2.2.4. 匹配模板
在Instruction定义的333行,成员Pattern描述了该指令匹配怎么样的SelectionDAG结构。这是一个list类型,因此存在一条指令匹配多个dag结构的可能。在上面的例子中,这部分就是312~315行的dag。LLVM将对这样的dag生成movq2dq\t{$src, $dst|$dst, $src}形式的汇编代码(实际上,指令选择会生成一个MachineSDNode实例,其操作码是指令TD定义的名字,如上面的MMX_MOVQ2DQrr,其他TableGen过程会导出同名的枚举值以供使用)。
2.2.4.1. SDNode
C++类SDNode是构成LLVM的指令选择器所使用的DAG的节点。在TableGen根据TD文件为指令选择生成的代码中,其核心函数SelectCode就具有原型:SDNode *SelectCode(SDNode *N),参数N是要进行指令选择的IR形式的DAG,返回值也是SDNode类型,即选中的指令。
TableGen不能直接使用C++类,与之对应,它也有自己的SDNode定义。它主要作为dag值的操作符,描述这个dag所代表的操作、操作数,SDNode派生自TD类SDPatternOperator(这是一个空类。在v7.0中将下面303行的Properties移进了这个类)。(在LLVM里,SDNode的定义出现在两处:一是在SelectDAGNodes.h里,是一个C++类。另一处在TargetSelectionDAG.td。每个SelectionDAG节点类型都有一个对应的SDNode定义)。
298 class SDNode<string opcode, SDTypeProfile typeprof,
299 list<SDNodeProperty> props = [], string sdclass = "SDNode">
300 : SDPatternOperator {
301 string Opcode = opcode;
302 string SDClass = sdclass;
303 list<SDNodeProperty> Properties = props;
304 SDTypeProfile TypeProfile = typeprof;
305 }
虽然TD语言有类似C++的语法,但它更类似于一个函数式语言,或者说更类似于C++的泛型形式,所有类型一旦声明(定义)就不能更改。要表示新的信息,就必须定义新的类,或具现一个尚未存在的模板实例。
2.2.4.1.1. 类型的描述
在上面的SDNode定义里,参数typeprof用来描述这个SDNode的类型要求。其类型SDTypeProfile的定义如下。它用于描述操作的“类型”。
93 class SDTypeProfile<int numresults, int numoperands,
94 list<SDTypeConstraint> constraints> {
95 int NumResults = numresults;
96 int NumOperands = numoperands;
97 list<SDTypeConstraint> Constraints = constraints;
98 }
很显然NumResults与NumOperands分别说明有几个结果及几个操作数,其中如果NumOperands是-1,则表示操作数的数目不定。Constraints则描述了对操作数类型的约束,SDTypeConstraint是一个简单的类。
22 class SDTypeConstraint<int opnum> {
23 int OperandNum = opnum;
24 }
OperandNum指明该约束适用第几个操作数。显然这个类是不足够的,需要高级一点的派生类,于是就有了下面的定义:
27 class SDTCisVT<int OpNum, ValueType vt> : SDTypeConstraint<OpNum> {
28 ValueType VT = vt;
29 }
这个定义表示OpNum所指向操作数必须具有指定的VT(ValueType)类型。
31 class SDTCisPtrTy<int OpNum> : SDTypeConstraint<OpNum>;
这个定义表示OpNum所指向操作数的类型是指针。
34 class SDTCisInt<int OpNum> : SDTypeConstraint<OpNum>;
这个定义表示OpNum所指向操作数的类型是整形。
37 class SDTCisFP<int OpNum> : SDTypeConstraint<OpNum>;
这个定义表示OpNum所指向操作数的类型是浮点类型。
40 class SDTCisVec<int OpNum> : SDTypeConstraint<OpNum>;
这个定义表示OpNum所指向操作数的类型是向量。
43 class SDTCisSameAs<int OpNum, int OtherOp> : SDTypeConstraint<OpNum> {
44 int OtherOperandNum = OtherOp;
45 }
这个定义表示OpNum所指定操作数与OtherOp所指定的操作数具有相同的类型。
49 class SDTCisVTSmallerThanOp<int OpNum, int OtherOp> : SDTypeConstraint<OpNum> {
50 int OtherOperandNum = OtherOp;
51 }
这个定义表示OpNum所指定操作数必须是VT派生类型,OtherOp所指定操作数则是整形,且前者的长度小于后者。
53 class SDTCisOpSmallerThanOp<int SmallOp, int BigOp> : SDTypeConstraint<SmallOp>{
54 int BigOperandNum = BigOp;
55 }
这个定义表示SmallOp与BigOp类型相同(注意不限定操作数必须VT类型),但前者的长度小于后者。
59 class SDTCisEltOfVec<int ThisOp, int OtherOp>
60 : SDTypeConstraint<ThisOp> {
61 int OtherOpNum = OtherOp;
62 }
这个定义表示ThisOp指定的操作数与OtherOp指定向量的元素具有相同的标量类型。
66 class SDTCisSubVecOfVec<int ThisOp, int OtherOp>