Path: blob/main/contrib/llvm-project/llvm/lib/Transforms/Vectorize/VPlanUtils.h
213799 views
//===- VPlanUtils.h - VPlan-related utilities -------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#ifndef LLVM_TRANSFORMS_VECTORIZE_VPLANUTILS_H9#define LLVM_TRANSFORMS_VECTORIZE_VPLANUTILS_H1011#include "VPlan.h"1213namespace llvm {14class ScalarEvolution;15class SCEV;16} // namespace llvm1718namespace llvm {1920namespace vputils {21/// Returns true if only the first lane of \p Def is used.22bool onlyFirstLaneUsed(const VPValue *Def);2324/// Returns true if only the first part of \p Def is used.25bool onlyFirstPartUsed(const VPValue *Def);2627/// Get or create a VPValue that corresponds to the expansion of \p Expr. If \p28/// Expr is a SCEVConstant or SCEVUnknown, return a VPValue wrapping the live-in29/// value. Otherwise return a VPExpandSCEVRecipe to expand \p Expr. If \p Plan's30/// pre-header already contains a recipe expanding \p Expr, return it. If not,31/// create a new one.32VPValue *getOrCreateVPValueForSCEVExpr(VPlan &Plan, const SCEV *Expr,33ScalarEvolution &SE);3435/// Return the SCEV expression for \p V. Returns SCEVCouldNotCompute if no36/// SCEV expression could be constructed.37const SCEV *getSCEVExprForVPValue(VPValue *V, ScalarEvolution &SE);3839/// Returns true if \p VPV is a single scalar, either because it produces the40/// same value for all lanes or only has its first lane used.41inline bool isSingleScalar(const VPValue *VPV) {42auto PreservesUniformity = [](unsigned Opcode) -> bool {43if (Instruction::isBinaryOp(Opcode) || Instruction::isCast(Opcode))44return true;45switch (Opcode) {46case Instruction::GetElementPtr:47case Instruction::ICmp:48case Instruction::FCmp:49case VPInstruction::Broadcast:50case VPInstruction::PtrAdd:51return true;52default:53return false;54}55};5657// A live-in must be uniform across the scope of VPlan.58if (VPV->isLiveIn())59return true;6061if (auto *Rep = dyn_cast<VPReplicateRecipe>(VPV)) {62const VPRegionBlock *RegionOfR = Rep->getParent()->getParent();63// Don't consider recipes in replicate regions as uniform yet; their first64// lane cannot be accessed when executing the replicate region for other65// lanes.66if (RegionOfR && RegionOfR->isReplicator())67return false;68return Rep->isSingleScalar() || (PreservesUniformity(Rep->getOpcode()) &&69all_of(Rep->operands(), isSingleScalar));70}71if (isa<VPWidenGEPRecipe, VPDerivedIVRecipe, VPBlendRecipe,72VPWidenSelectRecipe>(VPV))73return all_of(VPV->getDefiningRecipe()->operands(), isSingleScalar);74if (auto *WidenR = dyn_cast<VPWidenRecipe>(VPV)) {75return PreservesUniformity(WidenR->getOpcode()) &&76all_of(WidenR->operands(), isSingleScalar);77}78if (auto *VPI = dyn_cast<VPInstruction>(VPV))79return VPI->isSingleScalar() || VPI->isVectorToScalar() ||80(PreservesUniformity(VPI->getOpcode()) &&81all_of(VPI->operands(), isSingleScalar));8283// VPExpandSCEVRecipes must be placed in the entry and are alway uniform.84return isa<VPExpandSCEVRecipe>(VPV);85}8687/// Return true if \p V is a header mask in \p Plan.88bool isHeaderMask(const VPValue *V, VPlan &Plan);8990/// Checks if \p V is uniform across all VF lanes and UF parts. It is considered91/// as such if it is either loop invariant (defined outside the vector region)92/// or its operand is known to be uniform across all VFs and UFs (e.g.93/// VPDerivedIV or VPCanonicalIVPHI).94bool isUniformAcrossVFsAndUFs(VPValue *V);9596/// Returns the header block of the first, top-level loop, or null if none97/// exist.98VPBasicBlock *getFirstLoopHeader(VPlan &Plan, VPDominatorTree &VPDT);99} // namespace vputils100101//===----------------------------------------------------------------------===//102// Utilities for modifying predecessors and successors of VPlan blocks.103//===----------------------------------------------------------------------===//104105/// Class that provides utilities for VPBlockBases in VPlan.106class VPBlockUtils {107public:108VPBlockUtils() = delete;109110/// Insert disconnected VPBlockBase \p NewBlock after \p BlockPtr. Add \p111/// NewBlock as successor of \p BlockPtr and \p BlockPtr as predecessor of \p112/// NewBlock, and propagate \p BlockPtr parent to \p NewBlock. \p BlockPtr's113/// successors are moved from \p BlockPtr to \p NewBlock. \p NewBlock must114/// have neither successors nor predecessors.115static void insertBlockAfter(VPBlockBase *NewBlock, VPBlockBase *BlockPtr) {116assert(NewBlock->getSuccessors().empty() &&117NewBlock->getPredecessors().empty() &&118"Can't insert new block with predecessors or successors.");119NewBlock->setParent(BlockPtr->getParent());120SmallVector<VPBlockBase *> Succs(BlockPtr->successors());121for (VPBlockBase *Succ : Succs) {122Succ->replacePredecessor(BlockPtr, NewBlock);123NewBlock->appendSuccessor(Succ);124}125BlockPtr->clearSuccessors();126connectBlocks(BlockPtr, NewBlock);127}128129/// Insert disconnected block \p NewBlock before \p Blockptr. First130/// disconnects all predecessors of \p BlockPtr and connects them to \p131/// NewBlock. Add \p NewBlock as predecessor of \p BlockPtr and \p BlockPtr as132/// successor of \p NewBlock.133static void insertBlockBefore(VPBlockBase *NewBlock, VPBlockBase *BlockPtr) {134assert(NewBlock->getSuccessors().empty() &&135NewBlock->getPredecessors().empty() &&136"Can't insert new block with predecessors or successors.");137NewBlock->setParent(BlockPtr->getParent());138for (VPBlockBase *Pred : to_vector(BlockPtr->predecessors())) {139Pred->replaceSuccessor(BlockPtr, NewBlock);140NewBlock->appendPredecessor(Pred);141}142BlockPtr->clearPredecessors();143connectBlocks(NewBlock, BlockPtr);144}145146/// Insert disconnected VPBlockBases \p IfTrue and \p IfFalse after \p147/// BlockPtr. Add \p IfTrue and \p IfFalse as succesors of \p BlockPtr and \p148/// BlockPtr as predecessor of \p IfTrue and \p IfFalse. Propagate \p BlockPtr149/// parent to \p IfTrue and \p IfFalse. \p BlockPtr must have no successors150/// and \p IfTrue and \p IfFalse must have neither successors nor151/// predecessors.152static void insertTwoBlocksAfter(VPBlockBase *IfTrue, VPBlockBase *IfFalse,153VPBlockBase *BlockPtr) {154assert(IfTrue->getSuccessors().empty() &&155"Can't insert IfTrue with successors.");156assert(IfFalse->getSuccessors().empty() &&157"Can't insert IfFalse with successors.");158BlockPtr->setTwoSuccessors(IfTrue, IfFalse);159IfTrue->setPredecessors({BlockPtr});160IfFalse->setPredecessors({BlockPtr});161IfTrue->setParent(BlockPtr->getParent());162IfFalse->setParent(BlockPtr->getParent());163}164165/// Connect VPBlockBases \p From and \p To bi-directionally. If \p PredIdx is166/// -1, append \p From to the predecessors of \p To, otherwise set \p To's167/// predecessor at \p PredIdx to \p From. If \p SuccIdx is -1, append \p To to168/// the successors of \p From, otherwise set \p From's successor at \p SuccIdx169/// to \p To. Both VPBlockBases must have the same parent, which can be null.170/// Both VPBlockBases can be already connected to other VPBlockBases.171static void connectBlocks(VPBlockBase *From, VPBlockBase *To,172unsigned PredIdx = -1u, unsigned SuccIdx = -1u) {173assert((From->getParent() == To->getParent()) &&174"Can't connect two block with different parents");175assert((SuccIdx != -1u || From->getNumSuccessors() < 2) &&176"Blocks can't have more than two successors.");177if (SuccIdx == -1u)178From->appendSuccessor(To);179else180From->getSuccessors()[SuccIdx] = To;181182if (PredIdx == -1u)183To->appendPredecessor(From);184else185To->getPredecessors()[PredIdx] = From;186}187188/// Disconnect VPBlockBases \p From and \p To bi-directionally. Remove \p To189/// from the successors of \p From and \p From from the predecessors of \p To.190static void disconnectBlocks(VPBlockBase *From, VPBlockBase *To) {191assert(To && "Successor to disconnect is null.");192From->removeSuccessor(To);193To->removePredecessor(From);194}195196/// Reassociate all the blocks connected to \p Old so that they now point to197/// \p New.198static void reassociateBlocks(VPBlockBase *Old, VPBlockBase *New) {199for (auto *Pred : to_vector(Old->getPredecessors()))200Pred->replaceSuccessor(Old, New);201for (auto *Succ : to_vector(Old->getSuccessors()))202Succ->replacePredecessor(Old, New);203New->setPredecessors(Old->getPredecessors());204New->setSuccessors(Old->getSuccessors());205Old->clearPredecessors();206Old->clearSuccessors();207}208209/// Return an iterator range over \p Range which only includes \p BlockTy210/// blocks. The accesses are casted to \p BlockTy.211template <typename BlockTy, typename T>212static auto blocksOnly(const T &Range) {213// Create BaseTy with correct const-ness based on BlockTy.214using BaseTy = std::conditional_t<std::is_const<BlockTy>::value,215const VPBlockBase, VPBlockBase>;216217// We need to first create an iterator range over (const) BlocktTy & instead218// of (const) BlockTy * for filter_range to work properly.219auto Mapped =220map_range(Range, [](BaseTy *Block) -> BaseTy & { return *Block; });221auto Filter = make_filter_range(222Mapped, [](BaseTy &Block) { return isa<BlockTy>(&Block); });223return map_range(Filter, [](BaseTy &Block) -> BlockTy * {224return cast<BlockTy>(&Block);225});226}227228/// Inserts \p BlockPtr on the edge between \p From and \p To. That is, update229/// \p From's successor to \p To to point to \p BlockPtr and \p To's230/// predecessor from \p From to \p BlockPtr. \p From and \p To are added to \p231/// BlockPtr's predecessors and successors respectively. There must be a232/// single edge between \p From and \p To.233static void insertOnEdge(VPBlockBase *From, VPBlockBase *To,234VPBlockBase *BlockPtr) {235unsigned SuccIdx = From->getIndexForSuccessor(To);236unsigned PredIx = To->getIndexForPredecessor(From);237VPBlockUtils::connectBlocks(From, BlockPtr, -1, SuccIdx);238VPBlockUtils::connectBlocks(BlockPtr, To, PredIx, -1);239}240241/// Returns true if \p VPB is a loop header, based on regions or \p VPDT in242/// their absence.243static bool isHeader(const VPBlockBase *VPB, const VPDominatorTree &VPDT);244245/// Returns true if \p VPB is a loop latch, using isHeader().246static bool isLatch(const VPBlockBase *VPB, const VPDominatorTree &VPDT);247};248249} // namespace llvm250251#endif252253254