LLVM 20.0.0git
MemoryBuiltins.cpp
Go to the documentation of this file.
1//===- MemoryBuiltins.cpp - Identify calls to memory builtins -------------===//
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// This family of functions identifies calls to builtin functions that allocate
10// or free memory.
11//
12//===----------------------------------------------------------------------===//
13
15#include "llvm/ADT/APInt.h"
16#include "llvm/ADT/STLExtras.h"
17#include "llvm/ADT/Statistic.h"
23#include "llvm/IR/Argument.h"
24#include "llvm/IR/Attributes.h"
25#include "llvm/IR/Constants.h"
26#include "llvm/IR/DataLayout.h"
28#include "llvm/IR/Function.h"
29#include "llvm/IR/GlobalAlias.h"
31#include "llvm/IR/Instruction.h"
34#include "llvm/IR/Operator.h"
35#include "llvm/IR/Type.h"
36#include "llvm/IR/Value.h"
39#include "llvm/Support/Debug.h"
42#include <cassert>
43#include <cstdint>
44#include <iterator>
45#include <numeric>
46#include <optional>
47#include <type_traits>
48#include <utility>
49
50using namespace llvm;
51
52#define DEBUG_TYPE "memory-builtins"
53
55 "object-size-offset-visitor-max-visit-instructions",
56 cl::desc("Maximum number of instructions for ObjectSizeOffsetVisitor to "
57 "look at"),
58 cl::init(100));
59
60enum AllocType : uint8_t {
61 OpNewLike = 1<<0, // allocates; never returns null
62 MallocLike = 1<<1, // allocates; may return null
63 StrDupLike = 1<<2,
67};
68
69enum class MallocFamily {
70 Malloc,
71 CPPNew, // new(unsigned int)
72 CPPNewAligned, // new(unsigned int, align_val_t)
73 CPPNewArray, // new[](unsigned int)
74 CPPNewArrayAligned, // new[](unsigned long, align_val_t)
75 MSVCNew, // new(unsigned int)
76 MSVCArrayNew, // new[](unsigned int)
79};
80
82 switch (Family) {
84 return "malloc";
86 return "_Znwm";
88 return "_ZnwmSt11align_val_t";
90 return "_Znam";
92 return "_ZnamSt11align_val_t";
94 return "??2@YAPAXI@Z";
96 return "??_U@YAPAXI@Z";
98 return "vec_malloc";
100 return "__kmpc_alloc_shared";
101 }
102 llvm_unreachable("missing an alloc family");
103}
104
107 unsigned NumParams;
108 // First and Second size parameters (or -1 if unused)
110 // Alignment parameter for aligned_alloc and aligned new
112 // Name of default allocator function to group malloc/free calls by family
114};
115
116// clang-format off
117// FIXME: certain users need more information. E.g., SimplifyLibCalls needs to
118// know which functions are nounwind, noalias, nocapture parameters, etc.
119static const std::pair<LibFunc, AllocFnsTy> AllocationFnData[] = {
120 {LibFunc_Znwj, {OpNewLike, 1, 0, -1, -1, MallocFamily::CPPNew}}, // new(unsigned int)
121 {LibFunc_ZnwjRKSt9nothrow_t, {MallocLike, 2, 0, -1, -1, MallocFamily::CPPNew}}, // new(unsigned int, nothrow)
122 {LibFunc_ZnwjSt11align_val_t, {OpNewLike, 2, 0, -1, 1, MallocFamily::CPPNewAligned}}, // new(unsigned int, align_val_t)
123 {LibFunc_ZnwjSt11align_val_tRKSt9nothrow_t, {MallocLike, 3, 0, -1, 1, MallocFamily::CPPNewAligned}}, // new(unsigned int, align_val_t, nothrow)
124 {LibFunc_Znwm, {OpNewLike, 1, 0, -1, -1, MallocFamily::CPPNew}}, // new(unsigned long)
125 {LibFunc_Znwm12__hot_cold_t, {OpNewLike, 2, 0, -1, -1, MallocFamily::CPPNew}}, // new(unsigned long, __hot_cold_t)
126 {LibFunc_ZnwmRKSt9nothrow_t, {MallocLike, 2, 0, -1, -1, MallocFamily::CPPNew}}, // new(unsigned long, nothrow)
127 {LibFunc_ZnwmRKSt9nothrow_t12__hot_cold_t, {MallocLike, 3, 0, -1, -1, MallocFamily::CPPNew}}, // new(unsigned long, nothrow, __hot_cold_t)
128 {LibFunc_ZnwmSt11align_val_t, {OpNewLike, 2, 0, -1, 1, MallocFamily::CPPNewAligned}}, // new(unsigned long, align_val_t)
129 {LibFunc_ZnwmSt11align_val_t12__hot_cold_t, {OpNewLike, 3, 0, -1, 1, MallocFamily::CPPNewAligned}}, // new(unsigned long, align_val_t, __hot_cold_t)
130 {LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t, {MallocLike, 3, 0, -1, 1, MallocFamily::CPPNewAligned}}, // new(unsigned long, align_val_t, nothrow)
131 {LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t12__hot_cold_t, {MallocLike, 4, 0, -1, 1, MallocFamily::CPPNewAligned}}, // new(unsigned long, align_val_t, nothrow, __hot_cold_t)
132 {LibFunc_Znaj, {OpNewLike, 1, 0, -1, -1, MallocFamily::CPPNewArray}}, // new[](unsigned int)
133 {LibFunc_ZnajRKSt9nothrow_t, {MallocLike, 2, 0, -1, -1, MallocFamily::CPPNewArray}}, // new[](unsigned int, nothrow)
134 {LibFunc_ZnajSt11align_val_t, {OpNewLike, 2, 0, -1, 1, MallocFamily::CPPNewArrayAligned}}, // new[](unsigned int, align_val_t)
135 {LibFunc_ZnajSt11align_val_tRKSt9nothrow_t, {MallocLike, 3, 0, -1, 1, MallocFamily::CPPNewArrayAligned}}, // new[](unsigned int, align_val_t, nothrow)
136 {LibFunc_Znam, {OpNewLike, 1, 0, -1, -1, MallocFamily::CPPNewArray}}, // new[](unsigned long)
137 {LibFunc_Znam12__hot_cold_t, {OpNewLike, 2, 0, -1, -1, MallocFamily::CPPNew}}, // new[](unsigned long, __hot_cold_t)
138 {LibFunc_ZnamRKSt9nothrow_t, {MallocLike, 2, 0, -1, -1, MallocFamily::CPPNewArray}}, // new[](unsigned long, nothrow)
139 {LibFunc_ZnamRKSt9nothrow_t12__hot_cold_t, {MallocLike, 3, 0, -1, -1, MallocFamily::CPPNew}}, // new[](unsigned long, nothrow, __hot_cold_t)
140 {LibFunc_ZnamSt11align_val_t, {OpNewLike, 2, 0, -1, 1, MallocFamily::CPPNewArrayAligned}}, // new[](unsigned long, align_val_t)
141 {LibFunc_ZnamSt11align_val_t12__hot_cold_t, {OpNewLike, 3, 0, -1, 1, MallocFamily::CPPNewAligned}}, // new[](unsigned long, align_val_t, __hot_cold_t)
142 {LibFunc_ZnamSt11align_val_tRKSt9nothrow_t, {MallocLike, 3, 0, -1, 1, MallocFamily::CPPNewArrayAligned}}, // new[](unsigned long, align_val_t, nothrow)
143 {LibFunc_ZnamSt11align_val_tRKSt9nothrow_t12__hot_cold_t, {MallocLike, 4, 0, -1, 1, MallocFamily::CPPNewAligned}}, // new[](unsigned long, align_val_t, nothrow, __hot_cold_t)
144 {LibFunc_msvc_new_int, {OpNewLike, 1, 0, -1, -1, MallocFamily::MSVCNew}}, // new(unsigned int)
145 {LibFunc_msvc_new_int_nothrow, {MallocLike, 2, 0, -1, -1, MallocFamily::MSVCNew}}, // new(unsigned int, nothrow)
146 {LibFunc_msvc_new_longlong, {OpNewLike, 1, 0, -1, -1, MallocFamily::MSVCNew}}, // new(unsigned long long)
147 {LibFunc_msvc_new_longlong_nothrow, {MallocLike, 2, 0, -1, -1, MallocFamily::MSVCNew}}, // new(unsigned long long, nothrow)
148 {LibFunc_msvc_new_array_int, {OpNewLike, 1, 0, -1, -1, MallocFamily::MSVCArrayNew}}, // new[](unsigned int)
149 {LibFunc_msvc_new_array_int_nothrow, {MallocLike, 2, 0, -1, -1, MallocFamily::MSVCArrayNew}}, // new[](unsigned int, nothrow)
150 {LibFunc_msvc_new_array_longlong, {OpNewLike, 1, 0, -1, -1, MallocFamily::MSVCArrayNew}}, // new[](unsigned long long)
151 {LibFunc_msvc_new_array_longlong_nothrow, {MallocLike, 2, 0, -1, -1, MallocFamily::MSVCArrayNew}}, // new[](unsigned long long, nothrow)
152 {LibFunc_strdup, {StrDupLike, 1, -1, -1, -1, MallocFamily::Malloc}},
153 {LibFunc_dunder_strdup, {StrDupLike, 1, -1, -1, -1, MallocFamily::Malloc}},
154 {LibFunc_strndup, {StrDupLike, 2, 1, -1, -1, MallocFamily::Malloc}},
155 {LibFunc_dunder_strndup, {StrDupLike, 2, 1, -1, -1, MallocFamily::Malloc}},
156 {LibFunc___kmpc_alloc_shared, {MallocLike, 1, 0, -1, -1, MallocFamily::KmpcAllocShared}},
157};
158// clang-format on
159
160static const Function *getCalledFunction(const Value *V) {
161 // Don't care about intrinsics in this case.
162 if (isa<IntrinsicInst>(V))
163 return nullptr;
164
165 const auto *CB = dyn_cast<CallBase>(V);
166 if (!CB)
167 return nullptr;
168
169 if (CB->isNoBuiltin())
170 return nullptr;
171
172 return CB->getCalledFunction();
173}
174
175/// Returns the allocation data for the given value if it's a call to a known
176/// allocation function.
177static std::optional<AllocFnsTy>
179 const TargetLibraryInfo *TLI) {
180 // Don't perform a slow TLI lookup, if this function doesn't return a pointer
181 // and thus can't be an allocation function.
182 if (!Callee->getReturnType()->isPointerTy())
183 return std::nullopt;
184
185 // Make sure that the function is available.
186 LibFunc TLIFn;
187 if (!TLI || !TLI->getLibFunc(*Callee, TLIFn) || !TLI->has(TLIFn))
188 return std::nullopt;
189
190 const auto *Iter = find_if(
191 AllocationFnData, [TLIFn](const std::pair<LibFunc, AllocFnsTy> &P) {
192 return P.first == TLIFn;
193 });
194
195 if (Iter == std::end(AllocationFnData))
196 return std::nullopt;
197
198 const AllocFnsTy *FnData = &Iter->second;
199 if ((FnData->AllocTy & AllocTy) != FnData->AllocTy)
200 return std::nullopt;
201
202 // Check function prototype.
203 int FstParam = FnData->FstParam;
204 int SndParam = FnData->SndParam;
205 FunctionType *FTy = Callee->getFunctionType();
206
207 if (FTy->getReturnType()->isPointerTy() &&
208 FTy->getNumParams() == FnData->NumParams &&
209 (FstParam < 0 ||
210 (FTy->getParamType(FstParam)->isIntegerTy(32) ||
211 FTy->getParamType(FstParam)->isIntegerTy(64))) &&
212 (SndParam < 0 ||
213 FTy->getParamType(SndParam)->isIntegerTy(32) ||
214 FTy->getParamType(SndParam)->isIntegerTy(64)))
215 return *FnData;
216 return std::nullopt;
217}
218
219static std::optional<AllocFnsTy>
221 const TargetLibraryInfo *TLI) {
222 if (const Function *Callee = getCalledFunction(V))
223 return getAllocationDataForFunction(Callee, AllocTy, TLI);
224 return std::nullopt;
225}
226
227static std::optional<AllocFnsTy>
229 function_ref<const TargetLibraryInfo &(Function &)> GetTLI) {
230 if (const Function *Callee = getCalledFunction(V))
232 Callee, AllocTy, &GetTLI(const_cast<Function &>(*Callee)));
233 return std::nullopt;
234}
235
236static std::optional<AllocFnsTy>
238 if (const Function *Callee = getCalledFunction(CB)) {
239 // Prefer to use existing information over allocsize. This will give us an
240 // accurate AllocTy.
241 if (std::optional<AllocFnsTy> Data =
243 return Data;
244 }
245
246 Attribute Attr = CB->getFnAttr(Attribute::AllocSize);
247 if (Attr == Attribute())
248 return std::nullopt;
249
250 std::pair<unsigned, std::optional<unsigned>> Args = Attr.getAllocSizeArgs();
251
252 AllocFnsTy Result;
253 // Because allocsize only tells us how many bytes are allocated, we're not
254 // really allowed to assume anything, so we use MallocLike.
255 Result.AllocTy = MallocLike;
256 Result.NumParams = CB->arg_size();
257 Result.FstParam = Args.first;
258 Result.SndParam = Args.second.value_or(-1);
259 // Allocsize has no way to specify an alignment argument
260 Result.AlignParam = -1;
261 return Result;
262}
263
265 if (const auto *CB = dyn_cast<CallBase>(V)) {
266 Attribute Attr = CB->getFnAttr(Attribute::AllocKind);
267 if (Attr.isValid())
268 return AllocFnKind(Attr.getValueAsInt());
269 }
270 return AllocFnKind::Unknown;
271}
272
274 return F->getAttributes().getAllocKind();
275}
276
277static bool checkFnAllocKind(const Value *V, AllocFnKind Wanted) {
278 return (getAllocFnKind(V) & Wanted) != AllocFnKind::Unknown;
279}
280
281static bool checkFnAllocKind(const Function *F, AllocFnKind Wanted) {
282 return (getAllocFnKind(F) & Wanted) != AllocFnKind::Unknown;
283}
284
285/// Tests if a value is a call or invoke to a library function that
286/// allocates or reallocates memory (either malloc, calloc, realloc, or strdup
287/// like).
288bool llvm::isAllocationFn(const Value *V, const TargetLibraryInfo *TLI) {
289 return getAllocationData(V, AnyAlloc, TLI).has_value() ||
290 checkFnAllocKind(V, AllocFnKind::Alloc | AllocFnKind::Realloc);
291}
293 const Value *V,
294 function_ref<const TargetLibraryInfo &(Function &)> GetTLI) {
295 return getAllocationData(V, AnyAlloc, GetTLI).has_value() ||
296 checkFnAllocKind(V, AllocFnKind::Alloc | AllocFnKind::Realloc);
297}
298
299/// Tests if a value is a call or invoke to a library function that
300/// allocates memory via new.
301bool llvm::isNewLikeFn(const Value *V, const TargetLibraryInfo *TLI) {
302 return getAllocationData(V, OpNewLike, TLI).has_value();
303}
304
305/// Tests if a value is a call or invoke to a library function that
306/// allocates memory similar to malloc or calloc.
308 // TODO: Function behavior does not match name.
309 return getAllocationData(V, MallocOrOpNewLike, TLI).has_value();
310}
311
312/// Tests if a value is a call or invoke to a library function that
313/// allocates memory (either malloc, calloc, or strdup like).
314bool llvm::isAllocLikeFn(const Value *V, const TargetLibraryInfo *TLI) {
315 return getAllocationData(V, AllocLike, TLI).has_value() ||
316 checkFnAllocKind(V, AllocFnKind::Alloc);
317}
318
319/// Tests if a functions is a call or invoke to a library function that
320/// reallocates memory (e.g., realloc).
322 return checkFnAllocKind(F, AllocFnKind::Realloc);
323}
324
326 if (checkFnAllocKind(CB, AllocFnKind::Realloc))
327 return CB->getArgOperandWithAttribute(Attribute::AllocatedPointer);
328 return nullptr;
329}
330
332 // Note: Removability is highly dependent on the source language. For
333 // example, recent C++ requires direct calls to the global allocation
334 // [basic.stc.dynamic.allocation] to be observable unless part of a new
335 // expression [expr.new paragraph 13].
336
337 // Historically we've treated the C family allocation routines and operator
338 // new as removable
339 return isAllocLikeFn(CB, TLI);
340}
341
343 const TargetLibraryInfo *TLI) {
344 const std::optional<AllocFnsTy> FnData = getAllocationData(V, AnyAlloc, TLI);
345 if (FnData && FnData->AlignParam >= 0) {
346 return V->getOperand(FnData->AlignParam);
347 }
348 return V->getArgOperandWithAttribute(Attribute::AllocAlign);
349}
350
351/// When we're compiling N-bit code, and the user uses parameters that are
352/// greater than N bits (e.g. uint64_t on a 32-bit build), we can run into
353/// trouble with APInt size issues. This function handles resizing + overflow
354/// checks for us. Check and zext or trunc \p I depending on IntTyBits and
355/// I's value.
356static bool CheckedZextOrTrunc(APInt &I, unsigned IntTyBits) {
357 // More bits than we can handle. Checking the bit width isn't necessary, but
358 // it's faster than checking active bits, and should give `false` in the
359 // vast majority of cases.
360 if (I.getBitWidth() > IntTyBits && I.getActiveBits() > IntTyBits)
361 return false;
362 if (I.getBitWidth() != IntTyBits)
363 I = I.zextOrTrunc(IntTyBits);
364 return true;
365}
366
367std::optional<APInt>
369 function_ref<const Value *(const Value *)> Mapper) {
370 // Note: This handles both explicitly listed allocation functions and
371 // allocsize. The code structure could stand to be cleaned up a bit.
372 std::optional<AllocFnsTy> FnData = getAllocationSize(CB, TLI);
373 if (!FnData)
374 return std::nullopt;
375
376 // Get the index type for this address space, results and intermediate
377 // computations are performed at that width.
378 auto &DL = CB->getDataLayout();
379 const unsigned IntTyBits = DL.getIndexTypeSizeInBits(CB->getType());
380
381 // Handle strdup-like functions separately.
382 if (FnData->AllocTy == StrDupLike) {
383 APInt Size(IntTyBits, GetStringLength(Mapper(CB->getArgOperand(0))));
384 if (!Size)
385 return std::nullopt;
386
387 // Strndup limits strlen.
388 if (FnData->FstParam > 0) {
389 const ConstantInt *Arg =
390 dyn_cast<ConstantInt>(Mapper(CB->getArgOperand(FnData->FstParam)));
391 if (!Arg)
392 return std::nullopt;
393
394 APInt MaxSize = Arg->getValue().zext(IntTyBits);
395 if (Size.ugt(MaxSize))
396 Size = MaxSize + 1;
397 }
398 return Size;
399 }
400
401 const ConstantInt *Arg =
402 dyn_cast<ConstantInt>(Mapper(CB->getArgOperand(FnData->FstParam)));
403 if (!Arg)
404 return std::nullopt;
405
406 APInt Size = Arg->getValue();
407 if (!CheckedZextOrTrunc(Size, IntTyBits))
408 return std::nullopt;
409
410 // Size is determined by just 1 parameter.
411 if (FnData->SndParam < 0)
412 return Size;
413
414 Arg = dyn_cast<ConstantInt>(Mapper(CB->getArgOperand(FnData->SndParam)));
415 if (!Arg)
416 return std::nullopt;
417
418 APInt NumElems = Arg->getValue();
419 if (!CheckedZextOrTrunc(NumElems, IntTyBits))
420 return std::nullopt;
421
422 bool Overflow;
423 Size = Size.umul_ov(NumElems, Overflow);
424 if (Overflow)
425 return std::nullopt;
426 return Size;
427}
428
430 const TargetLibraryInfo *TLI,
431 Type *Ty) {
432 auto *Alloc = dyn_cast<CallBase>(V);
433 if (!Alloc)
434 return nullptr;
435
436 // malloc are uninitialized (undef)
437 if (getAllocationData(Alloc, MallocOrOpNewLike, TLI).has_value())
438 return UndefValue::get(Ty);
439
440 AllocFnKind AK = getAllocFnKind(Alloc);
441 if ((AK & AllocFnKind::Uninitialized) != AllocFnKind::Unknown)
442 return UndefValue::get(Ty);
443 if ((AK & AllocFnKind::Zeroed) != AllocFnKind::Unknown)
444 return Constant::getNullValue(Ty);
445
446 return nullptr;
447}
448
449struct FreeFnsTy {
450 unsigned NumParams;
451 // Name of default allocator function to group malloc/free calls by family
453};
454
455// clang-format off
456static const std::pair<LibFunc, FreeFnsTy> FreeFnData[] = {
457 {LibFunc_ZdlPv, {1, MallocFamily::CPPNew}}, // operator delete(void*)
458 {LibFunc_ZdaPv, {1, MallocFamily::CPPNewArray}}, // operator delete[](void*)
459 {LibFunc_msvc_delete_ptr32, {1, MallocFamily::MSVCNew}}, // operator delete(void*)
460 {LibFunc_msvc_delete_ptr64, {1, MallocFamily::MSVCNew}}, // operator delete(void*)
461 {LibFunc_msvc_delete_array_ptr32, {1, MallocFamily::MSVCArrayNew}}, // operator delete[](void*)
462 {LibFunc_msvc_delete_array_ptr64, {1, MallocFamily::MSVCArrayNew}}, // operator delete[](void*)
463 {LibFunc_ZdlPvj, {2, MallocFamily::CPPNew}}, // delete(void*, uint)
464 {LibFunc_ZdlPvm, {2, MallocFamily::CPPNew}}, // delete(void*, ulong)
465 {LibFunc_ZdlPvRKSt9nothrow_t, {2, MallocFamily::CPPNew}}, // delete(void*, nothrow)
466 {LibFunc_ZdlPvSt11align_val_t, {2, MallocFamily::CPPNewAligned}}, // delete(void*, align_val_t)
467 {LibFunc_ZdaPvj, {2, MallocFamily::CPPNewArray}}, // delete[](void*, uint)
468 {LibFunc_ZdaPvm, {2, MallocFamily::CPPNewArray}}, // delete[](void*, ulong)
469 {LibFunc_ZdaPvRKSt9nothrow_t, {2, MallocFamily::CPPNewArray}}, // delete[](void*, nothrow)
470 {LibFunc_ZdaPvSt11align_val_t, {2, MallocFamily::CPPNewArrayAligned}}, // delete[](void*, align_val_t)
471 {LibFunc_msvc_delete_ptr32_int, {2, MallocFamily::MSVCNew}}, // delete(void*, uint)
472 {LibFunc_msvc_delete_ptr64_longlong, {2, MallocFamily::MSVCNew}}, // delete(void*, ulonglong)
473 {LibFunc_msvc_delete_ptr32_nothrow, {2, MallocFamily::MSVCNew}}, // delete(void*, nothrow)
474 {LibFunc_msvc_delete_ptr64_nothrow, {2, MallocFamily::MSVCNew}}, // delete(void*, nothrow)
475 {LibFunc_msvc_delete_array_ptr32_int, {2, MallocFamily::MSVCArrayNew}}, // delete[](void*, uint)
476 {LibFunc_msvc_delete_array_ptr64_longlong, {2, MallocFamily::MSVCArrayNew}}, // delete[](void*, ulonglong)
477 {LibFunc_msvc_delete_array_ptr32_nothrow, {2, MallocFamily::MSVCArrayNew}}, // delete[](void*, nothrow)
478 {LibFunc_msvc_delete_array_ptr64_nothrow, {2, MallocFamily::MSVCArrayNew}}, // delete[](void*, nothrow)
479 {LibFunc___kmpc_free_shared, {2, MallocFamily::KmpcAllocShared}}, // OpenMP Offloading RTL free
480 {LibFunc_ZdlPvSt11align_val_tRKSt9nothrow_t, {3, MallocFamily::CPPNewAligned}}, // delete(void*, align_val_t, nothrow)
481 {LibFunc_ZdaPvSt11align_val_tRKSt9nothrow_t, {3, MallocFamily::CPPNewArrayAligned}}, // delete[](void*, align_val_t, nothrow)
482 {LibFunc_ZdlPvjSt11align_val_t, {3, MallocFamily::CPPNewAligned}}, // delete(void*, unsigned int, align_val_t)
483 {LibFunc_ZdlPvmSt11align_val_t, {3, MallocFamily::CPPNewAligned}}, // delete(void*, unsigned long, align_val_t)
484 {LibFunc_ZdaPvjSt11align_val_t, {3, MallocFamily::CPPNewArrayAligned}}, // delete[](void*, unsigned int, align_val_t)
485 {LibFunc_ZdaPvmSt11align_val_t, {3, MallocFamily::CPPNewArrayAligned}}, // delete[](void*, unsigned long, align_val_t)
486};
487// clang-format on
488
489std::optional<FreeFnsTy> getFreeFunctionDataForFunction(const Function *Callee,
490 const LibFunc TLIFn) {
491 const auto *Iter =
492 find_if(FreeFnData, [TLIFn](const std::pair<LibFunc, FreeFnsTy> &P) {
493 return P.first == TLIFn;
494 });
495 if (Iter == std::end(FreeFnData))
496 return std::nullopt;
497 return Iter->second;
498}
499
500std::optional<StringRef>
502 if (const Function *Callee = getCalledFunction(I)) {
503 LibFunc TLIFn;
504 if (TLI && TLI->getLibFunc(*Callee, TLIFn) && TLI->has(TLIFn)) {
505 // Callee is some known library function.
506 const auto AllocData =
508 if (AllocData)
509 return mangledNameForMallocFamily(AllocData->Family);
510 const auto FreeData = getFreeFunctionDataForFunction(Callee, TLIFn);
511 if (FreeData)
512 return mangledNameForMallocFamily(FreeData->Family);
513 }
514 }
515
516 // Callee isn't a known library function, still check attributes.
517 if (checkFnAllocKind(I, AllocFnKind::Free | AllocFnKind::Alloc |
518 AllocFnKind::Realloc)) {
519 Attribute Attr = cast<CallBase>(I)->getFnAttr("alloc-family");
520 if (Attr.isValid())
521 return Attr.getValueAsString();
522 }
523 return std::nullopt;
524}
525
526/// isLibFreeFunction - Returns true if the function is a builtin free()
527bool llvm::isLibFreeFunction(const Function *F, const LibFunc TLIFn) {
528 std::optional<FreeFnsTy> FnData = getFreeFunctionDataForFunction(F, TLIFn);
529 if (!FnData)
530 return checkFnAllocKind(F, AllocFnKind::Free);
531
532 // Check free prototype.
533 // FIXME: workaround for PR5130, this will be obsolete when a nobuiltin
534 // attribute will exist.
535 FunctionType *FTy = F->getFunctionType();
536 if (!FTy->getReturnType()->isVoidTy())
537 return false;
538 if (FTy->getNumParams() != FnData->NumParams)
539 return false;
540 if (!FTy->getParamType(0)->isPointerTy())
541 return false;
542
543 return true;
544}
545
547 if (const Function *Callee = getCalledFunction(CB)) {
548 LibFunc TLIFn;
549 if (TLI && TLI->getLibFunc(*Callee, TLIFn) && TLI->has(TLIFn) &&
550 isLibFreeFunction(Callee, TLIFn)) {
551 // All currently supported free functions free the first argument.
552 return CB->getArgOperand(0);
553 }
554 }
555
556 if (checkFnAllocKind(CB, AllocFnKind::Free))
557 return CB->getArgOperandWithAttribute(Attribute::AllocatedPointer);
558
559 return nullptr;
560}
561
562//===----------------------------------------------------------------------===//
563// Utility functions to compute size of objects.
564//
566 APInt Size = Data.Size;
567 APInt Offset = Data.Offset;
568 if (Offset.isNegative() || Size.ult(Offset))
569 return APInt(Size.getBitWidth(), 0);
570 return Size - Offset;
571}
572
573/// Compute the size of the object pointed by Ptr. Returns true and the
574/// object size in Size if successful, and false otherwise.
575/// If RoundToAlign is true, then Size is rounded up to the alignment of
576/// allocas, byval arguments, and global variables.
578 const TargetLibraryInfo *TLI, ObjectSizeOpts Opts) {
579 ObjectSizeOffsetVisitor Visitor(DL, TLI, Ptr->getContext(), Opts);
580 SizeOffsetAPInt Data = Visitor.compute(const_cast<Value *>(Ptr));
581 if (!Data.bothKnown())
582 return false;
583
585 return true;
586}
587
589 const DataLayout &DL,
590 const TargetLibraryInfo *TLI,
591 bool MustSucceed) {
592 return lowerObjectSizeCall(ObjectSize, DL, TLI, /*AAResults=*/nullptr,
593 MustSucceed);
594}
595
597 IntrinsicInst *ObjectSize, const DataLayout &DL,
598 const TargetLibraryInfo *TLI, AAResults *AA, bool MustSucceed,
599 SmallVectorImpl<Instruction *> *InsertedInstructions) {
600 assert(ObjectSize->getIntrinsicID() == Intrinsic::objectsize &&
601 "ObjectSize must be a call to llvm.objectsize!");
602
603 bool MaxVal = cast<ConstantInt>(ObjectSize->getArgOperand(1))->isZero();
604 ObjectSizeOpts EvalOptions;
605 EvalOptions.AA = AA;
606
607 // Unless we have to fold this to something, try to be as accurate as
608 // possible.
609 if (MustSucceed)
610 EvalOptions.EvalMode =
611 MaxVal ? ObjectSizeOpts::Mode::Max : ObjectSizeOpts::Mode::Min;
612 else
613 EvalOptions.EvalMode = ObjectSizeOpts::Mode::ExactSizeFromOffset;
614
615 EvalOptions.NullIsUnknownSize =
616 cast<ConstantInt>(ObjectSize->getArgOperand(2))->isOne();
617
618 auto *ResultType = cast<IntegerType>(ObjectSize->getType());
619 bool StaticOnly = cast<ConstantInt>(ObjectSize->getArgOperand(3))->isZero();
620 if (StaticOnly) {
621 // FIXME: Does it make sense to just return a failure value if the size won't
622 // fit in the output and `!MustSucceed`?
624 if (getObjectSize(ObjectSize->getArgOperand(0), Size, DL, TLI, EvalOptions) &&
625 isUIntN(ResultType->getBitWidth(), Size))
626 return ConstantInt::get(ResultType, Size);
627 } else {
628 LLVMContext &Ctx = ObjectSize->getFunction()->getContext();
629 ObjectSizeOffsetEvaluator Eval(DL, TLI, Ctx, EvalOptions);
630 SizeOffsetValue SizeOffsetPair = Eval.compute(ObjectSize->getArgOperand(0));
631
632 if (SizeOffsetPair != ObjectSizeOffsetEvaluator::unknown()) {
635 if (InsertedInstructions)
636 InsertedInstructions->push_back(I);
637 }));
638 Builder.SetInsertPoint(ObjectSize);
639
640 Value *Size = SizeOffsetPair.Size;
641 Value *Offset = SizeOffsetPair.Offset;
642
643 // If we've outside the end of the object, then we can always access
644 // exactly 0 bytes.
645 Value *ResultSize = Builder.CreateSub(Size, Offset);
646 Value *UseZero = Builder.CreateICmpULT(Size, Offset);
647 ResultSize = Builder.CreateZExtOrTrunc(ResultSize, ResultType);
648 Value *Ret = Builder.CreateSelect(
649 UseZero, ConstantInt::get(ResultType, 0), ResultSize);
650
651 // The non-constant size expression cannot evaluate to -1.
652 if (!isa<Constant>(Size) || !isa<Constant>(Offset))
653 Builder.CreateAssumption(
654 Builder.CreateICmpNE(Ret, ConstantInt::get(ResultType, -1)));
655
656 return Ret;
657 }
658 }
659
660 if (!MustSucceed)
661 return nullptr;
662
663 return ConstantInt::get(ResultType, MaxVal ? -1ULL : 0);
664}
665
666STATISTIC(ObjectVisitorArgument,
667 "Number of arguments with unsolved size and offset");
668STATISTIC(ObjectVisitorLoad,
669 "Number of load instructions with unsolved size and offset");
670
671APInt ObjectSizeOffsetVisitor::align(APInt Size, MaybeAlign Alignment) {
672 if (Options.RoundToAlign && Alignment)
673 return APInt(IntTyBits, alignTo(Size.getZExtValue(), *Alignment));
674 return Size;
675}
676
678 const TargetLibraryInfo *TLI,
679 LLVMContext &Context,
681 : DL(DL), TLI(TLI), Options(Options) {
682 // Pointer size must be rechecked for each object visited since it could have
683 // a different address space.
684}
685
687 InstructionsVisited = 0;
688 return computeImpl(V);
689}
690
691SizeOffsetAPInt ObjectSizeOffsetVisitor::computeImpl(Value *V) {
692 unsigned InitialIntTyBits = DL.getIndexTypeSizeInBits(V->getType());
693
694 // Stripping pointer casts can strip address space casts which can change the
695 // index type size. The invariant is that we use the value type to determine
696 // the index type size and if we stripped address space casts we have to
697 // readjust the APInt as we pass it upwards in order for the APInt to match
698 // the type the caller passed in.
699 APInt Offset(InitialIntTyBits, 0);
700 V = V->stripAndAccumulateConstantOffsets(
701 DL, Offset, /* AllowNonInbounds */ true, /* AllowInvariantGroup */ true);
702
703 // Later we use the index type size and zero but it will match the type of the
704 // value that is passed to computeImpl.
705 IntTyBits = DL.getIndexTypeSizeInBits(V->getType());
706 Zero = APInt::getZero(IntTyBits);
707
708 SizeOffsetAPInt SOT = computeValue(V);
709
710 bool IndexTypeSizeChanged = InitialIntTyBits != IntTyBits;
711 if (!IndexTypeSizeChanged && Offset.isZero())
712 return SOT;
713
714 // We stripped an address space cast that changed the index type size or we
715 // accumulated some constant offset (or both). Readjust the bit width to match
716 // the argument index type size and apply the offset, as required.
717 if (IndexTypeSizeChanged) {
718 if (SOT.knownSize() && !::CheckedZextOrTrunc(SOT.Size, InitialIntTyBits))
719 SOT.Size = APInt();
720 if (SOT.knownOffset() &&
721 !::CheckedZextOrTrunc(SOT.Offset, InitialIntTyBits))
722 SOT.Offset = APInt();
723 }
724 // If the computed offset is "unknown" we cannot add the stripped offset.
725 return {SOT.Size,
726 SOT.Offset.getBitWidth() > 1 ? SOT.Offset + Offset : SOT.Offset};
727}
728
729SizeOffsetAPInt ObjectSizeOffsetVisitor::computeValue(Value *V) {
730 if (Instruction *I = dyn_cast<Instruction>(V)) {
731 // If we have already seen this instruction, bail out. Cycles can happen in
732 // unreachable code after constant propagation.
733 auto P = SeenInsts.try_emplace(I, ObjectSizeOffsetVisitor::unknown());
734 if (!P.second)
735 return P.first->second;
736 ++InstructionsVisited;
737 if (InstructionsVisited > ObjectSizeOffsetVisitorMaxVisitInstructions)
738 return ObjectSizeOffsetVisitor::unknown();
739 SizeOffsetAPInt Res = visit(*I);
740 // Cache the result for later visits. If we happened to visit this during
741 // the above recursion, we would consider it unknown until now.
742 SeenInsts[I] = Res;
743 return Res;
744 }
745 if (Argument *A = dyn_cast<Argument>(V))
746 return visitArgument(*A);
747 if (ConstantPointerNull *P = dyn_cast<ConstantPointerNull>(V))
749 if (GlobalAlias *GA = dyn_cast<GlobalAlias>(V))
750 return visitGlobalAlias(*GA);
751 if (GlobalVariable *GV = dyn_cast<GlobalVariable>(V))
752 return visitGlobalVariable(*GV);
753 if (UndefValue *UV = dyn_cast<UndefValue>(V))
754 return visitUndefValue(*UV);
755
756 LLVM_DEBUG(dbgs() << "ObjectSizeOffsetVisitor::compute() unhandled value: "
757 << *V << '\n');
758 return ObjectSizeOffsetVisitor::unknown();
759}
760
761bool ObjectSizeOffsetVisitor::CheckedZextOrTrunc(APInt &I) {
762 return ::CheckedZextOrTrunc(I, IntTyBits);
763}
764
766 TypeSize ElemSize = DL.getTypeAllocSize(I.getAllocatedType());
767 if (ElemSize.isScalable() && Options.EvalMode != ObjectSizeOpts::Mode::Min)
768 return ObjectSizeOffsetVisitor::unknown();
769 APInt Size(IntTyBits, ElemSize.getKnownMinValue());
770 if (!I.isArrayAllocation())
771 return SizeOffsetAPInt(align(Size, I.getAlign()), Zero);
772
773 Value *ArraySize = I.getArraySize();
774 if (const ConstantInt *C = dyn_cast<ConstantInt>(ArraySize)) {
775 APInt NumElems = C->getValue();
776 if (!CheckedZextOrTrunc(NumElems))
777 return ObjectSizeOffsetVisitor::unknown();
778
779 bool Overflow;
780 Size = Size.umul_ov(NumElems, Overflow);
781 return Overflow ? ObjectSizeOffsetVisitor::unknown()
782 : SizeOffsetAPInt(align(Size, I.getAlign()), Zero);
783 }
784 return ObjectSizeOffsetVisitor::unknown();
785}
786
788 Type *MemoryTy = A.getPointeeInMemoryValueType();
789 // No interprocedural analysis is done at the moment.
790 if (!MemoryTy|| !MemoryTy->isSized()) {
791 ++ObjectVisitorArgument;
792 return ObjectSizeOffsetVisitor::unknown();
793 }
794
795 APInt Size(IntTyBits, DL.getTypeAllocSize(MemoryTy));
796 return SizeOffsetAPInt(align(Size, A.getParamAlign()), Zero);
797}
798
800 if (std::optional<APInt> Size = getAllocSize(&CB, TLI))
801 return SizeOffsetAPInt(*Size, Zero);
802 return ObjectSizeOffsetVisitor::unknown();
803}
804
807 // If null is unknown, there's nothing we can do. Additionally, non-zero
808 // address spaces can make use of null, so we don't presume to know anything
809 // about that.
810 //
811 // TODO: How should this work with address space casts? We currently just drop
812 // them on the floor, but it's unclear what we should do when a NULL from
813 // addrspace(1) gets casted to addrspace(0) (or vice-versa).
814 if (Options.NullIsUnknownSize || CPN.getType()->getAddressSpace())
815 return ObjectSizeOffsetVisitor::unknown();
816 return SizeOffsetAPInt(Zero, Zero);
817}
818
821 return ObjectSizeOffsetVisitor::unknown();
822}
823
826 // Easy cases were already folded by previous passes.
827 return ObjectSizeOffsetVisitor::unknown();
828}
829
831 if (GA.isInterposable())
832 return ObjectSizeOffsetVisitor::unknown();
833 return computeImpl(GA.getAliasee());
834}
835
838 if (!GV.getValueType()->isSized() || GV.hasExternalWeakLinkage() ||
839 ((!GV.hasInitializer() || GV.isInterposable()) &&
841 return ObjectSizeOffsetVisitor::unknown();
842
843 APInt Size(IntTyBits, DL.getTypeAllocSize(GV.getValueType()));
844 return SizeOffsetAPInt(align(Size, GV.getAlign()), Zero);
845}
846
848 // clueless
849 return ObjectSizeOffsetVisitor::unknown();
850}
851
852SizeOffsetAPInt ObjectSizeOffsetVisitor::findLoadSizeOffset(
855 unsigned &ScannedInstCount) {
856 constexpr unsigned MaxInstsToScan = 128;
857
858 auto Where = VisitedBlocks.find(&BB);
859 if (Where != VisitedBlocks.end())
860 return Where->second;
861
862 auto Unknown = [&BB, &VisitedBlocks]() {
863 return VisitedBlocks[&BB] = ObjectSizeOffsetVisitor::unknown();
864 };
865 auto Known = [&BB, &VisitedBlocks](SizeOffsetAPInt SO) {
866 return VisitedBlocks[&BB] = SO;
867 };
868
869 do {
870 Instruction &I = *From;
871
872 if (I.isDebugOrPseudoInst())
873 continue;
874
875 if (++ScannedInstCount > MaxInstsToScan)
876 return Unknown();
877
878 if (!I.mayWriteToMemory())
879 continue;
880
881 if (auto *SI = dyn_cast<StoreInst>(&I)) {
882 AliasResult AR =
883 Options.AA->alias(SI->getPointerOperand(), Load.getPointerOperand());
884 switch ((AliasResult::Kind)AR) {
886 continue;
888 if (SI->getValueOperand()->getType()->isPointerTy())
889 return Known(computeImpl(SI->getValueOperand()));
890 else
891 return Unknown(); // No handling of non-pointer values by `compute`.
892 default:
893 return Unknown();
894 }
895 }
896
897 if (auto *CB = dyn_cast<CallBase>(&I)) {
899 // Bail out on indirect call.
900 if (!Callee)
901 return Unknown();
902
903 LibFunc TLIFn;
904 if (!TLI || !TLI->getLibFunc(*CB->getCalledFunction(), TLIFn) ||
905 !TLI->has(TLIFn))
906 return Unknown();
907
908 // TODO: There's probably more interesting case to support here.
909 if (TLIFn != LibFunc_posix_memalign)
910 return Unknown();
911
912 AliasResult AR =
913 Options.AA->alias(CB->getOperand(0), Load.getPointerOperand());
914 switch ((AliasResult::Kind)AR) {
916 continue;
918 break;
919 default:
920 return Unknown();
921 }
922
923 // Is the error status of posix_memalign correctly checked? If not it
924 // would be incorrect to assume it succeeds and load doesn't see the
925 // previous value.
926 std::optional<bool> Checked = isImpliedByDomCondition(
927 ICmpInst::ICMP_EQ, CB, ConstantInt::get(CB->getType(), 0), &Load, DL);
928 if (!Checked || !*Checked)
929 return Unknown();
930
931 Value *Size = CB->getOperand(2);
932 auto *C = dyn_cast<ConstantInt>(Size);
933 if (!C)
934 return Unknown();
935
936 return Known({C->getValue(), APInt(C->getValue().getBitWidth(), 0)});
937 }
938
939 return Unknown();
940 } while (From-- != BB.begin());
941
942 SmallVector<SizeOffsetAPInt> PredecessorSizeOffsets;
943 for (auto *PredBB : predecessors(&BB)) {
944 PredecessorSizeOffsets.push_back(findLoadSizeOffset(
945 Load, *PredBB, BasicBlock::iterator(PredBB->getTerminator()),
946 VisitedBlocks, ScannedInstCount));
947 if (!PredecessorSizeOffsets.back().bothKnown())
948 return Unknown();
949 }
950
951 if (PredecessorSizeOffsets.empty())
952 return Unknown();
953
954 return Known(std::accumulate(
955 PredecessorSizeOffsets.begin() + 1, PredecessorSizeOffsets.end(),
956 PredecessorSizeOffsets.front(),
957 [this](SizeOffsetAPInt LHS, SizeOffsetAPInt RHS) {
958 return combineSizeOffset(LHS, RHS);
959 }));
960}
961
963 if (!Options.AA) {
964 ++ObjectVisitorLoad;
965 return ObjectSizeOffsetVisitor::unknown();
966 }
967
969 unsigned ScannedInstCount = 0;
970 SizeOffsetAPInt SO =
971 findLoadSizeOffset(LI, *LI.getParent(), BasicBlock::iterator(LI),
972 VisitedBlocks, ScannedInstCount);
973 if (!SO.bothKnown())
974 ++ObjectVisitorLoad;
975 return SO;
976}
977
979ObjectSizeOffsetVisitor::combineSizeOffset(SizeOffsetAPInt LHS,
980 SizeOffsetAPInt RHS) {
981 if (!LHS.bothKnown() || !RHS.bothKnown())
982 return ObjectSizeOffsetVisitor::unknown();
983
984 switch (Options.EvalMode) {
986 return (getSizeWithOverflow(LHS).slt(getSizeWithOverflow(RHS))) ? LHS : RHS;
988 return (getSizeWithOverflow(LHS).sgt(getSizeWithOverflow(RHS))) ? LHS : RHS;
990 return (getSizeWithOverflow(LHS).eq(getSizeWithOverflow(RHS)))
991 ? LHS
992 : ObjectSizeOffsetVisitor::unknown();
994 return LHS == RHS ? LHS : ObjectSizeOffsetVisitor::unknown();
995 }
996 llvm_unreachable("missing an eval mode");
997}
998
1000 if (PN.getNumIncomingValues() == 0)
1001 return ObjectSizeOffsetVisitor::unknown();
1002 auto IncomingValues = PN.incoming_values();
1003 return std::accumulate(IncomingValues.begin() + 1, IncomingValues.end(),
1004 computeImpl(*IncomingValues.begin()),
1005 [this](SizeOffsetAPInt LHS, Value *VRHS) {
1006 return combineSizeOffset(LHS, computeImpl(VRHS));
1007 });
1008}
1009
1011 return combineSizeOffset(computeImpl(I.getTrueValue()),
1012 computeImpl(I.getFalseValue()));
1013}
1014
1016 return SizeOffsetAPInt(Zero, Zero);
1017}
1018
1020 LLVM_DEBUG(dbgs() << "ObjectSizeOffsetVisitor unknown instruction:" << I
1021 << '\n');
1022 return ObjectSizeOffsetVisitor::unknown();
1023}
1024
1025// Just set these right here...
1027 : SizeOffsetType(SOT.Size, SOT.Offset) {}
1028
1030 const DataLayout &DL, const TargetLibraryInfo *TLI, LLVMContext &Context,
1031 ObjectSizeOpts EvalOpts)
1032 : DL(DL), TLI(TLI), Context(Context),
1033 Builder(Context, TargetFolder(DL),
1035 [&](Instruction *I) { InsertedInstructions.insert(I); })),
1036 EvalOpts(EvalOpts) {
1037 // IntTy and Zero must be set for each compute() since the address space may
1038 // be different for later objects.
1039}
1040
1042 // XXX - Are vectors of pointers possible here?
1043 IntTy = cast<IntegerType>(DL.getIndexType(V->getType()));
1044 Zero = ConstantInt::get(IntTy, 0);
1045
1046 SizeOffsetValue Result = compute_(V);
1047
1048 if (!Result.bothKnown()) {
1049 // Erase everything that was computed in this iteration from the cache, so
1050 // that no dangling references are left behind. We could be a bit smarter if
1051 // we kept a dependency graph. It's probably not worth the complexity.
1052 for (const Value *SeenVal : SeenVals) {
1053 CacheMapTy::iterator CacheIt = CacheMap.find(SeenVal);
1054 // non-computable results can be safely cached
1055 if (CacheIt != CacheMap.end() && CacheIt->second.anyKnown())
1056 CacheMap.erase(CacheIt);
1057 }
1058
1059 // Erase any instructions we inserted as part of the traversal.
1060 for (Instruction *I : InsertedInstructions) {
1061 I->replaceAllUsesWith(PoisonValue::get(I->getType()));
1062 I->eraseFromParent();
1063 }
1064 }
1065
1066 SeenVals.clear();
1067 InsertedInstructions.clear();
1068 return Result;
1069}
1070
1071SizeOffsetValue ObjectSizeOffsetEvaluator::compute_(Value *V) {
1072 ObjectSizeOffsetVisitor Visitor(DL, TLI, Context, EvalOpts);
1073 SizeOffsetAPInt Const = Visitor.compute(V);
1074 if (Const.bothKnown())
1075 return SizeOffsetValue(ConstantInt::get(Context, Const.Size),
1076 ConstantInt::get(Context, Const.Offset));
1077
1078 V = V->stripPointerCasts();
1079
1080 // Check cache.
1081 CacheMapTy::iterator CacheIt = CacheMap.find(V);
1082 if (CacheIt != CacheMap.end())
1083 return CacheIt->second;
1084
1085 // Always generate code immediately before the instruction being
1086 // processed, so that the generated code dominates the same BBs.
1087 BuilderTy::InsertPointGuard Guard(Builder);
1088 if (Instruction *I = dyn_cast<Instruction>(V))
1089 Builder.SetInsertPoint(I);
1090
1091 // Now compute the size and offset.
1092 SizeOffsetValue Result;
1093
1094 // Record the pointers that were handled in this run, so that they can be
1095 // cleaned later if something fails. We also use this set to break cycles that
1096 // can occur in dead code.
1097 if (!SeenVals.insert(V).second) {
1099 } else if (GEPOperator *GEP = dyn_cast<GEPOperator>(V)) {
1100 Result = visitGEPOperator(*GEP);
1101 } else if (Instruction *I = dyn_cast<Instruction>(V)) {
1102 Result = visit(*I);
1103 } else if (isa<Argument>(V) ||
1104 (isa<ConstantExpr>(V) &&
1105 cast<ConstantExpr>(V)->getOpcode() == Instruction::IntToPtr) ||
1106 isa<GlobalAlias>(V) ||
1107 isa<GlobalVariable>(V)) {
1108 // Ignore values where we cannot do more than ObjectSizeVisitor.
1110 } else {
1111 LLVM_DEBUG(
1112 dbgs() << "ObjectSizeOffsetEvaluator::compute() unhandled value: " << *V
1113 << '\n');
1115 }
1116
1117 // Don't reuse CacheIt since it may be invalid at this point.
1118 CacheMap[V] = SizeOffsetWeakTrackingVH(Result);
1119 return Result;
1120}
1121
1123 if (!I.getAllocatedType()->isSized())
1125
1126 // must be a VLA or vscale.
1127 assert(I.isArrayAllocation() || I.getAllocatedType()->isScalableTy());
1128
1129 // If needed, adjust the alloca's operand size to match the pointer indexing
1130 // size. Subsequent math operations expect the types to match.
1131 Value *ArraySize = Builder.CreateZExtOrTrunc(
1132 I.getArraySize(),
1133 DL.getIndexType(I.getContext(), DL.getAllocaAddrSpace()));
1134 assert(ArraySize->getType() == Zero->getType() &&
1135 "Expected zero constant to have pointer index type");
1136
1137 Value *Size = Builder.CreateTypeSize(
1138 ArraySize->getType(), DL.getTypeAllocSize(I.getAllocatedType()));
1139 Size = Builder.CreateMul(Size, ArraySize);
1140 return SizeOffsetValue(Size, Zero);
1141}
1142
1144 std::optional<AllocFnsTy> FnData = getAllocationSize(&CB, TLI);
1145 if (!FnData)
1147
1148 // Handle strdup-like functions separately.
1149 if (FnData->AllocTy == StrDupLike) {
1150 // TODO: implement evaluation of strdup/strndup
1152 }
1153
1154 Value *FirstArg = CB.getArgOperand(FnData->FstParam);
1155 FirstArg = Builder.CreateZExtOrTrunc(FirstArg, IntTy);
1156 if (FnData->SndParam < 0)
1157 return SizeOffsetValue(FirstArg, Zero);
1158
1159 Value *SecondArg = CB.getArgOperand(FnData->SndParam);
1160 SecondArg = Builder.CreateZExtOrTrunc(SecondArg, IntTy);
1161 Value *Size = Builder.CreateMul(FirstArg, SecondArg);
1162 return SizeOffsetValue(Size, Zero);
1163}
1164
1168}
1169
1173}
1174
1176 SizeOffsetValue PtrData = compute_(GEP.getPointerOperand());
1177 if (!PtrData.bothKnown())
1179
1180 Value *Offset = emitGEPOffset(&Builder, DL, &GEP, /*NoAssumptions=*/true);
1181 Offset = Builder.CreateAdd(PtrData.Offset, Offset);
1182 return SizeOffsetValue(PtrData.Size, Offset);
1183}
1184
1186 // clueless
1188}
1189
1192}
1193
1195 // Create 2 PHIs: one for size and another for offset.
1196 PHINode *SizePHI = Builder.CreatePHI(IntTy, PHI.getNumIncomingValues());
1197 PHINode *OffsetPHI = Builder.CreatePHI(IntTy, PHI.getNumIncomingValues());
1198
1199 // Insert right away in the cache to handle recursive PHIs.
1200 CacheMap[&PHI] = SizeOffsetWeakTrackingVH(SizePHI, OffsetPHI);
1201
1202 // Compute offset/size for each PHI incoming pointer.
1203 for (unsigned i = 0, e = PHI.getNumIncomingValues(); i != e; ++i) {
1204 BasicBlock *IncomingBlock = PHI.getIncomingBlock(i);
1205 Builder.SetInsertPoint(IncomingBlock, IncomingBlock->getFirstInsertionPt());
1206 SizeOffsetValue EdgeData = compute_(PHI.getIncomingValue(i));
1207
1208 if (!EdgeData.bothKnown()) {
1209 OffsetPHI->replaceAllUsesWith(PoisonValue::get(IntTy));
1210 OffsetPHI->eraseFromParent();
1211 InsertedInstructions.erase(OffsetPHI);
1212 SizePHI->replaceAllUsesWith(PoisonValue::get(IntTy));
1213 SizePHI->eraseFromParent();
1214 InsertedInstructions.erase(SizePHI);
1216 }
1217 SizePHI->addIncoming(EdgeData.Size, IncomingBlock);
1218 OffsetPHI->addIncoming(EdgeData.Offset, IncomingBlock);
1219 }
1220
1221 Value *Size = SizePHI, *Offset = OffsetPHI;
1222 if (Value *Tmp = SizePHI->hasConstantValue()) {
1223 Size = Tmp;
1224 SizePHI->replaceAllUsesWith(Size);
1225 SizePHI->eraseFromParent();
1226 InsertedInstructions.erase(SizePHI);
1227 }
1228 if (Value *Tmp = OffsetPHI->hasConstantValue()) {
1229 Offset = Tmp;
1230 OffsetPHI->replaceAllUsesWith(Offset);
1231 OffsetPHI->eraseFromParent();
1232 InsertedInstructions.erase(OffsetPHI);
1233 }
1234 return SizeOffsetValue(Size, Offset);
1235}
1236
1238 SizeOffsetValue TrueSide = compute_(I.getTrueValue());
1239 SizeOffsetValue FalseSide = compute_(I.getFalseValue());
1240
1241 if (!TrueSide.bothKnown() || !FalseSide.bothKnown())
1243 if (TrueSide == FalseSide)
1244 return TrueSide;
1245
1246 Value *Size =
1247 Builder.CreateSelect(I.getCondition(), TrueSide.Size, FalseSide.Size);
1248 Value *Offset =
1249 Builder.CreateSelect(I.getCondition(), TrueSide.Offset, FalseSide.Offset);
1250 return SizeOffsetValue(Size, Offset);
1251}
1252
1254 LLVM_DEBUG(dbgs() << "ObjectSizeOffsetEvaluator unknown instruction:" << I
1255 << '\n');
1257}
Rewrite undef for PHI
This file implements a class to represent arbitrary precision integral constant values and operations...
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
This file contains the simple types necessary to represent the attributes associated with functions a...
BlockVerifier::State From
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
#define LLVM_DEBUG(X)
Definition: Debug.h:101
uint64_t Size
Hexagon Common GEP
static LVOptions Options
Definition: LVOptions.cpp:25
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
MallocFamily
static AllocFnKind getAllocFnKind(const Value *V)
static std::optional< AllocFnsTy > getAllocationDataForFunction(const Function *Callee, AllocType AllocTy, const TargetLibraryInfo *TLI)
Returns the allocation data for the given value if it's a call to a known allocation function.
static std::optional< AllocFnsTy > getAllocationData(const Value *V, AllocType AllocTy, const TargetLibraryInfo *TLI)
std::optional< FreeFnsTy > getFreeFunctionDataForFunction(const Function *Callee, const LibFunc TLIFn)
static bool checkFnAllocKind(const Value *V, AllocFnKind Wanted)
StringRef mangledNameForMallocFamily(const MallocFamily &Family)
static std::optional< AllocFnsTy > getAllocationSize(const CallBase *CB, const TargetLibraryInfo *TLI)
static bool CheckedZextOrTrunc(APInt &I, unsigned IntTyBits)
When we're compiling N-bit code, and the user uses parameters that are greater than N bits (e....
static const std::pair< LibFunc, FreeFnsTy > FreeFnData[]
static const Function * getCalledFunction(const Value *V)
static cl::opt< unsigned > ObjectSizeOffsetVisitorMaxVisitInstructions("object-size-offset-visitor-max-visit-instructions", cl::desc("Maximum number of instructions for ObjectSizeOffsetVisitor to " "look at"), cl::init(100))
static const std::pair< LibFunc, AllocFnsTy > AllocationFnData[]
AllocType
@ MallocLike
@ AnyAlloc
@ AllocLike
@ StrDupLike
@ OpNewLike
@ MallocOrOpNewLike
static APInt getSizeWithOverflow(const SizeOffsetAPInt &Data)
#define P(N)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file contains some templates that are useful if you are working with the STL at all.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition: Statistic.h:167
static std::optional< unsigned > getOpcode(ArrayRef< VPValue * > Values)
Returns the opcode of Values or ~0 if they do not all agree.
Definition: VPlanSLP.cpp:191
Value * RHS
Value * LHS
AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB)
The main low level interface to the alias analysis implementation.
Class for arbitrary precision integers.
Definition: APInt.h:78
APInt zext(unsigned width) const
Zero extend to a new width.
Definition: APInt.cpp:981
uint64_t getZExtValue() const
Get zero extended value.
Definition: APInt.h:1500
unsigned getBitWidth() const
Return the number of bits in the APInt.
Definition: APInt.h:1448
static APInt getZero(unsigned numBits)
Get the '0' value for the specified bit-width.
Definition: APInt.h:180
The possible results of an alias query.
Definition: AliasAnalysis.h:82
@ NoAlias
The two locations do not alias at all.
@ MustAlias
The two locations precisely alias each other.
an instruction to allocate memory on the stack
Definition: Instructions.h:61
This class represents an incoming formal argument to a Function.
Definition: Argument.h:31
uint64_t getValueAsInt() const
Return the attribute's value as an integer.
Definition: Attributes.cpp:371
std::pair< unsigned, std::optional< unsigned > > getAllocSizeArgs() const
Returns the argument numbers for the allocsize attribute.
Definition: Attributes.cpp:454
StringRef getValueAsString() const
Return the attribute's value as a string.
Definition: Attributes.cpp:392
bool isValid() const
Return true if the attribute is any kind of attribute.
Definition: Attributes.h:203
LLVM Basic Block Representation.
Definition: BasicBlock.h:61
iterator begin()
Instruction iterator methods.
Definition: BasicBlock.h:448
const_iterator getFirstInsertionPt() const
Returns an iterator to the first instruction in this block that is suitable for inserting a non-PHI i...
Definition: BasicBlock.cpp:416
InstListType::iterator iterator
Instruction iterators...
Definition: BasicBlock.h:177
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
Definition: InstrTypes.h:1236
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
Definition: InstrTypes.h:1465
Attribute getFnAttr(StringRef Kind) const
Get the attribute of a given kind for the function.
Definition: InstrTypes.h:1705
Value * getArgOperand(unsigned i) const
Definition: InstrTypes.h:1410
Value * getArgOperandWithAttribute(Attribute::AttrKind Kind) const
If one of the arguments has the specified attribute, returns its operand value.
unsigned arg_size() const
Definition: InstrTypes.h:1408
@ ICMP_EQ
equal
Definition: InstrTypes.h:778
This is the shared class of boolean and integer constants.
Definition: Constants.h:81
const APInt & getValue() const
Return the constant as an APInt value reference.
Definition: Constants.h:146
A constant pointer value that points to null.
Definition: Constants.h:549
PointerType * getType() const
Specialize the getType() method to always return an PointerType, which reduces the amount of casting ...
Definition: Constants.h:565
This is an important base class in LLVM.
Definition: Constant.h:42
static Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
Definition: Constants.cpp:370
A parsed version of the target data layout string in and methods for querying it.
Definition: DataLayout.h:109
unsigned getIndexTypeSizeInBits(Type *Ty) const
Layout size of the index used in GEP calculation.
Definition: DataLayout.cpp:787
unsigned getAllocaAddrSpace() const
Definition: DataLayout.h:252
IntegerType * getIndexType(LLVMContext &C, unsigned AddressSpace) const
Returns the type of a GEP index in AddressSpace.
Definition: DataLayout.cpp:912
TypeSize getTypeAllocSize(Type *Ty) const
Returns the offset in bytes between successive objects of the specified type, including alignment pad...
Definition: DataLayout.h:480
iterator find(const_arg_type_t< KeyT > Val)
Definition: DenseMap.h:155
bool erase(const KeyT &Val)
Definition: DenseMap.h:336
DenseMapIterator< KeyT, ValueT, KeyInfoT, BucketT > iterator
Definition: DenseMap.h:71
iterator end()
Definition: DenseMap.h:84
This instruction extracts a single (scalar) element from a VectorType value.
This instruction extracts a struct member or array element value from an aggregate value.
Class to represent function types.
Definition: DerivedTypes.h:103
unsigned getNumParams() const
Return the number of fixed parameters this function type requires.
Definition: DerivedTypes.h:142
Type * getParamType(unsigned i) const
Parameter type accessors.
Definition: DerivedTypes.h:135
Type * getReturnType() const
Definition: DerivedTypes.h:124
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition: Function.cpp:380
const Constant * getAliasee() const
Definition: GlobalAlias.h:84
MaybeAlign getAlign() const
Returns the alignment of the given variable or function.
Definition: GlobalObject.h:80
bool hasExternalWeakLinkage() const
Definition: GlobalValue.h:529
bool isInterposable() const
Return true if this global's definition can be substituted with an arbitrary definition at link time ...
Definition: Globals.cpp:105
Type * getValueType() const
Definition: GlobalValue.h:296
bool hasInitializer() const
Definitions have initializers, declarations don't.
Value * CreateICmpULT(Value *LHS, Value *RHS, const Twine &Name="")
Definition: IRBuilder.h:2265
Value * CreateZExtOrTrunc(Value *V, Type *DestTy, const Twine &Name="")
Create a ZExt or Trunc from the integer value V to DestTy.
Definition: IRBuilder.h:2047
Value * CreateSelect(Value *C, Value *True, Value *False, const Twine &Name="", Instruction *MDFrom=nullptr)
Definition: IRBuilder.cpp:1091
Value * CreateTypeSize(Type *DstType, TypeSize Size)
Create an expression which evaluates to the number of units in Size at runtime.
Definition: IRBuilder.cpp:105
Value * CreateICmpNE(Value *LHS, Value *RHS, const Twine &Name="")
Definition: IRBuilder.h:2253
PHINode * CreatePHI(Type *Ty, unsigned NumReservedValues, const Twine &Name="")
Definition: IRBuilder.h:2405
Value * CreateSub(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Definition: IRBuilder.h:1349
CallInst * CreateAssumption(Value *Cond, ArrayRef< OperandBundleDef > OpBundles=std::nullopt)
Create an assume intrinsic call that allows the optimizer to assume that the provided condition will ...
Definition: IRBuilder.cpp:552
Value * CreateAdd(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Definition: IRBuilder.h:1332
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block.
Definition: IRBuilder.h:177
Value * CreateMul(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Definition: IRBuilder.h:1366
Provides an 'InsertHelper' that calls a user-provided callback after performing the default insertion...
Definition: IRBuilder.h:74
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition: IRBuilder.h:2674
InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
Definition: Instruction.cpp:92
const Function * getFunction() const
Return the function this instruction belongs to.
Definition: Instruction.cpp:70
const DataLayout & getDataLayout() const
Get the data layout of the module this instruction belongs to.
Definition: Instruction.cpp:74
This class represents a cast from an integer to a pointer.
A wrapper class for inspecting calls to intrinsic functions.
Definition: IntrinsicInst.h:48
Intrinsic::ID getIntrinsicID() const
Return the intrinsic ID of this intrinsic.
Definition: IntrinsicInst.h:55
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:67
An instruction for reading from memory.
Definition: Instructions.h:174
Evaluate the size and offset of an object pointed to by a Value*.
SizeOffsetValue visitExtractValueInst(ExtractValueInst &I)
SizeOffsetValue visitExtractElementInst(ExtractElementInst &I)
SizeOffsetValue compute(Value *V)
SizeOffsetValue visitInstruction(Instruction &I)
ObjectSizeOffsetEvaluator(const DataLayout &DL, const TargetLibraryInfo *TLI, LLVMContext &Context, ObjectSizeOpts EvalOpts={})
SizeOffsetValue visitLoadInst(LoadInst &I)
SizeOffsetValue visitGEPOperator(GEPOperator &GEP)
SizeOffsetValue visitIntToPtrInst(IntToPtrInst &)
SizeOffsetValue visitPHINode(PHINode &PHI)
SizeOffsetValue visitCallBase(CallBase &CB)
SizeOffsetValue visitSelectInst(SelectInst &I)
SizeOffsetValue visitAllocaInst(AllocaInst &I)
static SizeOffsetValue unknown()
Evaluate the size and offset of an object pointed to by a Value* statically.
SizeOffsetAPInt visitLoadInst(LoadInst &I)
SizeOffsetAPInt visitConstantPointerNull(ConstantPointerNull &)
SizeOffsetAPInt visitCallBase(CallBase &CB)
SizeOffsetAPInt visitInstruction(Instruction &I)
ObjectSizeOffsetVisitor(const DataLayout &DL, const TargetLibraryInfo *TLI, LLVMContext &Context, ObjectSizeOpts Options={})
SizeOffsetAPInt visitGlobalAlias(GlobalAlias &GA)
SizeOffsetAPInt visitIntToPtrInst(IntToPtrInst &)
SizeOffsetAPInt visitExtractElementInst(ExtractElementInst &I)
SizeOffsetAPInt compute(Value *V)
SizeOffsetAPInt visitExtractValueInst(ExtractValueInst &I)
SizeOffsetAPInt visitUndefValue(UndefValue &)
SizeOffsetAPInt visitPHINode(PHINode &)
SizeOffsetAPInt visitArgument(Argument &A)
SizeOffsetAPInt visitGlobalVariable(GlobalVariable &GV)
SizeOffsetAPInt visitSelectInst(SelectInst &I)
SizeOffsetAPInt visitAllocaInst(AllocaInst &I)
void addIncoming(Value *V, BasicBlock *BB)
Add an incoming value to the end of the PHI list.
op_range incoming_values()
Value * hasConstantValue() const
If the specified PHI node always merges together the same value, return the value,...
unsigned getNumIncomingValues() const
Return the number of incoming edges.
unsigned getAddressSpace() const
Return the address space of the Pointer type.
Definition: DerivedTypes.h:679
static PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
Definition: Constants.cpp:1852
This class represents the LLVM 'select' instruction.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
Definition: SmallPtrSet.h:368
bool empty() const
Definition: SmallVector.h:95
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:587
void push_back(const T &Elt)
Definition: SmallVector.h:427
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1210
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
TargetFolder - Create constants with target dependent folding.
Definition: TargetFolder.h:34
Provides information about what library functions are available for the current target.
bool has(LibFunc F) const
Tests whether a library function is available.
bool getLibFunc(StringRef funcName, LibFunc &F) const
Searches for a particular function name.
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
bool isPointerTy() const
True if this is an instance of PointerType.
Definition: Type.h:251
bool isSized(SmallPtrSetImpl< Type * > *Visited=nullptr) const
Return true if it makes sense to take the size of this type.
Definition: Type.h:298
bool isVoidTy() const
Return true if this is 'void'.
Definition: Type.h:139
'undef' values are things that do not have specified contents.
Definition: Constants.h:1398
static UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
Definition: Constants.cpp:1833
Value * getOperand(unsigned i) const
Definition: User.h:169
LLVM Value Representation.
Definition: Value.h:74
Type * getType() const
All values are typed, get the type of this value.
Definition: Value.h:255
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition: Value.cpp:534
constexpr bool isScalable() const
Returns whether the quantity is scaled by a runtime quantity (vscale).
Definition: TypeSize.h:171
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
Definition: TypeSize.h:168
An efficient, type-erasing, non-owning reference to a callable.
const ParentTy * getParent() const
Definition: ilist_node.h:32
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:443
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:480
Constant * getInitialValueOfAllocation(const Value *V, const TargetLibraryInfo *TLI, Type *Ty)
If this is a call to an allocation function that initializes memory to a fixed value,...
bool isUIntN(unsigned N, uint64_t x)
Checks if an unsigned integer fits into the given (dynamic) bit width.
Definition: MathExtras.h:255
AllocFnKind
Definition: Attributes.h:49
bool isRemovableAlloc(const CallBase *V, const TargetLibraryInfo *TLI)
Return true if this is a call to an allocation function that does not have side effects that we are r...
std::optional< StringRef > getAllocationFamily(const Value *I, const TargetLibraryInfo *TLI)
If a function is part of an allocation family (e.g.
Value * lowerObjectSizeCall(IntrinsicInst *ObjectSize, const DataLayout &DL, const TargetLibraryInfo *TLI, bool MustSucceed)
Try to turn a call to @llvm.objectsize into an integer value of the given Type.
Value * getAllocAlignment(const CallBase *V, const TargetLibraryInfo *TLI)
Gets the alignment argument for an aligned_alloc-like function, using either built-in knowledge based...
bool isLibFreeFunction(const Function *F, const LibFunc TLIFn)
isLibFreeFunction - Returns true if the function is a builtin free()
Value * getReallocatedOperand(const CallBase *CB)
If this is a call to a realloc function, return the reallocated operand.
bool isAllocLikeFn(const Value *V, const TargetLibraryInfo *TLI)
Tests if a value is a call or invoke to a library function that allocates memory (either malloc,...
bool getObjectSize(const Value *Ptr, uint64_t &Size, const DataLayout &DL, const TargetLibraryInfo *TLI, ObjectSizeOpts Opts={})
Compute the size of the object pointed by Ptr.
Value * emitGEPOffset(IRBuilderBase *Builder, const DataLayout &DL, User *GEP, bool NoAssumptions=false)
Given a getelementptr instruction/constantexpr, emit the code necessary to compute the offset from th...
Definition: Local.cpp:22
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
uint64_t GetStringLength(const Value *V, unsigned CharSize=8)
If we can compute the length of the string pointed to by the specified pointer, return 'len+1'.
bool isMallocOrCallocLikeFn(const Value *V, const TargetLibraryInfo *TLI)
Tests if a value is a call or invoke to a library function that allocates memory similar to malloc or...
bool isReallocLikeFn(const Function *F)
Tests if a function is a call or invoke to a library function that reallocates memory (e....
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition: Alignment.h:155
Value * getFreedOperand(const CallBase *CB, const TargetLibraryInfo *TLI)
If this if a call to a free function, return the freed operand.
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1749
auto predecessors(const MachineBasicBlock *BB)
bool isAllocationFn(const Value *V, const TargetLibraryInfo *TLI)
Tests if a value is a call or invoke to a library function that allocates or reallocates memory (eith...
std::optional< APInt > getAllocSize(const CallBase *CB, const TargetLibraryInfo *TLI, function_ref< const Value *(const Value *)> Mapper=[](const Value *V) { return V;})
Return the size of the requested allocation.
std::optional< bool > isImpliedByDomCondition(const Value *Cond, const Instruction *ContextI, const DataLayout &DL)
Return the boolean condition value in the context of the given instruction if it is known based on do...
bool isNewLikeFn(const Value *V, const TargetLibraryInfo *TLI)
Tests if a value is a call or invoke to a library function that allocates memory via new.
MallocFamily Family
unsigned NumParams
AllocType AllocTy
MallocFamily Family
unsigned NumParams
This struct is a compact representation of a valid (power of two) or undefined (0) alignment.
Definition: Alignment.h:117
Various options to control the behavior of getObjectSize.
bool NullIsUnknownSize
If this is true, null pointers in address space 0 will be treated as though they can't be evaluated.
Mode EvalMode
How we want to evaluate this object's size.
AAResults * AA
If set, used for more accurate evaluation.
bool RoundToAlign
Whether to round the result up to the alignment of allocas, byval arguments, and global variables.
@ ExactUnderlyingSizeAndOffset
All branches must be known and have the same underlying size and offset to be merged.
@ Max
Same as Min, except we pick the maximum size of all of the branches.
@ Min
Evaluate all branches of an unknown condition.
@ ExactSizeFromOffset
All branches must be known and have the same size, starting from the offset, to be merged.
SizeOffsetAPInt - Used by ObjectSizeOffsetVisitor, which works with APInts.
SizeOffsetType - A base template class for the object size visitors.
bool knownOffset() const
bool knownSize() const
bool bothKnown() const
SizeOffsetWeakTrackingVH - Used by ObjectSizeOffsetEvaluator in a DenseMap.