6814842: Load shortening optimizations
authortwisti
Wed, 13 May 2009 00:45:22 -0700
changeset 2872 93eb5ac6cfb0
parent 2871 519e22b6900d
child 2873 96526fe40c0e
6814842: Load shortening optimizations Summary: 6797305 handles load widening but no shortening which should be covered here. Reviewed-by: never, kvn
hotspot/src/cpu/sparc/vm/sparc.ad
hotspot/src/cpu/x86/vm/x86_32.ad
hotspot/src/cpu/x86/vm/x86_64.ad
hotspot/src/share/vm/adlc/output_c.cpp
hotspot/test/compiler/6814842/Test6814842.java
--- a/hotspot/src/cpu/sparc/vm/sparc.ad	Mon May 11 18:30:13 2009 -0700
+++ b/hotspot/src/cpu/sparc/vm/sparc.ad	Wed May 13 00:45:22 2009 -0700
@@ -1891,15 +1891,17 @@
 // The intptr_t operand types, defined by textual substitution.
 // (Cf. opto/type.hpp.  This lets us avoid many, many other ifdefs.)
 #ifdef _LP64
-#define immX    immL
-#define immX13  immL13
-#define iRegX   iRegL
-#define g1RegX  g1RegL
+#define immX     immL
+#define immX13   immL13
+#define immX13m7 immL13m7
+#define iRegX    iRegL
+#define g1RegX   g1RegL
 #else
-#define immX    immI
-#define immX13  immI13
-#define iRegX   iRegI
-#define g1RegX  g1RegI
+#define immX     immI
+#define immX13   immI13
+#define immX13m7 immI13m7
+#define iRegX    iRegI
+#define g1RegX   g1RegI
 #endif
 
 //----------ENCODING BLOCK-----------------------------------------------------
@@ -3454,6 +3456,16 @@
   interface(CONST_INTER);
 %}
 
