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