xref: /freebsd/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVMergeBaseOffset.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
10b57cec5SDimitry Andric //===----- RISCVMergeBaseOffset.cpp - Optimise address calculations  ------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // Merge the offset of address calculation into the offset field
100b57cec5SDimitry Andric // of instructions in a global address lowering sequence. This pass transforms:
110b57cec5SDimitry Andric //   lui  vreg1, %hi(s)
120b57cec5SDimitry Andric //   addi vreg2, vreg1, %lo(s)
130b57cec5SDimitry Andric //   addi vreg3, verg2, Offset
140b57cec5SDimitry Andric //
150b57cec5SDimitry Andric //   Into:
160b57cec5SDimitry Andric //   lui  vreg1, %hi(s+Offset)
170b57cec5SDimitry Andric //   addi vreg2, vreg1, %lo(s+Offset)
180b57cec5SDimitry Andric //
190b57cec5SDimitry Andric // The transformation is carried out under certain conditions:
200b57cec5SDimitry Andric // 1) The offset field in the base of global address lowering sequence is zero.
210b57cec5SDimitry Andric // 2) The lowered global address has only one use.
220b57cec5SDimitry Andric //
230b57cec5SDimitry Andric // The offset field can be in a different form. This pass handles all of them.
240b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric #include "RISCV.h"
270b57cec5SDimitry Andric #include "RISCVTargetMachine.h"
28*81ad6265SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
290b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h"
30349cc55cSDimitry Andric #include "llvm/MC/TargetRegistry.h"
310b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
320b57cec5SDimitry Andric #include "llvm/Target/TargetOptions.h"
330b57cec5SDimitry Andric #include <set>
340b57cec5SDimitry Andric using namespace llvm;
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric #define DEBUG_TYPE "riscv-merge-base-offset"
370b57cec5SDimitry Andric #define RISCV_MERGE_BASE_OFFSET_NAME "RISCV Merge Base Offset"
380b57cec5SDimitry Andric namespace {
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric struct RISCVMergeBaseOffsetOpt : public MachineFunctionPass {
41*81ad6265SDimitry Andric private:
42*81ad6265SDimitry Andric   const RISCVSubtarget *ST = nullptr;
43*81ad6265SDimitry Andric 
44*81ad6265SDimitry Andric public:
450b57cec5SDimitry Andric   static char ID;
460b57cec5SDimitry Andric   bool runOnMachineFunction(MachineFunction &Fn) override;
470b57cec5SDimitry Andric   bool detectLuiAddiGlobal(MachineInstr &LUI, MachineInstr *&ADDI);
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric   bool detectAndFoldOffset(MachineInstr &HiLUI, MachineInstr &LoADDI);
500b57cec5SDimitry Andric   void foldOffset(MachineInstr &HiLUI, MachineInstr &LoADDI, MachineInstr &Tail,
510b57cec5SDimitry Andric                   int64_t Offset);
528bcb0991SDimitry Andric   bool matchLargeOffset(MachineInstr &TailAdd, Register GSReg, int64_t &Offset);
53*81ad6265SDimitry Andric   bool matchShiftedOffset(MachineInstr &TailShXAdd, Register GSReg,
54*81ad6265SDimitry Andric                           int64_t &Offset);
55*81ad6265SDimitry Andric 
560b57cec5SDimitry Andric   RISCVMergeBaseOffsetOpt() : MachineFunctionPass(ID) {}
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric   MachineFunctionProperties getRequiredProperties() const override {
590b57cec5SDimitry Andric     return MachineFunctionProperties().set(
600b57cec5SDimitry Andric         MachineFunctionProperties::Property::IsSSA);
610b57cec5SDimitry Andric   }
620b57cec5SDimitry Andric 
63349cc55cSDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
64349cc55cSDimitry Andric     AU.setPreservesCFG();
65349cc55cSDimitry Andric     MachineFunctionPass::getAnalysisUsage(AU);
66349cc55cSDimitry Andric   }
67349cc55cSDimitry Andric 
680b57cec5SDimitry Andric   StringRef getPassName() const override {
690b57cec5SDimitry Andric     return RISCV_MERGE_BASE_OFFSET_NAME;
700b57cec5SDimitry Andric   }
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric private:
730b57cec5SDimitry Andric   MachineRegisterInfo *MRI;
740b57cec5SDimitry Andric   std::set<MachineInstr *> DeadInstrs;
750b57cec5SDimitry Andric };
760b57cec5SDimitry Andric } // end anonymous namespace
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric char RISCVMergeBaseOffsetOpt::ID = 0;
79e8d8bef9SDimitry Andric INITIALIZE_PASS(RISCVMergeBaseOffsetOpt, DEBUG_TYPE,
800b57cec5SDimitry Andric                 RISCV_MERGE_BASE_OFFSET_NAME, false, false)
810b57cec5SDimitry Andric 
820b57cec5SDimitry Andric // Detect the pattern:
830b57cec5SDimitry Andric //   lui   vreg1, %hi(s)
840b57cec5SDimitry Andric //   addi  vreg2, vreg1, %lo(s)
850b57cec5SDimitry Andric //
860b57cec5SDimitry Andric //   Pattern only accepted if:
870b57cec5SDimitry Andric //     1) ADDI has only one use.
880b57cec5SDimitry Andric //     2) LUI has only one use; which is the ADDI.
890b57cec5SDimitry Andric //     3) Both ADDI and LUI have GlobalAddress type which indicates that these
900b57cec5SDimitry Andric //        are generated from global address lowering.
910b57cec5SDimitry Andric //     4) Offset value in the Global Address is 0.
920b57cec5SDimitry Andric bool RISCVMergeBaseOffsetOpt::detectLuiAddiGlobal(MachineInstr &HiLUI,
930b57cec5SDimitry Andric                                                   MachineInstr *&LoADDI) {
940b57cec5SDimitry Andric   if (HiLUI.getOpcode() != RISCV::LUI ||
950b57cec5SDimitry Andric       HiLUI.getOperand(1).getTargetFlags() != RISCVII::MO_HI ||
96*81ad6265SDimitry Andric       !HiLUI.getOperand(1).isGlobal() ||
970b57cec5SDimitry Andric       HiLUI.getOperand(1).getOffset() != 0 ||
980b57cec5SDimitry Andric       !MRI->hasOneUse(HiLUI.getOperand(0).getReg()))
990b57cec5SDimitry Andric     return false;
1008bcb0991SDimitry Andric   Register HiLuiDestReg = HiLUI.getOperand(0).getReg();
101*81ad6265SDimitry Andric   LoADDI = &*MRI->use_instr_begin(HiLuiDestReg);
1020b57cec5SDimitry Andric   if (LoADDI->getOpcode() != RISCV::ADDI ||
1030b57cec5SDimitry Andric       LoADDI->getOperand(2).getTargetFlags() != RISCVII::MO_LO ||
104*81ad6265SDimitry Andric       !LoADDI->getOperand(2).isGlobal() ||
105*81ad6265SDimitry Andric       LoADDI->getOperand(2).getOffset() != 0)
1060b57cec5SDimitry Andric     return false;
1070b57cec5SDimitry Andric   return true;
1080b57cec5SDimitry Andric }
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric // Update the offset in HiLUI and LoADDI instructions.
1110b57cec5SDimitry Andric // Delete the tail instruction and update all the uses to use the
1120b57cec5SDimitry Andric // output from LoADDI.
1130b57cec5SDimitry Andric void RISCVMergeBaseOffsetOpt::foldOffset(MachineInstr &HiLUI,
1140b57cec5SDimitry Andric                                          MachineInstr &LoADDI,
1150b57cec5SDimitry Andric                                          MachineInstr &Tail, int64_t Offset) {
116*81ad6265SDimitry Andric   assert(isInt<32>(Offset) && "Unexpected offset");
1170b57cec5SDimitry Andric   // Put the offset back in HiLUI and the LoADDI
1180b57cec5SDimitry Andric   HiLUI.getOperand(1).setOffset(Offset);
1190b57cec5SDimitry Andric   LoADDI.getOperand(2).setOffset(Offset);
1200b57cec5SDimitry Andric   // Delete the tail instruction.
1210b57cec5SDimitry Andric   DeadInstrs.insert(&Tail);
1220b57cec5SDimitry Andric   MRI->replaceRegWith(Tail.getOperand(0).getReg(),
1230b57cec5SDimitry Andric                       LoADDI.getOperand(0).getReg());
1240b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "  Merged offset " << Offset << " into base.\n"
1250b57cec5SDimitry Andric                     << "     " << HiLUI << "     " << LoADDI;);
1260b57cec5SDimitry Andric }
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric // Detect patterns for large offsets that are passed into an ADD instruction.
1290b57cec5SDimitry Andric //
1300b57cec5SDimitry Andric //                     Base address lowering is of the form:
1310b57cec5SDimitry Andric //                        HiLUI:  lui   vreg1, %hi(s)
1320b57cec5SDimitry Andric //                       LoADDI:  addi  vreg2, vreg1, %lo(s)
1330b57cec5SDimitry Andric //                       /                                  \
1340b57cec5SDimitry Andric //                      /                                    \
1350b57cec5SDimitry Andric //                     /                                      \
1360b57cec5SDimitry Andric //                    /  The large offset can be of two forms: \
1370b57cec5SDimitry Andric //  1) Offset that has non zero bits in lower      2) Offset that has non zero
1380b57cec5SDimitry Andric //     12 bits and upper 20 bits                      bits in upper 20 bits only
1390b57cec5SDimitry Andric //   OffseLUI: lui   vreg3, 4
1400b57cec5SDimitry Andric // OffsetTail: addi  voff, vreg3, 188                OffsetTail: lui  voff, 128
1410b57cec5SDimitry Andric //                    \                                        /
1420b57cec5SDimitry Andric //                     \                                      /
1430b57cec5SDimitry Andric //                      \                                    /
1440b57cec5SDimitry Andric //                       \                                  /
1450b57cec5SDimitry Andric //                         TailAdd: add  vreg4, vreg2, voff
1460b57cec5SDimitry Andric bool RISCVMergeBaseOffsetOpt::matchLargeOffset(MachineInstr &TailAdd,
1478bcb0991SDimitry Andric                                                Register GAReg,
1480b57cec5SDimitry Andric                                                int64_t &Offset) {
1490b57cec5SDimitry Andric   assert((TailAdd.getOpcode() == RISCV::ADD) && "Expected ADD instruction!");
1508bcb0991SDimitry Andric   Register Rs = TailAdd.getOperand(1).getReg();
1518bcb0991SDimitry Andric   Register Rt = TailAdd.getOperand(2).getReg();
1528bcb0991SDimitry Andric   Register Reg = Rs == GAReg ? Rt : Rs;
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric   // Can't fold if the register has more than one use.
1550b57cec5SDimitry Andric   if (!MRI->hasOneUse(Reg))
1560b57cec5SDimitry Andric     return false;
1570b57cec5SDimitry Andric   // This can point to an ADDI or a LUI:
1580b57cec5SDimitry Andric   MachineInstr &OffsetTail = *MRI->getVRegDef(Reg);
159*81ad6265SDimitry Andric   if (OffsetTail.getOpcode() == RISCV::ADDI ||
160*81ad6265SDimitry Andric       OffsetTail.getOpcode() == RISCV::ADDIW) {
1610b57cec5SDimitry Andric     // The offset value has non zero bits in both %hi and %lo parts.
1620b57cec5SDimitry Andric     // Detect an ADDI that feeds from a LUI instruction.
1630b57cec5SDimitry Andric     MachineOperand &AddiImmOp = OffsetTail.getOperand(2);
1640b57cec5SDimitry Andric     if (AddiImmOp.getTargetFlags() != RISCVII::MO_None)
1650b57cec5SDimitry Andric       return false;
1660b57cec5SDimitry Andric     int64_t OffLo = AddiImmOp.getImm();
1670b57cec5SDimitry Andric     MachineInstr &OffsetLui =
1680b57cec5SDimitry Andric         *MRI->getVRegDef(OffsetTail.getOperand(1).getReg());
1690b57cec5SDimitry Andric     MachineOperand &LuiImmOp = OffsetLui.getOperand(1);
1700b57cec5SDimitry Andric     if (OffsetLui.getOpcode() != RISCV::LUI ||
1710b57cec5SDimitry Andric         LuiImmOp.getTargetFlags() != RISCVII::MO_None ||
1720b57cec5SDimitry Andric         !MRI->hasOneUse(OffsetLui.getOperand(0).getReg()))
1730b57cec5SDimitry Andric       return false;
174*81ad6265SDimitry Andric     Offset = SignExtend64<32>(LuiImmOp.getImm() << 12);
175*81ad6265SDimitry Andric     Offset += OffLo;
176*81ad6265SDimitry Andric     // RV32 ignores the upper 32 bits. ADDIW sign extends the result.
177*81ad6265SDimitry Andric     if (!ST->is64Bit() || OffsetTail.getOpcode() == RISCV::ADDIW)
178*81ad6265SDimitry Andric        Offset = SignExtend64<32>(Offset);
179*81ad6265SDimitry Andric     // We can only fold simm32 offsets.
180*81ad6265SDimitry Andric     if (!isInt<32>(Offset))
181*81ad6265SDimitry Andric       return false;
1820b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "  Offset Instrs: " << OffsetTail
1830b57cec5SDimitry Andric                       << "                 " << OffsetLui);
1840b57cec5SDimitry Andric     DeadInstrs.insert(&OffsetTail);
1850b57cec5SDimitry Andric     DeadInstrs.insert(&OffsetLui);
1860b57cec5SDimitry Andric     return true;
1870b57cec5SDimitry Andric   } else if (OffsetTail.getOpcode() == RISCV::LUI) {
1880b57cec5SDimitry Andric     // The offset value has all zero bits in the lower 12 bits. Only LUI
1890b57cec5SDimitry Andric     // exists.
1900b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "  Offset Instr: " << OffsetTail);
191*81ad6265SDimitry Andric     Offset = SignExtend64<32>(OffsetTail.getOperand(1).getImm() << 12);
1920b57cec5SDimitry Andric     DeadInstrs.insert(&OffsetTail);
1930b57cec5SDimitry Andric     return true;
1940b57cec5SDimitry Andric   }
1950b57cec5SDimitry Andric   return false;
1960b57cec5SDimitry Andric }
1970b57cec5SDimitry Andric 
198*81ad6265SDimitry Andric // Detect patterns for offsets that are passed into a SHXADD instruction.
199*81ad6265SDimitry Andric // The offset has 1,2, or 3 trailing zeros and fits in simm13, simm14, simm15.
200*81ad6265SDimitry Andric // The constant is created with addi    voff, x0, C, and shXadd is used to
201*81ad6265SDimitry Andric // fill insert the trailing zeros and do the addition.
202*81ad6265SDimitry Andric //
203*81ad6265SDimitry Andric // HiLUI:      lui     vreg1, %hi(s)
204*81ad6265SDimitry Andric // LoADDI:     addi    vreg2, vreg1, %lo(s)
205*81ad6265SDimitry Andric // OffsetTail: addi    voff, x0, C
206*81ad6265SDimitry Andric // TailAdd:    shXadd  vreg4, voff, vreg2
207*81ad6265SDimitry Andric bool RISCVMergeBaseOffsetOpt::matchShiftedOffset(MachineInstr &TailShXAdd,
208*81ad6265SDimitry Andric                                                  Register GAReg,
209*81ad6265SDimitry Andric                                                  int64_t &Offset) {
210*81ad6265SDimitry Andric   assert((TailShXAdd.getOpcode() == RISCV::SH1ADD ||
211*81ad6265SDimitry Andric           TailShXAdd.getOpcode() == RISCV::SH2ADD ||
212*81ad6265SDimitry Andric           TailShXAdd.getOpcode() == RISCV::SH3ADD) &&
213*81ad6265SDimitry Andric          "Expected SHXADD instruction!");
214*81ad6265SDimitry Andric 
215*81ad6265SDimitry Andric   // The first source is the shifted operand.
216*81ad6265SDimitry Andric   Register Rs1 = TailShXAdd.getOperand(1).getReg();
217*81ad6265SDimitry Andric 
218*81ad6265SDimitry Andric   if (GAReg != TailShXAdd.getOperand(2).getReg())
219*81ad6265SDimitry Andric     return false;
220*81ad6265SDimitry Andric 
221*81ad6265SDimitry Andric   // Can't fold if the register has more than one use.
222*81ad6265SDimitry Andric   if (!MRI->hasOneUse(Rs1))
223*81ad6265SDimitry Andric     return false;
224*81ad6265SDimitry Andric   // This can point to an ADDI X0, C.
225*81ad6265SDimitry Andric   MachineInstr &OffsetTail = *MRI->getVRegDef(Rs1);
226*81ad6265SDimitry Andric   if (OffsetTail.getOpcode() != RISCV::ADDI)
227*81ad6265SDimitry Andric     return false;
228*81ad6265SDimitry Andric   if (!OffsetTail.getOperand(1).isReg() ||
229*81ad6265SDimitry Andric       OffsetTail.getOperand(1).getReg() != RISCV::X0 ||
230*81ad6265SDimitry Andric       !OffsetTail.getOperand(2).isImm())
231*81ad6265SDimitry Andric     return false;
232*81ad6265SDimitry Andric 
233*81ad6265SDimitry Andric   Offset = OffsetTail.getOperand(2).getImm();
234*81ad6265SDimitry Andric   assert(isInt<12>(Offset) && "Unexpected offset");
235*81ad6265SDimitry Andric 
236*81ad6265SDimitry Andric   unsigned ShAmt;
237*81ad6265SDimitry Andric   switch (TailShXAdd.getOpcode()) {
238*81ad6265SDimitry Andric   default: llvm_unreachable("Unexpected opcode");
239*81ad6265SDimitry Andric   case RISCV::SH1ADD: ShAmt = 1; break;
240*81ad6265SDimitry Andric   case RISCV::SH2ADD: ShAmt = 2; break;
241*81ad6265SDimitry Andric   case RISCV::SH3ADD: ShAmt = 3; break;
242*81ad6265SDimitry Andric   }
243*81ad6265SDimitry Andric 
244*81ad6265SDimitry Andric   Offset = (uint64_t)Offset << ShAmt;
245*81ad6265SDimitry Andric 
246*81ad6265SDimitry Andric   LLVM_DEBUG(dbgs() << "  Offset Instr: " << OffsetTail);
247*81ad6265SDimitry Andric   DeadInstrs.insert(&OffsetTail);
248*81ad6265SDimitry Andric   return true;
249*81ad6265SDimitry Andric }
250*81ad6265SDimitry Andric 
2510b57cec5SDimitry Andric bool RISCVMergeBaseOffsetOpt::detectAndFoldOffset(MachineInstr &HiLUI,
2520b57cec5SDimitry Andric                                                   MachineInstr &LoADDI) {
2538bcb0991SDimitry Andric   Register DestReg = LoADDI.getOperand(0).getReg();
254*81ad6265SDimitry Andric 
255*81ad6265SDimitry Andric   // First, look for arithmetic instructions we can get an offset from.
256*81ad6265SDimitry Andric   // We might be able to remove the arithmetic instructions by folding the
257*81ad6265SDimitry Andric   // offset into the LUI+ADDI.
258*81ad6265SDimitry Andric   if (MRI->hasOneUse(DestReg)) {
2590b57cec5SDimitry Andric     // LoADDI has only one use.
260*81ad6265SDimitry Andric     MachineInstr &Tail = *MRI->use_instr_begin(DestReg);
2610b57cec5SDimitry Andric     switch (Tail.getOpcode()) {
2620b57cec5SDimitry Andric     default:
2630b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "Don't know how to get offset from this instr:"
2640b57cec5SDimitry Andric                         << Tail);
265*81ad6265SDimitry Andric       break;
2660b57cec5SDimitry Andric     case RISCV::ADDI: {
2670b57cec5SDimitry Andric       // Offset is simply an immediate operand.
2680b57cec5SDimitry Andric       int64_t Offset = Tail.getOperand(2).getImm();
269*81ad6265SDimitry Andric 
270*81ad6265SDimitry Andric       // We might have two ADDIs in a row.
271*81ad6265SDimitry Andric       Register TailDestReg = Tail.getOperand(0).getReg();
272*81ad6265SDimitry Andric       if (MRI->hasOneUse(TailDestReg)) {
273*81ad6265SDimitry Andric         MachineInstr &TailTail = *MRI->use_instr_begin(TailDestReg);
274*81ad6265SDimitry Andric         if (TailTail.getOpcode() == RISCV::ADDI) {
275*81ad6265SDimitry Andric           Offset += TailTail.getOperand(2).getImm();
276*81ad6265SDimitry Andric           LLVM_DEBUG(dbgs() << "  Offset Instrs: " << Tail << TailTail);
277*81ad6265SDimitry Andric           DeadInstrs.insert(&Tail);
278*81ad6265SDimitry Andric           foldOffset(HiLUI, LoADDI, TailTail, Offset);
279*81ad6265SDimitry Andric           return true;
280*81ad6265SDimitry Andric         }
281*81ad6265SDimitry Andric       }
282*81ad6265SDimitry Andric 
2830b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "  Offset Instr: " << Tail);
2840b57cec5SDimitry Andric       foldOffset(HiLUI, LoADDI, Tail, Offset);
2850b57cec5SDimitry Andric       return true;
286349cc55cSDimitry Andric     }
2870b57cec5SDimitry Andric     case RISCV::ADD: {
2880b57cec5SDimitry Andric       // The offset is too large to fit in the immediate field of ADDI.
2890b57cec5SDimitry Andric       // This can be in two forms:
2900b57cec5SDimitry Andric       // 1) LUI hi_Offset followed by:
2910b57cec5SDimitry Andric       //    ADDI lo_offset
2920b57cec5SDimitry Andric       //    This happens in case the offset has non zero bits in
2930b57cec5SDimitry Andric       //    both hi 20 and lo 12 bits.
2940b57cec5SDimitry Andric       // 2) LUI (offset20)
2950b57cec5SDimitry Andric       //    This happens in case the lower 12 bits of the offset are zeros.
2960b57cec5SDimitry Andric       int64_t Offset;
2970b57cec5SDimitry Andric       if (!matchLargeOffset(Tail, DestReg, Offset))
2980b57cec5SDimitry Andric         return false;
2990b57cec5SDimitry Andric       foldOffset(HiLUI, LoADDI, Tail, Offset);
3000b57cec5SDimitry Andric       return true;
301349cc55cSDimitry Andric     }
302*81ad6265SDimitry Andric     case RISCV::SH1ADD:
303*81ad6265SDimitry Andric     case RISCV::SH2ADD:
304*81ad6265SDimitry Andric     case RISCV::SH3ADD: {
305*81ad6265SDimitry Andric       // The offset is too large to fit in the immediate field of ADDI.
306*81ad6265SDimitry Andric       // It may be encoded as (SH2ADD (ADDI X0, C), DestReg) or
307*81ad6265SDimitry Andric       // (SH3ADD (ADDI X0, C), DestReg).
308*81ad6265SDimitry Andric       int64_t Offset;
309*81ad6265SDimitry Andric       if (!matchShiftedOffset(Tail, DestReg, Offset))
310*81ad6265SDimitry Andric         return false;
311*81ad6265SDimitry Andric       foldOffset(HiLUI, LoADDI, Tail, Offset);
312*81ad6265SDimitry Andric       return true;
313*81ad6265SDimitry Andric     }
314*81ad6265SDimitry Andric     }
315*81ad6265SDimitry Andric   }
316*81ad6265SDimitry Andric 
317*81ad6265SDimitry Andric   // We didn't find an arithmetic instruction. If all the uses are memory ops
318*81ad6265SDimitry Andric   // with the same offset, we can transform
319*81ad6265SDimitry Andric   // HiLUI:  lui vreg1, %hi(foo)          --->  lui vreg1, %hi(foo+8)
320*81ad6265SDimitry Andric   // LoADDI: addi vreg2, vreg1, %lo(foo)  --->  lw vreg3, lo(foo+8)(vreg1)
321*81ad6265SDimitry Andric   // Tail:   lw vreg3, 8(vreg2)
322*81ad6265SDimitry Andric 
323*81ad6265SDimitry Andric   Optional<int64_t> CommonOffset;
324*81ad6265SDimitry Andric   for (const MachineInstr &UseMI : MRI->use_instructions(DestReg)) {
325*81ad6265SDimitry Andric     switch (UseMI.getOpcode()) {
326*81ad6265SDimitry Andric     default:
327*81ad6265SDimitry Andric       LLVM_DEBUG(dbgs() << "Not a load or store instruction: " << UseMI);
328*81ad6265SDimitry Andric       return false;
3290b57cec5SDimitry Andric     case RISCV::LB:
3300b57cec5SDimitry Andric     case RISCV::LH:
3310b57cec5SDimitry Andric     case RISCV::LW:
3320b57cec5SDimitry Andric     case RISCV::LBU:
3330b57cec5SDimitry Andric     case RISCV::LHU:
3340b57cec5SDimitry Andric     case RISCV::LWU:
3350b57cec5SDimitry Andric     case RISCV::LD:
336e8d8bef9SDimitry Andric     case RISCV::FLH:
3370b57cec5SDimitry Andric     case RISCV::FLW:
3380b57cec5SDimitry Andric     case RISCV::FLD:
3390b57cec5SDimitry Andric     case RISCV::SB:
3400b57cec5SDimitry Andric     case RISCV::SH:
3410b57cec5SDimitry Andric     case RISCV::SW:
3420b57cec5SDimitry Andric     case RISCV::SD:
343e8d8bef9SDimitry Andric     case RISCV::FSH:
3440b57cec5SDimitry Andric     case RISCV::FSW:
3450b57cec5SDimitry Andric     case RISCV::FSD: {
346*81ad6265SDimitry Andric       if (UseMI.getOperand(1).isFI())
3470b57cec5SDimitry Andric         return false;
348*81ad6265SDimitry Andric       // Register defined by LoADDI should not be the value register.
349*81ad6265SDimitry Andric       if (DestReg == UseMI.getOperand(0).getReg())
3500b57cec5SDimitry Andric         return false;
351*81ad6265SDimitry Andric       assert(DestReg == UseMI.getOperand(1).getReg() &&
352*81ad6265SDimitry Andric              "Expected base address use");
353*81ad6265SDimitry Andric       // All load/store instructions must use the same offset.
354*81ad6265SDimitry Andric       int64_t Offset = UseMI.getOperand(2).getImm();
355*81ad6265SDimitry Andric       if (CommonOffset && Offset != CommonOffset)
356*81ad6265SDimitry Andric         return false;
357*81ad6265SDimitry Andric       CommonOffset = Offset;
358*81ad6265SDimitry Andric     }
359*81ad6265SDimitry Andric     }
360*81ad6265SDimitry Andric   }
361*81ad6265SDimitry Andric 
362*81ad6265SDimitry Andric   // We found a common offset.
3630b57cec5SDimitry Andric   // Update the offsets in global address lowering.
364*81ad6265SDimitry Andric   HiLUI.getOperand(1).setOffset(*CommonOffset);
3650b57cec5SDimitry Andric   MachineOperand &ImmOp = LoADDI.getOperand(2);
366*81ad6265SDimitry Andric   ImmOp.setOffset(*CommonOffset);
367*81ad6265SDimitry Andric 
368*81ad6265SDimitry Andric   // Update the immediate in the load/store instructions to add the offset.
369*81ad6265SDimitry Andric   for (MachineInstr &UseMI :
370*81ad6265SDimitry Andric        llvm::make_early_inc_range(MRI->use_instructions(DestReg))) {
371*81ad6265SDimitry Andric     UseMI.removeOperand(2);
372*81ad6265SDimitry Andric     UseMI.addOperand(ImmOp);
3730b57cec5SDimitry Andric     // Update the base reg in the Tail instruction to feed from LUI.
3740b57cec5SDimitry Andric     // Output of HiLUI is only used in LoADDI, no need to use
3750b57cec5SDimitry Andric     // MRI->replaceRegWith().
376*81ad6265SDimitry Andric     UseMI.getOperand(1).setReg(HiLUI.getOperand(0).getReg());
377*81ad6265SDimitry Andric   }
378*81ad6265SDimitry Andric 
3790b57cec5SDimitry Andric   DeadInstrs.insert(&LoADDI);
3800b57cec5SDimitry Andric   return true;
381349cc55cSDimitry Andric }
3820b57cec5SDimitry Andric 
3830b57cec5SDimitry Andric bool RISCVMergeBaseOffsetOpt::runOnMachineFunction(MachineFunction &Fn) {
3840b57cec5SDimitry Andric   if (skipFunction(Fn.getFunction()))
3850b57cec5SDimitry Andric     return false;
3860b57cec5SDimitry Andric 
387*81ad6265SDimitry Andric   ST = &Fn.getSubtarget<RISCVSubtarget>();
388*81ad6265SDimitry Andric 
389349cc55cSDimitry Andric   bool MadeChange = false;
3900b57cec5SDimitry Andric   DeadInstrs.clear();
3910b57cec5SDimitry Andric   MRI = &Fn.getRegInfo();
3920b57cec5SDimitry Andric   for (MachineBasicBlock &MBB : Fn) {
3930b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "MBB: " << MBB.getName() << "\n");
3940b57cec5SDimitry Andric     for (MachineInstr &HiLUI : MBB) {
3950b57cec5SDimitry Andric       MachineInstr *LoADDI = nullptr;
3960b57cec5SDimitry Andric       if (!detectLuiAddiGlobal(HiLUI, LoADDI))
3970b57cec5SDimitry Andric         continue;
398*81ad6265SDimitry Andric       LLVM_DEBUG(dbgs() << "  Found lowered global address: "
3990b57cec5SDimitry Andric                         << *LoADDI->getOperand(2).getGlobal() << "\n");
400349cc55cSDimitry Andric       MadeChange |= detectAndFoldOffset(HiLUI, *LoADDI);
4010b57cec5SDimitry Andric     }
4020b57cec5SDimitry Andric   }
4030b57cec5SDimitry Andric   // Delete dead instructions.
4040b57cec5SDimitry Andric   for (auto *MI : DeadInstrs)
4050b57cec5SDimitry Andric     MI->eraseFromParent();
406349cc55cSDimitry Andric   return MadeChange;
4070b57cec5SDimitry Andric }
4080b57cec5SDimitry Andric 
4090b57cec5SDimitry Andric /// Returns an instance of the Merge Base Offset Optimization pass.
4100b57cec5SDimitry Andric FunctionPass *llvm::createRISCVMergeBaseOffsetOptPass() {
4110b57cec5SDimitry Andric   return new RISCVMergeBaseOffsetOpt();
4120b57cec5SDimitry Andric }
413