Skip to content
X86InstrInfo.td 68.6 KiB
Newer Older
def IMUL32rri  : Ii32<0x69, MRMSrcReg,                      // R32 = R32*I32
                      (ops R32:$dst, R32:$src1, i32imm:$src2),
                      "imul{l} {$src2, $src1, $dst|$dst, $src1, $src2}">;
def IMUL16rri8 : Ii8<0x6B, MRMSrcReg,                       // R16 = R16*I8
                     (ops R16:$dst, R16:$src1, i8imm:$src2),
                     "imul{w} {$src2, $src1, $dst|$dst, $src1, $src2}">, OpSize;
def IMUL32rri8 : Ii8<0x6B, MRMSrcReg,                       // R32 = R32*I8
                     (ops R32:$dst, R32:$src1, i8imm:$src2),
                     "imul{l} {$src2, $src1, $dst|$dst, $src1, $src2}">;

def IMUL16rmi  : Ii16<0x69, MRMSrcMem,                      // R16 = [mem16]*I16
                      (ops R32:$dst, i16mem:$src1, i16imm:$src2),
                     "imul{w} {$src2, $src1, $dst|$dst, $src1, $src2}">, OpSize;
def IMUL32rmi  : Ii32<0x69, MRMSrcMem,                      // R32 = [mem32]*I32
                      (ops R32:$dst, i32mem:$src1, i32imm:$src2),
                     "imul{l} {$src2, $src1, $dst|$dst, $src1, $src2}">;
def IMUL16rmi8 : Ii8<0x6B, MRMSrcMem,                       // R16 = [mem16]*I8
                     (ops R32:$dst, i16mem:$src1, i8imm :$src2),
                     "imul{w} {$src2, $src1, $dst|$dst, $src1, $src2}">, OpSize;
def IMUL32rmi8 : Ii8<0x6B, MRMSrcMem,                       // R32 = [mem32]*I8
                     (ops R32:$dst, i32mem:$src1, i8imm: $src2),
                     "imul{l} {$src2, $src1, $dst|$dst, $src1, $src2}">;
//===----------------------------------------------------------------------===//
// Test instructions are just like AND, except they don't generate a result.
def TEST8rr  : I<0x84, MRMDestReg, (ops R8:$src1, R8:$src2),
                 "test{b} {$src2, $src1|$src1, $src2}">;
def TEST16rr : I<0x85, MRMDestReg, (ops R16:$src1, R16:$src2),
                 "test{w} {$src2, $src1|$src1, $src2}">, OpSize;
def TEST32rr : I<0x85, MRMDestReg, (ops R32:$src1, R32:$src2),
                 "test{l} {$src2, $src1|$src1, $src2}">;
def TEST8mr  : I<0x84, MRMDestMem, (ops i8mem :$src1, R8 :$src2),
                 "test{b} {$src2, $src1|$src1, $src2}">;
def TEST16mr : I<0x85, MRMDestMem, (ops i16mem:$src1, R16:$src2),
                 "test{w} {$src2, $src1|$src1, $src2}">, OpSize;
def TEST32mr : I<0x85, MRMDestMem, (ops i32mem:$src1, R32:$src2),
                 "test{l} {$src2, $src1|$src1, $src2}">;
def TEST8rm  : I<0x84, MRMSrcMem, (ops R8 :$src1, i8mem :$src2),
                 "test{b} {$src2, $src1|$src1, $src2}">;
def TEST16rm : I<0x85, MRMSrcMem, (ops R16:$src1, i16mem:$src2),
                 "test{w} {$src2, $src1|$src1, $src2}">, OpSize;
def TEST32rm : I<0x85, MRMSrcMem, (ops R32:$src1, i32mem:$src2),
                 "test{l} {$src2, $src1|$src1, $src2}">;
def TEST8ri  : Ii8 <0xF6, MRM0r, (ops R8:$dst, i8imm:$src),
                    "test{b} $dst, $src">;          // flags = R8  & imm8
def TEST16ri : Ii16<0xF7, MRM0r, (ops R16:$dst, i16imm:$src),
                    "test{w} $dst, $src">, OpSize;  // flags = R16 & imm16
def TEST32ri : Ii32<0xF7, MRM0r, (ops R32:$dst, i32imm:$src),
                    "test{l} $dst, $src">;          // flags = R32 & imm32
