GCC后端移植 机器描述文档(中文版)
Posted sci-dev
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GCC后端移植 机器描述文档(中文版)相关的知识,希望对你有一定的参考价值。
本手册适合需要深入分析GCC工作原理,或需要为GCC后端适配新的CPU架构的技术人员查阅。
本翻译所遵循的术语规范:
机器描述:Machine Description
指令匹配规则:Pattern
操作数约束:Operand Constraints
匹配约束:Matching Constraints
标准操作:Standard Operation
窥孔优化:Peephole Optimization
并行表达式:Parallel Experssion
识别模板:Recognition Template
机器模式:Machine Mode
翻译持续更新。上次更新2019/9/21。翻译过程中多有疏漏之处,欢迎批评指正。
目录
1.1 Overview of How the Machine Description is Used How the machine description is used.
1.1 机器描述的使用概述(如何使用机器描述)
1.2 Everything about Instruction Patterns How to write instruction patterns.
1.2 指令匹配规则详解(如何编写指令匹配规则)
1.3 Example of define_insn An explained example of a define_insn pattern.
1.3 define_insn实例(如何使用define_insn)
1.4 RTL Template The RTL template defines what insns match a pattern.
1.4 RTL模板(RTL模板:定义何种指令匹配何种规则)
1.5 Output Templates and Operand Substitution The output template says how to make assembler code from such an insn.
1.5 输出模板、操作数替换(输出模板:定义如何从指令生成汇编代码)
1.6 C Statements for Assembler Output For more generality, write C code to output the assembler code.
1.6 用于汇编程序输出的C代码(为了使GCC更加通用,请编写这部分的代码)
1.7 Predicates Controlling what kinds of operands can be used for an insn.
1.7 谓词控制(判断何种操作数可以被使用)
1.8 Operand Constraints Fine-tuning operand selection.
1.8 操作数约束(微调操作数的选择)
1.9 Standard Pattern Names For Generation Names mark patterns to use for code generation.
1.9 匹配规则标准名(标识用于生成的匹配规则)
1.10 When the Order of Patterns Matters When the order of patterns makes a difference.
1.10 注意匹配规则的顺序(当匹配规则的顺序不同时)
1.11 Interdependence of Patterns Having one pattern may make you need another.
1.11 匹配规则的互相依赖(一个规则可能依赖于另一个规则)
1.12 Defining Jump Instruction Patterns Special considerations for patterns for jump insns.
1.12 定义跳转指令的匹配规则(跳转类指令需要特殊考虑)
1.13 Defining Looping Instruction Patterns How to define patterns for special looping insns.
1.13 定义循环指令的匹配规则(循环类指令需要特殊考虑)
1.14 Canonicalization of Instructions
1.14 指令规范化
1.15 Defining RTL Sequences for Code Generation Generating a sequence of several RTL insns for a standard operation.
1.15 定义用于代码生成的RTL序列(为标准操作生成一系列RTL指令)
1.16 Defining How to Split Instructions Splitting Instructions into Multiple Instructions.
1.16 定义指令分割规则(将指令分割为多重指令)
1.17 Including Patterns in Machine Descriptions.
1.17 在机器描述中include匹配规则
1.18 Machine-Specific Peephole Optimizers Defining machine-specific peephole optimizations.
1.18 定义机器相关的窥孔优化器
1.19 Instruction Attributes Specifying the value of attributes for generated insns.
1.19 指令属性(为生成的指令设置属性值)
1.20 Conditional Execution Generating define_insn patterns for predication.
1.20 条件执行(生成用于预测的define_insn匹配规则)
1.21 RTL Templates Transformations Generating define_insn and define_expand patterns from other patterns.
1.21 RTL模板(生成define_insn和define_expand匹配规则)
1.22 Constant Definitions Defining symbolic constants that can be used in the md file.
1.22 常量定义(定义符号常量)
1.23 Iterators Using iterators to generate patterns from a template.
1.23 迭代器(使用迭代器从一个模板生成匹配规则)
前言
A machine description has two parts: a file of instruction patterns (‘.md’ file) and a C header file of macro definitions.
一个完整的机器描述应当包括两部分:描述指令匹配规则的文件(‘.md‘文件)、包含相关宏定义的C语言头文件。
The ‘.md’ file for a target machine contains a pattern for each instruction that the target machine supports (or at least each instruction that is worth telling the compiler about).
‘.md‘文件包含目标机器所支持的所有指令的匹配规则(或者应至少包含编译器用到的指令)。
It may also contain comments. A semicolon causes the rest of the line to be a comment, unless the semicolon is inside a quoted string.
机器描述文件还可以包括注释:由一个‘;’分号引导单行注释,如果分号在由 " 包围的字符串中则不视为注释。
See the next chapter for information on the C header file.
下一章节将介绍C语言头文件。
1.1 机器描述的使用概述(Overview of How the Machine Description is Used)
There are three main conversions that happen in the compiler:
在整个编译过程中,编译器内部发生了如下转换:
1. The front end reads the source code and builds a parse tree.
1. 前端读取源代码,构建语法树。
2. The parse tree is used to generate an RTL insn list based on named instruction patterns.
2. 根据命名指令匹配规则,从语法树生成RTL指令。
3. The insn list is matched against the RTL templates to produce assembler code.
3. 从(RTL)指令列表匹配RTL模板,生成汇编代码。
For the generate pass, only the names of the insns matter, from either a named define_insn
or a define_expand
. The compiler will choose the pattern with the right name and apply the operands according to the documentation later in this chapter, without regard for the RTL template or operand constraints. Note that the names the compiler looks for are hard-coded in the compiler—it will ignore unnamed patterns and patterns with names it doesn’t know about, but if you don’t provide a named pattern it needs, it will abort.
对于生成过程来说,不论是命名的define_insn指令还是define_expand指令,指令的名称都非常重要。编译器会根据名称选择对应匹配规则,在不考虑RTL模板和操作数约束的情况下(根据后文所述),将操作数应用到匹配规则。注意规则名称是硬性编码的——编译器忽略未命名的匹配规则、名称未知的匹配规则;如果缺失必要的命名规则,编译器将会异常终止。
If a define_insn
is used, the template given is inserted into the insn list. If a define_expand
is used, one of three things happens, based on the condition logic. The condition logic may manually create new insns for the insn list, say via emit_insn()
, and invoke DONE
. For certain named patterns, it may invoke FAIL
to tell the compiler to use an alternate way of performing that task. If it invokes neither DONE
nor FAIL
, the template given in the pattern is inserted, as if the define_expand
were a define_insn
.
如果使用define_insn,指定的模板将被插入到指令列表;
如果使用define_expand,根据条件逻辑可能出现3种情况:
1. 条件逻辑有可能手动地在指令列表中创建新指令(通过emit_insn()完成),然后调用DONE结束。
2. 对于特定的命名匹配规则而言,条件逻辑可能调用FAIL通知编译器使用另一种方法来执行该任务。
3. 如果条件逻辑既不调用DONE也不调用FAIL,则将匹配规则中指定的模板插入到指令列表,这种情况下define_expand
等效于define_insn。
Once the insn list is generated, various optimization passes convert, replace, and rearrange the insns in the insn list. This is where the define_split
and define_peephole
patterns get used, for example.
一旦指令列表被生成,就进行各种优化,包括转换、替换和重新排列指令列表中的指令。这时就用到了诸如define_split和define_peephole之类的匹配规则。
Finally, the insn list’s RTL is matched up with the RTL templates in the define_insn
patterns, and those patterns are used to emit the final assembly code. For this purpose, each named define_insn
acts like it’s unnamed, since the names are ignored.
最终,指令列表中的RTL与RTL模板中define_insn定义的规则相匹配,根据这些规则生成最终的汇编代码。为此,每一个命名的define_insn规则看起来并没有被命名,因为它们的名称被忽略了。
1.2 指令匹配规则详解(Everything about Instruction Patterns)
A define_insn
expression is used to define instruction patterns to which insns may be matched. A define_insn
expression contains an incomplete RTL expression, with pieces to be filled in later, operand constraints that restrict how the pieces can be filled in, and an output template or C code to generate the assembler output.
define_insn表达式用于定义指令匹配规则,指定关联何种指令。define_insn表达式包括:不完整RTL表达式(部分字段在之后才会填充)、操作数约束(限制如何填充这些字段)、输出模板或者相关C代码(生成汇编代码)。
A define_insn
is an RTL expression containing four or five operands:
define_insn是一种RTL表达式,包括4或5个操作数:
1. An optional name. The presence of a name indicate that this instruction pattern can perform a certain standard job for the RTL-generation pass of the compiler. This pass knows certain names and will use the instruction patterns with those names, if the names are defined in the machine description.
1. 可选的名称。如果给出名称,则说明该规则支持对应的标准操作。如果某些名称是在机器描述中定义的,则此过程知道这些名称,并将使用它们对应的指令规则。
The absence of a name is indicated by writing an empty string where the name should go. Nameless instruction patterns are never used for generating RTL code, but they may permit several simpler insns to be combined later on.
如果名称未给出(在名称字段书写一个空串),则该规则为无名规则。无名规则永不用于生成RTL代码,但是他们允许在以后合并一些更简单的指令。
Names that are not thus known and used in RTL-generation have no effect; they are equivalent to no name at all.
因此,在RTL生成中的未知名称没有任何效果;它们相当于完全没有名称。
For the purpose of debugging the compiler, you may also specify a name beginning with the ‘*’ character. Such a name is used only for identifying the instruction in RTL dumps; it is equivalent to having a nameless pattern for all other purposes. Names beginning with the ‘*’ character are not required to be unique.
为了调试编译器,可能要指定以`*`字符开始的名称。这类名称只标识RTL转储中的指令;它等价于有一个使用其它所有目的的无名规则。以`*`字符开始的名称不一定唯一。
2. The RTL template: This is a vector of incomplete RTL expressions which describe the semantics of the instruction (see section RTL Template). It is incomplete because it may contain match_operand
, match_operator
, and match_dup
expressions that stand for operands of the instruction.If the vector has multiple elements, the RTL template is treated as a parallel
expression.
2. RTL模板。一个向量,包含不完整RTL表达式。该参数描述了指令的语义【参见: RTL模板(RTL Template)】。该表达式是不完整的,因为它可能包含match_operand、
match_operator
和 match_dup表达式,表示指令的操作数。如果该向量有多个元素,RTL模板将被视为并行表达式
3. The condition: This is a string which contains a C expression. When the compiler attempts to match RTL against a pattern, the condition is evaluated. If the condition evaluates to true
, the match is permitted. The condition may be an empty string, which is treated as always true
.
3. 条件。包含C表达式的字符串。当编译器尝试通过规则匹配RTL前,会先判断条件的值。如果取值为true,才允许匹配。条件参数可为空串,此时视其为永真值(true)。
For a named pattern, the condition may not depend on the data in the insn being matched, but only the target-machine-type flags. The compiler needs to test these conditions during initialization in order to learn exactly which named instructions are available in a particular run.
对于命名规则而言,除target-machine-type标志外,条件可不依赖于待匹配指令中的数据。编译器在初始化时需要测试这些条件,以确定当前有哪些指令可用。
For nameless patterns, the condition is applied only when matching an individual insn, and only after the insn has matched the pattern’s recognition template. The insn’s operands may be found in the vector operands
.
对于无名规则而言,仅当匹配单个指令时,条件才发挥作用,而且仅当指令成功匹配到规则的识别模板之后,条件才有用。指令的操作数可在向量operands中找到。
For an insn where the condition has once matched, it cannot later be used to control register allocation by excluding certain register or value combinations.
已经成功进行条件匹配的指令,不能在之后通过排除某些寄存器或值组合来控制寄存器分配。
4.The output template or output statement: This is either a string, or a fragment of C code which returns a string.
4. 输出模板(或输出代码)。一个字符串,或者一个C代码片段(返回字符串)。
When simple substitution isn’t general enough, you can specify a piece of C code to compute the output. See section C Statements for Assembler Output.
当简单地替换不再满足需求时,你需要指定一个C代码片段来完成输出。【参考:用于汇编程序输出的C代码(C Statements for Assembler Output)】
5. The insn attributes: This is an optional vector containing the values of attributes for insns matching this pattern (see section Instruction Attributes).
5. 指令属性。一个可选的向量,包含匹配该规则的目标指令的属性值。【参考:指令属性(Instruction Attributes)】
1.3 define_insn实例(Example of define_insn)
Here is an example of an instruction pattern, taken from the machine description for the 68000/68020.
这是一个指令匹配规则的实例:(出自68000/68020架构的机器描述)
(define_insn "tstsi" [(set (cc0) (match_operand:SI 0 "general_operand" "rm"))] "" "* if (TARGET_68020 || ! ADDRESS_REG_P (operands[0])) return \"tstl %0\"; return \"cmpl #0,%0\"; ")
This can also be written using braced strings:
也可以写成花括号字符串的形式:
(define_insn "tstsi" [(set (cc0) (match_operand:SI 0 "general_operand" "rm"))] "" if (TARGET_68020 || ! ADDRESS_REG_P (operands[0])) return "tstl %0"; return "cmpl #0,%0"; )
(译者注:即直接将C代码片段书写在花括号中,而不必放到"包围的字符串里)
This describes an instruction which sets the condition codes based on the value of a general operand. It has no condition, so any insn with an RTL description of the form shown may be matched to this pattern. The name ‘tstsi’ means “test a SImode
value” and tells the RTL generation pass that, when it is necessary to test such a value, an insn to do so can be constructed using this pattern.
上述代码描述了一条根据通用寄存器的值设置条件码的指令。我们没有为该规则指定条件,故任何具有上述RTL描述形式的指令都可能被匹配到该条规则。"tstsi"即“测试一个SImode值”。当有必要测试这个值时,RTL生成器将处理该规则,使用该规则构造对应的指令。
The output control string is a piece of C code which chooses which output template to return based on the kind of operand and the specific type of CPU for which code is being generated.
‘"rm"’ is an operand constraint. Its meaning is explained below.
其中,输出控制字符串是一个C代码片段,用于根据操作数的种类以及指定的目标CPU来选择输出模板。
‘"rm"’ 是一个操作数约束,它的含义将在下文解释。
1.4 RTL模板(RTL Template)
The RTL template is used to define which insns match the particular pattern and how to find their operands. For named patterns, the RTL template also says how to construct an insn from specified operands.
RTL模板定义何种指令匹配何种特定的规则,以及如何寻找他们的操作数。对于命名规则而言,RTL模板也告诉我们如何从指定的操作数构造一条指令。
Construction involves substituting specified operands into a copy of the template. Matching involves determining the values that serve as the operands in the insn being matched. Both of these activities are controlled by special expression types that direct matching and substitution of the operands.
“构造”包括将指定操作数替换为模板的副本。“匹配”包括确定要匹配的指令中用作操作数的值。这些活动都受到特殊的表达式类型控制,这些表达式类型直接匹配和替换操作数。
(match_operand:m n predicate constraint)
This expression is a placeholder for operand number n of the insn. When constructing an insn, operand number n will be substituted at this point. When matching an insn, whatever appears at this position in the insn will be taken as operand number n; but it must satisfy predicate or this instruction pattern will not match at all.
该表达式是一个占位符,表示指令的第n操作数。当构造一条指令时,将替换操作数n;当匹配一条指令时,任何在此位置出现的指令中的内容都将被视为操作数n。但这必须满足predicate,否则不会匹配。
Operand numbers must be chosen consecutively counting from zero in each instruction pattern. There may be only one match_operand
expression in the pattern for each operand number. Usually operands are numbered in the order of appearance in match_operand
expressions. In the case of a define_expand
, any operand numbers used only in match_dup
expressions have higher values than all other operand numbers.
在每个指令匹配规则中,操作数必须从零开始连续计数。对于每个操作数,规则中只能有一个match_operand
表达式。通常来说,在match_operand表达式中,操作数按出现顺序编号。在使用define_expand的情况下,任何仅用在match_dup表达式中的操作数必须比其他所有操作数具有更大的值。
predicate is a string that is the name of a function that accepts two arguments, an expression and a machine mode. See section Predicates. During matching, the function will be called with the putative operand as the expression and m as the mode argument (if m is not specified, VOIDmode
will be used, which normally causes predicate to accept any mode). If it returns zero, this instruction pattern fails to match. predicate may be an empty string; then it means no test is to be done on the operand, so anything which occurs in this position is valid.
predicate是一个字符串,代表函数名称。该函数接受两个参数(expression和机器mode)【参考:谓词(Predicates)】。在匹配过程中,该函数将被调用:推导出的操作数作为expression参数,m作为mode参数。(如果m未指定,将使用VOIDmode,使predicate接受任何模式)。如果该函数返回0,本次指令匹配将失败。predicate可以是一个空串,意味着不需要对操作数进行测试,任何可能的匹配都是有效的。
Most of the time, predicate will reject modes other than m—but not always. For example, the predicate address_operand
uses m as the mode of memory ref that the address should be valid for. Many predicates accept const_int
nodes even though their mode is VOIDmode
.
大多数情况下,predicate将拒绝不是m的其它模式(但不绝对)。例如,谓词address_operand将m视作内存引用的模式,其中内存引用的地址必须有效。许多谓词接受const_int节点,尽管他们的模式是VOIDmode。
constraint controls reloading and the choice of the best register class to use for a value, as explained later (see section Operand Constraints). If the constraint would be an empty string, it can be omitted.
constraint控制重载,并选择最适合当前值的寄存器类型【参考:操作数约束(Operand Constraints)】。约束可以是空串,可省略。
People are often unclear on the difference between the constraint and the predicate. The predicate helps decide whether a given insn matches the pattern. The constraint plays no role in this decision; instead, it controls various decisions in the case of an insn which does match.
人们常常不清楚约束(constraint)和谓词(predicate)之间的区别。谓词帮助决定给定的指令是否与规则匹配。约束在这个决策中不起作用;相反地,它在指令不匹配的情况下控制各种决策。
(match_scratch:m n constraint)
This expression is also a placeholder for operand number n and indicates that operand must be a scratch
or reg
expression.
该表达式是一个占位符,表示指令的第n操作数。同时指出操作数必须是一个scratch或者reg类型的表达式。
When matching patterns, this is equivalent to
当进行规则的匹配时,该表达式等价于:
(match_operand:m n "scratch_operand" constraint)
but, when generating RTL, it produces a (scratch
:m) expression.
当生成RTL时,该表达式产生一个(scratch
:m)表达式。
(scratch
:m)
If the last few expressions in a parallel
are clobber
expressions whose operands are either a hard register or match_scratch
, the combiner can add or delete them when necessary. @xrefSide Effects.
如果parallel中最后几个表达式是clobber表达式,其操作数要么是硬件寄存器,要么是match_scratch指定的寄存器。“组合器”可以在必要时添加或删除它们。【注意:Side Effects】
(match_dup n)
This expression is also a placeholder for operand number n. It is used when the operand needs to appear more than once in the insn.
该表达式也是一个占位符,表示指令的第n操作数。当操作数需要在指令中出现多次时使用。
In construction, match_dup
acts just like match_operand
: the operand is substituted into the insn being constructed. But in matching, match_dup
behaves differently. It assumes that operand number n has already been determined by a match_operand
appearing earlier in the recognition template, and it matches only an identical-looking expression.
在“构造”过程中,match_dup的行为与match_operand基本相同:操作数n被替换为正在构造的指令的操作数。但是在“匹配”过程中,match_dup的行为发生了改变。它假设操作数n已经由前面出现在识别模板中的match_operand确定,并且它只匹配“外观相同”的表达式。
Note that match_dup
should not be used to tell the compiler that a particular register is being used for two operands (example: add
that adds one register to another; the second register is both an input operand and the output operand). Use a matching constraint (see section Simple Constraints) for those. match_dup
is for the cases where one operand is used in two places in the template, such as an instruction that computes both a quotient and a remainder, where the opcode takes two input operands but the RTL template has to refer to each of those twice; once for the quotient pattern and once for the remainder pattern.
注意,当两个操作数同时应用于某个特定寄存器时,不能使用match-dup来指明。(例如:add指令将一个寄存器的值加到另一个寄存器;其中第二个寄存器既是输入,又是输出),而应该使用匹配约束【参见:简单约束(Simple Constraints)】。match_dup的真正目的是指明模板中的两个位置使用一个操作数的情况,例如一条同时计算商和余数的指令,其操作码接受两个输入,但是RTL模板不得不引用这两个操作数,一个用于求商规则,另一个用于求余规则。
(match_operator:m n predicate [operands…])
This pattern is a kind of placeholder for a variable RTL expression code.
此规则是变量类型RTL表达式代码的占位符。
When constructing an insn, it stands for an RTL expression whose expression code is taken from that of operand n, and whose operands are constructed from the patterns operands.
当构造指令时,它代表一个RTL表达式,其表达式代码是从操作数n取出,并且操作数是根据operands构造的。
When matching an expression, it matches an expression if the function predicate returns nonzero on that expression and the patterns operands match the operands of the expression.
当匹配表达式时,如果函数predicate返回非0,并且规则的操作数与表达式的操作数匹配,则源表达式匹配成功。
Suppose that the function commutative_operator
is defined as follows, to match any expression whose operator is one of the commutative arithmetic operators of RTL and whose mode is mode:
假设函数commutative_operator定义如下,目标是匹配这样一个表达式:其算子为RTL规定的commutative算子之一,并且其模式为mode:
1 2 int 3 commutative_integer_operator (x, mode) 4 rtx x; 5 machine_mode mode; 6 7 enum rtx_code code = GET_CODE (x); 8 if (GET_MODE (x) != mode) 9 return 0; 10 return (GET_RTX_CLASS (code) == RTX_COMM_ARITH 11 || code == EQ || code == NE); 12
Then the following pattern will match any RTL expression consisting of a commutative operator applied to two general operands:
然后,以下规则将匹配这样一个RTL表达式:由commutative运算符组成,并且应用于两个通用操作数。
(match_operator:SI 3 "commutative_operator" [(match_operand:SI 1 "general_operand" "g") (match_operand:SI 2 "general_operand" "g")])
Here the vector [operands…]
contains two patterns because the expressions to be matched all contain two operands.
这里向量 [operands…]
包含了两个规则,因为待匹配的所有表达式都包含两个操作数。
When this pattern does match, the two operands of the commutative operator are recorded as operands 1 and 2 of the insn. (This is done by the two instances of match_operand
.) Operand 3 of the insn will be the entire commutative expression: use GET_CODE (operands[3])
to see which commutative operator was used.
当该规则匹配时,commutative运算符的两个操作数分别被记为指令的操作数1和2。(这是由match_operand的两个实例完成的)。指令的操作数3就是整个commutative表达式:使用GET_CODE (operands[3])来查询该表达式是哪一commutative算子。
The machine mode m of match_operator
works like that of match_operand
: it is passed as the second argument to the predicate function, and that function is solely responsible for deciding whether the expression to be matched “has” that mode.
match_operator中指定的
机器模式m与match_operand中指定的类似。它作为第二个参数传递给predicate函数,该函数只决定要匹配的表达式是否“具有”该模式。
When constructing an insn, argument 3 of the gen-function will specify the operation (i.e. the expression code) for the expression to be made. It should be an RTL expression, whose expression code is copied into a new expression whose operands are arguments 1 and 2 of the gen-function. The subexpressions of argument 3 are not used; only its expression code matters.
当构造指令时,生成函数(gen-function)的参数3指定要产生的表达式的操作(即表达式编码)。它应该是一个RTL表达式,其表达式代码被复制到一个新表达式中,该表达式的操作数是gen函数的参数1和2。不使用参数3的子表达式,而是只关心其表达式编码。
When match_operator
is used in a pattern for matching an insn, it usually best if the operand number of the match_operator
is higher than that of the actual operands of the insn. This improves register allocation because the register allocator often looks at operands 1 and 2 of insns to see if it can do register tying.
通常,在规则中使用match_operator匹配指令时,match_operator的操作数应大于指令的实际操作数。这有助于改进寄存器分配,因为寄存器分配器经常检查指令的操作数1和2,以判断是否可以进行寄存器tying。
There is no way to specify constraints in match_operator
. The operand of the insn which corresponds to the match_operator
never has any constraints because it is never reloaded as a whole. However, if parts of its operands are matched by match_operand
patterns, those parts may have constraints of their own.
不能在match_operator中指定约束。与match_operator相对应的指令的操作数根本没有约束,因为它不可能作为一个整体重新加载。但是,如果部分操作数与match_operand规则相匹配,则这些部分可能有自己的约束。
以上是关于GCC后端移植 机器描述文档(中文版)的主要内容,如果未能解决你的问题,请参考以下文章
移植 InterlockedExchange,仅使用 GCC 内在函数
将源代码从 Visual C++ 移植到 GCC 都有哪些陷阱[关闭]