LLVM linker: weird error message when importing a function - llvm

I'm trying to implement a module system in my programming language.
I've read the docs (https://llvm.org/doxygen/classllvm_1_1Linker.html) and the linkModules() function is exactly what I need. When linking two modules I'm getting a weird error message. I don't get what I'm doing wrong.
export.mylang:
export func eoeo(x: i32) -> void {}
import.mylang:
import "#project/eo.mylang";
func main() -> i32 {
return 0;
}
by the way, import.mylang doesn't even call to eoeo() ...
Then I use linkModules() to glue the two modules together:
llvm::Linker::linkModules(*mylang::CompilationUnits[mylang::CompilationUnits.size() - 2]->Module,
std::unique_ptr<llvm::Module>(mylang::CompilationUnits.back()->Module));
this code generates the following LLVM IR (after connecting the two modules):
define void #eoeo(i32 %x) {
entry:
%x1 = alloca i32, align 4
store i32 %x, i32* %x1, align 4
ret void
}
define i32 #main() {
entry:
ret i32 0
}
And in my terminal I see this error message:
Function context does not match Module context!
void (i32)* #eoeo
What does that even mean? Yeah, the two modules do have different contexts, but isn't linkModules() supposed to glue them together into a single large module (regardless of different contexts)? I'm so confused.
(I'm writing this an hour later).
So I've tried to call eoeo() and my source file did compile but I was left with a weird error message:
Call parameter type does not match function signature!
i32 3
i32 call void #eoeo(i32 3)
Function context does not match Module context!
void (i32)* #eoeo
Call parameter type does not match function signature!
i32 3
i32 call void #eoeo(i32 3)
So now I guess types are scoped to an LLVM context?
How can I simply take one module and put it's stuff into another module without worrying about contexts? What's interesting is that I can not define but declare a function in a module (without the body) and then have the body defined in a different module. then I can dump these modules to .ll files and use the llvm-link command line tool to link them (everything works).
The thing is that I really don't want to deal with the file system and use std::system() to interact with LLVM's tools. It does work, but it's tedious to deal with file paths manually.

How can I simply take one module and put it's stuff into another module without worrying about contexts?
The only way to do this is to serialize it down to bitcode out of one context, and then deserialize it into the target context.
Here's what LLVMContext is for. Suppose you're writing a video game and you want to use a scripting engine, a 3d audio subsystem and a graphics system. Each of these libraries uses LLVM under the hood for their own purposes. Instead of having global anything which would cause them to potentially step on each other's data, everything, everything, is scoped to the LLVMContext, keeping each library's data separate. Both Type* and Constant* are stored as members of the LLVMContext. The LLVM module linker assumes that the inputs come from the same context.
You're free to create multiple modules within a single context. These can share Type* and Constant*.
Sometimes people also use contexts for threading, since we have the same problem of making sure two threads don't touch each other's data. If you do that, you then need to serialize to bitcode and deserialize.

Related

How to get loopinfo in Module Pass

I want to get loopinfo in each function by iterating through functions in Module Pass. My code is as follows:
for (auto &F:M) {
if(!F.isDeclaration()){
LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>(F).getLoopInfo();
}
}
However, there is an error, I think my variable Settings should conform to the first function definition, how should I resolve.
clang-12: /llvmtest/llvm/lib/IR/LegacyPassManager.cpp:1645: virtual
std::tuple<llvm::Pass*, bool>
{anonymous}::MPPassManager::getOnTheFlyPass(llvm::Pass*,
llvm::AnalysisID, llvm::Function&): Assertion `FPP && “Unable to find
on the fly pass”’ failed. PLEASE submit a bug report to
https://bugs.llvm.org/ and include the crash backtrace, preprocessed
source, and associated run script.
You can not do this with the legacy pass manager. In the legacy pass manager, every pass could only get info from same-scoped passes -- module from module, function from function, loop from loop, plus one exception allowing function passes to get data from module passes.
With the new pass manager, you'd create a LoopAnalysisManager and add the analysis pass you want and run it. See https://llvm.org/docs/NewPassManager.html#using-analyses .
Note that most of LLVM is presently written to support both pass managers at once. If you do this, you'll need to write your pass differently from most of LLVM's passes, you can't use the types with names like "WrapperPass" that exist to support both legacy and new pass managers.

How to customise pragma in C?

I want to ask what is the simplest way to build a parser to recognise my customised pragmas in C/C++ code. Yes, a simple bash script can do but I am wondering if there is any formal way to do through Clang or LLVM? I tried to check Clang AST but I cannot find any pragmas.
For instance:
int foo1(){
#pragma hi k=1
...
}
int foo2(){
#pragma hello k=7
...
}
I want the pass returns the following:
function foo1 has hi and k=1
function foo2 has hello and k=7
Thanks.
Pragma handling needs to be done in the following parts:
Add a handler in ParsePragma.cpp file (there are examples how to do that). In this step you can parse the pragma token by token and store corresponding information in the AST (possibly the best way to transfer data from this stage to the later stages).
If you need to handle this information in the passes working on LLVM IR, then you need to attach the information previously stored into AST into an IR related classes, in your case it seems the llvm::Function is the place where to keep that. During this process it is needed to update 'lib/AsmParser/LLParser.cpp', 'lib/AsmParser/LLLexer.cpp' and 'lib/IR/AsmWriter.cpp' files. This will allow to read and write the information stored in IR.
Finally if you need to write extra information kept in IR into the assembler file then you will need to update 'lib/CodeGen/AsmPrinter/AsmPrinter.cpp' file correspondingly.

How to get a lua script into lua bytecode?

If I had a lua script, say
print'hi'
How would I get the lua bytecode equivalent to it using c++? I'm not sure if I'm explaining this right though. Thanks for all your help!
You need to load a script and then dump its bytecode.
The relevant C API functions are luaL_loadfile or luaL_loadstring for loading (they use the primitive lua_load) and lua_dump for dumping.
Loading is easy to do with these helper functions.
Dumping is a bt more work because of the need to provide a writer function. It may be easier to call string.dump after loading:
// load script, leave function on the stack
lua_getglobal(L,"string");
lua_getfield(L,"dump");
lua_pushvalue(L,-3);
lua_call(L,1,1);
// string containing bytecode left on the stack

llvm irbuilder call instruction throwing exception on function inlining pass

I'm new to LLVM. I am using the clang c++ API to compile multiple stub files (in c) to IR, and then stick them together using IR builder (after linking them) to eventually run via JIT.
All this works great, unless I add a functionInlining pass to my optimizations, at which point one of these function calls made in IR builder will trigger the following exception when the pass manager is run:
Assertion failed: (New->getType() == getType() && "replaceAllUses of value with new value of different type!"), function replaceAllUsesWith, file /Users/mike/Development/llvm/llvm/lib/IR/Value.cpp, line 356.
This is how I make the call instruction (pretty straight forward):
Function *kernelFunc = mModule->getFunction( (kernel->Name() + StringRef("_") + StringRef(funcName)).str());
if (kernelFunc){
CallInst* newInst = builder.CreateCall(kernelFunc, args);
}
Later the module is optimized:
legacy::PassManager passMan;
PassManagerBuilder Builder;
Builder.OptLevel = 3;
//Builder.Inliner = llvm::createFunctionInliningPass(); //commenting this back in trigger the exception
Builder.populateModulePassManager(passMan);
passMan.run( *mModule ); //exception occurs before this call returns
Any ideas what to look for?
Try running llvm::verifyModule on your module to see if it's correct. You might have an error and have been getting lucky beforehand but it tripped something up in the inliner.
In general assertions check a subset of things that can be wrong with your module but verify checks a lot more.
It could be a bug in LLVM but more than likely it's a bad module, it's easy to happen.
So I finally setup my dev environment so I could inspect the assertion call in the debugger. I turns out the basic block being replaced had a different context set than the one it was being replaced with. going back and making sure IRBuilder was using the same context as the IR parsers solved the problem.

What does badref mean?

What does that IR line mean
define i32 <badref>() {
for defining a new function and writing it in the file
Typically you get <badref> printed out when the IR is malformed. You should run the verifier pass on your module to see if it can help you find out what the precise problem is.
In this particular case I'm guessing you have created a new unnamed function but have not yet added it to a module - without a module it cannot number the global values, so it cannot name the function.