Previous: define_peephole, Up: Peephole Definitions


16.18.2 RTL到RTL的窥孔优化器

define_peephole2定义告诉了编译器如何将一个指令序列用来替换另一个序列, 可能需要那些额外的scratch寄存器,以及它们的生命期必须为什么。

     (define_peephole2
       [insn-pattern-1
        insn-pattern-2
        ...]
       "condition"
       [new-insn-pattern-1
        new-insn-pattern-2
        ...]
       "preparation-statements")

定义几乎与define_split(参见Insn Splitting)相同, 除了要匹配的指令模式不是一个单个指令,而是一个指令序列。

在输出模板中有可能需要用到额外的scratch寄存器。 如果没有合适的寄存器,则指令模式将简单的作为不匹配处理。

使用match_scratch描述所需要的scratch寄存器, 并放在输入指令模式的顶层。被分配的寄存器(最初的) 将会在原始指令序列中需要使用的位置死掉。 如果scratch被用于多个位置, 则位于输入指令模式顶层的match_dup 指令模式用来标记在输入序列中寄存器必须为活跃的最后位置。

这里有一个来自IA-32机器描述的例子:

     (define_peephole2
       [(match_scratch:SI 2 "r")
        (parallel [(set (match_operand:SI 0 "register_operand" "")
                        (match_operator:SI 3 "arith_or_logical_operator"
                          [(match_dup 0)
                           (match_operand:SI 1 "memory_operand" "")]))
                   (clobber (reg:CC 17))])]
       "! optimize_size && ! TARGET_READ_MODIFY"
       [(set (match_dup 2) (match_dup 1))
        (parallel [(set (match_dup 0)
                        (match_op_dup 3 [(match_dup 0) (match_dup 2)]))
                   (clobber (reg:CC 17))])]
       "")

该指令模式尝试拆分加载的使用,以希望我们能够调度内存加载延迟。 它分配了一个GENERAL_REGS("r")类别的单个的SImode寄存器, 其只需在算术运算之前的位置为活跃的。

很难找到需要延长scratch生命期的真实例子,所以这里只是一个制造的例子:

     (define_peephole2
       [(match_scratch:SI 4 "r")
        (set (match_operand:SI 0 "" "") (match_operand:SI 1 "" ""))
        (set (match_operand:SI 2 "" "") (match_dup 1))
        (match_dup 4)
        (set (match_operand:SI 3 "" "") (match_dup 1))]
       "/* determine 1 does not overlap 0 and 2 */"
       [(set (match_dup 4) (match_dup 1))
        (set (match_dup 0) (match_dup 4))
        (set (match_dup 2) (match_dup 4))]
        (set (match_dup 3) (match_dup 4))]
       "")

如果我们没有在输入序列的中间增加(match_dup 4), 则可能的情况是我们选择的寄存器会在序列的起始处被第一个或第二个set杀死。