mirror of
https://github.com/openjdk/jdk.git
synced 2026-04-24 05:40:39 +00:00
8378413: C2: Missed Ideal optimization opportunity in PhaseIterGVN for URShiftI still exists
Reviewed-by: qamai, dlong
This commit is contained in:
parent
ec3b58b5e0
commit
8a9b63f76f
@ -1539,15 +1539,20 @@ Node* URShiftINode::Ideal(PhaseGVN* phase, bool can_reshape) {
|
||||
Node *add = in(1);
|
||||
if (in1_op == Op_AddI) {
|
||||
Node *lshl = add->in(1);
|
||||
Node *y = add->in(2);
|
||||
if (lshl->Opcode() != Op_LShiftI) {
|
||||
lshl = add->in(2);
|
||||
y = add->in(1);
|
||||
}
|
||||
// Compare shift counts by value, not by node pointer, to also match a not-yet-normalized
|
||||
// negative constant (e.g. -1 vs 31)
|
||||
int lshl_con = 0;
|
||||
if (lshl->Opcode() == Op_LShiftI &&
|
||||
const_shift_count(phase, lshl, &lshl_con) &&
|
||||
(lshl_con & (BitsPerJavaInteger - 1)) == con) {
|
||||
Node *y_z = phase->transform( new URShiftINode(add->in(2),in(2)) );
|
||||
Node *sum = phase->transform( new AddINode( lshl->in(1), y_z ) );
|
||||
return new AndINode( sum, phase->intcon(mask) );
|
||||
Node *y_z = phase->transform(new URShiftINode(y, in(2)));
|
||||
Node *sum = phase->transform(new AddINode(lshl->in(1), y_z));
|
||||
return new AndINode(sum, phase->intcon(mask));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1699,13 +1704,18 @@ Node* URShiftLNode::Ideal(PhaseGVN* phase, bool can_reshape) {
|
||||
const TypeInt *t2 = phase->type(in(2))->isa_int();
|
||||
if (add->Opcode() == Op_AddL) {
|
||||
Node *lshl = add->in(1);
|
||||
Node *y = add->in(2);
|
||||
if (lshl->Opcode() != Op_LShiftL) {
|
||||
lshl = add->in(2);
|
||||
y = add->in(1);
|
||||
}
|
||||
// Compare shift counts by value, not by node pointer, to also match a not-yet-normalized
|
||||
// negative constant (e.g. -1 vs 63)
|
||||
int lshl_con = 0;
|
||||
if (lshl->Opcode() == Op_LShiftL &&
|
||||
const_shift_count(phase, lshl, &lshl_con) &&
|
||||
(lshl_con & (BitsPerJavaLong - 1)) == con) {
|
||||
Node* y_z = phase->transform(new URShiftLNode(add->in(2), in(2)));
|
||||
Node* y_z = phase->transform(new URShiftLNode(y, in(2)));
|
||||
Node* sum = phase->transform(new AddLNode(lshl->in(1), y_z));
|
||||
return new AndLNode(sum, phase->longcon(mask));
|
||||
}
|
||||
|
||||
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (c) 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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 compiler.c2.gvn;
|
||||
|
||||
import compiler.lib.ir_framework.*;
|
||||
import jdk.test.lib.Asserts;
|
||||
import jdk.test.lib.Utils;
|
||||
import java.util.Random;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8378413
|
||||
* @key randomness
|
||||
* @summary Verify that URShift{I,L}Node::Ideal optimizes ((x << C) + y) >>> C
|
||||
* regardless of Add input order, i.e. it is commutative w.r.t. the addition.
|
||||
* @library /test/lib /
|
||||
* @run driver ${test.main.class}
|
||||
* @run driver ${test.main.class} -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:VerifyIterativeGVN=1110 -Xbatch -XX:CompileCommand=compileonly,${test.main.class}::*
|
||||
*/
|
||||
public class MissedURShiftIAddILShiftIdeal {
|
||||
|
||||
private static final Random RANDOM = Utils.getRandomInstance();
|
||||
|
||||
public static void main(String[] args) {
|
||||
TestFramework.run();
|
||||
}
|
||||
|
||||
@Run(test = {"testI", "testICommuted", "testIComputedY",
|
||||
"testL", "testLCommuted", "testLComputedY"})
|
||||
public void runMethod() {
|
||||
int xi = RANDOM.nextInt();
|
||||
int yi = RANDOM.nextInt();
|
||||
int ai = RANDOM.nextInt();
|
||||
int bi = RANDOM.nextInt();
|
||||
long xl = RANDOM.nextLong();
|
||||
long yl = RANDOM.nextLong();
|
||||
long al = RANDOM.nextLong();
|
||||
long bl = RANDOM.nextLong();
|
||||
|
||||
assertResultI(xi, yi, ai, bi);
|
||||
assertResultL(xl, yl, al, bl);
|
||||
}
|
||||
|
||||
@DontCompile
|
||||
public void assertResultI(int x, int y, int a, int b) {
|
||||
Asserts.assertEQ(((x << 3) + y) >>> 3, testI(x, y));
|
||||
Asserts.assertEQ((y + (x << 5)) >>> 5, testICommuted(x, y));
|
||||
Asserts.assertEQ(((x << 7) + (a ^ b)) >>> 7, testIComputedY(x, a, b));
|
||||
}
|
||||
|
||||
@DontCompile
|
||||
public void assertResultL(long x, long y, long a, long b) {
|
||||
Asserts.assertEQ(((x << 9) + y) >>> 9, testL(x, y));
|
||||
Asserts.assertEQ((y + (x << 11)) >>> 11, testLCommuted(x, y));
|
||||
Asserts.assertEQ(((x << 13) + (a ^ b)) >>> 13, testLComputedY(x, a, b));
|
||||
}
|
||||
|
||||
@Test
|
||||
// ((x << 3) + y) >>> 3 => (x + (y >>> 3)) & mask
|
||||
@IR(counts = {IRNode.LSHIFT_I, "0",
|
||||
IRNode.URSHIFT_I, "1",
|
||||
IRNode.AND_I, "1"})
|
||||
static int testI(int x, int y) {
|
||||
return ((x << 3) + y) >>> 3;
|
||||
}
|
||||
|
||||
@Test
|
||||
// (y + (x << 5)) >>> 5 => (x + (y >>> 5)) & mask (commuted Add)
|
||||
@IR(counts = {IRNode.LSHIFT_I, "0",
|
||||
IRNode.URSHIFT_I, "1",
|
||||
IRNode.AND_I, "1"})
|
||||
static int testICommuted(int x, int y) {
|
||||
return (y + (x << 5)) >>> 5;
|
||||
}
|
||||
|
||||
@Test
|
||||
// ((x << 7) + (a ^ b)) >>> 7 => (x + ((a ^ b) >>> 7)) & mask
|
||||
// Computed y (a ^ b) has higher _idx than LShift, so LShift stays in Add's in(1).
|
||||
@IR(counts = {IRNode.LSHIFT_I, "0",
|
||||
IRNode.URSHIFT_I, "1",
|
||||
IRNode.AND_I, "1"})
|
||||
static int testIComputedY(int x, int a, int b) {
|
||||
return ((x << 7) + (a ^ b)) >>> 7;
|
||||
}
|
||||
|
||||
@Test
|
||||
// ((x << 9) + y) >>> 9 => (x + (y >>> 9)) & mask
|
||||
@IR(counts = {IRNode.LSHIFT_L, "0",
|
||||
IRNode.URSHIFT_L, "1",
|
||||
IRNode.AND_L, "1"})
|
||||
static long testL(long x, long y) {
|
||||
return ((x << 9) + y) >>> 9;
|
||||
}
|
||||
|
||||
@Test
|
||||
// (y + (x << 11)) >>> 11 => (x + (y >>> 11)) & mask (commuted Add)
|
||||
@IR(counts = {IRNode.LSHIFT_L, "0",
|
||||
IRNode.URSHIFT_L, "1",
|
||||
IRNode.AND_L, "1"})
|
||||
static long testLCommuted(long x, long y) {
|
||||
return (y + (x << 11)) >>> 11;
|
||||
}
|
||||
|
||||
@Test
|
||||
// ((x << 13) + (a ^ b)) >>> 13 => (x + ((a ^ b) >>> 13)) & mask
|
||||
// Computed y (a ^ b) has higher _idx than LShift, so LShift stays in Add's in(1).
|
||||
@IR(counts = {IRNode.LSHIFT_L, "0",
|
||||
IRNode.URSHIFT_L, "1",
|
||||
IRNode.AND_L, "1"})
|
||||
static long testLComputedY(long x, long a, long b) {
|
||||
return ((x << 13) + (a ^ b)) >>> 13;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user