[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