I want to parse an IR file created with clang++ -S -emit-llvm test.cpp -o test.ir using the parseIRFile call, manipulate this IR a bit, and then write the IR back to a file.
I've tried using the WriteBitcodeToFile call, but this doesn't work as expected.
How would I write the Module back to IR, and then compile and run the modified IR?
#include <llvm/IR/Module.h>
#include <llvm/IRReader/IRReader.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/Support/SourceMgr.h>
#include <llvm/Bitcode/ReaderWriter.h>
#include <llvm/Support/FileSystem.h>
using namespace llvm;
int main()
{
LLVMContext context;
SMDiagnostic error;
std::unique_ptr<Module> m = parseIRFile("test.ir", error, context);
std::error_code EC;
llvm::raw_fd_ostream OS("module", EC, llvm::sys::fs::F_None);
WriteBitcodeToFile(m.get(), OS);
OS.flush();
return 0;
}
An easy way to do it is dumping your module to stdout using:
m->dump();
Then you can redirect the output of your C++ program to a text file and compile it using llc :
llc < sample_module.ll > sample_module.s
You can also use the print function:
void print (raw_ostream &OS, AssemblyAnnotationWriter *AAW, bool ShouldPreserveUseListOrder=false, bool IsForDebug=false) const
What you need is to write an LLVM pass which allows you to go through the code Function by Function/Module by Module and read/modify/write to it. You can run this pass on your bytecode file using opt command and it will return the modified bytecode file which you can use.
Here are some sources for writing a pass:
1) http://llvm.org/docs/WritingAnLLVMPass.html
2) https://www.cs.cornell.edu/~asampson/blog/llvm.html
IR is not human readable. You can use llvm-dis to convert it to the human readable version like #TartanLlama said. You can run bitcode using lli command. After you modify the IR, you will see your modified IR running with lli.
Related
I am looking for a full sample that covers usage of the LLVM C++ API, particularly loading a function from a bitcode (not a typo, they call it bitcode) file, running it and get the results. I have studied this blog post and I am trying to port it to C++ but I am struggling to understand how to create the various instances needed, particularly the execution engine. I am using clang -c -emit-llvm file.c to compile a C file to a .bc LLVM bitcode file. The command clang -S -emit-llvm file.c also works and generates a textual .ll file. The function parseIRFile seems to be able to load both.
This is what I have so far:
LLVMContext context;
SMDiagnostic error;
unique_ptr<Module> mod = parseIRFile(StringRef(pathToLlOrBcFile), error, context);
I does not have to use JIT, I am fine with the basic interpreter for now; but I wish to make it work with MCJIT or whatever it's called later on.
Thanks to #arnt for noticing that I was actually using the IR text format; I changed the Makefile and the C++ app to reflect the fact that both .ll and .bc can be parsed by the same function.
I am using llvm-devel.x86_64 9.0.1-5.fc31 on Fedora 31. Full code below.
main.cc (This is the C++ app that loads the LLVM bitcode)
#include <iostream>
#include <llvm/IR/Module.h>
#include <llvm/IRReader/IRReader.h>
#include <llvm/Support/SourceMgr.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/ExecutionEngine/GenericValue.h>
using std::unique_ptr;
using std::cout;
using std::endl;
using llvm::Module;
using llvm::SMDiagnostic;
using llvm::LLVMContext;
using llvm::parseIRFile;
using llvm::StringRef;
using llvm::ExecutionEngine;
using llvm::EngineBuilder;
using llvm::ArrayRef;
using llvm::GenericValue;
using llvm::Function;
int main(int argc, char const *argv[]) {
LLVMContext context;
SMDiagnostic error;
unique_ptr<Module> mod = parseIRFile(StringRef("hosted.bc" /* .ll files also work */), error, context);
ExecutionEngine *executionEngine = EngineBuilder(std::move(mod)).setEngineKind(llvm::EngineKind::Interpreter).create();
Function *add = executionEngine->FindFunctionNamed(StringRef("add"));
GenericValue param1, param2;
param1.FloatVal = 5.5;
param2.FloatVal = 2.7;
GenericValue params[] = { param1, param2 };
ArrayRef<GenericValue> args = ArrayRef<GenericValue>(params, 2);
GenericValue result = executionEngine->runFunction(add, args);
cout << param1.FloatVal << " + " << param2.FloatVal << " = " << result.FloatVal << endl;
}
hosted.c (This is a C app that I compile into an .bc file with clang)
float add(float a, float b) {
return a + b;
}
Makefile (Used to compile the native app and the LLVM bytecode to be hosted in it)
app.o: main.cc
g++ main.cc -lLLVM -o app.o
hosted.bc: hosted.c
clang -c -emit-llvm hosted.c
clean:
rm app.o
rm hosted.bc
.PHONY: clean
Output (Compiling and running)
[dario#localhost llvm-cpp-first]$ make hosted.bc && make && ./app.o
clang -c -emit-llvm hosted.c
g++ main.cc -lLLVM -o app.o
5.5 + 2.7 = 8.2
This question already has answers here:
Rcpp - sourceCpp - undefined symbol
(2 answers)
Closed 4 years ago.
I have existing C code that consists of three files: a header file ( a ".h" file), a library file (a ".o" file), and a source file. They currently run under UNIX and as compiled "mex files" in Matlab. I would like to port them to R using Rcpp. They are all long and complex, so I made a minimal example to help me understand how to port them to R.
The simplified header file (my_header.h) is:
typedef unsigned int ui4;
ui4 add_one( ui4 );
The simplified "library" file (my_lib.cpp) is:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "my_header.h"
ui4 add_one(ui4 x) {
return(x+1);
}
The simplified function program (my_program.cpp) is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <Rcpp.h>
#include <cmath>
#include "my_header.h"
using namespace Rcpp;
// [[Rcpp::export]]
ui4 my_program_r () {
//int main (int argc, const char * argv[]) {
//
// As a MATLAB mex file, this function calls "main(..."
//
ui4 value = add_one( (ui4)1 );
printf( "%d", value );
return value;
}
From the terminal (I'm on a Mac), I can compile these without an error:
$ g++ my_lib.cpp -c -o my_lib.o
$ g++ my_program.cpp -o my_program my_lib.o
When I try to compile them in RStudio, I get:
> library(Rcpp)
> sourceCpp( "my_program.cpp" )
Warning message:
In sourceCpp("my_program.cpp") :
No Rcpp::export attributes or RCPP_MODULE declarations found in source
>
Why isn't this compiling under Rcpp? How do I specify the linked file (the ".o" library file) in the "sourceCpp" command? Do I need to specify the header file?
The sourceCpp command is meant for single files only. If you have multiple files, you have to use a package:
Call Rcpp::Rcpp.package.skeleton(...) to create a skeleton package.
Copy *.h, *.c and *.cpp to the src folder.
Call Rcpp::compileAtrributes().
Use R CMD build ..., R CMD check ... and R CMD INSTALL ... to build, check and compile the package. (The check will complain about undocumented functions ...)
For more details see Rcpp-package vignette and for example this question. BTW, since R does not have an unsigned int type, I am not sure if your return value will work. You might have to switch to an int or double. I also get a different error message than you:
Error in dyn.load("/tmp/RtmpSbvXHx/sourceCpp-i686-pc-linux-gnu-0.12.17/sourcecpp_625ad24a943/sourceCpp_2.so") :
unable to load shared object '/tmp/RtmpSbvXHx/sourceCpp-i686-pc-linux-gnu-0.12.17/sourcecpp_625ad24a943/sourceCpp_2.so':
/tmp/RtmpSbvXHx/sourceCpp-i686-pc-linux-gnu-0.12.17/sourcecpp_625ad24a943/sourceCpp_2.so: undefined symbol: _Z7add_onej
Are you sure the above code is exactly what you used?
I am trying to use XCppRefl lib to achieve reflections in c++. http://www.extreme.indiana.edu/reflcpp/. I could successfully install this library in linux and run the tests given with the source code of the library.
Here is the code that I have written --
#include <iostream>
using namespace std;
#include <reflcpp/ClassType_tmpl.hpp>
#include <reflcpp/BoundClassType_tmpl.hpp>
#include <reflcpp/Exceptions.hpp>
using namespace reflcpp;
#include "Complex.h"
int main()
{
//ClassType ct = ClassType::getClass( string("Complex") );
////PtrHolder_smptr_t obj = ct.createInstance();
//assert(ct.name() == "B");
Complex x;
int ret;
Complex a;
ClassType c = ClassType::getClass( string("Complex") );
//cout<<"name :: "<<c.name()<<endl;
}
It seems to compile just fine --
$ g++ -g -I /usr/local/include/reflcpp-0.2/ -L /usr/local/include/reflcpp-0.2/ -lreflcpp main.cpp
However when I execute the executable (a.out), I get a core-dump
a.out: Type.cpp:87: static const reflcpp::Type_body* reflcpp::Type_body::getType(const std::string&): Assertion `s_class_name_map' failed.
Aborted (core dumped)
Does anyone has used this lib before? Please help.
you have to link your main.o to libreflcpp.a . after compiling use this:
g++ -p -pg -o"project_name" ./A.o ./A_reflection.o ./main.o /usr/local/lib/libreflcpp.a
I'm trying to add a metadata string to my LLVM module. The stripped down version of what I'm trying is
#include <llvm/LLVMContext.h>
#include <llvm/Module.h>
#include <llvm/Metadata.h>
using namespace llvm;
int main() {
Module* module = new Module("test", getGlobalContext());
MDString::get(module->getContext(), "test");
module->dump();
}
I can compile and run it:
Desktop% g++ llvm.cc -o llvm `llvm-config --cppflags --ldflags --libs all`
Desktop% ./llvm
; ModuleID = 'test'
But as one can see, the metadata does not show up.
Can I somehow add the string to the module? The module itself only seems to offer access to named metadata. Now I don't know where else I could look. Any suggestions?
Supplement: I got the feeling that you can't just have a metadata string "floating around" in your module, it seems like you have to add it to a named metadata node. Is that right?
Try this:
#include <llvm/LLVMContext.h>
#include <llvm/Module.h>
#include <llvm/Metadata.h>
using namespace llvm;
int main() {
Module* module = new Module("test", getGlobalContext());
Value *Elts[] = {
MDString::get(module->getContext(), "test1")
};
MDNode *Node = MDNode::get(getGlobalContext(), Elts);
NamedMDNode *NMD = module->getOrInsertNamedMetadata("test2");
NMD->addOperand(Node);
module->dump();
}
I am not sure if you are able to have metadata "floating around" as you say. If it's not attached to any part of your program then what good is it doing? I've been looking into MD a bit lately... I found similar code in lib/Analysis/DIBuilder.cpp. Good luck.
I have generated a bc file with the online compiler on llvm.org, and I would like to know if it is possible to load this bc file from a c or c++ program, execute the IR in the bc file with the llvm jit (programmatically in the c program), and get the results.
How can I accomplish this?
Here's some working code based on Nathan Howell's:
#include <string>
#include <memory>
#include <iostream>
#include <llvm/LLVMContext.h>
#include <llvm/Target/TargetSelect.h>
#include <llvm/Bitcode/ReaderWriter.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/ModuleProvider.h>
#include <llvm/Support/MemoryBuffer.h>
#include <llvm/ExecutionEngine/JIT.h>
using namespace std;
using namespace llvm;
int main()
{
InitializeNativeTarget();
llvm_start_multithreaded();
LLVMContext context;
string error;
Module *m = ParseBitcodeFile(MemoryBuffer::getFile("tst.bc"), context, &error);
ExecutionEngine *ee = ExecutionEngine::create(m);
Function* func = ee->FindFunctionNamed("main");
typedef void (*PFN)();
PFN pfn = reinterpret_cast<PFN>(ee->getPointerToFunction(func));
pfn();
delete ee;
}
One oddity was that without the final include, ee is NULL. Bizarre.
To generate my tst.bc, I used http://llvm.org/demo/index.cgi and the llvm-as command-line tool.
This should (more or less) work using LLVM 2.6. It looks like there are some more helper functions in SVN to create a lazy ModuleProvider on top of a bitcode file. I haven't tried compiling it though, just glued together some bits from one of my JIT applications.
#include <string>
#include <memory>
#include <llvm/Bitcode/ReaderWriter.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/ModuleProvider.h>
#include <llvm/Support/MemoryBuffer.h>
#include <llvm/ExecutionEngine/JIT.h>
using namespace std;
using namespace llvm;
int main()
{
InitializeNativeTarget();
llvm_start_multithreaded();
LLVMContext context;
string error;
auto_ptr<MemoryBuffer> buffer(MemoryBuffer::getFile("bitcode.bc"));
auto_ptr<Module> module(ParseBitcodeFile(buffer.get(), context, &error));
auto_ptr<ModuleProvider> mp(new ExistingModuleProvider(module));
module.release();
auto_ptr<ExecutionEngine> ee(ExecutionEngine::createJIT(mp.get(), &error));
mp.release();
Function* func = ee->getFunction("foo");
typedef void (*PFN)();
PFN pfn = reinterpret_cast<PFN>(ee->getPointerToFunction(func));
pfn();
}
From the command line, you can use the LLVM program lli to run a bc file. If the file is in LLVM assembly language, you'll have to run llvm-as on it first to create a binary bitcode file.
It is easy to do this from C. I'd recommend you look at the extensive LLVM documentation: http://llvm.org/docs
The LLVM irc channel, which has a link on that page, is full of very knowledgeable people that are willing to answer questions.
Sorry for the indirect answer. I use LLVM extensively, but I do direct code generation not just in time compliation.