// 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<bits<5> 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<dag opnds, string asmstr, bits<8> opcode, Format f, list<dag> rtl> : Instruction { dag Operands = opnds; string AssemblyString = asmstr; bits<8> Opcode = opcode; Format Format = f; list<dag> 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 TargetRegisterInfo::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))]>;