xref: /freebsd-src/contrib/llvm-project/llvm/lib/Analysis/MemoryBuiltins.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===- MemoryBuiltins.cpp - Identify calls to memory builtins -------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This family of functions identifies calls to builtin functions that allocate
100b57cec5SDimitry Andric // or free memory.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "llvm/Analysis/MemoryBuiltins.h"
150b57cec5SDimitry Andric #include "llvm/ADT/APInt.h"
160b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
170b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h"
1881ad6265SDimitry Andric #include "llvm/Analysis/AliasAnalysis.h"
190b57cec5SDimitry Andric #include "llvm/Analysis/TargetFolder.h"
200b57cec5SDimitry Andric #include "llvm/Analysis/TargetLibraryInfo.h"
210b57cec5SDimitry Andric #include "llvm/Analysis/Utils/Local.h"
220b57cec5SDimitry Andric #include "llvm/Analysis/ValueTracking.h"
230b57cec5SDimitry Andric #include "llvm/IR/Argument.h"
240b57cec5SDimitry Andric #include "llvm/IR/Attributes.h"
250b57cec5SDimitry Andric #include "llvm/IR/Constants.h"
260b57cec5SDimitry Andric #include "llvm/IR/DataLayout.h"
270b57cec5SDimitry Andric #include "llvm/IR/DerivedTypes.h"
280b57cec5SDimitry Andric #include "llvm/IR/Function.h"
290b57cec5SDimitry Andric #include "llvm/IR/GlobalAlias.h"
300b57cec5SDimitry Andric #include "llvm/IR/GlobalVariable.h"
310b57cec5SDimitry Andric #include "llvm/IR/Instruction.h"
320b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
330b57cec5SDimitry Andric #include "llvm/IR/IntrinsicInst.h"
340b57cec5SDimitry Andric #include "llvm/IR/Operator.h"
350b57cec5SDimitry Andric #include "llvm/IR/Type.h"
360b57cec5SDimitry Andric #include "llvm/IR/Value.h"
370b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
385f757f3fSDimitry Andric #include "llvm/Support/CommandLine.h"
390b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
400b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h"
410b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
420b57cec5SDimitry Andric #include <cassert>
430b57cec5SDimitry Andric #include <cstdint>
440b57cec5SDimitry Andric #include <iterator>
4581ad6265SDimitry Andric #include <numeric>
46bdd1243dSDimitry Andric #include <optional>
4781ad6265SDimitry Andric #include <type_traits>
480b57cec5SDimitry Andric #include <utility>
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric using namespace llvm;
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric #define DEBUG_TYPE "memory-builtins"
530b57cec5SDimitry Andric 
545f757f3fSDimitry Andric static cl::opt<unsigned> ObjectSizeOffsetVisitorMaxVisitInstructions(
555f757f3fSDimitry Andric     "object-size-offset-visitor-max-visit-instructions",
565f757f3fSDimitry Andric     cl::desc("Maximum number of instructions for ObjectSizeOffsetVisitor to "
575f757f3fSDimitry Andric              "look at"),
585f757f3fSDimitry Andric     cl::init(100));
595f757f3fSDimitry Andric 
600b57cec5SDimitry Andric enum AllocType : uint8_t {
610b57cec5SDimitry Andric   OpNewLike          = 1<<0, // allocates; never returns null
6204eeddc0SDimitry Andric   MallocLike         = 1<<1, // allocates; may return null
63bdd1243dSDimitry Andric   StrDupLike         = 1<<2,
6404eeddc0SDimitry Andric   MallocOrOpNewLike  = MallocLike | OpNewLike,
65bdd1243dSDimitry Andric   AllocLike          = MallocOrOpNewLike | StrDupLike,
66bdd1243dSDimitry Andric   AnyAlloc           = AllocLike
670b57cec5SDimitry Andric };
680b57cec5SDimitry Andric 
6981ad6265SDimitry Andric enum class MallocFamily {
7081ad6265SDimitry Andric   Malloc,
7181ad6265SDimitry Andric   CPPNew,             // new(unsigned int)
7281ad6265SDimitry Andric   CPPNewAligned,      // new(unsigned int, align_val_t)
7381ad6265SDimitry Andric   CPPNewArray,        // new[](unsigned int)
7481ad6265SDimitry Andric   CPPNewArrayAligned, // new[](unsigned long, align_val_t)
7581ad6265SDimitry Andric   MSVCNew,            // new(unsigned int)
7681ad6265SDimitry Andric   MSVCArrayNew,       // new[](unsigned int)
7781ad6265SDimitry Andric   VecMalloc,
7881ad6265SDimitry Andric   KmpcAllocShared,
7981ad6265SDimitry Andric };
8081ad6265SDimitry Andric 
8181ad6265SDimitry Andric StringRef mangledNameForMallocFamily(const MallocFamily &Family) {
8281ad6265SDimitry Andric   switch (Family) {
8381ad6265SDimitry Andric   case MallocFamily::Malloc:
8481ad6265SDimitry Andric     return "malloc";
8581ad6265SDimitry Andric   case MallocFamily::CPPNew:
8681ad6265SDimitry Andric     return "_Znwm";
8781ad6265SDimitry Andric   case MallocFamily::CPPNewAligned:
8881ad6265SDimitry Andric     return "_ZnwmSt11align_val_t";
8981ad6265SDimitry Andric   case MallocFamily::CPPNewArray:
9081ad6265SDimitry Andric     return "_Znam";
9181ad6265SDimitry Andric   case MallocFamily::CPPNewArrayAligned:
9281ad6265SDimitry Andric     return "_ZnamSt11align_val_t";
9381ad6265SDimitry Andric   case MallocFamily::MSVCNew:
9481ad6265SDimitry Andric     return "??2@YAPAXI@Z";
9581ad6265SDimitry Andric   case MallocFamily::MSVCArrayNew:
9681ad6265SDimitry Andric     return "??_U@YAPAXI@Z";
9781ad6265SDimitry Andric   case MallocFamily::VecMalloc:
9881ad6265SDimitry Andric     return "vec_malloc";
9981ad6265SDimitry Andric   case MallocFamily::KmpcAllocShared:
10081ad6265SDimitry Andric     return "__kmpc_alloc_shared";
10181ad6265SDimitry Andric   }
10281ad6265SDimitry Andric   llvm_unreachable("missing an alloc family");
10381ad6265SDimitry Andric }
10481ad6265SDimitry Andric 
1050b57cec5SDimitry Andric struct AllocFnsTy {
1060b57cec5SDimitry Andric   AllocType AllocTy;
1070b57cec5SDimitry Andric   unsigned NumParams;
1080b57cec5SDimitry Andric   // First and Second size parameters (or -1 if unused)
1090b57cec5SDimitry Andric   int FstParam, SndParam;
11004eeddc0SDimitry Andric   // Alignment parameter for aligned_alloc and aligned new
11104eeddc0SDimitry Andric   int AlignParam;
11281ad6265SDimitry Andric   // Name of default allocator function to group malloc/free calls by family
11381ad6265SDimitry Andric   MallocFamily Family;
1140b57cec5SDimitry Andric };
1150b57cec5SDimitry Andric 
11681ad6265SDimitry Andric // clang-format off
1170b57cec5SDimitry Andric // FIXME: certain users need more information. E.g., SimplifyLibCalls needs to
1180b57cec5SDimitry Andric // know which functions are nounwind, noalias, nocapture parameters, etc.
1190b57cec5SDimitry Andric static const std::pair<LibFunc, AllocFnsTy> AllocationFnData[] = {
12081ad6265SDimitry Andric     {LibFunc_Znwj,                              {OpNewLike,        1,  0, -1, -1, MallocFamily::CPPNew}},             // new(unsigned int)
12181ad6265SDimitry Andric     {LibFunc_ZnwjRKSt9nothrow_t,                {MallocLike,       2,  0, -1, -1, MallocFamily::CPPNew}},             // new(unsigned int, nothrow)
12281ad6265SDimitry Andric     {LibFunc_ZnwjSt11align_val_t,               {OpNewLike,        2,  0, -1,  1, MallocFamily::CPPNewAligned}},      // new(unsigned int, align_val_t)
12381ad6265SDimitry Andric     {LibFunc_ZnwjSt11align_val_tRKSt9nothrow_t, {MallocLike,       3,  0, -1,  1, MallocFamily::CPPNewAligned}},      // new(unsigned int, align_val_t, nothrow)
12481ad6265SDimitry Andric     {LibFunc_Znwm,                              {OpNewLike,        1,  0, -1, -1, MallocFamily::CPPNew}},             // new(unsigned long)
12506c3fb27SDimitry Andric     {LibFunc_Znwm12__hot_cold_t,                  {OpNewLike,        2, 0,  -1, -1, MallocFamily::CPPNew}},             // new(unsigned long, __hot_cold_t)
12681ad6265SDimitry Andric     {LibFunc_ZnwmRKSt9nothrow_t,                {MallocLike,       2,  0, -1, -1, MallocFamily::CPPNew}},             // new(unsigned long, nothrow)
12706c3fb27SDimitry Andric     {LibFunc_ZnwmRKSt9nothrow_t12__hot_cold_t,      {MallocLike,       3, 0,  -1, -1, MallocFamily::CPPNew}},             // new(unsigned long, nothrow, __hot_cold_t)
12881ad6265SDimitry Andric     {LibFunc_ZnwmSt11align_val_t,               {OpNewLike,        2,  0, -1,  1, MallocFamily::CPPNewAligned}},      // new(unsigned long, align_val_t)
12906c3fb27SDimitry Andric     {LibFunc_ZnwmSt11align_val_t12__hot_cold_t,   {OpNewLike,        3, 0,  -1, 1, MallocFamily::CPPNewAligned}},       // new(unsigned long, align_val_t, __hot_cold_t)
13081ad6265SDimitry Andric     {LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t, {MallocLike,       3,  0, -1,  1, MallocFamily::CPPNewAligned}},      // new(unsigned long, align_val_t, nothrow)
13106c3fb27SDimitry Andric     {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)
13281ad6265SDimitry Andric     {LibFunc_Znaj,                              {OpNewLike,        1,  0, -1, -1, MallocFamily::CPPNewArray}},        // new[](unsigned int)
13381ad6265SDimitry Andric     {LibFunc_ZnajRKSt9nothrow_t,                {MallocLike,       2,  0, -1, -1, MallocFamily::CPPNewArray}},        // new[](unsigned int, nothrow)
13481ad6265SDimitry Andric     {LibFunc_ZnajSt11align_val_t,               {OpNewLike,        2,  0, -1,  1, MallocFamily::CPPNewArrayAligned}}, // new[](unsigned int, align_val_t)
13581ad6265SDimitry Andric     {LibFunc_ZnajSt11align_val_tRKSt9nothrow_t, {MallocLike,       3,  0, -1,  1, MallocFamily::CPPNewArrayAligned}}, // new[](unsigned int, align_val_t, nothrow)
13681ad6265SDimitry Andric     {LibFunc_Znam,                              {OpNewLike,        1,  0, -1, -1, MallocFamily::CPPNewArray}},        // new[](unsigned long)
13706c3fb27SDimitry Andric     {LibFunc_Znam12__hot_cold_t,                  {OpNewLike,        2, 0,  -1, -1, MallocFamily::CPPNew}},             // new[](unsigned long, __hot_cold_t)
13881ad6265SDimitry Andric     {LibFunc_ZnamRKSt9nothrow_t,                {MallocLike,       2,  0, -1, -1, MallocFamily::CPPNewArray}},        // new[](unsigned long, nothrow)
13906c3fb27SDimitry Andric     {LibFunc_ZnamRKSt9nothrow_t12__hot_cold_t,      {MallocLike,       3, 0,  -1, -1, MallocFamily::CPPNew}},             // new[](unsigned long, nothrow, __hot_cold_t)
14081ad6265SDimitry Andric     {LibFunc_ZnamSt11align_val_t,               {OpNewLike,        2,  0, -1,  1, MallocFamily::CPPNewArrayAligned}}, // new[](unsigned long, align_val_t)
14106c3fb27SDimitry Andric     {LibFunc_ZnamSt11align_val_t12__hot_cold_t,   {OpNewLike,        3, 0,  -1, 1, MallocFamily::CPPNewAligned}},       // new[](unsigned long, align_val_t, __hot_cold_t)
14281ad6265SDimitry Andric     {LibFunc_ZnamSt11align_val_tRKSt9nothrow_t, {MallocLike,       3,  0, -1,  1, MallocFamily::CPPNewArrayAligned}}, // new[](unsigned long, align_val_t, nothrow)
14306c3fb27SDimitry Andric     {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)
14481ad6265SDimitry Andric     {LibFunc_msvc_new_int,                      {OpNewLike,        1,  0, -1, -1, MallocFamily::MSVCNew}},            // new(unsigned int)
14581ad6265SDimitry Andric     {LibFunc_msvc_new_int_nothrow,              {MallocLike,       2,  0, -1, -1, MallocFamily::MSVCNew}},            // new(unsigned int, nothrow)
14681ad6265SDimitry Andric     {LibFunc_msvc_new_longlong,                 {OpNewLike,        1,  0, -1, -1, MallocFamily::MSVCNew}},            // new(unsigned long long)
14781ad6265SDimitry Andric     {LibFunc_msvc_new_longlong_nothrow,         {MallocLike,       2,  0, -1, -1, MallocFamily::MSVCNew}},            // new(unsigned long long, nothrow)
14881ad6265SDimitry Andric     {LibFunc_msvc_new_array_int,                {OpNewLike,        1,  0, -1, -1, MallocFamily::MSVCArrayNew}},       // new[](unsigned int)
14981ad6265SDimitry Andric     {LibFunc_msvc_new_array_int_nothrow,        {MallocLike,       2,  0, -1, -1, MallocFamily::MSVCArrayNew}},       // new[](unsigned int, nothrow)
15081ad6265SDimitry Andric     {LibFunc_msvc_new_array_longlong,           {OpNewLike,        1,  0, -1, -1, MallocFamily::MSVCArrayNew}},       // new[](unsigned long long)
15181ad6265SDimitry Andric     {LibFunc_msvc_new_array_longlong_nothrow,   {MallocLike,       2,  0, -1, -1, MallocFamily::MSVCArrayNew}},       // new[](unsigned long long, nothrow)
15281ad6265SDimitry Andric     {LibFunc_strdup,                            {StrDupLike,       1, -1, -1, -1, MallocFamily::Malloc}},
15381ad6265SDimitry Andric     {LibFunc_dunder_strdup,                     {StrDupLike,       1, -1, -1, -1, MallocFamily::Malloc}},
15481ad6265SDimitry Andric     {LibFunc_strndup,                           {StrDupLike,       2,  1, -1, -1, MallocFamily::Malloc}},
15581ad6265SDimitry Andric     {LibFunc_dunder_strndup,                    {StrDupLike,       2,  1, -1, -1, MallocFamily::Malloc}},
15681ad6265SDimitry Andric     {LibFunc___kmpc_alloc_shared,               {MallocLike,       1,  0, -1, -1, MallocFamily::KmpcAllocShared}},
1570b57cec5SDimitry Andric };
15881ad6265SDimitry Andric // clang-format on
1590b57cec5SDimitry Andric 
16004eeddc0SDimitry Andric static const Function *getCalledFunction(const Value *V,
1610b57cec5SDimitry Andric                                          bool &IsNoBuiltin) {
1620b57cec5SDimitry Andric   // Don't care about intrinsics in this case.
1630b57cec5SDimitry Andric   if (isa<IntrinsicInst>(V))
1640b57cec5SDimitry Andric     return nullptr;
1650b57cec5SDimitry Andric 
1665ffd83dbSDimitry Andric   const auto *CB = dyn_cast<CallBase>(V);
1675ffd83dbSDimitry Andric   if (!CB)
1680b57cec5SDimitry Andric     return nullptr;
1690b57cec5SDimitry Andric 
1705ffd83dbSDimitry Andric   IsNoBuiltin = CB->isNoBuiltin();
1710b57cec5SDimitry Andric 
1725ffd83dbSDimitry Andric   if (const Function *Callee = CB->getCalledFunction())
1730b57cec5SDimitry Andric     return Callee;
1740b57cec5SDimitry Andric   return nullptr;
1750b57cec5SDimitry Andric }
1760b57cec5SDimitry Andric 
177349cc55cSDimitry Andric /// Returns the allocation data for the given value if it's a call to a known
178349cc55cSDimitry Andric /// allocation function.
179bdd1243dSDimitry Andric static std::optional<AllocFnsTy>
1800b57cec5SDimitry Andric getAllocationDataForFunction(const Function *Callee, AllocType AllocTy,
1810b57cec5SDimitry Andric                              const TargetLibraryInfo *TLI) {
182fcaf7f86SDimitry Andric   // Don't perform a slow TLI lookup, if this function doesn't return a pointer
183fcaf7f86SDimitry Andric   // and thus can't be an allocation function.
184fcaf7f86SDimitry Andric   if (!Callee->getReturnType()->isPointerTy())
185bdd1243dSDimitry Andric     return std::nullopt;
186fcaf7f86SDimitry Andric 
1870b57cec5SDimitry Andric   // Make sure that the function is available.
1880b57cec5SDimitry Andric   LibFunc TLIFn;
189fe6060f1SDimitry Andric   if (!TLI || !TLI->getLibFunc(*Callee, TLIFn) || !TLI->has(TLIFn))
190bdd1243dSDimitry Andric     return std::nullopt;
1910b57cec5SDimitry Andric 
1920b57cec5SDimitry Andric   const auto *Iter = find_if(
1930b57cec5SDimitry Andric       AllocationFnData, [TLIFn](const std::pair<LibFunc, AllocFnsTy> &P) {
1940b57cec5SDimitry Andric         return P.first == TLIFn;
1950b57cec5SDimitry Andric       });
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric   if (Iter == std::end(AllocationFnData))
198bdd1243dSDimitry Andric     return std::nullopt;
1990b57cec5SDimitry Andric 
2000b57cec5SDimitry Andric   const AllocFnsTy *FnData = &Iter->second;
2010b57cec5SDimitry Andric   if ((FnData->AllocTy & AllocTy) != FnData->AllocTy)
202bdd1243dSDimitry Andric     return std::nullopt;
2030b57cec5SDimitry Andric 
2040b57cec5SDimitry Andric   // Check function prototype.
2050b57cec5SDimitry Andric   int FstParam = FnData->FstParam;
2060b57cec5SDimitry Andric   int SndParam = FnData->SndParam;
2070b57cec5SDimitry Andric   FunctionType *FTy = Callee->getFunctionType();
2080b57cec5SDimitry Andric 
209bdd1243dSDimitry Andric   if (FTy->getReturnType()->isPointerTy() &&
2100b57cec5SDimitry Andric       FTy->getNumParams() == FnData->NumParams &&
2110b57cec5SDimitry Andric       (FstParam < 0 ||
2120b57cec5SDimitry Andric        (FTy->getParamType(FstParam)->isIntegerTy(32) ||
2130b57cec5SDimitry Andric         FTy->getParamType(FstParam)->isIntegerTy(64))) &&
2140b57cec5SDimitry Andric       (SndParam < 0 ||
2150b57cec5SDimitry Andric        FTy->getParamType(SndParam)->isIntegerTy(32) ||
2160b57cec5SDimitry Andric        FTy->getParamType(SndParam)->isIntegerTy(64)))
2170b57cec5SDimitry Andric     return *FnData;
218bdd1243dSDimitry Andric   return std::nullopt;
2190b57cec5SDimitry Andric }
2200b57cec5SDimitry Andric 
221bdd1243dSDimitry Andric static std::optional<AllocFnsTy>
222bdd1243dSDimitry Andric getAllocationData(const Value *V, AllocType AllocTy,
22304eeddc0SDimitry Andric                   const TargetLibraryInfo *TLI) {
2240b57cec5SDimitry Andric   bool IsNoBuiltinCall;
22504eeddc0SDimitry Andric   if (const Function *Callee = getCalledFunction(V, IsNoBuiltinCall))
2260b57cec5SDimitry Andric     if (!IsNoBuiltinCall)
2270b57cec5SDimitry Andric       return getAllocationDataForFunction(Callee, AllocTy, TLI);
228bdd1243dSDimitry Andric   return std::nullopt;
2290b57cec5SDimitry Andric }
2300b57cec5SDimitry Andric 
231bdd1243dSDimitry Andric static std::optional<AllocFnsTy>
2328bcb0991SDimitry Andric getAllocationData(const Value *V, AllocType AllocTy,
23304eeddc0SDimitry Andric                   function_ref<const TargetLibraryInfo &(Function &)> GetTLI) {
2348bcb0991SDimitry Andric   bool IsNoBuiltinCall;
23504eeddc0SDimitry Andric   if (const Function *Callee = getCalledFunction(V, IsNoBuiltinCall))
2368bcb0991SDimitry Andric     if (!IsNoBuiltinCall)
2378bcb0991SDimitry Andric       return getAllocationDataForFunction(
2388bcb0991SDimitry Andric           Callee, AllocTy, &GetTLI(const_cast<Function &>(*Callee)));
239bdd1243dSDimitry Andric   return std::nullopt;
2408bcb0991SDimitry Andric }
2418bcb0991SDimitry Andric 
242bdd1243dSDimitry Andric static std::optional<AllocFnsTy>
243bdd1243dSDimitry Andric getAllocationSize(const Value *V, const TargetLibraryInfo *TLI) {
2440b57cec5SDimitry Andric   bool IsNoBuiltinCall;
2450b57cec5SDimitry Andric   const Function *Callee =
24604eeddc0SDimitry Andric       getCalledFunction(V, IsNoBuiltinCall);
2470b57cec5SDimitry Andric   if (!Callee)
248bdd1243dSDimitry Andric     return std::nullopt;
2490b57cec5SDimitry Andric 
2500b57cec5SDimitry Andric   // Prefer to use existing information over allocsize. This will give us an
2510b57cec5SDimitry Andric   // accurate AllocTy.
2520b57cec5SDimitry Andric   if (!IsNoBuiltinCall)
253bdd1243dSDimitry Andric     if (std::optional<AllocFnsTy> Data =
2540b57cec5SDimitry Andric             getAllocationDataForFunction(Callee, AnyAlloc, TLI))
2550b57cec5SDimitry Andric       return Data;
2560b57cec5SDimitry Andric 
2570b57cec5SDimitry Andric   Attribute Attr = Callee->getFnAttribute(Attribute::AllocSize);
2580b57cec5SDimitry Andric   if (Attr == Attribute())
259bdd1243dSDimitry Andric     return std::nullopt;
2600b57cec5SDimitry Andric 
261bdd1243dSDimitry Andric   std::pair<unsigned, std::optional<unsigned>> Args = Attr.getAllocSizeArgs();
2620b57cec5SDimitry Andric 
2630b57cec5SDimitry Andric   AllocFnsTy Result;
2640b57cec5SDimitry Andric   // Because allocsize only tells us how many bytes are allocated, we're not
2650b57cec5SDimitry Andric   // really allowed to assume anything, so we use MallocLike.
2660b57cec5SDimitry Andric   Result.AllocTy = MallocLike;
2670b57cec5SDimitry Andric   Result.NumParams = Callee->getNumOperands();
2680b57cec5SDimitry Andric   Result.FstParam = Args.first;
26981ad6265SDimitry Andric   Result.SndParam = Args.second.value_or(-1);
27004eeddc0SDimitry Andric   // Allocsize has no way to specify an alignment argument
27104eeddc0SDimitry Andric   Result.AlignParam = -1;
2720b57cec5SDimitry Andric   return Result;
2730b57cec5SDimitry Andric }
2740b57cec5SDimitry Andric 
275fcaf7f86SDimitry Andric static AllocFnKind getAllocFnKind(const Value *V) {
276fcaf7f86SDimitry Andric   if (const auto *CB = dyn_cast<CallBase>(V)) {
277fcaf7f86SDimitry Andric     Attribute Attr = CB->getFnAttr(Attribute::AllocKind);
278fcaf7f86SDimitry Andric     if (Attr.isValid())
279fcaf7f86SDimitry Andric       return AllocFnKind(Attr.getValueAsInt());
280fcaf7f86SDimitry Andric   }
281fcaf7f86SDimitry Andric   return AllocFnKind::Unknown;
282fcaf7f86SDimitry Andric }
283fcaf7f86SDimitry Andric 
284fcaf7f86SDimitry Andric static AllocFnKind getAllocFnKind(const Function *F) {
2855f757f3fSDimitry Andric   return F->getAttributes().getAllocKind();
286fcaf7f86SDimitry Andric }
287fcaf7f86SDimitry Andric 
288fcaf7f86SDimitry Andric static bool checkFnAllocKind(const Value *V, AllocFnKind Wanted) {
289fcaf7f86SDimitry Andric   return (getAllocFnKind(V) & Wanted) != AllocFnKind::Unknown;
290fcaf7f86SDimitry Andric }
291fcaf7f86SDimitry Andric 
292fcaf7f86SDimitry Andric static bool checkFnAllocKind(const Function *F, AllocFnKind Wanted) {
293fcaf7f86SDimitry Andric   return (getAllocFnKind(F) & Wanted) != AllocFnKind::Unknown;
294fcaf7f86SDimitry Andric }
295fcaf7f86SDimitry Andric 
2960b57cec5SDimitry Andric /// Tests if a value is a call or invoke to a library function that
2970b57cec5SDimitry Andric /// allocates or reallocates memory (either malloc, calloc, realloc, or strdup
2980b57cec5SDimitry Andric /// like).
29904eeddc0SDimitry Andric bool llvm::isAllocationFn(const Value *V, const TargetLibraryInfo *TLI) {
300fcaf7f86SDimitry Andric   return getAllocationData(V, AnyAlloc, TLI).has_value() ||
301fcaf7f86SDimitry Andric          checkFnAllocKind(V, AllocFnKind::Alloc | AllocFnKind::Realloc);
3020b57cec5SDimitry Andric }
3038bcb0991SDimitry Andric bool llvm::isAllocationFn(
304fcaf7f86SDimitry Andric     const Value *V,
305fcaf7f86SDimitry Andric     function_ref<const TargetLibraryInfo &(Function &)> GetTLI) {
306fcaf7f86SDimitry Andric   return getAllocationData(V, AnyAlloc, GetTLI).has_value() ||
307fcaf7f86SDimitry Andric          checkFnAllocKind(V, AllocFnKind::Alloc | AllocFnKind::Realloc);
3080b57cec5SDimitry Andric }
3090b57cec5SDimitry Andric 
3100b57cec5SDimitry Andric /// Tests if a value is a call or invoke to a library function that
311bdd1243dSDimitry Andric /// allocates memory via new.
312bdd1243dSDimitry Andric bool llvm::isNewLikeFn(const Value *V, const TargetLibraryInfo *TLI) {
313bdd1243dSDimitry Andric   return getAllocationData(V, OpNewLike, TLI).has_value();
3140b57cec5SDimitry Andric }
3150b57cec5SDimitry Andric 
3160b57cec5SDimitry Andric /// Tests if a value is a call or invoke to a library function that
3170b57cec5SDimitry Andric /// allocates memory similar to malloc or calloc.
31804eeddc0SDimitry Andric bool llvm::isMallocOrCallocLikeFn(const Value *V, const TargetLibraryInfo *TLI) {
319bdd1243dSDimitry Andric   // TODO: Function behavior does not match name.
320bdd1243dSDimitry Andric   return getAllocationData(V, MallocOrOpNewLike, TLI).has_value();
3210b57cec5SDimitry Andric }
3220b57cec5SDimitry Andric 
3230b57cec5SDimitry Andric /// Tests if a value is a call or invoke to a library function that
3240b57cec5SDimitry Andric /// allocates memory (either malloc, calloc, or strdup like).
32504eeddc0SDimitry Andric bool llvm::isAllocLikeFn(const Value *V, const TargetLibraryInfo *TLI) {
326fcaf7f86SDimitry Andric   return getAllocationData(V, AllocLike, TLI).has_value() ||
327fcaf7f86SDimitry Andric          checkFnAllocKind(V, AllocFnKind::Alloc);
3280b57cec5SDimitry Andric }
3290b57cec5SDimitry Andric 
3300b57cec5SDimitry Andric /// Tests if a functions is a call or invoke to a library function that
3310b57cec5SDimitry Andric /// reallocates memory (e.g., realloc).
332bdd1243dSDimitry Andric bool llvm::isReallocLikeFn(const Function *F) {
333bdd1243dSDimitry Andric   return checkFnAllocKind(F, AllocFnKind::Realloc);
3340b57cec5SDimitry Andric }
3350b57cec5SDimitry Andric 
336bdd1243dSDimitry Andric Value *llvm::getReallocatedOperand(const CallBase *CB) {
337fcaf7f86SDimitry Andric   if (checkFnAllocKind(CB, AllocFnKind::Realloc))
338fcaf7f86SDimitry Andric     return CB->getArgOperandWithAttribute(Attribute::AllocatedPointer);
339fcaf7f86SDimitry Andric   return nullptr;
340fcaf7f86SDimitry Andric }
34104eeddc0SDimitry Andric 
342fcaf7f86SDimitry Andric bool llvm::isRemovableAlloc(const CallBase *CB, const TargetLibraryInfo *TLI) {
34304eeddc0SDimitry Andric   // Note: Removability is highly dependent on the source language.  For
34404eeddc0SDimitry Andric   // example, recent C++ requires direct calls to the global allocation
34504eeddc0SDimitry Andric   // [basic.stc.dynamic.allocation] to be observable unless part of a new
34604eeddc0SDimitry Andric   // expression [expr.new paragraph 13].
34704eeddc0SDimitry Andric 
348fcaf7f86SDimitry Andric   // Historically we've treated the C family allocation routines and operator
349fcaf7f86SDimitry Andric   // new as removable
35004eeddc0SDimitry Andric   return isAllocLikeFn(CB, TLI);
3518bcb0991SDimitry Andric }
3528bcb0991SDimitry Andric 
35304eeddc0SDimitry Andric Value *llvm::getAllocAlignment(const CallBase *V,
35404eeddc0SDimitry Andric                                const TargetLibraryInfo *TLI) {
355bdd1243dSDimitry Andric   const std::optional<AllocFnsTy> FnData = getAllocationData(V, AnyAlloc, TLI);
35681ad6265SDimitry Andric   if (FnData && FnData->AlignParam >= 0) {
35704eeddc0SDimitry Andric     return V->getOperand(FnData->AlignParam);
3588bcb0991SDimitry Andric   }
35981ad6265SDimitry Andric   return V->getArgOperandWithAttribute(Attribute::AllocAlign);
36081ad6265SDimitry Andric }
3618bcb0991SDimitry Andric 
36204eeddc0SDimitry Andric /// When we're compiling N-bit code, and the user uses parameters that are
36304eeddc0SDimitry Andric /// greater than N bits (e.g. uint64_t on a 32-bit build), we can run into
36404eeddc0SDimitry Andric /// trouble with APInt size issues. This function handles resizing + overflow
36504eeddc0SDimitry Andric /// checks for us. Check and zext or trunc \p I depending on IntTyBits and
36604eeddc0SDimitry Andric /// I's value.
36704eeddc0SDimitry Andric static bool CheckedZextOrTrunc(APInt &I, unsigned IntTyBits) {
36804eeddc0SDimitry Andric   // More bits than we can handle. Checking the bit width isn't necessary, but
36904eeddc0SDimitry Andric   // it's faster than checking active bits, and should give `false` in the
37004eeddc0SDimitry Andric   // vast majority of cases.
37104eeddc0SDimitry Andric   if (I.getBitWidth() > IntTyBits && I.getActiveBits() > IntTyBits)
37204eeddc0SDimitry Andric     return false;
37304eeddc0SDimitry Andric   if (I.getBitWidth() != IntTyBits)
37404eeddc0SDimitry Andric     I = I.zextOrTrunc(IntTyBits);
37504eeddc0SDimitry Andric   return true;
3760b57cec5SDimitry Andric }
3770b57cec5SDimitry Andric 
378bdd1243dSDimitry Andric std::optional<APInt>
379fcaf7f86SDimitry Andric llvm::getAllocSize(const CallBase *CB, const TargetLibraryInfo *TLI,
380fcaf7f86SDimitry Andric                    function_ref<const Value *(const Value *)> Mapper) {
38104eeddc0SDimitry Andric   // Note: This handles both explicitly listed allocation functions and
38204eeddc0SDimitry Andric   // allocsize.  The code structure could stand to be cleaned up a bit.
383bdd1243dSDimitry Andric   std::optional<AllocFnsTy> FnData = getAllocationSize(CB, TLI);
38404eeddc0SDimitry Andric   if (!FnData)
385bdd1243dSDimitry Andric     return std::nullopt;
3860b57cec5SDimitry Andric 
38704eeddc0SDimitry Andric   // Get the index type for this address space, results and intermediate
38804eeddc0SDimitry Andric   // computations are performed at that width.
389*0fca6ea1SDimitry Andric   auto &DL = CB->getDataLayout();
39004eeddc0SDimitry Andric   const unsigned IntTyBits = DL.getIndexTypeSizeInBits(CB->getType());
3910b57cec5SDimitry Andric 
39204eeddc0SDimitry Andric   // Handle strdup-like functions separately.
39304eeddc0SDimitry Andric   if (FnData->AllocTy == StrDupLike) {
39404eeddc0SDimitry Andric     APInt Size(IntTyBits, GetStringLength(Mapper(CB->getArgOperand(0))));
39504eeddc0SDimitry Andric     if (!Size)
396bdd1243dSDimitry Andric       return std::nullopt;
3970b57cec5SDimitry Andric 
39804eeddc0SDimitry Andric     // Strndup limits strlen.
39904eeddc0SDimitry Andric     if (FnData->FstParam > 0) {
40004eeddc0SDimitry Andric       const ConstantInt *Arg =
40104eeddc0SDimitry Andric         dyn_cast<ConstantInt>(Mapper(CB->getArgOperand(FnData->FstParam)));
40204eeddc0SDimitry Andric       if (!Arg)
403bdd1243dSDimitry Andric         return std::nullopt;
4040b57cec5SDimitry Andric 
40581ad6265SDimitry Andric       APInt MaxSize = Arg->getValue().zext(IntTyBits);
40604eeddc0SDimitry Andric       if (Size.ugt(MaxSize))
40704eeddc0SDimitry Andric         Size = MaxSize + 1;
40804eeddc0SDimitry Andric     }
40904eeddc0SDimitry Andric     return Size;
4100b57cec5SDimitry Andric   }
4110b57cec5SDimitry Andric 
41204eeddc0SDimitry Andric   const ConstantInt *Arg =
41304eeddc0SDimitry Andric     dyn_cast<ConstantInt>(Mapper(CB->getArgOperand(FnData->FstParam)));
41404eeddc0SDimitry Andric   if (!Arg)
415bdd1243dSDimitry Andric     return std::nullopt;
4160b57cec5SDimitry Andric 
41704eeddc0SDimitry Andric   APInt Size = Arg->getValue();
41804eeddc0SDimitry Andric   if (!CheckedZextOrTrunc(Size, IntTyBits))
419bdd1243dSDimitry Andric     return std::nullopt;
4200b57cec5SDimitry Andric 
42104eeddc0SDimitry Andric   // Size is determined by just 1 parameter.
42204eeddc0SDimitry Andric   if (FnData->SndParam < 0)
42304eeddc0SDimitry Andric     return Size;
42404eeddc0SDimitry Andric 
42504eeddc0SDimitry Andric   Arg = dyn_cast<ConstantInt>(Mapper(CB->getArgOperand(FnData->SndParam)));
42604eeddc0SDimitry Andric   if (!Arg)
427bdd1243dSDimitry Andric     return std::nullopt;
42804eeddc0SDimitry Andric 
42904eeddc0SDimitry Andric   APInt NumElems = Arg->getValue();
43004eeddc0SDimitry Andric   if (!CheckedZextOrTrunc(NumElems, IntTyBits))
431bdd1243dSDimitry Andric     return std::nullopt;
43204eeddc0SDimitry Andric 
43304eeddc0SDimitry Andric   bool Overflow;
43404eeddc0SDimitry Andric   Size = Size.umul_ov(NumElems, Overflow);
43504eeddc0SDimitry Andric   if (Overflow)
436bdd1243dSDimitry Andric     return std::nullopt;
43704eeddc0SDimitry Andric   return Size;
4380b57cec5SDimitry Andric }
4390b57cec5SDimitry Andric 
44081ad6265SDimitry Andric Constant *llvm::getInitialValueOfAllocation(const Value *V,
4410b57cec5SDimitry Andric                                             const TargetLibraryInfo *TLI,
44204eeddc0SDimitry Andric                                             Type *Ty) {
44381ad6265SDimitry Andric   auto *Alloc = dyn_cast<CallBase>(V);
44481ad6265SDimitry Andric   if (!Alloc)
44581ad6265SDimitry Andric     return nullptr;
4460b57cec5SDimitry Andric 
447bdd1243dSDimitry Andric   // malloc are uninitialized (undef)
448bdd1243dSDimitry Andric   if (getAllocationData(Alloc, MallocOrOpNewLike, TLI).has_value())
44904eeddc0SDimitry Andric     return UndefValue::get(Ty);
45004eeddc0SDimitry Andric 
451fcaf7f86SDimitry Andric   AllocFnKind AK = getAllocFnKind(Alloc);
452fcaf7f86SDimitry Andric   if ((AK & AllocFnKind::Uninitialized) != AllocFnKind::Unknown)
453fcaf7f86SDimitry Andric     return UndefValue::get(Ty);
454fcaf7f86SDimitry Andric   if ((AK & AllocFnKind::Zeroed) != AllocFnKind::Unknown)
455fcaf7f86SDimitry Andric     return Constant::getNullValue(Ty);
456fcaf7f86SDimitry Andric 
45704eeddc0SDimitry Andric   return nullptr;
4580b57cec5SDimitry Andric }
4590b57cec5SDimitry Andric 
46081ad6265SDimitry Andric struct FreeFnsTy {
46181ad6265SDimitry Andric   unsigned NumParams;
46281ad6265SDimitry Andric   // Name of default allocator function to group malloc/free calls by family
46381ad6265SDimitry Andric   MallocFamily Family;
46481ad6265SDimitry Andric };
46581ad6265SDimitry Andric 
46681ad6265SDimitry Andric // clang-format off
46781ad6265SDimitry Andric static const std::pair<LibFunc, FreeFnsTy> FreeFnData[] = {
46881ad6265SDimitry Andric     {LibFunc_ZdlPv,                              {1, MallocFamily::CPPNew}},             // operator delete(void*)
46981ad6265SDimitry Andric     {LibFunc_ZdaPv,                              {1, MallocFamily::CPPNewArray}},        // operator delete[](void*)
47081ad6265SDimitry Andric     {LibFunc_msvc_delete_ptr32,                  {1, MallocFamily::MSVCNew}},            // operator delete(void*)
47181ad6265SDimitry Andric     {LibFunc_msvc_delete_ptr64,                  {1, MallocFamily::MSVCNew}},            // operator delete(void*)
47281ad6265SDimitry Andric     {LibFunc_msvc_delete_array_ptr32,            {1, MallocFamily::MSVCArrayNew}},       // operator delete[](void*)
47381ad6265SDimitry Andric     {LibFunc_msvc_delete_array_ptr64,            {1, MallocFamily::MSVCArrayNew}},       // operator delete[](void*)
47481ad6265SDimitry Andric     {LibFunc_ZdlPvj,                             {2, MallocFamily::CPPNew}},             // delete(void*, uint)
47581ad6265SDimitry Andric     {LibFunc_ZdlPvm,                             {2, MallocFamily::CPPNew}},             // delete(void*, ulong)
47681ad6265SDimitry Andric     {LibFunc_ZdlPvRKSt9nothrow_t,                {2, MallocFamily::CPPNew}},             // delete(void*, nothrow)
47781ad6265SDimitry Andric     {LibFunc_ZdlPvSt11align_val_t,               {2, MallocFamily::CPPNewAligned}},      // delete(void*, align_val_t)
47881ad6265SDimitry Andric     {LibFunc_ZdaPvj,                             {2, MallocFamily::CPPNewArray}},        // delete[](void*, uint)
47981ad6265SDimitry Andric     {LibFunc_ZdaPvm,                             {2, MallocFamily::CPPNewArray}},        // delete[](void*, ulong)
48081ad6265SDimitry Andric     {LibFunc_ZdaPvRKSt9nothrow_t,                {2, MallocFamily::CPPNewArray}},        // delete[](void*, nothrow)
48181ad6265SDimitry Andric     {LibFunc_ZdaPvSt11align_val_t,               {2, MallocFamily::CPPNewArrayAligned}}, // delete[](void*, align_val_t)
48281ad6265SDimitry Andric     {LibFunc_msvc_delete_ptr32_int,              {2, MallocFamily::MSVCNew}},            // delete(void*, uint)
48381ad6265SDimitry Andric     {LibFunc_msvc_delete_ptr64_longlong,         {2, MallocFamily::MSVCNew}},            // delete(void*, ulonglong)
48481ad6265SDimitry Andric     {LibFunc_msvc_delete_ptr32_nothrow,          {2, MallocFamily::MSVCNew}},            // delete(void*, nothrow)
48581ad6265SDimitry Andric     {LibFunc_msvc_delete_ptr64_nothrow,          {2, MallocFamily::MSVCNew}},            // delete(void*, nothrow)
48681ad6265SDimitry Andric     {LibFunc_msvc_delete_array_ptr32_int,        {2, MallocFamily::MSVCArrayNew}},       // delete[](void*, uint)
48781ad6265SDimitry Andric     {LibFunc_msvc_delete_array_ptr64_longlong,   {2, MallocFamily::MSVCArrayNew}},       // delete[](void*, ulonglong)
48881ad6265SDimitry Andric     {LibFunc_msvc_delete_array_ptr32_nothrow,    {2, MallocFamily::MSVCArrayNew}},       // delete[](void*, nothrow)
48981ad6265SDimitry Andric     {LibFunc_msvc_delete_array_ptr64_nothrow,    {2, MallocFamily::MSVCArrayNew}},       // delete[](void*, nothrow)
49081ad6265SDimitry Andric     {LibFunc___kmpc_free_shared,                 {2, MallocFamily::KmpcAllocShared}},    // OpenMP Offloading RTL free
49181ad6265SDimitry Andric     {LibFunc_ZdlPvSt11align_val_tRKSt9nothrow_t, {3, MallocFamily::CPPNewAligned}},      // delete(void*, align_val_t, nothrow)
49281ad6265SDimitry Andric     {LibFunc_ZdaPvSt11align_val_tRKSt9nothrow_t, {3, MallocFamily::CPPNewArrayAligned}}, // delete[](void*, align_val_t, nothrow)
49381ad6265SDimitry Andric     {LibFunc_ZdlPvjSt11align_val_t,              {3, MallocFamily::CPPNewAligned}},      // delete(void*, unsigned int, align_val_t)
49481ad6265SDimitry Andric     {LibFunc_ZdlPvmSt11align_val_t,              {3, MallocFamily::CPPNewAligned}},      // delete(void*, unsigned long, align_val_t)
49581ad6265SDimitry Andric     {LibFunc_ZdaPvjSt11align_val_t,              {3, MallocFamily::CPPNewArrayAligned}}, // delete[](void*, unsigned int, align_val_t)
49681ad6265SDimitry Andric     {LibFunc_ZdaPvmSt11align_val_t,              {3, MallocFamily::CPPNewArrayAligned}}, // delete[](void*, unsigned long, align_val_t)
49781ad6265SDimitry Andric };
49881ad6265SDimitry Andric // clang-format on
49981ad6265SDimitry Andric 
500bdd1243dSDimitry Andric std::optional<FreeFnsTy> getFreeFunctionDataForFunction(const Function *Callee,
50181ad6265SDimitry Andric                                                         const LibFunc TLIFn) {
50281ad6265SDimitry Andric   const auto *Iter =
50381ad6265SDimitry Andric       find_if(FreeFnData, [TLIFn](const std::pair<LibFunc, FreeFnsTy> &P) {
50481ad6265SDimitry Andric         return P.first == TLIFn;
50581ad6265SDimitry Andric       });
50681ad6265SDimitry Andric   if (Iter == std::end(FreeFnData))
507bdd1243dSDimitry Andric     return std::nullopt;
50881ad6265SDimitry Andric   return Iter->second;
50981ad6265SDimitry Andric }
51081ad6265SDimitry Andric 
511bdd1243dSDimitry Andric std::optional<StringRef>
512bdd1243dSDimitry Andric llvm::getAllocationFamily(const Value *I, const TargetLibraryInfo *TLI) {
51381ad6265SDimitry Andric   bool IsNoBuiltin;
51481ad6265SDimitry Andric   const Function *Callee = getCalledFunction(I, IsNoBuiltin);
51581ad6265SDimitry Andric   if (Callee == nullptr || IsNoBuiltin)
516bdd1243dSDimitry Andric     return std::nullopt;
51781ad6265SDimitry Andric   LibFunc TLIFn;
518fcaf7f86SDimitry Andric 
519fcaf7f86SDimitry Andric   if (TLI && TLI->getLibFunc(*Callee, TLIFn) && TLI->has(TLIFn)) {
520fcaf7f86SDimitry Andric     // Callee is some known library function.
52181ad6265SDimitry Andric     const auto AllocData = getAllocationDataForFunction(Callee, AnyAlloc, TLI);
52281ad6265SDimitry Andric     if (AllocData)
523bdd1243dSDimitry Andric       return mangledNameForMallocFamily(AllocData->Family);
52481ad6265SDimitry Andric     const auto FreeData = getFreeFunctionDataForFunction(Callee, TLIFn);
52581ad6265SDimitry Andric     if (FreeData)
526bdd1243dSDimitry Andric       return mangledNameForMallocFamily(FreeData->Family);
527fcaf7f86SDimitry Andric   }
528fcaf7f86SDimitry Andric   // Callee isn't a known library function, still check attributes.
529fcaf7f86SDimitry Andric   if (checkFnAllocKind(I, AllocFnKind::Free | AllocFnKind::Alloc |
530fcaf7f86SDimitry Andric                               AllocFnKind::Realloc)) {
531fcaf7f86SDimitry Andric     Attribute Attr = cast<CallBase>(I)->getFnAttr("alloc-family");
532fcaf7f86SDimitry Andric     if (Attr.isValid())
533fcaf7f86SDimitry Andric       return Attr.getValueAsString();
534fcaf7f86SDimitry Andric   }
535bdd1243dSDimitry Andric   return std::nullopt;
53681ad6265SDimitry Andric }
53781ad6265SDimitry Andric 
5380b57cec5SDimitry Andric /// isLibFreeFunction - Returns true if the function is a builtin free()
5390b57cec5SDimitry Andric bool llvm::isLibFreeFunction(const Function *F, const LibFunc TLIFn) {
540bdd1243dSDimitry Andric   std::optional<FreeFnsTy> FnData = getFreeFunctionDataForFunction(F, TLIFn);
54181ad6265SDimitry Andric   if (!FnData)
542fcaf7f86SDimitry Andric     return checkFnAllocKind(F, AllocFnKind::Free);
5430b57cec5SDimitry Andric 
5440b57cec5SDimitry Andric   // Check free prototype.
5450b57cec5SDimitry Andric   // FIXME: workaround for PR5130, this will be obsolete when a nobuiltin
5460b57cec5SDimitry Andric   // attribute will exist.
5470b57cec5SDimitry Andric   FunctionType *FTy = F->getFunctionType();
5480b57cec5SDimitry Andric   if (!FTy->getReturnType()->isVoidTy())
5490b57cec5SDimitry Andric     return false;
55081ad6265SDimitry Andric   if (FTy->getNumParams() != FnData->NumParams)
5510b57cec5SDimitry Andric     return false;
552bdd1243dSDimitry Andric   if (!FTy->getParamType(0)->isPointerTy())
5530b57cec5SDimitry Andric     return false;
5540b57cec5SDimitry Andric 
5550b57cec5SDimitry Andric   return true;
5560b57cec5SDimitry Andric }
5570b57cec5SDimitry Andric 
558fcaf7f86SDimitry Andric Value *llvm::getFreedOperand(const CallBase *CB, const TargetLibraryInfo *TLI) {
5590b57cec5SDimitry Andric   bool IsNoBuiltinCall;
560fcaf7f86SDimitry Andric   const Function *Callee = getCalledFunction(CB, IsNoBuiltinCall);
5610b57cec5SDimitry Andric   if (Callee == nullptr || IsNoBuiltinCall)
5620b57cec5SDimitry Andric     return nullptr;
5630b57cec5SDimitry Andric 
5640b57cec5SDimitry Andric   LibFunc TLIFn;
565fcaf7f86SDimitry Andric   if (TLI && TLI->getLibFunc(*Callee, TLIFn) && TLI->has(TLIFn) &&
566fcaf7f86SDimitry Andric       isLibFreeFunction(Callee, TLIFn)) {
567fcaf7f86SDimitry Andric     // All currently supported free functions free the first argument.
568fcaf7f86SDimitry Andric     return CB->getArgOperand(0);
5690b57cec5SDimitry Andric   }
5700b57cec5SDimitry Andric 
571fcaf7f86SDimitry Andric   if (checkFnAllocKind(CB, AllocFnKind::Free))
572fcaf7f86SDimitry Andric     return CB->getArgOperandWithAttribute(Attribute::AllocatedPointer);
573fcaf7f86SDimitry Andric 
574fcaf7f86SDimitry Andric   return nullptr;
575fcaf7f86SDimitry Andric }
5760b57cec5SDimitry Andric 
5770b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
5780b57cec5SDimitry Andric //  Utility functions to compute size of objects.
5790b57cec5SDimitry Andric //
5801db9f3b2SDimitry Andric static APInt getSizeWithOverflow(const SizeOffsetAPInt &Data) {
5811db9f3b2SDimitry Andric   APInt Size = Data.Size;
5821db9f3b2SDimitry Andric   APInt Offset = Data.Offset;
5831db9f3b2SDimitry Andric   if (Offset.isNegative() || Size.ult(Offset))
5841db9f3b2SDimitry Andric     return APInt(Size.getBitWidth(), 0);
5851db9f3b2SDimitry Andric   return Size - Offset;
5860b57cec5SDimitry Andric }
5870b57cec5SDimitry Andric 
5880b57cec5SDimitry Andric /// Compute the size of the object pointed by Ptr. Returns true and the
5890b57cec5SDimitry Andric /// object size in Size if successful, and false otherwise.
5900b57cec5SDimitry Andric /// If RoundToAlign is true, then Size is rounded up to the alignment of
5910b57cec5SDimitry Andric /// allocas, byval arguments, and global variables.
5920b57cec5SDimitry Andric bool llvm::getObjectSize(const Value *Ptr, uint64_t &Size, const DataLayout &DL,
5930b57cec5SDimitry Andric                          const TargetLibraryInfo *TLI, ObjectSizeOpts Opts) {
5940b57cec5SDimitry Andric   ObjectSizeOffsetVisitor Visitor(DL, TLI, Ptr->getContext(), Opts);
5951db9f3b2SDimitry Andric   SizeOffsetAPInt Data = Visitor.compute(const_cast<Value *>(Ptr));
5961db9f3b2SDimitry Andric   if (!Data.bothKnown())
5970b57cec5SDimitry Andric     return false;
5980b57cec5SDimitry Andric 
5990b57cec5SDimitry Andric   Size = getSizeWithOverflow(Data).getZExtValue();
6000b57cec5SDimitry Andric   return true;
6010b57cec5SDimitry Andric }
6020b57cec5SDimitry Andric 
6030b57cec5SDimitry Andric Value *llvm::lowerObjectSizeCall(IntrinsicInst *ObjectSize,
6040b57cec5SDimitry Andric                                  const DataLayout &DL,
6050b57cec5SDimitry Andric                                  const TargetLibraryInfo *TLI,
6060b57cec5SDimitry Andric                                  bool MustSucceed) {
60781ad6265SDimitry Andric   return lowerObjectSizeCall(ObjectSize, DL, TLI, /*AAResults=*/nullptr,
60881ad6265SDimitry Andric                              MustSucceed);
60981ad6265SDimitry Andric }
61081ad6265SDimitry Andric 
61106c3fb27SDimitry Andric Value *llvm::lowerObjectSizeCall(
61206c3fb27SDimitry Andric     IntrinsicInst *ObjectSize, const DataLayout &DL,
61306c3fb27SDimitry Andric     const TargetLibraryInfo *TLI, AAResults *AA, bool MustSucceed,
61406c3fb27SDimitry Andric     SmallVectorImpl<Instruction *> *InsertedInstructions) {
6150b57cec5SDimitry Andric   assert(ObjectSize->getIntrinsicID() == Intrinsic::objectsize &&
6160b57cec5SDimitry Andric          "ObjectSize must be a call to llvm.objectsize!");
6170b57cec5SDimitry Andric 
6180b57cec5SDimitry Andric   bool MaxVal = cast<ConstantInt>(ObjectSize->getArgOperand(1))->isZero();
6190b57cec5SDimitry Andric   ObjectSizeOpts EvalOptions;
62081ad6265SDimitry Andric   EvalOptions.AA = AA;
62181ad6265SDimitry Andric 
6220b57cec5SDimitry Andric   // Unless we have to fold this to something, try to be as accurate as
6230b57cec5SDimitry Andric   // possible.
6240b57cec5SDimitry Andric   if (MustSucceed)
6250b57cec5SDimitry Andric     EvalOptions.EvalMode =
6260b57cec5SDimitry Andric         MaxVal ? ObjectSizeOpts::Mode::Max : ObjectSizeOpts::Mode::Min;
6270b57cec5SDimitry Andric   else
628bdd1243dSDimitry Andric     EvalOptions.EvalMode = ObjectSizeOpts::Mode::ExactSizeFromOffset;
6290b57cec5SDimitry Andric 
6300b57cec5SDimitry Andric   EvalOptions.NullIsUnknownSize =
6310b57cec5SDimitry Andric       cast<ConstantInt>(ObjectSize->getArgOperand(2))->isOne();
6320b57cec5SDimitry Andric 
6330b57cec5SDimitry Andric   auto *ResultType = cast<IntegerType>(ObjectSize->getType());
6340b57cec5SDimitry Andric   bool StaticOnly = cast<ConstantInt>(ObjectSize->getArgOperand(3))->isZero();
6350b57cec5SDimitry Andric   if (StaticOnly) {
6360b57cec5SDimitry Andric     // FIXME: Does it make sense to just return a failure value if the size won't
6370b57cec5SDimitry Andric     // fit in the output and `!MustSucceed`?
6380b57cec5SDimitry Andric     uint64_t Size;
6390b57cec5SDimitry Andric     if (getObjectSize(ObjectSize->getArgOperand(0), Size, DL, TLI, EvalOptions) &&
6400b57cec5SDimitry Andric         isUIntN(ResultType->getBitWidth(), Size))
6410b57cec5SDimitry Andric       return ConstantInt::get(ResultType, Size);
6420b57cec5SDimitry Andric   } else {
6430b57cec5SDimitry Andric     LLVMContext &Ctx = ObjectSize->getFunction()->getContext();
6440b57cec5SDimitry Andric     ObjectSizeOffsetEvaluator Eval(DL, TLI, Ctx, EvalOptions);
6451db9f3b2SDimitry Andric     SizeOffsetValue SizeOffsetPair = Eval.compute(ObjectSize->getArgOperand(0));
6460b57cec5SDimitry Andric 
6470b57cec5SDimitry Andric     if (SizeOffsetPair != ObjectSizeOffsetEvaluator::unknown()) {
64806c3fb27SDimitry Andric       IRBuilder<TargetFolder, IRBuilderCallbackInserter> Builder(
64906c3fb27SDimitry Andric           Ctx, TargetFolder(DL), IRBuilderCallbackInserter([&](Instruction *I) {
65006c3fb27SDimitry Andric             if (InsertedInstructions)
65106c3fb27SDimitry Andric               InsertedInstructions->push_back(I);
65206c3fb27SDimitry Andric           }));
6530b57cec5SDimitry Andric       Builder.SetInsertPoint(ObjectSize);
6540b57cec5SDimitry Andric 
6551db9f3b2SDimitry Andric       Value *Size = SizeOffsetPair.Size;
6561db9f3b2SDimitry Andric       Value *Offset = SizeOffsetPair.Offset;
6571db9f3b2SDimitry Andric 
6580b57cec5SDimitry Andric       // If we've outside the end of the object, then we can always access
6590b57cec5SDimitry Andric       // exactly 0 bytes.
6601db9f3b2SDimitry Andric       Value *ResultSize = Builder.CreateSub(Size, Offset);
6611db9f3b2SDimitry Andric       Value *UseZero = Builder.CreateICmpULT(Size, Offset);
662480093f4SDimitry Andric       ResultSize = Builder.CreateZExtOrTrunc(ResultSize, ResultType);
663e8d8bef9SDimitry Andric       Value *Ret = Builder.CreateSelect(
664e8d8bef9SDimitry Andric           UseZero, ConstantInt::get(ResultType, 0), ResultSize);
665e8d8bef9SDimitry Andric 
666e8d8bef9SDimitry Andric       // The non-constant size expression cannot evaluate to -1.
6671db9f3b2SDimitry Andric       if (!isa<Constant>(Size) || !isa<Constant>(Offset))
668e8d8bef9SDimitry Andric         Builder.CreateAssumption(
669e8d8bef9SDimitry Andric             Builder.CreateICmpNE(Ret, ConstantInt::get(ResultType, -1)));
670e8d8bef9SDimitry Andric 
671e8d8bef9SDimitry Andric       return Ret;
6720b57cec5SDimitry Andric     }
6730b57cec5SDimitry Andric   }
6740b57cec5SDimitry Andric 
6750b57cec5SDimitry Andric   if (!MustSucceed)
6760b57cec5SDimitry Andric     return nullptr;
6770b57cec5SDimitry Andric 
6780b57cec5SDimitry Andric   return ConstantInt::get(ResultType, MaxVal ? -1ULL : 0);
6790b57cec5SDimitry Andric }
6800b57cec5SDimitry Andric 
6810b57cec5SDimitry Andric STATISTIC(ObjectVisitorArgument,
6820b57cec5SDimitry Andric           "Number of arguments with unsolved size and offset");
6830b57cec5SDimitry Andric STATISTIC(ObjectVisitorLoad,
6840b57cec5SDimitry Andric           "Number of load instructions with unsolved size and offset");
6850b57cec5SDimitry Andric 
6860eae32dcSDimitry Andric APInt ObjectSizeOffsetVisitor::align(APInt Size, MaybeAlign Alignment) {
6878bcb0991SDimitry Andric   if (Options.RoundToAlign && Alignment)
68881ad6265SDimitry Andric     return APInt(IntTyBits, alignTo(Size.getZExtValue(), *Alignment));
6890b57cec5SDimitry Andric   return Size;
6900b57cec5SDimitry Andric }
6910b57cec5SDimitry Andric 
6920b57cec5SDimitry Andric ObjectSizeOffsetVisitor::ObjectSizeOffsetVisitor(const DataLayout &DL,
6930b57cec5SDimitry Andric                                                  const TargetLibraryInfo *TLI,
6940b57cec5SDimitry Andric                                                  LLVMContext &Context,
6950b57cec5SDimitry Andric                                                  ObjectSizeOpts Options)
6960b57cec5SDimitry Andric     : DL(DL), TLI(TLI), Options(Options) {
6970b57cec5SDimitry Andric   // Pointer size must be rechecked for each object visited since it could have
6980b57cec5SDimitry Andric   // a different address space.
6990b57cec5SDimitry Andric }
7000b57cec5SDimitry Andric 
7011db9f3b2SDimitry Andric SizeOffsetAPInt ObjectSizeOffsetVisitor::compute(Value *V) {
7025f757f3fSDimitry Andric   InstructionsVisited = 0;
7035f757f3fSDimitry Andric   return computeImpl(V);
7045f757f3fSDimitry Andric }
7055f757f3fSDimitry Andric 
7061db9f3b2SDimitry Andric SizeOffsetAPInt ObjectSizeOffsetVisitor::computeImpl(Value *V) {
707d781ede6SDimitry Andric   unsigned InitialIntTyBits = DL.getIndexTypeSizeInBits(V->getType());
708d781ede6SDimitry Andric 
709d781ede6SDimitry Andric   // Stripping pointer casts can strip address space casts which can change the
710d781ede6SDimitry Andric   // index type size. The invariant is that we use the value type to determine
711d781ede6SDimitry Andric   // the index type size and if we stripped address space casts we have to
712d781ede6SDimitry Andric   // readjust the APInt as we pass it upwards in order for the APInt to match
713d781ede6SDimitry Andric   // the type the caller passed in.
714d781ede6SDimitry Andric   APInt Offset(InitialIntTyBits, 0);
715d781ede6SDimitry Andric   V = V->stripAndAccumulateConstantOffsets(
716d781ede6SDimitry Andric       DL, Offset, /* AllowNonInbounds */ true, /* AllowInvariantGroup */ true);
717d781ede6SDimitry Andric 
718d781ede6SDimitry Andric   // Later we use the index type size and zero but it will match the type of the
719d781ede6SDimitry Andric   // value that is passed to computeImpl.
720480093f4SDimitry Andric   IntTyBits = DL.getIndexTypeSizeInBits(V->getType());
721349cc55cSDimitry Andric   Zero = APInt::getZero(IntTyBits);
7220b57cec5SDimitry Andric 
7231db9f3b2SDimitry Andric   SizeOffsetAPInt SOT = computeValue(V);
7245f757f3fSDimitry Andric 
725d781ede6SDimitry Andric   bool IndexTypeSizeChanged = InitialIntTyBits != IntTyBits;
726d781ede6SDimitry Andric   if (!IndexTypeSizeChanged && Offset.isZero())
7275f757f3fSDimitry Andric     return SOT;
728d781ede6SDimitry Andric 
729d781ede6SDimitry Andric   // We stripped an address space cast that changed the index type size or we
730d781ede6SDimitry Andric   // accumulated some constant offset (or both). Readjust the bit width to match
731d781ede6SDimitry Andric   // the argument index type size and apply the offset, as required.
732d781ede6SDimitry Andric   if (IndexTypeSizeChanged) {
7331db9f3b2SDimitry Andric     if (SOT.knownSize() && !::CheckedZextOrTrunc(SOT.Size, InitialIntTyBits))
7341db9f3b2SDimitry Andric       SOT.Size = APInt();
7351db9f3b2SDimitry Andric     if (SOT.knownOffset() &&
7361db9f3b2SDimitry Andric         !::CheckedZextOrTrunc(SOT.Offset, InitialIntTyBits))
7371db9f3b2SDimitry Andric       SOT.Offset = APInt();
738d781ede6SDimitry Andric   }
739d781ede6SDimitry Andric   // If the computed offset is "unknown" we cannot add the stripped offset.
7401db9f3b2SDimitry Andric   return {SOT.Size,
7411db9f3b2SDimitry Andric           SOT.Offset.getBitWidth() > 1 ? SOT.Offset + Offset : SOT.Offset};
742d781ede6SDimitry Andric }
743d781ede6SDimitry Andric 
7441db9f3b2SDimitry Andric SizeOffsetAPInt ObjectSizeOffsetVisitor::computeValue(Value *V) {
7450b57cec5SDimitry Andric   if (Instruction *I = dyn_cast<Instruction>(V)) {
7460b57cec5SDimitry Andric     // If we have already seen this instruction, bail out. Cycles can happen in
7470b57cec5SDimitry Andric     // unreachable code after constant propagation.
7481db9f3b2SDimitry Andric     auto P = SeenInsts.try_emplace(I, ObjectSizeOffsetVisitor::unknown());
7495f757f3fSDimitry Andric     if (!P.second)
7505f757f3fSDimitry Andric       return P.first->second;
7515f757f3fSDimitry Andric     ++InstructionsVisited;
7525f757f3fSDimitry Andric     if (InstructionsVisited > ObjectSizeOffsetVisitorMaxVisitInstructions)
7531db9f3b2SDimitry Andric       return ObjectSizeOffsetVisitor::unknown();
7541db9f3b2SDimitry Andric     SizeOffsetAPInt Res = visit(*I);
7555f757f3fSDimitry Andric     // Cache the result for later visits. If we happened to visit this during
7565f757f3fSDimitry Andric     // the above recursion, we would consider it unknown until now.
7575f757f3fSDimitry Andric     SeenInsts[I] = Res;
7585f757f3fSDimitry Andric     return Res;
7590b57cec5SDimitry Andric   }
7600b57cec5SDimitry Andric   if (Argument *A = dyn_cast<Argument>(V))
7610b57cec5SDimitry Andric     return visitArgument(*A);
7620b57cec5SDimitry Andric   if (ConstantPointerNull *P = dyn_cast<ConstantPointerNull>(V))
7630b57cec5SDimitry Andric     return visitConstantPointerNull(*P);
7640b57cec5SDimitry Andric   if (GlobalAlias *GA = dyn_cast<GlobalAlias>(V))
7650b57cec5SDimitry Andric     return visitGlobalAlias(*GA);
7660b57cec5SDimitry Andric   if (GlobalVariable *GV = dyn_cast<GlobalVariable>(V))
7670b57cec5SDimitry Andric     return visitGlobalVariable(*GV);
7680b57cec5SDimitry Andric   if (UndefValue *UV = dyn_cast<UndefValue>(V))
7690b57cec5SDimitry Andric     return visitUndefValue(*UV);
7700b57cec5SDimitry Andric 
7710b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "ObjectSizeOffsetVisitor::compute() unhandled value: "
7720b57cec5SDimitry Andric                     << *V << '\n');
7731db9f3b2SDimitry Andric   return ObjectSizeOffsetVisitor::unknown();
7740b57cec5SDimitry Andric }
7750b57cec5SDimitry Andric 
7760b57cec5SDimitry Andric bool ObjectSizeOffsetVisitor::CheckedZextOrTrunc(APInt &I) {
77704eeddc0SDimitry Andric   return ::CheckedZextOrTrunc(I, IntTyBits);
7780b57cec5SDimitry Andric }
7790b57cec5SDimitry Andric 
7801db9f3b2SDimitry Andric SizeOffsetAPInt ObjectSizeOffsetVisitor::visitAllocaInst(AllocaInst &I) {
78181ad6265SDimitry Andric   TypeSize ElemSize = DL.getTypeAllocSize(I.getAllocatedType());
78281ad6265SDimitry Andric   if (ElemSize.isScalable() && Options.EvalMode != ObjectSizeOpts::Mode::Min)
7831db9f3b2SDimitry Andric     return ObjectSizeOffsetVisitor::unknown();
784bdd1243dSDimitry Andric   APInt Size(IntTyBits, ElemSize.getKnownMinValue());
7850b57cec5SDimitry Andric   if (!I.isArrayAllocation())
7861db9f3b2SDimitry Andric     return SizeOffsetAPInt(align(Size, I.getAlign()), Zero);
7870b57cec5SDimitry Andric 
7880b57cec5SDimitry Andric   Value *ArraySize = I.getArraySize();
7890b57cec5SDimitry Andric   if (const ConstantInt *C = dyn_cast<ConstantInt>(ArraySize)) {
7900b57cec5SDimitry Andric     APInt NumElems = C->getValue();
7910b57cec5SDimitry Andric     if (!CheckedZextOrTrunc(NumElems))
7921db9f3b2SDimitry Andric       return ObjectSizeOffsetVisitor::unknown();
7930b57cec5SDimitry Andric 
7940b57cec5SDimitry Andric     bool Overflow;
7950b57cec5SDimitry Andric     Size = Size.umul_ov(NumElems, Overflow);
7961db9f3b2SDimitry Andric     return Overflow ? ObjectSizeOffsetVisitor::unknown()
7971db9f3b2SDimitry Andric                     : SizeOffsetAPInt(align(Size, I.getAlign()), Zero);
7980b57cec5SDimitry Andric   }
7991db9f3b2SDimitry Andric   return ObjectSizeOffsetVisitor::unknown();
8000b57cec5SDimitry Andric }
8010b57cec5SDimitry Andric 
8021db9f3b2SDimitry Andric SizeOffsetAPInt ObjectSizeOffsetVisitor::visitArgument(Argument &A) {
803e8d8bef9SDimitry Andric   Type *MemoryTy = A.getPointeeInMemoryValueType();
8040b57cec5SDimitry Andric   // No interprocedural analysis is done at the moment.
805e8d8bef9SDimitry Andric   if (!MemoryTy|| !MemoryTy->isSized()) {
8060b57cec5SDimitry Andric     ++ObjectVisitorArgument;
8071db9f3b2SDimitry Andric     return ObjectSizeOffsetVisitor::unknown();
8080b57cec5SDimitry Andric   }
809e8d8bef9SDimitry Andric 
810e8d8bef9SDimitry Andric   APInt Size(IntTyBits, DL.getTypeAllocSize(MemoryTy));
8111db9f3b2SDimitry Andric   return SizeOffsetAPInt(align(Size, A.getParamAlign()), Zero);
8120b57cec5SDimitry Andric }
8130b57cec5SDimitry Andric 
8141db9f3b2SDimitry Andric SizeOffsetAPInt ObjectSizeOffsetVisitor::visitCallBase(CallBase &CB) {
815bdd1243dSDimitry Andric   if (std::optional<APInt> Size = getAllocSize(&CB, TLI))
8161db9f3b2SDimitry Andric     return SizeOffsetAPInt(*Size, Zero);
8171db9f3b2SDimitry Andric   return ObjectSizeOffsetVisitor::unknown();
8180b57cec5SDimitry Andric }
8190b57cec5SDimitry Andric 
8201db9f3b2SDimitry Andric SizeOffsetAPInt
8210b57cec5SDimitry Andric ObjectSizeOffsetVisitor::visitConstantPointerNull(ConstantPointerNull &CPN) {
8220b57cec5SDimitry Andric   // If null is unknown, there's nothing we can do. Additionally, non-zero
8230b57cec5SDimitry Andric   // address spaces can make use of null, so we don't presume to know anything
8240b57cec5SDimitry Andric   // about that.
8250b57cec5SDimitry Andric   //
8260b57cec5SDimitry Andric   // TODO: How should this work with address space casts? We currently just drop
8270b57cec5SDimitry Andric   // them on the floor, but it's unclear what we should do when a NULL from
8280b57cec5SDimitry Andric   // addrspace(1) gets casted to addrspace(0) (or vice-versa).
8290b57cec5SDimitry Andric   if (Options.NullIsUnknownSize || CPN.getType()->getAddressSpace())
8301db9f3b2SDimitry Andric     return ObjectSizeOffsetVisitor::unknown();
8311db9f3b2SDimitry Andric   return SizeOffsetAPInt(Zero, Zero);
8320b57cec5SDimitry Andric }
8330b57cec5SDimitry Andric 
8341db9f3b2SDimitry Andric SizeOffsetAPInt
8350b57cec5SDimitry Andric ObjectSizeOffsetVisitor::visitExtractElementInst(ExtractElementInst &) {
8361db9f3b2SDimitry Andric   return ObjectSizeOffsetVisitor::unknown();
8370b57cec5SDimitry Andric }
8380b57cec5SDimitry Andric 
8391db9f3b2SDimitry Andric SizeOffsetAPInt
8400b57cec5SDimitry Andric ObjectSizeOffsetVisitor::visitExtractValueInst(ExtractValueInst &) {
8410b57cec5SDimitry Andric   // Easy cases were already folded by previous passes.
8421db9f3b2SDimitry Andric   return ObjectSizeOffsetVisitor::unknown();
8430b57cec5SDimitry Andric }
8440b57cec5SDimitry Andric 
8451db9f3b2SDimitry Andric SizeOffsetAPInt ObjectSizeOffsetVisitor::visitGlobalAlias(GlobalAlias &GA) {
8460b57cec5SDimitry Andric   if (GA.isInterposable())
8471db9f3b2SDimitry Andric     return ObjectSizeOffsetVisitor::unknown();
8485f757f3fSDimitry Andric   return computeImpl(GA.getAliasee());
8490b57cec5SDimitry Andric }
8500b57cec5SDimitry Andric 
8511db9f3b2SDimitry Andric SizeOffsetAPInt
8521db9f3b2SDimitry Andric ObjectSizeOffsetVisitor::visitGlobalVariable(GlobalVariable &GV) {
85306c3fb27SDimitry Andric   if (!GV.getValueType()->isSized() || GV.hasExternalWeakLinkage() ||
85406c3fb27SDimitry Andric       ((!GV.hasInitializer() || GV.isInterposable()) &&
85506c3fb27SDimitry Andric        Options.EvalMode != ObjectSizeOpts::Mode::Min))
8561db9f3b2SDimitry Andric     return ObjectSizeOffsetVisitor::unknown();
8570b57cec5SDimitry Andric 
8580b57cec5SDimitry Andric   APInt Size(IntTyBits, DL.getTypeAllocSize(GV.getValueType()));
8591db9f3b2SDimitry Andric   return SizeOffsetAPInt(align(Size, GV.getAlign()), Zero);
8600b57cec5SDimitry Andric }
8610b57cec5SDimitry Andric 
8621db9f3b2SDimitry Andric SizeOffsetAPInt ObjectSizeOffsetVisitor::visitIntToPtrInst(IntToPtrInst &) {
8630b57cec5SDimitry Andric   // clueless
8641db9f3b2SDimitry Andric   return ObjectSizeOffsetVisitor::unknown();
8650b57cec5SDimitry Andric }
8660b57cec5SDimitry Andric 
8671db9f3b2SDimitry Andric SizeOffsetAPInt ObjectSizeOffsetVisitor::findLoadSizeOffset(
86881ad6265SDimitry Andric     LoadInst &Load, BasicBlock &BB, BasicBlock::iterator From,
8691db9f3b2SDimitry Andric     SmallDenseMap<BasicBlock *, SizeOffsetAPInt, 8> &VisitedBlocks,
87081ad6265SDimitry Andric     unsigned &ScannedInstCount) {
87181ad6265SDimitry Andric   constexpr unsigned MaxInstsToScan = 128;
87281ad6265SDimitry Andric 
87381ad6265SDimitry Andric   auto Where = VisitedBlocks.find(&BB);
87481ad6265SDimitry Andric   if (Where != VisitedBlocks.end())
87581ad6265SDimitry Andric     return Where->second;
87681ad6265SDimitry Andric 
8771db9f3b2SDimitry Andric   auto Unknown = [&BB, &VisitedBlocks]() {
8781db9f3b2SDimitry Andric     return VisitedBlocks[&BB] = ObjectSizeOffsetVisitor::unknown();
87981ad6265SDimitry Andric   };
8801db9f3b2SDimitry Andric   auto Known = [&BB, &VisitedBlocks](SizeOffsetAPInt SO) {
88181ad6265SDimitry Andric     return VisitedBlocks[&BB] = SO;
88281ad6265SDimitry Andric   };
88381ad6265SDimitry Andric 
88481ad6265SDimitry Andric   do {
88581ad6265SDimitry Andric     Instruction &I = *From;
88681ad6265SDimitry Andric 
88781ad6265SDimitry Andric     if (I.isDebugOrPseudoInst())
88881ad6265SDimitry Andric       continue;
88981ad6265SDimitry Andric 
89081ad6265SDimitry Andric     if (++ScannedInstCount > MaxInstsToScan)
89181ad6265SDimitry Andric       return Unknown();
89281ad6265SDimitry Andric 
89381ad6265SDimitry Andric     if (!I.mayWriteToMemory())
89481ad6265SDimitry Andric       continue;
89581ad6265SDimitry Andric 
89681ad6265SDimitry Andric     if (auto *SI = dyn_cast<StoreInst>(&I)) {
89781ad6265SDimitry Andric       AliasResult AR =
89881ad6265SDimitry Andric           Options.AA->alias(SI->getPointerOperand(), Load.getPointerOperand());
89981ad6265SDimitry Andric       switch ((AliasResult::Kind)AR) {
90081ad6265SDimitry Andric       case AliasResult::NoAlias:
90181ad6265SDimitry Andric         continue;
90281ad6265SDimitry Andric       case AliasResult::MustAlias:
90381ad6265SDimitry Andric         if (SI->getValueOperand()->getType()->isPointerTy())
9045f757f3fSDimitry Andric           return Known(computeImpl(SI->getValueOperand()));
90581ad6265SDimitry Andric         else
90681ad6265SDimitry Andric           return Unknown(); // No handling of non-pointer values by `compute`.
90781ad6265SDimitry Andric       default:
90881ad6265SDimitry Andric         return Unknown();
90981ad6265SDimitry Andric       }
91081ad6265SDimitry Andric     }
91181ad6265SDimitry Andric 
91281ad6265SDimitry Andric     if (auto *CB = dyn_cast<CallBase>(&I)) {
91381ad6265SDimitry Andric       Function *Callee = CB->getCalledFunction();
91481ad6265SDimitry Andric       // Bail out on indirect call.
91581ad6265SDimitry Andric       if (!Callee)
91681ad6265SDimitry Andric         return Unknown();
91781ad6265SDimitry Andric 
91881ad6265SDimitry Andric       LibFunc TLIFn;
91981ad6265SDimitry Andric       if (!TLI || !TLI->getLibFunc(*CB->getCalledFunction(), TLIFn) ||
92081ad6265SDimitry Andric           !TLI->has(TLIFn))
92181ad6265SDimitry Andric         return Unknown();
92281ad6265SDimitry Andric 
92381ad6265SDimitry Andric       // TODO: There's probably more interesting case to support here.
92481ad6265SDimitry Andric       if (TLIFn != LibFunc_posix_memalign)
92581ad6265SDimitry Andric         return Unknown();
92681ad6265SDimitry Andric 
92781ad6265SDimitry Andric       AliasResult AR =
92881ad6265SDimitry Andric           Options.AA->alias(CB->getOperand(0), Load.getPointerOperand());
92981ad6265SDimitry Andric       switch ((AliasResult::Kind)AR) {
93081ad6265SDimitry Andric       case AliasResult::NoAlias:
93181ad6265SDimitry Andric         continue;
93281ad6265SDimitry Andric       case AliasResult::MustAlias:
93381ad6265SDimitry Andric         break;
93481ad6265SDimitry Andric       default:
93581ad6265SDimitry Andric         return Unknown();
93681ad6265SDimitry Andric       }
93781ad6265SDimitry Andric 
93881ad6265SDimitry Andric       // Is the error status of posix_memalign correctly checked? If not it
93981ad6265SDimitry Andric       // would be incorrect to assume it succeeds and load doesn't see the
94081ad6265SDimitry Andric       // previous value.
941bdd1243dSDimitry Andric       std::optional<bool> Checked = isImpliedByDomCondition(
94281ad6265SDimitry Andric           ICmpInst::ICMP_EQ, CB, ConstantInt::get(CB->getType(), 0), &Load, DL);
94381ad6265SDimitry Andric       if (!Checked || !*Checked)
94481ad6265SDimitry Andric         return Unknown();
94581ad6265SDimitry Andric 
94681ad6265SDimitry Andric       Value *Size = CB->getOperand(2);
94781ad6265SDimitry Andric       auto *C = dyn_cast<ConstantInt>(Size);
94881ad6265SDimitry Andric       if (!C)
94981ad6265SDimitry Andric         return Unknown();
95081ad6265SDimitry Andric 
95181ad6265SDimitry Andric       return Known({C->getValue(), APInt(C->getValue().getBitWidth(), 0)});
95281ad6265SDimitry Andric     }
95381ad6265SDimitry Andric 
95481ad6265SDimitry Andric     return Unknown();
95581ad6265SDimitry Andric   } while (From-- != BB.begin());
95681ad6265SDimitry Andric 
9571db9f3b2SDimitry Andric   SmallVector<SizeOffsetAPInt> PredecessorSizeOffsets;
95881ad6265SDimitry Andric   for (auto *PredBB : predecessors(&BB)) {
95981ad6265SDimitry Andric     PredecessorSizeOffsets.push_back(findLoadSizeOffset(
96081ad6265SDimitry Andric         Load, *PredBB, BasicBlock::iterator(PredBB->getTerminator()),
96181ad6265SDimitry Andric         VisitedBlocks, ScannedInstCount));
9621db9f3b2SDimitry Andric     if (!PredecessorSizeOffsets.back().bothKnown())
96381ad6265SDimitry Andric       return Unknown();
96481ad6265SDimitry Andric   }
96581ad6265SDimitry Andric 
96681ad6265SDimitry Andric   if (PredecessorSizeOffsets.empty())
96781ad6265SDimitry Andric     return Unknown();
96881ad6265SDimitry Andric 
9691db9f3b2SDimitry Andric   return Known(std::accumulate(
9701db9f3b2SDimitry Andric       PredecessorSizeOffsets.begin() + 1, PredecessorSizeOffsets.end(),
97181ad6265SDimitry Andric       PredecessorSizeOffsets.front(),
9721db9f3b2SDimitry Andric       [this](SizeOffsetAPInt LHS, SizeOffsetAPInt RHS) {
97381ad6265SDimitry Andric         return combineSizeOffset(LHS, RHS);
97481ad6265SDimitry Andric       }));
97581ad6265SDimitry Andric }
97681ad6265SDimitry Andric 
9771db9f3b2SDimitry Andric SizeOffsetAPInt ObjectSizeOffsetVisitor::visitLoadInst(LoadInst &LI) {
97881ad6265SDimitry Andric   if (!Options.AA) {
9790b57cec5SDimitry Andric     ++ObjectVisitorLoad;
9801db9f3b2SDimitry Andric     return ObjectSizeOffsetVisitor::unknown();
9810b57cec5SDimitry Andric   }
9820b57cec5SDimitry Andric 
9831db9f3b2SDimitry Andric   SmallDenseMap<BasicBlock *, SizeOffsetAPInt, 8> VisitedBlocks;
98481ad6265SDimitry Andric   unsigned ScannedInstCount = 0;
9851db9f3b2SDimitry Andric   SizeOffsetAPInt SO =
98681ad6265SDimitry Andric       findLoadSizeOffset(LI, *LI.getParent(), BasicBlock::iterator(LI),
98781ad6265SDimitry Andric                          VisitedBlocks, ScannedInstCount);
9881db9f3b2SDimitry Andric   if (!SO.bothKnown())
98981ad6265SDimitry Andric     ++ObjectVisitorLoad;
99081ad6265SDimitry Andric   return SO;
99181ad6265SDimitry Andric }
99281ad6265SDimitry Andric 
9931db9f3b2SDimitry Andric SizeOffsetAPInt
9941db9f3b2SDimitry Andric ObjectSizeOffsetVisitor::combineSizeOffset(SizeOffsetAPInt LHS,
9951db9f3b2SDimitry Andric                                            SizeOffsetAPInt RHS) {
9961db9f3b2SDimitry Andric   if (!LHS.bothKnown() || !RHS.bothKnown())
9971db9f3b2SDimitry Andric     return ObjectSizeOffsetVisitor::unknown();
99881ad6265SDimitry Andric 
99981ad6265SDimitry Andric   switch (Options.EvalMode) {
100081ad6265SDimitry Andric   case ObjectSizeOpts::Mode::Min:
100181ad6265SDimitry Andric     return (getSizeWithOverflow(LHS).slt(getSizeWithOverflow(RHS))) ? LHS : RHS;
100281ad6265SDimitry Andric   case ObjectSizeOpts::Mode::Max:
100381ad6265SDimitry Andric     return (getSizeWithOverflow(LHS).sgt(getSizeWithOverflow(RHS))) ? LHS : RHS;
1004bdd1243dSDimitry Andric   case ObjectSizeOpts::Mode::ExactSizeFromOffset:
10051db9f3b2SDimitry Andric     return (getSizeWithOverflow(LHS).eq(getSizeWithOverflow(RHS)))
10061db9f3b2SDimitry Andric                ? LHS
10071db9f3b2SDimitry Andric                : ObjectSizeOffsetVisitor::unknown();
1008bdd1243dSDimitry Andric   case ObjectSizeOpts::Mode::ExactUnderlyingSizeAndOffset:
10091db9f3b2SDimitry Andric     return LHS == RHS ? LHS : ObjectSizeOffsetVisitor::unknown();
101081ad6265SDimitry Andric   }
101181ad6265SDimitry Andric   llvm_unreachable("missing an eval mode");
101281ad6265SDimitry Andric }
101381ad6265SDimitry Andric 
10141db9f3b2SDimitry Andric SizeOffsetAPInt ObjectSizeOffsetVisitor::visitPHINode(PHINode &PN) {
101506c3fb27SDimitry Andric   if (PN.getNumIncomingValues() == 0)
10161db9f3b2SDimitry Andric     return ObjectSizeOffsetVisitor::unknown();
101781ad6265SDimitry Andric   auto IncomingValues = PN.incoming_values();
101881ad6265SDimitry Andric   return std::accumulate(IncomingValues.begin() + 1, IncomingValues.end(),
10195f757f3fSDimitry Andric                          computeImpl(*IncomingValues.begin()),
10201db9f3b2SDimitry Andric                          [this](SizeOffsetAPInt LHS, Value *VRHS) {
10215f757f3fSDimitry Andric                            return combineSizeOffset(LHS, computeImpl(VRHS));
102281ad6265SDimitry Andric                          });
10230b57cec5SDimitry Andric }
10240b57cec5SDimitry Andric 
10251db9f3b2SDimitry Andric SizeOffsetAPInt ObjectSizeOffsetVisitor::visitSelectInst(SelectInst &I) {
10265f757f3fSDimitry Andric   return combineSizeOffset(computeImpl(I.getTrueValue()),
10275f757f3fSDimitry Andric                            computeImpl(I.getFalseValue()));
10280b57cec5SDimitry Andric }
10290b57cec5SDimitry Andric 
10301db9f3b2SDimitry Andric SizeOffsetAPInt ObjectSizeOffsetVisitor::visitUndefValue(UndefValue &) {
10311db9f3b2SDimitry Andric   return SizeOffsetAPInt(Zero, Zero);
10320b57cec5SDimitry Andric }
10330b57cec5SDimitry Andric 
10341db9f3b2SDimitry Andric SizeOffsetAPInt ObjectSizeOffsetVisitor::visitInstruction(Instruction &I) {
10350b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "ObjectSizeOffsetVisitor unknown instruction:" << I
10360b57cec5SDimitry Andric                     << '\n');
10371db9f3b2SDimitry Andric   return ObjectSizeOffsetVisitor::unknown();
10380b57cec5SDimitry Andric }
10390b57cec5SDimitry Andric 
10401db9f3b2SDimitry Andric // Just set these right here...
10411db9f3b2SDimitry Andric SizeOffsetValue::SizeOffsetValue(const SizeOffsetWeakTrackingVH &SOT)
10421db9f3b2SDimitry Andric     : SizeOffsetType(SOT.Size, SOT.Offset) {}
10431db9f3b2SDimitry Andric 
10440b57cec5SDimitry Andric ObjectSizeOffsetEvaluator::ObjectSizeOffsetEvaluator(
10450b57cec5SDimitry Andric     const DataLayout &DL, const TargetLibraryInfo *TLI, LLVMContext &Context,
10460b57cec5SDimitry Andric     ObjectSizeOpts EvalOpts)
10470b57cec5SDimitry Andric     : DL(DL), TLI(TLI), Context(Context),
10480b57cec5SDimitry Andric       Builder(Context, TargetFolder(DL),
10490b57cec5SDimitry Andric               IRBuilderCallbackInserter(
10500b57cec5SDimitry Andric                   [&](Instruction *I) { InsertedInstructions.insert(I); })),
10510b57cec5SDimitry Andric       EvalOpts(EvalOpts) {
10520b57cec5SDimitry Andric   // IntTy and Zero must be set for each compute() since the address space may
10530b57cec5SDimitry Andric   // be different for later objects.
10540b57cec5SDimitry Andric }
10550b57cec5SDimitry Andric 
10561db9f3b2SDimitry Andric SizeOffsetValue ObjectSizeOffsetEvaluator::compute(Value *V) {
10570b57cec5SDimitry Andric   // XXX - Are vectors of pointers possible here?
1058480093f4SDimitry Andric   IntTy = cast<IntegerType>(DL.getIndexType(V->getType()));
10590b57cec5SDimitry Andric   Zero = ConstantInt::get(IntTy, 0);
10600b57cec5SDimitry Andric 
10611db9f3b2SDimitry Andric   SizeOffsetValue Result = compute_(V);
10620b57cec5SDimitry Andric 
10631db9f3b2SDimitry Andric   if (!Result.bothKnown()) {
10640b57cec5SDimitry Andric     // Erase everything that was computed in this iteration from the cache, so
10650b57cec5SDimitry Andric     // that no dangling references are left behind. We could be a bit smarter if
10660b57cec5SDimitry Andric     // we kept a dependency graph. It's probably not worth the complexity.
10670b57cec5SDimitry Andric     for (const Value *SeenVal : SeenVals) {
10680b57cec5SDimitry Andric       CacheMapTy::iterator CacheIt = CacheMap.find(SeenVal);
10690b57cec5SDimitry Andric       // non-computable results can be safely cached
10701db9f3b2SDimitry Andric       if (CacheIt != CacheMap.end() && CacheIt->second.anyKnown())
10710b57cec5SDimitry Andric         CacheMap.erase(CacheIt);
10720b57cec5SDimitry Andric     }
10730b57cec5SDimitry Andric 
10740b57cec5SDimitry Andric     // Erase any instructions we inserted as part of the traversal.
10750b57cec5SDimitry Andric     for (Instruction *I : InsertedInstructions) {
107681ad6265SDimitry Andric       I->replaceAllUsesWith(PoisonValue::get(I->getType()));
10770b57cec5SDimitry Andric       I->eraseFromParent();
10780b57cec5SDimitry Andric     }
10790b57cec5SDimitry Andric   }
10800b57cec5SDimitry Andric 
10810b57cec5SDimitry Andric   SeenVals.clear();
10820b57cec5SDimitry Andric   InsertedInstructions.clear();
10830b57cec5SDimitry Andric   return Result;
10840b57cec5SDimitry Andric }
10850b57cec5SDimitry Andric 
10861db9f3b2SDimitry Andric SizeOffsetValue ObjectSizeOffsetEvaluator::compute_(Value *V) {
10870b57cec5SDimitry Andric   ObjectSizeOffsetVisitor Visitor(DL, TLI, Context, EvalOpts);
10881db9f3b2SDimitry Andric   SizeOffsetAPInt Const = Visitor.compute(V);
10891db9f3b2SDimitry Andric   if (Const.bothKnown())
10901db9f3b2SDimitry Andric     return SizeOffsetValue(ConstantInt::get(Context, Const.Size),
10911db9f3b2SDimitry Andric                            ConstantInt::get(Context, Const.Offset));
10920b57cec5SDimitry Andric 
10930b57cec5SDimitry Andric   V = V->stripPointerCasts();
10940b57cec5SDimitry Andric 
10950b57cec5SDimitry Andric   // Check cache.
10960b57cec5SDimitry Andric   CacheMapTy::iterator CacheIt = CacheMap.find(V);
10970b57cec5SDimitry Andric   if (CacheIt != CacheMap.end())
10980b57cec5SDimitry Andric     return CacheIt->second;
10990b57cec5SDimitry Andric 
11000b57cec5SDimitry Andric   // Always generate code immediately before the instruction being
11010b57cec5SDimitry Andric   // processed, so that the generated code dominates the same BBs.
11020b57cec5SDimitry Andric   BuilderTy::InsertPointGuard Guard(Builder);
11030b57cec5SDimitry Andric   if (Instruction *I = dyn_cast<Instruction>(V))
11040b57cec5SDimitry Andric     Builder.SetInsertPoint(I);
11050b57cec5SDimitry Andric 
11060b57cec5SDimitry Andric   // Now compute the size and offset.
11071db9f3b2SDimitry Andric   SizeOffsetValue Result;
11080b57cec5SDimitry Andric 
11090b57cec5SDimitry Andric   // Record the pointers that were handled in this run, so that they can be
11100b57cec5SDimitry Andric   // cleaned later if something fails. We also use this set to break cycles that
11110b57cec5SDimitry Andric   // can occur in dead code.
11120b57cec5SDimitry Andric   if (!SeenVals.insert(V).second) {
11131db9f3b2SDimitry Andric     Result = ObjectSizeOffsetEvaluator::unknown();
11140b57cec5SDimitry Andric   } else if (GEPOperator *GEP = dyn_cast<GEPOperator>(V)) {
11150b57cec5SDimitry Andric     Result = visitGEPOperator(*GEP);
11160b57cec5SDimitry Andric   } else if (Instruction *I = dyn_cast<Instruction>(V)) {
11170b57cec5SDimitry Andric     Result = visit(*I);
11180b57cec5SDimitry Andric   } else if (isa<Argument>(V) ||
11190b57cec5SDimitry Andric              (isa<ConstantExpr>(V) &&
11200b57cec5SDimitry Andric               cast<ConstantExpr>(V)->getOpcode() == Instruction::IntToPtr) ||
11210b57cec5SDimitry Andric              isa<GlobalAlias>(V) ||
11220b57cec5SDimitry Andric              isa<GlobalVariable>(V)) {
11230b57cec5SDimitry Andric     // Ignore values where we cannot do more than ObjectSizeVisitor.
11241db9f3b2SDimitry Andric     Result = ObjectSizeOffsetEvaluator::unknown();
11250b57cec5SDimitry Andric   } else {
11260b57cec5SDimitry Andric     LLVM_DEBUG(
11270b57cec5SDimitry Andric         dbgs() << "ObjectSizeOffsetEvaluator::compute() unhandled value: " << *V
11280b57cec5SDimitry Andric                << '\n');
11291db9f3b2SDimitry Andric     Result = ObjectSizeOffsetEvaluator::unknown();
11300b57cec5SDimitry Andric   }
11310b57cec5SDimitry Andric 
11320b57cec5SDimitry Andric   // Don't reuse CacheIt since it may be invalid at this point.
11331db9f3b2SDimitry Andric   CacheMap[V] = SizeOffsetWeakTrackingVH(Result);
11340b57cec5SDimitry Andric   return Result;
11350b57cec5SDimitry Andric }
11360b57cec5SDimitry Andric 
11371db9f3b2SDimitry Andric SizeOffsetValue ObjectSizeOffsetEvaluator::visitAllocaInst(AllocaInst &I) {
11380b57cec5SDimitry Andric   if (!I.getAllocatedType()->isSized())
11391db9f3b2SDimitry Andric     return ObjectSizeOffsetEvaluator::unknown();
11400b57cec5SDimitry Andric 
1141*0fca6ea1SDimitry Andric   // must be a VLA or vscale.
1142*0fca6ea1SDimitry Andric   assert(I.isArrayAllocation() || I.getAllocatedType()->isScalableTy());
1143fe6060f1SDimitry Andric 
114406c3fb27SDimitry Andric   // If needed, adjust the alloca's operand size to match the pointer indexing
114506c3fb27SDimitry Andric   // size. Subsequent math operations expect the types to match.
1146fe6060f1SDimitry Andric   Value *ArraySize = Builder.CreateZExtOrTrunc(
114706c3fb27SDimitry Andric       I.getArraySize(),
114806c3fb27SDimitry Andric       DL.getIndexType(I.getContext(), DL.getAllocaAddrSpace()));
1149fe6060f1SDimitry Andric   assert(ArraySize->getType() == Zero->getType() &&
115006c3fb27SDimitry Andric          "Expected zero constant to have pointer index type");
1151fe6060f1SDimitry Andric 
1152*0fca6ea1SDimitry Andric   Value *Size = Builder.CreateTypeSize(
1153*0fca6ea1SDimitry Andric       ArraySize->getType(), DL.getTypeAllocSize(I.getAllocatedType()));
11540b57cec5SDimitry Andric   Size = Builder.CreateMul(Size, ArraySize);
11551db9f3b2SDimitry Andric   return SizeOffsetValue(Size, Zero);
11560b57cec5SDimitry Andric }
11570b57cec5SDimitry Andric 
11581db9f3b2SDimitry Andric SizeOffsetValue ObjectSizeOffsetEvaluator::visitCallBase(CallBase &CB) {
1159bdd1243dSDimitry Andric   std::optional<AllocFnsTy> FnData = getAllocationSize(&CB, TLI);
11600b57cec5SDimitry Andric   if (!FnData)
11611db9f3b2SDimitry Andric     return ObjectSizeOffsetEvaluator::unknown();
11620b57cec5SDimitry Andric 
11630b57cec5SDimitry Andric   // Handle strdup-like functions separately.
11640b57cec5SDimitry Andric   if (FnData->AllocTy == StrDupLike) {
116504eeddc0SDimitry Andric     // TODO: implement evaluation of strdup/strndup
11661db9f3b2SDimitry Andric     return ObjectSizeOffsetEvaluator::unknown();
11670b57cec5SDimitry Andric   }
11680b57cec5SDimitry Andric 
11695ffd83dbSDimitry Andric   Value *FirstArg = CB.getArgOperand(FnData->FstParam);
1170480093f4SDimitry Andric   FirstArg = Builder.CreateZExtOrTrunc(FirstArg, IntTy);
11710b57cec5SDimitry Andric   if (FnData->SndParam < 0)
11721db9f3b2SDimitry Andric     return SizeOffsetValue(FirstArg, Zero);
11730b57cec5SDimitry Andric 
11745ffd83dbSDimitry Andric   Value *SecondArg = CB.getArgOperand(FnData->SndParam);
1175480093f4SDimitry Andric   SecondArg = Builder.CreateZExtOrTrunc(SecondArg, IntTy);
11760b57cec5SDimitry Andric   Value *Size = Builder.CreateMul(FirstArg, SecondArg);
11771db9f3b2SDimitry Andric   return SizeOffsetValue(Size, Zero);
11780b57cec5SDimitry Andric }
11790b57cec5SDimitry Andric 
11801db9f3b2SDimitry Andric SizeOffsetValue
11810b57cec5SDimitry Andric ObjectSizeOffsetEvaluator::visitExtractElementInst(ExtractElementInst &) {
11821db9f3b2SDimitry Andric   return ObjectSizeOffsetEvaluator::unknown();
11830b57cec5SDimitry Andric }
11840b57cec5SDimitry Andric 
11851db9f3b2SDimitry Andric SizeOffsetValue
11860b57cec5SDimitry Andric ObjectSizeOffsetEvaluator::visitExtractValueInst(ExtractValueInst &) {
11871db9f3b2SDimitry Andric   return ObjectSizeOffsetEvaluator::unknown();
11880b57cec5SDimitry Andric }
11890b57cec5SDimitry Andric 
11901db9f3b2SDimitry Andric SizeOffsetValue ObjectSizeOffsetEvaluator::visitGEPOperator(GEPOperator &GEP) {
11911db9f3b2SDimitry Andric   SizeOffsetValue PtrData = compute_(GEP.getPointerOperand());
11921db9f3b2SDimitry Andric   if (!PtrData.bothKnown())
11931db9f3b2SDimitry Andric     return ObjectSizeOffsetEvaluator::unknown();
11940b57cec5SDimitry Andric 
1195bdd1243dSDimitry Andric   Value *Offset = emitGEPOffset(&Builder, DL, &GEP, /*NoAssumptions=*/true);
11961db9f3b2SDimitry Andric   Offset = Builder.CreateAdd(PtrData.Offset, Offset);
11971db9f3b2SDimitry Andric   return SizeOffsetValue(PtrData.Size, Offset);
11980b57cec5SDimitry Andric }
11990b57cec5SDimitry Andric 
12001db9f3b2SDimitry Andric SizeOffsetValue ObjectSizeOffsetEvaluator::visitIntToPtrInst(IntToPtrInst &) {
12010b57cec5SDimitry Andric   // clueless
12021db9f3b2SDimitry Andric   return ObjectSizeOffsetEvaluator::unknown();
12030b57cec5SDimitry Andric }
12040b57cec5SDimitry Andric 
12051db9f3b2SDimitry Andric SizeOffsetValue ObjectSizeOffsetEvaluator::visitLoadInst(LoadInst &LI) {
12061db9f3b2SDimitry Andric   return ObjectSizeOffsetEvaluator::unknown();
12070b57cec5SDimitry Andric }
12080b57cec5SDimitry Andric 
12091db9f3b2SDimitry Andric SizeOffsetValue ObjectSizeOffsetEvaluator::visitPHINode(PHINode &PHI) {
12100b57cec5SDimitry Andric   // Create 2 PHIs: one for size and another for offset.
12110b57cec5SDimitry Andric   PHINode *SizePHI   = Builder.CreatePHI(IntTy, PHI.getNumIncomingValues());
12120b57cec5SDimitry Andric   PHINode *OffsetPHI = Builder.CreatePHI(IntTy, PHI.getNumIncomingValues());
12130b57cec5SDimitry Andric 
12140b57cec5SDimitry Andric   // Insert right away in the cache to handle recursive PHIs.
12151db9f3b2SDimitry Andric   CacheMap[&PHI] = SizeOffsetWeakTrackingVH(SizePHI, OffsetPHI);
12160b57cec5SDimitry Andric 
12170b57cec5SDimitry Andric   // Compute offset/size for each PHI incoming pointer.
12180b57cec5SDimitry Andric   for (unsigned i = 0, e = PHI.getNumIncomingValues(); i != e; ++i) {
12195f757f3fSDimitry Andric     BasicBlock *IncomingBlock = PHI.getIncomingBlock(i);
12205f757f3fSDimitry Andric     Builder.SetInsertPoint(IncomingBlock, IncomingBlock->getFirstInsertionPt());
12211db9f3b2SDimitry Andric     SizeOffsetValue EdgeData = compute_(PHI.getIncomingValue(i));
12220b57cec5SDimitry Andric 
12231db9f3b2SDimitry Andric     if (!EdgeData.bothKnown()) {
122481ad6265SDimitry Andric       OffsetPHI->replaceAllUsesWith(PoisonValue::get(IntTy));
12250b57cec5SDimitry Andric       OffsetPHI->eraseFromParent();
12260b57cec5SDimitry Andric       InsertedInstructions.erase(OffsetPHI);
122781ad6265SDimitry Andric       SizePHI->replaceAllUsesWith(PoisonValue::get(IntTy));
12280b57cec5SDimitry Andric       SizePHI->eraseFromParent();
12290b57cec5SDimitry Andric       InsertedInstructions.erase(SizePHI);
12301db9f3b2SDimitry Andric       return ObjectSizeOffsetEvaluator::unknown();
12310b57cec5SDimitry Andric     }
12321db9f3b2SDimitry Andric     SizePHI->addIncoming(EdgeData.Size, IncomingBlock);
12331db9f3b2SDimitry Andric     OffsetPHI->addIncoming(EdgeData.Offset, IncomingBlock);
12340b57cec5SDimitry Andric   }
12350b57cec5SDimitry Andric 
12360b57cec5SDimitry Andric   Value *Size = SizePHI, *Offset = OffsetPHI;
12370b57cec5SDimitry Andric   if (Value *Tmp = SizePHI->hasConstantValue()) {
12380b57cec5SDimitry Andric     Size = Tmp;
12390b57cec5SDimitry Andric     SizePHI->replaceAllUsesWith(Size);
12400b57cec5SDimitry Andric     SizePHI->eraseFromParent();
12410b57cec5SDimitry Andric     InsertedInstructions.erase(SizePHI);
12420b57cec5SDimitry Andric   }
12430b57cec5SDimitry Andric   if (Value *Tmp = OffsetPHI->hasConstantValue()) {
12440b57cec5SDimitry Andric     Offset = Tmp;
12450b57cec5SDimitry Andric     OffsetPHI->replaceAllUsesWith(Offset);
12460b57cec5SDimitry Andric     OffsetPHI->eraseFromParent();
12470b57cec5SDimitry Andric     InsertedInstructions.erase(OffsetPHI);
12480b57cec5SDimitry Andric   }
12491db9f3b2SDimitry Andric   return SizeOffsetValue(Size, Offset);
12500b57cec5SDimitry Andric }
12510b57cec5SDimitry Andric 
12521db9f3b2SDimitry Andric SizeOffsetValue ObjectSizeOffsetEvaluator::visitSelectInst(SelectInst &I) {
12531db9f3b2SDimitry Andric   SizeOffsetValue TrueSide = compute_(I.getTrueValue());
12541db9f3b2SDimitry Andric   SizeOffsetValue FalseSide = compute_(I.getFalseValue());
12550b57cec5SDimitry Andric 
12561db9f3b2SDimitry Andric   if (!TrueSide.bothKnown() || !FalseSide.bothKnown())
12571db9f3b2SDimitry Andric     return ObjectSizeOffsetEvaluator::unknown();
12580b57cec5SDimitry Andric   if (TrueSide == FalseSide)
12590b57cec5SDimitry Andric     return TrueSide;
12600b57cec5SDimitry Andric 
12611db9f3b2SDimitry Andric   Value *Size =
12621db9f3b2SDimitry Andric       Builder.CreateSelect(I.getCondition(), TrueSide.Size, FalseSide.Size);
12631db9f3b2SDimitry Andric   Value *Offset =
12641db9f3b2SDimitry Andric       Builder.CreateSelect(I.getCondition(), TrueSide.Offset, FalseSide.Offset);
12651db9f3b2SDimitry Andric   return SizeOffsetValue(Size, Offset);
12660b57cec5SDimitry Andric }
12670b57cec5SDimitry Andric 
12681db9f3b2SDimitry Andric SizeOffsetValue ObjectSizeOffsetEvaluator::visitInstruction(Instruction &I) {
12690b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "ObjectSizeOffsetEvaluator unknown instruction:" << I
12700b57cec5SDimitry Andric                     << '\n');
12711db9f3b2SDimitry Andric   return ObjectSizeOffsetEvaluator::unknown();
12720b57cec5SDimitry Andric }
1273