1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 10:42:39 +01:00

AArch64ISel: Fix ccmp code selection matching deep expressions.

Some of the conditions necessary to produce ccmp sequences were only
checked in recursive calls to emitConjunctionDisjunctionTree() after
some of the earlier expressions were already built. Move all checks over
to isConjunctionDisjunctionTree() so they are all checked before we
start emitting instructions.

Also rename some variable to better reflect their usage.

llvm-svn: 258605
This commit is contained in:
Matthias Braun 2016-01-23 04:05:22 +00:00
parent da14179563
commit 0892910f16
2 changed files with 98 additions and 48 deletions

View File

@ -1317,13 +1317,13 @@ static SDValue emitConditionalComparison(SDValue LHS, SDValue RHS,
/// at the leafs only. i.e. "not (or (or x y) z)" can be changed to
/// "and (and (not x) (not y)) (not z)"; "not (or (and x y) z)" cannot be
/// brought into such a form.
static bool isConjunctionDisjunctionTree(const SDValue Val, bool &CanPushNegate,
static bool isConjunctionDisjunctionTree(const SDValue Val, bool &CanNegate,
unsigned Depth = 0) {
if (!Val.hasOneUse())
return false;
unsigned Opcode = Val->getOpcode();
if (Opcode == ISD::SETCC) {
CanPushNegate = true;
CanNegate = true;
return true;
}
// Protect against exponential runtime and stack overflow.
@ -1332,16 +1332,32 @@ static bool isConjunctionDisjunctionTree(const SDValue Val, bool &CanPushNegate,
if (Opcode == ISD::AND || Opcode == ISD::OR) {
SDValue O0 = Val->getOperand(0);
SDValue O1 = Val->getOperand(1);
bool CanPushNegateL;
if (!isConjunctionDisjunctionTree(O0, CanPushNegateL, Depth+1))
bool CanNegateL;
if (!isConjunctionDisjunctionTree(O0, CanNegateL, Depth+1))
return false;
bool CanPushNegateR;
if (!isConjunctionDisjunctionTree(O1, CanPushNegateR, Depth+1))
bool CanNegateR;
if (!isConjunctionDisjunctionTree(O1, CanNegateR, Depth+1))
return false;
// We cannot push a negate through an AND operation (it would become an OR),
// we can however change a (not (or x y)) to (and (not x) (not y)) if we can
// push the negate through the x/y subtrees.
CanPushNegate = (Opcode == ISD::OR) && CanPushNegateL && CanPushNegateR;
if (Opcode == ISD::OR) {
// For an OR expression we need to be able to negate at least one side or
// we cannot do the transformation at all.
if (!CanNegateL && !CanNegateR)
return false;
// We can however change a (not (or x y)) to (and (not x) (not y)) if we
// can negate the x and y subtrees.
CanNegate = CanNegateL && CanNegateR;
} else {
// If the operands are OR expressions then we finally need to negate their
// outputs, we can only do that for the operand with emitted last by
// negating OutCC, not for both operands.
bool NeedsNegOutL = O0->getOpcode() == ISD::OR;
bool NeedsNegOutR = O1->getOpcode() == ISD::OR;
if (NeedsNegOutL && NeedsNegOutR)
return false;
// We cannot negate an AND operation (it would become an OR),
CanNegate = false;
}
return true;
}
return false;
@ -1357,10 +1373,9 @@ static bool isConjunctionDisjunctionTree(const SDValue Val, bool &CanPushNegate,
/// effects pushed to the tree leafs; @p Predicate is an NZCV flag predicate
/// for the comparisons in the current subtree; @p Depth limits the search
/// depth to avoid stack overflow.
static SDValue emitConjunctionDisjunctionTree(SelectionDAG &DAG, SDValue Val,
AArch64CC::CondCode &OutCC, bool PushNegate = false,
SDValue CCOp = SDValue(), AArch64CC::CondCode Predicate = AArch64CC::AL,
unsigned Depth = 0) {
static SDValue emitConjunctionDisjunctionTreeRec(SelectionDAG &DAG, SDValue Val,
AArch64CC::CondCode &OutCC, bool Negate, SDValue CCOp,
AArch64CC::CondCode Predicate) {
// We're at a tree leaf, produce a conditional comparison operation.
unsigned Opcode = Val->getOpcode();
if (Opcode == ISD::SETCC) {
@ -1368,7 +1383,7 @@ static SDValue emitConjunctionDisjunctionTree(SelectionDAG &DAG, SDValue Val,
SDValue RHS = Val->getOperand(1);
ISD::CondCode CC = cast<CondCodeSDNode>(Val->getOperand(2))->get();
bool isInteger = LHS.getValueType().isInteger();
if (PushNegate)
if (Negate)
CC = getSetCCInverse(CC, isInteger);
SDLoc DL(Val);
// Determine OutCC and handle FP special case.
@ -1393,43 +1408,47 @@ static SDValue emitConjunctionDisjunctionTree(SelectionDAG &DAG, SDValue Val,
}
// Produce a normal comparison if we are first in the chain
if (!CCOp.getNode())
if (!CCOp)
return emitComparison(LHS, RHS, CC, DL, DAG);
// Otherwise produce a ccmp.
return emitConditionalComparison(LHS, RHS, CC, CCOp, Predicate, OutCC, DL,
DAG);
} else if ((Opcode != ISD::AND && Opcode != ISD::OR) || !Val->hasOneUse())
return SDValue();
assert((Opcode == ISD::OR || !PushNegate)
&& "Can only push negate through OR operation");
}
assert(Opcode == ISD::AND || Opcode == ISD::OR && Val->hasOneUse()
&& "Valid conjunction/disjunction tree");
// Check if both sides can be transformed.
SDValue LHS = Val->getOperand(0);
SDValue RHS = Val->getOperand(1);
bool CanPushNegateL;
if (!isConjunctionDisjunctionTree(LHS, CanPushNegateL, Depth+1))
return SDValue();
bool CanPushNegateR;
if (!isConjunctionDisjunctionTree(RHS, CanPushNegateR, Depth+1))
return SDValue();
// Do we need to negate our operands?
bool NegateOperands = Opcode == ISD::OR;
// In case of an OR we need to negate our operands and the result.
// (A v B) <=> not(not(A) ^ not(B))
bool NegateOpsAndResult = Opcode == ISD::OR;
// We can negate the results of all previous operations by inverting the
// predicate flags giving us a free negation for one side. For the other side
// we need to be able to push the negation to the leafs of the tree.
if (NegateOperands) {
if (!CanPushNegateL && !CanPushNegateR)
return SDValue();
// Order the side where we can push the negate through to LHS.
if (!CanPushNegateL && CanPushNegateR)
// predicate flags giving us a free negation for one side. The other side
// must be negatable by itself.
if (NegateOpsAndResult) {
// See which side we can negate.
bool CanNegateL;
bool isValidL = isConjunctionDisjunctionTree(LHS, CanNegateL);
assert(isValidL && "Valid conjunction/disjunction tree");
(void)isValidL;
#ifndef NDEBUG
bool CanNegateR;
bool isValidR = isConjunctionDisjunctionTree(RHS, CanNegateR);
assert(isValidR && "Valid conjunction/disjunction tree");
assert((CanNegateL || CanNegateR) && "Valid conjunction/disjunction tree");
#endif
// Order the side which we cannot negate to RHS so we can emit it first.
if (!CanNegateL)
std::swap(LHS, RHS);
} else {
bool NeedsNegOutL = LHS->getOpcode() == ISD::OR;
bool NeedsNegOutR = RHS->getOpcode() == ISD::OR;
if (NeedsNegOutL && NeedsNegOutR)
return SDValue();
assert((!NeedsNegOutR || !NeedsNegOutL) &&
"Valid conjunction/disjunction tree");
// Order the side where we need to negate the output flags to RHS so it
// gets emitted first.
if (NeedsNegOutL)
@ -1440,22 +1459,34 @@ static SDValue emitConjunctionDisjunctionTree(SelectionDAG &DAG, SDValue Val,
// through if we are already in a PushNegate case, otherwise we can negate
// the "flags to test" afterwards.
AArch64CC::CondCode RHSCC;
SDValue CmpR = emitConjunctionDisjunctionTree(DAG, RHS, RHSCC, PushNegate,
CCOp, Predicate, Depth+1);
assert(CmpR && "Transform legality should have been checked already!");
if (NegateOperands && !PushNegate)
SDValue CmpR = emitConjunctionDisjunctionTreeRec(DAG, RHS, RHSCC, Negate,
CCOp, Predicate);
if (NegateOpsAndResult && !Negate)
RHSCC = AArch64CC::getInvertedCondCode(RHSCC);
// Emit LHS. We must push the negate through if we need to negate it.
SDValue CmpL = emitConjunctionDisjunctionTree(DAG, LHS, OutCC, NegateOperands,
CmpR, RHSCC, Depth+1);
assert(CmpL && "Transform legality should have been checked already!");
// Emit LHS. We may need to negate it.
SDValue CmpL = emitConjunctionDisjunctionTreeRec(DAG, LHS, OutCC,
NegateOpsAndResult, CmpR,
RHSCC);
// If we transformed an OR to and AND then we have to negate the result
// (or absorb a PushNegate resulting in a double negation).
if (Opcode == ISD::OR && !PushNegate)
// (or absorb the Negate parameter).
if (NegateOpsAndResult && !Negate)
OutCC = AArch64CC::getInvertedCondCode(OutCC);
return CmpL;
}
/// Emit conjunction or disjunction tree with the CMP/FCMP followed by a chain
/// of CCMP/CFCMP ops. See @ref AArch64CCMP.
/// \see emitConjunctionDisjunctionTreeRec().
static SDValue emitConjunctionDisjunctionTree(SelectionDAG &DAG, SDValue Val,
AArch64CC::CondCode &OutCC) {
bool CanNegate;
if (!isConjunctionDisjunctionTree(Val, CanNegate))
return SDValue();
return emitConjunctionDisjunctionTreeRec(DAG, Val, OutCC, false, SDValue(),
AArch64CC::AL);
}
/// @}
static SDValue getAArch64Cmp(SDValue LHS, SDValue RHS, ISD::CondCode CC,

View File

@ -426,6 +426,25 @@ define i64 @select_noccmp2(i64 %v1, i64 %v2, i64 %v3, i64 %r) {
ret i64 %sel
}
; The following is not possible to implement with a single cmp;ccmp;csel
; sequence.
; CHECK-LABEL: select_noccmp3
define i32 @select_noccmp3(i32 %v0, i32 %v1, i32 %v2) {
%c0 = icmp slt i32 %v0, 0
%c1 = icmp sgt i32 %v0, 13
%c2 = icmp slt i32 %v0, 22
%c3 = icmp sgt i32 %v0, 44
%c4 = icmp eq i32 %v0, 99
%c5 = icmp eq i32 %v0, 77
%or0 = or i1 %c0, %c1
%or1 = or i1 %c2, %c3
%and0 = and i1 %or0, %or1
%or2 = or i1 %c4, %c5
%and1 = and i1 %and0, %or2
%sel = select i1 %and1, i32 %v1, i32 %v2
ret i32 %sel
}
; Test the IR CCs that expand to two cond codes.
; CHECK-LABEL: select_and_olt_one: