[SystemZ] Add support for TMHH, TMHL, TMLH and TMLL

For now 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@189469 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Richard Sandiford 2013-08-28 10:31:43 +00:00
parent a6c3a4ee76
commit 477168192c
11 changed files with 490 additions and 12 deletions

View File

@ -57,6 +57,13 @@ namespace llvm {
const unsigned CCMASK_SRST_NOTFOUND = CCMASK_2;
const unsigned CCMASK_SRST = CCMASK_1 | CCMASK_2;
// Condition-code mask assignments for TEST UNDER MASK.
const unsigned CCMASK_TM_ALL_0 = CCMASK_0;
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 = CCMASK_ANY;
// Mask assignments for PFD.
const unsigned PFD_READ = 1;
const unsigned PFD_WRITE = 2;

View File

@ -1072,8 +1072,8 @@ static void adjustSubwordCmp(SelectionDAG &DAG, bool &IsUnsigned,
// 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(SelectionDAG &DAG, SDValue CmpOp0,
SDValue CmpOp1, unsigned CCMask) {
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;
@ -1176,12 +1176,52 @@ static bool shouldSwapCmpOperands(SDValue Op0, SDValue Op1,
return false;
}
// 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
// TM version if so.
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;
ConstantSDNode *ConstCmpOp1 = dyn_cast<ConstantSDNode>(CmpOp1);
if (!ConstCmpOp1 || ConstCmpOp1->getZExtValue() != 0)
return;
// Check whether the nonconstant input is an AND with a constant mask.
if (CmpOp0.getOpcode() != ISD::AND)
return;
SDValue AndOp0 = CmpOp0.getOperand(0);
SDValue AndOp1 = CmpOp0.getOperand(1);
ConstantSDNode *Mask = dyn_cast<ConstantSDNode>(AndOp1.getNode());
if (!Mask)
return;
// Check whether the mask is suitable for TMHH, TMHL, TMLH or TMLL.
uint64_t MaskVal = Mask->getZExtValue();
if (!SystemZ::isImmLL(MaskVal) && !SystemZ::isImmLH(MaskVal) &&
!SystemZ::isImmHL(MaskVal) && !SystemZ::isImmHH(MaskVal))
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);
}
// Return a target node that compares CmpOp0 with CmpOp1 and stores a
// 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, SDValue CmpOp0, SDValue CmpOp1,
ISD::CondCode Cond, unsigned &CCValid,
static SDValue emitCmp(SelectionDAG &DAG, SDLoc DL, SDValue CmpOp0,
SDValue CmpOp1, ISD::CondCode Cond, unsigned &CCValid,
unsigned &CCMask) {
bool IsUnsigned = false;
CCMask = CCMaskForCondCode(Cond);
@ -1193,7 +1233,7 @@ static SDValue emitCmp(SelectionDAG &DAG, SDValue CmpOp0, SDValue CmpOp1,
CCMask &= CCValid;
adjustZeroCmp(DAG, IsUnsigned, CmpOp0, CmpOp1, CCMask);
adjustSubwordCmp(DAG, IsUnsigned, CmpOp0, CmpOp1, CCMask);
if (preferUnsignedComparison(DAG, CmpOp0, CmpOp1, CCMask))
if (preferUnsignedComparison(CmpOp0, CmpOp1, CCMask))
IsUnsigned = true;
}
@ -1205,9 +1245,9 @@ static SDValue emitCmp(SelectionDAG &DAG, SDValue CmpOp0, SDValue CmpOp1,
(CCMask & SystemZ::CCMASK_CMP_UO));
}
SDLoc DL(CmpOp0);
return DAG.getNode((IsUnsigned ? SystemZISD::UCMP : SystemZISD::CMP),
DL, MVT::Glue, CmpOp0, CmpOp1);
unsigned Opcode = (IsUnsigned ? SystemZISD::UCMP : SystemZISD::CMP);
adjustForTestUnderMask(Opcode, CmpOp0, CmpOp1, CCValid, CCMask);
return DAG.getNode(Opcode, DL, MVT::Glue, CmpOp0, CmpOp1);
}
// Implement a 32-bit *MUL_LOHI operation by extending both operands to
@ -1256,7 +1296,7 @@ SDValue SystemZTargetLowering::lowerBR_CC(SDValue Op, SelectionDAG &DAG) const {
SDLoc DL(Op);
unsigned CCValid, CCMask;
SDValue Flags = emitCmp(DAG, CmpOp0, CmpOp1, CC, CCValid, CCMask);
SDValue Flags = emitCmp(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);
@ -1272,7 +1312,7 @@ SDValue SystemZTargetLowering::lowerSELECT_CC(SDValue Op,
SDLoc DL(Op);
unsigned CCValid, CCMask;
SDValue Flags = emitCmp(DAG, CmpOp0, CmpOp1, CC, CCValid, CCMask);
SDValue Flags = emitCmp(DAG, DL, CmpOp0, CmpOp1, CC, CCValid, CCMask);
SmallVector<SDValue, 5> Ops;
Ops.push_back(TrueOp);
@ -1908,6 +1948,7 @@ const char *SystemZTargetLowering::getTargetNodeName(unsigned Opcode) const {
OPCODE(PCREL_WRAPPER);
OPCODE(CMP);
OPCODE(UCMP);
OPCODE(TM);
OPCODE(BR_CCMASK);
OPCODE(SELECT_CCMASK);
OPCODE(ADJDYNALLOC);

View File

@ -45,6 +45,10 @@ namespace SystemZISD {
// Likewise unsigned integer comparison.
UCMP,
// Test under mask. The first operand is ANDed with the second operand
// and the condition codes are set on the result.
TM,
// Branches if a condition is true. Operand 0 is the chain operand;
// operand 1 is the 4-bit condition-code mask, with bit N in
// big-endian order meaning "branch if CC=N"; operand 2 is the

View File

@ -1034,6 +1034,19 @@ let mayLoad = 1, Defs = [CC] in
let mayLoad = 1, Defs = [CC], Uses = [R0W] in
defm CLST : StringRRE<"clst", 0xB25D, z_strcmp>;
// Test under mask.
let Defs = [CC] in {
let isCodeGenOnly = 1 in {
def TMLL32 : CompareRI<"tmll", 0xA71, z_tm, GR32, imm32ll16>;
def TMLH32 : CompareRI<"tmlh", 0xA70, z_tm, GR32, imm32lh16>;
}
def TMLL : CompareRI<"tmll", 0xA71, z_tm, GR64, imm64ll16>;
def TMLH : CompareRI<"tmlh", 0xA70, z_tm, GR64, imm64lh16>;
def TMHL : CompareRI<"tmhl", 0xA73, z_tm, GR64, imm64hl16>;
def TMHH : CompareRI<"tmhh", 0xA72, z_tm, GR64, imm64hh16>;
}
//===----------------------------------------------------------------------===//
// Prefetch
//===----------------------------------------------------------------------===//

View File

@ -96,6 +96,7 @@ def z_sibcall : SDNode<"SystemZISD::SIBCALL", SDT_ZCall,
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_tm : SDNode<"SystemZISD::TM", SDT_ZCmp, [SDNPOutGlue]>;
def z_br_ccmask : SDNode<"SystemZISD::BR_CCMASK", SDT_ZBRCCMask,
[SDNPHasChain, SDNPInGlue]>;
def z_select_ccmask : SDNode<"SystemZISD::SELECT_CCMASK", SDT_ZSelectCCMask,

View File

@ -203,11 +203,11 @@ exit:
; comparisons with zero if the immediate covers the whole register.
define i32 @f11(i32 %a, i32 %b, i32 *%dest) {
; CHECK-LABEL: f11:
; CHECK: nilf %r2, 100
; CHECK: nilf %r2, 100000001
; CHECK-NEXT: jl .L{{.*}}
; CHECK: br %r14
entry:
%res = and i32 %a, 100
%res = and i32 %a, 100000001
%cmp = icmp ne i32 %res, 0
br i1 %cmp, label %exit, label %store

View File

@ -0,0 +1,99 @@
; Test the use of TEST UNDER MASK for 32-bit operations.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z196 | FileCheck %s
@g = global i32 0
; Check the lowest useful TMLL value.
define void @f1(i32 %a) {
; CHECK-LABEL: f1:
; CHECK: tmll %r2, 1
; CHECK: je {{\.L.*}}
; CHECK: br %r14
entry:
%and = and i32 %a, 1
%cmp = icmp eq i32 %and, 0
br i1 %cmp, label %exit, label %store
store:
store i32 1, i32 *@g
br label %exit
exit:
ret void
}
; Check the high end of the TMLL range.
define void @f2(i32 %a) {
; CHECK-LABEL: f2:
; CHECK: tmll %r2, 65535
; CHECK: jne {{\.L.*}}
; CHECK: br %r14
entry:
%and = and i32 %a, 65535
%cmp = icmp ne i32 %and, 0
br i1 %cmp, label %exit, label %store
store:
store i32 1, i32 *@g
br label %exit
exit:
ret void
}
; Check the lowest useful TMLH value, which is the next value up.
define void @f3(i32 %a) {
; CHECK-LABEL: f3:
; CHECK: tmlh %r2, 1
; CHECK: jne {{\.L.*}}
; CHECK: br %r14
entry:
%and = and i32 %a, 65536
%cmp = icmp ne i32 %and, 0
br i1 %cmp, label %exit, label %store
store:
store i32 1, i32 *@g
br label %exit
exit:
ret void
}
; Check the next value up again, which cannot use TM.
define void @f4(i32 %a) {
; CHECK-LABEL: f4:
; CHECK-NOT: {{tm[lh].}}
; CHECK: br %r14
entry:
%and = and i32 %a, 4294901759
%cmp = icmp eq i32 %and, 0
br i1 %cmp, label %exit, label %store
store:
store i32 1, i32 *@g
br label %exit
exit:
ret void
}
; Check the high end of the TMLH range.
define void @f5(i32 %a) {
; CHECK-LABEL: f5:
; CHECK: tmlh %r2, 65535
; CHECK: je {{\.L.*}}
; CHECK: br %r14
entry:
%and = and i32 %a, 4294901760
%cmp = icmp eq i32 %and, 0
br i1 %cmp, label %exit, label %store
store:
store i32 1, i32 *@g
br label %exit
exit:
ret void
}

View File

@ -0,0 +1,193 @@
; Test the use of TEST UNDER MASK for 64-bit operations.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z196 | FileCheck %s
@g = global i32 0
; Check the lowest useful TMLL value.
define void @f1(i64 %a) {
; CHECK-LABEL: f1:
; CHECK: tmll %r2, 1
; CHECK: je {{\.L.*}}
; CHECK: br %r14
entry:
%and = and i64 %a, 1
%cmp = icmp eq i64 %and, 0
br i1 %cmp, label %exit, label %store
store:
store i32 1, i32 *@g
br label %exit
exit:
ret void
}
; Check the high end of the TMLL range.
define void @f2(i64 %a) {
; CHECK-LABEL: f2:
; CHECK: tmll %r2, 65535
; CHECK: jne {{\.L.*}}
; CHECK: br %r14
entry:
%and = and i64 %a, 65535
%cmp = icmp ne i64 %and, 0
br i1 %cmp, label %exit, label %store
store:
store i32 1, i32 *@g
br label %exit
exit:
ret void
}
; Check the lowest useful TMLH value, which is the next value up.
define void @f3(i64 %a) {
; CHECK-LABEL: f3:
; CHECK: tmlh %r2, 1
; CHECK: jne {{\.L.*}}
; CHECK: br %r14
entry:
%and = and i64 %a, 65536
%cmp = icmp ne i64 %and, 0
br i1 %cmp, label %exit, label %store
store:
store i32 1, i32 *@g
br label %exit
exit:
ret void
}
; Check the next value up again, which cannot use TM.
define void @f4(i64 %a) {
; CHECK-LABEL: f4:
; CHECK-NOT: {{tm[lh].}}
; CHECK: br %r14
entry:
%and = and i64 %a, 4294901759
%cmp = icmp eq i64 %and, 0
br i1 %cmp, label %exit, label %store
store:
store i32 1, i32 *@g
br label %exit
exit:
ret void
}
; Check the high end of the TMLH range.
define void @f5(i64 %a) {
; CHECK-LABEL: f5:
; CHECK: tmlh %r2, 65535
; CHECK: je {{\.L.*}}
; CHECK: br %r14
entry:
%and = and i64 %a, 4294901760
%cmp = icmp eq i64 %and, 0
br i1 %cmp, label %exit, label %store
store:
store i32 1, i32 *@g
br label %exit
exit:
ret void
}
; Check the lowest useful TMHL value.
define void @f6(i64 %a) {
; CHECK-LABEL: f6:
; CHECK: tmhl %r2, 1
; CHECK: je {{\.L.*}}
; CHECK: br %r14
entry:
%and = and i64 %a, 4294967296
%cmp = icmp eq i64 %and, 0
br i1 %cmp, label %exit, label %store
store:
store i32 1, i32 *@g
br label %exit
exit:
ret void
}
; Check the next value up again, which cannot use TM.
define void @f7(i64 %a) {
; CHECK-LABEL: f7:
; CHECK-NOT: {{tm[lh].}}
; CHECK: br %r14
entry:
%and = and i64 %a, 4294967297
%cmp = icmp ne i64 %and, 0
br i1 %cmp, label %exit, label %store
store:
store i32 1, i32 *@g
br label %exit
exit:
ret void
}
; Check the high end of the TMHL range.
define void @f8(i64 %a) {
; CHECK-LABEL: f8:
; CHECK: tmhl %r2, 65535
; CHECK: jne {{\.L.*}}
; CHECK: br %r14
entry:
%and = and i64 %a, 281470681743360
%cmp = icmp ne i64 %and, 0
br i1 %cmp, label %exit, label %store
store:
store i32 1, i32 *@g
br label %exit
exit:
ret void
}
; Check the lowest useful TMHH value.
define void @f9(i64 %a) {
; CHECK-LABEL: f9:
; CHECK: tmhh %r2, 1
; CHECK: jne {{\.L.*}}
; CHECK: br %r14
entry:
%and = and i64 %a, 281474976710656
%cmp = icmp ne i64 %and, 0
br i1 %cmp, label %exit, label %store
store:
store i32 1, i32 *@g
br label %exit
exit:
ret void
}
; Check the high end of the TMHH range.
define void @f10(i64 %a) {
; CHECK-LABEL: f10:
; CHECK: tmhh %r2, 65535
; CHECK: je {{\.L.*}}
; CHECK: br %r14
entry:
%and = and i64 %a, 18446462598732840960
%cmp = icmp eq i64 %and, 0
br i1 %cmp, label %exit, label %store
store:
store i32 1, i32 *@g
br label %exit
exit:
ret void
}

View File

@ -6964,6 +6964,54 @@
# CHECK: sy %r15, 0
0xe3 0xf0 0x00 0x00 0x00 0x5b
# CHECK: tmhh %r0, 0
0xa7 0x02 0x00 0x00
# CHECK: tmhh %r0, 32768
0xa7 0x02 0x80 0x00
# CHECK: tmhh %r0, 65535
0xa7 0x02 0xff 0xff
# CHECK: tmhh %r15, 0
0xa7 0xf2 0x00 0x00
# CHECK: tmhl %r0, 0
0xa7 0x03 0x00 0x00
# CHECK: tmhl %r0, 32768
0xa7 0x03 0x80 0x00
# CHECK: tmhl %r0, 65535
0xa7 0x03 0xff 0xff
# CHECK: tmhl %r15, 0
0xa7 0xf3 0x00 0x00
# CHECK: tmlh %r0, 0
0xa7 0x00 0x00 0x00
# CHECK: tmlh %r0, 32768
0xa7 0x00 0x80 0x00
# CHECK: tmlh %r0, 65535
0xa7 0x00 0xff 0xff
# CHECK: tmlh %r15, 0
0xa7 0xf0 0x00 0x00
# CHECK: tmll %r0, 0
0xa7 0x01 0x00 0x00
# CHECK: tmll %r0, 32768
0xa7 0x01 0x80 0x00
# CHECK: tmll %r0, 65535
0xa7 0x01 0xff 0xff
# CHECK: tmll %r15, 0
0xa7 0xf1 0x00 0x00
# CHECK: xgr %r0, %r0
0xb9 0x82 0x00 0x00

View File

@ -2863,6 +2863,38 @@
sy %r0, -524289
sy %r0, 524288
#CHECK: error: invalid operand
#CHECK: tmhh %r0, -1
#CHECK: error: invalid operand
#CHECK: tmhh %r0, 0x10000
tmhh %r0, -1
tmhh %r0, 0x10000
#CHECK: error: invalid operand
#CHECK: tmhl %r0, -1
#CHECK: error: invalid operand
#CHECK: tmhl %r0, 0x10000
tmhl %r0, -1
tmhl %r0, 0x10000
#CHECK: error: invalid operand
#CHECK: tmlh %r0, -1
#CHECK: error: invalid operand
#CHECK: tmlh %r0, 0x10000
tmlh %r0, -1
tmlh %r0, 0x10000
#CHECK: error: invalid operand
#CHECK: tmll %r0, -1
#CHECK: error: invalid operand
#CHECK: tmll %r0, 0x10000
tmll %r0, -1
tmll %r0, 0x10000
#CHECK: error: invalid operand
#CHECK: x %r0, -1
#CHECK: error: invalid operand

View File

@ -7284,6 +7284,46 @@
sy %r0, 524287(%r15,%r1)
sy %r15, 0
#CHECK: tmhh %r0, 0 # encoding: [0xa7,0x02,0x00,0x00]
#CHECK: tmhh %r0, 32768 # encoding: [0xa7,0x02,0x80,0x00]
#CHECK: tmhh %r0, 65535 # encoding: [0xa7,0x02,0xff,0xff]
#CHECK: tmhh %r15, 0 # encoding: [0xa7,0xf2,0x00,0x00]
tmhh %r0, 0
tmhh %r0, 0x8000
tmhh %r0, 0xffff
tmhh %r15, 0
#CHECK: tmhl %r0, 0 # encoding: [0xa7,0x03,0x00,0x00]
#CHECK: tmhl %r0, 32768 # encoding: [0xa7,0x03,0x80,0x00]
#CHECK: tmhl %r0, 65535 # encoding: [0xa7,0x03,0xff,0xff]
#CHECK: tmhl %r15, 0 # encoding: [0xa7,0xf3,0x00,0x00]
tmhl %r0, 0
tmhl %r0, 0x8000
tmhl %r0, 0xffff
tmhl %r15, 0
#CHECK: tmlh %r0, 0 # encoding: [0xa7,0x00,0x00,0x00]
#CHECK: tmlh %r0, 32768 # encoding: [0xa7,0x00,0x80,0x00]
#CHECK: tmlh %r0, 65535 # encoding: [0xa7,0x00,0xff,0xff]
#CHECK: tmlh %r15, 0 # encoding: [0xa7,0xf0,0x00,0x00]
tmlh %r0, 0
tmlh %r0, 0x8000
tmlh %r0, 0xffff
tmlh %r15, 0
#CHECK: tmll %r0, 0 # encoding: [0xa7,0x01,0x00,0x00]
#CHECK: tmll %r0, 32768 # encoding: [0xa7,0x01,0x80,0x00]
#CHECK: tmll %r0, 65535 # encoding: [0xa7,0x01,0xff,0xff]
#CHECK: tmll %r15, 0 # encoding: [0xa7,0xf1,0x00,0x00]
tmll %r0, 0
tmll %r0, 0x8000
tmll %r0, 0xffff
tmll %r15, 0
#CHECK: x %r0, 0 # encoding: [0x57,0x00,0x00,0x00]
#CHECK: x %r0, 4095 # encoding: [0x57,0x00,0x0f,0xff]
#CHECK: x %r0, 0(%r1) # encoding: [0x57,0x00,0x10,0x00]