Question about ISD::SUBCARRY

Dear all,

a couple of new generic DAG nodes ISD::ADCARRY and ISD::SUBCARRY were recently introduced in ⚙ D29872 Do not legalize large add with addc/adde, introduce addcarry and do it with uaddo/addcarry

These nodes have three inputs and two outputs, the second output being the "carry". I understand that carry is well defined for ADDCARRY but my question is about SUBCARRY.

Some architectures set the "carry" of a "x - y" subtraction is set when x < y (e.g x86, "borrow") and some others set it when x >= y (e.g. ARM). Does the ISD::SUBCARRY picks one interpretation (and uses it for combiners on top of this node) or leaves the interpretation to the target.

Maybe my whole question does not make sense and even if only one interpretation is chosen this does not impact the target?

Thank you very much,

That’s an excellent question. :slight_smile:

I’d say it should probably be defined as having the same boolean value as the hardware’s carry-flag, and there should be a TargetLowering function which describes the semantics upon subtract.

Hi James,

thanks for your answer.

Your suggestion looks sensible to me, then I understand that a combiner like the following one (DAGCombiner::visitSUBCARRY)

that assumes that “subcarry x, y, 0” can be simplified as “usubo x, y” should be parameterized using TargetLowering, as this assumes that the third input of subcarry is a borrow (e.g. x86) rather than a “carry” (e.g. ARM).

Does this make sense? Maybe I’m mixing things here.

( For context: I’m trying to establish if I can avoid adding ARM specific combiners in and use the generic ones instead. )

Kind regards,


I would tend to lean towards making SUBCARRY return the same value on all targets, assuming it doesn't complicate the target-specific code much. We want to make the target-independent code more straightforward if we can, and it probably makes the code easier to understand if SUBCARRY and USUBO are consistent.

If it somehow ends up being too tricky to lower SUBCARRY on ARM, it probably makes more sense to add new opcodes, rather than make the semantics of the existing opcodes depend on a target flag. (The end result is essentially equivalent, but it's harder to accidentally mistake which kind of node you're dealing with.)