Skip to content

Commit

Permalink
[GR-49684] Improve canonicalization of InstanceOfNode
Browse files Browse the repository at this point in the history
PullRequest: graal/15895
  • Loading branch information
c-refice committed Oct 31, 2023
2 parents 9e8106b + 65977d2 commit 9fb0c04
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 19 deletions.
12 changes: 6 additions & 6 deletions compiler/mx.compiler/mx_compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -566,14 +566,14 @@ def compiler_gate_benchmark_runner(tasks, extraVMarguments=None, prefix='', task
if t:
for name in dacapo_suite.benchmarkList(bmSuiteArgs):
iterations = int(dacapo_suite.daCapoIterations().get(name, -1) * default_iterations_reduction)
for i in range(default_iterations * scala_daily_scaling_factor):
for _ in range(default_iterations * scala_daily_scaling_factor):
_gate_dacapo(name, iterations, benchVmArgs + ['-Dgraal.TrackNodeSourcePosition=true'] + dacapo_esa)

with mx_gate.Task('Dacapo benchmark weekly workload', tasks, tags=['dacapo_weekly'], report=task_report_component) as t:
if t:
for name in dacapo_suite.benchmarkList(bmSuiteArgs):
iterations = int(dacapo_suite.daCapoIterations().get(name, -1) * default_iterations_reduction)
for i in range(default_iterations * scala_weekly_scaling_factor):
for _ in range(default_iterations * scala_weekly_scaling_factor):
_gate_dacapo(name, iterations, benchVmArgs + ['-Dgraal.TrackNodeSourcePosition=true'] + dacapo_esa)

# ensure we can also run on C2
Expand Down Expand Up @@ -603,14 +603,14 @@ def compiler_gate_benchmark_runner(tasks, extraVMarguments=None, prefix='', task
if t:
for name in scala_dacapo_suite.benchmarkList(bmSuiteArgs):
iterations = int(scala_dacapo_suite.daCapoIterations().get(name, -1) * default_iterations_reduction)
for i in range(default_iterations * scala_dacapo_daily_scaling_factor):
for _ in range(default_iterations * scala_dacapo_daily_scaling_factor):
_gate_scala_dacapo(name, iterations, benchVmArgs + ['-Dgraal.TrackNodeSourcePosition=true'] + dacapo_esa)

with mx_gate.Task('ScalaDacapo benchmark weekly workload', tasks, tags=['scala_dacapo_weekly'], report=task_report_component) as t:
if t:
for name in scala_dacapo_suite.benchmarkList(bmSuiteArgs):
iterations = int(scala_dacapo_suite.daCapoIterations().get(name, -1) * default_iterations_reduction)
for i in range(default_iterations * scala_dacapo_weekly_scaling_factor):
for _ in range(default_iterations * scala_dacapo_weekly_scaling_factor):
_gate_scala_dacapo(name, iterations, benchVmArgs + ['-Dgraal.TrackNodeSourcePosition=true'] + dacapo_esa)

# run Renaissance benchmarks #
Expand All @@ -630,14 +630,14 @@ def compiler_gate_benchmark_runner(tasks, extraVMarguments=None, prefix='', task
if t:
for name in renaissance_suite.benchmarkList(bmSuiteArgs):
iterations = int(renaissance_suite.renaissanceIterations().get(name, -1) * default_iterations_reduction)
for i in range(default_iterations):
for _ in range(default_iterations):
_gate_renaissance(name, iterations, benchVmArgs + ['-Dgraal.TrackNodeSourcePosition=true'] + enable_assertions)

with mx_gate.Task('Renaissance benchmark weekly workload', tasks, tags=['renaissance_weekly'], report=task_report_component) as t:
if t:
for name in renaissance_suite.benchmarkList(bmSuiteArgs):
iterations = int(renaissance_suite.renaissanceIterations().get(name, -1) * default_iterations_reduction)
for i in range(default_iterations * daily_weekly_jobs_ratio):
for _ in range(default_iterations * daily_weekly_jobs_ratio):
_gate_renaissance(name, iterations, benchVmArgs + ['-Dgraal.TrackNodeSourcePosition=true'] + enable_assertions)

# run benchmark with non default setup #
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright (c) 2023, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.graal.compiler.core.test;

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

import jdk.graal.compiler.nodes.StructuredGraph;
import jdk.graal.compiler.nodes.StructuredGraph.AllowAssumptions;
import jdk.graal.compiler.nodes.calc.IsNullNode;
import jdk.graal.compiler.nodes.java.InstanceOfNode;

public class InstanceOfCanonicalizationTest extends GraalCompilerTest {

public static boolean checkCastIncompatibleTypes(Object arr) {
// Cast first to a byte array, then to a boolean array. This only succeeds if arr is null.
byte[] barr = (byte[]) arr;
boolean[] bbarr = (boolean[]) (Object) barr;
return true;
}

public static int unsatisfiableInstanceOf(byte[] barr) {
// Plain instanceof does not allow null, so this will never succeed.
if ((Object) barr instanceof boolean[]) {
return -1;
}
return 1;
}

@Test
public void testCheckCastIncompatibleTypes() {
StructuredGraph g = parseEager("checkCastIncompatibleTypes", AllowAssumptions.NO, getInitialOptions());
createCanonicalizerPhase().apply(g, getDefaultHighTierContext());

// The second check-cast against boolean[] should canonicalize to a null check
Assert.assertEquals(1, g.getNodes().filter(InstanceOfNode.class).count());
Assert.assertEquals(1, g.getNodes().filter(IsNullNode.class).count());

testAgainstExpected(g.method(), new Result(checkCastIncompatibleTypes(null), null), null, new Object[]{null});
testAgainstExpected(g.method(), new Result(null, new ClassCastException()), null, new Object[]{new byte[10]});
testAgainstExpected(g.method(), new Result(null, new ClassCastException()), null, new Object[]{new boolean[10]});
}

@Test
public void testUnsatisfiableInstanceOf() {
StructuredGraph g = parseEager("unsatisfiableInstanceOf", AllowAssumptions.NO, getInitialOptions());
createCanonicalizerPhase().apply(g, getDefaultHighTierContext());

// Tested condition can never be true, so it should canonicalize to a constant.
Assert.assertEquals(0, g.getNodes().filter(InstanceOfNode.class).count());

testAgainstExpected(g.method(), new Result(unsatisfiableInstanceOf(null), null), null, new Object[]{null});
testAgainstExpected(g.method(), new Result(unsatisfiableInstanceOf(new byte[10]), null), null, new Object[]{new byte[10]});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@
import jdk.graal.compiler.nodes.spi.CanonicalizerTool;
import jdk.graal.compiler.nodes.spi.Lowerable;
import jdk.graal.compiler.nodes.type.StampTool;

import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.JavaTypeProfile;
import jdk.vm.ci.meta.ResolvedJavaType;
Expand Down Expand Up @@ -138,17 +137,19 @@ public static LogicNode findSynonym(ObjectStamp checkedStamp, ValueNode object,
if (joinedStamp.isEmpty()) {
// The check can never succeed, the intersection of the two stamps is empty.
return LogicConstantNode.contradiction();
} else if (joinedStamp.equals(inputStamp)) {
// The check will always succeed, the intersection of the two stamps is equal to the
// input stamp.
return LogicConstantNode.tautology();
} else if (joinedStamp.alwaysNull()) {
// The intersection of the two stamps is always null => simplify the check.
return IsNullNode.create(object);
} else {
ObjectStamp meetStamp = (ObjectStamp) checkedStamp.meet(inputStamp);
if (checkedStamp.equals(meetStamp)) {
// The check will always succeed, the union of the two stamps is equal to the
// checked stamp.
return LogicConstantNode.tautology();
} else if (checkedStamp.alwaysNull()) {
return IsNullNode.create(object);
} else if (Objects.equals(checkedStamp.type(), meetStamp.type()) && checkedStamp.isExactType() == meetStamp.isExactType() && checkedStamp.alwaysNull() == meetStamp.alwaysNull()) {
if (Objects.equals(checkedStamp.type(), meetStamp.type()) && checkedStamp.isExactType() == meetStamp.isExactType() && checkedStamp.alwaysNull() == meetStamp.alwaysNull()) {
assert checkedStamp.nonNull() != inputStamp.nonNull();
// The only difference makes the null-ness of the value => simplify the check.
// The only difference between the two stamps is their null-ness => simplify the
// check.
if (checkedStamp.nonNull()) {
return LogicNegationNode.create(IsNullNode.create(object));
} else {
Expand Down Expand Up @@ -182,8 +183,7 @@ public Stamp getSucceedingStampForValue(boolean negated) {

@Override
public TriState tryFold(Stamp valueStamp) {
if (valueStamp instanceof ObjectStamp) {
ObjectStamp inputStamp = (ObjectStamp) valueStamp;
if (valueStamp instanceof ObjectStamp inputStamp) {
ObjectStamp joinedStamp = (ObjectStamp) checkedStamp.join(inputStamp);

if (joinedStamp.isEmpty()) {
Expand Down Expand Up @@ -232,8 +232,7 @@ public static boolean intrinsify(GraphBuilderContext b, ResolvedJavaType type, V

@Override
public TriState implies(boolean thisNegated, LogicNode other) {
if (other instanceof InstanceOfNode) {
InstanceOfNode instanceOfNode = (InstanceOfNode) other;
if (other instanceof InstanceOfNode instanceOfNode) {
if (instanceOfNode.getValue() == getValue()) {
if (thisNegated) {
// !X => Y
Expand Down

0 comments on commit 9fb0c04

Please sign in to comment.