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.

Reply via email to