void RegionGenerator::addOperandToPHI(ScopStmt &Stmt, const PHINode *PHI, PHINode *PHICopy, BasicBlock *IncomingBB, ValueMapT &GlobalMap, LoopToScevMapT <S) { Region *StmtR = Stmt.getRegion(); // If the incoming block was not yet copied mark this PHI as incomplete. // Once the block will be copied the incoming value will be added. BasicBlock *BBCopy = BlockMap[IncomingBB]; if (!BBCopy) { assert(StmtR->contains(IncomingBB) && "Bad incoming block for PHI in non-affine region"); IncompletePHINodeMap[IncomingBB].push_back(std::make_pair(PHI, PHICopy)); return; } Value *OpCopy = nullptr; if (StmtR->contains(IncomingBB)) { assert(RegionMaps.count(BBCopy) && "Incoming PHI block did not have a BBMap"); ValueMapT &BBCopyMap = RegionMaps[BBCopy]; Value *Op = PHI->getIncomingValueForBlock(IncomingBB); OpCopy = getNewValue(Stmt, Op, BBCopyMap, GlobalMap, LTS, getLoopForInst(PHI)); } else { if (PHICopy->getBasicBlockIndex(BBCopy) >= 0) return; AllocaInst *PHIOpAddr = getOrCreateAlloca(const_cast<PHINode *>(PHI), PHIOpMap, ".phiops"); OpCopy = new LoadInst(PHIOpAddr, PHIOpAddr->getName() + ".reload", BlockMap[IncomingBB]->getTerminator()); } assert(OpCopy && "Incoming PHI value was not copied properly"); assert(BBCopy && "Incoming PHI block was not copied properly"); PHICopy->addIncoming(OpCopy, BBCopy); }
void BlockGenerator::copyInstruction(ScopStmt &Stmt, const Instruction *Inst, ValueMapT &BBMap, ValueMapT &GlobalMap, LoopToScevMapT <S) { // First check for possible scalar dependences for this instruction. generateScalarLoads(Stmt, Inst, BBMap); // Terminator instructions control the control flow. They are explicitly // expressed in the clast and do not need to be copied. if (Inst->isTerminator()) return; Loop *L = getLoopForInst(Inst); if ((Stmt.isBlockStmt() || !Stmt.getRegion()->contains(L)) && canSynthesize(Inst, &LI, &SE, &Stmt.getParent()->getRegion())) { Value *NewValue = getNewValue(Stmt, Inst, BBMap, GlobalMap, LTS, L); BBMap[Inst] = NewValue; return; } if (const LoadInst *Load = dyn_cast<LoadInst>(Inst)) { Value *NewLoad = generateScalarLoad(Stmt, Load, BBMap, GlobalMap, LTS); // Compute NewLoad before its insertion in BBMap to make the insertion // deterministic. BBMap[Load] = NewLoad; return; } if (const StoreInst *Store = dyn_cast<StoreInst>(Inst)) { Value *NewStore = generateScalarStore(Stmt, Store, BBMap, GlobalMap, LTS); // Compute NewStore before its insertion in BBMap to make the insertion // deterministic. BBMap[Store] = NewStore; return; } if (const PHINode *PHI = dyn_cast<PHINode>(Inst)) { copyPHIInstruction(Stmt, PHI, BBMap, GlobalMap, LTS); return; } // Skip some special intrinsics for which we do not adjust the semantics to // the new schedule. All others are handled like every other instruction. if (auto *IT = dyn_cast<IntrinsicInst>(Inst)) { switch (IT->getIntrinsicID()) { // Lifetime markers are ignored. case llvm::Intrinsic::lifetime_start: case llvm::Intrinsic::lifetime_end: // Invariant markers are ignored. case llvm::Intrinsic::invariant_start: case llvm::Intrinsic::invariant_end: // Some misc annotations are ignored. case llvm::Intrinsic::var_annotation: case llvm::Intrinsic::ptr_annotation: case llvm::Intrinsic::annotation: case llvm::Intrinsic::donothing: case llvm::Intrinsic::assume: case llvm::Intrinsic::expect: return; default: // Other intrinsics are copied. break; } } copyInstScalar(Stmt, Inst, BBMap, GlobalMap, LTS); }
void RegionGenerator::generateScalarStores(ScopStmt &Stmt, BasicBlock *BB, ValueMapT &BBMap, ValueMapT &GlobalMap) { const Region &R = Stmt.getParent()->getRegion(); Region *StmtR = Stmt.getRegion(); assert(StmtR && "Block statements need to use the generateScalarStores() " "function in the BlockGenerator"); BasicBlock *ExitBB = StmtR->getExit(); // For region statements three kinds of scalar stores exists: // (1) A definition used by a non-phi instruction outside the region. // (2) A phi-instruction in the region entry. // (3) A write to a phi instruction in the region exit. // The last case is the tricky one since we do not know anymore which // predecessor of the exit needs to store the operand value that doesn't // have a definition in the region. Therefore, we have to check in each // block in the region if we should store the value or not. // Iterate over all accesses in the given statement. for (MemoryAccess *MA : Stmt) { // Skip non-scalar and read accesses. if (!MA->isScalar() || MA->isRead()) continue; Instruction *ScalarBase = cast<Instruction>(MA->getBaseAddr()); Instruction *ScalarInst = MA->getAccessInstruction(); PHINode *ScalarBasePHI = dyn_cast<PHINode>(ScalarBase); Value *ScalarValue = nullptr; AllocaInst *ScalarAddr = nullptr; if (!ScalarBasePHI) { // Case (1) ScalarAddr = getOrCreateAlloca(ScalarBase, ScalarMap, ".s2a"); ScalarValue = ScalarInst; } else if (ScalarBasePHI->getParent() != ExitBB) { // Case (2) assert(ScalarBasePHI->getParent() == StmtR->getEntry() && "Bad PHI self write in non-affine region"); assert(ScalarBase == ScalarInst && "Bad PHI self write in non-affine region"); ScalarAddr = getOrCreateAlloca(ScalarBase, ScalarMap, ".s2a"); ScalarValue = ScalarInst; } else { int PHIIdx = ScalarBasePHI->getBasicBlockIndex(BB); // Skip accesses we will not handle in this basic block but in another one // in the statement region. if (PHIIdx < 0) continue; // Case (3) ScalarAddr = getOrCreateAlloca(ScalarBase, PHIOpMap, ".phiops"); ScalarValue = ScalarBasePHI->getIncomingValue(PHIIdx); } ScalarValue = getNewScalarValue(ScalarValue, R, ScalarMap, BBMap, GlobalMap); Builder.CreateStore(ScalarValue, ScalarAddr); } }
void RegionGenerator::copyStmt(ScopStmt &Stmt, ValueMapT &GlobalMap, LoopToScevMapT <S) { assert(Stmt.isRegionStmt() && "Only region statements can be copied by the block generator"); // Forget all old mappings. BlockMap.clear(); RegionMaps.clear(); IncompletePHINodeMap.clear(); // The region represented by the statement. Region *R = Stmt.getRegion(); // Create a dedicated entry for the region where we can reload all demoted // inputs. BasicBlock *EntryBB = R->getEntry(); BasicBlock *EntryBBCopy = SplitBlock(Builder.GetInsertBlock(), Builder.GetInsertPoint(), &DT, &LI); EntryBBCopy->setName("polly.stmt." + EntryBB->getName() + ".entry"); Builder.SetInsertPoint(EntryBBCopy->begin()); for (auto PI = pred_begin(EntryBB), PE = pred_end(EntryBB); PI != PE; ++PI) if (!R->contains(*PI)) BlockMap[*PI] = EntryBBCopy; // Iterate over all blocks in the region in a breadth-first search. std::deque<BasicBlock *> Blocks; SmallPtrSet<BasicBlock *, 8> SeenBlocks; Blocks.push_back(EntryBB); SeenBlocks.insert(EntryBB); while (!Blocks.empty()) { BasicBlock *BB = Blocks.front(); Blocks.pop_front(); // First split the block and update dominance information. BasicBlock *BBCopy = splitBB(BB); BasicBlock *BBCopyIDom = repairDominance(BB, BBCopy); // In order to remap PHI nodes we store also basic block mappings. BlockMap[BB] = BBCopy; // Get the mapping for this block and initialize it with the mapping // available at its immediate dominator (in the new region). ValueMapT &RegionMap = RegionMaps[BBCopy]; RegionMap = RegionMaps[BBCopyIDom]; // Copy the block with the BlockGenerator. copyBB(Stmt, BB, BBCopy, RegionMap, GlobalMap, LTS); // In order to remap PHI nodes we store also basic block mappings. BlockMap[BB] = BBCopy; // Add values to incomplete PHI nodes waiting for this block to be copied. for (const PHINodePairTy &PHINodePair : IncompletePHINodeMap[BB]) addOperandToPHI(Stmt, PHINodePair.first, PHINodePair.second, BB, GlobalMap, LTS); IncompletePHINodeMap[BB].clear(); // And continue with new successors inside the region. for (auto SI = succ_begin(BB), SE = succ_end(BB); SI != SE; SI++) if (R->contains(*SI) && SeenBlocks.insert(*SI).second) Blocks.push_back(*SI); } // Now create a new dedicated region exit block and add it to the region map. BasicBlock *ExitBBCopy = SplitBlock(Builder.GetInsertBlock(), Builder.GetInsertPoint(), &DT, &LI); ExitBBCopy->setName("polly.stmt." + R->getExit()->getName() + ".exit"); BlockMap[R->getExit()] = ExitBBCopy; repairDominance(R->getExit(), ExitBBCopy); // As the block generator doesn't handle control flow we need to add the // region control flow by hand after all blocks have been copied. for (BasicBlock *BB : SeenBlocks) { BranchInst *BI = cast<BranchInst>(BB->getTerminator()); BasicBlock *BBCopy = BlockMap[BB]; Instruction *BICopy = BBCopy->getTerminator(); ValueMapT &RegionMap = RegionMaps[BBCopy]; RegionMap.insert(BlockMap.begin(), BlockMap.end()); Builder.SetInsertPoint(BBCopy); copyInstScalar(Stmt, BI, RegionMap, GlobalMap, LTS); BICopy->eraseFromParent(); } // Add counting PHI nodes to all loops in the region that can be used as // replacement for SCEVs refering to the old loop. for (BasicBlock *BB : SeenBlocks) { Loop *L = LI.getLoopFor(BB); if (L == nullptr || L->getHeader() != BB) continue; BasicBlock *BBCopy = BlockMap[BB]; Value *NullVal = Builder.getInt32(0); PHINode *LoopPHI = PHINode::Create(Builder.getInt32Ty(), 2, "polly.subregion.iv"); Instruction *LoopPHIInc = BinaryOperator::CreateAdd( LoopPHI, Builder.getInt32(1), "polly.subregion.iv.inc"); LoopPHI->insertBefore(BBCopy->begin()); LoopPHIInc->insertBefore(BBCopy->getTerminator()); for (auto *PredBB : make_range(pred_begin(BB), pred_end(BB))) { if (!R->contains(PredBB)) continue; if (L->contains(PredBB)) LoopPHI->addIncoming(LoopPHIInc, BlockMap[PredBB]); else LoopPHI->addIncoming(NullVal, BlockMap[PredBB]); } for (auto *PredBBCopy : make_range(pred_begin(BBCopy), pred_end(BBCopy))) if (LoopPHI->getBasicBlockIndex(PredBBCopy) < 0) LoopPHI->addIncoming(NullVal, PredBBCopy); LTS[L] = SE.getUnknown(LoopPHI); } // Add all mappings from the region to the global map so outside uses will use // the copied instructions. for (auto &BBMap : RegionMaps) GlobalMap.insert(BBMap.second.begin(), BBMap.second.end()); // Reset the old insert point for the build. Builder.SetInsertPoint(ExitBBCopy->begin()); }