Adding a function call in my IR code in llvm

2019-02-01 15:44发布

问题:

Can you give me an example ,how to add a simple call of a function

foo(x); 

on my IR code with my pass in llvm?

回答1:

A simple way is to learn is to use ELLCC with Output Options as LLVM C++ API Code.

Two key notes:

  1. Make sure foo's definition is available; otherwise you need to define it firstly. Typically you need to get the prototype by using getOrInsertFunction and then use IRBuilder to insert the body for the function.

  2. Create the CallInst, an easy way is to use CallInst*IRBuilder::CreateCall(Value*, ArrayRef<Value*>, const Twine &).

Here is a segment I wrote before for llvm3.4; hope it can help.

#include "llvm/Analysis/Verifier.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/TypeBuilder.h"
#include "llvm/IR/IRBuilder.h"

using namespace llvm;

Constant* geti8StrVal(Module& M, char const* str, Twine const& name) {
  LLVMContext& ctx = getGlobalContext();
  Constant* strConstant = ConstantDataArray::getString(ctx, str);
  GlobalVariable* GVStr =
      new GlobalVariable(M, strConstant->getType(), true,
                         GlobalValue::InternalLinkage, strConstant, name);
  Constant* zero = Constant::getNullValue(IntegerType::getInt32Ty(ctx));
  Constant* indices[] = {zero, zero};
  Constant* strVal = ConstantExpr::getGetElementPtr(GVStr, indices, true);
  return strVal;
}

static Function *printf_prototype(LLVMContext &ctx, Module *mod) {

  FunctionType *printf_type =
      TypeBuilder<int(char *, ...), false>::get(getGlobalContext());

  Function *func = cast<Function>(mod->getOrInsertFunction(
      "printf", printf_type,
      AttributeSet().addAttribute(mod->getContext(), 1U, Attribute::NoAlias)));

  return func;
}

static Function *main_prototype(LLVMContext &ctx, Module *mod) {

  FunctionType *foo_type =
      TypeBuilder<int(int, char **), false>::get(getGlobalContext());
  Function *func = cast<Function>(mod->getOrInsertFunction("main", foo_type));
  /// func->setLinkage(GlobalValue::PrivateLinkage);

  return func;
}

int main(int argc, char **argv) {

  InitializeNativeTarget();

  LLVMContext &ctx = getGlobalContext();
  Module *module = new Module("example", ctx);
  /// auto module = std::make_unique<Module>("example", ctx);
  IRBuilder<> builder(ctx);
  module->setDataLayout(
      "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
      "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-"
      "a0:0:64-s0:64:64-f80:128:128");
  module->setTargetTriple("x86_64-unknown-linux-gnu");

  //
  // extern void printf(const char *fmt, ...);
  //
  Function *printf_func = printf_prototype(ctx, module);

  //
  // int foo(void)
  // {
  Function *main_fn = main_prototype(ctx, module);
  BasicBlock *block = BasicBlock::Create(ctx, "", main_fn, 0);
  builder.SetInsertPoint(block);

  //
  // int32_t temp = 15 + ...
  //
  Constant *left = ConstantInt::get(ctx, APInt(32, 15));

  AllocaInst *allocaInst =
      builder.CreateAlloca(TypeBuilder<int, false>::get(getGlobalContext()));
  SmallVector<Value *, 4> addsVect;
  for (Argument &arg : main_fn->getArgumentList()) {
    addsVect.push_back(&arg);
  }
  builder.CreateStore(addsVect[0], allocaInst);
  LoadInst *loadInst = builder.CreateLoad(allocaInst);

  Value *add = builder.CreateAdd(left, loadInst);
  /// add->getType()->dump();
  /// errs() << "\n";

  //
  // printf("%d\n", temp);
  //

  Constant *nullValue = Constant::getNullValue(add->getType());
  ///
  builder.CreateICmpEQ(add, nullValue);
  builder.CreateICmpNE(add, nullValue);
  ///
  Value *cmpResult = builder.CreateICmpUGT(add, nullValue);
  builder.CreateICmpUGE(add, nullValue);
  builder.CreateICmpULT(add, nullValue);
  builder.CreateICmpULE(add, nullValue);
  ///
  builder.CreateICmpSGT(add, nullValue);
  builder.CreateICmpSGE(add, nullValue);
  builder.CreateICmpSLT(add, nullValue);
  builder.CreateICmpSLE(add, nullValue);
  ///

  BasicBlock *br_true = BasicBlock::Create(ctx, "br_true", main_fn, 0);
  BasicBlock *br_false = BasicBlock::Create(ctx, "br_false", main_fn, 0);

  builder.CreateCondBr(cmpResult, br_true, br_false);

  builder.SetInsertPoint(br_false);
  builder.CreateCall2(printf_func, utils::geti8StrVal(*module, "%d\n"), add);

  SmallVector<Value *, 4> assertArgs;
  assertArgs.push_back(utils::geti8StrVal(*module, "__assert_fail"));
  assertArgs.push_back(utils::geti8StrVal(*module, __FILE__));
  /// assertArgs.push_back(
  ///     ConstantInt::get(TypeBuilder<int, false>::get(ctx), __LINE__, false));
  assertArgs.push_back(add);
  assertArgs.push_back(utils::geti8StrVal(*module, __FUNCTION__));
  Function *assertFunc = utils::getFn_assert(*module);
  /// errs() << *assertFunc;
  builder.CreateCall(assertFunc, assertArgs);

  /// builder.CreateBr(br_true);

  ConstantInt *zero = ConstantInt::get(IntegerType::getInt32Ty(ctx), 0);
  builder.CreateRet(zero);

  //
  // return 0;
  // }
  //
  builder.SetInsertPoint(br_true);
  builder.CreateRet(zero);
}