comparison graal/GraalCompiler/src/com/sun/c1x/target/amd64/AMD64GlobalStubEmitter.java @ 2509:16b9a8b5ad39

Renamings Runtime=>GraalRuntime and Compiler=>GraalCompiler
author Thomas Wuerthinger <thomas@wuerthinger.net>
date Wed, 27 Apr 2011 11:50:44 +0200
parents graal/Compiler/src/com/sun/c1x/target/amd64/AMD64GlobalStubEmitter.java@9ec15d6914ca
children 0ea5f12e873a
comparison
equal deleted inserted replaced
2508:fea94949e0a2 2509:16b9a8b5ad39
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 }