void VectorBlockGenerator::copyStmt(ScopStmt &Stmt) { assert(Stmt.isBlockStmt() && "TODO: Only block statements can be copied by " "the vector block generator"); BasicBlock *BB = Stmt.getBasicBlock(); BasicBlock *CopyBB = SplitBlock(Builder.GetInsertBlock(), Builder.GetInsertPoint(), &DT, &LI); CopyBB->setName("polly.stmt." + BB->getName()); Builder.SetInsertPoint(CopyBB->begin()); // Create two maps that store the mapping from the original instructions of // the old basic block to their copies in the new basic block. Those maps // are basic block local. // // As vector code generation is supported there is one map for scalar values // and one for vector values. // // In case we just do scalar code generation, the vectorMap is not used and // the scalarMap has just one dimension, which contains the mapping. // // In case vector code generation is done, an instruction may either appear // in the vector map once (as it is calculating >vectorwidth< values at a // time. Or (if the values are calculated using scalar operations), it // appears once in every dimension of the scalarMap. VectorValueMapT ScalarBlockMap(getVectorWidth()); ValueMapT VectorBlockMap; for (Instruction &Inst : *BB) copyInstruction(Stmt, &Inst, VectorBlockMap, ScalarBlockMap); }
void BlockGenerator::copyStmt(ScopStmt &Stmt, ValueMapT &GlobalMap, LoopToScevMapT <S) { assert(Stmt.isBlockStmt() && "Only block statements can be copied by the block generator"); ValueMapT BBMap; BasicBlock *BB = Stmt.getBasicBlock(); copyBB(Stmt, BB, BBMap, GlobalMap, LTS); }
void BlockGenerator::generateScalarStores(ScopStmt &Stmt, BasicBlock *BB, ValueMapT &BBMap, ValueMapT &GlobalMap) { const Region &R = Stmt.getParent()->getRegion(); assert(Stmt.isBlockStmt() && BB == Stmt.getBasicBlock() && "Region statements need to use the generateScalarStores() " "function in the RegionGenerator"); // Set to remember a store to the phiops alloca of a PHINode. It is needed as // we might have multiple write accesses to the same PHI and while one is the // self write of the PHI (to the ScalarMap alloca) the other is the write to // the operand alloca (PHIOpMap). SmallPtrSet<PHINode *, 4> SeenPHIs; // 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); // Get the alloca node for the base instruction and the value we want to // store. In total there are 4 options: // (1) The base is no PHI, hence it is a simple scalar def-use chain. // (2) The base is a PHI, // (a) and the write is caused by an operand in the block. // (b) and it is the PHI self write (same as case (1)). // (c) (2a) and (2b) are not distinguishable. // For case (1) and (2b) we get the alloca from the scalar map and the value // we want to store is initialized with the instruction attached to the // memory access. For case (2a) we get the alloca from the PHI operand map // and the value we want to store is initialized with the incoming value for // this block. The tricky case (2c) is when both (2a) and (2b) match. This // happens if the PHI operand is in the same block as the PHI. To handle // that we choose the alloca of (2a) first and (2b) for the next write // access to that PHI (there must be 2). Value *ScalarValue = nullptr; AllocaInst *ScalarAddr = nullptr; if (!ScalarBasePHI) { // Case (1) ScalarAddr = getOrCreateAlloca(ScalarBase, ScalarMap, ".s2a"); ScalarValue = ScalarInst; } else { int PHIIdx = ScalarBasePHI->getBasicBlockIndex(BB); if (ScalarBasePHI != ScalarInst) { // Case (2a) assert(PHIIdx >= 0 && "Bad scalar write to PHI operand"); SeenPHIs.insert(ScalarBasePHI); ScalarAddr = getOrCreateAlloca(ScalarBase, PHIOpMap, ".phiops"); ScalarValue = ScalarBasePHI->getIncomingValue(PHIIdx); } else if (PHIIdx < 0) { // Case (2b) ScalarAddr = getOrCreateAlloca(ScalarBase, ScalarMap, ".s2a"); ScalarValue = ScalarInst; } else { // Case (2c) if (SeenPHIs.insert(ScalarBasePHI).second) { // First access ==> same as (2a) ScalarAddr = getOrCreateAlloca(ScalarBase, PHIOpMap, ".phiops"); ScalarValue = ScalarBasePHI->getIncomingValue(PHIIdx); } else { // Second access ==> same as (2b) ScalarAddr = getOrCreateAlloca(ScalarBase, ScalarMap, ".s2a"); ScalarValue = ScalarInst; } } } ScalarValue = getNewScalarValue(ScalarValue, R, ScalarMap, BBMap, GlobalMap); Builder.CreateStore(ScalarValue, ScalarAddr); } }
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); }