• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===----- RISCVMergeBaseOffset.cpp - Optimise address calculations  ------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // Merge the offset of address calculation into the offset field
11 // of instructions in a global address lowering sequence. This pass transforms:
12 //   lui  vreg1, %hi(s)
13 //   addi vreg2, vreg1, %lo(s)
14 //   addi vreg3, verg2, Offset
15 //
16 //   Into:
17 //   lui  vreg1, %hi(s+Offset)
18 //   addi vreg2, vreg1, %lo(s+Offset)
19 //
20 // The transformation is carried out under certain conditions:
21 // 1) The offset field in the base of global address lowering sequence is zero.
22 // 2) The lowered global address has only one use.
23 //
24 // The offset field can be in a different form. This pass handles all of them.
25 //===----------------------------------------------------------------------===//
26 
27 #include "RISCV.h"
28 #include "RISCVTargetMachine.h"
29 #include "llvm/CodeGen/Passes.h"
30 #include "llvm/Support/Debug.h"
31 #include "llvm/Support/TargetRegistry.h"
32 #include "llvm/Target/TargetOptions.h"
33 #include <set>
34 using namespace llvm;
35 
36 #define DEBUG_TYPE "riscv-merge-base-offset"
37 #define RISCV_MERGE_BASE_OFFSET_NAME "RISCV Merge Base Offset"
38 namespace {
39 
40 struct RISCVMergeBaseOffsetOpt : public MachineFunctionPass {
41   static char ID;
42   const MachineFunction *MF;
43   bool runOnMachineFunction(MachineFunction &Fn) override;
44   bool detectLuiAddiGlobal(MachineInstr &LUI, MachineInstr *&ADDI);
45 
46   bool detectAndFoldOffset(MachineInstr &HiLUI, MachineInstr &LoADDI);
47   void foldOffset(MachineInstr &HiLUI, MachineInstr &LoADDI, MachineInstr &Tail,
48                   int64_t Offset);
49   bool matchLargeOffset(MachineInstr &TailAdd, unsigned GSReg, int64_t &Offset);
RISCVMergeBaseOffsetOpt__anona59fcc780111::RISCVMergeBaseOffsetOpt50   RISCVMergeBaseOffsetOpt() : MachineFunctionPass(ID) {}
51 
getRequiredProperties__anona59fcc780111::RISCVMergeBaseOffsetOpt52   MachineFunctionProperties getRequiredProperties() const override {
53     return MachineFunctionProperties().set(
54         MachineFunctionProperties::Property::IsSSA);
55   }
56 
getPassName__anona59fcc780111::RISCVMergeBaseOffsetOpt57   StringRef getPassName() const override {
58     return RISCV_MERGE_BASE_OFFSET_NAME;
59   }
60 
61 private:
62   MachineRegisterInfo *MRI;
63   std::set<MachineInstr *> DeadInstrs;
64 };
65 }; // end anonymous namespace
66 
67 char RISCVMergeBaseOffsetOpt::ID = 0;
68 INITIALIZE_PASS(RISCVMergeBaseOffsetOpt, "riscv-merge-base-offset",
69                 RISCV_MERGE_BASE_OFFSET_NAME, false, false)
70 
71 // Detect the pattern:
72 //   lui   vreg1, %hi(s)
73 //   addi  vreg2, vreg1, %lo(s)
74 //
75 //   Pattern only accepted if:
76 //     1) ADDI has only one use.
77 //     2) LUI has only one use; which is the ADDI.
78 //     3) Both ADDI and LUI have GlobalAddress type which indicates that these
79 //        are generated from global address lowering.
80 //     4) Offset value in the Global Address is 0.
detectLuiAddiGlobal(MachineInstr & HiLUI,MachineInstr * & LoADDI)81 bool RISCVMergeBaseOffsetOpt::detectLuiAddiGlobal(MachineInstr &HiLUI,
82                                                   MachineInstr *&LoADDI) {
83   if (HiLUI.getOpcode() != RISCV::LUI ||
84       HiLUI.getOperand(1).getTargetFlags() != RISCVII::MO_HI ||
85       HiLUI.getOperand(1).getType() != MachineOperand::MO_GlobalAddress ||
86       HiLUI.getOperand(1).getOffset() != 0 ||
87       !MRI->hasOneUse(HiLUI.getOperand(0).getReg()))
88     return false;
89   unsigned HiLuiDestReg = HiLUI.getOperand(0).getReg();
90   LoADDI = MRI->use_begin(HiLuiDestReg)->getParent();
91   if (LoADDI->getOpcode() != RISCV::ADDI ||
92       LoADDI->getOperand(2).getTargetFlags() != RISCVII::MO_LO ||
93       LoADDI->getOperand(2).getType() != MachineOperand::MO_GlobalAddress ||
94       LoADDI->getOperand(2).getOffset() != 0 ||
95       !MRI->hasOneUse(LoADDI->getOperand(0).getReg()))
96     return false;
97   return true;
98 }
99 
100 // Update the offset in HiLUI and LoADDI instructions.
101 // Delete the tail instruction and update all the uses to use the
102 // output from LoADDI.
foldOffset(MachineInstr & HiLUI,MachineInstr & LoADDI,MachineInstr & Tail,int64_t Offset)103 void RISCVMergeBaseOffsetOpt::foldOffset(MachineInstr &HiLUI,
104                                          MachineInstr &LoADDI,
105                                          MachineInstr &Tail, int64_t Offset) {
106   // Put the offset back in HiLUI and the LoADDI
107   HiLUI.getOperand(1).setOffset(Offset);
108   LoADDI.getOperand(2).setOffset(Offset);
109   // Delete the tail instruction.
110   DeadInstrs.insert(&Tail);
111   MRI->replaceRegWith(Tail.getOperand(0).getReg(),
112                       LoADDI.getOperand(0).getReg());
113   LLVM_DEBUG(dbgs() << "  Merged offset " << Offset << " into base.\n"
114                     << "     " << HiLUI << "     " << LoADDI;);
115 }
116 
117 // Detect patterns for large offsets that are passed into an ADD instruction.
118 //
119 //                     Base address lowering is of the form:
120 //                        HiLUI:  lui   vreg1, %hi(s)
121 //                       LoADDI:  addi  vreg2, vreg1, %lo(s)
122 //                       /                                  \
123 //                      /                                    \
124 //                     /                                      \
125 //                    /  The large offset can be of two forms: \
126 //  1) Offset that has non zero bits in lower      2) Offset that has non zero
127 //     12 bits and upper 20 bits                      bits in upper 20 bits only
128 //   OffseLUI: lui   vreg3, 4
129 // OffsetTail: addi  voff, vreg3, 188                OffsetTail: lui  voff, 128
130 //                    \                                        /
131 //                     \                                      /
132 //                      \                                    /
133 //                       \                                  /
134 //                         TailAdd: add  vreg4, vreg2, voff
matchLargeOffset(MachineInstr & TailAdd,unsigned GAReg,int64_t & Offset)135 bool RISCVMergeBaseOffsetOpt::matchLargeOffset(MachineInstr &TailAdd,
136                                                unsigned GAReg,
137                                                int64_t &Offset) {
138   assert((TailAdd.getOpcode() == RISCV::ADD) && "Expected ADD instruction!");
139   unsigned Rs = TailAdd.getOperand(1).getReg();
140   unsigned Rt = TailAdd.getOperand(2).getReg();
141   unsigned Reg = Rs == GAReg ? Rt : Rs;
142 
143   // Can't fold if the register has more than one use.
144   if (!MRI->hasOneUse(Reg))
145     return false;
146   // This can point to an ADDI or a LUI:
147   MachineInstr &OffsetTail = *MRI->getVRegDef(Reg);
148   if (OffsetTail.getOpcode() == RISCV::ADDI) {
149     // The offset value has non zero bits in both %hi and %lo parts.
150     // Detect an ADDI that feeds from a LUI instruction.
151     MachineOperand &AddiImmOp = OffsetTail.getOperand(2);
152     if (AddiImmOp.getTargetFlags() != RISCVII::MO_None)
153       return false;
154     int64_t OffLo = AddiImmOp.getImm();
155     MachineInstr &OffsetLui =
156         *MRI->getVRegDef(OffsetTail.getOperand(1).getReg());
157     MachineOperand &LuiImmOp = OffsetLui.getOperand(1);
158     if (OffsetLui.getOpcode() != RISCV::LUI ||
159         LuiImmOp.getTargetFlags() != RISCVII::MO_None ||
160         !MRI->hasOneUse(OffsetLui.getOperand(0).getReg()))
161       return false;
162     int64_t OffHi = OffsetLui.getOperand(1).getImm();
163     Offset = (OffHi << 12) + OffLo;
164     LLVM_DEBUG(dbgs() << "  Offset Instrs: " << OffsetTail
165                       << "                 " << OffsetLui);
166     DeadInstrs.insert(&OffsetTail);
167     DeadInstrs.insert(&OffsetLui);
168     return true;
169   } else if (OffsetTail.getOpcode() == RISCV::LUI) {
170     // The offset value has all zero bits in the lower 12 bits. Only LUI
171     // exists.
172     LLVM_DEBUG(dbgs() << "  Offset Instr: " << OffsetTail);
173     Offset = OffsetTail.getOperand(1).getImm() << 12;
174     DeadInstrs.insert(&OffsetTail);
175     return true;
176   }
177   return false;
178 }
179 
detectAndFoldOffset(MachineInstr & HiLUI,MachineInstr & LoADDI)180 bool RISCVMergeBaseOffsetOpt::detectAndFoldOffset(MachineInstr &HiLUI,
181                                                   MachineInstr &LoADDI) {
182   unsigned DestReg = LoADDI.getOperand(0).getReg();
183   assert(MRI->hasOneUse(DestReg) && "expected one use for LoADDI");
184   // LoADDI has only one use.
185   MachineInstr &Tail = *MRI->use_begin(DestReg)->getParent();
186   switch (Tail.getOpcode()) {
187   default:
188     LLVM_DEBUG(dbgs() << "Don't know how to get offset from this instr:"
189                       << Tail);
190     return false;
191   case RISCV::ADDI: {
192     // Offset is simply an immediate operand.
193     int64_t Offset = Tail.getOperand(2).getImm();
194     LLVM_DEBUG(dbgs() << "  Offset Instr: " << Tail);
195     foldOffset(HiLUI, LoADDI, Tail, Offset);
196     return true;
197   } break;
198   case RISCV::ADD: {
199     // The offset is too large to fit in the immediate field of ADDI.
200     // This can be in two forms:
201     // 1) LUI hi_Offset followed by:
202     //    ADDI lo_offset
203     //    This happens in case the offset has non zero bits in
204     //    both hi 20 and lo 12 bits.
205     // 2) LUI (offset20)
206     //    This happens in case the lower 12 bits of the offset are zeros.
207     int64_t Offset;
208     if (!matchLargeOffset(Tail, DestReg, Offset))
209       return false;
210     foldOffset(HiLUI, LoADDI, Tail, Offset);
211     return true;
212   } break;
213   case RISCV::LB:
214   case RISCV::LH:
215   case RISCV::LW:
216   case RISCV::LBU:
217   case RISCV::LHU:
218   case RISCV::LWU:
219   case RISCV::LD:
220   case RISCV::FLW:
221   case RISCV::FLD:
222   case RISCV::SB:
223   case RISCV::SH:
224   case RISCV::SW:
225   case RISCV::SD:
226   case RISCV::FSW:
227   case RISCV::FSD: {
228     // Transforms the sequence:            Into:
229     // HiLUI:  lui vreg1, %hi(foo)          --->  lui vreg1, %hi(foo+8)
230     // LoADDI: addi vreg2, vreg1, %lo(foo)  --->  lw vreg3, lo(foo+8)(vreg1)
231     // Tail:   lw vreg3, 8(vreg2)
232     if (Tail.getOperand(1).isFI())
233       return false;
234     // Register defined by LoADDI should be used in the base part of the
235     // load\store instruction. Otherwise, no folding possible.
236     unsigned BaseAddrReg = Tail.getOperand(1).getReg();
237     if (DestReg != BaseAddrReg)
238       return false;
239     MachineOperand &TailImmOp = Tail.getOperand(2);
240     int64_t Offset = TailImmOp.getImm();
241     // Update the offsets in global address lowering.
242     HiLUI.getOperand(1).setOffset(Offset);
243     // Update the immediate in the Tail instruction to add the offset.
244     Tail.RemoveOperand(2);
245     MachineOperand &ImmOp = LoADDI.getOperand(2);
246     ImmOp.setOffset(Offset);
247     Tail.addOperand(ImmOp);
248     // Update the base reg in the Tail instruction to feed from LUI.
249     // Output of HiLUI is only used in LoADDI, no need to use
250     // MRI->replaceRegWith().
251     Tail.getOperand(1).setReg(HiLUI.getOperand(0).getReg());
252     DeadInstrs.insert(&LoADDI);
253     return true;
254   } break;
255   }
256   return false;
257 }
258 
runOnMachineFunction(MachineFunction & Fn)259 bool RISCVMergeBaseOffsetOpt::runOnMachineFunction(MachineFunction &Fn) {
260   if (skipFunction(Fn.getFunction()))
261     return false;
262 
263   DeadInstrs.clear();
264   MRI = &Fn.getRegInfo();
265   for (MachineBasicBlock &MBB : Fn) {
266     LLVM_DEBUG(dbgs() << "MBB: " << MBB.getName() << "\n");
267     for (MachineInstr &HiLUI : MBB) {
268       MachineInstr *LoADDI = nullptr;
269       if (!detectLuiAddiGlobal(HiLUI, LoADDI))
270         continue;
271       LLVM_DEBUG(dbgs() << "  Found lowered global address with one use: "
272                         << *LoADDI->getOperand(2).getGlobal() << "\n");
273       // If the use count is only one, merge the offset
274       detectAndFoldOffset(HiLUI, *LoADDI);
275     }
276   }
277   // Delete dead instructions.
278   for (auto *MI : DeadInstrs)
279     MI->eraseFromParent();
280   return true;
281 }
282 
283 /// Returns an instance of the Merge Base Offset Optimization pass.
createRISCVMergeBaseOffsetOptPass()284 FunctionPass *llvm::createRISCVMergeBaseOffsetOptPass() {
285   return new RISCVMergeBaseOffsetOpt();
286 }
287