Next: Multi-Alternative, Up: Constraints
最简单的约束种类是一个由字母组成的字符串, 每个字母描述一种所允许的操作数。这里是所允许的字母:
例如,地址为常数的为一个偏移表;所以地址为一个寄存器和常数(只要常数在机器所支持 的地址偏移范围)的和;但是递增或者递减地址不是偏移表。更加复杂的间接/索引地址可 能是或者可能不是偏移表,这取决于机器支持的其它寻址模式。
const_double
), 但是必须target浮点格式与host机器(编译器运行的机器)的相同才行。
const_double
或者const_vector
)。
这可能有点奇怪;如果insn允许常量操作数具有在编译时不可知的值, 它当然必须允许任何可知的值。所以为什么用‘s’,而不是‘i’能?有时候, 它会允许生成更好的代码。
例如,在68000上的全字指令,有可能使用一个立即数操作数; 但是如果立即数的值是处于-128和127之间,更好的代码是将值加载到寄存器中, 使用寄存器。这是因为加载到寄存器中可以由‘moveq’指令来完成。 我们对此通过定义字母‘K’来表示任意范围超出-128和127的整数, 然后在操作数约束中指定‘Ks’。
general_operand
。 这通常用于match_scratch
的约束中,当一些的可选项实际上不需要scratch寄存器的时候。
该编号允许多于单个数字。如果多个数字连续的在一起, 则它们被解析为一个单独的十进制整数。很少会因此产生不明确,因为到目前为止, 还没有想要将‘10’解析为匹配操作数1或者0的。如果有这样的需要, 则可以使用多个可选项来替代。
这被称为匹配约束,其实际上是指汇编器只有一个单独的操作数, 却在RTL insn中扮演两个角色。例如,add insn在RTL中具有两个输入操作数和一个输出操作数, 但是多数CISC机器上,add指令实际上只有两个操作数,其中一个为输入输出操作数:
addl #35,r12
匹配约束被用于这些情况。更确切的说, 匹配的两个操作数必须包括一个只作输入的操作数和一个只作输出的操作数。
约束中的‘p’必须由match_operand
中的作为断言的address_operand
协同工作。该断言将match_operand
中指定的机器模式解析为地址有效的内存引用的机器模式。
为了具有有效的汇编代码,每个操作数必须满足它的约束。但是如果不满足的话,也不会阻止将该指令模式应用到insn上。替代的,它会指示编译器去修改代码以至于约束将被满足。通常,这是通过将一个操作数复制到寄存器中来完成的。
因此,对比下面的两条指令模式:
(define_insn "" [(set (match_operand:SI 0 "general_operand" "=r") (plus:SI (match_dup 0) (match_operand:SI 1 "general_operand" "r")))] "" "...")
其具有两个操作数,其中一个必须出现在两个位置,
(define_insn "" [(set (match_operand:SI 0 "general_operand" "=r") (plus:SI (match_operand:SI 1 "general_operand" "0") (match_operand:SI 2 "general_operand" "r")))] "" "...")
其具有三个操作数,其中两个通过约束被要求为是相同的。如果我们考虑如下形式的一条insn
(insn n prev next (set (reg:SI 3) (plus:SI (reg:SI 6) (reg:SI 109))) ...)
第一个指令模式将根本不会被应用,因为该insn不在合适的地方包含两个相同的子表达式。指令模式会说“这看起来不像是一条加法指令;试一下其它模式”。第二个指令模式将会说,“是的,这是一条加法指令,但是有些问题”。它将指使编译器的重载过程生成额外的insn,使得约束为真。结果可能看起来像:
(insn n2 prev n (set (reg:SI 3) (reg:SI 6)) ...) (insn n n2 next (set (reg:SI 3) (plus:SI (reg:SI 3) (reg:SI 109))) ...)
你必须确保每个操作数,在每个指令模式中,具有能够处理可能会出现的任何RTL表达式的约束。(当使用多个可选项时,每个指令模式,对于每个可能的操作数表达式组合,必须至少具有一个可选项可以处理该操作数的组合。)约束不需要允许任何可能的操作数——如果是这种情况,它们就不做约束了——但是它们必须至少指出可以加载任何可能操作数,使得适合约束的方法。
例如,操作数对于它的约束允许除了寄存器以外的任何事物,如果它的断言不接受寄存器的话,这样是安全的。
操作数对于断言只接受常量时,如果它的约束包含字母‘i’,则是安全的。如果任何可能的常量都被接受,则可以使用‘i’;如果断言具有更多的选择性,则约束也可以具有更多的选择性。
如果操作数的断言能够识别寄存器,但是约束不允许它们,则能够使编译器崩溃。当该操作数正好是寄存器时,重载过程将被打乱,因为它不知道如何将寄存器临时复制到内存中。
如果断言接受一元操作符,约束将被应用到操作数上。例如,MIPS处理器在ISA3级时,支持一条指令,其将两个SImode
的寄存器相加产生一个 DImode
的结果,但是必须寄存器能够被正确的符号扩展。该断言对于输入操作数接受一个SImode
寄存器的sign_extend
。将约束写成指示寄存器的类型需要为sign_extend
的操作数。