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;
}
尾调用由于是函数的最后一步操作,所以不需要保留外层函数的调用记录,因为调用位置、内部变量等信息都不会再用到了,只要直接用内层函数的调用记录,取代外层函数的调用记录就可以了。
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
https://blog.csdn.net/qq_29674357/article/details/78731713
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
i1 a single-bit integer.
i32 a 32-bit integer.
i1942652 a really big integer of over 1 million bits.
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.
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.
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.
%add = add nsw i32 %x, 1
相当于if (%x+1) overflows then %add = undef else %add = add i32 %x,1
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
生成.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_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
可以将.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
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
生成的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
}
#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
生成的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 ]
}
#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
输出的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
}
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);
#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
生成的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*)
#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
生成的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
}
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*
}
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;
}
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;
}
#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