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

via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 6 23:20:56 PDT 2025


https://github.com/hchandel created https://github.com/llvm/llvm-project/pull/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.

>From 61124e54e27d8ae404deb49fe04ac70347d1f692 Mon Sep 17 00:00:00 2001
From: Harsh Chandel <hchandel at qti.qualcomm.com>
Date: Thu, 7 Aug 2025 11:36:09 +0530
Subject: [PATCH] [RISCV] Add CodeGen support for qc.insbi and qc.insb insert
 instructions

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.

Change-Id: Id47db41fa25c37117ecaf1f20eff63bc87f1c073
---
 llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp |  55 ++++
 llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h   |   1 +
 llvm/test/CodeGen/RISCV/xqcibm-insbi.ll     | 262 ++++++++++++++++++++
 3 files changed, 318 insertions(+)
 create mode 100644 llvm/test/CodeGen/RISCV/xqcibm-insbi.ll

diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index 5998653129209..9f77e5e1555d6 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,57 @@ 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;
+
+  // Width must be in 1..32(inclusive).
+  if (Width > 32 || Width == 0)
+    return false;
+
+  if (!isUInt<5>(ShAmt))
+    return false;
+
+  int64_t Imm = CImm.getSExtValue();
+  Imm >>= ShAmt;
+  if (!isInt<32>(Imm))
+    return false;
+
+  SDLoc DL(Node);
+  auto Opc = RISCV::QC_INSB;
+  SDValue getImm = selectImm(CurDAG, DL, MVT::i32, Imm, *Subtarget);
+
+  if (isInt<5>(Imm)) {
+    Opc = RISCV::QC_INSBI;
+    getImm = CurDAG->getSignedTargetConstant(Imm, DL, MVT::i32);
+  }
+
+  SDValue Ops[] = {X, getImm, 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 +1401,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