Path: blob/main/contrib/llvm-project/llvm/lib/Target/ARC/ARCOptAddrMode.cpp
35294 views
//===- ARCOptAddrMode.cpp ---------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8/// \file9/// This pass folds LD/ST + ADD pairs into Pre/Post-increment form of10/// load/store instructions.11//===----------------------------------------------------------------------===//1213#include "ARC.h"14#define GET_INSTRMAP_INFO15#include "ARCInstrInfo.h"16#include "ARCTargetMachine.h"17#include "llvm/CodeGen/MachineBasicBlock.h"18#include "llvm/CodeGen/MachineDominators.h"19#include "llvm/CodeGen/MachineFunctionPass.h"20#include "llvm/CodeGen/MachineInstr.h"21#include "llvm/CodeGen/MachineInstrBuilder.h"22#include "llvm/CodeGen/TargetRegisterInfo.h"23#include "llvm/IR/Function.h"24#include "llvm/InitializePasses.h"25#include "llvm/Support/CommandLine.h"26#include "llvm/Support/Debug.h"27#include "llvm/Support/raw_ostream.h"2829using namespace llvm;3031#define OPTADDRMODE_DESC "ARC load/store address mode"32#define OPTADDRMODE_NAME "arc-addr-mode"33#define DEBUG_TYPE "arc-addr-mode"3435namespace llvm {3637static cl::opt<unsigned> ArcKillAddrMode("arc-kill-addr-mode", cl::init(0),38cl::ReallyHidden);3940#define DUMP_BEFORE() ((ArcKillAddrMode & 0x0001) != 0)41#define DUMP_AFTER() ((ArcKillAddrMode & 0x0002) != 0)42#define VIEW_BEFORE() ((ArcKillAddrMode & 0x0004) != 0)43#define VIEW_AFTER() ((ArcKillAddrMode & 0x0008) != 0)44#define KILL_PASS() ((ArcKillAddrMode & 0x0010) != 0)4546FunctionPass *createARCOptAddrMode();47void initializeARCOptAddrModePass(PassRegistry &);48} // end namespace llvm4950namespace {51class ARCOptAddrMode : public MachineFunctionPass {52public:53static char ID;5455ARCOptAddrMode() : MachineFunctionPass(ID) {}5657StringRef getPassName() const override { return OPTADDRMODE_DESC; }5859void getAnalysisUsage(AnalysisUsage &AU) const override {60AU.setPreservesCFG();61MachineFunctionPass::getAnalysisUsage(AU);62AU.addRequired<MachineDominatorTreeWrapperPass>();63AU.addPreserved<MachineDominatorTreeWrapperPass>();64}6566bool runOnMachineFunction(MachineFunction &MF) override;6768private:69const ARCSubtarget *AST = nullptr;70const ARCInstrInfo *AII = nullptr;71MachineRegisterInfo *MRI = nullptr;72MachineDominatorTree *MDT = nullptr;7374// Tries to combine \p Ldst with increment of its base register to form75// single post-increment instruction.76MachineInstr *tryToCombine(MachineInstr &Ldst);7778// Returns true if result of \p Add is not used before \p Ldst79bool noUseOfAddBeforeLoadOrStore(const MachineInstr *Add,80const MachineInstr *Ldst);8182// Returns true if load/store instruction \p Ldst can be hoisted up to83// instruction \p To84bool canHoistLoadStoreTo(MachineInstr *Ldst, MachineInstr *To);8586// // Returns true if load/store instruction \p Ldst can be sunk down87// // to instruction \p To88// bool canSinkLoadStoreTo(MachineInstr *Ldst, MachineInstr *To);8990// Check if instructions \p Ldst and \p Add can be moved to become adjacent91// If they can return instruction which need not to move.92// If \p Uses is not null, fill it with instructions after \p Ldst which use93// \p Ldst's base register94MachineInstr *canJoinInstructions(MachineInstr *Ldst, MachineInstr *Add,95SmallVectorImpl<MachineInstr *> *Uses);9697// Returns true if all instruction in \p Uses array can be adjusted98// to accomodate increment of register \p BaseReg by \p Incr99bool canFixPastUses(const ArrayRef<MachineInstr *> &Uses,100MachineOperand &Incr, unsigned BaseReg);101102// Update all instructions in \p Uses to accomodate increment103// of \p BaseReg by \p Offset104void fixPastUses(ArrayRef<MachineInstr *> Uses, unsigned BaseReg,105int64_t Offset);106107// Change instruction \p Ldst to postincrement form.108// \p NewBase is register to hold update base value109// \p NewOffset is instruction's new offset110void changeToAddrMode(MachineInstr &Ldst, unsigned NewOpcode,111unsigned NewBase, MachineOperand &NewOffset);112113bool processBasicBlock(MachineBasicBlock &MBB);114};115116} // end anonymous namespace117118char ARCOptAddrMode::ID = 0;119INITIALIZE_PASS_BEGIN(ARCOptAddrMode, OPTADDRMODE_NAME, OPTADDRMODE_DESC, false,120false)121INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)122INITIALIZE_PASS_END(ARCOptAddrMode, OPTADDRMODE_NAME, OPTADDRMODE_DESC, false,123false)124125// Return true if \p Off can be used as immediate offset126// operand of load/store instruction (S9 literal)127static bool isValidLoadStoreOffset(int64_t Off) { return isInt<9>(Off); }128129// Return true if \p Off can be used as immediate operand of130// ADD/SUB instruction (U6 literal)131static bool isValidIncrementOffset(int64_t Off) { return isUInt<6>(Off); }132133static bool isAddConstantOp(const MachineInstr &MI, int64_t &Amount) {134int64_t Sign = 1;135switch (MI.getOpcode()) {136case ARC::SUB_rru6:137Sign = -1;138[[fallthrough]];139case ARC::ADD_rru6:140assert(MI.getOperand(2).isImm() && "Expected immediate operand");141Amount = Sign * MI.getOperand(2).getImm();142return true;143default:144return false;145}146}147148// Return true if \p MI dominates of uses of virtual register \p VReg149static bool dominatesAllUsesOf(const MachineInstr *MI, unsigned VReg,150MachineDominatorTree *MDT,151MachineRegisterInfo *MRI) {152153assert(Register::isVirtualRegister(VReg) && "Expected virtual register!");154155for (const MachineOperand &Use : MRI->use_nodbg_operands(VReg)) {156const MachineInstr *User = Use.getParent();157if (User->isPHI()) {158unsigned BBOperandIdx = Use.getOperandNo() + 1;159MachineBasicBlock *MBB = User->getOperand(BBOperandIdx).getMBB();160if (MBB->empty()) {161const MachineBasicBlock *InstBB = MI->getParent();162assert(InstBB != MBB && "Instruction found in empty MBB");163if (!MDT->dominates(InstBB, MBB))164return false;165continue;166}167User = &*MBB->rbegin();168}169170if (!MDT->dominates(MI, User))171return false;172}173return true;174}175176// Return true if \p MI is load/store instruction with immediate offset177// which can be adjusted by \p Disp178static bool isLoadStoreThatCanHandleDisplacement(const TargetInstrInfo *TII,179const MachineInstr &MI,180int64_t Disp) {181unsigned BasePos, OffPos;182if (!TII->getBaseAndOffsetPosition(MI, BasePos, OffPos))183return false;184const MachineOperand &MO = MI.getOperand(OffPos);185if (!MO.isImm())186return false;187int64_t Offset = MO.getImm() + Disp;188return isValidLoadStoreOffset(Offset);189}190191bool ARCOptAddrMode::noUseOfAddBeforeLoadOrStore(const MachineInstr *Add,192const MachineInstr *Ldst) {193Register R = Add->getOperand(0).getReg();194return dominatesAllUsesOf(Ldst, R, MDT, MRI);195}196197MachineInstr *ARCOptAddrMode::tryToCombine(MachineInstr &Ldst) {198assert(Ldst.mayLoadOrStore() && "LD/ST instruction expected");199200unsigned BasePos, OffsetPos;201202LLVM_DEBUG(dbgs() << "[ABAW] tryToCombine " << Ldst);203if (!AII->getBaseAndOffsetPosition(Ldst, BasePos, OffsetPos)) {204LLVM_DEBUG(dbgs() << "[ABAW] Not a recognized load/store\n");205return nullptr;206}207208MachineOperand &Base = Ldst.getOperand(BasePos);209MachineOperand &Offset = Ldst.getOperand(OffsetPos);210211assert(Base.isReg() && "Base operand must be register");212if (!Offset.isImm()) {213LLVM_DEBUG(dbgs() << "[ABAW] Offset is not immediate\n");214return nullptr;215}216217Register B = Base.getReg();218if (Register::isStackSlot(B) || !Register::isVirtualRegister(B)) {219LLVM_DEBUG(dbgs() << "[ABAW] Base is not VReg\n");220return nullptr;221}222223// TODO: try to generate address preincrement224if (Offset.getImm() != 0) {225LLVM_DEBUG(dbgs() << "[ABAW] Non-zero offset\n");226return nullptr;227}228229for (auto &Add : MRI->use_nodbg_instructions(B)) {230int64_t Incr;231if (!isAddConstantOp(Add, Incr))232continue;233if (!isValidLoadStoreOffset(Incr))234continue;235236SmallVector<MachineInstr *, 8> Uses;237MachineInstr *MoveTo = canJoinInstructions(&Ldst, &Add, &Uses);238239if (!MoveTo)240continue;241242if (!canFixPastUses(Uses, Add.getOperand(2), B))243continue;244245LLVM_DEBUG(MachineInstr *First = &Ldst; MachineInstr *Last = &Add;246if (MDT->dominates(Last, First)) std::swap(First, Last);247dbgs() << "[ABAW] Instructions " << *First << " and " << *Last248<< " combined\n";249250);251252MachineInstr *Result = Ldst.getNextNode();253if (MoveTo == &Add) {254Ldst.removeFromParent();255Add.getParent()->insertAfter(Add.getIterator(), &Ldst);256}257if (Result == &Add)258Result = Result->getNextNode();259260fixPastUses(Uses, B, Incr);261262int NewOpcode = ARC::getPostIncOpcode(Ldst.getOpcode());263assert(NewOpcode > 0 && "No postincrement form found");264unsigned NewBaseReg = Add.getOperand(0).getReg();265changeToAddrMode(Ldst, NewOpcode, NewBaseReg, Add.getOperand(2));266Add.eraseFromParent();267268return Result;269}270return nullptr;271}272273MachineInstr *274ARCOptAddrMode::canJoinInstructions(MachineInstr *Ldst, MachineInstr *Add,275SmallVectorImpl<MachineInstr *> *Uses) {276assert(Ldst && Add && "NULL instruction passed");277278MachineInstr *First = Add;279MachineInstr *Last = Ldst;280if (MDT->dominates(Ldst, Add))281std::swap(First, Last);282else if (!MDT->dominates(Add, Ldst))283return nullptr;284285LLVM_DEBUG(dbgs() << "canJoinInstructions: " << *First << *Last);286287unsigned BasePos, OffPos;288289if (!AII->getBaseAndOffsetPosition(*Ldst, BasePos, OffPos)) {290LLVM_DEBUG(291dbgs()292<< "[canJoinInstructions] Cannot determine base/offset position\n");293return nullptr;294}295296Register BaseReg = Ldst->getOperand(BasePos).getReg();297298// prohibit this:299// v1 = add v0, c300// st v1, [v0, 0]301// and this302// st v0, [v0, 0]303// v1 = add v0, c304if (Ldst->mayStore() && Ldst->getOperand(0).isReg()) {305Register StReg = Ldst->getOperand(0).getReg();306if (Add->getOperand(0).getReg() == StReg || BaseReg == StReg) {307LLVM_DEBUG(dbgs() << "[canJoinInstructions] Store uses result of Add\n");308return nullptr;309}310}311312SmallVector<MachineInstr *, 4> UsesAfterLdst;313SmallVector<MachineInstr *, 4> UsesAfterAdd;314for (MachineInstr &MI : MRI->use_nodbg_instructions(BaseReg)) {315if (&MI == Ldst || &MI == Add)316continue;317if (&MI != Add && MDT->dominates(Ldst, &MI))318UsesAfterLdst.push_back(&MI);319else if (!MDT->dominates(&MI, Ldst))320return nullptr;321if (MDT->dominates(Add, &MI))322UsesAfterAdd.push_back(&MI);323}324325MachineInstr *Result = nullptr;326327if (First == Add) {328// n = add b, i329// ...330// x = ld [b, o] or x = ld [n, o]331332if (noUseOfAddBeforeLoadOrStore(First, Last)) {333Result = Last;334LLVM_DEBUG(dbgs() << "[canJoinInstructions] Can sink Add down to Ldst\n");335} else if (canHoistLoadStoreTo(Ldst, Add)) {336Result = First;337LLVM_DEBUG(dbgs() << "[canJoinInstructions] Can hoist Ldst to Add\n");338}339} else {340// x = ld [b, o]341// ...342// n = add b, i343Result = First;344LLVM_DEBUG(dbgs() << "[canJoinInstructions] Can hoist Add to Ldst\n");345}346if (Result && Uses)347*Uses = (Result == Ldst) ? UsesAfterLdst : UsesAfterAdd;348return Result;349}350351bool ARCOptAddrMode::canFixPastUses(const ArrayRef<MachineInstr *> &Uses,352MachineOperand &Incr, unsigned BaseReg) {353354assert(Incr.isImm() && "Expected immediate increment");355int64_t NewOffset = Incr.getImm();356for (MachineInstr *MI : Uses) {357int64_t Dummy;358if (isAddConstantOp(*MI, Dummy)) {359if (isValidIncrementOffset(Dummy + NewOffset))360continue;361return false;362}363if (isLoadStoreThatCanHandleDisplacement(AII, *MI, -NewOffset))364continue;365LLVM_DEBUG(dbgs() << "Instruction cannot handle displacement " << -NewOffset366<< ": " << *MI);367return false;368}369return true;370}371372void ARCOptAddrMode::fixPastUses(ArrayRef<MachineInstr *> Uses,373unsigned NewBase, int64_t NewOffset) {374375for (MachineInstr *MI : Uses) {376int64_t Amount;377unsigned BasePos, OffPos;378if (isAddConstantOp(*MI, Amount)) {379NewOffset += Amount;380assert(isValidIncrementOffset(NewOffset) &&381"New offset won't fit into ADD instr");382BasePos = 1;383OffPos = 2;384} else if (AII->getBaseAndOffsetPosition(*MI, BasePos, OffPos)) {385MachineOperand &MO = MI->getOperand(OffPos);386assert(MO.isImm() && "expected immediate operand");387NewOffset += MO.getImm();388assert(isValidLoadStoreOffset(NewOffset) &&389"New offset won't fit into LD/ST");390} else391llvm_unreachable("unexpected instruction");392393MI->getOperand(BasePos).setReg(NewBase);394MI->getOperand(OffPos).setImm(NewOffset);395}396}397398bool ARCOptAddrMode::canHoistLoadStoreTo(MachineInstr *Ldst, MachineInstr *To) {399if (Ldst->getParent() != To->getParent())400return false;401MachineBasicBlock::const_iterator MI(To), ME(Ldst),402End(Ldst->getParent()->end());403404bool IsStore = Ldst->mayStore();405for (; MI != ME && MI != End; ++MI) {406if (MI->isDebugValue())407continue;408if (MI->mayStore() || MI->isCall() || MI->isInlineAsm() ||409MI->hasUnmodeledSideEffects())410return false;411if (IsStore && MI->mayLoad())412return false;413}414415for (auto &O : Ldst->explicit_operands()) {416if (!O.isReg() || !O.isUse())417continue;418MachineInstr *OpDef = MRI->getVRegDef(O.getReg());419if (!OpDef || !MDT->dominates(OpDef, To))420return false;421}422return true;423}424425// bool ARCOptAddrMode::canSinkLoadStoreTo(MachineInstr *Ldst, MachineInstr *To) {426// // Can only sink load/store within same BB427// if (Ldst->getParent() != To->getParent())428// return false;429// MachineBasicBlock::const_iterator MI(Ldst), ME(To),430// End(Ldst->getParent()->end());431432// bool IsStore = Ldst->mayStore();433// bool IsLoad = Ldst->mayLoad();434435// Register ValReg = IsLoad ? Ldst->getOperand(0).getReg() : Register();436// for (; MI != ME && MI != End; ++MI) {437// if (MI->isDebugValue())438// continue;439// if (MI->mayStore() || MI->isCall() || MI->isInlineAsm() ||440// MI->hasUnmodeledSideEffects())441// return false;442// if (IsStore && MI->mayLoad())443// return false;444// if (ValReg && MI->readsVirtualRegister(ValReg))445// return false;446// }447// return true;448// }449450void ARCOptAddrMode::changeToAddrMode(MachineInstr &Ldst, unsigned NewOpcode,451unsigned NewBase,452MachineOperand &NewOffset) {453bool IsStore = Ldst.mayStore();454unsigned BasePos, OffPos;455MachineOperand Src = MachineOperand::CreateImm(0xDEADBEEF);456AII->getBaseAndOffsetPosition(Ldst, BasePos, OffPos);457458Register BaseReg = Ldst.getOperand(BasePos).getReg();459460Ldst.removeOperand(OffPos);461Ldst.removeOperand(BasePos);462463if (IsStore) {464Src = Ldst.getOperand(BasePos - 1);465Ldst.removeOperand(BasePos - 1);466}467468Ldst.setDesc(AST->getInstrInfo()->get(NewOpcode));469Ldst.addOperand(MachineOperand::CreateReg(NewBase, true));470if (IsStore)471Ldst.addOperand(Src);472Ldst.addOperand(MachineOperand::CreateReg(BaseReg, false));473Ldst.addOperand(NewOffset);474LLVM_DEBUG(dbgs() << "[ABAW] New Ldst: " << Ldst);475}476477bool ARCOptAddrMode::processBasicBlock(MachineBasicBlock &MBB) {478bool Changed = false;479for (auto MI = MBB.begin(), ME = MBB.end(); MI != ME; ++MI) {480if (MI->isDebugValue())481continue;482if (!MI->mayLoad() && !MI->mayStore())483continue;484if (ARC::getPostIncOpcode(MI->getOpcode()) < 0)485continue;486MachineInstr *Res = tryToCombine(*MI);487if (Res) {488Changed = true;489// Res points to the next instruction. Rewind to process it490MI = std::prev(Res->getIterator());491}492}493return Changed;494}495496bool ARCOptAddrMode::runOnMachineFunction(MachineFunction &MF) {497if (skipFunction(MF.getFunction()) || KILL_PASS())498return false;499500#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)501if (DUMP_BEFORE())502MF.dump();503#endif504if (VIEW_BEFORE())505MF.viewCFG();506507AST = &MF.getSubtarget<ARCSubtarget>();508AII = AST->getInstrInfo();509MRI = &MF.getRegInfo();510MDT = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();511512bool Changed = false;513for (auto &MBB : MF)514Changed |= processBasicBlock(MBB);515516#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)517if (DUMP_AFTER())518MF.dump();519#endif520if (VIEW_AFTER())521MF.viewCFG();522return Changed;523}524525//===----------------------------------------------------------------------===//526// Public Constructor Functions527//===----------------------------------------------------------------------===//528529FunctionPass *llvm::createARCOptAddrMode() { return new ARCOptAddrMode(); }530531532