52 #define DEBUG_TYPE "safepoint-ir-verifier" 78 auto &PU = PredIt.
getUse();
85 assert(!isDeadBlock(InBB) &&
"block must be live");
89 if (InBB == *PredIt) {
90 if (!isDeadEdge(&getEdge(PredIt)))
96 assert(Listed &&
"basic block is not found among incoming blocks");
101 bool isDeadBlock(
const BasicBlock *BB)
const {
102 return DeadBlocks.
count(BB);
105 bool isDeadEdge(
const Use *U)
const {
106 assert(dyn_cast<Instruction>(U->getUser())->isTerminator() &&
107 "edge must be operand of terminator");
108 assert(cast_or_null<BasicBlock>(U->get()) &&
109 "edge must refer to basic block");
110 assert(!isDeadBlock(dyn_cast<Instruction>(U->getUser())->
getParent()) &&
111 "isDeadEdge() must be applied to edge from live block");
112 return DeadEdges.
count(U);
115 bool hasLiveIncomingEdges(
const BasicBlock *BB)
const {
118 auto &PU = PredIt.
getUse();
120 if (!isDeadBlock(*PredIt) && !isDeadEdge(&U))
138 assert(TI &&
"blocks must be well formed");
164 while (!NewDead.
empty()) {
180 if (!isDeadBlock(S) && !hasLiveIncomingEdges(S))
185 void addDeadEdge(
const Use &DeadEdge) {
186 if (!DeadEdges.
insert(&DeadEdge))
190 if (hasLiveIncomingEdges(BB))
199 const CFGDeadness &CD);
210 auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
212 CD.processFunction(F, DT);
222 StringRef getPassName()
const override {
return "safepoint verifier"; }
227 SafepointIRVerifier
pass;
228 pass.runOnFunction(F);
234 return new SafepointIRVerifier();
238 "Safepoint IR Verifier",
false,
false)
244 if (
auto *PT = dyn_cast<PointerType>(T))
248 return (1 == PT->getAddressSpace());
255 if (
VectorType *VT = dyn_cast<VectorType>(Ty))
257 if (
ArrayType *AT = dyn_cast<ArrayType>(Ty))
265 template<
typename IteratorTy>
268 while (Begin != End) {
269 OS << **Begin <<
" ";
296 bool Cleared =
false;
320 bool isExclusivelyDerivedFromNull =
true;
325 while(!Worklist.
empty()) {
327 if (!Visited.
insert(V).second)
330 if (
const auto *CI = dyn_cast<CastInst>(V)) {
331 Worklist.
push_back(CI->stripPointerCasts());
334 if (
const auto *
GEP = dyn_cast<GetElementPtrInst>(V)) {
340 if (
const auto *PN = dyn_cast<PHINode>(V)) {
345 if (
const auto *
SI = dyn_cast<SelectInst>(V)) {
351 if (isa<Constant>(V)) {
355 isExclusivelyDerivedFromNull =
false;
375 class InstructionVerifier;
435 const CFGDeadness &CD;
447 const CFGDeadness &CD);
450 return CD.hasLiveIncomingEdge(PN, InBB);
456 bool isValuePoisoned(
const Value *V)
const {
return PoisonedDefs.
count(V); }
469 return BlockMap.
find(BB) != BlockMap.
end();
474 bool instructionMayBeSkipped(
const Instruction *
I)
const;
478 void recalculateBBsStates();
486 bool removeValidUnrelocatedDefs(
const BasicBlock *BB,
502 bool ContributionChanged);
505 static void transferInstruction(
const Instruction &I,
bool &Cleared,
512 class InstructionVerifier {
513 bool AnyInvalidUses =
false;
516 void verifyInstruction(
const GCPtrTracker *Tracker,
const Instruction &
I,
519 bool hasAnyInvalidUses()
const {
return AnyInvalidUses; }
527 const CFGDeadness &CD) :
F(F), CD(CD) {
531 if (!CD.isDeadBlock(&BB)) {
533 for (
const auto &
I : BB)
540 for (
auto &BBI : BlockMap) {
541 gatherDominatingDefs(BBI.first, BBI.second->AvailableIn, DT);
542 transferBlock(BBI.first, *BBI.second,
true);
548 recalculateBBsStates();
552 auto it = BlockMap.find(BB);
553 return it != BlockMap.end() ? it->second :
nullptr;
558 return const_cast<GCPtrTracker *
>(
this)->getBasicBlockState(BB);
561 bool GCPtrTracker::instructionMayBeSkipped(
const Instruction *
I)
const {
564 return ValidUnrelocatedDefs.count(I) || PoisonedDefs.count(I);
581 if (Tracker.instructionMayBeSkipped(&I))
584 Verifier.verifyInstruction(&Tracker, I, AvailableSet);
588 bool Cleared =
false;
589 transferInstruction(I, Cleared, AvailableSet);
595 void GCPtrTracker::recalculateBBsStates() {
599 for (
auto &BBI : BlockMap)
600 Worklist.
insert(BBI.first);
604 while (!Worklist.
empty()) {
614 if (PBBS && !CD.isDeadEdge(&CFGDeadness::getEdge(PredIt)))
621 bool ContributionChanged =
623 if (!InputsChanged && !ContributionChanged)
627 transferBlock(BB, *BBS, ContributionChanged);
635 bool GCPtrTracker::removeValidUnrelocatedDefs(
const BasicBlock *BB,
639 "Passed Contribution should be from the passed BasicBlockState!");
641 bool ContributionChanged =
false;
645 bool ValidUnrelocatedPointerDef =
false;
646 bool PoisonedPointerDef =
false;
648 if (
const PHINode *PN = dyn_cast<PHINode>(&I)) {
651 bool HasRelocatedInputs =
false;
652 bool HasUnrelocatedInputs =
false;
655 if (!isMapped(InBB) ||
656 !CD.hasLiveIncomingEdge(PN, InBB))
662 if (isValuePoisoned(InValue)) {
664 HasRelocatedInputs =
true;
665 HasUnrelocatedInputs =
true;
668 if (BlockMap[InBB]->AvailableOut.count(InValue))
669 HasRelocatedInputs =
true;
671 HasUnrelocatedInputs =
true;
674 if (HasUnrelocatedInputs) {
675 if (HasRelocatedInputs)
676 PoisonedPointerDef =
true;
678 ValidUnrelocatedPointerDef =
true;
681 }
else if ((isa<GetElementPtrInst>(I) || isa<BitCastInst>(I)) &&
688 if (isValuePoisoned(V))
689 PoisonedPointerDef =
true;
691 ValidUnrelocatedPointerDef =
true;
695 assert(!(ValidUnrelocatedPointerDef && PoisonedPointerDef) &&
696 "Value cannot be both unrelocated and poisoned!");
697 if (ValidUnrelocatedPointerDef) {
700 Contribution.
erase(&I);
701 PoisonedDefs.erase(&I);
702 ValidUnrelocatedDefs.insert(&I);
704 <<
" from Contribution of " << BB->
getName() <<
"\n");
705 ContributionChanged =
true;
706 }
else if (PoisonedPointerDef) {
709 Contribution.
erase(&I);
710 PoisonedDefs.insert(&I);
711 LLVM_DEBUG(
dbgs() <<
"Removing poisoned " << I <<
" from Contribution of " 713 ContributionChanged =
true;
715 bool Cleared =
false;
716 transferInstruction(I, Cleared, AvailableSet);
720 return ContributionChanged;
723 void GCPtrTracker::gatherDominatingDefs(
const BasicBlock *BB,
728 assert(DTN &&
"Unreachable blocks are ignored");
731 auto BBS = getBasicBlockState(DTN->
getBlock());
732 assert(BBS &&
"immediate dominator cannot be dead for a live block");
734 Result.
insert(Defs.begin(), Defs.end());
749 bool ContributionChanged) {
755 if (ContributionChanged)
762 AvailableOut = std::move(Temp);
772 void GCPtrTracker::transferInstruction(
const Instruction &I,
bool &Cleared,
781 void InstructionVerifier::verifyInstruction(
784 if (
const PHINode *PN = dyn_cast<PHINode>(&I)) {
790 !Tracker->hasLiveIncomingEdge(PN, InBB))
797 reportInvalidUse(*InValue, *PN);
799 }
else if (isa<CmpInst>(I) &&
807 auto hasValidUnrelocatedUse = [&AvailableSet, Tracker, baseTyLHS, baseTyRHS,
816 if (AvailableSet.
count(LHS) || AvailableSet.
count(RHS))
847 if (!hasValidUnrelocatedUse()) {
851 reportInvalidUse(*LHS, I);
853 reportInvalidUse(*RHS, I);
859 reportInvalidUse(*V, I);
863 void InstructionVerifier::reportInvalidUse(
const Value &V,
865 errs() <<
"Illegal use of unrelocated value found!\n";
866 errs() <<
"Def: " << V <<
"\n";
867 errs() <<
"Use: " << I <<
"\n";
870 AnyInvalidUses =
true;
874 const CFGDeadness &CD) {
878 dbgs() <<
"Verifying gc pointers in function: " << F.
getName() <<
"\n";
880 GCPtrTracker Tracker(F, DT, CD);
888 if (
PrintOnly && !Verifier.hasAnyInvalidUses()) {
889 dbgs() <<
"No illegal uses found by SafepointIRVerifier in: " << F.
getName()
static void PrintValueSet(raw_ostream &OS, IteratorTy Begin, IteratorTy End)
Safe Stack instrumentation pass
raw_ostream & errs()
This returns a reference to a raw_ostream for standard error.
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
This class represents an incoming formal argument to a Function.
LLVM_NODISCARD T pop_back_val()
This class represents lattice values for constants.
void initializeSafepointIRVerifierPass(PassRegistry &)
Implements a dense probed hash-table based set.
void push_back(const T &Elt)
static enum BaseType getBaseType(const Value *Val)
Return the baseType for Val which states whether Val is exclusively derived from constant/null, or not exclusively derived from constant.
bool erase(const ValueT &V)
const Use & getOperandUse(unsigned i) const
BasicBlock * getSuccessor(unsigned i) const
static bool isNotExclusivelyConstantDerived(const Value *V)
Value * getCondition() const
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...
bool isReachableFromEntry(const Use &U) const
Provide an overload for a Use.
static Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
#define INITIALIZE_PASS_DEPENDENCY(depName)
AvailableValueSet AvailableIn
Class to represent struct types.
A Use represents the edge between a Value definition and its users.
Interval::succ_iterator succ_begin(Interval *I)
succ_begin/succ_end - define methods so that Intervals may be used just like BasicBlocks can with the...
User * getUser() const LLVM_READONLY
Returns the User that contains this Use.
Type * getType() const
All values are typed, get the type of this value.
bool insert(const value_type &X)
Insert a new element into the SetVector.
Class to represent array types.
verify safepoint Safepoint IR static false bool isGCPointerType(Type *T)
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree...
Value * getOperand(unsigned i) const
size_type count(const key_type &key) const
Count the number of elements of a given key in the SetVector.
Interval::succ_iterator succ_end(Interval *I)
Use & getUse() const
getUse - Return the operand Use in the predecessor's terminator of the successor. ...
iterator find(const_arg_type_t< KeyT > Val)
AvailableValueSet Contribution
State we compute and track per basic block.
static bool runOnFunction(Function &F, bool PostInlining)
initializer< Ty > init(const Ty &Val)
void verifySafepointIR(Function &F)
Run the safepoint verifier over a single function. Crashes on failure.
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
FunctionPass * createSafepointIRVerifierPass()
Create an instance of the safepoint verifier pass which can be added to a pass pipeline to check for ...
void set_intersect(S1Ty &S1, const S2Ty &S2)
set_intersect(A, B) - Compute A := A ^ B Identical to set_intersection, except that it works on set<>...
LLVM Basic Block Representation.
The instances of the Type class are immutable: once they are created, they are never changed...
Conditional or Unconditional Branch instruction.
void getDescendants(NodeT *R, SmallVectorImpl< NodeT *> &Result) const
Get all nodes dominated by R, including R itself.
DomTreeNodeBase * getIDom() const
LLVM_ATTRIBUTE_ALWAYS_INLINE iterator begin()
std::pair< iterator, bool > insert(const ValueT &V)
static bool containsGCPtrType(Type *Ty)
Represent the analysis usage information of a pass.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly...
FunctionPass class - This class is used to implement most global optimizations.
Value * getIncomingValue(unsigned i) const
Return incoming value number x.
INITIALIZE_PASS_END(RegBankSelect, DEBUG_TYPE, "Assign register bank of generic virtual registers", false, false) RegBankSelect
bool verify(const TargetRegisterInfo &TRI) const
Check that information hold by this instance make sense for the given TRI.
BaseType
A given derived pointer can have multiple base pointers through phi/selects.
A SetVector that performs no allocations if smaller than a certain size.
This is the shared class of boolean and integer constants.
AnalysisUsage & addRequiredID(const void *ID)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
Module.h This file contains the declarations for the Module class.
LLVM_NODISCARD T pop_back_val()
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
bool isConditional() const
unsigned getNumIncomingValues() const
Return the number of incoming edges.
A BumpPtrAllocator that allows only elements of a specific type to be allocated.
AvailableValueSet AvailableOut
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Class to represent vector types.
void setPreservesAll()
Set by analyses that do not transform their input at all.
INITIALIZE_PASS_BEGIN(SafepointIRVerifier, "verify-safepoint-ir", "Safepoint IR Verifier", false, false) INITIALIZE_PASS_END(SafepointIRVerifier
LLVM_ATTRIBUTE_ALWAYS_INLINE iterator end()
static cl::opt< bool > PrintOnly("safepoint-ir-verifier-print-only", cl::init(false))
This option is used for writing test cases.
LLVM_NODISCARD bool empty() const
verify safepoint Safepoint IR Verifier
StringRef getName() const
Return a constant reference to the value's name.
BasicBlock * getIncomingBlock(unsigned i) const
Return incoming basic block number i.
const Function * getParent() const
Return the enclosing method, or null if none.
bool empty() const
Determine if the SetVector is empty or not.
bool verifyFunction(const Function &F, raw_ostream *OS=nullptr)
Check a function for errors, useful for use when debugging a pass.
LLVM_NODISCARD std::enable_if<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type dyn_cast(const Y &Val)
size_type count(const_arg_type_t< ValueT > V) const
Return 1 if the specified key is in the set, 0 otherwise.
bool isStatepoint(ImmutableCallSite CS)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
LLVM Value Representation.
A vector that has set insertion semantics.
succ_range successors(Instruction *I)
static const Function * getParent(const Value *V)
This class implements an extremely fast bulk output stream that can only output to a stream...
StringRef - Represent a constant reference to a string, i.e.
Legacy analysis pass which computes a DominatorTree.
op_range incoming_values()
bool set_union(S1Ty &S1, const S2Ty &S2)
set_union(A, B) - Compute A := A u B, return whether A changed.
Statically lint checks LLVM IR
iterator_range< arg_iterator > args()
const BasicBlock * getParent() const
static void Verify(const Function &F, const DominatorTree &DT, const CFGDeadness &CD)