def TEST8mi  : Ii8 <0xF6, MRM0m, (ops i32mem:$dst, i8imm:$src),
                    "test{b} $dst, $src">;          // flags = [mem8]  & imm8
def TEST16mi : Ii16<0xF7, MRM0m, (ops i16mem:$dst, i16imm:$src),
                    "test{w} $dst, $src">, OpSize;  // flags = [mem16] & imm16
def TEST32mi : Ii32<0xF7, MRM0m, (ops i32mem:$dst, i32imm:$src),
                    "test{l} $dst, $src">;          // flags = [mem32] & imm32
// Condition code ops, incl. set if equal/not equal/...
def SAHF     : I<0x9E, RawFrm, (ops), "sahf">, Imp<[AH],[]>;  // flags = AH
def LAHF     : I<0x9F, RawFrm, (ops), "lahf">, Imp<[],[AH]>;  // AH = flags
def SETBr    : I<0x92, MRM0r,
                 (ops R8   :$dst), "setb $dst">, TB;    // R8 = <  unsign
def SETBm    : I<0x92, MRM0m,
                 (ops i8mem:$dst), "setb $dst">, TB;    // [mem8] = <  unsign
def SETAEr   : I<0x93, MRM0r, 
                 (ops R8   :$dst), "setae $dst">, TB;   // R8 = >= unsign
def SETAEm   : I<0x93, MRM0m, 
                 (ops i8mem:$dst), "setae $dst">, TB;   // [mem8] = >= unsign
def SETEr    : I<0x94, MRM0r, 
                 (ops R8   :$dst), "sete $dst">, TB;    // R8 = ==
def SETEm    : I<0x94, MRM0m, 
                 (ops i8mem:$dst), "sete $dst">, TB;    // [mem8] = ==
def SETNEr   : I<0x95, MRM0r, 
                 (ops R8   :$dst), "setne $dst">, TB;   // R8 = !=
def SETNEm   : I<0x95, MRM0m, 
                 (ops i8mem:$dst), "setne $dst">, TB;   // [mem8] = !=
def SETBEr   : I<0x96, MRM0r, 
                 (ops R8   :$dst), "setbe $dst">, TB;   // R8 = <= unsign
def SETBEm   : I<0x96, MRM0m, 
                 (ops i8mem:$dst), "setbe $dst">, TB;   // [mem8] = <= unsign
def SETAr    : I<0x97, MRM0r, 
                 (ops R8   :$dst), "seta $dst">, TB;    // R8 = >  signed
def SETAm    : I<0x97, MRM0m, 
                 (ops i8mem:$dst), "seta $dst">, TB;    // [mem8] = >  signed
def SETSr    : I<0x98, MRM0r, 
                 (ops R8   :$dst), "sets $dst">, TB;    // R8 = <sign bit>
def SETSm    : I<0x98, MRM0m, 
                 (ops i8mem:$dst), "sets $dst">, TB;    // [mem8] = <sign bit>
def SETNSr   : I<0x99, MRM0r, 
                 (ops R8   :$dst), "setns $dst">, TB;   // R8 = !<sign bit>
def SETNSm   : I<0x99, MRM0m, 
                 (ops i8mem:$dst), "setns $dst">, TB;   // [mem8] = !<sign bit>
def SETPr    : I<0x9A, MRM0r, 
                 (ops R8   :$dst), "setp $dst">, TB;    // R8 = parity
def SETPm    : I<0x9A, MRM0m, 
                 (ops i8mem:$dst), "setp $dst">, TB;    // [mem8] = parity
def SETLr    : I<0x9C, MRM0r, 
                 (ops R8   :$dst), "setl $dst">, TB;    // R8 = <  signed
def SETLm    : I<0x9C, MRM0m, 
                 (ops i8mem:$dst), "setl $dst">, TB;    // [mem8] = <  signed
def SETGEr   : I<0x9D, MRM0r, 
                 (ops R8   :$dst), "setge $dst">, TB;   // R8 = >= signed
def SETGEm   : I<0x9D, MRM0m, 
                 (ops i8mem:$dst), "setge $dst">, TB;   // [mem8] = >= signed
def SETLEr   : I<0x9E, MRM0r, 
                 (ops R8   :$dst), "setle $dst">, TB;   // R8 = <= signed
def SETLEm   : I<0x9E, MRM0m, 
                 (ops i8mem:$dst), "setle $dst">, TB;   // [mem8] = <= signed
