[llvm-dev] Custom lower multiple return values

Jon Chesterfield via llvm-dev llvm-dev at lists.llvm.org
Wed Sep 27 09:18:31 PDT 2017


Hey,



I’ve been working on custom lowering ISD::UMUL_LOHI and ISD::SMUL_LOHI. Our
target has some legal vector types but no support for these so would like
to mark them as Expand. This yields “Cannot unroll a vector with multiple
results!” from the default case in VectorLegalizer::Expand. Hence custom
lowering. All the types are legal at this stage.



I would appreciate some clarification on how custom lowering of nodes with
multiple return values behaves. My theory is:



- The lowering function is called once per ResNo

- On each invocation, generate an SDValue for each ResNo

- Generate an ISD::MERGE_VALUES nodes to combine all of these SDValues

- Mutate the ResNo in the SDValue wrapping the ISD::MERGE_VALUES to match
the input ResNo



If that’s the right way to go, great. Confirmation would be appreciated.



My first few attempts involved only generating an SDValue for the requested
ResNo (which asserts when asked for ResNo == 1 and returning ResNo == 0)
and returning a ISD::MERGE_VALUES without mutating the ResNo (which leads
to constant folding merging the two result values together, effectively
dropping the second one).



The code I based this on is LowerXALUO in AArch64ISelLowering which returns
a MERGE_VALUES without mutating the ResNo. I’m concerned that AArch64 may
be dropping the carry bit based on the semantics observed above, but don’t
know AArch64 well enough to verify.



SDValue MyTarget::LowerXMUL_LOHI(SDValue Op, SelectionDAG &DAG) const {

  EVT VT = Op.getValueType();

  SDLoc dl(Op);

  unsigned Opc = Op.getOpcode();

  unsigned ResNo = Op.getResNo();

  assert(Opc == ISD::UMUL_LOHI || Opc == ISD::SMUL_LOHI);

  assert(ResNo == 0 || ResNo == 1);



  SDValue Op0 = Op.getOperand(0);

  SDValue Op1 = Op.getOperand(1);



  unsigned MULHXOpcode = Opc == ISD::UMUL_LOHI ? ISD::MULHU : ISD::MULHS;



  SDValue res[2] = { // Seems wasteful to generate both of these twice per
node

    DAG.getNode(ISD::MUL, dl, VT, Op0, Op1),

    LowerMULHX(DAG.getNode(MULHXOpcode, dl, VT, Op0, Op1), DAG),

  };



  SDVTList VTs = DAG.getVTList(VT, VT);

  SDNode * N =  DAG.getNode(ISD::MERGE_VALUES, dl, VTs, res[0],
res[1]).getNode();



  return SDValue(N,Op.getResNo()); // AArch64 doesn’t do this

}



The above is weird in at least two respects. It generates an ISD::MUL when
ResNo == 1, which will then be dropped elsewhere, and likewise the result
of custom lowering MULHX when ResNo == 0. It also mutates the ResNo before
returning, but without that codegen just drops the second half of the
lowering.



The reference from AArch64 is:

SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::i32);

return DAG.getNode(ISD::MERGE_VALUES, dl, VTs, Value, Overflow);



Am I on the right track here?



Cheers!



Jon
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20170927/3af7e15c/attachment.html>


More information about the llvm-dev mailing list