8313672: C2: PhaseCCP does not correctly track analysis dependencies involving shift, convert, and mask
Reviewed-by: epeter, rcastanedalo, thartmann
This commit is contained in:
parent
fbe19378c3
commit
bad6999634
src/hotspot/share/opto
test/hotspot/jtreg/compiler/ccp
@ -80,28 +80,6 @@ public:
|
||||
|
||||
Node* optimize_integer_cast(PhaseGVN* phase, BasicType bt);
|
||||
|
||||
// Visit all non-cast uses of the node, bypassing ConstraintCasts.
|
||||
// Pattern: this (-> ConstraintCast)* -> non_cast
|
||||
// In other words: find all non_cast nodes such that
|
||||
// non_cast->uncast() == this.
|
||||
template <typename Callback>
|
||||
static void visit_uncasted_uses(const Node* n, Callback callback) {
|
||||
ResourceMark rm;
|
||||
Unique_Node_List internals;
|
||||
internals.push((Node*)n); // start traversal
|
||||
for (uint j = 0; j < internals.size(); ++j) {
|
||||
Node* internal = internals.at(j); // for every internal
|
||||
for (DUIterator_Fast kmax, k = internal->fast_outs(kmax); k < kmax; k++) {
|
||||
Node* internal_use = internal->fast_out(k);
|
||||
if (internal_use->is_ConstraintCast()) {
|
||||
internals.push(internal_use); // traverse this cast also
|
||||
} else {
|
||||
callback(internal_use);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool higher_equal_types(PhaseGVN* phase, const Node* other) const;
|
||||
|
||||
int extra_types_count() const {
|
||||
|
@ -1128,6 +1128,13 @@ public:
|
||||
// Set control or add control as precedence edge
|
||||
void ensure_control_or_add_prec(Node* c);
|
||||
|
||||
// Visit boundary uses of the node and apply a callback function for each.
|
||||
// Recursively traverse uses, stopping and applying the callback when
|
||||
// reaching a boundary node, defined by is_boundary. Note: the function
|
||||
// definition appears after the complete type definition of Node_List.
|
||||
template <typename Callback, typename Check>
|
||||
void visit_uses(Callback callback, Check is_boundary) const;
|
||||
|
||||
//----------------- Code Generation
|
||||
|
||||
// Ideal register class for Matching. Zero means unmatched instruction
|
||||
@ -1628,6 +1635,35 @@ public:
|
||||
void dump_simple() const;
|
||||
};
|
||||
|
||||
// Definition must appear after complete type definition of Node_List
|
||||
template <typename Callback, typename Check>
|
||||
void Node::visit_uses(Callback callback, Check is_boundary) const {
|
||||
ResourceMark rm;
|
||||
VectorSet visited;
|
||||
Node_List worklist;
|
||||
|
||||
// The initial worklist consists of the direct uses
|
||||
for (DUIterator_Fast kmax, k = fast_outs(kmax); k < kmax; k++) {
|
||||
Node* out = fast_out(k);
|
||||
if (!visited.test_set(out->_idx)) { worklist.push(out); }
|
||||
}
|
||||
|
||||
while (worklist.size() > 0) {
|
||||
Node* use = worklist.pop();
|
||||
// Apply callback on boundary nodes
|
||||
if (is_boundary(use)) {
|
||||
callback(use);
|
||||
} else {
|
||||
// Not a boundary node, continue search
|
||||
for (DUIterator_Fast kmax, k = use->fast_outs(kmax); k < kmax; k++) {
|
||||
Node* out = use->fast_out(k);
|
||||
if (!visited.test_set(out->_idx)) { worklist.push(out); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------Unique_Node_List-------------------------------
|
||||
class Unique_Node_List : public Node_List {
|
||||
friend class VMStructs;
|
||||
|
@ -1606,7 +1606,9 @@ void PhaseIterGVN::add_users_to_worklist( Node *n ) {
|
||||
_worklist.push(n);
|
||||
}
|
||||
};
|
||||
ConstraintCastNode::visit_uncasted_uses(use, push_the_uses_to_worklist);
|
||||
auto is_boundary = [](Node* n){ return !n->is_ConstraintCast(); };
|
||||
use->visit_uses(push_the_uses_to_worklist, is_boundary);
|
||||
|
||||
}
|
||||
// If changed LShift inputs, check RShift users for useless sign-ext
|
||||
if( use_op == Op_LShiftI ) {
|
||||
@ -1832,7 +1834,7 @@ void PhaseCCP::verify_analyze(Unique_Node_List& worklist_verify) {
|
||||
// We should either make sure that these nodes are properly added back to the CCP worklist
|
||||
// in PhaseCCP::push_child_nodes_to_worklist() to update their type or add an exception
|
||||
// in the verification code above if that is not possible for some reason (like Load nodes).
|
||||
assert(!failure, "Missed optimization opportunity in PhaseCCP");
|
||||
assert(!failure, "PhaseCCP not at fixpoint: analysis result may be unsound.");
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1974,7 +1976,7 @@ void PhaseCCP::push_load_barrier(Unique_Node_List& worklist, const BarrierSetC2*
|
||||
|
||||
// AndI/L::Value() optimizes patterns similar to (v << 2) & 3 to zero if they are bitwise disjoint.
|
||||
// Add the AndI/L nodes back to the worklist to re-apply Value() in case the shift value changed.
|
||||
// Pattern: parent -> LShift (use) -> ConstraintCast* -> And
|
||||
// Pattern: parent -> LShift (use) -> (ConstraintCast | ConvI2L)* -> And
|
||||
void PhaseCCP::push_and(Unique_Node_List& worklist, const Node* parent, const Node* use) const {
|
||||
uint use_op = use->Opcode();
|
||||
if ((use_op == Op_LShiftI || use_op == Op_LShiftL)
|
||||
@ -1985,7 +1987,10 @@ void PhaseCCP::push_and(Unique_Node_List& worklist, const Node* parent, const No
|
||||
push_if_not_bottom_type(worklist, n);
|
||||
}
|
||||
};
|
||||
ConstraintCastNode::visit_uncasted_uses(use, push_and_uses_to_worklist);
|
||||
auto is_boundary = [](Node* n) {
|
||||
return !(n->is_ConstraintCast() || n->Opcode() == Op_ConvI2L);
|
||||
};
|
||||
use->visit_uses(push_and_uses_to_worklist, is_boundary);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2023, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8313672
|
||||
* @summary Test CCP notification for value update of AndL through LShiftI and
|
||||
* ConvI2L.
|
||||
* @run main/othervm -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:RepeatCompilation=20 -XX:-TieredCompilation
|
||||
* -XX:+StressIGVN -Xcomp
|
||||
* -XX:CompileCommand=compileonly,compiler.ccp.TestShiftConvertAndNotification::test
|
||||
* compiler.ccp.TestShiftConvertAndNotification
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8313672
|
||||
* @summary Test CCP notification for value update of AndL through LShiftI and
|
||||
* ConvI2L (no flags).
|
||||
* @run driver compiler.ccp.TestShiftConvertAndNotification
|
||||
*
|
||||
*/
|
||||
|
||||
package compiler.ccp;
|
||||
|
||||
public class TestShiftConvertAndNotification {
|
||||
static long instanceCount;
|
||||
static void test() {
|
||||
int i, i1 = 7;
|
||||
for (i = 7; i < 45; i++) {
|
||||
instanceCount = i;
|
||||
instanceCount &= i1 * i << i * Math.max(instanceCount, instanceCount);
|
||||
switch (i % 2) {
|
||||
case 8:
|
||||
i1 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
public static void main(String[] strArr) {
|
||||
for (int i = 0; i < 20_000; i++)
|
||||
test();
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user