diff --git a/test/functional/MicroJIT/.gitignore b/test/functional/MicroJIT/.gitignore new file mode 100644 index 00000000000..4a787cbf68a --- /dev/null +++ b/test/functional/MicroJIT/.gitignore @@ -0,0 +1,28 @@ +################################################################################ +# Copyright (c) 2023, 2023 IBM Corp. and others +# +# This program and the accompanying materials are made available under +# the terms of the Eclipse Public License 2.0 which accompanies this +# distribution and is available at https://www.eclipse.org/legal/epl-2.0/ +# or the Apache License, Version 2.0 which accompanies this distribution and +# is available at https://www.apache.org/licenses/LICENSE-2.0. +# +# This Source Code may also be made available under the following +# Secondary Licenses when the conditions for such availability set +# forth in the Eclipse Public License, v. 2.0 are satisfied: GNU +# General Public License, version 2 with the GNU Classpath +# Exception [1] and GNU General Public License, version 2 with the +# OpenJDK Assembly Exception [2]. +# +# [1] https://www.gnu.org/software/classpath/license.html +# [2] http://openjdk.java.net/legal/assembly-exception.html +# +# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception +################################################################################ + +build +.do +*.dmp +javacore.* +Snap* +failures.log diff --git a/test/functional/MicroJIT/README.md b/test/functional/MicroJIT/README.md new file mode 100644 index 00000000000..ef9fe4ee2c0 --- /dev/null +++ b/test/functional/MicroJIT/README.md @@ -0,0 +1,322 @@ + + +# MicroJIT Regression Tests + +## Quick Start + +Export your JAVA_HOME and MJIT_JAVA_BINARY environment variables and run `make all` to compile classes in `./build` directory. The `./run.sh` command will run all the tests in the `src/tests` directory. + +```bash +export JAVA_HOME=; +export CONF=release; +export MJIT_JAVA_BINARY="/openj9-openjdk-jdk8/build/linux-x86_64-normal-server-${CONF}/images/j2sdk-image/bin/java"; +make all; +./run.sh; +``` + +> Note: `CONF` can be one of release, slowdebug or fastdebug. See `./configure` help in `/openj9-openjdk-jdk8/`. + +--- + +## Usage + +### Table of Contents + +- [Running Individual Tests](#running-individual-tests) +- [Running with GDB](#running-with-gdb) +- [Project Structure](#project-structure) +- [JUnit Classes](#junit-classes) +- [test-list.txt Format](#test-list.txt-format) +- [Helpful Tips](#helpful-tips) + +### Running Individual Tests + +Tests can be run individually by passing the method signature to `run.sh`: + +```bash +./run.sh +./run.sh . +./run.sh ... +./run.sh +``` + +#### Example + +```bash +./run.sh add +``` + +The above command will run all tests with the add signature. + +#### Example + +```bash +./run.sh IntTests.add +``` + +The above command will run only the IntTests.add test. You can also provide a list of tests to perform. + +#### Example + +```bash +./run.sh add sub mul +``` + +Passing the class name will run all tests in the given file: + +#### Example + +```bash +./run.sh IntTests +``` + +This feature also works for debugging with gdb. + +### Running with GDB + +The `run.sh` script also works with gdb as follows: + +```bash +export MJIT_DEBUG_ENABLED=true; +./run.sh; +``` + +It will prompt you for each test to ask if you'd like to launch gdb: + +```bash +Using JVM: +openjdk version "1.8.0_342-internal" +OpenJDK Runtime Environment (build 1.8.0_342-internal-test_2022_06_02_09_41-b00) +Eclipse OpenJ9 VM (build microjit-rebased-0de87ac1b, JRE 1.8.0 Linux amd64-64-Bit Compressed References 20220602_000000 (JIT enabled, AOT enabled) +OpenJ9 - 0de87ac1b +OMR - 5432ae76a +JCL - 1a5e46c542 based on jdk8u342-b01) + +Running tests (n=30000,threshold=3)... + +Running using gdb BranchTests.gotoTestI Y/n [n]: ... skipping +Running using gdb ConversionTests.i2lJ Y/n [n]:y +GNU gdb (Ubuntu 10.2-0ubuntu1~18.04~2) 10.2 +Copyright (C) 2021 Free Software Foundation, Inc. + +[... snip] + +Reading symbols from /workspace/openj9-openjdk-jdk8/build/linux-x86_64-normal-server-release/images/j2sdk-image/bin/java... +(No debugging symbols found in /workspace/openj9-openjdk-jdk8/build/linux-x86_64-normal-server-release/images/j2sdk-image/bin/java) +(gdb) +``` + +> Note: You must run through the program once before setting any breakpoints, as the debug symbols are dynamically loaded. + +> To quit from `run.sh`, press Ctrl+C. + +### Project Structure + +```bash +├── build +│   ├── .class +│   ├── ... +├── .do +│   ├── +│   │   └── +│   │   ├── cmd +│   │   ├── debug.sh +│   │   ├── limit +│   │   ├── mjit.log.454115.12822.20200709.134022.454115 +│   │   ├── result_env +│   │   ├── run.err +│   │   ├── run.log +│   │   └── test.sh +│   └── pid +│   │   ├── currently_alive_test +├── lib +│   └── junit-platform-console-standalone-1.6.0.jar +├── makefile +├── README.md +├── run.sh +├── run-tests.sh +├── src +│   ├── Helper.java +│   ├── lib +│   | ├── .class +│   | ├── .java +│   | ├── ... +│   └── tests +│   ├── .java +│   ├── ... +└── test-list.txt +``` + +### JUnit Classes + +To implement new test cases, you must add a new Java method to the `src/tests` directory. The method can be added to an existing `.java` file, or a new file can be created. When creating new files, you must import the following JUnit libraries: + +#### Example Java Test Class + +```java +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +public class { + + @Tag("") + @Order(1) + @ParameterizedTest(name = "#{index} - ({0},{1}) = {2}") + @CsvSource({ + /* + * Each line is a JUnit test parameter and will be executed + * as indicated in @ParameterizedTest. Each line has its + * own unique index + */ + "<{0}>, <{1}>, <{2}>", + // Example + "1, 1, 2" + }) + public void (int arg1, int arg2, int expected){ + int result = 0; + for(int i = 0; i < Helper.invocations(); i++) { + result = (arg1, arg2); + } + assertEquals(expected, result); + } + + public static int (int x, int y){ + // method-body + } + +} +``` + +#### JUnit Tags + +JUnit tags must be of the form `methodNamereturnType` +where: + +- `methodName` must match the method you want to compile with MicroJIT. +- `` must match the types of variables you are passing. +- `returnType` must match the type of return value. + +where `Types` are: + +| Type | Meaning | +|:-----------------:|:-------------------------------------------:| +| **B** |
`byte`
| +| **C** |
`char`
| +| **D** |
`double`
| +| **F** |
`float`
| +| **I** |
`int`
| +| **J** |
`long`
| +| **L ClassName ;** | reference -> an instance of class ClassName | +| **S** |
`short`
| +| **Z** |
`boolean`
| +| **[** | reference -> one array dimension | + +Add the method JUNIT tags and class names to the test-list.txt. + +

test-list.txt Format

+ +```txt +# This is a comment +. + +# This test has one dependency +.: [ . ] + +# This test has multiple dependencies +.: [ ., . ] +``` + +> Note: Dependency array is only relevant if your test is dependent on another method, i.e., if you need to first warm up another method. You can also make a test dependent on itself, if you'd like to run the test multiple times on one VM session. + +#### Example + +```txt +LongTests.xorJ +GetPutStaticTests.add<>I: [ GetPutStaticTests.setIntsV ] +``` + +and their matching JUnit tags: + +```Java +public class LongTests { + // [... snip] + @Tag("xorJ") + @Order(1) + // [... snip] + public static long xor(long x, long y); + // [... snip] +} +``` + +```Java +public class GetPutStaticTests { + // [... snip] + @Tag("add<>I") + @Order(2) + // [... snip] + public static int add(); + // [... snip] + @Tag("setIntsV") + @Order(1) + // [... snip] + public static void setInts(int arg1, int arg2); +} +``` + +In this example, `setInts` must be warmed up before `add` for the GetPutStaticTests because of its dependency, so it gets `@Order(1)` and `add` gets `@Order(2)`. + +### Helpful Tips + +After running a test, the log files will appear in the .do file directory. If a test fails, it can be helpful to check the log files to find out what happened. + +#### `✔` + + > Your test passed! + +#### `✗ : Not compiled by MicroJIT` + + > The mjit.log file is a good place to start for these failures. It will show the disassembly for the method to be compiled which can be helpful, to know if you are testing the correct bytecodes, and to make sure that there are no unsupported bytecodes being used by the method. + +#### `✗ : JUnit or Java failure` + + > The run.log file will contain the JUnit test results. If there is a javacore dump file, that can be helpful too, as you will be able to see the state of all of the registers at the time the JVM crashed. + +--- + +## Adding an extra layer to testing: run-tests.sh to compile using Testarossa or MicroJIT + +```bash +./run-tests.sh +``` + +where `` is a mandatory parameter to signify which compiler to use and may take values as T/TR/M/MJIT in any case (will be ultimately converted to uppercase). +The tr.log file will be generated for TRJIT and mjit.log for MicroJIT and `` is an optional parameter which provides class and method names to the `run.sh` command, if specified. + +Hence, `./run-tests.sh ` will be executed as: +`./run.sh ` using the compiler specified in `` parameter. diff --git a/test/functional/MicroJIT/build.xml b/test/functional/MicroJIT/build.xml new file mode 100644 index 00000000000..b20b3160707 --- /dev/null +++ b/test/functional/MicroJIT/build.xml @@ -0,0 +1,82 @@ + + + + + + + + MicroJIT + + + + + + + + + + + + + + + + + Ant version is ${ant.version} + ============COMPILER SETTINGS============ + ===fork: yes + ===executable: ${compiler.javac} + ===debug: on + ===srcdir: ${src} + ===destdir: ${DEST} + ===builddir: ${build} + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/functional/MicroJIT/lib/junit-platform-console-standalone-1.6.0.jar b/test/functional/MicroJIT/lib/junit-platform-console-standalone-1.6.0.jar new file mode 100644 index 00000000000..eb9ecd225ec Binary files /dev/null and b/test/functional/MicroJIT/lib/junit-platform-console-standalone-1.6.0.jar differ diff --git a/test/functional/MicroJIT/playlist.xml b/test/functional/MicroJIT/playlist.xml new file mode 100644 index 00000000000..a6c273fa47c --- /dev/null +++ b/test/functional/MicroJIT/playlist.xml @@ -0,0 +1,40 @@ + + + + + MicroJIT + cd $(TEST_ROOT)/functional/MicroJIT; \ + ./run.sh; \ + $(TEST_STATUS) + os.linux,arch.x86,bits.64 + + extended + + + functional + + + openj9 + + + diff --git a/test/functional/MicroJIT/run-tests.sh b/test/functional/MicroJIT/run-tests.sh new file mode 100755 index 00000000000..7477f85d46a --- /dev/null +++ b/test/functional/MicroJIT/run-tests.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +################################################################################ +# Copyright (c) 2023, 2023 IBM Corp. and others +# +# This program and the accompanying materials are made available under +# the terms of the Eclipse Public License 2.0 which accompanies this +# distribution and is available at https://www.eclipse.org/legal/epl-2.0/ +# or the Apache License, Version 2.0 which accompanies this distribution and +# is available at https://www.apache.org/licenses/LICENSE-2.0. +# +# This Source Code may also be made available under the following +# Secondary Licenses when the conditions for such availability set +# forth in the Eclipse Public License, v. 2.0 are satisfied: GNU +# General Public License, version 2 with the GNU Classpath +# Exception [1] and GNU General Public License, version 2 with the +# OpenJDK Assembly Exception [2]. +# +# [1] https://www.gnu.org/software/classpath/license.html +# [2] http://openjdk.java.net/legal/assembly-exception.html +# +# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception +################################################################################ + +# Check whether compiling with TRJIT or MicroJIT + +var=${1^^} # Convert first argument to uppercase + +export MJIT_NON_BREAKING_TEST=false +if [ "$var" == "T" ] || [ "$var" == "TR" ]; then + export MJIT_NON_BREAKING_TEST=true +elif [ "$var" == "M" ] || [ "$var" == "MJIT" ]; then + export MJIT_NON_BREAKING_TEST=false +else + echo "Compiler required (as first argument): T/TR/M/MJIT" + exit 1 +fi + +./run.sh ${@:2} # Execute run.sh with all params except the first one diff --git a/test/functional/MicroJIT/run.sh b/test/functional/MicroJIT/run.sh new file mode 100755 index 00000000000..103db84a15e --- /dev/null +++ b/test/functional/MicroJIT/run.sh @@ -0,0 +1,277 @@ +#!/bin/bash + +################################################################################ +# Copyright (c) 2023, 2023 IBM Corp. and others +# +# This program and the accompanying materials are made available under +# the terms of the Eclipse Public License 2.0 which accompanies this +# distribution and is available at https://www.eclipse.org/legal/epl-2.0/ +# or the Apache License, Version 2.0 which accompanies this distribution and +# is available at https://www.apache.org/licenses/LICENSE-2.0. +# +# This Source Code may also be made available under the following +# Secondary Licenses when the conditions for such availability set +# forth in the Eclipse Public License, v. 2.0 are satisfied: GNU +# General Public License, version 2 with the GNU Classpath +# Exception [1] and GNU General Public License, version 2 with the +# OpenJDK Assembly Exception [2]. +# +# [1] https://www.gnu.org/software/classpath/license.html +# [2] http://openjdk.java.net/legal/assembly-exception.html +# +# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception +################################################################################ + +# Provide envars: +# VERBOSE: Output the log to the terminal +# MJIT_JAVA_BINARY: Full path to Java binary with MicroJIT enabled +# MJIT_LOG_FILE: Output from JVM; look here for method signature from MicroJIT. Default: mjit.log +# MJIT_INVOCATIONS: Number of times a method is run by the test driver. Default: 30000 +# MJIT_THRESHOLD: Compilation threshold. Default: 3 +# MJIT_DEBUG_ENABLED: Set to true for detailed output from OpenJ9 +# MJIT_NON_BREAKING_TEST: Set to true to test if MicroJIT changes have broken runs which do not use MicroJIT. Default: false +# JUNIT_ARGS: List of JUnit arguments +# See: https://junit.org/junit5/docs/current/user-guide/#running-tests-console-launcher +# e.g. export JUNIT_ARGS=--disable-ansi-colors # for nice Jenkins output + +# For each test defined in tests.json +# Execute TestRunner in JVM +# Result will be 0 if expected result is found, otherwise 1 (failure) +# Search $LOG_FILE for signature printed by MicroJIT +# If results == 0 and signature is found, then the function was JITed + +# Trap Ctrl+C and call ctrl_c() +trap ctrl_c INT + +SCRIPT=$(readlink -f "$0") +SCRIPTPATH=$(dirname "$SCRIPT") + +if [[ -z "$MJIT_JAVA_BINARY" ]]; then + echo "MJIT_JAVA_BINARY required." + exit 1 +fi + +JUNIT=${SCRIPTPATH}/lib/junit-platform-console-standalone-1.6.0.jar + +MJIT_INVOCATIONS=${MJIT_INVOCATIONS:-30000} + +MJIT_THRESHOLD=${MJIT_THRESHOLD:-3} + +MJIT_LOG_FILE=${MJIT_LOG_FILE:-${SCRIPTPATH}/log_file} + +MJIT_DEBUG_ENABLED=${MJIT_DEBUG_ENABLED:-false} + +MJIT_NON_BREAKING_TEST=${MJIT_NON_BREAKING_TEST:-false} + +VERBOSE=${VERBOSE:-false} + +if [ ! -f "$MJIT_JAVA_BINARY" ]; then + echo "$MJIT_JAVA_BINARY does not exist." + exit 1 +fi + +function ctrl_c() { + for pid_file in "${SCRIPTPATH}/.do/*/*/pid"; do + kill -SIGINT $(cat "${pid_file}") + rm "${pid_file}" + done + exit 127 +} + +function make_signature() { + input="$*" + j9_signature="${input//)}" + echo "+ (cold) ${j9_signature}" +} + +function extract_classname() { + echo "$*" | cut -d '.' -f 1 +} + +function extract_methodname() { + echo "$*" | cut -d '.' -f 2 +} + +echo "Using JVM:" + +eval ${MJIT_JAVA_BINARY} -version + +printf "\nRunning tests (n=${MJIT_INVOCATIONS},threshold=${MJIT_THRESHOLD})...\n\n" + +# Setup limit_file +rm -R .do || true +mkdir -p .do/pid + +grep -v '^#\|^[[:space:]]*$' test-list.txt | while read -r line ; do + signature="$(echo $line | cut -d':' -f1)" + + # Check if we passed test names + run_it=false + if [[ "_$*" == "_" ]]; then + run_it=true + else + for regexes in "$@"; do + if grep -E "${regexes}" < <( echo ${signature} ) &> /dev/null + then + run_it=true + break + fi + done + fi + + if [[ ${run_it} = true ]]; then + + # Run JVM with or without MicroJIT + mjit_arg="-Xjit:disableAsyncCompilation,traceFull" + if [[ "$MJIT_NON_BREAKING_TEST" = false ]]; then + mjit_arg+=",verbose={compilePerformance},count=10000000,mjitEnabled=1,mjitCount=$MJIT_THRESHOLD" + else + mjit_arg+=",verbose,count=2" + fi + + classname="$(extract_classname "${signature}")" + fname="$(extract_methodname "${signature}")" + this_rundir="${SCRIPTPATH}/.do/${classname}/${fname}" + mkdir -p "${this_rundir}" + + make_signature "${signature}" > "${this_rundir}/limit" + + mjit_arg+=",log='${this_rundir}/" + if [[ "$MJIT_NON_BREAKING_TEST" = false ]]; then + mjit_arg+="mjit" + else + mjit_arg+="tr" + fi + mjit_arg+=".log',limitFile='${this_rundir}/limit'" + + printf "\ +${MJIT_JAVA_BINARY} \\ + -XcompilationThreads1 \\ + ${mjit_arg} \\ + -jar $JUNIT \\ + --cp ${SCRIPTPATH}/build \\ + --disable-banner \\ + --disable-ansi-colors\ +" > "${this_rundir}/cmd" + # Dependant tests are a json array or a single test + echo $line | cut -d ':' -f2 | cut -d '[' -f2 | cut -d ']' -f1 | tr -s '[[:space:]]' | tr ',' '\n' | while read -r dependency ; do + make_signature "${dependency}" >> "${this_rundir}/limit" + + printf " \\ + --select-class='$(extract_classname "${dependency}")' \\ + --include-tag='$(extract_methodname "${dependency}")'\ +" >> "${this_rundir}/cmd" + done + + printf " \\ + --select-class='$(extract_classname "${signature}")' \\ + --include-tag='$(extract_methodname "${signature}")'\ +" >> "${this_rundir}/cmd" + + printf "\ +#!/bin/bash +export MJIT_INVOCATIONS=${MJIT_INVOCATIONS} +touch ${SCRIPTPATH}/.do/pid/\$$ + +gdb --args " > "${this_rundir}/debug.sh" +cat "${this_rundir}/cmd" >> "${this_rundir}/debug.sh" + + echo "\ +#!/bin/bash +export MJIT_INVOCATIONS=${MJIT_INVOCATIONS} +touch ${SCRIPTPATH}/.do/pid/\$$ + +pushd '${this_rundir}' &> /dev/null +echo 'Running $signature ...' + +TEST_PASSED=true +TEST_FAILURE_KIND='' +if ! source cmd 2> run.err > run.log; then + TEST_PASSED=false + TEST_FAILURE_KIND+=': JUnit or Java failure ' +fi + +if [[ "$MJIT_NON_BREAKING_TEST" = false ]]; then + if ! grep -q 'MicroJIT Compiled $j9_signature Successfully!' mjit.log*; then + TEST_PASSED=false + TEST_FAILURE_KIND+=': Not compiled by MicroJIT ' + fi +else + if ! grep -q '$j9_signature' tr.log*; then + TEST_PASSED=false + TEST_FAILURE_KIND+=': Not compiled by TRJIT ' + fi +fi + +echo \" +TEST_NAME=\\\"$signature\\\" +TEST_PASSED=\\\"\${TEST_PASSED}\\\" +TEST_FAILURE_KIND=\\\"\${TEST_FAILURE_KIND}\\\" +\" > result_env + +popd &> /dev/null +echo 'Running $signature ... Done' + +rm ${SCRIPTPATH}/.do/pid/\$$ +exit \$? +" > "${this_rundir}/test.sh" + + chmod +x "${this_rundir}/debug.sh" + chmod +x "${this_rundir}/test.sh" + fi +done + +if [[ ${MJIT_DEBUG_ENABLED} = true ]] ; then + for tests in .do/*/*/debug.sh; do + test_name="$(echo "${tests}" | sed 's+.do/++g' | sed 's+/debug.sh++g' | sed 's+/+.+g')" + printf "Running using gdb "${test_name}" Y/n [n]:" + read answer + case $answer in + Y|y|yes) + ${tests} + ;; + *) + printf "\e[1ARunning using gdb $test_name Y/n [n]: ... skipping\n" + ;; + esac + done +else + echo .do/*/*/test.sh | xargs -n1 | xargs -n1 -P$(nproc --all) -I{} /bin/bash '{}' + echo " +====================== Parsing Results ======================== +" + TESTS_FAILED=0 + + for results in $(echo .do/*/*/result_env | xargs -n1 | sort -u) ; do + source ${results} + + line='. . . . . . . . . . . . . . . . . . . . . . . . .' + printf "%s%s" $TEST_NAME "${line:${#TEST_NAME}}" + if [[ ${TEST_PASSED} = true ]]; then + printf "\033[0;32m \u2714 \033[0m\n" "${TEST_FAILURE_KIND}" + else + printf "\033[0;31m \u2717 %s\033[0m\n" "${TEST_FAILURE_KIND}" + # Don't print the JUnit container stuff + if [[ ${VERBOSE} = true ]] ; then + head -n -15 ${lines}/run.log + fi + TESTS_FAILED=$(( TESTS_FAILED + 1 )) + fi + done + + if (( TESTS_FAILED == 0 )); then + if [[ "$MJIT_NON_BREAKING_TEST" = false ]]; then + printf "Finished. All tests passed with MicroJIT!" + else + printf "Finished. All tests passed with TRJIT!" + fi + elif (( TESTS_FAILED == 1 )); then + printf "Finished with [${TESTS_FAILED}] failure." + else + printf "Finished with [${TESTS_FAILED}] failures." + fi + printf "\n\n" + + exit ${TESTS_FAILED} +fi diff --git a/test/functional/MicroJIT/src/Helper.java b/test/functional/MicroJIT/src/Helper.java new file mode 100644 index 00000000000..73274f6c0e6 --- /dev/null +++ b/test/functional/MicroJIT/src/Helper.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2023, 2023 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +public class Helper { + public static int invocations() { + return Integer.parseInt(System.getenv("MJIT_INVOCATIONS")); + } +} diff --git a/test/functional/MicroJIT/src/lib/Dup.class b/test/functional/MicroJIT/src/lib/Dup.class new file mode 100644 index 00000000000..88d76e00d2e Binary files /dev/null and b/test/functional/MicroJIT/src/lib/Dup.class differ diff --git a/test/functional/MicroJIT/src/lib/Dup.java b/test/functional/MicroJIT/src/lib/Dup.java new file mode 100644 index 00000000000..57d8704e1eb --- /dev/null +++ b/test/functional/MicroJIT/src/lib/Dup.java @@ -0,0 +1,117 @@ +/******************************************************************************* + * Copyright (c) 2023, 2023 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +/* Tests that have dependencies must be labelled as @Order(2), @Order(3)... */ +/* Tests with no dependencies are labelled as @Order(1) */ + +/* The resulting class file for this java class will be thrown away. This is only necessary for JUnit to + * be able to find and interpret the tests. The class file that will be used for testing MicroJIT will be swapped in + * after initial compilation. Said class file was created using Recaf, so that the bytecodes could be manually injected + * into the class file. After running run.sh, the decompiled bytecodes can be seen in the mjit.log file. + */ + +public class Dup { + + @Tag("dup2Form1I") + @Order(1) + public static int dup2Form1(int x, int y) { + int n = x; + int n2 = y; + return n + (n2 + (n + n2)); + } + + @Tag("dup_x1I") + @Order(1) + public static int dup_x1(int x, int y) { + int n = y; + return n + (x + n); + } + + @Tag("dup_x2Form1I") + @Order(1) + public static int dup_x2Form1(int x, int y, int z) { + int n = z; + return n + (x + (y + n)); + } + + @Tag("dup_x2Form2I") + @Order(1) + public static int dup_x2Form2(long x, int y) { + int n = y; + return n + (int)(x + (long)n); + } + + @Tag("dup2_x1Form1I") + @Order(1) + public static int dup2_x1Form1(int x, int y, int z) { + int n = y; + int n2 = z; + return n + (n2 + (x + (n + n2))); + } + + @Tag("dup2_x1Form2J") + @Order(1) + public static long dup2_x1Form2(int x, long y) { + long l = y; + return l + (long)(x + (int)l); + } + + @Tag("dup2_x2Form1I") + @Order(1) + public static int dup2_x2Form1(int w, int x, int y, int z) { + int n = y; + int n2 = z; + return n + (n2 + (w + (x + (n + n2)))); + } + + @Tag("dup2_x2Form2J") + @Order(1) + public static long dup2_x2Form2(int x, int y, long z) { + long l = z; + return l + (long)(x + (y + (int)l)); + } + + @Tag("dup2_x2Form3I") + @Order(1) + public static int dup2_x2Form3(long x, int y, int z) { + int n = y; + int n2 = z; + return n + (n2 + (int)(x + (long)(n + n2))); + } + + @Tag("dup2_x2Form4J") + @Order(1) + public static long dup2_x2Form4(long x, long y) { + long l = y; + return l + (x + l); + } + +} diff --git a/test/functional/MicroJIT/src/lib/Swap.class b/test/functional/MicroJIT/src/lib/Swap.class new file mode 100644 index 00000000000..9d7f02c41c5 Binary files /dev/null and b/test/functional/MicroJIT/src/lib/Swap.class differ diff --git a/test/functional/MicroJIT/src/lib/Swap.java b/test/functional/MicroJIT/src/lib/Swap.java new file mode 100644 index 00000000000..2745f3c04ee --- /dev/null +++ b/test/functional/MicroJIT/src/lib/Swap.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2023, 2023 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +/* The resulting class file for this java class will be thrown away. This is only necessary for JUnit to + * be able to find and interpret the tests. The class file that will be used for testing MicroJIT will be swapped in + * after initial compilation. Said class file was created using Recaf, so that the bytecodes could be manually injected + * into the class file. After running run.sh, the decompiled bytecodes can be seen in the mjit.log file. + */ + +public class Swap { + + @Tag("swapI") + @Order(1) + public static int swap(int x, int y, int z) { + x = z + y; + return x; + } + +} diff --git a/test/functional/MicroJIT/src/lib/dcmp.class b/test/functional/MicroJIT/src/lib/dcmp.class new file mode 100644 index 00000000000..4a15110f5fa Binary files /dev/null and b/test/functional/MicroJIT/src/lib/dcmp.class differ diff --git a/test/functional/MicroJIT/src/lib/dcmp.java b/test/functional/MicroJIT/src/lib/dcmp.java new file mode 100644 index 00000000000..7893811ec1c --- /dev/null +++ b/test/functional/MicroJIT/src/lib/dcmp.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2023, 2023 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +/* Tests that have dependencies must be labelled as @Order(2), @Order(3)... */ +/* Tests with no dependencies are labelled as @Order(1) */ + +/* The resulting class file for this java class will be thrown away. This is only necessary for JUnit to + * be able to find and interpret the tests. The class file that will be used for testing MicroJIT will be swapped in + * after initial compilation. Said class file was created using Recaf, so that the bytecodes could be manually injected + * into the class file. After running run.sh, the decompiled bytecodes can be seen in the mjit.log file. + */ + +// Decompiled with: CFR 0.150 +public class dcmp { + + @Tag("dcmpl
I") + @Order(1) + public static int dcmpl(double x, double y) { + return x == y ? 0 : (x > y ? 1 : -1); + } + + @Tag("dcmpl
I") + @Order(1) + public static int dcmpg(double x, double y) { + return x == y ? 0 : (x < y ? -1 : 1); + } + +} diff --git a/test/functional/MicroJIT/src/lib/fcmp.class b/test/functional/MicroJIT/src/lib/fcmp.class new file mode 100644 index 00000000000..e7b7d4201ae Binary files /dev/null and b/test/functional/MicroJIT/src/lib/fcmp.class differ diff --git a/test/functional/MicroJIT/src/lib/fcmp.java b/test/functional/MicroJIT/src/lib/fcmp.java new file mode 100644 index 00000000000..8ba1518e874 --- /dev/null +++ b/test/functional/MicroJIT/src/lib/fcmp.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2023, 2023 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +/* Tests that have dependencies must be labelled as @Order(2), @Order(3)... */ +/* Tests with no dependencies are labelled as @Order(1) */ + +/* The resulting class file for this java class will be thrown away. This is only necessary for JUnit to + * be able to find and interpret the tests. The class file that will be used for testing MicroJIT will be swapped in + * after initial compilation. Said class file was created using Recaf, so that the bytecodes could be manually injected + * into the class file. After running run.sh, the decompiled bytecodes can be seen in the mjit.log file. + */ + +// Decompiled with: CFR 0.150 +public class fcmp { + + @Tag("fcmplI") + @Order(1) + public static int fcmpl(float x, float y) { + return x == y ? 0 : (x > y ? 1 : -1); + } + + @Tag("fcmpgI") + @Order(1) + public static int fcmpg(float x, float y) { + return x == y ? 0 : (x < y ? -1 : 1); + } + +} diff --git a/test/functional/MicroJIT/src/lib/lcmp.class b/test/functional/MicroJIT/src/lib/lcmp.class new file mode 100644 index 00000000000..9f66d10eeb5 Binary files /dev/null and b/test/functional/MicroJIT/src/lib/lcmp.class differ diff --git a/test/functional/MicroJIT/src/lib/lcmp.java b/test/functional/MicroJIT/src/lib/lcmp.java new file mode 100644 index 00000000000..d8c3a0d04f2 --- /dev/null +++ b/test/functional/MicroJIT/src/lib/lcmp.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2023, 2023 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +/* Tests that have dependencies must be labelled as @Order(2), @Order(3)... */ +/* Tests with no dependencies are labelled as @Order(1) */ + +/* The resulting class file for this java class will be thrown away. This is only necessary for JUnit to + * be able to find and interpret the tests. The class file that will be used for testing MicroJIT will be swapped in + * after initial compilation. Said class file was created using Recaf, so that the bytecodes could be manually injected + * into the class file. After running run.sh, the decompiled bytecodes can be seen in the mjit.log file. + */ + +// Decompiled with: CFR 0.150 +public class lcmp { + + @Tag("lcmpI") + @Order(1) + public static int lcmp(long x, long y) { + return x == y ? 0 : (x > y ? 1 : -1); + } + +} diff --git a/test/functional/MicroJIT/src/tests/BranchTests.java b/test/functional/MicroJIT/src/tests/BranchTests.java new file mode 100644 index 00000000000..6279fcc991c --- /dev/null +++ b/test/functional/MicroJIT/src/tests/BranchTests.java @@ -0,0 +1,413 @@ +/******************************************************************************* + * Copyright (c) 2023, 2023 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +/* Tests that have dependencies must be labelled as @Order(2), @Order(3)... */ +/* Tests with no dependencies are labelled as @Order(1) */ + +public class BranchTests { + + @Tag("gotoTestI") + @Order(1) + @ParameterizedTest(name = "#{index} - gotoTest({0}) = {1}") + @CsvSource({ + "0, 0", + "1, 0", + "2, 1", + "5, 10" + }) + public void test_goto(int arg1, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = gotoTest(arg1); + } + assertEquals(expected, result); + } + + public static int gotoTest(int n) { + int result = 0; + for (int i = 0; i < n ; i++) { + result += i; + } + return result; + } + + @Tag("ifeqTestI") + @Order(1) + @ParameterizedTest(name = "#{index} - ifeqTest({0}) = {1}") + @CsvSource({ + "0, 0", + "1, 0", + "2, 1", + "5, 10" + }) + public void test_ifeq(int arg1, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = ifeqTest(arg1); + } + assertEquals(expected, result); + } + + public static int ifeqTest(int n) { + int result = 0; + for (int i = 0; i < n; i++) { + if (i != 0) { + result += i; + } + } + return result; + } + + @Tag("ifneTestI") + @Order(1) + @ParameterizedTest(name = "#{index} - ifneTest({0}) = {1}") + @CsvSource({ + "0, 0", + "1, 1", + "2, 2", + "5, 11" + }) + public void test_ifne(int arg1, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = ifneTest(arg1); + } + assertEquals(expected, result); + } + + public static int ifneTest(int n) { + int result = 0; + for (int i = 0; i < n; i++) { + if (i == 0) { + result += 1; + } + else { + result += i; + } + } + return result; + } + + @Tag("ifltTestI") + @Order(1) + @ParameterizedTest(name = "#{index} - ifltTest({0}) = {1}") + @CsvSource({ + "0, 0", + "1, 0", + "2, 1", + "5, 10" + }) + public void test_iflt(int arg1, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = ifltTest(arg1); + } + assertEquals(expected, result); + } + + public static int ifltTest(int n) { + int result = 0; + for (int i = 0; i < n; i++) { + if (i >= 0) { + result += i; + } + } + return result; + } + + @Tag("ifleTestI") + @Order(1) + @ParameterizedTest(name = "#{index} - ifleTest({0}) = {1}") + @CsvSource({ + "0, 0", + "1, 0", + "2, 1", + "5, 10" + }) + public void test_ifle(int arg1, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = ifleTest(arg1); + } + assertEquals(expected, result); + } + + public static int ifleTest(int n) { + int result = 0; + for (int i = 0; i < n; i++) { + if (i > 0) { + result += i; + } + } + return result; + } + + @Tag("ifgtTestI") + @Order(1) + @ParameterizedTest(name = "#{index} - ifgtTest({0}) = {1}") + @CsvSource({ + "0, -1", + "1, -1", + "2, 0", + "5, 9" + }) + public void test_ifgt(int arg1, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = ifgtTest(arg1); + } + assertEquals(expected, result); + } + + public static int ifgtTest(int n) { + int result = 0; + for (int i = -1; i < n; i++) { + if (i <= 0) { + result += i; + } + else { + result += i; + } + } + return result; + } + + @Tag("ifgeTestI") + @Order(1) + @ParameterizedTest(name = "#{index} - ifgeTest({0}) = {1}") + @CsvSource({ + "0, -1", + "1, -1", + "2, 0", + "5, 9" + }) + public void test_ifge(int arg1, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = ifgeTest(arg1); + } + assertEquals(expected, result); + } + + public static int ifgeTest(int n) { + int result = 0; + for (int i = -1; i < n; i++) { + if (i < 0) { + result += i; + } + else { + result += i; + } + } + return result; + } + + @Tag("if_icmpeqTestI") + @Order(1) + @ParameterizedTest(name = "#{index} - if_icmpeqTest({0}) = {1}") + @CsvSource({ + "0, 0", + "1, 2", + "2, 2", + "5,11" + }) + public void test_if_icmpeq(int arg1, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = if_icmpeqTest(arg1); + } + assertEquals(expected, result); + } + + public static int if_icmpeqTest(int n) { + int result = 0; + for (int i = 0; i < n ; i++) { + if (i != n-2) { + result += 2; + } + else { + result += i; + } + } + return result; + } + + @Tag("if_icmpneTestI") + @Order(1) + @ParameterizedTest(name = "#{index} - if_icmpneTest({0}) = {1}") + @CsvSource({ + "0, 0", + "1, 0", + "2, 3", + "5, 9" + }) + public void test_if_icmpne(int arg1, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = if_icmpneTest(arg1); + } + assertEquals(expected, result); + } + + public static int if_icmpneTest(int n) { + int result = 0; + for (int i = 0; i < n ; i++) { + if (i == n-2) { + result += 2; + } + else { + result += i; + } + } + return result; + } + + @Tag("if_icmpltTestI") + @Order(1) + @ParameterizedTest(name = "#{index} - if_icmpltTest({0}) = {1}") + @CsvSource({ + "0, 0", + "1, 2", + "2, 4", + "5, 7" + }) + public void test_if_icmplt(int arg1, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = if_icmpltTest(arg1); + } + assertEquals(expected, result); + } + + public static int if_icmpltTest(int n) { + int result = 0; + for (int i = 0; i < n ; i++) { + if (i >= n-2) { + result += 2; + } + else { + result += i; + } + } + return result; + } + + @Tag("if_icmpleTestI") + @Order(1) + @ParameterizedTest(name = "#{index} - if_icmpleTest({0}) = {1}") + @CsvSource({ + "0, 0", + "1, 2", + "2, 2", + "5, 8" + }) + public void test_if_icmple(int arg1, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = if_icmpleTest(arg1); + } + assertEquals(expected, result); + } + + public static int if_icmpleTest(int n) { + int result = 0; + for (int i = 0; i < n ; i++) { + if (i > n-2) { + result += 2; + } + else { + result += i; + } + } + return result; + } + + @Tag("if_icmpgtTestI") + @Order(1) + @ParameterizedTest(name = "#{index} - if_icmpgtTest({0}) = {1}") + @CsvSource({ + "0, 0", + "1, 0", + "2, 3", + "5, 12" + }) + public void test_if_icmpgt(int arg1, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = if_icmpgtTest(arg1); + } + assertEquals(expected, result); + } + + public static int if_icmpgtTest(int n) { + int result = 0; + for (int i = 0; i < n ; i++) { + if (i <= n-2) { + result += 2; + } + else { + result += i; + } + } + return result; + } + + @Tag("if_icmpgeTestI") + @Order(1) + @ParameterizedTest(name = "#{index} - if_icmpgeTest({0}) = {1}") + @CsvSource({ + "0, 0", + "1, 0", + "2, 1", + "5, 13" + }) + public void test_if_icmpge(int arg1, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = if_icmpgeTest(arg1); + } + assertEquals(expected, result); + } + + public static int if_icmpgeTest(int n) { + int result = 0; + for (int i = 0; i < n ; i++) { + if (i < n-2) { + result += 2; + } + else { + result += i; + } + } + return result; + } + +} diff --git a/test/functional/MicroJIT/src/tests/ConversionTests.java b/test/functional/MicroJIT/src/tests/ConversionTests.java new file mode 100644 index 00000000000..cb12804c808 --- /dev/null +++ b/test/functional/MicroJIT/src/tests/ConversionTests.java @@ -0,0 +1,409 @@ +/******************************************************************************* + * Copyright (c) 2023, 2023 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +/* Tests that have dependencies must be labelled as @Order(2), @Order(3)... */ +/* Tests with no dependencies are labelled as @Order(1) */ + +public class ConversionTests { + + @Tag("i2lJ") + @Order(1) + @ParameterizedTest(name = "#{index} - i2l({0}) = {1}") + @CsvSource({ + "0, 0", + "1, 1", + "2147483647, 2147483647", + "-2147483648, -2147483648" + }) + public void testI2L(int arg1, long expected) { + long result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = i2l(arg1); + } + assertEquals(expected, result); + } + + public static long i2l(int x) { + return (long)x; + } + + @Tag("l2iI") + @Order(1) + @ParameterizedTest(name = "#{index} - l2i({0}) = {1}") + @CsvSource({ + "0, 0", + "1, 1", + "9223372036854775807, -1", + "-9223372036854775808, 0" + }) + public void testL2I(long arg1, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = l2i(arg1); + } + assertEquals(expected, result); + } + + public static int l2i(long x) { + return (int)x; + } + + @Tag("i2bB") + @Order(1) + @ParameterizedTest(name = "#{index} - i2b({0}) = {1}") + @CsvSource({ + "0, 0", + "1, 1", + "2147483647, -1", + "-2147483648, 0" + }) + public void testI2B(int arg1, byte expected) { + byte result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = i2b(arg1); + } + assertEquals(expected, result); + } + + public static byte i2b(int x) { + return (byte)x; + } + + @Tag("i2sS") + @Order(1) + @ParameterizedTest(name = "#{index} - i2s({0}) = {1}") + @CsvSource({ + "-1, -1", + "0, 0", + "1, 1", + "2147483647, -1", + "-2147483648, 0", + "1050656, 2080" + }) + public void testI2S(int arg1, short expected) { + short result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = i2s(arg1); + } + assertEquals(expected, result); + } + + public static short i2s(int x) { + return (short)x; + } + + @Tag("i2cC") + @Order(1) + @ParameterizedTest(name = "#{index} - i2c({0}) = {1}") + @CsvSource({ + "68, \u0044", + "70, \u0046", + "68, \u0044", + "68, \u0044" + }) + public void testI2C(int arg1, char expected) { + char result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = i2c(arg1); + } + assertEquals(expected, result); + } + + public static char i2c(int x) { + return (char)x; + } + + @Tag("i2dD") + @Order(1) + @ParameterizedTest(name = "#{index} - i2d({0}) = {1}") + @CsvSource({ + "0, 0", + "1, 1", + "2147483647, 2147483647", + "-2147483648, -2147483648" + }) + public void testI2D(int arg1, double expected) { + double result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = i2d(arg1); + } + assertEquals(expected, result); + } + + public static double i2d(int x) { + return (double)x; + } + + @Tag("l2dD") + @Order(1) + @ParameterizedTest(name = "#{index} - l2d({0}) = {1}") + @CsvSource({ + "0, 0", + "1, 1", + "9223372036854775807, 9223372036854775807", + "-9223372036854775808, -9223372036854775808" + }) + public void testL2D(long arg1, double expected) { + double result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = l2d(arg1); + } + assertEquals(expected, result); + } + + public static double l2d(long x) { + return (double)x; + } + + @Tag("d2iI") + @Order(1) + @ParameterizedTest(name = "#{index} - d2i({0}) = {1}") + @CsvSource({ + "0, 0", + "1, 1", + "9223372036854775807, 2147483647", + "2147483648, 2147483647", + "NaN, 0", // If the value' is NaN, the result of the conversion is an int 0 + "309.9999999, 309", // Rounding towards zero using IEEE 754 round towards zero mode + "Infinity, 2147483647", // Result is the largest representable value of type int + "-Infinity, -2147483648", // Result is the smallest representable value of type int + "2147483647.5678, 2147483647", + "-9223372036854775808, -2147483648" + }) + public void testD2I(double arg1, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = d2i(arg1); + } + assertEquals(expected, result); + } + + public static int d2i(double x) { + return (int)x; + } + + @Tag("d2lJ") + @Order(1) + @ParameterizedTest(name = "#{index} - d2l({0}) = {1}") + @CsvSource({ + "0, 0", + "1, 1", + "9223372036854775807, 9223372036854775807", + "1.147483648, 1", + "309.999, 309", // Rounding towards zero using IEEE 754 round towards zero mode + "NaN, 0", // If the value' is NaN, the result of the conversion is a long 0 + "-Infinity, -9223372036854775808", // Result is the smallest representable value of type long + "Infinity, 9223372036854775807", // Result is the largest representable value of type long + "-9223372036854775808, -9223372036854775808" + }) + public void testD2L(double arg1, long expected) { + long result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = d2l(arg1); + } + assertEquals(expected, result); + } + + public static long d2l(double x) { + return (long)x; + } + + @Tag("i2fF") + @Order(1) + @ParameterizedTest(name = "#{index} - i2f({0}) = {1}") + @CsvSource({ + "0, 0", + "1, 1", + "-1, -1", + "2147483647, 2.14748365E9", + "-2147483648, -2.14748365E9" + }) + public void testI2F(int arg1, float expected) { + float result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = i2f(arg1); + } + assertEquals(expected, result); + } + + public static float i2f(int x) { + return (float)x; + } + + @Tag("f2iI") + @Order(1) + @ParameterizedTest(name = "#{index} - f2i({0}) = {1}") + @CsvSource({ + "0, 0", + "-0, 0", + "1, 1", + "-1, -1", + "9223372036854775807, 2147483647", + "-9223372036854775807, -2147483648", + "2147483648, 2147483647", + "-2147483648, -2147483648", + "3.4E+38, 2147483647", + "1.18E-38, 0", + "-1.18E-38, 0", + "1.4E-45, 0", + "NaN, 0", // If the value' is NaN, the result of the conversion is an int 0 + "309.9999, 309", // Rounding towards zero using IEEE 754 round towards zero mode + "-309.9999, -309", // Rounding towards zero using IEEE 754 round towards zero mode + "Infinity, 2147483647", // Result is the largest representable value of type int + "-Infinity, -2147483648", // Result is the smallest representable value of type int + "2147483650.5678, 2147483647", + "-2147483650.5678, -2147483648", + "2147483650.1234, 2147483647", + "-2147483650.1234, -2147483648", + "9223372036854775808, 2147483647", + "-9223372036854775808, -2147483648" + }) + public void testF2I(float arg1, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = f2i(arg1); + } + assertEquals(expected, result); + } + + public static int f2i(float x) { + return (int)x; + } + + @Tag("l2fF") + @Order(1) + @ParameterizedTest(name = "#{index} - l2f({0}) = {1}") + @CsvSource({ + "0, 0", + "1, 1", + "-1, -1", + "2147483647, 2.14748365E9", // Loss of precision + "-2147483648, -2.14748365E9", // because values of + "9223372036854775807, 9.223372E18", // type float have + "-9223372036854775808, -9.223372E18" // only 24 significand bits + }) + public void testL2F(long arg1, float expected) { + float result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = l2f(arg1); + } + assertEquals(expected, result); + } + + public static float l2f(long x) { + return (float)x; + } + + @Tag("f2lJ") + @Order(1) + @ParameterizedTest(name = "#{index} - f2l({0}) = {1}") + @CsvSource({ + "0, 0", + "-0, 0", + "1, 1", + "-1, -1", + "9223372036854775807, 9223372036854775807", + "-9223372036854775807, -9223372036854775808", + "9223372036854775808, 9223372036854775807", + "-9223372036854775808, -9223372036854775808", + "2147483647, 2147483648", + "-2147483648, -2147483648", + "3.4E+38, 9223372036854775807", + "-3.4E+38, -9223372036854775808", + "1.18E-38, 0", + "-1.18E-38, 0", + "1.4E-45, 0", + "NaN, 0", // If the value' is NaN, the result of the conversion is a long 0 + "309.9999, 309", // Rounding towards zero using IEEE 754 round towards zero mode + "-309.9999, -309", // Rounding towards zero using IEEE 754 round towards zero mode + "Infinity, 9223372036854775807", // Result is the largest representable value of type long + "-Infinity, -9223372036854775808" // Result is the smallest representable value of type long + }) + public void testF2L(float arg1, long expected) { + long result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = f2l(arg1); + } + assertEquals(expected, result); + } + + public static long f2l(float x) { + return (long)x; + } + + @Tag("d2fF") + @Order(1) + @ParameterizedTest(name = "#{index} - d2f({0}) = {1}") + @CsvSource({ + "0, 0", + "1, 1", + "-4.94E-324, -0", // A finite value too small to be represented as a float is converted to a zero of the same sign + "1.79E+308, Infinity", // A finite value too large to be represented as a float is converted to an infinity of the same sign + "NaN, NaN", // A double NaN is converted to a float NaN + "1.18E-38, 1.18E-38", + "1.4E-45, 1.4E-45", + "1.4E-46, 0" + }) + public void testD2F(double arg1, float expected) { + float result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = d2f(arg1); + } + assertEquals(expected, result); + } + + public static float d2f(double x) { + return (float)x; + } + + @Tag("f2dD") + @Order(1) + @ParameterizedTest(name = "#{index} - f2d({0}) = {1}") + @CsvSource({ + "0, 0", + "1, 1", + "1.18E-38, 1.179999945774631E-38", // Because f2d conversions are exact + "1.4E-45, 1.401298464324817E-45", // Because f2d conversions are exact + "3.4E+38, 3.3999999521443642E38" // Because f2d conversions are exact + }) + public void testF2D(float arg1, double expected) { + double result = 0D; + for (int i = 0; i < Helper.invocations(); i++) { + result = f2d(arg1); + } + assertEquals(expected, result); + } + + public static double f2d(float x) { + return (double)x; + } + +} diff --git a/test/functional/MicroJIT/src/tests/DoubleTests.java b/test/functional/MicroJIT/src/tests/DoubleTests.java new file mode 100644 index 00000000000..f9e7b335413 --- /dev/null +++ b/test/functional/MicroJIT/src/tests/DoubleTests.java @@ -0,0 +1,391 @@ +/******************************************************************************* + * Copyright (c) 2023, 2023 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +/* Tests that have dependencies must be labelled as @Order(2), @Order(3)... */ +/* Tests with no dependencies are labelled as @Order(1) */ + +public class DoubleTests { + + @Tag("add
D") + @Order(1) + @ParameterizedTest(name = "#{index} - add({0},{1}) = {2}") + @CsvSource({ + "99.264860, 2, 101.264860", + "1000, 43, 1043", + "101.26485238, 101.26485238, 202.52970476", + "1.79E+308, 1, 1.79E+308", + "2, 1.79E+308, 1.79E+308", + "1.79E+308, 0, 1.79E+308", + "NaN, 10, NaN", // If either value1 or value2 is NaN, the result is NaN + "1024, NaN, NaN", // If either value1 or value2 is NaN, the result is NaN + "NaN, NaN, NaN", // If either value1 or value2 is NaN, the result is NaN + "Infinity, -Infinity, NaN", // The sum of two infinities of opposite sign is NaN + "-4.94E-324, 4.94E-324, 0", + "Infinity, Infinity, Infinity", // The sum of two infinities of the same sign is the infinity of that sign + "-Infinity, -Infinity, -Infinity", // The sum of two infinities of the same sign is the infinity of that sign + "Infinity, 1.0247E+200, Infinity", // The sum of an infinity and any finite value is equal to the infinity + "-Infinity, -1.0247E+200, -Infinity", // The sum of an infinity and any finite value is equal to the infinity + "0, -0, 0", // The sum of two zeroes of opposite sign is positive zero + "0, 0, 0", // The sum of two zeroes of the same sign is the zero of that sign + "-0, -0, -0", // The sum of two zeroes of the same sign is the zero of that sign + "0, 1.111111111, 1.111111111", // The sum of a zero and a nonzero finite value is equal to the nonzero value + "1.1234567890, 0, 1.1234567890", // The sum of a zero and a nonzero finite value is equal to the nonzero value + "1.79E+308, -1.79E+308, 0", // The sum of two nonzero finite values of the same magnitude and opposite sign is positive zero + "1.79E+308, 1.79E+308, Infinity", // Magnitude too large, hence operation overflow results in an infinity of appropriate sign + "-1.79E+308, -0.01E+308, -Infinity", // Magnitude too large, hence operation overflow results in an infinity of appropriate sign + "4.94E-325, 0, 0", // Magnitude too small, hence operation underflow results in a zero of appropriate sign + "-4.94E-325, -0, -0" // Magnitude too small, hence operation underflow results in a zero of appropriate sign + }) + public void testDAdd(double arg1, double arg2, double expected) { + double result = 0D; + for (int i = 0; i < Helper.invocations(); i++) { + result = add(arg1, arg2); + } + assertEquals(expected, result); + } + + public static double add(double x, double y) { + return x + y; + } + + @Tag("sub
D") + @Order(1) + @ParameterizedTest(name = "#{index} - sub({0},{1}) = {2}") + @CsvSource({ + "0, 0, 0", + "0, 1, -1", + "1, 0, 1", + "-1, -1, 0", + "101.26485238, 2, 99.26485238", + "1.79E+308, 1.79E+308, 0", + "1.79E+308, -1.79E+308, Infinity", // Magnitude too large, hence operation overflow results in an infinity of appropriate sign + "-4.94E-324, -4.94E-324, 0", + "-1.79E+308, 1.79E+308, -Infinity", // Magnitude too large, hence operation overflow results in an infinity of appropriate sign + "Infinity, -Infinity, Infinity", + "Infinity, Infinity, NaN", + "4.94E-324, 0, 4.94E-324", + "4.94E-325, 0, 0", // Magnitude too small, hence operation underflow results in a zero of appropriate sign + "0, 0, 0", + "0, -0, 0", + "-0, 0, -0", + "0, -4.94E-324, 4.94E-324", + "0, 4.94E-324, -4.94E-324" + }) + public void testDSub(double arg1, double arg2, double expected) { + double result = 0D; + for (int i = 0; i < Helper.invocations(); i++) { + result = sub(arg1, arg2); + } + assertEquals(expected, result); + } + + public static double sub(double x, double y) { + return x - y; + } + + @Tag("mul
D") + @Order(1) + @ParameterizedTest(name = "#{index} - mul({0},{1}) = {2}") + @CsvSource({ + "0, 0, 0", + "0, 1, 0", + "100, 40, 4000", + "1.79E+308, 1, 1.79E+308", + "1.79E+308, 0, 0", + "-1.79E+308, 1, -1.79E+308", + "-4.94E-324, 0, -0", + "NaN, 10.1234567890, NaN", // If either value1 or value2 is NaN, the result is NaN + "1024.56745355, NaN, NaN", // If either value1 or value2 is NaN, the result is NaN + "NaN, NaN, NaN", // If either value1 or value2 is NaN, the result is NaN + "Infinity, 0, NaN", // Multiplication of an infinity by a zero results in NaN + "Infinity, -4.94E-324, -Infinity", // Multiplication of an infinity by a finite value results in a signed infinity + "-Infinity, 4.94E-324, -Infinity", // Multiplication of an infinity by a finite value results in a signed infinity + "Infinity, 4.94E-324, Infinity", // Multiplication of an infinity by a finite value results in a signed infinity + "-Infinity, -4.94E-324, Infinity", // Multiplication of an infinity by a finite value results in a signed infinity + "-4.94E-324, 4.94E-324, -0", // Magnitude too small, hence operation underflow results in a zero + "1.79E+308, 1.79E+308, Infinity" // Magnitude too large, hence operation overflow results in an infinity + }) + public void testDMul(double arg1, double arg2, double expected) { + double result = 0D; + for (int i = 0; i < Helper.invocations(); i++) { + result = mul(arg1, arg2); + } + assertEquals(expected, result); + } + + public static double mul(double x, double y) { + return x * y; + } + + @Tag("div
D") + @Order(1) + @ParameterizedTest(name = "#{index} - div({0},{1}) = {2}") + @CsvSource({ + "1.4E+18, 1, 1.4E+18", + "1.4E+18, 100, 1.4E+16", + "1.4E+18, -100, -1.4E+16", + "-1.4E+18, 100, -1.4E+16", + "-1.4E+18, -100, 1.4E+16", + "1.4E+18, 2, 0.7E+18", + "1.79E+308, 1.79E+308, 1", + "-1.79E+308, -1.79E+308, 1", + "1.79E+308, 1, 1.79E+308", + "NaN, 1.2E+40, NaN", // If either value1 or value2 is NaN, the result is NaN + "1.2E+40, NaN, NaN", // If either value1 or value2 is NaN, the result is NaN + "NaN, NaN, NaN", // If either value1 or value2 is NaN, the result is NaN + "Infinity, Infinity, NaN", // Division of an infinity by an infinity results in NaN + "Infinity, -4.94E-324, -Infinity", // Division of an infinity by a finite value results in a signed infinity + "-Infinity, 4.94E-324, -Infinity", // Division of an infinity by a finite value results in a signed infinity + "Infinity, 4.94E-324, Infinity", // Division of an infinity by a finite value results in a signed infinity + "-Infinity, -4.94E-324, Infinity", // Division of an infinity by a finite value results in a signed infinity + "1.79E+308, Infinity, 0", // Division of a finite value by an infinity results in a signed zero + "1.79E+308, -Infinity, -0", // Division of a finite value by an infinity results in a signed zero + "0, 0, NaN", // Division of a zero by a zero results in NaN + "0, 1.2E+40, 0", // Division of zero by any other finite value results in a signed zero + "-1.2E+40, 0, -Infinity", // Division of a nonzero finite value by a zero results in a signed infinity + "-4.94E-324, 4.94E+324, -0", // Magnitude too small, hence operation underflow results in a zero + "1.79E+308, 1.79E-308, Infinity" // Magnitude too large, hence operation overflow results in an infinity + }) + public void testDDiv(double arg1, double arg2, double expected) { + double result = 0D; + for (int i = 0; i < Helper.invocations(); i++) { + result = div(arg1, arg2); + } + assertEquals(expected, result); + } + + public static double div(double x, double y) { + return x / y; + } + + @Tag("rem
D") + @Order(1) + @ParameterizedTest(name = "#{index} - rem({0},{1}) = {2}") + @CsvSource({ + "10.0, 9.0, 1.0", + "3.0, 2.0, 1.0", + "10.0, 7.0, 3.0", + "9, 5, 4", + "9, -1, 0", + "100, 35, 30", + "100, -35, 30", + "-100, 35, -30", + "-100, -35, -30", + "21, 7, 0.0", + "21, -7, 0.0", + "-21, 7, -0.0", + "-21, -7, -0.0", + "31.34, 2.2, 0.5399999999999974", + "0, 1, 0", + "1000, 100, 0", + "1.79E+308, 1.79E+308, 0", + "-4.94E-324, -1, -4.94E-324", + "-4.94E-324, -4.94E-324, -0", + "4.94E-324, -1, 4.94E-324", + "-16.3, 4.1, -4.000000000000002", + "17.876543, 4, 1.8765430000000016", + "17.8, 4, 1.8000000000000007", + "17.8, 4.1, 1.4000000000000021", + "-17.8, 4.1, -1.4000000000000021", + "17.8, -4.1, 1.4000000000000021", + "-17.8, -4.1, -1.4000000000000021", + "60984.1, -497.99, 229.31999999999744", + "-497.99, 60984.1, -497.99", + + "NaN, 10E+20, NaN", // If either value1 + "10E+20, NaN, NaN", // or value2 is NaN, + "NaN, NaN, NaN", // the result is NaN + + "Infinity, -1.79E+308, NaN", // If the dividend is an infinity + "4.94E-324, 0, NaN", // or the divisor is a zero + "Infinity, 0, NaN", // or both, the result is NaN + "Infinity, -0, NaN", + "-Infinity, 2.3, NaN", // If the dividend is an infinity + "2.34, -0, NaN", // or the divisor is a zero + "-Infinity, -0, NaN", // or both, the result is NaN + "-Infinity, 0, NaN", + + "-2.34, Infinity, -2.34", // If the dividend is finite + "2.34, Infinity, 2.34", // and the divisor is an infinity, + "-2.34, -Infinity, -2.34", // the result equals the dividend + "2.34, -Infinity, 2.34", + + "0, -2.34, 0", // If the dividend is a zero + "-0, -2.34, -0", // and the divisor is finite, + "0, 2.34, 0", // the result equals the dividend + "-0, 2.34, -0" + }) + public void testDRem(double arg1, double arg2, double expected) { + double result = 0D; + for (int i = 0; i < Helper.invocations(); i++) { + result = rem(arg1, arg2); + } + assertEquals(expected, result); + } + + public static double rem(double x, double y) { + return x % y; + } + + @Tag("negD") + @Order(1) + @ParameterizedTest(name = "#{index} - neg({0}) = {1}") + @CsvSource({ + "0, -0", // If the operand is a zero, + "-0, 0", // the result is the zero of opposite sign. + "NaN, NaN", // If the operand is NaN, the result is NaN. + "Infinity, -Infinity", // If the operand is an infinity, + "-Infinity, Infinity", // the result is the infinity of opposite sign. + "-1.147483648, 1.147483648", + "1.147483648, -1.147483648", + "-4.94E-324, 4.94E-324", + "1.79E+308, -1.79E+308" + }) + public void testDNeg(double arg1, double expected) { + double result = 0D; + for (int i = 0; i < Helper.invocations(); i++) { + result = neg(arg1); + } + assertEquals(expected, result); + } + + public static double neg(double x) { + return -x; + } + + @Tag("dconst_0<>D") + @Order(1) + @ParameterizedTest(name = "#{index} - dconst_0() = {0}") + @CsvSource({ + "0" + }) + public void testdconst_0(double expected) { + double result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = dconst_0(); + } + assertEquals(expected, result); + } + + public static double dconst_0() { + return 0; + } + + @Tag("dconst_1<>D") + @Order(1) + @ParameterizedTest(name = "#{index} - dconst_1() = {0}") + @CsvSource({ + "1" + }) + public void testdconst_1(double expected) { + double result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = dconst_1(); + } + assertEquals(expected, result); + } + + public static double dconst_1() { + return 1; + } + + @Tag("dcmpl
I") + @Order(2) + @ParameterizedTest(name = "#{index} - dcmpl({0},{1}) = {2}") + @CsvSource({ + "99.26485999, 2, 1", + "101.26485999, 101.26485999, 0", + "3.4E+38, 1, 1", + "2, 3.4E+38, -1", + "3.4E+38, 0.0000001E+38, 1", + "3.4E+38, 3.4E38, 0", + "NaN, 10, -1", // If either value1 or value2 is NaN, the result is -1 + "1024, NaN, -1", // If either value1 or value2 is NaN, the result is -1 + "NaN, NaN, -1", // If either value1 or value2 is NaN, the result is -1 + "Infinity, 3.4E+38, 1", // Positive infinity is greater than all finite values + "3.4E+38, -Infinity, 1", // Negative infinity is less than all finite values + "3.4E+38, Infinity, -1", // Positive infinity is greater than all finite values + "-Infinity, 3.4E+38, -1", // Negative infinity is less than all finite values + "0.0, -0.0, 0", // Positive zero and negative zero are considered equal + "Infinity, -Infinity, 1", + "1.79E+308, 1, 1", + "1.79E+308, 0, 1", + "-1.79E+308, 1, -1" + }) + public void testDcmpl(double arg1, double arg2, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = dcmpl(arg1, arg2); + } + assertEquals(expected, result); + } + + public static int dcmpl(double x, double y) { + return dcmp.dcmpl(x, y); + } + + @Tag("dcmpg
I") + @Order(2) + @ParameterizedTest(name = "#{index} - dcmpg({0},{1}) = {2}") + @CsvSource({ + "99.26485999, 2, 1", + "101.26485999, 101.26485999, 0", + "3.4E+38, 1, 1", + "3.4E+38, -1, 1", + "2, 3.4E+38, -1", + "3.4E+38, 0.0000001E+38, 1", + "3.4E+38, 3.4E38, 0", + "NaN, 10, 1", // If either value1 or value2 is NaN, the result is 1 + "1024, NaN, 1", // If either value1 or value2 is NaN, the result is 1 + "NaN, NaN, 1", // If either value1 or value2 is NaN, the result is 1 + "Infinity, 3.4E+38, 1", // Positive infinity is greater than all finite values + "3.4E+38, -Infinity, 1", // Negative infinity is less than all finite values + "3.4E+38, Infinity, -1", // Positive infinity is greater than all finite values + "-Infinity, 3.4E+38, -1", // Negative infinity is less than all finite values + "0.0, -0.0, 0", // Positive zero and negative zero are considered equal + "Infinity, -Infinity, 1", + "1.79E+308, 1, 1", + "1.79E+308, 0, 1", + "-1.79E+308, 1, -1" + }) + public void testDcmpg(double arg1, double arg2, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = dcmpg(arg1, arg2); + } + assertEquals(expected, result); + } + + public static int dcmpg(double x, double y) { + return dcmp.dcmpg(x, y); + } + +} diff --git a/test/functional/MicroJIT/src/tests/FloatTests.java b/test/functional/MicroJIT/src/tests/FloatTests.java new file mode 100644 index 00000000000..55d11f70da2 --- /dev/null +++ b/test/functional/MicroJIT/src/tests/FloatTests.java @@ -0,0 +1,462 @@ +/******************************************************************************* + * Copyright (c) 2023, 2023 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +/* Tests that have dependencies must be labelled as @Order(2), @Order(3)... */ +/* Tests with no dependencies are labelled as @Order(1) */ + +public class FloatTests { + + @Tag("addF") + @Order(1) + @ParameterizedTest(name = "#{index} - add({0},{1}) = {2}") + @CsvSource({ + "99.26485999, 2, 101.264860", + "101.26485999, 101.26485999, 202.529720", + "3.4E+38, 1, 3.4E+38", + "2, 3.4E+38, 3.4E38", + "3.4E+38, 0.0000001E+38, 3.4E38", + "3.4E+38, 0, 3.4E38", + "NaN, 10, NaN", // If either value1 or value2 is NaN, the result is NaN + "1024, NaN, NaN", // If either value1 or value2 is NaN, the result is NaN + "NaN, NaN, NaN", // If either value1 or value2 is NaN, the result is NaN + "Infinity, -Infinity, NaN", // The sum of two infinities of opposite sign is NaN + "-1.18E-38, 1.18E-38, 0", + "Infinity, Infinity, Infinity", // The sum of two infinities of the same sign is the infinity of that sign + "-Infinity, -Infinity, -Infinity", // The sum of two infinities of the same sign is the infinity of that sign + "Infinity, 1.0247E+10, Infinity", // The sum of an infinity and any finite value is equal to the infinity + "-Infinity, -1.0247E+10, -Infinity", // The sum of an infinity and any finite value is equal to the infinity + "0, -0, 0", // The sum of two zeroes of opposite sign is positive zero + "0, 0, 0", // The sum of two zeroes of the same sign is the zero of that sign + "-0, -0, -0", // The sum of two zeroes of the same sign is the zero of that sign + "0, 1.1, 1.1", // The sum of a zero and a nonzero finite value is equal to the nonzero value + "1.123, 0, 1.123", // The sum of a zero and a nonzero finite value is equal to the nonzero value + "3.4E+38, -3.4E+38, 0", // The sum of two nonzero finite values of the same magnitude and opposite sign is positive zero + "3.4E+38, 3.4E+38, Infinity", // Magnitude too large, hence operation overflow results in an infinity of appropriate sign + "-3.4E+38, -0.01E+38, -Infinity", // Magnitude too large, hence operation overflow results in an infinity of appropriate sign + "1.18E-46, 0, 0", // Magnitude too small, hence operation underflow results in a zero of appropriate sign + "-1.18E-46, -0, -0" // Magnitude too small, hence operation underflow results in a zero of appropriate sign + }) + public void testFAdd(float arg1, float arg2, float expected) { + float result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = add(arg1, arg2); + } + assertEquals(expected, result); + } + + @Tag("addF") + @Order(1) + @ParameterizedTest(name = "#{index} - add({0},{1},{2}) = {3}") + @CsvSource({ + "0.23, 0, 0, 0.23", + "0.23, 1, 1, 2.23", + "1.23, 0, 1, 2.23", + "5.23, 10, 15, 30.23", + "3.23, 1, -1, 3.23" + }) + public void testFAdd3(float arg1, int arg2, int arg3, float expected) { + float result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = add(arg1, arg2, arg3); + } + assertEquals(expected, result); + } + + @Tag("addF") + @Order(1) + @ParameterizedTest(name = "#{index} - add({0},{1},{2},{3},{4},{5},{6},{7},{8},{9}) = {10}") + @CsvSource({ + "0.23, 0, 0, 0.23, 1, 2, 3, 4, 5, 6, 21.46" + }) + public void testFAdd10(float arg1, float arg2, float arg3, float arg4, float arg5, float arg6, float arg7, float arg8, float arg9, float arg10, float expected) { + float result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = add(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); + } + assertEquals(expected, result); + } + + @Tag("addF") + @Order(1) + @ParameterizedTest(name = "#{index} - add({0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15}) = {16}") + @CsvSource({ + "5.23, 10, 15, 30, 2, 2, 1024, 1, 3, 4, 5, 6, 7, 8, 9, 10, 1141.23" + }) + public void testFAdd16(float arg1, float arg2, int arg3, int arg4, double arg5, double arg6, long arg7, long arg8, float arg9, float arg10, int arg11, int arg12, double arg13, double arg14, long arg15, long arg16, float expected) { + float result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = add(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16); + } + assertEquals(expected, result); + } + + public static float add(float x, float y) { + return x + y; + } + + public static float add(float x, int y, int z) { + return x + y + z; + } + + public static float add(float x1, float x2, float x3, float x4, float x5, float x6, float x7, float x8, float x9, float x10) { + return x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10; + } + + public static float add(float x1, float x2, int x3, int x4, double x5, double x6, long x7, long x8, float x9, float x10, int x11, int x12, double x13, double x14, long x15, long x16) { + return x1 + x2 + x3 + x4 + (float)x5 + (float)x6 + x7 + x8 + x9 + x10 + x11 + x12 + (float)x13 + (float)x14 + x15 + x16; + } + + @Tag("subF") + @Order(1) + @ParameterizedTest(name = "#{index} - sub({0},{1}) = {2}") + @CsvSource({ + "100, 40, 60", + "1000, 43, 957", + "0, 0, 0", + "0, 1, -1", + "1, 0, 1", + "-1, -1, 0", + "101, 2, 99", + "3.4E+38, 3.4E+38, 0", + "3.4E+38, -3.4E+38, Infinity", // Magnitude too large, hence operation overflow results in an infinity of appropriate sign + "-3.4E+38, -3.4E+38, 0", + "-3.4E+38, 3.4E+38, -Infinity", // Magnitude too large, hence operation overflow results in an infinity of appropriate sign + "Infinity, -Infinity, Infinity", + "Infinity, Infinity, NaN", + "1.4E-45, 0, 1.4E-45", + "1.4E-46, 0, 0", // Magnitude too small, hence operation underflow results in a zero + "0, 0, 0", + "0, -0, 0", + "-0, 0, -0", + "0, -1.18E-38, 1.18E-38", + "0, 1.18E-38, -1.18E-38" + }) + public void testFSub(float arg1, float arg2, float expected) { + float result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = sub(arg1, arg2); + } + assertEquals(expected, result); + } + + public static float sub(float x, float y) { + return x - y; + } + + @Tag("mulF") + @Order(1) + @ParameterizedTest(name = "#{index} - mul({0},{1}) = {2}") + @CsvSource({ + "0, 0, 0", + "0, 1, 0", + "100, 40, 4000", + "3.4E+38, 1, 3.4E+38", + "3.4E+38, 0, 0", + "-3.4E+38, 1, -3.4E+38", + "-3.4E+38, 0, -0", + "NaN, 10, NaN", // If either value1 or value2 is NaN, the result is NaN + "1024, NaN, NaN", // If either value1 or value2 is NaN, the result is NaN + "NaN, NaN, NaN", // If either value1 or value2 is NaN, the result is NaN + "Infinity, 0, NaN", // Multiplication of an infinity by a zero results in NaN + "Infinity, -1.18E-38, -Infinity", // Multiplication of an infinity by a finite value results in a signed infinity + "-Infinity, 1.18E-38, -Infinity", // Multiplication of an infinity by a finite value results in a signed infinity + "Infinity, 1.18E-38, Infinity", // Multiplication of an infinity by a finite value results in a signed infinity + "-Infinity, -1.18E-38, Infinity", // Multiplication of an infinity by a finite value results in a signed infinity + "-1.18E-38, 1.18E-38, -0", // Magnitude too small, hence operation underflow results in a zero + "3.4E+38, 3.4E+38, Infinity" // Magnitude too large, hence operation overflow results in an infinity + }) + public void testFMul(float arg1, float arg2, float expected) { + float result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = mul(arg1, arg2); + } + assertEquals(expected, result); + } + + public static float mul(float x, float y) { + return x * y; + } + + @Tag("divF") + @Order(1) + @ParameterizedTest(name = "#{index} - div({0},{1}) = {2}") + @CsvSource({ + "1.4E+8, 1, 1.4E+8", + "1.4E+8, 100, 1.4E+6", + "1.4E+8, -100, -1.4E+6", + "-1.4E+8, 100, -1.4E+6", + "-1.4E+8, -100, 1.4E+6", + "1.4E+8, 2, 7.0E7", + "3.4E+38, 3.4E+38, 1", + "-3.4E+38, -3.4E+38, 1", + "3.4E+38, 1, 3.4E+38", + "NaN, 10E+20, NaN", // If either value1 or value2 is NaN, the result is NaN + "10E+20, NaN, NaN", // If either value1 or value2 is NaN, the result is NaN + "NaN, NaN, NaN", // If either value1 or value2 is NaN, the result is NaN + "Infinity, Infinity, NaN", // Division of an infinity by an infinity results in NaN + "Infinity, -1.18E-38, -Infinity", // Division of an infinity by a finite value results in a signed infinity + "-Infinity, 1.18E-38, -Infinity", // Division of an infinity by a finite value results in a signed infinity + "Infinity, 1.18E-38, Infinity", // Division of an infinity by a finite value results in a signed infinity + "-Infinity, -1.18E-38, Infinity", // Division of an infinity by a finite value results in a signed infinity + "1.18E+38, Infinity, 0", // Division of a finite value by an infinity results in a signed zero + "1.18E+38, -Infinity, -0", // Division of a finite value by an infinity results in a signed zero + "0, 0, NaN", // Division of a zero by a zero results in NaN + "0, 1.4E+8, 0", // Division of zero by any other finite value results in a signed zero + "-1.4E+8, 0, -Infinity", // Division of a nonzero finite value by a zero results in a signed infinity + "-1.18E-38, 1.18E+38, -0", // Magnitude too small, hence operation underflow results in a zero + "3.4E+38, 3.4E-38, Infinity" // Magnitude too large, hence operation overflow results in an infinity + }) + public void testFDiv(float arg1, float arg2, float expected) { + float result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = div(arg1, arg2); + } + assertEquals(expected, result); + } + + public static float div(float x, float y) { + return x / y; + } + + @Tag("remF") + @Order(1) + @ParameterizedTest(name = "#{index} - rem({0},{1}) = {2}") + @CsvSource({ + "10.0, 9.0, 1.0", + "3.0, 2.0, 1.0", + "10.0, 7.0, 3.0", + "9, 5, 4", + "9, -1, 0", + "100, 35, 30", + "100, -35, 30", + "-100, 35, -30", + "-100, -35, -30", + "21, 7, 0.0", + "21, -7, 0.0", + "-21, 7, -0.0", + "-21, -7, -0.0", + "31.34, 2.2, 0.5399995", + "0, 1, 0", + "1000, 100, 0", + "3.4E+38, 3.4E+38, 0", + "-1.18E-38, -1, -1.18E-38", + "-1.18E-38, -1.18E-38, -0", + "1.4E-45, -1, 1.4E-45", + "-16.3, 4.1, -3.9999995", + "17.876543, 4, 1.876543", + "17.8, 4, 1.7999992", + "17.8, 4.1, 1.3999996", + "-17.8, 4.1, -1.3999996", + "17.8, -4.1, 1.3999996", + "-17.8, -4.1, -1.3999996", + "60984.1, -497.99, 229.32275", + "-497.99, 60984.1, -497.99", + + "NaN, 10E+20, NaN", // If either value1 + "10E+20, NaN, NaN", // or value2 is NaN, + "NaN, NaN, NaN", // the result is NaN + + "Infinity, -3.4E+38, NaN", // If the dividend is an infinity + "1.18E-38, 0, NaN", // or the divisor is a zero + "Infinity, 0, NaN", // or both, the result is NaN + "Infinity, -0, NaN", + "-Infinity, 2.3, NaN", // If the dividend is an infinity + "2.34, -0, NaN", // or the divisor is a zero + "-Infinity, -0, NaN", // or both, the result is NaN + "-Infinity, 0, NaN", + + "-2.34, Infinity, -2.34", // If the dividend is finite + "2.34, Infinity, 2.34", // and the divisor is an infinity, + "-2.34, -Infinity, -2.34", // the result equals the dividend + "2.34, -Infinity, 2.34", + + "0, -2.34, 0", // If the dividend is a zero + "-0, -2.34, -0", // and the divisor is finite, + "0, 2.34, 0", // the result equals the dividend + "-0, 2.34, -0" + }) + public void testFRem(float arg1, float arg2, float expected) { + float result = 0F; + for (int i = 0; i < Helper.invocations(); i++) { + result = rem(arg1, arg2); + } + assertEquals(expected, result); + } + + public static float rem(float x, float y) { + return x % y; + } + + @Tag("negF") + @Order(1) + @ParameterizedTest(name = "#{index} - neg({0}) = {1}") + @CsvSource({ + "0, -0", // If the operand is a zero, + "-0, 0", // the result is the zero of opposite sign. + "NaN, NaN", // If the operand is NaN, the result is NaN. + "Infinity, -Infinity", // If the operand is an infinity, + "-Infinity, Infinity", // the result is the infinity of opposite sign. + "1.482261, -1.482261", + "-1.18E-38, 1.18E-38", + "3.4E+38, -3.4E+38" + }) + public void testFNeg(float arg1, float expected) { + float result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = neg(arg1); + } + assertEquals(expected, result); + } + + public static float neg(float x) { + return -x; + } + + @Tag("fconst_0<>F") + @Order(1) + @ParameterizedTest(name = "#{index} - fconst_0() = {0}") + @CsvSource({ + "0" + }) + public void testFConst_0(float expected) { + float result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = fconst_0(); + } + assertEquals(expected, result); + } + + public static float fconst_0() { + return 0; + } + + @Tag("fconst_1<>F") + @Order(1) + @ParameterizedTest(name = "#{index} - fconst_1() = {0}") + @CsvSource({ + "1" + }) + public void testFConst_1(float expected) { + float result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = fconst_1(); + } + assertEquals(expected, result); + } + + public static float fconst_1() { + return 1; + } + + @Tag("fconst_2<>F") + @Order(1) + @ParameterizedTest(name = "#{index} - fconst_2() = {0}") + @CsvSource({ + "2" + }) + public void testFConst_2(float expected) { + float result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = fconst_2(); + } + assertEquals(expected, result); + } + + public static float fconst_2() { + return 2; + } + + @Tag("fcmplI") + @Order(2) + @ParameterizedTest(name = "#{index} - fcmpl({0},{1}) = {2}") + @CsvSource({ + "99.26485999, 2, 1", + "101.26485999, 101.26485999, 0", + "3.4E+38, 1, 1", + "2, 3.4E+38, -1", + "3.4E+38, 0.0000001E+38, 1", + "3.4E+38, 3.4E38, 0", + "NaN, 10, -1", // If either value1 or value2 is NaN, the result is -1 + "1024, NaN, -1", // If either value1 or value2 is NaN, the result is -1 + "NaN, NaN, -1", // If either value1 or value2 is NaN, the result is -1 + "Infinity, 3.4E+38, 1", // Positive infinity is greater than all finite values + "3.4E+38, -Infinity, 1", // Negative infinity is less than all finite values + "3.4E+38, Infinity, -1", // Positive infinity is greater than all finite values + "-Infinity, 3.4E+38, -1", // Negative infinity is less than all finite values + "0.0, -0.0, 0", // Positive zero and negative zero are considered equal + "Infinity, -Infinity, 1" + }) + public void testFcmpl(float arg1, float arg2, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = fcmpl(arg1, arg2); + } + assertEquals(expected, result); + } + + public static int fcmpl(float x, float y) { + return fcmp.fcmpl(x, y); + } + + @Tag("fcmpgI") + @Order(2) + @ParameterizedTest(name = "#{index} - fcmpg({0},{1}) = {2}") + @CsvSource({ + "99.26485999, 2, 1", + "101.26485999, 101.26485999, 0", + "3.4E+38, 1, 1", + "3.4E+38, -1, 1", + "2, 3.4E+38, -1", + "3.4E+38, 0.0000001E+38, 1", + "3.4E+38, 3.4E38, 0", + "NaN, 10, 1", // If either value1 or value2 is NaN, the result is 1 + "1024, NaN, 1", // If either value1 or value2 is NaN, the result is 1 + "NaN, NaN, 1", // If either value1 or value2 is NaN, the result is 1 + "Infinity, 3.4E+38, 1", // Positive infinity is greater than all finite values + "3.4E+38, -Infinity, 1", // Negative infinity is less than all finite values + "3.4E+38, Infinity, -1", // Positive infinity is greater than all finite values + "-Infinity, 3.4E+38, -1", // Negative infinity is less than all finite values + "0.0, -0.0, 0", // Positive zero and negative zero are considered equal + "Infinity, -Infinity, 1" + }) + public void testFcmpg(float arg1, float arg2, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = fcmpg(arg1, arg2); + } + assertEquals(expected, result); + } + + public static int fcmpg(float x, float y) { + return fcmp.fcmpg(x, y); + } + +} diff --git a/test/functional/MicroJIT/src/tests/GetPutFieldTests.java b/test/functional/MicroJIT/src/tests/GetPutFieldTests.java new file mode 100644 index 00000000000..8f0365761d0 --- /dev/null +++ b/test/functional/MicroJIT/src/tests/GetPutFieldTests.java @@ -0,0 +1,364 @@ +/******************************************************************************* + * Copyright (c) 2023, 2023 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +/* Tests that have dependencies must be labelled as @Order(2), @Order(3)... */ +/* Tests with no dependencies are labelled as @Order(1) */ + +public class GetPutFieldTests { + + // For basic test with ints + int test = 7; + + // For testing with arithmetic + int a = 2; + int b = 0; + + @Tag("getField<>I") + @Order(2) + @ParameterizedTest(name = "#{index} - getPutField({0}) = {1}") + @CsvSource({ + "5, 5", + "9, 9", + "2, 2", + "3, 3" + }) + public void testGetPutField(int arg1, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + putField(arg1); + result = getField(); + } + assertEquals(expected, result); + } + + public void putField(int val) { + this.test = val; + } + + public int getField() { + return this.test; + } + + @Tag("add<>I") + @Order(2) + @ParameterizedTest(name = "#{index} - add({0}, {1}) = {2}") + @CsvSource({ + "8, 8, 16", + "0, 1, 1", + "1, 0, 1", + "2147483647, 2147483647, -2", + "-2147483648, 2147483647, -1" + }) + public void testadd(int arg1, int arg2, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + setInts(arg1, arg2); + result = add(); + } + assertEquals(expected, result); + } + + private int add() { + return this.a + this.b; + } + + @Tag("setIntsV") + @Order(1) + @ParameterizedTest(name = "#{index} - setInts({0},{0})") + @CsvSource({ + "1", + "100", + "-5", + "5743251" + }) + public void testSetInts(int arg1) { + boolean result = false; + for (int i = 0; i < Helper.invocations(); i++) { + setInts(arg1, arg1); + result = (a == b); + } + assertEquals(true, result); + } + + public void setInts(int x, int y) { + a = x; + b = y; + } + + // For basic test with longs + long testL = 17L; + + // For testing with arithmetic + long aL = 2L; + long bL = 0L; + + @Tag("getFieldL<>J") + @Order(2) + @ParameterizedTest(name = "#{index} - getPutFieldL({0}) = {1}") + @CsvSource({ + "0, 0", + "-1, -1", + "9223372036854775807, 9223372036854775807", + "-9223372036854775808, -9223372036854775808" + }) + public void testGetPutFieldL(long arg1, long expected) { + long result = 0L; + for (int i = 0; i < Helper.invocations(); i++) { + putFieldL(arg1); + result = getFieldL(); + } + assertEquals(expected, result); + } + + public void putFieldL(long val) { + this.testL = val; + } + + public long getFieldL() { + return this.testL; + } + + @Tag("addL<>J") + @Order(2) + @ParameterizedTest(name = "#{index} - addL({0}, {1}) = {2}") + @CsvSource({ + "0, 0, 0", + "0, 1, 1", + "1, 0, 1", + "101, -2, 99", + "-101, 101, 0", + "9223372036854775807, 9223372036854775807, -2", + "-9223372036854775808, 9223372036854775807, -1", + "9223372036854775807, 1, -9223372036854775808", + "2, 9223372036854775807, -9223372036854775807" + }) + public void testaddL(long arg1, long arg2, long expected) { + long result = 0L; + for (int i = 0; i < Helper.invocations(); i++) { + setLongs(arg1, arg2); + result = addL(); + } + assertEquals(expected, result); + } + + private long addL() { + return this.aL + this.bL; + } + + @Tag("setLongsV") + @Order(1) + @ParameterizedTest(name = "#{index} - setLongs({0},{0})") + @CsvSource({ + "0", + "-1", + "9223372036854775807", + "-9223372036854775808" + }) + public void testSetLongs(long arg1) { + boolean result = false; + for (int i = 0; i < Helper.invocations(); i++) { + setLongs(arg1, arg1); + result = (aL == bL); + } + assertEquals(true, result); + } + + public void setLongs(long x, long y) { + aL = x; + bL = y; + } + + // For basic test with floats + float testF = 17.23F; + + // For testing with arithmetic + float aF = 2.3F; + float bF = 0.2F; + + @Tag("getFieldF<>F") + @Order(2) + @ParameterizedTest(name = "#{index} - getPutFieldF({0}) = {1}") + @CsvSource({ + "5.3, 5.3", + "-9.234567, -9.234567", + "3.4E+38, 3.4E+38", + "NaN, NaN", + "-Infinity, -Infinity" + }) + public void testgetPutFieldF(float arg1, float expected) { + float result = 0F; + for (int i = 0; i < Helper.invocations(); i++) { + putFieldF(arg1); + result = getFieldF(); + } + assertEquals(expected, result); + } + + public void putFieldF(float val) { + this.testF = val; + } + + public float getFieldF() { + return this.testF; + } + + @Tag("addF<>F") + @Order(2) + @ParameterizedTest(name = "#{index} - addF({0}, {1}) = {2}") + @CsvSource({ + "99.26485999, 2, 101.264860", + "101.26485999, 101.26485999, 202.529720", + "3.4E+38, 1, 3.4E+38", + "3.4E+38, 0.0000001E+38, 3.4E38", + "NaN, 10, NaN", + "Infinity, -Infinity, NaN" + }) + public void testaddF(float arg1, float arg2, float expected) { + float result = 0F; + for (int i = 0; i < Helper.invocations(); i++) { + setFloats(arg1, arg2); + result = addF(); + } + assertEquals(expected, result); + } + + private float addF() { + return this.aF + this.bF; + } + + @Tag("setFloatsV") + @Order(1) + @ParameterizedTest(name = "#{index} - setFloats({0},{0})") + @CsvSource({ + "99.26485999", + "101.26485999", + "3.4E+38", + "Infinity" + }) + public void testSetFloats(float arg1) { + boolean result = false; + for (int i = 0; i < Helper.invocations(); i++) { + setFloats(arg1, arg1); + result = (aF == bF); + } + assertEquals(true, result); + } + + public void setFloats(float x, float y) { + aF = x; + bF = y; + } + + // For basic test with doubles + double testD = 17.23D; + + // For testing with arithmetic + double aD = 2.3D; + double bD = 0.2D; + + @Tag("getFieldD<>D") + @Order(2) + @ParameterizedTest(name = "#{index} - getPutFieldD({0}) = {1}") + @CsvSource({ + "99.264860, 99.264860", + "1000, 1000", + "1.79E+308, 1.79E+308", + "-4.94E-324, -4.94E-324", + "NaN, NaN", + "-Infinity, -Infinity" + }) + public void testgetPutFieldD(double arg1, double expected) { + double result = 0D; + for (int i = 0; i < Helper.invocations(); i++) { + putFieldD(arg1); + result = getFieldD(); + } + assertEquals(expected, result); + } + + public void putFieldD(double val) { + this.testD = val; + } + + public double getFieldD() { + return this.testD; + } + + @Tag("addD<>D") + @Order(2) + @ParameterizedTest(name = "#{index} - addD({0}, {1}) = {2}") + @CsvSource({ + "99.264860, 2, 101.264860", + "1000, 43, 1043", + "101.26485238, 101.26485238, 202.52970476", + "1.79E+308, 1, 1.79E+308", + "-4.94E-324, 4.94E-324, 0", + "NaN, 10, NaN", + "Infinity, -Infinity, NaN" + }) + public void testaddD(double arg1, double arg2, double expected) { + double result = 0D; + for (int i = 0; i < Helper.invocations(); i++) { + setDoubles(arg1, arg2); + result = addD(); + } + assertEquals(expected, result); + } + + private double addD() { + return this.aD + this.bD; + } + + @Tag("setDoubles
V") + @Order(1) + @ParameterizedTest(name = "#{index} - setDoubles({0},{0})") + @CsvSource({ + "99.264860", + "1000", + "1.79E+308", + "-4.94E-324", + "Infinity" + }) + public void testSetDoubles(double arg1) { + boolean result = false; + for (int i = 0; i < Helper.invocations(); i++) { + setDoubles(arg1, arg1); + result = (aD == bD); + } + assertEquals(true, result); + } + + public void setDoubles(double x, double y) { + aD = x; + bD = y; + } + +} diff --git a/test/functional/MicroJIT/src/tests/GetPutStaticTests.java b/test/functional/MicroJIT/src/tests/GetPutStaticTests.java new file mode 100644 index 00000000000..e62826c05aa --- /dev/null +++ b/test/functional/MicroJIT/src/tests/GetPutStaticTests.java @@ -0,0 +1,431 @@ +/******************************************************************************* + * Copyright (c) 2023, 2023 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +/* Tests that have dependencies must be labelled as @Order(2), @Order(3)... */ +/* Tests with no dependencies are labelled as @Order(1) */ + +public class GetPutStaticTests { + + static int x = -1; + static int y = 1; + + static long a = -1; + static long b = 1; + + static float m = -1; + static float n = 1; + + static double s = -1; + static double t = 1; + + @Tag("add<>I") + @Order(2) + @ParameterizedTest(name = "#{index} - add({0},{1}) = {2}") + @CsvSource({ + "0, 0, 0", + "0, 1, 1", + "1, 0, 1", + "2147483647, 2147483647, -2", + "-2147483648, 2147483647, -1" + }) + public void testIAdd(int arg1, int arg2, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + setInts(arg1, arg2); + result = add(); + } + assertEquals(expected, result); + } + + public static int add() { + return x + y; + } + + @Tag("sub<>I") + @Order(2) + @ParameterizedTest(name = "#{index} - sub({0},{1}) = {2}") + @CsvSource({ + "0, 0, 0", + "0, 1, -1", + "1, 0, 1", + "-1, -1, 0", + "2147483647, 2147483647, 0", + "-2147483648, 2147483647, 1" + }) + public void testISub(int arg1, int arg2, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + setInts(arg1, arg2); + result = sub(); + } + assertEquals(expected, result); + } + + public static int sub() { + return x - y; + } + + @Tag("mul<>I") + @Order(2) + @ParameterizedTest(name = "#{index} - mul({0},{1}) = {2}") + @CsvSource({ + "0, 0, 0", + "10, 10, 100", + "10, -10, -100", + "-10, 10, -100", + "-10, -10, 100", + "2147483647, 1, 2147483647", + "2147483647, 0, 0", + "0, 1, 0" + }) + public void testIMul(int arg1, int arg2, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + setInts(arg1, arg2); + result = mul(); + } + assertEquals(expected, result); + } + + public static int mul() { + return x * y; + } + + @Tag("div<>I") + @Order(2) + @ParameterizedTest(name = "#{index} - div({0},{1}) = {2}") + @CsvSource({ + "1000, 100, 10", + "1000, -100, -10", + "-1000, 100, -10", + "-1000, -100, 10", + "2147483647, 2147483647, 1", + "-2147483648, -2147483648, 1", + "0, 1, 0" + }) + public void testIDiv(int arg1, int arg2, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + setInts(arg1, arg2); + result = div(); + } + assertEquals(expected, result); + } + + public static int div() { + return x / y; + } + + @Tag("and<>I") + @Order(2) + @ParameterizedTest(name = "#{index} - and({0},{1}) = {2}") + @CsvSource({ + "1, 1, 1", + "1, 0, 0", + "0, 1, 0", + "5, 10, 0", + "5, 5, 5", + "3, 5, 1", + "5743251, 0, 0" + }) + public void testIAnd(int arg1, int arg2, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + setInts(arg1, arg2); + result = and(); + } + assertEquals(expected, result); + } + + public static int and() { + return x & y; + } + + @Tag("or<>I") + @Order(2) + @ParameterizedTest(name = "#{index} - or({0},{1}) = {2}") + @CsvSource({ + "1, 1, 1", + "1, 0, 1", + "0, 1, 1", + "5, 10, 15", + "5, 5, 5", + "3, 5, 7", + "5743251, 0, 5743251" + }) + public void testIOr(int arg1, int arg2, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + setInts(arg1, arg2); + result = or(); + } + assertEquals(expected, result); + } + + public static int or() { + return x | y; + } + + @Tag("xor<>I") + @Order(2) + @ParameterizedTest(name = "#{index} - xor({0},{1}) = {2}") + @CsvSource({ + "1, 1, 0", + "1, 0, 1", + "0, 1, 1", + "5, 10, 15", + "5, 5, 0", + "3, 5, 6", + "5743251, 0, 5743251" + }) + public void testIXor(int arg1, int arg2, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + setInts(arg1, arg2); + result = xor(); + } + assertEquals(expected, result); + } + + public static int xor() { + return x ^ y; + } + + @Tag("addLong<>J") + @Order(2) + @ParameterizedTest(name = "#{index} - addLong({0},{1}) = {2}") + @CsvSource({ + "0, 0, 0", + "0, 1, 1", + "1, 0, 1", + "101, -2, 99", + "-101, 101, 0", + "9223372036854775807, 9223372036854775807, -2", + "-9223372036854775808, 9223372036854775807, -1", + "9223372036854775807, 1, -9223372036854775808", + "2, 9223372036854775807, -9223372036854775807" + }) + public void testLAdd(long arg1, long arg2, long expected) { + long result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + setLongs(arg1, arg2); + result = addLong(); + } + assertEquals(expected, result); + } + + public static long addLong() { + return a + b; + } + + @Tag("addFloat<>F") + @Order(2) + @ParameterizedTest(name = "#{index} - addFloat({0},{1}) = {2}") + @CsvSource({ + "99.26485999, 2, 101.264860", + "101.26485999, 101.26485999, 202.529720", + "3.4E+38, 1, 3.4E+38", + "2, 3.4E+38, 3.4E38", + "3.4E+38, 0.0000001E+38, 3.4E38", + "3.4E+38, 0, 3.4E38", + "NaN, 10, NaN", // If either value1 or value2 is NaN, the result is NaN + "1024, NaN, NaN", // If either value1 or value2 is NaN, the result is NaN + "NaN, NaN, NaN", // If either value1 or value2 is NaN, the result is NaN + "Infinity, -Infinity, NaN", // The sum of two infinities of opposite sign is NaN + "-1.18E-38, 1.18E-38, 0", + "Infinity, Infinity, Infinity", // The sum of two infinities of the same sign is the infinity of that sign + "-Infinity, -Infinity, -Infinity", // The sum of two infinities of the same sign is the infinity of that sign + "Infinity, 1.0247E+10, Infinity", // The sum of an infinity and any finite value is equal to the infinity + "-Infinity, -1.0247E+10, -Infinity", // The sum of an infinity and any finite value is equal to the infinity + "0, -0, 0", // The sum of two zeroes of opposite sign is positive zero + "0, 0, 0", // The sum of two zeroes of the same sign is the zero of that sign + "-0, -0, -0", // The sum of two zeroes of the same sign is the zero of that sign + "0, 1.1, 1.1", // The sum of a zero and a nonzero finite value is equal to the nonzero value + "1.123, 0, 1.123", // The sum of a zero and a nonzero finite value is equal to the nonzero value + "3.4E+38, -3.4E+38, 0", // The sum of two nonzero finite values of the same magnitude and opposite sign is positive zero + "3.4E+38, 3.4E+38, Infinity", // Magnitude too large, hence operation overflow results in an infinity of appropriate sign + "-3.4E+38, -0.01E+38, -Infinity", // Magnitude too large, hence operation overflow results in an infinity of appropriate sign + "1.18E-46, 0, 0", // Magnitude too small, hence operation underflow results in a zero of appropriate sign + "-1.18E-46, -0, -0" // Magnitude too small, hence operation underflow results in a zero of appropriate sign + }) + public void testFAdd(float arg1, float arg2, float expected) { + float result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + setFloats(arg1, arg2); + result = addFloat(); + } + assertEquals(expected, result); + } + + public static float addFloat() { + return m + n; + } + + @Tag("addDouble<>D") + @Order(2) + @ParameterizedTest(name = "#{index} - addDouble({0},{1}) = {2}") + @CsvSource({ + "99.264860, 2, 101.264860", + "1000, 43, 1043", + "101.26485238, 101.26485238, 202.52970476", + "1.79E+308, 1, 1.79E+308", + "2, 1.79E+308, 1.79E+308", + "1.79E+308, 0, 1.79E+308", + "NaN, 10, NaN", // If either value1 or value2 is NaN, the result is NaN + "1024, NaN, NaN", // If either value1 or value2 is NaN, the result is NaN + "NaN, NaN, NaN", // If either value1 or value2 is NaN, the result is NaN + "Infinity, -Infinity, NaN", // The sum of two infinities of opposite sign is NaN + "-4.94E-324, 4.94E-324, 0", + "Infinity, Infinity, Infinity", // The sum of two infinities of the same sign is the infinity of that sign + "-Infinity, -Infinity, -Infinity", // The sum of two infinities of the same sign is the infinity of that sign + "Infinity, 1.0247E+200, Infinity", // The sum of an infinity and any finite value is equal to the infinity + "-Infinity, -1.0247E+200, -Infinity", // The sum of an infinity and any finite value is equal to the infinity + "0, -0, 0", // The sum of two zeroes of opposite sign is positive zero + "0, 0, 0", // The sum of two zeroes of the same sign is the zero of that sign + "-0, -0, -0", // The sum of two zeroes of the same sign is the zero of that sign + "0, 1.111111111, 1.111111111", // The sum of a zero and a nonzero finite value is equal to the nonzero value + "1.1234567890, 0, 1.1234567890", // The sum of a zero and a nonzero finite value is equal to the nonzero value + "1.79E+308, -1.79E+308, 0", // The sum of two nonzero finite values of the same magnitude and opposite sign is positive zero + "1.79E+308, 1.79E+308, Infinity", // Magnitude too large, hence operation overflow results in an infinity of appropriate sign + "-1.79E+308, -0.01E+308, -Infinity", // Magnitude too large, hence operation overflow results in an infinity of appropriate sign + "4.94E-325, 0, 0", // Magnitude too small, hence operation underflow results in a zero of appropriate sign + "-4.94E-325, -0, -0" // Magnitude too small, hence operation underflow results in a zero of appropriate sign + }) + public void testDAdd(double arg1, double arg2, double expected) { + double result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + setDoubles(arg1, arg2); + result = addDouble(); + } + assertEquals(expected, result); + } + + public static double addDouble() { + return s + t; + } + + @Tag("setIntsV") + @Order(1) + @ParameterizedTest(name = "#{index} - setInts({0},{0})") + @CsvSource({ + "1", + "100", + "-5", + "5743251" + }) + public void testSetInts(int arg1) { + boolean result = false; + for (int i = 0; i < Helper.invocations(); i++) { + setInts(arg1, arg1); + result = (x == y); + } + assertEquals(true, result); + } + + public static void setInts(int arg1, int arg2) { + x = arg1; + y = arg2; + } + + @Tag("setLongsV") + @Order(1) + @ParameterizedTest(name = "#{index} - setLongs({0},{0})") + @CsvSource({ + "1", + "100", + "-5", + "5743251" + }) + public void testSetLongs(long arg1) { + boolean result = false; + for (int i = 0; i < Helper.invocations(); i++) { + setLongs(arg1, arg1); + result = (a == b); + } + assertEquals(true, result); + } + + public static void setLongs(long arg1, long arg2) { + a = arg1; + b = arg2; + } + + @Tag("setFloatsV") + @Order(1) + @ParameterizedTest(name = "#{index} - setFloats({0},{0})") + @CsvSource({ + "1", + "100", + "-5", + "5743251", + "99.26485999", + "101.26485999", + "3.4E+38", + "Infinity" + }) + public void testSetFloats(float arg1) { + boolean result = false; + for (int i = 0; i < Helper.invocations(); i++) { + setFloats(arg1, arg1); + result = (m == n); + } + assertEquals(true, result); + } + + public static void setFloats(float arg1, float arg2) { + m = arg1; + n = arg2; + } + + @Tag("setDoubles
V") + @Order(1) + @ParameterizedTest(name = "#{index} - setDoubles({0},{0})") + @CsvSource({ + "1", + "100", + "-5", + "5743251" + }) + public void testSetDoubles(double arg1) { + boolean result = false; + for (int i = 0; i < Helper.invocations(); i++) { + setDoubles(arg1, arg1); + result = (s == t); + } + assertEquals(true, result); + } + + public static void setDoubles(double arg1, double arg2) { + s = arg1; + t = arg2; + } + +} diff --git a/test/functional/MicroJIT/src/tests/IntTests.java b/test/functional/MicroJIT/src/tests/IntTests.java new file mode 100644 index 00000000000..57b3c31b2ad --- /dev/null +++ b/test/functional/MicroJIT/src/tests/IntTests.java @@ -0,0 +1,667 @@ +/******************************************************************************* + * Copyright (c) 2023, 2023 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +/* Tests that have dependencies must be labelled as @Order(2), @Order(3)... */ +/* Tests with no dependencies are labelled as @Order(1) */ + +public class IntTests { + + @Tag("addI") + @Order(1) + @ParameterizedTest(name = "#{index} - add({0},{1}) = {2}") + @CsvSource({ + "0, 0, 0", + "0, 1, 1", + "1, 0, 1", + "2147483647, 2147483647, -2", + "-2147483648, 2147483647, -1" + }) + public void testIAdd(int arg1, int arg2, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = add(arg1, arg2); + } + assertEquals(expected, result); + } + + @Tag("addI") + @Order(1) + @ParameterizedTest(name = "#{index} - add({0},{1},{2}) = {3}") + @CsvSource({ + "0, 0, 0, 0", + "0, 1, 1, 2", + "1, 0, 1, 2", + "5, 10, 15, 30", + "3, 1, -1, 3" + }) + public void testAddThree(int arg1, int arg2, int arg3, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = add(arg1, arg2, arg3); + } + assertEquals(expected, result); + } + + @Tag("addI") + @Order(1) + @ParameterizedTest(name = "#{index} - add({0},{1},{2},{3}) = {4}") + @CsvSource({ + "0, 0, 0, 0, 0", + "0, 1, 1, 1, 3", + "1, 0, 1, 3, 5", + "5, 10, 15, 5, 35", + "3, 1, -1, 0, 3" + }) + public void testIAddFour(int arg1, int arg2, int arg3, int arg4, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = add(arg1, arg2, arg3, arg4); + } + assertEquals(expected, result); + } + + public static int add(int x, int y) { + return x + y; + } + + public static int add(int x, int y, int z) { + return x + y + z; + } + + public static int add(int w, int x, int y, int z) { + return w + x + y + z; + } + + @Tag("subI") + @Order(1) + @ParameterizedTest(name = "#{index} - sub({0},{1}) = {2}") + @CsvSource({ + "0, 0, 0", + "0, 1, -1", + "1, 0, 1", + "-1, -1, 0", + "2147483647, 2147483647, 0", + "-2147483648, 2147483647, 1" + }) + public void testISub(int arg1, int arg2, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = sub(arg1, arg2); + } + assertEquals(expected, result); + } + + public static int sub(int x, int y) { + return x - y; + } + + @Tag("mulI") + @Order(1) + @ParameterizedTest(name = "#{index} - mul({0},{1}) = {2}") + @CsvSource({ + "0, 0, 0", + "10, 10, 100", + "10, -10, -100", + "-10, 10, -100", + "-10, -10, 100", + "2147483647, 1, 2147483647", + "2147483647, 0, 0", + "0, 1, 0" + }) + public void testIMul(int arg1, int arg2, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = mul(arg1, arg2); + } + assertEquals(expected, result); + } + + public static int mul(int x, int y) { + return x * y; + } + + @Tag("divI") + @Order(1) + @ParameterizedTest(name = "#{index} - div({0},{1}) = {2}") + @CsvSource({ + "1000, 100, 10", + "1000, -100, -10", + "-1000, 100, -10", + "-1000, -100, 10", + "2147483647, 2147483647, 1", + "-2147483648, -2147483648, 1", + "0, 1, 0", + + /* If the dividend is the negative integer of largest possible magnitude + for the int type and the divisor is -1, then overflow occurs and the + result is equal to the dividend; despite the overflow, no exception + is thrown in this case. */ + "-2147483648, -1, -2147483648" + }) + public void testIDiv(int arg1, int arg2, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = div(arg1, arg2); + } + assertEquals(expected, result); + } + +// Test commented out until we support exceptions like this +/* + @Test + @DisplayName("div(10,0)=divide by zero") + public void testIDivBy0() { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + try { + result = div(10,0); + } + catch (java.lang.ArithmeticException e) { + assertEquals("divide by zero", e.getMessage()); + } + } + } +*/ + + public static int div(int x, int y) { + return x / y; + } + + @Tag("remI") + @Order(1) + @ParameterizedTest(name = "#{index} - rem({0},{1}) = {2}") + @CsvSource({ + "0, 1, 0", + "1000, 100, 0", + "29, 8, 5", + "-29, 8, -5", + "29, -8, 5", + "-29, -8, -5", + "2147483647, 2147483647, 0", + "2147483647, -1, 0", + "-2147483648, -2147483648, 0", + "-2147483648, -1, 0" + }) + public void testIRem(int arg1, int arg2, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = rem(arg1, arg2); + } + assertEquals(expected, result); + } + +// Test commented out until we support exceptions like this +/* + @Test + @DisplayName("rem(10,0)=divide by zero") + public void testIRemBy0() { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + try { + result = rem(10,0); + } + catch (java.lang.ArithmeticException e) { + assertEquals("divide by zero", e.getMessage()); + } + } + } +*/ + + public static int rem(int x, int y) { + return x % y; + } + + @Tag("incI") + @Order(1) + @ParameterizedTest(name = "#{index} - inc({0}) = {1}") + @CsvSource({ + "0, 3", + "-1, 2", + "10, 13", + "2147483640, 2147483643", + "2147483647, -2147483646", + "-2147483648, -2147483645" + }) + public void testIInc(int arg, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = inc(arg); + } + assertEquals(expected, result); + } + + public static int inc(int x) { + int v = x; + v += 3; + return v; + } + + @Tag("negI") + @Order(1) + @ParameterizedTest(name = "#{index} - neg({0}) = {1}") + @CsvSource({ + "1000, -1000", + "100, -100", + "-59, 59", + "2147483647, -2147483647", + "-2147483648, -2147483648", // JVM Section 6.5: Negation of the maximum negative int results in that same maximum negative number + "3, -3", + "0, 0" + }) + public void testINeg(int arg1, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = neg(arg1); + } + assertEquals(expected, result); + } + + public static int neg(int x) { + return -x; + } + + @Tag("shlI") + @Order(1) + @ParameterizedTest(name = "#{index} - shl({0},{1}) = {2}") + @CsvSource({ + "0, 0, 0", + "0, 31, 0", + "1, 0, 1", + "-1, 0, -1", + "-1, 31, -2147483648", + "1, 31, -2147483648", + "16, 2, 64", + "-16, 2, -64", + "1000, 20, 1048576000", + "-1000, 20, -1048576000", + "1000, 21, 2097152000", + "-1000, 21, -2097152000", + "2147483647, 0, 2147483647", + "-2147483648, 0, -2147483648" + }) + public void testIShl(int arg1, int arg2, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = shl(arg1, arg2); + } + assertEquals(expected, result); + } + + public static int shl(int x, int y) { + return x << y; + } + + @Tag("shrI") + @Order(1) + @ParameterizedTest(name = "#{index} - shr({0},{1}) = {2}") + @CsvSource({ + "0, 0, 0", + "0, 31, 0", + "1, 0, 1", + "-1, 0, -1", + "1, 31, 0", + "-1, 31, -1", + "256, 2, 64", + "-256, 2, -64", + "1000, 20, 0", + "-1000, 20, -1", + "1000, 5, 31", + "-1000, 5, -32", + "2147483647, 0, 2147483647", + "-2147483648, 0, -2147483648", + "2147483647, 1, 1073741823", + "-2147483647, 1, -1073741824", + "-2147483648, 1, -1073741824", + "-2147483648, 31, -1", + "2147483647, 31, 0" + }) + public void testIShr(int arg1, int arg2, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = shr(arg1, arg2); + } + assertEquals(expected, result); + } + + public static int shr(int x, int y) { + return x >> y; + } + + @Tag("ushrI") + @Order(1) + @ParameterizedTest(name = "#{index} - ushr({0},{1}) = {2}") + @CsvSource({ + "0, 0, 0", + "0, 31, 0", + "1, 0, 1", + "-1, 0, -1", + "1, 31, 0", + "-1, 31, 1", + "256, 2, 64", + "-256, 2, 1073741760", + "1000, 20, 0", + "-1000, 20, 4095", + "1000, 5, 31", + "-1000, 5, 134217696", + "2147483647, 0, 2147483647", + "-2147483648, 0, -2147483648", + "2147483647, 1, 1073741823", + "-2147483647, 1, 1073741824", + "-2147483648, 1, 1073741824", + "-2147483648, 31, 1", + "2147483647, 31, 0" + }) + public void testIUshr(int arg1, int arg2, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = ushr(arg1, arg2); + } + assertEquals(expected, result); + } + + public static int ushr(int x, int y) { + return x >>> y; + } + + @Tag("andI") + @Order(1) + @ParameterizedTest(name = "#{index} - and({0},{1}) = {2}") + @CsvSource({ + "1, 1, 1", + "1, 0, 0", + "0, 1, 0", + "5, 10, 0", + "5, 5, 5", + "3, 5, 1", + "5743251, 0, 0" + }) + public void testIAnd(int arg1, int arg2, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = and(arg1, arg2); + } + assertEquals(expected, result); + } + + public static int and(int x, int y) { + return x & y; + } + + @Tag("orI") + @Order(1) + @ParameterizedTest(name = "#{index} - or({0},{1}) = {2}") + @CsvSource({ + "1, 1, 1", + "1, 0, 1", + "0, 1, 1", + "5, 10, 15", + "5, 5, 5", + "3, 5, 7", + "5743251, 0, 5743251" + }) + public void testIOr(int arg1, int arg2, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = or(arg1, arg2); + } + assertEquals(expected, result); + } + + public static int or(int x, int y) { + return x | y; + } + + @Tag("xorI") + @Order(1) + @ParameterizedTest(name = "#{index} - xor({0},{1}) = {2}") + @CsvSource({ + "1, 1, 0", + "1, 0, 1", + "0, 1, 1", + "5, 10, 15", + "5, 5, 0", + "3, 5, 6", + "5743251, 0, 5743251" + }) + public void testIXor(int arg1, int arg2, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = xor(arg1, arg2); + } + assertEquals(expected, result); + } + + public static int xor(int x, int y) { + return x ^ y; + } + + @Tag("iconst_m1<>I") + @Order(1) + @ParameterizedTest(name = "#{index} - iconst_m1() = {0}") + @CsvSource({ + "-1" + }) + public void testIConst_m1(int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = iconst_m1(); + } + assertEquals(expected, result); + } + + public static int iconst_m1() { + return -1; + } + + @Tag("iconst_0<>I") + @Order(1) + @ParameterizedTest(name = "#{index} - iconst_0() = {0}") + @CsvSource({ + "0" + }) + public void testIConst_0(int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = iconst_0(); + } + assertEquals(expected, result); + } + + public static int iconst_0() { + return 0; + } + + @Tag("iconst_1<>I") + @Order(1) + @ParameterizedTest(name = "#{index} - iconst_1() = {0}") + @CsvSource({ + "1" + }) + public void testIConst_1(int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = iconst_1(); + } + assertEquals(1, result); + } + + public static int iconst_1() { + return 1; + } + + @Tag("iconst_2<>I") + @Order(1) + @ParameterizedTest(name = "#{index} - iconst_2() = {0}") + @CsvSource({ + "2" + }) + public void testIConst_2(int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = iconst_2(); + } + assertEquals(expected, result); + } + + public static int iconst_2() { + return 2; + } + + @Tag("iconst_3<>I") + @Order(1) + @ParameterizedTest(name = "#{index} - iconst_3() = {0}") + @CsvSource({ + "3" + }) + public void testIConst_3(int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = iconst_3(); + } + assertEquals(expected, result); + } + + public static int iconst_3() { + return 3; + } + + @Tag("iconst_4<>I") + @Order(1) + @ParameterizedTest(name = "#{index} - iconst_4() = {0}") + @CsvSource({ + "4" + }) + public void testIConst_4(int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = iconst_4(); + } + assertEquals(expected, result); + } + + public static int iconst_4() { + return 4; + } + + @Tag("iconst_5<>I") + @Order(1) + @ParameterizedTest(name = "#{index} - iconst_5() = {0}") + @CsvSource({ + "5" + }) + public void testIConst_5(int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = iconst_5(); + } + assertEquals(expected, result); + } + + public static int iconst_5() { + return 5; + } + + /* Outer bounds tested only to avoid writing replicated code */ + /* Note that -1 to 5 will result in iconst_ being called, not bipush */ + + @Tag("bipush_m32<>I") + @Order(1) + @ParameterizedTest(name = "#{index} - bipush_m32() = {0}") + @CsvSource({ + "-32" + }) + public void testBIPush_m32(int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations() ; i++) { + result = bipush_m32(); + } + assertEquals(expected, result); + } + + public static int bipush_m32() { + return -32; + } + + @Tag("bipush_31<>I") + @Order(1) + @ParameterizedTest(name = "#{index} - bipush_31() = {0}") + @CsvSource({ + "31" + }) + public void testBIPush_31(int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations() ; i++) { + result = bipush_31(); + } + assertEquals(expected, result); + } + + public static int bipush_31() { + return 31; + } + + @Tag("sipush_32767<>I") + @Order(1) + @ParameterizedTest(name = "#{index} - sipush_32767({0}, {1}) = {0}") + @CsvSource({ + "32767" + }) + public void testSIPush_32767(int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations() ; i++) { + result = sipush_32767(); + } + assertEquals(expected, result); + } + + public static int sipush_32767() { + return 32767; + } + + @Tag("sipush_m32768<>I") + @Order(1) + @ParameterizedTest(name = "#{index} - sipush_m32768({0}, {1}) = {0}") + @CsvSource({ + "-32768" + }) + public void testSIPush_m32768(int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations() ; i++) { + result = sipush_m32768(); + } + assertEquals(expected, result); + } + + public static int sipush_m32768() { + return -32768; + } + +} diff --git a/test/functional/MicroJIT/src/tests/InvokeTests.java b/test/functional/MicroJIT/src/tests/InvokeTests.java new file mode 100644 index 00000000000..36ab4ff2562 --- /dev/null +++ b/test/functional/MicroJIT/src/tests/InvokeTests.java @@ -0,0 +1,361 @@ +/******************************************************************************* + * Copyright (c) 2023, 2023 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +/* Tests that have dependencies must be labelled as @Order(2), @Order(3)... */ +/* Tests with no dependencies are labelled as @Order(1) */ + +public class InvokeTests { + + @Tag("indirectAddI") + @Order(2) + @ParameterizedTest(name = "#{index} - add({0},{1}) = {2}") + @CsvSource({ + "0, 0, 0", + "0, 1, 1", + "1, 0, 1", + "2147483647, 2147483647, -2", + "-2147483648, 2147483647, -1" + }) + public void _testIAdd(int arg1, int arg2, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = indirectAdd(arg1, arg2); + } + assertEquals(expected, result); + } + + public static int indirectAdd(int a, int b) { + return IntTests.add(a, b); + } + + @Tag("indirectSubI") + @Order(2) + @ParameterizedTest(name = "#{index} - sub({0},{1}) = {2}") + @CsvSource({ + "0, 0, 0", + "0, 1, -1", + "1, 0, 1", + "-1, -1, 0", + "2147483647, 2147483647, 0", + "-2147483648, 2147483647, 1" + }) + public void testISub(int arg1, int arg2, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = indirectSub(arg1, arg2); + } + assertEquals(expected, result); + } + + public static int indirectSub(int a, int b) { + return IntTests.sub(a, b); + } + + @Tag("indirectMulI") + @Order(2) + @ParameterizedTest(name = "#{index} - mul({0},{1}) = {2}") + @CsvSource({ + "0, 0, 0", + "10, 10, 100", + "10, -10, -100", + "-10, 10, -100", + "-10, -10, 100", + "2147483647, 1, 2147483647", + "2147483647, 0, 0", + "0, 1, 0" + }) + public void testIMul(int arg1, int arg2, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = indirectMul(arg1, arg2); + } + assertEquals(expected, result); + } + + public static int indirectMul(int a, int b) { + return IntTests.mul(a, b); + } + + @Tag("indirectDivI") + @Order(2) + @ParameterizedTest(name = "#{index} - div({0},{1}) = {2}") + @CsvSource({ + "1000, 100, 10", + "1000, -100, -10", + "-1000, 100, -10", + "-1000, -100, 10", + "2147483647, 2147483647, 1", + "-2147483648, -2147483648, 1", + "0, 1, 0" + }) + public void testIDiv(int arg1, int arg2, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = indirectDiv(arg1, arg2); + } + assertEquals(expected, result); + } + + public static int indirectDiv(int x, int y) { + return IntTests.div(x, y); + } + + @Tag("indirectLAddJ") + @Order(2) + @ParameterizedTest(name = "#{index} - indirectLAdd({0},{1}) = {2}") + @CsvSource({ + "0, 0, 0", + "0, 1, 1", + "1, 0, 1", + "2147483647, 2147483647, 4294967294", + "-2147483648, 2147483647, -1" + }) + public void _testLAdd(long arg1, long arg2, long expected) { + long result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = indirectLAdd(arg1, arg2); + } + assertEquals(expected, result); + } + public static long indirectLAdd(long a, long b) { + return LongTests.add(a, b); + } + + @Tag("indirectFAddF") + @Order(2) + @ParameterizedTest(name = "#{index} - indirectFAdd({0},{1}) = {2}") + @CsvSource({ + "99.26485999, 2, 101.264860", + "101.26485999, 101.26485999, 202.529720", + "3.4E+38, 1, 3.4E+38", + "2, 3.4E+38, 3.4E38", + "3.4E+38, 0.0000001E+38, 3.4E38", + "3.4E+38, 0, 3.4E38", + "NaN, 10, NaN", // If either value1 or value2 is NaN, the result is NaN + "1024, NaN, NaN", // If either value1 or value2 is NaN, the result is NaN + "NaN, NaN, NaN", // If either value1 or value2 is NaN, the result is NaN + "Infinity, -Infinity, NaN", // The sum of two infinities of opposite sign is NaN + "-1.18E-38, 1.18E-38, 0", + "Infinity, Infinity, Infinity", // The sum of two infinities of the same sign is the infinity of that sign + "-Infinity, -Infinity, -Infinity", // The sum of two infinities of the same sign is the infinity of that sign + "Infinity, 1.0247E+10, Infinity", // The sum of an infinity and any finite value is equal to the infinity + "-Infinity, -1.0247E+10, -Infinity", // The sum of an infinity and any finite value is equal to the infinity + "0, -0, 0", // The sum of two zeroes of opposite sign is positive zero + "0, 0, 0", // The sum of two zeroes of the same sign is the zero of that sign + "-0, -0, -0", // The sum of two zeroes of the same sign is the zero of that sign + "0, 1.1, 1.1", // The sum of a zero and a nonzero finite value is equal to the nonzero value + "1.123, 0, 1.123", // The sum of a zero and a nonzero finite value is equal to the nonzero value + "3.4E+38, -3.4E+38, 0", // The sum of two nonzero finite values of the same magnitude and opposite sign is positive zero + "3.4E+38, 3.4E+38, Infinity", // Magnitude too large, hence operation overflow results in an infinity of appropriate sign + "-3.4E+38, -0.01E+38, -Infinity", // Magnitude too large, hence operation overflow results in an infinity of appropriate sign + "1.18E-46, 0, 0", // Magnitude too small, hence operation underflow results in a zero of appropriate sign + "-1.18E-46, -0, -0" // Magnitude too small, hence operation underflow results in a zero of appropriate sign + }) + public void _testFAdd(float arg1, float arg2, float expected) { + float result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = indirectFAdd(arg1, arg2); + } + assertEquals(expected, result); + } + public static float indirectFAdd(float a, float b) { + return FloatTests.add(a, b); + } + + @Tag("indirectDAdd
D") + @Order(2) + @ParameterizedTest(name = "#{index} - indirectDAdd({0},{1}) = {2}") + @CsvSource({ + "99.264860, 2, 101.264860", + "1000, 43, 1043", + "101.26485238, 101.26485238, 202.52970476", + "1.79E+308, 1, 1.79E+308", + "2, 1.79E+308, 1.79E+308", + "1.79E+308, 0, 1.79E+308", + "NaN, 10, NaN", // If either value1 or value2 is NaN, the result is NaN + "1024, NaN, NaN", // If either value1 or value2 is NaN, the result is NaN + "NaN, NaN, NaN", // If either value1 or value2 is NaN, the result is NaN + "Infinity, -Infinity, NaN", // The sum of two infinities of opposite sign is NaN + "-4.94E-324, 4.94E-324, 0", + "Infinity, Infinity, Infinity", // The sum of two infinities of the same sign is the infinity of that sign + "-Infinity, -Infinity, -Infinity", // The sum of two infinities of the same sign is the infinity of that sign + "Infinity, 1.0247E+200, Infinity", // The sum of an infinity and any finite value is equal to the infinity + "-Infinity, -1.0247E+200, -Infinity", // The sum of an infinity and any finite value is equal to the infinity + "0, -0, 0", // The sum of two zeroes of opposite sign is positive zero + "0, 0, 0", // The sum of two zeroes of the same sign is the zero of that sign + "-0, -0, -0", // The sum of two zeroes of the same sign is the zero of that sign + "0, 1.111111111, 1.111111111", // The sum of a zero and a nonzero finite value is equal to the nonzero value + "1.1234567890, 0, 1.1234567890", // The sum of a zero and a nonzero finite value is equal to the nonzero value + "1.79E+308, -1.79E+308, 0", // The sum of two nonzero finite values of the same magnitude and opposite sign is positive zero + "1.79E+308, 1.79E+308, Infinity", // Magnitude too large, hence operation overflow results in an infinity of appropriate sign + "-1.79E+308, -0.01E+308, -Infinity", // Magnitude too large, hence operation overflow results in an infinity of appropriate sign + "4.94E-325, 0, 0", // Magnitude too small, hence operation underflow results in a zero of appropriate sign + "-4.94E-325, -0, -0" // Magnitude too small, hence operation underflow results in a zero of appropriate sign + }) + public void _testDAdd(double arg1, double arg2, double expected) { + double result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = indirectDAdd(arg1, arg2); + } + assertEquals(expected, result); + } + public static double indirectDAdd(double a, double b) { + return DoubleTests.add(a, b); + } + + @Tag("indirectAddI") + @Order(2) + @ParameterizedTest(name = "#{index} - indirectAdd({0},{1},{2},{3}) = {4}") + @CsvSource({ + "0, 0, 0, 0, 0", + "0, 1, 1, 1, 3", + "1, 0, 1, 3, 5", + "5, 10, 15, 5, 35", + "3, 1, -1, 0, 3" + }) + public void _testAddFour(int arg1, int arg2, int arg3, int arg4, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = indirectAdd(arg1, arg2, arg3, arg4); + } + assertEquals(expected, result); + } + public static int indirectAdd(int a, int b, int c, int d) { + return IntTests.add(a, b, c, d); + } + + @Tag("indirectAddI") + @Order(2) + @ParameterizedTest(name = "#{index} - indirectAdd({0},{1},{2}) = {3}") + @CsvSource({ + "0, 0, 0, 0", + "0, 1, 1, 2", + "1, 0, 1, 2", + "5, 10, 15, 30", + "3, 1, -1, 3" + }) + public void _testAddThree(int arg1, int arg2, int arg3, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = indirectAdd(arg1, arg2, arg3); + } + assertEquals(expected, result); + } + public static int indirectAdd(int a, int b, int c) { + return IntTests.add(a, b, c); + } + + @Tag("indirectAddJ") + @Order(2) + @ParameterizedTest(name = "#{index} - add({0},{1}) = {2}") + @CsvSource({ + "0, 0, 0", + "0, 1, 1", + "1, 0, 1", + "2147483647, 1, 2147483648", + "-2147483648, 2147483647, -1" + }) + public void _testIAdd(int arg1, long arg2, long expected) { + long result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = indirectAdd(arg1, arg2); + } + assertEquals(expected, result); + } + + public static long indirectAdd(int a, long b) { + return LongTests.add(a, b); + } + + @Tag("indirectAddJ") + @Order(2) + @ParameterizedTest(name = "#{index} - indirectAdd({0},{1},{2}) = {3}") + @CsvSource({ + "0, 0, 0, 0", + "0, 1, 1, 2", + "1, 0, 1, 2", + "5, 10, 15, 30", + "3, 1, -1, 3" + }) + public void _testAddThree(int arg1, int arg2, long arg3, long expected) { + long result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = indirectAdd(arg1, arg2, arg3); + } + assertEquals(expected, result); + } + public static long indirectAdd(int a, int b, long c) { + return LongTests.add(a, b, c); + } + + @Tag("indirectAddJ") + @Order(2) + @ParameterizedTest(name = "#{index} - indirectAdd({0},{1},{2}) = {3}") + @CsvSource({ + "0, 0, 0, 0", + "0, 1, 1, 2", + "1, 0, 1, 2", + "5, 10, 15, 30", + "3, 1, -1, 3" + }) + public void _testAddThree(long arg1, int arg2, int arg3, long expected) { + long result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = indirectAdd(arg1, arg2, arg3); + } + assertEquals(expected, result); + } + public static long indirectAdd(long a, int b, int c) { + return LongTests.add(a, b, c); + } + + @Tag("indirectAdd_I") + @Order(2) + @ParameterizedTest(name = "#{index} - indirectAdd({0},{1},{2}) = {3}") + @CsvSource({ + "0, 0, 0, 0", + "0, 1, 1, 2", + "1, 0, 1, 2", + "5, 10, 15, 30", + "3, 1, -1, 3" + }) + public void _testAddThree(long arg1, int arg2, int arg3, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = indirectAdd_(arg1, arg2, arg3); + } + assertEquals(expected, result); + } + public static int indirectAdd_(long a, int b, int c) { + return LongTests.add_(a, b, c); + } + +} diff --git a/test/functional/MicroJIT/src/tests/LongTests.java b/test/functional/MicroJIT/src/tests/LongTests.java new file mode 100644 index 00000000000..6bd15296015 --- /dev/null +++ b/test/functional/MicroJIT/src/tests/LongTests.java @@ -0,0 +1,625 @@ +/******************************************************************************* + * Copyright (c) 2023, 2023 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +/* Tests that have dependencies must be labelled as @Order(2), @Order(3)... */ +/* Tests with no dependencies are labelled as @Order(1) */ + +public class LongTests { + + @Tag("addJ") + @Order(1) + @ParameterizedTest(name = "#{index} - add({0},{1}) = {2}") + @CsvSource({ + "0, 0, 0", + "0, 1, 1", + "1, 0, 1", + "101, -2, 99", + "-101, 101, 0", + "9223372036854775807, 9223372036854775807, -2", + "-9223372036854775808, 9223372036854775807, -1", + "9223372036854775807, 1, -9223372036854775808", + "2, 9223372036854775807, -9223372036854775807" + }) + public void testLAdd(long arg1, long arg2, long expected) { + long result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = add(arg1, arg2); + } + assertEquals(expected, result); + } + + @Tag("addJ") + @Order(1) + @ParameterizedTest(name = "#{index} - add({0},{1},{2}) = {3}") + @CsvSource({ + "0, 0, 0, 0", + "0, 1, 1, 2", + "1, 0, 1, 2", + "5, 10, 15, 30", + "3, 1, -1, 3" + }) + public void testLAdd3(long arg1, long arg2, long arg3, long expected) { + long result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = add(arg1, arg2, arg3); + } + assertEquals(expected, result); + } + + @Tag("addJ") + @Order(1) + @ParameterizedTest(name = "#{index} - add({0},{1},{2}) = {3}") + @CsvSource({ + "0, 0, 0, 0", + "0, 1, 1, 2", + "1, 0, 1, 2", + "5, 10, 15, 30", + "3, 1, -1, 3" + }) + public void testLAddJII(long arg1, int arg2, int arg3, long expected) { + long result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = add(arg1, arg2, arg3); + } + assertEquals(expected, result); + } + + @Tag("addJ") + @Order(1) + @ParameterizedTest(name = "#{index} - add({0},{1},{2}) = {3}") + @CsvSource({ + "0, 0, 0, 0", + "0, 1, 1, 2", + "1, 0, 1, 2", + "5, 10, 15, 30", + "3, 1, -1, 3" + }) + public void testLAddIJI(int arg1, long arg2, int arg3, long expected) { + long result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = add(arg1, arg2, arg3); + } + assertEquals(expected, result); + } + + @Tag("addJ") + @Order(1) + @ParameterizedTest(name = "#{index} - add({0},{1},{2}) = {3}") + @CsvSource({ + "0, 0, 0, 0", + "0, 1, 1, 2", + "1, 0, 1, 2", + "5, 10, 15, 30", + "3, 1, -1, 3" + }) + public void testLAddIIJ(int arg1, int arg2, long arg3, long expected) { + long result = 0L; + for (int i = 0; i < Helper.invocations(); i++) { + result = add(arg1, arg2, arg3); + } + assertEquals(expected, result); + } + + @Tag("addJ") + @Order(1) + @ParameterizedTest(name = "#{index} - add({0},{1}) = {2}") + @CsvSource({ + "0, 0, 0", + "0, 1, 1", + "1, 0, 1", + "2147483647, 1, 2147483648", + "-2147483648, 2147483647, -1" + }) + public void testIAdd(int arg1, long arg2, long expected) { + long result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = add(arg1, arg2); + } + assertEquals(expected, result); + } + + @Tag("add_I") + @Order(1) + @ParameterizedTest(name = "#{index} - add({0},{1},{2}) = {3}") + @CsvSource({ + "0, 0, 0, 0", + "0, 1, 1, 2", + "1, 0, 1, 2", + "5, 10, 15, 30", + "3, 1, -1, 3" + }) + public void testIAdd(long arg1, int arg2, int arg3, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = add_(arg1, arg2, arg3); + } + assertEquals(expected, result); + } + + public static long add(long x, long y) { + return x + y; + } + + public static long add(int x, long y) { + return x + y; + } + + public static long add(long x, long y, long z) { + return x + y + z; + } + + public static int add_(long x, int y, int z) { + return (int)x + y + z; + } + + public static long add(long x, int y, int z) { + return x + y + z; + } + + public static long add(int x, long y, int z) { + return x + y + z; + } + + public static long add(int x, int y, long z) { + return x + y + z; + } + + @Tag("subJ") + @Order(1) + @ParameterizedTest(name = "#{index} - sub({0},{1}) = {2}") + @CsvSource({ + "0, 0, 0", + "0, 1, -1", + "1, 0, 1", + "-1, -1, 0", + "101, 2, 99", + "9223372036854775807, 1, 9223372036854775806", + "-9223372036854775808, 1, 9223372036854775807", + "9223372036854775807, -1, -9223372036854775808", + "2,-9223372036854775807, -9223372036854775807" + }) + public void testLSub(long arg1, long arg2, long expected) { + long result = 0L; + for (int i = 0; i < Helper.invocations(); i++) { + result = sub(arg1, arg2); + } + assertEquals(expected, result); + } + + public static long sub(long x, long y) { + return x - y; + } + + @Tag("mulJ") + @Order(1) + @ParameterizedTest(name = "#{index} - mul({0},{1}) = {2}") + @CsvSource({ + "0, 0, 0", + "0, 1, 0", + "10, 10, 100", + "10, -10, -100", + "-10, 10, -100", + "-10, -10, 100", + "9223372036854775807, 1, 9223372036854775807", + "9223372036854775807, 0, 0", + "-9223372036854775808, 1, -9223372036854775808" + }) + public void testLMul(long arg1, long arg2, long expected) { + long result = 0L; + for (int i = 0; i < Helper.invocations(); i++) { + result = mul(arg1, arg2); + } + assertEquals(expected, result); + } + + public static long mul(long x, long y) { + return x * y; + } + + @Tag("divJ") + @Order(1) + @ParameterizedTest(name = "#{index} - div({0},{1}) = {2}") + @CsvSource({ + "0, 1, 0", + "100, 1, 100", + "1000, 100, 10", + "1000, -100, -10", + "-1000, 100, -10", + "-1000, -100, 10", + "1000, 20, 50", + "-256, 4, -64", + "9223372036854775807, 9223372036854775807, 1", + "-9223372036854775808, -9223372036854775808, 1", + "9223372036854775807, 1, 9223372036854775807", + + /* If the dividend is the negative integer of largest possible magnitude + for the long type and the divisor is -1, then overflow occurs and the + result is equal to the dividend; despite the overflow, no exception + is thrown in this case. */ + "-9223372036854775808, -1, -9223372036854775808" + }) + public void testLDiv(long arg1, long arg2, long expected) { + long result = 0L; + for (int i = 0; i < Helper.invocations(); i++) { + result = div(arg1, arg2); + } + assertEquals(expected, result); + } + +// Test commented out until we support exceptions like this +/* + @Test + @DisplayName("div(10,0)=divide by zero") + public void testLDivBy0() { + long result = 0L; + for (int i = 0; i < Helper.invocations(); i++) { + try { + result = div(10L,0L); + } + catch (java.lang.ArithmeticException e) { + assertEquals("divide by zero", e.getMessage()); + } + } + } +*/ + + public static long div(long x, long y) { + return x / y; + } + + @Tag("remJ") + @Order(1) + @ParameterizedTest(name = "#{index} - rem({0},{1}) = {2}") + @CsvSource({ + "0, 1, 0", + "1000, 100, 0", + "29, 8, 5", + "-29, 8, -5", + "29, -8, 5", + "-29, -8, -5", + "9223372036854775807, 9223372036854775807, 0", + "9223372036854775807, -1, 0", + "-9223372036854775808, -9223372036854775808, 0", + "-9223372036854775808, -1, 0" + }) + public void testLRem(long arg1, long arg2, long expected) { + long result = 0L; + for (int i = 0; i < Helper.invocations(); i++) { + result = rem(arg1, arg2); + } + assertEquals(expected, result); + } + +// Test commented out until we support exceptions like this +/* + @Test + @DisplayName("rem(10,0)=divide by zero") + public void testLRemBy0() { + long result = 0L; + for (int i = 0; i < Helper.invocations(); i++) { + try { + result = rem(10L,0L); + } + catch (java.lang.ArithmeticException e) { + assertEquals("divide by zero", e.getMessage()); + } + } + } +*/ + + public static long rem(long x, long y) { + return x % y; + } + + @Tag("negJ") + @Order(1) + @ParameterizedTest(name = "#{index} - neg({0}) = {1}") + @CsvSource({ + "1000, -1000", + "100, -100", + "-59, 59", + "9223372036854775807, -9223372036854775807", + "-9223372036854775808, -9223372036854775808", // JVM Section 6.5: Negation of the maximum negative long results in that same maximum negative number + "-1, 1", + "3, -3", + "0, 0" + }) + public void testLNeg(long arg1, long expected) { + long result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = neg(arg1); + } + assertEquals(expected, result); + } + + public static long neg(long x) { + return -x; + } + + @Tag("shlJ") + @Order(1) + @ParameterizedTest(name = "#{index} - shl({0},{1}) = {2}") + @CsvSource({ + "0, 0, 0", + "0, 63, 0", + "1, 0, 1", + "-1, 0, -1", + "-1, 63, -9223372036854775808", + "1, 63, -9223372036854775808", + "1, 62, 4611686018427387904", + "16, 2, 64", + "-16, 2, -64", + "1000000, 43, 8796093022208000000", + "-1000000, 43, -8796093022208000000", + "9223372036854775807, 0, 9223372036854775807", + "-9223372036854775808, 0, -9223372036854775808" + }) + public void testLShl(long arg1, int arg2, long expected) { + long result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = shl(arg1, arg2); + } + assertEquals(expected, result); + } + + public static long shl(long x, int y) { + return x << y; + } + + @Tag("shrJ") + @Order(1) + @ParameterizedTest(name = "#{index} - shr({0},{1}) = {2}") + @CsvSource({ + "0, 0, 0", + "0, 63, 0", + "1, 0, 1", + "-1, 0, -1", + "1, 63, 0", + "-1, 63, -1", + "256, 2, 64", + "-256, 2, -64", + "100000000000, 20, 95367", + "-100000000000, 20, -95368", + "100000000000, 50, 0", + "-100000000000, 50, -1", + "9223372036854775807, 0, 9223372036854775807", + "-9223372036854775808, 0, -9223372036854775808", + "9223372036854775807, 1, 4611686018427387903", + "-9223372036854775807, 1, -4611686018427387904", + "-9223372036854775808, 1, -4611686018427387904", + "-9223372036854775808, 63, -1", + "9223372036854775807, 63, 0" + }) + public void testLShr(long arg1, int arg2, long expected) { + long result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = shr(arg1, arg2); + } + assertEquals(expected, result); + } + + public static long shr(long x, int y) { + return x >> y; + } + + @Tag("ushrJ") + @Order(1) + @ParameterizedTest(name = "#{index} - ushr({0},{1}) = {2}") + @CsvSource({ + "0, 0, 0", + "0, 63, 0", + "1, 0, 1", + "-1, 0, -1", + "1, 63, 0", + "-1, 63, 1", + "256, 2, 64", + "-256, 2, 4611686018427387840", + "100000000000, 20, 95367", + "-100000000000, 20, 17592185949048", + "100000000000, 50, 0", + "-100000000000, 50, 16383", + "9223372036854775807, 0, 9223372036854775807", + "-9223372036854775808, 0, -9223372036854775808", + "9223372036854775807, 1, 4611686018427387903", + "-9223372036854775807, 1, 4611686018427387904", + "-9223372036854775808, 1, 4611686018427387904", + "-9223372036854775808, 63, 1", + "9223372036854775807, 63, 0" + }) + public void testLUshr(long arg1, int arg2, long expected) { + long result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = ushr(arg1, arg2); + } + assertEquals(expected, result); + } + + public static long ushr(long x, int y) { + return x >>> y; + } + + @Tag("andJ") + @Order(1) + @ParameterizedTest(name = "#{index} - and({0},{1}) = {2}") + @CsvSource({ + "0, 0, 0", + "0, 1, 0", + "1, 0, 0", + "1, 1, 1", + "-101, 101, 1", + "9223372036854775807, 9223372036854775807, 9223372036854775807", + "-9223372036854775808, 9223372036854775807, 0", + "9223372036854775807, 1, 1", + "2, 9223372036854775807, 2" + }) + public void testLAnd(long arg1, long arg2, long expected) { + long result = 0L; + for (int i = 0; i < Helper.invocations(); i++) { + result = and(arg1, arg2); + } + assertEquals(expected, result); + } + + @Tag("andJ") + @Order(1) + @Test + @DisplayName("and(10,10,10)=10") + public void testLAnd3() { + long result = 0L; + for (int i = 0; i < Helper.invocations(); i++) { + result = and(10L, 10L, 10L); + } + assertEquals(10L, result); + } + + public static long and(long x, long y) { + return x & y; + } + + public static long and(long x, long y, long z) { + return x & y & z; + } + + @Tag("orJ") + @Order(1) + @ParameterizedTest(name = "#{index} - or({0},{1}) = {2}") + @CsvSource({ + "0, 0, 0", + "0, 1, 1", + "1, 0, 1", + "1, 1, 1", + "-101, 101, -1", + "9223372036854775807, 9223372036854775807, 9223372036854775807", + "-9223372036854775808, 9223372036854775807, -1", + "9223372036854775807, 1, 9223372036854775807", + "2, 9223372036854775807, 9223372036854775807" + }) + public void testLOr(long arg1, long arg2, long expected) { + long result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = or(arg1, arg2); + } + assertEquals(expected, result); + } + + public static long or(long x, long y) { + return x | y; + } + + @Tag("xorJ") + @Order(1) + @ParameterizedTest(name = "#{index} - xor({0},{1}) = {2}") + @CsvSource({ + "0, 0, 0", + "0, 1, 1", + "1, 0, 1", + "1, 1, 0", + "-101, 101, -2", + "9223372036854775807, 9223372036854775807, 0", + "-9223372036854775808, 9223372036854775807, -1", + "9223372036854775807, 1, 9223372036854775806", + "2, 9223372036854775807, 9223372036854775805" + }) + public void testLXor(long arg1, long arg2, long expected) { + long result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = xor(arg1, arg2); + } + assertEquals(expected, result); + } + + public static long xor(long x, long y) { + return x ^ y; + } + + @Tag("lconst_0<>J") + @Order(1) + @ParameterizedTest(name = "#{index} - lconst_0() = {0}") + @CsvSource({ + "0" + }) + public void testLConst_0(long expected) { + long result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = lconst_0(); + } + assertEquals(expected, result); + } + + public static long lconst_0() { + return (long)0; + } + + @Tag("lconst_1<>J") + @Order(1) + @ParameterizedTest(name = "#{index} - lconst_1() = {0}") + @CsvSource({ + "1" + }) + public void testLConst_1(long expected) { + long result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = lconst_1(); + } + assertEquals(1, result); + } + + public static long lconst_1() { + return (long)1; + } + + @Tag("lcmpI") + @Order(2) + @ParameterizedTest(name = "#{index} - lcmp({0}, {1}) = {2}") + @CsvSource({ + "0, 0, 0", + "1, 0, 1", + "0, 1, -1", + "1, 1, 0", + "45, 26, 1", + "26, 45, -1", + "7, 7, 0", + "9223372036854775807, -1, 1", + "9223372036854775807, 0, 1" + }) + public void test_lcmp(long arg1, long arg2, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = lcmp(arg1, arg2); + } + assertEquals(expected, result); + } + + public static int lcmp(long a, long b) { + return lcmp.lcmp(a, b); + } + +} diff --git a/test/functional/MicroJIT/src/tests/StackTests.java b/test/functional/MicroJIT/src/tests/StackTests.java new file mode 100644 index 00000000000..24ba5bc6ead --- /dev/null +++ b/test/functional/MicroJIT/src/tests/StackTests.java @@ -0,0 +1,359 @@ +/******************************************************************************* + * Copyright (c) 2023, 2023 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +/* Tests that have dependencies must be labelled as @Order(2), @Order(3)... */ +/* Tests with no dependencies are labelled as @Order(1) */ + +public class StackTests { + + @Tag("popV") + @Order(1) + @ParameterizedTest(name = "#{index} - popTest({0})") + @CsvSource({ + "0", + "1", + "2", + "2147483647" + }) + public void testPop(int arg1) { + for (int i = 0; i < Helper.invocations(); i++) { + pop(arg1); + } + } + + public static int return_int(int x) { + return x; + } + + public static void pop(int a) { + return_int(a); + } + + @Tag("pop2V") + @Order(1) + @ParameterizedTest(name = "#{index} - pop2Test({0})") + @CsvSource({ + "0", + "1", + "2", + "2147483647", + "9223372036854775807" + }) + public void testPop2(long arg1) { + for (int i = 0; i < Helper.invocations(); i++) { + pop2(arg1); + } + } + + public static long return_long(long x) { + return x; + } + + public static void pop2(long a) { + return_long(a); + } + + @Tag("swapI") + @Order(2) + @ParameterizedTest(name = "#{index} - swap({0}, {1}, {2}) = {3}") + @CsvSource({ + "0, 1, 1, 2", + "1, 1, 2, 3", + "2, 7, 9, 16", + "10, 5, 15, 20" + }) + public void testSwap(int arg1, int arg2, int arg3, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = swap(arg1, arg2, arg3); + } + assertEquals(expected, result); + } + + public static int swap(int x, int y, int z) { + return Swap.swap(x, y, z); + } + + @Tag("dupI") + @Order(1) + @ParameterizedTest(name = "#{index} - dup({0}, {1}) = {2}") + @CsvSource({ + "0, 1, 1", + "1, 1, 2", + "2, 7, 9", + "10, 5, 15" + }) + public void testDup(int arg1, int arg2, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = dup(arg1, arg2); + } + assertEquals(expected, result); + } + + public static int dup(int a, int b) { + return a += b; + } + + @Tag("dup2Form1I") + @Order(1) + @ParameterizedTest(name = "#{index} - dup2Form1({0}, {1}) = {2}") + @CsvSource({ + "0, 1, 2", + "1, 1, 4", + "2, 7, 18", + "10, 5, 30" + }) + public void testDup2Form1(int arg1, int arg2, int expected) { + long result = 0; + for (long i = 0; i < Helper.invocations(); i++) { + result = dup2Form1(arg1, arg2); + + } + assertEquals(expected, result); + } + + public static int dup2Form1(int a, int b) { + return Dup.dup2Form1(a, b); + } + + @Tag("dup2Form2J") + @Order(1) + @ParameterizedTest(name = "#{index} - dup2Form2({0}, {1}) = {2}") + @CsvSource({ + "0, 1, 1", + "1, 1, 2", + "2, 7, 9", + "10, 5, 15" + }) + public void testDup2Form2(long arg1, long arg2, long expected) { + long result = 0; + for (long i = 0; i < Helper.invocations(); i++) { + result = dup2Form2(arg1, arg2); + + } + assertEquals(expected, result); + } + + public static long dup2Form2(long a, long b) { + return a += b; + } + + @Tag("dup_x1I") + @Order(2) + @ParameterizedTest(name = "#{index} - dup_x1({0}, {1}) = {2}") + @CsvSource({ + "0, 1, 2", + "1, 1, 3", + "2, 7, 16", + "10, 5, 20" + }) + public void testDup_x1(int arg1, int arg2, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = dup_x1(arg1, arg2); + } + assertEquals(expected, result); + } + + public static int dup_x1(int x, int y) { + return Dup.dup_x1(x, y); + } + + @Tag("dup_x2Form1I") + @Order(2) + @ParameterizedTest(name = "#{index} - dup_x2Form1({0}, {1}, {2}) = {3}") + @CsvSource({ + "0, 1, 1, 3", + "1, 1, 2, 6", + "2, 7, 9, 27", + "10, 5, 15, 45" + }) + public void testDup_x2Form1(int arg1, int arg2, int arg3, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = dup_x2Form1(arg1, arg2, arg3); + } + assertEquals(expected, result); + } + + public static int dup_x2Form1(int x, int y, int z) { + return Dup.dup_x2Form1(x, y, z); + } + + @Tag("dup_x2Form2I") + @Order(2) + @ParameterizedTest(name = "#{index} - dup_x2Form2({0}, {1}) = {2}") + @CsvSource({ + "0, 1, 2", + "1, 1, 3", + "2, 7, 16", + "10, 5, 20" + }) + public void testDup_x2Form2(long arg1, int arg2, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = dup_x2Form2(arg1, arg2); + } + assertEquals(expected, result); + } + + public static int dup_x2Form2(long x, int y) { + return Dup.dup_x2Form2(x, y); + } + + @Tag("dup2_x1Form1I") + @Order(2) + @ParameterizedTest(name = "#{index} - dup2_x1Form1({0}, {1}, {2}) = {3}") + @CsvSource({ + "0, 1, 1, 4", + "1, 1, 2, 7", + "2, 7, 9, 34", + "10, 5, 15, 50" + }) + public void testDup2_x1Form1(int arg1, int arg2, int arg3, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = dup2_x1Form1(arg1, arg2, arg3); + } + assertEquals(expected, result); + } + + public static int dup2_x1Form1(int x, int y, int z) { + return Dup.dup2_x1Form1(x, y, z); + } + + @Tag("dup2_x1Form2J") + @Order(2) + @ParameterizedTest(name = "#{index} - dup2_x1Form2({0}, {1}) = {2}") + @CsvSource({ + "2, 7, 16", + "0, 1, 2", + "1, 1, 3", + "10, 5, 20" + }) + public void testDup2_x1Form2(int arg1, long arg2, long expected) { + long result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = dup2_x1Form2(arg1, arg2); + } + assertEquals(expected, result); + } + + public static long dup2_x1Form2(int x, long y) { + return Dup.dup2_x1Form2(x, y); + } + + @Tag("dup2_x2Form1I") + @Order(2) + @ParameterizedTest(name = "#{index} - dup2_x2Form1({0}, {1}, {2}, {3}) = {4}") + @CsvSource({ + "1, 1, 2, 3, 12", + "0, 1, 1, 6, 15", + "2, 7, 9, 10, 47", + "10, 5, 15, 20, 85" + }) + public void testDup2_x2Form1(int arg1, int arg2, int arg3, int arg4, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = dup2_x2Form1(arg1, arg2, arg3, arg4); + } + assertEquals(expected, result); + } + + public static int dup2_x2Form1(int w, int x, int y, int z) { + return Dup.dup2_x2Form1(w, x, y, z); + } + + @Tag("dup2_x2Form2J") + @Order(2) + @ParameterizedTest(name = "#{index} - dup2_x2Form2({0}, {1}, {2}) = {3}") + @CsvSource({ + "0, 1, 1, 3", + "1, 1, 2, 6", + "2, 7, 9, 27", + "10, 5, 15, 45" + }) + public void testDup2_x2Form2(int arg1, int arg2, long arg3, long expected) { + long result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = dup2_x2Form2(arg1, arg2, arg3); + } + assertEquals(expected, result); + } + + public static long dup2_x2Form2(int x, int y, long z) { + return Dup.dup2_x2Form2(x, y, z); + } + + @Tag("dup2_x2Form3I") + @Order(2) + @ParameterizedTest(name = "#{index} - dup2_x2Form3({0}, {1}, {2}) = {3}") + @CsvSource({ + "0, 1, 1, 4", + "1, 1, 2, 7", + "2, 7, 9, 34", + "10, 5, 15, 50" + }) + public void testDup2_x2Form3(long arg1, int arg2, int arg3, int expected) { + int result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = dup2_x2Form3(arg1, arg2, arg3); + } + assertEquals(expected, result); + } + + public static int dup2_x2Form3(long x, int y, int z) { + return Dup.dup2_x2Form3(x, y, z); + } + + @Tag("dup2_x2Form4J") + @Order(2) + @ParameterizedTest(name = "#{index} - dup2_x2Form4({0}, {1}) = {2}") + @CsvSource({ + "0, 1, 2", + "1, 1, 3", + "2, 7, 16", + "10, 5, 20" + }) + public void testDup2_x2Form4(long arg1, long arg2, long expected) { + long result = 0; + for (int i = 0; i < Helper.invocations(); i++) { + result = dup2_x2Form4(arg1, arg2); + } + assertEquals(expected, result); + } + + public static long dup2_x2Form4(long x, long y) { + return Dup.dup2_x2Form4(x, y); + } + +} diff --git a/test/functional/MicroJIT/test-list.txt b/test/functional/MicroJIT/test-list.txt new file mode 100644 index 00000000000..cbd680b3de1 --- /dev/null +++ b/test/functional/MicroJIT/test-list.txt @@ -0,0 +1,191 @@ +################################################################################ +# Copyright (c) 2023, 2023 IBM Corp. and others +# +# This program and the accompanying materials are made available under +# the terms of the Eclipse Public License 2.0 which accompanies this +# distribution and is available at https://www.eclipse.org/legal/epl-2.0/ +# or the Apache License, Version 2.0 which accompanies this distribution and +# is available at https://www.apache.org/licenses/LICENSE-2.0. +# +# This Source Code may also be made available under the following +# Secondary Licenses when the conditions for such availability set +# forth in the Eclipse Public License, v. 2.0 are satisfied: GNU +# General Public License, version 2 with the GNU Classpath +# Exception [1] and GNU General Public License, version 2 with the +# OpenJDK Assembly Exception [2]. +# +# [1] https://www.gnu.org/software/classpath/license.html +# [2] http://openjdk.java.net/legal/assembly-exception.html +# +# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception +################################################################################ + +# Format is method_signature + +# If the test you are adding is dependent on another method being compiled by MicroJIT, +# the dependency array must be added to the test invocation. + +# From Table 4.3-A of JVM: +# +# | FieldType term | Type | +# |----------------|---------------------------------------------| +# | B | byte | +# | C | char | +# | D | double | +# | F | float | +# | I | int | +# | J | long | +# | L ClassName ; | reference -> an instance of class ClassName | +# | S | short | +# | Z | boolean | +# | [ | reference -> one array dimension | + +IntTests.addI +IntTests.addI +IntTests.addI +IntTests.subI +IntTests.mulI +IntTests.divI +IntTests.remI +IntTests.incI +IntTests.negI +IntTests.shlI +IntTests.shrI +IntTests.ushrI +IntTests.andI +IntTests.orI +IntTests.xorI +IntTests.iconst_m1<>I +IntTests.iconst_0<>I +IntTests.iconst_1<>I +IntTests.iconst_2<>I +IntTests.iconst_3<>I +IntTests.iconst_4<>I +IntTests.iconst_5<>I +IntTests.bipush_m32<>I +IntTests.bipush_31<>I +IntTests.sipush_32767<>I +IntTests.sipush_m32768<>I +LongTests.addJ +LongTests.addJ +LongTests.addJ +LongTests.addJ +LongTests.addJ +LongTests.addJ +LongTests.add_I +LongTests.subJ +LongTests.mulJ +LongTests.divJ +LongTests.remJ +LongTests.negJ +LongTests.shlJ +LongTests.shrJ +LongTests.ushrJ +LongTests.lconst_0<>J +LongTests.lconst_1<>J +LongTests.andJ +LongTests.andJ +LongTests.orJ +LongTests.xorJ +LongTests.lcmpI: [ lcmp.lcmpI ] +GetPutStaticTests.add<>I: [ GetPutStaticTests.setIntsV ] +GetPutStaticTests.sub<>I: [ GetPutStaticTests.setIntsV ] +GetPutStaticTests.mul<>I: [ GetPutStaticTests.setIntsV ] +GetPutStaticTests.div<>I: [ GetPutStaticTests.setIntsV ] +GetPutStaticTests.and<>I: [ GetPutStaticTests.setIntsV ] +GetPutStaticTests.or<>I: [ GetPutStaticTests.setIntsV ] +GetPutStaticTests.xor<>I: [ GetPutStaticTests.setIntsV ] +GetPutStaticTests.addLong<>J: [ GetPutStaticTests.setLongsV ] +GetPutStaticTests.addFloat<>F: [ GetPutStaticTests.setFloatsV ] +GetPutStaticTests.addDouble<>D: [ GetPutStaticTests.setDoubles
V ] +GetPutFieldTests.getField<>I: [ GetPutFieldTests.putFieldV ] +GetPutFieldTests.add<>I: [ GetPutFieldTests.setIntsV ] +GetPutFieldTests.getFieldL<>J: [ GetPutFieldTests.putFieldLV ] +GetPutFieldTests.addL<>J: [ GetPutFieldTests.setLongsV ] +GetPutFieldTests.getFieldF<>F: [ GetPutFieldTests.putFieldFV ] +GetPutFieldTests.addF<>F: [ GetPutFieldTests.setFloatsV ] +GetPutFieldTests.getFieldD<>D: [ GetPutFieldTests.putFieldDV ] +GetPutFieldTests.addD<>D: [ GetPutFieldTests.setDoubles
V ] +BranchTests.gotoTestI +BranchTests.ifeqTestI +BranchTests.ifneTestI +BranchTests.ifltTestI +BranchTests.ifleTestI +BranchTests.ifgtTestI +BranchTests.ifgeTestI +BranchTests.if_icmpneTestI +BranchTests.if_icmpeqTestI +BranchTests.if_icmpltTestI +BranchTests.if_icmpleTestI +BranchTests.if_icmpgtTestI +BranchTests.if_icmpgeTestI +ConversionTests.i2lJ +ConversionTests.l2iI +ConversionTests.i2bB +ConversionTests.i2sS +ConversionTests.i2cC +ConversionTests.i2dD +ConversionTests.l2dD +ConversionTests.d2iI +ConversionTests.d2lJ +ConversionTests.i2fF +ConversionTests.f2iI +ConversionTests.l2fF +ConversionTests.f2lJ +ConversionTests.d2fF +ConversionTests.f2dD +InvokeTests.indirectAddI: [ IntTests.addI ] +InvokeTests.indirectSubI: [ IntTests.subI ] +InvokeTests.indirectMulI: [ IntTests.mulI ] +InvokeTests.indirectDivI: [ IntTests.divI ] +InvokeTests.indirectLAddJ: [ LongTests.addJ ] +InvokeTests.indirectFAddF: [ FloatTests.addF ] +InvokeTests.indirectDAdd
D: [ DoubleTests.add
D ] +InvokeTests.indirectAddI: [ IntTests.addI ] +InvokeTests.indirectAddI: [ IntTests.addI ] +InvokeTests.indirectAddJ: [ LongTests.addJ ] +InvokeTests.indirectAddJ: [ LongTests.addJ ] +InvokeTests.indirectAdd_I: [ LongTests.add_I ] +InvokeTests.indirectAddJ: [ LongTests.addJ ] +FloatTests.addF +FloatTests.addF +# Tests fail when the argument count exceeds the limit that can be +# handled by registers and have to be stored in stack instead. +# IntTests.addI -> Fails with MicroJIT +# FloatTests.addF -> Fails with MicroJIT +# FloatTests.addF -> Fails with MicroJIT +FloatTests.subF +FloatTests.mulF +FloatTests.divF +FloatTests.remF +FloatTests.negF +FloatTests.fconst_0<>F +FloatTests.fconst_1<>F +FloatTests.fconst_2<>F +FloatTests.fcmplI: [ fcmp.fcmplI ] +FloatTests.fcmpgI: [ fcmp.fcmpgI ] +DoubleTests.add
D +DoubleTests.sub
D +DoubleTests.mul
D +DoubleTests.div
D +DoubleTests.rem
D +DoubleTests.negD +DoubleTests.dconst_0<>D +DoubleTests.dconst_1<>D +StackTests.popV +StackTests.pop2V +StackTests.swapI: [ Swap.swapI ] +StackTests.dupI +StackTests.dup2Form1I: [ Dup.dup2Form1I ] +StackTests.dup2Form2J +StackTests.dup_x1I: [ Dup.dup_x1I ] +StackTests.dup_x2Form1I: [ Dup.dup_x2Form1I ] +StackTests.dup_x2Form2I: [ Dup.dup_x2Form2I ] +StackTests.dup2_x1Form1I: [ Dup.dup2_x1Form1I ] +StackTests.dup2_x1Form2J: [ Dup.dup2_x1Form2J ] +StackTests.dup2_x2Form1I: [ Dup.dup2_x2Form1I ] +StackTests.dup2_x2Form2J: [ Dup.dup2_x2Form2J ] +StackTests.dup2_x2Form3I: [ Dup.dup2_x2Form3I ] +StackTests.dup2_x2Form4J: [ Dup.dup2_x2Form4J ] +DoubleTests.dcmpl
I: [ dcmp.dcmpl
I ] +DoubleTests.dcmpg
I: [ dcmp.dcmpg
I ]