181ad6265SDimitry Andric //===- R600MachineCFGStructurizer.cpp - CFG Structurizer ------------------===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //==-----------------------------------------------------------------------===// 881ad6265SDimitry Andric 981ad6265SDimitry Andric #include "MCTargetDesc/R600MCTargetDesc.h" 1081ad6265SDimitry Andric #include "R600.h" 1181ad6265SDimitry Andric #include "R600RegisterInfo.h" 1281ad6265SDimitry Andric #include "R600Subtarget.h" 1381ad6265SDimitry Andric #include "llvm/ADT/DepthFirstIterator.h" 1481ad6265SDimitry Andric #include "llvm/ADT/SCCIterator.h" 1581ad6265SDimitry Andric #include "llvm/ADT/Statistic.h" 1681ad6265SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 1781ad6265SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 1881ad6265SDimitry Andric #include "llvm/CodeGen/MachineJumpTableInfo.h" 1981ad6265SDimitry Andric #include "llvm/CodeGen/MachineLoopInfo.h" 2081ad6265SDimitry Andric #include "llvm/CodeGen/MachinePostDominators.h" 2181ad6265SDimitry Andric #include "llvm/InitializePasses.h" 2281ad6265SDimitry Andric 2381ad6265SDimitry Andric using namespace llvm; 2481ad6265SDimitry Andric 2581ad6265SDimitry Andric #define DEBUG_TYPE "structcfg" 2681ad6265SDimitry Andric 27*0fca6ea1SDimitry Andric enum { DEFAULT_VEC_SLOTS = 8 }; 2881ad6265SDimitry Andric 2981ad6265SDimitry Andric // TODO: move-begin. 3081ad6265SDimitry Andric 3181ad6265SDimitry Andric //===----------------------------------------------------------------------===// 3281ad6265SDimitry Andric // 3381ad6265SDimitry Andric // Statistics for CFGStructurizer. 3481ad6265SDimitry Andric // 3581ad6265SDimitry Andric //===----------------------------------------------------------------------===// 3681ad6265SDimitry Andric 3781ad6265SDimitry Andric STATISTIC(numSerialPatternMatch, "CFGStructurizer number of serial pattern " 3881ad6265SDimitry Andric "matched"); 3981ad6265SDimitry Andric STATISTIC(numIfPatternMatch, "CFGStructurizer number of if pattern " 4081ad6265SDimitry Andric "matched"); 4181ad6265SDimitry Andric STATISTIC(numClonedBlock, "CFGStructurizer cloned blocks"); 4281ad6265SDimitry Andric STATISTIC(numClonedInstr, "CFGStructurizer cloned instructions"); 4381ad6265SDimitry Andric 4481ad6265SDimitry Andric namespace llvm { 4581ad6265SDimitry Andric 4681ad6265SDimitry Andric void initializeR600MachineCFGStructurizerPass(PassRegistry &); 4781ad6265SDimitry Andric 4881ad6265SDimitry Andric } // end namespace llvm 4981ad6265SDimitry Andric 5081ad6265SDimitry Andric namespace { 5181ad6265SDimitry Andric 5281ad6265SDimitry Andric //===----------------------------------------------------------------------===// 5381ad6265SDimitry Andric // 5481ad6265SDimitry Andric // Miscellaneous utility for CFGStructurizer. 5581ad6265SDimitry Andric // 5681ad6265SDimitry Andric //===----------------------------------------------------------------------===// 5781ad6265SDimitry Andric 5881ad6265SDimitry Andric #define SHOWNEWINSTR(i) LLVM_DEBUG(dbgs() << "New instr: " << *i << "\n"); 5981ad6265SDimitry Andric 6081ad6265SDimitry Andric #define SHOWNEWBLK(b, msg) \ 6181ad6265SDimitry Andric LLVM_DEBUG(dbgs() << msg << "BB" << b->getNumber() << "size " << b->size(); \ 6281ad6265SDimitry Andric dbgs() << "\n";); 6381ad6265SDimitry Andric 6481ad6265SDimitry Andric #define SHOWBLK_DETAIL(b, msg) \ 6581ad6265SDimitry Andric LLVM_DEBUG(if (b) { \ 6681ad6265SDimitry Andric dbgs() << msg << "BB" << b->getNumber() << "size " << b->size(); \ 6781ad6265SDimitry Andric b->print(dbgs()); \ 6881ad6265SDimitry Andric dbgs() << "\n"; \ 6981ad6265SDimitry Andric }); 7081ad6265SDimitry Andric 7181ad6265SDimitry Andric #define INVALIDSCCNUM -1 7281ad6265SDimitry Andric 7381ad6265SDimitry Andric //===----------------------------------------------------------------------===// 7481ad6265SDimitry Andric // 7581ad6265SDimitry Andric // supporting data structure for CFGStructurizer 7681ad6265SDimitry Andric // 7781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 7881ad6265SDimitry Andric 7981ad6265SDimitry Andric class BlockInformation { 8081ad6265SDimitry Andric public: 8181ad6265SDimitry Andric bool IsRetired = false; 8281ad6265SDimitry Andric int SccNum = INVALIDSCCNUM; 8381ad6265SDimitry Andric 8481ad6265SDimitry Andric BlockInformation() = default; 8581ad6265SDimitry Andric }; 8681ad6265SDimitry Andric 8781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 8881ad6265SDimitry Andric // 8981ad6265SDimitry Andric // CFGStructurizer 9081ad6265SDimitry Andric // 9181ad6265SDimitry Andric //===----------------------------------------------------------------------===// 9281ad6265SDimitry Andric 9381ad6265SDimitry Andric class R600MachineCFGStructurizer : public MachineFunctionPass { 9481ad6265SDimitry Andric public: 9581ad6265SDimitry Andric using MBBVector = SmallVector<MachineBasicBlock *, 32>; 9681ad6265SDimitry Andric using MBBInfoMap = std::map<MachineBasicBlock *, BlockInformation *>; 9781ad6265SDimitry Andric using LoopLandInfoMap = std::map<MachineLoop *, MachineBasicBlock *>; 9881ad6265SDimitry Andric 9981ad6265SDimitry Andric enum PathToKind { 10081ad6265SDimitry Andric Not_SinglePath = 0, 10181ad6265SDimitry Andric SinglePath_InPath = 1, 10281ad6265SDimitry Andric SinglePath_NotInPath = 2 10381ad6265SDimitry Andric }; 10481ad6265SDimitry Andric 10581ad6265SDimitry Andric static char ID; 10681ad6265SDimitry Andric 10781ad6265SDimitry Andric R600MachineCFGStructurizer() : MachineFunctionPass(ID) { 10881ad6265SDimitry Andric initializeR600MachineCFGStructurizerPass(*PassRegistry::getPassRegistry()); 10981ad6265SDimitry Andric } 11081ad6265SDimitry Andric 11181ad6265SDimitry Andric StringRef getPassName() const override { 11281ad6265SDimitry Andric return "AMDGPU Control Flow Graph structurizer Pass"; 11381ad6265SDimitry Andric } 11481ad6265SDimitry Andric 11581ad6265SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 116*0fca6ea1SDimitry Andric AU.addRequired<MachineDominatorTreeWrapperPass>(); 117*0fca6ea1SDimitry Andric AU.addRequired<MachinePostDominatorTreeWrapperPass>(); 118*0fca6ea1SDimitry Andric AU.addRequired<MachineLoopInfoWrapperPass>(); 11981ad6265SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 12081ad6265SDimitry Andric } 12181ad6265SDimitry Andric 12281ad6265SDimitry Andric /// Perform the CFG structurization 12381ad6265SDimitry Andric bool run(); 12481ad6265SDimitry Andric 12581ad6265SDimitry Andric /// Perform the CFG preparation 12681ad6265SDimitry Andric /// This step will remove every unconditionnal/dead jump instructions and make 12781ad6265SDimitry Andric /// sure all loops have an exit block 12881ad6265SDimitry Andric bool prepare(); 12981ad6265SDimitry Andric 13081ad6265SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override { 13181ad6265SDimitry Andric // FIXME: This pass causes verification failures. 13281ad6265SDimitry Andric MF.getProperties().set( 13381ad6265SDimitry Andric MachineFunctionProperties::Property::FailsVerification); 13481ad6265SDimitry Andric 13581ad6265SDimitry Andric TII = MF.getSubtarget<R600Subtarget>().getInstrInfo(); 13681ad6265SDimitry Andric TRI = &TII->getRegisterInfo(); 13781ad6265SDimitry Andric LLVM_DEBUG(MF.dump();); 13881ad6265SDimitry Andric OrderedBlks.clear(); 13981ad6265SDimitry Andric Visited.clear(); 14081ad6265SDimitry Andric FuncRep = &MF; 141*0fca6ea1SDimitry Andric MLI = &getAnalysis<MachineLoopInfoWrapperPass>().getLI(); 14281ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "LoopInfo:\n"; PrintLoopinfo(*MLI);); 143*0fca6ea1SDimitry Andric MDT = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree(); 144*0fca6ea1SDimitry Andric LLVM_DEBUG(MDT->print(dbgs());); 145*0fca6ea1SDimitry Andric PDT = &getAnalysis<MachinePostDominatorTreeWrapperPass>().getPostDomTree(); 14681ad6265SDimitry Andric LLVM_DEBUG(PDT->print(dbgs());); 14781ad6265SDimitry Andric prepare(); 14881ad6265SDimitry Andric run(); 14981ad6265SDimitry Andric LLVM_DEBUG(MF.dump();); 15081ad6265SDimitry Andric return true; 15181ad6265SDimitry Andric } 15281ad6265SDimitry Andric 15381ad6265SDimitry Andric protected: 15481ad6265SDimitry Andric MachineDominatorTree *MDT; 15581ad6265SDimitry Andric MachinePostDominatorTree *PDT; 15681ad6265SDimitry Andric MachineLoopInfo *MLI; 15781ad6265SDimitry Andric const R600InstrInfo *TII = nullptr; 15881ad6265SDimitry Andric const R600RegisterInfo *TRI = nullptr; 15981ad6265SDimitry Andric 16081ad6265SDimitry Andric // PRINT FUNCTIONS 16181ad6265SDimitry Andric /// Print the ordered Blocks. 16281ad6265SDimitry Andric void printOrderedBlocks() const { 16381ad6265SDimitry Andric size_t i = 0; 16481ad6265SDimitry Andric for (MBBVector::const_iterator iterBlk = OrderedBlks.begin(), 16581ad6265SDimitry Andric iterBlkEnd = OrderedBlks.end(); iterBlk != iterBlkEnd; ++iterBlk, ++i) { 16681ad6265SDimitry Andric dbgs() << "BB" << (*iterBlk)->getNumber(); 16781ad6265SDimitry Andric dbgs() << "(" << getSCCNum(*iterBlk) << "," << (*iterBlk)->size() << ")"; 16881ad6265SDimitry Andric if (i != 0 && i % 10 == 0) { 16981ad6265SDimitry Andric dbgs() << "\n"; 17081ad6265SDimitry Andric } else { 17181ad6265SDimitry Andric dbgs() << " "; 17281ad6265SDimitry Andric } 17381ad6265SDimitry Andric } 17481ad6265SDimitry Andric } 17581ad6265SDimitry Andric 17681ad6265SDimitry Andric static void PrintLoopinfo(const MachineLoopInfo &LoopInfo) { 17781ad6265SDimitry Andric for (const MachineLoop *L : LoopInfo) 17881ad6265SDimitry Andric L->print(dbgs()); 17981ad6265SDimitry Andric } 18081ad6265SDimitry Andric 18181ad6265SDimitry Andric // UTILITY FUNCTIONS 18281ad6265SDimitry Andric int getSCCNum(MachineBasicBlock *MBB) const; 18381ad6265SDimitry Andric MachineBasicBlock *getLoopLandInfo(MachineLoop *LoopRep) const; 18481ad6265SDimitry Andric bool hasBackEdge(MachineBasicBlock *MBB) const; 18581ad6265SDimitry Andric bool isRetiredBlock(MachineBasicBlock *MBB) const; 18681ad6265SDimitry Andric bool isActiveLoophead(MachineBasicBlock *MBB) const; 18781ad6265SDimitry Andric PathToKind singlePathTo(MachineBasicBlock *SrcMBB, MachineBasicBlock *DstMBB, 18881ad6265SDimitry Andric bool AllowSideEntry = true) const; 18981ad6265SDimitry Andric int countActiveBlock(MBBVector::const_iterator It, 19081ad6265SDimitry Andric MBBVector::const_iterator E) const; 19181ad6265SDimitry Andric bool needMigrateBlock(MachineBasicBlock *MBB) const; 19281ad6265SDimitry Andric 19381ad6265SDimitry Andric // Utility Functions 19481ad6265SDimitry Andric void reversePredicateSetter(MachineBasicBlock::iterator I, 19581ad6265SDimitry Andric MachineBasicBlock &MBB); 19681ad6265SDimitry Andric /// Compute the reversed DFS post order of Blocks 19781ad6265SDimitry Andric void orderBlocks(MachineFunction *MF); 19881ad6265SDimitry Andric 19981ad6265SDimitry Andric // Function originally from CFGStructTraits 20081ad6265SDimitry Andric void insertInstrEnd(MachineBasicBlock *MBB, int NewOpcode, 20181ad6265SDimitry Andric const DebugLoc &DL = DebugLoc()); 20281ad6265SDimitry Andric MachineInstr *insertInstrBefore(MachineBasicBlock *MBB, int NewOpcode, 20381ad6265SDimitry Andric const DebugLoc &DL = DebugLoc()); 20481ad6265SDimitry Andric MachineInstr *insertInstrBefore(MachineBasicBlock::iterator I, int NewOpcode); 20581ad6265SDimitry Andric void insertCondBranchBefore(MachineBasicBlock::iterator I, int NewOpcode, 20681ad6265SDimitry Andric const DebugLoc &DL); 20781ad6265SDimitry Andric void insertCondBranchBefore(MachineBasicBlock *MBB, 20881ad6265SDimitry Andric MachineBasicBlock::iterator I, int NewOpcode, 20981ad6265SDimitry Andric int RegNum, const DebugLoc &DL); 21081ad6265SDimitry Andric 21181ad6265SDimitry Andric static int getBranchNzeroOpcode(int OldOpcode); 21281ad6265SDimitry Andric static int getBranchZeroOpcode(int OldOpcode); 21381ad6265SDimitry Andric static int getContinueNzeroOpcode(int OldOpcode); 21481ad6265SDimitry Andric static int getContinueZeroOpcode(int OldOpcode); 21581ad6265SDimitry Andric static MachineBasicBlock *getTrueBranch(MachineInstr *MI); 21681ad6265SDimitry Andric static void setTrueBranch(MachineInstr *MI, MachineBasicBlock *MBB); 21781ad6265SDimitry Andric static MachineBasicBlock *getFalseBranch(MachineBasicBlock *MBB, 21881ad6265SDimitry Andric MachineInstr *MI); 21981ad6265SDimitry Andric static bool isCondBranch(MachineInstr *MI); 22081ad6265SDimitry Andric static bool isUncondBranch(MachineInstr *MI); 22181ad6265SDimitry Andric static DebugLoc getLastDebugLocInBB(MachineBasicBlock *MBB); 22281ad6265SDimitry Andric static MachineInstr *getNormalBlockBranchInstr(MachineBasicBlock *MBB); 22381ad6265SDimitry Andric 22481ad6265SDimitry Andric /// The correct naming for this is getPossibleLoopendBlockBranchInstr. 22581ad6265SDimitry Andric /// 22681ad6265SDimitry Andric /// BB with backward-edge could have move instructions after the branch 22781ad6265SDimitry Andric /// instruction. Such move instruction "belong to" the loop backward-edge. 22881ad6265SDimitry Andric MachineInstr *getLoopendBlockBranchInstr(MachineBasicBlock *MBB); 22981ad6265SDimitry Andric 23081ad6265SDimitry Andric static MachineInstr *getReturnInstr(MachineBasicBlock *MBB); 23181ad6265SDimitry Andric static bool isReturnBlock(MachineBasicBlock *MBB); 23281ad6265SDimitry Andric static void cloneSuccessorList(MachineBasicBlock *DstMBB, 23381ad6265SDimitry Andric MachineBasicBlock *SrcMBB); 23481ad6265SDimitry Andric static MachineBasicBlock *clone(MachineBasicBlock *MBB); 23581ad6265SDimitry Andric 23681ad6265SDimitry Andric /// MachineBasicBlock::ReplaceUsesOfBlockWith doesn't serve the purpose 23781ad6265SDimitry Andric /// because the AMDGPU instruction is not recognized as terminator fix this 23881ad6265SDimitry Andric /// and retire this routine 23981ad6265SDimitry Andric void replaceInstrUseOfBlockWith(MachineBasicBlock *SrcMBB, 24081ad6265SDimitry Andric MachineBasicBlock *OldMBB, MachineBasicBlock *NewBlk); 24181ad6265SDimitry Andric 24281ad6265SDimitry Andric static void wrapup(MachineBasicBlock *MBB); 24381ad6265SDimitry Andric 24481ad6265SDimitry Andric int patternMatch(MachineBasicBlock *MBB); 24581ad6265SDimitry Andric int patternMatchGroup(MachineBasicBlock *MBB); 24681ad6265SDimitry Andric int serialPatternMatch(MachineBasicBlock *MBB); 24781ad6265SDimitry Andric int ifPatternMatch(MachineBasicBlock *MBB); 24881ad6265SDimitry Andric int loopendPatternMatch(); 24981ad6265SDimitry Andric int mergeLoop(MachineLoop *LoopRep); 25081ad6265SDimitry Andric 25181ad6265SDimitry Andric /// return true iff src1Blk->succ_empty() && src1Blk and src2Blk are in 25281ad6265SDimitry Andric /// the same loop with LoopLandInfo without explicitly keeping track of 25381ad6265SDimitry Andric /// loopContBlks and loopBreakBlks, this is a method to get the information. 25481ad6265SDimitry Andric bool isSameloopDetachedContbreak(MachineBasicBlock *Src1MBB, 25581ad6265SDimitry Andric MachineBasicBlock *Src2MBB); 25681ad6265SDimitry Andric int handleJumpintoIf(MachineBasicBlock *HeadMBB, 25781ad6265SDimitry Andric MachineBasicBlock *TrueMBB, MachineBasicBlock *FalseMBB); 25881ad6265SDimitry Andric int handleJumpintoIfImp(MachineBasicBlock *HeadMBB, 25981ad6265SDimitry Andric MachineBasicBlock *TrueMBB, MachineBasicBlock *FalseMBB); 26081ad6265SDimitry Andric int improveSimpleJumpintoIf(MachineBasicBlock *HeadMBB, 26181ad6265SDimitry Andric MachineBasicBlock *TrueMBB, MachineBasicBlock *FalseMBB, 26281ad6265SDimitry Andric MachineBasicBlock **LandMBBPtr); 26381ad6265SDimitry Andric void showImproveSimpleJumpintoIf(MachineBasicBlock *HeadMBB, 26481ad6265SDimitry Andric MachineBasicBlock *TrueMBB, MachineBasicBlock *FalseMBB, 26581ad6265SDimitry Andric MachineBasicBlock *LandMBB, bool Detail = false); 26681ad6265SDimitry Andric int cloneOnSideEntryTo(MachineBasicBlock *PreMBB, 26781ad6265SDimitry Andric MachineBasicBlock *SrcMBB, MachineBasicBlock *DstMBB); 26881ad6265SDimitry Andric void mergeSerialBlock(MachineBasicBlock *DstMBB, 26981ad6265SDimitry Andric MachineBasicBlock *SrcMBB); 27081ad6265SDimitry Andric 27181ad6265SDimitry Andric void mergeIfthenelseBlock(MachineInstr *BranchMI, 27281ad6265SDimitry Andric MachineBasicBlock *MBB, MachineBasicBlock *TrueMBB, 27381ad6265SDimitry Andric MachineBasicBlock *FalseMBB, MachineBasicBlock *LandMBB); 27481ad6265SDimitry Andric void mergeLooplandBlock(MachineBasicBlock *DstMBB, 27581ad6265SDimitry Andric MachineBasicBlock *LandMBB); 27681ad6265SDimitry Andric void mergeLoopbreakBlock(MachineBasicBlock *ExitingMBB, 27781ad6265SDimitry Andric MachineBasicBlock *LandMBB); 27881ad6265SDimitry Andric void settleLoopcontBlock(MachineBasicBlock *ContingMBB, 27981ad6265SDimitry Andric MachineBasicBlock *ContMBB); 28081ad6265SDimitry Andric 28181ad6265SDimitry Andric /// normalizeInfiniteLoopExit change 28281ad6265SDimitry Andric /// B1: 28381ad6265SDimitry Andric /// uncond_br LoopHeader 28481ad6265SDimitry Andric /// 28581ad6265SDimitry Andric /// to 28681ad6265SDimitry Andric /// B1: 28781ad6265SDimitry Andric /// cond_br 1 LoopHeader dummyExit 28881ad6265SDimitry Andric /// and return the newly added dummy exit block 28981ad6265SDimitry Andric MachineBasicBlock *normalizeInfiniteLoopExit(MachineLoop *LoopRep); 29081ad6265SDimitry Andric void removeUnconditionalBranch(MachineBasicBlock *MBB); 29181ad6265SDimitry Andric 29281ad6265SDimitry Andric /// Remove duplicate branches instructions in a block. 29381ad6265SDimitry Andric /// For instance 29481ad6265SDimitry Andric /// B0: 29581ad6265SDimitry Andric /// cond_br X B1 B2 29681ad6265SDimitry Andric /// cond_br X B1 B2 29781ad6265SDimitry Andric /// is transformed to 29881ad6265SDimitry Andric /// B0: 29981ad6265SDimitry Andric /// cond_br X B1 B2 30081ad6265SDimitry Andric void removeRedundantConditionalBranch(MachineBasicBlock *MBB); 30181ad6265SDimitry Andric 30281ad6265SDimitry Andric void addDummyExitBlock(SmallVectorImpl<MachineBasicBlock *> &RetMBB); 30381ad6265SDimitry Andric void removeSuccessor(MachineBasicBlock *MBB); 30481ad6265SDimitry Andric MachineBasicBlock *cloneBlockForPredecessor(MachineBasicBlock *MBB, 30581ad6265SDimitry Andric MachineBasicBlock *PredMBB); 30681ad6265SDimitry Andric void migrateInstruction(MachineBasicBlock *SrcMBB, 30781ad6265SDimitry Andric MachineBasicBlock *DstMBB, MachineBasicBlock::iterator I); 30881ad6265SDimitry Andric void recordSccnum(MachineBasicBlock *MBB, int SCCNum); 30981ad6265SDimitry Andric void retireBlock(MachineBasicBlock *MBB); 31081ad6265SDimitry Andric 31181ad6265SDimitry Andric private: 31281ad6265SDimitry Andric MBBInfoMap BlockInfoMap; 31381ad6265SDimitry Andric LoopLandInfoMap LLInfoMap; 31481ad6265SDimitry Andric std::map<MachineLoop *, bool> Visited; 31581ad6265SDimitry Andric MachineFunction *FuncRep; 31681ad6265SDimitry Andric SmallVector<MachineBasicBlock *, DEFAULT_VEC_SLOTS> OrderedBlks; 31781ad6265SDimitry Andric }; 31881ad6265SDimitry Andric 31981ad6265SDimitry Andric } // end anonymous namespace 32081ad6265SDimitry Andric 32181ad6265SDimitry Andric char R600MachineCFGStructurizer::ID = 0; 32281ad6265SDimitry Andric 32381ad6265SDimitry Andric int R600MachineCFGStructurizer::getSCCNum(MachineBasicBlock *MBB) const { 32481ad6265SDimitry Andric MBBInfoMap::const_iterator It = BlockInfoMap.find(MBB); 32581ad6265SDimitry Andric if (It == BlockInfoMap.end()) 32681ad6265SDimitry Andric return INVALIDSCCNUM; 32781ad6265SDimitry Andric return (*It).second->SccNum; 32881ad6265SDimitry Andric } 32981ad6265SDimitry Andric 33081ad6265SDimitry Andric MachineBasicBlock *R600MachineCFGStructurizer::getLoopLandInfo(MachineLoop *LoopRep) 33181ad6265SDimitry Andric const { 33281ad6265SDimitry Andric LoopLandInfoMap::const_iterator It = LLInfoMap.find(LoopRep); 33381ad6265SDimitry Andric if (It == LLInfoMap.end()) 33481ad6265SDimitry Andric return nullptr; 33581ad6265SDimitry Andric return (*It).second; 33681ad6265SDimitry Andric } 33781ad6265SDimitry Andric 33881ad6265SDimitry Andric bool R600MachineCFGStructurizer::hasBackEdge(MachineBasicBlock *MBB) const { 33981ad6265SDimitry Andric MachineLoop *LoopRep = MLI->getLoopFor(MBB); 34081ad6265SDimitry Andric if (!LoopRep) 34181ad6265SDimitry Andric return false; 34281ad6265SDimitry Andric MachineBasicBlock *LoopHeader = LoopRep->getHeader(); 34381ad6265SDimitry Andric return MBB->isSuccessor(LoopHeader); 34481ad6265SDimitry Andric } 34581ad6265SDimitry Andric 34681ad6265SDimitry Andric bool R600MachineCFGStructurizer::isRetiredBlock(MachineBasicBlock *MBB) const { 34781ad6265SDimitry Andric MBBInfoMap::const_iterator It = BlockInfoMap.find(MBB); 34881ad6265SDimitry Andric if (It == BlockInfoMap.end()) 34981ad6265SDimitry Andric return false; 35081ad6265SDimitry Andric return (*It).second->IsRetired; 35181ad6265SDimitry Andric } 35281ad6265SDimitry Andric 35381ad6265SDimitry Andric bool R600MachineCFGStructurizer::isActiveLoophead(MachineBasicBlock *MBB) const { 35481ad6265SDimitry Andric MachineLoop *LoopRep = MLI->getLoopFor(MBB); 35581ad6265SDimitry Andric while (LoopRep && LoopRep->getHeader() == MBB) { 35681ad6265SDimitry Andric MachineBasicBlock *LoopLand = getLoopLandInfo(LoopRep); 35781ad6265SDimitry Andric if(!LoopLand) 35881ad6265SDimitry Andric return true; 35981ad6265SDimitry Andric if (!isRetiredBlock(LoopLand)) 36081ad6265SDimitry Andric return true; 36181ad6265SDimitry Andric LoopRep = LoopRep->getParentLoop(); 36281ad6265SDimitry Andric } 36381ad6265SDimitry Andric return false; 36481ad6265SDimitry Andric } 36581ad6265SDimitry Andric 36681ad6265SDimitry Andric R600MachineCFGStructurizer::PathToKind R600MachineCFGStructurizer::singlePathTo( 36781ad6265SDimitry Andric MachineBasicBlock *SrcMBB, MachineBasicBlock *DstMBB, 36881ad6265SDimitry Andric bool AllowSideEntry) const { 36981ad6265SDimitry Andric assert(DstMBB); 37081ad6265SDimitry Andric if (SrcMBB == DstMBB) 37181ad6265SDimitry Andric return SinglePath_InPath; 37281ad6265SDimitry Andric while (SrcMBB && SrcMBB->succ_size() == 1) { 37381ad6265SDimitry Andric SrcMBB = *SrcMBB->succ_begin(); 37481ad6265SDimitry Andric if (SrcMBB == DstMBB) 37581ad6265SDimitry Andric return SinglePath_InPath; 37681ad6265SDimitry Andric if (!AllowSideEntry && SrcMBB->pred_size() > 1) 37781ad6265SDimitry Andric return Not_SinglePath; 37881ad6265SDimitry Andric } 37981ad6265SDimitry Andric if (SrcMBB && SrcMBB->succ_size()==0) 38081ad6265SDimitry Andric return SinglePath_NotInPath; 38181ad6265SDimitry Andric return Not_SinglePath; 38281ad6265SDimitry Andric } 38381ad6265SDimitry Andric 38481ad6265SDimitry Andric int R600MachineCFGStructurizer::countActiveBlock(MBBVector::const_iterator It, 38581ad6265SDimitry Andric MBBVector::const_iterator E) const { 38681ad6265SDimitry Andric int Count = 0; 38781ad6265SDimitry Andric while (It != E) { 38881ad6265SDimitry Andric if (!isRetiredBlock(*It)) 38981ad6265SDimitry Andric ++Count; 39081ad6265SDimitry Andric ++It; 39181ad6265SDimitry Andric } 39281ad6265SDimitry Andric return Count; 39381ad6265SDimitry Andric } 39481ad6265SDimitry Andric 39581ad6265SDimitry Andric bool R600MachineCFGStructurizer::needMigrateBlock(MachineBasicBlock *MBB) const { 39681ad6265SDimitry Andric unsigned BlockSizeThreshold = 30; 39781ad6265SDimitry Andric unsigned CloneInstrThreshold = 100; 39881ad6265SDimitry Andric bool MultiplePreds = MBB && (MBB->pred_size() > 1); 39981ad6265SDimitry Andric 40081ad6265SDimitry Andric if(!MultiplePreds) 40181ad6265SDimitry Andric return false; 40281ad6265SDimitry Andric unsigned BlkSize = MBB->size(); 40381ad6265SDimitry Andric return ((BlkSize > BlockSizeThreshold) && 40481ad6265SDimitry Andric (BlkSize * (MBB->pred_size() - 1) > CloneInstrThreshold)); 40581ad6265SDimitry Andric } 40681ad6265SDimitry Andric 40781ad6265SDimitry Andric void R600MachineCFGStructurizer::reversePredicateSetter( 40881ad6265SDimitry Andric MachineBasicBlock::iterator I, MachineBasicBlock &MBB) { 40981ad6265SDimitry Andric assert(I.isValid() && "Expected valid iterator"); 41081ad6265SDimitry Andric for (;; --I) { 41181ad6265SDimitry Andric if (I == MBB.end()) 41281ad6265SDimitry Andric continue; 41381ad6265SDimitry Andric if (I->getOpcode() == R600::PRED_X) { 41481ad6265SDimitry Andric switch (I->getOperand(2).getImm()) { 41581ad6265SDimitry Andric case R600::PRED_SETE_INT: 41681ad6265SDimitry Andric I->getOperand(2).setImm(R600::PRED_SETNE_INT); 41781ad6265SDimitry Andric return; 41881ad6265SDimitry Andric case R600::PRED_SETNE_INT: 41981ad6265SDimitry Andric I->getOperand(2).setImm(R600::PRED_SETE_INT); 42081ad6265SDimitry Andric return; 42181ad6265SDimitry Andric case R600::PRED_SETE: 42281ad6265SDimitry Andric I->getOperand(2).setImm(R600::PRED_SETNE); 42381ad6265SDimitry Andric return; 42481ad6265SDimitry Andric case R600::PRED_SETNE: 42581ad6265SDimitry Andric I->getOperand(2).setImm(R600::PRED_SETE); 42681ad6265SDimitry Andric return; 42781ad6265SDimitry Andric default: 42881ad6265SDimitry Andric llvm_unreachable("PRED_X Opcode invalid!"); 42981ad6265SDimitry Andric } 43081ad6265SDimitry Andric } 43181ad6265SDimitry Andric } 43281ad6265SDimitry Andric } 43381ad6265SDimitry Andric 43481ad6265SDimitry Andric void R600MachineCFGStructurizer::insertInstrEnd(MachineBasicBlock *MBB, 43581ad6265SDimitry Andric int NewOpcode, const DebugLoc &DL) { 43681ad6265SDimitry Andric MachineInstr *MI = 43781ad6265SDimitry Andric MBB->getParent()->CreateMachineInstr(TII->get(NewOpcode), DL); 43881ad6265SDimitry Andric MBB->push_back(MI); 43981ad6265SDimitry Andric //assume the instruction doesn't take any reg operand ... 44081ad6265SDimitry Andric SHOWNEWINSTR(MI); 44181ad6265SDimitry Andric } 44281ad6265SDimitry Andric 44381ad6265SDimitry Andric MachineInstr *R600MachineCFGStructurizer::insertInstrBefore(MachineBasicBlock *MBB, 44481ad6265SDimitry Andric int NewOpcode, 44581ad6265SDimitry Andric const DebugLoc &DL) { 44681ad6265SDimitry Andric MachineInstr *MI = 44781ad6265SDimitry Andric MBB->getParent()->CreateMachineInstr(TII->get(NewOpcode), DL); 44881ad6265SDimitry Andric if (!MBB->empty()) 44981ad6265SDimitry Andric MBB->insert(MBB->begin(), MI); 45081ad6265SDimitry Andric else 45181ad6265SDimitry Andric MBB->push_back(MI); 45281ad6265SDimitry Andric SHOWNEWINSTR(MI); 45381ad6265SDimitry Andric return MI; 45481ad6265SDimitry Andric } 45581ad6265SDimitry Andric 45681ad6265SDimitry Andric MachineInstr *R600MachineCFGStructurizer::insertInstrBefore( 45781ad6265SDimitry Andric MachineBasicBlock::iterator I, int NewOpcode) { 45881ad6265SDimitry Andric MachineInstr *OldMI = &(*I); 45981ad6265SDimitry Andric MachineBasicBlock *MBB = OldMI->getParent(); 46081ad6265SDimitry Andric MachineInstr *NewMBB = 46181ad6265SDimitry Andric MBB->getParent()->CreateMachineInstr(TII->get(NewOpcode), DebugLoc()); 46281ad6265SDimitry Andric MBB->insert(I, NewMBB); 46381ad6265SDimitry Andric //assume the instruction doesn't take any reg operand ... 46481ad6265SDimitry Andric SHOWNEWINSTR(NewMBB); 46581ad6265SDimitry Andric return NewMBB; 46681ad6265SDimitry Andric } 46781ad6265SDimitry Andric 46881ad6265SDimitry Andric void R600MachineCFGStructurizer::insertCondBranchBefore( 46981ad6265SDimitry Andric MachineBasicBlock::iterator I, int NewOpcode, const DebugLoc &DL) { 47081ad6265SDimitry Andric MachineInstr *OldMI = &(*I); 47181ad6265SDimitry Andric MachineBasicBlock *MBB = OldMI->getParent(); 47281ad6265SDimitry Andric MachineFunction *MF = MBB->getParent(); 47381ad6265SDimitry Andric MachineInstr *NewMI = MF->CreateMachineInstr(TII->get(NewOpcode), DL); 47481ad6265SDimitry Andric MBB->insert(I, NewMI); 47581ad6265SDimitry Andric MachineInstrBuilder MIB(*MF, NewMI); 47681ad6265SDimitry Andric MIB.addReg(OldMI->getOperand(1).getReg(), false); 47781ad6265SDimitry Andric SHOWNEWINSTR(NewMI); 47881ad6265SDimitry Andric //erase later oldInstr->eraseFromParent(); 47981ad6265SDimitry Andric } 48081ad6265SDimitry Andric 48181ad6265SDimitry Andric void R600MachineCFGStructurizer::insertCondBranchBefore( 48281ad6265SDimitry Andric MachineBasicBlock *blk, MachineBasicBlock::iterator I, int NewOpcode, 48381ad6265SDimitry Andric int RegNum, const DebugLoc &DL) { 48481ad6265SDimitry Andric MachineFunction *MF = blk->getParent(); 48581ad6265SDimitry Andric MachineInstr *NewInstr = MF->CreateMachineInstr(TII->get(NewOpcode), DL); 48681ad6265SDimitry Andric //insert before 48781ad6265SDimitry Andric blk->insert(I, NewInstr); 48881ad6265SDimitry Andric MachineInstrBuilder(*MF, NewInstr).addReg(RegNum, false); 48981ad6265SDimitry Andric SHOWNEWINSTR(NewInstr); 49081ad6265SDimitry Andric } 49181ad6265SDimitry Andric 49281ad6265SDimitry Andric int R600MachineCFGStructurizer::getBranchNzeroOpcode(int OldOpcode) { 49381ad6265SDimitry Andric switch(OldOpcode) { 49481ad6265SDimitry Andric case R600::JUMP_COND: 49581ad6265SDimitry Andric case R600::JUMP: return R600::IF_PREDICATE_SET; 49681ad6265SDimitry Andric case R600::BRANCH_COND_i32: 49781ad6265SDimitry Andric case R600::BRANCH_COND_f32: return R600::IF_LOGICALNZ_f32; 49881ad6265SDimitry Andric default: llvm_unreachable("internal error"); 49981ad6265SDimitry Andric } 50081ad6265SDimitry Andric return -1; 50181ad6265SDimitry Andric } 50281ad6265SDimitry Andric 50381ad6265SDimitry Andric int R600MachineCFGStructurizer::getBranchZeroOpcode(int OldOpcode) { 50481ad6265SDimitry Andric switch(OldOpcode) { 50581ad6265SDimitry Andric case R600::JUMP_COND: 50681ad6265SDimitry Andric case R600::JUMP: return R600::IF_PREDICATE_SET; 50781ad6265SDimitry Andric case R600::BRANCH_COND_i32: 50881ad6265SDimitry Andric case R600::BRANCH_COND_f32: return R600::IF_LOGICALZ_f32; 50981ad6265SDimitry Andric default: llvm_unreachable("internal error"); 51081ad6265SDimitry Andric } 51181ad6265SDimitry Andric return -1; 51281ad6265SDimitry Andric } 51381ad6265SDimitry Andric 51481ad6265SDimitry Andric int R600MachineCFGStructurizer::getContinueNzeroOpcode(int OldOpcode) { 51581ad6265SDimitry Andric switch(OldOpcode) { 51681ad6265SDimitry Andric case R600::JUMP_COND: 51781ad6265SDimitry Andric case R600::JUMP: return R600::CONTINUE_LOGICALNZ_i32; 51881ad6265SDimitry Andric default: llvm_unreachable("internal error"); 51981ad6265SDimitry Andric } 52081ad6265SDimitry Andric return -1; 52181ad6265SDimitry Andric } 52281ad6265SDimitry Andric 52381ad6265SDimitry Andric int R600MachineCFGStructurizer::getContinueZeroOpcode(int OldOpcode) { 52481ad6265SDimitry Andric switch(OldOpcode) { 52581ad6265SDimitry Andric case R600::JUMP_COND: 52681ad6265SDimitry Andric case R600::JUMP: return R600::CONTINUE_LOGICALZ_i32; 52781ad6265SDimitry Andric default: llvm_unreachable("internal error"); 52881ad6265SDimitry Andric } 52981ad6265SDimitry Andric return -1; 53081ad6265SDimitry Andric } 53181ad6265SDimitry Andric 53281ad6265SDimitry Andric MachineBasicBlock *R600MachineCFGStructurizer::getTrueBranch(MachineInstr *MI) { 53381ad6265SDimitry Andric return MI->getOperand(0).getMBB(); 53481ad6265SDimitry Andric } 53581ad6265SDimitry Andric 53681ad6265SDimitry Andric void R600MachineCFGStructurizer::setTrueBranch(MachineInstr *MI, 53781ad6265SDimitry Andric MachineBasicBlock *MBB) { 53881ad6265SDimitry Andric MI->getOperand(0).setMBB(MBB); 53981ad6265SDimitry Andric } 54081ad6265SDimitry Andric 54181ad6265SDimitry Andric MachineBasicBlock * 54281ad6265SDimitry Andric R600MachineCFGStructurizer::getFalseBranch(MachineBasicBlock *MBB, 54381ad6265SDimitry Andric MachineInstr *MI) { 54481ad6265SDimitry Andric assert(MBB->succ_size() == 2); 54581ad6265SDimitry Andric MachineBasicBlock *TrueBranch = getTrueBranch(MI); 54681ad6265SDimitry Andric MachineBasicBlock::succ_iterator It = MBB->succ_begin(); 54781ad6265SDimitry Andric MachineBasicBlock::succ_iterator Next = It; 54881ad6265SDimitry Andric ++Next; 54981ad6265SDimitry Andric return (*It == TrueBranch) ? *Next : *It; 55081ad6265SDimitry Andric } 55181ad6265SDimitry Andric 55281ad6265SDimitry Andric bool R600MachineCFGStructurizer::isCondBranch(MachineInstr *MI) { 55381ad6265SDimitry Andric switch (MI->getOpcode()) { 55481ad6265SDimitry Andric case R600::JUMP_COND: 55581ad6265SDimitry Andric case R600::BRANCH_COND_i32: 55681ad6265SDimitry Andric case R600::BRANCH_COND_f32: return true; 55781ad6265SDimitry Andric default: 55881ad6265SDimitry Andric return false; 55981ad6265SDimitry Andric } 56081ad6265SDimitry Andric return false; 56181ad6265SDimitry Andric } 56281ad6265SDimitry Andric 56381ad6265SDimitry Andric bool R600MachineCFGStructurizer::isUncondBranch(MachineInstr *MI) { 56481ad6265SDimitry Andric switch (MI->getOpcode()) { 56581ad6265SDimitry Andric case R600::JUMP: 56681ad6265SDimitry Andric case R600::BRANCH: 56781ad6265SDimitry Andric return true; 56881ad6265SDimitry Andric default: 56981ad6265SDimitry Andric return false; 57081ad6265SDimitry Andric } 57181ad6265SDimitry Andric return false; 57281ad6265SDimitry Andric } 57381ad6265SDimitry Andric 57481ad6265SDimitry Andric DebugLoc R600MachineCFGStructurizer::getLastDebugLocInBB(MachineBasicBlock *MBB) { 57581ad6265SDimitry Andric //get DebugLoc from the first MachineBasicBlock instruction with debug info 57681ad6265SDimitry Andric DebugLoc DL; 57781ad6265SDimitry Andric for (MachineInstr &MI : *MBB) 57881ad6265SDimitry Andric if (MI.getDebugLoc()) 57981ad6265SDimitry Andric DL = MI.getDebugLoc(); 58081ad6265SDimitry Andric return DL; 58181ad6265SDimitry Andric } 58281ad6265SDimitry Andric 58381ad6265SDimitry Andric MachineInstr *R600MachineCFGStructurizer::getNormalBlockBranchInstr( 58481ad6265SDimitry Andric MachineBasicBlock *MBB) { 58581ad6265SDimitry Andric MachineBasicBlock::reverse_iterator It = MBB->rbegin(); 58681ad6265SDimitry Andric MachineInstr *MI = &*It; 58781ad6265SDimitry Andric if (MI && (isCondBranch(MI) || isUncondBranch(MI))) 58881ad6265SDimitry Andric return MI; 58981ad6265SDimitry Andric return nullptr; 59081ad6265SDimitry Andric } 59181ad6265SDimitry Andric 59281ad6265SDimitry Andric MachineInstr *R600MachineCFGStructurizer::getLoopendBlockBranchInstr( 59381ad6265SDimitry Andric MachineBasicBlock *MBB) { 59481ad6265SDimitry Andric for (MachineBasicBlock::reverse_iterator It = MBB->rbegin(), E = MBB->rend(); 59581ad6265SDimitry Andric It != E; ++It) { 59681ad6265SDimitry Andric // FIXME: Simplify 59781ad6265SDimitry Andric MachineInstr *MI = &*It; 59881ad6265SDimitry Andric if (MI) { 59981ad6265SDimitry Andric if (isCondBranch(MI) || isUncondBranch(MI)) 60081ad6265SDimitry Andric return MI; 601*0fca6ea1SDimitry Andric if (!TII->isMov(MI->getOpcode())) 60281ad6265SDimitry Andric break; 60381ad6265SDimitry Andric } 60481ad6265SDimitry Andric } 60581ad6265SDimitry Andric return nullptr; 60681ad6265SDimitry Andric } 60781ad6265SDimitry Andric 60881ad6265SDimitry Andric MachineInstr *R600MachineCFGStructurizer::getReturnInstr(MachineBasicBlock *MBB) { 60981ad6265SDimitry Andric MachineBasicBlock::reverse_iterator It = MBB->rbegin(); 61081ad6265SDimitry Andric if (It != MBB->rend()) { 61181ad6265SDimitry Andric MachineInstr *instr = &(*It); 61281ad6265SDimitry Andric if (instr->getOpcode() == R600::RETURN) 61381ad6265SDimitry Andric return instr; 61481ad6265SDimitry Andric } 61581ad6265SDimitry Andric return nullptr; 61681ad6265SDimitry Andric } 61781ad6265SDimitry Andric 61881ad6265SDimitry Andric bool R600MachineCFGStructurizer::isReturnBlock(MachineBasicBlock *MBB) { 61981ad6265SDimitry Andric MachineInstr *MI = getReturnInstr(MBB); 62081ad6265SDimitry Andric bool IsReturn = MBB->succ_empty(); 62181ad6265SDimitry Andric if (MI) 62281ad6265SDimitry Andric assert(IsReturn); 62381ad6265SDimitry Andric else if (IsReturn) 62481ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "BB" << MBB->getNumber() 62581ad6265SDimitry Andric << " is return block without RETURN instr\n";); 62681ad6265SDimitry Andric return IsReturn; 62781ad6265SDimitry Andric } 62881ad6265SDimitry Andric 62981ad6265SDimitry Andric void R600MachineCFGStructurizer::cloneSuccessorList(MachineBasicBlock *DstMBB, 63081ad6265SDimitry Andric MachineBasicBlock *SrcMBB) { 63181ad6265SDimitry Andric for (MachineBasicBlock *Succ : SrcMBB->successors()) 63281ad6265SDimitry Andric DstMBB->addSuccessor(Succ); // *iter's predecessor is also taken care of 63381ad6265SDimitry Andric } 63481ad6265SDimitry Andric 63581ad6265SDimitry Andric MachineBasicBlock *R600MachineCFGStructurizer::clone(MachineBasicBlock *MBB) { 63681ad6265SDimitry Andric MachineFunction *Func = MBB->getParent(); 63781ad6265SDimitry Andric MachineBasicBlock *NewMBB = Func->CreateMachineBasicBlock(); 63881ad6265SDimitry Andric Func->push_back(NewMBB); //insert to function 63981ad6265SDimitry Andric for (const MachineInstr &It : *MBB) 64081ad6265SDimitry Andric NewMBB->push_back(Func->CloneMachineInstr(&It)); 64181ad6265SDimitry Andric return NewMBB; 64281ad6265SDimitry Andric } 64381ad6265SDimitry Andric 64481ad6265SDimitry Andric void R600MachineCFGStructurizer::replaceInstrUseOfBlockWith( 64581ad6265SDimitry Andric MachineBasicBlock *SrcMBB, MachineBasicBlock *OldMBB, 64681ad6265SDimitry Andric MachineBasicBlock *NewBlk) { 64781ad6265SDimitry Andric MachineInstr *BranchMI = getLoopendBlockBranchInstr(SrcMBB); 64881ad6265SDimitry Andric if (BranchMI && isCondBranch(BranchMI) && 64981ad6265SDimitry Andric getTrueBranch(BranchMI) == OldMBB) 65081ad6265SDimitry Andric setTrueBranch(BranchMI, NewBlk); 65181ad6265SDimitry Andric } 65281ad6265SDimitry Andric 65381ad6265SDimitry Andric void R600MachineCFGStructurizer::wrapup(MachineBasicBlock *MBB) { 65481ad6265SDimitry Andric assert((!MBB->getParent()->getJumpTableInfo() 65581ad6265SDimitry Andric || MBB->getParent()->getJumpTableInfo()->isEmpty()) 65681ad6265SDimitry Andric && "found a jump table"); 65781ad6265SDimitry Andric 65881ad6265SDimitry Andric //collect continue right before endloop 65981ad6265SDimitry Andric SmallVector<MachineInstr *, DEFAULT_VEC_SLOTS> ContInstr; 66081ad6265SDimitry Andric MachineBasicBlock::iterator Pre = MBB->begin(); 66181ad6265SDimitry Andric MachineBasicBlock::iterator E = MBB->end(); 66281ad6265SDimitry Andric MachineBasicBlock::iterator It = Pre; 66381ad6265SDimitry Andric while (It != E) { 66481ad6265SDimitry Andric if (Pre->getOpcode() == R600::CONTINUE 66581ad6265SDimitry Andric && It->getOpcode() == R600::ENDLOOP) 66681ad6265SDimitry Andric ContInstr.push_back(&*Pre); 66781ad6265SDimitry Andric Pre = It; 66881ad6265SDimitry Andric ++It; 66981ad6265SDimitry Andric } 67081ad6265SDimitry Andric 67181ad6265SDimitry Andric //delete continue right before endloop 672*0fca6ea1SDimitry Andric for (auto *MI : ContInstr) 673*0fca6ea1SDimitry Andric MI->eraseFromParent(); 67481ad6265SDimitry Andric 67581ad6265SDimitry Andric // TODO to fix up jump table so later phase won't be confused. if 67681ad6265SDimitry Andric // (jumpTableInfo->isEmpty() == false) { need to clean the jump table, but 67781ad6265SDimitry Andric // there isn't such an interface yet. alternatively, replace all the other 67881ad6265SDimitry Andric // blocks in the jump table with the entryBlk //} 67981ad6265SDimitry Andric } 68081ad6265SDimitry Andric 68181ad6265SDimitry Andric bool R600MachineCFGStructurizer::prepare() { 68281ad6265SDimitry Andric bool Changed = false; 68381ad6265SDimitry Andric 68481ad6265SDimitry Andric //FIXME: if not reducible flow graph, make it so ??? 68581ad6265SDimitry Andric 68681ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "R600MachineCFGStructurizer::prepare\n";); 68781ad6265SDimitry Andric 68881ad6265SDimitry Andric orderBlocks(FuncRep); 68981ad6265SDimitry Andric 69081ad6265SDimitry Andric SmallVector<MachineBasicBlock *, DEFAULT_VEC_SLOTS> RetBlks; 69181ad6265SDimitry Andric 69281ad6265SDimitry Andric // Add an ExitBlk to loop that don't have one 69381ad6265SDimitry Andric for (MachineLoop *LoopRep : *MLI) { 69481ad6265SDimitry Andric MBBVector ExitingMBBs; 69581ad6265SDimitry Andric LoopRep->getExitingBlocks(ExitingMBBs); 69681ad6265SDimitry Andric 69781ad6265SDimitry Andric if (ExitingMBBs.size() == 0) { 69881ad6265SDimitry Andric MachineBasicBlock* DummyExitBlk = normalizeInfiniteLoopExit(LoopRep); 69981ad6265SDimitry Andric if (DummyExitBlk) 70081ad6265SDimitry Andric RetBlks.push_back(DummyExitBlk); 70181ad6265SDimitry Andric } 70281ad6265SDimitry Andric } 70381ad6265SDimitry Andric 70481ad6265SDimitry Andric // Remove unconditional branch instr. 70581ad6265SDimitry Andric // Add dummy exit block iff there are multiple returns. 70681ad6265SDimitry Andric for (MachineBasicBlock *MBB : OrderedBlks) { 70781ad6265SDimitry Andric removeUnconditionalBranch(MBB); 70881ad6265SDimitry Andric removeRedundantConditionalBranch(MBB); 70981ad6265SDimitry Andric if (isReturnBlock(MBB)) { 71081ad6265SDimitry Andric RetBlks.push_back(MBB); 71181ad6265SDimitry Andric } 71281ad6265SDimitry Andric assert(MBB->succ_size() <= 2); 71381ad6265SDimitry Andric } 71481ad6265SDimitry Andric 71581ad6265SDimitry Andric if (RetBlks.size() >= 2) { 71681ad6265SDimitry Andric addDummyExitBlock(RetBlks); 71781ad6265SDimitry Andric Changed = true; 71881ad6265SDimitry Andric } 71981ad6265SDimitry Andric 72081ad6265SDimitry Andric return Changed; 72181ad6265SDimitry Andric } 72281ad6265SDimitry Andric 72381ad6265SDimitry Andric bool R600MachineCFGStructurizer::run() { 72481ad6265SDimitry Andric //Assume reducible CFG... 72581ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "R600MachineCFGStructurizer::run\n"); 72681ad6265SDimitry Andric 72781ad6265SDimitry Andric #ifdef STRESSTEST 72881ad6265SDimitry Andric //Use the worse block ordering to test the algorithm. 72981ad6265SDimitry Andric ReverseVector(orderedBlks); 73081ad6265SDimitry Andric #endif 73181ad6265SDimitry Andric 73281ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Ordered blocks:\n"; printOrderedBlocks();); 73381ad6265SDimitry Andric int NumIter = 0; 73481ad6265SDimitry Andric bool Finish = false; 73581ad6265SDimitry Andric MachineBasicBlock *MBB; 73681ad6265SDimitry Andric bool MakeProgress = false; 73781ad6265SDimitry Andric int NumRemainedBlk = countActiveBlock(OrderedBlks.begin(), 73881ad6265SDimitry Andric OrderedBlks.end()); 73981ad6265SDimitry Andric 74081ad6265SDimitry Andric do { 74181ad6265SDimitry Andric ++NumIter; 74281ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "numIter = " << NumIter 74381ad6265SDimitry Andric << ", numRemaintedBlk = " << NumRemainedBlk << "\n";); 74481ad6265SDimitry Andric (void)NumIter; 74581ad6265SDimitry Andric 74681ad6265SDimitry Andric SmallVectorImpl<MachineBasicBlock *>::const_iterator It = 74781ad6265SDimitry Andric OrderedBlks.begin(); 74881ad6265SDimitry Andric SmallVectorImpl<MachineBasicBlock *>::const_iterator E = 74981ad6265SDimitry Andric OrderedBlks.end(); 75081ad6265SDimitry Andric 75181ad6265SDimitry Andric SmallVectorImpl<MachineBasicBlock *>::const_iterator SccBeginIter = 75281ad6265SDimitry Andric It; 75381ad6265SDimitry Andric MachineBasicBlock *SccBeginMBB = nullptr; 75481ad6265SDimitry Andric int SccNumBlk = 0; // The number of active blocks, init to a 75581ad6265SDimitry Andric // maximum possible number. 75681ad6265SDimitry Andric int SccNumIter; // Number of iteration in this SCC. 75781ad6265SDimitry Andric 75881ad6265SDimitry Andric while (It != E) { 75981ad6265SDimitry Andric MBB = *It; 76081ad6265SDimitry Andric 76181ad6265SDimitry Andric if (!SccBeginMBB) { 76281ad6265SDimitry Andric SccBeginIter = It; 76381ad6265SDimitry Andric SccBeginMBB = MBB; 76481ad6265SDimitry Andric SccNumIter = 0; 76581ad6265SDimitry Andric SccNumBlk = NumRemainedBlk; // Init to maximum possible number. 76681ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "start processing SCC" << getSCCNum(SccBeginMBB); 76781ad6265SDimitry Andric dbgs() << "\n";); 76881ad6265SDimitry Andric } 76981ad6265SDimitry Andric 77081ad6265SDimitry Andric if (!isRetiredBlock(MBB)) 77181ad6265SDimitry Andric patternMatch(MBB); 77281ad6265SDimitry Andric 77381ad6265SDimitry Andric ++It; 77481ad6265SDimitry Andric 77581ad6265SDimitry Andric bool ContNextScc = true; 77681ad6265SDimitry Andric if (It == E 77781ad6265SDimitry Andric || getSCCNum(SccBeginMBB) != getSCCNum(*It)) { 77881ad6265SDimitry Andric // Just finish one scc. 77981ad6265SDimitry Andric ++SccNumIter; 78081ad6265SDimitry Andric int sccRemainedNumBlk = countActiveBlock(SccBeginIter, It); 78181ad6265SDimitry Andric if (sccRemainedNumBlk != 1 && sccRemainedNumBlk >= SccNumBlk) { 78281ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Can't reduce SCC " << getSCCNum(MBB) 78381ad6265SDimitry Andric << ", sccNumIter = " << SccNumIter; 78481ad6265SDimitry Andric dbgs() << "doesn't make any progress\n";); 78581ad6265SDimitry Andric (void)SccNumIter; 78681ad6265SDimitry Andric ContNextScc = true; 78781ad6265SDimitry Andric } else if (sccRemainedNumBlk != 1 && sccRemainedNumBlk < SccNumBlk) { 78881ad6265SDimitry Andric SccNumBlk = sccRemainedNumBlk; 78981ad6265SDimitry Andric It = SccBeginIter; 79081ad6265SDimitry Andric ContNextScc = false; 79181ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "repeat processing SCC" << getSCCNum(MBB) 79281ad6265SDimitry Andric << "sccNumIter = " << SccNumIter << '\n';); 79381ad6265SDimitry Andric } else { 79481ad6265SDimitry Andric // Finish the current scc. 79581ad6265SDimitry Andric ContNextScc = true; 79681ad6265SDimitry Andric } 79781ad6265SDimitry Andric } else { 79881ad6265SDimitry Andric // Continue on next component in the current scc. 79981ad6265SDimitry Andric ContNextScc = false; 80081ad6265SDimitry Andric } 80181ad6265SDimitry Andric 80281ad6265SDimitry Andric if (ContNextScc) 80381ad6265SDimitry Andric SccBeginMBB = nullptr; 80481ad6265SDimitry Andric } //while, "one iteration" over the function. 80581ad6265SDimitry Andric 80681ad6265SDimitry Andric MachineBasicBlock *EntryMBB = 80781ad6265SDimitry Andric *GraphTraits<MachineFunction *>::nodes_begin(FuncRep); 80881ad6265SDimitry Andric if (EntryMBB->succ_empty()) { 80981ad6265SDimitry Andric Finish = true; 81081ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Reduce to one block\n";); 81181ad6265SDimitry Andric } else { 81281ad6265SDimitry Andric int NewnumRemainedBlk 81381ad6265SDimitry Andric = countActiveBlock(OrderedBlks.begin(), OrderedBlks.end()); 81481ad6265SDimitry Andric // consider cloned blocks ?? 81581ad6265SDimitry Andric if (NewnumRemainedBlk == 1 || NewnumRemainedBlk < NumRemainedBlk) { 81681ad6265SDimitry Andric MakeProgress = true; 81781ad6265SDimitry Andric NumRemainedBlk = NewnumRemainedBlk; 81881ad6265SDimitry Andric } else { 81981ad6265SDimitry Andric MakeProgress = false; 82081ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "No progress\n";); 82181ad6265SDimitry Andric } 82281ad6265SDimitry Andric } 82381ad6265SDimitry Andric } while (!Finish && MakeProgress); 82481ad6265SDimitry Andric 82581ad6265SDimitry Andric // Misc wrap up to maintain the consistency of the Function representation. 82681ad6265SDimitry Andric wrapup(*GraphTraits<MachineFunction *>::nodes_begin(FuncRep)); 82781ad6265SDimitry Andric 82881ad6265SDimitry Andric // Detach retired Block, release memory. 82981ad6265SDimitry Andric for (auto &It : BlockInfoMap) { 83081ad6265SDimitry Andric if (It.second && It.second->IsRetired) { 83181ad6265SDimitry Andric assert((It.first)->getNumber() != -1); 83281ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Erase BB" << (It.first)->getNumber() << "\n";); 83381ad6265SDimitry Andric It.first->eraseFromParent(); // Remove from the parent Function. 83481ad6265SDimitry Andric } 83581ad6265SDimitry Andric delete It.second; 83681ad6265SDimitry Andric } 83781ad6265SDimitry Andric BlockInfoMap.clear(); 83881ad6265SDimitry Andric LLInfoMap.clear(); 83981ad6265SDimitry Andric 84081ad6265SDimitry Andric if (!Finish) { 84181ad6265SDimitry Andric LLVM_DEBUG(FuncRep->viewCFG()); 84281ad6265SDimitry Andric report_fatal_error("IRREDUCIBLE_CFG"); 84381ad6265SDimitry Andric } 84481ad6265SDimitry Andric 84581ad6265SDimitry Andric return true; 84681ad6265SDimitry Andric } 84781ad6265SDimitry Andric 84881ad6265SDimitry Andric void R600MachineCFGStructurizer::orderBlocks(MachineFunction *MF) { 84981ad6265SDimitry Andric int SccNum = 0; 85081ad6265SDimitry Andric for (scc_iterator<MachineFunction *> It = scc_begin(MF); !It.isAtEnd(); 85181ad6265SDimitry Andric ++It, ++SccNum) { 85281ad6265SDimitry Andric const std::vector<MachineBasicBlock *> &SccNext = *It; 85381ad6265SDimitry Andric for (MachineBasicBlock *MBB : SccNext) { 85481ad6265SDimitry Andric OrderedBlks.push_back(MBB); 85581ad6265SDimitry Andric recordSccnum(MBB, SccNum); 85681ad6265SDimitry Andric } 85781ad6265SDimitry Andric } 85881ad6265SDimitry Andric 85981ad6265SDimitry Andric // walk through all the block in func to check for unreachable 86081ad6265SDimitry Andric for (auto *MBB : nodes(MF)) { 86181ad6265SDimitry Andric SccNum = getSCCNum(MBB); 86281ad6265SDimitry Andric if (SccNum == INVALIDSCCNUM) 86381ad6265SDimitry Andric dbgs() << "unreachable block BB" << MBB->getNumber() << "\n"; 86481ad6265SDimitry Andric } 86581ad6265SDimitry Andric } 86681ad6265SDimitry Andric 86781ad6265SDimitry Andric int R600MachineCFGStructurizer::patternMatch(MachineBasicBlock *MBB) { 86881ad6265SDimitry Andric int NumMatch = 0; 86981ad6265SDimitry Andric int CurMatch; 87081ad6265SDimitry Andric 87181ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Begin patternMatch BB" << MBB->getNumber() << "\n";); 87281ad6265SDimitry Andric 87381ad6265SDimitry Andric while ((CurMatch = patternMatchGroup(MBB)) > 0) 87481ad6265SDimitry Andric NumMatch += CurMatch; 87581ad6265SDimitry Andric 87681ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "End patternMatch BB" << MBB->getNumber() 87781ad6265SDimitry Andric << ", numMatch = " << NumMatch << "\n";); 87881ad6265SDimitry Andric 87981ad6265SDimitry Andric return NumMatch; 88081ad6265SDimitry Andric } 88181ad6265SDimitry Andric 88281ad6265SDimitry Andric int R600MachineCFGStructurizer::patternMatchGroup(MachineBasicBlock *MBB) { 88381ad6265SDimitry Andric int NumMatch = 0; 88481ad6265SDimitry Andric NumMatch += loopendPatternMatch(); 88581ad6265SDimitry Andric NumMatch += serialPatternMatch(MBB); 88681ad6265SDimitry Andric NumMatch += ifPatternMatch(MBB); 88781ad6265SDimitry Andric return NumMatch; 88881ad6265SDimitry Andric } 88981ad6265SDimitry Andric 89081ad6265SDimitry Andric int R600MachineCFGStructurizer::serialPatternMatch(MachineBasicBlock *MBB) { 89181ad6265SDimitry Andric if (MBB->succ_size() != 1) 89281ad6265SDimitry Andric return 0; 89381ad6265SDimitry Andric 89481ad6265SDimitry Andric MachineBasicBlock *childBlk = *MBB->succ_begin(); 89581ad6265SDimitry Andric if (childBlk->pred_size() != 1 || isActiveLoophead(childBlk)) 89681ad6265SDimitry Andric return 0; 89781ad6265SDimitry Andric 89881ad6265SDimitry Andric mergeSerialBlock(MBB, childBlk); 89981ad6265SDimitry Andric ++numSerialPatternMatch; 90081ad6265SDimitry Andric return 1; 90181ad6265SDimitry Andric } 90281ad6265SDimitry Andric 90381ad6265SDimitry Andric int R600MachineCFGStructurizer::ifPatternMatch(MachineBasicBlock *MBB) { 90481ad6265SDimitry Andric //two edges 90581ad6265SDimitry Andric if (MBB->succ_size() != 2) 90681ad6265SDimitry Andric return 0; 90781ad6265SDimitry Andric if (hasBackEdge(MBB)) 90881ad6265SDimitry Andric return 0; 90981ad6265SDimitry Andric MachineInstr *BranchMI = getNormalBlockBranchInstr(MBB); 91081ad6265SDimitry Andric if (!BranchMI) 91181ad6265SDimitry Andric return 0; 91281ad6265SDimitry Andric 91381ad6265SDimitry Andric assert(isCondBranch(BranchMI)); 91481ad6265SDimitry Andric int NumMatch = 0; 91581ad6265SDimitry Andric 91681ad6265SDimitry Andric MachineBasicBlock *TrueMBB = getTrueBranch(BranchMI); 91781ad6265SDimitry Andric NumMatch += serialPatternMatch(TrueMBB); 91881ad6265SDimitry Andric NumMatch += ifPatternMatch(TrueMBB); 91981ad6265SDimitry Andric MachineBasicBlock *FalseMBB = getFalseBranch(MBB, BranchMI); 92081ad6265SDimitry Andric NumMatch += serialPatternMatch(FalseMBB); 92181ad6265SDimitry Andric NumMatch += ifPatternMatch(FalseMBB); 92281ad6265SDimitry Andric MachineBasicBlock *LandBlk; 92381ad6265SDimitry Andric int Cloned = 0; 92481ad6265SDimitry Andric 92581ad6265SDimitry Andric assert (!TrueMBB->succ_empty() || !FalseMBB->succ_empty()); 92681ad6265SDimitry Andric // TODO: Simplify 92781ad6265SDimitry Andric if (TrueMBB->succ_size() == 1 && FalseMBB->succ_size() == 1 92881ad6265SDimitry Andric && *TrueMBB->succ_begin() == *FalseMBB->succ_begin()) { 92981ad6265SDimitry Andric // Diamond pattern 93081ad6265SDimitry Andric LandBlk = *TrueMBB->succ_begin(); 93181ad6265SDimitry Andric } else if (TrueMBB->succ_size() == 1 && *TrueMBB->succ_begin() == FalseMBB) { 93281ad6265SDimitry Andric // Triangle pattern, false is empty 93381ad6265SDimitry Andric LandBlk = FalseMBB; 93481ad6265SDimitry Andric FalseMBB = nullptr; 93581ad6265SDimitry Andric } else if (FalseMBB->succ_size() == 1 93681ad6265SDimitry Andric && *FalseMBB->succ_begin() == TrueMBB) { 93781ad6265SDimitry Andric // Triangle pattern, true is empty 93881ad6265SDimitry Andric // We reverse the predicate to make a triangle, empty false pattern; 93981ad6265SDimitry Andric std::swap(TrueMBB, FalseMBB); 94081ad6265SDimitry Andric reversePredicateSetter(MBB->end(), *MBB); 94181ad6265SDimitry Andric LandBlk = FalseMBB; 94281ad6265SDimitry Andric FalseMBB = nullptr; 94381ad6265SDimitry Andric } else if (FalseMBB->succ_size() == 1 94481ad6265SDimitry Andric && isSameloopDetachedContbreak(TrueMBB, FalseMBB)) { 94581ad6265SDimitry Andric LandBlk = *FalseMBB->succ_begin(); 94681ad6265SDimitry Andric } else if (TrueMBB->succ_size() == 1 94781ad6265SDimitry Andric && isSameloopDetachedContbreak(FalseMBB, TrueMBB)) { 94881ad6265SDimitry Andric LandBlk = *TrueMBB->succ_begin(); 94981ad6265SDimitry Andric } else { 95081ad6265SDimitry Andric return NumMatch + handleJumpintoIf(MBB, TrueMBB, FalseMBB); 95181ad6265SDimitry Andric } 95281ad6265SDimitry Andric 95381ad6265SDimitry Andric // improveSimpleJumpinfoIf can handle the case where landBlk == NULL but the 95481ad6265SDimitry Andric // new BB created for landBlk==NULL may introduce new challenge to the 95581ad6265SDimitry Andric // reduction process. 95681ad6265SDimitry Andric if (LandBlk && 95781ad6265SDimitry Andric ((TrueMBB && TrueMBB->pred_size() > 1) 95881ad6265SDimitry Andric || (FalseMBB && FalseMBB->pred_size() > 1))) { 95981ad6265SDimitry Andric Cloned += improveSimpleJumpintoIf(MBB, TrueMBB, FalseMBB, &LandBlk); 96081ad6265SDimitry Andric } 96181ad6265SDimitry Andric 96281ad6265SDimitry Andric if (TrueMBB && TrueMBB->pred_size() > 1) { 96381ad6265SDimitry Andric TrueMBB = cloneBlockForPredecessor(TrueMBB, MBB); 96481ad6265SDimitry Andric ++Cloned; 96581ad6265SDimitry Andric } 96681ad6265SDimitry Andric 96781ad6265SDimitry Andric if (FalseMBB && FalseMBB->pred_size() > 1) { 96881ad6265SDimitry Andric FalseMBB = cloneBlockForPredecessor(FalseMBB, MBB); 96981ad6265SDimitry Andric ++Cloned; 97081ad6265SDimitry Andric } 97181ad6265SDimitry Andric 97281ad6265SDimitry Andric mergeIfthenelseBlock(BranchMI, MBB, TrueMBB, FalseMBB, LandBlk); 97381ad6265SDimitry Andric 97481ad6265SDimitry Andric ++numIfPatternMatch; 97581ad6265SDimitry Andric 97681ad6265SDimitry Andric numClonedBlock += Cloned; 97781ad6265SDimitry Andric 97881ad6265SDimitry Andric return 1 + Cloned + NumMatch; 97981ad6265SDimitry Andric } 98081ad6265SDimitry Andric 98181ad6265SDimitry Andric int R600MachineCFGStructurizer::loopendPatternMatch() { 98281ad6265SDimitry Andric std::deque<MachineLoop *> NestedLoops; 98381ad6265SDimitry Andric for (auto &It: *MLI) 98481ad6265SDimitry Andric for (MachineLoop *ML : depth_first(It)) 98581ad6265SDimitry Andric NestedLoops.push_front(ML); 98681ad6265SDimitry Andric 98781ad6265SDimitry Andric if (NestedLoops.empty()) 98881ad6265SDimitry Andric return 0; 98981ad6265SDimitry Andric 99081ad6265SDimitry Andric // Process nested loop outside->inside (we did push_front), 99181ad6265SDimitry Andric // so "continue" to a outside loop won't be mistaken as "break" 99281ad6265SDimitry Andric // of the current loop. 99381ad6265SDimitry Andric int Num = 0; 99481ad6265SDimitry Andric for (MachineLoop *ExaminedLoop : NestedLoops) { 99581ad6265SDimitry Andric if (ExaminedLoop->getNumBlocks() == 0 || Visited[ExaminedLoop]) 99681ad6265SDimitry Andric continue; 99781ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Processing:\n"; ExaminedLoop->dump();); 99881ad6265SDimitry Andric int NumBreak = mergeLoop(ExaminedLoop); 99981ad6265SDimitry Andric if (NumBreak == -1) 100081ad6265SDimitry Andric break; 100181ad6265SDimitry Andric Num += NumBreak; 100281ad6265SDimitry Andric } 100381ad6265SDimitry Andric return Num; 100481ad6265SDimitry Andric } 100581ad6265SDimitry Andric 100681ad6265SDimitry Andric int R600MachineCFGStructurizer::mergeLoop(MachineLoop *LoopRep) { 100781ad6265SDimitry Andric MachineBasicBlock *LoopHeader = LoopRep->getHeader(); 100881ad6265SDimitry Andric MBBVector ExitingMBBs; 100981ad6265SDimitry Andric LoopRep->getExitingBlocks(ExitingMBBs); 101081ad6265SDimitry Andric assert(!ExitingMBBs.empty() && "Infinite Loop not supported"); 101181ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Loop has " << ExitingMBBs.size() 101281ad6265SDimitry Andric << " exiting blocks\n";); 101381ad6265SDimitry Andric // We assume a single ExitBlk 101481ad6265SDimitry Andric MBBVector ExitBlks; 101581ad6265SDimitry Andric LoopRep->getExitBlocks(ExitBlks); 101681ad6265SDimitry Andric SmallPtrSet<MachineBasicBlock *, 2> ExitBlkSet; 1017*0fca6ea1SDimitry Andric for (MachineBasicBlock *MBB : ExitBlks) 1018*0fca6ea1SDimitry Andric ExitBlkSet.insert(MBB); 101981ad6265SDimitry Andric assert(ExitBlkSet.size() == 1); 102081ad6265SDimitry Andric MachineBasicBlock *ExitBlk = *ExitBlks.begin(); 102181ad6265SDimitry Andric assert(ExitBlk && "Loop has several exit block"); 102281ad6265SDimitry Andric MBBVector LatchBlks; 102381ad6265SDimitry Andric for (auto *LB : inverse_children<MachineBasicBlock*>(LoopHeader)) 102481ad6265SDimitry Andric if (LoopRep->contains(LB)) 102581ad6265SDimitry Andric LatchBlks.push_back(LB); 102681ad6265SDimitry Andric 1027*0fca6ea1SDimitry Andric for (MachineBasicBlock *MBB : ExitingMBBs) 1028*0fca6ea1SDimitry Andric mergeLoopbreakBlock(MBB, ExitBlk); 1029*0fca6ea1SDimitry Andric for (MachineBasicBlock *MBB : LatchBlks) 1030*0fca6ea1SDimitry Andric settleLoopcontBlock(MBB, LoopHeader); 103181ad6265SDimitry Andric int Match = 0; 103281ad6265SDimitry Andric do { 103381ad6265SDimitry Andric Match = 0; 103481ad6265SDimitry Andric Match += serialPatternMatch(LoopHeader); 103581ad6265SDimitry Andric Match += ifPatternMatch(LoopHeader); 103681ad6265SDimitry Andric } while (Match > 0); 103781ad6265SDimitry Andric mergeLooplandBlock(LoopHeader, ExitBlk); 103881ad6265SDimitry Andric MachineLoop *ParentLoop = LoopRep->getParentLoop(); 103981ad6265SDimitry Andric if (ParentLoop) 104081ad6265SDimitry Andric MLI->changeLoopFor(LoopHeader, ParentLoop); 104181ad6265SDimitry Andric else 104281ad6265SDimitry Andric MLI->removeBlock(LoopHeader); 104381ad6265SDimitry Andric Visited[LoopRep] = true; 104481ad6265SDimitry Andric return 1; 104581ad6265SDimitry Andric } 104681ad6265SDimitry Andric 104781ad6265SDimitry Andric bool R600MachineCFGStructurizer::isSameloopDetachedContbreak( 104881ad6265SDimitry Andric MachineBasicBlock *Src1MBB, MachineBasicBlock *Src2MBB) { 104981ad6265SDimitry Andric if (Src1MBB->succ_empty()) { 105081ad6265SDimitry Andric MachineLoop *LoopRep = MLI->getLoopFor(Src1MBB); 105181ad6265SDimitry Andric if (LoopRep&& LoopRep == MLI->getLoopFor(Src2MBB)) { 105281ad6265SDimitry Andric MachineBasicBlock *&TheEntry = LLInfoMap[LoopRep]; 105381ad6265SDimitry Andric if (TheEntry) { 105481ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "isLoopContBreakBlock yes src1 = BB" 105581ad6265SDimitry Andric << Src1MBB->getNumber() << " src2 = BB" 105681ad6265SDimitry Andric << Src2MBB->getNumber() << "\n";); 105781ad6265SDimitry Andric return true; 105881ad6265SDimitry Andric } 105981ad6265SDimitry Andric } 106081ad6265SDimitry Andric } 106181ad6265SDimitry Andric return false; 106281ad6265SDimitry Andric } 106381ad6265SDimitry Andric 106481ad6265SDimitry Andric int R600MachineCFGStructurizer::handleJumpintoIf(MachineBasicBlock *HeadMBB, 106581ad6265SDimitry Andric MachineBasicBlock *TrueMBB, MachineBasicBlock *FalseMBB) { 106681ad6265SDimitry Andric int Num = handleJumpintoIfImp(HeadMBB, TrueMBB, FalseMBB); 106781ad6265SDimitry Andric if (Num == 0) { 106881ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "handleJumpintoIf swap trueBlk and FalseBlk" 106981ad6265SDimitry Andric << "\n";); 107081ad6265SDimitry Andric Num = handleJumpintoIfImp(HeadMBB, FalseMBB, TrueMBB); 107181ad6265SDimitry Andric } 107281ad6265SDimitry Andric return Num; 107381ad6265SDimitry Andric } 107481ad6265SDimitry Andric 107581ad6265SDimitry Andric int R600MachineCFGStructurizer::handleJumpintoIfImp(MachineBasicBlock *HeadMBB, 107681ad6265SDimitry Andric MachineBasicBlock *TrueMBB, MachineBasicBlock *FalseMBB) { 107781ad6265SDimitry Andric int Num = 0; 107881ad6265SDimitry Andric MachineBasicBlock *DownBlk; 107981ad6265SDimitry Andric 108081ad6265SDimitry Andric //trueBlk could be the common post dominator 108181ad6265SDimitry Andric DownBlk = TrueMBB; 108281ad6265SDimitry Andric 108381ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "handleJumpintoIfImp head = BB" << HeadMBB->getNumber() 108481ad6265SDimitry Andric << " true = BB" << TrueMBB->getNumber() 108581ad6265SDimitry Andric << ", numSucc=" << TrueMBB->succ_size() << " false = BB" 108681ad6265SDimitry Andric << FalseMBB->getNumber() << "\n";); 108781ad6265SDimitry Andric 108881ad6265SDimitry Andric while (DownBlk) { 108981ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "check down = BB" << DownBlk->getNumber();); 109081ad6265SDimitry Andric 109181ad6265SDimitry Andric if (singlePathTo(FalseMBB, DownBlk) == SinglePath_InPath) { 109281ad6265SDimitry Andric LLVM_DEBUG(dbgs() << " working\n";); 109381ad6265SDimitry Andric 109481ad6265SDimitry Andric Num += cloneOnSideEntryTo(HeadMBB, TrueMBB, DownBlk); 109581ad6265SDimitry Andric Num += cloneOnSideEntryTo(HeadMBB, FalseMBB, DownBlk); 109681ad6265SDimitry Andric 109781ad6265SDimitry Andric numClonedBlock += Num; 109881ad6265SDimitry Andric Num += serialPatternMatch(*HeadMBB->succ_begin()); 109981ad6265SDimitry Andric Num += serialPatternMatch(*std::next(HeadMBB->succ_begin())); 110081ad6265SDimitry Andric Num += ifPatternMatch(HeadMBB); 110181ad6265SDimitry Andric assert(Num > 0); 110281ad6265SDimitry Andric 110381ad6265SDimitry Andric break; 110481ad6265SDimitry Andric } 110581ad6265SDimitry Andric LLVM_DEBUG(dbgs() << " not working\n";); 110681ad6265SDimitry Andric DownBlk = (DownBlk->succ_size() == 1) ? (*DownBlk->succ_begin()) : nullptr; 110781ad6265SDimitry Andric } // walk down the postDomTree 110881ad6265SDimitry Andric 110981ad6265SDimitry Andric return Num; 111081ad6265SDimitry Andric } 111181ad6265SDimitry Andric 111281ad6265SDimitry Andric #ifndef NDEBUG 111381ad6265SDimitry Andric void R600MachineCFGStructurizer::showImproveSimpleJumpintoIf( 111481ad6265SDimitry Andric MachineBasicBlock *HeadMBB, MachineBasicBlock *TrueMBB, 111581ad6265SDimitry Andric MachineBasicBlock *FalseMBB, MachineBasicBlock *LandMBB, bool Detail) { 111681ad6265SDimitry Andric dbgs() << "head = BB" << HeadMBB->getNumber() 111781ad6265SDimitry Andric << " size = " << HeadMBB->size(); 111881ad6265SDimitry Andric if (Detail) { 111981ad6265SDimitry Andric dbgs() << "\n"; 112081ad6265SDimitry Andric HeadMBB->print(dbgs()); 112181ad6265SDimitry Andric dbgs() << "\n"; 112281ad6265SDimitry Andric } 112381ad6265SDimitry Andric 112481ad6265SDimitry Andric if (TrueMBB) { 112581ad6265SDimitry Andric dbgs() << ", true = BB" << TrueMBB->getNumber() << " size = " 112681ad6265SDimitry Andric << TrueMBB->size() << " numPred = " << TrueMBB->pred_size(); 112781ad6265SDimitry Andric if (Detail) { 112881ad6265SDimitry Andric dbgs() << "\n"; 112981ad6265SDimitry Andric TrueMBB->print(dbgs()); 113081ad6265SDimitry Andric dbgs() << "\n"; 113181ad6265SDimitry Andric } 113281ad6265SDimitry Andric } 113381ad6265SDimitry Andric if (FalseMBB) { 113481ad6265SDimitry Andric dbgs() << ", false = BB" << FalseMBB->getNumber() << " size = " 113581ad6265SDimitry Andric << FalseMBB->size() << " numPred = " << FalseMBB->pred_size(); 113681ad6265SDimitry Andric if (Detail) { 113781ad6265SDimitry Andric dbgs() << "\n"; 113881ad6265SDimitry Andric FalseMBB->print(dbgs()); 113981ad6265SDimitry Andric dbgs() << "\n"; 114081ad6265SDimitry Andric } 114181ad6265SDimitry Andric } 114281ad6265SDimitry Andric if (LandMBB) { 114381ad6265SDimitry Andric dbgs() << ", land = BB" << LandMBB->getNumber() << " size = " 114481ad6265SDimitry Andric << LandMBB->size() << " numPred = " << LandMBB->pred_size(); 114581ad6265SDimitry Andric if (Detail) { 114681ad6265SDimitry Andric dbgs() << "\n"; 114781ad6265SDimitry Andric LandMBB->print(dbgs()); 114881ad6265SDimitry Andric dbgs() << "\n"; 114981ad6265SDimitry Andric } 115081ad6265SDimitry Andric } 115181ad6265SDimitry Andric 115281ad6265SDimitry Andric dbgs() << "\n"; 115381ad6265SDimitry Andric } 115481ad6265SDimitry Andric #endif 115581ad6265SDimitry Andric 115681ad6265SDimitry Andric int R600MachineCFGStructurizer::improveSimpleJumpintoIf(MachineBasicBlock *HeadMBB, 115781ad6265SDimitry Andric MachineBasicBlock *TrueMBB, MachineBasicBlock *FalseMBB, 115881ad6265SDimitry Andric MachineBasicBlock **LandMBBPtr) { 115981ad6265SDimitry Andric bool MigrateTrue = false; 116081ad6265SDimitry Andric bool MigrateFalse = false; 116181ad6265SDimitry Andric 116281ad6265SDimitry Andric MachineBasicBlock *LandBlk = *LandMBBPtr; 116381ad6265SDimitry Andric 116481ad6265SDimitry Andric assert((!TrueMBB || TrueMBB->succ_size() <= 1) 116581ad6265SDimitry Andric && (!FalseMBB || FalseMBB->succ_size() <= 1)); 116681ad6265SDimitry Andric 116781ad6265SDimitry Andric if (TrueMBB == FalseMBB) 116881ad6265SDimitry Andric return 0; 116981ad6265SDimitry Andric 117081ad6265SDimitry Andric MigrateTrue = needMigrateBlock(TrueMBB); 117181ad6265SDimitry Andric MigrateFalse = needMigrateBlock(FalseMBB); 117281ad6265SDimitry Andric 117381ad6265SDimitry Andric if (!MigrateTrue && !MigrateFalse) 117481ad6265SDimitry Andric return 0; 117581ad6265SDimitry Andric 117681ad6265SDimitry Andric // If we need to migrate either trueBlk and falseBlk, migrate the rest that 117781ad6265SDimitry Andric // have more than one predecessors. without doing this, its predecessor 117881ad6265SDimitry Andric // rather than headBlk will have undefined value in initReg. 117981ad6265SDimitry Andric if (!MigrateTrue && TrueMBB && TrueMBB->pred_size() > 1) 118081ad6265SDimitry Andric MigrateTrue = true; 118181ad6265SDimitry Andric if (!MigrateFalse && FalseMBB && FalseMBB->pred_size() > 1) 118281ad6265SDimitry Andric MigrateFalse = true; 118381ad6265SDimitry Andric 118481ad6265SDimitry Andric LLVM_DEBUG( 118581ad6265SDimitry Andric dbgs() << "before improveSimpleJumpintoIf: "; 118681ad6265SDimitry Andric showImproveSimpleJumpintoIf(HeadMBB, TrueMBB, FalseMBB, LandBlk, 0);); 118781ad6265SDimitry Andric 118881ad6265SDimitry Andric // org: headBlk => if () {trueBlk} else {falseBlk} => landBlk 118981ad6265SDimitry Andric // 119081ad6265SDimitry Andric // new: headBlk => if () {initReg = 1; org trueBlk branch} else 119181ad6265SDimitry Andric // {initReg = 0; org falseBlk branch } 119281ad6265SDimitry Andric // => landBlk => if (initReg) {org trueBlk} else {org falseBlk} 119381ad6265SDimitry Andric // => org landBlk 119481ad6265SDimitry Andric // if landBlk->pred_size() > 2, put the about if-else inside 119581ad6265SDimitry Andric // if (initReg !=2) {...} 119681ad6265SDimitry Andric // 119781ad6265SDimitry Andric // add initReg = initVal to headBlk 119881ad6265SDimitry Andric 119981ad6265SDimitry Andric const TargetRegisterClass * I32RC = TRI->getCFGStructurizerRegClass(MVT::i32); 120081ad6265SDimitry Andric if (!MigrateTrue || !MigrateFalse) { 120181ad6265SDimitry Andric // XXX: We have an opportunity here to optimize the "branch into if" case 120281ad6265SDimitry Andric // here. Branch into if looks like this: 120381ad6265SDimitry Andric // entry 120481ad6265SDimitry Andric // / | 120581ad6265SDimitry Andric // diamond_head branch_from 120681ad6265SDimitry Andric // / \ | 120781ad6265SDimitry Andric // diamond_false diamond_true 120881ad6265SDimitry Andric // \ / 120981ad6265SDimitry Andric // done 121081ad6265SDimitry Andric // 121181ad6265SDimitry Andric // The diamond_head block begins the "if" and the diamond_true block 121281ad6265SDimitry Andric // is the block being "branched into". 121381ad6265SDimitry Andric // 121481ad6265SDimitry Andric // If MigrateTrue is true, then TrueBB is the block being "branched into" 121581ad6265SDimitry Andric // and if MigrateFalse is true, then FalseBB is the block being 121681ad6265SDimitry Andric // "branched into" 121781ad6265SDimitry Andric // 121881ad6265SDimitry Andric // Here is the pseudo code for how I think the optimization should work: 121981ad6265SDimitry Andric // 1. Insert MOV GPR0, 0 before the branch instruction in diamond_head. 122081ad6265SDimitry Andric // 2. Insert MOV GPR0, 1 before the branch instruction in branch_from. 122181ad6265SDimitry Andric // 3. Move the branch instruction from diamond_head into its own basic 122281ad6265SDimitry Andric // block (new_block). 122381ad6265SDimitry Andric // 4. Add an unconditional branch from diamond_head to new_block 122481ad6265SDimitry Andric // 5. Replace the branch instruction in branch_from with an unconditional 122581ad6265SDimitry Andric // branch to new_block. If branch_from has multiple predecessors, then 122681ad6265SDimitry Andric // we need to replace the True/False block in the branch 122781ad6265SDimitry Andric // instruction instead of replacing it. 122881ad6265SDimitry Andric // 6. Change the condition of the branch instruction in new_block from 122981ad6265SDimitry Andric // COND to (COND || GPR0) 123081ad6265SDimitry Andric // 123181ad6265SDimitry Andric // In order insert these MOV instruction, we will need to use the 123281ad6265SDimitry Andric // RegisterScavenger. Usually liveness stops being tracked during 123381ad6265SDimitry Andric // the late machine optimization passes, however if we implement 123481ad6265SDimitry Andric // bool TargetRegisterInfo::requiresRegisterScavenging( 123581ad6265SDimitry Andric // const MachineFunction &MF) 123681ad6265SDimitry Andric // and have it return true, liveness will be tracked correctly 123781ad6265SDimitry Andric // by generic optimization passes. We will also need to make sure that 123881ad6265SDimitry Andric // all of our target-specific passes that run after regalloc and before 123981ad6265SDimitry Andric // the CFGStructurizer track liveness and we will need to modify this pass 124081ad6265SDimitry Andric // to correctly track liveness. 124181ad6265SDimitry Andric // 124281ad6265SDimitry Andric // After the above changes, the new CFG should look like this: 124381ad6265SDimitry Andric // entry 124481ad6265SDimitry Andric // / | 124581ad6265SDimitry Andric // diamond_head branch_from 124681ad6265SDimitry Andric // \ / 124781ad6265SDimitry Andric // new_block 124881ad6265SDimitry Andric // / | 124981ad6265SDimitry Andric // diamond_false diamond_true 125081ad6265SDimitry Andric // \ / 125181ad6265SDimitry Andric // done 125281ad6265SDimitry Andric // 125381ad6265SDimitry Andric // Without this optimization, we are forced to duplicate the diamond_true 125481ad6265SDimitry Andric // block and we will end up with a CFG like this: 125581ad6265SDimitry Andric // 125681ad6265SDimitry Andric // entry 125781ad6265SDimitry Andric // / | 125881ad6265SDimitry Andric // diamond_head branch_from 125981ad6265SDimitry Andric // / \ | 126081ad6265SDimitry Andric // diamond_false diamond_true diamond_true (duplicate) 126181ad6265SDimitry Andric // \ / | 126281ad6265SDimitry Andric // done --------------------| 126381ad6265SDimitry Andric // 126481ad6265SDimitry Andric // Duplicating diamond_true can be very costly especially if it has a 126581ad6265SDimitry Andric // lot of instructions. 126681ad6265SDimitry Andric return 0; 126781ad6265SDimitry Andric } 126881ad6265SDimitry Andric 126981ad6265SDimitry Andric int NumNewBlk = 0; 127081ad6265SDimitry Andric 127181ad6265SDimitry Andric bool LandBlkHasOtherPred = (LandBlk->pred_size() > 2); 127281ad6265SDimitry Andric 127381ad6265SDimitry Andric //insert R600::ENDIF to avoid special case "input landBlk == NULL" 127481ad6265SDimitry Andric MachineBasicBlock::iterator I = insertInstrBefore(LandBlk, R600::ENDIF); 127581ad6265SDimitry Andric 127681ad6265SDimitry Andric if (LandBlkHasOtherPred) { 127781ad6265SDimitry Andric report_fatal_error("Extra register needed to handle CFG"); 127881ad6265SDimitry Andric Register CmpResReg = 127981ad6265SDimitry Andric HeadMBB->getParent()->getRegInfo().createVirtualRegister(I32RC); 128081ad6265SDimitry Andric report_fatal_error("Extra compare instruction needed to handle CFG"); 128181ad6265SDimitry Andric insertCondBranchBefore(LandBlk, I, R600::IF_PREDICATE_SET, 128281ad6265SDimitry Andric CmpResReg, DebugLoc()); 128381ad6265SDimitry Andric } 128481ad6265SDimitry Andric 128581ad6265SDimitry Andric // XXX: We are running this after RA, so creating virtual registers will 128681ad6265SDimitry Andric // cause an assertion failure in the PostRA scheduling pass. 128781ad6265SDimitry Andric Register InitReg = 128881ad6265SDimitry Andric HeadMBB->getParent()->getRegInfo().createVirtualRegister(I32RC); 128981ad6265SDimitry Andric insertCondBranchBefore(LandBlk, I, R600::IF_PREDICATE_SET, InitReg, 129081ad6265SDimitry Andric DebugLoc()); 129181ad6265SDimitry Andric 129281ad6265SDimitry Andric if (MigrateTrue) { 129381ad6265SDimitry Andric migrateInstruction(TrueMBB, LandBlk, I); 129481ad6265SDimitry Andric // need to uncondionally insert the assignment to ensure a path from its 129581ad6265SDimitry Andric // predecessor rather than headBlk has valid value in initReg if 129681ad6265SDimitry Andric // (initVal != 1). 129781ad6265SDimitry Andric report_fatal_error("Extra register needed to handle CFG"); 129881ad6265SDimitry Andric } 129981ad6265SDimitry Andric insertInstrBefore(I, R600::ELSE); 130081ad6265SDimitry Andric 130181ad6265SDimitry Andric if (MigrateFalse) { 130281ad6265SDimitry Andric migrateInstruction(FalseMBB, LandBlk, I); 130381ad6265SDimitry Andric // need to uncondionally insert the assignment to ensure a path from its 130481ad6265SDimitry Andric // predecessor rather than headBlk has valid value in initReg if 130581ad6265SDimitry Andric // (initVal != 0) 130681ad6265SDimitry Andric report_fatal_error("Extra register needed to handle CFG"); 130781ad6265SDimitry Andric } 130881ad6265SDimitry Andric 130981ad6265SDimitry Andric if (LandBlkHasOtherPred) { 131081ad6265SDimitry Andric // add endif 131181ad6265SDimitry Andric insertInstrBefore(I, R600::ENDIF); 131281ad6265SDimitry Andric 131381ad6265SDimitry Andric // put initReg = 2 to other predecessors of landBlk 131481ad6265SDimitry Andric for (MachineBasicBlock *MBB : LandBlk->predecessors()) 131581ad6265SDimitry Andric if (MBB != TrueMBB && MBB != FalseMBB) 131681ad6265SDimitry Andric report_fatal_error("Extra register needed to handle CFG"); 131781ad6265SDimitry Andric } 131881ad6265SDimitry Andric LLVM_DEBUG( 131981ad6265SDimitry Andric dbgs() << "result from improveSimpleJumpintoIf: "; 132081ad6265SDimitry Andric showImproveSimpleJumpintoIf(HeadMBB, TrueMBB, FalseMBB, LandBlk, 0);); 132181ad6265SDimitry Andric 132281ad6265SDimitry Andric // update landBlk 132381ad6265SDimitry Andric *LandMBBPtr = LandBlk; 132481ad6265SDimitry Andric 132581ad6265SDimitry Andric return NumNewBlk; 132681ad6265SDimitry Andric } 132781ad6265SDimitry Andric 132881ad6265SDimitry Andric void R600MachineCFGStructurizer::mergeSerialBlock(MachineBasicBlock *DstMBB, 132981ad6265SDimitry Andric MachineBasicBlock *SrcMBB) { 133081ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "serialPattern BB" << DstMBB->getNumber() << " <= BB" 133181ad6265SDimitry Andric << SrcMBB->getNumber() << "\n";); 133281ad6265SDimitry Andric DstMBB->splice(DstMBB->end(), SrcMBB, SrcMBB->begin(), SrcMBB->end()); 133381ad6265SDimitry Andric 133481ad6265SDimitry Andric DstMBB->removeSuccessor(SrcMBB, true); 133581ad6265SDimitry Andric cloneSuccessorList(DstMBB, SrcMBB); 133681ad6265SDimitry Andric 133781ad6265SDimitry Andric removeSuccessor(SrcMBB); 133881ad6265SDimitry Andric MLI->removeBlock(SrcMBB); 133981ad6265SDimitry Andric retireBlock(SrcMBB); 134081ad6265SDimitry Andric } 134181ad6265SDimitry Andric 134281ad6265SDimitry Andric void R600MachineCFGStructurizer::mergeIfthenelseBlock(MachineInstr *BranchMI, 134381ad6265SDimitry Andric MachineBasicBlock *MBB, MachineBasicBlock *TrueMBB, 134481ad6265SDimitry Andric MachineBasicBlock *FalseMBB, MachineBasicBlock *LandMBB) { 134581ad6265SDimitry Andric assert (TrueMBB); 134681ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "ifPattern BB" << MBB->getNumber(); dbgs() << "{ "; 134781ad6265SDimitry Andric if (TrueMBB) { dbgs() << "BB" << TrueMBB->getNumber(); } dbgs() 134881ad6265SDimitry Andric << " } else "; 134981ad6265SDimitry Andric dbgs() << "{ "; if (FalseMBB) { 135081ad6265SDimitry Andric dbgs() << "BB" << FalseMBB->getNumber(); 135181ad6265SDimitry Andric } dbgs() << " }\n "; 135281ad6265SDimitry Andric dbgs() << "landBlock: "; if (!LandMBB) { dbgs() << "NULL"; } else { 135381ad6265SDimitry Andric dbgs() << "BB" << LandMBB->getNumber(); 135481ad6265SDimitry Andric } dbgs() << "\n";); 135581ad6265SDimitry Andric 135681ad6265SDimitry Andric int OldOpcode = BranchMI->getOpcode(); 135781ad6265SDimitry Andric DebugLoc BranchDL = BranchMI->getDebugLoc(); 135881ad6265SDimitry Andric 135981ad6265SDimitry Andric // transform to 136081ad6265SDimitry Andric // if cond 136181ad6265SDimitry Andric // trueBlk 136281ad6265SDimitry Andric // else 136381ad6265SDimitry Andric // falseBlk 136481ad6265SDimitry Andric // endif 136581ad6265SDimitry Andric // landBlk 136681ad6265SDimitry Andric 136781ad6265SDimitry Andric MachineBasicBlock::iterator I = BranchMI; 136881ad6265SDimitry Andric insertCondBranchBefore(I, getBranchNzeroOpcode(OldOpcode), 136981ad6265SDimitry Andric BranchDL); 137081ad6265SDimitry Andric 137181ad6265SDimitry Andric if (TrueMBB) { 137281ad6265SDimitry Andric MBB->splice(I, TrueMBB, TrueMBB->begin(), TrueMBB->end()); 137381ad6265SDimitry Andric MBB->removeSuccessor(TrueMBB, true); 137481ad6265SDimitry Andric if (LandMBB && TrueMBB->succ_size()!=0) 137581ad6265SDimitry Andric TrueMBB->removeSuccessor(LandMBB, true); 137681ad6265SDimitry Andric retireBlock(TrueMBB); 137781ad6265SDimitry Andric MLI->removeBlock(TrueMBB); 137881ad6265SDimitry Andric } 137981ad6265SDimitry Andric 138081ad6265SDimitry Andric if (FalseMBB) { 138181ad6265SDimitry Andric insertInstrBefore(I, R600::ELSE); 138281ad6265SDimitry Andric MBB->splice(I, FalseMBB, FalseMBB->begin(), 138381ad6265SDimitry Andric FalseMBB->end()); 138481ad6265SDimitry Andric MBB->removeSuccessor(FalseMBB, true); 138581ad6265SDimitry Andric if (LandMBB && !FalseMBB->succ_empty()) 138681ad6265SDimitry Andric FalseMBB->removeSuccessor(LandMBB, true); 138781ad6265SDimitry Andric retireBlock(FalseMBB); 138881ad6265SDimitry Andric MLI->removeBlock(FalseMBB); 138981ad6265SDimitry Andric } 139081ad6265SDimitry Andric insertInstrBefore(I, R600::ENDIF); 139181ad6265SDimitry Andric 139281ad6265SDimitry Andric BranchMI->eraseFromParent(); 139381ad6265SDimitry Andric 139481ad6265SDimitry Andric if (LandMBB && TrueMBB && FalseMBB) 139581ad6265SDimitry Andric MBB->addSuccessor(LandMBB); 139681ad6265SDimitry Andric } 139781ad6265SDimitry Andric 139881ad6265SDimitry Andric void R600MachineCFGStructurizer::mergeLooplandBlock(MachineBasicBlock *DstBlk, 139981ad6265SDimitry Andric MachineBasicBlock *LandMBB) { 140081ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "loopPattern header = BB" << DstBlk->getNumber() 140181ad6265SDimitry Andric << " land = BB" << LandMBB->getNumber() << "\n";); 140281ad6265SDimitry Andric 140381ad6265SDimitry Andric insertInstrBefore(DstBlk, R600::WHILELOOP, DebugLoc()); 140481ad6265SDimitry Andric insertInstrEnd(DstBlk, R600::ENDLOOP, DebugLoc()); 140581ad6265SDimitry Andric DstBlk->replaceSuccessor(DstBlk, LandMBB); 140681ad6265SDimitry Andric } 140781ad6265SDimitry Andric 140881ad6265SDimitry Andric void R600MachineCFGStructurizer::mergeLoopbreakBlock(MachineBasicBlock *ExitingMBB, 140981ad6265SDimitry Andric MachineBasicBlock *LandMBB) { 141081ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "loopbreakPattern exiting = BB" 141181ad6265SDimitry Andric << ExitingMBB->getNumber() << " land = BB" 141281ad6265SDimitry Andric << LandMBB->getNumber() << "\n";); 141381ad6265SDimitry Andric MachineInstr *BranchMI = getLoopendBlockBranchInstr(ExitingMBB); 141481ad6265SDimitry Andric assert(BranchMI && isCondBranch(BranchMI)); 141581ad6265SDimitry Andric DebugLoc DL = BranchMI->getDebugLoc(); 141681ad6265SDimitry Andric MachineBasicBlock *TrueBranch = getTrueBranch(BranchMI); 141781ad6265SDimitry Andric MachineBasicBlock::iterator I = BranchMI; 141881ad6265SDimitry Andric if (TrueBranch != LandMBB) 141981ad6265SDimitry Andric reversePredicateSetter(I, *I->getParent()); 142081ad6265SDimitry Andric insertCondBranchBefore(ExitingMBB, I, R600::IF_PREDICATE_SET, R600::PREDICATE_BIT, DL); 142181ad6265SDimitry Andric insertInstrBefore(I, R600::BREAK); 142281ad6265SDimitry Andric insertInstrBefore(I, R600::ENDIF); 142381ad6265SDimitry Andric //now branchInst can be erase safely 142481ad6265SDimitry Andric BranchMI->eraseFromParent(); 142581ad6265SDimitry Andric //now take care of successors, retire blocks 142681ad6265SDimitry Andric ExitingMBB->removeSuccessor(LandMBB, true); 142781ad6265SDimitry Andric } 142881ad6265SDimitry Andric 142981ad6265SDimitry Andric void R600MachineCFGStructurizer::settleLoopcontBlock(MachineBasicBlock *ContingMBB, 143081ad6265SDimitry Andric MachineBasicBlock *ContMBB) { 143181ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "settleLoopcontBlock conting = BB" 143281ad6265SDimitry Andric << ContingMBB->getNumber() << ", cont = BB" 143381ad6265SDimitry Andric << ContMBB->getNumber() << "\n";); 143481ad6265SDimitry Andric 143581ad6265SDimitry Andric MachineInstr *MI = getLoopendBlockBranchInstr(ContingMBB); 143681ad6265SDimitry Andric if (MI) { 143781ad6265SDimitry Andric assert(isCondBranch(MI)); 143881ad6265SDimitry Andric MachineBasicBlock::iterator I = MI; 143981ad6265SDimitry Andric MachineBasicBlock *TrueBranch = getTrueBranch(MI); 144081ad6265SDimitry Andric int OldOpcode = MI->getOpcode(); 144181ad6265SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 144281ad6265SDimitry Andric 144381ad6265SDimitry Andric bool UseContinueLogical = ((&*ContingMBB->rbegin()) == MI); 144481ad6265SDimitry Andric 144581ad6265SDimitry Andric if (!UseContinueLogical) { 144681ad6265SDimitry Andric int BranchOpcode = 144781ad6265SDimitry Andric TrueBranch == ContMBB ? getBranchNzeroOpcode(OldOpcode) : 144881ad6265SDimitry Andric getBranchZeroOpcode(OldOpcode); 144981ad6265SDimitry Andric insertCondBranchBefore(I, BranchOpcode, DL); 145081ad6265SDimitry Andric // insertEnd to ensure phi-moves, if exist, go before the continue-instr. 145181ad6265SDimitry Andric insertInstrEnd(ContingMBB, R600::CONTINUE, DL); 145281ad6265SDimitry Andric insertInstrEnd(ContingMBB, R600::ENDIF, DL); 145381ad6265SDimitry Andric } else { 145481ad6265SDimitry Andric int BranchOpcode = 145581ad6265SDimitry Andric TrueBranch == ContMBB ? getContinueNzeroOpcode(OldOpcode) : 145681ad6265SDimitry Andric getContinueZeroOpcode(OldOpcode); 145781ad6265SDimitry Andric insertCondBranchBefore(I, BranchOpcode, DL); 145881ad6265SDimitry Andric } 145981ad6265SDimitry Andric 146081ad6265SDimitry Andric MI->eraseFromParent(); 146181ad6265SDimitry Andric } else { 146281ad6265SDimitry Andric // if we've arrived here then we've already erased the branch instruction 146381ad6265SDimitry Andric // travel back up the basic block to see the last reference of our debug 146481ad6265SDimitry Andric // location we've just inserted that reference here so it should be 146581ad6265SDimitry Andric // representative insertEnd to ensure phi-moves, if exist, go before the 146681ad6265SDimitry Andric // continue-instr. 146781ad6265SDimitry Andric insertInstrEnd(ContingMBB, R600::CONTINUE, 146881ad6265SDimitry Andric getLastDebugLocInBB(ContingMBB)); 146981ad6265SDimitry Andric } 147081ad6265SDimitry Andric } 147181ad6265SDimitry Andric 147281ad6265SDimitry Andric int R600MachineCFGStructurizer::cloneOnSideEntryTo(MachineBasicBlock *PreMBB, 147381ad6265SDimitry Andric MachineBasicBlock *SrcMBB, MachineBasicBlock *DstMBB) { 147481ad6265SDimitry Andric int Cloned = 0; 147581ad6265SDimitry Andric assert(PreMBB->isSuccessor(SrcMBB)); 147681ad6265SDimitry Andric while (SrcMBB && SrcMBB != DstMBB) { 147781ad6265SDimitry Andric assert(SrcMBB->succ_size() == 1); 147881ad6265SDimitry Andric if (SrcMBB->pred_size() > 1) { 147981ad6265SDimitry Andric SrcMBB = cloneBlockForPredecessor(SrcMBB, PreMBB); 148081ad6265SDimitry Andric ++Cloned; 148181ad6265SDimitry Andric } 148281ad6265SDimitry Andric 148381ad6265SDimitry Andric PreMBB = SrcMBB; 148481ad6265SDimitry Andric SrcMBB = *SrcMBB->succ_begin(); 148581ad6265SDimitry Andric } 148681ad6265SDimitry Andric 148781ad6265SDimitry Andric return Cloned; 148881ad6265SDimitry Andric } 148981ad6265SDimitry Andric 149081ad6265SDimitry Andric MachineBasicBlock * 149181ad6265SDimitry Andric R600MachineCFGStructurizer::cloneBlockForPredecessor(MachineBasicBlock *MBB, 149281ad6265SDimitry Andric MachineBasicBlock *PredMBB) { 149381ad6265SDimitry Andric assert(PredMBB->isSuccessor(MBB) && "succBlk is not a predecessor of curBlk"); 149481ad6265SDimitry Andric 149581ad6265SDimitry Andric MachineBasicBlock *CloneMBB = clone(MBB); //clone instructions 149681ad6265SDimitry Andric replaceInstrUseOfBlockWith(PredMBB, MBB, CloneMBB); 149781ad6265SDimitry Andric //srcBlk, oldBlk, newBlk 149881ad6265SDimitry Andric 149981ad6265SDimitry Andric PredMBB->replaceSuccessor(MBB, CloneMBB); 150081ad6265SDimitry Andric 150181ad6265SDimitry Andric // add all successor to cloneBlk 150281ad6265SDimitry Andric cloneSuccessorList(CloneMBB, MBB); 150381ad6265SDimitry Andric 150481ad6265SDimitry Andric numClonedInstr += MBB->size(); 150581ad6265SDimitry Andric 150681ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Cloned block: " 150781ad6265SDimitry Andric << "BB" << MBB->getNumber() << "size " << MBB->size() 150881ad6265SDimitry Andric << "\n";); 150981ad6265SDimitry Andric 151081ad6265SDimitry Andric SHOWNEWBLK(CloneMBB, "result of Cloned block: "); 151181ad6265SDimitry Andric 151281ad6265SDimitry Andric return CloneMBB; 151381ad6265SDimitry Andric } 151481ad6265SDimitry Andric 151581ad6265SDimitry Andric void R600MachineCFGStructurizer::migrateInstruction(MachineBasicBlock *SrcMBB, 151681ad6265SDimitry Andric MachineBasicBlock *DstMBB, MachineBasicBlock::iterator I) { 151781ad6265SDimitry Andric MachineBasicBlock::iterator SpliceEnd; 151881ad6265SDimitry Andric //look for the input branchinstr, not the AMDGPU branchinstr 151981ad6265SDimitry Andric MachineInstr *BranchMI = getNormalBlockBranchInstr(SrcMBB); 152081ad6265SDimitry Andric if (!BranchMI) { 152181ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "migrateInstruction don't see branch instr\n";); 152281ad6265SDimitry Andric SpliceEnd = SrcMBB->end(); 152381ad6265SDimitry Andric } else { 152481ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "migrateInstruction see branch instr: " << *BranchMI); 152581ad6265SDimitry Andric SpliceEnd = BranchMI; 152681ad6265SDimitry Andric } 152781ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "migrateInstruction before splice dstSize = " 152881ad6265SDimitry Andric << DstMBB->size() << "srcSize = " << SrcMBB->size() 152981ad6265SDimitry Andric << "\n";); 153081ad6265SDimitry Andric 153181ad6265SDimitry Andric //splice insert before insertPos 153281ad6265SDimitry Andric DstMBB->splice(I, SrcMBB, SrcMBB->begin(), SpliceEnd); 153381ad6265SDimitry Andric 153481ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "migrateInstruction after splice dstSize = " 153581ad6265SDimitry Andric << DstMBB->size() << "srcSize = " << SrcMBB->size() 153681ad6265SDimitry Andric << '\n';); 153781ad6265SDimitry Andric } 153881ad6265SDimitry Andric 153981ad6265SDimitry Andric MachineBasicBlock * 154081ad6265SDimitry Andric R600MachineCFGStructurizer::normalizeInfiniteLoopExit(MachineLoop* LoopRep) { 154181ad6265SDimitry Andric MachineBasicBlock *LoopHeader = LoopRep->getHeader(); 154281ad6265SDimitry Andric MachineBasicBlock *LoopLatch = LoopRep->getLoopLatch(); 154381ad6265SDimitry Andric 154481ad6265SDimitry Andric if (!LoopHeader || !LoopLatch) 154581ad6265SDimitry Andric return nullptr; 154681ad6265SDimitry Andric MachineInstr *BranchMI = getLoopendBlockBranchInstr(LoopLatch); 154781ad6265SDimitry Andric // Is LoopRep an infinite loop ? 154881ad6265SDimitry Andric if (!BranchMI || !isUncondBranch(BranchMI)) 154981ad6265SDimitry Andric return nullptr; 155081ad6265SDimitry Andric 155181ad6265SDimitry Andric MachineBasicBlock *DummyExitBlk = FuncRep->CreateMachineBasicBlock(); 155281ad6265SDimitry Andric FuncRep->push_back(DummyExitBlk); //insert to function 155381ad6265SDimitry Andric SHOWNEWBLK(DummyExitBlk, "DummyExitBlock to normalize infiniteLoop: "); 155481ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Old branch instr: " << *BranchMI << "\n";); 155581ad6265SDimitry Andric LLVMContext &Ctx = LoopHeader->getParent()->getFunction().getContext(); 155681ad6265SDimitry Andric Ctx.emitError("Extra register needed to handle CFG"); 155781ad6265SDimitry Andric return nullptr; 155881ad6265SDimitry Andric } 155981ad6265SDimitry Andric 156081ad6265SDimitry Andric void R600MachineCFGStructurizer::removeUnconditionalBranch(MachineBasicBlock *MBB) { 156181ad6265SDimitry Andric MachineInstr *BranchMI; 156281ad6265SDimitry Andric 156381ad6265SDimitry Andric // I saw two unconditional branch in one basic block in example 156481ad6265SDimitry Andric // test_fc_do_while_or.c need to fix the upstream on this to remove the loop. 156581ad6265SDimitry Andric while ((BranchMI = getLoopendBlockBranchInstr(MBB)) 156681ad6265SDimitry Andric && isUncondBranch(BranchMI)) { 156781ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Removing uncond branch instr: " << *BranchMI); 156881ad6265SDimitry Andric BranchMI->eraseFromParent(); 156981ad6265SDimitry Andric } 157081ad6265SDimitry Andric } 157181ad6265SDimitry Andric 157281ad6265SDimitry Andric void R600MachineCFGStructurizer::removeRedundantConditionalBranch( 157381ad6265SDimitry Andric MachineBasicBlock *MBB) { 157481ad6265SDimitry Andric if (MBB->succ_size() != 2) 157581ad6265SDimitry Andric return; 157681ad6265SDimitry Andric MachineBasicBlock *MBB1 = *MBB->succ_begin(); 157781ad6265SDimitry Andric MachineBasicBlock *MBB2 = *std::next(MBB->succ_begin()); 157881ad6265SDimitry Andric if (MBB1 != MBB2) 157981ad6265SDimitry Andric return; 158081ad6265SDimitry Andric 158181ad6265SDimitry Andric MachineInstr *BranchMI = getNormalBlockBranchInstr(MBB); 158281ad6265SDimitry Andric assert(BranchMI && isCondBranch(BranchMI)); 158381ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Removing unneeded cond branch instr: " << *BranchMI); 158481ad6265SDimitry Andric BranchMI->eraseFromParent(); 158581ad6265SDimitry Andric SHOWNEWBLK(MBB1, "Removing redundant successor"); 158681ad6265SDimitry Andric MBB->removeSuccessor(MBB1, true); 158781ad6265SDimitry Andric } 158881ad6265SDimitry Andric 158981ad6265SDimitry Andric void R600MachineCFGStructurizer::addDummyExitBlock( 159081ad6265SDimitry Andric SmallVectorImpl<MachineBasicBlock*> &RetMBB) { 159181ad6265SDimitry Andric MachineBasicBlock *DummyExitBlk = FuncRep->CreateMachineBasicBlock(); 159281ad6265SDimitry Andric FuncRep->push_back(DummyExitBlk); //insert to function 159381ad6265SDimitry Andric insertInstrEnd(DummyExitBlk, R600::RETURN); 159481ad6265SDimitry Andric 159581ad6265SDimitry Andric for (MachineBasicBlock *MBB : RetMBB) { 159681ad6265SDimitry Andric if (MachineInstr *MI = getReturnInstr(MBB)) 159781ad6265SDimitry Andric MI->eraseFromParent(); 159881ad6265SDimitry Andric MBB->addSuccessor(DummyExitBlk); 159981ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Add dummyExitBlock to BB" << MBB->getNumber() 160081ad6265SDimitry Andric << " successors\n";); 160181ad6265SDimitry Andric } 160281ad6265SDimitry Andric SHOWNEWBLK(DummyExitBlk, "DummyExitBlock: "); 160381ad6265SDimitry Andric } 160481ad6265SDimitry Andric 160581ad6265SDimitry Andric void R600MachineCFGStructurizer::removeSuccessor(MachineBasicBlock *MBB) { 160681ad6265SDimitry Andric while (MBB->succ_size()) 160781ad6265SDimitry Andric MBB->removeSuccessor(*MBB->succ_begin()); 160881ad6265SDimitry Andric } 160981ad6265SDimitry Andric 161081ad6265SDimitry Andric void R600MachineCFGStructurizer::recordSccnum(MachineBasicBlock *MBB, 161181ad6265SDimitry Andric int SccNum) { 161281ad6265SDimitry Andric BlockInformation *&srcBlkInfo = BlockInfoMap[MBB]; 161381ad6265SDimitry Andric if (!srcBlkInfo) 161481ad6265SDimitry Andric srcBlkInfo = new BlockInformation(); 161581ad6265SDimitry Andric srcBlkInfo->SccNum = SccNum; 161681ad6265SDimitry Andric } 161781ad6265SDimitry Andric 161881ad6265SDimitry Andric void R600MachineCFGStructurizer::retireBlock(MachineBasicBlock *MBB) { 161981ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Retiring BB" << MBB->getNumber() << "\n";); 162081ad6265SDimitry Andric 162181ad6265SDimitry Andric BlockInformation *&SrcBlkInfo = BlockInfoMap[MBB]; 162281ad6265SDimitry Andric 162381ad6265SDimitry Andric if (!SrcBlkInfo) 162481ad6265SDimitry Andric SrcBlkInfo = new BlockInformation(); 162581ad6265SDimitry Andric 162681ad6265SDimitry Andric SrcBlkInfo->IsRetired = true; 162781ad6265SDimitry Andric assert(MBB->succ_empty() && MBB->pred_empty() && "can't retire block yet"); 162881ad6265SDimitry Andric } 162981ad6265SDimitry Andric 163081ad6265SDimitry Andric INITIALIZE_PASS_BEGIN(R600MachineCFGStructurizer, "amdgpustructurizer", 163181ad6265SDimitry Andric "AMDGPU CFG Structurizer", false, false) 1632*0fca6ea1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass) 1633*0fca6ea1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachinePostDominatorTreeWrapperPass) 1634*0fca6ea1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineLoopInfoWrapperPass) 163581ad6265SDimitry Andric INITIALIZE_PASS_END(R600MachineCFGStructurizer, "amdgpustructurizer", 163681ad6265SDimitry Andric "AMDGPU CFG Structurizer", false, false) 163781ad6265SDimitry Andric 163881ad6265SDimitry Andric FunctionPass *llvm::createR600MachineCFGStructurizerPass() { 163981ad6265SDimitry Andric return new R600MachineCFGStructurizer(); 164081ad6265SDimitry Andric } 1641