Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion compiler/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@

This changelog summarizes newly introduced optimizations and other compiler related changes.

## GraalVM 25.3 (Internal Version 25.3.4.1)
## GraalVM 25.4 (Internal Version 25.4.4.1.1)
* (GR-79029): Add `PullThroughPhiPhase` and `DuplicationPhase` to the community compiler configuration.
The optimizations are enabled by default and can be disabled with `-Djdk.graal.OptPullThroughPhi=false` and
`-Djdk.graal.OptDuplication=false`, respectively.
* (GR-78795): Extended `OptimizeDivPhase` with magic-number optimizations for unsigned integer division
and remainder operations by constant values.

## GraalVM 25.3 (Internal Version 25.3.4.1)
* (GR-77137) Add new priority inlining algorithm that does extensive analysis of the call graph when making
inlining decisions (see `PriorityInliningPhase` for details). It is now the default inliner. To use the old
inliner now requires setting the `UsePriorityInlining` option to false (e.g. `-Djdk.graal.UsePriorityInlining=false`).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,19 @@
*/
package jdk.graal.compiler.duplication.test;

import org.junit.Assert;
import org.junit.Test;

import jdk.graal.compiler.core.common.GraalOptions;
import jdk.graal.compiler.core.phases.HighTier;
import jdk.graal.compiler.core.test.GraalCompilerTest;
import jdk.graal.compiler.duplication.phases.PullThroughPhiPhase;
import jdk.graal.compiler.duplication.phases.simulation.DuplicationOptions;
import jdk.graal.compiler.duplication.phases.simulation.DuplicationPhase;
import jdk.graal.compiler.duplication.phases.simulation.FixedDuplicationSimulationConfig;
import jdk.graal.compiler.nodes.StructuredGraph;
import jdk.graal.compiler.nodes.StructuredGraph.AllowAssumptions;
import jdk.graal.compiler.options.OptionValues;
import jdk.graal.compiler.phases.common.CanonicalizerPhase;
import jdk.graal.compiler.phases.common.DisableOverflownCountedLoopsPhase;
import jdk.graal.compiler.virtual.phases.ea.PartialEscapePhase;
Expand All @@ -41,6 +45,16 @@ public class DuplicationPhiCreationTest extends GraalCompilerTest {

public static Object field;

@Test
public void testCommunityPhasePlan() {
OptionValues enabled = getInitialOptions();
// Community compilation runs duplication by default.
Assert.assertNotNull(new HighTier(enabled).findPhase(DuplicationPhase.class));

OptionValues disabled = new OptionValues(enabled, GraalOptions.OptDuplication, false);
Assert.assertNull(new HighTier(disabled).findPhase(DuplicationPhase.class));
}

static final class A {
int a;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,36 @@

import static jdk.graal.compiler.api.directives.GraalDirectives.injectBranchProbability;

import org.junit.Assert;
import org.junit.Test;

import jdk.graal.compiler.api.directives.GraalDirectives;
import jdk.graal.compiler.core.phases.HighTier;
import jdk.graal.compiler.core.phases.MidTier;
import jdk.graal.compiler.core.test.GraalCompilerTest;
import jdk.graal.compiler.duplication.phases.PullThroughPhiPhase;
import jdk.graal.compiler.nodes.StructuredGraph;
import jdk.graal.compiler.nodes.StructuredGraph.AllowAssumptions;
import jdk.graal.compiler.options.OptionValues;
import jdk.graal.compiler.phases.common.CanonicalizerPhase;
import jdk.graal.compiler.phases.tiers.HighTierContext;
import jdk.graal.compiler.phases.util.GraphOrder;

public class PullThroughPhiTest extends GraalCompilerTest {
public static Object field;

@Test
public void testCommunityPhasePlan() {
OptionValues enabled = getInitialOptions();
// Community compilation runs the optimization in both tiers by default.
Assert.assertNotNull(new HighTier(enabled).findPhase(PullThroughPhiPhase.class));
Assert.assertNotNull(new MidTier(enabled).findPhase(PullThroughPhiPhase.class));

OptionValues disabled = new OptionValues(enabled, PullThroughPhiPhase.Options.OptPullThroughPhi, false);
Assert.assertNull(new HighTier(disabled).findPhase(PullThroughPhiPhase.class));
Assert.assertNull(new MidTier(disabled).findPhase(PullThroughPhiPhase.class));
}

public static int s01(int a, int b, int c) {
int phi1 = 0;
int phi2 = 0;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -88,6 +88,10 @@ public final class GraalOptions {
@Option(help = "Performs partial escape analysis and scalar replacement optimization.", type = OptionType.Expert)
public static final OptionKey<Boolean> PartialEscapeAnalysis = new OptionKey<>(true);

@Option(help = "Performs statement level code duplication at control flow merges to " +
"specialize code to branch values where possible.", type = OptionType.Expert)
public static final OptionKey<Boolean> OptDuplication = new OptionKey<>(true);

@Option(help = "", type = OptionType.Debug)
public static final OptionKey<Integer> EscapeAnalysisIterations = new OptionKey<>(2);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
package jdk.graal.compiler.core.phases;

import jdk.graal.compiler.core.common.GraalOptions;
import jdk.graal.compiler.duplication.phases.PullThroughPhiPhase;
import jdk.graal.compiler.duplication.phases.simulation.DuplicationPhase;
import jdk.graal.compiler.graph.Node.ValueNumberable;
import jdk.graal.compiler.guards.optimistic.memory.OptimisticAliasingAnalysisPhase;
import jdk.graal.compiler.loop.phases.ConvertDeoptimizeToGuardPhase;
Expand Down Expand Up @@ -108,6 +110,20 @@ public enum CEOptimization {
/// inlining is disabled. Inlining as a whole can be disabled with [HighTier.Options#Inline].
Inlining(HighTier.Options.Inline, InliningPhase.class),

/// [PullThroughPhiPhase] heuristically duplicates floating operations at control flow merges.
/// The duplicated operations can then be specialized based on the types and values of the
/// preceding branches.
///
/// This phase is enabled by default and can be disabled with
/// [PullThroughPhiPhase.Options#OptPullThroughPhi].
PullThroughPhi(PullThroughPhiPhase.Options.OptPullThroughPhi, PullThroughPhiPhase.class),

/// [DuplicationPhase] uses simulation to evaluate the optimization effects of tail
/// duplication while balancing the expected performance benefit against the code size cost.
///
/// This phase is enabled by default and can be disabled with [GraalOptions#OptDuplication].
Duplication(GraalOptions.OptDuplication, DuplicationPhase.class),

/**
* {@link DeadCodeEliminationPhase} tries to remove unused (i.e., "dead") code from a program.
* Program code is considered dead if it is proven to be never executed at runtime. This often
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,32 @@
*/
package jdk.graal.compiler.core.phases;

import static jdk.graal.compiler.duplication.phases.simulation.DuplicationOptions.EarlySimulationDepth;
import static jdk.graal.compiler.duplication.phases.simulation.DuplicationPhase.FACTORS_INCLUDING_PEA;
import static jdk.graal.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Optional;

import java.util.ListIterator;
import java.util.function.Consumer;

import jdk.graal.compiler.core.common.GraalOptions;
import jdk.graal.compiler.core.common.NativeImageSupport;
import jdk.graal.compiler.duplication.phases.MethodDuplicationPhase;
import jdk.graal.compiler.duplication.phases.PullThroughPhiPhase;
import jdk.graal.compiler.duplication.phases.simulation.DuplicationPhase;
import jdk.graal.compiler.duplication.phases.simulation.FixedDuplicationSimulationConfig;
import jdk.graal.compiler.loop.phases.ConvertDeoptimizeToGuardPhase;
import jdk.graal.compiler.loop.phases.LoopFullUnrollPhase;
import jdk.graal.compiler.loop.phases.LoopPeelingPhase;
import jdk.graal.compiler.loop.phases.LoopUnswitchingPhase;
import jdk.graal.compiler.nodes.loop.DefaultLoopPolicies;
import jdk.graal.compiler.nodes.loop.LoopPolicies;
import jdk.graal.compiler.nodes.spi.CoreProviders;
import jdk.graal.compiler.options.Option;
import jdk.graal.compiler.options.OptionKey;
import jdk.graal.compiler.options.OptionType;
import jdk.graal.compiler.options.OptionValues;
import jdk.graal.compiler.phases.BasePhase;
import jdk.graal.compiler.phases.PhaseSuite;
import jdk.graal.compiler.phases.common.BoxNodeIdentityPhase;
import jdk.graal.compiler.phases.common.BoxNodeOptimizationPhase;
import jdk.graal.compiler.phases.common.CanonicalizerPhase;
Expand Down Expand Up @@ -127,8 +138,11 @@ public HighTier(OptionValues options) {
appendPhase(new BoxNodeIdentityPhase());
}

this.<HighTierContext> appendControlFlowDuplicationPhases(this::appendPhase, options, canonicalizer);

if (GraalOptions.PartialEscapeAnalysis.getValue(options)) {
appendPhase(new FinalPartialEscapePhase(true, canonicalizer, null, options));
PhaseSuite<CoreProviders> cleanup = createFinalPEACleanup(options, canonicalizer);
appendPhase(new FinalPartialEscapePhase(true, canonicalizer, cleanup, options));
}

if (VectorAPIIntrinsics.intrinsificationSupported(options)) {
Expand All @@ -143,6 +157,54 @@ public HighTier(OptionValues options) {
appendPhase(new HighTierLoweringPhase(canonicalizer));
}

/// Determines whether at least one control flow duplication phase is enabled in `options`.
protected static boolean isControlFlowDuplicationEnabled(OptionValues options) {
return PullThroughPhiPhase.Options.OptPullThroughPhi.getValue(options) || GraalOptions.OptDuplication.getValue(options);
}

/// Adds the enabled control flow duplication phases through `phaseConsumer`.
protected final <C extends CoreProviders> void appendControlFlowDuplicationPhases(Consumer<BasePhase<? super C>> phaseConsumer, OptionValues options,
CanonicalizerPhase canonicalizer) {
if (PullThroughPhiPhase.Options.OptPullThroughPhi.getValue(options)) {
phaseConsumer.accept(new PullThroughPhiPhase(canonicalizer));
}
if (GraalOptions.OptDuplication.getValue(options)) {
// Dead code elimination reduces the graph considered by duplication simulation.
phaseConsumer.accept(new DeadCodeEliminationPhase());
phaseConsumer.accept(new DuplicationPhase(FixedDuplicationSimulationConfig.defaultForDepth(EarlySimulationDepth), true, true,
FACTORS_INCLUDING_PEA, canonicalizer, getDuplicationVectorizationCheck(), options));
}
}

/// Removes the top-level control flow duplication phases so a subclass can reposition them.
protected final void removeControlFlowDuplicationPhases() {
removePhase(PullThroughPhiPhase.class);
ListIterator<BasePhase<? super HighTierContext>> duplicationPosition = findPhase(DuplicationPhase.class);
if (duplicationPosition != null) {
duplicationPosition.previous();
duplicationPosition.remove();
BasePhase<? super HighTierContext> precedingPhase = duplicationPosition.previous();
assert precedingPhase instanceof DeadCodeEliminationPhase : precedingPhase;
duplicationPosition.remove();
}
}

/// Creates the control flow duplication phases that clean up and iteratively expose escape
/// analysis opportunities.
protected final PhaseSuite<CoreProviders> createFinalPEACleanup(OptionValues options, CanonicalizerPhase canonicalizer) {
if (!isControlFlowDuplicationEnabled(options)) {
return null;
}
PhaseSuite<CoreProviders> cleanup = new PhaseSuite<>();
this.<CoreProviders> appendControlFlowDuplicationPhases(cleanup::appendPhase, options, canonicalizer);
return cleanup;
}

/// Gets the policy used to prevent duplication from harming later vectorization.
protected DuplicationPhase.VectorizationCheck getDuplicationVectorizationCheck() {
return (loop, graph, providers) -> false;
}

@Override
public LoopPolicies createLoopPolicies(OptionValues options) {
return new DefaultLoopPolicies();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand All @@ -26,6 +26,7 @@

import jdk.graal.compiler.core.common.GraalOptions;
import jdk.graal.compiler.core.common.SpectrePHTMitigations;
import jdk.graal.compiler.duplication.phases.PullThroughPhiPhase;
import jdk.graal.compiler.loop.phases.LoopFullUnrollPhase;
import jdk.graal.compiler.loop.phases.LoopPartialUnrollPhase;
import jdk.graal.compiler.loop.phases.LoopPredicationPhase;
Expand Down Expand Up @@ -134,6 +135,10 @@ public MidTier(OptionValues options) {

appendPhase(new FrameStateAssignmentPhase());

if (PullThroughPhiPhase.Options.OptPullThroughPhi.getValue(options)) {
appendPhase(new PullThroughPhiPhase(canonicalizer));
}

if (VectorIntrinsics.Options.Vectorization.getValue(options)) {
appendPhase(new NodeVectorizationPhase(canonicalizer));
if (ConditionalMoveOptimizationPhase.Options.OptConditionalMoves.getValue(options)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ public class PullThroughPhiPhase extends BasePhase<CoreProviders> {

public static class Options {
// @formatter:off
@Option(help = "Performs expression level code duplication at control flow merges to specialize " +
"code to branch values where possible.")
public static final OptionKey<Boolean> OptPullThroughPhi = new OptionKey<>(true);
@Option(help = "PullThroughPhiOptimization: Enable floating node duplication over multiple phi nodes at once.", type = OptionType.Debug)
public static final OptionKey<Boolean> TryExplodeOverPhis = new OptionKey<>(true);
@Option(help = "PullThroughPhiOptimization: Enable floating node duplication over phis where the target node has different phis as input.", type = OptionType.Debug)
Expand All @@ -139,7 +142,7 @@ public static class Options {
public static final OptionKey<Double> PullThroughPhiCodeSizeIncrease = new OptionKey<>(0.1/*== 10% of the initial graph size*/);
@Option(help = "See PullThroughPhiCodeSizeIncrease", type = OptionType.Debug)
public static final OptionKey<Double> PullThroughPhiCodeSizeIncreaseHotCode = new OptionKey<>(2.5/*== 250% of the initial graph size*/);
@Option(help = "PullThroughPhiOptimization: Cost/Benefit heuristic for EE floating node duplication: " +
@Option(help = "PullThroughPhiOptimization: Cost/Benefit heuristic for floating node duplication: " +
"reduces cost by a constant factor when comparing with relative benefit.", type = OptionType.Debug)
public static final OptionKey<Double> CostReductionFactor = new OptionKey<>(32D);
@Option(help = "See CostReductionFactor.", type = OptionType.Debug)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public class DuplicationOptions {
@Option(help = "Ignores low frequency branches during simulation.", type = Debug)
public static final OptionKey<Boolean> SimulationPruneUnlikelyBranches = new OptionKey<>(true);

@Option(help = "Cost/Benefit heuristic for EE simulation-based code duplication: reduce cost by a constant factor when comparing with relative benefit.", type = Debug)
@Option(help = "Cost/Benefit heuristic for simulation-based code duplication: reduce cost by a constant factor when comparing with relative benefit.", type = Debug)
public static final OptionKey<Integer> DuplicationCostReductionFactor = new OptionKey<>(64);

@Option(help = "See DuplicationCostReductionFactor", type = Debug)
Expand Down
4 changes: 2 additions & 2 deletions docs/reference-manual/java/Options.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ To see the available configurations, supply the value `help` to this option.
### Performance Tuning Options

* `-Djdk.graal.Vectorization={ true | false }`: To disable the auto vectorization optimization (only available in Oracle GraalVM). (Default: `true`.)
* `-Djdk.graal.OptDuplication={ true | false }`: To disable the [path duplication optimization](http://ssw.jku.at/General/Staff/Leopoldseder/DBDS_CGO18_Preprint.pdf){:target="_blank"} (only available in Oracle GraalVM). (Default: `true`.)
* `-Djdk.graal.OptDuplication={ true | false }`: To disable the [path duplication optimization](http://ssw.jku.at/General/Staff/Leopoldseder/DBDS_CGO18_Preprint.pdf){:target="_blank"}. (Default: `true`.)
* `-Djdk.graal.TuneInlinerExploration=<value>`: To tune for better peak performance or faster warmup.
It automatically adjusts values governing the effort spent during inlining. The value of the option is a float clamped between `-1` and `1` inclusive. Anything below `0` reduces inlining effort and anything above `0` increases inlining effort. In general, peak performance is improved with more inlining effort while less inlining effort improves warmup (albeit to a lower peak). Note that this option is only a heuristic and the optimal value can differ from application to application (only available in Oracle GraalVM).

Expand Down Expand Up @@ -99,4 +99,4 @@ js --vm.Djdk.graal.ShowConfiguration=info -version
### Related Documentation

- [Graal Compiler](compiler.md)
- [Graal JIT Compiler Operations Manual](Operations.md)
- [Graal JIT Compiler Operations Manual](Operations.md)
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@
import com.oracle.svm.core.genscavenge.remset.FirstObjectTable;
import com.oracle.svm.core.genscavenge.remset.RememberedSet;
import com.oracle.svm.core.heap.ObjectVisitor;
import com.oracle.svm.guest.staging.core.heap.RestrictHeapAccess;
import com.oracle.svm.core.heap.UninterruptibleObjectReferenceVisitor;
import com.oracle.svm.core.heap.UninterruptibleObjectVisitor;
import com.oracle.svm.core.hub.DynamicHub;
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
import com.oracle.svm.guest.staging.jdk.RuntimeSupport;
import com.oracle.svm.guest.staging.log.Log;
import com.oracle.svm.core.metaspace.Metaspace;
import com.oracle.svm.core.thread.VMOperation;
import com.oracle.svm.guest.staging.core.heap.RestrictHeapAccess;
import com.oracle.svm.guest.staging.jdk.RuntimeSupport;
import com.oracle.svm.guest.staging.log.Log;
import com.oracle.svm.shared.Uninterruptible;
import com.oracle.svm.shared.singletons.traits.BuiltinTraits.AllAccess;
import com.oracle.svm.shared.singletons.traits.BuiltinTraits.DisallowLayered;
Expand Down Expand Up @@ -95,7 +95,7 @@ public static int getAge() {
@Override
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
public boolean isInAllocatedMemory(Object obj) {
return isInAllocatedMemory(Word.objectToTrackedPointer(obj));
return isInAllocatedMemory(Word.objectToUntrackedPointer(obj));
}

@Override
Expand All @@ -107,7 +107,7 @@ public boolean isInAllocatedMemory(Pointer ptr) {
@Override
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
public boolean isInAddressSpace(Object obj) {
return isInAddressSpace(Word.objectToTrackedPointer(obj));
return isInAddressSpace(Word.objectToUntrackedPointer(obj));
}

@Override
Expand Down
Loading