src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64BaseAssembler.java
changeset 52578 7dd81e82d083
parent 51736 42d99cb7f50f
child 52910 583fd71c47d6
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64BaseAssembler.java	Thu Nov 15 21:05:47 2018 +0100
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64BaseAssembler.java	Thu Nov 15 09:04:07 2018 -0800
@@ -59,6 +59,7 @@
 import jdk.vm.ci.amd64.AMD64.CPUFeature;
 import jdk.vm.ci.amd64.AMD64Kind;
 import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.Register.RegisterCategory;
 import jdk.vm.ci.code.TargetDescription;
 import jdk.vm.ci.meta.PlatformKind;
 
@@ -269,8 +270,12 @@
         return ((AMD64) target.arch).getFeatures().contains(feature);
     }
 
+    protected static boolean inRC(RegisterCategory rc, Register r) {
+        return r.getRegisterCategory().equals(rc);
+    }
+
     protected static int encode(Register r) {
-        assert r.encoding >= 0 && (r.getRegisterCategory().equals(XMM) ? r.encoding < 32 : r.encoding < 16) : "encoding out of range: " + r.encoding;
+        assert r.encoding >= 0 && (inRC(XMM, r) ? r.encoding < 32 : r.encoding < 16) : "encoding out of range: " + r.encoding;
         return r.encoding & 0x7;
     }
 
@@ -296,6 +301,10 @@
         private static final int REXWRB = 0x4D;
         private static final int REXWRX = 0x4E;
         private static final int REXWRXB = 0x4F;
+
+        private static final int VEX2 = 0xC5;
+        private static final int VEX3 = 0xC4;
+        private static final int EVEX = 0x62;
     }
 
     protected final void rexw() {
@@ -797,12 +806,17 @@
 
         @Override
         public void simdPrefix(Register reg, Register nds, AMD64Address rm, int sizePrefix, int opcodeEscapePrefix, boolean isRexW) {
-            emitVEX(L128, sizePrefixToPP(sizePrefix), opcodeEscapePrefixToMMMMM(opcodeEscapePrefix), isRexW ? W1 : W0, getRXB(reg, rm), nds.isValid() ? nds.encoding : 0);
+            assert reg.encoding < 16 : "encoding out of range: " + reg.encoding;
+            assert nds.encoding < 16 : "encoding out of range: " + nds.encoding;
+            emitVEX(L128, sizePrefixToPP(sizePrefix), opcodeEscapePrefixToMMMMM(opcodeEscapePrefix), isRexW ? W1 : W0, getRXB(reg, rm), nds.isValid() ? nds.encoding : 0, true);
         }
 
         @Override
         public void simdPrefix(Register dst, Register nds, Register src, int sizePrefix, int opcodeEscapePrefix, boolean isRexW) {
-            emitVEX(L128, sizePrefixToPP(sizePrefix), opcodeEscapePrefixToMMMMM(opcodeEscapePrefix), isRexW ? W1 : W0, getRXB(dst, src), nds.isValid() ? nds.encoding : 0);
+            assert dst.encoding < 16 : "encoding out of range: " + dst.encoding;
+            assert src.encoding < 16 : "encoding out of range: " + src.encoding;
+            assert nds.encoding < 16 : "encoding out of range: " + nds.encoding;
+            emitVEX(L128, sizePrefixToPP(sizePrefix), opcodeEscapePrefixToMMMMM(opcodeEscapePrefix), isRexW ? W1 : W0, getRXB(dst, src), nds.isValid() ? nds.encoding : 0, true);
         }
     }
 
@@ -822,6 +836,46 @@
         simdEncoder.simdPrefix(dst, nds, src, size.sizePrefix, opcodeEscapePrefix, isRexW);
     }
 
