def SDT_X86CallSeqEnd : SDTypeProfile<0, 2, [ SDTCisVT<0, i32>,
SDTCisVT<1, i32> ]>;
-def SDT_X86Call : SDTypeProfile<0, 1, [SDTCisVT<0, i32>]>;
+def SDT_X86Call : SDTypeProfile<0, 1, [SDTCisVT<0, iPTR>]>;
def SDTX86RepStr : SDTypeProfile<0, 1, [SDTCisVT<0, OtherVT>]>;
def X86shrd : SDNode<"X86ISD::SHRD", SDTIntShiftDOp>;
def X86cmp : SDNode<"X86ISD::CMP" , SDTX86CmpTest,
- [SDNPOutFlag]>;
-def X86test : SDNode<"X86ISD::TEST", SDTX86CmpTest,
- [SDNPOutFlag]>;
+ [SDNPHasChain, SDNPOutFlag]>;
def X86cmov : SDNode<"X86ISD::CMOV", SDTX86Cmov,
[SDNPInFlag, SDNPOutFlag]>;
def X86callseq_start :
SDNode<"ISD::CALLSEQ_START", SDT_X86CallSeqStart,
- [SDNPHasChain]>;
+ [SDNPHasChain, SDNPOutFlag]>;
def X86callseq_end :
SDNode<"ISD::CALLSEQ_END", SDT_X86CallSeqEnd,
[SDNPHasChain, SDNPInFlag, SDNPOutFlag]>;
def X86rdtsc : SDNode<"X86ISD::RDTSC_DAG",SDTX86RdTsc,
[SDNPHasChain, SDNPOutFlag]>;
-def X86Wrapper : SDNode<"X86ISD::Wrapper", SDTX86Wrapper>;
+def X86Wrapper : SDNode<"X86ISD::Wrapper", SDTX86Wrapper>;
+def X86WrapperRIP : SDNode<"X86ISD::WrapperRIP", SDTX86Wrapper>;
//===----------------------------------------------------------------------===//
// X86 Operand Definitions.
//
class X86MemOperand<string printMethod> : Operand<iPTR> {
let PrintMethod = printMethod;
- let NumMIOperands = 4;
- let MIOperandInfo = (ops GR32, i8imm, GR32, i32imm);
+ let MIOperandInfo = (ops ptr_rc, i8imm, ptr_rc, i32imm);
}
def i8mem : X86MemOperand<"printi8mem">;
def f64mem : X86MemOperand<"printf64mem">;
def f128mem : X86MemOperand<"printf128mem">;
+def lea32mem : Operand<i32> {
+ let PrintMethod = "printi32mem";
+ let MIOperandInfo = (ops GR32, i8imm, GR32, i32imm);
+}
+
def SSECC : Operand<i8> {
let PrintMethod = "printSSECC";
}
//
// Define X86 specific addressing mode.
-def addr : ComplexPattern<iPTR, 4, "SelectAddr", []>;
-def leaaddr : ComplexPattern<iPTR, 4, "SelectLEAAddr",
- [add, mul, shl, or, frameindex]>;
+def addr : ComplexPattern<iPTR, 4, "SelectAddr", [], []>;
+def lea32addr : ComplexPattern<i32, 4, "SelectLEAAddr",
+ [add, mul, shl, or, frameindex], []>;
//===----------------------------------------------------------------------===//
// X86 Instruction Format Definitions.
//===----------------------------------------------------------------------===//
// X86 Instruction Predicate Definitions.
-def HasMMX : Predicate<"Subtarget->hasMMX()">;
-def HasSSE1 : Predicate<"Subtarget->hasSSE1()">;
-def HasSSE2 : Predicate<"Subtarget->hasSSE2()">;
-def HasSSE3 : Predicate<"Subtarget->hasSSE3()">;
-def FPStack : Predicate<"!Subtarget->hasSSE2()">;
+def HasMMX : Predicate<"Subtarget->hasMMX()">;
+def HasSSE1 : Predicate<"Subtarget->hasSSE1()">;
+def HasSSE2 : Predicate<"Subtarget->hasSSE2()">;
+def HasSSE3 : Predicate<"Subtarget->hasSSE3()">;
+def FPStack : Predicate<"!Subtarget->hasSSE2()">;
+def In32BitMode : Predicate<"!Subtarget->is64Bit()">;
+def In64BitMode : Predicate<"Subtarget->is64Bit()">;
+def SmallCode : Predicate<"TM.getCodeModel() == CodeModel::Small">;
+def NotSmallCode : Predicate<"TM.getCodeModel() != CodeModel::Small">;
+def IsStatic : Predicate<"TM.getRelocationModel() == Reloc::Static">;
//===----------------------------------------------------------------------===//
// X86 specific pattern fragments.
// ImmType - This specifies the immediate type used by an instruction. This is
// part of the ad-hoc solution used to emit machine instruction encodings by our
// machine code emitter.
-class ImmType<bits<2> val> {
- bits<2> Value = val;
+class ImmType<bits<3> val> {
+ bits<3> Value = val;
}
def NoImm : ImmType<0>;
def Imm8 : ImmType<1>;
def Imm16 : ImmType<2>;
def Imm32 : ImmType<3>;
+def Imm64 : ImmType<4>;
// FPFormat - This specifies what form this FP instruction has. This is used by
// the Floating-Point stackifier pass.
Format Form = f;
bits<6> FormBits = Form.Value;
ImmType ImmT = i;
- bits<2> ImmTypeBits = ImmT.Value;
+ bits<3> ImmTypeBits = ImmT.Value;
dag OperandList = ops;
string AsmString = AsmStr;
//
// Attributes specific to X86 instructions...
//
- bit hasOpSizePrefix = 0; // Does this inst have a 0x66 prefix?
+ bit hasOpSizePrefix = 0; // Does this inst have a 0x66 prefix?
+ bit hasAdSizePrefix = 0; // Does this inst have a 0x67 prefix?
bits<4> Prefix = 0; // Which prefix byte does this inst have?
+ bit hasREX_WPrefix = 0; // Does this inst requires the REX.W prefix?
FPFormat FPForm; // What flavor of FP instruction is this?
bits<3> FPFormBits = 0;
}
-class Imp<list<Register> uses, list<Register> defs> {
- list<Register> Uses = uses;
- list<Register> Defs = defs;
-}
-
// Prefix byte classes which are used to indicate to the ad-hoc machine code
// emitter that various prefix bytes are required.
class OpSize { bit hasOpSizePrefix = 1; }
+class AdSize { bit hasAdSizePrefix = 1; }
+class REX_W { bit hasREX_WPrefix = 1; }
class TB { bits<4> Prefix = 1; }
class REP { bits<4> Prefix = 2; }
class D8 { bits<4> Prefix = 3; }
return (int32_t)N->getValue() == (int8_t)N->getValue();
}]>;
-def i16immZExt8 : PatLeaf<(i16 imm), [{
- // i16immZExt8 predicate - True if the 16-bit immediate fits in a 8-bit zero
- // extended field.
- return (uint16_t)N->getValue() == (uint8_t)N->getValue();
-}]>;
-
// Helper fragments for loads.
-def loadiPTR : PatFrag<(ops node:$ptr), (iPTR (load node:$ptr))>;
-
def loadi8 : PatFrag<(ops node:$ptr), (i8 (load node:$ptr))>;
def loadi16 : PatFrag<(ops node:$ptr), (i16 (load node:$ptr))>;
def loadi32 : PatFrag<(ops node:$ptr), (i32 (load node:$ptr))>;
def loadf32 : PatFrag<(ops node:$ptr), (f32 (load node:$ptr))>;
def loadf64 : PatFrag<(ops node:$ptr), (f64 (load node:$ptr))>;
-def sextloadi16i1 : PatFrag<(ops node:$ptr), (i16 (sextload node:$ptr, i1))>;
-def sextloadi32i1 : PatFrag<(ops node:$ptr), (i32 (sextload node:$ptr, i1))>;
-def sextloadi16i8 : PatFrag<(ops node:$ptr), (i16 (sextload node:$ptr, i8))>;
-def sextloadi32i8 : PatFrag<(ops node:$ptr), (i32 (sextload node:$ptr, i8))>;
-def sextloadi32i16 : PatFrag<(ops node:$ptr), (i32 (sextload node:$ptr, i16))>;
-
-def zextloadi8i1 : PatFrag<(ops node:$ptr), (i8 (zextload node:$ptr, i1))>;
-def zextloadi16i1 : PatFrag<(ops node:$ptr), (i16 (zextload node:$ptr, i1))>;
-def zextloadi32i1 : PatFrag<(ops node:$ptr), (i32 (zextload node:$ptr, i1))>;
-def zextloadi16i8 : PatFrag<(ops node:$ptr), (i16 (zextload node:$ptr, i8))>;
-def zextloadi32i8 : PatFrag<(ops node:$ptr), (i32 (zextload node:$ptr, i8))>;
-def zextloadi32i16 : PatFrag<(ops node:$ptr), (i32 (zextload node:$ptr, i16))>;
-
-def extloadi8i1 : PatFrag<(ops node:$ptr), (i8 (extload node:$ptr, i1))>;
-def extloadi16i1 : PatFrag<(ops node:$ptr), (i16 (extload node:$ptr, i1))>;
-def extloadi32i1 : PatFrag<(ops node:$ptr), (i32 (extload node:$ptr, i1))>;
-def extloadi16i8 : PatFrag<(ops node:$ptr), (i16 (extload node:$ptr, i8))>;
-def extloadi32i8 : PatFrag<(ops node:$ptr), (i32 (extload node:$ptr, i8))>;
-def extloadi32i16 : PatFrag<(ops node:$ptr), (i32 (extload node:$ptr, i16))>;
+def sextloadi16i1 : PatFrag<(ops node:$ptr), (i16 (sextloadi1 node:$ptr))>;
+def sextloadi32i1 : PatFrag<(ops node:$ptr), (i32 (sextloadi1 node:$ptr))>;
+def sextloadi16i8 : PatFrag<(ops node:$ptr), (i16 (sextloadi8 node:$ptr))>;
+def sextloadi32i8 : PatFrag<(ops node:$ptr), (i32 (sextloadi8 node:$ptr))>;
+def sextloadi32i16 : PatFrag<(ops node:$ptr), (i32 (sextloadi16 node:$ptr))>;
+
+def zextloadi8i1 : PatFrag<(ops node:$ptr), (i8 (zextloadi1 node:$ptr))>;
+def zextloadi16i1 : PatFrag<(ops node:$ptr), (i16 (zextloadi1 node:$ptr))>;
+def zextloadi32i1 : PatFrag<(ops node:$ptr), (i32 (zextloadi1 node:$ptr))>;
+def zextloadi16i8 : PatFrag<(ops node:$ptr), (i16 (zextloadi8 node:$ptr))>;
+def zextloadi32i8 : PatFrag<(ops node:$ptr), (i32 (zextloadi8 node:$ptr))>;
+def zextloadi32i16 : PatFrag<(ops node:$ptr), (i32 (zextloadi16 node:$ptr))>;
+
+def extloadi8i1 : PatFrag<(ops node:$ptr), (i8 (extloadi1 node:$ptr))>;
+def extloadi16i1 : PatFrag<(ops node:$ptr), (i16 (extloadi1 node:$ptr))>;
+def extloadi32i1 : PatFrag<(ops node:$ptr), (i32 (extloadi1 node:$ptr))>;
+def extloadi16i8 : PatFrag<(ops node:$ptr), (i16 (extloadi8 node:$ptr))>;
+def extloadi32i8 : PatFrag<(ops node:$ptr), (i32 (extloadi8 node:$ptr))>;
+def extloadi32i16 : PatFrag<(ops node:$ptr), (i32 (extloadi16 node:$ptr))>;
//===----------------------------------------------------------------------===//
// Instruction templates...
+//
class I<bits<8> o, Format f, dag ops, string asm, list<dag> pattern>
: X86Inst<o, f, NoImm, ops, asm> {
let Pattern = pattern;
+ let CodeSize = 3;
}
class Ii8 <bits<8> o, Format f, dag ops, string asm, list<dag> pattern>
: X86Inst<o, f, Imm8 , ops, asm> {
let Pattern = pattern;
+ let CodeSize = 3;
}
class Ii16<bits<8> o, Format f, dag ops, string asm, list<dag> pattern>
: X86Inst<o, f, Imm16, ops, asm> {
let Pattern = pattern;
+ let CodeSize = 3;
}
class Ii32<bits<8> o, Format f, dag ops, string asm, list<dag> pattern>
: X86Inst<o, f, Imm32, ops, asm> {
let Pattern = pattern;
+ let CodeSize = 3;
}
//===----------------------------------------------------------------------===//
// Instruction list...
//
+// ADJCALLSTACKDOWN/UP implicitly use/def ESP because they may be expanded into
+// a stack adjustment and the codegen must know that they may modify the stack
+// pointer before prolog-epilog rewriting occurs.
def ADJCALLSTACKDOWN : I<0, Pseudo, (ops i32imm:$amt), "#ADJCALLSTACKDOWN",
- [(X86callseq_start imm:$amt)]>;
+ [(X86callseq_start imm:$amt)]>, Imp<[ESP],[ESP]>;
def ADJCALLSTACKUP : I<0, Pseudo, (ops i32imm:$amt1, i32imm:$amt2),
"#ADJCALLSTACKUP",
- [(X86callseq_end imm:$amt1, imm:$amt2)]>;
+ [(X86callseq_end imm:$amt1, imm:$amt2)]>,
+ Imp<[ESP],[ESP]>;
def IMPLICIT_USE : I<0, Pseudo, (ops variable_ops), "#IMPLICIT_USE", []>;
def IMPLICIT_DEF : I<0, Pseudo, (ops variable_ops), "#IMPLICIT_DEF", []>;
def IMPLICIT_DEF_GR8 : I<0, Pseudo, (ops GR8:$dst),
def NOOP : I<0x90, RawFrm, (ops), "nop", []>;
// Truncate
-def TRUNC_GR32_GR8 : I<0x88, MRMDestReg, (ops GR8:$dst, GR32_:$src),
- "mov{b} {${src:subreg8}, $dst|$dst, ${src:subreg8}", []>;
-def TRUNC_GR16_GR8 : I<0x88, MRMDestReg, (ops GR8:$dst, GR16_:$src),
- "mov{b} {${src:subreg8}, $dst|$dst, ${src:subreg8}}", []>;
-def TRUNC_GR32_GR16 : I<0x89, MRMDestReg, (ops GR16:$dst, GR32:$src),
- "mov{w} {${src:subreg16}, $dst|$dst, ${src:subreg16}}",
- [(set GR16:$dst, (trunc GR32:$src))]>;
+def TRUNC_32_to8 : I<0x88, MRMDestReg, (ops GR8:$dst, GR32_:$src),
+ "mov{b} {${src:subreg8}, $dst|$dst, ${src:subreg8}", []>;
+def TRUNC_16_to8 : I<0x88, MRMDestReg, (ops GR8:$dst, GR16_:$src),
+ "mov{b} {${src:subreg8}, $dst|$dst, ${src:subreg8}}", []>;
+def TRUNC_32to16 : I<0x89, MRMDestReg, (ops GR16:$dst, GR32:$src),
+ "mov{w} {${src:subreg16}, $dst|$dst, ${src:subreg16}}",
+ [(set GR16:$dst, (trunc GR32:$src))]>;
//===----------------------------------------------------------------------===//
// Control Flow Instructions...
I<opcode, RawFrm, ops, asm, pattern>;
// Indirect branches
-let isBarrier = 1 in
+let isBranch = 1, isBarrier = 1 in
def JMP : IBr<0xE9, (ops brtarget:$dst), "jmp $dst", [(br bb:$dst)]>;
let isBranch = 1, isTerminator = 1, noResults = 1, isBarrier = 1 in {
def JMP32r : I<0xFF, MRM4r, (ops GR32:$dst), "jmp{l} {*}$dst",
[(brind GR32:$dst)]>;
def JMP32m : I<0xFF, MRM4m, (ops i32mem:$dst), "jmp{l} {*}$dst",
- [(brind (loadiPTR addr:$dst))]>;
+ [(brind (loadi32 addr:$dst))]>;
}
// Conditional branches
// Tail call stuff.
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, noResults = 1 in
- def TAILJMPd : IBr<0xE9, (ops i32imm:$dst), "jmp ${dst:call} # TAIL CALL", []>;
+ def TAILJMPd : IBr<0xE9, (ops i32imm:$dst), "jmp ${dst:call} # TAIL CALL",
+ []>;
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, noResults = 1 in
- def TAILJMPr : I<0xFF, MRM4r, (ops GR32:$dst), "jmp {*}$dst # TAIL CALL", []>;
+ def TAILJMPr : I<0xFF, MRM4r, (ops GR32:$dst), "jmp {*}$dst # TAIL CALL",
+ []>;
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, noResults = 1 in
def TAILJMPm : I<0xFF, MRM4m, (ops i32mem:$dst),
"jmp {*}$dst # TAIL CALL", []>;
-// ADJSTACKPTRri - This is a standard ADD32ri instruction, identical in every
-// way, except that it is marked as being a terminator. This causes the epilog
-// inserter to insert reloads of callee saved registers BEFORE this. We need
-// this until we have a more accurate way of tracking where the stack pointer is
-// within a function.
-let isTerminator = 1, isTwoAddress = 1 in
- def ADJSTACKPTRri : Ii32<0x81, MRM0r, (ops GR32:$dst, GR32:$src1, i32imm:$src2),
- "add{l} {$src2, $dst|$dst, $src2}", []>;
-
//===----------------------------------------------------------------------===//
// Miscellaneous Instructions...
//
(ops GR16:$dst, i32mem:$src),
"lea{w} {$src|$dst}, {$dst|$src}", []>, OpSize;
def LEA32r : I<0x8D, MRMSrcMem,
- (ops GR32:$dst, i32mem:$src),
+ (ops GR32:$dst, lea32mem:$src),
"lea{l} {$src|$dst}, {$dst|$src}",
- [(set GR32:$dst, leaaddr:$src)]>;
+ [(set GR32:$dst, lea32addr:$src)]>, Requires<[In32BitMode]>;
def REP_MOVSB : I<0xA4, RawFrm, (ops), "{rep;movsb|rep movsb}",
[(X86rep_movs i8)]>,
[(X86rep_stos i32)]>,
Imp<[EAX,ECX,EDI], [ECX,EDI]>, REP;
+def RDTSC : I<0x31, RawFrm, (ops), "rdtsc", [(X86rdtsc)]>,
+ TB, Imp<[],[RAX,RDX]>;
//===----------------------------------------------------------------------===//
// Input/Output Instructions...
"mov{w} {$src, $dst|$dst, $src}", []>, OpSize;
def MOV32rr : I<0x89, MRMDestReg, (ops GR32:$dst, GR32:$src),
"mov{l} {$src, $dst|$dst, $src}", []>;
+let isReMaterializable = 1 in {
def MOV8ri : Ii8 <0xB0, AddRegFrm, (ops GR8 :$dst, i8imm :$src),
"mov{b} {$src, $dst|$dst, $src}",
[(set GR8:$dst, imm:$src)]>;
def MOV32ri : Ii32<0xB8, AddRegFrm, (ops GR32:$dst, i32imm:$src),
"mov{l} {$src, $dst|$dst, $src}",
[(set GR32:$dst, imm:$src)]>;
+}
def MOV8mi : Ii8 <0xC6, MRM0m, (ops i8mem :$dst, i8imm :$src),
"mov{b} {$src, $dst|$dst, $src}",
[(store (i8 imm:$src), addr:$dst)]>;
// unary instructions
+let CodeSize = 2 in {
def NEG8r : I<0xF6, MRM3r, (ops GR8 :$dst, GR8 :$src), "neg{b} $dst",
[(set GR8:$dst, (ineg GR8:$src))]>;
def NEG16r : I<0xF7, MRM3r, (ops GR16:$dst, GR16:$src), "neg{w} $dst",
def NOT32m : I<0xF7, MRM2m, (ops i32mem:$dst), "not{l} $dst",
[(store (not (loadi32 addr:$dst)), addr:$dst)]>;
}
+} // CodeSize
// TODO: inc/dec is slow for P4, but fast for Pentium-M.
+let CodeSize = 2 in
def INC8r : I<0xFE, MRM0r, (ops GR8 :$dst, GR8 :$src), "inc{b} $dst",
[(set GR8:$dst, (add GR8:$src, 1))]>;
-let isConvertibleToThreeAddress = 1 in { // Can transform into LEA.
-def INC16r : I<0xFF, MRM0r, (ops GR16:$dst, GR16:$src), "inc{w} $dst",
- [(set GR16:$dst, (add GR16:$src, 1))]>, OpSize;
-def INC32r : I<0xFF, MRM0r, (ops GR32:$dst, GR32:$src), "inc{l} $dst",
- [(set GR32:$dst, (add GR32:$src, 1))]>;
+let isConvertibleToThreeAddress = 1, CodeSize = 1 in { // Can xform into LEA.
+def INC16r : I<0x40, AddRegFrm, (ops GR16:$dst, GR16:$src), "inc{w} $dst",
+ [(set GR16:$dst, (add GR16:$src, 1))]>,
+ OpSize, Requires<[In32BitMode]>;
+def INC32r : I<0x40, AddRegFrm, (ops GR32:$dst, GR32:$src), "inc{l} $dst",
+ [(set GR32:$dst, (add GR32:$src, 1))]>, Requires<[In32BitMode]>;
}
-let isTwoAddress = 0 in {
+let isTwoAddress = 0, CodeSize = 2 in {
def INC8m : I<0xFE, MRM0m, (ops i8mem :$dst), "inc{b} $dst",
[(store (add (loadi8 addr:$dst), 1), addr:$dst)]>;
def INC16m : I<0xFF, MRM0m, (ops i16mem:$dst), "inc{w} $dst",
[(store (add (loadi32 addr:$dst), 1), addr:$dst)]>;
}
+let CodeSize = 2 in
def DEC8r : I<0xFE, MRM1r, (ops GR8 :$dst, GR8 :$src), "dec{b} $dst",
[(set GR8:$dst, (add GR8:$src, -1))]>;
-let isConvertibleToThreeAddress = 1 in { // Can transform into LEA.
-def DEC16r : I<0xFF, MRM1r, (ops GR16:$dst, GR16:$src), "dec{w} $dst",
- [(set GR16:$dst, (add GR16:$src, -1))]>, OpSize;
-def DEC32r : I<0xFF, MRM1r, (ops GR32:$dst, GR32:$src), "dec{l} $dst",
- [(set GR32:$dst, (add GR32:$src, -1))]>;
+let isConvertibleToThreeAddress = 1, CodeSize = 1 in { // Can xform into LEA.
+def DEC16r : I<0x48, AddRegFrm, (ops GR16:$dst, GR16:$src), "dec{w} $dst",
+ [(set GR16:$dst, (add GR16:$src, -1))]>,
+ OpSize, Requires<[In32BitMode]>;
+def DEC32r : I<0x48, AddRegFrm, (ops GR32:$dst, GR32:$src), "dec{l} $dst",
+ [(set GR32:$dst, (add GR32:$src, -1))]>, Requires<[In32BitMode]>;
}
-let isTwoAddress = 0 in {
+let isTwoAddress = 0, CodeSize = 2 in {
def DEC8m : I<0xFE, MRM1m, (ops i8mem :$dst), "dec{b} $dst",
[(store (add (loadi8 addr:$dst), -1), addr:$dst)]>;
def DEC16m : I<0xFF, MRM1m, (ops i16mem:$dst), "dec{w} $dst",
[(set GR32:$dst, (shl GR32:$src1, (i8 imm:$src2)))]>;
}
+// Shift left by one. Not used because (add x, x) is slightly cheaper.
+def SHL8r1 : I<0xD0, MRM4r, (ops GR8 :$dst, GR8 :$src1),
+ "shl{b} $dst", []>;
+def SHL16r1 : I<0xD1, MRM4r, (ops GR16:$dst, GR16:$src1),
+ "shl{w} $dst", []>, OpSize;
+def SHL32r1 : I<0xD1, MRM4r, (ops GR32:$dst, GR32:$src1),
+ "shl{l} $dst", []>;
+
let isTwoAddress = 0 in {
def SHL8mCL : I<0xD2, MRM4m, (ops i8mem :$dst),
"shl{b} {%cl, $dst|$dst, %CL}",
def SHL32mi : Ii8<0xC1, MRM4m, (ops i32mem:$dst, i8imm:$src),
"shl{l} {$src, $dst|$dst, $src}",
[(store (shl (loadi32 addr:$dst), (i8 imm:$src)), addr:$dst)]>;
+
+ // Shift by 1
+ def SHL8m1 : I<0xD0, MRM4m, (ops i8mem :$dst),
+ "shl{b} $dst",
+ [(store (shl (loadi8 addr:$dst), (i8 1)), addr:$dst)]>;
+ def SHL16m1 : I<0xD1, MRM4m, (ops i16mem:$dst),
+ "shl{w} $dst",
+ [(store (shl (loadi16 addr:$dst), (i8 1)), addr:$dst)]>,
+ OpSize;
+ def SHL32m1 : I<0xD1, MRM4m, (ops i32mem:$dst),
+ "shl{l} $dst",
+ [(store (shl (loadi32 addr:$dst), (i8 1)), addr:$dst)]>;
}
def SHR8rCL : I<0xD2, MRM5r, (ops GR8 :$dst, GR8 :$src),
"shr{l} {$src2, $dst|$dst, $src2}",
[(set GR32:$dst, (srl GR32:$src1, (i8 imm:$src2)))]>;
+// Shift by 1
+def SHR8r1 : I<0xD0, MRM5r, (ops GR8:$dst, GR8:$src1),
+ "shr{b} $dst",
+ [(set GR8:$dst, (srl GR8:$src1, (i8 1)))]>;
+def SHR16r1 : I<0xD1, MRM5r, (ops GR16:$dst, GR16:$src1),
+ "shr{w} $dst",
+ [(set GR16:$dst, (srl GR16:$src1, (i8 1)))]>, OpSize;
+def SHR32r1 : I<0xD1, MRM5r, (ops GR32:$dst, GR32:$src1),
+ "shr{l} $dst",
+ [(set GR32:$dst, (srl GR32:$src1, (i8 1)))]>;
+
let isTwoAddress = 0 in {
def SHR8mCL : I<0xD2, MRM5m, (ops i8mem :$dst),
"shr{b} {%cl, $dst|$dst, %CL}",
def SHR32mi : Ii8<0xC1, MRM5m, (ops i32mem:$dst, i8imm:$src),
"shr{l} {$src, $dst|$dst, $src}",
[(store (srl (loadi32 addr:$dst), (i8 imm:$src)), addr:$dst)]>;
+
+ // Shift by 1
+ def SHR8m1 : I<0xD0, MRM5m, (ops i8mem :$dst),
+ "shr{b} $dst",
+ [(store (srl (loadi8 addr:$dst), (i8 1)), addr:$dst)]>;
+ def SHR16m1 : I<0xD1, MRM5m, (ops i16mem:$dst),
+ "shr{w} $dst",
+ [(store (srl (loadi16 addr:$dst), (i8 1)), addr:$dst)]>,OpSize;
+ def SHR32m1 : I<0xD1, MRM5m, (ops i32mem:$dst),
+ "shr{l} $dst",
+ [(store (srl (loadi32 addr:$dst), (i8 1)), addr:$dst)]>;
}
def SAR8rCL : I<0xD2, MRM7r, (ops GR8 :$dst, GR8 :$src),
def SAR32ri : Ii8<0xC1, MRM7r, (ops GR32:$dst, GR32:$src1, i8imm:$src2),
"sar{l} {$src2, $dst|$dst, $src2}",
[(set GR32:$dst, (sra GR32:$src1, (i8 imm:$src2)))]>;
+
+// Shift by 1
+def SAR8r1 : I<0xD0, MRM7r, (ops GR8 :$dst, GR8 :$src1),
+ "sar{b} $dst",
+ [(set GR8:$dst, (sra GR8:$src1, (i8 1)))]>;
+def SAR16r1 : I<0xD1, MRM7r, (ops GR16:$dst, GR16:$src1),
+ "sar{w} $dst",
+ [(set GR16:$dst, (sra GR16:$src1, (i8 1)))]>, OpSize;
+def SAR32r1 : I<0xD1, MRM7r, (ops GR32:$dst, GR32:$src1),
+ "sar{l} $dst",
+ [(set GR32:$dst, (sra GR32:$src1, (i8 1)))]>;
+
let isTwoAddress = 0 in {
def SAR8mCL : I<0xD2, MRM7m, (ops i8mem :$dst),
"sar{b} {%cl, $dst|$dst, %CL}",
def SAR32mi : Ii8<0xC1, MRM7m, (ops i32mem:$dst, i8imm:$src),
"sar{l} {$src, $dst|$dst, $src}",
[(store (sra (loadi32 addr:$dst), (i8 imm:$src)), addr:$dst)]>;
+
+ // Shift by 1
+ def SAR8m1 : I<0xD0, MRM7m, (ops i8mem :$dst),
+ "sar{b} $dst",
+ [(store (sra (loadi8 addr:$dst), (i8 1)), addr:$dst)]>;
+ def SAR16m1 : I<0xD1, MRM7m, (ops i16mem:$dst),
+ "sar{w} $dst",
+ [(store (sra (loadi16 addr:$dst), (i8 1)), addr:$dst)]>,
+ OpSize;
+ def SAR32m1 : I<0xD1, MRM7m, (ops i32mem:$dst),
+ "sar{l} $dst",
+ [(store (sra (loadi32 addr:$dst), (i8 1)), addr:$dst)]>;
}
// Rotate instructions
"rol{l} {$src2, $dst|$dst, $src2}",
[(set GR32:$dst, (rotl GR32:$src1, (i8 imm:$src2)))]>;
+// Rotate by 1
+def ROL8r1 : I<0xD0, MRM0r, (ops GR8 :$dst, GR8 :$src1),
+ "rol{b} $dst",
+ [(set GR8:$dst, (rotl GR8:$src1, (i8 1)))]>;
+def ROL16r1 : I<0xD1, MRM0r, (ops GR16:$dst, GR16:$src1),
+ "rol{w} $dst",
+ [(set GR16:$dst, (rotl GR16:$src1, (i8 1)))]>, OpSize;
+def ROL32r1 : I<0xD1, MRM0r, (ops GR32:$dst, GR32:$src1),
+ "rol{l} $dst",
+ [(set GR32:$dst, (rotl GR32:$src1, (i8 1)))]>;
+
let isTwoAddress = 0 in {
def ROL8mCL : I<0xD2, MRM0m, (ops i8mem :$dst),
"rol{b} {%cl, $dst|$dst, %CL}",
def ROL32mi : Ii8<0xC1, MRM0m, (ops i32mem:$dst, i8imm:$src),
"rol{l} {$src, $dst|$dst, $src}",
[(store (rotl (loadi32 addr:$dst), (i8 imm:$src)), addr:$dst)]>;
+
+ // Rotate by 1
+ def ROL8m1 : I<0xD0, MRM0m, (ops i8mem :$dst),
+ "rol{b} $dst",
+ [(store (rotl (loadi8 addr:$dst), (i8 1)), addr:$dst)]>;
+ def ROL16m1 : I<0xD1, MRM0m, (ops i16mem:$dst),
+ "rol{w} $dst",
+ [(store (rotl (loadi16 addr:$dst), (i8 1)), addr:$dst)]>,
+ OpSize;
+ def ROL32m1 : I<0xD1, MRM0m, (ops i32mem:$dst),
+ "rol{l} $dst",
+ [(store (rotl (loadi32 addr:$dst), (i8 1)), addr:$dst)]>;
}
def ROR8rCL : I<0xD2, MRM1r, (ops GR8 :$dst, GR8 :$src),
def ROR32ri : Ii8<0xC1, MRM1r, (ops GR32:$dst, GR32:$src1, i8imm:$src2),
"ror{l} {$src2, $dst|$dst, $src2}",
[(set GR32:$dst, (rotr GR32:$src1, (i8 imm:$src2)))]>;
+
+// Rotate by 1
+def ROR8r1 : I<0xD0, MRM1r, (ops GR8 :$dst, GR8 :$src1),
+ "ror{b} $dst",
+ [(set GR8:$dst, (rotr GR8:$src1, (i8 1)))]>;
+def ROR16r1 : I<0xD1, MRM1r, (ops GR16:$dst, GR16:$src1),
+ "ror{w} $dst",
+ [(set GR16:$dst, (rotr GR16:$src1, (i8 1)))]>, OpSize;
+def ROR32r1 : I<0xD1, MRM1r, (ops GR32:$dst, GR32:$src1),
+ "ror{l} $dst",
+ [(set GR32:$dst, (rotr GR32:$src1, (i8 1)))]>;
+
let isTwoAddress = 0 in {
def ROR8mCL : I<0xD2, MRM1m, (ops i8mem :$dst),
"ror{b} {%cl, $dst|$dst, %CL}",
def ROR32mi : Ii8<0xC1, MRM1m, (ops i32mem:$dst, i8imm:$src),
"ror{l} {$src, $dst|$dst, $src}",
[(store (rotr (loadi32 addr:$dst), (i8 imm:$src)), addr:$dst)]>;
+
+ // Rotate by 1
+ def ROR8m1 : I<0xD0, MRM1m, (ops i8mem :$dst),
+ "ror{b} $dst",
+ [(store (rotr (loadi8 addr:$dst), (i8 1)), addr:$dst)]>;
+ def ROR16m1 : I<0xD1, MRM1m, (ops i16mem:$dst),
+ "ror{w} $dst",
+ [(store (rotr (loadi16 addr:$dst), (i8 1)), addr:$dst)]>,
+ OpSize;
+ def ROR32m1 : I<0xD1, MRM1m, (ops i32mem:$dst),
+ "ror{l} $dst",
+ [(store (rotr (loadi32 addr:$dst), (i8 1)), addr:$dst)]>;
}
let isCommutable = 1 in { // TEST X, Y --> TEST Y, X
def TEST8rr : I<0x84, MRMDestReg, (ops GR8:$src1, GR8:$src2),
"test{b} {$src2, $src1|$src1, $src2}",
- [(X86test GR8:$src1, GR8:$src2)]>;
+ [(X86cmp (and GR8:$src1, GR8:$src2), 0)]>;
def TEST16rr : I<0x85, MRMDestReg, (ops GR16:$src1, GR16:$src2),
"test{w} {$src2, $src1|$src1, $src2}",
- [(X86test GR16:$src1, GR16:$src2)]>, OpSize;
+ [(X86cmp (and GR16:$src1, GR16:$src2), 0)]>, OpSize;
def TEST32rr : I<0x85, MRMDestReg, (ops GR32:$src1, GR32:$src2),
"test{l} {$src2, $src1|$src1, $src2}",
- [(X86test GR32:$src1, GR32:$src2)]>;
+ [(X86cmp (and GR32:$src1, GR32:$src2), 0)]>;
}
-def TEST8mr : I<0x84, MRMDestMem, (ops i8mem :$src1, GR8 :$src2),
- "test{b} {$src2, $src1|$src1, $src2}",
- [(X86test (loadi8 addr:$src1), GR8:$src2)]>;
-def TEST16mr : I<0x85, MRMDestMem, (ops i16mem:$src1, GR16:$src2),
- "test{w} {$src2, $src1|$src1, $src2}",
- [(X86test (loadi16 addr:$src1), GR16:$src2)]>,
- OpSize;
-def TEST32mr : I<0x85, MRMDestMem, (ops i32mem:$src1, GR32:$src2),
- "test{l} {$src2, $src1|$src1, $src2}",
- [(X86test (loadi32 addr:$src1), GR32:$src2)]>;
+
def TEST8rm : I<0x84, MRMSrcMem, (ops GR8 :$src1, i8mem :$src2),
"test{b} {$src2, $src1|$src1, $src2}",
- [(X86test GR8:$src1, (loadi8 addr:$src2))]>;
+ [(X86cmp (and GR8:$src1, (loadi8 addr:$src2)), 0)]>;
def TEST16rm : I<0x85, MRMSrcMem, (ops GR16:$src1, i16mem:$src2),
"test{w} {$src2, $src1|$src1, $src2}",
- [(X86test GR16:$src1, (loadi16 addr:$src2))]>,
+ [(X86cmp (and GR16:$src1, (loadi16 addr:$src2)), 0)]>,
OpSize;
def TEST32rm : I<0x85, MRMSrcMem, (ops GR32:$src1, i32mem:$src2),
"test{l} {$src2, $src1|$src1, $src2}",
- [(X86test GR32:$src1, (loadi32 addr:$src2))]>;
+ [(X86cmp (and GR32:$src1, (loadi32 addr:$src2)), 0)]>;
def TEST8ri : Ii8 <0xF6, MRM0r, // flags = GR8 & imm8
(ops GR8:$src1, i8imm:$src2),
"test{b} {$src2, $src1|$src1, $src2}",
- [(X86test GR8:$src1, imm:$src2)]>;
+ [(X86cmp (and GR8:$src1, imm:$src2), 0)]>;
def TEST16ri : Ii16<0xF7, MRM0r, // flags = GR16 & imm16
(ops GR16:$src1, i16imm:$src2),
"test{w} {$src2, $src1|$src1, $src2}",
- [(X86test GR16:$src1, imm:$src2)]>, OpSize;
+ [(X86cmp (and GR16:$src1, imm:$src2), 0)]>, OpSize;
def TEST32ri : Ii32<0xF7, MRM0r, // flags = GR32 & imm32
(ops GR32:$src1, i32imm:$src2),
"test{l} {$src2, $src1|$src1, $src2}",
- [(X86test GR32:$src1, imm:$src2)]>;
+ [(X86cmp (and GR32:$src1, imm:$src2), 0)]>;
+
def TEST8mi : Ii8 <0xF6, MRM0m, // flags = [mem8] & imm8
(ops i8mem:$src1, i8imm:$src2),
"test{b} {$src2, $src1|$src1, $src2}",
- [(X86test (loadi8 addr:$src1), imm:$src2)]>;
+ [(X86cmp (and (loadi8 addr:$src1), imm:$src2), 0)]>;
def TEST16mi : Ii16<0xF7, MRM0m, // flags = [mem16] & imm16
(ops i16mem:$src1, i16imm:$src2),
"test{w} {$src2, $src1|$src1, $src2}",
- [(X86test (loadi16 addr:$src1), imm:$src2)]>,
+ [(X86cmp (and (loadi16 addr:$src1), imm:$src2), 0)]>,
OpSize;
def TEST32mi : Ii32<0xF7, MRM0m, // flags = [mem32] & imm32
(ops i32mem:$src1, i32imm:$src2),
"test{l} {$src2, $src1|$src1, $src2}",
- [(X86test (loadi32 addr:$src1), imm:$src2)]>;
+ [(X86cmp (and (loadi32 addr:$src1), imm:$src2), 0)]>;
// Condition code ops, incl. set if equal/not equal/...
[(set GR32:$dst, (zextloadi32i16 addr:$src))]>, TB;
def CBW : I<0x98, RawFrm, (ops),
- "{cbtw|cbw}", []>, Imp<[AL],[AX]>; // AX = signext(AL)
+ "{cbtw|cbw}", []>, Imp<[AL],[AX]>, OpSize; // AX = signext(AL)
def CWDE : I<0x98, RawFrm, (ops),
"{cwtl|cwde}", []>, Imp<[AX],[EAX]>; // EAX = signext(AX)
def CWD : I<0x99, RawFrm, (ops),
- "{cwtd|cwd}", []>, Imp<[AX],[AX,DX]>; // DX:AX = signext(AX)
+ "{cwtd|cwd}", []>, Imp<[AX],[AX,DX]>, OpSize; // DX:AX = signext(AX)
def CDQ : I<0x99, RawFrm, (ops),
"{cltd|cdq}", []>, Imp<[EAX],[EAX,EDX]>; // EDX:EAX = signext(EAX)
-//===----------------------------------------------------------------------===//
-// Miscellaneous Instructions
-//===----------------------------------------------------------------------===//
-
-def RDTSC : I<0x31, RawFrm, (ops), "rdtsc", [(X86rdtsc)]>,
- TB, Imp<[],[EAX,EDX]>;
//===----------------------------------------------------------------------===//
// Alias Instructions
[(dwarf_loc (i32 imm:$line), (i32 imm:$col),
(i32 imm:$file))]>;
-def DWARF_LABEL : I<0, Pseudo, (ops i32imm:$id),
- "\nLdebug_loc${id:debug}:",
- [(dwarf_label (i32 imm:$id))]>;
-
//===----------------------------------------------------------------------===//
// Non-Instruction Patterns
//===----------------------------------------------------------------------===//
-// ConstantPool GlobalAddress, ExternalSymbol
+// ConstantPool GlobalAddress, ExternalSymbol, and JumpTable
def : Pat<(i32 (X86Wrapper tconstpool :$dst)), (MOV32ri tconstpool :$dst)>;
def : Pat<(i32 (X86Wrapper tjumptable :$dst)), (MOV32ri tjumptable :$dst)>;
def : Pat<(i32 (X86Wrapper tglobaladdr :$dst)), (MOV32ri tglobaladdr :$dst)>;
// Calls
def : Pat<(X86tailcall GR32:$dst),
- (CALL32r GR32:$dst)>;
+ (CALL32r GR32:$dst)>;
-def : Pat<(X86tailcall tglobaladdr:$dst),
+def : Pat<(X86tailcall (i32 tglobaladdr:$dst)),
(CALLpcrel32 tglobaladdr:$dst)>;
-def : Pat<(X86tailcall texternalsym:$dst),
+def : Pat<(X86tailcall (i32 texternalsym:$dst)),
(CALLpcrel32 texternalsym:$dst)>;
-
-
-def : Pat<(X86call tglobaladdr:$dst),
+def : Pat<(X86call (i32 tglobaladdr:$dst)),
(CALLpcrel32 tglobaladdr:$dst)>;
-def : Pat<(X86call texternalsym:$dst),
+def : Pat<(X86call (i32 texternalsym:$dst)),
(CALLpcrel32 texternalsym:$dst)>;
// X86 specific add which produces a flag.
def : Pat<(subc GR32:$src1, i32immSExt8:$src2),
(SUB32ri8 GR32:$src1, i32immSExt8:$src2)>;
-def : Pat<(truncstore (i8 imm:$src), addr:$dst, i1),
+def : Pat<(truncstorei1 (i8 imm:$src), addr:$dst),
(MOV8mi addr:$dst, imm:$src)>;
-def : Pat<(truncstore GR8:$src, addr:$dst, i1),
+def : Pat<(truncstorei1 GR8:$src, addr:$dst),
(MOV8mr addr:$dst, GR8:$src)>;
+// Comparisons.
+
+// TEST R,R is smaller than CMP R,0
+def : Pat<(X86cmp GR8:$src1, 0),
+ (TEST8rr GR8:$src1, GR8:$src1)>;
+def : Pat<(X86cmp GR16:$src1, 0),
+ (TEST16rr GR16:$src1, GR16:$src1)>;
+def : Pat<(X86cmp GR32:$src1, 0),
+ (TEST32rr GR32:$src1, GR32:$src1)>;
+
// {s|z}extload bool -> {s|z}extload byte
def : Pat<(sextloadi16i1 addr:$src), (MOVSX16rm8 addr:$src)>;
def : Pat<(sextloadi32i1 addr:$src), (MOVSX32rm8 addr:$src)>;
//===----------------------------------------------------------------------===//
include "X86InstrSSE.td"
+
+//===----------------------------------------------------------------------===//
+// X86-64 Support
+//===----------------------------------------------------------------------===//
+
+include "X86InstrX86-64.td"