diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp --- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp @@ -160,8 +160,9 @@ } // 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) +// (load (addi base, off1), off2) -> (load base, off1+off2) +// (store val, (addi base, off1), off2) -> (store val, base, off1+off2) +// This is possible when off1+off2 fits a 12-bit immediate. void RISCVDAGToDAGISel::doPeepholeLoadStoreADDI() { SelectionDAG::allnodes_iterator Position(CurDAG->getRoot().getNode()); ++Position; @@ -202,10 +203,7 @@ break; } - // Currently, the load/store offset must be 0 to be considered for this - // peephole optimisation. - if (!isa(N->getOperand(OffsetOpIdx)) || - N->getConstantOperandVal(OffsetOpIdx) != 0) + if (!isa(N->getOperand(OffsetOpIdx))) continue; SDValue Base = N->getOperand(BaseOpIdx); @@ -215,14 +213,28 @@ continue; SDValue ImmOperand = Base.getOperand(1); + uint64_t Offset2 = N->getConstantOperandVal(OffsetOpIdx); if (auto Const = dyn_cast(ImmOperand)) { - ImmOperand = CurDAG->getTargetConstant( - Const->getSExtValue(), SDLoc(ImmOperand), ImmOperand.getValueType()); + int64_t Offset1 = Const->getSExtValue(); + int64_t CombinedOffset = Offset1 + Offset2; + if (!isInt<12>(CombinedOffset)) + continue; + ImmOperand = CurDAG->getTargetConstant(CombinedOffset, SDLoc(ImmOperand), + ImmOperand.getValueType()); } else if (auto GA = dyn_cast(ImmOperand)) { + // If the off1 in (addi base, off1) is a global variable's address (its + // low part, really), then we can rely on the alignment of that variable + // to provide a margin of safety before off1 can overflow the 12 bits. + // Check if off2 falls within that margin; if so off1+off2 can't overflow. + unsigned Alignment = GA->getGlobal()->getAlignment(); + if (Offset2 != 0 && Offset2 >= Alignment) + continue; + int64_t Offset1 = GA->getOffset(); + int64_t CombinedOffset = Offset1 + Offset2; ImmOperand = CurDAG->getTargetGlobalAddress( GA->getGlobal(), SDLoc(ImmOperand), ImmOperand.getValueType(), - GA->getOffset(), GA->getTargetFlags()); + CombinedOffset, GA->getTargetFlags()); } else { continue; } diff --git a/llvm/test/CodeGen/RISCV/fold-addi-loadstore.ll b/llvm/test/CodeGen/RISCV/fold-addi-loadstore.ll --- a/llvm/test/CodeGen/RISCV/fold-addi-loadstore.ll +++ b/llvm/test/CodeGen/RISCV/fold-addi-loadstore.ll @@ -99,8 +99,7 @@ ; RV32I: # %bb.0: # %entry ; RV32I-NEXT: lui a1, %hi(g_8) ; RV32I-NEXT: lw a0, %lo(g_8)(a1) -; RV32I-NEXT: addi a1, a1, %lo(g_8) -; RV32I-NEXT: lw a1, 4(a1) +; RV32I-NEXT: lw a1, %lo(g_8+4)(a1) ; RV32I-NEXT: ret ; ; RV64I-LABEL: load_g_8: @@ -118,8 +117,7 @@ ; RV32I: # %bb.0: # %entry ; RV32I-NEXT: lui a1, %hi(g_16) ; RV32I-NEXT: lw a0, %lo(g_16)(a1) -; RV32I-NEXT: addi a1, a1, %lo(g_16) -; RV32I-NEXT: lw a1, 4(a1) +; RV32I-NEXT: lw a1, %lo(g_16+4)(a1) ; RV32I-NEXT: ret ; ; RV64I-LABEL: load_g_16: @@ -155,9 +153,8 @@ ; RV32I-LABEL: store_g_8: ; RV32I: # %bb.0: # %entry ; RV32I-NEXT: lui a0, %hi(g_8) +; RV32I-NEXT: sw zero, %lo(g_8+4)(a0) ; RV32I-NEXT: sw zero, %lo(g_8)(a0) -; RV32I-NEXT: addi a0, a0, %lo(g_8) -; RV32I-NEXT: sw zero, 4(a0) ; RV32I-NEXT: ret ; ; RV64I-LABEL: store_g_8: @@ -197,15 +194,14 @@ define i64 @load_ga_16() nounwind { ; RV32I-LABEL: load_ga_16: ; RV32I: # %bb.0: # %entry -; RV32I-NEXT: lui a0, %hi(ga_16) -; RV32I-NEXT: addi a1, a0, %lo(ga_16) -; RV32I-NEXT: lw a0, 8(a1) -; RV32I-NEXT: lw a1, 12(a1) +; RV32I-NEXT: lui a1, %hi(ga_16) +; RV32I-NEXT: lw a0, %lo(ga_16+8)(a1) +; RV32I-NEXT: lw a1, %lo(ga_16+12)(a1) ; RV32I-NEXT: ret ; ; RV64I-LABEL: load_ga_16: ; RV64I: # %bb.0: # %entry -; RV64I-NEXT: lui a0, %hi(ga_16+8) +; RV64I-NEXT: lui a0, %hi(ga_16) ; RV64I-NEXT: ld a0, %lo(ga_16+8)(a0) ; RV64I-NEXT: ret entry: @@ -245,8 +241,7 @@ ; RV32I-NEXT: lui a0, %tprel_hi(tl_8) ; RV32I-NEXT: add a1, a0, tp, %tprel_add(tl_8) ; RV32I-NEXT: lw a0, %tprel_lo(tl_8)(a1) -; RV32I-NEXT: addi a1, a1, %tprel_lo(tl_8) -; RV32I-NEXT: lw a1, 4(a1) +; RV32I-NEXT: lw a1, %tprel_lo(tl_8+4)(a1) ; RV32I-NEXT: ret ; ; RV64I-LABEL: load_tl_8: