diff --git a/.Rbuildignore b/.Rbuildignore index 76ecbab1..ea1b16ed 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -25,4 +25,6 @@ a.out.dSYM/.* \.tu explorations/.*\.png explorations/globalString +src/Rllc.cpp +src/llc.cpp diff --git a/Changelog b/Changelog index 2295dd17..77f4f036 100644 --- a/Changelog +++ b/Changelog @@ -6,6 +6,8 @@ Version 0.6-0 * insertBefore(), insertAfter(), moveBefore() + * isa() for Instruction classes. + Version 0.5-0 * show() methods for Module, Function, Type to make the diff --git a/DESCRIPTION b/DESCRIPTION index a6b29317..68903b9c 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -33,3 +33,4 @@ Collate: llvmVersion.R classDefs.R manual_generics.R BinaryOpEnums.R Function.R ostream.R targetMachine.R metadata.R opCodeClassMap.R + classof.R initialize.R diff --git a/NAMESPACE b/NAMESPACE index dbe0fe74..013b9522 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -378,3 +378,15 @@ export(LLVMAttributes) export(insertBefore, insertAfter, moveBefore) +export(isa) + +export(setCallingConv, getCallingConv) +export(InitializeAllTargets, InitializeAllTargetMCs, InitializeAllAsmPrinters, InitializeAllAsmParsers) + + +#Temporary +#export(llc) + +export(getDefaultTargetTriple) + + diff --git a/Paper/OtherFuncs b/Paper/OtherFuncs index 349b0a05..09fc6294 100644 --- a/Paper/OtherFuncs +++ b/Paper/OtherFuncs @@ -21,7 +21,7 @@ Context % Mention in exporting/importing IR code with other languages. I/O of code -{write,read}BitCode, parseIR, parseAssembly +[done] {write,read}BitCode, parseIR, parseAssembly Pass manager getPassManager diff --git a/R/Function.R b/R/Function.R index fb5341c6..85cee3d7 100644 --- a/R/Function.R +++ b/R/Function.R @@ -228,3 +228,12 @@ function(vals) +setClass("CallingConv", contains = "integer") + +setCallingConv = +function(fun, conv) + .Call("R_Function_setCallingConv", as(fun, "Function"), as(conv, "CallingConv")) + +getCallingConv = +function(fun) + as(.Call("R_Function_setCallingConv", as(fun, "Function")), "CallingConv") diff --git a/R/classDefs.R b/R/classDefs.R index 1fc95cc5..dad7f166 100644 --- a/R/classDefs.R +++ b/R/classDefs.R @@ -173,6 +173,7 @@ setClass("TargetMachine", contains = "RC++Reference") setClass("TargetLibraryInfo", contains = "RC++Reference") +setClass("PassRegistry", contains = "RC++Reference") setClass("Pass", contains = "RC++Reference") setClass("ImmutablePass", contains = "Pass") setClass("DataLayout", contains = "ImmutablePass") diff --git a/R/classof.R b/R/classof.R new file mode 100644 index 00000000..951bf7a1 --- /dev/null +++ b/R/classof.R @@ -0,0 +1,6 @@ +isa = +function(obj, classname = class(obj)) +{ + .Call("R_Instruction_classof", as(obj, "Instruction"), as.character(classname)) +} + diff --git a/R/initialize.R b/R/initialize.R new file mode 100644 index 00000000..fe7eddae --- /dev/null +++ b/R/initialize.R @@ -0,0 +1,16 @@ +InitializeAllTargets = + function() + .Call("R_InitializeAllTargets") + +InitializeAllTargetMCs = + function() + .Call("R_InitializeAllTargetMCs") + +InitializeAllAsmPrinters = + function() + .Call("R_InitializeAllAsmPrinters") + +InitializeAllAsmParsers = + function() + .Call("R_InitializeAllAsmParsers") + diff --git a/R/module.R b/R/module.R index 682c1b31..8b51ae67 100644 --- a/R/module.R +++ b/R/module.R @@ -241,7 +241,14 @@ setTriple = setTargetTriple = function(m, str) { .Call("R_Module_setTargetTriple", m, as.character(str)) -} +} + + +getDefaultTargetTriple = +function() +{ + .Call("R_getDefaultTargetTriple") +} setMethod("getDataLayout", "Module", diff --git a/R/ostream.R b/R/ostream.R index 4091b93d..694bdff5 100644 --- a/R/ostream.R +++ b/R/ostream.R @@ -6,12 +6,18 @@ function(filename) } formattedRawOstream = -function(stream, delete = FALSE) +function(stream, delete = FALSE, finalize = TRUE) { if(is.character(stream)) stream = rawFDOstream(stream) - .Call("R_new_formatted_raw_ostream", stream, as.logical(delete)) + ans = .Call("R_new_formatted_raw_ostream", stream, as.logical(delete)) + + if(finalize) + # could allow the caller to specify their own routine for the finalizer. + .Call("R_setFinalizer_formatted_raw_ostream", ans@ref) + + ans } stringRawOstream = @@ -19,3 +25,7 @@ function(value = "") { .Call("R_new_raw_string_ostream", as.character(value)) } + +setAs("raw_string_ostream", "character", + function(from) + .Call("R_raw_string_ostream_str", from)) diff --git a/R/targets.R.in b/R/targets.R.in index 2d0f2194..9eaeee9a 100644 --- a/R/targets.R.in +++ b/R/targets.R.in @@ -43,9 +43,9 @@ function(target, triple, cpu, features = "", options = list()) } lookupTarget = -function(triple) +function(triple, arch = character()) { - .Call("R_TargetRegistry_lookupTarget", as.character(triple)) + .Call("R_TargetRegistry_lookupTarget", as.character(triple), as.character(arch)) } diff --git a/R/utils.R b/R/utils.R index 8e4aaac9..a9d327d3 100644 --- a/R/utils.R +++ b/R/utils.R @@ -26,3 +26,15 @@ function(msg, class) structure(list(msg = paste(msg, collapse = " ")), class = c(class, c("simpleError", "error", "condition"))) } + + + +llc = +function(file, args, march = "nvptx64", out = NA) +{ + # "/Users/duncan/Projects/GPUs/Rnvvm/inst/sampleCode/simple-gpu64.ll", + args = c("Rllc", args, paste0("-march=", march), path.expand(file)) + if(!is.na(out)) + args = c(args, "-o", out) + .C("R_llc", length(args), args)[[1]] +} diff --git a/explorations/cpp.R b/explorations/cpp.R index 25ec728f..74562e43 100644 --- a/explorations/cpp.R +++ b/explorations/cpp.R @@ -10,7 +10,7 @@ if(FALSE) { ir$createReturn(createIntegerConstant(1L)) verifyModule(m) } else - m = parseIR("experiments/fib.ll") + m = parseIR("../experiments/fib.ll") ############ InitializeCppBackendTarget() diff --git a/explorations/ptx.R b/explorations/ptx.R index 75f9c828..d0bc36ba 100644 --- a/explorations/ptx.R +++ b/explorations/ptx.R @@ -1,25 +1,58 @@ library(Rllvm) -m = parseIR("experiments/fib.ll") + +#InitializeAllTargets() +#InitializeAllTargetMCs() +#InitializeAllAsmPrinters() +#InitializeAllAsmParsers() + +.Call("R_initPassRegistry", NULL) + +if(FALSE) { + m = parseIR("../experiments/fib.ll") + setMetadata(m, "nvvm.annotation", list(m$fib, "kernel", 1L)) +} else + m = parseIR("~/Projects/GPUs/Rnvvm/inst/sampleCode/simple-gpu64.ll") + +#Rllvm:::setCallingConv(m$simple, as(71L, "CallingConv")) + InitializeNVPTXTarget() -tri = "nvptx64" +tri = arch = "nvptx64" + +tri = Rllvm:::getDefaultTargetTriple() setTargetTriple(m, tri) -trgt = lookupTarget(tri) -machine = createTargetMachine(trgt, tri, "sm_20") -trgtLibInfo = targetLibraryInfo(tri) -dataLayout = getDataLayout(machine) +#trgt = lookupTarget(tri) +trgt = lookupTarget(tri, arch) +machine = createTargetMachine(trgt, tri, "sm_20") # sm_20 pm = passManager(m, FALSE) + +trgtLibInfo = targetLibraryInfo(tri) addPass(pm, trgtLibInfo) + addAnalysisPasses(machine, pm) + +dataLayout = getDataLayout(machine) addPass(pm, dataLayout) #out = .Call("R_new_raw_string_ostream", "") -out = formattedRawOstream("/tmp/foo.ptx") -addPassesToEmitFile(machine, pm, out, 0L) +#stream = rawFDOstream("/tmp/foo.ptx") + +stream = stringRawOstream() +out = formattedRawOstream(stream) + +if(addPassesToEmitFile(machine, pm, out, 0L)) + stop("failed in addPassesToEmitFile. Is this type of file supported by the manager?") run(pm, m) + +rm(out); gc() +code = as(stream, "character") +print(nchar(code)) + +#.Call("R_raw_ostream_close", stream, FALSE) +# cat("File size:", file.info("/tmp/foo.ptx")[1, "size"], "\n") diff --git a/inst/TU/clang.R b/inst/TU/clang.R index 538e0bea..7ce0b9a1 100644 --- a/inst/TU/clang.R +++ b/inst/TU/clang.R @@ -46,11 +46,18 @@ baseClass = sapply(insClass, function(x) gsub("class ", "", sapply(x@superClass instClasses = getAllDescendantClasses(insClass, , baseClass, namespace = "llvm") -code = c("CHAR(STRING_ELT" +insClass = insClass[ gsub("llvm::", "", instClasses) ] + +#code = c("CHAR(STRING_ELT" sprintf('if(strcmp(targetClass, "%s") == 0)\n\tans = static_cast<%s*>(ptr);', gsub("llvm::", "", instClasses), instClasses) +classof = sprintf('%s if(strcmp(targetClass, "%s") == 0)\n\tans = %s::classof(val);', + c("", rep("else", length(instClasses) -1)), gsub("llvm::", "", instClasses), instClasses) + +cat(classof, sep = "\n", file = "../../src/auto_classof.h") + ########### methodNames = setdiff(unique(unlist(sapply(insClass, function(x) names(x@methods)))), names(insClass)) diff --git a/inst/TU/llvm.c b/inst/TU/llvm.c index 93d2ad94..2109a184 100644 --- a/inst/TU/llvm.c +++ b/inst/TU/llvm.c @@ -43,6 +43,7 @@ #include #include +#include #include diff --git a/src/ExecEngine.cpp b/src/ExecEngine.cpp index a24ff573..6d117fa8 100644 --- a/src/ExecEngine.cpp +++ b/src/ExecEngine.cpp @@ -51,12 +51,6 @@ R_InitializeCppBackendTarget() } #endif -extern "C" -void -R_InitializeAllTargetInfos() -{ - llvm::InitializeAllTargetInfos(); -} extern "C" SEXP diff --git a/src/Function.cpp b/src/Function.cpp index dc706945..bde827f2 100644 --- a/src/Function.cpp +++ b/src/Function.cpp @@ -178,7 +178,7 @@ R_Argument_setAttrs(llvm::Argument *arg, SEXP r_vals) { /* now have the parameter, so set the values. */ llvm::AttrBuilder builder; - for(int i = 0 ; i < (unsigned) Rf_length(r_vals); i++) + for(unsigned i = 0 ; i < (unsigned) Rf_length(r_vals); i++) builder.addAttribute( (AttrKind) INTEGER(r_vals)[i] ); diff --git a/src/Instruction.cpp b/src/Instruction.cpp index 8c1dcda4..c1d118b9 100644 --- a/src/Instruction.cpp +++ b/src/Instruction.cpp @@ -152,9 +152,9 @@ R_Instruction_getOperand(SEXP r_inst, SEXP r_i) llvm::Instruction *inst = GET_REF(r_inst, Instruction); if(!inst) return(R_NilValue); llvm::Value *el; - int i = INTEGER(r_i)[0] - 1; - if(i >= inst->getNumOperands()) { - PROBLEM "index of operand too large" + unsigned i = INTEGER(r_i)[0] - 1; + if(i < 0 || i >= inst->getNumOperands()) { + PROBLEM "index of operand is incorrect" ERROR; } @@ -210,7 +210,7 @@ R_Instruction_moveBefore(SEXP r_base, SEXP r_inst) { llvm::Instruction *base = GET_REF(r_base, Instruction); llvm::Instruction *inst = GET_REF(r_inst, Instruction); -fprintf(stderr, "moveBefore: %p, %p\n", base, inst); + base->moveBefore(inst); return(R_NilValue); } diff --git a/src/Pass.cpp b/src/Pass.cpp new file mode 100644 index 00000000..dc3ec57c --- /dev/null +++ b/src/Pass.cpp @@ -0,0 +1,42 @@ +#include "Rllvm.h" + +extern "C" +SEXP +R_getPassRegistry() +{ + llvm::PassRegistry *reg = llvm::PassRegistry::getPassRegistry(); + return(R_createRef(reg, "PassRegistry")); +} + + +extern "C" +SEXP +R_initPassRegistry(SEXP r_registry) +{ + llvm::PassRegistry *Registry; + + if(Rf_length(r_registry)) + Registry = GET_REF(r_registry, PassRegistry); + else + Registry = llvm::PassRegistry::getPassRegistry(); + + if(!Registry) { + PROBLEM "no registry" + ERROR; + } + llvm::initializeCore(*Registry); + llvm::initializeCodeGen(*Registry); + llvm::initializeLoopStrengthReducePass(*Registry); + llvm::initializeLowerIntrinsicsPass(*Registry); + llvm::initializeUnreachableBlockElimPass(*Registry); + + return(R_NilValue); +} + + + + + + + + diff --git a/src/Target.cpp b/src/Target.cpp index 0fddda3b..eb12e4ea 100644 --- a/src/Target.cpp +++ b/src/Target.cpp @@ -12,12 +12,20 @@ extern "C" SEXP -R_TargetRegistry_lookupTarget(SEXP r_triple) +R_TargetRegistry_lookupTarget(SEXP r_triple, SEXP r_arch) { std::string err; const llvm::Target *ans; - std::string triple(CHAR(STRING_ELT(r_triple, 0))); - ans = llvm::TargetRegistry::lookupTarget(triple, err); + + if(Rf_length(r_arch)) { + std::string arch(CHAR(STRING_ELT(r_arch, 0))); + llvm::Triple triple(makeTwine(r_triple)); + ans = llvm::TargetRegistry::lookupTarget(arch, triple, err); + } else { + std::string triple(CHAR(STRING_ELT(r_triple, 0))); + ans = llvm::TargetRegistry::lookupTarget(triple, err); + } + return(R_createRef(ans, "Target")); } @@ -120,7 +128,7 @@ R_TargetMachine_addPassesToEmitFile(SEXP r_targetMachine, SEXP r_passManager, SE out = GET_REF(r_out, formatted_raw_ostream); bool ans = targetMachine->addPassesToEmitFile(*passManager, *out, (llvm::TargetMachine::CodeGenFileType) INTEGER(r_fileType)[0]); - + /* ans is true if addPasses... failed */ return(ScalarLogical(ans == true)); } @@ -145,6 +153,10 @@ R_new_raw_string_ostream(SEXP r_str) str = (std::string *) getRReference(r_str); llvm::raw_string_ostream *ans = new llvm::raw_string_ostream(*str); + if(!ans) { + PROBLEM "error creating string stream" + ERROR; + } return(R_createRef(ans, "raw_string_ostream")); } @@ -158,6 +170,23 @@ R_new_formatted_raw_ostream(SEXP r_stream, SEXP r_delete) return(R_createRef(ans, "formatted_raw_ostream")); } +void +R_formatted_raw_ostream_finalizer(SEXP obj) +{ + llvm::formatted_raw_ostream *stream = (llvm::formatted_raw_ostream *) R_ExternalPtrAddr(obj); + delete stream; +} + +extern "C" +SEXP +R_setFinalizer_formatted_raw_ostream(SEXP r_stream) +{ +// llvm::formatted_raw_ostream *stream = GET_REF(r_stream, formatted_raw_ostream); + R_RegisterCFinalizer(r_stream, R_formatted_raw_ostream_finalizer); + return(R_NilValue); +} + + extern "C" SEXP R_new_raw_fd_ostream(SEXP r_filename) @@ -172,6 +201,17 @@ R_new_raw_fd_ostream(SEXP r_filename) return(R_createRef(ans, "raw_fd_ostream")); } + +extern "C" +SEXP +R_raw_string_ostream_str(SEXP r_stream) +{ + llvm::raw_string_ostream *stream = GET_REF(r_stream, raw_string_ostream); + std::string str = stream->str(); + return(mkString(str.c_str() ? str.c_str() : "")); +} + + extern "C" SEXP R_raw_ostream_close(SEXP r_stream, SEXP r_delete) @@ -196,3 +236,36 @@ R_printRegisteredTargetsForVersion() return(R_NilValue); } + + +#include + + +#define MAKE_InitializeAll(suffix) \ + extern "C" \ + SEXP \ + R_InitializeAll##suffix() \ + { \ + llvm::InitializeAll ## suffix (); \ + return(R_NilValue); \ + } + +MAKE_InitializeAll(TargetInfos) +MAKE_InitializeAll(Targets) +MAKE_InitializeAll(TargetMCs) +MAKE_InitializeAll(AsmPrinters) +MAKE_InitializeAll(AsmParsers) +MAKE_InitializeAll(Disassemblers) + + + + + +#include +extern "C" +SEXP +R_getDefaultTargetTriple() +{ + std::string tri = llvm::sys::getDefaultTargetTriple(); + return(mkString(tri.c_str())); +} diff --git a/src/auto_classof.h b/src/auto_classof.h new file mode 100644 index 00000000..8bab64be --- /dev/null +++ b/src/auto_classof.h @@ -0,0 +1,88 @@ + if(strcmp(targetClass, "Instruction") == 0) + ans = llvm::Instruction::classof(val); +else if(strcmp(targetClass, "TerminatorInst") == 0) + ans = llvm::TerminatorInst::classof(val); +else if(strcmp(targetClass, "UnaryInstruction") == 0) + ans = llvm::UnaryInstruction::classof(val); +else if(strcmp(targetClass, "BinaryOperator") == 0) + ans = llvm::BinaryOperator::classof(val); +else if(strcmp(targetClass, "CmpInst") == 0) + ans = llvm::CmpInst::classof(val); +else if(strcmp(targetClass, "StoreInst") == 0) + ans = llvm::StoreInst::classof(val); +else if(strcmp(targetClass, "FenceInst") == 0) + ans = llvm::FenceInst::classof(val); +else if(strcmp(targetClass, "AtomicCmpXchgInst") == 0) + ans = llvm::AtomicCmpXchgInst::classof(val); +else if(strcmp(targetClass, "AtomicRMWInst") == 0) + ans = llvm::AtomicRMWInst::classof(val); +else if(strcmp(targetClass, "GetElementPtrInst") == 0) + ans = llvm::GetElementPtrInst::classof(val); +else if(strcmp(targetClass, "CallInst") == 0) + ans = llvm::CallInst::classof(val); +else if(strcmp(targetClass, "SelectInst") == 0) + ans = llvm::SelectInst::classof(val); +else if(strcmp(targetClass, "ExtractElementInst") == 0) + ans = llvm::ExtractElementInst::classof(val); +else if(strcmp(targetClass, "InsertElementInst") == 0) + ans = llvm::InsertElementInst::classof(val); +else if(strcmp(targetClass, "ShuffleVectorInst") == 0) + ans = llvm::ShuffleVectorInst::classof(val); +else if(strcmp(targetClass, "InsertValueInst") == 0) + ans = llvm::InsertValueInst::classof(val); +else if(strcmp(targetClass, "PHINode") == 0) + ans = llvm::PHINode::classof(val); +else if(strcmp(targetClass, "LandingPadInst") == 0) + ans = llvm::LandingPadInst::classof(val); +else if(strcmp(targetClass, "CastInst") == 0) + ans = llvm::CastInst::classof(val); +else if(strcmp(targetClass, "AllocaInst") == 0) + ans = llvm::AllocaInst::classof(val); +else if(strcmp(targetClass, "LoadInst") == 0) + ans = llvm::LoadInst::classof(val); +else if(strcmp(targetClass, "ICmpInst") == 0) + ans = llvm::ICmpInst::classof(val); +else if(strcmp(targetClass, "FCmpInst") == 0) + ans = llvm::FCmpInst::classof(val); +else if(strcmp(targetClass, "VAArgInst") == 0) + ans = llvm::VAArgInst::classof(val); +else if(strcmp(targetClass, "ExtractValueInst") == 0) + ans = llvm::ExtractValueInst::classof(val); +else if(strcmp(targetClass, "ReturnInst") == 0) + ans = llvm::ReturnInst::classof(val); +else if(strcmp(targetClass, "BranchInst") == 0) + ans = llvm::BranchInst::classof(val); +else if(strcmp(targetClass, "SwitchInst") == 0) + ans = llvm::SwitchInst::classof(val); +else if(strcmp(targetClass, "IndirectBrInst") == 0) + ans = llvm::IndirectBrInst::classof(val); +else if(strcmp(targetClass, "InvokeInst") == 0) + ans = llvm::InvokeInst::classof(val); +else if(strcmp(targetClass, "ResumeInst") == 0) + ans = llvm::ResumeInst::classof(val); +else if(strcmp(targetClass, "UnreachableInst") == 0) + ans = llvm::UnreachableInst::classof(val); +else if(strcmp(targetClass, "TruncInst") == 0) + ans = llvm::TruncInst::classof(val); +else if(strcmp(targetClass, "ZExtInst") == 0) + ans = llvm::ZExtInst::classof(val); +else if(strcmp(targetClass, "SExtInst") == 0) + ans = llvm::SExtInst::classof(val); +else if(strcmp(targetClass, "FPTruncInst") == 0) + ans = llvm::FPTruncInst::classof(val); +else if(strcmp(targetClass, "FPExtInst") == 0) + ans = llvm::FPExtInst::classof(val); +else if(strcmp(targetClass, "UIToFPInst") == 0) + ans = llvm::UIToFPInst::classof(val); +else if(strcmp(targetClass, "SIToFPInst") == 0) + ans = llvm::SIToFPInst::classof(val); +else if(strcmp(targetClass, "FPToUIInst") == 0) + ans = llvm::FPToUIInst::classof(val); +else if(strcmp(targetClass, "FPToSIInst") == 0) + ans = llvm::FPToSIInst::classof(val); +else if(strcmp(targetClass, "IntToPtrInst") == 0) + ans = llvm::IntToPtrInst::classof(val); +else if(strcmp(targetClass, "PtrToIntInst") == 0) + ans = llvm::PtrToIntInst::classof(val); +else if(strcmp(targetClass, "BitCastInst") == 0) + ans = llvm::BitCastInst::classof(val); diff --git a/src/classof.cpp b/src/classof.cpp new file mode 100644 index 00000000..458d04a1 --- /dev/null +++ b/src/classof.cpp @@ -0,0 +1,16 @@ +#include "Rllvm.h" + +extern "C" +SEXP +R_Instruction_classof(SEXP r_val, SEXP r_targetClass) +{ + const llvm::Value *val = GET_REF(r_val, Value); + const char *targetClass = CHAR(STRING_ELT(r_targetClass, 0)); + int ans = 0; + +#include "auto_classof.h" + else + return(ScalarLogical(NA_LOGICAL)); + + return(ScalarLogical(ans)); +} diff --git a/src/optimize.cpp b/src/optimize.cpp index 00dc4cb2..c337fa3e 100644 --- a/src/optimize.cpp +++ b/src/optimize.cpp @@ -93,9 +93,6 @@ R_PassManagerBase_Add(SEXP r_mgr, SEXP r_pass) - - - extern "C" SEXP R_PassManager_new(SEXP r_mod, SEXP r_fnMgr) diff --git a/tests/moveInstructions.R b/tests/moveInstructions.R index cf9b9f68..463057c9 100644 --- a/tests/moveInstructions.R +++ b/tests/moveInstructions.R @@ -1,3 +1,4 @@ +# This is an example of moving instructions around. library(Rllvm) m = Module() f = Function("foo", VoidType, list(x = DoubleType), module = m) @@ -7,8 +8,8 @@ ir = IRBuilder(b) i = ir$createLocalVariable(Int32Type, "i") j = ir$createLocalVariable(Int32Type, "j") -#ir$createStore(ir$createConstant(0L), i) -#ir$createStore(ir$createConstant(0L, Int32Type), j) +ir$createStore(ir$createConstant(0L), i) +ir$createStore(ir$createConstant(0L, Int32Type), j) l1 = ir$createLoad(i) l2 = ir$createLoad(j)