comparison graal/com.oracle.max.graal.compiler/src/com/sun/c1x/target/amd64/AMD64LIRAssembler.java @ 2872:0341b6424579

Project renaming.
author Thomas Wuerthinger <thomas@wuerthinger.net>
date Wed, 08 Jun 2011 08:42:25 +0200
parents graal/GraalCompiler/src/com/sun/c1x/target/amd64/AMD64LIRAssembler.java@1cd59ca9ac86
children
comparison
equal deleted inserted replaced
2871:d704eb526603 2872:0341b6424579
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.bytecode.Bytecodes.*;
26 import static com.sun.cri.ci.CiCallingConvention.Type.*;
27 import static com.sun.cri.ci.CiRegister.*;
28 import static com.sun.cri.ci.CiValue.*;
29 import static java.lang.Double.*;
30 import static java.lang.Float.*;
31
32 import java.util.*;
33
34 import com.oracle.max.asm.*;
35 import com.oracle.max.asm.target.amd64.*;
36 import com.oracle.max.asm.target.amd64.AMD64Assembler.*;
37 import com.sun.c1x.*;
38 import com.sun.c1x.debug.*;
39 import com.sun.c1x.gen.LIRGenerator.*;
40 import com.sun.c1x.globalstub.*;
41 import com.sun.c1x.ir.*;
42 import com.sun.c1x.lir.*;
43 import com.sun.c1x.lir.FrameMap.*;
44 import com.sun.c1x.util.*;
45 import com.sun.cri.ci.*;
46 import com.sun.cri.ci.CiAddress.*;
47 import com.sun.cri.ci.CiTargetMethod.*;
48 import com.sun.cri.xir.*;
49 import com.sun.cri.xir.CiXirAssembler.*;
50
51 /**
52 * This class implements the x86-specific code generation for LIR.
53 */
54 public final class AMD64LIRAssembler extends LIRAssembler {
55
56 private static final Object[] NO_PARAMS = new Object[0];
57 private static final long NULLWORD = 0;
58 private static final CiRegister SHIFTCount = AMD64.rcx;
59
60 private static final long DoubleSignMask = 0x7FFFFFFFFFFFFFFFL;
61
62 final CiTarget target;
63 final AMD64MacroAssembler masm;
64 final int wordSize;
65 final CiRegister rscratch1;
66
67 public AMD64LIRAssembler(C1XCompilation compilation) {
68 super(compilation);
69 masm = (AMD64MacroAssembler) asm;
70 target = compilation.target;
71 wordSize = target.wordSize;
72 rscratch1 = compilation.registerConfig.getScratchRegister();
73 }
74
75 private CiAddress asAddress(CiValue value) {
76 if (value.isAddress()) {
77 return (CiAddress) value;
78 }
79 assert value.isStackSlot();
80 return compilation.frameMap().toStackAddress((CiStackSlot) value);
81 }
82
83 @Override
84 protected int initialFrameSizeInBytes() {
85 return frameMap.frameSize();
86 }
87
88 @Override
89 protected void emitReturn(CiValue result) {
90 // TODO: Consider adding safepoint polling at return!
91 masm.ret(0);
92 }
93
94 @Override
95 protected void emitMonitorAddress(int monitor, CiValue dst) {
96 CiStackSlot slot = frameMap.toMonitorBaseStackAddress(monitor);
97 masm.leaq(dst.asRegister(), new CiAddress(slot.kind, AMD64.rsp.asValue(), slot.index() * target.arch.wordSize));
98 }
99
100 @Override
101 protected void emitBreakpoint() {
102 masm.int3();
103 }
104
105 @Override
106 protected void emitStackAllocate(StackBlock stackBlock, CiValue dst) {
107 masm.leaq(dst.asRegister(), compilation.frameMap().toStackAddress(stackBlock));
108 }
109
110 private void moveRegs(CiRegister fromReg, CiRegister toReg) {
111 if (fromReg != toReg) {
112 masm.mov(toReg, fromReg);
113 }
114 }
115
116 private void swapReg(CiRegister a, CiRegister b) {
117 masm.xchgptr(a, b);
118 }
119
120 private void const2reg(CiRegister dst, int constant) {
121 // Do not optimize with an XOR as this instruction may be between
122 // a CMP and a Jcc in which case the XOR will modify the condition
123 // flags and interfere with the Jcc.
124 masm.movl(dst, constant);
125 }
126
127 private void const2reg(CiRegister dst, long constant) {
128 // Do not optimize with an XOR as this instruction may be between
129 // a CMP and a Jcc in which case the XOR will modify the condition
130 // flags and interfere with the Jcc.
131 masm.movq(dst, constant);
132 }
133
134 private void const2reg(CiRegister dst, CiConstant constant) {
135 assert constant.kind == CiKind.Object;
136 // Do not optimize with an XOR as this instruction may be between
137 // a CMP and a Jcc in which case the XOR will modify the condition
138 // flags and interfere with the Jcc.
139 if (constant.isNull()) {
140 masm.movq(dst, 0x0L);
141 } else if (target.inlineObjects) {
142 tasm.recordDataReferenceInCode(constant);
143 masm.movq(dst, 0xDEADDEADDEADDEADL);
144 } else {
145 masm.movq(dst, tasm.recordDataReferenceInCode(constant));
146 }
147 }
148
149 @Override
150 public void emitTraps() {
151 for (int i = 0; i < C1XOptions.MethodEndBreakpointGuards; ++i) {
152 masm.int3();
153 }
154 }
155
156 private void const2reg(CiRegister dst, float constant) {
157 if (constant == 0.0f) {
158 masm.xorps(dst, dst);
159 } else {
160 masm.movflt(dst, tasm.recordDataReferenceInCode(CiConstant.forFloat(constant)));
161 }
162 }
163
164 private void const2reg(CiRegister dst, double constant) {
165 if (constant == 0.0f) {
166 masm.xorpd(dst, dst);
167 } else {
168 masm.movdbl(dst, tasm.recordDataReferenceInCode(CiConstant.forDouble(constant)));
169 }
170 }
171
172 @Override
173 protected void const2reg(CiValue src, CiValue dest, LIRDebugInfo info) {
174 assert src.isConstant();
175 assert dest.isRegister();
176 CiConstant c = (CiConstant) src;
177
178 // Checkstyle: off
179 switch (c.kind) {
180 case Boolean :
181 case Byte :
182 case Char :
183 case Short :
184 case Jsr :
185 case Int : const2reg(dest.asRegister(), c.asInt()); break;
186 case Word :
187 case Long : const2reg(dest.asRegister(), c.asLong()); break;
188 case Object : const2reg(dest.asRegister(), c); break;
189 case Float : const2reg(asXmmFloatReg(dest), c.asFloat()); break;
190 case Double : const2reg(asXmmDoubleReg(dest), c.asDouble()); break;
191 default : throw Util.shouldNotReachHere();
192 }
193 // Checkstyle: on
194 }
195
196 @Override
197 protected void const2stack(CiValue src, CiValue dst) {
198 assert src.isConstant();
199 assert dst.isStackSlot();
200 CiStackSlot slot = (CiStackSlot) dst;
201 CiConstant c = (CiConstant) src;
202
203 // Checkstyle: off
204 switch (c.kind) {
205 case Boolean :
206 case Byte :
207 case Char :
208 case Short :
209 case Jsr :
210 case Int : masm.movl(frameMap.toStackAddress(slot), c.asInt()); break;
211 case Float : masm.movl(frameMap.toStackAddress(slot), floatToRawIntBits(c.asFloat())); break;
212 case Object : movoop(frameMap.toStackAddress(slot), c); break;
213 case Long : masm.mov64(frameMap.toStackAddress(slot), c.asLong()); break;
214 case Double : masm.mov64(frameMap.toStackAddress(slot), doubleToRawLongBits(c.asDouble())); break;
215 default : throw Util.shouldNotReachHere("Unknown constant kind for const2stack: " + c.kind);
216 }
217 // Checkstyle: on
218 }
219
220 @Override
221 protected void const2mem(CiValue src, CiValue dst, CiKind kind, LIRDebugInfo info) {
222 assert src.isConstant();
223 assert dst.isAddress();
224 CiConstant constant = (CiConstant) src;
225 CiAddress addr = asAddress(dst);
226
227 int nullCheckHere = codePos();
228 // Checkstyle: off
229 switch (kind) {
230 case Boolean :
231 case Byte : masm.movb(addr, constant.asInt() & 0xFF); break;
232 case Char :
233 case Short : masm.movw(addr, constant.asInt() & 0xFFFF); break;
234 case Jsr :
235 case Int : masm.movl(addr, constant.asInt()); break;
236 case Float : masm.movl(addr, floatToRawIntBits(constant.asFloat())); break;
237 case Object : movoop(addr, constant); break;
238 case Word:
239 case Long : masm.movq(rscratch1, constant.asLong());
240 nullCheckHere = codePos();
241 masm.movq(addr, rscratch1); break;
242 case Double : masm.movq(rscratch1, doubleToRawLongBits(constant.asDouble()));
243 nullCheckHere = codePos();
244 masm.movq(addr, rscratch1); break;
245 default : throw Util.shouldNotReachHere();
246 }
247 // Checkstyle: on
248
249 if (info != null) {
250 tasm.recordImplicitException(nullCheckHere, info);
251 }
252 }
253
254 @Override
255 protected void reg2reg(CiValue src, CiValue dest) {
256 assert src.isRegister();
257 assert dest.isRegister();
258
259 if (dest.kind.isFloat()) {
260 masm.movflt(asXmmFloatReg(dest), asXmmFloatReg(src));
261 } else if (dest.kind.isDouble()) {
262 masm.movdbl(asXmmDoubleReg(dest), asXmmDoubleReg(src));
263 } else {
264 moveRegs(src.asRegister(), dest.asRegister());
265 }
266 }
267
268 @Override
269 protected void reg2stack(CiValue src, CiValue dst, CiKind kind) {
270 assert src.isRegister();
271 assert dst.isStackSlot();
272 CiAddress addr = frameMap.toStackAddress((CiStackSlot) dst);
273
274 // Checkstyle: off
275 switch (src.kind) {
276 case Boolean :
277 case Byte :
278 case Char :
279 case Short :
280 case Jsr :
281 case Int : masm.movl(addr, src.asRegister()); break;
282 case Object :
283 case Word :
284 case Long : masm.movq(addr, src.asRegister()); break;
285 case Float : masm.movflt(addr, asXmmFloatReg(src)); break;
286 case Double : masm.movsd(addr, asXmmDoubleReg(src)); break;
287 default : throw Util.shouldNotReachHere();
288 }
289 // Checkstyle: on
290 }
291
292 @Override
293 protected void reg2mem(CiValue src, CiValue dest, CiKind kind, LIRDebugInfo info, boolean unaligned) {
294 CiAddress toAddr = (CiAddress) dest;
295
296 if (info != null) {
297 tasm.recordImplicitException(codePos(), info);
298 }
299
300 // Checkstyle: off
301 switch (kind) {
302 case Float : masm.movflt(toAddr, asXmmFloatReg(src)); break;
303 case Double : masm.movsd(toAddr, asXmmDoubleReg(src)); break;
304 case Jsr :
305 case Int : masm.movl(toAddr, src.asRegister()); break;
306 case Long :
307 case Word :
308 case Object : masm.movq(toAddr, src.asRegister()); break;
309 case Char :
310 case Short : masm.movw(toAddr, src.asRegister()); break;
311 case Byte :
312 case Boolean : masm.movb(toAddr, src.asRegister()); break;
313 default : throw Util.shouldNotReachHere();
314 }
315 // Checkstyle: on
316 }
317
318 private static CiRegister asXmmFloatReg(CiValue src) {
319 assert src.kind.isFloat() : "must be float, actual kind: " + src.kind;
320 CiRegister result = src.asRegister();
321 assert result.isFpu() : "must be xmm, actual type: " + result;
322 return result;
323 }
324
325 @Override
326 protected void stack2reg(CiValue src, CiValue dest, CiKind kind) {
327 assert src.isStackSlot();
328 assert dest.isRegister();
329
330 CiAddress addr = frameMap.toStackAddress((CiStackSlot) src);
331
332 // Checkstyle: off
333 switch (dest.kind) {
334 case Boolean :
335 case Byte :
336 case Char :
337 case Short :
338 case Jsr :
339 case Int : masm.movl(dest.asRegister(), addr); break;
340 case Object :
341 case Word :
342 case Long : masm.movq(dest.asRegister(), addr); break;
343 case Float : masm.movflt(asXmmFloatReg(dest), addr); break;
344 case Double : masm.movdbl(asXmmDoubleReg(dest), addr); break;
345 default : throw Util.shouldNotReachHere();
346 }
347 // Checkstyle: on
348 }
349
350 @Override
351 protected void mem2mem(CiValue src, CiValue dest, CiKind kind) {
352 if (dest.kind.isInt()) {
353 masm.pushl((CiAddress) src);
354 masm.popl((CiAddress) dest);
355 } else {
356 masm.pushptr((CiAddress) src);
357 masm.popptr((CiAddress) dest);
358 }
359 }
360
361 @Override
362 protected void mem2stack(CiValue src, CiValue dest, CiKind kind) {
363 if (dest.kind.isInt()) {
364 masm.pushl((CiAddress) src);
365 masm.popl(frameMap.toStackAddress((CiStackSlot) dest));
366 } else {
367 masm.pushptr((CiAddress) src);
368 masm.popptr(frameMap.toStackAddress((CiStackSlot) dest));
369 }
370 }
371
372 @Override
373 protected void stack2stack(CiValue src, CiValue dest, CiKind kind) {
374 if (src.kind.isInt()) {
375 masm.pushl(frameMap.toStackAddress((CiStackSlot) src));
376 masm.popl(frameMap.toStackAddress((CiStackSlot) dest));
377 } else {
378 masm.pushptr(frameMap.toStackAddress((CiStackSlot) src));
379 masm.popptr(frameMap.toStackAddress((CiStackSlot) dest));
380 }
381 }
382
383 @Override
384 protected void mem2reg(CiValue src, CiValue dest, CiKind kind, LIRDebugInfo info, boolean unaligned) {
385 assert src.isAddress();
386 assert dest.isRegister() : "dest=" + dest;
387
388 CiAddress addr = (CiAddress) src;
389 if (info != null) {
390 tasm.recordImplicitException(codePos(), info);
391 }
392
393 // Checkstyle: off
394 switch (kind) {
395 case Float : masm.movflt(asXmmFloatReg(dest), addr); break;
396 case Double : masm.movdbl(asXmmDoubleReg(dest), addr); break;
397 case Object : masm.movq(dest.asRegister(), addr); break;
398 case Int : masm.movslq(dest.asRegister(), addr); break;
399 case Word :
400 case Long : masm.movq(dest.asRegister(), addr); break;
401 case Boolean :
402 case Byte : masm.movsxb(dest.asRegister(), addr); break;
403 case Char : masm.movzxl(dest.asRegister(), addr); break;
404 case Short : masm.movswl(dest.asRegister(), addr); break;
405 default : throw Util.shouldNotReachHere();
406 }
407 // Checkstyle: on
408 }
409
410 @Override
411 protected void emitReadPrefetch(CiValue src) {
412 CiAddress addr = (CiAddress) src;
413 // Checkstyle: off
414 switch (C1XOptions.ReadPrefetchInstr) {
415 case 0 : masm.prefetchnta(addr); break;
416 case 1 : masm.prefetcht0(addr); break;
417 case 2 : masm.prefetcht2(addr); break;
418 default : throw Util.shouldNotReachHere();
419 }
420 // Checkstyle: on
421 }
422
423 @Override
424 protected void emitOp3(LIROp3 op) {
425 // Checkstyle: off
426 switch (op.code) {
427 case Idiv :
428 case Irem : arithmeticIdiv(op.code, op.opr1(), op.opr2(), op.result(), op.info); break;
429 case Ldiv :
430 case Lrem : arithmeticLdiv(op.code, op.opr1(), op.opr2(), op.result(), op.info); break;
431 case Wdiv :
432 case Wdivi :
433 case Wrem :
434 case Wremi : arithmeticWdiv(op.code, op.opr1(), op.opr2(), op.result(), op.info); break;
435 default : throw Util.shouldNotReachHere();
436 }
437 // Checkstyle: on
438 }
439
440 private boolean assertEmitBranch(LIRBranch op) {
441 assert op.block() == null || op.block().label() == op.label() : "wrong label";
442 if (op.block() != null) {
443 branchTargetBlocks.add(op.block());
444 }
445 if (op.unorderedBlock() != null) {
446 branchTargetBlocks.add(op.unorderedBlock());
447 }
448 return true;
449 }
450
451 private boolean assertEmitTableSwitch(LIRTableSwitch op) {
452 assert op.defaultTarget != null;
453 branchTargetBlocks.add(op.defaultTarget);
454 for (LIRBlock target : op.targets) {
455 assert target != null;
456 branchTargetBlocks.add(target);
457 }
458 return true;
459 }
460
461 @Override
462 protected void emitTableSwitch(LIRTableSwitch op) {
463
464 assert assertEmitTableSwitch(op);
465
466 CiRegister value = op.value().asRegister();
467 final Buffer buf = masm.codeBuffer;
468
469 // Compare index against jump table bounds
470 int highKey = op.lowKey + op.targets.length - 1;
471 if (op.lowKey != 0) {
472 // subtract the low value from the switch value
473 masm.subl(value, op.lowKey);
474 masm.cmpl(value, highKey - op.lowKey);
475 } else {
476 masm.cmpl(value, highKey);
477 }
478
479 // Jump to default target if index is not within the jump table
480 masm.jcc(ConditionFlag.above, op.defaultTarget.label());
481
482 // Set scratch to address of jump table
483 int leaPos = buf.position();
484 buf.putMark();
485 masm.leaq(rscratch1, new CiAddress(CiKind.Word, InstructionRelative.asValue(), 0));
486
487 // Load jump table entry into scratch and jump to it
488 masm.movslq(value, new CiAddress(CiKind.Int, rscratch1.asValue(), value.asValue(), Scale.Times4, 0));
489 masm.addq(rscratch1, value);
490 masm.jmp(rscratch1);
491
492 // Inserting padding so that jump table address is 4-byte aligned
493 if ((buf.position() & 0x3) != 0) {
494 masm.nop(4 - (buf.position() & 0x3));
495 }
496
497 // Patch LEA instruction above now that we know the position of the jump table
498 int jumpTablePos = buf.position();
499 buf.setPosition(leaPos);
500 buf.putMark();
501 masm.leaq(rscratch1, new CiAddress(CiKind.Word, InstructionRelative.asValue(), jumpTablePos - leaPos));
502 buf.setPosition(jumpTablePos);
503
504 // Emit jump table entries
505 for (LIRBlock target : op.targets) {
506 Label label = target.label();
507 int offsetToJumpTableBase = buf.position() - jumpTablePos;
508 if (label.isBound()) {
509 int imm32 = label.position() - jumpTablePos;
510 buf.emitInt(imm32);
511 } else {
512 label.addPatchAt(buf.position());
513
514 buf.emitByte(0); // psuedo-opcode for jump table entry
515 buf.emitShort(offsetToJumpTableBase);
516 buf.emitByte(0); // padding to make jump table entry 4 bytes wide
517 }
518 }
519
520 JumpTable jt = new JumpTable(jumpTablePos, op.lowKey, highKey, 4);
521 tasm.targetMethod.addAnnotation(jt);
522 }
523
524 @Override
525 protected void emitBranch(LIRBranch op) {
526
527 assert assertEmitBranch(op);
528
529 if (op.cond() == Condition.TRUE) {
530 if (op.info != null) {
531 int codePos = codePos();
532 if (codePos <= tasm.lastSafepointPos()) {
533 masm.nop();
534 }
535 tasm.recordImplicitException(codePos(), op.info);
536 }
537 masm.jmp(op.label());
538 } else {
539 ConditionFlag acond = ConditionFlag.zero;
540 if (op.code == LIROpcode.CondFloatBranch) {
541 assert op.unorderedBlock() != null : "must have unordered successor";
542 masm.jcc(ConditionFlag.parity, op.unorderedBlock().label());
543 // Checkstyle: off
544 switch (op.cond()) {
545 case EQ : acond = ConditionFlag.equal; break;
546 case NE : acond = ConditionFlag.notEqual; break;
547 case LT : acond = ConditionFlag.below; break;
548 case LE : acond = ConditionFlag.belowEqual; break;
549 case GE : acond = ConditionFlag.aboveEqual; break;
550 case GT : acond = ConditionFlag.above; break;
551 default : throw Util.shouldNotReachHere();
552 }
553 } else {
554 switch (op.cond()) {
555 case EQ : acond = ConditionFlag.equal; break;
556 case NE : acond = ConditionFlag.notEqual; break;
557 case LT : acond = ConditionFlag.less; break;
558 case LE : acond = ConditionFlag.lessEqual; break;
559 case GE : acond = ConditionFlag.greaterEqual; break;
560 case GT : acond = ConditionFlag.greater; break;
561 case BE : acond = ConditionFlag.belowEqual; break;
562 case AE : acond = ConditionFlag.aboveEqual; break;
563 default : throw Util.shouldNotReachHere();
564 }
565 // Checkstyle: on
566 }
567 masm.jcc(acond, op.label());
568 }
569 }
570
571 @Override
572 protected void emitConvert(LIRConvert op) {
573 CiValue src = op.operand();
574 CiValue dest = op.result();
575 Label endLabel = new Label();
576 CiRegister srcRegister = src.asRegister();
577 switch (op.bytecode) {
578 case I2L:
579 masm.movslq(dest.asRegister(), srcRegister);
580 break;
581
582 case L2I:
583 moveRegs(srcRegister, dest.asRegister());
584 masm.andl(dest.asRegister(), 0xFFFFFFFF);
585 break;
586
587 case I2B:
588 moveRegs(srcRegister, dest.asRegister());
589 masm.signExtendByte(dest.asRegister());
590 break;
591
592 case I2C:
593 moveRegs(srcRegister, dest.asRegister());
594 masm.andl(dest.asRegister(), 0xFFFF);
595 break;
596
597 case I2S:
598 moveRegs(srcRegister, dest.asRegister());
599 masm.signExtendShort(dest.asRegister());
600 break;
601
602 case F2D:
603 masm.cvtss2sd(asXmmDoubleReg(dest), asXmmFloatReg(src));
604 break;
605
606 case D2F:
607 masm.cvtsd2ss(asXmmFloatReg(dest), asXmmDoubleReg(src));
608 break;
609
610 case I2F:
611 masm.cvtsi2ssl(asXmmFloatReg(dest), srcRegister);
612 break;
613 case I2D:
614 masm.cvtsi2sdl(asXmmDoubleReg(dest), srcRegister);
615 break;
616
617 case F2I: {
618 assert srcRegister.isFpu() && dest.isRegister() : "must both be XMM register (no fpu stack)";
619 masm.cvttss2sil(dest.asRegister(), srcRegister);
620 masm.cmp32(dest.asRegister(), Integer.MIN_VALUE);
621 masm.jcc(ConditionFlag.notEqual, endLabel);
622 callGlobalStub(op.globalStub, null, dest.asRegister(), src);
623 // cannot cause an exception
624 masm.bind(endLabel);
625 break;
626 }
627 case D2I: {
628 assert srcRegister.isFpu() && dest.isRegister() : "must both be XMM register (no fpu stack)";
629 masm.cvttsd2sil(dest.asRegister(), asXmmDoubleReg(src));
630 masm.cmp32(dest.asRegister(), Integer.MIN_VALUE);
631 masm.jcc(ConditionFlag.notEqual, endLabel);
632 callGlobalStub(op.globalStub, null, dest.asRegister(), src);
633 // cannot cause an exception
634 masm.bind(endLabel);
635 break;
636 }
637 case L2F:
638 masm.cvtsi2ssq(asXmmFloatReg(dest), srcRegister);
639 break;
640
641 case L2D:
642 masm.cvtsi2sdq(asXmmDoubleReg(dest), srcRegister);
643 break;
644
645 case F2L: {
646 assert srcRegister.isFpu() && dest.kind.isLong() : "must both be XMM register (no fpu stack)";
647 masm.cvttss2siq(dest.asRegister(), asXmmFloatReg(src));
648 masm.movq(rscratch1, java.lang.Long.MIN_VALUE);
649 masm.cmpq(dest.asRegister(), rscratch1);
650 masm.jcc(ConditionFlag.notEqual, endLabel);
651 callGlobalStub(op.globalStub, null, dest.asRegister(), src);
652 masm.bind(endLabel);
653 break;
654 }
655
656 case D2L: {
657 assert srcRegister.isFpu() && dest.kind.isLong() : "must both be XMM register (no fpu stack)";
658 masm.cvttsd2siq(dest.asRegister(), asXmmDoubleReg(src));
659 masm.movq(rscratch1, java.lang.Long.MIN_VALUE);
660 masm.cmpq(dest.asRegister(), rscratch1);
661 masm.jcc(ConditionFlag.notEqual, endLabel);
662 callGlobalStub(op.globalStub, null, dest.asRegister(), src);
663 masm.bind(endLabel);
664 break;
665 }
666
667 case MOV_I2F:
668 masm.movdl(asXmmFloatReg(dest), srcRegister);
669 break;
670
671 case MOV_L2D:
672 masm.movdq(asXmmDoubleReg(dest), srcRegister);
673 break;
674
675 case MOV_F2I:
676 masm.movdl(dest.asRegister(), asXmmFloatReg(src));
677 break;
678
679 case MOV_D2L:
680 masm.movdq(dest.asRegister(), asXmmDoubleReg(src));
681 break;
682
683 default:
684 throw Util.shouldNotReachHere();
685 }
686 }
687
688 @Override
689 protected void emitCompareAndSwap(LIRCompareAndSwap op) {
690 CiAddress address = new CiAddress(CiKind.Object, op.address(), 0);
691 CiRegister newval = op.newValue().asRegister();
692 CiRegister cmpval = op.expectedValue().asRegister();
693 assert cmpval == AMD64.rax : "wrong register";
694 assert newval != null : "new val must be register";
695 assert cmpval != newval : "cmp and new values must be in different registers";
696 assert cmpval != address.base() : "cmp and addr must be in different registers";
697 assert newval != address.base() : "new value and addr must be in different registers";
698 assert cmpval != address.index() : "cmp and addr must be in different registers";
699 assert newval != address.index() : "new value and addr must be in different registers";
700 if (compilation.target.isMP) {
701 masm.lock();
702 }
703 if (op.code == LIROpcode.CasInt) {
704 masm.cmpxchgl(newval, address);
705 } else {
706 assert op.code == LIROpcode.CasObj || op.code == LIROpcode.CasLong || op.code == LIROpcode.CasWord;
707 masm.cmpxchgq(newval, address);
708 }
709 }
710
711 @Override
712 protected void emitConditionalMove(Condition condition, CiValue opr1, CiValue opr2, CiValue result) {
713 ConditionFlag acond;
714 ConditionFlag ncond;
715 switch (condition) {
716 case EQ:
717 acond = ConditionFlag.equal;
718 ncond = ConditionFlag.notEqual;
719 break;
720 case NE:
721 acond = ConditionFlag.notEqual;
722 ncond = ConditionFlag.equal;
723 break;
724 case LT:
725 acond = ConditionFlag.less;
726 ncond = ConditionFlag.greaterEqual;
727 break;
728 case LE:
729 acond = ConditionFlag.lessEqual;
730 ncond = ConditionFlag.greater;
731 break;
732 case GE:
733 acond = ConditionFlag.greaterEqual;
734 ncond = ConditionFlag.less;
735 break;
736 case GT:
737 acond = ConditionFlag.greater;
738 ncond = ConditionFlag.lessEqual;
739 break;
740 case BE:
741 acond = ConditionFlag.belowEqual;
742 ncond = ConditionFlag.above;
743 break;
744 case BT:
745 acond = ConditionFlag.below;
746 ncond = ConditionFlag.aboveEqual;
747 break;
748 case AE:
749 acond = ConditionFlag.aboveEqual;
750 ncond = ConditionFlag.below;
751 break;
752 case AT:
753 acond = ConditionFlag.above;
754 ncond = ConditionFlag.belowEqual;
755 break;
756 default:
757 throw Util.shouldNotReachHere();
758 }
759
760 CiValue def = opr1; // assume left operand as default
761 CiValue other = opr2;
762
763 if (opr2.isRegister() && opr2.asRegister() == result.asRegister()) {
764 // if the right operand is already in the result register, then use it as the default
765 def = opr2;
766 other = opr1;
767 // and flip the condition
768 ConditionFlag tcond = acond;
769 acond = ncond;
770 ncond = tcond;
771 }
772
773 if (def.isRegister()) {
774 reg2reg(def, result);
775 } else if (def.isStackSlot()) {
776 stack2reg(def, result, result.kind);
777 } else {
778 assert def.isConstant();
779 const2reg(def, result, null);
780 }
781
782 if (!other.isConstant()) {
783 // optimized version that does not require a branch
784 if (other.isRegister()) {
785 assert other.asRegister() != result.asRegister() : "other already overwritten by previous move";
786 if (other.kind.isInt()) {
787 masm.cmovq(ncond, result.asRegister(), other.asRegister());
788 } else {
789 masm.cmovq(ncond, result.asRegister(), other.asRegister());
790 }
791 } else {
792 assert other.isStackSlot();
793 CiStackSlot otherSlot = (CiStackSlot) other;
794 if (other.kind.isInt()) {
795 masm.cmovl(ncond, result.asRegister(), frameMap.toStackAddress(otherSlot));
796 } else {
797 masm.cmovq(ncond, result.asRegister(), frameMap.toStackAddress(otherSlot));
798 }
799 }
800
801 } else {
802 // conditional move not available, use emit a branch and move
803 Label skip = new Label();
804 masm.jcc(acond, skip);
805 if (other.isRegister()) {
806 reg2reg(other, result);
807 } else if (other.isStackSlot()) {
808 stack2reg(other, result, result.kind);
809 } else {
810 assert other.isConstant();
811 const2reg(other, result, null);
812 }
813 masm.bind(skip);
814 }
815 }
816
817 @Override
818 protected void emitArithOp(LIROpcode code, CiValue left, CiValue right, CiValue dest, LIRDebugInfo info) {
819 assert info == null : "should never be used : idiv/irem and ldiv/lrem not handled by this method";
820 assert Util.archKindsEqual(left.kind, right.kind) || (left.kind == CiKind.Word && right.kind == CiKind.Int) : code.toString() + " left arch is " + left.kind + " and right arch is " + right.kind;
821 assert left.equals(dest) : "left and dest must be equal";
822 CiKind kind = left.kind;
823
824 // Checkstyle: off
825 if (left.isRegister()) {
826 CiRegister lreg = left.asRegister();
827
828 if (right.isRegister()) {
829 // register - register
830 CiRegister rreg = right.asRegister();
831 if (kind.isInt()) {
832 switch (code) {
833 case Add : masm.addl(lreg, rreg); break;
834 case Sub : masm.subl(lreg, rreg); break;
835 case Mul : masm.imull(lreg, rreg); break;
836 default : throw Util.shouldNotReachHere();
837 }
838 } else if (kind.isFloat()) {
839 assert rreg.isFpu() : "must be xmm";
840 switch (code) {
841 case Add : masm.addss(lreg, rreg); break;
842 case Sub : masm.subss(lreg, rreg); break;
843 case Mul : masm.mulss(lreg, rreg); break;
844 case Div : masm.divss(lreg, rreg); break;
845 default : throw Util.shouldNotReachHere();
846 }
847 } else if (kind.isDouble()) {
848 assert rreg.isFpu();
849 switch (code) {
850 case Add : masm.addsd(lreg, rreg); break;
851 case Sub : masm.subsd(lreg, rreg); break;
852 case Mul : masm.mulsd(lreg, rreg); break;
853 case Div : masm.divsd(lreg, rreg); break;
854 default : throw Util.shouldNotReachHere();
855 }
856 } else {
857 assert target.sizeInBytes(kind) == 8;
858 switch (code) {
859 case Add : masm.addq(lreg, rreg); break;
860 case Sub : masm.subq(lreg, rreg); break;
861 case Mul : masm.imulq(lreg, rreg); break;
862 default : throw Util.shouldNotReachHere();
863 }
864 }
865 } else {
866 if (kind.isInt()) {
867 if (right.isStackSlot()) {
868 // register - stack
869 CiAddress raddr = frameMap.toStackAddress(((CiStackSlot) right));
870 switch (code) {
871 case Add : masm.addl(lreg, raddr); break;
872 case Sub : masm.subl(lreg, raddr); break;
873 default : throw Util.shouldNotReachHere();
874 }
875 } else if (right.isConstant()) {
876 // register - constant
877 assert kind.isInt();
878 int delta = ((CiConstant) right).asInt();
879 switch (code) {
880 case Add : masm.incrementl(lreg, delta); break;
881 case Sub : masm.decrementl(lreg, delta); break;
882 default : throw Util.shouldNotReachHere();
883 }
884 }
885 } else if (kind.isFloat()) {
886 // register - stack/constant
887 CiAddress raddr;
888 if (right.isStackSlot()) {
889 raddr = frameMap.toStackAddress(((CiStackSlot) right));
890 } else {
891 assert right.isConstant();
892 raddr = tasm.recordDataReferenceInCode(CiConstant.forFloat(((CiConstant) right).asFloat()));
893 }
894 switch (code) {
895 case Add : masm.addss(lreg, raddr); break;
896 case Sub : masm.subss(lreg, raddr); break;
897 case Mul : masm.mulss(lreg, raddr); break;
898 case Div : masm.divss(lreg, raddr); break;
899 default : throw Util.shouldNotReachHere();
900 }
901 } else if (kind.isDouble()) {
902 // register - stack/constant
903 CiAddress raddr;
904 if (right.isStackSlot()) {
905 raddr = frameMap.toStackAddress(((CiStackSlot) right));
906 } else {
907 assert right.isConstant();
908 raddr = tasm.recordDataReferenceInCode(CiConstant.forDouble(((CiConstant) right).asDouble()));
909 }
910 switch (code) {
911 case Add : masm.addsd(lreg, raddr); break;
912 case Sub : masm.subsd(lreg, raddr); break;
913 case Mul : masm.mulsd(lreg, raddr); break;
914 case Div : masm.divsd(lreg, raddr); break;
915 default : throw Util.shouldNotReachHere();
916 }
917 } else {
918 assert target.sizeInBytes(kind) == 8;
919 if (right.isStackSlot()) {
920 // register - stack
921 CiAddress raddr = frameMap.toStackAddress(((CiStackSlot) right));
922 switch (code) {
923 case Add : masm.addq(lreg, raddr); break;
924 case Sub : masm.subq(lreg, raddr); break;
925 default : throw Util.shouldNotReachHere();
926 }
927 } else {
928 // register - constant
929 assert right.isConstant();
930 long c = ((CiConstant) right).asLong();
931 if (NumUtil.isInt(c)) {
932 switch (code) {
933 case Add : masm.addq(lreg, (int) c); break;
934 case Sub : masm.subq(lreg, (int) c); break;
935 default : throw Util.shouldNotReachHere();
936 }
937 } else {
938 masm.movq(rscratch1, c);
939 switch (code) {
940 case Add : masm.addq(lreg, rscratch1); break;
941 case Sub : masm.subq(lreg, rscratch1); break;
942 default : throw Util.shouldNotReachHere();
943 }
944 }
945 }
946 }
947 }
948 } else {
949 assert kind.isInt();
950 CiAddress laddr = asAddress(left);
951
952 if (right.isRegister()) {
953 CiRegister rreg = right.asRegister();
954 switch (code) {
955 case Add : masm.addl(laddr, rreg); break;
956 case Sub : masm.subl(laddr, rreg); break;
957 default : throw Util.shouldNotReachHere();
958 }
959 } else {
960 assert right.isConstant();
961 int c = ((CiConstant) right).asInt();
962 switch (code) {
963 case Add : masm.incrementl(laddr, c); break;
964 case Sub : masm.decrementl(laddr, c); break;
965 default : throw Util.shouldNotReachHere();
966 }
967 }
968 }
969 // Checkstyle: on
970 }
971
972 @Override
973 protected void emitIntrinsicOp(LIROpcode code, CiValue value, CiValue unused, CiValue dest, LIROp2 op) {
974 assert value.kind.isDouble();
975 switch (code) {
976 case Abs:
977 if (asXmmDoubleReg(dest) != asXmmDoubleReg(value)) {
978 masm.movdbl(asXmmDoubleReg(dest), asXmmDoubleReg(value));
979 }
980 masm.andpd(asXmmDoubleReg(dest), tasm.recordDataReferenceInCode(CiConstant.forLong(DoubleSignMask)));
981 break;
982
983 case Sqrt:
984 masm.sqrtsd(asXmmDoubleReg(dest), asXmmDoubleReg(value));
985 break;
986
987 default:
988 throw Util.shouldNotReachHere();
989 }
990 }
991
992 @Override
993 protected void emitLogicOp(LIROpcode code, CiValue left, CiValue right, CiValue dst) {
994 assert left.isRegister();
995 // Checkstyle: off
996 if (left.kind.isInt()) {
997 CiRegister reg = left.asRegister();
998 if (right.isConstant()) {
999 int val = ((CiConstant) right).asInt();
1000 switch (code) {
1001 case LogicAnd : masm.andl(reg, val); break;
1002 case LogicOr : masm.orl(reg, val); break;
1003 case LogicXor : masm.xorl(reg, val); break;
1004 default : throw Util.shouldNotReachHere();
1005 }
1006 } else if (right.isStackSlot()) {
1007 // added support for stack operands
1008 CiAddress raddr = frameMap.toStackAddress(((CiStackSlot) right));
1009 switch (code) {
1010 case LogicAnd : masm.andl(reg, raddr); break;
1011 case LogicOr : masm.orl(reg, raddr); break;
1012 case LogicXor : masm.xorl(reg, raddr); break;
1013 default : throw Util.shouldNotReachHere();
1014 }
1015 } else {
1016 CiRegister rright = right.asRegister();
1017 switch (code) {
1018 case LogicAnd : masm.andq(reg, rright); break;
1019 case LogicOr : masm.orq(reg, rright); break;
1020 case LogicXor : masm.xorptr(reg, rright); break;
1021 default : throw Util.shouldNotReachHere();
1022 }
1023 }
1024 moveRegs(reg, dst.asRegister());
1025 } else {
1026 assert target.sizeInBytes(left.kind) == 8;
1027 CiRegister lreg = left.asRegister();
1028 if (right.isConstant()) {
1029 CiConstant rightConstant = (CiConstant) right;
1030 masm.movq(rscratch1, rightConstant.asLong());
1031 switch (code) {
1032 case LogicAnd : masm.andq(lreg, rscratch1); break;
1033 case LogicOr : masm.orq(lreg, rscratch1); break;
1034 case LogicXor : masm.xorq(lreg, rscratch1); break;
1035 default : throw Util.shouldNotReachHere();
1036 }
1037 } else {
1038 CiRegister rreg = right.asRegister();
1039 switch (code) {
1040 case LogicAnd : masm.andq(lreg, rreg); break;
1041 case LogicOr : masm.orq(lreg, rreg); break;
1042 case LogicXor : masm.xorptr(lreg, rreg); break;
1043 default : throw Util.shouldNotReachHere();
1044 }
1045 }
1046
1047 CiRegister dreg = dst.asRegister();
1048 moveRegs(lreg, dreg);
1049 }
1050 // Checkstyle: on
1051 }
1052
1053 void arithmeticIdiv(LIROpcode code, CiValue left, CiValue right, CiValue result, LIRDebugInfo info) {
1054 assert left.isRegister() : "left must be register";
1055 assert right.isRegister() || right.isConstant() : "right must be register or constant";
1056 assert result.isRegister() : "result must be register";
1057
1058 CiRegister lreg = left.asRegister();
1059 CiRegister dreg = result.asRegister();
1060
1061 if (right.isConstant()) {
1062 int divisor = ((CiConstant) right).asInt();
1063 assert divisor > 0 && CiUtil.isPowerOf2(divisor) : "divisor must be power of two";
1064 if (code == LIROpcode.Idiv) {
1065 assert lreg == AMD64.rax : "dividend must be rax";
1066 masm.cdql(); // sign extend into rdx:rax
1067 if (divisor == 2) {
1068 masm.subl(lreg, AMD64.rdx);
1069 } else {
1070 masm.andl(AMD64.rdx, divisor - 1);
1071 masm.addl(lreg, AMD64.rdx);
1072 }
1073 masm.sarl(lreg, CiUtil.log2(divisor));
1074 moveRegs(lreg, dreg);
1075 } else {
1076 assert code == LIROpcode.Irem;
1077 Label done = new Label();
1078 masm.mov(dreg, lreg);
1079 masm.andl(dreg, 0x80000000 | (divisor - 1));
1080 masm.jcc(ConditionFlag.positive, done);
1081 masm.decrementl(dreg, 1);
1082 masm.orl(dreg, ~(divisor - 1));
1083 masm.incrementl(dreg, 1);
1084 masm.bind(done);
1085 }
1086 } else {
1087 CiRegister rreg = right.asRegister();
1088 assert lreg == AMD64.rax : "left register must be rax";
1089 assert rreg != AMD64.rdx : "right register must not be rdx";
1090
1091 moveRegs(lreg, AMD64.rax);
1092
1093 Label continuation = new Label();
1094
1095 if (C1XOptions.GenSpecialDivChecks) {
1096 // check for special case of Integer.MIN_VALUE / -1
1097 Label normalCase = new Label();
1098 masm.cmpl(AMD64.rax, Integer.MIN_VALUE);
1099 masm.jcc(ConditionFlag.notEqual, normalCase);
1100 if (code == LIROpcode.Irem) {
1101 // prepare X86Register.rdx for possible special case where remainder = 0
1102 masm.xorl(AMD64.rdx, AMD64.rdx);
1103 }
1104 masm.cmpl(rreg, -1);
1105 masm.jcc(ConditionFlag.equal, continuation);
1106
1107 // handle normal case
1108 masm.bind(normalCase);
1109 }
1110 masm.cdql();
1111 int offset = masm.codeBuffer.position();
1112 masm.idivl(rreg);
1113
1114 // normal and special case exit
1115 masm.bind(continuation);
1116
1117 tasm.recordImplicitException(offset, info);
1118 if (code == LIROpcode.Irem) {
1119 moveRegs(AMD64.rdx, dreg); // result is in rdx
1120 } else {
1121 assert code == LIROpcode.Idiv;
1122 moveRegs(AMD64.rax, dreg);
1123 }
1124 }
1125 }
1126
1127 void arithmeticLdiv(LIROpcode code, CiValue left, CiValue right, CiValue result, LIRDebugInfo info) {
1128 assert left.isRegister() : "left must be register";
1129 assert right.isRegister() : "right must be register";
1130 assert result.isRegister() : "result must be register";
1131 assert result.kind.isLong();
1132
1133 CiRegister lreg = left.asRegister();
1134 CiRegister dreg = result.asRegister();
1135 CiRegister rreg = right.asRegister();
1136 assert lreg == AMD64.rax : "left register must be rax";
1137 assert rreg != AMD64.rdx : "right register must not be rdx";
1138
1139 moveRegs(lreg, AMD64.rax);
1140
1141 Label continuation = new Label();
1142
1143 if (C1XOptions.GenSpecialDivChecks) {
1144 // check for special case of Long.MIN_VALUE / -1
1145 Label normalCase = new Label();
1146 masm.movq(AMD64.rdx, java.lang.Long.MIN_VALUE);
1147 masm.cmpq(AMD64.rax, AMD64.rdx);
1148 masm.jcc(ConditionFlag.notEqual, normalCase);
1149 if (code == LIROpcode.Lrem) {
1150 // prepare X86Register.rdx for possible special case (where remainder = 0)
1151 masm.xorq(AMD64.rdx, AMD64.rdx);
1152 }
1153 masm.cmpl(rreg, -1);
1154 masm.jcc(ConditionFlag.equal, continuation);
1155
1156 // handle normal case
1157 masm.bind(normalCase);
1158 }
1159 masm.cdqq();
1160 int offset = masm.codeBuffer.position();
1161 masm.idivq(rreg);
1162
1163 // normal and special case exit
1164 masm.bind(continuation);
1165
1166 tasm.recordImplicitException(offset, info);
1167 if (code == LIROpcode.Lrem) {
1168 moveRegs(AMD64.rdx, dreg);
1169 } else {
1170 assert code == LIROpcode.Ldiv;
1171 moveRegs(AMD64.rax, dreg);
1172 }
1173 }
1174
1175 void arithmeticWdiv(LIROpcode code, CiValue left, CiValue right, CiValue result, LIRDebugInfo info) {
1176 assert left.isRegister() : "left must be register";
1177 assert right.isRegister() : "right must be register";
1178 assert result.isRegister() : "result must be register";
1179
1180 CiRegister lreg = left.asRegister();
1181 CiRegister dreg = result.asRegister();
1182 CiRegister rreg = right.asRegister();
1183 assert lreg == AMD64.rax : "left register must be rax";
1184 assert rreg != AMD64.rdx : "right register must not be rdx";
1185
1186 // Must zero the high 64-bit word (in RDX) of the dividend
1187 masm.xorq(AMD64.rdx, AMD64.rdx);
1188
1189 if (code == LIROpcode.Wdivi || code == LIROpcode.Wremi) {
1190 // Zero the high 32 bits of the divisor
1191 masm.movzxd(rreg, rreg);
1192 }
1193
1194 moveRegs(lreg, AMD64.rax);
1195
1196 int offset = masm.codeBuffer.position();
1197 masm.divq(rreg);
1198
1199 tasm.recordImplicitException(offset, info);
1200 if (code == LIROpcode.Wrem || code == LIROpcode.Wremi) {
1201 moveRegs(AMD64.rdx, dreg);
1202 } else {
1203 assert code == LIROpcode.Wdiv || code == LIROpcode.Wdivi;
1204 moveRegs(AMD64.rax, dreg);
1205 }
1206 }
1207
1208 @Override
1209 protected void emitCompare(Condition condition, CiValue opr1, CiValue opr2, LIROp2 op) {
1210 // Checkstyle: off
1211 assert Util.archKindsEqual(opr1.kind.stackKind(), opr2.kind.stackKind()) || (opr1.kind == CiKind.Word && opr2.kind == CiKind.Int) : "nonmatching stack kinds (" + condition + "): " + opr1.kind.stackKind() + "==" + opr2.kind.stackKind();
1212
1213 if (opr1.isConstant()) {
1214 // Use scratch register
1215 CiValue newOpr1 = compilation.registerConfig.getScratchRegister().asValue(opr1.kind);
1216 const2reg(opr1, newOpr1, null);
1217 opr1 = newOpr1;
1218 }
1219
1220 if (opr1.isRegister()) {
1221 CiRegister reg1 = opr1.asRegister();
1222 if (opr2.isRegister()) {
1223 // register - register
1224 switch (opr1.kind) {
1225 case Boolean :
1226 case Byte :
1227 case Char :
1228 case Short :
1229 case Int : masm.cmpl(reg1, opr2.asRegister()); break;
1230 case Long :
1231 case Word :
1232 case Object : masm.cmpq(reg1, opr2.asRegister()); break;
1233 case Float : masm.ucomiss(reg1, asXmmFloatReg(opr2)); break;
1234 case Double : masm.ucomisd(reg1, asXmmDoubleReg(opr2)); break;
1235 default : throw Util.shouldNotReachHere(opr1.kind.toString());
1236 }
1237 } else if (opr2.isStackSlot()) {
1238 // register - stack
1239 CiStackSlot opr2Slot = (CiStackSlot) opr2;
1240 switch (opr1.kind) {
1241 case Boolean :
1242 case Byte :
1243 case Char :
1244 case Short :
1245 case Int : masm.cmpl(reg1, frameMap.toStackAddress(opr2Slot)); break;
1246 case Long :
1247 case Word :
1248 case Object : masm.cmpptr(reg1, frameMap.toStackAddress(opr2Slot)); break;
1249 case Float : masm.ucomiss(reg1, frameMap.toStackAddress(opr2Slot)); break;
1250 case Double : masm.ucomisd(reg1, frameMap.toStackAddress(opr2Slot)); break;
1251 default : throw Util.shouldNotReachHere();
1252 }
1253 } else if (opr2.isConstant()) {
1254 // register - constant
1255 CiConstant c = (CiConstant) opr2;
1256 switch (opr1.kind) {
1257 case Boolean :
1258 case Byte :
1259 case Char :
1260 case Short :
1261 case Int : masm.cmpl(reg1, c.asInt()); break;
1262 case Float : masm.ucomiss(reg1, tasm.recordDataReferenceInCode(CiConstant.forFloat(((CiConstant) opr2).asFloat()))); break;
1263 case Double : masm.ucomisd(reg1, tasm.recordDataReferenceInCode(CiConstant.forDouble(((CiConstant) opr2).asDouble()))); break;
1264 case Long :
1265 case Word : {
1266 if (c.asLong() == 0) {
1267 masm.cmpq(reg1, 0);
1268 } else {
1269 masm.movq(rscratch1, c.asLong());
1270 masm.cmpq(reg1, rscratch1);
1271
1272 }
1273 break;
1274 }
1275 case Object : {
1276 movoop(rscratch1, c);
1277 masm.cmpq(reg1, rscratch1);
1278 break;
1279 }
1280 default : throw Util.shouldNotReachHere();
1281 }
1282 } else {
1283 throw Util.shouldNotReachHere();
1284 }
1285 } else if (opr1.isStackSlot()) {
1286 CiAddress left = asAddress(opr1);
1287 if (opr2.isConstant()) {
1288 CiConstant right = (CiConstant) opr2;
1289 // stack - constant
1290 switch (opr1.kind) {
1291 case Boolean :
1292 case Byte :
1293 case Char :
1294 case Short :
1295 case Int : masm.cmpl(left, right.asInt()); break;
1296 case Long :
1297 case Word : assert NumUtil.isInt(right.asLong());
1298 masm.cmpq(left, right.asInt()); break;
1299 case Object : assert right.isNull();
1300 masm.cmpq(left, 0); break;
1301 default : throw Util.shouldNotReachHere();
1302 }
1303 } else {
1304 throw Util.shouldNotReachHere();
1305 }
1306
1307 } else {
1308 throw Util.shouldNotReachHere(opr1.toString() + " opr2 = " + opr2);
1309 }
1310 // Checkstyle: on
1311 }
1312
1313 @Override
1314 protected void emitCompare2Int(LIROpcode code, CiValue left, CiValue right, CiValue dst, LIROp2 op) {
1315 if (code == LIROpcode.Cmpfd2i || code == LIROpcode.Ucmpfd2i) {
1316 if (left.kind.isFloat()) {
1317 masm.cmpss2int(asXmmFloatReg(left), asXmmFloatReg(right), dst.asRegister(), code == LIROpcode.Ucmpfd2i);
1318 } else if (left.kind.isDouble()) {
1319 masm.cmpsd2int(asXmmDoubleReg(left), asXmmDoubleReg(right), dst.asRegister(), code == LIROpcode.Ucmpfd2i);
1320 } else {
1321 assert false : "no fpu stack";
1322 }
1323 } else {
1324 assert code == LIROpcode.Cmpl2i;
1325 CiRegister dest = dst.asRegister();
1326 Label high = new Label();
1327 Label done = new Label();
1328 Label isEqual = new Label();
1329 masm.cmpptr(left.asRegister(), right.asRegister());
1330 masm.jcc(ConditionFlag.equal, isEqual);
1331 masm.jcc(ConditionFlag.greater, high);
1332 masm.xorptr(dest, dest);
1333 masm.decrementl(dest, 1);
1334 masm.jmp(done);
1335 masm.bind(high);
1336 masm.xorptr(dest, dest);
1337 masm.incrementl(dest, 1);
1338 masm.jmp(done);
1339 masm.bind(isEqual);
1340 masm.xorptr(dest, dest);
1341 masm.bind(done);
1342 }
1343 }
1344
1345 @Override
1346 protected void emitCallAlignment(LIROpcode code) {
1347 if (C1XOptions.AlignCallsForPatching) {
1348 // make sure that the displacement word of the call ends up word aligned
1349 int offset = masm.codeBuffer.position();
1350 offset += compilation.target.arch.machineCodeCallDisplacementOffset;
1351 while (offset++ % wordSize != 0) {
1352 masm.nop();
1353 }
1354 }
1355 }
1356
1357 @Override
1358 protected void emitIndirectCall(Object target, LIRDebugInfo info, CiValue callAddress) {
1359 CiRegister reg = rscratch1;
1360 if (callAddress.isRegister()) {
1361 reg = callAddress.asRegister();
1362 } else {
1363 moveOp(callAddress, reg.asValue(callAddress.kind), callAddress.kind, null, false);
1364 }
1365 indirectCall(reg, target, info);
1366 }
1367
1368 @Override
1369 protected void emitDirectCall(Object target, LIRDebugInfo info) {
1370 directCall(target, info);
1371 }
1372
1373 @Override
1374 protected void emitNativeCall(String symbol, LIRDebugInfo info, CiValue callAddress) {
1375 CiRegister reg = rscratch1;
1376 if (callAddress.isRegister()) {
1377 reg = callAddress.asRegister();
1378 } else {
1379 moveOp(callAddress, reg.asValue(callAddress.kind), callAddress.kind, null, false);
1380 }
1381 indirectCall(reg, symbol, info);
1382 }
1383
1384 @Override
1385 protected void emitTemplateCall(CiValue address) {
1386 if (address == null) {
1387 directCall(null, null);
1388 return;
1389 }
1390
1391 CiRegister reg = rscratch1;
1392 if (address.isRegister()) {
1393 reg = address.asRegister();
1394 } else {
1395 moveOp(address, reg.asValue(address.kind), address.kind, null, false);
1396 }
1397 indirectCall(reg, null, null);
1398 }
1399
1400 private void emitXIRShiftOp(LIROpcode code, CiValue left, CiValue count, CiValue dest) {
1401 if (count.isConstant()) {
1402 emitShiftOp(code, left, ((CiConstant) count).asInt(), dest);
1403 } else {
1404 emitShiftOp(code, left, count, dest, IllegalValue);
1405 }
1406 }
1407
1408 @Override
1409 protected void emitShiftOp(LIROpcode code, CiValue left, CiValue count, CiValue dest, CiValue tmp) {
1410 // optimized version for linear scan:
1411 // * count must be already in ECX (guaranteed by LinearScan)
1412 // * left and dest must be equal
1413 // * tmp must be unused
1414 assert count.asRegister() == SHIFTCount : "count must be in ECX";
1415 assert left == dest : "left and dest must be equal";
1416 assert tmp.isIllegal() : "wasting a register if tmp is allocated";
1417 assert left.isRegister();
1418
1419 if (left.kind.isInt()) {
1420 CiRegister value = left.asRegister();
1421 assert value != SHIFTCount : "left cannot be ECX";
1422
1423 // Checkstyle: off
1424 switch (code) {
1425 case Shl : masm.shll(value); break;
1426 case Shr : masm.sarl(value); break;
1427 case Ushr : masm.shrl(value); break;
1428 default : throw Util.shouldNotReachHere();
1429 }
1430 } else {
1431 CiRegister lreg = left.asRegister();
1432 assert lreg != SHIFTCount : "left cannot be ECX";
1433
1434 switch (code) {
1435 case Shl : masm.shlq(lreg); break;
1436 case Shr : masm.sarq(lreg); break;
1437 case Ushr : masm.shrq(lreg); break;
1438 default : throw Util.shouldNotReachHere();
1439 }
1440 // Checkstyle: on
1441 }
1442 }
1443
1444 @Override
1445 protected void emitShiftOp(LIROpcode code, CiValue left, int count, CiValue dest) {
1446 assert dest.isRegister();
1447 if (dest.kind.isInt()) {
1448 // first move left into dest so that left is not destroyed by the shift
1449 CiRegister value = dest.asRegister();
1450 count = count & 0x1F; // Java spec
1451
1452 moveRegs(left.asRegister(), value);
1453 // Checkstyle: off
1454 switch (code) {
1455 case Shl : masm.shll(value, count); break;
1456 case Shr : masm.sarl(value, count); break;
1457 case Ushr : masm.shrl(value, count); break;
1458 default : throw Util.shouldNotReachHere();
1459 }
1460 } else {
1461
1462 // first move left into dest so that left is not destroyed by the shift
1463 CiRegister value = dest.asRegister();
1464 count = count & 0x1F; // Java spec
1465
1466 moveRegs(left.asRegister(), value);
1467 switch (code) {
1468 case Shl : masm.shlq(value, count); break;
1469 case Shr : masm.sarq(value, count); break;
1470 case Ushr : masm.shrq(value, count); break;
1471 default : throw Util.shouldNotReachHere();
1472 }
1473 // Checkstyle: on
1474 }
1475 }
1476
1477 @Override
1478 protected void emitSignificantBitOp(boolean most, CiValue src, CiValue dst) {
1479 assert dst.isRegister();
1480 CiRegister result = dst.asRegister();
1481 masm.xorq(result, result);
1482 masm.notq(result);
1483 if (src.isRegister()) {
1484 CiRegister value = src.asRegister();
1485 assert value != result;
1486 if (most) {
1487 masm.bsrq(result, value);
1488 } else {
1489 masm.bsfq(result, value);
1490 }
1491 } else {
1492 CiAddress laddr = asAddress(src);
1493 if (most) {
1494 masm.bsrq(result, laddr);
1495 } else {
1496 masm.bsfq(result, laddr);
1497 }
1498 }
1499 }
1500
1501 @Override
1502 protected void emitAlignment() {
1503 masm.align(wordSize);
1504 }
1505
1506 @Override
1507 protected void emitNegate(LIRNegate op) {
1508 CiValue left = op.operand();
1509 CiValue dest = op.result();
1510 assert left.isRegister();
1511 if (left.kind.isInt()) {
1512 masm.negl(left.asRegister());
1513 moveRegs(left.asRegister(), dest.asRegister());
1514
1515 } else if (dest.kind.isFloat()) {
1516 if (asXmmFloatReg(left) != asXmmFloatReg(dest)) {
1517 masm.movflt(asXmmFloatReg(dest), asXmmFloatReg(left));
1518 }
1519 callGlobalStub(op.globalStub, null, asXmmFloatReg(dest), dest);
1520
1521 } else if (dest.kind.isDouble()) {
1522 if (asXmmDoubleReg(left) != asXmmDoubleReg(dest)) {
1523 masm.movdbl(asXmmDoubleReg(dest), asXmmDoubleReg(left));
1524 }
1525
1526 callGlobalStub(op.globalStub, null, asXmmDoubleReg(dest), dest);
1527 } else {
1528 CiRegister lreg = left.asRegister();
1529 CiRegister dreg = dest.asRegister();
1530 masm.movq(dreg, lreg);
1531 masm.negq(dreg);
1532 }
1533 }
1534
1535 @Override
1536 protected void emitLea(CiValue src, CiValue dest) {
1537 CiRegister reg = dest.asRegister();
1538 masm.leaq(reg, asAddress(src));
1539 }
1540
1541 @Override
1542 protected void emitNullCheck(CiValue src, LIRDebugInfo info) {
1543 assert src.isRegister();
1544 if (C1XOptions.NullCheckUniquePc) {
1545 masm.nop();
1546 }
1547 tasm.recordImplicitException(codePos(), info);
1548 masm.nullCheck(src.asRegister());
1549 }
1550
1551 @Override
1552 protected void emitVolatileMove(CiValue src, CiValue dest, CiKind kind, LIRDebugInfo info) {
1553 assert kind == CiKind.Long : "only for volatile long fields";
1554
1555 if (info != null) {
1556 tasm.recordImplicitException(codePos(), info);
1557 }
1558
1559 if (src.kind.isDouble()) {
1560 if (dest.isRegister()) {
1561 masm.movdq(dest.asRegister(), asXmmDoubleReg(src));
1562 } else if (dest.isStackSlot()) {
1563 masm.movsd(frameMap.toStackAddress((CiStackSlot) dest), asXmmDoubleReg(src));
1564 } else {
1565 assert dest.isAddress();
1566 masm.movsd((CiAddress) dest, asXmmDoubleReg(src));
1567 }
1568 } else {
1569 assert dest.kind.isDouble();
1570 if (src.isStackSlot()) {
1571 masm.movdbl(asXmmDoubleReg(dest), frameMap.toStackAddress((CiStackSlot) src));
1572 } else {
1573 assert src.isAddress();
1574 masm.movdbl(asXmmDoubleReg(dest), (CiAddress) src);
1575 }
1576 }
1577 }
1578
1579 private static CiRegister asXmmDoubleReg(CiValue dest) {
1580 assert dest.kind.isDouble() : "must be double XMM register";
1581 CiRegister result = dest.asRegister();
1582 assert result.isFpu() : "must be XMM register";
1583 return result;
1584 }
1585
1586 @Override
1587 protected void emitMemoryBarriers(int barriers) {
1588 masm.membar(barriers);
1589 }
1590
1591 @Override
1592 protected void doPeephole(LIRList list) {
1593 // Do nothing for now
1594 }
1595
1596 @Override
1597 protected void emitXir(LIRXirInstruction instruction) {
1598 XirSnippet snippet = instruction.snippet;
1599
1600 Label[] labels = new Label[snippet.template.labels.length];
1601 for (int i = 0; i < labels.length; i++) {
1602 labels[i] = new Label();
1603 }
1604 emitXirInstructions(instruction, snippet.template.fastPath, labels, instruction.getOperands(), snippet.marks);
1605 if (snippet.template.slowPath != null) {
1606 addSlowPath(new SlowPath(instruction, labels, snippet.marks));
1607 }
1608 }
1609
1610 @Override
1611 protected void emitSlowPath(SlowPath sp) {
1612 int start = -1;
1613 if (C1XOptions.TraceAssembler) {
1614 TTY.println("Emitting slow path for XIR instruction " + sp.instruction.snippet.template.name);
1615 start = masm.codeBuffer.position();
1616 }
1617 emitXirInstructions(sp.instruction, sp.instruction.snippet.template.slowPath, sp.labels, sp.instruction.getOperands(), sp.marks);
1618 masm.nop();
1619 if (C1XOptions.TraceAssembler) {
1620 TTY.println("From " + start + " to " + masm.codeBuffer.position());
1621 }
1622 }
1623
1624 public void emitXirInstructions(LIRXirInstruction xir, XirInstruction[] instructions, Label[] labels, CiValue[] operands, Map<XirMark, Mark> marks) {
1625 LIRDebugInfo info = xir == null ? null : xir.info;
1626 LIRDebugInfo infoAfter = xir == null ? null : xir.infoAfter;
1627
1628 for (XirInstruction inst : instructions) {
1629 switch (inst.op) {
1630 case Add:
1631 emitArithOp(LIROpcode.Add, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index], null);
1632 break;
1633
1634 case Sub:
1635 emitArithOp(LIROpcode.Sub, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index], null);
1636 break;
1637
1638 case Div:
1639 if (inst.kind == CiKind.Int) {
1640 arithmeticIdiv(LIROpcode.Idiv, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index], null);
1641 } else {
1642 emitArithOp(LIROpcode.Div, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index], null);
1643 }
1644 break;
1645
1646 case Mul:
1647 emitArithOp(LIROpcode.Mul, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index], null);
1648 break;
1649
1650 case Mod:
1651 if (inst.kind == CiKind.Int) {
1652 arithmeticIdiv(LIROpcode.Irem, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index], null);
1653 } else {
1654 emitArithOp(LIROpcode.Rem, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index], null);
1655 }
1656 break;
1657
1658 case Shl:
1659 emitXIRShiftOp(LIROpcode.Shl, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index]);
1660 break;
1661
1662 case Sar:
1663 emitXIRShiftOp(LIROpcode.Shr, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index]);
1664 break;
1665
1666 case Shr:
1667 emitXIRShiftOp(LIROpcode.Ushr, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index]);
1668 break;
1669
1670 case And:
1671 emitLogicOp(LIROpcode.LogicAnd, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index]);
1672 break;
1673
1674 case Or:
1675 emitLogicOp(LIROpcode.LogicOr, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index]);
1676 break;
1677
1678 case Xor:
1679 emitLogicOp(LIROpcode.LogicXor, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index]);
1680 break;
1681
1682 case Mov: {
1683 CiValue result = operands[inst.result.index];
1684 CiValue source = operands[inst.x().index];
1685 moveOp(source, result, result.kind, null, false);
1686 break;
1687 }
1688
1689 case PointerLoad: {
1690 if ((Boolean) inst.extra && info != null) {
1691 tasm.recordImplicitException(codePos(), info);
1692 }
1693
1694 CiValue result = operands[inst.result.index];
1695 CiValue pointer = operands[inst.x().index];
1696 CiRegisterValue register = assureInRegister(pointer);
1697 moveOp(new CiAddress(inst.kind, register, 0), result, inst.kind, null, false);
1698 break;
1699 }
1700
1701 case PointerStore: {
1702 if ((Boolean) inst.extra && info != null) {
1703 tasm.recordImplicitException(codePos(), info);
1704 }
1705
1706 CiValue value = operands[inst.y().index];
1707 CiValue pointer = operands[inst.x().index];
1708 assert pointer.isVariableOrRegister();
1709 moveOp(value, new CiAddress(inst.kind, pointer, 0), inst.kind, null, false);
1710 break;
1711 }
1712
1713 case PointerLoadDisp: {
1714 CiXirAssembler.AddressAccessInformation addressInformation = (CiXirAssembler.AddressAccessInformation) inst.extra;
1715 boolean canTrap = addressInformation.canTrap;
1716
1717 CiAddress.Scale scale = addressInformation.scale;
1718 int displacement = addressInformation.disp;
1719
1720 CiValue result = operands[inst.result.index];
1721 CiValue pointer = operands[inst.x().index];
1722 CiValue index = operands[inst.y().index];
1723
1724 pointer = assureInRegister(pointer);
1725 assert pointer.isVariableOrRegister();
1726
1727 CiValue src = null;
1728 if (index.isConstant()) {
1729 assert index.kind == CiKind.Int;
1730 CiConstant constantIndex = (CiConstant) index;
1731 src = new CiAddress(inst.kind, pointer, constantIndex.asInt() * scale.value + displacement);
1732 } else {
1733 src = new CiAddress(inst.kind, pointer, index, scale, displacement);
1734 }
1735
1736 moveOp(src, result, inst.kind, canTrap ? info : null, false);
1737 break;
1738 }
1739
1740 case LoadEffectiveAddress: {
1741 CiXirAssembler.AddressAccessInformation addressInformation = (CiXirAssembler.AddressAccessInformation) inst.extra;
1742
1743 CiAddress.Scale scale = addressInformation.scale;
1744 int displacement = addressInformation.disp;
1745
1746 CiValue result = operands[inst.result.index];
1747 CiValue pointer = operands[inst.x().index];
1748 CiValue index = operands[inst.y().index];
1749
1750 pointer = assureInRegister(pointer);
1751 assert pointer.isVariableOrRegister();
1752 CiValue src = new CiAddress(CiKind.Illegal, pointer, index, scale, displacement);
1753 emitLea(src, result);
1754 break;
1755 }
1756
1757 case PointerStoreDisp: {
1758 CiXirAssembler.AddressAccessInformation addressInformation = (CiXirAssembler.AddressAccessInformation) inst.extra;
1759 boolean canTrap = addressInformation.canTrap;
1760
1761 CiAddress.Scale scale = addressInformation.scale;
1762 int displacement = addressInformation.disp;
1763
1764 CiValue value = operands[inst.z().index];
1765 CiValue pointer = operands[inst.x().index];
1766 CiValue index = operands[inst.y().index];
1767
1768 pointer = assureInRegister(pointer);
1769 assert pointer.isVariableOrRegister();
1770
1771 CiValue dst;
1772 if (index.isConstant()) {
1773 assert index.kind == CiKind.Int;
1774 CiConstant constantIndex = (CiConstant) index;
1775 dst = new CiAddress(inst.kind, pointer, IllegalValue, scale, constantIndex.asInt() * scale.value + displacement);
1776 } else {
1777 dst = new CiAddress(inst.kind, pointer, index, scale, displacement);
1778 }
1779
1780 moveOp(value, dst, inst.kind, canTrap ? info : null, false);
1781 break;
1782 }
1783
1784 case RepeatMoveBytes:
1785 assert operands[inst.x().index].asRegister().equals(AMD64.rsi) : "wrong input x: " + operands[inst.x().index];
1786 assert operands[inst.y().index].asRegister().equals(AMD64.rdi) : "wrong input y: " + operands[inst.y().index];
1787 assert operands[inst.z().index].asRegister().equals(AMD64.rcx) : "wrong input z: " + operands[inst.z().index];
1788 masm.repeatMoveBytes();
1789 break;
1790
1791 case RepeatMoveWords:
1792 assert operands[inst.x().index].asRegister().equals(AMD64.rsi) : "wrong input x: " + operands[inst.x().index];
1793 assert operands[inst.y().index].asRegister().equals(AMD64.rdi) : "wrong input y: " + operands[inst.y().index];
1794 assert operands[inst.z().index].asRegister().equals(AMD64.rcx) : "wrong input z: " + operands[inst.z().index];
1795 masm.repeatMoveWords();
1796 break;
1797
1798 case PointerCAS:
1799
1800 if ((Boolean) inst.extra && info != null) {
1801 tasm.recordImplicitException(codePos(), info);
1802 }
1803 assert operands[inst.x().index].asRegister().equals(AMD64.rax) : "wrong input x: " + operands[inst.x().index];
1804
1805 CiValue exchangedVal = operands[inst.y().index];
1806 CiValue exchangedAddress = operands[inst.x().index];
1807 CiRegisterValue pointerRegister = assureInRegister(exchangedAddress);
1808 CiAddress addr = new CiAddress(CiKind.Word, pointerRegister);
1809 masm.cmpxchgq(exchangedVal.asRegister(), addr);
1810
1811 break;
1812
1813 case CallStub: {
1814 XirTemplate stubId = (XirTemplate) inst.extra;
1815 CiRegister result = CiRegister.None;
1816 if (inst.result != null) {
1817 result = operands[inst.result.index].asRegister();
1818 }
1819 CiValue[] args = new CiValue[inst.arguments.length];
1820 for (int i = 0; i < args.length; i++) {
1821 args[i] = operands[inst.arguments[i].index];
1822 }
1823 callGlobalStub(stubId, info, result, args);
1824 break;
1825 }
1826 case CallRuntime: {
1827 CiKind[] signature = new CiKind[inst.arguments.length];
1828 for (int i = 0; i < signature.length; i++) {
1829 signature[i] = inst.arguments[i].kind;
1830 }
1831
1832 CiCallingConvention cc = frameMap.getCallingConvention(signature, RuntimeCall);
1833 for (int i = 0; i < inst.arguments.length; i++) {
1834 CiValue argumentLocation = cc.locations[i];
1835 CiValue argumentSourceLocation = operands[inst.arguments[i].index];
1836 if (argumentLocation != argumentSourceLocation) {
1837 moveOp(argumentSourceLocation, argumentLocation, argumentLocation.kind, null, false);
1838 }
1839 }
1840
1841 RuntimeCallInformation runtimeCallInformation = (RuntimeCallInformation) inst.extra;
1842 directCall(runtimeCallInformation.target, (runtimeCallInformation.useInfoAfter) ? infoAfter : info);
1843
1844 if (inst.result != null && inst.result.kind != CiKind.Illegal && inst.result.kind != CiKind.Void) {
1845 CiRegister returnRegister = compilation.registerConfig.getReturnRegister(inst.result.kind);
1846 CiValue resultLocation = returnRegister.asValue(inst.result.kind.stackKind());
1847 moveOp(resultLocation, operands[inst.result.index], inst.result.kind.stackKind(), null, false);
1848 }
1849 break;
1850 }
1851 case Jmp: {
1852 if (inst.extra instanceof XirLabel) {
1853 Label label = labels[((XirLabel) inst.extra).index];
1854 masm.jmp(label);
1855 } else {
1856 directJmp(inst.extra);
1857 }
1858 break;
1859 }
1860 case DecAndJumpNotZero: {
1861 Label label = labels[((XirLabel) inst.extra).index];
1862 CiValue value = operands[inst.x().index];
1863 if (value.kind == CiKind.Long) {
1864 masm.decq(value.asRegister());
1865 } else {
1866 assert value.kind == CiKind.Int;
1867 masm.decl(value.asRegister());
1868 }
1869 masm.jcc(ConditionFlag.notZero, label);
1870 break;
1871 }
1872 case Jeq: {
1873 Label label = labels[((XirLabel) inst.extra).index];
1874 emitXirCompare(inst, Condition.EQ, ConditionFlag.equal, operands, label);
1875 break;
1876 }
1877 case Jneq: {
1878 Label label = labels[((XirLabel) inst.extra).index];
1879 emitXirCompare(inst, Condition.NE, ConditionFlag.notEqual, operands, label);
1880 break;
1881 }
1882
1883 case Jgt: {
1884 Label label = labels[((XirLabel) inst.extra).index];
1885 emitXirCompare(inst, Condition.GT, ConditionFlag.greater, operands, label);
1886 break;
1887 }
1888
1889 case Jgteq: {
1890 Label label = labels[((XirLabel) inst.extra).index];
1891 emitXirCompare(inst, Condition.GE, ConditionFlag.greaterEqual, operands, label);
1892 break;
1893 }
1894
1895 case Jugteq: {
1896 Label label = labels[((XirLabel) inst.extra).index];
1897 emitXirCompare(inst, Condition.AE, ConditionFlag.aboveEqual, operands, label);
1898 break;
1899 }
1900
1901 case Jlt: {
1902 Label label = labels[((XirLabel) inst.extra).index];
1903 emitXirCompare(inst, Condition.LT, ConditionFlag.less, operands, label);
1904 break;
1905 }
1906
1907 case Jlteq: {
1908 Label label = labels[((XirLabel) inst.extra).index];
1909 emitXirCompare(inst, Condition.LE, ConditionFlag.lessEqual, operands, label);
1910 break;
1911 }
1912
1913 case Jbset: {
1914 Label label = labels[((XirLabel) inst.extra).index];
1915 CiValue pointer = operands[inst.x().index];
1916 CiValue offset = operands[inst.y().index];
1917 CiValue bit = operands[inst.z().index];
1918 assert offset.isConstant() && bit.isConstant();
1919 CiConstant constantOffset = (CiConstant) offset;
1920 CiConstant constantBit = (CiConstant) bit;
1921 CiAddress src = new CiAddress(inst.kind, pointer, constantOffset.asInt());
1922 masm.btli(src, constantBit.asInt());
1923 masm.jcc(ConditionFlag.aboveEqual, label);
1924 break;
1925 }
1926
1927 case Bind: {
1928 XirLabel l = (XirLabel) inst.extra;
1929 Label label = labels[l.index];
1930 asm.bind(label);
1931 break;
1932 }
1933 case Safepoint: {
1934 assert info != null : "Must have debug info in order to create a safepoint.";
1935 tasm.recordSafepoint(codePos(), info);
1936 break;
1937 }
1938 case NullCheck: {
1939 tasm.recordImplicitException(codePos(), info);
1940 CiValue pointer = operands[inst.x().index];
1941 masm.nullCheck(pointer.asRegister());
1942 break;
1943 }
1944 case Align: {
1945 masm.align((Integer) inst.extra);
1946 break;
1947 }
1948 case StackOverflowCheck: {
1949 int frameSize = initialFrameSizeInBytes();
1950 int lastFramePage = frameSize / target.pageSize;
1951 // emit multiple stack bangs for methods with frames larger than a page
1952 for (int i = 0; i <= lastFramePage; i++) {
1953 int offset = (i + C1XOptions.StackShadowPages) * target.pageSize;
1954 // Deduct 'frameSize' to handle frames larger than the shadow
1955 bangStackWithOffset(offset - frameSize);
1956 }
1957 break;
1958 }
1959 case PushFrame: {
1960 int frameSize = initialFrameSizeInBytes();
1961 masm.decrementq(AMD64.rsp, frameSize); // does not emit code for frameSize == 0
1962 if (C1XOptions.ZapStackOnMethodEntry) {
1963 final int intSize = 4;
1964 for (int i = 0; i < frameSize / intSize; ++i) {
1965 masm.movl(new CiAddress(CiKind.Int, AMD64.rsp.asValue(), i * intSize), 0xC1C1C1C1);
1966 }
1967 }
1968 CiCalleeSaveArea csa = compilation.registerConfig.getCalleeSaveArea();
1969 if (csa.size != 0) {
1970 int frameToCSA = frameMap.offsetToCalleeSaveAreaStart();
1971 assert frameToCSA >= 0;
1972 masm.save(csa, frameToCSA);
1973 }
1974 break;
1975 }
1976 case PopFrame: {
1977 int frameSize = initialFrameSizeInBytes();
1978
1979 CiCalleeSaveArea csa = compilation.registerConfig.getCalleeSaveArea();
1980 if (csa.size != 0) {
1981 registerRestoreEpilogueOffset = masm.codeBuffer.position();
1982 // saved all registers, restore all registers
1983 int frameToCSA = frameMap.offsetToCalleeSaveAreaStart();
1984 masm.restore(csa, frameToCSA);
1985 }
1986
1987 masm.incrementq(AMD64.rsp, frameSize);
1988 break;
1989 }
1990 case Push: {
1991 CiRegisterValue value = assureInRegister(operands[inst.x().index]);
1992 masm.push(value.asRegister());
1993 break;
1994 }
1995 case Pop: {
1996 CiValue result = operands[inst.result.index];
1997 if (result.isRegister()) {
1998 masm.pop(result.asRegister());
1999 } else {
2000 masm.pop(rscratch1);
2001 moveOp(rscratch1.asValue(), result, result.kind, null, true);
2002 }
2003 break;
2004 }
2005 case Mark: {
2006 XirMark xmark = (XirMark) inst.extra;
2007 Mark[] references = new Mark[xmark.references.length];
2008 for (int i = 0; i < references.length; i++) {
2009 references[i] = marks.get(xmark.references[i]);
2010 assert references[i] != null;
2011 }
2012 Mark mark = tasm.recordMark(xmark.id, references);
2013 marks.put(xmark, mark);
2014 break;
2015 }
2016 case Nop: {
2017 for (int i = 0; i < (Integer) inst.extra; i++) {
2018 masm.nop();
2019 }
2020 break;
2021 }
2022 case RawBytes: {
2023 for (byte b : (byte[]) inst.extra) {
2024 masm.codeBuffer.emitByte(b & 0xff);
2025 }
2026 break;
2027 }
2028 case ShouldNotReachHere: {
2029 if (inst.extra == null) {
2030 stop("should not reach here");
2031 } else {
2032 stop("should not reach here: " + inst.extra);
2033 }
2034 break;
2035 }
2036 default:
2037 assert false : "Unknown XIR operation " + inst.op;
2038 }
2039 }
2040 }
2041
2042 /**
2043 * @param offset the offset RSP at which to bang. Note that this offset is relative to RSP after RSP has been
2044 * adjusted to allocated the frame for the method. It denotes an offset "down" the stack.
2045 * For very large frames, this means that the offset may actually be negative (i.e. denoting
2046 * a slot "up" the stack above RSP).
2047 */
2048 private void bangStackWithOffset(int offset) {
2049 masm.movq(new CiAddress(CiKind.Word, AMD64.RSP, -offset), AMD64.rax);
2050 }
2051
2052 private CiRegisterValue assureInRegister(CiValue pointer) {
2053 if (pointer.isConstant()) {
2054 CiRegisterValue register = rscratch1.asValue(pointer.kind);
2055 moveOp(pointer, register, pointer.kind, null, false);
2056 return register;
2057 }
2058
2059 assert pointer.isRegister() : "should be register, but is: " + pointer;
2060 return (CiRegisterValue) pointer;
2061 }
2062
2063 private void emitXirCompare(XirInstruction inst, Condition condition, ConditionFlag cflag, CiValue[] ops, Label label) {
2064 CiValue x = ops[inst.x().index];
2065 CiValue y = ops[inst.y().index];
2066 emitCompare(condition, x, y, null);
2067 masm.jcc(cflag, label);
2068 }
2069
2070 @Override
2071 public void emitDeoptizationStub(DeoptimizationStub stub) {
2072 masm.bind(stub.label);
2073 directCall(CiRuntimeCall.Deoptimize, stub.info);
2074 shouldNotReachHere();
2075 }
2076
2077 public GlobalStub lookupGlobalStub(XirTemplate template) {
2078 return compilation.compiler.lookupGlobalStub(template);
2079 }
2080
2081 public void callGlobalStub(XirTemplate stub, LIRDebugInfo info, CiRegister result, CiValue... args) {
2082 callGlobalStubHelper(lookupGlobalStub(stub), stub.resultOperand.kind, info, result, args);
2083 }
2084
2085 public void callGlobalStub(GlobalStub stub, LIRDebugInfo info, CiRegister result, CiValue... args) {
2086 callGlobalStubHelper(stub, stub.resultKind, info, result, args);
2087 }
2088
2089 private void callGlobalStubHelper(GlobalStub stub, CiKind resultKind, LIRDebugInfo info, CiRegister result, CiValue... args) {
2090 assert args.length == stub.argOffsets.length;
2091
2092 for (int i = 0; i < args.length; i++) {
2093 storeParameter(args[i], stub.argOffsets[i]);
2094 }
2095
2096 directCall(stub.stubObject, info);
2097
2098 if (result != CiRegister.None) {
2099 loadResult(result, stub.resultOffset, resultKind);
2100 }
2101
2102 // Clear out parameters
2103 if (C1XOptions.GenAssertionCode) {
2104 for (int i = 0; i < args.length; i++) {
2105 masm.movptr(new CiAddress(CiKind.Word, AMD64.RSP, stub.argOffsets[i]), 0);
2106 }
2107 }
2108 }
2109
2110 private void loadResult(CiRegister r, int offset, CiKind kind) {
2111 if (kind == CiKind.Int || kind == CiKind.Boolean) {
2112 masm.movl(r, new CiAddress(CiKind.Int, AMD64.RSP, offset));
2113 } else if (kind == CiKind.Float) {
2114 masm.movss(r, new CiAddress(CiKind.Float, AMD64.RSP, offset));
2115 } else if (kind == CiKind.Double) {
2116 masm.movsd(r, new CiAddress(CiKind.Double, AMD64.RSP, offset));
2117 } else {
2118 masm.movq(r, new CiAddress(CiKind.Word, AMD64.RSP, offset));
2119 }
2120 }
2121
2122 private void storeParameter(CiValue registerOrConstant, int offset) {
2123 CiKind k = registerOrConstant.kind;
2124 if (registerOrConstant.isConstant()) {
2125 CiConstant c = (CiConstant) registerOrConstant;
2126 if (c.kind == CiKind.Object) {
2127 movoop(new CiAddress(CiKind.Word, AMD64.RSP, offset), c);
2128 } else {
2129 masm.movptr(new CiAddress(CiKind.Word, AMD64.RSP, offset), c.asInt());
2130 }
2131 } else if (registerOrConstant.isRegister()) {
2132 if (k.isFloat()) {
2133 masm.movss(new CiAddress(CiKind.Float, AMD64.RSP, offset), registerOrConstant.asRegister());
2134 } else if (k.isDouble()) {
2135 masm.movsd(new CiAddress(CiKind.Double, AMD64.RSP, offset), registerOrConstant.asRegister());
2136 } else {
2137 masm.movq(new CiAddress(CiKind.Word, AMD64.RSP, offset), registerOrConstant.asRegister());
2138 }
2139 } else {
2140 throw new InternalError("should not reach here");
2141 }
2142 }
2143
2144 public void movoop(CiRegister dst, CiConstant obj) {
2145 assert obj.kind == CiKind.Object;
2146 if (obj.isNull()) {
2147 masm.xorq(dst, dst);
2148 } else {
2149 if (target.inlineObjects) {
2150 tasm.recordDataReferenceInCode(obj);
2151 masm.movq(dst, 0xDEADDEADDEADDEADL);
2152 } else {
2153 masm.movq(dst, tasm.recordDataReferenceInCode(obj));
2154 }
2155 }
2156 }
2157
2158 public void movoop(CiAddress dst, CiConstant obj) {
2159 movoop(rscratch1, obj);
2160 masm.movq(dst, rscratch1);
2161 }
2162
2163 public void directCall(Object target, LIRDebugInfo info) {
2164 int before = masm.codeBuffer.position();
2165 masm.call();
2166 int after = masm.codeBuffer.position();
2167 tasm.recordDirectCall(before, after, target, info);
2168 tasm.recordExceptionHandlers(after, info);
2169 }
2170
2171 public void directJmp(Object target) {
2172 int before = masm.codeBuffer.position();
2173 masm.jmp(0, true);
2174 int after = masm.codeBuffer.position();
2175 tasm.recordDirectCall(before, after, target, null);
2176 }
2177
2178 public void indirectCall(CiRegister dst, Object target, LIRDebugInfo info) {
2179 int before = masm.codeBuffer.position();
2180 masm.call(dst);
2181 int after = masm.codeBuffer.position();
2182 tasm.recordIndirectCall(before, after, target, info);
2183 tasm.recordExceptionHandlers(after, info);
2184 }
2185
2186 protected void stop(String msg) {
2187 if (C1XOptions.GenAssertionCode) {
2188 // TODO: pass a pointer to the message
2189 directCall(CiRuntimeCall.Debug, null);
2190 masm.hlt();
2191 }
2192 }
2193
2194 public void shouldNotReachHere() {
2195 stop("should not reach here");
2196 }
2197 }