Skip to content

Commit de58009

Browse files
committed
8351468: C2: array fill optimization assigns wrong type to intrinsic call
Reviewed-by: epeter, thartmann, qamai
1 parent a875733 commit de58009

File tree

3 files changed

+489
-3
lines changed

3 files changed

+489
-3
lines changed

src/hotspot/share/opto/loopTransform.cpp

+14-3
Original file line numberDiff line numberDiff line change
@@ -3567,6 +3567,16 @@ bool PhaseIdealLoop::match_fill_loop(IdealLoopTree* lpt, Node*& store, Node*& st
35673567
return false;
35683568
}
35693569

3570+
if (msg == nullptr && store->as_Mem()->is_mismatched_access()) {
3571+
// This optimization does not currently support mismatched stores, where the
3572+
// type of the value to be stored differs from the element type of the
3573+
// destination array. Such patterns arise for example from memory segment
3574+
// initialization. This limitation could be overcome by extending this
3575+
// function's address matching logic and ensuring that the fill intrinsic
3576+
// implementations support mismatched array filling.
3577+
msg = "mismatched store";
3578+
}
3579+
35703580
if (msg == nullptr && head->stride_con() != 1) {
35713581
// could handle negative strides too
35723582
if (head->stride_con() < 0) {
@@ -3589,7 +3599,8 @@ bool PhaseIdealLoop::match_fill_loop(IdealLoopTree* lpt, Node*& store, Node*& st
35893599
}
35903600

35913601
// Make sure there is an appropriate fill routine
3592-
BasicType t = store->as_Mem()->memory_type();
3602+
BasicType t = msg == nullptr ?
3603+
store->adr_type()->isa_aryptr()->elem()->array_element_basic_type() : T_VOID;
35933604
const char* fill_name;
35943605
if (msg == nullptr &&
35953606
StubRoutines::select_fill_function(t, false, fill_name) == nullptr) {
@@ -3635,7 +3646,7 @@ bool PhaseIdealLoop::match_fill_loop(IdealLoopTree* lpt, Node*& store, Node*& st
36353646
if (value != head->phi()) {
36363647
msg = "unhandled shift in address";
36373648
} else {
3638-
if (type2aelembytes(store->as_Mem()->memory_type(), true) != (1 << n->in(2)->get_int())) {
3649+
if (type2aelembytes(t, true) != (1 << n->in(2)->get_int())) {
36393650
msg = "scale doesn't match";
36403651
} else {
36413652
found_index = true;
@@ -3841,7 +3852,7 @@ bool PhaseIdealLoop::intrinsify_fill(IdealLoopTree* lpt) {
38413852
#endif
38423853
}
38433854

3844-
BasicType t = store->as_Mem()->memory_type();
3855+
BasicType t = store->adr_type()->isa_aryptr()->elem()->array_element_basic_type();
38453856
bool aligned = false;
38463857
if (offset != nullptr && head->init_trip()->is_Con()) {
38473858
int element_size = type2aelembytes(t);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. 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+
package compiler.loopopts;
25+
26+
import jdk.test.lib.Asserts;
27+
28+
/**
29+
* @test
30+
* @bug 8351468
31+
* @summary Test that loads anti-dependent on array fill intrinsics are
32+
* scheduled correctly, for different load and array fill types.
33+
* See detailed comments in testShort() below.
34+
* @library /test/lib
35+
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions
36+
* -Xbatch -XX:-TieredCompilation
37+
* -XX:CompileOnly=compiler.loopopts.TestArrayFillAntiDependence::test*
38+
* -XX:CompileCommand=quiet -XX:LoopUnrollLimit=0 -XX:+OptimizeFill
39+
* compiler.loopopts.TestArrayFillAntiDependence
40+
* @run main/othervm compiler.loopopts.TestArrayFillAntiDependence
41+
*/
42+
43+
public class TestArrayFillAntiDependence {
44+
45+
static int N = 10;
46+
static short M = 4;
47+
static boolean BOOLEAN_VAL = true;
48+
static char CHAR_VAL = 42;
49+
static float FLOAT_VAL = 42.0f;
50+
static double DOUBLE_VAL = 42.0;
51+
static byte BYTE_VAL = 42;
52+
static short SHORT_VAL = 42;
53+
static int INT_VAL = 42;
54+
static long LONG_VAL = 42;
55+
56+
static boolean testBoolean(int pos, int samePos) {
57+
assert pos == samePos;
58+
boolean total = false;
59+
boolean[] array = new boolean[N];
60+
array[pos] = BOOLEAN_VAL;
61+
for (int i = 0; i < M; i++) {
62+
total |= array[samePos];
63+
for (int t = 0; t < array.length; t++) {
64+
array[t] = false;
65+
}
66+
}
67+
return total;
68+
}
69+
70+
static char testChar(int pos, int samePos) {
71+
assert pos == samePos;
72+
char total = 0;
73+
char[] array = new char[N];
74+
array[pos] = CHAR_VAL;
75+
for (int i = 0; i < M; i++) {
76+
total += array[samePos];
77+
for (int t = 0; t < array.length; t++) {
78+
array[t] = 0;
79+
}
80+
}
81+
return total;
82+
}
83+
84+
static float testFloat(int pos, int samePos) {
85+
assert pos == samePos;
86+
float total = 0.0f;
87+
float[] array = new float[N];
88+
array[pos] = FLOAT_VAL;
89+
for (int i = 0; i < M; i++) {
90+
total += array[samePos];
91+
for (int t = 0; t < array.length; t++) {
92+
array[t] = 0.0f;
93+
}
94+
}
95+
return total;
96+
}
97+
98+
static double testDouble(int pos, int samePos) {
99+
assert pos == samePos;
100+
double total = 0.0;
101+
double[] array = new double[N];
102+
array[pos] = DOUBLE_VAL;
103+
for (int i = 0; i < M; i++) {
104+
total += array[samePos];
105+
for (int t = 0; t < array.length; t++) {
106+
array[t] = 0.0;
107+
}
108+
}
109+
return total;
110+
}
111+
112+
static byte testByte(int pos, int samePos) {
113+
assert pos == samePos;
114+
byte total = 0;
115+
byte[] array = new byte[N];
116+
array[pos] = BYTE_VAL;
117+
for (int i = 0; i < M; i++) {
118+
total += array[samePos];
119+
for (int t = 0; t < array.length; t++) {
120+
array[t] = 0;
121+
}
122+
}
123+
return total;
124+
}
125+
126+
static short testShort(int pos, int samePos) {
127+
// This pre-condition is necessary to reproduce the miscompilation, but
128+
// should not be exploited by C2 for optimization.
129+
assert pos == samePos;
130+
short total = 0;
131+
short[] array = new short[N];
132+
array[pos] = SHORT_VAL;
133+
for (int i = 0; i < M; i++) {
134+
// This load is wrongly scheduled after the loop below, which is
135+
// transformed into a call to arrayof_jshort_fill and clears the
136+
// entire array. As a consequence, the function returns 0 instead of
137+
// the expected SHORT_VAL.
138+
// The load is wrongly allowed to be moved beyond the loop
139+
// (arrayof_jshort_fill call) because their anti-dependence is
140+
// missed. This is because the call operates on a different memory
141+
// slice (char[] instead of the expected short[]).
142+
total += array[samePos];
143+
for (int t = 0; t < array.length; t++) {
144+
array[t] = 0;
145+
}
146+
}
147+
return total;
148+
}
149+
150+
static int testInt(int pos, int samePos) {
151+
assert pos == samePos;
152+
int total = 0;
153+
int[] array = new int[N];
154+
array[pos] = INT_VAL;
155+
for (int i = 0; i < M; i++) {
156+
total += array[samePos];
157+
for (int t = 0; t < array.length; t++) {
158+
array[t] = 0;
159+
}
160+
}
161+
return total;
162+
}
163+
164+
static long testLong(int pos, int samePos) {
165+
assert pos == samePos;
166+
long total = 0;
167+
long[] array = new long[N];
168+
array[pos] = LONG_VAL;
169+
for (int i = 0; i < M; i++) {
170+
total += array[samePos];
171+
for (int t = 0; t < array.length; t++) {
172+
array[t] = 0;
173+
}
174+
}
175+
return total;
176+
}
177+
178+
public static void main(String[] args) {
179+
for (int i = 0; i < 10_000; i++) {
180+
boolean result = testBoolean(0, 0);
181+
Asserts.assertEquals(BOOLEAN_VAL, result);
182+
}
183+
for (int i = 0; i < 10_000; i++) {
184+
char result = testChar(0, 0);
185+
Asserts.assertEquals(CHAR_VAL, result);
186+
}
187+
for (int i = 0; i < 10_000; i++) {
188+
float result = testFloat(0, 0);
189+
Asserts.assertEquals(FLOAT_VAL, result);
190+
}
191+
for (int i = 0; i < 10_000; i++) {
192+
double result = testDouble(0, 0);
193+
Asserts.assertEquals(DOUBLE_VAL, result);
194+
}
195+
for (int i = 0; i < 10_000; i++) {
196+
byte result = testByte(0, 0);
197+
Asserts.assertEquals(BYTE_VAL, result);
198+
}
199+
for (int i = 0; i < 10_000; i++) {
200+
short result = testShort(0, 0);
201+
Asserts.assertEquals(SHORT_VAL, result);
202+
}
203+
for (int i = 0; i < 10_000; i++) {
204+
int result = testInt(0, 0);
205+
Asserts.assertEquals(INT_VAL, result);
206+
}
207+
for (int i = 0; i < 10_000; i++) {
208+
long result = testLong(0, 0);
209+
Asserts.assertEquals(LONG_VAL, result);
210+
}
211+
}
212+
}

0 commit comments

Comments
 (0)