Mercurial > hg > graal-jvmci-8
comparison graal/Compiler/src/com/sun/c1x/target/amd64/AMD64GlobalStubEmitter.java @ 2507:9ec15d6914ca
Pull over of compiler from maxine repository.
author | Thomas Wuerthinger <thomas@wuerthinger.net> |
---|---|
date | Wed, 27 Apr 2011 11:43:22 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
2506:4a3bf8a5bf41 | 2507:9ec15d6914ca |
---|---|
1 /* | |
2 * Copyright (c) 2009, 2011, 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 com.sun.c1x.target.amd64; | |
24 | |
25 import static com.sun.cri.ci.CiCallingConvention.Type.*; | |
26 | |
27 import java.util.*; | |
28 | |
29 import com.sun.c1x.*; | |
30 import com.sun.c1x.asm.*; | |
31 import com.sun.c1x.globalstub.*; | |
32 import com.sun.c1x.target.amd64.AMD64Assembler.ConditionFlag; | |
33 import com.sun.cri.ci.*; | |
34 import com.sun.cri.ci.CiRegister.RegisterFlag; | |
35 import com.sun.cri.ri.*; | |
36 import com.sun.cri.xir.*; | |
37 import com.sun.cri.xir.CiXirAssembler.XirConstant; | |
38 import com.sun.cri.xir.CiXirAssembler.XirConstantOperand; | |
39 import com.sun.cri.xir.CiXirAssembler.XirOperand; | |
40 import com.sun.cri.xir.CiXirAssembler.XirParameter; | |
41 import com.sun.cri.xir.CiXirAssembler.XirRegister; | |
42 import com.sun.cri.xir.CiXirAssembler.XirTemp; | |
43 | |
44 public class AMD64GlobalStubEmitter implements GlobalStubEmitter { | |
45 | |
46 public static final int ARGUMENT_SIZE = 8; | |
47 | |
48 private static final long FloatSignFlip = 0x8000000080000000L; | |
49 private static final long DoubleSignFlip = 0x8000000000000000L; | |
50 private static final CiRegister convertArgument = AMD64.xmm0; | |
51 private static final CiRegister convertResult = AMD64.rax; | |
52 private static final CiRegister negateArgument = AMD64.xmm0; | |
53 private static final CiRegister negateTemp = AMD64.xmm1; | |
54 | |
55 private AMD64MacroAssembler asm; | |
56 private final CiTarget target; | |
57 private int argsSize; | |
58 private int[] argOffsets; | |
59 private int resultOffset; | |
60 private int saveSize; | |
61 private int registerRestoreEpilogueOffset; | |
62 | |
63 private RiRuntime runtime; | |
64 private C1XCompiler compiler; | |
65 private CiRegister[] registersSaved; | |
66 | |
67 private boolean savedAllRegisters; | |
68 | |
69 public AMD64GlobalStubEmitter(C1XCompiler compiler) { | |
70 this.compiler = compiler; | |
71 this.target = compiler.target; | |
72 this.runtime = compiler.runtime; | |
73 } | |
74 | |
75 private void reset(CiKind resultKind, CiKind[] argTypes) { | |
76 asm = new AMD64MacroAssembler.WithCompiler(compiler, compiler.globalStubRegisterConfig); | |
77 saveSize = 0; | |
78 argsSize = 0; | |
79 argOffsets = new int[argTypes.length]; | |
80 resultOffset = 0; | |
81 registerRestoreEpilogueOffset = -1; | |
82 registersSaved = null; | |
83 | |
84 for (int i = 0; i < argTypes.length; i++) { | |
85 argOffsets[i] = argsSize; | |
86 argsSize += ARGUMENT_SIZE; | |
87 } | |
88 | |
89 if (resultKind != CiKind.Void) { | |
90 if (argsSize == 0) { | |
91 argsSize = ARGUMENT_SIZE; | |
92 } | |
93 resultOffset = 0; | |
94 } | |
95 } | |
96 | |
97 public GlobalStub emit(CiRuntimeCall runtimeCall, RiRuntime runtime) { | |
98 reset(runtimeCall.resultKind, runtimeCall.arguments); | |
99 emitStandardForward(null, runtimeCall); | |
100 String name = "stub-" + runtimeCall; | |
101 CiTargetMethod targetMethod = asm.finishTargetMethod(name, runtime, registerRestoreEpilogueOffset, true); | |
102 Object stubObject = runtime.registerGlobalStub(targetMethod, name); | |
103 return new GlobalStub(null, runtimeCall.resultKind, stubObject, argsSize, argOffsets, resultOffset); | |
104 } | |
105 | |
106 public GlobalStub emit(GlobalStub.Id stub, RiRuntime runtime) { | |
107 reset(stub.resultKind, stub.arguments); | |
108 | |
109 switch (stub) { | |
110 case f2i: | |
111 emitF2I(); | |
112 break; | |
113 case f2l: | |
114 emitF2L(); | |
115 break; | |
116 case d2i: | |
117 emitD2I(); | |
118 break; | |
119 case d2l: | |
120 emitD2L(); | |
121 break; | |
122 case fneg: | |
123 emitFNEG(); | |
124 break; | |
125 case dneg: | |
126 emitDNEG(); | |
127 break; | |
128 } | |
129 | |
130 String name = "stub-" + stub; | |
131 CiTargetMethod targetMethod = asm.finishTargetMethod(name, runtime, registerRestoreEpilogueOffset, true); | |
132 Object stubObject = runtime.registerGlobalStub(targetMethod, name); | |
133 return new GlobalStub(stub, stub.resultKind, stubObject, argsSize, argOffsets, resultOffset); | |
134 } | |
135 | |
136 private CiValue allocateParameterOperand(XirParameter param, int parameterIndex) { | |
137 return new CiAddress(param.kind, AMD64.RSP, argumentIndexToStackOffset(parameterIndex)); | |
138 } | |
139 | |
140 private CiValue allocateResultOperand(XirOperand result) { | |
141 return new CiAddress(result.kind, AMD64.RSP, argumentIndexToStackOffset(0)); | |
142 } | |
143 | |
144 private CiValue allocateOperand(XirTemp temp, ArrayList<CiRegister> allocatableRegisters) { | |
145 if (temp instanceof XirRegister) { | |
146 XirRegister fixed = (XirRegister) temp; | |
147 return fixed.register; | |
148 } | |
149 | |
150 return newRegister(temp.kind, allocatableRegisters); | |
151 } | |
152 | |
153 private CiValue newRegister(CiKind kind, ArrayList<CiRegister> allocatableRegisters) { | |
154 assert kind != CiKind.Float && kind != CiKind.Double; | |
155 assert allocatableRegisters.size() > 0; | |
156 return allocatableRegisters.remove(allocatableRegisters.size() - 1).asValue(kind); | |
157 } | |
158 | |
159 public GlobalStub emit(XirTemplate template, RiRuntime runtime) { | |
160 C1XCompilation compilation = new C1XCompilation(compiler, null, -1, null); | |
161 try { | |
162 return emit(template, compilation); | |
163 } finally { | |
164 compilation.close(); | |
165 } | |
166 } | |
167 | |
168 public GlobalStub emit(XirTemplate template, C1XCompilation compilation) { | |
169 reset(template.resultOperand.kind, getArgumentKinds(template)); | |
170 compilation.initFrameMap(0); | |
171 compilation.frameMap().setFrameSize(frameSize()); | |
172 AMD64LIRAssembler assembler = new AMD64LIRAssembler(compilation); | |
173 asm = assembler.masm; | |
174 | |
175 ArrayList<CiRegister> allocatableRegisters = new ArrayList<CiRegister>(Arrays.asList(compiler.globalStubRegisterConfig.getCategorizedAllocatableRegisters().get(RegisterFlag.CPU))); | |
176 for (XirTemp t : template.temps) { | |
177 if (t instanceof XirRegister) { | |
178 final XirRegister fixed = (XirRegister) t; | |
179 if (fixed.register.isRegister()) { | |
180 allocatableRegisters.remove(fixed.register.asRegister()); | |
181 } | |
182 } | |
183 } | |
184 | |
185 completeSavePrologue(); | |
186 | |
187 CiValue[] operands = new CiValue[template.variableCount]; | |
188 | |
189 XirOperand resultOperand = template.resultOperand; | |
190 | |
191 if (template.allocateResultOperand) { | |
192 CiValue outputOperand = CiValue.IllegalValue; | |
193 // This snippet has a result that must be separately allocated | |
194 // Otherwise it is assumed that the result is part of the inputs | |
195 if (resultOperand.kind != CiKind.Void && resultOperand.kind != CiKind.Illegal) { | |
196 outputOperand = allocateResultOperand(resultOperand); | |
197 assert operands[resultOperand.index] == null; | |
198 } | |
199 operands[resultOperand.index] = outputOperand; | |
200 } | |
201 | |
202 for (XirParameter param : template.parameters) { | |
203 assert !(param instanceof XirConstantOperand) : "constant parameters not supported for stubs"; | |
204 CiValue op = allocateParameterOperand(param, param.parameterIndex); | |
205 assert operands[param.index] == null; | |
206 | |
207 // Is the value destroyed? | |
208 if (template.isParameterDestroyed(param.parameterIndex)) { | |
209 CiValue newOp = newRegister(op.kind, allocatableRegisters); | |
210 assembler.moveOp(op, newOp, op.kind, null, false); | |
211 operands[param.index] = newOp; | |
212 } else { | |
213 operands[param.index] = op; | |
214 } | |
215 } | |
216 | |
217 for (XirConstant c : template.constants) { | |
218 assert operands[c.index] == null; | |
219 operands[c.index] = c.value; | |
220 } | |
221 | |
222 for (XirTemp t : template.temps) { | |
223 CiValue op = allocateOperand(t, allocatableRegisters); | |
224 assert operands[t.index] == null; | |
225 operands[t.index] = op; | |
226 } | |
227 | |
228 for (CiValue operand : operands) { | |
229 assert operand != null; | |
230 } | |
231 | |
232 Label[] labels = new Label[template.labels.length]; | |
233 for (int i = 0; i < labels.length; i++) { | |
234 labels[i] = new Label(); | |
235 } | |
236 | |
237 assert template.marks.length == 0 : "marks not supported in global stubs"; | |
238 assembler.emitXirInstructions(null, template.fastPath, labels, operands, null); | |
239 epilogue(); | |
240 CiTargetMethod targetMethod = asm.finishTargetMethod(template.name, runtime, registerRestoreEpilogueOffset, true); | |
241 Object stubObject = runtime.registerGlobalStub(targetMethod, template.name); | |
242 return new GlobalStub(null, template.resultOperand.kind, stubObject, argsSize, argOffsets, resultOffset); | |
243 } | |
244 | |
245 private CiKind[] getArgumentKinds(XirTemplate template) { | |
246 CiXirAssembler.XirParameter[] params = template.parameters; | |
247 CiKind[] result = new CiKind[params.length]; | |
248 for (int i = 0; i < params.length; i++) { | |
249 result[i] = params[i].kind; | |
250 } | |
251 return result; | |
252 } | |
253 | |
254 private void negatePrologue() { | |
255 partialSavePrologue(negateArgument, negateTemp); | |
256 loadArgument(0, negateArgument); | |
257 } | |
258 | |
259 private void negateEpilogue() { | |
260 storeArgument(0, negateArgument); | |
261 epilogue(); | |
262 } | |
263 | |
264 private void emitDNEG() { | |
265 negatePrologue(); | |
266 asm.movsd(negateTemp, asm.recordDataReferenceInCode(CiConstant.forLong(DoubleSignFlip))); | |
267 asm.xorpd(negateArgument, negateTemp); | |
268 negateEpilogue(); | |
269 } | |
270 | |
271 private void emitFNEG() { | |
272 negatePrologue(); | |
273 asm.movsd(negateTemp, asm.recordDataReferenceInCode(CiConstant.forLong(FloatSignFlip))); | |
274 asm.xorps(negateArgument, negateTemp); | |
275 negateEpilogue(); | |
276 } | |
277 | |
278 private void convertPrologue() { | |
279 partialSavePrologue(convertArgument, convertResult); | |
280 loadArgument(0, convertArgument); | |
281 } | |
282 | |
283 private void convertEpilogue() { | |
284 storeArgument(0, convertResult); | |
285 epilogue(); | |
286 } | |
287 | |
288 private void emitD2L() { | |
289 emitCOMISSD(true, false); | |
290 } | |
291 | |
292 private void emitD2I() { | |
293 emitCOMISSD(true, true); | |
294 } | |
295 | |
296 private void emitF2L() { | |
297 emitCOMISSD(false, false); | |
298 } | |
299 | |
300 private void emitF2I() { | |
301 emitCOMISSD(false, true); | |
302 } | |
303 | |
304 private void emitCOMISSD(boolean isDouble, boolean isInt) { | |
305 convertPrologue(); | |
306 if (isDouble) { | |
307 asm.ucomisd(convertArgument, asm.recordDataReferenceInCode(CiConstant.DOUBLE_0)); | |
308 } else { | |
309 asm.ucomiss(convertArgument, asm.recordDataReferenceInCode(CiConstant.FLOAT_0)); | |
310 } | |
311 Label nan = new Label(); | |
312 Label ret = new Label(); | |
313 asm.jccb(ConditionFlag.parity, nan); | |
314 asm.jccb(ConditionFlag.below, ret); | |
315 | |
316 // input is > 0 -> return maxInt | |
317 // result register already contains 0x80000000, so subtracting 1 gives 0x7fffffff | |
318 asm.decrementl(convertResult, 1); | |
319 asm.jmpb(ret); | |
320 | |
321 // input is NaN -> return 0 | |
322 asm.bind(nan); | |
323 asm.xorptr(convertResult, convertResult); | |
324 | |
325 asm.bind(ret); | |
326 convertEpilogue(); | |
327 } | |
328 | |
329 private void emitStandardForward(GlobalStub.Id stub, CiRuntimeCall call) { | |
330 if (stub != null) { | |
331 assert stub.resultKind == call.resultKind; | |
332 assert stub.arguments.length == call.arguments.length; | |
333 for (int i = 0; i < stub.arguments.length; i++) { | |
334 assert stub.arguments[i] == call.arguments[i]; | |
335 } | |
336 } | |
337 | |
338 completeSavePrologue(); | |
339 forwardRuntimeCall(call); | |
340 epilogue(); | |
341 } | |
342 | |
343 private int argumentIndexToStackOffset(int index) { | |
344 // <-- lower addresses | |
345 // | stub frame | caller frame | | |
346 // | locals,savearea,retaddr | args ..... | | |
347 return frameSize() + (index + 1) * ARGUMENT_SIZE; | |
348 } | |
349 | |
350 private void loadArgument(int index, CiRegister register) { | |
351 asm.movq(register, new CiAddress(CiKind.Word, AMD64.RSP, argumentIndexToStackOffset(index))); | |
352 } | |
353 | |
354 private void storeArgument(int index, CiRegister register) { | |
355 asm.movq(new CiAddress(CiKind.Word, AMD64.RSP, argumentIndexToStackOffset(index)), register); | |
356 } | |
357 | |
358 private void partialSavePrologue(CiRegister... registersToSave) { | |
359 this.registersSaved = registersToSave; | |
360 this.saveSize = registersToSave.length * target.wordSize; | |
361 | |
362 // align to code size | |
363 int entryCodeOffset = runtime.codeOffset(); | |
364 if (entryCodeOffset != 0) { | |
365 asm.nop(entryCodeOffset); | |
366 } | |
367 asm.subq(AMD64.rsp, frameSize()); | |
368 | |
369 int index = 0; | |
370 for (CiRegister r : registersToSave) { | |
371 asm.movq(new CiAddress(CiKind.Word, AMD64.RSP, index * target.arch.wordSize), r); | |
372 index++; | |
373 } | |
374 | |
375 asm.setFrameSize(frameSize()); | |
376 this.savedAllRegisters = false; | |
377 } | |
378 | |
379 private void completeSavePrologue() { | |
380 CiCalleeSaveArea csa = compiler.globalStubRegisterConfig.getCalleeSaveArea(); | |
381 this.saveSize = csa.size; | |
382 int entryCodeOffset = runtime.codeOffset(); | |
383 if (entryCodeOffset != 0) { | |
384 // align to code size | |
385 asm.nop(entryCodeOffset); | |
386 } | |
387 asm.subq(AMD64.rsp, frameSize()); | |
388 asm.setFrameSize(frameSize()); | |
389 int frameToCSA = 0; | |
390 asm.save(csa, frameToCSA); | |
391 this.savedAllRegisters = true; | |
392 } | |
393 | |
394 private void epilogue() { | |
395 assert registerRestoreEpilogueOffset == -1; | |
396 registerRestoreEpilogueOffset = asm.codeBuffer.position(); | |
397 | |
398 if (savedAllRegisters) { | |
399 CiCalleeSaveArea csa = compiler.globalStubRegisterConfig.getCalleeSaveArea(); | |
400 int frameToCSA = 0; | |
401 asm.restore(csa, frameToCSA); | |
402 } else { | |
403 // saved only select registers | |
404 for (int index = 0; index < registersSaved.length; index++) { | |
405 CiRegister r = registersSaved[index]; | |
406 asm.movq(r, new CiAddress(CiKind.Word, AMD64.RSP, index * target.wordSize)); | |
407 } | |
408 registersSaved = null; | |
409 } | |
410 | |
411 // Restore rsp | |
412 asm.addq(AMD64.rsp, frameSize()); | |
413 asm.ret(0); | |
414 } | |
415 | |
416 private int frameSize() { | |
417 return target.alignFrameSize(saveSize); | |
418 } | |
419 | |
420 private void forwardRuntimeCall(CiRuntimeCall call) { | |
421 // Load arguments | |
422 CiCallingConvention cc = compiler.globalStubRegisterConfig.getCallingConvention(RuntimeCall, call.arguments, target); | |
423 for (int i = 0; i < cc.locations.length; ++i) { | |
424 CiValue location = cc.locations[i]; | |
425 loadArgument(i, location.asRegister()); | |
426 } | |
427 | |
428 // Call to the runtime | |
429 asm.directCall(call, null); | |
430 | |
431 if (call.resultKind != CiKind.Void) { | |
432 CiRegister returnRegister = compiler.globalStubRegisterConfig.getReturnRegister(call.resultKind); | |
433 this.storeArgument(0, returnRegister); | |
434 } | |
435 } | |
436 } |