| 1 | //===- AliasAnalysisEvaluator.cpp - Alias Analysis Accuracy Evaluator -----===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #include "llvm/Analysis/AliasAnalysisEvaluator.h" |
| 10 | #include "llvm/ADT/SetVector.h" |
| 11 | #include "llvm/Analysis/AliasAnalysis.h" |
| 12 | #include "llvm/IR/DataLayout.h" |
| 13 | #include "llvm/IR/Function.h" |
| 14 | #include "llvm/IR/InstIterator.h" |
| 15 | #include "llvm/IR/Instructions.h" |
| 16 | #include "llvm/IR/Module.h" |
| 17 | #include "llvm/Support/CommandLine.h" |
| 18 | #include "llvm/Support/raw_ostream.h" |
| 19 | using namespace llvm; |
| 20 | |
| 21 | static cl::opt<bool> PrintAll("print-all-alias-modref-info" , cl::ReallyHidden); |
| 22 | |
| 23 | static cl::opt<bool> PrintNoAlias("print-no-aliases" , cl::ReallyHidden); |
| 24 | static cl::opt<bool> PrintMayAlias("print-may-aliases" , cl::ReallyHidden); |
| 25 | static cl::opt<bool> PrintPartialAlias("print-partial-aliases" , cl::ReallyHidden); |
| 26 | static cl::opt<bool> PrintMustAlias("print-must-aliases" , cl::ReallyHidden); |
| 27 | |
| 28 | static cl::opt<bool> PrintNoModRef("print-no-modref" , cl::ReallyHidden); |
| 29 | static cl::opt<bool> PrintRef("print-ref" , cl::ReallyHidden); |
| 30 | static cl::opt<bool> PrintMod("print-mod" , cl::ReallyHidden); |
| 31 | static cl::opt<bool> PrintModRef("print-modref" , cl::ReallyHidden); |
| 32 | |
| 33 | static cl::opt<bool> EvalAAMD("evaluate-aa-metadata" , cl::ReallyHidden); |
| 34 | |
| 35 | static void PrintResults(AliasResult AR, bool P, |
| 36 | std::pair<const Value *, Type *> Loc1, |
| 37 | std::pair<const Value *, Type *> Loc2, |
| 38 | const Module *M) { |
| 39 | if (PrintAll || P) { |
| 40 | Type *Ty1 = Loc1.second, *Ty2 = Loc2.second; |
| 41 | unsigned AS1 = Loc1.first->getType()->getPointerAddressSpace(); |
| 42 | unsigned AS2 = Loc2.first->getType()->getPointerAddressSpace(); |
| 43 | std::string o1, o2; |
| 44 | { |
| 45 | raw_string_ostream os1(o1), os2(o2); |
| 46 | Loc1.first->printAsOperand(O&: os1, PrintType: false, M); |
| 47 | Loc2.first->printAsOperand(O&: os2, PrintType: false, M); |
| 48 | } |
| 49 | |
| 50 | if (o2 < o1) { |
| 51 | std::swap(lhs&: o1, rhs&: o2); |
| 52 | std::swap(a&: Ty1, b&: Ty2); |
| 53 | std::swap(a&: AS1, b&: AS2); |
| 54 | // Change offset sign for the local AR, for printing only. |
| 55 | AR.swap(); |
| 56 | } |
| 57 | errs() << " " << AR << ":\t" ; |
| 58 | Ty1->print(O&: errs(), IsForDebug: false, /* NoDetails */ true); |
| 59 | if (AS1 != 0) |
| 60 | errs() << " addrspace(" << AS1 << ")" ; |
| 61 | errs() << "* " << o1 << ", " ; |
| 62 | Ty2->print(O&: errs(), IsForDebug: false, /* NoDetails */ true); |
| 63 | if (AS2 != 0) |
| 64 | errs() << " addrspace(" << AS2 << ")" ; |
| 65 | errs() << "* " << o2 << "\n" ; |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | static inline void PrintModRefResults( |
| 70 | const char *Msg, bool P, Instruction *I, |
| 71 | std::pair<const Value *, Type *> Loc, Module *M) { |
| 72 | if (PrintAll || P) { |
| 73 | errs() << " " << Msg << ": Ptr: " ; |
| 74 | Loc.second->print(O&: errs(), IsForDebug: false, /* NoDetails */ true); |
| 75 | errs() << "* " ; |
| 76 | Loc.first->printAsOperand(O&: errs(), PrintType: false, M); |
| 77 | errs() << "\t<->" << *I << '\n'; |
| 78 | } |
| 79 | } |
| 80 | |
| 81 | static inline void PrintModRefResults(const char *Msg, bool P, CallBase *CallA, |
| 82 | CallBase *CallB, Module *M) { |
| 83 | if (PrintAll || P) { |
| 84 | errs() << " " << Msg << ": " << *CallA << " <-> " << *CallB << '\n'; |
| 85 | } |
| 86 | } |
| 87 | |
| 88 | static inline void PrintLoadStoreResults(AliasResult AR, bool P, |
| 89 | const Value *V1, const Value *V2, |
| 90 | const Module *M) { |
| 91 | if (PrintAll || P) { |
| 92 | errs() << " " << AR << ": " << *V1 << " <-> " << *V2 << '\n'; |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | PreservedAnalyses AAEvaluator::run(Function &F, FunctionAnalysisManager &AM) { |
| 97 | runInternal(F, AA&: AM.getResult<AAManager>(IR&: F)); |
| 98 | return PreservedAnalyses::all(); |
| 99 | } |
| 100 | |
| 101 | void AAEvaluator::runInternal(Function &F, AAResults &AA) { |
| 102 | const DataLayout &DL = F.getDataLayout(); |
| 103 | |
| 104 | ++FunctionCount; |
| 105 | |
| 106 | SetVector<std::pair<const Value *, Type *>> Pointers; |
| 107 | SmallSetVector<CallBase *, 16> Calls; |
| 108 | SetVector<Value *> Loads; |
| 109 | SetVector<Value *> Stores; |
| 110 | |
| 111 | for (Instruction &Inst : instructions(F)) { |
| 112 | if (auto *LI = dyn_cast<LoadInst>(Val: &Inst)) { |
| 113 | Pointers.insert(X: {LI->getPointerOperand(), LI->getType()}); |
| 114 | Loads.insert(X: LI); |
| 115 | } else if (auto *SI = dyn_cast<StoreInst>(Val: &Inst)) { |
| 116 | Pointers.insert(X: {SI->getPointerOperand(), |
| 117 | SI->getValueOperand()->getType()}); |
| 118 | Stores.insert(X: SI); |
| 119 | } else if (auto *CB = dyn_cast<CallBase>(Val: &Inst)) |
| 120 | Calls.insert(X: CB); |
| 121 | } |
| 122 | |
| 123 | if (PrintAll || PrintNoAlias || PrintMayAlias || PrintPartialAlias || |
| 124 | PrintMustAlias || PrintNoModRef || PrintMod || PrintRef || PrintModRef) |
| 125 | errs() << "Function: " << F.getName() << ": " << Pointers.size() |
| 126 | << " pointers, " << Calls.size() << " call sites\n" ; |
| 127 | |
| 128 | // iterate over the worklist, and run the full (n^2)/2 disambiguations |
| 129 | for (auto I1 = Pointers.begin(), E = Pointers.end(); I1 != E; ++I1) { |
| 130 | LocationSize Size1 = LocationSize::precise(Value: DL.getTypeStoreSize(Ty: I1->second)); |
| 131 | for (auto I2 = Pointers.begin(); I2 != I1; ++I2) { |
| 132 | LocationSize Size2 = |
| 133 | LocationSize::precise(Value: DL.getTypeStoreSize(Ty: I2->second)); |
| 134 | AliasResult AR = AA.alias(V1: I1->first, V1Size: Size1, V2: I2->first, V2Size: Size2); |
| 135 | switch (AR) { |
| 136 | case AliasResult::NoAlias: |
| 137 | PrintResults(AR, P: PrintNoAlias, Loc1: *I1, Loc2: *I2, M: F.getParent()); |
| 138 | ++NoAliasCount; |
| 139 | break; |
| 140 | case AliasResult::MayAlias: |
| 141 | PrintResults(AR, P: PrintMayAlias, Loc1: *I1, Loc2: *I2, M: F.getParent()); |
| 142 | ++MayAliasCount; |
| 143 | break; |
| 144 | case AliasResult::PartialAlias: |
| 145 | PrintResults(AR, P: PrintPartialAlias, Loc1: *I1, Loc2: *I2, M: F.getParent()); |
| 146 | ++PartialAliasCount; |
| 147 | break; |
| 148 | case AliasResult::MustAlias: |
| 149 | PrintResults(AR, P: PrintMustAlias, Loc1: *I1, Loc2: *I2, M: F.getParent()); |
| 150 | ++MustAliasCount; |
| 151 | break; |
| 152 | } |
| 153 | } |
| 154 | } |
| 155 | |
| 156 | if (EvalAAMD) { |
| 157 | // iterate over all pairs of load, store |
| 158 | for (Value *Load : Loads) { |
| 159 | for (Value *Store : Stores) { |
| 160 | AliasResult AR = AA.alias(LocA: MemoryLocation::get(LI: cast<LoadInst>(Val: Load)), |
| 161 | LocB: MemoryLocation::get(SI: cast<StoreInst>(Val: Store))); |
| 162 | switch (AR) { |
| 163 | case AliasResult::NoAlias: |
| 164 | PrintLoadStoreResults(AR, P: PrintNoAlias, V1: Load, V2: Store, M: F.getParent()); |
| 165 | ++NoAliasCount; |
| 166 | break; |
| 167 | case AliasResult::MayAlias: |
| 168 | PrintLoadStoreResults(AR, P: PrintMayAlias, V1: Load, V2: Store, M: F.getParent()); |
| 169 | ++MayAliasCount; |
| 170 | break; |
| 171 | case AliasResult::PartialAlias: |
| 172 | PrintLoadStoreResults(AR, P: PrintPartialAlias, V1: Load, V2: Store, M: F.getParent()); |
| 173 | ++PartialAliasCount; |
| 174 | break; |
| 175 | case AliasResult::MustAlias: |
| 176 | PrintLoadStoreResults(AR, P: PrintMustAlias, V1: Load, V2: Store, M: F.getParent()); |
| 177 | ++MustAliasCount; |
| 178 | break; |
| 179 | } |
| 180 | } |
| 181 | } |
| 182 | |
| 183 | // iterate over all pairs of store, store |
| 184 | for (SetVector<Value *>::iterator I1 = Stores.begin(), E = Stores.end(); |
| 185 | I1 != E; ++I1) { |
| 186 | for (SetVector<Value *>::iterator I2 = Stores.begin(); I2 != I1; ++I2) { |
| 187 | AliasResult AR = AA.alias(LocA: MemoryLocation::get(SI: cast<StoreInst>(Val: *I1)), |
| 188 | LocB: MemoryLocation::get(SI: cast<StoreInst>(Val: *I2))); |
| 189 | switch (AR) { |
| 190 | case AliasResult::NoAlias: |
| 191 | PrintLoadStoreResults(AR, P: PrintNoAlias, V1: *I1, V2: *I2, M: F.getParent()); |
| 192 | ++NoAliasCount; |
| 193 | break; |
| 194 | case AliasResult::MayAlias: |
| 195 | PrintLoadStoreResults(AR, P: PrintMayAlias, V1: *I1, V2: *I2, M: F.getParent()); |
| 196 | ++MayAliasCount; |
| 197 | break; |
| 198 | case AliasResult::PartialAlias: |
| 199 | PrintLoadStoreResults(AR, P: PrintPartialAlias, V1: *I1, V2: *I2, M: F.getParent()); |
| 200 | ++PartialAliasCount; |
| 201 | break; |
| 202 | case AliasResult::MustAlias: |
| 203 | PrintLoadStoreResults(AR, P: PrintMustAlias, V1: *I1, V2: *I2, M: F.getParent()); |
| 204 | ++MustAliasCount; |
| 205 | break; |
| 206 | } |
| 207 | } |
| 208 | } |
| 209 | } |
| 210 | |
| 211 | // Mod/ref alias analysis: compare all pairs of calls and values |
| 212 | for (CallBase *Call : Calls) { |
| 213 | for (const auto &Pointer : Pointers) { |
| 214 | LocationSize Size = |
| 215 | LocationSize::precise(Value: DL.getTypeStoreSize(Ty: Pointer.second)); |
| 216 | switch (AA.getModRefInfo(I: Call, P: Pointer.first, Size)) { |
| 217 | case ModRefInfo::NoModRef: |
| 218 | PrintModRefResults(Msg: "NoModRef" , P: PrintNoModRef, I: Call, Loc: Pointer, |
| 219 | M: F.getParent()); |
| 220 | ++NoModRefCount; |
| 221 | break; |
| 222 | case ModRefInfo::Mod: |
| 223 | PrintModRefResults(Msg: "Just Mod" , P: PrintMod, I: Call, Loc: Pointer, M: F.getParent()); |
| 224 | ++ModCount; |
| 225 | break; |
| 226 | case ModRefInfo::Ref: |
| 227 | PrintModRefResults(Msg: "Just Ref" , P: PrintRef, I: Call, Loc: Pointer, M: F.getParent()); |
| 228 | ++RefCount; |
| 229 | break; |
| 230 | case ModRefInfo::ModRef: |
| 231 | PrintModRefResults(Msg: "Both ModRef" , P: PrintModRef, I: Call, Loc: Pointer, |
| 232 | M: F.getParent()); |
| 233 | ++ModRefCount; |
| 234 | break; |
| 235 | } |
| 236 | } |
| 237 | } |
| 238 | |
| 239 | // Mod/ref alias analysis: compare all pairs of calls |
| 240 | for (CallBase *CallA : Calls) { |
| 241 | for (CallBase *CallB : Calls) { |
| 242 | if (CallA == CallB) |
| 243 | continue; |
| 244 | switch (AA.getModRefInfo(I: CallA, Call: CallB)) { |
| 245 | case ModRefInfo::NoModRef: |
| 246 | PrintModRefResults(Msg: "NoModRef" , P: PrintNoModRef, CallA, CallB, |
| 247 | M: F.getParent()); |
| 248 | ++NoModRefCount; |
| 249 | break; |
| 250 | case ModRefInfo::Mod: |
| 251 | PrintModRefResults(Msg: "Just Mod" , P: PrintMod, CallA, CallB, M: F.getParent()); |
| 252 | ++ModCount; |
| 253 | break; |
| 254 | case ModRefInfo::Ref: |
| 255 | PrintModRefResults(Msg: "Just Ref" , P: PrintRef, CallA, CallB, M: F.getParent()); |
| 256 | ++RefCount; |
| 257 | break; |
| 258 | case ModRefInfo::ModRef: |
| 259 | PrintModRefResults(Msg: "Both ModRef" , P: PrintModRef, CallA, CallB, |
| 260 | M: F.getParent()); |
| 261 | ++ModRefCount; |
| 262 | break; |
| 263 | } |
| 264 | } |
| 265 | } |
| 266 | } |
| 267 | |
| 268 | static void PrintPercent(int64_t Num, int64_t Sum) { |
| 269 | errs() << "(" << Num * 100LL / Sum << "." << ((Num * 1000LL / Sum) % 10) |
| 270 | << "%)\n" ; |
| 271 | } |
| 272 | |
| 273 | AAEvaluator::~AAEvaluator() { |
| 274 | if (FunctionCount == 0) |
| 275 | return; |
| 276 | |
| 277 | int64_t AliasSum = |
| 278 | NoAliasCount + MayAliasCount + PartialAliasCount + MustAliasCount; |
| 279 | errs() << "===== Alias Analysis Evaluator Report =====\n" ; |
| 280 | if (AliasSum == 0) { |
| 281 | errs() << " Alias Analysis Evaluator Summary: No pointers!\n" ; |
| 282 | } else { |
| 283 | errs() << " " << AliasSum << " Total Alias Queries Performed\n" ; |
| 284 | errs() << " " << NoAliasCount << " no alias responses " ; |
| 285 | PrintPercent(Num: NoAliasCount, Sum: AliasSum); |
| 286 | errs() << " " << MayAliasCount << " may alias responses " ; |
| 287 | PrintPercent(Num: MayAliasCount, Sum: AliasSum); |
| 288 | errs() << " " << PartialAliasCount << " partial alias responses " ; |
| 289 | PrintPercent(Num: PartialAliasCount, Sum: AliasSum); |
| 290 | errs() << " " << MustAliasCount << " must alias responses " ; |
| 291 | PrintPercent(Num: MustAliasCount, Sum: AliasSum); |
| 292 | errs() << " Alias Analysis Evaluator Pointer Alias Summary: " |
| 293 | << NoAliasCount * 100 / AliasSum << "%/" |
| 294 | << MayAliasCount * 100 / AliasSum << "%/" |
| 295 | << PartialAliasCount * 100 / AliasSum << "%/" |
| 296 | << MustAliasCount * 100 / AliasSum << "%\n" ; |
| 297 | } |
| 298 | |
| 299 | // Display the summary for mod/ref analysis |
| 300 | int64_t ModRefSum = NoModRefCount + RefCount + ModCount + ModRefCount; |
| 301 | if (ModRefSum == 0) { |
| 302 | errs() << " Alias Analysis Mod/Ref Evaluator Summary: no " |
| 303 | "mod/ref!\n" ; |
| 304 | } else { |
| 305 | errs() << " " << ModRefSum << " Total ModRef Queries Performed\n" ; |
| 306 | errs() << " " << NoModRefCount << " no mod/ref responses " ; |
| 307 | PrintPercent(Num: NoModRefCount, Sum: ModRefSum); |
| 308 | errs() << " " << ModCount << " mod responses " ; |
| 309 | PrintPercent(Num: ModCount, Sum: ModRefSum); |
| 310 | errs() << " " << RefCount << " ref responses " ; |
| 311 | PrintPercent(Num: RefCount, Sum: ModRefSum); |
| 312 | errs() << " " << ModRefCount << " mod & ref responses " ; |
| 313 | PrintPercent(Num: ModRefCount, Sum: ModRefSum); |
| 314 | errs() << " Alias Analysis Evaluator Mod/Ref Summary: " |
| 315 | << NoModRefCount * 100 / ModRefSum << "%/" |
| 316 | << ModCount * 100 / ModRefSum << "%/" << RefCount * 100 / ModRefSum |
| 317 | << "%/" << ModRefCount * 100 / ModRefSum << "%\n" ; |
| 318 | } |
| 319 | } |
| 320 | |