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