[llvm] 6b95aa6 - [RISCV] Use QC.INSBI for OR with immediate when ORI isn't possible (#147349)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Jul 7 23:08:08 PDT 2025
Author: Sudharsan Veeravalli
Date: 2025-07-08T11:38:04+05:30
New Revision: 6b95aa6444a0a63c13893b0629eb20e2ecaf322e
URL: https://github.com/llvm/llvm-project/commit/6b95aa6444a0a63c13893b0629eb20e2ecaf322e
DIFF: https://github.com/llvm/llvm-project/commit/6b95aa6444a0a63c13893b0629eb20e2ecaf322e.diff
LOG: [RISCV] Use QC.INSBI for OR with immediate when ORI isn't possible (#147349)
When the immediate to the ORI is a ShiftedMask_32 that does not fit in
12-bits we can use the QC.INSBI instruction instead. We do not do this
for cases where the ORI can be replaced with a BSETI since these can be
compressesd when the Xqcibm extension (which QC.INSBI is a part of) is
enabled.
Added:
llvm/test/CodeGen/RISCV/xqcibm-insert.ll
Modified:
llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
llvm/test/CodeGen/RISCV/xqcibm-cto-clo-brev.ll
Removed:
################################################################################
diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index 6298c7d5e9ef5..1a6f65a789a28 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -681,6 +681,43 @@ bool RISCVDAGToDAGISel::trySignedBitfieldExtract(SDNode *Node) {
return false;
}
+bool RISCVDAGToDAGISel::trySignedBitfieldInsertInMask(SDNode *Node) {
+ // Supported only in Xqcibm for now.
+ if (!Subtarget->hasVendorXqcibm())
+ return false;
+
+ auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1));
+ if (!N1C)
+ return false;
+
+ int32_t C1 = N1C->getSExtValue();
+ if (!isShiftedMask_32(C1) || isInt<12>(C1))
+ return false;
+
+ // If C1 is a shifted mask (but can't be formed as an ORI),
+ // use a bitfield insert of -1.
+ // Transform (or x, C1)
+ // -> (qc.insbi x, width, shift)
+ const unsigned Leading = llvm::countl_zero((uint32_t)C1);
+ const unsigned Trailing = llvm::countr_zero((uint32_t)C1);
+ const unsigned Width = 32 - Leading - Trailing;
+
+ // If Zbs is enabled and it is a single bit set we can use BSETI which
+ // can be compressed to C_BSETI when Xqcibm in enabled.
+ if (Width == 1 && Subtarget->hasStdExtZbs())
+ return false;
+
+ SDLoc DL(Node);
+ MVT VT = Node->getSimpleValueType(0);
+
+ SDValue Ops[] = {CurDAG->getSignedTargetConstant(-1, DL, VT),
+ CurDAG->getTargetConstant(Width, DL, VT),
+ CurDAG->getTargetConstant(Trailing, DL, VT)};
+ SDNode *BitIns = CurDAG->getMachineNode(RISCV::QC_INSBI, DL, VT, Ops);
+ ReplaceNode(Node, BitIns);
+ return true;
+}
+
bool RISCVDAGToDAGISel::trySignedBitfieldInsertInSign(SDNode *Node) {
// Only supported with XAndesPerf at the moment.
if (!Subtarget->hasVendorXAndesPerf())
@@ -1298,7 +1335,15 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
ReplaceNode(Node, SRAI);
return;
}
- case ISD::OR:
+ case ISD::OR: {
+ if (trySignedBitfieldInsertInMask(Node))
+ return;
+
+ if (tryShrinkShlLogicImm(Node))
+ return;
+
+ break;
+ }
case ISD::XOR:
if (tryShrinkShlLogicImm(Node))
return;
diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
index 66d878f037446..29ee3ae31606e 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
@@ -79,6 +79,7 @@ class RISCVDAGToDAGISel : public SelectionDAGISel {
bool tryShrinkShlLogicImm(SDNode *Node);
bool trySignedBitfieldExtract(SDNode *Node);
bool trySignedBitfieldInsertInSign(SDNode *Node);
+ bool trySignedBitfieldInsertInMask(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-cto-clo-brev.ll b/llvm/test/CodeGen/RISCV/xqcibm-cto-clo-brev.ll
index 691c5bec7fb51..f227fa9aa423d 100644
--- a/llvm/test/CodeGen/RISCV/xqcibm-cto-clo-brev.ll
+++ b/llvm/test/CodeGen/RISCV/xqcibm-cto-clo-brev.ll
@@ -105,8 +105,7 @@ define i16 @test_cttz_i16(i16 %a) nounwind {
;
; RV32ZBBXQCIBM-LABEL: test_cttz_i16:
; RV32ZBBXQCIBM: # %bb.0:
-; RV32ZBBXQCIBM-NEXT: lui a1, 16
-; RV32ZBBXQCIBM-NEXT: orn a0, a1, a0
+; RV32ZBBXQCIBM-NEXT: qc.insbi a0, -1, 1, 16
; RV32ZBBXQCIBM-NEXT: ctz a0, a0
; RV32ZBBXQCIBM-NEXT: ret
%1 = xor i16 %a, -1
diff --git a/llvm/test/CodeGen/RISCV/xqcibm-insert.ll b/llvm/test/CodeGen/RISCV/xqcibm-insert.ll
new file mode 100644
index 0000000000000..6b7f9ae856625
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/xqcibm-insert.ll
@@ -0,0 +1,88 @@
+; 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=RV32IXQCIBM
+; RUN: llc -mtriple=riscv32 -mattr=+experimental-xqcibm,+zbs -verify-machineinstrs < %s \
+; RUN: | FileCheck %s -check-prefixes=RV32IXQCIBMZBS
+
+
+define i32 @test_ori(i32 %a) nounwind {
+; RV32I-LABEL: test_ori:
+; RV32I: # %bb.0:
+; RV32I-NEXT: ori a0, a0, 511
+; RV32I-NEXT: ret
+;
+; RV32IXQCIBM-LABEL: test_ori:
+; RV32IXQCIBM: # %bb.0:
+; RV32IXQCIBM-NEXT: ori a0, a0, 511
+; RV32IXQCIBM-NEXT: ret
+;
+; RV32IXQCIBMZBS-LABEL: test_ori:
+; RV32IXQCIBMZBS: # %bb.0:
+; RV32IXQCIBMZBS-NEXT: ori a0, a0, 511
+; RV32IXQCIBMZBS-NEXT: ret
+ %or = or i32 %a, 511
+ ret i32 %or
+}
+
+define i32 @test_insbi_mask(i32 %a) nounwind {
+; RV32I-LABEL: test_insbi_mask:
+; RV32I: # %bb.0:
+; RV32I-NEXT: lui a1, 16
+; RV32I-NEXT: addi a1, a1, -1
+; RV32I-NEXT: or a0, a0, a1
+; RV32I-NEXT: ret
+;
+; RV32IXQCIBM-LABEL: test_insbi_mask:
+; RV32IXQCIBM: # %bb.0:
+; RV32IXQCIBM-NEXT: qc.insbi a0, -1, 16, 0
+; RV32IXQCIBM-NEXT: ret
+;
+; RV32IXQCIBMZBS-LABEL: test_insbi_mask:
+; RV32IXQCIBMZBS: # %bb.0:
+; RV32IXQCIBMZBS-NEXT: qc.insbi a0, -1, 16, 0
+; RV32IXQCIBMZBS-NEXT: ret
+ %or = or i32 %a, 65535
+ ret i32 %or
+}
+
+define i32 @test_insbi_shifted_mask(i32 %a) nounwind {
+; RV32I-LABEL: test_insbi_shifted_mask:
+; RV32I: # %bb.0:
+; RV32I-NEXT: lui a1, 15
+; RV32I-NEXT: or a0, a0, a1
+; RV32I-NEXT: ret
+;
+; RV32IXQCIBM-LABEL: test_insbi_shifted_mask:
+; RV32IXQCIBM: # %bb.0:
+; RV32IXQCIBM-NEXT: qc.insbi a0, -1, 4, 12
+; RV32IXQCIBM-NEXT: ret
+;
+; RV32IXQCIBMZBS-LABEL: test_insbi_shifted_mask:
+; RV32IXQCIBMZBS: # %bb.0:
+; RV32IXQCIBMZBS-NEXT: qc.insbi a0, -1, 4, 12
+; RV32IXQCIBMZBS-NEXT: ret
+ %or = or i32 %a, 61440
+ ret i32 %or
+}
+
+define i32 @test_single_bit_set(i32 %a) nounwind {
+; RV32I-LABEL: test_single_bit_set:
+; RV32I: # %bb.0:
+; RV32I-NEXT: lui a1, 1
+; RV32I-NEXT: or a0, a0, a1
+; RV32I-NEXT: ret
+;
+; RV32IXQCIBM-LABEL: test_single_bit_set:
+; RV32IXQCIBM: # %bb.0:
+; RV32IXQCIBM-NEXT: qc.insbi a0, -1, 1, 12
+; RV32IXQCIBM-NEXT: ret
+;
+; RV32IXQCIBMZBS-LABEL: test_single_bit_set:
+; RV32IXQCIBMZBS: # %bb.0:
+; RV32IXQCIBMZBS-NEXT: bseti a0, a0, 12
+; RV32IXQCIBMZBS-NEXT: ret
+ %or = or i32 %a, 4096
+ ret i32 %or
+}
More information about the llvm-commits
mailing list