30#define DEBUG_TYPE "predicateinfo"
32using namespace PatternMatch;
36 cl::desc(
"Verify PredicateInfo in legacy printer pass."));
38 "Controls which variables are renamed with predicateinfo");
49 "Only branches and switches should have PHIOnly defs that "
50 "require branch blocks.");
51 return cast<PredicateWithEdge>(
PB)->From;
58 "Not a predicate info type we know how to get a terminator from.");
59 return cast<PredicateWithEdge>(
PB)->From->getTerminator();
64std::pair<BasicBlock *, BasicBlock *> getBlockEdge(
const PredicateBase *
PB) {
66 "Not a predicate info type we know how to get an edge from.");
67 const auto *PEdge = cast<PredicateWithEdge>(
PB);
68 return std::make_pair(PEdge->From, PEdge->To);
99 auto *ArgA = dyn_cast_or_null<Argument>(
A);
100 auto *ArgB = dyn_cast_or_null<Argument>(
B);
106 return ArgA->getArgNo() < ArgB->getArgNo();
107 return cast<Instruction>(
A)->comesBefore(cast<Instruction>(
B));
124 assert((
A.DFSIn !=
B.DFSIn ||
A.DFSOut ==
B.DFSOut) &&
125 "Equal DFS-in numbers imply equal out numbers");
126 bool SameBlock =
A.DFSIn ==
B.DFSIn;
138 return std::tie(
A.DFSIn,
A.LocalNum, isADef) <
139 std::tie(
B.DFSIn,
B.LocalNum, isBDef);
145 if (!VD.
Def && VD.
U) {
146 auto *
PHI = cast<PHINode>(VD.
U->getUser());
147 return std::make_pair(
PHI->getIncomingBlock(*VD.
U),
PHI->getParent());
150 return ::getBlockEdge(VD.
PInfo);
164 "DFS numbers for A should match the ones of the source block");
166 "DFS numbers for B should match the ones of the source block");
167 assert(
A.DFSIn ==
B.DFSIn &&
"Values must be in the same block");
180 assert((!
A.Def || !
A.U) && (!
B.Def || !
B.U) &&
181 "Def and U cannot be set at the same time");
183 return std::tie(AIn, isADef) < std::tie(BIn, isBDef);
198 "No def, no use, and no predicateinfo should not occur");
200 "Middle of block should only occur for assumes");
201 return cast<PredicateAssume>(VD.
PInfo)->AssumeInst->getNextNode();
210 return cast<Instruction>(Def);
211 return cast<Instruction>(U->getUser());
223 auto *ArgA = dyn_cast_or_null<Argument>(ADef);
224 auto *ArgB = dyn_cast_or_null<Argument>(BDef);
282 : PI(PI),
F(
F), DT(DT), AC(AC) {
290bool PredicateInfoBuilder::stackIsInScope(
const ValueDFSStack &Stack,
299 if (Stack.back().EdgeOnly) {
302 auto *
PHI = dyn_cast<PHINode>(VDUse.
U->getUser());
307 if (EdgePred != getBranchBlock(Stack.back().PInfo))
311 return DT.
dominates(getBlockEdge(Stack.back().PInfo), *VDUse.
U);
318void PredicateInfoBuilder::popStackUntilDFSScope(ValueDFSStack &Stack,
320 while (!
Stack.empty() && !stackIsInScope(Stack, VD))
326void PredicateInfoBuilder::convertUsesToDFSOrdered(
328 for (
auto &U :
Op->uses()) {
329 if (
auto *
I = dyn_cast<Instruction>(
U.getUser())) {
333 if (
auto *PN = dyn_cast<PHINode>(
I)) {
334 IBlock = PN->getIncomingBlock(U);
341 IBlock =
I->getParent();
360 return (isa<Instruction>(V) || isa<Argument>(V)) && !V->hasOneUse();
366 auto *Op0 = Comparison->getOperand(0);
367 auto *Op1 = Comparison->getOperand(1);
381 PI.AllInfos.push_back(
PB);
387void PredicateInfoBuilder::processAssume(
393 while (!Worklist.
empty()) {
408 if (
auto *Cmp = dyn_cast<CmpInst>(
Cond))
411 for (
Value *V : Values) {
414 addInfoFor(OpsToRename, V, PA);
422void PredicateInfoBuilder::processBranch(
428 for (
BasicBlock *Succ : {FirstBB, SecondBB}) {
429 bool TakenEdge = Succ == FirstBB;
432 if (Succ == BranchBB)
438 while (!Worklist.
empty()) {
454 if (
auto *Cmp = dyn_cast<CmpInst>(
Cond))
457 for (
Value *V : Values) {
461 addInfoFor(OpsToRename, V,
PB);
462 if (!Succ->getSinglePredecessor())
463 EdgeUsesOnly.insert({BranchBB, Succ});
471void PredicateInfoBuilder::processSwitch(
475 if ((!isa<Instruction>(
Op) && !isa<Argument>(
Op)) ||
Op->hasOneUse())
481 ++SwitchEdges[TargetBlock];
484 for (
auto C :
SI->cases()) {
486 if (SwitchEdges.
lookup(TargetBlock) == 1) {
488 Op,
SI->getParent(), TargetBlock,
C.getCaseValue(), SI);
489 addInfoFor(OpsToRename,
Op, PS);
491 EdgeUsesOnly.insert({BranchBB, TargetBlock});
504 if (
auto *BI = dyn_cast<BranchInst>(BranchBB->
getTerminator())) {
510 processBranch(BI, BranchBB, OpsToRename);
511 }
else if (
auto *SI = dyn_cast<SwitchInst>(BranchBB->
getTerminator())) {
512 processSwitch(SI, BranchBB, OpsToRename);
516 if (
auto *
II = dyn_cast_or_null<IntrinsicInst>(Assume))
518 processAssume(
II,
II->getParent(), OpsToRename);
521 renameUses(OpsToRename);
526Value *PredicateInfoBuilder::materializeStack(
unsigned int &Counter,
527 ValueDFSStack &RenameStack,
530 auto RevIter = RenameStack.rbegin();
531 for (; RevIter != RenameStack.rend(); ++RevIter)
535 size_t Start = RevIter - RenameStack.rbegin();
539 for (
auto RenameIter = RenameStack.end() - Start;
540 RenameIter != RenameStack.end(); ++RenameIter) {
542 RenameIter == RenameStack.begin() ? OrigOp : (RenameIter - 1)->Def;
544 auto *ValInfo = Result.PInfo;
545 ValInfo->RenamedOp = (RenameStack.end() - Start) == RenameStack.begin()
547 : (RenameStack.end() - Start - 1)->Def;
558 if (isa<PredicateWithEdge>(ValInfo)) {
562 F.
getParent(), Intrinsic::ssa_copy,
Op->getType());
564 PI.CreatedDeclarations.insert(IF);
566 B.CreateCall(IF,
Op,
Op->getName() +
"." +
Twine(Counter++));
567 PI.PredicateMap.insert({
PIC, ValInfo});
570 auto *PAssume = dyn_cast<PredicateAssume>(ValInfo);
572 "Should not have gotten here without it being an assume");
578 F.
getParent(), Intrinsic::ssa_copy,
Op->getType());
580 PI.CreatedDeclarations.insert(IF);
582 PI.PredicateMap.insert({
PIC, ValInfo});
586 return RenameStack.back().Def;
611 for (
auto *
Op : OpsToRename) {
613 unsigned Counter = 0;
619 for (
const auto &PossibleCopy :
ValueInfo.Infos) {
626 if (
const auto *PAssume = dyn_cast<PredicateAssume>(PossibleCopy)) {
633 VD.
PInfo = PossibleCopy;
635 }
else if (isa<PredicateWithEdge>(PossibleCopy)) {
639 auto BlockEdge = getBlockEdge(PossibleCopy);
640 if (EdgeUsesOnly.count(BlockEdge)) {
642 auto *DomNode = DT.
getNode(BlockEdge.first);
646 VD.
PInfo = PossibleCopy;
655 auto *DomNode = DT.
getNode(BlockEdge.second);
659 VD.
PInfo = PossibleCopy;
666 convertUsesToDFSOrdered(
Op, OrderedUses);
676 for (
auto &VD : OrderedUses) {
679 bool PossibleCopy = VD.
PInfo !=
nullptr;
680 if (RenameStack.
empty()) {
684 << RenameStack.
back().DFSIn <<
","
685 << RenameStack.
back().DFSOut <<
")\n");
691 bool ShouldPush = (VD.
Def || PossibleCopy);
692 bool OutOfScope = !stackIsInScope(RenameStack, VD);
693 if (OutOfScope || ShouldPush) {
695 popStackUntilDFSScope(RenameStack, VD);
702 if (RenameStack.
empty())
705 if (VD.
Def || PossibleCopy)
708 LLVM_DEBUG(
dbgs() <<
"Skipping execution due to debug counter\n");
717 Result.Def = materializeStack(Counter, RenameStack,
Op);
720 << *VD.
U->get() <<
" in " << *(VD.
U->getUser())
723 "Predicateinfo def should have dominated this use");
729PredicateInfoBuilder::ValueInfo &
730PredicateInfoBuilder::getOrCreateValueInfo(
Value *Operand) {
731 auto OIN = ValueInfoNums.find(Operand);
732 if (OIN == ValueInfoNums.end()) {
736 auto InsertResult = ValueInfoNums.insert({Operand, ValueInfos.
size() - 1});
737 assert(InsertResult.second &&
"Value info number already existed?");
738 return ValueInfos[InsertResult.first->second];
740 return ValueInfos[OIN->second];
743const PredicateInfoBuilder::ValueInfo &
744PredicateInfoBuilder::getValueInfo(
Value *Operand)
const {
745 auto OINI = ValueInfoNums.lookup(Operand);
746 assert(OINI != 0 &&
"Operand was not really in the Value Info Numbers");
748 "Value Info Number greater than size of Value Info Table");
749 return ValueInfos[OINI];
765 for (
const auto &F : CreatedDeclarations)
767 CreatedDeclarations.clear();
771 "PredicateInfo consumer did not remove all SSA copies.");
780 bool TrueEdge =
true;
781 if (
auto *PBranch = dyn_cast<PredicateBranch>(
this))
782 TrueEdge = PBranch->TrueEdge;
799 Pred = Cmp->getPredicate();
800 OtherOp = Cmp->getOperand(1);
801 }
else if (Cmp->getOperand(1) ==
RenamedOp) {
802 Pred = Cmp->getSwappedPredicate();
803 OtherOp = Cmp->getOperand(0);
813 return {{Pred, OtherOp}};
832 auto *
II = dyn_cast<IntrinsicInst>(&Inst);
833 if (!PI || !
II ||
II->getIntrinsicID() != Intrinsic::ssa_copy)
836 Inst.replaceAllUsesWith(
II->getOperand(0));
837 Inst.eraseFromParent();
845 OS <<
"PredicateInfo for function: " <<
F.getName() <<
"\n";
846 auto PredInfo = std::make_unique<PredicateInfo>(
F, DT, AC);
868 OS <<
"; Has predicate info\n";
869 if (
const auto *
PB = dyn_cast<PredicateBranch>(PI)) {
870 OS <<
"; branch predicate info { TrueEdge: " <<
PB->TrueEdge
871 <<
" Comparison:" << *
PB->Condition <<
" Edge: [";
872 PB->From->printAsOperand(
OS);
874 PB->To->printAsOperand(
OS);
876 }
else if (
const auto *PS = dyn_cast<PredicateSwitch>(PI)) {
877 OS <<
"; switch predicate info { CaseValue: " << *PS->CaseValue
878 <<
" Switch:" << *PS->Switch <<
" Edge: [";
879 PS->From->printAsOperand(
OS);
881 PS->To->printAsOperand(
OS);
883 }
else if (
const auto *PA = dyn_cast<PredicateAssume>(PI)) {
884 OS <<
"; assume predicate info {"
885 <<
" Comparison:" << *PA->Condition;
887 OS <<
", RenamedOp: ";
888 PI->RenamedOp->printAsOperand(
OS,
false);
896 F.print(
OS, &Writer);
901 F.print(
dbgs(), &Writer);
908 std::make_unique<PredicateInfo>(
F, DT, AC)->verifyPredicateInfo();
Expand Atomic instructions
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
This file provides an implementation of debug counters.
#define DEBUG_COUNTER(VARNAME, COUNTERNAME, DESC)
This file defines the DenseMap class.
This file builds on the ADT/GraphTraits.h file to build generic depth first graph iterator.
Module.h This file contains the declarations for the Module class.
uint64_t IntrinsicInst * II
PassInstrumentationCallbacks PIC
PassBuilder PB(Machine, PassOpts->PTO, std::nullopt, &PIC)
static cl::opt< bool > VerifyPredicateInfo("verify-predicateinfo", cl::init(false), cl::Hidden, cl::desc("Verify PredicateInfo in legacy printer pass."))
static const unsigned MaxCondsPerBranch
This file implements the PredicateInfo analysis, which creates an Extended SSA form for operations us...
const SmallVectorImpl< MachineOperand > & Cond
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file defines the SmallPtrSet class.
A container for analyses that lazily runs them and caches their results.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
A function analysis which provides an AssumptionCache.
A cache of @llvm.assume calls within a function.
MutableArrayRef< ResultElem > assumptions()
Access the list of assumption handles currently tracked for this function.
LLVM Basic Block Representation.
const BasicBlock * getSinglePredecessor() const
Return the predecessor of this block if it has a single predecessor block.
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
Conditional or Unconditional Branch instruction.
bool isConditional() const
BasicBlock * getSuccessor(unsigned i) const
Value * getCondition() const
This class represents a function call, abstracting a target machine's calling convention.
This class is the base class for the comparison instructions.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
Predicate getInversePredicate() const
For example, EQ -> NE, UGT -> ULE, SLT -> SGE, OEQ -> UNE, UGT -> OLE, OLT -> UGE,...
static ConstantInt * getTrue(LLVMContext &Context)
static ConstantInt * getFalse(LLVMContext &Context)
This class represents an Operation in the Expression.
static bool shouldExecute(unsigned CounterName)
ValueT lookup(const_arg_type_t< KeyT > Val) const
lookup - Return the entry for the specified key, or a default constructed value if no such entry exis...
Implements a dense probed hash-table based set.
unsigned getDFSNumIn() const
getDFSNumIn/getDFSNumOut - These return the DFS visitation order for nodes in the dominator tree.
unsigned getDFSNumOut() const
Analysis pass which computes a DominatorTree.
DomTreeNodeBase< NodeT > * getRootNode()
getRootNode - This returns the entry node for the CFG of the function.
void updateDFSNumbers() const
updateDFSNumbers - Assign In and Out numbers to the nodes while walking dominator tree in dfs order.
DomTreeNodeBase< NodeT > * getNode(const NodeT *BB) const
getNode - return the (Post)DominatorTree node for the specified basic block.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
bool isReachableFromEntry(const Use &U) const
Provide an overload for a Use.
bool dominates(const BasicBlock *BB, const Use &U) const
Return true if the (end of the) basic block BB dominates the use U.
void eraseFromParent()
eraseFromParent - This method unlinks 'this' from the containing module and deletes it.
Module * getParent()
Get the module that this global value is contained inside of...
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
A wrapper class for inspecting calls to intrinsic functions.
unsigned getNumNamedValues() const
Return the number of global values in the module.
std::optional< PredicateConstraint > getConstraint() const
Fetch condition in the form of PredicateConstraint, if possible.
An assembly annotator class to print PredicateInfo information in comments.
PredicateInfoAnnotatedWriter(const PredicateInfo *M)
void emitInstructionAnnot(const Instruction *I, formatted_raw_ostream &OS) override
emitInstructionAnnot - This may be implemented to emit a string right before an instruction is emitte...
void emitBasicBlockStartAnnot(const BasicBlock *BB, formatted_raw_ostream &OS) override
emitBasicBlockStartAnnot - This may be implemented to emit a string right after the basic block label...
void buildPredicateInfo()
PredicateInfoBuilder(PredicateInfo &PI, Function &F, DominatorTree &DT, AssumptionCache &AC)
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
Encapsulates PredicateInfo, including all data associated with memory accesses.
void verifyPredicateInfo() const
PredicateInfo(Function &, DominatorTree &, AssumptionCache &)
void print(raw_ostream &) const
const PredicateBase * getPredicateInfoFor(const Value *V) const
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
The instances of the Type class are immutable: once they are created, they are never changed.
A Use represents the edge between a Value definition and its users.
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
user_iterator user_begin()
This class implements an extremely fast bulk output stream that can only output to a stream.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ C
The default llvm calling convention, compatible with C.
Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > Tys={})
Look up the Function declaration of the intrinsic id in the Module M.
bool match(Val *V, const Pattern &P)
auto m_LogicalOr()
Matches L || R where L and R are arbitrary values.
class_match< Value > m_Value()
Match an arbitrary value and ignore it.
auto m_LogicalAnd()
Matches L && R where L and R are arbitrary values.
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
static bool valueComesBefore(const Value *A, const Value *B)
void stable_sort(R &&Range)
void collectCmpOps(CmpInst *Comparison, SmallVectorImpl< Value * > &CmpOperands)
auto successors(const MachineBasicBlock *BB)
static void replaceCreatedSSACopys(PredicateInfo &PredInfo, Function &F)
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
bool shouldRename(Value *V)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
iterator_range< df_iterator< T > > depth_first(const T &G)
Represents the EMUL and EEW of a MachineOperand.
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
std::pair< BasicBlock *, BasicBlock * > getBlockEdge(const ValueDFS &VD) const
bool operator()(const ValueDFS &A, const ValueDFS &B) const
bool comparePHIRelated(const ValueDFS &A, const ValueDFS &B) const
ValueDFS_Compare(DominatorTree &DT)
const Instruction * getDefOrUser(const Value *Def, const Use *U) const
bool localComesBefore(const ValueDFS &A, const ValueDFS &B) const
Value * getMiddleDef(const ValueDFS &VD) const
Struct that holds a reference to a particular GUID in a global value summary.