summaryrefslogtreecommitdiffstats
path: root/llvm
diff options
context:
space:
mode:
authorCraig Topper <craig.topper@intel.com>2018-12-24 05:27:13 +0000
committerCraig Topper <craig.topper@intel.com>2018-12-24 05:27:13 +0000
commitd8217b23ffb95e1affbe47f6d54f695d0eebfb30 (patch)
tree0857e9cc31b1e1aedf5a24969c3b59670df5117a /llvm
parent9ea1e9136bf3b74ffbdecc070a58df1f6ab55926 (diff)
downloadbcm5719-llvm-d8217b23ffb95e1affbe47f6d54f695d0eebfb30.tar.gz
bcm5719-llvm-d8217b23ffb95e1affbe47f6d54f695d0eebfb30.zip
[X86] Move the optimization that turns 'CMP (AND+IMM64), 0' into SRL/SHL+TEST to X86ISelDAGToDAG.
This cleans more code out of EmitTest. llvm-svn: 350041
Diffstat (limited to 'llvm')
-rw-r--r--llvm/lib/Target/X86/X86ISelDAGToDAG.cpp75
-rw-r--r--llvm/lib/Target/X86/X86ISelLowering.cpp55
2 files changed, 75 insertions, 55 deletions
diff --git a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
index 90fc39f97a4..7e171d77033 100644
--- a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
@@ -473,6 +473,7 @@ namespace {
bool tryOptimizeRem8Extend(SDNode *N);
+ bool onlyUsesZeroFlag(SDValue Flags) const;
bool hasNoSignFlagUses(SDValue Flags) const;
bool hasNoCarryFlagUses(SDValue Flags) const;
};
@@ -2250,6 +2251,42 @@ static X86::CondCode getCondFromOpc(unsigned Opc) {
return CC;
}
+/// Test whether the given X86ISD::CMP node has any users that use a flag
+/// other than ZF.
+bool X86DAGToDAGISel::onlyUsesZeroFlag(SDValue Flags) const {
+ // Examine each user of the node.
+ for (SDNode::use_iterator UI = Flags->use_begin(), UE = Flags->use_end();
+ UI != UE; ++UI) {
+ // Only check things that use the flags.
+ if (UI.getUse().getResNo() != Flags.getResNo())
+ continue;
+ // Only examine CopyToReg uses that copy to EFLAGS.
+ if (UI->getOpcode() != ISD::CopyToReg ||
+ cast<RegisterSDNode>(UI->getOperand(1))->getReg() != X86::EFLAGS)
+ return false;
+ // Examine each user of the CopyToReg use.
+ for (SDNode::use_iterator FlagUI = UI->use_begin(),
+ FlagUE = UI->use_end(); FlagUI != FlagUE; ++FlagUI) {
+ // Only examine the Flag result.
+ if (FlagUI.getUse().getResNo() != 1) continue;
+ // Anything unusual: assume conservatively.
+ if (!FlagUI->isMachineOpcode()) return false;
+ // Examine the condition code of the user.
+ X86::CondCode CC = getCondFromOpc(FlagUI->getMachineOpcode());
+
+ switch (CC) {
+ // Comparisons which only use the zero flag.
+ case X86::COND_E: case X86::COND_NE:
+ continue;
+ // Anything else: assume conservatively.
+ default:
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
/// Test whether the given X86ISD::CMP node has any uses which require the SF
/// flag to be accurate.
bool X86DAGToDAGISel::hasNoSignFlagUses(SDValue Flags) const {
@@ -3685,6 +3722,10 @@ void X86DAGToDAGISel::Select(SDNode *Node) {
SDValue N0 = Node->getOperand(0);
SDValue N1 = Node->getOperand(1);
+ // Optimizations for TEST compares.
+ if (!isNullConstant(N1))
+ break;
+
// Save the original VT of the compare.
MVT CmpVT = N0.getSimpleValueType();
@@ -3692,7 +3733,7 @@ void X86DAGToDAGISel::Select(SDNode *Node) {
// by a test instruction. The test should be removed later by
// analyzeCompare if we are using only the zero flag.
// TODO: Should we check the users and use the BEXTR flags directly?
- if (isNullConstant(N1) && N0.getOpcode() == ISD::AND && N0.hasOneUse()) {
+ if (N0.getOpcode() == ISD::AND && N0.hasOneUse()) {
if (MachineSDNode *NewNode = matchBEXTRFromAndImm(N0.getNode())) {
unsigned TestOpc = CmpVT == MVT::i64 ? X86::TEST64rr
: X86::TEST32rr;
@@ -3713,12 +3754,40 @@ void X86DAGToDAGISel::Select(SDNode *Node) {
// Look past the truncate if CMP is the only use of it.
if (N0.getOpcode() == ISD::AND &&
N0.getNode()->hasOneUse() &&
- N0.getValueType() != MVT::i8 &&
- isNullConstant(N1)) {
+ N0.getValueType() != MVT::i8) {
ConstantSDNode *C = dyn_cast<ConstantSDNode>(N0.getOperand(1));
if (!C) break;
uint64_t Mask = C->getZExtValue();
+ // Check if we can replace AND+IMM64 with a shift. This is possible for
+ // masks/ like 0xFF000000 or 0x00FFFFFF and if we care only about the zero
+ // flag.
+ if (CmpVT == MVT::i64 && !isInt<32>(Mask) &&
+ onlyUsesZeroFlag(SDValue(Node, 0))) {
+ if (isMask_64(~Mask)) {
+ unsigned TrailingZeros = countTrailingZeros(Mask);
+ SDValue Imm = CurDAG->getTargetConstant(TrailingZeros, dl, MVT::i64);
+ SDValue Shift =
+ SDValue(CurDAG->getMachineNode(X86::SHR64ri, dl, MVT::i64,
+ N0.getOperand(0), Imm), 0);
+ MachineSDNode *Test = CurDAG->getMachineNode(X86::TEST64rr, dl,
+ MVT::i32, Shift, Shift);
+ ReplaceNode(Node, Test);
+ return;
+ }
+ if (isMask_64(Mask)) {
+ unsigned LeadingZeros = countLeadingZeros(Mask);
+ SDValue Imm = CurDAG->getTargetConstant(LeadingZeros, dl, MVT::i64);
+ SDValue Shift =
+ SDValue(CurDAG->getMachineNode(X86::SHL64ri, dl, MVT::i64,
+ N0.getOperand(0), Imm), 0);
+ MachineSDNode *Test = CurDAG->getMachineNode(X86::TEST64rr, dl,
+ MVT::i32, Shift, Shift);
+ ReplaceNode(Node, Test);
+ return;
+ }
+ }
+
MVT VT;
int SubRegOp;
unsigned ROpc, MOpc;
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index c2230ee598c..85bcb8d2803 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -18690,59 +18690,10 @@ static SDValue EmitTest(SDValue Op, unsigned X86CC, const SDLoc &dl,
case ISD::AND:
// If the primary 'and' result isn't used, don't bother using X86ISD::AND,
- // because a TEST instruction will be better. However, AND should be
- // preferred if the instruction can be combined into ANDN.
- if (!hasNonFlagsUse(Op)) {
- SDValue Op0 = ArithOp->getOperand(0);
- SDValue Op1 = ArithOp->getOperand(1);
- EVT VT = ArithOp.getValueType();
-
- // Check if we can replace AND+IMM64 with a shift before giving up. This
- // is possible for masks/ like 0xFF000000 or 0x00FFFFFF and if we care
- // only about the zero flag.
- if (!ZeroCheck)
- break;
-
- // And with constant should be canonicalized unless we're dealing
- // with opaque constants.
- assert((!isa<ConstantSDNode>(Op0) ||
- (isa<ConstantSDNode>(Op1) &&
- (cast<ConstantSDNode>(Op0)->isOpaque() ||
- cast<ConstantSDNode>(Op1)->isOpaque()))) &&
- "AND node isn't canonicalized");
- auto *CN = dyn_cast<ConstantSDNode>(Op1);
- if (!CN)
- break;
-
- const APInt &Mask = CN->getAPIntValue();
- if (Mask.isSignedIntN(ShiftToAndMaxMaskWidth))
- break; // Prefer TEST instruction.
-
- unsigned BitWidth = Mask.getBitWidth();
- unsigned LeadingOnes = Mask.countLeadingOnes();
- unsigned TrailingZeros = Mask.countTrailingZeros();
-
- if (LeadingOnes + TrailingZeros == BitWidth) {
- assert(TrailingZeros < VT.getSizeInBits() &&
- "Shift amount should be less than the type width");
- SDValue ShAmt = DAG.getConstant(TrailingZeros, dl, MVT::i8);
- Op = DAG.getNode(ISD::SRL, dl, VT, Op0, ShAmt);
- break;
- }
-
- unsigned LeadingZeros = Mask.countLeadingZeros();
- unsigned TrailingOnes = Mask.countTrailingOnes();
-
- if (LeadingZeros + TrailingOnes == BitWidth) {
- assert(LeadingZeros < VT.getSizeInBits() &&
- "Shift amount should be less than the type width");
- SDValue ShAmt = DAG.getConstant(LeadingZeros, dl, MVT::i8);
- Op = DAG.getNode(ISD::SHL, dl, VT, Op0, ShAmt);
- break;
- }
-
+ // because a TEST instruction will be better.
+ if (!hasNonFlagsUse(Op))
break;
- }
+
LLVM_FALLTHROUGH;
case ISD::SUB:
case ISD::OR:
OpenPOWER on IntegriCloud