Skip to content

Commit 2c0507e

Browse files
committed
8261812: C2 compilation fails with assert(!had_error) failed: bad dominance
Reviewed-by: kvn, thartmann
1 parent 9755782 commit 2c0507e

File tree

6 files changed

+170
-23
lines changed

6 files changed

+170
-23
lines changed

src/hotspot/share/opto/compile.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4793,3 +4793,27 @@ void Compile::igv_print_method_to_network(const char* phase_name) {
47934793
void Compile::add_native_invoker(RuntimeStub* stub) {
47944794
_native_invokers.append(stub);
47954795
}
4796+
4797+
Node* Compile::narrow_value(BasicType bt, Node* value, const Type* type, PhaseGVN* phase, bool transform_res) {
4798+
if (type != NULL && phase->type(value)->higher_equal(type)) {
4799+
return value;
4800+
}
4801+
Node* result = NULL;
4802+
if (bt == T_BYTE) {
4803+
result = phase->transform(new LShiftINode(value, phase->intcon(24)));
4804+
result = new RShiftINode(result, phase->intcon(24));
4805+
} else if (bt == T_BOOLEAN) {
4806+
result = new AndINode(value, phase->intcon(0xFF));
4807+
} else if (bt == T_CHAR) {
4808+
result = new AndINode(value,phase->intcon(0xFFFF));
4809+
} else {
4810+
assert(bt == T_SHORT, "unexpected narrow type");
4811+
result = phase->transform(new LShiftINode(value, phase->intcon(16)));
4812+
result = new RShiftINode(result, phase->intcon(16));
4813+
}
4814+
if (transform_res) {
4815+
result = phase->transform(result);
4816+
}
4817+
return result;
4818+
}
4819+

src/hotspot/share/opto/compile.hpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,9 +1192,10 @@ class Compile : public Phase {
11921192
bool has_exception_backedge() const { return _exception_backedge; }
11931193
#endif
11941194

1195-
static bool
1196-
push_thru_add(PhaseGVN* phase, Node* z, const TypeInteger* tz, const TypeInteger*& rx, const TypeInteger*& ry,
1197-
BasicType bt);
1195+
static bool push_thru_add(PhaseGVN* phase, Node* z, const TypeInteger* tz, const TypeInteger*& rx, const TypeInteger*& ry,
1196+
BasicType bt);
1197+
1198+
static Node* narrow_value(BasicType bt, Node* value, const Type* type, PhaseGVN* phase, bool transform_res);
11981199
};
11991200

12001201
#endif // SHARE_OPTO_COMPILE_HPP

src/hotspot/share/opto/macro.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,9 @@ Node *PhaseMacroExpand::value_from_mem_phi(Node *mem, BasicType ft, const Type *
450450
Node* n = val->in(MemNode::ValueIn);
451451
BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2();
452452
n = bs->step_over_gc_barrier(n);
453+
if (is_subword_type(ft)) {
454+
n = Compile::narrow_value(ft, n, phi_type, &_igvn, true);
455+
}
453456
values.at_put(j, n);
454457
} else if(val->is_Proj() && val->in(0) == alloc) {
455458
values.at_put(j, _igvn.zerocon(ft));

src/hotspot/share/opto/memnode.cpp

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2079,12 +2079,14 @@ uint LoadNode::match_edge(uint idx) const {
20792079
// with the value stored truncated to a byte. If no truncation is
20802080
// needed, the replacement is done in LoadNode::Identity().
20812081
//
2082-
Node *LoadBNode::Ideal(PhaseGVN *phase, bool can_reshape) {
2082+
Node* LoadBNode::Ideal(PhaseGVN* phase, bool can_reshape) {
20832083
Node* mem = in(MemNode::Memory);
20842084
Node* value = can_see_stored_value(mem,phase);
2085-
if( value && !phase->type(value)->higher_equal( _type ) ) {
2086-
Node *result = phase->transform( new LShiftINode(value, phase->intcon(24)) );
2087-
return new RShiftINode(result, phase->intcon(24));
2085+
if (value != NULL) {
2086+
Node* narrow = Compile::narrow_value(T_BYTE, value, _type, phase, false);
2087+
if (narrow != value) {
2088+
return narrow;
2089+
}
20882090
}
20892091
// Identity call will handle the case where truncation is not needed.
20902092
return LoadNode::Ideal(phase, can_reshape);
@@ -2114,8 +2116,12 @@ const Type* LoadBNode::Value(PhaseGVN* phase) const {
21142116
Node* LoadUBNode::Ideal(PhaseGVN* phase, bool can_reshape) {
21152117
Node* mem = in(MemNode::Memory);
21162118
Node* value = can_see_stored_value(mem, phase);
2117-
if (value && !phase->type(value)->higher_equal(_type))
2118-
return new AndINode(value, phase->intcon(0xFF));
2119+
if (value != NULL) {
2120+
Node* narrow = Compile::narrow_value(T_BOOLEAN, value, _type, phase, false);
2121+
if (narrow != value) {
2122+
return narrow;
2123+
}
2124+
}
21192125
// Identity call will handle the case where truncation is not needed.
21202126
return LoadNode::Ideal(phase, can_reshape);
21212127
}
@@ -2141,11 +2147,15 @@ const Type* LoadUBNode::Value(PhaseGVN* phase) const {
21412147
// with the value stored truncated to a char. If no truncation is
21422148
// needed, the replacement is done in LoadNode::Identity().
21432149
//
2144-
Node *LoadUSNode::Ideal(PhaseGVN *phase, bool can_reshape) {
2150+
Node* LoadUSNode::Ideal(PhaseGVN* phase, bool can_reshape) {
21452151
Node* mem = in(MemNode::Memory);
21462152
Node* value = can_see_stored_value(mem,phase);
2147-
if( value && !phase->type(value)->higher_equal( _type ) )
2148-
return new AndINode(value,phase->intcon(0xFFFF));
2153+
if (value != NULL) {
2154+
Node* narrow = Compile::narrow_value(T_CHAR, value, _type, phase, false);
2155+
if (narrow != value) {
2156+
return narrow;
2157+
}
2158+
}
21492159
// Identity call will handle the case where truncation is not needed.
21502160
return LoadNode::Ideal(phase, can_reshape);
21512161
}
@@ -2171,12 +2181,14 @@ const Type* LoadUSNode::Value(PhaseGVN* phase) const {
21712181
// with the value stored truncated to a short. If no truncation is
21722182
// needed, the replacement is done in LoadNode::Identity().
21732183
//
2174-
Node *LoadSNode::Ideal(PhaseGVN *phase, bool can_reshape) {
2184+
Node* LoadSNode::Ideal(PhaseGVN* phase, bool can_reshape) {
21752185
Node* mem = in(MemNode::Memory);
21762186
Node* value = can_see_stored_value(mem,phase);
2177-
if( value && !phase->type(value)->higher_equal( _type ) ) {
2178-
Node *result = phase->transform( new LShiftINode(value, phase->intcon(16)) );
2179-
return new RShiftINode(result, phase->intcon(16));
2187+
if (value != NULL) {
2188+
Node* narrow = Compile::narrow_value(T_SHORT, value, _type, phase, false);
2189+
if (narrow != value) {
2190+
return narrow;
2191+
}
21802192
}
21812193
// Identity call will handle the case where truncation is not needed.
21822194
return LoadNode::Ideal(phase, can_reshape);

src/hotspot/share/opto/parse2.cpp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2586,19 +2586,18 @@ void Parse::do_one_bytecode() {
25862586
case Bytecodes::_i2b:
25872587
// Sign extend
25882588
a = pop();
2589-
a = _gvn.transform( new LShiftINode(a,_gvn.intcon(24)) );
2590-
a = _gvn.transform( new RShiftINode(a,_gvn.intcon(24)) );
2591-
push( a );
2589+
a = Compile::narrow_value(T_BYTE, a, NULL, &_gvn, true);
2590+
push(a);
25922591
break;
25932592
case Bytecodes::_i2s:
25942593
a = pop();
2595-
a = _gvn.transform( new LShiftINode(a,_gvn.intcon(16)) );
2596-
a = _gvn.transform( new RShiftINode(a,_gvn.intcon(16)) );
2597-
push( a );
2594+
a = Compile::narrow_value(T_SHORT, a, NULL, &_gvn, true);
2595+
push(a);
25982596
break;
25992597
case Bytecodes::_i2c:
26002598
a = pop();
2601-
push( _gvn.transform( new AndINode(a,_gvn.intcon(0xFFFF)) ) );
2599+
a = Compile::narrow_value(T_CHAR, a, NULL, &_gvn, true);
2600+
push(a);
26022601
break;
26032602

26042603
case Bytecodes::_i2f:
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
* Copyright (c) 2021, Red Hat, Inc. 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+
24+
/**
25+
* @test
26+
* @bug 8261812
27+
* @summary C2 compilation fails with assert(!had_error) failed: bad dominance
28+
*
29+
* @run main/othervm -XX:-BackgroundCompilation TestValAtSafepointOverflowsInt
30+
*
31+
*/
32+
33+
public class TestValAtSafepointOverflowsInt {
34+
private static volatile int volatileField;
35+
36+
public static void main(String[] args) {
37+
for (int i = 0; i < 20_000; i++) {
38+
testByte(true, false);
39+
testByte(false, false);
40+
testShort(true, false);
41+
testShort(false, false);
42+
testChar(true, false);
43+
testChar(false, false);
44+
}
45+
testByte(true, true);
46+
testShort(true, true);
47+
testChar(true, true);
48+
}
49+
50+
private static Object testByte(boolean flag, boolean flag2) {
51+
int i;
52+
// loop to delay constant folding
53+
for (i = 0; i < 9; i++) {
54+
}
55+
C obj = new C();
56+
if (flag) {
57+
obj.byteField = (byte)(1 << i);
58+
} else {
59+
obj.byteField = (byte)(1 << (i+1));
60+
}
61+
// Phi for byte here for uncommon trap in never taken path below
62+
// Phi inputs don't fit in a byte. Phi transfomed to top.
63+
if (flag2) {
64+
return obj;
65+
}
66+
return null;
67+
}
68+
69+
private static Object testShort(boolean flag, boolean flag2) {
70+
int i;
71+
for (i = 0; i < 17; i++) {
72+
}
73+
C obj = new C();
74+
if (flag) {
75+
obj.shortField = (short)(1 << i);
76+
} else {
77+
obj.shortField = (short)(1 << (i+1));
78+
}
79+
if (flag2) {
80+
return obj;
81+
}
82+
return null;
83+
}
84+
85+
private static Object testChar(boolean flag, boolean flag2) {
86+
int i;
87+
for (i = 0; i < 17; i++) {
88+
}
89+
C obj = new C();
90+
if (flag) {
91+
obj.charField = (char)(1 << i);
92+
} else {
93+
obj.charField = (char)(1 << (i+1));
94+
}
95+
if (flag2) {
96+
return obj;
97+
}
98+
return null;
99+
}
100+
101+
102+
static class C {
103+
byte byteField;
104+
short shortField;
105+
char charField;
106+
}
107+
108+
}

0 commit comments

Comments
 (0)