[llvm] 71b066e - [RISCV] Add CodeGen support for qc.insbi and qc.insb insert instructions (#152447)

via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 13 23:38:31 PDT 2025


Author: quic_hchandel
Date: 2025-08-14T12:08:28+05:30
New Revision: 71b066e3a2512d582e34a0b5257e12b1177d4bcc

URL: https://github.com/llvm/llvm-project/commit/71b066e3a2512d582e34a0b5257e12b1177d4bcc
DIFF: https://github.com/llvm/llvm-project/commit/71b066e3a2512d582e34a0b5257e12b1177d4bcc.diff

LOG: [RISCV] Add CodeGen support for qc.insbi and qc.insb insert instructions (#152447)

This patch adds CodeGen support for qc.insbi and qc.insb instructions
defined in the Qualcomm uC Xqcibm extension. qc.insbi and qc.insb
inserts bits into destination register from immediate and register
operand respectively.
A sequence of `xor`, `and` & `xor` depending on appropriate conditions
are converted to `qc.insbi` or `qc.insb` which depends on the
immediate's value.

Added: 
    llvm/test/CodeGen/RISCV/xqcibm-insbi.ll

Modified: 
    llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
    llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index 5998653129209..9e1530a2d00f4 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -18,6 +18,7 @@
 #include "RISCVInstrInfo.h"
 #include "RISCVSelectionDAGInfo.h"
 #include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/SDPatternMatch.h"
 #include "llvm/IR/IntrinsicsRISCV.h"
 #include "llvm/Support/Alignment.h"
 #include "llvm/Support/Debug.h"
@@ -772,6 +773,49 @@ bool RISCVDAGToDAGISel::trySignedBitfieldInsertInSign(SDNode *Node) {
   return false;
 }
 
+// (xor X, (and (xor X, C1), C2))
+// -> (qc.insbi X, (C1 >> ShAmt), Width, ShAmt)
+// where C2 is a shifted mask with width=Width and shift=ShAmt
+bool RISCVDAGToDAGISel::tryBitfieldInsertOpFromXor(SDNode *Node) {
+
+  if (!Subtarget->hasVendorXqcibm())
+    return false;
+
+  using namespace SDPatternMatch;
+
+  SDValue X;
+  APInt CImm, CMask;
+  if (!sd_match(
+          Node,
+          m_Xor(m_Value(X),
+                m_OneUse(m_And(m_OneUse(m_Xor(m_Deferred(X), m_ConstInt(CImm))),
+                               m_ConstInt(CMask))))))
+    return false;
+
+  unsigned Width, ShAmt;
+  if (!CMask.isShiftedMask(ShAmt, Width))
+    return false;
+
+  int64_t Imm = CImm.getSExtValue();
+  Imm >>= ShAmt;
+
+  SDLoc DL(Node);
+  SDValue ImmNode;
+  auto Opc = RISCV::QC_INSB;
+
+  if (isInt<5>(Imm)) {
+    Opc = RISCV::QC_INSBI;
+    ImmNode = CurDAG->getSignedTargetConstant(Imm, DL, MVT::i32);
+  } else {
+    ImmNode = selectImm(CurDAG, DL, MVT::i32, Imm, *Subtarget);
+  }
+  SDValue Ops[] = {X, ImmNode, CurDAG->getTargetConstant(Width, DL, MVT::i32),
+                   CurDAG->getTargetConstant(ShAmt, DL, MVT::i32)};
+  ReplaceNode(Node, CurDAG->getMachineNode(Opc, DL, MVT::i32, Ops));
+
+  return true;
+}
+
 bool RISCVDAGToDAGISel::tryUnsignedBitfieldExtract(SDNode *Node,
                                                    const SDLoc &DL, MVT VT,
                                                    SDValue X, unsigned Msb,
@@ -1349,6 +1393,9 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
     if (tryShrinkShlLogicImm(Node))
       return;
 
+    if (tryBitfieldInsertOpFromXor(Node))
+      return;
+
     break;
   case ISD::AND: {
     auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1));

diff  --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
index ee3a86e25add0..9d4cd0e6e3393 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
@@ -75,6 +75,7 @@ class RISCVDAGToDAGISel : public SelectionDAGISel {
   bool trySignedBitfieldExtract(SDNode *Node);
   bool trySignedBitfieldInsertInSign(SDNode *Node);
   bool trySignedBitfieldInsertInMask(SDNode *Node);
+  bool tryBitfieldInsertOpFromXor(SDNode *Node);
   bool tryUnsignedBitfieldExtract(SDNode *Node, const SDLoc &DL, MVT VT,
                                   SDValue X, unsigned Msb, unsigned Lsb);
   bool tryUnsignedBitfieldInsertInZero(SDNode *Node, const SDLoc &DL, MVT VT,

diff  --git a/llvm/test/CodeGen/RISCV/xqcibm-insbi.ll b/llvm/test/CodeGen/RISCV/xqcibm-insbi.ll
new file mode 100644
index 0000000000000..e4a545169d210
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/xqcibm-insbi.ll
@@ -0,0 +1,262 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -mtriple=riscv32 --verify-machineinstrs < %s \
+; RUN:   | FileCheck %s -check-prefixes=RV32I
+; RUN: llc -mtriple=riscv32 -mattr=+experimental-xqcibm --verify-machineinstrs < %s \
+; RUN:   | FileCheck %s -check-prefixes=RV32XQCIBM
+
+define i32 @insbi(i32 %in1) nounwind {
+; RV32I-LABEL: insbi:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    xori a1, a0, 176
+; RV32I-NEXT:    andi a1, a1, 496
+; RV32I-NEXT:    xor a0, a1, a0
+; RV32I-NEXT:    ret
+;
+; RV32XQCIBM-LABEL: insbi:
+; RV32XQCIBM:       # %bb.0:
+; RV32XQCIBM-NEXT:    qc.insbi a0, 11, 5, 4
+; RV32XQCIBM-NEXT:    ret
+  %xor1 = xor i32 %in1, 176
+  %and1 = and i32 %xor1, 496
+  %xor2 = xor i32 %and1, %in1
+  ret i32 %xor2
+}
+
+define i32 @insbi_comm_xor(i32 %in1) nounwind {
+; RV32I-LABEL: insbi_comm_xor:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    li a1, 9
+; RV32I-NEXT:    li a2, 15
+; RV32I-NEXT:    slli a1, a1, 9
+; RV32I-NEXT:    xor a1, a0, a1
+; RV32I-NEXT:    slli a2, a2, 9
+; RV32I-NEXT:    and a1, a1, a2
+; RV32I-NEXT:    xor a0, a1, a0
+; RV32I-NEXT:    ret
+;
+; RV32XQCIBM-LABEL: insbi_comm_xor:
+; RV32XQCIBM:       # %bb.0:
+; RV32XQCIBM-NEXT:    qc.insbi a0, 9, 4, 9
+; RV32XQCIBM-NEXT:    ret
+  %xor1 = xor i32 4608, %in1
+  %and1 = and i32 %xor1, 7680
+  %xor2 = xor i32 %and1, %in1
+  ret i32 %xor2
+}
+
+define i32 @insbi_comm_and(i32 %in1) nounwind {
+; RV32I-LABEL: insbi_comm_and:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    li a1, 11
+; RV32I-NEXT:    li a2, 15
+; RV32I-NEXT:    slli a1, a1, 9
+; RV32I-NEXT:    xor a1, a0, a1
+; RV32I-NEXT:    slli a2, a2, 9
+; RV32I-NEXT:    and a1, a1, a2
+; RV32I-NEXT:    xor a0, a1, a0
+; RV32I-NEXT:    ret
+;
+; RV32XQCIBM-LABEL: insbi_comm_and:
+; RV32XQCIBM:       # %bb.0:
+; RV32XQCIBM-NEXT:    qc.insbi a0, 11, 4, 9
+; RV32XQCIBM-NEXT:    ret
+  %xor1 = xor i32 %in1, 5632
+  %and1 = and i32 7680, %xor1
+  %xor2 = xor i32 %and1, %in1
+  ret i32 %xor2
+}
+
+define i32 @insbi_comm_xor2(i32 %in1) nounwind {
+; RV32I-LABEL: insbi_comm_xor2:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    xori a1, a0, 176
+; RV32I-NEXT:    andi a1, a1, 496
+; RV32I-NEXT:    xor a0, a0, a1
+; RV32I-NEXT:    ret
+;
+; RV32XQCIBM-LABEL: insbi_comm_xor2:
+; RV32XQCIBM:       # %bb.0:
+; RV32XQCIBM-NEXT:    qc.insbi a0, 11, 5, 4
+; RV32XQCIBM-NEXT:    ret
+  %xor1 = xor i32 %in1, 176
+  %and1 = and i32 %xor1, 496
+  %xor2 = xor i32 %in1, %and1
+  ret i32 %xor2
+}
+
+define i32 @insbi_immg(i32 %in1) nounwind {
+; RV32I-LABEL: insbi_immg:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    xori a1, a0, 256
+; RV32I-NEXT:    andi a1, a1, 496
+; RV32I-NEXT:    xor a0, a1, a0
+; RV32I-NEXT:    ret
+;
+; RV32XQCIBM-LABEL: insbi_immg:
+; RV32XQCIBM:       # %bb.0:
+; RV32XQCIBM-NEXT:    li a1, 16
+; RV32XQCIBM-NEXT:    qc.insb a0, a1, 5, 4
+; RV32XQCIBM-NEXT:    ret
+  %xor1 = xor i32 %in1, 256
+  %and1 = and i32 %xor1, 496
+  %xor2 = xor i32 %and1, %in1
+  ret i32 %xor2
+}
+
+define i32 @insbi_not_shifted_mask(i32 %in1) nounwind {
+; RV32I-LABEL: insbi_not_shifted_mask:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    xori a1, a0, 128
+; RV32I-NEXT:    andi a1, a1, 716
+; RV32I-NEXT:    xor a0, a1, a0
+; RV32I-NEXT:    ret
+;
+; RV32XQCIBM-LABEL: insbi_not_shifted_mask:
+; RV32XQCIBM:       # %bb.0:
+; RV32XQCIBM-NEXT:    xori a1, a0, 128
+; RV32XQCIBM-NEXT:    andi a1, a1, 716
+; RV32XQCIBM-NEXT:    xor a0, a0, a1
+; RV32XQCIBM-NEXT:    ret
+  %xor1 = xor i32 %in1, 176
+  %and1 = and i32 %xor1, 716
+  %xor2 = xor i32 %and1, %in1
+  ret i32 %xor2
+}
+
+define i32 @insbi_width_z(i32 %in1) nounwind {
+; RV32I-LABEL: insbi_width_z:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    andi a1, a0, 256
+; RV32I-NEXT:    xor a0, a1, a0
+; RV32I-NEXT:    ret
+;
+; RV32XQCIBM-LABEL: insbi_width_z:
+; RV32XQCIBM:       # %bb.0:
+; RV32XQCIBM-NEXT:    andi a1, a0, 256
+; RV32XQCIBM-NEXT:    xor a0, a0, a1
+; RV32XQCIBM-NEXT:    ret
+  %xor1 = xor i32 %in1, 176
+  %and1 = and i32 %xor1, 256
+  %xor2 = xor i32 %and1, %in1
+  ret i32 %xor2
+}
+
+define i32 @insbi_mul_use_and(i32 %in1, i32 %in2) nounwind {
+; RV32I-LABEL: insbi_mul_use_and:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    li a1, 11
+; RV32I-NEXT:    li a2, 15
+; RV32I-NEXT:    slli a1, a1, 9
+; RV32I-NEXT:    slli a2, a2, 9
+; RV32I-NEXT:    xor a1, a0, a1
+; RV32I-NEXT:    and a1, a1, a2
+; RV32I-NEXT:    xor a2, a1, a0
+; RV32I-NEXT:    add a0, a0, a1
+; RV32I-NEXT:    add a0, a0, a2
+; RV32I-NEXT:    ret
+;
+; RV32XQCIBM-LABEL: insbi_mul_use_and:
+; RV32XQCIBM:       # %bb.0:
+; RV32XQCIBM-NEXT:    li a1, 11
+; RV32XQCIBM-NEXT:    li a2, 15
+; RV32XQCIBM-NEXT:    slli a1, a1, 9
+; RV32XQCIBM-NEXT:    slli a2, a2, 9
+; RV32XQCIBM-NEXT:    xor a1, a1, a0
+; RV32XQCIBM-NEXT:    and a1, a1, a2
+; RV32XQCIBM-NEXT:    xor a2, a1, a0
+; RV32XQCIBM-NEXT:    add a0, a0, a1
+; RV32XQCIBM-NEXT:    add a0, a0, a2
+; RV32XQCIBM-NEXT:    ret
+  %xor1 = xor i32 %in1, 5632
+  %and1 = and i32 %xor1, 7680
+  %xor2 = xor i32 %and1, %in1
+  %add1 = add i32 %in1, %and1
+  %add2 = add i32 %add1, %xor2
+  ret i32 %add2
+}
+
+define i32 @insbi_mul_use_xor(i32 %in1, i32 %in2) nounwind {
+; RV32I-LABEL: insbi_mul_use_xor:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    xori a1, a0, 176
+; RV32I-NEXT:    andi a2, a1, 496
+; RV32I-NEXT:    xor a2, a2, a0
+; RV32I-NEXT:    add a0, a0, a1
+; RV32I-NEXT:    add a0, a0, a2
+; RV32I-NEXT:    ret
+;
+; RV32XQCIBM-LABEL: insbi_mul_use_xor:
+; RV32XQCIBM:       # %bb.0:
+; RV32XQCIBM-NEXT:    xori a1, a0, 176
+; RV32XQCIBM-NEXT:    andi a2, a1, 496
+; RV32XQCIBM-NEXT:    xor a2, a2, a0
+; RV32XQCIBM-NEXT:    add a0, a0, a1
+; RV32XQCIBM-NEXT:    add a0, a0, a2
+; RV32XQCIBM-NEXT:    ret
+  %xor1 = xor i32 %in1, 176
+  %and1 = and i32 %xor1, 496
+  %xor2 = xor i32 %and1, %in1
+  %add1 = add i32 %in1, %xor1
+  %add2 = add i32 %add1, %xor2
+  ret i32 %add2
+}
+
+define i32 @insbi_imm_too_neg(i32 %in1) nounwind {
+; RV32I-LABEL: insbi_imm_too_neg:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    xori a1, a0, -34
+; RV32I-NEXT:    andi a1, a1, -2
+; RV32I-NEXT:    xor a0, a1, a0
+; RV32I-NEXT:    ret
+;
+; RV32XQCIBM-LABEL: insbi_imm_too_neg:
+; RV32XQCIBM:       # %bb.0:
+; RV32XQCIBM-NEXT:    li a1, -17
+; RV32XQCIBM-NEXT:    qc.insb a0, a1, 31, 1
+; RV32XQCIBM-NEXT:    ret
+  %xor1 = xor i32 %in1, -34
+  %and1 = and i32 %xor1, -2
+  %xor2 = xor i32 %and1, %in1
+  ret i32 %xor2
+}
+
+define i64 @insbi_i64(i64 %in1) nounwind {
+; RV32I-LABEL: insbi_i64:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    lui a2, 57344
+; RV32I-NEXT:    lui a3, 1044480
+; RV32I-NEXT:    xor a2, a0, a2
+; RV32I-NEXT:    and a2, a2, a3
+; RV32I-NEXT:    zext.b a3, a1
+; RV32I-NEXT:    xor a1, a3, a1
+; RV32I-NEXT:    xor a0, a2, a0
+; RV32I-NEXT:    ret
+;
+; RV32XQCIBM-LABEL: insbi_i64:
+; RV32XQCIBM:       # %bb.0:
+; RV32XQCIBM-NEXT:    qc.extu a2, a1, 8, 0
+; RV32XQCIBM-NEXT:    xor a1, a1, a2
+; RV32XQCIBM-NEXT:    qc.insbi a0, 14, 8, 24
+; RV32XQCIBM-NEXT:    ret
+  %xor1 = xor i64 %in1, 234881024
+  %and1 = and i64 %xor1, 1099494850560
+  %xor2 = xor i64 %and1, %in1
+  ret i64 %xor2
+}
+define i64 @insbi_i64_large_mask(i64 %in1) nounwind {
+; RV32I-LABEL: insbi_i64_large_mask:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    xori a2, a1, 9
+; RV32I-NEXT:    andi a2, a2, 15
+; RV32I-NEXT:    xor a1, a2, a1
+; RV32I-NEXT:    ret
+;
+; RV32XQCIBM-LABEL: insbi_i64_large_mask:
+; RV32XQCIBM:       # %bb.0:
+; RV32XQCIBM-NEXT:    qc.insbi a1, 9, 4, 0
+; RV32XQCIBM-NEXT:    ret
+  %xor1 = xor i64 %in1, 38654705664
+  %and1 = and i64 %xor1, 64424509440
+  %xor2 = xor i64 %and1, %in1
+  ret i64 %xor2
+}


        


More information about the llvm-commits mailing list