def SETGr    : I<0x9F, MRM0r, 
                 (ops R8   :$dst), "setg $dst">, TB;    // R8 = <  signed
def SETGm    : I<0x9F, MRM0m, 
                 (ops i8mem:$dst), "setg $dst">, TB;    // [mem8] = <  signed

// Integer comparisons
def CMP8rr  : I<0x38, MRMDestReg,
                (ops R8 :$src1, R8 :$src2),
                "cmp{b} {$src2, $src1|$src1, $src2}">;
def CMP16rr : I<0x39, MRMDestReg,
                (ops R16:$src1, R16:$src2),
                "cmp{w} {$src2, $src1|$src1, $src2}">, OpSize;
def CMP32rr : I<0x39, MRMDestReg,
                (ops R32:$src1, R32:$src2),
                "cmp{l} {$src2, $src1|$src1, $src2}">;
def CMP8mr  : I<0x38, MRMDestMem,
                (ops i8mem :$src1, R8 :$src2),
                "cmp{b} {$src2, $src1|$src1, $src2}">;
def CMP16mr : I<0x39, MRMDestMem,
                (ops i16mem:$src1, R16:$src2),
                "cmp{w} {$src2, $src1|$src1, $src2}">, OpSize;
def CMP32mr : I<0x39, MRMDestMem,
                (ops i32mem:$src1, R32:$src2),
                "cmp{l} {$src2, $src1|$src1, $src2}">;
def CMP8rm  : I<0x3A, MRMSrcMem,
                (ops R8 :$src1, i8mem :$src2),
                "cmp{b} {$src2, $src1|$src1, $src2}">;
def CMP16rm : I<0x3B, MRMSrcMem,
                (ops R16:$src1, i16mem:$src2),
                "cmp{w} {$src2, $src1|$src1, $src2}">, OpSize;
def CMP32rm : I<0x3B, MRMSrcMem,
                (ops R32:$src1, i32mem:$src2),
                "cmp{l} {$src2, $src1|$src1, $src2}">;
def CMP8ri  : Ii8<0x80, MRM7r,
                  (ops R16:$src1, i8imm:$src2),
                  "cmp{b} {$src2, $src1|$src1, $src2}">;
def CMP16ri : Ii16<0x81, MRM7r,
                   (ops R16:$src1, i16imm:$src2),
                   "cmp{w} {$src2, $src1|$src1, $src2}">, OpSize;
def CMP32ri : Ii32<0x81, MRM7r,
                   (ops R32:$src1, i32imm:$src2),
                   "cmp{l} {$src2, $src1|$src1, $src2}">;
def CMP8mi  : Ii8 <0x80, MRM7m,
                   (ops i8mem :$src1, i8imm :$src2),
                   "cmp{b} {$src2, $src1|$src1, $src2}">;
def CMP16mi : Ii16<0x81, MRM7m,
                   (ops i16mem:$src1, i16imm:$src2),
                   "cmp{w} {$src2, $src1|$src1, $src2}">, OpSize;
def CMP32mi : Ii32<0x81, MRM7m,
                   (ops i32mem:$src1, i32imm:$src2),
                   "cmp{l} {$src2, $src1|$src1, $src2}">;

// Sign/Zero extenders
def MOVSX16rr8 : I<0xBE, MRMSrcReg, (ops R16:$dst, R8 :$src),
                   "movs{bw|x} {$src, $dst|$dst, $src}">, TB, OpSize;
def MOVSX16rm8 : I<0xBE, MRMSrcMem, (ops R16:$dst, i8mem :$src),
                   "movs{bw|x} {$src, $dst|$dst, $src}">, TB, OpSize;
def MOVSX32rr8 : I<0xBE, MRMSrcReg, (ops R32:$dst, R8 :$src),
                   "movs{bl|x} {$src, $dst|$dst, $src}">, TB;
def MOVSX32rm8 : I<0xBE, MRMSrcMem, (ops R32:$dst, i8mem :$src),
                   "movs{bl|x} {$src, $dst|$dst, $src}">, TB;
def MOVSX32rr16: I<0xBF, MRMSrcReg, (ops R32:$dst, R16:$src),
                   "movs{wl|x} {$src, $dst|$dst, $src}">, TB;
def MOVSX32rm16: I<0xBF, MRMSrcMem, (ops R32:$dst, i16mem:$src),
                   "movs{wl|x} {$src, $dst|$dst, $src}">, TB;

