< prev index next >

src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64BaseAssembler.java

Print this page
rev 52509 : [mq]: graal2

*** 57,66 **** --- 57,67 ---- import jdk.vm.ci.amd64.AMD64; 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; /** * This class implements an assembler that can encode most X86 instructions.
*** 267,278 **** public final boolean supports(CPUFeature feature) { return ((AMD64) target.arch).getFeatures().contains(feature); } 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; return r.encoding & 0x7; } private static final int MinEncodingNeedsRex = 8; --- 268,283 ---- public final boolean supports(CPUFeature feature) { 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 && (inRC(XMM, r) ? r.encoding < 32 : r.encoding < 16) : "encoding out of range: " + r.encoding; return r.encoding & 0x7; } private static final int MinEncodingNeedsRex = 8;
*** 294,303 **** --- 299,312 ---- private static final int REXWXB = 0x4B; private static final int REXWR = 0x4C; 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() { emitByte(Prefix.REXW); }
*** 795,810 **** } } @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); } @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); } } protected final void simdPrefix(Register xreg, Register nds, AMD64Address adr, OperandSize size, int overriddenSizePrefix, int opcodeEscapePrefix, boolean isRexW) { simdEncoder.simdPrefix(xreg, nds, adr, overriddenSizePrefix != 0 ? overriddenSizePrefix : size.sizePrefix, opcodeEscapePrefix, isRexW); --- 804,824 ---- } } @Override public void simdPrefix(Register reg, Register nds, AMD64Address rm, int sizePrefix, int opcodeEscapePrefix, boolean isRexW) { ! 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) { ! 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); } } protected final void simdPrefix(Register xreg, Register nds, AMD64Address adr, OperandSize size, int overriddenSizePrefix, int opcodeEscapePrefix, boolean isRexW) { simdEncoder.simdPrefix(xreg, nds, adr, overriddenSizePrefix != 0 ? overriddenSizePrefix : size.sizePrefix, opcodeEscapePrefix, isRexW);
*** 820,829 **** --- 834,883 ---- protected final void simdPrefix(Register dst, Register nds, Register src, OperandSize size, int opcodeEscapePrefix, boolean isRexW) { 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> * 2 byte form: [1100 0101] [R vvvv L pp]<br> * 3 byte form: [1100 0100] [RXB m-mmmm] [W vvvv L pp]
*** 844,855 **** * 00011: implied 0F 3A leading opcode bytes * <p> * 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"; 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"; assert mmmmm == M_0F || mmmmm == M_0F38 || mmmmm == M_0F3A : "invalid value for VEX.m-mmmm"; assert w == W0 || w == W1 : "invalid value for VEX.W"; --- 898,909 ---- * 00011: implied 0F 3A leading opcode bytes * <p> * 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, 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"; assert mmmmm == M_0F || mmmmm == M_0F38 || mmmmm == M_0F3A : "invalid value for VEX.m-mmmm"; assert w == W0 || w == W1 : "invalid value for VEX.W";
*** 865,875 **** byte2 |= (rxb1s & 0x04) << 5; byte2 |= vvvv1s << 3; byte2 |= l << 2; byte2 |= pp; ! emitByte(0xC5); emitByte(byte2); } else { // 3 byte encoding int byte2 = 0; byte2 = (rxb1s & 0x07) << 5; --- 919,929 ---- byte2 |= (rxb1s & 0x04) << 5; byte2 |= vvvv1s << 3; byte2 |= l << 2; byte2 |= pp; ! emitByte(Prefix.VEX2); emitByte(byte2); } else { // 3 byte encoding int byte2 = 0; byte2 = (rxb1s & 0x07) << 5;
*** 879,889 **** byte3 |= w << 7; byte3 |= vvvv1s << 3; byte3 |= l << 2; byte3 |= pp; ! emitByte(0xC4); emitByte(byte2); emitByte(byte3); } } --- 933,943 ---- byte3 |= w << 7; byte3 |= vvvv1s << 3; byte3 |= l << 2; byte3 |= pp; ! emitByte(Prefix.VEX3); emitByte(byte2); emitByte(byte3); } }
*** 898,913 **** default: return LZ; } } ! 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, AMD64Address src, AVXSize size, int pp, int mmmmm, int w) { ! emitVEX(getLFlag(size), pp, mmmmm, w, getRXB(dst, src), nds.isValid() ? nds.encoding() : 0); } protected static final class EVEXPrefixConfig { public static final int L512 = 2; public static final int LIG = 0; --- 952,967 ---- default: return LZ; } } ! 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, boolean checkAVX) { ! emitVEX(getLFlag(size), pp, mmmmm, w, getRXB(dst, src), nds.isValid() ? nds.encoding() : 0, checkAVX); } protected static final class EVEXPrefixConfig { public static final int L512 = 2; public static final int LIG = 0;
*** 984,993 **** --- 1038,1092 ---- throw GraalError.shouldNotReachHere("Unsupported vector size."); } } } + // @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> * 62 [0 1 1 0 0 0 1 0]<br> * P1 [R X B R'0 0 m m]<br>
*** 1019,1045 **** assert mm == M_0F || mm == M_0F38 || mm == M_0F3A : "invalid value for EVEX.mm"; assert w == W0 || w == W1 : "invalid value for EVEX.W"; 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 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); int p1 = 0; p1 |= ((rxb ^ 0x07) & 0x07) << 5; p1 |= reg < 16 ? 0x10 : 0; p1 |= mm; emitByte(p1); int p2 = 0; p2 |= w << 7; p2 |= ((vvvvv ^ 0x0F) & 0x0F) << 3; ! p2 |= 0x4; p2 |= pp; emitByte(p2); int p3 = 0; p3 |= z << 7; --- 1118,1144 ---- assert mm == M_0F || mm == M_0F38 || mm == M_0F3A : "invalid value for EVEX.mm"; assert w == W0 || w == W1 : "invalid value for EVEX.W"; 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.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(Prefix.EVEX); int p1 = 0; p1 |= ((rxb ^ 0x07) & 0x07) << 5; p1 |= reg < 16 ? 0x10 : 0; p1 |= mm; emitByte(p1); int p2 = 0; p2 |= w << 7; p2 |= ((vvvvv ^ 0x0F) & 0x0F) << 3; ! p2 |= 0x04; p2 |= pp; emitByte(p2); int p3 = 0; p3 |= z << 7;
*** 1048,1078 **** p3 |= vvvvv < 16 ? 0x08 : 0; p3 |= aaa; emitByte(p3); } 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; return rxb; } /** * 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); emitEVEX(getLFlag(size), pp, mm, w, getRXBForEVEX(dst, src), dst.encoding, nds.isValid() ? nds.encoding() : 0, z, b, mask.isValid() ? mask.encoding : 0); } /** * Helper method for emitting EVEX prefix in the form of RRRM. Because the memory addressing in * EVEX-encoded instructions employ a compressed displacement scheme when using disp8 form, the * user of this API should make sure to encode the operands using * {@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); emitEVEX(getLFlag(size), pp, mm, w, getRXB(dst, src), dst.encoding, nds.isValid() ? nds.encoding() : 0, z, b, mask.isValid() ? mask.encoding : 0); } } --- 1147,1182 ---- p3 |= vvvvv < 16 ? 0x08 : 0; p3 |= aaa; 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; return rxb; } /** * 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() || 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); } /** * Helper method for emitting EVEX prefix in the form of RRRM. Because the memory addressing in * EVEX-encoded instructions employ a compressed displacement scheme when using disp8 form, the * user of this API should make sure to encode the operands using * {@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() || 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); } }
< prev index next >