diff --git a/IRBindings.cpp b/IRBindings.cpp index be0a466..4788c92 100644 --- a/IRBindings.cpp +++ b/IRBindings.cpp @@ -11,11 +11,13 @@ //===----------------------------------------------------------------------===// #include "IRBindings.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/DebugLoc.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Intrinsics.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" @@ -85,3 +87,27 @@ LLVMValueRef LLVMGoGetInlineAsm(LLVMTypeRef Ty, char *AsmString, IsAlignStack, Dialect, CanThrow); } + +LLVMValueRef LLVMGoBuildIntrinsicCall(LLVMBuilderRef B, LLVMTypeRef RetTy, + unsigned ID, LLVMValueRef *Args, + unsigned Count, const char *Name) { + Intrinsic::ID IntrinsicID = static_cast(ID); + ArrayRef UnwrappedArgs(unwrap(Args), Count); + SmallVector ParamTys; + SmallVector OverloadTys; + SmallVector Infos; + + ParamTys.reserve(Count); + for (Value *Arg : UnwrappedArgs) + ParamTys.push_back(Arg->getType()); + + FunctionType *FTy = FunctionType::get(unwrap(RetTy), ParamTys, false); + Intrinsic::getIntrinsicInfoTableEntries(IntrinsicID, Infos); + ArrayRef InfoRef(Infos); + if (Intrinsic::matchIntrinsicSignature(FTy, InfoRef, OverloadTys) != + Intrinsic::MatchIntrinsicTypes_Match) + return nullptr; + + return wrap(unwrap(B)->CreateIntrinsic(IntrinsicID, OverloadTys, + UnwrappedArgs, nullptr, Name)); +} diff --git a/IRBindings.h b/IRBindings.h index 80552de..5428be7 100644 --- a/IRBindings.h +++ b/IRBindings.h @@ -55,6 +55,10 @@ LLVMValueRef LLVMGoGetInlineAsm(LLVMTypeRef Ty, char *AsmString, LLVMBool IsAlignStack, LLVMInlineAsmDialect Dialect, LLVMBool CanThrow); +LLVMValueRef LLVMGoBuildIntrinsicCall(LLVMBuilderRef B, LLVMTypeRef RetTy, + unsigned ID, LLVMValueRef *Args, + unsigned Count, const char *Name); + #ifdef __cplusplus } #endif diff --git a/ir.go b/ir.go index 3925053..f93d080 100644 --- a/ir.go +++ b/ir.go @@ -385,6 +385,13 @@ func MDKindID(name string) (id int) { return } +func LookupIntrinsicID(name string) (id int) { + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + id = int(C.LLVMLookupIntrinsicID(cname, C.size_t(len(name)))) + return +} + //------------------------------------------------------------------------- // llvm.Attribute //------------------------------------------------------------------------- @@ -1955,6 +1962,14 @@ func (b Builder) CreateCall(t Type, fn Value, args []Value, name string) (v Valu return } +func (b Builder) CreateIntrinsic(ret Type, id int, args []Value, name string) (v Value) { + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + ptr, nvals := llvmValueRefs(args) + v.C = C.LLVMGoBuildIntrinsicCall(b.C, ret.C, C.unsigned(id), ptr, nvals, cname) + return +} + func (b Builder) CreateSelect(ifv, thenv, elsev Value, name string) (v Value) { cname := C.CString(name) defer C.free(unsafe.Pointer(cname)) diff --git a/ir_test.go b/ir_test.go index a912aec..0a9d5e8 100644 --- a/ir_test.go +++ b/ir_test.go @@ -145,6 +145,36 @@ func TestDebugLoc(t *testing.T) { } } +func TestIntrinsicBindings(t *testing.T) { + ctx := NewContext() + mod := ctx.NewModule("") + defer mod.Dispose() + + memsetID := LookupIntrinsicID("llvm.memset") + if memsetID == 0 { + t.Fatal("could not look up llvm.memset intrinsic") + } + ptrTy := PointerType(ctx.Int8Type(), 0) + fnTy := FunctionType(ctx.VoidType(), []Type{ptrTy}, false) + fn := AddFunction(mod, "use_memset", fnTy) + builder := ctx.NewBuilder() + defer builder.Dispose() + builder.SetInsertPointAtEnd(ctx.AddBasicBlock(fn, "entry")) + call := builder.CreateIntrinsic(ctx.VoidType(), memsetID, []Value{ + fn.Param(0), + ConstInt(ctx.Int8Type(), 0, false), + ConstInt(ctx.Int64Type(), 8, false), + ConstInt(ctx.Int1Type(), 0, false), + }, "") + builder.CreateRetVoid() + if got := call.CalledValue().IntrinsicID(); got != memsetID { + t.Fatalf("got intrinsic ID %d, want %d", got, memsetID) + } + if err := VerifyModule(mod, ReturnStatusAction); err != nil { + t.Fatalf("module with intrinsic call should verify: %v", err) + } +} + func TestSubtypes(t *testing.T) { cont := NewContext() defer cont.Dispose()