Defining How to Split Instructions. GNU GCC
Anúncio
Anúncio
Chapter 12: Machine Descriptions 223
Here two RTL insns are generated, one to clear the entire output operand and the other to copy the input operand into its low half. This sequence is incorrect if the input operand refers to [the old value of] the output operand, so the preparation statement makes sure this isn’t so. The function make_safe_from copies the operands[1] into a temporary register if it refers to operands[0]. It does this by emitting another RTL insn.
Finally, a third example shows the use of an internal operand. Zero-extension on the
SPUR chip is done by and-ing the result against a halfword mask. But this mask cannot be represented by a const_int because the constant value is too large to be legitimate on this machine. So it must be copied into a register with force_reg and then the register used in the and.
(define_expand "zero_extendhisi2"
[(set (match_operand:SI 0 "register_operand" "")
(and:SI (subreg:SI
(match_operand:HI 1 "register_operand" "")
0)
(match_dup 2)))]
""
"operands[2]
= force_reg (SImode, GEN_INT (65535)); ")
Note: If the define_expand is used to serve a standard binary or unary arithmetic operation or a bit-field operation, then the last insn it generates must not be a code_label, barrier or note. It must be an insn, jump_insn or call_insn. If you don’t need a real insn at the end, emit an insn to copy the result of the operation into itself. Such an insn will generate no code, but it can avoid problems in the compiler.
12.16 Defining How to Split Instructions
There are two cases where you should specify how to split a pattern into multiple insns.
On machines that have instructions requiring delay slots (see Section 12.19.7 [Delay Slots], page 238) or that have instructions whose output is not available for multiple cycles (see
Section 12.19.8 [Processor pipeline description], page 239), the compiler phases that optimize these cases need to be able to move insns into one-instruction delay slots. However, some insns may generate more than one machine instruction. These insns cannot be placed into a delay slot.
Often you can rewrite the single insn as a list of individual insns, each corresponding to one machine instruction. The disadvantage of doing so is that it will cause the compilation to be slower and require more space. If the resulting insns are too complex, it may also suppress some optimizations. The compiler splits the insn if there is a reason to believe that it might improve instruction or delay slot scheduling.
The insn combiner phase also splits putative insns. If three insns are merged into one insn with a complex expression that cannot be matched by some define_insn pattern, the combiner phase attempts to split the complex pattern into two insns that are recognized. Usually it can break the complex pattern into two patterns by splitting out some subexpression. However, in some other cases, such as performing an addition of a large constant in two insns on a RISC machine, the way to split the addition into two insns is machine-dependent.
The define_split definition tells the compiler how to split a complex insn into several simpler insns. It looks like this:
224 GNU Compiler Collection (GCC) Internals
(define_split
[insn-pattern ]
"condition "
[new-insn-pattern-1 new-insn-pattern-2
...]
"preparation-statements ") insn-pattern is a pattern that needs to be split and condition is the final condition to be tested, as in a define_insn. When an insn matching insn-pattern and satisfying condition is found, it is replaced in the insn list with the insns given by new-insn-pattern-1, new-insnpattern-2, etc.
The preparation-statements are similar to those statements that are specified for define_ expand
(see Section 12.15 [Expander Definitions], page 220) and are executed before the new RTL is generated to prepare for the generated code or emit some insns whose pattern is not fixed. Unlike those in define_expand, however, these statements must not generate any new pseudo-registers. Once reload has completed, they also must not allocate any space in the stack frame.
Patterns are matched against insn-pattern in two different circumstances. If an insn needs to be split for delay slot scheduling or insn scheduling, the insn is already known to be valid, which means that it must have been matched by some define_insn and, if reload_completed is nonzero, is known to satisfy the constraints of that define_insn. In that case, the new insn patterns must also be insns that are matched by some define_insn and, if reload_completed is nonzero, must also satisfy the constraints of those definitions.
As an example of this usage of define_split, consider the following example from
‘a29k.md’, which splits a sign_extend from HImode to SImode into a pair of shift insns:
(define_split
[(set (match_operand:SI 0 "gen_reg_operand" "")
(sign_extend:SI (match_operand:HI 1 "gen_reg_operand" "")))]
""
[(set (match_dup 0)
(ashift:SI (match_dup 1)
(const_int 16)))
(set (match_dup 0)
(ashiftrt:SI (match_dup 0)
(const_int 16)))]
"
{ operands[1] = gen_lowpart (SImode, operands[1]); }")
When the combiner phase tries to split an insn pattern, it is always the case that the pattern is not matched by any define_insn. The combiner pass first tries to split a single set expression and then the same set expression inside a parallel, but followed by a clobber of a pseudo-reg to use as a scratch register. In these cases, the combiner expects exactly two new insn patterns to be generated. It will verify that these patterns match some define_insn definitions, so you need not do this test in the define_split (of course, there is no point in writing a define_split that will never produce insns that match).
Here is an example of this use of define_split, taken from ‘rs6000.md’:
(define_split
[(set (match_operand:SI 0 "gen_reg_operand" "")
(plus:SI (match_operand:SI 1 "gen_reg_operand" "")
(match_operand:SI 2 "non_add_cint_operand" "")))]
""
Chapter 12: Machine Descriptions 225
"
{
[(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 3)))
(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 4)))] int low = INTVAL (operands[2]) & 0xffff; int high = (unsigned) INTVAL (operands[2]) >> 16; if (low & 0x8000) high++, low |= 0xffff0000; operands[3] = GEN_INT (high << 16); operands[4] = GEN_INT (low);
}")
Here the predicate non_add_cint_operand matches any const_int that is not a valid operand of a single add insn. The add with the smaller displacement is written so that it can be substituted into the address of a subsequent operation.
An example that uses a scratch register, from the same file, generates an equality comparison of a register and a large constant:
(define_split
[(set (match_operand:CC 0 "cc_reg_operand" "")
(compare:CC (match_operand:SI 1 "gen_reg_operand" "")
(match_operand:SI 2 "non_short_cint_operand" "")))
(clobber (match_operand:SI 3 "gen_reg_operand" ""))]
"find_single_use (operands[0], insn, 0)
&& (GET_CODE (*find_single_use (operands[0], insn, 0)) == EQ
|| GET_CODE (*find_single_use (operands[0], insn, 0)) == NE)"
[(set (match_dup 3) (xor:SI (match_dup 1) (match_dup 4)))
"
(set (match_dup 0) (compare:CC (match_dup 3) (match_dup 5)))]
{
/*
Get the constant we are comparing against, C, and see what it looks like sign-extended to 16 bits. Then see what constant could be XOR’ed with C to get the sign-extended value.
*/ int c = INTVAL (operands[2]); int sextc = (c << 16) >> 16; int xorv = c ^ sextc; operands[4] = GEN_INT (xorv); operands[5] = GEN_INT (sextc);
}")
To avoid confusion, don’t write a single define_split that accepts some insns that match some define_insn as well as some insns that don’t. Instead, write two separate define_split definitions, one for the insns that are valid and one for the insns that are not valid.
The splitter is allowed to split jump instructions into sequence of jumps or create new jumps in while splitting non-jump instructions. As the central flowgraph and branch prediction information needs to be updated, several restriction apply.
Splitting of jump instruction into sequence that over by another jump instruction is always valid, as compiler expect identical behavior of new jump. When new sequence contains multiple jump instructions or new labels, more assistance is needed. Splitter is required to create only unconditional jumps, or simple conditional jump instructions.
Additionally it must attach a REG_BR_PROB note to each conditional jump. A global variable
Download
Anúncio