Last active
April 15, 2021 08:54
-
-
Save caphosra/9cd38e8658bb2d07cb9306b73435fada to your computer and use it in GitHub Desktop.
[LLVM, C++] Print the answer of the sum of two float values
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <fstream> | |
#include <memory> | |
#include <vector> | |
#include "llvm/ADT/APInt.h" | |
#include "llvm/ADT/APFloat.h" | |
#include "llvm/ADT/STLExtras.h" | |
#include "llvm/IR/BasicBlock.h" | |
#include "llvm/IR/Constants.h" | |
#include "llvm/IR/DerivedTypes.h" | |
#include "llvm/IR/Function.h" | |
#include "llvm/IR/IRBuilder.h" | |
#include "llvm/IR/LLVMContext.h" | |
#include "llvm/IR/Module.h" | |
#include "llvm/IR/Type.h" | |
#include "llvm/IR/Verifier.h" | |
using namespace std; | |
llvm::LLVMContext context; | |
llvm::IRBuilder<> Builder(context); | |
llvm::Module* module; | |
#define LLVM_INT8_PTR_TY llvm::Type::getInt8PtrTy(context) | |
#define LLVM_INT32_TY llvm::Type::getInt32Ty(context) | |
#define LLVM_FLOAT_TY llvm::Type::getFloatTy(context) | |
#define LLVM_DOUBLE_TY llvm::Type::getDoubleTy(context) | |
int main() { | |
module = new llvm::Module("test.ll", context); | |
// | |
// Define main. | |
// | |
std::vector<llvm::Type*> mainFuncArgs; | |
auto mainFuncType = llvm::FunctionType::get( | |
LLVM_INT32_TY, | |
mainFuncArgs, | |
false | |
); | |
auto mainFunc = llvm::Function::Create(mainFuncType, llvm::GlobalValue::ExternalLinkage, "main", module); | |
mainFunc->setCallingConv(llvm::CallingConv::C); | |
// | |
// Define printf. | |
// | |
std::vector<llvm::Type*> printfFuncArgs; | |
printfFuncArgs.push_back(LLVM_INT8_PTR_TY); | |
auto printfFuncType = llvm::FunctionType::get( | |
LLVM_INT32_TY, | |
printfFuncArgs, | |
true | |
); | |
auto printfFunc = llvm::Function::Create(printfFuncType, llvm::GlobalValue::ExternalLinkage, "printf", module); | |
printfFunc->setCallingConv(llvm::CallingConv::C); | |
// | |
// Create a basic block which will put into main. | |
// | |
auto mainBlock = llvm::BasicBlock::Create(context, "entry", module->getFunction("main")); | |
Builder.SetInsertPoint(mainBlock); | |
// | |
// Allocate memories whose size equals to that of a float value. | |
// | |
auto f1PtrVal = Builder.CreateAlloca(LLVM_FLOAT_TY, llvm::ConstantInt::get(LLVM_INT32_TY, 1)); | |
Builder.CreateStore(llvm::ConstantFP::get(LLVM_FLOAT_TY, 3.5), f1PtrVal); | |
auto f2PtrVal = Builder.CreateAlloca(LLVM_FLOAT_TY, llvm::ConstantInt::get(LLVM_INT32_TY, 1)); | |
Builder.CreateStore(llvm::ConstantFP::get(LLVM_FLOAT_TY, 6.4), f2PtrVal); | |
// | |
// Add them. | |
// | |
auto f1Val= Builder.CreateLoad(f1PtrVal); | |
auto f2Val = Builder.CreateLoad(f2PtrVal); | |
auto calcVal = Builder.CreateFAdd(f1Val, f2Val); | |
// | |
// Create a constant text. | |
// | |
auto formatVal = Builder.CreateGlobalStringPtr("%f + %f = %f\n"); | |
// | |
// Call printf. | |
// | |
std::vector<llvm::Value*> callArgs; | |
callArgs.push_back(formatVal); | |
callArgs.push_back(Builder.CreateFPExt(f1Val, LLVM_FLOAT_TY)); | |
callArgs.push_back(Builder.CreateFPExt(f2Val, LLVM_DOUBLE_TY)); | |
callArgs.push_back(Builder.CreateFPExt(calcVal, LLVM_DOUBLE_TY)); | |
Builder.CreateCall(printfFunc, callArgs); | |
// | |
// Finish main. | |
// | |
Builder.CreateRet(llvm::Constant::getNullValue(LLVM_INT32_TY)); | |
// | |
// Verify the module. | |
// | |
llvm::verifyModule(*module); | |
// | |
// Emit all as LLVM IR. | |
// | |
std::error_code errorcode; | |
auto stream = new llvm::raw_fd_ostream("test.ll", errorcode); | |
module->print(*stream, nullptr); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; ModuleID = 'test.ll' | |
source_filename = "test.ll" | |
@0 = private unnamed_addr constant [14 x i8] c"%f + %f = %f\0A\00", align 1 | |
define i32 @main() { | |
entry: | |
%0 = alloca float | |
store float 3.500000e+00, float* %0 | |
%1 = alloca float | |
store float 0x40199999A0000000, float* %1 | |
%2 = load float, float* %0 | |
%3 = load float, float* %1 | |
%4 = fadd float %2, %3 | |
%5 = fpext float %3 to double | |
%6 = fpext float %4 to double | |
%7 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @0, i32 0, i32 0), float %2, double %5, double %6) | |
ret i32 0 | |
} | |
declare i32 @printf(i8*, ...) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I describe how it works on https://capra314cabra.github.io/en/posts/2020-04-09-llvm-printf-float/ .