ExpandDivRemLibCall vs. AEABI


I’m working on bug 16387:
“clang doesn’t produce ARM EABI-compliant modulo runtime function”


And I need some pointers.

I’ve changed ARMISelLowering::ARMTargetLowering::ARMTargetLowering() to associate _aeabi_idivmod variants to RTLIB::{U,S}DIVREM* library calls, but now I need to teach the expansion that on AEABI case, the remainder is not on the stack, but on registers.

However, SelectionDAGLegalize::ExpandDivRemLibCall() assumes the remainder is always on the stack, as is the case for GNU:

// Remainder is loaded back from the stack frame.
SDValue Rem = DAG.getLoad(RetVT, dl, CallInfo.second, FIPtr,
MachinePointerInfo(), false, false, false, 0);

Since I don’t want to add a target-specific condition there, and I found no hierarchy for DAGLegalize, I’m wondering what’s the best approach.

Two options could be:

  • Creating a feature (HasDivRemRegister or whatever) and hard-code AEABI together with the hard-coded GNU
  • Have some call-back mechanism, possibly upon a flag (HasSpecialDivRemLowering), and update the remainder result

Both are ugly… :frowning:

Is there anything like that elsewhere, that would hopefully be implemented inside ARM’s tree, that I could follow?


Hi Renato,

* Have some call-back mechanism, possibly upon a flag
(HasSpecialDivRemLowering), and update the remainder result

If you setOperationAction on SDIVREM and UDIVREM to Custom you can
expand the rtlib call appropriately yourself. There's precedent for
sincos on Darwin systems (both ARM and x86) and in AArch64 for
basically every operation on fp128.



I was trying to avoid Custom, the code duplication will not be small... :frowning:



Just following up.

I have assigned Custom lowering:

    setOperationAction(ISD::SREM, MVT::i32, Custom);
    setOperationAction(ISD::UREM, MVT::i32, Custom);
    setOperationAction(ISD::SDIVREM, MVT::i32, Custom);
    setOperationAction(ISD::UDIVREM, MVT::i32, Custom);

Added it to the LowerOperation() switch and created a LowerDIVREM(SDValue,

My idea is to change the DAG this way:

* {U,S}REM:
  * up to 32bits: call {U,S}DIVREM result in R1 (Follow through or use MOV)
  * 64bits: call {U,S}DIVREM + result in {R2,R3} (Follow through or use MOV)
  * Change the reminder from stack to to R1 / {R2,R3}

But for that, SelectionDAGLegalize::ExpandDivRemLibCall() has to stop
always loading the result from the stack, and that should become a
post-processing thing. I'm not sure how to change the result at the end,
but I saw that some calls use ARMTargetLowering::ReplaceNodeResults(),
would that be the right place for adding my magic?

Does this make sense? Or is it better for me to copy&paste most of the
ExpandDivRemLibCall() into LowerDIVREM()?