comparison graal/Compiler/src/com/sun/c1x/target/amd64/AMD64LIRGenerator.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
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 }