mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-11-02 07:11:49 +00:00
[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:
parent
e3273b3275
commit
aff1c6427c
@ -1069,73 +1069,33 @@ static void adjustSubwordCmp(SelectionDAG &DAG, bool &IsUnsigned,
|
||||
CmpOp1 = DAG.getConstant(Value, MVT::i32);
|
||||
}
|
||||
|
||||
// Return true if a comparison described by CCMask, CmpOp0 and CmpOp1
|
||||
// is an equality comparison that is better implemented using unsigned
|
||||
// rather than signed comparison instructions.
|
||||
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) {
|
||||
// Return true if Op is either an unextended load, or a load suitable
|
||||
// for integer register-memory comparisons of type ICmpType.
|
||||
static bool isNaturalMemoryOperand(SDValue Op, unsigned ICmpType) {
|
||||
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()) {
|
||||
case ISD::NON_EXTLOAD:
|
||||
case ISD::EXTLOAD:
|
||||
return true;
|
||||
case ISD::SEXTLOAD:
|
||||
return !IsUnsigned;
|
||||
return ICmpType != SystemZICMP::UnsignedOnly;
|
||||
case ISD::ZEXTLOAD:
|
||||
return IsUnsigned;
|
||||
return ICmpType != SystemZICMP::SignedOnly;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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,
|
||||
bool IsUnsigned) {
|
||||
unsigned ICmpType) {
|
||||
// Leave f128 comparisons alone, since they have no memory forms.
|
||||
if (Op0.getValueType() == MVT::f128)
|
||||
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.
|
||||
// In that case we generally prefer the memory to be second.
|
||||
if ((isNaturalMemoryOperand(Op0, IsUnsigned) && Op0.hasOneUse()) &&
|
||||
!(isNaturalMemoryOperand(Op1, IsUnsigned) && Op1.hasOneUse())) {
|
||||
if ((isNaturalMemoryOperand(Op0, ICmpType) && Op0.hasOneUse()) &&
|
||||
!(isNaturalMemoryOperand(Op1, ICmpType) && Op1.hasOneUse())) {
|
||||
// The only exceptions are when the second operand is a constant and
|
||||
// we can use things like CHHSI.
|
||||
if (!COp1)
|
||||
return true;
|
||||
if (IsUnsigned) {
|
||||
// The memory-immediate instructions require 16-bit unsigned integers.
|
||||
if (isUInt<16>(COp1->getZExtValue()))
|
||||
return false;
|
||||
} else {
|
||||
// There are no comparisons between integers and signed memory bytes.
|
||||
// The others require 16-bit signed integers.
|
||||
if (cast<LoadSDNode>(Op0.getNode())->getMemoryVT() == MVT::i8 ||
|
||||
isInt<16>(COp1->getSExtValue()))
|
||||
return false;
|
||||
}
|
||||
// The unsigned memory-immediate instructions can handle 16-bit
|
||||
// unsigned integers.
|
||||
if (ICmpType != SystemZICMP::SignedOnly &&
|
||||
isUInt<16>(COp1->getZExtValue()))
|
||||
return false;
|
||||
// The signed memory-immediate instructions can handle 16-bit
|
||||
// signed integers.
|
||||
if (ICmpType != SystemZICMP::UnsignedOnly &&
|
||||
isInt<16>(COp1->getSExtValue()))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
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
|
||||
// should be used for the TEST UNDER MASK result, or 0 if the condition is
|
||||
// too complex.
|
||||
static unsigned getTestUnderMaskCond(unsigned BitSize, unsigned Opcode,
|
||||
unsigned CCMask, uint64_t Mask,
|
||||
uint64_t CmpVal) {
|
||||
static unsigned getTestUnderMaskCond(unsigned BitSize, unsigned CCMask,
|
||||
uint64_t Mask, uint64_t CmpVal,
|
||||
unsigned ICmpType) {
|
||||
assert(Mask != 0 && "ANDs with zero should have been removed by now");
|
||||
|
||||
// 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
|
||||
// bit is dropped.
|
||||
bool EffectivelyUnsigned = (Opcode == SystemZISD::UCMP
|
||||
|| HighShift < BitSize - 1);
|
||||
bool EffectivelyUnsigned = (ICmpType != SystemZICMP::SignedOnly);
|
||||
|
||||
// Check for equality comparisons with 0, or the equivalent.
|
||||
if (CmpVal == 0) {
|
||||
@ -1274,7 +1232,7 @@ static unsigned getTestUnderMaskCond(unsigned BitSize, unsigned Opcode,
|
||||
// TM version if so.
|
||||
static void adjustForTestUnderMask(unsigned &Opcode, SDValue &CmpOp0,
|
||||
SDValue &CmpOp1, unsigned &CCValid,
|
||||
unsigned &CCMask) {
|
||||
unsigned &CCMask, unsigned ICmpType) {
|
||||
// Check that we have a comparison with a constant.
|
||||
ConstantSDNode *ConstCmpOp1 = dyn_cast<ConstantSDNode>(CmpOp1);
|
||||
if (!ConstCmpOp1)
|
||||
@ -1298,8 +1256,9 @@ static void adjustForTestUnderMask(unsigned &Opcode, SDValue &CmpOp0,
|
||||
// Check whether the combination of mask, comparison value and comparison
|
||||
// type are suitable.
|
||||
unsigned BitSize = CmpOp0.getValueType().getSizeInBits();
|
||||
unsigned NewCCMask = getTestUnderMaskCond(BitSize, Opcode, CCMask, MaskVal,
|
||||
ConstCmpOp1->getZExtValue());
|
||||
unsigned NewCCMask = getTestUnderMaskCond(BitSize, CCMask, MaskVal,
|
||||
ConstCmpOp1->getZExtValue(),
|
||||
ICmpType);
|
||||
if (!NewCCMask)
|
||||
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 results and CCMask to the subset of those results that are
|
||||
// associated with Cond.
|
||||
static SDValue emitCmp(SelectionDAG &DAG, SDLoc DL, SDValue CmpOp0,
|
||||
SDValue CmpOp1, ISD::CondCode Cond, unsigned &CCValid,
|
||||
static SDValue emitCmp(const SystemZTargetMachine &TM, SelectionDAG &DAG,
|
||||
SDLoc DL, SDValue CmpOp0, SDValue CmpOp1,
|
||||
ISD::CondCode Cond, unsigned &CCValid,
|
||||
unsigned &CCMask) {
|
||||
bool IsUnsigned = false;
|
||||
CCMask = CCMaskForCondCode(Cond);
|
||||
if (CmpOp0.getValueType().isFloatingPoint())
|
||||
unsigned Opcode, ICmpType = 0;
|
||||
if (CmpOp0.getValueType().isFloatingPoint()) {
|
||||
CCValid = SystemZ::CCMASK_FCMP;
|
||||
else {
|
||||
Opcode = SystemZISD::FCMP;
|
||||
} else {
|
||||
IsUnsigned = CCMask & SystemZ::CCMASK_CMP_UO;
|
||||
CCValid = SystemZ::CCMASK_ICMP;
|
||||
CCMask &= CCValid;
|
||||
adjustZeroCmp(DAG, IsUnsigned, CmpOp0, CmpOp1, CCMask);
|
||||
adjustSubwordCmp(DAG, IsUnsigned, CmpOp0, CmpOp1, CCMask);
|
||||
if (preferUnsignedComparison(CmpOp0, CmpOp1, CCMask))
|
||||
IsUnsigned = true;
|
||||
Opcode = SystemZISD::ICMP;
|
||||
// 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);
|
||||
CCMask = ((CCMask & SystemZ::CCMASK_CMP_EQ) |
|
||||
(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));
|
||||
}
|
||||
|
||||
unsigned Opcode = (IsUnsigned ? SystemZISD::UCMP : SystemZISD::CMP);
|
||||
adjustForTestUnderMask(Opcode, CmpOp0, CmpOp1, CCValid, CCMask);
|
||||
adjustForTestUnderMask(Opcode, CmpOp0, CmpOp1, CCValid, CCMask, ICmpType);
|
||||
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);
|
||||
}
|
||||
|
||||
@ -1391,7 +1367,7 @@ SDValue SystemZTargetLowering::lowerBR_CC(SDValue Op, SelectionDAG &DAG) const {
|
||||
SDLoc DL(Op);
|
||||
|
||||
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(),
|
||||
Chain, DAG.getConstant(CCValid, MVT::i32),
|
||||
DAG.getConstant(CCMask, MVT::i32), Dest, Flags);
|
||||
@ -1407,7 +1383,7 @@ SDValue SystemZTargetLowering::lowerSELECT_CC(SDValue Op,
|
||||
SDLoc DL(Op);
|
||||
|
||||
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;
|
||||
Ops.push_back(TrueOp);
|
||||
@ -2041,8 +2017,8 @@ const char *SystemZTargetLowering::getTargetNodeName(unsigned Opcode) const {
|
||||
OPCODE(CALL);
|
||||
OPCODE(SIBCALL);
|
||||
OPCODE(PCREL_WRAPPER);
|
||||
OPCODE(CMP);
|
||||
OPCODE(UCMP);
|
||||
OPCODE(ICMP);
|
||||
OPCODE(FCMP);
|
||||
OPCODE(TM);
|
||||
OPCODE(BR_CCMASK);
|
||||
OPCODE(SELECT_CCMASK);
|
||||
|
@ -38,12 +38,12 @@ namespace SystemZISD {
|
||||
// accesses (LARL). Operand 0 is the address.
|
||||
PCREL_WRAPPER,
|
||||
|
||||
// Signed integer and floating-point comparisons. The operands are the
|
||||
// two values to compare.
|
||||
CMP,
|
||||
// Integer comparisons. There are three operands: the two values
|
||||
// to compare, and an integer of type SystemZICMP.
|
||||
ICMP,
|
||||
|
||||
// Likewise unsigned integer comparison.
|
||||
UCMP,
|
||||
// Floating-point comparisons. The two operands are the values to compare.
|
||||
FCMP,
|
||||
|
||||
// Test under mask. The first operand is ANDed with the second operand
|
||||
// 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 SystemZTargetMachine;
|
||||
|
||||
|
@ -349,12 +349,12 @@ def DDB : BinaryRXE<"ddb", 0xED1D, fdiv, FP64, load, 8>;
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
let Defs = [CC], CCValues = 0xF in {
|
||||
def CEBR : CompareRRE<"ceb", 0xB309, z_cmp, FP32, FP32>;
|
||||
def CDBR : CompareRRE<"cdb", 0xB319, z_cmp, FP64, FP64>;
|
||||
def CXBR : CompareRRE<"cxb", 0xB349, z_cmp, FP128, FP128>;
|
||||
def CEBR : CompareRRE<"ceb", 0xB309, z_fcmp, FP32, FP32>;
|
||||
def CDBR : CompareRRE<"cdb", 0xB319, z_fcmp, FP64, FP64>;
|
||||
def CXBR : CompareRRE<"cxb", 0xB349, z_fcmp, FP128, FP128>;
|
||||
|
||||
def CEB : CompareRXE<"ceb", 0xED09, z_cmp, FP32, load, 4>;
|
||||
def CDB : CompareRXE<"cdb", 0xED19, z_cmp, FP64, load, 8>;
|
||||
def CEB : CompareRXE<"ceb", 0xED09, z_fcmp, FP32, load, 4>;
|
||||
def CDB : CompareRXE<"cdb", 0xED19, z_fcmp, FP64, load, 8>;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -954,39 +954,41 @@ let Defs = [CC] in {
|
||||
// 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 {
|
||||
// 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 CGR : CompareRRE<"cg", 0xB920, z_cmp, GR64, GR64>;
|
||||
def CGR : CompareRRE<"cg", 0xB920, z_scmp, GR64, GR64>;
|
||||
|
||||
// Comparison with a signed 16-bit immediate.
|
||||
def CHI : CompareRI<"chi", 0xA7E, z_cmp, GR32, imm32sx16>;
|
||||
def CGHI : CompareRI<"cghi", 0xA7F, z_cmp, GR64, imm64sx16>;
|
||||
def CHI : CompareRI<"chi", 0xA7E, z_scmp, GR32, imm32sx16>;
|
||||
def CGHI : CompareRI<"cghi", 0xA7F, z_scmp, GR64, imm64sx16>;
|
||||
|
||||
// Comparison with a signed 32-bit immediate.
|
||||
def CFI : CompareRIL<"cfi", 0xC2D, z_cmp, GR32, simm32>;
|
||||
def CGFI : CompareRIL<"cgfi", 0xC2C, z_cmp, GR64, imm64sx32>;
|
||||
def CFI : CompareRIL<"cfi", 0xC2D, z_scmp, GR32, simm32>;
|
||||
def CGFI : CompareRIL<"cgfi", 0xC2C, z_scmp, GR64, imm64sx32>;
|
||||
|
||||
// Comparison with memory.
|
||||
defm CH : CompareRXPair<"ch", 0x49, 0xE379, z_cmp, GR32, sextloadi16, 2>;
|
||||
defm C : CompareRXPair<"c", 0x59, 0xE359, z_cmp, GR32, load, 4>;
|
||||
def CGH : CompareRXY<"cgh", 0xE334, z_cmp, GR64, sextloadi16, 2>;
|
||||
def CGF : CompareRXY<"cgf", 0xE330, z_cmp, GR64, sextloadi32, 4>;
|
||||
def CG : CompareRXY<"cg", 0xE320, z_cmp, GR64, load, 8>;
|
||||
def CHRL : CompareRILPC<"chrl", 0xC65, z_cmp, GR32, aligned_sextloadi16>;
|
||||
def CRL : CompareRILPC<"crl", 0xC6D, z_cmp, GR32, aligned_load>;
|
||||
def CGHRL : CompareRILPC<"cghrl", 0xC64, z_cmp, GR64, aligned_sextloadi16>;
|
||||
def CGFRL : CompareRILPC<"cgfrl", 0xC6C, z_cmp, GR64, aligned_sextloadi32>;
|
||||
def CGRL : CompareRILPC<"cgrl", 0xC68, z_cmp, GR64, aligned_load>;
|
||||
defm CH : CompareRXPair<"ch", 0x49, 0xE379, z_scmp, GR32, sextloadi16, 2>;
|
||||
defm C : CompareRXPair<"c", 0x59, 0xE359, z_scmp, GR32, load, 4>;
|
||||
def CGH : CompareRXY<"cgh", 0xE334, z_scmp, GR64, sextloadi16, 2>;
|
||||
def CGF : CompareRXY<"cgf", 0xE330, z_scmp, GR64, sextloadi32, 4>;
|
||||
def CG : CompareRXY<"cg", 0xE320, z_scmp, GR64, load, 8>;
|
||||
def CHRL : CompareRILPC<"chrl", 0xC65, z_scmp, GR32, aligned_sextloadi16>;
|
||||
def CRL : CompareRILPC<"crl", 0xC6D, z_scmp, GR32, aligned_load>;
|
||||
def CGHRL : CompareRILPC<"cghrl", 0xC64, z_scmp, GR64, aligned_sextloadi16>;
|
||||
def CGFRL : CompareRILPC<"cgfrl", 0xC6C, z_scmp, GR64, aligned_sextloadi32>;
|
||||
def CGRL : CompareRILPC<"cgrl", 0xC68, z_scmp, GR64, aligned_load>;
|
||||
|
||||
// Comparison between memory and a signed 16-bit immediate.
|
||||
def CHHSI : CompareSIL<"chhsi", 0xE554, z_cmp, sextloadi16, imm32sx16>;
|
||||
def CHSI : CompareSIL<"chsi", 0xE55C, z_cmp, load, imm32sx16>;
|
||||
def CGHSI : CompareSIL<"cghsi", 0xE558, z_cmp, load, imm64sx16>;
|
||||
def CHHSI : CompareSIL<"chhsi", 0xE554, z_scmp, sextloadi16, imm32sx16>;
|
||||
def CHSI : CompareSIL<"chsi", 0xE55C, z_scmp, load, imm32sx16>;
|
||||
def CGHSI : CompareSIL<"cghsi", 0xE558, z_scmp, load, imm64sx16>;
|
||||
}
|
||||
defm : SXB<z_cmp, GR64, CGFR>;
|
||||
defm : SXB<z_scmp, GR64, CGFR>;
|
||||
|
||||
// Unsigned comparisons.
|
||||
let Defs = [CC], CCValues = 0xE, IsLogical = 1 in {
|
||||
|
@ -15,6 +15,9 @@ def SDT_CallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i64>,
|
||||
SDTCisVT<1, i64>]>;
|
||||
def SDT_ZCall : SDTypeProfile<0, -1, [SDTCisPtrTy<0>]>;
|
||||
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,
|
||||
[SDTCisVT<0, i8>,
|
||||
SDTCisVT<1, i8>,
|
||||
@ -94,8 +97,8 @@ def z_sibcall : SDNode<"SystemZISD::SIBCALL", SDT_ZCall,
|
||||
[SDNPHasChain, SDNPOutGlue, SDNPOptInGlue,
|
||||
SDNPVariadic]>;
|
||||
def z_pcrel_wrapper : SDNode<"SystemZISD::PCREL_WRAPPER", SDT_ZWrapPtr, []>;
|
||||
def z_cmp : SDNode<"SystemZISD::CMP", SDT_ZCmp, [SDNPOutGlue]>;
|
||||
def z_ucmp : SDNode<"SystemZISD::UCMP", SDT_ZCmp, [SDNPOutGlue]>;
|
||||
def z_icmp : SDNode<"SystemZISD::ICMP", SDT_ZICmp, [SDNPOutGlue]>;
|
||||
def z_fcmp : SDNode<"SystemZISD::FCMP", SDT_ZCmp, [SDNPOutGlue]>;
|
||||
def z_tm : SDNode<"SystemZISD::TM", SDT_ZCmp, [SDNPOutGlue]>;
|
||||
def z_br_ccmask : SDNode<"SystemZISD::BR_CCMASK", SDT_ZBRCCMask,
|
||||
[SDNPHasChain, SDNPInGlue]>;
|
||||
@ -163,6 +166,16 @@ def z_prefetch : SDNode<"SystemZISD::PREFETCH", SDT_ZPrefetch,
|
||||
// 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.
|
||||
def sext8 : PatFrag<(ops node:$src), (sext_inreg node:$src, i8)>;
|
||||
def sext16 : PatFrag<(ops node:$src), (sext_inreg node:$src, i16)>;
|
||||
|
@ -103,4 +103,4 @@ multiclass BlockLoadStore<SDPatternOperator load, ValueType vt,
|
||||
// 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.
|
||||
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)>;
|
||||
|
@ -3,6 +3,7 @@
|
||||
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
|
||||
|
||||
declare i32 @foo()
|
||||
@g1 = global i16 0
|
||||
|
||||
define void @f1(i32 %target) {
|
||||
; CHECK-LABEL: f1:
|
||||
@ -87,3 +88,103 @@ loop:
|
||||
exit:
|
||||
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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user