llvm用法

  • 为什么用llvm::make_unique?
make_unique是C++14中才加入的,C++11中只有make_shared

循环优化

  • 把循环不变式的计算移到循环外部
  • 消除额外的归纳变量

循环不变量代码外移的过程:

	FOR index := 1 TO 10000 DO	          t := y * z
	BEGIN				                  FOR index := 1 TO 10000 DO
		x := y * z ;		              BEGIN
		j := index * 3 ;          -->		  x := t
	END					                      j := index * 3
	.				                      END
--------------------- 
原文:https://blog.csdn.net/qq_29674357/article/details/78564033 

尾调用优化

概念:某个函数的最后一步是调用另一个函数。

function f(x){
  return g(x);
}

以下两种情况,都不属于尾调用。

// 情况一:调用函数g之后,还有别的操作,所以不属于尾调用,即使语义完全一样
function f(x){
  let y = g(x);
  return y;   
}

// 情况二:也属于调用后还有操作,即使写在一行内。
function f(x){
  return g(x) + 1;		
}

尾调用由于是函数的最后一步操作,所以不需要保留外层函数的调用记录,因为调用位置、内部变量等信息都不会再用到了,只要直接用内层函数的调用记录,取代外层函数的调用记录就可以了。

  • 针对尾递归的情况
    递归非常耗费内存,因为需要同时保存成千上百个调用记录,很容易发生"栈溢出"错误(stack overflow)。但对于尾递归来说,由于只存在一个调用记录,所以永远不会发生"栈溢出"错误。
    比较两段求斐波那契数列的函数:

function factorial(n) {
  if (n === 1) return 1;
  return n * factorial(n - 1);
}

factorial(5) // 120
function factorial(n, total) {
  if (n === 1) return total;
  return factorial(n - 1, n * total);
}

factorial(5, 1) // 120

SSA

https://blog.csdn.net/qq_29674357/article/details/78731713

  • 为什么要使用 SSA ?
    第一,可以简化很多编译优化方法的过程;第二,对很多编译优化方法来说,可以获得更好的优化结果。
    https://wiki.aalto.fi/display/t1065450/LLVM+SSA 介绍llvm IR例子

LLVM Type

  • @ and % in LLVM
    Global identifiers (functions, global variables) begin with the ‘@’ character. Local identifiers (register names, types) begin with the ‘%’ character.
  • Function Type
    The function type can be thought of as a function signature. It consists of a return type and a list of formal parameter types. The return type of a function type is a void type or first class type — except for label and metadata types.
    Syntax:
    ()
    Examples:
i32 (i32)	function taking an i32, returning an i32
float (i16, i32 *) *	Pointer to a function that takes an i16 and a pointer to i32, returning float.
i32 (i8*, ...)	A vararg function that takes at least one pointer to i8 (char in C), which returns an integer. This is the signature for printf in LLVM.
{i32, i32} (i32)	A function taking an i32, returning a structure containing two i32 values
  • Integer Type
    The integer type is a very simple type that simply specifies an arbitrary bit width for the integer type desired. Any bit width from 1 bit to 223-1 (about 8 million) can be specified.
    Syntax:
    iN
i1	a single-bit integer.
i32	a 32-bit integer.
i1942652	a really big integer of over 1 million bits.
  • Floating-Point Types
Type	Description
half	16-bit floating-point value
float	32-bit floating-point value
double	64-bit floating-point value
fp128	128-bit floating-point value (112-bit mantissa)
x86_fp80	80-bit floating-point value (X87)
ppc_fp128	128-bit floating-point value (two 64-bits)

