[llvm] [RISCV] Implement EmitTargetCodeForMemset for Xqcilsm (PR #151555)

Sam Elliott via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 31 10:51:24 PDT 2025


================
@@ -62,3 +64,102 @@ void RISCVSelectionDAGInfo::verifyTargetNode(const SelectionDAG &DAG,
   }
 #endif
 }
+
+SDValue RISCVSelectionDAGInfo::EmitTargetCodeForMemset(
+    SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Dst, SDValue Src,
+    SDValue Size, Align Alignment, bool isVolatile, bool AlwaysInline,
+    MachinePointerInfo DstPtrInfo) const {
+  const RISCVSubtarget &Subtarget =
+      DAG.getMachineFunction().getSubtarget<RISCVSubtarget>();
+  // We currently do this only for Xqcilsm
+  if (!Subtarget.hasVendorXqcilsm())
+    return SDValue();
+
+  // Do this only if we know the size at compile time.
+  ConstantSDNode *ConstantSize = dyn_cast<ConstantSDNode>(Size);
+  if (!ConstantSize)
+    return SDValue();
+
+  uint64_t NumberOfBytesToWrite = ConstantSize->getZExtValue();
+
+  // Do this only if it is word aligned and we write multiple of 4 bytes.
+  if (!((Alignment.value() & 3) == 0 && (NumberOfBytesToWrite & 3) == 0))
+    return SDValue();
+
+  SmallVector<SDValue, 8> OutChains;
+  SDValue SizeWords, OffsetSetwmi;
+  SDValue SrcValueReplicated = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i32, Src);
+  int NumberOfWords = NumberOfBytesToWrite / 4;
+
+  // Helper for constructing the QC_SETWMI instruction
+  auto getSetwmiNode = [&](SDValue SizeWords, SDValue OffsetSetwmi) -> SDValue {
+    SDValue Ops[] = {Chain, SrcValueReplicated, Dst, SizeWords, OffsetSetwmi};
+    return DAG.getNode(RISCVISD::QC_SETWMI, dl, MVT::Other, Ops);
+  };
+
+  bool IsZeroVal =
+      isa<ConstantSDNode>(Src) && cast<ConstantSDNode>(Src)->isZero();
+
+  // If i8 type and constant non-zero value.
+  if ((Src.getValueType() == MVT::i8) && !IsZeroVal)
+    // Replicate byte to word by multiplication with 0x01010101.
+    SrcValueReplicated = DAG.getNode(ISD::MUL, dl, MVT::i32, SrcValueReplicated,
+                                     DAG.getConstant(16843009, dl, MVT::i32));
+
+  // We limit a QC_SETWMI to 16 words or less to improve interruptibility.
+  // So for 1-16 words we use a single QC_SETWMI:
+  //
+  // QC_SETWMI reg1, N, 0(reg2)
+  //
+  // For 17-32 words we use two QC_SETWMI's with the first as 16 words and the
+  // second for the remainder:
+  //
+  // QC_SETWMI reg1, 16, 0(reg2)
+  // QC_SETWMI reg1, N, 64(reg2)
+  //
+  // For 33-48 words, we would like to use (16, 16, n), but that means the last
+  // QC_SETWMI needs an offset of 128 which the instruction doesnt support.
+  // So in this case we use a length of 15 for the second instruction and we do
+  // the rest with the third instruction.
+  // This means the maximum inlined number of words is 47 (for now):
+  //
+  // QC_SETWMI R2, R0, 16, 0
+  // QC_SETWMI R2, R0, 15, 64
+  // QC_SETWMI R2, R0, N, 124
+  //
+  // For 48 words or more, call the target independent memset
+  if (NumberOfWords <= 16) {
----------------
lenary wrote:

Do we need to handle `if (NumberOfWords == 0)` separately? Please also add a test for this case.

https://github.com/llvm/llvm-project/pull/151555


More information about the llvm-commits mailing list