/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/lib/Target/Hexagon/HexagonOptAddrMode.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- HexagonOptAddrMode.cpp ---------------------------------------------===// |
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 | | // This implements a Hexagon-specific pass to optimize addressing mode for |
10 | | // load/store instructions. |
11 | | //===----------------------------------------------------------------------===// |
12 | | |
13 | | #include "HexagonInstrInfo.h" |
14 | | #include "HexagonSubtarget.h" |
15 | | #include "MCTargetDesc/HexagonBaseInfo.h" |
16 | | #include "RDFGraph.h" |
17 | | #include "RDFLiveness.h" |
18 | | #include "RDFRegisters.h" |
19 | | #include "llvm/ADT/DenseMap.h" |
20 | | #include "llvm/ADT/DenseSet.h" |
21 | | #include "llvm/ADT/StringRef.h" |
22 | | #include "llvm/CodeGen/MachineBasicBlock.h" |
23 | | #include "llvm/CodeGen/MachineDominanceFrontier.h" |
24 | | #include "llvm/CodeGen/MachineDominators.h" |
25 | | #include "llvm/CodeGen/MachineFunction.h" |
26 | | #include "llvm/CodeGen/MachineFunctionPass.h" |
27 | | #include "llvm/CodeGen/MachineInstr.h" |
28 | | #include "llvm/CodeGen/MachineInstrBuilder.h" |
29 | | #include "llvm/CodeGen/MachineOperand.h" |
30 | | #include "llvm/MC/MCInstrDesc.h" |
31 | | #include "llvm/Pass.h" |
32 | | #include "llvm/Support/CommandLine.h" |
33 | | #include "llvm/Support/Debug.h" |
34 | | #include "llvm/Support/ErrorHandling.h" |
35 | | #include "llvm/Support/raw_ostream.h" |
36 | | #include "llvm/Target/TargetSubtargetInfo.h" |
37 | | #include <cassert> |
38 | | #include <cstdint> |
39 | | |
40 | | #define DEBUG_TYPE "opt-addr-mode" |
41 | | |
42 | | using namespace llvm; |
43 | | using namespace rdf; |
44 | | |
45 | | static cl::opt<int> CodeGrowthLimit("hexagon-amode-growth-limit", |
46 | | cl::Hidden, cl::init(0), cl::desc("Code growth limit for address mode " |
47 | | "optimization")); |
48 | | |
49 | | namespace llvm { |
50 | | |
51 | | FunctionPass *createHexagonOptAddrMode(); |
52 | | void initializeHexagonOptAddrModePass(PassRegistry&); |
53 | | |
54 | | } // end namespace llvm |
55 | | |
56 | | namespace { |
57 | | |
58 | | class HexagonOptAddrMode : public MachineFunctionPass { |
59 | | public: |
60 | | static char ID; |
61 | | |
62 | 405 | HexagonOptAddrMode() : MachineFunctionPass(ID) {} |
63 | | |
64 | 401 | StringRef getPassName() const override { |
65 | 401 | return "Optimize addressing mode of load/store"; |
66 | 401 | } |
67 | | |
68 | 401 | void getAnalysisUsage(AnalysisUsage &AU) const override { |
69 | 401 | MachineFunctionPass::getAnalysisUsage(AU); |
70 | 401 | AU.addRequired<MachineDominatorTree>(); |
71 | 401 | AU.addRequired<MachineDominanceFrontier>(); |
72 | 401 | AU.setPreservesAll(); |
73 | 401 | } |
74 | | |
75 | | bool runOnMachineFunction(MachineFunction &MF) override; |
76 | | |
77 | | private: |
78 | | using MISetType = DenseSet<MachineInstr *>; |
79 | | using InstrEvalMap = DenseMap<MachineInstr *, bool>; |
80 | | |
81 | | const HexagonInstrInfo *HII = nullptr; |
82 | | MachineDominatorTree *MDT = nullptr; |
83 | | DataFlowGraph *DFG = nullptr; |
84 | | DataFlowGraph::DefStackMap DefM; |
85 | | Liveness *LV = nullptr; |
86 | | MISetType Deleted; |
87 | | |
88 | | bool processBlock(NodeAddr<BlockNode *> BA); |
89 | | bool xformUseMI(MachineInstr *TfrMI, MachineInstr *UseMI, |
90 | | NodeAddr<UseNode *> UseN, unsigned UseMOnum); |
91 | | bool analyzeUses(unsigned DefR, const NodeList &UNodeList, |
92 | | InstrEvalMap &InstrEvalResult, short &SizeInc); |
93 | | bool hasRepForm(MachineInstr &MI, unsigned TfrDefR); |
94 | | bool canRemoveAddasl(NodeAddr<StmtNode *> AddAslSN, MachineInstr &MI, |
95 | | const NodeList &UNodeList); |
96 | | void getAllRealUses(NodeAddr<StmtNode *> SN, NodeList &UNodeList); |
97 | | bool allValidCandidates(NodeAddr<StmtNode *> SA, NodeList &UNodeList); |
98 | | short getBaseWithLongOffset(const MachineInstr &MI) const; |
99 | | bool changeStore(MachineInstr *OldMI, MachineOperand ImmOp, |
100 | | unsigned ImmOpNum); |
101 | | bool changeLoad(MachineInstr *OldMI, MachineOperand ImmOp, unsigned ImmOpNum); |
102 | | bool changeAddAsl(NodeAddr<UseNode *> AddAslUN, MachineInstr *AddAslMI, |
103 | | const MachineOperand &ImmOp, unsigned ImmOpNum); |
104 | | }; |
105 | | |
106 | | } // end anonymous namespace |
107 | | |
108 | | char HexagonOptAddrMode::ID = 0; |
109 | | |
110 | 90.0k | INITIALIZE_PASS_BEGIN90.0k (HexagonOptAddrMode, "amode-opt",
|
111 | 90.0k | "Optimize addressing mode", false, false) |
112 | 90.0k | INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree) |
113 | 90.0k | INITIALIZE_PASS_DEPENDENCY(MachineDominanceFrontier) |
114 | 90.0k | INITIALIZE_PASS_END(HexagonOptAddrMode, "amode-opt", "Optimize addressing mode", |
115 | | false, false) |
116 | | |
117 | 997 | bool HexagonOptAddrMode::hasRepForm(MachineInstr &MI, unsigned TfrDefR) { |
118 | 997 | const MCInstrDesc &MID = MI.getDesc(); |
119 | 997 | |
120 | 997 | if ((!MID.mayStore() && 997 !MID.mayLoad()628 ) || HII->isPredicated(MI)997 ) |
121 | 0 | return false; |
122 | 997 | |
123 | 997 | if (997 MID.mayStore()997 ) { |
124 | 369 | MachineOperand StOp = MI.getOperand(MI.getNumOperands() - 1); |
125 | 369 | if (StOp.isReg() && 369 StOp.getReg() == TfrDefR369 ) |
126 | 25 | return false; |
127 | 972 | } |
128 | 972 | |
129 | 972 | if (972 HII->getAddrMode(MI) == HexagonII::BaseRegOffset972 ) |
130 | 972 | // Tranform to Absolute plus register offset. |
131 | 21 | return (HII->getBaseWithLongOffset(MI) >= 0); |
132 | 951 | else if (951 HII->getAddrMode(MI) == HexagonII::BaseImmOffset951 ) |
133 | 951 | // Tranform to absolute addressing mode. |
134 | 747 | return (HII->getAbsoluteForm(MI) >= 0); |
135 | 204 | |
136 | 204 | return false; |
137 | 204 | } |
138 | | |
139 | | // Check if addasl instruction can be removed. This is possible only |
140 | | // if it's feeding to only load/store instructions with base + register |
141 | | // offset as these instruction can be tranformed to use 'absolute plus |
142 | | // shifted register offset'. |
143 | | // ex: |
144 | | // Rs = ##foo |
145 | | // Rx = addasl(Rs, Rt, #2) |
146 | | // Rd = memw(Rx + #28) |
147 | | // Above three instructions can be replaced with Rd = memw(Rt<<#2 + ##foo+28) |
148 | | |
149 | | bool HexagonOptAddrMode::canRemoveAddasl(NodeAddr<StmtNode *> AddAslSN, |
150 | | MachineInstr &MI, |
151 | 3 | const NodeList &UNodeList) { |
152 | 3 | // check offset size in addasl. if 'offset > 3' return false |
153 | 3 | const MachineOperand &OffsetOp = MI.getOperand(3); |
154 | 3 | if (!OffsetOp.isImm() || 3 OffsetOp.getImm() > 33 ) |
155 | 0 | return false; |
156 | 3 | |
157 | 3 | unsigned OffsetReg = MI.getOperand(2).getReg(); |
158 | 3 | RegisterRef OffsetRR; |
159 | 3 | NodeId OffsetRegRD = 0; |
160 | 6 | for (NodeAddr<UseNode *> UA : AddAslSN.Addr->members_if(DFG->IsUse, *DFG)) { |
161 | 6 | RegisterRef RR = UA.Addr->getRegRef(*DFG); |
162 | 6 | if (OffsetReg == RR.Reg6 ) { |
163 | 3 | OffsetRR = RR; |
164 | 3 | OffsetRegRD = UA.Addr->getReachingDef(); |
165 | 3 | } |
166 | 6 | } |
167 | 3 | |
168 | 4 | for (auto I = UNodeList.rbegin(), E = UNodeList.rend(); I != E4 ; ++I1 ) { |
169 | 3 | NodeAddr<UseNode *> UA = *I; |
170 | 3 | NodeAddr<InstrNode *> IA = UA.Addr->getOwner(*DFG); |
171 | 3 | if (UA.Addr->getFlags() & NodeAttrs::PhiRef) |
172 | 0 | return false; |
173 | 3 | NodeAddr<RefNode*> AA = LV->getNearestAliasedRef(OffsetRR, IA); |
174 | 3 | if ((DFG->IsDef(AA) && 3 AA.Id != OffsetRegRD2 ) || |
175 | 1 | AA.Addr->getReachingDef() != OffsetRegRD) |
176 | 2 | return false; |
177 | 1 | |
178 | 1 | MachineInstr &UseMI = *NodeAddr<StmtNode *>(IA).Addr->getCode(); |
179 | 1 | NodeAddr<DefNode *> OffsetRegDN = DFG->addr<DefNode *>(OffsetRegRD); |
180 | 1 | // Reaching Def to an offset register can't be a phi. |
181 | 1 | if ((OffsetRegDN.Addr->getFlags() & NodeAttrs::PhiRef) && |
182 | 1 | MI.getParent() != UseMI.getParent()) |
183 | 0 | return false; |
184 | 1 | |
185 | 1 | const MCInstrDesc &UseMID = UseMI.getDesc(); |
186 | 1 | if ((!UseMID.mayLoad() && 1 !UseMID.mayStore()1 ) || |
187 | 1 | HII->getAddrMode(UseMI) != HexagonII::BaseImmOffset || |
188 | 1 | getBaseWithLongOffset(UseMI) < 0) |
189 | 0 | return false; |
190 | 1 | |
191 | 1 | // Addasl output can't be a store value. |
192 | 1 | if (1 UseMID.mayStore() && 1 UseMI.getOperand(2).isReg()1 && |
193 | 1 | UseMI.getOperand(2).getReg() == MI.getOperand(0).getReg()) |
194 | 0 | return false; |
195 | 1 | |
196 | 1 | for (auto &Mo : UseMI.operands()) |
197 | 3 | if (3 Mo.isFI()3 ) |
198 | 0 | return false; |
199 | 3 | } |
200 | 1 | return true; |
201 | 3 | } |
202 | | |
203 | | bool HexagonOptAddrMode::allValidCandidates(NodeAddr<StmtNode *> SA, |
204 | 121 | NodeList &UNodeList) { |
205 | 1.16k | for (auto I = UNodeList.rbegin(), E = UNodeList.rend(); I != E1.16k ; ++I1.03k ) { |
206 | 1.04k | NodeAddr<UseNode *> UN = *I; |
207 | 1.04k | RegisterRef UR = UN.Addr->getRegRef(*DFG); |
208 | 1.04k | NodeSet Visited, Defs; |
209 | 1.04k | const auto &P = LV->getAllReachingDefsRec(UR, UN, Visited, Defs); |
210 | 1.04k | if (!P.second1.04k ) { |
211 | 0 | DEBUG({ |
212 | 0 | dbgs() << "*** Unable to collect all reaching defs for use ***\n" |
213 | 0 | << PrintNode<UseNode*>(UN, *DFG) << '\n' |
214 | 0 | << "The program's complexity may exceed the limits.\n"; |
215 | 0 | }); |
216 | 0 | return false; |
217 | 0 | } |
218 | 1.04k | const auto &ReachingDefs = P.first; |
219 | 1.04k | if (ReachingDefs.size() > 11.04k ) { |
220 | 9 | DEBUG({ |
221 | 9 | dbgs() << "*** Multiple Reaching Defs found!!! ***\n"; |
222 | 9 | for (auto DI : ReachingDefs) { |
223 | 9 | NodeAddr<UseNode *> DA = DFG->addr<UseNode *>(DI); |
224 | 9 | NodeAddr<StmtNode *> TempIA = DA.Addr->getOwner(*DFG); |
225 | 9 | dbgs() << "\t\t[Reaching Def]: " |
226 | 9 | << Print<NodeAddr<InstrNode *>>(TempIA, *DFG) << "\n"; |
227 | 9 | } |
228 | 9 | }); |
229 | 9 | return false; |
230 | 9 | } |
231 | 1.04k | } |
232 | 112 | return true; |
233 | 121 | } |
234 | | |
235 | | void HexagonOptAddrMode::getAllRealUses(NodeAddr<StmtNode *> SA, |
236 | 122 | NodeList &UNodeList) { |
237 | 122 | for (NodeAddr<DefNode *> DA : SA.Addr->members_if(DFG->IsDef, *DFG)) { |
238 | 122 | DEBUG(dbgs() << "\t\t[DefNode]: " << Print<NodeAddr<DefNode *>>(DA, *DFG) |
239 | 122 | << "\n"); |
240 | 122 | RegisterRef DR = DFG->getPRI().normalize(DA.Addr->getRegRef(*DFG)); |
241 | 122 | |
242 | 122 | auto UseSet = LV->getAllReachedUses(DR, DA); |
243 | 122 | |
244 | 1.06k | for (auto UI : UseSet) { |
245 | 1.06k | NodeAddr<UseNode *> UA = DFG->addr<UseNode *>(UI); |
246 | 1.06k | DEBUG({ |
247 | 1.06k | NodeAddr<StmtNode *> TempIA = UA.Addr->getOwner(*DFG); |
248 | 1.06k | dbgs() << "\t\t\t[Reached Use]: " |
249 | 1.06k | << Print<NodeAddr<InstrNode *>>(TempIA, *DFG) << "\n"; |
250 | 1.06k | }); |
251 | 1.06k | |
252 | 1.06k | if (UA.Addr->getFlags() & NodeAttrs::PhiRef1.06k ) { |
253 | 15 | NodeAddr<PhiNode *> PA = UA.Addr->getOwner(*DFG); |
254 | 15 | NodeId id = PA.Id; |
255 | 15 | const Liveness::RefMap &phiUse = LV->getRealUses(id); |
256 | 15 | DEBUG(dbgs() << "\t\t\t\tphi real Uses" |
257 | 15 | << Print<Liveness::RefMap>(phiUse, *DFG) << "\n"); |
258 | 15 | if (!phiUse.empty()15 ) { |
259 | 14 | for (auto I : phiUse) { |
260 | 14 | if (!DFG->getPRI().alias(RegisterRef(I.first), DR)) |
261 | 3 | continue; |
262 | 11 | auto phiUseSet = I.second; |
263 | 23 | for (auto phiUI : phiUseSet) { |
264 | 23 | NodeAddr<UseNode *> phiUA = DFG->addr<UseNode *>(phiUI.first); |
265 | 23 | UNodeList.push_back(phiUA); |
266 | 23 | } |
267 | 14 | } |
268 | 10 | } |
269 | 15 | } else |
270 | 1.04k | UNodeList.push_back(UA); |
271 | 1.06k | } |
272 | 122 | } |
273 | 122 | } |
274 | | |
275 | | bool HexagonOptAddrMode::analyzeUses(unsigned tfrDefR, |
276 | | const NodeList &UNodeList, |
277 | | InstrEvalMap &InstrEvalResult, |
278 | 109 | short &SizeInc) { |
279 | 109 | bool KeepTfr = false; |
280 | 109 | bool HasRepInstr = false; |
281 | 109 | InstrEvalResult.clear(); |
282 | 109 | |
283 | 1.14k | for (auto I = UNodeList.rbegin(), E = UNodeList.rend(); I != E1.14k ; ++I1.03k ) { |
284 | 1.03k | bool CanBeReplaced = false; |
285 | 1.03k | NodeAddr<UseNode *> UN = *I; |
286 | 1.03k | NodeAddr<StmtNode *> SN = UN.Addr->getOwner(*DFG); |
287 | 1.03k | MachineInstr &MI = *SN.Addr->getCode(); |
288 | 1.03k | const MCInstrDesc &MID = MI.getDesc(); |
289 | 1.03k | if ((MID.mayLoad() || 1.03k MID.mayStore()384 )) { |
290 | 997 | if (!hasRepForm(MI, tfrDefR)997 ) { |
291 | 967 | KeepTfr = true; |
292 | 967 | continue; |
293 | 967 | } |
294 | 30 | SizeInc++; |
295 | 30 | CanBeReplaced = true; |
296 | 1.03k | } else if (39 MI.getOpcode() == Hexagon::S2_addasl_rrri39 ) { |
297 | 3 | NodeList AddaslUseList; |
298 | 3 | |
299 | 3 | DEBUG(dbgs() << "\nGetting ReachedUses for === " << MI << "\n"); |
300 | 3 | getAllRealUses(SN, AddaslUseList); |
301 | 3 | // Process phi nodes. |
302 | 3 | if (allValidCandidates(SN, AddaslUseList) && |
303 | 3 | canRemoveAddasl(SN, MI, AddaslUseList)3 ) { |
304 | 1 | SizeInc += AddaslUseList.size(); |
305 | 1 | SizeInc -= 1; // Reduce size by 1 as addasl itself can be removed. |
306 | 1 | CanBeReplaced = true; |
307 | 1 | } else |
308 | 2 | SizeInc++; |
309 | 3 | } else |
310 | 39 | // Currently, only load/store and addasl are handled. |
311 | 39 | // Some other instructions to consider - |
312 | 39 | // A2_add -> A2_addi |
313 | 39 | // M4_mpyrr_addr -> M4_mpyrr_addi |
314 | 36 | KeepTfr = true; |
315 | 1.03k | |
316 | 69 | InstrEvalResult[&MI] = CanBeReplaced; |
317 | 69 | HasRepInstr |= CanBeReplaced; |
318 | 69 | } |
319 | 109 | |
320 | 109 | // Reduce total size by 2 if original tfr can be deleted. |
321 | 109 | if (!KeepTfr) |
322 | 17 | SizeInc -= 2; |
323 | 109 | |
324 | 109 | return HasRepInstr; |
325 | 109 | } |
326 | | |
327 | | bool HexagonOptAddrMode::changeLoad(MachineInstr *OldMI, MachineOperand ImmOp, |
328 | 13 | unsigned ImmOpNum) { |
329 | 13 | bool Changed = false; |
330 | 13 | MachineBasicBlock *BB = OldMI->getParent(); |
331 | 13 | auto UsePos = MachineBasicBlock::iterator(OldMI); |
332 | 13 | MachineBasicBlock::instr_iterator InsertPt = UsePos.getInstrIterator(); |
333 | 13 | ++InsertPt; |
334 | 13 | unsigned OpStart; |
335 | 13 | unsigned OpEnd = OldMI->getNumOperands(); |
336 | 13 | MachineInstrBuilder MIB; |
337 | 13 | |
338 | 13 | if (ImmOpNum == 113 ) { |
339 | 13 | if (HII->getAddrMode(*OldMI) == HexagonII::BaseRegOffset13 ) { |
340 | 6 | short NewOpCode = HII->getBaseWithLongOffset(*OldMI); |
341 | 6 | assert(NewOpCode >= 0 && "Invalid New opcode\n"); |
342 | 6 | MIB = BuildMI(*BB, InsertPt, OldMI->getDebugLoc(), HII->get(NewOpCode)); |
343 | 6 | MIB.add(OldMI->getOperand(0)); |
344 | 6 | MIB.add(OldMI->getOperand(2)); |
345 | 6 | MIB.add(OldMI->getOperand(3)); |
346 | 6 | MIB.add(ImmOp); |
347 | 6 | OpStart = 4; |
348 | 6 | Changed = true; |
349 | 13 | } else if (7 HII->getAddrMode(*OldMI) == HexagonII::BaseImmOffset7 ) { |
350 | 7 | short NewOpCode = HII->getAbsoluteForm(*OldMI); |
351 | 7 | assert(NewOpCode >= 0 && "Invalid New opcode\n"); |
352 | 7 | MIB = BuildMI(*BB, InsertPt, OldMI->getDebugLoc(), HII->get(NewOpCode)) |
353 | 7 | .add(OldMI->getOperand(0)); |
354 | 7 | const GlobalValue *GV = ImmOp.getGlobal(); |
355 | 7 | int64_t Offset = ImmOp.getOffset() + OldMI->getOperand(2).getImm(); |
356 | 7 | |
357 | 7 | MIB.addGlobalAddress(GV, Offset, ImmOp.getTargetFlags()); |
358 | 7 | OpStart = 3; |
359 | 7 | Changed = true; |
360 | 7 | } else |
361 | 0 | Changed = false; |
362 | 13 | |
363 | 13 | DEBUG(dbgs() << "[Changing]: " << *OldMI << "\n"); |
364 | 13 | DEBUG(dbgs() << "[TO]: " << MIB << "\n"); |
365 | 0 | } else if (0 ImmOpNum == 2 && 0 OldMI->getOperand(3).getImm() == 00 ) { |
366 | 0 | short NewOpCode = HII->xformRegToImmOffset(*OldMI); |
367 | 0 | assert(NewOpCode >= 0 && "Invalid New opcode\n"); |
368 | 0 | MIB = BuildMI(*BB, InsertPt, OldMI->getDebugLoc(), HII->get(NewOpCode)); |
369 | 0 | MIB.add(OldMI->getOperand(0)); |
370 | 0 | MIB.add(OldMI->getOperand(1)); |
371 | 0 | MIB.add(ImmOp); |
372 | 0 | OpStart = 4; |
373 | 0 | Changed = true; |
374 | 0 | DEBUG(dbgs() << "[Changing]: " << *OldMI << "\n"); |
375 | 0 | DEBUG(dbgs() << "[TO]: " << MIB << "\n"); |
376 | 0 | } |
377 | 13 | |
378 | 13 | if (Changed) |
379 | 13 | for (unsigned i = OpStart; 13 i < OpEnd13 ; ++i0 ) |
380 | 0 | MIB.add(OldMI->getOperand(i)); |
381 | 13 | |
382 | 13 | return Changed; |
383 | 13 | } |
384 | | |
385 | | bool HexagonOptAddrMode::changeStore(MachineInstr *OldMI, MachineOperand ImmOp, |
386 | 3 | unsigned ImmOpNum) { |
387 | 3 | bool Changed = false; |
388 | 3 | unsigned OpStart; |
389 | 3 | unsigned OpEnd = OldMI->getNumOperands(); |
390 | 3 | MachineBasicBlock *BB = OldMI->getParent(); |
391 | 3 | auto UsePos = MachineBasicBlock::iterator(OldMI); |
392 | 3 | MachineBasicBlock::instr_iterator InsertPt = UsePos.getInstrIterator(); |
393 | 3 | ++InsertPt; |
394 | 3 | MachineInstrBuilder MIB; |
395 | 3 | if (ImmOpNum == 03 ) { |
396 | 3 | if (HII->getAddrMode(*OldMI) == HexagonII::BaseRegOffset3 ) { |
397 | 3 | short NewOpCode = HII->getBaseWithLongOffset(*OldMI); |
398 | 3 | assert(NewOpCode >= 0 && "Invalid New opcode\n"); |
399 | 3 | MIB = BuildMI(*BB, InsertPt, OldMI->getDebugLoc(), HII->get(NewOpCode)); |
400 | 3 | MIB.add(OldMI->getOperand(1)); |
401 | 3 | MIB.add(OldMI->getOperand(2)); |
402 | 3 | MIB.add(ImmOp); |
403 | 3 | MIB.add(OldMI->getOperand(3)); |
404 | 3 | OpStart = 4; |
405 | 3 | } else if (0 HII->getAddrMode(*OldMI) == HexagonII::BaseImmOffset0 ) { |
406 | 0 | short NewOpCode = HII->getAbsoluteForm(*OldMI); |
407 | 0 | assert(NewOpCode >= 0 && "Invalid New opcode\n"); |
408 | 0 | MIB = BuildMI(*BB, InsertPt, OldMI->getDebugLoc(), HII->get(NewOpCode)); |
409 | 0 | const GlobalValue *GV = ImmOp.getGlobal(); |
410 | 0 | int64_t Offset = ImmOp.getOffset() + OldMI->getOperand(1).getImm(); |
411 | 0 | MIB.addGlobalAddress(GV, Offset, ImmOp.getTargetFlags()); |
412 | 0 | MIB.add(OldMI->getOperand(2)); |
413 | 0 | OpStart = 3; |
414 | 0 | } |
415 | 3 | Changed = true; |
416 | 3 | DEBUG(dbgs() << "[Changing]: " << *OldMI << "\n"); |
417 | 3 | DEBUG(dbgs() << "[TO]: " << MIB << "\n"); |
418 | 0 | } else if (0 ImmOpNum == 1 && 0 OldMI->getOperand(2).getImm() == 00 ) { |
419 | 0 | short NewOpCode = HII->xformRegToImmOffset(*OldMI); |
420 | 0 | assert(NewOpCode >= 0 && "Invalid New opcode\n"); |
421 | 0 | MIB = BuildMI(*BB, InsertPt, OldMI->getDebugLoc(), HII->get(NewOpCode)); |
422 | 0 | MIB.add(OldMI->getOperand(0)); |
423 | 0 | MIB.add(ImmOp); |
424 | 0 | MIB.add(OldMI->getOperand(1)); |
425 | 0 | OpStart = 2; |
426 | 0 | Changed = true; |
427 | 0 | DEBUG(dbgs() << "[Changing]: " << *OldMI << "\n"); |
428 | 0 | DEBUG(dbgs() << "[TO]: " << MIB << "\n"); |
429 | 0 | } |
430 | 3 | if (Changed) |
431 | 3 | for (unsigned i = OpStart; 3 i < OpEnd3 ; ++i0 ) |
432 | 0 | MIB.add(OldMI->getOperand(i)); |
433 | 3 | |
434 | 3 | return Changed; |
435 | 3 | } |
436 | | |
437 | 2 | short HexagonOptAddrMode::getBaseWithLongOffset(const MachineInstr &MI) const { |
438 | 2 | if (HII->getAddrMode(MI) == HexagonII::BaseImmOffset2 ) { |
439 | 2 | short TempOpCode = HII->getBaseWithRegOffset(MI); |
440 | 2 | return HII->getBaseWithLongOffset(TempOpCode); |
441 | 2 | } else |
442 | 0 | return HII->getBaseWithLongOffset(MI); |
443 | 0 | } |
444 | | |
445 | | bool HexagonOptAddrMode::changeAddAsl(NodeAddr<UseNode *> AddAslUN, |
446 | | MachineInstr *AddAslMI, |
447 | | const MachineOperand &ImmOp, |
448 | 1 | unsigned ImmOpNum) { |
449 | 1 | NodeAddr<StmtNode *> SA = AddAslUN.Addr->getOwner(*DFG); |
450 | 1 | |
451 | 1 | DEBUG(dbgs() << "Processing addasl :" << *AddAslMI << "\n"); |
452 | 1 | |
453 | 1 | NodeList UNodeList; |
454 | 1 | getAllRealUses(SA, UNodeList); |
455 | 1 | |
456 | 2 | for (auto I = UNodeList.rbegin(), E = UNodeList.rend(); I != E2 ; ++I1 ) { |
457 | 1 | NodeAddr<UseNode *> UseUN = *I; |
458 | 1 | assert(!(UseUN.Addr->getFlags() & NodeAttrs::PhiRef) && |
459 | 1 | "Can't transform this 'AddAsl' instruction!"); |
460 | 1 | |
461 | 1 | NodeAddr<StmtNode *> UseIA = UseUN.Addr->getOwner(*DFG); |
462 | 1 | DEBUG(dbgs() << "[InstrNode]: " << Print<NodeAddr<InstrNode *>>(UseIA, *DFG) |
463 | 1 | << "\n"); |
464 | 1 | MachineInstr *UseMI = UseIA.Addr->getCode(); |
465 | 1 | DEBUG(dbgs() << "[MI <BB#" << UseMI->getParent()->getNumber() |
466 | 1 | << ">]: " << *UseMI << "\n"); |
467 | 1 | const MCInstrDesc &UseMID = UseMI->getDesc(); |
468 | 1 | assert(HII->getAddrMode(*UseMI) == HexagonII::BaseImmOffset); |
469 | 1 | |
470 | 1 | auto UsePos = MachineBasicBlock::iterator(UseMI); |
471 | 1 | MachineBasicBlock::instr_iterator InsertPt = UsePos.getInstrIterator(); |
472 | 1 | short NewOpCode = getBaseWithLongOffset(*UseMI); |
473 | 1 | assert(NewOpCode >= 0 && "Invalid New opcode\n"); |
474 | 1 | |
475 | 1 | unsigned OpStart; |
476 | 1 | unsigned OpEnd = UseMI->getNumOperands(); |
477 | 1 | |
478 | 1 | MachineBasicBlock *BB = UseMI->getParent(); |
479 | 1 | MachineInstrBuilder MIB = |
480 | 1 | BuildMI(*BB, InsertPt, UseMI->getDebugLoc(), HII->get(NewOpCode)); |
481 | 1 | // change mem(Rs + # ) -> mem(Rt << # + ##) |
482 | 1 | if (UseMID.mayLoad()1 ) { |
483 | 0 | MIB.add(UseMI->getOperand(0)); |
484 | 0 | MIB.add(AddAslMI->getOperand(2)); |
485 | 0 | MIB.add(AddAslMI->getOperand(3)); |
486 | 0 | const GlobalValue *GV = ImmOp.getGlobal(); |
487 | 0 | MIB.addGlobalAddress(GV, UseMI->getOperand(2).getImm()+ImmOp.getOffset(), |
488 | 0 | ImmOp.getTargetFlags()); |
489 | 0 | OpStart = 3; |
490 | 1 | } else if (1 UseMID.mayStore()1 ) { |
491 | 1 | MIB.add(AddAslMI->getOperand(2)); |
492 | 1 | MIB.add(AddAslMI->getOperand(3)); |
493 | 1 | const GlobalValue *GV = ImmOp.getGlobal(); |
494 | 1 | MIB.addGlobalAddress(GV, UseMI->getOperand(1).getImm()+ImmOp.getOffset(), |
495 | 1 | ImmOp.getTargetFlags()); |
496 | 1 | MIB.add(UseMI->getOperand(2)); |
497 | 1 | OpStart = 3; |
498 | 1 | } else |
499 | 0 | llvm_unreachable("Unhandled instruction"); |
500 | 1 | |
501 | 1 | for (unsigned i = OpStart; 1 i < OpEnd1 ; ++i0 ) |
502 | 0 | MIB.add(UseMI->getOperand(i)); |
503 | 1 | |
504 | 1 | Deleted.insert(UseMI); |
505 | 1 | } |
506 | 1 | |
507 | 1 | return true; |
508 | 1 | } |
509 | | |
510 | | bool HexagonOptAddrMode::xformUseMI(MachineInstr *TfrMI, MachineInstr *UseMI, |
511 | | NodeAddr<UseNode *> UseN, |
512 | 17 | unsigned UseMOnum) { |
513 | 17 | const MachineOperand ImmOp = TfrMI->getOperand(1); |
514 | 17 | const MCInstrDesc &MID = UseMI->getDesc(); |
515 | 17 | unsigned Changed = false; |
516 | 17 | if (MID.mayLoad()) |
517 | 13 | Changed = changeLoad(UseMI, ImmOp, UseMOnum); |
518 | 4 | else if (4 MID.mayStore()4 ) |
519 | 3 | Changed = changeStore(UseMI, ImmOp, UseMOnum); |
520 | 1 | else if (1 UseMI->getOpcode() == Hexagon::S2_addasl_rrri1 ) |
521 | 1 | Changed = changeAddAsl(UseN, UseMI, ImmOp, UseMOnum); |
522 | 17 | |
523 | 17 | if (Changed) |
524 | 17 | Deleted.insert(UseMI); |
525 | 17 | |
526 | 17 | return Changed; |
527 | 17 | } |
528 | | |
529 | 2.04k | bool HexagonOptAddrMode::processBlock(NodeAddr<BlockNode *> BA) { |
530 | 2.04k | bool Changed = false; |
531 | 2.04k | |
532 | 15.6k | for (auto IA : BA.Addr->members(*DFG)) { |
533 | 15.6k | if (!DFG->IsCode<NodeAttrs::Stmt>(IA)) |
534 | 4.11k | continue; |
535 | 11.5k | |
536 | 11.5k | NodeAddr<StmtNode *> SA = IA; |
537 | 11.5k | MachineInstr *MI = SA.Addr->getCode(); |
538 | 11.5k | if (MI->getOpcode() != Hexagon::A2_tfrsi || |
539 | 669 | !MI->getOperand(1).isGlobal()) |
540 | 11.4k | continue; |
541 | 118 | |
542 | 118 | DEBUG118 (dbgs() << "[Analyzing " << HII->getName(MI->getOpcode()) << "]: " |
543 | 118 | << *MI << "\n\t[InstrNode]: " |
544 | 118 | << Print<NodeAddr<InstrNode *>>(IA, *DFG) << '\n'); |
545 | 118 | |
546 | 118 | NodeList UNodeList; |
547 | 118 | getAllRealUses(SA, UNodeList); |
548 | 118 | |
549 | 118 | if (!allValidCandidates(SA, UNodeList)) |
550 | 9 | continue; |
551 | 109 | |
552 | 109 | short SizeInc = 0; |
553 | 109 | unsigned DefR = MI->getOperand(0).getReg(); |
554 | 109 | InstrEvalMap InstrEvalResult; |
555 | 109 | |
556 | 109 | // Analyze all uses and calculate increase in size. Perform the optimization |
557 | 109 | // only if there is no increase in size. |
558 | 109 | if (!analyzeUses(DefR, UNodeList, InstrEvalResult, SizeInc)) |
559 | 92 | continue; |
560 | 17 | if (17 SizeInc > CodeGrowthLimit17 ) |
561 | 4 | continue; |
562 | 13 | |
563 | 13 | bool KeepTfr = false; |
564 | 13 | |
565 | 13 | DEBUG(dbgs() << "\t[Total reached uses] : " << UNodeList.size() << "\n"); |
566 | 13 | DEBUG(dbgs() << "\t[Processing Reached Uses] ===\n"); |
567 | 30 | for (auto I = UNodeList.rbegin(), E = UNodeList.rend(); I != E30 ; ++I17 ) { |
568 | 17 | NodeAddr<UseNode *> UseN = *I; |
569 | 17 | assert(!(UseN.Addr->getFlags() & NodeAttrs::PhiRef) && |
570 | 17 | "Found a PhiRef node as a real reached use!!"); |
571 | 17 | |
572 | 17 | NodeAddr<StmtNode *> OwnerN = UseN.Addr->getOwner(*DFG); |
573 | 17 | MachineInstr *UseMI = OwnerN.Addr->getCode(); |
574 | 17 | DEBUG(dbgs() << "\t\t[MI <BB#" << UseMI->getParent()->getNumber() |
575 | 17 | << ">]: " << *UseMI << "\n"); |
576 | 17 | |
577 | 17 | int UseMOnum = -1; |
578 | 17 | unsigned NumOperands = UseMI->getNumOperands(); |
579 | 61 | for (unsigned j = 0; j < NumOperands - 161 ; ++j44 ) { |
580 | 44 | const MachineOperand &op = UseMI->getOperand(j); |
581 | 44 | if (op.isReg() && 44 op.isUse()41 && DefR == op.getReg()27 ) |
582 | 17 | UseMOnum = j; |
583 | 44 | } |
584 | 17 | assert(UseMOnum >= 0 && "Invalid reached use!"); |
585 | 17 | |
586 | 17 | if (InstrEvalResult[UseMI]) |
587 | 17 | // Change UseMI if replacement is possible. |
588 | 17 | Changed |= xformUseMI(MI, UseMI, UseN, UseMOnum); |
589 | 17 | else |
590 | 0 | KeepTfr = true; |
591 | 17 | } |
592 | 13 | if (!KeepTfr) |
593 | 13 | Deleted.insert(MI); |
594 | 15.6k | } |
595 | 2.04k | return Changed; |
596 | 2.04k | } |
597 | | |
598 | 857 | bool HexagonOptAddrMode::runOnMachineFunction(MachineFunction &MF) { |
599 | 857 | if (skipFunction(*MF.getFunction())) |
600 | 0 | return false; |
601 | 857 | |
602 | 857 | bool Changed = false; |
603 | 857 | auto &HST = MF.getSubtarget<HexagonSubtarget>(); |
604 | 857 | auto &MRI = MF.getRegInfo(); |
605 | 857 | HII = HST.getInstrInfo(); |
606 | 857 | const auto &MDF = getAnalysis<MachineDominanceFrontier>(); |
607 | 857 | MDT = &getAnalysis<MachineDominatorTree>(); |
608 | 857 | const auto &TRI = *MF.getSubtarget().getRegisterInfo(); |
609 | 857 | const TargetOperandInfo TOI(*HII); |
610 | 857 | |
611 | 857 | DataFlowGraph G(MF, *HII, TRI, *MDT, MDF, TOI); |
612 | 857 | // Need to keep dead phis because we can propagate uses of registers into |
613 | 857 | // nodes dominated by those would-be phis. |
614 | 857 | G.build(BuildOptions::KeepDeadPhis); |
615 | 857 | DFG = &G; |
616 | 857 | |
617 | 857 | Liveness L(MRI, *DFG); |
618 | 857 | L.computePhiInfo(); |
619 | 857 | LV = &L; |
620 | 857 | |
621 | 857 | Deleted.clear(); |
622 | 857 | NodeAddr<FuncNode *> FA = DFG->getFunc(); |
623 | 857 | DEBUG(dbgs() << "==== [RefMap#]=====:\n " |
624 | 857 | << Print<NodeAddr<FuncNode *>>(FA, *DFG) << "\n"); |
625 | 857 | |
626 | 857 | for (NodeAddr<BlockNode *> BA : FA.Addr->members(*DFG)) |
627 | 2.04k | Changed |= processBlock(BA); |
628 | 857 | |
629 | 857 | for (auto MI : Deleted) |
630 | 31 | MI->eraseFromParent(); |
631 | 857 | |
632 | 857 | if (Changed857 ) { |
633 | 13 | G.build(); |
634 | 13 | L.computeLiveIns(); |
635 | 13 | L.resetLiveIns(); |
636 | 13 | L.resetKills(); |
637 | 13 | } |
638 | 857 | |
639 | 857 | return Changed; |
640 | 857 | } |
641 | | |
642 | | //===----------------------------------------------------------------------===// |
643 | | // Public Constructor Functions |
644 | | //===----------------------------------------------------------------------===// |
645 | | |
646 | 403 | FunctionPass *llvm::createHexagonOptAddrMode() { |
647 | 403 | return new HexagonOptAddrMode(); |
648 | 403 | } |