The binary format of half, float, double, and fp128 correspond to the IEEE-754-2008 specifications for binary16, binary32, binary64, and binary128 respectively.

  • Array Type
    Syntax:
    [<# elements> x <#elementtype> ]
    The number of elements is a constant integer value; elementtype may be any type with a size.

Examples:

[40 x i32]	Array of 40 32-bit integer values.
[41 x i32]	Array of 41 32-bit integer values.
[4 x i8]	Array of 4 8-bit integer values.
Here are some examples of multidimensional arrays:

[3 x [4 x i32]]	3x4 array of 32-bit integer values.
[12 x [10 x float]]	12x10 array of single precision floating-point values.
[2 x [3 x [4 x i16]]]	2x3x4 array of 16-bit integer values.
  • Vector Type

Syntax:
< <# elements> x <#elementtype> >

<4 x i32>	Vector of 4 32-bit integer values.
<8 x float>	Vector of 8 32-bit floating-point values.
<2 x i64>	Vector of 2 64-bit integer values.
<4 x i64*>	Vector of 4 pointers to 64-bit integer values.
  • Poison Value
    考虑到溢出会带来不确定的行为
    %add = add nsw i32 %x, 1相当于if (%x+1) overflows then %add = undef else %add = add i32 %x,1
    https://stackoverflow.com/questions/34190997/the-poison-value-and-undefined-value-in-llvm

LLVM IR

  • alloca
    https://stackoverflow.com/questions/45507294/llvm-ir-alloca-instruction
    The alloca instruction reserves space on the stack frame of the current function. The amount of space is determined by element type size, and it respects a specified alignment. The first instruction, %a.addr = alloca i32, align 4, allocates a 4-byte stack element, which respects a 4-byte alignment. A pointer to the stack element is stored in the local identifier, %a.addr. The alloca instruction is commonly used to represent local (automatic) variables.

  • load & store
    The ‘load’ instruction is used to read from memory.

%ptr = alloca i32                               ; yields i32*:ptr
store i32 3, i32* %ptr                          ; yields void
%val = load i32, i32* %ptr                      ; yields i32:val = i32 3
  • getelementptr
    http://llvm.org/docs/GetElementPtr.html

LLVM Command

生成.ll文件 #How to make clang compile to llvm IR https://stackoverflow.com/questions/9148890/how-to-make-clang-compile-to-llvm-ir

clang -S -emit-llvm add.c

运行.ll文件

llvm-as < printf.ll | lli

LLVM Blogs

llvm Makefile

LLVM_DIR = /usr/lib/llvm-3.9
CXXFLAGS = -g -std=c++11 -Wall -Wno-deprecated -Wno-unused -fpermissive -Wno-write-strings
CXXFLAGS += `${LLVM_DIR}/bin/llvm-config --cxxflags`
LDFLAGS += `${LLVM_DIR}/bin/llvm-config --ldflags`
LLVMLIBS = `${LLVM_DIR}/bin/llvm-config --libs`
LLVMLIBS += `${LLVM_DIR}/bin/llvm-config --system-libs`
CXX = clang++

all:
	${CXX} llvm_test.cpp ${CXXFLAGS} ${LDFLAGS} ${LLVMLIBS} -o llvm_test

llvm链接方式

可以将.bc文件和.o文件链接使用,在.ll文件中必须对要使用的函数进行声明,example:

1.在execute.c中有main函数,里面调用了print_hello(),print_hello()在runtime.c中实现
2.clang -c -emit-llvm execute.c	// 生成.ll
3.llvm-as execute.ll -o execute.bc  //.ll -> .bc
4.llc -filetype=asm execute.bc -o execute.s  // .bc->.s
3.clang -c runtime.c -o runtime.o	// 声明要链接的目标文件
4.clang -g execute.s runtime.o -o main.out  // .s  .o  -> .out

llvm demo

  • 对应的CMake文件
cmake_minimum_required(VERSION 3.15)
project(llvm_test)

set(CMAKE_CXX_STANDARD 11)
find_package(LLVM REQUIRED CONFIG)
set(LLVM_LINK_COMPONENTS
        Core
        Support)
add_executable(llvm_test main.cpp)
llvm_map_components_to_libnames(llvm_libs ${LLVM_LINK_COMPONENTS})
target_link_libraries(llvm_test ${llvm_libs})

  • 创建函数,调用函数,运算
#include 
#include "llvm/IR/Function.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/ADT/APFloat.h"
#include 
#include 
#include 

using namespace llvm;

llvm::LLVMContext TheContext;
IRBuilder<> Builder(TheContext);
std::unique_ptr TheModule;
std::map NamedValues;

int main() {
    TheModule = make_unique("llvm_test", TheContext);
    std::vector Doubles(2, Type::getDoubleTy(TheContext));  // 形参类型声明
    Doubles.push_back(Type::getInt32Ty(TheContext));

    FunctionType *FT = FunctionType::get(Type::getDoubleTy(TheContext),
            Doubles, false);    // 创建函数类型,param2不能为NULL
    Function *F = Function::Create(FT, Function::ExternalLinkage,
            "add", TheModule.get());    // 函数声明,函数名为add

    // 声明形参,给形参标注变量名
    std::vector name_vec = {"a", "b", "c"};
    unsigned idx = 0;
    for (auto &arg : F->args())
        arg.setName(name_vec[idx++]);

    // 创建一个基本块,名字为entry,属于函数F
    BasicBlock *BB = BasicBlock::Create(TheContext, "entry", F);
    BasicBlock *BB1 = BasicBlock::Create(TheContext, "label1", F);
    Builder.SetInsertPoint(BB);  // 要先设置InsertPoint,才能生成IR

    for (auto &Arg : F->args())
        NamedValues[Arg.getName()] = &Arg;

    // 创建返回值,返回值为Float Constant 0.0
    Builder.CreateRet(ConstantFP::get(TheContext, APFloat(0.0)));

    Builder.SetInsertPoint(BB1);
    Builder.CreateRet(ConstantFP::get(TheContext, APFloat(1.0)));

    // 运算
    Value *addtmp = Builder.CreateFAdd(NamedValues["a"], NamedValues["b"], "");
    Builder.CreateFSub(NamedValues["a"], addtmp, "");
    Builder.CreateFMul(NamedValues["a"], NamedValues["b"], "");
    Builder.CreateFDiv(NamedValues["a"], NamedValues["b"], "");
    Value *L = Builder.CreateFCmpULT(NamedValues["a"], NamedValues["b"], "");   // float-point less than
    Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "");     // uitofp:unsigned int convert to float-point value

    // 打印生成的llvmIR
    TheModule->print(errs(), nullptr);  // errs() from Verifier.h
    return 0;
}

