From 2bcfc7deba7f3aeec74bae65c5e0c843a446e910 Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 28 Mar 2015 20:29:13 +0100 Subject: [PATCH 01/11] adding PHIAddIncoming, which allows addding incoming Blocks to a PHI Node --- R/IRBuilder.R | 5 +++++ src/IRBuilder.cpp | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/R/IRBuilder.R b/R/IRBuilder.R index f290b7f4..1a95d518 100644 --- a/R/IRBuilder.R +++ b/R/IRBuilder.R @@ -446,6 +446,11 @@ function(builder, type, numReservedVals) .Call("R_IRBuilder_CreatePHI", builder, type, as.integer(numReservedVals)) } +PHIAddIncoming = +function(phiNode, value, block) +{ + .Call("R_PHINode_addIncoming", phiNode, value, block) +} if(FALSE) { diff --git a/src/IRBuilder.cpp b/src/IRBuilder.cpp index 526a8c46..d063bb17 100644 --- a/src/IRBuilder.cpp +++ b/src/IRBuilder.cpp @@ -1003,3 +1003,24 @@ R_IRBuilder_CreatePHI(SEXP r_builder, SEXP r_type, SEXP r_numReservedValues, SEX return(R_createRef(ret, "PHINode")); } + +extern "C" +SEXP +R_PHINode_addIncoming(SEXP r_phiNode, SEXP r_value, SEXP r_block) +{ + llvm::PHINode* phiNode; + phiNode = GET_REF(r_phiNode, PHINode); + + + llvm::Value *value; + value = GET_REF(r_value, Value); + + llvm::BasicBlock *block; + block = GET_REF(r_block, BasicBlock); + + + phiNode->addIncoming(value, block); + + return(R_NilValue); + +} \ No newline at end of file From 619dcc88e6f57802aac4d2e660ba232c4d8115a0 Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 29 Mar 2015 19:23:50 +0200 Subject: [PATCH 02/11] removing export for class functionType. This class was already exported under the name of FunctionType.. --- NAMESPACE | 1 - 1 file changed, 1 deletion(-) diff --git a/NAMESPACE b/NAMESPACE index c0244e82..3515ba2b 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -35,7 +35,6 @@ exportClasses( SExtInst, StoreInst, StructType, - functionType, TerminatorInst, Type, UnaryInstruction, From f698bd96794c5806e07afbe83f556776376d538a Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 29 Mar 2015 19:50:48 +0200 Subject: [PATCH 03/11] adding function finalizeEngine that calls finalizeObject on the engine, that is needed for using MC JIT, see http://blog.llvm.org/2013/07/using-mcjit-with-kaleidoscope-tutorial.html --- NAMESPACE | 1 + R/ExecutionEngine.R | 12 ++++++++++++ src/ExecEngine.cpp | 13 +++++++++++++ 3 files changed, 26 insertions(+) diff --git a/NAMESPACE b/NAMESPACE index 3515ba2b..5868cfc0 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -113,6 +113,7 @@ FCMP_ULT, FCMP_UNE, FCMP_UNO, FDiv, +finalizeEngine, FIRST_FCMP_PREDICATE, FIRST_ICMP_PREDICATE, FloatPtrType, diff --git a/R/ExecutionEngine.R b/R/ExecutionEngine.R index 6e2ae54c..86a479ed 100644 --- a/R/ExecutionEngine.R +++ b/R/ExecutionEngine.R @@ -34,6 +34,18 @@ function(module, optimizationLevel = CodeGenOpt_Default) .Call("R_create_ExecutionEngine", as(module, "Module"), as.integer(optimizationLevel)) } +#finalize must be called before invoking code that has been +#compiled using MC Jit +finalizeEngine = +function(engine) +{ + if(!is(engine, "ExecutionEngine")) + stop("can only finalize an ExecutionEngine") + + .Call("R_ExecutionEngine_finalize", engine) +} + + addModule = function(engine, ...) { diff --git a/src/ExecEngine.cpp b/src/ExecEngine.cpp index 8fbe23a9..2c007cfc 100644 --- a/src/ExecEngine.cpp +++ b/src/ExecEngine.cpp @@ -105,6 +105,19 @@ R_create_ExecutionEngine(SEXP r_module, SEXP r_optLevel) return(R_createRef(EE, "ExecutionEngine")); } +/* finalize engine must be called before invoking code +compiled with MC Jit */ +extern "C" +void +R_ExecutionEngine_finalize(SEXP r_ee) +{ + + /* Do we want to use some of the create() methods in the ExecutionEngine class. */ + + llvm::ExecutionEngine *EE = GET_REF(r_ee, ExecutionEngine); + EE->finalizeObject(); +} + extern "C" SEXP R_callFunction(SEXP r_fun, SEXP r_args, SEXP r_execEngine) From b81df34ccc05d21aed6de02445815d11e56346ff Mon Sep 17 00:00:00 2001 From: Chris Date: Fri, 3 Apr 2015 12:26:10 +0200 Subject: [PATCH 04/11] Prelimnary support for mc jit under llvm 3.5 runFunction is no longer supported experiments/mcjit.R gives a primer on how to use mc jit --- NAMESPACE | 3 ++- R/ExecutionEngine.R | 48 +++++++++++++++++++++++++++++++--------- R/classDefs.R | 2 +- experiments/mcjit.R | 54 +++++++++++++++++++++++++++++++++++++++++++++ src/ExecEngine.cpp | 38 +++++++++++++++++++++++++++---- 5 files changed, 129 insertions(+), 16 deletions(-) create mode 100644 experiments/mcjit.R diff --git a/NAMESPACE b/NAMESPACE index 5868cfc0..68a00521 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -186,7 +186,8 @@ exportMethods(Optimize) export(setLinkage) -export(findFunction, getPointerToFunction) +export(findFunction, getPointerToFunction, + getNativePointerToFunction) export(createDoubleConstant) diff --git a/R/ExecutionEngine.R b/R/ExecutionEngine.R index 86a479ed..de430d8e 100644 --- a/R/ExecutionEngine.R +++ b/R/ExecutionEngine.R @@ -27,11 +27,25 @@ function(val, values) } ExecutionEngine = -function(module, optimizationLevel = CodeGenOpt_Default) +function(module, optimizationLevel = CodeGenOpt_Default, useMCJIT) { optimizationLevel = matchEnum(optimizationLevel, CodeGenOptEnum) + + if (missing(useMCJIT)) { + if(all(llvmVersion() >= c(3, 6))) { + #defaulting to mc jit on llvm 3.6 + useMCJIT=TRUE + } else { + useMCJIT=FALSE + } + } - .Call("R_create_ExecutionEngine", as(module, "Module"), as.integer(optimizationLevel)) + res=.Call("R_create_ExecutionEngine", as(module, "Module"), as.integer(optimizationLevel),as.logical(useMCJIT)) + + res@useMCJIT=useMCJIT + res@finalized=FALSE + + res } #finalize must be called before invoking code that has been @@ -41,8 +55,11 @@ function(engine) { if(!is(engine, "ExecutionEngine")) stop("can only finalize an ExecutionEngine") + + if(engine@finalized) + stop("engine has already been finalized") - .Call("R_ExecutionEngine_finalize", engine) + invisible(.Call("R_ExecutionEngine_finalize", engine)) } @@ -83,15 +100,20 @@ function(.x, ..., .args = list(...), .ee = ExecutionEngine(as(.x, "Module")), .a if(!is(.x, "Function")) stop("argument to .llvm must be a Function") -# If an argument is a Function, we probably want to treat it as a function pointer and so want -# its address which can be obtained via getPointerToFunction() with the exec engine also. -# .args = lapply(.args, function(x) if(is(x, "Function")) getPointerToFunction(x, .ee)@ref else x) + if (.ee@useMCJIT) { + stop("calling .llvm/runFunction is not supported with MC-JIT") + } else { - if(length(.duplicate)) - .args[.duplicate] = lapply(.args[.duplicate], function(x) .Call('Rf_duplicate', x)) + # If an argument is a Function, we probably want to treat it as a function pointer and so want + # its address which can be obtained via getPointerToFunction() with the exec engine also. + # .args = lapply(.args, function(x) if(is(x, "Function")) getPointerToFunction(x, .ee)@ref else x) - - ans = .Call("R_callFunction", .x, .args, .ee) + if(length(.duplicate)) + .args[.duplicate] = lapply(.args[.duplicate], function(x) .Call('Rf_duplicate', x)) + + + ans = .Call("R_callFunction", .x, .args, .ee) + } if(.all) append(ans, structure(.args, names = names(.args))) @@ -135,6 +157,12 @@ function(fun, execEngine) .Call("R_ExecutionEngine_getPointerToFunction", execEngine, fun) } +getNativePointerToFunction = +function(fun, execEngine) +{ + .Call("R_ExecutionEngine_getNativePointerToFunction", execEngine, fun) +} + getPointerToGlobal = function(var, execEngine) { diff --git a/R/classDefs.R b/R/classDefs.R index 9ae5afb7..0c7c8cb9 100644 --- a/R/classDefs.R +++ b/R/classDefs.R @@ -14,7 +14,7 @@ setClass("formatted_raw_ostream", contains = "raw_ostream") setClass("Module", contains = "RC++Reference") setClass("IRBuilder", contains = "RC++Reference") setClass("LLVMContext", contains = "RC++Reference") -setClass("ExecutionEngine", contains = "RC++Reference") +setClass("ExecutionEngine", representation(useMCJIT = "logical", finalized = "logical"), contains = "RC++Reference") setClass("Value", contains = "RC++Reference") setClass("BasicBlock", contains = "Value") diff --git a/experiments/mcjit.R b/experiments/mcjit.R new file mode 100644 index 00000000..a27369fc --- /dev/null +++ b/experiments/mcjit.R @@ -0,0 +1,54 @@ +# The following script illuminates how to call function under the old JIT +# and using MC JIT + +library(Rllvm) + +m = Module() + +# Create two simple routines that do the same : +# taking a double value and returns that value multiplied by 2. + +# The first function will be run under the old JIT +f = Function("fun", DoubleType, list(x = DoubleType), module = m) +b = Block(f) +ir = IRBuilder(b) +x = getParameters(f)$x +two = createConstant(, 2, context = getContext(m)) +ir$createReturn(ir$binOp(FMul, x, two)) + +# the second function uses mc jit and will be called using .C +# Hence it takes a pointer to a double as argument +f2 = Function("fun2", VoidType, list(x = pointerType(DoubleType)), module = m) +b = Block(f2) +ir = IRBuilder(b) +x = getParameters(f2)$x +x2= ir$createLoad(x) +two = createConstant(, 2, context = getContext(m)) +res=ir$binOp(FMul, x2, two) +ir$createStore(res,x) +ir$createReturn() + +# Now we create two EEs +eeNew = ExecutionEngine(m, useMCJIT=TRUE) +eeOld = ExecutionEngine(m, useMCJIT=FALSE) + + +# getNativePointerToFunction returns a pointer that can be used by .C et al +fnPtr = getNativePointerToFunction(f2, eeNew) + +# the MC JIT must be finalized before callin into the code +finalizeEngine(eeNew) +print(.C(fnPtr,10.4)) + +# call using the old JIT +print(.llvm(f, 10.4,.ee = eeOld)) + +# using pointers works with the old JIT, too +fnPtr = getNativePointerToFunction(f2, eeOld) +print(.C(fnPtr,10.4)) + + + + + + diff --git a/src/ExecEngine.cpp b/src/ExecEngine.cpp index 2c007cfc..18bf9822 100644 --- a/src/ExecEngine.cpp +++ b/src/ExecEngine.cpp @@ -83,20 +83,34 @@ R_InitializeCppBackendTarget() extern "C" SEXP -R_create_ExecutionEngine(SEXP r_module, SEXP r_optLevel) +R_create_ExecutionEngine(SEXP r_module, SEXP r_optLevel, + SEXP r_usemcjit) { /* Do we want to use some of the create() methods in the ExecutionEngine class. */ std::string errStr; llvm::Module *module = GET_REF(r_module, Module); - llvm::ExecutionEngine *EE = llvm::EngineBuilder( + llvm::EngineBuilder builder( #if LLVM_VERSION == 3 && LLVM_MINOR_VERSION > 5 std::unique_ptr(module) #else module #endif - ).setErrorStr(&errStr).setEngineKind(llvm::EngineKind::JIT).setOptLevel((enum llvm::CodeGenOpt::Level) INTEGER(r_optLevel)[0]).create(); + ); + + builder.setErrorStr(&errStr); + builder.setEngineKind(llvm::EngineKind::JIT); + builder.setUseMCJIT(*LOGICAL(r_usemcjit)); + builder.setOptLevel((enum llvm::CodeGenOpt::Level) INTEGER(r_optLevel)[0]); + + llvm::TargetOptions Options; + Options.JITEmitDebugInfo = *LOGICAL(r_usemcjit); + + builder.setTargetOptions(Options); + + + llvm::ExecutionEngine *EE = builder.create(); if(!EE) { PROBLEM "failed to create execution engine: %s", errStr.c_str() ERROR; @@ -108,7 +122,7 @@ R_create_ExecutionEngine(SEXP r_module, SEXP r_optLevel) /* finalize engine must be called before invoking code compiled with MC Jit */ extern "C" -void +SEXP R_ExecutionEngine_finalize(SEXP r_ee) { @@ -116,6 +130,7 @@ R_ExecutionEngine_finalize(SEXP r_ee) llvm::ExecutionEngine *EE = GET_REF(r_ee, ExecutionEngine); EE->finalizeObject(); + return(R_NilValue); } extern "C" @@ -178,6 +193,21 @@ R_ExecutionEngine_getPointerToFunction(SEXP r_execEngine, SEXP r_func) return(R_createRef(ans, "NativeFunctionPointer", "native symbol")); } +extern "C" +SEXP +R_ExecutionEngine_getNativePointerToFunction(SEXP r_execEngine, SEXP r_func) +{ + llvm::ExecutionEngine *ee = GET_REF(r_execEngine, ExecutionEngine); + llvm::Function *fun = GET_REF(r_func, Function); + void *ans = ee->getPointerToFunction(fun); + + SEXP ans2; + PROTECT(ans2=R_MakeExternalPtr(ans, install("native symbol"), + R_NilValue)); + UNPROTECT(1); + return(ans2); +} + extern "C" SEXP R_ExecutionEngine_getPointerToGlobal(SEXP r_execEngine, SEXP r_var) From c2f69e6366e4ddd8ad6689609c7bfea5a0a4d64b Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 5 Apr 2015 13:31:48 +0200 Subject: [PATCH 05/11] initial commit for DIBuilder see experiments/DIBuilder.R in conjucntion with LLVM Kaleidoscope tutorial for usage instructions --- DESCRIPTION | 3 +- NAMESPACE | 10 ++ R/DIBuilder.R | 54 ++++++++++ R/classDefs.R | 7 ++ experiments/DIBuilder.R | 102 +++++++++++++++++++ src/DIBuilder.cpp | 219 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 394 insertions(+), 1 deletion(-) create mode 100644 R/DIBuilder.R create mode 100644 experiments/DIBuilder.R create mode 100644 src/DIBuilder.cpp diff --git a/DESCRIPTION b/DESCRIPTION index 835d95b0..23016f98 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -46,4 +46,5 @@ Collate: llvmVersion.R classDefs.R manual_generics.R BinaryOpEnums.R z_enumDefs_3.4.R z_enumDefs_3.5.R z_enumDefs_3.6.R - Function.R \ No newline at end of file + Function.R + DIBuilder.R \ No newline at end of file diff --git a/NAMESPACE b/NAMESPACE index 68a00521..e7cd1a94 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -471,3 +471,13 @@ export(insertAtEnd) export(isLandingPad, getLandingPadInst) export(createPHI,createPhi) + +export(DIBuilder, + finalizeDIBuilder, + newDebugCU, + newDebugFunction, + newDebugLocalVariable, + newDebugBasicType, + newDebugFunctionType, + newDebugPointerType, + debugSetLocation) diff --git a/R/DIBuilder.R b/R/DIBuilder.R new file mode 100644 index 00000000..c5d0ba2f --- /dev/null +++ b/R/DIBuilder.R @@ -0,0 +1,54 @@ +DIBuilder = +function(module) +{ + .Call("R_new_DIBuilder", module) +} + +finalizeDIBuilder = +function(builder) +{ + invisible(.Call("R_finalize_DIBuilder", builder)) +} + +newDebugCU = +function(builder, filename, path) +{ + .Call("R_new_DIBuilder_CU",builder, filename, path) +} + +newDebugFunction = +function(builder, cu, func, type, line) +{ + .Call("R_new_DIBuilder_Function",builder, cu, func, type, line) +} + +newDebugLocalVariable = +function(builder, ir_builder, sp, var, lineNo, cu, di_type, idx) +{ + .Call("R_DIBuilder_CreateLocalVariable",builder, ir_builder, sp, var, lineNo, cu, di_type, idx) +} + +newDebugBasicType = +function(builder, name, size, align, dwarf_type) { + .Call("R_IRBuilder_CreateBasicType", builder, name, as.integer(size), as.integer(align), as.integer(dwarf_type)) +} + +newDebugFunctionType = +function(builder, args, cu) +{ + .Call("R_IRBuilder_CreateFunctionType", builder, as.vector(args), cu) +} + +newDebugPointerType = +function(builder,baseType, name) { + .Call("R_IRBuilder_CreatePointerType", builder, baseType, name) +} + +debugSetLocation = +function(builder, func, lineNo, colNo) +{ + .Call("R_IRBuilder_SetLocation", builder, func, as.integer(lineNo), as.integer(colNo)) +} + + + diff --git a/R/classDefs.R b/R/classDefs.R index 0c7c8cb9..772a30a4 100644 --- a/R/classDefs.R +++ b/R/classDefs.R @@ -92,6 +92,13 @@ setClass("NamedMDNode", contains = "RC++Reference") setClass("MDNode", contains = "Value") setClass("MDString", contains = "Value") +#Classes for DIBuilder +setClass("DIBuilder", contains = "RC++Reference") +setClass("DICompileUnit", contains = "RC++Reference") +setClass("DIDescriptor", contains = "RC++Reference") +setClass("DISubprogram", contains = "RC++Reference") +setClass("DIType", contains = "RC++Reference") +setClass("DICompositeType", contains = "DIType") setClass("Type", contains = "RC++Reference") diff --git a/experiments/DIBuilder.R b/experiments/DIBuilder.R new file mode 100644 index 00000000..75f5b9b6 --- /dev/null +++ b/experiments/DIBuilder.R @@ -0,0 +1,102 @@ +# The following script illuminates how to add Debug Information to LLVM Code +# the following function is used to show linenumbers in gdb + +fun2 = function(x) { + res=x*2 + return(res) +} + +# dont move the uper function in the file, because the line numbers are encoded in the debug data!! +#set the path to the script here, otherwise gdb cant display source lines + +absPath="/home/chris/dev/llvm/Rllvm/experiments/DIBuilder.R" + +#if gdb doesnt stop in the function, check if you can set a breakpoint in __jit_debug_register_code +#see https://sourceware.org/gdb/onlinedocs/gdb/JIT-Interface.html and http://llvm.org/docs/DebuggingJITedCode.html + + +#end of preambel, start of code + +library(Rllvm) + +cat (paste("Is this script really saved in: ", absPath)) +cat (paste("attach gdb to process ", Sys.getpid(), " and set breakpoint on fun2")) +cat("then come back here, enter a character and press return!") +line <- scan("stdin", character(), n=1) + +m = Module() + +# Create a simple routines that takes a double value and returns that value multiplied by 2. + +f2 = Function("fun2", VoidType, list(x = pointerType(DoubleType)), module = m) +b = Block(f2) +ir = IRBuilder(b) +param_x = getParameters(f2)$x +var_res=createLocalVariable(ir,DoubleType, "res") + +#creating the Debug Builder and tools +debugBuilder = DIBuilder(m) + + + + +#generate CompilationUnit +debugCompUnit = newDebugCU(debugBuilder, basename(absPath), dirname(absPath)) + +#Type +debugDouble=newDebugBasicType(debugBuilder, "double", 64, 64, 4 ) #4 = dwarf::DW_ATE_float +debugVoid=newDebugBasicType(debugBuilder, "void", 64, 64, 5 ) #5 = dwarf::DW_ATE_signed +debugDoublePtr=newDebugPointerType(debugBuilder, debugDouble, "double*") + + +#Function for Debug +debugSignature=c(debugVoid,list(x=debugDoublePtr)) +debugFunSignature=newDebugFunctionType(debugBuilder, debugSignature, debugCompUnit) +debugFun=newDebugFunction(debugBuilder, debugCompUnit, f2, debugFunSignature, absPath) + +#adding function parameters +newDebugLocalVariable(debugBuilder, ir, debugFun, param_x, absPath, debugCompUnit, debugDoublePtr, 1) + +#adding local variable res +newDebugLocalVariable(debugBuilder, ir, debugFun, var_res, absPath, debugCompUnit, debugDouble, 0) + + + +# +# START emitting IR +# +#emit first source location +debugSetLocation(ir, debugFun, 5, 1) + +x2= ir$createLoad(param_x) +two = createConstant(, 2, context = getContext(m)) +res=ir$binOp(FMul, x2, two) +ir$createStore(res,var_res) + +#emit second source location +debugSetLocation(ir, debugFun, 6, 1) +ir$createStore(res,param_x) +ir$createReturn() + + + + +# +# FINISH Emitting IR +# now cleaning up and executing +# + +finalizeDIBuilder(debugBuilder) + + +# Now we create the EEs +eeNew = ExecutionEngine(m, useMCJIT=TRUE) + + +# getNativePointerToFunction returns a pointer that can be used by .C et al +fnPtr = getNativePointerToFunction(f2, eeNew) + +# the MC JIT must be finalized before callin into the code +finalizeEngine(eeNew) +print(.C(fnPtr,10.4)) + diff --git a/src/DIBuilder.cpp b/src/DIBuilder.cpp new file mode 100644 index 00000000..6e0e8ba9 --- /dev/null +++ b/src/DIBuilder.cpp @@ -0,0 +1,219 @@ +#include "Rllvm.h" +#if LLVM_VERSION <= 3 && LLVM_MINOR_VERSION < 2 +#include +#else +#if LLVM_VERSION >= 3 && LLVM_MINOR_VERSION >= 3 +#include +#include +#include +#include +#else +#include +#include +#endif +#endif + +#include "llvm/IR/DIBuilder.h" +#include "llvm/Support/Dwarf.h" +#include "llvm/IR/Metadata.h" + +//extern "C" void __jit_debug_register_code(); + +extern "C" +SEXP +R_new_DIBuilder(SEXP r_module) +{ + llvm::Module *module; + module = llvm::cast (GET_REF(r_module, Module)); + llvm::DIBuilder *ans; + ans = new llvm::DIBuilder(*module); + return(R_createRef(ans, "DIBuilder")); +} + +extern "C" +SEXP +R_new_DIBuilder_CU(SEXP r_dibuilder, SEXP filename, SEXP path) +{ + llvm::DIBuilder *builder; + builder = (GET_REF(r_dibuilder, DIBuilder)); + llvm::DICompileUnit ans; + ans = builder->createCompileUnit( + llvm::dwarf::DW_LANG_C, llvm::StringRef(CHAR(STRING_ELT(filename, 0))), + llvm::StringRef(CHAR(STRING_ELT(path, 0))), "Rllvm", 0, "", 0); + + llvm::DICompileUnit* ptr = new llvm::DICompileUnit(); + *ptr=ans; + + //llvm::DIRef ans2=ans; + return(R_createRef(ptr, "DICompileUnit")); +} + +extern "C" +SEXP +R_finalize_DIBuilder(SEXP r_dibuilder) +{ + llvm::DIBuilder *builder; + builder = (GET_REF(r_dibuilder, DIBuilder)); + builder->finalize(); + + return(R_NilValue); +} + + +extern "C" +SEXP +R_new_DIBuilder_Function(SEXP r_dibuilder, SEXP r_cu, SEXP r_func, SEXP r_type, SEXP r_lineno) +{ + llvm::DIBuilder *builder; + builder = (GET_REF(r_dibuilder, DIBuilder)); + + llvm::Function *func; + func = (GET_REF(r_func, Function)); + + llvm::DICompileUnit *cu; + cu = (GET_REF(r_cu, DICompileUnit)); + llvm::DIFile Unit = builder->createFile(cu->getFilename(), cu->getDirectory()); + llvm::DIDescriptor FContext(Unit); + + llvm::DICompositeType *type; + type = (GET_REF(r_type, DICompositeType)); + + int lineNo=asInteger(r_lineno); + + llvm::DISubprogram SP = builder->createFunction( + FContext, func->getName(), llvm::StringRef(), Unit, lineNo, + *type, false /* internal linkage */, + true /* definition */, lineNo, llvm::DIDescriptor::FlagPrototyped, false, func); + + llvm::DISubprogram* ptr = new llvm::DISubprogram(); + *ptr=SP; + + return(R_createRef(ptr, "DISubprogram")); +} + + + +extern "C" +SEXP +R_DIBuilder_CreateLocalVariable(SEXP r_builder, SEXP r_ir_builder, SEXP r_sp, SEXP r_var, SEXP r_lineNo, + SEXP r_cu, SEXP r_di_type, SEXP r_idx) +{ + llvm::DIBuilder *builder; + builder = GET_REF(r_builder, DIBuilder); + + llvm::DISubprogram *SP; + SP = GET_REF(r_sp, DISubprogram); + + llvm::DICompileUnit *cu; + cu = (GET_REF(r_cu, DICompileUnit)); + llvm::DIFile Unit = builder->createFile(cu->getFilename(), cu->getDirectory()); + + llvm::DIType* di_type; + di_type = (GET_REF(r_di_type, DIType)); + + llvm::AllocaInst *var; + var = (GET_REF(r_var, AllocaInst)); + + llvm::StringRef varName=var->getName(); + + llvm::IRBuilder<> *ir_builder; + ir_builder = GET_REF(r_ir_builder, IRBuilder<>); + + llvm::DIVariable D = builder->createLocalVariable(llvm::dwarf::DW_TAG_arg_variable, + *SP, varName, Unit, asInteger(r_lineNo), + *di_type, false, 0, asInteger(r_idx)); + + llvm::Instruction *Call = builder->insertDeclare( + var, D, ir_builder->GetInsertBlock()); + + Call->setDebugLoc(llvm::DebugLoc::get(asInteger(r_lineNo), 0, *SP)); + + return(R_NilValue); +} + +extern "C" +SEXP +R_IRBuilder_CreateBasicType(SEXP r_builder,SEXP r_name, SEXP r_size, SEXP r_align, SEXP r_dwarf_type) { + + llvm::DIBuilder *builder; + builder = GET_REF(r_builder, DIBuilder); + + const char * name=CHAR(STRING_ELT(r_name, 0)); + int size=asInteger(r_size); + int align=asInteger(r_align); + int dwarf_type=asInteger(r_dwarf_type); + + llvm::DIType ans = builder->createBasicType(llvm::StringRef(name), size, align, dwarf_type); + llvm::DIType* ptr = new llvm::DIType(); + *ptr=ans; + return(R_createRef(ptr,"DIType")); +} + +extern "C" +SEXP +R_IRBuilder_CreatePointerType(SEXP r_builder, SEXP r_type, SEXP r_name) { + + llvm::DIBuilder *builder; + builder = GET_REF(r_builder, DIBuilder); + + llvm::DIType *baseType=GET_REF(r_type, DIType); + + const char * name=CHAR(STRING_ELT(r_name, 0)); + + llvm::DIType ans = builder->createPointerType(*baseType,sizeof(void*),0,llvm::StringRef(name)); + llvm::DIType* ptr = new llvm::DIType(); + *ptr=ans; + return(R_createRef(ptr,"DIType")); +} + + + +extern "C" +SEXP +R_IRBuilder_CreateFunctionType(SEXP r_builder, SEXP args, SEXP r_cu) { + llvm::SmallVector EltTys; + + llvm::DIBuilder *builder; + builder = GET_REF(r_builder, DIBuilder); + + llvm::DICompileUnit* cu; + cu = (GET_REF(r_cu, DICompileUnit)); + + llvm::DIFile file = builder->createFile(cu->getFilename(), cu->getDirectory()); + + for (unsigned i = 0; i < Rf_length(args); ++i) { + llvm::DIType *element=GET_REF(VECTOR_ELT(args,i), DIType); + //llvm::DITypeRef *element2 = llvm::cast(element); + //llvm::Value *element3 = llvm::cast(element2); + EltTys.push_back(*element); + //EltTys.push_back(const_cast( (llvm::MDNodeContext, MDs *)element)); + } + + llvm::DIArray EltTypeArray = builder->getOrCreateArray(EltTys); + + llvm::DICompositeType ans=builder->createSubroutineType(file, EltTypeArray); + + llvm::DICompositeType* ptr = new llvm::DICompositeType(); + *ptr=ans; + return R_createRef(ptr,"DICompositeType"); +} + + +extern "C" +SEXP +R_IRBuilder_SetLocation(SEXP r_builder, SEXP r_func, SEXP r_lineNo, SEXP r_colNo) +{ + llvm::IRBuilder<> *builder; + builder = GET_REF(r_builder, IRBuilder<>); + + llvm::DISubprogram *SP; + SP = GET_REF(r_func, DISubprogram); + + int lineNo=asInteger(r_lineNo); + int colNo=asInteger(r_colNo); + + builder->SetCurrentDebugLocation( + llvm::DebugLoc::get(lineNo, colNo, *SP)); + + return(R_NilValue); +} From 76309ce2be40cd0b60d9e430e1d84a26df818edd Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 5 Apr 2015 14:04:15 +0200 Subject: [PATCH 06/11] adding export of function functionType again --- NAMESPACE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NAMESPACE b/NAMESPACE index e7cd1a94..27d2b2eb 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -304,7 +304,7 @@ export(getIntegerType) export(setAlignment) exportMethods(setAlignment) -#export(getFunctionType) +export(functionType) export(addModule) From 0da54f40eb5fabee7a9363503a736df7e56987ba Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 5 Apr 2015 14:14:56 +0200 Subject: [PATCH 07/11] distinguish between function parameters and local variables in DIBuilder's CreateLocalVariable --- src/DIBuilder.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/DIBuilder.cpp b/src/DIBuilder.cpp index 6e0e8ba9..ffe013d7 100644 --- a/src/DIBuilder.cpp +++ b/src/DIBuilder.cpp @@ -119,9 +119,12 @@ R_DIBuilder_CreateLocalVariable(SEXP r_builder, SEXP r_ir_builder, SEXP r_sp, SE llvm::IRBuilder<> *ir_builder; ir_builder = GET_REF(r_ir_builder, IRBuilder<>); - llvm::DIVariable D = builder->createLocalVariable(llvm::dwarf::DW_TAG_arg_variable, + int idx=asInteger(r_idx); + + llvm::DIVariable D = builder->createLocalVariable( + (idx == 0) ? llvm::dwarf::DW_TAG_auto_variable : llvm::dwarf::DW_TAG_arg_variable, *SP, varName, Unit, asInteger(r_lineNo), - *di_type, false, 0, asInteger(r_idx)); + *di_type, false, 0, idx); llvm::Instruction *Call = builder->insertDeclare( var, D, ir_builder->GetInsertBlock()); From 62460a3812e8db522f934351569375b463a19343 Mon Sep 17 00:00:00 2001 From: Chris Date: Wed, 8 Apr 2015 20:57:46 +0200 Subject: [PATCH 08/11] forgot to add PHIAddIncoming to NAMESPACE --- NAMESPACE | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NAMESPACE b/NAMESPACE index 27d2b2eb..fb6a7539 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -472,6 +472,8 @@ export(isLandingPad, getLandingPadInst) export(createPHI,createPhi) +export(PHIAddIncoming) + export(DIBuilder, finalizeDIBuilder, newDebugCU, From 7501d77bd1eed7b09057cf766877ed3a07ff5db5 Mon Sep 17 00:00:00 2001 From: Chris Date: Wed, 8 Apr 2015 21:00:47 +0200 Subject: [PATCH 09/11] createPHI wad defined twice -> removing first occurence correcting a typo in definition of createPHI --- R/IRBuilder.R | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/R/IRBuilder.R b/R/IRBuilder.R index 1a95d518..644b41c9 100644 --- a/R/IRBuilder.R +++ b/R/IRBuilder.R @@ -439,13 +439,6 @@ function(builder, vec, elt, idx) .Call("R_IRBuilder_CreateInsertElement", builder, vec, elt, idx) } - -createPHI = -function(builder, type, numReservedVals) -{ - .Call("R_IRBuilder_CreatePHI", builder, type, as.integer(numReservedVals)) -} - PHIAddIncoming = function(phiNode, value, block) { @@ -516,7 +509,7 @@ function(builder, value, type, id = "") createPhi = createPHI = -function(build, type, numReservedValues, id = character()) +function(builder, type, numReservedValues, id = character()) { .Call("R_IRBuilder_CreatePHI", as(builder, "IRBuilder"), as(type, "Type"), as.integer(numReservedValues), as.character(id)) } From 11c50c0830ddd51b9c1fa2acc76f78bd9e945a0a Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 11 Apr 2015 00:56:50 +0200 Subject: [PATCH 10/11] change R_getTypeDefinitions so that the preloaded types are not external poiners, but objects of class Type --- R/onLoad.R | 11 ++++++++--- src/types.cpp | 20 ++++++++++++++++++-- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/R/onLoad.R b/R/onLoad.R index 494a204c..8ef534a6 100644 --- a/R/onLoad.R +++ b/R/onLoad.R @@ -1,7 +1,9 @@ getTypeDefs = -function() +function(namespace) { - types = .Call("R_getTypeDefinitions") + typeClass= getClass("Type", .Force=TRUE, where=namespace) + types = .Call("R_getTypeDefinitions", typeClass) + names(types) = c("Void", "Label", "Float", "Double", "Int1", "Int8", "Int16", "Int32", "Int64", "FloatPtr", "DoublePtr", "Int32Ptr", "String") types @@ -10,8 +12,11 @@ function() .onLoad = function(...) { - types = getTypeDefs() + e = getNamespace("Rllvm") + + types = getTypeDefs(e) + mapply(utils::assignInNamespace, paste(names(types), "Type", sep = ""), types, diff --git a/src/types.cpp b/src/types.cpp index 5e446b94..7bc9af35 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -10,9 +10,20 @@ struct TypeName { const char * const name; } ; + +SEXP +R_createRefTypes(const void *ptr, SEXP klass, const char * tag) +{ + SEXP ans; + PROTECT(ans = NEW_OBJECT(klass)); + SET_SLOT(ans, Rf_install("ref"), R_MakeExternalPtr((void*)ptr, Rf_install(tag), R_NilValue)); + UNPROTECT(1); + return(ans); +} + extern "C" SEXP -R_getTypeDefinitions() +R_getTypeDefinitions(SEXP r_TypeClass) { llvm::LLVMContext &ctxt = llvm::getGlobalContext(); @@ -37,10 +48,15 @@ R_getTypeDefinitions() SEXP ans; PROTECT(ans = NEW_LIST(n)); + + Rf_install("Type"); + for(int i = 0; i < n; i++) { SEXP tmp; - SET_VECTOR_ELT(ans, i, tmp = R_MakeExternalPtr((void *) types[i].type, Rf_install("Type"), R_NilValue)); // R_createRef((void *) types[i], "Type") + //SET_VECTOR_ELT(ans, i, tmp = R_MakeExternalPtr((void *) types[i].type, Rf_install("Type"), R_NilValue)); // R_createRef((void *) types[i], "Type") // Rf_setAttrib(tmp, Rf_install("typeName"), mkString(types[i].name)); + + SET_VECTOR_ELT(ans, i, R_createRefTypes(types[i].type, r_TypeClass, "Type")); } UNPROTECT(1); From bdce0b1499fa166220bfa0d4ff9b03a2f3c06379 Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 3 May 2015 20:30:37 +0200 Subject: [PATCH 11/11] add FIXME comment in order to make clear that DIBUILDER leaks memory. In llvm 3.6 DIBUILDER returns pointers, which should ease a non-leaking implementation --- src/DIBuilder.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/DIBuilder.cpp b/src/DIBuilder.cpp index ffe013d7..bf2768ff 100644 --- a/src/DIBuilder.cpp +++ b/src/DIBuilder.cpp @@ -17,7 +17,7 @@ #include "llvm/Support/Dwarf.h" #include "llvm/IR/Metadata.h" -//extern "C" void __jit_debug_register_code(); +//FIXME: this code leaks memory. the interface changes with llvm 3.6. writing non leaking code should be easier with llvm 3.6 extern "C" SEXP @@ -44,7 +44,6 @@ R_new_DIBuilder_CU(SEXP r_dibuilder, SEXP filename, SEXP path) llvm::DICompileUnit* ptr = new llvm::DICompileUnit(); *ptr=ans; - //llvm::DIRef ans2=ans; return(R_createRef(ptr, "DICompileUnit")); } @@ -186,10 +185,7 @@ R_IRBuilder_CreateFunctionType(SEXP r_builder, SEXP args, SEXP r_cu) { for (unsigned i = 0; i < Rf_length(args); ++i) { llvm::DIType *element=GET_REF(VECTOR_ELT(args,i), DIType); - //llvm::DITypeRef *element2 = llvm::cast(element); - //llvm::Value *element3 = llvm::cast(element2); EltTys.push_back(*element); - //EltTys.push_back(const_cast( (llvm::MDNodeContext, MDs *)element)); } llvm::DIArray EltTypeArray = builder->getOrCreateArray(EltTys);