3.10. X86折叠表的生成(v7.0)
指令折叠是在寄存器分配过程中执行的优化,目的是删除不必要的拷贝指令。例如,这样的一组指令:
%EBX = LOAD %mem_address
%EAX = COPY %EBX
可以被安全地替换为单条指令:
%EAX = LOAD %mem_address
通常,后者较前者更小,更快。
在X86中,许多指令有内存形式与寄存器形式,即通过内存或寄存器传递操作数。为了执行指令折叠优化,需要某种方式将这两种形式的同一条指令关联起来。目前LLVM维护了几张体量庞大的表用于关联这些指令。
Intel以色列的雇员Ayman Musa开发了这部分的codegen,希望能通过TableGen自动生成这些表。不过这部分代码目前因为尚有bug,没有默认生成。这里有关于这个bug的描述。
总的来说,这是因为Musa的主要假设是同一条指令的这两个形式共享相同的编码信息,除了负责“如何向指令传递参数”的部分,其中一个版本定义其中一个参数是寄存器,另一个版本定义它为内存操作数,而其他参数以相同方式传递。
但实际上,某些指令在寄存器与内存形式间有不同与上面假设的情形,例如bt(比特测试)指令,其寄存器形式寄存器参数相关比特是第4、5、6比特(依赖于模式与寄存器大小),而内存形式相关比特是第16、32或64比特。
这导致了编译错误。Musa建议特别处理这些指令。目前,这部分的codegen默认是关闭的,防止X86加入新指令时导致生成错误的表。可以在编译llvm时使用选项X86_GEN_FOLD_TABLES=ON来打开这个codegen。
与这个codegen相关,在td层面,在X86Inst定义里原有isMemoryFoldable域,它缺省设置为1。后来又添加了一个类:class NotMemoryFoldable { bit isMemoryFoldable = 0; },所有不能折叠的指令使用它作为一个基类(它与X86inst原有的isMemoryFoldable是重复的,TableGen比较奇怪,域可以重复声明,反正最后出现的获胜。因此有时会出现有点难看的扩展)。
561 void X86FoldTablesEmitter::run(raw_ostream &OS) {
562 emitSourceFileHeader("X86 fold tables", OS);
563
564 // Holds all memory instructions
565 std::vector<const CodeGenInstruction *> MemInsts;
566 // Holds all register instructions - divided according to opcode.
567 std::map<uint8_t, std::vector<const CodeGenInstruction *>> RegInsts;
568
569 ArrayRef<const CodeGenInstruction *> NumberedInstructions =
570 Target.getInstructionsByEnumValue();
571
572 for (const CodeGenInstruction *Inst : NumberedInstructions) {
573 if (!Inst->TheDef->getNameInit() || !Inst->TheDef->isSubClassOf("X86Inst"))
574 continue;
575
576 const Record *Rec = Inst->TheDef;
577
578 // - Do not proceed if the instruction is marked as notMemoryFoldable.
579 // - Instructions including RST register class operands are not relevant
580 // for memory folding (for further details check the explanation in
581 // lib/Target/X86/X86InstrFPStack.td file).
582 // - Some instructions (listed in the manual map above) use the register
583 // class ptr_rc_tailcall, which can be of a size 32 or 64, to ensure
584 // safe mapping of these instruction we manually map them and exclude
585 // them from the automation.
586 if (Rec->getValueAsBit("isMemoryFoldable") == false ||
587 hasRSTRegClass(Inst) || hasPtrTailcallRegClass(Inst))
588 continue;
589
590 // Add all the memory form instructions to