生成的llvm IR:

define double @add(double %a, double %b, i32 %c) {
entry:
  ret double 0.000000e+00

label1:                                           ; No predecessors!
  ret double 1.000000e+00
  %0 = fadd double %a, %b
  %1 = fsub double %a, %0
  %2 = fmul double %a, %b
  %3 = fdiv double %a, %b
  %4 = fcmp ult double %a, %b
  %5 = uitofp i1 %4 to double
}

  • if-then-else
#include 
#include "llvm/IR/Function.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/ADT/APFloat.h"
#include 
#include 
#include 

using namespace llvm;

llvm::LLVMContext TheContext;
IRBuilder<> Builder(TheContext);
std::unique_ptr TheModule;
std::map NamedValues;

void llvm_test1() {
    TheModule = make_unique("llvm_test", TheContext);
    std::vector Doubles(3, Type::getDoubleTy(TheContext));  // 形参类型声明

    FunctionType *FT = FunctionType::get(Type::getDoubleTy(TheContext),
            Doubles, false);    // 创建函数类型
    Function *F = Function::Create(FT, Function::ExternalLinkage,
            "func", TheModule.get());    // 函数声明,函数名为func

    // 声明形参,给形参标注变量名
    std::vector name_vec = {"a", "b", "c"};
    unsigned idx = 0;
    for (auto &arg : F->args())
        arg.setName(name_vec[idx++]);

    for (auto &Arg : F->args())
        NamedValues[Arg.getName()] = &Arg;

    // 创建一个基本块,名字为entry,属于函数F
    BasicBlock *BB = BasicBlock::Create(TheContext, "entry", F);
    Builder.SetInsertPoint(BB);


    BasicBlock *then_block = BasicBlock::Create(TheContext, "then", F);
    BasicBlock *else_block = BasicBlock::Create(TheContext, "else", F);
    BasicBlock *merge_block = BasicBlock::Create(TheContext, "merge", F);

    Value *CondV = NamedValues["c"];
    CondV = Builder.CreateFCmpONE(ConstantFP::get(TheContext, APFloat(0.0)), CondV, "ifcond");
    Builder.CreateCondBr(CondV, then_block, else_block);

    Builder.SetInsertPoint(then_block);
    Value *then_val = Builder.CreateFAdd(NamedValues["a"], NamedValues["b"], "");
    Builder.CreateBr(merge_block);

    Builder.SetInsertPoint(else_block);
    Value *else_val = Builder.CreateFMul(NamedValues["a"], NamedValues["b"], "");
    Builder.CreateBr(merge_block);

    Builder.SetInsertPoint(merge_block);
    PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, "iftmp");
    PN->addIncoming(then_val, then_block);
    PN->addIncoming(else_val, else_block);

    // 打印生成的llvmIR
    TheModule->print(errs(), nullptr);  // errs() from Verifier.h
}


