46 changes: 46 additions & 0 deletions llvm/lib/Target/X86/X86InstrConditionalCompare.td
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,34 @@ let mayLoad = 1 in {
}
}

def : Pat<(X86ccmp GR8:$src1, GR8:$src2, timm:$dcf, timm:$cond, EFLAGS),
(CCMP8rr GR8:$src1, GR8:$src2, timm:$dcf, timm:$cond)>;
def : Pat<(X86ccmp GR16:$src1, GR16:$src2, timm:$dcf, timm:$cond, EFLAGS),
(CCMP16rr GR16:$src1, GR16:$src2, timm:$dcf, timm:$cond)>;
def : Pat<(X86ccmp GR32:$src1, GR32:$src2, timm:$dcf, timm:$cond, EFLAGS),
(CCMP32rr GR32:$src1, GR32:$src2, timm:$dcf, timm:$cond)>;
def : Pat<(X86ccmp GR64:$src1, GR64:$src2, timm:$dcf, timm:$cond, EFLAGS),
(CCMP64rr GR64:$src1, GR64:$src2, timm:$dcf, timm:$cond)>;

def : Pat<(X86ccmp GR8:$src1, (i8 imm:$src2), timm:$dcf, timm:$cond, EFLAGS),
(CCMP8ri GR8:$src1, imm:$src2, timm:$dcf, timm:$cond)>;
def : Pat<(X86ccmp GR16:$src1, (i16 imm:$src2), timm:$dcf, timm:$cond, EFLAGS),
(CCMP16ri GR16:$src1, imm:$src2, timm:$dcf, timm:$cond)>;
def : Pat<(X86ccmp GR32:$src1, (i32 imm:$src2), timm:$dcf, timm:$cond, EFLAGS),
(CCMP32ri GR32:$src1, imm:$src2, timm:$dcf, timm:$cond)>;
def : Pat<(X86ccmp GR64:$src1, (i64 imm:$src2), timm:$dcf, timm:$cond, EFLAGS),
(CCMP64ri32 GR64:$src1, imm:$src2, timm:$dcf, timm:$cond)>;

def : Pat<(X86ccmp GR8:$src1, (loadi8 addr:$src2), timm:$dcf, timm:$cond, EFLAGS),
(CCMP8rm GR8:$src1, addr:$src2, timm:$dcf, timm:$cond)>;
def : Pat<(X86ccmp GR16:$src1, (loadi16 addr:$src2), timm:$dcf, timm:$cond, EFLAGS),
(CCMP16rm GR16:$src1, addr:$src2, timm:$dcf, timm:$cond)>;
def : Pat<(X86ccmp GR32:$src1, (loadi32 addr:$src2), timm:$dcf, timm:$cond, EFLAGS),
(CCMP32rm GR32:$src1, addr:$src2, timm:$dcf, timm:$cond)>;
def : Pat<(X86ccmp GR64:$src1, (loadi64 addr:$src2), timm:$dcf, timm:$cond, EFLAGS),
(CCMP64rm GR64:$src1, addr:$src2, timm:$dcf, timm:$cond)>;


//===----------------------------------------------------------------------===//
// CTEST Instructions
//
Expand Down Expand Up @@ -108,3 +136,21 @@ let mayLoad = 1 in {
def CTEST64mr: Ctest<0x85, MRMDestMem, Xi64, i64mem, GR64>;
}
}

def : Pat<(X86ctest GR8:$src1, GR8:$src2, timm:$dcf, timm:$cond, EFLAGS),
(CTEST8rr GR8:$src1, GR8:$src2, timm:$dcf, timm:$cond)>;
def : Pat<(X86ctest GR16:$src1, GR16:$src2, timm:$dcf, timm:$cond, EFLAGS),
(CTEST16rr GR16:$src1, GR16:$src2, timm:$dcf, timm:$cond)>;
def : Pat<(X86ctest GR32:$src1, GR32:$src2, timm:$dcf, timm:$cond, EFLAGS),
(CTEST32rr GR32:$src1, GR32:$src2, timm:$dcf, timm:$cond)>;
def : Pat<(X86ctest GR64:$src1, GR64:$src2, timm:$dcf, timm:$cond, EFLAGS),
(CTEST64rr GR64:$src1, GR64:$src2, timm:$dcf, timm:$cond)>;

