1 //===-- SafepointIRVerifier.cpp - Verify gc.statepoint invariants ---------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // Run a sanity check on the IR to ensure that Safepoints - if they've been 11 // inserted - were inserted correctly. In particular, look for use of 12 // non-relocated values after a safepoint. It's primary use is to check the 13 // correctness of safepoint insertion immediately after insertion, but it can 14 // also be used to verify that later transforms have not found a way to break 15 // safepoint semenatics. 16 // 17 // In its current form, this verify checks a property which is sufficient, but 18 // not neccessary for correctness. There are some cases where an unrelocated 19 // pointer can be used after the safepoint. Consider this example: 20 // 21 // a = ... 22 // b = ... 23 // (a',b') = safepoint(a,b) 24 // c = cmp eq a b 25 // br c, ..., .... 26 // 27 // Because it is valid to reorder 'c' above the safepoint, this is legal. In 28 // practice, this is a somewhat uncommon transform, but CodeGenPrep does create 29 // idioms like this. The verifier knows about these cases and avoids reporting 30 // false positives. 31 // 32 //===----------------------------------------------------------------------===// 33 34 #include "llvm/ADT/DenseSet.h" 35 #include "llvm/ADT/SetOperations.h" 36 #include "llvm/ADT/SetVector.h" 37 #include "llvm/IR/BasicBlock.h" 38 #include "llvm/IR/Dominators.h" 39 #include "llvm/IR/Function.h" 40 #include "llvm/IR/Instructions.h" 41 #include "llvm/IR/Intrinsics.h" 42 #include "llvm/IR/IntrinsicInst.h" 43 #include "llvm/IR/Module.h" 44 #include "llvm/IR/Value.h" 45 #include "llvm/IR/SafepointIRVerifier.h" 46 #include "llvm/IR/Statepoint.h" 47 #include "llvm/Support/Debug.h" 48 #include "llvm/Support/CommandLine.h" 49 #include "llvm/Support/raw_ostream.h" 50 51 #define DEBUG_TYPE "safepoint-ir-verifier" 52 53 using namespace llvm; 54 55 /// This option is used for writing test cases. Instead of crashing the program 56 /// when verification fails, report a message to the console (for FileCheck 57 /// usage) and continue execution as if nothing happened. 58 static cl::opt<bool> PrintOnly("safepoint-ir-verifier-print-only", 59 cl::init(false)); 60 61 static void Verify(const Function &F, const DominatorTree &DT); 62 63 namespace { 64 struct SafepointIRVerifier : public FunctionPass { 65 static char ID; // Pass identification, replacement for typeid 66 DominatorTree DT; 67 SafepointIRVerifier() : FunctionPass(ID) { 68 initializeSafepointIRVerifierPass(*PassRegistry::getPassRegistry()); 69 } 70 71 bool runOnFunction(Function &F) override { 72 DT.recalculate(F); 73 Verify(F, DT); 74 return false; // no modifications 75 } 76 77 void getAnalysisUsage(AnalysisUsage &AU) const override { 78 AU.setPreservesAll(); 79 } 80 81 StringRef getPassName() const override { return "safepoint verifier"; } 82 }; 83 } // namespace 84 85 void llvm::verifySafepointIR(Function &F) { 86 SafepointIRVerifier pass; 87 pass.runOnFunction(F); 88 } 89 90 char SafepointIRVerifier::ID = 0; 91 92 FunctionPass *llvm::createSafepointIRVerifierPass() { 93 return new SafepointIRVerifier(); 94 } 95 96 INITIALIZE_PASS_BEGIN(SafepointIRVerifier, "verify-safepoint-ir", 97 "Safepoint IR Verifier", false, true) 98 INITIALIZE_PASS_END(SafepointIRVerifier, "verify-safepoint-ir", 99 "Safepoint IR Verifier", false, true) 100 101 static bool isGCPointerType(Type *T) { 102 if (auto *PT = dyn_cast<PointerType>(T)) 103 // For the sake of this example GC, we arbitrarily pick addrspace(1) as our 104 // GC managed heap. We know that a pointer into this heap needs to be 105 // updated and that no other pointer does. 106 return (1 == PT->getAddressSpace()); 107 return false; 108 } 109 110 static bool containsGCPtrType(Type *Ty) { 111 if (isGCPointerType(Ty)) 112 return true; 113 if (VectorType *VT = dyn_cast<VectorType>(Ty)) 114 return isGCPointerType(VT->getScalarType()); 115 if (ArrayType *AT = dyn_cast<ArrayType>(Ty)) 116 return containsGCPtrType(AT->getElementType()); 117 if (StructType *ST = dyn_cast<StructType>(Ty)) 118 return std::any_of(ST->subtypes().begin(), ST->subtypes().end(), 119 containsGCPtrType); 120 return false; 121 } 122 123 // Debugging aid -- prints a [Begin, End) range of values. 124 template<typename IteratorTy> 125 static void PrintValueSet(raw_ostream &OS, IteratorTy Begin, IteratorTy End) { 126 OS << "[ "; 127 while (Begin != End) { 128 OS << **Begin << " "; 129 ++Begin; 130 } 131 OS << "]"; 132 } 133 134 /// The verifier algorithm is phrased in terms of availability. The set of 135 /// values "available" at a given point in the control flow graph is the set of 136 /// correctly relocated value at that point, and is a subset of the set of 137 /// definitions dominating that point. 138 139 /// State we compute and track per basic block. 140 struct BasicBlockState { 141 // Set of values available coming in, before the phi nodes 142 DenseSet<const Value *> AvailableIn; 143 144 // Set of values available going out 145 DenseSet<const Value *> AvailableOut; 146 147 // AvailableOut minus AvailableIn. 148 // All elements are Instructions 149 DenseSet<const Value *> Contribution; 150 151 // True if this block contains a safepoint and thus AvailableIn does not 152 // contribute to AvailableOut. 153 bool Cleared = false; 154 }; 155 156 157 /// Gather all the definitions dominating the start of BB into Result. This is 158 /// simply the Defs introduced by every dominating basic block and the function 159 /// arguments. 160 static void GatherDominatingDefs(const BasicBlock *BB, 161 DenseSet<const Value *> &Result, 162 const DominatorTree &DT, 163 DenseMap<const BasicBlock *, BasicBlockState *> &BlockMap) { 164 DomTreeNode *DTN = DT[const_cast<BasicBlock *>(BB)]; 165 166 while (DTN->getIDom()) { 167 DTN = DTN->getIDom(); 168 const auto &Defs = BlockMap[DTN->getBlock()]->Contribution; 169 Result.insert(Defs.begin(), Defs.end()); 170 // If this block is 'Cleared', then nothing LiveIn to this block can be 171 // available after this block completes. Note: This turns out to be 172 // really important for reducing memory consuption of the initial available 173 // sets and thus peak memory usage by this verifier. 174 if (BlockMap[DTN->getBlock()]->Cleared) 175 return; 176 } 177 178 for (const Argument &A : BB->getParent()->args()) 179 if (containsGCPtrType(A.getType())) 180 Result.insert(&A); 181 } 182 183 /// Model the effect of an instruction on the set of available values. 184 static void TransferInstruction(const Instruction &I, bool &Cleared, 185 DenseSet<const Value *> &Available) { 186 if (isStatepoint(I)) { 187 Cleared = true; 188 Available.clear(); 189 } else if (containsGCPtrType(I.getType())) 190 Available.insert(&I); 191 } 192 193 /// Compute the AvailableOut set for BB, based on the 194 /// BasicBlockState BBS, which is the BasicBlockState for BB. FirstPass is set 195 /// when the verifier runs for the first time computing the AvailableOut set 196 /// for BB. 197 static void TransferBlock(const BasicBlock *BB, 198 BasicBlockState &BBS, bool FirstPass) { 199 200 const DenseSet<const Value *> &AvailableIn = BBS.AvailableIn; 201 DenseSet<const Value *> &AvailableOut = BBS.AvailableOut; 202 203 if (BBS.Cleared) { 204 // AvailableOut does not change no matter how the input changes, just 205 // leave it be. We need to force this calculation the first time so that 206 // we have a AvailableOut at all. 207 if (FirstPass) { 208 AvailableOut = BBS.Contribution; 209 } 210 } else { 211 // Otherwise, we need to reduce the AvailableOut set by things which are no 212 // longer in our AvailableIn 213 DenseSet<const Value *> Temp = BBS.Contribution; 214 set_union(Temp, AvailableIn); 215 AvailableOut = std::move(Temp); 216 } 217 218 DEBUG(dbgs() << "Transfered block " << BB->getName() << " from "; 219 PrintValueSet(dbgs(), AvailableIn.begin(), AvailableIn.end()); 220 dbgs() << " to "; 221 PrintValueSet(dbgs(), AvailableOut.begin(), AvailableOut.end()); 222 dbgs() << "\n";); 223 } 224 225 /// A given derived pointer can have multiple base pointers through phi/selects. 226 /// This type indicates when the base pointer is exclusively constant 227 /// (ExclusivelySomeConstant), and if that constant is proven to be exclusively 228 /// null, we record that as ExclusivelyNull. In all other cases, the BaseType is 229 /// NonConstant. 230 enum BaseType { 231 NonConstant = 1, // Base pointers is not exclusively constant. 232 ExclusivelyNull, 233 ExclusivelySomeConstant // Base pointers for a given derived pointer is from a 234 // set of constants, but they are not exclusively 235 // null. 236 }; 237 238 /// Return the baseType for Val which states whether Val is exclusively 239 /// derived from constant/null, or not exclusively derived from constant. 240 /// Val is exclusively derived off a constant base when all operands of phi and 241 /// selects are derived off a constant base. 242 static enum BaseType getBaseType(const Value *Val) { 243 244 SmallVector<const Value *, 32> Worklist; 245 DenseSet<const Value *> Visited; 246 bool isExclusivelyDerivedFromNull = true; 247 Worklist.push_back(Val); 248 // Strip through all the bitcasts and geps to get base pointer. Also check for 249 // the exclusive value when there can be multiple base pointers (through phis 250 // or selects). 251 while(!Worklist.empty()) { 252 const Value *V = Worklist.pop_back_val(); 253 if (!Visited.insert(V).second) 254 continue; 255 256 if (const auto *CI = dyn_cast<CastInst>(V)) { 257 Worklist.push_back(CI->stripPointerCasts()); 258 continue; 259 } 260 if (const auto *GEP = dyn_cast<GetElementPtrInst>(V)) { 261 Worklist.push_back(GEP->getPointerOperand()); 262 continue; 263 } 264 // Push all the incoming values of phi node into the worklist for 265 // processing. 266 if (const auto *PN = dyn_cast<PHINode>(V)) { 267 for (Value *InV: PN->incoming_values()) 268 Worklist.push_back(InV); 269 continue; 270 } 271 if (const auto *SI = dyn_cast<SelectInst>(V)) { 272 // Push in the true and false values 273 Worklist.push_back(SI->getTrueValue()); 274 Worklist.push_back(SI->getFalseValue()); 275 continue; 276 } 277 if (isa<Constant>(V)) { 278 // We found at least one base pointer which is non-null, so this derived 279 // pointer is not exclusively derived from null. 280 if (V != Constant::getNullValue(V->getType())) 281 isExclusivelyDerivedFromNull = false; 282 // Continue processing the remaining values to make sure it's exclusively 283 // constant. 284 continue; 285 } 286 // At this point, we know that the base pointer is not exclusively 287 // constant. 288 return BaseType::NonConstant; 289 } 290 // Now, we know that the base pointer is exclusively constant, but we need to 291 // differentiate between exclusive null constant and non-null constant. 292 return isExclusivelyDerivedFromNull ? BaseType::ExclusivelyNull 293 : BaseType::ExclusivelySomeConstant; 294 } 295 296 static void Verify(const Function &F, const DominatorTree &DT) { 297 SpecificBumpPtrAllocator<BasicBlockState> BSAllocator; 298 DenseMap<const BasicBlock *, BasicBlockState *> BlockMap; 299 300 DEBUG(dbgs() << "Verifying gc pointers in function: " << F.getName() << "\n"); 301 if (PrintOnly) 302 dbgs() << "Verifying gc pointers in function: " << F.getName() << "\n"; 303 304 305 for (const BasicBlock &BB : F) { 306 BasicBlockState *BBS = new(BSAllocator.Allocate()) BasicBlockState; 307 for (const auto &I : BB) 308 TransferInstruction(I, BBS->Cleared, BBS->Contribution); 309 BlockMap[&BB] = BBS; 310 } 311 312 for (auto &BBI : BlockMap) { 313 GatherDominatingDefs(BBI.first, BBI.second->AvailableIn, DT, BlockMap); 314 TransferBlock(BBI.first, *BBI.second, true); 315 } 316 317 SetVector<const BasicBlock *> Worklist; 318 for (auto &BBI : BlockMap) 319 Worklist.insert(BBI.first); 320 321 // This loop iterates the AvailableIn and AvailableOut sets to a fixed point. 322 // The AvailableIn and AvailableOut sets decrease as we iterate. 323 while (!Worklist.empty()) { 324 const BasicBlock *BB = Worklist.pop_back_val(); 325 BasicBlockState *BBS = BlockMap[BB]; 326 327 size_t OldInCount = BBS->AvailableIn.size(); 328 for (const BasicBlock *PBB : predecessors(BB)) 329 set_intersect(BBS->AvailableIn, BlockMap[PBB]->AvailableOut); 330 331 if (OldInCount == BBS->AvailableIn.size()) 332 continue; 333 334 assert(OldInCount > BBS->AvailableIn.size() && "invariant!"); 335 336 size_t OldOutCount = BBS->AvailableOut.size(); 337 TransferBlock(BB, *BBS, false); 338 if (OldOutCount != BBS->AvailableOut.size()) { 339 assert(OldOutCount > BBS->AvailableOut.size() && "invariant!"); 340 Worklist.insert(succ_begin(BB), succ_end(BB)); 341 } 342 } 343 344 // We now have all the information we need to decide if the use of a heap 345 // reference is legal or not, given our safepoint semantics. 346 347 bool AnyInvalidUses = false; 348 349 auto ReportInvalidUse = [&AnyInvalidUses](const Value &V, 350 const Instruction &I) { 351 errs() << "Illegal use of unrelocated value found!\n"; 352 errs() << "Def: " << V << "\n"; 353 errs() << "Use: " << I << "\n"; 354 if (!PrintOnly) 355 abort(); 356 AnyInvalidUses = true; 357 }; 358 359 auto isNotExclusivelyConstantDerived = [](const Value *V) { 360 return getBaseType(V) == BaseType::NonConstant; 361 }; 362 363 for (const BasicBlock &BB : F) { 364 // We destructively modify AvailableIn as we traverse the block instruction 365 // by instruction. 366 DenseSet<const Value *> &AvailableSet = BlockMap[&BB]->AvailableIn; 367 for (const Instruction &I : BB) { 368 if (const PHINode *PN = dyn_cast<PHINode>(&I)) { 369 if (containsGCPtrType(PN->getType())) 370 for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { 371 const BasicBlock *InBB = PN->getIncomingBlock(i); 372 const Value *InValue = PN->getIncomingValue(i); 373 374 if (isNotExclusivelyConstantDerived(InValue) && 375 !BlockMap[InBB]->AvailableOut.count(InValue)) 376 ReportInvalidUse(*InValue, *PN); 377 } 378 } else if (isa<CmpInst>(I) && 379 containsGCPtrType(I.getOperand(0)->getType())) { 380 Value *LHS = I.getOperand(0), *RHS = I.getOperand(1); 381 enum BaseType baseTyLHS = getBaseType(LHS), 382 baseTyRHS = getBaseType(RHS); 383 384 // Returns true if LHS and RHS are unrelocated pointers and they are 385 // valid unrelocated uses. 386 auto hasValidUnrelocatedUse = [&AvailableSet, baseTyLHS, baseTyRHS, &LHS, &RHS] () { 387 // A cmp instruction has valid unrelocated pointer operands only if 388 // both operands are unrelocated pointers. 389 // In the comparison between two pointers, if one is an unrelocated 390 // use, the other *should be* an unrelocated use, for this 391 // instruction to contain valid unrelocated uses. This unrelocated 392 // use can be a null constant as well, or another unrelocated 393 // pointer. 394 if (AvailableSet.count(LHS) || AvailableSet.count(RHS)) 395 return false; 396 // Constant pointers (that are not exclusively null) may have 397 // meaning in different VMs, so we cannot reorder the compare 398 // against constant pointers before the safepoint. In other words, 399 // comparison of an unrelocated use against a non-null constant 400 // maybe invalid. 401 if ((baseTyLHS == BaseType::ExclusivelySomeConstant && 402 baseTyRHS == BaseType::NonConstant) || 403 (baseTyLHS == BaseType::NonConstant && 404 baseTyRHS == BaseType::ExclusivelySomeConstant)) 405 return false; 406 // All other cases are valid cases enumerated below: 407 // 1. Comparison between an exlusively derived null pointer and a 408 // constant base pointer. 409 // 2. Comparison between an exlusively derived null pointer and a 410 // non-constant unrelocated base pointer. 411 // 3. Comparison between 2 unrelocated pointers. 412 return true; 413 }; 414 if (!hasValidUnrelocatedUse()) { 415 // Print out all non-constant derived pointers that are unrelocated 416 // uses, which are invalid. 417 if (baseTyLHS == BaseType::NonConstant && !AvailableSet.count(LHS)) 418 ReportInvalidUse(*LHS, I); 419 if (baseTyRHS == BaseType::NonConstant && !AvailableSet.count(RHS)) 420 ReportInvalidUse(*RHS, I); 421 } 422 } else { 423 for (const Value *V : I.operands()) 424 if (containsGCPtrType(V->getType()) && 425 isNotExclusivelyConstantDerived(V) && !AvailableSet.count(V)) 426 ReportInvalidUse(*V, I); 427 } 428 429 bool Cleared = false; 430 TransferInstruction(I, Cleared, AvailableSet); 431 (void)Cleared; 432 } 433 } 434 435 if (PrintOnly && !AnyInvalidUses) { 436 dbgs() << "No illegal uses found by SafepointIRVerifier in: " << F.getName() 437 << "\n"; 438 } 439 } 440