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     }
224 
225     private final EnumSet<CPUFeature> features;
226 
227     /**
228      * Set of flags to control code emission.
229      */
230     public enum Flag {
231         UseCountLeadingZerosInstruction,
232         UseCountTrailingZerosInstruction
233     }
234 
235     private final EnumSet<Flag> flags;
236 
237     private final AMD64Kind largestKind;
238 
AMD64(EnumSet<CPUFeature> features, EnumSet<Flag> flags)239     public AMD64(EnumSet<CPUFeature> features, EnumSet<Flag> flags) {
240         super("AMD64", AMD64Kind.QWORD, ByteOrder.LITTLE_ENDIAN, true, allRegisters, LOAD_LOAD | LOAD_STORE | STORE_STORE, 1, 8);
241         this.features = features;
242         this.flags = flags;
243         assert features.contains(CPUFeature.SSE2) : "minimum config for x64";
244 
245         if (features.contains(CPUFeature.AVX512F)) {
246             largestKind = AMD64Kind.V512_QWORD;
247         } else if (features.contains(CPUFeature.AVX)) {
248             largestKind = AMD64Kind.V256_QWORD;
249         } else {
250             largestKind = AMD64Kind.V128_QWORD;
251         }
252     }
253 
254     @Override
getFeatures()255     public EnumSet<CPUFeature> getFeatures() {
256         return features;
257     }
258 
getFlags()259     public EnumSet<Flag> getFlags() {
260         return flags;
261     }
262 
263     @Override
getAvailableValueRegisters()264     public RegisterArray getAvailableValueRegisters() {
265         if (features.contains(CPUFeature.AVX512F)) {
266             return valueRegistersAVX512;
267         } else {
268             return valueRegistersSSE;
269         }
270     }
271 
272     @Override
getPlatformKind(JavaKind javaKind)273     public PlatformKind getPlatformKind(JavaKind javaKind) {
274         switch (javaKind) {
275             case Boolean:
276             case Byte:
277                 return AMD64Kind.BYTE;
278             case Short:
279             case Char:
280                 return AMD64Kind.WORD;
281             case Int:
282                 return AMD64Kind.DWORD;
283             case Long:
284             case Object:
285                 return AMD64Kind.QWORD;
286             case Float:
287                 return AMD64Kind.SINGLE;
288             case Double:
289                 return AMD64Kind.DOUBLE;
290             default:
291                 return null;
292         }
293     }
294 
295     @Override
canStoreValue(RegisterCategory category, PlatformKind platformKind)296     public boolean canStoreValue(RegisterCategory category, PlatformKind platformKind) {
297         AMD64Kind kind = (AMD64Kind) platformKind;
298         if (kind.isInteger()) {
299             return category.equals(CPU);
300         } else if (kind.isXMM()) {
301             return category.equals(XMM);
302         } else {
303             assert kind.isMask();
304             return category.equals(MASK);
305         }
306     }
307 
308     @Override
getLargestStorableKind(RegisterCategory category)309     public AMD64Kind getLargestStorableKind(RegisterCategory category) {
310         if (category.equals(CPU)) {
311             return AMD64Kind.QWORD;
312         } else if (category.equals(XMM)) {
313             return largestKind;
314         } else if (category.equals(MASK)) {
315             return AMD64Kind.MASK64;
316         } else {
317             return null;
318         }
319     }
320 }
321