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;
// 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;
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);
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;
}
(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
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);
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);
OPCODE(PCREL_WRAPPER);
OPCODE(CMP);
OPCODE(UCMP);
+ OPCODE(TM);
OPCODE(BR_CCMASK);
OPCODE(SELECT_CCMASK);
OPCODE(ADJDYNALLOC);
// 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
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
//===----------------------------------------------------------------------===//
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,
; 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
--- /dev/null
+; 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
+}
--- /dev/null
+; 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
+}
# 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
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
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]