mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-29 13:29:28 +00:00
utils/sort_includes.py script. Most of these are updating the new R600 target and fixing up a few regressions that have creeped in since the last time I sorted the includes. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@171362 91177308-0d34-0410-b5e6-96231b3b80d8
3050 lines
98 KiB
C++
3050 lines
98 KiB
C++
//===-- AMDILCFGStructurizer.cpp - CFG Structurizer -----------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
/// \file
|
|
//==-----------------------------------------------------------------------===//
|
|
|
|
#define DEBUGME 0
|
|
#define DEBUG_TYPE "structcfg"
|
|
|
|
#include "AMDGPUInstrInfo.h"
|
|
#include "AMDIL.h"
|
|
#include "llvm/ADT/SCCIterator.h"
|
|
#include "llvm/ADT/SmallVector.h"
|
|
#include "llvm/ADT/Statistic.h"
|
|
#include "llvm/Analysis/DominatorInternals.h"
|
|
#include "llvm/Analysis/Dominators.h"
|
|
#include "llvm/CodeGen/MachineDominators.h"
|
|
#include "llvm/CodeGen/MachineFunction.h"
|
|
#include "llvm/CodeGen/MachineFunctionAnalysis.h"
|
|
#include "llvm/CodeGen/MachineFunctionPass.h"
|
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
|
#include "llvm/CodeGen/MachineJumpTableInfo.h"
|
|
#include "llvm/CodeGen/MachineLoopInfo.h"
|
|
#include "llvm/CodeGen/MachinePostDominators.h"
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
|
#include "llvm/Target/TargetInstrInfo.h"
|
|
|
|
using namespace llvm;
|
|
|
|
// TODO: move-begin.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Statistics for CFGStructurizer.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
STATISTIC(numSerialPatternMatch, "CFGStructurizer number of serial pattern "
|
|
"matched");
|
|
STATISTIC(numIfPatternMatch, "CFGStructurizer number of if pattern "
|
|
"matched");
|
|
STATISTIC(numLoopbreakPatternMatch, "CFGStructurizer number of loop-break "
|
|
"pattern matched");
|
|
STATISTIC(numLoopcontPatternMatch, "CFGStructurizer number of loop-continue "
|
|
"pattern matched");
|
|
STATISTIC(numLoopPatternMatch, "CFGStructurizer number of loop pattern "
|
|
"matched");
|
|
STATISTIC(numClonedBlock, "CFGStructurizer cloned blocks");
|
|
STATISTIC(numClonedInstr, "CFGStructurizer cloned instructions");
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Miscellaneous utility for CFGStructurizer.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
namespace llvmCFGStruct {
|
|
#define SHOWNEWINSTR(i) \
|
|
if (DEBUGME) errs() << "New instr: " << *i << "\n"
|
|
|
|
#define SHOWNEWBLK(b, msg) \
|
|
if (DEBUGME) { \
|
|
errs() << msg << "BB" << b->getNumber() << "size " << b->size(); \
|
|
errs() << "\n"; \
|
|
}
|
|
|
|
#define SHOWBLK_DETAIL(b, msg) \
|
|
if (DEBUGME) { \
|
|
if (b) { \
|
|
errs() << msg << "BB" << b->getNumber() << "size " << b->size(); \
|
|
b->print(errs()); \
|
|
errs() << "\n"; \
|
|
} \
|
|
}
|
|
|
|
#define INVALIDSCCNUM -1
|
|
#define INVALIDREGNUM 0
|
|
|
|
template<class LoopinfoT>
|
|
void PrintLoopinfo(const LoopinfoT &LoopInfo, llvm::raw_ostream &OS) {
|
|
for (typename LoopinfoT::iterator iter = LoopInfo.begin(),
|
|
iterEnd = LoopInfo.end();
|
|
iter != iterEnd; ++iter) {
|
|
(*iter)->print(OS, 0);
|
|
}
|
|
}
|
|
|
|
template<class NodeT>
|
|
void ReverseVector(SmallVector<NodeT *, DEFAULT_VEC_SLOTS> &Src) {
|
|
size_t sz = Src.size();
|
|
for (size_t i = 0; i < sz/2; ++i) {
|
|
NodeT *t = Src[i];
|
|
Src[i] = Src[sz - i - 1];
|
|
Src[sz - i - 1] = t;
|
|
}
|
|
}
|
|
|
|
} //end namespace llvmCFGStruct
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// supporting data structure for CFGStructurizer
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
namespace llvmCFGStruct {
|
|
template<class PassT>
|
|
struct CFGStructTraits {
|
|
};
|
|
|
|
template <class InstrT>
|
|
class BlockInformation {
|
|
public:
|
|
bool isRetired;
|
|
int sccNum;
|
|
//SmallVector<InstrT*, DEFAULT_VEC_SLOTS> succInstr;
|
|
//Instructions defining the corresponding successor.
|
|
BlockInformation() : isRetired(false), sccNum(INVALIDSCCNUM) {}
|
|
};
|
|
|
|
template <class BlockT, class InstrT, class RegiT>
|
|
class LandInformation {
|
|
public:
|
|
BlockT *landBlk;
|
|
std::set<RegiT> breakInitRegs; //Registers that need to "reg = 0", before
|
|
//WHILELOOP(thisloop) init before entering
|
|
//thisloop.
|
|
std::set<RegiT> contInitRegs; //Registers that need to "reg = 0", after
|
|
//WHILELOOP(thisloop) init after entering
|
|
//thisloop.
|
|
std::set<RegiT> endbranchInitRegs; //Init before entering this loop, at loop
|
|
//land block, branch cond on this reg.
|
|
std::set<RegiT> breakOnRegs; //registers that need to "if (reg) break
|
|
//endif" after ENDLOOP(thisloop) break
|
|
//outerLoopOf(thisLoop).
|
|
std::set<RegiT> contOnRegs; //registers that need to "if (reg) continue
|
|
//endif" after ENDLOOP(thisloop) continue on
|
|
//outerLoopOf(thisLoop).
|
|
LandInformation() : landBlk(NULL) {}
|
|
};
|
|
|
|
} //end of namespace llvmCFGStruct
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// CFGStructurizer
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
namespace llvmCFGStruct {
|
|
// bixia TODO: port it to BasicBlock, not just MachineBasicBlock.
|
|
template<class PassT>
|
|
class CFGStructurizer {
|
|
public:
|
|
typedef enum {
|
|
Not_SinglePath = 0,
|
|
SinglePath_InPath = 1,
|
|
SinglePath_NotInPath = 2
|
|
} PathToKind;
|
|
|
|
public:
|
|
typedef typename PassT::InstructionType InstrT;
|
|
typedef typename PassT::FunctionType FuncT;
|
|
typedef typename PassT::DominatortreeType DomTreeT;
|
|
typedef typename PassT::PostDominatortreeType PostDomTreeT;
|
|
typedef typename PassT::DomTreeNodeType DomTreeNodeT;
|
|
typedef typename PassT::LoopinfoType LoopInfoT;
|
|
|
|
typedef GraphTraits<FuncT *> FuncGTraits;
|
|
//typedef FuncGTraits::nodes_iterator BlockIterator;
|
|
typedef typename FuncT::iterator BlockIterator;
|
|
|
|
typedef typename FuncGTraits::NodeType BlockT;
|
|
typedef GraphTraits<BlockT *> BlockGTraits;
|
|
typedef GraphTraits<Inverse<BlockT *> > InvBlockGTraits;
|
|
//typedef BlockGTraits::succ_iterator InstructionIterator;
|
|
typedef typename BlockT::iterator InstrIterator;
|
|
|
|
typedef CFGStructTraits<PassT> CFGTraits;
|
|
typedef BlockInformation<InstrT> BlockInfo;
|
|
typedef std::map<BlockT *, BlockInfo *> BlockInfoMap;
|
|
|
|
typedef int RegiT;
|
|
typedef typename PassT::LoopType LoopT;
|
|
typedef LandInformation<BlockT, InstrT, RegiT> LoopLandInfo;
|
|
typedef std::map<LoopT *, LoopLandInfo *> LoopLandInfoMap;
|
|
//landing info for loop break
|
|
typedef SmallVector<BlockT *, 32> BlockTSmallerVector;
|
|
|
|
public:
|
|
CFGStructurizer();
|
|
~CFGStructurizer();
|
|
|
|
/// Perform the CFG structurization
|
|
bool run(FuncT &Func, PassT &Pass, const AMDGPURegisterInfo *tri);
|
|
|
|
/// Perform the CFG preparation
|
|
bool prepare(FuncT &Func, PassT &Pass, const AMDGPURegisterInfo *tri);
|
|
|
|
private:
|
|
void reversePredicateSetter(typename BlockT::iterator);
|
|
void orderBlocks();
|
|
void printOrderedBlocks(llvm::raw_ostream &OS);
|
|
int patternMatch(BlockT *CurBlock);
|
|
int patternMatchGroup(BlockT *CurBlock);
|
|
|
|
int serialPatternMatch(BlockT *CurBlock);
|
|
int ifPatternMatch(BlockT *CurBlock);
|
|
int switchPatternMatch(BlockT *CurBlock);
|
|
int loopendPatternMatch(BlockT *CurBlock);
|
|
int loopPatternMatch(BlockT *CurBlock);
|
|
|
|
int loopbreakPatternMatch(LoopT *LoopRep, BlockT *LoopHeader);
|
|
int loopcontPatternMatch(LoopT *LoopRep, BlockT *LoopHeader);
|
|
//int loopWithoutBreak(BlockT *);
|
|
|
|
void handleLoopbreak (BlockT *ExitingBlock, LoopT *ExitingLoop,
|
|
BlockT *ExitBlock, LoopT *exitLoop, BlockT *landBlock);
|
|
void handleLoopcontBlock(BlockT *ContingBlock, LoopT *contingLoop,
|
|
BlockT *ContBlock, LoopT *contLoop);
|
|
bool isSameloopDetachedContbreak(BlockT *Src1Block, BlockT *Src2Block);
|
|
int handleJumpintoIf(BlockT *HeadBlock, BlockT *TrueBlock,
|
|
BlockT *FalseBlock);
|
|
int handleJumpintoIfImp(BlockT *HeadBlock, BlockT *TrueBlock,
|
|
BlockT *FalseBlock);
|
|
int improveSimpleJumpintoIf(BlockT *HeadBlock, BlockT *TrueBlock,
|
|
BlockT *FalseBlock, BlockT **LandBlockPtr);
|
|
void showImproveSimpleJumpintoIf(BlockT *HeadBlock, BlockT *TrueBlock,
|
|
BlockT *FalseBlock, BlockT *LandBlock,
|
|
bool Detail = false);
|
|
PathToKind singlePathTo(BlockT *SrcBlock, BlockT *DstBlock,
|
|
bool AllowSideEntry = true);
|
|
BlockT *singlePathEnd(BlockT *srcBlock, BlockT *DstBlock,
|
|
bool AllowSideEntry = true);
|
|
int cloneOnSideEntryTo(BlockT *PreBlock, BlockT *SrcBlock, BlockT *DstBlock);
|
|
void mergeSerialBlock(BlockT *DstBlock, BlockT *srcBlock);
|
|
|
|
void mergeIfthenelseBlock(InstrT *BranchInstr, BlockT *CurBlock,
|
|
BlockT *TrueBlock, BlockT *FalseBlock,
|
|
BlockT *LandBlock);
|
|
void mergeLooplandBlock(BlockT *DstBlock, LoopLandInfo *LoopLand);
|
|
void mergeLoopbreakBlock(BlockT *ExitingBlock, BlockT *ExitBlock,
|
|
BlockT *ExitLandBlock, RegiT SetReg);
|
|
void settleLoopcontBlock(BlockT *ContingBlock, BlockT *ContBlock,
|
|
RegiT SetReg);
|
|
BlockT *relocateLoopcontBlock(LoopT *ParentLoopRep, LoopT *LoopRep,
|
|
std::set<BlockT*> &ExitBlockSet,
|
|
BlockT *ExitLandBlk);
|
|
BlockT *addLoopEndbranchBlock(LoopT *LoopRep,
|
|
BlockTSmallerVector &ExitingBlocks,
|
|
BlockTSmallerVector &ExitBlocks);
|
|
BlockT *normalizeInfiniteLoopExit(LoopT *LoopRep);
|
|
void removeUnconditionalBranch(BlockT *SrcBlock);
|
|
void removeRedundantConditionalBranch(BlockT *SrcBlock);
|
|
void addDummyExitBlock(SmallVector<BlockT *, DEFAULT_VEC_SLOTS> &RetBlocks);
|
|
|
|
void removeSuccessor(BlockT *SrcBlock);
|
|
BlockT *cloneBlockForPredecessor(BlockT *CurBlock, BlockT *PredBlock);
|
|
BlockT *exitingBlock2ExitBlock (LoopT *LoopRep, BlockT *exitingBlock);
|
|
|
|
void migrateInstruction(BlockT *SrcBlock, BlockT *DstBlock,
|
|
InstrIterator InsertPos);
|
|
|
|
void recordSccnum(BlockT *SrcBlock, int SCCNum);
|
|
int getSCCNum(BlockT *srcBlk);
|
|
|
|
void retireBlock(BlockT *DstBlock, BlockT *SrcBlock);
|
|
bool isRetiredBlock(BlockT *SrcBlock);
|
|
bool isActiveLoophead(BlockT *CurBlock);
|
|
bool needMigrateBlock(BlockT *Block);
|
|
|
|
BlockT *recordLoopLandBlock(LoopT *LoopRep, BlockT *LandBlock,
|
|
BlockTSmallerVector &exitBlocks,
|
|
std::set<BlockT*> &ExitBlockSet);
|
|
void setLoopLandBlock(LoopT *LoopRep, BlockT *Block = NULL);
|
|
BlockT *getLoopLandBlock(LoopT *LoopRep);
|
|
LoopLandInfo *getLoopLandInfo(LoopT *LoopRep);
|
|
|
|
void addLoopBreakOnReg(LoopT *LoopRep, RegiT RegNum);
|
|
void addLoopContOnReg(LoopT *LoopRep, RegiT RegNum);
|
|
void addLoopBreakInitReg(LoopT *LoopRep, RegiT RegNum);
|
|
void addLoopContInitReg(LoopT *LoopRep, RegiT RegNum);
|
|
void addLoopEndbranchInitReg(LoopT *LoopRep, RegiT RegNum);
|
|
|
|
bool hasBackEdge(BlockT *curBlock);
|
|
unsigned getLoopDepth (LoopT *LoopRep);
|
|
int countActiveBlock(
|
|
typename SmallVector<BlockT *, DEFAULT_VEC_SLOTS>::const_iterator IterStart,
|
|
typename SmallVector<BlockT *, DEFAULT_VEC_SLOTS>::const_iterator IterEnd);
|
|
BlockT *findNearestCommonPostDom(std::set<BlockT *>&);
|
|
BlockT *findNearestCommonPostDom(BlockT *Block1, BlockT *Block2);
|
|
|
|
private:
|
|
DomTreeT *domTree;
|
|
PostDomTreeT *postDomTree;
|
|
LoopInfoT *loopInfo;
|
|
PassT *passRep;
|
|
FuncT *funcRep;
|
|
|
|
BlockInfoMap blockInfoMap;
|
|
LoopLandInfoMap loopLandInfoMap;
|
|
SmallVector<BlockT *, DEFAULT_VEC_SLOTS> orderedBlks;
|
|
const AMDGPURegisterInfo *TRI;
|
|
|
|
}; //template class CFGStructurizer
|
|
|
|
template<class PassT> CFGStructurizer<PassT>::CFGStructurizer()
|
|
: domTree(NULL), postDomTree(NULL), loopInfo(NULL) {
|
|
}
|
|
|
|
template<class PassT> CFGStructurizer<PassT>::~CFGStructurizer() {
|
|
for (typename BlockInfoMap::iterator I = blockInfoMap.begin(),
|
|
E = blockInfoMap.end(); I != E; ++I) {
|
|
delete I->second;
|
|
}
|
|
}
|
|
|
|
template<class PassT>
|
|
bool CFGStructurizer<PassT>::prepare(FuncT &func, PassT &pass,
|
|
const AMDGPURegisterInfo * tri) {
|
|
passRep = &pass;
|
|
funcRep = &func;
|
|
TRI = tri;
|
|
|
|
bool changed = false;
|
|
|
|
//FIXME: if not reducible flow graph, make it so ???
|
|
|
|
if (DEBUGME) {
|
|
errs() << "AMDGPUCFGStructurizer::prepare\n";
|
|
}
|
|
|
|
loopInfo = CFGTraits::getLoopInfo(pass);
|
|
if (DEBUGME) {
|
|
errs() << "LoopInfo:\n";
|
|
PrintLoopinfo(*loopInfo, errs());
|
|
}
|
|
|
|
orderBlocks();
|
|
if (DEBUGME) {
|
|
errs() << "Ordered blocks:\n";
|
|
printOrderedBlocks(errs());
|
|
}
|
|
|
|
SmallVector<BlockT *, DEFAULT_VEC_SLOTS> retBlks;
|
|
|
|
for (typename LoopInfoT::iterator iter = loopInfo->begin(),
|
|
iterEnd = loopInfo->end();
|
|
iter != iterEnd; ++iter) {
|
|
LoopT* loopRep = (*iter);
|
|
BlockTSmallerVector exitingBlks;
|
|
loopRep->getExitingBlocks(exitingBlks);
|
|
|
|
if (exitingBlks.size() == 0) {
|
|
BlockT* dummyExitBlk = normalizeInfiniteLoopExit(loopRep);
|
|
if (dummyExitBlk != NULL)
|
|
retBlks.push_back(dummyExitBlk);
|
|
}
|
|
}
|
|
|
|
// Remove unconditional branch instr.
|
|
// Add dummy exit block iff there are multiple returns.
|
|
|
|
for (typename SmallVector<BlockT *, DEFAULT_VEC_SLOTS>::const_iterator
|
|
iterBlk = orderedBlks.begin(), iterEndBlk = orderedBlks.end();
|
|
iterBlk != iterEndBlk;
|
|
++iterBlk) {
|
|
BlockT *curBlk = *iterBlk;
|
|
removeUnconditionalBranch(curBlk);
|
|
removeRedundantConditionalBranch(curBlk);
|
|
if (CFGTraits::isReturnBlock(curBlk)) {
|
|
retBlks.push_back(curBlk);
|
|
}
|
|
assert(curBlk->succ_size() <= 2);
|
|
} //for
|
|
|
|
if (retBlks.size() >= 2) {
|
|
addDummyExitBlock(retBlks);
|
|
changed = true;
|
|
}
|
|
|
|
return changed;
|
|
} //CFGStructurizer::prepare
|
|
|
|
template<class PassT>
|
|
bool CFGStructurizer<PassT>::run(FuncT &func, PassT &pass,
|
|
const AMDGPURegisterInfo * tri) {
|
|
passRep = &pass;
|
|
funcRep = &func;
|
|
TRI = tri;
|
|
|
|
//Assume reducible CFG...
|
|
if (DEBUGME) {
|
|
errs() << "AMDGPUCFGStructurizer::run\n";
|
|
func.viewCFG();
|
|
}
|
|
|
|
domTree = CFGTraits::getDominatorTree(pass);
|
|
if (DEBUGME) {
|
|
domTree->print(errs(), (const llvm::Module*)0);
|
|
}
|
|
|
|
postDomTree = CFGTraits::getPostDominatorTree(pass);
|
|
if (DEBUGME) {
|
|
postDomTree->print(errs());
|
|
}
|
|
|
|
loopInfo = CFGTraits::getLoopInfo(pass);
|
|
if (DEBUGME) {
|
|
errs() << "LoopInfo:\n";
|
|
PrintLoopinfo(*loopInfo, errs());
|
|
}
|
|
|
|
orderBlocks();
|
|
#ifdef STRESSTEST
|
|
//Use the worse block ordering to test the algorithm.
|
|
ReverseVector(orderedBlks);
|
|
#endif
|
|
|
|
if (DEBUGME) {
|
|
errs() << "Ordered blocks:\n";
|
|
printOrderedBlocks(errs());
|
|
}
|
|
int numIter = 0;
|
|
bool finish = false;
|
|
BlockT *curBlk;
|
|
bool makeProgress = false;
|
|
int numRemainedBlk = countActiveBlock(orderedBlks.begin(),
|
|
orderedBlks.end());
|
|
|
|
do {
|
|
++numIter;
|
|
if (DEBUGME) {
|
|
errs() << "numIter = " << numIter
|
|
<< ", numRemaintedBlk = " << numRemainedBlk << "\n";
|
|
}
|
|
|
|
typename SmallVector<BlockT *, DEFAULT_VEC_SLOTS>::const_iterator
|
|
iterBlk = orderedBlks.begin();
|
|
typename SmallVector<BlockT *, DEFAULT_VEC_SLOTS>::const_iterator
|
|
iterBlkEnd = orderedBlks.end();
|
|
|
|
typename SmallVector<BlockT *, DEFAULT_VEC_SLOTS>::const_iterator
|
|
sccBeginIter = iterBlk;
|
|
BlockT *sccBeginBlk = NULL;
|
|
int sccNumBlk = 0; // The number of active blocks, init to a
|
|
// maximum possible number.
|
|
int sccNumIter; // Number of iteration in this SCC.
|
|
|
|
while (iterBlk != iterBlkEnd) {
|
|
curBlk = *iterBlk;
|
|
|
|
if (sccBeginBlk == NULL) {
|
|
sccBeginIter = iterBlk;
|
|
sccBeginBlk = curBlk;
|
|
sccNumIter = 0;
|
|
sccNumBlk = numRemainedBlk; // Init to maximum possible number.
|
|
if (DEBUGME) {
|
|
errs() << "start processing SCC" << getSCCNum(sccBeginBlk);
|
|
errs() << "\n";
|
|
}
|
|
}
|
|
|
|
if (!isRetiredBlock(curBlk)) {
|
|
patternMatch(curBlk);
|
|
}
|
|
|
|
++iterBlk;
|
|
|
|
bool contNextScc = true;
|
|
if (iterBlk == iterBlkEnd
|
|
|| getSCCNum(sccBeginBlk) != getSCCNum(*iterBlk)) {
|
|
// Just finish one scc.
|
|
++sccNumIter;
|
|
int sccRemainedNumBlk = countActiveBlock(sccBeginIter, iterBlk);
|
|
if (sccRemainedNumBlk != 1 && sccRemainedNumBlk >= sccNumBlk) {
|
|
if (DEBUGME) {
|
|
errs() << "Can't reduce SCC " << getSCCNum(curBlk)
|
|
<< ", sccNumIter = " << sccNumIter;
|
|
errs() << "doesn't make any progress\n";
|
|
}
|
|
contNextScc = true;
|
|
} else if (sccRemainedNumBlk != 1 && sccRemainedNumBlk < sccNumBlk) {
|
|
sccNumBlk = sccRemainedNumBlk;
|
|
iterBlk = sccBeginIter;
|
|
contNextScc = false;
|
|
if (DEBUGME) {
|
|
errs() << "repeat processing SCC" << getSCCNum(curBlk)
|
|
<< "sccNumIter = " << sccNumIter << "\n";
|
|
func.viewCFG();
|
|
}
|
|
} else {
|
|
// Finish the current scc.
|
|
contNextScc = true;
|
|
}
|
|
} else {
|
|
// Continue on next component in the current scc.
|
|
contNextScc = false;
|
|
}
|
|
|
|
if (contNextScc) {
|
|
sccBeginBlk = NULL;
|
|
}
|
|
} //while, "one iteration" over the function.
|
|
|
|
BlockT *entryBlk = FuncGTraits::nodes_begin(&func);
|
|
if (entryBlk->succ_size() == 0) {
|
|
finish = true;
|
|
if (DEBUGME) {
|
|
errs() << "Reduce to one block\n";
|
|
}
|
|
} else {
|
|
int newnumRemainedBlk
|
|
= countActiveBlock(orderedBlks.begin(), orderedBlks.end());
|
|
// consider cloned blocks ??
|
|
if (newnumRemainedBlk == 1 || newnumRemainedBlk < numRemainedBlk) {
|
|
makeProgress = true;
|
|
numRemainedBlk = newnumRemainedBlk;
|
|
} else {
|
|
makeProgress = false;
|
|
if (DEBUGME) {
|
|
errs() << "No progress\n";
|
|
}
|
|
}
|
|
}
|
|
} while (!finish && makeProgress);
|
|
|
|
// Misc wrap up to maintain the consistency of the Function representation.
|
|
CFGTraits::wrapup(FuncGTraits::nodes_begin(&func));
|
|
|
|
// Detach retired Block, release memory.
|
|
for (typename BlockInfoMap::iterator iterMap = blockInfoMap.begin(),
|
|
iterEndMap = blockInfoMap.end(); iterMap != iterEndMap; ++iterMap) {
|
|
if ((*iterMap).second && (*iterMap).second->isRetired) {
|
|
assert(((*iterMap).first)->getNumber() != -1);
|
|
if (DEBUGME) {
|
|
errs() << "Erase BB" << ((*iterMap).first)->getNumber() << "\n";
|
|
}
|
|
(*iterMap).first->eraseFromParent(); //Remove from the parent Function.
|
|
}
|
|
delete (*iterMap).second;
|
|
}
|
|
blockInfoMap.clear();
|
|
|
|
// clear loopLandInfoMap
|
|
for (typename LoopLandInfoMap::iterator iterMap = loopLandInfoMap.begin(),
|
|
iterEndMap = loopLandInfoMap.end(); iterMap != iterEndMap; ++iterMap) {
|
|
delete (*iterMap).second;
|
|
}
|
|
loopLandInfoMap.clear();
|
|
|
|
if (DEBUGME) {
|
|
func.viewCFG();
|
|
}
|
|
|
|
if (!finish) {
|
|
assert(!"IRREDUCIBL_CF");
|
|
}
|
|
|
|
return true;
|
|
} //CFGStructurizer::run
|
|
|
|
/// Print the ordered Blocks.
|
|
///
|
|
template<class PassT>
|
|
void CFGStructurizer<PassT>::printOrderedBlocks(llvm::raw_ostream &os) {
|
|
size_t i = 0;
|
|
for (typename SmallVector<BlockT *, DEFAULT_VEC_SLOTS>::const_iterator
|
|
iterBlk = orderedBlks.begin(), iterBlkEnd = orderedBlks.end();
|
|
iterBlk != iterBlkEnd;
|
|
++iterBlk, ++i) {
|
|
os << "BB" << (*iterBlk)->getNumber();
|
|
os << "(" << getSCCNum(*iterBlk) << "," << (*iterBlk)->size() << ")";
|
|
if (i != 0 && i % 10 == 0) {
|
|
os << "\n";
|
|
} else {
|
|
os << " ";
|
|
}
|
|
}
|
|
} //printOrderedBlocks
|
|
|
|
/// Compute the reversed DFS post order of Blocks
|
|
///
|
|
template<class PassT> void CFGStructurizer<PassT>::orderBlocks() {
|
|
int sccNum = 0;
|
|
BlockT *bb;
|
|
for (scc_iterator<FuncT *> sccIter = scc_begin(funcRep),
|
|
sccEnd = scc_end(funcRep); sccIter != sccEnd; ++sccIter, ++sccNum) {
|
|
std::vector<BlockT *> &sccNext = *sccIter;
|
|
for (typename std::vector<BlockT *>::const_iterator
|
|
blockIter = sccNext.begin(), blockEnd = sccNext.end();
|
|
blockIter != blockEnd; ++blockIter) {
|
|
bb = *blockIter;
|
|
orderedBlks.push_back(bb);
|
|
recordSccnum(bb, sccNum);
|
|
}
|
|
}
|
|
|
|
//walk through all the block in func to check for unreachable
|
|
for (BlockIterator blockIter1 = FuncGTraits::nodes_begin(funcRep),
|
|
blockEnd1 = FuncGTraits::nodes_end(funcRep);
|
|
blockIter1 != blockEnd1; ++blockIter1) {
|
|
BlockT *bb = &(*blockIter1);
|
|
sccNum = getSCCNum(bb);
|
|
if (sccNum == INVALIDSCCNUM) {
|
|
errs() << "unreachable block BB" << bb->getNumber() << "\n";
|
|
}
|
|
}
|
|
} //orderBlocks
|
|
|
|
template<class PassT> int CFGStructurizer<PassT>::patternMatch(BlockT *curBlk) {
|
|
int numMatch = 0;
|
|
int curMatch;
|
|
|
|
if (DEBUGME) {
|
|
errs() << "Begin patternMatch BB" << curBlk->getNumber() << "\n";
|
|
}
|
|
|
|
while ((curMatch = patternMatchGroup(curBlk)) > 0) {
|
|
numMatch += curMatch;
|
|
}
|
|
|
|
if (DEBUGME) {
|
|
errs() << "End patternMatch BB" << curBlk->getNumber()
|
|
<< ", numMatch = " << numMatch << "\n";
|
|
}
|
|
|
|
return numMatch;
|
|
} //patternMatch
|
|
|
|
template<class PassT>
|
|
int CFGStructurizer<PassT>::patternMatchGroup(BlockT *curBlk) {
|
|
int numMatch = 0;
|
|
numMatch += serialPatternMatch(curBlk);
|
|
numMatch += ifPatternMatch(curBlk);
|
|
numMatch += loopendPatternMatch(curBlk);
|
|
numMatch += loopPatternMatch(curBlk);
|
|
return numMatch;
|
|
}//patternMatchGroup
|
|
|
|
template<class PassT>
|
|
int CFGStructurizer<PassT>::serialPatternMatch(BlockT *curBlk) {
|
|
if (curBlk->succ_size() != 1) {
|
|
return 0;
|
|
}
|
|
|
|
BlockT *childBlk = *curBlk->succ_begin();
|
|
if (childBlk->pred_size() != 1 || isActiveLoophead(childBlk)) {
|
|
return 0;
|
|
}
|
|
|
|
mergeSerialBlock(curBlk, childBlk);
|
|
++numSerialPatternMatch;
|
|
return 1;
|
|
} //serialPatternMatch
|
|
|
|
template<class PassT>
|
|
int CFGStructurizer<PassT>::ifPatternMatch(BlockT *curBlk) {
|
|
//two edges
|
|
if (curBlk->succ_size() != 2) {
|
|
return 0;
|
|
}
|
|
|
|
if (hasBackEdge(curBlk)) {
|
|
return 0;
|
|
}
|
|
|
|
InstrT *branchInstr = CFGTraits::getNormalBlockBranchInstr(curBlk);
|
|
if (branchInstr == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
assert(CFGTraits::isCondBranch(branchInstr));
|
|
|
|
BlockT *trueBlk = CFGTraits::getTrueBranch(branchInstr);
|
|
BlockT *falseBlk = CFGTraits::getFalseBranch(curBlk, branchInstr);
|
|
BlockT *landBlk;
|
|
int cloned = 0;
|
|
|
|
// TODO: Simplify
|
|
if (trueBlk->succ_size() == 1 && falseBlk->succ_size() == 1
|
|
&& *trueBlk->succ_begin() == *falseBlk->succ_begin()) {
|
|
landBlk = *trueBlk->succ_begin();
|
|
} else if (trueBlk->succ_size() == 0 && falseBlk->succ_size() == 0) {
|
|
landBlk = NULL;
|
|
} else if (trueBlk->succ_size() == 1 && *trueBlk->succ_begin() == falseBlk) {
|
|
landBlk = falseBlk;
|
|
falseBlk = NULL;
|
|
} else if (falseBlk->succ_size() == 1
|
|
&& *falseBlk->succ_begin() == trueBlk) {
|
|
landBlk = trueBlk;
|
|
trueBlk = NULL;
|
|
} else if (falseBlk->succ_size() == 1
|
|
&& isSameloopDetachedContbreak(trueBlk, falseBlk)) {
|
|
landBlk = *falseBlk->succ_begin();
|
|
} else if (trueBlk->succ_size() == 1
|
|
&& isSameloopDetachedContbreak(falseBlk, trueBlk)) {
|
|
landBlk = *trueBlk->succ_begin();
|
|
} else {
|
|
return handleJumpintoIf(curBlk, trueBlk, falseBlk);
|
|
}
|
|
|
|
// improveSimpleJumpinfoIf can handle the case where landBlk == NULL but the
|
|
// new BB created for landBlk==NULL may introduce new challenge to the
|
|
// reduction process.
|
|
if (landBlk != NULL &&
|
|
((trueBlk && trueBlk->pred_size() > 1)
|
|
|| (falseBlk && falseBlk->pred_size() > 1))) {
|
|
cloned += improveSimpleJumpintoIf(curBlk, trueBlk, falseBlk, &landBlk);
|
|
}
|
|
|
|
if (trueBlk && trueBlk->pred_size() > 1) {
|
|
trueBlk = cloneBlockForPredecessor(trueBlk, curBlk);
|
|
++cloned;
|
|
}
|
|
|
|
if (falseBlk && falseBlk->pred_size() > 1) {
|
|
falseBlk = cloneBlockForPredecessor(falseBlk, curBlk);
|
|
++cloned;
|
|
}
|
|
|
|
mergeIfthenelseBlock(branchInstr, curBlk, trueBlk, falseBlk, landBlk);
|
|
|
|
++numIfPatternMatch;
|
|
|
|
numClonedBlock += cloned;
|
|
|
|
return 1 + cloned;
|
|
} //ifPatternMatch
|
|
|
|
template<class PassT>
|
|
int CFGStructurizer<PassT>::switchPatternMatch(BlockT *curBlk) {
|
|
return 0;
|
|
} //switchPatternMatch
|
|
|
|
template<class PassT>
|
|
int CFGStructurizer<PassT>::loopendPatternMatch(BlockT *curBlk) {
|
|
LoopT *loopRep = loopInfo->getLoopFor(curBlk);
|
|
typename std::vector<LoopT *> nestedLoops;
|
|
while (loopRep) {
|
|
nestedLoops.push_back(loopRep);
|
|
loopRep = loopRep->getParentLoop();
|
|
}
|
|
|
|
if (nestedLoops.size() == 0) {
|
|
return 0;
|
|
}
|
|
|
|
// Process nested loop outside->inside, so "continue" to a outside loop won't
|
|
// be mistaken as "break" of the current loop.
|
|
int num = 0;
|
|
for (typename std::vector<LoopT *>::reverse_iterator
|
|
iter = nestedLoops.rbegin(), iterEnd = nestedLoops.rend();
|
|
iter != iterEnd; ++iter) {
|
|
loopRep = *iter;
|
|
|
|
if (getLoopLandBlock(loopRep) != NULL) {
|
|
continue;
|
|
}
|
|
|
|
BlockT *loopHeader = loopRep->getHeader();
|
|
|
|
int numBreak = loopbreakPatternMatch(loopRep, loopHeader);
|
|
|
|
if (numBreak == -1) {
|
|
break;
|
|
}
|
|
|
|
int numCont = loopcontPatternMatch(loopRep, loopHeader);
|
|
num += numBreak + numCont;
|
|
}
|
|
|
|
return num;
|
|
} //loopendPatternMatch
|
|
|
|
template<class PassT>
|
|
int CFGStructurizer<PassT>::loopPatternMatch(BlockT *curBlk) {
|
|
if (curBlk->succ_size() != 0) {
|
|
return 0;
|
|
}
|
|
|
|
int numLoop = 0;
|
|
LoopT *loopRep = loopInfo->getLoopFor(curBlk);
|
|
while (loopRep && loopRep->getHeader() == curBlk) {
|
|
LoopLandInfo *loopLand = getLoopLandInfo(loopRep);
|
|
if (loopLand) {
|
|
BlockT *landBlk = loopLand->landBlk;
|
|
assert(landBlk);
|
|
if (!isRetiredBlock(landBlk)) {
|
|
mergeLooplandBlock(curBlk, loopLand);
|
|
++numLoop;
|
|
}
|
|
}
|
|
loopRep = loopRep->getParentLoop();
|
|
}
|
|
|
|
numLoopPatternMatch += numLoop;
|
|
|
|
return numLoop;
|
|
} //loopPatternMatch
|
|
|
|
template<class PassT>
|
|
int CFGStructurizer<PassT>::loopbreakPatternMatch(LoopT *loopRep,
|
|
BlockT *loopHeader) {
|
|
BlockTSmallerVector exitingBlks;
|
|
loopRep->getExitingBlocks(exitingBlks);
|
|
|
|
if (DEBUGME) {
|
|
errs() << "Loop has " << exitingBlks.size() << " exiting blocks\n";
|
|
}
|
|
|
|
if (exitingBlks.size() == 0) {
|
|
setLoopLandBlock(loopRep);
|
|
return 0;
|
|
}
|
|
|
|
// Compute the corresponding exitBlks and exit block set.
|
|
BlockTSmallerVector exitBlks;
|
|
std::set<BlockT *> exitBlkSet;
|
|
for (typename BlockTSmallerVector::const_iterator iter = exitingBlks.begin(),
|
|
iterEnd = exitingBlks.end(); iter != iterEnd; ++iter) {
|
|
BlockT *exitingBlk = *iter;
|
|
BlockT *exitBlk = exitingBlock2ExitBlock(loopRep, exitingBlk);
|
|
exitBlks.push_back(exitBlk);
|
|
exitBlkSet.insert(exitBlk); //non-duplicate insert
|
|
}
|
|
|
|
assert(exitBlkSet.size() > 0);
|
|
assert(exitBlks.size() == exitingBlks.size());
|
|
|
|
if (DEBUGME) {
|
|
errs() << "Loop has " << exitBlkSet.size() << " exit blocks\n";
|
|
}
|
|
|
|
// Find exitLandBlk.
|
|
BlockT *exitLandBlk = NULL;
|
|
int numCloned = 0;
|
|
int numSerial = 0;
|
|
|
|
if (exitBlkSet.size() == 1) {
|
|
exitLandBlk = *exitBlkSet.begin();
|
|
} else {
|
|
exitLandBlk = findNearestCommonPostDom(exitBlkSet);
|
|
|
|
if (exitLandBlk == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
bool allInPath = true;
|
|
bool allNotInPath = true;
|
|
for (typename std::set<BlockT*>::const_iterator
|
|
iter = exitBlkSet.begin(),
|
|
iterEnd = exitBlkSet.end();
|
|
iter != iterEnd; ++iter) {
|
|
BlockT *exitBlk = *iter;
|
|
|
|
PathToKind pathKind = singlePathTo(exitBlk, exitLandBlk, true);
|
|
if (DEBUGME) {
|
|
errs() << "BB" << exitBlk->getNumber()
|
|
<< " to BB" << exitLandBlk->getNumber() << " PathToKind="
|
|
<< pathKind << "\n";
|
|
}
|
|
|
|
allInPath = allInPath && (pathKind == SinglePath_InPath);
|
|
allNotInPath = allNotInPath && (pathKind == SinglePath_NotInPath);
|
|
|
|
if (!allInPath && !allNotInPath) {
|
|
if (DEBUGME) {
|
|
errs() << "singlePath check fail\n";
|
|
}
|
|
return -1;
|
|
}
|
|
} // check all exit blocks
|
|
|
|
if (allNotInPath) {
|
|
|
|
// TODO: Simplify, maybe separate function?
|
|
LoopT *parentLoopRep = loopRep->getParentLoop();
|
|
BlockT *parentLoopHeader = NULL;
|
|
if (parentLoopRep)
|
|
parentLoopHeader = parentLoopRep->getHeader();
|
|
|
|
if (exitLandBlk == parentLoopHeader &&
|
|
(exitLandBlk = relocateLoopcontBlock(parentLoopRep,
|
|
loopRep,
|
|
exitBlkSet,
|
|
exitLandBlk)) != NULL) {
|
|
if (DEBUGME) {
|
|
errs() << "relocateLoopcontBlock success\n";
|
|
}
|
|
} else if ((exitLandBlk = addLoopEndbranchBlock(loopRep,
|
|
exitingBlks,
|
|
exitBlks)) != NULL) {
|
|
if (DEBUGME) {
|
|
errs() << "insertEndbranchBlock success\n";
|
|
}
|
|
} else {
|
|
if (DEBUGME) {
|
|
errs() << "loop exit fail\n";
|
|
}
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
// Handle side entry to exit path.
|
|
exitBlks.clear();
|
|
exitBlkSet.clear();
|
|
for (typename BlockTSmallerVector::iterator iterExiting =
|
|
exitingBlks.begin(),
|
|
iterExitingEnd = exitingBlks.end();
|
|
iterExiting != iterExitingEnd; ++iterExiting) {
|
|
BlockT *exitingBlk = *iterExiting;
|
|
BlockT *exitBlk = exitingBlock2ExitBlock(loopRep, exitingBlk);
|
|
BlockT *newExitBlk = exitBlk;
|
|
|
|
if (exitBlk != exitLandBlk && exitBlk->pred_size() > 1) {
|
|
newExitBlk = cloneBlockForPredecessor(exitBlk, exitingBlk);
|
|
++numCloned;
|
|
}
|
|
|
|
numCloned += cloneOnSideEntryTo(exitingBlk, newExitBlk, exitLandBlk);
|
|
|
|
exitBlks.push_back(newExitBlk);
|
|
exitBlkSet.insert(newExitBlk);
|
|
}
|
|
|
|
for (typename BlockTSmallerVector::iterator iterExit = exitBlks.begin(),
|
|
iterExitEnd = exitBlks.end();
|
|
iterExit != iterExitEnd; ++iterExit) {
|
|
BlockT *exitBlk = *iterExit;
|
|
numSerial += serialPatternMatch(exitBlk);
|
|
}
|
|
|
|
for (typename BlockTSmallerVector::iterator iterExit = exitBlks.begin(),
|
|
iterExitEnd = exitBlks.end();
|
|
iterExit != iterExitEnd; ++iterExit) {
|
|
BlockT *exitBlk = *iterExit;
|
|
if (exitBlk->pred_size() > 1) {
|
|
if (exitBlk != exitLandBlk) {
|
|
return -1;
|
|
}
|
|
} else {
|
|
if (exitBlk != exitLandBlk &&
|
|
(exitBlk->succ_size() != 1 ||
|
|
*exitBlk->succ_begin() != exitLandBlk)) {
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
} // else
|
|
|
|
exitLandBlk = recordLoopLandBlock(loopRep, exitLandBlk, exitBlks, exitBlkSet);
|
|
|
|
// Fold break into the breaking block. Leverage across level breaks.
|
|
assert(exitingBlks.size() == exitBlks.size());
|
|
for (typename BlockTSmallerVector::const_iterator iterExit = exitBlks.begin(),
|
|
iterExiting = exitingBlks.begin(), iterExitEnd = exitBlks.end();
|
|
iterExit != iterExitEnd; ++iterExit, ++iterExiting) {
|
|
BlockT *exitBlk = *iterExit;
|
|
BlockT *exitingBlk = *iterExiting;
|
|
assert(exitBlk->pred_size() == 1 || exitBlk == exitLandBlk);
|
|
LoopT *exitingLoop = loopInfo->getLoopFor(exitingBlk);
|
|
handleLoopbreak(exitingBlk, exitingLoop, exitBlk, loopRep, exitLandBlk);
|
|
}
|
|
|
|
int numBreak = static_cast<int>(exitingBlks.size());
|
|
numLoopbreakPatternMatch += numBreak;
|
|
numClonedBlock += numCloned;
|
|
return numBreak + numSerial + numCloned;
|
|
} //loopbreakPatternMatch
|
|
|
|
template<class PassT>
|
|
int CFGStructurizer<PassT>::loopcontPatternMatch(LoopT *loopRep,
|
|
BlockT *loopHeader) {
|
|
int numCont = 0;
|
|
SmallVector<BlockT *, DEFAULT_VEC_SLOTS> contBlk;
|
|
for (typename InvBlockGTraits::ChildIteratorType iter =
|
|
InvBlockGTraits::child_begin(loopHeader),
|
|
iterEnd = InvBlockGTraits::child_end(loopHeader);
|
|
iter != iterEnd; ++iter) {
|
|
BlockT *curBlk = *iter;
|
|
if (loopRep->contains(curBlk)) {
|
|
handleLoopcontBlock(curBlk, loopInfo->getLoopFor(curBlk),
|
|
loopHeader, loopRep);
|
|
contBlk.push_back(curBlk);
|
|
++numCont;
|
|
}
|
|
}
|
|
|
|
for (typename SmallVector<BlockT *, DEFAULT_VEC_SLOTS>::iterator
|
|
iter = contBlk.begin(), iterEnd = contBlk.end();
|
|
iter != iterEnd; ++iter) {
|
|
(*iter)->removeSuccessor(loopHeader);
|
|
}
|
|
|
|
numLoopcontPatternMatch += numCont;
|
|
|
|
return numCont;
|
|
} //loopcontPatternMatch
|
|
|
|
|
|
template<class PassT>
|
|
bool CFGStructurizer<PassT>::isSameloopDetachedContbreak(BlockT *src1Blk,
|
|
BlockT *src2Blk) {
|
|
// return true iff src1Blk->succ_size() == 0 && src1Blk and src2Blk are in the
|
|
// same loop with LoopLandInfo without explicitly keeping track of
|
|
// loopContBlks and loopBreakBlks, this is a method to get the information.
|
|
//
|
|
if (src1Blk->succ_size() == 0) {
|
|
LoopT *loopRep = loopInfo->getLoopFor(src1Blk);
|
|
if (loopRep != NULL && loopRep == loopInfo->getLoopFor(src2Blk)) {
|
|
LoopLandInfo *&theEntry = loopLandInfoMap[loopRep];
|
|
if (theEntry != NULL) {
|
|
if (DEBUGME) {
|
|
errs() << "isLoopContBreakBlock yes src1 = BB"
|
|
<< src1Blk->getNumber()
|
|
<< " src2 = BB" << src2Blk->getNumber() << "\n";
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
} //isSameloopDetachedContbreak
|
|
|
|
template<class PassT>
|
|
int CFGStructurizer<PassT>::handleJumpintoIf(BlockT *headBlk,
|
|
BlockT *trueBlk,
|
|
BlockT *falseBlk) {
|
|
int num = handleJumpintoIfImp(headBlk, trueBlk, falseBlk);
|
|
if (num == 0) {
|
|
if (DEBUGME) {
|
|
errs() << "handleJumpintoIf swap trueBlk and FalseBlk" << "\n";
|
|
}
|
|
num = handleJumpintoIfImp(headBlk, falseBlk, trueBlk);
|
|
}
|
|
return num;
|
|
}
|
|
|
|
template<class PassT>
|
|
int CFGStructurizer<PassT>::handleJumpintoIfImp(BlockT *headBlk,
|
|
BlockT *trueBlk,
|
|
BlockT *falseBlk) {
|
|
int num = 0;
|
|
BlockT *downBlk;
|
|
|
|
//trueBlk could be the common post dominator
|
|
downBlk = trueBlk;
|
|
|
|
if (DEBUGME) {
|
|
errs() << "handleJumpintoIfImp head = BB" << headBlk->getNumber()
|
|
<< " true = BB" << trueBlk->getNumber()
|
|
<< ", numSucc=" << trueBlk->succ_size()
|
|
<< " false = BB" << falseBlk->getNumber() << "\n";
|
|
}
|
|
|
|
while (downBlk) {
|
|
if (DEBUGME) {
|
|
errs() << "check down = BB" << downBlk->getNumber();
|
|
}
|
|
|
|
if (singlePathTo(falseBlk, downBlk) == SinglePath_InPath) {
|
|
if (DEBUGME) {
|
|
errs() << " working\n";
|
|
}
|
|
|
|
num += cloneOnSideEntryTo(headBlk, trueBlk, downBlk);
|
|
num += cloneOnSideEntryTo(headBlk, falseBlk, downBlk);
|
|
|
|
numClonedBlock += num;
|
|
num += serialPatternMatch(*headBlk->succ_begin());
|
|
num += serialPatternMatch(*(++headBlk->succ_begin()));
|
|
num += ifPatternMatch(headBlk);
|
|
assert(num > 0);
|
|
|
|
break;
|
|
}
|
|
if (DEBUGME) {
|
|
errs() << " not working\n";
|
|
}
|
|
downBlk = (downBlk->succ_size() == 1) ? (*downBlk->succ_begin()) : NULL;
|
|
} // walk down the postDomTree
|
|
|
|
return num;
|
|
} //handleJumpintoIf
|
|
|
|
template<class PassT>
|
|
void CFGStructurizer<PassT>::showImproveSimpleJumpintoIf(BlockT *headBlk,
|
|
BlockT *trueBlk,
|
|
BlockT *falseBlk,
|
|
BlockT *landBlk,
|
|
bool detail) {
|
|
errs() << "head = BB" << headBlk->getNumber()
|
|
<< " size = " << headBlk->size();
|
|
if (detail) {
|
|
errs() << "\n";
|
|
headBlk->print(errs());
|
|
errs() << "\n";
|
|
}
|
|
|
|
if (trueBlk) {
|
|
errs() << ", true = BB" << trueBlk->getNumber() << " size = "
|
|
<< trueBlk->size() << " numPred = " << trueBlk->pred_size();
|
|
if (detail) {
|
|
errs() << "\n";
|
|
trueBlk->print(errs());
|
|
errs() << "\n";
|
|
}
|
|
}
|
|
if (falseBlk) {
|
|
errs() << ", false = BB" << falseBlk->getNumber() << " size = "
|
|
<< falseBlk->size() << " numPred = " << falseBlk->pred_size();
|
|
if (detail) {
|
|
errs() << "\n";
|
|
falseBlk->print(errs());
|
|
errs() << "\n";
|
|
}
|
|
}
|
|
if (landBlk) {
|
|
errs() << ", land = BB" << landBlk->getNumber() << " size = "
|
|
<< landBlk->size() << " numPred = " << landBlk->pred_size();
|
|
if (detail) {
|
|
errs() << "\n";
|
|
landBlk->print(errs());
|
|
errs() << "\n";
|
|
}
|
|
}
|
|
|
|
errs() << "\n";
|
|
} //showImproveSimpleJumpintoIf
|
|
|
|
template<class PassT>
|
|
int CFGStructurizer<PassT>::improveSimpleJumpintoIf(BlockT *headBlk,
|
|
BlockT *trueBlk,
|
|
BlockT *falseBlk,
|
|
BlockT **plandBlk) {
|
|
bool migrateTrue = false;
|
|
bool migrateFalse = false;
|
|
|
|
BlockT *landBlk = *plandBlk;
|
|
|
|
assert((trueBlk == NULL || trueBlk->succ_size() <= 1)
|
|
&& (falseBlk == NULL || falseBlk->succ_size() <= 1));
|
|
|
|
if (trueBlk == falseBlk) {
|
|
return 0;
|
|
}
|
|
|
|
migrateTrue = needMigrateBlock(trueBlk);
|
|
migrateFalse = needMigrateBlock(falseBlk);
|
|
|
|
if (!migrateTrue && !migrateFalse) {
|
|
return 0;
|
|
}
|
|
|
|
// If we need to migrate either trueBlk and falseBlk, migrate the rest that
|
|
// have more than one predecessors. without doing this, its predecessor
|
|
// rather than headBlk will have undefined value in initReg.
|
|
if (!migrateTrue && trueBlk && trueBlk->pred_size() > 1) {
|
|
migrateTrue = true;
|
|
}
|
|
if (!migrateFalse && falseBlk && falseBlk->pred_size() > 1) {
|
|
migrateFalse = true;
|
|
}
|
|
|
|
if (DEBUGME) {
|
|
errs() << "before improveSimpleJumpintoIf: ";
|
|
showImproveSimpleJumpintoIf(headBlk, trueBlk, falseBlk, landBlk, 0);
|
|
}
|
|
|
|
// org: headBlk => if () {trueBlk} else {falseBlk} => landBlk
|
|
//
|
|
// new: headBlk => if () {initReg = 1; org trueBlk branch} else
|
|
// {initReg = 0; org falseBlk branch }
|
|
// => landBlk => if (initReg) {org trueBlk} else {org falseBlk}
|
|
// => org landBlk
|
|
// if landBlk->pred_size() > 2, put the about if-else inside
|
|
// if (initReg !=2) {...}
|
|
//
|
|
// add initReg = initVal to headBlk
|
|
|
|
const TargetRegisterClass * I32RC = TRI->getCFGStructurizerRegClass(MVT::i32);
|
|
unsigned initReg =
|
|
funcRep->getRegInfo().createVirtualRegister(I32RC);
|
|
if (!migrateTrue || !migrateFalse) {
|
|
int initVal = migrateTrue ? 0 : 1;
|
|
CFGTraits::insertAssignInstrBefore(headBlk, passRep, initReg, initVal);
|
|
}
|
|
|
|
int numNewBlk = 0;
|
|
|
|
if (landBlk == NULL) {
|
|
landBlk = funcRep->CreateMachineBasicBlock();
|
|
funcRep->push_back(landBlk); //insert to function
|
|
|
|
if (trueBlk) {
|
|
trueBlk->addSuccessor(landBlk);
|
|
} else {
|
|
headBlk->addSuccessor(landBlk);
|
|
}
|
|
|
|
if (falseBlk) {
|
|
falseBlk->addSuccessor(landBlk);
|
|
} else {
|
|
headBlk->addSuccessor(landBlk);
|
|
}
|
|
|
|
numNewBlk ++;
|
|
}
|
|
|
|
bool landBlkHasOtherPred = (landBlk->pred_size() > 2);
|
|
|
|
//insert AMDGPU::ENDIF to avoid special case "input landBlk == NULL"
|
|
typename BlockT::iterator insertPos =
|
|
CFGTraits::getInstrPos
|
|
(landBlk, CFGTraits::insertInstrBefore(landBlk, AMDGPU::ENDIF, passRep));
|
|
|
|
if (landBlkHasOtherPred) {
|
|
unsigned immReg =
|
|
funcRep->getRegInfo().createVirtualRegister(I32RC);
|
|
CFGTraits::insertAssignInstrBefore(insertPos, passRep, immReg, 2);
|
|
unsigned cmpResReg =
|
|
funcRep->getRegInfo().createVirtualRegister(I32RC);
|
|
|
|
CFGTraits::insertCompareInstrBefore(landBlk, insertPos, passRep, cmpResReg,
|
|
initReg, immReg);
|
|
CFGTraits::insertCondBranchBefore(landBlk, insertPos,
|
|
AMDGPU::IF_PREDICATE_SET, passRep,
|
|
cmpResReg, DebugLoc());
|
|
}
|
|
|
|
CFGTraits::insertCondBranchBefore(landBlk, insertPos, AMDGPU::IF_PREDICATE_SET,
|
|
passRep, initReg, DebugLoc());
|
|
|
|
if (migrateTrue) {
|
|
migrateInstruction(trueBlk, landBlk, insertPos);
|
|
// need to uncondionally insert the assignment to ensure a path from its
|
|
// predecessor rather than headBlk has valid value in initReg if
|
|
// (initVal != 1).
|
|
CFGTraits::insertAssignInstrBefore(trueBlk, passRep, initReg, 1);
|
|
}
|
|
CFGTraits::insertInstrBefore(insertPos, AMDGPU::ELSE, passRep);
|
|
|
|
if (migrateFalse) {
|
|
migrateInstruction(falseBlk, landBlk, insertPos);
|
|
// need to uncondionally insert the assignment to ensure a path from its
|
|
// predecessor rather than headBlk has valid value in initReg if
|
|
// (initVal != 0)
|
|
CFGTraits::insertAssignInstrBefore(falseBlk, passRep, initReg, 0);
|
|
}
|
|
|
|
if (landBlkHasOtherPred) {
|
|
// add endif
|
|
CFGTraits::insertInstrBefore(insertPos, AMDGPU::ENDIF, passRep);
|
|
|
|
// put initReg = 2 to other predecessors of landBlk
|
|
for (typename BlockT::pred_iterator predIter = landBlk->pred_begin(),
|
|
predIterEnd = landBlk->pred_end(); predIter != predIterEnd;
|
|
++predIter) {
|
|
BlockT *curBlk = *predIter;
|
|
if (curBlk != trueBlk && curBlk != falseBlk) {
|
|
CFGTraits::insertAssignInstrBefore(curBlk, passRep, initReg, 2);
|
|
}
|
|
} //for
|
|
}
|
|
if (DEBUGME) {
|
|
errs() << "result from improveSimpleJumpintoIf: ";
|
|
showImproveSimpleJumpintoIf(headBlk, trueBlk, falseBlk, landBlk, 0);
|
|
}
|
|
|
|
// update landBlk
|
|
*plandBlk = landBlk;
|
|
|
|
return numNewBlk;
|
|
} //improveSimpleJumpintoIf
|
|
|
|
template<class PassT>
|
|
void CFGStructurizer<PassT>::handleLoopbreak(BlockT *exitingBlk,
|
|
LoopT *exitingLoop,
|
|
BlockT *exitBlk,
|
|
LoopT *exitLoop,
|
|
BlockT *landBlk) {
|
|
if (DEBUGME) {
|
|
errs() << "Trying to break loop-depth = " << getLoopDepth(exitLoop)
|
|
<< " from loop-depth = " << getLoopDepth(exitingLoop) << "\n";
|
|
}
|
|
const TargetRegisterClass * I32RC = TRI->getCFGStructurizerRegClass(MVT::i32);
|
|
|
|
RegiT initReg = INVALIDREGNUM;
|
|
if (exitingLoop != exitLoop) {
|
|
initReg = static_cast<int>
|
|
(funcRep->getRegInfo().createVirtualRegister(I32RC));
|
|
assert(initReg != INVALIDREGNUM);
|
|
addLoopBreakInitReg(exitLoop, initReg);
|
|
while (exitingLoop != exitLoop && exitingLoop) {
|
|
addLoopBreakOnReg(exitingLoop, initReg);
|
|
exitingLoop = exitingLoop->getParentLoop();
|
|
}
|
|
assert(exitingLoop == exitLoop);
|
|
}
|
|
|
|
mergeLoopbreakBlock(exitingBlk, exitBlk, landBlk, initReg);
|
|
|
|
} //handleLoopbreak
|
|
|
|
template<class PassT>
|
|
void CFGStructurizer<PassT>::handleLoopcontBlock(BlockT *contingBlk,
|
|
LoopT *contingLoop,
|
|
BlockT *contBlk,
|
|
LoopT *contLoop) {
|
|
if (DEBUGME) {
|
|
errs() << "loopcontPattern cont = BB" << contingBlk->getNumber()
|
|
<< " header = BB" << contBlk->getNumber() << "\n";
|
|
|
|
errs() << "Trying to continue loop-depth = "
|
|
<< getLoopDepth(contLoop)
|
|
<< " from loop-depth = " << getLoopDepth(contingLoop) << "\n";
|
|
}
|
|
|
|
RegiT initReg = INVALIDREGNUM;
|
|
const TargetRegisterClass * I32RC = TRI->getCFGStructurizerRegClass(MVT::i32);
|
|
if (contingLoop != contLoop) {
|
|
initReg = static_cast<int>
|
|
(funcRep->getRegInfo().createVirtualRegister(I32RC));
|
|
assert(initReg != INVALIDREGNUM);
|
|
addLoopContInitReg(contLoop, initReg);
|
|
while (contingLoop && contingLoop->getParentLoop() != contLoop) {
|
|
addLoopBreakOnReg(contingLoop, initReg); //not addLoopContOnReg
|
|
contingLoop = contingLoop->getParentLoop();
|
|
}
|
|
assert(contingLoop && contingLoop->getParentLoop() == contLoop);
|
|
addLoopContOnReg(contingLoop, initReg);
|
|
}
|
|
|
|
settleLoopcontBlock(contingBlk, contBlk, initReg);
|
|
} //handleLoopcontBlock
|
|
|
|
template<class PassT>
|
|
void CFGStructurizer<PassT>::mergeSerialBlock(BlockT *dstBlk, BlockT *srcBlk) {
|
|
if (DEBUGME) {
|
|
errs() << "serialPattern BB" << dstBlk->getNumber()
|
|
<< " <= BB" << srcBlk->getNumber() << "\n";
|
|
}
|
|
dstBlk->splice(dstBlk->end(), srcBlk, srcBlk->begin(), srcBlk->end());
|
|
|
|
dstBlk->removeSuccessor(srcBlk);
|
|
CFGTraits::cloneSuccessorList(dstBlk, srcBlk);
|
|
|
|
removeSuccessor(srcBlk);
|
|
retireBlock(dstBlk, srcBlk);
|
|
} //mergeSerialBlock
|
|
|
|
template<class PassT>
|
|
void CFGStructurizer<PassT>::mergeIfthenelseBlock(InstrT *branchInstr,
|
|
BlockT *curBlk,
|
|
BlockT *trueBlk,
|
|
BlockT *falseBlk,
|
|
BlockT *landBlk) {
|
|
if (DEBUGME) {
|
|
errs() << "ifPattern BB" << curBlk->getNumber();
|
|
errs() << "{ ";
|
|
if (trueBlk) {
|
|
errs() << "BB" << trueBlk->getNumber();
|
|
}
|
|
errs() << " } else ";
|
|
errs() << "{ ";
|
|
if (falseBlk) {
|
|
errs() << "BB" << falseBlk->getNumber();
|
|
}
|
|
errs() << " }\n ";
|
|
errs() << "landBlock: ";
|
|
if (landBlk == NULL) {
|
|
errs() << "NULL";
|
|
} else {
|
|
errs() << "BB" << landBlk->getNumber();
|
|
}
|
|
errs() << "\n";
|
|
}
|
|
|
|
int oldOpcode = branchInstr->getOpcode();
|
|
DebugLoc branchDL = branchInstr->getDebugLoc();
|
|
|
|
// transform to
|
|
// if cond
|
|
// trueBlk
|
|
// else
|
|
// falseBlk
|
|
// endif
|
|
// landBlk
|
|
|
|
typename BlockT::iterator branchInstrPos =
|
|
CFGTraits::getInstrPos(curBlk, branchInstr);
|
|
CFGTraits::insertCondBranchBefore(branchInstrPos,
|
|
CFGTraits::getBranchNzeroOpcode(oldOpcode),
|
|
passRep,
|
|
branchDL);
|
|
|
|
if (trueBlk) {
|
|
curBlk->splice(branchInstrPos, trueBlk, trueBlk->begin(), trueBlk->end());
|
|
curBlk->removeSuccessor(trueBlk);
|
|
if (landBlk && trueBlk->succ_size()!=0) {
|
|
trueBlk->removeSuccessor(landBlk);
|
|
}
|
|
retireBlock(curBlk, trueBlk);
|
|
}
|
|
CFGTraits::insertInstrBefore(branchInstrPos, AMDGPU::ELSE, passRep);
|
|
|
|
if (falseBlk) {
|
|
curBlk->splice(branchInstrPos, falseBlk, falseBlk->begin(),
|
|
falseBlk->end());
|
|
curBlk->removeSuccessor(falseBlk);
|
|
if (landBlk && falseBlk->succ_size() != 0) {
|
|
falseBlk->removeSuccessor(landBlk);
|
|
}
|
|
retireBlock(curBlk, falseBlk);
|
|
}
|
|
CFGTraits::insertInstrBefore(branchInstrPos, AMDGPU::ENDIF, passRep);
|
|
|
|
branchInstr->eraseFromParent();
|
|
|
|
if (landBlk && trueBlk && falseBlk) {
|
|
curBlk->addSuccessor(landBlk);
|
|
}
|
|
|
|
} //mergeIfthenelseBlock
|
|
|
|
template<class PassT>
|
|
void CFGStructurizer<PassT>::mergeLooplandBlock(BlockT *dstBlk,
|
|
LoopLandInfo *loopLand) {
|
|
BlockT *landBlk = loopLand->landBlk;
|
|
|
|
if (DEBUGME) {
|
|
errs() << "loopPattern header = BB" << dstBlk->getNumber()
|
|
<< " land = BB" << landBlk->getNumber() << "\n";
|
|
}
|
|
|
|
// Loop contInitRegs are init at the beginning of the loop.
|
|
for (typename std::set<RegiT>::const_iterator iter =
|
|
loopLand->contInitRegs.begin(),
|
|
iterEnd = loopLand->contInitRegs.end(); iter != iterEnd; ++iter) {
|
|
CFGTraits::insertAssignInstrBefore(dstBlk, passRep, *iter, 0);
|
|
}
|
|
|
|
/* we last inserterd the DebugLoc in the
|
|
* BREAK_LOGICALZ_i32 or AMDGPU::BREAK_LOGICALNZ statement in the current dstBlk.
|
|
* search for the DebugLoc in the that statement.
|
|
* if not found, we have to insert the empty/default DebugLoc */
|
|
InstrT *loopBreakInstr = CFGTraits::getLoopBreakInstr(dstBlk);
|
|
DebugLoc DLBreak = (loopBreakInstr) ? loopBreakInstr->getDebugLoc() : DebugLoc();
|
|
|
|
CFGTraits::insertInstrBefore(dstBlk, AMDGPU::WHILELOOP, passRep, DLBreak);
|
|
// Loop breakInitRegs are init before entering the loop.
|
|
for (typename std::set<RegiT>::const_iterator iter =
|
|
loopLand->breakInitRegs.begin(),
|
|
iterEnd = loopLand->breakInitRegs.end(); iter != iterEnd; ++iter) {
|
|
CFGTraits::insertAssignInstrBefore(dstBlk, passRep, *iter, 0);
|
|
}
|
|
// Loop endbranchInitRegs are init before entering the loop.
|
|
for (typename std::set<RegiT>::const_iterator iter =
|
|
loopLand->endbranchInitRegs.begin(),
|
|
iterEnd = loopLand->endbranchInitRegs.end(); iter != iterEnd; ++iter) {
|
|
CFGTraits::insertAssignInstrBefore(dstBlk, passRep, *iter, 0);
|
|
}
|
|
|
|
/* we last inserterd the DebugLoc in the continue statement in the current dstBlk
|
|
* search for the DebugLoc in the continue statement.
|
|
* if not found, we have to insert the empty/default DebugLoc */
|
|
InstrT *continueInstr = CFGTraits::getContinueInstr(dstBlk);
|
|
DebugLoc DLContinue = (continueInstr) ? continueInstr->getDebugLoc() : DebugLoc();
|
|
|
|
CFGTraits::insertInstrEnd(dstBlk, AMDGPU::ENDLOOP, passRep, DLContinue);
|
|
// Loop breakOnRegs are check after the ENDLOOP: break the loop outside this
|
|
// loop.
|
|
for (typename std::set<RegiT>::const_iterator iter =
|
|
loopLand->breakOnRegs.begin(),
|
|
iterEnd = loopLand->breakOnRegs.end(); iter != iterEnd; ++iter) {
|
|
CFGTraits::insertCondBranchEnd(dstBlk, AMDGPU::PREDICATED_BREAK, passRep,
|
|
*iter);
|
|
}
|
|
|
|
// Loop contOnRegs are check after the ENDLOOP: cont the loop outside this
|
|
// loop.
|
|
for (std::set<RegiT>::const_iterator iter = loopLand->contOnRegs.begin(),
|
|
iterEnd = loopLand->contOnRegs.end(); iter != iterEnd; ++iter) {
|
|
CFGTraits::insertCondBranchEnd(dstBlk, AMDGPU::CONTINUE_LOGICALNZ_i32,
|
|
passRep, *iter);
|
|
}
|
|
|
|
dstBlk->splice(dstBlk->end(), landBlk, landBlk->begin(), landBlk->end());
|
|
|
|
for (typename BlockT::succ_iterator iter = landBlk->succ_begin(),
|
|
iterEnd = landBlk->succ_end(); iter != iterEnd; ++iter) {
|
|
dstBlk->addSuccessor(*iter); // *iter's predecessor is also taken care of.
|
|
}
|
|
|
|
removeSuccessor(landBlk);
|
|
retireBlock(dstBlk, landBlk);
|
|
} //mergeLooplandBlock
|
|
|
|
template<class PassT>
|
|
void CFGStructurizer<PassT>::reversePredicateSetter(typename BlockT::iterator I) {
|
|
while (I--) {
|
|
if (I->getOpcode() == AMDGPU::PRED_X) {
|
|
switch (static_cast<MachineInstr *>(I)->getOperand(2).getImm()) {
|
|
case OPCODE_IS_ZERO_INT:
|
|
static_cast<MachineInstr *>(I)->getOperand(2).setImm(OPCODE_IS_NOT_ZERO_INT);
|
|
return;
|
|
case OPCODE_IS_NOT_ZERO_INT:
|
|
static_cast<MachineInstr *>(I)->getOperand(2).setImm(OPCODE_IS_ZERO_INT);
|
|
return;
|
|
case OPCODE_IS_ZERO:
|
|
static_cast<MachineInstr *>(I)->getOperand(2).setImm(OPCODE_IS_NOT_ZERO);
|
|
return;
|
|
case OPCODE_IS_NOT_ZERO:
|
|
static_cast<MachineInstr *>(I)->getOperand(2).setImm(OPCODE_IS_ZERO);
|
|
return;
|
|
default:
|
|
assert(0 && "PRED_X Opcode invalid!");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template<class PassT>
|
|
void CFGStructurizer<PassT>::mergeLoopbreakBlock(BlockT *exitingBlk,
|
|
BlockT *exitBlk,
|
|
BlockT *exitLandBlk,
|
|
RegiT setReg) {
|
|
if (DEBUGME) {
|
|
errs() << "loopbreakPattern exiting = BB" << exitingBlk->getNumber()
|
|
<< " exit = BB" << exitBlk->getNumber()
|
|
<< " land = BB" << exitLandBlk->getNumber() << "\n";
|
|
}
|
|
|
|
InstrT *branchInstr = CFGTraits::getLoopendBlockBranchInstr(exitingBlk);
|
|
assert(branchInstr && CFGTraits::isCondBranch(branchInstr));
|
|
|
|
DebugLoc DL = branchInstr->getDebugLoc();
|
|
|
|
BlockT *trueBranch = CFGTraits::getTrueBranch(branchInstr);
|
|
|
|
// transform exitingBlk to
|
|
// if ( ) {
|
|
// exitBlk (if exitBlk != exitLandBlk)
|
|
// setReg = 1
|
|
// break
|
|
// }endif
|
|
// successor = {orgSuccessor(exitingBlk) - exitBlk}
|
|
|
|
typename BlockT::iterator branchInstrPos =
|
|
CFGTraits::getInstrPos(exitingBlk, branchInstr);
|
|
|
|
if (exitBlk == exitLandBlk && setReg == INVALIDREGNUM) {
|
|
//break_logical
|
|
|
|
if (trueBranch != exitBlk) {
|
|
reversePredicateSetter(branchInstrPos);
|
|
}
|
|
CFGTraits::insertCondBranchBefore(branchInstrPos, AMDGPU::PREDICATED_BREAK, passRep, DL);
|
|
} else {
|
|
if (trueBranch != exitBlk) {
|
|
reversePredicateSetter(branchInstr);
|
|
}
|
|
CFGTraits::insertCondBranchBefore(branchInstrPos, AMDGPU::PREDICATED_BREAK, passRep, DL);
|
|
if (exitBlk != exitLandBlk) {
|
|
//splice is insert-before ...
|
|
exitingBlk->splice(branchInstrPos, exitBlk, exitBlk->begin(),
|
|
exitBlk->end());
|
|
}
|
|
if (setReg != INVALIDREGNUM) {
|
|
CFGTraits::insertAssignInstrBefore(branchInstrPos, passRep, setReg, 1);
|
|
}
|
|
CFGTraits::insertInstrBefore(branchInstrPos, AMDGPU::BREAK, passRep);
|
|
} //if_logical
|
|
|
|
//now branchInst can be erase safely
|
|
branchInstr->eraseFromParent();
|
|
|
|
//now take care of successors, retire blocks
|
|
exitingBlk->removeSuccessor(exitBlk);
|
|
if (exitBlk != exitLandBlk) {
|
|
//splice is insert-before ...
|
|
exitBlk->removeSuccessor(exitLandBlk);
|
|
retireBlock(exitingBlk, exitBlk);
|
|
}
|
|
|
|
} //mergeLoopbreakBlock
|
|
|
|
template<class PassT>
|
|
void CFGStructurizer<PassT>::settleLoopcontBlock(BlockT *contingBlk,
|
|
BlockT *contBlk,
|
|
RegiT setReg) {
|
|
if (DEBUGME) {
|
|
errs() << "settleLoopcontBlock conting = BB"
|
|
<< contingBlk->getNumber()
|
|
<< ", cont = BB" << contBlk->getNumber() << "\n";
|
|
}
|
|
|
|
InstrT *branchInstr = CFGTraits::getLoopendBlockBranchInstr(contingBlk);
|
|
if (branchInstr) {
|
|
assert(CFGTraits::isCondBranch(branchInstr));
|
|
typename BlockT::iterator branchInstrPos =
|
|
CFGTraits::getInstrPos(contingBlk, branchInstr);
|
|
BlockT *trueBranch = CFGTraits::getTrueBranch(branchInstr);
|
|
int oldOpcode = branchInstr->getOpcode();
|
|
DebugLoc DL = branchInstr->getDebugLoc();
|
|
|
|
// transform contingBlk to
|
|
// if () {
|
|
// move instr after branchInstr
|
|
// continue
|
|
// or
|
|
// setReg = 1
|
|
// break
|
|
// }endif
|
|
// successor = {orgSuccessor(contingBlk) - loopHeader}
|
|
|
|
bool useContinueLogical =
|
|
(setReg == INVALIDREGNUM && (&*contingBlk->rbegin()) == branchInstr);
|
|
|
|
if (useContinueLogical == false) {
|
|
int branchOpcode =
|
|
trueBranch == contBlk ? CFGTraits::getBranchNzeroOpcode(oldOpcode)
|
|
: CFGTraits::getBranchZeroOpcode(oldOpcode);
|
|
|
|
CFGTraits::insertCondBranchBefore(branchInstrPos, branchOpcode, passRep, DL);
|
|
|
|
if (setReg != INVALIDREGNUM) {
|
|
CFGTraits::insertAssignInstrBefore(branchInstrPos, passRep, setReg, 1);
|
|
// insertEnd to ensure phi-moves, if exist, go before the continue-instr.
|
|
CFGTraits::insertInstrEnd(contingBlk, AMDGPU::BREAK, passRep, DL);
|
|
} else {
|
|
// insertEnd to ensure phi-moves, if exist, go before the continue-instr.
|
|
CFGTraits::insertInstrEnd(contingBlk, AMDGPU::CONTINUE, passRep, DL);
|
|
}
|
|
|
|
CFGTraits::insertInstrEnd(contingBlk, AMDGPU::ENDIF, passRep, DL);
|
|
} else {
|
|
int branchOpcode =
|
|
trueBranch == contBlk ? CFGTraits::getContinueNzeroOpcode(oldOpcode)
|
|
: CFGTraits::getContinueZeroOpcode(oldOpcode);
|
|
|
|
CFGTraits::insertCondBranchBefore(branchInstrPos, branchOpcode, passRep, DL);
|
|
}
|
|
|
|
branchInstr->eraseFromParent();
|
|
} else {
|
|
// if we've arrived here then we've already erased the branch instruction
|
|
// travel back up the basic block to see the last reference of our debug location
|
|
// we've just inserted that reference here so it should be representative
|
|
if (setReg != INVALIDREGNUM) {
|
|
CFGTraits::insertAssignInstrBefore(contingBlk, passRep, setReg, 1);
|
|
// insertEnd to ensure phi-moves, if exist, go before the continue-instr.
|
|
CFGTraits::insertInstrEnd(contingBlk, AMDGPU::BREAK, passRep, CFGTraits::getLastDebugLocInBB(contingBlk));
|
|
} else {
|
|
// insertEnd to ensure phi-moves, if exist, go before the continue-instr.
|
|
CFGTraits::insertInstrEnd(contingBlk, AMDGPU::CONTINUE, passRep, CFGTraits::getLastDebugLocInBB(contingBlk));
|
|
}
|
|
} //else
|
|
|
|
} //settleLoopcontBlock
|
|
|
|
// BBs in exitBlkSet are determined as in break-path for loopRep,
|
|
// before we can put code for BBs as inside loop-body for loopRep
|
|
// check whether those BBs are determined as cont-BB for parentLoopRep
|
|
// earlier.
|
|
// If so, generate a new BB newBlk
|
|
// (1) set newBlk common successor of BBs in exitBlkSet
|
|
// (2) change the continue-instr in BBs in exitBlkSet to break-instr
|
|
// (3) generate continue-instr in newBlk
|
|
//
|
|
template<class PassT>
|
|
typename CFGStructurizer<PassT>::BlockT *
|
|
CFGStructurizer<PassT>::relocateLoopcontBlock(LoopT *parentLoopRep,
|
|
LoopT *loopRep,
|
|
std::set<BlockT *> &exitBlkSet,
|
|
BlockT *exitLandBlk) {
|
|
std::set<BlockT *> endBlkSet;
|
|
|
|
|
|
|
|
for (typename std::set<BlockT *>::const_iterator iter = exitBlkSet.begin(),
|
|
iterEnd = exitBlkSet.end();
|
|
iter != iterEnd; ++iter) {
|
|
BlockT *exitBlk = *iter;
|
|
BlockT *endBlk = singlePathEnd(exitBlk, exitLandBlk);
|
|
|
|
if (endBlk == NULL || CFGTraits::getContinueInstr(endBlk) == NULL)
|
|
return NULL;
|
|
|
|
endBlkSet.insert(endBlk);
|
|
}
|
|
|
|
BlockT *newBlk = funcRep->CreateMachineBasicBlock();
|
|
funcRep->push_back(newBlk); //insert to function
|
|
CFGTraits::insertInstrEnd(newBlk, AMDGPU::CONTINUE, passRep);
|
|
SHOWNEWBLK(newBlk, "New continue block: ");
|
|
|
|
for (typename std::set<BlockT*>::const_iterator iter = endBlkSet.begin(),
|
|
iterEnd = endBlkSet.end();
|
|
iter != iterEnd; ++iter) {
|
|
BlockT *endBlk = *iter;
|
|
InstrT *contInstr = CFGTraits::getContinueInstr(endBlk);
|
|
if (contInstr) {
|
|
contInstr->eraseFromParent();
|
|
}
|
|
endBlk->addSuccessor(newBlk);
|
|
if (DEBUGME) {
|
|
errs() << "Add new continue Block to BB"
|
|
<< endBlk->getNumber() << " successors\n";
|
|
}
|
|
}
|
|
|
|
return newBlk;
|
|
} //relocateLoopcontBlock
|
|
|
|
|
|
// LoopEndbranchBlock is a BB created by the CFGStructurizer to use as
|
|
// LoopLandBlock. This BB branch on the loop endBranchInit register to the
|
|
// pathes corresponding to the loop exiting branches.
|
|
|
|
template<class PassT>
|
|
typename CFGStructurizer<PassT>::BlockT *
|
|
CFGStructurizer<PassT>::addLoopEndbranchBlock(LoopT *loopRep,
|
|
BlockTSmallerVector &exitingBlks,
|
|
BlockTSmallerVector &exitBlks) {
|
|
const AMDGPUInstrInfo *tii =
|
|
static_cast<const AMDGPUInstrInfo *>(passRep->getTargetInstrInfo());
|
|
const TargetRegisterClass * I32RC = TRI->getCFGStructurizerRegClass(MVT::i32);
|
|
|
|
RegiT endBranchReg = static_cast<int>
|
|
(funcRep->getRegInfo().createVirtualRegister(I32RC));
|
|
assert(endBranchReg >= 0);
|
|
|
|
// reg = 0 before entering the loop
|
|
addLoopEndbranchInitReg(loopRep, endBranchReg);
|
|
|
|
uint32_t numBlks = static_cast<uint32_t>(exitingBlks.size());
|
|
assert(numBlks >=2 && numBlks == exitBlks.size());
|
|
|
|
BlockT *preExitingBlk = exitingBlks[0];
|
|
BlockT *preExitBlk = exitBlks[0];
|
|
BlockT *preBranchBlk = funcRep->CreateMachineBasicBlock();
|
|
funcRep->push_back(preBranchBlk); //insert to function
|
|
SHOWNEWBLK(preBranchBlk, "New loopEndbranch block: ");
|
|
|
|
BlockT *newLandBlk = preBranchBlk;
|
|
|
|
CFGTraits::replaceInstrUseOfBlockWith(preExitingBlk, preExitBlk,
|
|
newLandBlk);
|
|
preExitingBlk->removeSuccessor(preExitBlk);
|
|
preExitingBlk->addSuccessor(newLandBlk);
|
|
|
|
//it is redundant to add reg = 0 to exitingBlks[0]
|
|
|
|
// For 1..n th exiting path (the last iteration handles two pathes) create the
|
|
// branch to the previous path and the current path.
|
|
for (uint32_t i = 1; i < numBlks; ++i) {
|
|
BlockT *curExitingBlk = exitingBlks[i];
|
|
BlockT *curExitBlk = exitBlks[i];
|
|
BlockT *curBranchBlk;
|
|
|
|
if (i == numBlks - 1) {
|
|
curBranchBlk = curExitBlk;
|
|
} else {
|
|
curBranchBlk = funcRep->CreateMachineBasicBlock();
|
|
funcRep->push_back(curBranchBlk); //insert to function
|
|
SHOWNEWBLK(curBranchBlk, "New loopEndbranch block: ");
|
|
}
|
|
|
|
// Add reg = i to exitingBlks[i].
|
|
CFGTraits::insertAssignInstrBefore(curExitingBlk, passRep,
|
|
endBranchReg, i);
|
|
|
|
// Remove the edge (exitingBlks[i] exitBlks[i]) add new edge
|
|
// (exitingBlks[i], newLandBlk).
|
|
CFGTraits::replaceInstrUseOfBlockWith(curExitingBlk, curExitBlk,
|
|
newLandBlk);
|
|
curExitingBlk->removeSuccessor(curExitBlk);
|
|
curExitingBlk->addSuccessor(newLandBlk);
|
|
|
|
// add to preBranchBlk the branch instruction:
|
|
// if (endBranchReg == preVal)
|
|
// preExitBlk
|
|
// else
|
|
// curBranchBlk
|
|
//
|
|
// preValReg = i - 1
|
|
|
|
DebugLoc DL;
|
|
RegiT preValReg = static_cast<int>
|
|
(funcRep->getRegInfo().createVirtualRegister(I32RC));
|
|
|
|
preBranchBlk->insert(preBranchBlk->begin(),
|
|
tii->getMovImmInstr(preBranchBlk->getParent(), preValReg,
|
|
i - 1));
|
|
|
|
// condResReg = (endBranchReg == preValReg)
|
|
RegiT condResReg = static_cast<int>
|
|
(funcRep->getRegInfo().createVirtualRegister(I32RC));
|
|
BuildMI(preBranchBlk, DL, tii->get(tii->getIEQOpcode()), condResReg)
|
|
.addReg(endBranchReg).addReg(preValReg);
|
|
|
|
BuildMI(preBranchBlk, DL, tii->get(AMDGPU::BRANCH_COND_i32))
|
|
.addMBB(preExitBlk).addReg(condResReg);
|
|
|
|
preBranchBlk->addSuccessor(preExitBlk);
|
|
preBranchBlk->addSuccessor(curBranchBlk);
|
|
|
|
// Update preExitingBlk, preExitBlk, preBranchBlk.
|
|
preExitingBlk = curExitingBlk;
|
|
preExitBlk = curExitBlk;
|
|
preBranchBlk = curBranchBlk;
|
|
|
|
} //end for 1 .. n blocks
|
|
|
|
return newLandBlk;
|
|
} //addLoopEndbranchBlock
|
|
|
|
template<class PassT>
|
|
typename CFGStructurizer<PassT>::PathToKind
|
|
CFGStructurizer<PassT>::singlePathTo(BlockT *srcBlk, BlockT *dstBlk,
|
|
bool allowSideEntry) {
|
|
assert(dstBlk);
|
|
|
|
if (srcBlk == dstBlk) {
|
|
return SinglePath_InPath;
|
|
}
|
|
|
|
while (srcBlk && srcBlk->succ_size() == 1) {
|
|
srcBlk = *srcBlk->succ_begin();
|
|
if (srcBlk == dstBlk) {
|
|
return SinglePath_InPath;
|
|
}
|
|
|
|
if (!allowSideEntry && srcBlk->pred_size() > 1) {
|
|
return Not_SinglePath;
|
|
}
|
|
}
|
|
|
|
if (srcBlk && srcBlk->succ_size()==0) {
|
|
return SinglePath_NotInPath;
|
|
}
|
|
|
|
return Not_SinglePath;
|
|
} //singlePathTo
|
|
|
|
// If there is a single path from srcBlk to dstBlk, return the last block before
|
|
// dstBlk If there is a single path from srcBlk->end without dstBlk, return the
|
|
// last block in the path Otherwise, return NULL
|
|
template<class PassT>
|
|
typename CFGStructurizer<PassT>::BlockT *
|
|
CFGStructurizer<PassT>::singlePathEnd(BlockT *srcBlk, BlockT *dstBlk,
|
|
bool allowSideEntry) {
|
|
assert(dstBlk);
|
|
|
|
if (srcBlk == dstBlk) {
|
|
return srcBlk;
|
|
}
|
|
|
|
if (srcBlk->succ_size() == 0) {
|
|
return srcBlk;
|
|
}
|
|
|
|
while (srcBlk && srcBlk->succ_size() == 1) {
|
|
BlockT *preBlk = srcBlk;
|
|
|
|
srcBlk = *srcBlk->succ_begin();
|
|
if (srcBlk == NULL) {
|
|
return preBlk;
|
|
}
|
|
|
|
if (!allowSideEntry && srcBlk->pred_size() > 1) {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if (srcBlk && srcBlk->succ_size()==0) {
|
|
return srcBlk;
|
|
}
|
|
|
|
return NULL;
|
|
|
|
} //singlePathEnd
|
|
|
|
template<class PassT>
|
|
int CFGStructurizer<PassT>::cloneOnSideEntryTo(BlockT *preBlk, BlockT *srcBlk,
|
|
BlockT *dstBlk) {
|
|
int cloned = 0;
|
|
assert(preBlk->isSuccessor(srcBlk));
|
|
while (srcBlk && srcBlk != dstBlk) {
|
|
assert(srcBlk->succ_size() == 1);
|
|
if (srcBlk->pred_size() > 1) {
|
|
srcBlk = cloneBlockForPredecessor(srcBlk, preBlk);
|
|
++cloned;
|
|
}
|
|
|
|
preBlk = srcBlk;
|
|
srcBlk = *srcBlk->succ_begin();
|
|
}
|
|
|
|
return cloned;
|
|
} //cloneOnSideEntryTo
|
|
|
|
template<class PassT>
|
|
typename CFGStructurizer<PassT>::BlockT *
|
|
CFGStructurizer<PassT>::cloneBlockForPredecessor(BlockT *curBlk,
|
|
BlockT *predBlk) {
|
|
assert(predBlk->isSuccessor(curBlk) &&
|
|
"succBlk is not a prececessor of curBlk");
|
|
|
|
BlockT *cloneBlk = CFGTraits::clone(curBlk); //clone instructions
|
|
CFGTraits::replaceInstrUseOfBlockWith(predBlk, curBlk, cloneBlk);
|
|
//srcBlk, oldBlk, newBlk
|
|
|
|
predBlk->removeSuccessor(curBlk);
|
|
predBlk->addSuccessor(cloneBlk);
|
|
|
|
// add all successor to cloneBlk
|
|
CFGTraits::cloneSuccessorList(cloneBlk, curBlk);
|
|
|
|
numClonedInstr += curBlk->size();
|
|
|
|
if (DEBUGME) {
|
|
errs() << "Cloned block: " << "BB"
|
|
<< curBlk->getNumber() << "size " << curBlk->size() << "\n";
|
|
}
|
|
|
|
SHOWNEWBLK(cloneBlk, "result of Cloned block: ");
|
|
|
|
return cloneBlk;
|
|
} //cloneBlockForPredecessor
|
|
|
|
template<class PassT>
|
|
typename CFGStructurizer<PassT>::BlockT *
|
|
CFGStructurizer<PassT>::exitingBlock2ExitBlock(LoopT *loopRep,
|
|
BlockT *exitingBlk) {
|
|
BlockT *exitBlk = NULL;
|
|
|
|
for (typename BlockT::succ_iterator iterSucc = exitingBlk->succ_begin(),
|
|
iterSuccEnd = exitingBlk->succ_end();
|
|
iterSucc != iterSuccEnd; ++iterSucc) {
|
|
BlockT *curBlk = *iterSucc;
|
|
if (!loopRep->contains(curBlk)) {
|
|
assert(exitBlk == NULL);
|
|
exitBlk = curBlk;
|
|
}
|
|
}
|
|
|
|
assert(exitBlk != NULL);
|
|
|
|
return exitBlk;
|
|
} //exitingBlock2ExitBlock
|
|
|
|
template<class PassT>
|
|
void CFGStructurizer<PassT>::migrateInstruction(BlockT *srcBlk,
|
|
BlockT *dstBlk,
|
|
InstrIterator insertPos) {
|
|
InstrIterator spliceEnd;
|
|
//look for the input branchinstr, not the AMDGPU branchinstr
|
|
InstrT *branchInstr = CFGTraits::getNormalBlockBranchInstr(srcBlk);
|
|
if (branchInstr == NULL) {
|
|
if (DEBUGME) {
|
|
errs() << "migrateInstruction don't see branch instr\n" ;
|
|
}
|
|
spliceEnd = srcBlk->end();
|
|
} else {
|
|
if (DEBUGME) {
|
|
errs() << "migrateInstruction see branch instr\n" ;
|
|
branchInstr->dump();
|
|
}
|
|
spliceEnd = CFGTraits::getInstrPos(srcBlk, branchInstr);
|
|
}
|
|
if (DEBUGME) {
|
|
errs() << "migrateInstruction before splice dstSize = " << dstBlk->size()
|
|
<< "srcSize = " << srcBlk->size() << "\n";
|
|
}
|
|
|
|
//splice insert before insertPos
|
|
dstBlk->splice(insertPos, srcBlk, srcBlk->begin(), spliceEnd);
|
|
|
|
if (DEBUGME) {
|
|
errs() << "migrateInstruction after splice dstSize = " << dstBlk->size()
|
|
<< "srcSize = " << srcBlk->size() << "\n";
|
|
}
|
|
} //migrateInstruction
|
|
|
|
// normalizeInfiniteLoopExit change
|
|
// B1:
|
|
// uncond_br LoopHeader
|
|
//
|
|
// to
|
|
// B1:
|
|
// cond_br 1 LoopHeader dummyExit
|
|
// and return the newly added dummy exit block
|
|
//
|
|
template<class PassT>
|
|
typename CFGStructurizer<PassT>::BlockT *
|
|
CFGStructurizer<PassT>::normalizeInfiniteLoopExit(LoopT* LoopRep) {
|
|
BlockT *loopHeader;
|
|
BlockT *loopLatch;
|
|
loopHeader = LoopRep->getHeader();
|
|
loopLatch = LoopRep->getLoopLatch();
|
|
BlockT *dummyExitBlk = NULL;
|
|
const TargetRegisterClass * I32RC = TRI->getCFGStructurizerRegClass(MVT::i32);
|
|
if (loopHeader!=NULL && loopLatch!=NULL) {
|
|
InstrT *branchInstr = CFGTraits::getLoopendBlockBranchInstr(loopLatch);
|
|
if (branchInstr!=NULL && CFGTraits::isUncondBranch(branchInstr)) {
|
|
dummyExitBlk = funcRep->CreateMachineBasicBlock();
|
|
funcRep->push_back(dummyExitBlk); //insert to function
|
|
SHOWNEWBLK(dummyExitBlk, "DummyExitBlock to normalize infiniteLoop: ");
|
|
|
|
if (DEBUGME) errs() << "Old branch instr: " << *branchInstr << "\n";
|
|
|
|
typename BlockT::iterator insertPos =
|
|
CFGTraits::getInstrPos(loopLatch, branchInstr);
|
|
unsigned immReg =
|
|
funcRep->getRegInfo().createVirtualRegister(I32RC);
|
|
CFGTraits::insertAssignInstrBefore(insertPos, passRep, immReg, 1);
|
|
InstrT *newInstr =
|
|
CFGTraits::insertInstrBefore(insertPos, AMDGPU::BRANCH_COND_i32, passRep);
|
|
MachineInstrBuilder MIB(*funcRep, newInstr);
|
|
MIB.addMBB(loopHeader);
|
|
MIB.addReg(immReg, false);
|
|
|
|
SHOWNEWINSTR(newInstr);
|
|
|
|
branchInstr->eraseFromParent();
|
|
loopLatch->addSuccessor(dummyExitBlk);
|
|
}
|
|
}
|
|
|
|
return dummyExitBlk;
|
|
} //normalizeInfiniteLoopExit
|
|
|
|
template<class PassT>
|
|
void CFGStructurizer<PassT>::removeUnconditionalBranch(BlockT *srcBlk) {
|
|
InstrT *branchInstr;
|
|
|
|
// I saw two unconditional branch in one basic block in example
|
|
// test_fc_do_while_or.c need to fix the upstream on this to remove the loop.
|
|
while ((branchInstr = CFGTraits::getLoopendBlockBranchInstr(srcBlk))
|
|
&& CFGTraits::isUncondBranch(branchInstr)) {
|
|
if (DEBUGME) {
|
|
errs() << "Removing unconditional branch instruction" ;
|
|
branchInstr->dump();
|
|
}
|
|
branchInstr->eraseFromParent();
|
|
}
|
|
} //removeUnconditionalBranch
|
|
|
|
template<class PassT>
|
|
void CFGStructurizer<PassT>::removeRedundantConditionalBranch(BlockT *srcBlk) {
|
|
if (srcBlk->succ_size() == 2) {
|
|
BlockT *blk1 = *srcBlk->succ_begin();
|
|
BlockT *blk2 = *(++srcBlk->succ_begin());
|
|
|
|
if (blk1 == blk2) {
|
|
InstrT *branchInstr = CFGTraits::getNormalBlockBranchInstr(srcBlk);
|
|
assert(branchInstr && CFGTraits::isCondBranch(branchInstr));
|
|
if (DEBUGME) {
|
|
errs() << "Removing unneeded conditional branch instruction" ;
|
|
branchInstr->dump();
|
|
}
|
|
branchInstr->eraseFromParent();
|
|
SHOWNEWBLK(blk1, "Removing redundant successor");
|
|
srcBlk->removeSuccessor(blk1);
|
|
}
|
|
}
|
|
} //removeRedundantConditionalBranch
|
|
|
|
template<class PassT>
|
|
void CFGStructurizer<PassT>::addDummyExitBlock(SmallVector<BlockT*,
|
|
DEFAULT_VEC_SLOTS> &retBlks) {
|
|
BlockT *dummyExitBlk = funcRep->CreateMachineBasicBlock();
|
|
funcRep->push_back(dummyExitBlk); //insert to function
|
|
CFGTraits::insertInstrEnd(dummyExitBlk, AMDGPU::RETURN, passRep);
|
|
|
|
for (typename SmallVector<BlockT *, DEFAULT_VEC_SLOTS>::iterator iter =
|
|
retBlks.begin(),
|
|
iterEnd = retBlks.end(); iter != iterEnd; ++iter) {
|
|
BlockT *curBlk = *iter;
|
|
InstrT *curInstr = CFGTraits::getReturnInstr(curBlk);
|
|
if (curInstr) {
|
|
curInstr->eraseFromParent();
|
|
}
|
|
curBlk->addSuccessor(dummyExitBlk);
|
|
if (DEBUGME) {
|
|
errs() << "Add dummyExitBlock to BB" << curBlk->getNumber()
|
|
<< " successors\n";
|
|
}
|
|
} //for
|
|
|
|
SHOWNEWBLK(dummyExitBlk, "DummyExitBlock: ");
|
|
} //addDummyExitBlock
|
|
|
|
template<class PassT>
|
|
void CFGStructurizer<PassT>::removeSuccessor(BlockT *srcBlk) {
|
|
while (srcBlk->succ_size()) {
|
|
srcBlk->removeSuccessor(*srcBlk->succ_begin());
|
|
}
|
|
}
|
|
|
|
template<class PassT>
|
|
void CFGStructurizer<PassT>::recordSccnum(BlockT *srcBlk, int sccNum) {
|
|
BlockInfo *&srcBlkInfo = blockInfoMap[srcBlk];
|
|
|
|
if (srcBlkInfo == NULL) {
|
|
srcBlkInfo = new BlockInfo();
|
|
}
|
|
|
|
srcBlkInfo->sccNum = sccNum;
|
|
}
|
|
|
|
template<class PassT>
|
|
int CFGStructurizer<PassT>::getSCCNum(BlockT *srcBlk) {
|
|
BlockInfo *srcBlkInfo = blockInfoMap[srcBlk];
|
|
return srcBlkInfo ? srcBlkInfo->sccNum : INVALIDSCCNUM;
|
|
}
|
|
|
|
template<class PassT>
|
|
void CFGStructurizer<PassT>::retireBlock(BlockT *dstBlk, BlockT *srcBlk) {
|
|
if (DEBUGME) {
|
|
errs() << "Retiring BB" << srcBlk->getNumber() << "\n";
|
|
}
|
|
|
|
BlockInfo *&srcBlkInfo = blockInfoMap[srcBlk];
|
|
|
|
if (srcBlkInfo == NULL) {
|
|
srcBlkInfo = new BlockInfo();
|
|
}
|
|
|
|
srcBlkInfo->isRetired = true;
|
|
assert(srcBlk->succ_size() == 0 && srcBlk->pred_size() == 0
|
|
&& "can't retire block yet");
|
|
}
|
|
|
|
template<class PassT>
|
|
bool CFGStructurizer<PassT>::isRetiredBlock(BlockT *srcBlk) {
|
|
BlockInfo *srcBlkInfo = blockInfoMap[srcBlk];
|
|
return (srcBlkInfo && srcBlkInfo->isRetired);
|
|
}
|
|
|
|
template<class PassT>
|
|
bool CFGStructurizer<PassT>::isActiveLoophead(BlockT *curBlk) {
|
|
LoopT *loopRep = loopInfo->getLoopFor(curBlk);
|
|
while (loopRep && loopRep->getHeader() == curBlk) {
|
|
LoopLandInfo *loopLand = getLoopLandInfo(loopRep);
|
|
|
|
if(loopLand == NULL)
|
|
return true;
|
|
|
|
BlockT *landBlk = loopLand->landBlk;
|
|
assert(landBlk);
|
|
if (!isRetiredBlock(landBlk)) {
|
|
return true;
|
|
}
|
|
|
|
loopRep = loopRep->getParentLoop();
|
|
}
|
|
|
|
return false;
|
|
} //isActiveLoophead
|
|
|
|
template<class PassT>
|
|
bool CFGStructurizer<PassT>::needMigrateBlock(BlockT *blk) {
|
|
const unsigned blockSizeThreshold = 30;
|
|
const unsigned cloneInstrThreshold = 100;
|
|
|
|
bool multiplePreds = blk && (blk->pred_size() > 1);
|
|
|
|
if(!multiplePreds)
|
|
return false;
|
|
|
|
unsigned blkSize = blk->size();
|
|
return ((blkSize > blockSizeThreshold)
|
|
&& (blkSize * (blk->pred_size() - 1) > cloneInstrThreshold));
|
|
} //needMigrateBlock
|
|
|
|
template<class PassT>
|
|
typename CFGStructurizer<PassT>::BlockT *
|
|
CFGStructurizer<PassT>::recordLoopLandBlock(LoopT *loopRep, BlockT *landBlk,
|
|
BlockTSmallerVector &exitBlks,
|
|
std::set<BlockT *> &exitBlkSet) {
|
|
SmallVector<BlockT *, DEFAULT_VEC_SLOTS> inpathBlks; //in exit path blocks
|
|
|
|
for (typename BlockT::pred_iterator predIter = landBlk->pred_begin(),
|
|
predIterEnd = landBlk->pred_end();
|
|
predIter != predIterEnd; ++predIter) {
|
|
BlockT *curBlk = *predIter;
|
|
if (loopRep->contains(curBlk) || exitBlkSet.count(curBlk)) {
|
|
inpathBlks.push_back(curBlk);
|
|
}
|
|
} //for
|
|
|
|
//if landBlk has predecessors that are not in the given loop,
|
|
//create a new block
|
|
BlockT *newLandBlk = landBlk;
|
|
if (inpathBlks.size() != landBlk->pred_size()) {
|
|
newLandBlk = funcRep->CreateMachineBasicBlock();
|
|
funcRep->push_back(newLandBlk); //insert to function
|
|
newLandBlk->addSuccessor(landBlk);
|
|
for (typename SmallVector<BlockT*, DEFAULT_VEC_SLOTS>::iterator iter =
|
|
inpathBlks.begin(),
|
|
iterEnd = inpathBlks.end(); iter != iterEnd; ++iter) {
|
|
BlockT *curBlk = *iter;
|
|
CFGTraits::replaceInstrUseOfBlockWith(curBlk, landBlk, newLandBlk);
|
|
//srcBlk, oldBlk, newBlk
|
|
curBlk->removeSuccessor(landBlk);
|
|
curBlk->addSuccessor(newLandBlk);
|
|
}
|
|
for (size_t i = 0, tot = exitBlks.size(); i < tot; ++i) {
|
|
if (exitBlks[i] == landBlk) {
|
|
exitBlks[i] = newLandBlk;
|
|
}
|
|
}
|
|
SHOWNEWBLK(newLandBlk, "NewLandingBlock: ");
|
|
}
|
|
|
|
setLoopLandBlock(loopRep, newLandBlk);
|
|
|
|
return newLandBlk;
|
|
} // recordLoopbreakLand
|
|
|
|
template<class PassT>
|
|
void CFGStructurizer<PassT>::setLoopLandBlock(LoopT *loopRep, BlockT *blk) {
|
|
LoopLandInfo *&theEntry = loopLandInfoMap[loopRep];
|
|
|
|
if (theEntry == NULL) {
|
|
theEntry = new LoopLandInfo();
|
|
}
|
|
assert(theEntry->landBlk == NULL);
|
|
|
|
if (blk == NULL) {
|
|
blk = funcRep->CreateMachineBasicBlock();
|
|
funcRep->push_back(blk); //insert to function
|
|
SHOWNEWBLK(blk, "DummyLandingBlock for loop without break: ");
|
|
}
|
|
|
|
theEntry->landBlk = blk;
|
|
|
|
if (DEBUGME) {
|
|
errs() << "setLoopLandBlock loop-header = BB"
|
|
<< loopRep->getHeader()->getNumber()
|
|
<< " landing-block = BB" << blk->getNumber() << "\n";
|
|
}
|
|
} // setLoopLandBlock
|
|
|
|
template<class PassT>
|
|
void CFGStructurizer<PassT>::addLoopBreakOnReg(LoopT *loopRep, RegiT regNum) {
|
|
LoopLandInfo *&theEntry = loopLandInfoMap[loopRep];
|
|
|
|
if (theEntry == NULL) {
|
|
theEntry = new LoopLandInfo();
|
|
}
|
|
|
|
theEntry->breakOnRegs.insert(regNum);
|
|
|
|
if (DEBUGME) {
|
|
errs() << "addLoopBreakOnReg loop-header = BB"
|
|
<< loopRep->getHeader()->getNumber()
|
|
<< " regNum = " << regNum << "\n";
|
|
}
|
|
} // addLoopBreakOnReg
|
|
|
|
template<class PassT>
|
|
void CFGStructurizer<PassT>::addLoopContOnReg(LoopT *loopRep, RegiT regNum) {
|
|
LoopLandInfo *&theEntry = loopLandInfoMap[loopRep];
|
|
|
|
if (theEntry == NULL) {
|
|
theEntry = new LoopLandInfo();
|
|
}
|
|
theEntry->contOnRegs.insert(regNum);
|
|
|
|
if (DEBUGME) {
|
|
errs() << "addLoopContOnReg loop-header = BB"
|
|
<< loopRep->getHeader()->getNumber()
|
|
<< " regNum = " << regNum << "\n";
|
|
}
|
|
} // addLoopContOnReg
|
|
|
|
template<class PassT>
|
|
void CFGStructurizer<PassT>::addLoopBreakInitReg(LoopT *loopRep, RegiT regNum) {
|
|
LoopLandInfo *&theEntry = loopLandInfoMap[loopRep];
|
|
|
|
if (theEntry == NULL) {
|
|
theEntry = new LoopLandInfo();
|
|
}
|
|
theEntry->breakInitRegs.insert(regNum);
|
|
|
|
if (DEBUGME) {
|
|
errs() << "addLoopBreakInitReg loop-header = BB"
|
|
<< loopRep->getHeader()->getNumber()
|
|
<< " regNum = " << regNum << "\n";
|
|
}
|
|
} // addLoopBreakInitReg
|
|
|
|
template<class PassT>
|
|
void CFGStructurizer<PassT>::addLoopContInitReg(LoopT *loopRep, RegiT regNum) {
|
|
LoopLandInfo *&theEntry = loopLandInfoMap[loopRep];
|
|
|
|
if (theEntry == NULL) {
|
|
theEntry = new LoopLandInfo();
|
|
}
|
|
theEntry->contInitRegs.insert(regNum);
|
|
|
|
if (DEBUGME) {
|
|
errs() << "addLoopContInitReg loop-header = BB"
|
|
<< loopRep->getHeader()->getNumber()
|
|
<< " regNum = " << regNum << "\n";
|
|
}
|
|
} // addLoopContInitReg
|
|
|
|
template<class PassT>
|
|
void CFGStructurizer<PassT>::addLoopEndbranchInitReg(LoopT *loopRep,
|
|
RegiT regNum) {
|
|
LoopLandInfo *&theEntry = loopLandInfoMap[loopRep];
|
|
|
|
if (theEntry == NULL) {
|
|
theEntry = new LoopLandInfo();
|
|
}
|
|
theEntry->endbranchInitRegs.insert(regNum);
|
|
|
|
if (DEBUGME) {
|
|
errs() << "addLoopEndbranchInitReg loop-header = BB"
|
|
<< loopRep->getHeader()->getNumber()
|
|
<< " regNum = " << regNum << "\n";
|
|
}
|
|
} // addLoopEndbranchInitReg
|
|
|
|
template<class PassT>
|
|
typename CFGStructurizer<PassT>::LoopLandInfo *
|
|
CFGStructurizer<PassT>::getLoopLandInfo(LoopT *loopRep) {
|
|
LoopLandInfo *&theEntry = loopLandInfoMap[loopRep];
|
|
|
|
return theEntry;
|
|
} // getLoopLandInfo
|
|
|
|
template<class PassT>
|
|
typename CFGStructurizer<PassT>::BlockT *
|
|
CFGStructurizer<PassT>::getLoopLandBlock(LoopT *loopRep) {
|
|
LoopLandInfo *&theEntry = loopLandInfoMap[loopRep];
|
|
|
|
return theEntry ? theEntry->landBlk : NULL;
|
|
} // getLoopLandBlock
|
|
|
|
|
|
template<class PassT>
|
|
bool CFGStructurizer<PassT>::hasBackEdge(BlockT *curBlk) {
|
|
LoopT *loopRep = loopInfo->getLoopFor(curBlk);
|
|
if (loopRep == NULL)
|
|
return false;
|
|
|
|
BlockT *loopHeader = loopRep->getHeader();
|
|
|
|
return curBlk->isSuccessor(loopHeader);
|
|
|
|
} //hasBackEdge
|
|
|
|
template<class PassT>
|
|
unsigned CFGStructurizer<PassT>::getLoopDepth(LoopT *loopRep) {
|
|
return loopRep ? loopRep->getLoopDepth() : 0;
|
|
} //getLoopDepth
|
|
|
|
template<class PassT>
|
|
int CFGStructurizer<PassT>::countActiveBlock
|
|
(typename SmallVector<BlockT*, DEFAULT_VEC_SLOTS>::const_iterator iterStart,
|
|
typename SmallVector<BlockT*, DEFAULT_VEC_SLOTS>::const_iterator iterEnd) {
|
|
int count = 0;
|
|
while (iterStart != iterEnd) {
|
|
if (!isRetiredBlock(*iterStart)) {
|
|
++count;
|
|
}
|
|
++iterStart;
|
|
}
|
|
|
|
return count;
|
|
} //countActiveBlock
|
|
|
|
// This is work around solution for findNearestCommonDominator not avaiable to
|
|
// post dom a proper fix should go to Dominators.h.
|
|
|
|
template<class PassT>
|
|
typename CFGStructurizer<PassT>::BlockT*
|
|
CFGStructurizer<PassT>::findNearestCommonPostDom(BlockT *blk1, BlockT *blk2) {
|
|
|
|
if (postDomTree->dominates(blk1, blk2)) {
|
|
return blk1;
|
|
}
|
|
if (postDomTree->dominates(blk2, blk1)) {
|
|
return blk2;
|
|
}
|
|
|
|
DomTreeNodeT *node1 = postDomTree->getNode(blk1);
|
|
DomTreeNodeT *node2 = postDomTree->getNode(blk2);
|
|
|
|
// Handle newly cloned node.
|
|
if (node1 == NULL && blk1->succ_size() == 1) {
|
|
return findNearestCommonPostDom(*blk1->succ_begin(), blk2);
|
|
}
|
|
if (node2 == NULL && blk2->succ_size() == 1) {
|
|
return findNearestCommonPostDom(blk1, *blk2->succ_begin());
|
|
}
|
|
|
|
if (node1 == NULL || node2 == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
node1 = node1->getIDom();
|
|
while (node1) {
|
|
if (postDomTree->dominates(node1, node2)) {
|
|
return node1->getBlock();
|
|
}
|
|
node1 = node1->getIDom();
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
template<class PassT>
|
|
typename CFGStructurizer<PassT>::BlockT *
|
|
CFGStructurizer<PassT>::findNearestCommonPostDom
|
|
(typename std::set<BlockT *> &blks) {
|
|
BlockT *commonDom;
|
|
typename std::set<BlockT *>::const_iterator iter = blks.begin();
|
|
typename std::set<BlockT *>::const_iterator iterEnd = blks.end();
|
|
for (commonDom = *iter; iter != iterEnd && commonDom != NULL; ++iter) {
|
|
BlockT *curBlk = *iter;
|
|
if (curBlk != commonDom) {
|
|
commonDom = findNearestCommonPostDom(curBlk, commonDom);
|
|
}
|
|
}
|
|
|
|
if (DEBUGME) {
|
|
errs() << "Common post dominator for exit blocks is ";
|
|
if (commonDom) {
|
|
errs() << "BB" << commonDom->getNumber() << "\n";
|
|
} else {
|
|
errs() << "NULL\n";
|
|
}
|
|
}
|
|
|
|
return commonDom;
|
|
} //findNearestCommonPostDom
|
|
|
|
} //end namespace llvm
|
|
|
|
//todo: move-end
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// CFGStructurizer for AMDGPU
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
using namespace llvmCFGStruct;
|
|
|
|
namespace llvm {
|
|
class AMDGPUCFGStructurizer : public MachineFunctionPass {
|
|
public:
|
|
typedef MachineInstr InstructionType;
|
|
typedef MachineFunction FunctionType;
|
|
typedef MachineBasicBlock BlockType;
|
|
typedef MachineLoopInfo LoopinfoType;
|
|
typedef MachineDominatorTree DominatortreeType;
|
|
typedef MachinePostDominatorTree PostDominatortreeType;
|
|
typedef MachineDomTreeNode DomTreeNodeType;
|
|
typedef MachineLoop LoopType;
|
|
|
|
protected:
|
|
TargetMachine &TM;
|
|
const TargetInstrInfo *TII;
|
|
const AMDGPURegisterInfo *TRI;
|
|
|
|
public:
|
|
AMDGPUCFGStructurizer(char &pid, TargetMachine &tm);
|
|
const TargetInstrInfo *getTargetInstrInfo() const;
|
|
|
|
private:
|
|
|
|
};
|
|
|
|
} //end of namespace llvm
|
|
AMDGPUCFGStructurizer::AMDGPUCFGStructurizer(char &pid, TargetMachine &tm)
|
|
: MachineFunctionPass(pid), TM(tm), TII(tm.getInstrInfo()),
|
|
TRI(static_cast<const AMDGPURegisterInfo *>(tm.getRegisterInfo())) {
|
|
}
|
|
|
|
const TargetInstrInfo *AMDGPUCFGStructurizer::getTargetInstrInfo() const {
|
|
return TII;
|
|
}
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// CFGPrepare
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
using namespace llvmCFGStruct;
|
|
|
|
namespace llvm {
|
|
class AMDGPUCFGPrepare : public AMDGPUCFGStructurizer {
|
|
public:
|
|
static char ID;
|
|
|
|
public:
|
|
AMDGPUCFGPrepare(TargetMachine &tm);
|
|
|
|
virtual const char *getPassName() const;
|
|
virtual void getAnalysisUsage(AnalysisUsage &AU) const;
|
|
|
|
bool runOnMachineFunction(MachineFunction &F);
|
|
|
|
private:
|
|
|
|
};
|
|
|
|
char AMDGPUCFGPrepare::ID = 0;
|
|
} //end of namespace llvm
|
|
|
|
AMDGPUCFGPrepare::AMDGPUCFGPrepare(TargetMachine &tm)
|
|
: AMDGPUCFGStructurizer(ID, tm ) {
|
|
}
|
|
const char *AMDGPUCFGPrepare::getPassName() const {
|
|
return "AMD IL Control Flow Graph Preparation Pass";
|
|
}
|
|
|
|
void AMDGPUCFGPrepare::getAnalysisUsage(AnalysisUsage &AU) const {
|
|
AU.addPreserved<MachineFunctionAnalysis>();
|
|
AU.addRequired<MachineFunctionAnalysis>();
|
|
AU.addRequired<MachineDominatorTree>();
|
|
AU.addRequired<MachinePostDominatorTree>();
|
|
AU.addRequired<MachineLoopInfo>();
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// CFGPerform
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
using namespace llvmCFGStruct;
|
|
|
|
namespace llvm {
|
|
class AMDGPUCFGPerform : public AMDGPUCFGStructurizer {
|
|
public:
|
|
static char ID;
|
|
|
|
public:
|
|
AMDGPUCFGPerform(TargetMachine &tm);
|
|
virtual const char *getPassName() const;
|
|
virtual void getAnalysisUsage(AnalysisUsage &AU) const;
|
|
bool runOnMachineFunction(MachineFunction &F);
|
|
|
|
private:
|
|
|
|
};
|
|
|
|
char AMDGPUCFGPerform::ID = 0;
|
|
} //end of namespace llvm
|
|
|
|
AMDGPUCFGPerform::AMDGPUCFGPerform(TargetMachine &tm)
|
|
: AMDGPUCFGStructurizer(ID, tm) {
|
|
}
|
|
|
|
const char *AMDGPUCFGPerform::getPassName() const {
|
|
return "AMD IL Control Flow Graph structurizer Pass";
|
|
}
|
|
|
|
void AMDGPUCFGPerform::getAnalysisUsage(AnalysisUsage &AU) const {
|
|
AU.addPreserved<MachineFunctionAnalysis>();
|
|
AU.addRequired<MachineFunctionAnalysis>();
|
|
AU.addRequired<MachineDominatorTree>();
|
|
AU.addRequired<MachinePostDominatorTree>();
|
|
AU.addRequired<MachineLoopInfo>();
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// CFGStructTraits<AMDGPUCFGStructurizer>
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
namespace llvmCFGStruct {
|
|
// this class is tailor to the AMDGPU backend
|
|
template<>
|
|
struct CFGStructTraits<AMDGPUCFGStructurizer> {
|
|
typedef int RegiT;
|
|
|
|
static int getBranchNzeroOpcode(int oldOpcode) {
|
|
switch(oldOpcode) {
|
|
case AMDGPU::JUMP: return AMDGPU::IF_PREDICATE_SET;
|
|
case AMDGPU::BRANCH_COND_i32:
|
|
case AMDGPU::BRANCH_COND_f32: return AMDGPU::IF_LOGICALNZ_f32;
|
|
default:
|
|
assert(0 && "internal error");
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int getBranchZeroOpcode(int oldOpcode) {
|
|
switch(oldOpcode) {
|
|
case AMDGPU::JUMP: return AMDGPU::IF_PREDICATE_SET;
|
|
case AMDGPU::BRANCH_COND_i32:
|
|
case AMDGPU::BRANCH_COND_f32: return AMDGPU::IF_LOGICALZ_f32;
|
|
default:
|
|
assert(0 && "internal error");
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int getContinueNzeroOpcode(int oldOpcode) {
|
|
switch(oldOpcode) {
|
|
case AMDGPU::JUMP: return AMDGPU::CONTINUE_LOGICALNZ_i32;
|
|
default:
|
|
assert(0 && "internal error");
|
|
};
|
|
return -1;
|
|
}
|
|
|
|
static int getContinueZeroOpcode(int oldOpcode) {
|
|
switch(oldOpcode) {
|
|
case AMDGPU::JUMP: return AMDGPU::CONTINUE_LOGICALZ_i32;
|
|
default:
|
|
assert(0 && "internal error");
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static MachineBasicBlock *getTrueBranch(MachineInstr *instr) {
|
|
return instr->getOperand(0).getMBB();
|
|
}
|
|
|
|
static void setTrueBranch(MachineInstr *instr, MachineBasicBlock *blk) {
|
|
instr->getOperand(0).setMBB(blk);
|
|
}
|
|
|
|
static MachineBasicBlock *
|
|
getFalseBranch(MachineBasicBlock *blk, MachineInstr *instr) {
|
|
assert(blk->succ_size() == 2);
|
|
MachineBasicBlock *trueBranch = getTrueBranch(instr);
|
|
MachineBasicBlock::succ_iterator iter = blk->succ_begin();
|
|
MachineBasicBlock::succ_iterator iterNext = iter;
|
|
++iterNext;
|
|
|
|
return (*iter == trueBranch) ? *iterNext : *iter;
|
|
}
|
|
|
|
static bool isCondBranch(MachineInstr *instr) {
|
|
switch (instr->getOpcode()) {
|
|
case AMDGPU::JUMP:
|
|
return instr->getOperand(instr->findFirstPredOperandIdx()).getReg() != 0;
|
|
case AMDGPU::BRANCH_COND_i32:
|
|
case AMDGPU::BRANCH_COND_f32:
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static bool isUncondBranch(MachineInstr *instr) {
|
|
switch (instr->getOpcode()) {
|
|
case AMDGPU::JUMP:
|
|
return instr->getOperand(instr->findFirstPredOperandIdx()).getReg() == 0;
|
|
case AMDGPU::BRANCH:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static DebugLoc getLastDebugLocInBB(MachineBasicBlock *blk) {
|
|
//get DebugLoc from the first MachineBasicBlock instruction with debug info
|
|
DebugLoc DL;
|
|
for (MachineBasicBlock::iterator iter = blk->begin(); iter != blk->end(); ++iter) {
|
|
MachineInstr *instr = &(*iter);
|
|
if (instr->getDebugLoc().isUnknown() == false) {
|
|
DL = instr->getDebugLoc();
|
|
}
|
|
}
|
|
return DL;
|
|
}
|
|
|
|
static MachineInstr *getNormalBlockBranchInstr(MachineBasicBlock *blk) {
|
|
MachineBasicBlock::reverse_iterator iter = blk->rbegin();
|
|
MachineInstr *instr = &*iter;
|
|
if (instr && (isCondBranch(instr) || isUncondBranch(instr))) {
|
|
return instr;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// The correct naming for this is getPossibleLoopendBlockBranchInstr.
|
|
//
|
|
// BB with backward-edge could have move instructions after the branch
|
|
// instruction. Such move instruction "belong to" the loop backward-edge.
|
|
//
|
|
static MachineInstr *getLoopendBlockBranchInstr(MachineBasicBlock *blk) {
|
|
const AMDGPUInstrInfo * TII = static_cast<const AMDGPUInstrInfo *>(
|
|
blk->getParent()->getTarget().getInstrInfo());
|
|
|
|
for (MachineBasicBlock::reverse_iterator iter = blk->rbegin(),
|
|
iterEnd = blk->rend(); iter != iterEnd; ++iter) {
|
|
// FIXME: Simplify
|
|
MachineInstr *instr = &*iter;
|
|
if (instr) {
|
|
if (isCondBranch(instr) || isUncondBranch(instr)) {
|
|
return instr;
|
|
} else if (!TII->isMov(instr->getOpcode())) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static MachineInstr *getReturnInstr(MachineBasicBlock *blk) {
|
|
MachineBasicBlock::reverse_iterator iter = blk->rbegin();
|
|
if (iter != blk->rend()) {
|
|
MachineInstr *instr = &(*iter);
|
|
if (instr->getOpcode() == AMDGPU::RETURN) {
|
|
return instr;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static MachineInstr *getContinueInstr(MachineBasicBlock *blk) {
|
|
MachineBasicBlock::reverse_iterator iter = blk->rbegin();
|
|
if (iter != blk->rend()) {
|
|
MachineInstr *instr = &(*iter);
|
|
if (instr->getOpcode() == AMDGPU::CONTINUE) {
|
|
return instr;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static MachineInstr *getLoopBreakInstr(MachineBasicBlock *blk) {
|
|
for (MachineBasicBlock::iterator iter = blk->begin(); (iter != blk->end()); ++iter) {
|
|
MachineInstr *instr = &(*iter);
|
|
if (instr->getOpcode() == AMDGPU::PREDICATED_BREAK) {
|
|
return instr;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static bool isReturnBlock(MachineBasicBlock *blk) {
|
|
MachineInstr *instr = getReturnInstr(blk);
|
|
bool isReturn = (blk->succ_size() == 0);
|
|
if (instr) {
|
|
assert(isReturn);
|
|
} else if (isReturn) {
|
|
if (DEBUGME) {
|
|
errs() << "BB" << blk->getNumber()
|
|
<<" is return block without RETURN instr\n";
|
|
}
|
|
}
|
|
|
|
return isReturn;
|
|
}
|
|
|
|
static MachineBasicBlock::iterator
|
|
getInstrPos(MachineBasicBlock *blk, MachineInstr *instr) {
|
|
assert(instr->getParent() == blk && "instruction doesn't belong to block");
|
|
MachineBasicBlock::iterator iter = blk->begin();
|
|
MachineBasicBlock::iterator iterEnd = blk->end();
|
|
while (&(*iter) != instr && iter != iterEnd) {
|
|
++iter;
|
|
}
|
|
|
|
assert(iter != iterEnd);
|
|
return iter;
|
|
}//getInstrPos
|
|
|
|
static MachineInstr *insertInstrBefore(MachineBasicBlock *blk, int newOpcode,
|
|
AMDGPUCFGStructurizer *passRep) {
|
|
return insertInstrBefore(blk,newOpcode,passRep,DebugLoc());
|
|
} //insertInstrBefore
|
|
|
|
static MachineInstr *insertInstrBefore(MachineBasicBlock *blk, int newOpcode,
|
|
AMDGPUCFGStructurizer *passRep, DebugLoc DL) {
|
|
const TargetInstrInfo *tii = passRep->getTargetInstrInfo();
|
|
MachineInstr *newInstr =
|
|
blk->getParent()->CreateMachineInstr(tii->get(newOpcode), DL);
|
|
|
|
MachineBasicBlock::iterator res;
|
|
if (blk->begin() != blk->end()) {
|
|
blk->insert(blk->begin(), newInstr);
|
|
} else {
|
|
blk->push_back(newInstr);
|
|
}
|
|
|
|
SHOWNEWINSTR(newInstr);
|
|
|
|
return newInstr;
|
|
} //insertInstrBefore
|
|
|
|
static void insertInstrEnd(MachineBasicBlock *blk, int newOpcode,
|
|
AMDGPUCFGStructurizer *passRep) {
|
|
insertInstrEnd(blk,newOpcode,passRep,DebugLoc());
|
|
} //insertInstrEnd
|
|
|
|
static void insertInstrEnd(MachineBasicBlock *blk, int newOpcode,
|
|
AMDGPUCFGStructurizer *passRep, DebugLoc DL) {
|
|
const TargetInstrInfo *tii = passRep->getTargetInstrInfo();
|
|
MachineInstr *newInstr = blk->getParent()
|
|
->CreateMachineInstr(tii->get(newOpcode), DL);
|
|
|
|
blk->push_back(newInstr);
|
|
//assume the instruction doesn't take any reg operand ...
|
|
|
|
SHOWNEWINSTR(newInstr);
|
|
} //insertInstrEnd
|
|
|
|
static MachineInstr *insertInstrBefore(MachineBasicBlock::iterator instrPos,
|
|
int newOpcode,
|
|
AMDGPUCFGStructurizer *passRep) {
|
|
MachineInstr *oldInstr = &(*instrPos);
|
|
const TargetInstrInfo *tii = passRep->getTargetInstrInfo();
|
|
MachineBasicBlock *blk = oldInstr->getParent();
|
|
MachineInstr *newInstr =
|
|
blk->getParent()->CreateMachineInstr(tii->get(newOpcode),
|
|
DebugLoc());
|
|
|
|
blk->insert(instrPos, newInstr);
|
|
//assume the instruction doesn't take any reg operand ...
|
|
|
|
SHOWNEWINSTR(newInstr);
|
|
return newInstr;
|
|
} //insertInstrBefore
|
|
|
|
static void insertCondBranchBefore(MachineBasicBlock::iterator instrPos,
|
|
int newOpcode,
|
|
AMDGPUCFGStructurizer *passRep,
|
|
DebugLoc DL) {
|
|
MachineInstr *oldInstr = &(*instrPos);
|
|
const TargetInstrInfo *tii = passRep->getTargetInstrInfo();
|
|
MachineBasicBlock *blk = oldInstr->getParent();
|
|
MachineFunction *MF = blk->getParent();
|
|
MachineInstr *newInstr = MF->CreateMachineInstr(tii->get(newOpcode), DL);
|
|
|
|
blk->insert(instrPos, newInstr);
|
|
MachineInstrBuilder MIB(*MF, newInstr);
|
|
MIB.addReg(oldInstr->getOperand(1).getReg(), false);
|
|
|
|
SHOWNEWINSTR(newInstr);
|
|
//erase later oldInstr->eraseFromParent();
|
|
} //insertCondBranchBefore
|
|
|
|
static void insertCondBranchBefore(MachineBasicBlock *blk,
|
|
MachineBasicBlock::iterator insertPos,
|
|
int newOpcode,
|
|
AMDGPUCFGStructurizer *passRep,
|
|
RegiT regNum,
|
|
DebugLoc DL) {
|
|
const TargetInstrInfo *tii = passRep->getTargetInstrInfo();
|
|
MachineFunction *MF = blk->getParent();
|
|
|
|
MachineInstr *newInstr = MF->CreateMachineInstr(tii->get(newOpcode), DL);
|
|
|
|
//insert before
|
|
blk->insert(insertPos, newInstr);
|
|
MachineInstrBuilder(*MF, newInstr).addReg(regNum, false);
|
|
|
|
SHOWNEWINSTR(newInstr);
|
|
} //insertCondBranchBefore
|
|
|
|
static void insertCondBranchEnd(MachineBasicBlock *blk,
|
|
int newOpcode,
|
|
AMDGPUCFGStructurizer *passRep,
|
|
RegiT regNum) {
|
|
const TargetInstrInfo *tii = passRep->getTargetInstrInfo();
|
|
MachineFunction *MF = blk->getParent();
|
|
MachineInstr *newInstr =
|
|
MF->CreateMachineInstr(tii->get(newOpcode), DebugLoc());
|
|
|
|
blk->push_back(newInstr);
|
|
MachineInstrBuilder(*MF, newInstr).addReg(regNum, false);
|
|
|
|
SHOWNEWINSTR(newInstr);
|
|
} //insertCondBranchEnd
|
|
|
|
|
|
static void insertAssignInstrBefore(MachineBasicBlock::iterator instrPos,
|
|
AMDGPUCFGStructurizer *passRep,
|
|
RegiT regNum, int regVal) {
|
|
MachineInstr *oldInstr = &(*instrPos);
|
|
const AMDGPUInstrInfo *tii =
|
|
static_cast<const AMDGPUInstrInfo *>(passRep->getTargetInstrInfo());
|
|
MachineBasicBlock *blk = oldInstr->getParent();
|
|
MachineInstr *newInstr = tii->getMovImmInstr(blk->getParent(), regNum,
|
|
regVal);
|
|
blk->insert(instrPos, newInstr);
|
|
|
|
SHOWNEWINSTR(newInstr);
|
|
} //insertAssignInstrBefore
|
|
|
|
static void insertAssignInstrBefore(MachineBasicBlock *blk,
|
|
AMDGPUCFGStructurizer *passRep,
|
|
RegiT regNum, int regVal) {
|
|
const AMDGPUInstrInfo *tii =
|
|
static_cast<const AMDGPUInstrInfo *>(passRep->getTargetInstrInfo());
|
|
|
|
MachineInstr *newInstr = tii->getMovImmInstr(blk->getParent(), regNum,
|
|
regVal);
|
|
if (blk->begin() != blk->end()) {
|
|
blk->insert(blk->begin(), newInstr);
|
|
} else {
|
|
blk->push_back(newInstr);
|
|
}
|
|
|
|
SHOWNEWINSTR(newInstr);
|
|
|
|
} //insertInstrBefore
|
|
|
|
static void insertCompareInstrBefore(MachineBasicBlock *blk,
|
|
MachineBasicBlock::iterator instrPos,
|
|
AMDGPUCFGStructurizer *passRep,
|
|
RegiT dstReg, RegiT src1Reg,
|
|
RegiT src2Reg) {
|
|
const AMDGPUInstrInfo *tii =
|
|
static_cast<const AMDGPUInstrInfo *>(passRep->getTargetInstrInfo());
|
|
MachineFunction *MF = blk->getParent();
|
|
MachineInstr *newInstr =
|
|
MF->CreateMachineInstr(tii->get(tii->getIEQOpcode()), DebugLoc());
|
|
|
|
MachineInstrBuilder MIB(*MF, newInstr);
|
|
MIB.addReg(dstReg, RegState::Define); //set target
|
|
MIB.addReg(src1Reg); //set src value
|
|
MIB.addReg(src2Reg); //set src value
|
|
|
|
blk->insert(instrPos, newInstr);
|
|
SHOWNEWINSTR(newInstr);
|
|
|
|
} //insertCompareInstrBefore
|
|
|
|
static void cloneSuccessorList(MachineBasicBlock *dstBlk,
|
|
MachineBasicBlock *srcBlk) {
|
|
for (MachineBasicBlock::succ_iterator iter = srcBlk->succ_begin(),
|
|
iterEnd = srcBlk->succ_end(); iter != iterEnd; ++iter) {
|
|
dstBlk->addSuccessor(*iter); // *iter's predecessor is also taken care of
|
|
}
|
|
} //cloneSuccessorList
|
|
|
|
static MachineBasicBlock *clone(MachineBasicBlock *srcBlk) {
|
|
MachineFunction *func = srcBlk->getParent();
|
|
MachineBasicBlock *newBlk = func->CreateMachineBasicBlock();
|
|
func->push_back(newBlk); //insert to function
|
|
for (MachineBasicBlock::iterator iter = srcBlk->begin(),
|
|
iterEnd = srcBlk->end();
|
|
iter != iterEnd; ++iter) {
|
|
MachineInstr *instr = func->CloneMachineInstr(iter);
|
|
newBlk->push_back(instr);
|
|
}
|
|
return newBlk;
|
|
}
|
|
|
|
//MachineBasicBlock::ReplaceUsesOfBlockWith doesn't serve the purpose because
|
|
//the AMDGPU instruction is not recognized as terminator fix this and retire
|
|
//this routine
|
|
static void replaceInstrUseOfBlockWith(MachineBasicBlock *srcBlk,
|
|
MachineBasicBlock *oldBlk,
|
|
MachineBasicBlock *newBlk) {
|
|
MachineInstr *branchInstr = getLoopendBlockBranchInstr(srcBlk);
|
|
if (branchInstr && isCondBranch(branchInstr) &&
|
|
getTrueBranch(branchInstr) == oldBlk) {
|
|
setTrueBranch(branchInstr, newBlk);
|
|
}
|
|
}
|
|
|
|
static void wrapup(MachineBasicBlock *entryBlk) {
|
|
assert((!entryBlk->getParent()->getJumpTableInfo()
|
|
|| entryBlk->getParent()->getJumpTableInfo()->isEmpty())
|
|
&& "found a jump table");
|
|
|
|
//collect continue right before endloop
|
|
SmallVector<MachineInstr *, DEFAULT_VEC_SLOTS> contInstr;
|
|
MachineBasicBlock::iterator pre = entryBlk->begin();
|
|
MachineBasicBlock::iterator iterEnd = entryBlk->end();
|
|
MachineBasicBlock::iterator iter = pre;
|
|
while (iter != iterEnd) {
|
|
if (pre->getOpcode() == AMDGPU::CONTINUE
|
|
&& iter->getOpcode() == AMDGPU::ENDLOOP) {
|
|
contInstr.push_back(pre);
|
|
}
|
|
pre = iter;
|
|
++iter;
|
|
} //end while
|
|
|
|
//delete continue right before endloop
|
|
for (unsigned i = 0; i < contInstr.size(); ++i) {
|
|
contInstr[i]->eraseFromParent();
|
|
}
|
|
|
|
// TODO to fix up jump table so later phase won't be confused. if
|
|
// (jumpTableInfo->isEmpty() == false) { need to clean the jump table, but
|
|
// there isn't such an interface yet. alternatively, replace all the other
|
|
// blocks in the jump table with the entryBlk //}
|
|
|
|
} //wrapup
|
|
|
|
static MachineDominatorTree *getDominatorTree(AMDGPUCFGStructurizer &pass) {
|
|
return &pass.getAnalysis<MachineDominatorTree>();
|
|
}
|
|
|
|
static MachinePostDominatorTree*
|
|
getPostDominatorTree(AMDGPUCFGStructurizer &pass) {
|
|
return &pass.getAnalysis<MachinePostDominatorTree>();
|
|
}
|
|
|
|
static MachineLoopInfo *getLoopInfo(AMDGPUCFGStructurizer &pass) {
|
|
return &pass.getAnalysis<MachineLoopInfo>();
|
|
}
|
|
}; // template class CFGStructTraits
|
|
} //end of namespace llvm
|
|
|
|
// createAMDGPUCFGPreparationPass- Returns a pass
|
|
FunctionPass *llvm::createAMDGPUCFGPreparationPass(TargetMachine &tm
|
|
) {
|
|
return new AMDGPUCFGPrepare(tm );
|
|
}
|
|
|
|
bool AMDGPUCFGPrepare::runOnMachineFunction(MachineFunction &func) {
|
|
return llvmCFGStruct::CFGStructurizer<AMDGPUCFGStructurizer>().prepare(func,
|
|
*this,
|
|
TRI);
|
|
}
|
|
|
|
// createAMDGPUCFGStructurizerPass- Returns a pass
|
|
FunctionPass *llvm::createAMDGPUCFGStructurizerPass(TargetMachine &tm
|
|
) {
|
|
return new AMDGPUCFGPerform(tm );
|
|
}
|
|
|
|
bool AMDGPUCFGPerform::runOnMachineFunction(MachineFunction &func) {
|
|
return llvmCFGStruct::CFGStructurizer<AMDGPUCFGStructurizer>().run(func,
|
|
*this,
|
|
TRI);
|
|
}
|