/src/llvm-project/llvm/lib/Analysis/MemoryLocation.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- MemoryLocation.cpp - Memory location descriptions -------------------==// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | |
9 | | #include "llvm/Analysis/MemoryLocation.h" |
10 | | #include "llvm/Analysis/TargetLibraryInfo.h" |
11 | | #include "llvm/IR/DataLayout.h" |
12 | | #include "llvm/IR/Instructions.h" |
13 | | #include "llvm/IR/IntrinsicInst.h" |
14 | | #include "llvm/IR/IntrinsicsARM.h" |
15 | | #include "llvm/IR/Module.h" |
16 | | #include "llvm/IR/Type.h" |
17 | | #include <optional> |
18 | | using namespace llvm; |
19 | | |
20 | 0 | void LocationSize::print(raw_ostream &OS) const { |
21 | 0 | OS << "LocationSize::"; |
22 | 0 | if (*this == beforeOrAfterPointer()) |
23 | 0 | OS << "beforeOrAfterPointer"; |
24 | 0 | else if (*this == afterPointer()) |
25 | 0 | OS << "afterPointer"; |
26 | 0 | else if (*this == mapEmpty()) |
27 | 0 | OS << "mapEmpty"; |
28 | 0 | else if (*this == mapTombstone()) |
29 | 0 | OS << "mapTombstone"; |
30 | 0 | else if (isPrecise()) |
31 | 0 | OS << "precise(" << getValue() << ')'; |
32 | 0 | else |
33 | 0 | OS << "upperBound(" << getValue() << ')'; |
34 | 0 | } |
35 | | |
36 | 3.30M | MemoryLocation MemoryLocation::get(const LoadInst *LI) { |
37 | 3.30M | const auto &DL = LI->getModule()->getDataLayout(); |
38 | | |
39 | 3.30M | return MemoryLocation( |
40 | 3.30M | LI->getPointerOperand(), |
41 | 3.30M | LocationSize::precise(DL.getTypeStoreSize(LI->getType())), |
42 | 3.30M | LI->getAAMetadata()); |
43 | 3.30M | } |
44 | | |
45 | 20.4M | MemoryLocation MemoryLocation::get(const StoreInst *SI) { |
46 | 20.4M | const auto &DL = SI->getModule()->getDataLayout(); |
47 | | |
48 | 20.4M | return MemoryLocation(SI->getPointerOperand(), |
49 | 20.4M | LocationSize::precise(DL.getTypeStoreSize( |
50 | 20.4M | SI->getValueOperand()->getType())), |
51 | 20.4M | SI->getAAMetadata()); |
52 | 20.4M | } |
53 | | |
54 | 0 | MemoryLocation MemoryLocation::get(const VAArgInst *VI) { |
55 | 0 | return MemoryLocation(VI->getPointerOperand(), |
56 | 0 | LocationSize::afterPointer(), VI->getAAMetadata()); |
57 | 0 | } |
58 | | |
59 | 2 | MemoryLocation MemoryLocation::get(const AtomicCmpXchgInst *CXI) { |
60 | 2 | const auto &DL = CXI->getModule()->getDataLayout(); |
61 | | |
62 | 2 | return MemoryLocation(CXI->getPointerOperand(), |
63 | 2 | LocationSize::precise(DL.getTypeStoreSize( |
64 | 2 | CXI->getCompareOperand()->getType())), |
65 | 2 | CXI->getAAMetadata()); |
66 | 2 | } |
67 | | |
68 | 24 | MemoryLocation MemoryLocation::get(const AtomicRMWInst *RMWI) { |
69 | 24 | const auto &DL = RMWI->getModule()->getDataLayout(); |
70 | | |
71 | 24 | return MemoryLocation(RMWI->getPointerOperand(), |
72 | 24 | LocationSize::precise(DL.getTypeStoreSize( |
73 | 24 | RMWI->getValOperand()->getType())), |
74 | 24 | RMWI->getAAMetadata()); |
75 | 24 | } |
76 | | |
77 | | std::optional<MemoryLocation> |
78 | 8.15M | MemoryLocation::getOrNone(const Instruction *Inst) { |
79 | 8.15M | switch (Inst->getOpcode()) { |
80 | 277k | case Instruction::Load: |
81 | 277k | return get(cast<LoadInst>(Inst)); |
82 | 7.87M | case Instruction::Store: |
83 | 7.87M | return get(cast<StoreInst>(Inst)); |
84 | 0 | case Instruction::VAArg: |
85 | 0 | return get(cast<VAArgInst>(Inst)); |
86 | 0 | case Instruction::AtomicCmpXchg: |
87 | 0 | return get(cast<AtomicCmpXchgInst>(Inst)); |
88 | 0 | case Instruction::AtomicRMW: |
89 | 0 | return get(cast<AtomicRMWInst>(Inst)); |
90 | 77 | default: |
91 | 77 | return std::nullopt; |
92 | 8.15M | } |
93 | 8.15M | } |
94 | | |
95 | 0 | MemoryLocation MemoryLocation::getForSource(const MemTransferInst *MTI) { |
96 | 0 | return getForSource(cast<AnyMemTransferInst>(MTI)); |
97 | 0 | } |
98 | | |
99 | 0 | MemoryLocation MemoryLocation::getForSource(const AtomicMemTransferInst *MTI) { |
100 | 0 | return getForSource(cast<AnyMemTransferInst>(MTI)); |
101 | 0 | } |
102 | | |
103 | 0 | MemoryLocation MemoryLocation::getForSource(const AnyMemTransferInst *MTI) { |
104 | 0 | assert(MTI->getRawSource() == MTI->getArgOperand(1)); |
105 | 0 | return getForArgument(MTI, 1, nullptr); |
106 | 0 | } |
107 | | |
108 | 0 | MemoryLocation MemoryLocation::getForDest(const MemIntrinsic *MI) { |
109 | 0 | return getForDest(cast<AnyMemIntrinsic>(MI)); |
110 | 0 | } |
111 | | |
112 | 0 | MemoryLocation MemoryLocation::getForDest(const AtomicMemIntrinsic *MI) { |
113 | 0 | return getForDest(cast<AnyMemIntrinsic>(MI)); |
114 | 0 | } |
115 | | |
116 | 0 | MemoryLocation MemoryLocation::getForDest(const AnyMemIntrinsic *MI) { |
117 | 0 | assert(MI->getRawDest() == MI->getArgOperand(0)); |
118 | 0 | return getForArgument(MI, 0, nullptr); |
119 | 0 | } |
120 | | |
121 | | std::optional<MemoryLocation> |
122 | 11 | MemoryLocation::getForDest(const CallBase *CB, const TargetLibraryInfo &TLI) { |
123 | 11 | if (!CB->onlyAccessesArgMemory()) |
124 | 0 | return std::nullopt; |
125 | | |
126 | 11 | if (CB->hasOperandBundles()) |
127 | | // TODO: remove implementation restriction |
128 | 0 | return std::nullopt; |
129 | | |
130 | 11 | Value *UsedV = nullptr; |
131 | 11 | std::optional<unsigned> UsedIdx; |
132 | 49 | for (unsigned i = 0; i < CB->arg_size(); i++) { |
133 | 38 | if (!CB->getArgOperand(i)->getType()->isPointerTy()) |
134 | 16 | continue; |
135 | 22 | if (CB->onlyReadsMemory(i)) |
136 | 11 | continue; |
137 | 11 | if (!UsedV) { |
138 | | // First potentially writing parameter |
139 | 11 | UsedV = CB->getArgOperand(i); |
140 | 11 | UsedIdx = i; |
141 | 11 | continue; |
142 | 11 | } |
143 | 0 | UsedIdx = std::nullopt; |
144 | 0 | if (UsedV != CB->getArgOperand(i)) |
145 | | // Can't describe writing to two distinct locations. |
146 | | // TODO: This results in an inprecision when two values derived from the |
147 | | // same object are passed as arguments to the same function. |
148 | 0 | return std::nullopt; |
149 | 0 | } |
150 | 11 | if (!UsedV) |
151 | | // We don't currently have a way to represent a "does not write" result |
152 | | // and thus have to be conservative and return unknown. |
153 | 0 | return std::nullopt; |
154 | | |
155 | 11 | if (UsedIdx) |
156 | 11 | return getForArgument(CB, *UsedIdx, &TLI); |
157 | 0 | return MemoryLocation::getBeforeOrAfter(UsedV, CB->getAAMetadata()); |
158 | 11 | } |
159 | | |
160 | | MemoryLocation MemoryLocation::getForArgument(const CallBase *Call, |
161 | | unsigned ArgIdx, |
162 | 10.6k | const TargetLibraryInfo *TLI) { |
163 | 10.6k | AAMDNodes AATags = Call->getAAMetadata(); |
164 | 10.6k | const Value *Arg = Call->getArgOperand(ArgIdx); |
165 | | |
166 | | // We may be able to produce an exact size for known intrinsics. |
167 | 10.6k | if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(Call)) { |
168 | 10.5k | const DataLayout &DL = II->getModule()->getDataLayout(); |
169 | | |
170 | 10.5k | switch (II->getIntrinsicID()) { |
171 | 2.35k | default: |
172 | 2.35k | break; |
173 | 4.80k | case Intrinsic::memset: |
174 | 5.79k | case Intrinsic::memcpy: |
175 | 5.79k | case Intrinsic::memcpy_inline: |
176 | 5.86k | case Intrinsic::memmove: |
177 | 5.92k | case Intrinsic::memcpy_element_unordered_atomic: |
178 | 5.95k | case Intrinsic::memmove_element_unordered_atomic: |
179 | 5.97k | case Intrinsic::memset_element_unordered_atomic: |
180 | 5.97k | assert((ArgIdx == 0 || ArgIdx == 1) && |
181 | 5.97k | "Invalid argument index for memory intrinsic"); |
182 | 5.97k | if (ConstantInt *LenCI = dyn_cast<ConstantInt>(II->getArgOperand(2))) |
183 | 5.34k | return MemoryLocation(Arg, LocationSize::precise(LenCI->getZExtValue()), |
184 | 5.34k | AATags); |
185 | 636 | return MemoryLocation::getAfter(Arg, AATags); |
186 | | |
187 | 294 | case Intrinsic::lifetime_start: |
188 | 1.47k | case Intrinsic::lifetime_end: |
189 | 1.71k | case Intrinsic::invariant_start: |
190 | 1.71k | assert(ArgIdx == 1 && "Invalid argument index"); |
191 | 0 | return MemoryLocation( |
192 | 1.71k | Arg, |
193 | 1.71k | LocationSize::precise( |
194 | 1.71k | cast<ConstantInt>(II->getArgOperand(0))->getZExtValue()), |
195 | 1.71k | AATags); |
196 | | |
197 | 41 | case Intrinsic::masked_load: |
198 | 41 | assert(ArgIdx == 0 && "Invalid argument index"); |
199 | 0 | return MemoryLocation( |
200 | 41 | Arg, |
201 | 41 | LocationSize::upperBound(DL.getTypeStoreSize(II->getType())), |
202 | 41 | AATags); |
203 | | |
204 | 219 | case Intrinsic::masked_store: |
205 | 219 | assert(ArgIdx == 1 && "Invalid argument index"); |
206 | 0 | return MemoryLocation( |
207 | 219 | Arg, |
208 | 219 | LocationSize::upperBound( |
209 | 219 | DL.getTypeStoreSize(II->getArgOperand(0)->getType())), |
210 | 219 | AATags); |
211 | | |
212 | 230 | case Intrinsic::invariant_end: |
213 | | // The first argument to an invariant.end is a "descriptor" type (e.g. a |
214 | | // pointer to a empty struct) which is never actually dereferenced. |
215 | 230 | if (ArgIdx == 0) |
216 | 115 | return MemoryLocation(Arg, LocationSize::precise(0), AATags); |
217 | 115 | assert(ArgIdx == 2 && "Invalid argument index"); |
218 | 0 | return MemoryLocation( |
219 | 115 | Arg, |
220 | 115 | LocationSize::precise( |
221 | 115 | cast<ConstantInt>(II->getArgOperand(1))->getZExtValue()), |
222 | 115 | AATags); |
223 | | |
224 | 2 | case Intrinsic::arm_neon_vld1: |
225 | 2 | assert(ArgIdx == 0 && "Invalid argument index"); |
226 | | // LLVM's vld1 and vst1 intrinsics currently only support a single |
227 | | // vector register. |
228 | 0 | return MemoryLocation( |
229 | 2 | Arg, LocationSize::precise(DL.getTypeStoreSize(II->getType())), |
230 | 2 | AATags); |
231 | | |
232 | 0 | case Intrinsic::arm_neon_vst1: |
233 | 0 | assert(ArgIdx == 0 && "Invalid argument index"); |
234 | 0 | return MemoryLocation(Arg, |
235 | 0 | LocationSize::precise(DL.getTypeStoreSize( |
236 | 0 | II->getArgOperand(1)->getType())), |
237 | 0 | AATags); |
238 | 10.5k | } |
239 | | |
240 | 2.35k | assert( |
241 | 2.35k | !isa<AnyMemTransferInst>(II) && |
242 | 2.35k | "all memory transfer intrinsics should be handled by the switch above"); |
243 | 2.35k | } |
244 | | |
245 | | // We can bound the aliasing properties of memset_pattern16 just as we can |
246 | | // for memcpy/memset. This is particularly important because the |
247 | | // LoopIdiomRecognizer likes to turn loops into calls to memset_pattern16 |
248 | | // whenever possible. |
249 | 2.50k | LibFunc F; |
250 | 2.50k | if (TLI && TLI->getLibFunc(*Call, F) && TLI->has(F)) { |
251 | 15 | switch (F) { |
252 | 3 | case LibFunc_strcpy: |
253 | 7 | case LibFunc_strcat: |
254 | 7 | case LibFunc_strncat: |
255 | 7 | assert((ArgIdx == 0 || ArgIdx == 1) && "Invalid argument index for str function"); |
256 | 0 | return MemoryLocation::getAfter(Arg, AATags); |
257 | | |
258 | 0 | case LibFunc_memset_chk: |
259 | 0 | assert(ArgIdx == 0 && "Invalid argument index for memset_chk"); |
260 | 0 | [[fallthrough]]; |
261 | 0 | case LibFunc_memcpy_chk: { |
262 | 0 | assert((ArgIdx == 0 || ArgIdx == 1) && |
263 | 0 | "Invalid argument index for memcpy_chk"); |
264 | 0 | LocationSize Size = LocationSize::afterPointer(); |
265 | 0 | if (const auto *Len = dyn_cast<ConstantInt>(Call->getArgOperand(2))) { |
266 | | // memset_chk writes at most Len bytes, memcpy_chk reads/writes at most |
267 | | // Len bytes. They may read/write less, if Len exceeds the specified max |
268 | | // size and aborts. |
269 | 0 | Size = LocationSize::upperBound(Len->getZExtValue()); |
270 | 0 | } |
271 | 0 | return MemoryLocation(Arg, Size, AATags); |
272 | 0 | } |
273 | 0 | case LibFunc_strncpy: { |
274 | 0 | assert((ArgIdx == 0 || ArgIdx == 1) && |
275 | 0 | "Invalid argument index for strncpy"); |
276 | 0 | LocationSize Size = LocationSize::afterPointer(); |
277 | 0 | if (const auto *Len = dyn_cast<ConstantInt>(Call->getArgOperand(2))) { |
278 | | // strncpy is guaranteed to write Len bytes, but only reads up to Len |
279 | | // bytes. |
280 | 0 | Size = ArgIdx == 0 ? LocationSize::precise(Len->getZExtValue()) |
281 | 0 | : LocationSize::upperBound(Len->getZExtValue()); |
282 | 0 | } |
283 | 0 | return MemoryLocation(Arg, Size, AATags); |
284 | 0 | } |
285 | 0 | case LibFunc_memset_pattern16: |
286 | 0 | case LibFunc_memset_pattern4: |
287 | 0 | case LibFunc_memset_pattern8: |
288 | 0 | assert((ArgIdx == 0 || ArgIdx == 1) && |
289 | 0 | "Invalid argument index for memset_pattern16"); |
290 | 0 | if (ArgIdx == 1) { |
291 | 0 | unsigned Size = 16; |
292 | 0 | if (F == LibFunc_memset_pattern4) |
293 | 0 | Size = 4; |
294 | 0 | else if (F == LibFunc_memset_pattern8) |
295 | 0 | Size = 8; |
296 | 0 | return MemoryLocation(Arg, LocationSize::precise(Size), AATags); |
297 | 0 | } |
298 | 0 | if (const ConstantInt *LenCI = |
299 | 0 | dyn_cast<ConstantInt>(Call->getArgOperand(2))) |
300 | 0 | return MemoryLocation(Arg, LocationSize::precise(LenCI->getZExtValue()), |
301 | 0 | AATags); |
302 | 0 | return MemoryLocation::getAfter(Arg, AATags); |
303 | 0 | case LibFunc_bcmp: |
304 | 0 | case LibFunc_memcmp: |
305 | 0 | assert((ArgIdx == 0 || ArgIdx == 1) && |
306 | 0 | "Invalid argument index for memcmp/bcmp"); |
307 | 0 | if (const ConstantInt *LenCI = |
308 | 0 | dyn_cast<ConstantInt>(Call->getArgOperand(2))) |
309 | 0 | return MemoryLocation(Arg, LocationSize::precise(LenCI->getZExtValue()), |
310 | 0 | AATags); |
311 | 0 | return MemoryLocation::getAfter(Arg, AATags); |
312 | 0 | case LibFunc_memchr: |
313 | 0 | assert((ArgIdx == 0) && "Invalid argument index for memchr"); |
314 | 0 | if (const ConstantInt *LenCI = |
315 | 0 | dyn_cast<ConstantInt>(Call->getArgOperand(2))) |
316 | 0 | return MemoryLocation(Arg, LocationSize::precise(LenCI->getZExtValue()), |
317 | 0 | AATags); |
318 | 0 | return MemoryLocation::getAfter(Arg, AATags); |
319 | 8 | case LibFunc_memccpy: |
320 | 8 | assert((ArgIdx == 0 || ArgIdx == 1) && |
321 | 8 | "Invalid argument index for memccpy"); |
322 | | // We only know an upper bound on the number of bytes read/written. |
323 | 8 | if (const ConstantInt *LenCI = |
324 | 8 | dyn_cast<ConstantInt>(Call->getArgOperand(3))) |
325 | 8 | return MemoryLocation( |
326 | 8 | Arg, LocationSize::upperBound(LenCI->getZExtValue()), AATags); |
327 | 0 | return MemoryLocation::getAfter(Arg, AATags); |
328 | 0 | default: |
329 | 0 | break; |
330 | 15 | }; |
331 | 0 | } |
332 | | |
333 | 2.49k | return MemoryLocation::getBeforeOrAfter(Call->getArgOperand(ArgIdx), AATags); |
334 | 2.50k | } |