[llvm] 8a1ff7f - [RISCV] Support CodeGen of Zilx extension
via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 29 23:52:32 PDT 2026
Author: Pengcheng Wang
Date: 2026-07-30T14:52:23+08:00
New Revision: 8a1ff7feefc5825cc10349b8946fe555f435d53b
URL: https://github.com/llvm/llvm-project/commit/8a1ff7feefc5825cc10349b8946fe555f435d53b
DIFF: https://github.com/llvm/llvm-project/commit/8a1ff7feefc5825cc10349b8946fe555f435d53b.diff
LOG: [RISCV] Support CodeGen of Zilx extension
Thanks for `XTheadMemIdx` extension that makes life easier.
Reviewers: lukel97, topperc, kito-cheng, tclin914
Reviewed By: topperc
Pull Request: https://github.com/llvm/llvm-project/pull/209420
Added:
llvm/test/CodeGen/RISCV/zilx-opt-w-instrs.mir
llvm/test/CodeGen/RISCV/zilx.ll
Modified:
llvm/docs/ReleaseNotes.md
llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
llvm/lib/Target/RISCV/RISCVInstrInfoZilx.td
llvm/lib/Target/RISCV/RISCVOptWInstrs.cpp
Removed:
################################################################################
diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index b9ee0425d06f7..b26fb21e3ad29 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -89,7 +89,8 @@ Makes programs 10x faster by doing Special New Thing.
### Changes to the RISC-V Backend
-* Adds experimental assembler support for the `Zilx` (Indexed Integer Load) extension.
+* Adds experimental assembler/CodeGen support for the `Zilx` (Indexed Integer
+ Load) extension.
### Changes to the WebAssembly Backend
diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index 611306b6ab7b3..f36f27769a353 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -3756,17 +3756,21 @@ bool RISCVDAGToDAGISel::SelectAddrRegImmLsb00000(SDValue Addr, SDValue &Base,
/// Return true if this a load/store that we have a RegRegScale instruction for.
static bool isRegRegScaleLoadOrStore(SDNode *User, SDValue Add,
const RISCVSubtarget &Subtarget) {
- if (User->getOpcode() != ISD::LOAD && User->getOpcode() != ISD::STORE)
+ unsigned UserOpc = User->getOpcode();
+ if (UserOpc != ISD::LOAD && UserOpc != ISD::STORE)
return false;
EVT VT = cast<MemSDNode>(User)->getMemoryVT();
- if (!(VT.isScalarInteger() &&
- (Subtarget.hasVendorXTHeadMemIdx() || Subtarget.hasVendorXqcisls())) &&
+ // Zilx only provides indexed loads, so it must not enable reg+reg-scale
+ // address folding for stores. XTheadMemIdx and Xqcisls have scaled stores.
+ bool HasScalarIntegerMemIdx =
+ Subtarget.hasVendorXTHeadMemIdx() || Subtarget.hasVendorXqcisls() ||
+ (Subtarget.hasStdExtZilx() && UserOpc == ISD::LOAD);
+ if (!(VT.isScalarInteger() && HasScalarIntegerMemIdx) &&
!((VT == MVT::f32 || VT == MVT::f64) &&
Subtarget.hasVendorXTHeadFMemIdx()))
return false;
// Don't allow stores of the value. It must be used as the address.
- if (User->getOpcode() == ISD::STORE &&
- cast<StoreSDNode>(User)->getValue() == Add)
+ if (UserOpc == ISD::STORE && cast<StoreSDNode>(User)->getValue() == Add)
return false;
return true;
@@ -3809,7 +3813,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)
@@ -3818,14 +3822,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);
@@ -3885,6 +3889,10 @@ bool RISCVDAGToDAGISel::SelectAddrRegRegScale(SDValue Addr,
if (!isWorthFoldingIntoRegRegScale(*Subtarget, Addr))
return false;
+ // Bail out if 0 is not in candidate shift amounts.
+ if (!llvm::is_contained(Amounts, 0))
+ return false;
+
Base = LHS;
Index = RHS;
Scale = CurDAG->getTargetConstant(0, SDLoc(Addr), VT);
@@ -3892,11 +3900,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..fabd32750a73e 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h
@@ -53,23 +53,48 @@ 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);
+ std::array<unsigned, MaxShift + 1> Amounts;
+ std::iota(Amounts.begin(), Amounts.end(), 0);
+ 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);
+ std::array<unsigned, MaxShift + 1> Amounts;
+ std::iota(Amounts.begin(), Amounts.end(), 0);
+ 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 1db547a77daa7..4555c07b1d850 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoZilx.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZilx.td
@@ -31,6 +31,7 @@ class ZilxLoad<bits<5> funct5, bits<3> funct3, string opcodestr>
//===----------------------------------------------------------------------===//
let Predicates = [HasStdExtZilx] in {
+let IsSignExtendingOpW = 1 in {
// Unscaled indexed loads: address = base + index. Byte loads are not provided
// in the unscaled mode.
def LXH : ZilxLoad<0b10010, 0b001, "lxh">,
@@ -52,6 +53,7 @@ def LXSBU : ZilxLoad<0b11010, 0b100, "lxsbu">,
Sched<[WriteLDB, ReadMemBase, ReadMemBase]>;
def LXSHU : ZilxLoad<0b11010, 0b101, "lxshu">,
Sched<[WriteLDH, ReadMemBase, ReadMemBase]>;
+} // IsSignExtendingOpW = 1
let append Predicates = [IsRV64] in {
// Unscaled indexed loads (RV64-only widths).
@@ -68,18 +70,25 @@ def LXSWU : ZilxLoad<0b11010, 0b110, "lxswu">,
// Scaled indexed loads with a zero-extended 32-bit index (RV64-only):
// address = base + (zext32(index) << log2(access-size)).
+let IsSignExtendingOpW = 1 in {
def LXSUWB : ZilxLoad<0b11110, 0b000, "lxsuwb">,
Sched<[WriteLDB, ReadMemBase, ReadMemBase]>;
def LXSUWH : ZilxLoad<0b11110, 0b001, "lxsuwh">,
Sched<[WriteLDH, ReadMemBase, ReadMemBase]>;
def LXSUWW : ZilxLoad<0b11110, 0b010, "lxsuww">,
Sched<[WriteLDW, ReadMemBase, ReadMemBase]>;
+} // IsSignExtendingOpW = 1
+
def LXSUWD : ZilxLoad<0b11110, 0b011, "lxsuwd">,
Sched<[WriteLDD, ReadMemBase, ReadMemBase]>;
+
+let IsSignExtendingOpW = 1 in {
def LXSUWBU : ZilxLoad<0b11110, 0b100, "lxsuwbu">,
Sched<[WriteLDB, ReadMemBase, ReadMemBase]>;
def LXSUWHU : ZilxLoad<0b11110, 0b101, "lxsuwhu">,
Sched<[WriteLDH, ReadMemBase, ReadMemBase]>;
+} // IsSignExtendingOpW = 1
+
def LXSUWWU : ZilxLoad<0b11110, 0b110, "lxsuwwu">,
Sched<[WriteLDW, ReadMemBase, ReadMemBase]>;
} // append Predicates = [IsRV64]
@@ -93,3 +102,107 @@ let Predicates = [HasStdExtZilx] in {
def : InstAlias<"lxb $rd, $rs2, $rs1", (LXSB GPR:$rd, GPRMemZeroOffset:$rs2, GPR:$rs1), 0>;
def : InstAlias<"lxbu $rd, $rs2, $rs1", (LXSBU GPR:$rd, GPRMemZeroOffset:$rs2, GPR:$rs1), 0>;
}
+
+//===----------------------------------------------------------------------===//
+// Pattern matching
+//===----------------------------------------------------------------------===//
+
+// The complexities below are chosen to give the indexed loads a strict
+// priority over the plain reg+imm loads and to encode which form is the more
+// specific match. Without an explicit complexity these patterns tie with the
+// base L{B,H,W,D}[U] patterns (which also match a "reg + reg" address as
+// base+0) and, being listed later, would never be selected. The required
+// ordering is:
+// base L* < unscaled (shift-amount 0) Zilx < scaled Zilx
+// For a given load only the shift-amount-0 form (which leaves the shift as a
+// separate slli) and the exactly-matching scaled form can compete, so a scaled
+// load only needs to outrank its own unscaled form; distinct non-zero shift
+// amounts never compete for the same node.
+class AddrRegReg<int N>
+ : ComplexPattern<iPTR, 2, "SelectAddrRegRegFixedScale<"#N#">",
+ [], [], !if(!eq(N, 0), 10, 11)>;
+// The zero-extended-index forms additionally fold the zext, so they are the
+// most specific match and must outrank the plain AddrRegReg forms above.
+class AddrRegZextReg<int N>
+ : ComplexPattern<i64, 2, "SelectAddrRegZextRegFixedScale<"#N#", 32>",
+ [], [], !if(!eq(N, 0), 20, 21)>;
+
+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>;
+
+// The addressing-mode ComplexPatterns bind the base first and the (shifted)
+// index second. Zilx encodes rs2 as the base (written in parentheses) and rs1
+// as the index, so the operands are emitted in that order.
+class UnscaledIndexLoadPat<PatFrag LoadOp, RVInst Inst, ValueType vt = XLenVT>
+ : Pat<(vt (LoadOp (AddrRegReg0 (XLenVT GPR:$base), (XLenVT GPR:$index)))),
+ (Inst GPRMemZeroOffset:$base, GPR:$index)>;
+
+class ScaledIndexLoadPat<PatFrag LoadOp, RVInst Inst, int Scale, ValueType vt = XLenVT>
+ : Pat<(vt (LoadOp (!cast<AddrRegReg>("AddrRegReg" # Scale)
+ (XLenVT GPR:$base), (XLenVT GPR:$index)))),
+ (Inst GPRMemZeroOffset:$base, GPR:$index)>;
+
+class ScaledZextIndexLoadPat<PatFrag LoadOp, RVInst Inst, int Scale, ValueType vt = XLenVT>
+ : Pat<(vt (LoadOp (!cast<AddrRegZextReg>("AddrRegZextReg" # Scale)
+ (XLenVT GPR:$base), (XLenVT GPR:$index)))),
+ (Inst GPRMemZeroOffset:$base, GPR:$index)>;
+
+// Patterns
+let Predicates = [HasStdExtZilx] in {
+// Byte loads only exist in scaled form, but the byte scale factor is 1, so
+// they match with shift amount 0 (address = base + index).
+def : UnscaledIndexLoadPat<extloadi8, LXSB>;
+def : UnscaledIndexLoadPat<sextloadi8, LXSB>;
+def : UnscaledIndexLoadPat<zextloadi8, LXSBU>;
+
+def : UnscaledIndexLoadPat<extloadi16, LXH>;
+def : UnscaledIndexLoadPat<sextloadi16, LXH>;
+def : UnscaledIndexLoadPat<zextloadi16, LXHU>;
+
+def : UnscaledIndexLoadPat<load, LXW, i32>;
+
+def : ScaledIndexLoadPat<extloadi16, LXSH, 1>;
+def : ScaledIndexLoadPat<sextloadi16, LXSH, 1>;
+def : ScaledIndexLoadPat<zextloadi16, LXSHU, 1>;
+
+def : ScaledIndexLoadPat<load, LXSW, 2, i32>;
+
+let append Predicates = [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, LXSW, 2, i64>;
+def : ScaledIndexLoadPat<sextloadi32, LXSW, 2, i64>;
+def : ScaledIndexLoadPat<zextloadi32, LXSWU, 2, i64>;
+
+def : ScaledIndexLoadPat<load, LXSD, 3, i64>;
+
+// Zero-extended 32-bit index. Byte loads match with shift amount 0.
+def : ScaledZextIndexLoadPat<extloadi8, LXSUWB, 0>;
+def : ScaledZextIndexLoadPat<sextloadi8, LXSUWB, 0>;
+def : ScaledZextIndexLoadPat<zextloadi8, LXSUWBU, 0>;
+
+def : ScaledZextIndexLoadPat<extloadi16, LXSUWH, 1>;
+def : ScaledZextIndexLoadPat<sextloadi16, LXSUWH, 1>;
+def : ScaledZextIndexLoadPat<zextloadi16, LXSUWHU, 1>;
+
+def : ScaledZextIndexLoadPat<load, LXSUWW, 2, i32>;
+
+def : ScaledZextIndexLoadPat<extloadi32, LXSUWW, 2, i64>;
+def : ScaledZextIndexLoadPat<sextloadi32, LXSUWW, 2, i64>;
+def : ScaledZextIndexLoadPat<zextloadi32, LXSUWWU, 2, i64>;
+
+def : ScaledZextIndexLoadPat<load, LXSUWD, 3, i64>;
+} // append Predicates = [IsRV64]
+
+} // Predicates = [HasStdExtZilx]
diff --git a/llvm/lib/Target/RISCV/RISCVOptWInstrs.cpp b/llvm/lib/Target/RISCV/RISCVOptWInstrs.cpp
index 1ad2956320b9d..0b50bab121abd 100644
--- a/llvm/lib/Target/RISCV/RISCVOptWInstrs.cpp
+++ b/llvm/lib/Target/RISCV/RISCVOptWInstrs.cpp
@@ -671,7 +671,8 @@ static bool isSignExtendedW(Register SrcReg, const RISCVSubtarget &ST,
return false;
}
- case RISCV::LD: {
+ case RISCV::LD:
+ case RISCV::LXD: {
if (MI->hasOneMemOperand() && !(*MI->memoperands_begin())->isVolatile() &&
hasAllWUsers(*MI, ST, MRI)) {
FixableDef.insert(MI);
@@ -689,6 +690,7 @@ static bool isSignExtendedW(Register SrcReg, const RISCVSubtarget &ST,
[[fallthrough]];
case RISCV::ADD:
case RISCV::LWU:
+ 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,14 @@ bool RISCVOptWInstrs::canonicalizeWSuffixes(MachineFunction &MF,
case RISCV::LWU:
WOpc = RISCV::LW;
break;
+ case RISCV::LXD:
+ if (!MI.hasOneMemOperand() || (*MI.memoperands_begin())->isVolatile())
+ continue;
+ WOpc = RISCV::LXW;
+ break;
+ case RISCV::LXWU:
+ WOpc = RISCV::LXW;
+ break;
}
if (ShouldStripW && NonWOpc.has_value() && hasAllWUsers(MI, ST, MRI)) {
diff --git a/llvm/test/CodeGen/RISCV/zilx-opt-w-instrs.mir b/llvm/test/CodeGen/RISCV/zilx-opt-w-instrs.mir
new file mode 100644
index 0000000000000..b620a5371d74d
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/zilx-opt-w-instrs.mir
@@ -0,0 +1,182 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 3
+# RUN: llc -mtriple=riscv64 -mattr=+experimental-zilx -verify-machineinstrs -run-pass=riscv-opt-w-instrs %s -o - | FileCheck %s
+
+# The Zilx doubleword/unsigned-word indexed loads participate in the W-suffix
+# canonicalization the same way LD/LWU do: LXD and LXWU can be narrowed to LXW
+# when only the low 32 bits are used. As with LD, narrowing LXD (a 64-bit
+# access) must not happen for volatile loads.
+
+---
+name: lxd_sext_removal
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x10, $x11
+ ; CHECK-LABEL: name: lxd_sext_removal
+ ; CHECK: liveins: $x10, $x11
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
+ ; CHECK-NEXT: [[LXW:%[0-9]+]]:gpr = LXW [[COPY]], [[COPY1]] :: (load (s64))
+ ; CHECK-NEXT: $x10 = COPY [[LXW]]
+ ; CHECK-NEXT: PseudoRET implicit $x10
+ %0:gpr = COPY $x10
+ %1:gpr = COPY $x11
+ %2:gpr = LXD %0, %1 :: (load (s64))
+ %3:gpr = ADDIW %2, 0
+ $x10 = COPY %3
+ PseudoRET implicit $x10
+...
+---
+name: lxwu_sext_removal
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x10, $x11
+ ; CHECK-LABEL: name: lxwu_sext_removal
+ ; CHECK: liveins: $x10, $x11
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
+ ; CHECK-NEXT: [[LXW:%[0-9]+]]:gpr = LXW [[COPY]], [[COPY1]] :: (load (s32))
+ ; CHECK-NEXT: $x10 = COPY [[LXW]]
+ ; CHECK-NEXT: PseudoRET implicit $x10
+ %0:gpr = COPY $x10
+ %1:gpr = COPY $x11
+ %2:gpr = LXWU %0, %1 :: (load (s32))
+ %3:gpr = ADDIW %2, 0
+ $x10 = COPY %3
+ PseudoRET implicit $x10
+...
+---
+name: volatile_lxd_not_narrowed
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x10, $x11
+ ; CHECK-LABEL: name: volatile_lxd_not_narrowed
+ ; CHECK: liveins: $x10, $x11
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
+ ; CHECK-NEXT: [[LXD:%[0-9]+]]:gpr = LXD [[COPY]], [[COPY1]] :: (volatile load (s64))
+ ; CHECK-NEXT: [[ADDIW:%[0-9]+]]:gpr = ADDIW [[LXD]], 0
+ ; CHECK-NEXT: $x10 = COPY [[ADDIW]]
+ ; CHECK-NEXT: PseudoRET implicit $x10
+ %0:gpr = COPY $x10
+ %1:gpr = COPY $x11
+ %2:gpr = LXD %0, %1 :: (volatile load (s64))
+ %3:gpr = ADDIW %2, 0
+ $x10 = COPY %3
+ PseudoRET implicit $x10
+...
+
+# The byte, halfword, and signed word loads are marked IsSignExtendingOpW, so
+# a sext.w that consumes their result is redundant and gets removed.
+
+---
+name: lxh_sextw_removed
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x10, $x11
+ ; CHECK-LABEL: name: lxh_sextw_removed
+ ; CHECK: liveins: $x10, $x11
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
+ ; CHECK-NEXT: [[LXH:%[0-9]+]]:gpr = LXH [[COPY]], [[COPY1]] :: (load (s16))
+ ; CHECK-NEXT: $x10 = COPY [[LXH]]
+ ; CHECK-NEXT: PseudoRET implicit $x10
+ %0:gpr = COPY $x10
+ %1:gpr = COPY $x11
+ %2:gpr = LXH %0, %1 :: (load (s16))
+ %3:gpr = ADDIW %2, 0
+ $x10 = COPY %3
+ PseudoRET implicit $x10
+...
+---
+name: lxsb_sextw_removed
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x10, $x11
+ ; CHECK-LABEL: name: lxsb_sextw_removed
+ ; CHECK: liveins: $x10, $x11
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
+ ; CHECK-NEXT: [[LXSB:%[0-9]+]]:gpr = LXSB [[COPY]], [[COPY1]] :: (load (s8))
+ ; CHECK-NEXT: $x10 = COPY [[LXSB]]
+ ; CHECK-NEXT: PseudoRET implicit $x10
+ %0:gpr = COPY $x10
+ %1:gpr = COPY $x11
+ %2:gpr = LXSB %0, %1 :: (load (s8))
+ %3:gpr = ADDIW %2, 0
+ $x10 = COPY %3
+ PseudoRET implicit $x10
+...
+---
+name: lxshu_sextw_removed
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x10, $x11
+ ; CHECK-LABEL: name: lxshu_sextw_removed
+ ; CHECK: liveins: $x10, $x11
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
+ ; CHECK-NEXT: [[LXSHU:%[0-9]+]]:gpr = LXSHU [[COPY]], [[COPY1]] :: (load (s16))
+ ; CHECK-NEXT: $x10 = COPY [[LXSHU]]
+ ; CHECK-NEXT: PseudoRET implicit $x10
+ %0:gpr = COPY $x10
+ %1:gpr = COPY $x11
+ %2:gpr = LXSHU %0, %1 :: (load (s16))
+ %3:gpr = ADDIW %2, 0
+ $x10 = COPY %3
+ PseudoRET implicit $x10
+...
+---
+name: lxsuww_sextw_removed
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x10, $x11
+ ; CHECK-LABEL: name: lxsuww_sextw_removed
+ ; CHECK: liveins: $x10, $x11
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
+ ; CHECK-NEXT: [[LXSUWW:%[0-9]+]]:gpr = LXSUWW [[COPY]], [[COPY1]] :: (load (s32))
+ ; CHECK-NEXT: $x10 = COPY [[LXSUWW]]
+ ; CHECK-NEXT: PseudoRET implicit $x10
+ %0:gpr = COPY $x10
+ %1:gpr = COPY $x11
+ %2:gpr = LXSUWW %0, %1 :: (load (s32))
+ %3:gpr = ADDIW %2, 0
+ $x10 = COPY %3
+ PseudoRET implicit $x10
+...
+---
+name: lxsuwwu_sextw_kept
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x10, $x11
+ ; CHECK-LABEL: name: lxsuwwu_sextw_kept
+ ; CHECK: liveins: $x10, $x11
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
+ ; CHECK-NEXT: [[LXSUWWU:%[0-9]+]]:gpr = LXSUWWU [[COPY]], [[COPY1]] :: (load (s32))
+ ; CHECK-NEXT: [[ADDIW:%[0-9]+]]:gpr = ADDIW [[LXSUWWU]], 0
+ ; CHECK-NEXT: $x10 = COPY [[ADDIW]]
+ ; CHECK-NEXT: PseudoRET implicit $x10
+ %0:gpr = COPY $x10
+ %1:gpr = COPY $x11
+ %2:gpr = LXSUWWU %0, %1 :: (load (s32))
+ %3:gpr = ADDIW %2, 0
+ $x10 = COPY %3
+ PseudoRET implicit $x10
+...
diff --git a/llvm/test/CodeGen/RISCV/zilx.ll b/llvm/test/CodeGen/RISCV/zilx.ll
new file mode 100644
index 0000000000000..4c045e581eefa
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/zilx.ll
@@ -0,0 +1,1880 @@
+; 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/i32/g' %s | llc -mtriple=riscv32 -mattr=+zba -verify-machineinstrs \
+; RUN: | FileCheck -check-prefix=RV32-ZBA %s
+; RUN: sed 's/iXLen/i32/g' %s | llc -mtriple=riscv32 -mattr=+zba,+experimental-zilx -verify-machineinstrs \
+; RUN: | FileCheck -check-prefix=RV32-ZBA-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
+; RUN: sed 's/iXLen/i64/g' %s | llc -mtriple=riscv64 -mattr=+zba -verify-machineinstrs \
+; RUN: | FileCheck -check-prefix=RV64-ZBA %s
+; RUN: sed 's/iXLen/i64/g' %s | llc -mtriple=riscv64 -mattr=+zba,+experimental-zilx -verify-machineinstrs \
+; RUN: | FileCheck -check-prefix=RV64-ZBA-ZILX %s
+
+;------------------------------------------------------------------------------
+; Unscaled indexed loads: address = base + index.
+;------------------------------------------------------------------------------
+
+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
+;
+; RV32-ZBA-LABEL: lxh:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: add a0, a0, a1
+; RV32-ZBA-NEXT: lh a0, 0(a0)
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxh:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: lxh a0, (a0), a1
+; RV32-ZBA-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
+;
+; RV64-ZBA-LABEL: lxh:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: add a0, a0, a1
+; RV64-ZBA-NEXT: lh a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxh:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: lxh a0, (a0), a1
+; RV64-ZBA-ZILX-NEXT: ret
+ %1 = getelementptr i8, ptr %a, iXLen %b
+ %2 = load i16, ptr %1, align 2
+ ret i16 %2
+}
+
+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
+;
+; RV32-ZBA-LABEL: lxhu:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: add a0, a0, a1
+; RV32-ZBA-NEXT: lhu a0, 0(a0)
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxhu:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: lxhu a0, (a0), a1
+; RV32-ZBA-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
+;
+; RV64-ZBA-LABEL: lxhu:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: add a0, a0, a1
+; RV64-ZBA-NEXT: lhu a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxhu:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: lxhu a0, (a0), a1
+; RV64-ZBA-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 @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
+;
+; RV32-ZBA-LABEL: lxw:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: add a0, a0, a1
+; RV32-ZBA-NEXT: lw a0, 0(a0)
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxw:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: lxw a0, (a0), a1
+; RV32-ZBA-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
+;
+; RV64-ZBA-LABEL: lxw:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: add a0, a0, a1
+; RV64-ZBA-NEXT: lw a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxw:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: lxw a0, (a0), a1
+; RV64-ZBA-ZILX-NEXT: ret
+ %1 = getelementptr i8, ptr %a, iXLen %b
+ %2 = load i32, ptr %1, align 4
+ ret i32 %2
+}
+
+define i64 @lxwu(ptr %a, iXLen %b) {
+; RV32-LABEL: lxwu:
+; RV32: # %bb.0:
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lw a0, 0(a0)
+; RV32-NEXT: li a1, 0
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxwu:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: lxw a0, (a0), a1
+; RV32-ZILX-NEXT: li a1, 0
+; RV32-ZILX-NEXT: ret
+;
+; RV32-ZBA-LABEL: lxwu:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: add a0, a0, a1
+; RV32-ZBA-NEXT: lw a0, 0(a0)
+; RV32-ZBA-NEXT: li a1, 0
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxwu:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: lxw a0, (a0), a1
+; RV32-ZBA-ZILX-NEXT: li a1, 0
+; RV32-ZBA-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxwu:
+; RV64: # %bb.0:
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lwu a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxwu:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxwu a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+;
+; RV64-ZBA-LABEL: lxwu:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: add a0, a0, a1
+; RV64-ZBA-NEXT: lwu a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxwu:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: lxwu a0, (a0), a1
+; RV64-ZBA-ZILX-NEXT: ret
+ %1 = getelementptr i8, ptr %a, iXLen %b
+ %2 = load i32, ptr %1, align 4
+ %3 = zext i32 %2 to i64
+ ret i64 %3
+}
+
+define i64 @lxd(ptr %a, iXLen %b) {
+; RV32-LABEL: lxd:
+; RV32: # %bb.0:
+; RV32-NEXT: add a1, a0, a1
+; RV32-NEXT: lw a0, 0(a1)
+; RV32-NEXT: lw a1, 4(a1)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxd:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: add a1, a0, a1
+; RV32-ZILX-NEXT: lw a0, 0(a1)
+; RV32-ZILX-NEXT: lw a1, 4(a1)
+; RV32-ZILX-NEXT: ret
+;
+; RV32-ZBA-LABEL: lxd:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: add a1, a0, a1
+; RV32-ZBA-NEXT: lw a0, 0(a1)
+; RV32-ZBA-NEXT: lw a1, 4(a1)
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxd:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: add a1, a0, a1
+; RV32-ZBA-ZILX-NEXT: lw a0, 0(a1)
+; RV32-ZBA-ZILX-NEXT: lw a1, 4(a1)
+; RV32-ZBA-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxd:
+; RV64: # %bb.0:
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: ld a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxd:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxd a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+;
+; RV64-ZBA-LABEL: lxd:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: add a0, a0, a1
+; RV64-ZBA-NEXT: ld a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxd:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: lxd a0, (a0), a1
+; RV64-ZBA-ZILX-NEXT: ret
+ %1 = getelementptr i8, ptr %a, iXLen %b
+ %2 = load i64, ptr %1, align 8
+ ret i64 %2
+}
+
+;------------------------------------------------------------------------------
+; Scaled indexed loads: address = base + (index << log2(access-size)).
+; Byte loads are provided only in scaled form (the byte scale factor is 1).
+;------------------------------------------------------------------------------
+
+define i8 @lxsb_anyext(ptr %a, iXLen %b) {
+; RV32-LABEL: lxsb_anyext:
+; RV32: # %bb.0:
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lbu a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxsb_anyext:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: lxsb a0, (a0), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV32-ZBA-LABEL: lxsb_anyext:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: add a0, a0, a1
+; RV32-ZBA-NEXT: lbu a0, 0(a0)
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxsb_anyext:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: lxsb a0, (a0), a1
+; RV32-ZBA-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxsb_anyext:
+; RV64: # %bb.0:
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lbu a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxsb_anyext:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxsb a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+;
+; RV64-ZBA-LABEL: lxsb_anyext:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: add a0, a0, a1
+; RV64-ZBA-NEXT: lbu a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxsb_anyext:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: lxsb a0, (a0), a1
+; RV64-ZBA-ZILX-NEXT: ret
+ %1 = getelementptr i8, ptr %a, iXLen %b
+ %2 = load i8, ptr %1, align 1
+ ret i8 %2
+}
+
+define i32 @lxsb(ptr %a, iXLen %b) {
+; RV32-LABEL: lxsb:
+; RV32: # %bb.0:
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lb a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxsb:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: lxsb a0, (a0), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV32-ZBA-LABEL: lxsb:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: add a0, a0, a1
+; RV32-ZBA-NEXT: lb a0, 0(a0)
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxsb:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: lxsb a0, (a0), a1
+; RV32-ZBA-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxsb:
+; RV64: # %bb.0:
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lb a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxsb:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxsb a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+;
+; RV64-ZBA-LABEL: lxsb:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: add a0, a0, a1
+; RV64-ZBA-NEXT: lb a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxsb:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: lxsb a0, (a0), a1
+; RV64-ZBA-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 i32 @lxsbu(ptr %a, iXLen %b) {
+; RV32-LABEL: lxsbu:
+; RV32: # %bb.0:
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lbu a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxsbu:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: lxsbu a0, (a0), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV32-ZBA-LABEL: lxsbu:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: add a0, a0, a1
+; RV32-ZBA-NEXT: lbu a0, 0(a0)
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxsbu:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: lxsbu a0, (a0), a1
+; RV32-ZBA-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxsbu:
+; RV64: # %bb.0:
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lbu a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxsbu:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxsbu a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+;
+; RV64-ZBA-LABEL: lxsbu:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: add a0, a0, a1
+; RV64-ZBA-NEXT: lbu a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxsbu:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: lxsbu a0, (a0), a1
+; RV64-ZBA-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 i16 @lxsh_anyext(ptr %a, iXLen %b) {
+; RV32-LABEL: lxsh_anyext:
+; RV32: # %bb.0:
+; RV32-NEXT: slli a1, a1, 1
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lh a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxsh_anyext:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: lxsh a0, (a0), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV32-ZBA-LABEL: lxsh_anyext:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: sh1add a0, a1, a0
+; RV32-ZBA-NEXT: lh a0, 0(a0)
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxsh_anyext:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: lxsh a0, (a0), a1
+; RV32-ZBA-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxsh_anyext:
+; RV64: # %bb.0:
+; RV64-NEXT: slli a1, a1, 1
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lh a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxsh_anyext:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxsh a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+;
+; RV64-ZBA-LABEL: lxsh_anyext:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: sh1add a0, a1, a0
+; RV64-ZBA-NEXT: lh a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxsh_anyext:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: lxsh a0, (a0), a1
+; RV64-ZBA-ZILX-NEXT: ret
+ %1 = getelementptr i16, ptr %a, iXLen %b
+ %2 = load i16, ptr %1, align 2
+ ret i16 %2
+}
+
+define i32 @lxsh(ptr %a, iXLen %b) {
+; RV32-LABEL: lxsh:
+; RV32: # %bb.0:
+; RV32-NEXT: slli a1, a1, 1
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lh a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxsh:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: lxsh a0, (a0), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV32-ZBA-LABEL: lxsh:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: sh1add a0, a1, a0
+; RV32-ZBA-NEXT: lh a0, 0(a0)
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxsh:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: lxsh a0, (a0), a1
+; RV32-ZBA-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxsh:
+; RV64: # %bb.0:
+; RV64-NEXT: slli a1, a1, 1
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lh a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxsh:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxsh a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+;
+; RV64-ZBA-LABEL: lxsh:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: sh1add a0, a1, a0
+; RV64-ZBA-NEXT: lh a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxsh:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: lxsh a0, (a0), a1
+; RV64-ZBA-ZILX-NEXT: ret
+ %1 = getelementptr i16, ptr %a, iXLen %b
+ %2 = load i16, ptr %1, align 2
+ %3 = sext i16 %2 to i32
+ ret i32 %3
+}
+
+define i32 @lxshu(ptr %a, iXLen %b) {
+; RV32-LABEL: lxshu:
+; RV32: # %bb.0:
+; RV32-NEXT: slli a1, a1, 1
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lhu a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxshu:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: lxshu a0, (a0), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV32-ZBA-LABEL: lxshu:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: sh1add a0, a1, a0
+; RV32-ZBA-NEXT: lhu a0, 0(a0)
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxshu:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: lxshu a0, (a0), a1
+; RV32-ZBA-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxshu:
+; RV64: # %bb.0:
+; RV64-NEXT: slli a1, a1, 1
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lhu a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxshu:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxshu a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+;
+; RV64-ZBA-LABEL: lxshu:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: sh1add a0, a1, a0
+; RV64-ZBA-NEXT: lhu a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxshu:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: lxshu a0, (a0), a1
+; RV64-ZBA-ZILX-NEXT: ret
+ %1 = getelementptr i16, ptr %a, iXLen %b
+ %2 = load i16, ptr %1, align 2
+ %3 = zext i16 %2 to i32
+ ret i32 %3
+}
+
+define i32 @lxsw_anyext(ptr %a, iXLen %b) {
+; RV32-LABEL: lxsw_anyext:
+; RV32: # %bb.0:
+; RV32-NEXT: slli a1, a1, 2
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lw a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxsw_anyext:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: lxsw a0, (a0), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV32-ZBA-LABEL: lxsw_anyext:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: sh2add a0, a1, a0
+; RV32-ZBA-NEXT: lw a0, 0(a0)
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxsw_anyext:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: lxsw a0, (a0), a1
+; RV32-ZBA-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxsw_anyext:
+; RV64: # %bb.0:
+; RV64-NEXT: slli a1, a1, 2
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lw a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxsw_anyext:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxsw a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+;
+; RV64-ZBA-LABEL: lxsw_anyext:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: sh2add a0, a1, a0
+; RV64-ZBA-NEXT: lw a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxsw_anyext:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: lxsw a0, (a0), a1
+; RV64-ZBA-ZILX-NEXT: ret
+ %1 = getelementptr i32, ptr %a, iXLen %b
+ %2 = load i32, ptr %1, align 4
+ ret i32 %2
+}
+
+define i64 @lxsw(ptr %a, iXLen %b) {
+; RV32-LABEL: lxsw:
+; RV32: # %bb.0:
+; RV32-NEXT: slli a1, a1, 2
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lw a0, 0(a0)
+; RV32-NEXT: srai a1, a0, 31
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxsw:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: lxsw a0, (a0), a1
+; RV32-ZILX-NEXT: srai a1, a0, 31
+; RV32-ZILX-NEXT: ret
+;
+; RV32-ZBA-LABEL: lxsw:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: sh2add a0, a1, a0
+; RV32-ZBA-NEXT: lw a0, 0(a0)
+; RV32-ZBA-NEXT: srai a1, a0, 31
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxsw:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: lxsw a0, (a0), a1
+; RV32-ZBA-ZILX-NEXT: srai a1, a0, 31
+; RV32-ZBA-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxsw:
+; RV64: # %bb.0:
+; RV64-NEXT: slli a1, a1, 2
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lw a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxsw:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxsw a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+;
+; RV64-ZBA-LABEL: lxsw:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: sh2add a0, a1, a0
+; RV64-ZBA-NEXT: lw a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxsw:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: lxsw a0, (a0), a1
+; RV64-ZBA-ZILX-NEXT: ret
+ %1 = getelementptr i32, ptr %a, iXLen %b
+ %2 = load i32, ptr %1, align 4
+ %3 = sext i32 %2 to i64
+ ret i64 %3
+}
+
+define i64 @lxswu(ptr %a, iXLen %b) {
+; RV32-LABEL: lxswu:
+; RV32: # %bb.0:
+; RV32-NEXT: slli a1, a1, 2
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lw a0, 0(a0)
+; RV32-NEXT: li a1, 0
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxswu:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: lxsw a0, (a0), a1
+; RV32-ZILX-NEXT: li a1, 0
+; RV32-ZILX-NEXT: ret
+;
+; RV32-ZBA-LABEL: lxswu:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: sh2add a0, a1, a0
+; RV32-ZBA-NEXT: lw a0, 0(a0)
+; RV32-ZBA-NEXT: li a1, 0
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxswu:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: lxsw a0, (a0), a1
+; RV32-ZBA-ZILX-NEXT: li a1, 0
+; RV32-ZBA-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxswu:
+; RV64: # %bb.0:
+; RV64-NEXT: slli a1, a1, 2
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lwu a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxswu:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxswu a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+;
+; RV64-ZBA-LABEL: lxswu:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: sh2add a0, a1, a0
+; RV64-ZBA-NEXT: lwu a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxswu:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: lxswu a0, (a0), a1
+; RV64-ZBA-ZILX-NEXT: ret
+ %1 = getelementptr i32, ptr %a, iXLen %b
+ %2 = load i32, ptr %1, align 4
+ %3 = zext i32 %2 to i64
+ ret i64 %3
+}
+
+define i64 @lxsd(ptr %a, iXLen %b) {
+; RV32-LABEL: lxsd:
+; RV32: # %bb.0:
+; RV32-NEXT: slli a1, a1, 3
+; RV32-NEXT: add a1, a0, a1
+; RV32-NEXT: lw a0, 0(a1)
+; RV32-NEXT: lw a1, 4(a1)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxsd:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: slli a1, a1, 3
+; RV32-ZILX-NEXT: add a1, a0, a1
+; RV32-ZILX-NEXT: lw a0, 0(a1)
+; RV32-ZILX-NEXT: lw a1, 4(a1)
+; RV32-ZILX-NEXT: ret
+;
+; RV32-ZBA-LABEL: lxsd:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: sh3add a1, a1, a0
+; RV32-ZBA-NEXT: lw a0, 0(a1)
+; RV32-ZBA-NEXT: lw a1, 4(a1)
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxsd:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: sh3add a1, a1, a0
+; RV32-ZBA-ZILX-NEXT: lw a0, 0(a1)
+; RV32-ZBA-ZILX-NEXT: lw a1, 4(a1)
+; RV32-ZBA-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxsd:
+; RV64: # %bb.0:
+; RV64-NEXT: slli a1, a1, 3
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: ld a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxsd:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxsd a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+;
+; RV64-ZBA-LABEL: lxsd:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: sh3add a0, a1, a0
+; RV64-ZBA-NEXT: ld a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxsd:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: lxsd a0, (a0), a1
+; RV64-ZBA-ZILX-NEXT: ret
+ %1 = getelementptr i64, ptr %a, iXLen %b
+ %2 = load i64, ptr %1, align 8
+ ret i64 %2
+}
+
+define i64 @lxsd_disjoint(ptr %a, iXLen %b) {
+; RV32-LABEL: lxsd_disjoint:
+; RV32: # %bb.0:
+; RV32-NEXT: slli a1, a1, 3
+; RV32-NEXT: add a1, a1, a0
+; RV32-NEXT: lw a0, 96(a1)
+; RV32-NEXT: lw a1, 100(a1)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxsd_disjoint:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: slli a1, a1, 3
+; RV32-ZILX-NEXT: add a1, a1, a0
+; RV32-ZILX-NEXT: lw a0, 96(a1)
+; RV32-ZILX-NEXT: lw a1, 100(a1)
+; RV32-ZILX-NEXT: ret
+;
+; RV32-ZBA-LABEL: lxsd_disjoint:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: sh3add a1, a1, a0
+; RV32-ZBA-NEXT: lw a0, 96(a1)
+; RV32-ZBA-NEXT: lw a1, 100(a1)
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxsd_disjoint:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: sh3add a1, a1, a0
+; RV32-ZBA-ZILX-NEXT: lw a0, 96(a1)
+; RV32-ZBA-ZILX-NEXT: lw a1, 100(a1)
+; RV32-ZBA-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxsd_disjoint:
+; RV64: # %bb.0:
+; RV64-NEXT: slli a1, a1, 3
+; RV64-NEXT: add a0, a1, a0
+; RV64-NEXT: ld a0, 96(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxsd_disjoint:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: addi a0, a0, 96
+; RV64-ZILX-NEXT: lxsd a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+;
+; RV64-ZBA-LABEL: lxsd_disjoint:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: sh3add a0, a1, a0
+; RV64-ZBA-NEXT: ld a0, 96(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxsd_disjoint:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: sh3add a0, a1, a0
+; RV64-ZBA-ZILX-NEXT: ld a0, 96(a0)
+; RV64-ZBA-ZILX-NEXT: ret
+ %1 = add iXLen %b, 12
+ %2 = getelementptr i64, ptr %a, iXLen %1
+ %3 = load i64, ptr %2, align 8
+ ret i64 %3
+}
+
+;------------------------------------------------------------------------------
+; Scaled indexed loads with a zero-extended 32-bit index (RV64-only):
+; address = base + (zext32(index) << log2(access-size)).
+;------------------------------------------------------------------------------
+
+define i8 @lxsuwb_anyext(ptr %a, i32 %b) {
+; RV32-LABEL: lxsuwb_anyext:
+; RV32: # %bb.0:
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lbu a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxsuwb_anyext:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: lxsb a0, (a0), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV32-ZBA-LABEL: lxsuwb_anyext:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: add a0, a0, a1
+; RV32-ZBA-NEXT: lbu a0, 0(a0)
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxsuwb_anyext:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: lxsb a0, (a0), a1
+; RV32-ZBA-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxsuwb_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: lxsuwb_anyext:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxsuwb a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+;
+; RV64-ZBA-LABEL: lxsuwb_anyext:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: add.uw a0, a1, a0
+; RV64-ZBA-NEXT: lbu a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxsuwb_anyext:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: lxsuwb a0, (a0), a1
+; RV64-ZBA-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 @lxsuwb(ptr %a, i32 %b) {
+; RV32-LABEL: lxsuwb:
+; RV32: # %bb.0:
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lb a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxsuwb:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: lxsb a0, (a0), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV32-ZBA-LABEL: lxsuwb:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: add a0, a0, a1
+; RV32-ZBA-NEXT: lb a0, 0(a0)
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxsuwb:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: lxsb a0, (a0), a1
+; RV32-ZBA-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxsuwb:
+; 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: lxsuwb:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxsuwb a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+;
+; RV64-ZBA-LABEL: lxsuwb:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: add.uw a0, a1, a0
+; RV64-ZBA-NEXT: lb a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxsuwb:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: lxsuwb a0, (a0), a1
+; RV64-ZBA-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 @lxsuwbu(ptr %a, i32 %b) {
+; RV32-LABEL: lxsuwbu:
+; RV32: # %bb.0:
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lbu a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxsuwbu:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: lxsbu a0, (a0), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV32-ZBA-LABEL: lxsuwbu:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: add a0, a0, a1
+; RV32-ZBA-NEXT: lbu a0, 0(a0)
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxsuwbu:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: lxsbu a0, (a0), a1
+; RV32-ZBA-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxsuwbu:
+; 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: lxsuwbu:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxsuwbu a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+;
+; RV64-ZBA-LABEL: lxsuwbu:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: add.uw a0, a1, a0
+; RV64-ZBA-NEXT: lbu a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxsuwbu:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: lxsuwbu a0, (a0), a1
+; RV64-ZBA-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 @lxsuwh_anyext(ptr %a, i32 %b) {
+; RV32-LABEL: lxsuwh_anyext:
+; RV32: # %bb.0:
+; RV32-NEXT: slli a1, a1, 1
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lh a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxsuwh_anyext:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: lxsh a0, (a0), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV32-ZBA-LABEL: lxsuwh_anyext:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: sh1add a0, a1, a0
+; RV32-ZBA-NEXT: lh a0, 0(a0)
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxsuwh_anyext:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: lxsh a0, (a0), a1
+; RV32-ZBA-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxsuwh_anyext:
+; RV64: # %bb.0:
+; RV64-NEXT: slli a1, a1, 32
+; RV64-NEXT: srli a1, a1, 31
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lh a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxsuwh_anyext:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxsuwh a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+;
+; RV64-ZBA-LABEL: lxsuwh_anyext:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: sh1add.uw a0, a1, a0
+; RV64-ZBA-NEXT: lh a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxsuwh_anyext:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: lxsuwh a0, (a0), a1
+; RV64-ZBA-ZILX-NEXT: ret
+ %1 = zext i32 %b to i64
+ %2 = getelementptr i16, ptr %a, i64 %1
+ %3 = load i16, ptr %2, align 2
+ ret i16 %3
+}
+
+define i32 @lxsuwh(ptr %a, i32 %b) {
+; RV32-LABEL: lxsuwh:
+; RV32: # %bb.0:
+; RV32-NEXT: slli a1, a1, 1
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lh a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxsuwh:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: lxsh a0, (a0), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV32-ZBA-LABEL: lxsuwh:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: sh1add a0, a1, a0
+; RV32-ZBA-NEXT: lh a0, 0(a0)
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxsuwh:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: lxsh a0, (a0), a1
+; RV32-ZBA-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxsuwh:
+; RV64: # %bb.0:
+; RV64-NEXT: slli a1, a1, 32
+; RV64-NEXT: srli a1, a1, 31
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lh a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxsuwh:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxsuwh a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+;
+; RV64-ZBA-LABEL: lxsuwh:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: sh1add.uw a0, a1, a0
+; RV64-ZBA-NEXT: lh a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxsuwh:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: lxsuwh a0, (a0), a1
+; RV64-ZBA-ZILX-NEXT: ret
+ %1 = zext i32 %b to i64
+ %2 = getelementptr i16, ptr %a, i64 %1
+ %3 = load i16, ptr %2, align 2
+ %4 = sext i16 %3 to i32
+ ret i32 %4
+}
+
+define i32 @lxsuwhu(ptr %a, i32 %b) {
+; RV32-LABEL: lxsuwhu:
+; RV32: # %bb.0:
+; RV32-NEXT: slli a1, a1, 1
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lhu a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxsuwhu:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: lxshu a0, (a0), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV32-ZBA-LABEL: lxsuwhu:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: sh1add a0, a1, a0
+; RV32-ZBA-NEXT: lhu a0, 0(a0)
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxsuwhu:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: lxshu a0, (a0), a1
+; RV32-ZBA-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxsuwhu:
+; RV64: # %bb.0:
+; RV64-NEXT: slli a1, a1, 32
+; RV64-NEXT: srli a1, a1, 31
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lhu a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxsuwhu:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxsuwhu a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+;
+; RV64-ZBA-LABEL: lxsuwhu:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: sh1add.uw a0, a1, a0
+; RV64-ZBA-NEXT: lhu a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxsuwhu:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: lxsuwhu a0, (a0), a1
+; RV64-ZBA-ZILX-NEXT: ret
+ %1 = zext i32 %b to i64
+ %2 = getelementptr i16, ptr %a, i64 %1
+ %3 = load i16, ptr %2, align 2
+ %4 = zext i16 %3 to i32
+ ret i32 %4
+}
+
+define i32 @lxsuww_anyext(ptr %a, i32 %b) {
+; RV32-LABEL: lxsuww_anyext:
+; RV32: # %bb.0:
+; RV32-NEXT: slli a1, a1, 2
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lw a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxsuww_anyext:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: lxsw a0, (a0), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV32-ZBA-LABEL: lxsuww_anyext:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: sh2add a0, a1, a0
+; RV32-ZBA-NEXT: lw a0, 0(a0)
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxsuww_anyext:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: lxsw a0, (a0), a1
+; RV32-ZBA-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxsuww_anyext:
+; RV64: # %bb.0:
+; RV64-NEXT: slli a1, a1, 32
+; RV64-NEXT: srli a1, a1, 30
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lw a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxsuww_anyext:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxsuww a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+;
+; RV64-ZBA-LABEL: lxsuww_anyext:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: sh2add.uw a0, a1, a0
+; RV64-ZBA-NEXT: lw a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxsuww_anyext:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: lxsuww a0, (a0), a1
+; RV64-ZBA-ZILX-NEXT: ret
+ %1 = zext i32 %b to i64
+ %2 = getelementptr i32, ptr %a, i64 %1
+ %3 = load i32, ptr %2, align 4
+ ret i32 %3
+}
+
+define i64 @lxsuww(ptr %a, i32 %b) {
+; RV32-LABEL: lxsuww:
+; RV32: # %bb.0:
+; RV32-NEXT: slli a1, a1, 2
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lw a0, 0(a0)
+; RV32-NEXT: srai a1, a0, 31
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxsuww:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: lxsw a0, (a0), a1
+; RV32-ZILX-NEXT: srai a1, a0, 31
+; RV32-ZILX-NEXT: ret
+;
+; RV32-ZBA-LABEL: lxsuww:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: sh2add a0, a1, a0
+; RV32-ZBA-NEXT: lw a0, 0(a0)
+; RV32-ZBA-NEXT: srai a1, a0, 31
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxsuww:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: lxsw a0, (a0), a1
+; RV32-ZBA-ZILX-NEXT: srai a1, a0, 31
+; RV32-ZBA-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxsuww:
+; RV64: # %bb.0:
+; RV64-NEXT: slli a1, a1, 32
+; RV64-NEXT: srli a1, a1, 30
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lw a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxsuww:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxsuww a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+;
+; RV64-ZBA-LABEL: lxsuww:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: sh2add.uw a0, a1, a0
+; RV64-ZBA-NEXT: lw a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxsuww:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: lxsuww a0, (a0), a1
+; RV64-ZBA-ZILX-NEXT: ret
+ %1 = zext i32 %b to i64
+ %2 = getelementptr i32, ptr %a, i64 %1
+ %3 = load i32, ptr %2, align 4
+ %4 = sext i32 %3 to i64
+ ret i64 %4
+}
+
+define i64 @lxsuwwu(ptr %a, i32 %b) {
+; RV32-LABEL: lxsuwwu:
+; RV32: # %bb.0:
+; RV32-NEXT: slli a1, a1, 2
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lw a0, 0(a0)
+; RV32-NEXT: li a1, 0
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxsuwwu:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: lxsw a0, (a0), a1
+; RV32-ZILX-NEXT: li a1, 0
+; RV32-ZILX-NEXT: ret
+;
+; RV32-ZBA-LABEL: lxsuwwu:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: sh2add a0, a1, a0
+; RV32-ZBA-NEXT: lw a0, 0(a0)
+; RV32-ZBA-NEXT: li a1, 0
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxsuwwu:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: lxsw a0, (a0), a1
+; RV32-ZBA-ZILX-NEXT: li a1, 0
+; RV32-ZBA-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxsuwwu:
+; RV64: # %bb.0:
+; RV64-NEXT: slli a1, a1, 32
+; RV64-NEXT: srli a1, a1, 30
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lwu a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxsuwwu:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxsuwwu a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+;
+; RV64-ZBA-LABEL: lxsuwwu:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: sh2add.uw a0, a1, a0
+; RV64-ZBA-NEXT: lwu a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxsuwwu:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: lxsuwwu a0, (a0), a1
+; RV64-ZBA-ZILX-NEXT: ret
+ %1 = zext i32 %b to i64
+ %2 = getelementptr i32, ptr %a, i64 %1
+ %3 = load i32, ptr %2, align 4
+ %4 = zext i32 %3 to i64
+ ret i64 %4
+}
+
+define i64 @lxsuwd(ptr %a, i32 %b) {
+; RV32-LABEL: lxsuwd:
+; RV32: # %bb.0:
+; RV32-NEXT: slli a1, a1, 3
+; RV32-NEXT: add a1, a0, a1
+; RV32-NEXT: lw a0, 0(a1)
+; RV32-NEXT: lw a1, 4(a1)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxsuwd:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: slli a1, a1, 3
+; RV32-ZILX-NEXT: add a1, a0, a1
+; RV32-ZILX-NEXT: lw a0, 0(a1)
+; RV32-ZILX-NEXT: lw a1, 4(a1)
+; RV32-ZILX-NEXT: ret
+;
+; RV32-ZBA-LABEL: lxsuwd:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: sh3add a1, a1, a0
+; RV32-ZBA-NEXT: lw a0, 0(a1)
+; RV32-ZBA-NEXT: lw a1, 4(a1)
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxsuwd:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: sh3add a1, a1, a0
+; RV32-ZBA-ZILX-NEXT: lw a0, 0(a1)
+; RV32-ZBA-ZILX-NEXT: lw a1, 4(a1)
+; RV32-ZBA-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxsuwd:
+; RV64: # %bb.0:
+; RV64-NEXT: slli a1, a1, 32
+; RV64-NEXT: srli a1, a1, 29
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: ld a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxsuwd:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: lxsuwd a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+;
+; RV64-ZBA-LABEL: lxsuwd:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: sh3add.uw a0, a1, a0
+; RV64-ZBA-NEXT: ld a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxsuwd:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: lxsuwd a0, (a0), a1
+; RV64-ZBA-ZILX-NEXT: ret
+ %1 = zext i32 %b to i64
+ %2 = getelementptr i64, ptr %a, i64 %1
+ %3 = load i64, ptr %2, align 8
+ ret i64 %3
+}
+
+;------------------------------------------------------------------------------
+; Mismatched shift amount: the shift does not match the access size, so the
+; scaled forms must not be selected.
+;------------------------------------------------------------------------------
+
+define zeroext i8 @lxsbu_shl_too_large(ptr %a, iXLen %b) {
+; RV32-LABEL: lxsbu_shl_too_large:
+; RV32: # %bb.0:
+; RV32-NEXT: slli a1, a1, 2
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lbu a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxsbu_shl_too_large:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: slli a1, a1, 2
+; RV32-ZILX-NEXT: lxsbu a0, (a0), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV32-ZBA-LABEL: lxsbu_shl_too_large:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: sh2add a0, a1, a0
+; RV32-ZBA-NEXT: lbu a0, 0(a0)
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxsbu_shl_too_large:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: slli a1, a1, 2
+; RV32-ZBA-ZILX-NEXT: lxsbu a0, (a0), a1
+; RV32-ZBA-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxsbu_shl_too_large:
+; RV64: # %bb.0:
+; RV64-NEXT: slli a1, a1, 2
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lbu a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxsbu_shl_too_large:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: slli a1, a1, 2
+; RV64-ZILX-NEXT: lxsbu a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+;
+; RV64-ZBA-LABEL: lxsbu_shl_too_large:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: sh2add a0, a1, a0
+; RV64-ZBA-NEXT: lbu a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxsbu_shl_too_large:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: slli a1, a1, 2
+; RV64-ZBA-ZILX-NEXT: lxsbu a0, (a0), a1
+; RV64-ZBA-ZILX-NEXT: ret
+ %1 = getelementptr i32, ptr %a, iXLen %b
+ %2 = load i8, ptr %1, align 1
+ ret i8 %2
+}
+
+define signext i16 @lxsh_shl_too_large(ptr %a, iXLen %b) {
+; RV32-LABEL: lxsh_shl_too_large:
+; RV32: # %bb.0:
+; RV32-NEXT: slli a1, a1, 2
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lh a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxsh_shl_too_large:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: slli a1, a1, 2
+; RV32-ZILX-NEXT: lxh a0, (a0), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV32-ZBA-LABEL: lxsh_shl_too_large:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: sh2add a0, a1, a0
+; RV32-ZBA-NEXT: lh a0, 0(a0)
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxsh_shl_too_large:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: slli a1, a1, 2
+; RV32-ZBA-ZILX-NEXT: lxh a0, (a0), a1
+; RV32-ZBA-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxsh_shl_too_large:
+; RV64: # %bb.0:
+; RV64-NEXT: slli a1, a1, 2
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lh a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxsh_shl_too_large:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: slli a1, a1, 2
+; RV64-ZILX-NEXT: lxh a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+;
+; RV64-ZBA-LABEL: lxsh_shl_too_large:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: sh2add a0, a1, a0
+; RV64-ZBA-NEXT: lh a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxsh_shl_too_large:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: slli a1, a1, 2
+; RV64-ZBA-ZILX-NEXT: lxh a0, (a0), a1
+; RV64-ZBA-ZILX-NEXT: ret
+ %1 = getelementptr i32, ptr %a, iXLen %b
+ %2 = load i16, ptr %1, align 2
+ ret i16 %2
+}
+
+define i32 @lxsw_shl_too_small(ptr %a, iXLen %b) {
+; RV32-LABEL: lxsw_shl_too_small:
+; RV32: # %bb.0:
+; RV32-NEXT: slli a1, a1, 1
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lw a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxsw_shl_too_small:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: slli a1, a1, 1
+; RV32-ZILX-NEXT: lxw a0, (a0), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV32-ZBA-LABEL: lxsw_shl_too_small:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: sh1add a0, a1, a0
+; RV32-ZBA-NEXT: lw a0, 0(a0)
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxsw_shl_too_small:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: slli a1, a1, 1
+; RV32-ZBA-ZILX-NEXT: lxw a0, (a0), a1
+; RV32-ZBA-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxsw_shl_too_small:
+; RV64: # %bb.0:
+; RV64-NEXT: slli a1, a1, 1
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lw a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxsw_shl_too_small:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: slli a1, a1, 1
+; RV64-ZILX-NEXT: lxw a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+;
+; RV64-ZBA-LABEL: lxsw_shl_too_small:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: sh1add a0, a1, a0
+; RV64-ZBA-NEXT: lw a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxsw_shl_too_small:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: slli a1, a1, 1
+; RV64-ZBA-ZILX-NEXT: lxw a0, (a0), a1
+; RV64-ZBA-ZILX-NEXT: ret
+ %1 = getelementptr i16, ptr %a, iXLen %b
+ %2 = load i32, ptr %1, align 4
+ ret i32 %2
+}
+
+define i32 @lxsw_shl_too_large(ptr %a, iXLen %b) {
+; RV32-LABEL: lxsw_shl_too_large:
+; RV32: # %bb.0:
+; RV32-NEXT: slli a1, a1, 3
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lw a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxsw_shl_too_large:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: slli a1, a1, 3
+; RV32-ZILX-NEXT: lxw a0, (a0), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV32-ZBA-LABEL: lxsw_shl_too_large:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: sh3add a0, a1, a0
+; RV32-ZBA-NEXT: lw a0, 0(a0)
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxsw_shl_too_large:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: slli a1, a1, 3
+; RV32-ZBA-ZILX-NEXT: lxw a0, (a0), a1
+; RV32-ZBA-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxsw_shl_too_large:
+; RV64: # %bb.0:
+; RV64-NEXT: slli a1, a1, 3
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lw a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxsw_shl_too_large:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: slli a1, a1, 3
+; RV64-ZILX-NEXT: lxw a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+;
+; RV64-ZBA-LABEL: lxsw_shl_too_large:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: sh3add a0, a1, a0
+; RV64-ZBA-NEXT: lw a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxsw_shl_too_large:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: slli a1, a1, 3
+; RV64-ZBA-ZILX-NEXT: lxw a0, (a0), a1
+; RV64-ZBA-ZILX-NEXT: ret
+ %1 = getelementptr i64, ptr %a, iXLen %b
+ %2 = load i32, ptr %1, align 4
+ ret i32 %2
+}
+
+define i64 @lxsd_shl_too_small(ptr %a, iXLen %b) {
+; RV32-LABEL: lxsd_shl_too_small:
+; RV32: # %bb.0:
+; RV32-NEXT: slli a1, a1, 2
+; RV32-NEXT: add a1, a0, a1
+; RV32-NEXT: lw a0, 0(a1)
+; RV32-NEXT: lw a1, 4(a1)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxsd_shl_too_small:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: addi a2, a0, 4
+; RV32-ZILX-NEXT: lxsw a0, (a0), a1
+; RV32-ZILX-NEXT: lxsw a1, (a2), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV32-ZBA-LABEL: lxsd_shl_too_small:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: sh2add a1, a1, a0
+; RV32-ZBA-NEXT: lw a0, 0(a1)
+; RV32-ZBA-NEXT: lw a1, 4(a1)
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxsd_shl_too_small:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: sh2add a1, a1, a0
+; RV32-ZBA-ZILX-NEXT: lw a0, 0(a1)
+; RV32-ZBA-ZILX-NEXT: lw a1, 4(a1)
+; RV32-ZBA-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxsd_shl_too_small:
+; RV64: # %bb.0:
+; RV64-NEXT: slli a1, a1, 2
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: ld a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxsd_shl_too_small:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: slli a1, a1, 2
+; RV64-ZILX-NEXT: lxd a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+;
+; RV64-ZBA-LABEL: lxsd_shl_too_small:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: sh2add a0, a1, a0
+; RV64-ZBA-NEXT: ld a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxsd_shl_too_small:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: slli a1, a1, 2
+; RV64-ZBA-ZILX-NEXT: lxd a0, (a0), a1
+; RV64-ZBA-ZILX-NEXT: ret
+ %1 = getelementptr i32, ptr %a, iXLen %b
+ %2 = load i64, ptr %1, align 8
+ ret i64 %2
+}
+
+define signext i16 @lxsuwh_shl_too_large(ptr %a, i32 %b) {
+; RV32-LABEL: lxsuwh_shl_too_large:
+; RV32: # %bb.0:
+; RV32-NEXT: slli a1, a1, 2
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lh a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxsuwh_shl_too_large:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: slli a1, a1, 2
+; RV32-ZILX-NEXT: lxh a0, (a0), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV32-ZBA-LABEL: lxsuwh_shl_too_large:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: sh2add a0, a1, a0
+; RV32-ZBA-NEXT: lh a0, 0(a0)
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxsuwh_shl_too_large:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: slli a1, a1, 2
+; RV32-ZBA-ZILX-NEXT: lxh a0, (a0), a1
+; RV32-ZBA-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxsuwh_shl_too_large:
+; RV64: # %bb.0:
+; RV64-NEXT: slli a1, a1, 32
+; RV64-NEXT: srli a1, a1, 30
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lh a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxsuwh_shl_too_large:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: slli a1, a1, 32
+; RV64-ZILX-NEXT: srli a1, a1, 30
+; RV64-ZILX-NEXT: lxh a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+;
+; RV64-ZBA-LABEL: lxsuwh_shl_too_large:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: sh2add.uw a0, a1, a0
+; RV64-ZBA-NEXT: lh a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxsuwh_shl_too_large:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: slli.uw a1, a1, 2
+; RV64-ZBA-ZILX-NEXT: lxh a0, (a0), a1
+; RV64-ZBA-ZILX-NEXT: ret
+ %1 = zext i32 %b to i64
+ %2 = getelementptr i32, ptr %a, i64 %1
+ %3 = load i16, ptr %2, align 2
+ ret i16 %3
+}
+
+define i32 @lxsuww_shl_too_small(ptr %a, i32 %b) {
+; RV32-LABEL: lxsuww_shl_too_small:
+; RV32: # %bb.0:
+; RV32-NEXT: slli a1, a1, 1
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lw a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxsuww_shl_too_small:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: slli a1, a1, 1
+; RV32-ZILX-NEXT: lxw a0, (a0), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV32-ZBA-LABEL: lxsuww_shl_too_small:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: sh1add a0, a1, a0
+; RV32-ZBA-NEXT: lw a0, 0(a0)
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxsuww_shl_too_small:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: slli a1, a1, 1
+; RV32-ZBA-ZILX-NEXT: lxw a0, (a0), a1
+; RV32-ZBA-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxsuww_shl_too_small:
+; RV64: # %bb.0:
+; RV64-NEXT: slli a1, a1, 32
+; RV64-NEXT: srli a1, a1, 31
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lw a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxsuww_shl_too_small:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: slli a1, a1, 32
+; RV64-ZILX-NEXT: srli a1, a1, 31
+; RV64-ZILX-NEXT: lxw a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+;
+; RV64-ZBA-LABEL: lxsuww_shl_too_small:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: sh1add.uw a0, a1, a0
+; RV64-ZBA-NEXT: lw a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxsuww_shl_too_small:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: slli.uw a1, a1, 1
+; RV64-ZBA-ZILX-NEXT: lxw a0, (a0), a1
+; RV64-ZBA-ZILX-NEXT: ret
+ %1 = zext i32 %b to i64
+ %2 = getelementptr i16, ptr %a, i64 %1
+ %3 = load i32, ptr %2, align 4
+ ret i32 %3
+}
+
+define i32 @lxsuww_shl_too_large(ptr %a, i32 %b) {
+; RV32-LABEL: lxsuww_shl_too_large:
+; RV32: # %bb.0:
+; RV32-NEXT: slli a1, a1, 3
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: lw a0, 0(a0)
+; RV32-NEXT: ret
+;
+; RV32-ZILX-LABEL: lxsuww_shl_too_large:
+; RV32-ZILX: # %bb.0:
+; RV32-ZILX-NEXT: slli a1, a1, 3
+; RV32-ZILX-NEXT: lxw a0, (a0), a1
+; RV32-ZILX-NEXT: ret
+;
+; RV32-ZBA-LABEL: lxsuww_shl_too_large:
+; RV32-ZBA: # %bb.0:
+; RV32-ZBA-NEXT: sh3add a0, a1, a0
+; RV32-ZBA-NEXT: lw a0, 0(a0)
+; RV32-ZBA-NEXT: ret
+;
+; RV32-ZBA-ZILX-LABEL: lxsuww_shl_too_large:
+; RV32-ZBA-ZILX: # %bb.0:
+; RV32-ZBA-ZILX-NEXT: slli a1, a1, 3
+; RV32-ZBA-ZILX-NEXT: lxw a0, (a0), a1
+; RV32-ZBA-ZILX-NEXT: ret
+;
+; RV64-LABEL: lxsuww_shl_too_large:
+; RV64: # %bb.0:
+; RV64-NEXT: slli a1, a1, 32
+; RV64-NEXT: srli a1, a1, 29
+; RV64-NEXT: add a0, a0, a1
+; RV64-NEXT: lw a0, 0(a0)
+; RV64-NEXT: ret
+;
+; RV64-ZILX-LABEL: lxsuww_shl_too_large:
+; RV64-ZILX: # %bb.0:
+; RV64-ZILX-NEXT: slli a1, a1, 32
+; RV64-ZILX-NEXT: srli a1, a1, 29
+; RV64-ZILX-NEXT: lxw a0, (a0), a1
+; RV64-ZILX-NEXT: ret
+;
+; RV64-ZBA-LABEL: lxsuww_shl_too_large:
+; RV64-ZBA: # %bb.0:
+; RV64-ZBA-NEXT: sh3add.uw a0, a1, a0
+; RV64-ZBA-NEXT: lw a0, 0(a0)
+; RV64-ZBA-NEXT: ret
+;
+; RV64-ZBA-ZILX-LABEL: lxsuww_shl_too_large:
+; RV64-ZBA-ZILX: # %bb.0:
+; RV64-ZBA-ZILX-NEXT: slli.uw a1, a1, 3
+; RV64-ZBA-ZILX-NEXT: lxw a0, (a0), a1
+; RV64-ZBA-ZILX-NEXT: ret
+ %1 = zext i32 %b to i64
+ %2 = getelementptr i64, ptr %a, i64 %1
+ %3 = load i32, ptr %2, align 4
+ ret i32 %3
+}
More information about the llvm-commits
mailing list