Writing An LLVM Backend

Preliminaries

在lib/Target/下创建你的目标,如lib/Target/MIps;
创建CMakeLIsts.txt;

Target Machine

继承LLVMTargetMachine实现MipsTargetMachine.h MipsTargetMachine.cpp,需要包含get*INfo的方法;

Register

定义一个寄存器类:

// We have banks of 32 registers each.
class MipsReg<bits<16> Enc, string n> : Register<n> {
  let HWEncoding = Enc;
  let Namespace = "Mips";
}
...

MipsRegisterInfo.td中有浮点寄存器, Register Classes(注意)
.td完成后就需要手写.h和.cpp文件,以实现相应的接口.

Instruction

在代码生成的早期阶段,LLVM IR代码被转换为SelectionDAG,其中节点是包含目标指令的SDNode类的实例。 SDNode具有操作码,操作数,类型要求和操作属性。 例如,是一个交换操作,从内存中执行一个操作加载。 include / llvm / CodeGen / SelectionDAGNodes.h文件(ISD命名空间中的NodeType枚举的值)中描述了各种操作节点类型。
Target.td - 指令,操作数,InstrInfo和其他基本类的定义。
TargetSelectionDAG.td - 由SelectionDAG指令选择生成器使用,包含SDTC *类(选择DAG类型约束),SelectionDAG节点的定义(例如imm,cond,bb,add,fadd,sub)和模式支持(Pattern,Pat, PatFrag,PatLeaf,ComplexPattern。
MipsInstrFormats.td - 用于定义特定于目标的指令的模式。
MipsInstrInfo.td - 指令模板,条件代码和指令集指令的特定于目标的定义。对于架构修改,可以使用不同的文件名。
要描述一个具体的目标特定类XXXInstrInfo,它表示目标机器支持的机器指令。 XXXInstrInfo包含一个XXXInstrDescriptor对象数组,每个对象描述一条指令。 指令描述符定义:
操作码助记符
操作数的数量
隐式寄存器定义和用途列表
与目标无关的属性(如内存访问,是可交换的)
特定于目标的标志
指令类(在Target.td中定义)主要用作更复杂指令类的基础:

class Instruction {
  string Namespace = "";
  dag OutOperandList;    // A dag containing the MI def operand list.
  dag InOperandList;     // A dag containing the MI use operand list.
  string AsmString = ""; // The .s format to print the instruction with.
  list<dag> Pattern;     // Set to the DAG pattern for this instruction.
  list<Register> Uses = [];
  list<Register> Defs = [];
  list<Predicate> Predicates = [];  // predicates turned into isel match code
  ... remainder not shown for space ...
}

SelectionDAG节点(SDNode)包含一个对象,该对象表示在MipsInstrInfo.td中定义的特定于目标的指令。指令对象应代表来自目标机器的体系结构手册的指令.

体系结构手册中的单个指令通常建模为多个目标指令,具体取决于其操作数。例如,手册可能会描述一个带有寄存器或立即操作数的加法指令。 LLVM目标可以使用名为ADDri和ADDrr的两条指令对其进行建模。

应该为每个指令类别定义一个类,并使用适当的参数(例如操作码和扩展操作码的固定二进制编码)将每个操作码定义为该类别的子类。应该将寄存器位映射到它们编码的指令位(对于JIT)。还应该指定在使用自动装配打印机时如何打印指令。

Mips通用寄存器+指令这是一篇介绍Mips寄存器和指令的博客,写的很好.其中:
指令长度和寄存器个数
MIPS的所有指令都是32位的,指令格式简单。
32 个通用寄存器,寄存器数量跟编译器的的要求有关。寄存器分配在编译优化中是最重要的优化之一(也许是做重要的)。现在的寄存器分配算法都是基于图着色的技 术。其基本思想是构造一个图,用以代表分配寄存器的各个方案,然后用此图来分配寄存器。粗略说来就是使用有限的颜色使图中相临的节点着以不同的颜色,图着 色问题是个图大小的指数函数,有些启发式算法产生近乎线形时间运行的分配。全局分配中如果有16个通用寄存器用于整型变量,同时另有额外的寄存器用于浮点 数,那么图着色会很好的工作。在寄存器数教少时候图着色并不能很好的工作。
指令格式
所有MIPS指令长度相同,都是32位,但为了让指令的格式刚好合适,于是设计者做了一个折衷:所有指令定长,但是不同的指令有不同的格式。MIPS指令有三种格式:R格式,I格式,J格式。每种格式都由若干字段(filed)组成,图示如下:
I型指令
6 5 5 16
   ——|—–|—–|——————|
| op | rs | rt | 立即数操作 |
——|—–|—–|——————|
加载/存储字节,半字,字,双字
条件分支,跳转,跳转并链接寄存器
R型指令
6 5 5 5 5 6
   ——|—–|—–|—–|—–|——--|
|op | rs | rt | rd |shamt|funct |
   ——|—–|—–|—–|—–|——---|
寄存器-寄存器ALU操作
读写专用寄存器
J型指令
6 26
——|——————————|
|op |  跳转地址 |
——|——————————|
跳转,跳转并链接
陷阱和从异常中返回

各字段含义:
op:指令基本操作,称为操作码。
rs:第一个源操作数寄存器。
rt:第二个源操作数寄存器。
rd:存放操作结果的目的操作数。
shamt:位移量
funct:函数,这个字段选择op操作的某个特定变体。
所有指令都按照着三种类型之一来编码,通用字段在每种格式中的位置都是相同的。
这种定长和简单格式的指令编码很规则,很容易看出其机器码,例如:
add t0, t 0 , s0, s1 s 1 表 示 t0= s0+ s 0 + s1,即16号寄存器(s0)的内容和17号寄存器(s1)的内容相加,结果放到8号寄存器(t0)。
指令各字段的十进制表示为
   ——|—–|—–|—–|—–|——|
| 0 | 16 | 17 | 8 | 0 | 32 |
   ——|—–|—–|—–|—–|——|
op=0和funct=32表示这是加法,16= s0(rs)1617= s 0 表 示 第 一 个 源 操 作 数 ( r s ) 在 16 号 寄 存 器 里 , 17 = s1表示第二个源操作数(rt)在17号寄存器里,8=$t0表示目的操作数(rd)在8号寄存器里。
把各字段写成二进制,为
——|—–|—–|—–|—–|——|
|000000|10000|10001|01000|00000|100000|
——|—–|—–|—–|—–|——|
这就是上述指令的机器码(machine code),可以看出是很有规则性的

这些格式中的每一种在SparcInstrFormat.td中都有相应的类。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值