[SystemZ] Add support for TMHH, TMHL, TMLH and TMLL
authorRichard Sandiford <rsandifo@linux.vnet.ibm.com>
Wed, 28 Aug 2013 10:31:43 +0000 (10:31 +0000)
committerRichard Sandiford <rsandifo@linux.vnet.ibm.com>
Wed, 28 Aug 2013 10:31:43 +0000 (10:31 +0000)
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

lib/Target/SystemZ/SystemZ.h
lib/Target/SystemZ/SystemZISelLowering.cpp
lib/Target/SystemZ/SystemZISelLowering.h
lib/Target/SystemZ/SystemZInstrInfo.td
lib/Target/SystemZ/SystemZOperators.td
test/CodeGen/SystemZ/int-cmp-44.ll
test/CodeGen/SystemZ/int-cmp-46.ll [new file with mode: 0644]
test/CodeGen/SystemZ/int-cmp-47.ll [new file with mode: 0644]
test/MC/Disassembler/SystemZ/insns.txt
test/MC/SystemZ/insn-bad.s
test/MC/SystemZ/insn-good.s

index ea6c7d17fa5bf65c118dc982d5a59a373b6e5823..051ba1dcfb661e62cfabcdcbf82e15aa690dc623 100644 (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;
index dd230c62a5a872f404e566236fb053ee6b124c8e..1ab1ef4acaf3649ad6f59402f339a5161e22f4e2 100644 (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);
index 9831777873a151118481ce190522dcd596e3a971..ec5051f3e6e95c0e9cf209ba4eaa1ba6703165af 100644 (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
index 399b48a3368a6d393fd69f08cb7135b6d06e2bc4..7793818b7968685e1b1f7b7d3c73b80fc11a0cee 100644 (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
 //===----------------------------------------------------------------------===//
index ff64ea8fa0b2d6c021af07bdf9f73a4a5d3286fb..822195c02a5e653d561b50215cf50587196b184e 100644 (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,
index b94f482f8b32340cbe165b73d274a6d93c17a877..ae0133f10860d3d7a121933ce3978900cf6dce52 100644 (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
 
diff --git a/test/CodeGen/SystemZ/int-cmp-46.ll b/test/CodeGen/SystemZ/int-cmp-46.ll
new file mode 100644 (file)
index 0000000..b46ca5e
--- /dev/null
@@ -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 (file)
index 0000000..bf206ed
--- /dev/null
@@ -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
+}
index 360785e94baaae370e2ceaf24b796824476798e7..912837c9a6020b2655daf8419167c70d765fb14d 100644 (file)
 # 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
 
index 1c478caa0378c63cc900cdc88060d73ffa5ca479..54979fdaf9128e458cde74acba5f72df4aee9dfe 100644 (file)
        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
index 9930d8ce6d1ed22a52d02ba11db073640af1a9ba..be7e3085496e6b3813e75e89fa6f39461bdbf4f7 100644 (file)
        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]