Next: define_peephole2, Up: Peephole Definitions
(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_operator
和match_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)))]) ...] ...)