def MOVZX16rr8 : I<0xB6, MRMSrcReg, (ops R16:$dst, R8 :$src),
                   "movz{bw|x} {$src, $dst|$dst, $src}">, TB, OpSize;
def MOVZX16rm8 : I<0xB6, MRMSrcMem, (ops R16:$dst, i8mem :$src),
                   "movz{bw|x} {$src, $dst|$dst, $src}">, TB, OpSize;
def MOVZX32rr8 : I<0xB6, MRMSrcReg, (ops R32:$dst, R8 :$src),
                   "movz{bl|x} {$src, $dst|$dst, $src}">, TB;
def MOVZX32rm8 : I<0xB6, MRMSrcMem, (ops R32:$dst, i8mem :$src),
                   "movz{bl|x} {$src, $dst|$dst, $src}">, TB;
def MOVZX32rr16: I<0xB7, MRMSrcReg, (ops R32:$dst, R16:$src),
                   "movz{wl|x} {$src, $dst|$dst, $src}">, TB;
def MOVZX32rm16: I<0xB7, MRMSrcMem, (ops R32:$dst, i16mem:$src),
                   "movz{wl|x} {$src, $dst|$dst, $src}">, TB;


//===----------------------------------------------------------------------===//
// Floating point support
//===----------------------------------------------------------------------===//

// FIXME: These need to indicate mod/ref sets for FP regs... & FP 'TOP'

// Floating point instruction template
class FPI<bits<8> o, Format F, FPFormat fp, dag ops, string asm>
  let FPForm = fp; let FPFormBits = FPForm.Value;
}
// Pseudo instructions for floating point.  We use these pseudo instructions
// because they can be expanded by the fp spackifier into one of many different
// forms of instructions for doing these operations.  Until the stackifier runs,
// we prefer to be abstract.
def FpMOV : FPI<0, Pseudo, SpecialFP,
                (ops RFP, RFP), "">;   // f1 = fmov f2
def FpADD : FPI<0, Pseudo, TwoArgFP ,
                (ops RFP, RFP, RFP), "">;    // f1 = fadd f2, f3
def FpSUB : FPI<0, Pseudo, TwoArgFP ,
                (ops RFP, RFP, RFP), "">;    // f1 = fsub f2, f3
def FpMUL : FPI<0, Pseudo, TwoArgFP ,
                (ops RFP, RFP, RFP), "">;    // f1 = fmul f2, f3
def FpDIV : FPI<0, Pseudo, TwoArgFP ,
                (ops RFP, RFP, RFP), "">;    // f1 = fdiv f2, f3
def FpGETRESULT : FPI<0, Pseudo, SpecialFP, (ops RFP), "">,
                  Imp<[ST0], []>;  // FPR = ST(0)
def FpSETRESULT : FPI<0, Pseudo, SpecialFP, (ops RFP), "">,
                  Imp<[], [ST0]>;  // ST(0) = FPR
// FADD reg, mem: Before stackification, these are represented by:
// R1 = FADD* R2, [mem]
def FADD32m  : FPI<0xD8, MRM0m, OneArgFPRW,    // ST(0) = ST(0) + [mem32real]
                   (ops f32mem:$src), "fadd{s} $src">;
def FADD64m  : FPI<0xDC, MRM0m, OneArgFPRW,    // ST(0) = ST(0) + [mem64real]
                   (ops f64mem:$src), "fadd{l} $src">;
//def FIADD16m : FPI<0xDE, MRM0m, OneArgFPRW>;    // ST(0) = ST(0) + [mem16int]
//def FIADD32m : FPI<0xDA, MRM0m, OneArgFPRW>;    // ST(0) = ST(0) + [mem32int]
// FMUL reg, mem: Before stackification, these are represented by:
// R1 = FMUL* R2, [mem]
def FMUL32m  : FPI<0xD8, MRM1m, OneArgFPRW,    // ST(0) = ST(0) * [mem32real]
                   (ops f32mem:$src), "fmul{s} $src">;
def FMUL64m  : FPI<0xDC, MRM1m, OneArgFPRW,    // ST(0) = ST(0) * [mem64real]
                   (ops f64mem:$src), "fmul{l} $src">;
