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
canHandle(const Instruction * I,const TargetLibraryInfo & TLI)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
visit(const Instruction * I)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
explainSource(StringRef Type) const110fe6060f1SDimitry Andric std::string MemoryOpRemark::explainSource(StringRef Type) const {
111fe6060f1SDimitry Andric return (Type + ".").str();
112fe6060f1SDimitry Andric }
113fe6060f1SDimitry Andric
remarkName(RemarkKind RK) const114fe6060f1SDimitry 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
inlineVolatileOrAtomicWithExtraArgs(bool * Inline,bool Volatile,bool Atomic,DiagnosticInfoIROptimization & R)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>
getSizeInBytes(std::optional<uint64_t> SizeInBits)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>
makeRemark(Ts...Args)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
visitStore(const StoreInst & SI)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
visitUnknown(const Instruction & I)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
visitIntrinsicCall(const IntrinsicInst & II)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
visitCall(const CallInst & CI)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>
visitCallee(FTy F,bool KnownLibCall,DiagnosticInfoIROptimization & R)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
visitKnownLibCall(const CallInst & CI,LibFunc LF,DiagnosticInfoIROptimization & R)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
visitSizeOperand(Value * V,DiagnosticInfoIROptimization & R)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
nameOrNone(const Value * V)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
visitVariable(const Value * V,SmallVectorImpl<VariableInfo> & Result)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
visitPtr(Value * Ptr,bool IsRead,DiagnosticInfoIROptimization & R)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
canHandle(const Instruction * I)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
explainSource(StringRef Type) const398fe6060f1SDimitry Andric std::string AutoInitRemark::explainSource(StringRef Type) const {
399fe6060f1SDimitry Andric return (Type + " inserted by -ftrivial-auto-var-init.").str();
400fe6060f1SDimitry Andric }
401fe6060f1SDimitry Andric
remarkName(RemarkKind RK) const402fe6060f1SDimitry 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