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 MaxVal ? Constant::getAllOnesValue(ResultType)
664 : Constant::getNullValue(ResultType);
665}
666
667STATISTIC(ObjectVisitorArgument,
668 "Number of arguments with unsolved size and offset");
669STATISTIC(ObjectVisitorLoad,
670 "Number of load instructions with unsolved size and offset");
671
672APInt ObjectSizeOffsetVisitor::align(APInt Size, MaybeAlign Alignment) {
673 if (Options.RoundToAlign && Alignment)
674 return APInt(IntTyBits, alignTo(Size.getZExtValue(), *Alignment));
675 return Size;
676}
677
679 const TargetLibraryInfo *TLI,
680 LLVMContext &Context,
682 : DL(DL), TLI(TLI), Options(Options) {
683 // Pointer size must be rechecked for each object visited since it could have
684 // a different address space.
685}
686
688 InstructionsVisited = 0;
689 return computeImpl(V);
690}
691
692SizeOffsetAPInt ObjectSizeOffsetVisitor::computeImpl(Value *V) {
693 unsigned InitialIntTyBits = DL.getIndexTypeSizeInBits(V->getType());
694
695 // Stripping pointer casts can strip address space casts which can change the
696 // index type size. The invariant is that we use the value type to determine
697 // the index type size and if we stripped address space casts we have to
698 // readjust the APInt as we pass it upwards in order for the APInt to match
699 // the type the caller passed in.
700 APInt Offset(InitialIntTyBits, 0);
701 V = V->stripAndAccumulateConstantOffsets(
702 DL, Offset, /* AllowNonInbounds */ true, /* AllowInvariantGroup */ true);
703
704 // Later we use the index type size and zero but it will match the type of the
705 // value that is passed to computeImpl.
706 IntTyBits = DL.getIndexTypeSizeInBits(V->getType());
707 Zero = APInt::getZero(IntTyBits);
708
709 SizeOffsetAPInt SOT = computeValue(V);
710
711 bool IndexTypeSizeChanged = InitialIntTyBits != IntTyBits;
712 if (!IndexTypeSizeChanged && Offset.isZero())
713 return SOT;
714
715 // We stripped an address space cast that changed the index type size or we
716 // accumulated some constant offset (or both). Readjust the bit width to match
717 // the argument index type size and apply the offset, as required.
718 if (IndexTypeSizeChanged) {
719 if (SOT.knownSize() && !::CheckedZextOrTrunc(SOT.Size, InitialIntTyBits))
720 SOT.Size = APInt();
721 if (SOT.knownOffset() &&
722 !::CheckedZextOrTrunc(SOT.Offset, InitialIntTyBits))
723 SOT.Offset = APInt();
724 }
725 // If the computed offset is "unknown" we cannot add the stripped offset.
726 return {SOT.Size,
727 SOT.Offset.getBitWidth() > 1 ? SOT.Offset + Offset : SOT.Offset};
728}
729
730SizeOffsetAPInt ObjectSizeOffsetVisitor::computeValue(Value *V) {
731 if (Instruction *I = dyn_cast<Instruction>(V)) {
732 // If we have already seen this instruction, bail out. Cycles can happen in
733 // unreachable code after constant propagation.
734 auto P = SeenInsts.try_emplace(I, ObjectSizeOffsetVisitor::unknown());
735 if (!P.second)
736 return P.first->second;
737 ++InstructionsVisited;
738 if (InstructionsVisited > ObjectSizeOffsetVisitorMaxVisitInstructions)
739 return ObjectSizeOffsetVisitor::unknown();
740 SizeOffsetAPInt Res = visit(*I);
741 // Cache the result for later visits. If we happened to visit this during
742 // the above recursion, we would consider it unknown until now.
743 SeenInsts[I] = Res;
744 return Res;
745 }
746 if (Argument *A = dyn_cast<Argument>(V))
747 return visitArgument(*A);
748 if (ConstantPointerNull *P = dyn_cast<ConstantPointerNull>(V))
750 if (GlobalAlias *GA = dyn_cast<GlobalAlias>(V))
751 return visitGlobalAlias(*GA);
752 if (GlobalVariable *GV = dyn_cast<GlobalVariable>(V))
753 return visitGlobalVariable(*GV);
754 if (UndefValue *UV = dyn_cast<UndefValue>(V))
755 return visitUndefValue(*UV);
756
757 LLVM_DEBUG(dbgs() << "ObjectSizeOffsetVisitor::compute() unhandled value: "
758 << *V << '\n');
759 return ObjectSizeOffsetVisitor::unknown();
760}
761
762bool ObjectSizeOffsetVisitor::CheckedZextOrTrunc(APInt &I) {
763 return ::CheckedZextOrTrunc(I, IntTyBits);
764}
765
767 TypeSize ElemSize = DL.getTypeAllocSize(I.getAllocatedType());
768 if (ElemSize.isScalable() && Options.EvalMode != ObjectSizeOpts::Mode::Min)
769 return ObjectSizeOffsetVisitor::unknown();
770 APInt Size(IntTyBits, ElemSize.getKnownMinValue());
771 if (!I.isArrayAllocation())
772 return SizeOffsetAPInt(align(Size, I.getAlign()), Zero);
773
774 Value *ArraySize = I.getArraySize();
775 if (const ConstantInt *C = dyn_cast<ConstantInt>(ArraySize)) {
776 APInt NumElems = C->getValue();
777 if (!CheckedZextOrTrunc(NumElems))
778 return ObjectSizeOffsetVisitor::unknown();
779
780 bool Overflow;
781 Size = Size.umul_ov(NumElems, Overflow);
782 return Overflow ? ObjectSizeOffsetVisitor::unknown()
783 : SizeOffsetAPInt(align(Size, I.getAlign()), Zero);
784 }
785 return ObjectSizeOffsetVisitor::unknown();
786}
787
789 Type *MemoryTy = A.getPointeeInMemoryValueType();
790 // No interprocedural analysis is done at the moment.
791 if (!MemoryTy|| !MemoryTy->isSized()) {
792 ++ObjectVisitorArgument;
793 return ObjectSizeOffsetVisitor::unknown();
794 }
795
796 APInt Size(IntTyBits, DL.getTypeAllocSize(MemoryTy));
797 return SizeOffsetAPInt(align(Size, A.getParamAlign()), Zero);
798}
799
801 if (std::optional<APInt> Size = getAllocSize(&CB, TLI))
802 return SizeOffsetAPInt(*Size, Zero);
803 return ObjectSizeOffsetVisitor::unknown();
804}
805
808 // If null is unknown, there's nothing we can do. Additionally, non-zero
809 // address spaces can make use of null, so we don't presume to know anything
810 // about that.
811 //
812 // TODO: How should this work with address space casts? We currently just drop
813 // them on the floor, but it's unclear what we should do when a NULL from
814 // addrspace(1) gets casted to addrspace(0) (or vice-versa).
815 if (Options.NullIsUnknownSize || CPN.getType()->getAddressSpace())
816 return ObjectSizeOffsetVisitor::unknown();
817 return SizeOffsetAPInt(Zero, Zero);
818}
819
822 return ObjectSizeOffsetVisitor::unknown();
823}
824
827 // Easy cases were already folded by previous passes.
828 return ObjectSizeOffsetVisitor::unknown();
829}
830
832 if (GA.isInterposable())
833 return ObjectSizeOffsetVisitor::unknown();
834 return computeImpl(GA.getAliasee());
835}
836
839 if (!GV.getValueType()->isSized() || GV.hasExternalWeakLinkage() ||
840 ((!GV.hasInitializer() || GV.isInterposable()) &&
842 return ObjectSizeOffsetVisitor::unknown();
843
844 APInt Size(IntTyBits, DL.getTypeAllocSize(GV.getValueType()));
845 return SizeOffsetAPInt(align(Size, GV.getAlign()), Zero);
846}
847
849 // clueless
850 return ObjectSizeOffsetVisitor::unknown();
851}
852
853SizeOffsetAPInt ObjectSizeOffsetVisitor::findLoadSizeOffset(
856 unsigned &ScannedInstCount) {
857 constexpr unsigned MaxInstsToScan = 128;
858
859 auto Where = VisitedBlocks.find(&BB);
860 if (Where != VisitedBlocks.end())
861 return Where->second;
862
863 auto Unknown = [&BB, &VisitedBlocks]() {
864 return VisitedBlocks[&BB] = ObjectSizeOffsetVisitor::unknown();
865 };
866 auto Known = [&BB, &VisitedBlocks](SizeOffsetAPInt SO) {
867 return VisitedBlocks[&BB] = SO;
868 };
869
870 do {
871 Instruction &I = *From;
872
873 if (I.isDebugOrPseudoInst())
874 continue;
875
876 if (++ScannedInstCount > MaxInstsToScan)
877 return Unknown();
878
879 if (!I.mayWriteToMemory())
880 continue;
881
882 if (auto *SI = dyn_cast<StoreInst>(&I)) {
883 AliasResult AR =
884 Options.AA->alias(SI->getPointerOperand(), Load.getPointerOperand());
885 switch ((AliasResult::Kind)AR) {
887 continue;
889 if (SI->getValueOperand()->getType()->isPointerTy())
890 return Known(computeImpl(SI->getValueOperand()));
891 else
892 return Unknown(); // No handling of non-pointer values by `compute`.
893 default:
894 return Unknown();
895 }
896 }
897
898 if (auto *CB = dyn_cast<CallBase>(&I)) {
900 // Bail out on indirect call.
901 if (!Callee)
902 return Unknown();
903
904 LibFunc TLIFn;
905 if (!TLI || !TLI->getLibFunc(*CB->getCalledFunction(), TLIFn) ||
906 !TLI->has(TLIFn))
907 return Unknown();
908
909 // TODO: There's probably more interesting case to support here.
910 if (TLIFn != LibFunc_posix_memalign)
911 return Unknown();
912
913 AliasResult AR =
914 Options.AA->alias(CB->getOperand(0), Load.getPointerOperand());
915 switch ((AliasResult::Kind)AR) {
917 continue;
919 break;
920 default:
921 return Unknown();
922 }
923
924 // Is the error status of posix_memalign correctly checked? If not it
925 // would be incorrect to assume it succeeds and load doesn't see the
926 // previous value.
927 std::optional<bool> Checked = isImpliedByDomCondition(
928 ICmpInst::ICMP_EQ, CB, ConstantInt::get(CB->getType(), 0), &Load, DL);
929 if (!Checked || !*Checked)
930 return Unknown();
931
932 Value *Size = CB->getOperand(2);
933 auto *C = dyn_cast<ConstantInt>(Size);
934 if (!C)
935 return Unknown();
936
937 return Known({C->getValue(), APInt(C->getValue().getBitWidth(), 0)});
938 }
939
940 return Unknown();
941 } while (From-- != BB.begin());
942
943 SmallVector<SizeOffsetAPInt> PredecessorSizeOffsets;
944 for (auto *PredBB : predecessors(&BB)) {
945 PredecessorSizeOffsets.push_back(findLoadSizeOffset(
946 Load, *PredBB, BasicBlock::iterator(PredBB->getTerminator()),
947 VisitedBlocks, ScannedInstCount));
948 if (!PredecessorSizeOffsets.back().bothKnown())
949 return Unknown();
950 }
951
952 if (PredecessorSizeOffsets.empty())
953 return Unknown();
954
955 return Known(std::accumulate(
956 PredecessorSizeOffsets.begin() + 1, PredecessorSizeOffsets.end(),
957 PredecessorSizeOffsets.front(),
958 [this](SizeOffsetAPInt LHS, SizeOffsetAPInt RHS) {
959 return combineSizeOffset(LHS, RHS);
960 }));
961}
962
964 if (!Options.AA) {
965 ++ObjectVisitorLoad;
966 return ObjectSizeOffsetVisitor::unknown();
967 }
968
970 unsigned ScannedInstCount = 0;
971 SizeOffsetAPInt SO =
972 findLoadSizeOffset(LI, *LI.getParent(), BasicBlock::iterator(LI),
973 VisitedBlocks, ScannedInstCount);
974 if (!SO.bothKnown())
975 ++ObjectVisitorLoad;
976 return SO;
977}
978
980ObjectSizeOffsetVisitor::combineSizeOffset(SizeOffsetAPInt LHS,
981 SizeOffsetAPInt RHS) {
982 if (!LHS.bothKnown() || !RHS.bothKnown())
983 return ObjectSizeOffsetVisitor::unknown();
984
985 switch (Options.EvalMode) {
987 return (getSizeWithOverflow(LHS).slt(getSizeWithOverflow(RHS))) ? LHS : RHS;
989 return (getSizeWithOverflow(LHS).sgt(getSizeWithOverflow(RHS))) ? LHS : RHS;
991 return (getSizeWithOverflow(LHS).eq(getSizeWithOverflow(RHS)))
992 ? LHS
993 : ObjectSizeOffsetVisitor::unknown();
995 return LHS == RHS ? LHS : ObjectSizeOffsetVisitor::unknown();
996 }
997 llvm_unreachable("missing an eval mode");
998}
999
1001 if (PN.getNumIncomingValues() == 0)
1002 return ObjectSizeOffsetVisitor::unknown();
1003 auto IncomingValues = PN.incoming_values();
1004 return std::accumulate(IncomingValues.begin() + 1, IncomingValues.end(),
1005 computeImpl(*IncomingValues.begin()),
1006 [this](SizeOffsetAPInt LHS, Value *VRHS) {
1007 return combineSizeOffset(LHS, computeImpl(VRHS));
1008 });
1009}
1010
1012 return combineSizeOffset(computeImpl(I.getTrueValue()),
1013 computeImpl(I.getFalseValue()));
1014}
1015
1017 return SizeOffsetAPInt(Zero, Zero);
1018}
1019
1021 LLVM_DEBUG(dbgs() << "ObjectSizeOffsetVisitor unknown instruction:" << I
1022 << '\n');
1023 return ObjectSizeOffsetVisitor::unknown();
1024}
1025
1026// Just set these right here...
1028 : SizeOffsetType(SOT.Size, SOT.Offset) {}
1029
1031 const DataLayout &DL, const TargetLibraryInfo *TLI, LLVMContext &Context,
1032 ObjectSizeOpts EvalOpts)
1033 : DL(DL), TLI(TLI), Context(Context),
1034 Builder(Context, TargetFolder(DL),
1036 [&](Instruction *I) { InsertedInstructions.insert(I); })),
1037 EvalOpts(EvalOpts) {
1038 // IntTy and Zero must be set for each compute() since the address space may
1039 // be different for later objects.
1040}
1041
1043 // XXX - Are vectors of pointers possible here?
1044 IntTy = cast<IntegerType>(DL.getIndexType(V->getType()));
1045 Zero = ConstantInt::get(IntTy, 0);
1046
1047 SizeOffsetValue Result = compute_(V);
1048
1049 if (!Result.bothKnown()) {
1050 // Erase everything that was computed in this iteration from the cache, so
1051 // that no dangling references are left behind. We could be a bit smarter if
1052 // we kept a dependency graph. It's probably not worth the complexity.
1053 for (const Value *SeenVal : SeenVals) {
1054 CacheMapTy::iterator CacheIt = CacheMap.find(SeenVal);
1055 // non-computable results can be safely cached
1056 if (CacheIt != CacheMap.end() && CacheIt->second.anyKnown())
1057 CacheMap.erase(CacheIt);
1058 }
1059
1060 // Erase any instructions we inserted as part of the traversal.
1061 for (Instruction *I : InsertedInstructions) {
1062 I->replaceAllUsesWith(PoisonValue::get(I->getType()));
1063 I->eraseFromParent();
1064 }
1065 }
1066
1067 SeenVals.clear();
1068 InsertedInstructions.clear();
1069 return Result;
1070}
1071
1072SizeOffsetValue ObjectSizeOffsetEvaluator::compute_(Value *V) {
1073 ObjectSizeOffsetVisitor Visitor(DL, TLI, Context, EvalOpts);
1074 SizeOffsetAPInt Const = Visitor.compute(V);
1075 if (Const.bothKnown())
1076 return SizeOffsetValue(ConstantInt::get(Context, Const.Size),
1077 ConstantInt::get(Context, Const.Offset));
1078
1079 V = V->stripPointerCasts();
1080
1081 // Check cache.
1082 CacheMapTy::iterator CacheIt = CacheMap.find(V);
1083 if (CacheIt != CacheMap.end())
1084 return CacheIt->second;
1085
1086 // Always generate code immediately before the instruction being
1087 // processed, so that the generated code dominates the same BBs.
1088 BuilderTy::InsertPointGuard Guard(Builder);
1089 if (Instruction *I = dyn_cast<Instruction>(V))
1090 Builder.SetInsertPoint(I);
1091
1092 // Now compute the size and offset.
1093 SizeOffsetValue Result;
1094
1095 // Record the pointers that were handled in this run, so that they can be
1096 // cleaned later if something fails. We also use this set to break cycles that
1097 // can occur in dead code.
1098 if (!SeenVals.insert(V).second) {
1100 } else if (GEPOperator *GEP = dyn_cast<GEPOperator>(V)) {
1101 Result = visitGEPOperator(*GEP);
1102 } else if (Instruction *I = dyn_cast<Instruction>(V)) {
1103 Result = visit(*I);
1104 } else if (isa<Argument>(V) ||
1105 (isa<ConstantExpr>(V) &&
1106 cast<ConstantExpr>(V)->getOpcode() == Instruction::IntToPtr) ||
1107 isa<GlobalAlias>(V) ||
1108 isa<GlobalVariable>(V)) {
1109 // Ignore values where we cannot do more than ObjectSizeVisitor.
1111 } else {
1112 LLVM_DEBUG(
1113 dbgs() << "ObjectSizeOffsetEvaluator::compute() unhandled value: " << *V
1114 << '\n');
1116 }
1117
1118 // Don't reuse CacheIt since it may be invalid at this point.
1119 CacheMap[V] = SizeOffsetWeakTrackingVH(Result);
1120 return Result;
1121}
1122
1124 if (!I.getAllocatedType()->isSized())
1126
1127 // must be a VLA or vscale.
1128 assert(I.isArrayAllocation() || I.getAllocatedType()->isScalableTy());
1129
1130 // If needed, adjust the alloca's operand size to match the pointer indexing
1131 // size. Subsequent math operations expect the types to match.
1132 Value *ArraySize = Builder.CreateZExtOrTrunc(
1133 I.getArraySize(),
1134 DL.getIndexType(I.getContext(), DL.getAllocaAddrSpace()));
1135 assert(ArraySize->getType() == Zero->getType() &&
1136 "Expected zero constant to have pointer index type");
1137
1138 Value *Size = Builder.CreateTypeSize(
1139 ArraySize->getType(), DL.getTypeAllocSize(I.getAllocatedType()));
1140 Size = Builder.CreateMul(Size, ArraySize);
1141 return SizeOffsetValue(Size, Zero);
1142}
1143
1145 std::optional<AllocFnsTy> FnData = getAllocationSize(&CB, TLI);
1146 if (!FnData)
1148
1149 // Handle strdup-like functions separately.
1150 if (FnData->AllocTy == StrDupLike) {
1151 // TODO: implement evaluation of strdup/strndup
1153 }
1154
1155 Value *FirstArg = CB.getArgOperand(FnData->FstParam);
1156 FirstArg = Builder.CreateZExtOrTrunc(FirstArg, IntTy);
1157 if (FnData->SndParam < 0)
1158 return SizeOffsetValue(FirstArg, Zero);
1159
1160 Value *SecondArg = CB.getArgOperand(FnData->SndParam);
1161 SecondArg = Builder.CreateZExtOrTrunc(SecondArg, IntTy);
1162 Value *Size = Builder.CreateMul(FirstArg, SecondArg);
1163 return SizeOffsetValue(Size, Zero);
1164}
1165
1169}
1170
1174}
1175
1177 SizeOffsetValue PtrData = compute_(GEP.getPointerOperand());
1178 if (!PtrData.bothKnown())
1180
1181 Value *Offset = emitGEPOffset(&Builder, DL, &GEP, /*NoAssumptions=*/true);
1182 Offset = Builder.CreateAdd(PtrData.Offset, Offset);
1183 return SizeOffsetValue(PtrData.Size, Offset);
1184}
1185
1187 // clueless
1189}
1190
1193}
1194
1196 // Create 2 PHIs: one for size and another for offset.
1197 PHINode *SizePHI = Builder.CreatePHI(IntTy, PHI.getNumIncomingValues());
1198 PHINode *OffsetPHI = Builder.CreatePHI(IntTy, PHI.getNumIncomingValues());
1199
1200 // Insert right away in the cache to handle recursive PHIs.
1201 CacheMap[&PHI] = SizeOffsetWeakTrackingVH(SizePHI, OffsetPHI);
1202
1203 // Compute offset/size for each PHI incoming pointer.
1204 for (unsigned i = 0, e = PHI.getNumIncomingValues(); i != e; ++i) {
1205 BasicBlock *IncomingBlock = PHI.getIncomingBlock(i);
1206 Builder.SetInsertPoint(IncomingBlock, IncomingBlock->getFirstInsertionPt());
1207 SizeOffsetValue EdgeData = compute_(PHI.getIncomingValue(i));
1208
1209 if (!EdgeData.bothKnown()) {
1210 OffsetPHI->replaceAllUsesWith(PoisonValue::get(IntTy));
1211 OffsetPHI->eraseFromParent();
1212 InsertedInstructions.erase(OffsetPHI);
1213 SizePHI->replaceAllUsesWith(PoisonValue::get(IntTy));
1214 SizePHI->eraseFromParent();
1215 InsertedInstructions.erase(SizePHI);
1217 }
1218 SizePHI->addIncoming(EdgeData.Size, IncomingBlock);
1219 OffsetPHI->addIncoming(EdgeData.Offset, IncomingBlock);
1220 }
1221
1222 Value *Size = SizePHI, *Offset = OffsetPHI;
1223 if (Value *Tmp = SizePHI->hasConstantValue()) {
1224 Size = Tmp;
1225 SizePHI->replaceAllUsesWith(Size);
1226 SizePHI->eraseFromParent();
1227 InsertedInstructions.erase(SizePHI);
1228 }
1229 if (Value *Tmp = OffsetPHI->hasConstantValue()) {
1230 Offset = Tmp;
1231 OffsetPHI->replaceAllUsesWith(Offset);
1232 OffsetPHI->eraseFromParent();
1233 InsertedInstructions.erase(OffsetPHI);
1234 }
1235 return SizeOffsetValue(Size, Offset);
1236}
1237
1239 SizeOffsetValue TrueSide = compute_(I.getTrueValue());
1240 SizeOffsetValue FalseSide = compute_(I.getFalseValue());
1241
1242 if (!TrueSide.bothKnown() || !FalseSide.bothKnown())
1244 if (TrueSide == FalseSide)
1245 return TrueSide;
1246
1247 Value *Size =
1248 Builder.CreateSelect(I.getCondition(), TrueSide.Size, FalseSide.Size);
1249 Value *Offset =
1250 Builder.CreateSelect(I.getCondition(), TrueSide.Offset, FalseSide.Offset);
1251 return SizeOffsetValue(Size, Offset);
1252}
1253
1255 LLVM_DEBUG(dbgs() << "ObjectSizeOffsetEvaluator unknown instruction:" << I
1256 << '\n');
1258}
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:166
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:1498
unsigned getBitWidth() const
Return the number of bits in the APInt.
Definition: APInt.h:1446
static APInt getZero(unsigned numBits)
Get the '0' value for the specified bit-width.
Definition: APInt.h:178
The possible results of an alias query.
Definition: AliasAnalysis.h:77
@ NoAlias
The two locations do not alias at all.
Definition: AliasAnalysis.h:95
@ 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 * getAllOnesValue(Type *Ty)
Definition: Constants.cpp:417
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:63
unsigned getIndexTypeSizeInBits(Type *Ty) const
Layout size of the index used in GEP calculation.
Definition: DataLayout.cpp:749
unsigned getAllocaAddrSpace() const
Definition: DataLayout.h:233
IntegerType * getIndexType(LLVMContext &C, unsigned AddressSpace) const
Returns the type of a GEP index in AddressSpace.
Definition: DataLayout.cpp:873
TypeSize getTypeAllocSize(Type *Ty) const
Returns the offset in bytes between successive objects of the specified type, including alignment pad...
Definition: DataLayout.h:461
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:2277
Value * CreateZExtOrTrunc(Value *V, Type *DestTy, const Twine &Name="")
Create a ZExt or Trunc from the integer value V to DestTy.
Definition: IRBuilder.h:2059
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:2265
PHINode * CreatePHI(Type *Ty, unsigned NumReservedValues, const Twine &Name="")
Definition: IRBuilder.h:2417
Value * CreateSub(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Definition: IRBuilder.h:1361
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:1344
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:1378
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:2686
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:367
bool empty() const
Definition: SmallVector.h:94
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:586
void push_back(const T &Elt)
Definition: SmallVector.h:426
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1209
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.