LLVM系列第二十六章:理解LLVMContext

系列文章目录

LLVM系列第一章:编译LLVM源码
LLVM系列第二章:模块Module
LLVM系列第三章:函数Function
LLVM系列第四章:逻辑代码块Block
LLVM系列第五章:全局变量Global Variable
LLVM系列第六章:函数返回值Return
LLVM系列第七章:函数参数Function Arguments
LLVM系列第八章:算术运算语句Arithmetic Statement
LLVM系列第九章:控制流语句if-else
LLVM系列第十章:控制流语句if-else-phi
LLVM系列第十一章:写一个Hello World
LLVM系列第十二章:写一个简单的词法分析器Lexer
LLVM系列第十三章:写一个简单的语法分析器Parser
LLVM系列第十四章:写一个简单的语义分析器Semantic Analyzer
LLVM系列第十五章:写一个简单的中间代码生成器IR Generator
LLVM系列第十六章:写一个简单的编译器
LLVM系列第十七章:for循环
LLVM系列第十八章:写一个简单的IR处理流程Pass
LLVM系列第十九章:写一个简单的Module Pass
LLVM系列第二十章:写一个简单的Function Pass
LLVM系列第二十一章:写一个简单的Loop Pass
LLVM系列第二十二章:写一个简单的编译时函数调用统计器(Pass)
LLVM系列第二十三章:写一个简单的运行时函数调用统计器(Pass)
LLVM系列第二十四章:用Xcode编译调试LLVM源码
LLVM系列第二十五章:简单统计一下LLVM源码行数
LLVM系列第二十六章:理解LLVMContext
LLVM系列第二十七章:理解IRBuilder
LLVM系列第二十八章:写一个JIT Hello World
LLVM系列第二十九章:写一个简单的常量加法“消除”工具(Pass)

flex&bison系列



前言

在此,记录下对LLVM源码中LLVMContext这个类的理解,以备查阅。

How

不知您注意到没有,当我们调用LLVM提供的C++ API来生成IR代码时,第一行C++代码就是初始化LLVMContext。如下面这个简单的例子,它创建了一个模块(Module):

// HelloModule.cpp

#include "llvm/IR/Module.h"
#include "llvm/IR/LLVMContext.h"

using namespace llvm;

int main(int argc, char* argv[])
{
    LLVMContext context;
    Module* module = new Module("HelloModule", context);

    module->print(outs(), nullptr);

    return 0;
}

main函数的第一行就是初始化context的代码:

    LLVMContext context;

注意到,当我们创建一个模块(Module)时,context是其中一个输入参数:

Module* module = new Module("HelloModule", context);

另外,我们还可以利用context创建Type(示例):

IntegerType* int32Type = Type::getInt32Ty(context);

Why

在LLVM API中,context是一个很重要的类,它能让我们在多线程中使用LLVM API。我们可以把它理解为一个黑盒,它包含(并管理)了LLVM中基础的、核心的“全局”数据,如类型(Type)、标准化的常量表等。

这里用到了“黑盒”这个词,是为了表明,API的调用者无需过多地深究context是什么。比如,我们无需深究它是如何实现的,包含了什么数据,作用是什么等各种问题。我们可以简单地把它当做一个“代表”,它代表了LLVM这个“引擎库”。我们只需记住,当一个函数需要context的时候,我们就把它传进去即可。

What

通常来说,LLVM的用户也许不需要知道context是什么,但编程语言的开发者(即编译器的开发者)是需要清楚地知道context是什么的。

Context包含了LLVM在一个线程中正常运行(比如一个编译任务)所需要的数据(即LLVM程序状态数据)。在很久以前,也就是LLVM的老版本中,这些状态数据都是全局数据。后来,它们被一股脑儿打包到了一个名叫“LLVMContext”的对象中,这样,LLVM就能支持在多线程中运行编译任务了。

多线程共享context

虽然context可以在多线程中共享使用,但它不是线程安全的,因为它自己不提供数据同步(如加锁)机制。Context本身以及它所包含的数据都是设计成给一个单独的线程使用的。所以,在多线程中共享使用context,可能会导致竞争、数据不同步等多线程常见问题。

线程独有context

当然,如果每个线程都创建一份自己独有的context,则不会有这些问题了。当每一个线程都有自己独立的一份context时,那命名冲突、类型冲突等问题就不再存在了。比如,某个线程正在处理模块A中的类型“Foo”,而另一个线程正在处理模块B中的类型“Foo”。那这两个类型不会互相干扰,因为它们处于不同的context下。

再举个例子,有这样一个多线程的程序,其中一个线程运行图像处理库(Graphics Library),另一个线程运行音频处理库(Audio Library),而这两个库都调用了LLVM。既然它们都调用了LLVM,为了避免这两个处理任务相互干扰,我们只需让它们各自创建一份context即可。所有在当前context之下创建出来的模块(Module)、类型(Type)、常量(Constant)等数据都属于当前的context。另外,我们还可以利用LLVM提供的工具Verifier(这是一个C++类)进行检查,它能确保一个模块下所有的IR对象都属于同一个模块。

Context融合

一般情况下,每一个线程都应该创建一份自己独有的context,以确保数据安全。但如果要合并两个线程的数据,我们不能直接融合两份context对象为一份context。我们可以做的是,把两份context对象转为IR代码,然后合并IR代码。

总结

本章,我们简单地分析了一下LLVM API中的LLVMContext的作用和用法。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值