Skip to content

Instantly share code, notes, and snippets.

@MaxXSoft
Last active March 10, 2019 08:03
Show Gist options
  • Save MaxXSoft/fd3bcb1b3901861268564da90023ab56 to your computer and use it in GitHub Desktop.
Save MaxXSoft/fd3bcb1b3901861268564da90023ab56 to your computer and use it in GitHub Desktop.
Generate a simple program to object file using LLVM.
/*
generate a simple program to object file using LLVM
int main(int argc, const char *argv[]) {
if (argc == 2) {
puts(argv[1]);
}
return 0;
}
*/
#include <memory>
#include <system_error>
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Transforms/Utils.h"
#include "llvm/Transforms/InstCombine/InstCombine.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Scalar/GVN.h"
using namespace llvm;
void InitTarget() {
// initialize target registry
InitializeAllTargetInfos();
InitializeAllTargets();
InitializeAllTargetMCs();
InitializeAllAsmParsers();
InitializeAllAsmPrinters();
}
bool Compile(Module *module, const char *filename) {
// initialize target triple
std::string target_error;
auto target_tri = sys::getDefaultTargetTriple();
module->setTargetTriple(target_tri);
// lookup target in target registry
auto target = TargetRegistry::lookupTarget(target_tri, target_error);
if (!target) {
errs() << target_error << '\n';
return false;
}
// initialize target machine
TargetOptions opt;
auto rm = Optional<Reloc::Model>();
auto machine = target->createTargetMachine(target_tri, "generic", "", opt, rm);
module->setDataLayout(machine->createDataLayout());
// open object file
std::error_code ec;
raw_fd_ostream dest(filename, ec, sys::fs::F_None);
if (ec) {
errs() << "could not open file '" << filename << "': " << ec.message() << "\n";
return false;
}
// compile to object file
legacy::PassManager pass;
auto file_type = TargetMachine::CGFT_ObjectFile;
if (machine->addPassesToEmitFile(pass, dest, nullptr, file_type)) {
errs() << "target machine cannot emit file of this type\n";
return false;
}
pass.run(*module);
dest.flush();
return true;
}
auto InitFPM(Module *module) {
auto fpm = std::make_unique<legacy::FunctionPassManager>(module);
// allocas to registers
fpm->add(createPromoteMemoryToRegisterPass());
// peephole optimizations
fpm->add(createInstructionCombiningPass());
// reassociate expressions
fpm->add(createReassociatePass());
// eliminate common sub-expressions
fpm->add(createGVNPass());
// simplify the control flow graph
fpm->add(createCFGSimplificationPass());
fpm->doInitialization();
return fpm;
}
int main(int argc, const char *argv[]) {
// create context, builder, top module and pass manager
LLVMContext context;
IRBuilder<> builder(context);
auto module = std::make_unique<Module>("test module", context);
auto fpm = InitFPM(module.get());
// declare 'puts' function
Type *puts_arg_ty[] = {builder.getInt8PtrTy()};
auto puts_type = FunctionType::get(builder.getInt32Ty(), puts_arg_ty, false);
auto puts_func = module->getOrInsertFunction("puts", puts_type);
// create main function declaration
// int main(int argc, char **argv)
Type *main_arg_ty[] = {builder.getInt32Ty(), builder.getInt8PtrTy()->getPointerTo()};
auto main_type = FunctionType::get(builder.getInt32Ty(), main_arg_ty, false);
auto main_func = Function::Create(main_type, Function::ExternalLinkage, "main", module.get());
// create entry block for function
auto entry = BasicBlock::Create(context, "entry", main_func);
builder.SetInsertPoint(entry);
// generate contidion
// argc == 2
auto cond = builder.CreateICmpEQ(main_func->arg_begin(), builder.getInt32(2));
// generate blocks of 'if'
// if (cond) { then_block }
auto then_block = BasicBlock::Create(context, "then", main_func);
auto merge_block = BasicBlock::Create(context, "merge");
builder.CreateCondBr(cond, then_block, merge_block);
// generate code in 'then' block
// puts(argv[1])
builder.SetInsertPoint(then_block);
auto str_ptr = builder.CreateGEP(main_func->arg_begin() + 1, builder.getInt32(1));
auto str = builder.CreateLoad(str_ptr);
builder.CreateCall(puts_func, str);
builder.CreateBr(merge_block);
// generate 'merge' block
main_func->getBasicBlockList().push_back(merge_block);
builder.SetInsertPoint(merge_block);
// generate return
// return 0
builder.CreateRet(builder.getInt32(0));
// optimize function
fpm->run(*main_func);
// dump generated IR
module->print(errs(), nullptr);
// compile to object
if (argc == 2) {
InitTarget();
Compile(module.get(), argv[1]);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment