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 @@ -1839,10 +1839,37 @@ if (SelectAddrFrameIndex(Addr, Base, Offset)) return true; + if (Addr.getOpcode() == RISCVISD::ADD_LO) { + Base = Addr.getOperand(0); + Offset = Addr.getOperand(1); + return true; + } + if (CurDAG->isBaseWithConstantOffset(Addr)) { int64_t CVal = cast(Addr.getOperand(1))->getSExtValue(); if (isInt<12>(CVal)) { Base = Addr.getOperand(0); + if (Base.getOpcode() == RISCVISD::ADD_LO) { + SDValue LoOperand = Base.getOperand(1); + if (auto *GA = dyn_cast(LoOperand)) { + // If the Lo in (ADD_LO hi, lo) 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 low part can overflow + // the 12 bits of the load/store offset. Check if CVal falls within + // that margin; if so (low part + CVal) can't overflow. + const DataLayout &DL = CurDAG->getDataLayout(); + Align Alignment = GA->getGlobal()->getPointerAlignment(DL); + if (CVal == 0 || Alignment > CVal) { + int64_t CombinedOffset = CVal + GA->getOffset(); + Base = Base.getOperand(0); + Offset = CurDAG->getTargetGlobalAddress( + GA->getGlobal(), SDLoc(LoOperand), LoOperand.getValueType(), + CombinedOffset, GA->getTargetFlags()); + return true; + } + } + } + if (auto *FIN = dyn_cast(Base)) Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getXLenVT()); @@ -2213,30 +2240,6 @@ return false; 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. - const DataLayout &DL = CurDAG->getDataLayout(); - Align Alignment = GA->getGlobal()->getPointerAlignment(DL); - if (Offset2 != 0 && Alignment <= Offset2) - return false; - int64_t Offset1 = GA->getOffset(); - int64_t CombinedOffset = Offset1 + Offset2; - ImmOperand = CurDAG->getTargetGlobalAddress( - GA->getGlobal(), SDLoc(ImmOperand), ImmOperand.getValueType(), - CombinedOffset, GA->getTargetFlags()); - } else if (auto *CP = dyn_cast(ImmOperand)) { - // Ditto. - Align Alignment = CP->getAlign(); - if (Offset2 != 0 && Alignment <= Offset2) - return false; - int64_t Offset1 = CP->getOffset(); - int64_t CombinedOffset = Offset1 + Offset2; - ImmOperand = CurDAG->getTargetConstantPool( - CP->getConstVal(), ImmOperand.getValueType(), CP->getAlign(), - CombinedOffset, CP->getTargetFlags()); } else { return false; }