[llvm-branch-commits] [RISCV] Support CodeGen of Zilx extension (PR #209420)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Jul 14 02:54:02 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-risc-v
Author: Pengcheng Wang (wangpc-pp)
<details>
<summary>Changes</summary>
Thanks for `XTheadMemidx` extension that makes life easier.
---
Patch is 35.74 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/209420.diff
5 Files Affected:
- (modified) llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp (+12-7)
- (modified) llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h (+31-4)
- (modified) llvm/lib/Target/RISCV/RISCVInstrInfoZilx.td (+103)
- (modified) llvm/lib/Target/RISCV/RISCVOptWInstrs.cpp (+9)
- (added) llvm/test/CodeGen/RISCV/zilx.ll (+970)
``````````diff
diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index c86926e075c99..9208762e8d1fe 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -3736,7 +3736,8 @@ static bool isRegRegScaleLoadOrStore(SDNode *User, SDValue Add,
return false;
EVT VT = cast<MemSDNode>(User)->getMemoryVT();
if (!(VT.isScalarInteger() &&
- (Subtarget.hasVendorXTHeadMemIdx() || Subtarget.hasVendorXqcisls())) &&
+ (Subtarget.hasStdExtZilx() ||
+ Subtarget.hasVendorXTHeadMemIdx() || Subtarget.hasVendorXqcisls())) &&
!((VT == MVT::f32 || VT == MVT::f64) &&
Subtarget.hasVendorXTHeadFMemIdx()))
return false;
@@ -3785,7 +3786,7 @@ static bool isWorthFoldingIntoRegRegScale(const RISCVSubtarget &Subtarget,
}
bool RISCVDAGToDAGISel::SelectAddrRegRegScale(SDValue Addr,
- unsigned MaxShiftAmount,
+ ArrayRef<unsigned> Amounts,
SDValue &Base, SDValue &Index,
SDValue &Scale) {
if (Addr.getOpcode() != ISD::ADD)
@@ -3794,14 +3795,14 @@ bool RISCVDAGToDAGISel::SelectAddrRegRegScale(SDValue Addr,
SDValue RHS = Addr.getOperand(1);
EVT VT = Addr.getSimpleValueType();
- auto SelectShl = [this, VT, MaxShiftAmount](SDValue N, SDValue &Index,
- SDValue &Shift) {
+ auto SelectShl = [this, VT, Amounts](SDValue N, SDValue &Index,
+ SDValue &Shift) {
if (N.getOpcode() != ISD::SHL || !isa<ConstantSDNode>(N.getOperand(1)))
return false;
// Only match shifts by a value in range [0, MaxShiftAmount].
unsigned ShiftAmt = N.getConstantOperandVal(1);
- if (ShiftAmt > MaxShiftAmount)
+ if (!llvm::is_contained(Amounts, ShiftAmt))
return false;
Index = N.getOperand(0);
@@ -3861,6 +3862,10 @@ bool RISCVDAGToDAGISel::SelectAddrRegRegScale(SDValue Addr,
if (!isWorthFoldingIntoRegRegScale(*Subtarget, Addr))
return false;
+ // Bail out if 0 is not in candicate shift amounts.
+ if (!llvm::is_contained(Amounts, 0))
+ return false;
+
Base = LHS;
Index = RHS;
Scale = CurDAG->getTargetConstant(0, SDLoc(Addr), VT);
@@ -3868,11 +3873,11 @@ bool RISCVDAGToDAGISel::SelectAddrRegRegScale(SDValue Addr,
}
bool RISCVDAGToDAGISel::SelectAddrRegZextRegScale(SDValue Addr,
- unsigned MaxShiftAmount,
+ ArrayRef<unsigned> Amounts,
unsigned Bits, SDValue &Base,
SDValue &Index,
SDValue &Scale) {
- if (!SelectAddrRegRegScale(Addr, MaxShiftAmount, Base, Index, Scale))
+ if (!SelectAddrRegRegScale(Addr, Amounts, Base, Index, Scale))
return false;
if (Index.getOpcode() == ISD::AND) {
diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
index 190dc083d014a..41938f76397eb 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
@@ -53,23 +53,50 @@ class RISCVDAGToDAGISel : public SelectionDAGISel {
bool SelectAddrRegImm9(SDValue Addr, SDValue &Base, SDValue &Offset);
bool SelectAddrRegImmLsb00000(SDValue Addr, SDValue &Base, SDValue &Offset);
- bool SelectAddrRegRegScale(SDValue Addr, unsigned MaxShiftAmount,
+ bool SelectAddrRegRegScale(SDValue Addr, ArrayRef<unsigned> Amounts,
SDValue &Base, SDValue &Index, SDValue &Scale);
+ template <unsigned ShiftAmount>
+ bool SelectAddrRegRegFixedScale(SDValue Addr, SDValue &Base, SDValue &Index) {
+ SDValue Scale;
+ if (!SelectAddrRegRegScale(Addr, ShiftAmount, Base, Index, Scale))
+ return false;
+ assert(Scale->getAsZExtVal() == ShiftAmount &&
+ "ShiftAmount doesn't match!");
+ return true;
+ }
+
template <unsigned MaxShift>
bool SelectAddrRegRegScale(SDValue Addr, SDValue &Base, SDValue &Index,
SDValue &Scale) {
- return SelectAddrRegRegScale(Addr, MaxShift, Base, Index, Scale);
+ SmallVector<unsigned, MaxShift> Amounts;
+ for (unsigned I = 0; I <= MaxShift; I++)
+ Amounts.push_back(I);
+ return SelectAddrRegRegScale(Addr, Amounts, Base, Index, Scale);
}
- bool SelectAddrRegZextRegScale(SDValue Addr, unsigned MaxShiftAmount,
+ bool SelectAddrRegZextRegScale(SDValue Addr, ArrayRef<unsigned> Amounts,
unsigned Bits, SDValue &Base, SDValue &Index,
SDValue &Scale);
+ template <unsigned ShiftAmount, unsigned Bits>
+ bool SelectAddrRegZextRegFixedScale(SDValue Addr, SDValue &Base,
+ SDValue &Index) {
+ SDValue Scale;
+ if (!SelectAddrRegZextRegScale(Addr, ShiftAmount, Bits, Base, Index, Scale))
+ return false;
+ assert(Scale->getAsZExtVal() == ShiftAmount &&
+ "ShiftAmount doesn't match!");
+ return true;
+ }
+
template <unsigned MaxShift, unsigned Bits>
bool SelectAddrRegZextRegScale(SDValue Addr, SDValue &Base, SDValue &Index,
SDValue &Scale) {
- return SelectAddrRegZextRegScale(Addr, MaxShift, Bits, Base, Index, Scale);
+ SmallVector<unsigned, MaxShift> Amounts;
+ for (unsigned I = 0; I <= MaxShift; I++)
+ Amounts.push_back(I);
+ return SelectAddrRegZextRegScale(Addr, Amounts, Bits, Base, Index, Scale);
}
bool SelectAddrRegReg(SDValue Addr, SDValue &Base, SDValue &Offset);
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZilx.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZilx.td
index 2c43e4e30eb31..8cd56ddee4846 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoZilx.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZilx.td
@@ -71,3 +71,106 @@ def LXWU_S_UW : ScaledIndexLoad<0b101, 0b10, 1, "lxwu.s.uw">, Sched<[WriteLDW, R
def LXD_S : ScaledIndexLoad<0b100, 0b11, 0, "lxd.s">, Sched<[WriteLDD, ReadMemBase, ReadMemBase]>;
def LXD_S_UW : ScaledIndexLoad<0b101, 0b11, 0, "lxd.s.uw">, Sched<[WriteLDD, ReadMemBase, ReadMemBase]>;
} // Predicates = [HasStdExtZilsx, IsRV64]
+
+class AddrRegReg<int N>
+ : ComplexPattern<iPTR, 2, "SelectAddrRegRegFixedScale<"#N#">">;
+class AddrRegZextReg<int N>
+ : ComplexPattern<i64, 2, "SelectAddrRegZextRegFixedScale<"#N#", 32>",
+ [], [], 10>;
+
+def AddrRegReg0 : AddrRegReg<0>;
+def AddrRegReg1 : AddrRegReg<1>;
+def AddrRegReg2 : AddrRegReg<2>;
+def AddrRegReg3 : AddrRegReg<3>;
+
+def AddrRegZextReg0 : AddrRegZextReg<0>;
+def AddrRegZextReg1 : AddrRegZextReg<1>;
+def AddrRegZextReg2 : AddrRegZextReg<2>;
+def AddrRegZextReg3 : AddrRegZextReg<3>;
+
+let AddedComplexity = 2 in {
+class UnscaledIndexLoadPat<PatFrag LoadOp, RVInst Inst, ValueType vt = XLenVT>
+ : Pat<(vt (LoadOp (AddrRegReg0 (XLenVT GPR:$rs1), (XLenVT GPR:$rs2)))),
+ (Inst GPR:$rs1, GPR:$rs2)>;
+} // AddedComplexity = 2
+
+let AddedComplexity = 3 in {
+class UnscaledZextIndexLoadPat<PatFrag LoadOp, RVInst Inst, ValueType vt = XLenVT>
+ : Pat<(vt (LoadOp (AddrRegZextReg0 (XLenVT GPR:$rs1), (XLenVT GPR:$rs2)))),
+ (Inst GPR:$rs1, GPR:$rs2)>;
+} // AddedComplexity = 3
+
+let AddedComplexity = 4 in {
+class ScaledIndexLoadPat<PatFrag LoadOp, RVInst Inst, int Scale, ValueType vt = XLenVT>
+ : Pat<(vt (LoadOp (!cast<AddrRegReg>("AddrRegReg" # Scale)
+ (XLenVT GPR:$rs1), (XLenVT GPR:$rs2)))),
+ (Inst GPR:$rs1, GPR:$rs2)>;
+} // AddedComplexity = 4
+
+let AddedComplexity = 6 in {
+class ScaledZextIndexLoadPat<PatFrag LoadOp, RVInst Inst, int Scale, ValueType vt = XLenVT>
+ : Pat<(vt (LoadOp (!cast<AddrRegZextReg>("AddrRegZextReg" # Scale)
+ (XLenVT GPR:$rs1), (XLenVT GPR:$rs2)))),
+ (Inst GPR:$rs1, GPR:$rs2)>;
+} // AddedComplexity = 6
+
+// Patterns
+let Predicates = [HasStdExtZilx] in {
+def : UnscaledIndexLoadPat<extloadi8, LXB>;
+def : UnscaledIndexLoadPat<sextloadi8, LXB>;
+def : UnscaledIndexLoadPat<zextloadi8, LXBU>;
+
+def : UnscaledIndexLoadPat<extloadi16, LXH>;
+def : UnscaledIndexLoadPat<sextloadi16, LXH>;
+def : UnscaledIndexLoadPat<zextloadi16, LXHU>;
+
+def : UnscaledIndexLoadPat<load, LXW, i32>;
+
+def : ScaledIndexLoadPat<extloadi16, LXH_S, 1>;
+def : ScaledIndexLoadPat<sextloadi16, LXH_S, 1>;
+def : ScaledIndexLoadPat<zextloadi16, LXHU_S, 1>;
+
+def : ScaledIndexLoadPat<load, LXW_S, 2, i32>;
+} // Predicates = [HasStdExtZilx]
+
+let Predicates = [HasStdExtZilx, IsRV64] in {
+def : UnscaledIndexLoadPat<extloadi32, LXW, i64>;
+def : UnscaledIndexLoadPat<sextloadi32, LXW, i64>;
+def : UnscaledIndexLoadPat<zextloadi32, LXWU, i64>;
+
+def : UnscaledIndexLoadPat<load, LXD, i64>;
+
+def : ScaledIndexLoadPat<extloadi32, LXW_S, 2, i64>;
+def : ScaledIndexLoadPat<sextloadi32, LXW_S, 2, i64>;
+def : ScaledIndexLoadPat<zextloadi32, LXWU_S, 2, i64>;
+
+def : ScaledIndexLoadPat<load, LXD_S, 3, i64>;
+
+def : UnscaledZextIndexLoadPat<extloadi8, LXB_UW>;
+def : UnscaledZextIndexLoadPat<sextloadi8, LXB_UW>;
+def : UnscaledZextIndexLoadPat<zextloadi8, LXBU_UW>;
+
+def : UnscaledZextIndexLoadPat<extloadi16, LXH_UW>;
+def : UnscaledZextIndexLoadPat<sextloadi16, LXH_UW>;
+def : UnscaledZextIndexLoadPat<zextloadi16, LXHU_UW>;
+
+def : UnscaledZextIndexLoadPat<load, LXW_UW, i32>;
+
+def : UnscaledZextIndexLoadPat<extloadi32, LXW_UW>;
+def : UnscaledZextIndexLoadPat<sextloadi32, LXW_UW>;
+def : UnscaledZextIndexLoadPat<zextloadi32, LXWU_UW>;
+
+def : UnscaledZextIndexLoadPat<load, LXD_UW>;
+
+def : ScaledZextIndexLoadPat<extloadi16, LXH_S_UW, 1>;
+def : ScaledZextIndexLoadPat<sextloadi16, LXH_S_UW, 1>;
+def : ScaledZextIndexLoadPat<zextloadi16, LXHU_S_UW, 1>;
+
+def : ScaledZextIndexLoadPat<load, LXW_S_UW, 2, i32>;
+
+def : ScaledZextIndexLoadPat<extloadi32, LXW_S_UW, 2, i64>;
+def : ScaledZextIndexLoadPat<sextloadi32, LXW_S_UW, 2, i64>;
+def : ScaledZextIndexLoadPat<zextloadi32, LXWU_S_UW, 2, i64>;
+
+def : ScaledZextIndexLoadPat<load, LXD_S_UW, 3, i64>;
+} // Predicates = [HasStdExtZilx, IsRV64]
diff --git a/llvm/lib/Target/RISCV/RISCVOptWInstrs.cpp b/llvm/lib/Target/RISCV/RISCVOptWInstrs.cpp
index 1ad2956320b9d..01423fa11e66e 100644
--- a/llvm/lib/Target/RISCV/RISCVOptWInstrs.cpp
+++ b/llvm/lib/Target/RISCV/RISCVOptWInstrs.cpp
@@ -689,6 +689,8 @@ static bool isSignExtendedW(Register SrcReg, const RISCVSubtarget &ST,
[[fallthrough]];
case RISCV::ADD:
case RISCV::LWU:
+ case RISCV::LXD:
+ case RISCV::LXWU:
case RISCV::MUL:
case RISCV::SUB:
if (hasAllWUsers(*MI, ST, MRI)) {
@@ -713,6 +715,9 @@ static unsigned getWOp(unsigned Opcode) {
case RISCV::LD:
case RISCV::LWU:
return RISCV::LW;
+ case RISCV::LXD:
+ case RISCV::LXWU:
+ return RISCV::LXW;
case RISCV::MUL:
return RISCV::MULW;
case RISCV::SLLI:
@@ -835,6 +840,10 @@ bool RISCVOptWInstrs::canonicalizeWSuffixes(MachineFunction &MF,
case RISCV::LWU:
WOpc = RISCV::LW;
break;
+ case RISCV::LXD:
+ case RISCV::LXWU:
+ WOpc = RISCV::LXW;
+ break;
}
if (ShouldStripW && NonWOpc.has_value() && hasAllWUsers(MI, ST, MRI)) {
diff --git a/llvm/test/CodeGen/RISCV/zilx.ll b/llvm/test/CodeGen/RISCV/zilx.ll
new file mode 100644
index 0000000000000..3a27d801230a7
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/zilx.ll
@@ -0,0 +1,970 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: sed 's/iXLen/i32/g' %s | llc -mtriple=riscv32 -verify-machineinstrs \
+; RUN: | FileCheck -check-prefix=RV32 %s
+; RUN: sed 's/iXLen/i32/g' %s | llc -mtriple=riscv32 -mattr=+experimental-zilx -verify-machineinstrs \
+; RUN: | FileCheck -check-prefix=RV32-ZILX %s
+; RUN: sed 's/iXLen/i64/g' %s | llc -mtriple=riscv64 -verify-machineinstrs \
+; RUN: | FileCheck -check-prefix=RV64 %s
+; RUN: sed 's/iXLen/i64/g' %s | llc -mtriple=riscv64 -mattr=+experimental-zilx -verify-machineinstrs \
+; RUN: | FileCheck -check-prefix=RV64-ZILX %s
+
+;------------------------------------------------------------------------------
+; Unscaled Load
+;------------------------------------------------------------------------------
+
+define i8 @lxb_anyext(ptr %a, iXLen %b) {
+; RV32-LABEL: lxb_anyext:
+; RV32: # %bb.0:
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lbu a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxb_anyext:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: lxb a0, (a0), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxb_anyext:
+; RV64: # %bb.0:
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lbu a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxb_anyext:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxb a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+ %1 = getelementptr i8, ptr %a, iXLen %b
+ %2 = load i8, ptr %1, align 1
+ ret i8 %2
+}
+
+define i32 @lxb(ptr %a, iXLen %b) {
+; RV32-LABEL: lxb:
+; RV32: # %bb.0:
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lb a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxb:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: lxb a0, (a0), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxb:
+; RV64: # %bb.0:
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lb a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxb:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxb a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+ %1 = getelementptr i8, ptr %a, iXLen %b
+ %2 = load i8, ptr %1, align 1
+ %3 = sext i8 %2 to i32
+ ret i32 %3
+}
+
+define i8 @lxb_uw_anyext(ptr %a, i32 %b) {
+; RV32-LABEL: lxb_uw_anyext:
+; RV32: # %bb.0:
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lbu a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxb_uw_anyext:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: lxb a0, (a0), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxb_uw_anyext:
+; RV64: # %bb.0:
+; RV64-NEXT: slli a1, a1, 32
+; RV64-NEXT: srli a1, a1, 32
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lbu a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxb_uw_anyext:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxb.uw a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+ %1 = zext i32 %b to i64
+ %2 = getelementptr i8, ptr %a, i64 %1
+ %3 = load i8, ptr %2, align 1
+ ret i8 %3
+}
+
+define i32 @lxb_uw(ptr %a, i32 %b) {
+; RV32-LABEL: lxb_uw:
+; RV32: # %bb.0:
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lb a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxb_uw:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: lxb a0, (a0), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxb_uw:
+; RV64: # %bb.0:
+; RV64-NEXT: slli a1, a1, 32
+; RV64-NEXT: srli a1, a1, 32
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lb a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxb_uw:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxb.uw a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+ %1 = zext i32 %b to i64
+ %2 = getelementptr i8, ptr %a, i64 %1
+ %3 = load i8, ptr %2, align 1
+ %4 = sext i8 %3 to i32
+ ret i32 %4
+}
+
+define i32 @lxbu(ptr %a, iXLen %b) {
+; RV32-LABEL: lxbu:
+; RV32: # %bb.0:
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lbu a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxbu:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: lxbu a0, (a0), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxbu:
+; RV64: # %bb.0:
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lbu a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxbu:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxbu a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+ %1 = getelementptr i8, ptr %a, iXLen %b
+ %2 = load i8, ptr %1, align 1
+ %3 = zext i8 %2 to i32
+ ret i32 %3
+}
+
+define i32 @lxbu_uw(ptr %a, i32 %b) {
+; RV32-LABEL: lxbu_uw:
+; RV32: # %bb.0:
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lbu a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxbu_uw:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: lxbu a0, (a0), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxbu_uw:
+; RV64: # %bb.0:
+; RV64-NEXT: slli a1, a1, 32
+; RV64-NEXT: srli a1, a1, 32
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lbu a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxbu_uw:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxbu.uw a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+ %1 = zext i32 %b to i64
+ %2 = getelementptr i8, ptr %a, i64 %1
+ %3 = load i8, ptr %2, align 1
+ %4 = zext i8 %3 to i32
+ ret i32 %4
+}
+
+define i16 @lxh(ptr %a, iXLen %b) {
+; RV32-LABEL: lxh:
+; RV32: # %bb.0:
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lh a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxh:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: lxh a0, (a0), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxh:
+; RV64: # %bb.0:
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lh a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxh:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxh a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+ %1 = getelementptr i8, ptr %a, iXLen %b
+ %2 = load i16, ptr %1, align 2
+ ret i16 %2
+}
+
+define i16 @lxh_uw(ptr %a, i32 %b) {
+; RV32-LABEL: lxh_uw:
+; RV32: # %bb.0:
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lh a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxh_uw:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: lxh a0, (a0), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxh_uw:
+; RV64: # %bb.0:
+; RV64-NEXT: slli a1, a1, 32
+; RV64-NEXT: srli a1, a1, 32
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lh a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxh_uw:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxh.uw a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+ %1 = zext i32 %b to i64
+ %2 = getelementptr i8, ptr %a, i64 %1
+ %3 = load i16, ptr %2, align 2
+ ret i16 %3
+}
+
+define i32 @lxhu(ptr %a, iXLen %b) {
+; RV32-LABEL: lxhu:
+; RV32: # %bb.0:
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lhu a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxhu:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: lxhu a0, (a0), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxhu:
+; RV64: # %bb.0:
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lhu a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxhu:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxhu a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+ %1 = getelementptr i8, ptr %a, iXLen %b
+ %2 = load i16, ptr %1, align 2
+ %3 = zext i16 %2 to i32
+ ret i32 %3
+}
+
+define i32 @lxhu_uw(ptr %a, i32 %b) {
+; RV32-LABEL: lxhu_uw:
+; RV32: # %bb.0:
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lhu a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxhu_uw:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: lxhu a0, (a0), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxhu_uw:
+; RV64: # %bb.0:
+; RV64-NEXT: slli a1, a1, 32
+; RV64-NEXT: srli a1, a1, 32
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lhu a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxhu_uw:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxhu.uw a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+ %1 = zext i32 %b to i64
+ %2 = getelementptr i8, ptr %a, i64 %1
+ %3 = load i16, ptr %2, align 2
+ %4 = zext i16 %3 to i32
+ ret i32 %4
+}
+
+define i32 @lxw(ptr %a, iXLen %b) {
+; RV32-LABEL: lxw:
+; RV32: # %bb.0:
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lw a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxw:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: lxw a0, (a0), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxw:
+; RV64: # %bb.0:
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lw a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxw:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxw a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+ %1 = getelementptr i8, ptr %a, iXLen %b
+ %2 = load i32, ptr %1, align 4
+ ret i32 %2
+}
+
+define i32 @lxw_uw(ptr %a, i32 %b) {
+; RV32-LABEL: lxw_uw:
+; RV32: # %bb.0:
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lw a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxw_uw:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: lxw a0, (a0), a1
+; R...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/209420
More information about the llvm-branch-commits
mailing list