diff --git a/src/hotspot/share/opto/addnode.cpp b/src/hotspot/share/opto/addnode.cpp index 305501bfb1467..49d17d84fc91c 100644 --- a/src/hotspot/share/opto/addnode.cpp +++ b/src/hotspot/share/opto/addnode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, 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 @@ -253,6 +253,22 @@ AddNode* AddNode::make(Node* in1, Node* in2, BasicType bt) { return nullptr; } +bool AddNode::is_not(PhaseGVN* phase, Node* n, BasicType bt) { + return n->Opcode() == Op_Xor(bt) && phase->type(n->in(2)) == TypeInteger::minus_1(bt); +} + +AddNode* AddNode::make_not(PhaseGVN* phase, Node* n, BasicType bt) { + switch (bt) { + case T_INT: + return new XorINode(n, phase->intcon(-1)); + case T_LONG: + return new XorLNode(n, phase->longcon(-1L)); + default: + fatal("Not implemented for %s", type2name(bt)); + } + return nullptr; +} + //============================================================================= //------------------------------Idealize--------------------------------------- Node* AddNode::IdealIL(PhaseGVN* phase, bool can_reshape, BasicType bt) { diff --git a/src/hotspot/share/opto/addnode.hpp b/src/hotspot/share/opto/addnode.hpp index 709958b6abf25..577dd6ba29588 100644 --- a/src/hotspot/share/opto/addnode.hpp +++ b/src/hotspot/share/opto/addnode.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, 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 @@ -78,6 +78,13 @@ class AddNode : public Node { virtual int min_opcode() const = 0; static AddNode* make(Node* in1, Node* in2, BasicType bt); + + // Utility function to check if the given node is a NOT operation, + // i.e., n == m ^ (-1). + static bool is_not(PhaseGVN* phase, Node* n, BasicType bt); + + // Utility function to make a NOT operation, i.e., returning n ^ (-1). + static AddNode* make_not(PhaseGVN* phase, Node* n, BasicType bt); }; //------------------------------AddINode--------------------------------------- diff --git a/src/hotspot/share/opto/mulnode.cpp b/src/hotspot/share/opto/mulnode.cpp index 6709f8314478f..56d0b94a6614e 100644 --- a/src/hotspot/share/opto/mulnode.cpp +++ b/src/hotspot/share/opto/mulnode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, 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 @@ -610,6 +610,13 @@ Node *AndINode::Ideal(PhaseGVN *phase, bool can_reshape) { return progress; } + // Convert "(~a) & (~b)" into "~(a | b)" + if (AddNode::is_not(phase, in(1), T_INT) && AddNode::is_not(phase, in(2), T_INT)) { + Node* or_a_b = new OrINode(in(1)->in(1), in(2)->in(1)); + Node* tn = phase->transform(or_a_b); + return AddNode::make_not(phase, tn, T_INT); + } + // Special case constant AND mask const TypeInt *t2 = phase->type( in(2) )->isa_int(); if( !t2 || !t2->is_con() ) return MulNode::Ideal(phase, can_reshape); @@ -750,6 +757,13 @@ Node *AndLNode::Ideal(PhaseGVN *phase, bool can_reshape) { return progress; } + // Convert "(~a) & (~b)" into "~(a | b)" + if (AddNode::is_not(phase, in(1), T_LONG) && AddNode::is_not(phase, in(2), T_LONG)) { + Node* or_a_b = new OrLNode(in(1)->in(1), in(2)->in(1)); + Node* tn = phase->transform(or_a_b); + return AddNode::make_not(phase, tn, T_LONG); + } + // Special case constant AND mask const TypeLong *t2 = phase->type( in(2) )->isa_long(); if( !t2 || !t2->is_con() ) return MulNode::Ideal(phase, can_reshape); diff --git a/test/hotspot/jtreg/compiler/c2/irTests/AndINodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/AndINodeIdealizationTests.java index ad2b52392b6c3..f20c28e321db1 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/AndINodeIdealizationTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/AndINodeIdealizationTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 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 @@ -38,22 +38,24 @@ public static void main(String[] args) { TestFramework.run(); } - @Run(test = { "test1" }) + @Run(test = { "test1", "test2" }) public void runMethod() { int a = RunInfo.getRandom().nextInt(); + int b = RunInfo.getRandom().nextInt(); int min = Integer.MIN_VALUE; int max = Integer.MAX_VALUE; - assertResult(0); - assertResult(a); - assertResult(min); - assertResult(max); + assertResult(0, 0); + assertResult(a, b); + assertResult(min, min); + assertResult(max, max); } @DontCompile - public void assertResult(int a) { + public void assertResult(int a, int b) { Asserts.assertEQ((0 - a) & 1, test1(a)); + Asserts.assertEQ((~a) & (~b), test2(a, b)); } @Test @@ -63,4 +65,13 @@ public void assertResult(int a) { public int test1(int x) { return (0 - x) & 1; } + + @Test + @IR(failOn = { IRNode.AND }) + @IR(counts = { IRNode.OR, "1", + IRNode.XOR, "1" }) + // Checks (~a) & (~b) => ~(a | b) + public int test2(int a, int b) { + return (~a) & (~b); + } } diff --git a/test/hotspot/jtreg/compiler/c2/irTests/AndLNodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/AndLNodeIdealizationTests.java new file mode 100644 index 0000000000000..9aa1b62be9743 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/AndLNodeIdealizationTests.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2024, 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.irTests; + +import jdk.test.lib.Asserts; +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8322589 + * @summary Test that Ideal transformations of AndLNode* are being performed as expected. + * @library /test/lib / + * @run driver compiler.c2.irTests.AndLNodeIdealizationTests + */ +public class AndLNodeIdealizationTests { + + public static void main(String[] args) { + TestFramework.run(); + } + + @Run(test = { "test1" }) + public void runMethod() { + long a = RunInfo.getRandom().nextLong(); + long b = RunInfo.getRandom().nextLong(); + + long min = Long.MIN_VALUE; + long max = Long.MAX_VALUE; + + assertResult(0, 0); + assertResult(a, b); + assertResult(min, min); + assertResult(max, max); + } + + @DontCompile + public void assertResult(long a, long b) { + Asserts.assertEQ((~a) & (~b), test1(a, b)); + } + + @Test + @IR(failOn = { IRNode.AND }) + @IR(counts = { IRNode.OR, "1", + IRNode.XOR, "1" }) + // Checks (~a) & (~b) => ~(a | b) + public long test1(long a, long b) { + return (~a) & (~b); + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 1778c2292df4e..a0d8b99731165 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, 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 @@ -298,6 +298,11 @@ public class IRNode { optoOnly(ALLOC_ARRAY_OF, regex); } + public static final String OR = PREFIX + "OR" + POSTFIX; + static { + beforeMatchingNameRegex(OR, "Or(I|L)"); + } + public static final String AND = PREFIX + "AND" + POSTFIX; static { beforeMatchingNameRegex(AND, "And(I|L)");