Replacing instruction with multiple substitute instructions

Hi,

I’m trying to replace a shift left instruction with multiple add instructions in LLVM’s RISCV backend, since my target RISCV processor might not contain an implementation of the shift left instruction. For example:

slli x5, x5, 3

should be replaced by

add x5, x5, x5
add x5, x5, x5
add x5, x5, x5

However, everything I’ve tried results in llc either crashing, or outputting just a single replacement add instruction. Here’s what I’ve tried so far - in RISCVTargetLowering::RISCVTargetLowering:

// Using Expand in place of Custom results in a crash
setOperationAction(ISD::SHL, MVT::i32, Custom);

In RISCVTargetLowering::LowerOperation:

case ISD::SHL:
    return replaceShlWithAdd(Op, DAG);

And

SDValue RISCVTargetLowering::replaceShlWithAdd(SDValue Op, SelectionDAG &DAG) const {
  SDLoc DL(Op);
  SDValue finalReplacement;

  SDValue num = Op.getOperand(0);
  EVT VT = num.getValueType();

  SDValue shamtOp = Op.getOperand(1);

  if (DAG.isConstantIntBuildVectorOrConstantInt(shamtOp)) {
    uint64_t shamt = Op.getConstantOperandVal(1);
    SmallVector<SDValue, 32> additions;

    for (int i = 0; i < shamt; i++) {
      SDValue addn = DAG.getNode(ISD::ADD, DL, VT, num, num);
      additions.push_back(addn);
      num = addn;
    }
    finalReplacement = DAG.getMergeValues(additions, DL);
    // The following didn't work either:
    // finalReplacement = DAG.getNode(ISD::TokenFactor, DL, VT, additions);
  }
  else {
    // TODO
  }
  return finalReplacement;
}

Let me know if any further details are required.

Thanks.

MERGE_VALUES is for creating a replacement that has multiple output values. For example, loads have a data result and a chain result. Or ISD::UADDO has the addition result and an overflow indication. You’re replacing an ISD::SHL which only has one result.

You just need to return the SDValue from the last ISD::ADD.

Something like

SDValue RISCVTargetLowering::replaceShlWithAdd(SDValue Op, SelectionDAG &DAG) const {
  SDLoc DL(Op);
  SDValue finalReplacement;

  SDValue num = Op.getOperand(0);
  EVT VT = num.getValueType();

  SDValue shamtOp = Op.getOperand(1);

  if (DAG.isConstantIntBuildVectorOrConstantInt(shamtOp)) {
    uint64_t shamt = Op.getConstantOperandVal(1);

    for (int i = 0; i < shamt; i++) {
      num = DAG.getNode(ISD::ADD, DL, VT, num, num);
    }

    finalReplacement = num;
  }
  else {
    // TODO
  }
  return finalReplacement;
}

Ah got it. That worked!
Thanks a lot!