+ // @formatter:off
+ //
+ // Instruction Format and VEX illustrated below (optional []):
+ //
+ // #of bytes:    2,3      1       1       1       1,2,4       1
+ // [Prefixes]    VEX   OpCode   ModR/M  [SIB]   [Disp8*N] [Immediate]
+ //                                             [Disp16,32]
+ //
+ // VEX: 0xC4 | P1 | P2
+ //
+ //     7   6   5   4   3   2   1   0
+ // P1  R   X   B   m   m   m   m   m      P[ 7:0]
+ // P2  W   v   v   v   v   L   p   p      P[15:8]
+ //
+ // VEX: 0xC5 | B1
+ //
+ //     7   6   5   4   3   2   1   0
+ // P1  R   v   v   v   v   L   p   p      P[7:0]
+ //
+ // Figure. Bit Field Layout of the VEX Prefix
+ //
+ // Table. VEX Prefix Bit Field Functional Grouping
+ //
+ // Notation        Bit field Group        Position        Comment
+ // ----------  -------------------------  --------  -------------------
+ // VEX.RXB     Next-8 register specifier  P[7:5]    Combine with ModR/M.reg, ModR/M.rm (base, index/vidx).
+ // VEX.R       REX.R inverse              P[7]      Combine with EVEX.R and ModR/M.reg.
+ // VEX.X       REX.X inverse              P[6]      Combine with EVEX.B and ModR/M.rm, when SIB/VSIB absent.
+ // VEX.B       REX.B inverse              P[5]
+ // VEX.mmmmmm  0F, 0F_38, 0F_3A encoding  P[4:0]    b01/0x0F, b10/0F_38, b11/0F_3A (all other reserved)
+ //
+ // VEX.W       Opcode specific            P[15]
+ // VEX.vvvv    A register specifier       P[14:11]  In inverse form, b1111 if not used.
+ //                                        P[6:3]
+ // VEX.L       Vector length/RC           P[10]     b0/scalar or 128b vec, b1/256b vec.
+ //                                        P[2]
+ // VEX.pp      Compressed legacy prefix   P[9:8]    b00/None, b01/0x66, b10/0xF3, b11/0xF2
+ //                                        P[1:0]
+ // @formatter:on
+
     /**
      * Low-level function to encode and emit the VEX prefix.
      * <p>
@@ -846,8 +900,8 @@
      * This function automatically chooses the 2 or 3 byte encoding, based on the XBW flags and the
      * m-mmmm field.
      */
-    protected final void emitVEX(int l, int pp, int mmmmm, int w, int rxb, int vvvv) {
-        assert ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX) : "emitting VEX prefix on a CPU without AVX support";
+    protected final void emitVEX(int l, int pp, int mmmmm, int w, int rxb, int vvvv, boolean checkAVX) {
+        assert !checkAVX || ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX) : "emitting VEX prefix on a CPU without AVX support";
 
         assert l == L128 || l == L256 : "invalid value for VEX.L";
         assert pp == P_ || pp == P_66 || pp == P_F3 || pp == P_F2 : "invalid value for VEX.pp";
@@ -867,7 +921,7 @@
             byte2 |= l << 2;
             byte2 |= pp;
 
-            emitByte(0xC5);
+            emitByte(Prefix.VEX2);
             emitByte(byte2);
         } else {
             // 3 byte encoding
@@ -881,7 +935,7 @@
             byte3 |= l << 2;
             byte3 |= pp;
 
-            emitByte(0xC4);
+            emitByte(Prefix.VEX3);
             emitByte(byte2);
             emitByte(byte3);
         }
@@ -900,12 +954,12 @@
         }
     }
 
