comparison graal/GraalCompiler/src/com/sun/c1x/gen/LIRGenerator.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/gen/LIRGenerator.java@9ec15d6914ca
children 4fdef1464592
comparison
equal deleted inserted replaced
2508:fea94949e0a2 2509:16b9a8b5ad39
1 /*
2 * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23 package com.sun.c1x.gen;
24
25 import static com.sun.cri.bytecode.Bytecodes.*;
26 import static com.sun.cri.bytecode.Bytecodes.MemoryBarriers.*;
27 import static com.sun.cri.ci.CiCallingConvention.Type.*;
28 import static com.sun.cri.ci.CiValue.*;
29
30 import java.lang.reflect.*;
31 import java.util.*;
32
33 import com.sun.c1x.*;
34 import com.sun.c1x.alloc.*;
35 import com.sun.c1x.alloc.OperandPool.VariableFlag;
36 import com.sun.c1x.asm.*;
37 import com.sun.c1x.debug.*;
38 import com.sun.c1x.globalstub.*;
39 import com.sun.c1x.graph.*;
40 import com.sun.c1x.ir.*;
41 import com.sun.c1x.ir.Value.Flag;
42 import com.sun.c1x.lir.FrameMap.StackBlock;
43 import com.sun.c1x.lir.*;
44 import com.sun.c1x.opt.*;
45 import com.sun.c1x.util.*;
46 import com.sun.c1x.value.*;
47 import com.sun.c1x.value.FrameState.PhiProcedure;
48 import com.sun.cri.bytecode.*;
49 import com.sun.cri.bytecode.Bytecodes.MemoryBarriers;
50 import com.sun.cri.ci.*;
51 import com.sun.cri.ci.CiAddress.Scale;
52 import com.sun.cri.ri.*;
53 import com.sun.cri.xir.CiXirAssembler.XirConstant;
54 import com.sun.cri.xir.CiXirAssembler.XirInstruction;
55 import com.sun.cri.xir.CiXirAssembler.XirOperand;
56 import com.sun.cri.xir.CiXirAssembler.XirParameter;
57 import com.sun.cri.xir.CiXirAssembler.XirRegister;
58 import com.sun.cri.xir.CiXirAssembler.XirTemp;
59 import com.sun.cri.xir.*;
60
61 /**
62 * This class traverses the HIR instructions and generates LIR instructions from them.
63 *
64 * @author Thomas Wuerthinger
65 * @author Ben L. Titzer
66 * @author Marcelo Cintra
67 * @author Doug Simon
68 */
69 public abstract class LIRGenerator extends ValueVisitor {
70
71 /**
72 * Helper class for inserting memory barriers as necessary to implement the Java Memory Model
73 * with respect to volatile field accesses.
74 *
75 * @see MemoryBarriers
76 */
77 class VolatileMemoryAccess {
78 /**
79 * Inserts any necessary memory barriers before a volatile write as required by the JMM.
80 */
81 void preVolatileWrite() {
82 int barriers = compilation.target.arch.requiredBarriers(JMM_PRE_VOLATILE_WRITE);
83 if (compilation.target.isMP && barriers != 0) {
84 lir.membar(barriers);
85 }
86 }
87
88 /**
89 * Inserts any necessary memory barriers after a volatile write as required by the JMM.
90 */
91 void postVolatileWrite() {
92 int barriers = compilation.target.arch.requiredBarriers(JMM_POST_VOLATILE_WRITE);
93 if (compilation.target.isMP && barriers != 0) {
94 lir.membar(barriers);
95 }
96 }
97
98 /**
99 * Inserts any necessary memory barriers before a volatile read as required by the JMM.
100 */
101 void preVolatileRead() {
102 int barriers = compilation.target.arch.requiredBarriers(JMM_PRE_VOLATILE_READ);
103 if (compilation.target.isMP && barriers != 0) {
104 lir.membar(barriers);
105 }
106 }
107
108 /**
109 * Inserts any necessary memory barriers after a volatile read as required by the JMM.
110 */
111 void postVolatileRead() {
112 // Ensure field's data is loaded before any subsequent loads or stores.
113 int barriers = compilation.target.arch.requiredBarriers(LOAD_LOAD | LOAD_STORE);
114 if (compilation.target.isMP && barriers != 0) {
115 lir.membar(barriers);
116 }
117 }
118 }
119
120 /**
121 * Forces the result of a given instruction to be available in a given register,
122 * inserting move instructions if necessary.
123 *
124 * @param instruction an instruction that produces a {@linkplain Value#operand() result}
125 * @param register the {@linkplain CiRegister} in which the result of {@code instruction} must be available
126 * @return {@code register} as an operand
127 */
128 protected CiValue force(Value instruction, CiRegister register) {
129 return force(instruction, register.asValue(instruction.kind));
130 }
131
132 /**
133 * Forces the result of a given instruction to be available in a given operand,
134 * inserting move instructions if necessary.
135 *
136 * @param instruction an instruction that produces a {@linkplain Value#operand() result}
137 * @param operand the operand in which the result of {@code instruction} must be available
138 * @return {@code operand}
139 */
140 protected CiValue force(Value instruction, CiValue operand) {
141 CiValue result = makeOperand(instruction);
142 if (result != operand) {
143 assert result.kind != CiKind.Illegal;
144 if (!compilation.archKindsEqual(result.kind, operand.kind)) {
145 // moves between different types need an intervening spill slot
146 CiValue tmp = forceToSpill(result, operand.kind, false);
147 lir.move(tmp, operand);
148 } else {
149 lir.move(result, operand);
150 }
151 }
152 return operand;
153 }
154
155 protected CiValue load(Value val) {
156 CiValue result = makeOperand(val);
157 if (!result.isVariableOrRegister()) {
158 CiVariable operand = newVariable(val.kind);
159 lir.move(result, operand);
160 return operand;
161 }
162 return result;
163 }
164
165 // the range of values in a lookupswitch or tableswitch statement
166 private static final class SwitchRange {
167 final int lowKey;
168 int highKey;
169 final BlockBegin sux;
170
171 SwitchRange(int lowKey, BlockBegin sux) {
172 this.lowKey = lowKey;
173 this.highKey = lowKey;
174 this.sux = sux;
175 }
176 }
177
178 protected final C1XCompilation compilation;
179 protected final IR ir;
180 protected final XirSupport xirSupport;
181 protected final RiXirGenerator xir;
182 protected final boolean isTwoOperand;
183
184 private BlockBegin currentBlock;
185
186 public final OperandPool operands;
187
188 private Value currentInstruction;
189 private Value lastInstructionPrinted; // Debugging only
190
191 private List<CiConstant> constants;
192 private List<CiVariable> variablesForConstants;
193 protected LIRList lir;
194 final VolatileMemoryAccess vma;
195 private ArrayList<DeoptimizationStub> deoptimizationStubs;
196
197 public LIRGenerator(C1XCompilation compilation) {
198 this.compilation = compilation;
199 this.ir = compilation.hir();
200 this.xir = compilation.compiler.xir;
201 this.xirSupport = new XirSupport();
202 this.isTwoOperand = compilation.target.arch.twoOperandMode();
203 this.vma = new VolatileMemoryAccess();
204
205 constants = new ArrayList<CiConstant>();
206 variablesForConstants = new ArrayList<CiVariable>();
207
208 this.operands = new OperandPool(compilation.target);
209
210 // mark the liveness of all instructions if it hasn't already been done by the optimizer
211 LivenessMarker livenessMarker = new LivenessMarker(ir);
212 C1XMetrics.LiveHIRInstructions += livenessMarker.liveCount();
213 }
214
215 public ArrayList<DeoptimizationStub> deoptimizationStubs() {
216 return deoptimizationStubs;
217 }
218
219 public static class DeoptimizationStub {
220 public final Label label = new Label();
221 public final LIRDebugInfo info;
222
223 public DeoptimizationStub(FrameState state) {
224 info = new LIRDebugInfo(state, null);
225 }
226 }
227
228 public final void emitGuard(Guard x) {
229 FrameState state = x.stateBefore();
230 assert state != null : "deoptimize instruction always needs a state";
231
232 if (deoptimizationStubs == null) {
233 deoptimizationStubs = new ArrayList<DeoptimizationStub>();
234 }
235
236 // (tw) TODO: Try to reuse an existing stub if possible.
237 // It is only allowed if there are no LIR instructions in between that can modify registers.
238
239 DeoptimizationStub stub = new DeoptimizationStub(state);
240 deoptimizationStubs.add(stub);
241 lir.branch(x.condition.negate(), stub.label, stub.info);
242 }
243
244 public void doBlock(BlockBegin block) {
245 blockDoProlog(block);
246 this.currentBlock = block;
247
248 for (Instruction instr = block; instr != null; instr = instr.next()) {
249 if (instr.isLive()) {
250 walkState(instr, instr.stateBefore());
251 doRoot(instr);
252 }
253 }
254
255 this.currentBlock = null;
256 blockDoEpilog(block);
257 }
258
259 @Override
260 public void visitArrayLength(ArrayLength x) {
261 emitArrayLength(x);
262 }
263
264 public CiValue emitArrayLength(ArrayLength x) {
265 XirArgument array = toXirArgument(x.array());
266 XirSnippet snippet = xir.genArrayLength(site(x), array);
267 emitXir(snippet, x, x.needsNullCheck() ? stateFor(x) : null, null, true);
268 return x.operand();
269 }
270
271 @Override
272 public void visitBase(Base x) {
273 // emit phi-instruction move after safepoint since this simplifies
274 // describing the state at the safepoint.
275 moveToPhi(x.stateAfter());
276
277 // all blocks with a successor must end with an unconditional jump
278 // to the successor even if they are consecutive
279 lir.jump(x.defaultSuccessor());
280 }
281
282 private void setOperandsForLocals(FrameState state) {
283 CiCallingConvention args = compilation.frameMap().incomingArguments();
284 int javaIndex = 0;
285 for (int i = 0; i < args.locations.length; i++) {
286 CiValue src = args.locations[i];
287 assert src.isLegal() : "check";
288
289 CiVariable dest = newVariable(src.kind.stackKind());
290 lir.move(src, dest, src.kind);
291
292 // Assign new location to Local instruction for this local
293 Value instr = state.localAt(javaIndex);
294 Local local = ((Local) instr);
295 CiKind kind = src.kind.stackKind();
296 assert kind == local.kind.stackKind() : "local type check failed";
297 if (local.isLive()) {
298 setResult(local, dest);
299 }
300 javaIndex += kind.jvmSlots;
301 }
302 }
303
304 @Override
305 public void visitResolveClass(ResolveClass i) {
306 LIRDebugInfo info = stateFor(i);
307 XirSnippet snippet = xir.genResolveClass(site(i), i.type, i.portion);
308 emitXir(snippet, i, info, null, true);
309 }
310
311 @Override
312 public void visitCheckCast(CheckCast x) {
313 XirArgument obj = toXirArgument(x.object());
314 XirSnippet snippet = xir.genCheckCast(site(x), obj, toXirArgument(x.targetClassInstruction), x.targetClass());
315 emitXir(snippet, x, stateFor(x), null, true);
316 }
317
318 @Override
319 public void visitInstanceOf(InstanceOf x) {
320 XirArgument obj = toXirArgument(x.object());
321 XirSnippet snippet = xir.genInstanceOf(site(x), obj, toXirArgument(x.targetClassInstruction), x.targetClass());
322 emitXir(snippet, x, maybeStateFor(x), null, true);
323 }
324
325 @Override
326 public void visitMonitorEnter(MonitorEnter x) {
327 XirArgument obj = toXirArgument(x.object());
328 XirArgument lockAddress = toXirArgument(x.lockAddress());
329 XirSnippet snippet = xir.genMonitorEnter(site(x), obj, lockAddress);
330 emitXir(snippet, x, maybeStateFor(x), stateFor(x, x.stateAfter()), null, true, null);
331 }
332
333 @Override
334 public void visitMonitorExit(MonitorExit x) {
335 XirArgument obj = toXirArgument(x.object());
336 XirArgument lockAddress = toXirArgument(x.lockAddress());
337 XirSnippet snippet = xir.genMonitorExit(site(x), obj, lockAddress);
338 emitXir(snippet, x, maybeStateFor(x), null, true);
339 }
340
341 @Override
342 public void visitStoreIndexed(StoreIndexed x) {
343 XirArgument array = toXirArgument(x.array());
344 XirArgument length = x.length() == null ? null : toXirArgument(x.length());
345 XirArgument index = toXirArgument(x.index());
346 XirArgument value = toXirArgument(x.value());
347 XirSnippet snippet = xir.genArrayStore(site(x), array, index, length, value, x.elementKind(), null);
348 emitXir(snippet, x, maybeStateFor(x), null, true);
349 }
350
351 @Override
352 public void visitNewInstance(NewInstance x) {
353 XirSnippet snippet = xir.genNewInstance(site(x), x.instanceClass());
354 emitXir(snippet, x, stateFor(x), null, true);
355 }
356
357 @Override
358 public void visitNewTypeArray(NewTypeArray x) {
359 XirArgument length = toXirArgument(x.length());
360 XirSnippet snippet = xir.genNewArray(site(x), length, x.elementKind(), null, null);
361 emitXir(snippet, x, stateFor(x), null, true);
362 }
363
364 @Override
365 public void visitNewObjectArray(NewObjectArray x) {
366 XirArgument length = toXirArgument(x.length());
367 XirSnippet snippet = xir.genNewArray(site(x), length, CiKind.Object, x.elementClass(), x.exactType());
368 emitXir(snippet, x, stateFor(x), null, true);
369 }
370
371 @Override
372 public void visitNewObjectArrayClone(NewObjectArrayClone x) {
373 XirArgument length = toXirArgument(x.length());
374 XirArgument referenceArray = toXirArgument(x.referenceArray());
375 XirSnippet snippet = xir.genNewObjectArrayClone(site(x), length, referenceArray);
376 emitXir(snippet, x, stateFor(x), null, true);
377 }
378
379 @Override
380 public void visitNewMultiArray(NewMultiArray x) {
381 XirArgument[] dims = new XirArgument[x.dimensions().length];
382
383 for (int i = 0; i < dims.length; i++) {
384 dims[i] = toXirArgument(x.dimensions()[i]);
385 }
386
387 XirSnippet snippet = xir.genNewMultiArray(site(x), dims, x.elementKind);
388 emitXir(snippet, x, stateFor(x), null, true);
389 }
390
391 @Override
392 public void visitConstant(Constant x) {
393 if (canInlineAsConstant(x)) {
394 //setResult(x, loadConstant(x));
395 } else {
396 CiValue res = x.operand();
397 if (!(res.isLegal())) {
398 res = x.asConstant();
399 }
400 if (res.isConstant()) {
401 if (isUsedForValue(x)) {
402 CiVariable reg = createResultVariable(x);
403 lir.move(res, reg);
404 } else {
405 assert x.checkFlag(Value.Flag.LiveDeopt);
406 x.setOperand(res);
407 }
408 } else {
409 setResult(x, (CiVariable) res);
410 }
411 }
412 }
413
414 @Override
415 public void visitExceptionObject(ExceptionObject x) {
416 assert currentBlock.isExceptionEntry() : "ExceptionObject only allowed in exception handler block";
417 assert currentBlock.next() == x : "ExceptionObject must be first instruction of block";
418
419 // no moves are created for phi functions at the begin of exception
420 // handlers, so assign operands manually here
421 currentBlock.stateBefore().forEachLivePhi(currentBlock, new PhiProcedure() {
422 public boolean doPhi(Phi phi) {
423 operandForPhi(phi);
424 return true;
425 }
426 });
427
428 XirSnippet snippet = xir.genExceptionObject(site(x));
429 emitXir(snippet, x, maybeStateFor(x), null, true);
430 }
431
432 @Override
433 public void visitGoto(Goto x) {
434 setNoResult(x);
435
436 if (currentBlock.next() instanceof OsrEntry) {
437 // need to free up storage used for OSR entry point
438 CiValue osrBuffer = currentBlock.next().operand();
439 callRuntime(CiRuntimeCall.OSRMigrationEnd, null, osrBuffer);
440 emitXir(xir.genSafepoint(site(x)), x, stateFor(x, x.stateAfter()), null, false);
441 }
442
443 // emit phi-instruction moves after safepoint since this simplifies
444 // describing the state at the safepoint.
445 moveToPhi(x.stateAfter());
446
447 lir.jump(x.defaultSuccessor());
448 }
449
450 @Override
451 public void visitIfOp(IfOp i) {
452 Value x = i.x();
453 Value y = i.y();
454 CiKind xtype = x.kind;
455 CiKind ttype = i.trueValue().kind;
456 assert xtype.isInt() || xtype.isObject() : "cannot handle others";
457 assert ttype.isInt() || ttype.isObject() || ttype.isLong() || ttype.isWord() : "cannot handle others";
458 assert ttype.equals(i.falseValue().kind) : "cannot handle others";
459
460 CiValue left = load(x);
461 CiValue right = null;
462 if (!canInlineAsConstant(y)) {
463 right = load(y);
464 } else {
465 right = makeOperand(y);
466 }
467
468 CiValue tVal = makeOperand(i.trueValue());
469 CiValue fVal = makeOperand(i.falseValue());
470 CiValue reg = createResultVariable(i);
471
472 lir.cmp(i.condition(), left, right);
473 lir.cmove(i.condition(), tVal, fVal, reg);
474 }
475
476 @Override
477 public void visitIntrinsic(Intrinsic x) {
478 Value[] vals = x.arguments();
479 XirSnippet snippet;
480
481 switch (x.intrinsic()) {
482 case java_lang_Float$intBitsToFloat:
483 case java_lang_Double$doubleToRawLongBits:
484 case java_lang_Double$longBitsToDouble:
485 case java_lang_Float$floatToRawIntBits: {
486 visitFPIntrinsics(x);
487 return;
488 }
489
490 case java_lang_System$currentTimeMillis: {
491 assert x.numberOfArguments() == 0 : "wrong type";
492 CiValue reg = callRuntimeWithResult(CiRuntimeCall.JavaTimeMillis, null, (CiValue[]) null);
493 CiValue result = createResultVariable(x);
494 lir.move(reg, result);
495 return;
496 }
497
498 case java_lang_System$nanoTime: {
499 assert x.numberOfArguments() == 0 : "wrong type";
500 CiValue reg = callRuntimeWithResult(CiRuntimeCall.JavaTimeNanos, null, (CiValue[]) null);
501 CiValue result = createResultVariable(x);
502 lir.move(reg, result);
503 return;
504 }
505
506 case java_lang_Object$init:
507 visitRegisterFinalizer(x);
508 return;
509
510 case java_lang_Math$log: // fall through
511 case java_lang_Math$log10: // fall through
512 case java_lang_Math$abs: // fall through
513 case java_lang_Math$sqrt: // fall through
514 case java_lang_Math$tan: // fall through
515 case java_lang_Math$sin: // fall through
516 case java_lang_Math$cos:
517 genMathIntrinsic(x);
518 return;
519
520 case sun_misc_Unsafe$compareAndSwapObject:
521 genCompareAndSwap(x, CiKind.Object);
522 return;
523 case sun_misc_Unsafe$compareAndSwapInt:
524 genCompareAndSwap(x, CiKind.Int);
525 return;
526 case sun_misc_Unsafe$compareAndSwapLong:
527 genCompareAndSwap(x, CiKind.Long);
528 return;
529
530 case java_lang_Thread$currentThread:
531 snippet = xir.genCurrentThread(site(x));
532 if (snippet != null) {
533 emitXir(snippet, x, null, null, true);
534 return;
535 }
536 break;
537
538 case java_lang_Object$getClass:
539 snippet = xir.genGetClass(site(x), toXirArgument(vals[0]));
540 if (snippet != null) {
541 emitXir(snippet, x, stateFor(x), null, true);
542 return;
543 }
544 break;
545 }
546
547
548 XirArgument[] args = new XirArgument[vals.length];
549 for (int i = 0; i < vals.length; i++) {
550 args[i] = toXirArgument(vals[i]);
551 }
552 snippet = xir.genIntrinsic(site(x), args, x.target());
553 if (snippet != null) {
554 emitXir(snippet, x, x.stateBefore() == null ? null : stateFor(x), null, true);
555 return;
556 }
557 x.setOperand(emitInvokeKnown(x.target(), x.stateBefore(), vals));
558 }
559
560 @Override
561 public void visitInvoke(Invoke x) {
562 RiMethod target = x.target();
563 LIRDebugInfo info = stateFor(x, x.stateBefore());
564
565 XirSnippet snippet = null;
566
567 int opcode = x.opcode();
568 XirArgument receiver;
569 switch (opcode) {
570 case INVOKESTATIC:
571 snippet = xir.genInvokeStatic(site(x), target);
572 break;
573 case INVOKESPECIAL:
574 receiver = toXirArgument(x.receiver());
575 snippet = xir.genInvokeSpecial(site(x), receiver, target);
576 break;
577 case INVOKEVIRTUAL:
578 receiver = toXirArgument(x.receiver());
579 snippet = xir.genInvokeVirtual(site(x), receiver, target);
580 break;
581 case INVOKEINTERFACE:
582 receiver = toXirArgument(x.receiver());
583 snippet = xir.genInvokeInterface(site(x), receiver, target);
584 break;
585 }
586
587 CiValue destinationAddress = null;
588 // emitting the template earlier can ease pressure on register allocation, but the argument loading can destroy an
589 // implicit calling convention between the XirSnippet and the call.
590 if (!C1XOptions.InvokeSnippetAfterArguments) {
591 destinationAddress = emitXir(snippet, x, info.copy(), x.target(), false);
592 }
593
594 CiValue resultOperand = resultOperandFor(x.kind);
595 CiCallingConvention cc = compilation.frameMap().getCallingConvention(x.signature(), JavaCall);
596 List<CiValue> pointerSlots = new ArrayList<CiValue>(2);
597 List<CiValue> argList = visitInvokeArguments(cc, x.arguments(), pointerSlots);
598
599 if (C1XOptions.InvokeSnippetAfterArguments) {
600 destinationAddress = emitXir(snippet, x, info.copy(), null, x.target(), false, pointerSlots);
601 }
602
603 // emit direct or indirect call to the destination address
604 if (destinationAddress instanceof CiConstant) {
605 // Direct call
606 assert ((CiConstant) destinationAddress).isDefaultValue() : "destination address should be zero";
607 lir.callDirect(target, resultOperand, argList, info, snippet.marks, pointerSlots);
608 } else {
609 // Indirect call
610 argList.add(destinationAddress);
611 lir.callIndirect(target, resultOperand, argList, info, snippet.marks, pointerSlots);
612 }
613
614 if (resultOperand.isLegal()) {
615 CiValue result = createResultVariable(x);
616 lir.move(resultOperand, result);
617 }
618 }
619
620 @Override
621 public void visitNativeCall(NativeCall x) {
622 LIRDebugInfo info = stateFor(x, x.stateBefore());
623 CiValue resultOperand = resultOperandFor(x.kind);
624 CiValue callAddress = load(x.address());
625 CiKind[] signature = Util.signatureToKinds(x.signature, null);
626 CiCallingConvention cc = compilation.frameMap().getCallingConvention(signature, NativeCall);
627 List<CiValue> argList = visitInvokeArguments(cc, x.arguments, null);
628 argList.add(callAddress);
629 lir.callNative(x.nativeMethod.jniSymbol(), resultOperand, argList, info, null);
630 if (resultOperand.isLegal()) {
631 CiValue result = createResultVariable(x);
632 lir.move(resultOperand, result);
633 }
634 }
635
636 @Override
637 public void visitTemplateCall(TemplateCall x) {
638 CiValue resultOperand = resultOperandFor(x.kind);
639 List<CiValue> argList;
640 if (x.receiver() != null) {
641 CiCallingConvention cc = compilation.frameMap().getCallingConvention(new CiKind[] {CiKind.Object}, JavaCall);
642 argList = visitInvokeArguments(cc, new Value[] {x.receiver()}, null);
643 } else {
644 argList = new ArrayList<CiValue>();
645 }
646
647 if (x.address() != null) {
648 CiValue callAddress = load(x.address());
649 argList.add(callAddress);
650 }
651 lir.templateCall(resultOperand, argList);
652 if (resultOperand.isLegal()) {
653 CiValue result = createResultVariable(x);
654 lir.move(resultOperand, result);
655 }
656 }
657
658 @Override
659 public void visitLoadRegister(LoadRegister x) {
660 x.setOperand(x.register.asValue(x.kind));
661 }
662
663 @Override
664 public void visitPause(Pause i) {
665 lir.pause();
666 }
667
668 @Override
669 public void visitBreakpointTrap(BreakpointTrap i) {
670 lir.breakpoint();
671 }
672
673 protected CiAddress getAddressForPointerOp(PointerOp x, CiKind kind, CiValue pointer) {
674 CiAddress addr;
675 Value offset = x.offset();
676 Value index = x.index();
677 if (x.displacement() == null) {
678 // address is [pointer + offset]
679 if (offset.isConstant() && offset.kind.isInt()) {
680 int displacement = x.offset().asConstant().asInt();
681 addr = new CiAddress(kind, pointer, displacement);
682 } else {
683 addr = new CiAddress(kind, pointer, load(offset));
684 }
685 } else {
686 // address is [pointer + disp + (index * scale)]
687 assert (x.opcode & 0xff) == PGET || (x.opcode & 0xff) == PSET;
688 if (!x.displacement().isConstant()) {
689 CiVariable tmp = newVariable(CiKind.Word);
690 arithmeticOpLong(Bytecodes.LADD, tmp, pointer, load(x.displacement()), null);
691 int kindSize = compilation.target.sizeInBytes(kind);
692 Scale scale = Scale.fromInt(kindSize);
693 if (index.isConstant()) {
694 addr = new CiAddress(kind, tmp, index.asConstant().asInt() * kindSize);
695 } else {
696 addr = new CiAddress(kind, tmp, load(index), scale, 0);
697 }
698 } else {
699 int displacement = x.displacement().asConstant().asInt();
700 int kindSize = compilation.target.sizeInBytes(kind);
701 Scale scale = Scale.fromInt(kindSize);
702 if (index.isConstant()) {
703 displacement += index.asConstant().asInt() * kindSize;
704 addr = new CiAddress(kind, pointer, displacement);
705 } else {
706 addr = new CiAddress(kind, pointer, load(index), scale, displacement);
707 }
708 }
709 }
710 return addr;
711 }
712
713 @Override
714 public void visitAllocateStackHandle(StackHandle x) {
715 CiValue value = load(x.value());
716 CiValue src = forceToSpill(value, x.value().kind, true);
717 CiValue dst = createResultVariable(x);
718
719 CiConstant constant = x.value().isConstant() ? x.value().asConstant() : null;
720 if (constant == null) {
721 CiConstant zero = CiConstant.defaultValue(x.value().kind);
722 lir.cmp(Condition.EQ, src, zero);
723 }
724 lir.lea(src, dst);
725 if (constant != null) {
726 if (constant.isDefaultValue()) {
727 lir.move(value, dst);
728 }
729 } else {
730 lir.cmove(Condition.EQ, CiConstant.ZERO, dst, dst);
731 }
732 }
733
734 @Override
735 public void visitLoadPointer(LoadPointer x) {
736 LIRDebugInfo info = maybeStateFor(x);
737 CiValue pointer = load(x.pointer());
738 CiValue dst = createResultVariable(x);
739 CiAddress src = getAddressForPointerOp(x, x.dataKind, pointer);
740 lir.load(src, dst, info);
741 }
742
743 @Override
744 public void visitStorePointer(StorePointer x) {
745 LIRDebugInfo info = maybeStateFor(x);
746 LIRItem value = new LIRItem(x.value(), this);
747 CiValue pointer = load(x.pointer());
748 value.loadItem(x.dataKind);
749 CiAddress dst = getAddressForPointerOp(x, x.dataKind, pointer);
750 lir.store(value.result(), dst, info);
751 }
752
753 @Override
754 public void visitInfopoint(Infopoint x) {
755 LIRDebugInfo info = stateFor(x);
756 if (x.opcode == SAFEPOINT) {
757 emitXir(xir.genSafepoint(site(x)), x, info, null, false);
758 return;
759 }
760 assert x.opcode == HERE || x.opcode == INFO;
761 CiValue result = x.kind.isVoid() ? CiValue.IllegalValue : createResultVariable(x);
762 LIROpcode opcode = x.opcode == HERE ? LIROpcode.Here : LIROpcode.Info;
763 lir.infopoint(opcode, result, info);
764 }
765
766 @Override
767 public void visitStackAllocate(StackAllocate x) {
768 CiValue result = createResultVariable(x);
769 assert x.size().isConstant() : "ALLOCA bytecode 'size' operand is not a constant: " + x.size();
770 StackBlock stackBlock = compilation.frameMap().reserveStackBlock(x.size().asConstant().asInt());
771 lir.alloca(stackBlock, result);
772 }
773
774 @Override
775 public void visitMonitorAddress(MonitorAddress x) {
776 CiValue result = createResultVariable(x);
777 lir.monitorAddress(x.monitor(), result);
778 }
779
780 @Override
781 public void visitMemoryBarrier(MemoryBarrier x) {
782 if (x.barriers != 0) {
783 lir.membar(x.barriers);
784 }
785 }
786
787 @Override
788 public void visitUnsafeCast(UnsafeCast i) {
789 assert !i.redundant : "redundant UnsafeCasts must be eliminated by the front end";
790 CiValue src = load(i.value());
791 CiValue dst = createResultVariable(i);
792 lir.move(src, dst);
793 }
794
795 /**
796 * For note on volatile fields, see {@link #visitStoreField(StoreField)}.
797 */
798 @Override
799 public void visitLoadField(LoadField x) {
800 RiField field = x.field();
801 boolean needsPatching = x.needsPatching();
802 LIRDebugInfo info = null;
803 if (needsPatching || x.needsNullCheck()) {
804 info = stateFor(x, x.stateBefore());
805 assert info != null;
806 }
807
808 XirArgument receiver = toXirArgument(x.object());
809 XirSnippet snippet = x.isStatic() ? xir.genGetStatic(site(x), receiver, field) : xir.genGetField(site(x), receiver, field);
810 emitXir(snippet, x, info, null, true);
811
812 if (x.isVolatile()) {
813 vma.postVolatileRead();
814 }
815 }
816
817 @Override
818 public void visitLoadIndexed(LoadIndexed x) {
819 XirArgument array = toXirArgument(x.array());
820 XirArgument index = toXirArgument(x.index());
821 XirArgument length = toXirArgument(x.length());
822 XirSnippet snippet = xir.genArrayLoad(site(x), array, index, length, x.elementKind(), null);
823 emitXir(snippet, x, maybeStateFor(x), null, true);
824 }
825
826 protected GlobalStub stubFor(CiRuntimeCall runtimeCall) {
827 GlobalStub stub = compilation.compiler.lookupGlobalStub(runtimeCall);
828 compilation.frameMap().usesGlobalStub(stub);
829 return stub;
830 }
831
832 protected GlobalStub stubFor(GlobalStub.Id globalStub) {
833 GlobalStub stub = compilation.compiler.lookupGlobalStub(globalStub);
834 compilation.frameMap().usesGlobalStub(stub);
835 return stub;
836 }
837
838 protected GlobalStub stubFor(XirTemplate template) {
839 GlobalStub stub = compilation.compiler.lookupGlobalStub(template);
840 compilation.frameMap().usesGlobalStub(stub);
841 return stub;
842 }
843
844 @Override
845 public void visitLocal(Local x) {
846 if (x.operand().isIllegal()) {
847 createResultVariable(x);
848 }
849 }
850
851 @Override
852 public void visitLookupSwitch(LookupSwitch x) {
853 CiValue tag = load(x.value());
854 setNoResult(x);
855
856 if (x.isSafepoint()) {
857 emitXir(xir.genSafepoint(site(x)), x, stateFor(x, x.stateAfter()), null, false);
858 }
859
860 // move values into phi locations
861 moveToPhi(x.stateAfter());
862
863 if (x.numberOfCases() == 0 || x.numberOfCases() < C1XOptions.SequentialSwitchLimit) {
864 int len = x.numberOfCases();
865 for (int i = 0; i < len; i++) {
866 lir.cmp(Condition.EQ, tag, x.keyAt(i));
867 lir.branch(Condition.EQ, CiKind.Int, x.suxAt(i));
868 }
869 lir.jump(x.defaultSuccessor());
870 } else {
871 visitSwitchRanges(createLookupRanges(x), tag, x.defaultSuccessor());
872 }
873 }
874
875 @Override
876 public void visitNullCheck(NullCheck x) {
877 // TODO: this is suboptimal because it may result in an unnecessary move
878 CiValue value = load(x.object());
879 if (x.canTrap()) {
880 LIRDebugInfo info = stateFor(x);
881 lir.nullCheck(value, info);
882 }
883 x.setOperand(value);
884 }
885
886 @Override
887 public void visitOsrEntry(OsrEntry x) {
888 // construct our frame and model the production of incoming pointer
889 // to the OSR buffer.
890 lir.osrEntry(osrBufferPointer());
891 CiValue result = createResultVariable(x);
892 lir.move(osrBufferPointer(), result);
893 }
894
895 @Override
896 public void visitPhi(Phi i) {
897 Util.shouldNotReachHere();
898 }
899
900 @Override
901 public void visitReturn(Return x) {
902 if (x.kind.isVoid()) {
903 XirSnippet epilogue = xir.genEpilogue(site(x), compilation.method);
904 if (epilogue != null) {
905 emitXir(epilogue, x, stateFor(x, x.stateAfter()), compilation.method, false);
906 lir.returnOp(IllegalValue);
907 }
908 } else {
909 CiValue operand = resultOperandFor(x.kind);
910 CiValue result = force(x.result(), operand);
911 XirSnippet epilogue = xir.genEpilogue(site(x), compilation.method);
912 if (epilogue != null) {
913 emitXir(epilogue, x, stateFor(x, x.stateAfter()), compilation.method, false);
914 lir.returnOp(result);
915 }
916 }
917 setNoResult(x);
918 }
919
920 protected XirArgument toXirArgument(CiValue v) {
921 if (v == null) {
922 return null;
923 }
924
925 return XirArgument.forInternalObject(v);
926 }
927
928 protected XirArgument toXirArgument(Value i) {
929 if (i == null) {
930 return null;
931 }
932
933 return XirArgument.forInternalObject(new LIRItem(i, this));
934 }
935
936 private CiValue allocateOperand(XirSnippet snippet, XirOperand op) {
937 if (op instanceof XirParameter) {
938 XirParameter param = (XirParameter) op;
939 return allocateOperand(snippet.arguments[param.parameterIndex], op, param.canBeConstant);
940 } else if (op instanceof XirRegister) {
941 XirRegister reg = (XirRegister) op;
942 return reg.register;
943 } else if (op instanceof XirTemp) {
944 return newVariable(op.kind);
945 } else {
946 Util.shouldNotReachHere();
947 return null;
948 }
949 }
950
951 private CiValue allocateOperand(XirArgument arg, XirOperand var, boolean canBeConstant) {
952 if (arg.constant != null) {
953 return arg.constant;
954 } else {
955 assert arg.object != null;
956 if (arg.object instanceof CiValue) {
957 return (CiValue) arg.object;
958 }
959 assert arg.object instanceof LIRItem;
960 LIRItem item = (LIRItem) arg.object;
961 if (canBeConstant) {
962 return item.instruction.operand();
963 } else {
964 item.loadItem(var.kind);
965 return item.result();
966 }
967 }
968 }
969
970 protected CiValue emitXir(XirSnippet snippet, Instruction x, LIRDebugInfo info, RiMethod method, boolean setInstructionResult) {
971 return emitXir(snippet, x, info, null, method, setInstructionResult, null);
972 }
973
974 protected CiValue emitXir(XirSnippet snippet, Instruction instruction, LIRDebugInfo info, LIRDebugInfo infoAfter, RiMethod method, boolean setInstructionResult, List<CiValue> pointerSlots) {
975 if (C1XOptions.PrintXirTemplates) {
976 TTY.println("Emit XIR template " + snippet.template.name);
977 }
978
979 final CiValue[] operands = new CiValue[snippet.template.variableCount];
980
981 compilation.frameMap().reserveOutgoing(snippet.template.outgoingStackSize);
982
983 XirOperand resultOperand = snippet.template.resultOperand;
984
985 if (snippet.template.allocateResultOperand) {
986 CiValue outputOperand = IllegalValue;
987 // This snippet has a result that must be separately allocated
988 // Otherwise it is assumed that the result is part of the inputs
989 if (resultOperand.kind != CiKind.Void && resultOperand.kind != CiKind.Illegal) {
990 if (setInstructionResult) {
991 outputOperand = newVariable(instruction.kind);
992 } else {
993 outputOperand = newVariable(resultOperand.kind);
994 }
995 assert operands[resultOperand.index] == null;
996 }
997 operands[resultOperand.index] = outputOperand;
998 if (C1XOptions.PrintXirTemplates) {
999 TTY.println("Output operand: " + outputOperand);
1000 }
1001 }
1002
1003 for (XirTemp t : snippet.template.temps) {
1004 if (t instanceof XirRegister) {
1005 XirRegister reg = (XirRegister) t;
1006 if (!t.reserve) {
1007 operands[t.index] = reg.register;
1008 }
1009 }
1010 }
1011
1012 for (XirTemplate calleeTemplate : snippet.template.calleeTemplates) {
1013 // TODO Save these for use in X86LIRAssembler
1014 stubFor(calleeTemplate);
1015 }
1016
1017 for (XirConstant c : snippet.template.constants) {
1018 assert operands[c.index] == null;
1019 operands[c.index] = c.value;
1020 }
1021
1022 XirOperand[] inputOperands = snippet.template.inputOperands;
1023 XirOperand[] inputTempOperands = snippet.template.inputTempOperands;
1024 XirOperand[] tempOperands = snippet.template.tempOperands;
1025
1026 CiValue[] operandArray = new CiValue[inputOperands.length + inputTempOperands.length + tempOperands.length];
1027 int[] operandIndicesArray = new int[inputOperands.length + inputTempOperands.length + tempOperands.length];
1028 for (int i = 0; i < inputOperands.length; i++) {
1029 XirOperand x = inputOperands[i];
1030 CiValue op = allocateOperand(snippet, x);
1031 operands[x.index] = op;
1032 operandArray[i] = op;
1033 operandIndicesArray[i] = x.index;
1034 if (C1XOptions.PrintXirTemplates) {
1035 TTY.println("Input operand: " + x);
1036 }
1037 }
1038
1039 for (int i = 0; i < inputTempOperands.length; i++) {
1040 XirOperand x = inputTempOperands[i];
1041 CiValue op = allocateOperand(snippet, x);
1042 CiValue newOp = newVariable(op.kind);
1043 lir.move(op, newOp);
1044 operands[x.index] = newOp;
1045 operandArray[i + inputOperands.length] = newOp;
1046 operandIndicesArray[i + inputOperands.length] = x.index;
1047 if (C1XOptions.PrintXirTemplates) {
1048 TTY.println("InputTemp operand: " + x);
1049 }
1050 }
1051
1052 for (int i = 0; i < tempOperands.length; i++) {
1053 XirOperand x = tempOperands[i];
1054 CiValue op = allocateOperand(snippet, x);
1055 operands[x.index] = op;
1056 operandArray[i + inputOperands.length + inputTempOperands.length] = op;
1057 operandIndicesArray[i + inputOperands.length + inputTempOperands.length] = x.index;
1058 if (C1XOptions.PrintXirTemplates) {
1059 TTY.println("Temp operand: " + x);
1060 }
1061 }
1062
1063 for (CiValue operand : operands) {
1064 assert operand != null;
1065 }
1066
1067 CiValue allocatedResultOperand = operands[resultOperand.index];
1068 if (!allocatedResultOperand.isVariableOrRegister()) {
1069 allocatedResultOperand = IllegalValue;
1070 }
1071
1072 if (setInstructionResult && allocatedResultOperand.isLegal()) {
1073 if (instruction.operand().isIllegal()) {
1074 setResult(instruction, (CiVariable) allocatedResultOperand);
1075 } else {
1076 assert instruction.operand() == allocatedResultOperand;
1077 }
1078 }
1079
1080
1081 XirInstruction[] slowPath = snippet.template.slowPath;
1082 if (!operands[resultOperand.index].isConstant() || snippet.template.fastPath.length != 0 || (slowPath != null && slowPath.length > 0)) {
1083 // XIR instruction is only needed when the operand is not a constant!
1084 lir.xir(snippet, operands, allocatedResultOperand, inputTempOperands.length, tempOperands.length,
1085 operandArray, operandIndicesArray,
1086 (operands[resultOperand.index] == IllegalValue) ? -1 : resultOperand.index,
1087 info, infoAfter, method, pointerSlots);
1088 }
1089
1090 return operands[resultOperand.index];
1091 }
1092
1093 @Override
1094 public void visitIncrementRegister(IncrementRegister x) {
1095 CiValue reg = x.register.asValue(CiKind.Word);
1096 if (x.delta().isConstant()) {
1097 int delta = x.delta().asConstant().asInt();
1098 if (delta < 0) {
1099 lir.sub(reg, CiConstant.forInt(-delta), reg);
1100 } else {
1101 lir.add(reg, CiConstant.forInt(delta), reg);
1102 }
1103 } else {
1104 lir.add(reg, makeOperand(x.delta()), reg);
1105 }
1106 }
1107
1108 @Override
1109 public void visitStoreRegister(StoreRegister x) {
1110 CiValue reg = x.register.asValue(x.kind);
1111 lir.move(makeOperand(x.value()), reg);
1112 }
1113
1114 @Override
1115 public void visitStoreField(StoreField x) {
1116 RiField field = x.field();
1117 boolean needsPatching = x.needsPatching();
1118
1119 LIRDebugInfo info = null;
1120 if (needsPatching || x.needsNullCheck()) {
1121 info = stateFor(x, x.stateBefore());
1122 }
1123
1124 if (x.isVolatile()) {
1125 vma.preVolatileWrite();
1126 }
1127
1128 XirArgument receiver = toXirArgument(x.object());
1129 XirArgument value = toXirArgument(x.value());
1130 XirSnippet snippet = x.isStatic() ? xir.genPutStatic(site(x), receiver, field, value) : xir.genPutField(site(x), receiver, field, value);
1131 emitXir(snippet, x, info, null, true);
1132
1133 if (x.isVolatile()) {
1134 vma.postVolatileWrite();
1135 }
1136 }
1137
1138 @Override
1139 public void visitTableSwitch(TableSwitch x) {
1140
1141 LIRItem value = new LIRItem(x.value(), this);
1142 // Making a copy of the switch value is necessary when generating a jump table
1143 value.setDestroysRegister();
1144 value.loadItem();
1145
1146 CiValue tag = value.result();
1147 setNoResult(x);
1148
1149 if (x.isSafepoint()) {
1150 emitXir(xir.genSafepoint(site(x)), x, stateFor(x, x.stateAfter()), null, false);
1151 }
1152
1153 // move values into phi locations
1154 moveToPhi(x.stateAfter());
1155
1156 // TODO: tune the defaults for the controls used to determine what kind of translation to use
1157 if (x.numberOfCases() == 0 || x.numberOfCases() <= C1XOptions.SequentialSwitchLimit) {
1158 int loKey = x.lowKey();
1159 int len = x.numberOfCases();
1160 for (int i = 0; i < len; i++) {
1161 lir.cmp(Condition.EQ, tag, i + loKey);
1162 lir.branch(Condition.EQ, CiKind.Int, x.suxAt(i));
1163 }
1164 lir.jump(x.defaultSuccessor());
1165 } else {
1166 SwitchRange[] switchRanges = createLookupRanges(x);
1167 int rangeDensity = x.numberOfCases() / switchRanges.length;
1168 if (rangeDensity >= C1XOptions.RangeTestsSwitchDensity) {
1169 visitSwitchRanges(switchRanges, tag, x.defaultSuccessor());
1170 } else {
1171 List<BlockBegin> nonDefaultSuccessors = x.successors().subList(0, x.numberOfCases());
1172 BlockBegin[] targets = nonDefaultSuccessors.toArray(new BlockBegin[nonDefaultSuccessors.size()]);
1173 lir.tableswitch(tag, x.lowKey(), x.defaultSuccessor(), targets);
1174 }
1175 }
1176 }
1177
1178 @Override
1179 public void visitThrow(Throw x) {
1180 setNoResult(x);
1181 CiValue exceptionOpr = load(x.exception());
1182 LIRDebugInfo info = stateFor(x, x.stateAfter());
1183
1184 // check if the instruction has an xhandler in any of the nested scopes
1185 boolean unwind = false;
1186 if (x.exceptionHandlers().size() == 0) {
1187 // this throw is not inside an xhandler
1188 unwind = true;
1189 } else {
1190 // get some idea of the throw type
1191 boolean typeIsExact = true;
1192 RiType throwType = x.exception().exactType();
1193 if (throwType == null) {
1194 typeIsExact = false;
1195 throwType = x.exception().declaredType();
1196 }
1197 if (throwType != null && throwType.isResolved() && throwType.isInstanceClass()) {
1198 unwind = !ExceptionHandler.couldCatch(x.exceptionHandlers(), throwType, typeIsExact);
1199 }
1200 }
1201
1202 assert !currentBlock.checkBlockFlag(BlockBegin.BlockFlag.DefaultExceptionHandler) || unwind : "should be no more handlers to dispatch to";
1203
1204 // move exception oop into fixed register
1205 CiCallingConvention callingConvention = compilation.frameMap().getCallingConvention(new CiKind[]{CiKind.Object}, RuntimeCall);
1206 CiValue argumentOperand = callingConvention.locations[0];
1207 lir.move(exceptionOpr, argumentOperand);
1208
1209 if (unwind) {
1210 lir.unwindException(exceptionPcOpr(), exceptionOpr, info);
1211 } else {
1212 lir.throwException(exceptionPcOpr(), argumentOperand, info);
1213 }
1214 }
1215
1216 @Override
1217 public void visitUnsafeGetObject(UnsafeGetObject x) {
1218 CiKind kind = x.unsafeOpKind;
1219
1220 CiValue off = load(x.offset());
1221 CiValue src = load(x.object());
1222
1223 CiValue reg = createResultVariable(x);
1224
1225 if (x.isVolatile()) {
1226 vma.preVolatileRead();
1227 }
1228 genGetObjectUnsafe(reg, src, off, kind, x.isVolatile());
1229 if (x.isVolatile()) {
1230 vma.postVolatileRead();
1231 }
1232 }
1233
1234 @Override
1235 public void visitUnsafeGetRaw(UnsafeGetRaw x) {
1236 LIRItem idx = new LIRItem(this);
1237 CiValue base = load(x.base());
1238 if (x.hasIndex()) {
1239 idx.setInstruction(x.index());
1240 idx.loadNonconstant();
1241 }
1242
1243 CiValue reg = createResultVariable(x);
1244
1245 int log2scale = 0;
1246 if (x.hasIndex()) {
1247 assert x.index().kind.isInt() : "should not find non-int index";
1248 log2scale = x.log2Scale();
1249 }
1250
1251 assert !x.hasIndex() || idx.instruction == x.index() : "should match";
1252
1253 CiKind dstKind = x.unsafeOpKind;
1254 CiValue indexOp = idx.result();
1255
1256 CiAddress addr = null;
1257 if (indexOp.isConstant()) {
1258 assert log2scale == 0 : "must not have a scale";
1259 CiConstant constantIndexOp = (CiConstant) indexOp;
1260 addr = new CiAddress(dstKind, base, constantIndexOp.asInt());
1261 } else {
1262
1263 if (compilation.target.arch.isX86()) {
1264 addr = new CiAddress(dstKind, base, indexOp, CiAddress.Scale.fromInt(2 ^ log2scale), 0);
1265
1266 } else if (compilation.target.arch.isSPARC()) {
1267 if (indexOp.isIllegal() || log2scale == 0) {
1268 addr = new CiAddress(dstKind, base, indexOp);
1269 } else {
1270 CiValue tmp = newVariable(CiKind.Int);
1271 lir.shiftLeft(indexOp, log2scale, tmp);
1272 addr = new CiAddress(dstKind, base, tmp);
1273 }
1274
1275 } else {
1276 Util.shouldNotReachHere();
1277 }
1278 }
1279
1280 if (x.mayBeUnaligned() && (dstKind == CiKind.Long || dstKind == CiKind.Double)) {
1281 lir.unalignedMove(addr, reg);
1282 } else {
1283 lir.move(addr, reg);
1284 }
1285 }
1286
1287 @Override
1288 public void visitUnsafePrefetchRead(UnsafePrefetchRead x) {
1289 visitUnsafePrefetch(x, false);
1290 }
1291
1292 @Override
1293 public void visitUnsafePrefetchWrite(UnsafePrefetchWrite x) {
1294 visitUnsafePrefetch(x, true);
1295 }
1296
1297 @Override
1298 public void visitUnsafePutObject(UnsafePutObject x) {
1299 CiKind kind = x.unsafeOpKind;
1300 LIRItem data = new LIRItem(x.value(), this);
1301
1302 CiValue src = load(x.object());
1303 data.loadItem(kind);
1304 CiValue off = load(x.offset());
1305
1306 setNoResult(x);
1307
1308 if (x.isVolatile()) {
1309 vma.preVolatileWrite();
1310 }
1311 genPutObjectUnsafe(src, off, data.result(), kind, x.isVolatile());
1312 if (x.isVolatile()) {
1313 vma.postVolatileWrite();
1314 }
1315 }
1316
1317 @Override
1318 public void visitUnsafePutRaw(UnsafePutRaw x) {
1319 int log2scale = 0;
1320 CiKind kind = x.unsafeOpKind;
1321
1322 if (x.hasIndex()) {
1323 assert x.index().kind.isInt() : "should not find non-int index";
1324 log2scale = x.log2scale();
1325 }
1326
1327 LIRItem value = new LIRItem(x.value(), this);
1328 LIRItem idx = new LIRItem(this);
1329
1330 CiValue base = load(x.base());
1331 if (x.hasIndex()) {
1332 idx.setInstruction(x.index());
1333 idx.loadItem();
1334 }
1335
1336 value.loadItem(kind);
1337
1338 setNoResult(x);
1339
1340 CiValue indexOp = idx.result();
1341 if (log2scale != 0) {
1342 // temporary fix (platform dependent code without shift on Intel would be better)
1343 indexOp = newVariable(CiKind.Int);
1344 lir.move(idx.result(), indexOp);
1345 lir.shiftLeft(indexOp, log2scale, indexOp);
1346 }
1347
1348 CiValue addr = new CiAddress(x.unsafeOpKind, base, indexOp);
1349 lir.move(value.result(), addr);
1350 }
1351
1352 private void blockDoEpilog(BlockBegin block) {
1353 if (C1XOptions.PrintIRWithLIR) {
1354 TTY.println();
1355 }
1356
1357 // clear out variables for local constants
1358 constants.clear();
1359 variablesForConstants.clear();
1360 }
1361
1362 private void blockDoProlog(BlockBegin block) {
1363 if (C1XOptions.PrintIRWithLIR) {
1364 TTY.print(block.toString());
1365 }
1366 // set up the list of LIR instructions
1367 assert block.lir() == null : "LIR list already computed for this block";
1368 lir = new LIRList(this);
1369 block.setLir(lir);
1370
1371 lir.branchDestination(block.label());
1372 if (block == ir.startBlock) {
1373 XirSnippet prologue = xir.genPrologue(null, compilation.method);
1374 if (prologue != null) {
1375 emitXir(prologue, null, null, null, false);
1376 }
1377 setOperandsForLocals(block.end().stateAfter());
1378 }
1379 }
1380
1381 /**
1382 * Copies a given value into an operand that is forced to be a stack location.
1383 *
1384 * @param value a value to be forced onto the stack
1385 * @param kind the kind of new operand
1386 * @param mustStayOnStack specifies if the new operand must never be allocated to a register
1387 * @return the operand that is guaranteed to be a stack location when it is
1388 * initially defined a by move from {@code value}
1389 */
1390 CiValue forceToSpill(CiValue value, CiKind kind, boolean mustStayOnStack) {
1391 assert value.isLegal() : "value should not be illegal";
1392 assert kind.jvmSlots == value.kind.jvmSlots : "size mismatch";
1393 if (!value.isVariableOrRegister()) {
1394 // force into a variable that must start in memory
1395 CiValue operand = operands.newVariable(value.kind, mustStayOnStack ? VariableFlag.MustStayInMemory : VariableFlag.MustStartInMemory);
1396 lir.move(value, operand);
1397 return operand;
1398 }
1399
1400 // create a spill location
1401 CiValue operand = operands.newVariable(kind, mustStayOnStack ? VariableFlag.MustStayInMemory : VariableFlag.MustStartInMemory);
1402 // move from register to spill
1403 lir.move(value, operand);
1404 return operand;
1405 }
1406
1407 private CiVariable loadConstant(Constant x) {
1408 return loadConstant(x.asConstant(), x.kind);
1409 }
1410
1411 protected CiVariable loadConstant(CiConstant c, CiKind kind) {
1412 // XXX: linear search might be kind of slow for big basic blocks
1413 int index = constants.indexOf(c);
1414 if (index != -1) {
1415 C1XMetrics.LoadConstantIterations += index;
1416 return variablesForConstants.get(index);
1417 }
1418 C1XMetrics.LoadConstantIterations += constants.size();
1419
1420 CiVariable result = newVariable(kind);
1421 lir.move(c, result);
1422 constants.add(c);
1423 variablesForConstants.add(result);
1424 return result;
1425 }
1426
1427 /**
1428 * Allocates a variable operand to hold the result of a given instruction.
1429 * This can only be performed once for any given instruction.
1430 *
1431 * @param x an instruction that produces a result
1432 * @return the variable assigned to hold the result produced by {@code x}
1433 */
1434 protected CiVariable createResultVariable(Value x) {
1435 CiVariable operand = newVariable(x.kind);
1436 setResult(x, operand);
1437 return operand;
1438 }
1439
1440 private void visitFPIntrinsics(Intrinsic x) {
1441 assert x.numberOfArguments() == 1 : "wrong type";
1442 CiValue reg = createResultVariable(x);
1443 CiValue value = load(x.argumentAt(0));
1444 CiValue tmp = forceToSpill(value, x.kind, false);
1445 lir.move(tmp, reg);
1446 }
1447
1448 private void visitRegisterFinalizer(Intrinsic x) {
1449 assert x.numberOfArguments() == 1 : "wrong type";
1450 CiValue receiver = load(x.argumentAt(0));
1451 LIRDebugInfo info = stateFor(x, x.stateBefore());
1452 callRuntime(CiRuntimeCall.RegisterFinalizer, info, receiver);
1453 setNoResult(x);
1454 }
1455
1456 private void visitSwitchRanges(SwitchRange[] x, CiValue value, BlockBegin defaultSux) {
1457 for (int i = 0; i < x.length; i++) {
1458 SwitchRange oneRange = x[i];
1459 int lowKey = oneRange.lowKey;
1460 int highKey = oneRange.highKey;
1461 BlockBegin dest = oneRange.sux;
1462 if (lowKey == highKey) {
1463 lir.cmp(Condition.EQ, value, lowKey);
1464 lir.branch(Condition.EQ, CiKind.Int, dest);
1465 } else if (highKey - lowKey == 1) {
1466 lir.cmp(Condition.EQ, value, lowKey);
1467 lir.branch(Condition.EQ, CiKind.Int, dest);
1468 lir.cmp(Condition.EQ, value, highKey);
1469 lir.branch(Condition.EQ, CiKind.Int, dest);
1470 } else {
1471 Label l = new Label();
1472 lir.cmp(Condition.LT, value, lowKey);
1473 lir.branch(Condition.LT, l);
1474 lir.cmp(Condition.LE, value, highKey);
1475 lir.branch(Condition.LE, CiKind.Int, dest);
1476 lir.branchDestination(l);
1477 }
1478 }
1479 lir.jump(defaultSux);
1480 }
1481
1482 private void visitUnsafePrefetch(UnsafePrefetch x, boolean isStore) {
1483 LIRItem src = new LIRItem(x.object(), this);
1484 LIRItem off = new LIRItem(x.offset(), this);
1485
1486 src.loadItem();
1487 if (!(off.result().isConstant() && canInlineAsConstant(x.offset()))) {
1488 off.loadItem();
1489 }
1490
1491 setNoResult(x);
1492
1493 CiAddress addr = genAddress(src.result(), off.result(), 0, 0, CiKind.Byte);
1494 lir.prefetch(addr, isStore);
1495 }
1496
1497 protected void arithmeticOpFpu(int code, CiValue result, CiValue left, CiValue right, CiValue tmp) {
1498 CiValue leftOp = left;
1499
1500 if (isTwoOperand && leftOp != result) {
1501 assert right != result : "malformed";
1502 lir.move(leftOp, result);
1503 leftOp = result;
1504 }
1505
1506 switch (code) {
1507 case DADD:
1508 case FADD:
1509 lir.add(leftOp, right, result);
1510 break;
1511 case FMUL:
1512 case DMUL:
1513 lir.mul(leftOp, right, result);
1514 break;
1515 case DSUB:
1516 case FSUB:
1517 lir.sub(leftOp, right, result);
1518 break;
1519 case FDIV:
1520 case DDIV:
1521 lir.div(leftOp, right, result, null);
1522 break;
1523 default:
1524 Util.shouldNotReachHere();
1525 }
1526 }
1527
1528 protected void arithmeticOpInt(int code, CiValue result, CiValue left, CiValue right, CiValue tmp) {
1529 CiValue leftOp = left;
1530
1531 if (isTwoOperand && leftOp != result) {
1532 assert right != result : "malformed";
1533 lir.move(leftOp, result);
1534 leftOp = result;
1535 }
1536
1537 switch (code) {
1538 case IADD:
1539 lir.add(leftOp, right, result);
1540 break;
1541 case IMUL:
1542 boolean didStrengthReduce = false;
1543 if (right.isConstant()) {
1544 CiConstant rightConstant = (CiConstant) right;
1545 int c = rightConstant.asInt();
1546 if (CiUtil.isPowerOf2(c)) {
1547 // do not need tmp here
1548 lir.shiftLeft(leftOp, CiUtil.log2(c), result);
1549 didStrengthReduce = true;
1550 } else {
1551 didStrengthReduce = strengthReduceMultiply(leftOp, c, result, tmp);
1552 }
1553 }
1554 // we couldn't strength reduce so just emit the multiply
1555 if (!didStrengthReduce) {
1556 lir.mul(leftOp, right, result);
1557 }
1558 break;
1559 case ISUB:
1560 lir.sub(leftOp, right, result);
1561 break;
1562 default:
1563 // idiv and irem are handled elsewhere
1564 Util.shouldNotReachHere();
1565 }
1566 }
1567
1568 protected void arithmeticOpLong(int code, CiValue result, CiValue left, CiValue right, LIRDebugInfo info) {
1569 CiValue leftOp = left;
1570
1571 if (isTwoOperand && leftOp != result) {
1572 assert right != result : "malformed";
1573 lir.move(leftOp, result);
1574 leftOp = result;
1575 }
1576
1577 switch (code) {
1578 case LADD:
1579 lir.add(leftOp, right, result);
1580 break;
1581 case LMUL:
1582 lir.mul(leftOp, right, result);
1583 break;
1584 case LSUB:
1585 lir.sub(leftOp, right, result);
1586 break;
1587 default:
1588 // ldiv and lrem are handled elsewhere
1589 Util.shouldNotReachHere();
1590 }
1591 }
1592
1593 protected final CiValue callRuntime(CiRuntimeCall runtimeCall, LIRDebugInfo info, CiValue... args) {
1594 // get a result register
1595 CiKind result = runtimeCall.resultKind;
1596 CiKind[] arguments = runtimeCall.arguments;
1597
1598 CiValue physReg = result.isVoid() ? IllegalValue : resultOperandFor(result);
1599
1600 List<CiValue> argumentList;
1601 if (arguments.length > 0) {
1602 // move the arguments into the correct location
1603 CiCallingConvention cc = compilation.frameMap().getCallingConvention(arguments, RuntimeCall);
1604 assert cc.locations.length == args.length : "argument count mismatch";
1605 for (int i = 0; i < args.length; i++) {
1606 CiValue arg = args[i];
1607 CiValue loc = cc.locations[i];
1608 if (loc.isRegister()) {
1609 lir.move(arg, loc);
1610 } else {
1611 assert loc.isStackSlot();
1612 CiStackSlot slot = (CiStackSlot) loc;
1613 if (slot.kind == CiKind.Long || slot.kind == CiKind.Double) {
1614 lir.unalignedMove(arg, slot);
1615 } else {
1616 lir.move(arg, slot);
1617 }
1618 }
1619 }
1620 argumentList = Arrays.asList(cc.locations);
1621 } else {
1622 // no arguments
1623 assert args == null || args.length == 0;
1624 argumentList = Util.uncheckedCast(Collections.emptyList());
1625 }
1626
1627 lir.callRuntime(runtimeCall, physReg, argumentList, info);
1628
1629 return physReg;
1630 }
1631
1632 protected final CiVariable callRuntimeWithResult(CiRuntimeCall runtimeCall, LIRDebugInfo info, CiValue... args) {
1633 CiVariable result = newVariable(runtimeCall.resultKind);
1634 CiValue location = callRuntime(runtimeCall, info, args);
1635 lir.move(location, result);
1636 return result;
1637 }
1638
1639 SwitchRange[] createLookupRanges(LookupSwitch x) {
1640 // we expect the keys to be sorted by increasing value
1641 List<SwitchRange> res = new ArrayList<SwitchRange>(x.numberOfCases());
1642 int len = x.numberOfCases();
1643 if (len > 0) {
1644 BlockBegin defaultSux = x.defaultSuccessor();
1645 int key = x.keyAt(0);
1646 BlockBegin sux = x.suxAt(0);
1647 SwitchRange range = new SwitchRange(key, sux);
1648 for (int i = 1; i < len; i++) {
1649 int newKey = x.keyAt(i);
1650 BlockBegin newSux = x.suxAt(i);
1651 if (key + 1 == newKey && sux == newSux) {
1652 // still in same range
1653 range.highKey = newKey;
1654 } else {
1655 // skip tests which explicitly dispatch to the default
1656 if (range.sux != defaultSux) {
1657 res.add(range);
1658 }
1659 range = new SwitchRange(newKey, newSux);
1660 }
1661 key = newKey;
1662 sux = newSux;
1663 }
1664 if (res.size() == 0 || res.get(res.size() - 1) != range) {
1665 res.add(range);
1666 }
1667 }
1668 return res.toArray(new SwitchRange[res.size()]);
1669 }
1670
1671 SwitchRange[] createLookupRanges(TableSwitch x) {
1672 // XXX: try to merge this with the code for LookupSwitch
1673 List<SwitchRange> res = new ArrayList<SwitchRange>(x.numberOfCases());
1674 int len = x.numberOfCases();
1675 if (len > 0) {
1676 BlockBegin sux = x.suxAt(0);
1677 int key = x.lowKey();
1678 BlockBegin defaultSux = x.defaultSuccessor();
1679 SwitchRange range = new SwitchRange(key, sux);
1680 for (int i = 0; i < len; i++, key++) {
1681 BlockBegin newSux = x.suxAt(i);
1682 if (sux == newSux) {
1683 // still in same range
1684 range.highKey = key;
1685 } else {
1686 // skip tests which explicitly dispatch to the default
1687 if (sux != defaultSux) {
1688 res.add(range);
1689 }
1690 range = new SwitchRange(key, newSux);
1691 }
1692 sux = newSux;
1693 }
1694 if (res.size() == 0 || res.get(res.size() - 1) != range) {
1695 res.add(range);
1696 }
1697 }
1698 return res.toArray(new SwitchRange[res.size()]);
1699 }
1700
1701 void doRoot(Instruction instr) {
1702 currentInstruction = instr;
1703 assert instr.isLive() : "use only with roots";
1704 assert !instr.hasSubst() : "shouldn't have missed substitution";
1705
1706 if (C1XOptions.TraceLIRVisit) {
1707 TTY.println("Visiting " + instr);
1708 }
1709 instr.accept(this);
1710 if (C1XOptions.TraceLIRVisit) {
1711 TTY.println("Operand for " + instr + " = " + instr.operand());
1712 }
1713
1714 assert (instr.operand().isLegal()) || !isUsedForValue(instr) || instr.isConstant() || instr instanceof UnsafeCast : "operand was not set for live instruction";
1715 }
1716
1717 private boolean isUsedForValue(Instruction instr) {
1718 return instr.checkFlag(Value.Flag.LiveValue);
1719 }
1720
1721 protected void logicOp(int code, CiValue resultOp, CiValue leftOp, CiValue rightOp) {
1722 if (isTwoOperand && leftOp != resultOp) {
1723 assert rightOp != resultOp : "malformed";
1724 lir.move(leftOp, resultOp);
1725 leftOp = resultOp;
1726 }
1727
1728 switch (code) {
1729 case IAND:
1730 case LAND:
1731 lir.logicalAnd(leftOp, rightOp, resultOp);
1732 break;
1733
1734 case IOR:
1735 case LOR:
1736 lir.logicalOr(leftOp, rightOp, resultOp);
1737 break;
1738
1739 case IXOR:
1740 case LXOR:
1741 lir.logicalXor(leftOp, rightOp, resultOp);
1742 break;
1743
1744 default:
1745 Util.shouldNotReachHere();
1746 }
1747 }
1748
1749 void moveToPhi(PhiResolver resolver, Value curVal, Value suxVal) {
1750 // move current value to referenced phi function
1751 if (suxVal instanceof Phi) {
1752 Phi phi = (Phi) suxVal;
1753 // curVal can be null without phi being null in conjunction with inlining
1754 if (phi.isLive() && curVal != null && curVal != phi) {
1755 assert curVal.isLive() : "value not live: " + curVal + ", suxVal=" + suxVal;
1756 assert !phi.isIllegal() : "illegal phi cannot be marked as live";
1757 if (curVal instanceof Phi) {
1758 operandForPhi((Phi) curVal);
1759 }
1760 CiValue operand = curVal.operand();
1761 if (operand.isIllegal()) {
1762 assert curVal instanceof Constant || curVal instanceof Local : "these can be produced lazily";
1763 operand = operandForInstruction(curVal);
1764 }
1765 resolver.move(operand, operandForPhi(phi));
1766 }
1767 }
1768 }
1769
1770 protected void moveToPhi(FrameState curState) {
1771 // Moves all stack values into their phi position
1772 BlockBegin bb = currentBlock;
1773 if (bb.numberOfSux() == 1) {
1774 BlockBegin sux = bb.suxAt(0);
1775 assert sux.numberOfPreds() > 0 : "invalid CFG";
1776
1777 // a block with only one predecessor never has phi functions
1778 if (sux.numberOfPreds() > 1) {
1779 PhiResolver resolver = new PhiResolver(this);
1780
1781 FrameState suxState = sux.stateBefore();
1782
1783 for (int index = 0; index < suxState.stackSize(); index++) {
1784 moveToPhi(resolver, curState.stackAt(index), suxState.stackAt(index));
1785 }
1786
1787 // walk up the inlined scopes until locals match
1788 while (curState.scope() != suxState.scope()) {
1789 curState = curState.callerState();
1790 assert curState != null : "scopes don't match up";
1791 }
1792
1793 for (int index = 0; index < suxState.localsSize(); index++) {
1794 moveToPhi(resolver, curState.localAt(index), suxState.localAt(index));
1795 }
1796
1797 assert curState.scope().callerState == suxState.scope().callerState : "caller states must be equal";
1798 resolver.dispose();
1799 }
1800 }
1801 }
1802
1803 /**
1804 * Creates a new {@linkplain CiVariable variable}.
1805 *
1806 * @param kind the kind of the variable
1807 * @return a new variable
1808 */
1809 public CiVariable newVariable(CiKind kind) {
1810 return operands.newVariable(kind);
1811 }
1812
1813 CiValue operandForInstruction(Value x) {
1814 CiValue operand = x.operand();
1815 if (operand.isIllegal()) {
1816 if (x instanceof Constant) {
1817 x.setOperand(x.asConstant());
1818 } else {
1819 assert x instanceof Phi || x instanceof Local : "only for Phi and Local";
1820 // allocate a variable for this local or phi
1821 createResultVariable(x);
1822 }
1823 }
1824 return x.operand();
1825 }
1826
1827 private CiValue operandForPhi(Phi phi) {
1828 if (phi.operand().isIllegal()) {
1829 // allocate a variable for this phi
1830 CiVariable operand = newVariable(phi.kind);
1831 setResult(phi, operand);
1832 }
1833 return phi.operand();
1834 }
1835
1836 protected void postGCWriteBarrier(CiValue addr, CiValue newVal) {
1837 XirSnippet writeBarrier = xir.genWriteBarrier(toXirArgument(addr));
1838 if (writeBarrier != null) {
1839 emitXir(writeBarrier, null, null, null, false);
1840 }
1841 }
1842
1843 protected void preGCWriteBarrier(CiValue addrOpr, boolean patch, LIRDebugInfo info) {
1844 }
1845
1846 protected void setNoResult(Instruction x) {
1847 assert !isUsedForValue(x) : "can't have use";
1848 x.clearOperand();
1849 }
1850
1851 protected CiValue setResult(Value x, CiVariable operand) {
1852 x.setOperand(operand);
1853 if (C1XOptions.DetailedAsserts) {
1854 operands.recordResult(operand, x);
1855 }
1856 return operand;
1857 }
1858
1859 protected void shiftOp(int code, CiValue resultOp, CiValue value, CiValue count, CiValue tmp) {
1860 if (isTwoOperand && value != resultOp) {
1861 assert count != resultOp : "malformed";
1862 lir.move(value, resultOp);
1863 value = resultOp;
1864 }
1865
1866 assert count.isConstant() || count.isVariableOrRegister();
1867 switch (code) {
1868 case ISHL:
1869 case LSHL:
1870 lir.shiftLeft(value, count, resultOp, tmp);
1871 break;
1872 case ISHR:
1873 case LSHR:
1874 lir.shiftRight(value, count, resultOp, tmp);
1875 break;
1876 case IUSHR:
1877 case LUSHR:
1878 lir.unsignedShiftRight(value, count, resultOp, tmp);
1879 break;
1880 default:
1881 Util.shouldNotReachHere();
1882 }
1883 }
1884
1885 protected void walkState(Instruction x, FrameState state) {
1886 if (state == null) {
1887 return;
1888 }
1889 for (int index = 0; index < state.stackSize(); index++) {
1890 walkStateValue(state.stackAt(index));
1891 }
1892 FrameState s = state;
1893 int bci = x.bci();
1894
1895 while (s != null) {
1896 IRScope scope = s.scope();
1897 if (bci == Instruction.SYNCHRONIZATION_ENTRY_BCI) {
1898 assert x instanceof ExceptionObject ||
1899 x instanceof Throw ||
1900 x instanceof MonitorEnter ||
1901 x instanceof MonitorExit;
1902 }
1903
1904 for (int index = 0; index < s.localsSize(); index++) {
1905 final Value value = s.localAt(index);
1906 if (value != null) {
1907 if (!value.isIllegal()) {
1908 walkStateValue(value);
1909 }
1910 }
1911 }
1912 bci = scope.callerBCI();
1913 s = s.callerState();
1914 }
1915 }
1916
1917 private void walkStateValue(Value value) {
1918 if (value != null) {
1919 assert !value.hasSubst() : "missed substitution";
1920 assert value.isLive() : "value must be marked live in frame state";
1921 if (value instanceof Phi && !value.isIllegal()) {
1922 // phi's are special
1923 operandForPhi((Phi) value);
1924 } else if (value.operand().isIllegal() && !(value instanceof UnsafeCast)) {
1925 // instruction doesn't have an operand yet
1926 CiValue operand = makeOperand(value);
1927 assert operand.isLegal() : "must be evaluated now";
1928 }
1929 }
1930 }
1931
1932 protected LIRDebugInfo maybeStateFor(Instruction x) {
1933 FrameState stateBefore = x.stateBefore();
1934 if (stateBefore == null) {
1935 return null;
1936 }
1937 return stateFor(x, stateBefore);
1938 }
1939
1940 protected LIRDebugInfo stateFor(Instruction x) {
1941 assert x.stateBefore() != null : "must have state before instruction for " + x;
1942 return stateFor(x, x.stateBefore());
1943 }
1944
1945 protected LIRDebugInfo stateFor(Instruction x, FrameState state) {
1946 if (compilation.placeholderState != null) {
1947 state = compilation.placeholderState;
1948 }
1949
1950 return new LIRDebugInfo(state, x.exceptionHandlers());
1951 }
1952
1953 List<CiValue> visitInvokeArguments(CiCallingConvention cc, Value[] args, List<CiValue> pointerSlots) {
1954 // for each argument, load it into the correct location
1955 List<CiValue> argList = new ArrayList<CiValue>(args.length);
1956 int j = 0;
1957 for (Value arg : args) {
1958 if (arg != null) {
1959 CiValue operand = cc.locations[j++];
1960 if (operand.isRegister()) {
1961 force(arg, operand);
1962 } else {
1963 LIRItem param = new LIRItem(arg, this);
1964 assert operand.isStackSlot();
1965 CiStackSlot slot = (CiStackSlot) operand;
1966 assert !slot.inCallerFrame();
1967 param.loadForStore(slot.kind);
1968 if (slot.kind == CiKind.Long || slot.kind == CiKind.Double) {
1969 lir.unalignedMove(param.result(), slot);
1970 } else {
1971 lir.move(param.result(), slot);
1972 }
1973
1974 if (arg.kind == CiKind.Object && pointerSlots != null) {
1975 // This slot must be marked explicitedly in the pointer map.
1976 pointerSlots.add(slot);
1977 }
1978 }
1979 argList.add(operand);
1980 }
1981 }
1982 return argList;
1983 }
1984
1985 /**
1986 * Ensures that an operand has been {@linkplain Value#setOperand(CiValue) initialized}
1987 * for storing the result of an instruction.
1988 *
1989 * @param instruction an instruction that produces a result value
1990 */
1991 protected CiValue makeOperand(Value instruction) {
1992 assert instruction.isLive();
1993 CiValue operand = instruction.operand();
1994 if (operand.isIllegal()) {
1995 if (instruction instanceof Phi) {
1996 // a phi may not have an operand yet if it is for an exception block
1997 operand = operandForPhi((Phi) instruction);
1998 } else if (instruction instanceof Constant) {
1999 operand = operandForInstruction(instruction);
2000 }
2001 }
2002 // the value must be a constant or have a valid operand
2003 assert operand.isLegal() : "this root has not been visited yet";
2004 return operand;
2005 }
2006
2007 /**
2008 * Gets the ABI specific operand used to return a value of a given kind from a method.
2009 *
2010 * @param kind the kind of value being returned
2011 * @return the operand representing the ABI defined location used return a value of kind {@code kind}
2012 */
2013 protected CiValue resultOperandFor(CiKind kind) {
2014 if (kind == CiKind.Void) {
2015 return IllegalValue;
2016 }
2017 CiRegister returnRegister = compilation.registerConfig.getReturnRegister(kind);
2018 return returnRegister.asValue(kind);
2019 }
2020
2021 protected XirSupport site(Value x) {
2022 return xirSupport.site(x);
2023 }
2024
2025 public void maybePrintCurrentInstruction() {
2026 if (currentInstruction != null && lastInstructionPrinted != currentInstruction) {
2027 lastInstructionPrinted = currentInstruction;
2028 InstructionPrinter ip = new InstructionPrinter(TTY.out());
2029 ip.printInstructionListing(currentInstruction);
2030 }
2031 }
2032
2033 protected abstract boolean canInlineAsConstant(Value i);
2034
2035 protected abstract boolean canStoreAsConstant(Value i, CiKind kind);
2036
2037 protected abstract CiValue exceptionPcOpr();
2038
2039 protected abstract CiValue osrBufferPointer();
2040
2041 protected abstract boolean strengthReduceMultiply(CiValue left, int constant, CiValue result, CiValue tmp);
2042
2043 protected abstract CiAddress genAddress(CiValue base, CiValue index, int shift, int disp, CiKind kind);
2044
2045 protected abstract void genCmpMemInt(Condition condition, CiValue base, int disp, int c, LIRDebugInfo info);
2046
2047 protected abstract void genCmpRegMem(Condition condition, CiValue reg, CiValue base, int disp, CiKind kind, LIRDebugInfo info);
2048
2049 protected abstract void genGetObjectUnsafe(CiValue dest, CiValue src, CiValue offset, CiKind kind, boolean isVolatile);
2050
2051 protected abstract void genPutObjectUnsafe(CiValue src, CiValue offset, CiValue data, CiKind kind, boolean isVolatile);
2052
2053 protected abstract void genCompareAndSwap(Intrinsic x, CiKind kind);
2054
2055 protected abstract void genMathIntrinsic(Intrinsic x);
2056
2057 /**
2058 * Implements site-specific information for the XIR interface.
2059 */
2060 static class XirSupport implements XirSite {
2061 Value current;
2062
2063 XirSupport() {
2064 }
2065
2066 public CiCodePos getCodePos() {
2067 // TODO: get the code position of the current instruction if possible
2068 return null;
2069 }
2070
2071 public boolean isNonNull(XirArgument argument) {
2072 if (argument.constant == null && argument.object instanceof LIRItem) {
2073 // check the flag on the original value
2074 return ((LIRItem) argument.object).instruction.isNonNull();
2075 }
2076 return false;
2077 }
2078
2079 public boolean requiresNullCheck() {
2080 return current == null || current.needsNullCheck();
2081 }
2082
2083 public boolean requiresBoundsCheck() {
2084 return current == null || !current.checkFlag(Value.Flag.NoBoundsCheck);
2085 }
2086
2087 public boolean requiresReadBarrier() {
2088 return current == null || !current.checkFlag(Value.Flag.NoReadBarrier);
2089 }
2090
2091 public boolean requiresWriteBarrier() {
2092 return current == null || !current.checkFlag(Value.Flag.NoWriteBarrier);
2093 }
2094
2095 public boolean requiresArrayStoreCheck() {
2096 return current == null || !current.checkFlag(Value.Flag.NoStoreCheck);
2097 }
2098
2099 public RiType getApproximateType(XirArgument argument) {
2100 return current == null ? null : current.declaredType();
2101 }
2102
2103 public RiType getExactType(XirArgument argument) {
2104 return current == null ? null : current.exactType();
2105 }
2106
2107 XirSupport site(Value v) {
2108 current = v;
2109 return this;
2110 }
2111
2112 @Override
2113 public String toString() {
2114 return "XirSupport<" + current + ">";
2115 }
2116
2117 }
2118
2119 public void arrayCopy(RiType type, ArrayCopy arrayCopy, XirSnippet snippet) {
2120 emitXir(snippet, arrayCopy, stateFor(arrayCopy), null, false);
2121 }
2122
2123 @Override
2124 public void visitArrayCopy(ArrayCopy arrayCopy) {
2125 Value src = arrayCopy.src();
2126 Value dest = arrayCopy.dest();
2127 Value srcPos = arrayCopy.srcPos();
2128 Value destPos = arrayCopy.destPos();
2129 Value length = arrayCopy.length();
2130 RiType srcType = src.declaredType();
2131 RiType destType = dest.declaredType();
2132 if ((srcType != null && srcType.isArrayClass()) || (destType != null && destType.isArrayClass())) {
2133 RiType type = (srcType == null) ? destType : srcType;
2134 if ((srcType == null || destType == null || srcType.kind() != destType.kind()) && type.kind() != CiKind.Object) {
2135 TypeEqualityCheck typeCheck = new TypeEqualityCheck(src, dest, arrayCopy.stateBefore(), Condition.EQ);
2136 visitTypeEqualityCheck(typeCheck);
2137 }
2138 boolean inputsSame = (src == dest);
2139 boolean inputsDifferent = !inputsSame && (src.checkFlag(Flag.ResultIsUnique) || dest.checkFlag(Flag.ResultIsUnique));
2140 boolean needsStoreCheck = type.componentType().kind() == CiKind.Object && destType != srcType;
2141 if (!needsStoreCheck) {
2142 arrayCopy.setFlag(Flag.NoStoreCheck);
2143 }
2144 XirSnippet snippet = xir.genArrayCopy(site(arrayCopy), toXirArgument(src), toXirArgument(srcPos), toXirArgument(dest), toXirArgument(destPos), toXirArgument(length), type.componentType(), inputsSame, inputsDifferent);
2145 arrayCopy(type, arrayCopy, snippet);
2146 return;
2147 }
2148 arrayCopySlow(arrayCopy);
2149 }
2150
2151 private void arrayCopySlow(ArrayCopy arrayCopy) {
2152 emitInvokeKnown(arrayCopy.arrayCopyMethod, arrayCopy.stateBefore(), arrayCopy.src(), arrayCopy.srcPos(), arrayCopy.dest(), arrayCopy.destPos(), arrayCopy.length());
2153 }
2154
2155 private CiValue emitInvokeKnown(RiMethod method, FrameState stateBefore, Value... args) {
2156 boolean isStatic = Modifier.isStatic(method.accessFlags());
2157 Invoke invoke = new Invoke(isStatic ? Bytecodes.INVOKESTATIC : Bytecodes.INVOKESPECIAL, method.signature().returnKind(), args, isStatic, method, null, stateBefore);
2158 visitInvoke(invoke);
2159 return invoke.operand();
2160 }
2161
2162 @Override
2163 public void visitTypeEqualityCheck(TypeEqualityCheck typeEqualityCheck) {
2164 Value x = typeEqualityCheck.left();
2165 Value y = typeEqualityCheck.right();
2166
2167 CiValue leftValue = emitXir(xir.genGetClass(site(typeEqualityCheck), toXirArgument(x)), typeEqualityCheck, stateFor(typeEqualityCheck), null, false);
2168 CiValue rightValue = emitXir(xir.genGetClass(site(typeEqualityCheck), toXirArgument(y)), typeEqualityCheck, stateFor(typeEqualityCheck), null, false);
2169 lir.cmp(typeEqualityCheck.condition.negate(), leftValue, rightValue);
2170 emitGuard(typeEqualityCheck);
2171 }
2172 }