23#ifndef LIBRARYFUNCS_H_
24#define LIBRARYFUNCS_H_
26#include <llvm/ADT/StringMap.h>
27#include <llvm/Analysis/AliasAnalysis.h>
28#include <llvm/Analysis/TargetLibraryInfo.h>
29#include <llvm/IR/IRBuilder.h>
30#include <llvm/IR/InlineAsm.h>
31#include <llvm/IR/Instructions.h>
36extern llvm::StringMap<std::function<llvm::Value *(
37 llvm::IRBuilder<> &, llvm::CallInst *, llvm::ArrayRef<llvm::Value *>,
40extern llvm::StringMap<
41 std::function<llvm::CallInst *(llvm::IRBuilder<> &, llvm::Value *)>>
47 const llvm::TargetLibraryInfo &
TLI) {
48 if (name ==
"enzyme_allocator")
50 if (name ==
"calloc" || name ==
"malloc")
52 if (name ==
"_mlir_memref_to_llvm_alloc")
54 if (name ==
"swift_allocObject")
56 if (name ==
"__size_returning_new_experiment")
58 if (name ==
"__rust_alloc" || name ==
"__rust_alloc_zeroed")
60 if (name ==
"julia.gc_alloc_obj" || name ==
"jl_gc_alloc_typed" ||
61 name ==
"ijl_gc_alloc_typed")
67 llvm::LibFunc libfunc;
68#if LLVM_VERSION_MAJOR >= 24
69 libfunc =
TLI.getLibFunc(name);
70 if (libfunc == NotLibFunc)
73 if (!
TLI.getLibFunc(name, libfunc))
80 case LibFunc_aligned_alloc:
83 case LibFunc_ZnwjRKSt9nothrow_t:
84 case LibFunc_ZnwjSt11align_val_t:
85 case LibFunc_ZnwjSt11align_val_tRKSt9nothrow_t:
89 case LibFunc_ZnwmRKSt9nothrow_t:
90 case LibFunc_ZnwmSt11align_val_t:
91 case LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t:
95 case LibFunc_ZnajRKSt9nothrow_t:
96 case LibFunc_ZnajSt11align_val_t:
97 case LibFunc_ZnajSt11align_val_tRKSt9nothrow_t:
101 case LibFunc_ZnamRKSt9nothrow_t:
102 case LibFunc_ZnamSt11align_val_t:
103 case LibFunc_ZnamSt11align_val_tRKSt9nothrow_t:
106 case LibFunc_msvc_new_int:
107 case LibFunc_msvc_new_int_nothrow:
108 case LibFunc_msvc_new_longlong:
109 case LibFunc_msvc_new_longlong_nothrow:
110 case LibFunc_msvc_new_array_int:
111 case LibFunc_msvc_new_array_int_nothrow:
112 case LibFunc_msvc_new_array_longlong:
113 case LibFunc_msvc_new_array_longlong_nothrow:
131 return name ==
"cuMemFree" || name ==
"cuMemFree_v2" ||
132 name ==
"cuMemFreeAsync" || name ==
"cudaFree" ||
133 name ==
"cudaFreeAsync" || name ==
"cudaFreeHost";
140 const llvm::TargetLibraryInfo &
TLI) {
141 using namespace llvm;
142 llvm::LibFunc libfunc;
143 if (name ==
"_ZdlPvmSt11align_val_t")
145#if LLVM_VERSION_MAJOR >= 24
146 libfunc =
TLI.getLibFunc(name);
147 if (libfunc == NotLibFunc) {
149 if (!
TLI.getLibFunc(name, libfunc)) {
153 if (name ==
"_mlir_memref_to_llvm_free")
155 if (name ==
"__rust_dealloc")
157 if (name ==
"swift_release")
175 case LibFunc_msvc_delete_array_ptr32:
177 case LibFunc_msvc_delete_array_ptr64:
179 case LibFunc_msvc_delete_ptr32:
181 case LibFunc_msvc_delete_ptr64:
184 case LibFunc_ZdaPvRKSt9nothrow_t:
190 case LibFunc_ZdlPvRKSt9nothrow_t:
196 case LibFunc_ZdlPvSt11align_val_t:
198 case LibFunc_ZdaPvSt11align_val_t:
200 case LibFunc_msvc_delete_array_ptr32_int:
202 case LibFunc_msvc_delete_array_ptr32_nothrow:
204 case LibFunc_msvc_delete_array_ptr64_longlong:
206 case LibFunc_msvc_delete_array_ptr64_nothrow:
208 case LibFunc_msvc_delete_ptr32_int:
210 case LibFunc_msvc_delete_ptr32_nothrow:
212 case LibFunc_msvc_delete_ptr64_longlong:
214 case LibFunc_msvc_delete_ptr64_nothrow:
216 case LibFunc_ZdlPvSt11align_val_tRKSt9nothrow_t:
218 case LibFunc_ZdaPvSt11align_val_tRKSt9nothrow_t:
227 llvm::ArrayRef<llvm::Value *> argValues,
228 const llvm::StringRef funcName,
229 const llvm::TargetLibraryInfo &
TLI,
230 llvm::CallInst *orig) {
231 using namespace llvm;
235 if (funcName ==
"calloc" || funcName ==
"__rust_alloc_zeroed")
238 Value *allocSize = argValues[0];
239 if (funcName ==
"julia.gc_alloc_obj" || funcName ==
"jl_gc_alloc_typed" ||
240 funcName ==
"ijl_gc_alloc_typed" || funcName ==
"aligned_alloc") {
241 allocSize = argValues[1];
243 if (funcName ==
"enzyme_allocator") {
245 allocSize = argValues[*index];
247 Value *dst_arg = toZero;
249 if (funcName ==
"__size_returning_new_experiment")
250 dst_arg = bb.CreateExtractValue(dst_arg, 0);
252 if (dst_arg->getType()->isIntegerTy())
253 dst_arg = bb.CreateIntToPtr(dst_arg,
getInt8PtrTy(toZero->getContext()));
255 dst_arg = bb.CreateBitCast(
257 toZero->getType()->getPointerAddressSpace()));
259 auto val_arg = ConstantInt::get(Type::getInt8Ty(toZero->getContext()), 0);
261 bb.CreateZExtOrTrunc(allocSize, Type::getInt64Ty(toZero->getContext()));
263 auto memset = bb.CreateMemSet(dst_arg, val_arg, len_arg, MaybeAlign());
264 memset->addParamAttr(0, Attribute::NonNull);
265 if (
auto CI = dyn_cast<ConstantInt>(allocSize)) {
266 auto derefBytes = CI->getLimitedValue();
267#if LLVM_VERSION_MAJOR >= 14
268 memset->addDereferenceableParamAttr(0, derefBytes);
269 memset->setAttributes(
270 memset->getAttributes().addDereferenceableOrNullParamAttr(
271 memset->getContext(), 0, derefBytes));
273 memset->addDereferenceableAttr(llvm::AttributeList::FirstArgIndex,
275 memset->addDereferenceableOrNullAttr(llvm::AttributeList::FirstArgIndex,
286 llvm::StringRef allocationfn,
287 const llvm::DebugLoc &debuglocation,
288 const llvm::TargetLibraryInfo &
TLI,
289 llvm::CallInst *orig,
293 llvm::TargetLibraryInfo &
TLI) {
294 if (
auto *CI = llvm::dyn_cast<llvm::CallBase>(TmpOrig)) {
296 CI->getAttributes().getAttributes(llvm::AttributeList::FunctionIndex);
297 if (AttrList.hasAttribute(
"enzyme_allocation"))
300 if (Fn->hasFnAttribute(
"enzyme_allocation"))
308 llvm::TargetLibraryInfo &
TLI) {
309 if (
auto *CI = llvm::dyn_cast<llvm::CallBase>(TmpOrig)) {
static bool isDeallocationFunction(const llvm::StringRef name, const llvm::TargetLibraryInfo &TLI)
Return whether a given function is a known C/C++ memory deallocation function For updating below one ...
static bool isDeallocationCall(const llvm::Value *TmpOrig, llvm::TargetLibraryInfo &TLI)
llvm::StringMap< std::function< llvm::CallInst *(llvm::IRBuilder<> &, llvm::Value *)> > shadowErasers
static bool isCudaDeallocationFunction(const llvm::StringRef name)
Return whether a given function frees a CUDA allocation.
llvm::StringMap< std::function< llvm::Value *(llvm::IRBuilder<> &, llvm::CallInst *, llvm::ArrayRef< llvm::Value * >, GradientUtils *)> > shadowHandlers
llvm::CallInst * freeKnownAllocation(llvm::IRBuilder<> &builder, llvm::Value *tofree, llvm::StringRef allocationfn, const llvm::DebugLoc &debuglocation, const llvm::TargetLibraryInfo &TLI, llvm::CallInst *orig, GradientUtils *gutils)
Perform the corresponding deallocation of tofree, given it was allocated by allocationfn.
static bool isAllocationFunction(const llvm::StringRef name, const llvm::TargetLibraryInfo &TLI)
Return whether a given function is a known C/C++ memory allocation function For updating below one sh...
static void zeroKnownAllocation(llvm::IRBuilder<> &bb, llvm::Value *toZero, llvm::ArrayRef< llvm::Value * > argValues, const llvm::StringRef funcName, const llvm::TargetLibraryInfo &TLI, llvm::CallInst *orig)
static bool isAllocationCall(const llvm::Value *TmpOrig, llvm::TargetLibraryInfo &TLI)
static Operation * getFunctionFromCall(CallOpInterface iface)
static llvm::PointerType * getInt8PtrTy(llvm::LLVMContext &Context, unsigned AddressSpace=0)
static llvm::StringRef getFuncNameFromCall(const llvm::CallBase *op)
static llvm::Optional< size_t > getAllocationIndexFromCall(const llvm::CallBase *op)
llvm::TargetLibraryInfo & TLI
Various analysis results of newFunc.