int main() {
    llvm_test1();
}

生成的llvm ir

define double @func(double %a, double %b, double %c) {
entry:
  %ifcond = fcmp one double 0.000000e+00, %c
  br i1 %ifcond, label %then, label %else

then:                                             ; preds = %entry
  %0 = fadd double %a, %b
  br label %merge

else:                                             ; preds = %entry
  %1 = fmul double %a, %b
  br label %merge

merge:                                            ; preds = %else, %then
  %iftmp = phi double [ %0, %then ], [ %1, %else ]
}
  • alloca,load,store
#include 
#include "llvm/IR/Function.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/ADT/APFloat.h"
#include 
#include 
#include 

using namespace llvm;

llvm::LLVMContext TheContext;
IRBuilder<> Builder(TheContext);
std::unique_ptr TheModule;
std::map NamedValues;

void llvm_test1() {
    TheModule = make_unique("llvm_test", TheContext);
    FunctionType *FT = FunctionType::get(Type::getVoidTy(TheContext), std::vector(), false);
    Function *F = Function::Create(FT, Function::ExternalLinkage, "main", TheModule.get());
    BasicBlock *entry_block = BasicBlock::Create(TheContext, "entry", F);
    Builder.SetInsertPoint(entry_block);
    AllocaInst *a_ptr = Builder.CreateAlloca(Type::getDoubleTy(TheContext), nullptr, "a");
    AllocaInst *b_ptr = Builder.CreateAlloca(Type::getDoubleTy(TheContext), nullptr, "b");
    Builder.CreateStore(ConstantFP::get(TheContext, APFloat(1.0)), a_ptr);	// store 1.0 a_ptr
    Builder.CreateStore(ConstantFP::get(TheContext, APFloat(2.0)), b_ptr);	// store 2.0 b_ptr

    Value *tmp1 = Builder.CreateLoad(a_ptr, "");	// %1 = load a_ptr 
    Value *tmp2 = Builder.CreateLoad(b_ptr, "");  // %2 = load b_ptr

    Builder.CreateStore(tmp1, b_ptr);
    Builder.CreateStore(tmp2, a_ptr);

    AllocaInst *c_ptr = Builder.CreateAlloca(Type::getInt32Ty(TheContext), nullptr, "c");
    AllocaInst *d_ptr = Builder.CreateAlloca(Type::getInt32Ty(TheContext), nullptr, "d");
    Builder.CreateStore(ConstantInt::get(TheContext, APInt(32, 1)), c_ptr);   // APInt第一个参数为整数的位数
    Builder.CreateStore(ConstantInt::get(TheContext, APInt(32, 1)), d_ptr);
    Value *tmp3 = Builder.CreateLoad(c_ptr, "");
    Value *tmp4 = Builder.CreateLoad(d_ptr, "");
    Value *tmp5 = Builder.CreateAdd(tmp3, tmp4);
    Builder.CreateStore(tmp5, c_ptr);

    // 打印生成的llvmIR
    TheModule->print(errs(), nullptr);  // errs() from Verifier.h
}


