xref: /llvm-project/llvm/lib/Transforms/Utils/MemoryOpRemark.cpp (revision ffd08c7759000f55332f1657a1fab64a7adc03fd)
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"
1439d8e6e2SElliot Goodrich #include "llvm/ADT/SmallString.h"
15095e91c9SJon Roelofs #include "llvm/Analysis/OptimizationRemarkEmitter.h"
16095e91c9SJon Roelofs #include "llvm/Analysis/ValueTracking.h"
17095e91c9SJon Roelofs #include "llvm/IR/DebugInfo.h"
18095e91c9SJon Roelofs #include "llvm/IR/Instructions.h"
19095e91c9SJon Roelofs #include "llvm/IR/IntrinsicInst.h"
200ca43d44SKrzysztof Parzyszek #include <optional>
21095e91c9SJon Roelofs 
22095e91c9SJon Roelofs using namespace llvm;
23095e91c9SJon Roelofs using namespace llvm::ore;
24095e91c9SJon Roelofs 
25095e91c9SJon Roelofs MemoryOpRemark::~MemoryOpRemark() = default;
26095e91c9SJon Roelofs 
canHandle(const Instruction * I,const TargetLibraryInfo & TLI)27095e91c9SJon Roelofs bool MemoryOpRemark::canHandle(const Instruction *I, const TargetLibraryInfo &TLI) {
28095e91c9SJon Roelofs   if (isa<StoreInst>(I))
29095e91c9SJon Roelofs     return true;
30095e91c9SJon Roelofs 
31095e91c9SJon Roelofs   if (auto *II = dyn_cast<IntrinsicInst>(I)) {
32095e91c9SJon Roelofs     switch (II->getIntrinsicID()) {
33095e91c9SJon Roelofs     case Intrinsic::memcpy_inline:
34095e91c9SJon Roelofs     case Intrinsic::memcpy:
35095e91c9SJon Roelofs     case Intrinsic::memmove:
36095e91c9SJon Roelofs     case Intrinsic::memset:
37095e91c9SJon Roelofs     case Intrinsic::memcpy_element_unordered_atomic:
38095e91c9SJon Roelofs     case Intrinsic::memmove_element_unordered_atomic:
39095e91c9SJon Roelofs     case Intrinsic::memset_element_unordered_atomic:
40095e91c9SJon Roelofs       return true;
41095e91c9SJon Roelofs     default:
42095e91c9SJon Roelofs       return false;
43095e91c9SJon Roelofs     }
44095e91c9SJon Roelofs   }
45095e91c9SJon Roelofs 
46095e91c9SJon Roelofs   if (auto *CI = dyn_cast<CallInst>(I)) {
47095e91c9SJon Roelofs     auto *CF = CI->getCalledFunction();
48095e91c9SJon Roelofs     if (!CF)
49095e91c9SJon Roelofs       return false;
50095e91c9SJon Roelofs 
51095e91c9SJon Roelofs     if (!CF->hasName())
52095e91c9SJon Roelofs       return false;
53095e91c9SJon Roelofs 
54095e91c9SJon Roelofs     LibFunc LF;
55095e91c9SJon Roelofs     bool KnownLibCall = TLI.getLibFunc(*CF, LF) && TLI.has(LF);
56095e91c9SJon Roelofs     if (!KnownLibCall)
57095e91c9SJon Roelofs       return false;
58095e91c9SJon Roelofs 
59095e91c9SJon Roelofs     switch (LF) {
60095e91c9SJon Roelofs     case LibFunc_memcpy_chk:
61095e91c9SJon Roelofs     case LibFunc_mempcpy_chk:
62095e91c9SJon Roelofs     case LibFunc_memset_chk:
63095e91c9SJon Roelofs     case LibFunc_memmove_chk:
64095e91c9SJon Roelofs     case LibFunc_memcpy:
65095e91c9SJon Roelofs     case LibFunc_mempcpy:
66095e91c9SJon Roelofs     case LibFunc_memset:
67095e91c9SJon Roelofs     case LibFunc_memmove:
68095e91c9SJon Roelofs     case LibFunc_bzero:
69095e91c9SJon Roelofs     case LibFunc_bcopy:
70095e91c9SJon Roelofs       return true;
71095e91c9SJon Roelofs     default:
72095e91c9SJon Roelofs       return false;
73095e91c9SJon Roelofs     }
74095e91c9SJon Roelofs   }
75095e91c9SJon Roelofs 
76095e91c9SJon Roelofs   return false;
77095e91c9SJon Roelofs }
78095e91c9SJon Roelofs 
visit(const Instruction * I)79095e91c9SJon Roelofs void MemoryOpRemark::visit(const Instruction *I) {
80095e91c9SJon Roelofs   // For some of them, we can provide more information:
81095e91c9SJon Roelofs 
82095e91c9SJon Roelofs   // For stores:
83095e91c9SJon Roelofs   // * size
84095e91c9SJon Roelofs   // * volatile / atomic
85095e91c9SJon Roelofs   if (auto *SI = dyn_cast<StoreInst>(I)) {
86095e91c9SJon Roelofs     visitStore(*SI);
87095e91c9SJon Roelofs     return;
88095e91c9SJon Roelofs   }
89095e91c9SJon Roelofs 
90095e91c9SJon Roelofs   // For intrinsics:
91095e91c9SJon Roelofs   // * user-friendly name
92095e91c9SJon Roelofs   // * size
93095e91c9SJon Roelofs   if (auto *II = dyn_cast<IntrinsicInst>(I)) {
94095e91c9SJon Roelofs     visitIntrinsicCall(*II);
95095e91c9SJon Roelofs     return;
96095e91c9SJon Roelofs   }
97095e91c9SJon Roelofs 
98095e91c9SJon Roelofs   // For calls:
99095e91c9SJon Roelofs   // * known/unknown function (e.g. the compiler knows bzero, but it doesn't
100095e91c9SJon Roelofs   //                                know my_bzero)
101095e91c9SJon Roelofs   // * memory operation size
102095e91c9SJon Roelofs   if (auto *CI = dyn_cast<CallInst>(I)) {
103095e91c9SJon Roelofs     visitCall(*CI);
104095e91c9SJon Roelofs     return;
105095e91c9SJon Roelofs   }
106095e91c9SJon Roelofs 
107095e91c9SJon Roelofs   visitUnknown(*I);
108095e91c9SJon Roelofs }
109095e91c9SJon Roelofs 
explainSource(StringRef Type) const110493d6928SJon Roelofs std::string MemoryOpRemark::explainSource(StringRef Type) const {
111095e91c9SJon Roelofs   return (Type + ".").str();
112095e91c9SJon Roelofs }
113095e91c9SJon Roelofs 
remarkName(RemarkKind RK) const114493d6928SJon Roelofs StringRef MemoryOpRemark::remarkName(RemarkKind RK) const {
115095e91c9SJon Roelofs   switch (RK) {
116095e91c9SJon Roelofs   case RK_Store:
117095e91c9SJon Roelofs     return "MemoryOpStore";
118095e91c9SJon Roelofs   case RK_Unknown:
119095e91c9SJon Roelofs     return "MemoryOpUnknown";
120095e91c9SJon Roelofs   case RK_IntrinsicCall:
121095e91c9SJon Roelofs     return "MemoryOpIntrinsicCall";
122095e91c9SJon Roelofs   case RK_Call:
123095e91c9SJon Roelofs     return "MemoryOpCall";
124095e91c9SJon Roelofs   }
125095e91c9SJon Roelofs   llvm_unreachable("missing RemarkKind case");
126095e91c9SJon Roelofs }
127095e91c9SJon Roelofs 
inlineVolatileOrAtomicWithExtraArgs(bool * Inline,bool Volatile,bool Atomic,DiagnosticInfoIROptimization & R)128095e91c9SJon Roelofs static void inlineVolatileOrAtomicWithExtraArgs(bool *Inline, bool Volatile,
129095e91c9SJon Roelofs                                                 bool Atomic,
130493d6928SJon Roelofs                                                 DiagnosticInfoIROptimization &R) {
131095e91c9SJon Roelofs   if (Inline && *Inline)
132095e91c9SJon Roelofs     R << " Inlined: " << NV("StoreInlined", true) << ".";
133095e91c9SJon Roelofs   if (Volatile)
134095e91c9SJon Roelofs     R << " Volatile: " << NV("StoreVolatile", true) << ".";
135095e91c9SJon Roelofs   if (Atomic)
136095e91c9SJon Roelofs     R << " Atomic: " << NV("StoreAtomic", true) << ".";
137095e91c9SJon Roelofs   // Emit the false cases under ExtraArgs. This won't show them in the remark
138095e91c9SJon Roelofs   // message but will end up in the serialized remarks.
139095e91c9SJon Roelofs   if ((Inline && !*Inline) || !Volatile || !Atomic)
140095e91c9SJon Roelofs     R << setExtraArgs();
141095e91c9SJon Roelofs   if (Inline && !*Inline)
142095e91c9SJon Roelofs     R << " Inlined: " << NV("StoreInlined", false) << ".";
143095e91c9SJon Roelofs   if (!Volatile)
144095e91c9SJon Roelofs     R << " Volatile: " << NV("StoreVolatile", false) << ".";
145095e91c9SJon Roelofs   if (!Atomic)
146095e91c9SJon Roelofs     R << " Atomic: " << NV("StoreAtomic", false) << ".";
147095e91c9SJon Roelofs }
148095e91c9SJon Roelofs 
1490ca43d44SKrzysztof Parzyszek static std::optional<uint64_t>
getSizeInBytes(std::optional<uint64_t> SizeInBits)1500ca43d44SKrzysztof Parzyszek getSizeInBytes(std::optional<uint64_t> SizeInBits) {
151095e91c9SJon Roelofs   if (!SizeInBits || *SizeInBits % 8 != 0)
152343de685SKazu Hirata     return std::nullopt;
153095e91c9SJon Roelofs   return *SizeInBits / 8;
154095e91c9SJon Roelofs }
155095e91c9SJon Roelofs 
156493d6928SJon Roelofs template<typename ...Ts>
157493d6928SJon Roelofs std::unique_ptr<DiagnosticInfoIROptimization>
makeRemark(Ts...Args)158493d6928SJon Roelofs MemoryOpRemark::makeRemark(Ts... Args) {
159493d6928SJon Roelofs   switch (diagnosticKind()) {
160493d6928SJon Roelofs   case DK_OptimizationRemarkAnalysis:
161493d6928SJon Roelofs     return std::make_unique<OptimizationRemarkAnalysis>(Args...);
162493d6928SJon Roelofs   case DK_OptimizationRemarkMissed:
163493d6928SJon Roelofs     return std::make_unique<OptimizationRemarkMissed>(Args...);
164493d6928SJon Roelofs   default:
165493d6928SJon Roelofs     llvm_unreachable("unexpected DiagnosticKind");
166493d6928SJon Roelofs   }
167493d6928SJon Roelofs }
168493d6928SJon Roelofs 
visitStore(const StoreInst & SI)169095e91c9SJon Roelofs void MemoryOpRemark::visitStore(const StoreInst &SI) {
170095e91c9SJon Roelofs   bool Volatile = SI.isVolatile();
171095e91c9SJon Roelofs   bool Atomic = SI.isAtomic();
172095e91c9SJon Roelofs   int64_t Size = DL.getTypeStoreSize(SI.getOperand(0)->getType());
173095e91c9SJon Roelofs 
174493d6928SJon Roelofs   auto R = makeRemark(RemarkPass.data(), remarkName(RK_Store), &SI);
175493d6928SJon Roelofs   *R << explainSource("Store") << "\nStore size: " << NV("StoreSize", Size)
176095e91c9SJon Roelofs      << " bytes.";
177493d6928SJon Roelofs   visitPtr(SI.getOperand(1), /*IsRead=*/false, *R);
178493d6928SJon Roelofs   inlineVolatileOrAtomicWithExtraArgs(nullptr, Volatile, Atomic, *R);
179493d6928SJon Roelofs   ORE.emit(*R);
180095e91c9SJon Roelofs }
181095e91c9SJon Roelofs 
visitUnknown(const Instruction & I)182095e91c9SJon Roelofs void MemoryOpRemark::visitUnknown(const Instruction &I) {
183493d6928SJon Roelofs   auto R = makeRemark(RemarkPass.data(), remarkName(RK_Unknown), &I);
184493d6928SJon Roelofs   *R << explainSource("Initialization");
185493d6928SJon Roelofs   ORE.emit(*R);
186095e91c9SJon Roelofs }
187095e91c9SJon Roelofs 
visitIntrinsicCall(const IntrinsicInst & II)188095e91c9SJon Roelofs void MemoryOpRemark::visitIntrinsicCall(const IntrinsicInst &II) {
189095e91c9SJon Roelofs   SmallString<32> CallTo;
190095e91c9SJon Roelofs   bool Atomic = false;
191095e91c9SJon Roelofs   bool Inline = false;
192095e91c9SJon Roelofs   switch (II.getIntrinsicID()) {
193095e91c9SJon Roelofs   case Intrinsic::memcpy_inline:
194095e91c9SJon Roelofs     CallTo = "memcpy";
195095e91c9SJon Roelofs     Inline = true;
196095e91c9SJon Roelofs     break;
197095e91c9SJon Roelofs   case Intrinsic::memcpy:
198095e91c9SJon Roelofs     CallTo = "memcpy";
199095e91c9SJon Roelofs     break;
200095e91c9SJon Roelofs   case Intrinsic::memmove:
201095e91c9SJon Roelofs     CallTo = "memmove";
202095e91c9SJon Roelofs     break;
203095e91c9SJon Roelofs   case Intrinsic::memset:
204095e91c9SJon Roelofs     CallTo = "memset";
205095e91c9SJon Roelofs     break;
206095e91c9SJon Roelofs   case Intrinsic::memcpy_element_unordered_atomic:
207095e91c9SJon Roelofs     CallTo = "memcpy";
208095e91c9SJon Roelofs     Atomic = true;
209095e91c9SJon Roelofs     break;
210095e91c9SJon Roelofs   case Intrinsic::memmove_element_unordered_atomic:
211095e91c9SJon Roelofs     CallTo = "memmove";
212095e91c9SJon Roelofs     Atomic = true;
213095e91c9SJon Roelofs     break;
214095e91c9SJon Roelofs   case Intrinsic::memset_element_unordered_atomic:
215095e91c9SJon Roelofs     CallTo = "memset";
216095e91c9SJon Roelofs     Atomic = true;
217095e91c9SJon Roelofs     break;
218095e91c9SJon Roelofs   default:
219095e91c9SJon Roelofs     return visitUnknown(II);
220095e91c9SJon Roelofs   }
221095e91c9SJon Roelofs 
222493d6928SJon Roelofs   auto R = makeRemark(RemarkPass.data(), remarkName(RK_IntrinsicCall), &II);
2231def2579SDavid Blaikie   visitCallee(CallTo.str(), /*KnownLibCall=*/true, *R);
224493d6928SJon Roelofs   visitSizeOperand(II.getOperand(2), *R);
225095e91c9SJon Roelofs 
226095e91c9SJon Roelofs   auto *CIVolatile = dyn_cast<ConstantInt>(II.getOperand(3));
227095e91c9SJon Roelofs   // No such thing as a memory intrinsic that is both atomic and volatile.
228095e91c9SJon Roelofs   bool Volatile = !Atomic && CIVolatile && CIVolatile->getZExtValue();
229095e91c9SJon Roelofs   switch (II.getIntrinsicID()) {
230095e91c9SJon Roelofs   case Intrinsic::memcpy_inline:
231095e91c9SJon Roelofs   case Intrinsic::memcpy:
232095e91c9SJon Roelofs   case Intrinsic::memmove:
233095e91c9SJon Roelofs   case Intrinsic::memcpy_element_unordered_atomic:
234493d6928SJon Roelofs     visitPtr(II.getOperand(1), /*IsRead=*/true, *R);
235493d6928SJon Roelofs     visitPtr(II.getOperand(0), /*IsRead=*/false, *R);
236095e91c9SJon Roelofs     break;
237095e91c9SJon Roelofs   case Intrinsic::memset:
238095e91c9SJon Roelofs   case Intrinsic::memset_element_unordered_atomic:
239493d6928SJon Roelofs     visitPtr(II.getOperand(0), /*IsRead=*/false, *R);
240095e91c9SJon Roelofs     break;
241095e91c9SJon Roelofs   }
242493d6928SJon Roelofs   inlineVolatileOrAtomicWithExtraArgs(&Inline, Volatile, Atomic, *R);
243493d6928SJon Roelofs   ORE.emit(*R);
244095e91c9SJon Roelofs }
245095e91c9SJon Roelofs 
visitCall(const CallInst & CI)246095e91c9SJon Roelofs void MemoryOpRemark::visitCall(const CallInst &CI) {
247095e91c9SJon Roelofs   Function *F = CI.getCalledFunction();
248095e91c9SJon Roelofs   if (!F)
249095e91c9SJon Roelofs     return visitUnknown(CI);
250095e91c9SJon Roelofs 
251095e91c9SJon Roelofs   LibFunc LF;
252095e91c9SJon Roelofs   bool KnownLibCall = TLI.getLibFunc(*F, LF) && TLI.has(LF);
253493d6928SJon Roelofs   auto R = makeRemark(RemarkPass.data(), remarkName(RK_Call), &CI);
254493d6928SJon Roelofs   visitCallee(F, KnownLibCall, *R);
255493d6928SJon Roelofs   visitKnownLibCall(CI, LF, *R);
256493d6928SJon Roelofs   ORE.emit(*R);
257095e91c9SJon Roelofs }
258095e91c9SJon Roelofs 
259095e91c9SJon Roelofs template <typename FTy>
visitCallee(FTy F,bool KnownLibCall,DiagnosticInfoIROptimization & R)260095e91c9SJon Roelofs void MemoryOpRemark::visitCallee(FTy F, bool KnownLibCall,
261493d6928SJon Roelofs                                  DiagnosticInfoIROptimization &R) {
262095e91c9SJon Roelofs   R << "Call to ";
263095e91c9SJon Roelofs   if (!KnownLibCall)
264095e91c9SJon Roelofs     R << NV("UnknownLibCall", "unknown") << " function ";
265095e91c9SJon Roelofs   R << NV("Callee", F) << explainSource("");
266095e91c9SJon Roelofs }
267095e91c9SJon Roelofs 
visitKnownLibCall(const CallInst & CI,LibFunc LF,DiagnosticInfoIROptimization & R)268095e91c9SJon Roelofs void MemoryOpRemark::visitKnownLibCall(const CallInst &CI, LibFunc LF,
269493d6928SJon Roelofs                                        DiagnosticInfoIROptimization &R) {
270095e91c9SJon Roelofs   switch (LF) {
271095e91c9SJon Roelofs   default:
272095e91c9SJon Roelofs     return;
273095e91c9SJon Roelofs   case LibFunc_memset_chk:
274095e91c9SJon Roelofs   case LibFunc_memset:
275095e91c9SJon Roelofs     visitSizeOperand(CI.getOperand(2), R);
276095e91c9SJon Roelofs     visitPtr(CI.getOperand(0), /*IsRead=*/false, R);
277095e91c9SJon Roelofs     break;
278095e91c9SJon Roelofs   case LibFunc_bzero:
279095e91c9SJon Roelofs     visitSizeOperand(CI.getOperand(1), R);
280095e91c9SJon Roelofs     visitPtr(CI.getOperand(0), /*IsRead=*/false, R);
281095e91c9SJon Roelofs     break;
282095e91c9SJon Roelofs   case LibFunc_memcpy_chk:
283095e91c9SJon Roelofs   case LibFunc_mempcpy_chk:
284095e91c9SJon Roelofs   case LibFunc_memmove_chk:
285095e91c9SJon Roelofs   case LibFunc_memcpy:
286095e91c9SJon Roelofs   case LibFunc_mempcpy:
287095e91c9SJon Roelofs   case LibFunc_memmove:
288095e91c9SJon Roelofs   case LibFunc_bcopy:
289095e91c9SJon Roelofs     visitSizeOperand(CI.getOperand(2), R);
290095e91c9SJon Roelofs     visitPtr(CI.getOperand(1), /*IsRead=*/true, R);
291095e91c9SJon Roelofs     visitPtr(CI.getOperand(0), /*IsRead=*/false, R);
292095e91c9SJon Roelofs     break;
293095e91c9SJon Roelofs   }
294095e91c9SJon Roelofs }
295095e91c9SJon Roelofs 
visitSizeOperand(Value * V,DiagnosticInfoIROptimization & R)296493d6928SJon Roelofs void MemoryOpRemark::visitSizeOperand(Value *V, DiagnosticInfoIROptimization &R) {
297095e91c9SJon Roelofs   if (auto *Len = dyn_cast<ConstantInt>(V)) {
298095e91c9SJon Roelofs     uint64_t Size = Len->getZExtValue();
299095e91c9SJon Roelofs     R << " Memory operation size: " << NV("StoreSize", Size) << " bytes.";
300095e91c9SJon Roelofs   }
301095e91c9SJon Roelofs }
302095e91c9SJon Roelofs 
nameOrNone(const Value * V)3030ca43d44SKrzysztof Parzyszek static std::optional<StringRef> nameOrNone(const Value *V) {
304f8f1c9c3SJon Roelofs   if (V->hasName())
305f8f1c9c3SJon Roelofs     return V->getName();
306343de685SKazu Hirata   return std::nullopt;
307f8f1c9c3SJon Roelofs }
308f8f1c9c3SJon Roelofs 
visitVariable(const Value * V,SmallVectorImpl<VariableInfo> & Result)309095e91c9SJon Roelofs void MemoryOpRemark::visitVariable(const Value *V,
310095e91c9SJon Roelofs                                    SmallVectorImpl<VariableInfo> &Result) {
311f8f1c9c3SJon Roelofs   if (auto *GV = dyn_cast<GlobalVariable>(V)) {
3124e601325SArthur Eubanks     auto *Ty = GV->getValueType();
3138fd5558bSGuillaume Chatelet     uint64_t Size = DL.getTypeSizeInBits(Ty).getFixedValue();
314f8f1c9c3SJon Roelofs     VariableInfo Var{nameOrNone(GV), Size};
315f8f1c9c3SJon Roelofs     if (!Var.isEmpty())
316f8f1c9c3SJon Roelofs       Result.push_back(std::move(Var));
317f8f1c9c3SJon Roelofs     return;
318f8f1c9c3SJon Roelofs   }
319f8f1c9c3SJon Roelofs 
320095e91c9SJon Roelofs   // If we find some information in the debug info, take that.
321095e91c9SJon Roelofs   bool FoundDI = false;
322095e91c9SJon Roelofs   // Try to get an llvm.dbg.declare, which has a DILocalVariable giving us the
323095e91c9SJon Roelofs   // real debug info name and size of the variable.
3244fc60489SOrlando Cazalet-Hyams   auto FindDI = [&](const auto *DVI) {
325095e91c9SJon Roelofs     if (DILocalVariable *DILV = DVI->getVariable()) {
3260ca43d44SKrzysztof Parzyszek       std::optional<uint64_t> DISize = getSizeInBytes(DILV->getSizeInBits());
327095e91c9SJon Roelofs       VariableInfo Var{DILV->getName(), DISize};
328095e91c9SJon Roelofs       if (!Var.isEmpty()) {
329095e91c9SJon Roelofs         Result.push_back(std::move(Var));
330095e91c9SJon Roelofs         FoundDI = true;
331095e91c9SJon Roelofs       }
332095e91c9SJon Roelofs     }
3334fc60489SOrlando Cazalet-Hyams   };
33430411986SStephen Tozer   for_each(findDbgDeclares(const_cast<Value *>(V)), FindDI);
335*ffd08c77SStephen Tozer   for_each(findDVRDeclares(const_cast<Value *>(V)), FindDI);
3364fc60489SOrlando Cazalet-Hyams 
337095e91c9SJon Roelofs   if (FoundDI) {
338095e91c9SJon Roelofs     assert(!Result.empty());
339095e91c9SJon Roelofs     return;
340095e91c9SJon Roelofs   }
341095e91c9SJon Roelofs 
342095e91c9SJon Roelofs   const auto *AI = dyn_cast<AllocaInst>(V);
343095e91c9SJon Roelofs   if (!AI)
344095e91c9SJon Roelofs     return;
345095e91c9SJon Roelofs 
346095e91c9SJon Roelofs   // If not, get it from the alloca.
347a6a526ecSNikita Popov   std::optional<TypeSize> TySize = AI->getAllocationSize(DL);
3480ca43d44SKrzysztof Parzyszek   std::optional<uint64_t> Size =
3498fd5558bSGuillaume Chatelet       TySize ? std::optional(TySize->getFixedValue()) : std::nullopt;
350f8f1c9c3SJon Roelofs   VariableInfo Var{nameOrNone(AI), Size};
351095e91c9SJon Roelofs   if (!Var.isEmpty())
352095e91c9SJon Roelofs     Result.push_back(std::move(Var));
353095e91c9SJon Roelofs }
354095e91c9SJon Roelofs 
visitPtr(Value * Ptr,bool IsRead,DiagnosticInfoIROptimization & R)355493d6928SJon Roelofs void MemoryOpRemark::visitPtr(Value *Ptr, bool IsRead, DiagnosticInfoIROptimization &R) {
356095e91c9SJon Roelofs   // Find if Ptr is a known variable we can give more information on.
357095e91c9SJon Roelofs   SmallVector<Value *, 2> Objects;
358095e91c9SJon Roelofs   getUnderlyingObjectsForCodeGen(Ptr, Objects);
359095e91c9SJon Roelofs   SmallVector<VariableInfo, 2> VIs;
360095e91c9SJon Roelofs   for (const Value *V : Objects)
361095e91c9SJon Roelofs     visitVariable(V, VIs);
362095e91c9SJon Roelofs 
363095e91c9SJon Roelofs   if (VIs.empty()) {
364095e91c9SJon Roelofs     bool CanBeNull;
365095e91c9SJon Roelofs     bool CanBeFreed;
366095e91c9SJon Roelofs     uint64_t Size = Ptr->getPointerDereferenceableBytes(DL, CanBeNull, CanBeFreed);
367095e91c9SJon Roelofs     if (!Size)
368095e91c9SJon Roelofs       return;
369343de685SKazu Hirata     VIs.push_back({std::nullopt, Size});
370095e91c9SJon Roelofs   }
371095e91c9SJon Roelofs 
372095e91c9SJon Roelofs   R << (IsRead ? "\n Read Variables: " : "\n Written Variables: ");
373095e91c9SJon Roelofs   for (unsigned i = 0; i < VIs.size(); ++i) {
374095e91c9SJon Roelofs     const VariableInfo &VI = VIs[i];
375095e91c9SJon Roelofs     assert(!VI.isEmpty() && "No extra content to display.");
376095e91c9SJon Roelofs     if (i != 0)
377095e91c9SJon Roelofs       R << ", ";
378095e91c9SJon Roelofs     if (VI.Name)
379095e91c9SJon Roelofs       R << NV(IsRead ? "RVarName" : "WVarName", *VI.Name);
380095e91c9SJon Roelofs     else
381095e91c9SJon Roelofs       R << NV(IsRead ? "RVarName" : "WVarName", "<unknown>");
382095e91c9SJon Roelofs     if (VI.Size)
383095e91c9SJon Roelofs       R << " (" << NV(IsRead ? "RVarSize" : "WVarSize", *VI.Size) << " bytes)";
384095e91c9SJon Roelofs   }
385095e91c9SJon Roelofs   R << ".";
386095e91c9SJon Roelofs }
387095e91c9SJon Roelofs 
canHandle(const Instruction * I)388095e91c9SJon Roelofs bool AutoInitRemark::canHandle(const Instruction *I) {
389095e91c9SJon Roelofs   if (!I->hasMetadata(LLVMContext::MD_annotation))
390095e91c9SJon Roelofs     return false;
391095e91c9SJon Roelofs   return any_of(I->getMetadata(LLVMContext::MD_annotation)->operands(),
392095e91c9SJon Roelofs                 [](const MDOperand &Op) {
3935d3a8842SZain Jaffal                   return isa<MDString>(Op.get()) &&
3945d3a8842SZain Jaffal                          cast<MDString>(Op.get())->getString() == "auto-init";
395095e91c9SJon Roelofs                 });
396095e91c9SJon Roelofs }
397095e91c9SJon Roelofs 
explainSource(StringRef Type) const398493d6928SJon Roelofs std::string AutoInitRemark::explainSource(StringRef Type) const {
399095e91c9SJon Roelofs   return (Type + " inserted by -ftrivial-auto-var-init.").str();
400095e91c9SJon Roelofs }
401095e91c9SJon Roelofs 
remarkName(RemarkKind RK) const402493d6928SJon Roelofs StringRef AutoInitRemark::remarkName(RemarkKind RK) const {
403095e91c9SJon Roelofs   switch (RK) {
404095e91c9SJon Roelofs   case RK_Store:
405095e91c9SJon Roelofs     return "AutoInitStore";
406095e91c9SJon Roelofs   case RK_Unknown:
407095e91c9SJon Roelofs     return "AutoInitUnknownInstruction";
408095e91c9SJon Roelofs   case RK_IntrinsicCall:
409095e91c9SJon Roelofs     return "AutoInitIntrinsicCall";
410095e91c9SJon Roelofs   case RK_Call:
411095e91c9SJon Roelofs     return "AutoInitCall";
412095e91c9SJon Roelofs   }
413095e91c9SJon Roelofs   llvm_unreachable("missing RemarkKind case");
414095e91c9SJon Roelofs }
415