[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.

llvm-svn: 189819
This commit is contained in:
Richard Sandiford 2013-09-03 15:38:35 +00:00
parent ffdeb595ba
commit 113c870397
3 changed files with 459 additions and 8 deletions

View File

@ -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.

View File

@ -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<ConstantSDNode>(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

View File

@ -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
}