int main() {
    llvm_test1();
}

输出的llvm ir

define void @main() {
entry:
  %a = alloca double
  %b = alloca double
  store double 1.000000e+00, double* %a
  store double 2.000000e+00, double* %b
  %0 = load double, double* %a
  %1 = load double, double* %b
  store double %0, double* %b
  store double %1, double* %a
  %c = alloca i32
  %d = alloca i32
  store i32 1, i32* %c
  store i32 1, i32* %d
  %2 = load i32, i32* %c
  %3 = load i32, i32* %d
  %4 = add i32 %2, %3
  store i32 %4, i32* %c
}
  • 将生成的llvm ir输出到一个文件中
 std::ofstream fs("output.txt");
std::ostream& os = fs;
 llvm::raw_os_ostream llvm_os(os);  // 需要#include "llvm/Support/raw_os_ostream"
TheModule->print(llvm_os, nullptr);
  • 显示"hello wrold!"
#include 
#include "llvm/IR/Function.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/Support/raw_os_ostream.h"
#include 
#include 
#include 
#include 
#include 
using namespace llvm;

llvm::LLVMContext TheContext;
IRBuilder<> Builder(TheContext);
std::unique_ptr TheModule = make_unique("llvm_test", TheContext);
std::map NamedValues;

void llvm_test1() {
    //TheModule = make_unique("llvm_test", TheContext);
    FunctionType *FT = FunctionType::get(Type::getVoidTy(TheContext), std::vector(), false);
    Function *F = Function::Create(FT, Function::ExternalLinkage, "main", TheModule.get());
    BasicBlock *entry_block = BasicBlock::Create(TheContext, "entry", F);
    Builder.SetInsertPoint(entry_block);
    Value* helloworld_str = Builder.CreateGlobalStringPtr("hello world!\n");  // 创建字符常量
    std::vector puts_args; 
    puts_args.push_back(Builder.getInt8Ty()->getPointerTo());
    ArrayRef args_ref(puts_args);
    FunctionType * puts_type = FunctionType::get(Builder.getInt32Ty(), args_ref, false);
    Function* puts_func = Function::Create(puts_type, Function::ExternalLinkage, "puts", TheModule.get());   //声明puts函数
    Builder.CreateCall(puts_func, helloworld_str); // 调用puts函数
    Builder.CreateRetVoid();	
    outs() << *TheModule;
}

int main() {
    llvm_test1();
}

生成的llvm ir,指令lli命令后直接运行

; ModuleID = 'llvm_test'
source_filename = "llvm_test"

@0 = private unnamed_addr constant [14 x i8] c"hello world!\0A\00"

define void @main() {
entry:
  %0 = call i32 @puts(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @0, i32 0, i32 0))
  ret void
}

declare i32 @puts(i8*)
  • StructType, getelementptr, bitcast(将类型A转换为类型B,转换的过程中不改变原本的数据,相当于只是改变读的方式)
#include 
#include "llvm/IR/Function.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/Support/raw_os_ostream.h"
#include 
#include 
#include 
#include 
#include 
using namespace llvm;

llvm::LLVMContext TheContext;
IRBuilder<> Builder(TheContext);
std::unique_ptr TheModule = make_unique("llvm_test", TheContext);
std::map NamedValues;

