#include "VPlanHCFGBuilder.h"
#include "LoopVectorizationPlanner.h"
#include "llvm/Analysis/LoopIterator.h"
#define DEBUG_TYPE "loop-vectorize"
using namespace llvm;
namespace {
class PlainCFGBuilder {
private:
Loop *TheLoop;
LoopInfo *LI;
VPlan &Plan;
VPBuilder VPIRBuilder;
DenseMap<BasicBlock *, VPBasicBlock *> BB2VPBB;
DenseMap<Value *, VPValue *> IRDef2VPValue;
SmallVector<PHINode *, 8> PhisToFix;
DenseMap<Loop *, VPRegionBlock *> Loop2Region;
void setVPBBPredsFromBB(VPBasicBlock *VPBB, BasicBlock *BB);
void fixPhiNodes();
VPBasicBlock *getOrCreateVPBB(BasicBlock *BB);
#ifndef NDEBUG
bool isExternalDef(Value *Val);
#endif
VPValue *getOrCreateVPOperand(Value *IRVal);
void createVPInstructionsForVPBB(VPBasicBlock *VPBB, BasicBlock *BB);
public:
PlainCFGBuilder(Loop *Lp, LoopInfo *LI, VPlan &P)
: TheLoop(Lp), LI(LI), Plan(P) {}
VPBasicBlock *buildPlainCFG();
};
}
void PlainCFGBuilder::setVPBBPredsFromBB(VPBasicBlock *VPBB, BasicBlock *BB) {
SmallVector<VPBlockBase *, 8> VPBBPreds;
for (BasicBlock *Pred : predecessors(BB))
VPBBPreds.push_back(getOrCreateVPBB(Pred));
VPBB->setPredecessors(VPBBPreds);
}
void PlainCFGBuilder::fixPhiNodes() {
for (auto *Phi : PhisToFix) {
assert(IRDef2VPValue.count(Phi) && "Missing VPInstruction for PHINode.");
VPValue *VPVal = IRDef2VPValue[Phi];
assert(isa<VPWidenPHIRecipe>(VPVal) &&
"Expected WidenPHIRecipe for phi node.");
auto *VPPhi = cast<VPWidenPHIRecipe>(VPVal);
assert(VPPhi->getNumOperands() == 0 &&
"Expected VPInstruction with no operands.");
for (unsigned I = 0; I != Phi->getNumOperands(); ++I)
VPPhi->addIncoming(getOrCreateVPOperand(Phi->getIncomingValue(I)),
BB2VPBB[Phi->getIncomingBlock(I)]);
}
}
VPBasicBlock *PlainCFGBuilder::getOrCreateVPBB(BasicBlock *BB) {
auto BlockIt = BB2VPBB.find(BB);
if (BlockIt != BB2VPBB.end())
return BlockIt->second;
Loop *CurrentLoop = LI->getLoopFor(BB);
VPRegionBlock *ParentR = nullptr;
if (CurrentLoop) {
auto Iter = Loop2Region.insert({CurrentLoop, nullptr});
if (Iter.second)
Iter.first->second = new VPRegionBlock(
CurrentLoop->getHeader()->getName().str(), false );
ParentR = Iter.first->second;
}
LLVM_DEBUG(dbgs() << "Creating VPBasicBlock for " << BB->getName() << "\n");
VPBasicBlock *VPBB = new VPBasicBlock(BB->getName());
BB2VPBB[BB] = VPBB;
VPBB->setParent(ParentR);
return VPBB;
}
#ifndef NDEBUG
bool PlainCFGBuilder::isExternalDef(Value *Val) {
Instruction *Inst = dyn_cast<Instruction>(Val);
if (!Inst)
return true;
BasicBlock *InstParent = Inst->getParent();
assert(InstParent && "Expected instruction parent.");
BasicBlock *PH = TheLoop->getLoopPreheader();
assert(PH && "Expected loop pre-header.");
if (InstParent == PH)
return false;
BasicBlock *Exit = TheLoop->getUniqueExitBlock();
assert(Exit && "Expected loop with single exit.");
if (InstParent == Exit) {
return false;
}
return !TheLoop->contains(Inst);
}
#endif
VPValue *PlainCFGBuilder::getOrCreateVPOperand(Value *IRVal) {
auto VPValIt = IRDef2VPValue.find(IRVal);
if (VPValIt != IRDef2VPValue.end())
return VPValIt->second;
assert(isExternalDef(IRVal) && "Expected external definition as operand.");
VPValue *NewVPVal = Plan.getOrAddExternalDef(IRVal);
IRDef2VPValue[IRVal] = NewVPVal;
return NewVPVal;
}
void PlainCFGBuilder::createVPInstructionsForVPBB(VPBasicBlock *VPBB,
BasicBlock *BB) {
VPIRBuilder.setInsertPoint(VPBB);
for (Instruction &InstRef : *BB) {
Instruction *Inst = &InstRef;
assert(!IRDef2VPValue.count(Inst) &&
"Instruction shouldn't have been visited.");
if (auto *Br = dyn_cast<BranchInst>(Inst)) {
if (Br->isConditional()) {
VPValue *Cond = getOrCreateVPOperand(Br->getCondition());
VPBB->appendRecipe(
new VPInstruction(VPInstruction::BranchOnCond, {Cond}));
}
continue;
}
VPValue *NewVPV;
if (auto *Phi = dyn_cast<PHINode>(Inst)) {
NewVPV = new VPWidenPHIRecipe(Phi);
VPBB->appendRecipe(cast<VPWidenPHIRecipe>(NewVPV));
PhisToFix.push_back(Phi);
} else {
SmallVector<VPValue *, 4> VPOperands;
for (Value *Op : Inst->operands())
VPOperands.push_back(getOrCreateVPOperand(Op));
NewVPV = cast<VPInstruction>(
VPIRBuilder.createNaryOp(Inst->getOpcode(), VPOperands, Inst));
}
IRDef2VPValue[Inst] = NewVPV;
}
}
VPBasicBlock *PlainCFGBuilder::buildPlainCFG() {
BasicBlock *ThePreheaderBB = TheLoop->getLoopPreheader();
assert((ThePreheaderBB->getTerminator()->getNumSuccessors() == 1) &&
"Unexpected loop preheader");
VPBasicBlock *ThePreheaderVPBB = getOrCreateVPBB(ThePreheaderBB);
ThePreheaderVPBB->setName("vector.ph");
for (auto &I : *ThePreheaderBB) {
if (I.getType()->isVoidTy())
continue;
IRDef2VPValue[&I] = Plan.getOrAddExternalDef(&I);
}
VPBlockBase *HeaderVPBB = getOrCreateVPBB(TheLoop->getHeader());
HeaderVPBB->setName("vector.body");
ThePreheaderVPBB->setOneSuccessor(HeaderVPBB);
LoopBlocksRPO RPO(TheLoop);
RPO.perform(LI);
for (BasicBlock *BB : RPO) {
VPBasicBlock *VPBB = getOrCreateVPBB(BB);
createVPInstructionsForVPBB(VPBB, BB);
Instruction *TI = BB->getTerminator();
assert(TI && "Terminator expected.");
unsigned NumSuccs = TI->getNumSuccessors();
if (NumSuccs == 1) {
VPBasicBlock *SuccVPBB = getOrCreateVPBB(TI->getSuccessor(0));
assert(SuccVPBB && "VPBB Successor not found.");
VPBB->setOneSuccessor(SuccVPBB);
} else if (NumSuccs == 2) {
VPBasicBlock *SuccVPBB0 = getOrCreateVPBB(TI->getSuccessor(0));
assert(SuccVPBB0 && "Successor 0 not found.");
VPBasicBlock *SuccVPBB1 = getOrCreateVPBB(TI->getSuccessor(1));
assert(SuccVPBB1 && "Successor 1 not found.");
assert(isa<BranchInst>(TI) && "Unsupported terminator!");
assert(IRDef2VPValue.count(cast<BranchInst>(TI)->getCondition()) &&
"Missing condition bit in IRDef2VPValue!");
VPBB->setTwoSuccessors(SuccVPBB0, SuccVPBB1);
} else
llvm_unreachable("Number of successors not supported.");
setVPBBPredsFromBB(VPBB, BB);
}
BasicBlock *LoopExitBB = TheLoop->getUniqueExitBlock();
assert(LoopExitBB && "Loops with multiple exits are not supported.");
VPBasicBlock *LoopExitVPBB = BB2VPBB[LoopExitBB];
setVPBBPredsFromBB(LoopExitVPBB, LoopExitBB);
SmallVector<Loop *> LoopWorkList;
LoopWorkList.push_back(TheLoop);
while (!LoopWorkList.empty()) {
Loop *L = LoopWorkList.pop_back_val();
BasicBlock *Header = L->getHeader();
BasicBlock *Exiting = L->getLoopLatch();
assert(Exiting == L->getExitingBlock() &&
"Latch must be the only exiting block");
VPRegionBlock *Region = Loop2Region[L];
VPBasicBlock *HeaderVPBB = getOrCreateVPBB(Header);
VPBasicBlock *ExitingVPBB = getOrCreateVPBB(Exiting);
VPBasicBlock *PreheaderVPBB = getOrCreateVPBB(L->getLoopPreheader());
VPBlockUtils::disconnectBlocks(PreheaderVPBB, HeaderVPBB);
VPBlockUtils::disconnectBlocks(ExitingVPBB, HeaderVPBB);
Region->setParent(PreheaderVPBB->getParent());
Region->setEntry(HeaderVPBB);
VPBlockUtils::connectBlocks(PreheaderVPBB, Region);
VPBasicBlock *ExitVPBB = getOrCreateVPBB(L->getExitBlock());
VPBlockUtils::disconnectBlocks(ExitingVPBB, ExitVPBB);
Region->setExiting(ExitingVPBB);
VPBlockUtils::connectBlocks(Region, ExitVPBB);
LoopWorkList.append(L->begin(), L->end());
}
fixPhiNodes();
return ThePreheaderVPBB;
}
VPBasicBlock *VPlanHCFGBuilder::buildPlainCFG() {
PlainCFGBuilder PCFGBuilder(TheLoop, LI, Plan);
return PCFGBuilder.buildPlainCFG();
}
void VPlanHCFGBuilder::buildHierarchicalCFG() {
VPBasicBlock *EntryVPBB = buildPlainCFG();
Plan.setEntry(EntryVPBB);
LLVM_DEBUG(Plan.setName("HCFGBuilder: Plain CFG\n"); dbgs() << Plan);
VPRegionBlock *TopRegion = Plan.getVectorLoopRegion();
Verifier.verifyHierarchicalCFG(TopRegion);
VPDomTree.recalculate(*TopRegion);
LLVM_DEBUG(dbgs() << "Dominator Tree after building the plain CFG.\n";
VPDomTree.print(dbgs()));
}