1 //===- ARCOptAddrMode.cpp ---------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
10 /// This pass folds LD/ST + ADD pairs into Pre/Post-increment form of
11 /// load/store instructions.
12 //===----------------------------------------------------------------------===//
15 #define GET_INSTRMAP_INFO
16 #include "ARCInstrInfo.h"
17 #include "ARCTargetMachine.h"
18 #include "llvm/CodeGen/MachineBasicBlock.h"
19 #include "llvm/CodeGen/MachineDominators.h"
20 #include "llvm/CodeGen/MachineFunctionPass.h"
21 #include "llvm/CodeGen/MachineInstr.h"
22 #include "llvm/CodeGen/MachineInstrBuilder.h"
23 #include "llvm/CodeGen/TargetRegisterInfo.h"
24 #include "llvm/IR/Function.h"
25 #include "llvm/Support/Debug.h"
26 #include "llvm/Support/raw_ostream.h"
30 #define OPTADDRMODE_DESC "ARC load/store address mode"
31 #define OPTADDRMODE_NAME "arc-addr-mode"
32 #define DEBUG_TYPE "arc-addr-mode"
35 FunctionPass *createARCOptAddrMode();
36 void initializeARCOptAddrModePass(PassRegistry &);
37 } // end namespace llvm
40 class ARCOptAddrMode : public MachineFunctionPass {
44 ARCOptAddrMode() : MachineFunctionPass(ID) {}
46 StringRef getPassName() const override { return OPTADDRMODE_DESC; }
48 void getAnalysisUsage(AnalysisUsage &AU) const override {
50 MachineFunctionPass::getAnalysisUsage(AU);
51 AU.addRequired<MachineDominatorTree>();
52 AU.addPreserved<MachineDominatorTree>();
55 bool runOnMachineFunction(MachineFunction &MF) override;
58 const ARCSubtarget *AST = nullptr;
59 const ARCInstrInfo *AII = nullptr;
60 MachineRegisterInfo *MRI = nullptr;
61 MachineDominatorTree *MDT = nullptr;
63 // Tries to combine \p Ldst with increment of its base register to form
64 // single post-increment instruction.
65 MachineInstr *tryToCombine(MachineInstr &Ldst);
67 // Returns true if result of \p Add is not used before \p Ldst
68 bool noUseOfAddBeforeLoadOrStore(const MachineInstr *Add,
69 const MachineInstr *Ldst);
71 // Returns true if load/store instruction \p Ldst can be hoisted up to
73 bool canHoistLoadStoreTo(MachineInstr *Ldst, MachineInstr *To);
75 // Returns true if load/store instruction \p Ldst can be sunk down
76 // to instruction \p To
77 bool canSinkLoadStoreTo(MachineInstr *Ldst, MachineInstr *To);
79 // Check if instructions \p Ldst and \p Add can be moved to become adjacent
80 // If they can return instruction which need not to move.
81 // If \p Uses is not null, fill it with instructions after \p Ldst which use
82 // \p Ldst's base register
83 MachineInstr *canJoinInstructions(MachineInstr *Ldst, MachineInstr *Add,
84 SmallVectorImpl<MachineInstr *> *Uses);
86 // Returns true if all instruction in \p Uses array can be adjusted
87 // to accomodate increment of register \p BaseReg by \p Incr
88 bool canFixPastUses(const ArrayRef<MachineInstr *> &Uses,
89 MachineOperand &Incr, unsigned BaseReg);
91 // Update all instructions in \p Uses to accomodate increment
92 // of \p BaseReg by \p Offset
93 void fixPastUses(ArrayRef<MachineInstr *> Uses, unsigned BaseReg,
96 // Change instruction \p Ldst to postincrement form.
97 // \p NewBase is register to hold update base value
98 // \p NewOffset is instruction's new offset
99 void changeToAddrMode(MachineInstr &Ldst, unsigned NewOpcode,
100 unsigned NewBase, MachineOperand &NewOffset);
102 bool processBasicBlock(MachineBasicBlock &MBB);
105 } // end anonymous namespace
107 char ARCOptAddrMode::ID = 0;
108 INITIALIZE_PASS_BEGIN(ARCOptAddrMode, OPTADDRMODE_NAME, OPTADDRMODE_DESC, false,
110 INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
111 INITIALIZE_PASS_END(ARCOptAddrMode, OPTADDRMODE_NAME, OPTADDRMODE_DESC, false,
114 // Return true if \p Off can be used as immediate offset
115 // operand of load/store instruction (S9 literal)
116 static bool isValidLoadStoreOffset(int64_t Off) { return isInt<9>(Off); }
118 // Return true if \p Off can be used as immediate operand of
119 // ADD/SUB instruction (U6 literal)
120 static bool isValidIncrementOffset(int64_t Off) { return isUInt<6>(Off); }
122 static bool isAddConstantOp(const MachineInstr &MI, int64_t &Amount) {
124 switch (MI.getOpcode()) {
129 assert(MI.getOperand(2).isImm() && "Expected immediate operand");
130 Amount = Sign * MI.getOperand(2).getImm();
137 // Return true if \p MI dominates of uses of virtual register \p VReg
138 static bool dominatesAllUsesOf(const MachineInstr *MI, unsigned VReg,
139 MachineDominatorTree *MDT,
140 MachineRegisterInfo *MRI) {
142 assert(TargetRegisterInfo::isVirtualRegister(VReg) &&
143 "Expected virtual register!");
145 for (auto it = MRI->use_nodbg_begin(VReg), end = MRI->use_nodbg_end();
147 MachineInstr *User = it->getParent();
149 unsigned BBOperandIdx = User->getOperandNo(&*it) + 1;
150 MachineBasicBlock *MBB = User->getOperand(BBOperandIdx).getMBB();
152 const MachineBasicBlock *InstBB = MI->getParent();
153 assert(InstBB != MBB && "Instruction found in empty MBB");
154 if (!MDT->dominates(InstBB, MBB))
158 User = &*MBB->rbegin();
161 if (!MDT->dominates(MI, User))
167 // Return true if \p MI is load/store instruction with immediate offset
168 // which can be adjusted by \p Disp
169 static bool isLoadStoreThatCanHandleDisplacement(const TargetInstrInfo *TII,
170 const MachineInstr &MI,
172 unsigned BasePos, OffPos;
173 if (!TII->getBaseAndOffsetPosition(MI, BasePos, OffPos))
175 const MachineOperand &MO = MI.getOperand(OffPos);
178 int64_t Offset = MO.getImm() + Disp;
179 return isValidLoadStoreOffset(Offset);
182 bool ARCOptAddrMode::noUseOfAddBeforeLoadOrStore(const MachineInstr *Add,
183 const MachineInstr *Ldst) {
184 unsigned R = Add->getOperand(0).getReg();
185 return dominatesAllUsesOf(Ldst, R, MDT, MRI);
188 MachineInstr *ARCOptAddrMode::tryToCombine(MachineInstr &Ldst) {
189 assert((Ldst.mayLoad() || Ldst.mayStore()) && "LD/ST instruction expected");
191 unsigned BasePos, OffsetPos;
193 LLVM_DEBUG(dbgs() << "[ABAW] tryToCombine " << Ldst);
194 if (!AII->getBaseAndOffsetPosition(Ldst, BasePos, OffsetPos)) {
195 LLVM_DEBUG(dbgs() << "[ABAW] Not a recognized load/store\n");
199 MachineOperand &Base = Ldst.getOperand(BasePos);
200 MachineOperand &Offset = Ldst.getOperand(OffsetPos);
202 assert(Base.isReg() && "Base operand must be register");
203 if (!Offset.isImm()) {
204 LLVM_DEBUG(dbgs() << "[ABAW] Offset is not immediate\n");
208 unsigned B = Base.getReg();
209 if (TargetRegisterInfo::isStackSlot(B) ||
210 !TargetRegisterInfo::isVirtualRegister(B)) {
211 LLVM_DEBUG(dbgs() << "[ABAW] Base is not VReg\n");
215 // TODO: try to generate address preincrement
216 if (Offset.getImm() != 0) {
217 LLVM_DEBUG(dbgs() << "[ABAW] Non-zero offset\n");
221 for (auto &Add : MRI->use_nodbg_instructions(B)) {
223 if (!isAddConstantOp(Add, Incr))
225 if (!isValidLoadStoreOffset(Incr))
228 SmallVector<MachineInstr *, 8> Uses;
229 MachineInstr *MoveTo = canJoinInstructions(&Ldst, &Add, &Uses);
234 if (!canFixPastUses(Uses, Add.getOperand(2), B))
237 LLVM_DEBUG(MachineInstr *First = &Ldst; MachineInstr *Last = &Add;
238 if (MDT->dominates(Last, First)) std::swap(First, Last);
239 dbgs() << "[ABAW] Instructions " << *First << " and " << *Last
244 MachineInstr *Result = Ldst.getNextNode();
245 if (MoveTo == &Add) {
246 Ldst.removeFromParent();
247 Add.getParent()->insertAfter(Add.getIterator(), &Ldst);
250 Result = Result->getNextNode();
252 fixPastUses(Uses, B, Incr);
254 int NewOpcode = ARC::getPostIncOpcode(Ldst.getOpcode());
255 assert(NewOpcode > 0 && "No postincrement form found");
256 unsigned NewBaseReg = Add.getOperand(0).getReg();
257 changeToAddrMode(Ldst, NewOpcode, NewBaseReg, Add.getOperand(2));
258 Add.eraseFromParent();
266 ARCOptAddrMode::canJoinInstructions(MachineInstr *Ldst, MachineInstr *Add,
267 SmallVectorImpl<MachineInstr *> *Uses) {
268 assert(Ldst && Add && "NULL instruction passed");
270 MachineInstr *First = Add;
271 MachineInstr *Last = Ldst;
272 if (MDT->dominates(Ldst, Add))
273 std::swap(First, Last);
274 else if (!MDT->dominates(Add, Ldst))
277 LLVM_DEBUG(dbgs() << "canJoinInstructions: " << *First << *Last);
279 unsigned BasePos, OffPos;
281 if (!AII->getBaseAndOffsetPosition(*Ldst, BasePos, OffPos)) {
284 << "[canJoinInstructions] Cannot determine base/offset position\n");
288 unsigned BaseReg = Ldst->getOperand(BasePos).getReg();
296 if (Ldst->mayStore() && Ldst->getOperand(0).isReg()) {
297 unsigned StReg = Ldst->getOperand(0).getReg();
298 if (Add->getOperand(0).getReg() == StReg || BaseReg == StReg) {
299 LLVM_DEBUG(dbgs() << "[canJoinInstructions] Store uses result of Add\n");
304 SmallVector<MachineInstr *, 4> UsesAfterLdst;
305 SmallVector<MachineInstr *, 4> UsesAfterAdd;
306 for (MachineInstr &MI : MRI->use_nodbg_instructions(BaseReg)) {
307 if (&MI == Ldst || &MI == Add)
309 if (&MI != Add && MDT->dominates(Ldst, &MI))
310 UsesAfterLdst.push_back(&MI);
311 else if (!MDT->dominates(&MI, Ldst))
313 if (MDT->dominates(Add, &MI))
314 UsesAfterAdd.push_back(&MI);
317 MachineInstr *Result = nullptr;
322 // x = ld [b, o] or x = ld [n, o]
324 if (noUseOfAddBeforeLoadOrStore(First, Last)) {
326 LLVM_DEBUG(dbgs() << "[canJoinInstructions] Can sink Add down to Ldst\n");
327 } else if (canHoistLoadStoreTo(Ldst, Add)) {
329 LLVM_DEBUG(dbgs() << "[canJoinInstructions] Can hoist Ldst to Add\n");
336 LLVM_DEBUG(dbgs() << "[canJoinInstructions] Can hoist Add to Ldst\n");
339 *Uses = (Result == Ldst) ? UsesAfterLdst : UsesAfterAdd;
343 bool ARCOptAddrMode::canFixPastUses(const ArrayRef<MachineInstr *> &Uses,
344 MachineOperand &Incr, unsigned BaseReg) {
346 assert(Incr.isImm() && "Expected immediate increment");
347 int64_t NewOffset = Incr.getImm();
348 for (MachineInstr *MI : Uses) {
350 if (isAddConstantOp(*MI, Dummy)) {
351 if (isValidIncrementOffset(Dummy + NewOffset))
355 if (isLoadStoreThatCanHandleDisplacement(AII, *MI, -NewOffset))
357 LLVM_DEBUG(dbgs() << "Instruction cannot handle displacement " << -NewOffset
364 void ARCOptAddrMode::fixPastUses(ArrayRef<MachineInstr *> Uses,
365 unsigned NewBase, int64_t NewOffset) {
367 for (MachineInstr *MI : Uses) {
369 unsigned BasePos, OffPos;
370 if (isAddConstantOp(*MI, Amount)) {
372 assert(isValidIncrementOffset(NewOffset) &&
373 "New offset won't fit into ADD instr");
376 } else if (AII->getBaseAndOffsetPosition(*MI, BasePos, OffPos)) {
377 MachineOperand &MO = MI->getOperand(OffPos);
378 assert(MO.isImm() && "expected immediate operand");
379 NewOffset += MO.getImm();
380 assert(isValidLoadStoreOffset(NewOffset) &&
381 "New offset won't fit into LD/ST");
383 llvm_unreachable("unexpected instruction");
385 MI->getOperand(BasePos).setReg(NewBase);
386 MI->getOperand(OffPos).setImm(NewOffset);
390 bool ARCOptAddrMode::canHoistLoadStoreTo(MachineInstr *Ldst, MachineInstr *To) {
391 if (Ldst->getParent() != To->getParent())
393 MachineBasicBlock::const_iterator MI(To), ME(Ldst),
394 End(Ldst->getParent()->end());
396 bool IsStore = Ldst->mayStore();
397 for (; MI != ME && MI != End; ++MI) {
398 if (MI->isDebugValue())
400 if (MI->mayStore() || MI->isCall() || MI->isInlineAsm() ||
401 MI->hasUnmodeledSideEffects())
403 if (IsStore && MI->mayLoad())
407 for (auto &O : Ldst->explicit_operands()) {
408 if (!O.isReg() || !O.isUse())
410 MachineInstr *OpDef = MRI->getVRegDef(O.getReg());
411 if (!OpDef || !MDT->dominates(OpDef, To))
417 bool ARCOptAddrMode::canSinkLoadStoreTo(MachineInstr *Ldst, MachineInstr *To) {
418 // Can only sink load/store within same BB
419 if (Ldst->getParent() != To->getParent())
421 MachineBasicBlock::const_iterator MI(Ldst), ME(To),
422 End(Ldst->getParent()->end());
424 bool IsStore = Ldst->mayStore();
425 bool IsLoad = Ldst->mayLoad();
427 Register ValReg = IsLoad ? Ldst->getOperand(0).getReg() : Register();
428 for (; MI != ME && MI != End; ++MI) {
429 if (MI->isDebugValue())
431 if (MI->mayStore() || MI->isCall() || MI->isInlineAsm() ||
432 MI->hasUnmodeledSideEffects())
434 if (IsStore && MI->mayLoad())
436 if (ValReg && MI->readsVirtualRegister(ValReg))
442 void ARCOptAddrMode::changeToAddrMode(MachineInstr &Ldst, unsigned NewOpcode,
444 MachineOperand &NewOffset) {
445 bool IsStore = Ldst.mayStore();
446 unsigned BasePos, OffPos;
447 MachineOperand Src = MachineOperand::CreateImm(0xDEADBEEF);
448 AII->getBaseAndOffsetPosition(Ldst, BasePos, OffPos);
450 unsigned BaseReg = Ldst.getOperand(BasePos).getReg();
452 Ldst.RemoveOperand(OffPos);
453 Ldst.RemoveOperand(BasePos);
456 Src = Ldst.getOperand(BasePos - 1);
457 Ldst.RemoveOperand(BasePos - 1);
460 Ldst.setDesc(AST->getInstrInfo()->get(NewOpcode));
461 Ldst.addOperand(MachineOperand::CreateReg(NewBase, true));
463 Ldst.addOperand(Src);
464 Ldst.addOperand(MachineOperand::CreateReg(BaseReg, false));
465 Ldst.addOperand(NewOffset);
466 LLVM_DEBUG(dbgs() << "[ABAW] New Ldst: " << Ldst);
469 bool ARCOptAddrMode::processBasicBlock(MachineBasicBlock &MBB) {
470 bool Changed = false;
471 for (auto MI = MBB.begin(), ME = MBB.end(); MI != ME; ++MI) {
472 if (MI->isDebugValue())
474 if (!MI->mayLoad() && !MI->mayStore())
476 if (ARC::getPostIncOpcode(MI->getOpcode()) < 0)
478 MachineInstr *Res = tryToCombine(*MI);
481 // Res points to the next instruction. Rewind to process it
482 MI = std::prev(Res->getIterator());
488 bool ARCOptAddrMode::runOnMachineFunction(MachineFunction &MF) {
489 if (skipFunction(MF.getFunction()))
492 AST = &MF.getSubtarget<ARCSubtarget>();
493 AII = AST->getInstrInfo();
494 MRI = &MF.getRegInfo();
495 MDT = &getAnalysis<MachineDominatorTree>();
497 bool Changed = false;
499 Changed |= processBasicBlock(MBB);
503 //===----------------------------------------------------------------------===//
504 // Public Constructor Functions
505 //===----------------------------------------------------------------------===//
507 FunctionPass *llvm::createARCOptAddrMode() { return new ARCOptAddrMode(); }