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

Renamings Runtime=>GraalRuntime and Compiler=>GraalCompiler
author Thomas Wuerthinger <thomas@wuerthinger.net>
date Wed, 27 Apr 2011 11:50:44 +0200
parents graal/Compiler/src/com/sun/c1x/target/amd64/AMD64LIRAssembler.java@9ec15d6914ca
children 9f557e940180
comparison
equal deleted inserted replaced
2508:fea94949e0a2 2509:16b9a8b5ad39
1 /*
2 * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23 package com.sun.c1x.target.amd64;
24
25 import static com.sun.cri.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.sun.c1x.*;
35 import com.sun.c1x.asm.*;
36 import com.sun.c1x.debug.*;
37 import com.sun.c1x.gen.LIRGenerator.DeoptimizationStub;
38 import com.sun.c1x.ir.*;
39 import com.sun.c1x.lir.FrameMap.StackBlock;
40 import com.sun.c1x.lir.*;
41 import com.sun.c1x.target.amd64.AMD64Assembler.ConditionFlag;
42 import com.sun.c1x.util.*;
43 import com.sun.cri.ci.*;
44 import com.sun.cri.ci.CiAddress.Scale;
45 import com.sun.cri.ci.CiTargetMethod.JumpTable;
46 import com.sun.cri.ci.CiTargetMethod.Mark;
47 import com.sun.cri.xir.*;
48 import com.sun.cri.xir.CiXirAssembler.RuntimeCallInformation;
49 import com.sun.cri.xir.CiXirAssembler.XirInstruction;
50 import com.sun.cri.xir.CiXirAssembler.XirLabel;
51 import com.sun.cri.xir.CiXirAssembler.XirMark;
52
53 /**
54 * This class implements the x86-specific code generation for LIR.
55 *
56 * @author Thomas Wuerthinger
57 * @author Ben L. Titzer
58 */
59 public final class AMD64LIRAssembler extends LIRAssembler {
60
61 private static final Object[] NO_PARAMS = new Object[0];
62 private static final long NULLWORD = 0;
63 private static final CiRegister SHIFTCount = AMD64.rcx;
64
65 private static final long DoubleSignMask = 0x7FFFFFFFFFFFFFFFL;
66
67 final CiTarget target;
68 final AMD64MacroAssembler masm;
69 final int wordSize;
70 final CiRegister rscratch1;
71
72 public AMD64LIRAssembler(C1XCompilation compilation) {
73 super(compilation);
74 masm = (AMD64MacroAssembler) compilation.masm();
75 target = compilation.target;
76 wordSize = target.wordSize;
77 rscratch1 = compilation.registerConfig.getScratchRegister();
78 }
79
80 private CiAddress asAddress(CiValue value) {
81 if (value.isAddress()) {
82 return (CiAddress) value;
83 }
84 assert value.isStackSlot();
85 return compilation.frameMap().toStackAddress((CiStackSlot) value);
86 }
87
88 @Override
89 protected void emitOsrEntry() {
90 throw Util.unimplemented();
91 }
92
93 @Override
94 protected int initialFrameSizeInBytes() {
95 return frameMap.frameSize();
96 }
97
98 @Override
99 protected void emitReturn(CiValue result) {
100 // TODO: Consider adding safepoint polling at return!
101 masm.ret(0);
102 }
103
104 @Override
105 protected void emitHere(CiValue dst, LIRDebugInfo info, boolean infoOnly) {
106 masm.recordSafepoint(codePos(), info);
107 if (!infoOnly) {
108 masm.codeBuffer.mark();
109 masm.leaq(dst.asRegister(), new CiAddress(CiKind.Word, InstructionRelative.asValue(), 0));
110 }
111 }
112
113 @Override
114 protected void emitMonitorAddress(int monitor, CiValue dst) {
115 CiStackSlot slot = frameMap.toMonitorBaseStackAddress(monitor);
116 masm.leaq(dst.asRegister(), new CiAddress(slot.kind, AMD64.rsp.asValue(), slot.index() * target.arch.wordSize));
117 }
118
119 @Override
120 protected void emitPause() {
121 masm.pause();
122 }
123
124 @Override
125 protected void emitBreakpoint() {
126 masm.int3();
127 }
128
129 @Override
130 protected void emitStackAllocate(StackBlock stackBlock, CiValue dst) {
131 masm.leaq(dst.asRegister(), compilation.frameMap().toStackAddress(stackBlock));
132 }
133
134 private void moveRegs(CiRegister fromReg, CiRegister toReg) {
135 if (fromReg != toReg) {
136 masm.mov(toReg, fromReg);
137 }
138 }
139
140 private void swapReg(CiRegister a, CiRegister b) {
141 masm.xchgptr(a, b);
142 }
143
144 private void const2reg(CiRegister dst, int constant) {
145 // Do not optimize with an XOR as this instruction may be between
146 // a CMP and a Jcc in which case the XOR will modify the condition
147 // flags and interfere with the Jcc.
148 masm.movl(dst, constant);
149 }
150
151 private void const2reg(CiRegister dst, long constant) {
152 // Do not optimize with an XOR as this instruction may be between
153 // a CMP and a Jcc in which case the XOR will modify the condition
154 // flags and interfere with the Jcc.
155 masm.movq(dst, constant);
156 }
157
158 private void const2reg(CiRegister dst, CiConstant constant) {
159 assert constant.kind == CiKind.Object;
160 // Do not optimize with an XOR as this instruction may be between
161 // a CMP and a Jcc in which case the XOR will modify the condition
162 // flags and interfere with the Jcc.
163 if (constant.isNull()) {
164 masm.movq(dst, 0x0L);
165 } else if (target.inlineObjects) {
166 masm.recordDataReferenceInCode(constant);
167 masm.movq(dst, 0xDEADDEADDEADDEADL);
168 } else {
169 masm.movq(dst, masm.recordDataReferenceInCode(constant));
170 }
171 }
172
173 @Override
174 public void emitTraps() {
175 for (int i = 0; i < C1XOptions.MethodEndBreakpointGuards; ++i) {
176 masm.int3();
177 }
178 }
179
180 private void const2reg(CiRegister dst, float constant) {
181 if (constant == 0.0f) {
182 masm.xorps(dst, dst);
183 } else {
184 masm.movflt(dst, masm.recordDataReferenceInCode(CiConstant.forFloat(constant)));
185 }
186 }
187
188 private void const2reg(CiRegister dst, double constant) {
189 if (constant == 0.0f) {
190 masm.xorpd(dst, dst);
191 } else {
192 masm.movdbl(dst, masm.recordDataReferenceInCode(CiConstant.forDouble(constant)));
193 }
194 }
195
196 @Override
197 protected void const2reg(CiValue src, CiValue dest, LIRDebugInfo info) {
198 assert src.isConstant();
199 assert dest.isRegister();
200 CiConstant c = (CiConstant) src;
201
202 switch (c.kind) {
203 case Boolean :
204 case Byte :
205 case Char :
206 case Short :
207 case Jsr :
208 case Int : const2reg(dest.asRegister(), c.asInt()); break;
209 case Word :
210 case Long : const2reg(dest.asRegister(), c.asLong()); break;
211 case Object : const2reg(dest.asRegister(), c); break;
212 case Float : const2reg(asXmmFloatReg(dest), c.asFloat()); break;
213 case Double : const2reg(asXmmDoubleReg(dest), c.asDouble()); break;
214 default : throw Util.shouldNotReachHere();
215 }
216 }
217
218 @Override
219 protected void const2stack(CiValue src, CiValue dst) {
220 assert src.isConstant();
221 assert dst.isStackSlot();
222 CiStackSlot slot = (CiStackSlot) dst;
223 CiConstant c = (CiConstant) src;
224
225 switch (c.kind) {
226 case Boolean :
227 case Byte :
228 case Char :
229 case Short :
230 case Jsr :
231 case Int : masm.movl(frameMap.toStackAddress(slot), c.asInt()); break;
232 case Float : masm.movl(frameMap.toStackAddress(slot), floatToRawIntBits(c.asFloat())); break;
233 case Object : masm.movoop(frameMap.toStackAddress(slot), c); break;
234 case Long : masm.mov64(frameMap.toStackAddress(slot), c.asLong()); break;
235 case Double : masm.mov64(frameMap.toStackAddress(slot), doubleToRawLongBits(c.asDouble())); break;
236 default : throw Util.shouldNotReachHere("Unknown constant kind for const2stack: " + c.kind);
237 }
238 }
239
240 @Override
241 protected void const2mem(CiValue src, CiValue dst, CiKind kind, LIRDebugInfo info) {
242 assert src.isConstant();
243 assert dst.isAddress();
244 CiConstant constant = (CiConstant) src;
245 CiAddress addr = asAddress(dst);
246
247 int nullCheckHere = codePos();
248 switch (kind) {
249 case Boolean :
250 case Byte : masm.movb(addr, constant.asInt() & 0xFF); break;
251 case Char :
252 case Short : masm.movw(addr, constant.asInt() & 0xFFFF); break;
253 case Jsr :
254 case Int : masm.movl(addr, constant.asInt()); break;
255 case Float : masm.movl(addr, floatToRawIntBits(constant.asFloat())); break;
256 case Object : masm.movoop(addr, constant); break;
257 case Word:
258 case Long : masm.movq(rscratch1, constant.asLong());
259 nullCheckHere = codePos();
260 masm.movq(addr, rscratch1); break;
261 case Double : masm.movq(rscratch1, doubleToRawLongBits(constant.asDouble()));
262 nullCheckHere = codePos();
263 masm.movq(addr, rscratch1); break;
264 default : throw Util.shouldNotReachHere();
265 }
266
267 if (info != null) {
268 asm.recordImplicitException(nullCheckHere, info);
269 }
270 }
271
272 @Override
273 protected void reg2reg(CiValue src, CiValue dest) {
274 assert src.isRegister();
275 assert dest.isRegister();
276
277 if (dest.kind.isFloat()) {
278 masm.movflt(asXmmFloatReg(dest), asXmmFloatReg(src));
279 } else if (dest.kind.isDouble()) {
280 masm.movdbl(asXmmDoubleReg(dest), asXmmDoubleReg(src));
281 } else {
282 moveRegs(src.asRegister(), dest.asRegister());
283 }
284 }
285
286 @Override
287 protected void reg2stack(CiValue src, CiValue dst, CiKind kind) {
288 assert src.isRegister();
289 assert dst.isStackSlot();
290 CiAddress addr = frameMap.toStackAddress(((CiStackSlot) dst));
291
292 switch (src.kind) {
293 case Boolean :
294 case Byte :
295 case Char :
296 case Short :
297 case Jsr :
298 case Int : masm.movl(addr, src.asRegister()); break;
299 case Object :
300 case Word :
301 case Long : masm.movq(addr, src.asRegister()); break;
302 case Float : masm.movflt(addr, asXmmFloatReg(src)); break;
303 case Double : masm.movsd(addr, asXmmDoubleReg(src)); break;
304 default : throw Util.shouldNotReachHere();
305 }
306 }
307
308 @Override
309 protected void reg2mem(CiValue src, CiValue dest, CiKind kind, LIRDebugInfo info, boolean unaligned) {
310 CiAddress toAddr = (CiAddress) dest;
311
312 if (info != null) {
313 asm.recordImplicitException(codePos(), info);
314 }
315
316 switch (kind) {
317 case Float : masm.movflt(toAddr, asXmmFloatReg(src)); break;
318 case Double : masm.movsd(toAddr, asXmmDoubleReg(src)); break;
319 case Jsr :
320 case Int : masm.movl(toAddr, src.asRegister()); break;
321 case Long :
322 case Word :
323 case Object : masm.movq(toAddr, src.asRegister()); break;
324 case Char :
325 case Short : masm.movw(toAddr, src.asRegister()); break;
326 case Byte :
327 case Boolean : masm.movb(toAddr, src.asRegister()); break;
328 default : throw Util.shouldNotReachHere();
329 }
330 }
331
332 private static CiRegister asXmmFloatReg(CiValue src) {
333 assert src.kind.isFloat() : "must be float, actual kind: " + src.kind;
334 CiRegister result = src.asRegister();
335 assert result.isFpu() : "must be xmm, actual type: " + result;
336 return result;
337 }
338
339 @Override
340 protected void stack2reg(CiValue src, CiValue dest, CiKind kind) {
341 assert src.isStackSlot();
342 assert dest.isRegister();
343
344 CiAddress addr = frameMap.toStackAddress(((CiStackSlot) src));
345
346 switch (dest.kind) {
347 case Boolean :
348 case Byte :
349 case Char :
350 case Short :
351 case Jsr :
352 case Int : masm.movl(dest.asRegister(), addr); break;
353 case Object :
354 case Word :
355 case Long : masm.movq(dest.asRegister(), addr); break;
356 case Float : masm.movflt(asXmmFloatReg(dest), addr); break;
357 case Double : masm.movdbl(asXmmDoubleReg(dest), addr); break;
358 default : throw Util.shouldNotReachHere();
359 }
360 }
361
362 @Override
363 protected void mem2mem(CiValue src, CiValue dest, CiKind kind) {
364 if (dest.kind.isInt()) {
365 masm.pushl(((CiAddress) src));
366 masm.popl(((CiAddress) dest));
367 } else {
368 masm.pushptr(((CiAddress) src));
369 masm.popptr(((CiAddress) dest));
370 }
371 }
372
373 @Override
374 protected void mem2stack(CiValue src, CiValue dest, CiKind kind) {
375 if (dest.kind.isInt()) {
376 masm.pushl(((CiAddress) src));
377 masm.popl(frameMap.toStackAddress(((CiStackSlot) dest)));
378 } else {
379 masm.pushptr(((CiAddress) src));
380 masm.popptr(frameMap.toStackAddress(((CiStackSlot) dest)));
381 }
382 }
383
384 @Override
385 protected void stack2stack(CiValue src, CiValue dest, CiKind kind) {
386 if (src.kind.isInt()) {
387 masm.pushl(frameMap.toStackAddress(((CiStackSlot) src)));
388 masm.popl(frameMap.toStackAddress(((CiStackSlot) dest)));
389 } else {
390 masm.pushptr(frameMap.toStackAddress(((CiStackSlot) src)));
391 masm.popptr(frameMap.toStackAddress(((CiStackSlot) dest)));
392 }
393 }
394
395 @Override
396 protected void mem2reg(CiValue src, CiValue dest, CiKind kind, LIRDebugInfo info, boolean unaligned) {
397 assert src.isAddress();
398 assert dest.isRegister() : "dest=" + dest;
399
400 CiAddress addr = (CiAddress) src;
401 if (info != null) {
402 asm.recordImplicitException(codePos(), info);
403 }
404
405 switch (kind) {
406 case Float : masm.movflt(asXmmFloatReg(dest), addr); break;
407 case Double : masm.movdbl(asXmmDoubleReg(dest), addr); break;
408 case Object : masm.movq(dest.asRegister(), addr); break;
409 case Int : masm.movslq(dest.asRegister(), addr); break;
410 case Word :
411 case Long : masm.movq(dest.asRegister(), addr); break;
412 case Boolean :
413 case Byte : masm.movsxb(dest.asRegister(), addr); break;
414 case Char : masm.movzxl(dest.asRegister(), addr); break;
415 case Short : masm.movswl(dest.asRegister(), addr); break;
416 default : throw Util.shouldNotReachHere();
417 }
418 }
419
420 @Override
421 protected void emitReadPrefetch(CiValue src) {
422 CiAddress addr = (CiAddress) src;
423 switch (C1XOptions.ReadPrefetchInstr) {
424 case 0 : masm.prefetchnta(addr); break;
425 case 1 : masm.prefetcht0(addr); break;
426 case 2 : masm.prefetcht2(addr); break;
427 default : throw Util.shouldNotReachHere();
428 }
429 }
430
431 @Override
432 protected void emitOp3(LIROp3 op) {
433 switch (op.code) {
434 case Idiv :
435 case Irem : arithmeticIdiv(op.code, op.opr1(), op.opr2(), op.result(), op.info); break;
436 case Ldiv :
437 case Lrem : arithmeticLdiv(op.code, op.opr1(), op.opr2(), op.result(), op.info); break;
438 case Wdiv :
439 case Wdivi :
440 case Wrem :
441 case Wremi : arithmeticWdiv(op.code, op.opr1(), op.opr2(), op.result(), op.info); break;
442 default : throw Util.shouldNotReachHere();
443 }
444 }
445
446 private boolean assertEmitBranch(LIRBranch op) {
447 assert op.block() == null || op.block().label() == op.label() : "wrong label";
448 if (op.block() != null) {
449 branchTargetBlocks.add(op.block());
450 }
451 if (op.unorderedBlock() != null) {
452 branchTargetBlocks.add(op.unorderedBlock());
453 }
454 return true;
455 }
456
457 private boolean assertEmitTableSwitch(LIRTableSwitch op) {
458 assert op.defaultTarget != null;
459 branchTargetBlocks.add(op.defaultTarget);
460 for (BlockBegin target : op.targets) {
461 assert target != null;
462 branchTargetBlocks.add(target);
463 }
464 return true;
465 }
466
467 @Override
468 protected void emitTableSwitch(LIRTableSwitch op) {
469
470 assert assertEmitTableSwitch(op);
471
472 CiRegister value = op.value().asRegister();
473 final Buffer buf = masm.codeBuffer;
474
475 // Compare index against jump table bounds
476 int highKey = op.lowKey + op.targets.length - 1;
477 if (op.lowKey != 0) {
478 // subtract the low value from the switch value
479 masm.subl(value, op.lowKey);
480 masm.cmpl(value, highKey - op.lowKey);
481 } else {
482 masm.cmpl(value, highKey);
483 }
484
485 // Jump to default target if index is not within the jump table
486 masm.jcc(ConditionFlag.above, op.defaultTarget.label());
487
488 // Set scratch to address of jump table
489 int leaPos = buf.position();
490 buf.mark();
491 masm.leaq(rscratch1, new CiAddress(CiKind.Word, InstructionRelative.asValue(), 0));
492
493 // Load jump table entry into scratch and jump to it
494 masm.movslq(value, new CiAddress(CiKind.Int, rscratch1.asValue(), value.asValue(), Scale.Times4, 0));
495 masm.addq(rscratch1, value);
496 masm.jmp(rscratch1);
497
498 // Inserting padding so that jump table address is 4-byte aligned
499 if ((buf.position() & 0x3) != 0) {
500 masm.nop(4 - (buf.position() & 0x3));
501 }
502
503 // Patch LEA instruction above now that we know the position of the jump table
504 int jumpTablePos = buf.position();
505 buf.setPosition(leaPos);
506 buf.mark();
507 masm.leaq(rscratch1, new CiAddress(CiKind.Word, InstructionRelative.asValue(), jumpTablePos - leaPos));
508 buf.setPosition(jumpTablePos);
509
510 // Emit jump table entries
511 for (BlockBegin target : op.targets) {
512 Label label = target.label();
513 int offsetToJumpTableBase = buf.position() - jumpTablePos;
514 if (label.isBound()) {
515 int imm32 = label.position() - jumpTablePos;
516 buf.emitInt(imm32);
517 } else {
518 label.addPatchAt(buf.position());
519
520 buf.emitByte(0); // psuedo-opcode for jump table entry
521 buf.emitShort(offsetToJumpTableBase);
522 buf.emitByte(0); // padding to make jump table entry 4 bytes wide
523 }
524 }
525
526 JumpTable jt = new JumpTable(jumpTablePos, op.lowKey, highKey, 4);
527 masm.targetMethod.addAnnotation(jt);
528 }
529
530 @Override
531 protected void emitBranch(LIRBranch op) {
532
533 assert assertEmitBranch(op);
534
535 if (op.cond() == Condition.TRUE) {
536 if (op.info != null) {
537 asm.recordImplicitException(codePos(), op.info);
538 }
539 masm.jmp(op.label());
540 } else {
541 ConditionFlag acond = ConditionFlag.zero;
542 if (op.code == LIROpcode.CondFloatBranch) {
543 assert op.unorderedBlock() != null : "must have unordered successor";
544 masm.jcc(ConditionFlag.parity, op.unorderedBlock().label());
545 switch (op.cond()) {
546 case EQ : acond = ConditionFlag.equal; break;
547 case NE : acond = ConditionFlag.notEqual; break;
548 case LT : acond = ConditionFlag.below; break;
549 case LE : acond = ConditionFlag.belowEqual; break;
550 case GE : acond = ConditionFlag.aboveEqual; break;
551 case GT : acond = ConditionFlag.above; break;
552 default : throw Util.shouldNotReachHere();
553 }
554 } else {
555 switch (op.cond()) {
556 case EQ : acond = ConditionFlag.equal; break;
557 case NE : acond = ConditionFlag.notEqual; break;
558 case LT : acond = ConditionFlag.less; break;
559 case LE : acond = ConditionFlag.lessEqual; break;
560 case GE : acond = ConditionFlag.greaterEqual; break;
561 case GT : acond = ConditionFlag.greater; break;
562 case BE : acond = ConditionFlag.belowEqual; break;
563 case AE : acond = ConditionFlag.aboveEqual; break;
564 default : throw Util.shouldNotReachHere();
565 }
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 masm.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 masm.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 masm.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 masm.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 if (left.isRegister()) {
825 CiRegister lreg = left.asRegister();
826
827 if (right.isRegister()) {
828 // register - register
829 CiRegister rreg = right.asRegister();
830 if (kind.isInt()) {
831 switch (code) {
832 case Add : masm.addl(lreg, rreg); break;
833 case Sub : masm.subl(lreg, rreg); break;
834 case Mul : masm.imull(lreg, rreg); break;
835 default : throw Util.shouldNotReachHere();
836 }
837 } else if (kind.isFloat()) {
838 assert rreg.isFpu() : "must be xmm";
839 switch (code) {
840 case Add : masm.addss(lreg, rreg); break;
841 case Sub : masm.subss(lreg, rreg); break;
842 case Mul : masm.mulss(lreg, rreg); break;
843 case Div : masm.divss(lreg, rreg); break;
844 default : throw Util.shouldNotReachHere();
845 }
846 } else if (kind.isDouble()) {
847 assert rreg.isFpu();
848 switch (code) {
849 case Add : masm.addsd(lreg, rreg); break;
850 case Sub : masm.subsd(lreg, rreg); break;
851 case Mul : masm.mulsd(lreg, rreg); break;
852 case Div : masm.divsd(lreg, rreg); break;
853 default : throw Util.shouldNotReachHere();
854 }
855 } else {
856 assert target.sizeInBytes(kind) == 8;
857 switch (code) {
858 case Add : masm.addq(lreg, rreg); break;
859 case Sub : masm.subq(lreg, rreg); break;
860 case Mul : masm.imulq(lreg, rreg); break;
861 default : throw Util.shouldNotReachHere();
862 }
863 }
864 } else {
865 if (kind.isInt()) {
866 if (right.isStackSlot()) {
867 // register - stack
868 CiAddress raddr = frameMap.toStackAddress(((CiStackSlot) right));
869 switch (code) {
870 case Add : masm.addl(lreg, raddr); break;
871 case Sub : masm.subl(lreg, raddr); break;
872 default : throw Util.shouldNotReachHere();
873 }
874 } else if (right.isConstant()) {
875 // register - constant
876 assert kind.isInt();
877 int delta = ((CiConstant) right).asInt();
878 switch (code) {
879 case Add : masm.incrementl(lreg, delta); break;
880 case Sub : masm.decrementl(lreg, delta); break;
881 default : throw Util.shouldNotReachHere();
882 }
883 }
884 } else if (kind.isFloat()) {
885 // register - stack/constant
886 CiAddress raddr;
887 if (right.isStackSlot()) {
888 raddr = frameMap.toStackAddress(((CiStackSlot) right));
889 } else {
890 assert right.isConstant();
891 raddr = masm.recordDataReferenceInCode(CiConstant.forFloat(((CiConstant) right).asFloat()));
892 }
893 switch (code) {
894 case Add : masm.addss(lreg, raddr); break;
895 case Sub : masm.subss(lreg, raddr); break;
896 case Mul : masm.mulss(lreg, raddr); break;
897 case Div : masm.divss(lreg, raddr); break;
898 default : throw Util.shouldNotReachHere();
899 }
900 } else if (kind.isDouble()) {
901 // register - stack/constant
902 CiAddress raddr;
903 if (right.isStackSlot()) {
904 raddr = frameMap.toStackAddress(((CiStackSlot) right));
905 } else {
906 assert right.isConstant();
907 raddr = masm.recordDataReferenceInCode(CiConstant.forDouble(((CiConstant) right).asDouble()));
908 }
909 switch (code) {
910 case Add : masm.addsd(lreg, raddr); break;
911 case Sub : masm.subsd(lreg, raddr); break;
912 case Mul : masm.mulsd(lreg, raddr); break;
913 case Div : masm.divsd(lreg, raddr); break;
914 default : throw Util.shouldNotReachHere();
915 }
916 } else {
917 assert target.sizeInBytes(kind) == 8;
918 if (right.isStackSlot()) {
919 // register - stack
920 CiAddress raddr = frameMap.toStackAddress(((CiStackSlot) right));
921 switch (code) {
922 case Add : masm.addq(lreg, raddr); break;
923 case Sub : masm.subq(lreg, raddr); break;
924 default : throw Util.shouldNotReachHere();
925 }
926 } else {
927 // register - constant
928 assert right.isConstant();
929 long c = ((CiConstant) right).asLong();
930 if (Util.isInt(c)) {
931 switch (code) {
932 case Add : masm.addq(lreg, (int) c); break;
933 case Sub : masm.subq(lreg, (int) c); break;
934 default : throw Util.shouldNotReachHere();
935 }
936 } else {
937 masm.movq(rscratch1, c);
938 switch (code) {
939 case Add : masm.addq(lreg, rscratch1); break;
940 case Sub : masm.subq(lreg, rscratch1); break;
941 default : throw Util.shouldNotReachHere();
942 }
943 }
944 }
945 }
946 }
947 } else {
948 assert kind.isInt();
949 CiAddress laddr = asAddress(left);
950
951 if (right.isRegister()) {
952 CiRegister rreg = right.asRegister();
953 switch (code) {
954 case Add : masm.addl(laddr, rreg); break;
955 case Sub : masm.subl(laddr, rreg); break;
956 default : throw Util.shouldNotReachHere();
957 }
958 } else {
959 assert right.isConstant();
960 int c = ((CiConstant) right).asInt();
961 switch (code) {
962 case Add : masm.incrementl(laddr, c); break;
963 case Sub : masm.decrementl(laddr, c); break;
964 default : throw Util.shouldNotReachHere();
965 }
966 }
967 }
968 }
969
970 @Override
971 protected void emitIntrinsicOp(LIROpcode code, CiValue value, CiValue unused, CiValue dest, LIROp2 op) {
972 assert value.kind.isDouble();
973 switch (code) {
974 case Abs:
975 if (asXmmDoubleReg(dest) != asXmmDoubleReg(value)) {
976 masm.movdbl(asXmmDoubleReg(dest), asXmmDoubleReg(value));
977 }
978 masm.andpd(asXmmDoubleReg(dest), masm.recordDataReferenceInCode(CiConstant.forLong(DoubleSignMask)));
979 break;
980
981 case Sqrt:
982 masm.sqrtsd(asXmmDoubleReg(dest), asXmmDoubleReg(value));
983 break;
984
985 default:
986 throw Util.shouldNotReachHere();
987 }
988 }
989
990 @Override
991 protected void emitLogicOp(LIROpcode code, CiValue left, CiValue right, CiValue dst) {
992 assert left.isRegister();
993 if (left.kind.isInt()) {
994 CiRegister reg = left.asRegister();
995 if (right.isConstant()) {
996 int val = ((CiConstant) right).asInt();
997 switch (code) {
998 case LogicAnd : masm.andl(reg, val); break;
999 case LogicOr : masm.orl(reg, val); break;
1000 case LogicXor : masm.xorl(reg, val); break;
1001 default : throw Util.shouldNotReachHere();
1002 }
1003 } else if (right.isStackSlot()) {
1004 // added support for stack operands
1005 CiAddress raddr = frameMap.toStackAddress(((CiStackSlot) right));
1006 switch (code) {
1007 case LogicAnd : masm.andl(reg, raddr); break;
1008 case LogicOr : masm.orl(reg, raddr); break;
1009 case LogicXor : masm.xorl(reg, raddr); break;
1010 default : throw Util.shouldNotReachHere();
1011 }
1012 } else {
1013 CiRegister rright = right.asRegister();
1014 switch (code) {
1015 case LogicAnd : masm.andq(reg, rright); break;
1016 case LogicOr : masm.orq(reg, rright); break;
1017 case LogicXor : masm.xorptr(reg, rright); break;
1018 default : throw Util.shouldNotReachHere();
1019 }
1020 }
1021 moveRegs(reg, dst.asRegister());
1022 } else {
1023 assert target.sizeInBytes(left.kind) == 8;
1024 CiRegister lreg = left.asRegister();
1025 if (right.isConstant()) {
1026 CiConstant rightConstant = (CiConstant) right;
1027 masm.movq(rscratch1, rightConstant.asLong());
1028 switch (code) {
1029 case LogicAnd : masm.andq(lreg, rscratch1); break;
1030 case LogicOr : masm.orq(lreg, rscratch1); break;
1031 case LogicXor : masm.xorq(lreg, rscratch1); break;
1032 default : throw Util.shouldNotReachHere();
1033 }
1034 } else {
1035 CiRegister rreg = right.asRegister();
1036 switch (code) {
1037 case LogicAnd : masm.andq(lreg, rreg); break;
1038 case LogicOr : masm.orq(lreg, rreg); break;
1039 case LogicXor : masm.xorptr(lreg, rreg); break;
1040 default : throw Util.shouldNotReachHere();
1041 }
1042 }
1043
1044 CiRegister dreg = dst.asRegister();
1045 moveRegs(lreg, dreg);
1046 }
1047 }
1048
1049 void arithmeticIdiv(LIROpcode code, CiValue left, CiValue right, CiValue result, LIRDebugInfo info) {
1050 assert left.isRegister() : "left must be register";
1051 assert right.isRegister() || right.isConstant() : "right must be register or constant";
1052 assert result.isRegister() : "result must be register";
1053
1054 CiRegister lreg = left.asRegister();
1055 CiRegister dreg = result.asRegister();
1056
1057 if (right.isConstant()) {
1058 int divisor = ((CiConstant) right).asInt();
1059 assert divisor > 0 && CiUtil.isPowerOf2(divisor) : "divisor must be power of two";
1060 if (code == LIROpcode.Idiv) {
1061 assert lreg == AMD64.rax : "dividend must be rax";
1062 masm.cdql(); // sign extend into rdx:rax
1063 if (divisor == 2) {
1064 masm.subl(lreg, AMD64.rdx);
1065 } else {
1066 masm.andl(AMD64.rdx, divisor - 1);
1067 masm.addl(lreg, AMD64.rdx);
1068 }
1069 masm.sarl(lreg, CiUtil.log2(divisor));
1070 moveRegs(lreg, dreg);
1071 } else {
1072 assert code == LIROpcode.Irem;
1073 Label done = new Label();
1074 masm.mov(dreg, lreg);
1075 masm.andl(dreg, 0x80000000 | (divisor - 1));
1076 masm.jcc(ConditionFlag.positive, done);
1077 masm.decrementl(dreg, 1);
1078 masm.orl(dreg, ~(divisor - 1));
1079 masm.incrementl(dreg, 1);
1080 masm.bind(done);
1081 }
1082 } else {
1083 CiRegister rreg = right.asRegister();
1084 assert lreg == AMD64.rax : "left register must be rax";
1085 assert rreg != AMD64.rdx : "right register must not be rdx";
1086
1087 moveRegs(lreg, AMD64.rax);
1088
1089 Label continuation = new Label();
1090
1091 if (C1XOptions.GenSpecialDivChecks) {
1092 // check for special case of Integer.MIN_VALUE / -1
1093 Label normalCase = new Label();
1094 masm.cmpl(AMD64.rax, Integer.MIN_VALUE);
1095 masm.jcc(ConditionFlag.notEqual, normalCase);
1096 if (code == LIROpcode.Irem) {
1097 // prepare X86Register.rdx for possible special case where remainder = 0
1098 masm.xorl(AMD64.rdx, AMD64.rdx);
1099 }
1100 masm.cmpl(rreg, -1);
1101 masm.jcc(ConditionFlag.equal, continuation);
1102
1103 // handle normal case
1104 masm.bind(normalCase);
1105 }
1106 masm.cdql();
1107 int offset = masm.codeBuffer.position();
1108 masm.idivl(rreg);
1109
1110 // normal and special case exit
1111 masm.bind(continuation);
1112
1113 asm.recordImplicitException(offset, info);
1114 if (code == LIROpcode.Irem) {
1115 moveRegs(AMD64.rdx, dreg); // result is in rdx
1116 } else {
1117 assert code == LIROpcode.Idiv;
1118 moveRegs(AMD64.rax, dreg);
1119 }
1120 }
1121 }
1122
1123 void arithmeticLdiv(LIROpcode code, CiValue left, CiValue right, CiValue result, LIRDebugInfo info) {
1124 assert left.isRegister() : "left must be register";
1125 assert right.isRegister() : "right must be register";
1126 assert result.isRegister() : "result must be register";
1127 assert result.kind.isLong();
1128
1129 CiRegister lreg = left.asRegister();
1130 CiRegister dreg = result.asRegister();
1131 CiRegister rreg = right.asRegister();
1132 assert lreg == AMD64.rax : "left register must be rax";
1133 assert rreg != AMD64.rdx : "right register must not be rdx";
1134
1135 moveRegs(lreg, AMD64.rax);
1136
1137 Label continuation = new Label();
1138
1139 if (C1XOptions.GenSpecialDivChecks) {
1140 // check for special case of Long.MIN_VALUE / -1
1141 Label normalCase = new Label();
1142 masm.movq(AMD64.rdx, java.lang.Long.MIN_VALUE);
1143 masm.cmpq(AMD64.rax, AMD64.rdx);
1144 masm.jcc(ConditionFlag.notEqual, normalCase);
1145 if (code == LIROpcode.Lrem) {
1146 // prepare X86Register.rdx for possible special case (where remainder = 0)
1147 masm.xorq(AMD64.rdx, AMD64.rdx);
1148 }
1149 masm.cmpl(rreg, -1);
1150 masm.jcc(ConditionFlag.equal, continuation);
1151
1152 // handle normal case
1153 masm.bind(normalCase);
1154 }
1155 masm.cdqq();
1156 int offset = masm.codeBuffer.position();
1157 masm.idivq(rreg);
1158
1159 // normal and special case exit
1160 masm.bind(continuation);
1161
1162 asm.recordImplicitException(offset, info);
1163 if (code == LIROpcode.Lrem) {
1164 moveRegs(AMD64.rdx, dreg);
1165 } else {
1166 assert code == LIROpcode.Ldiv;
1167 moveRegs(AMD64.rax, dreg);
1168 }
1169 }
1170
1171 void arithmeticWdiv(LIROpcode code, CiValue left, CiValue right, CiValue result, LIRDebugInfo info) {
1172 assert left.isRegister() : "left must be register";
1173 assert right.isRegister() : "right must be register";
1174 assert result.isRegister() : "result must be register";
1175
1176 CiRegister lreg = left.asRegister();
1177 CiRegister dreg = result.asRegister();
1178 CiRegister rreg = right.asRegister();
1179 assert lreg == AMD64.rax : "left register must be rax";
1180 assert rreg != AMD64.rdx : "right register must not be rdx";
1181
1182 // Must zero the high 64-bit word (in RDX) of the dividend
1183 masm.xorq(AMD64.rdx, AMD64.rdx);
1184
1185 if (code == LIROpcode.Wdivi || code == LIROpcode.Wremi) {
1186 // Zero the high 32 bits of the divisor
1187 masm.movzxd(rreg, rreg);
1188 }
1189
1190 moveRegs(lreg, AMD64.rax);
1191
1192 int offset = masm.codeBuffer.position();
1193 masm.divq(rreg);
1194
1195 asm.recordImplicitException(offset, info);
1196 if (code == LIROpcode.Wrem || code == LIROpcode.Wremi) {
1197 moveRegs(AMD64.rdx, dreg);
1198 } else {
1199 assert code == LIROpcode.Wdiv || code == LIROpcode.Wdivi;
1200 moveRegs(AMD64.rax, dreg);
1201 }
1202 }
1203
1204 @Override
1205 protected void emitCompare(Condition condition, CiValue opr1, CiValue opr2, LIROp2 op) {
1206 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();
1207
1208 if (opr1.isConstant()) {
1209 // Use scratch register
1210 CiValue newOpr1 = compilation.registerConfig.getScratchRegister().asValue(opr1.kind);
1211 const2reg(opr1, newOpr1, null);
1212 opr1 = newOpr1;
1213 }
1214
1215 if (opr1.isRegister()) {
1216 CiRegister reg1 = opr1.asRegister();
1217 if (opr2.isRegister()) {
1218 // register - register
1219 switch (opr1.kind) {
1220 case Boolean :
1221 case Byte :
1222 case Char :
1223 case Short :
1224 case Int : masm.cmpl(reg1, opr2.asRegister()); break;
1225 case Long :
1226 case Word :
1227 case Object : masm.cmpq(reg1, opr2.asRegister()); break;
1228 case Float : masm.ucomiss(reg1, asXmmFloatReg(opr2)); break;
1229 case Double : masm.ucomisd(reg1, asXmmDoubleReg(opr2)); break;
1230 default : throw Util.shouldNotReachHere(opr1.kind.toString());
1231 }
1232 } else if (opr2.isStackSlot()) {
1233 // register - stack
1234 CiStackSlot opr2Slot = (CiStackSlot) opr2;
1235 switch (opr1.kind) {
1236 case Boolean :
1237 case Byte :
1238 case Char :
1239 case Short :
1240 case Int : masm.cmpl(reg1, frameMap.toStackAddress(opr2Slot)); break;
1241 case Long :
1242 case Word :
1243 case Object : masm.cmpptr(reg1, frameMap.toStackAddress(opr2Slot)); break;
1244 case Float : masm.ucomiss(reg1, frameMap.toStackAddress(opr2Slot)); break;
1245 case Double : masm.ucomisd(reg1, frameMap.toStackAddress(opr2Slot)); break;
1246 default : throw Util.shouldNotReachHere();
1247 }
1248 } else if (opr2.isConstant()) {
1249 // register - constant
1250 CiConstant c = (CiConstant) opr2;
1251 switch (opr1.kind) {
1252 case Boolean :
1253 case Byte :
1254 case Char :
1255 case Short :
1256 case Int : masm.cmpl(reg1, c.asInt()); break;
1257 case Float : masm.ucomiss(reg1, masm.recordDataReferenceInCode(CiConstant.forFloat(((CiConstant) opr2).asFloat()))); break;
1258 case Double : masm.ucomisd(reg1, masm.recordDataReferenceInCode(CiConstant.forDouble(((CiConstant) opr2).asDouble()))); break;
1259 case Long :
1260 case Word : {
1261 if (c.asLong() == 0) {
1262 masm.cmpq(reg1, 0);
1263 } else {
1264 masm.movq(rscratch1, c.asLong());
1265 masm.cmpq(reg1, rscratch1);
1266
1267 }
1268 break;
1269 }
1270 case Object : {
1271 masm.movoop(rscratch1, c);
1272 masm.cmpq(reg1, rscratch1);
1273 break;
1274 }
1275 default : throw Util.shouldNotReachHere();
1276 }
1277 } else {
1278 throw Util.shouldNotReachHere();
1279 }
1280 } else if (opr1.isStackSlot()) {
1281 CiAddress left = asAddress(opr1);
1282 if (opr2.isConstant()) {
1283 CiConstant right = (CiConstant) opr2;
1284 // stack - constant
1285 switch (opr1.kind) {
1286 case Boolean :
1287 case Byte :
1288 case Char :
1289 case Short :
1290 case Int : masm.cmpl(left, right.asInt()); break;
1291 case Long :
1292 case Word : assert Util.isInt(right.asLong());
1293 masm.cmpq(left, right.asInt()); break;
1294 case Object : assert right.isNull();
1295 masm.cmpq(left, 0); break;
1296 default : throw Util.shouldNotReachHere();
1297 }
1298 } else {
1299 throw Util.shouldNotReachHere();
1300 }
1301
1302 } else {
1303 throw Util.shouldNotReachHere(opr1.toString() + " opr2 = " + opr2);
1304 }
1305 }
1306
1307 @Override
1308 protected void emitCompare2Int(LIROpcode code, CiValue left, CiValue right, CiValue dst, LIROp2 op) {
1309 if (code == LIROpcode.Cmpfd2i || code == LIROpcode.Ucmpfd2i) {
1310 if (left.kind.isFloat()) {
1311 masm.cmpss2int(asXmmFloatReg(left), asXmmFloatReg(right), dst.asRegister(), code == LIROpcode.Ucmpfd2i);
1312 } else if (left.kind.isDouble()) {
1313 masm.cmpsd2int(asXmmDoubleReg(left), asXmmDoubleReg(right), dst.asRegister(), code == LIROpcode.Ucmpfd2i);
1314 } else {
1315 throw Util.unimplemented("no fpu stack");
1316 }
1317 } else {
1318 assert code == LIROpcode.Cmpl2i;
1319 CiRegister dest = dst.asRegister();
1320 Label high = new Label();
1321 Label done = new Label();
1322 Label isEqual = new Label();
1323 masm.cmpptr(left.asRegister(), right.asRegister());
1324 masm.jcc(ConditionFlag.equal, isEqual);
1325 masm.jcc(ConditionFlag.greater, high);
1326 masm.xorptr(dest, dest);
1327 masm.decrementl(dest, 1);
1328 masm.jmp(done);
1329 masm.bind(high);
1330 masm.xorptr(dest, dest);
1331 masm.incrementl(dest, 1);
1332 masm.jmp(done);
1333 masm.bind(isEqual);
1334 masm.xorptr(dest, dest);
1335 masm.bind(done);
1336 }
1337 }
1338
1339 @Override
1340 protected void emitCallAlignment(LIROpcode code) {
1341 if (C1XOptions.AlignCallsForPatching) {
1342 // make sure that the displacement word of the call ends up word aligned
1343 int offset = masm.codeBuffer.position();
1344 offset += compilation.target.arch.machineCodeCallDisplacementOffset;
1345 while (offset++ % wordSize != 0) {
1346 masm.nop();
1347 }
1348 }
1349 }
1350
1351 @Override
1352 protected void emitIndirectCall(Object target, LIRDebugInfo info, CiValue callAddress) {
1353 CiRegister reg = rscratch1;
1354 if (callAddress.isRegister()) {
1355 reg = callAddress.asRegister();
1356 } else {
1357 moveOp(callAddress, reg.asValue(callAddress.kind), callAddress.kind, null, false);
1358 }
1359 masm.indirectCall(reg, target, info);
1360 }
1361
1362 @Override
1363 protected void emitDirectCall(Object target, LIRDebugInfo info) {
1364 masm.directCall(target, info);
1365 }
1366
1367 @Override
1368 protected void emitNativeCall(String symbol, LIRDebugInfo info, CiValue callAddress) {
1369 CiRegister reg = rscratch1;
1370 if (callAddress.isRegister()) {
1371 reg = callAddress.asRegister();
1372 } else {
1373 moveOp(callAddress, reg.asValue(callAddress.kind), callAddress.kind, null, false);
1374 }
1375 masm.nativeCall(reg, symbol, info);
1376 }
1377
1378 @Override
1379 protected void emitTemplateCall(CiValue address) {
1380 if (address == null) {
1381 masm.directCall(null, null);
1382 return;
1383 }
1384
1385 CiRegister reg = rscratch1;
1386 if (address.isRegister()) {
1387 reg = address.asRegister();
1388 } else {
1389 moveOp(address, reg.asValue(address.kind), address.kind, null, false);
1390 }
1391 masm.indirectCall(reg, null, null);
1392 }
1393
1394 @Override
1395 protected void emitThrow(CiValue exceptionPC, CiValue exceptionOop, LIRDebugInfo info, boolean unwind) {
1396 // exception object is not added to oop map by LinearScan
1397 // (LinearScan assumes that no oops are in fixed registers)
1398 // info.addRegisterOop(exceptionOop);
1399 masm.directCall(unwind ? CiRuntimeCall.UnwindException : CiRuntimeCall.HandleException, info);
1400 // enough room for two byte trap
1401 masm.nop();
1402 }
1403
1404 private void emitXIRShiftOp(LIROpcode code, CiValue left, CiValue count, CiValue dest) {
1405 if (count.isConstant()) {
1406 emitShiftOp(code, left, ((CiConstant) count).asInt(), dest);
1407 } else {
1408 emitShiftOp(code, left, count, dest, IllegalValue);
1409 }
1410 }
1411
1412 @Override
1413 protected void emitShiftOp(LIROpcode code, CiValue left, CiValue count, CiValue dest, CiValue tmp) {
1414 // optimized version for linear scan:
1415 // * count must be already in ECX (guaranteed by LinearScan)
1416 // * left and dest must be equal
1417 // * tmp must be unused
1418 assert count.asRegister() == SHIFTCount : "count must be in ECX";
1419 assert left == dest : "left and dest must be equal";
1420 assert tmp.isIllegal() : "wasting a register if tmp is allocated";
1421 assert left.isRegister();
1422
1423 if (left.kind.isInt()) {
1424 CiRegister value = left.asRegister();
1425 assert value != SHIFTCount : "left cannot be ECX";
1426
1427 switch (code) {
1428 case Shl : masm.shll(value); break;
1429 case Shr : masm.sarl(value); break;
1430 case Ushr : masm.shrl(value); break;
1431 default : throw Util.shouldNotReachHere();
1432 }
1433 } else {
1434 CiRegister lreg = left.asRegister();
1435 assert lreg != SHIFTCount : "left cannot be ECX";
1436
1437 switch (code) {
1438 case Shl : masm.shlq(lreg); break;
1439 case Shr : masm.sarq(lreg); break;
1440 case Ushr : masm.shrq(lreg); break;
1441 default : throw Util.shouldNotReachHere();
1442 }
1443 }
1444 }
1445
1446 @Override
1447 protected void emitShiftOp(LIROpcode code, CiValue left, int count, CiValue dest) {
1448 assert dest.isRegister();
1449 if (dest.kind.isInt()) {
1450 // first move left into dest so that left is not destroyed by the shift
1451 CiRegister value = dest.asRegister();
1452 count = count & 0x1F; // Java spec
1453
1454 moveRegs(left.asRegister(), value);
1455 switch (code) {
1456 case Shl : masm.shll(value, count); break;
1457 case Shr : masm.sarl(value, count); break;
1458 case Ushr : masm.shrl(value, count); break;
1459 default : throw Util.shouldNotReachHere();
1460 }
1461 } else {
1462
1463 // first move left into dest so that left is not destroyed by the shift
1464 CiRegister value = dest.asRegister();
1465 count = count & 0x1F; // Java spec
1466
1467 moveRegs(left.asRegister(), value);
1468 switch (code) {
1469 case Shl : masm.shlq(value, count); break;
1470 case Shr : masm.sarq(value, count); break;
1471 case Ushr : masm.shrq(value, count); break;
1472 default : throw Util.shouldNotReachHere();
1473 }
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 masm.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 masm.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 emitVolatileMove(CiValue src, CiValue dest, CiKind kind, LIRDebugInfo info) {
1543 assert kind == CiKind.Long : "only for volatile long fields";
1544
1545 if (info != null) {
1546 asm.recordImplicitException(codePos(), info);
1547 }
1548
1549 if (src.kind.isDouble()) {
1550 if (dest.isRegister()) {
1551 masm.movdq(dest.asRegister(), asXmmDoubleReg(src));
1552 } else if (dest.isStackSlot()) {
1553 masm.movsd(frameMap.toStackAddress(((CiStackSlot) dest)), asXmmDoubleReg(src));
1554 } else {
1555 assert dest.isAddress();
1556 masm.movsd(((CiAddress) dest), asXmmDoubleReg(src));
1557 }
1558 } else {
1559 assert dest.kind.isDouble();
1560 if (src.isStackSlot()) {
1561 masm.movdbl(asXmmDoubleReg(dest), frameMap.toStackAddress(((CiStackSlot) src)));
1562 } else {
1563 assert src.isAddress();
1564 masm.movdbl(asXmmDoubleReg(dest), ((CiAddress) src));
1565 }
1566 }
1567 }
1568
1569 private static CiRegister asXmmDoubleReg(CiValue dest) {
1570 assert dest.kind.isDouble() : "must be double XMM register";
1571 CiRegister result = dest.asRegister();
1572 assert result.isFpu() : "must be XMM register";
1573 return result;
1574 }
1575
1576 @Override
1577 protected void emitMemoryBarriers(int barriers) {
1578 masm.membar(barriers);
1579 }
1580
1581 @Override
1582 protected void doPeephole(LIRList list) {
1583 // Do nothing for now
1584 }
1585
1586 @Override
1587 protected void emitXir(LIRXirInstruction instruction) {
1588 XirSnippet snippet = instruction.snippet;
1589
1590 Label[] labels = new Label[snippet.template.labels.length];
1591 for (int i = 0; i < labels.length; i++) {
1592 labels[i] = new Label();
1593 }
1594 emitXirInstructions(instruction, snippet.template.fastPath, labels, instruction.getOperands(), snippet.marks);
1595 if (snippet.template.slowPath != null) {
1596 addSlowPath(new SlowPath(instruction, labels, snippet.marks));
1597 }
1598 }
1599
1600 @Override
1601 protected void emitSlowPath(SlowPath sp) {
1602 int start = -1;
1603 if (C1XOptions.TraceAssembler) {
1604 TTY.println("Emitting slow path for XIR instruction " + sp.instruction.snippet.template.name);
1605 start = masm.codeBuffer.position();
1606 }
1607 emitXirInstructions(sp.instruction, sp.instruction.snippet.template.slowPath, sp.labels, sp.instruction.getOperands(), sp.marks);
1608 masm.nop();
1609 if (C1XOptions.TraceAssembler) {
1610 TTY.println("From " + start + " to " + masm.codeBuffer.position());
1611 }
1612 }
1613
1614 public void emitXirInstructions(LIRXirInstruction xir, XirInstruction[] instructions, Label[] labels, CiValue[] operands, Map<XirMark, Mark> marks) {
1615 LIRDebugInfo info = xir == null ? null : xir.info;
1616 LIRDebugInfo infoAfter = xir == null ? null : xir.infoAfter;
1617
1618 for (XirInstruction inst : instructions) {
1619 switch (inst.op) {
1620 case Add:
1621 emitArithOp(LIROpcode.Add, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index], null);
1622 break;
1623
1624 case Sub:
1625 emitArithOp(LIROpcode.Sub, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index], null);
1626 break;
1627
1628 case Div:
1629 if (inst.kind == CiKind.Int) {
1630 arithmeticIdiv(LIROpcode.Idiv, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index], null);
1631 } else {
1632 emitArithOp(LIROpcode.Div, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index], null);
1633 }
1634 break;
1635
1636 case Mul:
1637 emitArithOp(LIROpcode.Mul, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index], null);
1638 break;
1639
1640 case Mod:
1641 if (inst.kind == CiKind.Int) {
1642 arithmeticIdiv(LIROpcode.Irem, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index], null);
1643 } else {
1644 emitArithOp(LIROpcode.Rem, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index], null);
1645 }
1646 break;
1647
1648 case Shl:
1649 emitXIRShiftOp(LIROpcode.Shl, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index]);
1650 break;
1651
1652 case Sar:
1653 emitXIRShiftOp(LIROpcode.Shr, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index]);
1654 break;
1655
1656 case Shr:
1657 emitXIRShiftOp(LIROpcode.Ushr, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index]);
1658 break;
1659
1660 case And:
1661 emitLogicOp(LIROpcode.LogicAnd, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index]);
1662 break;
1663
1664 case Or:
1665 emitLogicOp(LIROpcode.LogicOr, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index]);
1666 break;
1667
1668 case Xor:
1669 emitLogicOp(LIROpcode.LogicXor, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index]);
1670 break;
1671
1672 case Mov: {
1673 CiValue result = operands[inst.result.index];
1674 CiValue source = operands[inst.x().index];
1675 moveOp(source, result, result.kind, null, false);
1676 break;
1677 }
1678
1679 case PointerLoad: {
1680 if ((Boolean) inst.extra && info != null) {
1681 asm.recordImplicitException(codePos(), info);
1682 }
1683
1684 CiValue result = operands[inst.result.index];
1685 CiValue pointer = operands[inst.x().index];
1686 CiRegisterValue register = assureInRegister(pointer);
1687 moveOp(new CiAddress(inst.kind, register, 0), result, inst.kind, null, false);
1688 break;
1689 }
1690
1691 case PointerStore: {
1692 if ((Boolean) inst.extra && info != null) {
1693 asm.recordImplicitException(codePos(), info);
1694 }
1695
1696 CiValue value = operands[inst.y().index];
1697 CiValue pointer = operands[inst.x().index];
1698 assert pointer.isVariableOrRegister();
1699 moveOp(value, new CiAddress(inst.kind, pointer, 0), inst.kind, null, false);
1700 break;
1701 }
1702
1703 case PointerLoadDisp: {
1704 CiXirAssembler.AddressAccessInformation addressInformation = (CiXirAssembler.AddressAccessInformation) inst.extra;
1705 boolean canTrap = addressInformation.canTrap;
1706
1707 CiAddress.Scale scale = addressInformation.scale;
1708 int displacement = addressInformation.disp;
1709
1710 CiValue result = operands[inst.result.index];
1711 CiValue pointer = operands[inst.x().index];
1712 CiValue index = operands[inst.y().index];
1713
1714 pointer = assureInRegister(pointer);
1715 assert pointer.isVariableOrRegister();
1716
1717 CiValue src = null;
1718 if (index.isConstant()) {
1719 assert index.kind == CiKind.Int;
1720 CiConstant constantIndex = (CiConstant) index;
1721 src = new CiAddress(inst.kind, pointer, constantIndex.asInt() * scale.value + displacement);
1722 } else {
1723 src = new CiAddress(inst.kind, pointer, index, scale, displacement);
1724 }
1725
1726 moveOp(src, result, inst.kind, (canTrap) ? info : null, false);
1727 break;
1728 }
1729
1730 case LoadEffectiveAddress: {
1731 CiXirAssembler.AddressAccessInformation addressInformation = (CiXirAssembler.AddressAccessInformation) inst.extra;
1732
1733 CiAddress.Scale scale = addressInformation.scale;
1734 int displacement = addressInformation.disp;
1735
1736 CiValue result = operands[inst.result.index];
1737 CiValue pointer = operands[inst.x().index];
1738 CiValue index = operands[inst.y().index];
1739
1740 pointer = assureInRegister(pointer);
1741 assert pointer.isVariableOrRegister();
1742 CiValue src = new CiAddress(CiKind.Illegal, pointer, index, scale, displacement);
1743 emitLea(src, result);
1744 break;
1745 }
1746
1747 case PointerStoreDisp: {
1748 CiXirAssembler.AddressAccessInformation addressInformation = (CiXirAssembler.AddressAccessInformation) inst.extra;
1749 boolean canTrap = addressInformation.canTrap;
1750
1751 CiAddress.Scale scale = addressInformation.scale;
1752 int displacement = addressInformation.disp;
1753
1754 CiValue value = operands[inst.z().index];
1755 CiValue pointer = operands[inst.x().index];
1756 CiValue index = operands[inst.y().index];
1757
1758 pointer = assureInRegister(pointer);
1759 assert pointer.isVariableOrRegister();
1760
1761 CiValue dst;
1762 if (index.isConstant()) {
1763 assert index.kind == CiKind.Int;
1764 CiConstant constantIndex = (CiConstant) index;
1765 dst = new CiAddress(inst.kind, pointer, IllegalValue, scale, constantIndex.asInt() * scale.value + displacement);
1766 } else {
1767 dst = new CiAddress(inst.kind, pointer, index, scale, displacement);
1768 }
1769
1770 moveOp(value, dst, inst.kind, (canTrap) ? info : null, false);
1771 break;
1772 }
1773
1774 case RepeatMoveBytes:
1775 assert operands[inst.x().index].asRegister().equals(AMD64.rsi) : "wrong input x: " + operands[inst.x().index];
1776 assert operands[inst.y().index].asRegister().equals(AMD64.rdi) : "wrong input y: " + operands[inst.y().index];
1777 assert operands[inst.z().index].asRegister().equals(AMD64.rcx) : "wrong input z: " + operands[inst.z().index];
1778 masm.repeatMoveBytes();
1779 break;
1780
1781 case RepeatMoveWords:
1782 assert operands[inst.x().index].asRegister().equals(AMD64.rsi) : "wrong input x: " + operands[inst.x().index];
1783 assert operands[inst.y().index].asRegister().equals(AMD64.rdi) : "wrong input y: " + operands[inst.y().index];
1784 assert operands[inst.z().index].asRegister().equals(AMD64.rcx) : "wrong input z: " + operands[inst.z().index];
1785 masm.repeatMoveWords();
1786 break;
1787
1788 case PointerCAS:
1789
1790 if ((Boolean) inst.extra && info != null) {
1791 asm.recordImplicitException(codePos(), info);
1792 }
1793 assert operands[inst.x().index].asRegister().equals(AMD64.rax) : "wrong input x: " + operands[inst.x().index];
1794
1795 CiValue exchangedVal = operands[inst.y().index];
1796 CiValue exchangedAddress = operands[inst.x().index];
1797 CiRegisterValue pointerRegister = assureInRegister(exchangedAddress);
1798 CiAddress addr = new CiAddress(CiKind.Word, pointerRegister);
1799 masm.cmpxchgq(exchangedVal.asRegister(), addr);
1800
1801 break;
1802
1803 case CallStub: {
1804 XirTemplate stubId = (XirTemplate) inst.extra;
1805 CiRegister result = CiRegister.None;
1806 if (inst.result != null) {
1807 result = operands[inst.result.index].asRegister();
1808 }
1809 CiValue[] args = new CiValue[inst.arguments.length];
1810 for (int i = 0; i < args.length; i++) {
1811 args[i] = operands[inst.arguments[i].index];
1812 }
1813 masm.callGlobalStub(stubId, info, result, args);
1814 break;
1815 }
1816 case CallRuntime: {
1817 CiKind[] signature = new CiKind[inst.arguments.length];
1818 for (int i = 0; i < signature.length; i++) {
1819 signature[i] = inst.arguments[i].kind;
1820 }
1821
1822 CiCallingConvention cc = frameMap.getCallingConvention(signature, RuntimeCall);
1823 for (int i = 0; i < inst.arguments.length; i++) {
1824 CiValue argumentLocation = cc.locations[i];
1825 CiValue argumentSourceLocation = operands[inst.arguments[i].index];
1826 if (argumentLocation != argumentSourceLocation) {
1827 moveOp(argumentSourceLocation, argumentLocation, argumentLocation.kind, null, false);
1828 }
1829 }
1830
1831 RuntimeCallInformation runtimeCallInformation = (RuntimeCallInformation) inst.extra;
1832 masm.directCall(runtimeCallInformation.target, (runtimeCallInformation.useInfoAfter) ? infoAfter : info);
1833
1834 if (inst.result != null && inst.result.kind != CiKind.Illegal && inst.result.kind != CiKind.Void) {
1835 CiRegister returnRegister = compilation.registerConfig.getReturnRegister(inst.result.kind);
1836 CiValue resultLocation = returnRegister.asValue(inst.result.kind.stackKind());
1837 moveOp(resultLocation, operands[inst.result.index], inst.result.kind.stackKind(), null, false);
1838 }
1839 break;
1840 }
1841 case Jmp: {
1842 if (inst.extra instanceof XirLabel) {
1843 Label label = labels[((XirLabel) inst.extra).index];
1844 masm.jmp(label);
1845 } else {
1846 masm.directJmp(inst.extra);
1847 }
1848 break;
1849 }
1850 case DecAndJumpNotZero: {
1851 Label label = labels[((XirLabel) inst.extra).index];
1852 CiValue value = operands[inst.x().index];
1853 if (value.kind == CiKind.Long) {
1854 masm.decq(value.asRegister());
1855 } else {
1856 assert value.kind == CiKind.Int;
1857 masm.decl(value.asRegister());
1858 }
1859 masm.jcc(ConditionFlag.notZero, label);
1860 break;
1861 }
1862 case Jeq: {
1863 Label label = labels[((XirLabel) inst.extra).index];
1864 emitXirCompare(inst, Condition.EQ, ConditionFlag.equal, operands, label);
1865 break;
1866 }
1867 case Jneq: {
1868 Label label = labels[((XirLabel) inst.extra).index];
1869 emitXirCompare(inst, Condition.NE, ConditionFlag.notEqual, operands, label);
1870 break;
1871 }
1872
1873 case Jgt: {
1874 Label label = labels[((XirLabel) inst.extra).index];
1875 emitXirCompare(inst, Condition.GT, ConditionFlag.greater, operands, label);
1876 break;
1877 }
1878
1879 case Jgteq: {
1880 Label label = labels[((XirLabel) inst.extra).index];
1881 emitXirCompare(inst, Condition.GE, ConditionFlag.greaterEqual, operands, label);
1882 break;
1883 }
1884
1885 case Jugteq: {
1886 Label label = labels[((XirLabel) inst.extra).index];
1887 emitXirCompare(inst, Condition.AE, ConditionFlag.aboveEqual, operands, label);
1888 break;
1889 }
1890
1891 case Jlt: {
1892 Label label = labels[((XirLabel) inst.extra).index];
1893 emitXirCompare(inst, Condition.LT, ConditionFlag.less, operands, label);
1894 break;
1895 }
1896
1897 case Jlteq: {
1898 Label label = labels[((XirLabel) inst.extra).index];
1899 emitXirCompare(inst, Condition.LE, ConditionFlag.lessEqual, operands, label);
1900 break;
1901 }
1902
1903 case Jbset: {
1904 Label label = labels[((XirLabel) inst.extra).index];
1905 CiValue pointer = operands[inst.x().index];
1906 CiValue offset = operands[inst.y().index];
1907 CiValue bit = operands[inst.z().index];
1908 assert offset.isConstant() && bit.isConstant();
1909 CiConstant constantOffset = (CiConstant) offset;
1910 CiConstant constantBit = (CiConstant) bit;
1911 CiAddress src = new CiAddress(inst.kind, pointer, constantOffset.asInt());
1912 masm.btli(src, constantBit.asInt());
1913 masm.jcc(ConditionFlag.aboveEqual, label);
1914 break;
1915 }
1916
1917 case Bind: {
1918 XirLabel l = (XirLabel) inst.extra;
1919 Label label = labels[l.index];
1920 asm.bind(label);
1921 break;
1922 }
1923 case Safepoint: {
1924 assert info != null : "Must have debug info in order to create a safepoint.";
1925 asm.recordSafepoint(codePos(), info);
1926 break;
1927 }
1928 case NullCheck: {
1929 asm.recordImplicitException(codePos(), info);
1930 CiValue pointer = operands[inst.x().index];
1931 asm.nullCheck(pointer.asRegister());
1932 break;
1933 }
1934 case Align: {
1935 asm.align((Integer) inst.extra);
1936 break;
1937 }
1938 case StackOverflowCheck: {
1939 int frameSize = initialFrameSizeInBytes();
1940 int lastFramePage = frameSize / target.pageSize;
1941 // emit multiple stack bangs for methods with frames larger than a page
1942 for (int i = 0; i <= lastFramePage; i++) {
1943 int offset = (i + C1XOptions.StackShadowPages) * target.pageSize;
1944 // Deduct 'frameSize' to handle frames larger than the shadow
1945 bangStackWithOffset(offset - frameSize);
1946 }
1947 break;
1948 }
1949 case PushFrame: {
1950 int frameSize = initialFrameSizeInBytes();
1951 masm.decrementq(AMD64.rsp, frameSize); // does not emit code for frameSize == 0
1952 if (C1XOptions.ZapStackOnMethodEntry) {
1953 final int intSize = 4;
1954 for (int i = 0; i < frameSize / intSize; ++i) {
1955 masm.movl(new CiAddress(CiKind.Int, AMD64.rsp.asValue(), i * intSize), 0xC1C1C1C1);
1956 }
1957 }
1958 CiCalleeSaveArea csa = compilation.registerConfig.getCalleeSaveArea();
1959 if (csa.size != 0) {
1960 int frameToCSA = frameMap.offsetToCalleeSaveAreaStart();
1961 assert frameToCSA >= 0;
1962 masm.save(csa, frameToCSA);
1963 }
1964 break;
1965 }
1966 case PopFrame: {
1967 int frameSize = initialFrameSizeInBytes();
1968
1969 CiCalleeSaveArea csa = compilation.registerConfig.getCalleeSaveArea();
1970 if (csa.size != 0) {
1971 registerRestoreEpilogueOffset = masm.codeBuffer.position();
1972 // saved all registers, restore all registers
1973 int frameToCSA = frameMap.offsetToCalleeSaveAreaStart();
1974 masm.restore(csa, frameToCSA);
1975 }
1976
1977 masm.incrementq(AMD64.rsp, frameSize);
1978 break;
1979 }
1980 case Push: {
1981 CiRegisterValue value = assureInRegister(operands[inst.x().index]);
1982 masm.push(value.asRegister());
1983 break;
1984 }
1985 case Pop: {
1986 CiValue result = operands[inst.result.index];
1987 if (result.isRegister()) {
1988 masm.pop(result.asRegister());
1989 } else {
1990 masm.pop(rscratch1);
1991 moveOp(rscratch1.asValue(), result, result.kind, null, true);
1992 }
1993 break;
1994 }
1995 case Mark: {
1996 XirMark xmark = (XirMark) inst.extra;
1997 Mark[] references = new Mark[xmark.references.length];
1998 for (int i = 0; i < references.length; i++) {
1999 references[i] = marks.get(xmark.references[i]);
2000 assert references[i] != null;
2001 }
2002 Mark mark = asm.recordMark(xmark.id, references);
2003 marks.put(xmark, mark);
2004 break;
2005 }
2006 case Nop: {
2007 for (int i = 0; i < (Integer) inst.extra; i++) {
2008 masm.nop();
2009 }
2010 break;
2011 }
2012 case RawBytes: {
2013 for (byte b : (byte[]) inst.extra) {
2014 masm.emitByte(b & 0xff);
2015 }
2016 break;
2017 }
2018 case ShouldNotReachHere: {
2019 if (inst.extra == null) {
2020 masm.stop("should not reach here");
2021 } else {
2022 masm.stop("should not reach here: " + inst.extra);
2023 }
2024 break;
2025 }
2026 default:
2027 throw Util.unimplemented("XIR operation " + inst.op);
2028 }
2029 }
2030 }
2031
2032 /**
2033 * @param offset the offset RSP at which to bang. Note that this offset is relative to RSP after RSP has been
2034 * adjusted to allocated the frame for the method. It denotes an offset "down" the stack.
2035 * For very large frames, this means that the offset may actually be negative (i.e. denoting
2036 * a slot "up" the stack above RSP).
2037 */
2038 private void bangStackWithOffset(int offset) {
2039 masm.movq(new CiAddress(CiKind.Word, AMD64.RSP, (-offset)), AMD64.rax);
2040 }
2041
2042 private CiRegisterValue assureInRegister(CiValue pointer) {
2043 if (pointer.isConstant()) {
2044 CiRegisterValue register = rscratch1.asValue(pointer.kind);
2045 moveOp(pointer, register, pointer.kind, null, false);
2046 return register;
2047 }
2048
2049 assert pointer.isRegister() : "should be register, but is: " + pointer;
2050 return (CiRegisterValue) pointer;
2051 }
2052
2053 private void emitXirCompare(XirInstruction inst, Condition condition, ConditionFlag cflag, CiValue[] ops, Label label) {
2054 CiValue x = ops[inst.x().index];
2055 CiValue y = ops[inst.y().index];
2056 emitCompare(condition, x, y, null);
2057 masm.jcc(cflag, label);
2058 }
2059
2060 @Override
2061 public void emitDeoptizationStub(DeoptimizationStub stub) {
2062 masm.bind(stub.label);
2063 masm.directCall(CiRuntimeCall.Deoptimize, stub.info);
2064 masm.shouldNotReachHere();
2065 }
2066 }