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 
PrintResults(AliasResult AR,bool P,std::pair<const Value *,Type * > Loc1,std::pair<const Value *,Type * > Loc2,const Module * M)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(os1, false, M);
47       Loc2.first->printAsOperand(os2, false, M);
48     }
49 
50     if (o2 < o1) {
51       std::swap(o1, o2);
52       std::swap(Ty1, Ty2);
53       std::swap(AS1, AS2);
54       // Change offset sign for the local AR, for printing only.
55       AR.swap();
56     }
57     errs() << "  " << AR << ":\t";
58     Ty1->print(errs(), false, /* NoDetails */ true);
59     if (AS1 != 0)
60       errs() << " addrspace(" << AS1 << ")";
61     errs() << "* " << o1 << ", ";
62     Ty2->print(errs(), false, /* NoDetails */ true);
63     if (AS2 != 0)
64       errs() << " addrspace(" << AS2 << ")";
65     errs() << "* " << o2 << "\n";
66   }
67 }
68 
PrintModRefResults(const char * Msg,bool P,Instruction * I,std::pair<const Value *,Type * > Loc,Module * M)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(errs(), false, /* NoDetails */ true);
75     errs() << "* ";
76     Loc.first->printAsOperand(errs(), false, M);
77     errs() << "\t<->" << *I << '\n';
78   }
79 }
80 
PrintModRefResults(const char * Msg,bool P,CallBase * CallA,CallBase * CallB,Module * M)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 
PrintLoadStoreResults(AliasResult AR,bool P,const Value * V1,const Value * V2,const Module * M)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 
run(Function & F,FunctionAnalysisManager & AM)96 PreservedAnalyses AAEvaluator::run(Function &F, FunctionAnalysisManager &AM) {
97   runInternal(F, AM.getResult<AAManager>(F));
98   return PreservedAnalyses::all();
99 }
100 
runInternal(Function & F,AAResults & AA)101 void AAEvaluator::runInternal(Function &F, AAResults &AA) {
102   const DataLayout &DL = F.getParent()->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>(&Inst)) {
113       Pointers.insert({LI->getPointerOperand(), LI->getType()});
114       Loads.insert(LI);
115     } else if (auto *SI = dyn_cast<StoreInst>(&Inst)) {
116       Pointers.insert({SI->getPointerOperand(),
117                        SI->getValueOperand()->getType()});
118       Stores.insert(SI);
119     } else if (auto *CB = dyn_cast<CallBase>(&Inst))
120       Calls.insert(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(DL.getTypeStoreSize(I1->second));
131     for (auto I2 = Pointers.begin(); I2 != I1; ++I2) {
132       LocationSize Size2 =
133           LocationSize::precise(DL.getTypeStoreSize(I2->second));
134       AliasResult AR = AA.alias(I1->first, Size1, I2->first, Size2);
135       switch (AR) {
136       case AliasResult::NoAlias:
137         PrintResults(AR, PrintNoAlias, *I1, *I2, F.getParent());
138         ++NoAliasCount;
139         break;
140       case AliasResult::MayAlias:
141         PrintResults(AR, PrintMayAlias, *I1, *I2, F.getParent());
142         ++MayAliasCount;
143         break;
144       case AliasResult::PartialAlias:
145         PrintResults(AR, PrintPartialAlias, *I1, *I2, F.getParent());
146         ++PartialAliasCount;
147         break;
148       case AliasResult::MustAlias:
149         PrintResults(AR, PrintMustAlias, *I1, *I2, 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(MemoryLocation::get(cast<LoadInst>(Load)),
161                                   MemoryLocation::get(cast<StoreInst>(Store)));
162         switch (AR) {
163         case AliasResult::NoAlias:
164           PrintLoadStoreResults(AR, PrintNoAlias, Load, Store, F.getParent());
165           ++NoAliasCount;
166           break;
167         case AliasResult::MayAlias:
168           PrintLoadStoreResults(AR, PrintMayAlias, Load, Store, F.getParent());
169           ++MayAliasCount;
170           break;
171         case AliasResult::PartialAlias:
172           PrintLoadStoreResults(AR, PrintPartialAlias, Load, Store, F.getParent());
173           ++PartialAliasCount;
174           break;
175         case AliasResult::MustAlias:
176           PrintLoadStoreResults(AR, PrintMustAlias, Load, Store, 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(MemoryLocation::get(cast<StoreInst>(*I1)),
188                                   MemoryLocation::get(cast<StoreInst>(*I2)));
189         switch (AR) {
190         case AliasResult::NoAlias:
191           PrintLoadStoreResults(AR, PrintNoAlias, *I1, *I2, F.getParent());
192           ++NoAliasCount;
193           break;
194         case AliasResult::MayAlias:
195           PrintLoadStoreResults(AR, PrintMayAlias, *I1, *I2, F.getParent());
196           ++MayAliasCount;
197           break;
198         case AliasResult::PartialAlias:
199           PrintLoadStoreResults(AR, PrintPartialAlias, *I1, *I2, F.getParent());
200           ++PartialAliasCount;
201           break;
202         case AliasResult::MustAlias:
203           PrintLoadStoreResults(AR, PrintMustAlias, *I1, *I2, 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(DL.getTypeStoreSize(Pointer.second));
216       switch (AA.getModRefInfo(Call, Pointer.first, Size)) {
217       case ModRefInfo::NoModRef:
218         PrintModRefResults("NoModRef", PrintNoModRef, Call, Pointer,
219                            F.getParent());
220         ++NoModRefCount;
221         break;
222       case ModRefInfo::Mod:
223         PrintModRefResults("Just Mod", PrintMod, Call, Pointer, F.getParent());
224         ++ModCount;
225         break;
226       case ModRefInfo::Ref:
227         PrintModRefResults("Just Ref", PrintRef, Call, Pointer, F.getParent());
228         ++RefCount;
229         break;
230       case ModRefInfo::ModRef:
231         PrintModRefResults("Both ModRef", PrintModRef, Call, Pointer,
232                            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(CallA, CallB)) {
245       case ModRefInfo::NoModRef:
246         PrintModRefResults("NoModRef", PrintNoModRef, CallA, CallB,
247                            F.getParent());
248         ++NoModRefCount;
249         break;
250       case ModRefInfo::Mod:
251         PrintModRefResults("Just Mod", PrintMod, CallA, CallB, F.getParent());
252         ++ModCount;
253         break;
254       case ModRefInfo::Ref:
255         PrintModRefResults("Just Ref", PrintRef, CallA, CallB, F.getParent());
256         ++RefCount;
257         break;
258       case ModRefInfo::ModRef:
259         PrintModRefResults("Both ModRef", PrintModRef, CallA, CallB,
260                            F.getParent());
261         ++ModRefCount;
262         break;
263       }
264     }
265   }
266 }
267 
PrintPercent(int64_t Num,int64_t Sum)268 static void PrintPercent(int64_t Num, int64_t Sum) {
269   errs() << "(" << Num * 100LL / Sum << "." << ((Num * 1000LL / Sum) % 10)
270          << "%)\n";
271 }
272 
~AAEvaluator()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(NoAliasCount, AliasSum);
286     errs() << "  " << MayAliasCount << " may alias responses ";
287     PrintPercent(MayAliasCount, AliasSum);
288     errs() << "  " << PartialAliasCount << " partial alias responses ";
289     PrintPercent(PartialAliasCount, AliasSum);
290     errs() << "  " << MustAliasCount << " must alias responses ";
291     PrintPercent(MustAliasCount, 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(NoModRefCount, ModRefSum);
308     errs() << "  " << ModCount << " mod responses ";
309     PrintPercent(ModCount, ModRefSum);
310     errs() << "  " << RefCount << " ref responses ";
311     PrintPercent(RefCount, ModRefSum);
312     errs() << "  " << ModRefCount << " mod & ref responses ";
313     PrintPercent(ModRefCount, 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