LLVM提供了很多的API用于操作IR,因此我们可以使用这些接口直接在内存中生成IR,同时直接运行,输出结果。(如果我们想要开发一种新的编程语言,那么我们可以在完成词法语法解析后,很快的利用LLVM 接口生成有效的中间代码,同时能够很快的编译到目标平台上。)
LLVM IR 的基本结构如下:

模块中包含函数,函数中包含基本块,基本块中包含指令。我们可以使用很简单的代码进行遍历。
LLVM默认实现了C++接口,但同时也提供了C接口,下面我们使用C接口完成一个生成并且运行IR的简单示例
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <llvm-c/Core.h>
int main() {
// 创建一个模块(模块名 module-test 可以任意)
LLVMModuleRef Module = LLVMModuleCreateWithName("module-test");
// 0. extern int printf(char*, ...)
LLVMTypeRef PrintfArgsTyList[] = { LLVMPointerType(LLVMInt8Type(), 0) };
LLVMTypeRef PrintfTy = LLVMFunctionType(
LLVMInt32Type(),
PrintfArgsTyList,
0,
true // 是否是可变参数
);
// 添加printf函数到模块中
LLVMValueRef PrintfFunction = LLVMAddFunction(Module, "printf", PrintfTy);
// 1. void main(void)
LLVMTypeRef MainFunctionTy = LLVMFunctionType(
LLVMVoidType(),
NULL,
0,
false
);
// 添加main函数到模块中
LLVMValueRef MainFunction = LLVMAddFunction(Module, "main", MainFunctionTy);
// 添加基本块
LLVMBasicBlockRef BasicBlock = LLVMAppendBasicBlock(MainFunction,
"entrypoint");
// 创建builder
LLVMBuilderRef Builder = LLVMCreateBuilder();
LLVMPositionBuilderAtEnd(Builder, BasicBlock);
// 2. char *format = "Hello, %s.\n", *world = "World"";
LLVMValueRef Format = LLVMBuildGlobalStringPtr(
Builder,
"Hello, %s.\n",
"format"
), World = LLVMBuildGlobalStringPtr(
Builder,
"World",
"world"
);
// 3. printf("Hello, %s!", world);
LLVMValueRef PrintfArgs[] = { Format, World };
LLVMBuildCall(
Builder,
PrintfFunction,
PrintfArgs,
2,
"printf"
);
// 4. return;
LLVMBuildRetVoid(Builder);
// dump模块
LLVMDumpModule(Module);
// 释放模块
LLVMDisposeModule(Module);
return 0;
}
使用如下命令编译:
clang++ -x c llvm_ir.c `llvm-config --cflags --ldflags --libs` -o ./llvm_ir
代码中我只做了基本的解释,详细的接口说明,参考 LLVM-C: C interface to LLVM。
参考文献:
LLVM-C: C interface to LLVM - llvm.org/docs/doxygen/html/group__LLVMC.html
LLVM Language Reference Manual -llvm.org/docs/LangRef.html
Comments | NOTHING