llvm后端之SDNode设计

引言

llvm后端将中端的IR转为有向无环图,即DAG。如下图:
在这里插入图片描述
图中黑色箭头为数据依赖;蓝色线和红色线为控制依赖。蓝色表示指令序列化时两个节点中间可以插入其他节点对应的指令,称为chain(类型为MVT::Other);而红色节点表示两个节点生成的指令中间不能插入其他节点的指令,称为glue(类型为MVT::Glue)。
chain操作数如果存在的话,总是第一个操作数,而glue操作数如果存在的话,则总是最后一个操作数。当输出值有chain或glue时,则它们总是最后两个。

注:本文参考源码路径为 https://github.com/llvm/llvm-project/tree/release/10.x

1 核心类设计

DAG图是围绕SDNode、SDUse、SDValue组织,如下图:
在这里插入图片描述

  • DAG图中每个节点,用SDNode表示。节点有依赖节点,用OperandList表示;节点可以有多个输出值,其输出值类型用ValueList表示;
  • 用SDValue表示每个节点的输出值,其中记录了SDNode和输出值序号ResNo;
  • SDUse表示DAG图的依赖箭头。用Val表示箭头指向的节点,即被依赖的节点输出值;用User表示箭头起点的节点,即使用节点;
  • 每个SDUse设置Val时,会将自己添加到SDNode的UseList链表中。这样每个Node就可以遍历到使用自己的其他节点。

2 类型系统

llvm后端DAG的类型系统分为三个层级,从外到内为:EVT、MVT、SimpleValueType。如下图:
在这里插入图片描述

2.1 MVT::SimpleValueType

SimpleValueType是基本数据类型的枚举定义,其中包括:

  • 整数类型
  • 浮点类型
  • 向量类型:其中包括按类型分类有整数向量和浮点向量,按长度分类有固定长度向量和变长向量
  • 其他类型

2.2 MVT

MVT是对SimpleValueType值的封装。并提供常规的方法:

  • isValid : 为整数类型、浮点类、向量类型以及x86mmx、Glue、isVoid、Untyped、exnref,则为true;
  • isFloatingPoint / isInteger : 整数/浮点及其相应类型的向量为true;
  • isScalarInteger : 非向量的整数类型则为true;
  • isScalableVector : 变长向量则为true;
  • isFixedLengthVector :定长向量则为true;
  • isOverloaded : 可重载类型,就是由内置函数可以解释的任意长度类型。有Any、iAny、vAny、fAny、iPTRAny;
  • isPow2VectorType :向量元素个数为2的N次方,则为true;
  • getPow2VectorType : 返回元素个数扩展为2的N次方的新向量类型,例如16个不扩展,5个则扩展为8个;
  • getHalfNumVectorElementsVT : 将向量元素个数截断为原来的一半并返回其类型;
  • getScalarType : 为向量则返回元素类型,否则返回自身相同类型;
  • getVectorNumElements : 返回向量元素个数,变长向量则返回最小向量元素个数;
  • getSizeInBits : 返回类型的bit位数,变长向量则返回最小元素个数乘以元素类型的bit数。
  • getScalarSizeInBits : 返回getScalarType类型的bit位数;
  • getStoreSize : 返回类型从存储长度,即扩展为字节长度。例如1位int扩展为8位int;
  • bitsGT / bitsGE / bitsLT / bitsLE : 比较MVT的getSizeInBits值;

此外,还提供了根据bit位返回类型的系列静态方法。

2.3 EVT

EVT是对MVT的封装,此外还提供了对MVT类型的扩展。当表示MVT之外的类型时,其V.SimpleTy为INVALID_SIMPLE_VALUE_TYPE。例如,当定义一个1024位的int,此时就是一个扩展类型。

3 节点类型

DAG节点的类型(也就是操作类型,对应于指令类型)是定义在llvm::ISD::NodeType枚举类型中;此外,可以基于BUILTIN_OP_END往后自定义目标的操作类型。

