1095e91c9SJon Roelofs //===-- MemoryOpRemark.cpp - Auto-init remark analysis---------------------===//
2095e91c9SJon Roelofs //
3095e91c9SJon Roelofs // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4095e91c9SJon Roelofs // See https://llvm.org/LICENSE.txt for license information.
5095e91c9SJon Roelofs // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6095e91c9SJon Roelofs //
7095e91c9SJon Roelofs //===----------------------------------------------------------------------===//
8095e91c9SJon Roelofs //
9095e91c9SJon Roelofs // Implementation of the analysis for the "auto-init" remark.
10095e91c9SJon Roelofs //
11095e91c9SJon Roelofs //===----------------------------------------------------------------------===//
12095e91c9SJon Roelofs 
13095e91c9SJon Roelofs #include "llvm/Transforms/Utils/MemoryOpRemark.h"
14095e91c9SJon Roelofs #include "llvm/Analysis/OptimizationRemarkEmitter.h"
15095e91c9SJon Roelofs #include "llvm/Analysis/ValueTracking.h"
16095e91c9SJon Roelofs #include "llvm/IR/DebugInfo.h"
17095e91c9SJon Roelofs #include "llvm/IR/Instructions.h"
18095e91c9SJon Roelofs #include "llvm/IR/IntrinsicInst.h"
19095e91c9SJon Roelofs 
20095e91c9SJon Roelofs using namespace llvm;
21095e91c9SJon Roelofs using namespace llvm::ore;
22095e91c9SJon Roelofs 
23095e91c9SJon Roelofs MemoryOpRemark::~MemoryOpRemark() = default;
24095e91c9SJon Roelofs 
canHandle(const Instruction * I,const TargetLibraryInfo & TLI)25095e91c9SJon Roelofs bool MemoryOpRemark::canHandle(const Instruction *I, const TargetLibraryInfo &TLI) {
26095e91c9SJon Roelofs   if (isa<StoreInst>(I))
27095e91c9SJon Roelofs     return true;
28095e91c9SJon Roelofs 
29095e91c9SJon Roelofs   if (auto *II = dyn_cast<IntrinsicInst>(I)) {
30095e91c9SJon Roelofs     switch (II->getIntrinsicID()) {
31095e91c9SJon Roelofs     case Intrinsic::memcpy_inline:
32095e91c9SJon Roelofs     case Intrinsic::memcpy:
33095e91c9SJon Roelofs     case Intrinsic::memmove:
34095e91c9SJon Roelofs     case Intrinsic::memset:
35095e91c9SJon Roelofs     case Intrinsic::memcpy_element_unordered_atomic:
36095e91c9SJon Roelofs     case Intrinsic::memmove_element_unordered_atomic:
37095e91c9SJon Roelofs     case Intrinsic::memset_element_unordered_atomic:
38095e91c9SJon Roelofs       return true;
39095e91c9SJon Roelofs     default:
40095e91c9SJon Roelofs       return false;
41095e91c9SJon Roelofs     }
42095e91c9SJon Roelofs   }
43095e91c9SJon Roelofs 
44095e91c9SJon Roelofs   if (auto *CI = dyn_cast<CallInst>(I)) {
45095e91c9SJon Roelofs     auto *CF = CI->getCalledFunction();
46095e91c9SJon Roelofs     if (!CF)
47095e91c9SJon Roelofs       return false;
48095e91c9SJon Roelofs 
49095e91c9SJon Roelofs     if (!CF->hasName())
50095e91c9SJon Roelofs       return false;
51095e91c9SJon Roelofs 
52095e91c9SJon Roelofs     LibFunc LF;
53095e91c9SJon Roelofs     bool KnownLibCall = TLI.getLibFunc(*CF, LF) && TLI.has(LF);
54095e91c9SJon Roelofs     if (!KnownLibCall)
55095e91c9SJon Roelofs       return false;
56095e91c9SJon Roelofs 
57095e91c9SJon Roelofs     switch (LF) {
58095e91c9SJon Roelofs     case LibFunc_memcpy_chk:
59095e91c9SJon Roelofs     case LibFunc_mempcpy_chk:
60095e91c9SJon Roelofs     case LibFunc_memset_chk:
61095e91c9SJon Roelofs     case LibFunc_memmove_chk:
62095e91c9SJon Roelofs     case LibFunc_memcpy:
63095e91c9SJon Roelofs     case LibFunc_mempcpy:
64095e91c9SJon Roelofs     case LibFunc_memset:
65095e91c9SJon Roelofs     case LibFunc_memmove:
66095e91c9SJon Roelofs     case LibFunc_bzero:
67095e91c9SJon Roelofs     case LibFunc_bcopy:
68095e91c9SJon Roelofs       return true;
69095e91c9SJon Roelofs     default:
70095e91c9SJon Roelofs       return false;
71095e91c9SJon Roelofs     }
72095e91c9SJon Roelofs   }
73095e91c9SJon Roelofs 
74095e91c9SJon Roelofs   return false;
75095e91c9SJon Roelofs }
76095e91c9SJon Roelofs 
visit(const Instruction * I)77095e91c9SJon Roelofs void MemoryOpRemark::visit(const Instruction *I) {
78095e91c9SJon Roelofs   // For some of them, we can provide more information:
79095e91c9SJon Roelofs 
80095e91c9SJon Roelofs   // For stores:
81095e91c9SJon Roelofs   // * size
82095e91c9SJon Roelofs   // * volatile / atomic
83095e91c9SJon Roelofs   if (auto *SI = dyn_cast<StoreInst>(I)) {
84095e91c9SJon Roelofs     visitStore(*SI);
85095e91c9SJon Roelofs     return;
86095e91c9SJon Roelofs   }
87095e91c9SJon Roelofs 
88095e91c9SJon Roelofs   // For intrinsics:
89095e91c9SJon Roelofs   // * user-friendly name
90095e91c9SJon Roelofs   // * size
91095e91c9SJon Roelofs   if (auto *II = dyn_cast<IntrinsicInst>(I)) {
92095e91c9SJon Roelofs     visitIntrinsicCall(*II);
93095e91c9SJon Roelofs     return;
94095e91c9SJon Roelofs   }
95095e91c9SJon Roelofs 
96095e91c9SJon Roelofs   // For calls:
97095e91c9SJon Roelofs   // * known/unknown function (e.g. the compiler knows bzero, but it doesn't
98095e91c9SJon Roelofs   //                                know my_bzero)
99095e91c9SJon Roelofs   // * memory operation size
100095e91c9SJon Roelofs   if (auto *CI = dyn_cast<CallInst>(I)) {
101095e91c9SJon Roelofs     visitCall(*CI);
102095e91c9SJon Roelofs     return;
103095e91c9SJon Roelofs   }
104095e91c9SJon Roelofs 
105095e91c9SJon Roelofs   visitUnknown(*I);
106095e91c9SJon Roelofs }
107095e91c9SJon Roelofs 
explainSource(StringRef Type) const108493d6928SJon Roelofs std::string MemoryOpRemark::explainSource(StringRef Type) const {
109095e91c9SJon Roelofs   return (Type + ".").str();
110095e91c9SJon Roelofs }
111095e91c9SJon Roelofs 
remarkName(RemarkKind RK) const112493d6928SJon Roelofs StringRef MemoryOpRemark::remarkName(RemarkKind RK) const {
113095e91c9SJon Roelofs   switch (RK) {
114095e91c9SJon Roelofs   case RK_Store:
115095e91c9SJon Roelofs     return "MemoryOpStore";
116095e91c9SJon Roelofs   case RK_Unknown:
117095e91c9SJon Roelofs     return "MemoryOpUnknown";
118095e91c9SJon Roelofs   case RK_IntrinsicCall:
119095e91c9SJon Roelofs     return "MemoryOpIntrinsicCall";
120095e91c9SJon Roelofs   case RK_Call:
121095e91c9SJon Roelofs     return "MemoryOpCall";
122095e91c9SJon Roelofs   }
123095e91c9SJon Roelofs   llvm_unreachable("missing RemarkKind case");
124095e91c9SJon Roelofs }
125095e91c9SJon Roelofs 
inlineVolatileOrAtomicWithExtraArgs(bool * Inline,bool Volatile,bool Atomic,DiagnosticInfoIROptimization & R)126095e91c9SJon Roelofs static void inlineVolatileOrAtomicWithExtraArgs(bool *Inline, bool Volatile,
127095e91c9SJon Roelofs                                                 bool Atomic,
128493d6928SJon Roelofs                                                 DiagnosticInfoIROptimization &R) {
129095e91c9SJon Roelofs   if (Inline && *Inline)
130095e91c9SJon Roelofs     R << " Inlined: " << NV("StoreInlined", true) << ".";
131095e91c9SJon Roelofs   if (Volatile)
132095e91c9SJon Roelofs     R << " Volatile: " << NV("StoreVolatile", true) << ".";
133095e91c9SJon Roelofs   if (Atomic)
134095e91c9SJon Roelofs     R << " Atomic: " << NV("StoreAtomic", true) << ".";
135095e91c9SJon Roelofs   // Emit the false cases under ExtraArgs. This won't show them in the remark
136095e91c9SJon Roelofs   // message but will end up in the serialized remarks.
137095e91c9SJon Roelofs   if ((Inline && !*Inline) || !Volatile || !Atomic)
138095e91c9SJon Roelofs     R << setExtraArgs();
139095e91c9SJon Roelofs   if (Inline && !*Inline)
140095e91c9SJon Roelofs     R << " Inlined: " << NV("StoreInlined", false) << ".";
141095e91c9SJon Roelofs   if (!Volatile)
142095e91c9SJon Roelofs     R << " Volatile: " << NV("StoreVolatile", false) << ".";
143095e91c9SJon Roelofs   if (!Atomic)
144095e91c9SJon Roelofs     R << " Atomic: " << NV("StoreAtomic", false) << ".";
145095e91c9SJon Roelofs }
146095e91c9SJon Roelofs 
getSizeInBytes(Optional<uint64_t> SizeInBits)147095e91c9SJon Roelofs static Optional<uint64_t> getSizeInBytes(Optional<uint64_t> SizeInBits) {
148095e91c9SJon Roelofs   if (!SizeInBits || *SizeInBits % 8 != 0)
149095e91c9SJon Roelofs     return None;
150095e91c9SJon Roelofs   return *SizeInBits / 8;
151095e91c9SJon Roelofs }
152095e91c9SJon Roelofs 
153493d6928SJon Roelofs template<typename ...Ts>
154493d6928SJon Roelofs std::unique_ptr<DiagnosticInfoIROptimization>
makeRemark(Ts...Args)155493d6928SJon Roelofs MemoryOpRemark::makeRemark(Ts... Args) {
156493d6928SJon Roelofs   switch (diagnosticKind()) {
157493d6928SJon Roelofs   case DK_OptimizationRemarkAnalysis:
158493d6928SJon Roelofs     return std::make_unique<OptimizationRemarkAnalysis>(Args...);
159493d6928SJon Roelofs   case DK_OptimizationRemarkMissed:
160493d6928SJon Roelofs     return std::make_unique<OptimizationRemarkMissed>(Args...);
161493d6928SJon Roelofs   default:
162493d6928SJon Roelofs     llvm_unreachable("unexpected DiagnosticKind");
163493d6928SJon Roelofs   }
164493d6928SJon Roelofs }
165493d6928SJon Roelofs 
visitStore(const StoreInst & SI)166095e91c9SJon Roelofs void MemoryOpRemark::visitStore(const StoreInst &SI) {
167095e91c9SJon Roelofs   bool Volatile = SI.isVolatile();
168095e91c9SJon Roelofs   bool Atomic = SI.isAtomic();
169095e91c9SJon Roelofs   int64_t Size = DL.getTypeStoreSize(SI.getOperand(0)->getType());
170095e91c9SJon Roelofs 
171493d6928SJon Roelofs   auto R = makeRemark(RemarkPass.data(), remarkName(RK_Store), &SI);
172493d6928SJon Roelofs   *R << explainSource("Store") << "\nStore size: " << NV("StoreSize", Size)
173095e91c9SJon Roelofs      << " bytes.";
174493d6928SJon Roelofs   visitPtr(SI.getOperand(1), /*IsRead=*/false, *R);
175493d6928SJon Roelofs   inlineVolatileOrAtomicWithExtraArgs(nullptr, Volatile, Atomic, *R);
176493d6928SJon Roelofs   ORE.emit(*R);
177095e91c9SJon Roelofs }
178095e91c9SJon Roelofs 
visitUnknown(const Instruction & I)179095e91c9SJon Roelofs void MemoryOpRemark::visitUnknown(const Instruction &I) {
180493d6928SJon Roelofs   auto R = makeRemark(RemarkPass.data(), remarkName(RK_Unknown), &I);
181493d6928SJon Roelofs   *R << explainSource("Initialization");
182493d6928SJon Roelofs   ORE.emit(*R);
183095e91c9SJon Roelofs }
184095e91c9SJon Roelofs 
visitIntrinsicCall(const IntrinsicInst & II)185095e91c9SJon Roelofs void MemoryOpRemark::visitIntrinsicCall(const IntrinsicInst &II) {
186095e91c9SJon Roelofs   SmallString<32> CallTo;
187095e91c9SJon Roelofs   bool Atomic = false;
188095e91c9SJon Roelofs   bool Inline = false;
189095e91c9SJon Roelofs   switch (II.getIntrinsicID()) {
190095e91c9SJon Roelofs   case Intrinsic::memcpy_inline:
191095e91c9SJon Roelofs     CallTo = "memcpy";
192095e91c9SJon Roelofs     Inline = true;
193095e91c9SJon Roelofs     break;
194095e91c9SJon Roelofs   case Intrinsic::memcpy:
195095e91c9SJon Roelofs     CallTo = "memcpy";
196095e91c9SJon Roelofs     break;
197095e91c9SJon Roelofs   case Intrinsic::memmove:
198095e91c9SJon Roelofs     CallTo = "memmove";
199095e91c9SJon Roelofs     break;
200095e91c9SJon Roelofs   case Intrinsic::memset:
201095e91c9SJon Roelofs     CallTo = "memset";
202095e91c9SJon Roelofs     break;
203095e91c9SJon Roelofs   case Intrinsic::memcpy_element_unordered_atomic:
204095e91c9SJon Roelofs     CallTo = "memcpy";
205095e91c9SJon Roelofs     Atomic = true;
206095e91c9SJon Roelofs     break;
207095e91c9SJon Roelofs   case Intrinsic::memmove_element_unordered_atomic:
208095e91c9SJon Roelofs     CallTo = "memmove";
209095e91c9SJon Roelofs     Atomic = true;
210095e91c9SJon Roelofs     break;
211095e91c9SJon Roelofs   case Intrinsic::memset_element_unordered_atomic:
212095e91c9SJon Roelofs     CallTo = "memset";
213095e91c9SJon Roelofs     Atomic = true;
214095e91c9SJon Roelofs     break;
215095e91c9SJon Roelofs   default:
216095e91c9SJon Roelofs     return visitUnknown(II);
217095e91c9SJon Roelofs   }
218095e91c9SJon Roelofs 
219493d6928SJon Roelofs   auto R = makeRemark(RemarkPass.data(), remarkName(RK_IntrinsicCall), &II);
2201def2579SDavid Blaikie   visitCallee(CallTo.str(), /*KnownLibCall=*/true, *R);
221493d6928SJon Roelofs   visitSizeOperand(II.getOperand(2), *R);
222095e91c9SJon Roelofs 
223095e91c9SJon Roelofs   auto *CIVolatile = dyn_cast<ConstantInt>(II.getOperand(3));
224095e91c9SJon Roelofs   // No such thing as a memory intrinsic that is both atomic and volatile.
225095e91c9SJon Roelofs   bool Volatile = !Atomic && CIVolatile && CIVolatile->getZExtValue();
226095e91c9SJon Roelofs   switch (II.getIntrinsicID()) {
227095e91c9SJon Roelofs   case Intrinsic::memcpy_inline:
228095e91c9SJon Roelofs   case Intrinsic::memcpy:
229095e91c9SJon Roelofs   case Intrinsic::memmove:
230095e91c9SJon Roelofs   case Intrinsic::memcpy_element_unordered_atomic:
231493d6928SJon Roelofs     visitPtr(II.getOperand(1), /*IsRead=*/true, *R);
232493d6928SJon Roelofs     visitPtr(II.getOperand(0), /*IsRead=*/false, *R);
233095e91c9SJon Roelofs     break;
234095e91c9SJon Roelofs   case Intrinsic::memset:
235095e91c9SJon Roelofs   case Intrinsic::memset_element_unordered_atomic:
236493d6928SJon Roelofs     visitPtr(II.getOperand(0), /*IsRead=*/false, *R);
237095e91c9SJon Roelofs     break;
238095e91c9SJon Roelofs   }
239493d6928SJon Roelofs   inlineVolatileOrAtomicWithExtraArgs(&Inline, Volatile, Atomic, *R);
240493d6928SJon Roelofs   ORE.emit(*R);
241095e91c9SJon Roelofs }
242095e91c9SJon Roelofs 
visitCall(const CallInst & CI)243095e91c9SJon Roelofs void MemoryOpRemark::visitCall(const CallInst &CI) {
244095e91c9SJon Roelofs   Function *F = CI.getCalledFunction();
245095e91c9SJon Roelofs   if (!F)
246095e91c9SJon Roelofs     return visitUnknown(CI);
247095e91c9SJon Roelofs 
248095e91c9SJon Roelofs   LibFunc LF;
249095e91c9SJon Roelofs   bool KnownLibCall = TLI.getLibFunc(*F, LF) && TLI.has(LF);
250493d6928SJon Roelofs   auto R = makeRemark(RemarkPass.data(), remarkName(RK_Call), &CI);
251493d6928SJon Roelofs   visitCallee(F, KnownLibCall, *R);
252493d6928SJon Roelofs   visitKnownLibCall(CI, LF, *R);
253493d6928SJon Roelofs   ORE.emit(*R);
254095e91c9SJon Roelofs }
255095e91c9SJon Roelofs 
256095e91c9SJon Roelofs template <typename FTy>
visitCallee(FTy F,bool KnownLibCall,DiagnosticInfoIROptimization & R)257095e91c9SJon Roelofs void MemoryOpRemark::visitCallee(FTy F, bool KnownLibCall,
258493d6928SJon Roelofs                                  DiagnosticInfoIROptimization &R) {
259095e91c9SJon Roelofs   R << "Call to ";
260095e91c9SJon Roelofs   if (!KnownLibCall)
261095e91c9SJon Roelofs     R << NV("UnknownLibCall", "unknown") << " function ";
262095e91c9SJon Roelofs   R << NV("Callee", F) << explainSource("");
263095e91c9SJon Roelofs }
264095e91c9SJon Roelofs 
visitKnownLibCall(const CallInst & CI,LibFunc LF,DiagnosticInfoIROptimization & R)265095e91c9SJon Roelofs void MemoryOpRemark::visitKnownLibCall(const CallInst &CI, LibFunc LF,
266493d6928SJon Roelofs                                        DiagnosticInfoIROptimization &R) {
267095e91c9SJon Roelofs   switch (LF) {
268095e91c9SJon Roelofs   default:
269095e91c9SJon Roelofs     return;
270095e91c9SJon Roelofs   case LibFunc_memset_chk:
271095e91c9SJon Roelofs   case LibFunc_memset:
272095e91c9SJon Roelofs     visitSizeOperand(CI.getOperand(2), R);
273095e91c9SJon Roelofs     visitPtr(CI.getOperand(0), /*IsRead=*/false, R);
274095e91c9SJon Roelofs     break;
275095e91c9SJon Roelofs   case LibFunc_bzero:
276095e91c9SJon Roelofs     visitSizeOperand(CI.getOperand(1), R);
277095e91c9SJon Roelofs     visitPtr(CI.getOperand(0), /*IsRead=*/false, R);
278095e91c9SJon Roelofs     break;
279095e91c9SJon Roelofs   case LibFunc_memcpy_chk:
280095e91c9SJon Roelofs   case LibFunc_mempcpy_chk:
281095e91c9SJon Roelofs   case LibFunc_memmove_chk:
282095e91c9SJon Roelofs   case LibFunc_memcpy:
283095e91c9SJon Roelofs   case LibFunc_mempcpy:
284095e91c9SJon Roelofs   case LibFunc_memmove:
285095e91c9SJon Roelofs   case LibFunc_bcopy:
286095e91c9SJon Roelofs     visitSizeOperand(CI.getOperand(2), R);
287095e91c9SJon Roelofs     visitPtr(CI.getOperand(1), /*IsRead=*/true, R);
288095e91c9SJon Roelofs     visitPtr(CI.getOperand(0), /*IsRead=*/false, R);
289095e91c9SJon Roelofs     break;
290095e91c9SJon Roelofs   }
291095e91c9SJon Roelofs }
292095e91c9SJon Roelofs 
visitSizeOperand(Value * V,DiagnosticInfoIROptimization & R)293493d6928SJon Roelofs void MemoryOpRemark::visitSizeOperand(Value *V, DiagnosticInfoIROptimization &R) {
294095e91c9SJon Roelofs   if (auto *Len = dyn_cast<ConstantInt>(V)) {
295095e91c9SJon Roelofs     uint64_t Size = Len->getZExtValue();
296095e91c9SJon Roelofs     R << " Memory operation size: " << NV("StoreSize", Size) << " bytes.";
297095e91c9SJon Roelofs   }
298095e91c9SJon Roelofs }
299095e91c9SJon Roelofs 
nameOrNone(const Value * V)300f8f1c9c3SJon Roelofs static Optional<StringRef> nameOrNone(const Value *V) {
301f8f1c9c3SJon Roelofs   if (V->hasName())
302f8f1c9c3SJon Roelofs     return V->getName();
303f8f1c9c3SJon Roelofs   return None;
304f8f1c9c3SJon Roelofs }
305f8f1c9c3SJon Roelofs 
visitVariable(const Value * V,SmallVectorImpl<VariableInfo> & Result)306095e91c9SJon Roelofs void MemoryOpRemark::visitVariable(const Value *V,
307095e91c9SJon Roelofs                                    SmallVectorImpl<VariableInfo> &Result) {
308f8f1c9c3SJon Roelofs   if (auto *GV = dyn_cast<GlobalVariable>(V)) {
309*4e601325SArthur Eubanks     auto *Ty = GV->getValueType();
310b01d393fSSimon Pilgrim     uint64_t Size = DL.getTypeSizeInBits(Ty).getFixedSize();
311f8f1c9c3SJon Roelofs     VariableInfo Var{nameOrNone(GV), Size};
312f8f1c9c3SJon Roelofs     if (!Var.isEmpty())
313f8f1c9c3SJon Roelofs       Result.push_back(std::move(Var));
314f8f1c9c3SJon Roelofs     return;
315f8f1c9c3SJon Roelofs   }
316f8f1c9c3SJon Roelofs 
317095e91c9SJon Roelofs   // If we find some information in the debug info, take that.
318095e91c9SJon Roelofs   bool FoundDI = false;
319095e91c9SJon Roelofs   // Try to get an llvm.dbg.declare, which has a DILocalVariable giving us the
320095e91c9SJon Roelofs   // real debug info name and size of the variable.
321095e91c9SJon Roelofs   for (const DbgVariableIntrinsic *DVI :
322095e91c9SJon Roelofs        FindDbgAddrUses(const_cast<Value *>(V))) {
323095e91c9SJon Roelofs     if (DILocalVariable *DILV = DVI->getVariable()) {
324095e91c9SJon Roelofs       Optional<uint64_t> DISize = getSizeInBytes(DILV->getSizeInBits());
325095e91c9SJon Roelofs       VariableInfo Var{DILV->getName(), DISize};
326095e91c9SJon Roelofs       if (!Var.isEmpty()) {
327095e91c9SJon Roelofs         Result.push_back(std::move(Var));
328095e91c9SJon Roelofs         FoundDI = true;
329095e91c9SJon Roelofs       }
330095e91c9SJon Roelofs     }
331095e91c9SJon Roelofs   }
332095e91c9SJon Roelofs   if (FoundDI) {
333095e91c9SJon Roelofs     assert(!Result.empty());
334095e91c9SJon Roelofs     return;
335095e91c9SJon Roelofs   }
336095e91c9SJon Roelofs 
337095e91c9SJon Roelofs   const auto *AI = dyn_cast<AllocaInst>(V);
338095e91c9SJon Roelofs   if (!AI)
339095e91c9SJon Roelofs     return;
340095e91c9SJon Roelofs 
341095e91c9SJon Roelofs   // If not, get it from the alloca.
342095e91c9SJon Roelofs   Optional<TypeSize> TySize = AI->getAllocationSizeInBits(DL);
343095e91c9SJon Roelofs   Optional<uint64_t> Size =
344095e91c9SJon Roelofs       TySize ? getSizeInBytes(TySize->getFixedSize()) : None;
345f8f1c9c3SJon Roelofs   VariableInfo Var{nameOrNone(AI), Size};
346095e91c9SJon Roelofs   if (!Var.isEmpty())
347095e91c9SJon Roelofs     Result.push_back(std::move(Var));
348095e91c9SJon Roelofs }
349095e91c9SJon Roelofs 
visitPtr(Value * Ptr,bool IsRead,DiagnosticInfoIROptimization & R)350493d6928SJon Roelofs void MemoryOpRemark::visitPtr(Value *Ptr, bool IsRead, DiagnosticInfoIROptimization &R) {
351095e91c9SJon Roelofs   // Find if Ptr is a known variable we can give more information on.
352095e91c9SJon Roelofs   SmallVector<Value *, 2> Objects;
353095e91c9SJon Roelofs   getUnderlyingObjectsForCodeGen(Ptr, Objects);
354095e91c9SJon Roelofs   SmallVector<VariableInfo, 2> VIs;
355095e91c9SJon Roelofs   for (const Value *V : Objects)
356095e91c9SJon Roelofs     visitVariable(V, VIs);
357095e91c9SJon Roelofs 
358095e91c9SJon Roelofs   if (VIs.empty()) {
359095e91c9SJon Roelofs     bool CanBeNull;
360095e91c9SJon Roelofs     bool CanBeFreed;
361095e91c9SJon Roelofs     uint64_t Size = Ptr->getPointerDereferenceableBytes(DL, CanBeNull, CanBeFreed);
362095e91c9SJon Roelofs     if (!Size)
363095e91c9SJon Roelofs       return;
364095e91c9SJon Roelofs     VIs.push_back({None, Size});
365095e91c9SJon Roelofs   }
366095e91c9SJon Roelofs 
367095e91c9SJon Roelofs   R << (IsRead ? "\n Read Variables: " : "\n Written Variables: ");
368095e91c9SJon Roelofs   for (unsigned i = 0; i < VIs.size(); ++i) {
369095e91c9SJon Roelofs     const VariableInfo &VI = VIs[i];
370095e91c9SJon Roelofs     assert(!VI.isEmpty() && "No extra content to display.");
371095e91c9SJon Roelofs     if (i != 0)
372095e91c9SJon Roelofs       R << ", ";
373095e91c9SJon Roelofs     if (VI.Name)
374095e91c9SJon Roelofs       R << NV(IsRead ? "RVarName" : "WVarName", *VI.Name);
375095e91c9SJon Roelofs     else
376095e91c9SJon Roelofs       R << NV(IsRead ? "RVarName" : "WVarName", "<unknown>");
377095e91c9SJon Roelofs     if (VI.Size)
378095e91c9SJon Roelofs       R << " (" << NV(IsRead ? "RVarSize" : "WVarSize", *VI.Size) << " bytes)";
379095e91c9SJon Roelofs   }
380095e91c9SJon Roelofs   R << ".";
381095e91c9SJon Roelofs }
382095e91c9SJon Roelofs 
canHandle(const Instruction * I)383095e91c9SJon Roelofs bool AutoInitRemark::canHandle(const Instruction *I) {
384095e91c9SJon Roelofs   if (!I->hasMetadata(LLVMContext::MD_annotation))
385095e91c9SJon Roelofs     return false;
386095e91c9SJon Roelofs   return any_of(I->getMetadata(LLVMContext::MD_annotation)->operands(),
387095e91c9SJon Roelofs                 [](const MDOperand &Op) {
388095e91c9SJon Roelofs                   return cast<MDString>(Op.get())->getString() == "auto-init";
389095e91c9SJon Roelofs                 });
390095e91c9SJon Roelofs }
391095e91c9SJon Roelofs 
explainSource(StringRef Type) const392493d6928SJon Roelofs std::string AutoInitRemark::explainSource(StringRef Type) const {
393095e91c9SJon Roelofs   return (Type + " inserted by -ftrivial-auto-var-init.").str();
394095e91c9SJon Roelofs }
395095e91c9SJon Roelofs 
remarkName(RemarkKind RK) const396493d6928SJon Roelofs StringRef AutoInitRemark::remarkName(RemarkKind RK) const {
397095e91c9SJon Roelofs   switch (RK) {
398095e91c9SJon Roelofs   case RK_Store:
399095e91c9SJon Roelofs     return "AutoInitStore";
400095e91c9SJon Roelofs   case RK_Unknown:
401095e91c9SJon Roelofs     return "AutoInitUnknownInstruction";
402095e91c9SJon Roelofs   case RK_IntrinsicCall:
403095e91c9SJon Roelofs     return "AutoInitIntrinsicCall";
404095e91c9SJon Roelofs   case RK_Call:
405095e91c9SJon Roelofs     return "AutoInitCall";
406095e91c9SJon Roelofs   }
407095e91c9SJon Roelofs   llvm_unreachable("missing RemarkKind case");
408095e91c9SJon Roelofs }
409