Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

llvm - How to implement print function in my language?

Tags:

c++

llvm

I'm following llvm's tutorial for their own simple programming language "Kaleidoscope" and there's an obvious functionality in my language which this tutorial doesn't seem to cover. I simply want to print any double to standard output pretty much as C++ would do:

std::cout << 5.0;

my language would do something like

print(5.0);

Third chapter of llvm's tutorial covers function calls. The code they use is:

Value *CallExprAST::codegen() {
  // Look up the name in the global module table.
  Function *CalleeF = TheModule->getFunction(Callee);
  if (!CalleeF)
    return ErrorV("Unknown function referenced");

  // If argument mismatch error.
  if (CalleeF->arg_size() != Args.size())
    return ErrorV("Incorrect # arguments passed");

  std::vector<Value *> ArgsV;
  for (unsigned i = 0, e = Args.size(); i != e; ++i) {
    ArgsV.push_back(Args[i]->codegen());
    if (!ArgsV.back())
      return nullptr;
  }

  return Builder.CreateCall(CalleeF, ArgsV, "calltmp");
}

How could I implement codegen() method for specific function call print(any fp number)?

like image 408
Saraph Avatar asked Feb 20 '16 16:02

Saraph


People also ask

Which programming languages use LLVM?

LLVM currently supports compiling of Ada, C, C++, D, Delphi, Fortran, Haskell, Julia, Objective-C, Rust, and Swift using various front ends. Widespread interest in LLVM has led to several efforts to develop new front ends for a variety of languages.

What is NSW in LLVM?

• nsw – no signed wrap for add, sub, mul, shl. • nuw – no unsigned wrap for add, sub, mul, shl. • exact – no remainder for sdiv, udiv, lshr, ashr.

What is LLVM in Rust?

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies, with a primary focus on these two compilers: The LLVM back-end compiler and core libraries provide a modern source- and target-independent optimizer, along with code generation support for the RHEL CPU architectures.


2 Answers

below is the llvm ir code generated for printf("%f", a); using clang. printf signature is int printf(const char*, ...);

@.str = private unnamed_addr constant [3 x i8] c"%f\00", align 1

; Function Attrs: nounwind uwtable
define i32 @main() #0 {
%a = alloca double, align 8
%1 = load double* %a, align 8
%2 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([3 x i8]*  @.str, i32 0, i32 0), double %1)
ret i32 0
}

declare i32 @printf(i8*, ...) #1

to implement in codegen you first need to check if the function is already present in module or not. if not then you need to add the declaration, you can do both in one call.

Function *CalleeF = TheModule->getOrInsertFunction("printf",
                                                   FunctionType::get(IntegerType::getInt32Ty(Context), PointerType::get(Type::getInt8Ty(Context), 0), true /* this is var arg func type*/) 
                                                   );

above will get or add you the handle to function declaration

 declare i32 @printf(i8*, ...) #1

then you can call function via matching params.

 std::vector<Value *> ArgsV;
 for (unsigned i = 0, e = Args.size(); i != e; ++i) 
   ArgsV.push_back(Args[i]->codegen());

return Builder.CreateCall(CalleeF, ArgsV, "printfCall");
like image 172
Chirag Patel Avatar answered Sep 21 '22 00:09

Chirag Patel


You'd first check if Callee == "print" and then insert any instructions you want.

LLVM IR has no concept of "printing" since that's not really a language consideration -- it's a facility provided by the OS. Probably the simplest option for you would be to translate the call into a call to printf, so that e.g. print(5.0) becomes printf("%f\n", 5.0).

The tutorial you linked does show how external function calls work -- you'd have to insert a declaration for printf with the correct signature, then build a call to that.

like image 40
Ismail Badawi Avatar answered Sep 19 '22 00:09

Ismail Badawi