Next: , Up: Peephole Definitions


16.18.1 RTL到文本的窥孔优化器

定义的形式如下:

     (define_peephole
       [insn-pattern-1
        insn-pattern-2
        ...]
       "condition"
       "template"
       "optional-insn-attributes")

如果没有在该机器描述中使用任何机器特定的信息, 则可以省略掉最后的字符串操作数。 如果有,则其必须遵守在define_insn中相同的规则。

该结构中,insn-pattern-1等为匹配连续insn的指令模式。 当insn-pattern-1匹配第一个insn, insn-pattern-2匹配下一个,等等依次类推的情况时, 则会将优化应用到该insn序列。

每个由窥孔匹配的insn也必须匹配一个define_insn。 窥孔只在代码生成前的最后阶段被检查,并且只是可选的。 因此,在一个未优化的编译中,或者不同的优化阶段中, 任何匹配窥孔但是不匹配define_insn的将会在代码生成时造成崩溃。

和通常一样,insn的操作数使用match_operands, match_operatormatch_dup来匹配。 不同的是,操作数编号应用在定义的所有insn指令模式中。所以, 你可以通过一个insn中的match_operand和另一个insn中的match_dup, 来在两个insn中检查相同的操作数。

用于match_operand指令模式的操作数constraint对窥孔的适用性没有任何直接的影响, 不过它们将会在后面被验证,所以要确信当窥孔匹配时,你的constraint要足够通用。 如果窥孔匹配,但constraint却不满足,则编译器将崩溃。

将窥孔中的所有操作数的constraint省略掉是安全的; 或者你可以编写constraint作为之前测试过的标准的二次检查。

一旦insn序列匹配指令模式,则condition将被检查。 这是一个C表达式,用于对是否执行优化来做最后的决定 (如果表达式非0时,我们这样做)。 如果condition被省略掉(换句话说,字符串为空) 则优化会被应用到每个匹配指令模式的insn序列。

定义的窥孔优化在寄存器分配完成之后应用。 因此,窥孔定义可以只是查看操作数,便能检查哪些操作数结束于哪种寄存器。

在条件中引用操作数的方式为对操作数编号i编写operands[i] (匹配于(match_operand i ...))。 使用变量insn来引用正在被匹配的insns的最后一个insn; 使用prev_active_insn来找到先前的insns。

当正在优化中间结果计算时, 你可以使用条件来匹配只有当中间结果不在其它地方被使用的情况。 使用C表达式dead_or_set_p (insn, op), 其中insn为你所期望其值为最后一次被使用的insn, 以及op为中间值(来自operands[i])。

应用优化,意味着将insn序列替换为新的insn。 template控制了针对该组合insn的最终汇编代码输出。 就像define_insn模板所做的一样。 该模板中的操作数编号与用于要匹配的原始insn序列中的相同。

被定义的窥孔优化器的结果不需要匹配机器描述中的任何insn模式; 它甚至没有机会来匹配它们。窥孔优化器定义本身是作为insn模式, 用来控制insn如何输出。

被定义的窥孔优化器被作为汇编代码运行输出, 所以它们产生的insns不再被组合或重排。

这里有一个例子,来自68000机器描述:

     (define_peephole
       [(set (reg:SI 15) (plus:SI (reg:SI 15) (const_int 4)))
        (set (match_operand:DF 0 "register_operand" "=f")
             (match_operand:DF 1 "register_operand" "ad"))]
       "FP_REG_P (operands[0]) && ! FP_REG_P (operands[1])"
     {
       rtx xoperands[2];
       xoperands[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
     #ifdef MOTOROLA
       output_asm_insn ("move.l %1,(sp)", xoperands);
       output_asm_insn ("move.l %1,-(sp)", operands);
       return "fmove.d (sp)+,%0";
     #else
       output_asm_insn ("movel %1,sp@", xoperands);
       output_asm_insn ("movel %1,sp@-", operands);
       return "fmoved sp@+,%0";
     #endif
     })

该优化的效果是将

     jbsr _foobar
     addql #4,sp
     movel d1,sp@-
     movel d0,sp@-
     fmoved sp@+,fp0

转换为

     jbsr _foobar
     movel d1,sp@
     movel d0,sp@-
     fmoved sp@+,fp0

insn-pattern-1等看起来与define_insn的第二个操作数非常相似。 不过有一个重要的不同:define_insn的第二个操作数包含了一个或多个RTX, 使用方括号包裹。通常,只有一个: 那么相同的动作则可以写成define_peephole的一个元素。 但是,当在define_insn中有多个动作时,它们被隐式的由parallel包裹。 则你必须在define_peephole中,显式的写出parallel,以及里面的方括号。 因此,如果一个insn的指令模式如下,

     (define_insn "divmodsi4"
       [(set (match_operand:SI 0 "general_operand" "=d")
             (div:SI (match_operand:SI 1 "general_operand" "0")
                     (match_operand:SI 2 "general_operand" "dmsK")))
        (set (match_operand:SI 3 "general_operand" "=d")
             (mod:SI (match_dup 1) (match_dup 2)))]
       "TARGET_68020"
       "divsl%.l %2,%3:%0")

则在窥孔中提及该insn的方法为:

     (define_peephole
       [...
        (parallel
         [(set (match_operand:SI 0 "general_operand" "=d")
               (div:SI (match_operand:SI 1 "general_operand" "0")
                       (match_operand:SI 2 "general_operand" "dmsK")))
          (set (match_operand:SI 3 "general_operand" "=d")
               (mod:SI (match_dup 1) (match_dup 2)))])
        ...]
       ...)