// ST(0) = ST(0) * [mem16int]
//def FIMUL16m : FPI16m<"fimul", 0xDE, MRM1m, OneArgFPRW>;
// ST(0) = ST(0) * [mem32int]
//def FIMUL32m : FPI32m<"fimul", 0xDA, MRM1m, OneArgFPRW>;

// FSUB reg, mem: Before stackification, these are represented by:
// R1 = FSUB* R2, [mem]
def FSUB32m  : FPI<0xD8, MRM4m, OneArgFPRW,    // ST(0) = ST(0) - [mem32real]
                   (ops f32mem:$src), "fsub{s} $src">;
def FSUB64m  : FPI<0xDC, MRM4m, OneArgFPRW,    // ST(0) = ST(0) - [mem64real]
                   (ops f64mem:$src), "fsub{l} $src">;
// ST(0) = ST(0) - [mem16int]
//def FISUB16m : FPI16m<"fisub", 0xDE, MRM4m, OneArgFPRW>;
// ST(0) = ST(0) - [mem32int]
//def FISUB32m : FPI32m<"fisub", 0xDA, MRM4m, OneArgFPRW>;

// FSUBR reg, mem: Before stackification, these are represented by:
// R1 = FSUBR* R2, [mem]

// Note that the order of operands does not reflect the operation being
// performed.
def FSUBR32m  : FPI<0xD8, MRM5m, OneArgFPRW,  // ST(0) = [mem32real] - ST(0)
                    (ops f32mem:$src), "fsubr{s} $src">;
def FSUBR64m  : FPI<0xDC, MRM5m, OneArgFPRW,  // ST(0) = [mem64real] - ST(0)
                    (ops f64mem:$src), "fsubr{l} $src">;
// ST(0) = [mem16int] - ST(0)
//def FISUBR16m : FPI16m<"fisubr", 0xDE, MRM5m, OneArgFPRW>;
// ST(0) = [mem32int] - ST(0)
//def FISUBR32m : FPI32m<"fisubr", 0xDA, MRM5m, OneArgFPRW>;

// FDIV reg, mem: Before stackification, these are represented by:
// R1 = FDIV* R2, [mem]
def FDIV32m  : FPI<0xD8, MRM6m, OneArgFPRW,    // ST(0) = ST(0) / [mem32real]
                   (ops f32mem:$src), "fdiv{s} $src">;
def FDIV64m  : FPI<0xDC, MRM6m, OneArgFPRW,    // ST(0) = ST(0) / [mem64real]
                   (ops f64mem:$src), "fdiv{l} $src">;
// ST(0) = ST(0) / [mem16int]
//def FIDIV16m : FPI16m<"fidiv", 0xDE, MRM6m, OneArgFPRW>;
// ST(0) = ST(0) / [mem32int]
//def FIDIV32m : FPI32m<"fidiv", 0xDA, MRM6m, OneArgFPRW>;

// FDIVR reg, mem: Before stackification, these are represented by:
// R1 = FDIVR* R2, [mem]
// Note that the order of operands does not reflect the operation being
// performed.
def FDIVR32m  : FPI<0xD8, MRM7m, OneArgFPRW,  // ST(0) = [mem32real] / ST(0)
                    (ops f32mem:$src), "fdivr{s} $src">;
def FDIVR64m  : FPI<0xDC, MRM7m, OneArgFPRW,  // ST(0) = [mem64real] / ST(0)
                    (ops f64mem:$src), "fdivr{l} $src">;
