|  | // This test describes how we eventually want to describe instructions in | 
|  | // the target independent code generators. | 
|  | // RUN: llvm-tblgen %s | 
|  | // XFAIL: vg_leak | 
|  |  | 
|  | // 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. | 
|  | 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 apart. | 
|  | 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))]>; | 
|  |  |