summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Target/SystemZ/SystemZ.h7
-rw-r--r--lib/Target/SystemZ/SystemZISelLowering.cpp61
-rw-r--r--lib/Target/SystemZ/SystemZISelLowering.h4
-rw-r--r--lib/Target/SystemZ/SystemZInstrInfo.td13
-rw-r--r--lib/Target/SystemZ/SystemZOperators.td1
-rw-r--r--test/CodeGen/SystemZ/int-cmp-44.ll4
-rw-r--r--test/CodeGen/SystemZ/int-cmp-46.ll99
-rw-r--r--test/CodeGen/SystemZ/int-cmp-47.ll193
-rw-r--r--test/MC/Disassembler/SystemZ/insns.txt48
-rw-r--r--test/MC/SystemZ/insn-bad.s32
-rw-r--r--test/MC/SystemZ/insn-good.s40
11 files changed, 490 insertions, 12 deletions
diff --git a/lib/Target/SystemZ/SystemZ.h b/lib/Target/SystemZ/SystemZ.h
index ea6c7d17fa..051ba1dcfb 100644
--- a/lib/Target/SystemZ/SystemZ.h
+++ b/lib/Target/SystemZ/SystemZ.h
@@ -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;
diff --git a/lib/Target/SystemZ/SystemZISelLowering.cpp b/lib/Target/SystemZ/SystemZISelLowering.cpp
index dd230c62a5..1ab1ef4aca 100644
--- a/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -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);
diff --git a/lib/Target/SystemZ/SystemZISelLowering.h b/lib/Target/SystemZ/SystemZISelLowering.h
index 9831777873..ec5051f3e6 100644
--- a/lib/Target/SystemZ/SystemZISelLowering.h
+++ b/lib/Target/SystemZ/SystemZISelLowering.h
@@ -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
diff --git a/lib/Target/SystemZ/SystemZInstrInfo.td b/lib/Target/SystemZ/SystemZInstrInfo.td
index 399b48a336..7793818b79 100644
--- a/lib/Target/SystemZ/SystemZInstrInfo.td
+++ b/lib/Target/SystemZ/SystemZInstrInfo.td
@@ -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
//===----------------------------------------------------------------------===//
diff --git a/lib/Target/SystemZ/SystemZOperators.td b/lib/Target/SystemZ/SystemZOperators.td
index ff64ea8fa0..822195c02a 100644
--- a/lib/Target/SystemZ/SystemZOperators.td
+++ b/lib/Target/SystemZ/SystemZOperators.td
@@ -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,
diff --git a/test/CodeGen/SystemZ/int-cmp-44.ll b/test/CodeGen/SystemZ/int-cmp-44.ll
index b94f482f8b..ae0133f108 100644
--- a/test/CodeGen/SystemZ/int-cmp-44.ll
+++ b/test/CodeGen/SystemZ/int-cmp-44.ll
@@ -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
diff --git a/test/CodeGen/SystemZ/int-cmp-46.ll b/test/CodeGen/SystemZ/int-cmp-46.ll
new file mode 100644
index 0000000000..b46ca5e6d1
--- /dev/null
+++ b/test/CodeGen/SystemZ/int-cmp-46.ll
@@ -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
+}
diff --git a/test/CodeGen/SystemZ/int-cmp-47.ll b/test/CodeGen/SystemZ/int-cmp-47.ll
new file mode 100644
index 0000000000..bf206ed9db
--- /dev/null
+++ b/test/CodeGen/SystemZ/int-cmp-47.ll
@@ -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
+}
diff --git a/test/MC/Disassembler/SystemZ/insns.txt b/test/MC/Disassembler/SystemZ/insns.txt
index 360785e94b..912837c9a6 100644
--- a/test/MC/Disassembler/SystemZ/insns.txt
+++ b/test/MC/Disassembler/SystemZ/insns.txt
@@ -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
diff --git a/test/MC/SystemZ/insn-bad.s b/test/MC/SystemZ/insn-bad.s
index 1c478caa03..54979fdaf9 100644
--- a/test/MC/SystemZ/insn-bad.s
+++ b/test/MC/SystemZ/insn-bad.s
@@ -2864,6 +2864,38 @@
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
#CHECK: x %r0, 4096
diff --git a/test/MC/SystemZ/insn-good.s b/test/MC/SystemZ/insn-good.s
index 9930d8ce6d..be7e308549 100644
--- a/test/MC/SystemZ/insn-good.s
+++ b/test/MC/SystemZ/insn-good.s
@@ -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]