diff --git a/test/TableGen/TargetInstrInfo.td b/test/TableGen/TargetInstrInfo.td new file mode 100644 index 00000000000..bbee7430f5d --- /dev/null +++ b/test/TableGen/TargetInstrInfo.td @@ -0,0 +1,148 @@ +// This test describes how we eventually want to describe instructions in +// the target independent code generators. +// RUN: tblgen %s + +// Target indep stuff. +class Instruction { // Would have other stuff eventually + bit isTwoAddress = 0; + string AssemblyString; +} +class RegisterClass; + +class RTLNode; + +def ops; // Marker for operand list. + +// Various expressions used in RTL descriptions. +def imm8 : RTLNode; +def imm32 : RTLNode; +def addr : RTLNode; + +def set : RTLNode; +def signext : RTLNode; +def zeroext : RTLNode; +def plus : RTLNode; +def and : RTLNode; +def xor : RTLNode; +def shl : RTLNode; +def load : RTLNode; +def store : RTLNode; +def unspec : RTLNode; + +// Start of X86 specific stuff. + +def R8 : RegisterClass; +def R16 : RegisterClass; +def R32 : RegisterClass; + +def CL; // As are currently defined +def AL; +def AX; +def EDX; + +class Format val> { + bits<5> Value = val; +} + +def Pseudo : Format<0>; def RawFrm : Format<1>; +def AddRegFrm : Format<2>; def MRMDestReg : Format<3>; +def MRMDestMem : Format<4>; def MRMSrcReg : Format<5>; +def MRMSrcMem : Format<6>; +def MRM0r : Format<16>; def MRM1r : Format<17>; def MRM2r : Format<18>; +def MRM3r : Format<19>; def MRM4r : Format<20>; def MRM5r : Format<21>; +def MRM6r : Format<22>; def MRM7r : Format<23>; +def MRM0m : Format<24>; def MRM1m : Format<25>; def MRM2m : Format<26>; +def MRM3m : Format<27>; def MRM4m : Format<28>; def MRM5m : Format<29>; +def MRM6m : Format<30>; def MRM7m : Format<31>; + + +class Inst opcode, + Format f, list rtl> : Instruction { + dag Operands = opnds; + string AssemblyString = asmstr; + bits<8> Opcode = opcode; + Format Format = f; + list RTL = rtl; +} + + +// Start of instruction definitions, the real point of this file. +// +// Note that these patterns show a couple of important things: +// 1. The order and contents of the operands of the MachineInstr are +// described here. Eventually we can do away with this when everything +// is generated from the description. +// 2. The asm string is captured here, which makes it possible to get rid of +// a ton of hacks in the various printers and a bunch of flags. +// 3. Target specific properties (e.g. Format) can still be captured as +// needed. +// 4. We capture the behavior of the instruction with a simplified RTL-like +// expression. +// 5. The use/def properties for each operand are automatically inferred from +// the pattern. +// 6. Address expressions should become first-class entities. + +// Simple copy instruction. isMoveInstr could easily be inferred from this, +// as could MRegisterInfo::copyRegToReg. +def MOV8rr : Inst<(ops R8:$dst, R8:$src), + "mov $dst, $src", 0x88, MRMDestReg, + [(set R8:$dst, R8:$src)]>; + +// Simple immediate initialization. +def MOV8ri : Inst<(ops R8:$dst, imm8:$src), + "mov $dst, $src", 0xB0, AddRegFrm, + [(set R8:$dst, imm8:$src)]>; + +// Two address instructions are described as three-addr instructions, with +// the special target-independent isTwoAddress flag set. The asm pattern +// should not refer to the $src1, this would be enforced by the +// TargetInstrInfo tablegen backend. +let isTwoAddress = 1 in +def AND8rr : Inst<(ops R8:$dst, R8:$src1, R8:$src2), + "and $dst, $src2", 0x20, MRMDestReg, + [(set R8:$dst, (and R8:$src1, R8:$src2))]>; + +// Instructions that have explicit uses/defs make them explicit in the RTL. +// Instructions that need extra stuff emitted in the assembly can, trivially. +let isTwoAddress = 1 in +def SHL32rCL : Inst<(ops R32:$dst, R32:$src), + "shl $dst, CL", 0xD2, MRM4r, + [(set R32:$dst, (shl R32:$src, CL))]>; + +// The RTL list is a list, allowing complex instructions to be defined easily. +// Temporary 'internal' registers can be used to break instructions appart. +let isTwoAddress = 1 in +def XOR32mi : Inst<(ops addr:$addr, imm32:$imm), + "xor $dst, $src2", 0x81, MRM6m, + [(set R32:$tmp1, (load addr:$addr)), + (set R32:$tmp2, (xor R32:$tmp1, imm32:$imm)), + (store addr:$addr, R32:$tmp2)]>; + +// Alternatively, if each tmporary register is only used once, the instruction +// can just be described in nested form. This would be the canonical +// representation the target generator would convert the above into. Pick your +// favorite indentation scheme. +let isTwoAddress = 1 in +def AND32mr : Inst<(ops addr:$addr, R32:$src), + "xor $dst, $src2", 0x81, MRM6m, + [(store addr:$addr, + (and + (load addr:$addr), + R32:$src) + ) + ]>; + +// Describing complex instructions is not too hard! Note how implicit uses/defs +// become explicit here. +def CBW : Inst<(ops), + "cbw", 0x98, RawFrm, + [(set AX, (signext AL))]>; + +// Noop, does nothing. +def NOOP : Inst<(ops), "nop", 0x90, RawFrm, []>; + + +// Instructions that don't expect optimization can use unspec. +def IN8rr : Inst<(ops), "in AL, EDX", 0xEC, RawFrm, + [(set AL, (unspec EDX))]>; +