LLVM how to map custom function call to printf - c++

I just started with LLVM. I am using C++ to create a compiler for Pascal-like language. Given that print functions are system calls, how do I map from my language writeln(5) to the system function printf ("%d",5)? I thought that code below should do it.
NamedValues.clear();
vector<Type *> Doubles(1, Type::getInt32Ty(TheContext));
FunctionType * FT = FunctionType::get(Type::getInt32Ty(TheContext), Doubles, false);
Function * function = Function::Create(FT, Function::ExternalLinkage, "writeln", TheModule.get());
// create function body
BasicBlock * BB = BasicBlock::Create(TheContext, "entry", function);
Builder.SetInsertPoint(BB);
// get param
Function::arg_iterator AI = function->arg_begin();
Value * val = AI;
AI->setName("val");
// get format string
string format = "%d";
Constant * ConstStr = ConstantDataArray::getString(TheContext, format.c_str());
ConstStr = new GlobalVariable(*TheModule, ConstStr->getType(), true, GlobalValue::InternalLinkage, ConstStr, format);
Constant * Idxs[] = {ConstantInt::get(Type::getInt32Ty(TheContext), 0), 0};
Idxs[1] = Idxs[0];
// make params
vector<Type *> params;
params.push_back(PointerType::getUnqual(Type::getInt8Ty(TheContext)));
// get printf function
FunctionCallee PrintF = TheModule->getOrInsertFunction("printf", FunctionType::get(Type::getVoidTy(TheContext), params, true));
// call
/*
* CallInst *CreateCall(FunctionCallee Callee, ArrayRef<Value *> Args = None,
const Twine &Name = "", MDNode *FPMathTag = nullptr)
*/
Builder.CreateCall(PrintF.getFunctionType(), ConstantExpr::getGetElementPtr(ConstStr->getType(), ConstStr, Idxs), val);
Builder.CreateRet(Builder.getInt32(0));
main_loop();
Error I got:
Assertion failed: (Ty == cast<PointerType>(C->getType()->getScalarType())->getElementType()), function getGetElementPtr, file /Users/ustynov/Documents/Study/HOMEWORKS/semestralwork/llvm/lib/IR/Constants.cpp, line 2012.

Related

How can I pass array to LLVM IR Function arguments and get value by index

I want to pass an array to LLVM IR Function, and get value by index. The code as follows, but it dont't work.
Function *FooF =
Function::Create(FunctionType::get(Type::getInt32Ty(Context), {ArrayType::getInt32PtrTy(Context), Type::getInt32Ty(Context)}, false),
Function::ExternalLinkage, "foo", M);
// Add a basic block to the FooF function.
BasicBlock *BB = BasicBlock::Create(Context, "EntryBlock", FooF);
IRBuilder<> builder(BB);
// Get pointer to array
Value *arg1 = FooF->arg_begin();
// Get index
Value *index = arg1+1;
// Get first_element
Value *first_element = builder.CreateExtractElement(arg1, index);
builder.CreateRet(first_element);
// Now we create the JIT.
ExecutionEngine* EE = EngineBuilder(std::move(Owner)).create();
using FunctionPtr = int(*)(int32_t *, int);
FunctionPtr func = reinterpret_cast<FunctionPtr>(EE->getFunctionAddress("foo")) ;
int32_t array[3] = {1,2,3};
int first = func(array, 0);
}

something wrong when I declare an int64 global variable in llvm

