Mercurial > hg > graal-compiler
comparison graal/GraalCompiler/src/com/sun/c1x/target/amd64/AMD64LIRGenerator.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/AMD64LIRGenerator.java@9ec15d6914ca |
children | 4fdef1464592 |
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 | |
24 package com.sun.c1x.target.amd64; | |
25 | |
26 import static com.sun.cri.bytecode.Bytecodes.UnsignedComparisons.*; | |
27 | |
28 import com.sun.c1x.*; | |
29 import com.sun.c1x.alloc.OperandPool.VariableFlag; | |
30 import com.sun.c1x.gen.*; | |
31 import com.sun.c1x.globalstub.*; | |
32 import com.sun.c1x.ir.*; | |
33 import com.sun.c1x.lir.*; | |
34 import com.sun.c1x.util.*; | |
35 import com.sun.cri.bytecode.*; | |
36 import com.sun.cri.ci.*; | |
37 | |
38 /** | |
39 * This class implements the X86-specific portion of the LIR generator. | |
40 * | |
41 * @author Thomas Wuerthinger | |
42 * @author Ben L. Titzer | |
43 */ | |
44 public class AMD64LIRGenerator extends LIRGenerator { | |
45 | |
46 private static final CiRegisterValue RAX_I = AMD64.rax.asValue(CiKind.Int); | |
47 private static final CiRegisterValue RAX_L = AMD64.rax.asValue(CiKind.Long); | |
48 private static final CiRegisterValue RAX_W = AMD64.rax.asValue(CiKind.Word); | |
49 private static final CiRegisterValue RDX_I = AMD64.rdx.asValue(CiKind.Int); | |
50 private static final CiRegisterValue RDX_L = AMD64.rdx.asValue(CiKind.Long); | |
51 | |
52 private static final CiRegisterValue LDIV_TMP = RDX_L; | |
53 | |
54 | |
55 /** | |
56 * The register in which MUL puts the result for 64-bit multiplication. | |
57 */ | |
58 private static final CiRegisterValue LMUL_OUT = RAX_L; | |
59 | |
60 private static final CiRegisterValue SHIFT_COUNT_IN = AMD64.rcx.asValue(CiKind.Int); | |
61 | |
62 protected static final CiValue ILLEGAL = CiValue.IllegalValue; | |
63 | |
64 public AMD64LIRGenerator(C1XCompilation compilation) { | |
65 super(compilation); | |
66 } | |
67 | |
68 @Override | |
69 protected CiValue exceptionPcOpr() { | |
70 return ILLEGAL; | |
71 } | |
72 | |
73 @Override | |
74 protected boolean canStoreAsConstant(Value v, CiKind kind) { | |
75 if (kind == CiKind.Short || kind == CiKind.Char) { | |
76 // there is no immediate move of word values in asemblerI486.?pp | |
77 return false; | |
78 } | |
79 return v instanceof Constant; | |
80 } | |
81 | |
82 @Override | |
83 protected boolean canInlineAsConstant(Value v) { | |
84 if (v.kind == CiKind.Long) { | |
85 if (v.isConstant() && Util.isInt(v.asConstant().asLong())) { | |
86 return true; | |
87 } | |
88 return false; | |
89 } | |
90 return v.kind != CiKind.Object || v.isNullConstant(); | |
91 } | |
92 | |
93 @Override | |
94 protected CiAddress genAddress(CiValue base, CiValue index, int shift, int disp, CiKind kind) { | |
95 assert base.isVariableOrRegister(); | |
96 if (index.isConstant()) { | |
97 return new CiAddress(kind, base, (((CiConstant) index).asInt() << shift) + disp); | |
98 } else { | |
99 assert index.isVariableOrRegister(); | |
100 return new CiAddress(kind, base, (index), CiAddress.Scale.fromShift(shift), disp); | |
101 } | |
102 } | |
103 | |
104 @Override | |
105 protected void genCmpMemInt(Condition condition, CiValue base, int disp, int c, LIRDebugInfo info) { | |
106 lir.cmpMemInt(condition, base, disp, c, info); | |
107 } | |
108 | |
109 @Override | |
110 protected void genCmpRegMem(Condition condition, CiValue reg, CiValue base, int disp, CiKind kind, LIRDebugInfo info) { | |
111 lir.cmpRegMem(condition, reg, new CiAddress(kind, base, disp), info); | |
112 } | |
113 | |
114 @Override | |
115 protected boolean strengthReduceMultiply(CiValue left, int c, CiValue result, CiValue tmp) { | |
116 if (tmp.isLegal()) { | |
117 if (CiUtil.isPowerOf2(c + 1)) { | |
118 lir.move(left, tmp); | |
119 lir.shiftLeft(left, CiUtil.log2(c + 1), left); | |
120 lir.sub(left, tmp, result); | |
121 return true; | |
122 } else if (CiUtil.isPowerOf2(c - 1)) { | |
123 lir.move(left, tmp); | |
124 lir.shiftLeft(left, CiUtil.log2(c - 1), left); | |
125 lir.add(left, tmp, result); | |
126 return true; | |
127 } | |
128 } | |
129 return false; | |
130 } | |
131 | |
132 @Override | |
133 public void visitNegateOp(NegateOp x) { | |
134 LIRItem value = new LIRItem(x.x(), this); | |
135 value.setDestroysRegister(); | |
136 value.loadItem(); | |
137 CiVariable reg = newVariable(x.kind); | |
138 GlobalStub globalStub = null; | |
139 if (x.kind == CiKind.Float) { | |
140 globalStub = stubFor(GlobalStub.Id.fneg); | |
141 } else if (x.kind == CiKind.Double) { | |
142 globalStub = stubFor(GlobalStub.Id.dneg); | |
143 } | |
144 lir.negate(value.result(), reg, globalStub); | |
145 setResult(x, reg); | |
146 } | |
147 | |
148 @Override | |
149 public void visitSignificantBit(SignificantBitOp x) { | |
150 LIRItem value = new LIRItem(x.value(), this); | |
151 value.setDestroysRegister(); | |
152 value.loadItem(); | |
153 CiValue reg = createResultVariable(x); | |
154 if (x.op == Bytecodes.LSB) { | |
155 lir.lsb(value.result(), reg); | |
156 } else { | |
157 lir.msb(value.result(), reg); | |
158 } | |
159 } | |
160 | |
161 public boolean livesLonger(Value x, Value y) { | |
162 BlockBegin bx = x.block(); | |
163 BlockBegin by = y.block(); | |
164 if (bx == null || by == null) { | |
165 return false; | |
166 } | |
167 return bx.loopDepth() < by.loopDepth(); | |
168 } | |
169 | |
170 public void visitArithmeticOpFloat(ArithmeticOp x) { | |
171 LIRItem left = new LIRItem(x.x(), this); | |
172 LIRItem right = new LIRItem(x.y(), this); | |
173 assert !left.isStack() || !right.isStack() : "can't both be memory operands"; | |
174 boolean mustLoadBoth = (x.opcode == Bytecodes.FREM || x.opcode == Bytecodes.DREM); | |
175 | |
176 // Both are in register, swap operands such that the short-living one is on the left side. | |
177 if (x.isCommutative() && left.isRegisterOrVariable() && right.isRegisterOrVariable()) { | |
178 if (livesLonger(x.x(), x.y())) { | |
179 LIRItem tmp = left; | |
180 left = right; | |
181 right = tmp; | |
182 } | |
183 } | |
184 | |
185 if (left.isRegisterOrVariable() || x.x().isConstant() || mustLoadBoth) { | |
186 left.loadItem(); | |
187 } | |
188 | |
189 if (mustLoadBoth) { | |
190 // frem and drem destroy also right operand, so move it to a new register | |
191 right.setDestroysRegister(); | |
192 right.loadItem(); | |
193 } else if (right.isRegisterOrVariable()) { | |
194 right.loadItem(); | |
195 } | |
196 | |
197 CiVariable reg; | |
198 | |
199 if (x.opcode == Bytecodes.FREM) { | |
200 reg = callRuntimeWithResult(CiRuntimeCall.ArithmeticFrem, null, left.result(), right.result()); | |
201 } else if (x.opcode == Bytecodes.DREM) { | |
202 reg = callRuntimeWithResult(CiRuntimeCall.ArithmeticDrem, null, left.result(), right.result()); | |
203 } else { | |
204 reg = newVariable(x.kind); | |
205 arithmeticOpFpu(x.opcode, reg, left.result(), right.result(), ILLEGAL); | |
206 } | |
207 | |
208 setResult(x, reg); | |
209 } | |
210 | |
211 public void visitArithmeticOpLong(ArithmeticOp x) { | |
212 int opcode = x.opcode; | |
213 if (opcode == Bytecodes.LDIV || opcode == Bytecodes.LREM) { | |
214 // emit inline 64-bit code | |
215 LIRDebugInfo info = x.needsZeroCheck() ? stateFor(x) : null; | |
216 CiValue dividend = force(x.x(), RAX_L); // dividend must be in RAX | |
217 CiValue divisor = load(x.y()); // divisor can be in any (other) register | |
218 | |
219 CiValue result = createResultVariable(x); | |
220 CiValue resultReg; | |
221 if (opcode == Bytecodes.LREM) { | |
222 resultReg = RDX_L; // remainder result is produced in rdx | |
223 lir.lrem(dividend, divisor, resultReg, LDIV_TMP, info); | |
224 } else { | |
225 resultReg = RAX_L; // division result is produced in rax | |
226 lir.ldiv(dividend, divisor, resultReg, LDIV_TMP, info); | |
227 } | |
228 | |
229 lir.move(resultReg, result); | |
230 } else if (opcode == Bytecodes.LMUL) { | |
231 LIRItem right = new LIRItem(x.y(), this); | |
232 | |
233 // right register is destroyed by the long mul, so it must be | |
234 // copied to a new register. | |
235 right.setDestroysRegister(); | |
236 | |
237 CiValue left = load(x.x()); | |
238 right.loadItem(); | |
239 | |
240 arithmeticOpLong(opcode, LMUL_OUT, left, right.result(), null); | |
241 CiValue result = createResultVariable(x); | |
242 lir.move(LMUL_OUT, result); | |
243 } else { | |
244 LIRItem right = new LIRItem(x.y(), this); | |
245 | |
246 CiValue left = load(x.x()); | |
247 // don't load constants to save register | |
248 right.loadNonconstant(); | |
249 createResultVariable(x); | |
250 arithmeticOpLong(opcode, x.operand(), left, right.result(), null); | |
251 } | |
252 } | |
253 | |
254 public void visitArithmeticOpInt(ArithmeticOp x) { | |
255 int opcode = x.opcode; | |
256 if (opcode == Bytecodes.IDIV || opcode == Bytecodes.IREM) { | |
257 // emit code for integer division or modulus | |
258 | |
259 // Call 'stateFor' before 'force()' because 'stateFor()' may | |
260 // force the evaluation of other instructions that are needed for | |
261 // correct debug info. Otherwise the live range of the fixed | |
262 // register might be too long. | |
263 LIRDebugInfo info = x.needsZeroCheck() ? stateFor(x) : null; | |
264 | |
265 CiValue dividend = force(x.x(), RAX_I); // dividend must be in RAX | |
266 CiValue divisor = load(x.y()); // divisor can be in any (other) register | |
267 | |
268 // idiv and irem use rdx in their implementation so the | |
269 // register allocator must not assign it to an interval that overlaps | |
270 // this division instruction. | |
271 CiRegisterValue tmp = RDX_I; | |
272 | |
273 CiValue result = createResultVariable(x); | |
274 CiValue resultReg; | |
275 if (opcode == Bytecodes.IREM) { | |
276 resultReg = tmp; // remainder result is produced in rdx | |
277 lir.irem(dividend, divisor, resultReg, tmp, info); | |
278 } else { | |
279 resultReg = RAX_I; // division result is produced in rax | |
280 lir.idiv(dividend, divisor, resultReg, tmp, info); | |
281 } | |
282 | |
283 lir.move(resultReg, result); | |
284 } else { | |
285 // emit code for other integer operations | |
286 LIRItem left = new LIRItem(x.x(), this); | |
287 LIRItem right = new LIRItem(x.y(), this); | |
288 LIRItem leftArg = left; | |
289 LIRItem rightArg = right; | |
290 if (x.isCommutative() && left.isStack() && right.isRegisterOrVariable()) { | |
291 // swap them if left is real stack (or cached) and right is real register(not cached) | |
292 leftArg = right; | |
293 rightArg = left; | |
294 } | |
295 | |
296 leftArg.loadItem(); | |
297 | |
298 // do not need to load right, as we can handle stack and constants | |
299 if (opcode == Bytecodes.IMUL) { | |
300 // check if we can use shift instead | |
301 boolean useConstant = false; | |
302 boolean useTmp = false; | |
303 if (rightArg.result().isConstant()) { | |
304 int iconst = rightArg.instruction.asConstant().asInt(); | |
305 if (iconst > 0) { | |
306 if (CiUtil.isPowerOf2(iconst)) { | |
307 useConstant = true; | |
308 } else if (CiUtil.isPowerOf2(iconst - 1) || CiUtil.isPowerOf2(iconst + 1)) { | |
309 useConstant = true; | |
310 useTmp = true; | |
311 } | |
312 } | |
313 } | |
314 if (!useConstant) { | |
315 rightArg.loadItem(); | |
316 } | |
317 CiValue tmp = ILLEGAL; | |
318 if (useTmp) { | |
319 tmp = newVariable(CiKind.Int); | |
320 } | |
321 createResultVariable(x); | |
322 | |
323 arithmeticOpInt(opcode, x.operand(), leftArg.result(), rightArg.result(), tmp); | |
324 } else { | |
325 createResultVariable(x); | |
326 CiValue tmp = ILLEGAL; | |
327 arithmeticOpInt(opcode, x.operand(), leftArg.result(), rightArg.result(), tmp); | |
328 } | |
329 } | |
330 } | |
331 | |
332 public void visitArithmeticOpWord(ArithmeticOp x) { | |
333 int opcode = x.opcode; | |
334 if (opcode == Bytecodes.WDIV || opcode == Bytecodes.WREM || opcode == Bytecodes.WDIVI || opcode == Bytecodes.WREMI) { | |
335 // emit code for long division or modulus | |
336 // emit inline 64-bit code | |
337 LIRDebugInfo info = x.needsZeroCheck() ? stateFor(x) : null; | |
338 CiValue dividend = force(x.x(), RAX_L); // dividend must be in RAX | |
339 CiValue divisor = load(x.y()); // divisor can be in any (other) register | |
340 | |
341 CiValue result = createResultVariable(x); | |
342 CiValue resultReg; | |
343 if (opcode == Bytecodes.WREM) { | |
344 resultReg = RDX_L; // remainder result is produced in rdx | |
345 lir.wrem(dividend, divisor, resultReg, LDIV_TMP, info); | |
346 } else if (opcode == Bytecodes.WREMI) { | |
347 resultReg = RDX_L; // remainder result is produced in rdx | |
348 lir.wremi(dividend, divisor, resultReg, LDIV_TMP, info); | |
349 } else if (opcode == Bytecodes.WDIV) { | |
350 resultReg = RAX_L; // division result is produced in rax | |
351 lir.wdiv(dividend, divisor, resultReg, LDIV_TMP, info); | |
352 } else { | |
353 assert opcode == Bytecodes.WDIVI; | |
354 resultReg = RAX_L; // division result is produced in rax | |
355 lir.wdivi(dividend, divisor, resultReg, LDIV_TMP, info); | |
356 } | |
357 | |
358 lir.move(resultReg, result); | |
359 } else if (opcode == Bytecodes.LMUL) { | |
360 LIRItem right = new LIRItem(x.y(), this); | |
361 | |
362 // right register is destroyed by the long mul, so it must be | |
363 // copied to a new register. | |
364 right.setDestroysRegister(); | |
365 | |
366 CiValue left = load(x.x()); | |
367 right.loadItem(); | |
368 | |
369 CiValue reg = LMUL_OUT; | |
370 arithmeticOpLong(opcode, reg, left, right.result(), null); | |
371 CiValue result = createResultVariable(x); | |
372 lir.move(reg, result); | |
373 } else { | |
374 LIRItem right = new LIRItem(x.y(), this); | |
375 | |
376 CiValue left = load(x.x()); | |
377 // don't load constants to save register | |
378 right.loadNonconstant(); | |
379 createResultVariable(x); | |
380 arithmeticOpLong(opcode, x.operand(), left, right.result(), null); | |
381 } | |
382 } | |
383 | |
384 @Override | |
385 public void visitArithmeticOp(ArithmeticOp x) { | |
386 trySwap(x); | |
387 | |
388 if (x.kind.isWord() || x.opcode == Bytecodes.WREMI) { | |
389 visitArithmeticOpWord(x); | |
390 return; | |
391 } | |
392 | |
393 assert Util.archKindsEqual(x.x().kind, x.kind) && Util.archKindsEqual(x.y().kind, x.kind) : "wrong parameter types: " + Bytecodes.nameOf(x.opcode); | |
394 switch (x.kind) { | |
395 case Float: | |
396 case Double: | |
397 visitArithmeticOpFloat(x); | |
398 return; | |
399 case Long: | |
400 visitArithmeticOpLong(x); | |
401 return; | |
402 case Int: | |
403 visitArithmeticOpInt(x); | |
404 return; | |
405 } | |
406 throw Util.shouldNotReachHere(); | |
407 } | |
408 | |
409 @Override | |
410 public void visitShiftOp(ShiftOp x) { | |
411 // count must always be in rcx | |
412 CiValue count = makeOperand(x.y()); | |
413 boolean mustLoadCount = !count.isConstant() || x.kind == CiKind.Long; | |
414 if (mustLoadCount) { | |
415 // count for long must be in register | |
416 count = force(x.y(), SHIFT_COUNT_IN); | |
417 } | |
418 | |
419 CiValue value = load(x.x()); | |
420 CiValue reg = createResultVariable(x); | |
421 | |
422 shiftOp(x.opcode, reg, value, count, ILLEGAL); | |
423 } | |
424 | |
425 @Override | |
426 public void visitLogicOp(LogicOp x) { | |
427 trySwap(x); | |
428 | |
429 LIRItem right = new LIRItem(x.y(), this); | |
430 | |
431 CiValue left = load(x.x()); | |
432 right.loadNonconstant(); | |
433 CiValue reg = createResultVariable(x); | |
434 | |
435 logicOp(x.opcode, reg, left, right.result()); | |
436 } | |
437 | |
438 private void trySwap(Op2 x) { | |
439 // (tw) TODO: Check what this is for? | |
440 } | |
441 | |
442 @Override | |
443 public void visitCompareOp(CompareOp x) { | |
444 LIRItem left = new LIRItem(x.x(), this); | |
445 LIRItem right = new LIRItem(x.y(), this); | |
446 if (!x.kind.isVoid() && x.x().kind.isLong()) { | |
447 left.setDestroysRegister(); | |
448 } | |
449 left.loadItem(); | |
450 right.loadItem(); | |
451 | |
452 if (x.kind.isVoid()) { | |
453 lir.cmp(Condition.TRUE, left.result(), right.result()); | |
454 } else if (x.x().kind.isFloat() || x.x().kind.isDouble()) { | |
455 CiValue reg = createResultVariable(x); | |
456 int code = x.opcode; | |
457 lir.fcmp2int(left.result(), right.result(), reg, (code == Bytecodes.FCMPL || code == Bytecodes.DCMPL)); | |
458 } else if (x.x().kind.isLong() || x.x().kind.isWord()) { | |
459 CiValue reg = createResultVariable(x); | |
460 lir.lcmp2int(left.result(), right.result(), reg); | |
461 } else { | |
462 Util.unimplemented(); | |
463 } | |
464 } | |
465 | |
466 @Override | |
467 public void visitUnsignedCompareOp(UnsignedCompareOp x) { | |
468 LIRItem left = new LIRItem(x.x(), this); | |
469 LIRItem right = new LIRItem(x.y(), this); | |
470 left.loadItem(); | |
471 right.loadItem(); | |
472 Condition condition = null; | |
473 switch (x.op) { | |
474 case BELOW_THAN : condition = Condition.BT; break; | |
475 case ABOVE_THAN : condition = Condition.AT; break; | |
476 case BELOW_EQUAL : condition = Condition.BE; break; | |
477 case ABOVE_EQUAL : condition = Condition.AE; break; | |
478 default: | |
479 Util.unimplemented(); | |
480 } | |
481 CiValue result = createResultVariable(x); | |
482 lir.cmp(condition, left.result(), right.result()); | |
483 lir.cmove(condition, CiConstant.INT_1, CiConstant.INT_0, result); | |
484 } | |
485 | |
486 @Override | |
487 public void visitCompareAndSwap(CompareAndSwap x) { | |
488 | |
489 // (tw) TODO: Factor out common code with genCompareAndSwap. | |
490 | |
491 CiKind dataKind = x.dataKind; | |
492 CiValue tempPointer = load(x.pointer()); | |
493 CiAddress addr = getAddressForPointerOp(x, dataKind, tempPointer); | |
494 | |
495 CiValue expectedValue = force(x.expectedValue(), AMD64.rax.asValue(dataKind)); | |
496 CiValue newValue = load(x.newValue()); | |
497 assert Util.archKindsEqual(newValue.kind, dataKind) : "invalid type"; | |
498 | |
499 if (dataKind.isObject()) { // Write-barrier needed for Object fields. | |
500 // Do the pre-write barrier : if any. | |
501 preGCWriteBarrier(addr, false, null); | |
502 } | |
503 | |
504 CiValue pointer = newVariable(CiKind.Word); | |
505 lir.lea(addr, pointer); | |
506 CiValue result = createResultVariable(x); | |
507 CiValue resultReg = AMD64.rax.asValue(dataKind); | |
508 if (dataKind.isObject()) { | |
509 lir.casObj(pointer, expectedValue, newValue); | |
510 } else if (dataKind.isInt()) { | |
511 lir.casInt(pointer, expectedValue, newValue); | |
512 } else { | |
513 assert dataKind.isLong() || dataKind.isWord(); | |
514 lir.casLong(pointer, expectedValue, newValue); | |
515 } | |
516 | |
517 lir.move(resultReg, result); | |
518 | |
519 if (dataKind.isObject()) { // Write-barrier needed for Object fields. | |
520 // Seems to be precise | |
521 postGCWriteBarrier(pointer, newValue); | |
522 } | |
523 } | |
524 | |
525 @Override | |
526 protected void genCompareAndSwap(Intrinsic x, CiKind kind) { | |
527 assert x.numberOfArguments() == 5 : "wrong number of arguments: " + x.numberOfArguments(); | |
528 // Argument 0 is the receiver. | |
529 LIRItem obj = new LIRItem(x.argumentAt(1), this); // object | |
530 LIRItem offset = new LIRItem(x.argumentAt(2), this); // offset of field | |
531 LIRItem val = new LIRItem(x.argumentAt(4), this); // replace field with val if matches cmp | |
532 | |
533 assert obj.instruction.kind.isObject() : "invalid type"; | |
534 | |
535 assert val.instruction.kind == kind : "invalid type"; | |
536 | |
537 // get address of field | |
538 obj.loadItem(); | |
539 offset.loadNonconstant(); | |
540 CiAddress addr; | |
541 if (offset.result().isConstant()) { | |
542 addr = new CiAddress(kind, obj.result(), (int) ((CiConstant) offset.result()).asLong()); | |
543 } else { | |
544 addr = new CiAddress(kind, obj.result(), offset.result()); | |
545 } | |
546 | |
547 // Compare operand needs to be in RAX. | |
548 CiValue cmp = force(x.argumentAt(3), AMD64.rax.asValue(kind)); | |
549 val.loadItem(); | |
550 | |
551 CiValue pointer = newVariable(CiKind.Word); | |
552 lir.lea(addr, pointer); | |
553 | |
554 if (kind.isObject()) { // Write-barrier needed for Object fields. | |
555 // Do the pre-write barrier : if any. | |
556 preGCWriteBarrier(pointer, false, null); | |
557 } | |
558 | |
559 if (kind.isObject()) { | |
560 lir.casObj(pointer, cmp, val.result()); | |
561 } else if (kind.isInt()) { | |
562 lir.casInt(pointer, cmp, val.result()); | |
563 } else if (kind.isLong()) { | |
564 lir.casLong(pointer, cmp, val.result()); | |
565 } else { | |
566 Util.shouldNotReachHere(); | |
567 } | |
568 | |
569 // generate conditional move of boolean result | |
570 CiValue result = createResultVariable(x); | |
571 lir.cmove(Condition.EQ, CiConstant.INT_1, CiConstant.INT_0, result); | |
572 if (kind.isObject()) { // Write-barrier needed for Object fields. | |
573 // Seems to be precise | |
574 postGCWriteBarrier(pointer, val.result()); | |
575 } | |
576 } | |
577 | |
578 @Override | |
579 protected void genMathIntrinsic(Intrinsic x) { | |
580 assert x.numberOfArguments() == 1 : "wrong type"; | |
581 | |
582 CiValue calcInput = load(x.argumentAt(0)); | |
583 | |
584 switch (x.intrinsic()) { | |
585 case java_lang_Math$abs: | |
586 lir.abs(calcInput, createResultVariable(x), ILLEGAL); | |
587 break; | |
588 case java_lang_Math$sqrt: | |
589 lir.sqrt(calcInput, createResultVariable(x), ILLEGAL); | |
590 break; | |
591 case java_lang_Math$sin: | |
592 setResult(x, callRuntimeWithResult(CiRuntimeCall.ArithmeticSin, null, calcInput)); | |
593 break; | |
594 case java_lang_Math$cos: | |
595 setResult(x, callRuntimeWithResult(CiRuntimeCall.ArithmeticCos, null, calcInput)); | |
596 break; | |
597 case java_lang_Math$tan: | |
598 setResult(x, callRuntimeWithResult(CiRuntimeCall.ArithmeticTan, null, calcInput)); | |
599 break; | |
600 case java_lang_Math$log: | |
601 setResult(x, callRuntimeWithResult(CiRuntimeCall.ArithmeticLog, null, calcInput)); | |
602 break; | |
603 case java_lang_Math$log10: | |
604 setResult(x, callRuntimeWithResult(CiRuntimeCall.ArithmeticLog10, null, calcInput)); | |
605 break; | |
606 default: | |
607 Util.shouldNotReachHere("Unknown math intrinsic"); | |
608 } | |
609 } | |
610 | |
611 @Override | |
612 public void visitConvert(Convert x) { | |
613 CiValue input = load(x.value()); | |
614 CiVariable result = newVariable(x.kind); | |
615 // arguments of lirConvert | |
616 GlobalStub globalStub = null; | |
617 switch (x.opcode) { | |
618 case Bytecodes.F2I: globalStub = stubFor(GlobalStub.Id.f2i); break; | |
619 case Bytecodes.F2L: globalStub = stubFor(GlobalStub.Id.f2l); break; | |
620 case Bytecodes.D2I: globalStub = stubFor(GlobalStub.Id.d2i); break; | |
621 case Bytecodes.D2L: globalStub = stubFor(GlobalStub.Id.d2l); break; | |
622 } | |
623 if (globalStub != null) { | |
624 // Force result to be rax to match global stubs expectation. | |
625 CiValue stubResult = x.kind == CiKind.Int ? RAX_I : RAX_L; | |
626 lir.convert(x.opcode, input, stubResult, globalStub); | |
627 lir.move(stubResult, result); | |
628 } else { | |
629 lir.convert(x.opcode, input, result, globalStub); | |
630 } | |
631 setResult(x, result); | |
632 } | |
633 | |
634 @Override | |
635 public void visitBlockBegin(BlockBegin x) { | |
636 // nothing to do for now | |
637 } | |
638 | |
639 @Override | |
640 public void visitIf(If x) { | |
641 CiKind kind = x.x().kind; | |
642 | |
643 Condition cond = x.condition(); | |
644 | |
645 LIRItem xitem = new LIRItem(x.x(), this); | |
646 LIRItem yitem = new LIRItem(x.y(), this); | |
647 LIRItem xin = xitem; | |
648 LIRItem yin = yitem; | |
649 | |
650 if (kind.isLong()) { | |
651 // for longs, only conditions "eql", "neq", "lss", "geq" are valid; | |
652 // mirror for other conditions | |
653 if (cond == Condition.GT || cond == Condition.LE) { | |
654 cond = cond.mirror(); | |
655 xin = yitem; | |
656 yin = xitem; | |
657 } | |
658 xin.setDestroysRegister(); | |
659 } | |
660 xin.loadItem(); | |
661 if (kind.isLong() && yin.result().isConstant() && yin.instruction.asConstant().asLong() == 0 && (cond == Condition.EQ || cond == Condition.NE)) { | |
662 // dont load item | |
663 } else if (kind.isLong() || kind.isFloat() || kind.isDouble()) { | |
664 // longs cannot handle constants at right side | |
665 yin.loadItem(); | |
666 } | |
667 | |
668 // add safepoint before generating condition code so it can be recomputed | |
669 if (x.isSafepoint()) { | |
670 emitXir(xir.genSafepoint(site(x)), x, stateFor(x, x.stateAfter()), null, false); | |
671 } | |
672 setNoResult(x); | |
673 | |
674 CiValue left = xin.result(); | |
675 CiValue right = yin.result(); | |
676 lir.cmp(cond, left, right); | |
677 moveToPhi(x.stateAfter()); | |
678 if (x.x().kind.isFloat() || x.x().kind.isDouble()) { | |
679 lir.branch(cond, right.kind, x.trueSuccessor(), x.unorderedSuccessor()); | |
680 } else { | |
681 lir.branch(cond, right.kind, x.trueSuccessor()); | |
682 } | |
683 assert x.defaultSuccessor() == x.falseSuccessor() : "wrong destination above"; | |
684 lir.jump(x.defaultSuccessor()); | |
685 } | |
686 | |
687 @Override | |
688 protected void genGetObjectUnsafe(CiValue dst, CiValue src, CiValue offset, CiKind kind, boolean isVolatile) { | |
689 if (isVolatile && kind == CiKind.Long) { | |
690 CiAddress addr = new CiAddress(CiKind.Double, src, offset); | |
691 CiValue tmp = newVariable(CiKind.Double); | |
692 lir.load(addr, tmp, null); | |
693 CiValue spill = operands.newVariable(CiKind.Long, VariableFlag.MustStartInMemory); | |
694 lir.move(tmp, spill); | |
695 lir.move(spill, dst); | |
696 } else { | |
697 CiAddress addr = new CiAddress(kind, src, offset); | |
698 lir.load(addr, dst, null); | |
699 } | |
700 } | |
701 | |
702 @Override | |
703 protected void genPutObjectUnsafe(CiValue src, CiValue offset, CiValue data, CiKind kind, boolean isVolatile) { | |
704 if (isVolatile && kind == CiKind.Long) { | |
705 CiAddress addr = new CiAddress(CiKind.Double, src, offset); | |
706 CiValue tmp = newVariable(CiKind.Double); | |
707 CiValue spill = operands.newVariable(CiKind.Double, VariableFlag.MustStartInMemory); | |
708 lir.move(data, spill); | |
709 lir.move(spill, tmp); | |
710 lir.move(tmp, addr); | |
711 } else { | |
712 CiAddress addr = new CiAddress(kind, src, offset); | |
713 boolean isObj = (kind == CiKind.Jsr || kind == CiKind.Object); | |
714 if (isObj) { | |
715 // Do the pre-write barrier, if any. | |
716 preGCWriteBarrier(addr, false, null); | |
717 lir.move(data, addr); | |
718 assert src.isVariableOrRegister() : "must be register"; | |
719 // Seems to be a precise address | |
720 postGCWriteBarrier(addr, data); | |
721 } else { | |
722 lir.move(data, addr); | |
723 } | |
724 } | |
725 } | |
726 | |
727 @Override | |
728 protected CiValue osrBufferPointer() { | |
729 return Util.nonFatalUnimplemented(null); | |
730 } | |
731 | |
732 @Override | |
733 public void visitBoundsCheck(BoundsCheck boundsCheck) { | |
734 Value x = boundsCheck.index(); | |
735 Value y = boundsCheck.length(); | |
736 CiValue left = load(x); | |
737 CiValue right = null; | |
738 if (y.isConstant()) { | |
739 right = makeOperand(y); | |
740 } else { | |
741 right = load(y); | |
742 } | |
743 lir.cmp(boundsCheck.condition.negate(), left, right); | |
744 emitGuard(boundsCheck); | |
745 } | |
746 } |