59 import org.graalvm.compiler.lir.LIRFrameState; |
59 import org.graalvm.compiler.lir.LIRFrameState; |
60 import org.graalvm.compiler.lir.LIRInstruction; |
60 import org.graalvm.compiler.lir.LIRInstruction; |
61 import org.graalvm.compiler.lir.LIRInstruction.OperandFlag; |
61 import org.graalvm.compiler.lir.LIRInstruction.OperandFlag; |
62 import org.graalvm.compiler.lir.LIRInstruction.OperandMode; |
62 import org.graalvm.compiler.lir.LIRInstruction.OperandMode; |
63 import org.graalvm.compiler.lir.StandardOp.LabelOp; |
63 import org.graalvm.compiler.lir.StandardOp.LabelOp; |
|
64 import org.graalvm.compiler.lir.StandardOp.RestoreRegistersOp; |
64 import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; |
65 import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; |
65 import org.graalvm.compiler.lir.ValueConsumer; |
66 import org.graalvm.compiler.lir.ValueConsumer; |
66 import org.graalvm.compiler.lir.asm.CompilationResultBuilder; |
67 import org.graalvm.compiler.lir.asm.CompilationResultBuilder; |
67 import org.graalvm.compiler.lir.framemap.FrameMap; |
68 import org.graalvm.compiler.lir.framemap.FrameMap; |
68 import org.graalvm.compiler.nodes.UnwindNode; |
69 import org.graalvm.compiler.nodes.UnwindNode; |
74 import org.graalvm.compiler.phases.tiers.SuitesProvider; |
75 import org.graalvm.compiler.phases.tiers.SuitesProvider; |
75 import org.graalvm.compiler.serviceprovider.JavaVersionUtil; |
76 import org.graalvm.compiler.serviceprovider.JavaVersionUtil; |
76 import org.graalvm.compiler.word.Word; |
77 import org.graalvm.compiler.word.Word; |
77 import jdk.internal.vm.compiler.word.Pointer; |
78 import jdk.internal.vm.compiler.word.Pointer; |
78 |
79 |
|
80 import jdk.vm.ci.code.CallingConvention; |
79 import jdk.vm.ci.code.CompilationRequest; |
81 import jdk.vm.ci.code.CompilationRequest; |
80 import jdk.vm.ci.code.CompiledCode; |
82 import jdk.vm.ci.code.CompiledCode; |
81 import jdk.vm.ci.code.Register; |
83 import jdk.vm.ci.code.Register; |
82 import jdk.vm.ci.code.RegisterSaveLayout; |
|
83 import jdk.vm.ci.code.StackSlot; |
84 import jdk.vm.ci.code.StackSlot; |
84 import jdk.vm.ci.code.ValueUtil; |
85 import jdk.vm.ci.code.ValueUtil; |
85 import jdk.vm.ci.hotspot.HotSpotCompilationRequest; |
86 import jdk.vm.ci.hotspot.HotSpotCompilationRequest; |
86 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; |
87 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; |
87 import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; |
88 import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; |
|
89 import jdk.vm.ci.meta.AllocatableValue; |
88 import jdk.vm.ci.meta.ResolvedJavaMethod; |
90 import jdk.vm.ci.meta.ResolvedJavaMethod; |
89 import jdk.vm.ci.meta.Value; |
91 import jdk.vm.ci.meta.Value; |
90 import jdk.vm.ci.runtime.JVMCICompiler; |
92 import jdk.vm.ci.runtime.JVMCICompiler; |
91 |
93 |
92 /** |
94 /** |
95 public abstract class HotSpotBackend extends Backend implements FrameMap.ReferenceMapBuilderFactory { |
97 public abstract class HotSpotBackend extends Backend implements FrameMap.ReferenceMapBuilderFactory { |
96 |
98 |
97 public static class Options { |
99 public static class Options { |
98 // @formatter:off |
100 // @formatter:off |
99 @Option(help = "Use Graal arithmetic stubs instead of HotSpot stubs where possible") |
101 @Option(help = "Use Graal arithmetic stubs instead of HotSpot stubs where possible") |
100 public static final OptionKey<Boolean> GraalArithmeticStubs = new OptionKey<>(JavaVersionUtil.JAVA_SPECIFICATION_VERSION >= 9); |
102 public static final OptionKey<Boolean> GraalArithmeticStubs = new OptionKey<>(JavaVersionUtil.JAVA_SPEC >= 9); |
101 @Option(help = "Enables instruction profiling on assembler level. Valid values are a comma separated list of supported instructions." + |
103 @Option(help = "Enables instruction profiling on assembler level. Valid values are a comma separated list of supported instructions." + |
102 " Compare with subclasses of Assembler.InstructionCounter.", type = OptionType.Debug) |
104 " Compare with subclasses of Assembler.InstructionCounter.", type = OptionType.Debug) |
103 public static final OptionKey<String> ASMInstructionProfiling = new OptionKey<>(null); |
105 public static final OptionKey<String> ASMInstructionProfiling = new OptionKey<>(null); |
104 // @formatter:on |
106 // @formatter:on |
105 } |
107 } |
423 } |
425 } |
424 |
426 |
425 /** |
427 /** |
426 * Finds all the registers that are defined by some given LIR. |
428 * Finds all the registers that are defined by some given LIR. |
427 * |
429 * |
428 * @param lir the LIR to examine |
430 * @param gen the result to examine |
429 * @return the registers that are defined by or used as temps for any instruction in {@code lir} |
431 * @return the registers that are defined by or used as temps for any instruction in {@code lir} |
430 */ |
432 */ |
431 protected final EconomicSet<Register> gatherDestroyedCallerRegisters(LIR lir) { |
433 private EconomicSet<Register> gatherDestroyedCallerRegisters(HotSpotLIRGenerationResult gen) { |
|
434 LIR lir = gen.getLIR(); |
|
435 final EconomicSet<Register> preservedRegisters = EconomicSet.create(Equivalence.IDENTITY); |
432 final EconomicSet<Register> destroyedRegisters = EconomicSet.create(Equivalence.IDENTITY); |
436 final EconomicSet<Register> destroyedRegisters = EconomicSet.create(Equivalence.IDENTITY); |
433 ValueConsumer defConsumer = new ValueConsumer() { |
437 ValueConsumer defConsumer = new ValueConsumer() { |
434 |
438 |
435 @Override |
439 @Override |
436 public void visitValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) { |
440 public void visitValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) { |
437 if (ValueUtil.isRegister(value)) { |
441 if (ValueUtil.isRegister(value)) { |
438 final Register reg = ValueUtil.asRegister(value); |
442 final Register reg = ValueUtil.asRegister(value); |
439 destroyedRegisters.add(reg); |
443 if (!preservedRegisters.contains(reg)) { |
|
444 destroyedRegisters.add(reg); |
|
445 } |
440 } |
446 } |
441 } |
447 } |
442 }; |
448 }; |
|
449 boolean sawSaveRegisters = false; |
443 for (AbstractBlockBase<?> block : lir.codeEmittingOrder()) { |
450 for (AbstractBlockBase<?> block : lir.codeEmittingOrder()) { |
444 if (block == null) { |
451 if (block == null) { |
445 continue; |
452 continue; |
446 } |
453 } |
|
454 // Ignore the effects of instructions bracketed by save/restore |
|
455 SaveRegistersOp save = null; |
447 for (LIRInstruction op : lir.getLIRforBlock(block)) { |
456 for (LIRInstruction op : lir.getLIRforBlock(block)) { |
448 if (op instanceof LabelOp) { |
457 if (op instanceof LabelOp) { |
449 // Don't consider this as a definition |
458 // Don't consider this as a definition |
|
459 } else if (op instanceof SaveRegistersOp) { |
|
460 save = (SaveRegistersOp) op; |
|
461 sawSaveRegisters = true; |
|
462 preservedRegisters.addAll(save.getSaveableRegisters()); |
|
463 } else if (op instanceof RestoreRegistersOp) { |
|
464 save = null; |
|
465 preservedRegisters.clear(); |
450 } else { |
466 } else { |
451 op.visitEachTemp(defConsumer); |
467 op.visitEachTemp(defConsumer); |
452 op.visitEachOutput(defConsumer); |
468 op.visitEachOutput(defConsumer); |
453 } |
469 } |
454 } |
470 } |
|
471 assert save == null : "missing RestoreRegistersOp"; |
|
472 } |
|
473 |
|
474 if (sawSaveRegisters) { |
|
475 // The return value must be killed so it can be propagated out |
|
476 CallingConvention cc = gen.getCallingConvention(); |
|
477 AllocatableValue returnValue = cc.getReturn(); |
|
478 if (returnValue != null) { |
|
479 if (ValueUtil.isRegister(returnValue)) { |
|
480 destroyedRegisters.add(ValueUtil.asRegister(returnValue)); |
|
481 } |
|
482 } |
455 } |
483 } |
456 return translateToCallerRegisters(destroyedRegisters); |
484 return translateToCallerRegisters(destroyedRegisters); |
457 } |
485 } |
458 |
486 |
459 /** |
487 /** |
462 * register windows on SPARC). Registers which are not visible by the caller are removed. |
490 * register windows on SPARC). Registers which are not visible by the caller are removed. |
463 */ |
491 */ |
464 protected abstract EconomicSet<Register> translateToCallerRegisters(EconomicSet<Register> calleeRegisters); |
492 protected abstract EconomicSet<Register> translateToCallerRegisters(EconomicSet<Register> calleeRegisters); |
465 |
493 |
466 /** |
494 /** |
467 * Updates a given stub with respect to the registers it destroys. |
495 * Updates a given stub with respect to the registers it destroys by |
468 * <p> |
496 * {@link #gatherDestroyedCallerRegisters(HotSpotLIRGenerationResult) computing the destroyed |
469 * Any entry in {@code calleeSaveInfo} that {@linkplain SaveRegistersOp#supportsRemove() |
497 * registers} and removing those registers from the {@linkplain SaveRegistersOp SaveRegistersOp} |
470 * supports} pruning will have {@code destroyedRegisters} |
498 * as these registers are declared as temporaries in the stub's {@linkplain ForeignCallLinkage |
471 * {@linkplain SaveRegistersOp#remove(EconomicSet) removed} as these registers are declared as |
499 * linkage} (and thus will be saved by the stub's caller). |
472 * temporaries in the stub's {@linkplain ForeignCallLinkage linkage} (and thus will be saved by |
|
473 * the stub's caller). |
|
474 * |
500 * |
475 * @param stub the stub to update |
501 * @param stub the stub to update |
476 * @param destroyedRegisters the registers destroyed by the stub |
502 * @param gen the HotSpotLIRGenerationResult being emitted |
477 * @param calleeSaveInfo a map from debug infos to the operations that provide their |
|
478 * {@linkplain RegisterSaveLayout callee-save information} |
|
479 * @param frameMap used to {@linkplain FrameMap#offsetForStackSlot(StackSlot) convert} a virtual |
503 * @param frameMap used to {@linkplain FrameMap#offsetForStackSlot(StackSlot) convert} a virtual |
480 * slot to a frame slot index |
504 */ |
481 */ |
505 protected void updateStub(Stub stub, HotSpotLIRGenerationResult gen, FrameMap frameMap) { |
482 protected void updateStub(Stub stub, EconomicSet<Register> destroyedRegisters, EconomicMap<LIRFrameState, SaveRegistersOp> calleeSaveInfo, FrameMap frameMap) { |
506 EconomicSet<Register> destroyedRegisters = gatherDestroyedCallerRegisters(gen); |
|
507 EconomicMap<LIRFrameState, SaveRegistersOp> calleeSaveInfo = gen.getCalleeSaveInfo(); |
|
508 |
|
509 if (stub.getLinkage().needsDebugInfo() && calleeSaveInfo.isEmpty()) { |
|
510 // This call is a safepoint but no register saving was done so we must ensure that all |
|
511 // registers appear to be killed. The Native ABI may allow caller save registers but |
|
512 // for HotSpot they must be described in a RegisterMap so they are accessible. |
|
513 for (Register r : frameMap.getRegisterConfig().getCallerSaveRegisters()) { |
|
514 destroyedRegisters.add(r); |
|
515 } |
|
516 } |
|
517 |
483 stub.initDestroyedCallerRegisters(destroyedRegisters); |
518 stub.initDestroyedCallerRegisters(destroyedRegisters); |
484 |
519 |
485 MapCursor<LIRFrameState, SaveRegistersOp> cursor = calleeSaveInfo.getEntries(); |
520 MapCursor<LIRFrameState, SaveRegistersOp> cursor = calleeSaveInfo.getEntries(); |
486 while (cursor.advance()) { |
521 while (cursor.advance()) { |
487 SaveRegistersOp save = cursor.getValue(); |
522 SaveRegistersOp save = cursor.getValue(); |
488 if (save.supportsRemove()) { |
523 save.remove(destroyedRegisters); |
489 save.remove(destroyedRegisters); |
|
490 } |
|
491 if (cursor.getKey() != LIRFrameState.NO_STATE) { |
524 if (cursor.getKey() != LIRFrameState.NO_STATE) { |
492 cursor.getKey().debugInfo().setCalleeSaveInfo(save.getMap(frameMap)); |
525 cursor.getKey().debugInfo().setCalleeSaveInfo(save.getMap(frameMap)); |
493 } |
526 } |
494 } |
527 } |
495 } |
528 } |