|GNU Compiler Collection (GCC) Internals: Insn Canonicalizations|
There are often cases where multiple RTL expressions could represent an operation performed by a single machine instruction. This situation is most commonly encountered with logical, branch, and multiply-accumulate instructions. In such cases, the compiler attempts to convert these multiple RTL expressions into a single canonical form to reduce the number of insn patterns required.
In addition to algebraic simplifications, following canonicalizations are performed:
pluscan itself be a
umaxare associative when applied to integers, and sometimes to floating-point.
minusexpression, it will be the first operand.
negoperations (if any) will be moved inside the operations as far as possible. For instance,
(neg (mult A B))is canonicalized as
(mult (neg A) B), but
(plus (mult (neg B) C) A)is canonicalized as
(minus A (mult B C)).
compareoperator, a constant is always the second operand if the first argument is a condition code register or
minusis made the first operand under the same conditions as above.
(ltu (plus a b) b)is converted to
(ltu (plus a b) a). Likewise with
(minus x (const_int n))is converted to
(plus x (const_int -n)).
mem), a left shift is converted into the appropriate multiplication by a power of two.
notexpression, it will be the first one.
A machine that has an instruction that performs a bitwise logical-and of one operand with the bitwise negation of the other should specify the pattern for that instruction as
(define_insn "" [(set (match_operand:m 0 …) (and:m (not:m (match_operand:m 1 …)) (match_operand:m 2 …)))] "…" "…")
Similarly, a pattern for a “NAND” instruction should be written
(define_insn "" [(set (match_operand:m 0 …) (ior:m (not:m (match_operand:m 1 …)) (not:m (match_operand:m 2 …))))] "…" "…")
In both cases, it is not necessary to include patterns for the many logically equivalent RTL expressions.
(xor:m x y)and
(not:m (xor:m x y)).
(plus:m (plus:m x y) constant)
zero_extractrather than the equivalent
(sign_extend:m1 (mult:m2 (sign_extend:m2 x) (sign_extend:m2 y)))is converted to
(mult:m1 (sign_extend:m1 x) (sign_extend:m1 y)), and likewise for
(sign_extend:m1 (mult:m2 (ashiftrt:m2 x s) (sign_extend:m2 y)))is converted to
(mult:m1 (sign_extend:m1 (ashiftrt:m2 x s)) (sign_extend:m1 y)), and likewise for patterns using
lshiftrt. If the second operand of
multis also a shift, then that is extended also. This transformation is only applied when it can be proven that the original operation had sufficient precision to prevent overflow.
Further canonicalization rules are defined in the function
commutative_operand_precedence in gcc/rtlanal.c.