Clang, LLVM tools

Рассмотрим исходник.

#include <stdio.h>

int main() {
    printf("hello");
    return 0;
}

Вот что мы можем с ним сделать:

.PHONY: byte-code interpret assembler code-generator native compile run

help:
	@echo "tagets: byte-code interpret assembler code-generator native compile run help"

compile:
	clang hello.c -o hello

byte-code:
	clang -O0 -emit-llvm hello.c -c -o hello.bc

assembler:
	llvm-dis-mp-3.2 < hello.bc | less

code-generator:
	llc-mp-3.2 -disable-cfi hello.bc -o hello.s

native:
	gcc hello.s -o hello.native

run:
	./hello

interpret:
	lli-mp-3.2 hello.bc

Кодогенерация

one

Научимся генерировать код для функции

double one()
{
    return 1.0;
}

При помощи llvm это делается следующим образом:

#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/IRBuilder.h"
#include <vector>

int main(int argc, const char* argv[])
{
    using namespace llvm;

    IRBuilder<> builder(getGlobalContext());
    Module* theModule = new Module("module.1", getGlobalContext());

    std::vector<Type*> noParams;
    FunctionType* functionType =
        FunctionType::get(Type::getDoubleTy(getGlobalContext()), noParams, false);
    Function* function =
        Function::Create(functionType, Function::ExternalLinkage, "one", theModule);

    BasicBlock* bb = BasicBlock::Create(getGlobalContext(), "entry", function);
    builder.SetInsertPoint(bb);
    Value* d = ConstantFP::get(getGlobalContext(), APFloat(1.0));
    builder.CreateRet(d);

    verifyFunction(*function);

    theModule->dump();

    return 0;
}

И собирается так:

.PHONY: build

build:
	 g++ -o one `llvm-config-mp-3.2 --cppflags --ldflags --libs core` one.cpp

Если запустить получившийся исполняемый файл, то на экран выведется

; ModuleID = 'module.1'

define double @one() {
entry:
  ret double 1.000000e+00
}

inc

Теперь рассмотрим более интересную функцию:

double inc(double x)
{
    return x + 1.0;
}

Код генерируем так:

#include "llvm/DerivedTypes.h"
#include "llvm/BasicBlock.h"
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/IRBuilder.h"
#include <string>
#include <vector>
#include <iostream>

int main(int argc, const char* argv[])
{
    using namespace llvm;

    IRBuilder<> builder(getGlobalContext());
    Module* module = new Module("module.1", getGlobalContext());

    std::vector<Type*> doubles(1, Type::getDoubleTy(getGlobalContext()));
    FunctionType* functionType =
        FunctionType::get(Type::getDoubleTy(getGlobalContext()), doubles, false);
    Function* function =
        Function::Create(functionType, Function::ExternalLinkage, "inc", module);
    function->arg_begin()->setName("x");

    BasicBlock* bb = BasicBlock::Create(getGlobalContext(), "entry", function);
    builder.SetInsertPoint(bb);
    Value* d = ConstantFP::get(getGlobalContext(), APFloat(1.0));
    Value* inc = builder.CreateFAdd(function->arg_begin(), d, "addtmp");
    builder.CreateRet(inc);

    verifyFunction(*function);

    verifyModule(*module);

    module->dump();

    return 0;
}

Makefile:

.PHONY: build

build:
	 g++ -o inc `llvm-config-mp-3.2 --cppflags --ldflags --libs core` inc.cpp

Результат запуска ./inc:

; ModuleID = 'module.1'

define double @inc(double %x) {
entry:
  %addtmp = fadd double %x, 1.000000e+00
  ret double %addtmp
}

Ссылки на документацию

Домашнее задание

Его нет. Празднуем начало весны.