注:DELETED_NODE为无效节点

3.1 辅助节点

  • EntryToken : 代表一个基本块的入口;
  • TokenFactor : 当一个节点扩展为多个节点时,由该节点聚合成一个节点返回;
  • MERGE_VALUES:聚合输出值的节点,例如load结构体分拆后再由其聚合成一个;

3.2 叶子节点

  • BasicBlock: 代表一个基本块,由BasicBlockSDNode封装;

  • BlockAddress / TargetBlockAddress : 记录块地址,基本块加偏移,由BlockAddressSDNode封装;

  • VALUETYPE : 类型声明节点,由VTSDNode封装;

  • CONDCODE :条件码类型节点,例如用于跳转指令的比较类型。由CondCodeSDNode封装;

  • Register: 代表一个寄存器号的节点,由RegisterSDNode封装;

  • RegisterMask :寄存器掩码节点,由RegisterMaskSDNode封装;

  • Constant / TargetConstant : int常量节点,由ConstantSDNode封装;

  • ConstantFP / TargetConstantFP : 浮点常量节点,由ConstantFPSDNode封装

  • ConstantPool / TargetConstantPool : 特定语言支持的常量池,例如java。由ConstantPoolSDNode封装;

  • GlobalAddress / TargetGlobalAddress : 全局地址,代表一个全局变量,由GlobalAddressSDNode封装;

  • GlobalTLSAddress / TargetGlobalTLSAddress : 全局变量在线程本地存储中的地址,由GlobalAddressSDNode封装;

  • FrameIndex / TargetFrameIndex : 用于记录分配的栈内存位置,由FrameIndexSDNode封装;

  • JumpTable / TargetJumpTable : 通过索引值记录跳转位置,例如switch跳转,由JumpTableSDNode封装;

  • ExternalSymbol / TargetExternalSymbol : 外部符号的引用,例如外部全局变量或函数,由ExternalSymbolSDNode封装;

3.3 类型转换节点

  • AssertSext :将一个较小类型扩展为较大类型,保留符号位;
  • AssertZext :将一个较小类型扩展为较大类型,高位全0填充;

3.4 重定位节点

  • GLOBAL_OFFSET_TABLE :
  • MCSymbol :代表一个符号,由MCSymbolSDNode封装;

3.5 栈帧操作节点

  • FRAMEADDR : 用索引记录帧地址,0为当前帧、1为上级调用函数帧、以此类推。
  • RETURNADDR: 用索引记录返回地址,0为当前函数返回地址、1为上级调用函数返回地址、以此类推。
  • ADDROFRETURNADDR:代表当前函数的返回地址;
  • SPONENTRY :代表当前函数帧的帧地址;
  • LOCAL_RECOVER :
  • READ_REGISTER :用名字读取寄存器;

3.6 内置函数节点

INTRINSIC_WO_CHAIN : 没有输入输出chain、有返回值的内置函数
INTRINSIC_W_CHAIN : 有输入输出chain、有返回值的内置函数
INTRINSIC_VOID: 有输入输出chain、没有返回值的内置函数

3.7 寄存器操作节点

  • WRITE_REGISTER :用名字写寄存器;
  • FRAME_TO_ARGS_OFFSET : 代表当前帧指针到第一个压栈参数的栈偏移;
  • CopyToReg:
  • CopyFromReg:
  • UNDEF: 未定义节点,代表一个未初始化的值

3.8 异常处理节点

  • EH_DWARF_CFA: 代表相对当前函数第一个压栈参数的栈偏移地址;
  • EH_RETURN: 代表异常返回的数据结构;
  • EH_SJLJ_SETJMP: 利用setjmp方式实现在try中call异常函数,代表异常捕获点
  • EH_SJLJ_LONGJMP: 利用longjmp方式实现throw概念,代表异常抛出点
  • EH_SJLJ_SETUP_DISPATCH: 代表异常处理点,与catch相关;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值