/*
 * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.
 * Copyright (c) 2021, 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 8263707
 * @summary Test range check for constant array and NewMultiArray is removed properly
 * @author Hui Shi
 *
 * @requires vm.flagless
 * @requires vm.debug == true & vm.compiler1.enabled
 *
 * @library /test/lib
 *
 * @run driver compiler.c1.TestRangeCheckEliminated
 */

package compiler.c1;

import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;

public class TestRangeCheckEliminated {
    static final String eliminated = "can be fully eliminated";
    public static void main(String[] args) throws Throwable {
        boolean error = false;
        String[] procArgs = new String[] {
            "-XX:CompileCommand=compileonly,*test_constant_array::constant_array_rc",
            "-XX:TieredStopAtLevel=1",
            "-XX:+TraceRangeCheckElimination",
            "-XX:-BackgroundCompilation",
            "-XX:CompileThreshold=500",
            test_constant_array.class.getName()
         };

        ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(procArgs);
        String output = new OutputAnalyzer(pb.start()).getOutput();
        // should have 2 "can be fully eliminated"
        System.out.println(output);
        if ((output.split(eliminated, -1).length - 1) == 2) {
            System.out.println("test_constant_array pass");
        } else {
            System.out.println("test_constant_array fail");
            error = true;
        }

        procArgs = new String[] {
            "-XX:CompileCommand=compileonly,*test_multi_constant_array::multi_constant_array_rc",
            "-XX:TieredStopAtLevel=1",
            "-XX:+TraceRangeCheckElimination",
            "-XX:-BackgroundCompilation",
            "-XX:CompileThreshold=500",
            test_multi_constant_array.class.getName()
        };

        pb = ProcessTools.createLimitedTestJavaProcessBuilder(procArgs);
        output = new OutputAnalyzer(pb.start()).getOutput();
        // should have 1 "can be fully eliminated"
        System.out.println(output);
        if ((output.split(eliminated, -1).length - 1) == 1) {
            System.out.println("test_multi_constant_array pass");
        } else {
            System.out.println("test_multi_constant_array fail");
            error = true;
        }

        procArgs = new String[] {
            "-XX:CompileCommand=compileonly,*test_multi_new_array::multi_new_array_rc",
            "-XX:TieredStopAtLevel=1",
            "-XX:+TraceRangeCheckElimination",
            "-XX:-BackgroundCompilation",
            "-XX:CompileThreshold=500",
            test_multi_new_array.class.getName()
         };

        pb = ProcessTools.createLimitedTestJavaProcessBuilder(procArgs);
        output = new OutputAnalyzer(pb.start()).getOutput();
        // should have 2 "can be fully eliminated"
        System.out.println(output);
        if ((output.split(eliminated, -1).length - 1) == 2) {
            System.out.println("test_multi_new_array pass");
        } else {
            System.out.println("test_multi_new_array fail");
            error = true;
        }

        if (error) {
            throw new InternalError();
        }
    }

    public static class test_constant_array {
        static final int constant_array[] =
            {50,60,55,67,70,62,65,70,70,81,72,66,77,80,69};
        static void constant_array_rc() {
            constant_array[1] += 5;
        }

        public static void main(String[] args) {
            for(int i = 0; i < 1_000; i++) {
                constant_array_rc();
            }
        }
    }

    public static class test_multi_constant_array {
        static final int constant_multi_array[][] = {
            {50,60,55,67,70}, {62,65,70,70,81}, {72,66,77,80,69}};
        static void multi_constant_array_rc() {
            constant_multi_array[2][3] += 5;
        }

        public static void main(String[] args) {
            for(int i = 0; i < 1_000; i++) {
                multi_constant_array_rc();
            }
        }
    }

    public static class test_multi_new_array {
        static void foo(int i) {}
        static void multi_new_array_rc(int index) {
            int na[] = new int[800];
            int nma[][] = new int[600][2];
            nma[20][1] += 5;   // optimize rc on NewMultiArray first dimension
            nma[index][0] = 0; // index < 600 after this statement
            foo(na[index]);    // index must < 800, remove rc
        }

        public static void main(String[] args) {
            for(int i = 0; i < 600; i++) {
                multi_new_array_rc(i);
            }
        }
    }
}