[SystemZ] Tweak integer comparison code

The architecture has many comparison instructions, including some that
extend one of the operands.  The signed comparison instructions use sign
extensions and the unsigned comparison instructions use zero extensions.
In cases where we had a free choice between signed or unsigned comparisons,
we were trying to decide at lowering time which would best fit the available
instructions, taking things like extension type into account.  The code
to do that was getting increasingly hairy and was also making some bad
decisions.  E.g. when comparing the result of two LLCs, it is better to use
CR rather than CLR, since CR can be fused with a branch while CLR can't.

This patch removes the lowering code and instead adds an operand to
integer comparisons to say whether signed comparison is required,
whether unsigned comparison is required, or whether either is OK.
We can then leave the choice of instruction up to the normal isel code.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@190138 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Richard Sandiford 2013-09-06 11:51:39 +00:00
parent e3273b3275
commit aff1c6427c
7 changed files with 223 additions and 121 deletions

View File

@ -1069,73 +1069,33 @@ static void adjustSubwordCmp(SelectionDAG &DAG, bool &IsUnsigned,
CmpOp1 = DAG.getConstant(Value, MVT::i32); CmpOp1 = DAG.getConstant(Value, MVT::i32);
} }
// Return true if a comparison described by CCMask, CmpOp0 and CmpOp1 // Return true if Op is either an unextended load, or a load suitable
// is an equality comparison that is better implemented using unsigned // for integer register-memory comparisons of type ICmpType.
// rather than signed comparison instructions. static bool isNaturalMemoryOperand(SDValue Op, unsigned ICmpType) {
static bool preferUnsignedComparison(SDValue CmpOp0, SDValue CmpOp1,
unsigned CCMask) {
// The test must be for equality or inequality.
if (CCMask != SystemZ::CCMASK_CMP_EQ && CCMask != SystemZ::CCMASK_CMP_NE)
return false;
if (CmpOp1.getOpcode() == ISD::Constant) {
uint64_t Value = cast<ConstantSDNode>(CmpOp1)->getSExtValue();
// If we're comparing with memory, prefer unsigned comparisons for
// values that are in the unsigned 16-bit range but not the signed
// 16-bit range. We want to use CLFHSI and CLGHSI.
if (CmpOp0.hasOneUse() &&
ISD::isNormalLoad(CmpOp0.getNode()) &&
(Value >= 32768 && Value < 65536))
return true;
// Use unsigned comparisons for values that are in the CLGFI range
// but not in the CGFI range.
if (CmpOp0.getValueType() == MVT::i64 && (Value >> 31) == 1)
return true;
return false;
}
// Prefer CL for zero-extended loads.
if (CmpOp1.getOpcode() == ISD::ZERO_EXTEND ||
ISD::isZEXTLoad(CmpOp1.getNode()))
return true;
// ...and for "in-register" zero extensions.
if (CmpOp1.getOpcode() == ISD::AND && CmpOp1.getValueType() == MVT::i64) {
SDValue Mask = CmpOp1.getOperand(1);
if (Mask.getOpcode() == ISD::Constant &&
cast<ConstantSDNode>(Mask)->getZExtValue() == 0xffffffff)
return true;
}
return false;
}
// Return true if Op is either an unextended load, or a load with the
// extension type given by IsUnsigned.
static bool isNaturalMemoryOperand(SDValue Op, bool IsUnsigned) {
LoadSDNode *Load = dyn_cast<LoadSDNode>(Op.getNode()); LoadSDNode *Load = dyn_cast<LoadSDNode>(Op.getNode());
if (Load) if (Load) {
// There are no instructions to compare a register with a memory byte.
if (Load->getMemoryVT() == MVT::i8)
return false;
// Otherwise decide on extension type.
switch (Load->getExtensionType()) { switch (Load->getExtensionType()) {
case ISD::NON_EXTLOAD: case ISD::NON_EXTLOAD:
case ISD::EXTLOAD:
return true; return true;
case ISD::SEXTLOAD: case ISD::SEXTLOAD:
return !IsUnsigned; return ICmpType != SystemZICMP::UnsignedOnly;
case ISD::ZEXTLOAD: case ISD::ZEXTLOAD:
return IsUnsigned; return ICmpType != SystemZICMP::SignedOnly;
default: default:
break; break;
} }
}
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 comparison operands Op0 and Op1.
// IsUnsigned says whether an integer comparison is signed or unsigned. // ICmpType is the type of an integer comparison.
static bool shouldSwapCmpOperands(SDValue Op0, SDValue Op1, static bool shouldSwapCmpOperands(SDValue Op0, SDValue Op1,
bool IsUnsigned) { 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 (Op0.getValueType() == MVT::f128)
return false; return false;
@ -1154,23 +1114,22 @@ static bool shouldSwapCmpOperands(SDValue Op0, SDValue Op1,
// 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, IsUnsigned) && Op0.hasOneUse()) && if ((isNaturalMemoryOperand(Op0, ICmpType) && Op0.hasOneUse()) &&
!(isNaturalMemoryOperand(Op1, IsUnsigned) && Op1.hasOneUse())) { !(isNaturalMemoryOperand(Op1, ICmpType) && Op1.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 (!COp1)
return true; return true;
if (IsUnsigned) { // The unsigned memory-immediate instructions can handle 16-bit
// The memory-immediate instructions require 16-bit unsigned integers. // unsigned integers.
if (isUInt<16>(COp1->getZExtValue())) if (ICmpType != SystemZICMP::SignedOnly &&
return false; isUInt<16>(COp1->getZExtValue()))
} else { return false;
// There are no comparisons between integers and signed memory bytes. // The signed memory-immediate instructions can handle 16-bit
// The others require 16-bit signed integers. // signed integers.
if (cast<LoadSDNode>(Op0.getNode())->getMemoryVT() == MVT::i8 || if (ICmpType != SystemZICMP::UnsignedOnly &&
isInt<16>(COp1->getSExtValue())) isInt<16>(COp1->getSExtValue()))
return false; return false;
}
return true; return true;
} }
return false; return false;
@ -1182,9 +1141,9 @@ static bool shouldSwapCmpOperands(SDValue Op0, SDValue Op1,
// BitSize is the number of bits in the operands. Return the CC mask that // BitSize is the number of bits in the operands. Return the CC mask that
// should be used for the TEST UNDER MASK result, or 0 if the condition is // should be used for the TEST UNDER MASK result, or 0 if the condition is
// too complex. // too complex.
static unsigned getTestUnderMaskCond(unsigned BitSize, unsigned Opcode, static unsigned getTestUnderMaskCond(unsigned BitSize, unsigned CCMask,
unsigned CCMask, uint64_t Mask, uint64_t Mask, uint64_t CmpVal,
uint64_t CmpVal) { unsigned ICmpType) {
assert(Mask != 0 && "ANDs with zero should have been removed by now"); assert(Mask != 0 && "ANDs with zero should have been removed by now");
// Work out the masks for the lowest and highest bits. // Work out the masks for the lowest and highest bits.
@ -1194,8 +1153,7 @@ static unsigned getTestUnderMaskCond(unsigned BitSize, unsigned Opcode,
// Signed ordered comparisons are effectively unsigned if the sign // Signed ordered comparisons are effectively unsigned if the sign
// bit is dropped. // bit is dropped.
bool EffectivelyUnsigned = (Opcode == SystemZISD::UCMP bool EffectivelyUnsigned = (ICmpType != SystemZICMP::SignedOnly);
|| HighShift < BitSize - 1);
// Check for equality comparisons with 0, or the equivalent. // Check for equality comparisons with 0, or the equivalent.
if (CmpVal == 0) { if (CmpVal == 0) {
@ -1274,7 +1232,7 @@ static unsigned getTestUnderMaskCond(unsigned BitSize, unsigned Opcode,
// TM version if so. // TM version if so.
static void adjustForTestUnderMask(unsigned &Opcode, SDValue &CmpOp0, static void adjustForTestUnderMask(unsigned &Opcode, SDValue &CmpOp0,
SDValue &CmpOp1, unsigned &CCValid, SDValue &CmpOp1, unsigned &CCValid,
unsigned &CCMask) { 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 *ConstCmpOp1 = dyn_cast<ConstantSDNode>(CmpOp1);
if (!ConstCmpOp1) if (!ConstCmpOp1)
@ -1298,8 +1256,9 @@ static void adjustForTestUnderMask(unsigned &Opcode, SDValue &CmpOp0,
// 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 = CmpOp0.getValueType().getSizeInBits();
unsigned NewCCMask = getTestUnderMaskCond(BitSize, Opcode, CCMask, MaskVal, unsigned NewCCMask = getTestUnderMaskCond(BitSize, CCMask, MaskVal,
ConstCmpOp1->getZExtValue()); ConstCmpOp1->getZExtValue(),
ICmpType);
if (!NewCCMask) if (!NewCCMask)
return; return;
@ -1315,24 +1274,39 @@ static void adjustForTestUnderMask(unsigned &Opcode, SDValue &CmpOp0,
// 2-bit result in CC. Set CCValid to the CCMASK_* of all possible // 2-bit result in CC. Set CCValid to the CCMASK_* of all possible
// 2-bit results and CCMask to the subset of those results that are // 2-bit results and CCMask to the subset of those results that are
// associated with Cond. // associated with Cond.
static SDValue emitCmp(SelectionDAG &DAG, SDLoc DL, SDValue CmpOp0, static SDValue emitCmp(const SystemZTargetMachine &TM, SelectionDAG &DAG,
SDValue CmpOp1, ISD::CondCode Cond, unsigned &CCValid, SDLoc DL, SDValue CmpOp0, SDValue CmpOp1,
ISD::CondCode Cond, unsigned &CCValid,
unsigned &CCMask) { unsigned &CCMask) {
bool IsUnsigned = false; bool IsUnsigned = false;
CCMask = CCMaskForCondCode(Cond); CCMask = CCMaskForCondCode(Cond);
if (CmpOp0.getValueType().isFloatingPoint()) unsigned Opcode, ICmpType = 0;
if (CmpOp0.getValueType().isFloatingPoint()) {
CCValid = SystemZ::CCMASK_FCMP; CCValid = SystemZ::CCMASK_FCMP;
else { Opcode = SystemZISD::FCMP;
} else {
IsUnsigned = CCMask & SystemZ::CCMASK_CMP_UO; IsUnsigned = CCMask & SystemZ::CCMASK_CMP_UO;
CCValid = SystemZ::CCMASK_ICMP; CCValid = SystemZ::CCMASK_ICMP;
CCMask &= CCValid; CCMask &= CCValid;
adjustZeroCmp(DAG, IsUnsigned, CmpOp0, CmpOp1, CCMask); adjustZeroCmp(DAG, IsUnsigned, CmpOp0, CmpOp1, CCMask);
adjustSubwordCmp(DAG, IsUnsigned, CmpOp0, CmpOp1, CCMask); adjustSubwordCmp(DAG, IsUnsigned, CmpOp0, CmpOp1, CCMask);
if (preferUnsignedComparison(CmpOp0, CmpOp1, CCMask)) Opcode = SystemZISD::ICMP;
IsUnsigned = true; // Choose the type of comparison. Equality and inequality tests can
// 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
// want to give the main isel code the freedom to choose whichever
// form fits best.
if (CCMask == SystemZ::CCMASK_CMP_EQ ||
CCMask == SystemZ::CCMASK_CMP_NE ||
(DAG.SignBitIsZero(CmpOp0) && DAG.SignBitIsZero(CmpOp1)))
ICmpType = SystemZICMP::Any;
else if (IsUnsigned)
ICmpType = SystemZICMP::UnsignedOnly;
else
ICmpType = SystemZICMP::SignedOnly;
} }
if (shouldSwapCmpOperands(CmpOp0, CmpOp1, IsUnsigned)) { if (shouldSwapCmpOperands(CmpOp0, CmpOp1, ICmpType)) {
std::swap(CmpOp0, CmpOp1); std::swap(CmpOp0, CmpOp1);
CCMask = ((CCMask & SystemZ::CCMASK_CMP_EQ) | CCMask = ((CCMask & SystemZ::CCMASK_CMP_EQ) |
(CCMask & SystemZ::CCMASK_CMP_GT ? SystemZ::CCMASK_CMP_LT : 0) | (CCMask & SystemZ::CCMASK_CMP_GT ? SystemZ::CCMASK_CMP_LT : 0) |
@ -1340,8 +1314,10 @@ static SDValue emitCmp(SelectionDAG &DAG, SDLoc DL, SDValue CmpOp0,
(CCMask & SystemZ::CCMASK_CMP_UO)); (CCMask & SystemZ::CCMASK_CMP_UO));
} }
unsigned Opcode = (IsUnsigned ? SystemZISD::UCMP : SystemZISD::CMP); adjustForTestUnderMask(Opcode, CmpOp0, CmpOp1, CCValid, CCMask, ICmpType);
adjustForTestUnderMask(Opcode, CmpOp0, CmpOp1, CCValid, CCMask); if (Opcode == SystemZISD::ICMP)
return DAG.getNode(Opcode, DL, MVT::Glue, CmpOp0, CmpOp1,
DAG.getConstant(ICmpType, MVT::i32));
return DAG.getNode(Opcode, DL, MVT::Glue, CmpOp0, CmpOp1); return DAG.getNode(Opcode, DL, MVT::Glue, CmpOp0, CmpOp1);
} }
@ -1391,7 +1367,7 @@ SDValue SystemZTargetLowering::lowerBR_CC(SDValue Op, SelectionDAG &DAG) const {
SDLoc DL(Op); SDLoc DL(Op);
unsigned CCValid, CCMask; unsigned CCValid, CCMask;
SDValue Flags = emitCmp(DAG, DL, CmpOp0, CmpOp1, CC, CCValid, CCMask); SDValue Flags = emitCmp(TM, DAG, DL, CmpOp0, CmpOp1, CC, CCValid, CCMask);
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(CCValid, MVT::i32),
DAG.getConstant(CCMask, MVT::i32), Dest, Flags); DAG.getConstant(CCMask, MVT::i32), Dest, Flags);
@ -1407,7 +1383,7 @@ SDValue SystemZTargetLowering::lowerSELECT_CC(SDValue Op,
SDLoc DL(Op); SDLoc DL(Op);
unsigned CCValid, CCMask; unsigned CCValid, CCMask;
SDValue Flags = emitCmp(DAG, DL, CmpOp0, CmpOp1, CC, CCValid, CCMask); SDValue Flags = emitCmp(TM, DAG, DL, CmpOp0, CmpOp1, CC, CCValid, CCMask);
SmallVector<SDValue, 5> Ops; SmallVector<SDValue, 5> Ops;
Ops.push_back(TrueOp); Ops.push_back(TrueOp);
@ -2041,8 +2017,8 @@ const char *SystemZTargetLowering::getTargetNodeName(unsigned Opcode) const {
OPCODE(CALL); OPCODE(CALL);
OPCODE(SIBCALL); OPCODE(SIBCALL);
OPCODE(PCREL_WRAPPER); OPCODE(PCREL_WRAPPER);
OPCODE(CMP); OPCODE(ICMP);
OPCODE(UCMP); OPCODE(FCMP);
OPCODE(TM); OPCODE(TM);
OPCODE(BR_CCMASK); OPCODE(BR_CCMASK);
OPCODE(SELECT_CCMASK); OPCODE(SELECT_CCMASK);

View File

@ -38,12 +38,12 @@ namespace SystemZISD {
// accesses (LARL). Operand 0 is the address. // accesses (LARL). Operand 0 is the address.
PCREL_WRAPPER, PCREL_WRAPPER,
// Signed integer and floating-point comparisons. The operands are the // Integer comparisons. There are three operands: the two values
// two values to compare. // to compare, and an integer of type SystemZICMP.
CMP, ICMP,
// Likewise unsigned integer comparison. // Floating-point comparisons. The two operands are the values to compare.
UCMP, FCMP,
// Test under mask. The first operand is ANDed with the second operand // Test under mask. The first operand is ANDed with the second operand
// and the condition codes are set on the result. // and the condition codes are set on the result.
@ -162,6 +162,16 @@ namespace SystemZISD {
}; };
} }
namespace SystemZICMP {
// Describes whether an integer comparison needs to be signed or unsigned,
// or whether either type is OK.
enum {
Any,
UnsignedOnly,
SignedOnly
};
}
class SystemZSubtarget; class SystemZSubtarget;
class SystemZTargetMachine; class SystemZTargetMachine;

View File

@ -349,12 +349,12 @@ def DDB : BinaryRXE<"ddb", 0xED1D, fdiv, FP64, load, 8>;
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
let Defs = [CC], CCValues = 0xF in { let Defs = [CC], CCValues = 0xF in {
def CEBR : CompareRRE<"ceb", 0xB309, z_cmp, FP32, FP32>; def CEBR : CompareRRE<"ceb", 0xB309, z_fcmp, FP32, FP32>;
def CDBR : CompareRRE<"cdb", 0xB319, z_cmp, FP64, FP64>; def CDBR : CompareRRE<"cdb", 0xB319, z_fcmp, FP64, FP64>;
def CXBR : CompareRRE<"cxb", 0xB349, z_cmp, FP128, FP128>; def CXBR : CompareRRE<"cxb", 0xB349, z_fcmp, FP128, FP128>;
def CEB : CompareRXE<"ceb", 0xED09, z_cmp, FP32, load, 4>; def CEB : CompareRXE<"ceb", 0xED09, z_fcmp, FP32, load, 4>;
def CDB : CompareRXE<"cdb", 0xED19, z_cmp, FP64, load, 8>; def CDB : CompareRXE<"cdb", 0xED19, z_fcmp, FP64, load, 8>;
} }
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

View File

@ -954,39 +954,41 @@ let Defs = [CC] in {
// Comparison // Comparison
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Signed comparisons. // Signed comparisons. We put these before the unsigned comparisons because
// some of the signed forms have COMPARE AND BRANCH equivalents whereas none
// of the unsigned forms do.
let Defs = [CC], CCValues = 0xE in { let Defs = [CC], CCValues = 0xE in {
// Comparison with a register. // Comparison with a register.
def CR : CompareRR <"c", 0x19, z_cmp, GR32, GR32>; def CR : CompareRR <"c", 0x19, z_scmp, GR32, GR32>;
def CGFR : CompareRRE<"cgf", 0xB930, null_frag, GR64, GR32>; def CGFR : CompareRRE<"cgf", 0xB930, null_frag, GR64, GR32>;
def CGR : CompareRRE<"cg", 0xB920, z_cmp, GR64, GR64>; def CGR : CompareRRE<"cg", 0xB920, z_scmp, GR64, GR64>;
// Comparison with a signed 16-bit immediate. // Comparison with a signed 16-bit immediate.
def CHI : CompareRI<"chi", 0xA7E, z_cmp, GR32, imm32sx16>; def CHI : CompareRI<"chi", 0xA7E, z_scmp, GR32, imm32sx16>;
def CGHI : CompareRI<"cghi", 0xA7F, z_cmp, GR64, imm64sx16>; def CGHI : CompareRI<"cghi", 0xA7F, z_scmp, GR64, imm64sx16>;
// Comparison with a signed 32-bit immediate. // Comparison with a signed 32-bit immediate.
def CFI : CompareRIL<"cfi", 0xC2D, z_cmp, GR32, simm32>; def CFI : CompareRIL<"cfi", 0xC2D, z_scmp, GR32, simm32>;
def CGFI : CompareRIL<"cgfi", 0xC2C, z_cmp, GR64, imm64sx32>; def CGFI : CompareRIL<"cgfi", 0xC2C, z_scmp, GR64, imm64sx32>;
// Comparison with memory. // Comparison with memory.
defm CH : CompareRXPair<"ch", 0x49, 0xE379, z_cmp, GR32, sextloadi16, 2>; defm CH : CompareRXPair<"ch", 0x49, 0xE379, z_scmp, GR32, sextloadi16, 2>;
defm C : CompareRXPair<"c", 0x59, 0xE359, z_cmp, GR32, load, 4>; defm C : CompareRXPair<"c", 0x59, 0xE359, z_scmp, GR32, load, 4>;
def CGH : CompareRXY<"cgh", 0xE334, z_cmp, GR64, sextloadi16, 2>; def CGH : CompareRXY<"cgh", 0xE334, z_scmp, GR64, sextloadi16, 2>;
def CGF : CompareRXY<"cgf", 0xE330, z_cmp, GR64, sextloadi32, 4>; def CGF : CompareRXY<"cgf", 0xE330, z_scmp, GR64, sextloadi32, 4>;
def CG : CompareRXY<"cg", 0xE320, z_cmp, GR64, load, 8>; def CG : CompareRXY<"cg", 0xE320, z_scmp, GR64, load, 8>;
def CHRL : CompareRILPC<"chrl", 0xC65, z_cmp, GR32, aligned_sextloadi16>; def CHRL : CompareRILPC<"chrl", 0xC65, z_scmp, GR32, aligned_sextloadi16>;
def CRL : CompareRILPC<"crl", 0xC6D, z_cmp, GR32, aligned_load>; def CRL : CompareRILPC<"crl", 0xC6D, z_scmp, GR32, aligned_load>;
def CGHRL : CompareRILPC<"cghrl", 0xC64, z_cmp, GR64, aligned_sextloadi16>; def CGHRL : CompareRILPC<"cghrl", 0xC64, z_scmp, GR64, aligned_sextloadi16>;
def CGFRL : CompareRILPC<"cgfrl", 0xC6C, z_cmp, GR64, aligned_sextloadi32>; def CGFRL : CompareRILPC<"cgfrl", 0xC6C, z_scmp, GR64, aligned_sextloadi32>;
def CGRL : CompareRILPC<"cgrl", 0xC68, z_cmp, GR64, aligned_load>; def CGRL : CompareRILPC<"cgrl", 0xC68, z_scmp, GR64, aligned_load>;
// Comparison between memory and a signed 16-bit immediate. // Comparison between memory and a signed 16-bit immediate.
def CHHSI : CompareSIL<"chhsi", 0xE554, z_cmp, sextloadi16, imm32sx16>; def CHHSI : CompareSIL<"chhsi", 0xE554, z_scmp, sextloadi16, imm32sx16>;
def CHSI : CompareSIL<"chsi", 0xE55C, z_cmp, load, imm32sx16>; def CHSI : CompareSIL<"chsi", 0xE55C, z_scmp, load, imm32sx16>;
def CGHSI : CompareSIL<"cghsi", 0xE558, z_cmp, load, imm64sx16>; def CGHSI : CompareSIL<"cghsi", 0xE558, z_scmp, load, imm64sx16>;
} }
defm : SXB<z_cmp, GR64, CGFR>; defm : SXB<z_scmp, GR64, CGFR>;
// Unsigned comparisons. // Unsigned comparisons.
let Defs = [CC], CCValues = 0xE, IsLogical = 1 in { let Defs = [CC], CCValues = 0xE, IsLogical = 1 in {

View File

@ -15,6 +15,9 @@ def SDT_CallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i64>,
SDTCisVT<1, i64>]>; SDTCisVT<1, i64>]>;
def SDT_ZCall : SDTypeProfile<0, -1, [SDTCisPtrTy<0>]>; def SDT_ZCall : SDTypeProfile<0, -1, [SDTCisPtrTy<0>]>;
def SDT_ZCmp : SDTypeProfile<0, 2, [SDTCisSameAs<0, 1>]>; def SDT_ZCmp : SDTypeProfile<0, 2, [SDTCisSameAs<0, 1>]>;
def SDT_ZICmp : SDTypeProfile<0, 3,
[SDTCisSameAs<0, 1>,
SDTCisVT<2, i32>]>;
def SDT_ZBRCCMask : SDTypeProfile<0, 3, def SDT_ZBRCCMask : SDTypeProfile<0, 3,
[SDTCisVT<0, i8>, [SDTCisVT<0, i8>,
SDTCisVT<1, i8>, SDTCisVT<1, i8>,
@ -94,8 +97,8 @@ def z_sibcall : SDNode<"SystemZISD::SIBCALL", SDT_ZCall,
[SDNPHasChain, SDNPOutGlue, SDNPOptInGlue, [SDNPHasChain, SDNPOutGlue, SDNPOptInGlue,
SDNPVariadic]>; SDNPVariadic]>;
def z_pcrel_wrapper : SDNode<"SystemZISD::PCREL_WRAPPER", SDT_ZWrapPtr, []>; def z_pcrel_wrapper : SDNode<"SystemZISD::PCREL_WRAPPER", SDT_ZWrapPtr, []>;
def z_cmp : SDNode<"SystemZISD::CMP", SDT_ZCmp, [SDNPOutGlue]>; def z_icmp : SDNode<"SystemZISD::ICMP", SDT_ZICmp, [SDNPOutGlue]>;
def z_ucmp : SDNode<"SystemZISD::UCMP", SDT_ZCmp, [SDNPOutGlue]>; def z_fcmp : SDNode<"SystemZISD::FCMP", SDT_ZCmp, [SDNPOutGlue]>;
def z_tm : SDNode<"SystemZISD::TM", SDT_ZCmp, [SDNPOutGlue]>; def z_tm : SDNode<"SystemZISD::TM", SDT_ZCmp, [SDNPOutGlue]>;
def z_br_ccmask : SDNode<"SystemZISD::BR_CCMASK", SDT_ZBRCCMask, def z_br_ccmask : SDNode<"SystemZISD::BR_CCMASK", SDT_ZBRCCMask,
[SDNPHasChain, SDNPInGlue]>; [SDNPHasChain, SDNPInGlue]>;
@ -163,6 +166,16 @@ def z_prefetch : SDNode<"SystemZISD::PREFETCH", SDT_ZPrefetch,
// Pattern fragments // Pattern fragments
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Signed and unsigned comparisons.
def z_scmp : PatFrag<(ops node:$a, node:$b), (z_icmp node:$a, node:$b, imm), [{
unsigned Type = cast<ConstantSDNode>(N->getOperand(2))->getZExtValue();
return Type != SystemZICMP::UnsignedOnly;
}]>;
def z_ucmp : PatFrag<(ops node:$a, node:$b), (z_icmp node:$a, node:$b, imm), [{
unsigned Type = cast<ConstantSDNode>(N->getOperand(2))->getZExtValue();
return Type != SystemZICMP::SignedOnly;
}]>;
// Register sign-extend operations. Sub-32-bit values are represented as i32s. // Register sign-extend operations. Sub-32-bit values are represented as i32s.
def sext8 : PatFrag<(ops node:$src), (sext_inreg node:$src, i8)>; def sext8 : PatFrag<(ops node:$src), (sext_inreg node:$src, i8)>;
def sext16 : PatFrag<(ops node:$src), (sext_inreg node:$src, i16)>; def sext16 : PatFrag<(ops node:$src), (sext_inreg node:$src, i16)>;

View File

@ -103,4 +103,4 @@ multiclass BlockLoadStore<SDPatternOperator load, ValueType vt,
// registers in CLS against zero. The instruction has separate R1 and R2 // registers in CLS against zero. The instruction has separate R1 and R2
// operands, but they must be the same when the instruction is used like this. // operands, but they must be the same when the instruction is used like this.
class CompareZeroFP<Instruction insn, RegisterOperand cls> class CompareZeroFP<Instruction insn, RegisterOperand cls>
: Pat<(z_cmp cls:$reg, (fpimm0)), (insn cls:$reg, cls:$reg)>; : Pat<(z_fcmp cls:$reg, (fpimm0)), (insn cls:$reg, cls:$reg)>;

View File

@ -3,6 +3,7 @@
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s ; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
declare i32 @foo() declare i32 @foo()
@g1 = global i16 0
define void @f1(i32 %target) { define void @f1(i32 %target) {
; CHECK-LABEL: f1: ; CHECK-LABEL: f1:
@ -87,3 +88,103 @@ loop:
exit: exit:
ret void ret void
} }
; Check that CRJ is used for checking equality with a zero-extending
; character load.
define void @f7(i8 *%targetptr) {
; CHECK-LABEL: f7:
; CHECK: .cfi_def_cfa_offset
; CHECK: .L[[LABEL:.*]]:
; CHECK: llc [[REG:%r[0-5]]],
; CHECK: crje %r2, [[REG]], .L[[LABEL]]
br label %loop
loop:
%val = call i32 @foo()
%byte = load i8 *%targetptr
%target = zext i8 %byte to i32
%cond = icmp eq i32 %val, %target
br i1 %cond, label %loop, label %exit
exit:
ret void
}
; ...and zero-extending i16 loads.
define void @f8(i16 *%targetptr) {
; CHECK-LABEL: f8:
; CHECK: .cfi_def_cfa_offset
; CHECK: .L[[LABEL:.*]]:
; CHECK: llh [[REG:%r[0-5]]],
; CHECK: crje %r2, [[REG]], .L[[LABEL]]
br label %loop
loop:
%val = call i32 @foo()
%half = load i16 *%targetptr
%target = zext i16 %half to i32
%cond = icmp eq i32 %val, %target
br i1 %cond, label %loop, label %exit
exit:
ret void
}
; ...unless the address is a global.
define void @f9(i16 *%targetptr) {
; CHECK-LABEL: f9:
; CHECK: .cfi_def_cfa_offset
; CHECK: .L[[LABEL:.*]]:
; CHECK: clhrl %r2, g1
; CHECK: je .L[[LABEL]]
br label %loop
loop:
%val = call i32 @foo()
%half = load i16 *@g1
%target = zext i16 %half to i32
%cond = icmp eq i32 %val, %target
br i1 %cond, label %loop, label %exit
exit:
ret void
}
; Check that CRJ is used for checking order between two zero-extending
; byte loads, even if the original comparison was unsigned.
define void @f10(i8 *%targetptr1) {
; CHECK-LABEL: f10:
; CHECK: .cfi_def_cfa_offset
; CHECK: .L[[LABEL:.*]]:
; CHECK-DAG: llc [[REG1:%r[0-5]]], 0(
; CHECK-DAG: llc [[REG2:%r[0-5]]], 1(
; CHECK: crjl [[REG1]], [[REG2]], .L[[LABEL]]
br label %loop
loop:
%val = call i32 @foo()
%targetptr2 = getelementptr i8 *%targetptr1, i64 1
%byte1 = load i8 *%targetptr1
%byte2 = load i8 *%targetptr2
%ext1 = zext i8 %byte1 to i32
%ext2 = zext i8 %byte2 to i32
%cond = icmp ult i32 %ext1, %ext2
br i1 %cond, label %loop, label %exit
exit:
ret void
}
; ...likewise halfword loads.
define void @f11(i16 *%targetptr1) {
; CHECK-LABEL: f11:
; CHECK: .cfi_def_cfa_offset
; CHECK: .L[[LABEL:.*]]:
; CHECK-DAG: llh [[REG1:%r[0-5]]], 0(
; CHECK-DAG: llh [[REG2:%r[0-5]]], 2(
; CHECK: crjl [[REG1]], [[REG2]], .L[[LABEL]]
br label %loop
loop:
%val = call i32 @foo()
%targetptr2 = getelementptr i16 *%targetptr1, i64 1
%half1 = load i16 *%targetptr1
%half2 = load i16 *%targetptr2
%ext1 = zext i16 %half1 to i32
%ext2 = zext i16 %half2 to i32
%cond = icmp ult i32 %ext1, %ext2
br i1 %cond, label %loop, label %exit
exit:
ret void
}