32 import static jdk.vm.ci.aarch64.AArch64.r29;
33 import static jdk.vm.ci.aarch64.AArch64.r3;
34 import static jdk.vm.ci.aarch64.AArch64.r31;
35 import static jdk.vm.ci.aarch64.AArch64.r4;
36 import static jdk.vm.ci.aarch64.AArch64.r5;
37 import static jdk.vm.ci.aarch64.AArch64.r6;
38 import static jdk.vm.ci.aarch64.AArch64.r7;
39 import static jdk.vm.ci.aarch64.AArch64.r9;
40 import static jdk.vm.ci.aarch64.AArch64.sp;
41 import static jdk.vm.ci.aarch64.AArch64.v0;
42 import static jdk.vm.ci.aarch64.AArch64.v1;
43 import static jdk.vm.ci.aarch64.AArch64.v2;
44 import static jdk.vm.ci.aarch64.AArch64.v3;
45 import static jdk.vm.ci.aarch64.AArch64.v4;
46 import static jdk.vm.ci.aarch64.AArch64.v5;
47 import static jdk.vm.ci.aarch64.AArch64.v6;
48 import static jdk.vm.ci.aarch64.AArch64.v7;
49 import static jdk.vm.ci.aarch64.AArch64.zr;
50
51 import java.util.ArrayList;
52 import java.util.Arrays;
53 import java.util.Collections;
54 import java.util.HashSet;
55 import java.util.List;
56 import java.util.Set;
57
58 import jdk.vm.ci.aarch64.AArch64;
59 import jdk.vm.ci.code.Architecture;
60 import jdk.vm.ci.code.CallingConvention;
61 import jdk.vm.ci.code.CallingConvention.Type;
62 import jdk.vm.ci.code.Register;
63 import jdk.vm.ci.code.RegisterAttributes;
64 import jdk.vm.ci.code.RegisterConfig;
65 import jdk.vm.ci.code.StackSlot;
66 import jdk.vm.ci.code.TargetDescription;
67 import jdk.vm.ci.code.ValueKindFactory;
68 import jdk.vm.ci.common.JVMCIError;
69 import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
70 import jdk.vm.ci.meta.AllocatableValue;
71 import jdk.vm.ci.meta.JavaKind;
72 import jdk.vm.ci.meta.JavaType;
73 import jdk.vm.ci.meta.PlatformKind;
74 import jdk.vm.ci.meta.Value;
75 import jdk.vm.ci.meta.ValueKind;
76
77 public class AArch64HotSpotRegisterConfig implements RegisterConfig {
78
79 private final TargetDescription target;
80
81 private final Register[] allocatable;
82
83 /**
84 * The caller saved registers always include all parameter registers.
85 */
86 private final Register[] callerSaved;
87
88 private final boolean allAllocatableAreCallerSaved;
89
90 private final RegisterAttributes[] attributesMap;
91
92 @Override
93 public Register[] getAllocatableRegisters() {
94 return allocatable.clone();
95 }
96
97 @Override
98 public Register[] filterAllocatableRegisters(PlatformKind kind, Register[] registers) {
99 ArrayList<Register> list = new ArrayList<>();
100 for (Register reg : registers) {
101 if (target.arch.canStoreValue(reg.getRegisterCategory(), kind)) {
102 list.add(reg);
103 }
104 }
105
106 Register[] ret = list.toArray(new Register[list.size()]);
107 return ret;
108 }
109
110 @Override
111 public RegisterAttributes[] getAttributesMap() {
112 return attributesMap.clone();
113 }
114
115 private final Register[] javaGeneralParameterRegisters = {r1, r2, r3, r4, r5, r6, r7, r0};
116 private final Register[] nativeGeneralParameterRegisters = {r0, r1, r2, r3, r4, r5, r6, r7};
117 private final Register[] simdParameterRegisters = {v0, v1, v2, v3, v4, v5, v6, v7};
118
119 public static final Register inlineCacheRegister = r9;
120
121 /**
122 * Vtable stubs expect the metaspace Method in r12.
123 */
124 public static final Register metaspaceMethodRegister = r12;
125
126 public static final Register heapBaseRegister = r27;
127 public static final Register threadRegister = r28;
128 public static final Register fp = r29;
129
130 private static final Register[] reservedRegisters = {threadRegister, fp, lr, r31, zr, sp};
131
132 private static Register[] initAllocatable(Architecture arch, boolean reserveForHeapBase) {
133 Register[] allRegisters = arch.getAvailableValueRegisters();
134 Register[] registers = new Register[allRegisters.length - reservedRegisters.length - (reserveForHeapBase ? 1 : 0)];
135 List<Register> reservedRegistersList = Arrays.asList(reservedRegisters);
136
137 int idx = 0;
138 for (Register reg : allRegisters) {
139 if (reservedRegistersList.contains(reg)) {
140 // skip reserved registers
141 continue;
142 }
143 assert !(reg.equals(threadRegister) || reg.equals(fp) || reg.equals(lr) || reg.equals(r31) || reg.equals(zr) || reg.equals(sp));
144 if (reserveForHeapBase && reg.equals(heapBaseRegister)) {
145 // skip heap base register
146 continue;
147 }
148
149 registers[idx++] = reg;
150 }
151
152 assert idx == registers.length;
153 return registers;
154 }
155
156 public AArch64HotSpotRegisterConfig(TargetDescription target, boolean useCompressedOops) {
157 this(target, initAllocatable(target.arch, useCompressedOops));
158 assert callerSaved.length >= allocatable.length;
159 }
160
161 public AArch64HotSpotRegisterConfig(TargetDescription target, Register[] allocatable) {
162 this.target = target;
163
164 this.allocatable = allocatable.clone();
165 Set<Register> callerSaveSet = new HashSet<>();
166 Collections.addAll(callerSaveSet, allocatable);
167 Collections.addAll(callerSaveSet, simdParameterRegisters);
168 Collections.addAll(callerSaveSet, javaGeneralParameterRegisters);
169 Collections.addAll(callerSaveSet, nativeGeneralParameterRegisters);
170 callerSaved = callerSaveSet.toArray(new Register[callerSaveSet.size()]);
171
172 allAllocatableAreCallerSaved = true;
173 attributesMap = RegisterAttributes.createMap(this, AArch64.allRegisters);
174 }
175
176 @Override
177 public Register[] getCallerSaveRegisters() {
178 return callerSaved;
179 }
180
181 public Register[] getCalleeSaveRegisters() {
182 return null;
183 }
184
185 @Override
186 public boolean areAllAllocatableRegistersCallerSaved() {
187 return allAllocatableAreCallerSaved;
188 }
189
190 @Override
191 public CallingConvention getCallingConvention(Type type, JavaType returnType, JavaType[] parameterTypes, ValueKindFactory<?> valueKindFactory) {
192 HotSpotCallingConventionType hotspotType = (HotSpotCallingConventionType) type;
193 if (type == HotSpotCallingConventionType.NativeCall) {
194 return callingConvention(nativeGeneralParameterRegisters, returnType, parameterTypes, hotspotType, valueKindFactory);
195 }
196 // On x64, parameter locations are the same whether viewed
197 // from the caller or callee perspective
198 return callingConvention(javaGeneralParameterRegisters, returnType, parameterTypes, hotspotType, valueKindFactory);
199 }
200
201 @Override
202 public Register[] getCallingConventionRegisters(Type type, JavaKind kind) {
203 HotSpotCallingConventionType hotspotType = (HotSpotCallingConventionType) type;
204 switch (kind) {
205 case Boolean:
206 case Byte:
207 case Short:
208 case Char:
209 case Int:
210 case Long:
211 case Object:
212 return hotspotType == HotSpotCallingConventionType.NativeCall ? nativeGeneralParameterRegisters : javaGeneralParameterRegisters;
213 case Float:
214 case Double:
215 return simdParameterRegisters;
216 default:
217 throw JVMCIError.shouldNotReachHere();
218 }
219 }
220
221 private CallingConvention callingConvention(Register[] generalParameterRegisters, JavaType returnType, JavaType[] parameterTypes, HotSpotCallingConventionType type,
222 ValueKindFactory<?> valueKindFactory) {
223 AllocatableValue[] locations = new AllocatableValue[parameterTypes.length];
224
225 int currentGeneral = 0;
226 int currentSIMD = 0;
227 int currentStackOffset = 0;
228
229 for (int i = 0; i < parameterTypes.length; i++) {
230 final JavaKind kind = parameterTypes[i].getJavaKind().getStackKind();
231
232 switch (kind) {
233 case Byte:
234 case Boolean:
235 case Short:
236 case Char:
237 case Int:
238 case Long:
239 case Object:
240 if (currentGeneral < generalParameterRegisters.length) {
241 Register register = generalParameterRegisters[currentGeneral++];
242 locations[i] = register.asValue(valueKindFactory.getValueKind(kind));
243 }
244 break;
245 case Float:
246 case Double:
247 if (currentSIMD < simdParameterRegisters.length) {
248 Register register = simdParameterRegisters[currentSIMD++];
249 locations[i] = register.asValue(valueKindFactory.getValueKind(kind));
250 }
251 break;
252 default:
253 throw JVMCIError.shouldNotReachHere();
254 }
255
256 if (locations[i] == null) {
257 ValueKind<?> valueKind = valueKindFactory.getValueKind(kind);
258 locations[i] = StackSlot.get(valueKind, currentStackOffset, !type.out);
259 currentStackOffset += Math.max(valueKind.getPlatformKind().getSizeInBytes(), target.wordSize);
260 }
261 }
262
263 JavaKind returnKind = returnType == null ? JavaKind.Void : returnType.getJavaKind();
264 AllocatableValue returnLocation = returnKind == JavaKind.Void ? Value.ILLEGAL : getReturnRegister(returnKind).asValue(valueKindFactory.getValueKind(returnKind.getStackKind()));
265 return new CallingConvention(currentStackOffset, returnLocation, locations);
266 }
267
268 @Override
277 case Object:
278 return r0;
279 case Float:
280 case Double:
281 return v0;
282 case Void:
283 case Illegal:
284 return null;
285 default:
286 throw new UnsupportedOperationException("no return register for type " + kind);
287 }
288 }
289
290 @Override
291 public Register getFrameRegister() {
292 return sp;
293 }
294
295 @Override
296 public String toString() {
297 return String.format("Allocatable: " + Arrays.toString(getAllocatableRegisters()) + "%n" + "CallerSave: " + Arrays.toString(getCallerSaveRegisters()) + "%n");
298 }
299 }
|
32 import static jdk.vm.ci.aarch64.AArch64.r29;
33 import static jdk.vm.ci.aarch64.AArch64.r3;
34 import static jdk.vm.ci.aarch64.AArch64.r31;
35 import static jdk.vm.ci.aarch64.AArch64.r4;
36 import static jdk.vm.ci.aarch64.AArch64.r5;
37 import static jdk.vm.ci.aarch64.AArch64.r6;
38 import static jdk.vm.ci.aarch64.AArch64.r7;
39 import static jdk.vm.ci.aarch64.AArch64.r9;
40 import static jdk.vm.ci.aarch64.AArch64.sp;
41 import static jdk.vm.ci.aarch64.AArch64.v0;
42 import static jdk.vm.ci.aarch64.AArch64.v1;
43 import static jdk.vm.ci.aarch64.AArch64.v2;
44 import static jdk.vm.ci.aarch64.AArch64.v3;
45 import static jdk.vm.ci.aarch64.AArch64.v4;
46 import static jdk.vm.ci.aarch64.AArch64.v5;
47 import static jdk.vm.ci.aarch64.AArch64.v6;
48 import static jdk.vm.ci.aarch64.AArch64.v7;
49 import static jdk.vm.ci.aarch64.AArch64.zr;
50
51 import java.util.ArrayList;
52 import java.util.HashSet;
53 import java.util.List;
54 import java.util.Set;
55
56 import jdk.vm.ci.aarch64.AArch64;
57 import jdk.vm.ci.code.Architecture;
58 import jdk.vm.ci.code.CallingConvention;
59 import jdk.vm.ci.code.CallingConvention.Type;
60 import jdk.vm.ci.code.Register;
61 import jdk.vm.ci.code.RegisterArray;
62 import jdk.vm.ci.code.RegisterAttributes;
63 import jdk.vm.ci.code.RegisterConfig;
64 import jdk.vm.ci.code.StackSlot;
65 import jdk.vm.ci.code.TargetDescription;
66 import jdk.vm.ci.code.ValueKindFactory;
67 import jdk.vm.ci.common.JVMCIError;
68 import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
69 import jdk.vm.ci.meta.AllocatableValue;
70 import jdk.vm.ci.meta.JavaKind;
71 import jdk.vm.ci.meta.JavaType;
72 import jdk.vm.ci.meta.PlatformKind;
73 import jdk.vm.ci.meta.Value;
74 import jdk.vm.ci.meta.ValueKind;
75
76 public class AArch64HotSpotRegisterConfig implements RegisterConfig {
77
78 private final TargetDescription target;
79
80 private final RegisterArray allocatable;
81
82 /**
83 * The caller saved registers always include all parameter registers.
84 */
85 private final RegisterArray callerSaved;
86
87 private final boolean allAllocatableAreCallerSaved;
88
89 private final RegisterAttributes[] attributesMap;
90
91 @Override
92 public RegisterArray getAllocatableRegisters() {
93 return allocatable;
94 }
95
96 @Override
97 public RegisterArray filterAllocatableRegisters(PlatformKind kind, RegisterArray registers) {
98 ArrayList<Register> list = new ArrayList<>();
99 for (Register reg : registers) {
100 if (target.arch.canStoreValue(reg.getRegisterCategory(), kind)) {
101 list.add(reg);
102 }
103 }
104
105 return new RegisterArray(list);
106 }
107
108 @Override
109 public RegisterAttributes[] getAttributesMap() {
110 return attributesMap.clone();
111 }
112
113 private final RegisterArray javaGeneralParameterRegisters = new RegisterArray(r1, r2, r3, r4, r5, r6, r7, r0);
114 private final RegisterArray nativeGeneralParameterRegisters = new RegisterArray(r0, r1, r2, r3, r4, r5, r6, r7);
115 private final RegisterArray simdParameterRegisters = new RegisterArray(v0, v1, v2, v3, v4, v5, v6, v7);
116
117 public static final Register inlineCacheRegister = r9;
118
119 /**
120 * Vtable stubs expect the metaspace Method in r12.
121 */
122 public static final Register metaspaceMethodRegister = r12;
123
124 public static final Register heapBaseRegister = r27;
125 public static final Register threadRegister = r28;
126 public static final Register fp = r29;
127
128 private static final RegisterArray reservedRegisters = new RegisterArray(threadRegister, fp, lr, r31, zr, sp);
129
130 private static RegisterArray initAllocatable(Architecture arch, boolean reserveForHeapBase) {
131 RegisterArray allRegisters = arch.getAvailableValueRegisters();
132 Register[] registers = new Register[allRegisters.size() - reservedRegisters.size() - (reserveForHeapBase ? 1 : 0)];
133 List<Register> reservedRegistersList = reservedRegisters.asList();
134
135 int idx = 0;
136 for (Register reg : allRegisters) {
137 if (reservedRegistersList.contains(reg)) {
138 // skip reserved registers
139 continue;
140 }
141 assert !(reg.equals(threadRegister) || reg.equals(fp) || reg.equals(lr) || reg.equals(r31) || reg.equals(zr) || reg.equals(sp));
142 if (reserveForHeapBase && reg.equals(heapBaseRegister)) {
143 // skip heap base register
144 continue;
145 }
146
147 registers[idx++] = reg;
148 }
149
150 assert idx == registers.length;
151 return new RegisterArray(registers);
152 }
153
154 public AArch64HotSpotRegisterConfig(TargetDescription target, boolean useCompressedOops) {
155 this(target, initAllocatable(target.arch, useCompressedOops));
156 assert callerSaved.size() >= allocatable.size();
157 }
158
159 public AArch64HotSpotRegisterConfig(TargetDescription target, RegisterArray allocatable) {
160 this.target = target;
161
162 this.allocatable = allocatable;
163 Set<Register> callerSaveSet = new HashSet<>();
164 allocatable.addTo(callerSaveSet);
165 simdParameterRegisters.addTo(callerSaveSet);
166 javaGeneralParameterRegisters.addTo(callerSaveSet);
167 nativeGeneralParameterRegisters.addTo(callerSaveSet);
168 callerSaved = new RegisterArray(callerSaveSet);
169
170 allAllocatableAreCallerSaved = true;
171 attributesMap = RegisterAttributes.createMap(this, AArch64.allRegisters);
172 }
173
174 @Override
175 public RegisterArray getCallerSaveRegisters() {
176 return callerSaved;
177 }
178
179 public RegisterArray getCalleeSaveRegisters() {
180 return null;
181 }
182
183 @Override
184 public boolean areAllAllocatableRegistersCallerSaved() {
185 return allAllocatableAreCallerSaved;
186 }
187
188 @Override
189 public CallingConvention getCallingConvention(Type type, JavaType returnType, JavaType[] parameterTypes, ValueKindFactory<?> valueKindFactory) {
190 HotSpotCallingConventionType hotspotType = (HotSpotCallingConventionType) type;
191 if (type == HotSpotCallingConventionType.NativeCall) {
192 return callingConvention(nativeGeneralParameterRegisters, returnType, parameterTypes, hotspotType, valueKindFactory);
193 }
194 // On x64, parameter locations are the same whether viewed
195 // from the caller or callee perspective
196 return callingConvention(javaGeneralParameterRegisters, returnType, parameterTypes, hotspotType, valueKindFactory);
197 }
198
199 @Override
200 public RegisterArray getCallingConventionRegisters(Type type, JavaKind kind) {
201 HotSpotCallingConventionType hotspotType = (HotSpotCallingConventionType) type;
202 switch (kind) {
203 case Boolean:
204 case Byte:
205 case Short:
206 case Char:
207 case Int:
208 case Long:
209 case Object:
210 return hotspotType == HotSpotCallingConventionType.NativeCall ? nativeGeneralParameterRegisters : javaGeneralParameterRegisters;
211 case Float:
212 case Double:
213 return simdParameterRegisters;
214 default:
215 throw JVMCIError.shouldNotReachHere();
216 }
217 }
218
219 private CallingConvention callingConvention(RegisterArray generalParameterRegisters, JavaType returnType, JavaType[] parameterTypes, HotSpotCallingConventionType type,
220 ValueKindFactory<?> valueKindFactory) {
221 AllocatableValue[] locations = new AllocatableValue[parameterTypes.length];
222
223 int currentGeneral = 0;
224 int currentSIMD = 0;
225 int currentStackOffset = 0;
226
227 for (int i = 0; i < parameterTypes.length; i++) {
228 final JavaKind kind = parameterTypes[i].getJavaKind().getStackKind();
229
230 switch (kind) {
231 case Byte:
232 case Boolean:
233 case Short:
234 case Char:
235 case Int:
236 case Long:
237 case Object:
238 if (currentGeneral < generalParameterRegisters.size()) {
239 Register register = generalParameterRegisters.get(currentGeneral++);
240 locations[i] = register.asValue(valueKindFactory.getValueKind(kind));
241 }
242 break;
243 case Float:
244 case Double:
245 if (currentSIMD < simdParameterRegisters.size()) {
246 Register register = simdParameterRegisters.get(currentSIMD++);
247 locations[i] = register.asValue(valueKindFactory.getValueKind(kind));
248 }
249 break;
250 default:
251 throw JVMCIError.shouldNotReachHere();
252 }
253
254 if (locations[i] == null) {
255 ValueKind<?> valueKind = valueKindFactory.getValueKind(kind);
256 locations[i] = StackSlot.get(valueKind, currentStackOffset, !type.out);
257 currentStackOffset += Math.max(valueKind.getPlatformKind().getSizeInBytes(), target.wordSize);
258 }
259 }
260
261 JavaKind returnKind = returnType == null ? JavaKind.Void : returnType.getJavaKind();
262 AllocatableValue returnLocation = returnKind == JavaKind.Void ? Value.ILLEGAL : getReturnRegister(returnKind).asValue(valueKindFactory.getValueKind(returnKind.getStackKind()));
263 return new CallingConvention(currentStackOffset, returnLocation, locations);
264 }
265
266 @Override
275 case Object:
276 return r0;
277 case Float:
278 case Double:
279 return v0;
280 case Void:
281 case Illegal:
282 return null;
283 default:
284 throw new UnsupportedOperationException("no return register for type " + kind);
285 }
286 }
287
288 @Override
289 public Register getFrameRegister() {
290 return sp;
291 }
292
293 @Override
294 public String toString() {
295 return String.format("Allocatable: " + getAllocatableRegisters() + "%n" + "CallerSave: " + getCallerSaveRegisters() + "%n");
296 }
297 }
|