Skip to content

Instantly share code, notes, and snippets.

@caphosra
Last active April 15, 2021 08:54
Show Gist options
  • Save caphosra/9cd38e8658bb2d07cb9306b73435fada to your computer and use it in GitHub Desktop.
Save caphosra/9cd38e8658bb2d07cb9306b73435fada to your computer and use it in GitHub Desktop.
[LLVM, C++] Print the answer of the sum of two float values
#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);
}
; 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*, ...)
@caphosra
Copy link
Author

caphosra commented Apr 9, 2020

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment