From c2751e7050b20be713d08b6e8001d57bb828c7ee Mon Sep 17 00:00:00 2001 From: Sanjay Patel Date: Sat, 7 May 2016 15:03:40 +0000 Subject: [x86, BMI] add TLI hook for 'andn' and use it to simplify comparisons For the sake of minimalism, this patch is x86 only, but I think that at least PPC, ARM, AArch64, and Sparc probably want to do this too. We might want to generalize the hook and pattern recognition for a target like PPC that has a full assortment of negated logic ops (orc, nand). Note that http://reviews.llvm.org/D18842 will cause this transform to trigger more often. For reference, this relates to: https://llvm.org/bugs/show_bug.cgi?id=27105 https://llvm.org/bugs/show_bug.cgi?id=27202 https://llvm.org/bugs/show_bug.cgi?id=27203 https://llvm.org/bugs/show_bug.cgi?id=27328 Differential Revision: http://reviews.llvm.org/D19087 llvm-svn: 268858 --- llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp | 49 ++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'llvm/lib/CodeGen/SelectionDAG') diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp index 762b34a8fbe..6faad8b8151 100644 --- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -1304,6 +1304,52 @@ bool TargetLowering::isExtendedTrueVal(const ConstantSDNode *N, EVT VT, llvm_unreachable("Unexpected enumeration."); } +/// If the target supports an 'and-not' or 'and-complement' logic operation, +/// try to use that to make a comparison operation more efficient. +static SDValue createAndNotSetCC(EVT VT, SDValue N0, SDValue N1, + ISD::CondCode Cond, SelectionDAG &DAG, + SDLoc dl) { + // Match these patterns in any of their permutations: + // (X & Y) == Y + // (X & Y) != Y + if (N1.getOpcode() == ISD::AND && N0.getOpcode() != ISD::AND) + std::swap(N0, N1); + + if (N0.getOpcode() != ISD::AND || !N0.hasOneUse() || + (Cond != ISD::SETEQ && Cond != ISD::SETNE)) + return SDValue(); + + SDValue X, Y; + if (N0.getOperand(0) == N1) { + X = N0.getOperand(1); + Y = N0.getOperand(0); + } else if (N0.getOperand(1) == N1) { + X = N0.getOperand(0); + Y = N0.getOperand(1); + } else { + return SDValue(); + } + + // Bail out if the compare operand that we want to turn into a zero is already + // a zero (otherwise, infinite loop). + auto *YConst = dyn_cast(Y); + if (YConst && YConst->isNullValue()) + return SDValue(); + + // We don't want to do this transform if the mask is a single bit because + // there are more efficient ways to deal with that case (for example, 'bt' on + // x86 or 'rlwinm' on PPC). + if (!DAG.getTargetLoweringInfo().hasAndNotCompare(Y) || + valueHasExactlyOneBitSet(Y, DAG)) + return SDValue(); + + // Transform this into: ~X & Y == 0. + EVT OpVT = X.getValueType(); + SDValue NotX = DAG.getNOT(SDLoc(X), X, OpVT); + SDValue NewAnd = DAG.getNode(ISD::AND, SDLoc(N0), OpVT, NotX, Y); + return DAG.getSetCC(dl, VT, NewAnd, DAG.getConstant(0, dl, OpVT), Cond); +} + /// Try to simplify a setcc built with the specified operands and cc. If it is /// unable to simplify it, return a null SDValue. SDValue @@ -2166,6 +2212,9 @@ TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1, return N0; } + if (SDValue AndNotCC = createAndNotSetCC(VT, N0, N1, Cond, DAG, dl)) + return AndNotCC; + // Could not fold it. return SDValue(); } -- cgit v1.2.3