I'm trying using llvm to build my own dsl.
Here I meet a strange problem when I'm using VS2017 win32 mode.
I defined a int64 global variable in one module with value 3 by external linkage.
Then when I declare this variable in another module and load it's value, I got 12884901891(same as 0x300000003). When I try this on Linux, it works well.
Hope someone can help me.
Blow is my code.CJITEngine is a simple singleton package.
PS. If I define the global variable with other type rather than int64, such as int32,float,double, this code can run well.
int main()
{
CJITEngine::Instance().Init();
DataLayout &layout = CJITEngine::Instance().GetDataLayout();
using fpType = void(*)(int64_t*);
fpType fp = nullptr;
string name("aaaaaaaa");
{
unique_ptr<Module> pModule = CJITEngine::Instance().CreateModule("module1");
IRBuilder<>& m_oBuilder = CJITEngine::Instance().GetIRBuilder();
Type* pType = m_oBuilder.getInt64Ty();
GlobalVariable* pVarValue = new GlobalVariable(*pModule, pType, false, GlobalValue::ExternalLinkage,
m_oBuilder.getInt64(3), name);
pVarValue->setAlignment(layout.getABITypeAlignment(pType));
pVarValue->setDSOLocal(true);
pModule->addModuleFlag(Module::Error, "NumRegisterParameters", m_oBuilder.getInt32(0));
pModule->addModuleFlag(Module::Error, "wchar_size", m_oBuilder.getInt32(2));
pModule->print(outs(), nullptr);
std::cout << "--------------------------------------------------------" << std::endl;
CJITEngine::Instance().AddModule(std::move(pModule));
}
/////////////////////////////////////////////////////////
{
unique_ptr<Module> pModule = CJITEngine::Instance().CreateModule("module2");
LLVMContext& m_oContext = CJITEngine::Instance().GetContext();
IRBuilder<>& m_oBuilder = CJITEngine::Instance().GetIRBuilder();
Type* pType = m_oBuilder.getInt64Ty();
GlobalVariable* pVarValue = new GlobalVariable(*pModule, pType, false, GlobalValue::ExternalLinkage,
nullptr, name);
pVarValue->setAlignment(layout.getABITypeAlignment(pType));
pVarValue->setDSOLocal(true);
FunctionType* pFuncType = FunctionType::get(m_oBuilder.getVoidTy(), {Type::getInt64PtrTy(m_oContext)}, false);
Function* pFunc = Function::Create(pFuncType, Function::ExternalLinkage, "func", pModule.get());
pFunc->setDSOLocal(true);
BasicBlock* pEntryBlock = BasicBlock::Create(m_oContext, "entry", pFunc);
BasicBlock* pExitBlock = BasicBlock::Create(m_oContext, "exit");
m_oBuilder.SetInsertPoint(pEntryBlock);
auto agr = pFunc->args().begin();
AllocaInst* pParam = m_oBuilder.CreateAlloca(agr->getType());
pParam->setAlignment(layout.getABITypeAlignment(Type::getInt64PtrTy(m_oContext)));
m_oBuilder.CreateAlignedStore(agr, pParam, layout.getABITypeAlignment(Type::getInt64PtrTy(m_oContext)));
Value* pStr = m_oBuilder.CreateAlignedLoad(pVarValue, layout.getABITypeAlignment(Type::getInt64Ty(m_oContext)));
Value* ppp= m_oBuilder.CreateAlignedLoad(pParam, layout.getABITypeAlignment(Type::getInt64PtrTy(m_oContext)));
m_oBuilder.CreateAlignedStore(pStr, ppp, layout.getABITypeAlignment(Type::getInt64Ty(m_oContext)));
m_oBuilder.CreateRetVoid();
pModule->addModuleFlag(Module::Error, "NumRegisterParameters", m_oBuilder.getInt32(0));
pModule->addModuleFlag(Module::Error, "wchar_size", m_oBuilder.getInt32(2));
pModule->print(outs(), nullptr);
CJITEngine::Instance().AddModule(std::move(pModule));
JITSymbol symbol = CJITEngine::Instance().FindSymbol("func");
fp = (fpType)static_cast<intptr_t>(cantFail(symbol.getAddress()));
int64_t x = 10;
fp(&x);
std::cout << hex << x << endl; // x is 0x300000003 here
}
return 0;
}

memory allocate functions in llvm

How to detect malloc and free function calls in a llvm pass and replace it with a new function calls by getting the arguments and return type in llvm?
i.e. Is there a way to create new functions (Malloc and free) and then create function calls whenever Malloc and free are detected?
1.Create malloc and free
Type *BPTy = PointerType::getUnqual(Type::getInt8Ty(M.getContext()));
FunctionType *malloc_Fty = FunctionType::get(BPTy, llvm::ArrayRef<Type*>(), true);
Function *malloc_func = cast<Function>(M.getOrInsertFunction("malloc", malloc_Fty));
FunctionType *free_Fty = FunctionType::get(Type::getVoidTy(M.getContext()), BPTy, false);
Function *free_func = cast<Function>(M.getOrInsertFunction("free",free_Fty));
2. Detect malloc and free and replace it with new malloc and free function calls
if(CallInst *CI = dyn_cast<CallInst>(I)) {
Function *Callee = CI->getCalledFunction();
if (Callee->getName() == "malloc") {
FunctionType *Ty = Callee->getFunctionType();
PointerType *PtrTy = dyn_cast<PointerType>(Ty);
Type *AllocTy = PtrTy->getElementType();
const DataLayout &DL = M.getDataLayout();
Type *IntPtrTy = DL.getIntPtrType(M.getContext());
Value *mallocArgs;
mallocArgs = ConstantExpr::getSizeOf(AllocTy);
mallocArgs = ConstantExpr::getTruncOrBitCast(cast<Constant>(mallocArgs), IntPtrTy);
if (const AllocaInst *AI = dyn_cast<AllocaInst>(&*I)) {
if (AI->isArrayAllocation()) {
if (isa<ConstantInt>(mallocArgs) && cast<ConstantInt>(mallocArgs)->isOne()) {
mallocArgs = I->getOperand(0);
} else if (Constant *CO = dyn_cast<Constant>(I->getOperand(0))) {
CO = ConstantExpr::getIntegerCast(CO, IntPtrTy, false );
mallocArgs = ConstantExpr::getMul(CO, cast<Constant>(mallocArgs));
} else {
Value *Scale = I->getOperand(0);
if (Scale->getType() != IntPtrTy)
Scale = CastInst::CreateIntegerCast(Scale, IntPtrTy, false,"", &*I);
// Multiply it by the array size if necessary...
mallocArgs =BinaryOperator::Create(Instruction::Mul, Scale, mallocArgs, "", &*I);
}
}
}
// Create the call to malloc
CallInst *malloc_Call = CallInst::Create(malloc_func, mallocArgs, "", &*I);
// Cast the instruction to convert to the correct type
Value *malloc_PtrCast;
Type * voidty=Type::getVoidTy (M.getContext());
if (malloc_Call->getType() !=voidty )
malloc_PtrCast = new BitCastInst(malloc_Call, I->getType(), "", &*I);
else
malloc_PtrCast = Constant::getNullValue(I->getType());
Instruction *II=dyn_cast<Instruction>(&*I);
II->replaceAllUsesWith(malloc_PtrCast);
}
if (Callee->getName() == "free") {
Value *free_PtrCast =
new BitCastInst(I->getOperand(0), PointerType::getUnqual(Type::getInt8Ty(M.getContext())), "", &*I);
// Create the call to free function
CallInst::Create(free_func, free_PtrCast, "", &*I);
Instruction *II=dyn_cast<Instruction>(&*I);
II->replaceAllUsesWith(free_PtrCast);
}
}
3. Example on which I am testing
void* ptr;
void malloc_func()
{
ptr = malloc(512);
}
void free_func()
{
free(ptr);
}
But, I am getting segmentation fault, is this the correct way to replace malloc and free function calls with the new functions?

