From f301663b346bf2388ecfa429be1cf64c6e93ee8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20H=C3=A4ssig?= Date: Wed, 2 Apr 2025 06:30:55 +0000 Subject: [PATCH] 8352893: C2: OrL/INode::add_ring optimize (x | -1) to -1 Reviewed-by: epeter, thartmann, kvn --- src/hotspot/share/opto/addnode.cpp | 12 +++ .../integerArithmetic/TestOrSaturate.java | 87 +++++++++++++++++++ .../compiler/lib/ir_framework/IRNode.java | 10 +++ 3 files changed, 109 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/integerArithmetic/TestOrSaturate.java diff --git a/src/hotspot/share/opto/addnode.cpp b/src/hotspot/share/opto/addnode.cpp index 8406fe8b69e..d1be0180fd9 100644 --- a/src/hotspot/share/opto/addnode.cpp +++ b/src/hotspot/share/opto/addnode.cpp @@ -854,6 +854,12 @@ const Type *OrINode::add_ring( const Type *t0, const Type *t1 ) const { } } + // If either input is all ones, the output is all ones. + // x | ~0 == ~0 <==> x | -1 == -1 + if (r0 == TypeInt::MINUS_1 || r1 == TypeInt::MINUS_1) { + return TypeInt::MINUS_1; + } + // If either input is not a constant, just return all integers. if( !r0->is_con() || !r1->is_con() ) return TypeInt::INT; // Any integer, but still no symbols. @@ -911,6 +917,12 @@ const Type *OrLNode::add_ring( const Type *t0, const Type *t1 ) const { const TypeLong *r0 = t0->is_long(); // Handy access const TypeLong *r1 = t1->is_long(); + // If either input is all ones, the output is all ones. + // x | ~0 == ~0 <==> x | -1 == -1 + if (r0 == TypeLong::MINUS_1 || r1 == TypeLong::MINUS_1) { + return TypeLong::MINUS_1; + } + // If either input is not a constant, just return all integers. if( !r0->is_con() || !r1->is_con() ) return TypeLong::LONG; // Any integer, but still no symbols. diff --git a/test/hotspot/jtreg/compiler/integerArithmetic/TestOrSaturate.java b/test/hotspot/jtreg/compiler/integerArithmetic/TestOrSaturate.java new file mode 100644 index 00000000000..0d1d66c2909 --- /dev/null +++ b/test/hotspot/jtreg/compiler/integerArithmetic/TestOrSaturate.java @@ -0,0 +1,87 @@ +/* + * 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.integerArithmetic; + +import compiler.lib.ir_framework.*; +import java.util.Random; +import jdk.test.lib.Utils; +import jdk.test.lib.Asserts; + +/* + * @test + * @bug 8352893 + * @summary Test that an or with all bits set is folded to all bits (x | -1 == -1). + * @key randomness + * @library / /test/lib + * @run driver compiler.integerArithmetic.TestOrSaturate + */ + +public class TestOrSaturate { + public static void main(String[] args) { + TestFramework.run(); + } + + private static final Random random = Utils.getRandomInstance(); + + @Run(test = {"testL", "testI", "testDelayed"}) + public static void check() { + Asserts.assertEQ(-1L, testL(random.nextLong())); + Asserts.assertEQ(-1, testI(random.nextInt())); + Asserts.assertEQ(-1, testDelayed(random.nextInt())); + } + + @Test + @IR(failOn = { IRNode.OR_L }) + // Tests that the OrLNode is folded if one operand is -1. + private static long testL(long x) { + return x | -1L; + } + + @Test + @IR(failOn = { IRNode.OR_I }) + // Tests that the OrINode is folded if one operand is -1. + private static int testI(int x) { + return x | -1; + } + + @Test + @IR(counts = {IRNode.OR_I, "1"}, + phase = CompilePhase.AFTER_PARSING) + @IR(failOn = { IRNode.OR_I }) + // Tests that the OrI node is folded after parsing if one operand is -1. + private static int testDelayed(int x) { + int min1 = 42; + int limit = 2; + + // Ensure that min1 == -1 is only known after some constant propagation. + for (; limit < 4; limit *= 2) {} + for (int i = 2; i < limit; i++) { + min1 = -1; + } + + // Will only be folded after min1 == -1 is established. + return x | min1; + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index ae9126d4395..6d4f2508d8a 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -1440,6 +1440,16 @@ public class IRNode { optoOnly(OOPMAP_WITH, regex); } + public static final String OR_I = PREFIX + "OR_I" + POSTFIX; + static { + beforeMatchingNameRegex(OR_I, "OrI"); + } + + public static final String OR_L = PREFIX + "OR_L" + POSTFIX; + static { + beforeMatchingNameRegex(OR_L, "OrL"); + } + public static final String OR_VB = VECTOR_PREFIX + "OR_VB" + POSTFIX; static { vectorNode(OR_VB, "OrV", TYPE_BYTE);