Index: lib/Target/RISCV/RISCVISelDAGToDAG.cpp =================================================================== --- lib/Target/RISCV/RISCVISelDAGToDAG.cpp +++ lib/Target/RISCV/RISCVISelDAGToDAG.cpp @@ -56,12 +56,14 @@ private: void doPeepholeLoadStoreADDI(); + void doPeepholeGlobalAddiLuiOffset(); void doPeepholeBuildPairF64SplitF64(); }; } void RISCVDAGToDAGISel::PostprocessISelDAG() { doPeepholeLoadStoreADDI(); + doPeepholeGlobalAddiLuiOffset(); doPeepholeBuildPairF64SplitF64(); } @@ -128,6 +130,208 @@ return false; } +// Detect the pattern lui %hi(global) --> ADDI %lo(global) +// HiLUI LoADDI +static bool detectLuiAddiGlobal(SDNode *Tail, unsigned &Idx, SDValue &LoADDI, + SDValue &HiLUI, GlobalAddressSDNode *&GAlo, + GlobalAddressSDNode *&GAhi) { + // Try to detect the pattern on every operand of the tail instruction. + for (Idx = 0; Idx < Tail->getNumOperands(); Idx++) { + LoADDI = Tail->getOperand(Idx); + // LoADDI should only be used by one instruction (Tail). + if (!LoADDI->isMachineOpcode() || + !(LoADDI->getMachineOpcode() == RISCV::ADDI) || + !isa(LoADDI->getOperand(1)) || + !LoADDI->hasOneUse()) + continue; + // Check for existence of %lo target flag. + GAlo = cast(LoADDI->getOperand(1)); + if (!(GAlo->getTargetFlags() == RISCVII::MO_LO) || + !(GAlo->getOffset() == 0)) + return false; + // Check for existence of %hi target flag. + HiLUI = LoADDI->getOperand(0); + if (!HiLUI->isMachineOpcode() || + !(HiLUI->getMachineOpcode() == RISCV::LUI) || + !isa(HiLUI->getOperand(0)) || !HiLUI->hasOneUse()) + return false; + GAhi = cast(HiLUI->getOperand(0)); + if (!(GAhi->getTargetFlags() == RISCVII::MO_HI) || + !(GAhi->getOffset() == 0)) + return false; + return true; + } + return false; +} + +static bool matchLuiOffset(SDValue &OffsetLUI, int64_t &Offset) { + if (!OffsetLUI->isMachineOpcode() || + !(OffsetLUI->getMachineOpcode() == RISCV::LUI) || + !isa(OffsetLUI->getOperand(0))) + return false; + Offset = cast(OffsetLUI->getOperand(0))->getSExtValue(); + Offset = Offset << 12; + DEBUG(dbgs() << " Detected \" LUI Offset_hi\"\n"); + return true; +} + +static bool matchAddiLuiOffset(SDValue &OffsetLoADDI, int64_t &Offset) { + // LoADDI should only be used by the tail instruction only. + if (!OffsetLoADDI->isMachineOpcode() || + !(OffsetLoADDI->getMachineOpcode() == RISCV::ADDI) || + !isa(OffsetLoADDI->getOperand(1)) || + !OffsetLoADDI->hasOneUse()) + return false; + int64_t OffLo = + cast(OffsetLoADDI->getOperand(1))->getZExtValue(); + // HiLUI should only be used by the loADDI. + SDValue OffsetHiLUI = (OffsetLoADDI->getOperand(0)); + if (!OffsetHiLUI->isMachineOpcode() || + !(OffsetHiLUI->getMachineOpcode() == RISCV::LUI) || + !isa(OffsetHiLUI->getOperand(0)) || + !OffsetHiLUI->hasOneUse()) + return false; + int64_t OffHi = + cast(OffsetHiLUI->getOperand(0))->getSExtValue(); + Offset = (OffHi << 12) + OffLo; + DEBUG(dbgs() << " Detected \" ADDI (LUI Offset_hi), Offset_lo\"\n"); + return true; +} + +static void updateTailInstrUsers(SDNode *Tail, SelectionDAG *CurDAG, + GlobalAddressSDNode *GAhi, + GlobalAddressSDNode *GAlo, + SDValue &GlobalHiLUI, SDValue &GlobalLoADDI, + int64_t Offset) { + // Update the offset in GAhi and GAlo. + SDLoc DL(Tail->getOperand(1)); + SDValue GAHiNew = CurDAG->getTargetGlobalAddress(GAhi->getGlobal(), DL, + GlobalHiLUI.getValueType(), + Offset, RISCVII::MO_HI); + SDValue GALoNew = CurDAG->getTargetGlobalAddress(GAlo->getGlobal(), DL, + GlobalLoADDI.getValueType(), + Offset, RISCVII::MO_LO); + CurDAG->UpdateNodeOperands(GlobalHiLUI.getNode(), GAHiNew); + CurDAG->UpdateNodeOperands(GlobalLoADDI.getNode(), GlobalHiLUI, GALoNew); + // Update all uses of the Tail with the GlobalLoADDI. After + // this Tail will be a dead node. + SDValue From = SDValue(Tail, 0); + CurDAG->ReplaceAllUsesOfValuesWith(&From, &GlobalLoADDI, 1); +} + +// Merge the offset of address calculation into the offset field +// of a global address node in a global address lowering sequence ("LUI +// %hi(global) --> add %lo(global)") under the following conditions: 1) The +// offset field in the global address lowering sequence is zero. 2) The lowered +// global address is only used in one node, referred to as "Tail". + +// This peephole does the following transformations to merge the offset: + +// 1) ADDI (ADDI (LUI %hi(global)) %lo(global)), offset +// ---> +// ADDI (LUI %hi(global + offset)) %lo(global + offset). +// +// This generates: +// lui a0, hi (global + offset) +// add a0, a0, lo (global + offset) +// Instead of +// lui a0, hi (global) +// addi a0, hi (global) +// addi a0, offset +// This pattern is for cases when the offset is small enough to fit in the +// immediate filed of ADDI (less than 12 bits). + +// 2) ADD ((ADDI (LUI %hi(global)) %lo(global)), (LUI hi_offset)) +// ---> +// offset = hi_offset << 12 +// ADDI (LUI %hi(global + offset)) %lo(global + offset) + +// Which generates the ASM: +// lui a0, hi(global + offset) +// addi a0, lo(global + offset) +// Instead of: +// lui a0, hi(global) +// addi a0, lo(global) +// lui a1, (offset) +// add a0, a0, a1 + +// This pattern is for cases when the offset doesn't fit in an immediate field +// of ADDI but the lower 12 bits are all zeros. + +// 3) ADD ((ADDI (LUI %hi(global)) %lo(global)), (ADDI lo_offset, (LUI +// hi_offset))) +// ---> +// ADDI (LUI %hi(global + offset)) %lo(global + offset) +// Which generates the ASM: +// lui a1, %hi(global + offhi20<<12 + offlo12) +// addi a1, %lo(global + offhi20<<12 + offlo12) +// Instead of: +// lui a0, hi(global) +// addi a0, lo(global) +// lui a1, (offhi20) +// addi a1, (offlo12) +// add a0, a0, a1 +// This pattern is for cases when the offset doesn't fit in an immediate field +// of ADDI and both the lower 1 bits and high 20 bits are non zero. +void RISCVDAGToDAGISel::doPeepholeGlobalAddiLuiOffset() { + SelectionDAG::allnodes_iterator Position(CurDAG->getRoot().getNode()); + ++Position; + SelectionDAG::allnodes_iterator Begin(CurDAG->allnodes_begin()); + while (Position != Begin) { + SDNode *Tail = &*--Position; + // Skip dead nodes and any non-machine opcodes. + if (Tail->use_empty() || !Tail->isMachineOpcode()) + continue; + // The tail instruction can be an ADD or an ADDI. + if (!Tail->isMachineOpcode() || !(Tail->getMachineOpcode() == RISCV::ADD || + Tail->getMachineOpcode() == RISCV::ADDI)) + continue; + // First detect the global address part of pattern: + // (lui %hi(global) --> Addi %lo(global)) + unsigned GlobalLoADDiIdx; + SDValue GlobalLoADDI; + SDValue GlobalHiLUI; + GlobalAddressSDNode *GAhi; + GlobalAddressSDNode *GAlo; + if (!detectLuiAddiGlobal(Tail, GlobalLoADDiIdx, GlobalLoADDI, GlobalHiLUI, + GAlo, GAhi)) + continue; + DEBUG(dbgs() << " Detected \"ADDI LUI %hi(global), %lo(global)\n"); + // Detect the offset part for the address calculation by looking at the + // other operand of the tail instruction: + int64_t Offset; + if (Tail->getMachineOpcode() == RISCV::ADD) { + // If the Tail is an ADD instruction, the offset can be in two forms: + // 1) LUI hi_Offset followed by: + // ADDI lo_offset + // This happens in case the offset has non zero bits in + // both hi 20 and lo 12 bits. + // 2) LUI (offset20) + // This happens in case the lower 12 bits of the offset are zeros. + SDValue OffsetVal = Tail->getOperand(1 - GlobalLoADDiIdx); + if (!matchAddiLuiOffset(OffsetVal, Offset) && + !matchLuiOffset(OffsetVal, Offset)) + continue; + } else + // The Tail is an ADDI instruction: + Offset = cast(Tail->getOperand(1 - GlobalLoADDiIdx)) + ->getSExtValue(); + + DEBUG(dbgs() + << " Fold offset value into global offset of LUI %hi and ADDI %lo\n"); + DEBUG(dbgs() << "\tTail:"); + DEBUG(Tail->dump(CurDAG)); + DEBUG(dbgs() << "\tGlobalHiLUI:"); + DEBUG(GlobalHiLUI->dump(CurDAG)); + DEBUG(dbgs() << "\tGlobalLoADDI:"); + DEBUG(GlobalLoADDI->dump(CurDAG)); + DEBUG(dbgs() << "\n"); + updateTailInstrUsers(Tail, CurDAG, GAhi, GAlo, GlobalHiLUI, GlobalLoADDI, + Offset); + } + CurDAG->RemoveDeadNodes(); +} + // Merge an ADDI into the offset of a load/store instruction where possible. // (load (add base, off), 0) -> (load base, off) // (store val, (add base, off)) -> (store val, base, off) Index: lib/Target/RISCV/RISCVISelLowering.cpp =================================================================== --- lib/Target/RISCV/RISCVISelLowering.cpp +++ lib/Target/RISCV/RISCVISelLowering.cpp @@ -293,17 +293,19 @@ GlobalAddressSDNode *N = cast(Op); const GlobalValue *GV = N->getGlobal(); int64_t Offset = N->getOffset(); + MVT XLenVT = Subtarget.getXLenVT(); if (isPositionIndependent() || Subtarget.is64Bit()) report_fatal_error("Unable to lowerGlobalAddress"); - SDValue GAHi = - DAG.getTargetGlobalAddress(GV, DL, Ty, Offset, RISCVII::MO_HI); - SDValue GALo = - DAG.getTargetGlobalAddress(GV, DL, Ty, Offset, RISCVII::MO_LO); + SDValue GAHi = DAG.getTargetGlobalAddress(GV, DL, Ty, 0, RISCVII::MO_HI); + SDValue GALo = DAG.getTargetGlobalAddress(GV, DL, Ty, 0, RISCVII::MO_LO); SDValue MNHi = SDValue(DAG.getMachineNode(RISCV::LUI, DL, Ty, GAHi), 0); SDValue MNLo = SDValue(DAG.getMachineNode(RISCV::ADDI, DL, Ty, MNHi, GALo), 0); + if (Offset != 0) + return DAG.getNode(ISD::ADD, DL, Ty, MNLo, + DAG.getConstant(Offset, DL, XLenVT)); return MNLo; } Index: test/CodeGen/RISCV/byval.ll =================================================================== --- test/CodeGen/RISCV/byval.ll +++ test/CodeGen/RISCV/byval.ll @@ -22,18 +22,16 @@ ; RV32I: # %bb.0: # %entry ; RV32I-NEXT: addi sp, sp, -32 ; RV32I-NEXT: sw ra, 28(sp) -; RV32I-NEXT: lui a0, %hi(foo+12) -; RV32I-NEXT: lw a0, %lo(foo+12)(a0) -; RV32I-NEXT: sw a0, 24(sp) -; RV32I-NEXT: lui a0, %hi(foo+8) -; RV32I-NEXT: lw a0, %lo(foo+8)(a0) -; RV32I-NEXT: sw a0, 20(sp) -; RV32I-NEXT: lui a0, %hi(foo+4) -; RV32I-NEXT: lw a0, %lo(foo+4)(a0) -; RV32I-NEXT: sw a0, 16(sp) ; RV32I-NEXT: lui a0, %hi(foo) -; RV32I-NEXT: lw a0, %lo(foo)(a0) -; RV32I-NEXT: sw a0, 12(sp) +; RV32I-NEXT: lw a1, %lo(foo)(a0) +; RV32I-NEXT: sw a1, 12(sp) +; RV32I-NEXT: addi a0, a0, %lo(foo) +; RV32I-NEXT: lw a1, 12(a0) +; RV32I-NEXT: sw a1, 24(sp) +; RV32I-NEXT: lw a1, 8(a0) +; RV32I-NEXT: sw a1, 20(sp) +; RV32I-NEXT: lw a0, 4(a0) +; RV32I-NEXT: sw a0, 16(sp) ; RV32I-NEXT: addi a0, sp, 12 ; RV32I-NEXT: call callee ; RV32I-NEXT: lw ra, 28(sp) Index: test/CodeGen/RISCV/double-mem.ll =================================================================== --- test/CodeGen/RISCV/double-mem.ll +++ test/CodeGen/RISCV/double-mem.ll @@ -64,9 +64,9 @@ ; RV32IFD-NEXT: lui a0, %hi(G) ; RV32IFD-NEXT: fld ft1, %lo(G)(a0) ; RV32IFD-NEXT: fsd ft0, %lo(G)(a0) -; RV32IFD-NEXT: lui a0, %hi(G+72) -; RV32IFD-NEXT: fld ft1, %lo(G+72)(a0) -; RV32IFD-NEXT: fsd ft0, %lo(G+72)(a0) +; RV32IFD-NEXT: addi a0, a0, %lo(G) +; RV32IFD-NEXT: fld ft1, 72(a0) +; RV32IFD-NEXT: fsd ft0, 72(a0) ; RV32IFD-NEXT: fsd ft0, 8(sp) ; RV32IFD-NEXT: lw a0, 8(sp) ; RV32IFD-NEXT: lw a1, 12(sp) Index: test/CodeGen/RISCV/float-mem.ll =================================================================== --- test/CodeGen/RISCV/float-mem.ll +++ test/CodeGen/RISCV/float-mem.ll @@ -51,9 +51,9 @@ ; RV32IF-NEXT: lui a0, %hi(G) ; RV32IF-NEXT: flw ft1, %lo(G)(a0) ; RV32IF-NEXT: fsw ft0, %lo(G)(a0) -; RV32IF-NEXT: lui a0, %hi(G+36) -; RV32IF-NEXT: flw ft1, %lo(G+36)(a0) -; RV32IF-NEXT: fsw ft0, %lo(G+36)(a0) +; RV32IF-NEXT: addi a0, a0, %lo(G) +; RV32IF-NEXT: flw ft1, 36(a0) +; RV32IF-NEXT: fsw ft0, 36(a0) ; RV32IF-NEXT: fmv.x.w a0, ft0 ; RV32IF-NEXT: ret %1 = fadd float %a, %b Index: test/CodeGen/RISCV/fp128.ll =================================================================== --- test/CodeGen/RISCV/fp128.ll +++ test/CodeGen/RISCV/fp128.ll @@ -13,30 +13,26 @@ ; RV32I: # %bb.0: ; RV32I-NEXT: addi sp, sp, -48 ; RV32I-NEXT: sw ra, 44(sp) -; RV32I-NEXT: lui a0, %hi(y+12) -; RV32I-NEXT: lw a0, %lo(y+12)(a0) -; RV32I-NEXT: sw a0, 20(sp) -; RV32I-NEXT: lui a0, %hi(y+8) -; RV32I-NEXT: lw a0, %lo(y+8)(a0) -; RV32I-NEXT: sw a0, 16(sp) -; RV32I-NEXT: lui a0, %hi(y+4) -; RV32I-NEXT: lw a0, %lo(y+4)(a0) -; RV32I-NEXT: sw a0, 12(sp) ; RV32I-NEXT: lui a0, %hi(y) -; RV32I-NEXT: lw a0, %lo(y)(a0) -; RV32I-NEXT: sw a0, 8(sp) -; RV32I-NEXT: lui a0, %hi(x+12) -; RV32I-NEXT: lw a0, %lo(x+12)(a0) -; RV32I-NEXT: sw a0, 36(sp) -; RV32I-NEXT: lui a0, %hi(x+8) -; RV32I-NEXT: lw a0, %lo(x+8)(a0) -; RV32I-NEXT: sw a0, 32(sp) -; RV32I-NEXT: lui a0, %hi(x+4) -; RV32I-NEXT: lw a0, %lo(x+4)(a0) +; RV32I-NEXT: lw a1, %lo(y)(a0) +; RV32I-NEXT: sw a1, 8(sp) +; RV32I-NEXT: lui a1, %hi(x) +; RV32I-NEXT: lw a2, %lo(x)(a1) +; RV32I-NEXT: sw a2, 24(sp) +; RV32I-NEXT: addi a0, a0, %lo(y) +; RV32I-NEXT: lw a2, 12(a0) +; RV32I-NEXT: sw a2, 20(sp) +; RV32I-NEXT: lw a2, 8(a0) +; RV32I-NEXT: sw a2, 16(sp) +; RV32I-NEXT: lw a0, 4(a0) +; RV32I-NEXT: sw a0, 12(sp) +; RV32I-NEXT: addi a0, a1, %lo(x) +; RV32I-NEXT: lw a1, 12(a0) +; RV32I-NEXT: sw a1, 36(sp) +; RV32I-NEXT: lw a1, 8(a0) +; RV32I-NEXT: sw a1, 32(sp) +; RV32I-NEXT: lw a0, 4(a0) ; RV32I-NEXT: sw a0, 28(sp) -; RV32I-NEXT: lui a0, %hi(x) -; RV32I-NEXT: lw a0, %lo(x)(a0) -; RV32I-NEXT: sw a0, 24(sp) ; RV32I-NEXT: addi a0, sp, 24 ; RV32I-NEXT: addi a1, sp, 8 ; RV32I-NEXT: call __netf2 @@ -57,30 +53,26 @@ ; RV32I: # %bb.0: ; RV32I-NEXT: addi sp, sp, -80 ; RV32I-NEXT: sw ra, 76(sp) -; RV32I-NEXT: lui a0, %hi(y+12) -; RV32I-NEXT: lw a0, %lo(y+12)(a0) -; RV32I-NEXT: sw a0, 36(sp) -; RV32I-NEXT: lui a0, %hi(y+8) -; RV32I-NEXT: lw a0, %lo(y+8)(a0) -; RV32I-NEXT: sw a0, 32(sp) -; RV32I-NEXT: lui a0, %hi(y+4) -; RV32I-NEXT: lw a0, %lo(y+4)(a0) -; RV32I-NEXT: sw a0, 28(sp) ; RV32I-NEXT: lui a0, %hi(y) -; RV32I-NEXT: lw a0, %lo(y)(a0) -; RV32I-NEXT: sw a0, 24(sp) -; RV32I-NEXT: lui a0, %hi(x+12) -; RV32I-NEXT: lw a0, %lo(x+12)(a0) -; RV32I-NEXT: sw a0, 52(sp) -; RV32I-NEXT: lui a0, %hi(x+8) -; RV32I-NEXT: lw a0, %lo(x+8)(a0) -; RV32I-NEXT: sw a0, 48(sp) -; RV32I-NEXT: lui a0, %hi(x+4) -; RV32I-NEXT: lw a0, %lo(x+4)(a0) +; RV32I-NEXT: lw a1, %lo(y)(a0) +; RV32I-NEXT: sw a1, 24(sp) +; RV32I-NEXT: lui a1, %hi(x) +; RV32I-NEXT: lw a2, %lo(x)(a1) +; RV32I-NEXT: sw a2, 40(sp) +; RV32I-NEXT: addi a0, a0, %lo(y) +; RV32I-NEXT: lw a2, 12(a0) +; RV32I-NEXT: sw a2, 36(sp) +; RV32I-NEXT: lw a2, 8(a0) +; RV32I-NEXT: sw a2, 32(sp) +; RV32I-NEXT: lw a0, 4(a0) +; RV32I-NEXT: sw a0, 28(sp) +; RV32I-NEXT: addi a0, a1, %lo(x) +; RV32I-NEXT: lw a1, 12(a0) +; RV32I-NEXT: sw a1, 52(sp) +; RV32I-NEXT: lw a1, 8(a0) +; RV32I-NEXT: sw a1, 48(sp) +; RV32I-NEXT: lw a0, 4(a0) ; RV32I-NEXT: sw a0, 44(sp) -; RV32I-NEXT: lui a0, %hi(x) -; RV32I-NEXT: lw a0, %lo(x)(a0) -; RV32I-NEXT: sw a0, 40(sp) ; RV32I-NEXT: addi a0, sp, 56 ; RV32I-NEXT: addi a1, sp, 40 ; RV32I-NEXT: addi a2, sp, 24 Index: test/CodeGen/RISCV/hoist-global-addr-base.ll =================================================================== --- /dev/null +++ test/CodeGen/RISCV/hoist-global-addr-base.ll @@ -0,0 +1,67 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 < %s | FileCheck %s + +%struct.S = type { [40 x i32], i32, i32, i32, [4100 x i32], i32, i32, i32 } +@s = common dso_local global %struct.S zeroinitializer, align 4 + +define dso_local void @multiple_stores() local_unnamed_addr { +; CHECK-LABEL: multiple_stores: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: lui a0, %hi(s) +; CHECK-NEXT: addi a0, a0, %lo(s) +; CHECK-NEXT: addi a1, zero, 20 +; CHECK-NEXT: sw a1, 164(a0) +; CHECK-NEXT: addi a1, zero, 10 +; CHECK-NEXT: sw a1, 160(a0) +; CHECK-NEXT: ret +entry: + store i32 10, i32* getelementptr inbounds (%struct.S, %struct.S* @s, i32 0, i32 1), align 4 + store i32 20, i32* getelementptr inbounds (%struct.S, %struct.S* @s, i32 0, i32 2), align 4 + ret void +} + +define dso_local void @control_flow() local_unnamed_addr #0 { +; CHECK-LABEL: control_flow: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: lui a0, %hi(s) +; CHECK-NEXT: addi a0, a0, %lo(s) +; CHECK-NEXT: lw a1, 164(a0) +; CHECK-NEXT: addi a2, zero, 1 +; CHECK-NEXT: blt a1, a2, .LBB1_2 +; CHECK-NEXT: # %bb.1: # %if.then +; CHECK-NEXT: addi a1, zero, 10 +; CHECK-NEXT: sw a1, 160(a0) +; CHECK-NEXT: .LBB1_2: # %if.end +; CHECK-NEXT: ret +entry: + %0 = load i32, i32* getelementptr inbounds (%struct.S, %struct.S* @s, i32 0, i32 2), align 4 + %cmp = icmp sgt i32 %0, 0 + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %entry + store i32 10, i32* getelementptr inbounds (%struct.S, %struct.S* @s, i32 0, i32 1), align 4 + br label %if.end + +if.end: ; preds = %if.then, %entry + ret void +} + +define dso_local i32* @big_offset_one_use() local_unnamed_addr { +; CHECK-LABEL: big_offset_one_use: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: lui a0, %hi(s+16572) +; CHECK-NEXT: addi a0, a0, %lo(s+16572) +; CHECK-NEXT: ret +entry: + ret i32* getelementptr inbounds (%struct.S, %struct.S* @s, i32 0, i32 5) +} + +define dso_local i32* @small_offset_one_use() local_unnamed_addr { +; CHECK-LABEL: small_offset_one_use: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: lui a0, %hi(s+160) +; CHECK-NEXT: addi a0, a0, %lo(s+160) +; CHECK-NEXT: ret +entry: + ret i32* getelementptr inbounds (%struct.S, %struct.S* @s, i32 0, i32 1) +} Index: test/CodeGen/RISCV/mem.ll =================================================================== --- test/CodeGen/RISCV/mem.ll +++ test/CodeGen/RISCV/mem.ll @@ -168,9 +168,9 @@ ; RV32I-NEXT: lui a2, %hi(G) ; RV32I-NEXT: lw a1, %lo(G)(a2) ; RV32I-NEXT: sw a0, %lo(G)(a2) -; RV32I-NEXT: lui a2, %hi(G+36) -; RV32I-NEXT: lw a3, %lo(G+36)(a2) -; RV32I-NEXT: sw a0, %lo(G+36)(a2) +; RV32I-NEXT: addi a2, a2, %lo(G) +; RV32I-NEXT: lw a3, 36(a2) +; RV32I-NEXT: sw a0, 36(a2) ; RV32I-NEXT: mv a0, a1 ; RV32I-NEXT: ret %1 = load volatile i32, i32* @G Index: test/CodeGen/RISCV/wide-mem.ll =================================================================== --- test/CodeGen/RISCV/wide-mem.ll +++ test/CodeGen/RISCV/wide-mem.ll @@ -20,10 +20,10 @@ define i64 @load_i64_global() nounwind { ; RV32I-LABEL: load_i64_global: ; RV32I: # %bb.0: -; RV32I-NEXT: lui a0, %hi(val64) -; RV32I-NEXT: lw a0, %lo(val64)(a0) -; RV32I-NEXT: lui a1, %hi(val64+4) -; RV32I-NEXT: lw a1, %lo(val64+4)(a1) +; RV32I-NEXT: lui a1, %hi(val64) +; RV32I-NEXT: lw a0, %lo(val64)(a1) +; RV32I-NEXT: addi a1, a1, %lo(val64) +; RV32I-NEXT: lw a1, 4(a1) ; RV32I-NEXT: ret %1 = load i64, i64* @val64 ret i64 %1 Index: test/CodeGen/RISCV/zext-with-load-is-free.ll =================================================================== --- test/CodeGen/RISCV/zext-with-load-is-free.ll +++ test/CodeGen/RISCV/zext-with-load-is-free.ll @@ -10,12 +10,12 @@ ; RV32I-LABEL: test_zext_i8: ; RV32I: # %bb.0: # %entry ; RV32I-NEXT: lui a0, %hi(bytes) -; RV32I-NEXT: lbu a0, %lo(bytes)(a0) -; RV32I-NEXT: addi a1, zero, 136 -; RV32I-NEXT: bne a0, a1, .LBB0_3 +; RV32I-NEXT: lbu a1, %lo(bytes)(a0) +; RV32I-NEXT: addi a2, zero, 136 +; RV32I-NEXT: bne a1, a2, .LBB0_3 ; RV32I-NEXT: # %bb.1: # %entry -; RV32I-NEXT: lui a0, %hi(bytes+1) -; RV32I-NEXT: lbu a0, %lo(bytes+1)(a0) +; RV32I-NEXT: addi a0, a0, %lo(bytes) +; RV32I-NEXT: lbu a0, 1(a0) ; RV32I-NEXT: addi a1, zero, 7 ; RV32I-NEXT: bne a0, a1, .LBB0_3 ; RV32I-NEXT: # %bb.2: # %if.end @@ -44,14 +44,14 @@ define i32 @test_zext_i16() { ; RV32I-LABEL: test_zext_i16: ; RV32I: # %bb.0: # %entry -; RV32I-NEXT: lui a0, 16 -; RV32I-NEXT: addi a0, a0, -120 -; RV32I-NEXT: lui a1, %hi(shorts) -; RV32I-NEXT: lhu a1, %lo(shorts)(a1) -; RV32I-NEXT: bne a1, a0, .LBB1_3 +; RV32I-NEXT: lui a0, %hi(shorts) +; RV32I-NEXT: lui a1, 16 +; RV32I-NEXT: addi a1, a1, -120 +; RV32I-NEXT: lhu a2, %lo(shorts)(a0) +; RV32I-NEXT: bne a2, a1, .LBB1_3 ; RV32I-NEXT: # %bb.1: # %entry -; RV32I-NEXT: lui a0, %hi(shorts+2) -; RV32I-NEXT: lhu a0, %lo(shorts+2)(a0) +; RV32I-NEXT: addi a0, a0, %lo(shorts) +; RV32I-NEXT: lhu a0, 2(a0) ; RV32I-NEXT: addi a1, zero, 7 ; RV32I-NEXT: bne a0, a1, .LBB1_3 ; RV32I-NEXT: # %bb.2: # %if.end