diff --git a/llvm/lib/Target/SystemZ/SystemZ.h b/llvm/lib/Target/SystemZ/SystemZ.h index 051ba1dcfb66..1647d93c02dc 100644 --- a/llvm/lib/Target/SystemZ/SystemZ.h +++ b/llvm/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/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp index 1ab1ef4acaf3..13d5604be13d 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp +++ b/llvm/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/llvm/test/CodeGen/SystemZ/int-cmp-46.ll b/llvm/test/CodeGen/SystemZ/int-cmp-46.ll index b46ca5e6d1f5..339ba11694a4 100644 --- a/llvm/test/CodeGen/SystemZ/int-cmp-46.ll +++ b/llvm/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 +}