forked from OSchip/llvm-project
[SystemZ] Add a structure to represent a selected comparison
...in an attempt to rein back the increasingly complex selection code. A knock-on effect is that ICmpType is exposed from the outset, which slightly simplifies adjustSubwordCmp. The code is no piece of art even after this change, but at least it should be slightly better. No behavioral change intended. llvm-svn: 197235
This commit is contained in:
parent
bd2f0e9cd0
commit
d420f7344f
|
@ -38,6 +38,27 @@ struct IPMConversion {
|
||||||
int64_t AddValue;
|
int64_t AddValue;
|
||||||
unsigned Bit;
|
unsigned Bit;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Represents information about a comparison.
|
||||||
|
struct Comparison {
|
||||||
|
Comparison(SDValue Op0In, SDValue Op1In)
|
||||||
|
: Op0(Op0In), Op1(Op1In), Opcode(0), ICmpType(0), CCValid(0), CCMask(0) {}
|
||||||
|
|
||||||
|
// The operands to the comparison.
|
||||||
|
SDValue Op0, Op1;
|
||||||
|
|
||||||
|
// The opcode that should be used to compare Op0 and Op1.
|
||||||
|
unsigned Opcode;
|
||||||
|
|
||||||
|
// A SystemZICMP value. Only used for integer comparisons.
|
||||||
|
unsigned ICmpType;
|
||||||
|
|
||||||
|
// The mask of CC values that Opcode can produce.
|
||||||
|
unsigned CCValid;
|
||||||
|
|
||||||
|
// The mask of CC values for which the original condition is true.
|
||||||
|
unsigned CCMask;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Classify VT as either 32 or 64 bit.
|
// Classify VT as either 32 or 64 bit.
|
||||||
|
@ -1070,103 +1091,94 @@ static IPMConversion getIPMConversion(unsigned CCValid, unsigned CCMask) {
|
||||||
llvm_unreachable("Unexpected CC combination");
|
llvm_unreachable("Unexpected CC combination");
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a comparison described by IsUnsigned, CCMask, CmpOp0 and CmpOp1
|
// If C can be converted to a comparison against zero, adjust the operands
|
||||||
// can be converted to a comparison against zero, adjust the operands
|
|
||||||
// as necessary.
|
// as necessary.
|
||||||
static void adjustZeroCmp(SelectionDAG &DAG, bool &IsUnsigned,
|
static void adjustZeroCmp(SelectionDAG &DAG, Comparison &C) {
|
||||||
SDValue &CmpOp0, SDValue &CmpOp1,
|
if (C.ICmpType == SystemZICMP::UnsignedOnly)
|
||||||
unsigned &CCMask) {
|
|
||||||
if (IsUnsigned)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ConstantSDNode *ConstOp1 = dyn_cast<ConstantSDNode>(CmpOp1.getNode());
|
ConstantSDNode *ConstOp1 = dyn_cast<ConstantSDNode>(C.Op1.getNode());
|
||||||
if (!ConstOp1)
|
if (!ConstOp1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int64_t Value = ConstOp1->getSExtValue();
|
int64_t Value = ConstOp1->getSExtValue();
|
||||||
if ((Value == -1 && CCMask == SystemZ::CCMASK_CMP_GT) ||
|
if ((Value == -1 && C.CCMask == SystemZ::CCMASK_CMP_GT) ||
|
||||||
(Value == -1 && CCMask == SystemZ::CCMASK_CMP_LE) ||
|
(Value == -1 && C.CCMask == SystemZ::CCMASK_CMP_LE) ||
|
||||||
(Value == 1 && CCMask == SystemZ::CCMASK_CMP_LT) ||
|
(Value == 1 && C.CCMask == SystemZ::CCMASK_CMP_LT) ||
|
||||||
(Value == 1 && CCMask == SystemZ::CCMASK_CMP_GE)) {
|
(Value == 1 && C.CCMask == SystemZ::CCMASK_CMP_GE)) {
|
||||||
CCMask ^= SystemZ::CCMASK_CMP_EQ;
|
C.CCMask ^= SystemZ::CCMASK_CMP_EQ;
|
||||||
CmpOp1 = DAG.getConstant(0, CmpOp1.getValueType());
|
C.Op1 = DAG.getConstant(0, C.Op1.getValueType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a comparison described by IsUnsigned, CCMask, CmpOp0 and CmpOp1
|
// If a comparison described by C is suitable for CLI(Y), CHHSI or CLHHSI,
|
||||||
// is suitable for CLI(Y), CHHSI or CLHHSI, adjust the operands as necessary.
|
// adjust the operands as necessary.
|
||||||
static void adjustSubwordCmp(SelectionDAG &DAG, bool &IsUnsigned,
|
static void adjustSubwordCmp(SelectionDAG &DAG, Comparison &C) {
|
||||||
SDValue &CmpOp0, SDValue &CmpOp1,
|
|
||||||
unsigned &CCMask) {
|
|
||||||
// For us to make any changes, it must a comparison between a single-use
|
// For us to make any changes, it must a comparison between a single-use
|
||||||
// load and a constant.
|
// load and a constant.
|
||||||
if (!CmpOp0.hasOneUse() ||
|
if (!C.Op0.hasOneUse() ||
|
||||||
CmpOp0.getOpcode() != ISD::LOAD ||
|
C.Op0.getOpcode() != ISD::LOAD ||
|
||||||
CmpOp1.getOpcode() != ISD::Constant)
|
C.Op1.getOpcode() != ISD::Constant)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// We must have an 8- or 16-bit load.
|
// We must have an 8- or 16-bit load.
|
||||||
LoadSDNode *Load = cast<LoadSDNode>(CmpOp0);
|
LoadSDNode *Load = cast<LoadSDNode>(C.Op0);
|
||||||
unsigned NumBits = Load->getMemoryVT().getStoreSizeInBits();
|
unsigned NumBits = Load->getMemoryVT().getStoreSizeInBits();
|
||||||
if (NumBits != 8 && NumBits != 16)
|
if (NumBits != 8 && NumBits != 16)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// The load must be an extending one and the constant must be within the
|
// The load must be an extending one and the constant must be within the
|
||||||
// range of the unextended value.
|
// range of the unextended value.
|
||||||
ConstantSDNode *Constant = cast<ConstantSDNode>(CmpOp1);
|
ConstantSDNode *ConstOp1 = cast<ConstantSDNode>(C.Op1);
|
||||||
uint64_t Value = Constant->getZExtValue();
|
uint64_t Value = ConstOp1->getZExtValue();
|
||||||
uint64_t Mask = (1 << NumBits) - 1;
|
uint64_t Mask = (1 << NumBits) - 1;
|
||||||
if (Load->getExtensionType() == ISD::SEXTLOAD) {
|
if (Load->getExtensionType() == ISD::SEXTLOAD) {
|
||||||
int64_t SignedValue = Constant->getSExtValue();
|
// Make sure that ConstOp1 is in range of C.Op0.
|
||||||
if (uint64_t(SignedValue) + (1ULL << (NumBits - 1)) > Mask)
|
int64_t SignedValue = ConstOp1->getSExtValue();
|
||||||
|
if (uint64_t(SignedValue) + (uint64_t(1) << (NumBits - 1)) > Mask)
|
||||||
return;
|
return;
|
||||||
// Unsigned comparison between two sign-extended values is equivalent
|
if (C.ICmpType != SystemZICMP::SignedOnly) {
|
||||||
// to unsigned comparison between two zero-extended values.
|
// Unsigned comparison between two sign-extended values is equivalent
|
||||||
if (IsUnsigned)
|
// to unsigned comparison between two zero-extended values.
|
||||||
Value &= Mask;
|
Value &= Mask;
|
||||||
else if (CCMask == SystemZ::CCMASK_CMP_EQ ||
|
} else if (NumBits == 8) {
|
||||||
CCMask == SystemZ::CCMASK_CMP_NE)
|
|
||||||
// Any choice of IsUnsigned is OK for equality comparisons.
|
|
||||||
// We could use either CHHSI or CLHHSI for 16-bit comparisons,
|
|
||||||
// but since we use CLHHSI for zero extensions, it seems better
|
|
||||||
// to be consistent and do the same here.
|
|
||||||
Value &= Mask, IsUnsigned = true;
|
|
||||||
else if (NumBits == 8) {
|
|
||||||
// Try to treat the comparison as unsigned, so that we can use CLI.
|
// Try to treat the comparison as unsigned, so that we can use CLI.
|
||||||
// Adjust CCMask and Value as necessary.
|
// Adjust CCMask and Value as necessary.
|
||||||
if (Value == 0 && CCMask == SystemZ::CCMASK_CMP_LT)
|
if (Value == 0 && C.CCMask == SystemZ::CCMASK_CMP_LT)
|
||||||
// Test whether the high bit of the byte is set.
|
// Test whether the high bit of the byte is set.
|
||||||
Value = 127, CCMask = SystemZ::CCMASK_CMP_GT, IsUnsigned = true;
|
Value = 127, C.CCMask = SystemZ::CCMASK_CMP_GT;
|
||||||
else if (Value == 0 && CCMask == SystemZ::CCMASK_CMP_GE)
|
else if (Value == 0 && C.CCMask == SystemZ::CCMASK_CMP_GE)
|
||||||
// Test whether the high bit of the byte is clear.
|
// Test whether the high bit of the byte is clear.
|
||||||
Value = 128, CCMask = SystemZ::CCMASK_CMP_LT, IsUnsigned = true;
|
Value = 128, C.CCMask = SystemZ::CCMASK_CMP_LT;
|
||||||
else
|
else
|
||||||
// No instruction exists for this combination.
|
// No instruction exists for this combination.
|
||||||
return;
|
return;
|
||||||
|
C.ICmpType = SystemZICMP::UnsignedOnly;
|
||||||
}
|
}
|
||||||
} else if (Load->getExtensionType() == ISD::ZEXTLOAD) {
|
} else if (Load->getExtensionType() == ISD::ZEXTLOAD) {
|
||||||
if (Value > Mask)
|
if (Value > Mask)
|
||||||
return;
|
return;
|
||||||
// Signed comparison between two zero-extended values is equivalent
|
assert(C.ICmpType == SystemZICMP::Any &&
|
||||||
// to unsigned comparison.
|
"Signedness shouldn't matter here.");
|
||||||
IsUnsigned = true;
|
|
||||||
} else
|
} else
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Make sure that the first operand is an i32 of the right extension type.
|
// Make sure that the first operand is an i32 of the right extension type.
|
||||||
ISD::LoadExtType ExtType = IsUnsigned ? ISD::ZEXTLOAD : ISD::SEXTLOAD;
|
ISD::LoadExtType ExtType = (C.ICmpType == SystemZICMP::SignedOnly ?
|
||||||
if (CmpOp0.getValueType() != MVT::i32 ||
|
ISD::SEXTLOAD :
|
||||||
|
ISD::ZEXTLOAD);
|
||||||
|
if (C.Op0.getValueType() != MVT::i32 ||
|
||||||
Load->getExtensionType() != ExtType)
|
Load->getExtensionType() != ExtType)
|
||||||
CmpOp0 = DAG.getExtLoad(ExtType, SDLoc(Load), MVT::i32,
|
C.Op0 = DAG.getExtLoad(ExtType, SDLoc(Load), MVT::i32,
|
||||||
Load->getChain(), Load->getBasePtr(),
|
Load->getChain(), Load->getBasePtr(),
|
||||||
Load->getPointerInfo(), Load->getMemoryVT(),
|
Load->getPointerInfo(), Load->getMemoryVT(),
|
||||||
Load->isVolatile(), Load->isNonTemporal(),
|
Load->isVolatile(), Load->isNonTemporal(),
|
||||||
Load->getAlignment());
|
Load->getAlignment());
|
||||||
|
|
||||||
// Make sure that the second operand is an i32 with the right value.
|
// Make sure that the second operand is an i32 with the right value.
|
||||||
if (CmpOp1.getValueType() != MVT::i32 ||
|
if (C.Op1.getValueType() != MVT::i32 ||
|
||||||
Value != Constant->getZExtValue())
|
Value != ConstOp1->getZExtValue())
|
||||||
CmpOp1 = DAG.getConstant(Value, MVT::i32);
|
C.Op1 = DAG.getConstant(Value, MVT::i32);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return true if Op is either an unextended load, or a load suitable
|
// Return true if Op is either an unextended load, or a load suitable
|
||||||
|
@ -1192,61 +1204,59 @@ static bool isNaturalMemoryOperand(SDValue Op, unsigned ICmpType) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return true if it is better to swap comparison operands Op0 and Op1.
|
// Return true if it is better to swap the operands of C.
|
||||||
// ICmpType is the type of an integer comparison.
|
static bool shouldSwapCmpOperands(const Comparison &C) {
|
||||||
static bool shouldSwapCmpOperands(SDValue Op0, SDValue Op1,
|
|
||||||
unsigned ICmpType) {
|
|
||||||
// Leave f128 comparisons alone, since they have no memory forms.
|
// Leave f128 comparisons alone, since they have no memory forms.
|
||||||
if (Op0.getValueType() == MVT::f128)
|
if (C.Op0.getValueType() == MVT::f128)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Always keep a floating-point constant second, since comparisons with
|
// Always keep a floating-point constant second, since comparisons with
|
||||||
// zero can use LOAD TEST and comparisons with other constants make a
|
// zero can use LOAD TEST and comparisons with other constants make a
|
||||||
// natural memory operand.
|
// natural memory operand.
|
||||||
if (isa<ConstantFPSDNode>(Op1))
|
if (isa<ConstantFPSDNode>(C.Op1))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Never swap comparisons with zero since there are many ways to optimize
|
// Never swap comparisons with zero since there are many ways to optimize
|
||||||
// those later.
|
// those later.
|
||||||
ConstantSDNode *COp1 = dyn_cast<ConstantSDNode>(Op1);
|
ConstantSDNode *ConstOp1 = dyn_cast<ConstantSDNode>(C.Op1);
|
||||||
if (COp1 && COp1->getZExtValue() == 0)
|
if (ConstOp1 && ConstOp1->getZExtValue() == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Also keep natural memory operands second if the loaded value is
|
// Also keep natural memory operands second if the loaded value is
|
||||||
// only used here. Several comparisons have memory forms.
|
// only used here. Several comparisons have memory forms.
|
||||||
if (isNaturalMemoryOperand(Op1, ICmpType) && Op1.hasOneUse())
|
if (isNaturalMemoryOperand(C.Op1, C.ICmpType) && C.Op1.hasOneUse())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Look for cases where Cmp0 is a single-use load and Cmp1 isn't.
|
// Look for cases where Cmp0 is a single-use load and Cmp1 isn't.
|
||||||
// In that case we generally prefer the memory to be second.
|
// In that case we generally prefer the memory to be second.
|
||||||
if (isNaturalMemoryOperand(Op0, ICmpType) && Op0.hasOneUse()) {
|
if (isNaturalMemoryOperand(C.Op0, C.ICmpType) && C.Op0.hasOneUse()) {
|
||||||
// The only exceptions are when the second operand is a constant and
|
// The only exceptions are when the second operand is a constant and
|
||||||
// we can use things like CHHSI.
|
// we can use things like CHHSI.
|
||||||
if (!COp1)
|
if (!ConstOp1)
|
||||||
return true;
|
return true;
|
||||||
// The unsigned memory-immediate instructions can handle 16-bit
|
// The unsigned memory-immediate instructions can handle 16-bit
|
||||||
// unsigned integers.
|
// unsigned integers.
|
||||||
if (ICmpType != SystemZICMP::SignedOnly &&
|
if (C.ICmpType != SystemZICMP::SignedOnly &&
|
||||||
isUInt<16>(COp1->getZExtValue()))
|
isUInt<16>(ConstOp1->getZExtValue()))
|
||||||
return false;
|
return false;
|
||||||
// The signed memory-immediate instructions can handle 16-bit
|
// The signed memory-immediate instructions can handle 16-bit
|
||||||
// signed integers.
|
// signed integers.
|
||||||
if (ICmpType != SystemZICMP::UnsignedOnly &&
|
if (C.ICmpType != SystemZICMP::UnsignedOnly &&
|
||||||
isInt<16>(COp1->getSExtValue()))
|
isInt<16>(ConstOp1->getSExtValue()))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to promote the use of CGFR and CLGFR.
|
// Try to promote the use of CGFR and CLGFR.
|
||||||
unsigned Opcode0 = Op0.getOpcode();
|
unsigned Opcode0 = C.Op0.getOpcode();
|
||||||
if (ICmpType != SystemZICMP::UnsignedOnly && Opcode0 == ISD::SIGN_EXTEND)
|
if (C.ICmpType != SystemZICMP::UnsignedOnly && Opcode0 == ISD::SIGN_EXTEND)
|
||||||
return true;
|
return true;
|
||||||
if (ICmpType != SystemZICMP::SignedOnly && Opcode0 == ISD::ZERO_EXTEND)
|
if (C.ICmpType != SystemZICMP::SignedOnly && Opcode0 == ISD::ZERO_EXTEND)
|
||||||
return true;
|
return true;
|
||||||
if (ICmpType != SystemZICMP::SignedOnly &&
|
if (C.ICmpType != SystemZICMP::SignedOnly &&
|
||||||
Opcode0 == ISD::AND &&
|
Opcode0 == ISD::AND &&
|
||||||
Op0.getOperand(1).getOpcode() == ISD::Constant &&
|
C.Op0.getOperand(1).getOpcode() == ISD::Constant &&
|
||||||
cast<ConstantSDNode>(Op0.getOperand(1))->getZExtValue() == 0xffffffff)
|
cast<ConstantSDNode>(C.Op0.getOperand(1))->getZExtValue() == 0xffffffff)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -1261,48 +1271,47 @@ static unsigned reverseCCMask(unsigned CCMask) {
|
||||||
(CCMask & SystemZ::CCMASK_CMP_UO));
|
(CCMask & SystemZ::CCMASK_CMP_UO));
|
||||||
}
|
}
|
||||||
|
|
||||||
// CmpOp0 and CmpOp1 are being compared using CC mask CCMask. Check whether
|
// Check whether C compares a floating-point value with zero and if that
|
||||||
// CmpOp0 is a floating-point result that is also negated and if CmpOp1
|
// floating-point value is also negated. In this case we can use the
|
||||||
// is zero. In this case we can use the negation to set CC, so avoiding
|
// negation to set CC, so avoiding separate LOAD AND TEST and
|
||||||
// separate LOAD AND TEST and LOAD (NEGATIVE/COMPLEMENT) instructions.
|
// LOAD (NEGATIVE/COMPLEMENT) instructions.
|
||||||
static void adjustForFNeg(SDValue &CmpOp0, SDValue &CmpOp1, unsigned &CCMask) {
|
static void adjustForFNeg(Comparison &C) {
|
||||||
ConstantFPSDNode *C1 = dyn_cast<ConstantFPSDNode>(CmpOp1);
|
ConstantFPSDNode *C1 = dyn_cast<ConstantFPSDNode>(C.Op1);
|
||||||
if (C1 && C1->isZero()) {
|
if (C1 && C1->isZero()) {
|
||||||
for (SDNode::use_iterator I = CmpOp0->use_begin(), E = CmpOp0->use_end();
|
for (SDNode::use_iterator I = C.Op0->use_begin(), E = C.Op0->use_end();
|
||||||
I != E; ++I) {
|
I != E; ++I) {
|
||||||
SDNode *N = *I;
|
SDNode *N = *I;
|
||||||
if (N->getOpcode() == ISD::FNEG) {
|
if (N->getOpcode() == ISD::FNEG) {
|
||||||
CmpOp0 = SDValue(N, 0);
|
C.Op0 = SDValue(N, 0);
|
||||||
CCMask = reverseCCMask(CCMask);
|
C.CCMask = reverseCCMask(C.CCMask);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether CmpOp0 is (shl X, 32), CmpOp1 is 0, and whether X is
|
// Check whether C compares (shl X, 32) with 0 and whether X is
|
||||||
// also sign-extended. In that case it is better to test the result
|
// also sign-extended. In that case it is better to test the result
|
||||||
// of the sign extension using LTGFR.
|
// of the sign extension using LTGFR.
|
||||||
//
|
//
|
||||||
// This case is important because InstCombine transforms a comparison
|
// This case is important because InstCombine transforms a comparison
|
||||||
// with (sext (trunc X)) into a comparison with (shl X, 32).
|
// with (sext (trunc X)) into a comparison with (shl X, 32).
|
||||||
static void adjustForLTGFR(SDValue &CmpOp0, SDValue &CmpOp1,
|
static void adjustForLTGFR(Comparison &C) {
|
||||||
unsigned &IcmpType) {
|
|
||||||
// Check for a comparison between (shl X, 32) and 0.
|
// Check for a comparison between (shl X, 32) and 0.
|
||||||
if (CmpOp0.getOpcode() == ISD::SHL &&
|
if (C.Op0.getOpcode() == ISD::SHL &&
|
||||||
CmpOp0.getValueType() == MVT::i64 &&
|
C.Op0.getValueType() == MVT::i64 &&
|
||||||
CmpOp1.getOpcode() == ISD::Constant &&
|
C.Op1.getOpcode() == ISD::Constant &&
|
||||||
cast<ConstantSDNode>(CmpOp1)->getZExtValue() == 0) {
|
cast<ConstantSDNode>(C.Op1)->getZExtValue() == 0) {
|
||||||
ConstantSDNode *C1 = dyn_cast<ConstantSDNode>(CmpOp0.getOperand(1));
|
ConstantSDNode *C1 = dyn_cast<ConstantSDNode>(C.Op0.getOperand(1));
|
||||||
if (C1 && C1->getZExtValue() == 32) {
|
if (C1 && C1->getZExtValue() == 32) {
|
||||||
SDValue ShlOp0 = CmpOp0.getOperand(0);
|
SDValue ShlOp0 = C.Op0.getOperand(0);
|
||||||
// See whether X has any SIGN_EXTEND_INREG uses.
|
// See whether X has any SIGN_EXTEND_INREG uses.
|
||||||
for (SDNode::use_iterator I = ShlOp0->use_begin(), E = ShlOp0->use_end();
|
for (SDNode::use_iterator I = ShlOp0->use_begin(), E = ShlOp0->use_end();
|
||||||
I != E; ++I) {
|
I != E; ++I) {
|
||||||
SDNode *N = *I;
|
SDNode *N = *I;
|
||||||
if (N->getOpcode() == ISD::SIGN_EXTEND_INREG &&
|
if (N->getOpcode() == ISD::SIGN_EXTEND_INREG &&
|
||||||
cast<VTSDNode>(N->getOperand(1))->getVT() == MVT::i32) {
|
cast<VTSDNode>(N->getOperand(1))->getVT() == MVT::i32) {
|
||||||
CmpOp0 = SDValue(N, 0);
|
C.Op0 = SDValue(N, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1421,25 +1430,20 @@ static unsigned getTestUnderMaskCond(unsigned BitSize, unsigned CCMask,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// See whether the comparison (Opcode CmpOp0, CmpOp1, ICmpType) can be
|
// See whether C can be implemented as a TEST UNDER MASK instruction.
|
||||||
// implemented as a TEST UNDER MASK instruction when the condition being
|
// Update the arguments with the TM version if so.
|
||||||
// tested is as described by CCValid and CCMask. Update the arguments
|
static void adjustForTestUnderMask(SelectionDAG &DAG, Comparison &C) {
|
||||||
// with the TM version if so.
|
|
||||||
static void adjustForTestUnderMask(SelectionDAG &DAG, unsigned &Opcode,
|
|
||||||
SDValue &CmpOp0, SDValue &CmpOp1,
|
|
||||||
unsigned &CCValid, unsigned &CCMask,
|
|
||||||
unsigned &ICmpType) {
|
|
||||||
// Check that we have a comparison with a constant.
|
// Check that we have a comparison with a constant.
|
||||||
ConstantSDNode *ConstCmpOp1 = dyn_cast<ConstantSDNode>(CmpOp1);
|
ConstantSDNode *ConstOp1 = dyn_cast<ConstantSDNode>(C.Op1);
|
||||||
if (!ConstCmpOp1)
|
if (!ConstOp1)
|
||||||
return;
|
return;
|
||||||
uint64_t CmpVal = ConstCmpOp1->getZExtValue();
|
uint64_t CmpVal = ConstOp1->getZExtValue();
|
||||||
|
|
||||||
// Check whether the nonconstant input is an AND with a constant mask.
|
// Check whether the nonconstant input is an AND with a constant mask.
|
||||||
if (CmpOp0.getOpcode() != ISD::AND)
|
if (C.Op0.getOpcode() != ISD::AND)
|
||||||
return;
|
return;
|
||||||
SDValue AndOp0 = CmpOp0.getOperand(0);
|
SDValue AndOp0 = C.Op0.getOperand(0);
|
||||||
SDValue AndOp1 = CmpOp0.getOperand(1);
|
SDValue AndOp1 = C.Op0.getOperand(1);
|
||||||
ConstantSDNode *Mask = dyn_cast<ConstantSDNode>(AndOp1.getNode());
|
ConstantSDNode *Mask = dyn_cast<ConstantSDNode>(AndOp1.getNode());
|
||||||
if (!Mask)
|
if (!Mask)
|
||||||
return;
|
return;
|
||||||
|
@ -1447,91 +1451,92 @@ static void adjustForTestUnderMask(SelectionDAG &DAG, unsigned &Opcode,
|
||||||
|
|
||||||
// Check whether the combination of mask, comparison value and comparison
|
// Check whether the combination of mask, comparison value and comparison
|
||||||
// type are suitable.
|
// type are suitable.
|
||||||
unsigned BitSize = CmpOp0.getValueType().getSizeInBits();
|
unsigned BitSize = C.Op0.getValueType().getSizeInBits();
|
||||||
unsigned NewCCMask, ShiftVal;
|
unsigned NewCCMask, ShiftVal;
|
||||||
if (ICmpType != SystemZICMP::SignedOnly &&
|
if (C.ICmpType != SystemZICMP::SignedOnly &&
|
||||||
AndOp0.getOpcode() == ISD::SHL &&
|
AndOp0.getOpcode() == ISD::SHL &&
|
||||||
isSimpleShift(AndOp0, ShiftVal) &&
|
isSimpleShift(AndOp0, ShiftVal) &&
|
||||||
(NewCCMask = getTestUnderMaskCond(BitSize, CCMask, MaskVal >> ShiftVal,
|
(NewCCMask = getTestUnderMaskCond(BitSize, C.CCMask, MaskVal >> ShiftVal,
|
||||||
CmpVal >> ShiftVal,
|
CmpVal >> ShiftVal,
|
||||||
SystemZICMP::Any))) {
|
SystemZICMP::Any))) {
|
||||||
AndOp0 = AndOp0.getOperand(0);
|
AndOp0 = AndOp0.getOperand(0);
|
||||||
AndOp1 = DAG.getConstant(MaskVal >> ShiftVal, AndOp0.getValueType());
|
AndOp1 = DAG.getConstant(MaskVal >> ShiftVal, AndOp0.getValueType());
|
||||||
} else if (ICmpType != SystemZICMP::SignedOnly &&
|
} else if (C.ICmpType != SystemZICMP::SignedOnly &&
|
||||||
AndOp0.getOpcode() == ISD::SRL &&
|
AndOp0.getOpcode() == ISD::SRL &&
|
||||||
isSimpleShift(AndOp0, ShiftVal) &&
|
isSimpleShift(AndOp0, ShiftVal) &&
|
||||||
(NewCCMask = getTestUnderMaskCond(BitSize, CCMask,
|
(NewCCMask = getTestUnderMaskCond(BitSize, C.CCMask,
|
||||||
MaskVal << ShiftVal,
|
MaskVal << ShiftVal,
|
||||||
CmpVal << ShiftVal,
|
CmpVal << ShiftVal,
|
||||||
SystemZICMP::UnsignedOnly))) {
|
SystemZICMP::UnsignedOnly))) {
|
||||||
AndOp0 = AndOp0.getOperand(0);
|
AndOp0 = AndOp0.getOperand(0);
|
||||||
AndOp1 = DAG.getConstant(MaskVal << ShiftVal, AndOp0.getValueType());
|
AndOp1 = DAG.getConstant(MaskVal << ShiftVal, AndOp0.getValueType());
|
||||||
} else {
|
} else {
|
||||||
NewCCMask = getTestUnderMaskCond(BitSize, CCMask, MaskVal, CmpVal,
|
NewCCMask = getTestUnderMaskCond(BitSize, C.CCMask, MaskVal, CmpVal,
|
||||||
ICmpType);
|
C.ICmpType);
|
||||||
if (!NewCCMask)
|
if (!NewCCMask)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Go ahead and make the change.
|
// Go ahead and make the change.
|
||||||
Opcode = SystemZISD::TM;
|
C.Opcode = SystemZISD::TM;
|
||||||
CmpOp0 = AndOp0;
|
C.Op0 = AndOp0;
|
||||||
CmpOp1 = AndOp1;
|
C.Op1 = AndOp1;
|
||||||
ICmpType = (bool(NewCCMask & SystemZ::CCMASK_TM_MIXED_MSB_0) !=
|
C.CCValid = SystemZ::CCMASK_TM;
|
||||||
bool(NewCCMask & SystemZ::CCMASK_TM_MIXED_MSB_1));
|
C.CCMask = NewCCMask;
|
||||||
CCValid = SystemZ::CCMASK_TM;
|
|
||||||
CCMask = NewCCMask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return a target node that compares CmpOp0 with CmpOp1 and stores a
|
// Decide how to implement a comparison of type Cond between CmpOp0 with CmpOp1.
|
||||||
// 2-bit result in CC. Set CCValid to the CCMASK_* of all possible
|
static Comparison getCmp(SelectionDAG &DAG, SDValue CmpOp0, SDValue CmpOp1,
|
||||||
// 2-bit results and CCMask to the subset of those results that are
|
ISD::CondCode Cond) {
|
||||||
// associated with Cond.
|
Comparison C(CmpOp0, CmpOp1);
|
||||||
static SDValue emitCmp(const SystemZTargetMachine &TM, SelectionDAG &DAG,
|
C.CCMask = CCMaskForCondCode(Cond);
|
||||||
SDLoc DL, SDValue CmpOp0, SDValue CmpOp1,
|
if (C.Op0.getValueType().isFloatingPoint()) {
|
||||||
ISD::CondCode Cond, unsigned &CCValid,
|
C.CCValid = SystemZ::CCMASK_FCMP;
|
||||||
unsigned &CCMask) {
|
C.Opcode = SystemZISD::FCMP;
|
||||||
bool IsUnsigned = false;
|
|
||||||
CCMask = CCMaskForCondCode(Cond);
|
|
||||||
unsigned Opcode, ICmpType = 0;
|
|
||||||
if (CmpOp0.getValueType().isFloatingPoint()) {
|
|
||||||
CCValid = SystemZ::CCMASK_FCMP;
|
|
||||||
Opcode = SystemZISD::FCMP;
|
|
||||||
} else {
|
} else {
|
||||||
IsUnsigned = CCMask & SystemZ::CCMASK_CMP_UO;
|
C.CCValid = SystemZ::CCMASK_ICMP;
|
||||||
CCValid = SystemZ::CCMASK_ICMP;
|
C.Opcode = SystemZISD::ICMP;
|
||||||
CCMask &= CCValid;
|
|
||||||
adjustZeroCmp(DAG, IsUnsigned, CmpOp0, CmpOp1, CCMask);
|
|
||||||
adjustSubwordCmp(DAG, IsUnsigned, CmpOp0, CmpOp1, CCMask);
|
|
||||||
Opcode = SystemZISD::ICMP;
|
|
||||||
// Choose the type of comparison. Equality and inequality tests can
|
// Choose the type of comparison. Equality and inequality tests can
|
||||||
// use either signed or unsigned comparisons. The choice also doesn't
|
// use either signed or unsigned comparisons. The choice also doesn't
|
||||||
// matter if both sign bits are known to be clear. In those cases we
|
// matter if both sign bits are known to be clear. In those cases we
|
||||||
// want to give the main isel code the freedom to choose whichever
|
// want to give the main isel code the freedom to choose whichever
|
||||||
// form fits best.
|
// form fits best.
|
||||||
if (CCMask == SystemZ::CCMASK_CMP_EQ ||
|
if (C.CCMask == SystemZ::CCMASK_CMP_EQ ||
|
||||||
CCMask == SystemZ::CCMASK_CMP_NE ||
|
C.CCMask == SystemZ::CCMASK_CMP_NE ||
|
||||||
(DAG.SignBitIsZero(CmpOp0) && DAG.SignBitIsZero(CmpOp1)))
|
(DAG.SignBitIsZero(C.Op0) && DAG.SignBitIsZero(C.Op1)))
|
||||||
ICmpType = SystemZICMP::Any;
|
C.ICmpType = SystemZICMP::Any;
|
||||||
else if (IsUnsigned)
|
else if (C.CCMask & SystemZ::CCMASK_CMP_UO)
|
||||||
ICmpType = SystemZICMP::UnsignedOnly;
|
C.ICmpType = SystemZICMP::UnsignedOnly;
|
||||||
else
|
else
|
||||||
ICmpType = SystemZICMP::SignedOnly;
|
C.ICmpType = SystemZICMP::SignedOnly;
|
||||||
|
C.CCMask &= ~SystemZ::CCMASK_CMP_UO;
|
||||||
|
adjustZeroCmp(DAG, C);
|
||||||
|
adjustSubwordCmp(DAG, C);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldSwapCmpOperands(CmpOp0, CmpOp1, ICmpType)) {
|
if (shouldSwapCmpOperands(C)) {
|
||||||
std::swap(CmpOp0, CmpOp1);
|
std::swap(C.Op0, C.Op1);
|
||||||
CCMask = reverseCCMask(CCMask);
|
C.CCMask = reverseCCMask(C.CCMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
adjustForTestUnderMask(DAG, Opcode, CmpOp0, CmpOp1, CCValid, CCMask,
|
adjustForTestUnderMask(DAG, C);
|
||||||
ICmpType);
|
adjustForFNeg(C);
|
||||||
adjustForFNeg(CmpOp0, CmpOp1, CCMask);
|
adjustForLTGFR(C);
|
||||||
adjustForLTGFR(CmpOp0, CmpOp1, ICmpType);
|
return C;
|
||||||
if (Opcode == SystemZISD::ICMP || Opcode == SystemZISD::TM)
|
}
|
||||||
return DAG.getNode(Opcode, DL, MVT::Glue, CmpOp0, CmpOp1,
|
|
||||||
DAG.getConstant(ICmpType, MVT::i32));
|
// Emit the comparison instruction described by C.
|
||||||
return DAG.getNode(Opcode, DL, MVT::Glue, CmpOp0, CmpOp1);
|
static SDValue emitCmp(SelectionDAG &DAG, SDLoc DL, Comparison &C) {
|
||||||
|
if (C.Opcode == SystemZISD::ICMP)
|
||||||
|
return DAG.getNode(SystemZISD::ICMP, DL, MVT::Glue, C.Op0, C.Op1,
|
||||||
|
DAG.getConstant(C.ICmpType, MVT::i32));
|
||||||
|
if (C.Opcode == SystemZISD::TM) {
|
||||||
|
bool RegisterOnly = (bool(C.CCMask & SystemZ::CCMASK_TM_MIXED_MSB_0) !=
|
||||||
|
bool(C.CCMask & SystemZ::CCMASK_TM_MIXED_MSB_1));
|
||||||
|
return DAG.getNode(SystemZISD::TM, DL, MVT::Glue, C.Op0, C.Op1,
|
||||||
|
DAG.getConstant(RegisterOnly, MVT::i32));
|
||||||
|
}
|
||||||
|
return DAG.getNode(C.Opcode, DL, MVT::Glue, C.Op0, C.Op1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implement a 32-bit *MUL_LOHI operation by extending both operands to
|
// Implement a 32-bit *MUL_LOHI operation by extending both operands to
|
||||||
|
@ -1597,9 +1602,9 @@ SDValue SystemZTargetLowering::lowerSETCC(SDValue Op,
|
||||||
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(2))->get();
|
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(2))->get();
|
||||||
SDLoc DL(Op);
|
SDLoc DL(Op);
|
||||||
|
|
||||||
unsigned CCValid, CCMask;
|
Comparison C(getCmp(DAG, CmpOp0, CmpOp1, CC));
|
||||||
SDValue Glue = emitCmp(TM, DAG, DL, CmpOp0, CmpOp1, CC, CCValid, CCMask);
|
SDValue Glue = emitCmp(DAG, DL, C);
|
||||||
return emitSETCC(DAG, DL, Glue, CCValid, CCMask);
|
return emitSETCC(DAG, DL, Glue, C.CCValid, C.CCMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
SDValue SystemZTargetLowering::lowerBR_CC(SDValue Op, SelectionDAG &DAG) const {
|
SDValue SystemZTargetLowering::lowerBR_CC(SDValue Op, SelectionDAG &DAG) const {
|
||||||
|
@ -1610,11 +1615,11 @@ SDValue SystemZTargetLowering::lowerBR_CC(SDValue Op, SelectionDAG &DAG) const {
|
||||||
SDValue Dest = Op.getOperand(4);
|
SDValue Dest = Op.getOperand(4);
|
||||||
SDLoc DL(Op);
|
SDLoc DL(Op);
|
||||||
|
|
||||||
unsigned CCValid, CCMask;
|
Comparison C(getCmp(DAG, CmpOp0, CmpOp1, CC));
|
||||||
SDValue Glue = emitCmp(TM, DAG, DL, CmpOp0, CmpOp1, CC, CCValid, CCMask);
|
SDValue Glue = emitCmp(DAG, DL, C);
|
||||||
return DAG.getNode(SystemZISD::BR_CCMASK, DL, Op.getValueType(),
|
return DAG.getNode(SystemZISD::BR_CCMASK, DL, Op.getValueType(),
|
||||||
Chain, DAG.getConstant(CCValid, MVT::i32),
|
Chain, DAG.getConstant(C.CCValid, MVT::i32),
|
||||||
DAG.getConstant(CCMask, MVT::i32), Dest, Glue);
|
DAG.getConstant(C.CCMask, MVT::i32), Dest, Glue);
|
||||||
}
|
}
|
||||||
|
|
||||||
SDValue SystemZTargetLowering::lowerSELECT_CC(SDValue Op,
|
SDValue SystemZTargetLowering::lowerSELECT_CC(SDValue Op,
|
||||||
|
@ -1626,8 +1631,8 @@ SDValue SystemZTargetLowering::lowerSELECT_CC(SDValue Op,
|
||||||
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get();
|
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get();
|
||||||
SDLoc DL(Op);
|
SDLoc DL(Op);
|
||||||
|
|
||||||
unsigned CCValid, CCMask;
|
Comparison C(getCmp(DAG, CmpOp0, CmpOp1, CC));
|
||||||
SDValue Glue = emitCmp(TM, DAG, DL, CmpOp0, CmpOp1, CC, CCValid, CCMask);
|
SDValue Glue = emitCmp(DAG, DL, C);
|
||||||
|
|
||||||
// Special case for handling -1/0 results. The shifts we use here
|
// Special case for handling -1/0 results. The shifts we use here
|
||||||
// should get optimized with the IPM conversion sequence.
|
// should get optimized with the IPM conversion sequence.
|
||||||
|
@ -1639,8 +1644,8 @@ SDValue SystemZTargetLowering::lowerSELECT_CC(SDValue Op,
|
||||||
if ((TrueVal == -1 && FalseVal == 0) || (TrueVal == 0 && FalseVal == -1)) {
|
if ((TrueVal == -1 && FalseVal == 0) || (TrueVal == 0 && FalseVal == -1)) {
|
||||||
// Invert the condition if we want -1 on false.
|
// Invert the condition if we want -1 on false.
|
||||||
if (TrueVal == 0)
|
if (TrueVal == 0)
|
||||||
CCMask ^= CCValid;
|
C.CCMask ^= C.CCValid;
|
||||||
SDValue Result = emitSETCC(DAG, DL, Glue, CCValid, CCMask);
|
SDValue Result = emitSETCC(DAG, DL, Glue, C.CCValid, C.CCMask);
|
||||||
EVT VT = Op.getValueType();
|
EVT VT = Op.getValueType();
|
||||||
// Extend the result to VT. Upper bits are ignored.
|
// Extend the result to VT. Upper bits are ignored.
|
||||||
if (!is32Bit(VT))
|
if (!is32Bit(VT))
|
||||||
|
@ -1655,8 +1660,8 @@ SDValue SystemZTargetLowering::lowerSELECT_CC(SDValue Op,
|
||||||
SmallVector<SDValue, 5> Ops;
|
SmallVector<SDValue, 5> Ops;
|
||||||
Ops.push_back(TrueOp);
|
Ops.push_back(TrueOp);
|
||||||
Ops.push_back(FalseOp);
|
Ops.push_back(FalseOp);
|
||||||
Ops.push_back(DAG.getConstant(CCValid, MVT::i32));
|
Ops.push_back(DAG.getConstant(C.CCValid, MVT::i32));
|
||||||
Ops.push_back(DAG.getConstant(CCMask, MVT::i32));
|
Ops.push_back(DAG.getConstant(C.CCMask, MVT::i32));
|
||||||
Ops.push_back(Glue);
|
Ops.push_back(Glue);
|
||||||
|
|
||||||
SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Glue);
|
SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Glue);
|
||||||
|
|
Loading…
Reference in New Issue