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 (!
TLI.getLibFunc(name, libfunc))
76 case LibFunc_ZnwjRKSt9nothrow_t:
77 case LibFunc_ZnwjSt11align_val_t:
78 case LibFunc_ZnwjSt11align_val_tRKSt9nothrow_t:
82 case LibFunc_ZnwmRKSt9nothrow_t:
83 case LibFunc_ZnwmSt11align_val_t:
84 case LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t:
88 case LibFunc_ZnajRKSt9nothrow_t:
89 case LibFunc_ZnajSt11align_val_t:
90 case LibFunc_ZnajSt11align_val_tRKSt9nothrow_t:
94 case LibFunc_ZnamRKSt9nothrow_t:
95 case LibFunc_ZnamSt11align_val_t:
96 case LibFunc_ZnamSt11align_val_tRKSt9nothrow_t:
99 case LibFunc_msvc_new_int:
100 case LibFunc_msvc_new_int_nothrow:
101 case LibFunc_msvc_new_longlong:
102 case LibFunc_msvc_new_longlong_nothrow:
103 case LibFunc_msvc_new_array_int:
104 case LibFunc_msvc_new_array_int_nothrow:
105 case LibFunc_msvc_new_array_longlong:
106 case LibFunc_msvc_new_array_longlong_nothrow:
124 const llvm::TargetLibraryInfo &
TLI) {
125 using namespace llvm;
126 llvm::LibFunc libfunc;
127 if (name ==
"_ZdlPvmSt11align_val_t")
129 if (!
TLI.getLibFunc(name, libfunc)) {
132 if (name ==
"_mlir_memref_to_llvm_free")
134 if (name ==
"__rust_dealloc")
136 if (name ==
"swift_release")
150 case LibFunc_msvc_delete_array_ptr32:
152 case LibFunc_msvc_delete_array_ptr64:
154 case LibFunc_msvc_delete_ptr32:
156 case LibFunc_msvc_delete_ptr64:
159 case LibFunc_ZdaPvRKSt9nothrow_t:
165 case LibFunc_ZdlPvRKSt9nothrow_t:
171 case LibFunc_ZdlPvSt11align_val_t:
173 case LibFunc_ZdaPvSt11align_val_t:
175 case LibFunc_msvc_delete_array_ptr32_int:
177 case LibFunc_msvc_delete_array_ptr32_nothrow:
179 case LibFunc_msvc_delete_array_ptr64_longlong:
181 case LibFunc_msvc_delete_array_ptr64_nothrow:
183 case LibFunc_msvc_delete_ptr32_int:
185 case LibFunc_msvc_delete_ptr32_nothrow:
187 case LibFunc_msvc_delete_ptr64_longlong:
189 case LibFunc_msvc_delete_ptr64_nothrow:
191 case LibFunc_ZdlPvSt11align_val_tRKSt9nothrow_t:
193 case LibFunc_ZdaPvSt11align_val_tRKSt9nothrow_t:
202 llvm::ArrayRef<llvm::Value *> argValues,
203 const llvm::StringRef funcName,
204 const llvm::TargetLibraryInfo &
TLI,
205 llvm::CallInst *orig) {
206 using namespace llvm;
210 if (funcName ==
"calloc" || funcName ==
"__rust_alloc_zeroed")
213 Value *allocSize = argValues[0];
214 if (funcName ==
"julia.gc_alloc_obj" || funcName ==
"jl_gc_alloc_typed" ||
215 funcName ==
"ijl_gc_alloc_typed") {
216 allocSize = argValues[1];
218 if (funcName ==
"enzyme_allocator") {
220 allocSize = argValues[*index];
222 Value *dst_arg = toZero;
224 if (funcName ==
"__size_returning_new_experiment")
225 dst_arg = bb.CreateExtractValue(dst_arg, 0);
227 if (dst_arg->getType()->isIntegerTy())
228 dst_arg = bb.CreateIntToPtr(dst_arg,
getInt8PtrTy(toZero->getContext()));
230 dst_arg = bb.CreateBitCast(
232 toZero->getType()->getPointerAddressSpace()));
234 auto val_arg = ConstantInt::get(Type::getInt8Ty(toZero->getContext()), 0);
236 bb.CreateZExtOrTrunc(allocSize, Type::getInt64Ty(toZero->getContext()));
238 auto memset = bb.CreateMemSet(dst_arg, val_arg, len_arg, MaybeAlign());
239 memset->addParamAttr(0, Attribute::NonNull);
240 if (
auto CI = dyn_cast<ConstantInt>(allocSize)) {
241 auto derefBytes = CI->getLimitedValue();
242#if LLVM_VERSION_MAJOR >= 14
243 memset->addDereferenceableParamAttr(0, derefBytes);
244 memset->setAttributes(
245 memset->getAttributes().addDereferenceableOrNullParamAttr(
246 memset->getContext(), 0, derefBytes));
248 memset->addDereferenceableAttr(llvm::AttributeList::FirstArgIndex,
250 memset->addDereferenceableOrNullAttr(llvm::AttributeList::FirstArgIndex,
261 llvm::StringRef allocationfn,
262 const llvm::DebugLoc &debuglocation,
263 const llvm::TargetLibraryInfo &
TLI,
264 llvm::CallInst *orig,
268 llvm::TargetLibraryInfo &
TLI) {
269 if (
auto *CI = llvm::dyn_cast<llvm::CallBase>(TmpOrig)) {
271 CI->getAttributes().getAttributes(llvm::AttributeList::FunctionIndex);
272 if (AttrList.hasAttribute(
"enzyme_allocation"))
275 if (Fn->hasFnAttribute(
"enzyme_allocation"))
283 llvm::TargetLibraryInfo &
TLI) {
284 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
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.