Skip to content

Commit

Permalink
[SystemZ] Add support for TMHH, TMHL, TMLH and TMLL
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Richard Sandiford committed Aug 28, 2013
1 parent a6c3a4e commit 4771681
Show file tree
Hide file tree
Showing 11 changed files with 490 additions and 12 deletions.
7 changes: 7 additions & 0 deletions lib/Target/SystemZ/SystemZ.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
61 changes: 51 additions & 10 deletions lib/Target/SystemZ/SystemZISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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;
}

Expand All @@ -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
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 4 additions & 0 deletions lib/Target/SystemZ/SystemZISelLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 13 additions & 0 deletions lib/Target/SystemZ/SystemZInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -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
//===----------------------------------------------------------------------===//
Expand Down
1 change: 1 addition & 0 deletions lib/Target/SystemZ/SystemZOperators.td
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions test/CodeGen/SystemZ/int-cmp-44.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
99 changes: 99 additions & 0 deletions test/CodeGen/SystemZ/int-cmp-46.ll
Original file line number Diff line number Diff line change
@@ -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
}
Loading

0 comments on commit 4771681

Please sign in to comment.