I i'm trying to create a exception handler inside JIT llvm code. the current documentation regarding exception handling in LLVM is very handwavy at the moment, so i've been trying to reuse most of the snippets i get from http://llvm.org/demo in order to get a working example, but i'm not sure if those are up to date with llvm 2.9 (the version i am using).
This is what the module looks after Module::dump();
; ModuleID = 'testModule'
declare i32 #myfunc()
define i32 #test_function_that_invokes_another() {
entryBlock:
%0 = alloca i8*
%1 = alloca i32
%someName = invoke i32 #myfunc()
to label %exitBlock unwind label %unwindBlock
exitBlock: ; preds = %entryBlock
ret i32 1
unwindBlock: ; preds = %entryBlock
%2 = call i8* #llvm.eh.exception()
store i8* %2, i8** %0
%3 = call i32 (i8*, i8*, ...)* #llvm.eh.selector(i8* %2, i8* bitcast (i32 (...)* #__gxx_personality_v0 to i8*), i8* null)
store i32 1, i32* %1
%4 = load i8** %0
%5 = call i32 (...)* #__cxa_begin_catch(i8* %4) nounwind
%cleanup_call = call i32 #myCleanup()
%6 = call i32 (...)* #__cxa_end_catch()
ret i32 1
}
declare i32 #__gxx_personality_v0(...)
declare i32 #__cxa_begin_catch(...)
declare i32 #__cxa_end_catch(...)
declare i8* #llvm.eh.exception() nounwind readonly
declare i32 #llvm.eh.selector(i8*, i8*, ...) nounwind
declare i32 #myCleanup()
and this is what happens when i try to execute the function:
inside JIT calling C/C++ call
terminate called after throwing an instance of 'int'
Aborted
this shows that the function that throws gets called, it throws, but i never land in the cleanup call. (my cleanup call should have said 'inside JIT calling C/C++ Cleanup')
The function that invokes and (attempts) to catch a thrown exception is:
const inline llvm::FunctionType* getTestFunctionSignature(llvm::LLVMContext& context) {
return llvm::TypeBuilder< unsigned int(), false > ::get(context);
}
llvm::Function* createFunctionThatInvokesAnother( llvm::LLVMContext& ctx, llvm::Module* mod , llvm::Function* another ) {
llvm::Function* result = llvm::Function::Create(getTestFunctionSignature(ctx),
llvm::GlobalValue::ExternalLinkage,
"test_function_that_invokes_another",
mod);
llvm::BasicBlock* entry_block = llvm::BasicBlock::Create(ctx, "entryBlock", result);
llvm::BasicBlock* exit_block = llvm::BasicBlock::Create(ctx, "exitBlock", result);
llvm::BasicBlock* unwind_block = llvm::BasicBlock::Create(ctx, "unwindBlock", result);
llvm::IRBuilder<> builder(entry_block);
llvm::ConstantInt* ci = llvm::ConstantInt::get( mod->getContext() , llvm::APInt( 32 , llvm::StringRef("1"), 10));
llvm::PointerType* pty3 = llvm::PointerType::get(llvm::IntegerType::get(mod->getContext(), 8), 0);
llvm::AllocaInst* ptr_24 = new llvm::AllocaInst(pty3, "", entry_block);
llvm::AllocaInst* ptr_25 = new llvm::AllocaInst(llvm::IntegerType::get(mod->getContext(), 32), "", entry_block);
llvm::Twine name("someName");
builder.CreateInvoke( another , exit_block , unwind_block , "someName" );
builder.SetInsertPoint( exit_block );
builder.CreateRet(ci);
builder.SetInsertPoint( unwind_block );
llvm::Function* func___gxx_personality_v0 = func__gxx_personality_v0(mod);
llvm::Function* func___cxa_begin_catch = func__cxa_begin_catch(mod);
llvm::Function* func___cxa_end_catch = func__cxa_end_catch(mod);
llvm::Function* func_eh_ex = func_llvm_eh_exception(mod);
llvm::Function* func_eh_sel = func__llvm_eh_selector(mod);
llvm::Constant* const_ptr_17 = llvm::ConstantExpr::getCast(llvm::Instruction::BitCast, func___gxx_personality_v0, pty3);
llvm::ConstantPointerNull* const_ptr_18 = llvm::ConstantPointerNull::get(pty3);
llvm::CallInst* get_ex = llvm::CallInst::Create(func_eh_ex, "", unwind_block);
get_ex->setCallingConv(llvm::CallingConv::C);
get_ex->setTailCall(false);
new llvm::StoreInst(get_ex, ptr_24, false, unwind_block);
std::vector<llvm::Value*> int32_37_params;
int32_37_params.push_back(get_ex);
int32_37_params.push_back(const_ptr_17);
int32_37_params.push_back(const_ptr_18);
llvm::CallInst* eh_sel = llvm::CallInst::Create(func_eh_sel, int32_37_params.begin(), int32_37_params.end(), "", unwind_block);
eh_sel->setCallingConv(llvm::CallingConv::C);
eh_sel->setTailCall(false);
new llvm::StoreInst(ci, ptr_25, false, unwind_block);
llvm::LoadInst* ptr_29 = new llvm::LoadInst(ptr_24, "", false, unwind_block);
llvm::CallInst* ptr_30 = llvm::CallInst::Create(func___cxa_begin_catch, ptr_29, "", unwind_block);
ptr_30->setCallingConv(llvm::CallingConv::C);
ptr_30->setTailCall(false);
llvm::AttrListPtr ptr_30_PAL;
{
llvm::SmallVector<llvm::AttributeWithIndex, 4 > Attrs;
llvm::AttributeWithIndex PAWI;
PAWI.Index = 4294967295U;
PAWI.Attrs = 0 | llvm::Attribute::NoUnwind;
Attrs.push_back(PAWI);
ptr_30_PAL = llvm::AttrListPtr::get(Attrs.begin(), Attrs.end());
}
ptr_30->setAttributes(ptr_30_PAL);
llvm::Function* cleanup = call_myCleanup( mod );
builder.CreateCall( cleanup , "cleanup_call");
llvm::CallInst* end_catch = llvm::CallInst::Create(func___cxa_end_catch, "", unwind_block);
builder.CreateRet(ci);
//createCatchHandler( mod , unwind_block );
return result;
}
This gets called like the usual business:
testMain() {
llvm::LLVMContext ctx;
llvm::InitializeNativeTarget();
llvm::StringRef idRef("testModule");
llvm::Module* module = new llvm::Module(idRef, ctx);
std::string jitErrorString;
llvm::ExecutionEngine* execEngine = executionEngine( module , jitErrorString );
llvm::FunctionPassManager* OurFPM = new llvm::FunctionPassManager(module);
llvm::Function *thr = call_my_func_that_throws( module );
llvm::Function* result = createFunctionThatInvokesAnother(ctx, module ,thr);
std::string errorInfo;
llvm::verifyModule(* module, llvm::PrintMessageAction, & errorInfo);
module->dump();
void *fptr = execEngine->getPointerToFunction(result);
unsigned int (*fp)() = (unsigned int (*)())fptr;
try {
unsigned int value = fp();
} catch (...) {
std::cout << " handled a throw from JIT function" << std::endl;
}
}
where my function that throws is:
int myfunc() {
std::cout << " inside JIT calling C/C++ call" << std::endl;
throw 0;
};
llvm::Function* call_my_func_that_throws (llvm::Module* mod) {
std::vector< const llvm::Type* > FuncTy_ex_args;
llvm::FunctionType* FuncTy_ex = llvm::FunctionType::get( llvm::IntegerType::get( mod->getContext() , 32) , FuncTy_ex_args , false);
llvm::Function* result = llvm::Function::Create(FuncTy_ex, llvm::GlobalValue::ExternalLinkage, "myfunc", mod);
result->setCallingConv( llvm::CallingConv::C );
llvm::AttrListPtr PAL;
result->setAttributes( PAL );
llvm::sys::DynamicLibrary::AddSymbol( "myfunc" , (void*) &myfunc );
return result;
}
and my cleanup function is defined in a similar way:
int myCleanup() {
std::cout << " inside JIT calling C/C++ Cleanup" << std::endl;
return 18;
};
llvm::Function* call_myCleanup (llvm::Module* mod) {
std::vector< const llvm::Type* > FuncTy_ex_args;
llvm::FunctionType* FuncTy_ex = llvm::FunctionType::get( llvm::IntegerType::get( mod->getContext() , 32) , FuncTy_ex_args , false);
llvm::Function* result = llvm::Function::Create(FuncTy_ex, llvm::GlobalValue::ExternalLinkage, "myCleanup", mod);
result->setCallingConv( llvm::CallingConv::C );
llvm::AttrListPtr PAL;
result->setAttributes( PAL );
llvm::sys::DynamicLibrary::AddSymbol( "myCleanup" , (void*) &myCleanup );
return result;
}
I've also read this document regarding recent exception handling changes in LLVM, but is not clear how those changes translate to actual, you know, code
Right now the EH code is undergoing a large amount of revision. The demo, if I recall correctly, is not version 2.9, but current development sources - meaning trying to do something with 2.9 is going to be a world of hurt if you try that way.
That said, the EH representation is much better now and numerous patches have gone in to improve the documentation just this week. If you are trying to write a language that uses exceptions via llvm I highly suggest you migrate your code to current development sources.
All of that said, I'm not sure how well exception handling works in the JIT at all right now. It's nominally supported, but you may need to debug the unwind tables that are put into memory to make sure they're correct.
Related
I am a beginner in LLVM, and I wanna get the true value of a given varibale name and line number by using LLVM pass. I have several problems.
correctly get the metadata;
get the type of String;
get dynamic value.
For example, I wanna get the value of b after line 7:
#include <iostream>
int main() {
int b;
int a;
std::cin >> a;
b = a; // line 7
return 0;
}
IR of the main function:
; Function Attrs: mustprogress noinline norecurse optnone uwtable
define dso_local i32 #main() #4 !dbg !857 {
%1 = alloca i32, align 4
%2 = alloca i32, align 4
%3 = alloca i32, align 4
store i32 0, i32* %1, align 4
call void #llvm.dbg.declare(metadata i32* %2, metadata !858, metadata !DIExpression()), !dbg !859
call void #llvm.dbg.declare(metadata i32* %3, metadata !860, metadata !DIExpression()), !dbg !861
%4 = call nonnull align 8 dereferenceable(16) %"class.std::basic_istream"* #_ZNSirsERi(%"class.std::basic_istream"* nonnull align 8 dereferenceable(16) #_ZSt3cin, i32* nonnull align 4 dereferenceable(4) %3), !dbg !862
%5 = load i32, i32* %3, align 4, !dbg !863
store i32 %5, i32* %2, align 4, !dbg !864
ret i32 0, !dbg !865
}
; METADATA
!857 = distinct !DISubprogram(name: "main", scope: !8, file: !8, line: 11, type: !539, scopeLine: 11, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !7, retainedNodes: !9)
!858 = !DILocalVariable(name: "b", scope: !857, file: !8, line: 12, type: !20)
!859 = !DILocation(line: 12, column: 9, scope: !857)
!860 = !DILocalVariable(name: "a", scope: !857, file: !8, line: 13, type: !20)
!861 = !DILocation(line: 13, column: 9, scope: !857)
!862 = !DILocation(line: 14, column: 14, scope: !857)
!863 = !DILocation(line: 15, column: 9, scope: !857)
!864 = !DILocation(line: 15, column: 7, scope: !857)
!865 = !DILocation(line: 16, column: 5, scope: !857)
I need to read dynamic value, so I instrument logvar function:
#include <iostream>
#include <string>
extern "C" void logvar(int i, std::string name) {
std::cout << "Num: " << i << "; Name: " << name << std::endl;
}
And now, my pass.cpp is as follows:
virtual bool runOnFunction(Function &F) {
// Get the function to call from our runtime library.
LLVMContext &Ctx = F.getContext();
std::vector<Type*> paramTypes = {
Type::getInt32Ty(Ctx),
// Here I need a string type to match logvar function,
// but I don't know how to write it.
// Maybe a pointerType?
};
Type *retType = Type::getVoidTy(Ctx);
FunctionType *logFuncType = FunctionType::get(retType, paramTypes, false);
FunctionCallee logFunc =
F.getParent()->getOrInsertFunction("logvar", logFuncType);
for (auto &B : F) {
for (auto &I : B) {
if (auto *op = dyn_cast<LoadInst>(&I)) { // timo_schalachter
int number;
auto alloca = dyn_cast<AllocaInst>(op->getOperand(0));
for (auto user: alloca->users()) {
if (auto store = dyn_cast<StoreInst>(user)) {
auto constant_int = dyn_cast<ConstantInt>(store->getOperand(0));
number = constant_int->getSExtValue();
errs() << number << "\n";
}
}
}
if (auto *op = dyn_cast<StoreInst>(&I)) {
errs() << *op << ".StoreInst\n";
Value *val = op->getValueOperand();
if (auto constant_int = dyn_cast<ConstantInt>(val)) {
int number = constant_int->getSExtValue();
errs() << number << ".\n\n";
} else if (auto constant_fp = dyn_cast<ConstantFP>(val)) {
float number = constant_fp->???;
// I cannot find the function to get the value of float point here.
} // and how to deal with constant string?
// metadata:
// store i32 %4, i32* %2, align 4, !dbg !863
Value *arg1 = op->getOperand(0); // %4 = xxx
Value *arg2 = op->getOperand(1); // %2 = xxx
unsigned mk = op->getContext().getMDKindID("dbg");
MDNode *mdn = op->getMetadata(mk);
if (mdn) {
Metadata *mds = mdn->getOperand(0);
StringRef str;
if (MDString::classof(mds)) {
str = (cast<MDString>(*mds)).getString();
errs() << str;
}
} else {
errs() << "no dbg!\n";
// when I run this code, it always says: "no dbg!"
// I don't know why...
}
// instrumentation
IRBuilder<> builder(op);
builder.SetInsertPoint(&B, ++builder.GetInsertPoint());
Value* args[] = {arg1, ???};
// I cannot find the name of variable.
// I think it should be str in metadata.
// Still the problem: how to write STRING's type in LLVM?
builder.CreateCall(logFunc, args);
}
}
}
return false;
}
Problems are in code. I cannot make myself understood clearly by using English.
I think String maybe i8*. You can read this link https://llvm.org/docs/LangRef.html#function-type to get function type.
I'm writing a C-subset compiler using the LLVM C++ API, and using a pass for generating object code as well. But the object code generation step is giving segfault when the source files include an if-else block. Below are the codes I'm using
Compiler code for generating the if-else block
llvm::Value *Conditional::generateCode(CodeKit &kit) {
auto *cond = condition->generateCode(kit);
if (cond == nullptr) {
return nullptr;
}
llvm::Function *func = kit.builder.GetInsertBlock()->getParent();
auto *ifBlock = llvm::BasicBlock::Create(kit.context, "if", func);
auto *elseBlock = llvm::BasicBlock::Create(kit.context, "else");
auto *mergeBlock = llvm::BasicBlock::Create(kit.context, "ifelsemerge");
kit.builder.CreateCondBr(cond, ifBlock, elseBlock);
kit.builder.SetInsertPoint(ifBlock);
if (ifstmt != nullptr) {
kit.symbolTable.enterScope();
ifstmt->generateCode(kit);
kit.symbolTable.exitScope();
}
kit.builder.CreateBr(mergeBlock);
ifBlock = kit.builder.GetInsertBlock();
func->getBasicBlockList().push_back(elseBlock);
kit.builder.SetInsertPoint(elseBlock);
if (elsestmt != nullptr) {
kit.symbolTable.enterScope();
elsestmt->generateCode(kit);
kit.symbolTable.exitScope();
}
kit.builder.CreateBr(mergeBlock);
elseBlock = kit.builder.GetInsertBlock();
func->getBasicBlockList().push_back(mergeBlock);
kit.builder.SetInsertPoint(mergeBlock);
return nullptr;
Code for generating object code from the llvm module.
void emitCode(CodeKit &kit) {
kit.module.print(llvm::outs(), nullptr);
auto irFile = "output.bc";
error_code ec;
llvm::raw_fd_ostream irFileStream(irFile, ec, llvm::sys::fs::F_None);
llvm::WriteBitcodeToFile(kit.module, irFileStream);
irFileStream.flush();
auto targetTriple = llvm::sys::getDefaultTargetTriple();
llvm::InitializeAllTargetInfos();
llvm::InitializeAllTargets();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllAsmParsers();
llvm::InitializeAllAsmPrinters();
string error;
auto target = llvm::TargetRegistry::lookupTarget(targetTriple, error);
auto cpu = "generic";
auto features = "";
llvm::TargetOptions opt;
auto rm = llvm::Optional<llvm::Reloc::Model>();
auto targetMachine =
target->createTargetMachine(targetTriple, cpu, features, opt, rm);
kit.module.setDataLayout(targetMachine->createDataLayout());
kit.module.setTargetTriple(targetTriple);
auto objectFile = "output.o";
llvm::raw_fd_ostream objectFileStream(objectFile, ec,
llvm::sys::fs::OF_None);
llvm::legacy::PassManager pass;
auto fileType = llvm::CGFT_ObjectFile;
targetMachine->addPassesToEmitFile(pass, objectFileStream, nullptr,
fileType);
pass.run(kit.module);
objectFileStream.flush();
}
Source file on which I'm testing at the moment
int factorial(int n) {
if (n <= 0)
return 1;
else
return n * factorial(n - 1);
}
Generated IR code
; ModuleID = 'bootleg c compiler'
source_filename = "bootleg c compiler"
define i32 #factorial(i32 %n) {
entry:
%n1 = alloca i32
store i32 %n, i32* %n1
%n2 = load i32, i32* %n1
%"Less or Equal" = icmp sle i32 %n2, 0
br i1 %"Less or Equal", label %if, label %else
if: ; preds = %entry
ret i32 1
br label %ifelsemerge
else: ; preds = %entry
%n3 = load i32, i32* %n1
%n4 = load i32, i32* %n1
%Subtract = sub i32 %n4, 1
%call = call i32 #factorial(i32 %Subtract)
%Multiply = mul i32 %n3, %call
ret i32 %Multiply
br label %ifelsemerge
ifelsemerge: ; preds = %else, %if
}
GDB stack trace of the segfault
#0 0x00007ffff4386bc0 in llvm::Instruction::getNumSuccessors() const () from /lib/x86_64-linux-gnu/libLLVM-10.so.1
#1 0x00007ffff4fd643c in llvm::BranchProbabilityInfo::computePostDominatedByUnreachable(llvm::Function const&, llvm::PostDominatorTree*) ()
from /lib/x86_64-linux-gnu/libLLVM-10.so.1
#2 0x00007ffff4fdb175 in llvm::BranchProbabilityInfo::calculate(llvm::Function const&, llvm::LoopInfo const&, llvm::TargetLibraryInfo const*) ()
from /lib/x86_64-linux-gnu/libLLVM-10.so.1
#3 0x00007ffff4fdb9c4 in llvm::BranchProbabilityInfoWrapperPass::runOnFunction(llvm::Function&) () from /lib/x86_64-linux-gnu/libLLVM-10.so.1
#4 0x00007ffff43a7d76 in llvm::FPPassManager::runOnFunction(llvm::Function&) () from /lib/x86_64-linux-gnu/libLLVM-10.so.1
#5 0x00007ffff43a7ff3 in llvm::FPPassManager::runOnModule(llvm::Module&) () from /lib/x86_64-linux-gnu/libLLVM-10.so.1
#6 0x00007ffff43a84a0 in llvm::legacy::PassManagerImpl::run(llvm::Module&) () from /lib/x86_64-linux-gnu/libLLVM-10.so.1
#7 0x0000555555565b73 in emitCode (kit=...) at c.ast.cpp:88
#8 0x0000555555579957 in generateCode (ast=...) at cc.cpp:25
#9 0x0000555555579a83 in main (argc=2, argv=0x7fffffffdfe8) at cc.cpp:41
ret i32 1
br label %ifelsemerge
is invalid IR, you must have exactly one terminator instruction (e.g. br or ret) in a BasicBlock. You can avoid this by checking for a terminator instruction before inserting the branch,
if (ifBlock->size() == 0 || !ifBlock->back().isTerminator()) {
kit.builder.CreateBr(mergeBlock);
}
// ...
if (elseBlock->size() == 0 || !elseBlock->back().isTerminator()) {
kit.builder.CreateBr(mergeBlock);
}
Note that empty blocks are also invalid so in case both branches of the conditional exit the function, you probably shouldn't generate mergeBlock. AFAIK if you have no branches to an empty block it's fine to leave it in.
Usually you can catch these kinds of bugs in your front-end by adding a verification pass or using llvm::verifyFunction or llvm::verifyModule. Also running llc with the generated IR code will give a more detailed error message.
I am trying to retrieve the name of the pointer passed to a cudaMalloc call.
CallInst *CUMallocCI = ... ; // CI of cudaMalloc call
Value *Ptr = CUMallocCI->getOperand(0);
if (AllocaInst *AI = dyn_cast<AllocaInst>(Ptr) != nullptr) {
errs() << AI->getName() << "\n";
}
The above however just prints an empty line. Is is possible to get the pointer name out of this alloca?
This is the relevant IR:
%28 = alloca i8*, align 8
...
...
call void #llvm.dbg.declare(metadata i8** %28, metadata !926, metadata !DIExpression()), !dbg !927
%257 = call i32 #cudaMalloc(i8** %28, i64 1), !dbg !928
...
...
!926 = !DILocalVariable(name: "d_over", scope: !677, file: !3, line: 191, type: !22)
!927 = !DILocation(line: 191, column: 10, scope: !677)
Answering my own question. It turns out that there is an llvm.dbg.declare call (DbgDeclareInst) corresponding to the alloca but it may appear anywhere in the caller function's basic blocks. Probably it comes after the first use of this Alloca value? Not sure. In any case, my solution is to search for DbgDeclareInst instructions, check if it is for an AllocaInst and if so compare that alloca with the alloca of interest and if equal get the variable name. Something like this:
CallInst *CUMallocCI = ... ; // CI of cudaMalloc call
Value *Ptr = CUMallocCI->getOperand(0);
if (AllocaInst *AI = dyn_cast<AllocaInst>(Ptr) != nullptr) {
if ( !AI->hasName() ) {
// Function this AllocaInst belongs
Function *Caller = AI->getParent()->getParent();
// Search for llvm.dbg.declare
for ( BasicBlock& BB : *Caller)
for (Instruction &I : BB) {
if ( DbgDeclareInst *dbg = dyn_cast<DbgDeclareInst>(&I))
// found. is it for an AllocaInst?
if ( AllocaInst *dbgAI = dyn_cast<AllocaInst>(dbg->getAddress()))
// is it for our AllocaInst?
if (dbgAI == AI)
if (DILocalVariable *varMD = dbg->getVariable()) // probably not needed?
errs() << varMD->getName() << "\n";
} else {
errs() << AI->getName() << "\n";
}
}
I am pretty new with llvm and having trouble digging deep into the following IR line:
%call2 = call float bitcast (float (float, i32*)* #function to float (float, i32 addrspace(1)*)*)(float %11, i32 addrspace(1)* %arrayidx)
What I need to extract from this is line the type of the arguments of the function (i.e., (float %11, i32 addrspace(1)* %arrayidx))
I have tried the following, and played arround with ConstExpr a little as well, but cannot get to extract that addrspace(1)
for (Function::iterator block = F.begin(), blockEnd = F.end(); block != blockEnd; ++block) {
for (BasicBlock::iterator inst = block->begin(), instEnd = block->end(); inst != instEnd; ++inst) {
if (CallInst *call = dyn_cast<CallInst>(inst)) {
Function *calledFunction = call->getCalledFunction();
if (calledFunction == NULL) { // Called function is wrapped in a bitcast
Value* v = call->getCalledValue();
calledFunction = dyn_cast<Function>(v->stripPointerCasts());
FunctionType *ft = calledFunction->getFunctionType(); // This gives me the type "from" (the args without addrspace(1)
for( Function::arg_iterator arg = calledFunction->arg_begin(), marg_end = calledFunction->arg_end(); arg != marg_end ; arg++){
Type *argTy = arg->getType();
if (PointerType *ptrTy = dyn_cast<PointerType>(argTy)) {
if( ptrTy->getAddressSpace() !=0)
...
}
}
}
}
}
}
The above code gives me the types (float, i32*) and not (float, i32 addrspace(1)*)
Any help please?
The llvm ir
%call2 = call float bitcast (float (float, i32*)* #function to float (float, i32 addrspace(1)*)*)(float %11, i32 addrspace(1)* %arrayidx)
is casting function type float (float, i32*) to float (float, i32 addrspace(1)*) and calling it with argument (%11, %arrayidx).
If you want the types of argument you can check it using callInst::getArgOperand to get arguments in call instruction itself.
for (Function::iterator block = F.begin(), blockEnd = F.end(); block != blockEnd; ++block) {
for (BasicBlock::iterator inst = block->begin(), instEnd = block->end(); inst != instEnd; ++inst) {
if (CallInst *call = dyn_cast<CallInst>(inst)) {
Value *val11 = call->getArgOperand(0);
Value *valarrayIdx = call->getArgOperand(1);
Type *val11ty = val11->getType(); // this should be of float
Type *valarrayIdx = valarrayIdx->getType(); // this should be of i32 address(1)*
}
}
}
CallInst::getCalledFunction will give you the function.
For more info you can go through http://llvm.org/docs/doxygen/html/classllvm_1_1CallInst.html
I'm trying to build a compiler for my language at the moment. In my language, I want to have implicit pointer usage for objects/structs just like in Java. In the program below, I am testing out this feature. However, the program does not run as I had expected. I do not expect you guys to read through my entire compiler code because that would be a waste of time. Instead I was hoping I could explain what I intended for the program to do and you guys could spot in the llvm ir what went wrong. That way, I can adjust the compiler to generate proper llvm ir.
Flow:
[Function] Main - [Return: Int] {
-> Allocates space for structure of one i32
-> Calls createObj function and stores the returning value inside previous allocated space
-> Returns the i32 of the structure
}
[Function] createObj - [Return: struct { i32 }] {
-> Allocates space for structure of one i32
-> Calls Object function on this space (pointer really)
-> Returns this space (pointer really)
}
[Function] Object - [Return: void] {
-> Stores the i32 value of 5 inside of the struct pointer argument
}
The program is that main keeps returning some random number instead of 5. One such number is 159383856. I'm guessing that this is the decimal representation of a pointer address, but I'm not sure why it is printing out the pointer address.
; ModuleID = 'main'
%Object = type { i32 }
define i32 #main() {
entry:
%0 = call %Object* #createObj()
%o = alloca %Object*
store %Object* %0, %Object** %o
%1 = load %Object** %o
%2 = getelementptr inbounds %Object* %1, i32 0, i32 0
%3 = load i32* %2
ret i32 %3
}
define %Object* #createObj() {
entry:
%0 = alloca %Object
call void #-Object(%Object* %0)
%o = alloca %Object*
store %Object* %0, %Object** %o
%1 = load %Object** %o
ret %Object* %1
}
define void #-Object(%Object* %this) {
entry:
%0 = getelementptr inbounds %Object* %this, i32 0, i32 0
store i32 5, i32* %0
ret void
}
This llvm ir is generated from this syntax.
func () > main > (int) {
Object o = createObj();
return o.id;
}
// Create an object and returns it
func () > createObj > (Object) {
Object o = make Object < ();
return o;
}
// Object decl
tmpl Object {
int id; // Property
// This is run every time an object is created.
constructor < () {
this.id = 5;
}
}
It seems like in createObj you're returning a pointer to a stack variable which will no longer be valid after function return.
If you're doing implicit object pointers like Java at minimum you're going to need a call to a heap allocation like malloc which I don't think you have.