-    public final void vexPrefix(Register dst, Register nds, Register src, AVXSize size, int pp, int mmmmm, int w) {
-        emitVEX(getLFlag(size), pp, mmmmm, w, getRXB(dst, src), nds.isValid() ? nds.encoding() : 0);
+    public final void vexPrefix(Register dst, Register nds, Register src, AVXSize size, int pp, int mmmmm, int w, boolean checkAVX) {
+        emitVEX(getLFlag(size), pp, mmmmm, w, getRXB(dst, src), nds.isValid() ? nds.encoding() : 0, checkAVX);
     }
 
-    public final void vexPrefix(Register dst, Register nds, AMD64Address src, AVXSize size, int pp, int mmmmm, int w) {
-        emitVEX(getLFlag(size), pp, mmmmm, w, getRXB(dst, src), nds.isValid() ? nds.encoding() : 0);
+    public final void vexPrefix(Register dst, Register nds, AMD64Address src, AVXSize size, int pp, int mmmmm, int w, boolean checkAVX) {
+        emitVEX(getLFlag(size), pp, mmmmm, w, getRXB(dst, src), nds.isValid() ? nds.encoding() : 0, checkAVX);
     }
 
     protected static final class EVEXPrefixConfig {
@@ -986,6 +1040,51 @@
         }
     }
 
+ // @formatter:off
+ //
+ // Instruction Format and EVEX illustrated below (optional []):
+ //
+ // #of bytes:      4       1       1       1       1,2,4       1
+ // [Prefixes]    EVEX   OpCode   ModR/M  [SIB]   [Disp8*N] [Immediate]
+ //                                              [Disp16,32]
+ //
+ // The EVEX prefix is a 4-byte prefix, with the first two bytes derived from unused encoding
+ // form of the 32-bit-mode-only BOUND instruction. The layout of the EVEX prefix is shown in
+ // the figure below. The first byte must be 0x62, followed by three pay-load bytes, denoted
+ // as P1, P2, and P3 individually or collectively as P[23:0] (see below).
+ //
+ // EVEX: 0x62 | P1 | P2 | P3
+ //
+ //     7   6   5   4   3   2   1   0
+ // P1  R   X   B   R'  0   0   m   m      P[ 7: 0]
+ // P2  W   v   v   v   v   1   p   p      P[15: 8]
+ // P3  z   L'  L   b   V'  a   a   a      P[23:16]
+ //
+ // Figure. Bit Field Layout of the EVEX Prefix
+ //
+ // Table. EVEX Prefix Bit Field Functional Grouping
+ //
+ // Notation        Bit field Group        Position        Comment
+ // ---------  --------------------------  --------  -----------------------
+ // EVEX.RXB   Next-8 register specifier   P[7:5]    Combine with ModR/M.reg, ModR/M.rm (base, index/vidx).
+ // EVEX.X     High-16 register specifier  P[6]      Combine with EVEX.B and ModR/M.rm, when SIB/VSIB absent.
+ // EVEX.R'    High-16 register specifier  P[4]      Combine with EVEX.R and ModR/M.reg.
+ // --         Reserved                    P[3:2]    Must be 0.
+ // EVEX.mm    Compressed legacy escape    P[1:0]    Identical to low two bits of VEX.mmmmm.
+ //
+ // EVEX.W     Osize promotion/Opcode ext  P[15]
+ // EVEX.vvvv  NDS register specifier      P[14:11]  Same as VEX.vvvv.
+ // --         Fixed Value                 P[10]     Must be 1.
+ // EVEX.pp    Compressed legacy prefix    P[9:8]    Identical to VEX.pp.
+ //
+ // EVEX.z     Zeroing/Merging             P[23]
+ // EVEX.L'L   Vector length/RC            P[22:21]
+ // EVEX.b     Broadcast/RC/SAE Context    P[20]
+ // EVEX.V'    High-16 NDS/VIDX register   P[19]     Combine with EVEX.vvvv or VSIB when present.
+ // EVEX.aaa   Embedded opmask register    P[18:16]
+ //
+ // @formatter:on
+
     /**
      * Low-level function to encode and emit the EVEX prefix.
      * <p>
@@ -1021,13 +1120,13 @@
 
         assert (rxb & 0x07) == rxb : "invalid value for EVEX.RXB";
         assert (reg & 0x1F) == reg : "invalid value for EVEX.R'";
-        assert (vvvvv & 0x1F) == vvvvv : "invalid value for EVEX.vvvvv";
+        assert (vvvvv & 0x1F) == vvvvv : "invalid value for EVEX.V'vvvv";
 
         assert z == Z0 || z == Z1 : "invalid value for EVEX.z";
         assert b == B0 || b == B1 : "invalid value for EVEX.b";
         assert (aaa & 0x07) == aaa : "invalid value for EVEX.aaa";
 
-        emitByte(0x62);
+        emitByte(Prefix.EVEX);
         int p1 = 0;
         p1 |= ((rxb ^ 0x07) & 0x07) << 5;
         p1 |= reg < 16 ? 0x10 : 0;
@@ -1037,7 +1136,7 @@
         int p2 = 0;
         p2 |= w << 7;
         p2 |= ((vvvvv ^ 0x0F) & 0x0F) << 3;
-        p2 |= 0x4;
+        p2 |= 0x04;
         p2 |= pp;
         emitByte(p2);
 
@@ -1050,6 +1149,11 @@
         emitByte(p3);
     }
 
+    /**
+     * Get RXB bits for register-register instructions in EVEX-encoding, where ModRM.rm contains a
+     * register index. The R bit extends the ModRM.reg field and the X and B bits extends the
+     * ModRM.rm field.
+     */
     private static int getRXBForEVEX(Register reg, Register rm) {
         int rxb = (reg == null ? 0 : reg.encoding & 0x08) >> 1;
         rxb |= (rm == null ? 0 : rm.encoding & 0x018) >> 3;
@@ -1060,7 +1164,7 @@
      * Helper method for emitting EVEX prefix in the form of RRRR.
      */
     protected final void evexPrefix(Register dst, Register mask, Register nds, Register src, AVXSize size, int pp, int mm, int w, int z, int b) {
-        assert !mask.isValid() || mask.getRegisterCategory().equals(MASK);
+        assert !mask.isValid() || inRC(MASK, mask);
         emitEVEX(getLFlag(size), pp, mm, w, getRXBForEVEX(dst, src), dst.encoding, nds.isValid() ? nds.encoding() : 0, z, b, mask.isValid() ? mask.encoding : 0);
     }
 
@@ -1071,7 +1175,7 @@
      * {@link #emitEVEXOperandHelper(Register, AMD64Address, int, int)}.
      */
     protected final void evexPrefix(Register dst, Register mask, Register nds, AMD64Address src, AVXSize size, int pp, int mm, int w, int z, int b) {
-        assert !mask.isValid() || mask.getRegisterCategory().equals(MASK);
+        assert !mask.isValid() || inRC(MASK, mask);
         emitEVEX(getLFlag(size), pp, mm, w, getRXB(dst, src), dst.encoding, nds.isValid() ? nds.encoding() : 0, z, b, mask.isValid() ? mask.encoding : 0);
     }