LLVM: lib/Target/ARC/ARCOptAddrMode.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
15#define GET_INSTRMAP_INFO
29
30using namespace llvm;
31
32#define OPTADDRMODE_DESC "ARC load/store address mode"
33#define OPTADDRMODE_NAME "arc-addr-mode"
34#define DEBUG_TYPE "arc-addr-mode"
35
36namespace llvm {
37
40
41#define DUMP_BEFORE() ((ArcKillAddrMode & 0x0001) != 0)
42#define DUMP_AFTER() ((ArcKillAddrMode & 0x0002) != 0)
43#define VIEW_BEFORE() ((ArcKillAddrMode & 0x0004) != 0)
44#define VIEW_AFTER() ((ArcKillAddrMode & 0x0008) != 0)
45#define KILL_PASS() ((ArcKillAddrMode & 0x0010) != 0)
46
49}
50
51namespace {
53public:
54 static char ID;
55
57
58 StringRef getPassName() const override { return OPTADDRMODE_DESC; }
59
60 void getAnalysisUsage(AnalysisUsage &AU) const override {
63 AU.addRequired();
64 AU.addPreserved();
65 }
66
67 bool runOnMachineFunction(MachineFunction &MF) override;
68
69private:
70 const ARCSubtarget *AST = nullptr;
71 const ARCInstrInfo *AII = nullptr;
72 MachineRegisterInfo *MRI = nullptr;
73 MachineDominatorTree *MDT = nullptr;
74
75
76
77 MachineInstr *tryToCombine(MachineInstr &Ldst);
78
79
80 bool noUseOfAddBeforeLoadOrStore(const MachineInstr *Add,
81 const MachineInstr *Ldst);
82
83
84
85 bool canHoistLoadStoreTo(MachineInstr *Ldst, MachineInstr *To);
86
87
88
89
90
91
92
93
94
95 MachineInstr *canJoinInstructions(MachineInstr *Ldst, MachineInstr *Add,
96 SmallVectorImpl<MachineInstr *> *Uses);
97
98
99
101 MachineOperand &Incr, unsigned BaseReg);
102
103
104
107
108
109
110
111 void changeToAddrMode(MachineInstr &Ldst, unsigned NewOpcode,
112 unsigned NewBase, MachineOperand &NewOffset);
113
114 bool processBasicBlock(MachineBasicBlock &MBB);
115};
116
117}
118
119char ARCOptAddrMode::ID = 0;
121 false)
125
126
127
129
130
131
133
135 int64_t Sign = 1;
136 switch (MI.getOpcode()) {
137 case ARC::SUB_rru6:
138 Sign = -1;
139 [[fallthrough]];
140 case ARC::ADD_rru6:
141 assert(MI.getOperand(2).isImm() && "Expected immediate operand");
142 Amount = Sign * MI.getOperand(2).getImm();
143 return true;
144 default:
145 return false;
146 }
147}
148
149
153
155
158 if (User->isPHI()) {
161 if (MBB->empty()) {
163 assert(InstBB != MBB && "Instruction found in empty MBB");
165 return false;
166 continue;
167 }
169 }
170
172 return false;
173 }
174 return true;
175}
176
177
178
181 int64_t Disp) {
182 unsigned BasePos, OffPos;
183 if (->getBaseAndOffsetPosition(MI, BasePos, OffPos))
184 return false;
187 return false;
190}
191
192bool ARCOptAddrMode::noUseOfAddBeforeLoadOrStore(const MachineInstr *Add,
196}
197
198MachineInstr *ARCOptAddrMode::tryToCombine(MachineInstr &Ldst) {
200
201 unsigned BasePos, OffsetPos;
202
203 LLVM_DEBUG(dbgs() << "[ABAW] tryToCombine " << Ldst);
205 LLVM_DEBUG(dbgs() << "[ABAW] Not a recognized load/store\n");
206 return nullptr;
207 }
208
211
212 assert(Base.isReg() && "Base operand must be register");
213 if (.isImm()) {
214 LLVM_DEBUG(dbgs() << "[ABAW] Offset is not immediate\n");
215 return nullptr;
216 }
217
219 if (!Register::isVirtualRegister(B)) {
221 return nullptr;
222 }
223
224
225 if (Offset.getImm() != 0) {
227 return nullptr;
228 }
229
230 for (auto &Add : MRI->use_nodbg_instructions(B)) {
231 int64_t Incr;
233 continue;
235 continue;
236
237 SmallVector<MachineInstr *, 8> Uses;
238 MachineInstr *MoveTo = canJoinInstructions(&Ldst, &Add, &Uses);
239
240 if (!MoveTo)
241 continue;
242
243 if (!canFixPastUses(Uses, Add.getOperand(2), B))
244 continue;
245
248 dbgs() << "[ABAW] Instructions " << *First << " and " << *Last
249 << " combined\n";
250
251 );
252
254 if (MoveTo == &Add) {
257 }
258 if (Result == &Add)
260
261 fixPastUses(Uses, B, Incr);
262
263 int NewOpcode = ARC::getPostIncOpcode(Ldst.getOpcode());
264 assert(NewOpcode > 0 && "No postincrement form found");
265 unsigned NewBaseReg = Add.getOperand(0).getReg();
266 changeToAddrMode(Ldst, NewOpcode, NewBaseReg, Add.getOperand(2));
267 Add.eraseFromParent();
268
270 }
271 return nullptr;
272}
273
274MachineInstr *
275ARCOptAddrMode::canJoinInstructions(MachineInstr *Ldst, MachineInstr *Add,
276 SmallVectorImpl<MachineInstr *> *Uses) {
277 assert(Ldst && Add && "NULL instruction passed");
278
280 MachineInstr *Last = Ldst;
284 return nullptr;
285
287
288 unsigned BasePos, OffPos;
289
293 << "[canJoinInstructions] Cannot determine base/offset position\n");
294 return nullptr;
295 }
296
298
299
300
301
302
303
304
307 if (Add->getOperand(0).getReg() == StReg || BaseReg == StReg) {
308 LLVM_DEBUG(dbgs() << "[canJoinInstructions] Store uses result of Add\n");
309 return nullptr;
310 }
311 }
312
313 SmallVector<MachineInstr *, 4> UsesAfterLdst;
314 SmallVector<MachineInstr *, 4> UsesAfterAdd;
315 for (MachineInstr &MI : MRI->use_nodbg_instructions(BaseReg)) {
316 if (&MI == Ldst || &MI == Add)
317 continue;
321 return nullptr;
324 }
325
326 MachineInstr *Result = nullptr;
327
329
330
331
332
333 if (noUseOfAddBeforeLoadOrStore(First, Last)) {
335 LLVM_DEBUG(dbgs() << "[canJoinInstructions] Can sink Add down to Ldst\n");
336 } else if (canHoistLoadStoreTo(Ldst, Add)) {
338 LLVM_DEBUG(dbgs() << "[canJoinInstructions] Can hoist Ldst to Add\n");
339 }
340 } else {
341
342
343
345 LLVM_DEBUG(dbgs() << "[canJoinInstructions] Can hoist Add to Ldst\n");
346 }
347 if (Result && Uses)
348 *Uses = (Result == Ldst) ? UsesAfterLdst : UsesAfterAdd;
350}
351
353 MachineOperand &Incr, unsigned BaseReg) {
354
355 assert(Incr.isImm() && "Expected immediate increment");
356 int64_t NewOffset = Incr.getImm();
357 for (MachineInstr *MI : Uses) {
358 int64_t Dummy;
361 continue;
362 return false;
363 }
365 continue;
366 LLVM_DEBUG(dbgs() << "Instruction cannot handle displacement " << -NewOffset
367 << ": " << *MI);
368 return false;
369 }
370 return true;
371}
372
374 unsigned NewBase, int64_t NewOffset) {
375
376 for (MachineInstr *MI : Uses) {
377 int64_t Amount;
378 unsigned BasePos, OffPos;
380 NewOffset += Amount;
382 "New offset won't fit into ADD instr");
383 BasePos = 1;
384 OffPos = 2;
386 MachineOperand &MO = MI->getOperand(OffPos);
387 assert(MO.isImm() && "expected immediate operand");
388 NewOffset += MO.getImm();
390 "New offset won't fit into LD/ST");
391 } else
393
394 MI->getOperand(BasePos).setReg(NewBase);
395 MI->getOperand(OffPos).setImm(NewOffset);
396 }
397}
398
399bool ARCOptAddrMode::canHoistLoadStoreTo(MachineInstr *Ldst, MachineInstr *To) {
401 return false;
404
405 bool IsStore = Ldst->mayStore();
406 for (; MI != ME && MI != End; ++MI) {
407 if (MI->isDebugValue())
408 continue;
409 if (MI->mayStore() || MI->isCall() || MI->isInlineAsm() ||
410 MI->hasUnmodeledSideEffects())
411 return false;
412 if (IsStore && MI->mayLoad())
413 return false;
414 }
415
417 if (.isReg() ||
.isUse())
418 continue;
419 MachineInstr *OpDef = MRI->getVRegDef(O.getReg());
420 if (!OpDef || !MDT->dominates(OpDef, To))
421 return false;
422 }
423 return true;
424}
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451void ARCOptAddrMode::changeToAddrMode(MachineInstr &Ldst, unsigned NewOpcode,
452 unsigned NewBase,
453 MachineOperand &NewOffset) {
454 bool IsStore = Ldst.mayStore();
455 unsigned BasePos, OffPos;
458
460
463
464 if (IsStore) {
467 }
468
471 if (IsStore)
476}
477
478bool ARCOptAddrMode::processBasicBlock(MachineBasicBlock &MBB) {
481 if (MI->isDebugValue())
482 continue;
483 if (->mayLoad() &&
->mayStore())
484 continue;
485 if (ARC::getPostIncOpcode(MI->getOpcode()) < 0)
486 continue;
487 MachineInstr *Res = tryToCombine(*MI);
488 if (Res) {
490
492 }
493 }
495}
496
497bool ARCOptAddrMode::runOnMachineFunction(MachineFunction &MF) {
499 return false;
500
501#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
504#endif
507
511 MDT = &getAnalysis().getDomTree();
512
514 for (auto &MBB : MF)
516
517#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
519 MF.dump();
520#endif
522 MF.viewCFG();
524}
525
526
527
528
529
unsigned const MachineRegisterInfo * MRI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
const TargetInstrInfo & TII
#define VIEW_BEFORE()
Definition ARCOptAddrMode.cpp:43
static bool isLoadStoreThatCanHandleDisplacement(const TargetInstrInfo *TII, const MachineInstr &MI, int64_t Disp)
Definition ARCOptAddrMode.cpp:179
static bool dominatesAllUsesOf(const MachineInstr *MI, unsigned VReg, MachineDominatorTree *MDT, MachineRegisterInfo *MRI)
Definition ARCOptAddrMode.cpp:150
static bool isValidIncrementOffset(int64_t Off)
Definition ARCOptAddrMode.cpp:132
static false bool isValidLoadStoreOffset(int64_t Off)
Definition ARCOptAddrMode.cpp:128
#define DUMP_AFTER()
Definition ARCOptAddrMode.cpp:42
#define OPTADDRMODE_NAME
Definition ARCOptAddrMode.cpp:33
#define KILL_PASS()
Definition ARCOptAddrMode.cpp:45
#define OPTADDRMODE_DESC
Definition ARCOptAddrMode.cpp:32
static bool isAddConstantOp(const MachineInstr &MI, int64_t &Amount)
Definition ARCOptAddrMode.cpp:134
#define VIEW_AFTER()
Definition ARCOptAddrMode.cpp:44
#define DUMP_BEFORE()
Definition ARCOptAddrMode.cpp:41
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
Promote Memory to Register
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Remove Loads Into Fake Uses
virtual bool getBaseAndOffsetPosition(const MachineInstr &MI, unsigned &BasePos, unsigned &OffsetPos) const override
const ARCInstrInfo * getInstrInfo() const override
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
FunctionPass class - This class is used to implement most global optimizations.
MachineInstrBundleIterator< const MachineInstr > const_iterator
iterator insertAfter(iterator I, MachineInstr *MI)
Insert MI into the instruction list after I.
Analysis pass which computes a MachineDominatorTree.
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
bool dominates(const MachineInstr *A, const MachineInstr *B) const
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
void dump() const
dump - Print the current MachineFunction to cerr, useful for debugger use.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
void viewCFG() const
viewCFG - This function is meant for use from the debugger.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
bool mayLoadOrStore(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly read or modify memory.
LLVM_ABI MachineInstr * removeFromParent()
Unlink 'this' from the containing basic block, and return it without deleting it.
const MachineBasicBlock * getParent() const
LLVM_ABI void addOperand(MachineFunction &MF, const MachineOperand &Op)
Add the specified operand to the instruction.
LLVM_ABI void setDesc(const MCInstrDesc &TID)
Replace the instruction descriptor (thus opcode) of the current instruction with a new one.
mop_range explicit_operands()
bool mayStore(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly modify memory.
LLVM_ABI void removeOperand(unsigned OpNo)
Erase an operand from an instruction, leaving it with one fewer operand than it started with.
const MachineOperand & getOperand(unsigned i) const
MachineOperand class - Representation of each machine instruction operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
static MachineOperand CreateImm(int64_t Val)
Register getReg() const
getReg - Returns the register number.
static MachineOperand CreateReg(Register Reg, bool isDef, bool isImp=false, bool isKill=false, bool isDead=false, bool isUndef=false, bool isEarlyClobber=false, unsigned SubReg=0, bool isDebug=false, bool isInternalRead=false, bool isRenamable=false)
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
PassRegistry - This class manages the registration and intitialization of the pass subsystem as appli...
static constexpr bool isVirtualRegister(unsigned Reg)
Return true if the specified register number is in the virtual register namespace.
void push_back(const T &Elt)
TargetInstrInfo - Interface to description of machine instruction set.
A Use represents the edge between a Value definition and its users.
LLVM_ABI unsigned getOperandNo() const
Return the operand # of this use in its User.
Value * getOperand(unsigned i) const
self_iterator getIterator()
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
initializer< Ty > init(const Ty &Val)
BaseReg
Stack frame base register. Bit 0 of FREInfo.Info.
This is an optimization pass for GlobalISel generic memory operations.
constexpr bool isInt(int64_t x)
Checks if an integer fits into the given bit width.
void initializeARCOptAddrModePass(PassRegistry &)
static cl::opt< unsigned > ArcKillAddrMode("arc-kill-addr-mode", cl::init(0), cl::ReallyHidden)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
ArrayRef(const T &OneElt) -> ArrayRef< T >
FunctionPass * createARCOptAddrMode()
Definition ARCOptAddrMode.cpp:530
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.