Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GR-53019] Potential new optimisation for IntegerEqualsNode #8679

Open
default-jamc opened this issue Apr 2, 2024 · 1 comment
Open

[GR-53019] Potential new optimisation for IntegerEqualsNode #8679

default-jamc opened this issue Apr 2, 2024 · 1 comment
Assignees

Comments

@default-jamc
Copy link

Overview

Hi,

I noticed that there may be another optimisation that can be added to IntegerEqualsNode. Specifically, comparing the And and Or of two values is equivalent to comparing the values directly.

 ((x & y) == (x | y)) -> (x == y)

 Commutativity permutations:
 ((x & y) == (y | x)) -> (x == y)
 ((x | y) == (x & y)) -> (x == y)
 ((x | y) == (y & x)) -> (x == y)

This optimisation has also been formally verified in an interactive theorem prover (Isabelle/HOL).

Sample Program

I've written a sample program to demonstrate the speed-up of this optimisation:

public class BinaryExprTest {

  public static void main(String[] args) {
    long start = System.nanoTime();
    long sum = 0;
    for (int i = 1; i < 1000000; i++) {
      sum += calculate(i);
    }
    System.out.println(sum);
    long end = System.nanoTime();
    System.out.println("Time taken: " + ((end - start) / 1000000) + "ms");
  }

  static int calculate(int i) {
    int m = 1;
    int s = i;
    boolean condition = false;
    for (int j = 1; j < 1000; j++) {
      s = s * 6 + j;
      m = calc2(s,j);

      //condition = ((m & s) == (m | s)); // Unoptimised
      condition = (m == s);       // Optimised

    }

    return (condition) ? 1 : 2;
  }

  static int calc2(int i, int j) {
    int x = i;
    for (int y = 0; y < 10; y++) {
      x = x + ((j + (i*10)) + y);
    }

    return x;
  }
}

The optimised version is around 15-20% faster than the unoptimised version, yielding runtimes of approximately 3.7s and 4.5s, respectively.

Unit Test

I've also written a JUnit test to check whether this optimisation is applied:

package jdk.graal.compiler.core.test;

import jdk.graal.compiler.nodes.StructuredGraph;
import jdk.graal.compiler.nodes.calc.AndNode;
import jdk.graal.compiler.nodes.calc.IntegerEqualsNode;
import jdk.graal.compiler.nodes.calc.OrNode;
import org.junit.Test;

public class NewOptimizationTest extends GraalCompilerTest {

    // ((x & y) == (x | y)) |-> (x == y)
    public static boolean andOrEquals1(int x, int y) {
        return ((x & y) == (x | y));
    }

    public static boolean andOrEquals2(int x, int y) {
        return ((x & y) == (y | x));
    }

    public static boolean andOrEquals3(int x, int y) {
        return ((x | y) == (x & y));
    }

    public static boolean andOrEquals4(int x, int y) {
        return ((x | y) == (y & x));
    }

    private void checkNodes(String methodName) {
        StructuredGraph graph = parseForCompile(getResolvedJavaMethod(methodName));

        System.out.println("(Before) Nodes in graph: ");
        System.out.println("IntegerEquals: " + graph.getNodes().filter(IntegerEqualsNode.class).count());
        System.out.println("And: " + graph.getNodes().filter(AndNode.class).count());
        System.out.println("Or: " + graph.getNodes().filter(OrNode.class).count());

        createCanonicalizerPhase().apply(graph, getProviders());

        System.out.println("(After) Nodes in graph: ");
        System.out.println("IntegerEquals: " + graph.getNodes().filter(IntegerEqualsNode.class).count());
        System.out.println("And: " + graph.getNodes().filter(AndNode.class).count());
        System.out.println("Or: " + graph.getNodes().filter(OrNode.class).count());

        // If there are no AndNodes or OrNodes in the graph, the optimisation was applied
        assertTrue(graph.getNodes().filter(AndNode.class).count() == 0);
        assertTrue(graph.getNodes().filter(OrNode.class).count() == 0);
    }

    @Test
    public void testOptimization1() {
        checkNodes("andOrEquals1");
    }

    @Test
    public void testOptimization2() {
        checkNodes("andOrEquals2");
    }

    @Test
    public void testOptimization3() {
        checkNodes("andOrEquals3");
    }

    @Test
    public void testOptimization4() {
        checkNodes("andOrEquals4");
    }
}

Running this test produces the following output:

MxJUnitCore
JUnit version 4.12
.(Before) Nodes in graph: 
IntegerEquals: 1
And: 1
Or: 1
(After) Nodes in graph: 
IntegerEquals: 1
And: 1
Or: 1
E
testOptimization1(jdk.graal.compiler.core.test.NewOptimizationTest)
java.lang.AssertionError
	...
.(Before) Nodes in graph: 
IntegerEquals: 1
And: 1
Or: 1
(After) Nodes in graph: 
IntegerEquals: 1
And: 1
Or: 1
E
testOptimization2(jdk.graal.compiler.core.test.NewOptimizationTest)
java.lang.AssertionError
	...
.(Before) Nodes in graph: 
IntegerEquals: 1
And: 1
Or: 1
(After) Nodes in graph: 
IntegerEquals: 1
And: 1
Or: 1
E
testOptimization3(jdk.graal.compiler.core.test.NewOptimizationTest)
java.lang.AssertionError
	...
.(Before) Nodes in graph: 
IntegerEquals: 1
And: 1
Or: 1
(After) Nodes in graph: 
IntegerEquals: 1
And: 1
Or: 1
E
testOptimization4(jdk.graal.compiler.core.test.NewOptimizationTest)
java.lang.AssertionError
	...

Time: 0.79
There were 4 failures:
1) jdk.graal.compiler.core.test.NewOptimizationTest#testOptimization1
java.lang.AssertionError
	...
2) jdk.graal.compiler.core.test.NewOptimizationTest#testOptimization2
java.lang.AssertionError
	...
3) jdk.graal.compiler.core.test.NewOptimizationTest#testOptimization3
java.lang.AssertionError
	...
4) jdk.graal.compiler.core.test.NewOptimizationTest#testOptimization4
java.lang.AssertionError
	...

FAILURES!!!
Tests run: 4,  Failures: 4
...
@davleopo
Copy link
Member

davleopo commented Apr 2, 2024

@gergo- can you have a look ?

@oubidar-Abderrahim oubidar-Abderrahim changed the title Potential new optimisation for IntegerEqualsNode [GR-53019] Potential new optimisation for IntegerEqualsNode Apr 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants