Next: , Previous: Example, Up: Machine Desc


16.4 RTL模板

RTL模板用来定义哪些insn匹配特定的模式,以及如何找到它们的操作数。对于命名的模 式,RTL模板还说明了如何根据特定的操作数来构建一个insn。

构建insn涉及到替换指定操作数到模板。匹配insn涉及到测定被匹配insn的操作数值。这 些匹配和替换操作数的行为都是由专门的表达式类型来控制。

(match_operand:m n predicate constraint)
该表达式用来代表insn中的第 n 个操作数。当构建insn时,操作数编号 n 将 在此处被替换。当匹配insn时,凡是在insn中该位置出现的将被当作操作数编号 n; 但是其必须满足 predicate,否则该指令模式将根本不匹配

每个指令模式中的操作数编号必须从0开始连续的选择。在指令模式中,可以对每个操作数 编号只是用一个 match_operand 表达式。 通常操作数按照在 match_operand 表达式中出现的顺序被编号。对于 define_expand,任何 使用的操作数编号,只有在 match_dup 表达式中才会具有比其它操作数编号更高 的值。

predicate 为一个字符串,为一个函数的名字,其接受两个参数,一个表达式和一个 机器模式。参见Predicates。在匹配过程中,函数将会被调用,使用假定的操作数作为 表达式并且 m 作为机器模式参数(如果 m 没有被指定,则使用 VOIDmode,这通常会使得 predicate 可以接受任何机器模式)。如果其返 回0,则该指令模式匹配失败。predicate 可以为一个空字符串;这意味着不对操作 数作测试,这样出现在该位置的任何都是有效的。

大多时候,predicate 将会拒绝 m 之外的机器模式——但并不总是这样。例 如,predicate address_operand 使用 m 作为内存引用的机器模式。许多predicate 接受 const_int 节点,即使它们的机器模式为 VOIDmode

constraint 控制重载以及针对一个值选择最好的寄存器类别来使用,将在后面解释 (参见Constraints)。如果constraint为空字符串,则可以忽略掉。

人们经常弄不清楚constraint和predicate的区别。predicate帮助决定一个给定的insn是否匹配指令模式。constraint在该决定中不发挥作用;替代的,其控制已经匹配的insn的各种决定。


(match_scratch:m n constraint)
该表达式也是操作数编号 n 的占位符,并且指示操作数必须为一个 scratch 或者 reg 表达式。

当在匹配指令模式时,其相当于

          (match_operand:m n "scratch_operand" pred)

但是,当在生成RTL时,其产生一个(scratch:m)表达式。

如果在一个 parallel 中的最后几个表达式为 clobber 表达式,其操作数 为一个硬寄存器或者 match_scratch,则组合器可以在需要的时候增加或删除它 们。参见Side Effects


(match_dup n)
该表达式也为操作数编号 n 的占位符。其用于当操作数需要在insn中出现多次的 情况。

在构建过程中,match_dup 的作用就跟 match_operand 一样。操作数被 替换到正在被构建的insn中。但是在匹配时,match_dup 的行为就有所不同了。 其假设操作数编号 n 已经由在识别模板中之前出现的 match_operand 确 定了,其只匹配相同的表达式。

注意 match_dup 不要用来告诉编译器特定寄存器被用于两个操作数(例如: add 将一个寄存器加到另一个之上;第二个寄存器即为输入操作数,同样也为输 出操作数)。可以为此使用匹配constraint(参见Simple Constraints)。match_dup 是用于一个操作数在模板中的两个地方被使用的情况,例如一条指令同时计算商和余数, 其中操作码接受两个输入操作数,但是RTL模板不得不引用它们两次;一次用于求商指令 模式,一次用于求余数指令模式。


(match_operator:m n predicate [operands...])
该指令模式为一个可变RTL表达式代码的一种占位符。

当构造一个insn时,其代表RTL表达式,其表达式代码取自操作数 n,并且其操作 数从指令模式 operands 中构造。

当匹配一个表达式时,其匹配一个表达式,如果函数 predicate 对于该表达式返 回非零,并且 指令模式 operands 匹配表达式的操作数。

假设函数 commutative_operator 被如下定义,来匹配任何表达式,其操作符为 RTL中可交换的算术操作符,并且其机器模式为 mode

          int
          commutative_integer_operator (x, mode)
               rtx x;
               enum machine_mode mode;
          {
            enum rtx_code code = GET_CODE (x);
            if (GET_MODE (x) != mode)
              return 0;
            return (GET_RTX_CLASS (code) == RTX_COMM_ARITH
                    || code == EQ || code == NE);
          }

那么下列指令模式将匹配任何RTL表达式,其由一个可交换操作符和两个通用操作数组成:

          (match_operator:SI 3 "commutative_operator"
            [(match_operand:SI 1 "general_operand" "g")
             (match_operand:SI 2 "general_operand" "g")])

这里的向量 [operands...] 包含了两个指令模式,因为要匹配的表达 式都是包含两个操作数。

当该指令模式确实匹配时,可交换操作符的两个操作数被记录为insn的操作数1和2。(这 由 match_operand 的两个实例完成)。insn的操作数3将为整个可交换表达式:使 用 GET_CODE (operands[3]) 来查看使用了哪个可交换操作符。

match_operator 的机器模式 m 的作用与 match_operand 的类似: 其被作为第二个参数传递给predicate函数,并且函数专门负责决定被匹配的表达式是否具有那 个机器模式。

当构造insn时,gen-function 的参数3将会指定要构造的表达式的操作(即,表达式代 码)。其应该为一个RTL表达式,其表达式代码被复制到一个新的表达式中,新表达式的 操作数为 gen-function的参数1和2。参数3的子表达式不被使用;只与它的表达式代码 有关。

match_operator 被用于指令模式中来匹配insn时,通常最好让 match_operator 的操作数编号高于insn的实际操作数。这将提高寄存器分配, 因为寄存器分配者通常查看insn的操作数1和2,来看是否它可以做寄存器绑定 (register tying)。

无法指定在 match_operator 中的constraint。对应于 match_operator 的 insn的操作数,不具有任何constraint,因为它从来不作为一个整体被重载。但是,如果它 的 operands 的一部分被 match_operand 指令模式匹配,那些部分可 以具有它们自己的constraint。


(match_op_dup:m n[operands...])
类似 match_dup,除了其应用于操作符而不是操作数。当构造insn时,操作数 编号 n 将在这一点被替代。但是在匹配时,match_op_dup 的行为有所 不同。其假设操作数编号 n 已经被在识别模板中先前出现的 match_operator 所确定,并且其只匹配identical-looking的表达式。


(match_parallel n predicate [subpat...])
该指令模式为一个insn的占位符,该insn由一个具有可变数目元素的 parallel 表达式组成。该表达式应该只在insn指令模式的顶层出现。

当构造insn时,操作数编号 n 将在该处被替换。当匹配一个insn时,其当insn 的主体为一个 parallel 表达式,其具有至少跟向量 subpat 表达式同 样多数目元素,并且函数 predicate 返回非零时才匹配。predicate负责判定在 match_parallel 中的 parallel 的元素是否有效。

match_parallel 的一个典型用法是,匹配加载和存储多个表达式,其可以在 parallel 中包含一个可变数目的元素。例如,

          (define_insn ""
            [(match_parallel 0 "load_multiple_operation"
               [(set (match_operand:SI 1 "gpc_reg_operand" "=r")
                     (match_operand:SI 2 "memory_operand" "m"))
                (use (reg:SI 179))
                (clobber (reg:SI 179))])]
            ""
            "loadm 0,0,%1,%2")

这个例子来自 a29k.md。函数 load_multiple_operationa29k.c 中定义,其检查在 parallel 中的序列元素,是否与在 指令模式中的 set 相同,除非它们在引用后续的寄存器和内存位置。

匹配该指令模式的insn可能看起来像:

          (parallel
           [(set (reg:SI 20) (mem:SI (reg:SI 100)))
            (use (reg:SI 179))
            (clobber (reg:SI 179))
            (set (reg:SI 21)
                 (mem:SI (plus:SI (reg:SI 100)
                                  (const_int 4))))
            (set (reg:SI 22)
                 (mem:SI (plus:SI (reg:SI 100)
                                  (const_int 8))))])


(match_par_dup n [subpat...])
match_op_dup 类似,但是针对于 match_parallel,而不是 match_operator