xref: /freebsd-src/contrib/llvm-project/llvm/lib/Transforms/Utils/MemoryOpRemark.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1fe6060f1SDimitry Andric //===-- MemoryOpRemark.cpp - Auto-init remark analysis---------------------===//
2fe6060f1SDimitry Andric //
3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fe6060f1SDimitry Andric //
7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
8fe6060f1SDimitry Andric //
9fe6060f1SDimitry Andric // Implementation of the analysis for the "auto-init" remark.
10fe6060f1SDimitry Andric //
11fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
12fe6060f1SDimitry Andric 
13fe6060f1SDimitry Andric #include "llvm/Transforms/Utils/MemoryOpRemark.h"
1406c3fb27SDimitry Andric #include "llvm/ADT/SmallString.h"
15fe6060f1SDimitry Andric #include "llvm/Analysis/OptimizationRemarkEmitter.h"
16fe6060f1SDimitry Andric #include "llvm/Analysis/ValueTracking.h"
17fe6060f1SDimitry Andric #include "llvm/IR/DebugInfo.h"
18fe6060f1SDimitry Andric #include "llvm/IR/Instructions.h"
19fe6060f1SDimitry Andric #include "llvm/IR/IntrinsicInst.h"
20bdd1243dSDimitry Andric #include <optional>
21fe6060f1SDimitry Andric 
22fe6060f1SDimitry Andric using namespace llvm;
23fe6060f1SDimitry Andric using namespace llvm::ore;
24fe6060f1SDimitry Andric 
25fe6060f1SDimitry Andric MemoryOpRemark::~MemoryOpRemark() = default;
26fe6060f1SDimitry Andric 
27fe6060f1SDimitry Andric bool MemoryOpRemark::canHandle(const Instruction *I, const TargetLibraryInfo &TLI) {
28fe6060f1SDimitry Andric   if (isa<StoreInst>(I))
29fe6060f1SDimitry Andric     return true;
30fe6060f1SDimitry Andric 
31fe6060f1SDimitry Andric   if (auto *II = dyn_cast<IntrinsicInst>(I)) {
32fe6060f1SDimitry Andric     switch (II->getIntrinsicID()) {
33fe6060f1SDimitry Andric     case Intrinsic::memcpy_inline:
34fe6060f1SDimitry Andric     case Intrinsic::memcpy:
35fe6060f1SDimitry Andric     case Intrinsic::memmove:
36fe6060f1SDimitry Andric     case Intrinsic::memset:
37fe6060f1SDimitry Andric     case Intrinsic::memcpy_element_unordered_atomic:
38fe6060f1SDimitry Andric     case Intrinsic::memmove_element_unordered_atomic:
39fe6060f1SDimitry Andric     case Intrinsic::memset_element_unordered_atomic:
40fe6060f1SDimitry Andric       return true;
41fe6060f1SDimitry Andric     default:
42fe6060f1SDimitry Andric       return false;
43fe6060f1SDimitry Andric     }
44fe6060f1SDimitry Andric   }
45fe6060f1SDimitry Andric 
46fe6060f1SDimitry Andric   if (auto *CI = dyn_cast<CallInst>(I)) {
47fe6060f1SDimitry Andric     auto *CF = CI->getCalledFunction();
48fe6060f1SDimitry Andric     if (!CF)
49fe6060f1SDimitry Andric       return false;
50fe6060f1SDimitry Andric 
51fe6060f1SDimitry Andric     if (!CF->hasName())
52fe6060f1SDimitry Andric       return false;
53fe6060f1SDimitry Andric 
54fe6060f1SDimitry Andric     LibFunc LF;
55fe6060f1SDimitry Andric     bool KnownLibCall = TLI.getLibFunc(*CF, LF) && TLI.has(LF);
56fe6060f1SDimitry Andric     if (!KnownLibCall)
57fe6060f1SDimitry Andric       return false;
58fe6060f1SDimitry Andric 
59fe6060f1SDimitry Andric     switch (LF) {
60fe6060f1SDimitry Andric     case LibFunc_memcpy_chk:
61fe6060f1SDimitry Andric     case LibFunc_mempcpy_chk:
62fe6060f1SDimitry Andric     case LibFunc_memset_chk:
63fe6060f1SDimitry Andric     case LibFunc_memmove_chk:
64fe6060f1SDimitry Andric     case LibFunc_memcpy:
65fe6060f1SDimitry Andric     case LibFunc_mempcpy:
66fe6060f1SDimitry Andric     case LibFunc_memset:
67fe6060f1SDimitry Andric     case LibFunc_memmove:
68fe6060f1SDimitry Andric     case LibFunc_bzero:
69fe6060f1SDimitry Andric     case LibFunc_bcopy:
70fe6060f1SDimitry Andric       return true;
71fe6060f1SDimitry Andric     default:
72fe6060f1SDimitry Andric       return false;
73fe6060f1SDimitry Andric     }
74fe6060f1SDimitry Andric   }
75fe6060f1SDimitry Andric 
76fe6060f1SDimitry Andric   return false;
77fe6060f1SDimitry Andric }
78fe6060f1SDimitry Andric 
79fe6060f1SDimitry Andric void MemoryOpRemark::visit(const Instruction *I) {
80fe6060f1SDimitry Andric   // For some of them, we can provide more information:
81fe6060f1SDimitry Andric 
82fe6060f1SDimitry Andric   // For stores:
83fe6060f1SDimitry Andric   // * size
84fe6060f1SDimitry Andric   // * volatile / atomic
85fe6060f1SDimitry Andric   if (auto *SI = dyn_cast<StoreInst>(I)) {
86fe6060f1SDimitry Andric     visitStore(*SI);
87fe6060f1SDimitry Andric     return;
88fe6060f1SDimitry Andric   }
89fe6060f1SDimitry Andric 
90fe6060f1SDimitry Andric   // For intrinsics:
91fe6060f1SDimitry Andric   // * user-friendly name
92fe6060f1SDimitry Andric   // * size
93fe6060f1SDimitry Andric   if (auto *II = dyn_cast<IntrinsicInst>(I)) {
94fe6060f1SDimitry Andric     visitIntrinsicCall(*II);
95fe6060f1SDimitry Andric     return;
96fe6060f1SDimitry Andric   }
97fe6060f1SDimitry Andric 
98fe6060f1SDimitry Andric   // For calls:
99fe6060f1SDimitry Andric   // * known/unknown function (e.g. the compiler knows bzero, but it doesn't
100fe6060f1SDimitry Andric   //                                know my_bzero)
101fe6060f1SDimitry Andric   // * memory operation size
102fe6060f1SDimitry Andric   if (auto *CI = dyn_cast<CallInst>(I)) {
103fe6060f1SDimitry Andric     visitCall(*CI);
104fe6060f1SDimitry Andric     return;
105fe6060f1SDimitry Andric   }
106fe6060f1SDimitry Andric 
107fe6060f1SDimitry Andric   visitUnknown(*I);
108fe6060f1SDimitry Andric }
109fe6060f1SDimitry Andric 
110fe6060f1SDimitry Andric std::string MemoryOpRemark::explainSource(StringRef Type) const {
111fe6060f1SDimitry Andric   return (Type + ".").str();
112fe6060f1SDimitry Andric }
113fe6060f1SDimitry Andric 
114fe6060f1SDimitry Andric StringRef MemoryOpRemark::remarkName(RemarkKind RK) const {
115fe6060f1SDimitry Andric   switch (RK) {
116fe6060f1SDimitry Andric   case RK_Store:
117fe6060f1SDimitry Andric     return "MemoryOpStore";
118fe6060f1SDimitry Andric   case RK_Unknown:
119fe6060f1SDimitry Andric     return "MemoryOpUnknown";
120fe6060f1SDimitry Andric   case RK_IntrinsicCall:
121fe6060f1SDimitry Andric     return "MemoryOpIntrinsicCall";
122fe6060f1SDimitry Andric   case RK_Call:
123fe6060f1SDimitry Andric     return "MemoryOpCall";
124fe6060f1SDimitry Andric   }
125fe6060f1SDimitry Andric   llvm_unreachable("missing RemarkKind case");
126fe6060f1SDimitry Andric }
127fe6060f1SDimitry Andric 
128fe6060f1SDimitry Andric static void inlineVolatileOrAtomicWithExtraArgs(bool *Inline, bool Volatile,
129fe6060f1SDimitry Andric                                                 bool Atomic,
130fe6060f1SDimitry Andric                                                 DiagnosticInfoIROptimization &R) {
131fe6060f1SDimitry Andric   if (Inline && *Inline)
132fe6060f1SDimitry Andric     R << " Inlined: " << NV("StoreInlined", true) << ".";
133fe6060f1SDimitry Andric   if (Volatile)
134fe6060f1SDimitry Andric     R << " Volatile: " << NV("StoreVolatile", true) << ".";
135fe6060f1SDimitry Andric   if (Atomic)
136fe6060f1SDimitry Andric     R << " Atomic: " << NV("StoreAtomic", true) << ".";
137fe6060f1SDimitry Andric   // Emit the false cases under ExtraArgs. This won't show them in the remark
138fe6060f1SDimitry Andric   // message but will end up in the serialized remarks.
139fe6060f1SDimitry Andric   if ((Inline && !*Inline) || !Volatile || !Atomic)
140fe6060f1SDimitry Andric     R << setExtraArgs();
141fe6060f1SDimitry Andric   if (Inline && !*Inline)
142fe6060f1SDimitry Andric     R << " Inlined: " << NV("StoreInlined", false) << ".";
143fe6060f1SDimitry Andric   if (!Volatile)
144fe6060f1SDimitry Andric     R << " Volatile: " << NV("StoreVolatile", false) << ".";
145fe6060f1SDimitry Andric   if (!Atomic)
146fe6060f1SDimitry Andric     R << " Atomic: " << NV("StoreAtomic", false) << ".";
147fe6060f1SDimitry Andric }
148fe6060f1SDimitry Andric 
149bdd1243dSDimitry Andric static std::optional<uint64_t>
150bdd1243dSDimitry Andric getSizeInBytes(std::optional<uint64_t> SizeInBits) {
151fe6060f1SDimitry Andric   if (!SizeInBits || *SizeInBits % 8 != 0)
152bdd1243dSDimitry Andric     return std::nullopt;
153fe6060f1SDimitry Andric   return *SizeInBits / 8;
154fe6060f1SDimitry Andric }
155fe6060f1SDimitry Andric 
156fe6060f1SDimitry Andric template<typename ...Ts>
157fe6060f1SDimitry Andric std::unique_ptr<DiagnosticInfoIROptimization>
158fe6060f1SDimitry Andric MemoryOpRemark::makeRemark(Ts... Args) {
159fe6060f1SDimitry Andric   switch (diagnosticKind()) {
160fe6060f1SDimitry Andric   case DK_OptimizationRemarkAnalysis:
161fe6060f1SDimitry Andric     return std::make_unique<OptimizationRemarkAnalysis>(Args...);
162fe6060f1SDimitry Andric   case DK_OptimizationRemarkMissed:
163fe6060f1SDimitry Andric     return std::make_unique<OptimizationRemarkMissed>(Args...);
164fe6060f1SDimitry Andric   default:
165fe6060f1SDimitry Andric     llvm_unreachable("unexpected DiagnosticKind");
166fe6060f1SDimitry Andric   }
167fe6060f1SDimitry Andric }
168fe6060f1SDimitry Andric 
169fe6060f1SDimitry Andric void MemoryOpRemark::visitStore(const StoreInst &SI) {
170fe6060f1SDimitry Andric   bool Volatile = SI.isVolatile();
171fe6060f1SDimitry Andric   bool Atomic = SI.isAtomic();
172fe6060f1SDimitry Andric   int64_t Size = DL.getTypeStoreSize(SI.getOperand(0)->getType());
173fe6060f1SDimitry Andric 
174fe6060f1SDimitry Andric   auto R = makeRemark(RemarkPass.data(), remarkName(RK_Store), &SI);
175fe6060f1SDimitry Andric   *R << explainSource("Store") << "\nStore size: " << NV("StoreSize", Size)
176fe6060f1SDimitry Andric      << " bytes.";
177fe6060f1SDimitry Andric   visitPtr(SI.getOperand(1), /*IsRead=*/false, *R);
178fe6060f1SDimitry Andric   inlineVolatileOrAtomicWithExtraArgs(nullptr, Volatile, Atomic, *R);
179fe6060f1SDimitry Andric   ORE.emit(*R);
180fe6060f1SDimitry Andric }
181fe6060f1SDimitry Andric 
182fe6060f1SDimitry Andric void MemoryOpRemark::visitUnknown(const Instruction &I) {
183fe6060f1SDimitry Andric   auto R = makeRemark(RemarkPass.data(), remarkName(RK_Unknown), &I);
184fe6060f1SDimitry Andric   *R << explainSource("Initialization");
185fe6060f1SDimitry Andric   ORE.emit(*R);
186fe6060f1SDimitry Andric }
187fe6060f1SDimitry Andric 
188fe6060f1SDimitry Andric void MemoryOpRemark::visitIntrinsicCall(const IntrinsicInst &II) {
189fe6060f1SDimitry Andric   SmallString<32> CallTo;
190fe6060f1SDimitry Andric   bool Atomic = false;
191fe6060f1SDimitry Andric   bool Inline = false;
192fe6060f1SDimitry Andric   switch (II.getIntrinsicID()) {
193fe6060f1SDimitry Andric   case Intrinsic::memcpy_inline:
194fe6060f1SDimitry Andric     CallTo = "memcpy";
195fe6060f1SDimitry Andric     Inline = true;
196fe6060f1SDimitry Andric     break;
197fe6060f1SDimitry Andric   case Intrinsic::memcpy:
198fe6060f1SDimitry Andric     CallTo = "memcpy";
199fe6060f1SDimitry Andric     break;
200fe6060f1SDimitry Andric   case Intrinsic::memmove:
201fe6060f1SDimitry Andric     CallTo = "memmove";
202fe6060f1SDimitry Andric     break;
203fe6060f1SDimitry Andric   case Intrinsic::memset:
204fe6060f1SDimitry Andric     CallTo = "memset";
205fe6060f1SDimitry Andric     break;
206fe6060f1SDimitry Andric   case Intrinsic::memcpy_element_unordered_atomic:
207fe6060f1SDimitry Andric     CallTo = "memcpy";
208fe6060f1SDimitry Andric     Atomic = true;
209fe6060f1SDimitry Andric     break;
210fe6060f1SDimitry Andric   case Intrinsic::memmove_element_unordered_atomic:
211fe6060f1SDimitry Andric     CallTo = "memmove";
212fe6060f1SDimitry Andric     Atomic = true;
213fe6060f1SDimitry Andric     break;
214fe6060f1SDimitry Andric   case Intrinsic::memset_element_unordered_atomic:
215fe6060f1SDimitry Andric     CallTo = "memset";
216fe6060f1SDimitry Andric     Atomic = true;
217fe6060f1SDimitry Andric     break;
218fe6060f1SDimitry Andric   default:
219fe6060f1SDimitry Andric     return visitUnknown(II);
220fe6060f1SDimitry Andric   }
221fe6060f1SDimitry Andric 
222fe6060f1SDimitry Andric   auto R = makeRemark(RemarkPass.data(), remarkName(RK_IntrinsicCall), &II);
223fe6060f1SDimitry Andric   visitCallee(CallTo.str(), /*KnownLibCall=*/true, *R);
224fe6060f1SDimitry Andric   visitSizeOperand(II.getOperand(2), *R);
225fe6060f1SDimitry Andric 
226fe6060f1SDimitry Andric   auto *CIVolatile = dyn_cast<ConstantInt>(II.getOperand(3));
227fe6060f1SDimitry Andric   // No such thing as a memory intrinsic that is both atomic and volatile.
228fe6060f1SDimitry Andric   bool Volatile = !Atomic && CIVolatile && CIVolatile->getZExtValue();
229fe6060f1SDimitry Andric   switch (II.getIntrinsicID()) {
230fe6060f1SDimitry Andric   case Intrinsic::memcpy_inline:
231fe6060f1SDimitry Andric   case Intrinsic::memcpy:
232fe6060f1SDimitry Andric   case Intrinsic::memmove:
233fe6060f1SDimitry Andric   case Intrinsic::memcpy_element_unordered_atomic:
234fe6060f1SDimitry Andric     visitPtr(II.getOperand(1), /*IsRead=*/true, *R);
235fe6060f1SDimitry Andric     visitPtr(II.getOperand(0), /*IsRead=*/false, *R);
236fe6060f1SDimitry Andric     break;
237fe6060f1SDimitry Andric   case Intrinsic::memset:
238fe6060f1SDimitry Andric   case Intrinsic::memset_element_unordered_atomic:
239fe6060f1SDimitry Andric     visitPtr(II.getOperand(0), /*IsRead=*/false, *R);
240fe6060f1SDimitry Andric     break;
241fe6060f1SDimitry Andric   }
242fe6060f1SDimitry Andric   inlineVolatileOrAtomicWithExtraArgs(&Inline, Volatile, Atomic, *R);
243fe6060f1SDimitry Andric   ORE.emit(*R);
244fe6060f1SDimitry Andric }
245fe6060f1SDimitry Andric 
246fe6060f1SDimitry Andric void MemoryOpRemark::visitCall(const CallInst &CI) {
247fe6060f1SDimitry Andric   Function *F = CI.getCalledFunction();
248fe6060f1SDimitry Andric   if (!F)
249fe6060f1SDimitry Andric     return visitUnknown(CI);
250fe6060f1SDimitry Andric 
251fe6060f1SDimitry Andric   LibFunc LF;
252fe6060f1SDimitry Andric   bool KnownLibCall = TLI.getLibFunc(*F, LF) && TLI.has(LF);
253fe6060f1SDimitry Andric   auto R = makeRemark(RemarkPass.data(), remarkName(RK_Call), &CI);
254fe6060f1SDimitry Andric   visitCallee(F, KnownLibCall, *R);
255fe6060f1SDimitry Andric   visitKnownLibCall(CI, LF, *R);
256fe6060f1SDimitry Andric   ORE.emit(*R);
257fe6060f1SDimitry Andric }
258fe6060f1SDimitry Andric 
259fe6060f1SDimitry Andric template <typename FTy>
260fe6060f1SDimitry Andric void MemoryOpRemark::visitCallee(FTy F, bool KnownLibCall,
261fe6060f1SDimitry Andric                                  DiagnosticInfoIROptimization &R) {
262fe6060f1SDimitry Andric   R << "Call to ";
263fe6060f1SDimitry Andric   if (!KnownLibCall)
264fe6060f1SDimitry Andric     R << NV("UnknownLibCall", "unknown") << " function ";
265fe6060f1SDimitry Andric   R << NV("Callee", F) << explainSource("");
266fe6060f1SDimitry Andric }
267fe6060f1SDimitry Andric 
268fe6060f1SDimitry Andric void MemoryOpRemark::visitKnownLibCall(const CallInst &CI, LibFunc LF,
269fe6060f1SDimitry Andric                                        DiagnosticInfoIROptimization &R) {
270fe6060f1SDimitry Andric   switch (LF) {
271fe6060f1SDimitry Andric   default:
272fe6060f1SDimitry Andric     return;
273fe6060f1SDimitry Andric   case LibFunc_memset_chk:
274fe6060f1SDimitry Andric   case LibFunc_memset:
275fe6060f1SDimitry Andric     visitSizeOperand(CI.getOperand(2), R);
276fe6060f1SDimitry Andric     visitPtr(CI.getOperand(0), /*IsRead=*/false, R);
277fe6060f1SDimitry Andric     break;
278fe6060f1SDimitry Andric   case LibFunc_bzero:
279fe6060f1SDimitry Andric     visitSizeOperand(CI.getOperand(1), R);
280fe6060f1SDimitry Andric     visitPtr(CI.getOperand(0), /*IsRead=*/false, R);
281fe6060f1SDimitry Andric     break;
282fe6060f1SDimitry Andric   case LibFunc_memcpy_chk:
283fe6060f1SDimitry Andric   case LibFunc_mempcpy_chk:
284fe6060f1SDimitry Andric   case LibFunc_memmove_chk:
285fe6060f1SDimitry Andric   case LibFunc_memcpy:
286fe6060f1SDimitry Andric   case LibFunc_mempcpy:
287fe6060f1SDimitry Andric   case LibFunc_memmove:
288fe6060f1SDimitry Andric   case LibFunc_bcopy:
289fe6060f1SDimitry Andric     visitSizeOperand(CI.getOperand(2), R);
290fe6060f1SDimitry Andric     visitPtr(CI.getOperand(1), /*IsRead=*/true, R);
291fe6060f1SDimitry Andric     visitPtr(CI.getOperand(0), /*IsRead=*/false, R);
292fe6060f1SDimitry Andric     break;
293fe6060f1SDimitry Andric   }
294fe6060f1SDimitry Andric }
295fe6060f1SDimitry Andric 
296fe6060f1SDimitry Andric void MemoryOpRemark::visitSizeOperand(Value *V, DiagnosticInfoIROptimization &R) {
297fe6060f1SDimitry Andric   if (auto *Len = dyn_cast<ConstantInt>(V)) {
298fe6060f1SDimitry Andric     uint64_t Size = Len->getZExtValue();
299fe6060f1SDimitry Andric     R << " Memory operation size: " << NV("StoreSize", Size) << " bytes.";
300fe6060f1SDimitry Andric   }
301fe6060f1SDimitry Andric }
302fe6060f1SDimitry Andric 
303bdd1243dSDimitry Andric static std::optional<StringRef> nameOrNone(const Value *V) {
304fe6060f1SDimitry Andric   if (V->hasName())
305fe6060f1SDimitry Andric     return V->getName();
306bdd1243dSDimitry Andric   return std::nullopt;
307fe6060f1SDimitry Andric }
308fe6060f1SDimitry Andric 
309fe6060f1SDimitry Andric void MemoryOpRemark::visitVariable(const Value *V,
310fe6060f1SDimitry Andric                                    SmallVectorImpl<VariableInfo> &Result) {
311fe6060f1SDimitry Andric   if (auto *GV = dyn_cast<GlobalVariable>(V)) {
312fe6060f1SDimitry Andric     auto *Ty = GV->getValueType();
313bdd1243dSDimitry Andric     uint64_t Size = DL.getTypeSizeInBits(Ty).getFixedValue();
314fe6060f1SDimitry Andric     VariableInfo Var{nameOrNone(GV), Size};
315fe6060f1SDimitry Andric     if (!Var.isEmpty())
316fe6060f1SDimitry Andric       Result.push_back(std::move(Var));
317fe6060f1SDimitry Andric     return;
318fe6060f1SDimitry Andric   }
319fe6060f1SDimitry Andric 
320fe6060f1SDimitry Andric   // If we find some information in the debug info, take that.
321fe6060f1SDimitry Andric   bool FoundDI = false;
322fe6060f1SDimitry Andric   // Try to get an llvm.dbg.declare, which has a DILocalVariable giving us the
323fe6060f1SDimitry Andric   // real debug info name and size of the variable.
3245f757f3fSDimitry Andric   auto FindDI = [&](const auto *DVI) {
325fe6060f1SDimitry Andric     if (DILocalVariable *DILV = DVI->getVariable()) {
326bdd1243dSDimitry Andric       std::optional<uint64_t> DISize = getSizeInBytes(DILV->getSizeInBits());
327fe6060f1SDimitry Andric       VariableInfo Var{DILV->getName(), DISize};
328fe6060f1SDimitry Andric       if (!Var.isEmpty()) {
329fe6060f1SDimitry Andric         Result.push_back(std::move(Var));
330fe6060f1SDimitry Andric         FoundDI = true;
331fe6060f1SDimitry Andric       }
332fe6060f1SDimitry Andric     }
3335f757f3fSDimitry Andric   };
3347a6dacacSDimitry Andric   for_each(findDbgDeclares(const_cast<Value *>(V)), FindDI);
335*0fca6ea1SDimitry Andric   for_each(findDVRDeclares(const_cast<Value *>(V)), FindDI);
3365f757f3fSDimitry Andric 
337fe6060f1SDimitry Andric   if (FoundDI) {
338fe6060f1SDimitry Andric     assert(!Result.empty());
339fe6060f1SDimitry Andric     return;
340fe6060f1SDimitry Andric   }
341fe6060f1SDimitry Andric 
342fe6060f1SDimitry Andric   const auto *AI = dyn_cast<AllocaInst>(V);
343fe6060f1SDimitry Andric   if (!AI)
344fe6060f1SDimitry Andric     return;
345fe6060f1SDimitry Andric 
346fe6060f1SDimitry Andric   // If not, get it from the alloca.
347bdd1243dSDimitry Andric   std::optional<TypeSize> TySize = AI->getAllocationSize(DL);
348bdd1243dSDimitry Andric   std::optional<uint64_t> Size =
349bdd1243dSDimitry Andric       TySize ? std::optional(TySize->getFixedValue()) : std::nullopt;
350fe6060f1SDimitry Andric   VariableInfo Var{nameOrNone(AI), Size};
351fe6060f1SDimitry Andric   if (!Var.isEmpty())
352fe6060f1SDimitry Andric     Result.push_back(std::move(Var));
353fe6060f1SDimitry Andric }
354fe6060f1SDimitry Andric 
355fe6060f1SDimitry Andric void MemoryOpRemark::visitPtr(Value *Ptr, bool IsRead, DiagnosticInfoIROptimization &R) {
356fe6060f1SDimitry Andric   // Find if Ptr is a known variable we can give more information on.
357fe6060f1SDimitry Andric   SmallVector<Value *, 2> Objects;
358fe6060f1SDimitry Andric   getUnderlyingObjectsForCodeGen(Ptr, Objects);
359fe6060f1SDimitry Andric   SmallVector<VariableInfo, 2> VIs;
360fe6060f1SDimitry Andric   for (const Value *V : Objects)
361fe6060f1SDimitry Andric     visitVariable(V, VIs);
362fe6060f1SDimitry Andric 
363fe6060f1SDimitry Andric   if (VIs.empty()) {
364fe6060f1SDimitry Andric     bool CanBeNull;
365fe6060f1SDimitry Andric     bool CanBeFreed;
366fe6060f1SDimitry Andric     uint64_t Size = Ptr->getPointerDereferenceableBytes(DL, CanBeNull, CanBeFreed);
367fe6060f1SDimitry Andric     if (!Size)
368fe6060f1SDimitry Andric       return;
369bdd1243dSDimitry Andric     VIs.push_back({std::nullopt, Size});
370fe6060f1SDimitry Andric   }
371fe6060f1SDimitry Andric 
372fe6060f1SDimitry Andric   R << (IsRead ? "\n Read Variables: " : "\n Written Variables: ");
373fe6060f1SDimitry Andric   for (unsigned i = 0; i < VIs.size(); ++i) {
374fe6060f1SDimitry Andric     const VariableInfo &VI = VIs[i];
375fe6060f1SDimitry Andric     assert(!VI.isEmpty() && "No extra content to display.");
376fe6060f1SDimitry Andric     if (i != 0)
377fe6060f1SDimitry Andric       R << ", ";
378fe6060f1SDimitry Andric     if (VI.Name)
379fe6060f1SDimitry Andric       R << NV(IsRead ? "RVarName" : "WVarName", *VI.Name);
380fe6060f1SDimitry Andric     else
381fe6060f1SDimitry Andric       R << NV(IsRead ? "RVarName" : "WVarName", "<unknown>");
382fe6060f1SDimitry Andric     if (VI.Size)
383fe6060f1SDimitry Andric       R << " (" << NV(IsRead ? "RVarSize" : "WVarSize", *VI.Size) << " bytes)";
384fe6060f1SDimitry Andric   }
385fe6060f1SDimitry Andric   R << ".";
386fe6060f1SDimitry Andric }
387fe6060f1SDimitry Andric 
388fe6060f1SDimitry Andric bool AutoInitRemark::canHandle(const Instruction *I) {
389fe6060f1SDimitry Andric   if (!I->hasMetadata(LLVMContext::MD_annotation))
390fe6060f1SDimitry Andric     return false;
391fe6060f1SDimitry Andric   return any_of(I->getMetadata(LLVMContext::MD_annotation)->operands(),
392fe6060f1SDimitry Andric                 [](const MDOperand &Op) {
39306c3fb27SDimitry Andric                   return isa<MDString>(Op.get()) &&
39406c3fb27SDimitry Andric                          cast<MDString>(Op.get())->getString() == "auto-init";
395fe6060f1SDimitry Andric                 });
396fe6060f1SDimitry Andric }
397fe6060f1SDimitry Andric 
398fe6060f1SDimitry Andric std::string AutoInitRemark::explainSource(StringRef Type) const {
399fe6060f1SDimitry Andric   return (Type + " inserted by -ftrivial-auto-var-init.").str();
400fe6060f1SDimitry Andric }
401fe6060f1SDimitry Andric 
402fe6060f1SDimitry Andric StringRef AutoInitRemark::remarkName(RemarkKind RK) const {
403fe6060f1SDimitry Andric   switch (RK) {
404fe6060f1SDimitry Andric   case RK_Store:
405fe6060f1SDimitry Andric     return "AutoInitStore";
406fe6060f1SDimitry Andric   case RK_Unknown:
407fe6060f1SDimitry Andric     return "AutoInitUnknownInstruction";
408fe6060f1SDimitry Andric   case RK_IntrinsicCall:
409fe6060f1SDimitry Andric     return "AutoInitIntrinsicCall";
410fe6060f1SDimitry Andric   case RK_Call:
411fe6060f1SDimitry Andric     return "AutoInitCall";
412fe6060f1SDimitry Andric   }
413fe6060f1SDimitry Andric   llvm_unreachable("missing RemarkKind case");
414fe6060f1SDimitry Andric }
415