mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-10-03 08:55:51 +00:00
Use sbb x, x to materialize carry bit in a GPR. The result is all one's or all zero's.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@91381 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
8acb3100de
commit
ad9c0a3d8b
@ -5750,6 +5750,15 @@ SDValue X86TargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) {
|
|||||||
return SDValue();
|
return SDValue();
|
||||||
|
|
||||||
SDValue Cond = EmitCmp(Op0, Op1, X86CC, DAG);
|
SDValue Cond = EmitCmp(Op0, Op1, X86CC, DAG);
|
||||||
|
|
||||||
|
// Use sbb x, x to materialize carry bit into a GPR.
|
||||||
|
if (X86CC == X86::COND_B) {
|
||||||
|
return DAG.getNode(ISD::AND, dl, MVT::i8,
|
||||||
|
DAG.getNode(X86ISD::SETCC_CARRY, dl, MVT::i8,
|
||||||
|
DAG.getConstant(X86CC, MVT::i8), Cond),
|
||||||
|
DAG.getConstant(1, MVT::i8));
|
||||||
|
}
|
||||||
|
|
||||||
return DAG.getNode(X86ISD::SETCC, dl, MVT::i8,
|
return DAG.getNode(X86ISD::SETCC, dl, MVT::i8,
|
||||||
DAG.getConstant(X86CC, MVT::i8), Cond);
|
DAG.getConstant(X86CC, MVT::i8), Cond);
|
||||||
}
|
}
|
||||||
@ -5902,9 +5911,18 @@ SDValue X86TargetLowering::LowerSELECT(SDValue Op, SelectionDAG &DAG) {
|
|||||||
Cond = NewCond;
|
Cond = NewCond;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Look pass (and (setcc_carry (cmp ...)), 1).
|
||||||
|
if (Cond.getOpcode() == ISD::AND &&
|
||||||
|
Cond.getOperand(0).getOpcode() == X86ISD::SETCC_CARRY) {
|
||||||
|
ConstantSDNode *C = dyn_cast<ConstantSDNode>(Cond.getOperand(1));
|
||||||
|
if (C && C->getAPIntValue() == 1)
|
||||||
|
Cond = Cond.getOperand(0);
|
||||||
|
}
|
||||||
|
|
||||||
// If condition flag is set by a X86ISD::CMP, then use it as the condition
|
// If condition flag is set by a X86ISD::CMP, then use it as the condition
|
||||||
// setting operand in place of the X86ISD::SETCC.
|
// setting operand in place of the X86ISD::SETCC.
|
||||||
if (Cond.getOpcode() == X86ISD::SETCC) {
|
if (Cond.getOpcode() == X86ISD::SETCC ||
|
||||||
|
Cond.getOpcode() == X86ISD::SETCC_CARRY) {
|
||||||
CC = Cond.getOperand(0);
|
CC = Cond.getOperand(0);
|
||||||
|
|
||||||
SDValue Cmp = Cond.getOperand(1);
|
SDValue Cmp = Cond.getOperand(1);
|
||||||
@ -5987,9 +6005,18 @@ SDValue X86TargetLowering::LowerBRCOND(SDValue Op, SelectionDAG &DAG) {
|
|||||||
Cond = LowerXALUO(Cond, DAG);
|
Cond = LowerXALUO(Cond, DAG);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Look pass (and (setcc_carry (cmp ...)), 1).
|
||||||
|
if (Cond.getOpcode() == ISD::AND &&
|
||||||
|
Cond.getOperand(0).getOpcode() == X86ISD::SETCC_CARRY) {
|
||||||
|
ConstantSDNode *C = dyn_cast<ConstantSDNode>(Cond.getOperand(1));
|
||||||
|
if (C && C->getAPIntValue() == 1)
|
||||||
|
Cond = Cond.getOperand(0);
|
||||||
|
}
|
||||||
|
|
||||||
// If condition flag is set by a X86ISD::CMP, then use it as the condition
|
// If condition flag is set by a X86ISD::CMP, then use it as the condition
|
||||||
// setting operand in place of the X86ISD::SETCC.
|
// setting operand in place of the X86ISD::SETCC.
|
||||||
if (Cond.getOpcode() == X86ISD::SETCC) {
|
if (Cond.getOpcode() == X86ISD::SETCC ||
|
||||||
|
Cond.getOpcode() == X86ISD::SETCC_CARRY) {
|
||||||
CC = Cond.getOperand(0);
|
CC = Cond.getOperand(0);
|
||||||
|
|
||||||
SDValue Cmp = Cond.getOperand(1);
|
SDValue Cmp = Cond.getOperand(1);
|
||||||
@ -7376,6 +7403,7 @@ const char *X86TargetLowering::getTargetNodeName(unsigned Opcode) const {
|
|||||||
case X86ISD::COMI: return "X86ISD::COMI";
|
case X86ISD::COMI: return "X86ISD::COMI";
|
||||||
case X86ISD::UCOMI: return "X86ISD::UCOMI";
|
case X86ISD::UCOMI: return "X86ISD::UCOMI";
|
||||||
case X86ISD::SETCC: return "X86ISD::SETCC";
|
case X86ISD::SETCC: return "X86ISD::SETCC";
|
||||||
|
case X86ISD::SETCC_CARRY: return "X86ISD::SETCC_CARRY";
|
||||||
case X86ISD::CMOV: return "X86ISD::CMOV";
|
case X86ISD::CMOV: return "X86ISD::CMOV";
|
||||||
case X86ISD::BRCOND: return "X86ISD::BRCOND";
|
case X86ISD::BRCOND: return "X86ISD::BRCOND";
|
||||||
case X86ISD::RET_FLAG: return "X86ISD::RET_FLAG";
|
case X86ISD::RET_FLAG: return "X86ISD::RET_FLAG";
|
||||||
@ -8950,11 +8978,42 @@ static SDValue PerformMulCombine(SDNode *N, SelectionDAG &DAG,
|
|||||||
return SDValue();
|
return SDValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SDValue PerformSHLCombine(SDNode *N, SelectionDAG &DAG) {
|
||||||
|
SDValue N0 = N->getOperand(0);
|
||||||
|
SDValue N1 = N->getOperand(1);
|
||||||
|
ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N1);
|
||||||
|
EVT VT = N0.getValueType();
|
||||||
|
|
||||||
|
// fold (shl (and (setcc_c), c1), c2) -> (and setcc_c, (c1 << c2))
|
||||||
|
// since the result of setcc_c is all zero's or all ones.
|
||||||
|
if (N1C && N0.getOpcode() == ISD::AND &&
|
||||||
|
N0.getOperand(1).getOpcode() == ISD::Constant) {
|
||||||
|
SDValue N00 = N0.getOperand(0);
|
||||||
|
if (N00.getOpcode() == X86ISD::SETCC_CARRY ||
|
||||||
|
((N00.getOpcode() == ISD::ANY_EXTEND ||
|
||||||
|
N00.getOpcode() == ISD::ZERO_EXTEND) &&
|
||||||
|
N00.getOperand(0).getOpcode() == X86ISD::SETCC_CARRY)) {
|
||||||
|
APInt Mask = cast<ConstantSDNode>(N0.getOperand(1))->getAPIntValue();
|
||||||
|
APInt ShAmt = N1C->getAPIntValue();
|
||||||
|
Mask = Mask.shl(ShAmt);
|
||||||
|
if (Mask != 0)
|
||||||
|
return DAG.getNode(ISD::AND, N->getDebugLoc(), VT,
|
||||||
|
N00, DAG.getConstant(Mask, VT));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SDValue();
|
||||||
|
}
|
||||||
|
|
||||||
/// PerformShiftCombine - Transforms vector shift nodes to use vector shifts
|
/// PerformShiftCombine - Transforms vector shift nodes to use vector shifts
|
||||||
/// when possible.
|
/// when possible.
|
||||||
static SDValue PerformShiftCombine(SDNode* N, SelectionDAG &DAG,
|
static SDValue PerformShiftCombine(SDNode* N, SelectionDAG &DAG,
|
||||||
const X86Subtarget *Subtarget) {
|
const X86Subtarget *Subtarget) {
|
||||||
|
EVT VT = N->getValueType(0);
|
||||||
|
if (!VT.isVector() && VT.isInteger() &&
|
||||||
|
N->getOpcode() == ISD::SHL)
|
||||||
|
return PerformSHLCombine(N, DAG);
|
||||||
|
|
||||||
// On X86 with SSE2 support, we can transform this to a vector shift if
|
// On X86 with SSE2 support, we can transform this to a vector shift if
|
||||||
// all elements are shifted by the same amount. We can't do this in legalize
|
// all elements are shifted by the same amount. We can't do this in legalize
|
||||||
// because the a constant vector is typically transformed to a constant pool
|
// because the a constant vector is typically transformed to a constant pool
|
||||||
@ -8962,7 +9021,6 @@ static SDValue PerformShiftCombine(SDNode* N, SelectionDAG &DAG,
|
|||||||
if (!Subtarget->hasSSE2())
|
if (!Subtarget->hasSSE2())
|
||||||
return SDValue();
|
return SDValue();
|
||||||
|
|
||||||
EVT VT = N->getValueType(0);
|
|
||||||
if (VT != MVT::v2i64 && VT != MVT::v4i32 && VT != MVT::v8i16)
|
if (VT != MVT::v2i64 && VT != MVT::v4i32 && VT != MVT::v8i16)
|
||||||
return SDValue();
|
return SDValue();
|
||||||
|
|
||||||
|
@ -118,6 +118,10 @@ namespace llvm {
|
|||||||
/// operand produced by a CMP instruction.
|
/// operand produced by a CMP instruction.
|
||||||
SETCC,
|
SETCC,
|
||||||
|
|
||||||
|
// Same as SETCC except it's materialized with a sbb and the value is all
|
||||||
|
// one's or all zero's.
|
||||||
|
SETCC_CARRY,
|
||||||
|
|
||||||
/// X86 conditional moves. Operand 0 and operand 1 are the two values
|
/// X86 conditional moves. Operand 0 and operand 1 are the two values
|
||||||
/// to select from. Operand 2 is the condition code, and operand 3 is the
|
/// to select from. Operand 2 is the condition code, and operand 3 is the
|
||||||
/// flag operand produced by a CMP or TEST instruction. It also writes a
|
/// flag operand produced by a CMP or TEST instruction. It also writes a
|
||||||
|
@ -1333,6 +1333,15 @@ def CMOVNO64rm : RI<0x41, MRMSrcMem, // if !overflow, GR64 = [mem64]
|
|||||||
X86_COND_NO, EFLAGS))]>, TB;
|
X86_COND_NO, EFLAGS))]>, TB;
|
||||||
} // isTwoAddress
|
} // isTwoAddress
|
||||||
|
|
||||||
|
// Use sbb to materialize carry flag into a GPR.
|
||||||
|
let Defs = [EFLAGS], Uses = [EFLAGS], isCodeGenOnly = 1 in
|
||||||
|
def SETB_C64r : RI<0x19, MRMDestReg, (outs GR64:$dst), (ins),
|
||||||
|
"sbb{q}\t$dst, $dst",
|
||||||
|
[(set GR64:$dst, (zext (X86setcc_c X86_COND_B, EFLAGS)))]>;
|
||||||
|
|
||||||
|
def : Pat<(i64 (anyext (X86setcc_c X86_COND_B, EFLAGS))),
|
||||||
|
(SETB_C64r)>;
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Conversion Instructions...
|
// Conversion Instructions...
|
||||||
//
|
//
|
||||||
|
@ -87,6 +87,7 @@ def X86cmov : SDNode<"X86ISD::CMOV", SDTX86Cmov>;
|
|||||||
def X86brcond : SDNode<"X86ISD::BRCOND", SDTX86BrCond,
|
def X86brcond : SDNode<"X86ISD::BRCOND", SDTX86BrCond,
|
||||||
[SDNPHasChain]>;
|
[SDNPHasChain]>;
|
||||||
def X86setcc : SDNode<"X86ISD::SETCC", SDTX86SetCC>;
|
def X86setcc : SDNode<"X86ISD::SETCC", SDTX86SetCC>;
|
||||||
|
def X86setcc_c : SDNode<"X86ISD::SETCC_CARRY", SDTX86SetCC>;
|
||||||
|
|
||||||
def X86cas : SDNode<"X86ISD::LCMPXCHG_DAG", SDTX86cas,
|
def X86cas : SDNode<"X86ISD::LCMPXCHG_DAG", SDTX86cas,
|
||||||
[SDNPHasChain, SDNPInFlag, SDNPOutFlag, SDNPMayStore,
|
[SDNPHasChain, SDNPInFlag, SDNPOutFlag, SDNPMayStore,
|
||||||
@ -3059,6 +3060,21 @@ let Defs = [AH], Uses = [EFLAGS], neverHasSideEffects = 1 in
|
|||||||
def LAHF : I<0x9F, RawFrm, (outs), (ins), "lahf", []>; // AH = flags
|
def LAHF : I<0x9F, RawFrm, (outs), (ins), "lahf", []>; // AH = flags
|
||||||
|
|
||||||
let Uses = [EFLAGS] in {
|
let Uses = [EFLAGS] in {
|
||||||
|
// Use sbb to materialize carry bit.
|
||||||
|
|
||||||
|
let Defs = [EFLAGS], isCodeGenOnly = 1 in {
|
||||||
|
def SETB_C8r : I<0x18, MRMInitReg, (outs GR8:$dst), (ins),
|
||||||
|
"sbb{b}\t$dst, $dst",
|
||||||
|
[(set GR8:$dst, (X86setcc_c X86_COND_B, EFLAGS))]>;
|
||||||
|
def SETB_C16r : I<0x19, MRMInitReg, (outs GR16:$dst), (ins),
|
||||||
|
"sbb{w}\t$dst, $dst",
|
||||||
|
[(set GR16:$dst, (zext (X86setcc_c X86_COND_B, EFLAGS)))]>,
|
||||||
|
OpSize;
|
||||||
|
def SETB_C32r : I<0x19, MRMInitReg, (outs GR32:$dst), (ins),
|
||||||
|
"sbb{l}\t$dst, $dst",
|
||||||
|
[(set GR32:$dst, (zext (X86setcc_c X86_COND_B, EFLAGS)))]>;
|
||||||
|
} // isCodeGenOnly
|
||||||
|
|
||||||
def SETEr : I<0x94, MRM0r,
|
def SETEr : I<0x94, MRM0r,
|
||||||
(outs GR8 :$dst), (ins),
|
(outs GR8 :$dst), (ins),
|
||||||
"sete\t$dst",
|
"sete\t$dst",
|
||||||
@ -4169,6 +4185,12 @@ def : Pat<(store (shld (loadi16 addr:$dst), (i8 imm:$amt1),
|
|||||||
GR16:$src2, (i8 imm:$amt2)), addr:$dst),
|
GR16:$src2, (i8 imm:$amt2)), addr:$dst),
|
||||||
(SHLD16mri8 addr:$dst, GR16:$src2, (i8 imm:$amt1))>;
|
(SHLD16mri8 addr:$dst, GR16:$src2, (i8 imm:$amt1))>;
|
||||||
|
|
||||||
|
// (anyext (setcc_carry)) -> (zext (setcc_carry))
|
||||||
|
def : Pat<(i16 (anyext (X86setcc_c X86_COND_B, EFLAGS))),
|
||||||
|
(SETB_C16r)>;
|
||||||
|
def : Pat<(i32 (anyext (X86setcc_c X86_COND_B, EFLAGS))),
|
||||||
|
(SETB_C32r)>;
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// EFLAGS-defining Patterns
|
// EFLAGS-defining Patterns
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
; RUN: llc < %s -mtriple=x86_64-apple-darwin | FileCheck %s
|
; RUN: llc < %s -mtriple=x86_64-apple-darwin | FileCheck %s
|
||||||
|
; rdar://7329206
|
||||||
|
|
||||||
|
; Use sbb x, x to materialize carry bit in a GPR. The value is either
|
||||||
|
; all 1's or all 0's.
|
||||||
|
|
||||||
define zeroext i16 @t1(i16 zeroext %x) nounwind readnone ssp {
|
define zeroext i16 @t1(i16 zeroext %x) nounwind readnone ssp {
|
||||||
entry:
|
entry:
|
||||||
@ -11,3 +15,22 @@ entry:
|
|||||||
ret i16 %iftmp.1.0
|
ret i16 %iftmp.1.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define zeroext i16 @t2(i16 zeroext %x) nounwind readnone ssp {
|
||||||
|
entry:
|
||||||
|
; CHECK: t2:
|
||||||
|
; CHECK: sbbl %eax, %eax
|
||||||
|
; CHECK: andl $32, %eax
|
||||||
|
%0 = icmp ult i16 %x, 26 ; <i1> [#uses=1]
|
||||||
|
%iftmp.0.0 = select i1 %0, i16 32, i16 0 ; <i16> [#uses=1]
|
||||||
|
ret i16 %iftmp.0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @t3(i64 %x) nounwind readnone ssp {
|
||||||
|
entry:
|
||||||
|
; CHECK: t3:
|
||||||
|
; CHECK: sbbq %rax, %rax
|
||||||
|
; CHECK: andq $64, %rax
|
||||||
|
%0 = icmp ult i64 %x, 18 ; <i1> [#uses=1]
|
||||||
|
%iftmp.2.0 = select i1 %0, i64 64, i64 0 ; <i64> [#uses=1]
|
||||||
|
ret i64 %iftmp.2.0
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user