1 /*
  2  * Copyright (c) 2023, 2024, 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 /**
 25  * @test
 26  * @bug JDK-8310130
 27  * @summary Special test cases for PhaseIdealLoop::move_unordered_reduction_out_of_loop
 28  *          Here a case with partial vectorization of the reduction.
 29  * @library /test/lib /
 30  * @run driver compiler.loopopts.superword.TestUnorderedReductionPartialVectorization
 31  */
 32 
 33 package compiler.loopopts.superword;
 34 
 35 import compiler.lib.ir_framework.*;
 36 
 37 public class TestUnorderedReductionPartialVectorization {
 38     static final int RANGE = 1024;
 39     static final int ITER  = 10;
 40 
 41     public static void main(String[] args) {
 42         TestFramework.runWithFlags("-XX:+UnlockExperimentalVMOptions", "-XX:-UseCompactObjectHeaders", "-XX:-AlignVector");
 43         TestFramework.runWithFlags("-XX:+UnlockExperimentalVMOptions", "-XX:-UseCompactObjectHeaders", "-XX:+AlignVector");
 44         TestFramework.runWithFlags("-XX:+UnlockExperimentalVMOptions", "-XX:+UseCompactObjectHeaders", "-XX:-AlignVector");
 45         TestFramework.runWithFlags("-XX:+UnlockExperimentalVMOptions", "-XX:+UseCompactObjectHeaders", "-XX:+AlignVector");
 46     }
 47 
 48     @Run(test = {"test1"})
 49     @Warmup(0)
 50     public void runTests() throws Exception {
 51         int[] data = new int[RANGE];
 52 
 53         init(data);
 54         for (int i = 0; i < ITER; i++) {
 55             long r1 = test1(data, i);
 56             long r2 = ref1(data, i);
 57             if (r1 != r2) {
 58                 throw new RuntimeException("Wrong result test1: " + r1 + " != " + r2);
 59             }
 60         }
 61     }
 62 
 63     @Test
 64     @IR(counts = {IRNode.LOAD_VECTOR_I,   IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0",
 65                   IRNode.VECTOR_CAST_I2L, IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0",
 66                   IRNode.OR_REDUCTION_V,                                                 "> 0",},
 67         applyIfPlatform = {"64-bit", "true"},
 68         applyIfCPUFeatureOr = {"avx2", "true"})
 69     static long test1(int[] data, long sum) {
 70         for (int i = 0; i < data.length; i+=2) {
 71             // Mixing int and long ops means we only end up allowing half of the int
 72             // loads in one pack, and we have two int packs. The first pack has one
 73             // of the pairs missing because of the store, which creates a dependency.
 74             // The first pack is rejected and left as scalar, the second pack succeeds
 75             // with vectorization. That means we have a mixed scalar/vector reduction
 76             // chain. This way it is possible that a vector-reduction has a scalar
 77             // reduction as input, which is neigher a phi nor a vector reduction.
 78             // In such a case, we must bail out of the optimization in
 79             // PhaseIdealLoop::move_unordered_reduction_out_of_loop
 80             int v = data[i]; // int read
 81             data[0] = 0;     // ruin the first pack
 82             sum |= v;        // long reduction (and implicit cast from int to long)
 83 
 84             // This example used to rely on that reductions were ignored in SuperWord::unrolling_analysis,
 85             // and hence the largest data type in the loop was the ints. This would then unroll the doubles
 86             // for twice the vector length, and this resulted in us having twice as many packs. Because of
 87             // the store "data[0] = 0", the first packs were destroyed, since they do not have power of 2
 88             // size.
 89             // Now, we no longer ignore reductions, and now we unroll half as much before SuperWord. This
 90             // means we would only get one pack per operation, and that one would get ruined, and we have
 91             // no vectorization. We now ensure there are again 2 packs per operation with a 2x hand unroll.
 92             int v2 = data[i + 1];
 93             sum |= v2;
 94         }
 95         return sum;
 96     }
 97 
 98     static long ref1(int[] data, long sum) {
 99         for (int i = 0; i < data.length; i++) {
100             int v = data[i];
101             data[0] = 0;
102             sum |= v;
103         }
104         return sum;
105     }
106 
107     static void init(int[] data) {
108         for (int i = 0; i < RANGE; i++) {
109             data[i] = i + 1;
110         }
111     }
112 }