llvm createCall Calling a function with a bad signature

I want to make a function in LLVM which is an adapter with only a function call foo(idx, mn). The function prototype of foo is void foo(unsigned char, const char*).
// adapter Function with only a function call foo(idx, mn)
llvm::Function* createCallFun(llvm::Module* M, llvm::Function* exit_f) {
llvm::LLVMContext& Ctx = M->getContext();
llvm::Function* foo_f = foo_prototype(Ctx, M);
llvm::Constant* c = M->getOrInsertFunction("__call_fun", FunctionType::getVoidTy(Ctx), llvm::Type::getInt32Ty(Ctx), llvm::Type::getInt32Ty(Ctx), NULL);
llvm::Function* call_fun_f = llvm::cast<llvm::Function>(c);
llvm::BasicBlock* entry = llvm::BasicBlock::Create(llvm::getGlobalContext(), "entry", call_fun_f);
llvm::IRBuilder<> builder(entry);
llvm::Function::arg_iterator args = call_fun_f->arg_begin();
llvm::Value* idx = &*args++;
idx->setName("idx");
llvm::Value* mn = &*args++;
mn->setName("mn");
llvm::Value* greater = builder.CreateICmpSGE(idx, mn, "tmp");
std::vector<llvm::Value*> fun_args;
fun_args.push_back(greater);
fun_args.push_back(err_msg);
builder.CreateCall(foo_f, fun_args);
return call_fun_f;
}
Then I got this error:
lib/IR/Instructions.cpp:245: void llvm::CallInst::init(llvm::FunctionType*, llvm::Value*, llvm::ArrayRef, llvm::ArrayRef >, const llvm::Twine&): Assertion `(i >= FTy->getNumParams() || FTy->getParamType(i) == Args[i]->getType()) && "Calling a function with a bad signature!"' failed.
It seems the first argument of foo has a type mismatch. How can I cast the Value greater to unsigned char type?
I fixed this error by cast greater with CreateZExt.
llvm::Value *castuchar =
builder.CreateZExt(greater, llvm::Type::getInt8Ty(Ctx), "tmp1");

LLVM: Creating a CallInst with a null pointer operand

I'm trying to use the LLVM C++ bindings to write a pass which generates the following IR
%1 = call i64 #time(i64* null) #3
#time here is the C standard library time() function.
Here's the code I've written
void Pass::Insert(BasicBlock *bb, Type *timety, Module *m) {
Type *timetype[1];
timetype[0] = timety;
ArrayRef<Type *> timeTypeAref(timetype, 1);
Value *args[1];
args[0] = ConstantInt::get(timety, 0, false);
ArrayRef<Value *> argsRef(args, 1);
FunctionType *signature = FunctionType::get(timety, false);
Function *timeFunc =
Function::Create(signature, Function::ExternalLinkage, "time", m);
IRBuilder<> Builder(&*(bb->getFirstInsertionPt()));
AllocaInst *a1 = Builder.CreateAlloca(timety, nullptr, Twine("a1"));
CallInst *c1 = Builder.CreateCall(timeFunc, args, Twine("time"));
}
This compiles, but results in the following error when run
Incorrect number of arguments passed to called function!
%time = call i64 #time(i64 0)
As I understand this, I need to pass an int64 pointer which deferences to nullptr, but I'm unable to figure out how to do that.
LLVM provides a ConstantPointerNull class which does exactly what I want - it returns a null pointer of the required type.
All that needs to be changed is the line beginning with args[0] = ... to
args[0] = ConstantPointerNull::get(PointerType::get(timety, 0));.