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:
vec_merge
with constant mask(the third operand), the first
and the second operand can be exchanged by inverting the mask. In such cases,
a constant is always made the second operand, otherwise the least significant
bit of the mask is always set(select the first operand first).
plus
can itself be a plus
. and
, ior
, xor
,
plus
, mult
, smin
, smax
, umin
, and
umax
are associative when applied to integers, and sometimes to
floating-point.
neg
, not
,
mult
, plus
, or minus
expression, it will be the
first operand.
neg
, mult
, plus
, and
minus
, the neg
operations (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))
.
compare
operator, a constant is always the second operand
if the first argument is a condition code register.
compare
operator is always written as the first RTL expression of
the parallel
instruction pattern. For example,
(define_insn "" [(set (reg:CCZ FLAGS_REG) (compare:CCZ (plus:SI (match_operand:SI 1 "register_operand" "%r") (match_operand:SI 2 "register_operand" "r")) (const_int 0))) (set (match_operand:SI 0 "register_operand" "=r") (plus:SI (match_dup 1) (match_dup 2)))] "" "addl %0, %1, %2")
neg
, not
, mult
, plus
, or
minus
is 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 geu
instead
of ltu
.
(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.
not
expression, 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_extract
rather than the equivalent
and
or sign_extract
operations.
(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 zero_extend
.
(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 zero_extend
and lshiftrt
. If the second
operand of mult
is 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.cc.