PL-1-Intermediate-Representation
内容提要
本文介绍编译器与静态分析中的中间表示(IR),重点阐述为何使用IR而非AST进行静态分析,并详细说明三地址码(3AC)和静态单赋值(SSA)的特点,以及如何通过基本块和控制流图(CFG)构建控制流分析的基础结构。
延伸解读
为何静态分析偏爱IR而非AST
文章指出,AST虽接近语法结构且可读性强,但缺少控制流信息,且包含大量非终结符节点,结构不够紧凑。相比之下,IR更接近机器代码,结构统一紧凑,且显式包含控制流信息(如goto),因此更适合作为静态分析的基础。这解释了编译器前端在生成AST后,为何还要进一步翻译为IR再进行优化和分析。
SSA的权衡:优化与开销
SSA通过为每次赋值引入新变量,使定义与使用关系显式化,便于数据流分析和优化,如条件常量传播。但代价是引入大量临时变量和phi函数,可能降低机器代码生成效率。文章提醒,SSA并非万能,需根据场景权衡,例如LLVM采用SSA,而某些领域特定语言也使用SSA。
基本块与CFG的构建要点
构建基本块的关键在于识别leader:程序第一条指令、跳转目标、以及跳转指令的后一条指令。每个leader及其后续指令构成一个基本块。CFG的边由跳转或顺序执行决定,并额外添加Entry和Exit节点以完整表示控制流。理解这一过程是进行控制流分析的基础。
Q&A
为什么静态分析使用IR而不是AST?
因为IR比AST更接近机器代码,结构更紧凑统一,且包含控制流信息,更适合进行静态分析。AST虽然更接近语法结构,但缺少控制流信息,且依赖具体语言。
三地址码(3AC)中的“地址”可以是什么?
三地址码中的“地址”可以是名称(如变量a、b)、常量(如3)或编译器生成的临时变量(如t1、t2)。
静态单赋值(SSA)是什么?它有什么优点和缺点?
SSA是一种中间表示形式,要求每个变量只被赋值一次,每次赋值都使用新变量名。优点包括控制流信息间接集成到变量名中、定义与使用显式、便于数据流分析和优化。缺点是会引入过多变量和phi函数,可能降低代码生成效率。
如何构建基本块?
构建基本块首先确定leaders:程序的第一条指令、跳转目标指令、跳转指令的下一条指令。然后每个leader及其后续直到下一个leader前的所有指令构成一个基本块。
控制流图(CFG)中的边是如何确定的?
块A和块B之间存在边,当且仅当:A的末尾有跳转指令指向B的开头,或者A的末尾紧接着B的开头且A的末尾不是无条件跳转指令。
在控制流图中,Entry和Exit结点有什么作用?
Entry和Exit是额外添加的结点,不对应任何IR。Entry有一条边指向IR的第一条指令,Exit用于表示程序离开IR的出口,如果基本块的最后一条指令会让程序离开IR,则该基本块有一条边指向Exit。