Skip to content

Commit 66b5dba

Browse files
SirYwelleme64
authored andcommitted
8350988: Consolidate Identity of self-inverse operations
Reviewed-by: epeter, vlivanov
1 parent 1007811 commit 66b5dba

File tree

4 files changed

+240
-25
lines changed

4 files changed

+240
-25
lines changed

src/hotspot/share/opto/subnode.cpp

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2047,15 +2047,9 @@ const Type* ReverseLNode::Value(PhaseGVN* phase) const {
20472047
return bottom_type();
20482048
}
20492049

2050-
Node* ReverseINode::Identity(PhaseGVN* phase) {
2051-
if (in(1)->Opcode() == Op_ReverseI) {
2052-
return in(1)->in(1);
2053-
}
2054-
return this;
2055-
}
2056-
2057-
Node* ReverseLNode::Identity(PhaseGVN* phase) {
2058-
if (in(1)->Opcode() == Op_ReverseL) {
2050+
Node* InvolutionNode::Identity(PhaseGVN* phase) {
2051+
// Op ( Op x ) => x
2052+
if (in(1)->Opcode() == Opcode()) {
20592053
return in(1)->in(1);
20602054
}
20612055
return this;

src/hotspot/share/opto/subnode.hpp

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -439,11 +439,18 @@ class CmpLTMaskNode : public Node {
439439
virtual uint ideal_reg() const { return Op_RegI; }
440440
};
441441

442+
//------------------------------InvolutionNode----------------------------------
443+
// Represents a self-inverse operation, i.e., op(op(x)) = x for any x
444+
class InvolutionNode : public Node {
445+
public:
446+
InvolutionNode(Node* in) : Node(nullptr, in) {}
447+
virtual Node* Identity(PhaseGVN* phase);
448+
};
442449

443450
//------------------------------NegNode----------------------------------------
444-
class NegNode : public Node {
451+
class NegNode : public InvolutionNode {
445452
public:
446-
NegNode(Node* in1) : Node(nullptr, in1) {
453+
NegNode(Node* in1) : InvolutionNode(in1) {
447454
init_class_id(Class_Neg);
448455
}
449456
};
@@ -556,65 +563,63 @@ class SqrtHFNode : public Node {
556563

557564
//-------------------------------ReverseBytesINode--------------------------------
558565
// reverse bytes of an integer
559-
class ReverseBytesINode : public Node {
566+
class ReverseBytesINode : public InvolutionNode {
560567
public:
561-
ReverseBytesINode(Node* in) : Node(nullptr, in) {}
568+
ReverseBytesINode(Node* in) : InvolutionNode(in) {}
562569
virtual int Opcode() const;
563570
const Type* bottom_type() const { return TypeInt::INT; }
564571
virtual uint ideal_reg() const { return Op_RegI; }
565572
};
566573

567574
//-------------------------------ReverseBytesLNode--------------------------------
568575
// reverse bytes of a long
569-
class ReverseBytesLNode : public Node {
576+
class ReverseBytesLNode : public InvolutionNode {
570577
public:
571-
ReverseBytesLNode(Node* in) : Node(nullptr, in) {}
578+
ReverseBytesLNode(Node* in) : InvolutionNode(in) {}
572579
virtual int Opcode() const;
573580
const Type* bottom_type() const { return TypeLong::LONG; }
574581
virtual uint ideal_reg() const { return Op_RegL; }
575582
};
576583

577584
//-------------------------------ReverseBytesUSNode--------------------------------
578585
// reverse bytes of an unsigned short / char
579-
class ReverseBytesUSNode : public Node {
586+
class ReverseBytesUSNode : public InvolutionNode {
580587
public:
581-
ReverseBytesUSNode(Node* in1) : Node(nullptr, in1) {}
588+
ReverseBytesUSNode(Node* in1) : InvolutionNode(in1) {}
582589
virtual int Opcode() const;
583590
const Type* bottom_type() const { return TypeInt::CHAR; }
584591
virtual uint ideal_reg() const { return Op_RegI; }
585592
};
586593

587594
//-------------------------------ReverseBytesSNode--------------------------------
588595
// reverse bytes of a short
589-
class ReverseBytesSNode : public Node {
596+
class ReverseBytesSNode : public InvolutionNode {
590597
public:
591-
ReverseBytesSNode(Node* in) : Node(nullptr, in) {}
598+
ReverseBytesSNode(Node* in) : InvolutionNode(in) {}
592599
virtual int Opcode() const;
593600
const Type* bottom_type() const { return TypeInt::SHORT; }
594601
virtual uint ideal_reg() const { return Op_RegI; }
595602
};
596603

597604
//-------------------------------ReverseINode--------------------------------
598605
// reverse bits of an int
599-
class ReverseINode : public Node {
606+
class ReverseINode : public InvolutionNode {
600607
public:
601-
ReverseINode(Node* in) : Node(nullptr, in) {}
608+
ReverseINode(Node* in) : InvolutionNode(in) {}
602609
virtual int Opcode() const;
603610
const Type* bottom_type() const { return TypeInt::INT; }
604611
virtual uint ideal_reg() const { return Op_RegI; }
605-
virtual Node* Identity(PhaseGVN* phase);
606612
virtual const Type* Value(PhaseGVN* phase) const;
607613
};
608614

609615
//-------------------------------ReverseLNode--------------------------------
610616
// reverse bits of a long
611-
class ReverseLNode : public Node {
617+
class ReverseLNode : public InvolutionNode {
612618
public:
613-
ReverseLNode(Node* in) : Node(nullptr, in) {}
619+
ReverseLNode(Node* in) : InvolutionNode(in) {}
614620
virtual int Opcode() const;
615621
const Type* bottom_type() const { return TypeLong::LONG; }
616622
virtual uint ideal_reg() const { return Op_RegL; }
617-
virtual Node* Identity(PhaseGVN* phase);
618623
virtual const Type* Value(PhaseGVN* phase) const;
619624
};
620625

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
package compiler.c2.irTests;
24+
25+
import compiler.lib.generators.Generator;
26+
import compiler.lib.generators.Generators;
27+
import compiler.lib.generators.RestrictableGenerator;
28+
import compiler.lib.ir_framework.DontCompile;
29+
import compiler.lib.ir_framework.IR;
30+
import compiler.lib.ir_framework.IRNode;
31+
import compiler.lib.ir_framework.Run;
32+
import compiler.lib.ir_framework.Test;
33+
import compiler.lib.ir_framework.TestFramework;
34+
import jdk.test.lib.Asserts;
35+
36+
/*
37+
* @test
38+
* @bug 8350988
39+
* @summary Test that Identity simplifications of Involution nodes are being performed as expected.
40+
* @library /test/lib /
41+
* @run driver compiler.c2.irTests.InvolutionIdentityTests
42+
*/
43+
public class InvolutionIdentityTests {
44+
45+
public static final RestrictableGenerator<Integer> GEN_CHAR = Generators.G.safeRestrict(Generators.G.ints(), Character.MIN_VALUE, Character.MAX_VALUE);
46+
public static final RestrictableGenerator<Integer> GEN_SHORT = Generators.G.safeRestrict(Generators.G.ints(), Short.MIN_VALUE, Short.MAX_VALUE);
47+
public static final RestrictableGenerator<Long> GEN_LONG = Generators.G.longs();
48+
public static final RestrictableGenerator<Integer> GEN_INT = Generators.G.ints();
49+
public static final Generator<Float> GEN_FLOAT = Generators.G.floats();
50+
public static final Generator<Double> GEN_DOUBLE = Generators.G.doubles();
51+
52+
public static void main(String[] args) {
53+
TestFramework.run();
54+
}
55+
56+
@Run(test = {
57+
"testI1", "testI2",
58+
"testL1", "testL2",
59+
"testS1",
60+
"testUS1",
61+
"testF1",
62+
"testD1"
63+
})
64+
public void runMethod() {
65+
int ai = GEN_INT.next();
66+
67+
int mini = Integer.MIN_VALUE;
68+
int maxi = Integer.MAX_VALUE;
69+
70+
assertResultI(0);
71+
assertResultI(ai);
72+
assertResultI(mini);
73+
assertResultI(maxi);
74+
75+
long al = GEN_LONG.next();
76+
77+
long minl = Long.MIN_VALUE;
78+
long maxl = Long.MAX_VALUE;
79+
80+
assertResultL(0);
81+
assertResultL(al);
82+
assertResultL(minl);
83+
assertResultL(maxl);
84+
85+
short as = GEN_SHORT.next().shortValue();
86+
87+
short mins = Short.MIN_VALUE;
88+
short maxs = Short.MAX_VALUE;
89+
90+
assertResultS((short) 0);
91+
assertResultS(as);
92+
assertResultS(mins);
93+
assertResultS(maxs);
94+
95+
char ac = (char) GEN_CHAR.next().intValue();
96+
97+
char minc = Character.MIN_VALUE;
98+
char maxc = Character.MAX_VALUE;
99+
100+
assertResultUS((char) 0);
101+
assertResultUS(ac);
102+
assertResultUS(minc);
103+
assertResultUS(maxc);
104+
105+
float af = GEN_FLOAT.next();
106+
float inf = Float.POSITIVE_INFINITY;
107+
float nanf = Float.NaN;
108+
109+
assertResultF(0f);
110+
assertResultF(-0f);
111+
assertResultF(af);
112+
assertResultF(inf);
113+
assertResultF(nanf);
114+
115+
double ad = GEN_DOUBLE.next();
116+
double ind = Double.POSITIVE_INFINITY;
117+
double nand = Double.NaN;
118+
119+
assertResultD(0d);
120+
assertResultD(-0d);
121+
assertResultD(ad);
122+
assertResultD(ind);
123+
assertResultD(nand);
124+
125+
}
126+
127+
@DontCompile
128+
public void assertResultI(int a) {
129+
Asserts.assertEQ(Integer.reverseBytes(Integer.reverseBytes(a)), testI1(a));
130+
Asserts.assertEQ(Integer.reverse(Integer.reverse(a)) , testI2(a));
131+
}
132+
133+
@DontCompile
134+
public void assertResultL(long a) {
135+
Asserts.assertEQ(Long.reverseBytes(Long.reverseBytes(a)), testL1(a));
136+
Asserts.assertEQ(Long.reverse(Long.reverse(a)) , testL2(a));
137+
}
138+
139+
@DontCompile
140+
public void assertResultS(short a) {
141+
Asserts.assertEQ(Short.reverseBytes(Short.reverseBytes(a)), testS1(a));
142+
}
143+
144+
@DontCompile
145+
public void assertResultUS(char a) {
146+
Asserts.assertEQ(Character.reverseBytes(Character.reverseBytes(a)), testUS1(a));
147+
}
148+
149+
@DontCompile
150+
public void assertResultF(float a) {
151+
Asserts.assertEQ(Float.floatToRawIntBits(-(-a)), Float.floatToRawIntBits(testF1(a)));
152+
}
153+
154+
@DontCompile
155+
public void assertResultD(double a) {
156+
Asserts.assertEQ(Double.doubleToRawLongBits(-(-a)), Double.doubleToRawLongBits(testD1(a)));
157+
}
158+
159+
@Test
160+
@IR(failOn = {IRNode.REVERSE_BYTES_I})
161+
public int testI1(int x) {
162+
return Integer.reverseBytes(Integer.reverseBytes(x));
163+
}
164+
165+
@Test
166+
@IR(failOn = {IRNode.REVERSE_I})
167+
public int testI2(int x) {
168+
return Integer.reverse(Integer.reverse(x));
169+
}
170+
171+
@Test
172+
@IR(failOn = {IRNode.REVERSE_BYTES_L})
173+
public long testL1(long x) {
174+
return Long.reverseBytes(Long.reverseBytes(x));
175+
}
176+
177+
@Test
178+
@IR(failOn = {IRNode.REVERSE_L})
179+
public long testL2(long x) {
180+
return Long.reverse(Long.reverse(x));
181+
}
182+
183+
@Test
184+
@IR(failOn = {IRNode.REVERSE_BYTES_S})
185+
public short testS1(short x) {
186+
return Short.reverseBytes(Short.reverseBytes(x));
187+
}
188+
189+
@Test
190+
@IR(failOn = {IRNode.REVERSE_BYTES_US})
191+
public char testUS1(char x) {
192+
return Character.reverseBytes(Character.reverseBytes(x));
193+
}
194+
195+
@Test
196+
@IR(failOn = {IRNode.NEG_F})
197+
public float testF1(float x) {
198+
return -(-x);
199+
}
200+
201+
@Test
202+
@IR(failOn = {IRNode.NEG_D})
203+
public double testD1(double x) {
204+
return -(-x);
205+
}
206+
}

test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1399,6 +1399,16 @@ public class IRNode {
13991399
superWordNodes(MAX_REDUCTION_V, "MaxReductionV");
14001400
}
14011401

1402+
public static final String NEG_F = PREFIX + "NEG_F" + POSTFIX;
1403+
static {
1404+
beforeMatchingNameRegex(NEG_F, "NegF");
1405+
}
1406+
1407+
public static final String NEG_D = PREFIX + "NEG_D" + POSTFIX;
1408+
static {
1409+
beforeMatchingNameRegex(NEG_D, "NegD");
1410+
}
1411+
14021412
public static final String NEG_VF = VECTOR_PREFIX + "NEG_VF" + POSTFIX;
14031413
static {
14041414
vectorNode(NEG_VF, "NegVF", TYPE_FLOAT);

0 commit comments

Comments
 (0)