1 /*
  2  * Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 package jdk.vm.ci.amd64;
 24 
 25 import static jdk.vm.ci.code.MemoryBarriers.LOAD_LOAD;
 26 import static jdk.vm.ci.code.MemoryBarriers.LOAD_STORE;
 27 import static jdk.vm.ci.code.MemoryBarriers.STORE_STORE;
 28 import static jdk.vm.ci.code.Register.SPECIAL;
 29 
 30 import java.nio.ByteOrder;
 31 import java.util.EnumSet;
 32 
 33 import jdk.vm.ci.code.Architecture;
 34 import jdk.vm.ci.code.CPUFeatureName;
 35 import jdk.vm.ci.code.Register;
 36 import jdk.vm.ci.code.Register.RegisterCategory;
 37 import jdk.vm.ci.code.RegisterArray;
 38 import jdk.vm.ci.meta.JavaKind;
 39 import jdk.vm.ci.meta.PlatformKind;
 40 
 41 /**
 42  * Represents the AMD64 architecture.
 43  */
 44 public class AMD64 extends Architecture {
 45 
 46     public static final RegisterCategory CPU = new RegisterCategory("CPU");
 47 
 48     // @formatter:off
 49 
 50     // General purpose CPU registers
 51     public static final Register rax = new Register(0, 0, "rax", CPU);
 52     public static final Register rcx = new Register(1, 1, "rcx", CPU);
 53     public static final Register rdx = new Register(2, 2, "rdx", CPU);
 54     public static final Register rbx = new Register(3, 3, "rbx", CPU);
 55     public static final Register rsp = new Register(4, 4, "rsp", CPU);
 56     public static final Register rbp = new Register(5, 5, "rbp", CPU);
 57     public static final Register rsi = new Register(6, 6, "rsi", CPU);
 58     public static final Register rdi = new Register(7, 7, "rdi", CPU);
 59 
 60     public static final Register r8  = new Register(8,  8,  "r8", CPU);
 61     public static final Register r9  = new Register(9,  9,  "r9", CPU);
 62     public static final Register r10 = new Register(10, 10, "r10", CPU);
 63     public static final Register r11 = new Register(11, 11, "r11", CPU);
 64     public static final Register r12 = new Register(12, 12, "r12", CPU);
 65     public static final Register r13 = new Register(13, 13, "r13", CPU);
 66     public static final Register r14 = new Register(14, 14, "r14", CPU);
 67     public static final Register r15 = new Register(15, 15, "r15", CPU);
 68 
 69     public static final Register[] cpuRegisters = {
 70         rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi,
 71         r8, r9, r10, r11, r12, r13, r14, r15
 72     };
 73 
 74     public static final RegisterCategory XMM = new RegisterCategory("XMM");
 75 
 76     // XMM registers
 77     public static final Register xmm0 = new Register(16, 0, "xmm0", XMM);
 78     public static final Register xmm1 = new Register(17, 1, "xmm1", XMM);
 79     public static final Register xmm2 = new Register(18, 2, "xmm2", XMM);
 80     public static final Register xmm3 = new Register(19, 3, "xmm3", XMM);
 81     public static final Register xmm4 = new Register(20, 4, "xmm4", XMM);
 82     public static final Register xmm5 = new Register(21, 5, "xmm5", XMM);
 83     public static final Register xmm6 = new Register(22, 6, "xmm6", XMM);
 84     public static final Register xmm7 = new Register(23, 7, "xmm7", XMM);
 85 
 86     public static final Register xmm8  = new Register(24,  8, "xmm8",  XMM);
 87     public static final Register xmm9  = new Register(25,  9, "xmm9",  XMM);
 88     public static final Register xmm10 = new Register(26, 10, "xmm10", XMM);
 89     public static final Register xmm11 = new Register(27, 11, "xmm11", XMM);
 90     public static final Register xmm12 = new Register(28, 12, "xmm12", XMM);
 91     public static final Register xmm13 = new Register(29, 13, "xmm13", XMM);
 92     public static final Register xmm14 = new Register(30, 14, "xmm14", XMM);
 93     public static final Register xmm15 = new Register(31, 15, "xmm15", XMM);
 94 
 95     public static final Register xmm16 = new Register(32, 16, "xmm16", XMM);
 96     public static final Register xmm17 = new Register(33, 17, "xmm17", XMM);
 97     public static final Register xmm18 = new Register(34, 18, "xmm18", XMM);
 98     public static final Register xmm19 = new Register(35, 19, "xmm19", XMM);
 99     public static final Register xmm20 = new Register(36, 20, "xmm20", XMM);
100     public static final Register xmm21 = new Register(37, 21, "xmm21", XMM);
101     public static final Register xmm22 = new Register(38, 22, "xmm22", XMM);
102     public static final Register xmm23 = new Register(39, 23, "xmm23", XMM);
103 
104     public static final Register xmm24 = new Register(40, 24, "xmm24", XMM);
105     public static final Register xmm25 = new Register(41, 25, "xmm25", XMM);
106     public static final Register xmm26 = new Register(42, 26, "xmm26", XMM);
107     public static final Register xmm27 = new Register(43, 27, "xmm27", XMM);
108     public static final Register xmm28 = new Register(44, 28, "xmm28", XMM);
109     public static final Register xmm29 = new Register(45, 29, "xmm29", XMM);
110     public static final Register xmm30 = new Register(46, 30, "xmm30", XMM);
111     public static final Register xmm31 = new Register(47, 31, "xmm31", XMM);
112 
113     public static final Register[] xmmRegistersSSE = {
114         xmm0, xmm1, xmm2,  xmm3,  xmm4,  xmm5,  xmm6,  xmm7,
115         xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15
116     };
117 
118     public static final Register[] xmmRegistersAVX512 = {
119         xmm0, xmm1, xmm2,  xmm3,  xmm4,  xmm5,  xmm6,  xmm7,
120         xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15,
121         xmm16, xmm17, xmm18, xmm19, xmm20, xmm21, xmm22, xmm23,
122         xmm24, xmm25, xmm26, xmm27, xmm28, xmm29, xmm30, xmm31
123     };
124 
125     public static final RegisterCategory MASK = new RegisterCategory("MASK", false);
126 
127     public static final Register k0 = new Register(48, 0, "k0", MASK);
128     public static final Register k1 = new Register(49, 1, "k1", MASK);
129     public static final Register k2 = new Register(50, 2, "k2", MASK);
130     public static final Register k3 = new Register(51, 3, "k3", MASK);
131     public static final Register k4 = new Register(52, 4, "k4", MASK);
132     public static final Register k5 = new Register(53, 5, "k5", MASK);
133     public static final Register k6 = new Register(54, 6, "k6", MASK);
134     public static final Register k7 = new Register(55, 7, "k7", MASK);
135 
136     public static final RegisterArray valueRegistersSSE = new RegisterArray(
137         rax,  rcx,  rdx,   rbx,   rsp,   rbp,   rsi,   rdi,
138         r8,   r9,   r10,   r11,   r12,   r13,   r14,   r15,
139         xmm0, xmm1, xmm2,  xmm3,  xmm4,  xmm5,  xmm6,  xmm7,
140         xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15
141     );
142 
143     public static final RegisterArray valueRegistersAVX512 = new RegisterArray(
144         rax,  rcx,  rdx,   rbx,   rsp,   rbp,   rsi,   rdi,
145         r8,   r9,   r10,   r11,   r12,   r13,   r14,   r15,
146         xmm0, xmm1, xmm2,  xmm3,  xmm4,  xmm5,  xmm6,  xmm7,
147         xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15,
148         xmm16, xmm17, xmm18, xmm19, xmm20, xmm21, xmm22, xmm23,
149         xmm24, xmm25, xmm26, xmm27, xmm28, xmm29, xmm30, xmm31,
150         k0, k1, k2, k3, k4, k5, k6, k7
151     );
152 
153     /**
154      * Register used to construct an instruction-relative address.
155      */
156     public static final Register rip = new Register(56, -1, "rip", SPECIAL);
157 
158     public static final RegisterArray allRegisters = new RegisterArray(
159         rax,  rcx,  rdx,   rbx,   rsp,   rbp,   rsi,   rdi,
160         r8,   r9,   r10,   r11,   r12,   r13,   r14,   r15,
161         xmm0, xmm1, xmm2,  xmm3,  xmm4,  xmm5,  xmm6,  xmm7,
162         xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15,
163         xmm16, xmm17, xmm18, xmm19, xmm20, xmm21, xmm22, xmm23,
164         xmm24, xmm25, xmm26, xmm27, xmm28, xmm29, xmm30, xmm31,
165         k0, k1, k2, k3, k4, k5, k6, k7,
166         rip
167     );
168 
169     // @formatter:on
170 
171     /**
172      * Basic set of CPU features mirroring what is returned from the cpuid instruction. See:
173      * {@code VM_Version::cpuFeatureFlags}.
174      */
175     public enum CPUFeature implements CPUFeatureName {
176         CX8,
177         CMOV,
178         FXSR,
179         HT,
180         MMX,
181         AMD_3DNOW_PREFETCH,
182         SSE,
183         SSE2,
184         SSE3,
185         SSSE3,
186         SSE4A,
187         SSE4_1,
188         SSE4_2,
189         POPCNT,
190         LZCNT,
191         TSC,
192         TSCINV,
193         TSCINV_BIT,
194         AVX,
195         AVX2,
196         AES,
197         ERMS,
198         CLMUL,
199         BMI1,
200         BMI2,
201         RTM,
202         ADX,
203         AVX512F,
204         AVX512DQ,
205         AVX512PF,
206         AVX512ER,
207         AVX512CD,
208         AVX512BW,
209         AVX512VL,
210         SHA,
211         FMA,
212         VZEROUPPER,
213         AVX512_VPOPCNTDQ,
214         AVX512_VPCLMULQDQ,
215         AVX512_VAES,
216         AVX512_VNNI,
217         FLUSH,
218         FLUSHOPT,
219         CLWB,
220         AVX512_VBMI2,
221         AVX512_VBMI,
222         HV,
223         SERIALIZE,
224     }
225 
226     private final EnumSet<CPUFeature> features;
227 
228     /**
229      * Set of flags to control code emission.
230      */
231     public enum Flag {
232         UseCountLeadingZerosInstruction,
233         UseCountTrailingZerosInstruction
234     }
235 
236     private final EnumSet<Flag> flags;
237 
238     private final AMD64Kind largestKind;
239 
240     public AMD64(EnumSet<CPUFeature> features, EnumSet<Flag> flags) {
241         super("AMD64", AMD64Kind.QWORD, ByteOrder.LITTLE_ENDIAN, true, allRegisters, LOAD_LOAD | LOAD_STORE | STORE_STORE, 1, 8);
242         this.features = features;
243         this.flags = flags;
244         assert features.contains(CPUFeature.SSE2) : "minimum config for x64";
245 
246         if (features.contains(CPUFeature.AVX512F)) {
247             largestKind = AMD64Kind.V512_QWORD;
248         } else if (features.contains(CPUFeature.AVX)) {
249             largestKind = AMD64Kind.V256_QWORD;
250         } else {
251             largestKind = AMD64Kind.V128_QWORD;
252         }
253     }
254 
255     @Override
256     public EnumSet<CPUFeature> getFeatures() {
257         return features;
258     }
259 
260     public EnumSet<Flag> getFlags() {
261         return flags;
262     }
263 
264     @Override
265     public RegisterArray getAvailableValueRegisters() {
266         if (features.contains(CPUFeature.AVX512F)) {
267             return valueRegistersAVX512;
268         } else {
269             return valueRegistersSSE;
270         }
271     }
272 
273     @Override
274     public PlatformKind getPlatformKind(JavaKind javaKind) {
275         switch (javaKind) {
276             case Boolean:
277             case Byte:
278                 return AMD64Kind.BYTE;
279             case Short:
280             case Char:
281                 return AMD64Kind.WORD;
282             case Int:
283                 return AMD64Kind.DWORD;
284             case Long:
285             case Object:
286                 return AMD64Kind.QWORD;
287             case Float:
288                 return AMD64Kind.SINGLE;
289             case Double:
290                 return AMD64Kind.DOUBLE;
291             default:
292                 return null;
293         }
294     }
295 
296     @Override
297     public boolean canStoreValue(RegisterCategory category, PlatformKind platformKind) {
298         AMD64Kind kind = (AMD64Kind) platformKind;
299         if (kind.isInteger()) {
300             return category.equals(CPU);
301         } else if (kind.isXMM()) {
302             return category.equals(XMM);
303         } else {
304             assert kind.isMask();
305             return category.equals(MASK);
306         }
307     }
308 
309     @Override
310     public AMD64Kind getLargestStorableKind(RegisterCategory category) {
311         if (category.equals(CPU)) {
312             return AMD64Kind.QWORD;
313         } else if (category.equals(XMM)) {
314             return largestKind;
315         } else if (category.equals(MASK)) {
316             return AMD64Kind.MASK64;
317         } else {
318             return null;
319         }
320     }
321 }