def : Pat<(X86ctestpat GR8:$src1, imm:$src2, timm:$dcf, timm:$cond),
(CTEST8ri GR8:$src1, imm:$src2, timm:$dcf, timm:$cond)>;
def : Pat<(X86ctestpat GR16:$src1, imm:$src2, timm:$dcf, timm:$cond),
(CTEST16ri GR16:$src1, imm:$src2, timm:$dcf, timm:$cond)>;
def : Pat<(X86ctestpat GR32:$src1, imm:$src2, timm:$dcf, timm:$cond),
(CTEST32ri GR32:$src1, imm:$src2, timm:$dcf, timm:$cond)>;
def : Pat<(X86ctestpat GR64:$src1, imm:$src2, timm:$dcf, timm:$cond),
(CTEST64ri32 GR64:$src1, imm:$src2, timm:$dcf, timm:$cond)>;
19 changes: 18 additions & 1 deletion llvm/lib/Target/X86/X86InstrFragments.td
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ def SDTX86CmpTest : SDTypeProfile<1, 2, [SDTCisVT<0, i32>, SDTCisInt<1>,
def SDTX86FCmp : SDTypeProfile<1, 2, [SDTCisVT<0, i32>, SDTCisFP<1>,
SDTCisSameAs<1, 2>]>;

def SDTX86Ccmp : SDTypeProfile<1, 5,
[SDTCisVT<3, i8>, SDTCisVT<4, i8>, SDTCisVT<5, i32>]>;

def SDTX86Cmov : SDTypeProfile<1, 4,
[SDTCisSameAs<0, 1>, SDTCisSameAs<1, 2>,
SDTCisVT<3, i8>, SDTCisVT<4, i32>]>;
Expand Down Expand Up @@ -138,6 +141,9 @@ def X86strict_fcmp : SDNode<"X86ISD::STRICT_FCMP", SDTX86FCmp, [SDNPHasChain]>;
def X86strict_fcmps : SDNode<"X86ISD::STRICT_FCMPS", SDTX86FCmp, [SDNPHasChain]>;
def X86bt : SDNode<"X86ISD::BT", SDTX86CmpTest>;

def X86ccmp : SDNode<"X86ISD::CCMP", SDTX86Ccmp>;
def X86ctest : SDNode<"X86ISD::CTEST", SDTX86Ccmp>;

def X86cmov : SDNode<"X86ISD::CMOV", SDTX86Cmov>;
def X86brcond : SDNode<"X86ISD::BRCOND", SDTX86BrCond,
[SDNPHasChain]>;
Expand Down Expand Up @@ -577,6 +583,14 @@ def add_su : binop_oneuse<add>;
def and_su : binop_oneuse<and>;
def srl_su : binop_oneuse<srl>;

class binop_twouses<SDPatternOperator operator>
: PatFrag<(ops node:$A, node:$B),
(operator node:$A, node:$B), [{
return N->hasNUsesOfValue(2, 0);
}]>;

def and_du : binop_twouses<and>;

// unary op with only one user
class unop_oneuse<SDPatternOperator operator>
: PatFrag<(ops node:$A),
Expand All @@ -601,7 +615,10 @@ def X86sub_flag_nocf : PatFrag<(ops node:$lhs, node:$rhs),

def X86testpat : PatFrag<(ops node:$lhs, node:$rhs),
(X86cmp (and_su node:$lhs, node:$rhs), 0)>;

def X86ctestpat : PatFrag<(ops node:$lhs, node:$rhs, node:$dcf, node:$cond),
(X86ctest (and_du node:$lhs, node:$rhs),
(and_du node:$lhs, node:$rhs), node:$dcf,
node:$cond, EFLAGS)>;

def X86any_fcmp : PatFrags<(ops node:$lhs, node:$rhs),
[(X86strict_fcmp node:$lhs, node:$rhs),
Expand Down
57 changes: 57 additions & 0 deletions llvm/lib/Target/X86/X86InstrInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3164,6 +3164,63 @@ X86::CondCode X86::getCondFromCCMP(const MachineInstr &MI) {
: X86::COND_INVALID;
}

int X86::getCCMPCondFlagsFromCondCode(X86::CondCode CC) {
// CCMP/CTEST has two conditional operands:
// - SCC: source conditonal code (same as CMOV)
// - DCF: destination conditional flags, which has 4 valid bits
//
// +----+----+----+----+
// | OF | SF | ZF | CF |
// +----+----+----+----+
//
// If SCC(source conditional code) evaluates to false, CCMP/CTEST will updates
// the conditional flags by as follows:
//
// OF = DCF.OF
// SF = DCF.SF
// ZF = DCF.ZF
// CF = DCF.CF
// PF = DCF.CF
// AF = 0 (Auxiliary Carry Flag)
//
// Otherwise, the CMP or TEST is executed and it updates the
// CSPAZO flags normally.
//
// NOTE:
// If SCC = P, then SCC evaluates to true regardless of the CSPAZO value.
// If SCC = NP, then SCC evaluates to false regardless of the CSPAZO value.

enum { CF = 1, ZF = 2, SF = 4, OF = 8, PF = CF };

switch (CC) {
default:
llvm_unreachable("Illegal condition code!");
case X86::COND_NO:
case X86::COND_NE:
case X86::COND_GE:
case X86::COND_G:
case X86::COND_AE:
case X86::COND_A:
case X86::COND_NS:
case X86::COND_NP:
return 0;
case X86::COND_O:
return OF;
case X86::COND_B:
case X86::COND_BE:
return CF;
break;
case X86::COND_E:
case X86::COND_LE:
return ZF;
case X86::COND_S:
case X86::COND_L:
return SF;
case X86::COND_P:
return PF;
}
}

/// Return the inverse of the specified condition,
/// e.g. turning COND_E to COND_NE.
X86::CondCode X86::GetOppositeBranchCondition(X86::CondCode CC) {
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Target/X86/X86InstrInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ CondCode getCondFromCFCMov(const MachineInstr &MI);
// Turn CCMP instruction into condition code.
CondCode getCondFromCCMP(const MachineInstr &MI);

// Turn condition code into condition flags for CCMP/CTEST.
int getCCMPCondFlagsFromCondCode(CondCode CC);

/// GetOppositeBranchCondition - Return the inverse of the specified cond,
/// e.g. turning COND_E to COND_NE.
CondCode GetOppositeBranchCondition(CondCode CC);
Expand Down
1,102 changes: 1,102 additions & 0 deletions llvm/test/CodeGen/X86/apx/ccmp.ll

Large diffs are not rendered by default.

905 changes: 905 additions & 0 deletions llvm/test/CodeGen/X86/apx/ctest.ll

Large diffs are not rendered by default.