|
| 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.superword; |
| 25 | + |
| 26 | +import java.lang.foreign.*; |
| 27 | +import java.util.Set; |
| 28 | + |
| 29 | +import compiler.lib.ir_framework.*; |
| 30 | +import compiler.lib.verify.*; |
| 31 | + |
| 32 | +/* |
| 33 | + * @test |
| 34 | + * @bug 8369902 |
| 35 | + * @summary Bug in MemPointerParser::canonicalize_raw_summands let to wrong results or assert. |
| 36 | + * @library /test/lib / |
| 37 | + * @run driver compiler.loopopts.superword.TestMemorySegmentFilterSummands |
| 38 | + */ |
| 39 | + |
| 40 | +public class TestMemorySegmentFilterSummands { |
| 41 | + |
| 42 | + static long init = 1000; |
| 43 | + static long limit = 9000; |
| 44 | + |
| 45 | + static long invar0 = 0; |
| 46 | + static long invar1 = 0; |
| 47 | + static long invar2 = 0; |
| 48 | + static long invar3 = 0; |
| 49 | + static long invar4 = 0; |
| 50 | + static long invarX = 0; |
| 51 | + |
| 52 | + public static final long BIG = 0x200000000L; |
| 53 | + public static long big = -BIG; |
| 54 | + |
| 55 | + static MemorySegment a1 = Arena.ofAuto().allocate(10_000); |
| 56 | + static MemorySegment b1 = Arena.ofAuto().allocate(10_000); |
| 57 | + static { |
| 58 | + for (long i = init; i < limit; i++) { |
| 59 | + a1.set(ValueLayout.JAVA_BYTE, i, (byte)((i & 0xf) + 1)); |
| 60 | + } |
| 61 | + } |
| 62 | + |
| 63 | + static MemorySegment a2 = MemorySegment.ofArray(new byte[40_000]); |
| 64 | + static MemorySegment b2 = a2; |
| 65 | + |
| 66 | + public static void main(String[] args) { |
| 67 | + TestFramework f = new TestFramework(); |
| 68 | + f.addFlags("-XX:+IgnoreUnrecognizedVMOptions"); |
| 69 | + f.addCrossProductScenarios(Set.of("-XX:-AlignVector", "-XX:+AlignVector"), |
| 70 | + Set.of("-XX:-ShortRunningLongLoop", "-XX:+ShortRunningLoop")); |
| 71 | + f.start(); |
| 72 | + } |
| 73 | + |
| 74 | + @Test |
| 75 | + @IR(counts = {IRNode.STORE_VECTOR, "> 0", |
| 76 | + IRNode.LOAD_VECTOR_B, "> 0", |
| 77 | + ".*multiversion.*", "= 0"}, // AutoVectorization Predicate SUFFICES, there is no aliasing |
| 78 | + phase = CompilePhase.PRINT_IDEAL, |
| 79 | + applyIfPlatform = {"64-bit", "true"}, |
| 80 | + applyIf = {"AlignVector", "false"}, |
| 81 | + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) |
| 82 | + public static void test1() { |
| 83 | + long invar = 0; |
| 84 | + invar += invarX; // cancles out with above |
| 85 | + invar += invar0; |
| 86 | + invar += invar1; |
| 87 | + invar += invar2; |
| 88 | + invar += invar3; |
| 89 | + invar += invar4; |
| 90 | + invar -= invarX; // cancles out with above |
| 91 | + // invar contains a raw summand for invarX, which has a scaleL=0. It needs to be filtered out. |
| 92 | + // The two occurances of invarX are conveniently put in a long chain, so that IGVN cannot see |
| 93 | + // that they cancle out, so that they are not optimized out before loop-opts. |
| 94 | + for (long i = init; i < limit; i++) { |
| 95 | + byte v = a1.get(ValueLayout.JAVA_BYTE, i + invar); |
| 96 | + b1.set(ValueLayout.JAVA_BYTE, i + invar, v); |
| 97 | + } |
| 98 | + } |
| 99 | + |
| 100 | + @Check(test = "test1") |
| 101 | + static void check1() { |
| 102 | + Verify.checkEQ(a1, b1); |
| 103 | + } |
| 104 | + |
| 105 | + @Test |
| 106 | + @IR(failOn = {IRNode.STORE_VECTOR}) |
| 107 | + // This test could in principle show vectorization, but it would probably need to do some special |
| 108 | + // tricks to only vectorize around the overlap. Still, it could happen that at some point we end |
| 109 | + // up multiversioning, and having a vectorized loop that is never entered. |
| 110 | + // |
| 111 | + // For now, the long constant BIG leads to an invalid VPointer, which means we do not vectorize. |
| 112 | + static void test2() { |
| 113 | + // At runtime, "BIG + big" is zero. But BIG is a long constant that cannot be represented as |
| 114 | + // an int, and so the scaleL NoOverflowInt is a NaN. We should not filter it out from the summands, |
| 115 | + // but instead make the MemPointer / VPointer invalid, which prevents vectorization. |
| 116 | + long adr = 4L * 5000 + BIG + big; |
| 117 | + |
| 118 | + for (long i = init; i < limit; i++) { |
| 119 | + // The reference to a2 iterates linearly, while the reference to "b2" stays at the same adr. |
| 120 | + // But the two alias: in the middle of the "a2" range it crosses over "b2" adr, so the |
| 121 | + // aliasing runtime check (if we generate one) should fail. But if "BIG" is just filtered |
| 122 | + // out from the summands, we instead just create a runtime check without it, which leads |
| 123 | + // to a wrong answer, and the check does not fail, and we get wrong results. |
| 124 | + a2.set(ValueLayout.JAVA_INT_UNALIGNED, 4L * i, 0); |
| 125 | + int v = b2.get(ValueLayout.JAVA_INT_UNALIGNED, adr); |
| 126 | + b2.set(ValueLayout.JAVA_INT_UNALIGNED, adr, v + 1); |
| 127 | + } |
| 128 | + } |
| 129 | + |
| 130 | + @Check(test = "test2") |
| 131 | + static void check2() { |
| 132 | + int s = 0; |
| 133 | + for (long i = init; i < limit; i++) { |
| 134 | + s += a2.get(ValueLayout.JAVA_INT_UNALIGNED, 4L * i); |
| 135 | + } |
| 136 | + if (s != 4000) { |
| 137 | + throw new RuntimeException("wrong value"); |
| 138 | + } |
| 139 | + } |
| 140 | +} |
0 commit comments