[llvm] [RISCV] Use QC.INSBI instead of ORI when possible (PR #147349)
Sudharsan Veeravalli via llvm-commits
llvm-commits at lists.llvm.org
Mon Jul 7 21:59:39 PDT 2025
https://github.com/svs-quic updated https://github.com/llvm/llvm-project/pull/147349
>From c554cee293c61abf3648decfd20192fbd16f485a Mon Sep 17 00:00:00 2001
From: Sudharsan Veeravalli <quic_svs at quicinc.com>
Date: Mon, 7 Jul 2025 22:23:55 +0530
Subject: [PATCH 1/3] [RISCV] Use QC.INSBI instead of ORI when possible
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.
---
llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp | 37 +++++++-
.../test/CodeGen/RISCV/xqcibm-cto-clo-brev.ll | 3 +-
llvm/test/CodeGen/RISCV/xqcibm-insert.ll | 88 +++++++++++++++++++
3 files changed, 125 insertions(+), 3 deletions(-)
create mode 100644 llvm/test/CodeGen/RISCV/xqcibm-insert.ll
diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index 6298c7d5e9ef5..195e264582673 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -1298,7 +1298,42 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
ReplaceNode(Node, SRAI);
return;
}
- case ISD::OR:
+ case ISD::OR: {
+ if (Subtarget->hasVendorXqcibm()) {
+ auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1));
+ if (!N1C)
+ break;
+
+ int32_t C1 = N1C->getSExtValue();
+ // 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)
+ if (isShiftedMask_32(C1) && !isInt<12>(C1)) {
+ const unsigned Leading = llvm::countl_zero((uint32_t)C1);
+ const unsigned Trailing = llvm::countr_zero((uint32_t)C1);
+
+ // 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 ((Leading + Trailing == 31) && Subtarget->hasStdExtZbs())
+ break;
+
+ const unsigned Width = 32 - Leading - Trailing;
+ SmallVector<SDValue, 4> 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;
+ }
+ }
+
+ if (tryShrinkShlLogicImm(Node))
+ return;
+
+ break;
+ }
case ISD::XOR:
if (tryShrinkShlLogicImm(Node))
return;
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
+}
>From e24a29150b4cf8231ea4987bc963229eb7f6a4d2 Mon Sep 17 00:00:00 2001
From: Sudharsan Veeravalli <quic_svs at quicinc.com>
Date: Tue, 8 Jul 2025 08:10:20 +0530
Subject: [PATCH 2/3] Move code into separate function
---
llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp | 68 ++++++++++++---------
llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h | 1 +
2 files changed, 40 insertions(+), 29 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index 195e264582673..a96ecc0c7c430 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);
+
+ SmallVector<SDValue, 4> 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())
@@ -1299,35 +1336,8 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
return;
}
case ISD::OR: {
- if (Subtarget->hasVendorXqcibm()) {
- auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1));
- if (!N1C)
- break;
-
- int32_t C1 = N1C->getSExtValue();
- // 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)
- if (isShiftedMask_32(C1) && !isInt<12>(C1)) {
- const unsigned Leading = llvm::countl_zero((uint32_t)C1);
- const unsigned Trailing = llvm::countr_zero((uint32_t)C1);
-
- // 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 ((Leading + Trailing == 31) && Subtarget->hasStdExtZbs())
- break;
-
- const unsigned Width = 32 - Leading - Trailing;
- SmallVector<SDValue, 4> 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;
- }
- }
+ if (trySignedBitfieldInsertInMask(Node))
+ return;
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,
>From f10ce1962595a67938685f881e89eac961334554 Mon Sep 17 00:00:00 2001
From: Sudharsan Veeravalli <quic_svs at quicinc.com>
Date: Tue, 8 Jul 2025 10:29:01 +0530
Subject: [PATCH 3/3] Simplify code
---
llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index a96ecc0c7c430..1a6f65a789a28 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -691,7 +691,7 @@ bool RISCVDAGToDAGISel::trySignedBitfieldInsertInMask(SDNode *Node) {
return false;
int32_t C1 = N1C->getSExtValue();
- if (!(isShiftedMask_32(C1) && !isInt<12>(C1)))
+ if (!isShiftedMask_32(C1) || isInt<12>(C1))
return false;
// If C1 is a shifted mask (but can't be formed as an ORI),
@@ -710,9 +710,9 @@ bool RISCVDAGToDAGISel::trySignedBitfieldInsertInMask(SDNode *Node) {
SDLoc DL(Node);
MVT VT = Node->getSimpleValueType(0);
- SmallVector<SDValue, 4> Ops = {CurDAG->getSignedTargetConstant(-1, DL, VT),
- CurDAG->getTargetConstant(Width, DL, VT),
- CurDAG->getTargetConstant(Trailing, DL, VT)};
+ 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;
More information about the llvm-commits
mailing list