LRFRC系列:解读MIR基础

发布于 2021-09-27 22:24

learn rust from rustc(LRFRC)系列文章尝试从另外一个角度来学习Rust语言,通过了解编译器rustc基本原理来学习Rust语言,以便更好的理解和分析编译错误提示,更快的写出更好的Rust代码。

通过前面的文章了解Rust语言基础以及相关语法、生成AST语法树、遍历AST语法树、简易宏和过程宏、名称解析、生成高级中间描述HIR、类型系统基础之后,回顾LRFRC系列:快速入门rustc编译器概览中讲到将HIR转换成中间描述MIR并进行借用检查部分的内容,现对MIR如何生成相关内容进行解读;

 一、MIR基础

1.MIR简介

在https://blog.rust-lang.org/2016/04/19/MIR.html中详细介绍了为啥引进MIR(Mid-level IR)和其实现特点,编译器实现对MIR的支持极大促进Rust语言的发展,带来更快的编译速度、代码执行速度、更精准的类型检查和借用检查,帮助Rust语言及生态实现突破性的成长;

作为一种面向类型完整、安全借用检查、性能优化的中间描述,使用简易的数据结构,以实现从面向开发者结构化的HIR到面向底层LLVM IR的转换,从而以MIR为中心来实现Rust语言独特的类型系统、借用检查、所有权等特性;

有了MIR,为后续独立的MIRI解析器、分析检查器提供了可能,为使用GCC基于MIR作为后端来生成机器码成为可能;

其主要特点包括:基于控制流图来组织定义代码执行、以类型为中心确定代码执行对象的流转、显示确定对象析构及异常处理;

2.控制流图CFG

MIR基于控制流图来组织及定义,一个控制流图由一组基础块组成,每一个基础块由一系列语句和一个终结者组成,一个基础块中往往包含一个终结者并且处于基础块的末尾;

每一个基础块都有一个编号,在终结者中以图边连接的方式实现不同基础块之间的连接以实现逻辑跳转,终结者包括有Goto、函数调用、SwitchInt、Return、Drop等,进而将一段代码逻辑形成一个有向控制流图;

3.以类型为中心

构建MIR是在类型检查完成之后,在构建MIR过程中记录每一个数据操作对象的类型,以明确其作为Move或Copy操作数来使用;其中对引用类型明确其引用的Region值即生命周期;

其中定义的操作数类型包括有Copy、Move、Constant;Place表示用户定义的变量、临时变量、函数参数、返回值的访问路径;

pub enum Operand<'tcx> {   /// Copy: The value must be available for use afterwards.   /// This implies that the type of the place must be `Copy`;   Copy(Place<'tcx>),   /// Move: The value (including old borrows of it)   /// will not be used again.   Move(Place<'tcx>),   /// Synthesizes a constant value.   Constant(Box<Constant<'tcx>>),}

4.显示确定对象析构

通过维护数据操作对象的定义、使用及流转范围,显示明确对象的析构发生的地点,加上流程优化后,可简化析构的触发;

二、MIR主要数据结构

为了描述程序的执行,MIR定义了简易的数据结构来描述程序执行涉及到的逻辑,主要包括基础块、语句、终结者、操作数、右值、Place、Local等;

1.mir::Body

它用来描述一个函数体;

pub struct Body<'tcx> {    /// 函数包含的所有基础块,引用基础块需要通过基础块编号BasicBlock;    basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,        /// 函数本地Locals声明    /// 第1个Local用作返回值,紧接arg_count个Locals用作函数参数,    /// 后续Local用作记录用户定义的任何变量和临时变量;    /// Locals类似于维护函数的调用栈,在实现函数内部操作的过程中,    /// 对需要用到的任何变量或临时变量都记录在此;    /// 要访问Local的内容需要通过索引编号的方式;    pub local_decls: LocalDecls<'tcx>,    /// 这个函数的参数的数量,从本地索引1开始到arg_count的Locals,    /// 假定由调用者来提供并初始化;    pub arg_count: usize,    /// A span representing this MIR, for error reporting.    pub span: Span,    /// 函数体需要用到的Constants    pub required_consts: Vec<Constant<'tcx>>,    pub is_polymorphic: bool,    //..............................}rustc_index::newtype_index! {    /// A node in the MIR [control-flow graph][CFG].    pub struct BasicBlock {        derive [HashStable]        DEBUG_FORMAT = "bb{}",        const START_BLOCK = 0,    }}pub struct BasicBlockData<'tcx> {    /// List of statements in this block.    pub statements: Vec<Statement<'tcx>>,    /// Terminator for this block.    /// N.B., this should generally ONLY    /// be `None` during construction.    pub terminator: Option<Terminator<'tcx>>,    /// If true, this block lies on an unwind path.    pub is_cleanup: bool,}

2.mir::Statement和Terminator

pub struct Statement<'tcx> {    pub source_info: SourceInfo,    pub kind: StatementKind<'tcx>,}pub enum StatementKind<'tcx> {    /// 将右值Rvalue写到左边的访问路径    Assign(Box<(Place<'tcx>, Rvalue<'tcx>)>),    /// Local具有有效存储的开始    StorageLive(Local),    /// Local具有有效存储的结束    StorageDead(Local),    /// 省略部分其他语句.........    /// 空语句 用来删除指令而无须影响语句编号    Nop,}pub struct Terminator<'tcx> {    pub source_info: SourceInfo,    pub kind: TerminatorKind<'tcx>,}pub enum TerminatorKind<'tcx> {    /// 跳转到图中一个有效的块    Goto { target: BasicBlock },    /// 评估操作数,根据其值跳转到某一个目标;    SwitchInt {        /// 将被评估的操作数        discr: Operand<'tcx>,        /// 操作数类型,存在冗余        switch_ty: Ty<'tcx>,        /// 跳转目标列表        targets: SwitchTargets,    },    /// 表示landing pad已完成,unwinding可继续    Resume,    /// 表示landing pad已完成,需要终止后续unwinding    Abort,    /// 描述正常的返回。执行Return前,返回路径中的值应该已填充;    /// 可以在不同基础块中被调用多次    Return,    /// Indicates a terminator that can never be reached.    /// 描述该终结者不可达    Unreachable,    /// 析构指定访问路径中的Local,完成后跳转到target,    /// 发生异常则unwind    Drop { place: Place<'tcx>, target: BasicBlock           , unwind: Option<BasicBlock> },    /// 析构Place中值之后并为它赋上新值    DropAndReplace {        place: Place<'tcx>,        value: Operand<'tcx>,        target: BasicBlock,        unwind: Option<BasicBlock>,    },    /// Block ends with a call of a function.    /// 描述一次函数调用,func表示正被调用的函数,    /// args表示其参数,参数内容由调用者作为拥有者,函数可以自由修改,    /// destination表示返回值,    Call {        func: Operand<'tcx>,        args: Vec<Operand<'tcx>>,        destination: Option<(Place<'tcx>, BasicBlock)>,        /// Cleanups to be done if the call unwinds.        cleanup: Option<BasicBlock>,        from_hir_call: bool,        fn_span: Span,    },    /// 省略部分其他类型.........}

3.mir::LocalDecs和Place

pub type LocalDecls<'tcx> = IndexVec<Local, LocalDecl<'tcx>>;/// Local表示LocalDecls中的LocalDecl索引rustc_index::newtype_index! {    pub struct Local {        derive [HashStable]        DEBUG_FORMAT = "_{}",        const RETURN_PLACE = 0,    }}pub enum LocalKind {    /// 用户声明的变量    Var,    /// 临时变量    Temp,    /// 函数参数    Arg,    /// 函数返回值    ReturnPointer,}pub struct LocalDecl<'tcx{  pub mutability: Mutability,  pub local_info: Option<Box<LocalInfo<'tcx>>>,  pub internal: bool,  pub is_block_tail: Option<BlockTailInfo>,  /// The type of this local.  /// Local的类型,它决定Local存储空间大小及其可否Move/Copy等  pub ty: Ty<'tcx>,  pub user_ty: Option<Box<UserTypeProjections>>,    pub source_info: SourceInfo,}/// A path to a value; something that can be evaluated without/// changing or disturbing program state./// 指向一个值的路径pub struct Place<'tcx> {    pub local: Local,    /// projection out of a place    /// (access a field, deref a pointer, etc)    pub projection: &'tcx List<PlaceElem<'tcx>>,}pub enum ProjectionElem<V, T> {    Deref,    Field(Field, T),    Index(V),    Subslice {        from: u64,        to: u64,        /// Whether `to` counts from the start         /// or end of the array/slice.        from_end: bool,    },    /// 省略部分其他类型.........}

4.mir::Rvalue和Op

pub enum Rvalue<'tcx> {    /// x (either a move or copy, depending on type of x)    Use(Operand<'tcx>),    /// [x; 32]    Repeat(Operand<'tcx>, &'tcx ty::Const<'tcx>),    /// &x or &mut x    /// 对指定路径的值的引用或借用    Ref(Region<'tcx>, BorrowKind, Place<'tcx>),    /// Accessing a thread local static.     /// This is inherently a runtime operation.    ThreadLocalRef(DefId),    /// Create a raw pointer to the given place    /// Can be generated by raw address of expressions    /// (`&raw const x`),    /// or when casting a reference to a raw pointer.    AddressOf(Mutability, Place<'tcx>),    /// length of a `[X]` or `[X;n]` value    Len(Place<'tcx>),    Cast(CastKind, Operand<'tcx>, Ty<'tcx>),    BinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>),    CheckedBinaryOp(BinOp, Box<(Operand<'tcx>        , Operand<'tcx>)>),    NullaryOp(NullOp, Ty<'tcx>),    UnaryOp(UnOp, Operand<'tcx>),    /// Read the discriminant of an ADT.    /// 用于match语句    Discriminant(Place<'tcx>),    /// 省略部分其他类型.........}pub enum BinOp {    /// The `+` operator (addition)    Add,    /// The `-` operator (subtraction)    Sub,    /// The `*` operator (multiplication)    Mul,    /// The `/` operator (division)    Div,    /// The `%` operator (modulus)    Rem,    /// The `^` operator (bitwise xor)    BitXor,    /// The `&` operator (bitwise and)    BitAnd,    /// The `|` operator (bitwise or)    BitOr,    /// The `<<` operator (shift left)    Shl,    /// The `>>` operator (shift right)    Shr,    /// The `==` operator (equality)    Eq,    /// The `<` operator (less than)    Lt,    /// The `<=` operator (less than or equal to)    Le,    /// The `!=` operator (not equal to)    Ne,    /// The `>=` operator (greater than or equal to)    Ge,    /// The `>` operator (greater than)    Gt,    /// The `ptr.offset` operator    Offset,}pub enum NullOp {    /// Returns the size of a value of that type    SizeOf,    /// 为指定类型的值创建一个新未初始化的空间    Box,}pub enum UnOp {    /// The `!` operator for logical inversion    Not,    /// The `-` operator for negation    Neg,}

三、总结及其他

本文来自网络或网友投稿,如有侵犯您的权益,请发邮件至:aisoutu@outlook.com 我们将第一时间删除。

相关素材