1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-20 03:23:01 +02:00

Also combine zext/sext into selects for ARM.

This turns common i1 patterns into predicated instructions:

  (add (zext cc), x) -> (select cc (add x, 1), x)
  (add (sext cc), x) -> (select cc (add x, -1), x)

For a function like:

  unsigned f(unsigned s, int x) {
    return s + (x>0);
  }

We now produce:

  cmp r1, #0
  it  gt
  addgt.w r0, r0, #1

Instead of:

  movs  r2, #0
  cmp r1, #0
  it  gt
  movgt r2, #1
  add r0, r2

llvm-svn: 162177
This commit is contained in:
Jakob Stoklund Olesen 2012-08-18 21:25:22 +00:00
parent ece4a53017
commit e78d4a5b08
2 changed files with 116 additions and 47 deletions

View File

@ -6981,6 +6981,65 @@ static inline bool isZeroOrAllOnes(SDValue N, bool AllOnes) {
return AllOnes ? C->isAllOnesValue() : C->isNullValue();
}
// Return true if N is conditionally 0 or all ones.
// Detects these expressions where cc is an i1 value:
//
// (select cc 0, y) [AllOnes=0]
// (select cc y, 0) [AllOnes=0]
// (zext cc) [AllOnes=0]
// (sext cc) [AllOnes=0/1]
// (select cc -1, y) [AllOnes=1]
// (select cc y, -1) [AllOnes=1]
//
// Invert is set when N is the null/all ones constant when CC is false.
// OtherOp is set to the alternative value of N.
static bool isConditionalZeroOrAllOnes(SDNode *N, bool AllOnes,
SDValue &CC, bool &Invert,
SDValue &OtherOp,
SelectionDAG &DAG) {
switch (N->getOpcode()) {
default: return false;
case ISD::SELECT: {
CC = N->getOperand(0);
SDValue N1 = N->getOperand(1);
SDValue N2 = N->getOperand(2);
if (isZeroOrAllOnes(N1, AllOnes)) {
Invert = false;
OtherOp = N2;
return true;
}
if (isZeroOrAllOnes(N2, AllOnes)) {
Invert = true;
OtherOp = N1;
return true;
}
return false;
}
case ISD::ZERO_EXTEND:
// (zext cc) can never be the all ones value.
if (AllOnes)
return false;
// Fall through.
case ISD::SIGN_EXTEND: {
EVT VT = N->getValueType(0);
CC = N->getOperand(0);
if (CC.getValueType() != MVT::i1)
return false;
Invert = !AllOnes;
if (AllOnes)
// When looking for an AllOnes constant, N is an sext, and the 'other'
// value is 0.
OtherOp = DAG.getConstant(0, VT);
else if (N->getOpcode() == ISD::ZERO_EXTEND)
// When looking for a 0 constant, N can be zext or sext.
OtherOp = DAG.getConstant(1, VT);
else
OtherOp = DAG.getConstant(APInt::getAllOnesValue(VT.getSizeInBits()), VT);
return true;
}
}
}
// Combine a constant select operand into its use:
//
// (add (select cc, 0, c), x) -> (select cc, x, (add, x, c))
@ -6992,6 +7051,13 @@ static inline bool isZeroOrAllOnes(SDValue N, bool AllOnes) {
// The transform is rejected if the select doesn't have a constant operand that
// is null, or all ones when AllOnes is set.
//
// Also recognize sext/zext from i1:
//
// (add (zext cc), x) -> (select cc (add x, 1), x)
// (add (sext cc), x) -> (select cc (add x, -1), x)
//
// These transformations eventually create predicated instructions.
//
// @param N The node to transform.
// @param Slct The N operand that is a select.
// @param OtherOp The other N operand (x above).
@ -7003,53 +7069,24 @@ SDValue combineSelectAndUse(SDNode *N, SDValue Slct, SDValue OtherOp,
TargetLowering::DAGCombinerInfo &DCI,
bool AllOnes = false) {
SelectionDAG &DAG = DCI.DAG;
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
EVT VT = N->getValueType(0);
unsigned Opc = N->getOpcode();
bool isSlctCC = Slct.getOpcode() == ISD::SELECT_CC;
SDValue LHS = isSlctCC ? Slct.getOperand(2) : Slct.getOperand(1);
SDValue RHS = isSlctCC ? Slct.getOperand(3) : Slct.getOperand(2);
ISD::CondCode CC = ISD::SETCC_INVALID;
if (isSlctCC) {
CC = cast<CondCodeSDNode>(Slct.getOperand(4))->get();
} else {
SDValue CCOp = Slct.getOperand(0);
if (CCOp.getOpcode() == ISD::SETCC)
CC = cast<CondCodeSDNode>(CCOp.getOperand(2))->get();
}
bool DoXform = false;
bool InvCC = false;
if (isZeroOrAllOnes(LHS, AllOnes)) {
DoXform = true;
} else if (CC != ISD::SETCC_INVALID && isZeroOrAllOnes(RHS, AllOnes)) {
std::swap(LHS, RHS);
SDValue Op0 = Slct.getOperand(0);
EVT OpVT = isSlctCC ? Op0.getValueType() : Op0.getOperand(0).getValueType();
bool isInt = OpVT.isInteger();
CC = ISD::getSetCCInverse(CC, isInt);
if (!TLI.isCondCodeLegal(CC, OpVT))
return SDValue(); // Inverse operator isn't legal.
DoXform = true;
InvCC = true;
}
if (!DoXform)
SDValue NonConstantVal;
SDValue CCOp;
bool SwapSelectOps;
if (!isConditionalZeroOrAllOnes(Slct.getNode(), AllOnes, CCOp, SwapSelectOps,
NonConstantVal, DAG))
return SDValue();
SDValue Result = DAG.getNode(Opc, RHS.getDebugLoc(), VT, OtherOp, RHS);
if (isSlctCC)
return DAG.getSelectCC(N->getDebugLoc(), OtherOp, Result,
Slct.getOperand(0), Slct.getOperand(1), CC);
SDValue CCOp = Slct.getOperand(0);
if (InvCC)
CCOp = DAG.getSetCC(Slct.getDebugLoc(), CCOp.getValueType(),
CCOp.getOperand(0), CCOp.getOperand(1), CC);
// Slct is now know to be the desired identity constant when CC is true.
SDValue TrueVal = OtherOp;
SDValue FalseVal = DAG.getNode(N->getOpcode(), N->getDebugLoc(), VT,
OtherOp, NonConstantVal);
// Unless SwapSelectOps says CC should be false.
if (SwapSelectOps)
std::swap(TrueVal, FalseVal);
return DAG.getNode(ISD::SELECT, N->getDebugLoc(), VT,
CCOp, OtherOp, Result);
CCOp, TrueVal, FalseVal);
}
// Attempt combineSelectAndUse on each operand of a commutative operator N.
@ -7058,12 +7095,12 @@ SDValue combineSelectAndUseCommutative(SDNode *N, bool AllOnes,
TargetLowering::DAGCombinerInfo &DCI) {
SDValue N0 = N->getOperand(0);
SDValue N1 = N->getOperand(1);
if (N0.getOpcode() == ISD::SELECT && N0.getNode()->hasOneUse()) {
if (N0.getNode()->hasOneUse()) {
SDValue Result = combineSelectAndUse(N, N0, N1, DCI, AllOnes);
if (Result.getNode())
return Result;
}
if (N1.getOpcode() == ISD::SELECT && N1.getNode()->hasOneUse()) {
if (N1.getNode()->hasOneUse()) {
SDValue Result = combineSelectAndUse(N, N1, N0, DCI, AllOnes);
if (Result.getNode())
return Result;
@ -7174,7 +7211,7 @@ static SDValue PerformADDCombineWithOperands(SDNode *N, SDValue N0, SDValue N1,
return Result;
// fold (add (select cc, 0, c), x) -> (select cc, x, (add, x, c))
if (N0.getOpcode() == ISD::SELECT && N0.getNode()->hasOneUse()) {
if (N0.getNode()->hasOneUse()) {
SDValue Result = combineSelectAndUse(N, N0, N1, DCI);
if (Result.getNode()) return Result;
}
@ -7206,7 +7243,7 @@ static SDValue PerformSUBCombine(SDNode *N,
SDValue N1 = N->getOperand(1);
// fold (sub x, (select cc, 0, c)) -> (select cc, x, (sub, x, c))
if (N1.getOpcode() == ISD::SELECT && N1.getNode()->hasOneUse()) {
if (N1.getNode()->hasOneUse()) {
SDValue Result = combineSelectAndUse(N, N1, N0, DCI);
if (Result.getNode()) return Result;
}

View File

@ -190,3 +190,35 @@ define void @pr13628() nounwind uwtable align 2 {
ret void
}
declare void @bar(i8*)
; Fold zext i1 into predicated add
define i32 @t13(i32 %c, i32 %a) nounwind readnone ssp {
entry:
; ARM: t13
; ARM: cmp r1, #10
; ARM: addgt r0, r0, #1
; T2: t13
; T2: cmp r1, #10
; T2: addgt.w r0, r0, #1
%cmp = icmp sgt i32 %a, 10
%conv = zext i1 %cmp to i32
%add = add i32 %conv, %c
ret i32 %add
}
; Fold sext i1 into predicated sub
define i32 @t14(i32 %c, i32 %a) nounwind readnone ssp {
entry:
; ARM: t14
; ARM: cmp r1, #10
; ARM: subgt r0, r0, #1
; T2: t14
; T2: cmp r1, #10
; T2: subgt.w r0, r0, #1
%cmp = icmp sgt i32 %a, 10
%conv = sext i1 %cmp to i32
%add = add i32 %conv, %c
ret i32 %add
}