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