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)))])
...]
...)