From 8bce43648be1156fdced590beb81aed3915762f1 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Tue, 3 Sep 2013 15:38:35 +0000 Subject: [SystemZ] Add support for TMHH, TMHL, TMLH and TMLL For now this just handles simple comparisons of an ANDed value with zero. The CC value provides enough information to do any comparison for a 2-bit mask, and some nonzero comparisons with more populated masks, but that's all future work. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189819 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/SystemZ/SystemZ.h | 4 ++ lib/Target/SystemZ/SystemZISelLowering.cpp | 111 ++++++++++++++++++++++++++--- 2 files changed, 107 insertions(+), 8 deletions(-) (limited to 'lib/Target') diff --git a/lib/Target/SystemZ/SystemZ.h b/lib/Target/SystemZ/SystemZ.h index 051ba1d..1647d93 100644 --- a/lib/Target/SystemZ/SystemZ.h +++ b/lib/Target/SystemZ/SystemZ.h @@ -62,6 +62,10 @@ namespace llvm { const unsigned CCMASK_TM_MIXED_MSB_0 = CCMASK_1; const unsigned CCMASK_TM_MIXED_MSB_1 = CCMASK_2; const unsigned CCMASK_TM_ALL_1 = CCMASK_3; + const unsigned CCMASK_TM_SOME_0 = CCMASK_TM_ALL_1 ^ CCMASK_ANY; + const unsigned CCMASK_TM_SOME_1 = CCMASK_TM_ALL_0 ^ CCMASK_ANY; + const unsigned CCMASK_TM_MSB_0 = CCMASK_0 | CCMASK_1; + const unsigned CCMASK_TM_MSB_1 = CCMASK_2 | CCMASK_3; const unsigned CCMASK_TM = CCMASK_ANY; // Mask assignments for PFD. diff --git a/lib/Target/SystemZ/SystemZISelLowering.cpp b/lib/Target/SystemZ/SystemZISelLowering.cpp index 1ab1ef4..13d5604 100644 --- a/lib/Target/SystemZ/SystemZISelLowering.cpp +++ b/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -1176,6 +1176,98 @@ static bool shouldSwapCmpOperands(SDValue Op0, SDValue Op1, return false; } +// Check whether the CC value produced by TEST UNDER MASK is descriptive +// enough to handle an AND with Mask followed by a comparison of type Opcode +// with CmpVal. CCMask says which comparison result is being tested and +// 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) { + assert(Mask != 0 && "ANDs with zero should have been removed by now"); + + // Work out the masks for the lowest and highest bits. + unsigned HighShift = 63 - countLeadingZeros(Mask); + uint64_t High = uint64_t(1) << HighShift; + uint64_t Low = uint64_t(1) << countTrailingZeros(Mask); + + // Signed ordered comparisons are effectively unsigned if the sign + // bit is dropped. + bool EffectivelyUnsigned = (Opcode == SystemZISD::UCMP + || HighShift < BitSize - 1); + + // Check for equality comparisons with 0, or the equivalent. + if (CmpVal == 0) { + if (CCMask == SystemZ::CCMASK_CMP_EQ) + return SystemZ::CCMASK_TM_ALL_0; + if (CCMask == SystemZ::CCMASK_CMP_NE) + return SystemZ::CCMASK_TM_SOME_1; + } + if (EffectivelyUnsigned && CmpVal <= Low) { + if (CCMask == SystemZ::CCMASK_CMP_LT) + return SystemZ::CCMASK_TM_ALL_0; + if (CCMask == SystemZ::CCMASK_CMP_GE) + return SystemZ::CCMASK_TM_SOME_1; + } + if (EffectivelyUnsigned && CmpVal < Low) { + if (CCMask == SystemZ::CCMASK_CMP_LE) + return SystemZ::CCMASK_TM_ALL_0; + if (CCMask == SystemZ::CCMASK_CMP_GT) + return SystemZ::CCMASK_TM_SOME_1; + } + + // Check for equality comparisons with the mask, or the equivalent. + if (CmpVal == Mask) { + if (CCMask == SystemZ::CCMASK_CMP_EQ) + return SystemZ::CCMASK_TM_ALL_1; + if (CCMask == SystemZ::CCMASK_CMP_NE) + return SystemZ::CCMASK_TM_SOME_0; + } + if (EffectivelyUnsigned && CmpVal >= Mask - Low && CmpVal < Mask) { + if (CCMask == SystemZ::CCMASK_CMP_GT) + return SystemZ::CCMASK_TM_ALL_1; + if (CCMask == SystemZ::CCMASK_CMP_LE) + return SystemZ::CCMASK_TM_SOME_0; + } + if (EffectivelyUnsigned && CmpVal > Mask - Low && CmpVal <= Mask) { + if (CCMask == SystemZ::CCMASK_CMP_GE) + return SystemZ::CCMASK_TM_ALL_1; + if (CCMask == SystemZ::CCMASK_CMP_LT) + return SystemZ::CCMASK_TM_SOME_0; + } + + // Check for ordered comparisons with the top bit. + if (EffectivelyUnsigned && CmpVal >= Mask - High && CmpVal < High) { + if (CCMask == SystemZ::CCMASK_CMP_LE) + return SystemZ::CCMASK_TM_MSB_0; + if (CCMask == SystemZ::CCMASK_CMP_GT) + return SystemZ::CCMASK_TM_MSB_1; + } + if (EffectivelyUnsigned && CmpVal > Mask - High && CmpVal <= High) { + if (CCMask == SystemZ::CCMASK_CMP_LT) + return SystemZ::CCMASK_TM_MSB_0; + if (CCMask == SystemZ::CCMASK_CMP_GE) + return SystemZ::CCMASK_TM_MSB_1; + } + + // If there are just two bits, we can do equality checks for Low and High + // as well. + if (Mask == Low + High) { + if (CCMask == SystemZ::CCMASK_CMP_EQ && CmpVal == Low) + return SystemZ::CCMASK_TM_MIXED_MSB_0; + if (CCMask == SystemZ::CCMASK_CMP_NE && CmpVal == Low) + return SystemZ::CCMASK_TM_MIXED_MSB_0 ^ SystemZ::CCMASK_ANY; + if (CCMask == SystemZ::CCMASK_CMP_EQ && CmpVal == High) + return SystemZ::CCMASK_TM_MIXED_MSB_1; + if (CCMask == SystemZ::CCMASK_CMP_NE && CmpVal == High) + return SystemZ::CCMASK_TM_MIXED_MSB_1 ^ SystemZ::CCMASK_ANY; + } + + // Looks like we've exhausted our options. + return 0; +} + // See whether the comparison (Opcode CmpOp0, CmpOp1) can be implemented // as a TEST UNDER MASK instruction when the condition being tested is // as described by CCValid and CCMask. Update the arguments with the @@ -1183,12 +1275,9 @@ static bool shouldSwapCmpOperands(SDValue Op0, SDValue Op1, static void adjustForTestUnderMask(unsigned &Opcode, SDValue &CmpOp0, SDValue &CmpOp1, unsigned &CCValid, unsigned &CCMask) { - // For now we just handle equality and inequality with zero. - if (CCMask != SystemZ::CCMASK_CMP_EQ && - (CCMask ^ CCValid) != SystemZ::CCMASK_CMP_EQ) - return; + // Check that we have a comparison with a constant. ConstantSDNode *ConstCmpOp1 = dyn_cast(CmpOp1); - if (!ConstCmpOp1 || ConstCmpOp1->getZExtValue() != 0) + if (!ConstCmpOp1) return; // Check whether the nonconstant input is an AND with a constant mask. @@ -1206,14 +1295,20 @@ static void adjustForTestUnderMask(unsigned &Opcode, SDValue &CmpOp0, !SystemZ::isImmHL(MaskVal) && !SystemZ::isImmHH(MaskVal)) return; + // 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()); + if (!NewCCMask) + return; + // Go ahead and make the change. Opcode = SystemZISD::TM; CmpOp0 = AndOp0; CmpOp1 = AndOp1; CCValid = SystemZ::CCMASK_TM; - CCMask = (CCMask == SystemZ::CCMASK_CMP_EQ ? - SystemZ::CCMASK_TM_ALL_0 : - SystemZ::CCMASK_TM_ALL_0 ^ CCValid); + CCMask = NewCCMask; } // Return a target node that compares CmpOp0 with CmpOp1 and stores a -- cgit v1.1