From: Richard Sandiford Date: Tue, 3 Sep 2013 15:38:35 +0000 (+0000) Subject: [SystemZ] Add support for TMHH, TMHL, TMLH and TMLL X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=8bce43648be1156fdced590beb81aed3915762f1;p=oota-llvm.git [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 --- diff --git a/lib/Target/SystemZ/SystemZ.h b/lib/Target/SystemZ/SystemZ.h index 051ba1dcfb6..1647d93c02d 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 1ab1ef4acaf..13d5604be13 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 diff --git a/test/CodeGen/SystemZ/int-cmp-46.ll b/test/CodeGen/SystemZ/int-cmp-46.ll index b46ca5e6d1f..339ba11694a 100644 --- a/test/CodeGen/SystemZ/int-cmp-46.ll +++ b/test/CodeGen/SystemZ/int-cmp-46.ll @@ -97,3 +97,355 @@ store: exit: ret void } + +; Check that we can use TMLL for LT comparisons that are equivalent to +; an equality comparison with zero. +define void @f6(i32 %a) { +; CHECK-LABEL: f6: +; CHECK: tmll %r2, 240 +; CHECK: je {{\.L.*}} +; CHECK: br %r14 +entry: + %and = and i32 %a, 240 + %cmp = icmp slt i32 %and, 16 + br i1 %cmp, label %exit, label %store + +store: + store i32 1, i32 *@g + br label %exit + +exit: + ret void +} + +; ...same again with LE. +define void @f7(i32 %a) { +; CHECK-LABEL: f7: +; CHECK: tmll %r2, 240 +; CHECK: je {{\.L.*}} +; CHECK: br %r14 +entry: + %and = and i32 %a, 240 + %cmp = icmp sle i32 %and, 15 + br i1 %cmp, label %exit, label %store + +store: + store i32 1, i32 *@g + br label %exit + +exit: + ret void +} + +; Check that we can use TMLL for GE comparisons that are equivalent to +; an inequality comparison with zero. +define void @f8(i32 %a) { +; CHECK-LABEL: f8: +; CHECK: tmll %r2, 240 +; CHECK: jne {{\.L.*}} +; CHECK: br %r14 +entry: + %and = and i32 %a, 240 + %cmp = icmp uge i32 %and, 16 + br i1 %cmp, label %exit, label %store + +store: + store i32 1, i32 *@g + br label %exit + +exit: + ret void +} + +; ...same again with GT. +define void @f9(i32 %a) { +; CHECK-LABEL: f9: +; CHECK: tmll %r2, 240 +; CHECK: jne {{\.L.*}} +; CHECK: br %r14 +entry: + %and = and i32 %a, 240 + %cmp = icmp ugt i32 %and, 15 + br i1 %cmp, label %exit, label %store + +store: + store i32 1, i32 *@g + br label %exit + +exit: + ret void +} + +; Check that we can use TMLL for LT comparisons that effectively +; test whether the top bit is clear. +define void @f10(i32 %a) { +; CHECK-LABEL: f10: +; CHECK: tmll %r2, 35 +; CHECK: jle {{\.L.*}} +; CHECK: br %r14 +entry: + %and = and i32 %a, 35 + %cmp = icmp ult i32 %and, 8 + br i1 %cmp, label %exit, label %store + +store: + store i32 1, i32 *@g + br label %exit + +exit: + ret void +} + +; ...same again with LE. +define void @f11(i32 %a) { +; CHECK-LABEL: f11: +; CHECK: tmll %r2, 35 +; CHECK: jle {{\.L.*}} +; CHECK: br %r14 +entry: + %and = and i32 %a, 35 + %cmp = icmp ule i32 %and, 31 + br i1 %cmp, label %exit, label %store + +store: + store i32 1, i32 *@g + br label %exit + +exit: + ret void +} + +; Check that we can use TMLL for GE comparisons that effectively test +; whether the top bit is set. +define void @f12(i32 %a) { +; CHECK-LABEL: f12: +; CHECK: tmll %r2, 140 +; CHECK: jnle {{\.L.*}} +; CHECK: br %r14 +entry: + %and = and i32 %a, 140 + %cmp = icmp uge i32 %and, 128 + br i1 %cmp, label %exit, label %store + +store: + store i32 1, i32 *@g + br label %exit + +exit: + ret void +} + +; ...same again for GT. +define void @f13(i32 %a) { +; CHECK-LABEL: f13: +; CHECK: tmll %r2, 140 +; CHECK: jnle {{\.L.*}} +; CHECK: br %r14 +entry: + %and = and i32 %a, 140 + %cmp = icmp ugt i32 %and, 126 + br i1 %cmp, label %exit, label %store + +store: + store i32 1, i32 *@g + br label %exit + +exit: + ret void +} + +; Check that we can use TMLL for equality comparisons with the mask. +define void @f14(i32 %a) { +; CHECK-LABEL: f14: +; CHECK: tmll %r2, 101 +; CHECK: jo {{\.L.*}} +; CHECK: br %r14 +entry: + %and = and i32 %a, 101 + %cmp = icmp eq i32 %and, 101 + br i1 %cmp, label %exit, label %store + +store: + store i32 1, i32 *@g + br label %exit + +exit: + ret void +} + +; Check that we can use TMLL for inequality comparisons with the mask. +define void @f15(i32 %a) { +; CHECK-LABEL: f15: +; CHECK: tmll %r2, 65519 +; CHECK: jno {{\.L.*}} +; CHECK: br %r14 +entry: + %and = and i32 %a, 65519 + %cmp = icmp ne i32 %and, 65519 + br i1 %cmp, label %exit, label %store + +store: + store i32 1, i32 *@g + br label %exit + +exit: + ret void +} + +; Check that we can use TMLL for LT comparisons that are equivalent +; to inequality comparisons with the mask. +define void @f16(i32 %a) { +; CHECK-LABEL: f16: +; CHECK: tmll %r2, 130 +; CHECK: jno {{\.L.*}} +; CHECK: br %r14 +entry: + %and = and i32 %a, 130 + %cmp = icmp ult i32 %and, 129 + br i1 %cmp, label %exit, label %store + +store: + store i32 1, i32 *@g + br label %exit + +exit: + ret void +} + +; ...same again with LE. +define void @f17(i32 %a) { +; CHECK-LABEL: f17: +; CHECK: tmll %r2, 130 +; CHECK: jno {{\.L.*}} +; CHECK: br %r14 +entry: + %and = and i32 %a, 130 + %cmp = icmp ule i32 %and, 128 + br i1 %cmp, label %exit, label %store + +store: + store i32 1, i32 *@g + br label %exit + +exit: + ret void +} + +; Check that we can use TMLL for GE comparisons that are equivalent +; to equality comparisons with the mask. +define void @f18(i32 %a) { +; CHECK-LABEL: f18: +; CHECK: tmll %r2, 194 +; CHECK: jo {{\.L.*}} +; CHECK: br %r14 +entry: + %and = and i32 %a, 194 + %cmp = icmp uge i32 %and, 193 + br i1 %cmp, label %exit, label %store + +store: + store i32 1, i32 *@g + br label %exit + +exit: + ret void +} + +; ...same again for GT. +define void @f19(i32 %a) { +; CHECK-LABEL: f19: +; CHECK: tmll %r2, 194 +; CHECK: jo {{\.L.*}} +; CHECK: br %r14 +entry: + %and = and i32 %a, 194 + %cmp = icmp ugt i32 %and, 192 + br i1 %cmp, label %exit, label %store + +store: + store i32 1, i32 *@g + br label %exit + +exit: + ret void +} + +; Check that we can use TMLL for equality comparisons for the low bit +; when the mask has two bits. +define void @f20(i32 %a) { +; CHECK-LABEL: f20: +; CHECK: tmll %r2, 20 +; CHECK: jl {{\.L.*}} +; CHECK: br %r14 +entry: + %and = and i32 %a, 20 + %cmp = icmp eq i32 %and, 4 + br i1 %cmp, label %exit, label %store + +store: + store i32 1, i32 *@g + br label %exit + +exit: + ret void +} + +; Check that we can use TMLL for inequality comparisons for the low bit +; when the mask has two bits. +define void @f21(i32 %a) { +; CHECK-LABEL: f21: +; CHECK: tmll %r2, 20 +; CHECK: jnl {{\.L.*}} +; CHECK: br %r14 +entry: + %and = and i32 %a, 20 + %cmp = icmp ne i32 %and, 4 + br i1 %cmp, label %exit, label %store + +store: + store i32 1, i32 *@g + br label %exit + +exit: + ret void +} + +; Check that we can use TMLL for equality comparisons for the high bit +; when the mask has two bits. +define void @f22(i32 %a) { +; CHECK-LABEL: f22: +; CHECK: tmll %r2, 20 +; CHECK: jh {{\.L.*}} +; CHECK: br %r14 +entry: + %and = and i32 %a, 20 + %cmp = icmp eq i32 %and, 16 + br i1 %cmp, label %exit, label %store + +store: + store i32 1, i32 *@g + br label %exit + +exit: + ret void +} + +; Check that we can use TMLL for inequality comparisons for the high bit +; when the mask has two bits. +define void @f23(i32 %a) { +; CHECK-LABEL: f23: +; CHECK: tmll %r2, 20 +; CHECK: jnh {{\.L.*}} +; CHECK: br %r14 +entry: + %and = and i32 %a, 20 + %cmp = icmp ne i32 %and, 16 + br i1 %cmp, label %exit, label %store + +store: + store i32 1, i32 *@g + br label %exit + +exit: + ret void +}