+// Integer Immediate: 13-bit minus 7
+operand immI13m7() %{
+  predicate((-4096 < n->get_int()) && ((n->get_int() + 7) <= 4095));
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
 // Unsigned (positive) Integer Immediate: 13-bit
 operand immU13() %{
   predicate((0 <= n->get_int()) && Assembler::is_simm13(n->get_int()));
@@ -3532,6 +3544,28 @@
   interface(CONST_INTER);
 %}
 
+// Immediates for special shifts (sign extend)
+
+// Integer Immediate: the value 16
+operand immI_16() %{
+  predicate(n->get_int() == 16);
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
+// Integer Immediate: the value 24
+operand immI_24() %{
+  predicate(n->get_int() == 24);
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
 // Integer Immediate: the value 255
 operand immI_255() %{
   predicate( n->get_int() == 255 );
@@ -3542,6 +3576,16 @@
   interface(CONST_INTER);
 %}
 
+// Integer Immediate: the value 65535
+operand immI_65535() %{
+  predicate(n->get_int() == 65535);
+  match(ConI);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
 // Long Immediate: the value FF
 operand immL_FF() %{
   predicate( n->get_long() == 0xFFL );
@@ -3647,6 +3691,16 @@
   interface(CONST_INTER);
 %}
 
+// Long Immediate: 13-bit minus 7
+operand immL13m7() %{
+  predicate((-4096L < n->get_long()) && ((n->get_long() + 7L) <= 4095L));
+  match(ConL);
+  op_cost(0);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
 // Long Immediate: low 32-bit mask
 operand immL_32bits() %{
   predicate(n->get_long() == 0xFFFFFFFFL);
@@ -4084,7 +4138,7 @@
   %}
 %}
 
-// Indirect with Offset
+// Indirect with simm13 Offset
 operand indOffset13(sp_ptr_RegP reg, immX13 offset) %{
   constraint(ALLOC_IN_RC(sp_ptr_reg));
   match(AddP reg offset);
@@ -4099,6 +4153,21 @@
   %}
 %}
 
+// Indirect with simm13 Offset minus 7
+operand indOffset13m7(sp_ptr_RegP reg, immX13m7 offset) %{
+  constraint(ALLOC_IN_RC(sp_ptr_reg));
+  match(AddP reg offset);
+
+  op_cost(100);
+  format %{ "[$reg + $offset]" %}
+  interface(MEMORY_INTER) %{
+    base($reg);
+    index(0x0);
+    scale(0x0);
+    disp($offset);
+  %}
+%}
+
 // Note:  Intel has a swapped version also, like this:
 //operand indOffsetX(iRegI reg, immP offset) %{
 //  constraint(ALLOC_IN_RC(int_reg));
@@ -5504,6 +5573,20 @@
   ins_pipe(iload_mask_mem);
 %}
 
+// Load Short (16 bit signed) to Byte (8 bit signed)
+instruct loadS2B(iRegI dst, indOffset13m7 mem, immI_24 twentyfour) %{
+  match(Set dst (RShiftI (LShiftI (LoadS mem) twentyfour) twentyfour));
+  ins_cost(MEMORY_REF_COST);
+
+  size(4);
+
+  format %{ "LDSB   $mem+1,$dst\t! short -> byte" %}
+  ins_encode %{
+    __ ldsb($mem$$Address, $dst$$Register, 1);
+  %}
+  ins_pipe(iload_mask_mem);
+%}
+
 // Load Short (16bit signed) into a Long Register
 instruct loadS2L(iRegL dst, memory mem) %{
   match(Set dst (ConvI2L (LoadS mem)));
@@ -5530,6 +5613,19 @@
   ins_pipe(iload_mask_mem);
 %}
 
+// Load Unsigned Short/Char (16 bit UNsigned) to Byte (8 bit signed)
+instruct loadUS2B(iRegI dst, indOffset13m7 mem, immI_24 twentyfour) %{
+  match(Set dst (RShiftI (LShiftI (LoadUS mem) twentyfour) twentyfour));
+  ins_cost(MEMORY_REF_COST);
+
+  size(4);
+  format %{ "LDSB   $mem+1,$dst\t! ushort -> byte" %}
+  ins_encode %{
+    __ ldsb($mem$$Address, $dst$$Register, 1);
+  %}
+  ins_pipe(iload_mask_mem);
+%}
+
 // Load Unsigned Short/Char (16bit UNsigned) into a Long Register
 instruct loadUS2L(iRegL dst, memory mem) %{
   match(Set dst (ConvI2L (LoadUS mem)));
@@ -5556,6 +5652,62 @@
   ins_pipe(iload_mem);
 %}
 
+// Load Integer to Byte (8 bit signed)
+instruct loadI2B(iRegI dst, indOffset13m7 mem, immI_24 twentyfour) %{
+  match(Set dst (RShiftI (LShiftI (LoadI mem) twentyfour) twentyfour));
+  ins_cost(MEMORY_REF_COST);
+
+  size(4);
+
+  format %{ "LDSB   $mem+3,$dst\t! int -> byte" %}
+  ins_encode %{
+    __ ldsb($mem$$Address, $dst$$Register, 3);
+  %}
+  ins_pipe(iload_mask_mem);
+%}
+
+// Load Integer to Unsigned Byte (8 bit UNsigned)
+instruct loadI2UB(iRegI dst, indOffset13m7 mem, immI_255 mask) %{
+  match(Set dst (AndI (LoadI mem) mask));
+  ins_cost(MEMORY_REF_COST);
+
+  size(4);
+
+  format %{ "LDUB   $mem+3,$dst\t! int -> ubyte" %}
+  ins_encode %{
+    __ ldub($mem$$Address, $dst$$Register, 3);
+  %}
+  ins_pipe(iload_mask_mem);
+%}
+
+// Load Integer to Short (16 bit signed)
+instruct loadI2S(iRegI dst, indOffset13m7 mem, immI_16 sixteen) %{
+  match(Set dst (RShiftI (LShiftI (LoadI mem) sixteen) sixteen));
+  ins_cost(MEMORY_REF_COST);
+
+  size(4);
+
+  format %{ "LDSH   $mem+2,$dst\t! int -> short" %}
+  ins_encode %{
+    __ ldsh($mem$$Address, $dst$$Register, 2);
+  %}
+  ins_pipe(iload_mask_mem);
+%}
+
+// Load Integer to Unsigned Short (16 bit UNsigned)
+instruct loadI2US(iRegI dst, indOffset13m7 mem, immI_65535 mask) %{
+  match(Set dst (AndI (LoadI mem) mask));
+  ins_cost(MEMORY_REF_COST);
+
+  size(4);
+
+  format %{ "LDUH   $mem+2,$dst\t! int -> ushort/char" %}
+  ins_encode %{
+    __ lduh($mem$$Address, $dst$$Register, 2);
+  %}
+  ins_pipe(iload_mask_mem);
+%}
+
 // Load Integer into a Long Register
 instruct loadI2L(iRegL dst, memory mem) %{
   match(Set dst (ConvI2L (LoadI mem)));
--- a/hotspot/src/cpu/x86/vm/x86_32.ad	Mon May 11 18:30:13 2009 -0700
+++ b/hotspot/src/cpu/x86/vm/x86_32.ad	Wed May 13 00:45:22 2009 -0700
@@ -5240,6 +5240,15 @@
   interface(CONST_INTER);
 %}
 
+// Constant for short-wide masking
+operand immI_65535() %{
+  predicate(n->get_int() == 65535);
+  match(ConI);
+
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
 // Register Operands
 // Integer Register
 operand eRegI() %{
@@ -6938,6 +6947,18 @@
   ins_pipe(ialu_reg_mem);
 %}
 
+// Load Short (16 bit signed) to Byte (8 bit signed)
+instruct loadS2B(eRegI dst, memory mem, immI_24 twentyfour) %{
+  match(Set dst (RShiftI (LShiftI (LoadS mem) twentyfour) twentyfour));
+
+  ins_cost(125);
+  format %{ "MOVSX  $dst, $mem\t# short -> byte" %}
+  ins_encode %{
+    __ movsbl($dst$$Register, $mem$$Address);
+  %}
+  ins_pipe(ialu_reg_mem);
+%}
+
 // Load Short (16bit signed) into Long Register
 instruct loadS2L(eRegL dst, memory mem) %{
   match(Set dst (ConvI2L (LoadS mem)));
@@ -6970,9 +6991,20 @@
   ins_pipe(ialu_reg_mem);
 %}
 
+// Load Unsigned Short/Char (16 bit UNsigned) to Byte (8 bit signed)
+instruct loadUS2B(eRegI dst, memory mem, immI_24 twentyfour) %{
+  match(Set dst (RShiftI (LShiftI (LoadUS mem) twentyfour) twentyfour));
+
+  ins_cost(125);
+  format %{ "MOVSX  $dst, $mem\t# ushort -> byte" %}
+  ins_encode %{
+    __ movsbl($dst$$Register, $mem$$Address);
+  %}
+  ins_pipe(ialu_reg_mem);
+%}
+
 // Load Unsigned Short/Char (16 bit UNsigned) into Long Register
-instruct loadUS2L(eRegL dst, memory mem)
-%{
+instruct loadUS2L(eRegL dst, memory mem) %{
   match(Set dst (ConvI2L (LoadUS mem)));
 
   ins_cost(250);
@@ -7001,6 +7033,54 @@
   ins_pipe(ialu_reg_mem);
 %}
 
+// Load Integer (32 bit signed) to Byte (8 bit signed)
+instruct loadI2B(eRegI dst, memory mem, immI_24 twentyfour) %{
+  match(Set dst (RShiftI (LShiftI (LoadI mem) twentyfour) twentyfour));
+
+  ins_cost(125);
+  format %{ "MOVSX  $dst, $mem\t# int -> byte" %}
+  ins_encode %{
+    __ movsbl($dst$$Register, $mem$$Address);
+  %}
+  ins_pipe(ialu_reg_mem);
+%}
+
+// Load Integer (32 bit signed) to Unsigned Byte (8 bit UNsigned)
+instruct loadI2UB(eRegI dst, memory mem, immI_255 mask) %{
+  match(Set dst (AndI (LoadI mem) mask));
+
+  ins_cost(125);
+  format %{ "MOVZX  $dst, $mem\t# int -> ubyte" %}
+  ins_encode %{
+    __ movzbl($dst$$Register, $mem$$Address);
+  %}
+  ins_pipe(ialu_reg_mem);
+%}
+
+// Load Integer (32 bit signed) to Short (16 bit signed)
+instruct loadI2S(eRegI dst, memory mem, immI_16 sixteen) %{
+  match(Set dst (RShiftI (LShiftI (LoadI mem) sixteen) sixteen));
+
+  ins_cost(125);
+  format %{ "MOVSX  $dst, $mem\t# int -> short" %}
+  ins_encode %{
+    __ movswl($dst$$Register, $mem$$Address);
+  %}
+  ins_pipe(ialu_reg_mem);
+%}
+
+// Load Integer (32 bit signed) to Unsigned Short/Char (16 bit UNsigned)
+instruct loadI2US(eRegI dst, memory mem, immI_65535 mask) %{
+  match(Set dst (AndI (LoadI mem) mask));
+
+  ins_cost(125);
+  format %{ "MOVZX  $dst, $mem\t# int -> ushort/char" %}
+  ins_encode %{
+    __ movzwl($dst$$Register, $mem$$Address);
+  %}
+  ins_pipe(ialu_reg_mem);
+%}
+
 // Load Integer into Long Register
 instruct loadI2L(eRegL dst, memory mem) %{
   match(Set dst (ConvI2L (LoadI mem)));
@@ -9034,28 +9114,28 @@
 
 // Logical Shift Right by 24, followed by Arithmetic Shift Left by 24.
 // This idiom is used by the compiler for the i2b bytecode.
-instruct i2b(eRegI dst, xRegI src, immI_24 twentyfour, eFlagsReg cr) %{
+instruct i2b(eRegI dst, xRegI src, immI_24 twentyfour) %{
   match(Set dst (RShiftI (LShiftI src twentyfour) twentyfour));
-  effect(KILL cr);
 
   size(3);
   format %{ "MOVSX  $dst,$src :8" %}
-  opcode(0xBE, 0x0F);
-  ins_encode( OpcS, OpcP, RegReg( dst, src));
-  ins_pipe( ialu_reg_reg );
+  ins_encode %{
+    __ movsbl($dst$$Register, $src$$Register);
+  %}
+  ins_pipe(ialu_reg_reg);
 %}
 
 // Logical Shift Right by 16, followed by Arithmetic Shift Left by 16.
 // This idiom is used by the compiler the i2s bytecode.
-instruct i2s(eRegI dst, xRegI src, immI_16 sixteen, eFlagsReg cr) %{
+instruct i2s(eRegI dst, xRegI src, immI_16 sixteen) %{
   match(Set dst (RShiftI (LShiftI src sixteen) sixteen));
-  effect(KILL cr);
 
   size(3);
   format %{ "MOVSX  $dst,$src :16" %}
-  opcode(0xBF, 0x0F);
-  ins_encode( OpcS, OpcP, RegReg( dst, src));
-  ins_pipe( ialu_reg_reg );
+  ins_encode %{
+    __ movswl($dst$$Register, $src$$Register);
+  %}
+  ins_pipe(ialu_reg_reg);
 %}
 
 
--- a/hotspot/src/cpu/x86/vm/x86_64.ad	Mon May 11 18:30:13 2009 -0700
+++ b/hotspot/src/cpu/x86/vm/x86_64.ad	Wed May 13 00:45:22 2009 -0700
@@ -6459,6 +6459,18 @@
   ins_pipe(ialu_reg_mem);
 %}
 
+// Load Short (16 bit signed) to Byte (8 bit signed)
+instruct loadS2B(rRegI dst, memory mem, immI_24 twentyfour) %{
+  match(Set dst (RShiftI (LShiftI (LoadS mem) twentyfour) twentyfour));
+
+  ins_cost(125);
+  format %{ "movsbl $dst, $mem\t# short -> byte" %}
+  ins_encode %{
+    __ movsbl($dst$$Register, $mem$$Address);
+  %}
+  ins_pipe(ialu_reg_mem);
+%}
+
 // Load Short (16 bit signed) into Long Register
 instruct loadS2L(rRegL dst, memory mem)
 %{
@@ -6489,6 +6501,18 @@
   ins_pipe(ialu_reg_mem);
 %}
 
+// Load Unsigned Short/Char (16 bit UNsigned) to Byte (8 bit signed)
+instruct loadUS2B(rRegI dst, memory mem, immI_24 twentyfour) %{
+  match(Set dst (RShiftI (LShiftI (LoadUS mem) twentyfour) twentyfour));
+
+  ins_cost(125);
+  format %{ "movsbl $dst, $mem\t# ushort -> byte" %}
+  ins_encode %{
+    __ movsbl($dst$$Register, $mem$$Address);
+  %}
+  ins_pipe(ialu_reg_mem);
+%}
+
 // Load Unsigned Short/Char (16 bit UNsigned) into Long Register
 instruct loadUS2L(rRegL dst, memory mem)
 %{
@@ -6519,6 +6543,54 @@
   ins_pipe(ialu_reg_mem);
 %}
 
+// Load Integer (32 bit signed) to Byte (8 bit signed)
+instruct loadI2B(rRegI dst, memory mem, immI_24 twentyfour) %{
+  match(Set dst (RShiftI (LShiftI (LoadI mem) twentyfour) twentyfour));
+
+  ins_cost(125);
+  format %{ "movsbl  $dst, $mem\t# int -> byte" %}
+  ins_encode %{
+    __ movsbl($dst$$Register, $mem$$Address);
+  %}
+  ins_pipe(ialu_reg_mem);
+%}
+
+// Load Integer (32 bit signed) to Unsigned Byte (8 bit UNsigned)
+instruct loadI2UB(rRegI dst, memory mem, immI_255 mask) %{
+  match(Set dst (AndI (LoadI mem) mask));
+
+  ins_cost(125);
+  format %{ "movzbl  $dst, $mem\t# int -> ubyte" %}
+  ins_encode %{
+    __ movzbl($dst$$Register, $mem$$Address);
+  %}
+  ins_pipe(ialu_reg_mem);
+%}
+
+// Load Integer (32 bit signed) to Short (16 bit signed)
+instruct loadI2S(rRegI dst, memory mem, immI_16 sixteen) %{
+  match(Set dst (RShiftI (LShiftI (LoadI mem) sixteen) sixteen));
+
+  ins_cost(125);
+  format %{ "movswl  $dst, $mem\t# int -> short" %}
+  ins_encode %{
+    __ movswl($dst$$Register, $mem$$Address);
+  %}
+  ins_pipe(ialu_reg_mem);
+%}
+
+// Load Integer (32 bit signed) to Unsigned Short/Char (16 bit UNsigned)
+instruct loadI2US(rRegI dst, memory mem, immI_65535 mask) %{
+  match(Set dst (AndI (LoadI mem) mask));
+
+  ins_cost(125);
+  format %{ "movzwl  $dst, $mem\t# int -> ushort/char" %}
+  ins_encode %{
+    __ movzwl($dst$$Register, $mem$$Address);
+  %}
+  ins_pipe(ialu_reg_mem);
+%}
+
 // Load Integer into Long Register
 instruct loadI2L(rRegL dst, memory mem)
 %{
--- a/hotspot/src/share/vm/adlc/output_c.cpp	Mon May 11 18:30:13 2009 -0700
+++ b/hotspot/src/share/vm/adlc/output_c.cpp	Wed May 13 00:45:22 2009 -0700
@@ -1745,6 +1745,7 @@
       fprintf(fp,"    del_req(i);\n");
       fprintf(fp,"  }\n");
       fprintf(fp,"  _num_opnds = %d;\n", new_num_opnds);
+      assert(new_num_opnds == node->num_unique_opnds(), "what?");
     }
   }
 
@@ -3761,6 +3762,12 @@
     if ( this->captures_bottom_type() ) {
       fprintf(fp_cpp, "  node->_bottom_type = bottom_type();\n");
     }
+
+    uint cur_num_opnds = num_opnds();
+    if (cur_num_opnds > 1 && cur_num_opnds != num_unique_opnds()) {
+      fprintf(fp_cpp,"  node->_num_opnds = %d;\n", num_unique_opnds());
+    }
+
     fprintf(fp_cpp, "\n");
     fprintf(fp_cpp, "  // Copy _idx, inputs and operands to new node\n");
     fprintf(fp_cpp, "  fill_new_machnode(node, C);\n");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/6814842/Test6814842.java	Wed May 13 00:45:22 2009 -0700
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**
+ * @test
+ * @bug 6814842
+ * @summary Load shortening optimizations
+ *
+ * @run main/othervm -Xcomp -XX:CompileOnly=Test6814842.loadS2B,Test6814842.loadS2Bmask255,Test6814842.loadUS2B,Test6814842.loadUS2Bmask255,Test6814842.loadI2B,Test6814842.loadI2Bmask255,Test6814842.loadI2S,Test6814842.loadI2Smask255,Test6814842.loadI2Smask65535,Test6814842.loadI2US,Test6814842.loadI2USmask255,Test6814842.loadI2USmask65535 Test6814842
+ */
+
+public class Test6814842 {
+    static final short[] sa = new short[] { (short) 0xF1F2 };
+    static final char[]  ca = new char[]  { (char) 0xF3F4  };
+    static final int[]   ia = new int[]   { 0xF1F2F3F4     };
+
+    public static void main(String[] args)
+    {
+        byte s2b = loadS2B(sa);
+        if (s2b != (byte) 0xF2)
+            throw new InternalError("loadS2B failed: " + s2b + " != " + (byte) 0xF2);
+
+        byte s2bmask255 = loadS2Bmask255(sa);
+        if (s2bmask255 != (byte) 0xF2)
+            throw new InternalError("loadS2Bmask255 failed: " + s2bmask255 + " != " + (byte) 0xF2);
+
+        byte us2b = loadUS2B(ca);
+        if (us2b != (byte) 0xF4)
+            throw new InternalError("loadUS2B failed: " + us2b + " != " + (byte) 0xF4);
+
+        byte us2bmask255 = loadUS2Bmask255(ca);
+        if (us2bmask255 != (byte) 0xF4)
+            throw new InternalError("loadUS2Bmask255 failed: " + us2bmask255 + " != " + (byte) 0xF4);
+
+        byte i2b = loadI2B(ia);
+        if (i2b != (byte) 0xF4)
+            throw new InternalError("loadI2B failed: " + i2b + " != " + (byte) 0xF4);
+
+        byte i2bmask255 = loadI2Bmask255(ia);
+        if (i2bmask255 != (byte) 0xF4)
+            throw new InternalError("loadI2Bmask255 failed: " + i2bmask255 + " != " + (byte) 0xF4);
+
+        short i2s = loadI2S(ia);
+        if (i2s != (short) 0xF3F4)
+            throw new InternalError("loadI2S failed: " + i2s + " != " + (short) 0xF3F4);
+
+        short i2smask255 = loadI2Smask255(ia);
+        if (i2smask255 != (short) 0xF4)
+            throw new InternalError("loadI2Smask255 failed: " + i2smask255 + " != " + (short) 0xF4);
+
+        short i2smask65535 = loadI2Smask65535(ia);
+        if (i2smask65535 != (short) 0xF3F4)
+            throw new InternalError("loadI2Smask65535 failed: " + i2smask65535 + " != " + (short) 0xF3F4);
+
+        char i2us = loadI2US(ia);
+        if (i2us != (char) 0xF3F4)
+            throw new InternalError("loadI2US failed: " + (int) i2us + " != " + (char) 0xF3F4);
+
+        char i2usmask255 = loadI2USmask255(ia);
+        if (i2usmask255 != (char) 0xF4)
+            throw new InternalError("loadI2USmask255 failed: " + (int) i2usmask255 + " != " + (char) 0xF4);
+
+        char i2usmask65535 = loadI2USmask65535(ia);
+        if (i2usmask65535 != (char) 0xF3F4)
+            throw new InternalError("loadI2USmask65535 failed: " + (int) i2usmask65535 + " != " + (char) 0xF3F4);
+    }
+
+    static byte  loadS2B          (short[] sa) { return (byte)  (sa[0]         ); }
+    static byte  loadS2Bmask255   (short[] sa) { return (byte)  (sa[0] & 0xFF  ); }
+
+    static byte  loadUS2B         (char[]  ca) { return (byte)  (ca[0]         ); }
+    static byte  loadUS2Bmask255  (char[]  ca) { return (byte)  (ca[0] & 0xFF  ); }
+
+    static byte  loadI2B          (int[]   ia) { return (byte)  (ia[0]         ); }
+    static byte  loadI2Bmask255   (int[]   ia) { return (byte)  (ia[0] & 0xFF  ); }
+
+    static short loadI2S          (int[]   ia) { return (short) (ia[0]         ); }
+    static short loadI2Smask255   (int[]   ia) { return (short) (ia[0] & 0xFF  ); }
+    static short loadI2Smask65535 (int[]   ia) { return (short) (ia[0] & 0xFFFF); }
+
+    static char  loadI2US         (int[]   ia) { return (char)  (ia[0]         ); }
+    static char  loadI2USmask255  (int[]   ia) { return (char)  (ia[0] & 0xFF  ); }
+    static char  loadI2USmask65535(int[]   ia) { return (char)  (ia[0] & 0xFFFF); }
+}