Arm has an instruction that performs the following operation:
(parallel [
(set (reg:CC 100 cc)
(compare:CC (const_int 0 [0])
(reg:SI 121)))
(set (reg:SI 113)
(neg:SI (reg:SI 121)))
])
This is simply a reverse subtract from the constant zero, and setting
the condition flags. It's the low part of a negdi2 expansion.
However, combine will rip this up and try to transform the compare into
'canonical' form, ie
(parallel [
(set (reg:CC 100 cc)
(compare:CC (reg:SI 121)
(const_int 0 [0])))
(set (reg:SI 113)
(neg:SI (reg:SI 121)))
])
(and obviously swapping the condition on the instruction that uses the
comparison result).
This, of course, doesn't match the behaviour of the instruction and
no-longer matches the pattern in the md file.
SELECT_CC_MODE won't help me: the compare looks just like a simple
comparison that the machine supports, so it can't return a different
mode to allow me to fix things up.
I can't just stop the canonicalization: it's done in simplify_set and
the wider context of the instruction simply isn't available. If there
is no wider context (ie the comparison is not part of a parallel), then
the simplification is probably the right thing to do.
There are comments in combine.c (see for example just above the call to
target_canonicalize_comparison in try_combine) that suggest that this
sort of simplification should not be done, but it's clearly not being
done consistently.
So is there a way to describe this instruction within the compiler, or a
way to stop simplify_set from making this sort of simplification? I was
wondering if we might somehow annotate the compare (perhaps by setting
the volatile bit) to indicate that the comparison was being done as a
side-effect of another operation and that therefore swapping was not
permitted.
R.