29#include "llvm/ADT/SmallPtrSet.h"
30#include "llvm/ADT/SmallVector.h"
32#include "llvm/IR/BasicBlock.h"
33#include "llvm/IR/IRBuilder.h"
34#include "llvm/IR/Instructions.h"
35#include "llvm/IR/Type.h"
36#include "llvm/IR/User.h"
37#include "llvm/IR/Value.h"
38#include "llvm/IR/ValueMap.h"
40#include "llvm/Transforms/Utils/BasicBlockUtils.h"
41#include "llvm/Transforms/Utils/Cloning.h"
48 const SmallPtrSetImpl<Function *> &sampleFunctions,
49 const SmallPtrSetImpl<Function *> &observeFunctions,
50 Function *newFunc, Argument *trace,
51 Argument *observations, Argument *likelihood,
53 : trace(trace), observations(observations), likelihood(likelihood),
54 interface(interface), mode(mode), newFunc(newFunc),
55 sampleFunctions(sampleFunctions.begin(), sampleFunctions.end()),
56 observeFunctions(observeFunctions.begin(), observeFunctions.end()){};
60 const SmallPtrSetImpl<Function *> &sampleFunctions,
61 const SmallPtrSetImpl<Function *> &observeFunctions,
63 ValueToValueMapTy &originalToNewFn) {
64 auto &Context = oldFunc->getContext();
65 FunctionType *orig_FTy = oldFunc->getFunctionType();
66 SmallVector<Type *, 4> params;
68 for (
unsigned i = 0; i < orig_FTy->getNumParams(); ++i) {
69 params.push_back(orig_FTy->getParamType(i));
72 Type *likelihood_acc_type =
getUnqual(Type::getDoubleTy(Context));
73 params.push_back(likelihood_acc_type);
84 Type *RetTy = oldFunc->getReturnType();
85 FunctionType *FTy = FunctionType::get(RetTy, params, oldFunc->isVarArg());
90 mode_str =
"likelihood";
96 mode_str =
"condition";
100 Function *
newFunc = Function::Create(
101 FTy, Function::LinkageTypes::InternalLinkage,
102 Twine(mode_str) +
"_" + oldFunc->getName(), oldFunc->getParent());
104 auto DestArg =
newFunc->arg_begin();
105 auto SrcArg = oldFunc->arg_begin();
107 for (
unsigned i = 0; i < orig_FTy->getNumParams(); ++i) {
108 Argument *arg = SrcArg;
109 originalToNewFn[arg] = DestArg;
110 DestArg->setName(arg->getName());
115 SmallVector<ReturnInst *, 4> Returns;
116 if (!oldFunc->empty()) {
117#if LLVM_VERSION_MAJOR >= 13
118 CloneFunctionInto(
newFunc, oldFunc, originalToNewFn,
119 CloneFunctionChangeType::LocalChangesOnly, Returns,
"",
123 CloneFunctionInto(
newFunc, oldFunc, originalToNewFn,
true, Returns,
"",
129 auto entry = BasicBlock::Create(
newFunc->getContext(),
"entry",
newFunc);
130 IRBuilder<> B(entry);
131 B.CreateUnreachable();
134 newFunc->setLinkage(Function::LinkageTypes::InternalLinkage);
136 Argument *trace =
nullptr;
137 Argument *observations =
nullptr;
138 Argument *likelihood =
nullptr;
145 arg->setName(
"trace");
152 arg->setName(
"observations");
158 arg->setName(
"likelihood");
175std::pair<Value *, Constant *>
176TraceUtils::ValueToVoidPtrAndSize(IRBuilder<> &Builder, Value *val,
178 auto valsize = val->getType()->getPrimitiveSizeInBits();
180 if (val->getType()->isPointerTy()) {
182 Builder.CreatePointerCast(val,
getInt8PtrTy(val->getContext()));
183 return {retval, ConstantInt::get(size_type, valsize / 8)};
186 auto M = Builder.GetInsertBlock()->getModule();
187 auto &DL = M->getDataLayout();
188 auto pointersize = DL.getPointerSizeInBits();
190 if (valsize <= pointersize) {
192 Builder.CreateBitCast(val, IntegerType::get(M->getContext(), valsize));
193 if (valsize != pointersize)
194 cast = Builder.CreateZExt(cast, Builder.getIntPtrTy(DL));
197 Builder.CreateIntToPtr(cast,
getInt8PtrTy(cast->getContext()));
198 return {retval, ConstantInt::get(size_type, valsize / 8)};
201 &Builder.GetInsertBlock()->getParent()->getEntryBlock()));
202 auto alloca = AllocaBuilder.CreateAlloca(val->getType(),
nullptr,
203 val->getName() +
".ptr");
204 Builder.CreateStore(val, alloca);
205 return {alloca, ConstantInt::get(size_type, valsize / 8)};
212#if LLVM_VERSION_MAJOR >= 14
213 call->addAttributeAtIndex(
214 AttributeList::FunctionIndex,
215 Attribute::get(call->getContext(),
"enzyme_newtrace"));
217 call->addAttribute(AttributeList::FunctionIndex,
218 Attribute::get(call->getContext(),
"enzyme_newtrace"));
227#if LLVM_VERSION_MAJOR >= 14
228 call->addAttributeAtIndex(
229 AttributeList::FunctionIndex,
230 Attribute::get(call->getContext(),
"enzyme_freetrace"));
232 call->addAttribute(AttributeList::FunctionIndex,
233 Attribute::get(call->getContext(),
"enzyme_freetrace"));
240 Value *score, Value *choice) {
242 auto &&[retval, sizeval] = ValueToVoidPtrAndSize(Builder, choice, size_type);
244 Value *args[] = {trace, address, score, retval, sizeval};
248 call->addParamAttr(1, Attribute::ReadOnly);
256 Value *args[] = {trace, address, subtrace};
260 call->addParamAttr(1, Attribute::ReadOnly);
262#if LLVM_VERSION_MAJOR >= 14
263 call->addAttributeAtIndex(
264 AttributeList::FunctionIndex,
265 Attribute::get(call->getContext(),
"enzyme_insert_call"));
267 call->addAttribute(AttributeList::FunctionIndex,
268 Attribute::get(call->getContext(),
"enzyme_insert_call"));
277 auto &&[retval, sizeval] =
278 ValueToVoidPtrAndSize(Builder, argument, size_type);
280 Value *args[] = {trace, name, retval, sizeval};
284 call->addParamAttr(1, Attribute::ReadOnly);
291 auto &&[retval, sizeval] = ValueToVoidPtrAndSize(Builder, val, size_type);
293 Value *args[] = {trace, retval, sizeval};
301 assert(!function->isIntrinsic());
303 Builder.CreateBitCast(function,
getInt8PtrTy(function->getContext()));
305 Value *args[] = {trace, FunctionPtr};
313 FunctionType *interface_type,
314 Value *interface_function,
315 Value *address, Value *choice,
317 Type *size_type = interface_type->getParamType(3);
318 auto &&[retval, sizeval] = ValueToVoidPtrAndSize(Builder, choice, size_type);
320 Value *args[] = {trace, address, retval, sizeval};
322 auto call = Builder.CreateCall(interface_type, interface_function, args);
323 call->addParamAttr(1, Attribute::ReadOnly);
329 FunctionType *interface_type,
330 Value *interface_function,
331 Value *name, Value *argument,
333 Type *size_type = interface_type->getParamType(3);
334 auto &&[retval, sizeval] =
335 ValueToVoidPtrAndSize(Builder, argument, size_type);
337 Value *args[] = {trace, name, retval, sizeval};
339 auto call = Builder.CreateCall(interface_type, interface_function, args);
340 call->addParamAttr(1, Attribute::ReadOnly);
347 assert(address->getType()->isPointerTy());
349 Value *args[] = {observations, address};
353 call->addParamAttr(1, Attribute::ReadOnly);
359 Type *choiceType,
const Twine &Name) {
361 &Builder.GetInsertBlock()->getParent()->getEntryBlock()));
362 AllocaInst *store_dest =
363 AllocaBuilder.CreateAlloca(choiceType,
nullptr, Name +
".ptr");
364 auto preallocated_size = choiceType->getPrimitiveSizeInBits() / 8;
367 Value *args[] = {observations, address,
368 Builder.CreatePointerCast(
370 ConstantInt::get(size_type, preallocated_size)};
376#if LLVM_VERSION_MAJOR >= 14
377 call->addAttributeAtIndex(
378 AttributeList::FunctionIndex,
379 Attribute::get(call->getContext(),
"enzyme_inactive"));
381 call->addAttribute(AttributeList::FunctionIndex,
382 Attribute::get(call->getContext(),
"enzyme_inactive"));
384 call->addParamAttr(1, Attribute::ReadOnly);
386 return Builder.CreateLoad(choiceType, store_dest,
"from.trace." + Name);
391 Value *args[]{observations, address};
395 call->addParamAttr(1, Attribute::ReadOnly);
402 Value *args[]{observations, address};
406 call->addParamAttr(1, Attribute::ReadOnly);
413 ArrayRef<Value *> sample_args,
414 Value *address,
const Twine &Name) {
415 auto &Context = Builder.getContext();
416 auto parent_fn = Builder.GetInsertBlock()->getParent();
421 auto sample_call = Builder.CreateCall(sample_fn->getFunctionType(),
422 sample_fn, sample_args);
426 Instruction *hasChoice =
HasChoice(Builder, address,
"has.choice." + Name);
428 Value *ThenChoice, *ElseChoice;
429 BasicBlock *ThenBlock = BasicBlock::Create(
430 Context,
"condition." + Name +
".with.trace", parent_fn);
431 BasicBlock *ElseBlock = BasicBlock::Create(
432 Context,
"condition." + Name +
".without.trace", parent_fn);
433 BasicBlock *EndBlock = BasicBlock::Create(Context,
"end", parent_fn);
435 Builder.CreateCondBr(hasChoice, ThenBlock, ElseBlock);
436 Builder.SetInsertPoint(ThenBlock);
437 ThenChoice =
GetChoice(Builder, address, sample_fn->getReturnType(), Name);
438 Builder.CreateBr(EndBlock);
440 Builder.SetInsertPoint(ElseBlock);
441 ElseChoice = Builder.CreateCall(sample_fn->getFunctionType(), sample_fn,
442 sample_args,
"sample." + Name);
443 Builder.CreateBr(EndBlock);
445 Builder.SetInsertPoint(EndBlock);
446 auto phi = Builder.CreatePHI(sample_fn->getReturnType(), 2);
447 phi->addIncoming(ThenChoice, ThenBlock);
448 phi->addIncoming(ElseChoice, ElseBlock);
453 llvm_unreachable(
"Invalid sample_or_condition");
457 IRBuilder<> &Builder,
458 function_ref<
void(IRBuilder<> &,
TraceUtils *, ArrayRef<Value *>)> Outlined,
459 Type *RetTy, ArrayRef<Value *> Arguments,
bool needsLikelihood,
461 SmallVector<Type *, 4> Tys;
462 SmallVector<Value *, 4> Vals;
463 Module *M = Builder.GetInsertBlock()->getModule();
465 for (
auto Arg : Arguments) {
467 Tys.push_back(Arg->getType());
470 if (needsLikelihood) {
471 Vals.push_back(likelihood);
472 Tys.push_back(likelihood->getType());
476 Vals.push_back(observations);
477 Tys.push_back(observations->getType());
481 Vals.push_back(trace);
482 Tys.push_back(trace->getType());
485 FunctionType *FTy = FunctionType::get(RetTy, Tys,
false);
487 Function::Create(FTy, Function::LinkageTypes::InternalLinkage, Name, M);
488 F->addFnAttr(Attribute::AlwaysInline);
490 auto Entry = BasicBlock::Create(M->getContext(),
"entry", F);
492 auto ArgRange = make_pointer_range(
493 make_range(F->arg_begin(), F->arg_begin() + Arguments.size()));
494 SmallVector<Value *, 4> Rets(ArgRange);
496 auto idx = F->arg_begin() + Arguments.size();
498 Argument *likelihood_arg =
nullptr;
500 likelihood_arg = idx++;
502 Argument *observations_arg =
nullptr;
504 observations_arg = idx++;
506 Argument *trace_arg =
nullptr;
512 observations_arg, likelihood_arg,
interface);
513 IRBuilder<> OutlineBuilder(Entry);
514 Outlined(OutlineBuilder, &OutlineTutils, Rets);
516 return Builder.CreateCall(FTy, F, Vals);
static Operation * getFunctionFromCall(CallOpInterface iface)
PointerType * traceType(LLVMContext &C)
static llvm::PointerType * getUnqual(llvm::Type *T)
static llvm::PointerType * getInt8PtrTy(llvm::LLVMContext &Context, unsigned AddressSpace=0)
static void addCallSiteNoCapture(llvm::CallBase *call, size_t idx)
static void resetClonedGUID(llvm::Function *F)
static llvm::Instruction * getFirstNonPHIOrDbgOrLifetime(llvm::BasicBlock *B)
virtual llvm::Value * insertFunction(llvm::IRBuilder<> &Builder)=0
virtual llvm::Value * insertChoice(llvm::IRBuilder<> &Builder)=0
virtual llvm::Value * newTrace(llvm::IRBuilder<> &Builder)=0
virtual llvm::Value * freeTrace(llvm::IRBuilder<> &Builder)=0
llvm::FunctionType * hasCallTy()
llvm::FunctionType * insertFunctionTy()
llvm::FunctionType * hasChoiceTy()
llvm::FunctionType * insertChoiceTy()
virtual llvm::Value * insertArgument(llvm::IRBuilder<> &Builder)=0
llvm::FunctionType * insertArgumentTy()
llvm::FunctionType * insertCallTy()
virtual llvm::Value * hasCall(llvm::IRBuilder<> &Builder)=0
virtual llvm::Value * insertReturn(llvm::IRBuilder<> &Builder)=0
llvm::FunctionType * freeTraceTy()
virtual llvm::Value * getChoice(llvm::IRBuilder<> &Builder)=0
virtual llvm::Value * hasChoice(llvm::IRBuilder<> &Builder)=0
llvm::FunctionType * insertReturnTy()
virtual llvm::Value * insertCall(llvm::IRBuilder<> &Builder)=0
llvm::FunctionType * getChoiceTy()
llvm::FunctionType * newTraceTy()
llvm::FunctionType * getTraceTy()
virtual llvm::Value * getTrace(llvm::IRBuilder<> &Builder)=0
llvm::CallInst * InsertFunction(llvm::IRBuilder<> &Builder, llvm::Function *function)
static TraceUtils * FromClone(ProbProgMode mode, const llvm::SmallPtrSetImpl< llvm::Function * > &sampleFunctions, const llvm::SmallPtrSetImpl< llvm::Function * > &observeFunctions, TraceInterface *interface, llvm::Function *oldFunc, llvm::ValueMap< const llvm::Value *, llvm::WeakTrackingVH > &originalToNewFn)
static constexpr const char TraceParameterAttribute[]
llvm::CallInst * CreateTrace(llvm::IRBuilder<> &Builder, const llvm::Twine &Name="trace")
llvm::Instruction * SampleOrCondition(llvm::IRBuilder<> &Builder, llvm::Function *sample_fn, llvm::ArrayRef< llvm::Value * > sample_args, llvm::Value *address, const llvm::Twine &Name="")
TraceUtils(ProbProgMode mode, const llvm::SmallPtrSetImpl< llvm::Function * > &sampleFunctions, const llvm::SmallPtrSetImpl< llvm::Function * > &observeFunctions, llvm::Function *newFunc, llvm::Argument *trace, llvm::Argument *observations, llvm::Argument *likelihood, TraceInterface *interface)
llvm::CallInst * InsertChoice(llvm::IRBuilder<> &Builder, llvm::Value *address, llvm::Value *score, llvm::Value *choice)
llvm::Instruction * GetChoice(llvm::IRBuilder<> &Builder, llvm::Value *address, llvm::Type *choiceType, const llvm::Twine &Name="")
llvm::CallInst * InsertReturn(llvm::IRBuilder<> &Builder, llvm::Value *ret)
TraceInterface * getTraceInterface()
static llvm::CallInst * InsertChoiceGradient(llvm::IRBuilder<> &Builder, llvm::FunctionType *interface_type, llvm::Value *interface_function, llvm::Value *address, llvm::Value *choice, llvm::Value *trace)
TraceInterface * interface
llvm::CallInst * FreeTrace(llvm::IRBuilder<> &Builder)
llvm::Instruction * HasCall(llvm::IRBuilder<> &Builder, llvm::Value *address, const llvm::Twine &Name="")
static constexpr const char ObservationsParameterAttribute[]
llvm::Instruction * HasChoice(llvm::IRBuilder<> &Builder, llvm::Value *address, const llvm::Twine &Name="")
llvm::SmallPtrSet< llvm::Function *, 4 > observeFunctions
llvm::CallInst * CreateOutlinedFunction(llvm::IRBuilder<> &Builder, llvm::function_ref< void(llvm::IRBuilder<> &, TraceUtils *, llvm::ArrayRef< llvm::Value * >)> Outlined, llvm::Type *RetTy, llvm::ArrayRef< llvm::Value * > Arguments, bool needsLikelihood=true, const llvm::Twine &Name="")
static constexpr const char LikelihoodParameterAttribute[]
static llvm::CallInst * InsertArgumentGradient(llvm::IRBuilder<> &Builder, llvm::FunctionType *interface_type, llvm::Value *interface_function, llvm::Value *name, llvm::Value *argument, llvm::Value *trace)
llvm::SmallPtrSet< llvm::Function *, 4 > sampleFunctions
llvm::Value * getLikelihood()
bool isObserveCall(llvm::CallInst *call)
llvm::CallInst * InsertArgument(llvm::IRBuilder<> &Builder, llvm::Value *name, llvm::Value *argument)
llvm::CallInst * GetTrace(llvm::IRBuilder<> &Builder, llvm::Value *address, const llvm::Twine &Name="")
bool isSampleCall(llvm::CallInst *call)
llvm::Value * getObservations()
llvm::CallInst * InsertCall(llvm::IRBuilder<> &Builder, llvm::Value *address, llvm::Value *subtrace)