// ST(0) = [mem16int] / ST(0)
//def FIDIVR16m : FPI16m<"fidivr", 0xDE, MRM7m, OneArgFPRW>;
// ST(0) = [mem32int] / ST(0)
//def FIDIVR32m : FPI32m<"fidivr", 0xDA, MRM7m, OneArgFPRW>;
let isTwoAddress = 1, Uses = [ST0], Defs = [ST0] in {
  def FCMOVB  : FPI<0xC0, AddRegFrm, CondMovFP,
                    (ops RST:$op), "fcmovb {$op, %ST(0)|%ST(0), $op}">, DA;
  def FCMOVBE : FPI<0xD0, AddRegFrm, CondMovFP,
                    (ops RST:$op), "fcmovbe {$op, %ST(0)|%ST(0), $op}">, DA;
  def FCMOVE  : FPI<0xC8, AddRegFrm, CondMovFP,
                    (ops RST:$op), "fcmove {$op, %ST(0)|%ST(0), $op}">, DA;
  def FCMOVAE : FPI<0xC0, AddRegFrm, CondMovFP,
                    (ops RST:$op), "fcmovae {$op, %ST(0)|%ST(0), $op}">, DB;
  def FCMOVA  : FPI<0xD0, AddRegFrm, CondMovFP,
                    (ops RST:$op), "fcmova {$op, %ST(0)|%ST(0), $op}">, DB;
  def FCMOVNE : FPI<0xC8, AddRegFrm, CondMovFP,
                    (ops RST:$op), "fcmovne {$op, %ST(0)|%ST(0), $op}">, DB;
// Floating point loads & stores...
def FLDrr   : FPI<0xC0, AddRegFrm, NotFP, (ops    RST:$src), "fld $src">, D9;
def FLD32m  : FPI<0xD9, MRM0m, ZeroArgFP, (ops f32mem:$src), "fld{s} $src">;
def FLD64m  : FPI<0xDD, MRM0m, ZeroArgFP, (ops f64mem:$src), "fld{l} $src">;
def FLD80m  : FPI<0xDB, MRM5m, ZeroArgFP, (ops f80mem:$src), "fld{t} $src">;
def FILD16m : FPI<0xDF, MRM0m, ZeroArgFP, (ops i16mem:$src), "fild{s} $src">;
def FILD32m : FPI<0xDB, MRM0m, ZeroArgFP, (ops i32mem:$src), "fild{l} $src">;
def FILD64m : FPI<0xDF, MRM5m, ZeroArgFP, (ops i64mem:$src), "fild{t} $src">;

def FSTrr    : FPI<0xD0, AddRegFrm, NotFP, (ops RST:$op), "fst $op">, DD;
def FSTPrr   : FPI<0xD8, AddRegFrm, NotFP, (ops RST:$op), "fstp $op">, DD;
def FST32m   : FPI<0xD9, MRM2m, OneArgFP, (ops f32mem:$op), "fst{s} $op">;
def FST64m   : FPI<0xDD, MRM2m, OneArgFP, (ops f64mem:$op), "fst{l} $op">;
def FSTP32m  : FPI<0xD9, MRM3m, OneArgFP, (ops f32mem:$op), "fstp{s} $op">;
def FSTP64m  : FPI<0xDD, MRM3m, OneArgFP, (ops f64mem:$op), "fstp{l} $op">;
def FSTP80m  : FPI<0xDB, MRM7m, OneArgFP, (ops f80mem:$op), "fstp{t} $op">;

def FIST16m  : FPI<0xDF, MRM2m , OneArgFP, (ops i16mem:$op), "fist{s} $op">;
def FIST32m  : FPI<0xDB, MRM2m , OneArgFP, (ops i32mem:$op), "fist{l} $op">;
def FISTP16m : FPI<0xDF, MRM3m , NotFP   , (ops i16mem:$op), "fistp{s} $op">;
def FISTP32m : FPI<0xDB, MRM3m , NotFP   , (ops i32mem:$op), "fistp{l} $op">;
def FISTP64m : FPI<0xDF, MRM7m , OneArgFP, (ops i64mem:$op), "fistp{ll} $op">;
def FXCH     : FPI<0xC8, AddRegFrm, NotFP,
                   (ops RST:$op), "fxch $op">, D9;      // fxch ST(i), ST(0)

// Floating point constant loads...
def FLD0 : FPI<0xEE, RawFrm, ZeroArgFP, (ops), "fldz">, D9;
def FLD1 : FPI<0xE8, RawFrm, ZeroArgFP, (ops), "fld1">, D9;
Chris Lattner's avatar
Chris Lattner committed
// Unary operations...
def FCHS : FPI<0xE0, RawFrm, OneArgFPRW, (ops), "fchs">, D9;   // f1 = fchs f2
def FTST : FPI<0xE4, RawFrm, OneArgFP, (ops), "ftst">, D9;     // ftst ST(0)
// Binary arithmetic operations...
class FPST0rInst<bits<8> o, dag ops, string asm>
  : I<o, AddRegFrm, ops, asm>, D8 {
  list<Register> Uses = [ST0];
  list<Register> Defs = [ST0];
}
class FPrST0Inst<bits<8> o, dag ops, string asm>
  : I<o, AddRegFrm, ops, asm>, DC {
  list<Register> Uses = [ST0];
}
class FPrST0PInst<bits<8> o, dag ops, string asm>
  : I<o, AddRegFrm, ops, asm>, DE {
  list<Register> Uses = [ST0];
}

def FADDST0r   : FPST0rInst <0xC0, (ops RST:$op),
                             "fadd $op">;
def FADDrST0   : FPrST0Inst <0xC0, (ops RST:$op),
                             "fadd {%ST(0), $op|$op, %ST(0)}">;
def FADDPrST0  : FPrST0PInst<0xC0, (ops RST:$op),
                             "faddp $op">;

def FSUBRST0r  : FPST0rInst <0xE8, (ops RST:$op),
                             "fsubr $op">;
def FSUBrST0   : FPrST0Inst <0xE8, (ops RST:$op),
                             "fsub {%ST(0), $op|$op, %ST(0)}">;
def FSUBPrST0  : FPrST0PInst<0xE8, (ops RST:$op),
                             "fsubp $op">;

def FSUBST0r   : FPST0rInst <0xE0, (ops RST:$op),
                             "fsub $op">;
def FSUBRrST0  : FPrST0Inst <0xE0, (ops RST:$op),
                             "fsubr {%ST(0), $op|$op, %ST(0)}">;
def FSUBRPrST0 : FPrST0PInst<0xE0, (ops RST:$op),
                             "fsubrp $op">;

def FMULST0r   : FPST0rInst <0xC8, (ops RST:$op),
                             "fmul $op">;
def FMULrST0   : FPrST0Inst <0xC8, (ops RST:$op),
                             "fmul {%ST(0), $op|$op, %ST(0)}">;
def FMULPrST0  : FPrST0PInst<0xC8, (ops RST:$op),
                             "fmulp $op">;

def FDIVRST0r  : FPST0rInst <0xF8, (ops RST:$op),
                             "fdivr $op">;
def FDIVrST0   : FPrST0Inst <0xF8, (ops RST:$op),
                             "fdiv {%ST(0), $op|$op, %ST(0)}">;
def FDIVPrST0  : FPrST0PInst<0xF8, (ops RST:$op),
                             "fdivp $op">;

def FDIVST0r   : FPST0rInst <0xF0, (ops RST:$op),  // ST(0) = ST(0) / ST(i)
                             "fdiv $op">;
def FDIVRrST0  : FPrST0Inst <0xF0, (ops RST:$op),  // ST(i) = ST(0) / ST(i)
                             "fdivr {%ST(0), $op|$op, %ST(0)}">;
def FDIVRPrST0 : FPrST0PInst<0xF0, (ops RST:$op),  // ST(i) = ST(0) / ST(i), pop
                             "fdivrp $op">;

// Floating point compares
def FUCOMr    : FPI<0xE0, AddRegFrm, CompareFP,   // FPSW = cmp ST(0) with ST(i)
                    (ops RST:$reg),
                    "fucom $reg">, DD, Imp<[ST0],[]>;
def FUCOMPr   : I<0xE8, AddRegFrm,
                  (ops RST:$reg),           // FPSW = cmp ST(0) with ST(i), pop
                  "fucomp $reg">, DD, Imp<[ST0],[]>;
def FUCOMPPr  : I<0xE9, RawFrm,
                  (ops),                    // cmp ST(0) with ST(1), pop, pop
                  "fucompp">, DA, Imp<[ST0],[]>;

def FUCOMIr  : FPI<0xE8, AddRegFrm, CompareFP,  // CC = cmp ST(0) with ST(i)
                   (ops RST:$reg),
                   "fucomi {$reg, %ST(0)|%ST(0), $reg}">, DB, Imp<[ST0],[]>;
def FUCOMIPr : I<0xE8, AddRegFrm,              // CC = cmp ST(0) with ST(i), pop
                 (ops RST:$reg),
                 "fucomip {$reg, %ST(0)|%ST(0), $reg}">, DF, Imp<[ST0],[]>;
// Floating point flag ops
def FNSTSW8r  : I<0xE0, RawFrm,                  // AX = fp flags
                  (ops), "fnstsw">, DF, Imp<[],[AX]>;
def FNSTCW16m : I<0xD9, MRM7m,                   // [mem16] = X87 control world
                  (ops i16mem:$dst), "fnstcw $dst">;
def FLDCW16m  : I<0xD9, MRM5m,                   // X87 control world = [mem16]
                  (ops i16mem:$dst), "fldcw $dst">;