Skip to content
Closed
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
21 changes: 21 additions & 0 deletions src/hotspot/share/opto/subnode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2021,6 +2021,27 @@ const Type* SqrtHFNode::Value(PhaseGVN* phase) const {
return TypeH::make((float)sqrt((double)f));
}

static const Type* reverse_bytes(int opcode, const Type* con) {
switch (opcode) {
case Op_ReverseBytesS: return TypeInt::make(byteswap(checked_cast<jshort>(con->is_int()->get_con())));
case Op_ReverseBytesUS: return TypeInt::make(byteswap(checked_cast<jchar>(con->is_int()->get_con())));
case Op_ReverseBytesI: return TypeInt::make(byteswap(checked_cast<jint>(con->is_int()->get_con())));
case Op_ReverseBytesL: return TypeLong::make(byteswap(checked_cast<jlong>(con->is_long()->get_con())));
default: ShouldNotReachHere();
}
}

const Type* ReverseBytesNode::Value(PhaseGVN* phase) const {
const Type* type = phase->type(in(1));
if (type == Type::TOP) {
return Type::TOP;
}
if (type->singleton()) {
return reverse_bytes(Opcode(), type);
}
return bottom_type();
}

const Type* ReverseINode::Value(PhaseGVN* phase) const {
const Type *t1 = phase->type( in(1) );
if (t1 == Type::TOP) {
Expand Down
24 changes: 16 additions & 8 deletions src/hotspot/share/opto/subnode.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -561,41 +561,49 @@ class SqrtHFNode : public Node {
virtual const Type* Value(PhaseGVN* phase) const;
};


class ReverseBytesNode : public InvolutionNode {
public:
ReverseBytesNode(Node* in) : InvolutionNode(in) {}
virtual const Type* Value(PhaseGVN* phase) const;
};
//-------------------------------ReverseBytesINode--------------------------------
// reverse bytes of an integer
class ReverseBytesINode : public InvolutionNode {
class ReverseBytesINode : public ReverseBytesNode {
public:
ReverseBytesINode(Node* in) : InvolutionNode(in) {}
ReverseBytesINode(Node* in) : ReverseBytesNode(in) {
}

virtual int Opcode() const;
const Type* bottom_type() const { return TypeInt::INT; }
virtual uint ideal_reg() const { return Op_RegI; }
};

//-------------------------------ReverseBytesLNode--------------------------------
// reverse bytes of a long
class ReverseBytesLNode : public InvolutionNode {
class ReverseBytesLNode : public ReverseBytesNode {
public:
ReverseBytesLNode(Node* in) : InvolutionNode(in) {}
ReverseBytesLNode(Node* in) : ReverseBytesNode(in) {}
virtual int Opcode() const;
const Type* bottom_type() const { return TypeLong::LONG; }
virtual uint ideal_reg() const { return Op_RegL; }
};

//-------------------------------ReverseBytesUSNode--------------------------------
// reverse bytes of an unsigned short / char
class ReverseBytesUSNode : public InvolutionNode {
class ReverseBytesUSNode : public ReverseBytesNode {
public:
ReverseBytesUSNode(Node* in1) : InvolutionNode(in1) {}
ReverseBytesUSNode(Node* in1) : ReverseBytesNode(in1) {}
virtual int Opcode() const;
const Type* bottom_type() const { return TypeInt::CHAR; }
virtual uint ideal_reg() const { return Op_RegI; }
};

//-------------------------------ReverseBytesSNode--------------------------------
// reverse bytes of a short
class ReverseBytesSNode : public InvolutionNode {
class ReverseBytesSNode : public ReverseBytesNode {
public:
ReverseBytesSNode(Node* in) : InvolutionNode(in) {}
ReverseBytesSNode(Node* in) : ReverseBytesNode(in) {}
virtual int Opcode() const;
const Type* bottom_type() const { return TypeInt::SHORT; }
virtual uint ideal_reg() const { return Op_RegI; }
Expand Down
198 changes: 198 additions & 0 deletions test/hotspot/jtreg/compiler/c2/gvn/ReverseBytesConstantsTests.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
/*
* Copyright (c) 2025, 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.generators.Generators;
import compiler.lib.generators.RestrictableGenerator;
import compiler.lib.ir_framework.DontCompile;
import compiler.lib.ir_framework.IR;
import compiler.lib.ir_framework.IRNode;
import compiler.lib.ir_framework.Run;
import compiler.lib.ir_framework.Test;
import compiler.lib.ir_framework.TestFramework;
import jdk.test.lib.Asserts;

/*
* @test
* @bug 8353551
* @summary Test that ReverseBytes operations constant-fold.
* @library /test/lib /
* @run driver compiler.c2.gvn.ReverseBytesConstantsTests
*/
public class ReverseBytesConstantsTests {

private static final RestrictableGenerator<Integer> GEN_CHAR = Generators.G.safeRestrict(Generators.G.ints(), Character.MIN_VALUE, Character.MAX_VALUE);
private static final char C_CHAR = (char) GEN_CHAR.next().intValue();
private static final RestrictableGenerator<Integer> GEN_SHORT = Generators.G.safeRestrict(Generators.G.ints(), Short.MIN_VALUE, Short.MAX_VALUE);
private static final short C_SHORT = GEN_SHORT.next().shortValue();
private static final RestrictableGenerator<Long> GEN_LONG = Generators.G.longs();
private static final long C_LONG = GEN_LONG.next();
private static final RestrictableGenerator<Integer> GEN_INT = Generators.G.ints();
private static final int C_INT = GEN_INT.next();

public static void main(String[] args) {
TestFramework.run();
}

@Run(test = {
"testI1", "testI2", "testI3",
"testL1", "testL2", "testL3",
"testS1", "testS2", "testS3",
"testUS1", "testUS2", "testUS3",
})
public void runMethod() {
assertResultI();
assertResultL();
assertResultS();
assertResultUS();
}

@DontCompile
public void assertResultI() {
Asserts.assertEQ(Integer.reverseBytes(0x04030201), testI1());
Asserts.assertEQ(Integer.reverseBytes(0x50607080), testI2());
Asserts.assertEQ(Integer.reverseBytes(0x80706050), testI3());
Asserts.assertEQ(Integer.reverseBytes(C_INT), testI4());
}

@DontCompile
public void assertResultL() {
Asserts.assertEQ(Long.reverseBytes(0x0807060504030201L), testL1());
Asserts.assertEQ(Long.reverseBytes(0x1020304050607080L), testL2());
Asserts.assertEQ(Long.reverseBytes(0x8070605040302010L), testL3());
Asserts.assertEQ(Long.reverseBytes(C_LONG), testL4());
}

@DontCompile
public void assertResultS() {
Asserts.assertEQ(Short.reverseBytes((short) 0x0201), testS1());
Asserts.assertEQ(Short.reverseBytes((short) 0x7080), testS2());
Asserts.assertEQ(Short.reverseBytes((short) 0x8070), testS3());
Asserts.assertEQ(Short.reverseBytes(C_SHORT), testS4());
}

@DontCompile
public void assertResultUS() {
Asserts.assertEQ(Character.reverseBytes((char) 0x0201), testUS1());
Asserts.assertEQ(Character.reverseBytes((char) 0x7080), testUS2());
Asserts.assertEQ(Character.reverseBytes((char) 0x8070), testUS3());
Asserts.assertEQ(Character.reverseBytes(C_CHAR), testUS4());
}

@Test
@IR(failOn = {IRNode.REVERSE_BYTES_I})
public int testI1() {
return Integer.reverseBytes(0x04030201);
}

@Test
@IR(failOn = {IRNode.REVERSE_BYTES_I})
public int testI2() {
return Integer.reverseBytes(0x50607080);
}

@Test
@IR(failOn = {IRNode.REVERSE_BYTES_I})
public int testI3() {
return Integer.reverseBytes(0x80706050);
}

@Test
@IR(failOn = {IRNode.REVERSE_BYTES_I})
public int testI4() {
return Integer.reverseBytes(C_INT);
}

@Test
@IR(failOn = {IRNode.REVERSE_BYTES_L})
public long testL1() {
return Long.reverseBytes(0x0807060504030201L);
}

@Test
@IR(failOn = {IRNode.REVERSE_BYTES_L})
public long testL2() {
return Long.reverseBytes(0x1020304050607080L);
}

@Test
@IR(failOn = {IRNode.REVERSE_BYTES_L})
public long testL3() {
return Long.reverseBytes(0x8070605040302010L);
}

@Test
@IR(failOn = {IRNode.REVERSE_BYTES_L})
public long testL4() {
return Long.reverseBytes(C_LONG);
}

@Test
@IR(failOn = {IRNode.REVERSE_BYTES_S})
public short testS1() {
return Short.reverseBytes((short) 0x0201);
}

@Test
@IR(failOn = {IRNode.REVERSE_BYTES_S})
public short testS2() {
return Short.reverseBytes((short) 0x7080);
}

@Test
@IR(failOn = {IRNode.REVERSE_BYTES_S})
public short testS3() {
return Short.reverseBytes((short) 0x8070);
}

@Test
@IR(failOn = {IRNode.REVERSE_BYTES_S})
public short testS4() {
return Short.reverseBytes(C_SHORT);
}

@Test
@IR(failOn = {IRNode.REVERSE_BYTES_US})
public char testUS1() {
return Character.reverseBytes((char) 0x0201);
}

@Test
@IR(failOn = {IRNode.REVERSE_BYTES_US})
public char testUS2() {
return Character.reverseBytes((char) 0x7080);
}

@Test
@IR(failOn = {IRNode.REVERSE_BYTES_US})
public char testUS3() {
return Character.reverseBytes((char) 0x8070);
}

@Test
@IR(failOn = {IRNode.REVERSE_BYTES_US})
public char testUS4() {
return Character.reverseBytes(C_CHAR);
}

}