void llvm_test1() {
    //TheModule = make_unique("llvm_test", TheContext);

    FunctionType *FT = FunctionType::get(Type::getVoidTy(TheContext), std::vector(), false);
    Function *F = Function::Create(FT, Function::ExternalLinkage, "main", TheModule.get());
    BasicBlock *entry_block = BasicBlock::Create(TheContext, "entry", F);
    Builder.SetInsertPoint(entry_block);

    std::vector types;
    types.push_back(Type::getDoubleTy(TheContext));
    types.push_back(Type::getInt32Ty(TheContext));
    StructType *st = StructType::create(TheContext, types, "A");
    AllocaInst *a_ptr = Builder.CreateAlloca(st);
    Value *dest = Builder.CreateGEP(a_ptr, ConstantInt::get(Type::getInt32Ty(TheContext), APInt(32, 1)));
    Builder.CreateBitCast(a_ptr, Type::getInt32Ty(TheContext)->getPointerTo());
    Builder.CreateRetVoid();
    outs() << *TheModule;
}


int main() {
    llvm_test1();
}

生成的llvm ir

; ModuleID = 'llvm_test'
source_filename = "llvm_test"

%A = type { double, i32 }

define void @main() {
entry:
  %0 = alloca %A
  %1 = getelementptr %A, %A* %0, i32 1
  %2 = bitcast %A* %0 to i32*
  ret void
}
  • 创建vable(创建未定义类型的指针)
void define_vtable() {
    StructType *foo = StructType::create(TheContext, "Foo");   // 注意一定要用create不能用get,否则后面无法调用setBody()
    StructType *vtable = StructType::create(TheContext, "vtable");
    auto *foo_ptr = foo->getPointerTo();

    std::vector fields({vtable->getPointerTo(), Type::getInt32Ty(TheContext), Type::getInt32Ty(TheContext)});
    FunctionType *foo_create_default_type = FunctionType::get(Type::getVoidTy(TheContext), {foo_ptr},
                                                              false);
    Function *foo_create_default = Function::Create(foo_create_default_type, Function::ExternalLinkage,
                                                    "Foo_Create_Default", TheModule.get());
    func_map["Foo_Create_Default"] = foo_create_default;
    for (auto &arg : foo_create_default->args())
        arg.setName("this");
    Function *func_ptr = TheModule->getFunction("Foo_Create_Default");
    BasicBlock *entry_block = BasicBlock::Create(TheContext, "entry", func_ptr);
    Builder.SetInsertPoint(entry_block);


    Builder.CreateAlloca(foo->getPointerTo());
    //foo->setBody({Type::getInt32Ty(TheContext), Type::getInt32Ty(TheContext)});
    foo->setBody(fields);
    vtable->setBody({foo_create_default_type});
    outs() << *TheModule;
}

生成的llvm ir:

%Foo = type { %vtable*, i32, i32 }
%vtable = type { void (%Foo*) }

define void @Foo_Create_Default(%Foo* %this) {
entry:
  %0 = alloca %Foo*
}
  • 内置的printf函数使用
void print_test() {
    Function *print_func = get_printf(TheModule.get());
    FunctionType *func_type = FunctionType::get(Type::getVoidTy(TheContext), std::vector(), false);
    Function *main = Function::Create(func_type, Function::ExternalLinkage, "main", TheModule.get());
    BasicBlock *entry_block = BasicBlock::Create(TheContext, "entry", main);
    Builder.SetInsertPoint(entry_block);
    Value *print_arg = ConstantInt::get(Type::getInt32Ty(TheContext), APInt(32, 1));
    Builder.CreateCall(print_func, {Builder.CreateGlobalStringPtr("in llvm fun, value = %d\n"), print_arg});
    Builder.CreateCall(print_func, {Builder.CreateGlobalStringPtr("%s\n"), Builder.CreateGlobalStringPtr("hello world!")});
    outs() << *TheModule;
}

  • 打印类型的名字,如果是primitive类型调用getStructName会发生错误
void llvm_test1() {
    StructType *A = StructType::create(TheContext, {}, "A");
    std::vector Doubles(2, Type::getDoubleTy(TheContext));  // 形参类型声明
    Doubles.push_back(Type::getInt32Ty(TheContext));
    Doubles.push_back(A);
    FunctionType *FT = FunctionType::get(Type::getVoidTy(TheContext),
                                         Doubles, false);    // 创建函数类型,param2不能为NULL
    Function *F = Function::Create(FT, Function::ExternalLinkage,
                                   "add", TheModule.get());    // 函数声明,函数名为add

    // 声明形参,给形参标注变量名
    std::vector name_vec = {"a", "b", "c", "A"};
    unsigned idx = 0;
    for (auto &arg : F->args())
        arg.setName(name_vec[idx++]);

    for (auto &arg : F->args())
        if (arg.getType() == Type::getDoubleTy(TheContext))
            std::cout << "Double" << std::endl;
        else if (arg.getType() == Type::getInt32Ty(TheContext))
            std::cout << "Int" << std::endl;
        else if (arg.getType() == Type::getInt1Ty(TheContext))
            std::cout << "Bool" << std::endl;
        else
            std::cout << std::string(arg.getType()->getStructName()) << std::endl;

    // 创建一个基本块,名字为entry,属于函数F

    Builder.CreateRetVoid();
    outs() << *TheModule;
}
  • 将生成的llvm ir输出到文件
#include 
#include "llvm/IR/Function.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/Support/raw_os_ostream.h"
#include "llvm/Support/raw_ostream.h"
#include 
#include 
#include 
#include 
#include 

using namespace llvm;

llvm::LLVMContext TheContext;
IRBuilder<> Builder(TheContext);
std::unique_ptr TheModule;
std::map NamedValues;

int main() {
    TheModule = make_unique("llvm_test", TheContext);
    std::vector Doubles(2, Type::getDoubleTy(TheContext));  // 形参类型声明
    Doubles.push_back(Type::getInt32Ty(TheContext));

    FunctionType *FT = FunctionType::get(Type::getDoubleTy(TheContext),
                                         Doubles, false);    // 创建函数类型,param2不能为NULL
    Function *F = Function::Create(FT, Function::ExternalLinkage,
                                   "add", TheModule.get());    // 函数声明,函数名为add

    // 声明形参,给形参标注变量名
    std::vector name_vec = {"a", "b", "c"};
    unsigned idx = 0;
    for (auto &arg : F->args())
        arg.setName(name_vec[idx++]);

    // 创建一个基本块,名字为entry,属于函数F
    BasicBlock *BB = BasicBlock::Create(TheContext, "entry", F);
    BasicBlock *BB1 = BasicBlock::Create(TheContext, "label1", F);
    Builder.SetInsertPoint(BB);  // 要先设置InsertPoint,才能生成IR

    for (auto &Arg : F->args())
        NamedValues[Arg.getName()] = &Arg;

    // 创建返回值,返回值为Float Constant 0.0
    Builder.CreateRet(ConstantFP::get(TheContext, APFloat(0.0)));

    Builder.SetInsertPoint(BB1);
    Builder.CreateRet(ConstantFP::get(TheContext, APFloat(1.0)));

    // 运算
    Value *addtmp = Builder.CreateFAdd(NamedValues["a"], NamedValues["b"], "");
    Builder.CreateFSub(NamedValues["a"], addtmp, "");
    Builder.CreateFMul(NamedValues["a"], NamedValues["b"], "");
    Builder.CreateFDiv(NamedValues["a"], NamedValues["b"], "");
    Value *L = Builder.CreateFCmpULT(NamedValues["a"], NamedValues["b"], "");   // float-point less than
    Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "");     // uitofp:unsigned int convert to float-point value

    // 打印生成的llvmIR
    std::ofstream s("output");
    if (!s) {
        std::cerr << "cannot open output file" << std::endl;
        exit(1);
    }
    std::ostream &s1 = s;
    raw_os_ostream os(s1);
    TheModule->print(os, nullptr);

    return 0;
}

你可能感兴趣的:(llvm用法)