diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index f2d5f1c84d..2395483b55 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -4,11 +4,13 @@ on: push: branches: - main + tags: + - 'v*' pull_request: branches: - main env: - MACOSX_DEPLOYMENT_TARGET: 12.0 + MACOSX_DEPLOYMENT_TARGET: 15.0 jobs: Build: @@ -17,13 +19,19 @@ jobs: strategy: fail-fast: false matrix: - os: ["ubuntu-latest", "macos-latest", "windows-2019"] + os: ["ubuntu-latest", "macos-latest", "windows-2025"] python-version: ["3.10"] steps: - uses: actions/checkout@v3 with: + submodules: true fetch-depth: 0 + - name: Git Submodule Update + shell: bash -e -l {0} + run: | + git submodule update --init --recursive + - name: Cache conda uses: actions/cache@v3 env: @@ -33,32 +41,33 @@ jobs: key: ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-${{ hashFiles('ci/environment.yml') }} - - uses: conda-incubator/setup-miniconda@v2 + - uses: mamba-org/setup-micromamba@v1.9.0 with: - auto-update-conda: true environment-file: ci/environment.yml - python-version: ${{ matrix.python-version }} - use-only-tar-bz2: true + create-args: >- + python=${{ matrix.python-version }} + cmake=3.30.0 + nodejs=18.20.5 - name: Install Windows Conda Packages if: contains(matrix.os, 'windows') - shell: bash -l {0} - run: conda install m2-bison=3.0.4 + shell: bash -e -l {0} + run: micromamba install --freeze-installed m2-bison=3.0.4 m2-filesystem - name: Install Linux / macOS Conda Packages if: contains(matrix.os, 'ubuntu') || contains(matrix.os, 'macos') - shell: bash -l {0} - run: conda install bison=3.4 + shell: bash -e -l {0} + run: micromamba install --freeze-installed bison=3.4 - name: Conda info - shell: bash -l {0} + shell: bash -e -l {0} run: | - conda info - conda list + micromamba info + micromamba list - name: Setup Platform (Linux) if: contains(matrix.os, 'ubuntu') - shell: bash -l {0} + shell: bash -e -l {0} run: | echo "LFORTRAN_CMAKE_GENERATOR=Unix Makefiles" >> $GITHUB_ENV echo "WIN=0" >> $GITHUB_ENV @@ -67,7 +76,7 @@ jobs: - name: Setup Platform (macOS) if: contains(matrix.os, 'macos') - shell: bash -l {0} + shell: bash -e -l {0} run: | echo "LFORTRAN_CMAKE_GENERATOR=Unix Makefiles" >> $GITHUB_ENV echo "WIN=0" >> $GITHUB_ENV @@ -75,7 +84,7 @@ jobs: echo "ENABLE_RUNTIME_STACKTRACE=yes" >> $GITHUB_ENV - name: Build (Linux / macOS) - shell: bash -l {0} + shell: bash -e -l {0} if: contains(matrix.os, 'ubuntu') || contains(matrix.os, 'macos') run: | xonsh ci/build.xsh @@ -84,18 +93,21 @@ jobs: if: contains(matrix.os, 'windows') shell: cmd run: | - set CONDA_INSTALL_LOCN=C:\\Miniconda - call %CONDA_INSTALL_LOCN%\Scripts\activate.bat - call conda activate test + set MAMBA_INSTALL_LOCN=C:\\Users\runneradmin\micromamba + call %MAMBA_INSTALL_LOCN%\Scripts\activate.bat + call micromamba activate lp set LFORTRAN_CMAKE_GENERATOR=Ninja set WIN=1 set MACOS=0 set ENABLE_RUNTIME_STACKTRACE=no - call "C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Auxiliary/Build/vcvars64.bat" + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" + set CC=cl.exe + set CXX=cl.exe + set "PATH=%PATH:C:\mingw64\bin;=%" # Remove mingw from path xonsh ci\build.xsh - name: Test (Linux / macOS) - shell: bash -l {0} + shell: bash -e -l {0} if: contains(matrix.os, 'ubuntu') || contains(matrix.os, 'macos') run: | xonsh ci/test.xsh @@ -104,27 +116,36 @@ jobs: if: contains(matrix.os, 'windows') shell: cmd run: | - set CONDA_INSTALL_LOCN=C:\\Miniconda - call %CONDA_INSTALL_LOCN%\Scripts\activate.bat - call conda activate test + set MAMBA_INSTALL_LOCN=C:\\Users\runneradmin\micromamba + call %MAMBA_INSTALL_LOCN%\Scripts\activate.bat + call micromamba activate lp set LFORTRAN_CMAKE_GENERATOR=Ninja set WIN=1 set MACOS=0 - call "C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Auxiliary/Build/vcvars64.bat" + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" + set CC=cl.exe + set CXX=cl.exe + set "PATH=%PATH:C:\mingw64\bin;=%" # Remove mingw from path xonsh ci\test.xsh build_to_wasm: name: Build LPython to WASM - runs-on: "ubuntu-latest" + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: + submodules: true fetch-depth: 0 - - uses: mamba-org/provision-with-micromamba@main + - name: Git Submodule Update + shell: bash -e -l {0} + run: | + git submodule update --init --recursive + + - uses: mamba-org/setup-micromamba@v1 with: environment-file: ci/environment.yml - extra-specs: | + create-args: >- python=3.10 bison=3.4 @@ -133,6 +154,13 @@ jobs: variant: sccache key: ${{ github.job }}-${{ matrix.os }} + - name : Remove existing node + shell: bash -l {0} + run : | + which node + node -v + sudo rm -rf /usr/local/bin/node /usr/local/bin/npm + - name: Install Emscripten from Git shell: bash -l {0} run: | @@ -142,13 +170,12 @@ jobs: git clone https://github.com/emscripten-core/emsdk.git cd emsdk - # Download and install the latest SDK tools. - ./emsdk install latest + ./emsdk install 3.1.35 + ./emsdk activate 3.1.35 + ./emsdk install node-18.20.3-64bit + ./emsdk activate node-18.20.3-64bit - # Make the "latest" SDK "active" for the current user. (writes .emscripten file) - ./emsdk activate latest - - - name: Show Emscripten Info + - name: Show Emscripten and Node Info shell: bash -l {0} run: | set -ex @@ -156,13 +183,14 @@ jobs: source $HOME/ext/emsdk/emsdk_env.sh emcc -v em++ -v + which node + node -v - name: Build to WASM shell: bash -l {0} run: | set -ex source $HOME/ext/emsdk/emsdk_env.sh # Activate Emscripten - ./build0.sh ./build_to_wasm.sh - name: Test built lpython.wasm @@ -170,4 +198,493 @@ jobs: run: | set -ex source $HOME/ext/emsdk/emsdk_env.sh # Activate Emscripten + which node + node -v node src/lpython/tests/test_lpython.js + + test_pip_pkgs: + name: Test PIP Installable Packages + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + submodules: true + fetch-depth: 0 + + - name: Git Submodule Update + shell: bash -e -l {0} + run: | + git submodule update --init --recursive + + - uses: mamba-org/setup-micromamba@v1 + with: + environment-file: ci/environment.yml + create-args: >- + python=3.10 + bison=3.4 + + - uses: hendrikmuhs/ccache-action@main + with: + variant: sccache + key: ${{ github.job }}-${{ matrix.os }} + + - name: Build Linux + shell: bash -e -l {0} + run: | + ./build0.sh + cmake . -GNinja \ + -DCMAKE_BUILD_TYPE=Debug \ + -DWITH_LLVM=yes \ + -DLFORTRAN_BUILD_ALL=yes \ + -DWITH_STACKTRACE=no \ + -DWITH_RUNTIME_STACKTRACE=yes \ + -DCMAKE_PREFIX_PATH="$CONDA_PREFIX" \ + -DCMAKE_INSTALL_PREFIX=`pwd`/inst \ + -DCMAKE_C_COMPILER_LAUNCHER=sccache \ + -DCMAKE_CXX_COMPILER_LAUNCHER=sccache + + cmake --build . -j16 --target install + + - name: PIP show version + shell: bash -e -l {0} + run: | + python -m pip -V + + - name: PIP install required packages + shell: bash -e -l {0} + run: | + # Package lpynn has lpython_emulation as dependency + # Hence, it should by default install lpython_emulation + python -m pip install lpython_emulation==0.0.1.9 lpynn==0.0.1.4 numpy==1.24.3 + + - name: PIP show installed packages + shell: bash -e -l {0} + run: | + python -m pip list + + - name: Test PIP Packages with Python + shell: bash -e -l {0} + run: | + python integration_tests/test_pip_import_01.py + + # - name: Test PIP Packages with LPython + # shell: bash -e -l {0} + # run: | + # pip_pkg_path=$(python -c "import site; print(site.getsitepackages()[0])") + # echo $pip_pkg_path + # ./src/bin/lpython integration_tests/test_pip_import_01.py -I $pip_pkg_path + + debug: + name: Check Debug build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + submodules: true + fetch-depth: 0 + + - name: Git Submodule Update + shell: bash -e -l {0} + run: | + git submodule update --init --recursive + + - uses: mamba-org/setup-micromamba@v1 + with: + environment-file: ci/environment.yml + create-args: >- + python=3.10 + bison=3.4 + + - uses: hendrikmuhs/ccache-action@main + with: + variant: sccache + key: ${{ github.job }}-${{ matrix.os }} + + - name: Build Linux + shell: bash -e -l {0} + run: | + ./build0.sh + export CXXFLAGS="-Werror" + cmake . -GNinja \ + -DCMAKE_BUILD_TYPE=Debug \ + -DWITH_LLVM=yes \ + -DLFORTRAN_BUILD_ALL=yes \ + -DWITH_STACKTRACE=no \ + -DWITH_RUNTIME_STACKTRACE=yes \ + -DCMAKE_PREFIX_PATH="$CONDA_PREFIX" \ + -DCMAKE_INSTALL_PREFIX=`pwd`/inst \ + -DCMAKE_C_COMPILER_LAUNCHER=sccache \ + -DCMAKE_CXX_COMPILER_LAUNCHER=sccache + + cmake --build . -j16 --target install + + - name: Test Linux + shell: bash -e -l {0} + run: | + ctest + ./run_tests.py -s + cd integration_tests + ./run_tests.py -b llvm c + ./run_tests.py -b llvm c -f + + release: + name: Check Release build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + submodules: true + fetch-depth: 0 + + - name: Git Submodule Update + shell: bash -e -l {0} + run: | + git submodule update --init --recursive + + - uses: mamba-org/setup-micromamba@v1 + with: + environment-file: ci/environment.yml + create-args: >- + python=3.10 + bison=3.4 + + - uses: hendrikmuhs/ccache-action@main + with: + variant: sccache + key: ${{ github.job }}-${{ matrix.os }} + + - name: Build Linux + shell: bash -e -l {0} + run: | + ./build0.sh + export CXXFLAGS="-Werror" + cmake . -GNinja \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_CXX_FLAGS_RELEASE="-Wall -Wextra -O3 -funroll-loops -DNDEBUG" \ + -DWITH_LLVM=yes \ + -DLFORTRAN_BUILD_ALL=yes \ + -DWITH_STACKTRACE=no \ + -DWITH_RUNTIME_STACKTRACE=yes \ + -DCMAKE_PREFIX_PATH="$CONDA_PREFIX" \ + -DCMAKE_INSTALL_PREFIX=`pwd`/inst \ + -DCMAKE_C_COMPILER_LAUNCHER=sccache \ + -DCMAKE_CXX_COMPILER_LAUNCHER=sccache + + cmake --build . -j16 --target install + + - name: Test Linux + shell: bash -e -l {0} + run: | + ctest --rerun-failed --output-on-failure + ./run_tests.py -s + cd integration_tests + ./run_tests.py -b llvm c + ./run_tests.py -b llvm c -f + + cpython_interop: + name: Test CPython Interop (@pythoncall) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + submodules: true + fetch-depth: 0 + + - name: Git Submodule Update + shell: bash -e -l {0} + run: | + git submodule update --init --recursive + + - uses: mamba-org/setup-micromamba@v1 + with: + environment-file: ci/environment.yml + create-args: >- + python=3.10 + bison=3.4 + + - uses: hendrikmuhs/ccache-action@main + with: + variant: sccache + key: ${{ github.job }}-${{ matrix.os }} + + - name: Build Linux + shell: bash -e -l {0} + run: | + ./build0.sh + cmake . -GNinja \ + -DCMAKE_BUILD_TYPE=Debug \ + -DWITH_LLVM=yes \ + -DLFORTRAN_BUILD_ALL=yes \ + -DWITH_STACKTRACE=no \ + -DWITH_RUNTIME_STACKTRACE=yes \ + -DCMAKE_PREFIX_PATH="$CONDA_PREFIX" \ + -DCMAKE_INSTALL_PREFIX=`pwd`/inst \ + -DCMAKE_C_COMPILER_LAUNCHER=sccache \ + -DCMAKE_CXX_COMPILER_LAUNCHER=sccache + + cmake --build . -j16 --target install + + - name: Test Linux + shell: bash -e -l {0} + run: | + cd integration_tests + ./run_tests.py -b cpython c_py llvm_py + ./run_tests.py -b cpython c_py llvm_py -f + + sympy: + name: Run SymPy tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + submodules: true + fetch-depth: 0 + + - name: Git Submodule Update + shell: bash -e -l {0} + run: | + git submodule update --init --recursive + + - uses: mamba-org/setup-micromamba@v1 + with: + environment-file: ci/environment.yml + create-args: >- + python=3.10 + bison=3.4 + symengine=0.12.0 + sympy=1.11.1 + + - uses: hendrikmuhs/ccache-action@main + with: + key: ${{ github.job }}-${{ matrix.os }} + + - name: Build + shell: bash -e -l {0} + run: | + ./build0.sh + cmake . -G"Unix Makefiles" \ + -DCMAKE_BUILD_TYPE=Debug \ + -DWITH_LLVM=yes \ + -DLPYTHON_BUILD_ALL=yes \ + -DWITH_STACKTRACE=no \ + -DWITH_RUNTIME_STACKTRACE=no \ + -DCMAKE_PREFIX_PATH="$CONDA_PREFIX" \ + -DCMAKE_INSTALL_PREFIX=`pwd`/inst \ + -DCMAKE_C_COMPILER_LAUNCHER=ccache \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache + + cmake --build . -j16 --target install + + - name: Test + shell: bash -e -l {0} + run: | + cd integration_tests + ./run_tests.py -b c_sym cpython_sym llvm_sym llvm_jit + ./run_tests.py -b c_sym cpython_sym llvm_sym llvm_jit -f + + integration_tests_cpython: + name: Run Integration tests with Python ${{ matrix.python-version }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.9", "3.10", "3.11", "3.12"] + steps: + - uses: actions/checkout@v3 + with: + submodules: true + fetch-depth: 0 + + - name: Git Submodule Update + shell: bash -e -l {0} + run: | + git submodule update --init --recursive + + - uses: mamba-org/setup-micromamba@v1 + with: + environment-name: lp + condarc: | + channels: + - conda-forge + create-args: >- + llvmdev=11.1.0 + bison=3.4 + re2c=2.2 + zlib=1.3.1 + cmake=3.30.0 + make=4.3 + python=${{ matrix.python-version }} + numpy=1.26.4 + + - uses: hendrikmuhs/ccache-action@main + with: + key: ${{ github.job }}-${{ matrix.python-version }} + + - name: Show Python Info + shell: bash -e -l {0} + run: | + which python + python -m pip -V + python -m pip list + python --version + + - name: Build + shell: bash -e -l {0} + run: | + ./build0.sh + cmake . -G"Unix Makefiles" \ + -DCMAKE_BUILD_TYPE=Debug \ + -DWITH_LLVM=yes \ + -DLPYTHON_BUILD_ALL=yes \ + -DWITH_STACKTRACE=no \ + -DWITH_RUNTIME_STACKTRACE=no \ + -DCMAKE_PREFIX_PATH="$CONDA_PREFIX" \ + -DCMAKE_INSTALL_PREFIX=`pwd`/inst \ + -DCMAKE_C_COMPILER_LAUNCHER=ccache \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache + + cmake --build . -j16 --target install + + - name: Test + shell: bash -e -l {0} + run: | + cd integration_tests + ./run_tests.py -b cpython c_py + + test_llvm: + name: Test LLVM ${{ matrix.llvm-version }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + llvm-version: ["10", "15", "16"] + steps: + - uses: actions/checkout@v4 + with: + submodules: true + fetch-depth: 0 + + - name: Git Submodule Update + shell: bash -e -l {0} + run: | + git submodule update --init --recursive + + - uses: mamba-org/setup-micromamba@v1.8.0 + with: + environment-file: ci/environment_linux_llvm.yml + create-args: >- + llvmdev=${{ matrix.llvm-version }} + + - uses: hendrikmuhs/ccache-action@main + with: + variant: sccache + key: ${{ github.job }}-${{ matrix.llvm-version }} + + - name: Build Linux + shell: bash -e -l {0} + run: | + ./build0.sh + export CXXFLAGS="-Werror" + cmake . -G"Unix Makefiles" \ + -DCMAKE_BUILD_TYPE=Debug \ + -DWITH_LLVM=yes \ + -DLFORTRAN_BUILD_ALL=yes \ + -DWITH_STACKTRACE=no \ + -DWITH_RUNTIME_STACKTRACE=yes \ + -DCMAKE_PREFIX_PATH="$CONDA_PREFIX" \ + -DCMAKE_INSTALL_PREFIX=`pwd`/inst \ + -DCMAKE_C_COMPILER_LAUNCHER=sccache \ + -DCMAKE_CXX_COMPILER_LAUNCHER=sccache + + cmake --build . -j16 --target install + + - name: Test Linux LLVM ${{ matrix.llvm-version }} + shell: bash -e -l {0} + run: | + ctest --output-on-failure + cd integration_tests + ./run_tests.py -b llvm llvm_jit + ./run_tests.py -b llvm llvm_jit -f + + build_jupyter_kernel: + name: Build Jupyter Kernel + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + submodules: true + fetch-depth: 0 + + - name: Git Submodule Update + shell: bash -e -l {0} + run: | + git submodule update --init --recursive + + - uses: mamba-org/setup-micromamba@v1 + with: + environment-file: ci/environment.yml + create-args: >- + jupyter=1.0.0 + python=3.10 + bison=3.4 + + - uses: hendrikmuhs/ccache-action@main + with: + variant: sccache + key: ${{ github.job }}-${{ matrix.os }} + + - name: Build LPython with Kernel + shell: bash -e -l {0} + run: | + ./build0.sh + export CXXFLAGS="-Werror" + cmake . -GNinja \ + -DCMAKE_BUILD_TYPE=Debug \ + -DWITH_LLVM=yes \ + -DWITH_XEUS=yes \ + -DCMAKE_PREFIX_PATH="$CONDA_PREFIX" \ + -DCMAKE_INSTALL_PREFIX="$CONDA_PREFIX" + + ninja install + ctest --output-on-failure + jupyter kernelspec list --json + + - name: Test Kernel + shell: bash -e -l {0} + run: | + ctest --output-on-failure + + upload_tarball: + name: Upload Tarball + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: true + fetch-depth: 0 + + - name: Git Submodule Update + shell: bash -e -l {0} + run: | + git submodule update --init --recursive + + - uses: mamba-org/setup-micromamba@v1 + with: + environment-file: ci/environment.yml + create-args: >- + python=3.10 + + - name: Create Source Tarball + shell: bash -e -l {0} + run: | + ./build0.sh + lpython_version=$( version # Generate a Python AST from Python.asdl (Python) python grammar/asdl_py.py # Generate a Python AST from Python.asdl (C++) -python src/libasr/asdl_cpp.py grammar/Python.asdl src/lpython/python_ast.h +python libasr/src/libasr/asdl_cpp.py grammar/Python.asdl src/lpython/python_ast.h # Generate a Fortran ASR from ASR.asdl (C++) -python src/libasr/asdl_cpp.py src/libasr/ASR.asdl src/libasr/asr.h -# Generate a wasm_visitor.h from src/libasr/wasm_instructions.txt (C++) -python src/libasr/wasm_instructions_visitor.py +python libasr/src/libasr/asdl_cpp.py libasr/src/libasr/ASR.asdl libasr/src/libasr/asr.h +# Generate a wasm_visitor.h from libasr/src/libasr/wasm_instructions.txt (C++) +python libasr/src/libasr/wasm_instructions_visitor.py +# Generate the intrinsic_function_registry_util.h (C++) +python libasr/src/libasr/intrinsic_func_registry_util_gen.py # Generate the tokenizer and parser pushd src/lpython/parser && re2c -W -b tokenizer.re -o tokenizer.cpp && popd diff --git a/build_to_wasm.sh b/build_to_wasm.sh index 6eb3b49cf1..2d11afb250 100755 --- a/build_to_wasm.sh +++ b/build_to_wasm.sh @@ -3,9 +3,15 @@ set -e set -x +mkdir -p src/bin/asset_dir +cp src/runtime/*.py src/bin/asset_dir +cp -r src/runtime/lpython src/bin/asset_dir + +./build0.sh emcmake cmake \ - -DCMAKE_BUILD_TYPE=Debug \ + -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_CXX_FLAGS_DEBUG="-Wall -Wextra -fexceptions" \ + -DCMAKE_CXX_FLAGS_RELEASE="-Wall -Wextra -fexceptions" \ -DWITH_LLVM=no \ -DLPYTHON_BUILD_ALL=yes \ -DLPYTHON_BUILD_TO_WASM=yes \ diff --git a/ci/azure_install_macos.sh b/ci/azure_install_macos.sh deleted file mode 100755 index 5012f14ae7..0000000000 --- a/ci/azure_install_macos.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash - -set -ex - -conda config --set always_yes yes --set changeps1 no -conda info -a -conda update -q conda -conda install -c conda-forge python=3.8 re2c bison=3.4 m4 xonsh llvmdev=11.0.1 toml cmake=3.17.0 jupyter pytest xeus=1.0.1 xtl nlohmann_json cppzmq jupyter_kernel_test -export MACOSX_DEPLOYMENT_TARGET="10.12" -export CONDA_PREFIX=/usr/local/miniconda -export LFORTRAN_CMAKE_GENERATOR="Unix Makefiles" -export WIN=0 -export MACOS=1 -xonsh ci/build.xsh diff --git a/ci/build.xsh b/ci/build.xsh index fb2d9233c2..bdab77d1b9 100755 --- a/ci/build.xsh +++ b/ci/build.xsh @@ -27,19 +27,21 @@ llvm-config --components bash ci/version.sh # Generate a Fortran ASR from ASR.asdl (C++) -python src/libasr/asdl_cpp.py src/libasr/ASR.asdl src/libasr/asr.h +python libasr/src/libasr/asdl_cpp.py libasr/src/libasr/ASR.asdl libasr/src/libasr/asr.h # Generate a Python AST from Python.asdl (C++) -python src/libasr/asdl_cpp.py grammar/Python.asdl src/lpython/python_ast.h +python libasr/src/libasr/asdl_cpp.py grammar/Python.asdl src/lpython/python_ast.h # Generate a Python AST from Python.asdl (Python) python grammar/asdl_py.py -# Generate a wasm_visitor.h from src/libasr/wasm_instructions.txt (C++) -python src/libasr/wasm_instructions_visitor.py +# Generate a wasm_visitor.h from libasr/src/libasr/wasm_instructions.txt (C++) +python libasr/src/libasr/wasm_instructions_visitor.py +# Generate the intrinsic_function_registry_util.h (C++) +python libasr/src/libasr/intrinsic_func_registry_util_gen.py # Generate the tokenizer and parser pushd src/lpython/parser && re2c -W -b tokenizer.re -o tokenizer.cpp && popd pushd src/lpython/parser && bison -Wall -d -r all parser.yy && popd -$lpython_version=$(cat version).strip() +$lpython_version=$(cat lp_version).strip() $dest="lpython-" + $lpython_version bash ci/create_source_tarball0.sh tar xzf dist/lpython-$lpython_version.tar.gz diff --git a/ci/create_source_tarball.sh b/ci/create_source_tarball.sh index f1bfb4b4b7..aaf9b8e5ee 100755 --- a/ci/create_source_tarball.sh +++ b/ci/create_source_tarball.sh @@ -2,6 +2,6 @@ set -ex -lfortran_version=$1 -export dest=lfortran-$lfortran_version +lpython_version=$1 +export dest=lpython-$lpython_version bash -x -o errexit ci/create_source_tarball0.sh diff --git a/ci/create_source_tarball0.sh b/ci/create_source_tarball0.sh index bffa0f3584..ff8d6ab7db 100755 --- a/ci/create_source_tarball0.sh +++ b/ci/create_source_tarball0.sh @@ -9,9 +9,10 @@ cmake -E copy_directory src $dest/src cmake -E copy_directory share $dest/share cmake -E copy_directory cmake $dest/cmake cmake -E copy_directory examples $dest/examples +cmake -E copy_directory libasr/src/libasr $dest/libasr/src/libasr # Copy Files: -cmake -E copy CMakeLists.txt README.md LICENSE version $dest +cmake -E copy CMakeLists.txt README.md LICENSE lp_version $dest # Create the tarball cmake -E make_directory dist diff --git a/ci/environment.yml b/ci/environment.yml index b9b7fd715f..db5ded2261 100644 --- a/ci/environment.yml +++ b/ci/environment.yml @@ -4,19 +4,19 @@ channels: - defaults dependencies: - llvmdev=11.1.0 - - toml - - pytest - - jupyter - - xeus=1.0.1 - - xtl - - nlohmann_json - - cppzmq - - jupyter_kernel_test - - xonsh - - re2c - - numpy - - zlib - - ninja - - rapidjson + - toml=0.10.2 + - pytest=7.2.0 + - jupyter=1.0.0 + - xeus=5.1.0 + - xeus-zmq=3.0.0 + - nlohmann_json=3.11.3 + - jupyter_kernel_test=0.4.4 + - xonsh=0.13.3 + - re2c=2.2 + - numpy=1.26.4 + - zlib=1.3.1 + - zstd=1.5.6 + - ninja=1.11.0 + - rapidjson=1.1.0 # - bison=3.4 [not win] # - m2-bison=3.4 [win] diff --git a/ci/environment_linux_llvm.yml b/ci/environment_linux_llvm.yml new file mode 100644 index 0000000000..ffe4ddd2a9 --- /dev/null +++ b/ci/environment_linux_llvm.yml @@ -0,0 +1,20 @@ +name: lp +channels: + - conda-forge + - defaults +dependencies: + - git + - pip + - make + - re2c + - toml + - zlib + - cmake + - numpy + - flake8 + - setuptools + - bison=3.4 + - python=3.10.2 + - zstd-static=1.5 + - symengine=0.12.0 + - sympy=1.11.1 diff --git a/ci/test.xsh b/ci/test.xsh index f2db432453..23285e1ed9 100644 --- a/ci/test.xsh +++ b/ci/test.xsh @@ -13,7 +13,7 @@ src/bin/lpython -o expr2 expr2.o # Test the new Python frontend, manually for now: src/bin/lpython --show-ast tests/doconcurrentloop_01.py src/bin/lpython --show-asr tests/doconcurrentloop_01.py -src/bin/lpython --show-cpp tests/doconcurrentloop_01.py +# src/bin/lpython --show-cpp tests/doconcurrentloop_01.py if $WIN == "1": python run_tests.py --skip-run-with-dbg --no-color @@ -22,7 +22,12 @@ else: src/bin/lpython examples/expr2.py src/bin/lpython --backend=c examples/expr2.py cd integration_tests - python run_tests.py -j16 -b llvm cpython c wasm if $(uname).strip() == "Linux": + python run_tests.py -j16 -b llvm cpython c wasm + python run_tests.py -j16 -b llvm cpython c wasm -f python run_tests.py -j16 -b x86 wasm_x86 wasm_x64 + python run_tests.py -j16 -b x86 wasm_x86 wasm_x64 -f + else: + python run_tests.py -j1 -b llvm cpython c wasm + python run_tests.py -j1 -b llvm cpython c wasm -f diff --git a/ci/upload_tarball_to_release.sh b/ci/upload_tarball_to_release.sh new file mode 100755 index 0000000000..cc8f1e1c32 --- /dev/null +++ b/ci/upload_tarball_to_release.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +set -ex + +lpython_version=$( version +echo $version > lp_version diff --git a/cmake/UserOverride.cmake b/cmake/UserOverride.cmake index 3139f24c87..5c50301187 100644 --- a/cmake/UserOverride.cmake +++ b/cmake/UserOverride.cmake @@ -9,7 +9,12 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") # g++ set(common "-Wall -Wextra") - set(CMAKE_CXX_FLAGS_RELEASE_INIT "${common} -O3 -march=native -funroll-loops -DNDEBUG") + if (CMAKE_SYSTEM_PROCESSOR MATCHES "ppc|powerpc") + set(native "-mtune=native") + else () + set(native "-march=native") + endif () + set(CMAKE_CXX_FLAGS_RELEASE_INIT "${common} -O3 ${native} -funroll-loops -DNDEBUG") set(CMAKE_CXX_FLAGS_DEBUG_INIT "${common} -g -ggdb") elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Intel") # icpc diff --git a/doc/src/asr/asr_nodes/expression_nodes/IntrinsicFunction.md b/doc/src/asr/asr_nodes/expression_nodes/IntrinsicFunction.md new file mode 100644 index 0000000000..f5c53c6c7b --- /dev/null +++ b/doc/src/asr/asr_nodes/expression_nodes/IntrinsicFunction.md @@ -0,0 +1,107 @@ +# IntrinsicFunction + +An intrinsic function. An **expr** node. + +## Declaration + +### Syntax + +``` +IntrinsicFunction(expr* args, int intrinsic_id, int overload_id, + ttype type, expr? value) +``` + +### Arguments + +* `args` represents all arguments passed to the function +* `intrinsic_id` is the unique ID of the generic intrinsic function +* `overload_id` is the ID of the signature within the given generic function +* `type` represents the type of the output +* `value` is an optional compile time value + +### Return values + +The return value is the expression that the `IntrinsicFunction` represents. + +## Description + +**IntrinsicFunction** represents an intrinsic function (such as `Abs`, +`Modulo`, `Sin`, `Cos`, `LegendreP`, `FlipSign`, ...) that either the backend +or the middle-end (optimizer) needs to have some special logic for. Typically a +math function, but does not have to be. + +IntrinsicFunction is both side-effect-free (no writes to global variables) and +deterministic (no reads from global variables). They are also elemental: can be +vectorized over any argument(s). They can be used inside parallel code and +cached. + +The `intrinsic_id` determines the generic function uniquely (`Sin` and `Abs` +have different number, but `IntegerAbs` and `RealAbs` share the number) and +`overload_id` uniquely determines the signature starting from 0 for each +generic function (e.g., `IntegerAbs`, `RealAbs` and `ComplexAbs` can have +`overload_id` equal to 0, 1 and 2, and `RealSin`, `ComplexSin` can be 0, 1). + +Backend use cases: Some architectures have special hardware instructions for +operations like Sqrt or Sin and if they are faster than a software +implementation, the backend will use it. This includes the `FlipSign` function +which is our own "special function" that the optimizer emits for certain +conditional floating point operations, and the backend emits an efficient bit +manipulation implementation for architectures that support it. + +Middle-end use cases: the middle-end can use the high level semantics to +simplify, such as `sin(e)**2 + cos(e)**2 -> 1`, or it could approximate +expressions like `if (abs(sin(x) - 0.5) < 0.3)` with a lower accuracy version +of `sin`. + +We provide ASR -> ASR lowering transformations that substitute the given +intrinsic function with an ASR implementation using more primitive ASR nodes, +typically implemented in the surface language (say a `sin` implementation using +argument reduction and a polynomial fit, or a `sqrt` implementation using a +general power formula `x**(0.5)`, or `LegendreP(2,x)` implementation using a +formula `(3*x**2-1)/2`). + +This design also makes it possible to allow selecting using command line +options how certain intrinsic functions should be implemented, for example if +trigonometric functions should be implemented using our own fast +implementation, `libm` accurate implementation, we could also call into other +libraries. These choices should happen at the ASR level, and then the result +further optimized (such as inlined) as needed. + +## Types + +The argument types in `args` have the types of the corresponding signature as +determined by `intrinsic_id`. For example `IntegerAbs` accepts an integer, but +`RealAbs` accepts a real. + +## Examples + +The following example code creates `IntrinsicFunction` ASR node: + +```fortran +sin(0.5) +``` + +ASR: + +``` +(TranslationUnit + (SymbolTable + 1 + { + }) + [(IntrinsicFunction + [(RealConstant + 0.500000 + (Real 4 []) + )] + 0 + 0 + (Real 4 []) + (RealConstant 0.479426 (Real 4 [])) + )] +) +``` + +## See Also + +[FunctionCall]() \ No newline at end of file diff --git a/doc/src/built-in functions.md b/doc/src/built-in functions.md new file mode 100644 index 0000000000..b9804b5c28 --- /dev/null +++ b/doc/src/built-in functions.md @@ -0,0 +1,147 @@ +# Built-in Functions + +LPython has a variety of functions and types built into it that are always available. + +### abs(x) + +- **Parameter** + - x : integer (i8, i16, i32, i64), floating point number (f32, f64), complex number (c32, c64) or bool +- **Returns** : integer (i8, i16, i32, i64), floating point number (f32, f64) + +Returns the absolute value of a number. If the argument is a complex number, its magnitude is returned. + + +### bin(n) + +- **Parameters** + - n : integer (i32) +- **Returns** : str + +Returns the binary representation of n as a '0b' prefixed string. + + +### complex(x=0, y=0) + +- **Parameters** + - x : integer (i32, i64) or floating point number (f32, f64) + - y : integer (i32, i64) or floating point number (f32, f64) +- **Returns** : complex number (c32, c64) + +Returns a complex number with the provided real and imaginary parts. Both x and y should be of the same type. However, using both the 32-bit and 64-bit versions of the same type together is allowed. In that case, the returned complex number is of 64-bit type. + +Example: + +```python +real: i32 = 10 +imag: i64 = 22 +c: c64 = complex(real, imag) +``` + +### divmod(x, y) + +- **Parameters** + - x : integer (i32) + - y : integer (i32) +- **Returns** : tuple[i32, i32] + +Returns the tuple (x // y, x % y). + + +### exp(x) + +- ****Parameter**** + - x : floating point number (f32, f64) +- **Returns** : floating point number (f32, f64) between [0.0, inf] + +Returns the base-e exponential of x (ex), where e is the Euler's number (2.71828). For a very large output, the function returns **inf** indicating overflow. + + +### hex(n) + +- **Parameters** + - n : integer (i32) +- **Returns** : str + +Returns the hexadecimal representation of n as a '0x' prefixed string. + + +### len(s) + +- **Parameters** + - s : sequence (such as string, tuple, list or range) or collection (such as a dictionary or set) +- **Returns** : integer (i32) + +Returns the number of items present in an object. + + +### max(x, y) + +- **Parameters** + - x : integer (i32) or floating point number (f64) + - y : integer (i32) or floating point number (f64) +- **Returns** : integer (i32) or floating point number (f64) + +Returns the greater value between x and y. Both x and y should be of the same type. + + +### min(x, y) + +- **Parameters** + - x : integer (i32) or floating point number (f64) + - y : integer (i32) or floating point number (f64) +- **Returns** : integer (i32) or floating point number (f64) + +Returns the smaller value between x and y. Both x and y should be of the same type. + + +### mod(x, y) + +- **Parameters** + - x : integer (i32, i64) or floating point number (f32, f64) + - y : integer (i32, i64) or floating point number (f32, f64) +- **Returns** : integer (i32, i64) or floating point number (f32, f64) + +Returns the remainder of x / y, or x when x is smaller than y. Both x and y should be of the same type. + + +### pow(x, y) + +- **Parameters** + - x : integer (i32, i64), floating point number (f32, f64), complex number (c32) or bool + - y: integer (i32, i64), floating point number (f32, f64) or bool +- **Returns** : integer (i32), floating point number (f32, f64) or a complex number + +Returns xy. When x is of type bool, y must also be of the same type. If x is 32-bit complex number (c32), y can only be a 32-bit integer (i32). + +**Note** : `x ** y` is the recommended method for doing the above calculation. + + +### round(x) + +- **Parameters** + - x : integer (i8, i16, i32, i64), floating point number (f32, f64) or bool +- **Returns** : integer (i8, i16, i32, i64) + +Returns the integer nearest to x. + + +### sum(arr) + +- **Parameters** + - arr : list of integers (list[i32], list[i64]) or floating point numbers (list[i32], list[f64]) +- **Returns** : integer (i32, i64) or floating point number (f32, f64) + +Returns the sum of all elements present in the list. + + +### oct(n) + +- **Parameters** + - n : integer (i32) +- **Returns** : str + +Returns the octal representation of n as a '0o' prefixed string. + + + + diff --git a/doc/src/developers_example.ipynb b/doc/src/developers_example.ipynb new file mode 100644 index 0000000000..c63754c8f0 --- /dev/null +++ b/doc/src/developers_example.ipynb @@ -0,0 +1,67 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "c86338ac-53ca-4115-8c5a-8bf8a5c7113e", + "metadata": {}, + "outputs": [], + "source": [ + "%%showast\n", + "def add(x: i32, y: i32) -> i32:\n", + " return x + y" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "23834b08-2f3f-45e7-a1ce-21a9fd4e5117", + "metadata": {}, + "outputs": [], + "source": [ + "%%showasr\n", + "def add(x: i32, y: i32) -> i32:\n", + " return x + y" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ec7426b4-e2e5-416c-bcae-9bb9c8926c9b", + "metadata": {}, + "outputs": [], + "source": [ + "%%showllvm\n", + "def sub(x: i32, y: i32) -> i32:\n", + " return add(x, -y)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "716c56ef-8210-4daf-aa23-96b385801014", + "metadata": {}, + "outputs": [], + "source": [ + "%%showasm\n", + "def mul(x: i32, y: i32) -> i32:\n", + " return x * y" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "LPython", + "language": "python", + "name": "lpython" + }, + "language_info": { + "file_extension": ".f90", + "mimetype": "text/x-python", + "name": "python", + "version": "2018" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/doc/src/installation.md b/doc/src/installation.md index efe7bf662c..a6bdd9250e 100644 --- a/doc/src/installation.md +++ b/doc/src/installation.md @@ -1,206 +1,210 @@ # Installation -All the instructions below work on Linux, macOS and Windows. +Follow the steps below to install and run LPython on Linux, Windows or macOS. + +## Prerequisites +- ### Install Conda + Follow the instructions provided [here](https://github.com/conda-forge/miniforge/#download) to install Conda on your platform (Linux, macOS and Windows) using a conda-forge distribution called Miniforge. + + For Windows, these are additional requirements: + - Miniforge Prompt + - Visual Studio (with "Desktop Development with C++" workload) + +- ### Set up your system + - Linux + - Run the following command to install some global build dependencies: + + ```bash + sudo apt-get install build-essential binutils-dev clang zlib1g-dev + ``` + - Windows + - Download and install [Microsoft Visual Studio Community](https://visualstudio.microsoft.com/downloads/) for free. + + - Run the Visual Studio Installer. Download and install the "Desktop Development with C++" workload which will install the Visual C++ Compiler (MSVC). + + - Launch the Miniforge prompt from the Desktop. It is recommended to use MiniForge instead of Powershell as the main terminal to build and write code for LPython. In the MiniForge Prompt, initialize the MSVC compiler using the below command: + + ```bash + call "C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\Tools\VsDevCmd" -arch=x64 + ``` + + You can optionally test MSVC via: + + ```bash + cl /? + link /? + ``` + + Both commands must print several pages of help text. + + - Windows with WSL + - Install Miniforge Prompt and add it to path: + ```bash + wget https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-x86_64.sh -O miniconda.sh + bash miniconda.sh -b -p $HOME/conda_root + export PATH="$HOME/conda_root/bin:$PATH" + conda init bash # (shell name) + ``` + - Open a new terminal window and run the following commands to install dependencies: + ```bash + conda create -n lp -c conda-forge llvmdev=11.0.1 bison=3.4 re2c python cmake make toml clangdev git + ``` + + - Optionally, you can change the directory to a Windows location using `cd /mnt/[drive letter]/[windows location]`. For e.g. - `cd mnt/c/Users/name/source/repos/`. + + +- ### Clone the LPython repository + Make sure you have `git` installed. Type the following command to clone the repository: + + ```bash + git clone https://github.com/lcompilers/lpython.git + cd lpython + git submodule update --init + ``` + + You may also use GitHub Desktop to do the same. + +## Building LPython +- ### Linux and macOS + - Create a Conda environment: + + ```bash + conda env create -f environment_unix.yml + conda activate lp + ``` -## Binaries + - Generate the prerequisite files and build in Debug Mode: -The recommended way to install LFortran is using Conda. -Install Conda for example by installing the -[Miniconda](https://conda.io/en/latest/miniconda.html) installation by following instructions there for your platform. -Then create a new environment (you can choose any name, here we chose `lf`) and -activate it: -```bash -conda create -n lp -conda activate lp -``` -Then install LFortran by: -```bash -conda install lfortran -c conda-forge -``` -Now the `lf` environment has the `lfortran` compiler available, you can start the -interactive prompt by executing `lfortran`, or see the command line options using -`lfortran -h`. + ```bash + # if you are developing on top of a forked repository; please run following command first + # ./generate_default_tag.sh -The Jupyter kernel is automatically installed by the above command, so after installing Jupyter itself: -```bash -conda install jupyter -c conda-forge -``` -You can create a Fortran based Jupyter notebook by executing: -```bash -jupyter notebook -``` -and selecting `New->Fortran`. + ./build0.sh + ./build1.sh + ``` -## Build From a Source Tarball +- ### Windows + - Create a Conda environment using the pre-existing file: -This method is the recommended method if you just want to install LFortran, either yourself or in a package manager (Spack, Conda, Debian, etc.). The source tarball has all the generated files included and has minimal dependencies. + ```bash + conda env create -f environment_win.yml + conda activate lp + ``` -First we have to install dependencies, for example using Conda: -```bash -conda create -n lf python cmake llvmdev -conda activate lf -``` -Then download a tarball from -[https://lfortran.org/download/](https://lfortran.org/download/), -e.g.: -```bash -wget https://lfortran.github.io/tarballs/dev/lfortran-0.9.0.tar.gz -tar xzf lfortran-0.9.0.tar.gz -cd lfortran-0.9.0 -``` -And build: -``` -cmake -DWITH_LLVM=yes -DCMAKE_INSTALL_PREFIX=`pwd`/inst . -make -j8 -make install -``` -This will install the `lfortran` into the `inst/bin`. + - Generate the prerequisite files and build in Release Mode: -## Build From Git + ```bash + call build0.bat + call build1.bat + ``` +- ### Windows with WSL -We assume you have C++ compilers installed, as well as `git` and `wget`. -In Ubuntu, you can also install `binutils-dev` for stacktraces. + - Activate the Conda environment: + ```bash + conda activate lp + ``` -If you do not have Conda installed, you can do so on Linux (and similarly on -other platforms): -```bash -wget --no-check-certificate https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh -bash miniconda.sh -b -p $HOME/conda_root -export PATH="$HOME/conda_root/bin:$PATH" -``` -Then prepare the environment: -```bash -conda create -n lp -c conda-forge llvmdev=11.0.1 bison=3.4 re2c python cmake make toml numpy -conda activate lp -``` -Clone the LFortran git repository: -``` -git clone https://gitlab.com/lfortran/lfortran.git -cd lfortran -``` -Generate files that are needed for the build (this step depends on `re2c`, `bison` and `python`): -```bash -./build0.sh -``` -Now the process is the same as installing from the source tarball. For example to build in Debug mode: -``` -cmake -DCMAKE_BUILD_TYPE=Debug -DWITH_LLVM=yes -DCMAKE_INSTALL_PREFIX=`pwd`/inst . -make -j8 -``` + - Run the following commands to build the project: + ```bash + ./build0.sh + cmake -DCMAKE_BUILD_TYPE=Debug -DWITH_LLVM=yes -DCMAKE_INSTALL_PREFIX=`pwd`/inst .\ + make -j8 + ``` -Run tests: -```bash -ctest -./run_tests.py -``` -Run an interactive prompt: -```bash -./src/bin/lfortran -``` +## Tests -## Build on Windows with Visual Studio +- ### Linux and macOS -Install Conda for example by installing the Miniconda installation by following instructions there for your platform. If not already done, activate the Conda-Installation (cf. Conda installation instructions). + - Run tests: -First, clone the repo to a local folder. + ```bash + ctest + ./run_tests.py + ``` -Launch a Conda command interpreter and run the following commands: -```bash -conda update -q conda -conda install -c conda-forge python=3.7 re2c m2-bison xonsh llvmdev=11.1.0 jupyter xeus=1.0.1 xtl nlohmann_json cppzmq jupyter_kernel_test pytest -``` -Next, `cd` to the root of the repository and run -```bash -.\build0.bat -``` + - Update test references: + ``` + ./run_tests.py -u + ``` -Now, you can launch Visual Studio and open the LFortran folder. -Before the first build you have to set up the `ZLib`-pathes: Go to the CMake-Settings (Project -> CMake Settings for lfortran) and check `Show advanced variables`. Scroll to the `ZLIB_...` variables and set: -- `ZLIB_INCLUDE_DIR` = \\Library\include -- `ZLIB_LIBRARY_[DEBUG|RELEASE]` = \\Library\lib\zlib.lib + - Run integration tests: -Then you can generate the CMake-Cache and build the project. + ```bash + cd integration_tests + ./run_tests.py + ``` + - In case you have recently updated macOS, you may get a warning like below in some test cases: + ```bash + ld: warning: object file (test_list_index2.out.tmp.o) was built for newer macOS version (14.0) than being linked (13.3) + ``` + This leads to mismatch of hashes with expected output in some test cases, this can be resolved by updating command line tools: -## Build from Git on Windows with WSL -* In windows search "turn windows features on or off". -* Tick Windows subsystem for Linux. -* Press OK and restart computer. -* Go to Microsoft store and download Ubuntu 22.04, and launch it. -* Run the following commands. + ```bash + git clean -dfx + sudo rm -rf /Library/Developer/CommandLineTools # make sure you know what you're doing here + sudo xcode-select --install + ./build.sh + ./run_tests.py + ``` -```bash -wget https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-x86_64.sh -O miniconda.sh -bash miniconda.sh -b -p $HOME/conda_root -export PATH="$HOME/conda_root/bin:$PATH" -conda init bash # (shell name) -``` -* This adds all requirements used by Conda in the `.bashrc` file. -* After that, close the existing terminal and open a new one. -* Run the following -```bash -conda create -n lp -c conda-forge llvmdev=11.0.1 bison=3.4 re2c python cmake make toml clangdev git -conda activate lp -``` -* Note that Conda is slow for installing packages with specified versions. -* Instead use Mamba for faster installation, with the following commands (this is optional; if the above command works without any lag, then proceed to the next step): -```bash -conda create -n lp -c conda-forge re2c python cmake make toml numpy mamba clangdev git -mamba install llvmdev=11.0.1 bison=3.4 -conda activate lp -``` -* Run the following to install other required packages: -```bash -sudo apt update -sudo apt-get install build-essential binutils-dev -sudo apt-get install zlib1g-dev -``` -* You can change the directory to a Windows location using `cd /mnt/[drive letter]/[windows location]`. -* e.g. `cd mnt/c/Users/name/source/repos/` + - Speed up Integration Tests on macOS -* Now clone the LPython git repository -```bash -git clone https://github.com/lcompilers/lpython.git -cd lpython -``` + Integration tests run slowly because Apple checks the hash of each + executable online before running. -* Run the following commands to build the project: -```bash -./build0.sh -cmake -DCMAKE_BUILD_TYPE=Debug -DWITH_LLVM=yes -DCMAKE_INSTALL_PREFIX=`pwd`/inst .\ -make -j8 -``` + You can turn off that feature in the Privacy tab of the Security and Privacy item of System Preferences > Developer Tools > Terminal.app > "allow the apps below to run software locally that does not meet the system's security + policy." -* If everything compiles, you can use LPython as follows -```bash -./src/bin/lpython examples/expr2.py -``` -* Run tests +- ### Windows + + - Run integration tests + + ```bash + python run_tests.py --skip-run-with-dbg + ``` + + - Update reference tests + + ```bash + python run_tests.py -u --skip-run-with-dbg + ``` + +## Examples (Linux and macOS) + +You can run the following examples manually in a terminal: + ```bash -ctest -./run_tests.py +./src/bin/lpython examples/expr2.py +./src/bin/lpython examples/expr2.py -o expr +./expr +./src/bin/lpython --show-ast examples/expr2.py +./src/bin/lpython --show-asr examples/expr2.py +./src/bin/lpython --show-cpp examples/expr2.py +./src/bin/lpython --show-llvm examples/expr2.py +./src/bin/lpython --show-c examples/expr2.py ``` ## Enabling the Jupyter Kernel To install the Jupyter kernel, install the following Conda packages also: ``` -conda install xeus xtl nlohmann_json cppzmq +conda install xeus=5.1.0 xeus-zmq=3.0.0 nlohmann_json ``` and enable the kernel by `-DWITH_XEUS=yes` and install into `$CONDA_PREFIX`. For example: ``` -cmake \ +cmake . -GNinja \ -DCMAKE_BUILD_TYPE=Debug \ -DWITH_LLVM=yes \ -DWITH_XEUS=yes \ -DCMAKE_PREFIX_PATH="$CONDA_PREFIX" \ - -DCMAKE_INSTALL_PREFIX="$CONDA_PREFIX" \ + -DCMAKE_INSTALL_PREFIX="$CONDA_PREFIX" . -cmake --build . -j4 --target install +ninja install ``` -To use it, install Jupyter (`conda install jupyter`) and test that the LFortran +To use it, install Jupyter (`conda install jupyter`) and test that the LPython kernel was found: ``` jupyter kernelspec list --json @@ -209,111 +213,14 @@ Then launch a Jupyter notebook as follows: ``` jupyter notebook ``` -Click `New->Fortran`. To launch a terminal jupyter LFortran console: -``` -jupyter console --kernel=fortran -``` - - -## Build From Git with Nix - -One of the ways to ensure exact environment and dependencies is with `nix`. This will ensure that system dependencies do not interfere with the development environment. If you want, you can report bugs in a `nix-shell` environment to make it easier for others to reproduce. - -### With Root - -We start by getting `nix`. The following multi-user installation will work on any machine with a Linux distribution, MacOS or Windows (via WSL): -```bash -sh <(curl -L https://nixos.org/nix/install) --daemon -``` -### Without Root - -If you would like to not provide `nix` with root access to your machine, on Linux distributions we can use [nix-portable](https://github.com/DavHau/nix-portable). -```bash -wget https://github.com/DavHau/nix-portable/releases/download/v003/nix-portable -``` -Now just prepend all `nix-shell` commands with `NP_RUNTIME=bwrap ./nix-portable `. So: -```bash -# Do not -nix-shell --run "bash" -# Do -NP_RUNTIME=bwrap ./nix-portable nix-shell --run "bash" -``` - -### Development - -Now we can enter the development environment: -```bash -nix-shell --run "bash" --cores 4 -j4 --pure ci/shell.nix -``` -The `--pure` flag ensures no system dependencies are used in the environment. - -The build steps are the same as with the `ci`: -```bash -./build0.sh -./build1.sh +Click `New->LPython`. To launch a terminal jupyter LPython console: ``` - -To change the compilation environment from `gcc` (default) to `clang` we can use `--argstr`: -```bash -nix-shell --run "bash" --cores 4 -j4 --pure ci/shell.nix --argstr clangOnly "yes" +jupyter console --kernel=lpython ``` -## Note About Dependencies - -End users (and distributions) are encouraged to use the tarball -from [https://lfortran.org/download/](https://lfortran.org/download/), -which only depends on LLVM, CMake and a C++ compiler. - -The tarball is generated automatically by our CI (continuous integration) and -contains some autogenerated files: the parser, the AST and ASR nodes, which is generated by an ASDL -translator (requires Python). - -The instructions from git are to be used when developing LFortran itself. - -## Note for users who do not use Conda +## Found a bug? +Please report any bugs you find at our issue tracker [here](https://github.com/lcompilers/lpython/issues). Or, even better, fork the repository on GitHub and create a Pull Request (PR). -Following are the dependencies necessary for installing this -repository in development mode, +We welcome all changes, big or small. We will help you make a PR if you are new to git. -- [Bison - 3.5.1](https://ftp.gnu.org/gnu/bison/bison-3.5.1.tar.xz) -- [LLVM - 11.0.1](https://github.com/llvm/llvm-project/releases/download/llvmorg-11.0.1/llvm-11.0.1.src.tar.xz) -- [re2c - 2.0.3](https://re2c.org/install/install.html) -- [binutils - 2.31.90](ftp://sourceware.org/pub/binutils/snapshots/binutils-2.31.90.tar.xz) - Make sure that you should enable the required options related to this dependency to build the dynamic libraries (the ones ending with `.so`). - -## Stacktraces - -LFortran can print stacktraces when there is an unhandled exception, as well as -on any compiler error with the `--show-stacktrace` option. This is very helpful -for developing the compiler itself to see where in LFortran the problem is. The -stacktrace support is turned off by default, to enable it, -compile LFortran with the `-DWITH_STACKTRACE=yes` cmake option after installing -the prerequisites on each platform per the instructions below. - -### Ubuntu - -In Ubuntu, `apt install binutils-dev`. - -### macOS - -If you use the default Clang compiler on macOS, then the stacktraces should -just work on both Intel and M1 based macOS (the CMake build system -automatically invokes the `dsymtuil` tool and our Python scripts to store the -debug information, see `src/bin/CMakeLists.txt` for more details). If it does -not work, please report a bug. - -If you do not like the default way, an alternative is to use bintutils. For -that, first install -[Spack](https://spack.io/), then: -``` -spack install binutils -spack find -p binutils -``` -The last command will show a full path to the installed `binutils` package. Add -this path to your shell config file, e.g.: -``` -export CMAKE_PREFIX_PATH_LFORTRAN=/Users/ondrej/repos/spack/opt/spack/darwin-catalina-broadwell/apple-clang-11.0.0/binutils-2.36.1-wy6osfm6bp2323g3jpv2sjuttthwx3gd -``` -and compile LFortran with the -`-DCMAKE_PREFIX_PATH="$CMAKE_PREFIX_PATH_LFORTRAN;$CONDA_PREFIX"` cmake option. -The `$CONDA_PREFIX` is there if you install some other dependencies (such as -`llvm`) using Conda, otherwise you can remove it. +If you have any questions or need help, please ask us at [Zulip](https://lfortran.zulipchat.com/) or on our [mailinglist](https://groups.io/g/lfortran). diff --git a/doc/src/rebasing.md b/doc/src/rebasing.md index 1c5581b6e3..26cefa3355 100644 --- a/doc/src/rebasing.md +++ b/doc/src/rebasing.md @@ -1,5 +1,5 @@ -You should clean your branch's commits, and we have two approach for this. +You should clean your branch's commits, and we have two approaches for this. # Rebasing ```bash @@ -56,9 +56,9 @@ Date: Sat Jul 30 15:46:28 2022 +0530 Implementing tuples in LLVM backend ``` -here, we want make our commits as a bunch of batches. +here, we want to make our commits as a bunch of batches. -we will rebasing with main with interactive option `git rebase main -i`. +we will rebase with main with the interactive option `git rebase main -i`. but first create a backup branch before doing this interactive rebase. @@ -111,8 +111,8 @@ s 122a02bf3 refactor s 663edf45b refactor ... ``` -and it will open windows for every change you made to rename commit's message. -- first window to rename commit `Added add3.py` because we squashed the commit after it, and by default the message would be the original message of `Added add3.py` and messages of squashed commits, here i will not change anything i will leave message like that. +and it will open windows for every change you made to rename the commit's message. +- first window to rename commit `Added add3.py` because we squashed the commit after it, and by default the message would be the original message of `Added add3.py` and messages of squashed commits, here I will not change anything I will leave message like that. ```bash # This is a combination of 2 commits. # This is the 1st commit message: @@ -143,7 +143,7 @@ Refactor # Untracked files: ... ``` -- second window: rename(rewword) `Added add4.py`, you can edit the message as you want, i will rename it: `Added add4.py and edit it ` . +- second window: rename(reword) `Added add4.py`, you can edit the message as you want, I will rename it: `Added add4.py and edit it ` . ``` Added add4.py @@ -187,7 +187,7 @@ Added add4.py and edit it # with '#' will be ignored, and an empty message aborts the commit. ... ``` -- third window will be the same as dirst one because of squashing two commits to commit:`Added add4.py`, i will leave it with out changing message. +- third window will be the same as the first one because of squashing two commits to commit:`Added add4.py`, I will leave it without changing the message. Log now: ```bash @@ -223,7 +223,7 @@ Date: Sat Jul 30 23:36:27 2022 +0200 Added add.py ``` -and if you want to push to remote branch you must push with `--force` option. +and if you want to push to the remote branch you must push with `--force` option. This [video](https://drive.google.com/file/d/1506h86_RLgwtjLi_uKWbdVNDsSVusIbr/view?usp=sharing) by *Naman Gera* he was rebasing a branch. @@ -232,7 +232,7 @@ This [video](https://drive.google.com/file/d/1506h86_RLgwtjLi_uKWbdVNDsSVusIbr/v # Merging by *Gagandeep Singh* from [#783 comment](https://github.com/lcompilers/lpython/pull/783#issuecomment-1188875210) -Assuming initial state is your current branch (say `xyz_branch`), +Assuming the initial state is your current branch (say `xyz_branch`), 1. git checkout main or git checkout master (whichever is being used in a certain project as the lead branch). 2. git pull origin main (origin is the project remote say for lpython it will be pointing to (https://github.com/lcompilers/lpython). @@ -243,4 +243,4 @@ Assuming initial state is your current branch (say `xyz_branch`), 7. Repeat step 6 until you are satisfied with the group of changes you want to commit. 8. `git commit -m "nice_commit_message"` or `git commit (and then write detailed commit message in the command line editor)`. 9. Repeat 7 and 8 until all the changes are committed. -10. `git push -f your_remote xyz_branch`. \ No newline at end of file +10. `git push -f your_remote xyz_branch`. diff --git a/environment_unix.yml b/environment_unix.yml index 0942bbcbaf..af7dffcff0 100644 --- a/environment_unix.yml +++ b/environment_unix.yml @@ -2,16 +2,17 @@ name: lp channels: - conda-forge dependencies: - - bison=3.4 - - cmake - - flake8 - - llvmdev=11.0.1 - - make - - numpy + - git - pip - - python=3.10.2 + - make - re2c - - setuptools - toml - zlib - - git + - cmake + - numpy + - flake8 + - setuptools + - bison=3.4 + - python=3.10.2 + - llvmdev=11.0.1 + - zstd-static=1.5.5 diff --git a/environment_win.yml b/environment_win.yml index af80e30c7c..60774b822c 100644 --- a/environment_win.yml +++ b/environment_win.yml @@ -2,18 +2,19 @@ name: lp channels: - conda-forge dependencies: - - python=3.10.2 - - numpy - - flake8 + - git - pip + - make + - re2c - toml + - zlib + - cmake + - ninja + - numpy + - xonsh + - flake8 - setuptools - - llvmdev=11.1.0 + - python=3.10.2 - m2-bison=3.0.4 - - re2c - - xonsh - - ninja - - cmake - - make - - zlib - - git + - llvmdev=11.1.0 + - zstd-static=1.5.5 diff --git a/examples/example_notebook.ipynb b/examples/example_notebook.ipynb new file mode 100644 index 0000000000..17ce1ba2db --- /dev/null +++ b/examples/example_notebook.ipynb @@ -0,0 +1,134 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "e87300c2-64ed-4636-8448-591f36faba29", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Hello, LPython\n" + ] + } + ], + "source": [ + "print(\"Hello, LPython\")" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "dfcac851-7b49-4065-8c64-4a31658249f7", + "metadata": {}, + "outputs": [], + "source": [ + "def add(x: i32, y: i32) -> i32:\n", + " return x + y" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "09213386-84d5-4e7c-83ba-c3b027f765dd", + "metadata": {}, + "outputs": [], + "source": [ + "def sub(x: i32, y: i32) -> i32:\n", + " return x - y" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "a4b49fd3-bf17-4287-9d5e-60f14ebc9a0f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "5" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "add(2, 3)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "d6f4961f-7f0c-45a6-9bf8-e549e97098b0", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "-1" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sub(2, 3)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "398fd4be-d7cc-4912-8aa1-880aa58b37ab", + "metadata": {}, + "outputs": [], + "source": [ + "@dataclass\n", + "class MyClass:\n", + " x: i32\n", + " y: f64\n", + " z: str" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "628f0b7d-09a6-49de-a0e6-2f6c664f2ba2", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "12 2.45000000000000000e+01 LPython\n" + ] + } + ], + "source": [ + "x: MyClass = MyClass(12, 24.5, \"LPython\")\n", + "print(x)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "LPython", + "language": "python", + "name": "lpython" + }, + "language_info": { + "file_extension": ".f90", + "mimetype": "text/x-python", + "name": "python", + "version": "2018" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/expr2.py b/examples/expr2.py index 2e66f1e584..484873ac2d 100644 --- a/examples/expr2.py +++ b/examples/expr2.py @@ -1,10 +1,9 @@ +from lpython import i32 + def main0(): x: i32 x = (2+3)*5 print(x) -main0() - -# Not implemented yet in LPython: -#if __name__ == "__main__": -# main() +if __name__ == "__main__": + main0() diff --git a/generate_default_tag.sh b/generate_default_tag.sh new file mode 100755 index 0000000000..b38b4d7239 --- /dev/null +++ b/generate_default_tag.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +# Run this script when your local repo +# #doesn't automatically fetch tags from upstream +# It allows local development with a mocked tag +echo "Generating default tag..." +set -ex +git tag "v0.0.0=0" diff --git a/grammar/Python.asdl b/grammar/Python.asdl index a5ca1c672e..ade97a49a0 100644 --- a/grammar/Python.asdl +++ b/grammar/Python.asdl @@ -73,6 +73,7 @@ module LPython -- need sequences for compare to distinguish between -- x < 4 < 3 and (x < 4) < 3 | Compare(expr left, cmpop ops, expr* comparators) + | Membership(expr left, membershipop op, expr right) | Call(expr func, expr* args, keyword* keywords) | FormattedValue(expr value, int conversion, expr? format_spec) | JoinedStr(expr* values) @@ -110,7 +111,9 @@ module LPython unaryop = Invert | Not | UAdd | USub - cmpop = Eq | NotEq | Lt | LtE | Gt | GtE | Is | IsNot | In | NotIn + cmpop = Eq | NotEq | Lt | LtE | Gt | GtE | Is | IsNot + + membershipop = In | NotIn comprehension = (expr target, expr iter, expr* ifs, int is_async) diff --git a/grammar/asdl_py.py b/grammar/asdl_py.py index 1e3844131e..bb897b300d 100644 --- a/grammar/asdl_py.py +++ b/grammar/asdl_py.py @@ -5,7 +5,7 @@ import sys import os -sys.path.append("src/libasr") +sys.path.append("libasr/src/libasr") import asdl products = [] diff --git a/integration_tests/CMakeLists.txt b/integration_tests/CMakeLists.txt index 5e27af939d..e81feb9db2 100644 --- a/integration_tests/CMakeLists.txt +++ b/integration_tests/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5 FATAL_ERROR) +cmake_minimum_required(VERSION 3.15 FATAL_ERROR) project(lpython_tests C) @@ -13,11 +13,23 @@ if (NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR endif () set(KIND no CACHE STRING "Type of Test") +set(FAST no CACHE BOOL "Run supported tests with --fast") + +find_program(LPYTHON NAMES lpython) + +execute_process(COMMAND ${LPYTHON} --get-rtl-header-dir + OUTPUT_VARIABLE LPYTHON_RTL_HEADER_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE + ) +execute_process(COMMAND ${LPYTHON} --get-rtl-dir + OUTPUT_VARIABLE LPYTHON_RTL_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE + ) find_path(LPYTHON_RTLIB_DIR lfortran_intrinsics.h - ${CMAKE_SOURCE_DIR}/../src/libasr/runtime) + HINTS ${LPYTHON_RTL_HEADER_DIR}) find_library(LPYTHON_RTLIB_LIBRARY lpython_runtime_static - ${CMAKE_SOURCE_DIR}/../src/runtime/) + HINTS ${LPYTHON_RTL_DIR}) add_library(lpython_rtlib INTERFACE IMPORTED) set_property(TARGET lpython_rtlib PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${LPYTHON_RTLIB_DIR}) @@ -25,6 +37,24 @@ set_property(TARGET lpython_rtlib PROPERTY INTERFACE_LINK_LIBRARIES ${LPYTHON_RTLIB_LIBRARY}) target_link_libraries(lpython_rtlib INTERFACE m) +if (PYTHON_LIBS_REQ) + find_package(Python COMPONENTS Interpreter Development) + execute_process( + COMMAND "${Python_EXECUTABLE}" + -c "import numpy; print(numpy.get_include())" + OUTPUT_VARIABLE NUMPY_INCLUDE_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + message("\n") + message("System has the Python development artifacts: ${Python_Development_FOUND}") + message("The Python include directories: ${Python_INCLUDE_DIRS}") + message("The Python libraries: ${Python_LIBRARIES}") + message("The Python library directories: ${Python_LIBRARY_DIRS}") + message("The Python runtime library directories: ${Python_RUNTIME_LIBRARY_DIRS}") + message("Python version: ${Python_VERSION}") + message("Numpy Include Directory: ${NUMPY_INCLUDE_DIR}") +endif() + enable_testing() message("\n") @@ -39,160 +69,342 @@ else () endif () message("Installation prefix: ${CMAKE_INSTALL_PREFIX}") message("KIND: ${KIND}") +message("FAST: ${FAST}") +message("PYTHON_LIBS_REQ: ${PYTHON_LIBS_REQ}") +message("LPYTHON: ${LPYTHON}") message("LPYTHON_RTLIB_DIR: ${LPYTHON_RTLIB_DIR}") message("LPYTHON_RTLIB_LIBRARY: ${LPYTHON_RTLIB_LIBRARY}") +macro(RUN_UTIL RUN_FAIL RUN_NAME RUN_FILE_NAME RUN_LABELS RUN_EXTRAFILES RUN_NOMOD RUN_EXTRA_ARGS RUN_COPY_TO_BIN) + set(fail ${${RUN_FAIL}}) + set(name ${${RUN_NAME}}) + set(file_name ${${RUN_FILE_NAME}}) + set(labels ${${RUN_LABELS}}) + set(extra_files ${${RUN_EXTRAFILES}}) + set(no_mod ${${RUN_NOMOD}}) + set(extra_args ${${RUN_EXTRA_ARGS}}) + set(copy_to_bin ${${RUN_COPY_TO_BIN}}) -macro(RUN) - set(options FAIL) - set(oneValueArgs NAME IMPORT_PATH) - set(multiValueArgs LABELS EXTRAFILES) - cmake_parse_arguments(RUN "${options}" "${oneValueArgs}" - "${multiValueArgs}" ${ARGN} ) - set(name ${RUN_NAME}) - set(import_path ${RUN_IMPORT_PATH}) if (NOT name) message(FATAL_ERROR "Must specify the NAME argument") endif() - if (${KIND} IN_LIST RUN_LABELS) + if (${KIND} IN_LIST labels) if (KIND STREQUAL "llvm") - if (import_path) - add_custom_command( - OUTPUT ${name}.o - COMMAND lpython -c -I ${CMAKE_CURRENT_SOURCE_DIR}/${import_path} ${CMAKE_CURRENT_SOURCE_DIR}/${name}.py -o ${name}.o - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${name}.py - VERBATIM) - else () - add_custom_command( - OUTPUT ${name}.o - COMMAND lpython -c ${CMAKE_CURRENT_SOURCE_DIR}/${name}.py -o ${name}.o - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${name}.py - VERBATIM) - endif() - add_executable(${name} ${name}.o ${RUN_EXTRAFILES}) + add_custom_command( + OUTPUT ${name}.o + COMMAND ${LPYTHON} -c ${extra_args} ${CMAKE_CURRENT_SOURCE_DIR}/${file_name}.py -o ${name}.o + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${file_name}.py + VERBATIM) + add_executable(${name} ${name}.o ${extra_files}) set_target_properties(${name} PROPERTIES LINKER_LANGUAGE C) target_link_libraries(${name} lpython_rtlib) add_test(${name} ${CMAKE_CURRENT_BINARY_DIR}/${name}) - if (RUN_LABELS) - set_tests_properties(${name} PROPERTIES LABELS "${RUN_LABELS}") + if (labels) + set_tests_properties(${name} PROPERTIES LABELS "${labels}") endif() - if (${RUN_FAIL}) + if (${fail}) set_tests_properties(${name} PROPERTIES WILL_FAIL TRUE) endif() - elseif(KIND STREQUAL "c") - if (import_path) - add_custom_command( - OUTPUT ${name}.c - COMMAND lpython -I ${CMAKE_CURRENT_SOURCE_DIR}/${import_path} --show-c ${CMAKE_CURRENT_SOURCE_DIR}/${name}.py > ${name}.c - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${name}.py - VERBATIM) - else () - add_custom_command( - OUTPUT ${name}.c - COMMAND lpython --show-c ${CMAKE_CURRENT_SOURCE_DIR}/${name}.py > ${name}.c - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${name}.py - VERBATIM) + elseif (KIND STREQUAL "llvm_jit") + add_test( + NAME ${name} + COMMAND ${LPYTHON} --jit ${extra_args} ${CMAKE_CURRENT_SOURCE_DIR}/${file_name}.py) + if (labels) + set_tests_properties(${name} PROPERTIES LABELS "${labels}") endif() - - add_executable(${name} ${name}.c ${RUN_EXTRAFILES}) + if (${fail}) + set_tests_properties(${name} PROPERTIES WILL_FAIL TRUE) + endif() + elseif (KIND STREQUAL "llvm_py") + add_custom_command( + OUTPUT ${name}.o + COMMAND ${LPYTHON} -c ${extra_args} ${CMAKE_CURRENT_SOURCE_DIR}/${file_name}.py -o ${name}.o + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${file_name}.py + VERBATIM) + add_executable(${name} ${name}.o ${extra_files}) + target_include_directories(${name} PRIVATE ${CMAKE_SOURCE_DIR} ${NUMPY_INCLUDE_DIR}) + set_target_properties(${name} PROPERTIES LINKER_LANGUAGE C) + target_link_libraries(${name} lpython_rtlib Python::Python) + add_test(${name} ${CMAKE_CURRENT_BINARY_DIR}/${name}) + if (labels) + set_tests_properties(${name} PROPERTIES LABELS "${labels}") + endif() + if (${fail}) + set_tests_properties(${name} PROPERTIES WILL_FAIL TRUE) + endif() + elseif(KIND STREQUAL "llvm_sym") + add_custom_command( + OUTPUT ${name}.o + COMMAND ${LPYTHON} -c ${extra_args} ${CMAKE_CURRENT_SOURCE_DIR}/${file_name}.py -o ${name}.o + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${file_name}.py + VERBATIM) + add_executable(${name} ${name}.o ${extra_files}) + set_target_properties(${name} PROPERTIES LINKER_LANGUAGE C) + if (APPLE) + set(SYMENGINE_LIB "${Python_LIBRARY_DIRS}/libsymengine.dylib") + else() + set(SYMENGINE_LIB "${Python_LIBRARY_DIRS}/libsymengine.so") + endif() + target_link_libraries(${name} lpython_rtlib ${SYMENGINE_LIB}) + add_test(${name} ${CMAKE_CURRENT_BINARY_DIR}/${name}) + if (labels) + set_tests_properties(${name} PROPERTIES LABELS "${labels}") + endif() + if (${fail}) + set_tests_properties(${name} PROPERTIES WILL_FAIL TRUE) + endif() + elseif(KIND STREQUAL "c") + add_custom_command( + OUTPUT ${name}.c + COMMAND ${LPYTHON} ${extra_args} --show-c ${CMAKE_CURRENT_SOURCE_DIR}/${file_name}.py > ${name}.c + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${file_name}.py + VERBATIM) + add_executable(${name} ${name}.c ${extra_files}) + target_include_directories(${name} PRIVATE ${CMAKE_SOURCE_DIR}) set_target_properties(${name} PROPERTIES LINKER_LANGUAGE C) target_link_libraries(${name} lpython_rtlib) add_test(${name} ${CMAKE_CURRENT_BINARY_DIR}/${name}) - if (RUN_LABELS) - set_tests_properties(${name} PROPERTIES LABELS "${RUN_LABELS}") + if (labels) + set_tests_properties(${name} PROPERTIES LABELS "${labels}") endif() - if (${RUN_FAIL}) + if (${fail}) set_tests_properties(${name} PROPERTIES WILL_FAIL TRUE) endif() - elseif(KIND STREQUAL "cpython") + elseif(KIND STREQUAL "c_py") + add_custom_command( + OUTPUT ${name}.c + COMMAND ${LPYTHON} ${extra_args} --show-c ${CMAKE_CURRENT_SOURCE_DIR}/${file_name}.py > ${name}.c + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${file_name}.py + VERBATIM) + add_executable(${name} ${name}.c ${extra_files}) + target_include_directories(${name} PRIVATE ${CMAKE_SOURCE_DIR} ${NUMPY_INCLUDE_DIR}) + set_target_properties(${name} PROPERTIES LINKER_LANGUAGE C) + target_link_libraries(${name} lpython_rtlib Python::Python) + add_test(${name} ${CMAKE_CURRENT_BINARY_DIR}/${name}) + if (labels) + set_tests_properties(${name} PROPERTIES LABELS "${labels}") + endif() + if (${fail}) + set_tests_properties(${name} PROPERTIES WILL_FAIL TRUE) + endif() + elseif(KIND STREQUAL "c_sym") + add_custom_command( + OUTPUT ${name}.c + COMMAND ${LPYTHON} ${extra_args} --show-c + ${CMAKE_CURRENT_SOURCE_DIR}/${file_name}.py > ${name}.c + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${file_name}.py + VERBATIM) + add_executable(${name} ${name}.c ${extra_files}) + target_include_directories(${name} PRIVATE ${CMAKE_SOURCE_DIR} + "${Python_INCLUDE_DIRS}/..") + set_target_properties(${name} PROPERTIES LINKER_LANGUAGE C) + if (APPLE) + set(SYMENGINE_LIB "${Python_LIBRARY_DIRS}/libsymengine.dylib") + else() + set(SYMENGINE_LIB "${Python_LIBRARY_DIRS}/libsymengine.so") + endif() + target_link_libraries(${name} lpython_rtlib ${SYMENGINE_LIB}) + add_test(${name} ${CMAKE_CURRENT_BINARY_DIR}/${name}) + if (labels) + set_tests_properties(${name} PROPERTIES LABELS "${labels}") + endif() + if (${fail}) + set_tests_properties(${name} PROPERTIES WILL_FAIL TRUE) + endif() + elseif((KIND STREQUAL "cpython") OR (KIND STREQUAL "cpython_sym")) # CPython test - if (RUN_EXTRAFILES) + if (extra_files) set(PY_MOD "${name}_mod") - add_library(${PY_MOD} SHARED ${RUN_EXTRAFILES}) + add_library(${PY_MOD} SHARED ${extra_files}) set_target_properties(${PY_MOD} PROPERTIES LINKER_LANGUAGE C) else() set(PY_MOD "") endif() - add_test(${name} python ${CMAKE_CURRENT_SOURCE_DIR}/${name}.py) - set_tests_properties(${name} PROPERTIES - ENVIRONMENT "PYTHONPATH=${CMAKE_SOURCE_DIR}/../src/runtime/ltypes:${CMAKE_SOURCE_DIR}/..;LPYTHON_PY_MOD_NAME=${PY_MOD};LPYTHON_PY_MOD_PATH=${CMAKE_CURRENT_BINARY_DIR}") - if (RUN_LABELS) - set_tests_properties(${name} PROPERTIES LABELS "${RUN_LABELS}") + add_test(${name} python ${CMAKE_CURRENT_SOURCE_DIR}/${file_name}.py) + if (no_mod) + set_tests_properties(${name} PROPERTIES + ENVIRONMENT "PYTHONPATH=${CMAKE_SOURCE_DIR}/../src/runtime/lpython:${CMAKE_SOURCE_DIR}/..") + else() + set_tests_properties(${name} PROPERTIES + ENVIRONMENT "PYTHONPATH=${CMAKE_SOURCE_DIR}/../src/runtime/lpython:${CMAKE_SOURCE_DIR}/..;LPYTHON_PY_MOD_NAME=${PY_MOD};LPYTHON_PY_MOD_PATH=${CMAKE_CURRENT_BINARY_DIR}") endif() - if (${RUN_FAIL}) + if (labels) + set_tests_properties(${name} PROPERTIES LABELS "${labels}") + endif() + if (${fail}) set_tests_properties(${name} PROPERTIES WILL_FAIL TRUE) endif() elseif(KIND STREQUAL "x86") # x86 test add_custom_command( OUTPUT ${name}.x86 - COMMAND lpython --backend x86 ${CMAKE_CURRENT_SOURCE_DIR}/${name}.py -o ${name}.x86 - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${name}.py + COMMAND ${LPYTHON} ${extra_args} --backend x86 ${CMAKE_CURRENT_SOURCE_DIR}/${file_name}.py -o ${name}.x86 + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${file_name}.py VERBATIM ) add_custom_target(${name} ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${name}.x86) add_test(${name} ${CMAKE_CURRENT_BINARY_DIR}/${name}.x86) - if (RUN_LABELS) - set_tests_properties(${name} PROPERTIES LABELS "${RUN_LABELS}") + if (labels) + set_tests_properties(${name} PROPERTIES LABELS "${labels}") endif() - if (${RUN_FAIL}) + if (${fail}) set_tests_properties(${name} PROPERTIES WILL_FAIL TRUE) endif() elseif(KIND STREQUAL "wasm_x86") # wasm_to_x86 test add_custom_command( OUTPUT ${name}.x86 - COMMAND lpython --backend wasm_x86 ${CMAKE_CURRENT_SOURCE_DIR}/${name}.py -o ${name}.x86 - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${name}.py + COMMAND ${LPYTHON} ${extra_args} --backend wasm_x86 ${CMAKE_CURRENT_SOURCE_DIR}/${file_name}.py -o ${name}.x86 + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${file_name}.py VERBATIM ) add_custom_target(${name} ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${name}.x86) add_test(${name} ${CMAKE_CURRENT_BINARY_DIR}/${name}.x86) - if (RUN_LABELS) - set_tests_properties(${name} PROPERTIES LABELS "${RUN_LABELS}") + if (labels) + set_tests_properties(${name} PROPERTIES LABELS "${labels}") endif() - if (${RUN_FAIL}) + if (${fail}) set_tests_properties(${name} PROPERTIES WILL_FAIL TRUE) endif() elseif(KIND STREQUAL "wasm_x64") # wasm_to_x64 test add_custom_command( OUTPUT ${name}.x64 - COMMAND lpython --backend wasm_x64 ${CMAKE_CURRENT_SOURCE_DIR}/${name}.py -o ${name}.x64 - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${name}.py + COMMAND ${LPYTHON} ${extra_args} --backend wasm_x64 ${CMAKE_CURRENT_SOURCE_DIR}/${file_name}.py -o ${name}.x64 + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${file_name}.py VERBATIM ) add_custom_target(${name} ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${name}.x64) add_test(${name} ${CMAKE_CURRENT_BINARY_DIR}/${name}.x64) - if (RUN_LABELS) - set_tests_properties(${name} PROPERTIES LABELS "${RUN_LABELS}") + if (labels) + set_tests_properties(${name} PROPERTIES LABELS "${labels}") endif() - if (${RUN_FAIL}) + if (${fail}) set_tests_properties(${name} PROPERTIES WILL_FAIL TRUE) endif() elseif(KIND STREQUAL "wasm") # wasm test - execute_process(COMMAND lpython --backend wasm ${CMAKE_CURRENT_SOURCE_DIR}/${name}.py -o ${name}) + execute_process(COMMAND ${LPYTHON} ${extra_args} --backend wasm ${CMAKE_CURRENT_SOURCE_DIR}/${file_name}.py -o ${name}) find_program(WASM_EXEC_RUNTIME node) execute_process(COMMAND "${WASM_EXEC_RUNTIME}" --version OUTPUT_VARIABLE WASM_EXEC_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) - string(COMPARE GREATER_EQUAL "${WASM_EXEC_VERSION}" - "v16.0.0" IS_NODE_ABOVE_16) - if (NOT IS_NODE_ABOVE_16) + string(REGEX REPLACE "v([0-9]+)\\.([0-9]+)\\.([0-9]+)" "\\1" NODE_MAJOR_VERSION "${WASM_EXEC_VERSION}") + + if (NODE_MAJOR_VERSION LESS 16) message(STATUS "${WASM_EXEC_RUNTIME} version: ${WASM_EXEC_VERSION}") set(WASM_EXEC_FLAGS "--experimental-wasm-bigint") endif() set(WASM_EXEC_FLAGS ${WASM_EXEC_FLAGS} "--experimental-wasi-unstable-preview1") add_test(${name} ${WASM_EXEC_RUNTIME} ${WASM_EXEC_FLAGS} ${CMAKE_CURRENT_BINARY_DIR}/${name}.js) + if (labels) + set_tests_properties(${name} PROPERTIES LABELS "${labels}") + endif() + if (${fail}) + set_tests_properties(${name} PROPERTIES WILL_FAIL TRUE) + endif() + endif() + + if (copy_to_bin) + file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/${copy_to_bin} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) + endif() + + endif() +endmacro(RUN_UTIL) + +macro(RUN) + set(options FAIL NOFAST NOMOD) + set(oneValueArgs NAME IMPORT_PATH COPY_TO_BIN REQ_PY_VER) + set(multiValueArgs LABELS EXTRAFILES EXTRA_ARGS) + cmake_parse_arguments(RUN "${options}" "${oneValueArgs}" + "${multiValueArgs}" ${ARGN} ) + + set(RUN_FILE_NAME ${RUN_NAME}) + + if (RUN_IMPORT_PATH) + # Only one import path supported for now + # Later add support for multiple import paths by looping over and appending to extra args + set(RUN_EXTRA_ARGS ${RUN_EXTRA_ARGS} -I${CMAKE_CURRENT_SOURCE_DIR}/${RUN_IMPORT_PATH}) + endif() + + if (RUN_REQ_PY_VER) + string(REGEX REPLACE "([0-9]+)\\.([0-9]+)\\.([0-9]+)" "\\1" PY_MAJOR_VERSION "${Python_VERSION}") + string(REGEX REPLACE "([0-9]+)\\.([0-9]+)\\.([0-9]+)" "\\2" PY_MINOR_VERSION "${Python_VERSION}") + string(REGEX REPLACE "([0-9]+)\\.([0-9]+)" "\\1" REQ_PY_MAJOR_VERSION "${RUN_REQ_PY_VER}") + string(REGEX REPLACE "([0-9]+)\\.([0-9]+)" "\\2" REQ_PY_MINOR_VERSION "${RUN_REQ_PY_VER}") + + if (PY_MINOR_VERSION LESS REQ_PY_MINOR_VERSION) + # remove backends from the test that depend on CPython + list(REMOVE_ITEM RUN_LABELS cpython cpython_sym c_py c_sym llvm_sym llvm_py) + endif() + endif() + + if (NOT FAST) + RUN_UTIL(RUN_FAIL RUN_NAME RUN_FILE_NAME RUN_LABELS RUN_EXTRAFILES RUN_NOMOD RUN_EXTRA_ARGS RUN_COPY_TO_BIN) + endif() + + if ((FAST) AND (NOT RUN_NOFAST)) + set(RUN_EXTRA_ARGS ${RUN_EXTRA_ARGS} --fast) + set(RUN_NAME "${RUN_NAME}_FAST") + list(REMOVE_ITEM RUN_LABELS cpython cpython_sym) # remove cpython, cpython_sym, from --fast test + RUN_UTIL(RUN_FAIL RUN_NAME RUN_FILE_NAME RUN_LABELS RUN_EXTRAFILES RUN_NOMOD RUN_EXTRA_ARGS RUN_COPY_TO_BIN) + endif() +endmacro(RUN) + +# only compiles till object file +# to make sure that the generated code is syntactically correct +# but we cannot generate an executable due to --disable-main option enabled. +macro(COMPILE) + set(options FAIL) + set(oneValueArgs NAME IMPORT_PATH) + set(multiValueArgs LABELS EXTRAFILES) + cmake_parse_arguments(COMPILE "${options}" "${oneValueArgs}" + "${multiValueArgs}" ${ARGN} ) + set(name ${COMPILE_NAME}) + if (NOT name) + message(FATAL_ERROR "Must specify the NAME argument") + endif() + + set(extra_args "") + if (COMPILE_IMPORT_PATH) + # Only one import path supported for now + # Later add support for multiple import paths by looping over and appending to extra args + set(extra_args ${extra_args} -I${CMAKE_CURRENT_SOURCE_DIR}/${COMPILE_IMPORT_PATH}) + endif() + + if (${KIND} IN_LIST COMPILE_LABELS) + if (KIND STREQUAL "llvm") + add_custom_command( + OUTPUT ${name}.o + COMMAND ${LPYTHON} ${extra_args} --disable-main -c ${CMAKE_CURRENT_SOURCE_DIR}/${name}.py -o ${name}.o + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${name}.py + VERBATIM) + add_library(${name} OBJECT ${name}.o) + set_target_properties(${name} PROPERTIES LINKER_LANGUAGE C) + elseif(KIND STREQUAL "c") + add_custom_command( + OUTPUT ${name}.c + COMMAND ${LPYTHON} ${extra_args} --disable-main --show-c ${CMAKE_CURRENT_SOURCE_DIR}/${name}.py > ${name}.c + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${name}.py + VERBATIM) + add_library(${name} OBJECT ${name}.c) + set_target_properties(${name} PROPERTIES LINKER_LANGUAGE C) + target_link_libraries(${name} lpython_rtlib) + elseif(KIND STREQUAL "cpython") + # CPython test + set(PY_MOD "") + + add_test(${name} python ${CMAKE_CURRENT_SOURCE_DIR}/${name}.py) + set_tests_properties(${name} PROPERTIES + ENVIRONMENT "PYTHONPATH=${CMAKE_SOURCE_DIR}/../src/runtime/lpython:${CMAKE_SOURCE_DIR}/..;LPYTHON_PY_MOD_NAME=${PY_MOD};LPYTHON_PY_MOD_PATH=${CMAKE_CURRENT_BINARY_DIR}") if (RUN_LABELS) set_tests_properties(${name} PROPERTIES LABELS "${RUN_LABELS}") endif() @@ -201,241 +413,454 @@ macro(RUN) endif() endif() endif() -endmacro(RUN) +endmacro(COMPILE) # Test zero and non-zero exit code and assert statements -RUN(NAME array_01_decl LABELS cpython llvm c) -RUN(NAME array_02_decl LABELS cpython llvm c) -RUN(NAME array_03_decl LABELS cpython llvm c) -RUN(NAME variable_decl_01 LABELS cpython llvm c) -RUN(NAME variable_decl_02 LABELS cpython llvm c) -RUN(NAME array_expr_01 LABELS cpython llvm c) -RUN(NAME array_expr_02 LABELS cpython llvm c) -RUN(NAME array_01 LABELS cpython llvm wasm c) +RUN(NAME array_01_decl LABELS cpython llvm llvm_jit c) +RUN(NAME array_02_decl LABELS cpython llvm llvm_jit c) +RUN(NAME array_03_decl LABELS cpython llvm llvm_jit) # renable c +RUN(NAME variable_decl_01 LABELS cpython llvm llvm_jit c) +RUN(NAME variable_decl_02 LABELS cpython llvm llvm_jit c) +RUN(NAME variable_decl_03 LABELS cpython llvm llvm_jit c) +RUN(NAME array_expr_01 LABELS cpython llvm llvm_jit c) +RUN(NAME array_expr_02 LABELS cpython llvm llvm_jit c NOFAST) # post sync +RUN(NAME array_expr_03 LABELS cpython llvm llvm_jit c) +RUN(NAME array_expr_04 LABELS cpython llvm llvm_jit c) +RUN(NAME array_expr_05 LABELS cpython llvm llvm_jit c) +RUN(NAME array_expr_06 LABELS cpython llvm llvm_jit c) +RUN(NAME array_expr_07 LABELS cpython llvm llvm_jit c) +RUN(NAME array_expr_08 LABELS cpython llvm llvm_jit c) +RUN(NAME array_expr_09 LABELS cpython llvm llvm_jit c) +RUN(NAME array_expr_10 LABELS cpython llvm llvm_jit c) # post sync +RUN(NAME array_size_01 LABELS cpython llvm llvm_jit c) +RUN(NAME array_size_02 LABELS cpython llvm llvm_jit c) +RUN(NAME array_01 LABELS cpython llvm llvm_jit wasm c) RUN(NAME array_02 LABELS cpython wasm c) -RUN(NAME bindc_01 LABELS cpython llvm c) -RUN(NAME bindc_02 LABELS cpython llvm c) -RUN(NAME bindc_04 LABELS llvm c) -RUN(NAME bindc_07 LABELS cpython llvm c) -RUN(NAME exit_01 LABELS cpython llvm c wasm wasm_x86 wasm_x64) -RUN(NAME exit_02 FAIL LABELS cpython llvm c wasm wasm_x86 wasm_x64) -RUN(NAME exit_01b LABELS cpython llvm c wasm wasm_x86 wasm_x64) -RUN(NAME exit_02b FAIL LABELS cpython llvm c wasm wasm_x86 wasm_x64) -RUN(NAME exit_02c FAIL LABELS cpython llvm c) +RUN(NAME array_03 LABELS cpython llvm llvm_jit c) +RUN(NAME array_04 LABELS cpython llvm llvm_jit c) +RUN(NAME array_05 LABELS cpython llvm llvm_jit c) +RUN(NAME array_06 LABELS cpython llvm llvm_jit) +# RUN(NAME bindc_01 LABELS cpython llvm llvm_jit c) +# RUN(NAME bindc_02 LABELS cpython llvm llvm_jit c) +# RUN(NAME bindc_04 LABELS llvm llvm_jit c NOFAST) +# RUN(NAME bindc_07 LABELS cpython llvm llvm_jit c NOFAST) +# RUN(NAME bindc_08 LABELS cpython llvm llvm_jit c) +# RUN(NAME bindc_09 LABELS cpython llvm llvm_jit c NOFAST) +# RUN(NAME bindc_09b LABELS cpython llvm llvm_jit c NOFAST) +# RUN(NAME bindc_10 LABELS cpython llvm llvm_jit c NOFAST) +# RUN(NAME bindc_11 LABELS cpython) # This is CPython test only +RUN(NAME exit_01 LABELS cpython llvm llvm_jit NOFAST) # renable c +RUN(NAME exit_02 FAIL LABELS cpython llvm llvm_jit NOFAST) # renable c +RUN(NAME exit_03 LABELS cpython llvm llvm_jit c wasm wasm_x86 wasm_x64) +RUN(NAME exit_04 FAIL LABELS cpython llvm llvm_jit c wasm wasm_x86 wasm_x64) +RUN(NAME exit_01b LABELS cpython llvm llvm_jit c wasm wasm_x86 wasm_x64) +RUN(NAME exit_02b FAIL LABELS cpython llvm llvm_jit c wasm wasm_x86 wasm_x64) +RUN(NAME exit_02c FAIL LABELS cpython llvm llvm_jit c) # Test all four backends -RUN(NAME print_01 LABELS cpython llvm c wasm) # wasm not yet supports sep and end keywords +RUN(NAME print_01 LABELS cpython llvm llvm_jit) # renable c, wasm not yet supports sep and end keywords, wasm does not handle DescriptorString RUN(NAME print_03 LABELS x86 c wasm wasm_x86 wasm_x64) # simple test case specifically for x86, wasm_x86 and wasm_x64 -RUN(NAME print_04 LABELS cpython llvm c) -RUN(NAME print_06 LABELS cpython llvm c) -RUN(NAME print_05 LABELS cpython llvm c wasm wasm_x64) -RUN(NAME print_float LABELS cpython llvm c wasm wasm_x64) -RUN(NAME print_list_tuple_01 LABELS cpython llvm c) -RUN(NAME print_list_tuple_02 LABELS cpython llvm c) +RUN(NAME print_04 LABELS cpython llvm llvm_jit c) +RUN(NAME print_06 LABELS cpython llvm llvm_jit) # renable c +RUN(NAME print_05 LABELS cpython llvm llvm_jit c wasm wasm_x64) +RUN(NAME print_float LABELS cpython llvm llvm_jit c wasm wasm_x64) +# RUN(NAME print_list_tuple_01 LABELS cpython llvm llvm_jit NOFAST) # renable c # post sync +# RUN(NAME print_list_tuple_02 LABELS cpython llvm llvm_jit c NOFAST) +# RUN(NAME print_list_tuple_03 LABELS cpython llvm llvm_jit c NOFAST) +RUN(NAME test_list_item_mixed_print LABELS cpython llvm llvm_jit NOFAST) # renable c # post sync +# RUN(NAME test_intrinsic_function_mixed_print LABELS cpython llvm llvm_jit NOFAST) # post sync # CPython and LLVM -RUN(NAME const_01 LABELS cpython llvm c) -RUN(NAME const_02 LABELS cpython llvm c) +RUN(NAME const_01 LABELS cpython llvm llvm_jit c wasm) +RUN(NAME const_02 LABELS cpython llvm llvm_jit c wasm) RUN(NAME const_03 LABELS cpython llvm c EXTRAFILES const_03b.c) -RUN(NAME const_04 LABELS cpython llvm c) -RUN(NAME expr_01 LABELS cpython llvm c wasm wasm_x64) -RUN(NAME expr_02 LABELS cpython llvm c wasm wasm_x64) -RUN(NAME expr_03 LABELS cpython llvm c wasm wasm_x64) -RUN(NAME expr_04 LABELS cpython llvm c wasm) -RUN(NAME expr_05 LABELS cpython llvm c) -RUN(NAME expr_06 LABELS cpython llvm c) -RUN(NAME expr_07 LABELS cpython llvm c) -RUN(NAME expr_08 LABELS llvm c) -RUN(NAME expr_09 LABELS cpython llvm c) -RUN(NAME expr_10 LABELS cpython llvm c) -RUN(NAME expr_11 LABELS cpython llvm c wasm) -RUN(NAME expr_12 LABELS llvm c) -RUN(NAME expr_13 LABELS llvm c - EXTRAFILES expr_13b.c) -RUN(NAME expr_14 LABELS cpython llvm c) -RUN(NAME expr_15 LABELS cpython llvm c) -RUN(NAME loop_01 LABELS cpython llvm c) -RUN(NAME loop_02 LABELS cpython llvm c wasm wasm_x86 wasm_x64) -RUN(NAME loop_03 LABELS cpython llvm c wasm wasm_x64) -RUN(NAME loop_04 LABELS cpython llvm c) -RUN(NAME loop_05 LABELS cpython llvm c) -RUN(NAME if_01 LABELS cpython llvm c wasm wasm_x86 wasm_x64) -RUN(NAME if_02 LABELS cpython llvm c wasm wasm_x86 wasm_x64) -RUN(NAME print_02 LABELS cpython llvm c) -RUN(NAME test_types_01 LABELS cpython llvm c) -RUN(NAME test_str_01 LABELS cpython llvm c) -RUN(NAME test_str_02 LABELS cpython llvm c) -RUN(NAME test_str_03 LABELS cpython llvm c) -RUN(NAME test_list_01 LABELS cpython llvm c) -RUN(NAME test_list_02 LABELS cpython llvm c) -RUN(NAME test_list_03 LABELS cpython llvm c) -RUN(NAME test_list_04 LABELS cpython llvm c) -RUN(NAME test_list_05 LABELS cpython llvm c) -RUN(NAME test_list_06 LABELS cpython llvm c) -RUN(NAME test_list_07 LABELS cpython llvm c) -RUN(NAME test_list_08 LABELS cpython llvm c) -RUN(NAME test_list_09 LABELS cpython llvm c) -RUN(NAME test_list_10 LABELS cpython llvm c) -RUN(NAME test_list_section LABELS cpython llvm c) -RUN(NAME test_tuple_01 LABELS cpython llvm c) -RUN(NAME test_tuple_02 LABELS cpython llvm c) -RUN(NAME test_tuple_03 LABELS cpython llvm c) -RUN(NAME test_dict_01 LABELS cpython llvm c) -RUN(NAME test_dict_02 LABELS cpython llvm c) -RUN(NAME test_dict_03 LABELS cpython llvm) -RUN(NAME test_dict_04 LABELS cpython llvm) -RUN(NAME test_dict_05 LABELS cpython llvm) -RUN(NAME test_for_loop LABELS cpython llvm c) -RUN(NAME modules_01 LABELS cpython llvm c wasm wasm_x86 wasm_x64) -RUN(NAME modules_02 LABELS cpython llvm c wasm wasm_x86 wasm_x64) -RUN(NAME test_import_01 LABELS cpython llvm c) -RUN(NAME test_import_02 LABELS cpython llvm c) -RUN(NAME test_import_03 LABELS cpython llvm c) -RUN(NAME test_import_04 IMPORT_PATH .. - LABELS cpython llvm c) -RUN(NAME test_math LABELS cpython llvm) -RUN(NAME test_numpy_01 LABELS cpython llvm c) -RUN(NAME test_numpy_02 LABELS cpython llvm c) -RUN(NAME test_numpy_03 LABELS cpython llvm c) -RUN(NAME test_numpy_04 LABELS cpython llvm c) -RUN(NAME elemental_01 LABELS cpython llvm c) -RUN(NAME elemental_02 LABELS cpython llvm c) -RUN(NAME elemental_03 LABELS cpython llvm c) -RUN(NAME elemental_04 LABELS cpython llvm c) -RUN(NAME elemental_05 LABELS cpython llvm c) -RUN(NAME elemental_06 LABELS cpython llvm c) -RUN(NAME elemental_07 LABELS cpython llvm c) -RUN(NAME elemental_08 LABELS cpython llvm c) -RUN(NAME elemental_09 LABELS cpython llvm c) -RUN(NAME elemental_10 LABELS cpython llvm c) -RUN(NAME elemental_11 LABELS cpython llvm c) -RUN(NAME elemental_12 LABELS cpython llvm c) -RUN(NAME test_random LABELS cpython llvm) -RUN(NAME test_os LABELS cpython llvm c) -RUN(NAME test_builtin LABELS cpython llvm c) -RUN(NAME test_builtin_abs LABELS cpython llvm c) -RUN(NAME test_builtin_bool LABELS cpython llvm c) -RUN(NAME test_builtin_pow LABELS cpython llvm c) -RUN(NAME test_builtin_int LABELS cpython llvm c) -RUN(NAME test_builtin_len LABELS cpython llvm c) -RUN(NAME test_builtin_str LABELS cpython llvm c) -RUN(NAME test_builtin_oct LABELS cpython llvm c) -RUN(NAME test_builtin_hex LABELS cpython llvm c) -RUN(NAME test_builtin_bin LABELS cpython llvm c) -RUN(NAME test_builtin_float LABELS cpython llvm c) -RUN(NAME test_builtin_str_02 LABELS cpython llvm c) -RUN(NAME test_builtin_round LABELS cpython llvm c) -RUN(NAME test_builtin_divmod LABELS cpython llvm c) -RUN(NAME test_builtin_sum LABELS cpython llvm c) -RUN(NAME test_math1 LABELS cpython llvm c) -RUN(NAME test_math_02 LABELS cpython llvm) -RUN(NAME test_math_03 LABELS llvm) #1595: TODO: Test using CPython (3.11 recommended) -RUN(NAME test_pass_compare LABELS cpython llvm c) -RUN(NAME test_c_interop_01 LABELS cpython llvm c) -RUN(NAME test_c_interop_02 LABELS cpython llvm c - EXTRAFILES test_c_interop_02b.c) -RUN(NAME test_c_interop_03 LABELS cpython llvm c - EXTRAFILES test_c_interop_03b.c) -RUN(NAME test_c_interop_04 LABELS cpython llvm c - EXTRAFILES test_c_interop_04b.c) -RUN(NAME test_c_interop_05 LABELS llvm c - EXTRAFILES test_c_interop_05b.c) -RUN(NAME bindc_03 LABELS llvm c - EXTRAFILES bindc_03b.c) -RUN(NAME bindc_05 LABELS llvm c - EXTRAFILES bindc_05b.c) -RUN(NAME bindc_06 LABELS llvm c - EXTRAFILES bindc_06b.c) -RUN(NAME test_generics_01 LABELS cpython llvm c) -RUN(NAME test_cmath LABELS cpython llvm c) -RUN(NAME test_complex_01 LABELS cpython llvm c wasm wasm_x64) -RUN(NAME test_complex_02 LABELS cpython llvm c) -RUN(NAME test_max_min LABELS cpython llvm c) -RUN(NAME test_global LABELS cpython llvm c) -RUN(NAME test_global_decl LABELS cpython llvm c) -RUN(NAME test_integer_bitnot LABELS cpython llvm c wasm) -RUN(NAME test_ifexp LABELS cpython llvm c) -RUN(NAME test_unary_minus LABELS cpython llvm c) -RUN(NAME test_unary_plus LABELS cpython llvm c) -RUN(NAME test_bool_binop LABELS cpython llvm c) -RUN(NAME test_issue_518 LABELS cpython llvm c) -RUN(NAME structs_01 LABELS cpython llvm c) -RUN(NAME structs_02 LABELS cpython llvm c) -RUN(NAME structs_03 LABELS llvm c) -RUN(NAME structs_04 LABELS cpython llvm c) -RUN(NAME structs_05 LABELS llvm c) -RUN(NAME structs_06 LABELS cpython llvm c) -RUN(NAME structs_07 LABELS llvm c - EXTRAFILES structs_07b.c) -RUN(NAME structs_08 LABELS cpython llvm c) -RUN(NAME structs_09 LABELS cpython llvm c) -RUN(NAME structs_10 LABELS cpython llvm c) -RUN(NAME structs_11 LABELS cpython llvm c) -RUN(NAME structs_12 LABELS cpython llvm c) -RUN(NAME structs_13 LABELS llvm c - EXTRAFILES structs_13b.c) -RUN(NAME structs_14 LABELS cpython llvm c) -RUN(NAME structs_15 LABELS cpython llvm c) -RUN(NAME structs_16 LABELS cpython llvm c) -RUN(NAME structs_17 LABELS cpython llvm c) -RUN(NAME structs_18 LABELS cpython llvm c - EXTRAFILES structs_18b.c) -RUN(NAME structs_19 LABELS cpython llvm c - EXTRAFILES structs_19b.c) -RUN(NAME structs_20 LABELS cpython llvm c - EXTRAFILES structs_20b.c) -RUN(NAME structs_21 LABELS cpython llvm c) -RUN(NAME sizeof_01 LABELS llvm c - EXTRAFILES sizeof_01b.c) -RUN(NAME enum_01 LABELS cpython llvm c) -RUN(NAME enum_02 LABELS cpython llvm) -RUN(NAME enum_03 LABELS cpython llvm c) -RUN(NAME enum_04 LABELS cpython llvm c) -RUN(NAME enum_05 LABELS llvm c - EXTRAFILES enum_05b.c) -RUN(NAME enum_06 LABELS cpython llvm c) -RUN(NAME union_01 LABELS cpython llvm c) -RUN(NAME union_02 LABELS llvm c) -RUN(NAME union_03 LABELS cpython llvm c) -RUN(NAME test_str_to_int LABELS cpython llvm c) -RUN(NAME test_platform LABELS cpython llvm c) -RUN(NAME test_vars_01 LABELS cpython llvm) -RUN(NAME test_version LABELS cpython llvm) -RUN(NAME logical_binop1 LABELS cpython llvm) -RUN(NAME vec_01 LABELS cpython llvm c) -RUN(NAME test_str_comparison LABELS cpython llvm c) -RUN(NAME test_bit_length LABELS cpython llvm c) -RUN(NAME str_to_list_cast LABELS cpython llvm c) - -RUN(NAME test_package_01 LABELS cpython llvm) - -RUN(NAME generics_01 LABELS cpython llvm c) -RUN(NAME generics_02 LABELS cpython llvm c) -RUN(NAME generics_array_01 LABELS cpython llvm c) -RUN(NAME generics_array_02 LABELS cpython llvm c) -RUN(NAME generics_array_03 LABELS cpython llvm c) -RUN(NAME generics_list_01 LABELS cpython llvm c) -RUN(NAME test_statistics LABELS cpython llvm) -RUN(NAME test_str_attributes LABELS cpython llvm c) -RUN(NAME kwargs_01 LABELS cpython llvm c) -RUN(NAME test_01_goto LABELS cpython llvm c) - -RUN(NAME func_inline_01 LABELS llvm c wasm) -RUN(NAME func_inline_02 LABELS cpython llvm c) -RUN(NAME func_static_01 LABELS cpython llvm c wasm) -RUN(NAME func_static_02 LABELS cpython llvm c wasm) -RUN(NAME func_dep_03 LABELS cpython llvm c) -RUN(NAME func_dep_04 LABELS cpython llvm c) - -RUN(NAME float_01 LABELS cpython llvm c wasm wasm_x64) -RUN(NAME recursive_01 LABELS cpython llvm c wasm wasm_x64 wasm_x86) -RUN(NAME comp_01 LABELS cpython llvm c wasm wasm_x64) -RUN(NAME bit_operations_i32 LABELS cpython llvm c wasm wasm_x64) -RUN(NAME bit_operations_i64 LABELS cpython llvm c wasm) - -RUN(NAME test_argv_01 LABELS llvm) # TODO: Test using CPython -RUN(NAME global_syms_01 LABELS cpython llvm c) -RUN(NAME global_syms_02 LABELS cpython llvm c) -RUN(NAME global_syms_03_b LABELS cpython llvm c) +# RUN(NAME const_04 LABELS cpython llvm llvm_jit c) +RUN(NAME expr_01 LABELS cpython llvm llvm_jit c wasm) # renable wasm_x64 +RUN(NAME expr_02 LABELS cpython llvm llvm_jit c wasm) # renable wasm_x64 +RUN(NAME expr_03 LABELS cpython llvm llvm_jit c wasm) # renable wasm_x64 +RUN(NAME expr_04 LABELS cpython llvm llvm_jit c wasm NOFAST) +RUN(NAME expr_05 LABELS cpython llvm llvm_jit c NOFAST) +RUN(NAME expr_06 LABELS cpython llvm llvm_jit c NOFAST) +# RUN(NAME expr_07 LABELS cpython llvm llvm_jit c) # string refactor +# RUN(NAME expr_08 LABELS llvm llvm_jit c NOFAST) +RUN(NAME expr_09 LABELS cpython llvm llvm_jit c) +RUN(NAME expr_10 LABELS cpython llvm llvm_jit c) +RUN(NAME expr_11 LABELS cpython llvm llvm_jit c wasm) +# RUN(NAME expr_12 LABELS llvm llvm_jit c) +# RUN(NAME expr_13 LABELS llvm c +# EXTRAFILES expr_13b.c NOFAST) +RUN(NAME expr_14 LABELS cpython llvm llvm_jit c) +RUN(NAME expr_15 LABELS cpython llvm llvm_jit c) +# RUN(NAME expr_16 LABELS cpython llvm llvm_jit c) +RUN(NAME expr_17 LABELS cpython llvm llvm_jit c) +RUN(NAME expr_18 FAIL LABELS cpython llvm llvm_jit c) +RUN(NAME expr_19 LABELS cpython llvm llvm_jit c) +RUN(NAME expr_20 LABELS cpython llvm llvm_jit c) +# RUN(NAME expr_21 LABELS cpython llvm llvm_jit c) # post sync +RUN(NAME expr_22 LABELS cpython llvm llvm_jit c) +RUN(NAME expr_23 LABELS cpython llvm llvm_jit c) +# RUN(NAME expr_24 LABELS cpython wasm) # mandelbrot + +RUN(NAME expr_01u LABELS cpython llvm llvm_jit c NOFAST) +RUN(NAME expr_02u LABELS cpython llvm llvm_jit c NOFAST) +# RUN(NAME expr_03u LABELS cpython llvm llvm_jit c NOFAST) +# RUN(NAME expr_04u LABELS cpython llvm llvm_jit c) + +RUN(NAME list_01 LABELS cpython llvm llvm_jit) + +RUN(NAME loop_01 LABELS cpython llvm llvm_jit) # renable c +RUN(NAME loop_02 LABELS cpython llvm llvm_jit c wasm wasm_x86 wasm_x64) +RUN(NAME loop_03 LABELS cpython llvm llvm_jit c wasm wasm_x64) +RUN(NAME loop_04 LABELS cpython llvm llvm_jit c) +RUN(NAME loop_05 LABELS cpython llvm llvm_jit c) +RUN(NAME loop_06 LABELS cpython llvm llvm_jit NOFAST) # renable c +RUN(NAME loop_07 LABELS cpython llvm llvm_jit c) +RUN(NAME loop_08 LABELS cpython llvm llvm_jit c) +RUN(NAME loop_09 LABELS cpython llvm llvm_jit) +RUN(NAME loop_10 LABELS cpython llvm llvm_jit) +# RUN(NAME loop_11 LABELS cpython llvm llvm_jit) +RUN(NAME if_01 LABELS cpython llvm llvm_jit c wasm wasm_x86 wasm_x64) +RUN(NAME if_02 LABELS cpython llvm llvm_jit c wasm wasm_x86 wasm_x64) +RUN(NAME if_03 FAIL LABELS cpython llvm llvm_jit NOFAST) # renable c +# RUN(NAME print_02 LABELS cpython llvm llvm_jit) # renable c # post sync +RUN(NAME test_types_01 LABELS cpython llvm llvm_jit c) +RUN(NAME test_types_02 LABELS cpython llvm llvm_jit c wasm) +# RUN(NAME test_str_01 LABELS cpython llvm llvm_jit c) +RUN(NAME test_str_02 LABELS cpython llvm llvm_jit) # renable c +# RUN(NAME test_str_03 LABELS cpython llvm llvm_jit) # renable c # str negative indexing +RUN(NAME test_str_04 LABELS cpython llvm llvm_jit) # renable c, wasm +RUN(NAME test_str_05 LABELS cpython llvm llvm_jit) # renable c +# RUN(NAME test_str_06 LABELS cpython llvm llvm_jit c) +RUN(NAME test_string_01 LABELS cpython llvm llvm_jit) # renable c +RUN(NAME test_list_01 LABELS cpython llvm llvm_jit c) +RUN(NAME test_list_02 LABELS cpython llvm llvm_jit) # renable c +RUN(NAME test_list_03 LABELS cpython llvm llvm_jit NOFAST) # renable c +RUN(NAME test_list_04 LABELS cpython llvm llvm_jit NOFAST) # renable c +# RUN(NAME test_list_05 LABELS cpython llvm llvm_jit c NOFAST) +RUN(NAME test_list_06 LABELS cpython llvm llvm_jit c) +RUN(NAME test_list_07 LABELS cpython llvm llvm_jit c NOFAST) +RUN(NAME test_list_08 LABELS cpython llvm llvm_jit c NOFAST) +RUN(NAME test_list_09 LABELS cpython llvm llvm_jit NOFAST) # renable c +# RUN(NAME test_list_10 LABELS cpython llvm llvm_jit c NOFAST) +# RUN(NAME test_list_11 LABELS cpython llvm llvm_jit c) +# RUN(NAME test_list_section LABELS cpython llvm llvm_jit c NOFAST) +# RUN(NAME test_list_section2 LABELS cpython llvm llvm_jit c NOFAST) +# RUN(NAME test_list_count LABELS cpython llvm llvm_jit) # post sync +# RUN(NAME test_list_index LABELS cpython llvm llvm_jit) # post sync +# RUN(NAME test_list_index2 LABELS cpython llvm llvm_jit) # post sync +# RUN(NAME test_list_repeat LABELS cpython llvm llvm_jit c NOFAST) +# RUN(NAME test_list_repeat2 LABELS cpython llvm llvm_jit c NOFAST) +# RUN(NAME test_list_reverse LABELS cpython llvm llvm_jit) # post sync +# RUN(NAME test_list_pop LABELS cpython llvm llvm_jit NOFAST) # TODO: Remove NOFAST from here. +RUN(NAME test_list_pop2 LABELS cpython llvm llvm_jit NOFAST) # TODO: Remove NOFAST from here. +RUN(NAME test_list_pop3 LABELS cpython llvm llvm_jit) +# RUN(NAME test_list_compare LABELS cpython llvm llvm_jit) # post sync +RUN(NAME test_list_compare2 LABELS cpython llvm llvm_jit) +RUN(NAME test_list_concat LABELS cpython llvm llvm_jit c NOFAST) +# RUN(NAME test_list_reserve LABELS cpython llvm llvm_jit) # post sync +# RUN(NAME test_const_list LABELS cpython llvm llvm_jit) # post sync +# RUN(NAME test_const_access LABELS cpython llvm llvm_jit) # post sync +# RUN(NAME test_tuple_01 LABELS cpython llvm llvm_jit) # renable c # post sync +# RUN(NAME test_tuple_02 LABELS cpython llvm llvm_jit c NOFAST) +# RUN(NAME test_tuple_03 LABELS cpython llvm llvm_jit) # renable c # post sync +# RUN(NAME test_tuple_04 LABELS cpython llvm llvm_jit) # renable c # post sync +# RUN(NAME test_tuple_concat LABELS cpython llvm llvm_jit) # post sync +# RUN(NAME test_tuple_nested LABELS cpython llvm llvm_jit) # post sync +# RUN(NAME test_const_dict LABELS cpython llvm llvm_jit) # post sync +# RUN(NAME test_params LABELS cpython llvm llvm_jit NOFAST) +RUN(NAME test_dict_01 LABELS cpython llvm llvm_jit c) # post sync +RUN(NAME test_dict_02 LABELS cpython llvm llvm_jit c NOFAST) +# RUN(NAME test_dict_03 LABELS cpython llvm llvm_jit NOFAST) +RUN(NAME test_dict_04 LABELS cpython llvm llvm_jit NOFAST) +RUN(NAME test_dict_05 LABELS cpython llvm llvm_jit c) +RUN(NAME test_dict_06 LABELS cpython llvm llvm_jit c) +# RUN(NAME test_dict_07 LABELS cpython llvm llvm_jit c) +RUN(NAME test_dict_08 LABELS cpython llvm llvm_jit c) +RUN(NAME test_dict_09 LABELS cpython llvm llvm_jit c) +# RUN(NAME test_dict_10 LABELS cpython llvm llvm_jit) # renable c # post sync +# RUN(NAME test_dict_11 LABELS cpython llvm llvm_jit c) # post sync +RUN(NAME test_dict_12 LABELS cpython llvm) # renable c, jit +RUN(NAME test_dict_13 LABELS cpython llvm) # renable c, jit +# RUN(NAME test_dict_bool LABELS cpython llvm llvm_jit) # post sync +# RUN(NAME test_dict_increment LABELS cpython llvm llvm_jit) # post sync +# RUN(NAME test_dict_keys_values LABELS cpython llvm llvm_jit) +# RUN(NAME test_dict_nested1 LABELS cpython llvm llvm_jit) +# RUN(NAME test_dict_clear LABELS cpython llvm) +# RUN(NAME test_set_len LABELS cpython llvm llvm_jit) # post sync +# RUN(NAME test_set_add LABELS cpython llvm llvm_jit) # post sync +# RUN(NAME test_set_remove LABELS cpython llvm llvm_jit) +# RUN(NAME test_set_discard LABELS cpython llvm llvm_jit) +# RUN(NAME test_set_from_list LABELS cpython llvm llvm_jit) +# RUN(NAME test_set_clear LABELS cpython llvm) +# RUN(NAME test_set_pop LABELS cpython llvm) +# RUN(NAME test_global_set LABELS cpython llvm llvm_jit) # post sync +RUN(NAME test_for_loop LABELS cpython llvm llvm_jit c) +RUN(NAME modules_01 LABELS cpython llvm llvm_jit c wasm wasm_x86 wasm_x64) +RUN(NAME modules_02 LABELS cpython llvm llvm_jit c wasm wasm_x86 wasm_x64) +RUN(NAME test_import_01 LABELS cpython llvm llvm_jit) # renable c +RUN(NAME test_import_02 LABELS cpython llvm llvm_jit c) +RUN(NAME test_import_03 LABELS cpython llvm llvm_jit) # renable c +RUN(NAME test_import_04 LABELS cpython llvm llvm_jit c) +RUN(NAME test_import_05 LABELS cpython llvm llvm_jit c wasm wasm_x86 wasm_x64) +RUN(NAME test_import_06 LABELS cpython llvm llvm_jit) +RUN(NAME test_import_07 LABELS cpython llvm llvm_jit c) +RUN(NAME test_import_08 LABELS cpython llvm) +RUN(NAME test_math LABELS cpython llvm llvm_jit NOFAST) +# RUN(NAME test_membership_01 LABELS cpython llvm) +RUN(NAME test_numpy_01 LABELS cpython llvm llvm_jit c) +RUN(NAME test_numpy_02 LABELS cpython llvm llvm_jit c) +RUN(NAME test_numpy_03 LABELS cpython llvm llvm_jit c) +RUN(NAME test_numpy_04 LABELS cpython llvm llvm_jit c) +RUN(NAME elemental_01 LABELS cpython llvm llvm_jit NOFAST) # renable c +RUN(NAME elemental_02 LABELS cpython llvm llvm_jit c NOFAST) +RUN(NAME elemental_03 LABELS cpython llvm llvm_jit NOFAST) # renable c +RUN(NAME elemental_04 LABELS cpython llvm llvm_jit c NOFAST) +RUN(NAME elemental_05 LABELS cpython llvm llvm_jit NOFAST) # renable c +RUN(NAME elemental_06 LABELS cpython llvm llvm_jit NOFAST) # renable c +RUN(NAME elemental_07 LABELS cpython llvm llvm_jit NOFAST) # renable c +RUN(NAME elemental_08 LABELS cpython llvm llvm_jit c NOFAST) +RUN(NAME elemental_09 LABELS cpython llvm llvm_jit NOFAST) # renable c +RUN(NAME elemental_10 LABELS cpython llvm llvm_jit NOFAST) # renable c +RUN(NAME elemental_11 LABELS cpython llvm llvm_jit NOFAST) # renable c +RUN(NAME elemental_12 LABELS cpython llvm llvm_jit c NOFAST) +RUN(NAME elemental_13 LABELS cpython llvm llvm_jit c NOFAST) +RUN(NAME test_random LABELS cpython llvm llvm_jit NOFAST) +RUN(NAME test_random_02 LABELS cpython llvm llvm_jit NOFAST) +# RUN(NAME test_os LABELS cpython llvm llvm_jit NOFAST) # renable c # post sync +# RUN(NAME test_builtin LABELS cpython llvm llvm_jit) # renable c # post sync +RUN(NAME test_builtin_abs LABELS cpython llvm llvm_jit c) +# RUN(NAME test_builtin_bool LABELS cpython llvm llvm_jit c) +RUN(NAME test_builtin_pow LABELS cpython llvm llvm_jit c EXTRA_ARGS --no-warnings) +# RUN(NAME test_builtin_int LABELS cpython llvm llvm_jit c) +# RUN(NAME test_builtin_len LABELS cpython llvm llvm_jit c) +# RUN(NAME test_builtin_str LABELS cpython llvm llvm_jit c) +# RUN(NAME test_builtin_oct LABELS cpython llvm llvm_jit c) +# RUN(NAME test_builtin_hex LABELS cpython llvm llvm_jit c) +# RUN(NAME test_builtin_bin LABELS cpython llvm llvm_jit c) +RUN(NAME test_builtin_float LABELS cpython llvm llvm_jit c) +# RUN(NAME test_builtin_str_02 LABELS cpython llvm llvm_jit c NOFAST) +RUN(NAME test_builtin_round LABELS cpython llvm llvm_jit c) +RUN(NAME test_builtin_divmod LABELS cpython llvm llvm_jit c) +RUN(NAME test_builtin_sum LABELS cpython llvm llvm_jit c) +RUN(NAME test_math1 LABELS cpython llvm llvm_jit c) +RUN(NAME test_math_02 LABELS cpython llvm llvm_jit NOFAST) +RUN(NAME test_math_03 LABELS llvm llvm_jit) #1595: TODO: Test using CPython (3.11 recommended) +# RUN(NAME test_pass_compare LABELS cpython llvm llvm_jit) # renable c # post sync +RUN(NAME test_c_interop_01 LABELS cpython llvm llvm_jit c) +# RUN(NAME test_c_interop_02 LABELS cpython llvm c +# EXTRAFILES test_c_interop_02b.c) +# RUN(NAME test_c_interop_03 LABELS cpython llvm c + # EXTRAFILES test_c_interop_03b.c) +# RUN(NAME test_c_interop_04 LABELS cpython llvm llvm_jit c +# EXTRAFILES test_c_interop_04b.c) +# RUN(NAME test_c_interop_05 LABELS llvm c +# EXTRAFILES test_c_interop_05b.c) +# RUN(NAME bindc_03 LABELS llvm c +# EXTRAFILES bindc_03b.c) +# RUN(NAME bindc_05 LABELS llvm c +# EXTRAFILES bindc_05b.c) +# RUN(NAME bindc_06 LABELS llvm +# EXTRAFILES bindc_06b.c) # renable c +# RUN(NAME bindpy_01 LABELS cpython llvm_py c_py EXTRA_ARGS --enable-cpython NOFAST COPY_TO_BIN bindpy_01_module.py) +# RUN(NAME bindpy_02 LABELS cpython c_py EXTRA_ARGS --link-numpy COPY_TO_BIN bindpy_02_module.py) +# RUN(NAME bindpy_03 LABELS cpython c_py EXTRA_ARGS --link-numpy NOFAST COPY_TO_BIN bindpy_03_module.py) +# RUN(NAME bindpy_04 LABELS cpython c_py EXTRA_ARGS --link-numpy NOFAST COPY_TO_BIN bindpy_04_module.py) +# RUN(NAME bindpy_05 LABELS llvm_py c_py EXTRA_ARGS --enable-cpython COPY_TO_BIN bindpy_05_module.py REQ_PY_VER 3.10) +# RUN(NAME bindpy_06 LABELS cpython llvm_py EXTRA_ARGS --enable-cpython NOFAST COPY_TO_BIN bindpy_06_module.py REQ_PY_VER 3.10) +# RUN(NAME test_generics_01 LABELS cpython llvm llvm_jit NOFAST) # renable c # post sync +RUN(NAME test_cmath LABELS cpython llvm llvm_jit c NOFAST) +RUN(NAME test_complex_01 LABELS cpython llvm llvm_jit c wasm wasm_x64) +RUN(NAME test_complex_02 LABELS cpython llvm llvm_jit c) +RUN(NAME test_ConstantEllipsis LABLES cpython llvm llvm_jit c) +RUN(NAME test_max_min LABELS cpython llvm llvm_jit c) +RUN(NAME test_global LABELS cpython llvm llvm_jit) # renable c +RUN(NAME test_global_decl LABELS cpython llvm llvm_jit) # renable c +RUN(NAME test_ifexp_01 LABELS cpython llvm llvm_jit c) +RUN(NAME test_ifexp_02 LABELS cpython llvm llvm_jit c) +RUN(NAME test_ifexp_03 LABELS cpython llvm llvm_jit c) +RUN(NAME test_unary_op_01 LABELS cpython llvm llvm_jit c) # unary minus +RUN(NAME test_unary_op_02 LABELS cpython llvm llvm_jit c) # unary plus +RUN(NAME test_unary_op_03 LABELS cpython llvm llvm_jit c wasm) # unary bitinvert +RUN(NAME test_unary_op_04 LABELS cpython llvm llvm_jit c) # unary bitinvert +RUN(NAME test_unary_op_05 LABELS cpython llvm llvm_jit c) # unsigned unary minus, plus +RUN(NAME test_unary_op_06 LABELS cpython llvm llvm_jit c) # unsigned unary bitnot +RUN(NAME test_unsigned_01 LABELS cpython llvm llvm_jit c) # unsigned bitshift left, right +RUN(NAME test_unsigned_02 LABELS cpython llvm llvm_jit c) +RUN(NAME test_unsigned_03 LABELS cpython llvm llvm_jit c) +RUN(NAME test_bool_binop LABELS cpython llvm llvm_jit c) +RUN(NAME test_issue_518 LABELS cpython llvm llvm_jit c NOFAST) +RUN(NAME structs_01 LABELS cpython llvm llvm_jit c) +# RUN(NAME structs_02 LABELS cpython llvm llvm_jit c) +# RUN(NAME structs_02b LABELS cpython llvm llvm_jit c NOFAST) +# RUN(NAME structs_03 LABELS llvm llvm_jit c) +# RUN(NAME structs_04 LABELS cpython llvm llvm_jit c) +# RUN(NAME structs_05 LABELS cpython llvm llvm_jit c) +# RUN(NAME structs_06 LABELS cpython llvm llvm_jit c) +# RUN(NAME structs_07 LABELS llvm c +# EXTRAFILES structs_07b.c) +# RUN(NAME structs_08 LABELS cpython llvm llvm_jit c) +# RUN(NAME structs_09 LABELS cpython llvm llvm_jit c) +# RUN(NAME structs_10 LABELS cpython llvm llvm_jit c NOFAST) +# RUN(NAME structs_11 LABELS cpython llvm llvm_jit c) +RUN(NAME structs_12 LABELS cpython llvm llvm_jit c) +# RUN(NAME structs_13 LABELS llvm c +# EXTRAFILES structs_13b.c) +RUN(NAME structs_14 LABELS cpython llvm llvm_jit c) +# RUN(NAME structs_15 LABELS cpython llvm llvm_jit c) +# RUN(NAME structs_16 LABELS cpython llvm llvm_jit c) +# RUN(NAME structs_17 LABELS cpython llvm llvm_jit c) +# RUN(NAME structs_18 LABELS cpython llvm c +# EXTRAFILES structs_18b.c) +# RUN(NAME structs_19 LABELS cpython llvm c +# EXTRAFILES structs_19b.c) +# RUN(NAME structs_20 LABELS cpython llvm c +# EXTRAFILES structs_20b.c) +# RUN(NAME structs_21 LABELS cpython llvm llvm_jit c) +# RUN(NAME structs_22 LABELS cpython llvm llvm_jit c NOFAST) +RUN(NAME structs_23 LABELS cpython llvm llvm_jit c NOFAST) +# RUN(NAME structs_24 LABELS cpython llvm llvm_jit c) +# RUN(NAME structs_25 LABELS cpython llvm llvm_jit c) # post sync +RUN(NAME structs_26 LABELS cpython llvm llvm_jit) # renable c +RUN(NAME structs_27 LABELS cpython llvm llvm_jit) # renable c +RUN(NAME structs_28 LABELS cpython llvm llvm_jit) # renable c +# RUN(NAME structs_29 LABELS cpython llvm llvm_jit) +RUN(NAME structs_30 LABELS cpython llvm llvm_jit) # renable c +# RUN(NAME structs_31 LABELS cpython llvm llvm_jit c) +# RUN(NAME structs_32 LABELS cpython llvm llvm_jit c) +# RUN(NAME structs_33 LABELS cpython llvm llvm_jit c) +# RUN(NAME structs_34 LABELS cpython llvm llvm_jit c) +RUN(NAME structs_35 LABELS cpython llvm llvm_jit) + +# RUN(NAME symbolics_01 LABELS cpython_sym c_sym llvm_sym llvm_jit NOFAST EXTRA_ARGS --enable-symengine) +# RUN(NAME symbolics_02 LABELS cpython_sym c_sym llvm_sym llvm_jit NOFAST EXTRA_ARGS --enable-symengine) +# RUN(NAME symbolics_03 LABELS cpython_sym c_sym llvm_sym llvm_jit NOFAST EXTRA_ARGS --enable-symengine) +# RUN(NAME symbolics_04 LABELS cpython_sym c_sym llvm_sym llvm_jit NOFAST EXTRA_ARGS --enable-symengine) +# RUN(NAME symbolics_05 LABELS cpython_sym c_sym llvm_sym llvm_jit NOFAST EXTRA_ARGS --enable-symengine) +# RUN(NAME symbolics_06 LABELS cpython_sym c_sym llvm_sym llvm_jit NOFAST EXTRA_ARGS --enable-symengine) +# RUN(NAME symbolics_07 LABELS cpython_sym c_sym llvm_sym llvm_jit NOFAST EXTRA_ARGS --enable-symengine) +# RUN(NAME symbolics_08 LABELS cpython_sym llvm_sym llvm_jit EXTRA_ARGS --enable-symengine) # renable c_sym +# RUN(NAME symbolics_09 LABELS cpython_sym c_sym llvm_sym llvm_jit NOFAST EXTRA_ARGS --enable-symengine) +# RUN(NAME symbolics_10 LABELS cpython_sym c_sym llvm_sym NOFAST EXTRA_ARGS --enable-symengine) +# RUN(NAME symbolics_11 LABELS cpython_sym c_sym llvm_sym llvm_jit NOFAST EXTRA_ARGS --enable-symengine) +# RUN(NAME symbolics_12 LABELS cpython_sym c_sym llvm_sym llvm_jit NOFAST EXTRA_ARGS --enable-symengine) +# RUN(NAME symbolics_13 LABELS cpython_sym c_sym llvm_sym llvm_jit NOFAST EXTRA_ARGS --enable-symengine) +# RUN(NAME symbolics_14 LABELS cpython_sym c_sym llvm_sym llvm_jit NOFAST EXTRA_ARGS --enable-symengine) +# RUN(NAME test_gruntz LABELS cpython_sym c_sym llvm_sym NOFAST EXTRA_ARGS --enable-symengine) +# RUN(NAME symbolics_15 LABELS c_sym llvm_sym llvm_jit NOFAST EXTRA_ARGS --enable-symengine) +# RUN(NAME symbolics_16 LABELS cpython_sym c_sym llvm_sym llvm_jit NOFAST EXTRA_ARGS --enable-symengine) +# RUN(NAME symbolics_17 LABELS cpython_sym c_sym llvm_sym llvm_jit NOFAST EXTRA_ARGS --enable-symengine) +# RUN(NAME symbolics_18 LABELS cpython_sym c_sym llvm_sym llvm_jit NOFAST EXTRA_ARGS --enable-symengine) +# RUN(NAME gruntz_demo3 LABELS cpython_sym c_sym llvm_sym llvm_jit NOFAST EXTRA_ARGS --enable-symengine) + +# RUN(NAME sizeof_01 LABELS llvm c +# EXTRAFILES sizeof_01b.c) +# RUN(NAME sizeof_02 LABELS cpython llvm llvm_jit c) +# RUN(NAME enum_01 LABELS cpython llvm llvm_jit c NOFAST) +# RUN(NAME enum_02 LABELS cpython llvm llvm_jit NOFAST) +RUN(NAME enum_03 LABELS cpython llvm llvm_jit c NOFAST) +# RUN(NAME enum_04 LABELS cpython llvm llvm_jit c NOFAST) +# RUN(NAME enum_05 LABELS llvm c +# EXTRAFILES enum_05b.c NOFAST) +# RUN(NAME enum_06 LABELS cpython llvm llvm_jit c) +RUN(NAME enum_07 IMPORT_PATH .. + LABELS cpython llvm llvm_jit c NOFAST) +RUN(NAME union_01 LABELS cpython llvm llvm_jit c) +# RUN(NAME union_02 LABELS cpython llvm llvm_jit c NOFAST) +RUN(NAME union_03 LABELS cpython llvm llvm_jit c) +RUN(NAME union_04 IMPORT_PATH .. + LABELS cpython llvm llvm_jit c) +# RUN(NAME test_str_to_int LABELS cpython llvm llvm_jit c) +# RUN(NAME test_platform LABELS cpython llvm llvm_jit) # renable c +RUN(NAME test_vars_01 LABELS cpython llvm llvm_jit) +# RUN(NAME test_version LABELS cpython llvm llvm_jit) # post sync +RUN(NAME logical_binop1 LABELS cpython llvm llvm_jit) +# RUN(NAME test_logical_compare LABELS cpython llvm llvm_jit) # TODO: Add C backend after fixing issue #2708 +# RUN(NAME test_logical_assignment LABELS cpython llvm llvm_jit) # TODO: Add C backend after fixing issue #2708 +RUN(NAME vec_01 LABELS cpython llvm llvm_jit c NOFAST) +# RUN(NAME test_str_comparison LABELS cpython llvm llvm_jit c wasm) +RUN(NAME test_bit_length LABELS cpython) # renable c, FIXME: This test fails on llvm & llvm_jit +# RUN(NAME str_to_list_cast LABELS cpython llvm llvm_jit c) +# RUN(NAME cast_01 LABELS cpython llvm llvm_jit c) +# RUN(NAME cast_02 LABELS cpython llvm llvm_jit c) +# RUN(NAME test_sys_01 LABELS cpython llvm llvm_jit c NOFAST) +# RUN(NAME intent_01 LABELS cpython llvm llvm_jit) + + +# RUN(NAME test_package_01 LABELS cpython llvm llvm_jit NOFAST) +# RUN(NAME test_pkg_lpdraw LABELS cpython llvm llvm_jit wasm) +# RUN(NAME test_pkg_lnn_01 LABELS cpython llvm llvm_jit NOFAST) +# RUN(NAME test_pkg_lnn_02 LABELS cpython llvm llvm_jit NOFAST) +# RUN(NAME test_pkg_lpconvexhull LABELS cpython llvm llvm_jit c NOFAST) + +# RUN(NAME generics_01 LABELS cpython llvm llvm_jit) # renable c # post sync +# RUN(NAME generics_02 LABELS cpython llvm llvm_jit c) +# RUN(NAME generics_array_01 LABELS cpython llvm llvm_jit c) +# RUN(NAME generics_array_02 LABELS cpython llvm llvm_jit c) +# RUN(NAME generics_array_03 LABELS cpython llvm llvm_jit c) +# RUN(NAME generics_list_01 LABELS cpython llvm llvm_jit) # renable c # post sync +RUN(NAME test_statistics_01 LABELS cpython llvm llvm_jit NOFAST) +RUN(NAME test_statistics_02 LABELS cpython llvm llvm_jit NOFAST REQ_PY_VER 3.10) +# RUN(NAME test_attributes LABELS cpython llvm llvm_jit) +# RUN(NAME test_str_attributes LABELS cpython llvm llvm_jit c) +RUN(NAME kwargs_01 LABELS cpython llvm llvm_jit NOFAST) # renable c # post sync +RUN(NAME def_func_01 LABELS cpython llvm llvm_jit) # renable c # post sync + +RUN(NAME func_inline_01 LABELS llvm llvm_jit c wasm) +RUN(NAME func_inline_02 LABELS cpython llvm llvm_jit c) +RUN(NAME func_static_01 LABELS cpython llvm llvm_jit c wasm) +RUN(NAME func_static_02 LABELS cpython llvm llvm_jit c wasm) +RUN(NAME func_dep_03 LABELS cpython llvm llvm_jit c) +RUN(NAME func_dep_04 LABELS cpython llvm llvm_jit c) +RUN(NAME func_internal_def_01 LABELS cpython llvm llvm_jit NOFAST) +RUN(NAME func_01 LABELS cpython llvm llvm_jit) +RUN(NAME func_02 LABELS c_sym llvm_sym llvm_jit NOFAST EXTRA_ARGS --enable-symengine) + +RUN(NAME float_01 LABELS cpython llvm llvm_jit c wasm wasm_x64) +RUN(NAME recursive_01 LABELS cpython llvm llvm_jit c wasm wasm_x64 wasm_x86) +RUN(NAME comp_01 LABELS cpython llvm llvm_jit c wasm wasm_x64) +RUN(NAME bit_operations_i32 LABELS cpython llvm llvm_jit c wasm wasm_x64) +RUN(NAME bit_operations_i64 LABELS cpython llvm llvm_jit c wasm) + +# RUN(NAME test_argv_01 LABELS cpython llvm NOFAST) +RUN(NAME global_syms_01 LABELS cpython llvm llvm_jit c) +RUN(NAME global_syms_02 LABELS cpython llvm llvm_jit c) +# RUN(NAME global_syms_03_b LABELS cpython llvm llvm_jit c) +# RUN(NAME global_syms_03_c LABELS cpython llvm llvm_jit c) +# RUN(NAME global_syms_04 LABELS cpython llvm llvm_jit c wasm wasm_x64) +RUN(NAME global_syms_05 LABELS cpython llvm llvm_jit c) +RUN(NAME global_syms_06 LABELS cpython llvm llvm_jit c) + +RUN(NAME callback_01 LABELS cpython llvm llvm_jit c) +RUN(NAME callback_02 LABELS cpython llvm llvm_jit c) +RUN(NAME callback_03 LABELS cpython llvm llvm_jit c) + +RUN(NAME lambda_01 LABELS cpython llvm llvm_jit) + +RUN(NAME c_mangling LABELS cpython llvm llvm_jit) # renable c +# RUN(NAME class_01 LABELS cpython llvm llvm_jit) +# RUN(NAME class_02 LABELS cpython llvm llvm_jit) +# RUN(NAME class_03 LABELS cpython llvm llvm_jit) +# RUN(NAME class_04 LABELS cpython llvm llvm_jit) +# RUN(NAME class_05 LABELS cpython llvm llvm_jit) +# RUN(NAME class_06 LABELS cpython llvm llvm_jit) + + +# callback_04 is to test emulation. So just run with cpython +RUN(NAME callback_04 IMPORT_PATH .. LABELS cpython) + +# Intrinsic Functions +RUN(NAME intrinsics_01 LABELS cpython llvm llvm_jit NOFAST) # any +RUN(NAME intrinsics_02 LABELS cpython llvm llvm_jit c) # floordiv +# RUN(NAME test_builtin_type LABELS cpython llvm llvm_jit c) # type +# RUN(NAME test_builtin_type_set LABELS cpython llvm llvm_jit) # type (specifically for `set`) + +# lpython decorator +# RUN(NAME lpython_decorator_01 LABELS cpython) +# RUN(NAME lpython_decorator_02 LABELS cpython) + +COMPILE(NAME import_order_01 LABELS cpython llvm llvm_jit c) # any + +# LPython emulation mode +RUN(NAME lpython_emulation_01 LABELS cpython NOMOD) diff --git a/integration_tests/array_01.py b/integration_tests/array_01.py index 779b3934e1..c492d6b31c 100644 --- a/integration_tests/array_01.py +++ b/integration_tests/array_01.py @@ -1,9 +1,9 @@ -from ltypes import i32 -from numpy import empty +from lpython import i32 +from numpy import empty, int32 def main0(): Nx: i32 = 600; Ny: i32 = 450 - arr: i32[450, 600] = empty([Ny, Nx]) + arr: i32[450, 600] = empty([450, 600], dtype=int32) i: i32 j: i32 for i in range(Ny): diff --git a/integration_tests/array_01_decl.py b/integration_tests/array_01_decl.py index 52812a030a..153f7c9557 100644 --- a/integration_tests/array_01_decl.py +++ b/integration_tests/array_01_decl.py @@ -1,4 +1,4 @@ -from ltypes import i16, i32, i64, f32, f64, c32, c64 +from lpython import i16, i32, i64, f32, f64, c32, c64 from numpy import empty, int16, int32, int64, float32, float64, complex64, complex128 from enum import Enum diff --git a/integration_tests/array_02.py b/integration_tests/array_02.py index 6e3c7bca7d..6c9c2ea5c2 100644 --- a/integration_tests/array_02.py +++ b/integration_tests/array_02.py @@ -1,9 +1,9 @@ -from ltypes import i32 -from numpy import empty +from lpython import i32 +from numpy import empty, int32 def main0(): Nx: i32 = 60; Ny: i32 = 45; Nz: i32 = 20 - arr: i32[45, 60, 20] = empty([Ny, Nx, Nz]) + arr: i32[45, 60, 20] = empty([45, 60, 20], dtype=int32) i: i32 j: i32 k: i32 diff --git a/integration_tests/array_02_decl.py b/integration_tests/array_02_decl.py index 5969ba8a85..1f5c07d76c 100644 --- a/integration_tests/array_02_decl.py +++ b/integration_tests/array_02_decl.py @@ -1,5 +1,5 @@ -from ltypes import i32, i64, f32, f64, c32, c64 -from numpy import empty +from lpython import i32, i64, f32, f64, c32, c64 +from numpy import empty, int32, int64, float32, float64, complex64, complex128 def accept_multidim_i32_array(xi32: i32[:, :]) -> i32: return xi32[0, 0] @@ -14,12 +14,12 @@ def accept_multidim_f64_array(xf64: f64[:, :]) -> f64: return xf64[0, 1] def declare_arrays(): - ai32: i32[3, 3] = empty([3, 3]) - ai64: i64[10, 10, 10] = empty([10, 10, 10]) - af32: f32[3] = empty(3) - af64: f64[10, 4] = empty([10, 4]) - ac32: c32[3, 5, 99] = empty([3, 5, 99]) - ac64: c64[10, 13, 11, 16] = empty([10, 13, 11, 16]) + ai32: i32[3, 3] = empty([3, 3], dtype=int32) + ai64: i64[10, 10, 10] = empty([10, 10, 10], dtype=int64) + af32: f32[3] = empty(3, dtype=float32) + af64: f64[10, 4] = empty([10, 4], dtype=float64) + ac32: c32[3, 5, 99] = empty([3, 5, 99], dtype=complex64) + ac64: c64[10, 13, 11, 16] = empty([10, 13, 11, 16], dtype=complex128) print(accept_multidim_i32_array(ai32)) print(accept_multidim_i64_array(ai64)) print(accept_multidim_f32_array(af32)) diff --git a/integration_tests/array_03.py b/integration_tests/array_03.py new file mode 100644 index 0000000000..975fe4aea6 --- /dev/null +++ b/integration_tests/array_03.py @@ -0,0 +1,20 @@ +from lpython import Allocatable, f64, i32 +from numpy import empty, float64, int32 + +def f(): + n: i32 = 5 + a: Allocatable[f64[:]] = empty((n,), dtype=float64) + i: i32 + for i in range(n): + a[i] = f64(i+1) + for i in range(n): + assert abs(a[i] - f64(i + 1)) < 1e-12 + b: Allocatable[i32[:]] + n = 10 + b = empty((n,), dtype=int32) + for i in range(n): + b[i] = i+1 + for i in range(n): + assert b[i] == i+1 + +f() diff --git a/integration_tests/array_03_decl.py b/integration_tests/array_03_decl.py index 7b38806fc4..9fb02782ca 100644 --- a/integration_tests/array_03_decl.py +++ b/integration_tests/array_03_decl.py @@ -1,4 +1,4 @@ -from ltypes import i32, f64, dataclass +from lpython import i32, f64, dataclass from numpy import empty @dataclass @@ -12,8 +12,8 @@ class Truck: wheels: i32 def declare_struct_array(): - cars: Car[1] = empty(10, dtype=Car) - trucks: Truck[2] = empty(20, dtype=Truck) + cars: Car[1] = empty(1, dtype=Car) + trucks: Truck[2] = empty(2, dtype=Truck) cars[0] = Car(100000, 800.0) trucks[0] = Truck(1000000, 8) trucks[1] = Truck(5000000, 12) diff --git a/integration_tests/array_04.py b/integration_tests/array_04.py new file mode 100644 index 0000000000..c7cd24ae4a --- /dev/null +++ b/integration_tests/array_04.py @@ -0,0 +1,19 @@ +from lpython import i32, Const +from numpy import empty, int32 + +def main0(): + n: Const[i32] = 1 + x: i32[n, n] = empty([n, n], dtype=int32) + y: i32[n, n] = empty([n, n], dtype=int32) + + x[0, 0] = -10 + y[0, 0] = -10 + + print(x[0, 0], y[0, 0]) + assert x == y + + y[0, 0] = 10 + print(x[0, 0], y[0, 0]) + assert x != y + +main0() diff --git a/integration_tests/array_05.py b/integration_tests/array_05.py new file mode 100644 index 0000000000..4c18576cac --- /dev/null +++ b/integration_tests/array_05.py @@ -0,0 +1,39 @@ +from lpython import i32, f64, Array +from numpy import empty, int32, float64 + + +def test_1(): + y: Array[f64, 3] = empty([3], dtype=float64) + y[0] = 3.14 + y[1] = -4.14 + y[2] = 100.100 + + print(y) + assert abs(y[0] - (3.14)) <= 1e-6 + assert abs(y[1] - (-4.14)) <= 1e-6 + assert abs(y[2] - (100.100)) <= 1e-6 + +def test_2(): + x: Array[i32, 2, 3] = empty([2, 3], dtype=int32) + + x[0, 0] = 5 + x[0, 1] = -10 + x[0, 2] = 15 + x[1, 0] = 4 + x[1, 1] = -14 + x[1, 2] = 100 + + print(x) + assert x[0, 0] == 5 + assert x[0, 1] == -10 + assert x[0, 2] == 15 + assert x[1, 0] == 4 + assert x[1, 1] == -14 + assert x[1, 2] == 100 + + +def main0(): + test_1() + test_2() + +main0() diff --git a/integration_tests/array_06.py b/integration_tests/array_06.py new file mode 100644 index 0000000000..b44d4ed347 --- /dev/null +++ b/integration_tests/array_06.py @@ -0,0 +1,19 @@ +from numpy import empty, int16 +from lpython import i16, i32, Const + +def spot_print_lpython_array(a: i16[:,:]) -> None: + print(a) + +def main() -> i32: + n : Const[i32] = 15 + m : Const[i32] = 3 + Anm: i16[n, m] = empty((n,m), dtype=int16) + i: i32; j: i32 + for i in range(n): + for j in range(m): + Anm[i,j] = i16(5) + spot_print_lpython_array(Anm) + return 0 + +if __name__ == "__main__": + main() diff --git a/integration_tests/array_expr_01.py b/integration_tests/array_expr_01.py index 8890fd621f..0136710c93 100644 --- a/integration_tests/array_expr_01.py +++ b/integration_tests/array_expr_01.py @@ -1,22 +1,18 @@ -from ltypes import i32, f32, f64 +from lpython import Const, i32, f32, f64 from numpy import empty, reshape, int32, float64 def array_expr_01(): - dim1: i32 - dim2: i32 - dim3: i32 - dim1d: i32 + dim1: Const[i32] = 10 + dim2: Const[i32] = 10 + dim3: Const[i32] = 5 + dim1d: Const[i32] = dim1 * dim2 * dim3 + i: i32 shape1d: i32[1] = empty(1, dtype=int32) shape3d: i32[3] = empty(3, dtype=int32) eps: f64 eps = 1e-12 - dim1 = 10 - dim2 = 10 - dim3 = 5 - dim1d = dim1 * dim2 * dim3 - e: f64[10, 10, 5] = empty((dim1, dim2, dim3), dtype=float64) f: f64[10, 10, 5] = empty((dim1, dim2, dim3), dtype=float64) g: f64[500] = empty(dim1d, dtype=float64) diff --git a/integration_tests/array_expr_02.py b/integration_tests/array_expr_02.py index 332a223653..28fbe6b38a 100644 --- a/integration_tests/array_expr_02.py +++ b/integration_tests/array_expr_02.py @@ -1,7 +1,6 @@ -from ltypes import i32, f32, TypeVar +from lpython import i32, f32, TypeVar from numpy import empty, sqrt, float32 -n: i32 n = TypeVar("n") def modify(array_a: f32[:], n: i32) -> f32[n]: diff --git a/integration_tests/array_expr_03.py b/integration_tests/array_expr_03.py new file mode 100644 index 0000000000..f0af73a57b --- /dev/null +++ b/integration_tests/array_expr_03.py @@ -0,0 +1,24 @@ +from lpython import i8, i32, dataclass, field +from numpy import empty, int8, array + + +@dataclass +class LPBHV_small: + dim: i32 = 4 + a: i8[4] = field(default_factory=lambda: empty(4, dtype=int8)) + + +def g(): + l2: LPBHV_small = LPBHV_small(4, array([127, -127, 3, 111], dtype=int8)) + + print(l2.dim) + assert l2.dim == 4 + + print(l2.a[0], l2.a[1], l2.a[2], l2.a[3]) + assert l2.a[0] == i8(127) + assert l2.a[1] == i8(-127) + assert l2.a[2] == i8(3) + assert l2.a[3] == i8(111) + + +g() diff --git a/integration_tests/array_expr_04.py b/integration_tests/array_expr_04.py new file mode 100644 index 0000000000..c14e4cc988 --- /dev/null +++ b/integration_tests/array_expr_04.py @@ -0,0 +1,35 @@ +from lpython import i8, i16, i32, i64 +from numpy import int8, int16, int32, int64, array + +def g(): + a8: i8[4] = array([127, -127, 3, 111], dtype=int8) + a16: i16[4] = array([127, -127, 3, 111], dtype=int16) + a32: i32[4] = array([127, -127, 3, 111], dtype=int32) + a64: i64[4] = array([127, -127, 3, 111], dtype=int64) + + print(a8) + print(a16) + print(a32) + print(a64) + + assert (a8[0] == i8(127)) + assert (a8[1] == i8(-127)) + assert (a8[2] == i8(3)) + assert (a8[3] == i8(111)) + + assert (a16[0] == i16(127)) + assert (a16[1] == i16(-127)) + assert (a16[2] == i16(3)) + assert (a16[3] == i16(111)) + + assert (a32[0] == i32(127)) + assert (a32[1] == i32(-127)) + assert (a32[2] == i32(3)) + assert (a32[3] == i32(111)) + + assert (a64[0] == i64(127)) + assert (a64[1] == i64(-127)) + assert (a64[2] == i64(3)) + assert (a64[3] == i64(111)) + +g() diff --git a/integration_tests/array_expr_05.py b/integration_tests/array_expr_05.py new file mode 100644 index 0000000000..7a7beeb1ae --- /dev/null +++ b/integration_tests/array_expr_05.py @@ -0,0 +1,31 @@ +from lpython import u8, u16, u32, u64, i8 +from numpy import uint8, uint16, uint32, uint64, array + +def g(): + a8: u8[3] = array([127, 3, 111], dtype=uint8) + a16: u16[3] = array([127, 3, 111], dtype=uint16) + a32: u32[3] = array([127, 3, 111], dtype=uint32) + a64: u64[3] = array([127, 3, 111], dtype=uint64) + + assert (a8[0] == u8(127)) + assert (a8[1] == u8(3)) + assert (a8[2] == u8(111)) + + assert (a16[0] == u16(127)) + assert (a16[1] == u16(3)) + assert (a16[2] == u16(111)) + + assert (a32[0] == u32(127)) + assert (a32[1] == u32(3)) + assert (a32[2] == u32(111)) + + assert (a64[0] == u64(127)) + assert (a64[1] == u64(3)) + assert (a64[2] == u64(111)) + + print(a8) + print(a16) + print(a32) + print(a64) + +g() diff --git a/integration_tests/array_expr_06.py b/integration_tests/array_expr_06.py new file mode 100644 index 0000000000..b6dc397d87 --- /dev/null +++ b/integration_tests/array_expr_06.py @@ -0,0 +1,21 @@ +from lpython import f32, f64 +from numpy import float32, float64, array + +def g(): + a32: f32[4] = array([127, -127, 3, 111], dtype=float32) + a64: f64[4] = array([127, -127, 3, 111], dtype=float64) + + print(a32) + print(a64) + + assert (abs(a32[0] - f32(127)) <= f32(1e-5)) + assert (abs(a32[1] - f32(-127)) <= f32(1e-5)) + assert (abs(a32[2] - f32(3)) <= f32(1e-5)) + assert (abs(a32[3] - f32(111)) <= f32(1e-5)) + + assert (abs(a64[0] - f64(127)) <= 1e-5) + assert (abs(a64[1] - f64(-127)) <= 1e-5) + assert (abs(a64[2] - f64(3)) <= 1e-5) + assert (abs(a64[3] - f64(111)) <= 1e-5) + +g() diff --git a/integration_tests/array_expr_07.py b/integration_tests/array_expr_07.py new file mode 100644 index 0000000000..598a7fcb64 --- /dev/null +++ b/integration_tests/array_expr_07.py @@ -0,0 +1,21 @@ +from lpython import c32, c64, f32 +from numpy import complex64, complex128, array + +def g(): + a32: c32[4] = array([127, -127, 3, 111], dtype=complex64) + a64: c64[4] = array([127, -127, 3, 111], dtype=complex128) + + print(a32) + print(a64) + + assert (abs(a32[0] - c32(127)) <= f32(1e-5)) + assert (abs(a32[1] - c32(-127)) <= f32(1e-5)) + assert (abs(a32[2] - c32(3)) <= f32(1e-5)) + assert (abs(a32[3] - c32(111)) <= f32(1e-5)) + + assert (abs(a64[0] - c64(127)) <= 1e-5) + assert (abs(a64[1] - c64(-127)) <= 1e-5) + assert (abs(a64[2] - c64(3)) <= 1e-5) + assert (abs(a64[3] - c64(111)) <= 1e-5) + +g() diff --git a/integration_tests/array_expr_08.py b/integration_tests/array_expr_08.py new file mode 100644 index 0000000000..ba0cf0dcb7 --- /dev/null +++ b/integration_tests/array_expr_08.py @@ -0,0 +1,14 @@ +from lpython import i1 +from numpy import bool_, array + +def g(): + a1: i1[4] = array([0, -127, 0, 111], dtype=bool_) + + print(a1) + + assert not a1[0] + assert a1[1] + assert not a1[2] + assert a1[3] + +g() diff --git a/integration_tests/array_expr_09.py b/integration_tests/array_expr_09.py new file mode 100644 index 0000000000..3590f65ca3 --- /dev/null +++ b/integration_tests/array_expr_09.py @@ -0,0 +1,23 @@ +from lpython import (i32, Const) +from numpy import empty, int32 + +dim: Const[i32] = 2 +dim2: Const[i32] = 3 + +def g(): + a: i32[dim, dim2] = empty((dim, dim2), dtype=int32) + i1: i32 = 0 + i2: i32 = 0 + for i1 in range(dim): + for i2 in range(dim2): + a[i1, i2] = i32(i1 * dim2 + i2) + # a: [[0, 1, 2], [3, 4, 5]] + print(a) + assert a[-1, -1] == 5 + assert a[-1, -2] == 4 + assert a[-1, -3] == 3 + assert a[-2, -1] == 2 + assert a[-2, -2] == 1 + assert a[-2, -3] == 0 + +g() \ No newline at end of file diff --git a/integration_tests/array_expr_10.py b/integration_tests/array_expr_10.py new file mode 100644 index 0000000000..3681702818 --- /dev/null +++ b/integration_tests/array_expr_10.py @@ -0,0 +1,17 @@ +from lpython import i32 +from numpy import empty, int32, array + +def foo(x: i32[:]): + print(x[3], x[4], x[-1], x[-2]) + assert x[-1] == 5 + assert x[-2] == 4 + assert x[-3] == 3 + assert x[-4] == 2 + assert x[-5] == 1 + +def main(): + x: i32[5] = empty(5, dtype=int32) + x = array([1, 2, 3, 4, 5]) + foo(x) + +main() \ No newline at end of file diff --git a/integration_tests/array_size_01.py b/integration_tests/array_size_01.py new file mode 100644 index 0000000000..17135ee098 --- /dev/null +++ b/integration_tests/array_size_01.py @@ -0,0 +1,23 @@ +from lpython import i32, f64, c32, c64 +from numpy import empty, int32, float64, complex64, complex128 + +def main0(): + x: i32[4, 5, 2] = empty([4, 5, 2], dtype=int32) + y: f64[24, 100, 2, 5] = empty([24, 100, 2, 5], dtype=float64) + print(x.size) + print(y.size) + + assert x.size == 40 + assert y.size == 24000 + +def main1(): + a: c32[12] = empty([12], dtype=complex64) + b: c64[15, 15, 10] = empty([15, 15, 10], dtype=complex128) + print(a.size) + print(b.size) + + assert a.size == 12 + assert b.size == 2250 + +main0() +main1() diff --git a/integration_tests/array_size_02.py b/integration_tests/array_size_02.py new file mode 100644 index 0000000000..1d238926fd --- /dev/null +++ b/integration_tests/array_size_02.py @@ -0,0 +1,90 @@ +from lpython import i32, f64, c32, c64, u32, u64 +from numpy import empty, size, int32, uint32, uint64, float64, complex64, complex128 + +def main0(): + x: i32[4, 5, 2] = empty([4, 5, 2], dtype=int32) + y: f64[24, 100, 2, 5] = empty([24, 100, 2, 5], dtype=float64) + z: i32 + w: i32 + z = 2 + w = 3 + print(size(x)) + print(size(x, 0)) + print(size(x, 1)) + print(size(x, 2)) + print(size(y)) + print(size(y, 0)) + print(size(y, 1)) + print(size(y, z)) + print(size(y, w)) + + assert size(x) == 40 + assert size(x, 0) == 4 + assert size(x, 1) == 5 + assert size(x, 2) == 2 + assert size(y) == 24000 + assert size(y, 0) == 24 + assert size(y, 1) == 100 + assert size(y, z) == 2 + assert size(y, w) == 5 + +def main1(): + a: c32[12] = empty([12], dtype=complex64) + b: c64[15, 15, 10] = empty([15, 15, 10], dtype=complex128) + c: i32 + d: i32 + c = 1 + d = 2 + print(size(a)) + print(size(a, 0)) + print(size(b)) + print(size(b, 0)) + print(size(b, c)) + print(size(b, d)) + + assert size(a) == 12 + assert size(a, 0) == 12 + assert size(b) == 2250 + assert size(b, 0) == 15 + assert size(b, c) == 15 + assert size(b, d) == 10 + +def main2(): + a: i32[2, 3] = empty([2, 3], dtype=int32) + print(size(a)) + print(size(a, 0)) + print(size(a, 1)) + + assert size(a) == 2*3 + assert size(a, 0) == 2 + assert size(a, 1) == 3 + +def main3(): + a: u32[2, 3, 4] = empty([2, 3, 4], dtype=uint32) + b: u64[10, 5] = empty([10, 5], dtype=uint64) + c: i32 + d: i32 + c = 1 + d = 2 + print(size(a)) + print(size(a, 0)) + print(size(a, c)) + print(size(a, d)) + + print(size(b)) + print(size(b, 0)) + print(size(b, c)) + + assert size(a) == 2*3*4 + assert size(a, 0) == 2 + assert size(a, c) == 3 + assert size(a, d) == 4 + + assert size(b) == 50 + assert size(b, 0) == 10 + assert size(b, c) == 5 + +main0() +main1() +main2() +main3() diff --git a/integration_tests/bindc_01.py b/integration_tests/bindc_01.py index 5c758339e5..6b83811264 100644 --- a/integration_tests/bindc_01.py +++ b/integration_tests/bindc_01.py @@ -1,5 +1,14 @@ -from ltypes import c_p_pointer, CPtr, i16, Pointer, empty_c_void_p +from lpython import c_p_pointer, CPtr, i16, Pointer, empty_c_void_p queries: CPtr = empty_c_void_p() x: Pointer[i16] = c_p_pointer(queries, i16) print(queries, x) + + +def test_issue_1781(): + p: CPtr = empty_c_void_p() + assert p == empty_c_void_p() + assert not (p != empty_c_void_p()) + + +test_issue_1781() diff --git a/integration_tests/bindc_02.py b/integration_tests/bindc_02.py index 0ad7845489..58f0ad1290 100644 --- a/integration_tests/bindc_02.py +++ b/integration_tests/bindc_02.py @@ -1,8 +1,8 @@ -from ltypes import c_p_pointer, CPtr, pointer, i16, Pointer, empty_c_void_p -from numpy import empty, int16 +from lpython import c_p_pointer, CPtr, pointer, i16, Pointer, empty_c_void_p +from numpy import empty, int16, array queries: CPtr = empty_c_void_p() -x: Pointer[i16[:]] = c_p_pointer(queries, i16[:]) +x: Pointer[i16[:]] = c_p_pointer(queries, i16[:], array([1])) print(queries, x) def f(): @@ -17,8 +17,8 @@ def f(): assert yptr1[0] == i16(1) assert yptr1[1] == i16(2) - yptr1 = c_p_pointer(yq, i16[:]) + yptr1 = c_p_pointer(yq, i16[:], array([2])) - print(yq, yptr1) + # print(yq, yptr1) f() diff --git a/integration_tests/bindc_03.py b/integration_tests/bindc_03.py index 1138522b09..59b1f0efbc 100644 --- a/integration_tests/bindc_03.py +++ b/integration_tests/bindc_03.py @@ -1,17 +1,21 @@ -from ltypes import c_p_pointer, CPtr, pointer, i32, Pointer, ccall, p_c_pointer, dataclass +from lpython import (c_p_pointer, CPtr, pointer, i32, + Pointer, ccall, p_c_pointer, dataclass, + ccallable, empty_c_void_p, cptr_to_u64, + u64_to_cptr, u64) +from numpy import array @dataclass class ArrayWrapped: array: CPtr -@ccall +@ccall(header="bindc_03b.h") def g(a: CPtr, value: i32, offset_value: bool) -> None: pass def gpy(a: CPtr, value: i32, offset_value: bool) -> None: g(a, value, offset_value) -@ccall +@ccall(header="bindc_03b.h") def get_array(size: i32) -> CPtr: pass @@ -19,7 +23,7 @@ def get_array(size: i32) -> CPtr: def f(q_void: CPtr) -> None: i: i32 el: i32 - q: Pointer[i32[:]] = c_p_pointer(q_void, i32[:]) + q: Pointer[i32[:]] = c_p_pointer(q_void, i32[:], array([10])) for i in range(10): q2: CPtr p_c_pointer(pointer(q[i]), q2) @@ -32,23 +36,38 @@ def f(q_void: CPtr) -> None: def h(q_void: CPtr) -> None: i: i32 el: i32 - q: Pointer[i32[:]] = c_p_pointer(q_void, i32[:]) + q: Pointer[i32[:]] = c_p_pointer(q_void, i32[:], array([10])) for i in range(10): # TODO: Use q[i] directly in the assert. el = q[i] print(el) assert el == i * i + i%2 + +@ccallable(header="_test_bindc_03_my_header.h") +def test_emit_header_ccallable() -> i32: + i: i32 = 5 + assert i == 5 + i = i*5 + return i + 10 + def run(): a: CPtr array_wrapped: ArrayWrapped = ArrayWrapped(a) - array_wrapped1: ArrayWrapped + array_wrapped1: ArrayWrapped = ArrayWrapped() size: i32 size = 10 a = get_array(size) + assert a != empty_c_void_p() array_wrapped.array = a f(array_wrapped.array) + q: u64 = cptr_to_u64(a) + x: CPtr + x = u64_to_cptr(q) + array_wrapped.array = x + f(array_wrapped.array) array_wrapped1 = array_wrapped h(array_wrapped1.array) + assert test_emit_header_ccallable() == 35 run() diff --git a/integration_tests/bindc_04.py b/integration_tests/bindc_04.py index 1956c68c8c..0589fcee66 100644 --- a/integration_tests/bindc_04.py +++ b/integration_tests/bindc_04.py @@ -1,4 +1,4 @@ -from ltypes import pointer, i16, Pointer +from lpython import pointer, i16, Pointer # Testing Global Pointers x: Pointer[i16[:]] diff --git a/integration_tests/bindc_05.py b/integration_tests/bindc_05.py index ee936ab364..b01ceee8ba 100644 --- a/integration_tests/bindc_05.py +++ b/integration_tests/bindc_05.py @@ -1,14 +1,14 @@ -from ltypes import CPtr, empty_c_void_p, i32, f32, dataclass, Pointer, ccall, p_c_pointer, pointer +from lpython import CPtr, empty_c_void_p, i32, f32, dataclass, Pointer, ccall, p_c_pointer, pointer @dataclass class Void: data: CPtr -@ccall +@ccall(header="bindc_05b.h") def trunc_custom(value: Pointer[CPtr]) -> CPtr: pass -@ccall +@ccall(header="bindc_05b.h") def print_value(value: CPtr): pass diff --git a/integration_tests/bindc_05b.h b/integration_tests/bindc_05b.h index b4533c4320..95d372053c 100644 --- a/integration_tests/bindc_05b.h +++ b/integration_tests/bindc_05b.h @@ -1,2 +1,7 @@ +#ifndef BINDC_05BH +#define BINDC_05BH + void* trunc_custom(void** value); void print_value(float* value); + +#endif // BINDC_05BH diff --git a/integration_tests/bindc_06.py b/integration_tests/bindc_06.py index a80e1b5c4a..d01ca9b800 100644 --- a/integration_tests/bindc_06.py +++ b/integration_tests/bindc_06.py @@ -1,4 +1,4 @@ -from ltypes import i32, f64, ccall, dataclass +from lpython import i32, f64, ccall, dataclass from numpy import empty, int32, float64 @dataclass @@ -6,7 +6,7 @@ class CompareOperator: op_code: i32 op_name: str -@ccall +@ccall(header="bindc_06b.h") def compare_array_element(value1: i32, value2: f64, op: i32) -> i32: pass diff --git a/integration_tests/bindc_06b.h b/integration_tests/bindc_06b.h index 0e5fac7de4..680d387c7f 100644 --- a/integration_tests/bindc_06b.h +++ b/integration_tests/bindc_06b.h @@ -1,3 +1,8 @@ +#ifndef BINDC_06BH +#define BINDC_06BH + #include int32_t compare_array_element(int32_t value1, double value2, int32_t code); + +#endif // BINDC_06BH diff --git a/integration_tests/bindc_07.py b/integration_tests/bindc_07.py index 038a2d659b..f03af3331b 100644 --- a/integration_tests/bindc_07.py +++ b/integration_tests/bindc_07.py @@ -1,24 +1,37 @@ -from ltypes import CPtr, i64, sizeof, i32, i16, i8, ccall, c_p_pointer, empty_c_void_p, Pointer, pointer -from numpy import empty, int64 +from lpython import (CPtr, sizeof, ccall, c_p_pointer, empty_c_void_p, + i64, i32, i16, i8, + u64, u32, u16, u8, + Pointer, pointer, u16) +from numpy import array @ccall def _lfortran_malloc(size: i32) -> CPtr: pass -def allocate_memory(size: i32) -> tuple[CPtr, CPtr, CPtr, CPtr]: +def allocate_memory(size: i32) -> tuple[CPtr, CPtr, CPtr, CPtr, \ + CPtr, CPtr, CPtr, CPtr]: array1: CPtr = _lfortran_malloc(size * i32(sizeof(i8))) array2: CPtr = _lfortran_malloc(size * i32(sizeof(i16))) array3: CPtr = _lfortran_malloc(size * i32(sizeof(i32))) array4: CPtr = _lfortran_malloc(size * i32(sizeof(i64))) - return array1, array2, array3, array4 + array5: CPtr = _lfortran_malloc(size * i32(sizeof(u8))) + array6: CPtr = _lfortran_malloc(size * i32(sizeof(u16))) + array7: CPtr = _lfortran_malloc(size * i32(sizeof(u32))) + array8: CPtr = _lfortran_malloc(size * i32(sizeof(u64))) + return array1, array2, array3, array4, array5, array6, array7, array8 -def sum_arrays(array1: CPtr, array2: CPtr, array3: CPtr, array4: CPtr, size: i32): - iarray1: Pointer[i8[size]] = c_p_pointer(array1, i8[size]) - iarray2: Pointer[i16[size]] = c_p_pointer(array2, i16[size]) - iarray3: Pointer[i32[size]] = c_p_pointer(array3, i32[size]) - iarray4: Pointer[i64[size]] = c_p_pointer(array4, i64[size]) +def sum_arrays(array1: CPtr, array2: CPtr, array3: CPtr, array4: CPtr, \ + array5: CPtr, array6: CPtr, array7: CPtr, array8: CPtr, size: i32): + iarray1: Pointer[i8[:]] = c_p_pointer(array1, i8[:], array([size])) + iarray2: Pointer[i16[:]] = c_p_pointer(array2, i16[:], array([size])) + iarray3: Pointer[i32[:]] = c_p_pointer(array3, i32[:], array([size])) + iarray4: Pointer[i64[:]] = c_p_pointer(array4, i64[:], array([size])) + iarray5: Pointer[u8[:]] = c_p_pointer(array5, u8[:], array([size])) + iarray6: Pointer[u16[:]] = c_p_pointer(array6, u16[:], array([size])) + iarray7: Pointer[u32[:]] = c_p_pointer(array7, u32[:], array([size])) + iarray8: Pointer[u64[:]] = c_p_pointer(array8, u64[:], array([size])) sum_array_cptr: CPtr = _lfortran_malloc(size * i32(sizeof(i64))) - sum_array: Pointer[i64[size]] = c_p_pointer(sum_array_cptr, i64[size]) + sum_array: Pointer[i64[:]] = c_p_pointer(sum_array_cptr, i64[:], array([size])) i: i32 for i in range(size): @@ -26,20 +39,30 @@ def sum_arrays(array1: CPtr, array2: CPtr, array3: CPtr, array4: CPtr, size: i32 iarray2[i] = i16(2 * i) iarray3[i] = i32(3 * i) iarray4[i] = i64(4 * i) + iarray5[i] = u8(i) + iarray6[i] = u16(6 * i) + iarray7[i] = u32(7 * i) + iarray8[i] = u64(8 * i) for i in range(size): - sum_array[i] = i64(iarray1[i]) + i64(iarray2[i]) + i64(iarray3[i]) + iarray4[i] + sum_array[i] = i64(iarray1[i]) + i64(iarray2[i]) + i64(iarray3[i]) \ + + iarray4[i] + i64(iarray5[i]) + i64(iarray6[i]) \ + + i64(iarray7[i]) + i64(iarray8[i]) for i in range(size): print(i, sum_array[i]) - assert sum_array[i] == i64(10 * i) + assert sum_array[i] == i64(32 * i) def test_tuple_return(): a: CPtr = empty_c_void_p() b: CPtr = empty_c_void_p() c: CPtr = empty_c_void_p() d: CPtr = empty_c_void_p() - a, b, c, d = allocate_memory(50) - sum_arrays(a, b, c, d, 50) + e: CPtr = empty_c_void_p() + f: CPtr = empty_c_void_p() + g: CPtr = empty_c_void_p() + h: CPtr = empty_c_void_p() + a, b, c, d, e, f, g, h = allocate_memory(50) + sum_arrays(a, b, c, d, e, f, g, h, 50) test_tuple_return() diff --git a/integration_tests/bindc_08.py b/integration_tests/bindc_08.py new file mode 100644 index 0000000000..e23e979b80 --- /dev/null +++ b/integration_tests/bindc_08.py @@ -0,0 +1,26 @@ +# file: main.py +from lpython import CPtr, i32, dataclass, c_p_pointer, Pointer, empty_c_void_p, p_c_pointer, Array + +from numpy import empty, array + +@dataclass +class Foo: + x: i32 + y: i32 + +def init(foos_ptr: CPtr) -> None: + foos: Pointer[Array[Foo, :]] = c_p_pointer(foos_ptr, Array[Foo, :], array([1])) + foos[0] = Foo(3, 2) + +def main() -> None: + foos: Array[Foo, 1] = empty(1, dtype=Foo) + foos_ptr: CPtr = empty_c_void_p() + foos[0] = Foo(0, 1) + p_c_pointer(foos, foos_ptr) + init(foos_ptr) + print("foos[0].x = ", foos[0].x) + print("foos[0].y = ", foos[0].y) + assert foos[0].x == 3 + assert foos[0].y == 2 + +main() diff --git a/integration_tests/bindc_09.py b/integration_tests/bindc_09.py new file mode 100644 index 0000000000..956b56b658 --- /dev/null +++ b/integration_tests/bindc_09.py @@ -0,0 +1,42 @@ +from enum import Enum + +from lpython import (CPtr, c_p_pointer, p_c_pointer, dataclass, empty_c_void_p, + pointer, Pointer, i32, ccallable, InOut) + +class Value(Enum): + TEN: i32 = 10 + TWO: i32 = 2 + ONE: i32 = 1 + FIVE: i32 = 5 + +@dataclass +class Foo: + value: Value + +@ccallable +@dataclass +class FooC: + value: Value + +def bar(foo: InOut[Foo]) -> None: + foo.value = Value.FIVE + +def barc(foo_ptr: CPtr) -> None: + foo: Pointer[FooC] = c_p_pointer(foo_ptr, FooC) + foo.value = Value.ONE + +def main() -> None: + foo: Foo = Foo(Value.TEN) + fooc: FooC = FooC(Value.TWO) + foo_ptr: CPtr = empty_c_void_p() + + bar(foo) + print(foo.value, foo.value.name) + assert foo.value == Value.FIVE + + p_c_pointer(pointer(fooc), foo_ptr) + barc(foo_ptr) + print(fooc.value) + assert fooc.value == Value.ONE.value + +main() diff --git a/integration_tests/bindc_09b.py b/integration_tests/bindc_09b.py new file mode 100644 index 0000000000..58be1e768b --- /dev/null +++ b/integration_tests/bindc_09b.py @@ -0,0 +1,44 @@ +from enum import Enum + +from lpython import CPtr, c_p_pointer, p_c_pointer, dataclass, empty_c_void_p, pointer, Pointer, i32, ccallable + +class Value(Enum): + TEN: i32 = 10 + TWO: i32 = 2 + ONE: i32 = 1 + FIVE: i32 = 5 + +@ccallable +@dataclass +class Foo: + value: Value + +@ccallable +@dataclass +class FooC: + value: Value + +def bar(foo_ptr: CPtr) -> None: + foo: Pointer[Foo] = c_p_pointer(foo_ptr, Foo) + foo.value = Value.FIVE + +def barc(foo_ptr: CPtr) -> None: + foo: Pointer[FooC] = c_p_pointer(foo_ptr, FooC) + foo.value = Value.ONE + +def main() -> None: + foo: Foo = Foo(Value.TEN) + fooc: FooC = FooC(Value.TWO) + foo_ptr: CPtr = empty_c_void_p() + + p_c_pointer(pointer(foo), foo_ptr) + bar(foo_ptr) + print(foo.value) + assert foo.value == Value.FIVE.value + + p_c_pointer(pointer(fooc), foo_ptr) + barc(foo_ptr) + print(fooc.value) + assert fooc.value == Value.ONE.value + +main() diff --git a/integration_tests/bindc_10.py b/integration_tests/bindc_10.py new file mode 100644 index 0000000000..934eacfd43 --- /dev/null +++ b/integration_tests/bindc_10.py @@ -0,0 +1,32 @@ +from lpython import (i64, i16, CPtr, c_p_pointer, Pointer, sizeof, packed, + dataclass, ccallable, ccall, i32) + +@ccall +def _lfortran_malloc(size: i32) -> CPtr: + pass + + +def alloc(buf_size:i64) -> CPtr: + return _lfortran_malloc(i32(buf_size)) + + +@ccallable +@packed +@dataclass +class S: + a: i16 + b: i64 + + +def main(): + p1: CPtr = alloc(sizeof(S)) + print(p1) + p2: Pointer[S] = c_p_pointer(p1, S) + p2.a = i16(5) + p2.b = i64(4) + print(p2.a, p2.b) + assert p2.a == i16(5) + assert p2.b == i64(4) + + +main() diff --git a/integration_tests/bindc_11.py b/integration_tests/bindc_11.py new file mode 100644 index 0000000000..c2e81c9a0a --- /dev/null +++ b/integration_tests/bindc_11.py @@ -0,0 +1,34 @@ +import numpy, ctypes +from lpython import (i64, i16, CPtr, c_p_pointer, Pointer, sizeof, packed, + dataclass, ccallable, ccall, i32) + +global_arrays = [] + + +def alloc(buf_size:i64) -> CPtr: + xs = numpy.empty(buf_size, dtype=numpy.uint8) + global_arrays.append(xs) + p = ctypes.c_void_p(xs.ctypes.data) + return ctypes.cast(p.value, ctypes.c_void_p) + + +@ccallable +@packed +@dataclass +class S: + a: i16 + b: i64 + + +def main(): + p1: CPtr = alloc(sizeof(S)) + print(p1) + p2: Pointer[S] = c_p_pointer(p1, S) + p2.a = i16(5) + p2.b = i64(4) + print(p2.a, p2.b) + assert p2.a == i16(5) + assert p2.b == i64(4) + + +main() diff --git a/integration_tests/bindpy_01.py b/integration_tests/bindpy_01.py new file mode 100644 index 0000000000..1af92c6157 --- /dev/null +++ b/integration_tests/bindpy_01.py @@ -0,0 +1,99 @@ +from lpython import i32, i64, u32, u64, f32, f64, pythoncall + +@pythoncall(module = "bindpy_01_module") +def add_ints(a: i32, b: i32, c: i32, d: i32) -> i64: + pass + +@pythoncall(module = "bindpy_01_module") +def multiply_ints(a: i32, b: i32, c: i32, d: i32) -> i64: + pass + +@pythoncall(module = "bindpy_01_module") +def add_unsigned_ints(a: u32, b: u32, c: u32, d: u32) -> u64: + pass + +@pythoncall(module = "bindpy_01_module") +def multiply_unsigned_ints(a: u32, b: u32, c: u32, d: u32) -> u64: + pass + +@pythoncall(module = "bindpy_01_module") +def add_floats(a: f32, b: f64) -> f64: + pass + +@pythoncall(module = "bindpy_01_module") +def multiply_floats(a: f32, b: f64) -> f64: + pass + +@pythoncall(module = "bindpy_01_module") +def get_hello_world(a: str, b: str) -> str: + pass + +@pythoncall(module = "bindpy_01_module") +def str_n_times(a: str, n: i32) -> str: + pass + +@pythoncall(module = "bindpy_01_module") +def get_cpython_version() -> str: + pass + +# Integers: +def test_ints(): + i: i32 + j: i32 + k: i32 + l: i32 + i = -5 + j = 24 + k = 20 + l = 92 + + assert add_ints(i, j, k, l) == i64(131) + assert multiply_ints(i, j, k, l) == i64(-220800) + +# Unsigned Integers: +def test_unsigned_ints(): + i: u32 + j: u32 + k: u32 + l: u32 + i = u32(5) + j = u32(24) + k = u32(20) + l = u32(92) + + assert add_unsigned_ints(i, j, k, l) == u64(141) + assert multiply_unsigned_ints(i, j, k, l) == u64(220800) + +# Floats +def test_floats(): + a: f32 + b: f64 + a = f32(3.14) + b = -100.00 + + assert abs(add_floats(a, b) - (-96.86)) <= 1e-4 + assert abs(multiply_floats(a, b) - (-314.0)) <= 1e-4 + +# Strings +def test_strings(): + a: str + b: str + c: str + i: i32 + a = "hello" + b = "world" + i = 3 + + assert get_hello_world(a, b) == "hello world!" + assert str_n_times(a, i) == "hellohellohello" + assert get_hello_world(str_n_times(a, i), b) == "hellohellohello world!" + +def main0(): + print("CPython version: ", get_cpython_version()) + + test_ints() + test_floats() + test_strings() + + +main0() diff --git a/integration_tests/bindpy_01_module.py b/integration_tests/bindpy_01_module.py new file mode 100644 index 0000000000..ccaa7cfa65 --- /dev/null +++ b/integration_tests/bindpy_01_module.py @@ -0,0 +1,31 @@ +def get_cpython_version(): + import platform + return platform.python_version() + +def add_ints(a, b, c, d): + e = a + b + c + d + return e + +def multiply_ints(a, b, c, d): + e = a * b * c * d + return e + +def add_unsigned_ints(a, b, c, d): + e = a + b + c + d + return e + +def multiply_unsigned_ints(a, b, c, d): + e = a * b * c * d + return e + +def add_floats(a, b): + return a + b + +def multiply_floats(a, b): + return a * b + +def get_hello_world(a, b): + return f"{a} {b}!" + +def str_n_times(a, n): + return a * n diff --git a/integration_tests/bindpy_02.py b/integration_tests/bindpy_02.py new file mode 100644 index 0000000000..9328029200 --- /dev/null +++ b/integration_tests/bindpy_02.py @@ -0,0 +1,80 @@ +from lpython import i32, f64, pythoncall, Const +from numpy import empty, int32, float64 + +@pythoncall(module = "bindpy_02_module") +def get_cpython_version() -> str: + pass + +@pythoncall(module = "bindpy_02_module") +def get_int_array_sum(a: i32[:]) -> i32: + pass + +@pythoncall(module = "bindpy_02_module") +def get_int_array_product(a: i32[:]) -> i32: + pass + +@pythoncall(module = "bindpy_02_module") +def get_float_array_sum(a: f64[:]) -> f64: + pass + +@pythoncall(module = "bindpy_02_module") +def get_float_array_product(a: f64[:]) -> f64: + pass + +@pythoncall(module = "bindpy_02_module") +def show_array_dot_product(a: i32[:], b: f64[:]): + pass + +# Integers: +def test_array_ints(): + n: Const[i32] = 5 + a: i32[n] = empty([n], dtype=int32) + + i: i32 + for i in range(n): + a[i] = i + 10 + + assert get_int_array_sum(a) == i32(60) + assert get_int_array_product(a) == i32(240240) + +# Floats +def test_array_floats(): + n: Const[i32] = 3 + m: Const[i32] = 5 + b: f64[n, m] = empty([n, m], dtype=float64) + + i: i32 + j: i32 + + for i in range(n): + for j in range(m): + b[i, j] = f64((i + 1) * (j + 1)) + + assert abs(get_float_array_sum(b) - (90.000000)) <= 1e-4 + assert abs(get_float_array_product(b) - (13436928000.000000)) <= 1e-4 + +def test_array_broadcast(): + n: Const[i32] = 3 + m: Const[i32] = 5 + a: i32[n] = empty([n], dtype=int32) + b: f64[n, m] = empty([n, m], dtype=float64) + + i: i32 + j: i32 + for i in range(n): + a[i] = i + 10 + + for i in range(n): + for j in range(m): + b[i, j] = f64((i + 1) * (j + 1)) + + show_array_dot_product(a, b) + +def main0(): + print("CPython version: ", get_cpython_version()) + + test_array_ints() + test_array_floats() + test_array_broadcast() + +main0() diff --git a/integration_tests/bindpy_02_module.py b/integration_tests/bindpy_02_module.py new file mode 100644 index 0000000000..5e76238a8e --- /dev/null +++ b/integration_tests/bindpy_02_module.py @@ -0,0 +1,21 @@ +import numpy as np + +def get_cpython_version(): + import platform + return platform.python_version() + +def get_int_array_sum(a): + return np.sum(a) + +def get_int_array_product(a): + return np.prod(a) + +def get_float_array_sum(a): + return np.sum(a) + +def get_float_array_product(a): + return np.prod(a) + +def show_array_dot_product(a, b): + print(a, b) + print(a @ b) diff --git a/integration_tests/bindpy_03.py b/integration_tests/bindpy_03.py new file mode 100644 index 0000000000..30583afcc4 --- /dev/null +++ b/integration_tests/bindpy_03.py @@ -0,0 +1,136 @@ +from lpython import i32, i64, f64, pythoncall, Const, TypeVar +from numpy import empty, int32, int64, float64 + +n = TypeVar("n") +m = TypeVar("m") +p = TypeVar("p") +q = TypeVar("q") +r = TypeVar("r") + +@pythoncall(module = "bindpy_03_module") +def get_cpython_version() -> str: + pass + +@pythoncall(module = "bindpy_03_module") +def get_int_array_sum(n: i32, a: i32[:], b: i32[:]) -> i32[n]: + pass + +@pythoncall(module = "bindpy_03_module") +def get_int_array_product(n: i32, a: i32[:], b: i32[:]) -> i32[n]: + pass + +@pythoncall(module = "bindpy_03_module") +def get_float_array_sum(n: i32, m: i32, a: f64[:], b: f64[:]) -> f64[n, m]: + pass + +@pythoncall(module = "bindpy_03_module") +def get_float_array_product(n: i32, m: i32, a: f64[:], b: f64[:]) -> f64[n, m]: + pass + +@pythoncall(module = "bindpy_03_module") +def get_array_dot_product(m: i32, a: i64[:], b: f64[:]) -> f64[m]: + pass + +@pythoncall(module = "bindpy_03_module") +def get_multidim_array_i64(p: i32, q: i32, r: i32) -> i64[p, q, r]: + pass + +# Integers: +def test_array_ints(): + n: Const[i32] = 5 + a: i32[n] = empty([n], dtype=int32) + b: i32[n] = empty([n], dtype=int32) + + i: i32 + for i in range(n): + a[i] = i + 10 + for i in range(n): + b[i] = i + 20 + + c: i32[n] = get_int_array_sum(n, a, b) + print(c) + for i in range(n): + assert c[i] == (i + i + 30) + + + c = get_int_array_product(n, a, b) + print(c) + for i in range(n): + assert c[i] == ((i + 10) * (i + 20)) + +# Floats +def test_array_floats(): + n: Const[i32] = 3 + m: Const[i32] = 5 + a: f64[n, m] = empty([n, m], dtype=float64) + b: f64[n, m] = empty([n, m], dtype=float64) + + i: i32 + j: i32 + + for i in range(n): + for j in range(m): + a[i, j] = f64((i + 10) * (j + 10)) + + for i in range(n): + for j in range(m): + b[i, j] = f64((i + 20) * (j + 20)) + + c: f64[n, m] = get_float_array_sum(n, m, a, b) + print(c) + for i in range(n): + for j in range(m): + assert abs(c[i, j] - (f64((i + 10) * (j + 10)) + f64((i + 20) * (j + 20)))) <= 1e-4 + + c = get_float_array_product(n, m, a, b) + print(c) + for i in range(n): + for j in range(m): + assert abs(c[i, j] - (f64((i + 10) * (j + 10)) * f64((i + 20) * (j + 20)))) <= 1e-4 + +def test_array_broadcast(): + n: Const[i32] = 3 + m: Const[i32] = 5 + a: i64[n] = empty([n], dtype=int64) + b: f64[n, m] = empty([n, m], dtype=float64) + + i: i32 + j: i32 + for i in range(n): + a[i] = i64(i + 10) + + for i in range(n): + for j in range(m): + b[i, j] = f64((i + 1) * (j + 1)) + + c: f64[m] = get_array_dot_product(m, a, b) + print(c) + assert abs(c[0] - (68.0)) <= 1e-4 + assert abs(c[1] - (136.0)) <= 1e-4 + assert abs(c[2] - (204.0)) <= 1e-4 + assert abs(c[3] - (272.0)) <= 1e-4 + assert abs(c[4] - (340.0)) <= 1e-4 + +def test_multidim_array_return_i64(): + p: Const[i32] = 3 + q: Const[i32] = 4 + r: Const[i32] = 5 + a: i64[p, q, r] = empty([p, q, r], dtype=int64) + a = get_multidim_array_i64(p, q, r) + print(a) + + i: i32; j: i32; k: i32 + for i in range(p): + for j in range(q): + for k in range(r): + assert a[i, j, k] == i64(i * 2 + j * 3 + k * 4) + +def main0(): + print("CPython version: ", get_cpython_version()) + + test_array_ints() + test_array_floats() + test_array_broadcast() + test_multidim_array_return_i64() + +main0() diff --git a/integration_tests/bindpy_03_module.py b/integration_tests/bindpy_03_module.py new file mode 100644 index 0000000000..0c702067c4 --- /dev/null +++ b/integration_tests/bindpy_03_module.py @@ -0,0 +1,31 @@ +import numpy as np + +def get_cpython_version(): + import platform + return platform.python_version() + +def get_int_array_sum(n, a, b): + return np.add(a, b) + +def get_int_array_product(n, a, b): + return np.multiply(a, b) + +def get_float_array_sum(n, m, a, b): + return np.add(a, b) + +def get_float_array_product(n, m, a, b): + return np.multiply(a, b) + +def get_array_dot_product(m, a, b): + print(a, b) + c = a @ b + print(c) + return c + +def get_multidim_array_i64(p, q, r): + a = np.empty([p, q, r], dtype = np.int64) + for i in range(p): + for j in range(q): + for k in range(r): + a[i, j, k] = i * 2 + j * 3 + k * 4 + return a diff --git a/integration_tests/bindpy_04.py b/integration_tests/bindpy_04.py new file mode 100644 index 0000000000..0c38baa6f2 --- /dev/null +++ b/integration_tests/bindpy_04.py @@ -0,0 +1,150 @@ +from lpython import i1, i32, u32, f64, c64, pythoncall, Const, TypeVar +from numpy import empty, uint32, complex128 + +n = TypeVar("n") +m = TypeVar("m") + +# Defining the pythoncall decorator functions +@pythoncall(module = "bindpy_04_module") +def get_uint_array_sum(n: i32, a: u32[:], b: u32[:]) -> u32[n]: + pass + +@pythoncall(module = "bindpy_04_module") +def get_bool_array_or(n: i32, a: i1[:], b: i1[:]) -> i1[n]: + pass + +@pythoncall(module = "bindpy_04_module") +def get_complex_array_product(n: i32, a: c64[:], b: c64[:]) -> c64[n]: + pass + +@pythoncall(module = "bindpy_04_module") +def get_2D_uint_array_sum(n: i32, m: i32, a: u32[:,:], b: u32[:,:]) -> u32[n,m]: + pass + +@pythoncall(module = "bindpy_04_module") +def get_2D_bool_array_and(n: i32, m: i32, a: i1[:,:], b: i1[:,:]) -> i1[n,m]: + pass + +@pythoncall(module = "bindpy_04_module") +def get_2D_complex_array_sum(n: i32, m: i32, a: c64[:,:], b: c64[:,:]) -> c64[n,m]: + pass + +# Unsigned Integers +def test_array_uints(): + n: Const[i32] = 5 + a: u32[n] = empty([n], dtype=uint32) + b: u32[n] = empty([n], dtype=uint32) + + i: i32 + for i in range(n): + a[i] = u32(i + 10) + b[i] = u32(i + 20) + + c: u32[n] = get_uint_array_sum(n, a, b) + print(c) + for i in range(n): + assert c[i] == u32(i * 2 + 30) + +def test_2D_array_uints(): + n: Const[i32] = 3 + m: Const[i32] = 4 + a: u32[n, m] = empty([n, m], dtype=uint32) + b: u32[n, m] = empty([n, m], dtype=uint32) + + i: i32 + j: i32 + for i in range(n): + for j in range(m): + a[i, j] = u32(i * 10 + j) + b[i, j] = u32(i * 20 + j) + + c: u32[n, m] = get_2D_uint_array_sum(n, m, a, b) + print(c) + for i in range(n): + for j in range(m): + assert c[i, j] == u32(i * 30 + 2*j) + +# Boolean +def test_array_bools(): + n: Const[i32] = 5 + a: i1[n] = empty([n], dtype=bool) + b: i1[n] = empty([n], dtype=bool) + + i: i32 + for i in range(n): + a[i] = bool(i % 2 == 0) + b[i] = bool(i % 3 == 0) + + c: i1[n] = get_bool_array_or(n, a, b) + print(c) + for i in range(n): + assert c[i] == bool((i % 2 == 0) or (i % 3 == 0)) + +def test_2D_array_bools(): + n: Const[i32] = 3 + m: Const[i32] = 4 + a: i1[n, m] = empty([n, m], dtype=bool) + b: i1[n, m] = empty([n, m], dtype=bool) + + i: i32 + j: i32 + for i in range(n): + for j in range(m): + a[i, j] = bool(i % 2 == 0) + b[i, j] = bool(j % 2 == 0) + + c: i1[n, m] = get_2D_bool_array_and(n, m, a, b) + print(c) + for i in range(n): + for j in range(m): + assert c[i, j] == bool((i % 2 == 0) and (j % 2 == 0)) + +# Complex +def test_array_complexes(): + n: Const[i32] = 5 + a: c64[n] = empty([n], dtype=complex128) + b: c64[n] = empty([n], dtype=complex128) + + i: i32 + for i in range(n): + a[i] = c64(complex(i, i + 10)) + b[i] = c64(complex(i + 1, i + 11)) + + c: c64[n] = get_complex_array_product(n, a, b) + print(c) + for i in range(n): + p: f64 = f64(i) + q: f64 = f64(i + 10) + r: f64 = f64(i + 1) + s: f64 = f64(i + 11) + assert abs(c[i] - c64(complex((p*r - q*s), (p*s + q*r)))) <= 1e-5 + +def test_2D_array_complexes(): + n: Const[i32] = 3 + m: Const[i32] = 4 + a: c64[n, m] = empty([n, m], dtype=complex128) + b: c64[n, m] = empty([n, m], dtype=complex128) + + i: i32 + j: i32 + for i in range(n): + for j in range(m): + a[i, j] = c64(complex(i, 10*j)) + b[i, j] = c64(complex(i + 1, 10 * (j + 1))) + + c: c64[n, m] = get_2D_complex_array_sum(n, m, a, b) + print(c) + for i in range(n): + for j in range(m): + assert abs(c[i, j] - c64(complex(2*i + 1, 20*j + 10))) <= 1e-5 + +def main0(): + test_array_uints() + test_array_bools() + test_array_complexes() + + test_2D_array_uints() + test_2D_array_bools() + test_2D_array_complexes() + +main0() diff --git a/integration_tests/bindpy_04_module.py b/integration_tests/bindpy_04_module.py new file mode 100644 index 0000000000..f856a84074 --- /dev/null +++ b/integration_tests/bindpy_04_module.py @@ -0,0 +1,21 @@ +import numpy as np + +def get_uint_array_sum(n, a, b): + return np.add(a, b) + +def get_bool_array_or(n, a, b): + return np.logical_or(a, b) + +def get_complex_array_product(n, a, b): + print(a, b) + print(np.multiply(a, b)) + return np.multiply(a, b) + +def get_2D_uint_array_sum(n, m, a, b): + return np.add(a, b) + +def get_2D_bool_array_and(n, m, a, b): + return np.logical_and(a, b) + +def get_2D_complex_array_sum(n, m, a, b): + return np.add(a, b) diff --git a/integration_tests/bindpy_05.py b/integration_tests/bindpy_05.py new file mode 100644 index 0000000000..8cb4422cd0 --- /dev/null +++ b/integration_tests/bindpy_05.py @@ -0,0 +1,79 @@ +from lpython import ccall, Pointer, i32, i64, empty_c_void_p, CPtr, pointer + +@ccall(header="Python.h") +def Py_Initialize(): + pass + +@ccall(header="Python.h") +def Py_DecodeLocale(s: str, p: CPtr) -> CPtr: + pass + +@ccall(header="Python.h") +def PySys_SetArgv(n: i32, args: Pointer[CPtr]): + pass + +@ccall(header="Python.h") +def Py_FinalizeEx() -> i32: + pass + +@ccall(header="Python.h") +def PyUnicode_FromString(s: str) -> CPtr: + pass + +@ccall(header="Python.h") +def PyImport_Import(name: CPtr) -> CPtr: + pass + +@ccall(header="Python.h") +def _Py_DecRef(name: CPtr): + pass + +@ccall(header="Python.h") +def PyObject_GetAttrString(m: CPtr, s: str) -> CPtr: + pass + +@ccall(header="Python.h") +def PyTuple_New(n: i32) -> CPtr: + pass + +@ccall(header="Python.h") +def PyObject_CallObject(a: CPtr, b: CPtr) -> CPtr: + pass + +@ccall(header="Python.h") +def PyLong_AsLongLong(a: CPtr) -> i64: + pass + +def my_f(): + pName: CPtr; pModule: CPtr; pFunc: CPtr; pArgs: CPtr; pValue: CPtr + + pName = PyUnicode_FromString("bindpy_05_module") + assert bool(pName), "Failed to convert to unicode string bindpy_05_module\n" + + pModule = PyImport_Import(pName) + _Py_DecRef(pName) + assert bool(pModule), "Failed to load python module bindpy_05_module\n" + + pFunc = PyObject_GetAttrString(pModule, "my_f") + assert bool(pFunc), "Cannot find function my_f\n" + + pArgs = PyTuple_New(0) + pValue = PyObject_CallObject(pFunc, pArgs) + _Py_DecRef(pArgs) + assert bool(pValue), "Call to my_f failed\n" + + ans: i64 = PyLong_AsLongLong(pValue) + print("Ans is", ans) + assert ans == i64(5) + + +def main0(): + Py_Initialize() + argv1: CPtr = Py_DecodeLocale("", empty_c_void_p()) + PySys_SetArgv(1, pointer(argv1, i64)) + + my_f() + + assert(Py_FinalizeEx() >= 0), "BindPython: Unknown Error in FinalizeEx()\n" + +main0() diff --git a/integration_tests/bindpy_05_module.py b/integration_tests/bindpy_05_module.py new file mode 100644 index 0000000000..ce873c0044 --- /dev/null +++ b/integration_tests/bindpy_05_module.py @@ -0,0 +1,3 @@ +def my_f(): + print("hello from python") + return 5 diff --git a/integration_tests/bindpy_06.py b/integration_tests/bindpy_06.py new file mode 100644 index 0000000000..9b077d2e46 --- /dev/null +++ b/integration_tests/bindpy_06.py @@ -0,0 +1,72 @@ +from lpython import i32, f64, pythoncall, Const +from numpy import empty, int32, float64 + + +@pythoncall(module = "bindpy_06_module") +def get_cpython_version() -> str: + pass + + +@pythoncall(module = "bindpy_06_module") +def get_modified_dict(d: dict[str, i32]) -> dict[str, i32]: + pass + + +@pythoncall(module = "bindpy_06_module") +def get_modified_list(d: list[str]) -> list[str]: + pass + +@pythoncall(module = "bindpy_06_module") +def get_modified_tuple(t: tuple[i32, i32]) -> tuple[i32, i32, i32]: + pass + + +@pythoncall(module = "bindpy_06_module") +def get_modified_set(s: set[i32]) -> set[i32]: + pass + + +def test_list(): + l: list[str] = ["LPython"] + lr: list[str] = get_modified_list(l) + assert len(lr) == 2 + assert lr[0] == "LPython" + assert lr[1] == "LFortran" + + +def test_tuple(): + t: tuple[i32, i32] = (2, 4) + tr: tuple[i32, i32, i32] = get_modified_tuple(t) + assert tr[0] == t[0] + assert tr[1] == t[1] + assert tr[2] == t[0] + t[1] + + +def test_set(): + s: set[i32] = {1, 2, 3} + sr: set[i32] = get_modified_set(s) + assert len(sr) == 4 + assert 1 in sr + assert 2 in sr + assert 3 in sr + assert 100 in sr + + +def test_dict(): + d: dict[str, i32] = { + "LPython": 50 + } + dr: dict[str, i32] = get_modified_dict(d) + assert len(dr) == 2 + assert dr["LPython"] == 50 + assert dr["LFortran"] == 100 + + +def main0(): + test_list() + test_tuple() + test_set() + test_dict() + + +main0() diff --git a/integration_tests/bindpy_06_module.py b/integration_tests/bindpy_06_module.py new file mode 100644 index 0000000000..a22386e1b7 --- /dev/null +++ b/integration_tests/bindpy_06_module.py @@ -0,0 +1,24 @@ +import platform + + +def get_cpython_version(): + return platform.python_version() + + +def get_modified_dict(d): + d["LFortran"] = 100 + return d + + +def get_modified_list(l): + l.append("LFortran") + return l + + +def get_modified_tuple(t): + return (t[0], t[1], t[0] + t[1]) + + +def get_modified_set(s): + s.add(100) + return s diff --git a/integration_tests/bit_operations_i32.py b/integration_tests/bit_operations_i32.py index 67934c8ce3..7d01f1d279 100644 --- a/integration_tests/bit_operations_i32.py +++ b/integration_tests/bit_operations_i32.py @@ -1,4 +1,4 @@ -from ltypes import i32 +from lpython import i32 def test_bitnot(): x: i32 = 5 diff --git a/integration_tests/bit_operations_i64.py b/integration_tests/bit_operations_i64.py index c1ac77c413..efc61f6d33 100644 --- a/integration_tests/bit_operations_i64.py +++ b/integration_tests/bit_operations_i64.py @@ -1,4 +1,4 @@ -from ltypes import i64 +from lpython import i64 def test_bitnot(): x: i64 = i64(123) diff --git a/integration_tests/c_mangling.py b/integration_tests/c_mangling.py new file mode 100644 index 0000000000..5acc099f41 --- /dev/null +++ b/integration_tests/c_mangling.py @@ -0,0 +1,23 @@ +def f(): + int : str + int = "abc" + print(int) + + char : str + char = "char_variable" + print(char) + + void : str + void = "void_variable" + print(void) + + auto : str + auto = "auto_variable" + print(auto) + + + case : str + case = "case_variable" + print(case) + +f() diff --git a/integration_tests/callback_01.py b/integration_tests/callback_01.py new file mode 100644 index 0000000000..e297c98630 --- /dev/null +++ b/integration_tests/callback_01.py @@ -0,0 +1,26 @@ +from lpython import i32, Callable + + +def f(x: i32) -> i32: + return x + 1 + +def f2(x: i32) -> i32: + return x + 10 + +def f3(x: i32) -> i32: + return f(x) + f2(x) + + +def g(func: Callable[[i32], i32], arg: i32) -> i32: + ret: i32 + ret = func(arg) + return ret + + +def check(): + assert g(f, 10) == 11 + assert g(f2, 20) == 30 + assert g(f3, 5) == 21 + + +check() diff --git a/integration_tests/callback_02.py b/integration_tests/callback_02.py new file mode 100644 index 0000000000..330f75cbbf --- /dev/null +++ b/integration_tests/callback_02.py @@ -0,0 +1,18 @@ +from lpython import ccallback, i32, Callable + +# test issue 2169 + +def foo(x : i32) -> i32: + return x**2 + +def bar(func : Callable[[i32], i32], arg : i32) -> i32: + return func(arg) + +@ccallback +def entry_point() -> None: + z: i32 = 5 + x: i32 = bar(foo, z) + assert z**2 == x + + +entry_point() diff --git a/integration_tests/callback_03.py b/integration_tests/callback_03.py new file mode 100644 index 0000000000..0f1f62e722 --- /dev/null +++ b/integration_tests/callback_03.py @@ -0,0 +1,13 @@ +from lpython import i32, Callable + +def foo(x : i32) -> None: + print(x) + assert x == 3 + +def bar(func : Callable[[i32], None], arg : i32) -> i32: + func(arg) + +def main0(): + bar(foo, 3) + +main0() diff --git a/integration_tests/callback_04.py b/integration_tests/callback_04.py new file mode 100644 index 0000000000..8268574f28 --- /dev/null +++ b/integration_tests/callback_04.py @@ -0,0 +1,18 @@ +import lpython +from lpython import i32 +from types import FunctionType +import callback_04_module + +lpython.CTypes.emulations = {k: v for k, v in callback_04_module.__dict__.items() + if isinstance(v, FunctionType)} + + +def foo(x : i32) -> i32: + assert x == 3 + print(x) + return x + +def entry_point() -> None: + callback_04_module.bar(foo, 3) + +entry_point() diff --git a/integration_tests/callback_04_module.py b/integration_tests/callback_04_module.py new file mode 100644 index 0000000000..13cfef375e --- /dev/null +++ b/integration_tests/callback_04_module.py @@ -0,0 +1,4 @@ +from lpython import i32, Callable + +def bar(func : Callable[[i32], i32], arg : i32) -> i32: + return func(arg) diff --git a/integration_tests/cast_01.py b/integration_tests/cast_01.py new file mode 100644 index 0000000000..ee2b5b01df --- /dev/null +++ b/integration_tests/cast_01.py @@ -0,0 +1,18 @@ +from lpython import i32, u8, u32, dataclass, field +from numpy import empty, uint8 + +@dataclass +class LPBHV_small: + dim : i32 = 4 + a : u8[4] = field(default_factory=lambda: empty(4, dtype=uint8)) + +def main0(): + lphv_small : LPBHV_small = LPBHV_small() + i: i32 + for i in range(4): + lphv_small.a[i] = u8(10 + i) + elt: u32 = u32(lphv_small.a[i]) + print(elt) + assert elt == u32(10 + i) + +main0() diff --git a/integration_tests/cast_02.py b/integration_tests/cast_02.py new file mode 100644 index 0000000000..f984e5730c --- /dev/null +++ b/integration_tests/cast_02.py @@ -0,0 +1,41 @@ +from lpython import u8, u16, u32, u64 + +def test_01(): + x : u32 = u32(10) + print(x) + assert x == u32(10) + + y: u16 = u16(x) + print(y) + assert y == u16(10) + + z: u64 = u64(y) + print(z) + assert z == u64(10) + + w: u8 = u8(z) + print(w) + assert w == u8(10) + +def test_02(): + x : u64 = u64(11) + print(x) + assert x == u64(11) + + y: u8 = u8(x) + print(y) + assert y == u8(11) + + z: u16 = u16(y) + print(z) + assert z == u16(11) + + w: u32 = u32(z) + print(w) + assert w == u32(11) + +def main0(): + test_01() + test_02() + +main0() diff --git a/integration_tests/class_01.py b/integration_tests/class_01.py new file mode 100644 index 0000000000..103cb612c3 --- /dev/null +++ b/integration_tests/class_01.py @@ -0,0 +1,28 @@ +from lpython import i32,f64 +from math import sqrt + +class coord: + def __init__(self: "coord"): + self.x: i32 = 3 + self.y: i32 = 4 + +def main(): + p1: coord = coord() + sq_dist : i32 = p1.x*p1.x + p1.y*p1.y + dist : f64 = sqrt(f64(sq_dist)) + print("Squared Distance from origin = ", sq_dist) + assert sq_dist == 25 + print("Distance from origin = ", dist) + assert dist == f64(5) + print("p1.x = 6") + print("p1.y = 8") + p1.x = i32(6) + p1.y = 8 + sq_dist = p1.x*p1.x + p1.y*p1.y + dist = sqrt(f64(sq_dist)) + print("Squared Distance from origin = ", sq_dist) + assert sq_dist == 100 + print("Distance from origin = ", dist) + assert dist == f64(10) + +main() diff --git a/integration_tests/class_02.py b/integration_tests/class_02.py new file mode 100644 index 0000000000..94d92a9ec6 --- /dev/null +++ b/integration_tests/class_02.py @@ -0,0 +1,43 @@ +from lpython import i32 +class Character: + def __init__(self:"Character", name:str, health:i32, attack_power:i32): + self.name :str = name + self.health :i32 = health + self.attack_power : i32 = attack_power + self.is_immortal : bool = False + + def attack(self:"Character", other:"Character")->str: + other.health -= self.attack_power + return self.name+" attacks "+ other.name+" for "+str(self.attack_power)+" damage." + + def is_alive(self:"Character")->bool: + if self.is_immortal: + return True + else: + return self.health > 0 + +def main(): + hero : Character = Character("Hero", 10, 20) + monster : Character = Character("Monster", 50, 15) + print(hero.attack(monster)) + print(monster.health) + assert monster.health == 30 + print(monster.is_alive()) + assert monster.is_alive() == True + print("Hero gains temporary immortality") + hero.is_immortal = True + print(monster.attack(hero)) + print(hero.health) + assert hero. health == -5 + print(hero.is_alive()) + assert hero.is_alive() == True + print("Hero's immortality runs out") + hero.is_immortal = False + print(hero.is_alive()) + assert hero.is_alive() == False + print("Restarting") + hero = Character("Hero", 10, 20) + print(hero.is_alive()) + assert hero.is_alive() == True + +main() diff --git a/integration_tests/class_03.py b/integration_tests/class_03.py new file mode 100644 index 0000000000..8e4d9eded6 --- /dev/null +++ b/integration_tests/class_03.py @@ -0,0 +1,24 @@ +from lpython import f64 +from math import pi + +class Circle: + def __init__(self:"Circle", radius:f64): + self.radius :f64 = radius + + def circle_area(self:"Circle")->f64: + return pi * self.radius ** 2.0 + + def circle_print(self:"Circle"): + area : f64 = self.circle_area() + print("Circle: r = ",str(self.radius)," area = ",str(area)) + +def main(): + c : Circle = Circle(1.0) + c.circle_print() + assert abs(c.circle_area() - 3.141593) <= 1e-6 + c.radius = 1.5 + c.circle_print() + assert abs(c.circle_area() - 7.068583) < 1e-6 + +if __name__ == "__main__": + main() diff --git a/integration_tests/class_04.py b/integration_tests/class_04.py new file mode 100644 index 0000000000..7798526331 --- /dev/null +++ b/integration_tests/class_04.py @@ -0,0 +1,46 @@ +from lpython import i32 +class Person: + def __init__(self:"Person", first:str, last:str, birthyear:i32, sgender:str): + self.first:str = first + self.last:str = last + self.birthyear:i32 = birthyear + self.sgender:str = sgender + + def describe(self:"Person"): + print("first: " + self.first) + print("last: " + self.last) + print("birthyear: " + str(self.birthyear)) + print("sgender: " + self.sgender) + +class Employee: + def __init__(self:"Employee", person:Person, hire_date:i32, department:str): + self.person:Person = person + self.hire_date:i32 = hire_date + self.department:str = department + + def describe(self:"Employee"): + self.person.describe() + print("hire_date: " + str(self.hire_date)) + print("department: " + self.department) + +def main(): + jack:Person = Person("Jack", "Smith", 1984, "M") + jill_p:Person = Person("Jill", "Smith", 1984, "F") + jill:Employee = Employee(jill_p, 2003, "sales") + + jack.describe() + assert jack.first == "Jack" + assert jack.last == "Smith" + assert jack.birthyear == 1984 + assert jack.sgender == "M" + + jill.describe() + assert jill.person.first == "Jill" + assert jill.person.last == "Smith" + assert jill.person.birthyear == 1984 + assert jill.person.sgender == "F" + assert jill.department == "sales" + assert jill.hire_date == 2003 + +if __name__ == '__main__': + main() diff --git a/integration_tests/class_05.py b/integration_tests/class_05.py new file mode 100644 index 0000000000..75af54cd8f --- /dev/null +++ b/integration_tests/class_05.py @@ -0,0 +1,37 @@ +from lpython import i32 + +class Animal: + def __init__(self:"Animal"): + self.species: str = "Generic Animal" + self.age: i32 = 0 + self.is_domestic: bool = True + +class Dog(Animal): + def __init__(self:"Dog", name:str, age:i32): + super().__init__() + self.species: str = "Dog" + self.name: str = name + self.age: i32 = age + +class Cat(Animal): + def __init__(self:"Cat", name: str, age: i32): + super().__init__() + self.species: str = "Cat" + self.name:str = name + self.age: i32 = age + +def main(): + dog: Dog = Dog("Buddy", 5) + cat: Cat = Cat("Whiskers", 3) + op1: str = str(dog.name+" is a "+str(dog.age)+"-year-old "+dog.species+".") + print(op1) + assert op1 == "Buddy is a 5-year-old Dog." + print(dog.is_domestic) + assert dog.is_domestic == True + op2: str = str(cat.name+ " is a "+ str(cat.age)+ "-year-old "+ cat.species+ ".") + print(op2) + assert op2 == "Whiskers is a 3-year-old Cat." + print(cat.is_domestic) + assert cat.is_domestic == True + +main() diff --git a/integration_tests/class_06.py b/integration_tests/class_06.py new file mode 100644 index 0000000000..868985efdf --- /dev/null +++ b/integration_tests/class_06.py @@ -0,0 +1,36 @@ +from lpython import i32 + +class Base(): + def __init__(self:"Base"): + self.x : i32 = 10 + + def get_x(self:"Base")->i32: + print(self.x) + return self.x + +#Testing polymorphic fn calls +def get_x_static(d: Base)->i32: + print(d.x) + return d.x + +class Derived(Base): + def __init__(self: "Derived"): + super().__init__() + self.y : i32 = 20 + + def get_y(self:"Derived")->i32: + print(self.y) + return self.y + + +def main(): + d : Derived = Derived() + x : i32 = get_x_static(d) + assert x == 10 + # Testing parent method call using der obj + x = d.get_x() + assert x == 10 + y: i32 = d.get_y() + assert y == 20 + +main() diff --git a/integration_tests/comp_01.py b/integration_tests/comp_01.py index b04eb9a1d0..41ac380a5a 100644 --- a/integration_tests/comp_01.py +++ b/integration_tests/comp_01.py @@ -1,4 +1,4 @@ -from ltypes import i32, f64 +from lpython import i32, f64 def compI32(x: i32, y: i32): print(x) diff --git a/integration_tests/const_01.py b/integration_tests/const_01.py index 2db1a91b0f..377f3ab676 100644 --- a/integration_tests/const_01.py +++ b/integration_tests/const_01.py @@ -1,4 +1,4 @@ -from ltypes import Const, i32, i64, f32, f64 +from lpython import Const, i32, i64, f32, f64 def test_const_variables(): xci: Const[i32] = i32(0.0) @@ -13,6 +13,11 @@ def test_const_variables(): ycf: Const[f64] = 3.0 yf: f64 = 3.0 + print(xci, xi) + print(yci, yi) + print(xcf, xf) + print(ycf, yf) + assert xci == xi assert yci == yi assert xcf == xf diff --git a/integration_tests/const_02.py b/integration_tests/const_02.py index c84fea5a9d..b8c69b743c 100644 --- a/integration_tests/const_02.py +++ b/integration_tests/const_02.py @@ -1,4 +1,4 @@ -from ltypes import i32, f64, Const +from lpython import i32, f64, Const def f(x: Const[i32]) -> i32: return x + 1 diff --git a/integration_tests/const_03.py b/integration_tests/const_03.py index 40ebf818d5..13d448c0a3 100644 --- a/integration_tests/const_03.py +++ b/integration_tests/const_03.py @@ -1,4 +1,4 @@ -from ltypes import i64, f64, i32, Const, ccall +from lpython import i64, f64, i32, Const, ccall CONST_1: Const[f64] = 32.0 CONST_2: Const[f64] = CONST_1 * 2.0 diff --git a/integration_tests/const_04.py b/integration_tests/const_04.py index 6acd01dbd0..e65b5292fd 100644 --- a/integration_tests/const_04.py +++ b/integration_tests/const_04.py @@ -1,4 +1,4 @@ -from ltypes import i32, i16, Const +from lpython import i32, i16, Const from numpy import empty, int16 def sum_const_array(array: Const[i16[:]], size: i32) -> i16: diff --git a/integration_tests/def_func_01.py b/integration_tests/def_func_01.py new file mode 100644 index 0000000000..2564cff13e --- /dev/null +++ b/integration_tests/def_func_01.py @@ -0,0 +1,76 @@ +from lpython import i32,i64 + +def factorial_1(x: i32, y:i32 =1) ->i32 : + if x <= 1: + return y + return x * factorial_1(x-1) + +def factorial_2(x: i32, y:i32=3 ,z:i32 =2) ->i32: + if x ==4: + return x * y * z + return x * factorial_2(x-1) + +def default_func(x : str ="Hello", y : str = " ", z : str = "World") ->str: + return x + y + z + + +def even_positions(iterator : i32, to_add : str = "?")-> str: + if (iterator == 10): return "" + if iterator%2 == 0 : + return to_add + even_positions(iterator+1,"X") + return to_add +even_positions(iterator+1) + + + +def test_factorial_1(): + test_00 : i32 = factorial_1(1) + print("test_00 is =>", test_00) + assert test_00 == 1 + + test_01 : i32 = factorial_1(5,0) + print("test_01 is =>", test_01) + assert test_01 == 120 + + test_02 : i32 = factorial_1(1,5555) + print("test_02 is =>", test_02) + assert test_02 == 5555 + +def test_factorial_2(): + test_03 : i32 =factorial_2(5,99999,99999) + print("test_03 is =>", test_03) + assert test_03 == 120 + + test_04 : i32 = factorial_2(4,-1,100) + print("test_04 is =>", test_04) + assert test_04 == -400 + +def test_default_func(): + test_05 :str = default_func() + print("test_05 is =>", test_05) + assert test_05 == "Hello World" + + test_06 :str = default_func(y = "|||",x="Hi") + print("test_06 is =>", test_06) + assert test_06 == "Hi|||World" + + test_07 :str = default_func(y = "++",z = "LPython") + print("test_07 is =>", test_07) + assert test_07 == "Hello++LPython" + + test_8 :str = default_func("Welcome",z = "LPython") + print("test_8 is =>", test_8) + assert test_8 == "Welcome LPython" + +def test_even_positions(): + test_09 : str = even_positions(0) + print("test_09 is =>", test_09) + assert test_09 == "?X?X?X?X?X" + + test_10 : str = even_positions(0,"W") + print("test_10 is =>", test_10) + assert test_10 == "WX?X?X?X?X" + +test_factorial_1() +test_factorial_2() +test_default_func() +test_even_positions() diff --git a/integration_tests/elemental_01.py b/integration_tests/elemental_01.py index 22b44b90ed..0a2787c7ed 100644 --- a/integration_tests/elemental_01.py +++ b/integration_tests/elemental_01.py @@ -1,5 +1,5 @@ -from ltypes import i32, f64, f32 -from numpy import empty, sin, cos, reshape +from lpython import i32, f64, f32 +from numpy import empty, sin, cos, reshape, int32, float32, float64 def verify1d(array: f32[:], result: f32[:], size: i32): i: i32 @@ -35,7 +35,7 @@ def verify2d(array: f64[:, :], result: f64[:, :], size1: i32, size2: i32): def verify1d_sum(array_a: f64[:], array_b: f64[:], result: f64[:], size: i32): i: i32 eps: f64 - eps = 1e-12 + eps = 1e-9 for i in range(size): assert abs(array_a[i]**2.0 + 5.0*array_b[i]**3.0 - result[i]) <= eps @@ -44,7 +44,7 @@ def verify1d_sum(array_a: f64[:], array_b: f64[:], result: f64[:], size: i32): def verify1d_mul(array_a: f64[:], array_b: f64[:], result: f64[:], size: i32): i: i32 eps: f64 - eps = 1e-12 + eps = 1e-5 for i in range(size): assert abs(array_a[i]**2.0 * 5.0*array_b[i]**3.0 - result[i]) <= eps @@ -55,9 +55,9 @@ def elemental_sum(): j: i32 k: i32 - array_a: f64[100] = empty(100) - array_b: f64[100] = empty(100) - array_c: f64[100] = empty(100) + array_a: f64[100] = empty(100, dtype=float64) + array_b: f64[100] = empty(100, dtype=float64) + array_c: f64[100] = empty(100, dtype=float64) for i in range(100): array_a[i] = float(i) @@ -74,9 +74,9 @@ def elemental_mul(): j: i32 k: i32 - array_a: f64[100] = empty(100) - array_b: f64[100] = empty(100) - array_c: f64[100] = empty(100) + array_a: f64[100] = empty(100, dtype=float64) + array_b: f64[100] = empty(100, dtype=float64) + array_c: f64[100] = empty(100, dtype=float64) for i in range(100): array_a[i] = float(i) @@ -93,8 +93,8 @@ def elemental_sin(): j: i32 k: i32 - array1d: f32[256] = empty(256) - sin1d: f32[256] = empty(256) + array1d: f32[256] = empty(256, dtype=float32) + sin1d: f32[256] = empty(256, dtype=float32) for i in range(256): array1d[i] = f32(i) @@ -103,24 +103,24 @@ def elemental_sin(): verify1d(array1d, sin1d, 256) - arraynd: f64[256, 64, 16] = empty((256, 64, 16)) - sinnd: f64[256, 64, 16] = empty((256, 64, 16)) + arraynd: f64[200, 64, 16] = empty((200, 64, 16), dtype=float64) + sinnd: f64[200, 64, 16] = empty((200, 64, 16), dtype=float64) - for i in range(256): + for i in range(200): for j in range(64): for k in range(16): arraynd[i, j, k] = float(i + j + k) sinnd = sin(arraynd)**2.0 - verifynd(arraynd, sinnd, 256, 64, 16) + verifynd(arraynd, sinnd, 200, 64, 16) def elemental_cos(): i: i32 j: i32 - array2d: f64[256, 64] = empty((256, 64)) - cos2d: f64[256, 64] = empty((256, 64)) + array2d: f64[256, 64] = empty((256, 64), dtype=float64) + cos2d: f64[256, 64] = empty((256, 64), dtype=float64) for i in range(256): for j in range(64): @@ -138,9 +138,9 @@ def elemental_trig_identity(): eps: f32 eps = f32(1e-6) - arraynd: f32[64, 32, 8, 4] = empty((64, 32, 8, 4)) - observed: f32[64, 32, 8, 4] = empty((64, 32, 8, 4)) - observed1d: f32[65536] = empty(65536) + arraynd: f32[64, 32, 8, 4] = empty((64, 32, 8, 4), dtype=float32) + observed: f32[64, 32, 8, 4] = empty((64, 32, 8, 4), dtype=float32) + observed1d: f32[65536] = empty(65536, dtype=float32) for i in range(64): for j in range(32): @@ -150,7 +150,7 @@ def elemental_trig_identity(): observed = sin(arraynd)**f32(2) + cos(arraynd)**f32(2) - newshape: i32[1] = empty(1, dtype=int) + newshape: i32[1] = empty(1, dtype=int32) newshape[0] = 65536 observed1d = reshape(observed, newshape) @@ -162,4 +162,4 @@ def elemental_trig_identity(): elemental_cos() elemental_trig_identity() elemental_sum() -elemental_mul() +elemental_mul() \ No newline at end of file diff --git a/integration_tests/elemental_02.py b/integration_tests/elemental_02.py index 0d574b76f4..e0df66ea50 100644 --- a/integration_tests/elemental_02.py +++ b/integration_tests/elemental_02.py @@ -1,12 +1,12 @@ -from ltypes import i32, f64, f32 -from numpy import empty, tan, sin, cos, reshape +from lpython import i32, f64, f32 +from numpy import empty, tan, sin, cos, reshape, int32, float32, float64 def elemental_tan64(): - theta: f64[16, 8, 4, 2, 1] = empty((16, 8, 4, 2, 1)) - theta1d: f64[1024] = empty(1024) - tantheta: f64[16, 8, 4, 2, 1] = empty((16, 8, 4, 2, 1)) - observed: f64[16, 8, 4, 2, 1] = empty((16, 8, 4, 2, 1)) - shapend: i32[5] = empty(5, dtype=int) + theta: f64[16, 8, 4, 2, 1] = empty((16, 8, 4, 2, 1), dtype=float64) + theta1d: f64[1024] = empty(1024, dtype=float64) + tantheta: f64[16, 8, 4, 2, 1] = empty((16, 8, 4, 2, 1), dtype=float64) + observed: f64[16, 8, 4, 2, 1] = empty((16, 8, 4, 2, 1), dtype=float64) + shapend: i32[5] = empty(5, dtype=int32) i: i32 j: i32 k: i32 @@ -31,15 +31,15 @@ def elemental_tan64(): assert abs(tantheta[i, j, k, l, 0] - observed[i, j, k, l, 0]) <= eps def elemental_tan32(): - theta: f32[5, 5] = empty((5, 5)) - theta1d: f32[25] = empty(25) - tantheta: f32[5, 5] = empty((5, 5)) - observed: f32[5, 5] = empty((5, 5)) - shapend: i32[2] = empty(2, dtype=int) + theta: f32[5, 5] = empty((5, 5), dtype=float32) + theta1d: f32[25] = empty(25, dtype=float32) + tantheta: f32[5, 5] = empty((5, 5), dtype=float32) + observed: f32[5, 5] = empty((5, 5), dtype=float32) + shapend: i32[2] = empty(2, dtype=int32) i: i32 j: i32 eps: f32 - eps = f32(1e-6) + eps = f32(1e-4) for i in range(25): theta1d[i] = f32(i + 1) diff --git a/integration_tests/elemental_03.py b/integration_tests/elemental_03.py index c0f1aa0f9d..2638505344 100644 --- a/integration_tests/elemental_03.py +++ b/integration_tests/elemental_03.py @@ -1,10 +1,10 @@ -from ltypes import i32, f32, f64 -from numpy import empty, sqrt, reshape +from lpython import i32, f32, f64 +from numpy import empty, sqrt, reshape, int32, float32, float64 def elemental_sqrt64(): - array: f64[16, 16, 16] = empty((16, 16, 16)) - observed: f64[4096] = empty(4096) - shape: i32[1] = empty(1, dtype=int) + array: f64[16, 16, 16] = empty((16, 16, 16), dtype=float64) + observed: f64[4096] = empty(4096, dtype=float64) + shape: i32[1] = empty(1, dtype=int32) eps: f64 eps = 1e-12 i: i32 @@ -20,15 +20,15 @@ def elemental_sqrt64(): shape[0] = 4096 observed = reshape(sqrt(array), shape) for l in range(4096): - i = i32(int(l/256)) + i = i32(l/256) j = (l - i*256)//16 k = (l - i*256 - j*16) assert abs(observed[l]**2.0 - f64(i + j + k)) <= eps def elemental_sqrt32(): - array: f32[16, 16] = empty((16, 16)) - observed: f32[256] = empty(256) - shape: i32[1] = empty(1, dtype=int) + array: f32[16, 16] = empty((16, 16), dtype=float32) + observed: f32[256] = empty(256, dtype=float32) + shape: i32[1] = empty(1, dtype=int32) eps: f32 eps = f32(5e-6) i: i32 @@ -42,15 +42,15 @@ def elemental_sqrt32(): shape[0] = 256 observed = reshape(sqrt(array), shape) for l in range(256): - i = i32(int(l/16)) + i = i32(l/16) j = (l - i*16) assert abs(observed[l]**f32(2.0) - f32(i + j)) <= eps def elemental_norm(): - array_a: f64[100] = empty(100) - array_b: f64[100] = empty(100) - array_c: f64[100] = empty(100) + array_a: f64[100] = empty(100, dtype=float64) + array_b: f64[100] = empty(100, dtype=float64) + array_c: f64[100] = empty(100, dtype=float64) i: i32 j: i32 diff --git a/integration_tests/elemental_04.py b/integration_tests/elemental_04.py index df99903a67..d51e5d7a4f 100644 --- a/integration_tests/elemental_04.py +++ b/integration_tests/elemental_04.py @@ -1,10 +1,10 @@ -from ltypes import i32, f32, f64 -from numpy import empty, log, log10, log2, reshape +from lpython import i32, f32, f64 +from numpy import empty, log, log10, log2, reshape, int32, float32, float64 from math import exp def elemental_log(): - array: f64[100] = empty(100) - observed: f64[100] = empty(100) + array: f64[100] = empty(100, dtype=float64) + observed: f64[100] = empty(100, dtype=float64) i: i32 eps: f64 eps = 1e-12 @@ -23,14 +23,14 @@ def verify(observed: f32[:], base: i32, eps: f32): j: i32 for k in range(100): - i = i32(int(k/10)) + i = i32(k/10) j = (k - i*10) assert abs(f32(base)**(observed[k]) - f32(i + j + 1)) <= eps def elemental_log2_log10(): - array: f32[10, 10] = empty((10, 10)) - observed: f32[100] = empty(100) - shape: i32[1] = empty(1, dtype=int) + array: f32[10, 10] = empty((10, 10), dtype=float32) + observed: f32[100] = empty(100, dtype=float32) + shape: i32[1] = empty(1, dtype=int32) i: i32 j: i32 eps: f32 diff --git a/integration_tests/elemental_05.py b/integration_tests/elemental_05.py index 49b80b72ef..4e91b8eaa2 100644 --- a/integration_tests/elemental_05.py +++ b/integration_tests/elemental_05.py @@ -1,5 +1,5 @@ -from ltypes import i32, f64, f32 -from numpy import empty, sinh, cosh, reshape, int32, float64, sin +from lpython import i32, f64, f32 +from numpy import empty, sinh, cosh, reshape, int32, float32, float64, sin def verify1d(array: f32[:], result: f32[:], size: i32): i: i32 @@ -18,14 +18,14 @@ def verifynd(array: f64[:, :, :, :], result: f64[:, :, :, :], size1: i32, size2: result1d: f64[12800] = reshape(result, shape) for i in range(size): - assert abs((sinh(array1d[i]) + 2.0)/2 - result1d[i]) <= eps + assert abs((sinh(array1d[i]) + 2.0)/2.0 - result1d[i]) <= eps def elemental_sinh(): i: i32; j: i32; k: i32; l: i32; size: i32; - array1d: f32[10] = empty(10) - sinh1d: f32[10] = empty(10) + array1d: f32[10] = empty(10, dtype=float32) + sinh1d: f32[10] = empty(10, dtype=float32) for i in range(10): array1d[i] = f32(f64(i)/10.0) @@ -33,15 +33,15 @@ def elemental_sinh(): sinh1d = sinh(sinh(array1d)) verify1d(array1d, sinh1d, 10) - arraynd: f64[40, 10, 16, 2] = empty((40, 10, 16, 2)) - sinhnd: f64[40, 10, 16, 2] = empty((40, 10, 16, 2)) + arraynd: f64[40, 10, 16, 2] = empty((40, 10, 16, 2), dtype=float64) + sinhnd: f64[40, 10, 16, 2] = empty((40, 10, 16, 2), dtype=float64) size = 40 * 10 * 16 * 2 for i in range(40): for j in range(10): for k in range(16): for l in range(2): - arraynd[i, j, k, l] = float(i + 2*j + 3*k + 4*k)/size + arraynd[i, j, k, l] = float(i + 2*j + 3*k + 4*k)/float(size) sinhnd = (sinh(arraynd) + 2.0)/2.0 @@ -58,12 +58,12 @@ def verify2d(array: f64[:, :], result: f64[:, :], size1: i32, size2: i32): def elemental_cosh(): i: i32; j: i32 - array2d: f64[20, 10] = empty((20, 10)) - cosh2d: f64[20, 10] = empty((20, 10)) + array2d: f64[20, 10] = empty((20, 10), dtype=float64) + cosh2d: f64[20, 10] = empty((20, 10), dtype=float64) for i in range(20): for j in range(10): - array2d[i, j] = (i + 2*j)/200.0 + array2d[i, j] = float(i + 2*j)/200.0 cosh2d = cosh(5.0 + (array2d))**2.0 verify2d(array2d, cosh2d, 20, 10) @@ -72,12 +72,12 @@ def elemental_cosh_(): i: i32 j: i32 - array2d: f64[20, 10] = empty((20, 10)) - cosh2d: f64[20, 10] = empty((20, 10)) + array2d: f64[20, 10] = empty((20, 10), dtype=float64) + cosh2d: f64[20, 10] = empty((20, 10), dtype=float64) for i in range(20): for j in range(10): - array2d[i, j] = (i + 2*j)/200.0 + array2d[i, j] = float(i + 2*j)/200.0 cosh2d = cosh(5.0 + (array2d))**2.0 verify2d(array2d, cosh2d, 20, 10) @@ -111,7 +111,7 @@ def elemental_trig_identity(): cosh(arraynd/4.0) * cosh(arraynd/2.0) - sinh(arraynd/4.0) * sinh(arraynd/2.0)) - newshape: i32[1] = empty(1, dtype=int) + newshape: i32[1] = empty(1, dtype=int32) newshape[0] = 400 observed1d_1 = reshape(identity1, newshape) diff --git a/integration_tests/elemental_06.py b/integration_tests/elemental_06.py index 4acc162e47..13782bdb14 100644 --- a/integration_tests/elemental_06.py +++ b/integration_tests/elemental_06.py @@ -1,5 +1,5 @@ -from ltypes import i32, f32, f64 -from numpy import empty, arcsin, arccos, sin, cos, sqrt, arctan, tan, degrees, radians +from lpython import i32, f32, f64 +from numpy import empty, arcsin, arccos, sin, cos, sqrt, arctan, tan, degrees, radians, hypot, float32, float64 from math import pi def verify1d_same(array: f32[:], result: f32[:], size: i32): @@ -57,18 +57,27 @@ def verify_arctan_2d(array: f64[:, :], result: f64[:, :], size1:i32, size2:i32): for j in range(size2): assert abs(arctan(array[i, j])**2.0 - result[i, j]) <= eps +def verify_hypot_2d(array1: f64[:, :], array2: f64[:, :], result: f64[:, :], size1:i32, size2:i32): + i: i32 + j: i32 + eps: f64 + eps = 1e-12 + for i in range(size1): + for j in range(size2): + assert abs(hypot(array1[i, j], array2[i, j]) - result[i, j]) <= eps + def elemental_arcsin(): i: i32 j: i32 - array1d: f32[201] = empty(201) - arcsin1d: f32[201] = empty(201) + array1d: f32[201] = empty(201, dtype=float32) + arcsin1d: f32[201] = empty(201, dtype=float32) for i in range(201): array1d[i] = f32((i - 100)/100) arcsin1d = arcsin(array1d) ** f32(2.0) verify_arcsin_1d(array1d, arcsin1d, 201) - array2d: f64[64, 64] = empty((64, 64)) - arcsin2d: f64[64, 64] = empty((64, 64)) + array2d: f64[64, 64] = empty((64, 64), dtype=float64) + arcsin2d: f64[64, 64] = empty((64, 64), dtype=float64) for i in range(64): for j in range(64): # 2048 = 64 * 32 array2d[i,j]= float((i * 64 + j - 2048 )/2048) @@ -79,15 +88,15 @@ def elemental_arcsin(): def elemental_arccos(): i: i32 j: i32 - array1d: f32[201] = empty(201) - arccos1d: f32[201] = empty(201) + array1d: f32[201] = empty(201, dtype=float32) + arccos1d: f32[201] = empty(201, dtype=float32) for i in range(201): array1d[i] = f32((i - 100)/100) arccos1d = arccos(array1d) ** f32(2.0) verify_arccos_1d(array1d, arccos1d, 201) - array2d: f64[64, 64] = empty((64, 64)) - arccos2d: f64[64, 64] = empty((64, 64)) + array2d: f64[64, 64] = empty((64, 64), dtype=float64) + arccos2d: f64[64, 64] = empty((64, 64), dtype=float64) for i in range(64): for j in range(64): # 2048 = 64 * 32 array2d[i,j]= float((i * 64 + j - 2048 )/2048) @@ -100,9 +109,9 @@ def elemental_arctan(): j: i32 eps: f32 eps = f32(1e-6) - array1d: f32[201] = empty(201) - array1d_rec: f32[201] = empty(201) - arctan1d: f32[201] = empty(201) + array1d: f32[201] = empty(201, dtype=float32) + array1d_rec: f32[201] = empty(201, dtype=float32) + arctan1d: f32[201] = empty(201, dtype=float32) for i in range(201): array1d[i] = f32(i - 100) arctan1d = arctan(array1d) ** f32(2.0) @@ -110,13 +119,13 @@ def elemental_arctan(): for i in range(201): array1d[i] = f32(i + 1) - array1d_rec[i] = f32(1.0/(i+1)) + array1d_rec[i] = f32(1.0/f64(i+1)) arctan1d = arctan(array1d) + arctan(array1d_rec) for i in range(201): assert abs(arctan1d[i] - f32(f64(pi) / 2.0)) <= eps - array2d: f64[64, 64] = empty((64, 64)) - arctan2d: f64[64, 64] = empty((64, 64)) + array2d: f64[64, 64] = empty((64, 64), dtype=float64) + arctan2d: f64[64, 64] = empty((64, 64), dtype=float64) for i in range(64): for j in range(64): array2d[i,j]= float(64*i + j - 2048) @@ -128,8 +137,8 @@ def elemental_trig_identity(): i: i32 eps: f32 eps = f32(1e-6) - array1d: f32[201] = empty(201) - observed1d: f32[201] = empty(201) + array1d: f32[201] = empty(201, dtype=float32) + observed1d: f32[201] = empty(201, dtype=float32) for i in range(201): array1d[i] = f32((i - 100)/100) @@ -139,8 +148,8 @@ def elemental_trig_identity(): def elemental_reverse(): i: i32 - array1d: f32[201] = empty(201) - observed1d: f32[201] = empty(201) + array1d: f32[201] = empty(201, dtype=float32) + observed1d: f32[201] = empty(201, dtype=float32) for i in range(201): array1d[i] = f32((i - 100)/100) observed1d = sin(arcsin(array1d)) @@ -157,9 +166,9 @@ def elemental_reverse(): def elemental_trig_identity_extra(): i: i32 - array1d: f32[201] = empty(201) - array_x: f32[201] = empty(201) - array_y: f32[201] = empty(201) + array1d: f32[201] = empty(201, dtype=float32) + array_x: f32[201] = empty(201, dtype=float32) + array_y: f32[201] = empty(201, dtype=float32) for i in range(201): array1d[i] = f32((i - 100)/100) array_x = sin(arccos(array1d)) @@ -177,8 +186,8 @@ def elemental_degrees(): eps_64: f64 eps_32 = f32(1e-6) eps_64 = 1e-12 - array1d: f32[200] = empty(200) - degrees1d: f32[200] = empty(200) + array1d: f32[200] = empty(200, dtype=float32) + degrees1d: f32[200] = empty(200, dtype=float32) for i in range(200): array1d[i] = f32(i) degrees1d = sin(degrees(array1d)) @@ -186,8 +195,8 @@ def elemental_degrees(): for i in range(200): assert abs(degrees1d[i] - sin(degrees(array1d[i]))) <= eps_32 - array2d: f64[64, 64] = empty((64, 64)) - degrees2d: f64[64, 64] = empty((64, 64)) + array2d: f64[64, 64] = empty((64, 64), dtype=float64) + degrees2d: f64[64, 64] = empty((64, 64), dtype=float64) for i in range(64): for j in range(64): array2d[i,j]= float(i*64+j) @@ -203,8 +212,8 @@ def elemental_radians(): eps_64: f64 eps_32 = f32(1e-6) eps_64 = 1e-12 - array1d: f32[200] = empty(200) - radians1d: f32[200] = empty(200) + array1d: f32[200] = empty(200, dtype=float32) + radians1d: f32[200] = empty(200, dtype=float32) for i in range(200): array1d[i] = f32(i) radians1d = cos(radians(array1d)) @@ -212,8 +221,8 @@ def elemental_radians(): for i in range(200): assert abs(radians1d[i] - cos(radians(array1d[i]))) <= eps_32 - array2d: f64[64, 64] = empty((64, 64)) - radians2d: f64[64, 64] = empty((64, 64)) + array2d: f64[64, 64] = empty((64, 64), dtype=float64) + radians2d: f64[64, 64] = empty((64, 64), dtype=float64) for i in range(64): for j in range(64): array2d[i,j]= float(i*64+j) @@ -222,6 +231,35 @@ def elemental_radians(): for j in range(64): assert abs(radians2d[i, j] - cos(radians(array2d[i, j]))) <= eps_64 +def elemental_hypot(): + i: i32 + j: i32 + eps_32: f32 + eps_32 = f32(1e-6) + + hypot1d: f32[200] = empty(200, dtype=float32) + array1d1: f32[200] = empty(200, dtype=float32) + array1d2: f32[200] = empty(200, dtype=float32) + for i in range(200): + array1d1[i] = f32(i) + array1d2[i] = f32(i+10) + + hypot1d = hypot(array1d1, array1d2) + + for i in range(200): + assert abs(hypot1d[i] - hypot(array1d1[i], array1d2[i])) <= eps_32 + + array2d1: f64[64, 64] = empty((64, 64), dtype=float64) + array2d2: f64[64, 64] = empty((64, 64), dtype=float64) + hypot2d: f64[64, 64] = empty((64, 64), dtype=float64) + for i in range(64): + for j in range(64): + array2d1[i,j]= float(i * j) + array2d2[i,j]= float(64*i + j - 2048) + + hypot2d = hypot(array2d1, array2d2) + verify_hypot_2d(array2d1, array2d2, hypot2d, 64, 64) + elemental_arcsin() elemental_arccos() @@ -231,3 +269,4 @@ def elemental_radians(): elemental_trig_identity() elemental_reverse() elemental_trig_identity_extra() +elemental_hypot() diff --git a/integration_tests/elemental_07.py b/integration_tests/elemental_07.py index 44dd996d00..b458eab989 100644 --- a/integration_tests/elemental_07.py +++ b/integration_tests/elemental_07.py @@ -1,5 +1,5 @@ -from ltypes import i32, f64, f32 -from numpy import empty, tanh, reshape, int32, float64, sin, log10 +from lpython import i32, f64, f32 +from numpy import empty, tanh, reshape, int32, float32, float64, sin def verify1d(array: f32[:], result: f32[:], size: i32): i: i32 @@ -24,8 +24,8 @@ def verifynd(array: f64[:, :, :, :], result: f64[:, :, :, :], size1: i32, size2: def elemental_tanh(): i: i32; j: i32; k: i32; l: i32; size: i32; - array1d: f32[80] = empty(80) - tanh1d: f32[80] = empty(80) + array1d: f32[80] = empty(80, dtype=float32) + tanh1d: f32[80] = empty(80, dtype=float32) for i in range(80): array1d[i] = f32(f64(i) / 10.0) @@ -33,15 +33,15 @@ def elemental_tanh(): tanh1d = tanh(sin(array1d)) verify1d(array1d, tanh1d, 10) - arraynd: f64[16, 8, 4, 2] = empty((16, 8, 4, 2)) - tanhnd: f64[16, 8, 4, 2] = empty((16, 8, 4, 2)) + arraynd: f64[16, 8, 4, 2] = empty((16, 8, 4, 2), dtype=float64) + tanhnd: f64[16, 8, 4, 2] = empty((16, 8, 4, 2), dtype=float64) size = 16 * 8 * 4 * 2 for i in range(16): for j in range(8): for k in range(4): for l in range(2): - arraynd[i, j, k, l] = float(i + 2*j + 3*k + 4*k)/size + arraynd[i, j, k, l] = float(i + 2*j + 3*k + 4*k)/float(size) tanhnd = (tanh(sin(arraynd)) + 2.0)/2.0 diff --git a/integration_tests/elemental_08.py b/integration_tests/elemental_08.py index 76d74430c4..1903e93cd1 100644 --- a/integration_tests/elemental_08.py +++ b/integration_tests/elemental_08.py @@ -1,5 +1,5 @@ -from ltypes import i32, f64, f32 -from numpy import empty, reshape, int32, exp +from lpython import i32, f64, f32 +from numpy import empty, reshape, int32, float32, float64, exp def verify1d(array: f32[:], result: f32[:], size: i32): i: i32 @@ -18,13 +18,13 @@ def verifynd(array: f64[:, :, :, :], result: f64[:, :, :, :], size1: i32, size2: result1d: f64[1024] = reshape(result, shape) for i in range(size): - assert abs(( exp(array1d[i]) + exp(array1d[i] / 3) ) / 2 - result1d[i]) <= eps + assert abs(( exp(array1d[i]) + exp(array1d[i] / 3.0) ) / float(2) - result1d[i]) <= eps def elemental_exp(): i: i32; j: i32; k: i32; l: i32; size: i32; - array1d: f32[80] = empty(80) - exp1d: f32[80] = empty(80) + array1d: f32[80] = empty(80, dtype=float32) + exp1d: f32[80] = empty(80, dtype=float32) for i in range(80): array1d[i] = f32(f64(i) / 50.0) @@ -32,15 +32,15 @@ def elemental_exp(): exp1d = exp(array1d) verify1d(array1d, exp1d, 80) - arraynd: f64[16, 8, 4, 2] = empty((16, 8, 4, 2)) - expnd: f64[16, 8, 4, 2] = empty((16, 8, 4, 2)) + arraynd: f64[16, 8, 4, 2] = empty((16, 8, 4, 2), dtype=float64) + expnd: f64[16, 8, 4, 2] = empty((16, 8, 4, 2), dtype=float64) size = 32 for i in range(16): for j in range(8): for k in range(4): for l in range(2): - arraynd[i, j, k, l] = float( f64(i) / 8.0 + f64(j) / 4.0 + f64(k) / 2.0 + f64(l) ) / size + arraynd[i, j, k, l] = float( f64(i) / 8.0 + f64(j) / 4.0 + f64(k) / 2.0 + f64(l) ) / float(size) expnd = (exp(arraynd) + exp(arraynd / 3.0)) / 2.0 diff --git a/integration_tests/elemental_09.py b/integration_tests/elemental_09.py index fb840234cb..c879d0e926 100644 --- a/integration_tests/elemental_09.py +++ b/integration_tests/elemental_09.py @@ -1,5 +1,5 @@ -from ltypes import i32, f64, f32 -from numpy import empty, arcsinh, arccosh, reshape, float64, sinh, sqrt, sin, cosh +from lpython import i32, f64, f32 +from numpy import empty, arcsinh, arccosh, reshape, int32, float32, float64, sinh, sqrt, sin def verify1d_arcsinh(array: f32[:], result: f32[:], size: i32): i: i32 @@ -27,8 +27,8 @@ def elemental_arcsinh(): j: i32 k: i32 - array1d: f32[256] = empty(256) - arcsinh1d: f32[256] = empty(256) + array1d: f32[256] = empty(256, dtype=float32) + arcsinh1d: f32[256] = empty(256, dtype=float32) for i in range(256): array1d[i] = f32(i) @@ -36,16 +36,16 @@ def elemental_arcsinh(): arcsinh1d = arcsinh(arcsinh(array1d)) verify1d_arcsinh(array1d, arcsinh1d, 256) - arraynd: f64[256, 64, 16] = empty((256, 64, 16)) - arcsinhnd: f64[256, 64, 16] = empty((256, 64, 16)) + arraynd: f64[256, 64, 4] = empty((256, 64, 4), dtype=float64) + arcsinhnd: f64[256, 64, 4] = empty((256, 64, 4), dtype=float64) for i in range(256): for j in range(64): - for k in range(16): + for k in range(4): arraynd[i, j, k] = float(i + j + k) arcsinhnd = (1.0 + arcsinh(arraynd)) - verifynd_arcsinh(arraynd, arcsinhnd, 256, 64, 16) + verifynd_arcsinh(arraynd, arcsinhnd, 256, 64, 4) def verify2d_arccosh(array: f64[:, :], result: f64[:, :], size1: i32, size2: i32): i: i32 @@ -77,8 +77,8 @@ def elemental_arccosh(): k: i32 l: i32 - array2d: f64[256, 64] = empty((256, 64)) - arccosh2d: f64[256, 64] = empty((256, 64)) + array2d: f64[256, 64] = empty((256, 64), dtype=float64) + arccosh2d: f64[256, 64] = empty((256, 64), dtype=float64) for i in range(256): for j in range(64): @@ -87,8 +87,8 @@ def elemental_arccosh(): arccosh2d = arccosh(array2d)**2.0 verify2d_arccosh(array2d, arccosh2d, 256, 64) - arraynd: f64[32, 16, 4, 2] = empty((32, 16, 4, 2)) - arccosh_nd: f64[32, 16, 4, 2] = empty((32, 16, 4, 2)) + arraynd: f64[32, 16, 4, 2] = empty((32, 16, 4, 2), dtype=float64) + arccosh_nd: f64[32, 16, 4, 2] = empty((32, 16, 4, 2), dtype=float64) for i in range(32): for j in range(16): @@ -126,7 +126,7 @@ def elemental_trig_identity(): identity3 = 2.0 * arcsinh(arraynd) - arccosh((arraynd**2.0) * 2.0 + 1.0) - newshape: i32[1] = empty(1, dtype=int) + newshape: i32[1] = empty(1, dtype=int32) newshape[0] = 400 observed1d_1 = reshape(identity1, newshape) diff --git a/integration_tests/elemental_10.py b/integration_tests/elemental_10.py index ad742e2a13..3583d13806 100644 --- a/integration_tests/elemental_10.py +++ b/integration_tests/elemental_10.py @@ -1,4 +1,4 @@ -from ltypes import i32, i64, f64 +from lpython import i32, i64, f64 from numpy import mod, int64, empty def test_numpy_mod(): diff --git a/integration_tests/elemental_11.py b/integration_tests/elemental_11.py index 409150b2ac..ca6b111902 100644 --- a/integration_tests/elemental_11.py +++ b/integration_tests/elemental_11.py @@ -1,5 +1,5 @@ -from ltypes import i32, f64, f32 -from numpy import empty, arctanh, reshape, float64, sinh, sqrt, sin, cosh +from lpython import i32, f64, f32 +from numpy import empty, arctanh, reshape, int32, float32, float64, sinh, sqrt, sin, cosh def verify1d_arctanh(array: f32[:], result: f32[:], size: i32): i: i32 @@ -27,8 +27,8 @@ def elemental_arctanh(): j: i32 k: i32 - array1d: f32[999] = empty(999) - arctanh1d: f32[999] = empty(999) + array1d: f32[999] = empty(999, dtype=float32) + arctanh1d: f32[999] = empty(999, dtype=float32) for i in range(999): array1d[i] = f32(f64((-1)**i) * (float(i)/1000.0)) @@ -36,8 +36,8 @@ def elemental_arctanh(): arctanh1d = arctanh(array1d) verify1d_arctanh(array1d, arctanh1d, 999) - arraynd: f64[100, 50, 10] = empty((100, 50, 10)) - arctanhnd: f64[100, 50, 10] = empty((100, 50, 10)) + arraynd: f64[100, 50, 10] = empty((100, 50, 10), dtype=float64) + arctanhnd: f64[100, 50, 10] = empty((100, 50, 10), dtype=float64) for i in range(100): for j in range(50): @@ -70,7 +70,7 @@ def elemental_trig_identity(): identity1 = 2.0 * arctanh(arraynd) - arctanh((2.0 * arraynd) / ( 1.0 + arraynd**2.0)) identity2 = cosh(arctanh(arraynd)) - (sqrt(1.0 - (arraynd**2.0)))**(-1.0) - newshape: i32[1] = empty(1, dtype=int) + newshape: i32[1] = empty(1, dtype=int32) newshape[0] = 400 observed1d_1 = reshape(identity1, newshape) diff --git a/integration_tests/elemental_12.py b/integration_tests/elemental_12.py index 5bfbd1b3d7..d81baf7293 100644 --- a/integration_tests/elemental_12.py +++ b/integration_tests/elemental_12.py @@ -1,5 +1,5 @@ -from ltypes import i32, f32, f64 -from numpy import empty, floor, ceil, sqrt, reshape +from lpython import i32, f32, f64 +from numpy import empty, floor, ceil, sqrt, reshape, int32, float32, float64 def elemental_floor64(): i: i32 @@ -9,9 +9,9 @@ def elemental_floor64(): eps: f32 eps = f32(1e-6) - arraynd: f64[32, 16, 8, 4] = empty((32, 16, 8, 4)) + arraynd: f64[32, 16, 8, 4] = empty((32, 16, 8, 4), dtype=float64) - newshape: i32[1] = empty(1, dtype=int) + newshape: i32[1] = empty(1, dtype=int32) newshape[0] = 16384 for i in range(32): @@ -20,13 +20,13 @@ def elemental_floor64(): for l in range(4): arraynd[i, j, k, l] = f64((-1)**l) * sqrt(float(i + j + k + l)) - observed: f64[32, 16, 8, 4] = empty((32, 16, 8, 4)) + observed: f64[32, 16, 8, 4] = empty((32, 16, 8, 4), dtype=float64) observed = floor(arraynd) - observed1d: f64[16384] = empty(16384) + observed1d: f64[16384] = empty(16384, dtype=float64) observed1d = reshape(observed, newshape) - array: f64[16384] = empty(16384) + array: f64[16384] = empty(16384, dtype=float64) array = reshape(arraynd, newshape) for i in range(16384): @@ -41,7 +41,7 @@ def elemental_floor32(): eps: f32 eps = f32(1e-6) - arraynd: f32[32, 16, 8, 4] = empty((32, 16, 8, 4)) + arraynd: f32[32, 16, 8, 4] = empty((32, 16, 8, 4), dtype=float32) for i in range(32): for j in range(16): @@ -49,7 +49,7 @@ def elemental_floor32(): for l in range(4): arraynd[i, j, k, l] = f32(f64((-1)**l) * sqrt(float(i + j + k + l))) - observed: f32[32, 16, 8, 4] = empty((32, 16, 8, 4)) + observed: f32[32, 16, 8, 4] = empty((32, 16, 8, 4), dtype=float32) observed = floor(arraynd) for i in range(32): @@ -67,9 +67,9 @@ def elemental_ceil64(): eps: f32 eps = f32(1e-6) - arraynd: f64[32, 16, 8, 4] = empty((32, 16, 8, 4)) + arraynd: f64[32, 16, 8, 4] = empty((32, 16, 8, 4), dtype=float64) - newshape: i32[1] = empty(1, dtype=int) + newshape: i32[1] = empty(1, dtype=int32) newshape[0] = 16384 for i in range(32): @@ -78,13 +78,13 @@ def elemental_ceil64(): for l in range(4): arraynd[i, j, k, l] = f64((-1)**l) * sqrt(float(i + j + k + l)) - observed: f64[32, 16, 8, 4] = empty((32, 16, 8, 4)) + observed: f64[32, 16, 8, 4] = empty((32, 16, 8, 4), dtype=float64) observed = ceil(arraynd) - observed1d: f64[16384] = empty(16384) + observed1d: f64[16384] = empty(16384, dtype=float64) observed1d = reshape(observed, newshape) - array: f64[16384] = empty(16384) + array: f64[16384] = empty(16384, dtype=float64) array = reshape(arraynd, newshape) for i in range(16384): @@ -99,7 +99,7 @@ def elemental_ceil32(): eps: f32 eps = f32(1e-6) - arraynd: f32[32, 16, 8, 4] = empty((32, 16, 8, 4)) + arraynd: f32[32, 16, 8, 4] = empty((32, 16, 8, 4), dtype=float32) for i in range(32): for j in range(16): @@ -107,7 +107,7 @@ def elemental_ceil32(): for l in range(4): arraynd[i, j, k, l] = f32(f64((-1)**l) * sqrt(float(i + j + k + l))) - observed: f32[32, 16, 8, 4] = empty((32, 16, 8, 4)) + observed: f32[32, 16, 8, 4] = empty((32, 16, 8, 4), dtype=float32) observed = ceil(arraynd) for i in range(32): diff --git a/integration_tests/elemental_13.py b/integration_tests/elemental_13.py new file mode 100644 index 0000000000..d0e03ea985 --- /dev/null +++ b/integration_tests/elemental_13.py @@ -0,0 +1,124 @@ +from lpython import f32, f64 +from numpy import trunc, fix, empty, sqrt, reshape, int32, float32, float64 + + +def elemental_trunc64(): + i: i32 + j: i32 + k: i32 + l: i32 + eps: f32 + eps = f32(1e-6) + + arraynd: f64[32, 16, 8, 4] = empty((32, 16, 8, 4), dtype=float64) + + newshape: i32[1] = empty(1, dtype = int32) + newshape[0] = 16384 + + for i in range(32): + for j in range(16): + for k in range(8): + for l in range(4): + arraynd[i, j, k, l] = f64((-1)**l) * sqrt(float(i + j + j + l)) + + observed: f64[32, 16, 8, 4] = empty((32, 16, 8, 4), dtype=float64) + observed = trunc(arraynd) + + observed1d: f64[16384] = empty(16384, dtype=float64) + observed1d = reshape(observed, newshape) + + array: f64[16384] = empty(16384, dtype=float64) + array = reshape(arraynd, newshape) + + for i in range(16384): + assert f32(abs(trunc(array[i]) - observed1d[i])) <= eps + + +def elemental_trunc32(): + i: i32 + j: i32 + k: i32 + l: i32 + eps: f32 + eps = f32(1e-6) + + arraynd: f32[32, 16, 8, 4] = empty((32, 16, 8, 4), dtype=float32) + + for i in range(32): + for j in range(16): + for k in range(8): + for l in range(4): + arraynd[i, j, k, l] = f32(f64((-1)**l) * sqrt(float(i + j + j + l))) + + observed: f32[32, 16, 8, 4] = empty((32, 16, 8, 4), dtype=float32) + observed = trunc(arraynd) + + for i in range(32): + for j in range(16): + for k in range(8): + for l in range(4): + assert abs(trunc(arraynd[i, j, k, l]) - observed[i, j, k, l]) <= eps + + +def elemental_fix64(): + i: i32 + j: i32 + k: i32 + l: i32 + eps: f32 + eps = f32(1e-6) + + arraynd: f64[32, 16, 8, 4] = empty((32, 16, 8, 4), dtype=float64) + + newshape: i32[1] = empty(1, dtype = int32) + newshape[0] = 16384 + + for i in range(32): + for j in range(16): + for k in range(8): + for l in range(4): + arraynd[i, j, k, l] = f64((-1)**l) * sqrt(float(i + j + j + l)) + + observed: f64[32, 16, 8, 4] = empty((32, 16, 8, 4), dtype=float64) + observed = fix(arraynd) + + observed1d: f64[16384] = empty(16384, dtype=float64) + observed1d = reshape(observed, newshape) + + array: f64[16384] = empty(16384, dtype=float64) + array = reshape(arraynd, newshape) + + for i in range(16384): + assert f32(abs(fix(array[i]) - observed1d[i])) <= eps + + +def elemental_fix32(): + i: i32 + j: i32 + k: i32 + l: i32 + eps: f32 + eps = f32(1e-6) + + arraynd: f32[32, 16, 8, 4] = empty((32, 16, 8, 4), dtype=float32) + + for i in range(32): + for j in range(16): + for k in range(8): + for l in range(4): + arraynd[i, j, k, l] = f32(f64((-1)**l) * sqrt(float(i + j + j + l))) + + observed: f32[32, 16, 8, 4] = empty((32, 16, 8, 4), dtype=float32) + observed = fix(arraynd) + + for i in range(32): + for j in range(16): + for k in range(8): + for l in range(4): + assert abs(fix(arraynd[i, j, k, l]) - observed[i, j, k, l]) <= eps + + +elemental_trunc64() +elemental_trunc32() +elemental_fix64() +elemental_fix32() diff --git a/integration_tests/enum_01.py b/integration_tests/enum_01.py index 1e2288e8c4..3c043c767e 100644 --- a/integration_tests/enum_01.py +++ b/integration_tests/enum_01.py @@ -1,4 +1,4 @@ -from ltypes import i32 +from lpython import i32 from enum import Enum class Color(Enum): diff --git a/integration_tests/enum_02.py b/integration_tests/enum_02.py index 5dec80442f..c36210d2dd 100644 --- a/integration_tests/enum_02.py +++ b/integration_tests/enum_02.py @@ -1,5 +1,5 @@ from enum import Enum -from ltypes import i32, f64 +from lpython import i32, f64 class MolecularMass(Enum): water: i32 = 18 diff --git a/integration_tests/enum_03.py b/integration_tests/enum_03.py index 2b82c1f32a..b087ee7426 100644 --- a/integration_tests/enum_03.py +++ b/integration_tests/enum_03.py @@ -1,5 +1,5 @@ from enum import Enum -from ltypes import i32 +from lpython import i32 class NegativeNumbers(Enum): a: i32 = -1 diff --git a/integration_tests/enum_04.py b/integration_tests/enum_04.py index 1356fe3600..4b01f3fb79 100644 --- a/integration_tests/enum_04.py +++ b/integration_tests/enum_04.py @@ -1,4 +1,4 @@ -from ltypes import i32 +from lpython import i32 from enum import Enum, auto class Color(Enum): diff --git a/integration_tests/enum_05.py b/integration_tests/enum_05.py index 1510aa2236..a3a424e7c9 100644 --- a/integration_tests/enum_05.py +++ b/integration_tests/enum_05.py @@ -1,4 +1,4 @@ -from ltypes import i32, ccall +from lpython import i32, ccall from enum import Enum @ccall diff --git a/integration_tests/enum_06.py b/integration_tests/enum_06.py index 70111ab890..e50a0ca0a7 100644 --- a/integration_tests/enum_06.py +++ b/integration_tests/enum_06.py @@ -1,4 +1,4 @@ -from ltypes import i32, dataclass, f64 +from lpython import i32, dataclass, f64 from numpy import empty from enum import Enum diff --git a/integration_tests/enum_07.py b/integration_tests/enum_07.py new file mode 100644 index 0000000000..204443130a --- /dev/null +++ b/integration_tests/enum_07.py @@ -0,0 +1,7 @@ +from enum_07_module import Constants + +def check(): + assert Constants.NUM_ELEMS.value == 4 + assert Constants.NUM_CHECK.value == 51 + +check() diff --git a/integration_tests/enum_07_module.py b/integration_tests/enum_07_module.py new file mode 100644 index 0000000000..a42956ec59 --- /dev/null +++ b/integration_tests/enum_07_module.py @@ -0,0 +1,6 @@ +from enum import Enum +from lpython import i32 + +class Constants(Enum): + NUM_ELEMS: i32 = 4 + NUM_CHECK: i32 = 51 diff --git a/integration_tests/exit_03.py b/integration_tests/exit_03.py new file mode 100644 index 0000000000..e7c5304c6b --- /dev/null +++ b/integration_tests/exit_03.py @@ -0,0 +1,6 @@ +def main0(): + print("Before") + quit(0) + print("After") + +main0() diff --git a/integration_tests/exit_04.py b/integration_tests/exit_04.py new file mode 100644 index 0000000000..cd27645e18 --- /dev/null +++ b/integration_tests/exit_04.py @@ -0,0 +1,6 @@ +def main0(): + print("Before") + quit(1) + print("After") + +main0() diff --git a/integration_tests/expr_01.py b/integration_tests/expr_01.py index 4baa148c68..3bd2e6b139 100644 --- a/integration_tests/expr_01.py +++ b/integration_tests/expr_01.py @@ -1,4 +1,4 @@ -from ltypes import inline, i32 +from lpython import inline, i32 @inline def add(x: i32, y: i32) -> i32: diff --git a/integration_tests/expr_01u.py b/integration_tests/expr_01u.py new file mode 100644 index 0000000000..1ae3bb52fc --- /dev/null +++ b/integration_tests/expr_01u.py @@ -0,0 +1,41 @@ +from lpython import inline, u32, u64, i64, i32, u16 + +@inline +def uadd(x: u32, y: u32) -> u32: + return x + y + +@inline +def uand_op(x: u32, y: u32) -> u32: + return x & y + +def main1(): + x: u32 + y: u32 + z: u32 + x = (u32(2)+u32(3))*u32(5) + y = uadd(x, u32(2))*u32(2) + assert x == u32(25) + assert y == u32(54) + + z = uand_op(x, y) + assert z == u32(16) + + # test issue 1867 + cycles_count: u64 + end_cycle: i64 = i64(100) + start_cycle: i64 = i64(4) + num_iters: i64 = i64(4) + cycles_count = u64((end_cycle - start_cycle) / num_iters) + assert cycles_count == u64(24) + + # test issue 1949 + x1: i32 = 20 + y1: i32 = 10 + assert u16(x1) > u16(y1) + + +main1() + +# Not implemented yet in LPython: +#if __name__ == "__main__": +# main() diff --git a/integration_tests/expr_02.py b/integration_tests/expr_02.py index af8540d83d..3b3679ba55 100644 --- a/integration_tests/expr_02.py +++ b/integration_tests/expr_02.py @@ -7,7 +7,6 @@ def main0(): b = a or True a = a or b -main0() -# Not implemented yet in LPython: -#if __name__ == "__main__": -# main() + +if __name__ == "__main__": + main0() diff --git a/integration_tests/expr_02u.py b/integration_tests/expr_02u.py new file mode 100644 index 0000000000..962c449082 --- /dev/null +++ b/integration_tests/expr_02u.py @@ -0,0 +1,78 @@ +from lpython import u8, u16, u32, u64 + +def add_u8(x: u8, y: u8) -> u8: + return x + y + +def add_u16(x: u16, y: u16) -> u16: + return x + y + +def add_u32(x: u32, y: u32) -> u32: + return x + y + +def add_u64(x: u64, y: u64) -> u64: + return x + y + +def and_u8(x: u8, y: u8) -> u8: + return x & y + +def and_u16(x: u16, y: u16) -> u16: + return x & y + +def and_u32(x: u32, y: u32) -> u32: + return x & y + +def and_u64(x: u64, y: u64) -> u64: + return x & y + +def main_u8(): + x: u8 + y: u8 + z: u8 + x = (u8(2)+u8(3))*u8(5) + y = add_u8(x, u8(2))*u8(2) + z = and_u8(x, y) + assert x == u8(25) + assert y == u8(54) + assert z == u8(16) + +def main_u16(): + x: u16 + y: u16 + z: u16 + x = (u16(2)+u16(3))*u16(5) + y = add_u16(x, u16(2))*u16(2) + z = and_u16(x, y) + assert x == u16(25) + assert y == u16(54) + assert z == u16(16) + +def main_u32(): + x: u32 + y: u32 + z: u32 + x = (u32(2)+u32(3))*u32(5) + y = add_u32(x, u32(2))*u32(2) + z = and_u32(x, y) + assert x == u32(25) + assert y == u32(54) + assert z == u32(16) + +def main_u64(): + x: u64 + y: u64 + z: u64 + x = (u64(2)+u64(3))*u64(5) + y = add_u64(x, u64(2))*u64(2) + z = and_u64(x, y) + assert x == u64(25) + assert y == u64(54) + assert z == u64(16) + +main_u8() +main_u16() +main_u32() +main_u64() + +# Not implemented yet in LPython: +#if __name__ == "__main__": +# main() diff --git a/integration_tests/expr_03.py b/integration_tests/expr_03.py index 8b673cd4ff..d22e93e9f2 100644 --- a/integration_tests/expr_03.py +++ b/integration_tests/expr_03.py @@ -1,3 +1,5 @@ +from lpython import i32 + def main0(): x: i32 x = 5 diff --git a/integration_tests/expr_03u.py b/integration_tests/expr_03u.py new file mode 100644 index 0000000000..7ab7b16de3 --- /dev/null +++ b/integration_tests/expr_03u.py @@ -0,0 +1,159 @@ +from lpython import u8, u16, u32, u64, i8, i32, TypeVar +from numpy import (empty, uint8, uint16, uint32, uint64, int8, int16, int32, + int64, size) + +n = TypeVar("n") +def add_i8(n: i32, x: i8[n], y: i8[n]) -> i8[n]: + return x + y + +def add_i8_loop(n: i32, x: i8[n], y: i8[n]) -> i8[n]: + z: i8[n] = empty(n, dtype=int8) + i: i32 + for i in range(n): + z[i] = x[i] + y[i] + return z + +def add_u8(n: i32, x: u8[n], y: u8[n]) -> u8[n]: + return x + y + +def add_u8_loop(n: i32, x: u8[n], y: u8[n]) -> u8[n]: + z: u8[n] = empty(n, dtype=uint8) + i: i32 + for i in range(n): + z[i] = x[i] + y[i] + return z + +def add_u16(n: i32, x: u16[n], y: u16[n]) -> u16[n]: + return x + y + +def add_u16_loop(n: i32, x: u16[n], y: u16[n]) -> u16[n]: + z: u16[n] = empty(n, dtype=uint16) + i: i32 + for i in range(n): + z[i] = x[i] + y[i] + return z + +def add_u32(n: i32, x: u32[n], y: u32[n]) -> u32[n]: + return x + y + +def add_u32_loop(n: i32, x: u32[n], y: u32[n]) -> u32[n]: + z: u32[n] = empty(n, dtype=uint32) + i: i32 + for i in range(n): + z[i] = x[i] + y[i] + return z + +def add_u64(n: i32, x: u64[n], y: u64[n]) -> u64[n]: + return x + y + +def add_u64_loop(n: i32, x: u64[n], y: u64[n]) -> u64[n]: + z: u64[n] = empty(n, dtype=uint64) + i: i32 + for i in range(n): + z[i] = x[i] + y[i] + return z + +def main_i8(): + x: i8[3] = empty(3, dtype=int8) + y: i8[3] = empty(3, dtype=int8) + z: i8[3] = empty(3, dtype=int8) + x[0] = i8(1) + x[1] = i8(2) + x[2] = i8(3) + y[0] = i8(2) + y[1] = i8(3) + y[2] = i8(4) + z = add_i8(size(x), x, y) + assert z[0] == i8(3) + assert z[1] == i8(5) + assert z[2] == i8(7) + z = add_i8_loop(size(x), x, y) + assert z[0] == i8(3) + assert z[1] == i8(5) + assert z[2] == i8(7) + +def main_u8(): + x: u8[3] = empty(3, dtype=uint8) + y: u8[3] = empty(3, dtype=uint8) + z: u8[3] = empty(3, dtype=uint8) + x[0] = u8(1) + x[1] = u8(2) + x[2] = u8(3) + y[0] = u8(2) + y[1] = u8(3) + y[2] = u8(4) + z = add_u8(size(x), x, y) + assert z[0] == u8(3) + assert z[1] == u8(5) + assert z[2] == u8(7) + z = add_u8_loop(size(x), x, y) + assert z[0] == u8(3) + assert z[1] == u8(5) + assert z[2] == u8(7) + +def main_u16(): + x: u16[3] = empty(3, dtype=uint16) + y: u16[3] = empty(3, dtype=uint16) + z: u16[3] = empty(3, dtype=uint16) + x[0] = u16(1) + x[1] = u16(2) + x[2] = u16(3) + y[0] = u16(2) + y[1] = u16(3) + y[2] = u16(4) + z = add_u16(size(x), x, y) + assert z[0] == u16(3) + assert z[1] == u16(5) + assert z[2] == u16(7) + z = add_u16_loop(size(x), x, y) + assert z[0] == u16(3) + assert z[1] == u16(5) + assert z[2] == u16(7) + +def main_u32(): + x: u32[3] = empty(3, dtype=uint32) + y: u32[3] = empty(3, dtype=uint32) + z: u32[3] = empty(3, dtype=uint32) + x[0] = u32(1) + x[1] = u32(2) + x[2] = u32(3) + y[0] = u32(2) + y[1] = u32(3) + y[2] = u32(4) + z = add_u32(size(x), x, y) + assert z[0] == u32(3) + assert z[1] == u32(5) + assert z[2] == u32(7) + z = add_u32_loop(size(x), x, y) + assert z[0] == u32(3) + assert z[1] == u32(5) + assert z[2] == u32(7) + +def main_u64(): + x: u64[3] = empty(3, dtype=uint64) + y: u64[3] = empty(3, dtype=uint64) + z: u64[3] = empty(3, dtype=uint64) + x[0] = u64(1) + x[1] = u64(2) + x[2] = u64(3) + y[0] = u64(2) + y[1] = u64(3) + y[2] = u64(4) + z = add_u64(size(x), x, y) + assert z[0] == u64(3) + assert z[1] == u64(5) + assert z[2] == u64(7) + z = add_u64_loop(size(x), x, y) + assert z[0] == u64(3) + assert z[1] == u64(5) + assert z[2] == u64(7) + +main_i8() +main_u8() +main_u16() +main_u32() +main_u64() + +# Not implemented yet in LPython: +#if __name__ == "__main__": +# main() diff --git a/integration_tests/expr_04.py b/integration_tests/expr_04.py index 75a16e37f0..ad46256039 100644 --- a/integration_tests/expr_04.py +++ b/integration_tests/expr_04.py @@ -1,4 +1,4 @@ -from ltypes import i32, f32, f64, i64 +from lpython import i32, f32, f64, i64 def main0(): i: i32 sum: i32 diff --git a/integration_tests/expr_04u.py b/integration_tests/expr_04u.py new file mode 100644 index 0000000000..5c4a22bb8d --- /dev/null +++ b/integration_tests/expr_04u.py @@ -0,0 +1,12 @@ +from lpython import u8, u16, u32, u64 + +FLAG1 : u8 = u8(1) << u8(4) +FLAG2 : u16 = u16(1) << u16(4) +FLAG3: u32 = u32(1) << u32(4) +FLAG4: u64 = u64(1) << u64(4) + +print(FLAG1, FLAG2, FLAG3, FLAG4) +assert FLAG1 == u8(16) +assert FLAG2 == u16(16) +assert FLAG3 == u32(16) +assert FLAG4 == u64(16) diff --git a/integration_tests/expr_05.py b/integration_tests/expr_05.py index f02d26f1a1..08748469b7 100644 --- a/integration_tests/expr_05.py +++ b/integration_tests/expr_05.py @@ -1,4 +1,4 @@ -from ltypes import i32, i64 +from lpython import i32, i64, f64, u16 def test_multiply(a: i32, b: i32) -> i32: return a*b @@ -78,5 +78,12 @@ def main0(): assert abs((11.0%-3.0) - (-1.0)) < eps assert abs((-11.0%3.0) - (1.0)) < eps + # Test issue 1869 and 1870 + a1: u16 = u16(10) + b1: u16 = u16(3) + c1: u16 = a1 % b1 + assert c1 == u16(1) + c1 = a1 // b1 + assert c1 == u16(3) main0() diff --git a/integration_tests/expr_06.py b/integration_tests/expr_06.py index 3df110803c..566530ddb1 100644 --- a/integration_tests/expr_06.py +++ b/integration_tests/expr_06.py @@ -1,11 +1,11 @@ -from ltypes import i32, f32, f64 -from numpy import empty, cos, sin +from lpython import i32, f32, f64 +from numpy import empty, cos, sin, int32 def main0(): x: i32 = 25 y: i32 = (2 + 3) * 5 z: f32 = (f32(2.0) + f32(3)) * f32(5.0) - xa: i32[3] = empty(3) + xa: i32[3] = empty(3, dtype=int32) assert x == 25 assert y == 25 assert z == f32(25.0) diff --git a/integration_tests/expr_07.py b/integration_tests/expr_07.py index 5e78dbf46d..788fc41b58 100644 --- a/integration_tests/expr_07.py +++ b/integration_tests/expr_07.py @@ -1,4 +1,4 @@ -from ltypes import i32 +from lpython import i32 def g(x: i32): print(x) diff --git a/integration_tests/expr_08.py b/integration_tests/expr_08.py index 1956c68c8c..0589fcee66 100644 --- a/integration_tests/expr_08.py +++ b/integration_tests/expr_08.py @@ -1,4 +1,4 @@ -from ltypes import pointer, i16, Pointer +from lpython import pointer, i16, Pointer # Testing Global Pointers x: Pointer[i16[:]] diff --git a/integration_tests/expr_09.py b/integration_tests/expr_09.py index 4fb021173f..a64e5eb35f 100644 --- a/integration_tests/expr_09.py +++ b/integration_tests/expr_09.py @@ -1,4 +1,4 @@ -from ltypes import i32, f64, f32 +from lpython import i32, f64, f32 def main0(): i1: i32 = 10 diff --git a/integration_tests/expr_10.py b/integration_tests/expr_10.py index 24da1000ee..28a715f3e0 100644 --- a/integration_tests/expr_10.py +++ b/integration_tests/expr_10.py @@ -1,4 +1,4 @@ -from ltypes import i32 +from lpython import i32 def g() -> i32: return 5 diff --git a/integration_tests/expr_11.py b/integration_tests/expr_11.py index b72fd1b982..1e27e821b5 100644 --- a/integration_tests/expr_11.py +++ b/integration_tests/expr_11.py @@ -1,4 +1,4 @@ -from ltypes import i32 +from lpython import i32 def f(): i: i32 diff --git a/integration_tests/expr_12.py b/integration_tests/expr_12.py index 4933a04481..2707f0122f 100644 --- a/integration_tests/expr_12.py +++ b/integration_tests/expr_12.py @@ -1,4 +1,4 @@ -from ltypes import pointer, i16, Pointer +from lpython import pointer, i16, Pointer def g(x: Pointer[i16[:]], y: i16[:]): y[0] = i16(1) diff --git a/integration_tests/expr_13.py b/integration_tests/expr_13.py index 93ed7ba446..e9c386f12c 100644 --- a/integration_tests/expr_13.py +++ b/integration_tests/expr_13.py @@ -1,4 +1,4 @@ -from ltypes import CPtr, empty_c_void_p, i32, Pointer, ccall, Const +from lpython import CPtr, empty_c_void_p, i32, Pointer, ccall, Const @ccall def deref_array(x: Pointer[CPtr], idx: i32) -> CPtr: diff --git a/integration_tests/expr_14.py b/integration_tests/expr_14.py index 7cbd452bcd..5b22fee92c 100644 --- a/integration_tests/expr_14.py +++ b/integration_tests/expr_14.py @@ -1,4 +1,4 @@ -from ltypes import i32, i64, f32, f64, c32, c64 +from lpython import i32, i64, f32, f64, c32, c64 def test_divide(): a1: i32; a2: i32; a3: f64; diff --git a/integration_tests/expr_15.py b/integration_tests/expr_15.py index 51b47d7ced..2cf6dfa608 100644 --- a/integration_tests/expr_15.py +++ b/integration_tests/expr_15.py @@ -1,4 +1,4 @@ -from ltypes import i8, i16 +from lpython import i8, i16 def test_issue_1586(): x4: i16 @@ -13,7 +13,21 @@ def test_issue_1586(): b4 = i8(123) assert b4//a4 == i8(12) +def test_issue_1619(): + a: i16 + b: i16 + a = i16(10) + b = i16(12345) + assert b%a == i16(5) + + c: i8 + d: i8 + c = i8(10) + d = i8(123) + assert d%c == i8(3) + def check(): test_issue_1586() + test_issue_1619() check() diff --git a/integration_tests/expr_16.py b/integration_tests/expr_16.py new file mode 100644 index 0000000000..9a831d3765 --- /dev/null +++ b/integration_tests/expr_16.py @@ -0,0 +1,22 @@ +from lpython import f64, Pointer, c_p_pointer, ccall, i32, CPtr, sizeof +from numpy import array + +@ccall +def _lfortran_malloc(size: i32) -> CPtr: + pass + +def foo(xs_ptr: CPtr, length: i32) -> None: + xs: Pointer[f64[:]] = c_p_pointer(xs_ptr, f64[:], array([length])) + xs[0] = 3.0 + xs[1] = 4.0 + +def main() -> None: + length: i32 = 32 + xs_ptr: CPtr = _lfortran_malloc(length * i32(sizeof(f64))) + foo(xs_ptr, length) + t: Pointer[f64[:]] = c_p_pointer(xs_ptr, f64[:], array([32])) + print(t[0], t[1]) + assert t[0] == 3.0 + assert t[1] == 4.0 + +main() diff --git a/integration_tests/expr_17.py b/integration_tests/expr_17.py new file mode 100644 index 0000000000..eea47d9459 --- /dev/null +++ b/integration_tests/expr_17.py @@ -0,0 +1,16 @@ +from lpython import i32, f64 + +def main0(): + a: i32 = 4 + b: i32 = 3 + c: i32 = 12 + assert a * b == c, a * b + + d: f64 = 0.4 + e: f64 = 2.5 + f: f64 = 1.0 + assert abs((d * e) - f) <= 1e-6, abs((d * e) - f) + + assert a == b + 1, "Failed: a == b + 1" + +main0() diff --git a/integration_tests/expr_18.py b/integration_tests/expr_18.py new file mode 100644 index 0000000000..edfb17c327 --- /dev/null +++ b/integration_tests/expr_18.py @@ -0,0 +1,9 @@ +from lpython import i32, f64 + +def main0(): + a: i32 = 4 + b: i32 = 3 + c: i32 = 12 + assert a * b != c, "Error: 3 * 4 equals 12" + +main0() diff --git a/integration_tests/expr_19.py b/integration_tests/expr_19.py new file mode 100644 index 0000000000..6fe7a95998 --- /dev/null +++ b/integration_tests/expr_19.py @@ -0,0 +1,7 @@ +from lpython import (f64,) + +result : f64 = f64(14) +divisor : f64 = f64(4) +result /= divisor + +assert abs(result - f64(3.5)) < 1e-12 diff --git a/integration_tests/expr_20.py b/integration_tests/expr_20.py new file mode 100644 index 0000000000..f12636e845 --- /dev/null +++ b/integration_tests/expr_20.py @@ -0,0 +1,16 @@ +from lpython import i16, i32 + +def f(): + i: i32 = 5 + print(i16(i % 1023)) + +def u16(x: i16) -> i32: + if x >= i16(0): + return i32(x) + else: + return i32(x) + 65536 + +f() +print(u16(i16(10)), u16(i16(-10))) +assert(u16(i16(10)) == 10) +assert(u16(i16(-10)) == 65526) diff --git a/integration_tests/expr_21.py b/integration_tests/expr_21.py new file mode 100644 index 0000000000..e07693c580 --- /dev/null +++ b/integration_tests/expr_21.py @@ -0,0 +1,21 @@ +from lpython import i8, i16, i32, i64 + +def main0(): + x: i8 + y: i16 + z: i32 + w: i64 + + x = i8(97) + y = i16(47) + z = 56 + w = i64(67) + + print(chr(x), chr(y), chr(z), chr(w)) + + assert chr(x) == 'a' + assert chr(y) == '/' + assert chr(z) == '8' + assert chr(w) == 'C' + +main0() diff --git a/integration_tests/expr_22.py b/integration_tests/expr_22.py new file mode 100644 index 0000000000..5b61bebc35 --- /dev/null +++ b/integration_tests/expr_22.py @@ -0,0 +1,10 @@ +from lpython import f64 + +# test issue 1671 +def test_fast_fma() -> f64: + a : f64 = 5.00 + a = a + a * 10.00 + assert abs(a - 55.00) < 1e-12 + return a + +print(test_fast_fma()) diff --git a/integration_tests/expr_23.py b/integration_tests/expr_23.py new file mode 100644 index 0000000000..5aa5244d8a --- /dev/null +++ b/integration_tests/expr_23.py @@ -0,0 +1,23 @@ +from lpython import f32, i32 + +def flip_sign_check(): + x: f32 + eps: f32 = f32(1e-5) + + number: i32 = 123 + x = f32(5.5) + + if (number%2 == 1): + x = -x + + assert abs(x - f32(-5.5)) < eps + + number = 124 + x = f32(5.5) + + if (number%2 == 1): + x = -x + + assert abs(x - f32(5.5)) < eps + +flip_sign_check() diff --git a/integration_tests/expr_24.py b/integration_tests/expr_24.py new file mode 100644 index 0000000000..a616e2cc33 --- /dev/null +++ b/integration_tests/expr_24.py @@ -0,0 +1,77 @@ +from lpython import i32, f64, TypeVar, Const +from numpy import empty, int32 + +h = TypeVar("h") +w = TypeVar("w") + +def show_img(w: i32, h: i32, A: i32[h, w]): + print(w, h) + print(A[0, 0]) + print(A[h - 1, w - 1]) + + assert w == 600 + assert h == 450 + assert A[0, 0] == 254 + assert A[h - 1, w - 1] == 254 + +def show_img_color(w: i32, h: i32, A: i32[h, w, 4]): + print(w, h) + print(A[0, 0, 0]) + print(A[h - 1, w - 1, 3]) + + assert w == 600 + assert h == 450 + assert A[0, 0, 0] == 214 + assert A[h - 1, w - 1, 3] == 255 + +def main0(): + Nx: Const[i32] = 600; Ny: Const[i32] = 450; Nz: Const[i32] = 4; n_max: i32 = 255 + + xcenter: f64 = f64(-0.5); ycenter: f64 = f64(0.0) + width: f64 = f64(4); height: f64 = f64(3) + dx_di: f64 = width/f64(Nx); dy_dj: f64 = -height/f64(Ny) + x_offset: f64 = xcenter - f64(Nx+1)*dx_di/f64(2.0) + y_offset: f64 = ycenter - f64(Ny+1)*dy_dj/f64(2.0) + + i: i32; j: i32; n: i32; idx: i32 + x: f64; y: f64; x_0: f64; y_0: f64; x_sqr: f64; y_sqr: f64 + + image: i32[450, 600] = empty([Ny, Nx], dtype=int32) + image_color: i32[450, 600, 4] = empty([Ny, Nx, Nz], dtype=int32) + palette: i32[4, 3] = empty([4, 3], dtype=int32) + + for j in range(Ny): + y_0 = y_offset + dy_dj * f64(j + 1) + for i in range(Nx): + x_0 = x_offset + dx_di * f64(i + 1) + x = 0.0; y = 0.0; n = 0 + while(True): + x_sqr = x ** 2.0 + y_sqr = y ** 2.0 + if (x_sqr + y_sqr > f64(4) or n == n_max): + image[j,i] = 255 - n + break + y = y_0 + f64(2.0) * x * y + x = x_0 + x_sqr - y_sqr + n = n + 1 + + palette[0,0] = 0; palette[0,1] = 135; palette[0,2] = 68 + palette[1,0] = 0; palette[1,1] = 87; palette[1,2] = 231 + palette[2,0] = 214; palette[2,1] = 45; palette[2,2] = 32 + palette[3,0] = 255; palette[3,1] = 167; palette[3,2] = 0 + + for j in range(Ny): + for i in range(Nx): + idx = image[j,i] - i32(image[j,i]/4)*4 + image_color[j,i,0] = palette[idx,0] # Red + image_color[j,i,1] = palette[idx,1] # Green + image_color[j,i,2] = palette[idx,2] # Blue + image_color[j,i,3] = 255 # Alpha + + print("The Mandelbrot image in color:") + show_img_color(Nx, Ny, image_color) + print("The Mandelbrot image in grayscale:") + show_img(Nx, Ny, image) + print("Done.") + +main0() diff --git a/integration_tests/float_01.py b/integration_tests/float_01.py index fe5152d670..2826e44ea1 100644 --- a/integration_tests/float_01.py +++ b/integration_tests/float_01.py @@ -1,4 +1,4 @@ -from ltypes import f64 +from lpython import f64 def sqr(x: f64) -> f64: return x * x diff --git a/integration_tests/func_01.py b/integration_tests/func_01.py new file mode 100644 index 0000000000..0230bfcac2 --- /dev/null +++ b/integration_tests/func_01.py @@ -0,0 +1,14 @@ +from lpython import i32, InOut + +def reserve(a: InOut[list[i32]], b: i32): + a.append(b) + print("user defined reserve() called") + +def main0(): + x: list[i32] = [] + reserve(x, 5) + + assert len(x) == 1 + assert x[0] == 5 + +main0() diff --git a/integration_tests/func_02.py b/integration_tests/func_02.py new file mode 100644 index 0000000000..ea4fdf5b2b --- /dev/null +++ b/integration_tests/func_02.py @@ -0,0 +1,13 @@ +from lpython import S, Out +from sympy import pi + +def func(r: Out[S]) -> None: + r = pi + +def test_func(): + z: S + func(z) + print(z) + assert z == pi + +test_func() diff --git a/integration_tests/func_dep_03.py b/integration_tests/func_dep_03.py index d65a81c487..1e39f62c6a 100644 --- a/integration_tests/func_dep_03.py +++ b/integration_tests/func_dep_03.py @@ -1,4 +1,4 @@ -from ltypes import i32, i64 +from lpython import i32, i64 def casti32(x: i64) -> i32: y: i32 diff --git a/integration_tests/func_dep_04.py b/integration_tests/func_dep_04.py index 5319ef08d2..cb464eb716 100644 --- a/integration_tests/func_dep_04.py +++ b/integration_tests/func_dep_04.py @@ -1,5 +1,5 @@ from func_dep_04_module import manhattan_distance -from ltypes import i32 +from lpython import i32 def test_manhattan_distance(): a: i32; b: i32; c: i32; d: i32; diff --git a/integration_tests/func_dep_04_module.py b/integration_tests/func_dep_04_module.py index ec826ab60e..570d432088 100644 --- a/integration_tests/func_dep_04_module.py +++ b/integration_tests/func_dep_04_module.py @@ -1,4 +1,4 @@ -from ltypes import i32 +from lpython import i32 def manhattan_distance(x1: i32, y1: i32, x2: i32, y2: i32) -> i32: return abs(x1 - x2) + abs(y1 - y2) diff --git a/integration_tests/func_inline_01.py b/integration_tests/func_inline_01.py index 856a04ab4a..26173b52bd 100644 --- a/integration_tests/func_inline_01.py +++ b/integration_tests/func_inline_01.py @@ -1,4 +1,4 @@ -from ltypes import i64 +from lpython import i64 def fib(n: i64) -> i64: if n < i64(2): diff --git a/integration_tests/func_inline_02.py b/integration_tests/func_inline_02.py index f093a42c7b..89331d37a7 100644 --- a/integration_tests/func_inline_02.py +++ b/integration_tests/func_inline_02.py @@ -1,4 +1,4 @@ -from ltypes import i32, Const, inline +from lpython import i32, Const, inline @inline def f(x: i32) -> i32: diff --git a/integration_tests/func_internal_def_01.py b/integration_tests/func_internal_def_01.py new file mode 100644 index 0000000000..1c0c1d11e5 --- /dev/null +++ b/integration_tests/func_internal_def_01.py @@ -0,0 +1,11 @@ +def main(): + x: i32 + x = (2+3)*5 + print(x) + + def bar(): + assert x == 25 + + bar() + +main() diff --git a/integration_tests/func_static_01.py b/integration_tests/func_static_01.py index 0b0fbda394..c87377f36e 100644 --- a/integration_tests/func_static_01.py +++ b/integration_tests/func_static_01.py @@ -1,4 +1,4 @@ -from ltypes import i64, static +from lpython import i64, static @static def fib(n: i64) -> i64: diff --git a/integration_tests/func_static_02.py b/integration_tests/func_static_02.py index 74f802a126..85f8b0151d 100644 --- a/integration_tests/func_static_02.py +++ b/integration_tests/func_static_02.py @@ -1,4 +1,4 @@ -from ltypes import i64, static, inline +from lpython import i64, static, inline @static @inline diff --git a/integration_tests/generics_01.py b/integration_tests/generics_01.py index fd1603cf6a..c3f1357ade 100644 --- a/integration_tests/generics_01.py +++ b/integration_tests/generics_01.py @@ -1,4 +1,4 @@ -from ltypes import TypeVar, restriction, i32 +from lpython import TypeVar, restriction, i32 T = TypeVar('T') diff --git a/integration_tests/generics_02.py b/integration_tests/generics_02.py index 5e36813211..2507636102 100644 --- a/integration_tests/generics_02.py +++ b/integration_tests/generics_02.py @@ -1,8 +1,8 @@ -from ltypes import TypeVar +from lpython import TypeVar, InOut, i32 T = TypeVar('T') -def swap(x: T, y: T): +def swap(x: InOut[T], y: InOut[T]): temp: T temp = x x = y @@ -10,4 +10,20 @@ def swap(x: T, y: T): print(x) print(y) -swap(1,2) \ No newline at end of file +def main0(): + a: i32 = 5 + b: i32 = 10 + + # Invalid test case for CPython: + # CPython passes values by copy of object reference + # and hence does not support swapping variables + # passed by arguments. + # Therefore do not add asserts to this file + + print(a, b) + + swap(a, b) + + print(a, b) + +main0() diff --git a/integration_tests/generics_array_01.py b/integration_tests/generics_array_01.py index 4c733b7c4a..3ae77260ee 100644 --- a/integration_tests/generics_array_01.py +++ b/integration_tests/generics_array_01.py @@ -1,5 +1,5 @@ -from ltypes import TypeVar, i32 -from numpy import empty +from lpython import TypeVar, i32 +from numpy import empty, int32 T = TypeVar('T') @@ -9,9 +9,9 @@ def f(lst: T[:], i: T) -> T: def use_array(): array: i32[1] - array = empty(1) + array = empty(1, dtype=int32) x: i32 x = 69 print(f(array, x)) -use_array() \ No newline at end of file +use_array() diff --git a/integration_tests/generics_array_02.py b/integration_tests/generics_array_02.py index 94b23085ca..2315582ca0 100644 --- a/integration_tests/generics_array_02.py +++ b/integration_tests/generics_array_02.py @@ -1,7 +1,6 @@ -from ltypes import TypeVar, restriction, i32, f32 -from numpy import empty +from lpython import TypeVar, restriction, i32, f32 +from numpy import empty, int32, float32 -n: i32 n = TypeVar("n") T = TypeVar('T') @@ -17,21 +16,21 @@ def add_float(x: f32, y: f32) -> f32: def g(n: i32, a: T[n], b: T[n], **kwargs): r: T[n] - r = empty(n) + r = empty(n, dtype=object) i: i32 for i in range(n): r[i] = add(a[i], b[i]) print(r[0]) def main(): - a_int: i32[1] = empty(1) + a_int: i32[1] = empty(1, dtype=int32) a_int[0] = 400 - b_int: i32[1] = empty(1) + b_int: i32[1] = empty(1, dtype=int32) b_int[0] = 20 g(1, a_int, b_int, add=add_integer) - a_float: f32[1] = empty(1) + a_float: f32[1] = empty(1, dtype=float32) a_float[0] = f32(400.0) - b_float: f32[1] = empty(1) + b_float: f32[1] = empty(1, dtype=float32) b_float[0] = f32(20.0) g(1, a_float, b_float, add=add_float) diff --git a/integration_tests/generics_array_03.py b/integration_tests/generics_array_03.py index 8de3fe5908..ebc5875220 100644 --- a/integration_tests/generics_array_03.py +++ b/integration_tests/generics_array_03.py @@ -1,9 +1,7 @@ -from ltypes import TypeVar, restriction, i32, f32 -from numpy import empty +from lpython import TypeVar, restriction, i32, f32 +from numpy import empty, int32, float32 -n: i32 n = TypeVar("n") -m: i32 m = TypeVar("m") T = TypeVar('T') @@ -19,7 +17,7 @@ def add_float(x: f32, y: f32) -> f32: def g(n: i32, m: i32, a: T[n,m], b: T[n,m], **kwargs) -> T[n,m]: r: T[n,m] - r = empty([n,m]) + r = empty([n,m], dtype=object) i: i32 j: i32 for i in range(n): @@ -28,14 +26,14 @@ def g(n: i32, m: i32, a: T[n,m], b: T[n,m], **kwargs) -> T[n,m]: print(r[0,0]) def main(): - a_int: i32[1,1] = empty([1,1]) + a_int: i32[1,1] = empty([1,1], dtype=int32) a_int[0,0] = 400 - b_int: i32[1,1] = empty([1,1]) + b_int: i32[1,1] = empty([1,1], dtype=int32) b_int[0,0] = 20 g(1, 1, a_int, b_int, add=add_integer) - a_float: f32[1,1] = empty([1,1]) + a_float: f32[1,1] = empty([1,1], dtype=float32) a_float[0,0] = f32(400) - b_float: f32[1,1] = empty([1,1]) + b_float: f32[1,1] = empty([1,1], dtype=float32) b_float[0,0] = f32(20) g(1, 1, a_float, b_float, add=add_float) diff --git a/integration_tests/generics_list_01.py b/integration_tests/generics_list_01.py index ec76496b70..2d228532ce 100644 --- a/integration_tests/generics_list_01.py +++ b/integration_tests/generics_list_01.py @@ -1,4 +1,4 @@ -from ltypes import TypeVar, f64, i32, restriction +from lpython import TypeVar, f64, i32, restriction T = TypeVar('T') @@ -30,7 +30,7 @@ def add_float(x: f64, y: f64) -> f64: return x + y def div_float(x: f64, k: i32) -> f64: - return x / k + return x / f64(k) def empty_string(x: str) -> str: return "" diff --git a/integration_tests/global_syms_01.py b/integration_tests/global_syms_01.py index 808d324fcf..fbf9cbb97a 100644 --- a/integration_tests/global_syms_01.py +++ b/integration_tests/global_syms_01.py @@ -1,4 +1,4 @@ -from ltypes import i32 +from lpython import i32 x: list[i32] x = [1, 2] diff --git a/integration_tests/global_syms_02.py b/integration_tests/global_syms_02.py index d6ed192bac..840732e4cc 100644 --- a/integration_tests/global_syms_02.py +++ b/integration_tests/global_syms_02.py @@ -1,4 +1,4 @@ -from ltypes import i32 +from lpython import i32 x: list[i32] x = [0, 1] diff --git a/integration_tests/global_syms_03_a.py b/integration_tests/global_syms_03_a.py index 4f61061d53..ad8f62f759 100644 --- a/integration_tests/global_syms_03_a.py +++ b/integration_tests/global_syms_03_a.py @@ -1,7 +1,13 @@ -from ltypes import i32 +from lpython import i32, f64 + +print("Imported from global_syms_03_a") l_1: list[str] = ['Monday', 'Tuesday', 'Wednesday'] +l_1.append('Thursday') def populate_lists() -> list[i32]: return [10, -20] l_2: list[i32] = populate_lists() + +l_3: list[f64] +l_3 = [1.0, 2.0, 3.0] diff --git a/integration_tests/global_syms_03_b.py b/integration_tests/global_syms_03_b.py index 66295b1f1b..0d77cfc79e 100644 --- a/integration_tests/global_syms_03_b.py +++ b/integration_tests/global_syms_03_b.py @@ -1,5 +1,5 @@ from global_syms_03_a import l_1, l_2 -assert len(l_1) == 3 +assert len(l_1) == 4 assert l_1[1] == "Tuesday" assert l_2[1] == -20 diff --git a/integration_tests/global_syms_03_c.py b/integration_tests/global_syms_03_c.py new file mode 100644 index 0000000000..cf6f05375b --- /dev/null +++ b/integration_tests/global_syms_03_c.py @@ -0,0 +1,5 @@ +import global_syms_03_a + +assert len(global_syms_03_a.l_1) == 4 +assert global_syms_03_a.l_1[3] == "Thursday" +assert global_syms_03_a.l_3 == [1.0, 2.0, 3.0] diff --git a/integration_tests/global_syms_04.py b/integration_tests/global_syms_04.py new file mode 100644 index 0000000000..7b035167e2 --- /dev/null +++ b/integration_tests/global_syms_04.py @@ -0,0 +1,37 @@ +from lpython import i32, i64, f64 + +a: str = "hi" +b: i32 = -24 +c: i64 = i64(151) +d: f64 = -68.512 + +def print_global_symbols(): + print(a) + print(b) + print(c) + print(d) + +def test_global_symbols(): + assert b == -24 + assert c == i64(151) + assert abs(d - (-68.512)) <= 1e-12 + +def update_global_symbols(): + global b, c, d + x: f64 = f64(c) * d + b = i32(x) + y: f64 = f64(b) / 12.0 + c = i64(y) + z: i64 = i64(b) * c + d = f64(z) + +def test_global_symbols_post_update(): + assert b == -10345 + assert c == i64(-862) + assert abs(d - 8917390.0) <= 1e-12 + +print_global_symbols() +test_global_symbols() +update_global_symbols() +print_global_symbols() +test_global_symbols_post_update() diff --git a/integration_tests/global_syms_05.py b/integration_tests/global_syms_05.py new file mode 100644 index 0000000000..62b97c2593 --- /dev/null +++ b/integration_tests/global_syms_05.py @@ -0,0 +1,21 @@ +from lpython import i32 + +# GLOBAL Dictionary +x: dict[i32, i32] +x = {0 : 0, 1: 1000, 2: 2000, 3 : 3000} + +x[4] = 4000 +assert len(x) == 5 +x[5] = 5000 +assert x[2] == 2000 +i: i32 +for i in range(len(x)): + assert x[i] == i * 1000 + +# Copy of Dictionary +tmp: dict[i32, i32] +tmp = x +tmp[6] = 6000 +assert len(tmp) == 7 +assert tmp[6] == 6000 +assert tmp[1] == 1000 diff --git a/integration_tests/global_syms_06.py b/integration_tests/global_syms_06.py new file mode 100644 index 0000000000..0b396d1408 --- /dev/null +++ b/integration_tests/global_syms_06.py @@ -0,0 +1,9 @@ +from lpython import i32 + +def test() -> i32: + temp: i32 = 0 + return temp + +x: i32 = test() +i: i32 = 10 +j: i32 = i diff --git a/integration_tests/gruntz_demo.py b/integration_tests/gruntz_demo.py new file mode 100644 index 0000000000..6beb38f330 --- /dev/null +++ b/integration_tests/gruntz_demo.py @@ -0,0 +1,399 @@ +""" +Limits +====== + +Implemented according to the PhD thesis +https://www.cybertester.com/data/gruntz.pdf, which contains very thorough +descriptions of the algorithm including many examples. We summarize here +the gist of it. + +All functions are sorted according to how rapidly varying they are at +infinity using the following rules. Any two functions f and g can be +compared using the properties of L: + +L=lim log|f(x)| / log|g(x)| (for x -> oo) + +We define >, < ~ according to:: + + 1. f > g .... L=+-oo + + we say that: + - f is greater than any power of g + - f is more rapidly varying than g + - f goes to infinity/zero faster than g + + 2. f < g .... L=0 + + we say that: + - f is lower than any power of g + + 3. f ~ g .... L!=0, +-oo + + we say that: + - both f and g are bounded from above and below by suitable integral + powers of the other + +Examples +======== +:: + 2 < x < exp(x) < exp(x**2) < exp(exp(x)) + 2 ~ 3 ~ -5 + x ~ x**2 ~ x**3 ~ 1/x ~ x**m ~ -x + exp(x) ~ exp(-x) ~ exp(2x) ~ exp(x)**2 ~ exp(x+exp(-x)) + f ~ 1/f + +So we can divide all the functions into comparability classes (x and x^2 +belong to one class, exp(x) and exp(-x) belong to some other class). In +principle, we could compare any two functions, but in our algorithm, we +do not compare anything below the class 2~3~-5 (for example log(x) is +below this), so we set 2~3~-5 as the lowest comparability class. + +Given the function f, we find the list of most rapidly varying (mrv set) +subexpressions of it. This list belongs to the same comparability class. +Let's say it is {exp(x), exp(2x)}. Using the rule f ~ 1/f we find an +element "w" (either from the list or a new one) from the same +comparability class which goes to zero at infinity. In our example we +set w=exp(-x) (but we could also set w=exp(-2x) or w=exp(-3x) ...). We +rewrite the mrv set using w, in our case {1/w, 1/w^2}, and substitute it +into f. Then we expand f into a series in w:: + + f = c0*w^e0 + c1*w^e1 + ... + O(w^en), where e0oo, lim f = lim c0*w^e0, because all the other terms go to zero, +because w goes to zero faster than the ci and ei. So:: + + for e0>0, lim f = 0 + for e0<0, lim f = +-oo (the sign depends on the sign of c0) + for e0=0, lim f = lim c0 + +We need to recursively compute limits at several places of the algorithm, but +as is shown in the PhD thesis, it always finishes. + +Important functions from the implementation: + +compare(a, b, x) compares "a" and "b" by computing the limit L. +mrv(e, x) returns list of most rapidly varying (mrv) subexpressions of "e" +rewrite(e, Omega, x, wsym) rewrites "e" in terms of w +leadterm(f, x) returns the lowest power term in the series of f +mrv_leadterm(e, x) returns the lead term (c0, e0) for e +limitinf(e, x) computes lim e (for x->oo) +limit(e, z, z0) computes any limit by converting it to the case x->oo + +All the functions are really simple and straightforward except +rewrite(), which is the most difficult/complex part of the algorithm. +When the algorithm fails, the bugs are usually in the series expansion +(i.e. in SymPy) or in rewrite. + +This code is almost exact rewrite of the Maple code inside the Gruntz +thesis. + +Debugging +--------- + +Because the gruntz algorithm is highly recursive, it's difficult to +figure out what went wrong inside a debugger. Instead, turn on nice +debug prints by defining the environment variable SYMPY_DEBUG. For +example: + +[user@localhost]: SYMPY_DEBUG=True ./bin/isympy + +In [1]: limit(sin(x)/x, x, 0) +limitinf(_x*sin(1/_x), _x) = 1 ++-mrv_leadterm(_x*sin(1/_x), _x) = (1, 0) +| +-mrv(_x*sin(1/_x), _x) = set([_x]) +| | +-mrv(_x, _x) = set([_x]) +| | +-mrv(sin(1/_x), _x) = set([_x]) +| | +-mrv(1/_x, _x) = set([_x]) +| | +-mrv(_x, _x) = set([_x]) +| +-mrv_leadterm(exp(_x)*sin(exp(-_x)), _x, set([exp(_x)])) = (1, 0) +| +-rewrite(exp(_x)*sin(exp(-_x)), set([exp(_x)]), _x, _w) = (1/_w*sin(_w), -_x) +| +-sign(_x, _x) = 1 +| +-mrv_leadterm(1, _x) = (1, 0) ++-sign(0, _x) = 0 ++-limitinf(1, _x) = 1 + +And check manually which line is wrong. Then go to the source code and +debug this function to figure out the exact problem. + +""" +from functools import reduce + +from sympy.core import Basic, S, Mul, PoleError, expand_mul, evaluate +from sympy.core.cache import cacheit +from sympy.core.numbers import I, oo +from sympy.core.symbol import Dummy, Wild, Symbol +from sympy.core.traversal import bottom_up +from sympy.core.sorting import ordered + +from sympy.functions import log, exp, sign, sin +from sympy.series.order import Order +from sympy.utilities.exceptions import SymPyDeprecationWarning +from sympy.utilities.misc import debug_decorator as debug +from sympy.utilities.timeutils import timethis + +def mrv(e, x): + """ + Calculate the MRV set of the expression. + + Examples + ======== + + >>> mrv(log(x - log(x))/log(x), x) + {x} + + """ + + if not e.has(x): + return set() + if e == x: + return {x} + if e.is_Mul or e.is_Add: + a, b = e.as_two_terms() + return mrv_max(mrv(a, x), mrv(b, x), x) + if e.func == exp: + if e.exp == x: + return {e} + if any(a.is_infinite for a in Mul.make_args(limitinf(e.exp, x))): + return mrv_max({e}, mrv(e.exp, x), x) + return mrv(e.exp, x) + if e.is_Pow: + return mrv(e.base, x) + if isinstance(e, log): + return mrv(e.args[0], x) + if e.is_Function: + return reduce(lambda a, b: mrv_max(a, b, x), (mrv(a, x) for a in e.args)) + raise NotImplementedError(f"Can't calculate the MRV of {e}.") + +def mrv_max(f, g, x): + """Compute the maximum of two MRV sets. + + Examples + ======== + + >>> mrv_max({log(x)}, {x**5}, x) + {x**5} + + """ + + if not f: + return g + if not g: + return f + if f & g: + return f | g + + a, b = map(next, map(iter, (f, g))) + + # The log(exp(...)) must always be simplified here. + la = a.exp if a.is_Exp else log(a) + lb = b.exp if b.is_Exp else log(b) + + c = limitinf(la/lb, x) + if c.is_zero: + return g + if c.is_infinite: + return f + return f | g + +def rewrite(e, x, w): + r""" + Rewrites the expression in terms of the MRV subexpression. + + Parameters + ========== + + e : Expr + an expression + x : Symbol + variable of the `e` + w : Symbol + The symbol which is going to be used for substitution in place + of the MRV in `x` subexpression. + + Returns + ======= + + tuple + A pair: rewritten (in `w`) expression and `\log(w)`. + + Examples + ======== + + >>> rewrite(exp(x)*log(x), x, y) + (log(x)/y, -x) + + """ + + Omega = mrv(e, x) + if not Omega: + return e, None # e really does not depend on x + + if x in Omega: + # Moving up in the asymptotical scale: + with evaluate(False): + e = e.xreplace({x: exp(x)}) + Omega = {s.xreplace({x: exp(x)}) for s in Omega} + + Omega = list(ordered(Omega, keys=lambda a: -len(mrv(a, x)))) + + for g in Omega: + sig = signinf(g.exp, x) + if sig not in (1, -1): + raise NotImplementedError(f'Result depends on the sign of {sig}.') + + if sig == 1: + w = 1/w # if g goes to oo, substitute 1/w + + # Rewrite and substitute subexpressions in the Omega. + for a in Omega: + c = limitinf(a.exp/g.exp, x) + b = exp(a.exp - c*g.exp)*w**c # exponential must never be expanded here + with evaluate(False): + e = e.xreplace({a: b}) + + return e, -sig*g.exp + +@cacheit +def mrv_leadterm(e, x): + """ + Compute the leading term of the series. + + Returns + ======= + + tuple + The leading term `c_0 w^{e_0}` of the series of `e` in terms + of the most rapidly varying subexpression `w` in form of + the pair ``(c0, e0)`` of Expr. + + Examples + ======== + + >>> leadterm(1/exp(-x + exp(-x)) - exp(x), x) + (-1, 0) + + """ + + if not e.has(x): + return e, Integer(0) + + # Rewrite to exp-log functions per Sec. 3.3 of thesis. + e = e.replace(lambda f: f.is_Pow and f.exp.has(x), + lambda f: exp(log(f.base)*f.exp)) + e = e.replace(lambda f: f.is_Mul and sum(a.func == exp for a in f.args) > 1, + lambda f: Mul(exp(Add(*(a.exp for a in f.args if a.func == exp))), + *(a for a in f.args if not a.func == exp))) + + # The positive dummy, w, is used here so log(w*2) etc. will expand. + # TODO: For limits of complex functions, the algorithm would have to + # be improved, or just find limits of Re and Im components separately. + w = Dummy('w', real=True, positive=True) + e, logw = rewrite(e, x, w) + + c0, e0 = e.leadterm(w, logx=logw) + if c0.has(w): + raise NotImplementedError(f'Cannot compute leadterm({e}, {x}). ' + 'The coefficient should have been free of ' + f'{w}, but got {c0}.') + return c0.subs(log(w), logw), e0 + +@cacheit +def signinf(e, x): + r""" + Determine sign of the expression at the infinity. + + Returns + ======= + + {1, 0, -1} + One or minus one, if `e > 0` or `e < 0` for `x` sufficiently + large and zero if `e` is *constantly* zero for `x\to\infty`. + + """ + + if not e.has(x): + return sign(e).simplify() + if e == x or (e.is_Pow and signinf(e.base, x) == 1): + return S(1) + if e.is_Mul: + a, b = e.as_two_terms() + return signinf(a, x)*signinf(b, x) + + c0, _ = leadterm(e, x) + return signinf(c0, x) + +@cacheit +def limitinf(e, x): + """ + Compute the limit of the expression at the infinity. + + Examples + ======== + + >>> limitinf(exp(x)*(exp(1/x - exp(-x)) - exp(1/x)), x) + -1 + + """ + # Rewrite e in terms of tractable functions only: + e = e.rewrite('tractable', deep=True, limitvar=x) + + if not e.has(x): + return e.rewrite('intractable', deep=True) + + c0, e0 = mrv_leadterm(e, x) + sig = signinf(e0, x) + if sig == 1: + return S(0) + if sig == -1: + return signinf(c0, x)*oo + if sig == 0: + return limitinf(c0, x) + raise NotImplementedError(f'Result depends on the sign of {sig}.') + + +def gruntz(e, z, z0, dir="+"): + """ + Compute the limit of e(z) at the point z0 using the Gruntz algorithm. + + Explanation + =========== + + ``z0`` can be any expression, including oo and -oo. + + For ``dir="+"`` (default) it calculates the limit from the right + (z->z0+) and for ``dir="-"`` the limit from the left (z->z0-). For infinite z0 + (oo or -oo), the dir argument does not matter. + + This algorithm is fully described in the module docstring in the gruntz.py + file. It relies heavily on the series expansion. Most frequently, gruntz() + is only used if the faster limit() function (which uses heuristics) fails. + """ + if not z.is_symbol: + raise NotImplementedError("Second argument must be a Symbol") + + # convert all limits to the limit z->oo; sign of z is handled in limitinf + r = None + if z0 in (oo, I*oo): + e0 = e + elif z0 in (-oo, -I*oo): + e0 = e.subs(z, -z) + else: + if str(dir) == "-": + e0 = e.subs(z, z0 - 1/z) + elif str(dir) == "+": + e0 = e.subs(z, z0 + 1/z) + else: + raise NotImplementedError("dir must be '+' or '-'") + + r = limitinf(e0, z) + + # This is a bit of a heuristic for nice results... we always rewrite + # tractable functions in terms of familiar intractable ones. + # It might be nicer to rewrite the exactly to what they were initially, + # but that would take some work to implement. + return r.rewrite('intractable', deep=True) + +# tests +x = Symbol('x') +ans = gruntz(sin(x)/x, x, 0) +print(ans) \ No newline at end of file diff --git a/integration_tests/gruntz_demo2.py b/integration_tests/gruntz_demo2.py new file mode 100644 index 0000000000..a9faead47d --- /dev/null +++ b/integration_tests/gruntz_demo2.py @@ -0,0 +1,347 @@ +""" +Limits +====== + +Implemented according to the PhD thesis +https://www.cybertester.com/data/gruntz.pdf, which contains very thorough +descriptions of the algorithm including many examples. We summarize here +the gist of it. + +All functions are sorted according to how rapidly varying they are at +infinity using the following rules. Any two functions f and g can be +compared using the properties of L: + +L=lim log|f(x)| / log|g(x)| (for x -> oo) + +We define >, < ~ according to:: + + 1. f > g .... L=+-oo + + we say that: + - f is greater than any power of g + - f is more rapidly varying than g + - f goes to infinity/zero faster than g + + 2. f < g .... L=0 + + we say that: + - f is lower than any power of g + + 3. f ~ g .... L!=0, +-oo + + we say that: + - both f and g are bounded from above and below by suitable integral + powers of the other + +Examples +======== +:: + 2 < x < exp(x) < exp(x**2) < exp(exp(x)) + 2 ~ 3 ~ -5 + x ~ x**2 ~ x**3 ~ 1/x ~ x**m ~ -x + exp(x) ~ exp(-x) ~ exp(2x) ~ exp(x)**2 ~ exp(x+exp(-x)) + f ~ 1/f + +So we can divide all the functions into comparability classes (x and x^2 +belong to one class, exp(x) and exp(-x) belong to some other class). In +principle, we could compare any two functions, but in our algorithm, we +do not compare anything below the class 2~3~-5 (for example log(x) is +below this), so we set 2~3~-5 as the lowest comparability class. + +Given the function f, we find the list of most rapidly varying (mrv set) +subexpressions of it. This list belongs to the same comparability class. +Let's say it is {exp(x), exp(2x)}. Using the rule f ~ 1/f we find an +element "w" (either from the list or a new one) from the same +comparability class which goes to zero at infinity. In our example we +set w=exp(-x) (but we could also set w=exp(-2x) or w=exp(-3x) ...). We +rewrite the mrv set using w, in our case {1/w, 1/w^2}, and substitute it +into f. Then we expand f into a series in w:: + + f = c0*w^e0 + c1*w^e1 + ... + O(w^en), where e0oo, lim f = lim c0*w^e0, because all the other terms go to zero, +because w goes to zero faster than the ci and ei. So:: + + for e0>0, lim f = 0 + for e0<0, lim f = +-oo (the sign depends on the sign of c0) + for e0=0, lim f = lim c0 + +We need to recursively compute limits at several places of the algorithm, but +as is shown in the PhD thesis, it always finishes. + +Important functions from the implementation: + +compare(a, b, x) compares "a" and "b" by computing the limit L. +mrv(e, x) returns list of most rapidly varying (mrv) subexpressions of "e" +rewrite(e, Omega, x, wsym) rewrites "e" in terms of w +leadterm(f, x) returns the lowest power term in the series of f +mrv_leadterm(e, x) returns the lead term (c0, e0) for e +limitinf(e, x) computes lim e (for x->oo) +limit(e, z, z0) computes any limit by converting it to the case x->oo + +All the functions are really simple and straightforward except +rewrite(), which is the most difficult/complex part of the algorithm. +When the algorithm fails, the bugs are usually in the series expansion +(i.e. in SymPy) or in rewrite. + +This code is almost exact rewrite of the Maple code inside the Gruntz +thesis. + +Debugging +--------- + +Because the gruntz algorithm is highly recursive, it's difficult to +figure out what went wrong inside a debugger. Instead, turn on nice +debug prints by defining the environment variable SYMPY_DEBUG. For +example: + +[user@localhost]: SYMPY_DEBUG=True ./bin/isympy + +In [1]: limit(sin(x)/x, x, 0) +limitinf(_x*sin(1/_x), _x) = 1 ++-mrv_leadterm(_x*sin(1/_x), _x) = (1, 0) +| +-mrv(_x*sin(1/_x), _x) = set([_x]) +| | +-mrv(_x, _x) = set([_x]) +| | +-mrv(sin(1/_x), _x) = set([_x]) +| | +-mrv(1/_x, _x) = set([_x]) +| | +-mrv(_x, _x) = set([_x]) +| +-mrv_leadterm(exp(_x)*sin(exp(-_x)), _x, set([exp(_x)])) = (1, 0) +| +-rewrite(exp(_x)*sin(exp(-_x)), set([exp(_x)]), _x, _w) = (1/_w*sin(_w), -_x) +| +-sign(_x, _x) = 1 +| +-mrv_leadterm(1, _x) = (1, 0) ++-sign(0, _x) = 0 ++-limitinf(1, _x) = 1 + +And check manually which line is wrong. Then go to the source code and +debug this function to figure out the exact problem. + +""" +from functools import reduce + +from sympy.core import Basic, S, Mul, PoleError, expand_mul, evaluate, Integer +from sympy.core.cache import cacheit +from sympy.core.numbers import I, oo +from sympy.core.symbol import Dummy, Wild, Symbol +from sympy.core.traversal import bottom_up +from sympy.core.sorting import ordered + +from sympy.functions import log, exp, sign, sin +from sympy.series.order import Order +from sympy.utilities.exceptions import SymPyDeprecationWarning +from sympy.utilities.misc import debug_decorator as debug +from sympy.utilities.timeutils import timethis + +def mrv(e, x): + """ + Calculate the MRV set of the expression. + + Examples + ======== + + >>> mrv(log(x - log(x))/log(x), x) + {x} + + """ + + if e == x: + return {x} + elif e.is_Integer: + return {} + elif e.is_Mul or e.is_Add: + a, b = e.as_two_terms() + ans1 = mrv(a, x) + ans2 = mrv(b, x) + return mrv_max(mrv(a, x), mrv(b, x), x) + elif e.is_Pow: + return mrv(e.base, x) + elif e.is_Function: + return reduce(lambda a, b: mrv_max(a, b, x), (mrv(a, x) for a in e.args)) + raise NotImplementedError(f"Can't calculate the MRV of {e}.") + +def mrv_max(f, g, x): + """Compute the maximum of two MRV sets. + + Examples + ======== + + >>> mrv_max({log(x)}, {x**5}, x) + {x**5} + + """ + + if not f: + return g + if not g: + return f + if f & g: + return f | g + +def rewrite(e, x, w): + r""" + Rewrites the expression in terms of the MRV subexpression. + + Parameters + ========== + + e : Expr + an expression + x : Symbol + variable of the `e` + w : Symbol + The symbol which is going to be used for substitution in place + of the MRV in `x` subexpression. + + Returns + ======= + + The rewritten expression + + Examples + ======== + + >>> rewrite(exp(x)*log(x), x, y) + (log(x)/y, -x) + + """ + + Omega = mrv(e, x) + + if x in Omega: + # Moving up in the asymptotical scale: + with evaluate(False): + e = e.subs(x, exp(x)) + Omega = {s.subs(x, exp(x)) for s in Omega} + + Omega = list(ordered(Omega, keys=lambda a: -len(mrv(a, x)))) + + for g in Omega: + sig = signinf(g.exp, x) + if sig not in (1, -1): + raise NotImplementedError(f'Result depends on the sign of {sig}.') + + if sig == 1: + w = 1/w # if g goes to oo, substitute 1/w + + # Rewrite and substitute subexpressions in the Omega. + for a in Omega: + c = limitinf(a.exp/g.exp, x) + b = exp(a.exp - c*g.exp)*w**c # exponential must never be expanded here + with evaluate(False): + e = e.xreplace({a: b}) + + return e + +@cacheit +def mrv_leadterm(e, x): + """ + Compute the leading term of the series. + + Returns + ======= + + tuple + The leading term `c_0 w^{e_0}` of the series of `e` in terms + of the most rapidly varying subexpression `w` in form of + the pair ``(c0, e0)`` of Expr. + + Examples + ======== + + >>> leadterm(1/exp(-x + exp(-x)) - exp(x), x) + (-1, 0) + + """ + + w = Dummy('w', real=True, positive=True) + e = rewrite(e, x, w) + return e.leadterm(w) + +@cacheit +def signinf(e, x): + r""" + Determine sign of the expression at the infinity. + + Returns + ======= + + {1, 0, -1} + One or minus one, if `e > 0` or `e < 0` for `x` sufficiently + large and zero if `e` is *constantly* zero for `x\to\infty`. + + """ + + if not e.has(x): + return sign(e) + if e == x or (e.is_Pow and signinf(e.base, x) == 1): + return S(1) + +@cacheit +def limitinf(e, x): + """ + Compute the limit of the expression at the infinity. + + Examples + ======== + + >>> limitinf(exp(x)*(exp(1/x - exp(-x)) - exp(1/x)), x) + -1 + + """ + + if not e.has(x): + return e + + c0, e0 = mrv_leadterm(e, x) + sig = signinf(e0, x) + if sig == 1: + return Integer(0) + if sig == -1: + return signinf(c0, x)*oo + if sig == 0: + return limitinf(c0, x) + raise NotImplementedError(f'Result depends on the sign of {sig}.') + + +def gruntz(e, z, z0, dir="+"): + """ + Compute the limit of e(z) at the point z0 using the Gruntz algorithm. + + Explanation + =========== + + ``z0`` can be any expression, including oo and -oo. + + For ``dir="+"`` (default) it calculates the limit from the right + (z->z0+) and for ``dir="-"`` the limit from the left (z->z0-). For infinite z0 + (oo or -oo), the dir argument does not matter. + + This algorithm is fully described in the module docstring in the gruntz.py + file. It relies heavily on the series expansion. Most frequently, gruntz() + is only used if the faster limit() function (which uses heuristics) fails. + """ + + if str(dir) == "-": + e0 = e.subs(z, z0 - 1/z) + elif str(dir) == "+": + e0 = e.subs(z, z0 + 1/z) + else: + raise NotImplementedError("dir must be '+' or '-'") + + r = limitinf(e0, z) + return r + +# tests +x = Symbol('x') +# Print the basic limit: +print(gruntz(sin(x)/x, x, 0)) + +# Test other cases +assert gruntz(sin(x)/x, x, 0) == 1 +assert gruntz(2*sin(x)/x, x, 0) == 2 +assert gruntz(sin(2*x)/x, x, 0) == 2 +assert gruntz(sin(x)**2/x, x, 0) == 0 +assert gruntz(sin(x)/x**2, x, 0) == oo +assert gruntz(sin(x)**2/x**2, x, 0) == 1 +assert gruntz(sin(sin(sin(x)))/sin(x), x, 0) == 1 +assert gruntz(2*log(x+1)/x, x, 0) == 2 +assert gruntz(sin((log(x+1)/x)*x)/x, x, 0) == 1 diff --git a/integration_tests/gruntz_demo3.py b/integration_tests/gruntz_demo3.py new file mode 100644 index 0000000000..a4fb48405c --- /dev/null +++ b/integration_tests/gruntz_demo3.py @@ -0,0 +1,264 @@ +from lpython import S +from sympy import Symbol, Pow, sin, oo, pi, E, Mul, Add, oo, log, exp, sign + +def mrv(e: S, x: S) -> list[S]: + """ + Calculate the MRV set of the expression. + + Examples + ======== + + >>> mrv(log(x - log(x))/log(x), x) + {x} + + """ + + if e.is_integer: + empty_list: list[S] = [] + return empty_list + if e == x: + list1: list[S] = [x] + return list1 + if e.func == log: + arg0: S = e.args[0] + list2: list[S] = mrv(arg0, x) + return list2 + if e.func == Mul or e.func == Add: + a: S = e.args[0] + b: S = e.args[1] + ans1: list[S] = mrv(a, x) + ans2: list[S] = mrv(b, x) + list3: list[S] = mrv_max(ans1, ans2, x) + return list3 + if e.func == Pow: + base: S = e.args[0] + list4: list[S] = mrv(base, x) + return list4 + if e.func == sin: + list5: list[S] = [x] + return list5 + # elif e.is_Function: + # return reduce(lambda a, b: mrv_max(a, b, x), (mrv(a, x) for a in e.args)) + raise NotImplementedError(f"Can't calculate the MRV of {e}.") + +def mrv_max(f: list[S], g: list[S], x: S) -> list[S]: + """Compute the maximum of two MRV sets. + + Examples + ======== + + >>> mrv_max({log(x)}, {x**5}, x) + {x**5} + + """ + + if len(f) == 0: + return g + elif len(g) == 0: + return f + # elif f & g: + # return f | g + else: + f1: S = f[0] + g1: S = g[0] + bool1: bool = f1 == x + bool2: bool = g1 == x + if bool1 and bool2: + l: list[S] = [x] + return l + +def rewrite(e: S, x: S, w: S) -> S: + """ + Rewrites the expression in terms of the MRV subexpression. + + Parameters + ========== + + e : Expr + an expression + x : Symbol + variable of the `e` + w : Symbol + The symbol which is going to be used for substitution in place + of the MRV in `x` subexpression. + + Returns + ======= + + The rewritten expression + + Examples + ======== + + >>> rewrite(exp(x)*log(x), x, y) + (log(x)/y, -x) + + """ + Omega: list[S] = mrv(e, x) + Omega1: S = Omega[0] + + if Omega1 == x: + newe: S = e.subs(x, S(1)/w) + return newe + +def signinf(e: S, x : S) -> S: + r""" + Determine sign of the expression at the infinity. + + Returns + ======= + + {1, 0, -1} + One or minus one, if `e > 0` or `e < 0` for `x` sufficiently + large and zero if `e` is *constantly* zero for `x\to\infty`. + + """ + + if not e.has(x): + return sign(e) + if e == x: + return S(1) + if e.func == Pow: + base: S = e.args[0] + if signinf(base, x) == S(1): + return S(1) + +def leadterm(e: S, x: S) -> list[S]: + """ + Returns the leading term a*x**b as a list [a, b]. + """ + + l1: list[S] = [S(1), S(0)] + l2: list[S] = [S(2), S(0)] + l3: list[S] = [S(1), S(1)] + l4: list[S] = [S(1), S(-1)] + + if e == sin(x)/x: + return l1 + elif e == S(2)*sin(x)/x: + return l2 + elif e == sin(S(2)*x)/x: + return l2 + elif e == sin(x)**S(2)/x: + return l3 + elif e == sin(x)/x**S(2): + return l4 + elif e == sin(x)**S(2)/x**S(2): + return l1 + elif e == sin(sin(sin(x)))/sin(x): + return l1 + elif e == S(2)*log(x+S(1))/x: + return l2 + elif e == sin((log(x+S(1))/x)*x)/x: + return l1 + raise NotImplementedError(f"Can't calculate the leadterm of {e}.") + +def mrv_leadterm(e: S, x: S) -> list[S]: + """ + Compute the leading term of the series. + + Returns + ======= + + tuple + The leading term `c_0 w^{e_0}` of the series of `e` in terms + of the most rapidly varying subexpression `w` in form of + the pair ``(c0, e0)`` of Expr. + + Examples + ======== + + >>> leadterm(1/exp(-x + exp(-x)) - exp(x), x) + (-1, 0) + + """ + # w = Dummy('w', real=True, positive=True) + # e = rewrite(e, x, w) + # return e.leadterm(w) + w: S = Symbol('w') + newe: S = rewrite(e, x, w) + coeff_exp_list: list[S] = leadterm(newe, w) + return coeff_exp_list + +def limitinf(e: S, x: S) -> S: + """ + Compute the limit of the expression at the infinity. + + Examples + ======== + + >>> limitinf(exp(x)*(exp(1/x - exp(-x)) - exp(1/x)), x) + -1 + + """ + if not e.has(x): + return e + + coeff_exp_list: list[S] = mrv_leadterm(e, x) + c0: S = coeff_exp_list[0] + e0: S = coeff_exp_list[1] + sig: S = signinf(e0, x) + case_2: S = signinf(c0, x) * oo + if sig == S(1): + return S(0) + if sig == S(-1): + return case_2 + if sig == S(0): + return limitinf(c0, x) + raise NotImplementedError(f'Result depends on the sign of {sig}.') + +def gruntz(e: S, z: S, z0: S, dir: str ="+") -> S: + """ + Compute the limit of e(z) at the point z0 using the Gruntz algorithm. + + Explanation + =========== + + ``z0`` can be any expression, including oo and -oo. + + For ``dir="+"`` (default) it calculates the limit from the right + (z->z0+) and for ``dir="-"`` the limit from the left (z->z0-). For infinite z0 + (oo or -oo), the dir argument does not matter. + + This algorithm is fully described in the module docstring in the gruntz.py + file. It relies heavily on the series expansion. Most frequently, gruntz() + is only used if the faster limit() function (which uses heuristics) fails. + """ + + e0: S + sub_neg: S = z0 - S(1)/z + sub_pos: S = z0 + S(1)/z + if str(dir) == "-": + e0 = e.subs(z, sub_neg) + elif str(dir) == "+": + e0 = e.subs(z, sub_pos) + else: + raise NotImplementedError("dir must be '+' or '-'") + + r: S = limitinf(e0, z) + return r + +# test +def test(): + x: S = Symbol('x') + print(gruntz(sin(x)/x, x, S(0), "+")) + print(gruntz(S(2)*sin(x)/x, x, S(0), "+")) + print(gruntz(sin(S(2)*x)/x, x, S(0), "+")) + print(gruntz(sin(x)**S(2)/x, x, S(0), "+")) + print(gruntz(sin(x)/x**S(2), x, S(0), "+")) + print(gruntz(sin(x)**S(2)/x**S(2), x, S(0), "+")) + print(gruntz(sin(sin(sin(x)))/sin(x), x, S(0), "+")) + print(gruntz(S(2)*log(x+S(1))/x, x, S(0), "+")) + print(gruntz(sin((log(x+S(1))/x)*x)/x, x, S(0), "+")) + + assert gruntz(sin(x)/x, x, S(0)) == S(1) + assert gruntz(S(2)*sin(x)/x, x, S(0)) == S(2) + assert gruntz(sin(S(2)*x)/x, x, S(0)) == S(2) + assert gruntz(sin(x)**S(2)/x, x, S(0)) == S(0) + assert gruntz(sin(x)/x**S(2), x, S(0)) == oo + assert gruntz(sin(x)**S(2)/x**S(2), x, S(0)) == S(1) + assert gruntz(sin(sin(sin(x)))/sin(x), x, S(0)) == S(1) + assert gruntz(S(2)*log(x+S(1))/x, x, S(0)) == S(2) + assert gruntz(sin((log(x+S(1))/x)*x)/x, x, S(0)) == S(1) + +test() \ No newline at end of file diff --git a/integration_tests/if_01.py b/integration_tests/if_01.py index 842cf15443..dccda55adb 100644 --- a/integration_tests/if_01.py +++ b/integration_tests/if_01.py @@ -1,3 +1,5 @@ +from lpython import i32 + def Test_if_01(): z: i32 = 0 if True: diff --git a/integration_tests/if_02.py b/integration_tests/if_02.py index e3a5b203b6..2a607f7ae3 100644 --- a/integration_tests/if_02.py +++ b/integration_tests/if_02.py @@ -1,4 +1,4 @@ -from ltypes import i32 +from lpython import i32 def test_if_01(): x: bool = True diff --git a/integration_tests/if_03.py b/integration_tests/if_03.py new file mode 100644 index 0000000000..780a7a7af8 --- /dev/null +++ b/integration_tests/if_03.py @@ -0,0 +1,5 @@ +from sys import exit + +if True: + print("Yes, true") + exit(1) diff --git a/integration_tests/import_order_01.py b/integration_tests/import_order_01.py new file mode 100644 index 0000000000..0d8724338d --- /dev/null +++ b/integration_tests/import_order_01.py @@ -0,0 +1,7 @@ +from import_order_01b import f +from lpython import i32, ccallback + +@ccallback +def main1(): + a: i32 = f() + print(a) diff --git a/integration_tests/import_order_01b.py b/integration_tests/import_order_01b.py new file mode 100644 index 0000000000..2dd1989d2a --- /dev/null +++ b/integration_tests/import_order_01b.py @@ -0,0 +1,4 @@ +from lpython import i32 + +def f() -> i32: + return 42 diff --git a/integration_tests/intent_01.py b/integration_tests/intent_01.py new file mode 100644 index 0000000000..e4f679b05c --- /dev/null +++ b/integration_tests/intent_01.py @@ -0,0 +1,26 @@ +from lpython import i32, u32, f64, dataclass, In, Out, InOut + +@dataclass +class Foo: + p: i32 + +def f(x: i32, y: In[f64], z: InOut[list[u32]], w: Out[Foo]): + assert (x == -12) + assert abs(y - (4.44)) <= 1e-12 + z.append(u32(5)) + w.p = 24 + + +def main0(): + a: i32 = (-12) + b: f64 = 4.44 + c: list[u32] = [u32(1), u32(2), u32(3), u32(4)] + d: Foo = Foo(25) + + print(a, b, c, d.p) + + f(a, b, c, d) + assert c[-1] == u32(5) + assert d.p == 24 + +main0() diff --git a/integration_tests/intrinsics_01.py b/integration_tests/intrinsics_01.py new file mode 100644 index 0000000000..5547e86206 --- /dev/null +++ b/integration_tests/intrinsics_01.py @@ -0,0 +1,15 @@ +from numpy import array + +def any_01() -> None: + x: bool[2] + + x= array([False, False]) + assert not any(x) + + x = array([False, True]) + assert any(x) + + x = array([True, True]) + assert any(x) + +any_01() diff --git a/integration_tests/intrinsics_02.py b/integration_tests/intrinsics_02.py new file mode 100644 index 0000000000..c37d0aad3d --- /dev/null +++ b/integration_tests/intrinsics_02.py @@ -0,0 +1,42 @@ +from lpython import Const, i32, f32, f64 + +foo: Const[i32] = 4 +bar: Const[i32] = foo // 2 + +print(bar) +assert bar == 2 + +def floordiv1(): + a: f64 + b: f64 + c: f64 + a = 5.0 + b = 2.0 + c = a // b + + print(c) + assert c == 2.0 + +def floordiv2(): + a: Const[f32] = f32(5.0) + b: Const[f32] = f32(2.0) + c: f32 + c = a // b + + print(c) + assert c == f32(2.0) + +def floordiv3(): + a: f64 + b: f64 + c: f64 + a = 5.0 + b = -2.0 + c = a // b + + print(c) + assert c == -3.0 + +floordiv1() +floordiv2() +floordiv3() diff --git a/integration_tests/kwargs_01.py b/integration_tests/kwargs_01.py index 16fc30e5ea..2752769a15 100644 --- a/integration_tests/kwargs_01.py +++ b/integration_tests/kwargs_01.py @@ -1,4 +1,4 @@ -from ltypes import i32, i64, f32, f64, c64, overload +from lpython import i32, i64, f32, f64, c64, overload def func01(a: i32, b: i64) -> i64: return int(a) + b diff --git a/integration_tests/lambda_01.py b/integration_tests/lambda_01.py new file mode 100644 index 0000000000..7e49e4884c --- /dev/null +++ b/integration_tests/lambda_01.py @@ -0,0 +1,16 @@ +from lpython import i32, Callable + +def main0(): + x: Callable[[i32, i32, i32], i32] = lambda p, q, r: p + q + r + + a123: i32 = x(1, 2, 3) + a456: i32 = x(4, 5, 6) + a_1_2_3: i32 = x(-1, -2, -3) + + print(a123, a456, a_1_2_3) + + assert a123 == 6 + assert a456 == 15 + assert a_1_2_3 == -6 + +main0() diff --git a/integration_tests/list_01.py b/integration_tests/list_01.py new file mode 100644 index 0000000000..088b2237dd --- /dev/null +++ b/integration_tests/list_01.py @@ -0,0 +1,21 @@ +from lpython import i32 + +l: list[i32] = [1, 2, 3, 4] +print("Before Pop:", l) + +assert len(l) == 4 +assert l[0] == 1 +assert l[1] == 2 +assert l[2] == 3 +assert l[3] == 4 + +x: i32 = l.pop() +print("After Pop:", l) + +assert x == 4 +assert len(l) == 3 +assert l[0] == 1 +assert l[1] == 2 +assert l[2] == 3 + +print("Popped Element: ", x) diff --git a/src/libasr/compiler_tester/__init__.py b/integration_tests/lnn/__init__.py similarity index 100% rename from src/libasr/compiler_tester/__init__.py rename to integration_tests/lnn/__init__.py diff --git a/integration_tests/lnn/perceptron/__init__.py b/integration_tests/lnn/perceptron/__init__.py new file mode 100644 index 0000000000..1f60fac51f --- /dev/null +++ b/integration_tests/lnn/perceptron/__init__.py @@ -0,0 +1 @@ +from .perceptron_main import init_perceptron, train_dataset, test_perceptron, print_perceptron, Perceptron diff --git a/integration_tests/lnn/perceptron/perceptron_main.py b/integration_tests/lnn/perceptron/perceptron_main.py new file mode 100644 index 0000000000..a60fe8a4e8 --- /dev/null +++ b/integration_tests/lnn/perceptron/perceptron_main.py @@ -0,0 +1,96 @@ +from lpython import dataclass, i32, f64, InOut +from sys import exit + +@dataclass +class Perceptron: + no_of_inputs: i32 + weights: list[f64] + learn_rate: f64 + iterations_limit: i32 + des_accuracy: f64 + cur_accuracy: f64 + epochs_cnt: i32 + +def get_inp_vec_with_bias(a: list[f64]) -> list[f64]: + b: list[f64] = [] + i: i32 + for i in range(len(a)): + b.append(a[i]) + b.append(1.0) + return b + +def init_weights(size: i32) -> list[f64]: + weights: list[f64] = [] + i: i32 + for i in range(size): + weights.append(0.0) + weights.append(0.0) # append bias + return weights + +def init_perceptron(p: InOut[Perceptron], n: i32, rate: f64, iterations_limit: i32, des_accuracy: f64): + if (n < 1 or n > 1000): + print("no_of_inputs must be between [1, 1000]") + exit(1) + p.no_of_inputs = n + p.weights = init_weights(n) + p.learn_rate = rate + p.iterations_limit = iterations_limit + p.des_accuracy = des_accuracy + p.cur_accuracy = 0.0 + p.epochs_cnt = 0 + +def train_perceptron(p: InOut[Perceptron], input_vector: list[f64], actual_output: i32): + predicted_output: i32 = predict_perceptron(p, input_vector) + error: i32 = actual_output - predicted_output + i: i32 + for i in range(len(input_vector)): + p.weights[i] += p.learn_rate * f64(error) * f64(input_vector[i]) + +def predict_perceptron(p: Perceptron, input_vector: list[f64]) -> i32: + weighted_sum: f64 = 0.0 + i: i32 = 0 + for i in range(len(input_vector)): + weighted_sum = weighted_sum + p.weights[i] * f64(input_vector[i]) + return activation_function(weighted_sum) + +def activation_function(value: f64) -> i32: + if value >= 0.0: + return 1 + return -1 + +def train_epoch(p: Perceptron, input_vectors: list[list[f64]], outputs: list[i32]): + i: i32 + for i in range(len(input_vectors)): + input_vector: list[f64] = get_inp_vec_with_bias(input_vectors[i]) + if predict_perceptron(p, input_vector) != outputs[i]: + train_perceptron(p, input_vector, outputs[i]) + +def train_dataset(p: InOut[Perceptron], input_vectors: list[list[f64]], outputs: list[i32]): + p.cur_accuracy = 0.0 + p.epochs_cnt = 0 + while p.cur_accuracy < p.des_accuracy and p.epochs_cnt < p.iterations_limit: + p.epochs_cnt += 1 + train_epoch(p, input_vectors, outputs) + p.cur_accuracy = test_perceptron(p, input_vectors, outputs) + +def test_perceptron(p: Perceptron, input_vectors: list[list[f64]], outputs: list[i32]) -> f64: + correctly_classified_cnt: i32 = 0 + i: i32 + for i in range(len(input_vectors)): + input_vector: list[f64] = get_inp_vec_with_bias(input_vectors[i]) + if predict_perceptron(p, input_vector) == outputs[i]: + correctly_classified_cnt += 1 + return (correctly_classified_cnt / len(input_vectors)) * 100.0 + +def print_perceptron(p: Perceptron): + print("weights = [", end = "") + i: i32 + for i in range(p.no_of_inputs): + print(p.weights[i], end = ", ") + print(p.weights[p.no_of_inputs], end = "(bias)]\n") + print("learn_rate = ", end = "") + print(p.learn_rate) + print("accuracy = ", end = "") + print(p.cur_accuracy) + print("epochs_cnt = ", end = "") + print(p.epochs_cnt) diff --git a/integration_tests/lnn/regression/__init__.py b/integration_tests/lnn/regression/__init__.py new file mode 100644 index 0000000000..de58667620 --- /dev/null +++ b/integration_tests/lnn/regression/__init__.py @@ -0,0 +1 @@ +from .regression_main import init_perceptron, train_dataset, test_perceptron, print_perceptron, Perceptron diff --git a/integration_tests/lnn/regression/regression_main.py b/integration_tests/lnn/regression/regression_main.py new file mode 100644 index 0000000000..f5ad9979f7 --- /dev/null +++ b/integration_tests/lnn/regression/regression_main.py @@ -0,0 +1,92 @@ +from lpython import dataclass, i32, f64, InOut +from sys import exit + +@dataclass +class Perceptron: + no_of_inputs: i32 + weights: list[f64] + learn_rate: f64 + iterations_limit: i32 + err_limit: f64 + err: f64 + epochs_cnt: i32 + +def get_inp_vec_with_bias(a: list[f64]) -> list[f64]: + b: list[f64] = [] + i: i32 + for i in range(len(a)): + b.append(a[i]) + b.append(1.0) + return b + +def init_weights(size: i32) -> list[f64]: + weights: list[f64] = [] + i: i32 + for i in range(size): + weights.append(0.0) + weights.append(0.0) # append bias + return weights + +def init_perceptron(p: InOut[Perceptron], n: i32, rate: f64, iterations_limit: i32, err_limit: f64): + p.no_of_inputs = n + p.weights = init_weights(n) + p.learn_rate = rate + p.iterations_limit = iterations_limit + p.err_limit = err_limit + p.err = 1.0 + p.epochs_cnt = 0 + +def train_perceptron(p: InOut[Perceptron], input_vector: list[f64], actual_output: f64): + predicted_output: f64 = predict_perceptron(p, input_vector) + error: f64 = actual_output - predicted_output + i: i32 + for i in range(len(input_vector)): + p.weights[i] += p.learn_rate * f64(error) * f64(input_vector[i]) + +def predict_perceptron(p: Perceptron, input_vector: list[f64]) -> f64: + weighted_sum: f64 = 0.0 + i: i32 = 0 + for i in range(len(input_vector)): + weighted_sum = weighted_sum + p.weights[i] * f64(input_vector[i]) + return activation_function(weighted_sum) + +def activation_function(value: f64) -> f64: + return value + +def train_epoch(p: Perceptron, input_vectors: list[list[f64]], outputs: list[f64]): + i: i32 + for i in range(len(input_vectors)): + input_vector: list[f64] = get_inp_vec_with_bias(input_vectors[i]) + if predict_perceptron(p, input_vector) != outputs[i]: + train_perceptron(p, input_vector, outputs[i]) + +def train_dataset(p: InOut[Perceptron], input_vectors: list[list[f64]], outputs: list[f64]): + prev_err: f64 = 0.0 + p.err = 1.0 + p.epochs_cnt = 0 + while abs(p.err - prev_err) >= p.err_limit and p.epochs_cnt < p.iterations_limit: + p.epochs_cnt += 1 + train_epoch(p, input_vectors, outputs) + prev_err = p.err + p.err = test_perceptron(p, input_vectors, outputs) + +def test_perceptron(p: Perceptron, input_vectors: list[list[f64]], outputs: list[f64]) -> f64: + err: f64 = 0.0 + i: i32 + for i in range(len(input_vectors)): + input_vector: list[f64] = get_inp_vec_with_bias(input_vectors[i]) + err = err + (outputs[i] - predict_perceptron(p, input_vector)) ** 2.0 + return err + +def print_perceptron(p: Perceptron): + print("weights = [", end = "") + i: i32 + for i in range(p.no_of_inputs): + print(p.weights[i], end = ", ") + print(p.weights[p.no_of_inputs], end = "(bias)]\n") + print("learn_rate = ", end = "") + print(p.learn_rate) + print("error = ", end = "") + print(p.err) + print("epochs_cnt = ", end = "") + print(p.epochs_cnt) diff --git a/integration_tests/lnn/utils/__init__.py b/integration_tests/lnn/utils/__init__.py new file mode 100644 index 0000000000..26df89840f --- /dev/null +++ b/integration_tests/lnn/utils/__init__.py @@ -0,0 +1 @@ +from .utils_main import normalize, normalize_input_vectors, normalize_output_vector diff --git a/integration_tests/lnn/utils/utils_main.py b/integration_tests/lnn/utils/utils_main.py new file mode 100644 index 0000000000..4ee4f32f66 --- /dev/null +++ b/integration_tests/lnn/utils/utils_main.py @@ -0,0 +1,44 @@ +from lpython import i32, f64, InOut + +def normalize(value: f64, leftMin: f64, leftMax: f64, rightMin: f64, rightMax: f64) -> f64: + # Figure out how 'wide' each range is + leftSpan: f64 = leftMax - leftMin + rightSpan: f64 = rightMax - rightMin + + # Convert the left range into a 0-1 range (float) + valueScaled: f64 = (value - leftMin) / leftSpan + + # Convert the 0-1 range into a value in the right range. + return rightMin + (valueScaled * rightSpan) + +def normalize_input_vectors(input_vectors: InOut[list[list[f64]]]): + rows: i32 = len(input_vectors) + cols: i32 = len(input_vectors[0]) + + j: i32 + for j in range(cols): + colMinVal: f64 = input_vectors[0][j] + colMaxVal: f64 = input_vectors[0][j] + i: i32 + for i in range(rows): + if input_vectors[i][j] > colMaxVal: + colMaxVal = input_vectors[i][j] + if input_vectors[i][j] < colMinVal: + colMinVal = input_vectors[i][j] + + for i in range(rows): + input_vectors[i][j] = normalize(input_vectors[i][j], colMinVal, colMaxVal, -1.0, 1.0) + +def normalize_output_vector(output_vector: InOut[list[f64]]): + rows: i32 = len(output_vector) + colMinVal: f64 = output_vector[0] + colMaxVal: f64 = output_vector[0] + i: i32 + for i in range(rows): + if output_vector[i] > colMaxVal: + colMaxVal = output_vector[i] + if output_vector[i] < colMinVal: + colMinVal = output_vector[i] + + for i in range(rows): + output_vector[i] = normalize(output_vector[i], colMinVal, colMaxVal, -1.0, 1.0) diff --git a/integration_tests/logical_binop1.py b/integration_tests/logical_binop1.py index e7fe3a43e5..4c610e0236 100644 --- a/integration_tests/logical_binop1.py +++ b/integration_tests/logical_binop1.py @@ -1,4 +1,4 @@ -from ltypes import i32 +from lpython import i32 def test_issue_1487_1(): # OR operator: a or b a : i32 diff --git a/integration_tests/loop_01.py b/integration_tests/loop_01.py index 1b4f54a3c9..306dc9a09b 100644 --- a/integration_tests/loop_01.py +++ b/integration_tests/loop_01.py @@ -1,4 +1,4 @@ -from ltypes import i32, i64, i16 +from lpython import i32, i64, i16 def main0(): s: str = 'aabbcc'; c: str diff --git a/integration_tests/loop_02.py b/integration_tests/loop_02.py index bfd7eca86c..447ef6e6ad 100644 --- a/integration_tests/loop_02.py +++ b/integration_tests/loop_02.py @@ -1,4 +1,4 @@ -from ltypes import i32 +from lpython import i32 def test_loop_01(): i: i32 = 0 j: i32 = 0 diff --git a/integration_tests/loop_03.py b/integration_tests/loop_03.py index 9101f0889c..dca553b2ba 100644 --- a/integration_tests/loop_03.py +++ b/integration_tests/loop_03.py @@ -1,4 +1,4 @@ -from ltypes import i32 +from lpython import i32 def test_loop_01(): i: i32 = 0 diff --git a/integration_tests/loop_04.py b/integration_tests/loop_04.py index 7adc970d1e..1374a4edc8 100644 --- a/integration_tests/loop_04.py +++ b/integration_tests/loop_04.py @@ -1,4 +1,4 @@ -from ltypes import i32 +from lpython import i32 j: i32 i: i32 diff --git a/integration_tests/loop_05.py b/integration_tests/loop_05.py index 8379e23c42..fe06d74acd 100644 --- a/integration_tests/loop_05.py +++ b/integration_tests/loop_05.py @@ -1,4 +1,4 @@ -from ltypes import i32 +from lpython import i32 def f(): j: i32 = 0 diff --git a/integration_tests/loop_06.py b/integration_tests/loop_06.py new file mode 100644 index 0000000000..4b1bdfc120 --- /dev/null +++ b/integration_tests/loop_06.py @@ -0,0 +1,23 @@ +from lpython import i32 +from sys import exit + +def test_for(): + i: i32 + j: i32; k: i32; + k = 0 + for i in range(0, 10): + if i == 0: + j = 0 + continue + if i > 5: + k = k + i + break + if i == 3: + print(j, k) + assert j == 0 + assert k == 0 + quit() + print(j, k) + exit(2) + +test_for() diff --git a/integration_tests/loop_07.py b/integration_tests/loop_07.py new file mode 100644 index 0000000000..c0b045d5bb --- /dev/null +++ b/integration_tests/loop_07.py @@ -0,0 +1,17 @@ +from lpython import i32 + +def main0(): + points: list[tuple[i32, i32]] = [(445, 193), (138, 28), (418, 279)] + point: tuple[i32, i32] + x_sum: i32 = 0 + y_sum: i32 = 0 + for point in points: + print(point) + x_sum += point[0] + y_sum += point[1] + + print(x_sum, y_sum) + assert x_sum == 1001 + assert y_sum == 500 + +main0() diff --git a/integration_tests/loop_08.py b/integration_tests/loop_08.py new file mode 100644 index 0000000000..98ecbe2f7d --- /dev/null +++ b/integration_tests/loop_08.py @@ -0,0 +1,13 @@ +from lpython import i32, Const + +def main0(): + i: i32 + n: Const[i32] = 10 + M2: Const[i32] = 2 + y: i32 = 0 + for i in range(0, n, M2): # each M2 block in A cols and B rows # !!!!!!!!!!!!!! + y = y + 2 + print(y) + assert(y == 10) + +main0() diff --git a/integration_tests/loop_09.py b/integration_tests/loop_09.py new file mode 100644 index 0000000000..fabe12b747 --- /dev/null +++ b/integration_tests/loop_09.py @@ -0,0 +1,45 @@ +def with_break_for(): + i: i32 + s: i32 = 0 + for i in range(4): + s += i + break + else: + s += 10 + assert s == 0 + +def with_break_while(): + i: i32 = 0 + s: i32 = 0 + while i < 4: + s += i + break + else: + s += 10 + assert s == 0 + +def no_break_for(): + i: i32 + s: i32 = 0 + for i in range(2): + s += i + else: + s += 10 + assert s == 11 + +def no_break_while(): + i: i32 = 0 + s: i32 = 0 + while i < 2: + s += i + i += 1 + else: + s += 10 + assert s == 11 + +no_break_for() +no_break_while() + +with_break_for() +with_break_while() + diff --git a/integration_tests/loop_10.py b/integration_tests/loop_10.py new file mode 100644 index 0000000000..6f9f0defb9 --- /dev/null +++ b/integration_tests/loop_10.py @@ -0,0 +1,126 @@ +def with_break_for(): + i: i32 = 0 + for i in range(4): + i += 1 + break + else: + assert False + + +def with_break_while(): + i: i32 = 0 + while i < 4: + i += 1 + break + else: + assert False + + +def no_break_for(): + i: i32 + j: i32 = 0 + for i in range(2): + j += 1 + else: + print(j) + assert j == 2 + return + assert False + +def break_in_if_for(): + i: i32 + j: i32 = 0 + for i in range(2): + j += 1 + if i == 1: + break + else: + assert False + print(j) + assert j == 2 + +def nested_loop_for_for(): + i: i32 + j: i32 + m: i32 = 0 + for i in range(2): + for j in range(10, 20): + break + else: + m = 10 + print(m) + assert m == 10 + +def nested_loop_for_while(): + i: i32 + j: i32 = 10 + m: i32 = 0 + for i in range(2): + while j < 20: + break + else: + m = 10 + print(m) + assert m == 10 + +def nested_loop_while_for(): + i: i32 = 0 + j: i32 + m: i32 = 0 + while i < 2: + i += 1 + for j in range(10, 20): + break + else: + print(i) + assert i == 2 + m = 10 + print(m) + assert m == 10 + +def nested_loop_while_while(): + i: i32 = 0 + j: i32 = 10 + m: i32 = 0 + while i < 2: + i += 1 + while j < 20: + break + else: + print(i) + assert i == 2 + m = 10 + print(m) + assert m == 10 + +def nested_loop_else(): + i: i32 + j: i32 + l: i32 = 0 + m: i32 = 0 + for i in range(2): + l += 1 + m: i32 = 0 + for j in range(10, 12): + m += 1 + else: + print(m) + assert m == 2 + l += 10 + else: + print(l) + assert l == 22 + m = 10 + print(m) + assert m == 10 + + +with_break_for() +with_break_while() +no_break_for() +break_in_if_for() +nested_loop_for_for() +nested_loop_for_while() +nested_loop_while_for() +nested_loop_while_while() +nested_loop_else() diff --git a/integration_tests/loop_11.py b/integration_tests/loop_11.py new file mode 100644 index 0000000000..c5db7a40a9 --- /dev/null +++ b/integration_tests/loop_11.py @@ -0,0 +1,42 @@ +from lpython import i32 + +#checking for loops in the global scope +sum: i32 = 0 +i: i32 +for i in [1, 2, 3, 4]: + print(i) + sum += i +print("sum = ",sum) +assert sum == 10 + +alphabets: str = "" +c: str +for c in "abcde": + print(c) + alphabets += c +print("alphabets = ",alphabets) +assert alphabets == "abcde" + +alphabets = "" +s : str = "abcde" +for c in s[1:4]: + print(c) + alphabets += c +print("alphabets = ",alphabets) +assert alphabets == "bcd" + +sum = 0 +num_list : list[i32] = [1, 2, 3, 4] +for i in num_list[1:3]: + print(i) + sum += i +print("sum = ",sum) +assert sum == 5 + +sum = 0 +nested_list : list[list[i32]] = [[1, 2, 3, 4]] +for i in nested_list[0]: + print(i) + sum += i +print("sum = ",sum) +assert sum == 10 \ No newline at end of file diff --git a/integration_tests/loop_12.py b/integration_tests/loop_12.py new file mode 100644 index 0000000000..fb12c26981 --- /dev/null +++ b/integration_tests/loop_12.py @@ -0,0 +1,67 @@ + +def test_for_dict_int(): + dict_int: dict[i32, i32] = {1:2, 2:3, 3:4} + key: i32 + s1: i32 = 0 + s2: i32 = 0 + + for key in dict_int: + print(key) + s1 += key + s2 += dict_int[key] + + assert s1 == 6 + assert s2 == 9 + +def test_for_dict_str(): + dict_str: dict[str, str] = {"a":"b", "c":"d"} + key: str + s1: str = "" + s2: str = "" + + for key in dict_str: + print(key) + s1 += key + s2 += dict_str[key] + + assert (s1 == "ac" or s1 == "ca") + assert ((s1 == "ac" and s2 == "bd") or (s1 == "ca" and s2 == "db")) + +def test_for_set_int(): + set_int: set[i32] = {1, 2, 3} + el: i32 + s: i32 = 0 + + for el in set_int: + print(el) + s += el + + assert s == 6 + +def test_for_set_str(): + set_str: set[str] = {'a', 'b'} + el: str + s: str = "" + + for el in set_str: + print(el) + s += el + + assert (s == "ab" or s == "ba") + +def test_nested(): + graph: dict[i32, set[i32]] = {1: {2, 3}} + el: i32 + s: i32 = 0 + for el in graph[1]: + print(el) + s += el + + assert s == 5 + + +test_for_dict_int() +test_for_set_int() +test_for_dict_str() +test_for_set_str() +test_nested() diff --git a/integration_tests/lpconvexhull/__init__.py b/integration_tests/lpconvexhull/__init__.py new file mode 100644 index 0000000000..7744538843 --- /dev/null +++ b/integration_tests/lpconvexhull/__init__.py @@ -0,0 +1 @@ +from .lpconvexhull_main import convex_hull diff --git a/integration_tests/lpconvexhull/lpconvexhull_main.py b/integration_tests/lpconvexhull/lpconvexhull_main.py new file mode 100644 index 0000000000..7bdfa62af2 --- /dev/null +++ b/integration_tests/lpconvexhull/lpconvexhull_main.py @@ -0,0 +1,56 @@ +from lpython import i32 +from .utils import min, distance + +def orientation(p: tuple[i32, i32], q: tuple[i32, i32], r: tuple[i32, i32]) -> i32: + # Function to find the orientation of triplet (p, q, r) + # Returns the following values: + # 0: Colinear + # 1: Clockwise + # 2: Counterclockwise + value: i32 = (q[1] - p[1]) * (r[0] - q[0]) - (q[0] - p[0]) * (r[1] - q[1]) + if value == 0: + return 0 # Colinear + elif value > 0: + return 1 # Clockwise + else: + return 2 # Counterclockwise + + +def convex_hull(points: list[tuple[i32, i32]]) -> list[tuple[i32, i32]]: + """Finds the convex hull of a set of points. + + Args: + points: A list of points. + + Returns: + A list of points that form the convex hull. + """ + + n: i32 = len(points) + if n < 3: + return [(-1, -1)] # Convex hull not possible + + # Find the leftmost point + leftmost: tuple[i32, i32] = min(points) + hull: list[tuple[i32, i32]] = [] + + p: tuple[i32, i32] = leftmost + + while True: + hull.append(p) + q: tuple[i32, i32] = points[0] + + r: tuple[i32, i32] + for r in points: + if r == p or r == q: + continue + direction: i32 = orientation(p, q, r) + if direction == 1 or (direction == 0 and distance(p, r) > distance(p, q)): + q = r + + p = q + + if p == leftmost: + break + + return hull diff --git a/integration_tests/lpconvexhull/utils.py b/integration_tests/lpconvexhull/utils.py new file mode 100644 index 0000000000..a414cb7fa7 --- /dev/null +++ b/integration_tests/lpconvexhull/utils.py @@ -0,0 +1,29 @@ +from lpython import i32, f64 + +def min(points: list[tuple[i32, i32]]) -> tuple[i32, i32]: + """Finds the left-most point in a list of points. + + Args: + points: A list of points. + + Returns: + The left-most point in the list. + """ + + left_most_point: tuple[i32, i32] = points[0] + point: tuple[i32, i32] + for point in points: + if point[0] < left_most_point[0]: + left_most_point = point + + return left_most_point + + +def distance(p: tuple[i32, i32], q: tuple[i32, i32]) -> f64: + # Function to calculate the Euclidean distance between two points + x1: i32; y1: i32 + x2: i32; y2: i32 + + x1, y1 = p + x2, y2 = q + return f64((x2 - x1) ** 2 + (y2 - y1) ** 2) ** 0.5 diff --git a/integration_tests/lpdraw/__init__.py b/integration_tests/lpdraw/__init__.py new file mode 100644 index 0000000000..699214668a --- /dev/null +++ b/integration_tests/lpdraw/__init__.py @@ -0,0 +1 @@ +from .draw import Pixel, Line, Circle, Display, DisplayTerminal, Clear diff --git a/integration_tests/lpdraw/draw.py b/integration_tests/lpdraw/draw.py new file mode 100644 index 0000000000..771d9ea7a9 --- /dev/null +++ b/integration_tests/lpdraw/draw.py @@ -0,0 +1,108 @@ +from lpython import i32, f64, TypeVar +import numpy + +H = TypeVar("H") +W = TypeVar("W") + +def Pixel(H: i32, W: i32, Screen: i32[H, W], x: i32, y: i32) -> None: + if x >= 0 and y >= 0 and x < W and y < H: + Screen[H - 1 - y, x] = 255 + +def Clear(H: i32, W: i32, Screen: i32[H, W]): + i: i32 + j: i32 + for i in range(H): + for j in range(W): + Screen[i, j] = 0 + +def DisplayTerminal(H: i32, W: i32, Screen: i32[H, W]): + i: i32 + j: i32 + + print("+", end = "") + for i in range(W): + print("-", end = "") + print("+") + + for i in range(H): + print("|", end = "") + for j in range(W): + if bool(Screen[i, j]): + print(".", end = "") + else: + print(" ", end = "") + print("|") + + print("+", end = "") + for i in range(W): + print("-", end = "") + print("+") + +def Display(H: i32, W: i32, Screen: i32[H, W]): + i: i32 + j: i32 + + print("P2") + print(W, H) + print(255) + + for i in range(H): + for j in range(W): + print(Screen[i, j]) + +def Line(H: i32, W: i32, Screen: i32[H, W], x1: i32, y1: i32, x2: i32, y2: i32) -> None: + dx: i32 = abs(x2 - x1) + dy: i32 = abs(y2 - y1) + + sx: i32 + sy: i32 + + if x1 < x2: + sx = 1 + else: + sx = -1 + + if y1 < y2: + sy = 1 + else: + sy = -1 + + err: i32 = dx - dy + + while x1 != x2 or y1 != y2: + Pixel(H, W, Screen, x1, y1) + e2: i32 = 2 * err + + if e2 > -dy: + err -= dy + x1 += sx + + if x1 == x2 and y1 == y2: + Pixel(H, W, Screen, x1, y1) + break + + if e2 < dx: + err += dx + y1 += sy + +def Circle(H: i32, W: i32, Screen: i32[H, W], x: i32, y: i32, r: f64) -> None: + x0: i32 = i32(r) + y0: i32 = 0 + err: i32 = 0 + + while x0 >= y0: + Pixel(H, W, Screen, x + x0, y + y0) + Pixel(H, W, Screen, x - x0, y + y0) + Pixel(H, W, Screen, x + x0, y - y0) + Pixel(H, W, Screen, x - x0, y - y0) + Pixel(H, W, Screen, x + y0, y + x0) + Pixel(H, W, Screen, x - y0, y + x0) + Pixel(H, W, Screen, x + y0, y - x0) + Pixel(H, W, Screen, x - y0, y - x0) + + if err <= 0: + y0 += 1 + err += 2 * y0 + 1 + if err > 0: + x0 -= 1 + err -= 2 * x0 + 1 diff --git a/integration_tests/lpython_decorator_01.py b/integration_tests/lpython_decorator_01.py new file mode 100644 index 0000000000..65b1082c86 --- /dev/null +++ b/integration_tests/lpython_decorator_01.py @@ -0,0 +1,16 @@ +from numpy import array +from lpython import i32, f64, lpython + +@lpython(backend="c", backend_optimisation_flags=["-ffast-math", "-funroll-loops", "-O3"]) +def fast_sum(n: i32, x: f64[:]) -> f64: + s: f64 = 0.0 + i: i32 + for i in range(n): + s += x[i] + return s + +def test(): + x: f64[3] = array([1.0, 2.0, 3.0]) + assert fast_sum(3, x) == 6.0 + +test() diff --git a/integration_tests/lpython_decorator_02.py b/integration_tests/lpython_decorator_02.py new file mode 100644 index 0000000000..31cb14c6ba --- /dev/null +++ b/integration_tests/lpython_decorator_02.py @@ -0,0 +1,39 @@ +from numpy import array +from lpython import i32, i64, f64, lpython, TypeVar, Const + +n = TypeVar("n") + +@lpython(backend="c", backend_optimisation_flags=["-ffast-math", "-funroll-loops"]) +def multiply_01(n: i32, x: f64[:]) -> f64[n]: + i: i32 + for i in range(n): + x[i] *= 5.0 + return x + +@lpython +def multiply_02(n: i32, x: i64[:], y: i64[:]) -> i64[n]: + z: i64[n]; i: i32 + for i in range(n): + z[i] = x[i] * y[i] + return z + +@lpython +def const_arg_sum(x: Const[i32]) -> i32: + return 10 + x + + +def test_01(): + size = 5 + x = array([11.0, 12.0, 13.0, 14.0, 15.0]) + y = multiply_01(size, x) + assert y[2] == 65. + + size = 3 + x = array([11, 12, 13]) + y = array([14, 15, 16]) + z = multiply_02(size, x, y) + for i in range(size): + assert z[i] == x[i] * y[i] + assert const_arg_sum(size) == size + 10 + +test_01() diff --git a/integration_tests/lpython_emulation_01.py b/integration_tests/lpython_emulation_01.py new file mode 100644 index 0000000000..29b6c4a6e5 --- /dev/null +++ b/integration_tests/lpython_emulation_01.py @@ -0,0 +1,21 @@ +import lpython_emulation_01_mod +import lpython +from lpython import ccall, i64 +from types import FunctionType +lpython.CTypes.emulations = {k: v for k, v in \ + lpython_emulation_01_mod.__dict__.items() \ + if isinstance(v, FunctionType)} + +@ccall +def f1(a: i64) -> i64: + pass + +@ccall +def f2(a: i64): + pass + +def main(): + assert f1(2) == 3 + f2(4) + +main() diff --git a/integration_tests/lpython_emulation_01_mod.py b/integration_tests/lpython_emulation_01_mod.py new file mode 100644 index 0000000000..3a12ea4c5d --- /dev/null +++ b/integration_tests/lpython_emulation_01_mod.py @@ -0,0 +1,7 @@ +from lpython import i64 + +def f1(a: i64) -> i64: + return a + 1 + +def f2(a: i64): + assert a == 4 diff --git a/integration_tests/modules_01.py b/integration_tests/modules_01.py index 5b70e2d23c..96a0cfb10e 100644 --- a/integration_tests/modules_01.py +++ b/integration_tests/modules_01.py @@ -1,4 +1,5 @@ from modules_01b import f #, g +from lpython import i32 def main0(): x: i32 diff --git a/integration_tests/modules_02.py b/integration_tests/modules_02.py index 690070701e..ccafc3e905 100644 --- a/integration_tests/modules_02.py +++ b/integration_tests/modules_02.py @@ -1,4 +1,5 @@ from modules_02b import f +from lpython import i32 def main0(): x: i32 diff --git a/integration_tests/nrp/nr.py b/integration_tests/nrp/nr.py index 89be2fb0d0..37c33a6905 100644 --- a/integration_tests/nrp/nr.py +++ b/integration_tests/nrp/nr.py @@ -1,4 +1,4 @@ -from ltypes import i32, f64 +from lpython import i32, f64 def func(x: f64, c: f64) -> f64: diff --git a/integration_tests/overload_testing.py b/integration_tests/overload_testing.py index 5fa06f88f0..d7cf1cd96c 100644 --- a/integration_tests/overload_testing.py +++ b/integration_tests/overload_testing.py @@ -1,4 +1,4 @@ -from ltypes import i32, overload +from lpython import i32, overload @overload def foo(a: i32, b: i32) -> i32: diff --git a/integration_tests/overload_testing2.py b/integration_tests/overload_testing2.py index 84ed4d0a4c..c01ae9f6a9 100644 --- a/integration_tests/overload_testing2.py +++ b/integration_tests/overload_testing2.py @@ -1,4 +1,4 @@ -from ltypes import i32, overload +from lpython import i32, overload @overload def foo2(a: i32, b: i32) -> i32: diff --git a/integration_tests/print_02.py b/integration_tests/print_02.py index d87009c59c..5b53eac8f8 100644 --- a/integration_tests/print_02.py +++ b/integration_tests/print_02.py @@ -1,4 +1,4 @@ -from ltypes import i32, f64 +from lpython import i32, f64 # Test: Printing ListConstant def f(): diff --git a/integration_tests/print_04.py b/integration_tests/print_04.py index b6a7cc4766..b66175cefc 100644 --- a/integration_tests/print_04.py +++ b/integration_tests/print_04.py @@ -1,4 +1,4 @@ -from ltypes import i8, i16, i32, i64 +from lpython import i8, i16, i32, i64 u: i64 = i64(-922337203685477580) print(u) diff --git a/integration_tests/print_float.py b/integration_tests/print_float.py index bd43c93b99..66ccb3878b 100644 --- a/integration_tests/print_float.py +++ b/integration_tests/print_float.py @@ -1,4 +1,4 @@ -from ltypes import f64 +from lpython import f64 def main0(): x: f64 = 0.00012 diff --git a/integration_tests/print_list_tuple_01.py b/integration_tests/print_list_tuple_01.py index 17583c008f..2c599d9c0a 100644 --- a/integration_tests/print_list_tuple_01.py +++ b/integration_tests/print_list_tuple_01.py @@ -1,4 +1,4 @@ -from ltypes import f64, i32, c64 +from lpython import f64, i32, c64, InOut def test_print_list(): @@ -20,7 +20,7 @@ def test_print_list(): print(x, y, z, t) -def f(y: list[i32]) -> list[i32]: +def f(y: InOut[list[i32]]) -> list[i32]: y.append(4) return y diff --git a/integration_tests/print_list_tuple_02.py b/integration_tests/print_list_tuple_02.py index 71d85e19aa..57666c50e5 100644 --- a/integration_tests/print_list_tuple_02.py +++ b/integration_tests/print_list_tuple_02.py @@ -1,6 +1,6 @@ -from ltypes import i32, f64 +from lpython import i32, f64, InOut -def insert_tuples_into_list(l: list[tuple[i32, f64, str]], size: i32) -> list[tuple[i32, f64, str]]: +def insert_tuples_into_list(l: InOut[list[tuple[i32, f64, str]]], size: i32) -> list[tuple[i32, f64, str]]: i: i32 string: str t: tuple[i32, f64, str] diff --git a/integration_tests/print_list_tuple_03.py b/integration_tests/print_list_tuple_03.py new file mode 100644 index 0000000000..25006696dd --- /dev/null +++ b/integration_tests/print_list_tuple_03.py @@ -0,0 +1,11 @@ +from lpython import i32 + +def f(): + # issue 1862 + x: dict[i32, tuple[i32, i32]] + x = {1: (1, 2), 2: (3, 4)} + y: dict[i32, list[i32]] + y = {1: [1, 2], 2: [3, 4]} + print(x[1], x[2], y[1]) + +f() diff --git a/integration_tests/recursive_01.py b/integration_tests/recursive_01.py index 9800bc4f26..b739255654 100644 --- a/integration_tests/recursive_01.py +++ b/integration_tests/recursive_01.py @@ -1,4 +1,4 @@ -from ltypes import i32 +from lpython import i32 def fib(n: i32) -> i32: if n <= 1: diff --git a/integration_tests/run_tests.py b/integration_tests/run_tests.py index af4b1b725a..e5df7cf909 100755 --- a/integration_tests/run_tests.py +++ b/integration_tests/run_tests.py @@ -6,10 +6,12 @@ # Initialization DEFAULT_THREADS_TO_USE = 8 # default no of threads is 8 -SUPPORTED_BACKENDS = ['llvm', 'c', 'wasm', 'cpython', 'x86', 'wasm_x86', 'wasm_x64'] +SUPPORTED_BACKENDS = ['llvm', 'c', 'wasm', 'cpython', 'x86', 'wasm_x86', 'wasm_x64', 'c_py', 'c_sym', 'cpython_sym', 'llvm_sym', 'llvm_py', 'llvm_jit'] BASE_DIR = os.path.dirname(os.path.realpath(__file__)) LPYTHON_PATH = f"{BASE_DIR}/../src/bin" +fast_tests = "no" +python_libs_req = "no" def run_cmd(cmd, cwd=None): print(f"+ {cmd}") @@ -22,8 +24,8 @@ def run_cmd(cmd, cwd=None): def run_test(backend): run_cmd(f"mkdir {BASE_DIR}/_lpython-tmp-test-{backend}", cwd=BASE_DIR) cwd = f"{BASE_DIR}/_lpython-tmp-test-{backend}" - run_cmd(f"cmake -DKIND={backend} ..", cwd=cwd) - run_cmd(f"make -j{DEFAULT_THREADS_TO_USE}", cwd=cwd) + run_cmd(f"cmake -DKIND={backend} -DFAST={fast_tests} -DPYTHON_LIBS_REQ={python_libs_req} ..", cwd=cwd) + run_cmd(f"cmake --build . --parallel {DEFAULT_THREADS_TO_USE}", cwd=cwd) run_cmd(f"ctest -j{DEFAULT_THREADS_TO_USE} --output-on-failure", cwd=cwd) @@ -40,8 +42,10 @@ def get_args(): parser.add_argument("-j", "-n", "--no_of_threads", type=int, help="Parallel testing on given number of threads") parser.add_argument("-b", "--backends", nargs="*", default=["llvm", "cpython"], - type=str, help="Test the requested backends (%s)" % \ + type=str, help="Test the requested backends (%s), default: llvm, cpython" % \ ", ".join(SUPPORTED_BACKENDS)) + parser.add_argument("-f", "--fast", action='store_true', + help="Run supported tests with --fast") return parser.parse_args() @@ -49,14 +53,16 @@ def main(): args = get_args() # Setup - global DEFAULT_THREADS_TO_USE + global DEFAULT_THREADS_TO_USE, fast_tests, python_libs_req os.environ["PATH"] = LPYTHON_PATH + os.pathsep + os.environ["PATH"] # delete previously created directories (if any) for backend in SUPPORTED_BACKENDS: run_cmd(f"rm -rf {BASE_DIR}/_lpython-tmp-test-{backend}") DEFAULT_THREADS_TO_USE = args.no_of_threads or DEFAULT_THREADS_TO_USE + fast_tests = "yes" if args.fast else "no" for backend in args.backends: + python_libs_req = "yes" if backend in ["cpython", "c_py", "c_sym", "llvm_sym", 'llvm_py', 'llvm_jit'] else "no" test_backend(backend) diff --git a/integration_tests/sizeof_01.py b/integration_tests/sizeof_01.py index 10aae4437a..d6c042b50c 100644 --- a/integration_tests/sizeof_01.py +++ b/integration_tests/sizeof_01.py @@ -1,4 +1,4 @@ -from ltypes import sizeof, i64, i32, f32, f64, c32, c64, i16, ccall, CPtr +from lpython import sizeof, i64, i32, f32, f64, c32, c64, i16, ccall, CPtr @ccall def cmalloc(bytes: i64) -> CPtr: diff --git a/integration_tests/sizeof_02.py b/integration_tests/sizeof_02.py new file mode 100644 index 0000000000..40d34af64c --- /dev/null +++ b/integration_tests/sizeof_02.py @@ -0,0 +1,10 @@ +from sizeof_02_module import A +from lpython import i64, sizeof + +def get_sizeof() -> i64: + return sizeof(A) + +def test(): + print(get_sizeof()) + +test() diff --git a/integration_tests/sizeof_02_module.py b/integration_tests/sizeof_02_module.py new file mode 100644 index 0000000000..19aeb73705 --- /dev/null +++ b/integration_tests/sizeof_02_module.py @@ -0,0 +1,6 @@ +from lpython import i32, f32, dataclass + +@dataclass +class A: + x: i32 + y: f32 diff --git a/integration_tests/str_to_list_cast.py b/integration_tests/str_to_list_cast.py index 49db437d69..cff65fcce2 100644 --- a/integration_tests/str_to_list_cast.py +++ b/integration_tests/str_to_list_cast.py @@ -1,3 +1,5 @@ +from lpython import i32 + def f(): x: list[str] x = list("lpython") diff --git a/integration_tests/structs_01.py b/integration_tests/structs_01.py index cbf943867c..7ad860f5f2 100644 --- a/integration_tests/structs_01.py +++ b/integration_tests/structs_01.py @@ -1,4 +1,4 @@ -from ltypes import i32, f32, f64, dataclass +from lpython import i32, f32, f64, dataclass, InOut @dataclass class A: @@ -9,13 +9,12 @@ def f(a: A): print(a.x) print(a.y) -def change_struct(a: A): +def change_struct(a: InOut[A]): a.x = a.x + 1 a.y = a.y + f32(1) def g(): - x: A - x = A(f32(3.25), 3) + x: A = A(f32(3.25), 3) f(x) assert x.x == 3 assert f64(x.y) == 3.25 diff --git a/integration_tests/structs_02.py b/integration_tests/structs_02.py index 56a6a5217f..0e99458c34 100644 --- a/integration_tests/structs_02.py +++ b/integration_tests/structs_02.py @@ -1,4 +1,4 @@ -from ltypes import i32, f32, dataclass, CPtr, Pointer, c_p_pointer, pointer, ccallable, empty_c_void_p, f64 +from lpython import i32, f32, dataclass, CPtr, Pointer, c_p_pointer, pointer, ccallable, empty_c_void_p, f64 @dataclass class A: @@ -9,17 +9,14 @@ class A: def f(a: CPtr) -> None: x: i32 y: f32 - a1: A + a1: A = A(3, f32(3.25)) a2: Pointer[A] - a1 = A(3, f32(3.25)) a2 = pointer(a1) print(a2, pointer(a1)) x = a2.x y = a2.y assert x == 3 assert f64(y) == 3.25 - a2 = c_p_pointer(a, A) - print(a, a2, pointer(a1)) def g(): b: CPtr = empty_c_void_p() diff --git a/integration_tests/structs_02b.py b/integration_tests/structs_02b.py new file mode 100644 index 0000000000..ed061ff6ce --- /dev/null +++ b/integration_tests/structs_02b.py @@ -0,0 +1,43 @@ +from lpython import (i32, f32, dataclass, CPtr, Pointer, c_p_pointer, pointer, + ccallable, empty_c_void_p, f64, ccall, sizeof, i64) + +@ccall +def _lfortran_malloc(size: i32) -> CPtr: + pass + +def alloc(buf_size:i64) -> CPtr: + return _lfortran_malloc(i32(buf_size)) + +@ccallable +@dataclass +class A: + x: i32 + y: f32 + +@ccallable +def f(a: CPtr) -> None: + x: i32 + y: f32 + a1: A = A(3, f32(3.25)) + a2: Pointer[A] + a2 = pointer(a1) + print(a2, pointer(a1)) + # TODO: does not work: + #x = a2.x + #y = a2.y + #assert x == 3 + #assert f64(y) == 3.25 + a2 = c_p_pointer(a, A) + print(a, a2, pointer(a1)) + print(a2.x, a2.y) + assert a2.x == 5 + assert a2.y == f32(6.0) + +def g(): + b: CPtr = alloc(sizeof(A)) + b2: Pointer[A] = c_p_pointer(b, A) + b2.x = 5 + b2.y = f32(6) + f(b) + +g() diff --git a/integration_tests/structs_03.py b/integration_tests/structs_03.py index de92f83167..aa5e3214e2 100644 --- a/integration_tests/structs_03.py +++ b/integration_tests/structs_03.py @@ -1,4 +1,4 @@ -from ltypes import i32, f32, f64, dataclass, Pointer, pointer +from lpython import i32, f32, f64, dataclass, Pointer, pointer @dataclass class A: diff --git a/integration_tests/structs_04.py b/integration_tests/structs_04.py index ab3555b143..b1a1ad4307 100644 --- a/integration_tests/structs_04.py +++ b/integration_tests/structs_04.py @@ -1,4 +1,4 @@ -from ltypes import i32, f32, f64, dataclass +from lpython import i32, f32, f64, dataclass, field from copy import deepcopy @dataclass @@ -8,8 +8,8 @@ class A: @dataclass class B: - a: A z: i32 + a: A = field(default_factory=lambda: A(f32(0.0), 0)) def f(b: B): print(b.z, b.a.x, b.a.y) @@ -20,7 +20,7 @@ def f(b: B): def g(): a1: A = A(f32(1.0), 1) a2: A = A(f32(2.0), 2) - b: B = B(a1, 1) + b: B = B(1, a1) b.a = deepcopy(a2) b.z = 1 b.a.x = 2 diff --git a/integration_tests/structs_05.py b/integration_tests/structs_05.py index 233aa8190c..6ae6262ac7 100644 --- a/integration_tests/structs_05.py +++ b/integration_tests/structs_05.py @@ -1,4 +1,5 @@ -from ltypes import i32, f64, i64, i16, i8, f32, dataclass +from lpython import i32, f64, i64, i16, i8, f32, dataclass, InOut, Array +from numpy import empty @dataclass class A: @@ -10,7 +11,7 @@ class A: c: i8 d: bool -def verify(s: A[:], x1: i32, y1: f64, x2: i32, y2: f64): +def verify(s: Array[A, :], x1: i32, y1: f64, x2: i32, y2: f64): eps: f64 = 1e-12 s0: A = s[0] print(s0.x, s0.y, s0.z, s0.a, s0.b, s0.c, s0.d) @@ -32,7 +33,7 @@ def verify(s: A[:], x1: i32, y1: f64, x2: i32, y2: f64): assert s1.c == i8(x2) assert s1.d -def update_1(s: A): +def update_1(s: InOut[A]): s.x = 2 s.y = 1.2 s.z = i64(2) @@ -40,7 +41,7 @@ def update_1(s: A): s.b = i16(2) s.c = i8(2) -def update_2(s: A[:]): +def update_2(s: Array[A, :]): s[1].x = 3 s[1].y = 2.3 s[1].z = i64(3) @@ -49,9 +50,7 @@ def update_2(s: A[:]): s[1].c = i8(3) def g(): - # TODO: Replace y: A[2] with y: A[2] = [None, None] - # TODO: And enable cpython in integration_tests. - y: A[2] + y: Array[A, 2] = empty([2], dtype=A) y[0] = A(1.1, 1, i64(1), f32(1.1), i16(1), i8(1), True) y[1] = A(2.2, 2, i64(2), f32(2.2), i16(2), i8(2), True) verify(y, 1, 1.1, 2, 2.2) diff --git a/integration_tests/structs_06.py b/integration_tests/structs_06.py index 74a928a4ac..f82e026cdb 100644 --- a/integration_tests/structs_06.py +++ b/integration_tests/structs_06.py @@ -1,4 +1,4 @@ -from ltypes import i8, i32, i64, i8, i8, dataclass, packed +from lpython import i8, i32, i64, i8, i8, dataclass, packed @packed(aligned=1) @dataclass diff --git a/integration_tests/structs_07.py b/integration_tests/structs_07.py index 7d124ffb2e..3d0508ab3a 100644 --- a/integration_tests/structs_07.py +++ b/integration_tests/structs_07.py @@ -1,4 +1,4 @@ -from ltypes import i32, i64, i8, CPtr, sizeof, dataclass, ccall +from lpython import i32, i64, i8, CPtr, sizeof, dataclass, ccall @dataclass class A: diff --git a/integration_tests/structs_08.py b/integration_tests/structs_08.py index ba13e3e2db..0085334584 100644 --- a/integration_tests/structs_08.py +++ b/integration_tests/structs_08.py @@ -1,4 +1,4 @@ -from ltypes import i32, i64, dataclass, union, Union +from lpython import i32, i64, dataclass, union, Union from enum import Enum @union diff --git a/integration_tests/structs_09.py b/integration_tests/structs_09.py index ceff0277d5..9ba7139cbc 100644 --- a/integration_tests/structs_09.py +++ b/integration_tests/structs_09.py @@ -1,4 +1,4 @@ -from ltypes import i32, f32, f64, dataclass +from lpython import i32, f32, f64, dataclass, field @dataclass class C: @@ -7,13 +7,13 @@ class C: @dataclass class B: z: i32 - bc: C + bc: C = field(default_factory=lambda: C(f32(0.0))) @dataclass class A: y: f32 x: i32 - b: B + b: B = field(default_factory=lambda: B(0, C(f32(0.0)))) def f(a: A): @@ -22,8 +22,7 @@ def f(a: A): print(a.b.z) def g(): - x: A - x = A(f32(3.25), 3, B(71, C(f32(4.0)))) + x: A = A(f32(3.25), 3, B(71, C(f32(4.0)))) f(x) assert x.x == 3 assert f64(x.y) == 3.25 diff --git a/integration_tests/structs_10.py b/integration_tests/structs_10.py index bab2800e61..db067ed825 100644 --- a/integration_tests/structs_10.py +++ b/integration_tests/structs_10.py @@ -1,18 +1,18 @@ -from ltypes import i32, f64, dataclass +from lpython import i32, f64, dataclass, field from numpy import empty, float64 @dataclass class Mat: - mat: f64[2, 2] + mat: f64[2, 2] = field(default_factory=lambda: empty((2, 2), dtype=float64)) @dataclass class Vec: - vec: f64[2] + vec: f64[2] = field(default_factory=lambda: empty(2, dtype=float64)) @dataclass class MatVec: - mat: Mat - vec: Vec + mat: Mat = field(default_factory=lambda: Mat()) + vec: Vec = field(default_factory=lambda: Vec()) def rotate(mat_vec: MatVec) -> f64[2]: rotated_vec: f64[2] = empty(2, dtype=float64) diff --git a/integration_tests/structs_11.py b/integration_tests/structs_11.py index 4fc71e595e..1eea62eb75 100644 --- a/integration_tests/structs_11.py +++ b/integration_tests/structs_11.py @@ -1,4 +1,4 @@ -from ltypes import i32, f64, dataclass +from lpython import i32, f64, dataclass @dataclass class A: diff --git a/integration_tests/structs_12.py b/integration_tests/structs_12.py index cb48e11125..c7a2cfb715 100644 --- a/integration_tests/structs_12.py +++ b/integration_tests/structs_12.py @@ -1,4 +1,4 @@ -from ltypes import i32, i16, dataclass +from lpython import i32, i16, dataclass @dataclass class A: diff --git a/integration_tests/structs_13.py b/integration_tests/structs_13.py index 4a7bb51f32..9806fa1ac9 100644 --- a/integration_tests/structs_13.py +++ b/integration_tests/structs_13.py @@ -1,5 +1,8 @@ -from ltypes import i32, i16, i64, CPtr, dataclass, ccall, Pointer, c_p_pointer, sizeof +from lpython import (i32, i16, i64, CPtr, dataclass, ccall, Pointer, + c_p_pointer, sizeof, ccallable) +from numpy import array +@ccallable @dataclass class A: x: i32 @@ -23,7 +26,7 @@ def add_Aptr_members(Ax: i32, Ay: i16) -> i32: def test_A_member_passing(): array_cptr: CPtr = cmalloc(sizeof(A) * i64(10)) assert not bool(is_null(array_cptr)), "Failed to allocate array on memory" - array_ptr: Pointer[A[:]] = c_p_pointer(array_cptr, A[:]) + array_ptr: Pointer[A[:]] = c_p_pointer(array_cptr, A[:], array([10])) i: i32; sum_A_members: i32 for i in range(10): array_ptr[i] = A(i, i16(i + 1)) diff --git a/integration_tests/structs_14.py b/integration_tests/structs_14.py index 05e399758e..911ebc2094 100644 --- a/integration_tests/structs_14.py +++ b/integration_tests/structs_14.py @@ -1,4 +1,4 @@ -from ltypes import i8, dataclass, i32, f32, c32, f64, i16, i64, c64, ccallable, packed +from lpython import i8, dataclass, i32, f32, c32, f64, i16, i64, c64, ccallable, packed from numpy import empty, int8, int16, int32, int64, float32, complex64, complex128, float64 from copy import deepcopy @@ -71,7 +71,7 @@ def f(): buffer_.buffer3[i] = c32(i + 7) # buffer_clink_.buffer3 is a ctypes.Array # of type c_float_complex (a ctypes.Structure - # defined in ltypes.py) and c32(i + 8) is a + # defined in lpython.py) and c32(i + 8) is a # Python object. Python doesn't allow assigning # a Python object to ctypes.Structure. Hence, # the following line is commented out. diff --git a/integration_tests/structs_15.py b/integration_tests/structs_15.py index a7e9fc9c88..7341d42d60 100644 --- a/integration_tests/structs_15.py +++ b/integration_tests/structs_15.py @@ -1,5 +1,6 @@ -from ltypes import i32, i16, i8, i64, CPtr, dataclass, ccall, Pointer, c_p_pointer, sizeof +from lpython import i32, i16, i8, CPtr, dataclass, ccall, Pointer, c_p_pointer, sizeof, ccallable +@ccallable @dataclass class A: x: i16 diff --git a/integration_tests/structs_16.py b/integration_tests/structs_16.py index 1cb49e8e3f..6cf6e638d5 100644 --- a/integration_tests/structs_16.py +++ b/integration_tests/structs_16.py @@ -1,4 +1,4 @@ -from ltypes import i32, i64, dataclass, union, Union +from lpython import i32, i64, dataclass, union, Union @dataclass class A: diff --git a/integration_tests/structs_17.py b/integration_tests/structs_17.py index 10d9717451..30042f68f7 100644 --- a/integration_tests/structs_17.py +++ b/integration_tests/structs_17.py @@ -1,4 +1,4 @@ -from ltypes import i32, f32, f64, dataclass +from lpython import i32, f32, f64, dataclass, field @dataclass class B: @@ -6,13 +6,13 @@ class B: @dataclass class C: cz: f32 - bc: C + bc: C = field(default_factory=lambda: C(f32(0.0))) @dataclass class A: y: f32 x: i32 - b: B + b: B = field(default_factory=lambda: B(0, B.C(f32(0.0)))) def f(a: A): diff --git a/integration_tests/structs_18.py b/integration_tests/structs_18.py index 45ba10d1b5..d6a5fbd66b 100644 --- a/integration_tests/structs_18.py +++ b/integration_tests/structs_18.py @@ -1,4 +1,4 @@ -from ltypes import i8, dataclass, i32, f32, c32, f64, i16, i64, c64, ccallable, packed, ccall, CPtr, p_c_pointer, empty_c_void_p, pointer +from lpython import i8, dataclass, i32, f32, c32, f64, i16, i64, c64, ccallable, packed, ccall, CPtr, p_c_pointer, empty_c_void_p, pointer from numpy import empty, int8, int16, int32, int64, float32, complex64, complex128, float64 from copy import deepcopy diff --git a/integration_tests/structs_19.py b/integration_tests/structs_19.py index ac34ebf0a4..1ae675eb81 100644 --- a/integration_tests/structs_19.py +++ b/integration_tests/structs_19.py @@ -1,4 +1,4 @@ -from ltypes import (i8, dataclass, i32, f32, c32, f64, i16, i64, c64, +from lpython import (i8, dataclass, i32, f32, c32, f64, i16, i64, c64, ccall, CPtr, c_p_pointer, Pointer, ccallable) from numpy import empty, int32, int8, float32, float64, int16, int64, complex64, complex128 diff --git a/integration_tests/structs_20.py b/integration_tests/structs_20.py index 6270416cf1..0b26bb6398 100644 --- a/integration_tests/structs_20.py +++ b/integration_tests/structs_20.py @@ -1,4 +1,4 @@ -from ltypes import (i8, dataclass, i32, f32, c32, f64, i16, i64, c64, +from lpython import (i8, dataclass, i32, f32, c32, f64, i16, i64, c64, ccall, CPtr, c_p_pointer, Pointer, packed, ccallable) from numpy import empty, int8, int16, float32, complex64 diff --git a/integration_tests/structs_21.py b/integration_tests/structs_21.py index 24c672c149..26d83aee39 100644 --- a/integration_tests/structs_21.py +++ b/integration_tests/structs_21.py @@ -1,4 +1,4 @@ -from ltypes import i32, CPtr, dataclass, c_p_pointer, p_c_pointer, \ +from lpython import i32, CPtr, dataclass, c_p_pointer, p_c_pointer, \ pointer, empty_c_void_p, Pointer, ccallable @ccallable diff --git a/integration_tests/structs_22.py b/integration_tests/structs_22.py new file mode 100644 index 0000000000..7329d4c26b --- /dev/null +++ b/integration_tests/structs_22.py @@ -0,0 +1,43 @@ +from lpython import dataclass, i32, f64, u64 +from numpy import array + +@dataclass +class Foo: + x: i32 + y: i32 + +@dataclass +class Foo2: + p: f64 + q: i32 + r: u64 + +def main0() -> None: + foos: Foo[2] = array([Foo(1, 2), Foo(3, 4)]) + print(foos[0].x, foos[0].y, foos[1].x, foos[1].y) + + assert foos[0].x == 1 + assert foos[0].y == 2 + assert foos[1].x == 3 + assert foos[1].y == 4 + +def main1() -> None: + foos2: Foo2[3] = array([Foo2(-2.3, 42, u64(3)), Foo2(45.5, -3, u64(10001)), Foo2(1.0, -101, u64(100))]) + i: i32 + for i in range(3): + print(foos2[i].p, foos2[i].q, foos2[i].r) + + eps: f64 + eps = 1e-12 + assert abs(foos2[0].p - (-2.3)) <= eps + assert foos2[0].q == 42 + assert foos2[0].r == u64(3) + assert abs(foos2[1].p - (45.5)) <= eps + assert foos2[1].q == -3 + assert foos2[1].r == u64(10001) + assert abs(foos2[2].p - (1.0)) <= eps + assert foos2[2].q == -101 + assert foos2[2].r == u64(100) + +main0() +main1() diff --git a/integration_tests/structs_23.py b/integration_tests/structs_23.py new file mode 100644 index 0000000000..2e3950a48b --- /dev/null +++ b/integration_tests/structs_23.py @@ -0,0 +1,30 @@ +from lpython import dataclass, i32, u64, f64 + +@dataclass +class A: + a: i32 + b: i32 + +@dataclass +class B: + a: u64 + b: f64 + +def main0(): + s: A = A(b=-24, a=6) + print(s.a) + print(s.b) + + assert s.a == 6 + assert s.b == -24 + +def main1(): + s: B = B(u64(22), b=3.14) + print(s.a) + print(s.b) + + assert s.a == u64(22) + assert abs(s.b - 3.14) <= 1e-12 + +main0() +main1() diff --git a/integration_tests/structs_24.py b/integration_tests/structs_24.py new file mode 100644 index 0000000000..10bf76c890 --- /dev/null +++ b/integration_tests/structs_24.py @@ -0,0 +1,18 @@ +from lpython import dataclass, i32, f64, u64 +from numpy import array + +@dataclass +class Foo: + x: i32 + y: i32 + +def main0() -> None: + foos: Foo[2] = array([Foo(y=2, x=1), Foo(x=3, y=4)]) + print(foos[0].x, foos[0].y, foos[1].x, foos[1].y) + + assert foos[0].x == 1 + assert foos[0].y == 2 + assert foos[1].x == 3 + assert foos[1].y == 4 + +main0() diff --git a/integration_tests/structs_25.py b/integration_tests/structs_25.py new file mode 100644 index 0000000000..d5402c6c5d --- /dev/null +++ b/integration_tests/structs_25.py @@ -0,0 +1,20 @@ +from lpython import i32, dataclass, Array +from numpy import empty + +@dataclass +class Foo: + x: i32 + y: i32 + +def init(foos: Array[Foo, :]) -> None: + foos[0] = Foo(5, 21) + +def main0() -> None: + foos: Array[Foo, 1] = empty(1, dtype=Foo) + init(foos) + print("foos[0].x =", foos[0].x) + + assert foos[0].x == 5 + assert foos[0].y == 21 + +main0() diff --git a/integration_tests/structs_26.py b/integration_tests/structs_26.py new file mode 100644 index 0000000000..40cf3fdd4b --- /dev/null +++ b/integration_tests/structs_26.py @@ -0,0 +1,18 @@ +from lpython import dataclass, i32 + +@dataclass +class StringIO: + """Imitate the parts of io.StringIO we need.""" + _buf : str + _0cursor : i32 = 0 + _len : i32 = 0 + +def main0(): + io: StringIO = StringIO("random input xyz", 5, 24) + + print(io) + assert io._buf == "random input xyz" + assert io._0cursor == 5 + assert io._len == 24 + +main0() diff --git a/integration_tests/structs_27.py b/integration_tests/structs_27.py new file mode 100644 index 0000000000..4009794f48 --- /dev/null +++ b/integration_tests/structs_27.py @@ -0,0 +1,77 @@ +from lpython import dataclass, i32, u16, f32 + + +@dataclass +class StringIO: + _buf : str = '' + _0cursor : i32 = 10 + _len : i32 = 1 + +@dataclass +class StringIONew: + _buf : str + _0cursor : i32 = i32(142) + _len : i32 = i32(2439) + _var1 : u16 = u16(23) + _var2 : f32 = f32(30.24) + +#print("ok") + +def test_issue_1928(): + integer_asr : str = '(Integer 4 [])' + test_dude : StringIO = StringIO(integer_asr) + assert test_dude._buf == integer_asr + assert test_dude._len == 1 + assert test_dude._0cursor == 10 + test_dude._len = 100 + assert test_dude._len == 100 + test_dude._0cursor = 31 + assert test_dude._0cursor == 31 + + test_dude2 : StringIO = StringIO(integer_asr, 3) + assert test_dude2._buf == integer_asr + assert test_dude2._len == 1 + assert test_dude2._0cursor == 3 + test_dude2._len = 100 + assert test_dude2._len == 100 + test_dude2._0cursor = 31 + assert test_dude2._0cursor == 31 + + test_dude3 : StringIO = StringIO(integer_asr, 3, 5) + assert test_dude3._buf == integer_asr + assert test_dude3._len == 5 + assert test_dude3._0cursor == 3 + test_dude3._len = 100 + assert test_dude3._len == 100 + test_dude3._0cursor = 31 + assert test_dude3._0cursor == 31 + + test_dude4 : StringIO = StringIO() + assert test_dude4._buf == '' + assert test_dude4._len == 1 + assert test_dude4._0cursor == 10 + test_dude4._len = 100 + assert test_dude4._len == 100 + test_dude4._0cursor = 31 + assert test_dude4._0cursor == 31 + + +def test_issue_1981(): + integer_asr : str = '(Integer 4 [])' + test_dude : StringIONew = StringIONew(integer_asr) + assert test_dude._buf == integer_asr + assert test_dude._len == 2439 + assert test_dude._0cursor == 142 + assert test_dude._var1 == u16(23) + assert abs(test_dude._var2 - f32(30.24)) < f32(1e-5) + test_dude._len = 13 + test_dude._0cursor = 52 + test_dude._var1 = u16(34) + assert test_dude._buf == integer_asr + assert test_dude._len == 13 + assert test_dude._0cursor == 52 + assert test_dude._var1 == u16(34) + + +test_issue_1981() +test_issue_1928() diff --git a/integration_tests/structs_28.py b/integration_tests/structs_28.py new file mode 100644 index 0000000000..9e0f3bf502 --- /dev/null +++ b/integration_tests/structs_28.py @@ -0,0 +1,15 @@ +from lpython import dataclass, i32 + +@dataclass +class Pattern: + _foo : str + pass + _n: i32 + +def main0(): + p: Pattern = Pattern("some string", 5) + assert p._foo == "some string" + assert p._n == 5 + print(p) + +main0() diff --git a/integration_tests/structs_29.py b/integration_tests/structs_29.py new file mode 100644 index 0000000000..f78c7e2d94 --- /dev/null +++ b/integration_tests/structs_29.py @@ -0,0 +1,20 @@ +from lpython import dataclass, i32 + +@dataclass +class Foo: + x: i32 + y: i32 + + +def main0() -> None: + x: list[Foo] + y: Foo = Foo(0, 1) + z: Foo = Foo(1, 2) + x = [y, z] + i: i32 = 0 + for y in x: + assert y.x == i + assert y.y == i+1 + i += 1 + +main0() diff --git a/integration_tests/structs_30.py b/integration_tests/structs_30.py new file mode 100644 index 0000000000..83ad571a11 --- /dev/null +++ b/integration_tests/structs_30.py @@ -0,0 +1,15 @@ +from lpython import dataclass, i32 + +@dataclass +class Pattern: + _foo : str + ... + _n: i32 + +def main0(): + p: Pattern = Pattern("some string", 5) + assert p._foo == "some string" + assert p._n == 5 + print(p) + +main0() diff --git a/integration_tests/structs_31.py b/integration_tests/structs_31.py new file mode 100644 index 0000000000..472bf8d8d4 --- /dev/null +++ b/integration_tests/structs_31.py @@ -0,0 +1,22 @@ +from lpython import packed, dataclass, field, i32, InOut + +@packed +@dataclass +class inner_struct: + a: i32 + +@packed +@dataclass +class outer_struct: + b: inner_struct = field(default_factory=lambda: inner_struct(0)) + +def update_my_inner_struct(my_inner_struct: InOut[inner_struct]) -> None: + my_inner_struct.a = 99999 + +def main() -> None: + my_outer_struct: outer_struct = outer_struct() + + update_my_inner_struct(my_outer_struct.b) + assert my_outer_struct.b.a == 99999 + +main() diff --git a/integration_tests/structs_32.py b/integration_tests/structs_32.py new file mode 100644 index 0000000000..6e57217a87 --- /dev/null +++ b/integration_tests/structs_32.py @@ -0,0 +1,45 @@ +from lpython import packed, dataclass, field, i32, InOut + + +@packed +@dataclass +class inner_struct: + a: i32 + + +@packed +@dataclass +class outer_struct: + b: inner_struct = field(default_factory=lambda: inner_struct(0)) + + +def update_my_inner_struct(my_inner_struct: InOut[inner_struct]) -> None: + my_inner_struct.a = 99999 + + +def update_my_outer_struct(my_outer_struct: InOut[outer_struct]) -> None: + my_outer_struct.b.a = 12345 + + +def main() -> None: + my_outer_struct: outer_struct = outer_struct() + my_inner_struct: inner_struct = my_outer_struct.b + + assert my_outer_struct.b.a == 0 + + my_outer_struct.b.a = 12345 + assert my_outer_struct.b.a == 12345 + + my_outer_struct.b.a = 0 + assert my_outer_struct.b.a == 0 + + update_my_outer_struct(my_outer_struct) + assert my_outer_struct.b.a == 12345 + + my_inner_struct.a = 1111 + assert my_inner_struct.a == 1111 + + update_my_inner_struct(my_inner_struct) + assert my_inner_struct.a == 99999 + +main() diff --git a/integration_tests/structs_33.py b/integration_tests/structs_33.py new file mode 100644 index 0000000000..24a537447a --- /dev/null +++ b/integration_tests/structs_33.py @@ -0,0 +1,24 @@ +from lpython import packed, dataclass, field, i32 + +# test issue 2125 + +@packed +@dataclass +class inner_struct: + inner_field: i32 = 0 + + +@packed +@dataclass +class outer_struct: + inner_s : inner_struct = field(default_factory=lambda: inner_struct()) + + +def check() -> None: + outer_struct_instance : outer_struct = outer_struct(inner_struct(5)) + outer_struct_instance2 : outer_struct = outer_struct_instance + inner_struct_instance : inner_struct = outer_struct_instance2.inner_s + assert inner_struct_instance.inner_field == 5 + + +check() diff --git a/integration_tests/structs_34.py b/integration_tests/structs_34.py new file mode 100644 index 0000000000..f69d6d5f6a --- /dev/null +++ b/integration_tests/structs_34.py @@ -0,0 +1,24 @@ +from lpython import packed, dataclass, ccallable, i32, ccallback + +@ccallable +@packed +@dataclass +class struct_0: + val_0 : i32 = 613 + +@ccallable +@packed +@dataclass +class struct_1: + val_1 : struct_0 = struct_0() + +def print_val_0_in_struct_0(struct_0_instance : struct_0) -> i32: + print(struct_0_instance.val_0) + return 0 + +@ccallback +def entry_point() -> i32: + struct_1_instance : struct_1 = struct_1() + return print_val_0_in_struct_0(struct_1_instance.val_1) + +assert entry_point() == 0 diff --git a/integration_tests/structs_35.py b/integration_tests/structs_35.py new file mode 100644 index 0000000000..4bdb499d75 --- /dev/null +++ b/integration_tests/structs_35.py @@ -0,0 +1,26 @@ +from lpython import dataclass, field, i32 +from numpy import array + +@dataclass +class X: + a: i32 = 123 + b: bool = True + c: list[i32] = field(default_factory=lambda: [1, 2, 3]) + d: i32[3] = field(default_factory=lambda: array([4, 5, 6])) + e: i32 = field(default=-5) + +def main0(): + x: X = X() + print(x) + assert x.a == 123 + assert x.b == True + assert x.c[0] == 1 + assert x.d[1] == 5 + assert x.e == -5 + x.c[0] = 3 + x.d[0] = 3 + print(x) + assert x.c[0] == 3 + assert x.d[0] == 3 + +main0() diff --git a/integration_tests/symbolics_01.py b/integration_tests/symbolics_01.py new file mode 100644 index 0000000000..ae0dab1dd4 --- /dev/null +++ b/integration_tests/symbolics_01.py @@ -0,0 +1,22 @@ +from sympy import Symbol, pi +from lpython import S + +def main0(): + x: S = Symbol('x') + y: S = Symbol('y') + x = pi + z: S = x + y + x = z + print(x) + print(z) + assert(x == z) + assert(z == pi + y) + assert(z != S(2)*pi + y) + + # testing PR 2404 + p: S = Symbol('pi') + print(p) + print(p != pi) + assert(p != pi) + +main0() \ No newline at end of file diff --git a/integration_tests/symbolics_02.py b/integration_tests/symbolics_02.py new file mode 100644 index 0000000000..7650b11d2d --- /dev/null +++ b/integration_tests/symbolics_02.py @@ -0,0 +1,123 @@ +from sympy import Symbol, pi, Add, Mul, Pow +from lpython import S + +def test_symbolic_operations(): + x: S = Symbol('x') + y: S = Symbol('y') + pi1: S = pi + pi2: S = pi + + # Addition + z: S = x + y + z1: bool = z.func == Add + z2: bool = z.func == Mul + assert(z == x + y) + assert(z1 == True) + assert(z2 == False) + if z.func == Add: + assert True + else: + assert False + assert(z.func == Add) + assert(z.args[0] == x or z.args[0] == y) + assert(z.args[1] == y or z.args[1] == x) + print(z) + + # Subtraction + w: S = x - y + w1: bool = w.func == Add + assert(w == x - y) + assert(w1 == True) + if w.func == Add: + assert True + else: + assert False + assert(w.func == Add) + print(w) + + # Multiplication + u: S = x * y + u1: bool = u.func == Mul + assert(u == x * y) + assert(u1 == True) + if u.func == Mul: + assert True + else: + assert False + assert(u.func == Mul) + assert(u.args[0] == x) + assert(u.args[1] == y) + print(u) + + # Division + v: S = x / y + v1: bool = v.func == Mul + assert(v == x / y) + assert(v1 == True) + if v.func == Mul: + assert True + else: + assert False + assert(v.func == Mul) + print(v) + + # Power + p: S = x ** y + p1: bool = p.func == Pow + p2: bool = p.func == Add + p3: bool = p.func == Mul + assert(p == x ** y) + assert(p1 == True) + assert(p2 == False) + assert(p3 == False) + if p.func == Pow: + assert True + else: + assert False + assert(p.func == Pow) + print(p) + + # Casting + a: S = S(100) + b: S = S(-100) + c: S = a + b + assert(c == S(0)) + print(c) + + # Comparison + b1: bool = pi1 == pi2 + print(b1) + assert(b1 == True) + b2: bool = pi1 != pi + print(b2) + assert(b2 == False) + b3: bool = pi1 != x + print(b3) + assert(b3 == True) + b4: bool = pi == Symbol("x") + print(b4) + assert(b4 == False) + + # is_integer check + assert(pi1.is_integer == False) + assert(a.is_integer == True) + assert(c.is_integer == True) + + # is_positive check + assert(a.is_positive == True) + assert(b.is_positive == False) + assert(c.is_positive == False) + + # logical binop check + l1: bool = True and p.func == Pow + l2: bool = False or p.func == Pow + l3: bool = False and u.func == Mul + l4: bool = True or u.func == Add + if p.func == Pow and u.func == Mul: + print(True) + assert(l1) + assert(l2) + assert(not l3) + assert(l4) + +test_symbolic_operations() diff --git a/integration_tests/symbolics_03.py b/integration_tests/symbolics_03.py new file mode 100644 index 0000000000..8dc91a9720 --- /dev/null +++ b/integration_tests/symbolics_03.py @@ -0,0 +1,24 @@ +from sympy import Symbol, pi +from lpython import S + +def test_operator_chaining(): + w: S = S(2) + x: S = Symbol('x') + y: S = Symbol('y') + z: S = Symbol('z') + + a: S = x * w + b: S = a + pi + c: S = b / z + d: S = c ** w + + assert(a == S(2)*x) + assert(b == pi + S(2)*x) + assert(c == (pi + S(2)*x)/z) + assert(d == (pi + S(2)*x)**S(2)/z**S(2)) + print(a) # Expected: 2*x + print(b) # Expected: pi + 2*x + print(c) # Expected: (pi + 2*x)/z + print(d) # Expected: (pi + 2*x)**2/z**2 + +test_operator_chaining() \ No newline at end of file diff --git a/integration_tests/symbolics_04.py b/integration_tests/symbolics_04.py new file mode 100644 index 0000000000..63d30bf3f6 --- /dev/null +++ b/integration_tests/symbolics_04.py @@ -0,0 +1,41 @@ +from sympy import Symbol, pi, S +from lpython import S + +def test_chained_operations(): + x: S = Symbol('x') + y: S = Symbol('y') + z: S = Symbol('z') + a: S = Symbol('a') + b: S = Symbol('b') + + # Chained Operations + w: S = (x + y) * ((a - b) / (pi + z)) + result: S = (w ** S(2) - pi) + S(3) + + # Print Statements + assert(result == S(3) + (a -b)**S(2)*(x + y)**S(2)/(z + pi)**S(2) - pi) + print(result) + + # Additional Variables + c: S = Symbol('c') + d: S = Symbol('d') + e: S = Symbol('e') + f: S = Symbol('f') + + # Chained Operations with Additional Variables + x = (c * d + e) / f + y = (x - S(10)) * (pi + S(5)) + z = y ** (S(2) / (f + d)) + result = (z + e) * (a - b) + + # Print Statements + assert(result == (a - b)*(e + ((S(5) + pi)*(S(-10) + (e + c*d)/f))**(S(2)/(d + f)))) + print(result) + assert(x == (e + c*d)/f) + print(x) + assert(y == (S(5) + pi)*(S(-10) + (e + c*d)/f)) + print(y) + assert(z == ((S(5) + pi)*(S(-10) + (e + c*d)/f))**(S(2)/(d + f))) + print(z) + +test_chained_operations() \ No newline at end of file diff --git a/integration_tests/symbolics_05.py b/integration_tests/symbolics_05.py new file mode 100644 index 0000000000..b503bbcdda --- /dev/null +++ b/integration_tests/symbolics_05.py @@ -0,0 +1,51 @@ +from sympy import Symbol, expand, diff, sin, cos, exp, pi +from lpython import S + +def test_operations(): + x: S = Symbol('x') + y: S = Symbol('y') + z: S = Symbol('z') + a: S = (x + y)**S(2) + b: S = (x + y + z)**S(3) + + # test expand + assert(a.expand() == S(2)*x*y + x**S(2) + y**S(2)) + assert(expand(b) == S(3)*x*y**S(2) + S(3)*x*z**S(2) + S(3)*x**S(2)*y + S(3)*x**S(2)*z +\ + S(3)*y*z**S(2) + S(3)*y**S(2)*z + S(6)*x*y*z + x**S(3) + y**S(3) + z**S(3)) + print(a.expand()) + print(expand(b)) + + # test diff + assert(a.diff(x) == S(2)*(x + y)) + assert(diff(b, x) == S(3)*(x + y + z)**S(2)) + print(a.diff(x)) + print(diff(b, x)) + + # test diff 2 + c:S = sin(x) + d:S = cos(x) + assert(sin(Symbol("x")).diff(x) == d) + assert(sin(x).diff(Symbol("x")) == d) + assert(sin(x).diff(x) == d) + assert(sin(x).diff(x).diff(x) == S(-1)*c) + assert(sin(x).expand().diff(x).diff(x) == S(-1)*c) + assert((sin(x) + cos(x)).diff(x) == S(-1)*c + d) + assert((sin(x) + cos(x) + exp(x) + pi).diff(x).expand().diff(x) == exp(x) + S(-1)*c + S(-1)*d) + + # test args + assert(a.args[0] == x + y) + assert(a.args[1] == S(2)) + assert(b.args[0] == x + y + z) + assert(b.args[1] == S(3)) + assert(c.args[0] == x) + assert(d.args[0] == x) + + # test subs + b1: S = b.subs(x, y) + b1 = b1.subs(z, y) + assert(a.subs(x, y) == S(4)*y**S(2)) + assert(b1 == S(27)*y**S(3)) + assert(c.subs(x, y) == sin(y)) + assert(d.subs(x, z) == cos(z)) + +test_operations() \ No newline at end of file diff --git a/integration_tests/symbolics_06.py b/integration_tests/symbolics_06.py new file mode 100644 index 0000000000..f56d76c80d --- /dev/null +++ b/integration_tests/symbolics_06.py @@ -0,0 +1,58 @@ +from sympy import Symbol, sin, cos, exp, log, Abs, pi, diff, sign +from lpython import S + +def test_elementary_functions(): + + # test sin, cos + x: S = Symbol('x') + assert(sin(pi) == S(0)) + assert(sin(pi/S(2)) == S(1)) + assert(sin(S(2)*pi) == S(0)) + assert(cos(pi) == S(-1)) + assert(cos(pi/S(2)) == S(0)) + assert(cos(S(2)*pi) == S(1)) + assert(diff(sin(x), x) == cos(x)) + assert(diff(cos(x), x) == S(-1)*sin(x)) + + # test exp, log + assert(exp(S(0)) == S(1)) + assert(log(S(1)) == S(0)) + assert(diff(exp(x), x) == exp(x)) + assert(diff(log(x), x) == S(1)/x) + + # test Abs + assert(Abs(S(-10)) == S(10)) + assert(Abs(S(10)) == S(10)) + assert(Abs(S(-1)*x) == Abs(x)) + + # test sign + assert(sign(S(-10)) == S(-1)) + assert(sign(S(0)) == S(0)) + assert(sign(S(10)) == S(1)) + assert(sign(S(2)* x) == sign(x)) + assert(sign(S(-1)* x) == S(-1) * sign(x)) + + # test composite functions + a: S = exp(x) + b: S = sin(a) + b1: bool = b.func == sin + c: S = cos(b) + d: S = log(c) + d1: bool = d.func == log + e: S = Abs(d) + print(e) + assert(b1 == True) + if b.func == sin: + assert True + else: + assert False + assert(b.func == sin) + assert(d1 == True) + if d.func == log: + assert True + else: + assert False + assert(d.func == log) + assert(e == Abs(log(cos(sin(exp(x)))))) + +test_elementary_functions() \ No newline at end of file diff --git a/integration_tests/symbolics_07.py b/integration_tests/symbolics_07.py new file mode 100644 index 0000000000..f6d9ea947f --- /dev/null +++ b/integration_tests/symbolics_07.py @@ -0,0 +1,23 @@ +from lpython import ccall, CPtr +import os + +@ccall(header="symengine/cwrapper.h", c_shared_lib="symengine", c_shared_lib_path=f"{os.environ['CONDA_PREFIX']}/lib") +def basic_new_heap() -> CPtr: + pass + +@ccall(header="symengine/cwrapper.h", c_shared_lib="symengine", c_shared_lib_path=f"{os.environ['CONDA_PREFIX']}/lib") +def basic_const_pi(x: CPtr) -> None: + pass + +@ccall(header="symengine/cwrapper.h", c_shared_lib="symengine", c_shared_lib_path=f"{os.environ['CONDA_PREFIX']}/lib") +def basic_str(x: CPtr) -> str: + pass + +def main0(): + x: CPtr = basic_new_heap() + basic_const_pi(x) + s: str = basic_str(x) + print(s) + assert s == "pi" + +main0() diff --git a/integration_tests/symbolics_08.py b/integration_tests/symbolics_08.py new file mode 100644 index 0000000000..15e010d160 --- /dev/null +++ b/integration_tests/symbolics_08.py @@ -0,0 +1,31 @@ +from lpython import ccall, CPtr, p_c_pointer, pointer, i64, empty_c_void_p +import os + +@ccall(header="symengine/cwrapper.h", c_shared_lib="symengine", c_shared_lib_path=f"{os.environ['CONDA_PREFIX']}/lib") +def basic_new_stack(x: CPtr) -> None: + pass + +@ccall(header="symengine/cwrapper.h", c_shared_lib="symengine", c_shared_lib_path=f"{os.environ['CONDA_PREFIX']}/lib") +def basic_free_stack(x: CPtr) -> None: + pass + +@ccall(header="symengine/cwrapper.h", c_shared_lib="symengine", c_shared_lib_path=f"{os.environ['CONDA_PREFIX']}/lib") +def basic_const_pi(x: CPtr) -> None: + pass + +@ccall(header="symengine/cwrapper.h", c_shared_lib="symengine", c_shared_lib_path=f"{os.environ['CONDA_PREFIX']}/lib") +def basic_str(x: CPtr) -> str: + pass + +def main0(): + y: i64 = i64(0) + x: CPtr = empty_c_void_p() + p_c_pointer(pointer(y, i64), x) + basic_new_stack(x) + basic_const_pi(x) + s: str = basic_str(x) + print(s) + assert s == "pi" + basic_free_stack(x) + +main0() \ No newline at end of file diff --git a/integration_tests/symbolics_09.py b/integration_tests/symbolics_09.py new file mode 100644 index 0000000000..18567769a4 --- /dev/null +++ b/integration_tests/symbolics_09.py @@ -0,0 +1,21 @@ +from sympy import Symbol, pi, sin, cos +from lpython import S, i32 + +def addInteger(x: S, y: S, z: S, i: i32): + _i: S = S(i) + print(x + y + z + _i) + +def call_addInteger(): + a: S = Symbol("x") + b: S = Symbol("y") + c: S = pi + d: S = sin(a) + e: S = cos(b) + addInteger(c, d, e, 2) + addInteger(c, sin(a), cos(b), 2) + addInteger(pi, sin(Symbol("x")), cos(Symbol("y")), 2) + +def main0(): + call_addInteger() + +main0() diff --git a/integration_tests/symbolics_10.py b/integration_tests/symbolics_10.py new file mode 100644 index 0000000000..c833c1e59f --- /dev/null +++ b/integration_tests/symbolics_10.py @@ -0,0 +1,26 @@ +from sympy import Symbol, sin, pi +from lpython import S + +def test_attributes(): + w: S = pi + x: S = Symbol('x') + y: S = Symbol('y') + z: S = sin(x) + + # test has + assert(w.has(x) == False) + assert(y.has(x) == False) + assert(x.has(x) == True) + assert(x.has(x) == z.has(x)) + + # test has 2 + assert(sin(x).has(x) == True) + assert(sin(x).has(y) == False) + assert(sin(Symbol("x")).has(x) == True) + assert(sin(Symbol("x")).has(y) == False) + assert(sin(Symbol("x")).has(Symbol("x")) == True) + assert(sin(Symbol("x")).has(Symbol("y")) == False) + assert(sin(Symbol("x")).has(Symbol("x")) != sin(Symbol("x")).has(Symbol("y"))) + assert(sin(Symbol("x")).has(Symbol("x")) == sin(Symbol("y")).has(Symbol("y"))) + +test_attributes() \ No newline at end of file diff --git a/integration_tests/symbolics_11.py b/integration_tests/symbolics_11.py new file mode 100644 index 0000000000..49696c09c2 --- /dev/null +++ b/integration_tests/symbolics_11.py @@ -0,0 +1,19 @@ +from sympy import Symbol, sin, pi +from lpython import S + +def test_extraction_of_elements(): + x: S = Symbol("x") + l1: list[S] = [x, pi, sin(x), Symbol("y")] + ele1: S = l1[0] + ele2: S = l1[1] + ele3: S = l1[2] + ele4: S = l1[3] + + assert(ele1 == x) + assert(ele2 == pi) + assert(ele3 == sin(x)) + assert(ele4 == Symbol("y")) + print(ele1, ele2, ele3, ele4) + print(l1[0], l1[1], l1[2], l1[3]) + +test_extraction_of_elements() diff --git a/integration_tests/symbolics_12.py b/integration_tests/symbolics_12.py new file mode 100644 index 0000000000..05711e2b1e --- /dev/null +++ b/integration_tests/symbolics_12.py @@ -0,0 +1,70 @@ +from sympy import Symbol, E, log, exp, oo +from lpython import S + +def main0(): + # Testing out symbolic constants like E, oo etc + + # Define symbolic variables + x: S = Symbol('x') + y: S = Symbol('y') + + # Assign E to the variable x + x = E + + # Check if x is equal to E + assert x == E + + # Perform some symbolic operations + z: S = x + y + + # Check if z is equal to E + y + assert z == E + y + + # Check if x is not equal to 2E + y + assert x != S(2) * E + y + + # Evaluate some mathematical expressions + expr1: S = log(E) + expr2: S = exp(S(1)) + + # Check the results + assert expr1 == S(1) + assert expr2 == E ** S(1) + + # Print the results + print("x = ", x) + print("z = ", z) + print("log(E) = ", expr1) + print("exp(1) = ", expr2) + + # Test symbolic infinity constant + inf: S = oo + + # Check if inf is equal to oo + assert inf == oo + + # Perform some symbolic operations with oo + z = x + inf + + # Check if z is equal to x + oo + assert z == x + oo + + # Check if x is not equal to 2 * oo + y + assert x != S(2) * oo + y + + # Evaluate some mathematical expressions with oo + expr1 = log(oo) + expr2 = exp(oo) + + # Check the results + assert expr1 == oo + assert expr2 == oo + + # Print the results + print("inf = ", inf) + print("z = ", z) + print("log(oo) = ", expr1) + print("exp(oo) = ", expr2) + + +main0() diff --git a/integration_tests/symbolics_13.py b/integration_tests/symbolics_13.py new file mode 100644 index 0000000000..6494d28a40 --- /dev/null +++ b/integration_tests/symbolics_13.py @@ -0,0 +1,12 @@ +from lpython import S +from sympy import pi + +def func() -> S: + return pi + +def test_func(): + z: S = func() + print(z) + assert z == pi + +test_func() diff --git a/integration_tests/symbolics_14.py b/integration_tests/symbolics_14.py new file mode 100644 index 0000000000..f99ad7aa39 --- /dev/null +++ b/integration_tests/symbolics_14.py @@ -0,0 +1,15 @@ +from lpython import S +from sympy import Symbol + +def mmrv(x: S) -> list[S]: + l1: list[S] = [x] + return l1 + +def test_mrv1(): + x: S = Symbol("x") + ans: list[S] = mmrv(x) + element_1: S = ans[0] + print(element_1) + assert element_1 == x + +test_mrv1() \ No newline at end of file diff --git a/integration_tests/symbolics_15.py b/integration_tests/symbolics_15.py new file mode 100644 index 0000000000..096f7c442d --- /dev/null +++ b/integration_tests/symbolics_15.py @@ -0,0 +1,72 @@ +from lpython import ccall, CPtr, p_c_pointer, pointer, i64, empty_c_void_p, Out +import os + +@ccall(header="symengine/cwrapper.h", c_shared_lib="symengine", c_shared_lib_path=f"{os.environ['CONDA_PREFIX']}/lib") +def basic_new_stack(x: CPtr) -> None: + pass + +@ccall(header="symengine/cwrapper.h", c_shared_lib="symengine", c_shared_lib_path=f"{os.environ['CONDA_PREFIX']}/lib") +def basic_new_heap() -> CPtr: + pass + +@ccall(header="symengine/cwrapper.h", c_shared_lib="symengine", c_shared_lib_path=f"{os.environ['CONDA_PREFIX']}/lib") +def basic_const_pi(x: CPtr) -> None: + pass + +@ccall(header="symengine/cwrapper.h", c_shared_lib="symengine", c_shared_lib_path=f"{os.environ['CONDA_PREFIX']}/lib") +def basic_assign(x: CPtr, y:CPtr) -> None: + pass + +@ccall(header="symengine/cwrapper.h", c_shared_lib="symengine", c_shared_lib_path=f"{os.environ['CONDA_PREFIX']}/lib") +def basic_str(x: CPtr) -> str: + pass + +@ccall(header="symengine/cwrapper.h", c_shared_lib="symengine", c_shared_lib_path=f"{os.environ['CONDA_PREFIX']}/lib") +def basic_free_stack(x: CPtr) -> None: + pass + +def mmrv(r: Out[list[CPtr]]) -> None: + # x: S = pi + _x: i64 = i64(0) + x: CPtr = empty_c_void_p() + p_c_pointer(pointer(_x, i64), x) + basic_new_stack(x) + basic_const_pi(x) + + # l1: list[S] = [x] + _l1: list[CPtr] = [x] + l1: list[CPtr] = [] + + i: i32 = 0 + for i in range(len(_l1)): + tmp: CPtr = basic_new_heap() + l1.append(tmp) + basic_assign(l1[0], x) + + # print(l1[0]) + s1: str = basic_str(l1[0]) + print(s1) + assert s1 == "pi" + + # r = l1 + r = l1 + + basic_free_stack(x) + +def test_mrv(): + # ans : list[S] + # temp : list[S] + ans: list[CPtr] + temp: list[CPtr] + + # mmrv(ans) + # temp = ans + mmrv(ans) + temp = ans + + # print(temp[0]) + s2: str = basic_str(temp[0]) + print(s2) + assert s2 == "pi" + +test_mrv() \ No newline at end of file diff --git a/integration_tests/symbolics_16.py b/integration_tests/symbolics_16.py new file mode 100644 index 0000000000..abdaa2c92b --- /dev/null +++ b/integration_tests/symbolics_16.py @@ -0,0 +1,18 @@ +from lpython import S +from sympy import Symbol, pi, sin + +def mmrv() -> list[S]: + x: S = Symbol('x') + l1: list[S] = [pi, sin(x)] + return l1 + +def test_mrv1(): + ans: list[S] = mmrv() + element_1: S = ans[0] + element_2: S = ans[1] + assert element_1 == pi + assert element_2 == sin(Symbol('x')) + print(element_1, element_2) + + +test_mrv1() \ No newline at end of file diff --git a/integration_tests/symbolics_17.py b/integration_tests/symbolics_17.py new file mode 100644 index 0000000000..74494e8049 --- /dev/null +++ b/integration_tests/symbolics_17.py @@ -0,0 +1,10 @@ +from lpython import S +from sympy import Symbol, pi + +def test_main(): + x: S = Symbol('x') + if x != pi: + print(x != pi) + assert x != pi + +test_main() \ No newline at end of file diff --git a/integration_tests/symbolics_18.py b/integration_tests/symbolics_18.py new file mode 100644 index 0000000000..b3dd8bad2c --- /dev/null +++ b/integration_tests/symbolics_18.py @@ -0,0 +1,36 @@ +from lpython import S +from sympy import Symbol, log + +def func_01(e: S, x: S) -> S: + print(e) + if e == x: + return x + print(e) + return e + +def test_func_01(): + x: S = Symbol("x") + ans: S = func_01(log(x), x) + print(ans) + +def func_02(e: S, x: S) -> list[S]: + print(e) + if e == x: + list1: list[S] = [x] + return list1 + else: + print(e) + list2: list[S] = func_02(x, x) + return list2 + +def test_func_02(): + x: S = Symbol("x") + ans: list[S] = func_02(log(x), x) + ele: S = ans[0] + print(ele) + +def tests(): + test_func_01() + test_func_02() + +tests() \ No newline at end of file diff --git a/integration_tests/test_01_goto.py b/integration_tests/test_01_goto.py deleted file mode 100644 index 2857c01768..0000000000 --- a/integration_tests/test_01_goto.py +++ /dev/null @@ -1,35 +0,0 @@ -from ltypes import with_goto, i32 - -@with_goto -def f() -> i32: - i:i32 - for i in range(10): - if i == 5: - goto .end - - label .end - assert i == 5 - return i - -@with_goto -def g(size: i32) -> i32: - i:i32 - - i = 0 - label .loop - if i >= size: - goto .end - i += 1 - goto .loop - - label .end - return i - -def test_goto(): - print(f()) - print(g(10)) - print(g(20)) - assert g(30) == 30 - assert g(40) == 40 - -test_goto() diff --git a/integration_tests/test_ConstantEllipsis b/integration_tests/test_ConstantEllipsis new file mode 100644 index 0000000000..58222aa9eb --- /dev/null +++ b/integration_tests/test_ConstantEllipsis @@ -0,0 +1,13 @@ +from lpython import i32 + +def test_Ellipsis_Function(): + ... + +def test_Ellipsis_For(): + i:i32 + for i in range(5): + ... + +def main0(): + test_Ellipsis_Function() + test_Ellipsis_For() \ No newline at end of file diff --git a/integration_tests/test_argv_01.py b/integration_tests/test_argv_01.py index d22b468e37..c7ba747072 100644 --- a/integration_tests/test_argv_01.py +++ b/integration_tests/test_argv_01.py @@ -1,12 +1,22 @@ -from ltypes import i32 -from sys import _lpython_argv +from lpython import i32 +from sys import argv def test(): - exe: str = _lpython_argv()[0] - i: i32 - for i in range(len(exe)-1, 0, -1): - if exe[i] == '/': + exe: str = argv[0] + res: str = "" + + if exe[0] == '.': + exe = exe[1:len(exe)] + + s: str + for s in exe: + if s == '.': break - assert exe[i+1:len(exe)] == 'test_argv_01' + if s == '/': + res = "" + else: + res += s + + assert res == 'test_argv_01' test() diff --git a/integration_tests/test_attributes.py b/integration_tests/test_attributes.py new file mode 100644 index 0000000000..f42775b678 --- /dev/null +++ b/integration_tests/test_attributes.py @@ -0,0 +1,12 @@ +def test_attributes() -> None: + a: i32 = 10 + assert a.bit_length() == 4 + + b: str = 'abc' + assert b.upper() == 'ABC' + + c: list[i32] = [10, 20, 30] + assert c[0].bit_length() == 4 + assert c.index(10) == 0 + +test_attributes() diff --git a/integration_tests/test_bit_length.py b/integration_tests/test_bit_length.py index 68bccae13f..8c64a4682d 100644 --- a/integration_tests/test_bit_length.py +++ b/integration_tests/test_bit_length.py @@ -1,5 +1,5 @@ from math import floor, log2 -from ltypes import i8, i32, i16 +from lpython import i8, i32, i16 def ff(): assert -8 .bit_length() == -4 @@ -24,8 +24,25 @@ def ff3(): x = -i16(one << i16(13)) assert i32(x.bit_length()) == 14 +def ff4(): + print((-100).bit_length()) + print((-4).bit_length()) + + assert (-100).bit_length() == 7 + assert (-4).bit_length() == 3 + +def ff5(): + a: i32 + a = 100 + print((-a).bit_length()) + print((-(-(-(-a)))).bit_length()) + + assert (-a).bit_length() == 7 + assert (-(-(-(-a)))).bit_length() == 7 ff() ff1() ff2() ff3() +ff4() +ff5() diff --git a/integration_tests/test_bool_binop.py b/integration_tests/test_bool_binop.py index 98e817b2fa..e869e8f060 100644 --- a/integration_tests/test_bool_binop.py +++ b/integration_tests/test_bool_binop.py @@ -1,4 +1,4 @@ -from ltypes import i32, f64 +from lpython import i32, f64 def f(): i: i32 diff --git a/integration_tests/test_builtin.py b/integration_tests/test_builtin.py index 8980fc37bc..7df13c3833 100644 --- a/integration_tests/test_builtin.py +++ b/integration_tests/test_builtin.py @@ -1,4 +1,4 @@ -from ltypes import i32 +from lpython import i32 def test_ord(): s: str diff --git a/integration_tests/test_builtin_abs.py b/integration_tests/test_builtin_abs.py index 1186b832ce..73f1820f18 100644 --- a/integration_tests/test_builtin_abs.py +++ b/integration_tests/test_builtin_abs.py @@ -1,4 +1,4 @@ -from ltypes import f32, f64, i32, i64, i8, i16 +from lpython import f32, f64, i32, i64, i8, i16 def test_abs(): x: f64 @@ -32,8 +32,8 @@ def test_abs(): b: bool b = True - assert abs(b) == 1 + assert abs(i32(b)) == 1 b = False - assert abs(b) == 0 + assert abs(i32(b)) == 0 test_abs() diff --git a/integration_tests/test_builtin_bin.py b/integration_tests/test_builtin_bin.py index ce38dd7cc4..b8c3f20e5a 100644 --- a/integration_tests/test_builtin_bin.py +++ b/integration_tests/test_builtin_bin.py @@ -1,4 +1,4 @@ -from ltypes import i32 +from lpython import i32 def test_bin(): i: i32 diff --git a/integration_tests/test_builtin_bool.py b/integration_tests/test_builtin_bool.py index 03b68f592c..fee923a1f2 100644 --- a/integration_tests/test_builtin_bool.py +++ b/integration_tests/test_builtin_bool.py @@ -1,4 +1,4 @@ -from ltypes import i8, i16, i32, i64, f32, f64, c32, c64 +from lpython import i8, i16, i32, i64, f32, f64, c32, c64 def test_bool(): a: i32 diff --git a/integration_tests/test_builtin_divmod.py b/integration_tests/test_builtin_divmod.py index 7a2713a565..9296e0605d 100644 --- a/integration_tests/test_builtin_divmod.py +++ b/integration_tests/test_builtin_divmod.py @@ -1,4 +1,4 @@ -from ltypes import i32 +from lpython import i32 def f(): i: i32 = 42356 diff --git a/integration_tests/test_builtin_float.py b/integration_tests/test_builtin_float.py index f2b2ea20ec..9b28b0b61a 100644 --- a/integration_tests/test_builtin_float.py +++ b/integration_tests/test_builtin_float.py @@ -1,4 +1,4 @@ -from ltypes import i32, f32, f64 +from lpython import i32, f32, f64 def test_float(): i: i32 diff --git a/integration_tests/test_builtin_hex.py b/integration_tests/test_builtin_hex.py index 38ae1b0d7b..bf63d59f48 100644 --- a/integration_tests/test_builtin_hex.py +++ b/integration_tests/test_builtin_hex.py @@ -1,4 +1,4 @@ -from ltypes import i32 +from lpython import i32 def test_hex(): i: i32 diff --git a/integration_tests/test_builtin_int.py b/integration_tests/test_builtin_int.py index a1deb495ed..248a82c100 100644 --- a/integration_tests/test_builtin_int.py +++ b/integration_tests/test_builtin_int.py @@ -1,4 +1,4 @@ -from ltypes import f64, i32, i64 +from lpython import f64, i32, i64 def test_int(): f: f64 diff --git a/integration_tests/test_builtin_len.py b/integration_tests/test_builtin_len.py index 70f5ea9f98..8da4a0dfc5 100644 --- a/integration_tests/test_builtin_len.py +++ b/integration_tests/test_builtin_len.py @@ -1,4 +1,4 @@ -from ltypes import i32, f64 +from lpython import i32, f64 def test_len(): s: str diff --git a/integration_tests/test_builtin_oct.py b/integration_tests/test_builtin_oct.py index 516ee9933c..5613323f1f 100644 --- a/integration_tests/test_builtin_oct.py +++ b/integration_tests/test_builtin_oct.py @@ -1,4 +1,4 @@ -from ltypes import i32 +from lpython import i32 def test_oct(): i: i32 diff --git a/integration_tests/test_builtin_pow.py b/integration_tests/test_builtin_pow.py index f2869e10f5..3ee942a167 100644 --- a/integration_tests/test_builtin_pow.py +++ b/integration_tests/test_builtin_pow.py @@ -1,4 +1,4 @@ -from ltypes import i32, i64, f32, f64, c32 +from lpython import i32, i64, f32, f64, c32 def test_pow(): # TODO: the commented tests should also work @@ -80,7 +80,7 @@ def test_pow(): k: i64 k = i64(5) assert pow(i, j, k) == i64(4) - assert pow(102, 3, 121) == 38 + # assert pow(102, 3, 121) == 38 c1: c32 c1 = c32(complex(4, 5)) diff --git a/integration_tests/test_builtin_round.py b/integration_tests/test_builtin_round.py index 6ac3fd1d5e..ee158d18f3 100644 --- a/integration_tests/test_builtin_round.py +++ b/integration_tests/test_builtin_round.py @@ -1,4 +1,4 @@ -from ltypes import i8, i16, i32, i64, f32, f64 +from lpython import i8, i16, i32, i64, f32, f64 def test_round(): f: f64 diff --git a/integration_tests/test_builtin_str.py b/integration_tests/test_builtin_str.py index cb65a46b47..bf3c1c106f 100644 --- a/integration_tests/test_builtin_str.py +++ b/integration_tests/test_builtin_str.py @@ -1,4 +1,4 @@ -from ltypes import f32, f64, i32 +from lpython import f32, f64, i32 def test_str_int_float(): s: str diff --git a/integration_tests/test_builtin_str_02.py b/integration_tests/test_builtin_str_02.py index 6498a631b7..aef019b4bb 100644 --- a/integration_tests/test_builtin_str_02.py +++ b/integration_tests/test_builtin_str_02.py @@ -1,4 +1,4 @@ -from ltypes import i32 +from lpython import i32 def _lpython_strcmp_eq(a: str, b: str) -> bool: if len(a) != len(b): diff --git a/integration_tests/test_builtin_sum.py b/integration_tests/test_builtin_sum.py index 6243565801..000198dad0 100644 --- a/integration_tests/test_builtin_sum.py +++ b/integration_tests/test_builtin_sum.py @@ -1,4 +1,4 @@ -from ltypes import f32, f64, i32, i64 +from lpython import f32, f64, i32, i64 def test_sum(): arr_i32 :list[i32] diff --git a/integration_tests/test_builtin_type.py b/integration_tests/test_builtin_type.py new file mode 100644 index 0000000000..188313444f --- /dev/null +++ b/integration_tests/test_builtin_type.py @@ -0,0 +1,32 @@ +from lpython import i32, f64 + +def test_builtin_type(): + i: i32 = 42 + f: f64 = 64.0 + s: str = "Hello, LPython!" + l: list[i32] = [1, 2, 3, 4, 5] + d: dict[str, i32] = {"a": 1, "b": 2, "c": 3} + t: tuple[str, i32] = ("a", 1) + res: str = "" + + res = str(type(i)) + print(res) + assert res == "" + res = str(type(f)) + print(res) + assert res == "" + res = str(type(s)) + print(res) + assert res == "" + res = str(type(l)) + print(res) + assert res == "" + res = str(type(d)) + print(res) + assert res == "" + res = str(type(t)) + print(res) + assert res == "" + + +test_builtin_type() diff --git a/integration_tests/test_builtin_type_set.py b/integration_tests/test_builtin_type_set.py new file mode 100644 index 0000000000..d0265b1c1a --- /dev/null +++ b/integration_tests/test_builtin_type_set.py @@ -0,0 +1,11 @@ +from lpython import i32 + +def test_builtin_type_set(): + st: set[i32] = {1, 2, 3, 4} + + res: str = str(type(st)) + print(res) + assert res == "" + + +test_builtin_type_set() diff --git a/integration_tests/test_c_interop_01.py b/integration_tests/test_c_interop_01.py index 3d8c5e7852..278e49a7ea 100644 --- a/integration_tests/test_c_interop_01.py +++ b/integration_tests/test_c_interop_01.py @@ -1,4 +1,4 @@ -from ltypes import ccall, f32, f64, i32, i64 +from lpython import ccall, f32, f64, i32, i64 #from math import pi @ccall @@ -9,14 +9,6 @@ def _lfortran_dsin(x: f64) -> f64: def _lfortran_ssin(x: f32) -> f32: pass -@ccall -def _lfortran_bgt32(i: i32, j: i32) -> i32: - pass - -@ccall -def _lfortran_bgt64(i: i64, j: i64) -> i32: - pass - #@ccall #def _lfortran_random_number(n: i64, v: f64[:]): # pass @@ -24,13 +16,8 @@ def _lfortran_bgt64(i: i64, j: i64) -> i32: def test_c_callbacks(): pi: f64 = 3.141592653589793238462643383279502884197 assert abs(_lfortran_dsin(pi) - 0.0) < 1e-12 - assert abs(_lfortran_dsin(pi/2) - 1.0) < 1e-12 + assert abs(_lfortran_dsin(pi/2.0) - 1.0) < 1e-12 assert abs(_lfortran_ssin(f32(pi)) - f32(0.0)) < f32(1e-6) assert abs(_lfortran_ssin(f32(pi/2.0)) - f32(1.0)) < f32(1e-6) - assert _lfortran_bgt32(3, 4) == 0 - assert _lfortran_bgt32(4, 3) == 1 - assert _lfortran_bgt64(i64(3), i64(4)) == 0 - assert _lfortran_bgt64(i64(4), i64(3)) == 1 - test_c_callbacks() diff --git a/integration_tests/test_c_interop_02.py b/integration_tests/test_c_interop_02.py index 55efd59e1d..1500e09892 100644 --- a/integration_tests/test_c_interop_02.py +++ b/integration_tests/test_c_interop_02.py @@ -1,4 +1,4 @@ -from ltypes import ccall, f32, f64, i8, i16, i32, i64 +from lpython import ccall, f32, f64, i8, i16, i32, i64 @ccall def f_f64_f64(x: f64) -> f64: diff --git a/integration_tests/test_c_interop_03.py b/integration_tests/test_c_interop_03.py index c94037a4d4..516eee6cda 100644 --- a/integration_tests/test_c_interop_03.py +++ b/integration_tests/test_c_interop_03.py @@ -1,4 +1,4 @@ -from ltypes import (ccall, f32, f64, i32, i64, CPtr, pointer, Pointer, +from lpython import (ccall, f32, f64, i32, i64, CPtr, pointer, Pointer, p_c_pointer, empty_c_void_p) @ccall diff --git a/integration_tests/test_c_interop_04.py b/integration_tests/test_c_interop_04.py index 30bb8236b6..0be53d4841 100644 --- a/integration_tests/test_c_interop_04.py +++ b/integration_tests/test_c_interop_04.py @@ -1,4 +1,4 @@ -from ltypes import (ccall, f32, f64, i32, i64, CPtr, pointer, Pointer, +from lpython import (ccall, f32, f64, i32, i64, CPtr, pointer, Pointer, p_c_pointer, empty_c_void_p) from numpy import empty, int32 diff --git a/integration_tests/test_c_interop_05.py b/integration_tests/test_c_interop_05.py index 116779d8db..aaa799520d 100644 --- a/integration_tests/test_c_interop_05.py +++ b/integration_tests/test_c_interop_05.py @@ -1,4 +1,4 @@ -from ltypes import ccall, f32, f64, i32, i64, CPtr, pointer, Pointer, p_c_pointer +from lpython import ccall, f32, f64, i32, i64, CPtr, pointer, Pointer, p_c_pointer, ccallback @ccall def f_i32_i32(x: i32) -> i32: diff --git a/integration_tests/test_cmath.py b/integration_tests/test_cmath.py index 2721b04dfa..5b8429f41c 100644 --- a/integration_tests/test_cmath.py +++ b/integration_tests/test_cmath.py @@ -1,6 +1,8 @@ -from cmath import (exp, log, sqrt, acos, asin, atan, cos, sin, tan, - acosh, asinh, atanh, cosh, sinh, tanh) -from ltypes import c64, c32 +from cmath import (acos, acosh, asin, asinh, atan, atanh, cos, cosh, exp, log, + phase, polar, rect, sin, sinh, sqrt, tan, tanh) + +from lpython import c32, c64, f64 + def test_power_logarithmic(): x: c64 @@ -59,6 +61,17 @@ def test_hyperbolic(): b = tanh(a) +def test_polar(): + x: c64 + eps: f64 + eps = 1e-12 + x = complex(1, -2) + assert f64(abs(f64(phase(x)) - (-1.1071487177940904))) < eps + assert f64(abs(f64(polar(x)[0]) - (2.23606797749979))) < eps + assert abs(abs(rect(2.23606797749979, -1.1071487177940904))-abs(x)) < eps + + test_power_logarithmic() test_trigonometric() test_hyperbolic() +test_polar() diff --git a/integration_tests/test_complex_01.py b/integration_tests/test_complex_01.py index 16d712f1a1..04f88b6895 100644 --- a/integration_tests/test_complex_01.py +++ b/integration_tests/test_complex_01.py @@ -1,4 +1,4 @@ -from ltypes import i32, i64, f32, f64, c32, c64 +from lpython import i32, i64, f32, f64, c32, c64 def test_real_imag(): x: c64 diff --git a/integration_tests/test_complex_02.py b/integration_tests/test_complex_02.py index 0da86a3f33..9a48c6fcb9 100644 --- a/integration_tests/test_complex_02.py +++ b/integration_tests/test_complex_02.py @@ -1,4 +1,4 @@ -from ltypes import f64, c32, c64 +from lpython import f64, c32, c64 def test_complex_abs(): x: c32 diff --git a/integration_tests/test_const_access.py b/integration_tests/test_const_access.py new file mode 100644 index 0000000000..4368e3ed0c --- /dev/null +++ b/integration_tests/test_const_access.py @@ -0,0 +1,9 @@ +from lpython import i32, Const + +CONST_LIST: Const[list[i32]] = [1, 2, 3, 4, 5] +CONST_DICTIONARY: Const[dict[str, i32]] = {"a": 1, "b": 2, "c": 3} + +assert CONST_LIST[0] == 1 +assert CONST_LIST[-2] == 4 + +assert CONST_DICTIONARY["a"] == 1 \ No newline at end of file diff --git a/integration_tests/test_const_dict.py b/integration_tests/test_const_dict.py new file mode 100644 index 0000000000..e06578fc45 --- /dev/null +++ b/integration_tests/test_const_dict.py @@ -0,0 +1,24 @@ +from lpython import i32, f64, Const + +CONST_DICTIONARY_INTEGR: Const[dict[str, i32]] = {"a": 1, "b": 2, "c": 3} + +print(CONST_DICTIONARY_INTEGR.get("a")) +assert CONST_DICTIONARY_INTEGR.get("a") == 1 + +print(CONST_DICTIONARY_INTEGR.keys()) +assert len(CONST_DICTIONARY_INTEGR.keys()) == 3 + +print(CONST_DICTIONARY_INTEGR.values()) +assert len(CONST_DICTIONARY_INTEGR.values()) == 3 + +CONST_DICTIONARY_FLOAT: Const[dict[str, f64]] = {"a": 1.0, "b": 2.0, "c": 3.0} + +print(CONST_DICTIONARY_FLOAT.get("a")) +assert CONST_DICTIONARY_FLOAT.get("a") == 1.0 + +print(CONST_DICTIONARY_FLOAT.keys()) +assert len(CONST_DICTIONARY_FLOAT.keys()) == 3 + +print(CONST_DICTIONARY_FLOAT.values()) +assert len(CONST_DICTIONARY_FLOAT.values()) == 3 + diff --git a/integration_tests/test_const_list.py b/integration_tests/test_const_list.py new file mode 100644 index 0000000000..4f0a568251 --- /dev/null +++ b/integration_tests/test_const_list.py @@ -0,0 +1,19 @@ +from lpython import i32, Const + + +def test_const_list(): + CONST_INTEGER_LIST: Const[list[i32]] = [1, 2, 3, 4, 5, 1] + + print(CONST_INTEGER_LIST.count(1)) + print(CONST_INTEGER_LIST.index(1)) + assert CONST_INTEGER_LIST.count(1) == 2 + assert CONST_INTEGER_LIST.index(1) == 0 + + CONST_STRING_LIST: Const[list[str]] = ["ALPHA", "BETA", "RELEASE"] + print(CONST_STRING_LIST.count("ALPHA")) + print(CONST_STRING_LIST.index("RELEASE")) + assert CONST_STRING_LIST.count("ALPHA") == 1 + assert CONST_STRING_LIST.index("RELEASE") == 2 + + +test_const_list() diff --git a/integration_tests/test_dict_01.py b/integration_tests/test_dict_01.py index 99b3043248..0be09ad2fb 100644 --- a/integration_tests/test_dict_01.py +++ b/integration_tests/test_dict_01.py @@ -1,4 +1,4 @@ -from ltypes import i32, f64 +from lpython import i32, f64 def test_dict(): rollnumber2cpi: dict[i32, f64] = {} @@ -8,12 +8,20 @@ def test_dict(): rollnumber2cpi[0] = 1.1 for i in range(1000, 1000 + size): - rollnumber2cpi[i] = float(i/100.0 + 5.0) + rollnumber2cpi[i] = float(i)/100.0 + 5.0 for i in range(1000 + size - 1, 1001, -1): - assert abs(rollnumber2cpi[i] - i/100.0 - 5.0) <= 1e-12 + assert abs(rollnumber2cpi[i] - f64(i)/100.0 - 5.0) <= 1e-12 assert abs(rollnumber2cpi[0] - 1.1) <= 1e-12 assert len(rollnumber2cpi) == 1001 +def test_issue_1839(): + assert len({1: 2, 1: 3, 4: 5}) == 2 + x: dict[i32, i32] = {} + x = {1: 1, 1: 2, 1: 3} + assert len(x) == 1 + + test_dict() +test_issue_1839() diff --git a/integration_tests/test_dict_02.py b/integration_tests/test_dict_02.py index 2c397ae90c..672fcb1a5f 100644 --- a/integration_tests/test_dict_02.py +++ b/integration_tests/test_dict_02.py @@ -1,4 +1,4 @@ -from ltypes import i32, f64 +from lpython import i32, f64 def test_dict(): rollnumber2cpi: dict[i32, f64] = {0: 1.1} diff --git a/integration_tests/test_dict_03.py b/integration_tests/test_dict_03.py index fa9ecc4691..24583d4ba8 100644 --- a/integration_tests/test_dict_03.py +++ b/integration_tests/test_dict_03.py @@ -1,4 +1,4 @@ -from ltypes import f64, i32, i64 +from lpython import f64, i32, i64 def power2(i: i64, mod: i64) -> i64: if i == i64(0) or i == i64(1): diff --git a/integration_tests/test_dict_04.py b/integration_tests/test_dict_04.py index ae6a4ec919..2665f38c11 100644 --- a/integration_tests/test_dict_04.py +++ b/integration_tests/test_dict_04.py @@ -1,4 +1,4 @@ -from ltypes import i32, i64, f64 +from lpython import i32, i64, f64 from math import pi, sin, cos def test_dict(): diff --git a/integration_tests/test_dict_05.py b/integration_tests/test_dict_05.py index 68d93705e6..df35e97494 100644 --- a/integration_tests/test_dict_05.py +++ b/integration_tests/test_dict_05.py @@ -1,4 +1,4 @@ -from ltypes import i32, f64 +from lpython import i32, f64 def test_dict(): rollnumber2cpi: dict[i32, f64] = {} @@ -7,7 +7,7 @@ def test_dict(): end: i32 = 501 for i in range(start, end): - rollnumber2cpi[i] = float(i/100.0 + 5.0) + rollnumber2cpi[i] = float(i)/100.0 + 5.0 # for i in range(end - 1, start + 1, -1): # assert abs(rollnumber2cpi[i] - i/100.0 - 5.0) <= 1e-12 diff --git a/integration_tests/test_dict_06.py b/integration_tests/test_dict_06.py new file mode 100644 index 0000000000..44ba650bfa --- /dev/null +++ b/integration_tests/test_dict_06.py @@ -0,0 +1,24 @@ +from lpython import f64, i32 + +def fill_rollnumber2cpi(size: i32) -> dict[i32, f64]: + i : i32 + rollnumber2cpi: dict[i32, f64] = {} + + rollnumber2cpi[0] = 1.1 + for i in range(1000, 1000 + size): + rollnumber2cpi[i] = float(i)/100.0 + 5.0 + + return rollnumber2cpi + +def test_dict(): + i: i32 + size: i32 = 200 + rollnumber2cpi: dict[i32, f64] = fill_rollnumber2cpi(size) + + for i in range(1000 + size - 1, 1001, -1): + assert abs(rollnumber2cpi[i] - f64(i)/100.0 - 5.0) <= 1e-12 + + assert abs(rollnumber2cpi[0] - 1.1) <= 1e-12 + assert len(rollnumber2cpi) == 201 + +test_dict() diff --git a/integration_tests/test_dict_07.py b/integration_tests/test_dict_07.py new file mode 100644 index 0000000000..8c6b6e54a1 --- /dev/null +++ b/integration_tests/test_dict_07.py @@ -0,0 +1,21 @@ +from lpython import i32 + + +def fill_smalltocapital() -> dict[str, str]: + return {'a': 'A', 'b': 'B', 'c': 'C', 'd': 'D','e': 'E', + 'f': 'F', 'g': 'G', 'h': 'H', 'i': 'I','j': 'J', + 'k': 'K', 'l': 'L', 'm': 'M', 'n': 'N','o': 'O', + 'p': 'P', 'q': 'Q', 'r': 'R', 's': 'S','t': 'T', + 'u': 'U', 'v': 'V', 'w': 'W', 'x': 'X','y': 'Y', + 'z': 'Z'} + +def test_dict(): + i: i32 + smalltocaps: dict[str, str] + smalltocaps = fill_smalltocapital() + + assert len(smalltocaps) == 26 + for i in range(97, 97 + 26): + assert smalltocaps[chr(i)] == chr(i - 32) + +test_dict() diff --git a/integration_tests/test_dict_08.py b/integration_tests/test_dict_08.py new file mode 100644 index 0000000000..1845849458 --- /dev/null +++ b/integration_tests/test_dict_08.py @@ -0,0 +1,31 @@ +# test case for passing dict as args and return value to a function + +from lpython import i32 + +def get_cubes_from_squares(squares: dict[i32, i32]) -> dict[i32, i32]: + i : i32 + cubes: dict[i32, i32] = {} + for i in range(1, 16): + cubes[i] = squares[i] * i + return cubes + +def assert_dict(squares: dict[i32, i32], cubes: dict[i32, i32]): + i : i32 + for i in range(1, 16): + assert squares[i] == (i * i) + for i in range(1, 16): + assert cubes[i] == (i * i * i) + assert len(squares) == 15 + assert len(cubes) == 15 + +def test_dict(): + squares : dict[i32, i32] + squares = {1:1, 2:4, 3:9, 4:16, 5:25, 6:36, 7:49, + 8:64, 9:81, 10:100, 11:121, 12:144, 13:169, + 14: 196, 15:225} + + cubes : dict[i32, i32] + cubes = get_cubes_from_squares(squares) + assert_dict(squares, cubes) + +test_dict() diff --git a/integration_tests/test_dict_09.py b/integration_tests/test_dict_09.py new file mode 100644 index 0000000000..948288c0d3 --- /dev/null +++ b/integration_tests/test_dict_09.py @@ -0,0 +1,29 @@ +# test case for passing dict as args and return value to a function + +from lpython import f64, i32 + +def fill_rollnumber2cpi(size: i32) -> dict[i32, f64]: + i : i32 + rollnumber2cpi: dict[i32, f64] = {} + + rollnumber2cpi[0] = 1.1 + for i in range(1000, 1000 + size): + rollnumber2cpi[i] = float(i)/100.0 + 5.0 + + return rollnumber2cpi + +def test_assertion(rollnumber2cpi: dict[i32, f64], size: i32): + i: i32 + for i in range(1000 + size - 1, 1001, -1): + assert abs(rollnumber2cpi[i] - f64(i)/100.0 - 5.0) <= 1e-12 + + assert abs(rollnumber2cpi[0] - 1.1) <= 1e-12 + assert len(rollnumber2cpi) == 201 + +def test_dict(): + size: i32 = 200 + rollnumber2cpi: dict[i32, f64] = fill_rollnumber2cpi(size) + + test_assertion(rollnumber2cpi, size) + +test_dict() diff --git a/integration_tests/test_dict_10.py b/integration_tests/test_dict_10.py new file mode 100644 index 0000000000..8adbeab2ac --- /dev/null +++ b/integration_tests/test_dict_10.py @@ -0,0 +1,22 @@ +from lpython import i32 + +# test case for passing dict with key-value as strings as argument to function + +def test_assertion(smalltocaps: dict[str, str]): + i: i32 + assert len(smalltocaps) == 26 + for i in range(97, 97 + 26): + assert smalltocaps[chr(i)] == chr(i - 32) + +def test_dict(): + smalltocaps: dict[str, str] + smalltocaps = {'a': 'A', 'b': 'B', 'c': 'C', 'd': 'D','e': 'E', + 'f': 'F', 'g': 'G', 'h': 'H', 'i': 'I','j': 'J', + 'k': 'K', 'l': 'L', 'm': 'M', 'n': 'N','o': 'O', + 'p': 'P', 'q': 'Q', 'r': 'R', 's': 'S','t': 'T', + 'u': 'U', 'v': 'V', 'w': 'W', 'x': 'X','y': 'Y', + 'z': 'Z'} + + test_assertion(smalltocaps) + +test_dict() diff --git a/integration_tests/test_dict_11.py b/integration_tests/test_dict_11.py new file mode 100644 index 0000000000..57c64fe1b8 --- /dev/null +++ b/integration_tests/test_dict_11.py @@ -0,0 +1,16 @@ +from lpython import i32 + +def test_dict_11(): + num : dict[i32, i32] + num = {11: 22, 33: 44, 55: 66} + assert num.get(7, -1) == -1 + assert num.get(11, -1) == 22 + assert num.get(33, -1) == 44 + assert num.get(55, -1) == 66 + assert num.get(72, -110) == -110 + d : dict[i32, str] + d = {1: "1", 2: "22", 3: "333"} + assert d.get(2, "00") == "22" + assert d.get(21, "nokey") == "nokey" + +test_dict_11() diff --git a/integration_tests/test_dict_12.py b/integration_tests/test_dict_12.py new file mode 100644 index 0000000000..e56ac43f32 --- /dev/null +++ b/integration_tests/test_dict_12.py @@ -0,0 +1,36 @@ +from lpython import i32 + +def main(): + d: dict[str, i32] = { + '2': 2, '3': 3, + '4': 4, '5': 5, '6': 6, '7': 7, + '8': 8, '9': 9, + 'a': 10, 'b': 11, 'c': 12, 'd': 13, + 'A': 100, 'B': 110, 'C': 120, 'D': 130, + 'e': 14, 'f': 15, + 'E': 140, 'F': 150} + + assert (d['2'] == 2) + assert (d['3'] == 3) + assert (d['4'] == 4) + assert (d['5'] == 5) + assert (d['6'] == 6) + assert (d['7'] == 7) + assert (d['8'] == 8) + assert (d['9'] == 9) + + assert (d['a'] == 10) + assert (d['b'] == 11) + assert (d['c'] == 12) + assert (d['d'] == 13) + assert (d['A'] == 100) + assert (d['B'] == 110) + assert (d['C'] == 120) + assert (d['D'] == 130) + + assert (d['e'] == 14) + assert (d['f'] == 15) + assert (d['E'] == 140) + assert (d['F'] == 150) + +main() diff --git a/integration_tests/test_dict_13.py b/integration_tests/test_dict_13.py new file mode 100644 index 0000000000..670a9eb60c --- /dev/null +++ b/integration_tests/test_dict_13.py @@ -0,0 +1,43 @@ +from lpython import i32 + +I4C: dict[str, i32] = { + '0': 0, '1': 1, '2': 2, '3': 3, + '4': 4, '5': 5, '6': 6, '7': 7, + '8': 8, '9': 9, + 'a': 10, 'b': 11, 'c': 12, 'd': 13, + 'A': 10, 'B': 11, 'C': 12, 'D': 13, + 'e': 14, 'f': 15, + 'E': 14, 'F': 15} + + +def cnvi(s : str, base : i32=10) -> i32: + """Assume input has been through 'match_integer'.""" + assert base == 10 or base == 8 or base == 16 or base == 2 + result : i32 = 0 + c : str + pow_: i32 = base ** (len(s) - 1) + for c in s: + incr : i32 = pow_ * I4C[c] + result += incr + pow_ = (pow_ // base) + return result + + +if __name__ == '__main__': + print(cnvi('0b0', base=2)) + assert cnvi('0b0', base=2) == 22 + + print(cnvi('0b1', base=2)) + assert cnvi('0b1', base=2) == 23 + + print(cnvi('0b10', base=2)) + assert cnvi('0b10', base=2) == 46 + + print(cnvi('0b11', base=2)) + assert cnvi('0b11', base=2) == 47 + + print(cnvi('0b11110100111', base=2)) + assert cnvi('0b11110100111', base=2) == 24487 + + print(cnvi('0b7a7', base=16)) + assert cnvi('0b7a7', base=16) == 47015 diff --git a/integration_tests/test_dict_14.py b/integration_tests/test_dict_14.py new file mode 100644 index 0000000000..4fe91c687f --- /dev/null +++ b/integration_tests/test_dict_14.py @@ -0,0 +1,65 @@ +from lpython import i32 + +def test_dict(): + d_i32: dict[i32, i32] = {5: 1, 5: 2} + d_str: dict[str, i32] = {'a': 1, 'a': 2} + l_str_1: list[str] = [] + l_str_2: list[str] = [] + l_i32_1: list[i32] = [] + l_i32_2: list[i32] = [] + i: i32 + s: str + + assert len(d_i32) == 1 + d_i32.pop(5) + assert len(d_i32) == 0 + + assert len(d_str) == 1 + d_str.pop('a') + assert len(d_str) == 0 + + d_str = {'a': 2, 'a': 2, 'b': 2, 'c': 3, 'a': 5} + assert len(d_str) == 3 + d_str.pop('a') + assert len(d_str) == 2 + d_str.pop('b') + assert len(d_str) == 1 + + d_str['a'] = 20 + assert len(d_str) == 2 + d_str.pop('c') + assert len(d_str) == 1 + + l_str_1 = d_str.keys() + for s in l_str_1: + l_str_2.append(s) + assert l_str_2 == ['a'] + l_i32_1 = d_str.values() + for i in l_i32_1: + l_i32_2.append(i) + assert l_i32_2 == [20] + + d_i32 = {5: 2, 5: 2, 6: 2, 7: 3, 5: 5} + assert len(d_i32) == 3 + d_i32.pop(5) + assert len(d_i32) == 2 + d_i32.pop(6) + assert len(d_i32) == 1 + + d_i32[6] = 30 + assert len(d_i32) == 2 + d_i32.pop(7) + assert len(d_i32) == 1 + + l_i32_1 = d_i32.keys() + l_i32_2.clear() + for i in l_i32_1: + l_i32_2.append(i) + assert l_i32_2 == [6] + l_i32_1 = d_i32.values() + l_i32_2.clear() + for i in l_i32_1: + l_i32_2.append(i) + assert l_i32_2 == [30] + +test_dict() diff --git a/integration_tests/test_dict_bool.py b/integration_tests/test_dict_bool.py new file mode 100644 index 0000000000..c1e4e9cca9 --- /dev/null +++ b/integration_tests/test_dict_bool.py @@ -0,0 +1,47 @@ +from lpython import i32, f64 + +def test_dict_bool(): + d_int: dict[bool, i32] = {} + d_float: dict[bool, f64] = {} + d_str: dict[bool, str] = {} + i: i32 + j: f64 + s: str = "" + l_str: list[str] = ["a", "b", "c", "d"] + + for i in range(10): + d_int[True] = i + assert d_int[True] == i + + for i in range(10, 20): + d_int[True] = i + d_int[False] = i + 1 + assert d_int[True] == d_int[False] - 1 + assert d_int[True] == i + + d_int[True] = 0 + d_int[False] = d_int[True] + + for i in range(10, 99): + d_int[i%2 == 0] = d_int[i%2 == 0] + 1 + assert d_int[True] == d_int[False] + 1 + assert d_int[True] == 45 + + j = 0.0 + while j < 1.0: + d_float[False] = j + 1.0 + d_float[True] = d_float[False] * d_float[False] + assert d_float[True] == (j + 1.0) * (j + 1.0) + assert d_float[False] == j + 1.0 + j = j + 0.1 + + d_str[False] = s + + for i in range(len(l_str)): + d_str[True] = d_str[False] + s += l_str[i] + d_str[False] = s + assert d_str[True] + l_str[i] == d_str[False] + assert d_str[False] == s + +test_dict_bool() diff --git a/integration_tests/test_dict_clear.py b/integration_tests/test_dict_clear.py new file mode 100644 index 0000000000..eccfea0aa6 --- /dev/null +++ b/integration_tests/test_dict_clear.py @@ -0,0 +1,18 @@ +def test_clear(): + a: dict[i32, i32] = {1:1, 2:2} + + a.clear() + a[3] = 3 + + assert len(a) == 1 + assert 3 in a + + b: dict[str, str] = {'a':'a', 'b':'b'} + + b.clear() + b['c'] = 'c' + + assert len(b) == 1 + assert 'c' in b + +test_clear() diff --git a/integration_tests/test_dict_increment.py b/integration_tests/test_dict_increment.py new file mode 100644 index 0000000000..b342e26bcf --- /dev/null +++ b/integration_tests/test_dict_increment.py @@ -0,0 +1,66 @@ +from lpython import i32, f64 + +def test_dict_increment(): + d_int_int: dict[i32, i32] + d_int_float: dict[i32, f64] + d_bool_float: dict[bool, f64] + d_str_float: dict[str, f64] + d_int_str: dict[i32, str] + i1: i32 + i2: i32 + j1: f64 + j2: f64 + s1: str + + d_int_int = {0: 1} + d_int_int[0] += 1000 + assert d_int_int[0] == 1001 + + i2 = 1 + d_int_int = {1: i2} + for i1 in range(10): + d_int_int[1] += i1 + i2 += i1 + assert d_int_int[1] == i2 + + i2 = 10 + d_int_int = {0: 0, 1: 0} + for i1 in range(i2): + d_int_int[i1 % 2] += 1 + assert d_int_int[0] == d_int_int[1] + assert d_int_int[0] == i2 // 2 + + j1 = 2.0 + d_int_float = {2: j1} + while j1 < 4.0: + d_int_float[2] += 0.1 + j1 += 0.1 + assert d_int_float[2] == j1 + + j1 = 0.0 + j2 = 0.0 + d_bool_float = {True: 0.0, False: 0.0} + while j1 < 4.0: + d_bool_float[j1 < 2.0] += 0.1 + if j1 < 2.0: + j2 += 0.1 + j1 += 0.1 + assert d_bool_float[j1 < 2.0] == d_bool_float[j1 > 2.0] + assert d_bool_float[True] == j2 + + j1 = 2.0 + d_str_float = {'key': j1} + s1 = "ke" + while j1 < 4.0: + d_str_float[s1 + 'y'] += 0.1 + j1 += 0.1 + assert d_str_float['key'] == j1 + + s1 = "0" + d_int_str = {-1: s1} + for i1 in range(10): + d_int_str[-1] += str(i1) + s1 += str(i1) + assert d_int_str[-1] == s1 + +test_dict_increment() diff --git a/integration_tests/test_dict_keys_values.py b/integration_tests/test_dict_keys_values.py new file mode 100644 index 0000000000..2bcc20c084 --- /dev/null +++ b/integration_tests/test_dict_keys_values.py @@ -0,0 +1,99 @@ +from lpython import i32, f64 + +def test_dict_keys_values(): + d1: dict[i32, i32] = {} + k1: list[i32] + k1_copy: list[i32] = [] + v1: list[i32] + v1_copy: list[i32] = [] + i: i32 + j: i32 + s: str + key_count: i32 + + for i in range(105, 115): + d1[i] = i + 1 + k1 = d1.keys() + for i in k1: + k1_copy.append(i) + v1 = d1.values() + for i in v1: + v1_copy.append(i) + assert len(k1) == 10 + for i in range(105, 115): + key_count = 0 + for j in range(len(k1)): + if k1_copy[j] == i: + key_count += 1 + assert v1_copy[j] == d1[i] + assert key_count == 1 + + d2: dict[str, str] = {} + k2: list[str] + k2_copy: list[str] = [] + v2: list[str] + v2_copy: list[str] = [] + + for i in range(105, 115): + d2[str(i)] = str(i + 1) + k2 = d2.keys() + for s in k2: + k2_copy.append(s) + v2 = d2.values() + for s in v2: + v2_copy.append(s) + assert len(k2) == 10 + for i in range(105, 115): + key_count = 0 + for j in range(len(k2)): + if k2_copy[j] == str(i): + key_count += 1 + assert v2_copy[j] == d2[str(i)] + assert key_count == 1 + + + # dict.keys on dict constant + print({1: "a"}.keys()) + assert len({1: "a"}.keys()) == 1 + + print({"a": 1, "b": 2, "c": 3}.keys()) + assert len({"a": 1, "b": 2, "c": 3}.keys()) == 3 + + print({1: [1, 2, 3], 2: [4, 5, 6], 3: [7, 8, 9]}.keys()) + assert len({1: [1, 2, 3], 2: [4, 5, 6], 3: [7, 8, 9]}.keys()) == 3 + + print({(1, 2): "a", (3, 4): "b", (5, 6): "c"}.keys()) + assert len({(1, 2): "a", (3, 4): "b", (5, 6): "c"}.keys()) == 3 + + k_1: list[str] = {"list1": [1, 2, 3], "list2": [4, 5, 6], "list3": [7, 8, 9]}.keys() + print(k_1) + assert len(k_1) == 3 + + k_2: list[tuple[i32, i32]] = {(1, 2): "a", (3, 4): "b", (5, 6): "c"}.keys() + print(k_2) + assert len(k_2) == 3 + + + # dict.values on dict constant + print({1: "a"}.values()) + assert len({1: "a"}.values()) == 1 + + print({"a": 1, "b": 2, "c": 3}.values()) + assert len({"a": 1, "b": 2, "c": 3}.values()) == 3 + + print({1: [1, 2, 3], 2: [4, 5, 6], 3: [7, 8, 9]}.values()) + assert len({1: [1, 2, 3], 2: [4, 5, 6], 3: [7, 8, 9]}.values()) == 3 + + print({(1, 2): "a", (3, 4): "b", (5, 6): "c"}.values()) + assert len({(1, 2): "a", (3, 4): "b", (5, 6): "c"}.values()) == 3 + + v_1: list[list[i32]] = {"list1": [1, 2, 3], "list2": [4, 5, 6], "list3": [7, 8, 9]}.values() + print(v_1) + assert len(v_1) == 3 + + v_2: list[str] = {(1, 2): "a", (3, 4): "b", (5, 6): "c"}.values() + print(v_2) + assert len(v_2) == 3 + + +test_dict_keys_values() diff --git a/integration_tests/test_dict_nested1.py b/integration_tests/test_dict_nested1.py new file mode 100644 index 0000000000..14de899610 --- /dev/null +++ b/integration_tests/test_dict_nested1.py @@ -0,0 +1,9 @@ +from lpython import i32 + +def test_nested_dict(): + d: dict[i32, dict[i32, i32]] = {1001: {2002: 3003}, 1002: {101: 2}} + d[1001] = d[1002] + d[1001][100] = 4005 + assert d[1001][100] == 4005 + +test_nested_dict() diff --git a/integration_tests/test_for_loop.py b/integration_tests/test_for_loop.py index c94161f080..3f66e992c4 100644 --- a/integration_tests/test_for_loop.py +++ b/integration_tests/test_for_loop.py @@ -1,3 +1,5 @@ +from lpython import i32 + def test_issue_1153(): start: list[i32] = [-10, 0, 10] stop: list[i32] = [20, 0, -20] diff --git a/integration_tests/test_generics_01.py b/integration_tests/test_generics_01.py index e6074541be..871f8b48ac 100644 --- a/integration_tests/test_generics_01.py +++ b/integration_tests/test_generics_01.py @@ -1,5 +1,5 @@ from overload_testing import foo, test -from ltypes import overload, i32, i64 +from lpython import overload, i32, i64 import overload_testing2 diff --git a/integration_tests/test_global_decl.py b/integration_tests/test_global_decl.py index beb67fc441..d256f37d15 100644 --- a/integration_tests/test_global_decl.py +++ b/integration_tests/test_global_decl.py @@ -1,9 +1,9 @@ -from ltypes import i32 +from lpython import i32, Const from numpy import empty, int32 # issue-1368 -SIZE: i32 = i32(3) +SIZE: Const[i32] = i32(3) def main() -> None: xs: i32[SIZE] = empty(SIZE, dtype=int32) diff --git a/integration_tests/test_global_set.py b/integration_tests/test_global_set.py new file mode 100644 index 0000000000..487f12d108 --- /dev/null +++ b/integration_tests/test_global_set.py @@ -0,0 +1,9 @@ +from lpython import i32 + +s1: set[str] = {"a", "b", "c", "a"} +s2: set[i32] = {1, 2, 3, 1} +s3: set[tuple[i32, i32]] = {(1, 2), (2, 3), (4, 5)} + +assert len(s1) == 3 +assert len(s2) == 3 +assert len(s3) == 3 diff --git a/integration_tests/test_gruntz.py b/integration_tests/test_gruntz.py new file mode 100644 index 0000000000..70b5a307ee --- /dev/null +++ b/integration_tests/test_gruntz.py @@ -0,0 +1,80 @@ +from lpython import S +from sympy import Symbol, log, E, Pow, exp + +def mmrv(e: S, x: S) -> list[S]: + empty_list : list[S] = [] + if not e.has(x): + return empty_list + elif e == x: + list1: list[S] = [x] + return list1 + elif e.func == log: + arg0: S = e.args[0] + list2: list[S] = mmrv(arg0, x) + return list2 + elif e.func == Pow: + base: S = e.args[0] + exponent: S = e.args[1] + one: S = S(1) + if base != E: + newe_exponent: S = S(1) + newe: S = e + while newe.func == Pow: + newe_base: S = newe.args[0] + newe_args1: S = newe.args[1] + newe_exponent = newe_exponent * newe_args1 + newe = newe_base + if newe_base == one: + return empty_list + if not newe_exponent.has(x): + list3: list[S] = mmrv(newe_base, x) + return list3 + else: + # TODO as noted in #2526 + pass + else: + if exponent.func == log: + list4: list[S] = mmrv(exponent.args[0], x) + return list4 + # TODO + pass + else: + raise + +def test_mrv(): + # Case 1 + x: S = Symbol("x") + y: S = Symbol("y") + ans1: list[S] = mmrv(y, x) + print(ans1) + assert len(ans1) == 0 + + # Case 2 + ans2: list[S] = mmrv(x, x) + ele1: S = ans2[0] + print(ele1) + assert ele1 == x + assert len(ans2) == 1 + + # Case 3 + ans3: list[S] = mmrv(log(x), x) + ele2: S = ans3[0] + print(ele2) + assert ele2 == x + assert len(ans3) == 1 + + # Case 4 + ans4: list[S] = mmrv(x**S(2), x) + ele3: S = ans4[0] + print(ele3) + assert ele3 == x + assert len(ans4) == 1 + + # Case 5 + ans5: list[S] = mmrv(exp(log(x)), x) + ele4: S = ans5[0] + print(ele4) + assert ele4 == x + assert len(ans5) == 1 + +test_mrv() \ No newline at end of file diff --git a/integration_tests/test_ifexp.py b/integration_tests/test_ifexp_01.py similarity index 71% rename from integration_tests/test_ifexp.py rename to integration_tests/test_ifexp_01.py index 3b10e39326..fb2c0e06b3 100644 --- a/integration_tests/test_ifexp.py +++ b/integration_tests/test_ifexp_01.py @@ -1,11 +1,14 @@ -from ltypes import i32, f32 +from lpython import i32, f32 def f(): i: i32 i = 1 if True else 0 + print (i) assert i == 1 + j: f32 j = f32(1.0 if 1.0 <= 0.0 else 0.0) + print(j) assert j == f32(0.0) f() diff --git a/integration_tests/test_ifexp_02.py b/integration_tests/test_ifexp_02.py new file mode 100644 index 0000000000..5a41259476 --- /dev/null +++ b/integration_tests/test_ifexp_02.py @@ -0,0 +1,17 @@ +from lpython import i32 + +def g() -> i32: + return 10 + +def f(): + i: i32 + j: i32 + k: i32 + i = 5 + j = 6 + k = g() if i > j else g() - 1 + + print(k) + assert k == 9 + +f() diff --git a/integration_tests/test_ifexp_03.py b/integration_tests/test_ifexp_03.py new file mode 100644 index 0000000000..21c0424ac9 --- /dev/null +++ b/integration_tests/test_ifexp_03.py @@ -0,0 +1,11 @@ +from lpython import i32 + +def fib(n: i32) -> i32: + return fib(n - 1) + fib(n - 2) if n >= 3 else 1 + +def main0(): + res: i32 = fib(30) + print(res) + assert res == 832040 + +main0() diff --git a/integration_tests/test_import/import_module_01/test_import_4.py b/integration_tests/test_import/import_module_01/test_import_4.py index 7f0c7ac5c1..f85a664a12 100644 --- a/integration_tests/test_import/import_module_01/test_import_4.py +++ b/integration_tests/test_import/import_module_01/test_import_4.py @@ -1,4 +1,4 @@ -from ltypes import i32, f64, Const +from lpython import i32, f64, Const e: Const[f64] = 2.71828182845904523536 diff --git a/integration_tests/test_import/import_module_02/test_import_3.py b/integration_tests/test_import/import_module_02/test_import_3.py index 28bfbb7f0f..015ac2ae3f 100644 --- a/integration_tests/test_import/import_module_02/test_import_3.py +++ b/integration_tests/test_import/import_module_02/test_import_3.py @@ -1,4 +1,4 @@ -from ltypes import i32, f64, Const +from lpython import i32, f64, Const μ: Const[f64] = 1.45136923488338105028 diff --git a/integration_tests/test_import/sys.py b/integration_tests/test_import/sys.py new file mode 100644 index 0000000000..ac905eb29d --- /dev/null +++ b/integration_tests/test_import/sys.py @@ -0,0 +1,5 @@ +from lpython import i32 + +def hi_from_user_sys() -> i32: + print("hi from user sys!") + return -5 diff --git a/integration_tests/test_import_05.py b/integration_tests/test_import_05.py new file mode 100644 index 0000000000..8ee6c54c7a --- /dev/null +++ b/integration_tests/test_import_05.py @@ -0,0 +1,3 @@ +from test_import.sys import hi_from_user_sys + +assert hi_from_user_sys() == -5 diff --git a/integration_tests/test_import_06.py b/integration_tests/test_import_06.py new file mode 100644 index 0000000000..f46b88c50a --- /dev/null +++ b/integration_tests/test_import_06.py @@ -0,0 +1,8 @@ +from test_import_06_mod1 import StringIO +from test_import_06_mod2 import stringio_test + +if __name__ == '__main__': + integer_asr : str = '(Integer 4 [])' + fd : StringIO = StringIO(integer_asr) + stringio_test(fd, integer_asr) + print("Ok") diff --git a/integration_tests/test_import_06_mod1.py b/integration_tests/test_import_06_mod1.py new file mode 100644 index 0000000000..37e020cb43 --- /dev/null +++ b/integration_tests/test_import_06_mod1.py @@ -0,0 +1,5 @@ +from lpython import dataclass + +@dataclass +class StringIO: + a: str diff --git a/integration_tests/test_import_06_mod2.py b/integration_tests/test_import_06_mod2.py new file mode 100644 index 0000000000..da37cfa172 --- /dev/null +++ b/integration_tests/test_import_06_mod2.py @@ -0,0 +1,4 @@ +from test_import_06_mod1 import StringIO + +def stringio_test(fd: StringIO, integer_asr: str): + assert fd.a == integer_asr diff --git a/integration_tests/test_import_07.py b/integration_tests/test_import_07.py new file mode 100644 index 0000000000..b799410cbf --- /dev/null +++ b/integration_tests/test_import_07.py @@ -0,0 +1,8 @@ +# test issue 2153 +from test_import_07_module import f as fa + +def main0(): + assert fa(3) == 6 + assert fa(10) == 20 + +main0() diff --git a/integration_tests/test_import_07_module.py b/integration_tests/test_import_07_module.py new file mode 100644 index 0000000000..a0925aa5ae --- /dev/null +++ b/integration_tests/test_import_07_module.py @@ -0,0 +1,4 @@ +from lpython import i32 + +def f(x: i32) -> i32: + return 2 * x diff --git a/integration_tests/test_import_08.py b/integration_tests/test_import_08.py new file mode 100644 index 0000000000..80b1bffa0f --- /dev/null +++ b/integration_tests/test_import_08.py @@ -0,0 +1,3 @@ +import string + +import test_import_08_module diff --git a/integration_tests/test_import_08_module.py b/integration_tests/test_import_08_module.py new file mode 100644 index 0000000000..f92430e846 --- /dev/null +++ b/integration_tests/test_import_08_module.py @@ -0,0 +1,6 @@ +from lpython import i32 + +a: i32 = 10 +b: i32 = a + 10 + +print("Inside import") diff --git a/integration_tests/test_intrinsic_function_mixed_print.py b/integration_tests/test_intrinsic_function_mixed_print.py new file mode 100644 index 0000000000..8c5ee2f32d --- /dev/null +++ b/integration_tests/test_intrinsic_function_mixed_print.py @@ -0,0 +1,25 @@ +from lpython import i32 + +def test_intrinsic_function_mixed_print(): + # list and list methods + my_list: list[i32] = [1, 2, 3, 4, 5] + print("Popped element:", my_list.pop()) + assert my_list == [1, 2, 3, 4] + + print("1 is located at:", my_list.index(1)) + assert my_list.index(1) == 0 + + my_list.append(2) + print("2 is present", my_list.count(2), "times") + assert my_list.count(2) == 2 + + print(my_list.pop(), my_list) + assert my_list == [1, 2, 3, 4] + + # dict and dict methods + my_dict: dict[str, i32] = {"first": 1, "second": 2, "third": 3} + print("Keys:", my_dict.keys()) + print("Value of 'third':", my_dict.pop("third")) + assert len(my_dict.keys()) == 2 + +test_intrinsic_function_mixed_print() \ No newline at end of file diff --git a/integration_tests/test_issue_518.py b/integration_tests/test_issue_518.py index cb1a4eacb9..755719a27b 100644 --- a/integration_tests/test_issue_518.py +++ b/integration_tests/test_issue_518.py @@ -1,4 +1,4 @@ -from ltypes import i64 +from lpython import i64 def fib(n: i64) -> i64: if n < i64(2): diff --git a/integration_tests/test_list_01.py b/integration_tests/test_list_01.py index a9042aa5e0..3a8789c0e1 100644 --- a/integration_tests/test_list_01.py +++ b/integration_tests/test_list_01.py @@ -1,4 +1,4 @@ -from ltypes import f64, i32 +from lpython import f64, i32 def fill_list_i32(size: i32) -> list[i32]: aarg: list[i32] = [0, 1, 2, 3, 4] @@ -63,9 +63,21 @@ def test_list_03(): for i in range(size): assert x[i] == x[((i-len(x)) + size) % size] + +def test_issue_1681(): + a: list[i32] = [2, 3, 4] + a = [1, 2, 3] + assert len(a) == 3 and a[0] == 1 and a[1] == 2 and a[2] == 3 + a = [] + assert len(a) == 0 + a = [1] + assert len(a) == 1 and a[0] == 1 + + def tests(): test_list_01() test_list_02() test_list_03() + test_issue_1681() tests() diff --git a/integration_tests/test_list_02.py b/integration_tests/test_list_02.py index 7879ffc9d0..f96d1f23d0 100644 --- a/integration_tests/test_list_02.py +++ b/integration_tests/test_list_02.py @@ -1,4 +1,4 @@ -from ltypes import i32 +from lpython import i32 def fill_list_str(size: i32) -> list[str]: a: list[str] = ["0_str", "1_str"] diff --git a/integration_tests/test_list_03.py b/integration_tests/test_list_03.py index ee7c33b86a..1cb6953e7d 100644 --- a/integration_tests/test_list_03.py +++ b/integration_tests/test_list_03.py @@ -1,4 +1,4 @@ -from ltypes import i32 +from lpython import i32, InOut def test_list_01(n: i32) -> i32: a: list[i32] = [] @@ -10,7 +10,7 @@ def test_list_01(n: i32) -> i32: sum += a[i] return sum -def test_list_insert_02(x: list[i32], n: i32) -> list[i32]: +def test_list_insert_02(x: InOut[list[i32]], n: i32) -> list[i32]: i: i32 imod: i32 for i in range(n): diff --git a/integration_tests/test_list_04.py b/integration_tests/test_list_04.py index 687745bcf1..7c09061768 100644 --- a/integration_tests/test_list_04.py +++ b/integration_tests/test_list_04.py @@ -1,5 +1,5 @@ from math import sqrt -from ltypes import i32, f64 +from lpython import i32, f64 def test_list_01(): x: list[i32] = [] diff --git a/integration_tests/test_list_05.py b/integration_tests/test_list_05.py index 088048968e..7708b95dec 100644 --- a/integration_tests/test_list_05.py +++ b/integration_tests/test_list_05.py @@ -1,4 +1,4 @@ -from ltypes import i32, f64 +from lpython import i32, f64, InOut def check_list_of_tuples(l: list[tuple[i32, f64, str]], sign: i32): size: i32 = len(l) @@ -29,7 +29,7 @@ def fill_list_of_tuples(size: i32) -> list[tuple[i32, f64, str]]: return l1 -def insert_tuples_into_list(l: list[tuple[i32, f64, str]], size: i32) -> list[tuple[i32, f64, str]]: +def insert_tuples_into_list(l: InOut[list[tuple[i32, f64, str]]], size: i32) -> list[tuple[i32, f64, str]]: i: i32 string: str t: tuple[i32, f64, str] diff --git a/integration_tests/test_list_06.py b/integration_tests/test_list_06.py index dcede48d7e..0924b87691 100644 --- a/integration_tests/test_list_06.py +++ b/integration_tests/test_list_06.py @@ -1,4 +1,4 @@ -from ltypes import i32, f64 +from lpython import i32, f64 from copy import deepcopy def check_mat_and_vec(mat: list[list[f64]], vec: list[f64]): @@ -15,8 +15,8 @@ def check_mat_and_vec(mat: list[list[f64]], vec: list[f64]): assert vec[i] == 2.0 * float(i) def test_list_of_lists(): - tensors: list[list[list[list[f64]]]] = [] - tensor: list[list[list[f64]]] = [] + arrays: list[list[list[list[f64]]]] = [] + array: list[list[list[f64]]] = [] mat: list[list[f64]] = [] vec: list[f64] = [] rows: i32 = 10 @@ -38,7 +38,7 @@ def test_list_of_lists(): check_mat_and_vec(mat, vec) for k in range(rows): - tensor.append(deepcopy(mat)) + array.append(deepcopy(mat)) for i in range(rows): for j in range(cols): mat[i][j] += float(1) @@ -46,19 +46,19 @@ def test_list_of_lists(): for k in range(rows): for i in range(rows): for j in range(cols): - assert mat[i][j] - tensor[k][i][j] == f64(rows - k) + assert mat[i][j] - array[k][i][j] == f64(rows - k) for l in range(2 * rows): - tensors.append(deepcopy(tensor)) + arrays.append(deepcopy(array)) for i in range(rows): for j in range(rows): for k in range(cols): - tensor[i][j][k] += float(1) + array[i][j][k] += float(1) for l in range(2 * rows): for i in range(rows): for j in range(rows): for k in range(cols): - assert tensor[i][j][k] - tensors[l][i][j][k] == f64(2 * rows - l) + assert array[i][j][k] - arrays[l][i][j][k] == f64(2 * rows - l) test_list_of_lists() diff --git a/integration_tests/test_list_07.py b/integration_tests/test_list_07.py index bd33a079eb..904ee70b38 100644 --- a/integration_tests/test_list_07.py +++ b/integration_tests/test_list_07.py @@ -1,17 +1,17 @@ -from ltypes import c64, i32 +from lpython import c64, i32 from copy import deepcopy -def generate_complex_tensors(mat: list[list[c64]], vec: list[c64]) -> list[tuple[list[list[c64]], list[c64]]]: - tensor: tuple[list[list[c64]], list[c64]] - tensors: list[tuple[list[list[c64]], list[c64]]] = [] +def generate_complex_arrays(mat: list[list[c64]], vec: list[c64]) -> list[tuple[list[list[c64]], list[c64]]]: + array: tuple[list[list[c64]], list[c64]] + arrays: list[tuple[list[list[c64]], list[c64]]] = [] rows: i32 = len(mat) cols: i32 = len(vec) i: i32; j: i32; k: i32 - tensor = (deepcopy(mat), deepcopy(vec)) + array = (deepcopy(mat), deepcopy(vec)) for k in range(2 * rows): - tensors.append(deepcopy(tensor)) + arrays.append(deepcopy(array)) for i in range(rows): for j in range(cols): mat[i][j] += complex(1.0, 2.0) @@ -19,15 +19,15 @@ def generate_complex_tensors(mat: list[list[c64]], vec: list[c64]) -> list[tuple for i in range(cols): vec[i] += complex(1.0, 2.0) - tensor = (deepcopy(mat), deepcopy(vec)) + array = (deepcopy(mat), deepcopy(vec)) - return tensors + return arrays def test_tuple_with_lists(): mat: list[list[c64]] = [] vec: list[c64] = [] - tensor: tuple[list[list[c64]], list[c64]] - tensors: list[tuple[list[list[c64]], list[c64]]] = [] + array: tuple[list[list[c64]], list[c64]] + arrays: list[tuple[list[list[c64]], list[c64]]] = [] i: i32 j: i32 k: i32 @@ -48,7 +48,7 @@ def test_tuple_with_lists(): for j in range(cols): assert mat[i][j] - vec[j] == c64(i - j) - tensor = (deepcopy(mat), deepcopy(vec)) + array = (deepcopy(mat), deepcopy(vec)) for i in range(rows): for j in range(cols): @@ -59,20 +59,20 @@ def test_tuple_with_lists(): for i in range(rows): for j in range(cols): - assert tensor[0][i][j] - mat[i][j] == -complex(0, 3.0) + assert array[0][i][j] - mat[i][j] == -complex(0, 3.0) for i in range(cols): - assert tensor[1][i] - vec[i] == -complex(0, 2.0) + assert array[1][i] - vec[i] == -complex(0, 2.0) - tensors = generate_complex_tensors(mat, vec) + arrays = generate_complex_arrays(mat, vec) for k in range(2 * rows): for i in range(rows): for j in range(cols): - assert tensors[k][0][i][j] - mat[i][j] == -c64(2 * rows - k) * complex(1.0, 2.0) + assert arrays[k][0][i][j] - mat[i][j] == -c64(2 * rows - k) * complex(1.0, 2.0) for k in range(2 * rows): for i in range(cols): - assert tensors[k][1][i] - vec[i] == -c64(2 * rows - k) * complex(1.0, 2.0) + assert arrays[k][1][i] - vec[i] == -c64(2 * rows - k) * complex(1.0, 2.0) test_tuple_with_lists() diff --git a/integration_tests/test_list_08.py b/integration_tests/test_list_08.py index 21b2eb7758..f5a2cd33f3 100644 --- a/integration_tests/test_list_08.py +++ b/integration_tests/test_list_08.py @@ -1,7 +1,7 @@ -from ltypes import i32, f64 +from lpython import i32, f64, InOut from copy import deepcopy -def sort(l: list[i32]) -> list[i32]: +def sort(l: InOut[list[i32]]) -> list[i32]: i: i32; j: i32 for i in range(len(l)): diff --git a/integration_tests/test_list_09.py b/integration_tests/test_list_09.py index 2aa4a369b3..b7ca405765 100644 --- a/integration_tests/test_list_09.py +++ b/integration_tests/test_list_09.py @@ -1,4 +1,5 @@ -from ltypes import i32 +from lpython import i32 + def test_list_concat(): x: list[i32] = [] @@ -10,39 +11,41 @@ def test_list_concat(): x = [1, 2, 3] z = x + y for i in range(1, 4): - assert z[i-1] == i + assert z[i - 1] == i x.clear() y = [6, 7, 8] z = x + y for i in range(1, 4): - assert z[i-1] == i + 5 + assert z[i - 1] == i + 5 x = [1, 2, 3, 4, 5] z = x + y for i in range(1, 9): - assert z[i-1] == i + assert z[i - 1] == i - x.clear(); y.clear() + x.clear() + y.clear() for i in range(9, 51): x.append(i) for i in range(51, 101): y.append(i) z = z + x + y - x[0] = 0; x[1] = 0 + x[0] = 0 + x[1] = 0 y.clear() for i in range(1, 100): - assert z[i-1] == i - + assert z[i - 1] == i + c: list[str] d: list[str] - c = ['a', 'b'] - d = ['c', 'd', 'e'] + c = ["a", "b"] + d = ["c", "d", "e"] c += d assert len(c) == 5 for i in range(5): - assert ord(c[i]) - ord('a') == i + assert ord(c[i]) - ord("a") == i test_list_concat() diff --git a/integration_tests/test_list_10.py b/integration_tests/test_list_10.py index c938e56cbb..5216054ddf 100644 --- a/integration_tests/test_list_10.py +++ b/integration_tests/test_list_10.py @@ -1,4 +1,4 @@ -from ltypes import i32 +from lpython import i32 def test_list_section(): x: list[i32] = [] diff --git a/integration_tests/test_list_11.py b/integration_tests/test_list_11.py new file mode 100644 index 0000000000..2cb899ebf2 --- /dev/null +++ b/integration_tests/test_list_11.py @@ -0,0 +1,46 @@ +from lpython import i32 + +l: list[i32] = [1, 2] + +def add_item(i: i32) -> list[i32]: + l.append(i) + return l + + +def return_empty_list_of_tuples() -> list[i32]: + return [] + + +def test_issue_1882(): + i: i32 + x: list[i32] + x = [2, 3, 4] + for i in [1, 2, 3]: + assert i + 1 == x[i - 1] + +def test_iterate_over_string(): + s: str + i: i32 = 0 + temp: str = "abcd" + for s in "abcd": + assert s == temp[i] + i+=1 + +def test_issue_2639(): + print(add_item(3)) + + assert len(l) == 3 + assert l[0] == 1 + assert l[1] == 2 + assert l[2] == 3 + +def main0(): + x: list[i32] = return_empty_list_of_tuples() + print(len(x)) + + assert len(x) == 0 + test_issue_1882() + test_iterate_over_string() + test_issue_2639() + +main0() diff --git a/integration_tests/test_list_compare.py b/integration_tests/test_list_compare.py new file mode 100644 index 0000000000..24fcc485d5 --- /dev/null +++ b/integration_tests/test_list_compare.py @@ -0,0 +1,53 @@ +from lpython import i32, f64 + +def test_list_compare(): + l1: list[i32] = [1, 2, 3] + l2: list[i32] = [1, 2, 3, 4] + l3: list[tuple[i32, f64, str]] = [(1, 2.0, 'a'), (3, 4.0, 'b')] + l4: list[tuple[i32, f64, str]] = [(1, 3.0, 'a')] + l5: list[list[str]] = [[''], ['']] + l6: list[str] = [] + l7: list[str] = [] + t1: tuple[i32, i32] + t2: tuple[i32, i32] + i: i32 + + assert l1 < l2 and l1 <= l2 + assert not l1 > l2 and not l1 >= l2 + i = l2.pop() + i = l2.pop() + assert l2 < l1 and l1 > l2 and l1 >= l2 + assert not (l1 < l2) + + l1 = [3, 4, 5] + l2 = [1, 6, 7] + assert l1 > l2 and l1 >= l2 + assert not l1 < l2 and not l1 <= l2 + + l1 = l2 + assert l1 == l2 and l1 <= l2 and l1 >= l2 + assert not l1 < l2 and not l1 > l2 + + assert l4 > l3 and l4 >= l3 + l4[0] = l3[0] + assert l4 < l3 + + for i in range(0, 10): + if i % 2 == 0: + l6.append('a') + else: + l7.append('a') + l5[0] = l6 + l5[1] = l7 + if i % 2 == 0: + assert l5[1 - i % 2] < l5[i % 2] + assert l5[1 - i % 2] <= l5[i % 2] + assert not l5[1 - i % 2] > l5[i % 2] + assert not l5[1 - i % 2] >= l5[i % 2] + + t1 = (1, 2) + t2 = (2, 3) + assert t1 < t2 and t1 <= t2 + assert not t1 > t2 and not t1 >= t2 + +test_list_compare() \ No newline at end of file diff --git a/integration_tests/test_list_compare2.py b/integration_tests/test_list_compare2.py new file mode 100644 index 0000000000..9778c9a2a7 --- /dev/null +++ b/integration_tests/test_list_compare2.py @@ -0,0 +1,8 @@ +from lpython import i32 + +x: list[i32] = [1, 2, 3, 4] +y: list[i32] = [5, 6, 7, 8] +z: list[i32] = [1, 2, 3, 4] + +assert(x != y) +assert(x == z) \ No newline at end of file diff --git a/integration_tests/test_list_concat.py b/integration_tests/test_list_concat.py new file mode 100644 index 0000000000..2cf2b583a2 --- /dev/null +++ b/integration_tests/test_list_concat.py @@ -0,0 +1,18 @@ +from lpython import i32, f64 + +def test_list_concat(): + t1: list[i32] + t1 = [2] + [3] + print(t1) + assert len(t1) == 2 + assert t1[0] == 2 + assert t1[1] == 3 + + t2: list[f64] + t2 = [3.14, -4.5] + [1.233, -0.012, 5555.50] + print(t2) + assert len(t2) == 5 + assert abs(t2[0] - 3.14) <= 1e-5 + assert abs(t2[-1] - 5555.50) <= 1e-5 + +test_list_concat() diff --git a/integration_tests/test_list_count.py b/integration_tests/test_list_count.py new file mode 100644 index 0000000000..98c64fd6cb --- /dev/null +++ b/integration_tests/test_list_count.py @@ -0,0 +1,55 @@ +from lpython import i32, f64 + +def test_list_count(): + i: i32 + x: list[i32] = [] + y: list[str] = [] + z: list[tuple[i32, str, f64]] = [] + + for i in range(-5, 0): + assert x.count(i) == 0 + x.append(i) + assert x.count(i) == 1 + x.append(i) + assert x.count(i) == 2 + x.remove(i) + assert x.count(i) == 1 + + assert x == [-5, -4, -3, -2, -1] + + for i in range(0, 5): + assert x.count(i) == 0 + x.append(i) + assert x.count(i) == 1 + + assert x == [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4] + + while len(x) > 0: + i = x[-1] + x.remove(i) + assert x.count(i) == 0 + + assert len(x) == 0 + assert x.count(0) == 0 + + # str + assert y.count('a') == 0 + y = ['a', 'abc', 'a', 'b'] + assert y.count('a') == 2 + y.append('a') + assert y.count('a') == 3 + y.remove('a') + assert y.count('a') == 2 + + # tuple, float + assert z.count((i32(-1), 'b', f64(2))) == 0 + z = [(i32(1), 'a', f64(2.01)), (i32(-1), 'b', f64(2)), (i32(1), 'a', f64(2.02))] + assert z.count((i32(1), 'a', f64(2.00))) == 0 + assert z.count((i32(1), 'a', f64(2.01))) == 1 + z.append((i32(1), 'a', f64(2))) + z.append((i32(1), 'a', f64(2.00))) + assert z.count((i32(1), 'a', f64(2))) == 2 + z.remove((i32(1), 'a', f64(2))) + assert z.count((i32(1), 'a', f64(2.00))) == 1 + +test_list_count() diff --git a/integration_tests/test_list_index.py b/integration_tests/test_list_index.py new file mode 100644 index 0000000000..b74410bf1f --- /dev/null +++ b/integration_tests/test_list_index.py @@ -0,0 +1,40 @@ +from lpython import i32, f64 + +def test_list_index(): + i: i32 + x: list[i32] = [] + y: list[str] = [] + z: list[tuple[i32, str, f64]] = [] + + for i in range(-5, 0): + x.append(i) + assert x.index(i) == len(x)-1 + x.append(i) + assert x.index(i) == len(x)-2 + x.remove(i) + assert x.index(i) == len(x)-1 + + assert x == [-5, -4, -3, -2, -1] + + for i in range(-5, 0): + x.append(i) + assert x.index(i) == 0 + x.remove(i) + assert x.index(i) == len(x)-1 + + # str + y = ['a', 'abc', 'a', 'b', 'abc'] + assert y.index('a') == 0 + assert y.index('abc') == 1 + + # tuple, float + z = [(i32(1), 'a', f64(2.01)), (i32(-1), 'b', f64(2)), (i32(1), 'a', f64(2.02))] + assert z.index((i32(1), 'a', f64(2.01))) == 0 + z.insert(0, (i32(1), 'a', f64(2))) + assert z.index((i32(1), 'a', f64(2.00))) == 0 + z.append((i32(1), 'a', f64(2.00))) + assert z.index((i32(1), 'a', f64(2))) == 0 + z.remove((i32(1), 'a', f64(2))) + assert z.index((i32(1), 'a', f64(2.00))) == 3 + +test_list_index() \ No newline at end of file diff --git a/integration_tests/test_list_index2.py b/integration_tests/test_list_index2.py new file mode 100644 index 0000000000..9e74e929b4 --- /dev/null +++ b/integration_tests/test_list_index2.py @@ -0,0 +1,55 @@ +from lpython import i32, f64 + +def test_list_index2(): + # test optional start and end parameters + i: i32 + x: list[i32] = [] + y: list[str] = [] + z: list[tuple[i32, str, f64]] = [] + + x = [1, 2, 3, 2] + assert x.index(2, 0) == 1 + assert x.index(2, 1) == 1 + assert x.index(2, 2) == 3 + assert x.index(2, 1, 4) == 1 + assert x.index(2, 2, 4) == 3 + + x = [] + for i in range(-5, 0): + x.append(i) + assert x.index(i, 0) == len(x) - 1 + assert x.index(i, 0, len(x)) == len(x) - 1 + x.append(i) + assert x.index(i, 0) == len(x) - 2 + assert x.index(i, 0, len(x)) == len(x) - 2 + assert x.index(i, len(x) - 1) == len(x) - 1 + assert x.index(i, len(x) - 1, len(x)) == len(x) - 1 + x.remove(i) + assert x.index(i, 0) == len(x) - 1 + assert x.index(i, 0, len(x)) == len(x) - 1 + + assert x == [-5, -4, -3, -2, -1] + + # str + y = ['a', 'abc', 'a', 'b', 'abc'] + assert y.index('a', 0) == 0 + assert y.index('a', 0, 1) == 0 + assert y.index('a', 1) == 2 + assert y.index('a', 1, 3) == 2 + assert y.index('abc', 0) == 1 + assert y.index('abc', 1) == 1 + assert y.index('abc', 2) == 4 + + # tuple, float + z = [(1, 'a', 2.01), (-1, 'b', 2.0), (1, 'a', 2.02)] + assert z.index((1, 'a', 2.01), 0) == 0 + assert z.index((1, 'a', 2.01), 0, 1) == 0 + z.insert(0, (1, 'a', 2.0)) + assert z.index((1, 'a', 2.0), 0) == 0 + assert z.index((-1, 'b', 2.0), 1) == 2 + z.insert(0, (1, 'a', 2.0)) + assert z.index((-1, 'b', 2.0), 1) == 3 + assert z.index((-1, 'b', 2.0), 1, 4) == 3 + assert z.index((-1, 'b', 2.0), 1, 5) == 3 + +test_list_index2() \ No newline at end of file diff --git a/integration_tests/test_list_item_mixed_print.py b/integration_tests/test_list_item_mixed_print.py new file mode 100644 index 0000000000..10fdc32b75 --- /dev/null +++ b/integration_tests/test_list_item_mixed_print.py @@ -0,0 +1,44 @@ +from lpython import i32, f64 + +# Test for verifying printing items of different types with a list: +# 1. string and list item +# 2. integer and list item +# 3. float and list item +# 4. tuple and list item +# +# Also test with a list item which is a nested list. +def test_list_item_mixed_print(): + s_list: list[str] = ["Hello", "LPython"] + + print("", s_list[0]) + print("This is", s_list[1]) + + i_list: list[i32] = [1, 2, 3, 4, 5] + + print(i_list[0], i_list[1], i_list[2], "...", i_list[-3], i_list[-2], i_list[-1]) + print("The first element is:", i_list[0]) + + m: i32 = len(i_list) // 2 + print("The middle element is:", i_list[m]) + + f_list: list[f64] = [3.14, 6.28] + + print(f_list[0], "* 2 =", f_list[1]) + print("Total:", f_list[0] + f_list[1]) + + t: tuple[i32, i32, i32] = (1, 2, 3) + print(t, "is a tuple, but", i_list[0], "is a number.") + + i_list2: list[i32] = [1, 2, 3] + print(i_list2[0], i_list2[1], i_list2[2], sep=" is smaller than ") + + i: i32 + for i in range(len(i_list)): + print(i_list[i], end=" # ") + print("\n") + + n_list: list[list[i32]] = [[1, 2], [3, 4], [5, 6]] + for i in range(len(n_list)): + print("List ", i, ":", n_list[i]) + +test_list_item_mixed_print() \ No newline at end of file diff --git a/integration_tests/test_list_pop.py b/integration_tests/test_list_pop.py new file mode 100644 index 0000000000..da2db3e5fd --- /dev/null +++ b/integration_tests/test_list_pop.py @@ -0,0 +1,96 @@ +from lpython import i32, f64 + +def test_list_pop(): + l1: list[i32] + l2: list[tuple[i32, f64]] + l3: list[list[str]] + i: i32 + j: i32 + total: i32 + x: tuple[i32, f64] + + l1 = [1, 2, 3] + assert l1.pop() == 3 + assert l1 == [1, 2] + + l1 = [] + total = 10 + for i in range(total): + l1.append(i) + if i % 2 == 1: + assert l1.pop() == i + for i in range(total // 2): + assert l1[i] == 2 * i + + l2 = [(1, 2.0)] + x = l2.pop() + assert x == (1, 2.0) + assert len(l2) == 0 + l2.append((2, 3.0)) + assert x == (1, 2.0) + + l3 = [] + for i in range(total): + l3.insert(0, ["a"]) + for j in range(len(l3)): + l3[j] += ["a"] + while len(l3) > 0: + total = len(l3) + assert len(l3.pop()) == total + 1 + assert len(l3) == 0 + + l1 = [0, 1, 2, 3, 4] + assert l1.pop(3) == 3 + assert l1.pop(0) == 0 + assert l1.pop(len(l1) - 1) == 4 + assert l1 == [1, 2] + + total = 10 + l1 = [] + for i in range(total): + l1.append(i) + j = 0 + for i in range(total): + assert l1.pop(j - i) == i + j += 1 + assert len(l1) == 0 + + total = 10 + l2 = [] + for i in range(total): + l2.append((i, f64(i * i))) + j = 0 + for i in range(total): + assert l2.pop(j - i) == (i, f64(i * i)) + j += 1 + assert len(l2) == 0 + + # list.pop on list constant + print([1, 2, 3, 4, 5].pop()) + assert [1, 2, 3, 4, 5].pop() == 5 + + print([1, 2, 3, 4, 5].pop(3)) + assert [1, 2, 3, 4, 5].pop(3) == 4 + + index: i32 = 1 + print([1, 2, 3, 4, 5].pop(index)) + assert [1, 2, 3, 4, 5].pop(index) == 2 + + element_1: i32 = [1, 2, 3, 4, 5].pop() + print(element_1) + assert element_1 == 5 + + element_2: i32 = [1, 2, 3, 4, 5].pop(2) + print(element_2) + assert element_2 == 3 + + a: i32 = 5 + b: i32 = 3 + + print([(1, 2), (3, 4), (5, 6)].pop(a//b)) + assert [(1, 2), (3, 4), (5, 6)].pop(a//b) == (3, 4) + + print([["a", "b"], ["c", "d"], ["e", "f"]].pop()) + assert [["a", "b"], ["c", "d"], ["e", "f"]].pop() == ["e", "f"] + +test_list_pop() \ No newline at end of file diff --git a/integration_tests/test_list_pop2.py b/integration_tests/test_list_pop2.py new file mode 100644 index 0000000000..cee56b3684 --- /dev/null +++ b/integration_tests/test_list_pop2.py @@ -0,0 +1,22 @@ +from lpython import i32, f64, InOut + +def pop_wrapper(l: InOut[list[tuple[i32, f64]]], idx: i32) -> tuple[i32, f64]: + return l.pop(idx) + +def test_list_pop(): + l1: list[tuple[i32, f64]] + x: tuple[i32, f64] + i: i32 + + l1 = [(1, 1.0), (2, 4.0), (3, 6.0)] + + x = pop_wrapper(l1, 0) + assert x == (1, 1.0) + + l1.append((4, 8.0)) + assert x == (1, 1.0) + + for i in range(len(l1)): + assert l1[i] == (i + 2, 2.0 * f64(i + 2)) + +test_list_pop() \ No newline at end of file diff --git a/integration_tests/test_list_pop3.py b/integration_tests/test_list_pop3.py new file mode 100644 index 0000000000..13f0740a67 --- /dev/null +++ b/integration_tests/test_list_pop3.py @@ -0,0 +1,14 @@ +from lpython import i32 + +def main0(): + a: list[i32] = [3, 4, 5] + i: i32 + for i in range(10): + a.append(1) + a.pop() + + print(a) + assert a[-1] == 5 + assert len(a) == 3 + +main0() diff --git a/integration_tests/test_list_repeat.py b/integration_tests/test_list_repeat.py new file mode 100644 index 0000000000..1c9b1bbc81 --- /dev/null +++ b/integration_tests/test_list_repeat.py @@ -0,0 +1,41 @@ +from lpython import i32, f64 + +def test_list_repeat(): + l_int_1: list[i32] = [1, 2] + l_int_2: list[i32] = [] + l_int_3: list[i32] + l_tuple_1: list[tuple[f64, i32]] = [(1.0, 2), (2.0, 4), (3.0, 6)] + l_tuple_2: list[tuple[f64, i32]] = [] + l_tuple_3: list[tuple[f64, i32]] + l_str_1: list[str] = ['ab', 'cd'] + l_str_2: list[str] = [] + l_str_3: list[str] + i: i32 + + assert len(l_int_1 * 0) == 0 + assert l_int_1 * 1 == [1, 2] + assert l_int_1 * 2 == [1, 2, 1, 2] + + for i in range(10): + l_int_3 = l_int_1 * i + assert l_int_3 == l_int_2 + l_int_2 += l_int_1 + + l_tuple_3 = l_tuple_1 * i + assert l_tuple_3 == l_tuple_2 + l_tuple_2 += l_tuple_1 + + l_str_3 = l_str_1 * i + assert l_str_3 == l_str_2 + l_str_2 += l_str_1 + + for i in range(5): + assert l_int_1 * i + l_int_1 * (i + 1) == l_int_1 * (2 * i + 1) + assert l_tuple_1 * i + l_tuple_1 * (i + 1) == l_tuple_1 * (2 * i + 1) + assert l_str_1 * i + l_str_1 * (i + 1) == l_str_1 * (2 * i + 1) + + print(l_int_1) + print(l_tuple_1) + print(l_tuple_1) + +test_list_repeat() diff --git a/integration_tests/test_list_repeat2.py b/integration_tests/test_list_repeat2.py new file mode 100644 index 0000000000..f152e691ca --- /dev/null +++ b/integration_tests/test_list_repeat2.py @@ -0,0 +1,24 @@ +from lpython import i32, f32 + +def add_list(x: list[f32]) -> f32: + sum: f32 = f32(0.0) + i: i32 + + for i in range(len(x)): + sum = sum + f32(x[i]) + return sum + +def create_list(n: i32) -> list[f32]: + x: list[f32] + i: i32 + + x = [f32(0.0)] * n + for i in range(n): + x[i] = f32(i) + return x + +def main0(): + x: list[f32] = create_list(i32(10)) + print(add_list(x)) + +main0() diff --git a/integration_tests/test_list_reserve.py b/integration_tests/test_list_reserve.py new file mode 100644 index 0000000000..f359d7547d --- /dev/null +++ b/integration_tests/test_list_reserve.py @@ -0,0 +1,30 @@ +from lpython import i32, f64, reserve + +def test_list_reserve(): + l1: list[i32] = [] + l2: list[list[tuple[f64, str, tuple[i32, f64]]]] = [] + i: i32 + + reserve(l1, 100) + # for i in range(50): + # l1.append(i) + # assert len(l1) == i + 1 + + # reserve(l1, 150) + + # for i in range(50): + # l1.pop(0) + # assert len(l1) == 49 - i + + # reserve(l2, 100) + # for i in range(50): + # l2.append([(f64(i * i), str(i), (i, f64(i + 1))), (f64(i), str(i), (i, f64(i)))]) + # assert len(l2) == i + 1 + + # reserve(l2, 150) + + # for i in range(50): + # l2.pop(0) + # assert len(l2) == 49 - i + +test_list_reserve() diff --git a/integration_tests/test_list_reverse.py b/integration_tests/test_list_reverse.py new file mode 100644 index 0000000000..ca8595756c --- /dev/null +++ b/integration_tests/test_list_reverse.py @@ -0,0 +1,57 @@ +from lpython import i32, f64 + +def test_list_reverse(): + l1: list[i32] = [] + l2: list[i32] = [] + l3: list[f64] = [] + l4: list[f64] = [] + l5: list[str] = [] + l6: list[str] = [] + l7: list[str] = [] + l8: list[list[i32]] = [] + l9: list[tuple[i32, f64, str]] = [] + i: i32 + j: f64 + s: str + + l1 = [1, 2, 3] + l1.reverse() + assert l1 == [3, 2, 1] + + l1 = [] + for i in range(10): + l1.reverse() + l1.append(i) + l2.insert(0, i) + l1.reverse() + assert l1 == l2 + + j = 0.0 + while j < 2.1: + l3.reverse() + l3.append(j) + l4.insert(0, j) + l3.insert(0, j + 1.0) + l4.append(j + 1.0) + l3.reverse() + assert l3 == l4 + j += 0.1 + + l5 = ["abcd", "efgh", "ijkl"] + for s in l5: + l6.reverse() + l6.insert(0, s) + l7.append(s) + l6.reverse() + assert l6 == l7 + + l8 = [[1, 2], [3, 4, 5], [6, 7, 8, 9], [10]] + l8.reverse() + assert l8 == [[10], [6, 7, 8, 9], [3, 4, 5], [1, 2]] + + l9 = [(1, 2.0, "abc"), (3, 4.0, "def"), (5, 6.0, "ghi")] + l9.reverse() + assert l9 == [(5, 6.0, "ghi"), (3, 4.0, "def"), (1, 2.0, "abc")] + + +test_list_reverse() diff --git a/integration_tests/test_list_section.py b/integration_tests/test_list_section.py index 3c59383d79..639e639a55 100644 --- a/integration_tests/test_list_section.py +++ b/integration_tests/test_list_section.py @@ -1,4 +1,4 @@ -from ltypes import i32 +from lpython import i32 def test_issue_1369(): diff --git a/integration_tests/test_list_section2.py b/integration_tests/test_list_section2.py new file mode 100644 index 0000000000..493a6c407c --- /dev/null +++ b/integration_tests/test_list_section2.py @@ -0,0 +1,12 @@ +from lpython import i32 + + +def test_list_section(): + x: list[i32] + x = [5, -6, 7, -1, 2, 10, -8, 15] + + n: i32 = len(x[1:4]) + print(n) + assert n == 3 + +test_list_section() diff --git a/integration_tests/test_logical_assignment.py b/integration_tests/test_logical_assignment.py new file mode 100644 index 0000000000..86c03a8d2b --- /dev/null +++ b/integration_tests/test_logical_assignment.py @@ -0,0 +1,21 @@ +from lpython import i32, f64 + + +def test_logical_assignment(): + _LPYTHON: str = "LPython" + s_var: str = "" or _LPYTHON + assert s_var == "LPython" + print(s_var) + + _MAX_VAL: i32 = 100 + i_var: i32 = 0 and 100 + assert i_var == 0 + print(i_var) + + _PI: f64 = 3.14 + f_var: f64 = 2.0 * _PI or _PI**2.0 + assert f_var == 6.28 + print(f_var) + + +test_logical_assignment() diff --git a/integration_tests/test_logical_compare.py b/integration_tests/test_logical_compare.py new file mode 100644 index 0000000000..538598c29a --- /dev/null +++ b/integration_tests/test_logical_compare.py @@ -0,0 +1,129 @@ +from lpython import i32, f64 + + +def test_logical_compare_literal(): + # Integers + print(1 or 3) + assert (1 or 3) == 1 + + print(1 and 3) + assert (1 and 3) == 3 + + print(2 or 3 or 5 or 6) + assert (2 or 3 or 5 or 6) == 2 + + print(1 and 3 or 2 and 4) + assert (1 and 3 or 2 and 4) == 3 + + print(1 or 3 and 0 or 4) + assert (1 or 3 and 0 or 4) == 1 + + print(1 and 3 or 2 and 0) + assert (1 and 3 or 2 and 0) == 3 + + print(1 and 0 or 3 and 4) + assert (1 and 0 or 3 and 4) == 4 + + # Floating-point numbers + print(1.33 or 6.67) + assert (1.33 or 6.67) == 1.33 + + print(1.33 and 6.67) + assert (1.33 and 6.67) == 6.67 + + print(1.33 or 6.67 and 3.33 or 0.0) + assert (1.33 or 6.67 and 3.33 or 0.0) == 1.33 + + print(1.33 and 6.67 or 3.33 and 0.0) + assert (1.33 and 6.67 or 3.33 and 0.0) == 6.67 + + print(1.33 and 0.0 and 3.33 and 6.67) + assert (1.33 and 0.0 and 3.33 and 6.67) == 0.0 + + # Strings + print("a" or "b") + assert ("a" or "b") == "a" + + print("abc" or "b") + assert ("abc" or "b") == "abc" + + print("a" and "b") + assert ("a" and "b") == "b" + + print("a" or "b" and "c" or "d") + assert ("a" or "b" and "c" or "d") == "a" + + print("" or " ") + assert ("" or " ") == " " + + print("" and " " or "a" and "b" and "c") + assert ("" and " " or "a" and "b" and "c") == "c" + + print("" and " " and "a" and "b" and "c") + assert ("" and " " and "a" and "b" and "c") == "" + + +def test_logical_compare_variable(): + # Integers + i_a: i32 = 1 + i_b: i32 = 3 + + print(i_a and i_b) + assert (i_a and i_b) == 3 + + print(i_a or i_b or 2 or 4) + assert (i_a or i_b or 2 or 4) == 1 + + print(i_a and i_b or 2 and 4) + assert (i_a and i_b or 2 and 4) == 3 + + print(i_a or i_b and 0 or 4) + assert (i_a or i_b and 0 or 4) == i_a + + print(i_a and i_b or 2 and 0) + assert (i_a and i_b or 2 and 0) == i_b + + print(i_a and 0 or i_b and 4) + assert (i_a and 0 or i_b and 4) == 4 + + print(i_a + i_b or 0 - 4) + assert (i_a + i_b or 0 - 4) == 4 + + # Floating-point numbers + f_a: f64 = 1.67 + f_b: f64 = 3.33 + + print(f_a // f_b and f_a - f_b) + assert (f_a // f_b and f_a - f_b) == 0.0 + + print(f_a**3.0 or 3.0**f_a) + assert (f_a**3.0 or 3.0**f_a) == 4.657462999999999 + + print(f_a - 3.0 and f_a + 3.0 or f_b - 3.0 and f_b + 3.0) + assert (f_a - 3.0 and f_a + 3.0 or f_b - 3.0 and f_b + 3.0) == 4.67 + + # Strings + s_a: str = "a" + s_b: str = "b" + + print(s_a or s_b) + assert (s_a or s_b) == s_a + + print(s_a and s_b) + assert (s_a and s_b) == s_b + + print(s_a + s_b or s_b + s_a) + assert (s_a + s_b or s_b + s_a) == "ab" + + print(s_a[0] or s_b[-1]) + assert (s_a[0] or s_b[-1]) == "a" + + print(s_a[0] and s_b[-1]) + assert (s_a[0] and s_b[-1]) == "b" + + print(s_a + s_b or s_b + s_a + s_a[0] and s_b[-1]) + assert (s_a + s_b or s_b + s_a + s_a[0] and s_b[-1]) == "ab" + + +test_logical_compare_literal() +test_logical_compare_variable() diff --git a/integration_tests/test_math.py b/integration_tests/test_math.py index 05fa8dd4a0..b79d82f161 100644 --- a/integration_tests/test_math.py +++ b/integration_tests/test_math.py @@ -1,8 +1,8 @@ from math import (factorial, isqrt, perm, comb, degrees, radians, exp, pow, ldexp, fabs, gcd, lcm, floor, ceil, remainder, expm1, fmod, log1p, trunc, - modf, fsum, prod, dist) + modf, fsum, prod, dist, frexp, isclose) import math -from ltypes import i32, i64, f32, f64 +from lpython import i8, i16, i32, i64, f32, f64 eps: f64 eps = 1e-12 @@ -253,6 +253,58 @@ def test_issue_1242(): assert abs(math.pi - 3.14159265358979323846) < 1e-10 +def test_frexp(): + x:f64 = 6.23 + mantissa:f64 + exponent:i16 + mantissa, exponent = frexp(x) + assert abs(mantissa - 0.77875) < eps and exponent == i16(3) + + x = 0.8 + mantissa, exponent = frexp(x) + assert abs(mantissa - 0.8) < eps and exponent == i16(0) + + x = 19.74 + mantissa, exponent = frexp(x) + assert abs(mantissa - 0.616875) < eps and exponent == i16(5) + + x = -23.6 + mantissa, exponent = frexp(x) + assert abs(mantissa + 0.7375) < eps and exponent == i16(5) + + y:f32 = f32(1.23) + mantissa2:f32 + exponent2:i8 + mantissa2, exponent2 = frexp(y) + assert abs(mantissa2 - f32(0.615)) < f32(eps) and exponent2 == i8(1) + + y = f32(-1.23) + mantissa2, exponent2 = frexp(y) + assert abs(mantissa2 - f32(-0.615)) < f32(eps) and exponent2 == i8(1) + + +def test_isclose(): + x:f64 = 2.2130 + y:f64 = 2.2129 + assert isclose(x, y, rel_tol=0.01, abs_tol=0.001) + assert isclose(x,y,rel_tol=0.0000001,abs_tol=0.01) + assert isclose(x,y,rel_tol=0.1,abs_tol=0.000001) + assert not isclose(x,y,rel_tol=0.0000001,abs_tol=0.00001) + + x = -1.265 + y = 1.265 + assert not isclose(x,y,rel_tol=0.001,abs_tol=0.0001) + assert not isclose(y,x,rel_tol=0.01,abs_tol=0.1) + assert not isclose(x,y,rel_tol=0.01,abs_tol=0.1) + + x = -1.2650 + y = -1.2651 + assert isclose(x, y, rel_tol=0.01, abs_tol=0.001) + assert isclose(x,y,rel_tol=0.0000001,abs_tol=0.01) + assert isclose(x,y,rel_tol=0.1,abs_tol=0.000001) + assert not isclose(x,y,rel_tol=0.0000001,abs_tol=0.00001) + + def check(): test_factorial_1() test_comb() @@ -278,6 +330,8 @@ def check(): test_dist() test_modf() test_issue_1242() + test_frexp() + test_isclose() check() diff --git a/integration_tests/test_math1.py b/integration_tests/test_math1.py index b9e4bda987..41c4441660 100644 --- a/integration_tests/test_math1.py +++ b/integration_tests/test_math1.py @@ -1,6 +1,6 @@ import math from math import pi, e -from ltypes import i32 +from lpython import i32 def f(): diff --git a/integration_tests/test_math_02.py b/integration_tests/test_math_02.py index b154fcb152..a15b604326 100644 --- a/integration_tests/test_math_02.py +++ b/integration_tests/test_math_02.py @@ -1,20 +1,20 @@ from math import (sin, cos, tan, pi, sqrt, log, log10, log2, erf, erfc, gamma, lgamma, asin, acos, atan, atan2, asinh, acosh, atanh, tanh, sinh, cosh, hypot, copysign) -from ltypes import f64 +from lpython import f64 def test_trig(): eps: f64 = 1e-12 assert abs(sin(0.0) - 0.0) < eps - assert abs(sin(pi/2) - 1.0) < eps + assert abs(sin(pi/2.0) - 1.0) < eps assert abs(cos(0.0) - 1.0) < eps - assert abs(cos(pi/2) - 0.0) < eps + assert abs(cos(pi/2.0) - 0.0) < eps assert abs(tan(0.0) - 0.0) < eps - assert abs(tan(pi/4) - 1.0) < eps - assert abs(asin(1.0) - pi/2) < eps + assert abs(tan(pi/4.0) - 1.0) < eps + assert abs(asin(1.0) - pi/2.0) < eps assert abs(acos(1.0) - 0.0) < eps - assert abs(atan(1.0) - pi/4) < eps - assert abs(atan2(1.0, 1.0) - pi/4) < eps + assert abs(atan(1.0) - pi/4.0) < eps + assert abs(atan2(1.0, 1.0) - pi/4.0) < eps def test_sqrt(): eps: f64 = 1e-12 diff --git a/integration_tests/test_math_03.py b/integration_tests/test_math_03.py index adb6a2af09..8047ce2c24 100644 --- a/integration_tests/test_math_03.py +++ b/integration_tests/test_math_03.py @@ -1,5 +1,5 @@ from math import (cbrt, exp2) -from ltypes import f64 +from lpython import f64 eps: f64 eps = 1e-12 diff --git a/integration_tests/test_max_min.py b/integration_tests/test_max_min.py index 80eb924a10..79462ec2f4 100644 --- a/integration_tests/test_max_min.py +++ b/integration_tests/test_max_min.py @@ -1,4 +1,4 @@ -from ltypes import i32, f64 +from lpython import i32, f64 def test_max_int(): a: i32 = 1 diff --git a/integration_tests/test_membership_01.py b/integration_tests/test_membership_01.py new file mode 100644 index 0000000000..10cb4f682e --- /dev/null +++ b/integration_tests/test_membership_01.py @@ -0,0 +1,48 @@ +def test_int_dict(): + a: dict[i32, i32] = {1:2, 2:3, 3:4, 4:5} + i: i32 + assert (1 in a) + assert (6 not in a) + i = 4 + assert (i in a) + + a = {} + assert (1 not in a) + +def test_str_dict(): + a: dict[str, str] = {'a':'1', 'b':'2', 'c':'3'} + i: str + assert ('a' in a) + assert ('d' not in a) + i = 'c' + assert (i in a) + + a = {} + assert ('a' not in a) + +def test_int_set(): + a: set[i32] = {1, 2, 3, 4} + i: i32 + assert (1 in a) + assert (6 not in a) + i = 4 + assert (i in a) + + a = set() + assert (1 not in a) + +def test_str_set(): + a: set[str] = {'a', 'b', 'c', 'e', 'f'} + i: str + assert ('a' in a) + assert ('d' not in a) + i = 'c' + assert (i in a) + + a = set() + assert ('a' not in a) + +test_int_dict() +test_str_dict() +test_int_set() +test_str_set() diff --git a/test_modules/__init__.py b/integration_tests/test_modules/__init__.py similarity index 100% rename from test_modules/__init__.py rename to integration_tests/test_modules/__init__.py diff --git a/test_modules/mathfn/__init__.py b/integration_tests/test_modules/mathfn/__init__.py similarity index 100% rename from test_modules/mathfn/__init__.py rename to integration_tests/test_modules/mathfn/__init__.py diff --git a/test_modules/mathfn/sin.py b/integration_tests/test_modules/mathfn/sin.py similarity index 78% rename from test_modules/mathfn/sin.py rename to integration_tests/test_modules/mathfn/sin.py index d7724ea4f1..4d26103b13 100644 --- a/test_modules/mathfn/sin.py +++ b/integration_tests/test_modules/mathfn/sin.py @@ -1,4 +1,4 @@ -from ltypes import f64 +from lpython import f64 def sinx(x: f64) -> f64: return x + 1.0 diff --git a/integration_tests/test_numpy_01.py b/integration_tests/test_numpy_01.py index 6b4119b972..85685d01df 100644 --- a/integration_tests/test_numpy_01.py +++ b/integration_tests/test_numpy_01.py @@ -1,11 +1,11 @@ # This test handles various aspects of local arrays using the `numpy.empty()` # function -from ltypes import f64, i32 -from numpy import empty +from lpython import f64, i32 +from numpy import empty, float64 def test_local_arrays(): a: f64[16] - a = empty(16) + a = empty(16, dtype=float64) i: i32 for i in range(16): a[i] = f64(i) + 0.5 @@ -18,7 +18,7 @@ def test_local_arrays(): def f() -> f64[4]: a: f64[4] - a = empty(4) + a = empty(4, dtype=float64) i: i32 for i in range(4): a[i] = 1.0 * f64(i) diff --git a/integration_tests/test_numpy_02.py b/integration_tests/test_numpy_02.py index 7b23ac2a4b..920b102dbf 100644 --- a/integration_tests/test_numpy_02.py +++ b/integration_tests/test_numpy_02.py @@ -1,7 +1,7 @@ # This test handles actual LPython implementations of functions from the numpy # module. -from ltypes import i32, i64, f32, f64, c32, c64, TypeVar, overload -from numpy import empty, int64 +from lpython import i32, i64, f32, f64, c32, c64, TypeVar, overload +from numpy import empty, int64, float64 e: f64 = 2.718281828459045 pi: f64 = 3.141592653589793 @@ -12,12 +12,11 @@ eps: f64 eps = 1e-12 -n: i32 n = TypeVar("n") def zeros(n: i32) -> f64[n]: A: f64[n] - A = empty(n) + A = empty(n, dtype=float64) i: i32 for i in range(n): A[i] = 0.0 @@ -25,7 +24,7 @@ def zeros(n: i32) -> f64[n]: def ones(n: i32) -> f64[n]: A: f64[n] - A = empty(n) + A = empty(n, dtype=float64) i: i32 for i in range(n): A[i] = 1.0 @@ -126,11 +125,10 @@ def fabs(f: f64) -> f64: def fabs(b: bool) -> f64: return sqrt(b) -num: i32 num = TypeVar("num") def linspace(start: f64, stop: f64, num: i32) -> f64[num]: A: f64[num] - A = empty(num) + A = empty(num, dtype=float64) i: i32 for i in range(num): A[i] = start + (stop-start)*f64(i)/f64(num-1) diff --git a/integration_tests/test_numpy_03.py b/integration_tests/test_numpy_03.py index ea1058a19d..82faf76db4 100644 --- a/integration_tests/test_numpy_03.py +++ b/integration_tests/test_numpy_03.py @@ -1,5 +1,5 @@ -from ltypes import f64, i32 -from numpy import reshape, empty +from lpython import f64, i32 +from numpy import reshape, empty, int32, float64 def test_nd_to_1d(a: f64[:, :]): i: i32 @@ -9,8 +9,8 @@ def test_nd_to_1d(a: f64[:, :]): eps: f64 eps = 1e-12 - b: f64[256] = empty(256) - newshape: i32[1] = empty(1, dtype=int) + b: f64[256] = empty(256, dtype=float64) + newshape: i32[1] = empty(1, dtype=int32) newshape[0] = 256 b = reshape(a, newshape) for k in range(256): @@ -18,19 +18,19 @@ def test_nd_to_1d(a: f64[:, :]): j = k - i*16 assert abs(b[k] - f64(i + j) - 0.5) <= eps - c: f64[16, 16, 16] = empty((16, 16, 16)) - c = empty((16, 16, 16)) + c: f64[16, 16, 16] = empty((16, 16, 16), dtype=float64) + c = empty((16, 16, 16), dtype=float64) for i in range(16): for j in range(16): for k in range(16): c[i, j, k] = f64(i + j + k) + 0.5 - d: f64[4096] = empty(4096) - newshape1: i32[1] = empty(1, dtype=int) + d: f64[4096] = empty(4096, dtype=float64) + newshape1: i32[1] = empty(1, dtype=int32) newshape1[0] = 4096 d = reshape(c, newshape1) for l in range(4096): - i = i32(int(l/256)) + i = i32(l/256) j = (l - i*256)//16 k = (l - i*256 - j*16) assert abs(d[l] - f64(i + j + k) - 0.5) <= eps @@ -43,15 +43,15 @@ def test_1d_to_nd(d: f64[:]): eps: f64 eps = 1e-12 - b: f64[256] = empty(256) + b: f64[256] = empty(256, dtype=float64) for k in range(256): i = k//16 j = k - i*16 b[k] = f64(i + j) + 0.5 a: f64[16, 16] - a = empty((16, 16)) - newshape: i32[2] = empty(2, dtype=int) + a = empty((16, 16), dtype=float64) + newshape: i32[2] = empty(2, dtype=int32) newshape[0] = 16 newshape[1] = 16 a = reshape(b, newshape) @@ -60,8 +60,8 @@ def test_1d_to_nd(d: f64[:]): assert abs(a[i, j] - f64(i + j) - 0.5) <= eps c: f64[16, 16, 16] - c = empty((16, 16, 16)) - newshape1: i32[3] = empty(3, dtype=int) + c = empty((16, 16, 16), dtype=float64) + newshape1: i32[3] = empty(3, dtype=int32) newshape1[0] = 16 newshape1[1] = 16 newshape1[2] = 16 @@ -78,16 +78,16 @@ def test_reshape_with_argument(): l: i32 a: f64[16, 16] - a = empty((16, 16)) + a = empty((16, 16), dtype=float64) for i in range(16): for j in range(16): a[i, j] = f64(i + j) + 0.5 test_nd_to_1d(a) - d: f64[4096] = empty(4096) + d: f64[4096] = empty(4096, dtype=float64) for l in range(4096): - i = i32(int(l/256)) + i = i32(l/256) j = (l - i*256)//16 k = (l - i*256 - j*16) d[l] = f64(i + j + k) + 0.5 diff --git a/integration_tests/test_numpy_04.py b/integration_tests/test_numpy_04.py index 1225b307a7..823c573af8 100644 --- a/integration_tests/test_numpy_04.py +++ b/integration_tests/test_numpy_04.py @@ -1,4 +1,4 @@ -from ltypes import i32, f64 +from lpython import i32, f64 from numpy import array def test_array_01(): diff --git a/integration_tests/test_os.py b/integration_tests/test_os.py index b513fbbcae..20f92c342d 100644 --- a/integration_tests/test_os.py +++ b/integration_tests/test_os.py @@ -1,4 +1,4 @@ -from ltypes import i64 +from lpython import i64 from os import (open, read, close, O_RDONLY) def test(): diff --git a/integration_tests/test_package_01.py b/integration_tests/test_package_01.py index 0026a0c8c7..9ba20b210a 100644 --- a/integration_tests/test_package_01.py +++ b/integration_tests/test_package_01.py @@ -1,5 +1,5 @@ from nrp import newton_raphson -from ltypes import f64, i32 +from lpython import f64, i32 def check(): diff --git a/integration_tests/test_params.py b/integration_tests/test_params.py new file mode 100644 index 0000000000..0748dcfd2a --- /dev/null +++ b/integration_tests/test_params.py @@ -0,0 +1,14 @@ +from lpython import i32 + +def takes_set(a: set[i32]) -> set[i32]: + return {1, 2, 3} + +def takes_dict(a: dict[i32, i32]) -> dict[i32, i32]: + return {1:1, 2:2} + +s: set[i32] = takes_set({1, 2}) + +assert len(s) == 3 + +w: dict[i32, i32] = takes_dict({1:1, 2:2}) +assert len(w) == 2 diff --git a/integration_tests/test_pass_compare.py b/integration_tests/test_pass_compare.py index f98dee1416..f076366b83 100644 --- a/integration_tests/test_pass_compare.py +++ b/integration_tests/test_pass_compare.py @@ -1,4 +1,4 @@ -from ltypes import i32 +from lpython import i32 def f(): diff --git a/integration_tests/test_pip_import_01.py b/integration_tests/test_pip_import_01.py new file mode 100644 index 0000000000..530abb4552 --- /dev/null +++ b/integration_tests/test_pip_import_01.py @@ -0,0 +1,46 @@ +from lpynn.perceptron import init_perceptron, print_perceptron, Perceptron, train_dataset +from lpynn.utils import normalize_input_vectors +from lpython import i32, f64 + +def main0(): + p: Perceptron = Perceptron(0, [0.0], 0.0, 0, 0.0, 0.0, 0) + init_perceptron(p, 2, 0.05, 10000, 90.0) + print_perceptron(p) + print("=================================") + + input_vectors: list[list[f64]] = [[-1.0, -1.0], [-1.0, 1.0], [1.0, -1.0], [1.0, 1.0]] + outputs: list[i32] = [1, 1, 1, -1] + + normalize_input_vectors(input_vectors) + train_dataset(p, input_vectors, outputs) + print_perceptron(p) + print("=================================") + + assert p.cur_accuracy > 50.0 + assert p.epochs_cnt > 1 + assert abs(p.weights[0] - (-0.1)) < 1e-12 + assert abs(p.weights[1] - (-0.1)) < 1e-12 + assert abs(p.weights[2] - (0.1)) < 1e-12 + +def main1(): + p: Perceptron = Perceptron(0, [0.0], 0.0, 0, 0.0, 0.0, 0) + init_perceptron(p, 2, 0.05, 10000, 90.0) + print_perceptron(p) + print("=================================") + + input_vectors: list[list[f64]] = [[-1.0, -1.0], [-1.0, 1.0], [1.0, -1.0], [1.0, 1.0], [1.5, 1.0]] + outputs: list[i32] = [1, 1, -1, 1, -1] + + normalize_input_vectors(input_vectors) + train_dataset(p, input_vectors, outputs) + print_perceptron(p) + print("=================================") + + assert p.cur_accuracy > 50.0 + assert p.epochs_cnt > 1 + assert abs(p.weights[0] - (-0.22)) < 1e-12 + assert abs(p.weights[1] - (0.1)) < 1e-12 + assert abs(p.weights[2] - (0.1)) < 1e-12 + +main0() +main1() diff --git a/integration_tests/test_pkg_lnn_01.py b/integration_tests/test_pkg_lnn_01.py new file mode 100644 index 0000000000..63dcbf5ee2 --- /dev/null +++ b/integration_tests/test_pkg_lnn_01.py @@ -0,0 +1,90 @@ +from lnn.perceptron import init_perceptron, print_perceptron, Perceptron, train_dataset +from lnn.utils import normalize_input_vectors +from lpdraw import Line, Circle, Display, Clear +from lpython import i32, f64, Const +from numpy import empty, int32 + + +def compute_decision_boundary(p: Perceptron, x: f64) -> f64: + bias: f64 = p.weights[-1] + slope: f64 = (-p.weights[0] / p.weights[1]) + intercept: f64 = (-bias / p.weights[1]) + return slope * x + intercept + +def plot_graph(p: Perceptron, input_vectors: list[list[f64]], outputs: list[i32]): + Width: Const[i32] = 500 # x-axis limits [0, 499] + Height: Const[i32] = 500 # y-axis limits [0, 499] + Screen: i32[Height, Width] = empty((Height, Width), dtype=int32) + Clear(Height, Width, Screen) + + x1: f64 = 2.0 + y1: f64 = compute_decision_boundary(p, x1) + x2: f64 = -2.0 + y2: f64 = compute_decision_boundary(p, x2) + + # center the graph using the following offset + scale_offset: f64 = Width / 4 + shift_offset: f64 = Width / 2 + x1 *= scale_offset + y1 *= scale_offset + x2 *= scale_offset + y2 *= scale_offset + + # print (x1, y1, x2, y2) + Line(Height, Width, Screen, i32(x1 + shift_offset), i32(y1 + shift_offset), i32(x2 + shift_offset), i32(y2 + shift_offset)) + + i: i32 + point_size: i32 = 5 + for i in range(len(input_vectors)): + input_vectors[i][0] *= scale_offset + input_vectors[i][1] *= scale_offset + input_vectors[i][0] += shift_offset + input_vectors[i][1] += shift_offset + if outputs[i] == 1: + x: i32 = i32(input_vectors[i][0]) + y: i32 = i32(input_vectors[i][1]) + Line(Height, Width, Screen, x - point_size, y, x + point_size, y) + Line(Height, Width, Screen, x, y - point_size, x, y + point_size) + else: + Circle(Height, Width, Screen, i32(input_vectors[i][0]), i32(input_vectors[i][1]), f64(point_size)) + + Display(Height, Width, Screen) + +def main0(): + p: Perceptron = Perceptron(0, [0.0], 0.0, 0, 0.0, 0.0, 0) + init_perceptron(p, 2, 0.05, 10000, 90.0) + print_perceptron(p) + print("=================================") + + input_vectors: list[list[f64]] = [[-1.0, -1.0], [-1.0, 1.0], [1.0, -1.0], [1.0, 1.0]] + outputs: list[i32] = [1, 1, 1, -1] + + normalize_input_vectors(input_vectors) + train_dataset(p, input_vectors, outputs) + print_perceptron(p) + + assert p.cur_accuracy > 50.0 + assert p.epochs_cnt > 1 + + plot_graph(p, input_vectors, outputs) + +def main1(): + p: Perceptron = Perceptron(0, [0.0], 0.0, 0, 0.0, 0.0, 0) + init_perceptron(p, 2, 0.05, 10000, 90.0) + print_perceptron(p) + print("=================================") + + input_vectors: list[list[f64]] = [[-1.0, -1.0], [-1.0, 1.0], [1.0, -1.0], [1.0, 1.0], [1.5, 1.0]] + outputs: list[i32] = [1, 1, -1, 1, -1] + + normalize_input_vectors(input_vectors) + train_dataset(p, input_vectors, outputs) + print_perceptron(p) + + assert p.cur_accuracy > 50.0 + assert p.epochs_cnt > 1 + + plot_graph(p, input_vectors, outputs) + +main0() +main1() diff --git a/integration_tests/test_pkg_lnn_02.py b/integration_tests/test_pkg_lnn_02.py new file mode 100644 index 0000000000..c72543b179 --- /dev/null +++ b/integration_tests/test_pkg_lnn_02.py @@ -0,0 +1,89 @@ +from lnn.regression import init_perceptron, print_perceptron, Perceptron, train_dataset +from lnn.utils import normalize_input_vectors, normalize_output_vector +from lpdraw import Line, Circle, Display, Clear +from lpython import i32, f64, Const +from numpy import empty, int32 + + +def compute_decision_boundary(p: Perceptron, x: f64) -> f64: + bias: f64 = p.weights[1] + slope: f64 = p.weights[0] + intercept: f64 = bias + return slope * x + intercept + +def plot_graph(p: Perceptron, input_vectors: list[list[f64]], outputs: list[f64]): + Width: Const[i32] = 500 # x-axis limits [0, 499] + Height: Const[i32] = 500 # y-axis limits [0, 499] + Screen: i32[Height, Width] = empty((Height, Width), dtype=int32) + Clear(Height, Width, Screen) + + x1: f64 = 1.0 + y1: f64 = compute_decision_boundary(p, x1) + x2: f64 = -1.0 + y2: f64 = compute_decision_boundary(p, x2) + + # center the graph using the following offset + scale_offset: f64 = Width / 4 + shift_offset: f64 = Width / 2 + x1 *= scale_offset + y1 *= scale_offset + x2 *= scale_offset + y2 *= scale_offset + + # print (x1, y1, x2, y2) + Line(Height, Width, Screen, i32(x1 + shift_offset), i32(y1 + shift_offset), i32(x2 + shift_offset), i32(y2 + shift_offset)) + + i: i32 + point_size: i32 = 5 + for i in range(len(input_vectors)): + input_vectors[i][0] *= scale_offset + input_vectors[i][0] += shift_offset + outputs[i] *= scale_offset + outputs[i] += shift_offset + + Circle(Height, Width, Screen, i32(input_vectors[i][0]), i32(outputs[i]), f64(point_size)) + + Display(Height, Width, Screen) + +def main0(): + p: Perceptron = Perceptron(0, [0.0], 0.0, 0, 0.0, 0.0, 0) + init_perceptron(p, 1, 0.0005, 10000, 1e-16) + + input_vectors: list[list[f64]] = [[1.1], [1.3], [1.5], [2.0], [2.2], [2.9], [3.0], [3.2], [3.2], [3.7], [3.9], [4.0], [4.0], [4.1], [4.5], [4.9], [5.1], [5.3], [5.9], [6.0], [6.8], [7.1], [7.9], [8.2], [8.7], [9.0], [9.5], [9.6], [10.3], [10.5], [11.2], [11.5], [12.3], [12.9], [13.5]] + outputs: list[f64] = [39343.0, 46205.0, 37731.0, 43525.0, 39891.0, 56642.0, 60150.0, 54445.0, 64445.0, 57189.0, 63218.0, 55794.0, 56957.0, 57081.0, 61111.0, 67938.0, 66029.0, 83088.0, 81363.0, 93940.0, 91738.0, 98273.0, 101302.0, 113812.0, 109431.0, 105582.0, 116969.0, 112635.0, 122391.0, 121872.0, 127345.0, 126756.0, 128765.0, 135675.0, 139465.0] + + normalize_input_vectors(input_vectors) + normalize_output_vector(outputs) + + train_dataset(p, input_vectors, outputs) + print_perceptron(p) + + assert abs(p.weights[0] - (1.0640975812232145)) <= 1e-12 + assert abs(p.weights[1] - (0.0786977829749839)) <= 1e-12 + assert abs(p.err - (0.4735308448814293)) <= 1e-12 + assert p.epochs_cnt == 4515 + + plot_graph(p, input_vectors, outputs) + +def main1(): + p: Perceptron = Perceptron(0, [0.0], 0.0, 0, 0.0, 0.0, 0) + init_perceptron(p, 1, 0.0005, 10000, 1e-16) + + input_vectors: list[list[f64]] = [[1.0], [3.0], [7.0]] + outputs: list[f64] = [8.0, 4.0, -2.0] + + normalize_input_vectors(input_vectors) + normalize_output_vector(outputs) + + train_dataset(p, input_vectors, outputs) + print_perceptron(p) + + assert abs(p.weights[0] - (-0.9856542200697508)) <= 1e-12 + assert abs(p.weights[1] - (-0.0428446744717655)) <= 1e-12 + assert abs(p.err - 0.011428579012311327) <= 1e-12 + assert p.epochs_cnt == 10000 + + plot_graph(p, input_vectors, outputs) + +main0() +main1() diff --git a/integration_tests/test_pkg_lpconvexhull.py b/integration_tests/test_pkg_lpconvexhull.py new file mode 100644 index 0000000000..793ea696dd --- /dev/null +++ b/integration_tests/test_pkg_lpconvexhull.py @@ -0,0 +1,32 @@ +from lpython import Const, i32, f64 + +from lpdraw import Line, Circle, Clear, Display +from lpconvexhull import convex_hull +from numpy import empty, int32 + +def plot_graph(polygon: list[tuple[i32, i32]], points: list[tuple[i32, i32]]): + Width: Const[i32] = 500 # x-axis limits [0, 499] + Height: Const[i32] = 500 # y-axis limits [0, 499] + Screen: i32[Height, Width] = empty((Height, Width), dtype=int32) + Clear(Height, Width, Screen) + + i: i32 + n: i32 = len(polygon) + for i in range(n): + Line(Height, Width, Screen, polygon[i][0], polygon[i][1], polygon[(i + 1) % n][0], polygon[(i + 1) % n][1]) + + point_size: i32 = 5 + for i in range(len(points)): + Circle(Height, Width, Screen, points[i][0], points[i][1], f64(point_size)) + + Display(Height, Width, Screen) + +def main0(): + points: list[tuple[i32, i32]] = [(445, 193), (138, 28), (418, 279), (62, 438), (168, 345), (435, 325), (293, 440), (158, 94), (403, 288), (136, 278), (141, 243), (287, 313), (338, 492), (172, 78), (29, 404), (79, 377), (184, 91), (69, 324), (408, 72), (494, 1)] + convex_hull_points: list[tuple[i32, i32]] = convex_hull(points) + # print(convex_hull_points) + plot_graph(convex_hull_points, points) + + assert convex_hull_points == [(29, 404), (138, 28), (494, 1), (435, 325), (338, 492), (62, 438)] + +main0() diff --git a/integration_tests/test_pkg_lpdraw.py b/integration_tests/test_pkg_lpdraw.py new file mode 100644 index 0000000000..75fd1148da --- /dev/null +++ b/integration_tests/test_pkg_lpdraw.py @@ -0,0 +1,34 @@ +from lpdraw import Line, Circle, Clear, Display, DisplayTerminal + +from lpython import i32, TypeVar +from numpy import empty, int32 + +H = TypeVar("H") +W = TypeVar("W") + +def test_screen(H: i32, W: i32, Screen: i32[H, W]): + i: i32 + j: i32 + cnt: i32 = 0 + for i in range(H): + for j in range(W): + cnt += (Screen[i, j] - 256) + + assert cnt == -979630 + + +def main(): + Width: i32 = 100 # x-axis limits [0, 99] + Height: i32 = 40 # y-axis limits [0, 39] + Screen: i32[40, 100] = empty((40, 100), dtype=int32) + + Clear(Height, Width, Screen) + Line(Height, Width, Screen, 2, 4, 99, 11) + Line(Height, Width, Screen, 0, 39, 49, 0) + Circle(Height, Width, Screen, 52, 20, 6.0) + Display(Height, Width, Screen) + DisplayTerminal(Height, Width, Screen) + + test_screen(Height, Width, Screen) + +main() diff --git a/integration_tests/test_random.py b/integration_tests/test_random.py index d1cded5add..0cf91c7870 100644 --- a/integration_tests/test_random.py +++ b/integration_tests/test_random.py @@ -1,4 +1,4 @@ -from ltypes import i32, f64 +from lpython import i32, f64 import random @@ -52,6 +52,35 @@ def test_weibullvariate(): r = random.weibullvariate(-5.6, 1.2) print(r) +def test_seed(): + random.seed() + t6: f64 = random.random() + random.seed(123) + t1: f64 + t1 = random.random() + random.seed(321) + t2: f64 + t2 = random.random() + random.seed(123) + t3: f64 + t3 = random.random() + random.seed(0) + t4: f64 + t4 = random.random() + random.seed(0) + t5: f64 + t5 = random.random() + random.seed() + t7: f64 = random.random() + + print(t1, t2, t3, t4, t5, t6, t7) + assert t1 != t2 + assert t1 == t3 + assert t1 != t4 + assert t1 != t5 + assert t4 == t5 + # assert t6 != t7 + def check(): test_random() test_randrange() @@ -60,5 +89,6 @@ def check(): test_paretovariate() test_expovariate() test_weibullvariate() + test_seed() check() diff --git a/integration_tests/test_random_02.py b/integration_tests/test_random_02.py new file mode 100644 index 0000000000..560dfe8cd6 --- /dev/null +++ b/integration_tests/test_random_02.py @@ -0,0 +1,21 @@ +from lpython import i32, f64 +import random + +def test_seed(): + """test the distribution of random""" + num_samples:i32 = 100000 + bins: list[i32] = [0]*10 + _ : i32 + for _ in range(num_samples): + val: f64 = random.random() + assert val >= 0.0 and val < 1.0 # value out of range + bins[i32(val * 10.0)] += 1 # increment the appropriate bin + + # Check that no bin has significantly more or fewer values than expected + expected_bin_count:i32 = i32(num_samples / 10) + count : i32 + for count in bins: + blas: f64 = f64(abs(count - expected_bin_count)) + assert blas < f64(expected_bin_count) * 0.05 # allow 5% deviation + +test_seed() diff --git a/integration_tests/test_set_add.py b/integration_tests/test_set_add.py new file mode 100644 index 0000000000..699b1cfa58 --- /dev/null +++ b/integration_tests/test_set_add.py @@ -0,0 +1,34 @@ +from lpython import i32 + +def test_set_add(): + s1: set[i32] + s2: set[tuple[i32, tuple[i32, i32], str]] + s3: set[str] + st1: str + i: i32 + j: i32 + + s1 = {0} + s2 = {(0, (1, 2), 'a')} + for i in range(20): + j = i % 10 + s1.add(j) + s2.add((j, (j + 1, j + 2), 'a')) + assert len(s1) == len(s2) + if i < 10: + assert len(s1) == i + 1 + else: + assert len(s1) == 10 + + st1 = 'a' + s3 = {st1} + for i in range(20): + s3.add(st1) + if i < 10: + if i > 0: + assert len(s3) == i + st1 += 'a' + else: + assert len(s3) == 10 + +test_set_add() diff --git a/integration_tests/test_set_clear.py b/integration_tests/test_set_clear.py new file mode 100644 index 0000000000..871e2c2bf7 --- /dev/null +++ b/integration_tests/test_set_clear.py @@ -0,0 +1,21 @@ +def test_clear(): + a: set[i32] = {1, 2} + + a.clear() + a.add(3) + + assert len(a) == 1 + a.remove(3) + assert len(a) == 0 + + b: set[str] = {'a', 'b'} + + b.clear() + b.add('c') + + assert len(b) == 1 + b.remove('c') + assert len(b) == 0 + + +test_clear() diff --git a/integration_tests/test_set_constructor.py b/integration_tests/test_set_constructor.py new file mode 100644 index 0000000000..497819dbb7 --- /dev/null +++ b/integration_tests/test_set_constructor.py @@ -0,0 +1,17 @@ +def test_empty_set(): + a: set[i32] = set() + assert len(a) == 0 + a.add(2) + a.remove(2) + a.add(3) + assert a.pop() == 3 + + b: set[str] = set() + + assert len(b) == 0 + b.add('a') + b.remove('a') + b.add('b') + assert b.pop() == 3 + +test_empty_set() diff --git a/integration_tests/test_set_discard.py b/integration_tests/test_set_discard.py new file mode 100644 index 0000000000..730abaff7d --- /dev/null +++ b/integration_tests/test_set_discard.py @@ -0,0 +1,48 @@ +from lpython import i32 + +def test_set_discard(): + s1: set[i32] + s2: set[tuple[i32, tuple[i32, i32], str]] + s3: set[str] + st1: str + i: i32 + j: i32 + k: i32 + + for k in range(2): + s1 = {0} + s2 = {(0, (1, 2), "a")} + for i in range(20): + j = i % 10 + s1.add(j) + s2.add((j, (j + 1, j + 2), "a")) + + for i in range(10): + s1.discard(i) + s2.discard((i, (i + 1, i + 2), "a")) + assert len(s1) == 10 - 1 - i + assert len(s1) == len(s2) + + st1 = "a" + s3 = {st1} + for i in range(20): + s3.add(st1) + if i < 10: + if i > 0: + st1 += "a" + + st1 = "a" + for i in range(10): + s3.discard(st1) + assert len(s3) == 10 - 1 - i + if i < 10: + st1 += "a" + + for i in range(20): + s1.add(i) + if i % 2 == 0: + s1.discard(i) + assert len(s1) == (i + 1) // 2 + + +test_set_discard() diff --git a/integration_tests/test_set_from_list.py b/integration_tests/test_set_from_list.py new file mode 100644 index 0000000000..e06b4e40c1 --- /dev/null +++ b/integration_tests/test_set_from_list.py @@ -0,0 +1,14 @@ +from lpython import i32 + + +def test_set(): + s: set[i32] + s = set([1, 2, 2, 2, -1, 1, 1, 3]) + assert len(s) == 4 + + s2: set[str] + s2 = set(["a", "b", "b", "abc", "a"]) + assert len(s2) == 3 + + +test_set() diff --git a/integration_tests/test_set_len.py b/integration_tests/test_set_len.py new file mode 100644 index 0000000000..2b07c2d1ac --- /dev/null +++ b/integration_tests/test_set_len.py @@ -0,0 +1,11 @@ +from lpython import i32 + +def test_set(): + s: set[i32] + s = {1, 2, 22, 2, -1, 1} + assert len(s2) == 4 + s2: set[str] + s2 = {'a', 'b', 'cd', 'b', 'abc', 'a'} + assert len(s2) == 4 + +test_set() diff --git a/integration_tests/test_set_pop.py b/integration_tests/test_set_pop.py new file mode 100644 index 0000000000..af4500e236 --- /dev/null +++ b/integration_tests/test_set_pop.py @@ -0,0 +1,26 @@ +def set_pop_str(): + s: set[str] = {'a', 'b', 'c'} + + assert s.pop() in {'a', 'b', 'c'} + assert len(s) == 2 + assert s.pop() in {'a', 'b', 'c'} + assert s.pop() in {'a', 'b', 'c'} + assert len(s) == 0 + + s.add('d') + assert s.pop() == 'd' + +def set_pop_int(): + s: set[i32] = {1, 2, 3} + + assert s.pop() in {1, 2, 3} + assert len(s) == 2 + assert s.pop() in {1, 2, 3} + assert s.pop() in {1, 2, 3} + assert len(s) == 0 + + s.add(4) + assert s.pop() == 4 + +set_pop_str() +set_pop_int() diff --git a/integration_tests/test_set_remove.py b/integration_tests/test_set_remove.py new file mode 100644 index 0000000000..ca93ec0a80 --- /dev/null +++ b/integration_tests/test_set_remove.py @@ -0,0 +1,47 @@ +from lpython import i32 + +def test_set_add(): + s1: set[i32] + s2: set[tuple[i32, tuple[i32, i32], str]] + s3: set[str] + st1: str + i: i32 + j: i32 + k: i32 + + for k in range(2): + s1 = {0} + s2 = {(0, (1, 2), 'a')} + for i in range(20): + j = i % 10 + s1.add(j) + s2.add((j, (j + 1, j + 2), 'a')) + + for i in range(10): + s1.remove(i) + s2.remove((i, (i + 1, i + 2), 'a')) + # assert len(s1) == 10 - 1 - i + # assert len(s1) == len(s2) + + st1 = 'a' + s3 = {st1} + for i in range(20): + s3.add(st1) + if i < 10: + if i > 0: + st1 += 'a' + + st1 = 'a' + for i in range(10): + s3.remove(st1) + assert len(s3) == 10 - 1 - i + if i < 10: + st1 += 'a' + + for i in range(20): + s1.add(i) + if i % 2 == 0: + s1.remove(i) + assert len(s1) == (i + 1) // 2 + +test_set_add() \ No newline at end of file diff --git a/integration_tests/test_statistics.py b/integration_tests/test_statistics_01.py similarity index 64% rename from integration_tests/test_statistics.py rename to integration_tests/test_statistics_01.py index f6bb522899..3eeddeed6a 100644 --- a/integration_tests/test_statistics.py +++ b/integration_tests/test_statistics_01.py @@ -1,7 +1,6 @@ from statistics import (mean, fmean, geometric_mean, harmonic_mean, variance, - stdev, pvariance, pstdev, correlation, covariance, - linear_regression, mode) -from ltypes import i32, f64, i64, f32 + stdev, pvariance, pstdev, mode) +from lpython import i32, f64, i64 eps: f64 @@ -126,69 +125,6 @@ def test_pstdev(): k = pstdev(b) assert abs(k - 0.37537181567080935) < eps - -def test_covariance(): - a: list[i32] - a = [1, 2, 3, 4, 5, 6, 7, 8, 9] - b: list[i32] - b = [1, 2, 3, 1, 2, 3, 1, 2, 3] - j: f64 - j = covariance(a, b) - assert abs(j - 0.75) < eps - - c: list[f64] - c = [2.74, 1.23, 2.63, 2.22, 3.0, 1.98] - d: list[f64] - d = [9.4, 1.23, 2.63, 22.4, 1.9, 13.98] - k: f64 - k = covariance(c, d) - assert abs(k + 0.24955999999999934) < eps - - -def test_correlation(): - a: list[i32] - a = [11, 2, 7, 4, 15, 6, 10, 8, 9, 1, 11, 5, 13, 6, 15] - b: list[i32] - b = [2, 5, 17, 6, 10, 8, 13, 4, 6, 9, 11, 2, 5, 4, 7] - - j: f64 - j = correlation(a, b) - assert abs(j - 0.11521487988958108) < eps - - c: list[f64] - c = [2.0, 23.0, 24.55, 64.436, 5403.23] - d: list[f64] - d = [26.9, 75.6, 34.06, 356.89, 759.26] - - j = correlation(c, c) - assert abs(j - 1.0) < eps - - j = correlation(c, d) - assert abs(j - 0.9057925526720572) < eps - -def test_linear_regression(): - c: list[f64] - c = [2.74, 1.23, 2.63, 2.22, 3.0, 1.98] - d: list[f64] - d = [9.4, 1.23, 2.63, 22.4, 1.9, 13.98] - - slope: f64 - intercept: f64 - slope, intercept = linear_regression(c, d) - - assert abs(slope + 0.6098133124816717) < eps - assert abs(intercept - 9.992570618707845) < eps - - a: list[i32] - b: list[i32] - a = [12, 24, 2, 1, 43, 53, 23] - b = [2, 13, 14, 63, 49, 7, 3] - - slope, intercept = linear_regression(a, b) - - assert abs(slope + 0.18514007308160782) < eps - assert abs(intercept - 25.750304506699152) < eps - def test_mode(): a: list[i32] a = [3, 1, 12, 4, 0] @@ -228,9 +164,6 @@ def check(): test_stdev() test_pvariance() test_pstdev() - test_linear_regression() - test_correlation() - test_covariance() test_mode() check() diff --git a/integration_tests/test_statistics_02.py b/integration_tests/test_statistics_02.py new file mode 100644 index 0000000000..0930c095a5 --- /dev/null +++ b/integration_tests/test_statistics_02.py @@ -0,0 +1,77 @@ +from statistics import (covariance, correlation, + linear_regression) +from lpython import i32, f64 + + +eps: f64 +eps = 1e-12 + +def test_covariance(): + a: list[i32] + a = [1, 2, 3, 4, 5, 6, 7, 8, 9] + b: list[i32] + b = [1, 2, 3, 1, 2, 3, 1, 2, 3] + j: f64 + j = covariance(a, b) + assert abs(j - 0.75) < eps + + c: list[f64] + c = [2.74, 1.23, 2.63, 2.22, 3.0, 1.98] + d: list[f64] + d = [9.4, 1.23, 2.63, 22.4, 1.9, 13.98] + k: f64 + k = covariance(c, d) + assert abs(k + 0.24955999999999934) < eps + + +def test_correlation(): + a: list[i32] + a = [11, 2, 7, 4, 15, 6, 10, 8, 9, 1, 11, 5, 13, 6, 15] + b: list[i32] + b = [2, 5, 17, 6, 10, 8, 13, 4, 6, 9, 11, 2, 5, 4, 7] + + j: f64 + j = correlation(a, b) + assert abs(j - 0.11521487988958108) < eps + + c: list[f64] + c = [2.0, 23.0, 24.55, 64.436, 5403.23] + d: list[f64] + d = [26.9, 75.6, 34.06, 356.89, 759.26] + + j = correlation(c, c) + assert abs(j - 1.0) < eps + + j = correlation(c, d) + assert abs(j - 0.9057925526720572) < eps + +def test_linear_regression(): + c: list[f64] + c = [2.74, 1.23, 2.63, 2.22, 3.0, 1.98] + d: list[f64] + d = [9.4, 1.23, 2.63, 22.4, 1.9, 13.98] + + slope: f64 + intercept: f64 + slope, intercept = linear_regression(c, d) + + assert abs(slope + 0.6098133124816717) < eps + assert abs(intercept - 9.992570618707845) < eps + + a: list[i32] + b: list[i32] + a = [12, 24, 2, 1, 43, 53, 23] + b = [2, 13, 14, 63, 49, 7, 3] + + slope, intercept = linear_regression(a, b) + + assert abs(slope + 0.18514007308160782) < eps + assert abs(intercept - 25.750304506699152) < eps + + +def check(): + test_linear_regression() + test_correlation() + test_covariance() + +check() diff --git a/integration_tests/test_str_01.py b/integration_tests/test_str_01.py index 014b798fca..0a65e8d075 100644 --- a/integration_tests/test_str_01.py +++ b/integration_tests/test_str_01.py @@ -1,3 +1,5 @@ +from lpython import i32 + def f(): x: str x = "ok" @@ -37,17 +39,161 @@ def test_str_slice(): # TODO: # assert a[0:5:-1] == "" + +def test_str_title(): + a: str = "hello world" + b: str = "hj'kl" + c: str = "hELlo wOrlD" + d: str = "{Hel1o}world" + res: str = a.title() + res2: str = b.title() + res3: str = c.title() + res4: str = d.title() + assert res == "Hello World" + assert res2 == "Hj'Kl" + assert res3 == "Hello World" + assert res4 == "{Hel1O}World" + def test_str_repeat(): a: str a = "Xyz" assert a*3 == "XyzXyzXyz" assert a*2*3 == "XyzXyzXyzXyzXyzXyz" assert 3*a*3 == "XyzXyzXyzXyzXyzXyzXyzXyzXyz" - assert a*-1 == "" + b: str = a * -1 + assert b == "" + assert len(a*(10**6)) == (3 * 10 ** 6) + + # string repeat with a non-constant integer + s: str = "#" + n: i32 = 5 + + assert s * n == "#####" + assert n * s == "#####" + + assert "@" * n == "@@@@@" + assert "@#$%" * n == "@#$%@#$%@#$%@#$%@#$%" + + s = "@#$%" + assert n * s == "@#$%@#$%@#$%@#$%@#$%" + + n = 10 ** 6 + assert len(s * n) == (4 * 10 ** 6) + + s = "$" + m: i32 = 2 + n = 5 + t: str = s * m * n + assert t == "$$$$$$$$$$" + assert s * m * 2 == "$$$$" + assert 2 * (m + n) * s == "$$$$$$$$$$$$$$" + + t = 2 * (m + n) * "abc-" + assert t == "abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-" + + +# def test_str_join(): +# a: str +# a = "," +# p:list[str] = ["a","b"] +# res:str = a.join(p) +# assert res == "a,b" +# +# def test_str_join2(): +# a: str +# a = "**" +# p:list[str] = ["a","b"] +# res:str = a.join(p) +# assert res == "a**b" +# +# def test_str_join_empty_str(): +# a: str +# a = "" +# p:list[str] = ["a","b"] +# res:str = a.join(p) +# assert res == "ab" +# +# def test_str_join_empty_list(): +# a: str +# a = "ab" +# p:list[str] = [] +# res:str = a.join(p) +# assert res == "" +# +# def test_constant_str_subscript(): +# assert "abc"[2] == "c" +# assert "abc"[:2] == "ab" +# +# def test_str_split(): +# a: str = "1,2,3" +# b: str = "1,2,,3," +# c: str = "1and2and3" +# d: str = "1 2 3" +# e: str = " 1 2 3 " +# f: str = "123" +# res: list[str] = a.split(",") +# res1: list[str] = b.split(",") +# res2: list[str] = c.split("and") +# res3: list[str] = d.split() +# res4: list[str] = e.split() +# res5: list[str] = f.split(" ") +# # res6: list[str] = "".split(" ") +# assert res == ["1", "2", "3"] +# assert res1 == ["1", "2", "", "3", ""] +# assert res2 == ["1", "2", "3"] +# assert res3 == ["1", "2", "3"] +# assert res4 == ["1", "2", "3"] +# assert res5 == ["123"] +# # assert res6 == [""] + +def test_str_replace(): + x: str = "abc" + a: str = "zzaaabracadabra" + print(a.replace("a","")) + print(a.replace("","")) + print(a.replace("a","b")) + print(a.replace("e","a")) + print(a.replace("ab","ba")) + print(a.replace("c","z")) + print(a.replace("zza","yo")) + print(a.replace("a","b",0)) + print(a.replace("a","b",1)) + print(a.replace("a","b",2)) + print(a.replace("a","b",2)) + print(a.replace("a","b",3)) + print(a.replace("a","b",4)) + print(a.replace("a","b",5)) + print(a.replace("a","b",6)) + print(a.replace("a","b",7)) + print(a.replace("a","b",8)) + print(a.replace("a","b",9)) + print(a.replace("b","k",1)) + print(a.replace("b","k",2)) + print(a.replace("zza","yo",2)) + print(x.replace("", ",")) + assert a.replace("a","") == "zzbrcdbr" + assert a.replace("","") == "zzaaabracadabra" + assert a.replace("a","b") == "zzbbbbrbcbdbbrb" + assert a.replace("e","a") == "zzaaabracadabra" + assert a.replace("ab","ba") == "zzaabaracadbara" + assert a.replace("c","z") == "zzaaabrazadabra" + assert a.replace("zza","yo") == "yoaabracadabra" + assert a.replace("a","b",0) == "zzaaabracadabra" + assert a.replace("a","b",1) == "zzbaabracadabra" + assert a.replace("a","b",2) == "zzbbabracadabra" + assert a.replace("a","b",2) == "zzbbabracadabra" + assert a.replace("a","b",3) == "zzbbbbracadabra" + assert a.replace("a","b",4) == "zzbbbbrbcadabra" + assert a.replace("a","b",5) == "zzbbbbrbcbdabra" + assert a.replace("a","b",6) == "zzbbbbrbcbdbbra" + assert a.replace("a","b",7) == "zzbbbbrbcbdbbrb" + assert a.replace("a","b",8) == "zzbbbbrbcbdbbrb" + assert a.replace("a","b",9) == "zzbbbbrbcbdbbrb" + assert a.replace("b","k",1) == "zzaaakracadabra" + assert a.replace("b","k",2) == "zzaaakracadakra" + assert a.replace("zza","yo",2) == "yoaabracadabra" + assert x.replace("", ",") == ",a,b,c," -def test_constant_str_subscript(): - assert "abc"[2] == "c" - assert "abc"[:2] == "ab" def check(): f() @@ -55,6 +201,13 @@ def check(): test_str_index() test_str_slice() test_str_repeat() - test_constant_str_subscript() +# test_str_join() +# test_str_join2() +# test_str_join_empty_str() +# test_str_join_empty_list() +# test_constant_str_subscript() +# test_str_title() +# test_str_split() + test_str_replace() check() diff --git a/integration_tests/test_str_03.py b/integration_tests/test_str_03.py index 37f96c7632..5dd91d3d35 100644 --- a/integration_tests/test_str_03.py +++ b/integration_tests/test_str_03.py @@ -1,4 +1,4 @@ -from ltypes import i8, i16, i32, i64 +from lpython import i8, i16, i32, i64 def test_new_line(): print("abc\n") diff --git a/integration_tests/test_str_04.py b/integration_tests/test_str_04.py new file mode 100644 index 0000000000..c0ede7991f --- /dev/null +++ b/integration_tests/test_str_04.py @@ -0,0 +1,11 @@ +def main0(): + x: str + x = "abcdefghijkl" + print(len(x)) + assert len(x) == 12 + + y: str = "123" + print(len(y)) + assert len(y) == 3 + +main0() diff --git a/integration_tests/test_str_05.py b/integration_tests/test_str_05.py new file mode 100644 index 0000000000..e3eef630b2 --- /dev/null +++ b/integration_tests/test_str_05.py @@ -0,0 +1,12 @@ +def main0(): + x: str + x = "Hello, World" + y: str + y = "o" + assert x.count(y) == 2 + y = "" + assert x.count(y) == len(x) + 1 + y = "Hello," + assert x.count(y) == 1 + +main0() diff --git a/integration_tests/test_str_06.py b/integration_tests/test_str_06.py new file mode 100644 index 0000000000..8df130521d --- /dev/null +++ b/integration_tests/test_str_06.py @@ -0,0 +1,11 @@ +def main0(): + x: str + x = "Hello, World" + + assert "Hello" in x + assert "," in x + assert "rld" in x + + assert "Hello" not in "World" + +main0() diff --git a/integration_tests/test_str_attributes.py b/integration_tests/test_str_attributes.py old mode 100644 new mode 100755 index 6a9c0885e7..b8b24cf8fa --- a/integration_tests/test_str_attributes.py +++ b/integration_tests/test_str_attributes.py @@ -1,13 +1,20 @@ def capitalize(): s: str s = "tom and jerry" + print(s.capitalize()) assert s.capitalize() == "Tom and jerry" s = "12wddd" + print(s) assert s.capitalize() == s s = " tom and jerry" + print(s.capitalize()) assert s.capitalize() == s assert "empty string" .capitalize() == "Empty string" assert "".capitalize() == "" + assert "lPyThOn".capitalize() == "Lpython" + x: str + x = "lPyThOn" + assert x.capitalize() == "Lpython" def lower(): @@ -18,6 +25,14 @@ def lower(): assert "".lower() == "" +def upper(): + s: str + s = "AaaaAABBbbbbBB!@12223BN" + assert s.upper() == "AAAAAABBBBBBBB!@12223BN" + assert "DDd12Vv".upper() == "DDD12VV" + assert "".upper() == "" + + def strip(): s: str s = " AASAsaSas " @@ -59,6 +74,29 @@ def find(): assert s2.find("we") == -1 assert "".find("") == 0 +def count(): + s: str + sub: str + s = "ABC ABCDAB ABCDABCDABDE" + sub = "ABC" + print(s.count(sub), s.count("ABC")) + assert s.count(sub) == 4 + assert s.count("ABC") == 4 + + sub = "AB" + print(s.count(sub), s.count("AB")) + assert s.count(sub) == 6 + assert s.count("AB") == 6 + + sub = "ABC" + print("ABC ABCDAB ABCDABCDABDE".count(sub), "ABC ABCDAB ABCDABCDABDE".count("ABC")) + assert "ABC ABCDAB ABCDABCDABDE".count(sub) == 4 + assert "ABC ABCDAB ABCDABCDABDE".count("ABC") == 4 + + sub = "AB" + assert "ABC ABCDAB ABCDABCDABDE".count(sub) == 6 + assert "ABC ABCDAB ABCDABCDABDE".count("AB") == 6 + def startswith(): s: str @@ -78,14 +116,15 @@ def startswith(): assert s.startswith("sdd") == False assert "".startswith("ok") == False + def endswith(): # The following test suite fulfils the control flow graph coverage # in terms of Statement Coverage and Branch Coverage associated with endwith() functionality. - # Case 1: When string is constant and suffix is also constant + # Case 1: When string is constant and suffix is also constant assert "".endswith("") == True - assert "".endswith(" ") == False + assert "".endswith(" ") == False assert "".endswith("%") == False assert "".endswith("a1234PT#$") == False assert "".endswith("blah blah") == False @@ -95,13 +134,12 @@ def endswith(): assert " rendezvous 5:30 ".endswith("apple") == False assert "two plus".endswith("longer than string") == False - # Case 2: When string is constant and suffix is variable suffix: str suffix = "" assert "".endswith(suffix) == True suffix = " " - assert "".endswith(suffix) == False + assert "".endswith(suffix) == False suffix = "5:30 " assert " rendezvous 5:30 ".endswith(suffix) == True suffix = "" @@ -128,13 +166,359 @@ def endswith(): suffix = "apple" assert s.endswith(suffix) == False + +def partition(): + + # Note: Both string or seperator cannot be empty + # Case 1: When string is constant and seperator is also constant + assert " ".partition(" ") == ("", " ", " ") + assert "apple mango".partition(" ") == ("apple", " ", "mango") + assert "applemango".partition("afdnjkfsn") == ("applemango", "", "") + assert "applemango".partition("an") == ("applem", "an", "go") + assert "applemango".partition("mango") == ("apple", "mango", "") + assert "applemango".partition("applemango") == ("", "applemango", "") + assert "applemango".partition("ppleman") == ("a", "ppleman", "go") + assert "applemango".partition("pplt") == ("applemango", "", "") + + # Case 2: When string is constant and seperator is variable + seperator: str + seperator = " " + assert " ".partition(seperator) == ("", " ", " ") + seperator = " " + assert "apple mango".partition(seperator) == ("apple", " ", "mango") + seperator = "5:30 " + assert " rendezvous 5:30 ".partition( + seperator) == (" rendezvous ", "5:30 ", "") + seperator = "^&" + assert "@#$%^&*()#!".partition(seperator) == ("@#$%", "^&", "*()#!") + seperator = "daddada " + assert " rendezvous 5:30 ".partition( + seperator) == (" rendezvous 5:30 ", "", "") + seperator = "longer than string" + assert "two plus".partition(seperator) == ("two plus", "", "") + + # Case 3: When string is variable and seperator is either constant or variable + s: str + s = "tomorrow" + assert s.partition("apple") == ("tomorrow", "", "") + assert s.partition("rr") == ("tomo", "rr", "ow") + assert s.partition(seperator) == ("tomorrow", "", "") + + s = "rendezvous 5" + assert s.partition(" ") == ("rendezvous", " ", "5") + assert s.partition("5") == ("rendezvous ", "5", "") + assert s.partition(s) == ("", "rendezvous 5", "") + seperator = "vous " + assert s.partition(seperator) == ("rendez", "vous ", "5") + seperator = "apple" + assert s.partition(seperator) == ("rendezvous 5", "", "") + + +def is_lower(): + # Case 1: When constant string is present + assert "".islower() == False + assert "APPLE".islower() == False + assert "4432632479".islower() == False + assert "%#$#$#32a".islower() == True + assert "apple".islower() == True + assert "apple is a fruit".islower() == True + + # Case 2: When variable string is present + s: str + s = "APPLE" + assert s.islower() == False + s = "238734587" + assert s.islower() == False + s = "%#$#$#32a" + assert s.islower() == True + s = "apple" + assert s.islower() == True + s = "apple is a fruit" + assert s.islower() == True + + +def is_upper(): + # Case 1: When constant string is present + assert "".isupper() == False + assert "apple".isupper() == False + assert "4432632479".isupper() == False + assert "%#$#$#32A".isupper() == True + assert "APPLE".isupper() == True + assert "APPLE IS A FRUIT".isupper() == True + + # Case 2: When variable string is present + s: str + s = "apple" + assert s.isupper() == False + s = "238734587" + assert s.isupper() == False + s = "%#$#$#32A" + assert s.isupper() == True + s = "APPLE" + assert s.isupper() == True + s = "APPLE IS A FRUIT" + assert s.isupper() == True + + +def is_decimal(): + # Case 1: When constant string is present + assert "".isdecimal() == False + assert "apple".isdecimal() == False + assert "4432632479".isdecimal() == True + assert "%#$#$#32A".isdecimal() == False + assert "1.25".isdecimal() == False + assert "-325".isdecimal() == False + assert "12 35".isdecimal() == False + + # Case 2: When variable string is present + s: str + s = "apple" + assert s.isdecimal() == False + s = "238734587" + assert s.isdecimal() == True + s = "%#$#$#32A" + assert s.isdecimal() == False + s = "1.35" + assert s.isdecimal() == False + s = "-42556" + assert s.isdecimal() == False + s = "12 34" + assert s.isdecimal() == False + + +def is_ascii(): + # Case 1: When constant string is present + assert "".isascii() == True + assert " ".isascii() == True + assert "Hello, World123!".isascii() == True + assert "Hëllö, Wörld!".isascii() == False + assert "This is a test string with some non-ASCII characters: 🚀".isascii() == False + assert "\t\n\r".isascii() == True + assert "12 35".isascii() == True + + # # Case 2: When variable string is present + s: str + s = " " + assert s.isascii() == True + s = "Hello, World!" + assert s.isascii() == True + s = "Hëllö, Wörld!" + assert s.isascii() == False + s = "This is a test string with some non-ASCII characters: 🚀" + assert s.isascii() == False + s = "\t\n\r" + assert s.isascii() == True + s = "123 45 6" + assert s.isascii() == True + + +def is_alpha(): + a: str = "helloworld" + b: str = "hj kl" + c: str = "a12(){}A" + d: str = " " + e: str = "" + res: bool = a.isalpha() + res2: bool = b.isalpha() + res3: bool = c.isalpha() + res4: bool = d.isalpha() + res5: bool = e.isalpha() + assert res == True + assert res2 == False + assert res3 == False + assert res4 == False + assert res5 == False + + assert "helloworld".isalpha() == True + assert "hj kl".isalpha() == False + assert "a12(){}A".isalpha() == False + assert " ".isalpha() == False + assert "".isalpha() == False + + +def is_title(): + a: str = "Hello World" + b: str = "Hj'kl" + c: str = "hELlo wOrlD" + d: str = " Hello" + e: str = " " + res: bool = a.istitle() + res2: bool = b.istitle() + res3: bool = c.istitle() + res4: bool = d.istitle() + res5: bool = e.istitle() + assert res == True + assert res2 == False + assert res3 == False + assert res4 == True + assert res5 == False + + assert "Hello World".istitle() == True + assert "Hj'kl".istitle() == False + assert "hELlo wOrlD".istitle() == False + assert " Hello".istitle() == True + assert " ".istitle() == False + +def is_space(): + s0: str = "" + assert s0.isspace() == False + assert "".isspace() == False + + s1: str = " \t\n\v\f\r" + assert s1.isspace() == True + assert " \t\n\v\f\r".isspace() == True + + s2: str = " \t\n\v\f\rabcd" + assert s2.isspace() == False + assert " \t\n\v\f\rabcd".isspace() == False + + s3: str = "abcd \t\n\v\f\ref" + assert s3.isspace() == False + assert "abcd \t\n\v\f\ref".isspace() == False + + s4: str = " \\t\n\v\f\r" + assert s4.isspace() == False + assert " \\t\n\v\f\r".isspace() == False + + s5: str = " \\t\\n\\v\\f\\r" + assert s5.isspace() == False + assert " \\t\\n\\v\\f\\r".isspace() == False + + s6: str = "Hello, LPython!\n" + assert s6.isspace() == False + assert "Hello, LPython!\n".isspace() == False + + s7: str = "\t\tHello! \n" + assert s7.isspace() == False + assert "\t\tHello! \n".isspace() == False + + s8: str = " \t \n \v \f \r " + assert s8.isspace() == True + assert " \t \n \v \f \r ".isspace() == True + + assert "\n".isspace() == True + assert " ".isspace() == True + assert "\r".isspace() == True + assert "".isspace() == False + + s: str = " " + assert s.isspace() == True + s = "a" + assert s.isspace() == False + s = "" + assert s.isspace() == False + +def is_alnum(): + a: str = "helloworld" + b: str = "hj kl" + c: str = "a12(){}A" + d: str = " " + e: str = "" + f: str = "ab23" + g: str = "ab2%3" + res: bool = a.isalnum() + res2: bool = b.isalnum() + res3: bool = c.isalnum() + res4: bool = d.isalnum() + res5: bool = e.isalnum() + res6: bool = f.isalnum() + res7: bool = g.isalnum() + + assert res == True + assert res2 == False + assert res3 == False + assert res4 == False + assert res5 == False + assert res6 == True + assert res7 == False + + assert "helloworld".isalnum() == True + assert "hj kl".isalnum() == False + assert "a12(){}A".isalnum() == False + assert " ".isalnum() == False + assert "".isalnum() == False + assert "ab23".isalnum() == True + assert "ab2%3".isalnum() == False + +def is_numeric(): + a: str = "123" + b: str = "12 34" + c: str = "-123" + d: str = "12.3" + e: str = " " + f: str = "" + g: str = "ab2%3" + res: bool = a.isnumeric() + res2: bool = b.isnumeric() + res3: bool = c.isnumeric() + res4: bool = d.isnumeric() + res5: bool = e.isnumeric() + res6: bool = f.isnumeric() + res7: bool = g.isnumeric() + + assert res == True + assert res2 == False + assert res3 == False + assert res4 == False + assert res5 == False + assert res6 == False + assert res7 == False + + assert "123".isnumeric() == True + assert "12 34".isnumeric() == False + assert "-123".isnumeric() == False + assert "12.3".isnumeric() == False + assert " ".isnumeric() == False + assert "".isnumeric() == False + assert "ab2%3".isnumeric() == False + +def center(): + s: str = "test" + assert s.center(8,'*') == "**test**" + assert s.center(11) == " test " + assert s.center(2) == "test" + assert s.center(4) == "test" + assert s.center(9,'/') == "///test//" + +def expandtabs(): + s: str = '01\t012\t0123\t01234' + assert s.expandtabs() == "01 012 0123 01234" + assert s.expandtabs(4) == "01 012 0123 01234" + assert s.expandtabs(-1) == "01012012301234" + s = '\t' + assert s.expandtabs() == " " + s = '' + assert s.expandtabs() == "" + s = '\tThis\ris\na\ttest' + assert s.expandtabs(4) == " This\ris\na test" + s = '\t\t\t' + assert s.expandtabs(2) == " " + s = 'test\ttest' + assert s.expandtabs(0) == "testtest" + assert s.expandtabs(-5) == "testtest" + def check(): capitalize() lower() + upper() strip() swapcase() find() + count() startswith() endswith() + partition() + is_lower() + is_upper() + is_decimal() + is_ascii() + is_alpha() + is_title() + is_space() + is_alnum() + is_numeric() + center() + expandtabs() + check() diff --git a/integration_tests/test_str_comparison.py b/integration_tests/test_str_comparison.py index 4ac40aaa78..3108c224e0 100644 --- a/integration_tests/test_str_comparison.py +++ b/integration_tests/test_str_comparison.py @@ -5,18 +5,18 @@ def f(): assert s1 <= s2 assert s1 >= s2 s1 = "abcde" - assert s1 >= s2 + assert s1 >= s2 assert s1 > s2 s1 = "abc" - assert s1 < s2 + assert s1 < s2 assert s1 <= s2 s1 = "Abcd" s2 = "abcd" - assert s1 < s2 + assert s1 < s2 s1 = "orange" s2 = "apple" - assert s1 >= s2 - assert s1 > s2 + assert s1 >= s2 + assert s1 > s2 s1 = "albatross" s2 = "albany" assert s1 >= s2 @@ -28,9 +28,11 @@ def f(): assert s1 < s2 assert s1 != s2 s1 = "Zebra" - s2 = "ant" + s2 = "ant" assert s1 <= s2 assert s1 < s2 assert s1 != s2 + print("Ok") + f() diff --git a/integration_tests/test_str_to_int.py b/integration_tests/test_str_to_int.py index 374ca141f0..3c94dea4b9 100644 --- a/integration_tests/test_str_to_int.py +++ b/integration_tests/test_str_to_int.py @@ -1,4 +1,4 @@ -from ltypes import i32 +from lpython import i32 def f(): i: i32 @@ -20,4 +20,12 @@ def f(): i = i32(int(s)) assert i == -1234 + assert i32(int("01010",10)) == 1010 + assert i32(int("01010",2)) == 10 + assert i32(int("Beef",16)) == 48879 + assert i32(int("0xE",16)) == 14 + assert i32(int("0xE",0)) == 14 + assert i32(int("123",0)) == 123 + assert i32(int("0bE",16)) == 190 + f() diff --git a/integration_tests/test_string_01.py b/integration_tests/test_string_01.py new file mode 100644 index 0000000000..0e0fef30de --- /dev/null +++ b/integration_tests/test_string_01.py @@ -0,0 +1,9 @@ +from string import ascii_lowercase, ascii_letters + +def test_string(): + assert ascii_lowercase == 'abcdefghijklmnopqrstuvwxyz' + assert ascii_letters == 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' + + print(ascii_lowercase) + +test_string() \ No newline at end of file diff --git a/integration_tests/test_sys_01.py b/integration_tests/test_sys_01.py new file mode 100644 index 0000000000..e15e0b4503 --- /dev/null +++ b/integration_tests/test_sys_01.py @@ -0,0 +1,2 @@ +import sys +sys.exit(0) diff --git a/integration_tests/test_tuple_01.py b/integration_tests/test_tuple_01.py index fdafb23b4e..726f7d0e18 100644 --- a/integration_tests/test_tuple_01.py +++ b/integration_tests/test_tuple_01.py @@ -1,4 +1,4 @@ -from ltypes import i32, f64 +from lpython import i32, f64 def f(): t1: tuple[i32, f64, str, bool] = (1, 2.0, "3", True) diff --git a/integration_tests/test_tuple_02.py b/integration_tests/test_tuple_02.py index b2218288a5..85dc88381f 100644 --- a/integration_tests/test_tuple_02.py +++ b/integration_tests/test_tuple_02.py @@ -1,4 +1,4 @@ -from ltypes import i32, f64, c64 +from lpython import i32, f64, c64 def set_tuple(a: i32, b: f64) -> tuple[i32, f64, str, c64]: t: tuple[i32, f64, str, c64] diff --git a/integration_tests/test_tuple_03.py b/integration_tests/test_tuple_03.py index a2ba5f9543..affd983008 100644 --- a/integration_tests/test_tuple_03.py +++ b/integration_tests/test_tuple_03.py @@ -1,4 +1,4 @@ -from ltypes import i32, f64 +from lpython import i32, f64 def f(): t1: tuple[i32, f64, str] = (1, 2.0, "3") diff --git a/integration_tests/test_tuple_04.py b/integration_tests/test_tuple_04.py new file mode 100644 index 0000000000..393dc51ad0 --- /dev/null +++ b/integration_tests/test_tuple_04.py @@ -0,0 +1,11 @@ +from lpython import i32 + +# issue 2041 +ttype : tuple[list[i32], str] = ([-1], 'dimensions') +contents : tuple[list[i32], str] = ([1, 2], '') + +assert ttype[0] == [-1] +assert len(ttype[0]) == 1 +assert contents[0] == [1, 2] +assert len(contents[1]) == 0 +assert ttype[1] == 'dimensions' diff --git a/integration_tests/test_tuple_concat.py b/integration_tests/test_tuple_concat.py new file mode 100644 index 0000000000..8d09d12593 --- /dev/null +++ b/integration_tests/test_tuple_concat.py @@ -0,0 +1,42 @@ +from lpython import i32, f64 + +def test_tuple_concat(): + t1: tuple[i32, i32] + t2: tuple[f64, str, i32] + t3: tuple[f64] + t4: tuple[i32, i32, f64, str, i32, f64] + t5: tuple[i32, f64] + t6: tuple[i32, f64, i32, f64] + t7: tuple[i32, f64, i32, f64, i32, f64] + t8: tuple[i32, f64, i32, f64, i32, f64, i32, f64] + l1: list[tuple[i32, f64]] = [] + start: i32 + i:i32 + t9: tuple[tuple[tuple[i32, i32], tuple[i32, f64]], tuple[f64, str, i32]] + + t1 = (1, 2) + t2 = (3.0, "abc", -10) + t3 = (10.0,) + t4 = t1 + t2 + t3 + assert t4 == (t1[0], t1[1], t2[0], t2[1], t2[2], t3[0]) + assert t4 + t3 == t1 + t2 + t3 + (t3[0],) + + start = 117 + for i in range(start, start + 3): + t5 = (i, f64(i*i)) + l1.append(t5) + if i == start: + t6 = t5 + l1[-1] + elif i == start + 1: + t7 = t6 + l1[-1] + else: + t8 = t7 + l1[-1] + + assert t6 == l1[0] + l1[0] + assert t7 == t6 + l1[1] + assert t8 == t7 + l1[2] + + t9 = ((t1, t5),) + (t2,) + assert t9[0][0] == t1 and t9[0][1] == t5 and t9[1] == t2 + +test_tuple_concat() \ No newline at end of file diff --git a/integration_tests/test_tuple_nested.py b/integration_tests/test_tuple_nested.py new file mode 100644 index 0000000000..e10ea1b091 --- /dev/null +++ b/integration_tests/test_tuple_nested.py @@ -0,0 +1,35 @@ +from lpython import i32, f64 + +def test_tuple_nested(): + t1: tuple[i32, i32] = (-1, -2) + t2: tuple[i32, i32] = (-3, -4) + t3: tuple[tuple[i32, i32], tuple[i32, i32], tuple[i32, i32], tuple[i32, i32]] + t4: tuple[i32, f64, str] + t5: tuple[tuple[i32, f64, str], i32] + t6: tuple[tuple[tuple[i32, f64, str], i32], f64] + t7: tuple[tuple[i32, i32], tuple[list[i32], list[str]]] + l1: list[tuple[i32, f64, tuple[f64, i32]]] = [] + i: i32 + s: str + + t3 = (t1, t2, t1, t2) + assert t3[0] == t1 and t3[1] == t2 + assert t3[2] == t1 and t3[3] == t2 + + t4 = (1, 2.0, 'abc') + t5 = (t4, 3) + assert t5 == ((1, 2.0, 'abc'), 3) + t6 = (t5, 4.0) + assert t6 == ((t4, 3), 4.0) + + for i in range(5): + l1.append((i, f64(i+1), (f64(i+2), i+3))) + for i in range(5): + assert l1[i] == (i, f64(i+1), (f64(i+2), i+3)) + + i = 3 + s = 'a' + t7 = (t1, ([i, i+1, i+2], [s, s * 2, s * 3])) + assert t7 == ((-1, -2), ([3, 4, 5], ['a', 'aa', 'aaa'])) + +test_tuple_nested() \ No newline at end of file diff --git a/integration_tests/test_types_01.py b/integration_tests/test_types_01.py index 1894ebe961..ee4c1e9169 100644 --- a/integration_tests/test_types_01.py +++ b/integration_tests/test_types_01.py @@ -1,4 +1,4 @@ -from ltypes import i8, i16, i32, i64 +from lpython import i8, i16, i32, i64 def test_i8(): i: i8 diff --git a/integration_tests/test_types_02.py b/integration_tests/test_types_02.py new file mode 100644 index 0000000000..68d338dc94 --- /dev/null +++ b/integration_tests/test_types_02.py @@ -0,0 +1,10 @@ +from lpython import i32, f64 + +def main0(): + a: f64 + a = 3.25 + b: i32 = i32(a) * 4 + print(b) + assert b == 12 + +main0() diff --git a/integration_tests/test_unary_minus.py b/integration_tests/test_unary_op_01.py similarity index 83% rename from integration_tests/test_unary_minus.py rename to integration_tests/test_unary_op_01.py index 02de00715f..08182832f1 100644 --- a/integration_tests/test_unary_minus.py +++ b/integration_tests/test_unary_op_01.py @@ -1,4 +1,4 @@ -from ltypes import i32, f64 +from lpython import i32, f64 def f(): eps: f64 diff --git a/integration_tests/test_unary_plus.py b/integration_tests/test_unary_op_02.py similarity index 91% rename from integration_tests/test_unary_plus.py rename to integration_tests/test_unary_op_02.py index 7067c03639..396b8e07cc 100644 --- a/integration_tests/test_unary_plus.py +++ b/integration_tests/test_unary_op_02.py @@ -1,4 +1,4 @@ -from ltypes import i32, f64, c32 +from lpython import i32, f64, c32 def f(): eps: f64 diff --git a/integration_tests/test_integer_bitnot.py b/integration_tests/test_unary_op_03.py similarity index 83% rename from integration_tests/test_integer_bitnot.py rename to integration_tests/test_unary_op_03.py index 2c12e8ecf4..48ba56fe5b 100644 --- a/integration_tests/test_integer_bitnot.py +++ b/integration_tests/test_unary_op_03.py @@ -1,4 +1,4 @@ -from ltypes import i32 +from lpython import i32 def f(): i: i32 diff --git a/integration_tests/test_unary_op_04.py b/integration_tests/test_unary_op_04.py new file mode 100644 index 0000000000..a320617ba7 --- /dev/null +++ b/integration_tests/test_unary_op_04.py @@ -0,0 +1,19 @@ +from lpython import u16, bitnot_u16 + +def foo(grp: u16) -> u16: + i: u16 = bitnot_u16(grp) + return i + + +def foo2() -> u16: + i: u16 = bitnot_u16(u16(0xffff)) + return i + +def foo3() -> u16: + i: u16 = bitnot_u16(u16(0xffff)) + return bitnot_u16(i) + +assert foo(u16(0)) == u16(0xffff) +assert foo(u16(0xffff)) == u16(0) +assert foo2() == u16(0) +assert foo3() == u16(0xffff) diff --git a/integration_tests/test_unary_op_05.py b/integration_tests/test_unary_op_05.py new file mode 100644 index 0000000000..c480606591 --- /dev/null +++ b/integration_tests/test_unary_op_05.py @@ -0,0 +1,30 @@ +from lpython import u8, u16, u32, u64 + +def f(): + + h: u8 + h = u8(67) + print(+h) + assert +h == u8(67) + + i: u16 + i = u16(67) + print(+i) + assert +i == u16(67) + + j: u32 + j = u32(25) + print(+j) + assert +j == u32(25) + + k: u64 + k = u64(100000000000123) + print(+k) + assert +k == u64(100000000000123) + + assert -u8(0) == u8(0) + assert -u16(0) == u16(0) + assert -u32(0) == u32(0) + assert -u64(0) == u64(0) + +f() diff --git a/integration_tests/test_unary_op_06.py b/integration_tests/test_unary_op_06.py new file mode 100644 index 0000000000..212d7b1609 --- /dev/null +++ b/integration_tests/test_unary_op_06.py @@ -0,0 +1,35 @@ +from lpython import i32, i64, u16, u64, f32, f64 + +def f(): + + i: i32 + j: i64 + i = -67 + j = i64(0) + + print(i, j) + print(not i, not j) + assert (not i) == False + assert (not j) == True + + k: u16 + l: u64 + k = u16(0) + l = u64(55) + + print(k, l) + print(not k, not l) + assert (not k) == True + assert (not l) == False + + m: f32 + n: f64 + m = f32(0.0) + n = -3.14 + + print(m, n) + print(not m, not n) + assert (not m) == True + assert (not n) == False + +f() diff --git a/integration_tests/test_unsigned_01.py b/integration_tests/test_unsigned_01.py new file mode 100644 index 0000000000..44068cceb3 --- /dev/null +++ b/integration_tests/test_unsigned_01.py @@ -0,0 +1,37 @@ +from lpython import u8, u16, u32, u64 + +def f(): + + h: u8 + h = u8(5) + print(h << u8(4), h << u8(2), h >> u8(4), h >> u8(7)) + assert h << u8(4) == u8(80) + assert h << u8(2) == u8(20) + assert h >> u8(4) == u8(0) + assert h >> u8(7) == u8(0) + + i: u16 + i = u16(67) + print(i << u16(4), i << u16(7), i >> u16(4), i >> u16(7)) + assert i << u16(4) == u16(1072) + assert i << u16(7) == u16(8576) + assert i >> u16(4) == u16(4) + assert i >> u16(7) == u16(0) + + j: u32 + j = u32(25) + print(j << u32(4), j << u32(7), j >> u32(4), j >> u32(7)) + assert j << u32(4) == u32(400) + assert j << u32(7) == u32(3200) + assert j >> u32(4) == u32(1) + assert j >> u32(7) == u32(0) + + k: u64 + k = u64(100000000000123) + print(k << u64(4), k << u64(7), k >> u64(4), k >> u64(7)) + assert k << u64(4) == u64(1600000000001968) + assert k << u64(7) == u64(12800000000015744) + assert k >> u64(4) == u64(6250000000007) + assert k >> u64(7) == u64(781250000000) + +f() diff --git a/integration_tests/test_unsigned_02.py b/integration_tests/test_unsigned_02.py new file mode 100644 index 0000000000..ad7f938249 --- /dev/null +++ b/integration_tests/test_unsigned_02.py @@ -0,0 +1,15 @@ +from lpython import u16, i32, u8, u32, u64 + +# test issue 2170 + +u_1 : u16 = u16(32768) +u_2 : u8 = u8(24) +u_3 : u32 = u32(32768) +u_4 : u64 = u64(32768) + +assert u_1 == u16(32768) +assert u_2 == u8(24) +assert u_3 == u32(32768) +assert u_4 == u64(32768) + +print(u_1, u_2, u_3, u_4) diff --git a/integration_tests/test_unsigned_03.py b/integration_tests/test_unsigned_03.py new file mode 100644 index 0000000000..2bc0eaeac2 --- /dev/null +++ b/integration_tests/test_unsigned_03.py @@ -0,0 +1,19 @@ +from lpython import u16, i32, u8, u16, u64, i64, u32, i8 + +# test issue 2174 + +def f(): + u: u16 = u16(32768) + assert i32(u) == 32768 + u1: u8 = u8(23) + assert i8(u1) == i8(23) + assert u16(u1) == u16(23) + assert u32(u1) == u32(23) + assert u64(u1) == u64(23) + print(i8(u1), u16(u1), u32(u1), u64(u1)) + assert i64(u1) == i64(23) + assert i64(u) == i64(32768) + assert i32(u1) == 23 + print(i64(u), i32(u)) + +f() diff --git a/integration_tests/union_01.py b/integration_tests/union_01.py index 05cff1bf78..7fda2326df 100644 --- a/integration_tests/union_01.py +++ b/integration_tests/union_01.py @@ -1,4 +1,4 @@ -from ltypes import Union, i32, i64, f64, f32, ccall, union +from lpython import Union, i32, i64, f64, f32, ccall, union @ccall @union diff --git a/integration_tests/union_02.py b/integration_tests/union_02.py index dd693ef041..67cb4a3254 100644 --- a/integration_tests/union_02.py +++ b/integration_tests/union_02.py @@ -1,4 +1,4 @@ -from ltypes import i32, f64, i64, dataclass, ccall, union, Union +from lpython import i32, f64, i64, dataclass, ccall, union, Union @dataclass class A: @@ -19,9 +19,9 @@ class C: @ccall @union class D(Union): - a: A - b: B - c: C + a: A = A(0, 3.0) + b: B = B(i64(0), 2.0) + c: C = C(i64(0), 0.0, 1.0) def test_struct_union(): d: D = D() diff --git a/integration_tests/union_03.py b/integration_tests/union_03.py index 5033085158..4c8c538ac4 100644 --- a/integration_tests/union_03.py +++ b/integration_tests/union_03.py @@ -1,4 +1,4 @@ -from ltypes import Union, i32, i64, f64, f32, union +from lpython import Union, i32, i64, f64, f32, union # without ccall but same as union_01.py @union diff --git a/integration_tests/union_04.py b/integration_tests/union_04.py new file mode 100644 index 0000000000..58a604ecc1 --- /dev/null +++ b/integration_tests/union_04.py @@ -0,0 +1,24 @@ +from union_01 import u_type +from lpython import f32, f64, i64 + +# Test taken from union_01.py but checks importing union + +def test_union_04(): + unionobj: u_type = u_type() + unionobj.integer32 = 1 + print(unionobj.integer32) + assert unionobj.integer32 == 1 + + unionobj.real32 = f32(2.0) + print(unionobj.real32) + assert abs(f64(unionobj.real32) - 2.0) <= 1e-6 + + unionobj.real64 = 3.5 + print(unionobj.real64) + assert abs(unionobj.real64 - 3.5) <= 1e-12 + + unionobj.integer64 = i64(4) + print(unionobj.integer64) + assert unionobj.integer64 == i64(4) + +test_union_04() diff --git a/integration_tests/variable_decl_01.py b/integration_tests/variable_decl_01.py index 9672366969..669470411c 100644 --- a/integration_tests/variable_decl_01.py +++ b/integration_tests/variable_decl_01.py @@ -1,8 +1,8 @@ -from ltypes import i32, i64 +from lpython import i32, i64, Const from numpy import empty, int64 def f(n: i32, m: i32): - l: i32 = 2 + l: Const[i32] = 2 a: i64[n, m, l] = empty((n, m, l), dtype=int64) i: i32; j: i32; k: i32; for i in range(n): diff --git a/integration_tests/variable_decl_02.py b/integration_tests/variable_decl_02.py index 08d1486552..9ee2a67034 100644 --- a/integration_tests/variable_decl_02.py +++ b/integration_tests/variable_decl_02.py @@ -1,4 +1,4 @@ -from ltypes import i32, i64 +from lpython import i32, i64 def f(): d: i32 = 0 diff --git a/integration_tests/variable_decl_03.py b/integration_tests/variable_decl_03.py new file mode 100644 index 0000000000..f554b9fc5d --- /dev/null +++ b/integration_tests/variable_decl_03.py @@ -0,0 +1,11 @@ +from lpython import f64 + +def f() -> f64: + return abs(-5.5) + +def main(): + t1: f64 = f() * 1e6 + print(t1) + assert abs(t1 - 5.5 * 1e6) <= 1e-6 + +main() diff --git a/integration_tests/vec_01.py b/integration_tests/vec_01.py index 4bbcb87522..8d93b8b9c2 100644 --- a/integration_tests/vec_01.py +++ b/integration_tests/vec_01.py @@ -1,9 +1,9 @@ -from ltypes import f64 -from numpy import empty +from lpython import f64, i32 +from numpy import empty, float64 def loop_vec(): - a: f64[9216] = empty(9216) - b: f64[9216] = empty(9216) + a: f64[9216] = empty(9216, dtype=float64) + b: f64[9216] = empty(9216, dtype=float64) i: i32 for i in range(9216): diff --git a/libasr b/libasr new file mode 160000 index 0000000000..f2a04fc2ae --- /dev/null +++ b/libasr @@ -0,0 +1 @@ +Subproject commit f2a04fc2ae4dd9ccb940c0fee3f694791fec7005 diff --git a/run_tests.py b/run_tests.py index d818757b50..d45335ec3a 100755 --- a/run_tests.py +++ b/run_tests.py @@ -4,13 +4,13 @@ import os ROOT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__))) -sys.path.append(os.path.join(ROOT_DIR, "src", "libasr")) +sys.path.append(os.path.join(ROOT_DIR, "libasr", "src", "libasr")) from compiler_tester.tester import color, fg, log, run_test, style, tester_main def single_test(test, verbose, no_llvm, skip_run_with_dbg, update_reference, - no_color, specific_backends=None, excluded_backends=None): + verify_hash, no_color, specific_backends=None, excluded_backends=None): filename = test["filename"] def is_included(backend): return test.get(backend, False) \ @@ -21,19 +21,25 @@ def is_included(backend): ast = is_included("ast") ast_new = is_included("ast_new") asr = is_included("asr") + asr_json = is_included("asr_json") llvm = is_included("llvm") llvm_dbg = is_included("llvm_dbg") cpp = is_included("cpp") c = is_included("c") + python = is_included("python") + is_cumulative = is_included("cumulative") wat = is_included("wat") run = is_included("run") run_with_dbg = is_included("run_with_dbg") + disable_main = is_included("disable_main") + fast = is_included("fast") pass_ = test.get("pass", None) optimization_passes = ["flip_sign", "div_to_mul", "fma", "sign_from_value", "inline_function_calls", "loop_unroll", - "dead_code_removal", "loop_vectorise", "print_list_tuple"] + "dead_code_removal", "loop_vectorise", "print_list_tuple", + "class_constructor"] - if pass_ and (pass_ not in ["do_loops", "global_stmts"] and + if pass_ and (pass_ not in ["do_loops", "global_stmts", "while_else"] and pass_ not in optimization_passes): raise Exception(f"Unknown pass: {pass_}") if no_color: @@ -50,7 +56,7 @@ def is_included(backend): "lpython --no-color --show-tokens {infile} -o {outfile}", filename, update_reference, - extra_args) + extra_args=extra_args) if ast: run_test( @@ -59,7 +65,7 @@ def is_included(backend): "lpython --show-ast --no-color {infile} -o {outfile}", filename, update_reference, - extra_args) + extra_args=extra_args) if ast_new: run_test( @@ -68,7 +74,7 @@ def is_included(backend): "lpython --show-ast --new-parser --no-color {infile} -o {outfile}", filename, update_reference, - extra_args) + extra_args=extra_args) if asr: run_test( @@ -77,13 +83,27 @@ def is_included(backend): "lpython --show-asr --no-color {infile} -o {outfile}", filename, update_reference, - extra_args) + extra_args=extra_args) + + if asr_json: + run_test( + filename, + "asr_json", + "lpython --show-asr --json --no-color {infile} -o {outfile}", + filename, + update_reference, + extra_args=extra_args) if pass_ is not None: - cmd = "lpython --pass=" + pass_ + \ + cmd = "lpython " + if is_cumulative: + cmd += "--cumulative " + if fast: + cmd += "--fast " + cmd += "--pass=" + pass_ + \ " --show-asr --no-color {infile} -o {outfile}" run_test(filename, "pass_{}".format(pass_), cmd, - filename, update_reference, extra_args) + filename, update_reference, extra_args=extra_args) if no_llvm: log.info(f"{filename} * llvm SKIPPED as requested") @@ -95,7 +115,7 @@ def is_included(backend): "lpython --no-color --show-llvm {infile} -o {outfile}", filename, update_reference, - extra_args) + extra_args=extra_args) if llvm_dbg: run_test( filename, @@ -104,22 +124,31 @@ def is_included(backend): "{infile} -o {outfile}", filename, update_reference, - extra_args) + extra_args=extra_args) if cpp: run_test(filename, "cpp", "lpython --no-color --show-cpp {infile}", - filename, update_reference, extra_args) + filename, update_reference, extra_args=extra_args) if c: - run_test(filename, "c", "lpython --no-color --show-c {infile}", - filename, update_reference, extra_args) + if disable_main: + run_test(filename, "c", "lpython --no-color --disable-main --show-c {infile}", + filename, update_reference, extra_args=extra_args) + else: + run_test(filename, "c", "lpython --no-color --show-c {infile}", + filename, update_reference, extra_args=extra_args) + + if python: + run_test(filename, "python", "lpython --no-color --show-python {infile}", + filename, update_reference, extra_args=extra_args) + if wat: run_test(filename, "wat", "lpython --no-color --show-wat {infile}", - filename, update_reference, extra_args) + filename, update_reference, extra_args=extra_args) if run: run_test(filename, "runtime", "lpython {infile}", - filename, update_reference, extra_args) + filename, update_reference, extra_args=extra_args) if run_with_dbg: if skip_run_with_dbg: @@ -128,7 +157,7 @@ def is_included(backend): run_test( filename, "run_dbg", "lpython {infile} -g --debug-with-line-column --no-color", - filename, update_reference, extra_args) + filename, update_reference, extra_args=extra_args) if __name__ == "__main__": tester_main("LPython", single_test) diff --git a/share/jupyter/kernels/lpython/kernel.json.in b/share/jupyter/kernels/lpython/kernel.json.in new file mode 100644 index 0000000000..e1af020ba4 --- /dev/null +++ b/share/jupyter/kernels/lpython/kernel.json.in @@ -0,0 +1,10 @@ +{ + "display_name": "LPython", + "argv": [ + "@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_BINDIR@/lpython", + "kernel", + "-f", + "{connection_file}" + ], + "language": "python" +} diff --git a/share/lpython/lfortran-completion.bash b/share/lpython/lfortran-completion.bash index ca63ca03bd..69bb236096 100644 --- a/share/lpython/lfortran-completion.bash +++ b/share/lpython/lfortran-completion.bash @@ -1,6 +1,6 @@ #/usr/bin/env bash complete \ - -W "-h --help -S -c -o -v -E -I --version --cpp --fixed-form --show-prescan --show-tokens --show-ast --show-asr --with-intrinsic-modules --show-ast-f90 --no-color --indent --pass --show-llvm --show-cpp --show-stacktrace --time-report --static --backend --openmp fmt kernel mod pywrap" \ + -W "-h --help -S -c -o -v -E -I --version --cpp --fixed-form --show-prescan --show-tokens --show-ast --show-asr --with-intrinsic-modules --show-ast-f90 --no-color --pass --show-llvm --show-cpp --show-stacktrace --time-report --static --backend --openmp fmt kernel mod pywrap" \ -df \ lfortran diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 061b942762..ebba706be4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,4 @@ -add_subdirectory(libasr) +add_subdirectory(${CMAKE_SOURCE_DIR}/libasr/src/libasr ${CMAKE_BINARY_DIR}/libasr) add_subdirectory(tests) add_subdirectory(lpython) add_subdirectory(bin) diff --git a/src/bin/CMakeLists.txt b/src/bin/CMakeLists.txt index ba670e6037..c5a4f62032 100644 --- a/src/bin/CMakeLists.txt +++ b/src/bin/CMakeLists.txt @@ -19,10 +19,17 @@ if (WITH_STACKTRACE AND APPLE AND CMAKE_CXX_COMPILER_ID MATCHES Clang) # On macOS we have to call dsymutil to create the dSYM bundle so that the # stacktrace can find debugging information corresponding to the lpython # binary + find_program(DSYMUTIL NAMES dsymutil PATHS /usr/bin NO_DEFAULT_PATH) + + if(NOT DSYMUTIL) + find_program(DSYMUTIL NAMES dsymutil) + endif() + + message("DSYMUTIL: ${DSYMUTIL}") add_custom_command( TARGET lpython POST_BUILD - COMMAND dsymutil lpython + COMMAND ${DSYMUTIL} lpython ) if (WITH_DWARFDUMP) add_custom_command( @@ -33,7 +40,7 @@ if (WITH_STACKTRACE AND APPLE AND CMAKE_CXX_COMPILER_ID MATCHES Clang) add_custom_command( TARGET lpython POST_BUILD - COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/dwarf_convert.py lpython.dSYM/raw.txt lpython.dSYM/lines.txt lpython.dSYM/lines.dat + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/../../libasr/src/libasr/dwarf_convert.py lpython.dSYM/raw.txt lpython.dSYM/lines.txt lpython.dSYM/lines.dat ) endif() endif() @@ -48,29 +55,24 @@ set_target_properties(lpython PROPERTIES ) if (HAVE_BUILD_TO_WASM) - # set(WASM_LINK_FLAGS - # "-g0" # Store no debugging information in the generated wasm file. This helps reduce generated file size - # "-Oz" # Optimize for size. With this code size ~ 2.4mb. Without this code size ~49mb - # "-fexceptions" # Enable Cpp exception support - # "--no-entry" # No start function to execute - # "-s ASSERTIONS" # Compile with Assertions which (as per docs) are helpful to debug compilation process - # "-s ALLOW_MEMORY_GROWTH" # Allow dynamic memory growth upto the maximum page size limit - # "-s WASM_BIGINT" # Allow use of i64 integers. ASR is needing this option to be enabled. - # "-s EXPORTED_RUNTIME_METHODS=['cwrap']" # Export cwarp. cwarp helps us to call our EMSCRIPTEN_KEEPALIVE functions - # ) - - # Some extra flags below that we may need in future. But these may/might increase the code size - # "--preload-file ./asset_dir" - # "-s SAFE_HEAP=1" - # "-s \"EXPORTED_RUNTIME_METHODS=['ccall']\"" - # "-s EXPORTED_FUNCTIONS=\"['_free', '_malloc']\"" + # "-g0": Store no debugging information in the generated wasm file. This helps reduce generated file size + # "-Oz": Optimize for size. With this code size ~ 2.4mb. Without this code size ~49mb + # "-fexceptions": Enable Cpp exception support + # "--no-entry": No start function to execute + # "-s ASSERTIONS": Compile with Assertions which (as per docs) are helpful to debug compilation process + # "-s ALLOW_MEMORY_GROWTH": Allow dynamic memory growth upto the maximum page size limit + # "-s WASM_BIGINT": Allow use of i64 integers. ASR is needing this option to be enabled. + # "-s EXPORTED_RUNTIME_METHODS=['cwrap']": Export cwarp. cwarp helps us to call our EMSCRIPTEN_KEEPALIVE functions + # "-fsanitize=undefined": Clang's Undefined Behaviour Sanitizer. The LPython parser segfaults. + # This option is for debugging, but currently helps avoid the segfault in the parser. + # "-s INITIAL_MEMORY=536870912": Start the wasm linear memory with sufficiently large size 512Mb. # Notes: # STANDALONE_WASM is disabling support for exceptions, so it is currently omitted # In build_to_wasm.sh, we need CMAKE_CXX_FLAGS_DEBUG="-Wall -Wextra -fexceptions" flags for exception support - set(WASM_COMPILE_FLAGS "-g0 -fexceptions") + set(WASM_COMPILE_FLAGS "-g0 -fexceptions -fsanitize=undefined") set(WASM_LINK_FLAGS - "-g0 -Oz -fexceptions -Wall -Wextra --no-entry -s ASSERTIONS -s ALLOW_MEMORY_GROWTH=1 -s WASM_BIGINT -s \"EXPORTED_RUNTIME_METHODS=['cwrap']\"" + "-g0 -Oz -fexceptions -fsanitize=undefined --preload-file asset_dir -Wall -Wextra --no-entry -sASSERTIONS=1 -s INITIAL_MEMORY=536870912 -s ALLOW_MEMORY_GROWTH=1 -s WASM_BIGINT -s \"EXPORTED_RUNTIME_METHODS=['cwrap']\"" ) set_target_properties(lpython PROPERTIES COMPILE_FLAGS ${WASM_COMPILE_FLAGS}) set_target_properties(lpython PROPERTIES LINK_FLAGS ${WASM_LINK_FLAGS}) diff --git a/src/bin/bench_gen.py b/src/bin/bench_gen.py index a25957a5db..3c47106fd5 100755 --- a/src/bin/bench_gen.py +++ b/src/bin/bench_gen.py @@ -18,7 +18,7 @@ def A{i}(x: i32) -> i32: calls += f" y = A{i}(y)\n" source = f"""\ -from ltypes import i32 +from lpython import i32 {A_functions} diff --git a/src/bin/dat_convert.py b/src/bin/dat_convert.py deleted file mode 100755 index d7ae867e29..0000000000 --- a/src/bin/dat_convert.py +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env python3 - -from struct import unpack -from sys import argv -from re import sub - -lines = "" -with open(argv[1], "rb") as f: - lines = f.read() - -list = [] -for i in range(0, len(lines), 24): - list.append(sub('[(),]', '', str(unpack("3Q", lines[i:i+24])))) - -with open(argv[1] + ".txt", "w") as f: - j = 0 - for i in list: - f.write(i+'\n') diff --git a/src/bin/dwarf_convert.py b/src/bin/dwarf_convert.py deleted file mode 100755 index cfd5a56e81..0000000000 --- a/src/bin/dwarf_convert.py +++ /dev/null @@ -1,162 +0,0 @@ -#!/usr/bin/env python3 - -""" -This script is used to convert the output of dwarfdump into a file that is easy -to load into lfortran to lookup filenames and line numbers for a given address. -Here is how to use it: - - cd src/bin - llvm-dwarfdump --debug-line lfortran.dSYM > lfortran.dSYM/symbols.txt - ./dwarf_convert.py lfortran.dSYM/symbols.txt lfortran.dSYM/lines.txt lfortran.dSYM/lines.dat - -This is meant to be executed at build time. - -A better solution would be to use the `dwarf` library directly from C++ and -generate the same output directly. Here is the source code of llvm-dwarfdump: - -https://github.com/llvm/llvm-project/blob/91a6ad5ad887a16e361338303d4ff3d29dba5e10/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp - -We just have to do exactly what it does, but generate the output in the format -of lines.txt and lines.dat - -""" - -from collections import namedtuple -from glob import glob -import os -import re -from struct import pack -import sys - -DebugLines = namedtuple("DebugLines", ["lines"]) -DebugLine = namedtuple("DebugLine", ["include_directories", "file_names", "addresses"]) -IncludeDirectory = namedtuple("IncludeDirectory", ["id", "path"]) -FileName = namedtuple("FileName", ["id", "filename", "dir_idx"]) - -ASRDebugLines = namedtuple("ASRDebugLines", ["filenames", "addresses"]) - -class Parser: - """ - Parser for the output generated by dwarfdump. - - On macOS (both Intel and ARM based): - - dwarfdump --debug-line src/bin/lfortran.dSYM > symbols.txt - - Then parse it using: - - p = Parser() - ast = p.parse_file("symbols.txt") - """ - - def parse_file(self, filename): - self.file = open(filename) - self.line = self.file.readline() - while not self.line.startswith(".debug_line contents:"): - self.line = self.file.readline() - - self.line = self.file.readline() - lines = [] - while self.line.startswith("debug_line"): - d = self.parse_debug_line() - lines.append(d) - return DebugLines(lines) - - def parse_debug_line(self): - self.line = self.file.readline() - while not self.line.startswith("include_directories"): - self.line = self.file.readline() - - include_directories = [] - while self.line.startswith("include_directories"): - n, path = re.compile(r"include_directories\[[ ]*(\d+)\] = \"([^\"]+)\"").findall(self.line)[0] - n = int(n) - include_directories.append(IncludeDirectory(n, path)) - self.line = self.file.readline() - - file_names = [] - while self.line.startswith("file_names"): - n = re.compile(r"file_names\[[ ]*(\d+)\]:").findall(self.line)[0] - n = int(n) - - self.line = self.file.readline() - filename = re.compile(r"name: \"([^\"]+)\"").findall(self.line)[0] - - self.line = self.file.readline() - dir_idx = re.compile(r"dir_index: (\d+)").findall(self.line)[0] - dir_idx = int(dir_idx) - - self.line = self.file.readline() - self.line = self.file.readline() - - file_names.append(FileName(n, filename, dir_idx)) - - self.line = self.file.readline() - - self.line = self.file.readline() - self.line = self.file.readline() - self.line = self.file.readline() - - addresses = [] - while self.line.startswith("0x"): - address, line, column, file_id = self.line.split()[:4] - address = int(address, base=16) - line = int(line) - column = int(column) - file_id = int(file_id) - addresses.append([address, line, column, file_id]) - self.line = self.file.readline() - - self.line = self.file.readline() - - d = DebugLine(include_directories, file_names, addresses) - return d - -def ast_to_asr(ast): - local_files = glob("../**/*.cpp", recursive=True) + \ - glob("../**/*.h", recursive=True) - for i in range(len(local_files)): - local_files[i] = os.path.abspath(local_files[i]) - def make_abs(end_path): - if end_path[0] != "/": - for f in local_files: - if f.endswith(end_path): - return f - return end_path - lines = [] - last_address = -1 - global_filename_id = 0 - global_filenames = [] - global_addresses = [] - for line in ast.lines: - include_dirs = {} - for inc in line.include_directories: - include_dirs[inc.id] = inc.path - filenames = {} - for filename in line.file_names: - prefix = "" - if filename.dir_idx != 0: - prefix = include_dirs[filename.dir_idx] + "/" - filenames[filename.id] = global_filename_id - global_filenames.append(make_abs(prefix+filename.filename)) - global_filename_id += 1 - for address, line_num, column, file_id in line.addresses: - filename = global_filenames[filenames[file_id]] - assert last_address <= address - last_address = address - if line_num != 0: - global_addresses.append([address, line_num, filenames[file_id]]) - return ASRDebugLines(global_filenames, global_addresses) - - -p = Parser() -ast = p.parse_file(sys.argv[1]) -asr = ast_to_asr(ast) -with open(sys.argv[2], "w") as f: - f.write(str(len(asr.filenames)) + "\n") - for filename in asr.filenames: - f.write(filename + "\n") - f.write(str(len(asr.addresses)) + "\n") -with open(sys.argv[3], "wb") as f: - for addr, line, fileid in asr.addresses: - f.write(pack("3Q", addr, line, fileid)) diff --git a/src/bin/lpython.cpp b/src/bin/lpython.cpp index 913eadcccb..573a5a9658 100644 --- a/src/bin/lpython.cpp +++ b/src/bin/lpython.cpp @@ -6,12 +6,14 @@ #define CLI11_HAS_FILESYSTEM 0 #include -#include #include +#include +#include #include #include #include #include +#include #include #include #include @@ -27,10 +29,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include @@ -44,6 +48,9 @@ #include #include #endif + +extern std::string lcompilers_unique_ID_separate_compilation; + namespace { using LCompilers::endswith; @@ -51,9 +58,10 @@ using LCompilers::CompilerOptions; using LCompilers::LPython::parse_python_file; enum class Backend { - llvm, cpp, c, x86, wasm, wasm_x86, wasm_x64 + llvm, cpp, c, x86, wasm, wasm_x86, wasm_x64, python }; + std::string remove_extension(const std::string& filename) { size_t lastdot = filename.find_last_of("."); if (lastdot == std::string::npos) return filename; @@ -82,7 +90,7 @@ std::string get_kokkos_dir() int emit_tokens(const std::string &infile, bool line_numbers, const CompilerOptions &compiler_options) { - std::string input = LCompilers::read_file(infile); + std::string input = LCompilers::read_file_ok(infile); // Src -> Tokens Allocator al(64*1024*1024); std::vector toks; @@ -95,7 +103,7 @@ int emit_tokens(const std::string &infile, bool line_numbers, const CompilerOpti LCompilers::LocationManager::FileLocations fl; fl.in_filename = infile; lm.files.push_back(fl); - std::string input = LCompilers::read_file(infile); + std::string input = LCompilers::read_file_ok(infile); lm.init_simple(input); lm.file_ends.push_back(input.size()); } @@ -132,7 +140,7 @@ int emit_ast(const std::string &infile, LCompilers::LocationManager::FileLocations fl; fl.in_filename = infile; lm.files.push_back(fl); - std::string input = LCompilers::read_file(infile); + std::string input = LCompilers::read_file_ok(infile); lm.init_simple(input); lm.file_ends.push_back(input.size()); } @@ -144,20 +152,32 @@ int emit_ast(const std::string &infile, } LCompilers::LPython::AST::ast_t* ast = r.result; - if (compiler_options.tree) { + if (compiler_options.po.tree) { std::cout << LCompilers::LPython::pickle_tree_python(*ast, compiler_options.use_colors) << std::endl; - } else if (compiler_options.json) { + } else if (compiler_options.po.json) { LCompilers::LocationManager lm; { LCompilers::LocationManager::FileLocations fl; fl.in_filename = infile; lm.files.push_back(fl); - std::string input = LCompilers::read_file(infile); + std::string input = LCompilers::read_file_ok(infile); lm.init_simple(input); lm.file_ends.push_back(input.size()); } std::cout << LCompilers::LPython::pickle_json(*ast, lm) << std::endl; + } else if (compiler_options.po.visualize) { + LCompilers::LocationManager lm; + { + LCompilers::LocationManager::FileLocations fl; + fl.in_filename = infile; + lm.files.push_back(fl); + std::string input = LCompilers::read_file_ok(infile); + lm.init_simple(input); + lm.file_ends.push_back(input.size()); + } + LCompilers::Result r = LCompilers::LPython::pickle_json(*ast, lm); + return visualize_json(r.result, compiler_options.platform); } else { std::cout << LCompilers::LPython::pickle_python(*ast, compiler_options.use_colors, compiler_options.indent) << std::endl; @@ -177,7 +197,7 @@ int emit_asr(const std::string &infile, LCompilers::LocationManager::FileLocations fl; fl.in_filename = infile; lm.files.push_back(fl); - std::string input = LCompilers::read_file(infile); + std::string input = LCompilers::read_file_ok(infile); lm.init_simple(input); lm.file_ends.push_back(input.size()); } @@ -191,26 +211,29 @@ int emit_asr(const std::string &infile, diagnostics.diagnostics.clear(); LCompilers::Result - r = LCompilers::LPython::python_ast_to_asr(al, lm, *ast, diagnostics, - compiler_options, true, infile); + r = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *ast, diagnostics, + compiler_options, true, "__main__", infile); std::cerr << diagnostics.render(lm, compiler_options); if (!r.ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) return 2; } LCompilers::ASR::TranslationUnit_t* asr = r.result; - LCompilers::PassOptions pass_options; - pass_options.run_fun = "f"; - pass_options.always_run = true; - pass_manager.apply_passes(al, asr, pass_options, diagnostics); + compiler_options.po.always_run = true; + compiler_options.po.run_fun = "f"; + + pass_manager.apply_passes(al, asr, compiler_options.po, diagnostics); - if (compiler_options.tree) { - std::cout << LCompilers::LPython::pickle_tree(*asr, + if (compiler_options.po.tree) { + std::cout << LCompilers::pickle_tree(*asr, compiler_options.use_colors, with_intrinsic_modules) << std::endl; - } else if (compiler_options.json) { - std::cout << LCompilers::LPython::pickle_json(*asr, lm) << std::endl; + } else if (compiler_options.po.json) { + std::cout << LCompilers::pickle_json(*asr, lm, compiler_options.po.no_loc, with_intrinsic_modules) << std::endl; + } else if (compiler_options.po.visualize) { + std::string astr_data_json = LCompilers::pickle_json(*asr, lm, compiler_options.po.no_loc, with_intrinsic_modules); + return visualize_json(astr_data_json, compiler_options.platform); } else { - std::cout << LCompilers::LPython::pickle(*asr, compiler_options.use_colors, + std::cout << LCompilers::pickle(*asr, compiler_options.use_colors, compiler_options.indent, with_intrinsic_modules) << std::endl; } return 0; @@ -227,7 +250,7 @@ int emit_cpp(const std::string &infile, LCompilers::LocationManager::FileLocations fl; fl.in_filename = infile; lm.files.push_back(fl); - std::string input = LCompilers::read_file(infile); + std::string input = LCompilers::read_file_ok(infile); lm.init_simple(input); lm.file_ends.push_back(input.size()); } @@ -241,7 +264,7 @@ int emit_cpp(const std::string &infile, diagnostics.diagnostics.clear(); LCompilers::Result - r1 = LCompilers::LPython::python_ast_to_asr(al, lm, *ast, diagnostics, compiler_options, true, infile); + r1 = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *ast, diagnostics, compiler_options, true, "__main__", infile); std::cerr << diagnostics.render(lm, compiler_options); if (!r1.ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) @@ -262,6 +285,7 @@ int emit_cpp(const std::string &infile, int emit_c(const std::string &infile, const std::string &runtime_library_dir, + LCompilers::PassManager& pass_manager, CompilerOptions &compiler_options) { Allocator al(4*1024); @@ -271,7 +295,7 @@ int emit_c(const std::string &infile, LCompilers::LocationManager::FileLocations fl; fl.in_filename = infile; lm.files.push_back(fl); - std::string input = LCompilers::read_file(infile); + std::string input = LCompilers::read_file_ok(infile); lm.init_simple(input); lm.file_ends.push_back(input.size()); } @@ -285,7 +309,7 @@ int emit_c(const std::string &infile, diagnostics.diagnostics.clear(); LCompilers::Result - r1 = LCompilers::LPython::python_ast_to_asr(al, lm, *ast, diagnostics, compiler_options, true, infile); + r1 = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *ast, diagnostics, compiler_options, true, "__main__", infile); std::cerr << diagnostics.render(lm, compiler_options); if (!r1.ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) @@ -293,6 +317,14 @@ int emit_c(const std::string &infile, } LCompilers::ASR::TranslationUnit_t* asr = r1.result; + // Apply ASR passes + pass_manager.use_default_passes(true); + compiler_options.po.always_run = true; + compiler_options.po.run_fun = "f"; + compiler_options.po.c_skip_bindpy_pass = true; + + pass_manager.apply_passes(al, asr, compiler_options.po, diagnostics); + diagnostics.diagnostics.clear(); auto res = LCompilers::asr_to_c(al, *asr, diagnostics, compiler_options, 0); std::cerr << diagnostics.render(lm, compiler_options); @@ -305,7 +337,7 @@ int emit_c(const std::string &infile, } int emit_c_to_file(const std::string &infile, const std::string &outfile, - const std::string &runtime_library_dir, + const std::string &runtime_library_dir, LCompilers::PassManager& pass_manager, CompilerOptions &compiler_options) { Allocator al(4*1024); @@ -315,7 +347,7 @@ int emit_c_to_file(const std::string &infile, const std::string &outfile, LCompilers::LocationManager::FileLocations fl; fl.in_filename = infile; lm.files.push_back(fl); - std::string input = LCompilers::read_file(infile); + std::string input = LCompilers::read_file_ok(infile); lm.init_simple(input); lm.file_ends.push_back(input.size()); } @@ -329,7 +361,7 @@ int emit_c_to_file(const std::string &infile, const std::string &outfile, diagnostics.diagnostics.clear(); LCompilers::Result - r1 = LCompilers::LPython::python_ast_to_asr(al, lm, *ast, diagnostics, compiler_options, true, infile); + r1 = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *ast, diagnostics, compiler_options, true, "__main__", infile); std::cerr << diagnostics.render(lm, compiler_options); if (!r1.ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) @@ -337,6 +369,13 @@ int emit_c_to_file(const std::string &infile, const std::string &outfile, } LCompilers::ASR::TranslationUnit_t* asr = r1.result; + compiler_options.po.run_fun = "f"; + compiler_options.po.always_run = true; + compiler_options.po.c_skip_bindpy_pass = true; + + pass_manager.use_default_passes(true); + pass_manager.apply_passes(al, asr, compiler_options.po, diagnostics); + diagnostics.diagnostics.clear(); auto res = LCompilers::asr_to_c(al, *asr, diagnostics, compiler_options, 0); std::cerr << diagnostics.render(lm, compiler_options); @@ -351,6 +390,56 @@ int emit_c_to_file(const std::string &infile, const std::string &outfile, return 0; } +int emit_python(const std::string &infile, + const std::string &runtime_library_dir, + CompilerOptions &compiler_options) +{ + Allocator al(4*1024); + LCompilers::diag::Diagnostics diagnostics; + LCompilers::LocationManager lm; + { + LCompilers::LocationManager::FileLocations fl; + fl.in_filename = infile; + lm.files.push_back(fl); + std::string input = LCompilers::read_file_ok(infile); + lm.init_simple(input); + lm.file_ends.push_back(input.size()); + } + LCompilers::Result r = parse_python_file( + al, runtime_library_dir, infile, diagnostics, 0, compiler_options.new_parser); + std::cerr << diagnostics.render(lm, compiler_options); + if (!r.ok) { + return 1; + } + LCompilers::LPython::AST::ast_t* ast = r.result; + + diagnostics.diagnostics.clear(); + + // AST -> ASR + LCompilers::Result + r1 = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *ast, diagnostics, compiler_options, true, "__main__", infile); + std::cerr << diagnostics.render(lm, compiler_options); + if (!r1.ok) { + LCOMPILERS_ASSERT(diagnostics.has_error()) + return 2; + } + LCompilers::ASR::TranslationUnit_t* asr = r1.result; + + diagnostics.diagnostics.clear(); + + // ASR -> LPython + bool color = false; + int indent = 0; + LCompilers::Result res = LCompilers::asr_to_python(al, *asr, diagnostics, compiler_options, color, indent); + std::cerr << diagnostics.render(lm, compiler_options); + if (!res.ok) { + LCOMPILERS_ASSERT(diagnostics.has_error()) + return 3; + } + std::cout << res.result; + return 0; +} + int emit_wat(const std::string &infile, const std::string &runtime_library_dir, CompilerOptions &compiler_options) @@ -362,7 +451,7 @@ int emit_wat(const std::string &infile, LCompilers::LocationManager::FileLocations fl; fl.in_filename = infile; lm.files.push_back(fl); - std::string input = LCompilers::read_file(infile); + std::string input = LCompilers::read_file_ok(infile); lm.init_simple(input); lm.file_ends.push_back(input.size()); } @@ -376,7 +465,7 @@ int emit_wat(const std::string &infile, diagnostics.diagnostics.clear(); LCompilers::Result - r1 = LCompilers::LPython::python_ast_to_asr(al, lm, *ast, diagnostics, compiler_options, true, infile); + r1 = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *ast, diagnostics, compiler_options, true, "__main__", infile); std::cerr << diagnostics.render(lm, compiler_options); if (!r1.ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) @@ -385,7 +474,7 @@ int emit_wat(const std::string &infile, LCompilers::ASR::TranslationUnit_t* asr = r1.result; diagnostics.diagnostics.clear(); - LCompilers::Result> r2 = LCompilers::asr_to_wasm_bytes_stream(*asr, al, diagnostics); + LCompilers::Result> r2 = LCompilers::asr_to_wasm_bytes_stream(*asr, al, diagnostics, compiler_options); std::cerr << diagnostics.render(lm, compiler_options); if (!r2.ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) @@ -403,6 +492,45 @@ int emit_wat(const std::string &infile, return 0; } +int dump_all_passes(const std::string &infile, + const std::string &runtime_library_dir, + CompilerOptions &compiler_options) { + std::string input = LCompilers::read_file_ok(infile); + + Allocator al(4*1024); + LCompilers::LocationManager lm; + LCompilers::diag::Diagnostics diagnostics; + { + LCompilers::LocationManager::FileLocations fl; + fl.in_filename = infile; + lm.files.push_back(fl); + lm.file_ends.push_back(input.size()); + } + + LCompilers::Result r = parse_python_file( + al, runtime_library_dir, infile, diagnostics, 0, compiler_options.new_parser); + std::cerr << diagnostics.render(lm, compiler_options); + if (!r.ok) { + return 1; + } + LCompilers::LPython::AST::ast_t* ast = r.result; + diagnostics.diagnostics.clear(); + LCompilers::Result + r1 = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *ast, diagnostics, compiler_options, true, "__main__", infile); + std::cerr << diagnostics.render(lm, compiler_options); + if (r1.ok) { + LCompilers::PassManager pass_manager; + compiler_options.po.always_run = true; + compiler_options.po.run_fun = "f"; + pass_manager.dump_all_passes(al, r1.result, compiler_options.po, diagnostics, lm); + std::cerr << diagnostics.render(lm, compiler_options); + } else { + LCOMPILERS_ASSERT(diagnostics.has_error()) + return 1; + } + return 0; +} + #ifdef HAVE_LFORTRAN_RAPIDJSON int get_symbols (const std::string &infile, @@ -415,7 +543,7 @@ int get_symbols (const std::string &infile, LCompilers::LocationManager::FileLocations fl; fl.in_filename = infile; lm.files.push_back(fl); - std::string input = LCompilers::read_file(infile); + std::string input = LCompilers::read_file_ok(infile); lm.init_simple(input); lm.file_ends.push_back(input.size()); } @@ -425,14 +553,14 @@ int get_symbols (const std::string &infile, if (r1.ok) { LCompilers::LPython::AST::ast_t* ast = r1.result; LCompilers::Result - x = LCompilers::LPython::python_ast_to_asr(al, lm, *ast, diagnostics, compiler_options, true, infile); + x = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *ast, diagnostics, compiler_options, true, "__main__", infile); if (!x.ok) { std::cout << "{}\n"; return 0; } std::vector symbol_lists; LCompilers::document_symbols loc; - for (auto &a : x.result->m_global_scope->get_scope()) { + for (auto &a : x.result->m_symtab->get_scope()) { std::string symbol_name = a.first; uint32_t first_line; uint32_t last_line; @@ -516,7 +644,7 @@ int get_errors (const std::string &infile, LCompilers::LocationManager::FileLocations fl; fl.in_filename = infile; lm.files.push_back(fl); - std::string input = LCompilers::read_file(infile); + std::string input = LCompilers::read_file_ok(infile); lm.init_simple(input); lm.file_ends.push_back(input.size()); } @@ -526,12 +654,12 @@ int get_errors (const std::string &infile, if (r1.ok) { LCompilers::LPython::AST::ast_t* ast = r1.result; LCompilers::Result - r = LCompilers::LPython::python_ast_to_asr(al, lm, *ast, diagnostics, compiler_options, true, infile); + r = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *ast, diagnostics, compiler_options, true, "__main__", infile); } std::vector diag_lists; LCompilers::error_highlight h; for (auto &d : diagnostics.diagnostics) { - if (compiler_options.no_warnings && d.level != LCompilers::diag::Level::Error) { + if (!compiler_options.show_warnings && d.level != LCompilers::diag::Level::Error) { continue; } h.message = d.message; @@ -619,6 +747,11 @@ void print_time_report(std::vector> ×, bool #ifdef HAVE_LFORTRAN_LLVM +void section(const std::string &s) +{ + std::cout << color(LCompilers::style::bold) << color(LCompilers::fg::blue) << s << color(LCompilers::style::reset) << color(LCompilers::fg::reset) << std::endl; +} + int emit_llvm(const std::string &infile, const std::string &runtime_library_dir, LCompilers::PassManager& pass_manager, @@ -631,7 +764,7 @@ int emit_llvm(const std::string &infile, LCompilers::LocationManager::FileLocations fl; fl.in_filename = infile; lm.files.push_back(fl); - std::string input = LCompilers::read_file(infile); + std::string input = LCompilers::read_file_ok(infile); lm.init_simple(input); lm.file_ends.push_back(input.size()); } @@ -646,7 +779,7 @@ int emit_llvm(const std::string &infile, LCompilers::LPython::AST::ast_t* ast = r.result; diagnostics.diagnostics.clear(); LCompilers::Result - r1 = LCompilers::LPython::python_ast_to_asr(al, lm, *ast, diagnostics, compiler_options, true, infile); + r1 = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *ast, diagnostics, compiler_options, true, "__main__", infile); std::cerr << diagnostics.render(lm, compiler_options); if (!r1.ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) @@ -658,18 +791,7 @@ int emit_llvm(const std::string &infile, // ASR -> LLVM LCompilers::PythonCompiler fe(compiler_options); LCompilers::Result> - res = fe.get_llvm3(*asr, pass_manager, diagnostics, infile); - if (compiler_options.emit_debug_info) { - if (!compiler_options.emit_debug_line_column) { - diagnostics.add(LCompilers::diag::Diagnostic( - "The `emit_debug_line_column` is not enabled; please use the " - "`--debug-with-line-column` option to get the correct " - "location information", - LCompilers::diag::Level::Warning, - LCompilers::diag::Stage::Semantic, {}) - ); - } - } + res = fe.get_llvm3(*asr, pass_manager, diagnostics, lm, infile); std::cerr << diagnostics.render(lm, compiler_options); if (!res.ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) @@ -679,13 +801,251 @@ int emit_llvm(const std::string &infile, return 0; } -int compile_python_to_object_file( +bool determine_completeness(std::string command) +{ + auto get_last_line = [](std::string input) { + if(input.length() == 1) { + return input; + } + size_t position = input.length() - 2; + while ((!(input[position] == '\n' || input[position] == '\r')) && (position > 0)) { + position--; + } + if(input[position] == '\n' || input[position] == '\r') { + position += 1; + } + return input.substr(position); + }; + + std::string last_line = get_last_line(command); + if ((last_line.rfind("def", 0) == 0) || + (last_line.rfind("for", 0) == 0) || + (last_line.rfind("if", 0) == 0) || + (last_line.rfind("else", 0) == 0) || + (last_line.rfind("elif", 0) == 0) || + (last_line.rfind("class", 0) == 0) || + (last_line.rfind('@', 0) == 0) || + (last_line.rfind(' ', 0) == 0) || + (last_line.rfind('\t', 0) == 0)) { + return false; + } + return true; +} + +int interactive_python_repl( + LCompilers::PassManager& pass_manager, + CompilerOptions &compiler_options, + bool verbose) +{ + Allocator al(4*1024); + compiler_options.interactive = true; + LCompilers::PythonCompiler fe(compiler_options); + LCompilers::diag::Diagnostics diagnostics; + LCompilers::LocationManager lm; + std::vector> times; + LCompilers::PythonCompiler::EvalResult r; + + Terminal term(true, false); + std::cout << "Interactive LPython. Experimental prototype, not ready for end users." << std::endl; + std::string version = LFORTRAN_VERSION; + std::cout << "LPython version: " << version << std::endl; + std::cout << " * Use Ctrl-D to exit" << std::endl; + std::cout << " * Use Enter to submit" << std::endl; + std::cout << " * Use Alt-Enter or Ctrl-N to make a new line" << std::endl; + std::cout << " - Editing (Keys: Left, Right, Home, End, Backspace, Delete)" << std::endl; + std::cout << " - History (Keys: Up, Down)" << std::endl; + + std::vector history; + + std::function iscomplete = determine_completeness; + + std::string code_string; + size_t cell_count = 0; + while (true) { + std::string code_string = prompt0(term, ">>> ", history, iscomplete); + if (code_string.size() == 1 && code_string[0] == CTRL_KEY('d')) { + std::cout << std::endl; + std::cout << "Exiting." << std::endl; + return 0; + } + + { + cell_count++; + LCompilers::LocationManager::FileLocations fl; + fl.in_filename = "input"; + std::ofstream out("input"); + out << code_string; + lm.files.push_back(fl); + lm.init_simple(code_string); + lm.file_ends.push_back(code_string.size()); + } + + try { + auto evaluation_start_time = std::chrono::high_resolution_clock::now(); + LCompilers::Result + res = fe.evaluate(code_string, verbose, lm, pass_manager, diagnostics); + if (res.ok) { + r = res.result; + std::cerr << diagnostics.render(lm, compiler_options); + diagnostics.clear(); + } else { + LCOMPILERS_ASSERT(diagnostics.has_error()) + std::cerr << diagnostics.render(lm, compiler_options); + diagnostics.clear(); + continue; + } + + auto evaluation_end_time = std::chrono::high_resolution_clock::now(); + times.push_back(std::make_pair("evalution " + std::to_string(cell_count), std::chrono::duration + (evaluation_start_time - evaluation_end_time).count())); + + } catch (const LCompilers::LCompilersException &e) { + std::cerr << "Internal Compiler Error: Unhandled exception" << std::endl; + std::vector d = e.stacktrace_addresses(); + get_local_addresses(d); + get_local_info(d); + std::cerr << stacktrace2str(d, LCompilers::stacktrace_depth); + std::cerr << e.name() + ": " << e.msg() << std::endl; + continue; + } + + if (verbose) { + section("AST:"); + std::cout << r.ast << std::endl; + section("ASR:"); + std::cout << r.asr << std::endl; + section("LLVM IR:"); + std::cout << r.llvm_ir << std::endl; + } + + switch (r.type) { + case (LCompilers::PythonCompiler::EvalResult::integer1) : { + if (verbose) std::cout << "Return type: i8" << std::endl; + if (verbose) section("Result:"); + std::cout << r.i32 << std::endl; + break; + } + case (LCompilers::PythonCompiler::EvalResult::integer2) : { + if (verbose) std::cout << "Return type: i16" << std::endl; + if (verbose) section("Result:"); + std::cout << r.i64 << std::endl; + break; + } + case (LCompilers::PythonCompiler::EvalResult::integer4) : { + if (verbose) std::cout << "Return type: i32" << std::endl; + if (verbose) section("Result:"); + std::cout << r.i32 << std::endl; + break; + } + case (LCompilers::PythonCompiler::EvalResult::integer8) : { + if (verbose) std::cout << "Return type: i64" << std::endl; + if (verbose) section("Result:"); + std::cout << r.i64 << std::endl; + break; + } + case (LCompilers::PythonCompiler::EvalResult::unsignedInteger1) : { + if (verbose) std::cout << "Return type: u8" << std::endl; + if (verbose) section("Result:"); + std::cout << r.u32 << std::endl; + break; + } + case (LCompilers::PythonCompiler::EvalResult::unsignedInteger2) : { + if (verbose) std::cout << "Return type: u16" << std::endl; + if (verbose) section("Result:"); + std::cout << r.u64 << std::endl; + break; + } + case (LCompilers::PythonCompiler::EvalResult::unsignedInteger4) : { + if (verbose) std::cout << "Return type: u32" << std::endl; + if (verbose) section("Result:"); + std::cout << r.u32 << std::endl; + break; + } + case (LCompilers::PythonCompiler::EvalResult::unsignedInteger8) : { + if (verbose) std::cout << "Return type: u64" << std::endl; + if (verbose) section("Result:"); + std::cout << r.u64 << std::endl; + break; + } + case (LCompilers::PythonCompiler::EvalResult::real4) : { + if (verbose) std::cout << "Return type: f32" << std::endl; + if (verbose) section("Result:"); + std::cout << std::setprecision(8) << r.f32 << std::endl; + break; + } + case (LCompilers::PythonCompiler::EvalResult::real8) : { + if (verbose) std::cout << "Return type: f64" << std::endl; + if (verbose) section("Result:"); + std::cout << std::setprecision(17) << r.f64 << std::endl; + break; + } + case (LCompilers::PythonCompiler::EvalResult::complex4) : { + if (verbose) std::cout << "Return type: c32" << std::endl; + if (verbose) section("Result:"); + std::cout << std::setprecision(8) << "(" << r.c32.re << ", " << r.c32.im << ")" << std::endl; + break; + } + case (LCompilers::PythonCompiler::EvalResult::complex8) : { + if (verbose) std::cout << "Return type: c64" << std::endl; + if (verbose) section("Result:"); + std::cout << std::setprecision(17) << "(" << r.c64.re << ", " << r.c64.im << ")" << std::endl; + break; + } + case (LCompilers::PythonCompiler::EvalResult::boolean) : { + if (verbose) std::cout << "Return type: logical" << std::endl; + if (verbose) section("Result:"); + std::cout << (r.b ? "True" : "False") << std::endl; + break; + } + case (LCompilers::PythonCompiler::EvalResult::string) : { + if (verbose) std::cout << "Return type: str" << std::endl; + if (verbose) section("Result:"); + std::cout << (r.str == nullptr ? "" : r.str) << std::endl; + break; + } + case (LCompilers::PythonCompiler::EvalResult::statement) : { + if (verbose) { + std::cout << "Return type: none" << std::endl; + section("Result:"); + std::cout << "(statement)" << std::endl; + } + break; + } + case (LCompilers::PythonCompiler::EvalResult::struct_type) : { + if (verbose) { + std::cout << "Return type: " + << LCompilers::ASRUtils::get_type_code(r.structure.ttype) + << std::endl; + } + if (verbose) section("Result:"); + std::cout << fe.aggregate_type_to_string(r) << std::endl; + break; + } + case (LCompilers::PythonCompiler::EvalResult::none) : { + if (verbose) { + std::cout << "Return type: none" << std::endl; + section("Result:"); + std::cout << "(nothing to execute)" << std::endl; + } + break; + } + default : throw LCompilers::LCompilersException("Return type not supported"); + } + } + return 0; +} + +/* + Compiles python to object file, if `to_jit` is false + otherwise execute python code using llvm JIT +*/ +int compile_python_using_llvm( const std::string &infile, const std::string &outfile, const std::string &runtime_library_dir, LCompilers::PassManager& pass_manager, CompilerOptions &compiler_options, - bool time_report, bool arg_c=false) + bool time_report, bool arg_c=false, bool to_jit=false) { Allocator al(4*1024); LCompilers::diag::Diagnostics diagnostics; @@ -697,7 +1057,7 @@ int compile_python_to_object_file( lm.files.push_back(fl); auto file_reading_start = std::chrono::high_resolution_clock::now(); - std::string input = LCompilers::read_file(infile); + std::string input = LCompilers::read_file_ok(infile); auto file_reading_end = std::chrono::high_resolution_clock::now(); times.push_back(std::make_pair("File reading", std::chrono::duration (file_reading_end - file_reading_start).count())); @@ -721,8 +1081,8 @@ int compile_python_to_object_file( diagnostics.diagnostics.clear(); auto ast_to_asr_start = std::chrono::high_resolution_clock::now(); LCompilers::Result - r1 = LCompilers::LPython::python_ast_to_asr(al, lm, *ast, diagnostics, compiler_options, - !(arg_c && compiler_options.disable_main), infile); + r1 = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *ast, diagnostics, compiler_options, + !(arg_c && compiler_options.po.disable_main), "__main__", infile); auto ast_to_asr_end = std::chrono::high_resolution_clock::now(); times.push_back(std::make_pair("AST to ASR", std::chrono::duration(ast_to_asr_end - ast_to_asr_start).count())); @@ -733,8 +1093,8 @@ int compile_python_to_object_file( return 2; } LCompilers::ASR::TranslationUnit_t* asr = r1.result; - if( compiler_options.disable_main ) { - int err = LCompilers::LPython::save_pyc_files(*asr, infile); + if( compiler_options.po.disable_main ) { + int err = LCompilers::LPython::save_pyc_files(*asr, infile, lm); if( err ) { return err; } @@ -742,55 +1102,87 @@ int compile_python_to_object_file( diagnostics.diagnostics.clear(); // ASR -> LLVM + if (compiler_options.emit_debug_info) { +#ifndef HAVE_RUNTIME_STACKTRACE + diagnostics.add(LCompilers::diag::Diagnostic( + "The `runtime stacktrace` is not enabled. To get the stacktraces, " + "re-build LPython with `-DWITH_RUNTIME_STACKTRACE=yes`", + LCompilers::diag::Level::Error, + LCompilers::diag::Stage::Semantic, {}) + ); + std::cerr << diagnostics.render(lm, compiler_options); + return 1; +#endif + } LCompilers::PythonCompiler fe(compiler_options); LCompilers::LLVMEvaluator e(compiler_options.target); - std::unique_ptr m; auto asr_to_llvm_start = std::chrono::high_resolution_clock::now(); LCompilers::Result> - res = fe.get_llvm3(*asr, pass_manager, diagnostics, infile); + res = fe.get_llvm3(*asr, pass_manager, diagnostics, lm, infile); auto asr_to_llvm_end = std::chrono::high_resolution_clock::now(); times.push_back(std::make_pair("ASR to LLVM", std::chrono::duration(asr_to_llvm_end - asr_to_llvm_start).count())); - if (compiler_options.emit_debug_info) { -#ifdef HAVE_RUNTIME_STACKTRACE - if (!compiler_options.emit_debug_line_column) { - diagnostics.add(LCompilers::diag::Diagnostic( - "The `emit_debug_line_column` is not enabled; please use the " - "`--debug-with-line-column` option to get the correct " - "location information", - LCompilers::diag::Level::Warning, - LCompilers::diag::Stage::Semantic, {}) - ); - } -#else - diagnostics.add(LCompilers::diag::Diagnostic( - "The `runtime stacktrace` is not enabled. To get the stacktraces, " - "re-build LPython with `-DWITH_RUNTIME_STACKTRACE=yes`", - LCompilers::diag::Level::Warning, - LCompilers::diag::Stage::Semantic, {}) - ); -#endif - } std::cerr << diagnostics.render(lm, compiler_options); if (!res.ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) print_time_report(times, time_report); return 3; } - m = std::move(res.result); - auto llvm_start = std::chrono::high_resolution_clock::now(); - e.save_object_file(*(m->m_m), outfile); - auto llvm_end = std::chrono::high_resolution_clock::now(); - times.push_back(std::make_pair("LLVM to binary", std::chrono::duration(llvm_end - llvm_start).count())); - print_time_report(times, time_report); + std::unique_ptr m = std::move(res.result); + + if (to_jit) { + LCompilers::LPython::DynamicLibrary cpython_lib; + LCompilers::LPython::DynamicLibrary symengine_lib; + + if (compiler_options.po.enable_cpython) { + LCompilers::LPython::open_cpython_library(cpython_lib); + } + if (compiler_options.enable_symengine) { + LCompilers::LPython::open_symengine_library(symengine_lib); + } + + auto llvm_start = std::chrono::high_resolution_clock::now(); + + bool call_stmts = false; + if (m->get_return_type("__module___main_____main__global_stmts") == "void") { + call_stmts = true; + } + + e.add_module(std::move(m)); + if (call_stmts) { + e.execfn("__module___main_____main__global_stmts"); + } + + if (compiler_options.po.enable_cpython) { + LCompilers::LPython::close_cpython_library(cpython_lib); + } + if (compiler_options.enable_symengine) { + LCompilers::LPython::close_symengine_library(symengine_lib); + } + + auto llvm_end = std::chrono::high_resolution_clock::now(); + times.push_back(std::make_pair("LLVM JIT execution", std::chrono::duration(llvm_end - llvm_start).count())); + print_time_report(times, time_report); + } else { + auto llvm_start = std::chrono::high_resolution_clock::now(); + e.save_object_file(*(m->m_m), outfile); + auto llvm_end = std::chrono::high_resolution_clock::now(); + times.push_back(std::make_pair("LLVM to binary", std::chrono::duration(llvm_end - llvm_start).count())); + print_time_report(times, time_report); + } return 0; } #endif -void do_print_rtlib_header_dir() { - std::string rtlib_header_dir = LCompilers::LPython::get_runtime_library_header_dir(); - std::cout << rtlib_header_dir << std::endl; +void do_print_rtl_header_dir() { + std::string rtl_header_dir = LCompilers::LPython::get_runtime_library_header_dir(); + std::cout << rtl_header_dir << std::endl; +} + +void do_print_rtl_dir() { + std::string rtl_dir = LCompilers::LPython::get_runtime_library_dir(); + std::cout << rtl_dir << std::endl; } int compile_to_binary_wasm( @@ -810,7 +1202,7 @@ int compile_to_binary_wasm( lm.files.push_back(fl); auto file_reading_start = std::chrono::high_resolution_clock::now(); - std::string input = LCompilers::read_file(infile); + std::string input = LCompilers::read_file_ok(infile); auto file_reading_end = std::chrono::high_resolution_clock::now(); times.push_back(std::make_pair("File reading", std::chrono::duration (file_reading_end - file_reading_start).count())); @@ -834,7 +1226,7 @@ int compile_to_binary_wasm( diagnostics.diagnostics.clear(); auto ast_to_asr_start = std::chrono::high_resolution_clock::now(); LCompilers::Result - r1 = LCompilers::LPython::python_ast_to_asr(al, lm, *ast, diagnostics, compiler_options, true, infile); + r1 = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *ast, diagnostics, compiler_options, true, "__main__", infile); auto ast_to_asr_end = std::chrono::high_resolution_clock::now(); times.push_back(std::make_pair("AST to ASR", std::chrono::duration(ast_to_asr_end - ast_to_asr_start).count())); std::cerr << diagnostics.render(lm, compiler_options); @@ -844,8 +1236,8 @@ int compile_to_binary_wasm( return 2; } LCompilers::ASR::TranslationUnit_t* asr = r1.result; - if( compiler_options.disable_main ) { - int err = LCompilers::LPython::save_pyc_files(*asr, infile); + if( compiler_options.po.disable_main ) { + int err = LCompilers::LPython::save_pyc_files(*asr, infile, lm); if( err ) { return err; } @@ -854,7 +1246,7 @@ int compile_to_binary_wasm( // ASR -> WASM auto asr_to_wasm_start = std::chrono::high_resolution_clock::now(); - LCompilers::Result res = LCompilers::asr_to_wasm(*asr, al, outfile, time_report, diagnostics); + LCompilers::Result res = LCompilers::asr_to_wasm(*asr, al, outfile, time_report, diagnostics, compiler_options); auto asr_to_wasm_end = std::chrono::high_resolution_clock::now(); times.push_back(std::make_pair("ASR to WASM", std::chrono::duration(asr_to_wasm_end - asr_to_wasm_start).count())); std::cerr << diagnostics.render(lm, compiler_options); @@ -883,7 +1275,7 @@ int compile_to_binary_x86( lm.files.push_back(fl); auto file_reading_start = std::chrono::high_resolution_clock::now(); - std::string input = LCompilers::read_file(infile); + std::string input = LCompilers::read_file_ok(infile); auto file_reading_end = std::chrono::high_resolution_clock::now(); times.push_back(std::make_pair("File reading", std::chrono::duration (file_reading_end - file_reading_start).count())); @@ -907,7 +1299,7 @@ int compile_to_binary_x86( diagnostics.diagnostics.clear(); auto ast_to_asr_start = std::chrono::high_resolution_clock::now(); LCompilers::Result - r1 = LCompilers::LPython::python_ast_to_asr(al, lm, *ast, diagnostics, compiler_options, true, infile); + r1 = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *ast, diagnostics, compiler_options, true, "__main__", infile); auto ast_to_asr_end = std::chrono::high_resolution_clock::now(); times.push_back(std::make_pair("AST to ASR", std::chrono::duration(ast_to_asr_end - ast_to_asr_start).count())); std::cerr << diagnostics.render(lm, compiler_options); @@ -917,8 +1309,8 @@ int compile_to_binary_x86( return 2; } LCompilers::ASR::TranslationUnit_t* asr = r1.result; - if( compiler_options.disable_main ) { - int err = LCompilers::LPython::save_pyc_files(*asr, infile); + if( compiler_options.po.disable_main ) { + int err = LCompilers::LPython::save_pyc_files(*asr, infile, lm); if( err ) { return err; } @@ -957,7 +1349,7 @@ int compile_to_binary_wasm_to_x86( lm.files.push_back(fl); auto file_reading_start = std::chrono::high_resolution_clock::now(); - std::string input = LCompilers::read_file(infile); + std::string input = LCompilers::read_file_ok(infile); auto file_reading_end = std::chrono::high_resolution_clock::now(); times.push_back(std::make_pair("File reading", std::chrono::duration (file_reading_end - file_reading_start).count())); @@ -981,7 +1373,7 @@ int compile_to_binary_wasm_to_x86( diagnostics.diagnostics.clear(); auto ast_to_asr_start = std::chrono::high_resolution_clock::now(); LCompilers::Result - r1 = LCompilers::LPython::python_ast_to_asr(al, lm, *ast, diagnostics, compiler_options, true, infile); + r1 = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *ast, diagnostics, compiler_options, true, "__main__", infile); auto ast_to_asr_end = std::chrono::high_resolution_clock::now(); times.push_back(std::make_pair("AST to ASR", std::chrono::duration(ast_to_asr_end - ast_to_asr_start).count())); std::cerr << diagnostics.render(lm, compiler_options); @@ -991,8 +1383,8 @@ int compile_to_binary_wasm_to_x86( return 2; } LCompilers::ASR::TranslationUnit_t* asr = r1.result; - if( compiler_options.disable_main ) { - int err = LCompilers::LPython::save_pyc_files(*asr, infile); + if( compiler_options.po.disable_main ) { + int err = LCompilers::LPython::save_pyc_files(*asr, infile, lm); if( err ) { return err; } @@ -1001,7 +1393,7 @@ int compile_to_binary_wasm_to_x86( // ASR -> WASM auto asr_to_wasm_start = std::chrono::high_resolution_clock::now(); - LCompilers::Result> r3 = LCompilers::asr_to_wasm_bytes_stream(*asr, al, diagnostics); + LCompilers::Result> r3 = LCompilers::asr_to_wasm_bytes_stream(*asr, al, diagnostics, compiler_options); auto asr_to_wasm_end = std::chrono::high_resolution_clock::now(); times.push_back(std::make_pair("ASR to WASM", std::chrono::duration(asr_to_wasm_end - asr_to_wasm_start).count())); std::cerr << diagnostics.render(lm, compiler_options); @@ -1136,8 +1528,24 @@ int link_executable(const std::vector &infiles, for (auto &s : infiles) { cmd += s + " "; } + if (compiler_options.enable_symengine) { + cmd += " -I${CONDA_PREFIX}/include"; + } cmd += + " -L" + base_path + " -Wl,-rpath," + base_path + " -l" + runtime_lib + " -lm"; + if (compiler_options.enable_symengine) { + cmd += " -L$CONDA_PREFIX/lib -Wl,-rpath -Wl,$CONDA_PREFIX/lib -lsymengine"; + } + + if (compiler_options.po.enable_cpython) { + std::string py_version = "3.10"; + std::string py_flags = R"(-I $CONDA_PREFIX/include/python)" + py_version + R"( -L$CONDA_PREFIX/lib -Wl,-rpath -Wl,$CONDA_PREFIX/lib -lpython)" + py_version + R"()"; + if (compiler_options.link_numpy) { + py_flags += R"( -I$CONDA_PREFIX/lib/python)" + py_version + R"(/site-packages/numpy/core/include)"; + } + cmd += " " + py_flags; + } + int err = system(cmd.c_str()); if (err) { std::cout << "The command '" + cmd + "' failed." << std::endl; @@ -1174,10 +1582,28 @@ int link_executable(const std::vector &infiles, } else if (backend == Backend::c) { std::string CXX = "gcc"; std::string cmd = CXX + " -o " + outfile + " "; + std::string base_path = "\"" + runtime_library_dir + "\""; + std::string runtime_lib = "lpython_runtime"; for (auto &s : infiles) { cmd += s + " "; } cmd += " -I " + rtlib_header_dir; + if (compiler_options.enable_symengine) { + cmd += " -I${CONDA_PREFIX}/include"; + } + cmd += " -L" + base_path + + " -Wl,-rpath," + base_path + " -l" + runtime_lib + " -lm"; + if (compiler_options.enable_symengine) { + cmd += " -L$CONDA_PREFIX/lib -Wl,-rpath -Wl,$CONDA_PREFIX/lib -lsymengine"; + } + if (compiler_options.po.enable_cpython) { + std::string py_version = "3.10"; + std::string py_flags = R"(-I $CONDA_PREFIX/include/python)" + py_version + R"( -L$CONDA_PREFIX/lib -Wl,-rpath -Wl,$CONDA_PREFIX/lib -lpython)" + py_version + R"()"; + if (compiler_options.link_numpy) { + py_flags += R"( -I$CONDA_PREFIX/lib/python)" + py_version + R"(/site-packages/numpy/core/include)"; + } + cmd += " " + py_flags; + } int err = system(cmd.c_str()); if (err) { std::cout << "The command '" + cmd + "' failed." << std::endl; @@ -1200,7 +1626,7 @@ int link_executable(const std::vector &infiles, // int emit_c_preprocessor(const std::string &infile, CompilerOptions &compiler_options) // { -// std::string input = read_file(infile); +// std::string input = read_file_ok(infile); // // LFortran::CPreprocessor cpp(compiler_options); // LFortran::LocationManager lm; @@ -1259,10 +1685,10 @@ EMSCRIPTEN_KEEPALIVE char* emit_asr_from_source(char *input) { if (ast.ok) { auto casted_ast = (LCompilers::LPython::AST::ast_t*)ast.result; LCompilers::Result - asr = LCompilers::LPython::python_ast_to_asr(al, lm, *casted_ast, diagnostics, compiler_options, true, "input"); + asr = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *casted_ast, diagnostics, compiler_options, true, "__main__", "input"); out = diagnostics.render(lm, compiler_options); if (asr.ok) { - out += LCompilers::LPython::pickle(*asr.result, compiler_options.use_colors, compiler_options.indent, + out += LCompilers::pickle(*asr.result, compiler_options.use_colors, compiler_options.indent, false /* with_intrinsic_modules */); } } @@ -1277,11 +1703,11 @@ EMSCRIPTEN_KEEPALIVE char* emit_wat_from_source(char *input) { if (ast.ok) { auto casted_ast = (LCompilers::LPython::AST::ast_t*)ast.result; LCompilers::Result - asr = LCompilers::LPython::python_ast_to_asr(al, lm, *casted_ast, diagnostics, compiler_options, true, "input"); + asr = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *casted_ast, diagnostics, compiler_options, true, "__main__", "input"); out = diagnostics.render(lm, compiler_options); if (asr.ok) { LCompilers::Result> - wasm = LCompilers::asr_to_wasm_bytes_stream(*asr.result, al, diagnostics); + wasm = LCompilers::asr_to_wasm_bytes_stream(*asr.result, al, diagnostics, compiler_options); out = diagnostics.render(lm, compiler_options); if (wasm.ok) { LCompilers::Result @@ -1304,7 +1730,7 @@ EMSCRIPTEN_KEEPALIVE char* emit_cpp_from_source(char *input) { if (ast.ok) { auto casted_ast = (LCompilers::LPython::AST::ast_t*)ast.result; LCompilers::Result - asr = LCompilers::LPython::python_ast_to_asr(al, lm, *casted_ast, diagnostics, compiler_options, true, "input"); + asr = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *casted_ast, diagnostics, compiler_options, true, "__main__", "input"); out = diagnostics.render(lm, compiler_options); if (asr.ok) { auto res = LCompilers::asr_to_cpp(al, *asr.result, diagnostics, @@ -1342,11 +1768,11 @@ EMSCRIPTEN_KEEPALIVE char* emit_wasm_from_source(char *input) { if (ast.ok) { auto casted_ast = (LCompilers::LPython::AST::ast_t*)ast.result; LCompilers::Result - asr = LCompilers::LPython::python_ast_to_asr(al, lm, *casted_ast, diagnostics, compiler_options, true, "input"); + asr = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *casted_ast, diagnostics, compiler_options, true, "__main__", "input"); out = diagnostics.render(lm, compiler_options); if (asr.ok) { LCompilers::Result> - wasm = LCompilers::asr_to_wasm_bytes_stream(*asr.result, al, diagnostics); + wasm = LCompilers::asr_to_wasm_bytes_stream(*asr.result, al, diagnostics, compiler_options); out = diagnostics.render(lm, compiler_options); if (wasm.ok) { out = "0"; // exit code @@ -1397,12 +1823,14 @@ int main(int argc, char *argv[]) bool show_asr = false; bool show_cpp = false; bool show_c = false; + bool show_python = false; bool show_document_symbols = false; bool show_errors = false; bool with_intrinsic_modules = false; std::string arg_pass; std::string skip_pass; bool arg_no_color = false; + bool arg_no_indent = false; bool show_llvm = false; bool show_asm = false; bool show_wat = false; @@ -1411,7 +1839,12 @@ int main(int argc, char *argv[]) std::string arg_backend = "llvm"; std::string arg_kernel_f; bool print_targets = false; - bool print_rtlib_header_dir = false; + bool print_rtl_header_dir = false; + bool print_rtl_dir = false; + bool separate_compilation = false; + bool to_jit = false; + bool disable_warnings = false; + bool hide_error_banner = false; std::string arg_fmt_file; // int arg_fmt_indent = 4; @@ -1442,9 +1875,10 @@ int main(int argc, char *argv[]) // app.add_flag("-E", arg_E, "Preprocess only; do not compile, assemble or link"); // app.add_option("-l", arg_l, "Link library option"); // app.add_option("-L", arg_L, "Library path option"); - app.add_option("-I", compiler_options.import_path, "Specify the path" + app.add_option("-I", compiler_options.import_paths, "Specify the paths" "to look for the module")->allow_extra_args(false); // app.add_option("-J", arg_J, "Where to save mod files"); + app.add_flag("--jit", to_jit, "Execute the program using just-in-time (JIT) compiler"); app.add_flag("-g", compiler_options.emit_debug_info, "Compile with debugging information"); app.add_flag("--debug-with-line-column", compiler_options.emit_debug_line_column, "Convert the linear location info into line + column in the debugging information"); @@ -1460,29 +1894,45 @@ int main(int argc, char *argv[]) app.add_flag("--show-llvm", show_llvm, "Show LLVM IR for the given file and exit"); app.add_flag("--show-cpp", show_cpp, "Show C++ translation source for the given python file and exit"); app.add_flag("--show-c", show_c, "Show C translation source for the given python file and exit"); + app.add_flag("--show-python", show_python, "Show Python translation source for the given python file and exit"); app.add_flag("--show-asm", show_asm, "Show assembly for the given file and exit"); app.add_flag("--show-wat", show_wat, "Show WAT (WebAssembly Text Format) and exit"); app.add_flag("--show-stacktrace", compiler_options.show_stacktrace, "Show internal stacktrace on compiler errors"); app.add_flag("--with-intrinsic-mods", with_intrinsic_modules, "Show intrinsic modules in ASR"); app.add_flag("--no-color", arg_no_color, "Turn off colored AST/ASR"); - app.add_flag("--indent", compiler_options.indent, "Indented print ASR/AST"); - app.add_flag("--tree", compiler_options.tree, "Tree structure print ASR/AST"); - app.add_flag("--json", compiler_options.json, "Print ASR/AST Json format"); + app.add_flag("--no-indent", arg_no_indent, "Turn off Indented print ASR/AST"); + app.add_flag("--tree", compiler_options.po.tree, "Tree structure print ASR/AST"); + app.add_flag("--json", compiler_options.po.json, "Print ASR/AST Json format"); + app.add_flag("--no-loc", compiler_options.po.no_loc, "Skip location information in ASR/AST Json format"); + app.add_flag("--visualize", compiler_options.po.visualize, "Print ASR/AST Visualization"); app.add_option("--pass", arg_pass, "Apply the ASR pass and show ASR (implies --show-asr)"); app.add_option("--skip-pass", skip_pass, "Skip an ASR pass in default pipeline"); - app.add_flag("--disable-main", compiler_options.disable_main, "Do not generate any code for the `main` function"); + app.add_flag("--disable-main", compiler_options.po.disable_main, "Do not generate any code for the `main` function"); app.add_flag("--symtab-only", compiler_options.symtab_only, "Only create symbol tables in ASR (skip executable stmt)"); app.add_flag("--time-report", time_report, "Show compilation time report"); app.add_flag("--static", static_link, "Create a static executable"); - app.add_flag("--no-warnings", compiler_options.no_warnings, "Turn off all warnings"); - app.add_flag("--no-error-banner", compiler_options.no_error_banner, "Turn off error banner"); + app.add_flag("--no-warnings", disable_warnings, "Turn off all warnings"); + app.add_flag("--no-error-banner", hide_error_banner, "Turn off error banner"); app.add_option("--backend", arg_backend, "Select a backend (llvm, cpp, x86, wasm, wasm_x86, wasm_x64)")->capture_default_str(); - app.add_flag("--enable-bounds-checking", compiler_options.enable_bounds_checking, "Turn on index bounds checking"); + app.add_flag("--enable-bounds-checking", compiler_options.bounds_checking, "Turn on index bounds checking"); app.add_flag("--openmp", compiler_options.openmp, "Enable openmp"); - app.add_flag("--fast", compiler_options.fast, "Best performance (disable strict standard compliance)"); + app.add_flag("--fast", compiler_options.po.fast, "Best performance (disable strict standard compliance)"); app.add_option("--target", compiler_options.target, "Generate code for the given target")->capture_default_str(); app.add_flag("--print-targets", print_targets, "Print the registered targets"); - app.add_flag("--get-rtlib-header-dir", print_rtlib_header_dir, "Print the path to the runtime library header file"); + app.add_flag("--get-rtl-header-dir", print_rtl_header_dir, "Print the path to the runtime library header file"); + app.add_flag("--get-rtl-dir", print_rtl_dir, "Print the path to the runtime library file"); + app.add_flag("--verbose", compiler_options.po.verbose, "Print debugging statements"); + app.add_flag("--dump-all-passes", compiler_options.po.dump_all_passes, "Apply all the passes and dump the ASR into a file"); + app.add_flag("--dump-all-passes-fortran", compiler_options.po.dump_fortran, "Apply all passes and dump the ASR after each pass into fortran file"); + app.add_flag("--cumulative", compiler_options.po.pass_cumulative, "Apply all the passes cumulatively till the given pass"); + app.add_flag("--enable-cpython", compiler_options.po.enable_cpython, "Enable CPython runtime"); + app.add_flag("--enable-symengine", compiler_options.enable_symengine, "Enable Symengine runtime"); + app.add_flag("--link-numpy", compiler_options.link_numpy, "Enable NumPy runtime (implies --enable-cpython)"); + app.add_flag("--separate-compilation", separate_compilation, "Generates unique names for all the symbols"); + app.add_flag("--module-mangling", compiler_options.po.module_name_mangling, "Mangles the module name"); + app.add_flag("--global-mangling", compiler_options.po.global_symbols_mangling, "Mangles all the global symbols"); + app.add_flag("--intrinsic-mangling", compiler_options.po.intrinsic_symbols_mangling, "Mangles all the intrinsic symbols"); + app.add_flag("--all-mangling", compiler_options.po.all_symbols_mangling, "Mangles all possible symbols"); // LSP specific options app.add_flag("--show-errors", show_errors, "Show errors when LSP is running in the background"); @@ -1520,29 +1970,38 @@ int main(int argc, char *argv[]) app.require_subcommand(0, 1); CLI11_PARSE(app, argc, argv); - if( compiler_options.fast && compiler_options.enable_bounds_checking ) { + lcompilers_unique_ID_separate_compilation = separate_compilation ? LCompilers::get_unique_ID(): ""; + + + if( compiler_options.po.fast && compiler_options.bounds_checking ) { // ReleaseSafe Mode - } else if ( compiler_options.fast ) { + } else if ( compiler_options.po.fast ) { // Release Mode - lpython_pass_manager.use_optimization_passes(); + // No need to do anything, compiler_options.po.fast + // sends the signal to pass_manager when passes are applied + // Earlier it was redundant to call `use_optimisation_passes` + // which is now removed } else { // Debug Mode - compiler_options.enable_bounds_checking = true; + compiler_options.bounds_checking = true; + } + + if (compiler_options.link_numpy) { + compiler_options.po.enable_cpython = true; + } + + if (disable_warnings) { + compiler_options.show_warnings = false; + } + + if (hide_error_banner) { + compiler_options.show_error_banner = false; } if (arg_version) { std::string version = LFORTRAN_VERSION; std::cout << "LPython version: " << version << std::endl; - std::cout << "Platform: "; - switch (compiler_options.platform) { - case (LCompilers::Platform::Linux) : std::cout << "Linux"; break; - case (LCompilers::Platform::macOS_Intel) : std::cout << "macOS Intel"; break; - case (LCompilers::Platform::macOS_ARM) : std::cout << "macOS ARM"; break; - case (LCompilers::Platform::Windows) : std::cout << "Windows"; break; - case (LCompilers::Platform::FreeBSD) : std::cout << "FreeBSD"; break; - case (LCompilers::Platform::OpenBSD) : std::cout << "OpenBSD"; break; - } - std::cout << std::endl; + std::cout << "Platform: " << pf2s(compiler_options.platform) << std::endl; #ifdef HAVE_LFORTRAN_LLVM std::cout << "Default target: " << LCompilers::LLVMEvaluator::get_default_target_triple() << std::endl; #endif @@ -1559,12 +2018,18 @@ int main(int argc, char *argv[]) #endif } - if (print_rtlib_header_dir) { - do_print_rtlib_header_dir(); + if (print_rtl_header_dir) { + do_print_rtl_header_dir(); + return 0; + } + + if (print_rtl_dir) { + do_print_rtl_dir(); return 0; } compiler_options.use_colors = !arg_no_color; + compiler_options.indent = !arg_no_indent; // if (fmt) { // return format(arg_fmt_file, arg_fmt_inplace, !arg_fmt_no_color, @@ -1572,8 +2037,12 @@ int main(int argc, char *argv[]) // } if (kernel) { - std::cerr << "The kernel subcommand is not implemented yet for LPython." << std::endl; - return 1; +#ifdef HAVE_LFORTRAN_XEUS + return LCompilers::LPython::run_kernel(arg_kernel_f); +#else + std::cerr << "The kernel subcommand requires LFortran to be compiled with XEUS support. Recompile with `WITH_XEUS=yes`." << std::endl; + return 1; +#endif } // if (mod) { @@ -1612,15 +2081,25 @@ int main(int argc, char *argv[]) } if (arg_files.size() == 0) { - std::cerr << "Interactive prompt is not implemented yet in LPython" << std::endl; +#ifdef HAVE_LFORTRAN_LLVM + lpython_pass_manager.parse_pass_arg(arg_pass, skip_pass); + lpython_pass_manager.use_default_passes(); + compiler_options.po.disable_main = true; + compiler_options.emit_debug_line_column = false; + compiler_options.separate_compilation = false; + return interactive_python_repl(lpython_pass_manager, compiler_options, arg_v); +#else + std::cerr << "Interactive prompt requires the LLVM backend to be enabled. Recompile with `WITH_LLVM=yes`." << std::endl; return 1; +#endif } // TODO: for now we ignore the other filenames, only handle // the first: std::string arg_file = arg_files[0]; if (CLI::NonexistentPath(arg_file).empty()){ - throw LCompilers::LCompilersException("No such file or directory: " + arg_file); + std::cerr << "The input file does not exist: " << arg_file << std::endl; + return 1; } std::string outfile; @@ -1647,6 +2126,10 @@ int main(int argc, char *argv[]) outfile = basename + ".out"; } + if (compiler_options.po.dump_fortran || compiler_options.po.dump_all_passes) { + dump_all_passes(arg_file, runtime_library_dir, compiler_options); + } + // if (arg_E) { // return emit_c_preprocessor(arg_file, compiler_options); // } @@ -1666,7 +2149,12 @@ int main(int argc, char *argv[]) return emit_cpp(arg_file, runtime_library_dir, compiler_options); } if (show_c) { - return emit_c(arg_file, runtime_library_dir, compiler_options); + compiler_options.po.c_mangling = true; + return emit_c(arg_file, runtime_library_dir, lpython_pass_manager, + compiler_options); + } + if (show_python) { + return emit_python(arg_file, runtime_library_dir, compiler_options); } if (show_wat) { return emit_wat(arg_file, runtime_library_dir, compiler_options); @@ -1713,10 +2201,10 @@ int main(int argc, char *argv[]) } } - if (arg_c) { + if (arg_c && !to_jit) { if (backend == Backend::llvm) { #ifdef HAVE_LFORTRAN_LLVM - return compile_python_to_object_file(arg_file, outfile, runtime_library_dir, lpython_pass_manager, compiler_options, time_report, + return compile_python_using_llvm(arg_file, outfile, runtime_library_dir, lpython_pass_manager, compiler_options, time_report, arg_c); #else std::cerr << "The -c option requires the LLVM backend to be enabled. Recompile with `WITH_LLVM=yes`." << std::endl; @@ -1730,6 +2218,23 @@ int main(int argc, char *argv[]) if (endswith(arg_file, ".py")) { int err = 0; + if (to_jit) { +#ifdef HAVE_LFORTRAN_LLVM + if (backend != Backend::llvm) { + std::cerr << "JIT option is only available with LLVM backend" << std::endl; + return 1; + } + compiler_options.emit_debug_info = false; + compiler_options.emit_debug_line_column = false; + compiler_options.separate_compilation = false; + return compile_python_using_llvm(arg_file, "", runtime_library_dir, + lpython_pass_manager, compiler_options, time_report, false, true); +#else + std::cerr << "Just-In-Time Compilation of Python files requires the LLVM backend to be enabled." + " Recompile with `WITH_LLVM=yes`." << std::endl; + return 1; +#endif + } if (backend == Backend::x86) { err = compile_to_binary_x86(arg_file, outfile, runtime_library_dir, compiler_options, time_report); @@ -1740,19 +2245,21 @@ int main(int argc, char *argv[]) err = compile_to_binary_wasm_to_x86(arg_file, outfile, runtime_library_dir, compiler_options, time_report, backend); } else if (backend == Backend::c) { + compiler_options.po.c_mangling = true; std::string emit_file_name = basename + "__tmp__generated__.c"; - err = emit_c_to_file(arg_file, emit_file_name, runtime_library_dir, compiler_options); + err = emit_c_to_file(arg_file, emit_file_name, runtime_library_dir, + lpython_pass_manager, compiler_options); + if (err != 0) return err; err = link_executable({emit_file_name}, outfile, runtime_library_dir, backend, static_link, true, compiler_options, rtlib_header_dir); } else if (backend == Backend::llvm) { #ifdef HAVE_LFORTRAN_LLVM std::string tmp_o = outfile + ".tmp.o"; - err = compile_python_to_object_file(arg_file, tmp_o, runtime_library_dir, + err = compile_python_using_llvm(arg_file, tmp_o, runtime_library_dir, lpython_pass_manager, compiler_options, time_report); if (err != 0) return err; err = link_executable({tmp_o}, outfile, runtime_library_dir, backend, static_link, true, compiler_options, rtlib_header_dir); - if (err != 0) return err; #ifdef HAVE_RUNTIME_STACKTRACE if (compiler_options.emit_debug_info) { @@ -1764,14 +2271,14 @@ int main(int argc, char *argv[]) #else cmd += "llvm-dwarfdump --debug-line " + basename + ".out > "; #endif - cmd += basename + "_ldd.txt && (cd src/bin; ./dwarf_convert.py ../../" - + basename + "_ldd.txt ../../" + basename + "_lines.txt ../../" - + basename + "_lines.dat && ./dat_convert.py ../../" + cmd += basename + "_ldd.txt && (cd libasr/src/libasr; ./dwarf_convert.py ../../../" + + basename + "_ldd.txt ../../../" + basename + "_lines.txt ../../../" + + basename + "_lines.dat && ./dat_convert.py ../../../" + basename + "_lines.dat)"; int status = system(cmd.c_str()); if ( status != 0 ) { std::cerr << "Error in creating the files used to generate " - "the debug information. This might be caused because either" + "the debug information. This might be caused because either " "`llvm-dwarfdump` or `Python` are not available. " "Please activate the CONDA environment and compile again.\n"; return status; @@ -1785,7 +2292,7 @@ int main(int argc, char *argv[]) } else { throw LCompilers::LCompilersException("Unsupported backend."); } - + if (err != 0) return err; if (compiler_options.arg_o == "") { if (backend == Backend::wasm) { err = system(("node --experimental-wasi-unstable-preview1 " + outfile +".js").c_str()); diff --git a/src/libasr/ASR.asdl b/src/libasr/ASR.asdl deleted file mode 100644 index 5139f99481..0000000000 --- a/src/libasr/ASR.asdl +++ /dev/null @@ -1,425 +0,0 @@ --- Abstract Semantic Representation (ASR) definition - --- The aim of ASR is to represent all semantics in a non-redundant way, and that --- has all the semantic information available locally, so that the backend can --- do a single pass over ASR and have all the information at hand to generate --- code. --- --- ASR is always semantically valid Fortran code. It is as far from the original --- Fortran language code as possible (i.e. everything is explicitly figured out, --- all semantic information gathered and readily available locally from each ASR --- node), while ensuring no semantic information was lost (no lowering was --- done), so one can still generate Fortran code from ASR that will be logically --- equivalent to the original code. --- --- ASR can be used to do Fortran level transformations (such as optimizations). - --- ASDL's builtin types are: --- * identifier --- * int (signed integers of infinite precision) --- * string --- We extend these by: --- * bool (.true. / .false.) --- * float (floating point number of infinite precision) --- * symbol_table (scoped Symbol Table implementation) --- * node (any ASR node) --- --- Note: `symbol_table` contains `identifier` -> `symbol` mappings. - -module ASR { - -unit - = TranslationUnit(symbol_table global_scope, node* items) - --- # Documentation for the symbol type - --- Each symbol has either `symtab` (local symbol table) or `parent_symtab` --- (where this symbol is stored). One can get to parent_symtab via symtab, so --- only one is present. - --- Each symbol has a `name` for easy lookup of the name of the symbol when only --- having a pointer to it. - --- abi=Source means the symbol's implementation is included (full ASR), --- otherwise it is external (interface ASR, such as procedure interface). - --- SubroutineCall/FunctionCall store the actual final resolved subroutine or --- function (`name` member). They also store the original symbol --- (`original_name`), which can be one of: null, GenericProcedure or --- ExternalSymbol. - --- When a module is compiled, it is parsed into full ASR, an object file is --- produced, the full ASR (abi=Source, "body" is non-empty) is transformed into --- interface ASR (abi=LFortran, "body" is empty). Both interface and full ASR --- is saved into the mod file. - --- When a module is used, it is first looked up in the symbol table (as either --- full or interface ASR) and used if it is present. Otherwise a mod file is --- found on the disk, loaded (as either full or interface ASR for LFortran's --- mod file, depending on LFortran's compiler options; or for GFortran's mod --- file the corresponding interface ASR is constructed with abi=GFortran) and --- used. After the ASR is loaded, the symbols that are used are represented as --- ExternalSymbols in the current scope of the symbol table. - --- ExternalSymbol represents symbols that cannot be looked up in the current --- scoped symbol table. As an example, if a variable is defined in a module, --- but used in a nested subroutine, that is not an external symbol --- because it can be resolved in the current symbol table (nested subroutine) --- by following the parents. However if a symbol is used from a different --- module, then it is an external symbol, because usual symbol resolution by --- going to the parents will not find the definition. The `module_name` member --- is the name of the module the symbol is in, the `scope_names` is a list of --- names if the symbol is in a nested symbol table. For example if it is a --- local variable in a function `f` that is nested in function `g`, then --- `scope_names=[g, f]`. - --- REPL: each cell is parsed into full ASR, compiled + executed, the full ASR --- is transformed into interface ASR (abi=LFortran) and kept in the symbol --- table. A new cell starts with an empty symbol table, whose parent symbol --- table is the previous cell. That allows function / declaration shadowing. - - -symbol - = Program(symbol_table symtab, identifier name, identifier* dependencies, - stmt* body) - | Module(symbol_table symtab, identifier name, identifier* dependencies, - bool loaded_from_mod, bool intrinsic) - | Function(symbol_table symtab, identifier name, ttype function_signature, - identifier* dependencies, expr* args, stmt* body, expr? return_var, - access access, bool deterministic, bool side_effect_free) - | GenericProcedure(symbol_table parent_symtab, identifier name, - symbol* procs, access access) - | CustomOperator(symbol_table parent_symtab, identifier name, - symbol* procs, access access) - | ExternalSymbol(symbol_table parent_symtab, identifier name, - symbol external, identifier module_name, identifier* scope_names, - identifier original_name, access access) - | StructType(symbol_table symtab, identifier name, identifier* dependencies, - identifier* members, abi abi, access access, bool is_packed, - expr? alignment, symbol? parent) - | EnumType(symbol_table symtab, identifier name, identifier* dependencies, - identifier* members, abi abi, access access, enumtype enum_value_type, - ttype type, symbol? parent) - | UnionType(symbol_table symtab, identifier name, identifier* dependencies, - identifier* members, abi abi, access access, symbol? parent) - | Variable(symbol_table parent_symtab, identifier name, identifier* dependencies, - intent intent, expr? symbolic_value, expr? value, storage_type storage, ttype type, - abi abi, access access, presence presence, bool value_attr) - | ClassType(symbol_table symtab, identifier name, abi abi, access access) - | ClassProcedure(symbol_table parent_symtab, identifier name, identifier? self_argument, - identifier proc_name, symbol proc, abi abi) - | AssociateBlock(symbol_table symtab, identifier name, stmt* body) - | Block(symbol_table symtab, identifier name, stmt* body) - -storage_type = Default | Save | Parameter | Allocatable -access = Public | Private -intent = Local | In | Out | InOut | ReturnVar | Unspecified -deftype = Implementation | Interface -presence = Required | Optional - --- # Documentation for the ABI type - --- External Yes: the symbol's implementation is not part of ASR, the --- symbol is just an interface (e.g., subroutine/function interface, or variable --- marked as external, not allocated by this ASR). - --- External No: the symbol's implementation is part of ASR (e.g., --- subroutine/function body is included, variables must be allocated). - --- abi=Source: The symbol's implementation is included in ASR, the backend is --- free to use any ABI it wants (it might also decide to inline or eliminate --- the code in optimizations). - --- abi=LFortranModule/GFortranModule/BindC: the symbol's implementation is --- stored as machine code in some object file that must be linked in. It --- uses the specified ABI (one of LFortran module, GFortran module or C ABI). --- An interface that uses `iso_c_binding` and `bind(c)` is represented using --- abi=BindC. - --- abi=Interactive: the symbol's implementation has been provided by the --- previous REPL execution (e.g., if LLVM backend is used for the interactive --- mode, the previous execution generated machine code for this symbol's --- implementation that was loaded into memory). Note: this option might be --- converted/eliminated to just use LFortran ABI in the future. - --- abi=Intrinsic: the symbol's implementation is implicitly provided by the --- language itself as an intrinsic function. That means the backend is free to --- implement it in any way it wants. The function does not have a body, it is --- just an interface. - -abi -- External ABI - = Source -- No Unspecified - | LFortranModule -- Yes LFortran - | GFortranModule -- Yes GFortran - | BindC -- Yes C - | Interactive -- Yes Unspecified - | Intrinsic -- Yes Unspecified - - -stmt - = Allocate(alloc_arg* args, expr? stat, expr? errmsg, expr? source) - | Assign(int label, identifier variable) - | Assignment(expr target, expr value, stmt? overloaded) - | Associate(expr target, expr value) - | Cycle() - -- deallocates if allocated otherwise throws a runtime error - | ExplicitDeallocate(expr* vars) - -- deallocates if allocated otherwise does nothing - | ImplicitDeallocate(symbol* vars) - | DoConcurrentLoop(do_loop_head head, stmt* body) - | DoLoop(do_loop_head head, stmt* body) - | ErrorStop(expr? code) - | Exit() - | ForAllSingle(do_loop_head head, stmt assign_stmt) - -- GoTo points to a GoToTarget with the corresponding target_id within - -- the same procedure. We currently use `int` IDs to link GoTo with - -- GoToTarget to avoid issues with serialization. - | GoTo(int target_id, identifier name) - -- An empty statement, a target of zero or more GoTo statements - -- the `id` is only unique within a procedure - | GoToTarget(int id, identifier name) - | If(expr test, stmt* body, stmt* orelse) - | IfArithmetic(expr test, int lt_label, int eq_label, int gt_label) - | Print(expr? fmt, expr* values, expr? separator, expr? end) - | FileOpen(int label, expr? newunit, expr? filename, expr? status) - | FileClose(int label, expr? unit, expr? iostat, expr? iomsg, expr? err, expr? status) - | FileRead(int label, expr? unit, expr? fmt, expr? iomsg, expr? iostat, expr? id, expr* values) - | FileBackspace(int label, expr? unit, expr? iostat, expr? err) - | FileRewind(int label, expr? unit, expr? iostat, expr? err) - | FileInquire(int label, expr? unit, expr? file, expr? iostat, expr? err, - expr? exist, expr? opened, expr? number, expr? named, - expr? name, expr? access, expr? sequential, expr? direct, - expr? form, expr? formatted, expr? unformatted, expr? recl, - expr? nextrec, expr? blank, expr? position, expr? action, - expr? read, expr? write, expr? readwrite, expr? delim, - expr? pad, expr? flen, expr? blocksize, expr? convert, - expr? carriagecontrol, expr? iolength) - | FileWrite(int label, expr? unit, expr? fmt, expr? iomsg, expr? iostat, expr? id, expr* values, expr? separator, expr? end) - | Return() - | Select(expr test, case_stmt* body, stmt* default) - | Stop(expr? code) - | Assert(expr test, expr? msg) - | SubroutineCall(symbol name, symbol? original_name, call_arg* args, expr? dt) - | Where(expr test, stmt* body, stmt* orelse) - | WhileLoop(expr test, stmt* body) - | Nullify(symbol* vars) - | Flush(int label, expr unit, expr? err, expr? iomsg, expr? iostat) - | ListAppend(expr a, expr ele) - | AssociateBlockCall(symbol m) - | SelectType(type_stmt* body, stmt* default) - | CPtrToPointer(expr cptr, expr ptr, expr? shape) - | BlockCall(int label, symbol m) - | SetInsert(expr a, expr ele) - | SetRemove(expr a, expr ele) - | ListInsert(expr a, expr pos, expr ele) - | ListRemove(expr a, expr ele) - | ListClear(expr a) - | DictInsert(expr a, expr key, expr value) - - -expr - = IfExp(expr test, expr body, expr orelse, ttype type, expr? value) - -- Such as: (x, y+z), (3.0, 2.0) generally not known at compile time - | ComplexConstructor(expr re, expr im, ttype type, expr? value) - | NamedExpr(expr target, expr value, ttype type) - | FunctionCall(symbol name, symbol? original_name, call_arg* args, - ttype type, expr? value, expr? dt) - | StructTypeConstructor(symbol dt_sym, call_arg* args, ttype type, expr? value) - | EnumTypeConstructor(symbol dt_sym, expr* args, ttype type, expr? value) - | UnionTypeConstructor(symbol dt_sym, expr* args, ttype type, expr? value) - | ImpliedDoLoop(expr* values, expr var, expr start, expr end, - expr? increment, ttype type, expr? value) - | IntegerConstant(int n, ttype type) - | IntegerBOZ(int v, integerboz intboz_type, ttype? type) - | IntegerBitNot(expr arg, ttype type, expr? value) - | IntegerUnaryMinus(expr arg, ttype type, expr? value) - | IntegerCompare(expr left, cmpop op, expr right, ttype type, expr? value) - | IntegerBinOp(expr left, binop op, expr right, ttype type, expr? value) - | RealConstant(float r, ttype type) - | RealUnaryMinus(expr arg, ttype type, expr? value) - | RealCompare(expr left, cmpop op, expr right, ttype type, expr? value) - | RealBinOp(expr left, binop op, expr right, ttype type, expr? value) - | ComplexConstant(float re, float im, ttype type) - | ComplexUnaryMinus(expr arg, ttype type, expr? value) - | ComplexCompare(expr left, cmpop op, expr right, ttype type, expr? value) - | ComplexBinOp(expr left, binop op, expr right, ttype type, expr? value) - | LogicalConstant(bool value, ttype type) - | LogicalNot(expr arg, ttype type, expr? value) - | LogicalCompare(expr left, cmpop op, expr right, ttype type, expr? value) - | LogicalBinOp(expr left, logicalbinop op, expr right, ttype type, expr? value) - - | ListConstant(expr* args, ttype type) - | ListLen(expr arg, ttype type, expr? value) - | ListConcat(expr left, expr right, ttype type, expr? value) - | ListCompare(expr left, cmpop op, expr right, ttype type, expr? value) - - | SetConstant(expr* elements, ttype type) - | SetLen(expr arg, ttype type, expr? value) - - | TupleConstant(expr* elements, ttype type) - | TupleLen(expr arg, ttype type, expr value) - | TupleCompare(expr left, cmpop op, expr right, ttype type, expr? value) - - | StringConstant(string s, ttype type) - | StringConcat(expr left, expr right, ttype type, expr? value) - | StringRepeat(expr left, expr right, ttype type, expr? value) - | StringLen(expr arg, ttype type, expr? value) - | StringItem(expr arg, expr idx, ttype type, expr? value) - | StringSection(expr arg, expr? start, expr? end, expr? step, ttype type, expr? value) - | StringCompare(expr left, cmpop op, expr right, ttype type, expr? value) - | StringOrd(expr arg, ttype type, expr? value) - | StringChr(expr arg, ttype type, expr? value) - - | DictConstant(expr* keys, expr* values, ttype type) - | DictLen(expr arg, ttype type, expr? value) - - | Var(symbol v) - - | ArrayConstant(expr* args, ttype type, arraystorage storage_format) - | ArrayItem(expr v, array_index* args, ttype type, arraystorage storage_format, expr? value) - | ArraySection(expr v, array_index* args, ttype type, expr? value) - | ArraySize(expr v, expr? dim, ttype type, expr? value) - | ArrayBound(expr v, expr? dim, ttype type, arraybound bound, - expr? value) - | ArrayTranspose(expr matrix, ttype type, expr? value) - | ArrayMatMul(expr matrix_a, expr matrix_b, ttype type, expr? value) - | ArrayPack(expr array, expr mask, expr? vector, ttype type, expr? value) - | ArrayReshape(expr array, expr shape, ttype type, expr? value) - | ArrayMaxloc(expr array, expr? dim, expr? mask, expr? kind, expr? back, ttype type, expr? value) - | ArrayAll(expr mask, expr? dim, ttype type, expr? value) - - | BitCast(expr source, expr mold, expr? size, ttype type, expr? value) - | StructInstanceMember(expr v, symbol m, ttype type, expr? value) - | StructStaticMember(expr v, symbol m, ttype type, expr? value) - | EnumStaticMember(expr v, symbol m, ttype type, expr? value) - | UnionInstanceMember(expr v, symbol m, ttype type, expr? value) - | EnumName(expr v, ttype enum_type, ttype type, expr? value) - | EnumValue(expr v, ttype enum_type, ttype type, expr? value) - | OverloadedCompare(expr left, cmpop op, expr right, ttype type, expr? value, expr overloaded) - | OverloadedBinOp(expr left, binop op, expr right, ttype type, expr? value, expr overloaded) - | Cast(expr arg, cast_kind kind, ttype type, expr? value) - | ComplexRe(expr arg, ttype type, expr? value) - | ComplexIm(expr arg, ttype type, expr? value) - | DictItem(expr a, expr key, expr? default, ttype type, expr? value) - | CLoc(expr arg, ttype type, expr? value) - | PointerToCPtr(expr arg, ttype type, expr? value) - | GetPointer(expr arg, ttype type, expr? value) - | ListItem(expr a, expr pos, ttype type, expr? value) - | TupleItem(expr a, expr pos, ttype type, expr? value) - | ListSection(expr a, array_index section, ttype type, expr? value) - | ListPop(expr a, expr? index, ttype type, expr? value) - | DictPop(expr a, expr key, ttype type, expr? value) - | SetPop(expr a, ttype type, expr? value) - | IntegerBitLen(expr a, ttype type, expr? value) - | Ichar(expr arg, ttype type, expr? value) - | Iachar(expr arg, ttype type, expr? value) - - | SizeOfType(ttype arg, ttype type, expr? value) - - | PointerNullConstant(ttype type) - | PointerAssociated(expr ptr, expr? tgt, ttype type, expr? value) - - | IntrinsicFunctionSqrt(expr arg, ttype type, expr? value) - - --- `len` in Character: --- >=0 ... the length of the string, known at compile time --- -1 ... character(*), i.e., inferred at runtime --- -2 ... character(:), allocatable (possibly we might use -1 for that also) --- -3 ... character(n+3), i.e., a runtime expression stored in `len_expr` - --- kind: The `kind` member selects the kind of a given type. We currently --- support the following: --- Integer kinds: 1 (i8), 2 (i16), 4 (i32), 8 (i64) --- Real kinds: 4 (f32), 8 (f64) --- Complex kinds: 4 (c32), 8 (c64) --- Character kinds: 1 (utf8 string) --- Logical kinds: 1, 2, 4: (boolean represented by 1, 2, 4 bytes; the default --- kind is 4, just like the default integer kind, consistent with Python --- and Fortran: in Python "Booleans in Python are implemented as a subclass --- of integers", in Fortran the "default logical kind has the same storage --- size as the default integer"; we currently use kind=4 as default --- integer, so we also use kind=4 for the default logical.) - -ttype - = Integer(int kind, dimension* dims) - | Real(int kind, dimension* dims) - | Complex(int kind, dimension* dims) - | Character(int kind, int len, expr? len_expr, dimension* dims) - | Logical(int kind, dimension* dims) - | Set(ttype type) - | List(ttype type) - | Tuple(ttype* type) - | Struct(symbol derived_type, dimension* dims) - | Enum(symbol enum_type, dimension *dims) - | Union(symbol union_type, dimension *dims) - | Class(symbol class_type, dimension* dims) - | Dict(ttype key_type, ttype value_type) - | Pointer(ttype type) - | Const(ttype type) - | CPtr() - | TypeParameter(identifier param, dimension* dims) - | FunctionType(ttype* arg_types, ttype? return_var_type, - abi abi, deftype deftype, string? bindc_name, bool elemental, - bool pure, bool module, bool inline, bool static, ttype* type_params, - symbol* restrictions, bool is_restriction) - -restriction_arg = RestrictionArg(identifier restriction_name, symbol restriction_func) - -binop = Add | Sub | Mul | Div | Pow | BitAnd | BitOr | BitXor | BitLShift | BitRShift - -logicalbinop = And | Or | Xor | NEqv | Eqv - -cmpop = Eq | NotEq | Lt | LtE | Gt | GtE - -integerboz = Binary | Hex | Octal - -arraybound = LBound | UBound - -arraystorage = RowMajor | ColMajor - -cast_kind - = RealToInteger - | IntegerToReal - | LogicalToReal - | RealToReal - | IntegerToInteger - | RealToComplex - | IntegerToComplex - | IntegerToLogical - | RealToLogical - | CharacterToLogical - | CharacterToInteger - | CharacterToList - | ComplexToLogical - | ComplexToComplex - | ComplexToReal - | ComplexToInteger - | LogicalToInteger - | RealToCharacter - | IntegerToCharacter - | LogicalToCharacter - -dimension = (expr? start, expr? length) - -alloc_arg = (expr a, dimension* dims) - -attribute = Attribute(identifier name, attribute_arg *args) - -attribute_arg = (identifier arg) - -call_arg = (expr? value) - -tbind = Bind(string lang, string name) - -array_index = (expr? left, expr? right, expr? step) - -do_loop_head = (expr? v, expr? start, expr? end, expr? increment) - -case_stmt = CaseStmt(expr* test, stmt* body) | CaseStmt_Range(expr? start, expr? end, stmt* body) - -type_stmt = TypeStmtName(symbol sym, stmt* body) | TypeStmtType(ttype type, stmt* body) - -enumtype = IntegerConsecutiveFromZero | IntegerUnique | IntegerNotUnique | NonInteger - -} diff --git a/src/libasr/CMakeLists.txt b/src/libasr/CMakeLists.txt deleted file mode 100644 index 6e577df9ae..0000000000 --- a/src/libasr/CMakeLists.txt +++ /dev/null @@ -1,105 +0,0 @@ -cmake_minimum_required(VERSION 3.10) - -project(libasr) - -if (NOT CMAKE_CXX_STANDARD) - set(CMAKE_CXX_STANDARD 17 - CACHE STRING "C++ standard" FORCE) -endif () - -if (NOT LFORTRAN_VERSION) - set(LFORTRAN_VERSION "0.1-git" - CACHE STRING "LFortran version" FORCE) -endif () - -configure_file(config.h.in config.h) - -set(SRC - codegen/asr_to_cpp.cpp - codegen/asr_to_c.cpp - codegen/asr_to_julia.cpp - codegen/asr_to_py.cpp - codegen/x86_assembler.cpp - codegen/asr_to_x86.cpp - codegen/asr_to_wasm.cpp - codegen/wasm_to_wat.cpp - codegen/wasm_to_x86.cpp - codegen/wasm_to_x64.cpp - codegen/wasm_utils.cpp - - pass/param_to_const.cpp - pass/do_loops.cpp - pass/for_all.cpp - pass/global_stmts.cpp - pass/global_stmts_program.cpp - pass/global_symbols.cpp - pass/select_case.cpp - pass/implied_do_loops.cpp - pass/array_op.cpp - pass/subroutine_from_function.cpp - pass/transform_optional_argument_functions.cpp - pass/class_constructor.cpp - pass/arr_slice.cpp - pass/print_arr.cpp - pass/print_list_tuple.cpp - pass/pass_utils.cpp - pass/unused_functions.cpp - pass/flip_sign.cpp - pass/div_to_mul.cpp - pass/fma.cpp - pass/loop_vectorise.cpp - pass/sign_from_value.cpp - pass/inline_function_calls.cpp - pass/loop_unroll.cpp - pass/dead_code_removal.cpp - pass/instantiate_template.cpp - pass/update_array_dim_intrinsic_calls.cpp - pass/pass_array_by_data.cpp - pass/pass_list_expr.cpp - pass/pass_compare.cpp - - asr_verify.cpp - asr_utils.cpp - diagnostics.cpp - stacktrace.cpp - string_utils.cpp - asr_scopes.cpp - modfile.cpp - serialization.cpp - utils2.cpp -) -if (WITH_LLVM) - set(SRC ${SRC} - codegen/evaluator.cpp - codegen/asr_to_llvm.cpp - codegen/llvm_array_utils.cpp - codegen/llvm_utils.cpp - pass/nested_vars.cpp - ) - # We use deprecated API in LLVM, so we disable the warning until we upgrade - if (NOT MSVC) - set_source_files_properties(codegen/evaluator.cpp PROPERTIES - COMPILE_FLAGS -Wno-deprecated-declarations) - set_source_files_properties(codegen/asr_to_llvm.cpp PROPERTIES - COMPILE_FLAGS -Wno-deprecated-declarations) - set_source_files_properties(codegen/llvm_array_utils.cpp PROPERTIES - COMPILE_FLAGS -Wno-deprecated-declarations) - set_source_files_properties(codegen/llvm_utils.cpp PROPERTIES - COMPILE_FLAGS -Wno-deprecated-declarations) - endif() -endif() -add_library(asr ${SRC}) -target_include_directories(asr BEFORE PUBLIC ${libasr_SOURCE_DIR}/..) -target_include_directories(asr BEFORE PUBLIC ${libasr_BINARY_DIR}/..) -if (WITH_BFD) - target_link_libraries(asr p::bfd) -endif() -if (WITH_LINK) - target_link_libraries(asr p::link) -endif() -if (WITH_EXECINFO) - target_link_libraries(asr p::execinfo) -endif() -if (WITH_LLVM) - target_link_libraries(asr p::llvm) -endif() diff --git a/src/libasr/alloc.h b/src/libasr/alloc.h deleted file mode 100644 index 76588a2884..0000000000 --- a/src/libasr/alloc.h +++ /dev/null @@ -1,118 +0,0 @@ -#ifndef LFORTRAN_PARSER_ALLOC_H -#define LFORTRAN_PARSER_ALLOC_H - -#include -#include -#include -#include -#include - -#include - -#define ALIGNMENT 8 - -inline size_t align(size_t n) { - return (n + ALIGNMENT - 1) & ~(ALIGNMENT - 1); -} - -class Allocator -{ - void *start; - size_t current_pos; - size_t size; - std::vector blocks; -public: - Allocator(size_t s) { - s += ALIGNMENT; - start = malloc(s); - if (start == nullptr) throw std::runtime_error("malloc failed."); - current_pos = (size_t)start; - current_pos = align(current_pos); - size = s; - blocks.push_back(start); - } - Allocator() = delete; - Allocator(const Allocator&) = delete; - Allocator& operator=(const Allocator&) = delete; - Allocator(const Allocator&&) = delete; - Allocator& operator=(const Allocator&&) = delete; - ~Allocator() { - for (size_t i = 0; i < blocks.size(); i++) { - if (blocks[i] != nullptr) free(blocks[i]); - } - } - - // Allocates `s` bytes of memory, returns a pointer to it - void *alloc(size_t s) { - // For good performance, the code inside of `try` must be very short, as - // it will get inlined. One could just `return new_chunk(s)` instead of - // `throw std::bad_alloc()`, but a parsing benchmark gets about 2% or 3% - // slower. Even though it is never executed for the benchmark, the extra - // machine code makes the overall benchmark slower. One would have to - // force new_chunk() not to get inlined, but there is no standard way of - // doing it. This try/catch approach effectively achieves the same using - // standard C++. - try { - LCOMPILERS_ASSERT(start != nullptr); - size_t addr = current_pos; - current_pos += align(s); - if (size_current() > size_total()) throw std::bad_alloc(); - return (void*)addr; - } catch (const std::bad_alloc &e) { - return new_chunk(s); - } - } - - void *new_chunk(size_t s) { - size_t snew = std::max(s+ALIGNMENT, 2*size); - start = malloc(snew); - blocks.push_back(start); - if (start == nullptr) { - throw std::runtime_error("malloc failed."); - } - current_pos = (size_t)start; - current_pos = align(current_pos); - size = snew; - - size_t addr = current_pos; - current_pos += align(s); - - LCOMPILERS_ASSERT(size_current() <= size_total()); - return (void*)addr; - } - - // Allocates `n` elements of type T, returns the pointer T* to the first - // element - template T* allocate(size_t n=1) { - return (T *)alloc(sizeof(T) * n); - } - - // Just like `new`, but using Allocator - // The following two examples both construct the same instance MyInt(5), - // but first uses the default C++ allocator, while the second uses - // Allocator: - // - // MyInt *n = new MyInt(5); // Default C++ allocator - // - // Allocator al(1024); - // MyInt *n = al.make_new(5); // Allocator - template T* make_new(Args &&... args) { - return new(alloc(sizeof(T))) T(std::forward(args)...); - // To test the default "new", comment the above and uncomment this: - //return new T(std::forward(args)...); - } - - size_t size_current() { - return current_pos - (size_t)start; - } - - size_t size_total() { - return size; - } - - size_t num_chunks() { - return blocks.size(); - } -}; - -#endif diff --git a/src/libasr/asdl.py b/src/libasr/asdl.py deleted file mode 100644 index 3dbae6d344..0000000000 --- a/src/libasr/asdl.py +++ /dev/null @@ -1,375 +0,0 @@ -#------------------------------------------------------------------------------- -# Parser for ASDL [1] definition files. Reads in an ASDL description and parses -# it into an AST that describes it. -# -# The EBNF we're parsing here: Figure 1 of the paper [1]. Extended to support -# modules and attributes after a product. Words starting with Capital letters -# are terminals. Literal tokens are in "double quotes". Others are -# non-terminals. Id is either TokenId or ConstructorId. -# -# module ::= "module" Id "{" [definitions] "}" -# definitions ::= { TypeId "=" type } -# type ::= product | sum -# product ::= fields ["attributes" fields] -# fields ::= "(" { field, "," } field ")" -# field ::= TypeId ["?" | "*"] [Id] -# sum ::= constructor { "|" constructor } ["attributes" fields] -# constructor ::= ConstructorId [fields] -# -# [1] "The Zephyr Abstract Syntax Description Language" by Wang, et. al. See -# http://asdl.sourceforge.net/ -#------------------------------------------------------------------------------- -from collections import namedtuple -import re - -__all__ = [ - 'builtin_types', 'parse', 'AST', 'Module', 'Type', 'Constructor', - 'Field', 'Sum', 'Product', 'VisitorBase', 'Check', 'check'] - -# The following classes define nodes into which the ASDL description is parsed. -# Note: this is a "meta-AST". ASDL files (such as Python.asdl) describe the AST -# structure used by a programming language. But ASDL files themselves need to be -# parsed. This module parses ASDL files and uses a simple AST to represent them. -# See the EBNF at the top of the file to understand the logical connection -# between the various node types. - -builtin_types = {'identifier', 'string', 'int', 'bool', 'float', 'node', 'symbol_table'} - -class AST: - def __repr__(self): - raise NotImplementedError - -class Module(AST): - def __init__(self, name, dfns): - self.name = name - self.dfns = dfns - self.types = {type.name: type.value for type in dfns} - - def __repr__(self): - return 'Module({0.name}, {0.dfns})'.format(self) - -class Type(AST): - def __init__(self, name, value): - self.name = name - self.value = value - - def __repr__(self): - return 'Type({0.name}, {0.value})'.format(self) - -class Constructor(AST): - def __init__(self, name, fields=None): - self.name = name - self.fields = fields or [] - - def __repr__(self): - return 'Constructor({0.name}, {0.fields})'.format(self) - -class Field(AST): - def __init__(self, type, name=None, seq=False, opt=False): - self.type = type - self.name = name - self.seq = seq - self.opt = opt - - def __repr__(self): - if self.seq: - extra = ", seq=True" - elif self.opt: - extra = ", opt=True" - else: - extra = "" - if self.name is None: - return 'Field({0.type}{1})'.format(self, extra) - else: - return 'Field({0.type}, {0.name}{1})'.format(self, extra) - -class Sum(AST): - def __init__(self, types, attributes=None): - self.types = types - self.attributes = attributes or [] - - def __repr__(self): - if self.attributes: - return 'Sum({0.types}, {0.attributes})'.format(self) - else: - return 'Sum({0.types})'.format(self) - -class Product(AST): - def __init__(self, fields, attributes=None): - self.fields = fields - self.attributes = attributes or [] - - def __repr__(self): - if self.attributes: - return 'Product({0.fields}, {0.attributes})'.format(self) - else: - return 'Product({0.fields})'.format(self) - -# A generic visitor for the meta-AST that describes ASDL. This can be used by -# emitters. Note that this visitor does not provide a generic visit method, so a -# subclass must define visit methods from visitModule to as deep as the -# interesting node. -# We also define a Check visitor that makes sure the parsed ASDL is well-formed. - -class VisitorBase(object): - """Generic tree visitor for ASTs.""" - def __init__(self): - self.cache = {} - - def visit(self, obj, *args): - klass = obj.__class__ - meth = self.cache.get(klass) - if meth is None: - methname = "visit" + klass.__name__ - meth = getattr(self, methname, None) - self.cache[klass] = meth - if meth: - try: - meth(obj, *args) - except Exception as e: - print("Error visiting %r: %s" % (obj, e)) - raise - -class Check(VisitorBase): - """A visitor that checks a parsed ASDL tree for correctness. - - Errors are printed and accumulated. - """ - def __init__(self): - super(Check, self).__init__() - self.cons = {} - self.errors = 0 - self.types = {} - - def visitModule(self, mod): - for dfn in mod.dfns: - self.visit(dfn) - - def visitType(self, type): - self.visit(type.value, str(type.name)) - - def visitSum(self, sum, name): - for t in sum.types: - self.visit(t, name) - - def visitConstructor(self, cons, name): - key = str(cons.name) - conflict = self.cons.get(key) - if conflict is None: - self.cons[key] = name - else: - print('Redefinition of constructor {}'.format(key)) - print('Defined in {} and {}'.format(conflict, name)) - self.errors += 1 - for f in cons.fields: - self.visit(f, key) - - def visitField(self, field, name): - key = str(field.type) - l = self.types.setdefault(key, []) - l.append(name) - - def visitProduct(self, prod, name): - for f in prod.fields: - self.visit(f, name) - -def check(mod): - """Check the parsed ASDL tree for correctness. - - Return True if success. For failure, the errors are printed out and False - is returned. - """ - v = Check() - v.visit(mod) - - for t in v.types: - if t not in mod.types and not t in builtin_types: - v.errors += 1 - uses = ", ".join(v.types[t]) - print('Undefined type {}, used in {}'.format(t, uses)) - return not v.errors - -# The ASDL parser itself comes next. The only interesting external interface -# here is the top-level parse function. - -def parse(filename): - """Parse ASDL from the given file and return a Module node describing it.""" - with open(filename) as f: - parser = ASDLParser() - return parser.parse(f.read()) - -# Types for describing tokens in an ASDL specification. -class TokenKind: - """TokenKind is provides a scope for enumerated token kinds.""" - (ConstructorId, TypeId, Equals, Comma, Question, Pipe, Asterisk, - LParen, RParen, LBrace, RBrace) = range(11) - - operator_table = { - '=': Equals, ',': Comma, '?': Question, '|': Pipe, '(': LParen, - ')': RParen, '*': Asterisk, '{': LBrace, '}': RBrace} - -Token = namedtuple('Token', 'kind value lineno') - -class ASDLSyntaxError(Exception): - def __init__(self, msg, lineno=None): - self.msg = msg - self.lineno = lineno or '' - - def __str__(self): - return 'Syntax error on line {0.lineno}: {0.msg}'.format(self) - -def tokenize_asdl(buf): - """Tokenize the given buffer. Yield Token objects.""" - for lineno, line in enumerate(buf.splitlines(), 1): - for m in re.finditer(r'\s*(\w+|--.*|.)', line.strip()): - c = m.group(1) - if c[0].isalpha(): - # Some kind of identifier - if c[0].isupper(): - yield Token(TokenKind.ConstructorId, c, lineno) - else: - yield Token(TokenKind.TypeId, c, lineno) - elif c[:2] == '--': - # Comment - break - else: - # Operators - try: - op_kind = TokenKind.operator_table[c] - except KeyError: - raise ASDLSyntaxError('Invalid operator %s' % c, lineno) - yield Token(op_kind, c, lineno) - -class ASDLParser: - """Parser for ASDL files. - - Create, then call the parse method on a buffer containing ASDL. - This is a simple recursive descent parser that uses tokenize_asdl for the - lexing. - """ - def __init__(self): - self._tokenizer = None - self.cur_token = None - - def parse(self, buf): - """Parse the ASDL in the buffer and return an AST with a Module root. - """ - self._tokenizer = tokenize_asdl(buf) - self._advance() - return self._parse_module() - - def _parse_module(self): - if self._at_keyword('module'): - self._advance() - else: - raise ASDLSyntaxError( - 'Expected "module" (found {})'.format(self.cur_token.value), - self.cur_token.lineno) - name = self._match(self._id_kinds) - self._match(TokenKind.LBrace) - defs = self._parse_definitions() - self._match(TokenKind.RBrace) - return Module(name, defs) - - def _parse_definitions(self): - defs = [] - while self.cur_token.kind == TokenKind.TypeId: - typename = self._advance() - self._match(TokenKind.Equals) - type = self._parse_type() - defs.append(Type(typename, type)) - return defs - - def _parse_type(self): - if self.cur_token.kind == TokenKind.LParen: - # If we see a (, it's a product - return self._parse_product() - else: - # Otherwise it's a sum. Look for ConstructorId - sumlist = [Constructor(self._match(TokenKind.ConstructorId), - self._parse_optional_fields())] - while self.cur_token.kind == TokenKind.Pipe: - # More constructors - self._advance() - sumlist.append(Constructor( - self._match(TokenKind.ConstructorId), - self._parse_optional_fields())) - return Sum(sumlist, self._parse_optional_attributes()) - - def _parse_product(self): - return Product(self._parse_fields(), self._parse_optional_attributes()) - - def _parse_fields(self): - fields = [] - self._match(TokenKind.LParen) - while self.cur_token.kind == TokenKind.TypeId: - typename = self._advance() - is_seq, is_opt = self._parse_optional_field_quantifier() - id = (self._advance() if self.cur_token.kind in self._id_kinds - else None) - fields.append(Field(typename, id, seq=is_seq, opt=is_opt)) - if self.cur_token.kind == TokenKind.RParen: - break - elif self.cur_token.kind == TokenKind.Comma: - self._advance() - self._match(TokenKind.RParen) - return fields - - def _parse_optional_fields(self): - if self.cur_token.kind == TokenKind.LParen: - return self._parse_fields() - else: - return None - - def _parse_optional_attributes(self): - if self._at_keyword('attributes'): - self._advance() - return self._parse_fields() - else: - return None - - def _parse_optional_field_quantifier(self): - is_seq, is_opt = False, False - if self.cur_token.kind == TokenKind.Asterisk: - is_seq = True - self._advance() - elif self.cur_token.kind == TokenKind.Question: - is_opt = True - self._advance() - return is_seq, is_opt - - def _advance(self): - """ Return the value of the current token and read the next one into - self.cur_token. - """ - cur_val = None if self.cur_token is None else self.cur_token.value - try: - self.cur_token = next(self._tokenizer) - except StopIteration: - self.cur_token = None - return cur_val - - _id_kinds = (TokenKind.ConstructorId, TokenKind.TypeId) - - def _match(self, kind): - """The 'match' primitive of RD parsers. - - * Verifies that the current token is of the given kind (kind can - be a tuple, in which the kind must match one of its members). - * Returns the value of the current token - * Reads in the next token - """ - if (isinstance(kind, tuple) and self.cur_token.kind in kind or - self.cur_token.kind == kind - ): - value = self.cur_token.value - self._advance() - return value - else: - raise ASDLSyntaxError( - 'Unmatched {} (found {})'.format(kind, self.cur_token.kind), - self.cur_token.lineno) - - def _at_keyword(self, keyword): - return (self.cur_token.kind == TokenKind.TypeId and - self.cur_token.value == keyword) diff --git a/src/libasr/asdl_cpp.py b/src/libasr/asdl_cpp.py deleted file mode 100644 index 78a62e3b94..0000000000 --- a/src/libasr/asdl_cpp.py +++ /dev/null @@ -1,2608 +0,0 @@ -""" -Generate C++ AST node definitions from an ASDL description. -""" - -import sys -import os -import asdl - - -class ASDLVisitor(asdl.VisitorBase): - - def __init__(self, stream, data): - super(ASDLVisitor, self).__init__() - self.stream = stream - self.data = data - - def visitModule(self, mod, *args): - for df in mod.dfns: - self.visit(df, *args) - - def visitSum(self, sum, *args): - for tp in sum.types: - self.visit(tp, *args) - - def visitType(self, tp, *args): - self.visit(tp.value, *args) - - def visitProduct(self, prod, *args): - for field in prod.fields: - self.visit(field, *args) - - def visitConstructor(self, cons, *args): - for field in cons.fields: - self.visit(field, *args) - - def visitField(self, field, *args): - pass - - def emit(self, line, level=0): - indent = " "*level - self.stream.write(indent + line + "\n") - - -def is_simple_sum(sum): - """ - Returns true if `sum` is a simple sum. - - Example of a simple sum: - - boolop = And | Or - - Example of not a simple sum: - - type - = Integer(int kind) - | Real(int kind) - - """ - assert isinstance(sum, asdl.Sum) - for constructor in sum.types: - if constructor.fields: - return False - return True - -def attr_to_args(attrs): - args = [] - for attr in attrs: - kw = "" - if attr.type == "int": - if attr.name in ["lineno", "col_offset"]: - kw = "=1" - else: - kw = "=0" - elif attr.type in ["string", "identifier"]: - kw = '=None' - elif attr.seq: - kw = "=[]" - else: - kw = "=None" - args.append(attr.name + kw) - return ", ".join(args) - -simple_sums = [] -sums = [] -products = [] -subs = {} - -def convert_type(asdl_type, seq, opt, mod_name): - if asdl_type in simple_sums: - type_ = asdl_type + "Type" - assert not seq - elif asdl_type == "string": - type_ = "char*" - assert not seq - elif asdl_type == "identifier": - type_ = "char*" - if seq: - # List of strings is ** - type_ = type_ + "*" - elif asdl_type == "bool": - type_ = "bool" - assert not seq - elif asdl_type == "float": - type_ = "double" - assert not seq - elif asdl_type == "node": - type_ = "%s_t*" % mod_name - if seq: - type_ = type_ + "*" - elif asdl_type == "symbol_table": - type_ = "SymbolTable*" - elif asdl_type == "int": - type_ = "int64_t" - assert not seq - else: - type_ = asdl_type + "_t" - if asdl_type in products: - # Product type - # Not a pointer by default - if seq or opt: - # Sequence or an optional argument must be a pointer - type_ = type_ + "*" - else: - # Sum type - # Sum type is polymorphic, must be a pointer - type_ = type_ + "*" - if seq: - # Sequence of polymorphic types must be a double pointer - type_ = type_ + "*" - return type_ - -class CollectVisitor(ASDLVisitor): - - def visitType(self, tp): - self.visit(tp.value, tp.name) - - def visitSum(self, sum, base): - if not is_simple_sum(sum): - sums.append(base); - -class ASTNodeVisitor0(ASDLVisitor): - - def visitModule(self, mod): - self.emit("/" + "*"*78 + "/") - self.emit("// Forward declarations") - self.emit("") - super(ASTNodeVisitor0, self).visitModule(mod) - - def visitType(self, tp): - self.visit(tp.value, tp.name) - - def visitSum(self, sum, base): - if is_simple_sum(sum): - simple_sums.append(base) - self.emit("enum %sType // Simple Sum" % base) - self.emit("{ // Types"); - s = [cons.name for cons in sum.types] - self.emit( ", ".join(s), 1) - self.emit("};"); - else: - self.emit("struct %s_t; // Sum" % base) - - def visitProduct(self, product, name): - products.append(name) - self.emit("struct %s_t; // Product" % name) - - -class ASTNodeVisitor1(ASDLVisitor): - - def visitModule(self, mod): - self.emit("/" + "*"*78 + "/") - self.emit("// Products declarations") - self.emit("") - self.mod = mod - super(ASTNodeVisitor1, self).visitModule(mod) - - def visitType(self, tp): - self.visit(tp.value, tp.name) - - def visitProduct(self, product, name): - self.emit("struct %s_t // Product" % name) - self.emit("{"); - self.emit( "Location loc;", 1); - for f in product.fields: - type_ = convert_type(f.type, f.seq, f.opt, self.mod.name.lower()) - if f.seq: - seq = " size_t n_%s; // Sequence" % f.name - else: - seq = "" - self.emit("%s m_%s;%s" % (type_, f.name, seq), 1) - self.emit("};"); - - -class ASTNodeVisitor(ASDLVisitor): - - def visitModule(self, mod): - self.emit("/" + "*"*78 + "/") - self.emit("// Sums declarations") - self.emit("") - self.mod = mod - super(ASTNodeVisitor, self).visitModule(mod) - - def visitType(self, tp): - self.visit(tp.value, tp.name) - - def visitSum(self, sum, base): - if not is_simple_sum(sum): - self.emit("enum %sType // Types" % base) - self.emit("{"); - s = [cons.name for cons in sum.types] - self.emit( ", ".join(s), 1) - self.emit("};"); - self.emit("") - self.emit("struct %s_t // Sum" % base) - self.emit("{") - mod = subs["mod"] - self.emit( "const static %sType class_type = %sType::%s;" \ - % (mod, mod, base), 1) - self.emit( "%(mod)s_t base;" % subs, 1) - self.emit( "%sType type;" % base, 1) - self.emit("};") - self.emit("") - for cons in sum.types: - self.visit(cons, base, sum.attributes) - self.emit("") - self.emit("") - - def visitConstructor(self, cons, base, extra_attributes): - self.emit("struct %s_t // Constructor" % cons.name, 1) - self.emit("{", 1); - self.emit( "const static %sType class_type = %sType::%s;" \ - % (base, base, cons.name), 2) - self.emit( "typedef %s_t parent_type;" % base, 2) - self.emit( "%s_t base;" % base, 2); - args = ["Allocator &al", "const Location &a_loc"] - lines = [] - for f in cons.fields: - type_ = convert_type(f.type, f.seq, f.opt, self.mod.name.lower()) - if f.seq: - seq = " size_t n_%s; // Sequence" % f.name - else: - seq = "" - self.emit("%s m_%s;%s" % (type_, f.name, seq), 2) - args.append("%s a_%s" % (type_, f.name)) - lines.append("n->m_%s = a_%s;" % (f.name, f.name)) - if f.name in ["global_scope", "symtab"]: - lines.append("a_%s->asr_owner = (asr_t*)n;" % (f.name)) - if f.seq: - args.append("size_t n_%s" % (f.name)) - lines.append("n->n_%s = n_%s;" % (f.name, f.name)) - self.emit("};", 1) - self.emit("static inline %s_t* make_%s_t(%s) {" % (subs["mod"], - cons.name, ", ".join(args)), 1) - self.emit( "%s_t *n;" % cons.name, 2) - self.emit( "n = al.make_new<%s_t>();" % cons.name, 2) - self.emit( "n->base.type = %sType::%s;" % (base, cons.name), 2) - self.emit( "n->base.base.type = %sType::%s;" % (subs["mod"], - base), 2) - self.emit( "n->base.base.loc = a_loc;", 2) - for line in lines: - self.emit(line, 2) - self.emit( "return (%(mod)s_t*)n;" % subs, 2) - self.emit("}", 1) - self.emit("") - -class ASTVisitorVisitor1(ASDLVisitor): - - def visitModule(self, mod): - self.emit("/" + "*"*78 + "/") - self.emit("// Visitor functions") - self.emit("") - super(ASTVisitorVisitor1, self).visitModule(mod) - - def visitType(self, tp): - self.visit(tp.value, tp.name) - - def visitSum(self, sum, base): - if not is_simple_sum(sum): - self.emit("template ") - self.emit("static void visit_%s_t(const %s_t &x, Visitor &v) {" \ - % (base, base)) - self.emit( "LCOMPILERS_ASSERT(x.base.type == %sType::%s)" \ - % (subs["mod"], base), 1) - self.emit( "switch (x.type) {", 1) - for type_ in sum.types: - self.emit(" case %sType::%s: { v.visit_%s((const %s_t &)x);" - " return; }" % (base, type_.name, type_.name, type_.name)) - self.emit(" }") - self.emit("}") - self.emit("") - -class ASTVisitorVisitor1b(ASDLVisitor): - - def visitModule(self, mod): - self.emit("template ") - self.emit("static void visit_%(mod)s_t(const %(mod)s_t &x, Visitor &v) {" % subs) - self.emit(" switch (x.type) {") - for type_ in sums: - self.emit(" case %sType::%s: { v.visit_%s((const %s_t &)x);" - " return; }" % (subs["mod"], type_, type_, type_)) - self.emit(" }") - self.emit("}") - self.emit("") - -class ASTVisitorVisitor2(ASDLVisitor): - - def visitModule(self, mod): - self.emit("/" + "*"*78 + "/") - self.emit("// Visitor base class") - self.emit("") - self.emit("template ") - self.emit("class BaseVisitor") - self.emit("{") - self.emit("private:") - self.emit(" Struct& self() { return static_cast(*this); }") - self.emit("public:") - self.emit( "void visit_%(mod)s(const %(mod)s_t &b) { visit_%(mod)s_t(b, self()); }" % subs, 1) - super(ASTVisitorVisitor2, self).visitModule(mod) - self.emit("};") - - def visitType(self, tp): - self.visit(tp.value, tp.name) - - def visitSum(self, sum, base): - if not is_simple_sum(sum): - self.emit("void visit_%s(const %s_t &b) { visit_%s_t(b, self()); }"\ - % (base, base, base), 1) - for type_ in sum.types: - self.emit("""void visit_%s(const %s_t & /* x */) { throw LCompilersException("visit_%s() not implemented"); }""" \ - % (type_.name, type_.name, type_.name), 2) - - -class ASTWalkVisitorVisitor(ASDLVisitor): - - def visitModule(self, mod): - self.emit("/" + "*"*78 + "/") - self.emit("// Walk Visitor base class") - self.emit("") - self.emit("template ") - self.emit("class BaseWalkVisitor : public BaseVisitor") - self.emit("{") - self.emit("private:") - self.emit(" Struct& self() { return static_cast(*this); }") - self.emit("public:") - super(ASTWalkVisitorVisitor, self).visitModule(mod) - self.emit("};") - - def visitType(self, tp): - if not (isinstance(tp.value, asdl.Sum) and - is_simple_sum(tp.value)): - super(ASTWalkVisitorVisitor, self).visitType(tp, tp.name) - - def visitProduct(self, prod, name): - self.make_visitor(name, prod.fields) - - def visitConstructor(self, cons, _): - self.make_visitor(cons.name, cons.fields) - - def make_visitor(self, name, fields): - self.emit("void visit_%s(const %s_t &x) {" % (name, name), 1) - self.used = False - have_body = False - for field in fields: - self.visitField(field) - if not self.used: - # Note: a better solution would be to change `&x` to `& /* x */` - # above, but we would need to change emit to return a string. - self.emit("if ((bool&)x) { } // Suppress unused warning", 2) - self.emit("}", 1) - - def visitField(self, field): - if (field.type not in asdl.builtin_types and - field.type not in self.data.simple_types): - level = 2 - if field.seq: - self.used = True - self.emit("for (size_t i=0; iget_scope()) {" % field.name, 2) - self.emit( "this->visit_symbol(*a.second);", 3) - self.emit("}", 2) - -class CallReplacerOnExpressionsVisitor(ASDLVisitor): - - def __init__(self, stream, data): - self.current_expr_copy_variable_count = 0 - super(CallReplacerOnExpressionsVisitor, self).__init__(stream, data) - - def visitModule(self, mod): - self.emit("/" + "*"*78 + "/") - self.emit("// Walk Visitor base class") - self.emit("") - self.emit("template ") - self.emit("class CallReplacerOnExpressionsVisitor : public BaseVisitor") - self.emit("{") - self.emit("private:") - self.emit(" Struct& self() { return static_cast(*this); }") - self.emit("public:") - self.emit(" ASR::expr_t** current_expr;") - self.emit(" SymbolTable* current_scope;") - self.emit("") - self.emit(" void call_replacer() {}") - self.emit(" void transform_stmts(ASR::stmt_t **&m_body, size_t &n_body) {") - self.emit(" for (size_t i = 0; i < n_body; i++) {", 1) - self.emit(" self().visit_stmt(*m_body[i]);", 1) - self.emit(" }", 1) - self.emit(" }") - super(CallReplacerOnExpressionsVisitor, self).visitModule(mod) - self.emit("};") - - def visitType(self, tp): - if not (isinstance(tp.value, asdl.Sum) and - is_simple_sum(tp.value)): - super(CallReplacerOnExpressionsVisitor, self).visitType(tp, tp.name) - - def visitProduct(self, prod, name): - self.make_visitor(name, prod.fields) - - def visitConstructor(self, cons, _): - self.make_visitor(cons.name, cons.fields) - - def make_visitor(self, name, fields): - self.emit("void visit_%s(const %s_t &x) {" % (name, name), 1) - is_symtab_present = False - is_stmt_present = False - symtab_field_name = "" - for field in fields: - if field.type == "stmt": - is_stmt_present = True - if field.type == "symbol_table": - is_symtab_present = True - symtab_field_name = field.name - if is_stmt_present and is_symtab_present: - break - if is_stmt_present and name not in ("Assignment", "ForAllSingle"): - self.emit(" %s_t& xx = const_cast<%s_t&>(x);" % (name, name), 1) - self.used = False - - if is_symtab_present: - self.emit("SymbolTable* current_scope_copy = current_scope;", 2) - self.emit("current_scope = x.m_%s;" % symtab_field_name, 2) - - for field in fields: - self.visitField(field) - if not self.used: - # Note: a better solution would be to change `&x` to `& /* x */` - # above, but we would need to change emit to return a string. - self.emit("if ((bool&)x) { } // Suppress unused warning", 2) - - if is_symtab_present: - self.emit("current_scope = current_scope_copy;", 2) - self.emit("}", 1) - - def insert_call_replacer_code(self, name, level, index=""): - self.emit(" ASR::expr_t** current_expr_copy_%d = current_expr;" % (self.current_expr_copy_variable_count), level) - self.emit(" current_expr = const_cast(&(x.m_%s%s));" % (name, index), level) - self.emit(" self().call_replacer();", level) - self.emit(" current_expr = current_expr_copy_%d;" % (self.current_expr_copy_variable_count), level) - self.current_expr_copy_variable_count += 1 - - def visitField(self, field): - if (field.type not in asdl.builtin_types and - field.type not in self.data.simple_types): - level = 2 - if field.seq: - if field.type == "stmt": - self.emit("self().transform_stmts(xx.m_%s, xx.n_%s);" % (field.name, field.name), level) - return - self.used = True - self.emit("for (size_t i=0; iget_scope()) {" % field.name, 2) - self.emit( "this->visit_symbol(*a.second);", 3) - self.emit("}", 2) - -# This class generates a visitor that prints the tree structure of AST/ASR -class TreeVisitorVisitor(ASDLVisitor): - - def visitModule(self, mod): - self.emit("/" + "*"*78 + "/") - self.emit("// Tree Visitor base class") - self.emit("") - self.emit("template ") - self.emit("class TreeBaseVisitor : public BaseVisitor") - self.emit("{") - self.emit("private:") - self.emit( "Struct& self() { return static_cast(*this); }", 1) - self.emit("public:") - self.emit( "std::string s, indtd;", 1) - self.emit( "bool use_colors;", 1) - self.emit( "bool start_line = true;", 1) - self.emit( 'bool last, attached;', 1) - self.emit( "int indent_level = 0, indent_spaces = 2, lvl = 0;", 1) - self.emit("public:") - self.emit( "TreeBaseVisitor() : use_colors(false), last(true), attached(false) { s.reserve(100000); }", 1) - self.emit( "void inc_indent() {", 1) - self.emit( "indent_level++;", 2) - self.emit( 'indtd += " ";', 2) - self.emit( "}", 1) - self.emit( "void inc_lindent() {", 1) - self.emit( "indent_level++;", 2) - self.emit( 'indtd += "| ";', 2) - self.emit( "}", 1) - self.emit( "void dec_indent() {", 1) - self.emit( "indent_level--;", 2) - self.emit( "LCOMPILERS_ASSERT(indent_level >= 0);", 2) - self.emit( "indtd = indtd.substr(0, indent_level*indent_spaces);",2) - self.emit( "}", 1) - self.mod = mod - super(TreeVisitorVisitor, self).visitModule(mod) - self.emit("};") - - def visitType(self, tp): - super(TreeVisitorVisitor, self).visitType(tp, tp.name) - - def visitSum(self, sum, *args): - assert isinstance(sum, asdl.Sum) - if is_simple_sum(sum): - name = args[0] + "Type" - self.make_simple_sum_visitor(name, sum.types) - else: - for tp in sum.types: - self.visit(tp, *args) - - def visitProduct(self, prod, name): - self.make_visitor(name, prod.fields, False) - - def visitConstructor(self, cons, _): - self.make_visitor(cons.name, cons.fields, True) - - def make_visitor(self, name, fields, cons): - self.emit("void visit_%s(const %s_t &x) {" % (name, name), 1) - self.emit( 'if(!attached) {', 2) - self.emit( 'if(start_line) {', 3) - self.emit( 'start_line = false;', 4) - self.emit( 's.append(indtd);', 4) - self.emit( '} else {', 3) - self.emit( 's.append("\\n"+indtd);', 4) - self.emit( '}', 3) - self.emit( 'last ? s.append("└-") : s.append("|-");', 3) - self.emit( '}', 2) - self.emit( 'last ? inc_indent() : inc_lindent();', 2) - self.emit( 'attached = true;', 2) - self.emit( 'last = false;', 2) - if cons: - self.emit( 'if (use_colors) {', 2) - self.emit( 's.append(color(style::bold));', 3) - self.emit( 's.append(color(fg::magenta));', 3) - self.emit( '}', 2) - self.emit( 's.append("%s");' % name, 2) - self.emit( 'if (use_colors) {', 2) - self.emit( 's.append(color(fg::reset));', 3) - self.emit( 's.append(color(style::reset));', 3) - self.emit( '}', 2) - self.used = False - for n, field in enumerate(fields): - self.visitField(field, cons, n == len(fields)-1) - self.emit( 'dec_indent();', 2) - if not self.used: - # Note: a better solution would be to change `&x` to `& /* x */` - # above, but we would need to change emit to return a string. - self.emit("if ((bool&)x) { } // Suppress unused warning", 2) - self.emit("}", 1) - - def make_simple_sum_visitor(self, name, types): - self.emit("void visit_%s(const %s &x) {" % (name, name), 1) - self.emit( 'if (use_colors) {', 2) - self.emit( 's.append(color(style::bold));', 3) - self.emit( 's.append(color(fg::green));', 3) - self.emit( '}', 2) - self.emit( 'switch (x) {', 2) - for tp in types: - self.emit( 'case (%s::%s) : {' % (name, tp.name), 3) - self.emit( 's.append("%s");' % (tp.name), 4) - self.emit( ' break; }',3) - self.emit( '}', 2) - self.emit( 'if (use_colors) {', 2) - self.emit( 's.append(color(fg::reset));', 3) - self.emit( 's.append(color(style::reset));', 3) - self.emit( '}', 2) - self.emit("}", 1) - - def visitField(self, field, cons, last): - arr = '└-' if last else '|-' - if (field.type not in asdl.builtin_types and - field.type not in self.data.simple_types): - self.used = True - level = 2 - if field.type in products: - if field.opt: - template = "self().visit_%s(*x.m_%s);" % (field.type, field.name) - else: - template = "self().visit_%s(x.m_%s);" % (field.type, field.name) - else: - template = "self().visit_%s(*x.m_%s);" % (field.type, field.name) - if field.seq: - self.emit('s.append("\\n" + indtd + "%s" + "%s=\u21a7");' % (arr, field.name), level) - self.emit("for (size_t i=0; iget_scope()) {' % field.name, level) - self.emit( 'i++;', level+1) - self.emit( 'inc_indent();', level+1) - self.emit( 'last = i == x.m_%s->get_scope().size();' % field.name, level+1) - self.emit( 's.append("\\n" + indtd + (last ? "└-" : "|-") + a.first + ": ");', level+1) - self.emit( 'this->visit_symbol(*a.second);', level+1) - self.emit( 'dec_indent();', level+1) - self.emit('}', level) - self.emit('dec_indent();', level) - elif field.type == "string" and not field.seq: - if field.opt: - self.emit('s.append("\\n" + indtd + "%s" + "%s=");' % (arr, field.name), 2) - self.emit("if (x.m_%s) {" % field.name, 2) - self.emit( 's.append("\\"" + std::string(x.m_%s) + "\\"");' % field.name, 3) - self.emit("} else {", 2) - self.emit( 's.append("()");', 3) - self.emit("}", 2) - else: - self.emit('s.append("\\n" + indtd + "%s" + "%s=");' % (arr, field.name), 2) - self.emit('s.append("\\"" + std::string(x.m_%s) + "\\"");' % field.name, 2) - elif field.type == "int" and not field.seq: - if field.opt: - self.emit('s.append("\\n" + indtd + "%s" + "%s=");' % (arr, field.name), 2) - self.emit("if (x.m_%s) {" % field.name, 2) - self.emit( 's.append(std::to_string(x.m_%s));' % field.name, 3) - self.emit("} else {", 2) - self.emit( 's.append("()");', 3) - self.emit("}", 2) - else: - self.emit('s.append("\\n" + indtd + "%s" + "%s=");' % (arr, field.name), 2) - self.emit('s.append(std::to_string(x.m_%s));' % field.name, 2) - elif field.type == "float" and not field.seq and not field.opt: - self.emit('s.append("\\n" + indtd + "%s" + "%s=");' % (arr, field.name), 2) - self.emit('s.append(std::to_string(x.m_%s));' % field.name, 2) - elif field.type == "bool" and not field.seq and not field.opt: - self.emit('s.append("\\n" + indtd + "%s" + "%s=");' % (arr, field.name), 2) - self.emit("if (x.m_%s) {" % field.name, 2) - self.emit( 's.append(".true.");', 3) - self.emit("} else {", 2) - self.emit( 's.append(".false.");', 3) - self.emit("}", 2) - elif field.type in self.data.simple_types: - if field.opt: - self.emit('s.append("Unimplementedopt");', 2) - else: - self.emit('s.append("\\n" + indtd + "%s" + "%sType=");' % (arr, field.type), 2) - self.emit('visit_%sType(x.m_%s);' \ - % (field.type, field.name), 2) - else: - self.emit('s.append("Unimplemented' + field.type + '");', 2) - - -class ExprStmtDuplicatorVisitor(ASDLVisitor): - - def __init__(self, stream, data): - self.duplicate_stmt = [] - self.duplicate_expr = [] - self.duplicate_ttype = [] - self.duplicate_case_stmt = [] - self.is_stmt = False - self.is_expr = False - self.is_ttype = False - self.is_case_stmt = False - self.is_product = False - super(ExprStmtDuplicatorVisitor, self).__init__(stream, data) - - def visitModule(self, mod): - self.emit("/" + "*"*78 + "/") - self.emit("// Expression and statement Duplicator class") - self.emit("") - self.emit("template ") - self.emit("class BaseExprStmtDuplicator {") - self.emit("public:") - self.emit(" Struct& self() { return static_cast(*this); }") - self.emit("") - self.emit(" Allocator &al;") - self.emit(" bool success;") - self.emit(" bool allow_procedure_calls;") - self.emit(" bool allow_reshape;") - self.emit("") - self.emit(" BaseExprStmtDuplicator(Allocator& al_) : al(al_), success(false), allow_procedure_calls(true), allow_reshape(true) {}") - self.emit("") - self.duplicate_stmt.append((" ASR::stmt_t* duplicate_stmt(ASR::stmt_t* x) {", 0)) - self.duplicate_stmt.append((" if( !x ) {", 1)) - self.duplicate_stmt.append((" return nullptr;", 2)) - self.duplicate_stmt.append((" }", 1)) - self.duplicate_stmt.append(("", 0)) - self.duplicate_stmt.append((" switch(x->type) {", 1)) - - self.duplicate_expr.append((" ASR::expr_t* duplicate_expr(ASR::expr_t* x) {", 0)) - self.duplicate_expr.append((" if( !x ) {", 1)) - self.duplicate_expr.append((" return nullptr;", 2)) - self.duplicate_expr.append((" }", 1)) - self.duplicate_expr.append(("", 0)) - self.duplicate_expr.append((" switch(x->type) {", 1)) - - self.duplicate_ttype.append((" ASR::ttype_t* duplicate_ttype(ASR::ttype_t* x) {", 0)) - self.duplicate_ttype.append((" if( !x ) {", 1)) - self.duplicate_ttype.append((" return nullptr;", 2)) - self.duplicate_ttype.append((" }", 1)) - self.duplicate_ttype.append(("", 0)) - self.duplicate_ttype.append((" switch(x->type) {", 1)) - - self.duplicate_case_stmt.append((" ASR::case_stmt_t* duplicate_case_stmt(ASR::case_stmt_t* x) {", 0)) - self.duplicate_case_stmt.append((" if( !x ) {", 1)) - self.duplicate_case_stmt.append((" return nullptr;", 2)) - self.duplicate_case_stmt.append((" }", 1)) - self.duplicate_case_stmt.append(("", 0)) - self.duplicate_case_stmt.append((" switch(x->type) {", 1)) - - super(ExprStmtDuplicatorVisitor, self).visitModule(mod) - self.duplicate_stmt.append((" default: {", 2)) - self.duplicate_stmt.append((' LCOMPILERS_ASSERT_MSG(false, "Duplication of " + std::to_string(x->type) + " statement is not supported yet.");', 3)) - self.duplicate_stmt.append((" }", 2)) - self.duplicate_stmt.append((" }", 1)) - self.duplicate_stmt.append(("", 0)) - self.duplicate_stmt.append((" return nullptr;", 1)) - self.duplicate_stmt.append((" }", 0)) - - self.duplicate_expr.append((" default: {", 2)) - self.duplicate_expr.append((' LCOMPILERS_ASSERT_MSG(false, "Duplication of " + std::to_string(x->type) + " expression is not supported yet.");', 3)) - self.duplicate_expr.append((" }", 2)) - self.duplicate_expr.append((" }", 1)) - self.duplicate_expr.append(("", 0)) - self.duplicate_expr.append((" return nullptr;", 1)) - self.duplicate_expr.append((" }", 0)) - - self.duplicate_ttype.append((" default: {", 2)) - self.duplicate_ttype.append((' LCOMPILERS_ASSERT_MSG(false, "Duplication of " + std::to_string(x->type) + " type is not supported yet.");', 3)) - self.duplicate_ttype.append((" }", 2)) - self.duplicate_ttype.append((" }", 1)) - self.duplicate_ttype.append(("", 0)) - self.duplicate_ttype.append((" return nullptr;", 1)) - self.duplicate_ttype.append((" }", 0)) - - self.duplicate_case_stmt.append((" default: {", 2)) - self.duplicate_case_stmt.append((' LCOMPILERS_ASSERT_MSG(false, "Duplication of " + std::to_string(x->type) + " case statement is not supported yet.");', 3)) - self.duplicate_case_stmt.append((" }", 2)) - self.duplicate_case_stmt.append((" }", 1)) - self.duplicate_case_stmt.append(("", 0)) - self.duplicate_case_stmt.append((" return nullptr;", 1)) - self.duplicate_case_stmt.append((" }", 0)) - - for line, level in self.duplicate_stmt: - self.emit(line, level=level) - self.emit("") - for line, level in self.duplicate_expr: - self.emit(line, level=level) - self.emit("") - for line, level in self.duplicate_ttype: - self.emit(line, level=level) - self.emit("") - for line, level in self.duplicate_case_stmt: - self.emit(line, level=level) - self.emit("") - self.emit("};") - - def visitType(self, tp): - if not (isinstance(tp.value, asdl.Sum) and - is_simple_sum(tp.value)): - super(ExprStmtDuplicatorVisitor, self).visitType(tp, tp.name) - - def visitSum(self, sum, *args): - self.is_stmt = args[0] == 'stmt' - self.is_expr = args[0] == 'expr' - self.is_ttype = args[0] == "ttype" - self.is_case_stmt = args[0] == 'case_stmt' - if self.is_stmt or self.is_expr or self.is_case_stmt or self.is_ttype: - for tp in sum.types: - self.visit(tp, *args) - - def visitProduct(self, prod, name): - pass - - def visitConstructor(self, cons, _): - self.make_visitor(cons.name, cons.fields) - - def make_visitor(self, name, fields): - self.emit("") - self.emit("ASR::asr_t* duplicate_%s(%s_t* x) {" % (name, name), 1) - self.used = False - arguments = [] - for field in fields: - ret_value = self.visitField(field) - for node_arg in ret_value: - arguments.append(node_arg) - if not self.used: - self.emit("return (asr_t*)x;", 2) - else: - node_arg_str = ', '.join(arguments) - self.emit("return make_%s_t(al, x->base.base.loc, %s);" %(name, node_arg_str), 2) - if self.is_stmt: - self.duplicate_stmt.append((" case ASR::stmtType::%s: {" % name, 2)) - if name == "SubroutineCall": - self.duplicate_stmt.append((" if( !allow_procedure_calls ) {", 3)) - self.duplicate_stmt.append((" success = false;", 4)) - self.duplicate_stmt.append((" return nullptr;", 4)) - self.duplicate_stmt.append((" }", 3)) - self.duplicate_stmt.append((" return down_cast(self().duplicate_%s(down_cast(x)));" % (name, name), 3)) - self.duplicate_stmt.append((" }", 2)) - elif self.is_expr: - self.duplicate_expr.append((" case ASR::exprType::%s: {" % name, 2)) - if name == "FunctionCall": - self.duplicate_expr.append((" if( !allow_procedure_calls ) {", 3)) - self.duplicate_expr.append((" success = false;", 4)) - self.duplicate_expr.append((" return nullptr;", 4)) - self.duplicate_expr.append((" }", 3)) - elif name == "ArrayReshape": - self.duplicate_expr.append((" if( !allow_reshape ) {", 3)) - self.duplicate_expr.append((" success = false;", 4)) - self.duplicate_expr.append((" return nullptr;", 4)) - self.duplicate_expr.append((" }", 3)) - self.duplicate_expr.append((" return down_cast(self().duplicate_%s(down_cast(x)));" % (name, name), 3)) - self.duplicate_expr.append((" }", 2)) - elif self.is_ttype: - self.duplicate_ttype.append((" case ASR::ttypeType::%s: {" % name, 2)) - self.duplicate_ttype.append((" return down_cast(self().duplicate_%s(down_cast(x)));" % (name, name), 3)) - self.duplicate_ttype.append((" }", 2)) - elif self.is_case_stmt: - self.duplicate_case_stmt.append((" case ASR::case_stmtType::%s: {" % name, 2)) - self.duplicate_case_stmt.append((" return down_cast(self().duplicate_%s(down_cast(x)));" % (name, name), 3)) - self.duplicate_case_stmt.append((" }", 2)) - self.emit("}", 1) - self.emit("") - - def visitField(self, field): - arguments = None - if (field.type == "expr" or - field.type == "stmt" or - field.type == "symbol" or - field.type == "call_arg" or - field.type == "do_loop_head" or - field.type == "array_index" or - field.type == "alloc_arg" or - field.type == "case_stmt" or - field.type == "ttype" or - field.type == "dimension"): - level = 2 - if field.seq: - self.used = True - pointer_char = '' - if (field.type != "call_arg" and - field.type != "array_index" and - field.type != "alloc_arg" and - field.type != "dimension"): - pointer_char = '*' - self.emit("Vec<%s_t%s> m_%s;" % (field.type, pointer_char, field.name), level) - self.emit("m_%s.reserve(al, x->n_%s);" % (field.name, field.name), level) - self.emit("for (size_t i = 0; i < x->n_%s; i++) {" % field.name, level) - if field.type == "symbol": - self.emit(" m_%s.push_back(al, x->m_%s[i]);" % (field.name, field.name), level) - elif field.type == "call_arg": - self.emit(" ASR::call_arg_t call_arg_copy;", level) - self.emit(" call_arg_copy.loc = x->m_%s[i].loc;"%(field.name), level) - self.emit(" call_arg_copy.m_value = self().duplicate_expr(x->m_%s[i].m_value);"%(field.name), level) - self.emit(" m_%s.push_back(al, call_arg_copy);"%(field.name), level) - elif field.type == "alloc_arg": - self.emit(" ASR::alloc_arg_t alloc_arg_copy;", level) - self.emit(" alloc_arg_copy.loc = x->m_%s[i].loc;"%(field.name), level) - self.emit(" alloc_arg_copy.m_a = x->m_%s[i].m_a;"%(field.name), level) - self.emit(" alloc_arg_copy.n_dims = x->m_%s[i].n_dims;"%(field.name), level) - self.emit(" Vec dims_copy;", level) - self.emit(" dims_copy.reserve(al, alloc_arg_copy.n_dims);", level) - self.emit(" for (size_t j = 0; j < alloc_arg_copy.n_dims; j++) {", level) - self.emit(" ASR::dimension_t dim_copy;", level + 1) - self.emit(" dim_copy.loc = x->m_%s[i].m_dims[j].loc;"%(field.name), level + 1) - self.emit(" dim_copy.m_start = self().duplicate_expr(x->m_%s[i].m_dims[j].m_start);"%(field.name), level + 1) - self.emit(" dim_copy.m_length = self().duplicate_expr(x->m_%s[i].m_dims[j].m_length);"%(field.name), level + 1) - self.emit(" dims_copy.push_back(al, dim_copy);", level + 1) - self.emit(" }", level) - self.emit(" alloc_arg_copy.m_dims = dims_copy.p;", level) - self.emit(" m_%s.push_back(al, alloc_arg_copy);"%(field.name), level) - elif field.type == "array_index": - self.emit(" ASR::array_index_t array_index_copy;", level) - self.emit(" array_index_copy.loc = x->m_%s[i].loc;"%(field.name), level) - self.emit(" array_index_copy.m_left = duplicate_expr(x->m_%s[i].m_left);"%(field.name), level) - self.emit(" array_index_copy.m_right = duplicate_expr(x->m_%s[i].m_right);"%(field.name), level) - self.emit(" array_index_copy.m_step = duplicate_expr(x->m_%s[i].m_step);"%(field.name), level) - self.emit(" m_%s.push_back(al, array_index_copy);"%(field.name), level) - elif field.type == "dimension": - self.emit(" ASR::dimension_t dim_copy;", level) - self.emit(" dim_copy.loc = x->m_%s[i].loc;"%(field.name), level) - self.emit(" dim_copy.m_start = self().duplicate_expr(x->m_%s[i].m_start);"%(field.name), level) - self.emit(" dim_copy.m_length = self().duplicate_expr(x->m_%s[i].m_length);"%(field.name), level) - self.emit(" m_%s.push_back(al, dim_copy);" % (field.name), level) - else: - self.emit(" m_%s.push_back(al, self().duplicate_%s(x->m_%s[i]));" % (field.name, field.type, field.name), level) - self.emit("}", level) - arguments = ("m_" + field.name + ".p", "x->n_" + field.name) - else: - self.used = True - if field.type == "symbol": - self.emit("%s_t* m_%s = x->m_%s;" % (field.type, field.name, field.name), level) - elif field.type == "do_loop_head": - self.emit("ASR::do_loop_head_t m_head;", level) - self.emit("m_head.loc = x->m_head.loc;", level) - self.emit("m_head.m_v = duplicate_expr(x->m_head.m_v);", level) - self.emit("m_head.m_start = duplicate_expr(x->m_head.m_start);", level) - self.emit("m_head.m_end = duplicate_expr(x->m_head.m_end);", level) - self.emit("m_head.m_increment = duplicate_expr(x->m_head.m_increment);", level) - elif field.type == "array_index": - self.emit("ASR::array_index_t m_%s;"%(field.name), level) - self.emit("m_%s.loc = x->m_%s.loc;"%(field.name, field.name), level) - self.emit("m_%s.m_left = duplicate_expr(x->m_%s.m_left);"%(field.name, field.name), level) - self.emit("m_%s.m_right = duplicate_expr(x->m_%s.m_right);"%(field.name, field.name), level) - self.emit("m_%s.m_step = duplicate_expr(x->m_%s.m_step);"%(field.name, field.name), level) - else: - self.emit("%s_t* m_%s = self().duplicate_%s(x->m_%s);" % (field.type, field.name, field.type, field.name), level) - arguments = ("m_" + field.name, ) - else: - if field.seq: - arguments = ("x->m_" + field.name, "x->n_" + field.name) - else: - arguments = ("x->m_" + field.name, ) - return arguments - -class ExprBaseReplacerVisitor(ASDLVisitor): - - def __init__(self, stream, data): - self.replace_expr = [] - self.is_expr = False - self.is_product = False - self.current_expr_copy_variable_count = 0 - super(ExprBaseReplacerVisitor, self).__init__(stream, data) - - def visitModule(self, mod): - self.emit("/" + "*"*78 + "/") - self.emit("// Expression Replacer Base class") - self.emit("") - self.emit("template ") - self.emit("class BaseExprReplacer {") - self.emit("public:") - self.emit(" Struct& self() { return static_cast(*this); }") - self.emit("") - self.emit(" ASR::expr_t** current_expr;") - self.emit("") - self.emit(" BaseExprReplacer() : current_expr(nullptr) {}") - self.emit("") - - self.replace_expr.append((" void replace_expr(ASR::expr_t* x) {", 0)) - self.replace_expr.append((" if( !x ) {", 1)) - self.replace_expr.append((" return ;", 2)) - self.replace_expr.append((" }", 1)) - self.replace_expr.append(("", 0)) - self.replace_expr.append((" switch(x->type) {", 1)) - - super(ExprBaseReplacerVisitor, self).visitModule(mod) - - self.replace_expr.append((" default: {", 2)) - self.replace_expr.append((' LCOMPILERS_ASSERT_MSG(false, "Duplication of " + std::to_string(x->type) + " expression is not supported yet.");', 3)) - self.replace_expr.append((" }", 2)) - self.replace_expr.append((" }", 1)) - self.replace_expr.append(("", 0)) - self.replace_expr.append((" }", 0)) - for line, level in self.replace_expr: - self.emit(line, level=level) - self.emit("") - self.emit("};") - - def visitType(self, tp): - if not (isinstance(tp.value, asdl.Sum) and - is_simple_sum(tp.value)): - super(ExprBaseReplacerVisitor, self).visitType(tp, tp.name) - - def visitSum(self, sum, *args): - self.is_expr = args[0] == 'expr' - if self.is_expr: - for tp in sum.types: - self.visit(tp, *args) - - def visitProduct(self, prod, name): - pass - - def visitConstructor(self, cons, _): - self.make_visitor(cons.name, cons.fields) - - def make_visitor(self, name, fields): - self.emit("") - self.emit("void replace_%s(%s_t* x) {" % (name, name), 1) - self.used = False - for field in fields: - self.visitField(field) - if not self.used: - self.emit("if (x) { }", 2) - - if self.is_expr: - self.replace_expr.append((" case ASR::exprType::%s: {" % name, 2)) - self.replace_expr.append((" self().replace_%s(down_cast(x));" % (name, name), 3)) - self.replace_expr.append((" break;", 3)) - self.replace_expr.append((" }", 2)) - self.emit("}", 1) - self.emit("") - - def visitField(self, field): - arguments = None - if field.type == "expr" or field.type == "symbol" or field.type == "call_arg": - level = 2 - if field.seq: - self.used = True - self.emit("for (size_t i = 0; i < x->n_%s; i++) {" % field.name, level) - if field.type == "call_arg": - self.emit(" if (x->m_%s[i].m_value != nullptr) {" % (field.name), level) - self.emit(" ASR::expr_t** current_expr_copy_%d = current_expr;" % (self.current_expr_copy_variable_count), level + 1) - self.emit(" current_expr = &(x->m_%s[i].m_value);" % (field.name), level + 1) - self.emit(" self().replace_expr(x->m_%s[i].m_value);"%(field.name), level + 1) - self.emit(" current_expr = current_expr_copy_%d;" % (self.current_expr_copy_variable_count), level + 1) - self.emit(" }", level) - self.current_expr_copy_variable_count += 1 - self.emit("}", level) - else: - if field.type != "symbol": - self.used = True - self.emit("ASR::expr_t** current_expr_copy_%d = current_expr;" % (self.current_expr_copy_variable_count), level) - self.emit("current_expr = &(x->m_%s);" % (field.name), level) - self.emit("self().replace_%s(x->m_%s);" % (field.type, field.name), level) - self.emit("current_expr = current_expr_copy_%d;" % (self.current_expr_copy_variable_count), level) - self.current_expr_copy_variable_count += 1 - -class StmtBaseReplacerVisitor(ASDLVisitor): - - def __init__(self, stream, data): - self.replace_stmt = [] - self.is_stmt = False - self.is_product = False - super(StmtBaseReplacerVisitor, self).__init__(stream, data) - - def visitModule(self, mod): - self.emit("/" + "*"*78 + "/") - self.emit("// Statement Replacer Base class") - self.emit("") - self.emit("template ") - self.emit("class BaseStmtReplacer {") - self.emit("public:") - self.emit(" Struct& self() { return static_cast(*this); }") - self.emit("") - self.emit(" ASR::stmt_t** current_stmt;") - self.emit(" ASR::stmt_t** current_stmt_copy;") - self.emit(" bool has_replacement_happened;") - self.emit("") - self.emit(" BaseStmtReplacer() : current_stmt(nullptr), has_replacement_happened(false) {}") - self.emit("") - - self.replace_stmt.append((" void replace_stmt(ASR::stmt_t* x) {", 0)) - self.replace_stmt.append((" if( !x ) {", 1)) - self.replace_stmt.append((" return ;", 2)) - self.replace_stmt.append((" }", 1)) - self.replace_stmt.append(("", 0)) - self.replace_stmt.append((" switch(x->type) {", 1)) - - super(StmtBaseReplacerVisitor, self).visitModule(mod) - - self.replace_stmt.append((" default: {", 2)) - self.replace_stmt.append((' LCOMPILERS_ASSERT_MSG(false, "Replacement of " + std::to_string(x->type) + " statement is not supported yet.");', 3)) - self.replace_stmt.append((" }", 2)) - self.replace_stmt.append((" }", 1)) - self.replace_stmt.append(("", 0)) - self.replace_stmt.append((" }", 0)) - for line, level in self.replace_stmt: - self.emit(line, level=level) - self.emit("") - self.emit("};") - - def visitType(self, tp): - if not (isinstance(tp.value, asdl.Sum) and - is_simple_sum(tp.value)): - super(StmtBaseReplacerVisitor, self).visitType(tp, tp.name) - - def visitSum(self, sum, *args): - self.is_stmt = args[0] == 'stmt' - if self.is_stmt: - for tp in sum.types: - self.visit(tp, *args) - - def visitProduct(self, prod, name): - pass - - def visitConstructor(self, cons, _): - self.make_visitor(cons.name, cons.fields) - - def make_visitor(self, name, fields): - self.emit("") - self.emit("void replace_%s(%s_t* x) {" % (name, name), 1) - self.used = False - for field in fields: - self.visitField(field) - if not self.used: - self.emit("if (x) { }", 2) - - if self.is_stmt: - self.replace_stmt.append((" case ASR::stmtType::%s: {" % name, 2)) - self.replace_stmt.append((" self().replace_%s(down_cast(x));" % (name, name), 3)) - self.replace_stmt.append((" break;", 3)) - self.replace_stmt.append((" }", 2)) - self.emit("}", 1) - self.emit("") - - def visitField(self, field): - arguments = None - if field.type == "stmt": - level = 2 - if field.seq: - self.used = True - self.emit("for (size_t i = 0; i < x->n_%s; i++) {" % field.name, level) - self.emit(" current_stmt_copy = current_stmt;", level) - self.emit(" current_stmt = &(x->m_%s[i]);" % (field.name), level) - self.emit(" self().replace_stmt(x->m_%s[i]);"%(field.name), level) - self.emit(" current_stmt = current_stmt_copy;", level) - self.emit("}", level) - -class PickleVisitorVisitor(ASDLVisitor): - - def visitModule(self, mod): - self.emit("/" + "*"*78 + "/") - self.emit("// Pickle Visitor base class") - self.emit("") - self.emit("template ") - self.emit("class PickleBaseVisitor : public BaseVisitor") - self.emit("{") - self.emit("private:") - self.emit( "Struct& self() { return static_cast(*this); }", 1) - self.emit("public:") - self.emit( "std::string s, indented = \"\";", 1) - self.emit( "bool use_colors;", 1) - self.emit( "bool indent;", 1) - self.emit( "int indent_level = 0, indent_spaces = 4;", 1) - self.emit("public:") - self.emit( "PickleBaseVisitor() : use_colors(false), indent(false) { s.reserve(100000); }", 1) - self.emit( "void inc_indent() {", 1) - self.emit( "indent_level++;", 2) - self.emit( "indented = std::string(indent_level*indent_spaces, ' ');",2) - self.emit( "}",1) - self.emit( "void dec_indent() {", 1) - self.emit( "indent_level--;", 2) - self.emit( "LCOMPILERS_ASSERT(indent_level >= 0);", 2) - self.emit( "indented = std::string(indent_level*indent_spaces, ' ');",2) - self.emit( "}",1) - self.mod = mod - super(PickleVisitorVisitor, self).visitModule(mod) - self.emit("};") - - def visitType(self, tp): - super(PickleVisitorVisitor, self).visitType(tp, tp.name) - - def visitSum(self, sum, *args): - assert isinstance(sum, asdl.Sum) - if is_simple_sum(sum): - name = args[0] + "Type" - self.make_simple_sum_visitor(name, sum.types) - else: - for tp in sum.types: - self.visit(tp, *args) - - def visitProduct(self, prod, name): - self.make_visitor(name, prod.fields, False) - - def visitConstructor(self, cons, _): - self.make_visitor(cons.name, cons.fields, True) - - def make_visitor(self, name, fields, cons): - self.emit("void visit_%s(const %s_t &x) {" % (name, name), 1) - self.emit( 's.append("(");', 2) - subs = { - "Assignment": "=", - "Associate": "=>", - } - if name in subs: - name = subs[name] - - # For ASR - symbol = [ - "Integer", - "Real", - "Complex", - "Character", - "Logical", - "Var", - ] - - if cons: - self.emit( 'if (use_colors) {', 2) - self.emit( 's.append(color(style::bold));', 3) - self.emit( 's.append(color(fg::magenta));', 3) - self.emit( '}', 2) - self.emit( 's.append("%s");' % name, 2) - self.emit( 'if (use_colors) {', 2) - self.emit( 's.append(color(fg::reset));', 3) - self.emit( 's.append(color(style::reset));', 3) - self.emit( '}', 2) - if len(fields) > 0: - if name not in symbol: - self.emit( 'if(indent) {', 2) - self.emit( 'inc_indent();', 3) - self.emit( 's.append("\\n" + indented);', 3) - self.emit( '} else {', 2) - self.emit( 's.append(" ");', 3) - self.emit( '}', 2) - else: - self.emit( 's.append(" ");', 2) - self.used = False - for n, field in enumerate(fields): - self.visitField(field, cons) - if n < len(fields) - 1: - if name not in symbol: - self.emit( 'if(indent) s.append("\\n" + indented);', 2) - self.emit( 'else s.append(" ");', 2) - else: - self.emit( 's.append(" ");', 2) - if name not in symbol and cons and len(fields) > 0: - self.emit( 'if(indent) {', 2) - self.emit( 'dec_indent();', 3) - self.emit( 's.append("\\n" + indented);', 3) - self.emit( '}', 2) - self.emit( 's.append(")");', 2) - if not self.used: - # Note: a better solution would be to change `&x` to `& /* x */` - # above, but we would need to change emit to return a string. - self.emit("if ((bool&)x) { } // Suppress unused warning", 2) - self.emit("}", 1) - - def make_simple_sum_visitor(self, name, types): - self.emit("void visit_%s(const %s &x) {" % (name, name), 1) - self.emit( 'if (use_colors) {', 2) - self.emit( 's.append(color(style::bold));', 3) - self.emit( 's.append(color(fg::green));', 3) - self.emit( '}', 2) - self.emit( 'switch (x) {', 2) - for tp in types: - self.emit( 'case (%s::%s) : {' % (name, tp.name), 3) - self.emit( 's.append("%s");' % (tp.name), 4) - self.emit( ' break; }',3) - self.emit( '}', 2) - self.emit( 'if (use_colors) {', 2) - self.emit( 's.append(color(fg::reset));', 3) - self.emit( 's.append(color(style::reset));', 3) - self.emit( '}', 2) - self.emit("}", 1) - - def visitField(self, field, cons): - if (field.type not in asdl.builtin_types and - field.type not in self.data.simple_types): - self.used = True - level = 2 - if field.type in products: - if field.opt: - template = "self().visit_%s(*x.m_%s);" % (field.type, field.name) - else: - template = "self().visit_%s(x.m_%s);" % (field.type, field.name) - else: - template = "self().visit_%s(*x.m_%s);" % (field.type, field.name) - if field.seq: - self.emit('s.append("[");', level) - self.emit("for (size_t i=0; iget_counter());' % field.name, level) - else: - level = 2 - self.emit( 's.append("(");', level) - self.emit('if (use_colors) {', level) - self.emit( 's.append(color(fg::yellow));', level+1) - self.emit('}', level) - self.emit('s.append("SymbolTable");', level) - self.emit('if (use_colors) {', level) - self.emit( 's.append(color(fg::reset));', level+1) - self.emit('}', level) - self.emit('if(indent) {', level) - self.emit(' inc_indent();', level) - self.emit(' s.append("\\n" + indented);', level) - self.emit('} else {', level) - self.emit(' s.append(" ");', level) - self.emit('}', level) - self.emit('s.append(x.m_%s->get_counter());' % field.name, level) - self.emit('if(indent) s.append("\\n" + indented);', level) - self.emit('else s.append(" ");', level) - self.emit( 's.append("{");', level) - self.emit('if(indent) {', level) - self.emit(' inc_indent();', level) - self.emit(' s.append("\\n" + indented);', level) - self.emit('}', level) - self.emit('{', level) - self.emit(' size_t i = 0;', level) - self.emit(' for (auto &a : x.m_%s->get_scope()) {' % field.name, level) - self.emit(' s.append(a.first + ":");', level) - self.emit(' if(indent) {', level) - self.emit(' inc_indent();', level) - self.emit(' s.append("\\n" + indented);', level) - self.emit(' } else {', level) - self.emit(' s.append(" ");', level) - self.emit(' }', level) - self.emit(' this->visit_symbol(*a.second);', level) - self.emit(' if(indent) dec_indent();', level) - self.emit(' if (i < x.m_%s->get_scope().size()-1) {' % field.name, level) - self.emit(' s.append(",");', level) - self.emit(' if(indent) s.append("\\n" + indented);', level) - self.emit(' else s.append(" ");', level) - self.emit(' }', level) - self.emit(' i++;', level) - self.emit(' }', level) - self.emit('}', level) - self.emit('if(indent) {', level) - self.emit( 'dec_indent();', level+1) - self.emit( 's.append("\\n" + indented);', level+1) - self.emit('}', level) - self.emit('s.append("})");', level) - self.emit('if(indent) dec_indent();', level) - elif field.type == "string" and not field.seq: - if field.opt: - self.emit("if (x.m_%s) {" % field.name, 2) - self.emit( 's.append("\\"" + std::string(x.m_%s) + "\\"");' % field.name, 3) - self.emit("} else {", 2) - self.emit( 's.append("()");', 3) - self.emit("}", 2) - else: - self.emit('s.append("\\"" + std::string(x.m_%s) + "\\"");' % field.name, 2) - elif field.type == "int" and not field.seq: - if field.opt: - self.emit("if (x.m_%s) {" % field.name, 2) - self.emit( 's.append(std::to_string(x.m_%s));' % field.name, 3) - self.emit("} else {", 2) - self.emit( 's.append("()");', 3) - self.emit("}", 2) - else: - self.emit('s.append(std::to_string(x.m_%s));' % field.name, 2) - elif field.type == "float" and not field.seq and not field.opt: - self.emit('s.append(std::to_string(x.m_%s));' % field.name, 2) - elif field.type == "bool" and not field.seq and not field.opt: - self.emit("if (x.m_%s) {" % field.name, 2) - self.emit( 's.append(".true.");', 3) - self.emit("} else {", 2) - self.emit( 's.append(".false.");', 3) - self.emit("}", 2) - elif field.type in self.data.simple_types: - if field.opt: - self.emit('s.append("Unimplementedopt");', 2) - else: - self.emit('visit_%sType(x.m_%s);' \ - % (field.type, field.name), 2) - else: - self.emit('s.append("Unimplemented' + field.type + '");', 2) - -class JsonVisitorVisitor(ASDLVisitor): - - def visitModule(self, mod): - self.emit("/" + "*"*78 + "/") - self.emit("// Json Visitor base class") - self.emit("") - self.emit("template ") - self.emit("class JsonBaseVisitor : public BaseVisitor") - self.emit("{") - self.emit("private:") - self.emit( "Struct& self() { return static_cast(*this); }", 1) - self.emit("public:") - self.emit( "std::string s, indtd = \"\";", 1) - self.emit( "int indent_level = 0, indent_spaces = 4;", 1) - # Storing a reference to LocationManager like this isn't ideal. - # One must make sure JsonBaseVisitor isn't reused in a case where AST/ASR has changed - # but lm wasn't updated correspondingly. - # If LocationManager becomes needed in any of the other visitors, it should be - # passed by reference into all the visit functions instead of storing the reference here. - self.emit( "LocationManager &lm;", 1) - self.emit("public:") - self.emit( "JsonBaseVisitor(LocationManager &lmref) : lm(lmref) {", 1); - self.emit( "s.reserve(100000);", 2) - self.emit( "}", 1) - self.emit( "void inc_indent() {", 1) - self.emit( "indent_level++;", 2) - self.emit( "indtd = std::string(indent_level*indent_spaces, ' ');",2) - self.emit( "}",1) - self.emit( "void dec_indent() {", 1) - self.emit( "indent_level--;", 2) - self.emit( "LCOMPILERS_ASSERT(indent_level >= 0);", 2) - self.emit( "indtd = std::string(indent_level*indent_spaces, ' ');",2) - self.emit( "}",1) - self.emit( "void append_location(std::string &s, uint32_t first, uint32_t last) {", 1) - self.emit( 's.append("\\"loc\\": {");', 2); - self.emit( 'inc_indent();', 2) - self.emit( 's.append("\\n" + indtd);', 2) - self.emit( 's.append("\\"first\\": " + std::to_string(first));', 2) - self.emit( 's.append(",\\n" + indtd);', 2) - self.emit( 's.append("\\"last\\": " + std::to_string(last));', 2) - self.emit( '') - self.emit( 'uint32_t first_line = 0, first_col = 0;', 2) - self.emit( 'std::string first_filename;', 2) - self.emit( 'uint32_t last_line = 0, last_col = 0;', 2) - self.emit( 'std::string last_filename;', 2) - self.emit( '') - self.emit( 'lm.pos_to_linecol(first, first_line, first_col, first_filename);', 2) - self.emit( 'lm.pos_to_linecol(last, last_line, last_col, last_filename);', 2) - self.emit( '') - self.emit( 's.append(",\\n" + indtd);', 2) - self.emit( 's.append("\\"first_filename\\": \\"" + first_filename + "\\"");', 2) - self.emit( 's.append(",\\n" + indtd);', 2) - self.emit( 's.append("\\"first_line\\": " + std::to_string(first_line));', 2) - self.emit( 's.append(",\\n" + indtd);', 2) - self.emit( 's.append("\\"first_column\\": " + std::to_string(first_col));', 2) - self.emit( 's.append(",\\n" + indtd);', 2) - self.emit( 's.append("\\"last_filename\\": \\"" + last_filename + "\\"");', 2) - self.emit( 's.append(",\\n" + indtd);', 2) - self.emit( 's.append("\\"last_line\\": " + std::to_string(last_line));', 2) - self.emit( 's.append(",\\n" + indtd);', 2) - self.emit( 's.append("\\"last_column\\": " + std::to_string(last_col));', 2) - self.emit( '') - self.emit( 'dec_indent();', 2) - self.emit( 's.append("\\n" + indtd);', 2) - self.emit( 's.append("}");', 2) - self.emit( '}', 1) - - self.mod = mod - super(JsonVisitorVisitor, self).visitModule(mod) - self.emit("};") - - def visitType(self, tp): - super(JsonVisitorVisitor, self).visitType(tp, tp.name) - - def visitSum(self, sum, *args): - assert isinstance(sum, asdl.Sum) - if is_simple_sum(sum): - name = args[0] + "Type" - self.make_simple_sum_visitor(name, sum.types) - else: - for tp in sum.types: - self.visit(tp, *args) - - def visitProduct(self, prod, name): - self.make_visitor(name, prod.fields, False) - - def visitConstructor(self, cons, _): - self.make_visitor(cons.name, cons.fields, True) - - def make_visitor(self, name, fields, cons): - self.emit("void visit_%s(const %s_t &x) {" % (name, name), 1) - self.emit( 's.append("{");', 2) - self.emit( 'inc_indent(); s.append("\\n" + indtd);', 2) - self.emit( 's.append("\\"node\\": \\"%s\\"");' % name, 2) - self.emit( 's.append(",\\n" + indtd);', 2) - self.emit( 's.append("\\"fields\\": {");', 2) - if len(fields) > 0: - self.emit('inc_indent(); s.append("\\n" + indtd);', 2) - for n, field in enumerate(fields): - self.visitField(field, cons) - if n < len(fields) - 1: - self.emit('s.append(",\\n" + indtd);', 2) - self.emit('dec_indent(); s.append("\\n" + indtd);', 2) - self.emit( 's.append("}");', 2) - self.emit( 's.append(",\\n" + indtd);', 2) - if name in products: - self.emit( 'append_location(s, x.loc.first, x.loc.last);', 2) - else: - self.emit( 'append_location(s, x.base.base.loc.first, x.base.base.loc.last);', 2) - - self.emit( 'dec_indent(); s.append("\\n" + indtd);', 2) - self.emit( 's.append("}");', 2) - self.emit( 'if ((bool&)x) { } // Suppress unused warning', 2) - self.emit("}", 1) - - def make_simple_sum_visitor(self, name, types): - self.emit("void visit_%s(const %s &x) {" % (name, name), 1) - self.emit( 'switch (x) {', 2) - for tp in types: - self.emit( 'case (%s::%s) : {' % (name, tp.name), 3) - self.emit( 's.append("\\"%s\\"");' % (tp.name), 4) - self.emit( ' break; }',3) - self.emit( '}', 2) - self.emit("}", 1) - - def visitField(self, field, cons): - self.emit('s.append("\\"%s\\": ");' % field.name, 2) - if (field.type not in asdl.builtin_types and - field.type not in self.data.simple_types): - self.used = True - level = 2 - if field.type in products: - if field.opt: - template = "self().visit_%s(*x.m_%s);" % (field.type, field.name) - else: - template = "self().visit_%s(x.m_%s);" % (field.type, field.name) - else: - template = "self().visit_%s(*x.m_%s);" % (field.type, field.name) - if field.seq: - self.emit('s.append("[");', level) - self.emit('if (x.n_%s > 0) {' % field.name, level) - self.emit( 'inc_indent(); s.append("\\n" + indtd);', level+1) - self.emit( "for (size_t i=0; i 0) {' % field.name, level) - self.emit( 'inc_indent(); s.append("\\n" + indtd);', level+1) - self.emit( "for (size_t i=0; i 0) {' % field.name, level) - self.emit( 'inc_indent(); s.append("\\n" + indtd);', level+1) - self.emit( "for (size_t i=0; iget_counter());' % field.name, level) - else: - level = 2 - self.emit('s.append("{");', level) - self.emit('inc_indent(); s.append("\\n" + indtd);', level) - self.emit('s.append("\\"node\\": \\"SymbolTable" + x.m_%s->get_counter() +"\\"");' % field.name, level) - self.emit('s.append(",\\n" + indtd);', level) - self.emit('s.append("\\"fields\\": {");', level) - self.emit('if (x.m_%s->get_scope().size() > 0) {' % field.name, level) - self.emit( 'inc_indent(); s.append("\\n" + indtd);', level+1) - self.emit( 'size_t i = 0;', level+1) - self.emit( 'for (auto &a : x.m_%s->get_scope()) {' % field.name, level+1) - self.emit( 's.append("\\"" + a.first + "\\": ");', level+2) - self.emit( 'this->visit_symbol(*a.second);', level+2) - self.emit( 'if (i < x.m_%s->get_scope().size()-1) { ' % field.name, level+2) - self.emit( ' s.append(",\\n" + indtd);', level+3) - self.emit( '}', level+2) - self.emit( 'i++;', level+2) - self.emit( '}', level+1) - self.emit( 'dec_indent(); s.append("\\n" + indtd);', level+1) - self.emit('}', level) - self.emit('s.append("}");', level) - self.emit('dec_indent(); s.append("\\n" + indtd);', level) - self.emit('s.append("}");', level) - elif field.type == "string" and not field.seq: - if field.opt: - self.emit("if (x.m_%s) {" % field.name, 2) - self.emit( 's.append("\\"" + std::string(x.m_%s) + "\\"");' % field.name, 3) - self.emit("} else {", 2) - self.emit( 's.append("[]");', 3) - self.emit("}", 2) - else: - self.emit('s.append("\\"" + std::string(x.m_%s) + "\\"");' % field.name, 2) - elif field.type == "int" and not field.seq: - if field.opt: - self.emit("if (x.m_%s) {" % field.name, 2) - self.emit( 's.append(std::to_string(x.m_%s));' % field.name, 3) - self.emit("} else {", 2) - self.emit( 's.append("[]");', 3) - self.emit("}", 2) - else: - self.emit('s.append(std::to_string(x.m_%s));' % field.name, 2) - elif field.type == "float" and not field.seq and not field.opt: - self.emit('s.append(std::to_string(x.m_%s));' % field.name, 2) - elif field.type == "bool" and not field.seq and not field.opt: - self.emit("if (x.m_%s) {" % field.name, 2) - self.emit( 's.append("true");', 3) - self.emit("} else {", 2) - self.emit( 's.append("false");', 3) - self.emit("}", 2) - elif field.type in self.data.simple_types: - if field.opt: - self.emit('s.append("\\"Unimplementedopt\\"");', 2) - else: - self.emit('visit_%sType(x.m_%s);' \ - % (field.type, field.name), 2) - else: - self.emit('s.append("\\"Unimplemented%s\\"");' % field.type, 2) - - -class SerializationVisitorVisitor(ASDLVisitor): - - def visitModule(self, mod): - self.emit("/" + "*"*78 + "/") - self.emit("// Serialization Visitor base class") - self.emit("") - self.emit("template ") - self.emit("class SerializationBaseVisitor : public BaseVisitor") - self.emit("{") - self.emit("private:") - self.emit( "Struct& self() { return static_cast(*this); }", 1) - self.emit("public:") - self.mod = mod - super(SerializationVisitorVisitor, self).visitModule(mod) - self.emit("};") - - def visitType(self, tp): - super(SerializationVisitorVisitor, self).visitType(tp, tp.name) - - def visitSum(self, sum, *args): - assert isinstance(sum, asdl.Sum) - if is_simple_sum(sum): - name = args[0] + "Type" - self.make_simple_sum_visitor(name, sum.types) - else: - for tp in sum.types: - self.visit(tp, *args) - - def visitProduct(self, prod, name): - self.make_visitor(name, prod.fields, False) - - def visitConstructor(self, cons, _): - self.make_visitor(cons.name, cons.fields, True) - - def make_visitor(self, name, fields, cons): - self.emit("void visit_%s(const %s_t &x) {" % (name, name), 1) - if cons: - self.emit( 'self().write_int8(x.base.type);', 2) - self.emit( 'self().write_int64(x.base.base.loc.first);', 2) - self.emit( 'self().write_int64(x.base.base.loc.last);', 2) - self.used = False - for n, field in enumerate(fields): - self.visitField(field, cons, name) - if not self.used: - # Note: a better solution would be to change `&x` to `& /* x */` - # above, but we would need to change emit to return a string. - self.emit("if ((bool&)x) { } // Suppress unused warning", 2) - self.emit("}", 1) - - def make_simple_sum_visitor(self, name, types): - self.emit("void visit_%s(const %s &x) {" % (name, name), 1) - self.emit( 'self().write_int8(x);', 2) - self.emit("}", 1) - - def visitField(self, field, cons, cons_name): - if (field.type not in asdl.builtin_types and - field.type not in self.data.simple_types): - self.used = True - level = 2 - if field.type in products: - if field.opt: - template = "self().visit_%s(*x.m_%s);" % (field.type, field.name) - else: - template = "self().visit_%s(x.m_%s);" % (field.type, field.name) - else: - if field.type == "symbol": - if cons_name == "ExternalSymbol": - template = "// We skip the symbol for ExternalSymbol" - else: - template = "self().write_symbol(*x.m_%s);" \ - % field.name - else: - template = "self().visit_%s(*x.m_%s);" % (field.type, field.name) - if field.seq: - self.emit('self().write_int64(x.n_%s);' % field.name, level) - self.emit("for (size_t i=0; itype);" % \ - field.name, level+1) - self.emit("self().visit_%s(*x.m_%s[i]);" % (mod_name, field.name), level+1) - self.emit("}", level) - elif field.type == "symbol_table": - assert not field.opt - assert not field.seq - # TODO: write the symbol table consistent with the reader: - if field.name == "parent_symtab": - level = 2 - self.emit('self().write_int64(x.m_%s->counter);' % field.name, level) - else: - level = 2 - self.emit('self().write_int64(x.m_%s->counter);' % field.name, level) - self.emit('self().write_int64(x.m_%s->get_scope().size());' % field.name, level) - self.emit('for (auto &a : x.m_%s->get_scope()) {' % field.name, level) - self.emit(' if (ASR::is_a(*a.second)) {', level) - self.emit(' continue;', level) - self.emit(' }', level) - self.emit(' self().write_string(a.first);', level) - self.emit(' this->visit_symbol(*a.second);', level) - self.emit('}', level) - self.emit('for (auto &a : x.m_%s->get_scope()) {' % field.name, level) - self.emit(' if (ASR::is_a(*a.second)) {', level) - self.emit(' self().write_string(a.first);', level) - self.emit(' this->visit_symbol(*a.second);', level) - self.emit(' }', level) - self.emit('}', level) - elif field.type == "string" and not field.seq: - if field.opt: - self.emit("if (x.m_%s) {" % field.name, 2) - self.emit( 'self().write_bool(true);', 3) - self.emit( 'self().write_string(x.m_%s);' % field.name, 3) - self.emit("} else {", 2) - self.emit( 'self().write_bool(false);', 3) - self.emit("}", 2) - else: - self.emit('self().write_string(x.m_%s);' % field.name, 2) - elif field.type == "int" and not field.seq: - if field.opt: - self.emit("if (x.m_%s) {" % field.name, 2) - self.emit( 'self().write_bool(true);', 3) - self.emit( 'self().write_int64(x.m_%s);' % field.name, 3) - self.emit("} else {", 2) - self.emit( 'self().write_bool(false);', 3) - self.emit("}", 2) - else: - self.emit('self().write_int64(x.m_%s);' % field.name, 2) - elif field.type == "bool" and not field.seq and not field.opt: - self.emit("if (x.m_%s) {" % field.name, 2) - self.emit( 'self().write_bool(true);', 3) - self.emit("} else {", 2) - self.emit( 'self().write_bool(false);', 3) - self.emit("}", 2) - elif field.type == "float" and not field.seq and not field.opt: - self.emit('self().write_float64(x.m_%s);' % field.name, 2) - elif field.type in self.data.simple_types: - if field.opt: - raise Exception("Unimplemented opt for field type: " + field.type); - else: - self.emit('visit_%sType(x.m_%s);' \ - % (field.type, field.name), 2) - else: - raise Exception("Unimplemented field type: " + field.type); - -class DeserializationVisitorVisitor(ASDLVisitor): - - def visitModule(self, mod): - self.emit("/" + "*"*78 + "/") - self.emit("// Deserialization Visitor base class") - self.emit("") - self.emit("template ") - self.emit("class DeserializationBaseVisitor : public BaseVisitor") - self.emit("{") - self.emit("private:") - self.emit( "Struct& self() { return static_cast(*this); }", 1) - self.emit("public:") - self.emit( "Allocator &al;", 1) - self.emit( "bool load_symtab_id;", 1) - self.emit( "std::map id_symtab_map;", 1) - self.emit( r"DeserializationBaseVisitor(Allocator &al, bool load_symtab_id) : al{al}, load_symtab_id{load_symtab_id} {}", 1) - self.emit_deserialize_node(); - self.mod = mod - super(DeserializationVisitorVisitor, self).visitModule(mod) - self.emit("};") - - def visitType(self, tp): - super(DeserializationVisitorVisitor, self).visitType(tp, tp.name) - - def visitSum(self, sum, *args): - assert isinstance(sum, asdl.Sum) - if is_simple_sum(sum): - self.emit("%sType deserialize_%s() {" % (args[0], args[0]), 1) - self.emit( 'uint8_t t = self().read_int8();', 2) - self.emit( '%sType ty = static_cast<%sType>(t);' % (args[0], args[0]), 2) - self.emit( 'return ty;', 2) - self.emit("}", 1) - else: - for tp in sum.types: - self.visit(tp, *args) - self.emit("%s_t* deserialize_%s() {" % (subs["mod"], args[0]), 1) - self.emit( 'uint8_t t = self().read_int8();', 2) - self.emit( '%s::%sType ty = static_cast<%s::%sType>(t);' % (subs["MOD"], args[0], - subs["MOD"], args[0]), 2) - self.emit( 'switch (ty) {', 2) - for tp in sum.types: - self.emit( 'case (%s::%sType::%s) : return self().deserialize_%s();' \ - % (subs["MOD"], args[0], tp.name, tp.name), 3) - self.emit( 'default : throw LCompilersException("Unknown type in deserialize_%s()");' % args[0], 3) - self.emit( '}', 2) - self.emit( 'throw LCompilersException("Switch statement above was not exhaustive.");', 2) - - self.emit("}", 1) - - def emit_deserialize_node(self): - name = "node" - self.emit("%s_t* deserialize_%s() {" % (subs["mod"], name), 1) - self.emit( 'uint8_t t = self().read_int8();', 2) - self.emit( '%s::%sType ty = static_cast<%s::%sType>(t);' % (subs["MOD"], subs["mod"], - subs["MOD"], subs["mod"]), 2) - self.emit( 'switch (ty) {', 2) - for tp in sums: - self.emit( 'case (%s::%sType::%s) : return self().deserialize_%s();' \ - % (subs["MOD"], subs["mod"], tp, tp), 3) - self.emit( 'default : throw LCompilersException("Unknown type in deserialize_%s()");' % name, 3) - self.emit( '}', 2) - self.emit( 'throw LCompilersException("Switch statement above was not exhaustive.");', 2) - self.emit( '}', 1) - - def visitProduct(self, prod, name): - self.emit("%s_t deserialize_%s() {" % (name, name), 1) - self.emit( '%s_t x;' % (name), 2) - for field in prod.fields: - if field.seq: - assert not field.opt - assert field.type not in simple_sums - if field.type in asdl.builtin_types: - if field.type == "identifier": - self.emit('{', 2) - self.emit('uint64_t n = self().read_int64();', 3) - self.emit("Vec v;", 3) - self.emit("v.reserve(al, n);", 3) - self.emit("for (uint64_t i=0; i v;" % (field.type), 3) - else: - self.emit("Vec<%s_t*> v;" % (field.type), 3) - self.emit("v.reserve(al, n);", 3) - self.emit("for (uint64_t i=0; i(self().deserialize_%s()));" % (field.type, field.type), 4) - self.emit('}', 3) - self.emit('x.m_%s = v.p;' % (field.name), 3) - self.emit('x.n_%s = v.n;' % (field.name), 3) - self.emit('}', 2) - else: - self.emit('{', 2) - if field.opt: - self.emit("bool present=self().read_bool();", 3) - if field.type in asdl.builtin_types: - if field.type == "identifier": - rhs = "self().read_cstring()" - elif field.type == "string": - rhs = "self().read_cstring()" - elif field.type == "int": - rhs = "self().read_int64()" - else: - print(field.type) - assert False - elif field.type in simple_sums: - rhs = "deserialize_%s()" % (field.type) - else: - assert field.type not in products - if field.type == "symbol": - rhs = "self().read_symbol()" - else: - rhs = "down_cast<%s_t>(deserialize_%s())" % (field.type, - field.type) - if field.opt: - self.emit('if (present) {', 3) - self.emit('x.m_%s = %s;' % (field.name, rhs), 4) - if field.opt: - self.emit('} else {', 3) - self.emit( 'x.m_%s = nullptr;' % (field.name), 4) - self.emit('}', 3) - self.emit('}', 2) - self.emit( 'return x;', 2) - self.emit("}", 1) - - def visitConstructor(self, cons, _): - name = cons.name - self.emit("%s_t* deserialize_%s() {" % (subs["mod"], name), 1) - lines = [] - args = ["al", "loc"] - for f in cons.fields: - #type_ = convert_type(f.type, f.seq, f.opt, self.mod.name.lower()) - if f.seq: - seq = "size_t n_%s; // Sequence" % f.name - self.emit("%s" % seq, 2) - else: - seq = "" - if f.seq: - assert f.type not in self.data.simple_types - if f.type not in asdl.builtin_types: - lines.append("n_%s = self().read_int64();" % (f.name)) - if f.type in products: - lines.append("Vec<%s_t> v_%s;" % (f.type, f.name)) - else: - lines.append("Vec<%s_t*> v_%s;" % (f.type, f.name)) - lines.append("v_%s.reserve(al, n_%s);" % (f.name, f.name)) - lines.append("for (size_t i=0; i(self().deserialize_%s()));" % (f.name, - subs["MOD"], subs["MOD"], f.type, f.type)) - lines.append("}") - else: - if f.type == "node": - lines.append("n_%s = self().read_int64();" % (f.name)) - lines.append("Vec<%s_t*> v_%s;" % (subs["mod"], f.name)) - lines.append("v_%s.reserve(al, n_%s);" % (f.name, f.name)) - lines.append("for (size_t i=0; i v_%s;" % (f.name)) - lines.append("v_%s.reserve(al, n_%s);" % (f.name, f.name)) - lines.append("for (size_t i=0; i(nullptr);" % (f.name)) - lines.append("if (load_symtab_id) m_%s->counter = m_%s_counter;" % (f.name, f.name)) - lines.append("id_symtab_map[m_%s_counter] = m_%s;" % (f.name, f.name)) - lines.append("{") - lines.append(" size_t n = self().read_int64();") - lines.append(" for (size_t i=0; i(deserialize_symbol());") - lines.append(" self().symtab_insert_symbol(*m_%s, name, sym);" % f.name) - lines.append(" }") - lines.append("}") - else: - print(f.type) - assert False - else: - if f.type in products: - assert not f.opt - lines.append("%s::%s_t m_%s = self().deserialize_%s();" % (subs["MOD"], f.type, f.name, f.type)) - else: - if f.type in simple_sums: - assert not f.opt - lines.append("%s::%sType m_%s = self().deserialize_%s();" % (subs["MOD"], - f.type, f.name, f.type)) - else: - lines.append("%s::%s_t *m_%s;" % (subs["MOD"], - f.type, f.name)) - if f.opt: - lines.append("if (self().read_bool()) {") - if f.type == "symbol": - if name == "ExternalSymbol": - lines.append("// We skip the symbol for ExternalSymbol") - lines.append("m_%s = nullptr;" % (f.name)) - else: - lines.append("m_%s = self().read_symbol();" % (f.name)) - else: - lines.append("m_%s = %s::down_cast<%s::%s_t>(self().deserialize_%s());" % ( - f.name, subs["MOD"], subs["MOD"], f.type, f.type)) - if f.opt: - lines.append("} else {") - lines.append("m_%s = nullptr;" % f.name) - lines.append("}") - args.append("m_%s" % (f.name)) - - self.emit( 'Location loc;', 2) - self.emit( 'loc.first = self().read_int64();', 2) - self.emit( 'loc.last = self().read_int64();', 2) - if subs["lcompiler"] == "lfortran": - # Set the location to 0 for now, since we do not yet - # support multiple files - self.emit( 'loc.first = 0;', 2) - self.emit( 'loc.last = 0;', 2) - for line in lines: - self.emit(line, 2) - self.emit( 'return %s::make_%s_t(%s);' % (subs["MOD"], name, ", ".join(args)), 2) - self.emit("}", 1) - -class ExprTypeVisitor(ASDLVisitor): - - def __init__(self, stream, data): - self.replace_expr = [] - self.is_expr = False - self.is_product = False - super(ExprTypeVisitor, self).__init__(stream, data) - - def emit(self, line, level=0, new_line=True): - indent = " "*level - self.stream.write(indent + line) - if new_line: - self.stream.write("\n") - - def visitModule(self, mod): - self.emit("/" + "*"*78 + "/") - self.emit("// Expression Type (`expr_type`) visitor") - self.emit("""\ -static inline ASR::ttype_t* expr_type0(const ASR::expr_t *f) -{ - LCOMPILERS_ASSERT(f != nullptr); - switch (f->type) {""") - - super(ExprTypeVisitor, self).visitModule(mod) - - self.emit(""" default : throw LCompilersException("Not implemented"); - } -} -""") - - def visitType(self, tp): - if not (isinstance(tp.value, asdl.Sum) and - is_simple_sum(tp.value)): - super(ExprTypeVisitor, self).visitType(tp, tp.name) - - def visitSum(self, sum, *args): - self.is_expr = args[0] == 'expr' - if self.is_expr: - for tp in sum.types: - self.visit(tp, *args) - - def visitProduct(self, prod, name): - pass - - def visitConstructor(self, cons, _): - self.make_visitor(cons.name, cons.fields) - - def make_visitor(self, name, fields): - if name == "Var": - self.emit("""case ASR::exprType::%s: { - ASR::symbol_t *s = ((ASR::%s_t*)f)->m_v; - if (s->type == ASR::symbolType::ExternalSymbol) { - ASR::ExternalSymbol_t *e = ASR::down_cast(s); - LCOMPILERS_ASSERT(e->m_external); - LCOMPILERS_ASSERT(!ASR::is_a(*e->m_external)); - s = e->m_external; - } else if (s->type == ASR::symbolType::Function) { - return ASR::down_cast(s)->m_function_signature; - } - return ASR::down_cast(s)->m_type; - }""" \ - % (name, name), 2, new_line=False) - elif name == "OverloadedBinOp": - self.emit("case ASR::exprType::%s: { return expr_type0(((ASR::%s_t*)f)->m_overloaded); }"\ - % (name, name), 2, new_line=False) - else: - self.emit("case ASR::exprType::%s: { return ((ASR::%s_t*)f)->m_type; }"\ - % (name, name), 2, new_line=False) - self.emit("") - - def visitField(self, field): - pass - -class ExprValueVisitor(ASDLVisitor): - - def __init__(self, stream, data): - self.replace_expr = [] - self.is_expr = False - self.is_product = False - super(ExprValueVisitor, self).__init__(stream, data) - - def emit(self, line, level=0, new_line=True): - indent = " "*level - self.stream.write(indent + line) - if new_line: - self.stream.write("\n") - - def visitModule(self, mod): - self.emit("/" + "*"*78 + "/") - self.emit("// Expression Value (`expr_value`) visitor") - self.emit("""\ -static inline ASR::expr_t* expr_value0(ASR::expr_t *f) -{ - LCOMPILERS_ASSERT(f != nullptr); - switch (f->type) {""") - - super(ExprValueVisitor, self).visitModule(mod) - - self.emit(""" default : throw LCompilersException("Not implemented"); - } -} -""") - - def visitType(self, tp): - if not (isinstance(tp.value, asdl.Sum) and - is_simple_sum(tp.value)): - super(ExprValueVisitor, self).visitType(tp, tp.name) - - def visitSum(self, sum, *args): - self.is_expr = args[0] == 'expr' - if self.is_expr: - for tp in sum.types: - self.visit(tp, *args) - - def visitProduct(self, prod, name): - pass - - def visitConstructor(self, cons, _): - self.make_visitor(cons.name, cons.fields) - - def make_visitor(self, name, fields): - if name == "Var": - self.emit("""case ASR::exprType::%s: { - ASR::symbol_t *s = ((ASR::%s_t*)f)->m_v; - if (s->type == ASR::symbolType::ExternalSymbol) { - ASR::ExternalSymbol_t *e = ASR::down_cast(s); - LCOMPILERS_ASSERT(!ASR::is_a(*e->m_external)); - s = e->m_external; - } - return ASR::down_cast(s)->m_value; - }""" \ - % (name, name), 2, new_line=False) - elif name.endswith("Constant") or name == "IntegerBOZ": - self.emit("case ASR::exprType::%s: { return f; }"\ - % (name), 2, new_line=False) - else: - self.emit("case ASR::exprType::%s: { return ((ASR::%s_t*)f)->m_value; }"\ - % (name, name), 2, new_line=False) - self.emit("") - - def visitField(self, field): - pass - -class ASDLData(object): - - def __init__(self, tree): - simple_types = set() - prod_simple = set() - field_masks = {} - required_masks = {} - optional_masks = {} - cons_attributes = {} - def add_masks(fields, node): - required_mask = 0 - optional_mask = 0 - for i, field in enumerate(fields): - flag = 1 << i - if field not in field_masks: - field_masks[field] = flag - else: - assert field_masks[field] == flag - if field.opt: - optional_mask |= flag - else: - required_mask |= flag - required_masks[node] = required_mask - optional_masks[node] = optional_mask - for tp in tree.dfns: - if isinstance(tp.value, asdl.Sum): - sum = tp.value - if is_simple_sum(sum): - simple_types.add(tp.name) - else: - attrs = [field for field in sum.attributes] - for cons in sum.types: - add_masks(attrs + cons.fields, cons) - cons_attributes[cons] = attrs - else: - prod = tp.value - prod_simple.add(tp.name) - add_masks(prod.fields, prod) - prod_simple.update(simple_types) - self.cons_attributes = cons_attributes - self.simple_types = simple_types - self.prod_simple = prod_simple - self.field_masks = field_masks - self.required_masks = required_masks - self.optional_masks = optional_masks - - -HEAD = r"""#ifndef LFORTRAN_%(MOD2)s_H -#define LFORTRAN_%(MOD2)s_H - -// Generated by grammar/asdl_cpp.py - -#include -#include -#include -#include -#include -#include - - -namespace LCompilers::%(MOD)s { - -enum %(mod)sType -{ - %(types)s -}; - -struct %(mod)s_t -{ - %(mod)sType type; - Location loc; -}; - - -template -inline bool is_a(const U &x) -{ - return T::class_type == x.type; -} - -// Cast one level down - -template -static inline T* down_cast(const U *f) -{ - LCOMPILERS_ASSERT(f != nullptr); - LCOMPILERS_ASSERT(is_a(*f)); - return (T*)f; -} - -// Cast two levels down - -template -static inline T* down_cast2(const %(mod)s_t *f) -{ - typedef typename T::parent_type ptype; - ptype *t = down_cast(f); - return down_cast(t); -} - -""" - -FOOT = r"""} // namespace LCompilers::%(MOD)s - -#endif // LFORTRAN_%(MOD2)s_H -""" - -visitors = [ASTNodeVisitor0, ASTNodeVisitor1, ASTNodeVisitor, - ASTVisitorVisitor1, ASTVisitorVisitor1b, ASTVisitorVisitor2, - ASTWalkVisitorVisitor, TreeVisitorVisitor, PickleVisitorVisitor, - JsonVisitorVisitor, SerializationVisitorVisitor, DeserializationVisitorVisitor] - - -def main(argv): - if len(argv) == 3: - def_file, out_file = argv[1:] - else: - print("invalid arguments") - return 2 - mod = asdl.parse(def_file) - data = ASDLData(mod) - CollectVisitor(None, data).visit(mod) - types_ = ", ".join(sums) - global subs - subs = { - "MOD": mod.name.upper(), - "MOD2": mod.name.upper(), - "mod": mod.name.lower(), - "types": types_, - } - if subs["MOD"] == "LPYTHON": - subs["MOD"] = "LPython::AST" - subs["mod"] = "ast" - subs["lcompiler"] = "lpython" - elif subs["MOD"] == "AST": - subs["MOD"] = "LFortran::AST" - subs["lcompiler"] = "lfortran" - else: - subs["lcompiler"] = "lfortran" - is_asr = (mod.name.upper() == "ASR") - fp = open(out_file, "w", encoding="utf-8") - try: - fp.write(HEAD % subs) - for visitor in visitors: - visitor(fp, data).visit(mod) - fp.write("\n\n") - if not is_asr: - fp.write(FOOT % subs) - finally: - if not is_asr: - fp.close() - - try: - if is_asr: - ExprStmtDuplicatorVisitor(fp, data).visit(mod) - fp.write("\n\n") - ExprBaseReplacerVisitor(fp, data).visit(mod) - fp.write("\n\n") - StmtBaseReplacerVisitor(fp, data).visit(mod) - fp.write("\n\n") - CallReplacerOnExpressionsVisitor(fp, data).visit(mod) - fp.write("\n\n") - ExprTypeVisitor(fp, data).visit(mod) - fp.write("\n\n") - ExprValueVisitor(fp, data).visit(mod) - fp.write("\n\n") - fp.write(FOOT % subs) - finally: - fp.close() - - -if __name__ == "__main__": - sys.exit(main(sys.argv)) diff --git a/src/libasr/asr_scopes.cpp b/src/libasr/asr_scopes.cpp deleted file mode 100644 index 5fc47695f7..0000000000 --- a/src/libasr/asr_scopes.cpp +++ /dev/null @@ -1,303 +0,0 @@ -#include -#include - -#include -#include - -namespace LCompilers { - -// This function is taken from: -// https://github.com/aappleby/smhasher/blob/61a0530f28277f2e850bfc39600ce61d02b518de/src/MurmurHash2.cpp#L37 -uint32_t murmur_hash(const void * key, int len, uint32_t seed) -{ - // 'm' and 'r' are mixing constants generated offline. - // They're not really 'magic', they just happen to work well. - const uint32_t m = 0x5bd1e995; - const int r = 24; - // Initialize the hash to a 'random' value - uint32_t h = seed ^ len; - // Mix 4 bytes at a time into the hash - const unsigned char * data = (const unsigned char *)key; - while(len >= 4) - { - uint32_t k = *(uint32_t*)data; - k *= m; - k ^= k >> r; - k *= m; - h *= m; - h ^= k; - data += 4; - len -= 4; - } - // Handle the last few bytes of the input array - switch(len) - { - case 3: h ^= data[2] << 16; // fall through - case 2: h ^= data[1] << 8; // fall through - case 1: h ^= data[0]; - h *= m; - }; - // Do a few final mixes of the hash to ensure the last few - // bytes are well-incorporated. - h ^= h >> 13; - h *= m; - h ^= h >> 15; - return h; -} - -uint32_t murmur_hash_str(const std::string &s, uint32_t seed) -{ - return murmur_hash(&s[0], s.length(), seed); -} - -uint32_t murmur_hash_int(uint64_t i, uint32_t seed) -{ - return murmur_hash(&i, 8, seed); -} - -template< typename T > -std::string hexify(T i) -{ - std::stringbuf buf; - std::ostream os(&buf); - os << std::setfill('0') << std::setw(sizeof(T) * 2) << std::hex << i; - return buf.str(); -} - -unsigned int symbol_table_counter = 0; - -SymbolTable::SymbolTable(SymbolTable *parent) : parent{parent} { - symbol_table_counter++; - counter = symbol_table_counter; -} - -void SymbolTable::reset_global_counter() { - symbol_table_counter = 0; -} - -void SymbolTable::mark_all_variables_external(Allocator &/*al*/) { - for (auto &a : scope) { - switch (a.second->type) { - case (ASR::symbolType::Variable) : { - ASR::Variable_t *v = ASR::down_cast(a.second); - v->m_abi = ASR::abiType::Interactive; - break; - } - case (ASR::symbolType::Function) : { - ASR::Function_t *v = ASR::down_cast(a.second); - ASR::FunctionType_t* v_func_type = ASR::down_cast(v->m_function_signature); - v_func_type->m_abi = ASR::abiType::Interactive; - v->m_body = nullptr; - v->n_body = 0; - break; - } - default : {}; - } - } -} - -ASR::symbol_t *SymbolTable::find_scoped_symbol(const std::string &name, - size_t n_scope_names, char **m_scope_names) { - const SymbolTable *s = this; - for(size_t i=0; i < n_scope_names; i++) { - std::string scope_name = m_scope_names[i]; - if (s->scope.find(scope_name) != scope.end()) { - ASR::symbol_t *sym = s->scope.at(scope_name); - s = ASRUtils::symbol_symtab(sym); - if (s == nullptr) { - // The m_scope_names[i] found in the appropriate symbol table, - // but points to a symbol that itself does not have a symbol - // table - return nullptr; - } - } else { - // The m_scope_names[i] not found in the appropriate symbol table - return nullptr; - } - } - if (s->scope.find(name) != scope.end()) { - ASR::symbol_t *sym = s->scope.at(name); - LCOMPILERS_ASSERT(sym) - return sym; - } else { - // The `name` not found in the appropriate symbol table - return nullptr; - } -} - -std::string SymbolTable::get_unique_name(const std::string &name) { - std::string unique_name = name; - int counter = 1; - while (scope.find(unique_name) != scope.end()) { - unique_name = name + std::to_string(counter); - counter++; - } - return unique_name; -} - -void SymbolTable::move_symbols_from_global_scope(Allocator &al, - SymbolTable *module_scope, Vec &syms, - Vec &mod_dependencies, Vec &func_dependencies, - Vec &var_init) { - // TODO: This isn't scalable. We have write a visitor in asdl_cpp.py - syms.reserve(al, 4); - mod_dependencies.reserve(al, 4); - func_dependencies.reserve(al, 4); - var_init.reserve(al, 4); - for (auto &a : scope) { - switch (a.second->type) { - case (ASR::symbolType::Module): { - // Pass - break; - } case (ASR::symbolType::Function) : { - ASR::Function_t *fn = ASR::down_cast(a.second); - for (size_t i = 0; i < fn->n_dependencies; i++ ) { - ASR::symbol_t *s = fn->m_symtab->get_symbol( - fn->m_dependencies[i]); - if (s == nullptr) { - std::string block_name = "block"; - ASR::symbol_t *block_s = fn->m_symtab->get_symbol(block_name); - int32_t j = 1; - while(block_s != nullptr) { - while(block_s != nullptr) { - ASR::Block_t *b = ASR::down_cast(block_s); - s = b->m_symtab->get_symbol(fn->m_dependencies[i]); - if (s == nullptr) { - block_s = b->m_symtab->get_symbol("block"); - } else { - break; - } - } - if (s == nullptr) { - block_s = fn->m_symtab->get_symbol(block_name + - std::to_string(j)); - j++; - } else { - break; - } - } - } - if (s == nullptr) { - s = fn->m_symtab->parent->get_symbol(fn->m_dependencies[i]); - } - if (s != nullptr && ASR::is_a(*s)) { - char *es_name = ASR::down_cast< - ASR::ExternalSymbol_t>(s)->m_module_name; - if (!present(mod_dependencies, es_name)) { - mod_dependencies.push_back(al, es_name); - } - } - } - fn->m_symtab->parent = module_scope; - module_scope->add_symbol(a.first, (ASR::symbol_t *) fn); - syms.push_back(al, s2c(al, a.first)); - break; - } case (ASR::symbolType::GenericProcedure) : { - ASR::GenericProcedure_t *es = ASR::down_cast(a.second); - es->m_parent_symtab = module_scope; - module_scope->add_symbol(a.first, (ASR::symbol_t *) es); - syms.push_back(al, s2c(al, a.first)); - break; - } case (ASR::symbolType::ExternalSymbol) : { - ASR::ExternalSymbol_t *es = ASR::down_cast(a.second); - if (!present(mod_dependencies, es->m_module_name)) { - mod_dependencies.push_back(al, es->m_module_name); - } - es->m_parent_symtab = module_scope; - ASR::symbol_t *s = ASRUtils::symbol_get_past_external(a.second); - LCOMPILERS_ASSERT(s); - if (ASR::is_a(*s)) { - ASR::Variable_t *v = ASR::down_cast(s); - if (v->m_symbolic_value && !ASR::is_a(*v->m_type) - && ASR::is_a(*v->m_type)) { - ASR::expr_t* target = ASRUtils::EXPR(ASR::make_Var_t( - al, v->base.base.loc, (ASR::symbol_t *) es)); - ASR::expr_t *value = v->m_symbolic_value; - v->m_symbolic_value = nullptr; - v->m_value = nullptr; - if (ASR::is_a(*value)) { - ASR::FunctionCall_t *call = - ASR::down_cast(value); - ASR::Module_t *m = ASRUtils::get_sym_module(s); - ASR::symbol_t *func = m->m_symtab->get_symbol( - ASRUtils::symbol_name(call->m_name)); - ASR::Function_t *f = ASR::down_cast(func); - std::string func_name = std::string(m->m_name) + - "@" + f->m_name; - ASR::symbol_t *es_func; - if (!module_scope->get_symbol(func_name)) { - es_func = ASR::down_cast( - ASR::make_ExternalSymbol_t(al, f->base.base.loc, - module_scope, s2c(al, func_name), func, m->m_name, - nullptr, 0, s2c(al, f->m_name), ASR::accessType::Public)); - module_scope->add_symbol(func_name, es_func); - if (!present(func_dependencies, s2c(al, func_name))) { - func_dependencies.push_back(al, s2c(al,func_name)); - } - } else { - es_func = module_scope->get_symbol(func_name); - } - value = ASRUtils::EXPR(ASR::make_FunctionCall_t(al, - call->base.base.loc, es_func, call->m_original_name, - call->m_args, call->n_args, call->m_type, - call->m_value, call->m_dt)); - } - ASR::asr_t* assign = ASR::make_Assignment_t(al, - v->base.base.loc, target, value, nullptr); - var_init.push_back(al, ASRUtils::STMT(assign)); - } - } - module_scope->add_symbol(a.first, (ASR::symbol_t *) es); - syms.push_back(al, s2c(al, a.first)); - break; - } case (ASR::symbolType::StructType) : { - ASR::StructType_t *st = ASR::down_cast(a.second); - st->m_symtab->parent = module_scope; - module_scope->add_symbol(a.first, (ASR::symbol_t *) st); - syms.push_back(al, s2c(al, a.first)); - break; - } case (ASR::symbolType::EnumType) : { - ASR::EnumType_t *et = ASR::down_cast(a.second); - et->m_symtab->parent = module_scope; - module_scope->add_symbol(a.first, (ASR::symbol_t *) et); - syms.push_back(al, s2c(al, a.first)); - break; - } case (ASR::symbolType::UnionType) : { - ASR::UnionType_t *ut = ASR::down_cast(a.second); - ut->m_symtab->parent = module_scope; - module_scope->add_symbol(a.first, (ASR::symbol_t *) ut); - syms.push_back(al, s2c(al, a.first)); - break; - } case (ASR::symbolType::Variable) : { - ASR::Variable_t *v = ASR::down_cast(a.second); - v->m_parent_symtab = module_scope; - // Make the Assignment statement only for the data-types (List, - // Dict, ...), that cannot be handled in the LLVM global scope - if (v->m_symbolic_value && !ASR::is_a(*v->m_type) - && ASR::is_a(*v->m_type)) { - ASR::expr_t* v_expr = ASRUtils::EXPR(ASR::make_Var_t( - al, v->base.base.loc, (ASR::symbol_t *) v)); - ASR::asr_t* assign = ASR::make_Assignment_t(al, - v->base.base.loc, v_expr, v->m_symbolic_value, nullptr); - var_init.push_back(al, ASRUtils::STMT(assign)); - v->m_symbolic_value = nullptr; - v->m_value = nullptr; - Vec v_dependencies; - v_dependencies.reserve(al, 1); - ASRUtils::collect_variable_dependencies(al, - v_dependencies, v->m_type); - v->m_dependencies = v_dependencies.p; - v->n_dependencies = v_dependencies.size(); - } - module_scope->add_symbol(a.first, (ASR::symbol_t *) v); - syms.push_back(al, s2c(al, a.first)); - break; - } default : { - throw LCompilersException("Moving the symbol:`" + a.first + - "` from global scope is not implemented yet"); - } - } - } -} - -} // namespace LCompilers diff --git a/src/libasr/asr_scopes.h b/src/libasr/asr_scopes.h deleted file mode 100644 index 08395e30a7..0000000000 --- a/src/libasr/asr_scopes.h +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef LFORTRAN_SEMANTICS_ASR_SCOPES_H -#define LFORTRAN_SEMANTICS_ASR_SCOPES_H - -#include - -#include -#include - -namespace LCompilers { - -namespace ASR { - struct asr_t; - struct stmt_t; - struct symbol_t; -} - -struct SymbolTable { - private: - std::map scope; - - public: - SymbolTable *parent; - // The ASR node (either symbol_t or TranslationUnit_t) that contains this - // SymbolTable as m_symtab / m_global_scope member. One of: - // * symbol_symtab(down_cast(this->asr_owner)) == this - // * down_cast2(this->asr_owner)->m_global_scope == this - ASR::asr_t *asr_owner = nullptr; - unsigned int counter; - - SymbolTable(SymbolTable *parent); - - // Determines a stable hash based on the content of the symbol table - uint32_t get_hash_uint32(); // Returns the hash as an integer - std::string get_counter() { // Returns a unique ID as a string - return std::to_string(counter); - } - static void reset_global_counter(); // Resets the internal global counter - - // Resolves the symbol `name` recursively in current and parent scopes. - // Returns `nullptr` if symbol not found. - ASR::symbol_t* resolve_symbol(const std::string &name) { - if (scope.find(name) == scope.end()) { - if (parent) { - return parent->resolve_symbol(name); - } else { - return nullptr; - } - } - return scope[name]; - } - - const std::map& get_scope() const { - return scope; - } - - // Obtains the symbol `name` from the current symbol table - // Returns `nullptr` if symbol not found. - ASR::symbol_t* get_symbol(const std::string &name) const { - //auto it = scope.find(to_lower(name)); - auto it = scope.find(name); - if (it == scope.end()) { - return nullptr; - } else { - return it->second; - } - } - - void erase_symbol(const std::string &name) { - //auto it = scope.find(to_lower(name)); - LCOMPILERS_ASSERT(scope.find(name) != scope.end()) - scope.erase(name); - } - - void add_symbol(const std::string &name, ASR::symbol_t* symbol) { - scope[name] = symbol; - } - - // Marks all variables as external - void mark_all_variables_external(Allocator &al); - - ASR::symbol_t *find_scoped_symbol(const std::string &name, - size_t n_scope_names, char **m_scope_names); - - std::string get_unique_name(const std::string &name); - - void move_symbols_from_global_scope(Allocator &al, - SymbolTable *module_scope, Vec &syms, - Vec &mod_dependencies, Vec &func_dependencies, - Vec &var_init); -}; - -} // namespace LCompilers - -#endif // LFORTRAN_SEMANTICS_ASR_SCOPES_H diff --git a/src/libasr/asr_utils.cpp b/src/libasr/asr_utils.cpp deleted file mode 100644 index 3032d4d10d..0000000000 --- a/src/libasr/asr_utils.cpp +++ /dev/null @@ -1,1046 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace LCompilers { - - namespace ASRUtils { - -// depth-first graph traversal -void visit( - std::string const& a, - std::map> const& deps, - std::unordered_set& visited, - std::vector& result -) { - visited.insert(a); - auto it = deps.find(a); - if (it != deps.end()) { - for (auto n : it->second) { - if (!visited.count(n)) visit(n, deps, visited, result); - } - } - result.push_back(a); -} - -std::vector order_deps(std::map> const& deps) { - // Compute ordering: depth-first graph traversal, inserting nodes on way back - - // set containing the visited nodes - std::unordered_set visited; - - // vector containing result - std::vector result; - - for (auto d : deps) { - if (!visited.count(d.first)) { - visit(d.first, deps, visited, result); - } - } - return result; -} - -std::vector determine_module_dependencies( - const ASR::TranslationUnit_t &unit) -{ - std::map> deps; - for (auto &item : unit.m_global_scope->get_scope()) { - if (ASR::is_a(*item.second)) { - std::string name = item.first; - ASR::Module_t *m = ASR::down_cast(item.second); - deps[name] = std::vector(); - for (size_t i=0; i < m->n_dependencies; i++) { - std::string dep = m->m_dependencies[i]; - deps[name].push_back(dep); - } - } - } - return order_deps(deps); -} - -std::vector determine_function_definition_order( - SymbolTable* symtab) { - std::map> func_dep_graph; - ASR::symbol_t *sym; - for( auto itr: symtab->get_scope() ) { - if( ASR::is_a(*itr.second) ) { - std::vector deps; - ASR::Function_t* func = ASR::down_cast(itr.second); - for( size_t i = 0; i < func->n_dependencies; i++ ) { - std::string dep = func->m_dependencies[i]; - // Check if the dependent variable is present in the symtab. - // This will help us to include only local dependencies, and we - // assume that dependencies in the parent symtab are already declared - // earlier. - sym = symtab->get_symbol(dep); - if (sym != nullptr && ASR::is_a(*sym)) - deps.push_back(dep); - } - func_dep_graph[itr.first] = deps; - } - } - return ASRUtils::order_deps(func_dep_graph); -} - -std::vector determine_variable_declaration_order( - SymbolTable* symtab) { - std::map> var_dep_graph; - for( auto itr: symtab->get_scope() ) { - if( ASR::is_a(*itr.second) ) { - std::vector deps; - ASR::Variable_t* var = ASR::down_cast(itr.second); - for( size_t i = 0; i < var->n_dependencies; i++ ) { - std::string dep = var->m_dependencies[i]; - // Check if the dependent variable is present in the symtab. - // This will help us to include only local dependencies, and we - // assume that dependencies in the parent symtab are already declared - // earlier. - if (symtab->get_symbol(dep) != nullptr) - deps.push_back(dep); - } - var_dep_graph[itr.first] = deps; - } - } - return ASRUtils::order_deps(var_dep_graph); -} - -void extract_module_python(const ASR::TranslationUnit_t &m, - std::vector>& children_modules, - std::string module_name) { - bool module_found = false; - for (auto &a : m.m_global_scope->get_scope()) { - if( ASR::is_a(*a.second) ) { - if( a.first == "__main__" ) { - module_found = true; - children_modules.push_back(std::make_pair(module_name, - ASR::down_cast(a.second))); - } else { - children_modules.push_back(std::make_pair(a.first, - ASR::down_cast(a.second))); - } - } - } - if( !module_found ) { - throw LCompilersException("ICE: Module not found"); - } -} - -ASR::Module_t* extract_module(const ASR::TranslationUnit_t &m) { - LCOMPILERS_ASSERT(m.m_global_scope->get_scope().size()== 1); - for (auto &a : m.m_global_scope->get_scope()) { - LCOMPILERS_ASSERT(ASR::is_a(*a.second)); - return ASR::down_cast(a.second); - } - throw LCompilersException("ICE: Module not found"); -} - -ASR::Module_t* load_module(Allocator &al, SymbolTable *symtab, - const std::string &module_name, - const Location &loc, bool intrinsic, - LCompilers::PassOptions& pass_options, - bool run_verify, - const std::function err) { - LCOMPILERS_ASSERT(symtab); - if (symtab->get_symbol(module_name) != nullptr) { - ASR::symbol_t *m = symtab->get_symbol(module_name); - if (ASR::is_a(*m)) { - return ASR::down_cast(m); - } else { - err("The symbol '" + module_name + "' is not a module", loc); - } - } - LCOMPILERS_ASSERT(symtab->parent == nullptr); - ASR::TranslationUnit_t *mod1 = find_and_load_module(al, module_name, - *symtab, intrinsic, pass_options); - if (mod1 == nullptr && !intrinsic) { - // Module not found as a regular module. Try intrinsic module - if (module_name == "iso_c_binding" - ||module_name == "iso_fortran_env" - ||module_name == "ieee_arithmetic") { - mod1 = find_and_load_module(al, "lfortran_intrinsic_" + module_name, - *symtab, true, pass_options); - } - } - if (mod1 == nullptr) { - err("Module '" + module_name + "' not declared in the current source and the modfile was not found", - loc); - } - ASR::Module_t *mod2 = extract_module(*mod1); - symtab->add_symbol(module_name, (ASR::symbol_t*)mod2); - mod2->m_symtab->parent = symtab; - mod2->m_loaded_from_mod = true; - LCOMPILERS_ASSERT(symtab->resolve_symbol(module_name)); - - // Create a temporary TranslationUnit just for fixing the symbols - ASR::asr_t *orig_asr_owner = symtab->asr_owner; - ASR::TranslationUnit_t *tu - = ASR::down_cast2(ASR::make_TranslationUnit_t(al, loc, - symtab, nullptr, 0)); - - // Load any dependent modules recursively - bool rerun = true; - while (rerun) { - rerun = false; - std::vector modules_list - = determine_module_dependencies(*tu); - for (auto &item : modules_list) { - if (symtab->get_symbol(item) - == nullptr) { - // A module that was loaded requires to load another - // module - - // This is not very robust, we should store that information - // in the ASR itself, or encode in the name in a robust way, - // such as using `module_name@intrinsic`: - bool is_intrinsic = startswith(item, "lfortran_intrinsic"); - ASR::TranslationUnit_t *mod1 = find_and_load_module(al, - item, - *symtab, is_intrinsic, pass_options); - if (mod1 == nullptr && !is_intrinsic) { - // Module not found as a regular module. Try intrinsic module - if (item == "iso_c_binding" - ||item == "iso_fortran_env") { - mod1 = find_and_load_module(al, "lfortran_intrinsic_" + item, - *symtab, true, pass_options); - } - } - - if (mod1 == nullptr) { - err("Module '" + item + "' modfile was not found", loc); - } - ASR::Module_t *mod2 = extract_module(*mod1); - symtab->add_symbol(item, (ASR::symbol_t*)mod2); - mod2->m_symtab->parent = symtab; - mod2->m_loaded_from_mod = true; - rerun = true; - } - } - } - - // Check that all modules are included in ASR now - std::vector modules_list - = determine_module_dependencies(*tu); - for (auto &item : modules_list) { - if (symtab->get_symbol(item) == nullptr) { - err("ICE: Module '" + item + "' modfile was not found, but should have", loc); - } - } - - // Fix all external symbols - fix_external_symbols(*tu, *symtab); - PassUtils::UpdateDependenciesVisitor v(al); - v.visit_TranslationUnit(*tu); - if (run_verify) { -#if defined(WITH_LFORTRAN_ASSERT) - diag::Diagnostics diagnostics; - if (!asr_verify(*tu, true, diagnostics)) { - std::cerr << diagnostics.render2(); - throw LCompilersException("Verify failed"); - }; -#endif - } - symtab->asr_owner = orig_asr_owner; - - return mod2; -} - -void set_intrinsic(ASR::symbol_t* sym) { - switch( sym->type ) { - case ASR::symbolType::Module: { - ASR::Module_t* module_sym = ASR::down_cast(sym); - module_sym->m_intrinsic = true; - for( auto& itr: module_sym->m_symtab->get_scope() ) { - set_intrinsic(itr.second); - } - break; - } - case ASR::symbolType::Function: { - ASR::Function_t* function_sym = ASR::down_cast(sym); - ASR::FunctionType_t* func_sym_type = ASR::down_cast(function_sym->m_function_signature); - func_sym_type->m_abi = ASR::abiType::Intrinsic; - break; - } - case ASR::symbolType::StructType: { - ASR::StructType_t* derived_type_sym = ASR::down_cast(sym); - derived_type_sym->m_abi = ASR::abiType::Intrinsic; - break; - } - case ASR::symbolType::Variable: { - ASR::Variable_t* derived_type_sym = ASR::down_cast(sym); - derived_type_sym->m_abi = ASR::abiType::Intrinsic; - break; - } - default: { - break; - } - } -} - -void set_intrinsic(ASR::TranslationUnit_t* trans_unit) { - for( auto& itr: trans_unit->m_global_scope->get_scope() ) { - set_intrinsic(itr.second); - } -} - -ASR::TranslationUnit_t* find_and_load_module(Allocator &al, const std::string &msym, - SymbolTable &symtab, bool intrinsic, - LCompilers::PassOptions& pass_options) { - std::filesystem::path runtime_library_dir { pass_options.runtime_library_dir }; - std::filesystem::path filename {msym + ".mod"}; - std::vector mod_files_dirs; - - mod_files_dirs.push_back( runtime_library_dir ); - mod_files_dirs.push_back( pass_options.mod_files_dir ); - mod_files_dirs.insert(mod_files_dirs.end(), - pass_options.include_dirs.begin(), - pass_options.include_dirs.end()); - - for (auto path : mod_files_dirs) { - std::string modfile; - std::filesystem::path full_path = path / filename; - if (read_file(full_path.string(), modfile)) { - ASR::TranslationUnit_t *asr = load_modfile(al, modfile, false, symtab); - if (intrinsic) { - set_intrinsic(asr); - } - return asr; - } - } - return nullptr; -} - -ASR::asr_t* getStructInstanceMember_t(Allocator& al, const Location& loc, - ASR::asr_t* v_var, ASR::symbol_t *v, - ASR::symbol_t* member, SymbolTable* current_scope) { - member = ASRUtils::symbol_get_past_external(member); - if (ASR::is_a(*member)) { - ASR::StructType_t* member_variable = ASR::down_cast(member); - ASR::symbol_t *mem_es = nullptr; - std::string mem_name = "1_" + std::string(ASRUtils::symbol_name(member)); - if (current_scope->resolve_symbol(mem_name)) { - mem_es = current_scope->resolve_symbol(mem_name); - } else { - mem_es = ASR::down_cast(ASR::make_ExternalSymbol_t(al, - member->base.loc, current_scope, s2c(al, mem_name), member, - ASRUtils::symbol_name(ASRUtils::get_asr_owner(member)), - nullptr, 0, member_variable->m_name, ASR::accessType::Public)); - current_scope->add_symbol(mem_name, mem_es); - } - ASR::ttype_t* member_type = ASRUtils::TYPE(ASR::make_Struct_t(al, - member_variable->base.base.loc, mem_es, nullptr, 0)); - return ASR::make_StructInstanceMember_t(al, loc, ASRUtils::EXPR(v_var), - mem_es, member_type, nullptr); - } else { - LCOMPILERS_ASSERT(ASR::is_a(*member)); - ASR::Variable_t* member_variable = ASR::down_cast(member); - ASR::ttype_t* member_type = member_variable->m_type; - bool is_pointer = false; - if (ASRUtils::is_pointer(member_type)) { - is_pointer = true; - member_type = ASR::down_cast(member_type)->m_type; - } - switch( member_type->type ) { - case ASR::ttypeType::Struct: { - ASR::Struct_t* der = ASR::down_cast(member_type); - std::string der_type_name = ASRUtils::symbol_name(der->m_derived_type); - ASR::symbol_t* der_type_sym = current_scope->resolve_symbol(der_type_name); - if( der_type_sym == nullptr ) { - ASR::symbol_t* der_ext; - char* module_name = (char*)"~nullptr"; - ASR::symbol_t* m_external = der->m_derived_type; - if( ASR::is_a(*m_external) ) { - ASR::ExternalSymbol_t* m_ext = ASR::down_cast(m_external); - m_external = m_ext->m_external; - module_name = m_ext->m_module_name; - } else if( ASR::is_a(*m_external) ) { - ASR::symbol_t* asr_owner = ASRUtils::get_asr_owner(m_external); - if( ASR::is_a(*asr_owner) || - ASR::is_a(*asr_owner) ) { - module_name = ASRUtils::symbol_name(asr_owner); - } - } - std::string mangled_name = current_scope->get_unique_name( - std::string(module_name) + "_" + - std::string(der_type_name)); - char* mangled_name_char = s2c(al, mangled_name); - if( current_scope->get_symbol(mangled_name) == nullptr ) { - bool make_new_ext_sym = true; - ASR::symbol_t* der_tmp = nullptr; - if( current_scope->get_symbol(std::string(der_type_name)) != nullptr ) { - der_tmp = current_scope->get_symbol(std::string(der_type_name)); - if( ASR::is_a(*der_tmp) ) { - ASR::ExternalSymbol_t* der_ext_tmp = ASR::down_cast(der_tmp); - if( der_ext_tmp->m_external == m_external ) { - make_new_ext_sym = false; - } - } else { - make_new_ext_sym = false; - } - } - if( make_new_ext_sym ) { - der_ext = ASR::down_cast(ASR::make_ExternalSymbol_t( - al, loc, current_scope, mangled_name_char, m_external, - module_name, nullptr, 0, s2c(al, der_type_name), - ASR::accessType::Public)); - current_scope->add_symbol(mangled_name, der_ext); - } else { - LCOMPILERS_ASSERT(der_tmp != nullptr); - der_ext = der_tmp; - } - } else { - der_ext = current_scope->get_symbol(mangled_name); - } - ASR::asr_t* der_new = ASR::make_Struct_t(al, loc, der_ext, der->m_dims, der->n_dims); - member_type = ASRUtils::TYPE(der_new); - } else if(ASR::is_a(*der_type_sym)) { - member_type = ASRUtils::TYPE(ASR::make_Struct_t(al, loc, der_type_sym, - der->m_dims, der->n_dims)); - } - break; - } - default : - break; - } - if (is_pointer) { - member_type = ASRUtils::TYPE(ASR::make_Pointer_t(al, loc, member_type)); - } - ASR::ttype_t* member_type_ = nullptr; - ASR::symbol_t* member_ext = ASRUtils::import_struct_instance_member(al, member, current_scope, member_type_); - ASR::expr_t* value = nullptr; - v = ASRUtils::symbol_get_past_external(v); - if (v != nullptr && ASR::down_cast(v)->m_storage - == ASR::storage_typeType::Parameter) { - if (member_variable->m_symbolic_value != nullptr) { - value = expr_value(member_variable->m_symbolic_value); - } - } - return ASR::make_StructInstanceMember_t(al, loc, ASRUtils::EXPR(v_var), - member_ext, member_type, value); - } -} - -bool use_overloaded(ASR::expr_t* left, ASR::expr_t* right, - ASR::binopType op, std::string& intrinsic_op_name, - SymbolTable* curr_scope, ASR::asr_t*& asr, - Allocator &al, const Location& loc, - std::set& current_function_dependencies, - Vec& current_module_dependencies, - const std::function err) { - ASR::ttype_t *left_type = ASRUtils::expr_type(left); - ASR::ttype_t *right_type = ASRUtils::expr_type(right); - bool found = false; - if( is_op_overloaded(op, intrinsic_op_name, curr_scope) ) { - ASR::symbol_t* sym = curr_scope->resolve_symbol(intrinsic_op_name); - ASR::symbol_t* orig_sym = ASRUtils::symbol_get_past_external(sym); - ASR::CustomOperator_t* gen_proc = ASR::down_cast(orig_sym); - for( size_t i = 0; i < gen_proc->n_procs && !found; i++ ) { - ASR::symbol_t* proc = gen_proc->m_procs[i]; - switch(proc->type) { - case ASR::symbolType::Function: { - ASR::Function_t* func = ASR::down_cast(proc); - std::string matched_func_name = ""; - if( func->n_args == 2 ) { - ASR::ttype_t* left_arg_type = ASRUtils::expr_type(func->m_args[0]); - ASR::ttype_t* right_arg_type = ASRUtils::expr_type(func->m_args[1]); - if( left_arg_type->type == left_type->type && - right_arg_type->type == right_type->type ) { - found = true; - Vec a_args; - a_args.reserve(al, 2); - ASR::call_arg_t left_call_arg, right_call_arg; - left_call_arg.loc = left->base.loc, left_call_arg.m_value = left; - a_args.push_back(al, left_call_arg); - right_call_arg.loc = right->base.loc, right_call_arg.m_value = right; - a_args.push_back(al, right_call_arg); - std::string func_name = to_lower(func->m_name); - if( curr_scope->resolve_symbol(func_name) ) { - matched_func_name = func_name; - } else { - std::string mangled_name = func_name + "@" + intrinsic_op_name; - matched_func_name = mangled_name; - } - ASR::symbol_t* a_name = curr_scope->resolve_symbol(matched_func_name); - if( a_name == nullptr ) { - err("Unable to resolve matched function for operator overloading, " + matched_func_name, loc); - } - ASR::ttype_t *return_type = nullptr; - if( ASRUtils::get_FunctionType(func)->m_elemental && - func->n_args == 1 && - ASRUtils::is_array(ASRUtils::expr_type(a_args[0].m_value)) ) { - return_type = ASRUtils::duplicate_type(al, ASRUtils::expr_type(a_args[0].m_value)); - } else { - return_type = ASRUtils::expr_type(func->m_return_var); - } - current_function_dependencies.insert(matched_func_name); - ASRUtils::insert_module_dependency(a_name, al, current_module_dependencies); - asr = ASR::make_FunctionCall_t(al, loc, a_name, sym, - a_args.p, 2, - return_type, - nullptr, nullptr); - } - } - break; - } - default: { - err("While overloading binary operators only functions can be used", - proc->base.loc); - } - } - } - } - return found; -} - -bool is_op_overloaded(ASR::binopType op, std::string& intrinsic_op_name, - SymbolTable* curr_scope) { - bool result = true; - switch(op) { - case ASR::binopType::Add: { - if(intrinsic_op_name != "~add") { - result = false; - } - break; - } - case ASR::binopType::Sub: { - if(intrinsic_op_name != "~sub") { - result = false; - } - break; - } - case ASR::binopType::Mul: { - if(intrinsic_op_name != "~mul") { - result = false; - } - break; - } - case ASR::binopType::Div: { - if(intrinsic_op_name != "~div") { - result = false; - } - break; - } - case ASR::binopType::Pow: { - if(intrinsic_op_name != "~pow") { - result = false; - } - break; - } - default: { - throw LCompilersException("Binary operator '" + ASRUtils::binop_to_str_python(op) + "' not supported yet"); - } - } - if( result && curr_scope->get_symbol(intrinsic_op_name) == nullptr ) { - result = false; - } - return result; -} - -void process_overloaded_assignment_function(ASR::symbol_t* proc, ASR::expr_t* target, ASR::expr_t* value, - ASR::ttype_t* target_type, ASR::ttype_t* value_type, bool& found, Allocator& al, const Location& target_loc, - const Location& value_loc, SymbolTable* curr_scope, std::set& current_function_dependencies, - Vec& current_module_dependencies, ASR::asr_t*& asr, ASR::symbol_t* sym, const Location& loc, ASR::expr_t* expr_dt, - const std::function err, char* pass_arg=nullptr) { - ASR::Function_t* subrout = ASR::down_cast(proc); - std::string matched_subrout_name = ""; - if( subrout->n_args == 2 ) { - ASR::ttype_t* target_arg_type = ASRUtils::expr_type(subrout->m_args[0]); - ASR::ttype_t* value_arg_type = ASRUtils::expr_type(subrout->m_args[1]); - if( ASRUtils::types_equal(target_arg_type, target_type) && - ASRUtils::types_equal(value_arg_type, value_type) ) { - std::string arg0_name = ASRUtils::symbol_name(ASR::down_cast(subrout->m_args[0])->m_v); - std::string arg1_name = ASRUtils::symbol_name(ASR::down_cast(subrout->m_args[1])->m_v); - if( pass_arg != nullptr ) { - std::string pass_arg_str = std::string(pass_arg); - if( arg0_name != pass_arg_str && arg1_name != pass_arg_str ) { - err(pass_arg_str + " argument is not present in " + std::string(subrout->m_name), - proc->base.loc); - } - if( (arg0_name == pass_arg_str && target != expr_dt) ) { - err(std::string(subrout->m_name) + " is not a procedure of " + - ASRUtils::type_to_str(target_type), - loc); - } - if( (arg1_name == pass_arg_str && value != expr_dt) ) { - err(std::string(subrout->m_name) + " is not a procedure of " + - ASRUtils::type_to_str(value_type), - loc); - } - } - found = true; - Vec a_args; - a_args.reserve(al, 2); - ASR::call_arg_t target_arg, value_arg; - target_arg.loc = target_loc, target_arg.m_value = target; - a_args.push_back(al, target_arg); - value_arg.loc = value_loc, value_arg.m_value = value; - a_args.push_back(al, value_arg); - std::string subrout_name = to_lower(subrout->m_name); - if( curr_scope->resolve_symbol(subrout_name) ) { - matched_subrout_name = subrout_name; - } else { - std::string mangled_name = subrout_name + "@~assign"; - matched_subrout_name = mangled_name; - } - ASR::symbol_t *a_name = curr_scope->resolve_symbol(matched_subrout_name); - if( a_name == nullptr ) { - err("Unable to resolve matched subroutine for assignment overloading, " + matched_subrout_name, loc); - } - current_function_dependencies.insert(matched_subrout_name); - ASRUtils::insert_module_dependency(a_name, al, current_module_dependencies); - asr = ASR::make_SubroutineCall_t(al, loc, a_name, sym, - a_args.p, 2, nullptr); - } - } -} - -bool use_overloaded_assignment(ASR::expr_t* target, ASR::expr_t* value, - SymbolTable* curr_scope, ASR::asr_t*& asr, - Allocator &al, const Location& loc, - std::set& current_function_dependencies, - Vec& current_module_dependencies, - const std::function err) { - ASR::ttype_t *target_type = ASRUtils::expr_type(target); - ASR::ttype_t *value_type = ASRUtils::expr_type(value); - bool found = false; - ASR::symbol_t* sym = curr_scope->resolve_symbol("~assign"); - ASR::expr_t* expr_dt = nullptr; - if( !sym ) { - if( ASR::is_a(*target_type) ) { - ASR::StructType_t* target_struct = ASR::down_cast( - ASRUtils::symbol_get_past_external(ASR::down_cast(target_type)->m_derived_type)); - sym = target_struct->m_symtab->resolve_symbol("~assign"); - expr_dt = target; - } else if( ASR::is_a(*value_type) ) { - ASR::StructType_t* value_struct = ASR::down_cast( - ASRUtils::symbol_get_past_external(ASR::down_cast(value_type)->m_derived_type)); - sym = value_struct->m_symtab->resolve_symbol("~assign"); - expr_dt = value; - } - } - if (sym) { - ASR::symbol_t* orig_sym = ASRUtils::symbol_get_past_external(sym); - ASR::CustomOperator_t* gen_proc = ASR::down_cast(orig_sym); - for( size_t i = 0; i < gen_proc->n_procs && !found; i++ ) { - ASR::symbol_t* proc = gen_proc->m_procs[i]; - switch( proc->type ) { - case ASR::symbolType::Function: { - process_overloaded_assignment_function(proc, target, value, target_type, - value_type, found, al, target->base.loc, value->base.loc, curr_scope, - current_function_dependencies, current_module_dependencies, asr, sym, - loc, expr_dt, err); - break; - } - case ASR::symbolType::ClassProcedure: { - ASR::ClassProcedure_t* class_proc = ASR::down_cast(proc); - ASR::symbol_t* proc_func = ASR::down_cast(proc)->m_proc; - process_overloaded_assignment_function(proc_func, target, value, target_type, - value_type, found, al, target->base.loc, value->base.loc, curr_scope, - current_function_dependencies, current_module_dependencies, asr, proc_func, loc, - expr_dt, err, class_proc->m_self_argument); - break; - } - default: { - err("Only functions and class procedures can be used for generic assignment statement", loc); - } - } - } - } - return found; -} - -bool use_overloaded(ASR::expr_t* left, ASR::expr_t* right, - ASR::cmpopType op, std::string& intrinsic_op_name, - SymbolTable* curr_scope, ASR::asr_t*& asr, - Allocator &al, const Location& loc, - std::set& current_function_dependencies, - Vec& current_module_dependencies, - const std::function err) { - ASR::ttype_t *left_type = ASRUtils::expr_type(left); - ASR::ttype_t *right_type = ASRUtils::expr_type(right); - ASR::StructType_t *left_struct = nullptr; - if ( ASR::is_a(*left_type) ) { - left_struct = ASR::down_cast( - ASRUtils::symbol_get_past_external(ASR::down_cast( - left_type)->m_derived_type)); - } else if ( ASR::is_a(*left_type) ) { - left_struct = ASR::down_cast( - ASRUtils::symbol_get_past_external(ASR::down_cast( - left_type)->m_class_type)); - } - bool found = false; - if( is_op_overloaded(op, intrinsic_op_name, curr_scope, left_struct) ) { - ASR::symbol_t* sym = curr_scope->resolve_symbol(intrinsic_op_name); - ASR::symbol_t* orig_sym = ASRUtils::symbol_get_past_external(sym); - if ( left_struct != nullptr && orig_sym == nullptr ) { - orig_sym = left_struct->m_symtab->resolve_symbol(intrinsic_op_name); - } - ASR::CustomOperator_t* gen_proc = ASR::down_cast(orig_sym); - for( size_t i = 0; i < gen_proc->n_procs && !found; i++ ) { - ASR::symbol_t* proc; - if ( ASR::is_a(*gen_proc->m_procs[i]) ) { - proc = ASRUtils::symbol_get_past_external( - ASR::down_cast( - gen_proc->m_procs[i])->m_proc); - } else { - proc = gen_proc->m_procs[i]; - } - switch(proc->type) { - case ASR::symbolType::Function: { - ASR::Function_t* func = ASR::down_cast(proc); - std::string matched_func_name = ""; - if( func->n_args == 2 ) { - ASR::ttype_t* left_arg_type = ASRUtils::expr_type(func->m_args[0]); - ASR::ttype_t* right_arg_type = ASRUtils::expr_type(func->m_args[1]); - if( (left_arg_type->type == left_type->type && - right_arg_type->type == right_type->type) - || (ASR::is_a(*left_arg_type) && - ASR::is_a(*left_type)) - || (ASR::is_a(*right_arg_type) && - ASR::is_a(*right_type))) { - found = true; - Vec a_args; - a_args.reserve(al, 2); - ASR::call_arg_t left_call_arg, right_call_arg; - left_call_arg.loc = left->base.loc, left_call_arg.m_value = left; - a_args.push_back(al, left_call_arg); - right_call_arg.loc = right->base.loc, right_call_arg.m_value = right; - a_args.push_back(al, right_call_arg); - std::string func_name = to_lower(func->m_name); - if( curr_scope->resolve_symbol(func_name) ) { - matched_func_name = func_name; - } else { - std::string mangled_name = func_name + "@" + intrinsic_op_name; - matched_func_name = mangled_name; - } - ASR::symbol_t* a_name = curr_scope->resolve_symbol(matched_func_name); - if( a_name == nullptr ) { - err("Unable to resolve matched function for operator overloading, " + matched_func_name, loc); - } - ASR::ttype_t *return_type = nullptr; - if( ASRUtils::get_FunctionType(func)->m_elemental && - func->n_args == 1 && - ASRUtils::is_array(ASRUtils::expr_type(a_args[0].m_value)) ) { - return_type = ASRUtils::duplicate_type(al, ASRUtils::expr_type(a_args[0].m_value)); - } else { - return_type = ASRUtils::expr_type(func->m_return_var); - } - current_function_dependencies.insert(matched_func_name); - ASRUtils::insert_module_dependency(a_name, al, current_module_dependencies); - asr = ASR::make_FunctionCall_t(al, loc, a_name, sym, - a_args.p, 2, - return_type, - nullptr, nullptr); - } - } - break; - } - default: { - err("While overloading binary operators only functions can be used", - proc->base.loc); - } - } - } - } - return found; -} - -bool is_op_overloaded(ASR::cmpopType op, std::string& intrinsic_op_name, - SymbolTable* curr_scope, ASR::StructType_t *left_struct) { - bool result = true; - switch(op) { - case ASR::cmpopType::Eq: { - if(intrinsic_op_name != "~eq") { - result = false; - } - break; - } - case ASR::cmpopType::NotEq: { - if(intrinsic_op_name != "~noteq") { - result = false; - } - break; - } - case ASR::cmpopType::Lt: { - if(intrinsic_op_name != "~lt") { - result = false; - } - break; - } - case ASR::cmpopType::LtE: { - if(intrinsic_op_name != "~lte") { - result = false; - } - break; - } - case ASR::cmpopType::Gt: { - if(intrinsic_op_name != "~gt") { - result = false; - } - break; - } - case ASR::cmpopType::GtE: { - if(intrinsic_op_name != "~gte") { - result = false; - } - break; - } - } - if( result && curr_scope->resolve_symbol(intrinsic_op_name) == nullptr ) { - if ( left_struct != nullptr && left_struct->m_symtab->resolve_symbol( - intrinsic_op_name) != nullptr) { - result = true; - } else { - result = false; - } - } - - return result; -} - -template -bool argument_types_match(const Vec& args, - const T &sub) { - if (args.size() <= sub.n_args) { - size_t i; - for (i = 0; i < args.size(); i++) { - ASR::Variable_t *v = ASRUtils::EXPR2VAR(sub.m_args[i]); - if (args[i].m_value == nullptr && - v->m_presence == ASR::presenceType::Optional) { - // If it's optional and argument is empty - // continue to next argument. - continue; - } - // Otherwise this should not be nullptr - ASR::ttype_t *arg1 = ASRUtils::expr_type(args[i].m_value); - ASR::ttype_t *arg2 = v->m_type; - if (!types_equal(arg1, arg2)) { - return false; - } - } - for( ; i < sub.n_args; i++ ) { - ASR::Variable_t *v = ASRUtils::EXPR2VAR(sub.m_args[i]); - if( v->m_presence != ASR::presenceType::Optional ) { - return false; - } - } - return true; - } else { - return false; - } -} - -bool select_func_subrout(const ASR::symbol_t* proc, const Vec& args, - Location& loc, const std::function err) { - bool result = false; - proc = ASRUtils::symbol_get_past_external(proc); - if (ASR::is_a(*proc)) { - ASR::Function_t *fn - = ASR::down_cast(proc); - if (argument_types_match(args, *fn)) { - result = true; - } - } else { - err("Only Subroutine and Function supported in generic procedure", loc); - } - return result; -} - -int select_generic_procedure(const Vec& args, - const ASR::GenericProcedure_t &p, Location loc, - const std::function err, - bool raise_error) { - for (size_t i=0; i < p.n_procs; i++) { - if( ASR::is_a(*p.m_procs[i]) ) { - ASR::ClassProcedure_t *clss_fn - = ASR::down_cast(p.m_procs[i]); - const ASR::symbol_t *proc = ASRUtils::symbol_get_past_external(clss_fn->m_proc); - if( select_func_subrout(proc, args, loc, err) ) { - return i; - } - } else { - if( select_func_subrout(p.m_procs[i], args, loc, err) ) { - return i; - } - } - } - if( raise_error ) { - err("Arguments do not match for any generic procedure, " + std::string(p.m_name), loc); - } - return -1; -} - -ASR::asr_t* symbol_resolve_external_generic_procedure_without_eval( - const Location &loc, - ASR::symbol_t *v, Vec& args, - SymbolTable* current_scope, Allocator& al, - const std::function err) { - ASR::ExternalSymbol_t *p = ASR::down_cast(v); - ASR::symbol_t *f2 = ASR::down_cast(v)->m_external; - ASR::GenericProcedure_t *g = ASR::down_cast(f2); - int idx = select_generic_procedure(args, *g, loc, err); - ASR::symbol_t *final_sym; - final_sym = g->m_procs[idx]; - LCOMPILERS_ASSERT(ASR::is_a(*final_sym)); - bool is_subroutine = ASR::down_cast(final_sym)->m_return_var == nullptr; - ASR::ttype_t *return_type = nullptr; - if( ASR::is_a(*final_sym) ) { - ASR::Function_t* func = ASR::down_cast(final_sym); - if (func->m_return_var) { - if( ASRUtils::get_FunctionType(func)->m_elemental && - func->n_args == 1 && - ASRUtils::is_array(ASRUtils::expr_type(args[0].m_value)) ) { - return_type = ASRUtils::duplicate_type(al, ASRUtils::expr_type(args[0].m_value)); - } else { - return_type = ASRUtils::EXPR2VAR(func->m_return_var)->m_type; - } - } - } - // Create ExternalSymbol for the final subroutine: - // We mangle the new ExternalSymbol's local name as: - // generic_procedure_local_name @ - // specific_procedure_remote_name - std::string local_sym = std::string(p->m_name) + "@" - + ASRUtils::symbol_name(final_sym); - if (current_scope->get_symbol(local_sym) - == nullptr) { - Str name; - name.from_str(al, local_sym); - char *cname = name.c_str(al); - ASR::asr_t *sub = ASR::make_ExternalSymbol_t( - al, g->base.base.loc, - /* a_symtab */ current_scope, - /* a_name */ cname, - final_sym, - p->m_module_name, nullptr, 0, ASRUtils::symbol_name(final_sym), - ASR::accessType::Private - ); - final_sym = ASR::down_cast(sub); - current_scope->add_symbol(local_sym, final_sym); - } else { - final_sym = current_scope->get_symbol(local_sym); - } - // ASRUtils::insert_module_dependency(v, al, current_module_dependencies); - if( is_subroutine ) { - return ASR::make_SubroutineCall_t(al, loc, final_sym, - v, args.p, args.size(), - nullptr); - } else { - return ASR::make_FunctionCall_t(al, loc, final_sym, - v, args.p, args.size(), - return_type, - nullptr, nullptr); - } -} - -ASR::asr_t* make_Cast_t_value(Allocator &al, const Location &a_loc, - ASR::expr_t* a_arg, ASR::cast_kindType a_kind, ASR::ttype_t* a_type) { - - ASR::expr_t* value = nullptr; - - if (ASRUtils::expr_value(a_arg)) { - // calculate value - if (a_kind == ASR::cast_kindType::RealToInteger) { - int64_t v = ASR::down_cast( - ASRUtils::expr_value(a_arg))->m_r; - value = ASR::down_cast( - ASR::make_IntegerConstant_t(al, a_loc, v, a_type)); - } else if (a_kind == ASR::cast_kindType::RealToReal) { - double v = ASR::down_cast( - ASRUtils::expr_value(a_arg))->m_r; - value = ASR::down_cast( - ASR::make_RealConstant_t(al, a_loc, v, a_type)); - } else if (a_kind == ASR::cast_kindType::RealToComplex) { - double double_value = ASR::down_cast( - ASRUtils::expr_value(a_arg))->m_r; - value = ASR::down_cast(ASR::make_ComplexConstant_t(al, a_loc, - double_value, 0, a_type)); - } else if (a_kind == ASR::cast_kindType::IntegerToReal) { - // TODO: Clashes with the pow functions - // int64_t value = ASR::down_cast(ASRUtils::expr_value(a_arg))->m_n; - // value = ASR::down_cast(ASR::make_ConstantReal_t(al, a_loc, (double)v, a_type)); - } else if (a_kind == ASR::cast_kindType::IntegerToComplex) { - int64_t int_value = ASR::down_cast( - ASRUtils::expr_value(a_arg))->m_n; - value = ASR::down_cast(ASR::make_ComplexConstant_t(al, a_loc, - (double)int_value, 0, a_type)); - } else if (a_kind == ASR::cast_kindType::IntegerToInteger) { - int64_t int_value = ASR::down_cast( - ASRUtils::expr_value(a_arg))->m_n; - value = ASR::down_cast(ASR::make_IntegerConstant_t(al, a_loc, int_value, a_type)); - } else if (a_kind == ASR::cast_kindType::IntegerToLogical) { - // TODO: implement - } else if (a_kind == ASR::cast_kindType::ComplexToComplex) { - ASR::ComplexConstant_t* value_complex = ASR::down_cast( - ASRUtils::expr_value(a_arg)); - double real = value_complex->m_re; - double imag = value_complex->m_im; - value = ASR::down_cast( - ASR::make_ComplexConstant_t(al, a_loc, real, imag, a_type)); - } else if (a_kind == ASR::cast_kindType::ComplexToReal) { - ASR::ComplexConstant_t* value_complex = ASR::down_cast( - ASRUtils::expr_value(a_arg)); - double real = value_complex->m_re; - value = ASR::down_cast( - ASR::make_RealConstant_t(al, a_loc, real, a_type)); - } - } - - return ASR::make_Cast_t(al, a_loc, a_arg, a_kind, a_type, value); -} - -ASR::symbol_t* import_class_procedure(Allocator &al, const Location& loc, - ASR::symbol_t* original_sym, SymbolTable *current_scope) { - if( original_sym && ASR::is_a(*original_sym) ) { - std::string class_proc_name = ASRUtils::symbol_name(original_sym); - if( original_sym != current_scope->resolve_symbol(class_proc_name) ) { - std::string imported_proc_name = "1_" + class_proc_name; - if( current_scope->resolve_symbol(imported_proc_name) == nullptr ) { - ASR::symbol_t* module_sym = ASRUtils::get_asr_owner(original_sym); - std::string module_name = ASRUtils::symbol_name(module_sym); - if( current_scope->resolve_symbol(module_name) == nullptr ) { - std::string imported_module_name = "1_" + module_name; - if( current_scope->resolve_symbol(imported_module_name) == nullptr ) { - LCOMPILERS_ASSERT(ASR::is_a( - *ASRUtils::get_asr_owner(module_sym))); - ASR::symbol_t* imported_module = ASR::down_cast( - ASR::make_ExternalSymbol_t( - al, loc, current_scope, s2c(al, imported_module_name), - module_sym, ASRUtils::symbol_name(ASRUtils::get_asr_owner(module_sym)), - nullptr, 0, s2c(al, module_name), ASR::accessType::Public - ) - ); - current_scope->add_symbol(imported_module_name, imported_module); - } - module_name = imported_module_name; - } - ASR::symbol_t* imported_sym = ASR::down_cast( - ASR::make_ExternalSymbol_t( - al, loc, current_scope, s2c(al, imported_proc_name), - original_sym, s2c(al, module_name), nullptr, 0, - ASRUtils::symbol_name(original_sym), ASR::accessType::Public - ) - ); - current_scope->add_symbol(imported_proc_name, imported_sym); - original_sym = imported_sym; - } else { - original_sym = current_scope->resolve_symbol(imported_proc_name); - } - } - } - return original_sym; -} - -//Initialize pointer to zero so that it can be initialized in first call to get_instance -ASRUtils::LabelGenerator* ASRUtils::LabelGenerator::label_generator = nullptr; - -} // namespace ASRUtils - - -} // namespace LCompilers diff --git a/src/libasr/asr_utils.h b/src/libasr/asr_utils.h deleted file mode 100644 index 9b381c60a8..0000000000 --- a/src/libasr/asr_utils.h +++ /dev/null @@ -1,2952 +0,0 @@ -#ifndef LFORTRAN_ASR_UTILS_H -#define LFORTRAN_ASR_UTILS_H - -#include -#include -#include -#include - -#include -#include -#include -#include - -namespace LCompilers { - - namespace ASRUtils { - -ASR::symbol_t* import_class_procedure(Allocator &al, const Location& loc, - ASR::symbol_t* original_sym, SymbolTable *current_scope); - -static inline double extract_real(const char *s) { - // TODO: this is inefficient. We should - // convert this in the tokenizer where we know most information - std::string x = s; - x = replace(x, "d", "e"); - x = replace(x, "D", "E"); - return std::atof(x.c_str()); -} - -static inline ASR::expr_t* EXPR(const ASR::asr_t *f) -{ - return ASR::down_cast(f); -} - -static inline ASR::stmt_t* STMT(const ASR::asr_t *f) -{ - return ASR::down_cast(f); -} - -static inline ASR::case_stmt_t* CASE_STMT(const ASR::asr_t *f) -{ - return ASR::down_cast(f); -} - -static inline ASR::ttype_t* TYPE(const ASR::asr_t *f) -{ - return ASR::down_cast(f); -} - -static inline ASR::FunctionType_t* get_FunctionType(const ASR::Function_t* x) { - return ASR::down_cast(x->m_function_signature); -} - -static inline ASR::FunctionType_t* get_FunctionType(const ASR::Function_t& x) { - return ASR::down_cast(x.m_function_signature); -} - -static inline ASR::symbol_t *symbol_get_past_external(ASR::symbol_t *f) -{ - if (f && f->type == ASR::symbolType::ExternalSymbol) { - ASR::ExternalSymbol_t *e = ASR::down_cast(f); - if( e->m_external == nullptr ) { - return nullptr; - } - LCOMPILERS_ASSERT(!ASR::is_a(*e->m_external)); - return e->m_external; - } else { - return f; - } -} - -static inline const ASR::symbol_t *symbol_get_past_external(const ASR::symbol_t *f) -{ - if (f->type == ASR::symbolType::ExternalSymbol) { - ASR::ExternalSymbol_t *e = ASR::down_cast(f); - LCOMPILERS_ASSERT(!ASR::is_a(*e->m_external)); - return e->m_external; - } else { - return f; - } -} - -static inline ASR::ttype_t *type_get_past_pointer(ASR::ttype_t *f) -{ - if (ASR::is_a(*f)) { - ASR::Pointer_t *e = ASR::down_cast(f); - LCOMPILERS_ASSERT(!ASR::is_a(*e->m_type)); - return e->m_type; - } else { - return f; - } -} - -static inline ASR::Variable_t* EXPR2VAR(const ASR::expr_t *f) -{ - return ASR::down_cast(symbol_get_past_external( - ASR::down_cast(f)->m_v)); -} - -static inline ASR::Function_t* EXPR2FUN(const ASR::expr_t *f) -{ - return ASR::down_cast(symbol_get_past_external( - ASR::down_cast(f)->m_v)); -} - -static inline ASR::ttype_t* expr_type(const ASR::expr_t *f) -{ - return ASR::expr_type0(f); -} - -static inline ASR::ttype_t* symbol_type(const ASR::symbol_t *f) -{ - switch( f->type ) { - case ASR::symbolType::Variable: { - return ASR::down_cast(f)->m_type; - } - case ASR::symbolType::EnumType: { - return ASR::down_cast(f)->m_type; - } - case ASR::symbolType::ExternalSymbol: { - return symbol_type(ASRUtils::symbol_get_past_external(f)); - } - case ASR::symbolType::Function: { - return ASRUtils::expr_type( - ASR::down_cast(f)->m_return_var); - } - default: { - throw LCompilersException("Cannot return type of, " + - std::to_string(f->type) + " symbol."); - } - } - return nullptr; -} - -static inline ASR::abiType symbol_abi(const ASR::symbol_t *f) -{ - switch( f->type ) { - case ASR::symbolType::Variable: { - return ASR::down_cast(f)->m_abi; - } - case ASR::symbolType::EnumType: { - return ASR::down_cast(f)->m_abi; - } - case ASR::symbolType::ExternalSymbol: { - return symbol_abi(ASR::down_cast(f)->m_external); - } - default: { - throw LCompilersException("Cannot return ABI of, " + - std::to_string(f->type) + " symbol."); - } - } - return ASR::abiType::Source; -} - -static inline ASR::ttype_t* get_contained_type(ASR::ttype_t* asr_type) { - switch( asr_type->type ) { - case ASR::ttypeType::List: { - return ASR::down_cast(asr_type)->m_type; - } - case ASR::ttypeType::Set: { - return ASR::down_cast(asr_type)->m_type; - } - case ASR::ttypeType::Enum: { - ASR::Enum_t* enum_asr = ASR::down_cast(asr_type); - ASR::EnumType_t* enum_type = ASR::down_cast(enum_asr->m_enum_type); - return enum_type->m_type; - } - case ASR::ttypeType::Pointer: { - ASR::Pointer_t* pointer_asr = ASR::down_cast(asr_type); - return pointer_asr->m_type; - } - case ASR::ttypeType::Const: { - ASR::Const_t* const_asr = ASR::down_cast(asr_type); - return const_asr->m_type; - } - default: { - return asr_type; - } - } -} - -static inline ASR::abiType expr_abi(ASR::expr_t* e) { - switch( e->type ) { - case ASR::exprType::Var: { - return ASRUtils::symbol_abi(ASR::down_cast(e)->m_v); - } - case ASR::exprType::StructInstanceMember: { - return ASRUtils::symbol_abi(ASR::down_cast(e)->m_m); - } - case ASR::exprType::ArrayReshape: { - return ASRUtils::expr_abi(ASR::down_cast(e)->m_array); - } - case ASR::exprType::GetPointer: { - return ASRUtils::expr_abi(ASR::down_cast(e)->m_arg); - } - default: - throw LCompilersException("Cannot extract the ABI of " + - std::to_string(e->type) + " expression."); - } -} - -static inline char *symbol_name(const ASR::symbol_t *f) -{ - switch (f->type) { - case ASR::symbolType::Program: { - return ASR::down_cast(f)->m_name; - } - case ASR::symbolType::Module: { - return ASR::down_cast(f)->m_name; - } - case ASR::symbolType::Function: { - return ASR::down_cast(f)->m_name; - } - case ASR::symbolType::GenericProcedure: { - return ASR::down_cast(f)->m_name; - } - case ASR::symbolType::StructType: { - return ASR::down_cast(f)->m_name; - } - case ASR::symbolType::EnumType: { - return ASR::down_cast(f)->m_name; - } - case ASR::symbolType::UnionType: { - return ASR::down_cast(f)->m_name; - } - case ASR::symbolType::Variable: { - return ASR::down_cast(f)->m_name; - } - case ASR::symbolType::ExternalSymbol: { - return ASR::down_cast(f)->m_name; - } - case ASR::symbolType::ClassProcedure: { - return ASR::down_cast(f)->m_name; - } - case ASR::symbolType::CustomOperator: { - return ASR::down_cast(f)->m_name; - } - case ASR::symbolType::AssociateBlock: { - return ASR::down_cast(f)->m_name; - } - case ASR::symbolType::Block: { - return ASR::down_cast(f)->m_name; - } - default : throw LCompilersException("Not implemented"); - } -} - -static inline std::string type_to_str(const ASR::ttype_t *t) -{ - switch (t->type) { - case ASR::ttypeType::Integer: { - return "integer"; - } - case ASR::ttypeType::Real: { - return "real"; - } - case ASR::ttypeType::Complex: { - return "complex"; - } - case ASR::ttypeType::Logical: { - return "logical"; - } - case ASR::ttypeType::Character: { - return "character"; - } - case ASR::ttypeType::Tuple: { - return "tuple"; - } - case ASR::ttypeType::Set: { - return "set"; - } - case ASR::ttypeType::Dict: { - return "dict"; - } - case ASR::ttypeType::List: { - return "list"; - } - case ASR::ttypeType::Struct: { - return ASRUtils::symbol_name(ASR::down_cast(t)->m_derived_type); - } - case ASR::ttypeType::Union: { - return "union"; - } - case ASR::ttypeType::CPtr: { - return "type(c_ptr)"; - } - case ASR::ttypeType::Pointer: { - return type_to_str(ASRUtils::type_get_past_pointer( - const_cast(t))) + " pointer"; - } - case ASR::ttypeType::Const: { - return type_to_str(ASRUtils::get_contained_type( - const_cast(t))) + " const"; - } - case ASR::ttypeType::TypeParameter: { - ASR::TypeParameter_t* tp = ASR::down_cast(t); - return tp->m_param; - } - default : throw LCompilersException("Not implemented " + std::to_string(t->type) + "."); - } -} - -static inline std::string binop_to_str(const ASR::binopType t) { - switch (t) { - case (ASR::binopType::Add): { return " + "; } - case (ASR::binopType::Sub): { return " - "; } - case (ASR::binopType::Mul): { return "*"; } - case (ASR::binopType::Div): { return "/"; } - default : throw LCompilersException("Cannot represent the binary operator as a string"); - } -} - -static inline std::string cmpop_to_str(const ASR::cmpopType t) { - switch (t) { - case (ASR::cmpopType::Eq): { return " == "; } - case (ASR::cmpopType::NotEq): { return " != "; } - case (ASR::cmpopType::Lt): { return " < "; } - case (ASR::cmpopType::LtE): { return " <= "; } - case (ASR::cmpopType::Gt): { return " > "; } - case (ASR::cmpopType::GtE): { return " >= "; } - default : throw LCompilersException("Cannot represent the comparison as a string"); - } -} - -static inline std::string logicalbinop_to_str_python(const ASR::logicalbinopType t) { - switch (t) { - case (ASR::logicalbinopType::And): { return " && "; } - case (ASR::logicalbinopType::Or): { return " || "; } - case (ASR::logicalbinopType::Eqv): { return " == "; } - case (ASR::logicalbinopType::NEqv): { return " != "; } - default : throw LCompilersException("Cannot represent the boolean operator as a string"); - } -} - -static inline ASR::expr_t* expr_value(ASR::expr_t *f) -{ - return ASR::expr_value0(f); -} - -static inline std::pair symbol_dependencies(const ASR::symbol_t *f) -{ - switch (f->type) { - case ASR::symbolType::Program: { - ASR::Program_t* sym = ASR::down_cast(f); - return std::make_pair(sym->m_dependencies, sym->n_dependencies); - } - case ASR::symbolType::Module: { - ASR::Module_t* sym = ASR::down_cast(f); - return std::make_pair(sym->m_dependencies, sym->n_dependencies); - } - case ASR::symbolType::Function: { - ASR::Function_t* sym = ASR::down_cast(f); - return std::make_pair(sym->m_dependencies, sym->n_dependencies); - } - case ASR::symbolType::StructType: { - ASR::StructType_t* sym = ASR::down_cast(f); - return std::make_pair(sym->m_dependencies, sym->n_dependencies); - } - case ASR::symbolType::EnumType: { - ASR::EnumType_t* sym = ASR::down_cast(f); - return std::make_pair(sym->m_dependencies, sym->n_dependencies); - } - case ASR::symbolType::UnionType: { - ASR::UnionType_t* sym = ASR::down_cast(f); - return std::make_pair(sym->m_dependencies, sym->n_dependencies); - } - default : throw LCompilersException("Not implemented"); - } -} - -static inline SymbolTable *symbol_parent_symtab(const ASR::symbol_t *f) -{ - switch (f->type) { - case ASR::symbolType::Program: { - return ASR::down_cast(f)->m_symtab->parent; - } - case ASR::symbolType::Module: { - return ASR::down_cast(f)->m_symtab->parent; - } - case ASR::symbolType::Function: { - return ASR::down_cast(f)->m_symtab->parent; - } - case ASR::symbolType::GenericProcedure: { - return ASR::down_cast(f)->m_parent_symtab; - } - case ASR::symbolType::StructType: { - return ASR::down_cast(f)->m_symtab->parent; - } - case ASR::symbolType::EnumType: { - return ASR::down_cast(f)->m_symtab->parent; - } - case ASR::symbolType::UnionType: { - return ASR::down_cast(f)->m_symtab->parent; - } - case ASR::symbolType::Variable: { - return ASR::down_cast(f)->m_parent_symtab; - } - case ASR::symbolType::ExternalSymbol: { - return ASR::down_cast(f)->m_parent_symtab; - } - case ASR::symbolType::ClassProcedure: { - return ASR::down_cast(f)->m_parent_symtab; - } - case ASR::symbolType::CustomOperator: { - return ASR::down_cast(f)->m_parent_symtab; - } - case ASR::symbolType::AssociateBlock: { - return ASR::down_cast(f)->m_symtab->parent; - } - case ASR::symbolType::Block: { - return ASR::down_cast(f)->m_symtab->parent; - } - default : throw LCompilersException("Not implemented"); - } -} - -// Returns the `symbol`'s symtab, or nullptr if the symbol has no symtab -static inline SymbolTable *symbol_symtab(const ASR::symbol_t *f) -{ - switch (f->type) { - case ASR::symbolType::Program: { - return ASR::down_cast(f)->m_symtab; - } - case ASR::symbolType::Module: { - return ASR::down_cast(f)->m_symtab; - } - case ASR::symbolType::Function: { - return ASR::down_cast(f)->m_symtab; - } - case ASR::symbolType::GenericProcedure: { - return nullptr; - //throw LCompilersException("GenericProcedure does not have a symtab"); - } - case ASR::symbolType::StructType: { - return ASR::down_cast(f)->m_symtab; - } - case ASR::symbolType::EnumType: { - return ASR::down_cast(f)->m_symtab; - } - case ASR::symbolType::UnionType: { - return ASR::down_cast(f)->m_symtab; - } - case ASR::symbolType::Variable: { - return nullptr; - //throw LCompilersException("Variable does not have a symtab"); - } - case ASR::symbolType::ExternalSymbol: { - return nullptr; - //throw LCompilersException("ExternalSymbol does not have a symtab"); - } - case ASR::symbolType::ClassProcedure: { - return nullptr; - //throw LCompilersException("ClassProcedure does not have a symtab"); - } - case ASR::symbolType::AssociateBlock: { - return ASR::down_cast(f)->m_symtab; - } - case ASR::symbolType::Block: { - return ASR::down_cast(f)->m_symtab; - } - default : throw LCompilersException("Not implemented"); - } -} - -static inline ASR::symbol_t *get_asr_owner(const ASR::symbol_t *sym) { - const SymbolTable *s = symbol_parent_symtab(sym); - if( !ASR::is_a(*s->asr_owner) ) { - return nullptr; - } - return ASR::down_cast(s->asr_owner); -} - -// Returns the Module_t the symbol is in, or nullptr if not in a module -static inline ASR::Module_t *get_sym_module(const ASR::symbol_t *sym) { - const SymbolTable *s = symbol_parent_symtab(sym); - while (s->parent != nullptr) { - ASR::symbol_t *asr_owner = ASR::down_cast(s->asr_owner); - if (ASR::is_a(*asr_owner)) { - return ASR::down_cast(asr_owner); - } - s = s->parent; - } - return nullptr; -} - -static inline ASR::symbol_t *get_asr_owner(const ASR::expr_t *expr) { - switch( expr->type ) { - case ASR::exprType::Var: { - return ASRUtils::get_asr_owner(ASR::down_cast(expr)->m_v); - } - case ASR::exprType::StructInstanceMember: { - return ASRUtils::get_asr_owner(ASRUtils::symbol_get_past_external( - ASR::down_cast(expr)->m_m)); - } - case ASR::exprType::GetPointer: { - return ASRUtils::get_asr_owner(ASR::down_cast(expr)->m_arg); - } - default: { - throw LCompilersException("Cannot find the ASR owner of underlying symbol of expression " - + std::to_string(expr->type)); - } - } - return nullptr; -} - -// Returns the Module_t the symbol is in, or nullptr if not in a module -// or no asr_owner yet -static inline ASR::Module_t *get_sym_module0(const ASR::symbol_t *sym) { - const SymbolTable *s = symbol_parent_symtab(sym); - while (s->parent != nullptr) { - if (s->asr_owner != nullptr) { - ASR::symbol_t *asr_owner = ASR::down_cast(s->asr_owner); - if (ASR::is_a(*asr_owner)) { - return ASR::down_cast(asr_owner); - } - } - s = s->parent; - } - return nullptr; -} - -static inline bool is_c_ptr(ASR::symbol_t* v, std::string v_name="") { - if( v_name == "" ) { - v_name = ASRUtils::symbol_name(v); - } - ASR::symbol_t* v_orig = ASRUtils::symbol_get_past_external(v); - if( ASR::is_a(*v_orig) ) { - ASR::Module_t* der_type_module = ASRUtils::get_sym_module0(v_orig); - return (der_type_module && std::string(der_type_module->m_name) == - "lfortran_intrinsic_iso_c_binding" && - der_type_module->m_intrinsic && - v_name == "c_ptr"); - } - return false; -} - -// Returns true if the Function is intrinsic, otherwise false -template -static inline bool is_intrinsic_procedure(const T *fn) { - ASR::symbol_t *sym = (ASR::symbol_t*)fn; - ASR::Module_t *m = get_sym_module0(sym); - if (m != nullptr) { - if (startswith(m->m_name, "lfortran_intrinsic")) return true; - } - return false; -} - -static inline bool is_intrinsic_symbol(const ASR::symbol_t *fn) { - const ASR::symbol_t *sym = fn; - ASR::Module_t *m = get_sym_module0(sym); - if (m != nullptr) { - if (m->m_intrinsic) { - return true; - } - if (startswith(m->m_name, "lfortran_intrinsic")) return true; - } - return false; -} - -// Returns true if the Function is intrinsic, otherwise false -// This version uses the `intrinsic` member of `Module`, so it -// should be used instead of is_intrinsic_procedure -static inline bool is_intrinsic_function2(const ASR::Function_t *fn) { - ASR::symbol_t *sym = (ASR::symbol_t*)fn; - ASR::Module_t *m = get_sym_module0(sym); - if (m != nullptr) { - if (m->m_intrinsic || - ASRUtils::get_FunctionType(fn)->m_abi == - ASR::abiType::Intrinsic) { - return true; - } - } - return false; -} - -// Returns true if the Function is intrinsic, otherwise false -template -static inline bool is_intrinsic_optimization(const T *routine) { - ASR::symbol_t *sym = (ASR::symbol_t*)routine; - if( ASR::is_a(*sym) ) { - ASR::ExternalSymbol_t* ext_sym = ASR::down_cast(sym); - return (std::string(ext_sym->m_module_name).find("lfortran_intrinsic_optimization") != std::string::npos); - } - ASR::Module_t *m = get_sym_module0(sym); - if (m != nullptr) { - return (std::string(m->m_name).find("lfortran_intrinsic_optimization") != std::string::npos); - } - return false; -} - -// Returns true if all arguments have a `value` -static inline bool all_args_have_value(const Vec &args) { - for (auto &a : args) { - ASR::expr_t *v = expr_value(a); - if (v == nullptr) return false; - } - return true; -} - -static inline bool is_value_constant(ASR::expr_t *a_value) { - if( a_value == nullptr ) { - return false; - } - if (ASR::is_a(*a_value)) { - // OK - } else if (ASR::is_a(*a_value)) { - // OK - } else if (ASR::is_a(*a_value)) { - // OK - } else if (ASR::is_a(*a_value)) { - // OK - } else if (ASR::is_a(*a_value)) { - // OK - } else { - return false; - } - return true; -} - -static inline bool is_value_constant(ASR::expr_t *a_value, int64_t& const_value) { - if( a_value == nullptr ) { - return false; - } - if (ASR::is_a(*a_value)) { - ASR::IntegerConstant_t* const_int = ASR::down_cast(a_value); - const_value = const_int->m_n; - } else { - return false; - } - return true; -} - -static inline bool is_value_constant(ASR::expr_t *a_value, bool& const_value) { - if( a_value == nullptr ) { - return false; - } - if (ASR::is_a(*a_value)) { - ASR::LogicalConstant_t* const_logical = ASR::down_cast(a_value); - const_value = const_logical->m_value; - } else { - return false; - } - return true; -} - -static inline bool is_value_constant(ASR::expr_t *a_value, double& const_value) { - if( a_value == nullptr ) { - return false; - } - if (ASR::is_a(*a_value)) { - ASR::IntegerConstant_t* const_int = ASR::down_cast(a_value); - const_value = const_int->m_n; - } else if (ASR::is_a(*a_value)) { - ASR::RealConstant_t* const_real = ASR::down_cast(a_value); - const_value = const_real->m_r; - } else { - return false; - } - return true; -} - -static inline bool is_value_constant(ASR::expr_t *a_value, std::string& const_value) { - if( a_value == nullptr ) { - return false; - } - if (ASR::is_a(*a_value)) { - ASR::StringConstant_t* const_string = ASR::down_cast(a_value); - const_value = std::string(const_string->m_s); - } else { - return false; - } - return true; -} - -static inline bool is_value_equal(ASR::expr_t* test_expr, ASR::expr_t* desired_expr) { - ASR::expr_t* test_value = expr_value(test_expr); - ASR::expr_t* desired_value = expr_value(desired_expr); - if( !is_value_constant(test_value) || - !is_value_constant(desired_value) || - test_value->type != desired_value->type ) { - return false; - } - - switch( desired_value->type ) { - case ASR::exprType::IntegerConstant: { - ASR::IntegerConstant_t* test_int = ASR::down_cast(test_value); - ASR::IntegerConstant_t* desired_int = ASR::down_cast(desired_value); - return test_int->m_n == desired_int->m_n; - } - case ASR::exprType::StringConstant: { - ASR::StringConstant_t* test_str = ASR::down_cast(test_value); - ASR::StringConstant_t* desired_str = ASR::down_cast(desired_value); - return std::string(test_str->m_s) == std::string(desired_str->m_s); - } - default: { - return false; - } - } -} - -static inline bool is_value_in_range(ASR::expr_t* start, ASR::expr_t* end, ASR::expr_t* value) { - ASR::expr_t *start_value = nullptr, *end_value = nullptr; - if( start ) { - start_value = expr_value(start); - } - if( end ) { - end_value = expr_value(end); - } - ASR::expr_t* test_value = expr_value(value); - - - double start_double = std::numeric_limits::min(); - double end_double = std::numeric_limits::max(); - double value_double; - bool start_const = is_value_constant(start_value, start_double); - bool end_const = is_value_constant(end_value, end_double); - bool value_const = is_value_constant(test_value, value_double); - if( !value_const || (!start_const && !end_const) ) { - return false; - } - return value_double >= start_double && value_double <= end_double; -} - -// Returns true if all arguments are evaluated -static inline bool all_args_evaluated(const Vec &args) { - for (auto &a : args) { - ASR::expr_t* a_value = ASRUtils::expr_value(a); - if( !is_value_constant(a_value) ) { - return false; - } - } - return true; -} - -static inline std::string get_mangled_name(ASR::Module_t* module, std::string symbol_name) { - std::string module_name = module->m_name; - if( module_name == symbol_name ) { - return "__" + std::string(module->m_name) + "_" + symbol_name; - } else { - return symbol_name; - } -} - -// Returns true if all arguments are evaluated -// Overload for array -static inline bool all_args_evaluated(const Vec &args) { - for (auto &a : args) { - bool is_m_left_const, is_m_right_const, is_m_step_const; - is_m_left_const = is_m_right_const = is_m_step_const = false; - if( a.m_left != nullptr ) { - ASR::expr_t *m_left_value = ASRUtils::expr_value(a.m_left); - is_m_left_const = is_value_constant(m_left_value); - } else { - is_m_left_const = true; - } - if( a.m_right != nullptr ) { - ASR::expr_t *m_right_value = ASRUtils::expr_value(a.m_right); - is_m_right_const = is_value_constant(m_right_value); - } else { - is_m_right_const = true; - } - if( a.m_step != nullptr ) { - ASR::expr_t *m_step_value = ASRUtils::expr_value(a.m_step); - is_m_step_const = is_value_constant(m_step_value); - } else { - is_m_step_const = true; - } - if( !(is_m_left_const && is_m_right_const && is_m_step_const) ) { - return false; - } - } - return true; -} - -template -static inline bool extract_value(ASR::expr_t* value_expr, T& value) { - if( !is_value_constant(value_expr) ) { - return false; - } - - switch( value_expr->type ) { - case ASR::exprType::IntegerConstant: { - ASR::IntegerConstant_t* const_int = ASR::down_cast(value_expr); - value = (T) const_int->m_n; - break; - } - case ASR::exprType::RealConstant: { - ASR::RealConstant_t* const_real = ASR::down_cast(value_expr); - value = (T) const_real->m_r; - break; - } - case ASR::exprType::LogicalConstant: { - ASR::LogicalConstant_t* const_logical = ASR::down_cast(value_expr); - value = (T) const_logical->m_value; - break; - } - default: - return false; - } - return true; -} - -static inline std::string type_python_1dim_helper(const std::string & res, - const ASR::dimension_t* e ) -{ - if( !e->m_length && !e->m_start ) { - return res + "[:]"; - } - - if( ASRUtils::expr_value(e->m_length) ) { - int64_t length_dim = -1; - ASRUtils::extract_value(ASRUtils::expr_value(e->m_length), length_dim); - return res + "[" + std::to_string(length_dim + 1) + "]"; - } - - return res; -} - -static inline void encode_dimensions(size_t n_dims, std::string& res, - bool use_underscore_sep=false) { - if( n_dims == 0 ) { - return ; - } - - if( use_underscore_sep ) { - res += "_"; - } else { - res += "["; - } - - for( size_t i = 0; i < n_dims; i++ ) { - if( use_underscore_sep ) { - res += "_"; - } else { - res += ":"; - } - if( i == n_dims - 1 ) { - if( use_underscore_sep ) { - res += "_"; - } else { - res += "]"; - } - } else { - if( use_underscore_sep ) { - res += "_"; - } else { - res += ", "; - } - } - } -} - -static inline std::string get_type_code(const ASR::ttype_t *t, bool use_underscore_sep=false, - bool encode_dimensions_=true, bool set_dimensional_hint=true) -{ - bool is_dimensional = false; - std::string res = ""; - switch (t->type) { - case ASR::ttypeType::Integer: { - ASR::Integer_t *integer = ASR::down_cast(t); - res = "i" + std::to_string(integer->m_kind * 8); - if( encode_dimensions_ ) { - encode_dimensions(integer->n_dims, res, use_underscore_sep); - return res; - } - is_dimensional = integer->n_dims > 0; - break; - } - case ASR::ttypeType::Real: { - ASR::Real_t *real = ASR::down_cast(t); - res = "r" + std::to_string(real->m_kind * 8); - if( encode_dimensions_ ) { - encode_dimensions(real->n_dims, res, use_underscore_sep); - return res; - } - is_dimensional = real->n_dims > 0; - break; - } - case ASR::ttypeType::Complex: { - ASR::Complex_t *complx = ASR::down_cast(t); - res = "c" + std::to_string(complx->m_kind * 8); - if( encode_dimensions_ ) { - encode_dimensions(complx->n_dims, res, use_underscore_sep); - return res; - } - is_dimensional = complx->n_dims > 0; - break; - } - case ASR::ttypeType::Logical: { - ASR::Logical_t* bool_ = ASR::down_cast(t); - res = "bool"; - if( encode_dimensions_ ) { - encode_dimensions(bool_->n_dims, res, use_underscore_sep); - return res; - } - is_dimensional = bool_->n_dims > 0; - break; - } - case ASR::ttypeType::Character: { - return "str"; - } - case ASR::ttypeType::Tuple: { - ASR::Tuple_t *tup = ASR::down_cast(t); - std::string result = "tuple"; - if( use_underscore_sep ) { - result += "_"; - } else { - result += "["; - } - for (size_t i = 0; i < tup->n_type; i++) { - result += get_type_code(tup->m_type[i], use_underscore_sep, - encode_dimensions_, set_dimensional_hint); - if (i + 1 != tup->n_type) { - if( use_underscore_sep ) { - result += "_"; - } else { - result += ", "; - } - } - } - if( use_underscore_sep ) { - result += "_"; - } else { - result += "]"; - } - return result; - } - case ASR::ttypeType::Set: { - ASR::Set_t *s = ASR::down_cast(t); - if( use_underscore_sep ) { - return "set_" + get_type_code(s->m_type, use_underscore_sep, - encode_dimensions_, set_dimensional_hint) + "_"; - } - return "set[" + get_type_code(s->m_type, use_underscore_sep, - encode_dimensions_, set_dimensional_hint) + "]"; - } - case ASR::ttypeType::Dict: { - ASR::Dict_t *d = ASR::down_cast(t); - if( use_underscore_sep ) { - return "dict_" + get_type_code(d->m_key_type, use_underscore_sep, - encode_dimensions_, set_dimensional_hint) + - "_" + get_type_code(d->m_value_type, use_underscore_sep, - encode_dimensions_, set_dimensional_hint) + "_"; - } - return "dict[" + get_type_code(d->m_key_type, use_underscore_sep, - encode_dimensions_, set_dimensional_hint) + - ", " + get_type_code(d->m_value_type, use_underscore_sep, - encode_dimensions_, set_dimensional_hint) + "]"; - } - case ASR::ttypeType::List: { - ASR::List_t *l = ASR::down_cast(t); - if( use_underscore_sep ) { - return "list_" + get_type_code(l->m_type, use_underscore_sep, - encode_dimensions_, set_dimensional_hint) + "_"; - } - return "list[" + get_type_code(l->m_type, use_underscore_sep, - encode_dimensions_, set_dimensional_hint) + "]"; - } - case ASR::ttypeType::CPtr: { - return "CPtr"; - } - case ASR::ttypeType::Struct: { - ASR::Struct_t* d = ASR::down_cast(t); - res = symbol_name(d->m_derived_type); - if( encode_dimensions_ ) { - encode_dimensions(d->n_dims, res, use_underscore_sep); - return res; - } - is_dimensional = d->n_dims > 0; - break; - } - case ASR::ttypeType::Class: { - ASR::Class_t* d = ASR::down_cast(t); - res = symbol_name(d->m_class_type); - if( encode_dimensions_ ) { - encode_dimensions(d->n_dims, res, use_underscore_sep); - return res; - } - is_dimensional = d->n_dims > 0; - break; - } - case ASR::ttypeType::Union: { - ASR::Union_t* d = ASR::down_cast(t); - res = symbol_name(d->m_union_type); - if( encode_dimensions_ ) { - encode_dimensions(d->n_dims, res, use_underscore_sep); - return res; - } - is_dimensional = d->n_dims > 0; - break; - } - case ASR::ttypeType::Pointer: { - ASR::Pointer_t* p = ASR::down_cast(t); - if( use_underscore_sep ) { - return "Pointer_" + get_type_code(p->m_type, use_underscore_sep, - encode_dimensions_, set_dimensional_hint) + "_"; - } - return "Pointer[" + get_type_code(p->m_type, use_underscore_sep, - encode_dimensions_, set_dimensional_hint) + "]"; - } - case ASR::ttypeType::Const: { - ASR::Const_t* p = ASR::down_cast(t); - if( use_underscore_sep ) { - return "Const_" + get_type_code(p->m_type, use_underscore_sep, - encode_dimensions_, set_dimensional_hint) + "_"; - } - return "Const[" + get_type_code(p->m_type, use_underscore_sep, - encode_dimensions_, set_dimensional_hint) + "]"; - } - default: { - throw LCompilersException("Type encoding not implemented for " - + std::to_string(t->type)); - } - } - if( is_dimensional && set_dimensional_hint ) { - res += "dim"; - } - return res; -} - -static inline std::string get_type_code(ASR::ttype_t** types, size_t n_types, - bool use_underscore_sep=false, bool encode_dimensions=true) { - std::string code = ""; - for( size_t i = 0; i < n_types; i++ ) { - code += get_type_code(types[i], use_underscore_sep, encode_dimensions) + "_"; - } - return code; -} - -static inline std::string type_to_str_python(const ASR::ttype_t *t, - bool for_error_message=true) -{ - switch (t->type) { - case ASR::ttypeType::Integer: { - ASR::Integer_t *i = (ASR::Integer_t*)t; - std::string res = ""; - switch (i->m_kind) { - case 1: { res = "i8"; break; } - case 2: { res = "i16"; break; } - case 4: { res = "i32"; break; } - case 8: { res = "i64"; break; } - default: { throw LCompilersException("Integer kind not supported"); } - } - if (i->n_dims == 1 && for_error_message) { - res = type_python_1dim_helper(res, i->m_dims); - } - return res; - } - case ASR::ttypeType::Real: { - ASR::Real_t *r = (ASR::Real_t*)t; - std::string res = ""; - switch (r->m_kind) { - case 4: { res = "f32"; break; } - case 8: { res = "f64"; break; } - default: { throw LCompilersException("Float kind not supported"); } - } - if (r->n_dims == 1 && for_error_message) { - res = type_python_1dim_helper(res, r->m_dims); - } - return res; - } - case ASR::ttypeType::Complex: { - ASR::Complex_t *c = (ASR::Complex_t*)t; - switch (c->m_kind) { - case 4: { return "c32"; } - case 8: { return "c64"; } - default: { throw LCompilersException("Complex kind not supported"); } - } - } - case ASR::ttypeType::Logical: { - return "bool"; - } - case ASR::ttypeType::Character: { - return "str"; - } - case ASR::ttypeType::Tuple: { - ASR::Tuple_t *tup = ASR::down_cast(t); - std::string result = "tuple["; - for (size_t i=0; in_type; i++) { - result += type_to_str_python(tup->m_type[i]); - if (i+1 != tup->n_type) { - result += ", "; - } - } - result += "]"; - return result; - } - case ASR::ttypeType::Set: { - ASR::Set_t *s = (ASR::Set_t *)t; - return "set[" + type_to_str_python(s->m_type) + "]"; - } - case ASR::ttypeType::Dict: { - ASR::Dict_t *d = (ASR::Dict_t *)t; - return "dict[" + type_to_str_python(d->m_key_type) + ", " + type_to_str_python(d->m_value_type) + "]"; - } - case ASR::ttypeType::List: { - ASR::List_t *l = (ASR::List_t *)t; - return "list[" + type_to_str_python(l->m_type) + "]"; - } - case ASR::ttypeType::CPtr: { - return "CPtr"; - } - case ASR::ttypeType::Struct: { - ASR::Struct_t* d = ASR::down_cast(t); - return symbol_name(d->m_derived_type); - } - case ASR::ttypeType::Enum: { - ASR::Enum_t* d = ASR::down_cast(t); - return symbol_name(d->m_enum_type); - } - case ASR::ttypeType::Union: { - ASR::Union_t* d = ASR::down_cast(t); - return symbol_name(d->m_union_type); - } - case ASR::ttypeType::Pointer: { - ASR::Pointer_t* p = ASR::down_cast(t); - return "Pointer[" + type_to_str_python(p->m_type) + "]"; - } - case ASR::ttypeType::Const: { - ASR::Const_t* p = ASR::down_cast(t); - return "Const[" + type_to_str_python(p->m_type) + "]"; - } - case ASR::ttypeType::TypeParameter: { - ASR::TypeParameter_t *p = ASR::down_cast(t); - return p->m_param; - } - default : throw LCompilersException("Not implemented " + std::to_string(t->type)); - } -} - -static inline std::string binop_to_str_python(const ASR::binopType t) { - switch (t) { - case (ASR::binopType::Add): { return " + "; } - case (ASR::binopType::Sub): { return " - "; } - case (ASR::binopType::Mul): { return "*"; } - case (ASR::binopType::Div): { return "/"; } - case (ASR::binopType::BitAnd): { return "&"; } - case (ASR::binopType::BitOr): { return "|"; } - case (ASR::binopType::BitXor): { return "^"; } - case (ASR::binopType::BitLShift): { return "<<"; } - case (ASR::binopType::BitRShift): { return ">>"; } - default : throw LCompilersException("Cannot represent the binary operator as a string"); - } -} - -static inline bool is_immutable(const ASR::ttype_t *type) { - return ((ASR::is_a(*type) || ASR::is_a(*type) - || ASR::is_a(*type))); -} - -// Returns a list of values -static inline Vec get_arg_values(Allocator &al, const Vec& args) { - Vec values; - values.reserve(al, args.size()); - for (auto &a : args) { - ASR::expr_t *v = expr_value(a.m_value); - if (v == nullptr) return values; - ASR::call_arg_t v_arg; - v_arg.loc = v->base.loc, v_arg.m_value = v; - values.push_back(al, v_arg); - } - return values; -} - -// Converts a vector of call_arg to a vector of expr -// It skips missing call_args -static inline Vec call_arg2expr(Allocator &al, const Vec& call_args) { - Vec args; - args.reserve(al, call_args.size()); - for (auto &a : call_args) { - if (a.m_value != nullptr) { - args.push_back(al, a.m_value); - } - } - return args; -} - -// Returns the TranslationUnit_t's symbol table by going via parents -static inline SymbolTable *get_tu_symtab(SymbolTable *symtab) { - SymbolTable *s = symtab; - while (s->parent != nullptr) { - s = s->parent; - } - LCOMPILERS_ASSERT(ASR::is_a(*s->asr_owner)) - return s; -} - -// Returns the name of scopes in reverse order (local scope first, function second, module last) -static inline Vec get_scope_names(Allocator &al, const SymbolTable *symtab) { - Vec scope_names; - scope_names.reserve(al, 4); - const SymbolTable *s = symtab; - while (s->parent != nullptr) { - char *owner_name = symbol_name(ASR::down_cast(s->asr_owner)); - scope_names.push_back(al, owner_name); - s = s->parent; - } - return scope_names; -} - -static inline ASR::expr_t* get_constant_expression_with_given_type(Allocator& al, ASR::ttype_t* asr_type) { - switch (asr_type->type) { - case ASR::ttypeType::Integer: { - return ASRUtils::EXPR(ASR::make_IntegerConstant_t(al, asr_type->base.loc, -1, asr_type)); - } - case ASR::ttypeType::Real: { - return ASRUtils::EXPR(ASR::make_RealConstant_t(al, asr_type->base.loc, 0.0, asr_type)); - } - case ASR::ttypeType::Complex: { - return ASRUtils::EXPR(ASR::make_ComplexConstant_t(al, asr_type->base.loc, 0.0, 0.0, asr_type)); - } - case ASR::ttypeType::Logical: { - return ASRUtils::EXPR(ASR::make_LogicalConstant_t(al, asr_type->base.loc, false, asr_type)); - } - default: { - throw LCompilersException("Not implemented " + std::to_string(asr_type->type)); - } - } - return nullptr; -} - -const ASR::intentType intent_local=ASR::intentType::Local; // local variable (not a dummy argument) -const ASR::intentType intent_in =ASR::intentType::In; // dummy argument, intent(in) -const ASR::intentType intent_out =ASR::intentType::Out; // dummy argument, intent(out) -const ASR::intentType intent_inout=ASR::intentType::InOut; // dummy argument, intent(inout) -const ASR::intentType intent_return_var=ASR::intentType::ReturnVar; // return variable of a function -const ASR::intentType intent_unspecified=ASR::intentType::Unspecified; // dummy argument, ambiguous intent - -static inline bool is_arg_dummy(int intent) { - return intent == intent_in || intent == intent_out - || intent == intent_inout || intent == intent_unspecified; -} - -static inline bool main_program_present(const ASR::TranslationUnit_t &unit) -{ - for (auto &a : unit.m_global_scope->get_scope()) { - if (ASR::is_a(*a.second)) return true; - } - return false; -} - -// Accepts dependencies in the form A -> [B, D, ...], B -> [C, D] -// Returns a list of dependencies in the order that they should be built: -// [D, C, B, A] -std::vector order_deps(std::map> const &deps); - -std::vector determine_module_dependencies( - const ASR::TranslationUnit_t &unit); - -std::vector determine_function_definition_order( - SymbolTable* symtab); - -std::vector determine_variable_declaration_order( - SymbolTable* symtab); - -void extract_module_python(const ASR::TranslationUnit_t &m, - std::vector>& children_modules, - std::string module_name); - -ASR::Module_t* extract_module(const ASR::TranslationUnit_t &m); - -ASR::Module_t* load_module(Allocator &al, SymbolTable *symtab, - const std::string &module_name, - const Location &loc, bool intrinsic, - LCompilers::PassOptions& pass_options, - bool run_verify, - const std::function err); - -ASR::TranslationUnit_t* find_and_load_module(Allocator &al, const std::string &msym, - SymbolTable &symtab, bool intrinsic, - LCompilers::PassOptions& pass_options); - -void set_intrinsic(ASR::TranslationUnit_t* trans_unit); - -ASR::asr_t* getStructInstanceMember_t(Allocator& al, const Location& loc, - ASR::asr_t* v_var, ASR::symbol_t *v, - ASR::symbol_t* member, SymbolTable* current_scope); - -bool use_overloaded(ASR::expr_t* left, ASR::expr_t* right, - ASR::binopType op, std::string& intrinsic_op_name, - SymbolTable* curr_scope, ASR::asr_t*& asr, - Allocator &al, const Location& loc, - std::set& current_function_dependencies, - Vec& current_module_dependencies, - const std::function err); - -bool is_op_overloaded(ASR::binopType op, std::string& intrinsic_op_name, - SymbolTable* curr_scope); - -bool use_overloaded(ASR::expr_t* left, ASR::expr_t* right, - ASR::cmpopType op, std::string& intrinsic_op_name, - SymbolTable* curr_scope, ASR::asr_t*& asr, - Allocator &al, const Location& loc, - std::set& current_function_dependencies, - Vec& current_module_dependencies, - const std::function err); - -bool is_op_overloaded(ASR::cmpopType op, std::string& intrinsic_op_name, - SymbolTable* curr_scope, ASR::StructType_t *left_struct); - -bool use_overloaded_assignment(ASR::expr_t* target, ASR::expr_t* value, - SymbolTable* curr_scope, ASR::asr_t*& asr, - Allocator &al, const Location& loc, - std::set& current_function_dependencies, - Vec& /*current_module_dependencies*/, - const std::function err); - -void set_intrinsic(ASR::symbol_t* sym); - -static inline int extract_kind_from_ttype_t(const ASR::ttype_t* type) { - if (type == nullptr) { - return -1; - } - switch (type->type) { - case ASR::ttypeType::Integer : { - return ASR::down_cast(type)->m_kind; - } - case ASR::ttypeType::Real : { - return ASR::down_cast(type)->m_kind; - } - case ASR::ttypeType::Complex: { - return ASR::down_cast(type)->m_kind; - } - case ASR::ttypeType::Character: { - return ASR::down_cast(type)->m_kind; - } - case ASR::ttypeType::Logical: { - return ASR::down_cast(type)->m_kind; - } - case ASR::ttypeType::Pointer: { - return extract_kind_from_ttype_t(ASR::down_cast(type)->m_type); - } - case ASR::ttypeType::Const: { - return extract_kind_from_ttype_t(ASR::down_cast(type)->m_type); - } - default : { - return -1; - } - } -} - -static inline bool is_pointer(ASR::ttype_t *x) { - return ASR::is_a(*x); -} - -static inline bool is_integer(ASR::ttype_t &x) { - return ASR::is_a(*type_get_past_pointer(&x)); -} - -static inline bool is_real(ASR::ttype_t &x) { - return ASR::is_a(*type_get_past_pointer(&x)); -} - -static inline bool is_character(ASR::ttype_t &x) { - return ASR::is_a(*type_get_past_pointer(&x)); -} - -static inline bool is_complex(ASR::ttype_t &x) { - return ASR::is_a(*type_get_past_pointer(&x)); -} - -static inline bool is_logical(ASR::ttype_t &x) { - return ASR::is_a(*type_get_past_pointer(&x)); -} - -static inline bool is_generic(ASR::ttype_t &x) { - switch (x.type) { - case ASR::ttypeType::List: { - ASR::List_t *list_type = ASR::down_cast(type_get_past_pointer(&x)); - return is_generic(*list_type->m_type); - } - default : return ASR::is_a(*type_get_past_pointer(&x)); - } -} - -static inline bool is_generic_function(ASR::symbol_t *x) { - ASR::symbol_t* x2 = symbol_get_past_external(x); - switch (x2->type) { - case ASR::symbolType::Function: { - ASR::Function_t *func_sym = ASR::down_cast(x2); - return (ASRUtils::get_FunctionType(func_sym)->n_type_params > 0 && - !ASRUtils::get_FunctionType(func_sym)->m_is_restriction); - } - default: return false; - } -} - -static inline bool is_restriction_function(ASR::symbol_t *x) { - ASR::symbol_t* x2 = symbol_get_past_external(x); - switch (x2->type) { - case ASR::symbolType::Function: { - ASR::Function_t *func_sym = ASR::down_cast(x2); - return ASRUtils::get_FunctionType(func_sym)->m_is_restriction; - } - default: return false; - } -} - -static inline int get_body_size(ASR::symbol_t* s) { - int n_body = 0; - switch (s->type) { - case ASR::symbolType::Function: { - ASR::Function_t* f = ASR::down_cast(s); - n_body = f->n_body; - break; - } - case ASR::symbolType::Program: { - ASR::Program_t* p = ASR::down_cast(s); - n_body = p->n_body; - break; - } - default: { - n_body = -1; - } - } - return n_body; -} - -inline int extract_dimensions_from_ttype(ASR::ttype_t *x, - ASR::dimension_t*& m_dims) { - int n_dims = 0; - switch (x->type) { - case ASR::ttypeType::Integer: { - ASR::Integer_t* Integer_type = ASR::down_cast(x); - n_dims = Integer_type->n_dims; - m_dims = Integer_type->m_dims; - break; - } - case ASR::ttypeType::Real: { - ASR::Real_t* Real_type = ASR::down_cast(x); - n_dims = Real_type->n_dims; - m_dims = Real_type->m_dims; - break; - } - case ASR::ttypeType::Complex: { - ASR::Complex_t* Complex_type = ASR::down_cast(x); - n_dims = Complex_type->n_dims; - m_dims = Complex_type->m_dims; - break; - } - case ASR::ttypeType::Character: { - ASR::Character_t* Character_type = ASR::down_cast(x); - n_dims = Character_type->n_dims; - m_dims = Character_type->m_dims; - break; - } - case ASR::ttypeType::Logical: { - ASR::Logical_t* Logical_type = ASR::down_cast(x); - n_dims = Logical_type->n_dims; - m_dims = Logical_type->m_dims; - break; - } - case ASR::ttypeType::Struct: { - ASR::Struct_t* Struct_type = ASR::down_cast(x); - n_dims = Struct_type->n_dims; - m_dims = Struct_type->m_dims; - break; - } - case ASR::ttypeType::Enum: { - ASR::Enum_t* Enum_type = ASR::down_cast(x); - n_dims = Enum_type->n_dims; - m_dims = Enum_type->m_dims; - break; - } - case ASR::ttypeType::Union: { - ASR::Union_t* Union_type = ASR::down_cast(x); - n_dims = Union_type->n_dims; - m_dims = Union_type->m_dims; - break; - } - case ASR::ttypeType::Class: { - ASR::Class_t* Class_type = ASR::down_cast(x); - n_dims = Class_type->n_dims; - m_dims = Class_type->m_dims; - break; - } - case ASR::ttypeType::Pointer: { - n_dims = extract_dimensions_from_ttype(ASR::down_cast(x)->m_type, m_dims); - break; - } - case ASR::ttypeType::Const: { - n_dims = extract_dimensions_from_ttype(ASR::down_cast(x)->m_type, m_dims); - break; - } - case ASR::ttypeType::List: { - n_dims = 0; - m_dims = nullptr; - break; - } - case ASR::ttypeType::Tuple: { - n_dims = 0; - m_dims = nullptr; - break; - } - case ASR::ttypeType::Dict: { - n_dims = 0; - m_dims = nullptr; - break; - } - case ASR::ttypeType::CPtr: { - n_dims = 0; - m_dims = nullptr; - break; - } - case ASR::ttypeType::TypeParameter: { - ASR::TypeParameter_t* tp = ASR::down_cast(x); - n_dims = tp->n_dims; - m_dims = tp->m_dims; - break; - } - default: - throw LCompilersException("Not implemented."); - } - return n_dims; -} - -static inline bool is_fixed_size_array(ASR::dimension_t* m_dims, size_t n_dims) { - if( n_dims == 0 ) { - return false; - } - for( size_t i = 0; i < n_dims; i++ ) { - int64_t dim_size = -1; - if( m_dims[i].m_length == nullptr ) { - return false; - } - if( !ASRUtils::extract_value(ASRUtils::expr_value(m_dims[i].m_length), dim_size) ) { - return false; - } - } - return true; -} - -static inline int64_t get_fixed_size_of_array(ASR::dimension_t* m_dims, size_t n_dims) { - if( n_dims == 0 ) { - return 0; - } - int64_t array_size = 1; - for( size_t i = 0; i < n_dims; i++ ) { - int64_t dim_size = -1; - if( !ASRUtils::extract_value(ASRUtils::expr_value(m_dims[i].m_length), dim_size) ) { - return -1; - } - array_size *= dim_size; - } - return array_size; -} - -inline int extract_n_dims_from_ttype(ASR::ttype_t *x) { - ASR::dimension_t* m_dims_temp = nullptr; - return extract_dimensions_from_ttype(x, m_dims_temp); -} - -// Sets the dimension member of `ttype_t`. Returns `true` if dimensions set. -// Returns `false` if the `ttype_t` does not have a dimension member. -inline bool ttype_set_dimensions(ASR::ttype_t *x, - ASR::dimension_t *m_dims, int64_t n_dims) { - switch (x->type) { - case ASR::ttypeType::Integer: { - ASR::Integer_t* Integer_type = ASR::down_cast(x); - Integer_type->n_dims = n_dims; - Integer_type->m_dims = m_dims; - return true; - } - case ASR::ttypeType::Real: { - ASR::Real_t* Real_type = ASR::down_cast(x); - Real_type->n_dims = n_dims; - Real_type->m_dims = m_dims; - return true; - } - case ASR::ttypeType::Complex: { - ASR::Complex_t* Complex_type = ASR::down_cast(x); - Complex_type->n_dims = n_dims; - Complex_type->m_dims = m_dims; - return true; - } - case ASR::ttypeType::Character: { - ASR::Character_t* Character_type = ASR::down_cast(x); - Character_type->n_dims = n_dims; - Character_type->m_dims = m_dims; - return true; - } - case ASR::ttypeType::Logical: { - ASR::Logical_t* Logical_type = ASR::down_cast(x); - n_dims = Logical_type->n_dims; - m_dims = Logical_type->m_dims; - return true; - } - case ASR::ttypeType::Struct: { - ASR::Struct_t* Struct_type = ASR::down_cast(x); - n_dims = Struct_type->n_dims; - m_dims = Struct_type->m_dims; - return true; - } - case ASR::ttypeType::Class: { - ASR::Class_t* Class_type = ASR::down_cast(x); - Class_type->n_dims = n_dims; - Class_type->m_dims = m_dims; - return true; - } - case ASR::ttypeType::TypeParameter: { - ASR::TypeParameter_t* tp = ASR::down_cast(x); - n_dims = tp->n_dims; - m_dims = tp->m_dims; - return true; - } - case ASR::ttypeType::Pointer: { - return ttype_set_dimensions( - ASR::down_cast(x)->m_type, m_dims, n_dims); - } - default: - return false; - } - return false; -} - -inline bool is_array(ASR::ttype_t *x) { - ASR::dimension_t* dims = nullptr; - return extract_dimensions_from_ttype(x, dims) > 0; -} - -static inline bool is_aggregate_type(ASR::ttype_t* asr_type) { - if( ASR::is_a(*asr_type) ) { - asr_type = ASR::down_cast(asr_type)->m_type; - } - return ASRUtils::is_array(asr_type) || - !(ASR::is_a(*asr_type) || - ASR::is_a(*asr_type) || - ASR::is_a(*asr_type) || - ASR::is_a(*asr_type)); -} - -static inline ASR::ttype_t* duplicate_type(Allocator& al, const ASR::ttype_t* t, - Vec* dims = nullptr) { - switch (t->type) { - case ASR::ttypeType::Integer: { - ASR::Integer_t* tnew = ASR::down_cast(t); - ASR::dimension_t* dimsp = dims ? dims->p : tnew->m_dims; - size_t dimsn = dims ? dims->n : tnew->n_dims; - return ASRUtils::TYPE(ASR::make_Integer_t(al, t->base.loc, - tnew->m_kind, dimsp, dimsn)); - } - case ASR::ttypeType::Real: { - ASR::Real_t* tnew = ASR::down_cast(t); - ASR::dimension_t* dimsp = dims ? dims->p : tnew->m_dims; - size_t dimsn = dims ? dims->n : tnew->n_dims; - return ASRUtils::TYPE(ASR::make_Real_t(al, t->base.loc, - tnew->m_kind, dimsp, dimsn)); - } - case ASR::ttypeType::Complex: { - ASR::Complex_t* tnew = ASR::down_cast(t); - ASR::dimension_t* dimsp = dims ? dims->p : tnew->m_dims; - size_t dimsn = dims ? dims->n : tnew->n_dims; - return ASRUtils::TYPE(ASR::make_Complex_t(al, t->base.loc, - tnew->m_kind, dimsp, dimsn)); - } - case ASR::ttypeType::Logical: { - ASR::Logical_t* tnew = ASR::down_cast(t); - ASR::dimension_t* dimsp = dims ? dims->p : tnew->m_dims; - size_t dimsn = dims ? dims->n : tnew->n_dims; - return ASRUtils::TYPE(ASR::make_Logical_t(al, t->base.loc, - tnew->m_kind, dimsp, dimsn)); - } - case ASR::ttypeType::Character: { - ASR::Character_t* tnew = ASR::down_cast(t); - ASR::dimension_t* dimsp = dims ? dims->p : tnew->m_dims; - size_t dimsn = dims ? dims->n : tnew->n_dims; - return ASRUtils::TYPE(ASR::make_Character_t(al, t->base.loc, - tnew->m_kind, tnew->m_len, tnew->m_len_expr, - dimsp, dimsn)); - } - case ASR::ttypeType::Struct: { - ASR::Struct_t* tnew = ASR::down_cast(t); - ASR::dimension_t* dimsp = dims ? dims->p : tnew->m_dims; - size_t dimsn = dims ? dims->n : tnew->n_dims; - return ASRUtils::TYPE(ASR::make_Struct_t(al, t->base.loc, - tnew->m_derived_type, dimsp, dimsn)); - } - case ASR::ttypeType::Class: { - ASR::Class_t* tnew = ASR::down_cast(t); - ASR::dimension_t* dimsp = dims ? dims->p : tnew->m_dims; - size_t dimsn = dims ? dims->n : tnew->n_dims; - return ASRUtils::TYPE(ASR::make_Class_t(al, t->base.loc, - tnew->m_class_type, dimsp, dimsn)); - } - case ASR::ttypeType::Pointer: { - ASR::Pointer_t* ptr = ASR::down_cast(t); - ASR::ttype_t* dup_type = duplicate_type(al, ptr->m_type, dims); - return ASRUtils::TYPE(ASR::make_Pointer_t(al, ptr->base.base.loc, - dup_type)); - } - case ASR::ttypeType::Const: { - ASR::Const_t* c = ASR::down_cast(t); - ASR::ttype_t* dup_type = duplicate_type(al, c->m_type, dims); - return ASRUtils::TYPE(ASR::make_Const_t(al, c->base.base.loc, - dup_type)); - } - case ASR::ttypeType::TypeParameter: { - ASR::TypeParameter_t* tp = ASR::down_cast(t); - ASR::dimension_t* dimsp = dims ? dims->p : tp->m_dims; - size_t dimsn = dims ? dims->n : tp->n_dims; - //return ASRUtils::TYPE(ASR::make_TypeParameter_t(al, t->base.loc, - // tp->m_param, dimsp, dimsn, tp->m_rt, tp->n_rt)); - return ASRUtils::TYPE(ASR::make_TypeParameter_t(al, t->base.loc, - tp->m_param, dimsp, dimsn)); - } - default : throw LCompilersException("Not implemented " + std::to_string(t->type)); - } -} - -static inline ASR::ttype_t* duplicate_type_without_dims(Allocator& al, const ASR::ttype_t* t, const Location& loc) { - switch (t->type) { - case ASR::ttypeType::Integer: { - ASR::Integer_t* tnew = ASR::down_cast(t); - return ASRUtils::TYPE(ASR::make_Integer_t(al, loc, - tnew->m_kind, nullptr, 0)); - } - case ASR::ttypeType::Real: { - ASR::Real_t* tnew = ASR::down_cast(t); - return ASRUtils::TYPE(ASR::make_Real_t(al, loc, - tnew->m_kind, nullptr, 0)); - } - case ASR::ttypeType::Complex: { - ASR::Complex_t* tnew = ASR::down_cast(t); - return ASRUtils::TYPE(ASR::make_Complex_t(al, loc, - tnew->m_kind, nullptr, 0)); - } - case ASR::ttypeType::Logical: { - ASR::Logical_t* tnew = ASR::down_cast(t); - return ASRUtils::TYPE(ASR::make_Logical_t(al, loc, - tnew->m_kind, nullptr, 0)); - } - case ASR::ttypeType::Character: { - ASR::Character_t* tnew = ASR::down_cast(t); - return ASRUtils::TYPE(ASR::make_Character_t(al, loc, - tnew->m_kind, tnew->m_len, tnew->m_len_expr, - nullptr, 0)); - } - case ASR::ttypeType::Struct: { - ASR::Struct_t* tstruct = ASR::down_cast(t); - return ASRUtils::TYPE(ASR::make_Struct_t(al, loc, - tstruct->m_derived_type, nullptr, 0)); - } - case ASR::ttypeType::TypeParameter: { - ASR::TypeParameter_t* tp = ASR::down_cast(t); - //return ASRUtils::TYPE(ASR::make_TypeParameter_t(al, t->base.loc, - // tp->m_param, nullptr, 0, tp->m_rt, tp->n_rt)); - return ASRUtils::TYPE(ASR::make_TypeParameter_t(al, loc, - tp->m_param, nullptr, 0)); - } - default : throw LCompilersException("Not implemented " + std::to_string(t->type)); - } -} - -inline bool is_same_type_pointer(ASR::ttype_t* source, ASR::ttype_t* dest) { - bool is_source_pointer = is_pointer(source), is_dest_pointer = is_pointer(dest); - if( (!is_source_pointer && !is_dest_pointer) || - (is_source_pointer && is_dest_pointer) ) { - return false; - } - if( is_source_pointer && !is_dest_pointer ) { - ASR::ttype_t* temp = source; - source = dest; - dest = temp; - } - dest = ASR::down_cast(dest)->m_type; - if( (ASR::is_a(*source) || ASR::is_a(*source)) && - (ASR::is_a(*dest) || ASR::is_a(*dest)) ) { - return true; - } - bool res = source->type == dest->type; - return res; -} - -inline int extract_kind_str(char* m_n, char *&kind_str) { - char *p = m_n; - while (*p != '\0') { - if (*p == '_') { - p++; - std::string kind = std::string(p); - int ikind = std::atoi(p); - if (ikind == 0) { - // Not an integer, return a string - kind_str = p; - return 0; - } else { - return ikind; - } - } - if (*p == 'd' || *p == 'D') { - // Double precision - return 8; - } - p++; - } - return 4; -} - -template -inline int extract_kind(ASR::expr_t* kind_expr, const Location& loc) { - int a_kind = 4; - switch( kind_expr->type ) { - case ASR::exprType::IntegerConstant: { - a_kind = ASR::down_cast - (kind_expr)->m_n; - break; - } - case ASR::exprType::Var: { - ASR::Var_t* kind_var = - ASR::down_cast(kind_expr); - ASR::Variable_t* kind_variable = - ASR::down_cast( - symbol_get_past_external(kind_var->m_v)); - bool is_parent_enum = false; - if (kind_variable->m_parent_symtab->asr_owner != nullptr) { - ASR::symbol_t *s = ASR::down_cast( - kind_variable->m_parent_symtab->asr_owner); - is_parent_enum = ASR::is_a(*s); - } - if( kind_variable->m_storage == ASR::storage_typeType::Parameter - || is_parent_enum) { - if( kind_variable->m_type->type == ASR::ttypeType::Integer ) { - LCOMPILERS_ASSERT( kind_variable->m_value != nullptr ); - a_kind = ASR::down_cast(kind_variable->m_value)->m_n; - } else { - std::string msg = "Integer variable required. " + std::string(kind_variable->m_name) + - " is not an Integer variable."; - throw SemanticError(msg, loc); - } - } else { - std::string msg = "Parameter " + std::string(kind_variable->m_name) + - " is a variable, which does not reduce to a constant expression"; - throw SemanticError(msg, loc); - } - break; - } - default: { - throw SemanticError(R"""(Only Integer literals or expressions which reduce to constant Integer are accepted as kind parameters.)""", - loc); - } - } - return a_kind; -} - -template -inline int extract_len(ASR::expr_t* len_expr, const Location& loc) { - int a_len = -10; - switch( len_expr->type ) { - case ASR::exprType::IntegerConstant: { - a_len = ASR::down_cast - (len_expr)->m_n; - break; - } - case ASR::exprType::Var: { - ASR::Var_t* len_var = - ASR::down_cast(len_expr); - ASR::Variable_t* len_variable = - ASR::down_cast( - symbol_get_past_external(len_var->m_v)); - if( len_variable->m_storage == ASR::storage_typeType::Parameter ) { - if( len_variable->m_type->type == ASR::ttypeType::Integer ) { - LCOMPILERS_ASSERT( len_variable->m_value != nullptr ); - a_len = ASR::down_cast(len_variable->m_value)->m_n; - } else { - std::string msg = "Integer variable required. " + std::string(len_variable->m_name) + - " is not an Integer variable."; - throw SemanticError(msg, loc); - } - } else { - // An expression is beind used for `len` that cannot be evaluated - a_len = -3; - } - break; - } - case ASR::exprType::FunctionCall: { - a_len = -3; - break; - } - case ASR::exprType::IntegerBinOp: { - a_len = -3; - break; - } - default: { - throw SemanticError("Only Integers or variables implemented so far for `len` expressions", - loc); - } - } - LCOMPILERS_ASSERT(a_len != -10) - return a_len; -} - -inline bool is_parent(SymbolTable* a, SymbolTable* b) { - SymbolTable* current_parent = b->parent; - while( current_parent ) { - if( current_parent == a ) { - return true; - } - current_parent = current_parent->parent; - } - return false; -} - -inline bool is_parent(ASR::StructType_t* a, ASR::StructType_t* b) { - ASR::symbol_t* current_parent = b->m_parent; - while( current_parent ) { - current_parent = ASRUtils::symbol_get_past_external(current_parent); - if( current_parent == (ASR::symbol_t*) a ) { - return true; - } - LCOMPILERS_ASSERT(ASR::is_a(*current_parent)); - current_parent = ASR::down_cast(current_parent)->m_parent; - } - return false; -} - -inline bool is_derived_type_similar(ASR::StructType_t* a, ASR::StructType_t* b) { - return a == b || is_parent(a, b) || is_parent(b, a) || - (std::string(a->m_name) == "~abstract_type" && - std::string(b->m_name) == "~abstract_type"); -} - -// TODO: Scaled up implementation for all exprTypes -// One way is to do it in asdl_cpp.py -inline bool expr_equal(ASR::expr_t* x, ASR::expr_t* y) { - if( x->type != y->type ) { - return false; - } - - switch( x->type ) { - case ASR::exprType::IntegerBinOp: { - ASR::IntegerBinOp_t* intbinop_x = ASR::down_cast(x); - ASR::IntegerBinOp_t* intbinop_y = ASR::down_cast(y); - if( intbinop_x->m_op != intbinop_y->m_op ) { - return false; - } - bool left_left = expr_equal(intbinop_x->m_left, intbinop_y->m_left); - bool left_right = expr_equal(intbinop_x->m_left, intbinop_y->m_right); - bool right_left = expr_equal(intbinop_x->m_right, intbinop_y->m_left); - bool right_right = expr_equal(intbinop_x->m_right, intbinop_y->m_right); - switch( intbinop_x->m_op ) { - case ASR::binopType::Add: - case ASR::binopType::Mul: - case ASR::binopType::BitAnd: - case ASR::binopType::BitOr: - case ASR::binopType::BitXor: { - return (left_left && right_right) || (left_right && right_left); - } - case ASR::binopType::Sub: - case ASR::binopType::Div: - case ASR::binopType::Pow: - case ASR::binopType::BitLShift: - case ASR::binopType::BitRShift: { - return (left_left && right_right); - } - } - break; - } - case ASR::exprType::Var: { - ASR::Var_t* var_x = ASR::down_cast(x); - ASR::Var_t* var_y = ASR::down_cast(y); - return var_x->m_v == var_y->m_v; - } - default: { - // Let it pass for now. - return true; - } - } - - // Let it pass for now. - return true; -} - -inline bool dimension_expr_equal(ASR::expr_t* dim_a, ASR::expr_t* dim_b) { - if( !(dim_a && dim_b) ) { - return true; - } - ASR::expr_t* dim_a_fallback = nullptr; - ASR::expr_t* dim_b_fallback = nullptr; - if( ASR::is_a(*dim_a) && - ASR::is_a( - *ASR::down_cast(dim_a)->m_v) ) { - dim_a_fallback = ASRUtils::EXPR2VAR(dim_a)->m_symbolic_value; - } - if( ASR::is_a(*dim_b) && - ASR::is_a( - *ASR::down_cast(dim_b)->m_v) ) { - dim_b_fallback = ASRUtils::EXPR2VAR(dim_b)->m_symbolic_value; - } - if( !ASRUtils::expr_equal(dim_a, dim_b) && - !(dim_a_fallback && ASRUtils::expr_equal(dim_a_fallback, dim_b)) && - !(dim_b_fallback && ASRUtils::expr_equal(dim_a, dim_b_fallback)) ) { - return false; - } - return true; -} - -inline bool dimensions_equal(ASR::dimension_t* dims_a, size_t n_dims_a, - ASR::dimension_t* dims_b, size_t n_dims_b) { - if( n_dims_a != n_dims_b ) { - return false; - } - - for( size_t i = 0; i < n_dims_a; i++ ) { - ASR::dimension_t dim_a = dims_a[i]; - ASR::dimension_t dim_b = dims_b[i]; - if( !dimension_expr_equal(dim_a.m_length, dim_b.m_length) || - !dimension_expr_equal(dim_a.m_start, dim_b.m_start) ) { - return false; - } - } - return true; -} - -inline bool types_equal(ASR::ttype_t *a, ASR::ttype_t *b, - bool check_for_dimensions=false) { - // TODO: If anyone of the input or argument is derived type then - // add support for checking member wise types and do not compare - // directly. From stdlib_string len(pattern) error - a = ASRUtils::type_get_past_pointer(a); - b = ASRUtils::type_get_past_pointer(b); - if (a->type == b->type) { - // TODO: check dims - // TODO: check all types - switch (a->type) { - case (ASR::ttypeType::Integer) : { - ASR::Integer_t *a2 = ASR::down_cast(a); - ASR::Integer_t *b2 = ASR::down_cast(b); - if (a2->m_kind == b2->m_kind) { - if( check_for_dimensions ) { - return ASRUtils::dimensions_equal( - a2->m_dims, a2->n_dims, - b2->m_dims, b2->n_dims); - } else { - return true; - } - } else { - return false; - } - break; - } - case ASR::ttypeType::CPtr: { - return true; - } - case (ASR::ttypeType::Real) : { - ASR::Real_t *a2 = ASR::down_cast(a); - ASR::Real_t *b2 = ASR::down_cast(b); - if (a2->m_kind == b2->m_kind) { - if( check_for_dimensions ) { - return ASRUtils::dimensions_equal( - a2->m_dims, a2->n_dims, - b2->m_dims, b2->n_dims); - } else { - return true; - } - } else { - return false; - } - break; - } - case (ASR::ttypeType::Complex) : { - ASR::Complex_t *a2 = ASR::down_cast(a); - ASR::Complex_t *b2 = ASR::down_cast(b); - if (a2->m_kind == b2->m_kind) { - if( check_for_dimensions ) { - return ASRUtils::dimensions_equal( - a2->m_dims, a2->n_dims, - b2->m_dims, b2->n_dims); - } else { - return true; - } - } else { - return false; - } - break; - } - case (ASR::ttypeType::Logical) : { - ASR::Logical_t *a2 = ASR::down_cast(a); - ASR::Logical_t *b2 = ASR::down_cast(b); - if (a2->m_kind == b2->m_kind) { - if( check_for_dimensions ) { - return ASRUtils::dimensions_equal( - a2->m_dims, a2->n_dims, - b2->m_dims, b2->n_dims); - } else { - return true; - } - } else { - return false; - } - break; - } - case (ASR::ttypeType::Character) : { - ASR::Character_t *a2 = ASR::down_cast(a); - ASR::Character_t *b2 = ASR::down_cast(b); - if (a2->m_kind == b2->m_kind) { - if( check_for_dimensions ) { - return ASRUtils::dimensions_equal( - a2->m_dims, a2->n_dims, - b2->m_dims, b2->n_dims); - } else { - return true; - } - } else { - return false; - } - break; - } - case (ASR::ttypeType::List) : { - ASR::List_t *a2 = ASR::down_cast(a); - ASR::List_t *b2 = ASR::down_cast(b); - return types_equal(a2->m_type, b2->m_type); - } - case (ASR::ttypeType::Struct) : { - ASR::Struct_t *a2 = ASR::down_cast(a); - ASR::Struct_t *b2 = ASR::down_cast(b); - ASR::StructType_t *a2_type = ASR::down_cast( - ASRUtils::symbol_get_past_external( - a2->m_derived_type)); - ASR::StructType_t *b2_type = ASR::down_cast( - ASRUtils::symbol_get_past_external( - b2->m_derived_type)); - return a2_type == b2_type; - } - case (ASR::ttypeType::Class) : { - ASR::Class_t *a2 = ASR::down_cast(a); - ASR::Class_t *b2 = ASR::down_cast(b); - ASR::symbol_t* a2_typesym = ASRUtils::symbol_get_past_external(a2->m_class_type); - ASR::symbol_t* b2_typesym = ASRUtils::symbol_get_past_external(b2->m_class_type); - if( a2_typesym->type != b2_typesym->type ) { - return false; - } - if( a2_typesym->type == ASR::symbolType::ClassType ) { - ASR::ClassType_t *a2_type = ASR::down_cast(a2_typesym); - ASR::ClassType_t *b2_type = ASR::down_cast(b2_typesym); - return a2_type == b2_type; - } else if( a2_typesym->type == ASR::symbolType::StructType ) { - ASR::StructType_t *a2_type = ASR::down_cast(a2_typesym); - ASR::StructType_t *b2_type = ASR::down_cast(b2_typesym); - return is_derived_type_similar(a2_type, b2_type); - } - return false; - } - case (ASR::ttypeType::Union) : { - ASR::Union_t *a2 = ASR::down_cast(a); - ASR::Union_t *b2 = ASR::down_cast(b); - ASR::UnionType_t *a2_type = ASR::down_cast( - ASRUtils::symbol_get_past_external( - a2->m_union_type)); - ASR::UnionType_t *b2_type = ASR::down_cast( - ASRUtils::symbol_get_past_external( - b2->m_union_type)); - return a2_type == b2_type; - } - default : return false; - } - } else if( a->type == ASR::ttypeType::Struct && - b->type == ASR::ttypeType::Class ) { - ASR::Struct_t *a2 = ASR::down_cast(a); - ASR::Class_t *b2 = ASR::down_cast(b); - ASR::symbol_t* a2_typesym = ASRUtils::symbol_get_past_external(a2->m_derived_type); - ASR::symbol_t* b2_typesym = ASRUtils::symbol_get_past_external(b2->m_class_type); - if( a2_typesym->type != b2_typesym->type ) { - return false; - } - if( a2_typesym->type == ASR::symbolType::ClassType ) { - ASR::ClassType_t *a2_type = ASR::down_cast(a2_typesym); - ASR::ClassType_t *b2_type = ASR::down_cast(b2_typesym); - return a2_type == b2_type; - } else if( a2_typesym->type == ASR::symbolType::StructType ) { - ASR::StructType_t *a2_type = ASR::down_cast(a2_typesym); - ASR::StructType_t *b2_type = ASR::down_cast(b2_typesym); - return is_derived_type_similar(a2_type, b2_type); - } - } else if( a->type == ASR::ttypeType::Class && - b->type == ASR::ttypeType::Struct ) { - ASR::Class_t *a2 = ASR::down_cast(a); - ASR::Struct_t *b2 = ASR::down_cast(b); - ASR::symbol_t* a2_typesym = ASRUtils::symbol_get_past_external(a2->m_class_type); - ASR::symbol_t* b2_typesym = ASRUtils::symbol_get_past_external(b2->m_derived_type); - if( a2_typesym->type != b2_typesym->type ) { - return false; - } - if( a2_typesym->type == ASR::symbolType::ClassType ) { - ASR::ClassType_t *a2_type = ASR::down_cast(a2_typesym); - ASR::ClassType_t *b2_type = ASR::down_cast(b2_typesym); - return a2_type == b2_type; - } else if( a2_typesym->type == ASR::symbolType::StructType ) { - ASR::StructType_t *a2_type = ASR::down_cast(a2_typesym); - ASR::StructType_t *b2_type = ASR::down_cast(b2_typesym); - return is_derived_type_similar(a2_type, b2_type); - } - } - return false; -} - -inline bool check_equal_type(ASR::ttype_t* x, ASR::ttype_t* y) { - ASR::ttype_t *x_underlying, *y_underlying; - x_underlying = nullptr; - y_underlying = nullptr; - if( ASR::is_a(*x) ) { - ASR::Enum_t *x_enum = ASR::down_cast(x); - ASR::EnumType_t *x_enum_type = ASR::down_cast(x_enum->m_enum_type); - x_underlying = x_enum_type->m_type; - } - if( ASR::is_a(*y) ) { - ASR::Enum_t *y_enum = ASR::down_cast(y); - ASR::EnumType_t *y_enum_type = ASR::down_cast(y_enum->m_enum_type); - y_underlying = y_enum_type->m_type; - } - if( x_underlying || y_underlying ) { - if( x_underlying ) { - x = x_underlying; - } - if( y_underlying ) { - y = y_underlying; - } - return check_equal_type(x, y); - } - if( ASR::is_a(*x) || - ASR::is_a(*y) ) { - x = ASRUtils::type_get_past_pointer(x); - y = ASRUtils::type_get_past_pointer(y); - return check_equal_type(x, y); - } else if(ASR::is_a(*x) || - ASR::is_a(*y)) { - x = ASRUtils::get_contained_type(x); - y = ASRUtils::get_contained_type(y); - return check_equal_type(x, y); - } else if (ASR::is_a(*x) && ASR::is_a(*y)) { - x = ASR::down_cast(x)->m_type; - y = ASR::down_cast(y)->m_type; - return check_equal_type(x, y); - } else if (ASR::is_a(*x) && ASR::is_a(*y)) { - x = ASR::down_cast(x)->m_type; - y = ASR::down_cast(y)->m_type; - return check_equal_type(x, y); - } else if (ASR::is_a(*x) && ASR::is_a(*y)) { - ASR::ttype_t *x_key_type = ASR::down_cast(x)->m_key_type; - ASR::ttype_t *y_key_type = ASR::down_cast(y)->m_key_type; - ASR::ttype_t *x_value_type = ASR::down_cast(x)->m_value_type; - ASR::ttype_t *y_value_type = ASR::down_cast(y)->m_value_type; - return (check_equal_type(x_key_type, y_key_type) && - check_equal_type(x_value_type, y_value_type)); - } else if (ASR::is_a(*x) && ASR::is_a(*y)) { - ASR::Tuple_t *a = ASR::down_cast(x); - ASR::Tuple_t *b = ASR::down_cast(y); - if(a->n_type != b->n_type) { - return false; - } - bool result = true; - for (size_t i=0; in_type; i++) { - result = result && check_equal_type(a->m_type[i], b->m_type[i]); - if (!result) { - return false; - } - } - return result; - } else if (ASR::is_a(*x) && ASR::is_a(*y)) { - ASR::TypeParameter_t* left_tp = ASR::down_cast(x); - ASR::TypeParameter_t* right_tp = ASR::down_cast(y); - std::string left_param = left_tp->m_param; - std::string right_param = right_tp->m_param; - return left_param.compare(right_param) == 0; - } - - return types_equal(x, y); -} - -int select_generic_procedure(const Vec &args, - const ASR::GenericProcedure_t &p, Location loc, - const std::function err, - bool raise_error=true); - -ASR::asr_t* symbol_resolve_external_generic_procedure_without_eval( - const Location &loc, - ASR::symbol_t *v, Vec& args, - SymbolTable* current_scope, Allocator& al, - const std::function err); - -static inline bool is_dimension_empty(ASR::dimension_t& dim) { - return ((dim.m_length == nullptr) || - (dim.m_start == nullptr)); -} - -static inline bool is_dimension_empty(ASR::dimension_t* dims, size_t n) { - for( size_t i = 0; i < n; i++ ) { - if( is_dimension_empty(dims[i]) ) { - return true; - } - } - return false; -} - -static inline void insert_module_dependency(ASR::symbol_t* a, - Allocator& al, Vec& module_dependencies) { - if( ASR::is_a(*a) ) { - ASR::ExternalSymbol_t* a_ext = ASR::down_cast(a); - ASR::symbol_t* a_sym_module = ASRUtils::get_asr_owner(a_ext->m_external); - if( a_sym_module ) { - while( a_sym_module && !ASR::is_a(*a_sym_module) ) { - a_sym_module = ASRUtils::get_asr_owner(a_sym_module); - } - if( a_sym_module && !LCompilers::present(module_dependencies, - ASRUtils::symbol_name(a_sym_module)) ) { - module_dependencies.push_back(al, ASRUtils::symbol_name(a_sym_module)); - } - } - } -} - -static inline ASR::ttype_t* get_type_parameter(ASR::ttype_t* t) { - switch (t->type) { - case ASR::ttypeType::TypeParameter: { - return t; - } - case ASR::ttypeType::List: { - ASR::List_t *tl = ASR::down_cast(t); - return get_type_parameter(tl->m_type); - } - default: throw LCompilersException("Cannot get type parameter from this type."); - } -} - -static inline ASR::symbol_t* import_struct_instance_member(Allocator& al, ASR::symbol_t* v, - SymbolTable* scope, ASR::ttype_t*& mem_type) { - v = ASRUtils::symbol_get_past_external(v); - ASR::symbol_t* struct_t = ASRUtils::get_asr_owner(v); - std::string v_name = ASRUtils::symbol_name(v); - std::string struct_t_name = ASRUtils::symbol_name(struct_t); - std::string struct_ext_name = struct_t_name; - if( scope->resolve_symbol(struct_t_name) != struct_t ) { - struct_ext_name = "1_" + struct_ext_name; - } - if( scope->resolve_symbol(struct_ext_name) == nullptr ) { - ASR::symbol_t* struct_t_module = ASRUtils::get_asr_owner( - ASRUtils::symbol_get_past_external(struct_t)); - LCOMPILERS_ASSERT(struct_t_module != nullptr); - SymbolTable* import_struct_t_scope = scope; - while( import_struct_t_scope->asr_owner == nullptr || - !ASR::is_a(*ASR::down_cast( - import_struct_t_scope->asr_owner)) ) { - import_struct_t_scope = import_struct_t_scope->parent; - if( import_struct_t_scope->asr_owner != nullptr && - !ASR::is_a(*import_struct_t_scope->asr_owner) ) { - break; - } - } - LCOMPILERS_ASSERT(import_struct_t_scope != nullptr); - ASR::symbol_t* struct_ext = ASR::down_cast(ASR::make_ExternalSymbol_t(al, - v->base.loc, import_struct_t_scope, s2c(al, struct_ext_name), struct_t, - ASRUtils::symbol_name(struct_t_module), - nullptr, 0, s2c(al, struct_t_name), ASR::accessType::Public)); - import_struct_t_scope->add_symbol(struct_ext_name, struct_ext); - } - std::string v_ext_name = "1_" + struct_t_name + "_" + v_name; - if( scope->get_symbol(v_ext_name) == nullptr ) { - ASR::symbol_t* v_ext = ASR::down_cast(ASR::make_ExternalSymbol_t(al, - v->base.loc, scope, s2c(al, v_ext_name), ASRUtils::symbol_get_past_external(v), - s2c(al, struct_ext_name), nullptr, 0, s2c(al, v_name), ASR::accessType::Public)); - scope->add_symbol(v_ext_name, v_ext); - } - - if( mem_type && ASR::is_a(*mem_type) ) { - ASR::Struct_t* struct_t = ASR::down_cast(mem_type); - std::string struct_type_name = ASRUtils::symbol_name(struct_t->m_derived_type); - ASR::symbol_t* struct_t_m_derived_type = ASRUtils::symbol_get_past_external(struct_t->m_derived_type); - if( scope->resolve_symbol(struct_type_name) == nullptr ) { - std::string struct_type_name_ = "1_" + struct_type_name; - if( scope->get_symbol(struct_type_name_) == nullptr ) { - ASR::Module_t* struct_type_module = ASRUtils::get_sym_module(struct_t_m_derived_type); - LCOMPILERS_ASSERT(struct_type_module != nullptr); - ASR::symbol_t* imported_struct_type = ASR::down_cast(ASR::make_ExternalSymbol_t(al, - v->base.loc, scope, s2c(al, struct_type_name_), struct_t_m_derived_type, struct_type_module->m_name, - nullptr, 0, s2c(al, struct_type_name), ASR::accessType::Public)); - scope->add_symbol(struct_type_name_, imported_struct_type); - } - mem_type = ASRUtils::TYPE(ASR::make_Struct_t(al, mem_type->base.loc, scope->get_symbol(struct_type_name_), - struct_t->m_dims, struct_t->n_dims)); - } else { - mem_type = ASRUtils::TYPE(ASR::make_Struct_t(al, mem_type->base.loc, - scope->resolve_symbol(struct_type_name), - struct_t->m_dims, struct_t->n_dims)); - } - } - return scope->get_symbol(v_ext_name); -} - -static inline ASR::symbol_t* import_enum_member(Allocator& al, ASR::symbol_t* v, - SymbolTable* scope) { - v = ASRUtils::symbol_get_past_external(v); - ASR::symbol_t* enum_t = ASRUtils::get_asr_owner(v); - std::string v_name = ASRUtils::symbol_name(v); - std::string enum_t_name = ASRUtils::symbol_name(enum_t); - std::string enum_ext_name = enum_t_name; - if( scope->resolve_symbol(enum_t_name) != enum_t ) { - enum_ext_name = "1_" + enum_ext_name; - } - if( scope->resolve_symbol(enum_ext_name) == nullptr ) { - ASR::symbol_t* enum_t_module = ASRUtils::get_asr_owner( - ASRUtils::symbol_get_past_external(enum_t)); - LCOMPILERS_ASSERT(enum_t_module != nullptr); - SymbolTable* import_enum_t_scope = scope; - while( import_enum_t_scope->asr_owner == nullptr || - !ASR::is_a(*ASR::down_cast( - import_enum_t_scope->asr_owner)) ) { - import_enum_t_scope = import_enum_t_scope->parent; - } - LCOMPILERS_ASSERT(import_enum_t_scope != nullptr); - ASR::symbol_t* enum_ext = ASR::down_cast(ASR::make_ExternalSymbol_t(al, - v->base.loc, import_enum_t_scope, s2c(al, enum_ext_name), enum_t, - ASRUtils::symbol_name(enum_t_module), - nullptr, 0, s2c(al, enum_t_name), ASR::accessType::Public)); - import_enum_t_scope->add_symbol(enum_ext_name, enum_ext); - } - std::string v_ext_name = "1_" + enum_t_name + "_" + v_name; - if( scope->get_symbol(v_ext_name) == nullptr ) { - ASR::symbol_t* v_ext = ASR::down_cast(ASR::make_ExternalSymbol_t(al, - v->base.loc, scope, s2c(al, v_ext_name), ASRUtils::symbol_get_past_external(v), - s2c(al, enum_ext_name), nullptr, 0, s2c(al, v_name), ASR::accessType::Public)); - scope->add_symbol(v_ext_name, v_ext); - } - - return scope->get_symbol(v_ext_name); -} - -class ReplaceArgVisitor: public ASR::BaseExprReplacer { - - private: - - Allocator& al; - - SymbolTable* current_scope; - - ASR::Function_t* orig_func; - - Vec& orig_args; - - std::set& current_function_dependencies; - - public: - - ReplaceArgVisitor(Allocator& al_, SymbolTable* current_scope_, - ASR::Function_t* orig_func_, Vec& orig_args_, - std::set& current_function_dependencies_) : - al(al_), current_scope(current_scope_), orig_func(orig_func_), - orig_args(orig_args_), current_function_dependencies(current_function_dependencies_) - {} - - void replace_FunctionCall(ASR::FunctionCall_t* x) { - ASR::symbol_t *new_es = x->m_name; - // Import a function as external only if necessary - ASR::Function_t *f = nullptr; - ASR::symbol_t* f_sym = nullptr; - if (ASR::is_a(*x->m_name)) { - f = ASR::down_cast(x->m_name); - } else if( ASR::is_a(*x->m_name) ) { - f_sym = ASRUtils::symbol_get_past_external(x->m_name); - if( ASR::is_a(*f_sym) ) { - f = ASR::down_cast(f_sym); - } - } - ASR::Module_t *m = ASR::down_cast2(f->m_symtab->parent->asr_owner); - char *modname = m->m_name; - ASR::symbol_t *maybe_f = current_scope->resolve_symbol(std::string(f->m_name)); - ASR::symbol_t* maybe_f_actual = nullptr; - std::string maybe_modname = ""; - if( maybe_f && ASR::is_a(*maybe_f) ) { - maybe_modname = ASR::down_cast(maybe_f)->m_module_name; - maybe_f_actual = ASRUtils::symbol_get_past_external(maybe_f); - } - // If the Function to be imported is already present - // then do not import. - if( maybe_modname == std::string(modname) && - f_sym == maybe_f_actual ) { - new_es = maybe_f; - } else { - // Import while assigning a new name to avoid conflicts - // For example, if someone is using `len` from a user - // define module then `get_unique_name` will avoid conflict - std::string unique_name = current_scope->get_unique_name(f->m_name); - Str s; s.from_str_view(unique_name); - char *unique_name_c = s.c_str(al); - LCOMPILERS_ASSERT(current_scope->get_symbol(unique_name) == nullptr); - new_es = ASR::down_cast(ASR::make_ExternalSymbol_t( - al, f->base.base.loc, - /* a_symtab */ current_scope, - /* a_name */ unique_name_c, - (ASR::symbol_t*)f, - modname, nullptr, 0, - f->m_name, - ASR::accessType::Private - )); - current_scope->add_symbol(unique_name, new_es); - } - // The following substitutes args from the current scope - for (size_t i = 0; i < x->n_args; i++) { - ASR::expr_t** current_expr_copy_ = current_expr; - current_expr = &(x->m_args[i].m_value); - replace_expr(x->m_args[i].m_value); - current_expr = current_expr_copy_; - } - switch( x->m_type->type ) { - case ASR::ttypeType::Character: { - ASR::Character_t* char_type = ASR::down_cast(x->m_type); - if( char_type->m_len_expr ) { - ASR::expr_t** current_expr_copy_ = current_expr; - current_expr = &(char_type->m_len_expr); - replace_expr(char_type->m_len_expr); - current_expr = current_expr_copy_; - } - break; - } - default: - break; - } - current_function_dependencies.insert(std::string(ASRUtils::symbol_name(new_es))); - x->m_name = new_es; - } - - void replace_Var(ASR::Var_t* x) { - size_t arg_idx = 0; - bool idx_found = false; - std::string arg_name = ASRUtils::symbol_name(x->m_v); - // Finds the index of the argument to be used for substitution - // Basically if we are calling maybe(string, ret_type=character(len=len(s))) - // where string is a variable in current scope and s is one of the arguments - // accepted by maybe i.e., maybe has a signature maybe(s). Then, we will - // replace s with string. So, the call would become, - // maybe(string, ret_type=character(len=len(string))) - for( size_t j = 0; j < orig_func->n_args && !idx_found; j++ ) { - if( ASR::is_a(*(orig_func->m_args[j])) ) { - std::string arg_name_2 = std::string(ASRUtils::symbol_name( - ASR::down_cast(orig_func->m_args[j])->m_v)); - arg_idx = j; - idx_found = arg_name_2 == arg_name; - } - } - if( idx_found ) { - LCOMPILERS_ASSERT(current_expr); - *current_expr = orig_args[arg_idx].m_value; - } - } - -}; - -class ExprStmtDuplicator: public ASR::BaseExprStmtDuplicator -{ - public: - - ExprStmtDuplicator(Allocator &al): BaseExprStmtDuplicator(al) {} - -}; - -class ReplaceReturnWithGotoVisitor: public ASR::BaseStmtReplacer { - - private: - - Allocator& al; - - uint64_t goto_label; - - public: - - ReplaceReturnWithGotoVisitor(Allocator& al_, uint64_t goto_label_) : - al(al_), goto_label(goto_label_) - {} - - void set_goto_label(uint64_t label) { - goto_label = label; - } - - void replace_Return(ASR::Return_t* x) { - *current_stmt = ASRUtils::STMT(ASR::make_GoTo_t(al, x->base.base.loc, goto_label, - s2c(al, "__" + std::to_string(goto_label)))); - has_replacement_happened = true; - } - -}; - -static inline bool present(Vec &v, const ASR::symbol_t* name) { - for (auto &a : v) { - if (a == name) { - return true; - } - } - return false; -} - -// Singleton LabelGenerator so that it generates -// unique labels for different statements, from -// wherever it is called (be it ASR passes, be it -// AST to ASR transition, etc). -class LabelGenerator { - private: - - static LabelGenerator *label_generator; - uint64_t unique_label; - std::map node2label; - - // Private constructor so that more than - // one object cannot be created by calling the - // constructor. - LabelGenerator() { - unique_label = 0; - } - - public: - - static LabelGenerator *get_instance() { - if (!label_generator) { - label_generator = new LabelGenerator; - } - return label_generator; - } - - int get_unique_label() { - unique_label += 1; - return unique_label; - } - - void add_node_with_unique_label(ASR::asr_t* node, uint64_t label) { - LCOMPILERS_ASSERT( node2label.find(node) == node2label.end() ); - node2label[node] = label; - } - - bool verify(ASR::asr_t* node) { - return node2label.find(node) != node2label.end(); - } -}; - -ASR::asr_t* make_Cast_t_value(Allocator &al, const Location &a_loc, - ASR::expr_t* a_arg, ASR::cast_kindType a_kind, ASR::ttype_t* a_type); - -static inline ASR::expr_t* compute_length_from_start_end(Allocator& al, ASR::expr_t* start, ASR::expr_t* end) { - ASR::expr_t* start_value = ASRUtils::expr_value(start); - ASR::expr_t* end_value = ASRUtils::expr_value(end); - - // If both start and end have compile time values - // then length can be computed easily by extracting - // compile time values of end and start. - if( start_value && end_value ) { - int64_t start_int = -1, end_int = -1; - ASRUtils::extract_value(start_value, start_int); - ASRUtils::extract_value(end_value, end_int); - return ASRUtils::EXPR(ASR::make_IntegerConstant_t(al, start->base.loc, - end_int - start_int + 1, - ASRUtils::expr_type(start))); - } - - // If start has a compile time value and - // end is a variable then length can be - // simplified by computing 1 - start as a constant - // and then analysing the end expression. - if( start_value && !end_value ) { - int64_t start_int = -1; - ASRUtils::extract_value(start_value, start_int); - int64_t remaining_portion = 1 - start_int; - - // If 1 - start is 0 then length is clearly the - // end expression. - if( remaining_portion == 0 ) { - return end; - } - - // If end is a binary expression of Add, Sub - // type. - if( ASR::is_a(*end) ) { - ASR::IntegerBinOp_t* end_binop = ASR::down_cast(end); - if( end_binop->m_op == ASR::binopType::Add || - end_binop->m_op == ASR::binopType::Sub) { - ASR::expr_t* end_left = end_binop->m_left; - ASR::expr_t* end_right = end_binop->m_right; - ASR::expr_t* end_leftv = ASRUtils::expr_value(end_left); - ASR::expr_t* end_rightv = ASRUtils::expr_value(end_right); - if( end_leftv ) { - // If left part of end is a compile time constant - // then it can be merged with 1 - start. - int64_t el_int = -1; - ASRUtils::extract_value(end_leftv, el_int); - remaining_portion += el_int; - - // If 1 - start + end_left is 0 - // and end is an addition operation - // then clearly end_right is the length. - if( remaining_portion == 0 && - end_binop->m_op == ASR::binopType::Add ) { - return end_right; - } - - // In all other cases the length would be (1 - start + end_left) endop end_right - // endop is the operation of end expression and 1 - start + end_left is a constant. - ASR::expr_t* remaining_expr = ASRUtils::EXPR(ASR::make_IntegerConstant_t(al, - end->base.loc, remaining_portion, - ASRUtils::expr_type(end))); - return ASRUtils::EXPR(ASR::make_IntegerBinOp_t(al, end->base.loc, remaining_expr, - end_binop->m_op, end_right, end_binop->m_type, end_binop->m_value)); - } else if( end_rightv ) { - // If right part of end is a compile time constant - // then it can be merged with 1 - start. The sign - // of end_right depends on the operation in - // end expression. - int64_t er_int = -1; - ASRUtils::extract_value(end_rightv, er_int); - if( end_binop->m_op == ASR::binopType::Sub ) { - er_int = -er_int; - } - remaining_portion += er_int; - - // If (1 - start endop end_right) is 0 - // then clearly end_left is the length expression. - if( remaining_portion == 0 ) { - return end_left; - } - - // Otherwise, length is end_left Add (1 - start endop end_right) - // where endop is the operation in end expression and - // (1 - start endop end_right) is a compile time constant. - ASR::expr_t* remaining_expr = ASRUtils::EXPR(ASR::make_IntegerConstant_t(al, - end->base.loc, remaining_portion, - ASRUtils::expr_type(end))); - return ASRUtils::EXPR(ASR::make_IntegerBinOp_t(al, end->base.loc, end_left, - ASR::binopType::Add, remaining_expr, end_binop->m_type, end_binop->m_value)); - } - } - } - - // If start is a variable and end is a compile time constant - // then compute (end + 1) as a constant and then return - // (end + 1) - start as the length expression. - if( !start_value && end_value ) { - int64_t end_int = -1; - ASRUtils::extract_value(end_value, end_int); - int64_t remaining_portion = end_int + 1; - ASR::expr_t* remaining_expr = ASRUtils::EXPR(ASR::make_IntegerConstant_t(al, - end->base.loc, remaining_portion, - ASRUtils::expr_type(end))); - return ASRUtils::EXPR(ASR::make_IntegerBinOp_t(al, end->base.loc, remaining_expr, - ASR::binopType::Sub, start, ASRUtils::expr_type(end), nullptr)); - } - - // For all the other cases - ASR::expr_t* remaining_expr = ASRUtils::EXPR(ASR::make_IntegerConstant_t(al, - end->base.loc, remaining_portion, - ASRUtils::expr_type(end))); - return ASRUtils::EXPR(ASR::make_IntegerBinOp_t(al, end->base.loc, end, - ASR::binopType::Add, remaining_expr, ASRUtils::expr_type(end), - nullptr)); - } - - ASR::expr_t* diff = ASRUtils::EXPR(ASR::make_IntegerBinOp_t(al, end->base.loc, end, - ASR::binopType::Sub, start, ASRUtils::expr_type(end), - nullptr)); - ASR::expr_t *constant_one = ASR::down_cast(ASR::make_IntegerConstant_t( - al, diff->base.loc, 1, ASRUtils::expr_type(diff))); - return ASRUtils::EXPR(ASR::make_IntegerBinOp_t(al, end->base.loc, diff, - ASR::binopType::Add, constant_one, ASRUtils::expr_type(end), - nullptr)); -} - -static inline bool is_pass_array_by_data_possible(ASR::Function_t* x, std::vector& v) { - if (ASRUtils::get_FunctionType(x)->m_abi == ASR::abiType::BindC && - ASRUtils::get_FunctionType(x)->m_deftype == ASR::deftypeType::Interface) { - return false; - } - - ASR::ttype_t* typei = nullptr; - ASR::dimension_t* dims = nullptr; - for( size_t i = 0; i < x->n_args; i++ ) { - if( !ASR::is_a(*x->m_args[i]) ) { - continue; - } - ASR::Var_t* arg_Var = ASR::down_cast(x->m_args[i]); - if( !ASR::is_a(*arg_Var->m_v) ) { - continue; - } - typei = ASRUtils::expr_type(x->m_args[i]); - int n_dims = ASRUtils::extract_dimensions_from_ttype(typei, dims); - ASR::Variable_t* argi = ASRUtils::EXPR2VAR(x->m_args[i]); - if( ASRUtils::is_dimension_empty(dims, n_dims) && - (argi->m_intent == ASRUtils::intent_in || - argi->m_intent == ASRUtils::intent_out) && - argi->m_storage != ASR::storage_typeType::Allocatable) { - v.push_back(i); - } - } - return v.size() > 0; -} - -inline ASR::asr_t* make_Function_t_util(Allocator& al, const Location& loc, - SymbolTable* m_symtab, char* m_name, char** m_dependencies, size_t n_dependencies, - ASR::expr_t** a_args, size_t n_args, ASR::stmt_t** m_body, size_t n_body, - ASR::expr_t* m_return_var, ASR::abiType m_abi, ASR::accessType m_access, - ASR::deftypeType m_deftype, char* m_bindc_name, bool m_elemental, bool m_pure, - bool m_module, bool m_inline, bool m_static, ASR::ttype_t** m_type_params, - size_t n_type_params, ASR::symbol_t** m_restrictions, size_t n_restrictions, - bool m_is_restriction, bool m_deterministic, bool m_side_effect_free) { - Vec arg_types; - arg_types.reserve(al, n_args); - for( size_t i = 0; i < n_args; i++ ) { - arg_types.push_back(al, ASRUtils::expr_type(a_args[i])); - } - ASR::ttype_t* return_var_type = nullptr; - if( m_return_var ) { - return_var_type = ASRUtils::expr_type(m_return_var); - } - ASR::ttype_t* func_type = ASRUtils::TYPE(ASR::make_FunctionType_t( - al, loc, arg_types.p, arg_types.size(), return_var_type, m_abi, - m_deftype, m_bindc_name, m_elemental, m_pure, m_module, m_inline, - m_static, m_type_params, n_type_params, m_restrictions, n_restrictions, - m_is_restriction)); - return ASR::make_Function_t( - al, loc, m_symtab, m_name, func_type, m_dependencies, n_dependencies, - a_args, n_args, m_body, n_body, m_return_var, m_access, m_deterministic, - m_side_effect_free); -} - -static inline ASR::expr_t* get_bound(ASR::expr_t* arr_expr, int dim, - std::string bound, Allocator& al) { - ASR::ttype_t* int32_type = ASRUtils::TYPE(ASR::make_Integer_t(al, arr_expr->base.loc, - 4, nullptr, 0)); - ASR::expr_t* dim_expr = ASRUtils::EXPR(ASR::make_IntegerConstant_t(al, arr_expr->base.loc, - dim, int32_type)); - ASR::arrayboundType bound_type = ASR::arrayboundType::LBound; - if( bound == "ubound" ) { - bound_type = ASR::arrayboundType::UBound; - } - return ASRUtils::EXPR(ASR::make_ArrayBound_t(al, arr_expr->base.loc, arr_expr, dim_expr, - int32_type, bound_type, nullptr)); -} - -static inline ASR::expr_t* get_size(ASR::expr_t* arr_expr, int dim, - Allocator& al) { - ASR::ttype_t* int32_type = ASRUtils::TYPE(ASR::make_Integer_t(al, arr_expr->base.loc, 4, nullptr, 0)); - ASR::expr_t* dim_expr = ASRUtils::EXPR(ASR::make_IntegerConstant_t(al, arr_expr->base.loc, dim, int32_type)); - return ASRUtils::EXPR(ASR::make_ArraySize_t(al, arr_expr->base.loc, arr_expr, dim_expr, - int32_type, nullptr)); -} - -static inline void get_dimensions(ASR::expr_t* array, Vec& dims, - Allocator& al) { - ASR::ttype_t* array_type = ASRUtils::expr_type(array); - ASR::dimension_t* compile_time_dims = nullptr; - int n_dims = extract_dimensions_from_ttype(array_type, compile_time_dims); - for( int i = 0; i < n_dims; i++ ) { - ASR::expr_t* start = compile_time_dims[i].m_start; - if( start == nullptr ) { - start = get_bound(array, i + 1, "lbound", al); - } - ASR::expr_t* length = compile_time_dims[i].m_length; - if( length == nullptr ) { - length = get_size(array, i + 1, al); - } - dims.push_back(al, start); - dims.push_back(al, length); - } -} - -static inline ASR::EnumType_t* get_EnumType_from_symbol(ASR::symbol_t* s) { - ASR::Variable_t* s_var = ASR::down_cast(s); - if( ASR::is_a(*s_var->m_type) ) { - ASR::Enum_t* enum_ = ASR::down_cast(s_var->m_type); - return ASR::down_cast(enum_->m_enum_type); - } - ASR::symbol_t* enum_type_cand = ASR::down_cast(s_var->m_parent_symtab->asr_owner); - LCOMPILERS_ASSERT(ASR::is_a(*enum_type_cand)); - return ASR::down_cast(enum_type_cand); -} - -static inline void set_enum_value_type(ASR::enumtypeType &enum_value_type, - SymbolTable *scope) { - int8_t IntegerConsecutiveFromZero = 1; - int8_t IntegerNotUnique = 0; - int8_t IntegerUnique = 1; - std::map value2count; - for( auto sym: scope->get_scope() ) { - ASR::Variable_t* member_var = ASR::down_cast(sym.second); - ASR::expr_t* value = ASRUtils::expr_value(member_var->m_symbolic_value); - int64_t value_int64 = -1; - ASRUtils::extract_value(value, value_int64); - if( value2count.find(value_int64) == value2count.end() ) { - value2count[value_int64] = 0; - } - value2count[value_int64] += 1; - } - int64_t prev = -1; - for( auto itr: value2count ) { - if( itr.second > 1 ) { - IntegerNotUnique = 1; - IntegerUnique = 0; - IntegerConsecutiveFromZero = 0; - break ; - } - if( itr.first - prev != 1 ) { - IntegerConsecutiveFromZero = 0; - } - prev = itr.first; - } - if( IntegerConsecutiveFromZero ) { - if( value2count.find(0) == value2count.end() ) { - IntegerConsecutiveFromZero = 0; - IntegerUnique = 1; - } else { - IntegerUnique = 0; - } - } - LCOMPILERS_ASSERT(IntegerConsecutiveFromZero + IntegerNotUnique + IntegerUnique == 1); - if( IntegerConsecutiveFromZero ) { - enum_value_type = ASR::enumtypeType::IntegerConsecutiveFromZero; - } else if( IntegerNotUnique ) { - enum_value_type = ASR::enumtypeType::IntegerNotUnique; - } else if( IntegerUnique ) { - enum_value_type = ASR::enumtypeType::IntegerUnique; - } -} - -class CollectIdentifiersFromASRExpression: public ASR::BaseWalkVisitor { - private: - - Allocator& al; - Vec& identifiers; - - public: - - CollectIdentifiersFromASRExpression(Allocator& al_, Vec& identifiers_) : - al(al_), identifiers(identifiers_) - {} - - void visit_Var(const ASR::Var_t& x) { - identifiers.push_back(al, ASRUtils::symbol_name(x.m_v)); - } -}; - -static inline void collect_variable_dependencies(Allocator& al, Vec& deps_vec, - ASR::ttype_t* type=nullptr, ASR::expr_t* init_expr=nullptr, - ASR::expr_t* value=nullptr) { - ASRUtils::CollectIdentifiersFromASRExpression collector(al, deps_vec); - if( init_expr ) { - collector.visit_expr(*init_expr); - } - if( value ) { - collector.visit_expr(*value); - } - if( type ) { - collector.visit_ttype(*type); - } -} - -} // namespace ASRUtils - -} // namespace LCompilers - -#endif // LFORTRAN_ASR_UTILS_H diff --git a/src/libasr/asr_verify.cpp b/src/libasr/asr_verify.cpp deleted file mode 100644 index ec71755e36..0000000000 --- a/src/libasr/asr_verify.cpp +++ /dev/null @@ -1,863 +0,0 @@ -#include -#include -#include -#include -#include - -namespace { - class VerifyAbort - { - }; -} - -namespace LCompilers { - -namespace ASR { - -using ASRUtils::symbol_name; -using ASRUtils::symbol_parent_symtab; - -bool valid_char(char c) { - if (c >= 'a' && c <= 'z') return true; - if (c >= 'A' && c <= 'Z') return true; - if (c >= '0' && c <= '9') return true; - if (c == '_') return true; - return false; -} - -bool valid_name(const char *s) { - if (s == nullptr) return false; - std::string name = s; - if (name.size() == 0) return false; - for (size_t i=0; i -{ -private: - // For checking correct parent symbtab relationship - SymbolTable *current_symtab; - bool check_external; - diag::Diagnostics &diagnostics; - - // For checking that all symtabs have a unique ID. - // We first walk all symtabs, and then we check that everything else - // points to them (i.e., that nothing points to some symbol table that - // is not part of this ASR). - std::map id_symtab_map; - std::vector function_dependencies; - std::vector module_dependencies; - std::vector variable_dependencies; - - std::set> const_assigned; - -public: - VerifyVisitor(bool check_external, diag::Diagnostics &diagnostics) : check_external{check_external}, - diagnostics{diagnostics} {} - - // Requires the condition `cond` to be true. Raise an exception otherwise. -#define require(cond, error_msg) require_impl((cond), (error_msg), x.base.base.loc) - void require_impl(bool cond, const std::string &error_msg, const Location &loc) { - if (!cond) { - diagnostics.message_label("ASR verify: " + error_msg, - {loc}, "failed here", - diag::Level::Error, diag::Stage::ASRVerify); - throw VerifyAbort(); - } - } - - // Returns true if the `symtab_ID` (sym->symtab->parent) is the current - // symbol table `symtab` or any of its parents *and* if the symbol in the - // symbol table is equal to `sym`. It returns false otherwise, such as in the - // case when the symtab is in a different module or if the `sym`'s symbol table - // does not actually contain it. - bool symtab_in_scope(const SymbolTable *symtab, const ASR::symbol_t *sym) { - unsigned int symtab_ID = symbol_parent_symtab(sym)->counter; - char *sym_name = symbol_name(sym); - const SymbolTable *s = symtab; - while (s != nullptr) { - if (s->counter == symtab_ID) { - ASR::symbol_t *sym2 = s->get_symbol(sym_name); - if (sym2) { - if (sym2 == sym) { - // The symbol table was found and the symbol `sym` is in - // it - return true; - } else { - // The symbol table was found and the symbol in it - // shares the name, but is not equal to `sym` - return false; - } - } else { - // The symbol table was found, but the symbol `sym` is not - // in it - return false; - } - } - s = s->parent; - } - // The symbol table was not found in the scope of `symtab`. - return false; - } - - void visit_TranslationUnit(const TranslationUnit_t &x) { - current_symtab = x.m_global_scope; - require(x.m_global_scope != nullptr, - "The TranslationUnit::m_global_scope cannot be nullptr"); - require(x.m_global_scope->parent == nullptr, - "The TranslationUnit::m_global_scope->parent must be nullptr"); - require(id_symtab_map.find(x.m_global_scope->counter) == id_symtab_map.end(), - "TranslationUnit::m_global_scope->counter must be unique"); - require(x.m_global_scope->asr_owner == (ASR::asr_t*)&x, - "The TranslationUnit::m_global_scope::asr_owner must point to itself"); - require(down_cast2(current_symtab->asr_owner)->m_global_scope == current_symtab, - "The asr_owner invariant failed"); - id_symtab_map[x.m_global_scope->counter] = x.m_global_scope; - for (auto &a : x.m_global_scope->get_scope()) { - this->visit_symbol(*a.second); - } - for (size_t i=0; i(*item) || is_a(*item), - "TranslationUnit::m_items must be either stmt or expr"); - if (is_a(*item)) { - this->visit_stmt(*down_cast(item)); - } else { - this->visit_expr(*down_cast(item)); - } - } - current_symtab = nullptr; - } - - // -------------------------------------------------------- - // symbol instances: - - void visit_Program(const Program_t &x) { - SymbolTable *parent_symtab = current_symtab; - current_symtab = x.m_symtab; - require(x.m_symtab != nullptr, - "The Program::m_symtab cannot be nullptr"); - require(x.m_symtab->parent == parent_symtab, - "The Program::m_symtab->parent is not the right parent"); - require(x.m_symtab->parent->parent == nullptr, - "The Program::m_symtab's parent must be TranslationUnit"); - require(id_symtab_map.find(x.m_symtab->counter) == id_symtab_map.end(), - "Program::m_symtab->counter must be unique"); - require(x.m_symtab->asr_owner == (ASR::asr_t*)&x, - "The X::m_symtab::asr_owner must point to X"); - require(ASRUtils::symbol_symtab(down_cast(current_symtab->asr_owner)) == current_symtab, - "The asr_owner invariant failed"); - id_symtab_map[x.m_symtab->counter] = x.m_symtab; - for (auto &a : x.m_symtab->get_scope()) { - this->visit_symbol(*a.second); - } - for (size_t i=0; iparent == parent_symtab, - "The AssociateBlock::m_symtab->parent is not the right parent"); - require(id_symtab_map.find(x.m_symtab->counter) == id_symtab_map.end(), - "AssociateBlock::m_symtab->counter must be unique"); - require(x.m_symtab->asr_owner == (ASR::asr_t*)&x, - "The X::m_symtab::asr_owner must point to X"); - require(ASRUtils::symbol_symtab(down_cast(current_symtab->asr_owner)) == current_symtab, - "The asr_owner invariant failed"); - id_symtab_map[x.m_symtab->counter] = x.m_symtab; - for (auto &a : x.m_symtab->get_scope()) { - this->visit_symbol(*a.second); - } - for (size_t i=0; iparent == parent_symtab, - "The AssociateBlock::m_symtab->parent is not the right parent"); - require(id_symtab_map.find(x.m_symtab->counter) == id_symtab_map.end(), - "AssociateBlock::m_symtab->counter must be unique"); - require(x.m_symtab->asr_owner == (ASR::asr_t*)&x, - "The X::m_symtab::asr_owner must point to X"); - require(ASRUtils::symbol_symtab(down_cast(current_symtab->asr_owner)) == current_symtab, - "The asr_owner invariant failed"); - id_symtab_map[x.m_symtab->counter] = x.m_symtab; - for (auto &a : x.m_symtab->get_scope()) { - this->visit_symbol(*a.second); - } - for (size_t i=0; i(x.m_m); - LCOMPILERS_ASSERT(block); // already checked above, just making sure - current_symtab = block->m_symtab; - for (size_t i=0; in_body; i++) { - visit_stmt(*(block->m_body[i])); - } - current_symtab = parent_symtab; - } - - void visit_Module(const Module_t &x) { - module_dependencies.clear(); - module_dependencies.reserve(x.n_dependencies); - SymbolTable *parent_symtab = current_symtab; - current_symtab = x.m_symtab; - require(x.m_symtab != nullptr, - "The Module::m_symtab cannot be nullptr"); - require(x.m_symtab->parent == parent_symtab, - "The Module::m_symtab->parent is not the right parent"); - require(x.m_symtab->parent->parent == nullptr, - "The Module::m_symtab's parent must be TranslationUnit"); - require(id_symtab_map.find(x.m_symtab->counter) == id_symtab_map.end(), - "Module::m_symtab->counter must be unique"); - require(x.m_symtab->asr_owner == (ASR::asr_t*)&x, - "The X::m_symtab::asr_owner must point to X"); - require(ASRUtils::symbol_symtab(down_cast(current_symtab->asr_owner)) == current_symtab, - "The asr_owner invariant failed"); - id_symtab_map[x.m_symtab->counter] = x.m_symtab; - for (auto &a : x.m_symtab->get_scope()) { - this->visit_symbol(*a.second); - } - for (size_t i=0; i < x.n_dependencies; i++) { - require(x.m_dependencies[i] != nullptr, - "A module dependency must not be a nullptr"); - require(std::string(x.m_dependencies[i]) != "", - "A module dependency must not be an empty string"); - require(valid_name(x.m_dependencies[i]), - "A module dependency must be a valid string"); - } - for( auto& dep: module_dependencies ) { - if( dep != x.m_name ) { - require(present(x.m_dependencies, x.n_dependencies, dep), - "Module " + std::string(x.m_name) + - " dependencies must contain " + dep + - " because a function present in it is getting called in " - + std::string(x.m_name) + "."); - } - } - current_symtab = parent_symtab; - } - - void visit_Assignment(const Assignment_t& x) { - ASR::expr_t* target = x.m_target; - if( ASR::is_a(*target) ) { - ASR::Var_t* target_Var = ASR::down_cast(target); - ASR::ttype_t* target_type = nullptr; - if( ASR::is_a(*target_Var->m_v) || - (ASR::is_a(*target_Var->m_v) && - ASR::down_cast(target_Var->m_v)->m_external) ) { - target_type = ASRUtils::expr_type(target); - } - if( target_type && ASR::is_a(*target_type) ) { - std::string variable_name = ASRUtils::symbol_name(target_Var->m_v); - require(const_assigned.find(std::make_pair(current_symtab->counter, - variable_name)) == const_assigned.end(), - "Assignment target with " + ASRUtils::type_to_str_python(target_type) - + " cannot be re-assigned."); - const_assigned.insert(std::make_pair(current_symtab->counter, variable_name)); - } - } - BaseWalkVisitor::visit_Assignment(x); - } - - void visit_ClassProcedure(const ClassProcedure_t &x) { - require(x.m_name != nullptr, - "The ClassProcedure::m_name cannot be nullptr"); - require(x.m_proc != nullptr, - "The ClassProcedure::m_proc cannot be nullptr"); - require(x.m_proc_name != nullptr, - "The ClassProcedure::m_proc_name cannot be nullptr"); - - SymbolTable *symtab = x.m_parent_symtab; - require(symtab != nullptr, - "ClassProcedure::m_parent_symtab cannot be nullptr"); - require(symtab->get_symbol(std::string(x.m_name)) != nullptr, - "ClassProcedure '" + std::string(x.m_name) + "' not found in parent_symtab symbol table"); - symbol_t *symtab_sym = symtab->get_symbol(std::string(x.m_name)); - const symbol_t *current_sym = &x.base; - require(symtab_sym == current_sym, - "ClassProcedure's parent symbol table does not point to it"); - require(id_symtab_map.find(symtab->counter) != id_symtab_map.end(), - "ClassProcedure::m_parent_symtab must be present in the ASR (" - + std::string(x.m_name) + ")"); - - ASR::Function_t* x_m_proc = ASR::down_cast(x.m_proc); - if( x.m_self_argument ) { - bool arg_found = false; - std::string self_arg_name = std::string(x.m_self_argument); - for( size_t i = 0; i < x_m_proc->n_args; i++ ) { - std::string arg_name = std::string(ASRUtils::symbol_name( - ASR::down_cast(x_m_proc->m_args[i])->m_v)); - if( self_arg_name == arg_name ) { - arg_found = true; - break ; - } - } - require(arg_found, self_arg_name + " must be present in " + - std::string(x.m_name) + " procedures."); - } - } - - void visit_Function(const Function_t &x) { - std::vector function_dependencies_copy = function_dependencies; - function_dependencies.clear(); - function_dependencies.reserve(x.n_dependencies); - SymbolTable *parent_symtab = current_symtab; - current_symtab = x.m_symtab; - require(x.m_symtab != nullptr, - "The Function::m_symtab cannot be nullptr"); - require(x.m_symtab->parent == parent_symtab, - "The Function::m_symtab->parent is not the right parent"); - require(x.m_symtab->asr_owner == (ASR::asr_t*)&x, - "The X::m_symtab::asr_owner must point to X"); - require(id_symtab_map.find(x.m_symtab->counter) == id_symtab_map.end(), - "Function::m_symtab->counter must be unique"); - require(ASRUtils::symbol_symtab(down_cast(current_symtab->asr_owner)) == current_symtab, - "The asr_owner invariant failed"); - id_symtab_map[x.m_symtab->counter] = x.m_symtab; - for (auto &a : x.m_symtab->get_scope()) { - this->visit_symbol(*a.second); - } - for (size_t i=0; i - void visit_UserDefinedType(const T &x) { - SymbolTable *parent_symtab = current_symtab; - current_symtab = x.m_symtab; - require(x.m_symtab != nullptr, - "The StructType::m_symtab cannot be nullptr"); - require(x.m_symtab->parent == parent_symtab, - "The StructType::m_symtab->parent is not the right parent"); - require(x.m_symtab->asr_owner == (ASR::asr_t*)&x, - "The X::m_symtab::asr_owner must point to X"); - require(id_symtab_map.find(x.m_symtab->counter) == id_symtab_map.end(), - "StructType::m_symtab->counter must be unique"); - require(ASRUtils::symbol_symtab(down_cast(current_symtab->asr_owner)) == current_symtab, - "The asr_owner invariant failed"); - id_symtab_map[x.m_symtab->counter] = x.m_symtab; - std::vector struct_dependencies; - for (auto &a : x.m_symtab->get_scope()) { - this->visit_symbol(*a.second); - if( ASR::is_a(*a.second) || - ASR::is_a(*a.second) || - ASR::is_a(*a.second) || - ASR::is_a(*a.second) || - ASR::is_a(*a.second) || - ASR::is_a(*a.second) ) { - continue ; - } - ASR::ttype_t* var_type = ASRUtils::type_get_past_pointer(ASRUtils::symbol_type(a.second)); - char* aggregate_type_name = nullptr; - ASR::symbol_t* sym = nullptr; - if( ASR::is_a(*var_type) ) { - sym = ASR::down_cast(var_type)->m_derived_type; - aggregate_type_name = ASRUtils::symbol_name(sym); - } else if( ASR::is_a(*var_type) ) { - sym = ASR::down_cast(var_type)->m_enum_type; - aggregate_type_name = ASRUtils::symbol_name(sym); - } else if( ASR::is_a(*var_type) ) { - sym = ASR::down_cast(var_type)->m_union_type; - aggregate_type_name = ASRUtils::symbol_name(sym); - } else if( ASR::is_a(*var_type) ) { - sym = ASR::down_cast(var_type)->m_class_type; - aggregate_type_name = ASRUtils::symbol_name(sym); - } - if( aggregate_type_name && ASRUtils::symbol_parent_symtab(sym) != current_symtab ) { - struct_dependencies.push_back(std::string(aggregate_type_name)); - require(present(x.m_dependencies, x.n_dependencies, std::string(aggregate_type_name)), - std::string(x.m_name) + " depends on " + std::string(aggregate_type_name) - + " but it isn't found in its dependency list."); - } - } - for( size_t i = 0; i < x.n_dependencies; i++ ) { - require(std::find(struct_dependencies.begin(), struct_dependencies.end(), - std::string(x.m_dependencies[i])) != struct_dependencies.end(), - std::string(x.m_dependencies[i]) + " is not a dependency of " + std::string(x.m_name) - + " but it is present in its dependency list."); - } - current_symtab = parent_symtab; - } - - void visit_StructType(const StructType_t& x) { - visit_UserDefinedType(x); - if( !x.m_alignment ) { - return ; - } - ASR::expr_t* aligned_expr_value = ASRUtils::expr_value(x.m_alignment); - std::string msg = "Alignment should always evaluate to a constant expressions."; - require(aligned_expr_value, msg); - int64_t alignment_int; - require(ASRUtils::extract_value(aligned_expr_value, alignment_int), msg); - require(alignment_int != 0 && (alignment_int & (alignment_int - 1)) == 0, - "Alignment " + std::to_string(alignment_int) + - " is not a positive power of 2."); - } - - void visit_EnumType(const EnumType_t& x) { - visit_UserDefinedType(x); - require(x.m_type != nullptr, - "The common type of Enum cannot be nullptr. " + - std::string(x.m_name) + " doesn't seem to follow this rule."); - ASR::ttype_t* common_type = x.m_type; - std::map value2count; - for( auto itr: x.m_symtab->get_scope() ) { - ASR::Variable_t* itr_var = ASR::down_cast(itr.second); - require(itr_var->m_symbolic_value != nullptr, - "All members of Enum must have their values to be set. " + - std::string(itr_var->m_name) + " doesn't seem to follow this rule in " - + std::string(x.m_name) + " Enum."); - require(ASRUtils::check_equal_type(itr_var->m_type, common_type), - "All members of Enum must the same type. " + - std::string(itr_var->m_name) + " doesn't seem to follow this rule in " + - std::string(x.m_name) + " Enum."); - ASR::expr_t* value = ASRUtils::expr_value(itr_var->m_symbolic_value); - int64_t value_int64 = -1; - ASRUtils::extract_value(value, value_int64); - if( value2count.find(value_int64) == value2count.end() ) { - value2count[value_int64] = 0; - } - value2count[value_int64] += 1; - } - - bool is_enumtype_correct = false; - bool is_enum_integer = ASR::is_a(*x.m_type); - if( x.m_enum_value_type == ASR::enumtypeType::IntegerConsecutiveFromZero ) { - is_enumtype_correct = (is_enum_integer && - (value2count.find(0) != value2count.end()) && - (value2count.size() == x.n_members)); - int64_t prev = -1; - if( is_enumtype_correct ) { - for( auto enum_value: value2count ) { - if( enum_value.first - prev != 1 ) { - is_enumtype_correct = false; - break ; - } - prev = enum_value.first; - } - } - } else if( x.m_enum_value_type == ASR::enumtypeType::IntegerNotUnique ) { - is_enumtype_correct = is_enum_integer && (value2count.size() != x.n_members); - } else if( x.m_enum_value_type == ASR::enumtypeType::IntegerUnique ) { - is_enumtype_correct = is_enum_integer && (value2count.size() == x.n_members); - } else if( x.m_enum_value_type == ASR::enumtypeType::NonInteger ) { - is_enumtype_correct = !is_enum_integer; - } - require(is_enumtype_correct, "Properties of enum value members don't match correspond " - "to EnumType::m_enum_value_type"); - } - - void visit_UnionType(const UnionType_t& x) { - visit_UserDefinedType(x); - } - - void visit_Variable(const Variable_t &x) { - variable_dependencies.clear(); - SymbolTable *symtab = x.m_parent_symtab; - require(symtab != nullptr, - "Variable::m_parent_symtab cannot be nullptr"); - require(symtab->get_symbol(std::string(x.m_name)) != nullptr, - "Variable '" + std::string(x.m_name) + "' not found in parent_symtab symbol table"); - symbol_t *symtab_sym = symtab->get_symbol(std::string(x.m_name)); - const symbol_t *current_sym = &x.base; - require(symtab_sym == current_sym, - "Variable's parent symbol table does not point to it"); - require(id_symtab_map.find(symtab->counter) != id_symtab_map.end(), - "Variable::m_parent_symtab must be present in the ASR (" - + std::string(x.m_name) + ")"); - - if (x.m_symbolic_value) - visit_expr(*x.m_symbolic_value); - visit_ttype(*x.m_type); - - // Verify dependencies - for( size_t i = 0; i < x.n_dependencies; i++ ) { - require(std::find( - variable_dependencies.begin(), - variable_dependencies.end(), - std::string(x.m_dependencies[i]) - ) != variable_dependencies.end(), - "Variable " + std::string(x.m_name) + " doesn't depend on " + - std::string(x.m_dependencies[i]) + " but is found in its dependency list."); - } - - for( size_t i = 0; i < variable_dependencies.size(); i++ ) { - require(present(x.m_dependencies, x.n_dependencies, variable_dependencies[i]), - "Variable " + std::string(x.m_name) + " depends on " + - std::string(variable_dependencies[i]) + " but isn't found in its dependency list."); - } - } - - void visit_ExternalSymbol(const ExternalSymbol_t &x) { - if (check_external) { - require(x.m_external != nullptr, - "ExternalSymbol::m_external cannot be nullptr"); - require(!is_a(*x.m_external), - "ExternalSymbol::m_external cannot be an ExternalSymbol"); - char *orig_name = symbol_name(x.m_external); - require(std::string(x.m_original_name) == std::string(orig_name), - "ExternalSymbol::m_original_name must match external->m_name"); - ASR::Module_t *m = ASRUtils::get_sym_module(x.m_external); - ASR::StructType_t* sm = nullptr; - ASR::EnumType_t* em = nullptr; - bool is_valid_owner = false; - is_valid_owner = m != nullptr && ((ASR::symbol_t*) m == ASRUtils::get_asr_owner(x.m_external)); - std::string asr_owner_name = ""; - if( !is_valid_owner ) { - ASR::symbol_t* asr_owner_sym = ASRUtils::get_asr_owner(x.m_external); - is_valid_owner = (ASR::is_a(*asr_owner_sym) || - ASR::is_a(*asr_owner_sym)); - if( ASR::is_a(*asr_owner_sym) ) { - sm = ASR::down_cast(asr_owner_sym); - asr_owner_name = sm->m_name; - } else if( ASR::is_a(*asr_owner_sym) ) { - em = ASR::down_cast(asr_owner_sym); - asr_owner_name = em->m_name; - } - } else { - asr_owner_name = m->m_name; - } - std::string x_m_module_name = x.m_module_name; - if( current_symtab->resolve_symbol(x.m_module_name) ) { - x_m_module_name = ASRUtils::symbol_name( - ASRUtils::symbol_get_past_external( - current_symtab->resolve_symbol(x.m_module_name))); - } - require(is_valid_owner, - "ExternalSymbol::m_external is not in a module or struct type"); - require(x_m_module_name == asr_owner_name, - "ExternalSymbol::m_module_name `" + x_m_module_name - + "` must match external's module name `" + asr_owner_name + "`"); - ASR::symbol_t *s = nullptr; - if( m != nullptr && ((ASR::symbol_t*) m == ASRUtils::get_asr_owner(x.m_external)) ) { - s = m->m_symtab->find_scoped_symbol(x.m_original_name, x.n_scope_names, x.m_scope_names); - } else if( sm ) { - s = sm->m_symtab->resolve_symbol(std::string(x.m_original_name)); - } else if( em ) { - s = em->m_symtab->resolve_symbol(std::string(x.m_original_name)); - } - require(s != nullptr, - "ExternalSymbol::m_original_name ('" - + std::string(x.m_original_name) - + "') + scope_names not found in a module '" - + asr_owner_name + "'"); - require(s == x.m_external, - "ExternalSymbol::m_name + scope_names found but not equal to m_external"); - } - } - - // -------------------------------------------------------- - // nodes that have symbol in their fields: - - void visit_Var(const Var_t &x) { - require(x.m_v != nullptr, - "Var_t::m_v cannot be nullptr"); - std::string x_mv_name = ASRUtils::symbol_name(x.m_v); - require(is_a(*x.m_v) || is_a(*x.m_v) - || is_a(*x.m_v) || is_a(*x.m_v), - "Var_t::m_v " + x_mv_name + " does not point to a Variable_t, ExternalSymbol_t, " \ - "Function_t, Subroutine_t or EnumType_t"); - bool var_present_in_enum = false; - { - int i = 1; - std::string enum_name = "_nameless_enum"; - while (!var_present_in_enum && current_symtab->resolve_symbol( - std::to_string(i) + enum_name) != nullptr) { - ASR::symbol_t *enum_s = current_symtab->resolve_symbol( - std::to_string(i) + enum_name); - var_present_in_enum = symtab_in_scope(ASR::down_cast< - ASR::EnumType_t>(enum_s)->m_symtab, x.m_v); - i ++; - } - } - require(symtab_in_scope(current_symtab, x.m_v) || var_present_in_enum, - "Var::m_v `" + x_mv_name + "` cannot point outside of its symbol table"); - variable_dependencies.push_back(x_mv_name); - } - - void check_var_external(const ASR::expr_t &x) { - if (ASR::is_a(x)) { - ASR::symbol_t *s = ((ASR::Var_t*)&x)->m_v; - if (ASR::is_a(*s)) { - ASR::ExternalSymbol_t *e = ASR::down_cast(s); - require_impl(e->m_external, "m_external cannot be null here", - x.base.loc); - } - } - } - - template - void handle_ArrayItemSection(const T &x) { - visit_expr(*x.m_v); - for (size_t i=0; i(*x.m_type) && n_dims == 0) { - // TODO: This seems like a bug, we should not use ArrayItem with - // strings but StringItem. For now we ignore it, but we should - // fix it - } else { - require(n_dims > 0, - "The variable in ArrayItem must be an array, not a scalar"); - } - } - } - - void visit_ArrayItem(const ArrayItem_t &x) { - handle_ArrayItemSection(x); - } - - void visit_ArraySection(const ArraySection_t &x) { - handle_ArrayItemSection(x); - } - - template - void verify_args(const T& x) { - ASR::symbol_t* func_sym = ASRUtils::symbol_get_past_external(x.m_name); - ASR::Function_t* func = nullptr; - if( func_sym && ASR::is_a(*func_sym) ) { - func = ASR::down_cast(func_sym); - } - - if( func ) { - for (size_t i=0; i(func->m_args[i])->m_v; - if (x.m_args[i].m_value == nullptr && - (ASR::is_a(*arg_sym) && - ASR::down_cast(arg_sym)->m_presence != - ASR::presenceType::Optional)) { - - require(false, "Required argument " + - std::string(ASRUtils::symbol_name(arg_sym)) + - " cannot be nullptr."); - - } - } - } - - for (size_t i=0; i(*s) || - ASR::is_a(*s), - "SubroutineCall::m_name '" + std::string(symbol_name(x.m_name)) + "' must be a Function or ClassProcedure."); - } - - function_dependencies.push_back(std::string(ASRUtils::symbol_name(x.m_name))); - if( ASR::is_a(*x.m_name) ) { - ASR::ExternalSymbol_t* x_m_name = ASR::down_cast(x.m_name); - if( x_m_name->m_external && ASR::is_a(*ASRUtils::get_asr_owner(x_m_name->m_external)) ) { - module_dependencies.push_back(std::string(x_m_name->m_module_name)); - } - } - - verify_args(x); - } - - SymbolTable *get_dt_symtab(ASR::symbol_t *dt) { - LCOMPILERS_ASSERT(dt) - SymbolTable *symtab = ASRUtils::symbol_symtab(ASRUtils::symbol_get_past_external(dt)); - require_impl(symtab, - "m_dt::m_v::m_type::class/derived_type must point to a symbol with a symbol table", - dt->base.loc); - return symtab; - } - - SymbolTable *get_dt_symtab(ASR::expr_t *dt) { - ASR::ttype_t *t2 = ASRUtils::type_get_past_pointer(ASRUtils::expr_type(dt)); - ASR::symbol_t *type_sym=nullptr; - switch (t2->type) { - case (ASR::ttypeType::Struct): { - type_sym = ASR::down_cast(t2)->m_derived_type; - break; - } - case (ASR::ttypeType::Class): { - type_sym = ASR::down_cast(t2)->m_class_type; - break; - } - default : - require_impl(false, - "m_dt::m_v::m_type must point to a type with a symbol table (Struct or Class)", - dt->base.loc); - } - return get_dt_symtab(type_sym); - } - - ASR::symbol_t *get_parent_type_dt(ASR::symbol_t *dt) { - ASR::symbol_t *parent = nullptr; - switch (dt->type) { - case (ASR::symbolType::StructType): { - dt = ASRUtils::symbol_get_past_external(dt); - ASR::StructType_t* der_type = ASR::down_cast(dt); - parent = der_type->m_parent; - break; - } - default : - require_impl(false, - "m_dt::m_v::m_type must point to a Struct type", - dt->base.loc); - } - return parent; - } - - ASR::symbol_t *get_parent_type_dt(ASR::expr_t *dt) { - ASR::ttype_t *t2 = ASRUtils::type_get_past_pointer(ASRUtils::expr_type(dt)); - ASR::symbol_t *type_sym=nullptr; - ASR::symbol_t *parent = nullptr; - switch (t2->type) { - case (ASR::ttypeType::Struct): { - type_sym = ASR::down_cast(t2)->m_derived_type; - type_sym = ASRUtils::symbol_get_past_external(type_sym); - ASR::StructType_t* der_type = ASR::down_cast(type_sym); - parent = der_type->m_parent; - break; - } - case (ASR::ttypeType::Class): { - type_sym = ASR::down_cast(t2)->m_class_type; - type_sym = ASRUtils::symbol_get_past_external(type_sym); - if( type_sym->type == ASR::symbolType::StructType ) { - ASR::StructType_t* der_type = ASR::down_cast(type_sym); - parent = der_type->m_parent; - } - break; - } - default : - require_impl(false, - "m_dt::m_v::m_type must point to a Struct type", - dt->base.loc); - } - return parent; - } - - void visit_PointerNullConstant(const PointerNullConstant_t& x) { - require(x.m_type != nullptr, "null() must have a type"); - } - - void visit_FunctionCall(const FunctionCall_t &x) { - require(x.m_name, - "FunctionCall::m_name must be present"); - function_dependencies.push_back(std::string(ASRUtils::symbol_name(x.m_name))); - if( ASR::is_a(*x.m_name) ) { - ASR::ExternalSymbol_t* x_m_name = ASR::down_cast(x.m_name); - if( x_m_name->m_external && ASR::is_a(*ASRUtils::get_asr_owner(x_m_name->m_external)) ) { - module_dependencies.push_back(std::string(x_m_name->m_module_name)); - } - } - - require(symtab_in_scope(current_symtab, x.m_name), - "FunctionCall::m_name `" + std::string(symbol_name(x.m_name)) + - "` cannot point outside of its symbol table"); - // Check both `name` and `orig_name` that `orig_name` points - // to GenericProcedure (if applicable), both external and non - // external - if (check_external) { - const ASR::symbol_t *fn = ASRUtils::symbol_get_past_external(x.m_name); - require(ASR::is_a(*fn) || - (ASR::is_a(*fn) && - ASR::is_a(*ASRUtils::symbol_type(fn))) || - ASR::is_a(*fn), - "FunctionCall::m_name must be a Function or Variable with FunctionType"); - } - - verify_args(x); - visit_ttype(*x.m_type); - } - - void visit_Struct(const Struct_t &x) { - require(symtab_in_scope(current_symtab, x.m_derived_type), - "Struct::m_derived_type cannot point outside of its symbol table"); - for (size_t i=0; i - -namespace LCompilers { - - // Verifies that ASR is correctly constructed and contains valid Fortran - // code and passes all our requirements on ASR, such as: - // - // * All types and kinds are correctly inferred and implicit casting - // nodes are correctly inserted in expressions - // * Types match for function / subroutine calls - // * All symbols in the Symbol Table correctly link back to it or the - // parent table. - // * All Fortran rules will be checked eventually, such as: - // * Initializer expression only uses intrinsic functions - // * Any function used in array dimension declaration is pure - // * Pure function only calls pure functions - // * ... - // - // This should not replace correct semantic checking in ast2asr. This is - // only meant as a tool for LCompilers developers to check there are no bugs - // in LCompilers code that constructs ASR and that some requirement was not - // accidentally broken. - // This should not be called in Release mode for performance reasons, but - // it should be called in our tests to ensure ast2asr, deserialization, all - // the ASR passes and any other code that constructs ASR does not have - // bugs. - // Any code that takes ASR as an argument can assume that it is verified. - // Such as the LLVM, C++ backend, or any ASR pass, or pickle. - - // The function will raise an exception if there is an error. Otherwise - // it will return true. It can be used in Debug mode only as: - // - // LCOMPILERS_ASSERT(asr_verify(*asr)); - // - bool asr_verify(const ASR::TranslationUnit_t &unit, - bool check_external, diag::Diagnostics &diagnostics); - -} // namespace LCompilers - -#endif // LFORTRAN_ASR_VERIFY_H diff --git a/src/libasr/assert.h b/src/libasr/assert.h deleted file mode 100644 index dd628fbbbd..0000000000 --- a/src/libasr/assert.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef LFORTRAN_ASSERT_H -#define LFORTRAN_ASSERT_H - -// LCOMPILERS_ASSERT uses internal functions to perform as assert -// so that there is no effect with NDEBUG -#include -#include -#if defined(WITH_LFORTRAN_ASSERT) - -#include - -#if !defined(LCOMPILERS_ASSERT) -#define stringize(s) #s -#define XSTR(s) stringize(s) -#if defined(HAVE_LFORTRAN_STACKTRACE) -#define LCOMPILERS_ASSERT(cond) \ - { \ - if (!(cond)) { \ - throw LCompilers::AssertFailed(XSTR(cond)); \ - } \ - } -#else -#define LCOMPILERS_ASSERT(cond) \ - { \ - if (!(cond)) { \ - std::cerr << "LCOMPILERS_ASSERT failed: " << __FILE__ \ - << "\nfunction " << __func__ << "(), line number " \ - << __LINE__ << " at \n" \ - << XSTR(cond) << "\n"; \ - abort(); \ - } \ - } -#endif // defined(HAVE_LFORTRAN_STACKTRACE) -#endif // !defined(LCOMPILERS_ASSERT) - -#if !defined(LCOMPILERS_ASSERT_MSG) -#define LCOMPILERS_ASSERT_MSG(cond, msg) \ - { \ - if (!(cond)) { \ - std::cerr << "LCOMPILERS_ASSERT failed: " << __FILE__ \ - << "\nfunction " << __func__ << "(), line number " \ - << __LINE__ << " at \n" \ - << XSTR(cond) << "\n" \ - << "ERROR MESSAGE:\n" \ - << msg << "\n"; \ - abort(); \ - } \ - } -#endif // !defined(LCOMPILERS_ASSERT_MSG) - -#else // defined(WITH_LFORTRAN_ASSERT) - -#define LCOMPILERS_ASSERT(cond) -#define LCOMPILERS_ASSERT_MSG(cond, msg) - -#endif // defined(WITH_LFORTRAN_ASSERT) - -#define LFORTRAN_ERROR(description) \ - std::cerr << description; \ - std::cerr << "\n"; \ - abort(); - -#endif // LFORTRAN_ASSERT_H diff --git a/src/libasr/bigint.h b/src/libasr/bigint.h deleted file mode 100644 index a299dffe9e..0000000000 --- a/src/libasr/bigint.h +++ /dev/null @@ -1,174 +0,0 @@ -#ifndef LFORTRAN_BIGINT_H -#define LFORTRAN_BIGINT_H - -#include - -#include - -namespace LCompilers { - -namespace BigInt { - -/* - * Arbitrary size integer implementation. - * - * We use tagged signed 64bit integers with no padding bits and using 2's - * complement for negative values (int64_t) as the underlying data structure. - * Little-endian is assumed. - * - * Bits (from the left): - * 1 ..... sign: 0 positive, 1 negative - * 2 ..... tag: bits 1-2 equal to 01: pointer; otherwise integer - * 3-64 .. if the tag is - integer: rest of the signed integer bits in 2's - * complement - * - pointer: 64 bit pointer shifted by 2 - * to the right (>> 2) - * - * The pointer must be aligned to 4 bytes (bits 63-64 must be 00). - * Small signed integers are represented directly as integers in int64_t, large - * integers are allocated on heap and a pointer to it is used as "tag pointer" - * in int64_t. - * - * To check if the integer has a pointer tag, we check that the first two bits - * (1-2) are equal to 01. - * - * If the first bit is 0, then it can either be a positive integer or a - * pointer. We check the second bit, if it is 1, then it is a pointer (shifted - * by 2), if it is 0, then is is a positive integer, represented by the rest of - * the 62 bits. If the first bit is 1, then it is a negative integer, - * represented by the full 64 bits in 2's complement representation. - */ - -// Returns true if "i" is a pointer and false if "i" is an integer -inline static bool is_int_ptr(int64_t i) { - return (((uint64_t)i) >> (64 - 2)) == 1; -} - -/* - * A pointer is converted to integer by shifting by 2 to the right and adding - * 01 to the first two bits to tag it as a pointer: - */ - -// Converts a pointer "p" (must be aligned to 4 bytes) to a tagged int64_t -inline static int64_t ptr_to_int(void *p) { - return (int64_t)( (((uint64_t)p) >> 2) | (1ULL << (64 - 2)) ); -} - -/* An integer with the pointer tag is converted to a pointer by shifting by 2 - * to the left, which erases the tag and puts 00 to bits 63-64: - */ - -// Converts a tagged int64_t to a pointer (aligned to 4 bytes) -inline static void* int_to_ptr(int64_t i) { - return (void *)(((uint64_t)i) << 2); -} - -/* The maximum small int is 2^62-1 - */ -const int64_t MAX_SMALL_INT = (int64_t)((1ULL << 62)-1); - -/* The minimum small int is -2^63 - */ -const int64_t MIN_SMALL_INT = (int64_t)(-(1ULL << 63)); - -// Returns true if "i" is a small int -inline static bool is_small_int(int64_t i) { - return (MIN_SMALL_INT <= i && i <= MAX_SMALL_INT); -} - -/* Arbitrary integer implementation - * For now large integers are implemented as strings with decimal digits. The - * only supported operation on this is converting to and from a string. Later - * we will replace with an actual large integer implementation and add other - * operations. - */ - -// Converts a string to a large int (allocated on heap, returns a pointer) -inline static int64_t string_to_largeint(Allocator &al, const Str &s) { - char *cs = s.c_str(al); - return ptr_to_int(cs); -} - -// Converts a large int to a string -inline static char* largeint_to_string(int64_t i) { - LCOMPILERS_ASSERT(is_int_ptr(i)); - void *p = int_to_ptr(i); - char *cs = (char*)p; - return cs; -} - -inline static std::string int_to_str(int64_t i) { - if (is_int_ptr(i)) { - return std::string(largeint_to_string(i)); - } else { - return std::to_string(i); - } -} - -inline static bool is_int64(std::string str_repr) { - std::string str_int64 = "9223372036854775807"; - if( str_repr.size() > str_int64.size() ) { - return false; - } - - if( str_repr.size() < str_int64.size() ) { - return true; - } - - size_t i; - for( i = 0; i < str_repr.size() - 1 && str_repr[i] == str_int64[i]; i++ ) { - } - return i == str_repr.size() - 1 || str_repr[i] < str_int64[i]; -} - -/* BigInt is a thin wrapper over the functionality exposed in the functions - * above. The idea is that one can use the int64_t type directly and just use - * the function above to handle the large integer aspects, and if it is a small - * integer, one can use it directly as int64 integer. - * - * Alternatively, one can use the BigInt class below that exposes the - * functionality via methods. - */ - -struct BigInt { - int64_t n; - - BigInt() = default; - BigInt(const BigInt &) = default; - BigInt& operator=(const BigInt &) = default; - - void from_smallint(int64_t i) { - LCOMPILERS_ASSERT(is_small_int(i)); - n = i; - } - - void from_largeint(Allocator &al, const Str &s) { - n = string_to_largeint(al, s); - } - - bool is_large() const { - return is_int_ptr(n); - } - - int64_t as_smallint() const { - LCOMPILERS_ASSERT(!is_large()); - return n; - } - - std::string str() const { - return int_to_str(n); - } - -}; - -static_assert(std::is_standard_layout::value); -static_assert(std::is_trivial::value); -static_assert(sizeof(BigInt) == sizeof(int64_t)); -static_assert(sizeof(BigInt) == 8); - - -} // BigInt - -} // namespace LCompilers - -#endif // LFORTRAN_BIGINT_H diff --git a/src/libasr/bwriter.h b/src/libasr/bwriter.h deleted file mode 100644 index 0fc924af44..0000000000 --- a/src/libasr/bwriter.h +++ /dev/null @@ -1,257 +0,0 @@ -#ifndef LFORTRAN_BWRITER_H -#define LFORTRAN_BWRITER_H - -#include -#include - -#include - -namespace LCompilers { - -std::string static inline uint32_to_string(uint32_t i) { - char bytes[4]; - bytes[0] = (i >> 24) & 0xFF; - bytes[1] = (i >> 16) & 0xFF; - bytes[2] = (i >> 8) & 0xFF; - bytes[3] = i & 0xFF; - return std::string(bytes, 4); -} - -std::string static inline uint64_to_string(uint64_t i) { - char bytes[8]; - bytes[0] = (i >> 56) & 0xFF; - bytes[1] = (i >> 48) & 0xFF; - bytes[2] = (i >> 40) & 0xFF; - bytes[3] = (i >> 32) & 0xFF; - bytes[4] = (i >> 24) & 0xFF; - bytes[5] = (i >> 16) & 0xFF; - bytes[6] = (i >> 8) & 0xFF; - bytes[7] = i & 0xFF; - return std::string(bytes, 8); -} - -uint32_t static inline string_to_uint32(const char *s) { - // The cast from signed char to unsigned char is important, - // otherwise the signed char shifts return wrong value for negative numbers - const uint8_t *p = (const unsigned char*)s; - return (((uint32_t)p[0]) << 24) | - (((uint32_t)p[1]) << 16) | - (((uint32_t)p[2]) << 8) | - p[3]; -} - -uint64_t static inline string_to_uint64(const char *s) { - // The cast from signed char to unsigned char is important, - // otherwise the signed char shifts return wrong value for negative numbers - const uint8_t *p = (const unsigned char*)s; - return (((uint64_t)p[0]) << 56) | - (((uint64_t)p[1]) << 48) | - (((uint64_t)p[2]) << 40) | - (((uint64_t)p[3]) << 32) | - (((uint64_t)p[4]) << 24) | - (((uint64_t)p[5]) << 16) | - (((uint64_t)p[6]) << 8) | - p[7]; -} - -uint32_t static inline string_to_uint32(const std::string &s) { - return string_to_uint32(&s[0]); -} - -uint64_t static inline string_to_uint64(const std::string &s) { - return string_to_uint64(&s[0]); -} - -// BinaryReader / BinaryWriter encapsulate access to the file by providing -// primitives that other classes just use. -class BinaryWriter -{ -private: - std::string s; -public: - std::string get_str() { - return s; - } - - void write_int8(uint8_t i) { - char c=i; - s.append(std::string(&c, 1)); - } - - void write_int32(uint32_t i) { - s.append(uint32_to_string(i)); - } - - void write_int64(uint64_t i) { - s.append(uint64_to_string(i)); - } - - void write_string(const std::string &t) { - write_int64(t.size()); - s.append(t); - } - - void write_float64(double d) { - void *p = &d; - uint64_t *ip = (uint64_t*)p; - write_int64(*ip); - } - -}; - -class BinaryReader -{ -private: - std::string s; - size_t pos; -public: - BinaryReader(const std::string &s) : s{s}, pos{0} {} - - uint8_t read_int8() { - if (pos+1 > s.size()) { - throw LCompilersException("read_int8: String is too short for deserialization."); - } - uint8_t n = s[pos]; - pos += 1; - return n; - } - - uint32_t read_int32() { - if (pos+4 > s.size()) { - throw LCompilersException("read_int32: String is too short for deserialization."); - } - uint32_t n = string_to_uint32(&s[pos]); - pos += 4; - return n; - } - - uint64_t read_int64() { - if (pos+8 > s.size()) { - throw LCompilersException("read_int64: String is too short for deserialization."); - } - uint64_t n = string_to_uint64(&s[pos]); - pos += 8; - return n; - } - - std::string read_string() { - size_t n = read_int64(); - if (pos+n > s.size()) { - throw LCompilersException("read_string: String is too short for deserialization."); - } - std::string r = std::string(&s[pos], n); - pos += n; - return r; - } - - double read_float64() { - uint64_t x = read_int64(); - uint64_t *ip = &x; - void *p = ip; - double *dp = (double*)p; - return *dp; - } -}; - -// TextReader / TextWriter encapsulate access to the file by providing -// primitives that other classes just use. The file is a human readable -// text file. These classes are useful for debugging. -class TextWriter -{ -private: - std::string s; -public: - std::string get_str() { - return s; - } - - void write_int8(uint8_t i) { - s.append(std::to_string(i)); - s += " "; - } - - void write_int64(uint64_t i) { - s.append(std::to_string(i)); - s += " "; - } - - void write_string(const std::string &t) { - write_int64(t.size()); - s.append(t); - s += " "; - } - - void write_float64(double d) { - std::stringstream str; - str << std::fixed << std::setprecision(17) << d; - s.append(str.str()); - s += " "; - } -}; - -class TextReader -{ -private: - std::string s; - size_t pos; -public: - TextReader(const std::string &s) : s{s}, pos{0} {} - - uint8_t read_int8() { - uint64_t n = read_int64(); - if (n < 255) { - return n; - } else { - throw LCompilersException("read_int8: Integer too large to fit 8 bits."); - } - } - - uint64_t read_int64() { - std::string tmp; - while (s[pos] != ' ') { - tmp += s[pos]; - if (! (s[pos] >= '0' && s[pos] <= '9')) { - throw LCompilersException("read_int64: Expected integer, got `" + tmp + "`"); - } - pos++; - if (pos >= s.size()) { - throw LCompilersException("read_int64: String is too short for deserialization."); - } - } - pos++; - uint64_t n = std::stoull(tmp); - return n; - } - - double read_float64() { - std::string tmp; - while (s[pos] != ' ') { - tmp += s[pos]; - pos++; - if (pos >= s.size()) { - throw LCompilersException("read_float64: String is too short for deserialization."); - } - } - pos++; - double n = std::stod(tmp); - return n; - } - - std::string read_string() { - size_t n = read_int64(); - if (pos+n > s.size()) { - throw LCompilersException("read_string: String is too short for deserialization."); - } - std::string r = std::string(&s[pos], n); - pos += n; - if (s[pos] != ' ') { - throw LCompilersException("read_string: Space expected."); - } - pos ++; - return r; - } -}; - -} // namespace LCompilers - -#endif // LFORTRAN_BWRITER_H diff --git a/src/libasr/codegen/KaleidoscopeJIT.h b/src/libasr/codegen/KaleidoscopeJIT.h deleted file mode 100644 index 1fe7a057e0..0000000000 --- a/src/libasr/codegen/KaleidoscopeJIT.h +++ /dev/null @@ -1,110 +0,0 @@ -//===- KaleidoscopeJIT.h - A simple JIT for Kaleidoscope --------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Contains a simple JIT definition for use in the kaleidoscope tutorials. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H -#define LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H - -#include "llvm/ADT/StringRef.h" -#include "llvm/ExecutionEngine/JITSymbol.h" -#include "llvm/ExecutionEngine/Orc/CompileUtils.h" -#include "llvm/ExecutionEngine/Orc/Core.h" -#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" -#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" -#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" -#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" -#include "llvm/ExecutionEngine/SectionMemoryManager.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/LLVMContext.h" -#include - -namespace llvm { -namespace orc { - -class KaleidoscopeJIT { -private: - ExecutionSession ES; - RTDyldObjectLinkingLayer ObjectLayer; - IRCompileLayer CompileLayer; - - DataLayout DL; - MangleAndInterner Mangle; - ThreadSafeContext Ctx; - JITDylib &JITDL; - - TargetMachine *TM; - -public: - KaleidoscopeJIT(JITTargetMachineBuilder JTMB, DataLayout DL) - : -#if LLVM_VERSION_MAJOR >= 13 - ES(cantFail(SelfExecutorProcessControl::Create())), -#endif - ObjectLayer(ES, - []() { return std::make_unique(); }), - CompileLayer(ES, ObjectLayer, std::make_unique(ConcurrentIRCompiler(std::move(JTMB)))), - DL(std::move(DL)), Mangle(ES, this->DL), - Ctx(std::make_unique()), - JITDL( -#if LLVM_VERSION_MAJOR >= 11 - cantFail -#endif - (ES.createJITDylib("Main"))) { - JITDL.addGenerator( - cantFail(DynamicLibrarySearchGenerator::GetForCurrentProcess( - DL.getGlobalPrefix()))); - - std::string Error; - auto TargetTriple = sys::getDefaultTargetTriple(); - auto Target = TargetRegistry::lookupTarget(TargetTriple, Error); - if (!Target) { - throw std::runtime_error("Failed to lookup the target"); - } - auto CPU = "generic"; - auto Features = ""; - TargetOptions opt; - auto RM = Optional(); - TM = Target->createTargetMachine(TargetTriple, CPU, Features, opt, RM); - } - - static Expected> Create() { - auto JTMB = JITTargetMachineBuilder::detectHost(); - - if (!JTMB) - return JTMB.takeError(); - - auto DL = JTMB->getDefaultDataLayoutForTarget(); - if (!DL) - return DL.takeError(); - - return std::make_unique(std::move(*JTMB), std::move(*DL)); - } - - const DataLayout &getDataLayout() const { return DL; } - - LLVMContext &getContext() { return *Ctx.getContext(); } - - Error addModule(std::unique_ptr M) { - return CompileLayer.add(JITDL, - ThreadSafeModule(std::move(M), Ctx)); - } - - Expected lookup(StringRef Name) { - return ES.lookup({&JITDL}, Mangle(Name.str())); - } - - TargetMachine &getTargetMachine() { return *TM; } -}; - -} // end namespace orc -} // end namespace llvm - -#endif // LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H diff --git a/src/libasr/codegen/asr_to_c.cpp b/src/libasr/codegen/asr_to_c.cpp deleted file mode 100644 index b5a15f637e..0000000000 --- a/src/libasr/codegen/asr_to_c.cpp +++ /dev/null @@ -1,1315 +0,0 @@ -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define CHECK_FAST_C(compiler_options, x) \ - if (compiler_options.fast && x.m_value != nullptr) { \ - visit_expr(*x.m_value); \ - return; \ - } \ - -namespace LCompilers { - -class ASRToCVisitor : public BaseCCPPVisitor -{ -public: - - std::string array_types_decls; - - std::unique_ptr c_utils_functions; - - int counter; - - ASRToCVisitor(diag::Diagnostics &diag, CompilerOptions &co, - int64_t default_lower_bound) - : BaseCCPPVisitor(diag, co.platform, co, false, false, true, default_lower_bound), - array_types_decls(std::string("\nstruct dimension_descriptor\n" - "{\n int32_t lower_bound, length;\n};\n")), - c_utils_functions{std::make_unique()}, - counter{0} { - } - - std::string convert_dims_c(size_t n_dims, ASR::dimension_t *m_dims, - ASR::ttype_t* element_type, bool& is_fixed_size, - bool convert_to_1d=false) - { - std::string dims = ""; - size_t size = 1; - std::string array_size = ""; - for (size_t i=0; iget_array_type(type_name, encoded_type_name, array_types_decls); - std::string type_name_without_ptr = c_ds_api->get_array_type(type_name, encoded_type_name, array_types_decls, false); - if( declare_value ) { - std::string variable_name = std::string(v_m_name) + "_value"; - sub = format_type_c("", type_name_without_ptr, variable_name, use_ref, dummy) + ";\n"; - sub += indent + format_type_c("", type_name, v_m_name, use_ref, dummy); - sub += " = &" + variable_name; - if( !is_pointer ) { - sub += ";\n"; - if( !is_fixed_size ) { - sub += indent + format_type_c("*", type_name_copy, std::string(v_m_name) + "_data", - use_ref, dummy); - if( dims.size() > 0 ) { - sub += " = " + dims + ";\n"; - } else { - sub += ";\n"; - } - } else { - sub += indent + format_type_c(dims, type_name_copy, std::string(v_m_name) + "_data", - use_ref, dummy) + ";\n"; - } - sub += indent + std::string(v_m_name) + "->data = " + std::string(v_m_name) + "_data;\n"; - sub += indent + std::string(v_m_name) + "->n_dims = " + std::to_string(n_dims) + ";\n"; - for (int i = 0; i < n_dims; i++) { - if( m_dims[i].m_start ) { - this->visit_expr(*m_dims[i].m_start); - sub += indent + std::string(v_m_name) + - "->dims[" + std::to_string(i) + "].lower_bound = " + src + ";\n"; - } else { - sub += indent + std::string(v_m_name) + - "->dims[" + std::to_string(i) + "].lower_bound = 0" + ";\n"; - } - if( m_dims[i].m_length ) { - this->visit_expr(*m_dims[i].m_length); - sub += indent + std::string(v_m_name) + - "->dims[" + std::to_string(i) + "].length = " + src + ";\n"; - } else { - sub += indent + std::string(v_m_name) + - "->dims[" + std::to_string(i) + "].length = 0" + ";\n"; - } - } - sub.pop_back(); - sub.pop_back(); - } - } else { - if( m_abi == ASR::abiType::BindC ) { - sub = format_type_c("", type_name_copy, v_m_name + "[]", use_ref, dummy); - } else { - sub = format_type_c("", type_name, v_m_name, use_ref, dummy); - } - } - } - - void allocate_array_members_of_struct(ASR::StructType_t* der_type_t, std::string& sub, - std::string indent, std::string name) { - for( auto itr: der_type_t->m_symtab->get_scope() ) { - if( ASR::is_a(*itr.second) || - ASR::is_a(*itr.second) ) { - continue ; - } - ASR::ttype_t* mem_type = ASRUtils::symbol_type(itr.second); - if( ASRUtils::is_character(*mem_type) ) { - sub += indent + name + "->" + itr.first + " = NULL;\n"; - } else if( ASRUtils::is_array(mem_type) && - ASR::is_a(*itr.second) ) { - ASR::Variable_t* mem_var = ASR::down_cast(itr.second); - std::string mem_var_name = current_scope->get_unique_name(itr.first + std::to_string(counter)); - counter += 1; - ASR::dimension_t* m_dims = nullptr; - size_t n_dims = ASRUtils::extract_dimensions_from_ttype(mem_type, m_dims); - CDeclarationOptions c_decl_options_; - c_decl_options_.pre_initialise_derived_type = true; - c_decl_options_.use_ptr_for_derived_type = true; - c_decl_options_.use_static = true; - c_decl_options_.force_declare = true; - c_decl_options_.force_declare_name = mem_var_name; - sub += indent + convert_variable_decl(*mem_var, &c_decl_options_) + ";\n"; - if( !ASRUtils::is_fixed_size_array(m_dims, n_dims) ) { - sub += indent + name + "->" + itr.first + " = " + mem_var_name + ";\n"; - } - } else if( ASR::is_a(*mem_type) ) { - ASR::Struct_t* struct_t = ASR::down_cast(mem_type); - ASR::StructType_t* struct_type_t = ASR::down_cast( - ASRUtils::symbol_get_past_external(struct_t->m_derived_type)); - allocate_array_members_of_struct(struct_type_t, sub, indent, "(&(" + name + "->" + itr.first + "))"); - } - } - } - - std::string convert_variable_decl(const ASR::Variable_t &v, - DeclarationOptions* decl_options=nullptr) - { - bool pre_initialise_derived_type; - bool use_ptr_for_derived_type; - bool use_static; - bool force_declare; - std::string force_declare_name; - bool declare_as_constant; - std::string const_name; - - if( decl_options ) { - CDeclarationOptions* c_decl_options = reinterpret_cast(decl_options); - pre_initialise_derived_type = c_decl_options->pre_initialise_derived_type; - use_ptr_for_derived_type = c_decl_options->use_ptr_for_derived_type; - use_static = c_decl_options->use_static; - force_declare = c_decl_options->force_declare; - force_declare_name = c_decl_options->force_declare_name; - declare_as_constant = c_decl_options->declare_as_constant; - const_name = c_decl_options->const_name; - } else { - pre_initialise_derived_type = true; - use_ptr_for_derived_type = true; - use_static = true; - force_declare = false; - force_declare_name = ""; - declare_as_constant = false; - const_name = ""; - } - std::string sub; - bool use_ref = (v.m_intent == ASRUtils::intent_out || - v.m_intent == ASRUtils::intent_inout); - bool is_array = ASRUtils::is_array(v.m_type); - bool dummy = ASRUtils::is_arg_dummy(v.m_intent); - ASR::ttype_t* v_m_type = v.m_type; - if (ASR::is_a(*v_m_type)) { - if( is_array ) { - v_m_type = ASR::down_cast(v_m_type)->m_type; - } - } - if (ASRUtils::is_pointer(v_m_type)) { - ASR::ttype_t *t2 = ASR::down_cast(v_m_type)->m_type; - if (ASRUtils::is_integer(*t2)) { - ASR::Integer_t *t = ASR::down_cast(t2); - std::string type_name = "int" + std::to_string(t->m_kind * 8) + "_t"; - if( !ASRUtils::is_array(v_m_type) ) { - type_name.append(" *"); - } - if( is_array ) { - bool is_fixed_size = true; - std::string dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size, true); - std::string encoded_type_name = "i" + std::to_string(t->m_kind * 8); - generate_array_decl(sub, std::string(v.m_name), type_name, dims, - encoded_type_name, t->m_dims, t->n_dims, - use_ref, dummy, - v.m_intent != ASRUtils::intent_in && - v.m_intent != ASRUtils::intent_inout && - v.m_intent != ASRUtils::intent_out, is_fixed_size, true); - } else { - bool is_fixed_size = true; - std::string dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size); - sub = format_type_c(dims, type_name, v.m_name, use_ref, dummy); - } - } else if(ASR::is_a(*t2)) { - ASR::Struct_t *t = ASR::down_cast(t2); - std::string der_type_name = ASRUtils::symbol_name(t->m_derived_type); - if( is_array ) { - bool is_fixed_size = true; - std::string dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size, true); - std::string encoded_type_name = "x" + der_type_name; - std::string type_name = std::string("struct ") + der_type_name; - generate_array_decl(sub, std::string(v.m_name), type_name, dims, - encoded_type_name, t->m_dims, t->n_dims, - use_ref, dummy, - v.m_intent != ASRUtils::intent_in && - v.m_intent != ASRUtils::intent_inout, - is_fixed_size); - } else { - std::string ptr_char = "*"; - if( !use_ptr_for_derived_type ) { - ptr_char.clear(); - } - sub = format_type_c("", "struct " + der_type_name + ptr_char, - v.m_name, use_ref, dummy); - } - } else if(ASR::is_a(*t2)) { - sub = format_type_c("", "void**", v.m_name, false, false); - } else { - diag.codegen_error_label("Type number '" - + std::to_string(v_m_type->type) - + "' not supported", {v.base.base.loc}, ""); - throw Abort(); - } - } else { - std::string dims; - use_ref = use_ref && !is_array; - if (ASRUtils::is_integer(*v_m_type)) { - headers.insert("inttypes"); - ASR::Integer_t *t = ASR::down_cast(v_m_type); - std::string type_name = "int" + std::to_string(t->m_kind * 8) + "_t"; - if( is_array ) { - bool is_fixed_size = true; - dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size, true); - bool is_struct_type_member = ASR::is_a( - *ASR::down_cast(v.m_parent_symtab->asr_owner)); - if( is_fixed_size && is_struct_type_member ) { - if( !force_declare ) { - force_declare_name = std::string(v.m_name); - } - sub = type_name + " " + force_declare_name + dims; - } else { - std::string encoded_type_name = "i" + std::to_string(t->m_kind * 8); - if( !force_declare ) { - force_declare_name = std::string(v.m_name); - } - generate_array_decl(sub, force_declare_name, type_name, dims, - encoded_type_name, t->m_dims, t->n_dims, - use_ref, dummy, - (v.m_intent != ASRUtils::intent_in && - v.m_intent != ASRUtils::intent_inout && - v.m_intent != ASRUtils::intent_out && - !is_struct_type_member) || force_declare, - is_fixed_size, false, v.m_abi); - } - } else { - bool is_fixed_size = true; - std::string v_m_name = v.m_name; - if( declare_as_constant ) { - type_name = "const " + type_name; - v_m_name = const_name; - } - dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size); - sub = format_type_c(dims, type_name, v_m_name, use_ref, dummy); - } - } else if (ASRUtils::is_real(*v_m_type)) { - ASR::Real_t *t = ASR::down_cast(v_m_type); - std::string type_name = "float"; - if (t->m_kind == 8) type_name = "double"; - if( is_array ) { - bool is_fixed_size = true; - dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size, true); - bool is_struct_type_member = ASR::is_a( - *ASR::down_cast(v.m_parent_symtab->asr_owner)); - if( is_fixed_size && is_struct_type_member ) { - if( !force_declare ) { - force_declare_name = std::string(v.m_name); - } - sub = type_name + " " + force_declare_name + dims; - } else { - std::string encoded_type_name = "r" + std::to_string(t->m_kind * 8); - if( !force_declare ) { - force_declare_name = std::string(v.m_name); - } - generate_array_decl(sub, force_declare_name, type_name, dims, - encoded_type_name, t->m_dims, t->n_dims, - use_ref, dummy, - (v.m_intent != ASRUtils::intent_in && - v.m_intent != ASRUtils::intent_inout && - v.m_intent != ASRUtils::intent_out && - !is_struct_type_member) || force_declare, is_fixed_size); - } - } else { - bool is_fixed_size = true; - std::string v_m_name = v.m_name; - if( declare_as_constant ) { - type_name = "const " + type_name; - v_m_name = const_name; - } - dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size); - sub = format_type_c(dims, type_name, v_m_name, use_ref, dummy); - } - } else if (ASRUtils::is_complex(*v_m_type)) { - headers.insert("complex"); - ASR::Complex_t *t = ASR::down_cast(v_m_type); - std::string type_name = "float complex"; - if (t->m_kind == 8) type_name = "double complex"; - if( is_array ) { - bool is_fixed_size = true; - dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size, true); - bool is_struct_type_member = ASR::is_a( - *ASR::down_cast(v.m_parent_symtab->asr_owner)); - if( is_fixed_size && is_struct_type_member ) { - if( !force_declare ) { - force_declare_name = std::string(v.m_name); - } - sub = type_name + " " + force_declare_name + dims; - } else { - std::string encoded_type_name = "c" + std::to_string(t->m_kind * 8); - if( !force_declare ) { - force_declare_name = std::string(v.m_name); - } - generate_array_decl(sub, force_declare_name, type_name, dims, - encoded_type_name, t->m_dims, t->n_dims, - use_ref, dummy, - (v.m_intent != ASRUtils::intent_in && - v.m_intent != ASRUtils::intent_inout && - v.m_intent != ASRUtils::intent_out && - !is_struct_type_member) || force_declare, is_fixed_size); - } - } else { - bool is_fixed_size = true; - std::string v_m_name = v.m_name; - if( declare_as_constant ) { - type_name = "const " + type_name; - v_m_name = const_name; - } - dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size); - sub = format_type_c(dims, type_name, v_m_name, use_ref, dummy); - } - } else if (ASRUtils::is_logical(*v_m_type)) { - ASR::Logical_t *t = ASR::down_cast(v_m_type); - bool is_fixed_size = true; - dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size); - sub = format_type_c(dims, "bool", v.m_name, use_ref, dummy); - } else if (ASRUtils::is_character(*v_m_type)) { - ASR::Character_t *t = ASR::down_cast(v_m_type); - bool is_fixed_size = true; - std::string dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size); - sub = format_type_c(dims, "char *", v.m_name, use_ref, dummy); - if( v.m_intent == ASRUtils::intent_local && - !(ASR::is_a(*v.m_parent_symtab->asr_owner) && - ASR::is_a( - *ASR::down_cast(v.m_parent_symtab->asr_owner))) ) { - sub += " = NULL"; - return sub; - } - } else if (ASR::is_a(*v_m_type)) { - std::string indent(indentation_level*indentation_spaces, ' '); - ASR::Struct_t *t = ASR::down_cast(v_m_type); - std::string der_type_name = ASRUtils::symbol_name(t->m_derived_type); - if( is_array ) { - bool is_fixed_size = true; - dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size, true); - std::string encoded_type_name = "x" + der_type_name; - std::string type_name = std::string("struct ") + der_type_name; - generate_array_decl(sub, std::string(v.m_name), type_name, dims, - encoded_type_name, t->m_dims, t->n_dims, - use_ref, dummy, - v.m_intent != ASRUtils::intent_in && - v.m_intent != ASRUtils::intent_inout, - is_fixed_size); - } else if( v.m_intent == ASRUtils::intent_local && pre_initialise_derived_type) { - bool is_fixed_size = true; - dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size); - std::string value_var_name = v.m_parent_symtab->get_unique_name(std::string(v.m_name) + "_value"); - sub = format_type_c(dims, "struct " + der_type_name, - value_var_name, use_ref, dummy); - if (v.m_symbolic_value) { - this->visit_expr(*v.m_symbolic_value); - std::string init = src; - sub += "=" + init; - } - sub += ";\n"; - std::string ptr_char = "*"; - if( !use_ptr_for_derived_type ) { - ptr_char.clear(); - } - sub += indent + format_type_c("", "struct " + der_type_name + ptr_char, v.m_name, use_ref, dummy); - if( t->n_dims != 0 ) { - sub += " = " + value_var_name; - } else { - sub += " = &" + value_var_name + ";\n"; - ASR::StructType_t* der_type_t = ASR::down_cast( - ASRUtils::symbol_get_past_external(t->m_derived_type)); - allocate_array_members_of_struct(der_type_t, sub, indent, std::string(v.m_name)); - sub.pop_back(); - sub.pop_back(); - } - return sub; - } else { - bool is_fixed_size = true; - dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size); - if( v.m_intent == ASRUtils::intent_in || - v.m_intent == ASRUtils::intent_inout || - v.m_intent == ASRUtils::intent_out ) { - use_ref = false; - dims = ""; - } - std::string ptr_char = "*"; - if( !use_ptr_for_derived_type ) { - ptr_char.clear(); - } - sub = format_type_c(dims, "struct " + der_type_name + ptr_char, - v.m_name, use_ref, dummy); - } - } else if (ASR::is_a(*v_m_type)) { - std::string indent(indentation_level*indentation_spaces, ' '); - ASR::Union_t *t = ASR::down_cast(v_m_type); - std::string der_type_name = ASRUtils::symbol_name( - ASRUtils::symbol_get_past_external(t->m_union_type)); - if( is_array ) { - bool is_fixed_size = true; - dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size, true); - std::string encoded_type_name = "x" + der_type_name; - std::string type_name = std::string("union ") + der_type_name; - generate_array_decl(sub, std::string(v.m_name), type_name, dims, - encoded_type_name, t->m_dims, t->n_dims, - use_ref, dummy, - v.m_intent != ASRUtils::intent_in && - v.m_intent != ASRUtils::intent_inout, is_fixed_size); - } else { - bool is_fixed_size = true; - dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size); - if( v.m_intent == ASRUtils::intent_in || - v.m_intent == ASRUtils::intent_inout ) { - use_ref = false; - dims = ""; - } - sub = format_type_c(dims, "union " + der_type_name, - v.m_name, use_ref, dummy); - } - } else if (ASR::is_a(*v_m_type)) { - ASR::List_t* t = ASR::down_cast(v_m_type); - std::string list_type_c = c_ds_api->get_list_type(t); - sub = format_type_c("", list_type_c, v.m_name, - false, false); - } else if (ASR::is_a(*v_m_type)) { - ASR::Tuple_t* t = ASR::down_cast(v_m_type); - std::string tuple_type_c = c_ds_api->get_tuple_type(t); - sub = format_type_c("", tuple_type_c, v.m_name, - false, false); - } else if (ASR::is_a(*v_m_type)) { - ASR::Dict_t* t = ASR::down_cast(v_m_type); - std::string dict_type_c = c_ds_api->get_dict_type(t); - sub = format_type_c("", dict_type_c, v.m_name, - false, false); - } else if (ASR::is_a(*v_m_type)) { - sub = format_type_c("", "void*", v.m_name, false, false); - } else if (ASR::is_a(*v_m_type)) { - ASR::Enum_t* enum_ = ASR::down_cast(v_m_type); - ASR::EnumType_t* enum_type = ASR::down_cast(enum_->m_enum_type); - sub = format_type_c("", "enum " + std::string(enum_type->m_name), v.m_name, false, false); - } else if (ASR::is_a(*v_m_type)) { - if( v.m_intent == ASRUtils::intent_local ) { - LCOMPILERS_ASSERT(v.m_symbolic_value); - visit_expr(*v.m_symbolic_value); - sub = "#define " + std::string(v.m_name) + " " + src + "\n"; - return sub; - } else { - std::string const_underlying_type = CUtils::get_c_type_from_ttype_t( - ASR::down_cast(v_m_type)->m_type); - sub = format_type_c("", "const " + const_underlying_type + " ", - v.m_name, false, false); - } - } else if (ASR::is_a(*v_m_type)) { - // Ignore type variables - return ""; - } else { - diag.codegen_error_label("Type number '" - + std::to_string(v_m_type->type) - + "' not supported", {v.base.base.loc}, ""); - throw Abort(); - } - if (dims.size() == 0 && v.m_storage == ASR::storage_typeType::Save && use_static) { - sub = "static " + sub; - } - if (dims.size() == 0 && v.m_symbolic_value) { - ASR::expr_t* init_expr = v.m_symbolic_value; - if( !ASR::is_a(*v.m_type) ) { - for( size_t i = 0; i < v.n_dependencies; i++ ) { - std::string variable_name = v.m_dependencies[i]; - ASR::symbol_t* dep_sym = current_scope->resolve_symbol(variable_name); - if( (dep_sym && ASR::is_a(*dep_sym) && - !ASR::down_cast(dep_sym)->m_symbolic_value) ) { - init_expr = nullptr; - break; - } - } - } - if( init_expr ) { - this->visit_expr(*init_expr); - std::string init = src; - sub += " = " + init; - } - } - } - return sub; - } - - - void visit_TranslationUnit(const ASR::TranslationUnit_t &x) { - is_string_concat_present = false; - global_scope = x.m_global_scope; - // All loose statements must be converted to a function, so the items - // must be empty: - LCOMPILERS_ASSERT(x.n_items == 0); - std::string unit_src = ""; - indentation_level = 0; - indentation_spaces = 4; - c_ds_api->set_indentation(indentation_level, indentation_spaces); - c_ds_api->set_global_scope(global_scope); - c_utils_functions->set_indentation(indentation_level, indentation_spaces); - c_utils_functions->set_global_scope(global_scope); - c_ds_api->set_c_utils_functions(c_utils_functions.get()); - - std::string head = -R"( -#include -#include -#include -#include -#include - -#define ASSERT(cond) \ - { \ - if (!(cond)) { \ - printf("%s%s", "ASSERT failed: ", __FILE__); \ - printf("%s%s", "\nfunction ", __func__); \ - printf("%s%d%s", "(), line number ", __LINE__, " at \n"); \ - printf("%s%s", #cond, "\n"); \ - exit(1); \ - } \ - } -#define ASSERT_MSG(cond, msg) \ - { \ - if (!(cond)) { \ - printf("%s%s", "ASSERT failed: ", __FILE__); \ - printf("%s%s", "\nfunction ", __func__); \ - printf("%s%d%s", "(), line number ", __LINE__, " at \n"); \ - printf("%s%s", #cond, "\n"); \ - printf("%s", "ERROR MESSAGE:\n"); \ - printf("%s%s", msg, "\n"); \ - exit(1); \ - } \ - } - -)"; - - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string strcat_def = ""; - strcat_def += indent + "char* " + global_scope->get_unique_name("strcat_") + "(char* x, char* y) {\n"; - strcat_def += indent + tab + "char* str_tmp = (char*) malloc((strlen(x) + strlen(y) + 2) * sizeof(char));\n"; - strcat_def += indent + tab + "strcpy(str_tmp, x);\n"; - strcat_def += indent + tab + "return strcat(str_tmp, y);\n"; - strcat_def += indent + "}\n\n"; - - std::string unit_src_tmp; - for (auto &item : x.m_global_scope->get_scope()) { - if (ASR::is_a(*item.second)) { - ASR::Variable_t *v = ASR::down_cast(item.second); - unit_src_tmp = convert_variable_decl(*v); - unit_src += unit_src_tmp; - if(unit_src_tmp.size() > 0 && (!ASR::is_a(*v->m_type) || - v->m_intent == ASRUtils::intent_return_var )) { - unit_src += ";\n"; - } - } - } - - - std::map> struct_dep_graph; - for (auto &item : x.m_global_scope->get_scope()) { - if (ASR::is_a(*item.second) || - ASR::is_a(*item.second) || - ASR::is_a(*item.second)) { - std::vector struct_deps_vec; - std::pair struct_deps_ptr = ASRUtils::symbol_dependencies(item.second); - for( size_t i = 0; i < struct_deps_ptr.second; i++ ) { - struct_deps_vec.push_back(std::string(struct_deps_ptr.first[i])); - } - struct_dep_graph[item.first] = struct_deps_vec; - } - } - - std::vector struct_deps = ASRUtils::order_deps(struct_dep_graph); - - for (auto &item : struct_deps) { - ASR::symbol_t* struct_sym = x.m_global_scope->get_symbol(item); - visit_symbol(*struct_sym); - array_types_decls += src; - } - - // Topologically sort all global functions - // and then define them in the right order - std::vector global_func_order = ASRUtils::determine_function_definition_order(x.m_global_scope); - - unit_src += "\n"; - unit_src += "// Implementations\n"; - - { - // Process intrinsic modules in the right order - std::vector build_order - = ASRUtils::determine_module_dependencies(x); - for (auto &item : build_order) { - LCOMPILERS_ASSERT(x.m_global_scope->get_scope().find(item) - != x.m_global_scope->get_scope().end()); - if (startswith(item, "lfortran_intrinsic")) { - ASR::symbol_t *mod = x.m_global_scope->get_symbol(item); - if( ASRUtils::get_body_size(mod) != 0 ) { - visit_symbol(*mod); - unit_src += src; - } - } - } - } - - // Process modules in the right order - std::vector build_order - = ASRUtils::determine_module_dependencies(x); - for (auto &item : build_order) { - LCOMPILERS_ASSERT(x.m_global_scope->get_scope().find(item) - != x.m_global_scope->get_scope().end()); - if (!startswith(item, "lfortran_intrinsic")) { - ASR::symbol_t *mod = x.m_global_scope->get_symbol(item); - visit_symbol(*mod); - unit_src += src; - } - } - - // Process global functions - size_t i; - for (i = 0; i < global_func_order.size(); i++) { - ASR::symbol_t* sym = x.m_global_scope->get_symbol(global_func_order[i]); - // Ignore external symbols because they are already defined by the loop above. - if( !sym || ASR::is_a(*sym) ) { - continue ; - } - visit_symbol(*sym); - unit_src += src; - } - - // Then the main program: - for (auto &item : x.m_global_scope->get_scope()) { - if (ASR::is_a(*item.second)) { - visit_symbol(*item.second); - unit_src += src; - } - } - std::string to_include = ""; - for (auto s: headers) { - to_include += "#include <" + s + ".h>\n"; - } - if( c_ds_api->get_func_decls().size() > 0 ) { - array_types_decls += "\n" + c_ds_api->get_func_decls() + "\n"; - } - if( c_utils_functions->get_util_func_decls().size() > 0 ) { - array_types_decls += "\n" + c_utils_functions->get_util_func_decls() + "\n"; - } - std::string ds_funcs_defined = ""; - if( c_ds_api->get_generated_code().size() > 0 ) { - ds_funcs_defined = "\n" + c_ds_api->get_generated_code() + "\n"; - } - std::string util_funcs_defined = ""; - if( c_utils_functions->get_generated_code().size() > 0 ) { - util_funcs_defined = "\n" + c_utils_functions->get_generated_code() + "\n"; - } - if( is_string_concat_present ) { - head += strcat_def; - } - src = to_include + head + array_types_decls + unit_src + - ds_funcs_defined + util_funcs_defined; - } - - void visit_Module(const ASR::Module_t &x) { - std::string unit_src = ""; - for (auto &item : x.m_symtab->get_scope()) { - if (ASR::is_a(*item.second)) { - std::string unit_src_tmp; - ASR::Variable_t *v = ASR::down_cast( - item.second); - unit_src_tmp = convert_variable_decl(*v); - unit_src += unit_src_tmp; - if(unit_src_tmp.size() > 0 && - (!ASR::is_a(*v->m_type) || - v->m_intent == ASRUtils::intent_return_var )) { - unit_src += ";\n"; - } - } - } - std::map> struct_dep_graph; - for (auto &item : x.m_symtab->get_scope()) { - if (ASR::is_a(*item.second) || - ASR::is_a(*item.second) || - ASR::is_a(*item.second)) { - std::vector struct_deps_vec; - std::pair struct_deps_ptr = ASRUtils::symbol_dependencies(item.second); - for( size_t i = 0; i < struct_deps_ptr.second; i++ ) { - struct_deps_vec.push_back(std::string(struct_deps_ptr.first[i])); - } - struct_dep_graph[item.first] = struct_deps_vec; - } - } - - std::vector struct_deps = ASRUtils::order_deps(struct_dep_graph); - for (auto &item : struct_deps) { - ASR::symbol_t* struct_sym = x.m_symtab->get_symbol(item); - visit_symbol(*struct_sym); - } - - // Topologically sort all module functions - // and then define them in the right order - std::vector func_order = ASRUtils::determine_function_definition_order(x.m_symtab); - for (auto &item : func_order) { - ASR::symbol_t* sym = x.m_symtab->get_symbol(item); - ASR::Function_t *s = ASR::down_cast(sym); - visit_Function(*s); - unit_src += src; - } - src = unit_src; - } - - void visit_Program(const ASR::Program_t &x) { - // Topologically sort all program functions - // and then define them in the right order - std::vector func_order = ASRUtils::determine_function_definition_order(x.m_symtab); - - // Generate code for nested subroutines and functions first: - std::string contains; - for (auto &item : func_order) { - ASR::symbol_t* sym = x.m_symtab->get_symbol(item); - ASR::Function_t *s = ASR::down_cast(sym); - visit_Function(*s); - contains += src; - } - - // Generate code for the main program - indentation_level += 1; - std::string indent1(indentation_level*indentation_spaces, ' '); - std::string decl; - // Topologically sort all program functions - // and then define them in the right order - std::vector var_order = ASRUtils::determine_variable_declaration_order(x.m_symtab); - std::string decl_tmp; - for (auto &item : var_order) { - ASR::symbol_t* var_sym = x.m_symtab->get_symbol(item); - if (ASR::is_a(*var_sym)) { - ASR::Variable_t *v = ASR::down_cast(var_sym); - decl += indent1; - decl_tmp = convert_variable_decl(*v); - decl += decl_tmp; - if(decl_tmp.size() > 0 && (!ASR::is_a(*v->m_type) || - v->m_intent == ASRUtils::intent_return_var )) { - decl += ";\n"; - } - } - } - - std::string body; - for (size_t i=0; ivisit_stmt(*x.m_body[i]); - body += src; - } - src = contains - + "int main(int argc, char* argv[])\n{\n" - + decl + body - + indent1 + "return 0;\n}\n"; - indentation_level -= 2; - } - - template - void visit_AggregateTypeUtil(const T& x, std::string c_type_name, - std::string& src_dest) { - std::string body = ""; - int indendation_level_copy = indentation_level; - for( auto itr: x.m_symtab->get_scope() ) { - if( ASR::is_a(*itr.second) ) { - visit_AggregateTypeUtil(*ASR::down_cast(itr.second), - "union", src_dest); - } else if( ASR::is_a(*itr.second) ) { - std::string struct_c_type_name = get_StructCTypeName( - *ASR::down_cast(itr.second)); - visit_AggregateTypeUtil(*ASR::down_cast(itr.second), - struct_c_type_name, src_dest); - } - } - indentation_level = indendation_level_copy; - std::string indent(indentation_level*indentation_spaces, ' '); - indentation_level += 1; - std::string open_struct = indent + c_type_name + " " + std::string(x.m_name) + " {\n"; - indent.push_back(' '); - CDeclarationOptions c_decl_options_; - c_decl_options_.pre_initialise_derived_type = false; - c_decl_options_.use_ptr_for_derived_type = false; - for( size_t i = 0; i < x.n_members; i++ ) { - ASR::symbol_t* member = x.m_symtab->get_symbol(x.m_members[i]); - LCOMPILERS_ASSERT(ASR::is_a(*member)); - body += indent + convert_variable_decl( - *ASR::down_cast(member), - &c_decl_options_); - if( !ASR::is_a(*ASRUtils::symbol_type(member)) || - ASR::down_cast(member)->m_intent == ASRUtils::intent_return_var ) { - body += ";\n"; - } - } - indentation_level -= 1; - std::string end_struct = "};\n\n"; - src_dest += open_struct + body + end_struct; - } - - std::string get_StructCTypeName(const ASR::StructType_t& x) { - std::string c_type_name = "struct"; - if( x.m_is_packed ) { - std::string attr_args = "(packed"; - if( x.m_alignment ) { - LCOMPILERS_ASSERT(ASRUtils::expr_value(x.m_alignment)); - ASR::expr_t* alignment_value = ASRUtils::expr_value(x.m_alignment); - int64_t alignment_int = -1; - if( !ASRUtils::extract_value(alignment_value, alignment_int) ) { - LCOMPILERS_ASSERT(false); - } - attr_args += ", aligned(" + std::to_string(alignment_int) + ")"; - } - attr_args += ")"; - c_type_name += " __attribute__(" + attr_args + ")"; - } - return c_type_name; - } - - void visit_StructType(const ASR::StructType_t& x) { - src = ""; - std::string c_type_name = get_StructCTypeName(x); - visit_AggregateTypeUtil(x, c_type_name, array_types_decls); - src = ""; - } - - void visit_UnionType(const ASR::UnionType_t& x) { - visit_AggregateTypeUtil(x, "union", array_types_decls); - } - - void visit_EnumType(const ASR::EnumType_t& x) { - if( x.m_enum_value_type == ASR::enumtypeType::NonInteger ) { - throw CodeGenError("C backend only supports integer valued Enum. " + - std::string(x.m_name) + " is not integer valued."); - } - if( x.m_enum_value_type == ASR::enumtypeType::IntegerNotUnique ) { - throw CodeGenError("C backend only supports uniquely valued integer Enum. " + - std::string(x.m_name) + " Enum is having duplicate values for its members."); - } - if( x.m_enum_value_type == ASR::enumtypeType::IntegerUnique && - x.m_abi == ASR::abiType::BindC ) { - throw CodeGenError("C-interoperation support for non-consecutive but uniquely " - "valued integer enums isn't available yet."); - } - std::string indent(indentation_level*indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string meta_data = " = {"; - std::string open_struct = indent + "enum " + std::string(x.m_name) + " {\n"; - std::string body = ""; - int64_t min_value = INT64_MAX; - int64_t max_value = INT64_MIN; - size_t max_name_len = 0; - for( size_t i = 0; i < x.n_members; i++ ) { - ASR::symbol_t* member = x.m_symtab->get_symbol(x.m_members[i]); - LCOMPILERS_ASSERT(ASR::is_a(*member)); - ASR::Variable_t* member_var = ASR::down_cast(member); - ASR::expr_t* value = ASRUtils::expr_value(member_var->m_symbolic_value); - int64_t value_int64 = -1; - ASRUtils::extract_value(value, value_int64); - min_value = std::min(value_int64, min_value); - max_value = std::max(value_int64, max_value); - max_name_len = std::max(max_name_len, std::string(x.m_members[i]).size()); - this->visit_expr(*member_var->m_symbolic_value); - body += indent + tab + std::string(member_var->m_name) + " = " + src + ",\n"; - } - size_t max_names = max_value - min_value + 1; - std::vector enum_names(max_names, "\"\""); - for( size_t i = 0; i < x.n_members; i++ ) { - ASR::symbol_t* member = x.m_symtab->get_symbol(x.m_members[i]); - LCOMPILERS_ASSERT(ASR::is_a(*member)); - ASR::Variable_t* member_var = ASR::down_cast(member); - ASR::expr_t* value = ASRUtils::expr_value(member_var->m_symbolic_value); - int64_t value_int64 = -1; - ASRUtils::extract_value(value, value_int64); - min_value = std::min(value_int64, min_value); - enum_names[value_int64 - min_value] = "\"" + std::string(member_var->m_name) + "\""; - } - for( auto enum_name: enum_names ) { - meta_data += enum_name + ", "; - } - meta_data.pop_back(); - meta_data.pop_back(); - meta_data += "};\n"; - std::string end_struct = "};\n\n"; - std::string enum_names_type = "char " + global_scope->get_unique_name("enum_names_") + - std::string(x.m_name) + "[" + std::to_string(max_names) + "][" + std::to_string(max_name_len + 1) + "] "; - array_types_decls += enum_names_type + meta_data + open_struct + body + end_struct; - src = ""; - } - - void visit_EnumTypeConstructor(const ASR::EnumTypeConstructor_t& x) { - LCOMPILERS_ASSERT(x.n_args == 1); - ASR::expr_t* m_arg = x.m_args[0]; - this->visit_expr(*m_arg); - ASR::EnumType_t* enum_type = ASR::down_cast(x.m_dt_sym); - src = "(enum " + std::string(enum_type->m_name) + ") (" + src + ")"; - } - - void visit_UnionTypeConstructor(const ASR::UnionTypeConstructor_t& /*x*/) { - - } - - void visit_EnumStaticMember(const ASR::EnumStaticMember_t& x) { - CHECK_FAST_C(compiler_options, x) - ASR::Variable_t* enum_var = ASR::down_cast(x.m_m); - src = std::string(enum_var->m_name); - } - - void visit_EnumValue(const ASR::EnumValue_t& x) { - CHECK_FAST_C(compiler_options, x) - visit_expr(*x.m_v); - } - - void visit_EnumName(const ASR::EnumName_t& x) { - CHECK_FAST_C(compiler_options, x) - int64_t min_value = INT64_MAX; - ASR::Enum_t* enum_t = ASR::down_cast(x.m_enum_type); - ASR::EnumType_t* enum_type = ASR::down_cast(enum_t->m_enum_type); - for( auto itr: enum_type->m_symtab->get_scope() ) { - ASR::Variable_t* itr_var = ASR::down_cast(itr.second); - ASR::expr_t* value = ASRUtils::expr_value(itr_var->m_symbolic_value); - int64_t value_int64 = -1; - ASRUtils::extract_value(value, value_int64); - min_value = std::min(value_int64, min_value); - } - visit_expr(*x.m_v); - std::string enum_var_name = src; - src = global_scope->get_unique_name("enum_names_" + std::string(enum_type->m_name)) + - "[" + std::string(enum_var_name) + " - " + std::to_string(min_value) + "]"; - } - - void visit_ComplexConstant(const ASR::ComplexConstant_t &x) { - headers.insert("complex"); - std::string re = std::to_string(x.m_re); - std::string im = std::to_string(x.m_im); - src = "CMPLX(" + re + ", " + im + ")"; - - last_expr_precedence = 2; - } - - void visit_LogicalConstant(const ASR::LogicalConstant_t &x) { - if (x.m_value == true) { - src = "true"; - } else { - src = "false"; - } - last_expr_precedence = 2; - } - - void visit_Assert(const ASR::Assert_t &x) { - std::string indent(indentation_level*indentation_spaces, ' '); - std::string out = indent; - bracket_open++; - if (x.m_msg) { - out += "ASSERT_MSG("; - visit_expr(*x.m_test); - out += src + ", "; - visit_expr(*x.m_msg); - out += src + ");\n"; - } else { - out += "ASSERT("; - visit_expr(*x.m_test); - out += src + ");\n"; - } - bracket_open--; - src = check_tmp_buffer() + out; - } - - void visit_CPtrToPointer(const ASR::CPtrToPointer_t& x) { - visit_expr(*x.m_cptr); - std::string source_src = std::move(src); - visit_expr(*x.m_ptr); - std::string dest_src = std::move(src); - src = ""; - std::string indent(indentation_level*indentation_spaces, ' '); - if( ASRUtils::is_array(ASRUtils::expr_type(x.m_ptr)) ) { - std::string dim_set_code = ""; - ASR::dimension_t* m_dims = nullptr; - int n_dims = ASRUtils::extract_dimensions_from_ttype(ASRUtils::expr_type(x.m_ptr), m_dims); - dim_set_code = indent + dest_src + "->n_dims = " + std::to_string(n_dims) + ";\n"; - for( int i = 0; i < n_dims; i++ ) { - if( m_dims[i].m_start ) { - visit_expr(*m_dims[i].m_start); - dim_set_code += indent + dest_src + "->dims[" + std::to_string(i) + "].lower_bound = " + src + ";\n"; - } - if( m_dims[i].m_length ) { - visit_expr(*m_dims[i].m_length); - dim_set_code += indent + dest_src + "->dims[" + std::to_string(i) + "].length = " + src + ";\n"; - } - } - src.clear(); - src += dim_set_code; - dest_src += "->data"; - } - std::string type_src = CUtils::get_c_type_from_ttype_t(ASRUtils::expr_type(x.m_ptr)); - src += indent + dest_src + " = (" + type_src + ") " + source_src + ";\n"; - } - - void visit_Print(const ASR::Print_t &x) { - std::string indent(indentation_level*indentation_spaces, ' '); - std::string tmp_gen = indent + "printf(\"", out = ""; - bracket_open++; - std::vector v; - std::string separator; - if (x.m_separator) { - this->visit_expr(*x.m_separator); - separator = src; - } else { - separator = "\" \""; - } - for (size_t i=0; ivisit_expr(*x.m_values[i]); - if( ASRUtils::is_array(ASRUtils::expr_type(x.m_values[i])) ) { - src += "->data"; - } - ASR::ttype_t* value_type = ASRUtils::expr_type(x.m_values[i]); - if (value_type->type == ASR::ttypeType::List || - value_type->type == ASR::ttypeType::Tuple) { - tmp_gen += "\""; - if (!v.empty()) { - for (auto &s: v) { - tmp_gen += ", " + s; - } - } - tmp_gen += ");\n"; - out += tmp_gen; - tmp_gen = indent + "printf(\""; - v.clear(); - std::string p_func = c_ds_api->get_print_func(value_type); - out += indent + p_func + "(" + src + ");\n"; - continue; - } - tmp_gen += c_ds_api->get_print_type(value_type, ASR::is_a(*x.m_values[i])); - v.push_back(src); - if (value_type->type == ASR::ttypeType::Complex) { - v.pop_back(); - v.push_back("creal(" + src + ")"); - v.push_back("cimag(" + src + ")"); - } - if (i+1!=x.n_values) { - tmp_gen += "\%s"; - v.push_back(separator); - } - } - if (x.m_end) { - this->visit_expr(*x.m_end); - tmp_gen += "\%s\""; - v.push_back(src); - } else { - tmp_gen += "\\n\""; - } - if (!v.empty()) { - for (auto &s: v) { - tmp_gen += ", " + s; - } - } - tmp_gen += ");\n"; - bracket_open--; - out += tmp_gen; - src = this->check_tmp_buffer() + out; - } - - void visit_ArraySize(const ASR::ArraySize_t& x) { - CHECK_FAST_C(compiler_options, x) - visit_expr(*x.m_v); - std::string var_name = src; - std::string args = ""; - std::string result_type = CUtils::get_c_type_from_ttype_t(x.m_type); - if (x.m_dim == nullptr) { - std::string array_size_func = c_utils_functions->get_array_size(); - ASR::dimension_t* m_dims = nullptr; - int n_dims = ASRUtils::extract_dimensions_from_ttype(ASRUtils::expr_type(x.m_v), m_dims); - src = "((" + result_type + ") " + array_size_func + "(" + var_name + "->dims, " + std::to_string(n_dims) + "))"; - } else { - visit_expr(*x.m_dim); - std::string idx = src; - src = "((" + result_type + ")" + var_name + "->dims[" + idx + "-1].length)"; - } - } - - void visit_ArrayReshape(const ASR::ArrayReshape_t& x) { - CHECK_FAST_C(compiler_options, x) - visit_expr(*x.m_array); - std::string array = src; - visit_expr(*x.m_shape); - std::string shape = src; - - ASR::ttype_t* array_type_asr = ASRUtils::expr_type(x.m_array); - std::string array_type_name = CUtils::get_c_type_from_ttype_t(array_type_asr); - std::string array_encoded_type_name = ASRUtils::get_type_code(array_type_asr, true, false, false); - std::string array_type = c_ds_api->get_array_type(array_type_name, array_encoded_type_name, array_types_decls, true); - std::string return_type = c_ds_api->get_array_type(array_type_name, array_encoded_type_name, array_types_decls, false); - - ASR::ttype_t* shape_type_asr = ASRUtils::expr_type(x.m_shape); - std::string shape_type_name = CUtils::get_c_type_from_ttype_t(shape_type_asr); - std::string shape_encoded_type_name = ASRUtils::get_type_code(shape_type_asr, true, false, false); - std::string shape_type = c_ds_api->get_array_type(shape_type_name, shape_encoded_type_name, array_types_decls, true); - - std::string array_reshape_func = c_utils_functions->get_array_reshape(array_type, shape_type, - return_type, array_type_name, array_encoded_type_name); - src = array_reshape_func + "(" + array + ", " + shape + ")"; - } - - void visit_ArrayBound(const ASR::ArrayBound_t& x) { - CHECK_FAST_C(compiler_options, x) - visit_expr(*x.m_v); - std::string var_name = src; - std::string args = ""; - std::string result_type = CUtils::get_c_type_from_ttype_t(x.m_type); - visit_expr(*x.m_dim); - std::string idx = src; - if( x.m_bound == ASR::arrayboundType::LBound ) { - src = "((" + result_type + ")" + var_name + "->dims[" + idx + "-1].lower_bound)"; - } else if( x.m_bound == ASR::arrayboundType::UBound ) { - std::string lower_bound = var_name + "->dims[" + idx + "-1].lower_bound"; - std::string length = var_name + "->dims[" + idx + "-1].length"; - std::string upper_bound = length + " + " + lower_bound + " - 1"; - src = "((" + result_type + ") " + upper_bound + ")"; - } - } - - void visit_ArrayConstant(const ASR::ArrayConstant_t& x) { - // TODO: Support and test for multi-dimensional array constants - headers.insert("stdarg"); - std::string array_const = ""; - for( size_t i = 0; i < x.n_args; i++ ) { - visit_expr(*x.m_args[i]); - array_const += src + ", "; - } - array_const.pop_back(); - array_const.pop_back(); - - ASR::ttype_t* array_type_asr = x.m_type; - std::string array_type_name = CUtils::get_c_type_from_ttype_t(array_type_asr); - std::string array_encoded_type_name = ASRUtils::get_type_code(array_type_asr, true, false); - std::string return_type = c_ds_api->get_array_type(array_type_name, array_encoded_type_name,array_types_decls, false); - - src = c_utils_functions->get_array_constant(return_type, array_type_name, array_encoded_type_name) + - "(" + std::to_string(x.n_args) + ", " + array_const + ")"; - } - - void visit_ArrayItem(const ASR::ArrayItem_t &x) { - CHECK_FAST_C(compiler_options, x) - this->visit_expr(*x.m_v); - std::string array = src; - std::string out = array; - ASR::ttype_t* x_mv_type = ASRUtils::expr_type(x.m_v); - ASR::dimension_t* m_dims; - int n_dims = ASRUtils::extract_dimensions_from_ttype(x_mv_type, m_dims); - bool is_data_only_array = ASRUtils::is_fixed_size_array(m_dims, n_dims) && - ASR::is_a(*ASRUtils::get_asr_owner(x.m_v)); - if( is_data_only_array ) { - out += "["; - } else { - out += "->data["; - } - std::string index = ""; - for (size_t i=0; ivisit_expr(*x.m_args[i].m_right); - } else { - src = "/* FIXME right index */"; - } - - if( is_data_only_array ) { - current_index += src; - for( size_t j = i + 1; j < x.n_args; j++ ) { - int64_t dim_size; - ASRUtils::extract_value(m_dims[j].m_length, dim_size); - std::string length = std::to_string(dim_size); - current_index += " * " + length; - } - index += current_index; - } else { - current_index += "(" + src + " - " + array + "->dims[" - + std::to_string(i) + "].lower_bound)"; - for( size_t j = i + 1; j < x.n_args; j++ ) { - std::string length = array + "->dims[" + std::to_string(j) + "].length"; - current_index += " * " + length; - } - index += current_index; - } - if (i < x.n_args - 1) { - index += " + "; - } - } - out += index + "]"; - last_expr_precedence = 2; - src = out; - } - - void visit_StringItem(const ASR::StringItem_t& x) { - CHECK_FAST_C(compiler_options, x) - this->visit_expr(*x.m_idx); - std::string idx = std::move(src); - this->visit_expr(*x.m_arg); - std::string str = std::move(src); - src = "_lfortran_str_item(" + str + ", " + idx + ")"; - } - - void visit_StringLen(const ASR::StringLen_t &x) { - CHECK_FAST_C(compiler_options, x) - this->visit_expr(*x.m_arg); - src = "strlen(" + src + ")"; - } - - void visit_GoTo(const ASR::GoTo_t &x) { - std::string indent(indentation_level*indentation_spaces, ' '); - src = indent + "goto " + std::string(x.m_name) + ";\n"; - } - - void visit_GoToTarget(const ASR::GoToTarget_t &x) { - src = std::string(x.m_name) + ":\n"; - } -}; - -Result asr_to_c(Allocator &al, ASR::TranslationUnit_t &asr, - diag::Diagnostics &diagnostics, CompilerOptions &co, - int64_t default_lower_bound) -{ - - LCompilers::PassOptions pass_options; - pass_options.always_run = true; - pass_create_subroutine_from_function(al, asr, pass_options); - pass_replace_array_op(al, asr, pass_options); - pass_unused_functions(al, asr, pass_options); - pass_replace_class_constructor(al, asr, pass_options); - ASRToCVisitor v(diagnostics, co, default_lower_bound); - try { - v.visit_asr((ASR::asr_t &)asr); - } catch (const CodeGenError &e) { - diagnostics.diagnostics.push_back(e.d); - return Error(); - } catch (const Abort &) { - return Error(); - } - return v.src; -} - -} // namespace LCompilers diff --git a/src/libasr/codegen/asr_to_c.h b/src/libasr/codegen/asr_to_c.h deleted file mode 100644 index 5bf90948b5..0000000000 --- a/src/libasr/codegen/asr_to_c.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef LFORTRAN_ASR_TO_C_H -#define LFORTRAN_ASR_TO_C_H - -#include -#include - -namespace LCompilers { - - Result asr_to_c(Allocator &al, ASR::TranslationUnit_t &asr, - diag::Diagnostics &diagnostics, CompilerOptions &co, - int64_t default_lower_bound); - -} // namespace LCompilers - -#endif // LFORTRAN_ASR_TO_C_H diff --git a/src/libasr/codegen/asr_to_c_cpp.h b/src/libasr/codegen/asr_to_c_cpp.h deleted file mode 100644 index fb69904bcb..0000000000 --- a/src/libasr/codegen/asr_to_c_cpp.h +++ /dev/null @@ -1,2113 +0,0 @@ -#ifndef LFORTRAN_ASR_TO_C_CPP_H -#define LFORTRAN_ASR_TO_C_CPP_H - -/* - * Common code to be used in both of: - * - * * asr_to_cpp.cpp - * * asr_to_c.cpp - * - * In particular, a common base class visitor with visitors that are identical - * for both C and C++ code generation. - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define CHECK_FAST_C_CPP(compiler_options, x) \ - if (compiler_options.fast && x.m_value != nullptr) { \ - self().visit_expr(*x.m_value); \ - return; \ - } \ - - -namespace LCompilers { - - -// Platform dependent fast unique hash: -static inline uint64_t get_hash(ASR::asr_t *node) -{ - return (uint64_t)node; -} - -struct SymbolInfo -{ - bool needs_declaration = true; - bool intrinsic_function = false; -}; - -struct DeclarationOptions { -}; - -struct CDeclarationOptions: public DeclarationOptions { - bool pre_initialise_derived_type; - bool use_ptr_for_derived_type; - bool use_static; - bool force_declare; - std::string force_declare_name; - bool declare_as_constant; - std::string const_name; - - CDeclarationOptions() : - pre_initialise_derived_type{true}, - use_ptr_for_derived_type{true}, - use_static{true}, - force_declare{false}, - force_declare_name{""}, - declare_as_constant{false}, - const_name{""} { - } -}; - -struct CPPDeclarationOptions: public DeclarationOptions { - bool use_static; - bool use_templates_for_arrays; - - CPPDeclarationOptions() : - use_static{true}, - use_templates_for_arrays{false} { - } -}; - -template -class BaseCCPPVisitor : public ASR::BaseVisitor -{ -private: - Struct& self() { return static_cast(*this); } -public: - diag::Diagnostics &diag; - Platform platform; - std::string src; - std::string current_body; - CompilerOptions &compiler_options; - int indentation_level; - int indentation_spaces; - // The precedence of the last expression, using the table: - // https://en.cppreference.com/w/cpp/language/operator_precedence - int last_expr_precedence; - bool intrinsic_module = false; - const ASR::Function_t *current_function = nullptr; - std::map sym_info; - std::map const_var_names; - - // Output configuration: - // Use std::string or char* - bool gen_stdstring; - // Use std::complex or float/double complex - bool gen_stdcomplex; - bool is_c; - std::set headers; - std::vector tmp_buffer_src; - - SymbolTable* global_scope; - int64_t lower_bound; - - std::string template_for_Kokkos; - size_t template_number; - std::string from_std_vector_helper; - - std::unique_ptr c_ds_api; - std::string const_name; - size_t const_vars_count; - size_t loop_end_count; - - // This is used to track if during the codegeneration whether or not - // the source is inside any bracket. bracket_open is always >= 0. We - // increment when we come-across a open bracket and decrement when we - // come-across a closing bracket. - // This helps in putting the extra code-generation (mainly of Constants) - // in the right place and avoid producing syntax errors. - // For example: - // In FunctionCall node: we do `some_fun(` -> bracket_open++ - // and when we close the bracket `...)` -> bracket_open-- - - int bracket_open; - - SymbolTable* current_scope; - bool is_string_concat_present; - - BaseCCPPVisitor(diag::Diagnostics &diag, Platform &platform, - CompilerOptions &_compiler_options, bool gen_stdstring, bool gen_stdcomplex, bool is_c, - int64_t default_lower_bound) : diag{diag}, - platform{platform}, compiler_options{_compiler_options}, - gen_stdstring{gen_stdstring}, gen_stdcomplex{gen_stdcomplex}, - is_c{is_c}, global_scope{nullptr}, lower_bound{default_lower_bound}, - template_number{0}, c_ds_api{std::make_unique(is_c, platform)}, - const_name{"constname"}, - const_vars_count{0}, loop_end_count{0}, bracket_open{0}, - is_string_concat_present{false} { - } - - void visit_TranslationUnit(const ASR::TranslationUnit_t &x) { - global_scope = x.m_global_scope; - // All loose statements must be converted to a function, so the items - // must be empty: - LCOMPILERS_ASSERT(x.n_items == 0); - std::string unit_src = ""; - indentation_level = 0; - indentation_spaces = 4; - c_ds_api->set_indentation(indentation_level + 1, indentation_spaces); - c_ds_api->set_global_scope(global_scope); - - std::string headers = -R"(#include -#include -#include -#include -)"; - unit_src += headers; - - { - // Process intrinsic modules in the right order - std::vector build_order - = ASRUtils::determine_module_dependencies(x); - for (auto &item : build_order) { - LCOMPILERS_ASSERT(x.m_global_scope->get_scope().find(item) - != x.m_global_scope->get_scope().end()); - if (startswith(item, "lfortran_intrinsic")) { - ASR::symbol_t *mod = x.m_global_scope->get_symbol(item); - self().visit_symbol(*mod); - unit_src += src; - } - } - } - - // Process procedures first: - for (auto &item : x.m_global_scope->get_scope()) { - if (ASR::is_a(*item.second)) { - self().visit_symbol(*item.second); - unit_src += src; - } - } - - // Then do all the modules in the right order - std::vector build_order - = ASRUtils::determine_module_dependencies(x); - for (auto &item : build_order) { - LCOMPILERS_ASSERT(x.m_global_scope->get_scope().find(item) - != x.m_global_scope->get_scope().end()); - if (!startswith(item, "lfortran_intrinsic")) { - ASR::symbol_t *mod = x.m_global_scope->get_symbol(item); - self().visit_symbol(*mod); - unit_src += src; - } - } - - // Then the main program: - for (auto &item : x.m_global_scope->get_scope()) { - if (ASR::is_a(*item.second)) { - self().visit_symbol(*item.second); - unit_src += src; - } - } - - src = unit_src; - } - - std::string check_tmp_buffer() { - std::string ret = ""; - if (bracket_open == 0 && !tmp_buffer_src.empty()) { - for (auto &s: tmp_buffer_src) ret += s; - tmp_buffer_src.clear(); - } - return ret; - } - - void visit_Module(const ASR::Module_t &x) { - if (startswith(x.m_name, "lfortran_intrinsic_")) { - intrinsic_module = true; - } else { - intrinsic_module = false; - } - - std::string contains; - - // Declare the global variables that are imported from the module - std::vector var_order = ASRUtils::determine_variable_declaration_order(x.m_symtab); - for (auto &item : var_order) { - ASR::symbol_t* var_sym = x.m_symtab->get_symbol(item); - if (ASR::is_a(*var_sym)) { - ASR::Variable_t *v = ASR::down_cast(var_sym); - std::string decl = self().convert_variable_decl(*v); - decl = check_tmp_buffer() + decl; - bool used_define_for_const = (ASR::is_a(*v->m_type) && - v->m_intent == ASRUtils::intent_local); - if (used_define_for_const) { - contains += decl + "\n"; - continue; - } - if (v->m_value) { - self().visit_expr(*v->m_value); - decl += " = " + src; - } - decl += ";\n\n"; - contains += decl; - } - } - - // Topologically sort all module functions - // and then define them in the right order - std::vector func_order = ASRUtils::determine_function_definition_order(x.m_symtab); - - // Generate the bodies of subroutines - for (auto &item : func_order) { - ASR::symbol_t* sym = x.m_symtab->get_symbol(item); - if( !sym ) { - continue ; - } - ASR::Function_t *s = ASR::down_cast(sym); - self().visit_Function(*s); - contains += src; - } - - src = contains; - intrinsic_module = false; - } - - void visit_Program(const ASR::Program_t &x) { - // Generate code for nested subroutines and functions first: - SymbolTable* current_scope_copy = current_scope; - current_scope = x.m_symtab; - std::string contains; - for (auto &item : x.m_symtab->get_scope()) { - if (ASR::is_a(*item.second)) { - ASR::Function_t *s = ASR::down_cast(item.second); - visit_Function(*s); - contains += src; - } - } - - // Generate code for the main program - indentation_level += 1; - std::string indent1(indentation_level*indentation_spaces, ' '); - indentation_level += 1; - std::string indent(indentation_level*indentation_spaces, ' '); - std::string decl; - std::vector var_order = ASRUtils::determine_variable_declaration_order(x.m_symtab); - for (auto &item : var_order) { - ASR::symbol_t* var_sym = x.m_symtab->get_symbol(item); - if (ASR::is_a(*var_sym)) { - ASR::Variable_t *v = ASR::down_cast(var_sym); - std::string d = self().convert_variable_decl(*v); - if( !ASR::is_a(*v->m_type) || - v->m_intent == ASRUtils::intent_return_var ) { - d += ";\n"; - } - decl += check_tmp_buffer() + d; - } - } - - std::string body; - for (size_t i=0; i(*x.m_m)); - ASR::Block_t* block = ASR::down_cast(x.m_m); - std::string decl, body; - std::string indent(indentation_level*indentation_spaces, ' '); - std::string open_paranthesis = indent + "{\n"; - std::string close_paranthesis = indent + "}\n"; - indent += std::string(indentation_spaces, ' '); - indentation_level += 1; - SymbolTable* current_scope_copy = current_scope; - current_scope = block->m_symtab; - std::vector var_order = ASRUtils::determine_variable_declaration_order(block->m_symtab); - for (auto &item : var_order) { - ASR::symbol_t* var_sym = block->m_symtab->get_symbol(item); - if (ASR::is_a(*var_sym)) { - ASR::Variable_t *v = ASR::down_cast(var_sym); - std::string d = indent + self().convert_variable_decl(*v); - if( !ASR::is_a(*v->m_type) || - v->m_intent == ASRUtils::intent_return_var ) { - d += ";\n"; - } - decl += check_tmp_buffer() + d; - } - } - for (size_t i=0; in_body; i++) { - self().visit_stmt(*block->m_body[i]); - body += src; - } - decl += check_tmp_buffer(); - src = open_paranthesis + decl + body + close_paranthesis; - indentation_level -= 1; - current_scope = current_scope_copy; - } - - // Returns the declaration, no semi colon at the end - std::string get_function_declaration(const ASR::Function_t &x, bool &has_typevar) { - template_for_Kokkos.clear(); - template_number = 0; - std::string sub, inl, static_attr; - - // This helps to check if the function is generic. - // If it is generic we skip the codegen for that function. - has_typevar = false; - if (ASRUtils::get_FunctionType(x)->m_inline) { - inl = "inline __attribute__((always_inline)) "; - } - if( ASRUtils::get_FunctionType(x)->m_static ) { - static_attr = "static "; - } - if (x.m_return_var) { - ASR::Variable_t *return_var = ASRUtils::EXPR2VAR(x.m_return_var); - if (ASRUtils::is_integer(*return_var->m_type)) { - int kind = ASR::down_cast(return_var->m_type)->m_kind; - switch (kind) { - case (1) : sub = "int8_t "; break; - case (2) : sub = "int16_t "; break; - case (4) : sub = "int32_t "; break; - case (8) : sub = "int64_t "; break; - } - } else if (ASRUtils::is_real(*return_var->m_type)) { - bool is_float = ASR::down_cast(return_var->m_type)->m_kind == 4; - if (is_float) { - sub = "float "; - } else { - sub = "double "; - } - } else if (ASRUtils::is_logical(*return_var->m_type)) { - sub = "bool "; - } else if (ASRUtils::is_character(*return_var->m_type)) { - if (gen_stdstring) { - sub = "std::string "; - } else { - sub = "char* "; - } - } else if (ASRUtils::is_complex(*return_var->m_type)) { - bool is_float = ASR::down_cast(return_var->m_type)->m_kind == 4; - if (is_float) { - if (gen_stdcomplex) { - sub = "std::complex "; - } else { - sub = "float complex "; - } - } else { - if (gen_stdcomplex) { - sub = "std::complex "; - } else { - sub = "double complex "; - } - } - } else if (ASR::is_a(*return_var->m_type)) { - sub = "void* "; - } else if (ASR::is_a(*return_var->m_type)) { - ASR::List_t* list_type = ASR::down_cast(return_var->m_type); - sub = c_ds_api->get_list_type(list_type) + " "; - } else if (ASR::is_a(*return_var->m_type)) { - ASR::Tuple_t* tup_type = ASR::down_cast(return_var->m_type); - sub = c_ds_api->get_tuple_type(tup_type) + " "; - } else if (ASR::is_a(*return_var->m_type)) { - ASR::Const_t* const_type = ASR::down_cast(return_var->m_type); - std::string const_type_str = CUtils::get_c_type_from_ttype_t(const_type->m_type); - sub = "const " + const_type_str + " "; - } else if (ASR::is_a(*return_var->m_type)) { - ASR::Pointer_t* ptr_type = ASR::down_cast(return_var->m_type); - std::string pointer_type_str = CUtils::get_c_type_from_ttype_t(ptr_type->m_type); - sub = pointer_type_str + "*"; - } else if (ASR::is_a(*return_var->m_type)) { - has_typevar = true; - return ""; - } else { - throw CodeGenError("Return type not supported in function '" + - std::string(x.m_name) + - + "'", return_var->base.base.loc); - } - } else { - sub = "void "; - } - std::string sym_name = x.m_name; - if (sym_name == "main") { - sym_name = "_xx_lcompilers_changed_main_xx"; - } - if (sym_name == "exit") { - sym_name = "_xx_lcompilers_changed_exit_xx"; - } - std::string func = static_attr + inl + sub + sym_name + "("; - bracket_open++; - for (size_t i=0; im_intent)); - if (ASR::is_a(*arg->m_type)) { - has_typevar = true; - bracket_open--; - return ""; - } - if( is_c ) { - CDeclarationOptions c_decl_options; - c_decl_options.pre_initialise_derived_type = false; - func += self().convert_variable_decl(*arg, &c_decl_options); - } else { - CPPDeclarationOptions cpp_decl_options; - cpp_decl_options.use_static = false; - cpp_decl_options.use_templates_for_arrays = true; - func += self().convert_variable_decl(*arg, &cpp_decl_options); - } - if (i < x.n_args-1) func += ", "; - } - func += ")"; - bracket_open--; - if( is_c || template_for_Kokkos.empty() ) { - return func; - } - - template_for_Kokkos.pop_back(); - template_for_Kokkos.pop_back(); - return "\ntemplate <" + template_for_Kokkos + ">\n" + func; - } - - std::string declare_all_functions(const SymbolTable &scope) { - std::string code, t; - for (auto &item : scope.get_scope()) { - if (ASR::is_a(*item.second)) { - ASR::Function_t *s = ASR::down_cast(item.second); - bool has_typevar = false; - t = get_function_declaration(*s, has_typevar); - if (!has_typevar) code += t + ";\n"; - } - } - return code; - } - - void visit_Function(const ASR::Function_t &x) { - current_body = ""; - SymbolTable* current_scope_copy = current_scope; - current_scope = x.m_symtab; - if (std::string(x.m_name) == "size" && intrinsic_module ) { - // Intrinsic function `size` - SymbolInfo s; - s.intrinsic_function = true; - sym_info[get_hash((ASR::asr_t*)&x)] = s; - src = ""; - return; - } else if (( - std::string(x.m_name) == "int" || - std::string(x.m_name) == "char" || - std::string(x.m_name) == "present" || - std::string(x.m_name) == "len" || - std::string(x.m_name) == "not" - ) && intrinsic_module) { - // Intrinsic function `int` - SymbolInfo s; - s.intrinsic_function = true; - sym_info[get_hash((ASR::asr_t*)&x)] = s; - src = ""; - return; - } else { - SymbolInfo s; - s.intrinsic_function = false; - sym_info[get_hash((ASR::asr_t*)&x)] = s; - } - bool has_typevar = false; - std::string sub = get_function_declaration(x, has_typevar); - if (has_typevar) { - src = ""; - return; - } - if (ASRUtils::get_FunctionType(x)->m_abi == ASR::abiType::BindC - && ASRUtils::get_FunctionType(x)->m_deftype == ASR::deftypeType::Interface) { - sub += ";\n"; - } else { - sub += "\n"; - - indentation_level += 1; - std::string indent(indentation_level*indentation_spaces, ' '); - std::string decl; - std::vector var_order = ASRUtils::determine_variable_declaration_order(x.m_symtab); - for (auto &item : var_order) { - ASR::symbol_t* var_sym = x.m_symtab->get_symbol(item); - if (ASR::is_a(*var_sym)) { - ASR::Variable_t *v = ASR::down_cast(var_sym); - if (v->m_intent == ASRUtils::intent_local || - v->m_intent == ASRUtils::intent_return_var) { - std::string d = indent + self().convert_variable_decl(*v); - if( !ASR::is_a(*v->m_type) || - v->m_intent == ASRUtils::intent_return_var ) { - d += ";\n"; - } - decl += check_tmp_buffer() + d; - } - if (ASR::is_a(*v->m_type)) { - has_typevar = true; - break; - } - } - } - if (has_typevar) { - indentation_level -= 1; - src = ""; - return; - } - - current_function = &x; - - for (size_t i=0; i 0 && ASR::is_a(*x.m_body[x.n_body-1])) { - visited_return = true; - } - - if (!visited_return && x.m_return_var) { - current_body += indent + "return " - + ASRUtils::EXPR2VAR(x.m_return_var)->m_name - + ";\n"; - } - - if (decl.size() > 0 || current_body.size() > 0) { - sub += "{\n" + decl + current_body + "}\n"; - } else { - sub[sub.size()-1] = ';'; - sub += "\n"; - } - indentation_level -= 1; - } - sub += "\n"; - src = sub; - current_scope = current_scope_copy; - } - - void visit_FunctionCall(const ASR::FunctionCall_t &x) { - CHECK_FAST_C_CPP(compiler_options, x) - ASR::Function_t *fn = ASR::down_cast( - ASRUtils::symbol_get_past_external(x.m_name)); - std::string fn_name = fn->m_name; - if (sym_info[get_hash((ASR::asr_t*)fn)].intrinsic_function) { - if (fn_name == "size") { - LCOMPILERS_ASSERT(x.n_args > 0); - self().visit_expr(*x.m_args[0].m_value); - std::string var_name = src; - std::string args; - if (x.n_args == 1) { - args = "0"; - } else { - for (size_t i=1; i 0); - self().visit_expr(*x.m_args[0].m_value); - src = "(int)" + src; - } else if (fn_name == "not") { - LCOMPILERS_ASSERT(x.n_args > 0); - self().visit_expr(*x.m_args[0].m_value); - src = "!(" + src + ")"; - } else { - throw CodeGenError("Intrinsic function '" + fn_name - + "' not implemented"); - } - } else { - std::string args; - bracket_open++; - for (size_t i=0; i(*x.m_type) ) { - ASR::List_t* list_type = ASR::down_cast(x.m_type); - const_name += std::to_string(const_vars_count); - const_vars_count += 1; - const_name = current_scope->get_unique_name(const_name); - std::string indent(indentation_level*indentation_spaces, ' '); - tmp_buffer_src.push_back(check_tmp_buffer() + indent + c_ds_api->get_list_type(list_type) + " " + - const_name + " = " + src + ";\n"); - src = const_name; - return; - } - src = check_tmp_buffer() + src; - } - - void visit_SizeOfType(const ASR::SizeOfType_t& x) { - CHECK_FAST_C_CPP(compiler_options, x) - std::string c_type = CUtils::get_c_type_from_ttype_t(x.m_arg); - src = "sizeof(" + c_type + ")"; - } - - void visit_StringSection(const ASR::StringSection_t& x) { - CHECK_FAST_C_CPP(compiler_options, x) - self().visit_expr(*x.m_arg); - std::string arg, left, right, step, left_present, rig_present; - arg = src; - if (x.m_start) { - self().visit_expr(*x.m_start); - left = src; - left_present = "true"; - } else { - left = "0"; - left_present = "false"; - } - if (x.m_end) { - self().visit_expr(*x.m_end); - right = src; - rig_present = "true"; - } else { - right = "0"; - rig_present = "false"; - } - if (x.m_step) { - self().visit_expr(*x.m_step); - step = src; - } else { - step = "1"; - } - src = "_lfortran_str_slice(" + arg + ", " + left + ", " + right + ", " + \ - step + ", " + left_present + ", " + rig_present + ")"; - } - - void visit_StringChr(const ASR::StringChr_t& x) { - CHECK_FAST_C_CPP(compiler_options, x) - self().visit_expr(*x.m_arg); - src = "_lfortran_str_chr(" + src + ")"; - } - - void visit_StringOrd(const ASR::StringOrd_t& x) { - CHECK_FAST_C_CPP(compiler_options, x) - self().visit_expr(*x.m_arg); - if (ASR::is_a(*x.m_arg)) { - src = "(int)" + src + "[0]"; - } else { - src = "_lfortran_str_ord_c(" + src + ")"; - } - } - - void visit_StringRepeat(const ASR::StringRepeat_t &x) { - CHECK_FAST_C_CPP(compiler_options, x) - self().visit_expr(*x.m_left); - std::string s = src; - self().visit_expr(*x.m_right); - std::string n = src; - src = "_lfortran_strrepeat_c(" + s + ", " + n + ")"; - } - - void visit_Assignment(const ASR::Assignment_t &x) { - std::string target; - ASR::ttype_t* m_target_type = ASRUtils::expr_type(x.m_target); - if( ASR::is_a(*m_target_type) ) { - src = ""; - return ; - } - ASR::ttype_t* m_value_type = ASRUtils::expr_type(x.m_value); - bool is_target_list = ASR::is_a(*m_target_type); - bool is_value_list = ASR::is_a(*m_value_type); - bool is_target_tup = ASR::is_a(*m_target_type); - bool is_value_tup = ASR::is_a(*m_value_type); - bool is_target_dict = ASR::is_a(*m_target_type); - bool is_value_dict = ASR::is_a(*m_value_type); - bool alloc_return_var = false; - std::string indent(indentation_level*indentation_spaces, ' '); - if (ASR::is_a(*x.m_target)) { - ASR::Var_t* x_m_target = ASR::down_cast(x.m_target); - visit_Var(*x_m_target); - target = src; - if (!is_c && ASRUtils::is_array(ASRUtils::expr_type(x.m_target))) { - target += "->data"; - } - if (target == "_lpython_return_variable" && ASRUtils::is_character(*m_target_type)) { - // ASR assigns return variable only once at the end of function - alloc_return_var = true; - } - } else if (ASR::is_a(*x.m_target)) { - self().visit_ArrayItem(*ASR::down_cast(x.m_target)); - target = src; - } else if (ASR::is_a(*x.m_target)) { - visit_StructInstanceMember(*ASR::down_cast(x.m_target)); - target = src; - } else if (ASR::is_a(*x.m_target)) { - visit_UnionInstanceMember(*ASR::down_cast(x.m_target)); - target = src; - } else if (ASR::is_a(*x.m_target)) { - self().visit_ListItem(*ASR::down_cast(x.m_target)); - target = src; - } else if (ASR::is_a(*x.m_target)) { - self().visit_TupleItem(*ASR::down_cast(x.m_target)); - target = src; - } else if (ASR::is_a(*x.m_target)) { - ASR::TupleConstant_t *tup_c = ASR::down_cast(x.m_target); - std::string src_tmp = "", val_name = ""; - if (ASR::is_a(*x.m_value)) { - ASR::TupleConstant_t *tup_const = ASR::down_cast(x.m_value); - self().visit_TupleConstant(*tup_const); - val_name = const_var_names[get_hash((ASR::asr_t*)tup_const)]; - } else if (ASR::is_a(*x.m_value)) { - self().visit_FunctionCall(*ASR::down_cast(x.m_value)); - ASR::Tuple_t* t = ASR::down_cast(tup_c->m_type); - std::string tuple_type_c = c_ds_api->get_tuple_type(t); - const_name += std::to_string(const_vars_count); - const_vars_count += 1; - const_name = current_scope->get_unique_name(const_name); - src_tmp += indent + tuple_type_c + " " + const_name + " = " + src + ";\n"; - val_name = const_name; - } else { - visit_Var(*ASR::down_cast(x.m_value)); - val_name = src; - } - for (size_t i=0; in_elements; i++) { - self().visit_expr(*tup_c->m_elements[i]); - ASR::ttype_t *t = ASRUtils::expr_type(tup_c->m_elements[i]); - src_tmp += indent + c_ds_api->get_deepcopy(t, - val_name + ".element_" + std::to_string(i), src) + "\n"; - } - src = check_tmp_buffer() + src_tmp; - return; - } else { - LCOMPILERS_ASSERT(false) - } - from_std_vector_helper.clear(); - if( ASR::is_a(*x.m_value) ) { - src = ""; - return ; - } - self().visit_expr(*x.m_value); - std::string value = src; - ASR::ttype_t* value_type = ASRUtils::expr_type(x.m_value); - if( ASR::is_a(*value_type) ) { - if (ASR::is_a(*x.m_value) || - ASR::is_a(*x.m_value) || - ASR::is_a(*x.m_value)) { - value = "&" + value; - } - } - if( ASR::is_a(*m_target_type) ) { - if (ASR::is_a(*x.m_target) || - ASR::is_a(*x.m_target) || - ASR::is_a(*x.m_target)) { - target = "&" + target; - } - } - if( !from_std_vector_helper.empty() ) { - src = from_std_vector_helper; - } else { - src.clear(); - } - src = check_tmp_buffer(); - if( is_target_list && is_value_list ) { - ASR::List_t* list_target = ASR::down_cast(ASRUtils::expr_type(x.m_target)); - std::string list_dc_func = c_ds_api->get_list_deepcopy_func(list_target); - if (ASR::is_a(*x.m_value)) { - src += indent + list_dc_func + "(" + value + ", &" + target + ");\n\n"; - } else { - src += indent + list_dc_func + "(&" + value + ", &" + target + ");\n\n"; - } - } else if ( is_target_tup && is_value_tup ) { - ASR::Tuple_t* tup_target = ASR::down_cast(ASRUtils::expr_type(x.m_target)); - std::string dc_func = c_ds_api->get_tuple_deepcopy_func(tup_target); - src += indent + dc_func + "(" + value + ", &" + target + ");\n"; - } else if ( is_target_dict && is_value_dict ) { - ASR::Dict_t* d_target = ASR::down_cast(ASRUtils::expr_type(x.m_target)); - std::string dc_func = c_ds_api->get_dict_deepcopy_func(d_target); - src += indent + dc_func + "(&" + value + ", &" + target + ");\n"; - } else { - if( is_c ) { - std::string alloc = ""; - if (alloc_return_var) { - // char * return variable; - alloc = indent + target + " = NULL;\n"; - } - if( ASRUtils::is_array(m_target_type) && ASRUtils::is_array(m_value_type) ) { - ASR::dimension_t* m_target_dims = nullptr; - size_t n_target_dims = ASRUtils::extract_dimensions_from_ttype(m_target_type, m_target_dims); - ASR::dimension_t* m_value_dims = nullptr; - size_t n_value_dims = ASRUtils::extract_dimensions_from_ttype(m_value_type, m_value_dims); - bool is_target_data_only_array = ASRUtils::is_fixed_size_array(m_target_dims, n_target_dims) && - ASR::is_a(*ASRUtils::get_asr_owner(x.m_target)); - bool is_value_data_only_array = ASRUtils::is_fixed_size_array(m_value_dims, n_value_dims) && - ASR::is_a(*ASRUtils::get_asr_owner(x.m_value)); - if( is_target_data_only_array || is_value_data_only_array ) { - int64_t target_size = -1, value_size = -1; - if( !is_target_data_only_array ) { - target = target + "->data"; - } else { - target_size = ASRUtils::get_fixed_size_of_array(m_target_dims, n_target_dims); - } - if( !is_value_data_only_array ) { - value = value + "->data"; - } else { - value_size = ASRUtils::get_fixed_size_of_array(m_value_dims, n_value_dims); - } - if( target_size != -1 && value_size != -1 ) { - LCOMPILERS_ASSERT(target_size == value_size); - } - int64_t array_size = -1; - if( target_size != -1 ) { - array_size = target_size; - } else { - array_size = value_size; - } - src += indent + "memcpy(" + target + ", " + value + ", " + std::to_string(array_size) + "*sizeof(" + - CUtils::get_c_type_from_ttype_t(m_target_type) + "));\n"; - } else { - src += alloc + indent + c_ds_api->get_deepcopy(m_target_type, value, target) + "\n"; - } - } else { - src += alloc + indent + c_ds_api->get_deepcopy(m_target_type, value, target) + "\n"; - } - } else { - src += indent + c_ds_api->get_deepcopy(m_target_type, value, target) + "\n"; - } - } - from_std_vector_helper.clear(); - } - - void visit_IntegerConstant(const ASR::IntegerConstant_t &x) { - src = std::to_string(x.m_n); - last_expr_precedence = 2; - } - - void visit_RealConstant(const ASR::RealConstant_t &x) { - // TODO: remove extra spaces from the front of double_to_scientific result - src = double_to_scientific(x.m_r); - last_expr_precedence = 2; - } - - - void visit_StringConstant(const ASR::StringConstant_t &x) { - src = "\""; - std::string s = x.m_s; - for (size_t idx=0; idx < s.size(); idx++) { - src += s[idx]; - } - src += "\""; - last_expr_precedence = 2; - } - - void visit_StringConcat(const ASR::StringConcat_t& x) { - is_string_concat_present = true; - CHECK_FAST_C_CPP(compiler_options, x) - self().visit_expr(*x.m_left); - std::string left = std::move(src); - self().visit_expr(*x.m_right); - std::string right = std::move(src); - if( is_c ) { - src = "strcat_(" + left + ", " + right +")"; - } else { - src = left + " + " + right; - } - } - - void visit_ListConstant(const ASR::ListConstant_t& x) { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - const_name += std::to_string(const_vars_count); - const_vars_count += 1; - const_name = current_scope->get_unique_name(const_name); - std::string var_name = const_name; - const_var_names[get_hash((ASR::asr_t*)&x)] = var_name; - ASR::List_t* t = ASR::down_cast(x.m_type); - std::string list_type_c = c_ds_api->get_list_type(t); - std::string src_tmp = ""; - src_tmp += indent + list_type_c + " " + var_name + ";\n"; - std::string list_init_func = c_ds_api->get_list_init_func(t); - src_tmp += indent + list_init_func + "(&" + var_name + ", " + - std::to_string(x.n_args) + ");\n"; - for( size_t i = 0; i < x.n_args; i++ ) { - self().visit_expr(*x.m_args[i]); - if( ASR::is_a(*t->m_type) ) { - src_tmp += indent + var_name + ".data[" + std::to_string(i) +"] = NULL;\n"; - } - src_tmp += indent + c_ds_api->get_deepcopy(t->m_type, src, - var_name + ".data[" + std::to_string(i) +"]") + "\n"; - } - src_tmp += indent + var_name + ".current_end_point = " + std::to_string(x.n_args) + ";\n"; - src = var_name; - tmp_buffer_src.push_back(src_tmp); - } - - void visit_TupleConstant(const ASR::TupleConstant_t& x) { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - const_name += std::to_string(const_vars_count); - const_vars_count += 1; - const_name = current_scope->get_unique_name(const_name); - std::string var_name = const_name; - const_var_names[get_hash((ASR::asr_t*)&x)] = var_name; - ASR::Tuple_t* t = ASR::down_cast(x.m_type); - std::string tuple_type_c = c_ds_api->get_tuple_type(t); - std::string src_tmp = ""; - src_tmp += indent + tuple_type_c + " " + var_name + ";\n"; - for (size_t i = 0; i < x.n_elements; i++) { - self().visit_expr(*x.m_elements[i]); - std::string ele = ".element_" + std::to_string(i); - if (ASR::is_a(*t->m_type[i])) { - src_tmp += indent + var_name + ele + " = NULL;\n"; - } - src_tmp += indent + c_ds_api->get_deepcopy(t->m_type[i], src, var_name + ele) + "\n"; - } - src_tmp += indent + var_name + ".length" + " = " + std::to_string(x.n_elements) + ";\n"; - src = var_name; - tmp_buffer_src.push_back(src_tmp); - } - - void visit_DictConstant(const ASR::DictConstant_t& x) { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - const_name += std::to_string(const_vars_count); - const_vars_count += 1; - const_name = current_scope->get_unique_name(const_name); - std::string var_name = const_name; - const_var_names[get_hash((ASR::asr_t*)&x)] = var_name; - ASR::Dict_t* t = ASR::down_cast(x.m_type); - std::string dict_type_c = c_ds_api->get_dict_type(t); - std::string src_tmp = ""; - src_tmp += indent + dict_type_c + " " + var_name + ";\n"; - std::string dict_init_func = c_ds_api->get_dict_init_func(t); - std::string dict_ins_func = c_ds_api->get_dict_insert_func(t); - src_tmp += indent + dict_init_func + "(&" + var_name + ", " + - std::to_string(x.n_keys) + " + 1);\n"; - for ( size_t i = 0; i < x.n_keys; i++ ) { - self().visit_expr(*x.m_keys[i]); - std::string k, v; - k = std::move(src); - self().visit_expr(*x.m_values[i]); - v = std::move(src); - src_tmp += indent + dict_ins_func + "(&" + var_name + ", " +\ - k + ", " + v + ");\n"; - } - src = var_name; - tmp_buffer_src.push_back(src_tmp); - } - - void visit_TupleCompare(const ASR::TupleCompare_t& x) { - ASR::ttype_t* type = ASRUtils::expr_type(x.m_left); - std::string tup_cmp_func = c_ds_api->get_compare_func(type); - bracket_open++; - self().visit_expr(*x.m_left); - std::string left = std::move(src); - self().visit_expr(*x.m_right); - std::string right = std::move(src); - bracket_open--; - std::string indent(indentation_level * indentation_spaces, ' '); - src = tup_cmp_func + "(" + left + ", " + right + ")"; - if (x.m_op == ASR::cmpopType::NotEq) { - src = "!" + src; - } - src = check_tmp_buffer() + src; - } - - void visit_DictInsert(const ASR::DictInsert_t& x) { - ASR::ttype_t* t_ttype = ASRUtils::expr_type(x.m_a); - ASR::Dict_t* t = ASR::down_cast(t_ttype); - std::string dict_insert_fun = c_ds_api->get_dict_insert_func(t); - self().visit_expr(*x.m_a); - std::string d_var = std::move(src); - self().visit_expr(*x.m_key); - std::string key = std::move(src); - self().visit_expr(*x.m_value); - std::string val = std::move(src); - std::string indent(indentation_level * indentation_spaces, ' '); - src = indent + dict_insert_fun + "(&" + d_var + ", " + key + ", " + val + ");\n"; - } - - void visit_DictItem(const ASR::DictItem_t& x) { - ASR::Dict_t* dict_type = ASR::down_cast( - ASRUtils::expr_type(x.m_a)); - std::string dict_get_fun = c_ds_api->get_dict_get_func(dict_type); - - this->visit_expr(*x.m_a); - std::string d_var = std::move(src); - - this->visit_expr(*x.m_key); - std::string k = std::move(src); - - src = dict_get_fun + "(&" + d_var + ", " + k + ")"; - } - - void visit_ListAppend(const ASR::ListAppend_t& x) { - ASR::ttype_t* t_ttype = ASRUtils::expr_type(x.m_a); - ASR::List_t* t = ASR::down_cast(t_ttype); - std::string list_append_func = c_ds_api->get_list_append_func(t); - bracket_open++; - self().visit_expr(*x.m_a); - std::string list_var = std::move(src); - self().visit_expr(*x.m_ele); - std::string element = std::move(src); - bracket_open--; - std::string indent(indentation_level * indentation_spaces, ' '); - src = check_tmp_buffer(); - src += indent + list_append_func + "(&" + list_var + ", " + element + ");\n"; - } - - void visit_ListConcat(const ASR::ListConcat_t& x) { - CHECK_FAST_C_CPP(compiler_options, x) - ASR::List_t* t = ASR::down_cast(x.m_type); - std::string list_concat_func = c_ds_api->get_list_concat_func(t); - bracket_open++; - self().visit_expr(*x.m_left); - std::string left = std::move(src); - if (!ASR::is_a(*x.m_left)) { - left = "&" + left; - } - self().visit_expr(*x.m_right); - bracket_open--; - std::string rig = std::move(src); - if (!ASR::is_a(*x.m_right)) { - rig = "&" + rig; - } - src = check_tmp_buffer() + list_concat_func + "(" + left + ", " + rig + ")"; - } - - void visit_ListSection(const ASR::ListSection_t& x) { - CHECK_FAST_C_CPP(compiler_options, x) - std::string left, right, step, l_present, r_present; - bracket_open++; - if (x.m_section.m_left) { - self().visit_expr(*x.m_section.m_left); - left = src; - l_present = "true"; - } else { - left = "0"; - l_present = "false"; - } - if (x.m_section.m_right) { - self().visit_expr(*x.m_section.m_right); - right = src; - r_present = "true"; - } else { - right = "0"; - r_present = "false"; - } - if (x.m_section.m_step) { - self().visit_expr(*x.m_section.m_step); - step = src; - } else { - step = "1"; - } - self().visit_expr(*x.m_a); - bracket_open--; - ASR::ttype_t* t_ttype = ASRUtils::expr_type(x.m_a); - ASR::List_t* t = ASR::down_cast(t_ttype); - std::string list_var = std::move(src); - std::string list_type_c = c_ds_api->get_list_type(t); - std::string list_section_func = c_ds_api->get_list_section_func(t); - std::string indent(indentation_level * indentation_spaces, ' '); - const_name += std::to_string(const_vars_count); - const_vars_count += 1; - const_name = current_scope->get_unique_name(const_name); - std::string var_name = const_name, tmp_src_gen = ""; - tmp_src_gen = indent + list_type_c + "* " + var_name + " = "; - tmp_src_gen += list_section_func + "(&" + list_var + ", " + left + ", " + - right + ", " + step + ", " + l_present + ", " + r_present + ");\n"; - const_var_names[get_hash((ASR::asr_t*)&x)] = var_name; - tmp_buffer_src.push_back(tmp_src_gen); - src = "* " + var_name; - } - - void visit_ListClear(const ASR::ListClear_t& x) { - ASR::ttype_t* t_ttype = ASRUtils::expr_type(x.m_a); - ASR::List_t* t = ASR::down_cast(t_ttype); - std::string list_clear_func = c_ds_api->get_list_clear_func(t); - bracket_open++; - self().visit_expr(*x.m_a); - bracket_open--; - std::string list_var = std::move(src); - std::string indent(indentation_level * indentation_spaces, ' '); - src = check_tmp_buffer() + indent + list_clear_func + "(&" + list_var + ");\n"; - } - - void visit_ListCompare(const ASR::ListCompare_t& x) { - CHECK_FAST_C_CPP(compiler_options, x) - ASR::ttype_t* type = ASRUtils::expr_type(x.m_left); - std::string list_cmp_func = c_ds_api->get_compare_func(type); - bracket_open++; - self().visit_expr(*x.m_left); - std::string left = std::move(src); - self().visit_expr(*x.m_right); - bracket_open--; - std::string right = std::move(src), tmp_gen= ""; - std::string indent(indentation_level * indentation_spaces, ' '); - std::string val = list_cmp_func + "(" + left + ", " + right + ")"; - if (x.m_op == ASR::cmpopType::NotEq) { - val = "!" + val; - } - src = check_tmp_buffer() + val; - } - - void visit_ListInsert(const ASR::ListInsert_t& x) { - ASR::ttype_t* t_ttype = ASRUtils::expr_type(x.m_a); - ASR::List_t* t = ASR::down_cast(t_ttype); - std::string list_insert_func = c_ds_api->get_list_insert_func(t); - bracket_open++; - self().visit_expr(*x.m_a); - std::string list_var = std::move(src); - self().visit_expr(*x.m_ele); - std::string element = std::move(src); - self().visit_expr(*x.m_pos); - bracket_open--; - std::string pos = std::move(src); - std::string indent(indentation_level * indentation_spaces, ' '); - src = check_tmp_buffer(); - src += indent + list_insert_func + "(&" + list_var + ", " + pos + ", " + element + ");\n"; - } - - void visit_ListRemove(const ASR::ListRemove_t& x) { - ASR::ttype_t* t_ttype = ASRUtils::expr_type(x.m_a); - ASR::List_t* t = ASR::down_cast(t_ttype); - std::string list_remove_func = c_ds_api->get_list_remove_func(t); - bracket_open++; - self().visit_expr(*x.m_a); - std::string list_var = std::move(src); - self().visit_expr(*x.m_ele); - bracket_open--; - std::string element = std::move(src); - std::string indent(indentation_level * indentation_spaces, ' '); - src = check_tmp_buffer(); - src += indent + list_remove_func + "(&" + list_var + ", " + element + ");\n"; - } - - void visit_ListLen(const ASR::ListLen_t& x) { - CHECK_FAST_C_CPP(compiler_options, x) - self().visit_expr(*x.m_arg); - src = src + ".current_end_point"; - } - - void visit_TupleLen(const ASR::TupleLen_t& x) { - CHECK_FAST_C_CPP(compiler_options, x) - self().visit_expr(*x.m_arg); - src = src + ".length"; - } - - void visit_DictLen(const ASR::DictLen_t& x) { - CHECK_FAST_C_CPP(compiler_options, x) - ASR::ttype_t* t_ttype = ASRUtils::expr_type(x.m_arg); - ASR::Dict_t* t = ASR::down_cast(t_ttype); - std::string dict_len_fun = c_ds_api->get_dict_len_func(t); - bracket_open++; - self().visit_expr(*x.m_arg); - src = dict_len_fun + "(&" + src + ")"; - bracket_open--; - } - - void visit_DictPop(const ASR::DictPop_t& x) { - CHECK_FAST_C_CPP(compiler_options, x) - ASR::ttype_t* t_ttype = ASRUtils::expr_type(x.m_a); - ASR::Dict_t* t = ASR::down_cast(t_ttype); - std::string dict_pop_fun = c_ds_api->get_dict_pop_func(t); - bracket_open++; - self().visit_expr(*x.m_a); - std::string d = std::move(src); - self().visit_expr(*x.m_key); - std::string k = std::move(src); - src = dict_pop_fun + "(&" + d + ", " + k + ")"; - bracket_open--; - } - - void visit_ListItem(const ASR::ListItem_t& x) { - CHECK_FAST_C_CPP(compiler_options, x) - self().visit_expr(*x.m_a); - std::string list_var = std::move(src); - self().visit_expr(*x.m_pos); - std::string pos = std::move(src); - // TODO: check for out of bound indices - src = list_var + ".data[" + pos + "]"; - } - - void visit_TupleItem(const ASR::TupleItem_t& x) { - CHECK_FAST_C_CPP(compiler_options, x) - self().visit_expr(*x.m_a); - std::string tup_var = std::move(src); - ASR::expr_t *pos_val = ASRUtils::expr_value(x.m_pos); - if (pos_val == nullptr) { - throw CodeGenError("Compile time constant values are supported in Tuple Item yet"); - } - self().visit_expr(*pos_val); - std::string pos = std::move(src); - // TODO: check for out of bound indices - src = tup_var + ".element_" + pos; - } - - void visit_LogicalConstant(const ASR::LogicalConstant_t &x) { - if (x.m_value == true) { - src = "true"; - } else { - src = "false"; - } - last_expr_precedence = 2; - } - - void visit_Var(const ASR::Var_t &x) { - const ASR::symbol_t *s = ASRUtils::symbol_get_past_external(x.m_v); - ASR::Variable_t* sv = ASR::down_cast(s); - if( (sv->m_intent == ASRUtils::intent_in || - sv->m_intent == ASRUtils::intent_inout) && - is_c && ASRUtils::is_array(sv->m_type) && - ASRUtils::is_pointer(sv->m_type)) { - src = "(*" + std::string(ASR::down_cast(s)->m_name) + ")"; - } else { - src = std::string(ASR::down_cast(s)->m_name); - } - last_expr_precedence = 2; - } - - void visit_StructInstanceMember(const ASR::StructInstanceMember_t& x) { - CHECK_FAST_C_CPP(compiler_options, x) - std::string der_expr, member; - this->visit_expr(*x.m_v); - der_expr = std::move(src); - member = ASRUtils::symbol_name(ASRUtils::symbol_get_past_external(x.m_m)); - if( ASR::is_a(*x.m_v) || - ASR::is_a(*x.m_v) || - ASR::is_a(*x.m_v) ) { - src = der_expr + "." + member; - } else { - src = der_expr + "->" + member; - } - } - - void visit_UnionInstanceMember(const ASR::UnionInstanceMember_t& x) { - CHECK_FAST_C_CPP(compiler_options, x) - std::string der_expr, member; - this->visit_expr(*x.m_v); - der_expr = std::move(src); - member = ASRUtils::symbol_name(x.m_m); - src = der_expr + "." + member; - } - - void visit_Cast(const ASR::Cast_t &x) { - CHECK_FAST_C_CPP(compiler_options, x) - self().visit_expr(*x.m_arg); - switch (x.m_kind) { - case (ASR::cast_kindType::IntegerToReal) : { - int dest_kind = ASRUtils::extract_kind_from_ttype_t(x.m_type); - switch (dest_kind) { - case 4: src = "(float)(" + src + ")"; break; - case 8: src = "(double)(" + src + ")"; break; - default: throw CodeGenError("Cast IntegerToReal: Unsupported Kind " + std::to_string(dest_kind)); - } - last_expr_precedence = 2; - break; - } - case (ASR::cast_kindType::RealToInteger) : { - int dest_kind = ASRUtils::extract_kind_from_ttype_t(x.m_type); - src = "(int" + std::to_string(dest_kind * 8) + "_t)(" + src + ")"; - last_expr_precedence = 2; - break; - } - case (ASR::cast_kindType::RealToReal) : { - // In C++, we do not need to cast float to float explicitly: - // src = src; - break; - } - case (ASR::cast_kindType::IntegerToInteger) : { - // In C++, we do not need to cast int <-> long long explicitly: - // src = src; - break; - } - case (ASR::cast_kindType::ComplexToComplex) : { - break; - } - case (ASR::cast_kindType::IntegerToComplex) : { - if (is_c) { - headers.insert("complex"); - src = "CMPLX(" + src + ", 0)"; - } else { - src = "std::complex(" + src + ")"; - } - last_expr_precedence = 2; - break; - } - case (ASR::cast_kindType::ComplexToReal) : { - if (is_c) { - headers.insert("complex"); - src = "creal(" + src + ")"; - } else { - src = "std::real(" + src + ")"; - } - last_expr_precedence = 2; - break; - } - case (ASR::cast_kindType::RealToComplex) : { - if (is_c) { - headers.insert("complex"); - src = "CMPLX(" + src + ", 0.0)"; - } else { - src = "std::complex(" + src + ")"; - } - last_expr_precedence = 2; - break; - } - case (ASR::cast_kindType::LogicalToInteger) : { - src = "(int)(" + src + ")"; - last_expr_precedence = 2; - break; - } - case (ASR::cast_kindType::LogicalToCharacter) : { - src = "(" + src + " ? \"True\" : \"False\")"; - last_expr_precedence = 2; - break; - } - case (ASR::cast_kindType::IntegerToLogical) : { - src = "(bool)(" + src + ")"; - last_expr_precedence = 2; - break; - } - case (ASR::cast_kindType::LogicalToReal) : { - int dest_kind = ASRUtils::extract_kind_from_ttype_t(x.m_type); - switch (dest_kind) { - case 4: src = "(float)(" + src + ")"; break; - case 8: src = "(double)(" + src + ")"; break; - default: throw CodeGenError("Cast LogicalToReal: Unsupported Kind " + std::to_string(dest_kind)); - } - last_expr_precedence = 2; - break; - } - case (ASR::cast_kindType::RealToLogical) : { - src = "(bool)(" + src + ")"; - last_expr_precedence = 2; - break; - } - case (ASR::cast_kindType::CharacterToLogical) : { - src = "(bool)(strlen(" + src + ") > 0)"; - last_expr_precedence = 2; - break; - } - case (ASR::cast_kindType::ComplexToLogical) : { - src = "(bool)(" + src + ")"; - last_expr_precedence = 2; - break; - } - case (ASR::cast_kindType::IntegerToCharacter) : { - if (is_c) { - ASR::ttype_t *arg_type = ASRUtils::expr_type(x.m_arg); - int arg_kind = ASRUtils::extract_kind_from_ttype_t(arg_type); - switch (arg_kind) { - case 1: src = "_lfortran_int_to_str1(" + src + ")"; break; - case 2: src = "_lfortran_int_to_str2(" + src + ")"; break; - case 4: src = "_lfortran_int_to_str4(" + src + ")"; break; - case 8: src = "_lfortran_int_to_str8(" + src + ")"; break; - default: throw CodeGenError("Cast IntegerToCharacter: Unsupported Kind " + \ - std::to_string(arg_kind)); - } - - } else { - src = "std::to_string(" + src + ")"; - } - last_expr_precedence = 2; - break; - } - case (ASR::cast_kindType::CharacterToInteger) : { - if (is_c) { - src = "atoi(" + src + ")"; - } else { - src = "std::stoi(" + src + ")"; - } - last_expr_precedence = 2; - break; - } - case (ASR::cast_kindType::RealToCharacter) : { - if (is_c) { - ASR::ttype_t *arg_type = ASRUtils::expr_type(x.m_arg); - int arg_kind = ASRUtils::extract_kind_from_ttype_t(arg_type); - switch (arg_kind) { - case 4: src = "_lfortran_float_to_str4(" + src + ")"; break; - case 8: src = "_lfortran_float_to_str8(" + src + ")"; break; - default: throw CodeGenError("Cast RealToCharacter: Unsupported Kind " + \ - std::to_string(arg_kind)); - } - } else { - src = "std::to_string(" + src + ")"; - } - last_expr_precedence = 2; - break; - } - default : throw CodeGenError("Cast kind " + std::to_string(x.m_kind) + " not implemented", - x.base.base.loc); - } - } - - void visit_IntegerBitLen(const ASR::IntegerBitLen_t& x) { - CHECK_FAST_C_CPP(compiler_options, x) - self().visit_expr(*x.m_a); - int arg_kind = ASRUtils::extract_kind_from_ttype_t(x.m_type); - switch (arg_kind) { - case 1: src = "_lpython_bit_length1(" + src + ")"; break; - case 2: src = "_lpython_bit_length2(" + src + ")"; break; - case 4: src = "_lpython_bit_length4(" + src + ")"; break; - case 8: src = "_lpython_bit_length8(" + src + ")"; break; - default: throw CodeGenError("Unsupported Integer Kind: " + \ - std::to_string(arg_kind)); - } - } - - void visit_IntegerCompare(const ASR::IntegerCompare_t &x) { - handle_Compare(x); - } - - void visit_RealCompare(const ASR::RealCompare_t &x) { - handle_Compare(x); - } - - void visit_ComplexCompare(const ASR::ComplexCompare_t &x) { - handle_Compare(x); - } - - void visit_LogicalCompare(const ASR::LogicalCompare_t &x) { - handle_Compare(x); - } - - void visit_StringCompare(const ASR::StringCompare_t &x) { - handle_Compare(x); - } - - template - void handle_Compare(const T &x) { - CHECK_FAST_C_CPP(compiler_options, x) - self().visit_expr(*x.m_left); - std::string left = std::move(src); - int left_precedence = last_expr_precedence; - self().visit_expr(*x.m_right); - std::string right = std::move(src); - int right_precedence = last_expr_precedence; - switch (x.m_op) { - case (ASR::cmpopType::Eq) : { last_expr_precedence = 10; break; } - case (ASR::cmpopType::Gt) : { last_expr_precedence = 9; break; } - case (ASR::cmpopType::GtE) : { last_expr_precedence = 9; break; } - case (ASR::cmpopType::Lt) : { last_expr_precedence = 9; break; } - case (ASR::cmpopType::LtE) : { last_expr_precedence = 9; break; } - case (ASR::cmpopType::NotEq): { last_expr_precedence = 10; break; } - default : LCOMPILERS_ASSERT(false); // should never happen - } - if (left_precedence <= last_expr_precedence) { - src += left; - } else { - src += "(" + left + ")"; - } - std::string op_str = ASRUtils::cmpop_to_str(x.m_op); - if( T::class_type == ASR::exprType::StringCompare && is_c ) { - src = "strcmp(" + left + ", " + right + ") " + op_str + " 0"; - } else { - src += op_str; - if (right_precedence <= last_expr_precedence) { - src += right; - } else { - src += "(" + right + ")"; - } - } - } - - void visit_IntegerBitNot(const ASR::IntegerBitNot_t& x) { - CHECK_FAST_C_CPP(compiler_options, x) - self().visit_expr(*x.m_arg); - int expr_precedence = last_expr_precedence; - last_expr_precedence = 3; - if (expr_precedence <= last_expr_precedence) { - src = "~" + src; - } else { - src = "~(" + src + ")"; - } - } - - void visit_IntegerUnaryMinus(const ASR::IntegerUnaryMinus_t &x) { - handle_UnaryMinus(x); - } - - void visit_RealUnaryMinus(const ASR::RealUnaryMinus_t &x) { - handle_UnaryMinus(x); - } - - void visit_ComplexUnaryMinus(const ASR::ComplexUnaryMinus_t &x) { - handle_UnaryMinus(x); - } - - template - void handle_UnaryMinus(const T &x) { - CHECK_FAST_C_CPP(compiler_options, x) - self().visit_expr(*x.m_arg); - int expr_precedence = last_expr_precedence; - last_expr_precedence = 3; - if (expr_precedence <= last_expr_precedence) { - src = "-" + src; - } else { - src = "-(" + src + ")"; - } - } - - void visit_ComplexRe(const ASR::ComplexRe_t &x) { - headers.insert("complex"); - CHECK_FAST_C_CPP(compiler_options, x) - self().visit_expr(*x.m_arg); - if (is_c) { - src = "creal(" + src + ")"; - } else { - src = src + ".real()"; - } - } - - void visit_ComplexIm(const ASR::ComplexIm_t &x) { - headers.insert("complex"); - CHECK_FAST_C_CPP(compiler_options, x) - self().visit_expr(*x.m_arg); - if (is_c) { - src = "cimag(" + src + ")"; - } else { - src = src + ".imag()"; - } - } - - void visit_LogicalNot(const ASR::LogicalNot_t &x) { - CHECK_FAST_C_CPP(compiler_options, x) - self().visit_expr(*x.m_arg); - int expr_precedence = last_expr_precedence; - last_expr_precedence = 3; - if (expr_precedence <= last_expr_precedence) { - src = "!" + src; - } else { - src = "!(" + src + ")"; - } - } - - void visit_GetPointer(const ASR::GetPointer_t& x) { - CHECK_FAST_C_CPP(compiler_options, x) - self().visit_expr(*x.m_arg); - std::string arg_src = std::move(src); - std::string addr_prefix = "&"; - if( ASRUtils::is_array(ASRUtils::expr_type(x.m_arg)) || - ASR::is_a(*ASRUtils::expr_type(x.m_arg)) ) { - addr_prefix.clear(); - } - src = addr_prefix + arg_src; - } - - void visit_PointerToCPtr(const ASR::PointerToCPtr_t& x) { - CHECK_FAST_C_CPP(compiler_options, x) - self().visit_expr(*x.m_arg); - std::string arg_src = std::move(src); - if( ASRUtils::is_array(ASRUtils::expr_type(x.m_arg)) ) { - arg_src += "->data"; - } - std::string type_src = CUtils::get_c_type_from_ttype_t(x.m_type); - src = "(" + type_src + ") " + arg_src; - } - - void visit_IntegerBinOp(const ASR::IntegerBinOp_t &x) { - handle_BinOp(x); - } - - void visit_RealBinOp(const ASR::RealBinOp_t &x) { - handle_BinOp(x); - } - - void visit_ComplexBinOp(const ASR::ComplexBinOp_t &x) { - handle_BinOp(x); - } - - template - void handle_BinOp(const T &x) { - CHECK_FAST_C_CPP(compiler_options, x) - self().visit_expr(*x.m_left); - std::string left = std::move(src); - int left_precedence = last_expr_precedence; - self().visit_expr(*x.m_right); - std::string right = std::move(src); - int right_precedence = last_expr_precedence; - switch (x.m_op) { - case (ASR::binopType::Add) : { last_expr_precedence = 6; break; } - case (ASR::binopType::Sub) : { last_expr_precedence = 6; break; } - case (ASR::binopType::Mul) : { last_expr_precedence = 5; break; } - case (ASR::binopType::Div) : { last_expr_precedence = 5; break; } - case (ASR::binopType::BitAnd) : { last_expr_precedence = 11; break; } - case (ASR::binopType::BitOr) : { last_expr_precedence = 13; break; } - case (ASR::binopType::BitXor) : { last_expr_precedence = 12; break; } - case (ASR::binopType::BitLShift) : { last_expr_precedence = 7; break; } - case (ASR::binopType::BitRShift) : { last_expr_precedence = 7; break; } - case (ASR::binopType::Pow) : { - src = "pow(" + left + ", " + right + ")"; - if (is_c) { - headers.insert("math"); - } else { - src = "std::" + src; - } - return; - } - default: throw CodeGenError("BinOp: " + std::to_string(x.m_op) + " operator not implemented yet"); - } - src = ""; - if (left_precedence == 3) { - src += "(" + left + ")"; - } else { - if (left_precedence <= last_expr_precedence) { - src += left; - } else { - src += "(" + left + ")"; - } - } - src += ASRUtils::binop_to_str_python(x.m_op); - if (right_precedence == 3) { - src += "(" + right + ")"; - } else if (x.m_op == ASR::binopType::Sub || x.m_op == ASR::binopType::Div) { - if (right_precedence < last_expr_precedence) { - src += right; - } else { - src += "(" + right + ")"; - } - } else { - if (right_precedence <= last_expr_precedence) { - src += right; - } else { - src += "(" + right + ")"; - } - } - } - - void visit_LogicalBinOp(const ASR::LogicalBinOp_t &x) { - CHECK_FAST_C_CPP(compiler_options, x) - self().visit_expr(*x.m_left); - std::string left = std::move(src); - int left_precedence = last_expr_precedence; - self().visit_expr(*x.m_right); - std::string right = std::move(src); - int right_precedence = last_expr_precedence; - switch (x.m_op) { - case (ASR::logicalbinopType::And): { - last_expr_precedence = 14; - break; - } - case (ASR::logicalbinopType::Or): { - last_expr_precedence = 15; - break; - } - case (ASR::logicalbinopType::NEqv): { - last_expr_precedence = 10; - break; - } - case (ASR::logicalbinopType::Eqv): { - last_expr_precedence = 10; - break; - } - default : throw CodeGenError("Unhandled switch case"); - } - - if (left_precedence <= last_expr_precedence) { - src += left; - } else { - src += "(" + left + ")"; - } - src += ASRUtils::logicalbinop_to_str_python(x.m_op); - if (right_precedence <= last_expr_precedence) { - src += right; - } else { - src += "(" + right + ")"; - } - } - - void visit_Allocate(const ASR::Allocate_t &x) { - std::string indent(indentation_level*indentation_spaces, ' '); - std::string out = indent + "// FIXME: allocate("; - for (size_t i=0; i(*tmp_expr) ) { - const ASR::Var_t* tmp_var = ASR::down_cast(tmp_expr); - tmp_sym = tmp_var->m_v; - } else { - throw CodeGenError("Cannot deallocate variables in expression " + - std::to_string(tmp_expr->type), - tmp_expr->base.loc); - } - //ASR::dimension_t* dims = x.m_args[i].m_dims; - //size_t n_dims = x.m_args[i].n_dims; - out += std::string(ASRUtils::symbol_name(tmp_sym)) + ", "; - } - out += ");\n"; - src = out; - } - - void visit_Assert(const ASR::Assert_t &x) { - std::string indent(indentation_level*indentation_spaces, ' '); - std::string out = indent; - if (x.m_msg) { - out += "assert (("; - self().visit_expr(*x.m_msg); - out += src + ", "; - self().visit_expr(*x.m_test); - out += src + "));\n"; - } else { - out += "assert ("; - self().visit_expr(*x.m_test); - out += src + ");\n"; - } - src = out; - } - - void visit_ExplicitDeallocate(const ASR::ExplicitDeallocate_t &x) { - std::string indent(indentation_level*indentation_spaces, ' '); - std::string out = indent + "// FIXME: deallocate("; - for (size_t i=0; i(*tmp_expr) ) { - const ASR::Var_t* tmp_var = ASR::down_cast(tmp_expr); - tmp_sym = tmp_var->m_v; - } else { - throw CodeGenError("Cannot deallocate variables in expression " + - std::to_string(tmp_expr->type), - tmp_expr->base.loc); - } - out += std::string(ASRUtils::symbol_name(tmp_sym)) + ", "; - } - out += ");\n"; - src = out; - } - - void visit_ImplicitDeallocate(const ASR::ImplicitDeallocate_t &x) { - std::string indent(indentation_level*indentation_spaces, ' '); - std::string out = indent + "// FIXME: implicit deallocate("; - for (size_t i=0; ivisit_expr(*x.m_test); - std::string var = std::move(src); - std::string out = indent + "if ("; - - for (size_t i = 0; i < x.n_body; i++) { - if (i > 0) - out += indent + "else if ("; - bracket_open++; - ASR::case_stmt_t* stmt = x.m_body[i]; - if (stmt->type == ASR::case_stmtType::CaseStmt) { - ASR::CaseStmt_t* case_stmt = ASR::down_cast(stmt); - for (size_t j = 0; j < case_stmt->n_test; j++) { - if (j > 0) - out += " || "; - this->visit_expr(*case_stmt->m_test[j]); - out += var + " == " + src; - } - out += ") {\n"; - bracket_open--; - indentation_level += 1; - for (size_t j = 0; j < case_stmt->n_body; j++) { - this->visit_stmt(*case_stmt->m_body[j]); - out += src; - } - out += indent + "}\n"; - indentation_level -= 1; - } else { - ASR::CaseStmt_Range_t* case_stmt_range - = ASR::down_cast(stmt); - std::string left, right; - if (case_stmt_range->m_start) { - this->visit_expr(*case_stmt_range->m_start); - left = std::move(src); - } - if (case_stmt_range->m_end) { - this->visit_expr(*case_stmt_range->m_end); - right = std::move(src); - } - if (left.empty() && right.empty()) { - diag.codegen_error_label( - "Empty range in select statement", { x.base.base.loc }, ""); - throw Abort(); - } - if (left.empty()) { - out += var + " <= " + right; - } else if (right.empty()) { - out += var + " >= " + left; - } else { - out += left + " <= " + var + " <= " + right; - } - out += ") {\n"; - bracket_open--; - indentation_level += 1; - for (size_t j = 0; j < case_stmt_range->n_body; j++) { - this->visit_stmt(*case_stmt_range->m_body[j]); - out += src; - } - out += indent + "}\n"; - indentation_level -= 1; - } - } - if (x.n_default) { - out += indent + "else {\n"; - indentation_level += 1; - for (size_t i = 0; i < x.n_default; i++) { - this->visit_stmt(*x.m_default[i]); - out += src; - } - out += indent + "}\n"; - indentation_level -= 1; - } - src = check_tmp_buffer() + out; - } - - void visit_WhileLoop(const ASR::WhileLoop_t &x) { - std::string indent(indentation_level*indentation_spaces, ' '); - bracket_open++; - std::string out = indent + "while ("; - self().visit_expr(*x.m_test); - out += src + ") {\n"; - bracket_open--; - out = check_tmp_buffer() + out; - indentation_level += 1; - for (size_t i=0; im_return_var) { - src = indent + "return " - + ASRUtils::EXPR2VAR(current_function->m_return_var)->m_name - + ";\n"; - } else { - src = indent + "return;\n"; - } - } - - void visit_GoToTarget(const ASR::GoToTarget_t & /* x */) { - // Ignore for now - src = ""; - } - - void visit_Stop(const ASR::Stop_t &x) { - if (x.m_code) { - self().visit_expr(*x.m_code); - } else { - src = "0"; - } - std::string indent(indentation_level*indentation_spaces, ' '); - src = indent + "exit(" + src + ");\n"; - } - - void visit_ErrorStop(const ASR::ErrorStop_t & /* x */) { - std::string indent(indentation_level*indentation_spaces, ' '); - if (is_c) { - src = indent + "fprintf(stderr, \"ERROR STOP\");\n"; - } else { - src = indent + "std::cerr << \"ERROR STOP\" << std::endl;\n"; - } - src += indent + "exit(1);\n"; - } - - void visit_ImpliedDoLoop(const ASR::ImpliedDoLoop_t &/*x*/) { - std::string indent(indentation_level*indentation_spaces, ' '); - std::string out = indent + " /* FIXME: implied do loop */ "; - src = out; - last_expr_precedence = 2; - } - - void visit_DoLoop(const ASR::DoLoop_t &x) { - std::string current_body_copy = current_body; - current_body = ""; - std::string loop_end_decl = ""; - std::string indent(indentation_level*indentation_spaces, ' '); - std::string out = indent + "for ("; - ASR::Variable_t *loop_var = ASRUtils::EXPR2VAR(x.m_head.m_v); - std::string lvname=loop_var->m_name; - ASR::expr_t *a=x.m_head.m_start; - ASR::expr_t *b=x.m_head.m_end; - ASR::expr_t *c=x.m_head.m_increment; - LCOMPILERS_ASSERT(a); - LCOMPILERS_ASSERT(b); - int increment; - bool is_c_constant = false; - if (!c) { - increment = 1; - is_c_constant = true; - } else { - ASR::expr_t* c_value = ASRUtils::expr_value(c); - is_c_constant = ASRUtils::extract_value(c_value, increment); - } - - if( is_c_constant ) { - std::string cmp_op; - if (increment > 0) { - cmp_op = "<="; - } else { - cmp_op = ">="; - } - - out += lvname + "="; - self().visit_expr(*a); - out += src + "; " + lvname + cmp_op; - self().visit_expr(*b); - out += src + "; " + lvname; - if (increment == 1) { - out += "++"; - } else if (increment == -1) { - out += "--"; - } else { - out += "+=" + std::to_string(increment); - } - } else { - this->visit_expr(*c); - std::string increment_ = std::move(src); - self().visit_expr(*b); - std::string do_loop_end = std::move(src); - std::string do_loop_end_name = current_scope->get_unique_name( - "loop_end___" + std::to_string(loop_end_count)); - loop_end_count += 1; - loop_end_decl = indent + CUtils::get_c_type_from_ttype_t(ASRUtils::expr_type(b), is_c) + - " " + do_loop_end_name + " = " + do_loop_end + ";\n"; - out += lvname + " = "; - self().visit_expr(*a); - out += src + "; "; - out += "((" + increment_ + " >= 0) && (" + - lvname + " <= " + do_loop_end_name + ")) || ((" - + increment_ + " < 0) && (" + lvname + " >= " - + do_loop_end_name + ")); " + lvname; - out += " += " + increment_; - } - - out += ") {\n"; - indentation_level += 1; - for (size_t i=0; i( - ASRUtils::symbol_get_past_external(x.m_name)); - // TODO: use a mapping with a hash(s) instead: - std::string sym_name = s->m_name; - if (sym_name == "exit") { - sym_name = "_xx_lcompilers_changed_exit_xx"; - } - if (sym_name == "main") { - sym_name = "_xx_lcompilers_changed_main_xx"; - } - std::string out = indent + sym_name + "("; - for (size_t i=0; i(*x.m_args[i].m_value)) { - ASR::Variable_t *arg = ASRUtils::EXPR2VAR(x.m_args[i].m_value); - std::string arg_name = arg->m_name; - if( ASRUtils::is_array(arg->m_type) && - ASRUtils::is_pointer(arg->m_type) ) { - out += "&" + arg_name; - } else { - out += arg_name; - } - } else { - self().visit_expr(*x.m_args[i].m_value); - if( ASR::is_a(*x.m_args[i].m_value) && - ASR::is_a(*ASRUtils::expr_type(x.m_args[i].m_value)) ) { - out += "&" + src; - } else { - out += src; - } - } - if (i < x.n_args-1) out += ", "; - } - out += ");\n"; - src = out; - } - -}; - -} // namespace LCompilers - -#endif // LFORTRAN_ASR_TO_C_CPP_H diff --git a/src/libasr/codegen/asr_to_cpp.cpp b/src/libasr/codegen/asr_to_cpp.cpp deleted file mode 100644 index 593bebafb4..0000000000 --- a/src/libasr/codegen/asr_to_cpp.cpp +++ /dev/null @@ -1,760 +0,0 @@ -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace LCompilers { - -std::string format_type(const std::string &dims, const std::string &type, - const std::string &name, bool use_ref, bool dummy, bool use_kokko=true, - std::string kokko_ref="&", bool use_name=false, size_t size=0) -{ - std::string fmt; - if (dims.size() == 0) { - std::string ref; - if (use_ref) ref = "&"; - fmt = type + " " + ref + name; - } else { - if (dummy) { - std::string c; - if (!use_ref) c = "const "; - if( use_kokko ) { - fmt = "const Kokkos::View<" + c + type + dims + "> &" + name; - } else { - fmt = c + type + dims + " " + name; - } - } else { - if( use_kokko ) { - fmt = "Kokkos::View<" + type + dims + ">" + kokko_ref + " " + name; - if( use_name ) { - fmt += "(\"" + name + "\""; - if( size > 0 ) { - fmt += ", " + std::to_string(size); - } - fmt += ")"; - } - } else { - fmt = type + dims + " " + name; - } - } - } - return fmt; -} - -std::string trim_dims(std::string &dims) { - std::string trimmed; - bool last_is_digit = true; - size_t i = 0; - while (!isdigit(dims[i])) i++; - for (; i < dims.size(); i++) { - if (isdigit(dims[i])) { - if (!last_is_digit) { - trimmed += "_"; - last_is_digit = true; - } - trimmed.push_back(dims[i]); - } else { - last_is_digit = false; - } - } - return trimmed; -} - -class ASRToCPPVisitor : public BaseCCPPVisitor -{ -public: - - std::string array_types_decls; - std::map>> eltypedims2arraytype; - - ASRToCPPVisitor(diag::Diagnostics &diag, CompilerOptions &co, - int64_t default_lower_bound) - : BaseCCPPVisitor(diag, co.platform, co, true, true, false, - default_lower_bound), - array_types_decls(std::string("\nstruct dimension_descriptor\n" - "{\n int32_t lower_bound, length;\n};\n")) {} - - std::string convert_dims(size_t n_dims, ASR::dimension_t *m_dims, size_t& size) - { - std::string dims; - size = 1; - for (size_t i=0; ivisit_expr(*m_dims[i].m_start); - sub += indent + std::string(v_m_name) + - "->dims[" + std::to_string(i) + "].lower_bound = " + src + ";\n"; - } else { - sub += indent + std::string(v_m_name) + - "->dims[" + std::to_string(i) + "].lower_bound = 0" + ";\n"; - } - if( m_dims[i].m_length ) { - this->visit_expr(*m_dims[i].m_length); - sub += indent + std::string(v_m_name) + - "->dims[" + std::to_string(i) + "].length = " + src + ";\n"; - } else { - sub += indent + std::string(v_m_name) + - "->dims[" + std::to_string(i) + "].length = 0" + ";\n"; - } - } - sub.pop_back(); - sub.pop_back(); - } - } else { - sub = format_type("", type_name, v_m_name, use_ref, dummy, false); - } - } - - std::string generate_templates_for_arrays(std::string v_name) { - std::string typename_T = "T" + std::to_string(template_number); - template_for_Kokkos += "typename " + typename_T + ", "; - template_number += 1; - return typename_T + "* " + v_name; - } - - std::string convert_variable_decl(const ASR::Variable_t &v, DeclarationOptions* decl_options=nullptr) - { - bool use_static; - bool use_templates_for_arrays; - - if( decl_options ) { - CPPDeclarationOptions* cpp_decl_options = reinterpret_cast(decl_options); - use_static = cpp_decl_options->use_static; - use_templates_for_arrays = cpp_decl_options->use_templates_for_arrays; - } else { - use_static = true; - use_templates_for_arrays = false; - } - - std::string sub; - bool use_ref = (v.m_intent == ASRUtils::intent_out || - v.m_intent == ASRUtils::intent_inout || - v.m_intent == ASRUtils::intent_unspecified - ); - bool is_array = ASRUtils::is_array(v.m_type); - bool dummy = ASRUtils::is_arg_dummy(v.m_intent); - if (ASRUtils::is_pointer(v.m_type)) { - ASR::ttype_t *t2 = ASR::down_cast(v.m_type)->m_type; - if (ASRUtils::is_integer(*t2)) { - ASR::Integer_t *t = ASR::down_cast(t2); - size_t size; - std::string dims = convert_dims(t->n_dims, t->m_dims, size); - std::string type_name = "int" + std::to_string(t->m_kind * 8) + "_t"; - if( is_array ) { - if( use_templates_for_arrays ) { - sub += generate_templates_for_arrays(std::string(v.m_name)); - } else { - std::string encoded_type_name = "i" + std::to_string(t->m_kind * 8); - generate_array_decl(sub, std::string(v.m_name), type_name, dims, - encoded_type_name, t->m_dims, t->n_dims, size, - use_ref, dummy, - v.m_intent != ASRUtils::intent_in && - v.m_intent != ASRUtils::intent_inout && - v.m_intent != ASRUtils::intent_out, true, true); - } - } else { - sub = format_type(dims, type_name, v.m_name, use_ref, dummy); - } - } else { - diag.codegen_error_label("Type number '" - + std::to_string(v.m_type->type) - + "' not supported", {v.base.base.loc}, ""); - throw Abort(); - } - } else { - std::string dims; - use_ref = use_ref && !is_array; - if (ASRUtils::is_integer(*v.m_type)) { - ASR::Integer_t *t = ASR::down_cast(v.m_type); - size_t size; - dims = convert_dims(t->n_dims, t->m_dims, size); - std::string type_name = "int" + std::to_string(t->m_kind * 8) + "_t"; - if( is_array ) { - if( use_templates_for_arrays ) { - sub += generate_templates_for_arrays(std::string(v.m_name)); - } else { - std::string encoded_type_name = "i" + std::to_string(t->m_kind * 8); - generate_array_decl(sub, std::string(v.m_name), type_name, dims, - encoded_type_name, t->m_dims, t->n_dims, size, - use_ref, dummy, - v.m_intent != ASRUtils::intent_in && - v.m_intent != ASRUtils::intent_inout && - v.m_intent != ASRUtils::intent_out, true); - } - } else { - sub = format_type(dims, type_name, v.m_name, use_ref, dummy); - } - } else if (ASRUtils::is_real(*v.m_type)) { - ASR::Real_t *t = ASR::down_cast(v.m_type); - size_t size; - dims = convert_dims(t->n_dims, t->m_dims, size); - std::string type_name = "float"; - if (t->m_kind == 8) type_name = "double"; - if( is_array ) { - if( use_templates_for_arrays ) { - sub += generate_templates_for_arrays(std::string(v.m_name)); - } else { - std::string encoded_type_name = "f" + std::to_string(t->m_kind * 8); - generate_array_decl(sub, std::string(v.m_name), type_name, dims, - encoded_type_name, t->m_dims, t->n_dims, size, - use_ref, dummy, - v.m_intent != ASRUtils::intent_in && - v.m_intent != ASRUtils::intent_inout && - v.m_intent != ASRUtils::intent_out, true); - } - } else { - sub = format_type(dims, type_name, v.m_name, use_ref, dummy); - } - } else if (ASRUtils::is_complex(*v.m_type)) { - ASR::Complex_t *t = ASR::down_cast(v.m_type); - size_t size; - dims = convert_dims(t->n_dims, t->m_dims, size); - std::string type_name = "std::complex"; - if (t->m_kind == 8) type_name = "std::complex"; - if( is_array ) { - if( use_templates_for_arrays ) { - sub += generate_templates_for_arrays(std::string(v.m_name)); - } else { - std::string encoded_type_name = "c" + std::to_string(t->m_kind * 8); - generate_array_decl(sub, std::string(v.m_name), type_name, dims, - encoded_type_name, t->m_dims, t->n_dims, size, - use_ref, dummy, - v.m_intent != ASRUtils::intent_in && - v.m_intent != ASRUtils::intent_inout && - v.m_intent != ASRUtils::intent_out, true); - } - } else { - sub = format_type(dims, type_name, v.m_name, use_ref, dummy); - } - } else if (ASRUtils::is_logical(*v.m_type)) { - ASR::Logical_t *t = ASR::down_cast(v.m_type); - size_t size; - dims = convert_dims(t->n_dims, t->m_dims, size); - sub = format_type(dims, "bool", v.m_name, use_ref, dummy); - } else if (ASRUtils::is_character(*v.m_type)) { - ASR::Character_t *t = ASR::down_cast(v.m_type); - size_t size; - dims = convert_dims(t->n_dims, t->m_dims, size); - sub = format_type(dims, "std::string", v.m_name, use_ref, dummy); - } else if (ASR::is_a(*v.m_type)) { - ASR::Struct_t *t = ASR::down_cast(v.m_type); - std::string der_type_name = ASRUtils::symbol_name(t->m_derived_type); - size_t size; - dims = convert_dims(t->n_dims, t->m_dims, size); - if( is_array ) { - if( use_templates_for_arrays ) { - sub += generate_templates_for_arrays(std::string(v.m_name)); - } else { - std::string encoded_type_name = "x" + der_type_name; - std::string type_name = std::string("struct ") + der_type_name; - generate_array_decl(sub, std::string(v.m_name), type_name, dims, - encoded_type_name, t->m_dims, t->n_dims, size, - use_ref, dummy, - v.m_intent != ASRUtils::intent_in && - v.m_intent != ASRUtils::intent_inout && - v.m_intent != ASRUtils::intent_out, true); - } - } else { - sub = format_type(dims, "struct", v.m_name, use_ref, dummy); - } - } else { - diag.codegen_error_label("Type number '" - + std::to_string(v.m_type->type) - + "' not supported", {v.base.base.loc}, ""); - throw Abort(); - } - if (dims.size() == 0 && v.m_storage == ASR::storage_typeType::Save && use_static) { - sub = "static " + sub; - } - if (dims.size() == 0 && v.m_symbolic_value) { - this->visit_expr(*v.m_symbolic_value); - std::string init = src; - sub += "=" + init; - } - } - return sub; - } - - - void visit_TranslationUnit(const ASR::TranslationUnit_t &x) { - global_scope = x.m_global_scope; - // All loose statements must be converted to a function, so the items - // must be empty: - LCOMPILERS_ASSERT(x.n_items == 0); - std::string unit_src = ""; - indentation_level = 0; - indentation_spaces = 4; - - std::string headers = -R"(#include -#include -#include -#include -#include -#include -#include -#include - -template -Kokkos::View from_std_vector(const std::vector &v) -{ - Kokkos::View r("r", v.size()); - for (size_t i=0; i < v.size(); i++) { - r(i) = v[i]; - } - return r; -} - -)"; - - - // Pre-declare all functions first, then generate code - // Otherwise some function might not be found. - unit_src += "// Forward declarations\n"; - unit_src += declare_all_functions(*x.m_global_scope); - // Now pre-declare all functions from modules and programs - for (auto &item : x.m_global_scope->get_scope()) { - if (ASR::is_a(*item.second)) { - ASR::Module_t *m = ASR::down_cast(item.second); - unit_src += declare_all_functions(*m->m_symtab); - } else if (ASR::is_a(*item.second)) { - ASR::Program_t *p = ASR::down_cast(item.second); - unit_src += "namespace {\n" - + declare_all_functions(*p->m_symtab) - + "}\n"; - } - } - unit_src += "\n"; - unit_src += "// Implementations\n"; - - { - // Process intrinsic modules in the right order - std::vector build_order - = ASRUtils::determine_module_dependencies(x); - for (auto &item : build_order) { - LCOMPILERS_ASSERT(x.m_global_scope->get_scope().find(item) - != x.m_global_scope->get_scope().end()); - if (startswith(item, "lfortran_intrinsic")) { - ASR::symbol_t *mod = x.m_global_scope->get_symbol(item); - visit_symbol(*mod); - unit_src += src; - } - } - } - - // Process procedures first: - for (auto &item : x.m_global_scope->get_scope()) { - if (ASR::is_a(*item.second)) { - visit_symbol(*item.second); - unit_src += src; - } - } - - // Then do all the modules in the right order - std::vector build_order - = ASRUtils::determine_module_dependencies(x); - for (auto &item : build_order) { - LCOMPILERS_ASSERT(x.m_global_scope->get_scope().find(item) - != x.m_global_scope->get_scope().end()); - if (!startswith(item, "lfortran_intrinsic")) { - ASR::symbol_t *mod = x.m_global_scope->get_symbol(item); - visit_symbol(*mod); - unit_src += src; - } - } - - // Then the main program: - for (auto &item : x.m_global_scope->get_scope()) { - if (ASR::is_a(*item.second)) { - visit_symbol(*item.second); - unit_src += src; - } - } - - src = headers + array_types_decls + unit_src; - } - - void visit_Program(const ASR::Program_t &x) { - // Generate code for nested subroutines and functions first: - std::string contains; - for (auto &item : x.m_symtab->get_scope()) { - if (ASR::is_a(*item.second)) { - ASR::Function_t *s = ASR::down_cast(item.second); - visit_Function(*s); - contains += src; - } - } - - // Generate code for the main program - indentation_level += 1; - std::string indent1(indentation_level*indentation_spaces, ' '); - std::string decl; - for (auto &item : x.m_symtab->get_scope()) { - if (ASR::is_a(*item.second)) { - ASR::Variable_t *v = ASR::down_cast(item.second); - decl += indent1; - decl += convert_variable_decl(*v) + ";\n"; - } - } - - std::string body; - for (size_t i=0; ivisit_stmt(*x.m_body[i]); - body += src; - } - - src = "namespace {\n" - + contains - + "\nvoid main2() {\n" - + decl + body - + "}\n\n" - + "}\n" - + "int main(int argc, char* argv[])\n{\n" - + indent1 + "Kokkos::initialize(argc, argv);\n" - + indent1 + "main2();\n" - + indent1 + "Kokkos::finalize();\n" - + indent1 + "return 0;\n}\n"; - indentation_level -= 2; - } - - void visit_ComplexConstructor(const ASR::ComplexConstructor_t &x) { - this->visit_expr(*x.m_re); - std::string re = src; - this->visit_expr(*x.m_im); - std::string im = src; - src = "std::complex(" + re + ", " + im + ")"; - if (ASRUtils::extract_kind_from_ttype_t(x.m_type) == 8) { - src = "std::complex(" + re + ", " + im + ")"; - } - last_expr_precedence = 2; - } - - void visit_ComplexConstant(const ASR::ComplexConstant_t &x) { - std::string re = std::to_string(x.m_re); - std::string im = std::to_string(x.m_im); - src = "std::complex(" + re + ", " + im + ")"; - if (ASRUtils::extract_kind_from_ttype_t(x.m_type) == 8) { - src = "std::complex(" + re + ", " + im + ")"; - } - last_expr_precedence = 2; - } - - void visit_LogicalConstant(const ASR::LogicalConstant_t &x) { - if (x.m_value == true) { - src = "true"; - } else { - src = "false"; - } - last_expr_precedence = 2; - } - - void visit_SetConstant(const ASR::SetConstant_t &x) { - std::string out = "{"; - for (size_t i=0; i r;\n"; - std::string out = "from_std_vector({"; - for (size_t i=0; ivisit_expr(*x.m_args[i]); - out += src; - if (i < x.n_args-1) out += ", "; - } - out += "})"; - from_std_vector_helper += indent + "r = " + out + ";\n"; - src = "&r"; - last_expr_precedence = 2; - } - - void visit_ArraySize(const ASR::ArraySize_t& x) { - visit_expr(*x.m_v); - std::string var_name = src; - std::string args = ""; - if (x.m_dim == nullptr) { - // TODO: return the product of all dimensions: - args = "0"; - } else { - if( x.m_dim ) { - visit_expr(*x.m_dim); - args += src + "-1"; - args += ", "; - } - args += std::to_string(ASRUtils::extract_kind_from_ttype_t(x.m_type)) + "-1"; - } - src = var_name + "->data->extent(" + args + ")"; - } - - void visit_StringConcat(const ASR::StringConcat_t &x) { - this->visit_expr(*x.m_left); - std::string left = std::move(src); - int left_precedence = last_expr_precedence; - this->visit_expr(*x.m_right); - std::string right = std::move(src); - int right_precedence = last_expr_precedence; - last_expr_precedence = 6; - if (left_precedence <= last_expr_precedence) { - src += "std::string(" + left + ")"; - } else { - src += left; - } - src += " + "; // handle only concatenation for now - if (right_precedence <= last_expr_precedence) { - src += "std::string(" + right + ")"; - } else { - src += right; - } - } - - void visit_StringItem(const ASR::StringItem_t& x) { - this->visit_expr(*x.m_idx); - std::string idx = std::move(src); - this->visit_expr(*x.m_arg); - std::string str = std::move(src); - src = str + "[" + idx + " - 1]"; - } - - void visit_StringLen(const ASR::StringLen_t &x) { - this->visit_expr(*x.m_arg); - src = src + ".length()"; - } - - void visit_Print(const ASR::Print_t &x) { - std::string indent(indentation_level*indentation_spaces, ' '); - std::string out = indent + "std::cout ", sep; - if (x.m_separator) { - this->visit_expr(*x.m_separator); - sep = src; - } else { - sep = "\" \""; - } - for (size_t i=0; ivisit_expr(*x.m_values[i]); - out += "<< " + src + " "; - if (i+1 != x.n_values) { - out += "<< " + sep + " "; - } - } - if (x.m_end) { - this->visit_expr(*x.m_end); - out += "<< " + src + ";\n"; - } else { - out += "<< std::endl;\n"; - } - src = out; - } - - void visit_FileWrite(const ASR::FileWrite_t &x) { - std::string indent(indentation_level*indentation_spaces, ' '); - std::string out = indent + "std::cout "; - for (size_t i=0; ivisit_expr(*x.m_values[i]); - out += "<< " + src + " "; - } - out += "<< std::endl;\n"; - src = out; - } - - void visit_FileRead(const ASR::FileRead_t &x) { - std::string indent(indentation_level*indentation_spaces, ' '); - std::string out = indent + "// FIXME: READ: std::cout "; - for (size_t i=0; ivisit_expr(*x.m_values[i]); - out += "<< " + src + " "; - } - out += "<< std::endl;\n"; - src = out; - } - - void visit_DoConcurrentLoop(const ASR::DoConcurrentLoop_t &x) { - std::string indent(indentation_level*indentation_spaces, ' '); - std::string out = indent + "Kokkos::parallel_for("; - out += "Kokkos::RangePolicy("; - visit_expr(*x.m_head.m_start); - out += src + ", "; - visit_expr(*x.m_head.m_end); - out += src + "+1)"; - ASR::Variable_t *loop_var = ASRUtils::EXPR2VAR(x.m_head.m_v); - sym_info[get_hash((ASR::asr_t*) loop_var)].needs_declaration = false; - out += ", KOKKOS_LAMBDA(const long " + std::string(loop_var->m_name) - + ") {\n"; - indentation_level += 1; - for (size_t i=0; ivisit_stmt(*x.m_body[i]); - out += src; - } - out += indent + "});\n"; - indentation_level -= 1; - src = out; - } - - void visit_ArrayItem(const ASR::ArrayItem_t &x) { - this->visit_expr(*x.m_v); - std::string array = src; - std::string out = array; - ASR::dimension_t* m_dims; - ASRUtils::extract_dimensions_from_ttype(ASRUtils::expr_type(x.m_v), m_dims); - out += "->data->operator[]("; - std::string index = ""; - for (size_t i=0; ivisit_expr(*x.m_args[i].m_right); - } else { - src = "/* FIXME right index */"; - } - out += src; - out += " - " + array + "->dims[" + std::to_string(i) + "].lower_bound"; - if (i < x.n_args - 1) { - out += ", "; - } - } - out += ")"; - last_expr_precedence = 2; - src = out; - } - -}; - -Result asr_to_cpp(Allocator &al, ASR::TranslationUnit_t &asr, - diag::Diagnostics &diagnostics, CompilerOptions &co, - int64_t default_lower_bound) -{ - LCompilers::PassOptions pass_options; - pass_options.always_run = true; - pass_unused_functions(al, asr, pass_options); - ASRToCPPVisitor v(diagnostics, co, default_lower_bound); - try { - v.visit_asr((ASR::asr_t &)asr); - } catch (const CodeGenError &e) { - diagnostics.diagnostics.push_back(e.d); - return Error(); - } catch (const Abort &) { - return Error(); - } - return v.src; -} - -} // namespace LCompilers diff --git a/src/libasr/codegen/asr_to_cpp.h b/src/libasr/codegen/asr_to_cpp.h deleted file mode 100644 index e54035a391..0000000000 --- a/src/libasr/codegen/asr_to_cpp.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef LFORTRAN_ASR_TO_CPP_H -#define LFORTRAN_ASR_TO_CPP_H - -#include -#include - -namespace LCompilers { - - Result asr_to_cpp(Allocator &al, ASR::TranslationUnit_t &asr, - diag::Diagnostics &diagnostics, CompilerOptions &co, - int64_t default_lower_bound); - -} // namespace LCompilers - -#endif // LFORTRAN_ASR_TO_CPP_H diff --git a/src/libasr/codegen/asr_to_julia.cpp b/src/libasr/codegen/asr_to_julia.cpp deleted file mode 100644 index 6f468afff9..0000000000 --- a/src/libasr/codegen/asr_to_julia.cpp +++ /dev/null @@ -1,1894 +0,0 @@ -#include "libasr/asr.h" -#include "libasr/asr_utils.h" -#include "libasr/diagnostics.h" -#include - -namespace LCompilers { - -/* -Julia operator precedence: -https://docs.julialang.org/en/v1/manual/mathematical-operations/#Operator-Precedence-and-Associativity - -Can also be queried by `Base.operator_precedence()`. - -Different from C++, the larger the number, the higher the precedence. To follow LFortran's -convention, we need to revert the precedence table. -*/ -enum julia_prec { - Base = 2, - Pow, // ^ - Unary, // (-), !, ~ - BitShift, // <<, >> - Mul, // *, /, &, |, ⊻ - Add, // +, - - Comp, // ==, ≠, <, ≤, >, ≥ - LogicalAnd, // && - LogicalOr, // || - Cond, // ? : - Assign, // = -}; - -static inline bool -is_right_associated_julia(int prec) -{ - return prec == julia_prec::Pow || prec == julia_prec::Unary || prec >= julia_prec::LogicalAnd; -} - -static inline std::string -binop_to_str_julia(const ASR::binopType t) -{ - switch (t) { - case (ASR::binopType::Add): { - return " + "; - } - case (ASR::binopType::Sub): { - return " - "; - } - case (ASR::binopType::Mul): { - return " * "; - } - case (ASR::binopType::Div): { - return " / "; - } - case (ASR::binopType::Pow): { - return " ^ "; - } - case (ASR::binopType::BitAnd): { - return " & "; - } - case (ASR::binopType::BitOr): { - return " | "; - } - case (ASR::binopType::BitXor): { - return " ⊻ "; - } - case (ASR::binopType::BitLShift): { - return " << "; - } - case (ASR::binopType::BitRShift): { - return " >> "; - } - default: - throw LCompilersException("Cannot represent the binary operator as a string"); - } -} - -static inline std::string -logicalbinop_to_str_julia(const ASR::logicalbinopType t) -{ - switch (t) { - case (ASR::logicalbinopType::And): { - return " && "; - } - case (ASR::logicalbinopType::Or): { - return " || "; - } - case (ASR::logicalbinopType::Eqv): { - return " == "; - } - case (ASR::logicalbinopType::NEqv): { - return " ≠ "; - } - default: - throw LCompilersException("Cannot represent the boolean operator as a string"); - } -} - -static inline std::string -cmpop_to_str_julia(const ASR::cmpopType t) -{ - switch (t) { - case (ASR::cmpopType::Eq): { - return " == "; - } - case (ASR::cmpopType::NotEq): { - return " ≠ "; - } - case (ASR::cmpopType::Lt): { - return " < "; - } - case (ASR::cmpopType::LtE): { - return " ≤ "; - } - case (ASR::cmpopType::Gt): { - return " > "; - } - case (ASR::cmpopType::GtE): { - return " ≥ "; - } - default: - throw LCompilersException("Cannot represent the comparison as a string"); - } -} - -class ASRToJuliaVisitor : public ASR::BaseVisitor -{ -public: - Allocator& al; - diag::Diagnostics& diag; - std::string src; - int indentation_level; - int indentation_spaces; - int last_expr_precedence; - bool intrinsic_module = false; - const ASR::Function_t* current_function = nullptr; - - SymbolTable* global_scope; - std::map sym_info; - std::map> dependencies; - - ASRToJuliaVisitor(Allocator& al, diag::Diagnostics& diag) - : al{ al } - , diag{ diag } - { - } - - std::string format_type(const std::string& type, - const std::string& name, - bool use_ref, - const std::string& default_value = "") - { - std::string fmt; - if (use_ref) { - fmt = name + "::Base.RefValue{" + type + "}"; - } else { - fmt = name + "::" + type; - } - - if (!default_value.empty()) - fmt += " = " + default_value; - - return fmt; - } - - std::string format_dependencies() - { - std::string fmt; - if (dependencies.empty()) - return fmt; - - for (auto& p : dependencies) { - fmt += "using Main." + p.first + ": "; - for (auto it = p.second.begin(); it != p.second.end(); it++) { - fmt += *it; - if (std::next(it) != p.second.end()) - fmt += ", "; - } - fmt += "\n"; - } - fmt += "\n"; - - return fmt; - } - - std::string format_binop(const std::string& left, - const std::string& op, - const std::string& right, - int left_precedence, - int right_precedence, - bool is_sub_div = false) - { - std::string out; - if (is_right_associated_julia(left_precedence)) { - out += "(" + left + ")"; - } else { - if (left_precedence <= last_expr_precedence) { - out += left; - } else { - out += "(" + left + ")"; - } - } - out += op; - if (is_right_associated_julia(right_precedence)) { - out += "(" + right + ")"; - } else if (is_sub_div) { - if (right_precedence < last_expr_precedence) { - out += right; - } else { - out += "(" + right + ")"; - } - } else { - if (right_precedence <= last_expr_precedence) { - out += right; - } else { - out += "(" + right + ")"; - } - } - - return out; - } - - std::string get_primitive_type_name(ASR::Variable_t* farg) - { - std::string type_name; - if (ASRUtils::is_integer(*farg->m_type)) { - ASR::Integer_t* t = ASR::down_cast(farg->m_type); - type_name = "Int" + std::to_string(t->m_kind * 8); - } else if (ASRUtils::is_real(*farg->m_type)) { - ASR::Real_t* t = ASR::down_cast(farg->m_type); - type_name = "Float32"; - if (t->m_kind == 8) - type_name = "Float64"; - } else if (ASRUtils::is_complex(*farg->m_type)) { - ASR::Complex_t* t = ASR::down_cast(farg->m_type); - type_name = "ComplexF32"; - if (t->m_kind == 8) - type_name = "ComplexF64"; - } - return type_name; - } - - void generate_array_decl(std::string& sub, - std::string v_m_name, - std::string& type_name, - std::string& dims, - ASR::dimension_t* m_dims, - int n_dims, - bool init_default = false, - bool is_allocate = false) - { - if (!init_default) { - sub += v_m_name + "::Array{" + type_name + ", " + std::to_string(n_dims) + "}"; - } else { - sub += v_m_name + " = Array{" + type_name + ", " + std::to_string(n_dims) + "}(undef, "; - if (is_allocate) - return; - } - for (int i = 0; i < n_dims; i++) { - if (m_dims[i].m_length) { - visit_expr(*m_dims[i].m_length); - if (init_default) - sub += src; - else - dims += src; - if (i < n_dims - 1) { - if (init_default) - sub += ", "; - else - dims += ", "; - } - } - } - if (init_default) - sub += ")"; - } - - - std::string convert_variable_decl(const ASR::Variable_t& v, bool is_argument = false) - { - std::string sub; - bool is_array = ASRUtils::is_array(v.m_type); - bool use_ref = (v.m_intent == ASRUtils::intent_out - || v.m_intent == ASRUtils::intent_inout) - && !is_array; - std::string dims; - if (ASRUtils::is_pointer(v.m_type)) { - ASR::ttype_t* t2 = ASR::down_cast(v.m_type)->m_type; - if (ASRUtils::is_integer(*t2)) { - ASR::Integer_t* t = ASR::down_cast(t2); - std::string type_name = "Int" + std::to_string(t->m_kind * 8); - if (is_array) { - generate_array_decl(sub, - std::string(v.m_name), - type_name, - dims, - t->m_dims, - t->n_dims, - is_argument); - } else { - sub = format_type(type_name, v.m_name, use_ref); - } - } else { - diag.codegen_error_label("Type number '" + std::to_string(v.m_type->type) - + "' not supported", - { v.base.base.loc }, - ""); - throw Abort(); - } - } else { - bool init_default = !is_argument && !v.m_symbolic_value - && v.m_storage != ASR::storage_typeType::Allocatable; - if (ASRUtils::is_integer(*v.m_type)) { - ASR::Integer_t* t = ASR::down_cast(v.m_type); - std::string type_name = "Int" + std::to_string(t->m_kind * 8); - if (is_array) { - generate_array_decl(sub, - std::string(v.m_name), - type_name, - dims, - t->m_dims, - t->n_dims, - init_default); - } else { - sub = format_type(type_name, v.m_name, use_ref, init_default ? "0" : ""); - } - } else if (ASRUtils::is_real(*v.m_type)) { - ASR::Real_t* t = ASR::down_cast(v.m_type); - std::string type_name = "Float32"; - if (t->m_kind == 8) - type_name = "Float64"; - if (is_array) { - generate_array_decl(sub, - std::string(v.m_name), - type_name, - dims, - t->m_dims, - t->n_dims, - init_default); - } else { - sub = format_type(type_name, v.m_name, use_ref, init_default ? "0.0" : ""); - } - } else if (ASRUtils::is_complex(*v.m_type)) { - ASR::Complex_t* t = ASR::down_cast(v.m_type); - std::string type_name = "ComplexF32"; - if (t->m_kind == 8) - type_name = "ComplexF64"; - if (is_array) { - generate_array_decl(sub, - std::string(v.m_name), - type_name, - dims, - t->m_dims, - t->n_dims, - init_default); - } else { - sub = format_type(type_name, v.m_name, use_ref, init_default ? "0.0" : ""); - } - } else if (ASRUtils::is_logical(*v.m_type)) { - std::string type_name = "Bool"; - ASR::Logical_t* t = ASR::down_cast(v.m_type); - if (is_array) { - generate_array_decl(sub, - std::string(v.m_name), - type_name, - dims, - t->m_dims, - t->n_dims, - init_default); - } else { - sub = format_type(type_name, v.m_name, use_ref, init_default ? "false" : ""); - } - } else if (ASRUtils::is_character(*v.m_type)) { - std::string type_name = "String"; - ASR::Character_t* t = ASR::down_cast(v.m_type); - if (is_array) { - generate_array_decl(sub, - std::string(v.m_name), - type_name, - dims, - t->m_dims, - t->n_dims, - init_default); - } else { - sub = format_type(type_name, v.m_name, use_ref, init_default ? "\"\"" : ""); - } - } else if (ASR::is_a(*v.m_type)) { - // TODO: handle this - ASR::Struct_t* t = ASR::down_cast(v.m_type); - std::string der_type_name = ASRUtils::symbol_name(t->m_derived_type); - if (is_array) { - generate_array_decl(sub, - std::string(v.m_name), - der_type_name, - dims, - t->m_dims, - t->n_dims, - init_default); - } else { - sub = format_type(der_type_name, v.m_name, use_ref); - } - } else { - diag.codegen_error_label("Type number '" + std::to_string(v.m_type->type) - + "' not supported", - { v.base.base.loc }, - ""); - throw Abort(); - } - // if (dims.size() == 0 && v.m_storage == ASR::storage_typeType::Save) { - // sub = "static " + sub; - // } - if (v.m_symbolic_value) { - visit_expr(*v.m_symbolic_value); - std::string init = src; - if (is_array && !ASR::is_a(*v.m_symbolic_value)) { - sub += " = fill(" + init + ", " + dims + ")"; - } else { - sub += " = " + init; - } - } - } - - return sub; - } - - // Returns the declaration, no semi colon at the end - std::string get_function_declaration(const ASR::Function_t& x) - { - std::string sub, inl, ret_type; - if (ASRUtils::get_FunctionType(x)->m_inline) { - inl = "@inline "; - } - if (x.m_return_var) { - ASR::Variable_t* return_var = ASRUtils::EXPR2VAR(x.m_return_var); - if (ASRUtils::is_integer(*return_var->m_type)) { - int kind = ASR::down_cast(return_var->m_type)->m_kind; - switch (kind) { - case (1): - ret_type = "Int8"; - break; - case (2): - ret_type = "Int16"; - break; - case (4): - ret_type = "Int32"; - break; - case (8): - ret_type = "Int64"; - break; - } - } else if (ASRUtils::is_real(*return_var->m_type)) { - bool is_float = ASR::down_cast(return_var->m_type)->m_kind == 4; - if (is_float) { - ret_type = "Float32"; - } else { - ret_type = "Float64"; - } - } else if (ASRUtils::is_logical(*return_var->m_type)) { - ret_type = "Bool"; - } else if (ASRUtils::is_character(*return_var->m_type)) { - ret_type = "String"; - } else if (ASRUtils::is_complex(*return_var->m_type)) { - bool is_float = ASR::down_cast(return_var->m_type)->m_kind == 4; - if (is_float) { - ret_type = "ComplexF32"; - } else { - ret_type = "ComplexF64"; - } - } else if (ASR::is_a(*return_var->m_type)) { - ret_type = "Ptr{Cvoid}"; - } else { - throw CodeGenError("Return type not supported in function '" + std::string(x.m_name) - + +"'", - return_var->base.base.loc); - } - } - std::string sym_name = x.m_name; - if (sym_name == "main") { - sym_name = "_xx_lcompilers_changed_main_xx"; - } - if (sym_name == "exit") { - sym_name = "_xx_lcompilers_changed_exit_xx"; - } - std::string func = inl + "function " + sym_name + "("; - for (size_t i = 0; i < x.n_args; i++) { - ASR::Variable_t* arg = ASRUtils::EXPR2VAR(x.m_args[i]); - LCOMPILERS_ASSERT(ASRUtils::is_arg_dummy(arg->m_intent)); - func += this->convert_variable_decl(*arg, true); - if (i < x.n_args - 1) - func += ", "; - } - func += ")"; - if (!ret_type.empty()) - func += "::" + ret_type; - - return func; - } - - void visit_TranslationUnit(const ASR::TranslationUnit_t& x) - { - global_scope = x.m_global_scope; - - // All loose statements must be converted to a function, so the items - // must be empty: - LCOMPILERS_ASSERT(x.n_items == 0); - std::string unit_src = ""; - indentation_level = 0; - indentation_spaces = 4; - - std::string headers = R"()"; - unit_src += headers; - - { - // Process intrinsic modules in the right order - std::vector build_order - = ASRUtils::determine_module_dependencies(x); - for (auto& item : build_order) { - LCOMPILERS_ASSERT(x.m_global_scope->get_scope().find(item) - != x.m_global_scope->get_scope().end()); - if (startswith(item, "lfortran_intrinsic")) { - ASR::symbol_t* mod = x.m_global_scope->get_symbol(item); - visit_symbol(*mod); - unit_src += src; - } - } - } - - // Process procedures first: - for (auto& item : x.m_global_scope->get_scope()) { - if (ASR::is_a(*item.second)) { - visit_symbol(*item.second); - unit_src += src; - } - } - - // Then do all the modules in the right order - std::vector build_order = ASRUtils::determine_module_dependencies(x); - for (auto& item : build_order) { - LCOMPILERS_ASSERT(x.m_global_scope->get_scope().find(item) - != x.m_global_scope->get_scope().end()); - if (!startswith(item, "lfortran_intrinsic")) { - ASR::symbol_t* mod = x.m_global_scope->get_symbol(item); - visit_symbol(*mod); - unit_src += src; - } - } - - // Then the main program: - for (auto& item : x.m_global_scope->get_scope()) { - if (ASR::is_a(*item.second)) { - visit_symbol(*item.second); - unit_src += src; - } - } - - src = unit_src; - } - - void visit_Module(const ASR::Module_t& x) - { - dependencies.clear(); - std::string module = "module " + std::string(x.m_name) + "\n\n"; - if (startswith(x.m_name, "lfortran_intrinsic_")) { - intrinsic_module = true; - } else { - intrinsic_module = false; - } - - std::string contains; - - // Generate the bodies of subroutines - for (auto& item : x.m_symtab->get_scope()) { - if (ASR::is_a(*item.second)) { - ASR::Function_t* s = ASR::down_cast(item.second); - visit_Function(*s); - contains += src; - } - } - - module += format_dependencies() + contains + "end\n\n"; - src = module; - intrinsic_module = false; - } - - void visit_Program(const ASR::Program_t& x) - { - dependencies.clear(); - - // Generate code for nested subroutines and functions first: - std::string contains; - for (auto& item : x.m_symtab->get_scope()) { - if (ASR::is_a(*item.second)) { - ASR::Function_t* s = ASR::down_cast(item.second); - visit_Function(*s); - contains += src; - } - } - - // Generate code for the main program - indentation_level += 1; - std::string indent(indentation_level * indentation_spaces, ' '); - std::string decl; - for (auto& item : x.m_symtab->get_scope()) { - if (ASR::is_a(*item.second)) { - ASR::Variable_t* v = ASR::down_cast(item.second); - decl += indent + "local " + this->convert_variable_decl(*v) + "\n"; - } - } - - std::string body; - for (size_t i = 0; i < x.n_body; i++) { - visit_stmt(*x.m_body[i]); - body += src; - } - - src = format_dependencies() + contains + "function main()\n" + decl + body + "end\n\n" - + "main()\n"; - indentation_level -= 2; - } - - void visit_BlockCall(const ASR::BlockCall_t& x) - { - LCOMPILERS_ASSERT(ASR::is_a(*x.m_m)); - ASR::Block_t* block = ASR::down_cast(x.m_m); - std::string indent(indentation_level * indentation_spaces, ' '); - std::string decl, body; - std::string open_paranthesis = indent + "let\n"; - std::string close_paranthesis = indent + "end\n"; - indent += std::string(indentation_spaces, ' '); - indentation_level += 1; - for (auto& item : block->m_symtab->get_scope()) { - if (ASR::is_a(*item.second)) { - ASR::Variable_t* v = ASR::down_cast(item.second); - decl += indent + this->convert_variable_decl(*v) + "\n"; - } - } - for (size_t i = 0; i < block->n_body; i++) { - this->visit_stmt(*block->m_body[i]); - body += src; - } - src = open_paranthesis + decl + body + close_paranthesis; - indentation_level -= 1; - } - - void visit_Function(const ASR::Function_t& x) - { - if (std::string(x.m_name) == "size" && intrinsic_module) { - // Intrinsic function `size` - SymbolInfo s; - s.intrinsic_function = true; - sym_info[get_hash((ASR::asr_t*) &x)] = s; - src.clear(); - return; - } else if ((std::string(x.m_name) == "int" || std::string(x.m_name) == "char" - || std::string(x.m_name) == "present" || std::string(x.m_name) == "len" - || std::string(x.m_name) == "not") - && intrinsic_module) { - // Intrinsic function `int` - SymbolInfo s; - s.intrinsic_function = true; - sym_info[get_hash((ASR::asr_t*) &x)] = s; - src.clear(); - return; - } else { - SymbolInfo s; - s.intrinsic_function = false; - sym_info[get_hash((ASR::asr_t*) &x)] = s; - } - std::string sub = get_function_declaration(x); - if (ASRUtils::get_FunctionType(x)->m_abi == ASR::abiType::BindC && - ASRUtils::get_FunctionType(x)->m_deftype == ASR::deftypeType::Interface) { - } else { - indentation_level += 1; - std::string indent(indentation_level * indentation_spaces, ' '); - std::string decl; - for (auto& item : x.m_symtab->get_scope()) { - if (ASR::is_a(*item.second)) { - ASR::Variable_t* v = ASR::down_cast(item.second); - if (v->m_intent == ASRUtils::intent_local - || v->m_intent == ASRUtils::intent_return_var) { - decl += indent + "local " + this->convert_variable_decl(*v) + "\n"; - } - } - } - - current_function = &x; - std::string body; - - for (size_t i = 0; i < x.n_body; i++) { - visit_stmt(*x.m_body[i]); - body += src; - } - - current_function = nullptr; - bool visited_return = false; - - if (x.n_body > 0 && ASR::is_a(*x.m_body[x.n_body - 1])) { - visited_return = true; - } - - if (!visited_return && x.m_return_var) { - body += indent + "return " + ASRUtils::EXPR2VAR(x.m_return_var)->m_name - + "\n"; - } - - if (decl.size() > 0 || body.size() > 0) { - sub += "\n" + decl + body + "end\n"; - } else { - sub += " end\n"; - } - indentation_level -= 1; - } - sub += "\n"; - src = sub; - } - - void visit_FunctionCall(const ASR::FunctionCall_t& x) - { - // Add dependencies - if (x.m_name->type == ASR::symbolType::ExternalSymbol) { - ASR::ExternalSymbol_t* e = ASR::down_cast(x.m_name); - dependencies[std::string(e->m_module_name)].insert(std::string(e->m_name)); - } - - ASR::Function_t* fn = ASR::down_cast( - ASRUtils::symbol_get_past_external(x.m_name)); - std::string fn_name = fn->m_name; - if (sym_info[get_hash((ASR::asr_t*) fn)].intrinsic_function) { - if (fn_name == "size") { - // TODO: implement this properly - LCOMPILERS_ASSERT(x.n_args > 0); - visit_expr(*x.m_args[0].m_value); - std::string var_name = src; - std::string args; - if (x.n_args == 1) { - args = "0"; - } else { - for (size_t i = 1; i < x.n_args; i++) { - visit_expr(*x.m_args[i].m_value); - args += src + "-1"; - if (i < x.n_args - 1) - args += ", "; - } - } - src = var_name + ".extent(" + args + ")"; - } else { - throw CodeGenError("Intrinsic function '" + fn_name + "' not implemented"); - } - } else { - std::string args; - for (size_t i = 0; i < x.n_args; i++) { - ASR::Variable_t* farg = ASRUtils::EXPR2VAR(fn->m_args[i]); - bool use_ref = (farg->m_intent == ASR::intentType::Out - || farg->m_intent == ASR::intentType::InOut) - && !ASRUtils::is_array(farg->m_type); - - std::string type_name, prefix, suffix; - if (!use_ref) { - type_name = get_primitive_type_name(farg); - if (!type_name.empty()) { - prefix = type_name + "("; - suffix = ")"; - } - } - - if (ASR::is_a(*x.m_args[i].m_value)) { - ASR::Variable_t* arg = ASRUtils::EXPR2VAR(x.m_args[i].m_value); - std::string arg_name = arg->m_name; - bool is_ref = (arg->m_intent == ASR::intentType::Out - || arg->m_intent == ASR::intentType::InOut) - && !ASRUtils::is_array(arg->m_type); - if (use_ref && !is_ref) { - throw CodeGenError( - "intent(out) and intent(inout) cannot be used in functions unless the variables passed in are intent(out) or intent(inout) in the outer scope"); - } else if (!use_ref && is_ref) { - args += arg_name + "[]"; - } else { - args += arg_name; - } - } else { - visit_expr(*x.m_args[i].m_value); - args += prefix + src + suffix; - } - if (i < x.n_args - 1) - args += ", "; - } - src = fn_name + "(" + args + ")"; - } - last_expr_precedence = julia_prec::Base; - } - - void visit_Assignment(const ASR::Assignment_t& x) - { - std::string target, op = " = "; - if (ASR::is_a(*x.m_target)) { - visit_Var(*ASR::down_cast(x.m_target)); - target = src; - - // Use broadcast for array assignments - if (ASRUtils::is_array(ASRUtils::expr_type(x.m_target))) { - op = " .= "; - } - } else { - visit_expr(*x.m_target); - target = src; - - // Use broadcast for array section assignments - if (ASR::is_a(*x.m_target)) { - op = " .= "; - } - } - visit_expr(*x.m_value); - std::string value = src; - std::string indent(indentation_level * indentation_spaces, ' '); - src.clear(); - src += indent + target + op + value + "\n"; - } - - void visit_IntegerBinOp(const ASR::IntegerBinOp_t& x) - { - handle_BinOp(x, true); - } - - void visit_RealBinOp(const ASR::RealBinOp_t& x) - { - handle_BinOp(x); - } - - void visit_ComplexBinOp(const ASR::ComplexBinOp_t& x) - { - handle_BinOp(x); - } - - template - void handle_BinOp(const T& x, bool is_integer_binop = false) - { - visit_expr(*x.m_left); - std::string left = std::move(src); - int left_precedence = last_expr_precedence; - visit_expr(*x.m_right); - std::string right = std::move(src); - int right_precedence = last_expr_precedence; - std::string op = binop_to_str_julia(x.m_op); - switch (x.m_op) { - case (ASR::binopType::Add): - case (ASR::binopType::Sub): { - last_expr_precedence = julia_prec::Add; - break; - } - case (ASR::binopType::Mul): - case (ASR::binopType::BitAnd): - case (ASR::binopType::BitOr): - case (ASR::binopType::BitXor): { - last_expr_precedence = julia_prec::Mul; - break; - } - case (ASR::binopType::Div): { - last_expr_precedence = julia_prec::Mul; - if (is_integer_binop) - op = " ÷ "; - break; - } - case (ASR::binopType::BitLShift): - case (ASR::binopType::BitRShift): { - last_expr_precedence = julia_prec::BitShift; - break; - } - case (ASR::binopType::Pow): { - last_expr_precedence = julia_prec::Pow; - break; - } - default: - throw CodeGenError("BinOp: " + std::to_string(x.m_op) - + " operator not implemented yet"); - } - src = format_binop( - left, op, right, left_precedence, right_precedence, - x.m_op == ASR::binopType::Sub || x.m_op == ASR::binopType::Div); - } - - void visit_LogicalBinOp(const ASR::LogicalBinOp_t& x) - { - visit_expr(*x.m_left); - std::string left = std::move(src); - int left_precedence = last_expr_precedence; - visit_expr(*x.m_right); - std::string right = std::move(src); - int right_precedence = last_expr_precedence; - switch (x.m_op) { - case (ASR::logicalbinopType::And): { - last_expr_precedence = julia_prec::LogicalAnd; - break; - } - case (ASR::logicalbinopType::Or): { - last_expr_precedence = julia_prec::LogicalOr; - break; - } - case (ASR::logicalbinopType::NEqv): - case (ASR::logicalbinopType::Eqv): { - last_expr_precedence = julia_prec::Comp; - break; - } - default: - throw CodeGenError("Unhandled switch case"); - } - - if (left_precedence <= last_expr_precedence) { - src += left; - } else { - src += "(" + left + ")"; - } - src += logicalbinop_to_str_julia(x.m_op); - if (right_precedence <= last_expr_precedence) { - src += right; - } else { - src += "(" + right + ")"; - } - } - - void visit_Allocate(const ASR::Allocate_t& x) - { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string out, _dims; - for (size_t i = 0; i < x.n_args; i++) { - ASR::symbol_t* tmp_sym = nullptr; - ASR::expr_t* tmp_expr = x.m_args[i].m_a; - if( ASR::is_a(*tmp_expr) ) { - const ASR::Var_t* tmp_var = ASR::down_cast(tmp_expr); - tmp_sym = tmp_var->m_v; - } else { - throw CodeGenError("Cannot deallocate variables in expression " + - std::to_string(tmp_expr->type), - tmp_expr->base.loc); - } - const ASR::Variable_t* v = ASR::down_cast( - ASRUtils::symbol_get_past_external(tmp_sym)); - - // Skip pointer allocation - if (!ASRUtils::is_array(v->m_type)) - continue; - - out += indent; - ASR::dimension_t* dims = x.m_args[i].m_dims; - size_t n_dims = x.m_args[i].n_dims; - - if (ASRUtils::is_integer(*v->m_type)) { - ASR::Integer_t* t = ASR::down_cast(v->m_type); - std::string type_name = "Int" + std::to_string(t->m_kind * 8); - generate_array_decl( - out, std::string(v->m_name), type_name, _dims, nullptr, n_dims, true, true); - } else if (ASRUtils::is_real(*v->m_type)) { - ASR::Real_t* t = ASR::down_cast(v->m_type); - std::string type_name = "Float32"; - if (t->m_kind == 8) - type_name = "Float64"; - generate_array_decl( - out, std::string(v->m_name), type_name, _dims, nullptr, n_dims, true, true); - } else if (ASRUtils::is_complex(*v->m_type)) { - ASR::Complex_t* t = ASR::down_cast(v->m_type); - std::string type_name = "ComplexF32"; - if (t->m_kind == 8) - type_name = "ComplexF64"; - generate_array_decl( - out, std::string(v->m_name), type_name, _dims, nullptr, n_dims, true, true); - } else if (ASRUtils::is_logical(*v->m_type)) { - std::string type_name = "Bool"; - generate_array_decl( - out, std::string(v->m_name), type_name, _dims, nullptr, n_dims, true, true); - } else if (ASRUtils::is_character(*v->m_type)) { - std::string type_name = "String"; - generate_array_decl( - out, std::string(v->m_name), type_name, _dims, nullptr, n_dims, true, true); - } else if (ASR::is_a(*v->m_type)) { - ASR::Struct_t* t = ASR::down_cast(v->m_type); - std::string der_type_name = ASRUtils::symbol_name(t->m_derived_type); - generate_array_decl( - out, std::string(v->m_name), der_type_name, _dims, nullptr, n_dims, true, true); - } else { - diag.codegen_error_label("Type number '" + std::to_string(v->m_type->type) - + "' not supported", - { v->base.base.loc }, - ""); - throw Abort(); - } - - - for (size_t j = 0; j < n_dims; j++) { - if (dims[j].m_length) { - visit_expr(*dims[j].m_length); - out += src; - } - if (j < n_dims - 1) - out += ", "; - } - out += ")\n"; - } - src = out; - } - - void visit_Assert(const ASR::Assert_t& x) - { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string out = indent; - out += "@assert ("; - this->visit_expr(*x.m_test); - out += src + ")"; - if (x.m_msg) { - out += " "; - this->visit_expr(*x.m_msg); - out += src; - } - src = out; - } - - // We do not need to manually deallocate in Julia. - void visit_ExplicitDeallocate(const ASR::ExplicitDeallocate_t& /* x */) - { - src.clear(); - } - - void visit_ImplicitDeallocate(const ASR::ImplicitDeallocate_t& /* x */) - { - src.clear(); - } - - void visit_Select(const ASR::Select_t& x) - { - std::string indent(indentation_level * indentation_spaces, ' '); - this->visit_expr(*x.m_test); - std::string var = std::move(src); - std::string out = indent + "if "; - - for (size_t i = 0; i < x.n_body; i++) { - if (i > 0) - out += indent + "elseif "; - ASR::case_stmt_t* stmt = x.m_body[i]; - if (stmt->type == ASR::case_stmtType::CaseStmt) { - ASR::CaseStmt_t* case_stmt = ASR::down_cast(stmt); - for (size_t j = 0; j < case_stmt->n_test; j++) { - if (j > 0) - out += " || "; - this->visit_expr(*case_stmt->m_test[j]); - out += var + " == " + src; - } - out += "\n"; - indentation_level += 1; - for (size_t j = 0; j < case_stmt->n_body; j++) { - this->visit_stmt(*case_stmt->m_body[j]); - out += src; - } - indentation_level -= 1; - } else { - ASR::CaseStmt_Range_t* case_stmt_range - = ASR::down_cast(stmt); - std::string left, right; - if (case_stmt_range->m_start) { - this->visit_expr(*case_stmt_range->m_start); - left = std::move(src); - } - if (case_stmt_range->m_end) { - this->visit_expr(*case_stmt_range->m_end); - right = std::move(src); - } - if (left.empty() && right.empty()) { - diag.codegen_error_label( - "Empty range in select statement", { x.base.base.loc }, ""); - throw Abort(); - } - if (left.empty()) { - out += var + " ≤ " + right; - } else if (right.empty()) { - out += var + " ≥ " + left; - } else { - out += left + " ≤ " + var + " ≤ " + right; - } - out += "\n"; - indentation_level += 1; - for (size_t j = 0; j < case_stmt_range->n_body; j++) { - this->visit_stmt(*case_stmt_range->m_body[j]); - out += src; - } - indentation_level -= 1; - } - } - if (x.n_default) { - out += indent + "else\n"; - indentation_level += 1; - for (size_t i = 0; i < x.n_default; i++) { - this->visit_stmt(*x.m_default[i]); - out += src; - } - indentation_level -= 1; - } - - out += indent + "end\n"; - src = out; - } - - void visit_WhileLoop(const ASR::WhileLoop_t& x) - { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string out = indent + "while "; - this->visit_expr(*x.m_test); - out += src + "\n"; - indentation_level += 1; - for (size_t i = 0; i < x.n_body; i++) { - this->visit_stmt(*x.m_body[i]); - out += src; - } - out += indent + "end\n"; - indentation_level -= 1; - src = out; - } - - void visit_Exit(const ASR::Exit_t& /* x */) - { - std::string indent(indentation_level * indentation_spaces, ' '); - src = indent + "break\n"; - } - - void visit_Cycle(const ASR::Cycle_t& /* x */) - { - std::string indent(indentation_level * indentation_spaces, ' '); - src = indent + "continue\n"; - } - - void visit_Return(const ASR::Return_t& /* x */) - { - std::string indent(indentation_level * indentation_spaces, ' '); - if (current_function && current_function->m_return_var) { - src = indent + "return " - + ASRUtils::EXPR2VAR(current_function->m_return_var)->m_name + "\n"; - } else { - src = indent + "return\n"; - } - } - - void visit_GoTo(const ASR::GoTo_t& x) - { - std::string indent(indentation_level * indentation_spaces, ' '); - src = indent + "@goto label_" + std::to_string(x.m_target_id) + "\n"; - } - - void visit_GoToTarget(const ASR::GoToTarget_t& x) - { - std::string indent(indentation_level * indentation_spaces, ' '); - src = indent + "@label label_" + std::to_string(x.m_id) + "\n"; - } - - void visit_Stop(const ASR::Stop_t& x) - { - if (x.m_code) { - this->visit_expr(*x.m_code); - } else { - src = "0"; - } - std::string indent(indentation_level * indentation_spaces, ' '); - src = indent + "exit(" + src + ")\n"; - } - - void visit_ErrorStop(const ASR::ErrorStop_t& /* x */) - { - std::string indent(indentation_level * indentation_spaces, ' '); - src = indent + "println(Base.stderr, \"ERROR STOP\")\n"; - src += indent + "exit(1)\n"; - } - - void visit_IntrinsicFunctionSqrt(const ASR::IntrinsicFunctionSqrt_t &x) { - /* - if (x.m_value) { - this->visit_expr(*x.m_value); - return; - } - */ - this->visit_expr(*x.m_arg); - src = "sqrt(" + src + ")"; - } - - void visit_ImpliedDoLoop(const ASR::ImpliedDoLoop_t& /*x*/) - { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string out = indent + " /* FIXME: implied do loop */ "; - src = out; - last_expr_precedence = 2; - } - - void visit_DoLoop(const ASR::DoLoop_t& x, bool concurrent = false) - { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string out = indent; - if (concurrent) { - out += "Threads.@threads "; - } - out += "for "; - ASR::Variable_t* loop_var = ASRUtils::EXPR2VAR(x.m_head.m_v); - std::string lvname = loop_var->m_name; - ASR::expr_t* a = x.m_head.m_start; - ASR::expr_t* b = x.m_head.m_end; - ASR::expr_t* c = x.m_head.m_increment; - LCOMPILERS_ASSERT(a); - LCOMPILERS_ASSERT(b); - int increment; - if (!c) { - increment = 1; - } else { - if (c->type == ASR::exprType::IntegerConstant) { - increment = ASR::down_cast(c)->m_n; - } else if (c->type == ASR::exprType::IntegerUnaryMinus) { - ASR::IntegerUnaryMinus_t* ium = ASR::down_cast(c); - increment = -ASR::down_cast(ium->m_arg)->m_n; - } else { - throw CodeGenError("Do loop increment type not supported"); - } - } - out += lvname + " ∈ "; - visit_expr(*a); - out += src + ":" + (increment == 1 ? "" : (std::to_string(increment) + ":")); - visit_expr(*b); - out += src + "\n"; - indentation_level += 1; - for (size_t i = 0; i < x.n_body; i++) { - visit_stmt(*x.m_body[i]); - out += src; - } - out += indent + "end\n"; - indentation_level -= 1; - src = out; - } - - void visit_DoConcurrentLoop(const ASR::DoConcurrentLoop_t& x) - { - const ASR::DoLoop_t do_loop = ASR::DoLoop_t{ x.base, x.m_head, x.m_body, x.n_body }; - visit_DoLoop(do_loop, true); - } - - void visit_If(const ASR::If_t& x) - { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string out = indent + "if "; - visit_expr(*x.m_test); - out += src + "\n"; - indentation_level += 1; - for (size_t i = 0; i < x.n_body; i++) { - visit_stmt(*x.m_body[i]); - out += src; - } - out += indent; - if (x.n_orelse == 0) { - out += "end\n"; - } else { - out += "else\n"; - for (size_t i = 0; i < x.n_orelse; i++) { - visit_stmt(*x.m_orelse[i]); - out += src; - } - out += indent + "end\n"; - } - indentation_level -= 1; - src = out; - } - - void visit_IfExp(const ASR::IfExp_t& x) - { - // IfExp is like a ternary operator in Julia - // test ? body : orelse; - std::string out = "("; - visit_expr(*x.m_test); - out += src + ") ? ("; - visit_expr(*x.m_body); - out += src + ") : ("; - visit_expr(*x.m_orelse); - out += src + ")"; - src = out; - last_expr_precedence = julia_prec::Cond; - } - - void visit_SubroutineCall(const ASR::SubroutineCall_t& x) - { - // Add dependencies - if (x.m_name->type == ASR::symbolType::ExternalSymbol) { - ASR::ExternalSymbol_t* e = ASR::down_cast(x.m_name); - dependencies[std::string(e->m_module_name)].insert(std::string(e->m_name)); - } - - std::string indent(indentation_level * indentation_spaces, ' '); - ASR::Function_t* s = ASR::down_cast( - ASRUtils::symbol_get_past_external(x.m_name)); - // TODO: use a mapping with a hash(s) instead: - std::string sym_name = s->m_name; - if (sym_name == "exit") { - sym_name = "_xx_lcompilers_changed_exit_xx"; - } - std::string out = indent + sym_name + "(", pre, post; - for (size_t i = 0; i < x.n_args; i++) { - ASR::Variable_t* sarg = ASRUtils::EXPR2VAR(s->m_args[i]); - bool use_ref = (sarg->m_intent == ASR::intentType::Out - || sarg->m_intent == ASR::intentType::InOut) - && !ASRUtils::is_array(sarg->m_type); - - std::string type_name, prefix, suffix; - if (!use_ref) { - type_name = get_primitive_type_name(sarg); - if (!type_name.empty()) { - prefix = type_name + "("; - suffix = ")"; - } - } - - if (ASR::is_a(*x.m_args[i].m_value)) { - ASR::Variable_t* arg = ASRUtils::EXPR2VAR(x.m_args[i].m_value); - std::string arg_name = arg->m_name; - bool is_ref = (arg->m_intent == ASR::intentType::Out - || arg->m_intent == ASR::intentType::InOut) - && !ASRUtils::is_array(arg->m_type); - if (use_ref && !is_ref) { - std::string arg_ref = "__" + arg_name + "_ref__"; - pre += indent + arg_ref + "= Ref(" + arg_name + ")\n"; - out += arg_ref; - post += indent + arg_name + " = " + arg_ref + "[]\n"; - } else if (!use_ref && is_ref) { - out += arg_name + "[]"; - } else { - out += arg_name; - } - } else { - visit_expr(*x.m_args[i].m_value); - out += prefix + src + suffix; - } - if (i < x.n_args - 1) - out += ", "; - } - out += ")\n"; - src = pre + out + post; - } - - void visit_IntegerConstant(const ASR::IntegerConstant_t& x) - { - src = std::to_string(x.m_n); - last_expr_precedence = julia_prec::Base; - } - - void visit_RealConstant(const ASR::RealConstant_t& x) - { - src = double_to_scientific(x.m_r); - last_expr_precedence = julia_prec::Base; - } - - void visit_ComplexConstructor(const ASR::ComplexConstructor_t& x) - { - visit_expr(*x.m_re); - std::string re = src; - visit_expr(*x.m_im); - std::string im = src; - src = "ComplexF32(" + re + ", " + im + ")"; - if (ASRUtils::extract_kind_from_ttype_t(x.m_type) == 8) { - src = "ComplexF64(" + re + ", " + im + ")"; - } - last_expr_precedence = julia_prec::Base; - } - - void visit_ComplexConstant(const ASR::ComplexConstant_t& x) - { - std::string re = std::to_string(x.m_re); - std::string im = std::to_string(x.m_im); - src = "ComplexF32(" + re + ", " + im + ")"; - if (ASRUtils::extract_kind_from_ttype_t(x.m_type) == 8) { - src = "ComplexF64(" + re + ", " + im + ")"; - } - last_expr_precedence = julia_prec::Base; - } - - void visit_LogicalConstant(const ASR::LogicalConstant_t& x) - { - if (x.m_value == true) { - src = "true"; - } else { - src = "false"; - } - last_expr_precedence = julia_prec::Base; - } - - void visit_TupleConstant(const ASR::TupleConstant_t& x) - { - std::string out = "("; - for (size_t i = 0; i < x.n_elements; i++) { - visit_expr(*x.m_elements[i]); - out += src; - if (i != x.n_elements - 1) - out += ", "; - } - out += ")"; - src = out; - last_expr_precedence = julia_prec::Base; - } - - void visit_SetConstant(const ASR::SetConstant_t& x) - { - std::string out = "Set("; - for (size_t i = 0; i < x.n_elements; i++) { - visit_expr(*x.m_elements[i]); - out += src; - if (i != x.n_elements - 1) - out += ", "; - } - out += ")"; - src = out; - last_expr_precedence = julia_prec::Base; - } - - void visit_DictConstant(const ASR::DictConstant_t& x) - { - LCOMPILERS_ASSERT(x.n_keys == x.n_values); - std::string out = "Dict("; - for (size_t i = 0; i < x.n_keys; i++) { - visit_expr(*x.m_keys[i]); - out += src + " => "; - visit_expr(*x.m_values[i]); - if (i != x.n_keys - 1) - out += ", "; - } - out += ")"; - src = out; - last_expr_precedence = julia_prec::Base; - } - - void visit_ArrayConstant(const ASR::ArrayConstant_t& x) - { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string out = "["; - for (size_t i = 0; i < x.n_args; i++) { - visit_expr(*x.m_args[i]); - out += src; - if (i < x.n_args - 1) - out += ", "; - } - out += "]"; - src = out; - last_expr_precedence = julia_prec::Base; - } - - void visit_StringConstant(const ASR::StringConstant_t& x) - { - src = "\""; - std::string s = x.m_s; - for (size_t idx=0; idx < s.size(); idx++) { - src += s[idx]; - } - src += "\""; - last_expr_precedence = julia_prec::Base; - } - - void visit_Var(const ASR::Var_t& x) - { - const ASR::symbol_t* s = ASRUtils::symbol_get_past_external(x.m_v); - ASR::Variable_t* sv = ASR::down_cast(s); - if ((sv->m_intent == ASRUtils::intent_in || sv->m_intent == ASRUtils::intent_inout) - && ASRUtils::is_array(sv->m_type) && ASRUtils::is_pointer(sv->m_type)) { - src = "(*" + std::string(ASR::down_cast(s)->m_name) + ")"; - } else { - src = std::string(ASR::down_cast(s)->m_name); - bool use_ref = (sv->m_intent == ASRUtils::intent_out || - - sv->m_intent == ASRUtils::intent_inout) - && !ASRUtils::is_array(sv->m_type); - if (use_ref) { - src += "[]"; - } - } - last_expr_precedence = julia_prec::Base; - } - - void visit_StructInstanceMember(const ASR::StructInstanceMember_t& x) - { - std::string der_expr, member; - this->visit_expr(*x.m_v); - der_expr = std::move(src); - member = ASRUtils::symbol_name(ASRUtils::symbol_get_past_external(x.m_m)); - src = der_expr + "." + member; - } - - void visit_Cast(const ASR::Cast_t& x) - { - std::string broadcast; - if (x.m_arg->type == ASR::exprType::Var) { - ASR::Variable_t* value = ASRUtils::EXPR2VAR(x.m_arg); - if (ASRUtils::is_array(value->m_type)) - broadcast = "."; - } else if (x.m_arg->type == ASR::exprType::ArrayConstant - || x.m_arg->type == ASR::exprType::TupleConstant - || x.m_arg->type == ASR::exprType::SetConstant) { - broadcast = "."; - } - visit_expr(*x.m_arg); - switch (x.m_kind) { - case (ASR::cast_kindType::IntegerToReal): { - int dest_kind = ASRUtils::extract_kind_from_ttype_t(x.m_type); - switch (dest_kind) { - case 4: - src = "Float32" + broadcast + "(" + src + ")"; - break; - case 8: - src = "Float64" + broadcast + "(" + src + ")"; - break; - default: - throw CodeGenError("Cast IntegerToReal: Unsupported Kind " - + std::to_string(dest_kind)); - } - last_expr_precedence = julia_prec::Base; - break; - } - case (ASR::cast_kindType::RealToInteger): { - int dest_kind = ASRUtils::extract_kind_from_ttype_t(x.m_type); - src = "trunc" + broadcast + "(Int" + std::to_string(dest_kind * 8) + ", " + src - + ")"; - last_expr_precedence = julia_prec::Base; - break; - } - case (ASR::cast_kindType::RealToReal): { - // In Julia, we do not need to cast float to float explicitly: - // src = src; - // last_expr_precedence = last_expr_precedence; - break; - } - case (ASR::cast_kindType::IntegerToInteger): { - // In Julia, we do not need to cast int <-> long long explicitly: - // src = src; - // last_expr_precedence = last_expr_precedence; - break; - } - case (ASR::cast_kindType::ComplexToComplex): { - break; - } - case (ASR::cast_kindType::IntegerToComplex): { - src = "complex" + broadcast + "(" + src + ")"; - last_expr_precedence = julia_prec::Base; - break; - } - case (ASR::cast_kindType::ComplexToReal): { - src = "real" + broadcast + "(" + src + ")"; - last_expr_precedence = julia_prec::Base; - break; - } - case (ASR::cast_kindType::RealToComplex): { - src = "complex" + broadcast + "(" + src + ")"; - last_expr_precedence = julia_prec::Base; - break; - } - case (ASR::cast_kindType::LogicalToInteger): { - src = "Int32" + broadcast + "(" + src + ")"; - last_expr_precedence = julia_prec::Base; - break; - } - case (ASR::cast_kindType::IntegerToLogical): { - src = "Bool" + broadcast + "(" + src + ")"; - last_expr_precedence = julia_prec::Base; - break; - } - default: - throw CodeGenError("Cast kind " + std::to_string(x.m_kind) + " not implemented", - x.base.base.loc); - } - } - - void visit_IntegerCompare(const ASR::IntegerCompare_t& x) - { - handle_Compare(x); - } - - void visit_RealCompare(const ASR::RealCompare_t& x) - { - handle_Compare(x); - } - - void visit_ComplexCompare(const ASR::ComplexCompare_t& x) - { - handle_Compare(x); - } - - void visit_LogicalCompare(const ASR::LogicalCompare_t& x) - { - handle_Compare(x); - } - - void visit_StringCompare(const ASR::StringCompare_t& x) - { - handle_Compare(x); - } - - template - void handle_Compare(const T& x) - { - visit_expr(*x.m_left); - std::string left = std::move(src); - int left_precedence = last_expr_precedence; - visit_expr(*x.m_right); - std::string right = std::move(src); - int right_precedence = last_expr_precedence; - last_expr_precedence = julia_prec::Comp; - if (left_precedence <= last_expr_precedence) { - src += left; - } else { - src += "(" + left + ")"; - } - src += cmpop_to_str_julia(x.m_op); - if (right_precedence <= last_expr_precedence) { - src += right; - } else { - src += "(" + right + ")"; - } - } - - void visit_IntegerBitNot(const ASR::IntegerBitNot_t& x) - { - visit_expr(*x.m_arg); - int expr_precedence = last_expr_precedence; - last_expr_precedence = julia_prec::Unary; - if (expr_precedence <= last_expr_precedence) { - src = "~" + src; - } else { - src = "~(" + src + ")"; - } - } - - void visit_IntegerUnaryMinus(const ASR::IntegerUnaryMinus_t& x) - { - handle_UnaryMinus(x); - } - - void visit_RealUnaryMinus(const ASR::RealUnaryMinus_t& x) - { - handle_UnaryMinus(x); - } - - void visit_ComplexUnaryMinus(const ASR::ComplexUnaryMinus_t& x) - { - handle_UnaryMinus(x); - } - - template - void handle_UnaryMinus(const T& x) - { - visit_expr(*x.m_arg); - int expr_precedence = last_expr_precedence; - last_expr_precedence = julia_prec::Unary; - if (expr_precedence <= last_expr_precedence) { - src = "-" + src; - } else { - src = "-(" + src + ")"; - } - } - - void visit_LogicalNot(const ASR::LogicalNot_t& x) - { - visit_expr(*x.m_arg); - int expr_precedence = last_expr_precedence; - last_expr_precedence = julia_prec::Unary; - if (expr_precedence <= last_expr_precedence) { - src = "!" + src; - } else { - src = "!(" + src + ")"; - } - } - - void visit_ComplexRe(const ASR::ComplexRe_t& x) - { - visit_expr(*x.m_arg); - src = "real(" + src + ")"; - } - - void visit_ComplexIm(const ASR::ComplexIm_t& x) - { - visit_expr(*x.m_arg); - src = "imag(" + src + ")"; - } - - void visit_StringItem(const ASR::StringItem_t& x) - { - this->visit_expr(*x.m_idx); - std::string idx = std::move(src); - this->visit_expr(*x.m_arg); - std::string str = std::move(src); - src = str + "[" + idx + "]"; - } - - void visit_StringLen(const ASR::StringLen_t& x) - { - visit_expr(*x.m_arg); - src = "length(" + src + ")"; - } - - void visit_StringSection(const ASR::StringSection_t& x) - { - visit_expr(*x.m_arg); - std::string out = src; - out += "["; - if (!x.m_start && !x.m_end) { - out += ":"; - } - if (x.m_start) { - visit_expr(*x.m_start); - out += src; - } else { - out += "begin"; - } - out += ":"; - if (x.m_step) { - visit_expr(*x.m_step); - out += src + ":"; - } - if (x.m_end) { - visit_expr(*x.m_end); - out += src; - } else { - out += "end"; - } - out += "]"; - last_expr_precedence = julia_prec::Base; - src = out; - } - - void visit_ArraySize(const ASR::ArraySize_t& x) - { - this->visit_expr(*x.m_v); - std::string var_name = src; - std::string args = ""; - if (x.m_dim == nullptr) { - src = "length(" + var_name + ")"; - } else { - this->visit_expr(*x.m_dim); - src = "size(" + var_name + ")[" + src + "]"; - } - } - - void visit_ArrayItem(const ASR::ArrayItem_t& x) - { - visit_expr(*x.m_v); - std::string out = src; - ASR::dimension_t* m_dims; - ASRUtils::extract_dimensions_from_ttype(ASRUtils::expr_type(x.m_v), m_dims); - out += "["; - std::string index = ""; - for (size_t i = 0; i < x.n_args; i++) { - std::string current_index = ""; - if (x.m_args[i].m_right) { - visit_expr(*x.m_args[i].m_right); - } else { - src = "/* FIXME right index */"; - } - out += src; - if (i < x.n_args - 1) { - out += ", "; - } - } - out += "]"; - last_expr_precedence = julia_prec::Base; - src = out; - } - - void visit_ArraySection(const ASR::ArraySection_t& x) - { - visit_expr(*x.m_v); - std::string out = src; - ASR::dimension_t* m_dims; - ASRUtils::extract_dimensions_from_ttype(ASRUtils::expr_type(x.m_v), m_dims); - out += "["; - std::string index = ""; - for (size_t i = 0; i < x.n_args; i++) { - if (!x.m_args[i].m_left && !x.m_args[i].m_right) { - out += ":"; - } else { - if (x.m_args[i].m_left) { - visit_expr(*x.m_args[i].m_left); - } else { - src = "begin"; - } - out += src + ":"; - if (x.m_args[i].m_step) { - visit_expr(*x.m_args[i].m_step); - out += src + ":"; - } - if (x.m_args[i].m_right) { - visit_expr(*x.m_args[i].m_right); - } else { - src = "end"; - } - out += src; - } - if (i < x.n_args - 1) { - out += ", "; - } - } - out += "]"; - last_expr_precedence = julia_prec::Base; - src = out; - } - - void visit_ArrayMatMul(const ASR::ArrayMatMul_t& x) - { - visit_expr(*x.m_matrix_a); - std::string left = std::move(src); - int left_precedence = last_expr_precedence; - visit_expr(*x.m_matrix_b); - std::string right = std::move(src); - int right_precedence = last_expr_precedence; - last_expr_precedence = julia_prec::Mul; - src = format_binop(left, "*", right, left_precedence, right_precedence); - } - - void visit_TupleLen(const ASR::TupleLen_t& x) - { - visit_expr(*x.m_arg); - src = "length(" + src + ")"; - } - - void visit_SetLen(const ASR::SetLen_t& x) - { - visit_expr(*x.m_arg); - src = "length(" + src + ")"; - } - - void visit_DictItem(const ASR::DictItem_t& x) - { - visit_expr(*x.m_a); - std::string out = src; - out += "["; - visit_expr(*x.m_key); - out += src + "]"; - last_expr_precedence = julia_prec::Base; - src = out; - } - - void visit_DictLen(const ASR::DictLen_t& x) - { - visit_expr(*x.m_arg); - src = "length(" + src + ")"; - } - - void visit_Print(const ASR::Print_t& x) - { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string out = indent + "println(", sep; - if (x.m_separator) { - visit_expr(*x.m_separator); - sep = src; - } else { - sep = "\" \""; - } - for (size_t i = 0; i < x.n_values; i++) { - visit_expr(*x.m_values[i]); - out += src; - if (i + 1 != x.n_values) { - out += ", " + sep + ", "; - } - } - if (x.m_end) { - visit_expr(*x.m_end); - out += src; - } - - out += ")\n"; - src = out; - } - - // TODO: implement real file write - void visit_FileWrite(const ASR::FileWrite_t& /* x */) - { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string out = indent + "// FIXME: File Write\n"; - src = out; - } - - // TODO: implement real file read - void visit_FileRead(const ASR::FileRead_t& /* x */) - { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string out = indent + "// FIXME: File Read\n"; - src = out; - } -}; - -Result -asr_to_julia(Allocator& al, ASR::TranslationUnit_t& asr, diag::Diagnostics& diag) -{ - ASRToJuliaVisitor v(al, diag); - try { - v.visit_asr((ASR::asr_t&) asr); - } catch (const CodeGenError& e) { - diag.diagnostics.push_back(e.d); - return Error(); - } catch (const Abort&) { - return Error(); - } - return v.src; -}; - -} // namespace LCompilers diff --git a/src/libasr/codegen/asr_to_julia.h b/src/libasr/codegen/asr_to_julia.h deleted file mode 100644 index bc9e86289b..0000000000 --- a/src/libasr/codegen/asr_to_julia.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef LFORTRAN_ASR_TO_JULIA_H -#define LFORTRAN_ASR_TO_JULIA_H - -#include -#include -#include -// #include - -namespace LCompilers { - - Result - asr_to_julia(Allocator& al, ASR::TranslationUnit_t& asr, diag::Diagnostics& diag); - -} // namespace LCompilers - -#endif // LFORTRAN_ASR_TO_JULIA_H diff --git a/src/libasr/codegen/asr_to_llvm.cpp b/src/libasr/codegen/asr_to_llvm.cpp deleted file mode 100644 index 6627491a4a..0000000000 --- a/src/libasr/codegen/asr_to_llvm.cpp +++ /dev/null @@ -1,7059 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if LLVM_VERSION_MAJOR >= 11 -# define FIXED_VECTOR_TYPE llvm::FixedVectorType -#else -# define FIXED_VECTOR_TYPE llvm::VectorType -#endif - - -namespace LCompilers { - -namespace { - - // This exception is used to abort the visitor pattern when an error occurs. - // This is only used locally in this file, not propagated outside. An error - // must be already present in ASRToLLVMVisitor::diag before throwing this - // exception. This is checked with an assert when the CodeGenAbort is - // caught. - class CodeGenAbort - { - }; - - // Local exception that is only used in this file to exit the visitor - // pattern and caught later (not propagated outside). It accepts an error - // message that is then appended at the end of ASRToLLVMVisitor::diag. The - // `diag` can already contain other errors or warnings. This is a - // convenience class. One can also report the error into `diag` directly and - // call `CodeGenAbort` instead. - class CodeGenError - { - public: - diag::Diagnostic d; - public: - CodeGenError(const std::string &msg) - : d{diag::Diagnostic(msg, diag::Level::Error, diag::Stage::CodeGen)} - { } - - CodeGenError(const std::string &msg, const Location &loc) - : d{diag::Diagnostic(msg, diag::Level::Error, diag::Stage::CodeGen, { - diag::Label("", {loc}) - })} - { } - }; - -} - - -using ASR::is_a; -using ASR::down_cast; -using ASR::down_cast2; - -using ASRUtils::expr_type; -using ASRUtils::symbol_get_past_external; -using ASRUtils::EXPR2VAR; -using ASRUtils::EXPR2FUN; -using ASRUtils::intent_local; -using ASRUtils::intent_return_var; -using ASRUtils::determine_module_dependencies; -using ASRUtils::is_arg_dummy; - -// Platform dependent fast unique hash: -uint64_t static get_hash(ASR::asr_t *node) -{ - return (uint64_t)node; -} - -void string_init(llvm::LLVMContext &context, llvm::Module &module, - llvm::IRBuilder<> &builder, llvm::Value* arg_size, llvm::Value* arg_string) { - std::string func_name = "_lfortran_string_init"; - llvm::Function *fn = module.getFunction(func_name); - if (!fn) { - llvm::FunctionType *function_type = llvm::FunctionType::get( - llvm::Type::getVoidTy(context), { - llvm::Type::getInt32Ty(context), - llvm::Type::getInt8PtrTy(context) - }, true); - fn = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, func_name, module); - } - std::vector args = {arg_size, arg_string}; - builder.CreateCall(fn, args); -} - -class ASRToLLVMVisitor : public ASR::BaseVisitor -{ -private: - //! To be used by visit_StructInstanceMember. - std::string der_type_name; - - //! Helpful for debugging while testing LLVM code - void print_util(llvm::Value* v, std::string fmt_chars, std::string endline="\t") { - std::vector args; - std::vector fmt; - args.push_back(v); - fmt.push_back(fmt_chars); - std::string fmt_str; - for (size_t i=0; iCreateGlobalStringPtr(fmt_str); - std::vector printf_args; - printf_args.push_back(fmt_ptr); - printf_args.insert(printf_args.end(), args.begin(), args.end()); - printf(context, *module, *builder, printf_args); - } - -public: - diag::Diagnostics &diag; - llvm::LLVMContext &context; - std::unique_ptr module; - std::unique_ptr> builder; - std::string infile; - Allocator &al; - - llvm::Value *tmp; - llvm::BasicBlock *current_loophead, *current_loopend, *proc_return, *block_end_label; - std::string mangle_prefix; - bool prototype_only; - llvm::StructType *complex_type_4, *complex_type_8; - llvm::StructType *complex_type_4_ptr, *complex_type_8_ptr; - llvm::PointerType *character_type; - llvm::PointerType *list_type; - - std::unordered_map> arr_arg_type_cache; - - std::map> fname2arg_type; - - // Maps for containing information regarding derived types - std::map name2dertype; - std::map dertype2parent; - std::map> name2memidx; - - std::map llvm_symtab; // llvm_symtab_value - std::map llvm_symtab_fn; - std::map llvm_symtab_fn_names; - std::map llvm_symtab_fn_arg; - std::map llvm_goto_targets; - - // Data members for handling nested functions - std::map> nesting_map; /* For saving the - relationship between enclosing and nested functions */ - std::vector nested_globals; /* For saving the hash of variables - from a parent scope needed in a nested function */ - std::map> nested_func_types; /* For - saving the hash of a parent function needing to give access to - variables in a nested function, as well as the variable types */ - llvm::StructType* nested_global_struct; /*The struct type that will hold - variables needed in a nested function; will contain types as given in - the runtime descriptor member */ - std::string nested_desc_name; // For setting the name of the global struct - std::vector nested_call_out; /* Hash of functions containing - nested functions that can call functions besides the nested functions - - in such cases we need a means to save the local context */ - llvm::StructType* nested_global_struct_vals; /*Equivalent struct type to - nested_global_struct, but holding types that nested_global_struct points - to. Needed in cases where we need to store values and preserve a local - context */ - llvm::ArrayType* nested_global_stack; /* An array type for holding numerous - nested_global_struct_vals, serving as a stack to reload values when - we may are leaving or re-entering states with a need to preserve - context*/ - std::string nested_stack_name; // The name of the nested_global_stack - std::string nested_sp_name; /* The stack pointer name for the - nested_global_stack */ - uint64_t parent_function_hash; - uint64_t calling_function_hash; /* These hashes are compared to resulted - from the nested_vars analysis pass to determine if we need to save or - reload a local scope (and increment or decrement the stack pointer) */ - const ASR::Function_t *parent_function = nullptr; - - std::unique_ptr llvm_utils; - std::unique_ptr list_api; - std::unique_ptr tuple_api; - std::unique_ptr dict_api_lp; - std::unique_ptr dict_api_sc; - std::unique_ptr arr_descr; - - int64_t ptr_loads; - bool lookup_enum_value_for_nonints; - bool is_assignment_target; - bool in_block = false; - - CompilerOptions &compiler_options; - - // For handling debug information - std::unique_ptr DBuilder; - llvm::DICompileUnit *debug_CU; - llvm::DIScope *debug_current_scope; - std::map llvm_symtab_fn_discope; - llvm::DIFile *debug_Unit; - - ASRToLLVMVisitor(Allocator &al, llvm::LLVMContext &context, std::string infile, - CompilerOptions &compiler_options_, diag::Diagnostics &diagnostics) : - diag{diagnostics}, - context(context), - builder(std::make_unique>(context)), - infile{infile}, - al{al}, - prototype_only(false), - llvm_utils(std::make_unique(context, builder.get())), - list_api(std::make_unique(context, llvm_utils.get(), builder.get())), - tuple_api(std::make_unique(context, llvm_utils.get(), builder.get())), - dict_api_lp(std::make_unique(context, llvm_utils.get(), builder.get())), - dict_api_sc(std::make_unique(context, llvm_utils.get(), builder.get())), - arr_descr(LLVMArrUtils::Descriptor::get_descriptor(context, - builder.get(), - llvm_utils.get(), - LLVMArrUtils::DESCR_TYPE::_SimpleCMODescriptor)), - ptr_loads(2), - lookup_enum_value_for_nonints(false), - is_assignment_target(false), - compiler_options(compiler_options_) - { - llvm_utils->tuple_api = tuple_api.get(); - llvm_utils->list_api = list_api.get(); - llvm_utils->dict_api = nullptr; - llvm_utils->arr_api = arr_descr.get(); - } - - llvm::Value* CreateLoad(llvm::Value *x) { - return LLVM::CreateLoad(*builder, x); - } - - - llvm::Value* CreateGEP(llvm::Value *x, std::vector &idx) { - return LLVM::CreateGEP(*builder, x, idx); - } - - // Inserts a new block `bb` using the current builder - // and terminates the previous block if it is not already terminated - void start_new_block(llvm::BasicBlock *bb) { - llvm::BasicBlock *last_bb = builder->GetInsertBlock(); - llvm::Function *fn = last_bb->getParent(); - llvm::Instruction *block_terminator = last_bb->getTerminator(); - if (block_terminator == nullptr) { - // The previous block is not terminated --- terminate it by jumping - // to our new block - builder->CreateBr(bb); - } - fn->getBasicBlockList().push_back(bb); - builder->SetInsertPoint(bb); - } - - // Note: `create_if_else` and `create_loop` are optional APIs - // that do not have to be used. Many times, for more complicated - // things, it might be more readable to just use the LLVM API - // without any extra layer on top. In some other cases, it might - // be more readable to use this abstraction. - // The `if_block` and `else_block` must generate one or more blocks. In - // addition, the `if_block` must not be terminated, we terminate it - // ourselves. The `else_block` can be either terminated or not. - template - void create_if_else(llvm::Value * cond, IF if_block, ELSE else_block) { - llvm::Function *fn = builder->GetInsertBlock()->getParent(); - - llvm::BasicBlock *thenBB = llvm::BasicBlock::Create(context, "then", fn); - llvm::BasicBlock *elseBB = llvm::BasicBlock::Create(context, "else"); - llvm::BasicBlock *mergeBB = llvm::BasicBlock::Create(context, "ifcont"); - - builder->CreateCondBr(cond, thenBB, elseBB); - builder->SetInsertPoint(thenBB); { - if_block(); - } - builder->CreateBr(mergeBB); - - start_new_block(elseBB); { - else_block(); - } - start_new_block(mergeBB); - } - - template - void create_loop(Cond condition, Body loop_body) { - dict_api_lp->set_iterators(); - dict_api_sc->set_iterators(); - llvm::BasicBlock *loophead = llvm::BasicBlock::Create(context, "loop.head"); - llvm::BasicBlock *loopbody = llvm::BasicBlock::Create(context, "loop.body"); - llvm::BasicBlock *loopend = llvm::BasicBlock::Create(context, "loop.end"); - this->current_loophead = loophead; - this->current_loopend = loopend; - - // head - start_new_block(loophead); { - llvm::Value* cond = condition(); - builder->CreateCondBr(cond, loopbody, loopend); - } - - // body - start_new_block(loopbody); { - loop_body(); - builder->CreateBr(loophead); - } - - // end - start_new_block(loopend); - dict_api_lp->reset_iterators(); - dict_api_sc->reset_iterators(); - } - - void get_type_debug_info(ASR::ttype_t* t, std::string &type_name, - uint32_t &type_size, uint32_t &type_encoding) { - type_size = ASRUtils::extract_kind_from_ttype_t(t)*8; - switch( t->type ) { - case ASR::ttypeType::Integer: { - type_name = "integer"; - type_encoding = llvm::dwarf::DW_ATE_signed; - break; - } - case ASR::ttypeType::Logical: { - type_name = "boolean"; - type_encoding = llvm::dwarf::DW_ATE_boolean; - break; - } - case ASR::ttypeType::Real: { - if( type_size == 32 ) { - type_name = "float"; - } else if( type_size == 64 ) { - type_name = "double"; - } - type_encoding = llvm::dwarf::DW_ATE_float; - break; - } - default : throw LCompilersException("Debug information for the type: `" - + ASRUtils::type_to_str_python(t) + "` is not yet implemented"); - } - } - - void debug_get_line_column(const uint32_t &loc_first, - uint32_t &line, uint32_t &column) { - LocationManager lm; - LocationManager::FileLocations fl; - fl.in_filename = infile; - lm.files.push_back(fl); - std::string input = read_file(infile); - lm.init_simple(input); - lm.file_ends.push_back(input.size()); - lm.pos_to_linecol(lm.output_to_input_pos(loc_first, false), - line, column, fl.in_filename); - } - - template - void debug_emit_loc(const T &x) { - Location loc = x.base.base.loc; - uint32_t line, column; - if (compiler_options.emit_debug_line_column) { - debug_get_line_column(loc.first, line, column); - } else { - line = loc.first; - column = 0; - } - builder->SetCurrentDebugLocation( - llvm::DILocation::get(debug_current_scope->getContext(), - line, column, debug_current_scope)); - } - - template - void debug_emit_function(const T &x, llvm::DISubprogram *&SP) { - debug_Unit = DBuilder->createFile( - debug_CU->getFilename(), - debug_CU->getDirectory()); - llvm::DIScope *FContext = debug_Unit; - uint32_t line, column; - if (compiler_options.emit_debug_line_column) { - debug_get_line_column(x.base.base.loc.first, line, column); - } else { - line = 0; - } - std::string fn_debug_name = x.m_name; - llvm::DIBasicType *return_type_info = nullptr; - if constexpr (std::is_same_v){ - if(x.m_return_var != nullptr) { - std::string type_name; uint32_t type_size, type_encoding; - get_type_debug_info(ASRUtils::expr_type(x.m_return_var), - type_name, type_size, type_encoding); - return_type_info = DBuilder->createBasicType(type_name, - type_size, type_encoding); - } - } else if constexpr (std::is_same_v) { - return_type_info = DBuilder->createBasicType("integer", 32, - llvm::dwarf::DW_ATE_signed); - } - llvm::DISubroutineType *return_type = DBuilder->createSubroutineType( - DBuilder->getOrCreateTypeArray(return_type_info)); - SP = DBuilder->createFunction( - FContext, fn_debug_name, llvm::StringRef(), debug_Unit, - line, return_type, 0, // TODO: ScopeLine - llvm::DINode::FlagPrototyped, - llvm::DISubprogram::SPFlagDefinition); - debug_current_scope = SP; - } - - inline bool verify_dimensions_t(ASR::dimension_t* m_dims, int n_dims) { - if( n_dims <= 0 ) { - return false; - } - bool is_ok = true; - for( int r = 0; r < n_dims; r++ ) { - if( m_dims[r].m_length == nullptr ) { - is_ok = false; - break; - } - } - return is_ok; - } - - llvm::Type* - get_el_type(ASR::ttype_t* m_type_) { - int a_kind = ASRUtils::extract_kind_from_ttype_t(m_type_); - llvm::Type* el_type = nullptr; - if (ASR::is_a(*m_type_)) { - ASR::ttype_t *t2 = ASR::down_cast(m_type_)->m_type; - switch(t2->type) { - case ASR::ttypeType::Integer: { - el_type = getIntType(a_kind, true); - break; - } - case ASR::ttypeType::Real: { - el_type = getFPType(a_kind, true); - break; - } - case ASR::ttypeType::Complex: { - el_type = getComplexType(a_kind, true); - break; - } - case ASR::ttypeType::Logical: { - el_type = llvm::Type::getInt1Ty(context); - break; - } - case ASR::ttypeType::Struct: { - el_type = getStructType(m_type_); - break; - } - case ASR::ttypeType::Union: { - el_type = getUnionType(m_type_); - break; - } - case ASR::ttypeType::Character: { - el_type = character_type; - break; - } - default: - break; - } - } else { - switch(m_type_->type) { - case ASR::ttypeType::Integer: { - el_type = getIntType(a_kind); - break; - } - case ASR::ttypeType::Real: { - el_type = getFPType(a_kind); - break; - } - case ASR::ttypeType::Complex: { - el_type = getComplexType(a_kind); - break; - } - case ASR::ttypeType::Logical: { - el_type = llvm::Type::getInt1Ty(context); - break; - } - case ASR::ttypeType::Struct: { - el_type = getStructType(m_type_); - break; - } - case ASR::ttypeType::Character: { - el_type = character_type; - break; - } - default: - break; - } - } - return el_type; - } - - void fill_array_details(llvm::Value* arr, llvm::Type* llvm_data_type, - ASR::dimension_t* m_dims, int n_dims, bool is_data_only=false) { - std::vector> llvm_dims; - for( int r = 0; r < n_dims; r++ ) { - ASR::dimension_t m_dim = m_dims[r]; - visit_expr(*(m_dim.m_start)); - llvm::Value* start = tmp; - visit_expr(*(m_dim.m_length)); - llvm::Value* end = tmp; - llvm_dims.push_back(std::make_pair(start, end)); - } - if( is_data_only ) { - if( !ASRUtils::is_fixed_size_array(m_dims, n_dims) ) { - llvm::Value* const_1 = llvm::ConstantInt::get(context, llvm::APInt(32, 1)); - llvm::Value* prod = const_1; - for( int r = 0; r < n_dims; r++ ) { - llvm::Value* dim_size = llvm_dims[r].second; - prod = builder->CreateMul(prod, dim_size); - } - llvm::Value* arr_first = builder->CreateAlloca(llvm_data_type, prod); - builder->CreateStore(arr_first, arr); - } - } else { - arr_descr->fill_array_details(arr, llvm_data_type, n_dims, llvm_dims); - } - } - - /* - This function fills the descriptor - (pointer to the first element, offset and descriptor of each dimension) - of the array which are allocated memory in heap. - */ - inline void fill_malloc_array_details(llvm::Value* arr, llvm::Type* llvm_data_type, - ASR::dimension_t* m_dims, int n_dims) { - std::vector> llvm_dims; - for( int r = 0; r < n_dims; r++ ) { - ASR::dimension_t m_dim = m_dims[r]; - visit_expr(*(m_dim.m_start)); - llvm::Value* start = tmp; - visit_expr(*(m_dim.m_length)); - llvm::Value* end = tmp; - llvm_dims.push_back(std::make_pair(start, end)); - } - arr_descr->fill_malloc_array_details(arr, llvm_data_type, - n_dims, llvm_dims, module.get()); - } - - inline llvm::Type* getIntType(int a_kind, bool get_pointer=false) { - llvm::Type* type_ptr = nullptr; - if( get_pointer ) { - switch(a_kind) - { - case 1: - type_ptr = llvm::Type::getInt8PtrTy(context); - break; - case 2: - type_ptr = llvm::Type::getInt16PtrTy(context); - break; - case 4: - type_ptr = llvm::Type::getInt32PtrTy(context); - break; - case 8: - type_ptr = llvm::Type::getInt64PtrTy(context); - break; - default: - throw CodeGenError("Only 8, 16, 32 and 64 bits integer kinds are supported."); - } - } else { - switch(a_kind) - { - case 1: - type_ptr = llvm::Type::getInt8Ty(context); - break; - case 2: - type_ptr = llvm::Type::getInt16Ty(context); - break; - case 4: - type_ptr = llvm::Type::getInt32Ty(context); - break; - case 8: - type_ptr = llvm::Type::getInt64Ty(context); - break; - default: - throw CodeGenError("Only 8, 16, 32 and 64 bits integer kinds are supported."); - } - } - return type_ptr; - } - - inline llvm::Type* getFPType(int a_kind, bool get_pointer=false) { - llvm::Type* type_ptr = nullptr; - if( get_pointer ) { - switch(a_kind) - { - case 4: - type_ptr = llvm::Type::getFloatPtrTy(context); - break; - case 8: - type_ptr = llvm::Type::getDoublePtrTy(context); - break; - default: - throw CodeGenError("Only 32 and 64 bits real kinds are supported."); - } - } else { - switch(a_kind) - { - case 4: - type_ptr = llvm::Type::getFloatTy(context); - break; - case 8: - type_ptr = llvm::Type::getDoubleTy(context); - break; - default: - throw CodeGenError("Only 32 and 64 bits real kinds are supported."); - } - } - return type_ptr; - } - - inline llvm::Type* getComplexType(int a_kind, bool get_pointer=false) { - llvm::Type* type = nullptr; - switch(a_kind) - { - case 4: - type = complex_type_4; - break; - case 8: - type = complex_type_8; - break; - default: - throw CodeGenError("Only 32 and 64 bits complex kinds are supported."); - } - if( type != nullptr ) { - if( get_pointer ) { - return type->getPointerTo(); - } else { - return type; - } - } - return nullptr; - } - - llvm::Type* getMemberType(ASR::ttype_t* mem_type, ASR::Variable_t* member) { - llvm::Type* llvm_mem_type = nullptr; - switch( mem_type->type ) { - case ASR::ttypeType::Integer: { - int a_kind = down_cast(mem_type)->m_kind; - llvm_mem_type = getIntType(a_kind); - break; - } - case ASR::ttypeType::Real: { - int a_kind = down_cast(mem_type)->m_kind; - llvm_mem_type = getFPType(a_kind); - break; - } - case ASR::ttypeType::Struct: { - llvm_mem_type = getStructType(mem_type); - break; - } - case ASR::ttypeType::Enum: { - llvm_mem_type = llvm::Type::getInt32Ty(context); - break ; - } - case ASR::ttypeType::Union: { - llvm_mem_type = getUnionType(mem_type); - break; - } - case ASR::ttypeType::Pointer: { - ASR::Pointer_t* ptr_type = ASR::down_cast(mem_type); - llvm_mem_type = getMemberType(ptr_type->m_type, member)->getPointerTo(); - break; - } - case ASR::ttypeType::Complex: { - int a_kind = down_cast(mem_type)->m_kind; - llvm_mem_type = getComplexType(a_kind); - break; - } - case ASR::ttypeType::Character: { - llvm_mem_type = character_type; - break; - } - case ASR::ttypeType::CPtr: { - llvm_mem_type = llvm::Type::getVoidTy(context)->getPointerTo(); - break; - } - default: - throw CodeGenError("Cannot identify the type of member, '" + - std::string(member->m_name) + - "' in derived type, '" + der_type_name + "'.", - member->base.base.loc); - } - return llvm_mem_type; - } - - llvm::Type* getStructType(ASR::StructType_t* der_type, bool is_pointer=false) { - std::string der_type_name = std::string(der_type->m_name); - llvm::StructType* der_type_llvm; - if( name2dertype.find(der_type_name) != name2dertype.end() ) { - der_type_llvm = name2dertype[der_type_name]; - } else { - std::vector member_types; - int member_idx = 0; - if( der_type->m_parent != nullptr ) { - ASR::StructType_t *par_der_type = ASR::down_cast( - symbol_get_past_external(der_type->m_parent)); - llvm::Type* par_llvm = getStructType(par_der_type); - member_types.push_back(par_llvm); - dertype2parent[der_type_name] = std::string(par_der_type->m_name); - member_idx += 1; - } - - for( size_t i = 0; i < der_type->n_members; i++ ) { - std::string member_name = der_type->m_members[i]; - ASR::Variable_t* member = ASR::down_cast(der_type->m_symtab->get_symbol(member_name)); - llvm::Type* llvm_mem_type = get_type_from_ttype_t_util(member->m_type, member->m_abi); - member_types.push_back(llvm_mem_type); - name2memidx[der_type_name][std::string(member->m_name)] = member_idx; - member_idx++; - } - der_type_llvm = llvm::StructType::create(context, - member_types, - der_type_name, - der_type->m_is_packed); - name2dertype[der_type_name] = der_type_llvm; - } - if( is_pointer ) { - return der_type_llvm->getPointerTo(); - } - return (llvm::Type*) der_type_llvm; - } - - llvm::Type* getStructType(ASR::ttype_t* _type, bool is_pointer=false) { - ASR::Struct_t* der = (ASR::Struct_t*)(&(_type->base)); - ASR::symbol_t* der_sym; - if( der->m_derived_type->type == ASR::symbolType::ExternalSymbol ) { - ASR::ExternalSymbol_t* der_extr = (ASR::ExternalSymbol_t*)(&(der->m_derived_type->base)); - der_sym = der_extr->m_external; - } else { - der_sym = der->m_derived_type; - } - ASR::StructType_t* der_type = (ASR::StructType_t*)(&(der_sym->base)); - return getStructType(der_type, is_pointer); - } - - llvm::Type* getUnionType(ASR::UnionType_t* union_type, bool is_pointer=false) { - std::string union_type_name = std::string(union_type->m_name); - llvm::StructType* union_type_llvm = nullptr; - if( name2dertype.find(union_type_name) != name2dertype.end() ) { - union_type_llvm = name2dertype[union_type_name]; - } else { - const std::map& scope = union_type->m_symtab->get_scope(); - llvm::DataLayout data_layout(module.get()); - llvm::Type* max_sized_type = nullptr; - size_t max_type_size = 0; - for( auto itr = scope.begin(); itr != scope.end(); itr++ ) { - ASR::Variable_t* member = ASR::down_cast(itr->second); - llvm::Type* llvm_mem_type = getMemberType(member->m_type, member); - size_t type_size = data_layout.getTypeAllocSize(llvm_mem_type); - if( max_type_size < type_size ) { - max_sized_type = llvm_mem_type; - type_size = max_type_size; - } - } - union_type_llvm = llvm::StructType::create(context, {max_sized_type}, union_type_name); - name2dertype[union_type_name] = union_type_llvm; - } - if( is_pointer ) { - return union_type_llvm->getPointerTo(); - } - return (llvm::Type*) union_type_llvm; - } - - llvm::Type* getUnionType(ASR::ttype_t* _type, bool is_pointer=false) { - ASR::Union_t* union_ = ASR::down_cast(_type); - ASR::symbol_t* union_sym = ASRUtils::symbol_get_past_external(union_->m_union_type); - ASR::UnionType_t* union_type = ASR::down_cast(union_sym); - return getUnionType(union_type, is_pointer); - } - - llvm::Type* getClassType(ASR::ttype_t* _type, bool is_pointer=false) { - ASR::Class_t* der = (ASR::Class_t*)(&(_type->base)); - ASR::symbol_t* der_sym; - if( der->m_class_type->type == ASR::symbolType::ExternalSymbol ) { - ASR::ExternalSymbol_t* der_extr = (ASR::ExternalSymbol_t*)(&(der->m_class_type->base)); - der_sym = der_extr->m_external; - } else { - der_sym = der->m_class_type; - } - ASR::ClassType_t* der_type = (ASR::ClassType_t*)(&(der_sym->base)); - std::string der_type_name = std::string(der_type->m_name); - llvm::StructType* der_type_llvm; - if( name2dertype.find(der_type_name) != name2dertype.end() ) { - der_type_llvm = name2dertype[der_type_name]; - } else { - const std::map& scope = der_type->m_symtab->get_scope(); - std::vector member_types; - int member_idx = 0; - for( auto itr = scope.begin(); itr != scope.end(); itr++ ) { - if (!ASR::is_a(*itr->second) && - !ASR::is_a(*itr->second) && - !ASR::is_a(*itr->second)) { - ASR::Variable_t* member = ASR::down_cast(itr->second); - llvm::Type* mem_type = nullptr; - switch( member->m_type->type ) { - case ASR::ttypeType::Integer: { - int a_kind = down_cast(member->m_type)->m_kind; - mem_type = getIntType(a_kind); - break; - } - case ASR::ttypeType::Real: { - int a_kind = down_cast(member->m_type)->m_kind; - mem_type = getFPType(a_kind); - break; - } - case ASR::ttypeType::Class: { - mem_type = getClassType(member->m_type); - break; - } - case ASR::ttypeType::Complex: { - int a_kind = down_cast(member->m_type)->m_kind; - mem_type = getComplexType(a_kind); - break; - } - default: - throw CodeGenError("Cannot identify the type of member, '" + - std::string(member->m_name) + - "' in derived type, '" + der_type_name + "'.", - member->base.base.loc); - } - member_types.push_back(mem_type); - name2memidx[der_type_name][std::string(member->m_name)] = member_idx; - member_idx++; - } - } - der_type_llvm = llvm::StructType::create(context, member_types, der_type_name); - name2dertype[der_type_name] = der_type_llvm; - } - if( is_pointer ) { - return der_type_llvm->getPointerTo(); - } - return (llvm::Type*) der_type_llvm; - } - - - /* - * Dispatches the required function from runtime library to - * perform the specified binary operation. - * - * @param left_arg llvm::Value* The left argument of the binary operator. - * @param right_arg llvm::Value* The right argument of the binary operator. - * @param runtime_func_name std::string The name of the function to be dispatched - * from runtime library. - * @returns llvm::Value* The result of the operation. - * - * Note - * ==== - * - * Internally the call to this function gets transformed into a runtime call: - * void _lfortran_complex_add(complex* a, complex* b, complex *result) - * - * As of now the following values for func_name are supported, - * - * _lfortran_complex_add - * _lfortran_complex_sub - * _lfortran_complex_div - * _lfortran_complex_mul - */ - llvm::Value* lfortran_complex_bin_op(llvm::Value* left_arg, llvm::Value* right_arg, - std::string runtime_func_name, - llvm::Type* complex_type=nullptr) - { - if( complex_type == nullptr ) { - complex_type = complex_type_4; - } - llvm::Function *fn = module->getFunction(runtime_func_name); - if (!fn) { - llvm::FunctionType *function_type = llvm::FunctionType::get( - llvm::Type::getVoidTy(context), { - complex_type->getPointerTo(), - complex_type->getPointerTo(), - complex_type->getPointerTo() - }, true); - fn = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, runtime_func_name, *module); - } - - llvm::AllocaInst *pleft_arg = builder->CreateAlloca(complex_type, - nullptr); - - builder->CreateStore(left_arg, pleft_arg); - llvm::AllocaInst *pright_arg = builder->CreateAlloca(complex_type, - nullptr); - builder->CreateStore(right_arg, pright_arg); - llvm::AllocaInst *presult = builder->CreateAlloca(complex_type, - nullptr); - std::vector args = {pleft_arg, pright_arg, presult}; - builder->CreateCall(fn, args); - return CreateLoad(presult); - } - - - llvm::Value* lfortran_strop(llvm::Value* left_arg, llvm::Value* right_arg, - std::string runtime_func_name) - { - llvm::Function *fn = module->getFunction(runtime_func_name); - if (!fn) { - llvm::FunctionType *function_type = llvm::FunctionType::get( - llvm::Type::getVoidTy(context), { - character_type->getPointerTo(), - character_type->getPointerTo(), - character_type->getPointerTo() - }, false); - fn = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, runtime_func_name, *module); - } - llvm::AllocaInst *pleft_arg = builder->CreateAlloca(character_type, - nullptr); - builder->CreateStore(left_arg, pleft_arg); - llvm::AllocaInst *pright_arg = builder->CreateAlloca(character_type, - nullptr); - builder->CreateStore(right_arg, pright_arg); - llvm::AllocaInst *presult = builder->CreateAlloca(character_type, - nullptr); - std::vector args = {pleft_arg, pright_arg, presult}; - builder->CreateCall(fn, args); - return CreateLoad(presult); - } - - llvm::Value* lfortran_str_cmp(llvm::Value* left_arg, llvm::Value* right_arg, - std::string runtime_func_name) - { - llvm::Function *fn = module->getFunction(runtime_func_name); - if(!fn) { - llvm::FunctionType *function_type = llvm::FunctionType::get( - llvm::Type::getInt1Ty(context), { - character_type->getPointerTo(), - character_type->getPointerTo() - }, false); - fn = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, runtime_func_name, *module); - } - llvm::AllocaInst *pleft_arg = builder->CreateAlloca(character_type, - nullptr); - builder->CreateStore(left_arg, pleft_arg); - llvm::AllocaInst *pright_arg = builder->CreateAlloca(character_type, - nullptr); - builder->CreateStore(right_arg, pright_arg); - std::vector args = {pleft_arg, pright_arg}; - return builder->CreateCall(fn, args); - } - - llvm::Value* lfortran_strrepeat(llvm::Value* left_arg, llvm::Value* right_arg) - { - std::string runtime_func_name = "_lfortran_strrepeat"; - llvm::Function *fn = module->getFunction(runtime_func_name); - if (!fn) { - llvm::FunctionType *function_type = llvm::FunctionType::get( - llvm::Type::getVoidTy(context), { - character_type->getPointerTo(), - llvm::Type::getInt32Ty(context), - character_type->getPointerTo() - }, false); - fn = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, runtime_func_name, *module); - } - llvm::AllocaInst *pleft_arg = builder->CreateAlloca(character_type, - nullptr); - builder->CreateStore(left_arg, pleft_arg); - llvm::AllocaInst *presult = builder->CreateAlloca(character_type, - nullptr); - std::vector args = {pleft_arg, right_arg, presult}; - builder->CreateCall(fn, args); - return CreateLoad(presult); - } - - llvm::Value* lfortran_str_len(llvm::Value* str) - { - std::string runtime_func_name = "_lfortran_str_len"; - llvm::Function *fn = module->getFunction(runtime_func_name); - if (!fn) { - llvm::FunctionType *function_type = llvm::FunctionType::get( - llvm::Type::getInt32Ty(context), { - character_type->getPointerTo() - }, false); - fn = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, runtime_func_name, *module); - } - return builder->CreateCall(fn, {str}); - } - - llvm::Value* lfortran_str_to_int(llvm::Value* str) - { - std::string runtime_func_name = "_lfortran_str_to_int"; - llvm::Function *fn = module->getFunction(runtime_func_name); - if (!fn) { - llvm::FunctionType *function_type = llvm::FunctionType::get( - llvm::Type::getInt32Ty(context), { - character_type->getPointerTo() - }, false); - fn = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, runtime_func_name, *module); - } - return builder->CreateCall(fn, {str}); - } - - llvm::Value* lfortran_str_ord(llvm::Value* str) - { - std::string runtime_func_name = "_lfortran_str_ord"; - llvm::Function *fn = module->getFunction(runtime_func_name); - if (!fn) { - llvm::FunctionType *function_type = llvm::FunctionType::get( - llvm::Type::getInt32Ty(context), { - character_type->getPointerTo() - }, false); - fn = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, runtime_func_name, *module); - } - return builder->CreateCall(fn, {str}); - } - - llvm::Value* lfortran_str_chr(llvm::Value* str) - { - std::string runtime_func_name = "_lfortran_str_chr"; - llvm::Function *fn = module->getFunction(runtime_func_name); - if (!fn) { - llvm::FunctionType *function_type = llvm::FunctionType::get( - character_type, { - llvm::Type::getInt32Ty(context) - }, false); - fn = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, runtime_func_name, *module); - } - return builder->CreateCall(fn, {str}); - } - - llvm::Value* lfortran_str_item(llvm::Value* str, llvm::Value* idx1) - { - std::string runtime_func_name = "_lfortran_str_item"; - llvm::Function *fn = module->getFunction(runtime_func_name); - if (!fn) { - llvm::FunctionType *function_type = llvm::FunctionType::get( - character_type, { - character_type, llvm::Type::getInt32Ty(context) - }, false); - fn = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, runtime_func_name, *module); - } - return builder->CreateCall(fn, {str, idx1}); - } - - llvm::Value* lfortran_str_slice(llvm::Value* str, llvm::Value* idx1, llvm::Value* idx2, - llvm::Value* step, llvm::Value* left_present, llvm::Value* right_present) - { - std::string runtime_func_name = "_lfortran_str_slice"; - llvm::Function *fn = module->getFunction(runtime_func_name); - if (!fn) { - llvm::FunctionType *function_type = llvm::FunctionType::get( - character_type, { - character_type, llvm::Type::getInt32Ty(context), - llvm::Type::getInt32Ty(context), llvm::Type::getInt32Ty(context), - llvm::Type::getInt1Ty(context), llvm::Type::getInt1Ty(context) - }, false); - fn = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, runtime_func_name, *module); - } - return builder->CreateCall(fn, {str, idx1, idx2, step, left_present, right_present}); - } - - llvm::Value* lfortran_type_to_str(llvm::Value* arg, llvm::Type* value_type, std::string type, int value_kind) { - std::string func_name = "_lfortran_" + type + "_to_str" + std::to_string(value_kind); - llvm::Function *fn = module->getFunction(func_name); - if(!fn) { - llvm::FunctionType *function_type = llvm::FunctionType::get( - character_type, { - value_type - }, false); - fn = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, func_name, *module); - } - llvm::Value* res = builder->CreateCall(fn, {arg}); - return res; - } - - // This function is called as: - // float complex_re(complex a) - // And it extracts the real part of the complex number - llvm::Value *complex_re(llvm::Value *c, llvm::Type* complex_type=nullptr) { - if( complex_type == nullptr ) { - complex_type = complex_type_4; - } - if( c->getType()->isPointerTy() ) { - c = CreateLoad(c); - } - llvm::AllocaInst *pc = builder->CreateAlloca(complex_type, nullptr); - builder->CreateStore(c, pc); - std::vector idx = { - llvm::ConstantInt::get(context, llvm::APInt(32, 0)), - llvm::ConstantInt::get(context, llvm::APInt(32, 0))}; - llvm::Value *pim = CreateGEP(pc, idx); - return CreateLoad(pim); - } - - llvm::Value *complex_im(llvm::Value *c, llvm::Type* complex_type=nullptr) { - if( complex_type == nullptr ) { - complex_type = complex_type_4; - } - llvm::AllocaInst *pc = builder->CreateAlloca(complex_type, nullptr); - builder->CreateStore(c, pc); - std::vector idx = { - llvm::ConstantInt::get(context, llvm::APInt(32, 0)), - llvm::ConstantInt::get(context, llvm::APInt(32, 1))}; - llvm::Value *pim = CreateGEP(pc, idx); - return CreateLoad(pim); - } - - llvm::Value *complex_from_floats(llvm::Value *re, llvm::Value *im, - llvm::Type* complex_type=nullptr) { - if( complex_type == nullptr ) { - complex_type = complex_type_4; - } - llvm::AllocaInst *pres = builder->CreateAlloca(complex_type, nullptr); - std::vector idx1 = { - llvm::ConstantInt::get(context, llvm::APInt(32, 0)), - llvm::ConstantInt::get(context, llvm::APInt(32, 0))}; - std::vector idx2 = { - llvm::ConstantInt::get(context, llvm::APInt(32, 0)), - llvm::ConstantInt::get(context, llvm::APInt(32, 1))}; - llvm::Value *pre = CreateGEP(pres, idx1); - llvm::Value *pim = CreateGEP(pres, idx2); - builder->CreateStore(re, pre); - builder->CreateStore(im, pim); - return CreateLoad(pres); - } - - llvm::Value *nested_struct_rd(std::vector vals, - llvm::StructType* rd) { - llvm::AllocaInst *pres = builder->CreateAlloca(rd, nullptr); - llvm::Value *pim = CreateGEP(pres, vals); - return CreateLoad(pim); - } - - /** - * @brief This function generates the - * @detail This is converted to - * - * float lfortran_KEY(float *x) - * - * Where KEY can be any of the supported intrinsics; this is then - * transformed into a runtime call: - * - * void _lfortran_KEY(float x, float *result) - */ - llvm::Value* lfortran_intrinsic(llvm::Function *fn, llvm::Value* pa, int a_kind) - { - llvm::Type *presult_type = getFPType(a_kind); - llvm::AllocaInst *presult = builder->CreateAlloca(presult_type, nullptr); - llvm::Value *a = CreateLoad(pa); - std::vector args = {a, presult}; - builder->CreateCall(fn, args); - return CreateLoad(presult); - } - - void visit_TranslationUnit(const ASR::TranslationUnit_t &x) { - module = std::make_unique("LFortran", context); - module->setDataLayout(""); - - if (compiler_options.emit_debug_info) { - DBuilder = std::make_unique(*module); - debug_CU = DBuilder->createCompileUnit( - llvm::dwarf::DW_LANG_C, DBuilder->createFile(infile, "."), - "LPython Compiler", false, "", 0); - } - - // All loose statements must be converted to a function, so the items - // must be empty: - LCOMPILERS_ASSERT(x.n_items == 0); - - // Define LLVM types that we might need - // Complex type is represented as an identified struct in LLVM - // %complex = type { float, float } - std::vector els_4 = { - llvm::Type::getFloatTy(context), - llvm::Type::getFloatTy(context)}; - std::vector els_8 = { - llvm::Type::getDoubleTy(context), - llvm::Type::getDoubleTy(context)}; - std::vector els_4_ptr = { - llvm::Type::getFloatPtrTy(context), - llvm::Type::getFloatPtrTy(context)}; - std::vector els_8_ptr = { - llvm::Type::getDoublePtrTy(context), - llvm::Type::getDoublePtrTy(context)}; - complex_type_4 = llvm::StructType::create(context, els_4, "complex_4"); - complex_type_8 = llvm::StructType::create(context, els_8, "complex_8"); - complex_type_4_ptr = llvm::StructType::create(context, els_4_ptr, "complex_4_ptr"); - complex_type_8_ptr = llvm::StructType::create(context, els_8_ptr, "complex_8_ptr"); - character_type = llvm::Type::getInt8PtrTy(context); - list_type = llvm::Type::getInt8PtrTy(context); - - llvm::Type* bound_arg = static_cast(arr_descr->get_dimension_descriptor_type(true)); - fname2arg_type["lbound"] = std::make_pair(bound_arg, bound_arg->getPointerTo()); - fname2arg_type["ubound"] = std::make_pair(bound_arg, bound_arg->getPointerTo()); - - // Process Variables first: - for (auto &item : x.m_global_scope->get_scope()) { - if (is_a(*item.second) || - is_a(*item.second)) { - visit_symbol(*item.second); - } - } - - prototype_only = false; - for (auto &item : x.m_global_scope->get_scope()) { - if (is_a(*item.second) && - item.first.find("lfortran_intrinsic_optimization") != std::string::npos) { - ASR::Module_t* mod = ASR::down_cast(item.second); - for( auto &moditem: mod->m_symtab->get_scope() ) { - ASR::symbol_t* sym = ASRUtils::symbol_get_past_external(moditem.second); - if (is_a(*sym)) { - visit_Function(*ASR::down_cast(sym)); - } - } - } - } - - prototype_only = true; - // Generate function prototypes - for (auto &item : x.m_global_scope->get_scope()) { - if (is_a(*item.second)) { - if (ASRUtils::get_FunctionType(ASR::down_cast(item.second))->n_type_params == 0) { - visit_Function(*ASR::down_cast(item.second)); - } - } - } - prototype_only = false; - - // TODO: handle dependencies across modules and main program - - // Then do all the modules in the right order - std::vector build_order - = determine_module_dependencies(x); - for (auto &item : build_order) { - LCOMPILERS_ASSERT(x.m_global_scope->get_symbol(item) - != nullptr); - ASR::symbol_t *mod = x.m_global_scope->get_symbol(item); - visit_symbol(*mod); - } - - // Then do all the procedures - for (auto &item : x.m_global_scope->get_scope()) { - if (is_a(*item.second)) { - if (ASRUtils::get_FunctionType(ASR::down_cast(item.second))->n_type_params == 0) { - visit_symbol(*item.second); - } - } - } - - // Then the main program - for (auto &item : x.m_global_scope->get_scope()) { - if (is_a(*item.second)) { - visit_symbol(*item.second); - } - } - } - - void visit_Allocate(const ASR::Allocate_t& x) { - for( size_t i = 0; i < x.n_args; i++ ) { - ASR::alloc_arg_t curr_arg = x.m_args[i]; - ASR::symbol_t* tmp_sym = nullptr; - ASR::expr_t* tmp_expr = x.m_args[i].m_a; - if( ASR::is_a(*tmp_expr) ) { - const ASR::Var_t* tmp_var = ASR::down_cast(tmp_expr); - tmp_sym = tmp_var->m_v; - } else { - throw CodeGenError("Cannot deallocate variables in expression " + - std::to_string(tmp_expr->type), - tmp_expr->base.loc); - } - std::uint32_t h = get_hash((ASR::asr_t*)tmp_sym); - LCOMPILERS_ASSERT(llvm_symtab.find(h) != llvm_symtab.end()); - llvm::Value* x_arr = llvm_symtab[h]; - ASR::ttype_t* curr_arg_m_a_type = ASRUtils::symbol_type(tmp_sym); - ASR::ttype_t* asr_data_type = ASRUtils::duplicate_type_without_dims(al, - curr_arg_m_a_type, curr_arg_m_a_type->base.loc); - llvm::Type* llvm_data_type = get_type_from_ttype_t_util(asr_data_type); - fill_malloc_array_details(x_arr, llvm_data_type, curr_arg.m_dims, curr_arg.n_dims); - } - if (x.m_stat) { - ASR::Variable_t *asr_target = EXPR2VAR(x.m_stat); - uint32_t h = get_hash((ASR::asr_t*)asr_target); - if (llvm_symtab.find(h) != llvm_symtab.end()) { - llvm::Value *target, *value; - target = llvm_symtab[h]; - // Store 0 (success) in the stat variable - value = llvm::ConstantInt::get(context, llvm::APInt(32, 0)); - builder->CreateStore(value, target); - } else { - throw CodeGenError("Stat variable in allocate not found in LLVM symtab"); - } - } - } - - void visit_Nullify(const ASR::Nullify_t& x) { - for( size_t i = 0; i < x.n_vars; i++ ) { - std::uint32_t h = get_hash((ASR::asr_t*)x.m_vars[i]); - llvm::Value *target = llvm_symtab[h]; - llvm::Type* tp = target->getType()->getContainedType(0); - llvm::Value* np = builder->CreateIntToPtr( - llvm::ConstantInt::get(context, llvm::APInt(32, 0)), tp); - builder->CreateStore(np, target); - } - } - - inline void call_lfortran_free(llvm::Function* fn) { - llvm::Value* arr = CreateLoad(arr_descr->get_pointer_to_data(tmp)); - llvm::AllocaInst *arg_arr = builder->CreateAlloca(character_type, nullptr); - builder->CreateStore(builder->CreateBitCast(arr, character_type), arg_arr); - std::vector args = {CreateLoad(arg_arr)}; - builder->CreateCall(fn, args); - arr_descr->set_is_allocated_flag(tmp, 0); - } - - llvm::Function* _Deallocate() { - std::string func_name = "_lfortran_free"; - llvm::Function *free_fn = module->getFunction(func_name); - if (!free_fn) { - llvm::FunctionType *function_type = llvm::FunctionType::get( - llvm::Type::getVoidTy(context), { - character_type - }, true); - free_fn = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, func_name, *module); - } - return free_fn; - } - - void visit_ImplicitDeallocate(const ASR::ImplicitDeallocate_t& x) { - llvm::Function* free_fn = _Deallocate(); - for( size_t i = 0; i < x.n_vars; i++ ) { - const ASR::symbol_t* curr_obj = x.m_vars[i]; - ASR::Variable_t *v = ASR::down_cast( - symbol_get_past_external(curr_obj)); - fetch_var(v); - llvm::Value *cond = arr_descr->get_is_allocated_flag(tmp); - create_if_else(cond, [=]() { - call_lfortran_free(free_fn); - }, [](){}); - } - } - - void visit_ExplicitDeallocate(const ASR::ExplicitDeallocate_t& x) { - llvm::Function* free_fn = _Deallocate(); - for( size_t i = 0; i < x.n_vars; i++ ) { - const ASR::expr_t* tmp_expr = x.m_vars[i]; - ASR::symbol_t* curr_obj = nullptr; - if( ASR::is_a(*tmp_expr) ) { - const ASR::Var_t* tmp_var = ASR::down_cast(tmp_expr); - curr_obj = tmp_var->m_v; - } else { - throw CodeGenError("Cannot deallocate variables in expression " + - std::to_string(tmp_expr->type), - tmp_expr->base.loc); - } - ASR::Variable_t *v = ASR::down_cast( - symbol_get_past_external(curr_obj)); - fetch_var(v); - call_lfortran_free(free_fn); - } - } - - void visit_ListConstant(const ASR::ListConstant_t& x) { - ASR::List_t* list_type = ASR::down_cast(x.m_type); - bool is_array_type_local = false, is_malloc_array_type_local = false; - bool is_list_local = false; - ASR::dimension_t* m_dims_local = nullptr; - int n_dims_local = -1, a_kind_local = -1; - llvm::Type* llvm_el_type = get_type_from_ttype_t(list_type->m_type, - ASR::storage_typeType::Default, is_array_type_local, - is_malloc_array_type_local, is_list_local, m_dims_local, - n_dims_local, a_kind_local); - std::string type_code = ASRUtils::get_type_code(list_type->m_type); - int32_t type_size = -1; - if( ASR::is_a(*list_type->m_type) || - LLVM::is_llvm_struct(list_type->m_type) || - ASR::is_a(*list_type->m_type) ) { - llvm::DataLayout data_layout(module.get()); - type_size = data_layout.getTypeAllocSize(llvm_el_type); - } else { - type_size = ASRUtils::extract_kind_from_ttype_t(list_type->m_type); - } - llvm::Type* const_list_type = list_api->get_list_type(llvm_el_type, type_code, type_size); - llvm::Value* const_list = builder->CreateAlloca(const_list_type, nullptr, "const_list"); - list_api->list_init(type_code, const_list, *module, x.n_args, x.n_args); - int64_t ptr_loads_copy = ptr_loads; - ptr_loads = 1; - for( size_t i = 0; i < x.n_args; i++ ) { - this->visit_expr(*x.m_args[i]); - llvm::Value* item = tmp; - llvm::Value* pos = llvm::ConstantInt::get(context, llvm::APInt(32, i)); - list_api->write_item(const_list, pos, item, list_type->m_type, - false, module.get(), name2memidx); - } - ptr_loads = ptr_loads_copy; - tmp = const_list; - } - - void set_dict_api(ASR::Dict_t* dict_type) { - if( ASR::is_a(*dict_type->m_key_type) ) { - llvm_utils->dict_api = dict_api_sc.get(); - } else { - llvm_utils->dict_api = dict_api_lp.get(); - } - } - - void visit_DictConstant(const ASR::DictConstant_t& x) { - llvm::Type* const_dict_type = get_dict_type(x.m_type); - llvm::Value* const_dict = builder->CreateAlloca(const_dict_type, nullptr, "const_dict"); - ASR::Dict_t* x_dict = ASR::down_cast(x.m_type); - set_dict_api(x_dict); - std::string key_type_code = ASRUtils::get_type_code(x_dict->m_key_type); - std::string value_type_code = ASRUtils::get_type_code(x_dict->m_value_type); - llvm_utils->dict_api->dict_init(key_type_code, value_type_code, const_dict, module.get(), x.n_keys); - int64_t ptr_loads_key = LLVM::is_llvm_struct(x_dict->m_key_type) ? 0 : 2; - int64_t ptr_loads_value = LLVM::is_llvm_struct(x_dict->m_value_type) ? 0 : 2; - int64_t ptr_loads_copy = ptr_loads; - for( size_t i = 0; i < x.n_keys; i++ ) { - ptr_loads = ptr_loads_key; - visit_expr(*x.m_keys[i]); - llvm::Value* key = tmp; - ptr_loads = ptr_loads_value; - visit_expr(*x.m_values[i]); - llvm::Value* value = tmp; - llvm_utils->dict_api->write_item(const_dict, key, value, module.get(), - x_dict->m_key_type, x_dict->m_value_type, name2memidx); - } - ptr_loads = ptr_loads_copy; - tmp = const_dict; - } - - void visit_TupleConstant(const ASR::TupleConstant_t& x) { - ASR::Tuple_t* tuple_type = ASR::down_cast(x.m_type); - std::string type_code = ASRUtils::get_type_code(tuple_type->m_type, - tuple_type->n_type); - std::vector llvm_el_types; - ASR::storage_typeType m_storage = ASR::storage_typeType::Default; - bool is_array_type = false, is_malloc_array_type = false; - bool is_list = false; - ASR::dimension_t* m_dims = nullptr; - int n_dims = 0, a_kind = -1; - for( size_t i = 0; i < tuple_type->n_type; i++ ) { - llvm_el_types.push_back(get_type_from_ttype_t(tuple_type->m_type[i], - m_storage, is_array_type, is_malloc_array_type, - is_list, m_dims, n_dims, a_kind)); - } - llvm::Type* const_tuple_type = tuple_api->get_tuple_type(type_code, llvm_el_types); - llvm::Value* const_tuple = builder->CreateAlloca(const_tuple_type, nullptr, "const_tuple"); - std::vector init_values; - int64_t ptr_loads_copy = ptr_loads; - ptr_loads = 2; - for( size_t i = 0; i < x.n_elements; i++ ) { - this->visit_expr(*x.m_elements[i]); - init_values.push_back(tmp); - } - ptr_loads = ptr_loads_copy; - tuple_api->tuple_init(const_tuple, init_values); - tmp = const_tuple; - } - - void visit_IntegerBitLen(const ASR::IntegerBitLen_t& x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - this->visit_expr(*x.m_a); - llvm::Value *int_val = tmp; - int int_kind = ASRUtils::extract_kind_from_ttype_t(x.m_type); - std::string runtime_func_name = "_lpython_bit_length" + std::to_string(int_kind); - llvm::Function *fn = module->getFunction(runtime_func_name); - if (!fn) { - llvm::FunctionType *function_type = llvm::FunctionType::get( - llvm::Type::getInt32Ty(context), { - getIntType(int_kind) - }, false); - fn = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, runtime_func_name, *module); - } - tmp = builder->CreateCall(fn, {int_val}); - } - - void visit_Ichar(const ASR::Ichar_t &x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - this->visit_expr(*x.m_arg); - llvm::Value *c = tmp; - std::string runtime_func_name = "_lfortran_ichar"; - llvm::Function *fn = module->getFunction(runtime_func_name); - if (!fn) { - llvm::FunctionType *function_type = llvm::FunctionType::get( - llvm::Type::getInt32Ty(context), { - llvm::Type::getInt8PtrTy(context) - }, false); - fn = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, runtime_func_name, *module); - } - tmp = builder->CreateCall(fn, {c}); - } - - void visit_Iachar(const ASR::Iachar_t &x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - this->visit_expr(*x.m_arg); - llvm::Value *c = tmp; - std::string runtime_func_name = "_lfortran_iachar"; - llvm::Function *fn = module->getFunction(runtime_func_name); - if (!fn) { - llvm::FunctionType *function_type = llvm::FunctionType::get( - llvm::Type::getInt32Ty(context), { - llvm::Type::getInt8PtrTy(context) - }, false); - fn = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, runtime_func_name, *module); - } - tmp = builder->CreateCall(fn, {c}); - } - - void visit_ArrayAll(const ASR::ArrayAll_t &x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - this->visit_expr(*x.m_mask); - llvm::Value *mask = tmp; - ASR::ttype_t *type = ASRUtils::expr_type(x.m_mask); - LCOMPILERS_ASSERT(ASR::is_a(*type)) // TODO - int32_t n = ASR::down_cast(type)->n_dims; - llvm::Value *size = llvm::ConstantInt::get(context, llvm::APInt(32, n)); - if (ASR::is_a(*x.m_mask)) { - mask = LLVM::CreateLoad(*builder, llvm_utils->create_gep(mask, 0)); - } - std::string runtime_func_name = "_lfortran_all"; - llvm::Function *fn = module->getFunction(runtime_func_name); - if (!fn) { - llvm::FunctionType *function_type = llvm::FunctionType::get( - llvm::Type::getInt1Ty(context), { - llvm::Type::getInt1Ty(context)->getPointerTo(), - llvm::Type::getInt32Ty(context) - }, false); - fn = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, runtime_func_name, *module); - } - tmp = builder->CreateCall(fn, {mask, size}); - } - - void visit_IntrinsicFunctionSqrt(const ASR::IntrinsicFunctionSqrt_t &x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - this->visit_expr(*x.m_arg); - llvm::Value *c = tmp; - int64_t kind_value = ASRUtils::extract_kind_from_ttype_t(ASRUtils::expr_type(x.m_arg)); - std::string func_name; - if (kind_value ==4) { - func_name = "llvm.sqrt.f32"; - } else { - func_name = "llvm.sqrt.f64"; - } - llvm::Type *type = getFPType(kind_value); - llvm::Function *fn_sqrt = module->getFunction(func_name); - if (!fn_sqrt) { - llvm::FunctionType *function_type = llvm::FunctionType::get( - type, {type}, false); - fn_sqrt = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, func_name, - module.get()); - } - tmp = builder->CreateCall(fn_sqrt, {c}); - } - - void visit_ListAppend(const ASR::ListAppend_t& x) { - ASR::List_t* asr_list = ASR::down_cast(ASRUtils::expr_type(x.m_a)); - int64_t ptr_loads_copy = ptr_loads; - ptr_loads = 0; - this->visit_expr(*x.m_a); - llvm::Value* plist = tmp; - - ptr_loads = !LLVM::is_llvm_struct(asr_list->m_type); - this->visit_expr_wrapper(x.m_ele, true); - llvm::Value *item = tmp; - ptr_loads = ptr_loads_copy; - - list_api->append(plist, item, asr_list->m_type, module.get(), name2memidx); - } - - void visit_UnionInstanceMember(const ASR::UnionInstanceMember_t& x) { - int64_t ptr_loads_copy = ptr_loads; - ptr_loads = 0; - this->visit_expr(*x.m_v); - ptr_loads = ptr_loads_copy; - llvm::Value* union_llvm = tmp; - ASR::Variable_t* member_var = ASR::down_cast(x.m_m); - ASR::ttype_t* member_type_asr = ASRUtils::get_contained_type(member_var->m_type); - if( ASR::is_a(*member_type_asr) ) { - ASR::Struct_t* d = ASR::down_cast(member_type_asr); - der_type_name = ASRUtils::symbol_name(d->m_derived_type); - } - member_type_asr = member_var->m_type; - llvm::Type* member_type_llvm = getMemberType(member_type_asr, member_var)->getPointerTo(); - tmp = builder->CreateBitCast(union_llvm, member_type_llvm); - if( is_assignment_target ) { - return ; - } - if( ptr_loads > 0 ) { - tmp = LLVM::CreateLoad(*builder, tmp); - } - } - - void visit_ListItem(const ASR::ListItem_t& x) { - ASR::ttype_t* el_type = ASRUtils::get_contained_type( - ASRUtils::expr_type(x.m_a)); - int64_t ptr_loads_copy = ptr_loads; - ptr_loads = 0; - this->visit_expr(*x.m_a); - llvm::Value* plist = tmp; - - ptr_loads = 1; - this->visit_expr_wrapper(x.m_pos, true); - ptr_loads = ptr_loads_copy; - llvm::Value *pos = tmp; - - tmp = list_api->read_item(plist, pos, compiler_options.enable_bounds_checking, *module, - (LLVM::is_llvm_struct(el_type) || ptr_loads == 0)); - } - - void visit_DictItem(const ASR::DictItem_t& x) { - ASR::Dict_t* dict_type = ASR::down_cast( - ASRUtils::expr_type(x.m_a)); - int64_t ptr_loads_copy = ptr_loads; - ptr_loads = 0; - this->visit_expr(*x.m_a); - llvm::Value* pdict = tmp; - - ptr_loads = !LLVM::is_llvm_struct(dict_type->m_key_type); - this->visit_expr_wrapper(x.m_key, true); - ptr_loads = ptr_loads_copy; - llvm::Value *key = tmp; - - set_dict_api(dict_type); - tmp = llvm_utils->dict_api->read_item(pdict, key, *module, dict_type, - LLVM::is_llvm_struct(dict_type->m_value_type)); - } - - void visit_DictPop(const ASR::DictPop_t& x) { - ASR::Dict_t* dict_type = ASR::down_cast( - ASRUtils::expr_type(x.m_a)); - int64_t ptr_loads_copy = ptr_loads; - ptr_loads = 0; - this->visit_expr(*x.m_a); - llvm::Value* pdict = tmp; - - ptr_loads = !LLVM::is_llvm_struct(dict_type->m_key_type); - this->visit_expr_wrapper(x.m_key, true); - ptr_loads = ptr_loads_copy; - llvm::Value *key = tmp; - - set_dict_api(dict_type); - tmp = llvm_utils->dict_api->pop_item(pdict, key, *module, dict_type, - LLVM::is_llvm_struct(dict_type->m_value_type)); - } - - void visit_ListLen(const ASR::ListLen_t& x) { - if (x.m_value) { - this->visit_expr(*x.m_value); - } else { - int64_t ptr_loads_copy = ptr_loads; - ptr_loads = 0; - this->visit_expr(*x.m_arg); - ptr_loads = ptr_loads_copy; - llvm::Value* plist = tmp; - tmp = list_api->len(plist); - } - } - - void visit_ListCompare(const ASR::ListCompare_t x) { - int64_t ptr_loads_copy = ptr_loads; - ptr_loads = 0; - this->visit_expr(*x.m_left); - llvm::Value* left = tmp; - this->visit_expr(*x.m_right); - llvm::Value* right = tmp; - ptr_loads = ptr_loads_copy; - tmp = llvm_utils->is_equal_by_value(left, right, *module, - ASRUtils::expr_type(x.m_left)); - if (x.m_op == ASR::cmpopType::NotEq) { - tmp = builder->CreateNot(tmp); - } - } - - void visit_DictLen(const ASR::DictLen_t& x) { - if (x.m_value) { - this->visit_expr(*x.m_value); - return ; - } - - int64_t ptr_loads_copy = ptr_loads; - ptr_loads = 0; - this->visit_expr(*x.m_arg); - ptr_loads = ptr_loads_copy; - llvm::Value* pdict = tmp; - ASR::Dict_t* x_dict = ASR::down_cast(ASRUtils::expr_type(x.m_arg)); - set_dict_api(x_dict); - tmp = llvm_utils->dict_api->len(pdict); - } - - void visit_ListInsert(const ASR::ListInsert_t& x) { - ASR::List_t* asr_list = ASR::down_cast( - ASRUtils::expr_type(x.m_a)); - int64_t ptr_loads_copy = ptr_loads; - ptr_loads = 0; - this->visit_expr(*x.m_a); - llvm::Value* plist = tmp; - - ptr_loads = 1; - this->visit_expr_wrapper(x.m_pos, true); - llvm::Value *pos = tmp; - - ptr_loads = !LLVM::is_llvm_struct(asr_list->m_type); - this->visit_expr_wrapper(x.m_ele, true); - llvm::Value *item = tmp; - ptr_loads = ptr_loads_copy; - - list_api->insert_item(plist, pos, item, asr_list->m_type, module.get(), name2memidx); - } - - void visit_DictInsert(const ASR::DictInsert_t& x) { - ASR::Dict_t* dict_type = ASR::down_cast( - ASRUtils::expr_type(x.m_a)); - int64_t ptr_loads_copy = ptr_loads; - ptr_loads = 0; - this->visit_expr(*x.m_a); - llvm::Value* pdict = tmp; - - ptr_loads = !LLVM::is_llvm_struct(dict_type->m_key_type); - this->visit_expr_wrapper(x.m_key, true); - llvm::Value *key = tmp; - ptr_loads = !LLVM::is_llvm_struct(dict_type->m_value_type); - this->visit_expr_wrapper(x.m_value, true); - llvm::Value *value = tmp; - ptr_loads = ptr_loads_copy; - - set_dict_api(dict_type); - llvm_utils->dict_api->write_item(pdict, key, value, module.get(), - dict_type->m_key_type, - dict_type->m_value_type, name2memidx); - } - - void visit_ListRemove(const ASR::ListRemove_t& x) { - ASR::ttype_t* asr_el_type = ASRUtils::get_contained_type(ASRUtils::expr_type(x.m_a)); - int64_t ptr_loads_copy = ptr_loads; - ptr_loads = 0; - this->visit_expr(*x.m_a); - llvm::Value* plist = tmp; - - ptr_loads = !LLVM::is_llvm_struct(asr_el_type); - this->visit_expr_wrapper(x.m_ele, true); - ptr_loads = ptr_loads_copy; - llvm::Value *item = tmp; - list_api->remove(plist, item, asr_el_type, *module); - } - - void visit_ListClear(const ASR::ListClear_t& x) { - int64_t ptr_loads_copy = ptr_loads; - ptr_loads = 0; - this->visit_expr(*x.m_a); - llvm::Value* plist = tmp; - ptr_loads = ptr_loads_copy; - - list_api->list_clear(plist); - } - - void visit_TupleCompare(const ASR::TupleCompare_t& x) { - int64_t ptr_loads_copy = ptr_loads; - ptr_loads = 0; - this->visit_expr(*x.m_left); - llvm::Value* left = tmp; - this->visit_expr(*x.m_right); - llvm::Value* right = tmp; - ptr_loads = ptr_loads_copy; - tmp = llvm_utils->is_equal_by_value(left, right, *module, - ASRUtils::expr_type(x.m_left)); - if (x.m_op == ASR::cmpopType::NotEq) { - tmp = builder->CreateNot(tmp); - } - } - - void visit_TupleLen(const ASR::TupleLen_t& x) { - LCOMPILERS_ASSERT(x.m_value); - this->visit_expr(*x.m_value); - } - - void visit_TupleItem(const ASR::TupleItem_t& x) { - int64_t ptr_loads_copy = ptr_loads; - ptr_loads = 0; - this->visit_expr(*x.m_a); - ptr_loads = ptr_loads_copy; - llvm::Value* ptuple = tmp; - - this->visit_expr_wrapper(x.m_pos, true); - llvm::Value *pos = tmp; - - tmp = tuple_api->read_item(ptuple, pos, LLVM::is_llvm_struct(x.m_type)); - } - - void visit_ArrayItem(const ASR::ArrayItem_t& x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - ASR::ttype_t* x_mv_type = ASRUtils::expr_type(x.m_v); - bool is_argument = false; - llvm::Value* array = nullptr; - bool is_data_only = false; - if( ASR::is_a(*x.m_v) ) { - ASR::Variable_t *v = ASRUtils::EXPR2VAR(x.m_v); - if( ASR::is_a(*ASRUtils::get_contained_type(v->m_type)) ) { - ASR::Struct_t* der_type = ASR::down_cast( - ASRUtils::get_contained_type(v->m_type)); - der_type_name = ASRUtils::symbol_name(ASRUtils::symbol_get_past_external(der_type->m_derived_type)); - } - uint32_t v_h = get_hash((ASR::asr_t*)v); - if (llvm_symtab.find(v_h) == llvm_symtab.end()) { - LCOMPILERS_ASSERT(std::find(nested_globals.begin(), - nested_globals.end(), v_h) != nested_globals.end()); - auto finder = std::find(nested_globals.begin(), - nested_globals.end(), v_h); - llvm::Constant *ptr = module->getOrInsertGlobal(nested_desc_name, - nested_global_struct); - int idx = std::distance(nested_globals.begin(), finder); - std::vector idx_vec = { - llvm::ConstantInt::get(context, llvm::APInt(32, 0)), - llvm::ConstantInt::get(context, llvm::APInt(32, idx))}; - array = CreateLoad(CreateGEP(ptr, idx_vec)); - is_data_only = true; - } else { - array = llvm_symtab[v_h]; - } - is_argument = (v->m_intent == ASRUtils::intent_in) - || (v->m_intent == ASRUtils::intent_out) - || (v->m_intent == ASRUtils::intent_inout) - || (v->m_intent == ASRUtils::intent_unspecified); - } else { - int64_t ptr_loads_copy = ptr_loads; - ptr_loads = 0; - this->visit_expr(*x.m_v); - if( ASR::is_a(*x_mv_type) ) { - ASR::Struct_t* der_type = ASR::down_cast(x_mv_type); - der_type_name = ASRUtils::symbol_name(ASRUtils::symbol_get_past_external(der_type->m_derived_type)); - } - ptr_loads = ptr_loads_copy; - array = tmp; - } - ASR::dimension_t* m_dims; - int n_dims = ASRUtils::extract_dimensions_from_ttype(x_mv_type, m_dims); - if (ASR::is_a(*x.m_type) && n_dims == 0) { - // String indexing: - if (x.n_args != 1) { - throw CodeGenError("Only string(a) supported for now.", x.base.base.loc); - } - LCOMPILERS_ASSERT(ASR::is_a(*x.m_args[0].m_right)); - this->visit_expr_wrapper(x.m_args[0].m_right, true); - llvm::Value *p = nullptr; - llvm::Value *idx = tmp; - llvm::Value *str = CreateLoad(array); - if( is_assignment_target ) { - idx = builder->CreateSub(idx, llvm::ConstantInt::get(context, llvm::APInt(32, 1))); - std::vector idx_vec = {idx}; - p = CreateGEP(str, idx_vec); - } else { - p = lfortran_str_item(str, idx); - } - // TODO: Currently the string starts at the right location, but goes to the end of the original string. - // We have to allocate a new string, copy it and add null termination. - - tmp = builder->CreateAlloca(character_type, nullptr); - builder->CreateStore(p, tmp); - - //tmp = p; - } else { - // Array indexing: - std::vector indices; - for( size_t r = 0; r < x.n_args; r++ ) { - ASR::array_index_t curr_idx = x.m_args[r]; - int64_t ptr_loads_copy = ptr_loads; - ptr_loads = 2; - this->visit_expr_wrapper(curr_idx.m_right, true); - ptr_loads = ptr_loads_copy; - indices.push_back(tmp); - } - bool is_bindc_array = ASRUtils::expr_abi(x.m_v) == ASR::abiType::BindC; - if (ASR::is_a(*x_mv_type) || - ((is_bindc_array && !ASRUtils::is_fixed_size_array(m_dims, n_dims)) && - ASR::is_a(*x.m_v))) { - array = CreateLoad(array); - } - is_data_only = is_data_only || (is_argument && !ASRUtils::is_dimension_empty(m_dims, n_dims)); - is_data_only = is_data_only || is_bindc_array; - Vec llvm_diminfo; - llvm_diminfo.reserve(al, 2 * x.n_args + 1); - if( is_data_only ) { - for( size_t idim = 0; idim < x.n_args; idim++ ) { - this->visit_expr_wrapper(m_dims[idim].m_start, true); - llvm::Value* dim_start = tmp; - this->visit_expr_wrapper(m_dims[idim].m_length, true); - llvm::Value* dim_size = tmp; - llvm_diminfo.push_back(al, dim_start); - llvm_diminfo.push_back(al, dim_size); - } - } - LCOMPILERS_ASSERT(ASRUtils::extract_n_dims_from_ttype(x_mv_type) > 0); - tmp = arr_descr->get_single_element(array, indices, x.n_args, - is_data_only, - ASRUtils::is_fixed_size_array(m_dims, n_dims) && is_bindc_array, - llvm_diminfo.p); - } - } - - void visit_ArraySection(const ASR::ArraySection_t& x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - int64_t ptr_loads_copy = ptr_loads; - ptr_loads = 0; - this->visit_expr(*x.m_v); - ptr_loads = ptr_loads_copy; - llvm::Value* array = tmp; - ASR::dimension_t* m_dims; - int n_dims = ASRUtils::extract_dimensions_from_ttype( - ASRUtils::expr_type(x.m_v), m_dims); - LCOMPILERS_ASSERT(ASR::is_a(*ASRUtils::expr_type(x.m_v)) && - n_dims == 0); - // String indexing: - if (x.n_args == 1) { - throw CodeGenError("Only string(a:b) supported for now.", x.base.base.loc); - } - - LCOMPILERS_ASSERT(x.m_args[0].m_left) - LCOMPILERS_ASSERT(x.m_args[0].m_right) - //throw CodeGenError("Only string(a:b) for a,b variables for now.", x.base.base.loc); - // Use the "right" index for now - this->visit_expr_wrapper(x.m_args[0].m_right, true); - llvm::Value *idx2 = tmp; - this->visit_expr_wrapper(x.m_args[0].m_left, true); - llvm::Value *idx1 = tmp; - // idx = builder->CreateSub(idx, llvm::ConstantInt::get(context, llvm::APInt(32, 1))); - //std::vector idx_vec = {llvm::ConstantInt::get(context, llvm::APInt(32, 0)), idx}; - // std::vector idx_vec = {idx}; - llvm::Value *str = CreateLoad(array); - // llvm::Value *p = CreateGEP(str, idx_vec); - // TODO: Currently the string starts at the right location, but goes to the end of the original string. - // We have to allocate a new string, copy it and add null termination. - llvm::Value *step = llvm::ConstantInt::get(context, llvm::APInt(32, 1)); - llvm::Value *present = llvm::ConstantInt::get(context, llvm::APInt(1, 1)); - llvm::Value *p = lfortran_str_slice(str, idx1, idx2, step, present, present); - - tmp = builder->CreateAlloca(character_type, nullptr); - builder->CreateStore(p, tmp); - } - - void visit_ArrayReshape(const ASR::ArrayReshape_t& x) { - this->visit_expr(*x.m_array); - llvm::Value* array = tmp; - this->visit_expr(*x.m_shape); - llvm::Value* shape = tmp; - ASR::ttype_t* x_m_array_type = ASRUtils::expr_type(x.m_array); - ASR::ttype_t* asr_data_type = ASRUtils::duplicate_type_without_dims(al, - x_m_array_type, x_m_array_type->base.loc); - ASR::ttype_t* asr_shape_type = ASRUtils::get_contained_type(ASRUtils::expr_type(x.m_shape)); - llvm::Type* llvm_data_type = get_type_from_ttype_t_util(asr_data_type); - tmp = arr_descr->reshape(array, llvm_data_type, shape, asr_shape_type, module.get()); - } - - void lookup_EnumValue(const ASR::EnumValue_t& x) { - ASR::Enum_t* enum_t = ASR::down_cast(x.m_enum_type); - ASR::EnumType_t* enum_type = ASR::down_cast(enum_t->m_enum_type); - uint32_t h = get_hash((ASR::asr_t*) enum_type); - llvm::Value* array = llvm_symtab[h]; - tmp = llvm_utils->create_gep(array, tmp); - tmp = LLVM::CreateLoad(*builder, llvm_utils->create_gep(tmp, 1)); - } - - void visit_EnumValue(const ASR::EnumValue_t& x) { - if( x.m_value ) { - if( ASR::is_a(*x.m_type) ) { - this->visit_expr(*x.m_value); - } else if( ASR::is_a(*x.m_v) ) { - ASR::EnumStaticMember_t* x_enum_member = ASR::down_cast(x.m_v); - ASR::Variable_t* x_mv = ASR::down_cast(x_enum_member->m_m); - ASR::Enum_t* enum_t = ASR::down_cast(x.m_enum_type); - ASR::EnumType_t* enum_type = ASR::down_cast(enum_t->m_enum_type); - for( size_t i = 0; i < enum_type->n_members; i++ ) { - if( std::string(enum_type->m_members[i]) == std::string(x_mv->m_name) ) { - tmp = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), llvm::APInt(32, i)); - break ; - } - } - if( lookup_enum_value_for_nonints ) { - lookup_EnumValue(x); - } - } - return ; - } - - visit_expr(*x.m_v); - if( ASR::is_a(*x.m_v) ) { - tmp = LLVM::CreateLoad(*builder, tmp); - } - if( !ASR::is_a(*x.m_type) && lookup_enum_value_for_nonints ) { - lookup_EnumValue(x); - } - } - - void visit_EnumName(const ASR::EnumName_t& x) { - if( x.m_value ) { - this->visit_expr(*x.m_value); - return ; - } - - visit_expr(*x.m_v); - if( ASR::is_a(*x.m_v) ) { - tmp = LLVM::CreateLoad(*builder, tmp); - } - ASR::Enum_t* enum_t = ASR::down_cast(x.m_enum_type); - ASR::EnumType_t* enum_type = ASR::down_cast(enum_t->m_enum_type); - uint32_t h = get_hash((ASR::asr_t*) enum_type); - llvm::Value* array = llvm_symtab[h]; - if( ASR::is_a(*enum_type->m_type) ) { - int64_t min_value = INT64_MAX; - - for( auto itr: enum_type->m_symtab->get_scope() ) { - ASR::Variable_t* itr_var = ASR::down_cast(itr.second); - ASR::expr_t* value = ASRUtils::expr_value(itr_var->m_symbolic_value); - int64_t value_int64 = -1; - ASRUtils::extract_value(value, value_int64); - min_value = std::min(value_int64, min_value); - } - tmp = builder->CreateSub(tmp, llvm::ConstantInt::get(tmp->getType(), - llvm::APInt(32, min_value))); - tmp = llvm_utils->create_gep(array, tmp); - tmp = llvm_utils->create_gep(tmp, 0); - } - } - - void visit_EnumTypeConstructor(const ASR::EnumTypeConstructor_t& x) { - LCOMPILERS_ASSERT(x.n_args == 1); - ASR::expr_t* m_arg = x.m_args[0]; - this->visit_expr(*m_arg); - } - - void visit_UnionTypeConstructor(const ASR::UnionTypeConstructor_t& x) { - LCOMPILERS_ASSERT(x.n_args == 0); - } - - void visit_SizeOfType(const ASR::SizeOfType_t& x) { - llvm::Type* llvm_type = get_type_from_ttype_t_util(x.m_arg); - llvm::Type* llvm_type_size = get_type_from_ttype_t_util(x.m_type); - llvm::DataLayout data_layout(module.get()); - int64_t type_size = data_layout.getTypeAllocSize(llvm_type); - tmp = llvm::ConstantInt::get(llvm_type_size, llvm::APInt(64, type_size)); - } - - void visit_StructInstanceMember(const ASR::StructInstanceMember_t& x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - der_type_name = ""; - ASR::ttype_t* x_m_v_type = ASRUtils::expr_type(x.m_v); - int64_t ptr_loads_copy = ptr_loads; - if( ASR::is_a(*x.m_v) ) { - ptr_loads = 0; - } else { - ptr_loads = 2 - ASR::is_a(*x_m_v_type); - } - this->visit_expr(*x.m_v); - ptr_loads = ptr_loads_copy; - ASR::Variable_t* member = down_cast(symbol_get_past_external(x.m_m)); - std::string member_name = std::string(member->m_name); - LCOMPILERS_ASSERT(der_type_name.size() != 0); - while( name2memidx[der_type_name].find(member_name) == name2memidx[der_type_name].end() ) { - if( dertype2parent.find(der_type_name) == dertype2parent.end() ) { - throw CodeGenError(der_type_name + " doesn't have any member named " + member_name, - x.base.base.loc); - } - tmp = llvm_utils->create_gep(tmp, 0); - der_type_name = dertype2parent[der_type_name]; - } - int member_idx = name2memidx[der_type_name][member_name]; - std::vector idx_vec = { - llvm::ConstantInt::get(context, llvm::APInt(32, 0)), - llvm::ConstantInt::get(context, llvm::APInt(32, member_idx))}; - // if( (ASR::is_a(*x.m_v) || - // ASR::is_a(*x.m_v)) && - // is_nested_pointer(tmp) ) { - // tmp = CreateLoad(tmp); - // } - llvm::Value* tmp1 = CreateGEP(tmp, idx_vec); - ASR::ttype_t* member_type = member->m_type; - if( ASR::is_a(*member_type) ) { - member_type = ASR::down_cast(member_type)->m_type; - } - if( member_type->type == ASR::ttypeType::Struct ) { - ASR::Struct_t* der = (ASR::Struct_t*)(&(member_type->base)); - ASR::StructType_t* der_type = (ASR::StructType_t*)(&(der->m_derived_type->base)); - der_type_name = std::string(der_type->m_name); - uint32_t h = get_hash((ASR::asr_t*)member); - if( llvm_symtab.find(h) != llvm_symtab.end() ) { - tmp = llvm_symtab[h]; - } - } - tmp = tmp1; - } - - void visit_Variable(const ASR::Variable_t &x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - uint32_t h = get_hash((ASR::asr_t*)&x); - // This happens at global scope, so the intent can only be either local - // (global variable declared/initialized in this translation unit), or - // external (global variable not declared/initialized in this - // translation unit, just referenced). - LCOMPILERS_ASSERT(x.m_intent == intent_local - || x.m_abi == ASR::abiType::Interactive); - bool external = (x.m_abi != ASR::abiType::Source); - llvm::Constant* init_value = nullptr; - if (x.m_symbolic_value != nullptr){ - this->visit_expr_wrapper(x.m_symbolic_value, true); - init_value = llvm::dyn_cast(tmp); - } - if (x.m_type->type == ASR::ttypeType::Integer) { - int a_kind = down_cast(x.m_type)->m_kind; - llvm::Type *type; - int init_value_bits = 8*a_kind; - type = getIntType(a_kind); - llvm::Constant *ptr = module->getOrInsertGlobal(x.m_name, - type); - if (!external) { - if (init_value) { - module->getNamedGlobal(x.m_name)->setInitializer( - init_value); - } else { - module->getNamedGlobal(x.m_name)->setInitializer( - llvm::ConstantInt::get(context, - llvm::APInt(init_value_bits, 0))); - } - } - llvm_symtab[h] = ptr; - } else if (x.m_type->type == ASR::ttypeType::Real) { - int a_kind = down_cast(x.m_type)->m_kind; - llvm::Type *type; - int init_value_bits = 8*a_kind; - type = getFPType(a_kind); - llvm::Constant *ptr = module->getOrInsertGlobal(x.m_name, type); - if (!external) { - if (init_value) { - module->getNamedGlobal(x.m_name)->setInitializer( - init_value); - } else { - if( init_value_bits == 32 ) { - module->getNamedGlobal(x.m_name)->setInitializer( - llvm::ConstantFP::get(context, - llvm::APFloat((float)0))); - } else if( init_value_bits == 64 ) { - module->getNamedGlobal(x.m_name)->setInitializer( - llvm::ConstantFP::get(context, - llvm::APFloat((double)0))); - } - } - } - llvm_symtab[h] = ptr; - } else if (x.m_type->type == ASR::ttypeType::Logical) { - llvm::Constant *ptr = module->getOrInsertGlobal(x.m_name, - llvm::Type::getInt1Ty(context)); - if (!external) { - if (init_value) { - module->getNamedGlobal(x.m_name)->setInitializer( - init_value); - } else { - module->getNamedGlobal(x.m_name)->setInitializer( - llvm::ConstantInt::get(context, - llvm::APInt(1, 0))); - } - } - llvm_symtab[h] = ptr; - } else if (x.m_type->type == ASR::ttypeType::Character) { - llvm::Constant *ptr = module->getOrInsertGlobal(x.m_name, - character_type); - if (!external) { - if (init_value) { - module->getNamedGlobal(x.m_name)->setInitializer( - init_value); - } else { - module->getNamedGlobal(x.m_name)->setInitializer( - llvm::Constant::getNullValue(character_type) - ); - } - } - llvm_symtab[h] = ptr; - } else if( x.m_type->type == ASR::ttypeType::CPtr ) { - llvm::Type* void_ptr = llvm::Type::getVoidTy(context)->getPointerTo(); - llvm::Constant *ptr = module->getOrInsertGlobal(x.m_name, - void_ptr); - if (!external) { - if (init_value) { - module->getNamedGlobal(x.m_name)->setInitializer( - init_value); - } else { - module->getNamedGlobal(x.m_name)->setInitializer( - llvm::ConstantPointerNull::get( - static_cast(void_ptr)) - ); - } - } - llvm_symtab[h] = ptr; - } else if( x.m_type->type == ASR::ttypeType::Struct ) { - ASR::Struct_t* struct_t = ASR::down_cast(x.m_type); - if( ASRUtils::is_c_ptr(struct_t->m_derived_type) ) { - llvm::Type* void_ptr = llvm::Type::getVoidTy(context)->getPointerTo(); - llvm::Constant *ptr = module->getOrInsertGlobal(x.m_name, - void_ptr); - if (!external) { - if (init_value) { - module->getNamedGlobal(x.m_name)->setInitializer( - init_value); - } else { - module->getNamedGlobal(x.m_name)->setInitializer( - llvm::ConstantPointerNull::get( - static_cast(void_ptr)) - ); - } - } - llvm_symtab[h] = ptr; - } - } else if(x.m_type->type == ASR::ttypeType::Pointer) { - ASR::dimension_t* m_dims = nullptr; - int n_dims = -1, a_kind = -1; - bool is_array_type = false, is_malloc_array_type = false, is_list = false; - llvm::Type* x_ptr = get_type_from_ttype_t(x.m_type, x.m_storage, is_array_type, - is_malloc_array_type, is_list, - m_dims, n_dims, a_kind); - llvm::Constant *ptr = module->getOrInsertGlobal(x.m_name, - x_ptr); - if (!external) { - if (init_value) { - module->getNamedGlobal(x.m_name)->setInitializer( - init_value); - } else { - module->getNamedGlobal(x.m_name)->setInitializer( - llvm::ConstantPointerNull::get( - static_cast(x_ptr)) - ); - } - } - llvm_symtab[h] = ptr; - } else if (x.m_type->type == ASR::ttypeType::List) { - llvm::StructType* list_type = static_cast( - get_type_from_ttype_t_util(x.m_type)); - llvm::Constant *ptr = module->getOrInsertGlobal(x.m_name, list_type); - module->getNamedGlobal(x.m_name)->setInitializer( - llvm::ConstantStruct::get(list_type, - llvm::Constant::getNullValue(list_type))); - llvm_symtab[h] = ptr; - } else if (x.m_type->type == ASR::ttypeType::TypeParameter) { - // Ignore type variables - } else { - throw CodeGenError("Variable type not supported " + std::to_string(x.m_type->type), x.base.base.loc); - } - } - - void visit_EnumType(const ASR::EnumType_t& x) { - if( x.m_enum_value_type == ASR::enumtypeType::IntegerUnique && - x.m_abi == ASR::abiType::BindC ) { - throw CodeGenError("C-interoperation support for non-consecutive but uniquely " - "valued integer enums isn't available yet."); - } - bool is_integer = ASR::is_a(*x.m_type); - ASR::storage_typeType m_storage = ASR::storage_typeType::Default; - bool is_array_type = false, is_malloc_array_type = false, is_list = false; - ASR::dimension_t* m_dims = nullptr; - int n_dims = -1, a_kind = -1; - llvm::Type* value_type = get_type_from_ttype_t(x.m_type, m_storage, is_array_type, - is_malloc_array_type, is_list, m_dims, n_dims, a_kind); - if( is_integer ) { - int64_t min_value = INT64_MAX; - int64_t max_value = INT64_MIN; - size_t max_name_len = 0; - llvm::Value* itr_value = nullptr; - for( auto itr: x.m_symtab->get_scope() ) { - ASR::Variable_t* itr_var = ASR::down_cast(itr.second); - ASR::expr_t* value = ASRUtils::expr_value(itr_var->m_symbolic_value); - int64_t value_int64 = -1; - this->visit_expr(*value); - itr_value = tmp; - ASRUtils::extract_value(value, value_int64); - min_value = std::min(value_int64, min_value); - max_value = std::max(value_int64, max_value); - max_name_len = std::max(max_name_len, itr.first.size()); - } - - llvm::ArrayType* name_array_type = llvm::ArrayType::get(llvm::Type::getInt8Ty(context), - max_name_len + 1); - llvm::StructType* enum_value_type = llvm::StructType::create({name_array_type, value_type}); - llvm::Constant* empty_vt = llvm::ConstantStruct::get(enum_value_type, {llvm::ConstantArray::get(name_array_type, - {llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), llvm::APInt(8, '\0'))}), - (llvm::Constant*) itr_value}); - std::vector enum_value_pairs(max_value - min_value + 1, empty_vt); - - for( auto itr: x.m_symtab->get_scope() ) { - ASR::Variable_t* itr_var = ASR::down_cast(itr.second); - ASR::expr_t* value = ASRUtils::expr_value(itr_var->m_symbolic_value); - int64_t value_int64 = -1; - ASRUtils::extract_value(value, value_int64); - this->visit_expr(*value); - std::vector itr_var_name_v; - itr_var_name_v.reserve(itr.first.size()); - for( size_t i = 0; i < itr.first.size(); i++ ) { - itr_var_name_v.push_back(llvm::ConstantInt::get( - llvm::Type::getInt8Ty(context), llvm::APInt(8, itr_var->m_name[i]))); - } - itr_var_name_v.push_back(llvm::ConstantInt::get( - llvm::Type::getInt8Ty(context), llvm::APInt(8, '\0'))); - llvm::Constant* name = llvm::ConstantArray::get(name_array_type, itr_var_name_v); - enum_value_pairs[value_int64 - min_value] = llvm::ConstantStruct::get( - enum_value_type, {name, (llvm::Constant*) tmp}); - } - - llvm::ArrayType* global_enum_array = llvm::ArrayType::get(enum_value_type, - max_value - min_value + 1); - llvm::Constant *array = module->getOrInsertGlobal(x.m_name, - global_enum_array); - module->getNamedGlobal(x.m_name)->setInitializer( - llvm::ConstantArray::get(global_enum_array, enum_value_pairs)); - uint32_t h = get_hash((ASR::asr_t*)&x); - llvm_symtab[h] = array; - } else { - size_t max_name_len = 0; - - for( auto itr: x.m_symtab->get_scope() ) { - max_name_len = std::max(max_name_len, itr.first.size()); - } - - llvm::ArrayType* name_array_type = llvm::ArrayType::get(llvm::Type::getInt8Ty(context), - max_name_len + 1); - llvm::StructType* enum_value_type = llvm::StructType::create({name_array_type, value_type}); - std::vector enum_value_pairs(x.n_members, nullptr); - - for( auto itr: x.m_symtab->get_scope() ) { - ASR::Variable_t* itr_var = ASR::down_cast(itr.second); - ASR::expr_t* value = itr_var->m_symbolic_value; - int64_t value_int64 = -1; - ASRUtils::extract_value(value, value_int64); - this->visit_expr(*value); - std::vector itr_var_name_v; - itr_var_name_v.reserve(itr.first.size()); - for( size_t i = 0; i < itr.first.size(); i++ ) { - itr_var_name_v.push_back(llvm::ConstantInt::get( - llvm::Type::getInt8Ty(context), llvm::APInt(8, itr_var->m_name[i]))); - } - itr_var_name_v.push_back(llvm::ConstantInt::get( - llvm::Type::getInt8Ty(context), llvm::APInt(8, '\0'))); - llvm::Constant* name = llvm::ConstantArray::get(name_array_type, itr_var_name_v); - size_t dest_idx = 0; - for( size_t j = 0; j < x.n_members; j++ ) { - if( std::string(x.m_members[j]) == itr.first ) { - dest_idx = j; - break ; - } - } - enum_value_pairs[dest_idx] = llvm::ConstantStruct::get( - enum_value_type, {name, (llvm::Constant*) tmp}); - } - - llvm::ArrayType* global_enum_array = llvm::ArrayType::get(enum_value_type, - x.n_members); - llvm::Constant *array = module->getOrInsertGlobal(x.m_name, - global_enum_array); - module->getNamedGlobal(x.m_name)->setInitializer( - llvm::ConstantArray::get(global_enum_array, enum_value_pairs)); - uint32_t h = get_hash((ASR::asr_t*)&x); - llvm_symtab[h] = array; - } - } - - void start_module_init_function_prototype(const ASR::Module_t &x) { - uint32_t h = get_hash((ASR::asr_t*)&x); - llvm::FunctionType *function_type = llvm::FunctionType::get( - llvm::Type::getVoidTy(context), {}, false); - LCOMPILERS_ASSERT(llvm_symtab_fn.find(h) == llvm_symtab_fn.end()); - std::string module_fn_name = "__lfortran_module_init_" + std::string(x.m_name); - llvm::Function *F = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, module_fn_name, module.get()); - llvm::BasicBlock *BB = llvm::BasicBlock::Create(context, ".entry", F); - builder->SetInsertPoint(BB); - - llvm_symtab_fn[h] = F; - } - - void finish_module_init_function_prototype(const ASR::Module_t &x) { - uint32_t h = get_hash((ASR::asr_t*)&x); - builder->CreateRetVoid(); - llvm_symtab_fn[h]->removeFromParent(); - } - - void visit_Module(const ASR::Module_t &x) { - mangle_prefix = "__module_" + std::string(x.m_name) + "_"; - - start_module_init_function_prototype(x); - - for (auto &item : x.m_symtab->get_scope()) { - if (is_a(*item.second)) { - ASR::Variable_t *v = down_cast( - item.second); - visit_Variable(*v); - } else if (is_a(*item.second)) { - ASR::Function_t *v = down_cast( - item.second); - if (ASRUtils::get_FunctionType(v)->n_type_params == 0) { - instantiate_function(*v); - declare_needed_global_types(*v); - } - } else if (is_a(*item.second)) { - ASR::EnumType_t *et = down_cast(item.second); - visit_EnumType(*et); - } - } - finish_module_init_function_prototype(x); - - visit_procedures(x); - mangle_prefix = ""; - } - - void visit_Program(const ASR::Program_t &x) { - bool is_dict_present_copy_lp = dict_api_lp->is_dict_present(); - bool is_dict_present_copy_sc = dict_api_sc->is_dict_present(); - dict_api_lp->set_is_dict_present(false); - dict_api_sc->set_is_dict_present(false); - llvm_goto_targets.clear(); - // Generate code for nested subroutines and functions first: - for (auto &item : x.m_symtab->get_scope()) { - if (is_a(*item.second)) { - ASR::Function_t *v = down_cast( - item.second); - if (ASRUtils::get_FunctionType(v)->n_type_params == 0) { - instantiate_function(*v); - declare_needed_global_types(*v); - } - } - } - declare_needed_global_types(x); - visit_procedures(x); - - // Generate code for the main program - std::vector command_line_args = { - llvm::Type::getInt32Ty(context), - character_type->getPointerTo() - }; - llvm::FunctionType *function_type = llvm::FunctionType::get( - llvm::Type::getInt32Ty(context), command_line_args, false); - llvm::Function *F = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, "main", module.get()); - llvm::BasicBlock *BB = llvm::BasicBlock::Create(context, - ".entry", F); - if (compiler_options.emit_debug_info) { - llvm::DISubprogram *SP; - debug_emit_function(x, SP); - F->setSubprogram(SP); - } - builder->SetInsertPoint(BB); - - // Call the `_lpython_set_argv` function to assign command line argument - // values to `argc` and `argv`. - { - if (compiler_options.emit_debug_info) debug_emit_loc(x); - llvm::Function *fn = module->getFunction("_lpython_set_argv"); - if(!fn) { - llvm::FunctionType *function_type = llvm::FunctionType::get( - llvm::Type::getVoidTy(context), { - llvm::Type::getInt32Ty(context), - character_type->getPointerTo() - }, false); - fn = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, "_lpython_set_argv", *module); - } - std::vector args; - for (llvm::Argument &llvm_arg : F->args()) { - args.push_back(&llvm_arg); - } - builder->CreateCall(fn, args); - } - - declare_vars(x); - for (size_t i=0; ivisit_stmt(*x.m_body[i]); - } - llvm::Value *ret_val2 = llvm::ConstantInt::get(context, - llvm::APInt(32, 0)); - builder->CreateRet(ret_val2); - dict_api_lp->set_is_dict_present(is_dict_present_copy_lp); - dict_api_sc->set_is_dict_present(is_dict_present_copy_sc); - - // Finalize the debug info. - if (compiler_options.emit_debug_info) DBuilder->finalize(); - } - - /* - * This function detects if the current variable is an argument. - * of a function or argument. Some manipulations are to be done - * only on arguments and not on local variables. - */ - bool is_argument(ASR::Variable_t* v, ASR::expr_t** m_args, - int n_args) { - for( int i = 0; i < n_args; i++ ) { - ASR::expr_t* m_arg = m_args[i]; - uint32_t h_m_arg = get_hash((ASR::asr_t*)m_arg); - uint32_t h_v = get_hash((ASR::asr_t*)v); - if( h_m_arg == h_v ) { - return true; - } - } - return false; - } - - int32_t get_type_size(ASR::ttype_t* asr_type, llvm::Type* llvm_type, - int32_t a_kind) { - if( LLVM::is_llvm_struct(asr_type) || - ASR::is_a(*asr_type) || - ASR::is_a(*asr_type) ) { - llvm::DataLayout data_layout(module.get()); - return data_layout.getTypeAllocSize(llvm_type); - } - return a_kind; - } - - llvm::Type* get_dict_type(ASR::ttype_t* asr_type) { - ASR::Dict_t* asr_dict = ASR::down_cast(asr_type); - bool is_local_array_type = false, is_local_malloc_array_type = false; - bool is_local_list = false; - ASR::dimension_t* local_m_dims = nullptr; - int local_n_dims = 0; - int local_a_kind = -1; - ASR::storage_typeType local_m_storage = ASR::storage_typeType::Default; - llvm::Type* key_llvm_type = get_type_from_ttype_t(asr_dict->m_key_type, local_m_storage, - is_local_array_type, is_local_malloc_array_type, - is_local_list, local_m_dims, local_n_dims, - local_a_kind); - int32_t key_type_size = get_type_size(asr_dict->m_key_type, key_llvm_type, local_a_kind); - llvm::Type* value_llvm_type = get_type_from_ttype_t(asr_dict->m_value_type, local_m_storage, - is_local_array_type, is_local_malloc_array_type, - is_local_list, local_m_dims, local_n_dims, - local_a_kind); - int32_t value_type_size = get_type_size(asr_dict->m_value_type, value_llvm_type, local_a_kind); - std::string key_type_code = ASRUtils::get_type_code(asr_dict->m_key_type); - std::string value_type_code = ASRUtils::get_type_code(asr_dict->m_value_type); - set_dict_api(asr_dict); - return llvm_utils->dict_api->get_dict_type(key_type_code, value_type_code, key_type_size, - value_type_size, key_llvm_type, value_llvm_type); - } - - llvm::Type* get_type_from_ttype_t(ASR::ttype_t* asr_type, - ASR::storage_typeType m_storage, - bool& is_array_type, bool& is_malloc_array_type, - bool& is_list, ASR::dimension_t*& m_dims, - int& n_dims, int& a_kind, ASR::abiType m_abi=ASR::abiType::Source) { - llvm::Type* llvm_type = nullptr; - switch (asr_type->type) { - case (ASR::ttypeType::Integer) : { - ASR::Integer_t* v_type = down_cast(asr_type); - m_dims = v_type->m_dims; - n_dims = v_type->n_dims; - a_kind = v_type->m_kind; - if( n_dims > 0 ) { - if( m_abi == ASR::abiType::BindC ) { - if( ASRUtils::is_fixed_size_array(v_type->m_dims, v_type->n_dims) ) { - llvm_type = llvm::ArrayType::get(get_el_type(asr_type), ASRUtils::get_fixed_size_of_array( - v_type->m_dims, v_type->n_dims)); - } else { - llvm_type = get_el_type(asr_type)->getPointerTo(); - } - } else { - is_array_type = true; - llvm::Type* el_type = get_el_type(asr_type); - if( m_storage == ASR::storage_typeType::Allocatable ) { - is_malloc_array_type = true; - llvm_type = arr_descr->get_malloc_array_type(asr_type, el_type); - } else { - llvm_type = arr_descr->get_array_type(asr_type, el_type); - } - } - } else { - llvm_type = getIntType(a_kind); - } - break; - } - case (ASR::ttypeType::Real) : { - ASR::Real_t* v_type = down_cast(asr_type); - m_dims = v_type->m_dims; - n_dims = v_type->n_dims; - a_kind = v_type->m_kind; - if( n_dims > 0 ) { - if( m_abi == ASR::abiType::BindC ) { - if( ASRUtils::is_fixed_size_array(v_type->m_dims, v_type->n_dims) ) { - llvm_type = llvm::ArrayType::get(get_el_type(asr_type), ASRUtils::get_fixed_size_of_array( - v_type->m_dims, v_type->n_dims)); - } else { - llvm_type = get_el_type(asr_type)->getPointerTo(); - } - } else { - is_array_type = true; - llvm::Type* el_type = get_el_type(asr_type); - if( m_storage == ASR::storage_typeType::Allocatable ) { - is_malloc_array_type = true; - llvm_type = arr_descr->get_malloc_array_type(asr_type, el_type); - } else { - llvm_type = arr_descr->get_array_type(asr_type, el_type); - } - } - } else { - llvm_type = getFPType(a_kind); - } - break; - } - case (ASR::ttypeType::Complex) : { - ASR::Complex_t* v_type = down_cast(asr_type); - m_dims = v_type->m_dims; - n_dims = v_type->n_dims; - a_kind = v_type->m_kind; - if( n_dims > 0 ) { - if( m_abi == ASR::abiType::BindC ) { - if( ASRUtils::is_fixed_size_array(v_type->m_dims, v_type->n_dims) ) { - llvm_type = llvm::ArrayType::get(get_el_type(asr_type), ASRUtils::get_fixed_size_of_array( - v_type->m_dims, v_type->n_dims)); - } else { - llvm_type = get_el_type(asr_type)->getPointerTo(); - } - } else { - is_array_type = true; - llvm::Type* el_type = get_el_type(asr_type); - if( m_storage == ASR::storage_typeType::Allocatable ) { - is_malloc_array_type = true; - llvm_type = arr_descr->get_malloc_array_type(asr_type, el_type); - } else { - llvm_type = arr_descr->get_array_type(asr_type, el_type); - } - } - } else { - llvm_type = getComplexType(a_kind); - } - break; - } - case (ASR::ttypeType::Character) : { - ASR::Character_t* v_type = down_cast(asr_type); - m_dims = v_type->m_dims; - n_dims = v_type->n_dims; - a_kind = v_type->m_kind; - if( n_dims > 0 ) { - is_array_type = true; - llvm::Type* el_type = get_el_type(asr_type); - if( m_storage == ASR::storage_typeType::Allocatable ) { - is_malloc_array_type = true; - llvm_type = arr_descr->get_malloc_array_type(asr_type, el_type); - } else { - llvm_type = arr_descr->get_array_type(asr_type, el_type); - } - } else { - llvm_type = character_type; - } - break; - } - case (ASR::ttypeType::Logical) : { - ASR::Logical_t* v_type = down_cast(asr_type); - m_dims = v_type->m_dims; - n_dims = v_type->n_dims; - a_kind = v_type->m_kind; - if( n_dims > 0 ) { - if( m_abi == ASR::abiType::BindC ) { - llvm_type = get_el_type(asr_type)->getPointerTo(); - } else { - is_array_type = true; - llvm::Type* el_type = get_el_type(asr_type); - if( m_storage == ASR::storage_typeType::Allocatable ) { - is_malloc_array_type = true; - llvm_type = arr_descr->get_malloc_array_type(asr_type, el_type); - } else { - llvm_type = arr_descr->get_array_type(asr_type, el_type); - } - } - } else { - llvm_type = llvm::Type::getInt1Ty(context); - } - break; - } - case (ASR::ttypeType::Struct) : { - ASR::Struct_t* v_type = down_cast(asr_type); - m_dims = v_type->m_dims; - n_dims = v_type->n_dims; - if( n_dims > 0 ) { - is_array_type = true; - llvm::Type* el_type = get_el_type(asr_type); - if( m_storage == ASR::storage_typeType::Allocatable ) { - is_malloc_array_type = true; - llvm_type = arr_descr->get_malloc_array_type(asr_type, el_type); - } else { - llvm_type = arr_descr->get_array_type(asr_type, el_type); - } - } else { - llvm_type = getStructType(asr_type, false); - } - break; - } - case (ASR::ttypeType::Union) : { - ASR::Union_t* v_type = ASR::down_cast(asr_type); - m_dims = v_type->m_dims; - n_dims = v_type->n_dims; - if( n_dims > 0 ) { - is_array_type = true; - llvm::Type* el_type = get_el_type(asr_type); - if( m_storage == ASR::storage_typeType::Allocatable ) { - is_malloc_array_type = true; - llvm_type = arr_descr->get_malloc_array_type(asr_type, el_type); - } else { - llvm_type = arr_descr->get_array_type(asr_type, el_type); - } - } else { - llvm_type = getUnionType(asr_type, false); - } - break; - } - case (ASR::ttypeType::Pointer) : { - ASR::ttype_t *t2 = ASR::down_cast(asr_type)->m_type; - llvm_type = get_type_from_ttype_t(t2, m_storage, is_array_type, - is_malloc_array_type, is_list, m_dims, - n_dims, a_kind, m_abi); - llvm_type = llvm_type->getPointerTo(); - break; - } - case (ASR::ttypeType::List) : { - is_list = true; - ASR::List_t* asr_list = ASR::down_cast(asr_type); - llvm::Type* el_llvm_type = get_type_from_ttype_t(asr_list->m_type, m_storage, - is_array_type, is_malloc_array_type, - is_list, m_dims, n_dims, - a_kind, m_abi); - std::string el_type_code = ASRUtils::get_type_code(asr_list->m_type); - int32_t type_size = -1; - if( LLVM::is_llvm_struct(asr_list->m_type) || - ASR::is_a(*asr_list->m_type) || - ASR::is_a(*asr_list->m_type) ) { - llvm::DataLayout data_layout(module.get()); - type_size = data_layout.getTypeAllocSize(el_llvm_type); - } else { - type_size = a_kind; - } - llvm_type = list_api->get_list_type(el_llvm_type, el_type_code, type_size); - break; - } - case (ASR::ttypeType::Dict): { - llvm_type = get_dict_type(asr_type); - break; - } - case (ASR::ttypeType::Tuple) : { - ASR::Tuple_t* asr_tuple = ASR::down_cast(asr_type); - std::string type_code = ASRUtils::get_type_code(asr_tuple->m_type, - asr_tuple->n_type); - std::vector llvm_el_types; - for( size_t i = 0; i < asr_tuple->n_type; i++ ) { - bool is_local_array_type = false, is_local_malloc_array_type = false; - bool is_local_list = false; - ASR::dimension_t* local_m_dims = nullptr; - int local_n_dims = 0; - int local_a_kind = -1; - ASR::storage_typeType local_m_storage = ASR::storage_typeType::Default; - llvm_el_types.push_back(get_type_from_ttype_t(asr_tuple->m_type[i], local_m_storage, - is_local_array_type, is_local_malloc_array_type, - is_local_list, local_m_dims, local_n_dims, local_a_kind, m_abi)); - } - llvm_type = tuple_api->get_tuple_type(type_code, llvm_el_types); - break; - } - case (ASR::ttypeType::CPtr) : { - llvm_type = llvm::Type::getVoidTy(context)->getPointerTo(); - break; - } - case (ASR::ttypeType::Enum) : { - llvm_type = llvm::Type::getInt32Ty(context); - break ; - } - case (ASR::ttypeType::Const) : { - llvm_type = get_type_from_ttype_t(ASRUtils::get_contained_type(asr_type), - m_storage, is_array_type, is_malloc_array_type, is_list, - m_dims, n_dims, a_kind, m_abi); - break; - } - default : - throw CodeGenError("Support for type " + ASRUtils::type_to_str(asr_type) + - " not yet implemented."); - } - return llvm_type; - } - - inline llvm::Type* get_type_from_ttype_t_util(ASR::ttype_t* asr_type, ASR::abiType asr_abi=ASR::abiType::Source) { - ASR::storage_typeType m_storage_local = ASR::storage_typeType::Default; - bool is_array_type_local, is_malloc_array_type_local; - bool is_list_local; - ASR::dimension_t* m_dims_local; - int n_dims_local, a_kind_local; - return get_type_from_ttype_t(asr_type, m_storage_local, is_array_type_local, - is_malloc_array_type_local, is_list_local, - m_dims_local, n_dims_local, a_kind_local, asr_abi); - } - - void fill_array_details_(llvm::Value* ptr, ASR::dimension_t* m_dims, - size_t n_dims, bool is_malloc_array_type, bool is_array_type, - bool is_list, ASR::ttype_t* m_type, bool is_data_only=false) { - if( is_malloc_array_type && - m_type->type != ASR::ttypeType::Pointer && - !is_list && !is_data_only ) { - arr_descr->fill_dimension_descriptor(ptr, n_dims); - } - if( is_array_type && !is_malloc_array_type && - m_type->type != ASR::ttypeType::Pointer && - !is_list ) { - ASR::ttype_t* asr_data_type = ASRUtils::duplicate_type_without_dims(al, m_type, m_type->base.loc); - llvm::Type* llvm_data_type = get_type_from_ttype_t_util(asr_data_type); - fill_array_details(ptr, llvm_data_type, m_dims, n_dims, is_data_only); - } - if( is_array_type && is_malloc_array_type && - m_type->type != ASR::ttypeType::Pointer && - !is_list && !is_data_only ) { - // Set allocatable arrays as unallocated - arr_descr->set_is_allocated_flag(ptr, 0); - } - } - - void allocate_array_members_of_struct(llvm::Value* ptr, ASR::ttype_t* asr_type) { - LCOMPILERS_ASSERT(ASR::is_a(*asr_type)); - ASR::Struct_t* struct_t = ASR::down_cast(asr_type); - ASR::StructType_t* struct_type_t = ASR::down_cast( - ASRUtils::symbol_get_past_external(struct_t->m_derived_type)); - std::string struct_type_name = struct_type_t->m_name; - for( auto item: struct_type_t->m_symtab->get_scope() ) { - if( ASR::is_a(*item.second) || - ASR::is_a(*item.second) || - ASR::is_a(*item.second) || - ASR::is_a(*item.second) || - ASR::is_a(*item.second) ) { - continue ; - } - ASR::ttype_t* symbol_type = ASRUtils::symbol_type(item.second); - int idx = name2memidx[struct_type_name][item.first]; - llvm::Value* ptr_member = llvm_utils->create_gep(ptr, idx); - if( ASR::is_a(*item.second) ) { - ASR::Variable_t* v = ASR::down_cast(item.second); - if( v->m_symbolic_value ) { - visit_expr(*v->m_symbolic_value); - LLVM::CreateStore(*builder, tmp, ptr_member); - } - } - if( ASRUtils::is_array(symbol_type) ) { - // Assume that struct member array is not allocatable - ASR::dimension_t* m_dims = nullptr; - size_t n_dims = ASRUtils::extract_dimensions_from_ttype(symbol_type, m_dims); - bool is_data_only = (ASRUtils::symbol_abi(item.second) == ASR::abiType::BindC && - ASRUtils::is_fixed_size_array(m_dims, n_dims)); - fill_array_details_(ptr_member, m_dims, n_dims, false, true, false, symbol_type, is_data_only); - } else if( ASR::is_a(*symbol_type) ) { - allocate_array_members_of_struct(ptr_member, symbol_type); - } - } - } - - template - void declare_vars(const T &x) { - llvm::Value *target_var; - uint32_t debug_arg_count = 0; - std::vector var_order = ASRUtils::determine_variable_declaration_order(x.m_symtab); - for (auto &item : var_order) { - ASR::symbol_t* var_sym = x.m_symtab->get_symbol(item); - if (is_a(*var_sym)) { - ASR::Variable_t *v = down_cast(var_sym); - uint32_t h = get_hash((ASR::asr_t*)v); - llvm::Type *type; - int n_dims = 0, a_kind = 4; - ASR::dimension_t* m_dims = nullptr; - bool is_array_type = false; - bool is_malloc_array_type = false; - bool is_list = false; - if (v->m_intent == intent_local || - v->m_intent == intent_return_var || - !v->m_intent) { - type = get_type_from_ttype_t(v->m_type, v->m_storage, is_array_type, - is_malloc_array_type, is_list, m_dims, n_dims, - a_kind); - /* - * The following if block is used for converting any - * general array descriptor to a pointer type which - * can be passed as an argument in a function call in LLVM IR. - */ - if( x.class_type == ASR::symbolType::Function) { - std::uint32_t m_h; - std::string m_name = std::string(x.m_name); - ASR::abiType abi_type = ASR::abiType::Source; - bool is_v_arg = false; - if( x.class_type == ASR::symbolType::Function ) { - ASR::Function_t* _func = (ASR::Function_t*)(&(x.base)); - m_h = get_hash((ASR::asr_t*)_func); - abi_type = ASRUtils::get_FunctionType(_func)->m_abi; - is_v_arg = is_argument(v, _func->m_args, _func->n_args); - } - if( is_array_type && !is_list ) { - /* The first element in an array descriptor can be either of - * llvm::ArrayType or llvm::PointerType. However, a - * function only accepts llvm::PointerType for arrays. Hence, - * the following if block extracts the pointer to first element - * of an array from its descriptor. Note that this happens only - * for arguments and not for local function variables. - */ - if( abi_type == ASR::abiType::Source && is_v_arg ) { - type = arr_descr->get_argument_type(type, m_h, v->m_name, arr_arg_type_cache); - is_array_type = false; - } else if( abi_type == ASR::abiType::Intrinsic && - fname2arg_type.find(m_name) != fname2arg_type.end() ) { - type = fname2arg_type[m_name].second; - is_array_type = false; - } - } - } - llvm::AllocaInst *ptr = builder->CreateAlloca(type, nullptr, v->m_name); - if( ASR::is_a(*v->m_type) && - !(is_array_type || is_malloc_array_type) ) { - allocate_array_members_of_struct(ptr, v->m_type); - } - if (compiler_options.emit_debug_info) { - // Reset the debug location - builder->SetCurrentDebugLocation(nullptr); - uint32_t line, column; - if (compiler_options.emit_debug_line_column) { - debug_get_line_column(v->base.base.loc.first, line, column); - } else { - line = v->base.base.loc.first; - column = 0; - } - std::string type_name; - uint32_t type_size, type_encoding; - get_type_debug_info(v->m_type, type_name, type_size, - type_encoding); - llvm::DILocalVariable *debug_var = DBuilder->createParameterVariable( - debug_current_scope, v->m_name, ++debug_arg_count, debug_Unit, line, - DBuilder->createBasicType(type_name, type_size, type_encoding), true); - DBuilder->insertDeclare(ptr, debug_var, DBuilder->createExpression(), - llvm::DILocation::get(debug_current_scope->getContext(), - line, 0, debug_current_scope), builder->GetInsertBlock()); - } - - if( ASR::is_a(*v->m_type) ) { - ASR::Struct_t* struct_t = ASR::down_cast(v->m_type); - ASR::StructType_t* struct_type = ASR::down_cast( - ASRUtils::symbol_get_past_external(struct_t->m_derived_type)); - int64_t alignment_value = -1; - if( ASRUtils::extract_value(struct_type->m_alignment, alignment_value) ) { - llvm::Align align(alignment_value); - ptr->setAlignment(align); - } - } - - llvm_symtab[h] = ptr; - fill_array_details_(ptr, m_dims, n_dims, - is_malloc_array_type, - is_array_type, is_list, v->m_type); - ASR::expr_t* init_expr = v->m_symbolic_value; - if( !ASR::is_a(*v->m_type) ) { - for( size_t i = 0; i < v->n_dependencies; i++ ) { - std::string variable_name = v->m_dependencies[i]; - ASR::symbol_t* dep_sym = x.m_symtab->resolve_symbol(variable_name); - if( (dep_sym && ASR::is_a(*dep_sym) && - !ASR::down_cast(dep_sym)->m_symbolic_value) ) { - init_expr = nullptr; - break; - } - } - } - if( init_expr != nullptr && - !ASR::is_a(*v->m_type)) { - target_var = ptr; - tmp = nullptr; - if (v->m_value != nullptr) { - this->visit_expr_wrapper(v->m_value, true); - } else { - this->visit_expr_wrapper(v->m_symbolic_value, true); - } - llvm::Value *init_value = tmp; - if (ASR::is_a(*v->m_symbolic_value)) { - target_var = arr_descr->get_pointer_to_data(target_var); - } - builder->CreateStore(init_value, target_var); - auto finder = std::find(nested_globals.begin(), - nested_globals.end(), h); - if (finder != nested_globals.end()) { - llvm::Value* ptr = module->getOrInsertGlobal(nested_desc_name, - nested_global_struct); - int idx = std::distance(nested_globals.begin(), - finder); - if( is_array_type || is_malloc_array_type ) { - target_var = CreateLoad(target_var); - } - builder->CreateStore(target_var, llvm_utils->create_gep(ptr, - idx)); - } - } else { - if (is_a(*v->m_type) && !is_array_type && !is_list) { - ASR::Character_t *t = down_cast(v->m_type); - target_var = ptr; - int strlen = t->m_len; - if (strlen >= 0) { - // Compile time length - std::string empty(strlen, ' '); - llvm::Value *init_value = builder->CreateGlobalStringPtr(s2c(al, empty)); - builder->CreateStore(init_value, target_var); - } else if (strlen == -2) { - // Allocatable string. Initialize to `nullptr` (unallocated) - llvm::Value *init_value = llvm::Constant::getNullValue(type); - builder->CreateStore(init_value, target_var); - } else if (strlen == -3) { - LCOMPILERS_ASSERT(t->m_len_expr) - this->visit_expr(*t->m_len_expr); - llvm::Value *arg_size = tmp; - arg_size = builder->CreateAdd(arg_size, llvm::ConstantInt::get(context, llvm::APInt(32, 1))); - // TODO: this temporary string is never deallocated (leaks memory) - llvm::Value *init_value = LLVM::lfortran_malloc(context, *module, *builder, arg_size); - string_init(context, *module, *builder, arg_size, init_value); - builder->CreateStore(init_value, target_var); - } else { - throw CodeGenError("Unsupported len value in ASR"); - } - } else if (is_list) { - ASR::List_t* asr_list = ASR::down_cast(v->m_type); - std::string type_code = ASRUtils::get_type_code(asr_list->m_type); - list_api->list_init(type_code, ptr, *module); - } - } - } - } - } - } - - llvm::Type* get_arg_type_from_ttype_t(ASR::ttype_t* asr_type, - ASR::abiType m_abi, ASR::abiType arg_m_abi, - ASR::storage_typeType m_storage, - bool arg_m_value_attr, - int& n_dims, int& a_kind, bool& is_array_type, - ASR::intentType arg_intent, bool get_pointer=true) { - llvm::Type* type = nullptr; - switch (asr_type->type) { - case (ASR::ttypeType::Integer) : { - ASR::Integer_t* v_type = down_cast(asr_type); - n_dims = v_type->n_dims; - a_kind = v_type->m_kind; - if( n_dims > 0 ) { - if (m_abi == ASR::abiType::BindC || - (!ASRUtils::is_dimension_empty(v_type->m_dims, v_type->n_dims))) { - // Bind(C) arrays are represened as a pointer - type = getIntType(a_kind, true); - } else { - is_array_type = true; - llvm::Type* el_type = get_el_type(asr_type); - if( m_storage == ASR::storage_typeType::Allocatable ) { - type = arr_descr->get_malloc_array_type(asr_type, el_type, get_pointer); - } else { - type = arr_descr->get_array_type(asr_type, el_type, get_pointer); - } - } - } else { - if (arg_m_abi == ASR::abiType::BindC - && arg_m_value_attr) { - type = getIntType(a_kind, false); - } else { - type = getIntType(a_kind, true); - } - } - break; - } - case (ASR::ttypeType::Pointer) : { - ASR::ttype_t *t2 = ASRUtils::type_get_past_pointer(asr_type); - type = get_arg_type_from_ttype_t(t2, m_abi, arg_m_abi, - m_storage, arg_m_value_attr, n_dims, a_kind, - is_array_type, arg_intent, get_pointer); - type = type->getPointerTo(); - break; - } - case (ASR::ttypeType::Const) : { - ASR::ttype_t *t2 = ASRUtils::get_contained_type(asr_type); - type = get_arg_type_from_ttype_t(t2, m_abi, arg_m_abi, - m_storage, arg_m_value_attr, n_dims, a_kind, - is_array_type, arg_intent, get_pointer); - break; - } - case (ASR::ttypeType::Real) : { - ASR::Real_t* v_type = down_cast(asr_type); - n_dims = v_type->n_dims; - a_kind = v_type->m_kind; - if( n_dims > 0 ) { - if (m_abi == ASR::abiType::BindC || - (!ASRUtils::is_dimension_empty(v_type->m_dims, v_type->n_dims))) { - // Bind(C) arrays are represened as a pointer - type = getFPType(a_kind, true); - } else { - is_array_type = true; - llvm::Type* el_type = get_el_type(asr_type); - if( m_storage == ASR::storage_typeType::Allocatable ) { - type = arr_descr->get_malloc_array_type(asr_type, el_type, get_pointer); - } else { - type = arr_descr->get_array_type(asr_type, el_type, get_pointer); - } - } - } else { - if (arg_m_abi == ASR::abiType::BindC - && arg_m_value_attr) { - type = getFPType(a_kind, false); - } else { - type = getFPType(a_kind, true); - } - } - break; - } - case (ASR::ttypeType::Complex) : { - ASR::Complex_t* v_type = down_cast(asr_type); - n_dims = v_type->n_dims; - a_kind = v_type->m_kind; - if (m_abi != ASR::abiType::BindC && - (!ASRUtils::is_dimension_empty(v_type->m_dims, v_type->n_dims))) { - type = getComplexType(a_kind, true); - } else if( n_dims > 0 ) { - is_array_type = true; - llvm::Type* el_type = get_el_type(asr_type); - if( m_storage == ASR::storage_typeType::Allocatable ) { - type = arr_descr->get_malloc_array_type(asr_type, el_type, get_pointer); - } else { - type = arr_descr->get_array_type(asr_type, el_type, get_pointer); - } - } else { - if (arg_m_abi == ASR::abiType::BindC - && arg_m_value_attr) { - if (a_kind == 4) { - if (compiler_options.platform == Platform::Windows) { - // type_fx2 is i64 - llvm::Type* type_fx2 = llvm::Type::getInt64Ty(context); - type = type_fx2; - } else if (compiler_options.platform == Platform::macOS_ARM) { - // type_fx2 is [2 x float] - llvm::Type* type_fx2 = llvm::ArrayType::get(llvm::Type::getFloatTy(context), 2); - type = type_fx2; - } else { - // type_fx2 is <2 x float> - llvm::Type* type_fx2 = FIXED_VECTOR_TYPE::get(llvm::Type::getFloatTy(context), 2); - type = type_fx2; - } - } else { - LCOMPILERS_ASSERT(a_kind == 8) - if (compiler_options.platform == Platform::Windows) { - // 128 bit aggregate type is passed by reference - type = getComplexType(a_kind, true); - } else { - // Pass by value - type = getComplexType(a_kind, false); - } - } - } else { - type = getComplexType(a_kind, true); - } - } - break; - } - case (ASR::ttypeType::Character) : - if (arg_m_abi == ASR::abiType::BindC) { - type = character_type; - } else { - type = character_type->getPointerTo(); - } - break; - case (ASR::ttypeType::Logical) : { - ASR::Logical_t* v_type = down_cast(asr_type); - n_dims = v_type->n_dims; - a_kind = v_type->m_kind; - if( n_dims > 0 ) { - if (m_abi == ASR::abiType::BindC || - (!ASRUtils::is_dimension_empty(v_type->m_dims, v_type->n_dims))) { - // Bind(C) arrays are represened as a pointer - type = llvm::Type::getInt1PtrTy(context); - } else { - is_array_type = true; - llvm::Type* el_type = get_el_type(asr_type); - if( m_storage == ASR::storage_typeType::Allocatable ) { - type = arr_descr->get_malloc_array_type(asr_type, el_type, get_pointer); - } else { - type = arr_descr->get_array_type(asr_type, el_type, get_pointer); - } - } - } else { - if (arg_m_abi == ASR::abiType::BindC - && arg_m_value_attr) { - type = llvm::Type::getInt1Ty(context); - } else { - type = llvm::Type::getInt1PtrTy(context); - } - } - break; - } - case (ASR::ttypeType::Struct) : { - ASR::Struct_t* v_type = down_cast(asr_type); - n_dims = v_type->n_dims; - if( n_dims > 0 ) { - is_array_type = true; - llvm::Type* el_type = get_el_type(asr_type); - if( m_storage == ASR::storage_typeType::Allocatable ) { - type = arr_descr->get_malloc_array_type(asr_type, el_type, get_pointer); - } else { - type = arr_descr->get_array_type(asr_type, el_type, get_pointer); - } - } else { - type = getStructType(asr_type, true); - } - break; - } - case (ASR::ttypeType::Class) : { - ASR::Class_t* v_type = down_cast(asr_type); - n_dims = v_type->n_dims; - if( n_dims > 0 ) { - is_array_type = true; - llvm::Type* el_type = get_el_type(asr_type); - if( m_storage == ASR::storage_typeType::Allocatable ) { - type = arr_descr->get_malloc_array_type(asr_type, el_type, get_pointer); - } else { - type = arr_descr->get_array_type(asr_type, el_type, get_pointer); - } - } else { - type = getClassType(asr_type, true); - } - break; - } - case (ASR::ttypeType::CPtr) : { - type = llvm::Type::getVoidTy(context)->getPointerTo(); - break; - } - case (ASR::ttypeType::Tuple) : { - type = get_type_from_ttype_t_util(asr_type)->getPointerTo(); - break; - } - case (ASR::ttypeType::List) : { - bool is_array_type = false, is_malloc_array_type = false; - bool is_list = true; - ASR::dimension_t *m_dims = nullptr; - ASR::List_t* asr_list = ASR::down_cast(asr_type); - llvm::Type* el_llvm_type = get_type_from_ttype_t(asr_list->m_type, m_storage, - is_array_type, - is_malloc_array_type, - is_list, m_dims, n_dims, - a_kind, m_abi); - int32_t type_size = -1; - if( LLVM::is_llvm_struct(asr_list->m_type) || - ASR::is_a(*asr_list->m_type) || - ASR::is_a(*asr_list->m_type) ) { - llvm::DataLayout data_layout(module.get()); - type_size = data_layout.getTypeAllocSize(el_llvm_type); - } else { - type_size = a_kind; - } - std::string el_type_code = ASRUtils::get_type_code(asr_list->m_type); - type = list_api->get_list_type(el_llvm_type, el_type_code, type_size)->getPointerTo(); - break; - } - case ASR::ttypeType::Enum: { - if (arg_m_abi == ASR::abiType::BindC - && arg_m_value_attr) { - type = llvm::Type::getInt32Ty(context); - } else { - type = llvm::Type::getInt32PtrTy(context); - } - break ; - } - default : - LCOMPILERS_ASSERT(false); - } - return type; - } - - template - std::vector convert_args(const T &x) { - std::vector args; - for (size_t i=0; i(*symbol_get_past_external( - ASR::down_cast(x.m_args[i])->m_v))) { - ASR::Variable_t *arg = EXPR2VAR(x.m_args[i]); - LCOMPILERS_ASSERT(is_arg_dummy(arg->m_intent)); - // We pass all arguments as pointers for now, - // except bind(C) value arguments that are passed by value - llvm::Type *type = nullptr, *type_original = nullptr; - int n_dims = 0, a_kind = 4; - bool is_array_type = false; - type_original = get_arg_type_from_ttype_t(arg->m_type, ASRUtils::get_FunctionType(x)->m_abi, - arg->m_abi, arg->m_storage, arg->m_value_attr, - n_dims, a_kind, is_array_type, arg->m_intent, - false); - if( is_array_type ) { - type = type_original->getPointerTo(); - } else { - type = type_original; - } - if( arg->m_intent == ASRUtils::intent_out && - ASR::is_a(*arg->m_type) ) { - type = type->getPointerTo(); - } - std::uint32_t m_h; - std::string m_name = std::string(x.m_name); - if( x.class_type == ASR::symbolType::Function ) { - ASR::Function_t* _func = (ASR::Function_t*)(&(x.base)); - m_h = get_hash((ASR::asr_t*)_func); - } - if( is_array_type && arg->m_type->type != ASR::ttypeType::Pointer ) { - if( ASRUtils::get_FunctionType(x)->m_abi == ASR::abiType::Source ) { - llvm::Type* orig_type = type_original; - type = arr_descr->get_argument_type(orig_type, m_h, arg->m_name, arr_arg_type_cache); - is_array_type = false; - } else if( ASRUtils::get_FunctionType(x)->m_abi == ASR::abiType::Intrinsic && - fname2arg_type.find(m_name) != fname2arg_type.end()) { - type = fname2arg_type[m_name].second; - is_array_type = false; - } - } - args.push_back(type); - } else if (is_a(*symbol_get_past_external( - ASR::down_cast(x.m_args[i])->m_v))) { - /* This is likely a procedure passed as an argument. For the - type, we need to pass in a function pointer with the - correct call signature. */ - ASR::Function_t* fn = ASR::down_cast( - symbol_get_past_external(ASR::down_cast( - x.m_args[i])->m_v)); - llvm::Type* type = get_function_type(*fn)->getPointerTo(); - args.push_back(type); - } else { - throw CodeGenError("Argument type not implemented"); - } - } - return args; - } - - - template - void push_nested_stack(const T &x) { - bool finder = std::find(nested_call_out.begin(), nested_call_out.end(), - parent_function_hash) != nested_call_out.end(); - bool is_nested_call = std::find( - nesting_map[parent_function_hash].begin(), - nesting_map[parent_function_hash].end(), calling_function_hash) - != nesting_map[parent_function_hash].end(); - if (nested_func_types[parent_function_hash].size() > 0 - && parent_function_hash != calling_function_hash && finder - && !is_nested_call){ - llvm::Value *sp_loc = module->getOrInsertGlobal( - nested_sp_name, llvm::Type::getInt32Ty(context)); - llvm::Value *sp_val = CreateLoad(sp_loc); - for (auto &item : x->m_symtab->get_scope()) { - if (is_a(*item.second)) { - ASR::Variable_t *v = down_cast( - item.second); - uint32_t h = get_hash((ASR::asr_t*)v); - auto finder = std::find(nested_globals.begin(), - nested_globals.end(), h); - if (finder != nested_globals.end()) { - int idx = std::distance(nested_globals.begin(), - finder); - llvm::Value* glob_struct = module->getOrInsertGlobal( - nested_desc_name, nested_global_struct); - llvm::Value* target = CreateLoad(llvm_utils->create_gep( - glob_struct, idx)); - llvm::Value* glob_stack = module->getOrInsertGlobal( - nested_stack_name, nested_global_stack); - llvm::Value *glob_stack_gep = llvm_utils->create_gep(glob_stack, - sp_val); - llvm::Value *glob_stack_elem = llvm_utils->create_gep( - glob_stack_gep, idx); - builder->CreateStore(CreateLoad(target), - glob_stack_elem); - llvm::Value *glob_stack_val = CreateLoad( - glob_stack_gep); - llvm::Value *glob_stack_sp = llvm_utils->create_gep(glob_stack, - sp_val); - builder->CreateStore(glob_stack_val, glob_stack_sp); - } - } - } - builder->CreateStore(builder->CreateAdd(builder->getInt32(1), - sp_val), sp_loc); - } - } - - - template - void pop_nested_stack(const T &x) { - llvm::Function *lfn = builder->GetInsertBlock()->getParent(); - bool finder = std::find(nested_call_out.begin(), nested_call_out.end(), - calling_function_hash) != nested_call_out.end(); - bool is_nested_call = std::find( - nesting_map[parent_function_hash].begin(), - nesting_map[parent_function_hash].end(), calling_function_hash) - != nesting_map[parent_function_hash].end(); - if (nested_func_types[calling_function_hash].size() > 0 - && calling_function_hash != parent_function_hash && finder - && !is_nested_call){ - llvm::Value *sp_loc = module->getOrInsertGlobal(nested_sp_name, - llvm::Type::getInt32Ty(context)); - llvm::Value *sp_val = CreateLoad(sp_loc); - llvm::BasicBlock *dec_sp = llvm::BasicBlock::Create(context, - "decrement_sp", lfn); - llvm::BasicBlock *norm_cont = llvm::BasicBlock::Create(context, - "normal_continue", lfn); - llvm::Value *cond = builder->CreateICmpSGT(sp_val, - builder->getInt32(0)); - builder->CreateCondBr(cond, dec_sp, norm_cont); - builder->SetInsertPoint(dec_sp); - builder->CreateStore(builder->CreateAdd(builder->getInt32(-1), - sp_val), sp_loc); - for (auto &item : x->m_symtab->get_scope()) { - if (is_a(*item.second)) { - ASR::Variable_t *v = down_cast( - item.second); - uint32_t h = get_hash((ASR::asr_t*)v); - auto finder = std::find(nested_globals.begin(), - nested_globals.end(), h); - if (finder != nested_globals.end()) { - int idx = std::distance(nested_globals.begin(), - finder); - llvm::Value* glob_stack = module->getOrInsertGlobal( - nested_stack_name, nested_global_stack); - llvm::Value *sp_loc = module->getOrInsertGlobal( - nested_sp_name, llvm::Type::getInt32Ty(context)); - llvm::Value *sp_val = CreateLoad(sp_loc); - llvm::Value *glob_stack_elem = CreateLoad( - llvm_utils->create_gep(llvm_utils->create_gep(glob_stack, sp_val), idx)); - llvm::Value *glob_struct_loc = module-> - getOrInsertGlobal(nested_desc_name, - nested_global_struct); - llvm::Value* target = CreateLoad( - llvm_utils->create_gep(glob_struct_loc, idx)); - builder->CreateStore(glob_stack_elem, target); - builder->CreateStore(target, llvm_utils->create_gep( - glob_struct_loc, idx)); - } - } - } - builder->CreateBr(norm_cont); - builder->SetInsertPoint(norm_cont); - } - } - - template - void declare_args(const T &x, llvm::Function &F) { - size_t i = 0; - for (llvm::Argument &llvm_arg : F.args()) { - if (is_a(*symbol_get_past_external( - ASR::down_cast(x.m_args[i])->m_v))) { - ASR::Variable_t *arg = EXPR2VAR(x.m_args[i]); - LCOMPILERS_ASSERT(is_arg_dummy(arg->m_intent)); - uint32_t h = get_hash((ASR::asr_t*)arg); - auto finder = std::find(nested_globals.begin(), - nested_globals.end(), h); - if (finder != nested_globals.end()) { - llvm::Value* ptr = module->getOrInsertGlobal(nested_desc_name, - nested_global_struct); - int idx = std::distance(nested_globals.begin(), - finder); - builder->CreateStore(&llvm_arg, llvm_utils->create_gep(ptr, - idx)); - } - std::string arg_s = arg->m_name; - llvm_arg.setName(arg_s); - llvm_symtab[h] = &llvm_arg; - } else if (is_a(*symbol_get_past_external( - ASR::down_cast(x.m_args[i])->m_v))) { - // Deal with case where procedure passed in as argument - ASR::Function_t *arg = EXPR2FUN(x.m_args[i]); - uint32_t h = get_hash((ASR::asr_t*)arg); - std::string arg_s = arg->m_name; - llvm_arg.setName(arg_s); - llvm_symtab_fn_arg[h] = &llvm_arg; - } - i++; - } - } - - template - void declare_local_vars(const T &x) { - declare_vars(x); - } - - void visit_Function(const ASR::Function_t &x) { - bool is_dict_present_copy_lp = dict_api_lp->is_dict_present(); - bool is_dict_present_copy_sc = dict_api_sc->is_dict_present(); - dict_api_lp->set_is_dict_present(false); - dict_api_sc->set_is_dict_present(false); - llvm_goto_targets.clear(); - instantiate_function(x); - if (ASRUtils::get_FunctionType(x)->m_deftype == ASR::deftypeType::Interface) { - // Interface does not have an implementation and it is already - // declared, so there is nothing to do here - return; - } - visit_procedures(x); - generate_function(x); - parent_function = nullptr; - dict_api_lp->set_is_dict_present(is_dict_present_copy_lp); - dict_api_sc->set_is_dict_present(is_dict_present_copy_sc); - - // Finalize the debug info. - if (compiler_options.emit_debug_info) DBuilder->finalize(); - } - - void instantiate_function(const ASR::Function_t &x){ - uint32_t h = get_hash((ASR::asr_t*)&x); - llvm::Function *F = nullptr; - llvm::DISubprogram *SP; - std::string sym_name = x.m_name; - if (sym_name == "main") { - sym_name = "_xx_lcompilers_changed_main_xx"; - } - if (llvm_symtab_fn.find(h) != llvm_symtab_fn.end()) { - /* - throw CodeGenError("Function code already generated for '" - + std::string(x.m_name) + "'"); - */ - F = llvm_symtab_fn[h]; - } else { - llvm::FunctionType* function_type = get_function_type(x); - std::string fn_name; - if (ASRUtils::get_FunctionType(x)->m_abi == ASR::abiType::BindC) { - if (ASRUtils::get_FunctionType(x)->m_bindc_name) { - fn_name = ASRUtils::get_FunctionType(x)->m_bindc_name; - } else { - fn_name = sym_name; - } - } else if (ASRUtils::get_FunctionType(x)->m_deftype == ASR::deftypeType::Interface && - ASRUtils::get_FunctionType(x)->m_abi != ASR::abiType::Intrinsic) { - fn_name = sym_name; - } else { - fn_name = mangle_prefix + sym_name; - } - if (llvm_symtab_fn_names.find(fn_name) == llvm_symtab_fn_names.end()) { - llvm_symtab_fn_names[fn_name] = h; - F = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, fn_name, module.get()); - - // Add Debugging information to the LLVM function F - if (compiler_options.emit_debug_info) { - debug_emit_function(x, SP); - F->setSubprogram(SP); - } - } else { - uint32_t old_h = llvm_symtab_fn_names[fn_name]; - F = llvm_symtab_fn[old_h]; - if (compiler_options.emit_debug_info) { - SP = (llvm::DISubprogram*) llvm_symtab_fn_discope[old_h]; - } - } - llvm_symtab_fn[h] = F; - if (compiler_options.emit_debug_info) llvm_symtab_fn_discope[h] = SP; - - // Instantiate (pre-declare) all nested interfaces - for (auto &item : x.m_symtab->get_scope()) { - if (is_a(*item.second)) { - ASR::Function_t *v = down_cast( - item.second); - // check if item.second is present in x.m_args - bool interface_as_arg = false; - for (size_t i=0; i(*x.m_args[i])) { - ASR::Var_t *arg = down_cast(x.m_args[i]); - if ( arg->m_v == item.second ) { - interface_as_arg = true; - llvm::FunctionType* fntype = get_function_type(*v); - llvm::Function* fn = llvm::Function::Create(fntype, llvm::Function::ExternalLinkage, v->m_name, module.get()); - uint32_t hash = get_hash((ASR::asr_t*)v); - llvm_symtab_fn[hash] = fn; - } - } - } - if (!interface_as_arg) { - instantiate_function(*v); - } - } - } - } - } - - - llvm::FunctionType* get_function_type(const ASR::Function_t &x){ - llvm::Type *return_type; - if (x.m_return_var) { - ASR::ttype_t *return_var_type0 = EXPR2VAR(x.m_return_var)->m_type; - ASR::ttypeType return_var_type = return_var_type0->type; - switch (return_var_type) { - case (ASR::ttypeType::Integer) : { - int a_kind = down_cast(return_var_type0)->m_kind; - return_type = getIntType(a_kind); - break; - } - case (ASR::ttypeType::Real) : { - int a_kind = down_cast(return_var_type0)->m_kind; - return_type = getFPType(a_kind); - break; - } - case (ASR::ttypeType::Complex) : { - int a_kind = down_cast(return_var_type0)->m_kind; - if (a_kind == 4) { - if (ASRUtils::get_FunctionType(x)->m_abi == ASR::abiType::BindC) { - if (compiler_options.platform == Platform::Windows) { - // i64 - return_type = llvm::Type::getInt64Ty(context); - } else if (compiler_options.platform == Platform::macOS_ARM) { - // {float, float} - return_type = getComplexType(a_kind); - } else { - // <2 x float> - return_type = FIXED_VECTOR_TYPE::get(llvm::Type::getFloatTy(context), 2); - } - } else { - return_type = getComplexType(a_kind); - } - } else { - LCOMPILERS_ASSERT(a_kind == 8) - if (ASRUtils::get_FunctionType(x)->m_abi == ASR::abiType::BindC) { - if (compiler_options.platform == Platform::Windows) { - // pass as subroutine - return_type = getComplexType(a_kind, true); - std::vector args = convert_args(x); - args.insert(args.begin(), return_type); - llvm::FunctionType *function_type = llvm::FunctionType::get( - llvm::Type::getVoidTy(context), args, false); - return function_type; - } else { - return_type = getComplexType(a_kind); - } - } else { - return_type = getComplexType(a_kind); - } - } - break; - } - case (ASR::ttypeType::Character) : - return_type = character_type; - break; - case (ASR::ttypeType::Logical) : - return_type = llvm::Type::getInt1Ty(context); - break; - case (ASR::ttypeType::CPtr) : - return_type = llvm::Type::getVoidTy(context)->getPointerTo(); - break; - case (ASR::ttypeType::Const) : { - return_type = get_type_from_ttype_t_util(ASRUtils::get_contained_type(return_var_type0)); - break; - } - case (ASR::ttypeType::Pointer) : { - return_type = get_type_from_ttype_t_util(ASRUtils::get_contained_type(return_var_type0))->getPointerTo(); - break; - } - case (ASR::ttypeType::Struct) : - throw CodeGenError("Struct return type not implemented yet"); - break; - case (ASR::ttypeType::Tuple) : { - ASR::Tuple_t* asr_tuple = ASR::down_cast(return_var_type0); - std::string type_code = ASRUtils::get_type_code(asr_tuple->m_type, - asr_tuple->n_type); - std::vector llvm_el_types; - for( size_t i = 0; i < asr_tuple->n_type; i++ ) { - bool is_local_array_type = false, is_local_malloc_array_type = false; - bool is_local_list = false; - ASR::dimension_t* local_m_dims = nullptr; - int local_n_dims = 0; - int local_a_kind = -1; - ASR::storage_typeType local_m_storage = ASR::storage_typeType::Default; - llvm_el_types.push_back(get_type_from_ttype_t(asr_tuple->m_type[i], local_m_storage, - is_local_array_type, is_local_malloc_array_type, - is_local_list, local_m_dims, local_n_dims, local_a_kind)); - } - return_type = tuple_api->get_tuple_type(type_code, llvm_el_types); - break; - } - case (ASR::ttypeType::List) : { - bool is_array_type = false, is_malloc_array_type = false; - bool is_list = true; - ASR::dimension_t *m_dims = nullptr; - ASR::storage_typeType m_storage = ASR::storage_typeType::Default; - int n_dims = 0, a_kind = -1; - ASR::List_t* asr_list = ASR::down_cast(return_var_type0); - llvm::Type* el_llvm_type = get_type_from_ttype_t(asr_list->m_type, m_storage, - is_array_type, - is_malloc_array_type, - is_list, m_dims, n_dims, - a_kind); - int32_t type_size = -1; - if( LLVM::is_llvm_struct(asr_list->m_type) || - ASR::is_a(*asr_list->m_type) || - ASR::is_a(*asr_list->m_type) ) { - llvm::DataLayout data_layout(module.get()); - type_size = data_layout.getTypeAllocSize(el_llvm_type); - } else { - type_size = a_kind; - } - std::string el_type_code = ASRUtils::get_type_code(asr_list->m_type); - return_type = list_api->get_list_type(el_llvm_type, el_type_code, type_size); - break; - } - default : - throw CodeGenError("Type not implemented " + std::to_string(return_var_type)); - } - } else { - return_type = llvm::Type::getVoidTy(context); - } - std::vector args = convert_args(x); - llvm::FunctionType *function_type = llvm::FunctionType::get( - return_type, args, false); - return function_type; - } - - template - void declare_needed_global_types(T &x){ - // Check if the procedure has a nested function that needs access to - // some variables in its local scope - uint32_t h = get_hash((ASR::asr_t*)&x); - std::vector nested_type; - if (nested_func_types[h].size() > 0) { - nested_type = nested_func_types[h]; - nested_global_struct = llvm::StructType::create(context, - nested_type, std::string(x.m_name) + "_nstd_types"); - std::vector nested_stack; - for (size_t i = 0; i < nested_type.size(); i++){ - nested_stack.push_back(nested_type[i]->getContainedType(0)); - } - nested_desc_name = std::string(x.m_name) + "_nstd_strct"; - module->getOrInsertGlobal(nested_desc_name, nested_global_struct); - llvm::ConstantAggregateZero *initializer; - initializer = llvm::ConstantAggregateZero::get( - nested_global_struct); - module->getNamedGlobal(nested_desc_name)->setInitializer( - initializer); - if (std::find(nested_call_out.begin(), nested_call_out.end(), h) != - nested_call_out.end()){ - /* Only declare the stack types if needed (if the function - enclosing a nested function can call out, potentially leading to - recursion, etc */ - nested_global_struct_vals = - llvm::StructType::create(context, nested_stack, - std::string(x.m_name) + "_vals"); - nested_global_stack = llvm::ArrayType::get( - nested_global_struct_vals, 1000); - nested_stack_name = nested_desc_name + "_stack"; - nested_sp_name = "sp_" + std::string(x.m_name); - llvm::IntegerType *sp = llvm::Type::getInt32Ty(context); - module->getOrInsertGlobal(nested_stack_name, - nested_global_stack); - module->getOrInsertGlobal(nested_sp_name, sp); - initializer = llvm::ConstantAggregateZero::get( - nested_global_stack); - module->getNamedGlobal(nested_stack_name)->setInitializer( - initializer); - llvm::ConstantInt *sp_init = llvm::ConstantInt::get( - module->getContext(), llvm::APInt(32,0)); - module->getNamedGlobal(nested_sp_name)->setInitializer( - sp_init); - } - } - } - - inline void define_function_entry(const ASR::Function_t& x) { - uint32_t h = get_hash((ASR::asr_t*)&x); - parent_function = &x; - parent_function_hash = h; - llvm::Function* F = llvm_symtab_fn[h]; - if (compiler_options.emit_debug_info) debug_current_scope = llvm_symtab_fn_discope[h]; - proc_return = llvm::BasicBlock::Create(context, "return"); - llvm::BasicBlock *BB = llvm::BasicBlock::Create(context, - ".entry", F); - builder->SetInsertPoint(BB); - if (compiler_options.emit_debug_info) debug_emit_loc(x); - declare_args(x, *F); - declare_local_vars(x); - } - - - inline void define_function_exit(const ASR::Function_t& x) { - if (x.m_return_var) { - start_new_block(proc_return); - ASR::Variable_t *asr_retval = EXPR2VAR(x.m_return_var); - uint32_t h = get_hash((ASR::asr_t*)asr_retval); - llvm::Value *ret_val = llvm_symtab[h]; - llvm::Value *ret_val2 = CreateLoad(ret_val); - // Handle Complex type return value for BindC: - if (ASRUtils::get_FunctionType(x)->m_abi == ASR::abiType::BindC) { - ASR::ttype_t* arg_type = asr_retval->m_type; - llvm::Value *tmp = ret_val; - if (is_a(*arg_type)) { - int c_kind = ASRUtils::extract_kind_from_ttype_t(arg_type); - if (c_kind == 4) { - if (compiler_options.platform == Platform::Windows) { - // tmp is {float, float}* - // type_fx2p is i64* - llvm::Type* type_fx2p = llvm::Type::getInt64PtrTy(context); - // Convert {float,float}* to i64* using bitcast - tmp = builder->CreateBitCast(tmp, type_fx2p); - // Then convert i64* -> i64 - tmp = CreateLoad(tmp); - } else if (compiler_options.platform == Platform::macOS_ARM) { - // Pass by value - tmp = CreateLoad(tmp); - } else { - // tmp is {float, float}* - // type_fx2p is <2 x float>* - llvm::Type* type_fx2p = FIXED_VECTOR_TYPE::get(llvm::Type::getFloatTy(context), 2)->getPointerTo(); - // Convert {float,float}* to <2 x float>* using bitcast - tmp = builder->CreateBitCast(tmp, type_fx2p); - // Then convert <2 x float>* -> <2 x float> - tmp = CreateLoad(tmp); - } - } else { - LCOMPILERS_ASSERT(c_kind == 8) - if (compiler_options.platform == Platform::Windows) { - // 128 bit aggregate type is passed by reference - } else { - // Pass by value - tmp = CreateLoad(tmp); - } - } - ret_val2 = tmp; - } - } - builder->CreateRet(ret_val2); - } else { - start_new_block(proc_return); - builder->CreateRetVoid(); - } - } - - void generate_function(const ASR::Function_t &x) { - bool interactive = (ASRUtils::get_FunctionType(x)->m_abi == ASR::abiType::Interactive); - if (ASRUtils::get_FunctionType(x)->m_deftype == ASR::deftypeType::Implementation ) { - - if (interactive) return; - - if (compiler_options.generate_object_code - && (ASRUtils::get_FunctionType(x)->m_abi == ASR::abiType::Intrinsic) - && !compiler_options.rtlib) { - // Skip intrinsic functions in generate_object_code mode - // They must be later linked - return; - } - - if (!prototype_only) { - define_function_entry(x); - - for (size_t i=0; ivisit_stmt(*x.m_body[i]); - } - - define_function_exit(x); - } - } else if( ASRUtils::get_FunctionType(x)->m_abi == ASR::abiType::Intrinsic && - ASRUtils::get_FunctionType(x)->m_deftype == ASR::deftypeType::Interface ) { - std::string m_name = x.m_name; - if( m_name == "lbound" || m_name == "ubound" ) { - define_function_entry(x); - - // Defines the size intrinsic's body at LLVM level. - ASR::Variable_t *arg = EXPR2VAR(x.m_args[0]); - uint32_t h = get_hash((ASR::asr_t*)arg); - llvm::Value* llvm_arg1 = llvm_symtab[h]; - - arg = EXPR2VAR(x.m_args[1]); - h = get_hash((ASR::asr_t*)arg); - llvm::Value* llvm_arg2 = llvm_symtab[h]; - - ASR::Variable_t *ret = EXPR2VAR(x.m_return_var); - h = get_hash((ASR::asr_t*)ret); - llvm::Value* llvm_ret_ptr = llvm_symtab[h]; - - llvm::Value* dim_des_val = CreateLoad(llvm_arg1); - llvm::Value* dim_val = CreateLoad(llvm_arg2); - llvm::Value* const_1 = llvm::ConstantInt::get(context, llvm::APInt(32, 1)); - dim_val = builder->CreateSub(dim_val, const_1); - llvm::Value* dim_struct = arr_descr->get_pointer_to_dimension_descriptor(dim_des_val, dim_val); - llvm::Value* res = nullptr; - if( m_name == "lbound" ) { - res = arr_descr->get_lower_bound(dim_struct); - } else if( m_name == "ubound" ) { - res = arr_descr->get_upper_bound(dim_struct); - } - builder->CreateStore(res, llvm_ret_ptr); - - define_function_exit(x); - } - } - } - - - template - void visit_procedures(const T &x) { - for (auto &item : x.m_symtab->get_scope()) { - if (is_a(*item.second)) { - ASR::Function_t *s = ASR::down_cast(item.second); - if (ASRUtils::get_FunctionType(s)->n_type_params == 0) { - visit_Function(*s); - } - } - } - } - - bool is_nested_pointer(llvm::Value* val) { - // TODO: Remove this in future - // Related issue, https://github.com/lcompilers/lpython/pull/707#issuecomment-1169773106. - return val->getType()->isPointerTy() && - val->getType()->getContainedType(0)->isPointerTy(); - } - - void visit_CLoc(const ASR::CLoc_t& x) { - int64_t ptr_loads_copy = ptr_loads; - ptr_loads = 0; - this->visit_expr(*x.m_arg); - ptr_loads = ptr_loads_copy; - if( is_nested_pointer(tmp) ) { - tmp = CreateLoad(tmp); - } - ASR::ttype_t* arg_type = ASRUtils::get_contained_type(ASRUtils::expr_type(x.m_arg)); - if( arr_descr->is_array(arg_type) ) { - tmp = CreateLoad(arr_descr->get_pointer_to_data(tmp)); - } - tmp = builder->CreateBitCast(tmp, - llvm::Type::getVoidTy(context)->getPointerTo()); - } - - - llvm::Value* GetPointerCPtrUtil(llvm::Value* llvm_tmp, ASR::ttype_t* asr_type) { - // If the input is a simple variable and not a pointer - // then this check will fail and load will not happen - // (which is what we want for simple variables). - // For pointers, the actual LLVM variable will be a - // double pointer, so we need to load one time and then - // use it later on. - if( is_nested_pointer(llvm_tmp) && - !ASR::is_a(*asr_type)) { - llvm_tmp = CreateLoad(llvm_tmp); - } - if( arr_descr->is_array(asr_type) && - !ASR::is_a(*asr_type) ) { - llvm_tmp = CreateLoad(arr_descr->get_pointer_to_data(llvm_tmp)); - } - - // // TODO: refactor this into a function, it is being used a few times - // llvm::Type *target_type = llvm_tmp->getType(); - // // Create alloca to get a pointer, but do it - // // at the beginning of the function to avoid - // // using alloca inside a loop, which would - // // run out of stack - // llvm::BasicBlock &entry_block = builder->GetInsertBlock()->getParent()->getEntryBlock(); - // llvm::IRBuilder<> builder0(context); - // builder0.SetInsertPoint(&entry_block, entry_block.getFirstInsertionPt()); - // llvm::AllocaInst *target = builder0.CreateAlloca( - // target_type, nullptr, "call_arg_value_ptr"); - // builder->CreateStore(llvm_tmp, target); - // llvm_tmp = target; - return llvm_tmp; - } - - void visit_GetPointer(const ASR::GetPointer_t& x) { - int64_t ptr_loads_copy = ptr_loads; - ptr_loads = 0; - this->visit_expr(*x.m_arg); - ptr_loads = ptr_loads_copy; - ASR::ttype_t* arg_type = ASRUtils::get_contained_type(ASRUtils::expr_type(x.m_arg)); - tmp = GetPointerCPtrUtil(tmp, arg_type); - } - - void visit_PointerToCPtr(const ASR::PointerToCPtr_t& x) { - int64_t ptr_loads_copy = ptr_loads; - ptr_loads = 0; - this->visit_expr(*x.m_arg); - ptr_loads = ptr_loads_copy; - if( !ASR::is_a(*x.m_arg) ) { - ASR::ttype_t* arg_type = ASRUtils::get_contained_type( - ASRUtils::expr_type(x.m_arg)); - tmp = GetPointerCPtrUtil(tmp, arg_type); - } - tmp = builder->CreateBitCast(tmp, - llvm::Type::getVoidTy(context)->getPointerTo()); - } - - - void visit_CPtrToPointer(const ASR::CPtrToPointer_t& x) { - ASR::expr_t *cptr = x.m_cptr, *fptr = x.m_ptr, *shape = x.m_shape; - int reduce_loads = 0; - if( ASR::is_a(*cptr) ) { - ASR::Variable_t* cptr_var = ASRUtils::EXPR2VAR(cptr); - reduce_loads = cptr_var->m_intent == ASRUtils::intent_in; - } - if( ASRUtils::is_array(ASRUtils::expr_type(fptr)) ) { - int64_t ptr_loads_copy = ptr_loads; - ptr_loads = 1 - reduce_loads; - this->visit_expr(*cptr); - llvm::Value* llvm_cptr = tmp; - ptr_loads = 0; - this->visit_expr(*fptr); - llvm::Value* llvm_fptr = tmp; - ptr_loads = ptr_loads_copy; - llvm::Value* llvm_shape = nullptr; - ASR::ttype_t* asr_shape_type = nullptr; - if( shape ) { - asr_shape_type = ASRUtils::get_contained_type(ASRUtils::expr_type(shape)); - this->visit_expr(*shape); - llvm_shape = tmp; - } - ASR::ttype_t* fptr_type = ASRUtils::expr_type(fptr); - llvm::Type* llvm_fptr_type = get_type_from_ttype_t_util(ASRUtils::get_contained_type(fptr_type)); - llvm::Value* fptr_array = builder->CreateAlloca(llvm_fptr_type); - ASR::dimension_t* fptr_dims; - int fptr_rank = ASRUtils::extract_dimensions_from_ttype( - ASRUtils::expr_type(fptr), - fptr_dims); - llvm::Value* llvm_rank = llvm::ConstantInt::get(context, llvm::APInt(32, fptr_rank)); - llvm::Value* dim_des = builder->CreateAlloca(arr_descr->get_dimension_descriptor_type(), llvm_rank); - builder->CreateStore(dim_des, arr_descr->get_pointer_to_dimension_descriptor_array(fptr_array, false)); - arr_descr->set_rank(fptr_array, llvm_rank); - builder->CreateStore(fptr_array, llvm_fptr); - llvm_fptr = fptr_array; - ASR::ttype_t* fptr_data_type = ASRUtils::duplicate_type_without_dims(al, ASRUtils::get_contained_type(fptr_type), fptr_type->base.loc); - llvm::Type* llvm_fptr_data_type = get_type_from_ttype_t_util(fptr_data_type); - llvm::Value* fptr_data = arr_descr->get_pointer_to_data(llvm_fptr); - llvm::Value* fptr_des = arr_descr->get_pointer_to_dimension_descriptor_array(llvm_fptr); - llvm::Value* shape_data = llvm_shape; - if( llvm_shape && !ASR::is_a(*shape) && arr_descr->is_array(asr_shape_type) ) { - shape_data = CreateLoad(arr_descr->get_pointer_to_data(llvm_shape)); - } - llvm_cptr = builder->CreateBitCast(llvm_cptr, llvm_fptr_data_type->getPointerTo()); - builder->CreateStore(llvm_cptr, fptr_data); - for( int i = 0; i < fptr_rank; i++ ) { - llvm::Value* curr_dim = llvm::ConstantInt::get(context, llvm::APInt(32, i)); - llvm::Value* desi = arr_descr->get_pointer_to_dimension_descriptor(fptr_des, curr_dim); - llvm::Value* desi_lb = arr_descr->get_lower_bound(desi, false); - llvm::Value* desi_size = arr_descr->get_dimension_size(fptr_des, curr_dim, false); - llvm::Value* i32_one = llvm::ConstantInt::get(context, llvm::APInt(32, 1)); - llvm::Value* new_lb = i32_one; - llvm::Value* new_ub = shape_data ? CreateLoad(llvm_utils->create_ptr_gep(shape_data, i)) : i32_one; - builder->CreateStore(new_lb, desi_lb); - builder->CreateStore(builder->CreateAdd(builder->CreateSub(new_ub, new_lb), i32_one), desi_size); - } - } else { - int64_t ptr_loads_copy = ptr_loads; - ptr_loads = 1 - reduce_loads; - this->visit_expr(*cptr); - llvm::Value* llvm_cptr = tmp; - ptr_loads = 0; - this->visit_expr(*fptr); - llvm::Value* llvm_fptr = tmp; - ptr_loads = ptr_loads_copy; - llvm::Type* llvm_fptr_type = get_type_from_ttype_t_util( - ASRUtils::get_contained_type(ASRUtils::expr_type(fptr))); - llvm_cptr = builder->CreateBitCast(llvm_cptr, llvm_fptr_type->getPointerTo()); - builder->CreateStore(llvm_cptr, llvm_fptr); - } - } - - void visit_Associate(const ASR::Associate_t& x) { - ASR::Variable_t *asr_target = EXPR2VAR(x.m_target); - ASR::Variable_t *asr_value = EXPR2VAR(x.m_value); - uint32_t value_h = get_hash((ASR::asr_t*)asr_value); - uint32_t target_h = get_hash((ASR::asr_t*)asr_target); - builder->CreateStore(llvm_symtab[value_h], llvm_symtab[target_h]); - } - - void visit_Assignment(const ASR::Assignment_t &x) { - if (compiler_options.emit_debug_info) debug_emit_loc(x); - if( x.m_overloaded ) { - this->visit_stmt(*x.m_overloaded); - return ; - } - - ASR::ttype_t* asr_target_type = ASRUtils::expr_type(x.m_target); - ASR::ttype_t* asr_value_type = ASRUtils::expr_type(x.m_value); - bool is_target_list = ASR::is_a(*asr_target_type); - bool is_value_list = ASR::is_a(*asr_value_type); - bool is_target_tuple = ASR::is_a(*asr_target_type); - bool is_value_tuple = ASR::is_a(*asr_value_type); - bool is_target_dict = ASR::is_a(*asr_target_type); - bool is_value_dict = ASR::is_a(*asr_value_type); - bool is_target_struct = ASR::is_a(*asr_target_type); - bool is_value_struct = ASR::is_a(*asr_value_type); - if( is_target_list && is_value_list ) { - int64_t ptr_loads_copy = ptr_loads; - ptr_loads = 0; - this->visit_expr(*x.m_target); - llvm::Value* target_list = tmp; - this->visit_expr(*x.m_value); - llvm::Value* value_list = tmp; - ptr_loads = ptr_loads_copy; - ASR::List_t* value_asr_list = ASR::down_cast( - ASRUtils::expr_type(x.m_value)); - std::string value_type_code = ASRUtils::get_type_code(value_asr_list->m_type); - list_api->list_deepcopy(value_list, target_list, - value_asr_list, module.get(), - name2memidx); - return ; - } else if( is_target_tuple && is_value_tuple ) { - int64_t ptr_loads_copy = ptr_loads; - if( ASR::is_a(*x.m_target) && - !ASR::is_a(*x.m_value) ) { - ptr_loads = 0; - this->visit_expr(*x.m_value); - llvm::Value* value_tuple = tmp; - ASR::TupleConstant_t* const_tuple = ASR::down_cast(x.m_target); - for( size_t i = 0; i < const_tuple->n_elements; i++ ) { - ptr_loads = 0; - visit_expr(*const_tuple->m_elements[i]); - llvm::Value* target_ptr = tmp; - llvm::Value* item = tuple_api->read_item(value_tuple, i, false); - builder->CreateStore(item, target_ptr); - } - ptr_loads = ptr_loads_copy; - } else if( ASR::is_a(*x.m_target) && - ASR::is_a(*x.m_value) ) { - ASR::TupleConstant_t* asr_value_tuple = ASR::down_cast(x.m_value); - Vec src_deepcopies; - src_deepcopies.reserve(al, asr_value_tuple->n_elements); - for( size_t i = 0; i < asr_value_tuple->n_elements; i++ ) { - ASR::ttype_t* asr_tuple_i_type = ASRUtils::expr_type(asr_value_tuple->m_elements[i]); - llvm::Type* llvm_tuple_i_type = get_type_from_ttype_t_util(asr_tuple_i_type); - llvm::Value* llvm_tuple_i = builder->CreateAlloca(llvm_tuple_i_type, nullptr); - ptr_loads = !LLVM::is_llvm_struct(asr_tuple_i_type); - visit_expr(*asr_value_tuple->m_elements[i]); - llvm_utils->deepcopy(tmp, llvm_tuple_i, asr_tuple_i_type, module.get(), name2memidx); - src_deepcopies.push_back(al, llvm_tuple_i); - } - ASR::TupleConstant_t* asr_target_tuple = ASR::down_cast(x.m_target); - for( size_t i = 0; i < asr_target_tuple->n_elements; i++ ) { - ptr_loads = 0; - visit_expr(*asr_target_tuple->m_elements[i]); - LLVM::CreateStore(*builder, - LLVM::CreateLoad(*builder, src_deepcopies[i]), - tmp - ); - } - ptr_loads = ptr_loads_copy; - } else { - ptr_loads = 0; - this->visit_expr(*x.m_value); - llvm::Value* value_tuple = tmp; - this->visit_expr(*x.m_target); - llvm::Value* target_tuple = tmp; - ptr_loads = ptr_loads_copy; - ASR::Tuple_t* value_tuple_type = ASR::down_cast(asr_value_type); - std::string type_code = ASRUtils::get_type_code(value_tuple_type->m_type, - value_tuple_type->n_type); - tuple_api->tuple_deepcopy(value_tuple, target_tuple, - value_tuple_type, module.get(), - name2memidx); - } - return ; - } else if( is_target_dict && is_value_dict ) { - int64_t ptr_loads_copy = ptr_loads; - ptr_loads = 0; - this->visit_expr(*x.m_value); - llvm::Value* value_dict = tmp; - this->visit_expr(*x.m_target); - llvm::Value* target_dict = tmp; - ptr_loads = ptr_loads_copy; - ASR::Dict_t* value_dict_type = ASR::down_cast(asr_value_type); - set_dict_api(value_dict_type); - llvm_utils->dict_api->dict_deepcopy(value_dict, target_dict, - value_dict_type, module.get(), name2memidx); - return ; - } else if( is_target_struct && is_value_struct ) { - int64_t ptr_loads_copy = ptr_loads; - ptr_loads = 0; - this->visit_expr(*x.m_value); - llvm::Value* value_struct = tmp; - bool is_assignment_target_copy = is_assignment_target; - is_assignment_target = true; - this->visit_expr(*x.m_target); - is_assignment_target = is_assignment_target_copy; - llvm::Value* target_struct = tmp; - ptr_loads = ptr_loads_copy; - llvm_utils->deepcopy(value_struct, target_struct, - asr_target_type, module.get(), name2memidx); - return ; - } - - if( ASR::is_a(*ASRUtils::expr_type(x.m_target)) && - ASR::is_a(*x.m_value) ) { - ASR::Variable_t *asr_target = EXPR2VAR(x.m_target); - ASR::GetPointer_t* get_ptr = ASR::down_cast(x.m_value); - ASR::Variable_t *asr_value = EXPR2VAR(get_ptr->m_arg); - uint32_t value_h = get_hash((ASR::asr_t*)asr_value); - uint32_t target_h = get_hash((ASR::asr_t*)asr_target); - builder->CreateStore(llvm_symtab[value_h], llvm_symtab[target_h]); - return ; - } - llvm::Value *target, *value; - uint32_t h; - bool lhs_is_string_arrayref = false; - if( x.m_target->type == ASR::exprType::ArrayItem || - x.m_target->type == ASR::exprType::ArraySection || - x.m_target->type == ASR::exprType::StructInstanceMember || - x.m_target->type == ASR::exprType::ListItem || - x.m_target->type == ASR::exprType::UnionInstanceMember ) { - is_assignment_target = true; - this->visit_expr(*x.m_target); - is_assignment_target = false; - target = tmp; - if (is_a(*x.m_target)) { - ASR::ArrayItem_t *asr_target0 = ASR::down_cast(x.m_target); - if (is_a(*asr_target0->m_v)) { - ASR::Variable_t *asr_target = ASRUtils::EXPR2VAR(asr_target0->m_v); - if ( is_a(*asr_target->m_type) ) { - ASR::Character_t *t = ASR::down_cast(asr_target->m_type); - if (t->n_dims == 0) { - target = CreateLoad(target); - lhs_is_string_arrayref = true; - } - } - } - } else if (is_a(*x.m_target)) { - ASR::ArraySection_t *asr_target0 = ASR::down_cast(x.m_target); - if (is_a(*asr_target0->m_v)) { - ASR::Variable_t *asr_target = ASRUtils::EXPR2VAR(asr_target0->m_v); - if ( is_a(*asr_target->m_type) ) { - ASR::Character_t *t = ASR::down_cast(asr_target->m_type); - if (t->n_dims == 0) { - target = CreateLoad(target); - lhs_is_string_arrayref = true; - } - } - } - } else if( ASR::is_a(*x.m_target) ) { - ASR::ListItem_t* asr_target0 = ASR::down_cast(x.m_target); - int64_t ptr_loads_copy = ptr_loads; - ptr_loads = 0; - this->visit_expr(*asr_target0->m_a); - ptr_loads = ptr_loads_copy; - llvm::Value* list = tmp; - this->visit_expr_wrapper(asr_target0->m_pos, true); - llvm::Value* pos = tmp; - - target = list_api->read_item(list, pos, compiler_options.enable_bounds_checking, - *module, true); - } - } else { - ASR::Variable_t *asr_target = EXPR2VAR(x.m_target); - h = get_hash((ASR::asr_t*)asr_target); - if (llvm_symtab.find(h) != llvm_symtab.end()) { - target = llvm_symtab[h]; - if (ASR::is_a(*asr_target->m_type) && - !ASR::is_a( - *ASR::down_cast(asr_target->m_type)->m_type)) { - target = CreateLoad(target); - } - } else { - /* Target for assignment not in the symbol table - must be - assigning to an outer scope from a nested function - see - nested_05.f90 */ - auto finder = std::find(nested_globals.begin(), - nested_globals.end(), h); - LCOMPILERS_ASSERT(finder != nested_globals.end()); - llvm::Value* ptr = module->getOrInsertGlobal(nested_desc_name, - nested_global_struct); - int idx = std::distance(nested_globals.begin(), finder); - target = CreateLoad(llvm_utils->create_gep(ptr, idx)); - } - if( arr_descr->is_array(ASRUtils::get_contained_type(asr_target_type)) ) { - if( asr_target->m_type->type == - ASR::ttypeType::Character ) { - target = CreateLoad(arr_descr->get_pointer_to_data(target)); - } - } - } - if( ASR::is_a(*x.m_value) ) { - return ; - } - ASR::ttype_t* target_type = ASRUtils::expr_type(x.m_target); - ASR::ttype_t* value_type = ASRUtils::expr_type(x.m_value); - this->visit_expr_wrapper(x.m_value, true); - if( ASR::is_a(*x.m_value) && - ASR::is_a(*value_type) ) { - tmp = LLVM::CreateLoad(*builder, tmp); - } - value = tmp; - if ( is_a(*expr_type(x.m_value)) ) { - ASR::Character_t *t = ASR::down_cast(expr_type(x.m_value)); - if (t->n_dims == 0) { - if (lhs_is_string_arrayref) { - value = CreateLoad(value); - } - } - } - if( ASRUtils::is_array(target_type) && - ASRUtils::is_array(value_type) && - ASRUtils::check_equal_type(target_type, value_type) ) { - bool data_only_copy = false; - bool is_target_data_only_array = ASRUtils::expr_abi(x.m_target) == ASR::abiType::BindC; - bool is_value_data_only_array = ASRUtils::expr_abi(x.m_value) == ASR::abiType::BindC; - if( is_target_data_only_array || is_value_data_only_array ) { - llvm::Value *target_data = nullptr, *value_data = nullptr, *llvm_size = nullptr; - if( is_target_data_only_array ) { - target_data = target; - ASR::dimension_t* target_dims = nullptr; - int target_ndims = ASRUtils::extract_dimensions_from_ttype(target_type, target_dims); - size_t target_size = 1; - data_only_copy = true; - for( int i = 0; i < target_ndims; i++ ) { - int dim_length = -1; - if( !ASRUtils::extract_value(ASRUtils::expr_value(target_dims[i].m_length), dim_length) ) { - data_only_copy = false; - break; - } - target_size *= dim_length; - } - if( data_only_copy ) { - llvm_size = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), - llvm::APInt(32, target_size)); - data_only_copy = false; - } - } else { - target_data = LLVM::CreateLoad(*builder, arr_descr->get_pointer_to_data(target)); - } - if( is_value_data_only_array ) { - value_data = value; - ASR::dimension_t* value_dims = nullptr; - int value_ndims = ASRUtils::extract_dimensions_from_ttype(value_type, value_dims); - size_t value_size = 1; - data_only_copy = true; - for( int i = 0; i < value_ndims; i++ ) { - int dim_length = -1; - if( !ASRUtils::extract_value(ASRUtils::expr_value(value_dims[i].m_length), dim_length) ) { - data_only_copy = false; - break; - } - value_size *= dim_length; - } - if( data_only_copy ) { - llvm_size = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), - llvm::APInt(32, value_size)); - data_only_copy = false; - } - } else { - value_data = LLVM::CreateLoad(*builder, arr_descr->get_pointer_to_data(value)); - } - if( llvm_size ) { - arr_descr->copy_array_data_only(value_data, target_data, module.get(), - target_type, llvm_size); - } - } else { - arr_descr->copy_array(value, target, module.get(), - target_type, false, false); - } - } else { - builder->CreateStore(value, target); - } - auto finder = std::find(nested_globals.begin(), - nested_globals.end(), h); - if (finder != nested_globals.end()) { - /* Target for assignment could be in the symbol table - and we are - assigning to a variable needed in a nested function - see - nested_04.f90 */ - llvm::Value* ptr = module->getOrInsertGlobal(nested_desc_name, - nested_global_struct); - int idx = std::distance(nested_globals.begin(), finder); - builder->CreateStore(target, llvm_utils->create_gep(ptr, idx)); - } - if (is_a(*x.m_target)) { - ASR::ArrayItem_t *asr_target0 = ASR::down_cast(x.m_target); - if (is_a(*asr_target0->m_v)) { - ASR::Variable_t *asr_target = ASRUtils::EXPR2VAR(asr_target0->m_v); - h = get_hash((ASR::asr_t*)asr_target); - auto finder = std::find(nested_globals.begin(), - nested_globals.end(), h); - if (finder != nested_globals.end()) { - // This is used since array pass use array item visit - llvm::Constant *ptr = module->getOrInsertGlobal(nested_desc_name, - nested_global_struct); - int idx = std::distance(nested_globals.begin(), finder); - std::vector idx_vec = { - llvm::ConstantInt::get(context, llvm::APInt(32, 0)), - llvm::ConstantInt::get(context, llvm::APInt(32, idx))}; - llvm::Value* array = CreateGEP(ptr, idx_vec); - std::vector indices; - for( size_t r = 0; r < asr_target0->n_args; r++ ) { - ASR::array_index_t curr_idx = asr_target0->m_args[r]; - uint64_t ptr_loads_copy = ptr_loads; - ptr_loads = 2; - this->visit_expr_wrapper(curr_idx.m_right, true); - ptr_loads = ptr_loads_copy; - indices.push_back(tmp); - } - ASR::dimension_t* m_dims; - ASRUtils::extract_dimensions_from_ttype( - ASRUtils::expr_type(asr_target0->m_v), m_dims); - Vec llvm_diminfo; - llvm_diminfo.reserve(al, 2 * asr_target0->n_args + 1); - for( size_t idim = 0; idim < asr_target0->n_args; idim++ ) { - this->visit_expr_wrapper(m_dims[idim].m_start, true); - llvm::Value* dim_start = tmp; - this->visit_expr_wrapper(m_dims[idim].m_length, true); - llvm::Value* dim_size = tmp; - llvm_diminfo.push_back(al, dim_start); - llvm_diminfo.push_back(al, dim_size); - } - tmp = arr_descr->get_single_element(array, indices, asr_target0->n_args, - true, false, llvm_diminfo.p); - builder->CreateStore(target, tmp); - } - } - } - } - - void visit_AssociateBlockCall(const ASR::AssociateBlockCall_t& x) { - LCOMPILERS_ASSERT(ASR::is_a(*x.m_m)); - ASR::AssociateBlock_t* associate_block = ASR::down_cast(x.m_m); - declare_vars(*associate_block); - for (size_t i = 0; i < associate_block->n_body; i++) { - this->visit_stmt(*(associate_block->m_body[i])); - } - } - - void visit_BlockCall(const ASR::BlockCall_t& x) { - /* The current `in_block` implementation has the following limitations: - * - Does not work for nested blocks. To fix it there, we should change - * it to an integer and keep incrementing it for each block. - * - Combining blocks and loops. - * - The label in `exit` is currently ignored, so we only jump to the - * inner most label. Instead we need to jump to the actual label - * provided. - */ - in_block = true; - if( x.m_label != -1 ) { - if( llvm_goto_targets.find(x.m_label) == llvm_goto_targets.end() ) { - llvm::BasicBlock *new_target = llvm::BasicBlock::Create(context, "goto_target"); - llvm_goto_targets[x.m_label] = new_target; - } - start_new_block(llvm_goto_targets[x.m_label]); - } - LCOMPILERS_ASSERT(ASR::is_a(*x.m_m)); - ASR::Block_t* block = ASR::down_cast(x.m_m); - declare_vars(*block); - std::string block_name = std::string(block->m_name); - std::string block_end_name = "block_"+block_name+"_end"; - llvm::BasicBlock *block_start = llvm::BasicBlock::Create(context, "block_"+block_name+"_start"); - start_new_block(block_start); - llvm::BasicBlock *block_end = llvm::BasicBlock::Create(context, "block_"+block_name+"_end"); - llvm::Function *fn = block_start->getParent(); - fn->getBasicBlockList().push_back(block_end); - builder->SetInsertPoint(block_start); - block_end_label = block_end; - for (size_t i = 0; i < block->n_body; i++) { - this->visit_stmt(*(block->m_body[i])); - } - llvm::BasicBlock *last_bb = builder->GetInsertBlock(); - llvm::Instruction *block_terminator = last_bb->getTerminator(); - if (block_terminator == nullptr) { - // The previous block is not terminated --- terminate it by jumping - // to block_end - builder->CreateBr(block_end); - } - builder->SetInsertPoint(block_end); - in_block=false; - } - - inline void visit_expr_wrapper(const ASR::expr_t* x, bool load_ref=false) { - this->visit_expr(*x); - if( x->type == ASR::exprType::ArrayItem || - x->type == ASR::exprType::ArraySection || - x->type == ASR::exprType::StructInstanceMember ) { - if( load_ref ) { - tmp = CreateLoad(tmp); - } - } - } - - void visit_IntegerCompare(const ASR::IntegerCompare_t &x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - this->visit_expr_wrapper(x.m_left, true); - llvm::Value *left = tmp; - this->visit_expr_wrapper(x.m_right, true); - llvm::Value *right = tmp; - switch (x.m_op) { - case (ASR::cmpopType::Eq) : { - tmp = builder->CreateICmpEQ(left, right); - break; - } - case (ASR::cmpopType::Gt) : { - tmp = builder->CreateICmpSGT(left, right); - break; - } - case (ASR::cmpopType::GtE) : { - tmp = builder->CreateICmpSGE(left, right); - break; - } - case (ASR::cmpopType::Lt) : { - tmp = builder->CreateICmpSLT(left, right); - break; - } - case (ASR::cmpopType::LtE) : { - tmp = builder->CreateICmpSLE(left, right); - break; - } - case (ASR::cmpopType::NotEq) : { - tmp = builder->CreateICmpNE(left, right); - break; - } - default : { - throw CodeGenError("Comparison operator not implemented", - x.base.base.loc); - } - } - } - - void visit_RealCompare(const ASR::RealCompare_t &x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - this->visit_expr_wrapper(x.m_left, true); - llvm::Value *left = tmp; - this->visit_expr_wrapper(x.m_right, true); - llvm::Value *right = tmp; - switch (x.m_op) { - case (ASR::cmpopType::Eq) : { - tmp = builder->CreateFCmpUEQ(left, right); - break; - } - case (ASR::cmpopType::Gt) : { - tmp = builder->CreateFCmpUGT(left, right); - break; - } - case (ASR::cmpopType::GtE) : { - tmp = builder->CreateFCmpUGE(left, right); - break; - } - case (ASR::cmpopType::Lt) : { - tmp = builder->CreateFCmpULT(left, right); - break; - } - case (ASR::cmpopType::LtE) : { - tmp = builder->CreateFCmpULE(left, right); - break; - } - case (ASR::cmpopType::NotEq) : { - tmp = builder->CreateFCmpUNE(left, right); - break; - } - default : { - throw CodeGenError("Comparison operator not implemented", - x.base.base.loc); - } - } - } - - void visit_ComplexCompare(const ASR::ComplexCompare_t &x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - this->visit_expr_wrapper(x.m_left, true); - llvm::Value *left = tmp; - this->visit_expr_wrapper(x.m_right, true); - llvm::Value *right = tmp; - llvm::Value* real_left = complex_re(left, left->getType()); - llvm::Value* real_right = complex_re(right, right->getType()); - llvm::Value* img_left = complex_im(left, left->getType()); - llvm::Value* img_right = complex_im(right, right->getType()); - llvm::Value *real_res, *img_res; - switch (x.m_op) { - case (ASR::cmpopType::Eq) : { - real_res = builder->CreateFCmpUEQ(real_left, real_right); - img_res = builder->CreateFCmpUEQ(img_left, img_right); - break; - } - case (ASR::cmpopType::NotEq) : { - real_res = builder->CreateFCmpUNE(real_left, real_right); - img_res = builder->CreateFCmpUNE(img_left, img_right); - break; - } - default : { - throw CodeGenError("Comparison operator not implemented", - x.base.base.loc); - } - } - tmp = builder->CreateAnd(real_res, img_res); - } - - void visit_StringCompare(const ASR::StringCompare_t &x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - this->visit_expr_wrapper(x.m_left, true); - llvm::Value *left = tmp; - this->visit_expr_wrapper(x.m_right, true); - llvm::Value *right = tmp; - std::string fn; - switch (x.m_op) { - case (ASR::cmpopType::Eq) : { - fn = "_lpython_str_compare_eq"; - break; - } - case (ASR::cmpopType::NotEq) : { - fn = "_lpython_str_compare_noteq"; - break; - } - case (ASR::cmpopType::Gt) : { - fn = "_lpython_str_compare_gt"; - break; - } - case (ASR::cmpopType::GtE) : { - fn = "_lpython_str_compare_gte"; - break; - } - case (ASR::cmpopType::Lt) : { - fn = "_lpython_str_compare_lt"; - break; - } - case (ASR::cmpopType::LtE) : { - fn = "_lpython_str_compare_lte"; - break; - } - default : { - throw CodeGenError("Comparison operator not implemented", - x.base.base.loc); - } - } - tmp = lfortran_str_cmp(left, right, fn); - } - - void visit_LogicalCompare(const ASR::LogicalCompare_t &x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - this->visit_expr_wrapper(x.m_left, true); - llvm::Value *left = tmp; - this->visit_expr_wrapper(x.m_right, true); - llvm::Value *right = tmp; - // i1 -> i32 - left = builder->CreateZExt(left, llvm::Type::getInt32Ty(context)); - right = builder->CreateZExt(right, llvm::Type::getInt32Ty(context)); - switch (x.m_op) { - case (ASR::cmpopType::Eq) : { - tmp = builder->CreateICmpEQ(left, right); - break; - } - case (ASR::cmpopType::NotEq) : { - tmp = builder->CreateICmpNE(left, right); - break; - } - case (ASR::cmpopType::Gt) : { - tmp = builder->CreateICmpUGT(left, right); - break; - } - case (ASR::cmpopType::GtE) : { - tmp = builder->CreateICmpUGE(left, right); - break; - } - case (ASR::cmpopType::Lt) : { - tmp = builder->CreateICmpULT(left, right); - break; - } - case (ASR::cmpopType::LtE) : { - tmp = builder->CreateICmpULE(left, right); - break; - } - default : { - throw CodeGenError("Comparison operator not implemented", - x.base.base.loc); - } - } - } - - void visit_OverloadedCompare(const ASR::OverloadedCompare_t &x) { - this->visit_expr(*x.m_overloaded); - } - - void visit_If(const ASR::If_t &x) { - this->visit_expr_wrapper(x.m_test, true); - create_if_else(tmp, [=]() { - for (size_t i=0; ivisit_stmt(*x.m_body[i]); - } - }, [=]() { - for (size_t i=0; ivisit_stmt(*x.m_orelse[i]); - } - }); - } - - void visit_IfExp(const ASR::IfExp_t &x) { - // IfExp(expr test, expr body, expr orelse, ttype type, expr? value) - this->visit_expr_wrapper(x.m_test, true); - llvm::Value *cond = tmp; - llvm::Value *then_val = nullptr; - llvm::Value *else_val = nullptr; - create_if_else(cond, [=, &then_val]() { - this->visit_expr_wrapper(x.m_body, true); - then_val = tmp; - }, [=, &else_val]() { - this->visit_expr_wrapper(x.m_orelse, true); - else_val = tmp; - }); - tmp = builder->CreateSelect(cond, then_val, else_val); - } - - void visit_WhileLoop(const ASR::WhileLoop_t &x) { - create_loop([=]() { - this->visit_expr_wrapper(x.m_test, true); - return tmp; - }, [=]() { - for (size_t i=0; ivisit_stmt(*x.m_body[i]); - } - }); - } - - void visit_Exit(const ASR::Exit_t & /* x */) { - if ( in_block ) { - // If we are in a block, we need to exit the block. - // This is done by jumping to the end of the block. - builder->CreateBr(block_end_label); - llvm::BasicBlock *bb = llvm::BasicBlock::Create(context, "unreachable_after_exit_block"); - start_new_block(bb); - } else { - builder->CreateBr(current_loopend); - llvm::BasicBlock *bb = llvm::BasicBlock::Create(context, "unreachable_after_exit"); - start_new_block(bb); - } - } - - void visit_Cycle(const ASR::Cycle_t & /* x */) { - builder->CreateBr(current_loophead); - llvm::BasicBlock *bb = llvm::BasicBlock::Create(context, "unreachable_after_cycle"); - start_new_block(bb); - } - - void visit_Return(const ASR::Return_t & /* x */) { - builder->CreateBr(proc_return); - llvm::BasicBlock *bb = llvm::BasicBlock::Create(context, "unreachable_after_return"); - start_new_block(bb); - } - - void visit_GoTo(const ASR::GoTo_t &x) { - if (llvm_goto_targets.find(x.m_target_id) == llvm_goto_targets.end()) { - // If the target does not exist yet, create it - llvm::BasicBlock *new_target = llvm::BasicBlock::Create(context, "goto_target"); - llvm_goto_targets[x.m_target_id] = new_target; - } - llvm::BasicBlock *target = llvm_goto_targets[x.m_target_id]; - builder->CreateBr(target); - llvm::BasicBlock *bb = llvm::BasicBlock::Create(context, "unreachable_after_goto"); - start_new_block(bb); - } - - void visit_GoToTarget(const ASR::GoToTarget_t &x) { - if (llvm_goto_targets.find(x.m_id) == llvm_goto_targets.end()) { - // If the target does not exist yet, create it - llvm::BasicBlock *new_target = llvm::BasicBlock::Create(context, "goto_target"); - llvm_goto_targets[x.m_id] = new_target; - } - llvm::BasicBlock *target = llvm_goto_targets[x.m_id]; - start_new_block(target); - } - - void visit_LogicalBinOp(const ASR::LogicalBinOp_t &x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - this->visit_expr_wrapper(x.m_left, true); - llvm::Value *left_val = tmp; - this->visit_expr_wrapper(x.m_right, true); - llvm::Value *right_val = tmp; - llvm::Value *zero, *cond; - llvm::AllocaInst *result; - if (ASRUtils::is_integer(*x.m_type)) { - int a_kind = down_cast(x.m_type)->m_kind; - int init_value_bits = 8*a_kind; - zero = llvm::ConstantInt::get(context, - llvm::APInt(init_value_bits, 0)); - cond = builder->CreateICmpEQ(left_val, zero); - result = builder->CreateAlloca(getIntType(a_kind), nullptr); - } else if (ASRUtils::is_real(*x.m_type)) { - int a_kind = down_cast(x.m_type)->m_kind; - int init_value_bits = 8*a_kind; - if (init_value_bits == 32) { - zero = llvm::ConstantFP::get(context, - llvm::APFloat((float)0)); - } else { - zero = llvm::ConstantFP::get(context, - llvm::APFloat((double)0)); - } - result = builder->CreateAlloca(getFPType(a_kind), nullptr); - cond = builder->CreateFCmpUEQ(left_val, zero); - } else if (ASRUtils::is_character(*x.m_type)) { - zero = llvm::Constant::getNullValue(character_type); - cond = lfortran_str_cmp(left_val, zero, "_lpython_str_compare_eq"); - result = builder->CreateAlloca(character_type, nullptr); - } else if (ASRUtils::is_logical(*x.m_type)) { - zero = llvm::ConstantInt::get(context, - llvm::APInt(1, 0)); - cond = builder->CreateICmpEQ(left_val, zero); - result = builder->CreateAlloca(llvm::Type::getInt1Ty(context), nullptr); - } else { - throw CodeGenError("Only Integer, Real, Strings and Logical types are supported " - "in logical binary operation.", x.base.base.loc); - } - switch (x.m_op) { - case ASR::logicalbinopType::And: { - create_if_else(cond, [&, result, left_val]() { - LLVM::CreateStore(*builder, left_val, result); - }, [&, result, right_val]() { - LLVM::CreateStore(*builder, right_val, result); - }); - tmp = LLVM::CreateLoad(*builder, result); - break; - }; - case ASR::logicalbinopType::Or: { - create_if_else(cond, [&, result, right_val]() { - LLVM::CreateStore(*builder, right_val, result); - - }, [&, result, left_val]() { - LLVM::CreateStore(*builder, left_val, result); - }); - tmp = LLVM::CreateLoad(*builder, result); - break; - }; - case ASR::logicalbinopType::Xor: { - tmp = builder->CreateXor(left_val, right_val); - break; - }; - case ASR::logicalbinopType::NEqv: { - tmp = builder->CreateXor(left_val, right_val); - break; - }; - case ASR::logicalbinopType::Eqv: { - tmp = builder->CreateXor(left_val, right_val); - tmp = builder->CreateNot(tmp); - }; - } - } - - void visit_StringRepeat(const ASR::StringRepeat_t &x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - this->visit_expr_wrapper(x.m_left, true); - llvm::Value *left_val = tmp; - this->visit_expr_wrapper(x.m_right, true); - llvm::Value *right_val = tmp; - tmp = lfortran_strrepeat(left_val, right_val); - } - - void visit_StringConcat(const ASR::StringConcat_t &x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - this->visit_expr_wrapper(x.m_left, true); - llvm::Value *left_val = tmp; - this->visit_expr_wrapper(x.m_right, true); - llvm::Value *right_val = tmp; - tmp = lfortran_strop(left_val, right_val, "_lfortran_strcat"); - } - - void visit_StringLen(const ASR::StringLen_t &x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - this->visit_expr_wrapper(x.m_arg, true); - llvm::AllocaInst *parg = builder->CreateAlloca(character_type, nullptr); - builder->CreateStore(tmp, parg); - tmp = lfortran_str_len(parg); - } - - void visit_StringOrd(const ASR::StringOrd_t &x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - this->visit_expr_wrapper(x.m_arg, true); - llvm::AllocaInst *parg = builder->CreateAlloca(character_type, nullptr); - builder->CreateStore(tmp, parg); - tmp = lfortran_str_ord(parg); - } - - void visit_StringChr(const ASR::StringChr_t &x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - this->visit_expr_wrapper(x.m_arg, true); - tmp = lfortran_str_chr(tmp); - } - - void visit_StringItem(const ASR::StringItem_t& x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - this->visit_expr_wrapper(x.m_idx, true); - llvm::Value *idx = tmp; - this->visit_expr_wrapper(x.m_arg, true); - llvm::Value *str = tmp; - tmp = lfortran_str_item(str, idx); - } - - void visit_StringSection(const ASR::StringSection_t& x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - this->visit_expr_wrapper(x.m_arg, true); - llvm::Value *str = tmp; - llvm::Value *left, *right, *step; - llvm::Value *left_present, *right_present; - if (x.m_start) { - this->visit_expr_wrapper(x.m_start, true); - left = tmp; - left_present = llvm::ConstantInt::get(context, - llvm::APInt(1, 1)); - } else { - left = llvm::Constant::getNullValue(llvm::Type::getInt32Ty(context)); - left_present = llvm::ConstantInt::get(context, - llvm::APInt(1, 0)); - } - if (x.m_end) { - this->visit_expr_wrapper(x.m_end, true); - right = tmp; - right_present = llvm::ConstantInt::get(context, - llvm::APInt(1, 1)); - } else { - right = llvm::Constant::getNullValue(llvm::Type::getInt32Ty(context)); - right_present = llvm::ConstantInt::get(context, - llvm::APInt(1, 0)); - } - if (x.m_step) { - this->visit_expr_wrapper(x.m_step, true); - step = tmp; - } else { - step = llvm::ConstantInt::get(context, - llvm::APInt(32, 1)); - } - tmp = lfortran_str_slice(str, left, right, step, left_present, right_present); - } - - void visit_IntegerBinOp(const ASR::IntegerBinOp_t &x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - this->visit_expr_wrapper(x.m_left, true); - llvm::Value *left_val = tmp; - this->visit_expr_wrapper(x.m_right, true); - llvm::Value *right_val = tmp; - LCOMPILERS_ASSERT(ASRUtils::is_integer(*x.m_type)) - switch (x.m_op) { - case ASR::binopType::Add: { - tmp = builder->CreateAdd(left_val, right_val); - break; - }; - case ASR::binopType::Sub: { - tmp = builder->CreateSub(left_val, right_val); - break; - }; - case ASR::binopType::Mul: { - tmp = builder->CreateMul(left_val, right_val); - break; - }; - case ASR::binopType::Div: { - tmp = builder->CreateUDiv(left_val, right_val); - break; - }; - case ASR::binopType::Pow: { - llvm::Type *type; - int a_kind; - a_kind = down_cast(ASRUtils::type_get_past_pointer(x.m_type))->m_kind; - type = getFPType(a_kind); - llvm::Value *fleft = builder->CreateSIToFP(left_val, - type); - llvm::Value *fright = builder->CreateSIToFP(right_val, - type); - std::string func_name = a_kind == 4 ? "llvm.pow.f32" : "llvm.pow.f64"; - llvm::Function *fn_pow = module->getFunction(func_name); - if (!fn_pow) { - llvm::FunctionType *function_type = llvm::FunctionType::get( - type, { type, type}, false); - fn_pow = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, func_name, - module.get()); - } - tmp = builder->CreateCall(fn_pow, {fleft, fright}); - type = getIntType(a_kind); - tmp = builder->CreateFPToSI(tmp, type); - break; - }; - case ASR::binopType::BitOr: { - tmp = builder->CreateOr(left_val, right_val); - break; - } - case ASR::binopType::BitAnd: { - tmp = builder->CreateAnd(left_val, right_val); - break; - } - case ASR::binopType::BitXor: { - tmp = builder->CreateXor(left_val, right_val); - break; - } - case ASR::binopType::BitLShift: { - tmp = builder->CreateShl(left_val, right_val); - break; - } - case ASR::binopType::BitRShift: { - tmp = builder->CreateAShr(left_val, right_val); - break; - } - } - } - - void visit_RealBinOp(const ASR::RealBinOp_t &x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - lookup_enum_value_for_nonints = true; - this->visit_expr_wrapper(x.m_left, true); - llvm::Value *left_val = tmp; - this->visit_expr_wrapper(x.m_right, true); - llvm::Value *right_val = tmp; - lookup_enum_value_for_nonints = false; - LCOMPILERS_ASSERT(ASRUtils::is_real(*x.m_type)) - switch (x.m_op) { - case ASR::binopType::Add: { - tmp = builder->CreateFAdd(left_val, right_val); - break; - }; - case ASR::binopType::Sub: { - tmp = builder->CreateFSub(left_val, right_val); - break; - }; - case ASR::binopType::Mul: { - tmp = builder->CreateFMul(left_val, right_val); - break; - }; - case ASR::binopType::Div: { - tmp = builder->CreateFDiv(left_val, right_val); - break; - }; - case ASR::binopType::Pow: { - llvm::Type *type; - int a_kind; - a_kind = down_cast(ASRUtils::type_get_past_pointer(x.m_type))->m_kind; - type = getFPType(a_kind); - std::string func_name = a_kind == 4 ? "llvm.pow.f32" : "llvm.pow.f64"; - llvm::Function *fn_pow = module->getFunction(func_name); - if (!fn_pow) { - llvm::FunctionType *function_type = llvm::FunctionType::get( - type, { type, type }, false); - fn_pow = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, func_name, - module.get()); - } - tmp = builder->CreateCall(fn_pow, {left_val, right_val}); - break; - }; - default: { - throw CodeGenError("Binary operator '" + ASRUtils::binop_to_str_python(x.m_op) + "' not supported", - x.base.base.loc); - } - } - } - - void visit_ComplexBinOp(const ASR::ComplexBinOp_t &x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - this->visit_expr_wrapper(x.m_left, true); - llvm::Value *left_val = tmp; - this->visit_expr_wrapper(x.m_right, true); - llvm::Value *right_val = tmp; - LCOMPILERS_ASSERT(ASRUtils::is_complex(*x.m_type)); - llvm::Type *type; - int a_kind; - a_kind = down_cast(ASRUtils::type_get_past_pointer(x.m_type))->m_kind; - type = getComplexType(a_kind); - if( left_val->getType()->isPointerTy() ) { - left_val = CreateLoad(left_val); - } - if( right_val->getType()->isPointerTy() ) { - right_val = CreateLoad(right_val); - } - std::string fn_name; - switch (x.m_op) { - case ASR::binopType::Add: { - if (a_kind == 4) { - fn_name = "_lfortran_complex_add_32"; - } else { - fn_name = "_lfortran_complex_add_64"; - } - break; - }; - case ASR::binopType::Sub: { - if (a_kind == 4) { - fn_name = "_lfortran_complex_sub_32"; - } else { - fn_name = "_lfortran_complex_sub_64"; - } - break; - }; - case ASR::binopType::Mul: { - if (a_kind == 4) { - fn_name = "_lfortran_complex_mul_32"; - } else { - fn_name = "_lfortran_complex_mul_64"; - } - break; - }; - case ASR::binopType::Div: { - if (a_kind == 4) { - fn_name = "_lfortran_complex_div_32"; - } else { - fn_name = "_lfortran_complex_div_64"; - } - break; - }; - case ASR::binopType::Pow: { - if (a_kind == 4) { - fn_name = "_lfortran_complex_pow_32"; - } else { - fn_name = "_lfortran_complex_pow_64"; - } - break; - }; - default: { - throw CodeGenError("Binary operator '" + ASRUtils::binop_to_str_python(x.m_op) + "' not supported", - x.base.base.loc); - } - } - tmp = lfortran_complex_bin_op(left_val, right_val, fn_name, type); - } - - void visit_OverloadedBinOp(const ASR::OverloadedBinOp_t &x) { - this->visit_expr(*x.m_overloaded); - } - - void visit_IntegerBitNot(const ASR::IntegerBitNot_t &x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - this->visit_expr_wrapper(x.m_arg, true); - tmp = builder->CreateNot(tmp); - } - - void visit_IntegerUnaryMinus(const ASR::IntegerUnaryMinus_t &x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - this->visit_expr_wrapper(x.m_arg, true); - llvm::Value *zero = llvm::ConstantInt::get(context, - llvm::APInt(ASRUtils::extract_kind_from_ttype_t(ASRUtils::expr_type(x.m_arg)) * 8, 0)); - tmp = builder->CreateSub(zero, tmp); - } - - void visit_RealUnaryMinus(const ASR::RealUnaryMinus_t &x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - this->visit_expr_wrapper(x.m_arg, true); - llvm::Value *zero; - int a_kind = down_cast(x.m_type)->m_kind; - if (a_kind == 4) { - zero = llvm::ConstantFP::get(context, - llvm::APFloat((float)0.0)); - } else if (a_kind == 8) { - zero = llvm::ConstantFP::get(context, - llvm::APFloat((double)0.0)); - } else { - throw CodeGenError("RealUnaryMinus: kind not supported yet"); - } - - tmp = builder->CreateFSub(zero, tmp); - } - - void visit_ComplexUnaryMinus(const ASR::ComplexUnaryMinus_t &x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - this->visit_expr_wrapper(x.m_arg, true); - llvm::Value *c = tmp; - double re = 0.0; - double im = 0.0; - llvm::Value *re2, *im2; - llvm::Type *type; - int a_kind = down_cast(x.m_type)->m_kind; - std::string f_name; - switch (a_kind) { - case 4: { - re2 = llvm::ConstantFP::get(context, llvm::APFloat((float)re)); - im2 = llvm::ConstantFP::get(context, llvm::APFloat((float)im)); - type = complex_type_4; - f_name = "_lfortran_complex_sub_32"; - break; - } - case 8: { - re2 = llvm::ConstantFP::get(context, llvm::APFloat(re)); - im2 = llvm::ConstantFP::get(context, llvm::APFloat(im)); - type = complex_type_8; - f_name = "_lfortran_complex_sub_64"; - break; - } - default: { - throw CodeGenError("kind type is not supported"); - } - } - tmp = complex_from_floats(re2, im2, type); - llvm::Value *zero_c = tmp; - tmp = lfortran_complex_bin_op(zero_c, c, f_name, type); - } - - void visit_IntegerConstant(const ASR::IntegerConstant_t &x) { - int64_t val = x.m_n; - int a_kind = ASRUtils::extract_kind_from_ttype_t(x.m_type); - switch( a_kind ) { - - case 1: { - tmp = llvm::ConstantInt::get(context, llvm::APInt(8, val, true)); - break ; - } - case 2: { - tmp = llvm::ConstantInt::get(context, llvm::APInt(16, val, true)); - break ; - } - case 4 : { - tmp = llvm::ConstantInt::get(context, llvm::APInt(32, static_cast(val), true)); - break; - } - case 8 : { - tmp = llvm::ConstantInt::get(context, llvm::APInt(64, val, true)); - break; - } - default : { - throw CodeGenError("Constant integers of " + std::to_string(a_kind) - + " bytes aren't supported yet."); - } - - } - } - - void visit_RealConstant(const ASR::RealConstant_t &x) { - double val = x.m_r; - int a_kind = ((ASR::Real_t*)(&(x.m_type->base)))->m_kind; - switch( a_kind ) { - - case 4 : { - tmp = llvm::ConstantFP::get(context, llvm::APFloat((float)val)); - break; - } - case 8 : { - tmp = llvm::ConstantFP::get(context, llvm::APFloat(val)); - break; - } - default : { - break; - } - - } - - } - - void visit_ArrayConstant(const ASR::ArrayConstant_t &x) { - llvm::Type* el_type; - if (ASR::is_a(*x.m_type)) { - el_type = getIntType(ASR::down_cast(x.m_type)->m_kind); - } else if (ASR::is_a(*x.m_type)) { - switch (ASR::down_cast(x.m_type)->m_kind) { - case (4) : - el_type = llvm::Type::getFloatTy(context); break; - case (8) : - el_type = llvm::Type::getDoubleTy(context); break; - default : - throw CodeGenError("ConstArray real kind not supported yet"); - } - } else if (ASR::is_a(*x.m_type)) { - el_type = llvm::Type::getInt1Ty(context); - } else { - throw CodeGenError("ConstArray type not supported yet"); - } - // Create type, where `n` is the length of the `x` constant array - llvm::Type* type_fxn = FIXED_VECTOR_TYPE::get(el_type, x.n_args); - // Create a pointer * to a stack allocated - llvm::AllocaInst *p_fxn = builder->CreateAlloca(type_fxn, nullptr); - // Assign the array elements to `p_fxn`. - for (size_t i=0; i < x.n_args; i++) { - llvm::Value *llvm_el = llvm_utils->create_gep(p_fxn, i); - ASR::expr_t *el = x.m_args[i]; - llvm::Value *llvm_val; - if (ASR::is_a(*x.m_type)) { - ASR::IntegerConstant_t *ci = ASR::down_cast(el); - switch (ASR::down_cast(x.m_type)->m_kind) { - case (4) : { - int32_t el_value = ci->m_n; - llvm_val = llvm::ConstantInt::get(context, llvm::APInt(32, static_cast(el_value), true)); - break; - } - case (8) : { - int64_t el_value = ci->m_n; - llvm_val = llvm::ConstantInt::get(context, llvm::APInt(32, el_value, true)); - break; - } - default : - throw CodeGenError("ConstArray integer kind not supported yet"); - } - } else if (ASR::is_a(*x.m_type)) { - ASR::RealConstant_t *cr = ASR::down_cast(el); - switch (ASR::down_cast(x.m_type)->m_kind) { - case (4) : { - float el_value = cr->m_r; - llvm_val = llvm::ConstantFP::get(context, llvm::APFloat(el_value)); - break; - } - case (8) : { - double el_value = cr->m_r; - llvm_val = llvm::ConstantFP::get(context, llvm::APFloat(el_value)); - break; - } - default : - throw CodeGenError("ConstArray real kind not supported yet"); - } - } else if (ASR::is_a(*x.m_type)) { - ASR::LogicalConstant_t *cr = ASR::down_cast(el); - llvm_val = llvm::ConstantInt::get(context, llvm::APInt(1, cr->m_value)); - } else { - throw CodeGenError("ConstArray type not supported yet"); - } - builder->CreateStore(llvm_val, llvm_el); - } - // Return the vector as float* type: - tmp = llvm_utils->create_gep(p_fxn, 0); - } - - void visit_Assert(const ASR::Assert_t &x) { - if (compiler_options.emit_debug_info) debug_emit_loc(x); - this->visit_expr_wrapper(x.m_test, true); - create_if_else(tmp, []() {}, [=]() { - if (compiler_options.emit_debug_info) { - llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr(infile); - llvm::Value *fmt_ptr1 = llvm::ConstantInt::get(context, llvm::APInt( - 1, compiler_options.use_colors)); - call_print_stacktrace_addresses(context, *module, *builder, - {fmt_ptr, fmt_ptr1}); - } - if (x.m_msg) { - char* s = ASR::down_cast(x.m_msg)->m_s; - llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr("AssertionError: %s\n"); - llvm::Value *fmt_ptr2 = builder->CreateGlobalStringPtr(s); - print_error(context, *module, *builder, {fmt_ptr, fmt_ptr2}); - } else { - llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr("AssertionError\n"); - print_error(context, *module, *builder, {fmt_ptr}); - } - int exit_code_int = 1; - llvm::Value *exit_code = llvm::ConstantInt::get(context, - llvm::APInt(32, exit_code_int)); - exit(context, *module, *builder, exit_code); - }); - } - - void visit_ComplexConstructor(const ASR::ComplexConstructor_t &x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - throw CodeGenError("ComplexConstructor with runtime arguments not implemented yet."); - } - - void visit_ComplexConstant(const ASR::ComplexConstant_t &x) { - double re = x.m_re; - double im = x.m_im; - int a_kind = ASRUtils::extract_kind_from_ttype_t(x.m_type); - llvm::Value *re2, *im2; - llvm::Type *type; - switch( a_kind ) { - case 4: { - re2 = llvm::ConstantFP::get(context, llvm::APFloat((float)re)); - im2 = llvm::ConstantFP::get(context, llvm::APFloat((float)im)); - type = complex_type_4; - break; - } - case 8: { - re2 = llvm::ConstantFP::get(context, llvm::APFloat(re)); - im2 = llvm::ConstantFP::get(context, llvm::APFloat(im)); - type = complex_type_8; - break; - } - default: { - throw CodeGenError("kind type is not supported"); - } - } - tmp = complex_from_floats(re2, im2, type); - } - - void visit_LogicalConstant(const ASR::LogicalConstant_t &x) { - int val; - if (x.m_value == true) { - val = 1; - } else { - val = 0; - } - tmp = llvm::ConstantInt::get(context, llvm::APInt(1, val)); - } - - void visit_LogicalNot(const ASR::LogicalNot_t &x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - this->visit_expr_wrapper(x.m_arg, true); - llvm::Value *arg = tmp; - tmp = builder->CreateNot(arg); - } - - void visit_StringConstant(const ASR::StringConstant_t &x) { - std::string s = unescape_string(al, x.m_s); - tmp = builder->CreateGlobalStringPtr(s); - } - - inline void fetch_ptr(ASR::Variable_t* x) { - uint32_t x_h = get_hash((ASR::asr_t*)x); - LCOMPILERS_ASSERT(llvm_symtab.find(x_h) != llvm_symtab.end()); - llvm::Value* x_v = llvm_symtab[x_h]; - int64_t ptr_loads_copy = ptr_loads; - tmp = x_v; - while( ptr_loads_copy-- ) { - tmp = CreateLoad(tmp); - } - } - - inline void fetch_val(ASR::Variable_t* x) { - uint32_t x_h = get_hash((ASR::asr_t*)x); - llvm::Value* x_v; - // Check if x is a needed global here, if so, it should exist as an - // element in the runtime descriptor, get element pointer and create - // load - if (llvm_symtab.find(x_h) == llvm_symtab.end()) { - LCOMPILERS_ASSERT(std::find(nested_globals.begin(), - nested_globals.end(), x_h) != nested_globals.end()); - auto finder = std::find(nested_globals.begin(), - nested_globals.end(), x_h); - llvm::Constant *ptr = module->getOrInsertGlobal(nested_desc_name, - nested_global_struct); - int idx = std::distance(nested_globals.begin(), finder); - std::vector idx_vec = { - llvm::ConstantInt::get(context, llvm::APInt(32, 0)), - llvm::ConstantInt::get(context, llvm::APInt(32, idx))}; - x_v = CreateLoad(CreateGEP(ptr, idx_vec)); - } else { - x_v = llvm_symtab[x_h]; - if (x->m_value_attr) { - // Already a value, such as value argument to bind(c) - tmp = x_v; - return; - } - } - if( arr_descr->is_array(ASRUtils::get_contained_type(x->m_type)) ) { - tmp = x_v; - } else { - tmp = x_v; - // Load only once since its a value - if( ptr_loads > 0 ) { - tmp = CreateLoad(tmp); - } - } - } - - inline void fetch_var(ASR::Variable_t* x) { - if (x->m_value) { - this->visit_expr_wrapper(x->m_value, true); - return; - } - switch( x->m_type->type ) { - case ASR::ttypeType::Pointer: { - ASR::ttype_t *t2 = ASRUtils::type_get_past_pointer(x->m_type); - switch (t2->type) { - case ASR::ttypeType::Integer: - case ASR::ttypeType::Real: - case ASR::ttypeType::Complex: - case ASR::ttypeType::Struct: { - if( t2->type == ASR::ttypeType::Struct ) { - ASR::Struct_t* d = ASR::down_cast(t2); - der_type_name = ASRUtils::symbol_name(d->m_derived_type); - } - fetch_ptr(x); - break; - } - case ASR::ttypeType::Character: - case ASR::ttypeType::Logical: { - break; - } - default: - break; - } - break; - } - case ASR::ttypeType::Struct: { - ASR::Struct_t* der = ASR::down_cast(x->m_type); - ASR::StructType_t* der_type = ASR::down_cast( - ASRUtils::symbol_get_past_external(der->m_derived_type)); - der_type_name = std::string(der_type->m_name); - uint32_t h = get_hash((ASR::asr_t*)x); - if( llvm_symtab.find(h) != llvm_symtab.end() ) { - tmp = llvm_symtab[h]; - } - break; - } - case ASR::ttypeType::Union: { - ASR::Union_t* der = ASR::down_cast(x->m_type); - ASR::UnionType_t* der_type = ASR::down_cast( - ASRUtils::symbol_get_past_external(der->m_union_type)); - der_type_name = std::string(der_type->m_name); - uint32_t h = get_hash((ASR::asr_t*)x); - if( llvm_symtab.find(h) != llvm_symtab.end() ) { - tmp = llvm_symtab[h]; - } - break; - } - case ASR::ttypeType::Class: { - ASR::Class_t* der = ASR::down_cast(x->m_type); - ASR::ClassType_t* der_type = ASR::down_cast( - ASRUtils::symbol_get_past_external(der->m_class_type)); - der_type_name = std::string(der_type->m_name); - uint32_t h = get_hash((ASR::asr_t*)x); - if( llvm_symtab.find(h) != llvm_symtab.end() ) { - tmp = llvm_symtab[h]; - } - break; - } - default: { - fetch_val(x); - break; - } - } - } - - void visit_Var(const ASR::Var_t &x) { - ASR::Variable_t *v = ASR::down_cast( - symbol_get_past_external(x.m_v)); - fetch_var(v); - } - - inline ASR::ttype_t* extract_ttype_t_from_expr(ASR::expr_t* expr) { - return ASRUtils::expr_type(expr); - } - - void extract_kinds(const ASR::Cast_t& x, - int& arg_kind, int& dest_kind) - { - dest_kind = ASRUtils::extract_kind_from_ttype_t(x.m_type); - ASR::ttype_t* curr_type = extract_ttype_t_from_expr(x.m_arg); - LCOMPILERS_ASSERT(curr_type != nullptr) - arg_kind = ASRUtils::extract_kind_from_ttype_t(curr_type); - } - - void visit_ComplexRe(const ASR::ComplexRe_t &x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - this->visit_expr_wrapper(x.m_arg, true); - ASR::ttype_t* curr_type = extract_ttype_t_from_expr(x.m_arg); - int arg_kind = ASRUtils::extract_kind_from_ttype_t(curr_type); - int dest_kind = ASRUtils::extract_kind_from_ttype_t(x.m_type); - llvm::Value *re; - if (arg_kind == 4 && dest_kind == 4) { - // complex(4) -> real(4) - re = complex_re(tmp, complex_type_4); - tmp = re; - } else if (arg_kind == 4 && dest_kind == 8) { - // complex(4) -> real(8) - re = complex_re(tmp, complex_type_4); - tmp = builder->CreateFPExt(re, llvm::Type::getDoubleTy(context)); - } else if (arg_kind == 8 && dest_kind == 4) { - // complex(8) -> real(4) - re = complex_re(tmp, complex_type_8); - tmp = builder->CreateFPTrunc(re, llvm::Type::getFloatTy(context)); - } else if (arg_kind == 8 && dest_kind == 8) { - // complex(8) -> real(8) - re = complex_re(tmp, complex_type_8); - tmp = re; - } else { - std::string msg = "Conversion from " + std::to_string(arg_kind) + - " to " + std::to_string(dest_kind) + " not implemented yet."; - throw CodeGenError(msg); - } - } - - void visit_ComplexIm(const ASR::ComplexIm_t &x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - ASR::ttype_t* curr_type = extract_ttype_t_from_expr(x.m_arg); - int arg_kind = ASRUtils::extract_kind_from_ttype_t(curr_type); - llvm::Function *fn = nullptr; - llvm::Type *ret_type = nullptr, *complex_type = nullptr; - llvm::AllocaInst *arg = nullptr; - std::string runtime_func_name = ""; - if (arg_kind == 4) { - runtime_func_name = "_lfortran_complex_aimag_32"; - ret_type = llvm::Type::getFloatTy(context); - complex_type = complex_type_4; - arg = builder->CreateAlloca(complex_type_4, - nullptr); - } else { - runtime_func_name = "_lfortran_complex_aimag_64"; - ret_type = llvm::Type::getDoubleTy(context); - complex_type = complex_type_8; - arg = builder->CreateAlloca(complex_type_8, - nullptr); - } - fn = module->getFunction(runtime_func_name); - if (!fn) { - llvm::FunctionType *function_type = llvm::FunctionType::get( - llvm::Type::getVoidTy(context), { - complex_type->getPointerTo(), - ret_type->getPointerTo(), - }, true); - fn = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, runtime_func_name, *module); - } - this->visit_expr_wrapper(x.m_arg, true); - builder->CreateStore(tmp, arg); - llvm::AllocaInst *result = builder->CreateAlloca(ret_type, nullptr); - std::vector args = {arg, result}; - builder->CreateCall(fn, args); - tmp = CreateLoad(result); - } - - void visit_Cast(const ASR::Cast_t &x) { - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - this->visit_expr_wrapper(x.m_arg, true); - switch (x.m_kind) { - case (ASR::cast_kindType::IntegerToReal) : { - int a_kind = ASRUtils::extract_kind_from_ttype_t(x.m_type); - tmp = builder->CreateSIToFP(tmp, getFPType(a_kind, false)); - break; - } - case (ASR::cast_kindType::LogicalToReal) : { - int a_kind = ASRUtils::extract_kind_from_ttype_t(x.m_type); - tmp = builder->CreateUIToFP(tmp, getFPType(a_kind, false)); - break; - } - case (ASR::cast_kindType::RealToInteger) : { - llvm::Type *target_type; - int a_kind = ASRUtils::extract_kind_from_ttype_t(x.m_type); - target_type = getIntType(a_kind); - tmp = builder->CreateFPToSI(tmp, target_type); - break; - } - case (ASR::cast_kindType::RealToComplex) : { - llvm::Type *target_type; - llvm::Value *zero; - int a_kind = ASRUtils::extract_kind_from_ttype_t(x.m_type); - switch(a_kind) - { - case 4: - target_type = complex_type_4; - tmp = builder->CreateFPTrunc(tmp, llvm::Type::getFloatTy(context)); - zero = llvm::ConstantFP::get(context, llvm::APFloat((float)0.0)); - break; - case 8: - target_type = complex_type_8; - tmp = builder->CreateFPExt(tmp, llvm::Type::getDoubleTy(context)); - zero = llvm::ConstantFP::get(context, llvm::APFloat(0.0)); - break; - default: - throw CodeGenError("Only 32 and 64 bits real kinds are supported."); - } - tmp = complex_from_floats(tmp, zero, target_type); - break; - } - case (ASR::cast_kindType::IntegerToComplex) : { - int a_kind = ASRUtils::extract_kind_from_ttype_t(x.m_type); - llvm::Type *target_type; - llvm::Type *complex_type; - llvm::Value *zero; - switch(a_kind) - { - case 4: - target_type = llvm::Type::getFloatTy(context); - complex_type = complex_type_4; - zero = llvm::ConstantFP::get(context, llvm::APFloat((float)0.0)); - break; - case 8: - target_type = llvm::Type::getDoubleTy(context); - complex_type = complex_type_8; - zero = llvm::ConstantFP::get(context, llvm::APFloat(0.0)); - break; - default: - throw CodeGenError("Only 32 and 64 bits real kinds are supported."); - } - tmp = builder->CreateSIToFP(tmp, target_type); - tmp = complex_from_floats(tmp, zero, complex_type); - break; - } - case (ASR::cast_kindType::IntegerToLogical) : { - ASR::ttype_t* curr_type = extract_ttype_t_from_expr(x.m_arg); - LCOMPILERS_ASSERT(curr_type != nullptr) - int a_kind = ASRUtils::extract_kind_from_ttype_t(curr_type); - switch (a_kind) { - case 1: - tmp = builder->CreateICmpNE(tmp, builder->getInt8(0)); - break; - case 2: - tmp = builder->CreateICmpNE(tmp, builder->getInt16(0)); - break; - case 4: - tmp = builder->CreateICmpNE(tmp, builder->getInt32(0)); - break; - case 8: - tmp = builder->CreateICmpNE(tmp, builder->getInt64(0)); - break; - } - break; - } - case (ASR::cast_kindType::RealToLogical) : { - llvm::Value *zero; - ASR::ttype_t* curr_type = extract_ttype_t_from_expr(x.m_arg); - LCOMPILERS_ASSERT(curr_type != nullptr) - int a_kind = ASRUtils::extract_kind_from_ttype_t(curr_type); - if (a_kind == 4) { - zero = llvm::ConstantFP::get(context, llvm::APFloat((float)0.0)); - } else { - zero = llvm::ConstantFP::get(context, llvm::APFloat(0.0)); - } - tmp = builder->CreateFCmpUNE(tmp, zero); - break; - } - case (ASR::cast_kindType::CharacterToLogical) : { - llvm::AllocaInst *parg = builder->CreateAlloca(character_type, nullptr); - builder->CreateStore(tmp, parg); - tmp = builder->CreateICmpNE(lfortran_str_len(parg), builder->getInt32(0)); - break; - } - case (ASR::cast_kindType::CharacterToInteger) : { - llvm::AllocaInst *parg = builder->CreateAlloca(character_type, nullptr); - builder->CreateStore(tmp, parg); - tmp = lfortran_str_to_int(parg); - break; - } - case (ASR::cast_kindType::ComplexToLogical) : { - // !(c.real == 0.0 && c.imag == 0.0) - llvm::Value *zero; - ASR::ttype_t* curr_type = extract_ttype_t_from_expr(x.m_arg); - LCOMPILERS_ASSERT(curr_type != nullptr) - int a_kind = ASRUtils::extract_kind_from_ttype_t(curr_type); - if (a_kind == 4) { - zero = llvm::ConstantFP::get(context, llvm::APFloat((float)0.0)); - } else { - zero = llvm::ConstantFP::get(context, llvm::APFloat(0.0)); - } - llvm::Value *c_real = complex_re(tmp, tmp->getType()); - llvm::Value *real_check = builder->CreateFCmpUEQ(c_real, zero); - llvm::Value *c_imag = complex_im(tmp, tmp->getType()); - llvm::Value *imag_check = builder->CreateFCmpUEQ(c_imag, zero); - tmp = builder->CreateAnd(real_check, imag_check); - tmp = builder->CreateNot(tmp); - break; - } - case (ASR::cast_kindType::LogicalToInteger) : { - int a_kind = ASRUtils::extract_kind_from_ttype_t(x.m_type); - tmp = builder->CreateZExt(tmp, getIntType(a_kind)); - break; - } - case (ASR::cast_kindType::RealToReal) : { - int arg_kind = -1, dest_kind = -1; - extract_kinds(x, arg_kind, dest_kind); - if( arg_kind > 0 && dest_kind > 0 && - arg_kind != dest_kind ) - { - if( arg_kind == 4 && dest_kind == 8 ) { - tmp = builder->CreateFPExt(tmp, llvm::Type::getDoubleTy(context)); - } else if( arg_kind == 8 && dest_kind == 4 ) { - tmp = builder->CreateFPTrunc(tmp, llvm::Type::getFloatTy(context)); - } else { - std::string msg = "Conversion from " + std::to_string(arg_kind) + - " to " + std::to_string(dest_kind) + " not implemented yet."; - throw CodeGenError(msg); - } - } - break; - } - case (ASR::cast_kindType::IntegerToInteger) : { - int arg_kind = -1, dest_kind = -1; - extract_kinds(x, arg_kind, dest_kind); - if( arg_kind > 0 && dest_kind > 0 && - arg_kind != dest_kind ) - { - if (dest_kind > arg_kind) { - tmp = builder->CreateSExt(tmp, getIntType(dest_kind)); - } else { - tmp = builder->CreateTrunc(tmp, getIntType(dest_kind)); - } - } - break; - } - case (ASR::cast_kindType::ComplexToComplex) : { - llvm::Type *target_type; - int arg_kind = -1, dest_kind = -1; - extract_kinds(x, arg_kind, dest_kind); - llvm::Value *re, *im; - if( arg_kind > 0 && dest_kind > 0 && - arg_kind != dest_kind ) - { - if( arg_kind == 4 && dest_kind == 8 ) { - target_type = complex_type_8; - re = complex_re(tmp, complex_type_4); - re = builder->CreateFPExt(re, llvm::Type::getDoubleTy(context)); - im = complex_im(tmp, complex_type_4); - im = builder->CreateFPExt(im, llvm::Type::getDoubleTy(context)); - } else if( arg_kind == 8 && dest_kind == 4 ) { - target_type = complex_type_4; - re = complex_re(tmp, complex_type_8); - re = builder->CreateFPTrunc(re, llvm::Type::getFloatTy(context)); - im = complex_im(tmp, complex_type_8); - im = builder->CreateFPTrunc(im, llvm::Type::getFloatTy(context)); - } else { - std::string msg = "Conversion from " + std::to_string(arg_kind) + - " to " + std::to_string(dest_kind) + " not implemented yet."; - throw CodeGenError(msg); - } - } else { - throw CodeGenError("Negative kinds are not supported."); - } - tmp = complex_from_floats(re, im, target_type); - break; - } - case (ASR::cast_kindType::ComplexToReal) : { - int arg_kind = -1, dest_kind = -1; - extract_kinds(x, arg_kind, dest_kind); - llvm::Value *re; - if( arg_kind > 0 && dest_kind > 0) - { - if( arg_kind == 4 && dest_kind == 4 ) { - // complex(4) -> real(4) - re = complex_re(tmp, complex_type_4); - tmp = re; - } else if( arg_kind == 4 && dest_kind == 8 ) { - // complex(4) -> real(8) - re = complex_re(tmp, complex_type_4); - tmp = builder->CreateFPExt(re, llvm::Type::getDoubleTy(context)); - } else if( arg_kind == 8 && dest_kind == 4 ) { - // complex(8) -> real(4) - re = complex_re(tmp, complex_type_8); - tmp = builder->CreateFPTrunc(re, llvm::Type::getFloatTy(context)); - } else if( arg_kind == 8 && dest_kind == 8 ) { - // complex(8) -> real(8) - re = complex_re(tmp, complex_type_8); - tmp = re; - } else { - std::string msg = "Conversion from " + std::to_string(arg_kind) + - " to " + std::to_string(dest_kind) + " not implemented yet."; - throw CodeGenError(msg); - } - } else { - throw CodeGenError("Negative kinds are not supported."); - } - break; - } - case (ASR::cast_kindType::ComplexToInteger) : { - int arg_kind = -1, dest_kind = -1; - extract_kinds(x, arg_kind, dest_kind); - llvm::Value *re; - if (arg_kind > 0 && dest_kind > 0) - { - if (arg_kind == 4) { - // complex(4) -> real(8) - re = complex_re(tmp, complex_type_4); - tmp = re; - } else if (arg_kind == 8) { - // complex(8) -> real(8) - re = complex_re(tmp, complex_type_8); - tmp = re; - } else { - std::string msg = "Unsupported Complex type kind: " + std::to_string(arg_kind); - throw CodeGenError(msg); - } - llvm::Type *target_type; - target_type = getIntType(dest_kind); - tmp = builder->CreateFPToSI(tmp, target_type); - } else { - throw CodeGenError("Negative kinds are not supported."); - } - break; - } - case (ASR::cast_kindType::RealToCharacter) : { - llvm::Value *arg = tmp; - ASR::ttype_t* arg_type = extract_ttype_t_from_expr(x.m_arg); - LCOMPILERS_ASSERT(arg_type != nullptr) - int arg_kind = ASRUtils::extract_kind_from_ttype_t(arg_type); - tmp = lfortran_type_to_str(arg, getFPType(arg_kind), "float", arg_kind); - break; - } - case (ASR::cast_kindType::IntegerToCharacter) : { - llvm::Value *arg = tmp; - ASR::ttype_t* arg_type = extract_ttype_t_from_expr(x.m_arg); - LCOMPILERS_ASSERT(arg_type != nullptr) - int arg_kind = ASRUtils::extract_kind_from_ttype_t(arg_type); - tmp = lfortran_type_to_str(arg, getIntType(arg_kind), "int", arg_kind); - break; - } - case (ASR::cast_kindType::LogicalToCharacter) : { - llvm::Value *cmp = builder->CreateICmpEQ(tmp, builder->getInt1(0)); - llvm::Value *zero_str = builder->CreateGlobalStringPtr("False"); - llvm::Value *one_str = builder->CreateGlobalStringPtr("True"); - tmp = builder->CreateSelect(cmp, zero_str, one_str); - break; - } - default : throw CodeGenError("Cast kind not implemented"); - } - } - - void visit_FileRead(const ASR::FileRead_t &x) { - if (x.m_fmt != nullptr) { - diag.codegen_warning_label("format string in read() is not implemented yet and it is currently treated as '*'", - {x.m_fmt->base.loc}, "treated as '*'"); - } - if (x.m_unit != nullptr) { - diag.codegen_error_label("unit in read() is not implemented yet", - {x.m_unit->base.loc}, "not implemented"); - throw CodeGenAbort(); - } - diag.codegen_error_label("The intrinsic function read() is not implemented yet in the LLVM backend", - {x.base.base.loc}, "not implemented"); - throw CodeGenAbort(); - } - - void visit_Print(const ASR::Print_t &x) { - if (x.m_fmt != nullptr) { - diag.codegen_warning_label("format string in `print` is not implemented yet and it is currently treated as '*'", - {x.m_fmt->base.loc}, "treated as '*'"); - } - handle_print(x); - } - - void visit_FileWrite(const ASR::FileWrite_t &x) { - if (x.m_fmt != nullptr) { - diag.codegen_warning_label("format string in write() is not implemented yet and it is currently treated as '*'", - {x.m_fmt->base.loc}, "treated as '*'"); - } - if (x.m_unit != nullptr) { - diag.codegen_warning_label("unit in write() is not implemented yet and it is currently treated as '*'", - {x.m_unit->base.loc}, "treated as '*'"); - } - handle_print(x); - } - - template - void handle_print(const T &x) { - std::vector args; - std::vector fmt; - llvm::Value *sep = nullptr; - llvm::Value *end = nullptr; - if (x.m_separator) { - this->visit_expr_wrapper(x.m_separator, true); - sep = tmp; - } else { - sep = builder->CreateGlobalStringPtr(" "); - } - if (x.m_end) { - this->visit_expr_wrapper(x.m_end, true); - end = tmp; - } else { - end = builder->CreateGlobalStringPtr("\n"); - } - for (size_t i=0; i(*x.m_values[i]) ) { - ASR::Variable_t* var = ASRUtils::EXPR2VAR(x.m_values[i]); - reduce_loads = var->m_intent == ASRUtils::intent_in; - if( ASR::is_a(*var->m_type) ) { - ptr_loads = 1; - } - } - if (i != 0) { - fmt.push_back("%s"); - args.push_back(sep); - } - ptr_loads = ptr_loads - reduce_loads; - lookup_enum_value_for_nonints = true; - this->visit_expr_wrapper(x.m_values[i], true); - lookup_enum_value_for_nonints = false; - ptr_loads = ptr_loads_copy; - ASR::expr_t *v = x.m_values[i]; - ASR::ttype_t *t = ASRUtils::expr_type(v); - if( ASR::is_a(*t) ) { - t = ASRUtils::get_contained_type(t); - } - int a_kind = ASRUtils::extract_kind_from_ttype_t(t); - if( ASR::is_a(*t) && ASR::is_a(*v) ) { - if( ASRUtils::is_array(ASRUtils::type_get_past_pointer(t)) ) { - tmp = CreateLoad(arr_descr->get_pointer_to_data(tmp)); - } - fmt.push_back("%lld"); - llvm::Value* d = builder->CreatePtrToInt(tmp, getIntType(8, false)); - args.push_back(d); - continue; - } - if (t->type == ASR::ttypeType::CPtr || - (t->type == ASR::ttypeType::Pointer && - (ASR::is_a(*v) || ASR::is_a(*v))) - ) { - fmt.push_back("%lld"); - llvm::Value* d = builder->CreatePtrToInt(tmp, getIntType(8, false)); - args.push_back(d); - } else if (ASRUtils::is_integer(*t)) { - switch( a_kind ) { - case 1 : { - fmt.push_back("%hhi"); - break; - } - case 2 : { - fmt.push_back("%hi"); - break; - } - case 4 : { - fmt.push_back("%d"); - break; - } - case 8 : { - fmt.push_back("%lld"); - break; - } - default: { - throw CodeGenError(R"""(Printing support is available only - for 8, 16, 32, and 64 bit integer kinds.)""", - x.base.base.loc); - } - } - args.push_back(tmp); - } else if (ASRUtils::is_real(*t)) { - llvm::Value *d; - switch( a_kind ) { - case 4 : { - // Cast float to double as a workaround for the fact that - // vprintf() seems to cast to double even for %f, which - // causes it to print 0.000000. - fmt.push_back("%13.8e"); - d = builder->CreateFPExt(tmp, - llvm::Type::getDoubleTy(context)); - break; - } - case 8 : { - fmt.push_back("%23.17e"); - d = builder->CreateFPExt(tmp, - llvm::Type::getDoubleTy(context)); - break; - } - default: { - throw CodeGenError(R"""(Printing support is available only - for 32, and 64 bit real kinds.)""", - x.base.base.loc); - } - } - args.push_back(d); - } else if (t->type == ASR::ttypeType::Character) { - fmt.push_back("%s"); - args.push_back(tmp); - } else if (ASRUtils::is_logical(*t)) { - llvm::Value *cmp = builder->CreateICmpEQ(tmp, builder->getInt1(0)); - llvm::Value *zero_str = builder->CreateGlobalStringPtr("False"); - llvm::Value *one_str = builder->CreateGlobalStringPtr("True"); - llvm::Value *str = builder->CreateSelect(cmp, zero_str, one_str); - fmt.push_back("%s"); - args.push_back(str); - } else if (ASRUtils::is_complex(*t)) { - llvm::Type *type, *complex_type; - switch( a_kind ) { - case 4 : { - // Cast float to double as a workaround for the fact that - // vprintf() seems to cast to double even for %f, which - // causes it to print 0.000000. - fmt.push_back("(%f,%f)"); - type = llvm::Type::getDoubleTy(context); - complex_type = complex_type_4; - break; - } - case 8 : { - fmt.push_back("(%lf,%lf)"); - type = llvm::Type::getDoubleTy(context); - complex_type = complex_type_8; - break; - } - default: { - throw CodeGenError(R"""(Printing support is available only - for 32, and 64 bit complex kinds.)""", - x.base.base.loc); - } - } - llvm::Value *d; - d = builder->CreateFPExt(complex_re(tmp, complex_type), type); - args.push_back(d); - d = builder->CreateFPExt(complex_im(tmp, complex_type), type); - args.push_back(d); - } else if (t->type == ASR::ttypeType::CPtr) { - fmt.push_back("%lld"); - llvm::Value* d = builder->CreatePtrToInt(tmp, getIntType(8, false)); - args.push_back(d); - } else if (t->type == ASR::ttypeType::Enum) { - // TODO: Use recursion to generalise for any underlying type in enum - fmt.push_back("%d"); - args.push_back(tmp); - } else { - throw LCompilersException("Printing support is not available for " + - ASRUtils::type_to_str(t) + " type."); - } - } - fmt.push_back("%s"); - args.push_back(end); - std::string fmt_str; - for (size_t i=0; iCreateGlobalStringPtr(fmt_str); - std::vector printf_args; - printf_args.push_back(fmt_ptr); - printf_args.insert(printf_args.end(), args.begin(), args.end()); - printf(context, *module, *builder, printf_args); - } - - void visit_Stop(const ASR::Stop_t &x) { - if (compiler_options.emit_debug_info) { - debug_emit_loc(x); - llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr(infile); - llvm::Value *fmt_ptr1 = llvm::ConstantInt::get(context, llvm::APInt( - 1, compiler_options.use_colors)); - call_print_stacktrace_addresses(context, *module, *builder, - {fmt_ptr, fmt_ptr1}); - } - llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr("STOP\n"); - print_error(context, *module, *builder, {fmt_ptr}); - llvm::Value *exit_code; - if (x.m_code && ASRUtils::expr_type(x.m_code)->type == ASR::ttypeType::Integer) { - this->visit_expr(*x.m_code); - exit_code = tmp; - } else { - int exit_code_int = 0; - exit_code = llvm::ConstantInt::get(context, - llvm::APInt(32, exit_code_int)); - } - exit(context, *module, *builder, exit_code); - } - - void visit_ErrorStop(const ASR::ErrorStop_t &x) { - if (compiler_options.emit_debug_info) { - debug_emit_loc(x); - llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr(infile); - llvm::Value *fmt_ptr1 = llvm::ConstantInt::get(context, llvm::APInt( - 1, compiler_options.use_colors)); - call_print_stacktrace_addresses(context, *module, *builder, - {fmt_ptr, fmt_ptr1}); - } - llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr("ERROR STOP\n"); - print_error(context, *module, *builder, {fmt_ptr}); - int exit_code_int = 1; - llvm::Value *exit_code = llvm::ConstantInt::get(context, - llvm::APInt(32, exit_code_int)); - exit(context, *module, *builder, exit_code); - } - - template - inline void set_func_subrout_params(T* func_subrout, ASR::abiType& x_abi, - std::uint32_t& m_h, ASR::Variable_t*& orig_arg, - std::string& orig_arg_name, ASR::intentType& arg_intent, - size_t arg_idx) { - m_h = get_hash((ASR::asr_t*)func_subrout); - if( ASR::is_a(*func_subrout->m_args[arg_idx]) ) { - ASR::Var_t* arg_var = ASR::down_cast(func_subrout->m_args[arg_idx]); - ASR::symbol_t* arg_sym = symbol_get_past_external(arg_var->m_v); - if( ASR::is_a(*arg_sym) ) { - orig_arg = ASR::down_cast(arg_sym); - orig_arg_name = orig_arg->m_name; - arg_intent = orig_arg->m_intent; - } - } - x_abi = ASRUtils::get_FunctionType(func_subrout)->m_abi; - } - - - template - std::vector convert_call_args(const T &x) { - std::vector args; - const ASR::symbol_t* func_subrout = symbol_get_past_external(x.m_name); - ASR::abiType x_abi = ASR::abiType::Source; - if( is_a(*func_subrout) ) { - ASR::Function_t* func = down_cast(func_subrout); - x_abi = ASRUtils::get_FunctionType(func)->m_abi; - } - - for (size_t i=0; itype == ASR::symbolType::Function ) { - ASR::Function_t* func = down_cast(func_subrout); - set_func_subrout_params(func, x_abi, m_h, orig_arg, orig_arg_name, orig_arg_intent, i); - } else if( func_subrout->type == ASR::symbolType::ClassProcedure ) { - ASR::ClassProcedure_t* clss_proc = ASR::down_cast(func_subrout); - if( clss_proc->m_proc->type == ASR::symbolType::Function ) { - ASR::Function_t* func = down_cast(clss_proc->m_proc); - set_func_subrout_params(func, x_abi, m_h, orig_arg, orig_arg_name, orig_arg_intent, i); - } - } else { - LCOMPILERS_ASSERT(false) - } - - if( x.m_args[i].m_value == nullptr ) { - LCOMPILERS_ASSERT(orig_arg != nullptr); - llvm::Type* llvm_orig_arg_type = get_type_from_ttype_t_util(orig_arg->m_type); - llvm::Value* llvm_arg = builder->CreateAlloca(llvm_orig_arg_type); - args.push_back(llvm_arg); - continue ; - } - if (x.m_args[i].m_value->type == ASR::exprType::Var) { - if (is_a(*symbol_get_past_external( - ASR::down_cast(x.m_args[i].m_value)->m_v))) { - ASR::Variable_t *arg = EXPR2VAR(x.m_args[i].m_value); - uint32_t h = get_hash((ASR::asr_t*)arg); - if (llvm_symtab.find(h) != llvm_symtab.end()) { - tmp = llvm_symtab[h]; - bool is_data_only_array = false; - ASR::dimension_t* dims_arg = nullptr; - size_t n_arg = ASRUtils::extract_dimensions_from_ttype(arg->m_type, dims_arg); - if( ASRUtils::is_arg_dummy(arg->m_intent) && - !ASRUtils::is_dimension_empty(dims_arg, n_arg) ) { - is_data_only_array = true; - } - if( x_abi == ASR::abiType::Source && - arr_descr->is_array(arg->m_type) && - !is_data_only_array ) { - llvm::Type* new_arr_type = arr_arg_type_cache[m_h][orig_arg_name]; - ASR::dimension_t* dims; - size_t n; - n = ASRUtils::extract_dimensions_from_ttype(orig_arg->m_type, dims); - tmp = arr_descr->convert_to_argument(tmp, arg->m_type, new_arr_type, - (!ASRUtils::is_dimension_empty(dims, n))); - } else if (x_abi == ASR::abiType::Source && ASR::is_a(*arg->m_type)) { - if (arg->m_intent == intent_local) { - // Local variable of type - // CPtr is a void**, so we - // have to load it - tmp = CreateLoad(tmp); - } - } else if ( x_abi == ASR::abiType::BindC ) { - if( arr_descr->is_array(ASRUtils::get_contained_type(arg->m_type)) ) { - // TODO: we need a dedicated and robust - // function that determines from ASR only - // if a given array is represented by - // a descriptor or with just a pointer. - // Until then we use the following heuristic: - bool arg_is_using_descriptor = true; - if (LLVMArrUtils::is_explicit_shape(arg)) { - if (arg->m_intent != intent_local) { - arg_is_using_descriptor = false; - } - } - if (arg_is_using_descriptor) { - tmp = CreateLoad(arr_descr->get_pointer_to_data(tmp)); - } - } else { - if (orig_arg->m_abi == ASR::abiType::BindC - && orig_arg->m_value_attr) { - ASR::ttype_t* arg_type = arg->m_type; - if( ASR::is_a(*arg_type) ) { - arg_type = ASR::down_cast(arg_type)->m_type; - } - if (is_a(*arg_type)) { - int c_kind = ASRUtils::extract_kind_from_ttype_t(arg_type); - if (c_kind == 4) { - if (compiler_options.platform == Platform::Windows) { - // tmp is {float, float}* - // type_fx2p is i64* - llvm::Type* type_fx2p = llvm::Type::getInt64PtrTy(context); - // Convert {float,float}* to i64* using bitcast - tmp = builder->CreateBitCast(tmp, type_fx2p); - // Then convert i64* -> i64 - tmp = CreateLoad(tmp); - } else if (compiler_options.platform == Platform::macOS_ARM) { - // tmp is {float, float}* - // type_fx2p is [2 x float]* - llvm::Type* type_fx2p = llvm::ArrayType::get(llvm::Type::getFloatTy(context), 2)->getPointerTo(); - // Convert {float,float}* to [2 x float]* using bitcast - tmp = builder->CreateBitCast(tmp, type_fx2p); - // Then convert [2 x float]* -> [2 x float] - tmp = CreateLoad(tmp); - } else { - // tmp is {float, float}* - // type_fx2p is <2 x float>* - llvm::Type* type_fx2p = FIXED_VECTOR_TYPE::get(llvm::Type::getFloatTy(context), 2)->getPointerTo(); - // Convert {float,float}* to <2 x float>* using bitcast - tmp = builder->CreateBitCast(tmp, type_fx2p); - // Then convert <2 x float>* -> <2 x float> - tmp = CreateLoad(tmp); - } - } else { - LCOMPILERS_ASSERT(c_kind == 8) - if (compiler_options.platform == Platform::Windows) { - // 128 bit aggregate type is passed by reference - } else { - // Pass by value - tmp = CreateLoad(tmp); - } - } - } else if (is_a(*arg_type)) { - if (arg->m_intent == intent_local) { - // Local variable of type - // CPtr is a void**, so we - // have to load it - tmp = CreateLoad(tmp); - } - } else { - if (!arg->m_value_attr) { - // Dereference the pointer argument (unless it is a CPtr) - // to pass by value - // E.g.: - // i32* -> i32 - // {double,double}* -> {double,double} - tmp = CreateLoad(tmp); - } - } - } - if (!orig_arg->m_value_attr && arg->m_value_attr) { - llvm::Type *target_type = tmp->getType(); - // Create alloca to get a pointer, but do it - // at the beginning of the function to avoid - // using alloca inside a loop, which would - // run out of stack - llvm::BasicBlock &entry_block = builder->GetInsertBlock()->getParent()->getEntryBlock(); - llvm::IRBuilder<> builder0(context); - builder0.SetInsertPoint(&entry_block, entry_block.getFirstInsertionPt()); - llvm::AllocaInst *target = builder0.CreateAlloca( - target_type, nullptr, "call_arg_value_ptr"); - builder->CreateStore(tmp, target); - tmp = target; - } - } - } - } else { - auto finder = std::find(nested_globals.begin(), - nested_globals.end(), h); - if (finder == nested_globals.end()) { - if (arg->m_value == nullptr) { - throw CodeGenError(std::string(arg->m_name) + " isn't defined in any scope."); - } - this->visit_expr_wrapper(arg->m_value, true); - if( x_abi != ASR::abiType::BindC ) { - llvm::BasicBlock &entry_block = builder->GetInsertBlock()->getParent()->getEntryBlock(); - llvm::IRBuilder<> builder0(context); - builder0.SetInsertPoint(&entry_block, entry_block.getFirstInsertionPt()); - llvm::AllocaInst *target = builder0.CreateAlloca( - get_type_from_ttype_t_util(arg->m_type), nullptr, "call_arg_value"); - builder->CreateStore(tmp, target); - tmp = target; - } - } else { - llvm::Value* ptr = module->getOrInsertGlobal(nested_desc_name, - nested_global_struct); - int idx = std::distance(nested_globals.begin(), finder); - tmp = CreateLoad(llvm_utils->create_gep(ptr, idx)); - } - } - } else if (is_a(*symbol_get_past_external( - ASR::down_cast(x.m_args[i].m_value)->m_v))) { - ASR::Function_t* fn = ASR::down_cast( - symbol_get_past_external(ASR::down_cast( - x.m_args[i].m_value)->m_v)); - uint32_t h = get_hash((ASR::asr_t*)fn); - if (ASRUtils::get_FunctionType(fn)->m_deftype == ASR::deftypeType::Implementation) { - tmp = llvm_symtab_fn[h]; - } else { - // Must be an argument/chained procedure pass - tmp = llvm_symtab_fn_arg[h]; - } - } - } else { - ASR::ttype_t* arg_type = expr_type(x.m_args[i].m_value); - int64_t ptr_loads_copy = ptr_loads; - ptr_loads = !LLVM::is_llvm_struct(arg_type); - this->visit_expr_wrapper(x.m_args[i].m_value); - if( x_abi == ASR::abiType::BindC ) { - if( (ASR::is_a(*x.m_args[i].m_value) && - orig_arg_intent == ASR::intentType::In) || - ASR::is_a(*x.m_args[i].m_value) || - (ASR::is_a(*arg_type) && - ASR::is_a(*x.m_args[i].m_value)) ) { - if( ASR::is_a(*x.m_args[i].m_value) && - ASRUtils::is_array(arg_type) ) { - ASR::dimension_t* arg_m_dims = nullptr; - size_t n_dims = ASRUtils::extract_dimensions_from_ttype(arg_type, arg_m_dims); - if( !(ASRUtils::is_fixed_size_array(arg_m_dims, n_dims) && - ASRUtils::expr_abi(x.m_args[i].m_value) == ASR::abiType::BindC) ) { - tmp = LLVM::CreateLoad(*builder, arr_descr->get_pointer_to_data(tmp)); - } else { - tmp = llvm_utils->create_gep(tmp, llvm::ConstantInt::get( - llvm::Type::getInt32Ty(context), llvm::APInt(32, 0))); - } - } else { - tmp = LLVM::CreateLoad(*builder, tmp); - } - } - } - llvm::Value *value = tmp; - ptr_loads = ptr_loads_copy; - llvm::Type *target_type; - bool character_bindc = false; - switch (arg_type->type) { - case (ASR::ttypeType::Integer) : { - int a_kind = down_cast(arg_type)->m_kind; - target_type = getIntType(a_kind); - break; - } - case (ASR::ttypeType::Real) : { - int a_kind = down_cast(arg_type)->m_kind; - target_type = getFPType(a_kind); - break; - } - case (ASR::ttypeType::Complex) : { - int a_kind = down_cast(arg_type)->m_kind; - target_type = getComplexType(a_kind); - break; - } - case (ASR::ttypeType::Character) : { - ASR::Variable_t *orig_arg = nullptr; - if( func_subrout->type == ASR::symbolType::Function ) { - ASR::Function_t* func = down_cast(func_subrout); - orig_arg = EXPR2VAR(func->m_args[i]); - } else { - LCOMPILERS_ASSERT(false) - } - if (orig_arg->m_abi == ASR::abiType::BindC) { - character_bindc = true; - } - - target_type = character_type; - break; - } - case (ASR::ttypeType::Logical) : - target_type = llvm::Type::getInt1Ty(context); - break; - case (ASR::ttypeType::Enum) : - target_type = llvm::Type::getInt32Ty(context); - break; - case (ASR::ttypeType::Struct) : - break; - case (ASR::ttypeType::CPtr) : - target_type = llvm::Type::getVoidTy(context)->getPointerTo(); - break; - case (ASR::ttypeType::Pointer) : { - target_type = get_type_from_ttype_t_util(ASRUtils::get_contained_type(arg_type)); - target_type = target_type->getPointerTo(); - break; - } - case (ASR::ttypeType::List) : { - target_type = get_type_from_ttype_t_util(arg_type); - break ; - } - case (ASR::ttypeType::Tuple) : { - target_type = get_type_from_ttype_t_util(arg_type); - break ; - } - default : - throw CodeGenError("Type " + ASRUtils::type_to_str(arg_type) + " not implemented yet."); - } - if( ASR::is_a(*x.m_args[i].m_value) ) { - target_type = llvm::Type::getInt32Ty(context); - } - switch(arg_type->type) { - case ASR::ttypeType::Struct: { - tmp = value; - break; - } - default: { - if (!character_bindc) { - bool use_value = false; - ASR::Variable_t *orig_arg = nullptr; - if( func_subrout->type == ASR::symbolType::Function ) { - ASR::Function_t* func = down_cast(func_subrout); - orig_arg = EXPR2VAR(func->m_args[i]); - } else { - LCOMPILERS_ASSERT(false) - } - if (orig_arg->m_abi == ASR::abiType::BindC - && orig_arg->m_value_attr) { - use_value = true; - } - if (ASR::is_a(*x.m_args[i].m_value)) { - use_value = true; - } - if (!use_value) { - // Create alloca to get a pointer, but do it - // at the beginning of the function to avoid - // using alloca inside a loop, which would - // run out of stack - if( (ASR::is_a(*x.m_args[i].m_value) || - ASR::is_a(*x.m_args[i].m_value)) - && value->getType()->isPointerTy()) { - value = CreateLoad(value); - } - if( !ASR::is_a(*arg_type) ) { - llvm::BasicBlock &entry_block = builder->GetInsertBlock()->getParent()->getEntryBlock(); - llvm::IRBuilder<> builder0(context); - builder0.SetInsertPoint(&entry_block, entry_block.getFirstInsertionPt()); - llvm::AllocaInst *target = builder0.CreateAlloca( - target_type, nullptr, "call_arg_value"); - if( ASR::is_a(*arg_type) || - ASR::is_a(*arg_type) ) { - llvm_utils->deepcopy(value, target, arg_type, module.get(), name2memidx); - } else { - builder->CreateStore(value, target); - } - tmp = target; - } else { - tmp = value; - } - } - } - } - } - } - args.push_back(tmp); - } - return args; - } - - void generate_flip_sign(ASR::call_arg_t* m_args) { - this->visit_expr_wrapper(m_args[0].m_value, true); - llvm::Value* signal = tmp; - LCOMPILERS_ASSERT(m_args[1].m_value->type == ASR::exprType::Var); - ASR::Var_t* asr_var = ASR::down_cast(m_args[1].m_value); - ASR::Variable_t* asr_variable = ASR::down_cast(asr_var->m_v); - uint32_t x_h = get_hash((ASR::asr_t*)asr_variable); - llvm::Value* variable = llvm_symtab[x_h]; - // variable = xor(shiftl(int(Nd), 63), variable) - ASR::ttype_t* signal_type = ASRUtils::expr_type(m_args[0].m_value); - int signal_kind = ASRUtils::extract_kind_from_ttype_t(signal_type); - llvm::Value* num_shifts = llvm::ConstantInt::get(context, llvm::APInt(32, signal_kind * 8 - 1)); - llvm::Value* shifted_signal = builder->CreateShl(signal, num_shifts); - llvm::Value* int_var = builder->CreateBitCast(CreateLoad(variable), shifted_signal->getType()); - tmp = builder->CreateXor(shifted_signal, int_var); - llvm::Type* variable_type = get_type_from_ttype_t_util(asr_variable->m_type); - builder->CreateStore(builder->CreateBitCast(tmp, variable_type->getPointerTo()), variable); - } - - void generate_fma(ASR::call_arg_t* m_args) { - this->visit_expr_wrapper(m_args[0].m_value, true); - llvm::Value* a = tmp; - this->visit_expr_wrapper(m_args[1].m_value, true); - llvm::Value* b = tmp; - this->visit_expr_wrapper(m_args[2].m_value, true); - llvm::Value* c = tmp; - tmp = builder->CreateIntrinsic(llvm::Intrinsic::fma, - {a->getType()}, - {b, c, a}); - } - - void generate_sign_from_value(ASR::call_arg_t* m_args) { - this->visit_expr_wrapper(m_args[0].m_value, true); - llvm::Value* arg0 = tmp; - this->visit_expr_wrapper(m_args[1].m_value, true); - llvm::Value* arg1 = tmp; - llvm::Type* common_llvm_type = arg0->getType(); - ASR::ttype_t *arg1_type = ASRUtils::expr_type(m_args[1].m_value); - uint64_t kind = ASRUtils::extract_kind_from_ttype_t(arg1_type); - llvm::Value* num_shifts = llvm::ConstantInt::get(context, llvm::APInt(kind * 8, kind * 8 - 1)); - llvm::Value* shifted_one = builder->CreateShl(llvm::ConstantInt::get(context, llvm::APInt(kind * 8, 1)), num_shifts); - arg1 = builder->CreateBitCast(arg1, shifted_one->getType()); - arg0 = builder->CreateBitCast(arg0, shifted_one->getType()); - tmp = builder->CreateXor(arg0, builder->CreateAnd(shifted_one, arg1)); - tmp = builder->CreateBitCast(tmp, common_llvm_type); - } - - template - bool generate_optimization_instructions(const T* routine, ASR::call_arg_t* m_args) { - std::string routine_name = std::string(routine->m_name); - if( routine_name.find("flipsign") != std::string::npos ) { - generate_flip_sign(m_args); - return true; - } else if( routine_name.find("fma") != std::string::npos ) { - generate_fma(m_args); - return true; - } else if( routine_name.find("signfromvalue") != std::string::npos ) { - generate_sign_from_value(m_args); - return true; - } - return false; - } - - void visit_SubroutineCall(const ASR::SubroutineCall_t &x) { - if (compiler_options.emit_debug_info) debug_emit_loc(x); - if( ASRUtils::is_intrinsic_optimization(x.m_name) ) { - ASR::Function_t* routine = ASR::down_cast( - ASRUtils::symbol_get_past_external(x.m_name)); - if( generate_optimization_instructions(routine, x.m_args) ) { - return ; - } - } - ASR::Function_t *s; - std::vector args; - const ASR::symbol_t *proc_sym = symbol_get_past_external(x.m_name); - if (x.m_dt){ - ASR::Variable_t *caller = EXPR2VAR(x.m_dt); - std::uint32_t h = get_hash((ASR::asr_t*)caller); - args.push_back(llvm_symtab[h]); - } - if (ASR::is_a(*proc_sym)) { - s = ASR::down_cast(proc_sym); - } else { - ASR::ClassProcedure_t *clss_proc = ASR::down_cast< - ASR::ClassProcedure_t>(proc_sym); - s = ASR::down_cast(clss_proc->m_proc); - } - if (parent_function){ - push_nested_stack(parent_function); - } - uint32_t h; - ASR::FunctionType_t* s_func_type = ASR::down_cast(s->m_function_signature); - if (s_func_type->m_abi == ASR::abiType::LFortranModule) { - throw CodeGenError("Subroutine LCompilers interfaces not implemented yet"); - } else if (s_func_type->m_abi == ASR::abiType::Interactive) { - h = get_hash((ASR::asr_t*)s); - } else if (s_func_type->m_abi == ASR::abiType::Source) { - h = get_hash((ASR::asr_t*)s); - } else if (s_func_type->m_abi == ASR::abiType::BindC) { - h = get_hash((ASR::asr_t*)s); - } else if (s_func_type->m_abi == ASR::abiType::Intrinsic) { - h = get_hash((ASR::asr_t*)s); - } else { - throw CodeGenError("ABI type not implemented yet in SubroutineCall."); - } - if (llvm_symtab_fn_arg.find(h) != llvm_symtab_fn_arg.end()) { - // Check if this is a callback function - llvm::Value* fn = llvm_symtab_fn_arg[h]; - llvm::FunctionType* fntype = llvm_symtab_fn[h]->getFunctionType(); - std::string m_name = ASR::down_cast(x.m_name)->m_name; - args = convert_call_args(x); - tmp = builder->CreateCall(fntype, fn, args); - } else if (llvm_symtab_fn.find(h) == llvm_symtab_fn.end()) { - throw CodeGenError("Subroutine code not generated for '" - + std::string(s->m_name) + "'"); - } else { - llvm::Function *fn = llvm_symtab_fn[h]; - std::string m_name = ASRUtils::symbol_name(x.m_name); - std::vector args2 = convert_call_args(x); - args.insert(args.end(), args2.begin(), args2.end()); - builder->CreateCall(fn, args); - } - calling_function_hash = h; - pop_nested_stack(s); - } - - void handle_bitwise_args(const ASR::FunctionCall_t& x, llvm::Value*& arg1, - llvm::Value*& arg2) { - LCOMPILERS_ASSERT(x.n_args == 2); - tmp = nullptr; - this->visit_expr_wrapper(x.m_args[0].m_value, true); - arg1 = tmp; - tmp = nullptr; - this->visit_expr_wrapper(x.m_args[1].m_value, true); - arg2 = tmp; - } - - void handle_bitwise_xor(const ASR::FunctionCall_t& x) { - llvm::Value *arg1 = nullptr, *arg2 = nullptr; - handle_bitwise_args(x, arg1, arg2); - tmp = builder->CreateXor(arg1, arg2); - } - - void handle_bitwise_and(const ASR::FunctionCall_t& x) { - llvm::Value *arg1 = nullptr, *arg2 = nullptr; - handle_bitwise_args(x, arg1, arg2); - tmp = builder->CreateAnd(arg1, arg2); - } - - void handle_bitwise_or(const ASR::FunctionCall_t& x) { - llvm::Value *arg1 = nullptr, *arg2 = nullptr; - handle_bitwise_args(x, arg1, arg2); - tmp = builder->CreateOr(arg1, arg2); - } - - llvm::Value* CreatePointerToStructReturnValue(llvm::FunctionType* fnty, - llvm::Value* return_value, - ASR::ttype_t* asr_return_type) { - if( !LLVM::is_llvm_struct(asr_return_type) ) { - return return_value; - } - - // Call to LLVM APIs not needed to fetch the return type of the function. - // We can use asr_return_type as well but anyways for compactness I did it here. - llvm::Value* pointer_to_struct = builder->CreateAlloca(fnty->getReturnType(), nullptr); - LLVM::CreateStore(*builder, return_value, pointer_to_struct); - return pointer_to_struct; - } - - llvm::Value* CreateCallUtil(llvm::FunctionType* fnty, llvm::Function* fn, - std::vector& args, - ASR::ttype_t* asr_return_type) { - llvm::Value* return_value = builder->CreateCall(fn, args); - return CreatePointerToStructReturnValue(fnty, return_value, - asr_return_type); - } - - llvm::Value* CreateCallUtil(llvm::Function* fn, std::vector& args, - ASR::ttype_t* asr_return_type) { - return CreateCallUtil(fn->getFunctionType(), fn, args, asr_return_type); - } - - void visit_FunctionCall(const ASR::FunctionCall_t &x) { - if( ASRUtils::is_intrinsic_optimization(x.m_name) ) { - ASR::Function_t* routine = ASR::down_cast( - ASRUtils::symbol_get_past_external(x.m_name)); - if( generate_optimization_instructions(routine, x.m_args) ) { - return ; - } - } - if (x.m_value) { - this->visit_expr_wrapper(x.m_value, true); - return; - } - ASR::Function_t *s = nullptr; - std::vector args; - const ASR::symbol_t *proc_sym = symbol_get_past_external(x.m_name); - if (x.m_dt){ - ASR::Variable_t *caller = EXPR2VAR(x.m_dt); - std::uint32_t h = get_hash((ASR::asr_t*)caller); - args.push_back(llvm_symtab[h]); - } - if (ASR::is_a(*proc_sym)) { - s = ASR::down_cast(proc_sym); - } else { - ASR::ClassProcedure_t *clss_proc = ASR::down_cast< - ASR::ClassProcedure_t>(proc_sym); - s = ASR::down_cast(clss_proc->m_proc); - } - if( s == nullptr ) { - s = ASR::down_cast(symbol_get_past_external(x.m_name)); - } - if( ASRUtils::is_intrinsic_function2(s) ) { - std::string symbol_name = ASRUtils::symbol_name(x.m_name); - if( startswith(symbol_name, "_bitwise_xor") ) { - handle_bitwise_xor(x); - return ; - } - if( startswith(symbol_name, "_bitwise_and") ) { - handle_bitwise_and(x); - return ; - } - if( startswith(symbol_name, "_bitwise_or") ) { - handle_bitwise_or(x); - return ; - } - } - if (parent_function){ - push_nested_stack(parent_function); - } - bool intrinsic_function = ASRUtils::is_intrinsic_function2(s); - uint32_t h; - ASR::FunctionType_t* s_func_type = ASR::down_cast(s->m_function_signature); - if (s_func_type->m_abi == ASR::abiType::Source && !intrinsic_function) { - h = get_hash((ASR::asr_t*)s); - } else if (s_func_type->m_abi == ASR::abiType::LFortranModule) { - throw CodeGenError("Function LCompilers interfaces not implemented yet"); - } else if (s_func_type->m_abi == ASR::abiType::Interactive) { - h = get_hash((ASR::asr_t*)s); - } else if (s_func_type->m_abi == ASR::abiType::BindC) { - h = get_hash((ASR::asr_t*)s); - } else if (s_func_type->m_abi == ASR::abiType::Intrinsic || intrinsic_function) { - std::string func_name = s->m_name; - if( fname2arg_type.find(func_name) != fname2arg_type.end() ) { - h = get_hash((ASR::asr_t*)s); - } else { - if (func_name == "len") { - args = convert_call_args(x); - LCOMPILERS_ASSERT(args.size() == 3) - tmp = lfortran_str_len(args[0]); - return; - } - if( ASRUtils::get_FunctionType(s)->m_deftype == ASR::deftypeType::Interface ) { - throw CodeGenError("Intrinsic '" + func_name + "' not implemented yet and compile time value is not available."); - } else { - h = get_hash((ASR::asr_t*)s); - } - } - } else { - throw CodeGenError("ABI type not implemented yet."); - } - if (llvm_symtab_fn_arg.find(h) != llvm_symtab_fn_arg.end()) { - // Check if this is a callback function - llvm::Value* fn = llvm_symtab_fn_arg[h]; - llvm::FunctionType* fntype = llvm_symtab_fn[h]->getFunctionType(); - std::string m_name = std::string(((ASR::Function_t*)(&(x.m_name->base)))->m_name); - args = convert_call_args(x); - tmp = builder->CreateCall(fntype, fn, args); - } else if (llvm_symtab_fn.find(h) == llvm_symtab_fn.end()) { - throw CodeGenError("Function code not generated for '" - + std::string(s->m_name) + "'"); - } else { - llvm::Function *fn = llvm_symtab_fn[h]; - std::string m_name = std::string(((ASR::Function_t*)(&(x.m_name->base)))->m_name); - std::vector args2 = convert_call_args(x); - args.insert(args.end(), args2.begin(), args2.end()); - ASR::ttype_t *return_var_type0 = EXPR2VAR(s->m_return_var)->m_type; - if (ASRUtils::get_FunctionType(s)->m_abi == ASR::abiType::BindC) { - if (is_a(*return_var_type0)) { - int a_kind = down_cast(return_var_type0)->m_kind; - if (a_kind == 8) { - if (compiler_options.platform == Platform::Windows) { - tmp = builder->CreateAlloca(complex_type_8, nullptr); - args.insert(args.begin(), tmp); - builder->CreateCall(fn, args); - // Convert {double,double}* to {double,double} - tmp = CreateLoad(tmp); - } else { - tmp = builder->CreateCall(fn, args); - } - } else { - tmp = builder->CreateCall(fn, args); - } - } else { - tmp = builder->CreateCall(fn, args); - } - } else { - tmp = CreateCallUtil(fn, args, return_var_type0); - } - } - if (ASRUtils::get_FunctionType(s)->m_abi == ASR::abiType::BindC) { - ASR::ttype_t *return_var_type0 = EXPR2VAR(s->m_return_var)->m_type; - if (is_a(*return_var_type0)) { - int a_kind = down_cast(return_var_type0)->m_kind; - if (a_kind == 4) { - if (compiler_options.platform == Platform::Windows) { - // tmp is i64, have to convert to {float, float} - - // i64 - llvm::Type* type_fx2 = llvm::Type::getInt64Ty(context); - // Convert i64 to i64* - llvm::AllocaInst *p_fx2 = builder->CreateAlloca(type_fx2, nullptr); - builder->CreateStore(tmp, p_fx2); - // Convert i64* to {float,float}* using bitcast - tmp = builder->CreateBitCast(p_fx2, complex_type_4->getPointerTo()); - // Convert {float,float}* to {float,float} - tmp = CreateLoad(tmp); - } else if (compiler_options.platform == Platform::macOS_ARM) { - // pass - } else { - // tmp is <2 x float>, have to convert to {float, float} - - // <2 x float> - llvm::Type* type_fx2 = FIXED_VECTOR_TYPE::get(llvm::Type::getFloatTy(context), 2); - // Convert <2 x float> to <2 x float>* - llvm::AllocaInst *p_fx2 = builder->CreateAlloca(type_fx2, nullptr); - builder->CreateStore(tmp, p_fx2); - // Convert <2 x float>* to {float,float}* using bitcast - tmp = builder->CreateBitCast(p_fx2, complex_type_4->getPointerTo()); - // Convert {float,float}* to {float,float} - tmp = CreateLoad(tmp); - } - } - } - } - calling_function_hash = h; - pop_nested_stack(s); - } - - void visit_ArraySize(const ASR::ArraySize_t& x) { - if( x.m_value ) { - visit_expr_wrapper(x.m_value, true); - return ; - } - int output_kind = ASRUtils::extract_kind_from_ttype_t(x.m_type); - int dim_kind = 4; - int64_t ptr_loads_copy = ptr_loads; - ptr_loads = 2 - // Sync: instead of 2 - , should this be ptr_loads_copy - - (ASRUtils::expr_type(x.m_v)->type == - ASR::ttypeType::Pointer); - visit_expr_wrapper(x.m_v); - ptr_loads = ptr_loads_copy; - llvm::Value* llvm_arg = tmp; - llvm::Value* llvm_dim = nullptr; - if( x.m_dim ) { - visit_expr_wrapper(x.m_dim, true); - dim_kind = ASRUtils::extract_kind_from_ttype_t(ASRUtils::expr_type(x.m_dim)); - llvm_dim = tmp; - } - tmp = arr_descr->get_array_size(llvm_arg, llvm_dim, output_kind, dim_kind); - } - - void visit_ArrayBound(const ASR::ArrayBound_t& x) { - ASR::expr_t* array_value = ASRUtils::expr_value(x.m_v); - if( array_value && ASR::is_a(*array_value) ) { - ASR::ArrayConstant_t* array_const = ASR::down_cast(array_value); - int kind = ASRUtils::extract_kind_from_ttype_t(x.m_type); - size_t bound_value = 0; - if( x.m_bound == ASR::arrayboundType::LBound ) { - bound_value = 1; - } else if( x.m_bound == ASR::arrayboundType::UBound ) { - bound_value = array_const->n_args; - } else { - LCOMPILERS_ASSERT(false); - } - tmp = llvm::ConstantInt::get(context, llvm::APInt(kind * 8, bound_value)); - return ; - } - int64_t ptr_loads_copy = ptr_loads; - ptr_loads = 2 - // Sync: instead of 2 - , should this be ptr_loads_copy - - (ASRUtils::expr_type(x.m_v)->type == - ASR::ttypeType::Pointer); - visit_expr_wrapper(x.m_v); - ptr_loads = ptr_loads_copy; - llvm::Value* llvm_arg1 = tmp; - llvm::Value* dim_des_val = arr_descr->get_pointer_to_dimension_descriptor_array(llvm_arg1); - visit_expr_wrapper(x.m_dim, true); - llvm::Value* dim_val = tmp; - llvm::Value* const_1 = llvm::ConstantInt::get(context, llvm::APInt(32, 1)); - dim_val = builder->CreateSub(dim_val, const_1); - llvm::Value* dim_struct = arr_descr->get_pointer_to_dimension_descriptor(dim_des_val, dim_val); - llvm::Value* res = nullptr; - if( x.m_bound == ASR::arrayboundType::LBound ) { - res = arr_descr->get_lower_bound(dim_struct); - } else if( x.m_bound == ASR::arrayboundType::UBound ) { - res = arr_descr->get_upper_bound(dim_struct); - } - tmp = res; - } - -}; - - - -Result> asr_to_llvm(ASR::TranslationUnit_t &asr, - diag::Diagnostics &diagnostics, - llvm::LLVMContext &context, Allocator &al, - LCompilers::PassManager& pass_manager, - CompilerOptions &co, const std::string &run_fn, - const std::string &infile) -{ -#if LLVM_VERSION_MAJOR >= 15 - context.setOpaquePointers(false); -#endif - ASRToLLVMVisitor v(al, context, infile, co, diagnostics); - LCompilers::PassOptions pass_options; - pass_options.runtime_library_dir = co.runtime_library_dir; - pass_options.mod_files_dir = co.mod_files_dir; - pass_options.include_dirs = co.include_dirs; - pass_options.run_fun = run_fn; - pass_options.always_run = false; - pass_manager.rtlib = co.rtlib; - pass_manager.apply_passes(al, &asr, pass_options, diagnostics); - - // Uncomment for debugging the ASR after the transformation - // std::cout << LPython::pickle(asr, true, true, true) << std::endl; - - v.nested_func_types = pass_find_nested_vars(asr, context, - v.nested_globals, v.nested_call_out, v.nesting_map); - try { - v.visit_asr((ASR::asr_t&)asr); - } catch (const CodeGenError &e) { - Error error; - diagnostics.diagnostics.push_back(e.d); - return error; - } catch (const CodeGenAbort &) { - LCOMPILERS_ASSERT(diagnostics.has_error()) - Error error; - return error; - } - std::string msg; - llvm::raw_string_ostream err(msg); - if (llvm::verifyModule(*v.module, &err)) { - std::string buf; - llvm::raw_string_ostream os(buf); - v.module->print(os, nullptr); - std::cout << os.str(); - msg = "asr_to_llvm: module failed verification. Error:\n" + err.str(); - diagnostics.diagnostics.push_back(diag::Diagnostic(msg, - diag::Level::Error, diag::Stage::CodeGen)); - Error error; - return error; - }; - return std::make_unique(std::move(v.module)); -} - -} // namespace LCompilers diff --git a/src/libasr/codegen/asr_to_llvm.h b/src/libasr/codegen/asr_to_llvm.h deleted file mode 100644 index a1e911e0c2..0000000000 --- a/src/libasr/codegen/asr_to_llvm.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef LFORTRAN_ASR_TO_LLVM_H -#define LFORTRAN_ASR_TO_LLVM_H - -#include -#include -#include - -namespace LCompilers { - - Result> asr_to_llvm(ASR::TranslationUnit_t &asr, - diag::Diagnostics &diagnostics, - llvm::LLVMContext &context, Allocator &al, - LCompilers::PassManager& pass_manager, - CompilerOptions &compiler_options, - const std::string &run_fn, - const std::string &infile); - -} // namespace LCompilers - -#endif // LFORTRAN_ASR_TO_LLVM_H diff --git a/src/libasr/codegen/asr_to_py.cpp b/src/libasr/codegen/asr_to_py.cpp deleted file mode 100644 index a27891c07b..0000000000 --- a/src/libasr/codegen/asr_to_py.cpp +++ /dev/null @@ -1,473 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - - -/* - * - * This back-end generates wrapper code that allows Fortran to automatically be called from Python. - * It also generates a C header file, so I suppose it indirectly generates C wrappers as well. - * Currently, it outputs Cython, rather than the Python C API directly - much easier to implement. - * The actual output files are: - * - a .h file, containing C-language function declarations * - * - a .pxd file, basically containing the same information as the .h file, but in Cython's format. - * - a .pyx file, which is a Cython file that includes the actual python-callable wrapper functions. - * - * Currently, this back-end only wraps functions that are marked "bind (c)" in the Fortran source. - * At some later point we will offer the functionality to generate bind (c) wrapper functions for - * normal Fortran subprograms, but for now, we don't offer this functionality. - * - * --- H. Snyder, Aug 2021 - * - * */ - - -/* - * The following technique is called X-macros, if you don't recognize it. - * You should be able to look it up under that name for an explanation. - */ - -#define CTYPELIST \ - _X(ASR::Integer_t, 1, "int8_t" ) \ - _X(ASR::Integer_t, 2, "int16_t" ) \ - _X(ASR::Integer_t, 4, "int32_t" ) \ - _X(ASR::Integer_t, 8, "int64_t" ) \ - \ - _X(ASR::Real_t, 4, "float" ) \ - _X(ASR::Real_t, 8, "double" ) \ - \ - _X(ASR::Complex_t, 4, "float _Complex" ) \ - _X(ASR::Complex_t, 8, "double _Complex" ) \ - \ - _X(ASR::Logical_t, 1, "_Bool" ) \ - _X(ASR::Character_t, 1, "char" ) - - -/* - * We will use this list instead, once the ASR has symbolic kind information. - -#define CTYPELIST_FUTURE \ - _X(ASR::Integer_t, "c_int", "int" ) \ - _X(ASR::Integer_t, "c_short", "short" ) \ - _X(ASR::Integer_t, "c_long", "long" ) \ - _X(ASR::Integer_t, "c_long_long", "long long" ) \ - _X(ASR::Integer_t, "c_signed_char", "signed char" ) \ - _X(ASR::Integer_t, "c_size_t", "size_t" ) \ - \ - _X(ASR::Integer_t, "c_int8_t", "int8_t" ) \ - _X(ASR::Integer_t, "c_int16_t", "int16_t" ) \ - _X(ASR::Integer_t, "c_int32_t", "int32_t" ) \ - _X(ASR::Integer_t, "c_int64_t", "int64_t" ) \ - \ - _X(ASR::Integer_t, "c_int_least8_t", "int_least8_t" ) \ - _X(ASR::Integer_t, "c_int_least16_t", "int_least16_t" ) \ - _X(ASR::Integer_t, "c_int_least32_t", "int_least32_t" ) \ - _X(ASR::Integer_t, "c_int_least64_t", "int_least64_t" ) \ - \ - _X(ASR::Integer_t, "c_int_fast8_t", "int_fast8_t" ) \ - _X(ASR::Integer_t, "c_int_fast16_t", "int_fast16_t" ) \ - _X(ASR::Integer_t, "c_int_fast32_t", "int_fast32_t" ) \ - _X(ASR::Integer_t, "c_int_fast64_t", "int_fast64_t" ) \ - \ - _X(ASR::Integer_t, "c_intmax_t", "intmax_t" ) \ - _X(ASR::Integer_t, "c_intptr_t", "intptr_t" ) \ - _X(ASR::Integer_t, "c_ptrdiff_t", "ptrdiff_t" ) \ - \ - _X(ASR::Real_t, "c_float", "float" ) \ - _X(ASR::Real_t, "c_double", "double" ) \ - _X(ASR::Real_t, "c_long_double", "long double" ) \ - \ - _X(ASR::Complex_t, "c_float_complex", "float _Complex" ) \ - _X(ASR::Complex_t, "c_double_complex", "double _Complex" ) \ - _X(ASR::Complex_t, "c_long_double_complex", "long double _Complex" ) \ - \ - _X(ASR::Logical_t, "c_bool", "_Bool" ) \ - _X(ASR::Character_t, "c_char", "char" ) - */ - -namespace LCompilers { - -namespace { - - // Local exception that is only used in this file to exit the visitor - // pattern and caught later (not propagated outside) - class CodeGenError - { - public: - diag::Diagnostic d; - public: - CodeGenError(const std::string &msg) - : d{diag::Diagnostic(msg, diag::Level::Error, diag::Stage::CodeGen)} - { } - }; - -} - -using ASR::is_a; -using ASR::down_cast; -using ASR::down_cast2; - -class ASRToPyVisitor : public ASR::BaseVisitor -{ -public: - // These store the strings that will become the contents of the generated .h, .pxd, .pyx files - std::string chdr, pxd, pyx; - - // Stores the name of the current module being visited. - // Value is meaningless after calling ASRToPyVisitor::visit_asr. - std::string cur_module; - - // Are we assuming arrays to be in C order (row-major)? If not, assume Fortran order (column-major). - bool c_order; - - // What's the file name of the C header file we're going to generate? (needed for the .pxd) - std::string chdr_filename; - // What's the name of the pxd file (minus the .pxd extension) - std::string pxdf; - - ASRToPyVisitor(bool c_order_, std::string chdr_filename_) : - c_order(c_order_), - chdr_filename(chdr_filename_), - pxdf(chdr_filename_) - { - // we need to get get the pxd filename (minus extension), so we can import it in the pyx file - // knock off ".h" from the c header filename - pxdf.erase(--pxdf.end()); - pxdf.erase(--pxdf.end()); - // this is an unfortunate hack, but we have to add something so that the pxd and pyx filenames - // are different (beyond just their extensions). If we don't, the cython emits a warning. - // TODO we definitely need to change this somehow because right now this "append _pxd" trick - // exists in two places (bin/lfortran.cpp, and here), which could easily cause breakage. - pxdf += "_pxd"; - } - - std::tuple - helper_visit_arguments(size_t n_args, ASR::expr_t ** args) - { - - struct arg_info { - ASR::Variable_t* asr_obj; - std::string ctype; - int ndims; - - std::vector ubound_varnames; - std::vector > i_am_ubound_of; - }; - - std::vector arg_infos; - - - /* get_arg_infos */ for (size_t i=0; im_intent)); - - // TODO add support for (or emit error on) assumed-shape arrays - // TODO add support for interoperable derived types - - arg_info this_arg_info; - - const char * errmsg1 = "pywrap does not yet support array dummy arguments with lower bounds other than 1."; - const char * errmsg2 = "pywrap can only generate wrappers for array dummy arguments " - "if the upper bound is a constant integer, or another (scalar) dummy argument."; - - // Generate a sequence of if-blocks to determine the type, using the type list defined above - #define _X(ASR_TYPE, KIND, CTYPE_STR) \ - if ( is_a(*arg->m_type) && (down_cast(arg->m_type)->m_kind == KIND) ) { \ - this_arg_info.asr_obj = arg; \ - this_arg_info.ctype = CTYPE_STR; \ - auto tmp_arg = down_cast(arg->m_type); \ - this_arg_info.ndims = tmp_arg->n_dims; \ - for (int j = 0; j < this_arg_info.ndims; j++) { \ - auto lbound_ptr = tmp_arg->m_dims[j].m_start; \ - if (!is_a(*lbound_ptr)) { \ - throw CodeGenError(errmsg1); \ - } \ - if (down_cast(lbound_ptr)->m_n != 1) { \ - throw CodeGenError(errmsg1); \ - } \ - if (is_a(*tmp_arg->m_dims[j].m_length)) { \ - ASR::Variable_t *dimvar = ASRUtils::EXPR2VAR(tmp_arg->m_dims[j].m_length); \ - this_arg_info.ubound_varnames.push_back(dimvar->m_name); \ - } else if (!is_a(*lbound_ptr)) { \ - throw CodeGenError(errmsg2); \ - } \ - } \ - } else - - CTYPELIST { - // We end up in this block if none of the above if-blocks were triggered - throw CodeGenError("Type not supported"); - }; - #undef _X - - arg_infos.push_back(this_arg_info); - - } /* get_arg_infos */ - - - /* mark_array_bound_vars */ for(auto arg_iter = arg_infos.begin(); arg_iter != arg_infos.end(); arg_iter++) { - - /* some dummy args might just be the sizes of other dummy args, e.g.: - - subroutine foo(n,x) - integer :: n, x(n) - end subroutine - - We don't actually want `n` in the python wrapper's arguments - the Python programmer - shouldn't need to explicitly pass sizes. From the get_arg_infos block, we already have - the mapping from `x` to `n`, but we also need the opposite - we need be able to look at - `n` and know that it's related to `x`. So let's do a pass over the arg_infos list and - assemble that information. - - */ - - for (auto bound_iter = arg_iter->ubound_varnames.begin(); - bound_iter != arg_iter->ubound_varnames.end(); - bound_iter++ ) { - for (unsigned int j = 0; j < arg_infos.size(); j++) { - if (0 == std::string(arg_infos[j].asr_obj->m_name).compare(*bound_iter)) { - arg_infos[j].i_am_ubound_of.push_back(std::make_pair(arg_iter->asr_obj->m_name, j)); - } - } - } - - } /* mark_array_bound_vars */ - - - /* apply_c_order */ if(c_order) { - - for(auto arg_iter = arg_infos.begin(); arg_iter != arg_infos.end(); arg_iter++) { - - for (auto bound = arg_iter->i_am_ubound_of.begin(); - bound != arg_iter->i_am_ubound_of.end(); - bound++) { - auto x = std::make_pair(bound->first, - bound->second -1); - bound->swap(x); - } - - } - - } /* apply_c_order */ - - std::string c, cyargs, fargs, pyxbody, return_statement; - - /* build_return_strings */ for(auto it = arg_infos.begin(); it != arg_infos.end(); it++) { - - std::string c_wip, cyargs_wip, fargs_wip, rtn_wip; - - c_wip = it->ctype; - - // Get type for cython wrapper argument, from the C type name - if (it->ndims > 0) { - std::string mode = c_order ? ", mode=\"c\"" : ", mode=\"fortran\""; - std::string strndims = it->ndims > 1 ? ", ndim="+std::to_string(it->ndims) : ""; - cyargs_wip += "ndarray[" + it->ctype + strndims + mode + "]"; - } else { - cyargs_wip += it->ctype; - } - - // Fortran defaults to pass-by-reference, so the C argument is a pointer, unless - // it is not an array AND it has the value type. - if (it->ndims > 0 || !it->asr_obj->m_value_attr) { - c_wip += " *"; - fargs_wip = "&"; - // If the argument is intent(in) and a pointer, it should be a ptr-to-const. - if (ASR::intentType::In == it->asr_obj->m_intent) c_wip = "const " + c_wip; - } - - c_wip += " "; - c_wip += it->asr_obj->m_name; - - cyargs_wip += " "; - cyargs_wip += it->asr_obj->m_name; - - fargs_wip += it->asr_obj->m_name; - if(it->ndims > 0) { - fargs_wip += "[0"; - for(int h = 1; h < it->ndims; h++) - fargs_wip += ",0"; - fargs_wip += "]"; - } - - if (ASR::intentType::Out == it->asr_obj->m_intent || - ASR::intentType::InOut == it->asr_obj->m_intent) { - rtn_wip = it->asr_obj->m_name; - } - - - if(!it->i_am_ubound_of.empty()) { - cyargs_wip.clear(); - auto& i_am_ubound_of = it->i_am_ubound_of[0]; - pyxbody += " cdef " + it->ctype + " "; - pyxbody += it->asr_obj->m_name; - pyxbody += " = "; - pyxbody += i_am_ubound_of.first + ".shape[" + std::to_string(i_am_ubound_of.second) + "]\n"; - for(unsigned int k = 1; k < it->i_am_ubound_of.size(); k++) { - auto& i_am_ubound_of_k = it->i_am_ubound_of[k]; - pyxbody += " assert(" + i_am_ubound_of_k.first + ".shape[" + std::to_string(i_am_ubound_of_k.second) + "] == " - + i_am_ubound_of.first + ".shape[" + std::to_string(i_am_ubound_of.second) + "])\n"; - } - } - - if(!c.empty() && !c_wip.empty()) c += ", "; - if(!fargs.empty() && !fargs_wip.empty()) fargs += ", "; - if(!cyargs.empty() && !cyargs_wip.empty()) cyargs += ", "; - if(!return_statement.empty() && !rtn_wip.empty()) return_statement += ", "; - - c += c_wip; - fargs += fargs_wip; - cyargs += cyargs_wip; - return_statement += rtn_wip; - - - } /* build_return_strings */ - - return std::make_tuple(c, cyargs, fargs, pyxbody, return_statement); - } - - void visit_TranslationUnit(const ASR::TranslationUnit_t &x) { - // All loose statements must be converted to a function, so the items - // must be empty: - LCOMPILERS_ASSERT(x.n_items == 0); - - std::string chdr_tmp ; - std::string pxd_tmp ; - std::string pyx_tmp ; - - chdr_tmp = "// This file was automatically generated by the LCompilers compiler.\n"; - chdr_tmp += "// Editing by hand is discouraged.\n\n"; - chdr_tmp += "#include \n\n"; - - pxd_tmp = "# This file was automatically generated by the LCompilers compiler.\n"; - pxd_tmp += "# Editing by hand is discouraged.\n\n"; - pxd_tmp += "from libc.stdint cimport int8_t, int16_t, int32_t, int64_t\n"; - pxd_tmp += "cdef extern from \"" + chdr_filename + "\":\n"; - - - pyx_tmp = "# This file was automatically generated by the LCompilers compiler.\n"; - pyx_tmp += "# Editing by hand is discouraged.\n\n"; - pyx_tmp += "from numpy cimport import_array, ndarray, int8_t, int16_t, int32_t, int64_t\n"; - pyx_tmp += "from numpy import empty, int8, int16, int32, int64\n"; - pyx_tmp += "cimport " + pxdf + " \n\n"; - - // Process loose procedures first - for (auto &item : x.m_global_scope->get_scope()) { - if (is_a(*item.second)) { - visit_symbol(*item.second); - - chdr_tmp += chdr; - pxd_tmp += pxd; - pyx_tmp += pyx; - } - } - - // Then do all the modules in the right order - std::vector build_order - = ASRUtils::determine_module_dependencies(x); - for (auto &item : build_order) { - LCOMPILERS_ASSERT(x.m_global_scope->get_scope().find(item) - != x.m_global_scope->get_scope().end()); - if (!startswith(item, "lfortran_intrinsic")) { - ASR::symbol_t *mod = x.m_global_scope->get_symbol(item); - visit_symbol(*mod); - - chdr_tmp += chdr; - pxd_tmp += pxd; - pyx_tmp += pyx; - } - } - - // There's no need to process the `program` statement, which - // is the only other thing that can appear at the top level. - - chdr = chdr_tmp; - pyx = pyx_tmp; - pxd = pxd_tmp; - } - - void visit_Module(const ASR::Module_t &x) { - cur_module = x.m_name; - - // Generate code for nested subroutines and functions first: - std::string chdr_tmp ; - std::string pxd_tmp ; - std::string pyx_tmp ; - - for (auto &item : x.m_symtab->get_scope()) { - if (is_a(*item.second)) { - ASR::Function_t *s = ASR::down_cast(item.second); - visit_Function(*s); - - chdr_tmp += chdr; - pxd_tmp += pxd; - pyx_tmp += pyx; - } - } - - - chdr = chdr_tmp; - pyx = pyx_tmp; - pxd = pxd_tmp; - - cur_module.clear(); - } - - void visit_Function(const ASR::Function_t &x) { - - // Only process bind(c) subprograms for now - if (ASRUtils::get_FunctionType(x)->m_abi != ASR::abiType::BindC) return; - - // Return type and function name - bool bindc_name_not_given = ASRUtils::get_FunctionType(x)->m_bindc_name == NULL || - !strcmp("", ASRUtils::get_FunctionType(x)->m_bindc_name); - std::string effective_name = bindc_name_not_given ? x.m_name : ASRUtils::get_FunctionType(x)->m_bindc_name; - - ASR::Variable_t *rtnvar = ASRUtils::EXPR2VAR(x.m_return_var); - std::string rtnvar_type; - #define _X(ASR_TYPE, KIND, CTYPE_STR) \ - if ( is_a(*rtnvar->m_type) && (down_cast(rtnvar->m_type)->m_kind == KIND) ) { \ - rtnvar_type = CTYPE_STR; \ - } else - - CTYPELIST { - throw CodeGenError("Unrecognized or non-interoperable return type/kind"); - } - #undef _X - std::string rtnvar_name = effective_name + "_rtnval__"; - - chdr = rtnvar_type + " " + effective_name + " ("; - - std::string c_args, cy_args, call_args, pyx_body, rtn_statement; - std::tie(c_args,cy_args,call_args,pyx_body,rtn_statement) = helper_visit_arguments(x.n_args, x.m_args); - - std::string rtnarg_str = rtnvar_name; - if(!rtn_statement.empty()) rtnarg_str += ", "; - rtn_statement = " return " + rtnarg_str + rtn_statement; - - chdr += c_args + ")"; - pxd = " " + chdr + "\n"; - chdr += ";\n" ; - - pyx = "def " + effective_name + " (" + cy_args + "):\n"; - pyx += pyx_body; - pyx += " cdef " + rtnvar_type + " " + rtnvar_name + " = " + pxdf +"."+ effective_name + " (" + call_args + ")\n"; - pyx += rtn_statement + "\n\n"; - - } - -}; - -std::tuple asr_to_py(ASR::TranslationUnit_t &asr, bool c_order, std::string chdr_filename) -{ - ASRToPyVisitor v (c_order, chdr_filename); - v.visit_asr((ASR::asr_t &)asr); - - return std::make_tuple(v.chdr, v.pxd, v.pyx); -} - -} // namespace LCompilers diff --git a/src/libasr/codegen/asr_to_py.h b/src/libasr/codegen/asr_to_py.h deleted file mode 100644 index 750057f7ff..0000000000 --- a/src/libasr/codegen/asr_to_py.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef LFORTRAN_ASR_TO_PY_H -#define LFORTRAN_ASR_TO_PY_H - -#include -#include - -namespace LCompilers { - - std::tuple asr_to_py(ASR::TranslationUnit_t &asr, bool c_order, std::string chdr_filename); - -} // namespace LCompilers - -#endif // LFORTRAN_ASR_TO_PY_H diff --git a/src/libasr/codegen/asr_to_wasm.cpp b/src/libasr/codegen/asr_to_wasm.cpp deleted file mode 100644 index adf10a1f57..0000000000 --- a/src/libasr/codegen/asr_to_wasm.cpp +++ /dev/null @@ -1,2958 +0,0 @@ -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// #define SHOW_ASR - -#ifdef SHOW_ASR -#include -#endif - -namespace LCompilers { - -namespace { - -// This exception is used to abort the visitor pattern when an error occurs. -class CodeGenAbort {}; - -// Local exception that is only used in this file to exit the visitor -// pattern and caught later (not propagated outside) -class CodeGenError { - public: - diag::Diagnostic d; - - public: - CodeGenError(const std::string &msg) - : d{diag::Diagnostic(msg, diag::Level::Error, diag::Stage::CodeGen)} {} - - CodeGenError(const std::string &msg, const Location &loc) - : d{diag::Diagnostic(msg, diag::Level::Error, diag::Stage::CodeGen, - {diag::Label("", {loc})})} {} -}; - -} // namespace - -// Platform dependent fast unique hash: -static uint64_t get_hash(ASR::asr_t *node) { return (uint64_t)node; } - -struct SymbolFuncInfo { - bool needs_declaration = true; - bool intrinsic_function = false; - uint32_t index = 0; - uint32_t no_of_variables = 0; - ASR::Variable_t *return_var = nullptr; - Vec referenced_vars; -}; - -enum RT_FUNCS { - print_i64 = 0, - print_f64 = 1, - add_c32 = 2, - add_c64 = 3, - sub_c32 = 4, - sub_c64 = 5, - mul_c32 = 6, - mul_c64 = 7, - abs_c32 = 9, - abs_c64 = 10, - rt_funcs_last = 11, // keep this as the last enumerator -}; -const int NO_OF_RT_FUNCS = rt_funcs_last; - -enum GLOBAL_VAR { - cur_mem_loc = 0, - tmp_reg_f32 = 1, - tmp_reg_f64 = 2, - global_vars_cnt = 3 -}; - -enum IMPORT_FUNC { - proc_exit = 0, - fd_write = 1, - import_funcs_cnt = 2 -}; - -std::string import_fn_to_str(IMPORT_FUNC fn) { - switch(fn) { - case (IMPORT_FUNC::proc_exit): return "proc_exit"; - case (IMPORT_FUNC::fd_write): return "fd_write"; - default: throw CodeGenError("Unknown import function"); - } -} - -class ASRToWASMVisitor : public ASR::BaseVisitor { - public: - Allocator &m_al; - diag::Diagnostics &diag; - - SymbolFuncInfo *cur_sym_info; - uint32_t nesting_level; - uint32_t cur_loop_nesting_level; - bool is_prototype_only; - bool is_local_vars_only; - ASR::Function_t* main_func; - - Vec m_type_section; - Vec m_import_section; - Vec m_func_section; - Vec m_memory_section; - Vec m_global_section; - Vec m_export_section; - Vec m_code_section; - Vec m_data_section; - - uint32_t no_of_types; - uint32_t no_of_functions; - uint32_t no_of_memories; - uint32_t no_of_globals; - uint32_t no_of_exports; - uint32_t no_of_imports; - uint32_t no_of_data_segments; - uint32_t avail_mem_loc; - uint32_t digits_mem_loc; - - uint32_t min_no_pages; - uint32_t max_no_pages; - - std::map m_var_name_idx_map; - std::map m_func_name_idx_map; - std::map m_string_to_iov_loc_map; - - std::vector m_global_var_name_idx_map; - std::vector m_import_func_idx_map; - std::vector m_rt_funcs_map; - std::vector m_rt_func_used_idx; - - public: - ASRToWASMVisitor(Allocator &al, diag::Diagnostics &diagnostics) - : m_al(al), diag(diagnostics) { - is_prototype_only = false; - is_local_vars_only = false; - main_func = nullptr; - nesting_level = 0; - cur_loop_nesting_level = 0; - no_of_types = 0; - avail_mem_loc = 0; - no_of_functions = 0; - no_of_memories = 0; - no_of_globals = 0; - no_of_exports = 0; - no_of_imports = 0; - no_of_data_segments = 0; - - min_no_pages = 100; // fixed 6.4 Mb memory currently - max_no_pages = 100; // fixed 6.4 Mb memory currently - - m_type_section.reserve(m_al, 1024 * 128); - m_import_section.reserve(m_al, 1024 * 128); - m_func_section.reserve(m_al, 1024 * 128); - m_memory_section.reserve(m_al, 1024 * 128); - m_global_section.reserve(m_al, 1024 * 128); - m_export_section.reserve(m_al, 1024 * 128); - m_code_section.reserve(m_al, 1024 * 128); - m_data_section.reserve(m_al, 1024 * 128); - - m_global_var_name_idx_map.resize(global_vars_cnt); - m_import_func_idx_map.resize(import_funcs_cnt); - m_rt_funcs_map.resize(NO_OF_RT_FUNCS); - m_rt_func_used_idx = std::vector(NO_OF_RT_FUNCS, -1); - } - - void get_wasm(Vec &code) { - code.reserve(m_al, 8U /* preamble size */ + - 8U /* (section id + section size) */ * - 8U /* number of sections */ - + m_type_section.size() + - m_import_section.size() + m_func_section.size() + - m_memory_section.size() + m_global_section.size() + - m_export_section.size() + m_code_section.size() + - m_data_section.size()); - - wasm::emit_header(code, m_al); // emit header and version - wasm::encode_section( - code, m_type_section, m_al, 1U, - no_of_types); // no_of_types indicates total (imported + defined) - // no of functions - wasm::encode_section(code, m_import_section, m_al, 2U, no_of_imports); - wasm::encode_section(code, m_func_section, m_al, 3U, no_of_functions); - wasm::encode_section(code, m_memory_section, m_al, 5U, no_of_memories); - wasm::encode_section(code, m_global_section, m_al, 6U, no_of_globals); - wasm::encode_section(code, m_export_section, m_al, 7U, no_of_exports); - wasm::encode_section(code, m_code_section, m_al, 10U, no_of_functions); - wasm::encode_section(code, m_data_section, m_al, 11U, - no_of_data_segments); - } - - void import_function(IMPORT_FUNC fn, - std::vector param_types, - std::vector result_types) { - int func_idx = -1; - emit_func_type(param_types, result_types, func_idx); - m_import_func_idx_map[fn] = func_idx; - - wasm::emit_import_fn(m_import_section, m_al, "wasi_snapshot_preview1", import_fn_to_str(fn), func_idx); - no_of_imports++; - } - - void import_function2(ASR::Function_t* fn) { - if (ASRUtils::get_FunctionType(fn)->m_abi != ASR::abiType::BindC) return; - if (ASRUtils::get_FunctionType(fn)->m_deftype != ASR::deftypeType::Interface) return; - if (ASRUtils::get_FunctionType(fn)->m_abi != ASR::abiType::BindC) return; - if (ASRUtils::is_intrinsic_function2(fn)) return; - - wasm::emit_import_fn(m_import_section, m_al, "js", fn->m_name, no_of_types); - no_of_imports++; - emit_function_prototype(*fn); - } - - void emit_imports(SymbolTable *global_scope) { - using namespace wasm; - - avail_mem_loc += 4; /* initial 4 bytes to store return values of wasi funcs*/ - import_function(proc_exit, {i32}, {}); - import_function(fd_write, {i32, i32, i32, i32}, {i32}); - - // In WASM: The indices of the imports precede the indices of other - // definitions in the same index space. Therefore, declare the import - // functions before defined functions - for (auto &item : global_scope->get_scope()) { - if (ASR::is_a(*item.second)) { - ASR::Program_t *p = ASR::down_cast(item.second); - for (auto &item : p->m_symtab->get_scope()) { - if (ASR::is_a(*item.second)) { - ASR::Function_t *fn = ASR::down_cast(item.second); - import_function2(fn); - } - } - } else if (ASR::is_a(*item.second)) { - ASR::Function_t *fn = ASR::down_cast(item.second); - import_function2(fn); - } - } - } - - void emit_if_else(std::function test_cond, std::function if_block, std::function else_block) { - test_cond(); - wasm::emit_b8(m_code_section, m_al, 0x04); // emit if start - wasm::emit_b8(m_code_section, m_al, 0x40); // empty block type - nesting_level++; - if_block(); - wasm::emit_b8(m_code_section, m_al, 0x05); // starting of else - else_block(); - nesting_level--; - wasm::emit_expr_end(m_code_section, m_al); // emit if end - } - - void emit_loop(std::function test_cond, std::function loop_block) { - uint32_t prev_cur_loop_nesting_level = cur_loop_nesting_level; - cur_loop_nesting_level = nesting_level; - - wasm::emit_b8(m_code_section, m_al, 0x03); // emit loop start - wasm::emit_b8(m_code_section, m_al, 0x40); // empty block type - - nesting_level++; - - emit_if_else(test_cond, [&](){ - loop_block(); - // From WebAssembly Docs: - // Unlike with other index spaces, indexing of labels is relative by - // nesting depth, that is, label 0 refers to the innermost structured - // control instruction enclosing the referring branch instruction, while - // increasing indices refer to those farther out. - wasm::emit_branch(m_code_section, m_al, nesting_level - - cur_loop_nesting_level - 1); // emit_branch and label the loop - }, [&](){}); - - nesting_level--; - wasm::emit_expr_end(m_code_section, m_al); // end loop - cur_loop_nesting_level = prev_cur_loop_nesting_level; - } - - void emit_func_type(std::vector params, std::vector results, int &func_idx) { - wasm::emit_b8(m_type_section, m_al, 0x60); - wasm::emit_u32(m_type_section, m_al, params.size()); // no of params - for (auto param:params) { - wasm::emit_b8(m_type_section, m_al, param); - } - wasm::emit_u32(m_type_section, m_al, results.size()); // no of results - for (auto result:results) { - wasm::emit_b8(m_type_section, m_al, result); - } - if (func_idx == -1) { - func_idx = no_of_types++; - } - } - - void define_emit_func( - std::vector params, - std::vector results, - std::vector locals, - std::string func_name, - std::function func_body, - int func_idx = -1) { - - emit_func_type(params, results, func_idx); // type declaration - - /*** Reference Function Prototype ***/ - wasm::emit_u32(m_func_section, m_al, func_idx); - - /*** Function Body Starts Here ***/ - uint32_t len_idx_code_section_func_size = - wasm::emit_len_placeholder(m_code_section, m_al); - - wasm::emit_u32(m_code_section, m_al, locals.size()); - for (auto local:locals) { - wasm::emit_u32(m_code_section, m_al, 1u); // count of local vars of this type - wasm::emit_b8(m_code_section, m_al, local); - } - - func_body(); - - wasm::emit_b8(m_code_section, m_al, 0x0F); // emit wasm return instruction - wasm::emit_expr_end(m_code_section, m_al); - wasm::fixup_len(m_code_section, m_al, len_idx_code_section_func_size); - - /*** Export the function ***/ - wasm::emit_export_fn(m_export_section, m_al, func_name, func_idx); // add function to export - no_of_functions++; - no_of_exports++; - } - - void emit_print_int(int fn_idx = -1) { - using namespace wasm; - define_emit_func({i64}, {}, {i64, i64, i64, i64}, "print_i64", [&](){ - // locals 0 is given parameter - // locals 1 is digits_cnt - // locals 2 is divisor (in powers of 10) - // locals 3 is loop counter (counts upto digits_cnt (which is decreasing)) - // locals 4 is extra copy of given parameter - - emit_if_else([&](){ - wasm::emit_get_local(m_code_section, m_al, 0); - wasm::emit_i64_const(m_code_section, m_al, 0); - wasm::emit_i64_eq(m_code_section, m_al); - }, [&](){ - emit_call_fd_write(1, "0", 1, 0); - wasm::emit_b8(m_code_section, m_al, 0x0F); // emit wasm return instruction - }, [&](){}); - - emit_if_else([&](){ - wasm::emit_get_local(m_code_section, m_al, 0); - wasm::emit_i64_const(m_code_section, m_al, 0); - wasm::emit_i64_lt_s(m_code_section, m_al); - }, [&](){ - emit_call_fd_write(1, "-", 1, 0); - wasm::emit_get_local(m_code_section, m_al, 0); - wasm::emit_i64_const(m_code_section, m_al, -1); - wasm::emit_i64_mul(m_code_section, m_al); - wasm::emit_set_local(m_code_section, m_al, 0); - }, [&](){}); - - wasm::emit_get_local(m_code_section, m_al, 0); - wasm::emit_set_local(m_code_section, m_al, 4); - wasm::emit_i64_const(m_code_section, m_al, 0); - wasm::emit_set_local(m_code_section, m_al, 1); - - emit_loop([&](){ - wasm::emit_get_local(m_code_section, m_al, 0); - wasm::emit_i64_const(m_code_section, m_al, 0); - wasm::emit_i64_gt_s(m_code_section, m_al); - }, [&](){ - wasm::emit_get_local(m_code_section, m_al, 1); - wasm::emit_i64_const(m_code_section, m_al, 1); - wasm::emit_i64_add(m_code_section, m_al); - wasm::emit_set_local(m_code_section, m_al, 1); - wasm::emit_get_local(m_code_section, m_al, 0); - wasm::emit_i64_const(m_code_section, m_al, 10); - wasm::emit_i64_div_s(m_code_section, m_al); - wasm::emit_set_local(m_code_section, m_al, 0); - }); - - emit_loop([&](){ - wasm::emit_get_local(m_code_section, m_al, 1); - wasm::emit_i64_const(m_code_section, m_al, 0); - wasm::emit_i64_gt_s(m_code_section, m_al); - }, [&](){ - wasm::emit_get_local(m_code_section, m_al, 1); - wasm::emit_i64_const(m_code_section, m_al, 1); - wasm::emit_i64_sub(m_code_section, m_al); - wasm::emit_set_local(m_code_section, m_al, 1); - - wasm::emit_i64_const(m_code_section, m_al, 1); - wasm::emit_set_local(m_code_section, m_al, 2); - wasm::emit_i64_const(m_code_section, m_al, 0); - wasm::emit_set_local(m_code_section, m_al, 3); - - emit_loop([&](){ - wasm::emit_get_local(m_code_section, m_al, 3); - wasm::emit_get_local(m_code_section, m_al, 1); - wasm::emit_i64_lt_s(m_code_section, m_al); - }, [&](){ - wasm::emit_get_local(m_code_section, m_al, 3); - wasm::emit_i64_const(m_code_section, m_al, 1); - wasm::emit_i64_add(m_code_section, m_al); - wasm::emit_set_local(m_code_section, m_al, 3); - wasm::emit_get_local(m_code_section, m_al, 2); - wasm::emit_i64_const(m_code_section, m_al, 10); - wasm::emit_i64_mul(m_code_section, m_al); - wasm::emit_set_local(m_code_section, m_al, 2); - }); - - - wasm::emit_get_local(m_code_section, m_al, 4); - wasm::emit_get_local(m_code_section, m_al, 2); - wasm::emit_i64_div_s(m_code_section, m_al); - wasm::emit_i64_const(m_code_section, m_al, 10); - wasm::emit_i64_rem_s(m_code_section, m_al); - - /* The digit is on stack */ - wasm::emit_i64_const(m_code_section, m_al, 12 /* 4 + 4 + 4 (iov vec + str size)*/); - wasm::emit_i64_mul(m_code_section, m_al); - wasm::emit_i64_const(m_code_section, m_al, digits_mem_loc); - wasm::emit_i64_add(m_code_section, m_al); - wasm::emit_set_local(m_code_section, m_al, 0); // temporary save - - { - wasm::emit_i32_const(m_code_section, m_al, 1); // file type: 1 for stdout - wasm::emit_get_local(m_code_section, m_al, 0); // use stored digit - wasm::emit_i32_wrap_i64(m_code_section, m_al); - wasm::emit_i32_const(m_code_section, m_al, 1); // size of iov vector - wasm::emit_i32_const(m_code_section, m_al, 0); // mem_loction to return no. of bytes written - // call WASI fd_write - wasm::emit_call(m_code_section, m_al, m_import_func_idx_map[fd_write]); - wasm::emit_drop(m_code_section, m_al); - } - - }); - }, fn_idx); - } - - void emit_print_float(int fn_idx = -1) { - using namespace wasm; - define_emit_func({f64}, {}, {i64, i64, i64}, "print_f64", [&](){ - emit_if_else([&](){ - wasm::emit_get_local(m_code_section, m_al, 0); - wasm::emit_f64_const(m_code_section, m_al, 0); - wasm::emit_f64_lt(m_code_section, m_al); - }, [&](){ - emit_call_fd_write(1, "-", 1, 0); - wasm::emit_get_local(m_code_section, m_al, 0); - wasm::emit_f64_const(m_code_section, m_al, -1); - wasm::emit_f64_mul(m_code_section, m_al); - wasm::emit_set_local(m_code_section, m_al, 0); - }, [&](){}); - - wasm::emit_get_local(m_code_section, m_al, 0); - wasm::emit_i64_trunc_f64_s(m_code_section, m_al); - wasm::emit_call(m_code_section, m_al, m_rt_func_used_idx[print_i64]); - emit_call_fd_write(1, ".", 1, 0); - - wasm::emit_get_local(m_code_section, m_al, 0); - wasm::emit_get_local(m_code_section, m_al, 0); - wasm::emit_i64_trunc_f64_s(m_code_section, m_al); - wasm::emit_f64_convert_i64_s(m_code_section, m_al); - wasm::emit_f64_sub(m_code_section, m_al); - wasm::emit_f64_const(m_code_section, m_al, 1e8); - wasm::emit_f64_mul(m_code_section, m_al); - wasm::emit_i64_trunc_f64_s(m_code_section, m_al); - wasm::emit_set_local(m_code_section, m_al, 2); /* save the current fractional part value */ - wasm::emit_get_local(m_code_section, m_al, 2); - wasm::emit_set_local(m_code_section, m_al, 3); /* save the another copy */ - - wasm::emit_i64_const(m_code_section, m_al, 0); - wasm::emit_set_local(m_code_section, m_al, 1); // digits_cnt - - emit_loop([&](){ - wasm::emit_get_local(m_code_section, m_al, 2); - wasm::emit_i64_const(m_code_section, m_al, 0); - wasm::emit_i64_gt_s(m_code_section, m_al); - }, [&](){ - wasm::emit_get_local(m_code_section, m_al, 1); - wasm::emit_i64_const(m_code_section, m_al, 1); - wasm::emit_i64_add(m_code_section, m_al); - wasm::emit_set_local(m_code_section, m_al, 1); - - wasm::emit_get_local(m_code_section, m_al, 2); - wasm::emit_f64_convert_i64_s(m_code_section, m_al); - wasm::emit_i64_const(m_code_section, m_al, 10); - wasm::emit_f64_convert_i64_s(m_code_section, m_al); - wasm::emit_f64_div(m_code_section, m_al); - wasm::emit_i64_trunc_f64_s(m_code_section, m_al); - wasm::emit_set_local(m_code_section, m_al, 2); - }); - - emit_loop([&](){ - wasm::emit_get_local(m_code_section, m_al, 1); - wasm::emit_i64_const(m_code_section, m_al, 8); - wasm::emit_i64_lt_s(m_code_section, m_al); - }, [&](){ - wasm::emit_get_local(m_code_section, m_al, 1); - wasm::emit_i64_const(m_code_section, m_al, 1); - wasm::emit_i64_add(m_code_section, m_al); - wasm::emit_set_local(m_code_section, m_al, 1); - - emit_call_fd_write(1, "0", 1, 0); - }); - - wasm::emit_get_local(m_code_section, m_al, 3); - wasm::emit_call(m_code_section, m_al, m_rt_func_used_idx[print_i64]); - }, fn_idx); - } - - void emit_complex_add_32(int fn_idx = -1) { - using namespace wasm; - define_emit_func({f32, f32, f32, f32}, {f32, f32}, {}, "add_c32", [&](){ - wasm::emit_get_local(m_code_section, m_al, 0); - wasm::emit_get_local(m_code_section, m_al, 2); - wasm::emit_f32_add(m_code_section, m_al); - - wasm::emit_get_local(m_code_section, m_al, 1); - wasm::emit_get_local(m_code_section, m_al, 3); - wasm::emit_f32_add(m_code_section, m_al); - }, fn_idx); - } - - void emit_complex_add_64(int fn_idx = -1) { - using namespace wasm; - define_emit_func({f64, f64, f64, f64}, {f64, f64}, {}, "add_c64", [&](){ - wasm::emit_get_local(m_code_section, m_al, 0); - wasm::emit_get_local(m_code_section, m_al, 2); - wasm::emit_f64_add(m_code_section, m_al); - - wasm::emit_get_local(m_code_section, m_al, 1); - wasm::emit_get_local(m_code_section, m_al, 3); - wasm::emit_f64_add(m_code_section, m_al); - }, fn_idx); - } - - void emit_complex_sub_32(int fn_idx = -1) { - using namespace wasm; - define_emit_func({f32, f32, f32, f32}, {f32, f32}, {}, "sub_c32", [&](){ - wasm::emit_get_local(m_code_section, m_al, 0); - wasm::emit_get_local(m_code_section, m_al, 2); - wasm::emit_f32_sub(m_code_section, m_al); - - wasm::emit_get_local(m_code_section, m_al, 1); - wasm::emit_get_local(m_code_section, m_al, 3); - wasm::emit_f32_sub(m_code_section, m_al); - }, fn_idx); - } - - void emit_complex_sub_64(int fn_idx = -1) { - using namespace wasm; - define_emit_func({f64, f64, f64, f64}, {f64, f64}, {}, "sub_c64", [&](){ - wasm::emit_get_local(m_code_section, m_al, 0); - wasm::emit_get_local(m_code_section, m_al, 2); - wasm::emit_f64_sub(m_code_section, m_al); - - wasm::emit_get_local(m_code_section, m_al, 1); - wasm::emit_get_local(m_code_section, m_al, 3); - wasm::emit_f64_sub(m_code_section, m_al); - }, fn_idx); - } - - void emit_complex_mul_32(int fn_idx = -1) { - using namespace wasm; - define_emit_func({f32, f32, f32, f32}, {f32, f32}, {}, "mul_c32", [&](){ - wasm::emit_get_local(m_code_section, m_al, 0); - wasm::emit_get_local(m_code_section, m_al, 2); - wasm::emit_f32_mul(m_code_section, m_al); - - wasm::emit_get_local(m_code_section, m_al, 1); - wasm::emit_get_local(m_code_section, m_al, 3); - wasm::emit_f32_mul(m_code_section, m_al); - - wasm::emit_f32_sub(m_code_section, m_al); - - wasm::emit_get_local(m_code_section, m_al, 0); - wasm::emit_get_local(m_code_section, m_al, 3); - wasm::emit_f32_mul(m_code_section, m_al); - - wasm::emit_get_local(m_code_section, m_al, 1); - wasm::emit_get_local(m_code_section, m_al, 2); - wasm::emit_f32_mul(m_code_section, m_al); - - wasm::emit_f32_add(m_code_section, m_al); - }, fn_idx); - } - - void emit_complex_mul_64(int fn_idx = -1) { - using namespace wasm; - define_emit_func({f64, f64, f64, f64}, {f64, f64}, {}, "mul_c64", [&](){ - wasm::emit_get_local(m_code_section, m_al, 0); - wasm::emit_get_local(m_code_section, m_al, 2); - wasm::emit_f64_mul(m_code_section, m_al); - - wasm::emit_get_local(m_code_section, m_al, 1); - wasm::emit_get_local(m_code_section, m_al, 3); - wasm::emit_f64_mul(m_code_section, m_al); - - wasm::emit_f64_sub(m_code_section, m_al); - - wasm::emit_get_local(m_code_section, m_al, 0); - wasm::emit_get_local(m_code_section, m_al, 3); - wasm::emit_f64_mul(m_code_section, m_al); - - wasm::emit_get_local(m_code_section, m_al, 1); - wasm::emit_get_local(m_code_section, m_al, 2); - wasm::emit_f64_mul(m_code_section, m_al); - - wasm::emit_f64_add(m_code_section, m_al); - }, fn_idx); - } - - void emit_complex_abs_32(int fn_idx = -1) { - using namespace wasm; - define_emit_func({f32, f32}, {f32}, {}, "abs_c32", [&](){ - wasm::emit_get_local(m_code_section, m_al, 0); - wasm::emit_get_local(m_code_section, m_al, 0); - wasm::emit_f32_mul(m_code_section, m_al); - - wasm::emit_get_local(m_code_section, m_al, 1); - wasm::emit_get_local(m_code_section, m_al, 1); - wasm::emit_f32_mul(m_code_section, m_al); - - wasm::emit_f32_add(m_code_section, m_al); - wasm::emit_f32_sqrt(m_code_section, m_al); - }, fn_idx); - } - - void emit_complex_abs_64(int fn_idx = -1) { - using namespace wasm; - define_emit_func({f64, f64}, {f64}, {}, "abs_c64", [&](){ - wasm::emit_get_local(m_code_section, m_al, 0); - wasm::emit_get_local(m_code_section, m_al, 0); - wasm::emit_f64_mul(m_code_section, m_al); - - wasm::emit_get_local(m_code_section, m_al, 1); - wasm::emit_get_local(m_code_section, m_al, 1); - wasm::emit_f64_mul(m_code_section, m_al); - - wasm::emit_f64_add(m_code_section, m_al); - wasm::emit_f64_sqrt(m_code_section, m_al); - }, fn_idx); - } - - template - void declare_global_var(wasm::type var_type, GLOBAL_VAR name, T initial_value, bool isMutable) { - m_global_section.push_back(m_al, var_type); - m_global_section.push_back(m_al, isMutable); - switch (var_type) - { - case wasm::type::i32: wasm::emit_i32_const(m_global_section, m_al, initial_value); break; - case wasm::type::i64: wasm::emit_i64_const(m_global_section, m_al, initial_value); break; - case wasm::type::f32: wasm::emit_f32_const(m_global_section, m_al, initial_value); break; - case wasm::type::f64: wasm::emit_f64_const(m_global_section, m_al, initial_value); break; - default: throw CodeGenError("declare_global_var: Unsupport var_type"); break; - } - wasm::emit_expr_end(m_global_section, m_al); // end instructions - m_global_var_name_idx_map[name] = no_of_globals; - no_of_globals++; - } - - void declare_symbols(const ASR::TranslationUnit_t &x) { - { - // Process intrinsic modules in the right order - std::vector build_order = - ASRUtils::determine_module_dependencies(x); - for (auto &item : build_order) { - LCOMPILERS_ASSERT(x.m_global_scope->get_scope().find(item) != - x.m_global_scope->get_scope().end()); - ASR::symbol_t *mod = x.m_global_scope->get_symbol(item); - this->visit_symbol(*mod); - } - } - - // Process procedures first: - declare_all_functions(*x.m_global_scope); - - // then the main program: - for (auto &item : x.m_global_scope->get_scope()) { - if (ASR::is_a(*item.second)) { - visit_symbol(*item.second); - } - } - } - - void visit_TranslationUnit(const ASR::TranslationUnit_t &x) { - // All loose statements must be converted to a function, so the items - // must be empty: - LCOMPILERS_ASSERT(x.n_items == 0); - - emit_imports(x.m_global_scope); - - wasm::emit_declare_mem(m_memory_section, m_al, min_no_pages, max_no_pages); - no_of_memories++; - wasm::emit_export_mem(m_export_section, m_al, "memory", 0 /* mem_idx */); - no_of_exports++; - - declare_global_var(wasm::type::i32, cur_mem_loc, 0, true); - declare_global_var(wasm::type::f32, tmp_reg_f32, 0, true); - declare_global_var(wasm::type::f64, tmp_reg_f64, 0, true); - - emit_string(" "); - emit_string("\n"); - emit_string("-"); - emit_string("."); - emit_string("("); - emit_string(")"); - emit_string(","); - digits_mem_loc = avail_mem_loc; - for (int i = 0; i < 10; i++) { - emit_string(std::to_string(i)); - } - - m_rt_funcs_map[print_i64] = &ASRToWASMVisitor::emit_print_int; - m_rt_funcs_map[print_f64] = &ASRToWASMVisitor::emit_print_float; - m_rt_funcs_map[add_c32] = &ASRToWASMVisitor::emit_complex_add_32; - m_rt_funcs_map[add_c64] = &ASRToWASMVisitor::emit_complex_add_64; - m_rt_funcs_map[sub_c32] = &ASRToWASMVisitor::emit_complex_sub_32; - m_rt_funcs_map[sub_c64] = &ASRToWASMVisitor::emit_complex_sub_64; - m_rt_funcs_map[mul_c32] = &ASRToWASMVisitor::emit_complex_mul_32; - m_rt_funcs_map[mul_c64] = &ASRToWASMVisitor::emit_complex_mul_64; - m_rt_funcs_map[abs_c32] = &ASRToWASMVisitor::emit_complex_abs_32; - m_rt_funcs_map[abs_c64] = &ASRToWASMVisitor::emit_complex_abs_64; - - { - // Pre-declare all functions first, then generate code - // Otherwise some function might not be found. - is_prototype_only = true; - declare_symbols(x); - is_prototype_only = false; - } - declare_symbols(x); - - - std::vector> ordered_rt_funcs_type_idx; - for (int i = 0; i < NO_OF_RT_FUNCS; i++) { - if (m_rt_func_used_idx[i] != -1) { - ordered_rt_funcs_type_idx.push_back(std::make_pair(m_rt_func_used_idx[i], i)); - } - } - - sort(ordered_rt_funcs_type_idx.begin(), ordered_rt_funcs_type_idx.end()); - - for (auto rt_func:ordered_rt_funcs_type_idx) { - (this->*m_rt_funcs_map[rt_func.second])(rt_func.first); - } - } - - void declare_all_functions(const SymbolTable &symtab) { - for (auto &item : symtab.get_scope()) { - if (ASR::is_a(*item.second)) { - ASR::Function_t *s = - ASR::down_cast(item.second); - if (ASRUtils::get_FunctionType(s)->n_type_params == 0) { - this->visit_Function(*s); - } - } - } - } - - void visit_Module(const ASR::Module_t &x) { - // Generate the bodies of functions and subroutines - declare_all_functions(*x.m_symtab); - } - - void visit_Program(const ASR::Program_t &x) { - // Generate the bodies of functions and subroutines - declare_all_functions(*x.m_symtab); - - // Generate main program code - if (main_func == nullptr) { - main_func = (ASR::Function_t *)ASRUtils::make_Function_t_util( - m_al, x.base.base.loc, x.m_symtab, s2c(m_al, "_start"), - nullptr, 0, nullptr, 0, x.m_body, x.n_body, nullptr, - ASR::abiType::Source, ASR::accessType::Public, - ASR::deftypeType::Implementation, nullptr, false, false, false, false, false, - nullptr, 0, nullptr, 0, false, false, false); - } - this->visit_Function(*main_func); - } - - void emit_var_type(Vec &code, ASR::Variable_t *v) { - // bool use_ref = (v->m_intent == ASRUtils::intent_out || - // v->m_intent == ASRUtils::intent_inout); - bool is_array = ASRUtils::is_array(v->m_type); - - if (ASRUtils::is_pointer(v->m_type)) { - ASR::ttype_t *t2 = - ASR::down_cast(v->m_type)->m_type; - if (ASRUtils::is_integer(*t2)) { - ASR::Integer_t *t = ASR::down_cast(t2); - // size_t size; - diag.codegen_warning_label( - "Pointers are not currently supported", {v->base.base.loc}, - "emitting integer for now"); - if (t->m_kind == 4) { - wasm::emit_b8(code, m_al, wasm::type::i32); - } else if (t->m_kind == 8) { - wasm::emit_b8(code, m_al, wasm::type::i64); - } else { - throw CodeGenError( - "Integers of kind 4 and 8 only supported"); - } - } else { - diag.codegen_error_label("Type number '" + - std::to_string(v->m_type->type) + - "' not supported", - {v->base.base.loc}, ""); - throw CodeGenAbort(); - } - } else { - if (ASRUtils::is_integer(*v->m_type)) { - ASR::Integer_t *v_int = - ASR::down_cast(v->m_type); - if (is_array) { - wasm::emit_b8(code, m_al, wasm::type::i32); - } else { - if (v_int->m_kind == 4) { - wasm::emit_b8(code, m_al, wasm::type::i32); - } else if (v_int->m_kind == 8) { - wasm::emit_b8(code, m_al, wasm::type::i64); - } else { - throw CodeGenError( - "Integers of kind 4 and 8 only supported"); - } - } - } else if (ASRUtils::is_real(*v->m_type)) { - ASR::Real_t *v_float = ASR::down_cast(v->m_type); - - if (is_array) { - wasm::emit_b8(code, m_al, wasm::type::i32); - } else { - if (v_float->m_kind == 4) { - wasm::emit_b8(code, m_al, wasm::type::f32); - } else if (v_float->m_kind == 8) { - wasm::emit_b8(code, m_al, wasm::type::f64); - } else { - throw CodeGenError( - "Floating Points of kind 4 and 8 only supported"); - } - } - } else if (ASRUtils::is_logical(*v->m_type)) { - ASR::Logical_t *v_logical = - ASR::down_cast(v->m_type); - - if (is_array) { - wasm::emit_b8(code, m_al, wasm::type::i32); - } else { - // All Logicals are represented as i32 in WASM - if (v_logical->m_kind == 4) { - wasm::emit_b8(code, m_al, wasm::type::i32); - } else { - throw CodeGenError("Logicals of kind 4 only supported"); - } - } - } else if (ASRUtils::is_character(*v->m_type)) { - ASR::Character_t *v_int = - ASR::down_cast(v->m_type); - - if (is_array) { - wasm::emit_b8(code, m_al, wasm::type::i32); - } else { - if (v_int->m_kind == 1) { - /* Character is stored as string in memory. - The variable points to this location in memory - */ - wasm::emit_b8(code, m_al, wasm::type::i32); - } else { - throw CodeGenError( - "Characters of kind 1 only supported"); - } - } - } else if (ASRUtils::is_complex(*v->m_type)) { - ASR::Complex_t *v_comp = - ASR::down_cast(v->m_type); - - if (is_array) { - wasm::emit_b8(code, m_al, wasm::type::i32); - } else { - if (v_comp->m_kind == 4) { - wasm::emit_b8(code, m_al, wasm::type::f32); - } else if (v_comp->m_kind == 8) { - wasm::emit_b8(code, m_al, wasm::type::f64); - } else { - throw CodeGenError( - "Complex numbers of kind 4 and 8 only supported yet"); - } - } - } else { - // throw CodeGenError("Param, Result, Var Types other than - // integer, floating point and logical not yet supported"); - diag.codegen_warning_label("Unsupported variable type: " + - ASRUtils::type_to_str(v->m_type), - {v->base.base.loc}, "here"); - } - } - } - - void emit_local_vars(SymbolTable* symtab) { - for (auto &item : symtab->get_scope()) { - if (ASR::is_a(*item.second)) { - ASR::Variable_t *v = - ASR::down_cast(item.second); - if (v->m_intent == ASRUtils::intent_local || - v->m_intent == ASRUtils::intent_return_var) { - wasm::emit_u32(m_code_section, m_al, 1U); // count of local vars of this type - emit_var_type(m_code_section, v); // emit the type of this var - m_var_name_idx_map[get_hash((ASR::asr_t *)v)] = cur_sym_info->no_of_variables++; - if (!ASRUtils::is_array(v->m_type) && ASRUtils::is_complex(*v->m_type)) { - // emit type again for imaginary part - wasm::emit_u32(m_code_section, m_al, 1U); // count of local vars of this type - emit_var_type(m_code_section, v); // emit the type of this var - cur_sym_info->no_of_variables++; - } - } - } - } - } - - void initialize_local_vars(SymbolTable* symtab) { - // initialize the value for local variables if initialization exists - for (auto &item : symtab->get_scope()) { - if (ASR::is_a(*item.second)) { - ASR::Variable_t *v = - ASR::down_cast(item.second); - if (v->m_intent == ASRUtils::intent_local || - v->m_intent == ASRUtils::intent_return_var) { - if (v->m_symbolic_value) { - this->visit_expr(*v->m_symbolic_value); - // Todo: Checking for Array is currently omitted - LCOMPILERS_ASSERT(m_var_name_idx_map.find( - get_hash((ASR::asr_t *)v)) != - m_var_name_idx_map.end()) - if (ASRUtils::is_complex(*v->m_type)) { - wasm::emit_set_local( - m_code_section, m_al, - m_var_name_idx_map[get_hash((ASR::asr_t *)v)] + 1); - } - wasm::emit_set_local( - m_code_section, m_al, - m_var_name_idx_map[get_hash((ASR::asr_t *)v)]); - } else if (ASRUtils::is_array(v->m_type)) { - uint32_t kind = - ASRUtils::extract_kind_from_ttype_t(v->m_type); - - Vec array_dims; - get_array_dims(*v, array_dims); - - uint32_t total_array_size = 1; - for (auto &dim : array_dims) { - total_array_size *= dim; - } - - LCOMPILERS_ASSERT(m_var_name_idx_map.find( - get_hash((ASR::asr_t *)v)) != - m_var_name_idx_map.end()); - wasm::emit_i32_const(m_code_section, m_al, - avail_mem_loc); - wasm::emit_set_local( - m_code_section, m_al, - m_var_name_idx_map[get_hash((ASR::asr_t *)v)]); - avail_mem_loc += kind * total_array_size; - } - } - } - } - } - void emit_function_prototype(const ASR::Function_t &x) { - SymbolFuncInfo *s = new SymbolFuncInfo; - - /********************* New Type Declaration *********************/ - wasm::emit_b8(m_type_section, m_al, 0x60); - - /********************* Parameter Types List *********************/ - s->referenced_vars.reserve(m_al, x.n_args); - wasm::emit_u32(m_type_section, m_al, x.n_args); - for (size_t i = 0; i < x.n_args; i++) { - ASR::Variable_t *arg = ASRUtils::EXPR2VAR(x.m_args[i]); - LCOMPILERS_ASSERT(ASRUtils::is_arg_dummy(arg->m_intent)); - emit_var_type(m_type_section, arg); - m_var_name_idx_map[get_hash((ASR::asr_t *)arg)] = - s->no_of_variables++; - if (!ASRUtils::is_array(arg->m_type) && ASRUtils::is_complex(*arg->m_type)) { - // emit type again for imaginary part - emit_var_type(m_type_section, arg); // emit the type of this var - s->no_of_variables++; - } - if (arg->m_intent == ASR::intentType::Out || - arg->m_intent == ASR::intentType::InOut || - arg->m_intent == ASR::intentType::Unspecified) { - s->referenced_vars.push_back(m_al, arg); - } - } - - /********************* Result Types List *********************/ - if (x.m_return_var) { // It is a function - s->return_var = ASRUtils::EXPR2VAR(x.m_return_var); - if (!ASRUtils::is_array(s->return_var->m_type) && ASRUtils::is_complex(*s->return_var->m_type)) { - wasm::emit_u32(m_type_section, m_al, 2U); // there are two return variables - // emit type for real part - emit_var_type(m_type_section, s->return_var); // emit the type of this var - // emit type again for imaginary part - emit_var_type(m_type_section, s->return_var); // emit the type of this var - } else { - wasm::emit_u32(m_type_section, m_al, 1U); // there is just one return variable - emit_var_type(m_type_section, s->return_var); - } - } else { // It is a subroutine - uint32_t len_idx_type_section_return_types_list = - wasm::emit_len_placeholder(m_type_section, m_al); - for (size_t i = 0; i < x.n_args; i++) { - ASR::Variable_t *arg = ASRUtils::EXPR2VAR(x.m_args[i]); - if (arg->m_intent == ASR::intentType::Out || - arg->m_intent == ASR::intentType::InOut || - arg->m_intent == ASR::intentType::Unspecified) { - emit_var_type(m_type_section, arg); - if (!ASRUtils::is_array(arg->m_type) && ASRUtils::is_complex(*arg->m_type)) { - // emit type again for imaginary part - emit_var_type(m_type_section, arg); // emit the type of this var - } - } - } - wasm::fixup_len(m_type_section, m_al, - len_idx_type_section_return_types_list); - } - - /********************* Add Type to Map *********************/ - s->index = no_of_types++; - m_func_name_idx_map[get_hash((ASR::asr_t *)&x)] = - s; // add function to map - } - - template - void visit_BlockStatements(const T& x) { - for (size_t i = 0; i < x.n_body; i++) { - if (ASR::is_a(*x.m_body[i])) { - this->visit_stmt(*x.m_body[i]); - } - } - } - - void emit_function_body(const ASR::Function_t &x) { - LCOMPILERS_ASSERT(m_func_name_idx_map.find(get_hash((ASR::asr_t *)&x)) != - m_func_name_idx_map.end()); - - cur_sym_info = m_func_name_idx_map[get_hash((ASR::asr_t *)&x)]; - - /********************* Reference Function Prototype - * *********************/ - wasm::emit_u32(m_func_section, m_al, cur_sym_info->index); - - /********************* Function Body Starts Here *********************/ - uint32_t len_idx_code_section_func_size = - wasm::emit_len_placeholder(m_code_section, m_al); - - { - is_local_vars_only = true; - int params_cnt = cur_sym_info->no_of_variables; - /********************* Local Vars Types List *********************/ - uint32_t len_idx_code_section_local_vars_list = - wasm::emit_len_placeholder(m_code_section, m_al); - - emit_local_vars(x.m_symtab); - visit_BlockStatements(x); - - // fixup length of local vars list - wasm::emit_u32_b32_idx(m_code_section, m_al, - len_idx_code_section_local_vars_list, - cur_sym_info->no_of_variables - params_cnt); - is_local_vars_only = false; - } - - initialize_local_vars(x.m_symtab); - - for (size_t i = 0; i < x.n_body; i++) { - this->visit_stmt(*x.m_body[i]); - } - - if (strcmp(x.m_name, "_start") == 0) { - wasm::emit_i32_const(m_code_section, m_al, 0 /* zero exit code */); - wasm::emit_call(m_code_section, m_al, m_import_func_idx_map[proc_exit]); - } - - if (x.n_body == 0 || !ASR::is_a(*x.m_body[x.n_body - 1])) { - handle_return(); - } - wasm::emit_expr_end(m_code_section, m_al); - - wasm::fixup_len(m_code_section, m_al, len_idx_code_section_func_size); - - /********************* Export the function *********************/ - wasm::emit_export_fn(m_export_section, m_al, x.m_name, - cur_sym_info->index); // add function to export - no_of_functions++; - no_of_exports++; - } - - bool is_unsupported_function(const ASR::Function_t &x) { - if (!x.n_body) { - return true; - } - if (ASRUtils::get_FunctionType(x)->m_abi == ASR::abiType::BindC && - ASRUtils::get_FunctionType(x)->m_deftype == ASR::deftypeType::Interface) { - if (ASRUtils::is_intrinsic_function2(&x)) { - diag.codegen_warning_label( - "WASM: C Intrinsic Functions not yet supported", - {x.base.base.loc}, std::string(x.m_name)); - } - return true; - } - for (size_t i = 0; i < x.n_body; i++) { - if (x.m_body[i]->type == ASR::stmtType::SubroutineCall) { - auto sub_call = (const ASR::SubroutineCall_t &)(*x.m_body[i]); - ASR::Function_t *s = ASR::down_cast( - ASRUtils::symbol_get_past_external(sub_call.m_name)); - if (ASRUtils::get_FunctionType(s)->m_abi == ASR::abiType::BindC && - ASRUtils::get_FunctionType(s)->m_deftype == ASR::deftypeType::Interface && - ASRUtils::is_intrinsic_function2(s)) { - diag.codegen_warning_label( - "WASM: Calls to C Intrinsic Functions are not yet " - "supported", - {x.m_body[i]->base.loc}, - "Function: calls " + std::string(s->m_name)); - return true; - } - } - } - return false; - } - - void visit_Function(const ASR::Function_t &x) { - if (is_unsupported_function(x)) { - return; - } - if (is_prototype_only) { - emit_function_prototype(x); - return; - } - emit_function_body(x); - } - - void visit_BlockCall(const ASR::BlockCall_t &x) { - LCOMPILERS_ASSERT(ASR::is_a(*x.m_m)); - ASR::Block_t* block = ASR::down_cast(x.m_m); - if (is_local_vars_only) { - emit_local_vars(block->m_symtab); - visit_BlockStatements(*block); - } else { - initialize_local_vars(block->m_symtab); - for (size_t i = 0; i < block->n_body; i++) { - this->visit_stmt(*block->m_body[i]); - } - } - } - - uint32_t emit_memory_store(ASR::expr_t *v) { - auto ttype = ASRUtils::expr_type(v); - auto kind = ASRUtils::extract_kind_from_ttype_t(ttype); - switch (ttype->type) { - case ASR::ttypeType::Integer: { - switch (kind) { - case 4: - wasm::emit_i32_store(m_code_section, m_al, - wasm::mem_align::b8, 0); - break; - case 8: - wasm::emit_i64_store(m_code_section, m_al, - wasm::mem_align::b8, 0); - break; - default: - throw CodeGenError( - "MemoryStore: Unsupported Integer kind"); - } - break; - } - case ASR::ttypeType::Real: { - switch (kind) { - case 4: - wasm::emit_f32_store(m_code_section, m_al, - wasm::mem_align::b8, 0); - break; - case 8: - wasm::emit_f64_store(m_code_section, m_al, - wasm::mem_align::b8, 0); - break; - default: - throw CodeGenError( - "MemoryStore: Unsupported Real kind"); - } - break; - } - case ASR::ttypeType::Logical: { - switch (kind) { - case 4: - wasm::emit_i32_store(m_code_section, m_al, - wasm::mem_align::b8, 0); - break; - default: - throw CodeGenError( - "MemoryStore: Unsupported Logical kind"); - } - break; - } - case ASR::ttypeType::Character: { - switch (kind) { - case 4: - wasm::emit_i32_store(m_code_section, m_al, - wasm::mem_align::b8, 0); - break; - case 8: - wasm::emit_i64_store(m_code_section, m_al, - wasm::mem_align::b8, 0); - break; - default: - throw CodeGenError( - "MemoryStore: Unsupported Character kind"); - } - break; - } - default: { - throw CodeGenError("MemoryStore: Type " + - ASRUtils::type_to_str(ttype) + - " not yet supported"); - } - } - return kind; - } - - void emit_memory_load(ASR::expr_t *v) { - auto ttype = ASRUtils::expr_type(v); - auto kind = ASRUtils::extract_kind_from_ttype_t(ttype); - switch (ttype->type) { - case ASR::ttypeType::Integer: { - switch (kind) { - case 4: - wasm::emit_i32_load(m_code_section, m_al, - wasm::mem_align::b8, 0); - break; - case 8: - wasm::emit_i64_load(m_code_section, m_al, - wasm::mem_align::b8, 0); - break; - default: - throw CodeGenError( - "MemoryLoad: Unsupported Integer kind"); - } - break; - } - case ASR::ttypeType::Real: { - switch (kind) { - case 4: - wasm::emit_f32_load(m_code_section, m_al, - wasm::mem_align::b8, 0); - break; - case 8: - wasm::emit_f64_load(m_code_section, m_al, - wasm::mem_align::b8, 0); - break; - default: - throw CodeGenError("MemoryLoad: Unsupported Real kind"); - } - break; - } - case ASR::ttypeType::Logical: { - switch (kind) { - case 4: - wasm::emit_i32_load(m_code_section, m_al, - wasm::mem_align::b8, 0); - break; - default: - throw CodeGenError( - "MemoryLoad: Unsupported Logical kind"); - } - break; - } - case ASR::ttypeType::Character: { - switch (kind) { - case 4: - wasm::emit_i32_load(m_code_section, m_al, - wasm::mem_align::b8, 0); - break; - case 8: - wasm::emit_i64_load(m_code_section, m_al, - wasm::mem_align::b8, 0); - break; - default: - throw CodeGenError( - "MemoryLoad: Unsupported Character kind"); - } - break; - } - default: { - throw CodeGenError("MemoryLoad: Type " + - ASRUtils::type_to_str(ttype) + - " not yet supported"); - } - } - } - - void visit_Assignment(const ASR::Assignment_t &x) { - // this->visit_expr(*x.m_target); - if (ASR::is_a(*x.m_target)) { - this->visit_expr(*x.m_value); - ASR::Variable_t *asr_target = ASRUtils::EXPR2VAR(x.m_target); - LCOMPILERS_ASSERT( - m_var_name_idx_map.find(get_hash((ASR::asr_t *)asr_target)) != - m_var_name_idx_map.end()); - if (ASRUtils::is_complex(*asr_target->m_type)) { - // first set the imaginary part - wasm::emit_set_local(m_code_section, m_al, - m_var_name_idx_map[get_hash((ASR::asr_t *)asr_target)] + 1u); - } - wasm::emit_set_local( - m_code_section, m_al, - m_var_name_idx_map[get_hash((ASR::asr_t *)asr_target)]); - } else if (ASR::is_a(*x.m_target)) { - emit_array_item_address_onto_stack( - *(ASR::down_cast(x.m_target))); - this->visit_expr(*x.m_value); - emit_memory_store(x.m_value); - } else { - LCOMPILERS_ASSERT(false) - } - } - - void visit_IntegerBinOp(const ASR::IntegerBinOp_t &x) { - if (x.m_value) { - visit_expr(*x.m_value); - return; - } - this->visit_expr(*x.m_left); - this->visit_expr(*x.m_right); - ASR::Integer_t *i = ASR::down_cast(x.m_type); - if (i->m_kind == 4) { - switch (x.m_op) { - case ASR::binopType::Add: { - wasm::emit_i32_add(m_code_section, m_al); - break; - }; - case ASR::binopType::Sub: { - wasm::emit_i32_sub(m_code_section, m_al); - break; - }; - case ASR::binopType::Mul: { - wasm::emit_i32_mul(m_code_section, m_al); - break; - }; - case ASR::binopType::Div: { - wasm::emit_i32_div_s(m_code_section, m_al); - break; - }; - case ASR::binopType::Pow: { - ASR::expr_t *val = ASRUtils::expr_value(x.m_right); - if (ASR::is_a(*val)) { - ASR::IntegerConstant_t *c = - ASR::down_cast(val); - if (c->m_n == 2) { - // drop the last stack item in the wasm stack - wasm::emit_drop(m_code_section, m_al); - this->visit_expr(*x.m_left); - wasm::emit_i32_mul(m_code_section, m_al); - } else { - throw CodeGenError( - "IntegerBinop kind 4: only x**2 implemented so " - "far for powers"); - } - } else { - throw CodeGenError( - "IntegerBinop kind 4: only x**2 implemented so far " - "for powers"); - } - break; - }; - case ASR::binopType::BitAnd: { - wasm::emit_i32_and(m_code_section, m_al); - break; - }; - case ASR::binopType::BitOr: { - wasm::emit_i32_or(m_code_section, m_al); - break; - }; - case ASR::binopType::BitXor: { - wasm::emit_i32_xor(m_code_section, m_al); - break; - }; - case ASR::binopType::BitLShift: { - wasm::emit_i32_shl(m_code_section, m_al); - break; - }; - case ASR::binopType::BitRShift: { - wasm::emit_i32_shr_s(m_code_section, m_al); - break; - }; - default: { - throw CodeGenError( - "ICE IntegerBinop kind 4: unknown operation"); - } - } - } else if (i->m_kind == 8) { - switch (x.m_op) { - case ASR::binopType::Add: { - wasm::emit_i64_add(m_code_section, m_al); - break; - }; - case ASR::binopType::Sub: { - wasm::emit_i64_sub(m_code_section, m_al); - break; - }; - case ASR::binopType::Mul: { - wasm::emit_i64_mul(m_code_section, m_al); - break; - }; - case ASR::binopType::Div: { - wasm::emit_i64_div_s(m_code_section, m_al); - break; - }; - case ASR::binopType::Pow: { - ASR::expr_t *val = ASRUtils::expr_value(x.m_right); - if (ASR::is_a(*val)) { - ASR::IntegerConstant_t *c = - ASR::down_cast(val); - if (c->m_n == 2) { - // drop the last stack item in the wasm stack - wasm::emit_drop(m_code_section, m_al); - this->visit_expr(*x.m_left); - wasm::emit_i64_mul(m_code_section, m_al); - } else { - throw CodeGenError( - "IntegerBinop kind 8: only x**2 implemented so " - "far for powers"); - } - } else { - throw CodeGenError( - "IntegerBinop kind 8: only x**2 implemented so far " - "for powers"); - } - break; - }; - case ASR::binopType::BitAnd: { - wasm::emit_i64_and(m_code_section, m_al); - break; - }; - case ASR::binopType::BitOr: { - wasm::emit_i64_or(m_code_section, m_al); - break; - }; - case ASR::binopType::BitXor: { - wasm::emit_i64_xor(m_code_section, m_al); - break; - }; - case ASR::binopType::BitLShift: { - wasm::emit_i64_shl(m_code_section, m_al); - break; - }; - case ASR::binopType::BitRShift: { - wasm::emit_i64_shr_s(m_code_section, m_al); - break; - }; - default: { - throw CodeGenError( - "ICE IntegerBinop kind 8: unknown operation"); - } - } - } else { - throw CodeGenError("IntegerBinop: Integer kind not supported"); - } - } - - void visit_IntegerBitNot(const ASR::IntegerBitNot_t &x) { - if (x.m_value) { - visit_expr(*x.m_value); - return; - } - this->visit_expr(*x.m_arg); - ASR::Integer_t *i = ASR::down_cast(x.m_type); - // there is no direct bit-invert inst in wasm, - // so xor-ing with -1 (sequence of 32/64 1s) - if(i->m_kind == 4){ - wasm::emit_i32_const(m_code_section, m_al, -1); - wasm::emit_i32_xor(m_code_section, m_al); - } - else if(i->m_kind == 8){ - wasm::emit_i64_const(m_code_section, m_al, -1LL); - wasm::emit_i64_xor(m_code_section, m_al); - } - else{ - throw CodeGenError("IntegerBitNot: Only kind 4 and 8 supported"); - } - } - - void visit_RealBinOp(const ASR::RealBinOp_t &x) { - if (x.m_value) { - visit_expr(*x.m_value); - return; - } - this->visit_expr(*x.m_left); - this->visit_expr(*x.m_right); - ASR::Real_t *f = ASR::down_cast(x.m_type); - if (f->m_kind == 4) { - switch (x.m_op) { - case ASR::binopType::Add: { - wasm::emit_f32_add(m_code_section, m_al); - break; - }; - case ASR::binopType::Sub: { - wasm::emit_f32_sub(m_code_section, m_al); - break; - }; - case ASR::binopType::Mul: { - wasm::emit_f32_mul(m_code_section, m_al); - break; - }; - case ASR::binopType::Div: { - wasm::emit_f32_div(m_code_section, m_al); - break; - }; - case ASR::binopType::Pow: { - ASR::expr_t *val = ASRUtils::expr_value(x.m_right); - if (ASR::is_a(*val)) { - ASR::RealConstant_t *c = - ASR::down_cast(val); - if (c->m_r == 2.0) { - // drop the last stack item in the wasm stack - wasm::emit_drop(m_code_section, m_al); - this->visit_expr(*x.m_left); - wasm::emit_f32_mul(m_code_section, m_al); - } else { - throw CodeGenError( - "RealBinop: only x**2 implemented so far for " - "powers"); - } - } else { - throw CodeGenError( - "RealBinop: only x**2 implemented so far for " - "powers"); - } - break; - }; - default: { - throw CodeGenError( - "ICE RealBinop kind 4: unknown operation"); - } - } - } else if (f->m_kind == 8) { - switch (x.m_op) { - case ASR::binopType::Add: { - wasm::emit_f64_add(m_code_section, m_al); - break; - }; - case ASR::binopType::Sub: { - wasm::emit_f64_sub(m_code_section, m_al); - break; - }; - case ASR::binopType::Mul: { - wasm::emit_f64_mul(m_code_section, m_al); - break; - }; - case ASR::binopType::Div: { - wasm::emit_f64_div(m_code_section, m_al); - break; - }; - case ASR::binopType::Pow: { - ASR::expr_t *val = ASRUtils::expr_value(x.m_right); - if (ASR::is_a(*val)) { - ASR::RealConstant_t *c = - ASR::down_cast(val); - if (c->m_r == 2.0) { - // drop the last stack item in the wasm stack - wasm::emit_drop(m_code_section, m_al); - this->visit_expr(*x.m_left); - wasm::emit_f64_mul(m_code_section, m_al); - } else { - throw CodeGenError( - "RealBinop: only x**2 implemented so far for " - "powers"); - } - } else { - throw CodeGenError( - "RealBinop: only x**2 implemented so far for " - "powers"); - } - break; - }; - default: { - throw CodeGenError("ICE RealBinop: unknown operation"); - } - } - } else { - throw CodeGenError("RealBinop: Real kind not supported"); - } - } - - void visit_ComplexBinOp(const ASR::ComplexBinOp_t &x) { - if (x.m_value) { - this->visit_expr(*x.m_value); - return; - } - this->visit_expr(*x.m_left); - this->visit_expr(*x.m_right); - LCOMPILERS_ASSERT(ASRUtils::is_complex(*x.m_type)); - int a_kind = ASR::down_cast(ASRUtils::type_get_past_pointer(x.m_type))->m_kind; - switch (x.m_op) { - case ASR::binopType::Add: { - if (a_kind == 4) { - if (m_rt_func_used_idx[add_c32] == -1) { - m_rt_func_used_idx[add_c32] = no_of_types++; - } - wasm::emit_call(m_code_section, m_al, m_rt_func_used_idx[add_c32]); - } else { - if (m_rt_func_used_idx[add_c64] == -1) { - m_rt_func_used_idx[add_c64] = no_of_types++; - } - wasm::emit_call(m_code_section, m_al, m_rt_func_used_idx[add_c64]); - } - break; - }; - case ASR::binopType::Sub: { - if (a_kind == 4) { - if (m_rt_func_used_idx[sub_c32] == -1) { - m_rt_func_used_idx[sub_c32] = no_of_types++; - } - wasm::emit_call(m_code_section, m_al, m_rt_func_used_idx[sub_c32]); - } else { - if (m_rt_func_used_idx[sub_c64] == -1) { - m_rt_func_used_idx[sub_c64] = no_of_types++; - } - wasm::emit_call(m_code_section, m_al, m_rt_func_used_idx[sub_c64]); - } - break; - }; - case ASR::binopType::Mul: { - if (a_kind == 4) { - if (m_rt_func_used_idx[mul_c32] == -1) { - m_rt_func_used_idx[mul_c32] = no_of_types++; - } - wasm::emit_call(m_code_section, m_al, m_rt_func_used_idx[mul_c32]); - } else { - if (m_rt_func_used_idx[mul_c64] == -1) { - m_rt_func_used_idx[mul_c64] = no_of_types++; - } - wasm::emit_call(m_code_section, m_al, m_rt_func_used_idx[mul_c64]); - } - break; - }; - default: { - throw CodeGenError("ComplexBinOp: Binary operator '" + ASRUtils::binop_to_str_python(x.m_op) + "' not supported", - x.base.base.loc); - } - } - } - - void visit_IntegerUnaryMinus(const ASR::IntegerUnaryMinus_t &x) { - if (x.m_value) { - visit_expr(*x.m_value); - return; - } - ASR::Integer_t *i = ASR::down_cast(x.m_type); - // there seems no direct unary-minus inst in wasm, so subtracting from 0 - if (i->m_kind == 4) { - wasm::emit_i32_const(m_code_section, m_al, 0); - this->visit_expr(*x.m_arg); - wasm::emit_i32_sub(m_code_section, m_al); - } else if (i->m_kind == 8) { - wasm::emit_i64_const(m_code_section, m_al, 0LL); - this->visit_expr(*x.m_arg); - wasm::emit_i64_sub(m_code_section, m_al); - } else { - throw CodeGenError( - "IntegerUnaryMinus: Only kind 4 and 8 supported"); - } - } - - void visit_RealUnaryMinus(const ASR::RealUnaryMinus_t &x) { - if (x.m_value) { - visit_expr(*x.m_value); - return; - } - ASR::Real_t *f = ASR::down_cast(x.m_type); - if (f->m_kind == 4) { - this->visit_expr(*x.m_arg); - wasm::emit_f32_neg(m_code_section, m_al); - } else if (f->m_kind == 8) { - this->visit_expr(*x.m_arg); - wasm::emit_f64_neg(m_code_section, m_al); - } else { - throw CodeGenError("RealUnaryMinus: Only kind 4 and 8 supported"); - } - } - - void visit_ComplexUnaryMinus(const ASR::ComplexUnaryMinus_t &x) { - if (x.m_value) { - visit_expr(*x.m_value); - return; - } - ASR::Complex_t *f = ASR::down_cast(x.m_type); - if (f->m_kind == 4) { - this->visit_expr(*x.m_arg); - wasm::emit_f32_neg(m_code_section, m_al); - wasm::emit_set_global(m_code_section, m_al, m_global_var_name_idx_map[tmp_reg_f32]); - wasm::emit_f32_neg(m_code_section, m_al); - wasm::emit_get_global(m_code_section, m_al, m_global_var_name_idx_map[tmp_reg_f32]); - } else if (f->m_kind == 8) { - this->visit_expr(*x.m_arg); - wasm::emit_f64_neg(m_code_section, m_al); - wasm::emit_set_global(m_code_section, m_al, m_global_var_name_idx_map[tmp_reg_f64]); - wasm::emit_f64_neg(m_code_section, m_al); - wasm::emit_get_global(m_code_section, m_al, m_global_var_name_idx_map[tmp_reg_f64]); - } else { - throw CodeGenError("ComplexUnaryMinus: Only kind 4 and 8 supported"); - } - } - - template - int get_kind_from_operands(const T &x) { - ASR::ttype_t *left_ttype = ASRUtils::expr_type(x.m_left); - int left_kind = ASRUtils::extract_kind_from_ttype_t(left_ttype); - - ASR::ttype_t *right_ttype = ASRUtils::expr_type(x.m_right); - int right_kind = ASRUtils::extract_kind_from_ttype_t(right_ttype); - - if (left_kind != right_kind) { - diag.codegen_error_label("Operand kinds do not match", - {x.base.base.loc}, - "WASM Type Mismatch Error"); - throw CodeGenAbort(); - } - - return left_kind; - } - - template - void handle_integer_compare(const T &x) { - if (x.m_value) { - visit_expr(*x.m_value); - return; - } - this->visit_expr(*x.m_left); - this->visit_expr(*x.m_right); - // int a_kind = ASRUtils::extract_kind_from_ttype_t(x.m_type); - int a_kind = get_kind_from_operands(x); - if (a_kind == 4) { - switch (x.m_op) { - case (ASR::cmpopType::Eq): { - wasm::emit_i32_eq(m_code_section, m_al); - break; - } - case (ASR::cmpopType::Gt): { - wasm::emit_i32_gt_s(m_code_section, m_al); - break; - } - case (ASR::cmpopType::GtE): { - wasm::emit_i32_ge_s(m_code_section, m_al); - break; - } - case (ASR::cmpopType::Lt): { - wasm::emit_i32_lt_s(m_code_section, m_al); - break; - } - case (ASR::cmpopType::LtE): { - wasm::emit_i32_le_s(m_code_section, m_al); - break; - } - case (ASR::cmpopType::NotEq): { - wasm::emit_i32_ne(m_code_section, m_al); - break; - } - default: - throw CodeGenError( - "handle_integer_compare: Kind 4: Unhandled switch " - "case"); - } - } else if (a_kind == 8) { - switch (x.m_op) { - case (ASR::cmpopType::Eq): { - wasm::emit_i64_eq(m_code_section, m_al); - break; - } - case (ASR::cmpopType::Gt): { - wasm::emit_i64_gt_s(m_code_section, m_al); - break; - } - case (ASR::cmpopType::GtE): { - wasm::emit_i64_ge_s(m_code_section, m_al); - break; - } - case (ASR::cmpopType::Lt): { - wasm::emit_i64_lt_s(m_code_section, m_al); - break; - } - case (ASR::cmpopType::LtE): { - wasm::emit_i64_le_s(m_code_section, m_al); - break; - } - case (ASR::cmpopType::NotEq): { - wasm::emit_i64_ne(m_code_section, m_al); - break; - } - default: - throw CodeGenError( - "handle_integer_compare: Kind 8: Unhandled switch " - "case"); - } - } else { - throw CodeGenError("IntegerCompare: kind 4 and 8 supported only"); - } - } - - void handle_real_compare(const ASR::RealCompare_t &x) { - if (x.m_value) { - visit_expr(*x.m_value); - return; - } - this->visit_expr(*x.m_left); - this->visit_expr(*x.m_right); - // int a_kind = ASRUtils::extract_kind_from_ttype_t(x.m_type); - int a_kind = get_kind_from_operands(x); - if (a_kind == 4) { - switch (x.m_op) { - case (ASR::cmpopType::Eq): { - wasm::emit_f32_eq(m_code_section, m_al); - break; - } - case (ASR::cmpopType::Gt): { - wasm::emit_f32_gt(m_code_section, m_al); - break; - } - case (ASR::cmpopType::GtE): { - wasm::emit_f32_ge(m_code_section, m_al); - break; - } - case (ASR::cmpopType::Lt): { - wasm::emit_f32_lt(m_code_section, m_al); - break; - } - case (ASR::cmpopType::LtE): { - wasm::emit_f32_le(m_code_section, m_al); - break; - } - case (ASR::cmpopType::NotEq): { - wasm::emit_f32_ne(m_code_section, m_al); - break; - } - default: - throw CodeGenError( - "handle_real_compare: Kind 4: Unhandled switch case"); - } - } else if (a_kind == 8) { - switch (x.m_op) { - case (ASR::cmpopType::Eq): { - wasm::emit_f64_eq(m_code_section, m_al); - break; - } - case (ASR::cmpopType::Gt): { - wasm::emit_f64_gt(m_code_section, m_al); - break; - } - case (ASR::cmpopType::GtE): { - wasm::emit_f64_ge(m_code_section, m_al); - break; - } - case (ASR::cmpopType::Lt): { - wasm::emit_f64_lt(m_code_section, m_al); - break; - } - case (ASR::cmpopType::LtE): { - wasm::emit_f64_le(m_code_section, m_al); - break; - } - case (ASR::cmpopType::NotEq): { - wasm::emit_f64_ne(m_code_section, m_al); - break; - } - default: - throw CodeGenError( - "handle_real_compare: Kind 8: Unhandled switch case"); - } - } else { - throw CodeGenError("RealCompare: kind 4 and 8 supported only"); - } - } - - void visit_IntegerCompare(const ASR::IntegerCompare_t &x) { - handle_integer_compare(x); - } - - void visit_RealCompare(const ASR::RealCompare_t &x) { - handle_real_compare(x); - } - - void visit_ComplexCompare(const ASR::ComplexCompare_t & /*x*/) { - throw CodeGenError("Complex Types not yet supported"); - } - - void visit_LogicalCompare(const ASR::LogicalCompare_t &x) { - handle_integer_compare(x); - } - - void visit_StringCompare(const ASR::StringCompare_t & /*x*/) { - throw CodeGenError("String Types not yet supported"); - } - - void visit_LogicalBinOp(const ASR::LogicalBinOp_t &x) { - if (x.m_value) { - visit_expr(*x.m_value); - return; - } - this->visit_expr(*x.m_left); - this->visit_expr(*x.m_right); - int a_kind = ASRUtils::extract_kind_from_ttype_t(x.m_type); - if (a_kind == 4) { - switch (x.m_op) { - case (ASR::logicalbinopType::And): { - wasm::emit_i32_and(m_code_section, m_al); - break; - } - case (ASR::logicalbinopType::Or): { - wasm::emit_i32_or(m_code_section, m_al); - break; - } - case ASR::logicalbinopType::Xor: { - wasm::emit_i32_xor(m_code_section, m_al); - break; - } - case (ASR::logicalbinopType::NEqv): { - wasm::emit_i32_xor(m_code_section, m_al); - break; - } - case (ASR::logicalbinopType::Eqv): { - wasm::emit_i32_eq(m_code_section, m_al); - break; - } - default: - throw CodeGenError( - "LogicalBinOp: Kind 4: Unhandled switch case"); - } - } else { - throw CodeGenError("LogicalBinOp: kind 4 supported only"); - } - } - - void visit_LogicalNot(const ASR::LogicalNot_t &x) { - if (x.m_value) { - this->visit_expr(*x.m_value); - return; - } - this->visit_expr(*x.m_arg); - int a_kind = ASRUtils::extract_kind_from_ttype_t(x.m_type); - if (a_kind == 4) { - wasm::emit_i32_eqz(m_code_section, m_al); - } else if (a_kind == 8) { - wasm::emit_i64_eqz(m_code_section, m_al); - } else { - throw CodeGenError("LogicalNot: kind 4 and 8 supported only"); - } - } - - void visit_Var(const ASR::Var_t &x) { - const ASR::symbol_t *s = ASRUtils::symbol_get_past_external(x.m_v); - auto v = ASR::down_cast(s); - switch (v->m_type->type) { - case ASR::ttypeType::Integer: - case ASR::ttypeType::Logical: - case ASR::ttypeType::Real: - case ASR::ttypeType::Character: { - LCOMPILERS_ASSERT( - m_var_name_idx_map.find(get_hash((ASR::asr_t *)v)) != - m_var_name_idx_map.end()); - wasm::emit_get_local( - m_code_section, m_al, - m_var_name_idx_map[get_hash((ASR::asr_t *)v)]); - break; - } - case ASR::ttypeType::Complex: { - LCOMPILERS_ASSERT( - m_var_name_idx_map.find(get_hash((ASR::asr_t *)v)) != - m_var_name_idx_map.end()); - wasm::emit_get_local( - m_code_section, m_al, - m_var_name_idx_map[get_hash((ASR::asr_t *)v)]); // get real part - wasm::emit_get_local( - m_code_section, m_al, - m_var_name_idx_map[get_hash((ASR::asr_t *)v)] + 1); // get imag part - break; - } - default: - throw CodeGenError( - "Only Integer and Float Variable types currently " - "supported"); - } - } - - void get_array_dims(const ASR::Variable_t &x, Vec &dims) { - ASR::dimension_t *m_dims; - uint32_t n_dims = - ASRUtils::extract_dimensions_from_ttype(x.m_type, m_dims); - dims.reserve(m_al, n_dims); - for (uint32_t i = 0; i < n_dims; i++) { - ASR::expr_t *length_value = - ASRUtils::expr_value(m_dims[i].m_length); - uint64_t len_in_this_dim = -1; - ASRUtils::extract_value(length_value, len_in_this_dim); - dims.push_back(m_al, (uint32_t)len_in_this_dim); - } - } - - void emit_array_item_address_onto_stack(const ASR::ArrayItem_t &x) { - this->visit_expr(*x.m_v); - ASR::ttype_t *ttype = ASRUtils::expr_type(x.m_v); - uint32_t kind = ASRUtils::extract_kind_from_ttype_t(ttype); - ASR::dimension_t *m_dims; - ASRUtils::extract_dimensions_from_ttype(ttype, m_dims); - - wasm::emit_i32_const(m_code_section, m_al, 0); - for (uint32_t i = 0; i < x.n_args; i++) { - if (x.m_args[i].m_right) { - this->visit_expr(*x.m_args[i].m_right); - this->visit_expr(*m_dims[i].m_start); - wasm::emit_i32_sub(m_code_section, m_al); - size_t jmin, jmax; - - if (x.m_storage_format == ASR::arraystorageType::ColMajor) { - // Column-major order - jmin = 0; - jmax = i; - } else { - // Row-major order - jmin = i + 1; - jmax = x.n_args; - } - - for (size_t j = jmin; j < jmax; j++) { - this->visit_expr(*m_dims[j].m_length); - wasm::emit_i32_mul(m_code_section, m_al); - } - - wasm::emit_i32_add(m_code_section, m_al); - } else { - diag.codegen_warning_label("/* FIXME right index */", - {x.base.base.loc}, ""); - } - } - wasm::emit_i32_const(m_code_section, m_al, kind); - wasm::emit_i32_mul(m_code_section, m_al); - wasm::emit_i32_add(m_code_section, m_al); - } - - void visit_ArrayItem(const ASR::ArrayItem_t &x) { - emit_array_item_address_onto_stack(x); - emit_memory_load(x.m_v); - } - - void visit_ArraySize(const ASR::ArraySize_t &x) { - if (x.m_value) { - this->visit_expr(*x.m_value); - return; - } - ASR::dimension_t *m_dims; - int n_dims = ASRUtils::extract_dimensions_from_ttype( - ASRUtils::expr_type(x.m_v), m_dims); - if (x.m_dim) { - int dim_idx = -1; - ASRUtils::extract_value(ASRUtils::expr_value(x.m_dim), dim_idx); - if (dim_idx == -1) { - throw CodeGenError("Dimension index not available"); - } - if (!m_dims[dim_idx - 1].m_length) { - throw CodeGenError("Dimension length for index " + - std::to_string(dim_idx) + " does not exist"); - } - this->visit_expr(*(m_dims[dim_idx - 1].m_length)); - } else { - if (!m_dims[0].m_length) { - throw CodeGenError( - "Dimension length for index 0 does not exist"); - } - this->visit_expr(*(m_dims[0].m_length)); - for (int i = 1; i < n_dims; i++) { - this->visit_expr(*m_dims[i].m_length); - wasm::emit_i32_mul(m_code_section, m_al); - } - } - - int kind = ASRUtils::extract_kind_from_ttype_t(x.m_type); - if (kind == 8) { - wasm::emit_i64_extend_i32_s(m_code_section, m_al); - } - } - - void handle_return() { - if (cur_sym_info->return_var) { - LCOMPILERS_ASSERT(m_var_name_idx_map.find(get_hash( - (ASR::asr_t *)cur_sym_info->return_var)) != - m_var_name_idx_map.end()); - wasm::emit_get_local(m_code_section, m_al, - m_var_name_idx_map[get_hash( - (ASR::asr_t *)cur_sym_info->return_var)]); - if (!ASRUtils::is_array(cur_sym_info->return_var->m_type) - && ASRUtils::is_complex(*cur_sym_info->return_var->m_type)) { - wasm::emit_get_local(m_code_section, m_al, - m_var_name_idx_map[get_hash( - (ASR::asr_t *)cur_sym_info->return_var)] + 1); - } - } else { - for (auto return_var : cur_sym_info->referenced_vars) { - wasm::emit_get_local( - m_code_section, m_al, - m_var_name_idx_map[get_hash((ASR::asr_t *)(return_var))]); - if (!ASRUtils::is_array(return_var->m_type) - && ASRUtils::is_complex(*return_var->m_type)) { - wasm::emit_get_local(m_code_section, m_al, - m_var_name_idx_map[get_hash( - (ASR::asr_t *)return_var)] + 1); - } - } - } - wasm::emit_b8(m_code_section, m_al, - 0x0F); // emit wasm return instruction - } - - void visit_Return(const ASR::Return_t & /* x */) { handle_return(); } - - void visit_IntegerConstant(const ASR::IntegerConstant_t &x) { - int64_t val = x.m_n; - int a_kind = ((ASR::Integer_t *)(&(x.m_type->base)))->m_kind; - switch (a_kind) { - case 4: { - wasm::emit_i32_const(m_code_section, m_al, val); - break; - } - case 8: { - wasm::emit_i64_const(m_code_section, m_al, val); - break; - } - default: { - throw CodeGenError( - "Constant Integer: Only kind 4 and 8 supported"); - } - } - } - - void visit_RealConstant(const ASR::RealConstant_t &x) { - double val = x.m_r; - int a_kind = ((ASR::Real_t *)(&(x.m_type->base)))->m_kind; - switch (a_kind) { - case 4: { - wasm::emit_f32_const(m_code_section, m_al, val); - break; - } - case 8: { - wasm::emit_f64_const(m_code_section, m_al, val); - break; - } - default: { - throw CodeGenError( - "Constant Real: Only kind 4 and 8 supported"); - } - } - } - - void visit_LogicalConstant(const ASR::LogicalConstant_t &x) { - bool val = x.m_value; - int a_kind = ((ASR::Logical_t *)(&(x.m_type->base)))->m_kind; - switch (a_kind) { - case 4: { - wasm::emit_i32_const(m_code_section, m_al, val); - break; - } - default: { - throw CodeGenError("Constant Logical: Only kind 4 supported"); - } - } - } - - void visit_ComplexConstant(const ASR::ComplexConstant_t &x) { - int a_kind = ASRUtils::extract_kind_from_ttype_t(x.m_type); - switch( a_kind ) { - case 4: { - wasm::emit_f32_const(m_code_section, m_al, x.m_re); - wasm::emit_f32_const(m_code_section, m_al, x.m_im); - break; - } - case 8: { - wasm::emit_f64_const(m_code_section, m_al, x.m_re); - wasm::emit_f64_const(m_code_section, m_al, x.m_im); - break; - } - default: { - throw CodeGenError("kind type is not supported"); - } - } - } - - std::string convert_int_to_bytes_string(int n) { - uint8_t bytes[sizeof(n)]; - std::memcpy(&bytes, &n, sizeof(n)); - std::string result = ""; - for (size_t i = 0; i < sizeof(n); i++) { - result += char(bytes[i]); - } - return result; - } - - void align_str_by_4_bytes(std::string &s) { - int n = s.length(); - if (n % 4 == 0) return; - for (int i = 0; i < 4 - (n % 4); i++) { - s += " "; - } - } - - void emit_string(std::string str) { - if (m_string_to_iov_loc_map.find(str) != m_string_to_iov_loc_map.end()) { - return; - } - - // Todo: Add a check here if there is memory available to store the - // given string - - m_string_to_iov_loc_map[str] = avail_mem_loc; - - uint32_t string_loc = avail_mem_loc + 8U /* IOV_SIZE */; - std::string iov = convert_int_to_bytes_string(string_loc) + convert_int_to_bytes_string(str.length()); - wasm::emit_str_const(m_data_section, m_al, avail_mem_loc, iov); - avail_mem_loc += iov.length(); - no_of_data_segments++; - - align_str_by_4_bytes(str); - wasm::emit_str_const(m_data_section, m_al, avail_mem_loc, str); - avail_mem_loc += str.length(); - no_of_data_segments++; - } - - void visit_StringConstant(const ASR::StringConstant_t &x) { - emit_string(x.m_s); - wasm::emit_i32_const(m_code_section, m_al, m_string_to_iov_loc_map[x.m_s]); - } - - void visit_ArrayConstant(const ASR::ArrayConstant_t &x) { - // Todo: Add a check here if there is memory available to store the - // given string - uint32_t cur_mem_loc = avail_mem_loc; - for (size_t i = 0; i < x.n_args; i++) { - // emit memory location to store array element - wasm::emit_i32_const(m_code_section, m_al, avail_mem_loc); - - this->visit_expr(*x.m_args[i]); - int element_size_in_bytes = emit_memory_store(x.m_args[i]); - avail_mem_loc += element_size_in_bytes; - } - // leave array location in memory on the stack - wasm::emit_i32_const(m_code_section, m_al, cur_mem_loc); - } - - void visit_FunctionCall(const ASR::FunctionCall_t &x) { - if (x.m_value) { - this->visit_expr(*x.m_value); - return; - } - - ASR::Function_t *fn = ASR::down_cast( - ASRUtils::symbol_get_past_external(x.m_name)); - - for (size_t i = 0; i < x.n_args; i++) { - visit_expr(*x.m_args[i].m_value); - } - - LCOMPILERS_ASSERT(m_func_name_idx_map.find(get_hash((ASR::asr_t *)fn)) != - m_func_name_idx_map.end()) - wasm::emit_call(m_code_section, m_al, - m_func_name_idx_map[get_hash((ASR::asr_t *)fn)]->index); - } - - void visit_SubroutineCall(const ASR::SubroutineCall_t &x) { - ASR::Function_t *s = ASR::down_cast( - ASRUtils::symbol_get_past_external(x.m_name)); - - Vec vars_passed_by_refs; - vars_passed_by_refs.reserve(m_al, s->n_args); - if (x.n_args == s->n_args) { - for (size_t i = 0; i < x.n_args; i++) { - ASR::Variable_t *arg = ASRUtils::EXPR2VAR(s->m_args[i]); - if (arg->m_intent == ASRUtils::intent_out || - arg->m_intent == ASRUtils::intent_inout || - arg->m_intent == ASRUtils::intent_unspecified) { - vars_passed_by_refs.push_back(m_al, x.m_args[i].m_value); - } - visit_expr(*x.m_args[i].m_value); - } - } else { - throw CodeGenError( - "visitSubroutineCall: Number of arguments passed do not match " - "the number of parameters"); - } - - LCOMPILERS_ASSERT(m_func_name_idx_map.find(get_hash((ASR::asr_t *)s)) != - m_func_name_idx_map.end()) - wasm::emit_call(m_code_section, m_al, - m_func_name_idx_map[get_hash((ASR::asr_t *)s)]->index); - for (auto return_expr : vars_passed_by_refs) { - if (ASR::is_a(*return_expr)) { - auto return_var = ASRUtils::EXPR2VAR(return_expr); - LCOMPILERS_ASSERT( - m_var_name_idx_map.find(get_hash((ASR::asr_t *)return_var)) != - m_var_name_idx_map.end()); - wasm::emit_set_local( - m_code_section, m_al, - m_var_name_idx_map[get_hash((ASR::asr_t *)return_var)]); - } else if (ASR::is_a(*return_expr)) { - // emit_memory_store(ASRUtils::EXPR(return_var)); - - throw CodeGenError( - "Passing array elements as arguments (with intent out, " - "inout, unspecified) to Subroutines is not yet supported"); - } else { - LCOMPILERS_ASSERT(false); - } - } - } - - inline ASR::ttype_t *extract_ttype_t_from_expr(ASR::expr_t *expr) { - return ASRUtils::expr_type(expr); - } - - void extract_kinds(const ASR::Cast_t &x, int &arg_kind, int &dest_kind) { - dest_kind = ASRUtils::extract_kind_from_ttype_t(x.m_type); - ASR::ttype_t *curr_type = extract_ttype_t_from_expr(x.m_arg); - LCOMPILERS_ASSERT(curr_type != nullptr) - arg_kind = ASRUtils::extract_kind_from_ttype_t(curr_type); - } - - void visit_Cast(const ASR::Cast_t &x) { - if (x.m_value) { - this->visit_expr(*x.m_value); - return; - } - this->visit_expr(*x.m_arg); - switch (x.m_kind) { - case (ASR::cast_kindType::IntegerToReal): { - int arg_kind = -1, dest_kind = -1; - extract_kinds(x, arg_kind, dest_kind); - if (arg_kind > 0 && dest_kind > 0) { - if (arg_kind == 4 && dest_kind == 4) { - wasm::emit_f32_convert_i32_s(m_code_section, m_al); - } else if (arg_kind == 8 && dest_kind == 8) { - wasm::emit_f64_convert_i64_s(m_code_section, m_al); - } else if (arg_kind == 4 && dest_kind == 8) { - wasm::emit_f64_convert_i32_s(m_code_section, m_al); - } else if (arg_kind == 8 && dest_kind == 4) { - wasm::emit_f32_convert_i64_s(m_code_section, m_al); - } else { - std::string msg = "Conversion from " + - std::to_string(arg_kind) + " to " + - std::to_string(dest_kind) + - " not implemented yet."; - throw CodeGenError(msg); - } - } - break; - } - case (ASR::cast_kindType::RealToInteger): { - int arg_kind = -1, dest_kind = -1; - extract_kinds(x, arg_kind, dest_kind); - if (arg_kind > 0 && dest_kind > 0) { - if (arg_kind == 4 && dest_kind == 4) { - wasm::emit_i32_trunc_f32_s(m_code_section, m_al); - } else if (arg_kind == 8 && dest_kind == 8) { - wasm::emit_i64_trunc_f64_s(m_code_section, m_al); - } else if (arg_kind == 4 && dest_kind == 8) { - wasm::emit_i64_trunc_f32_s(m_code_section, m_al); - } else if (arg_kind == 8 && dest_kind == 4) { - wasm::emit_i32_trunc_f64_s(m_code_section, m_al); - } else { - std::string msg = "Conversion from " + - std::to_string(arg_kind) + " to " + - std::to_string(dest_kind) + - " not implemented yet."; - throw CodeGenError(msg); - } - } - break; - } - case (ASR::cast_kindType::RealToComplex): { - int arg_kind = -1, dest_kind = -1; - extract_kinds(x, arg_kind, dest_kind); - if (arg_kind == dest_kind) { - - } else if (arg_kind == 4 && dest_kind == 8) { - wasm::emit_f64_promote_f32(m_code_section, m_al); - } else if (arg_kind == 8 && dest_kind == 4) { - wasm::emit_f32_demote_f64(m_code_section, m_al); - } else { - std::string msg = "RealToComplex: Conversion from " + - std::to_string(arg_kind) + " to " + - std::to_string(dest_kind) + - " not implemented yet."; - throw CodeGenError(msg); - } - switch(dest_kind) - { - case 4: - wasm::emit_f32_const(m_code_section, m_al, 0.0); - break; - case 8: - wasm::emit_f64_const(m_code_section, m_al, 0.0); - break; - default: - throw CodeGenError("RealToComplex: Only 32 and 64 bits real kinds are supported."); - } - break; - } - case (ASR::cast_kindType::IntegerToComplex): { - int arg_kind = -1, dest_kind = -1; - extract_kinds(x, arg_kind, dest_kind); - if (arg_kind > 0 && dest_kind > 0) { - if (arg_kind == 4 && dest_kind == 4) { - wasm::emit_f32_convert_i32_s(m_code_section, m_al); - } else if (arg_kind == 8 && dest_kind == 8) { - wasm::emit_f64_convert_i64_s(m_code_section, m_al); - } else if (arg_kind == 4 && dest_kind == 8) { - wasm::emit_f64_convert_i32_s(m_code_section, m_al); - } else if (arg_kind == 8 && dest_kind == 4) { - wasm::emit_f32_convert_i64_s(m_code_section, m_al); - } else { - std::string msg = "IntegerToComplex: Conversion from " + - std::to_string(arg_kind) + " to " + - std::to_string(dest_kind) + - " not implemented yet."; - throw CodeGenError(msg); - } - } - switch(dest_kind) - { - case 4: - wasm::emit_f32_const(m_code_section, m_al, 0.0); - break; - case 8: - wasm::emit_f64_const(m_code_section, m_al, 0.0); - break; - default: - throw CodeGenError("RealToComplex: Only 32 and 64 bits real kinds are supported."); - } - break; - } - case (ASR::cast_kindType::IntegerToLogical): { - int arg_kind = -1, dest_kind = -1; - extract_kinds(x, arg_kind, dest_kind); - if (arg_kind > 0 && dest_kind > 0) { - if (arg_kind == 4 && dest_kind == 4) { - wasm::emit_i32_eqz(m_code_section, m_al); - wasm::emit_i32_eqz(m_code_section, m_al); - } else if (arg_kind == 8 && dest_kind == 4) { - wasm::emit_i64_eqz(m_code_section, m_al); - wasm::emit_i64_eqz(m_code_section, m_al); - wasm::emit_i32_wrap_i64(m_code_section, m_al); - } else { - std::string msg = "Conversion from kinds " + - std::to_string(arg_kind) + " to " + - std::to_string(dest_kind) + - " not supported"; - throw CodeGenError(msg); - } - } - break; - } - case (ASR::cast_kindType::RealToLogical): { - int arg_kind = -1, dest_kind = -1; - extract_kinds(x, arg_kind, dest_kind); - if (arg_kind > 0 && dest_kind > 0) { - if (arg_kind == 4 && dest_kind == 4) { - wasm::emit_f32_const(m_code_section, m_al, 0.0); - wasm::emit_f32_eq(m_code_section, m_al); - wasm::emit_i32_eqz(m_code_section, m_al); - } else if (arg_kind == 8 && dest_kind == 4) { - wasm::emit_f64_const(m_code_section, m_al, 0.0); - wasm::emit_f64_eq(m_code_section, m_al); - wasm::emit_i64_eqz(m_code_section, m_al); - wasm::emit_i32_wrap_i64(m_code_section, m_al); - } else { - std::string msg = "Conversion from kinds " + - std::to_string(arg_kind) + " to " + - std::to_string(dest_kind) + - " not supported"; - throw CodeGenError(msg); - } - } - break; - } - case (ASR::cast_kindType::CharacterToLogical): { - throw CodeGenError(R"""(STrings are not supported yet)""", - x.base.base.loc); - break; - } - case (ASR::cast_kindType::ComplexToLogical): { - int arg_kind = -1, dest_kind = -1; - extract_kinds(x, arg_kind, dest_kind); - if (arg_kind == 4) { - if (m_rt_func_used_idx[abs_c32] == -1) { - m_rt_func_used_idx[abs_c32] = no_of_types++; - } - wasm::emit_call(m_code_section, m_al, m_rt_func_used_idx[abs_c32]); - wasm::emit_f32_const(m_code_section, m_al, 0.0); - wasm::emit_f32_gt(m_code_section, m_al); - } else if (arg_kind == 8) { - if (m_rt_func_used_idx[abs_c64] == -1) { - m_rt_func_used_idx[abs_c64] = no_of_types++; - } - wasm::emit_call(m_code_section, m_al, m_rt_func_used_idx[abs_c64]); - wasm::emit_f64_const(m_code_section, m_al, 0.0); - wasm::emit_f64_gt(m_code_section, m_al); - } else { - std::string msg = "ComplexToLogical: Conversion from kinds " + - std::to_string(arg_kind) + " to " + - std::to_string(dest_kind) + - " not supported"; - throw CodeGenError(msg); - } - break; - } - case (ASR::cast_kindType::LogicalToInteger): { - int arg_kind = -1, dest_kind = -1; - extract_kinds(x, arg_kind, dest_kind); - if (arg_kind > 0 && dest_kind > 0) { - if (arg_kind == 4 && dest_kind == 8) { - wasm::emit_i64_extend_i32_s(m_code_section, m_al); - } else if (arg_kind == 4 && dest_kind == 4) { - } else { - std::string msg = "Conversion from kinds " + - std::to_string(arg_kind) + " to " + - std::to_string(dest_kind) + - " not supported"; - throw CodeGenError(msg); - } - } - break; - } - case (ASR::cast_kindType::LogicalToReal): { - int arg_kind = -1, dest_kind = -1; - extract_kinds(x, arg_kind, dest_kind); - if (arg_kind > 0 && dest_kind > 0) { - if (arg_kind == 4 && dest_kind == 4) { - wasm::emit_f32_convert_i32_s(m_code_section, m_al); - } else if (arg_kind == 4 && dest_kind == 8) { - wasm::emit_f64_convert_i32_s(m_code_section, m_al); - } else { - std::string msg = "Conversion from kinds " + - std::to_string(arg_kind) + " to " + - std::to_string(dest_kind) + - " not supported"; - throw CodeGenError(msg); - } - } - break; - } - case (ASR::cast_kindType::IntegerToInteger): { - int arg_kind = -1, dest_kind = -1; - extract_kinds(x, arg_kind, dest_kind); - if (arg_kind > 0 && dest_kind > 0 && arg_kind != dest_kind) { - if (arg_kind == 4 && dest_kind == 8) { - wasm::emit_i64_extend_i32_s(m_code_section, m_al); - } else if (arg_kind == 8 && dest_kind == 4) { - wasm::emit_i32_wrap_i64(m_code_section, m_al); - } else { - std::string msg = "Conversion from " + - std::to_string(arg_kind) + " to " + - std::to_string(dest_kind) + - " not implemented yet."; - throw CodeGenError(msg); - } - } - break; - } - case (ASR::cast_kindType::RealToReal): { - int arg_kind = -1, dest_kind = -1; - extract_kinds(x, arg_kind, dest_kind); - if (arg_kind > 0 && dest_kind > 0 && arg_kind != dest_kind) { - if (arg_kind == 4 && dest_kind == 8) { - wasm::emit_f64_promote_f32(m_code_section, m_al); - } else if (arg_kind == 8 && dest_kind == 4) { - wasm::emit_f32_demote_f64(m_code_section, m_al); - } else { - std::string msg = "Conversion from " + - std::to_string(arg_kind) + " to " + - std::to_string(dest_kind) + - " not implemented yet."; - throw CodeGenError(msg); - } - } - break; - } - case (ASR::cast_kindType::ComplexToComplex): { - throw CodeGenError("ComplexToComplex: Complex types are not supported yet."); - break; - } - case (ASR::cast_kindType::ComplexToReal): { - throw CodeGenError("ComplexToReal: Complex types are not supported yet."); - break; - } - default: - throw CodeGenError("Cast kind not implemented"); - } - } - - void visit_ComplexRe(const ASR::ComplexRe_t &x) { - this->visit_expr(*x.m_arg); - wasm::emit_drop(m_code_section, m_al); - } - - void visit_ComplexIm(const ASR::ComplexIm_t &x) { - this->visit_expr(*x.m_arg); - - int a_kind = ASRUtils::extract_kind_from_ttype_t(ASRUtils::expr_type(x.m_arg)); - wasm::emit_set_global(m_code_section, m_al, - (a_kind == 4) ? m_global_var_name_idx_map[tmp_reg_f32] - : m_global_var_name_idx_map[tmp_reg_f64]); - wasm::emit_drop(m_code_section, m_al); - wasm::emit_get_global(m_code_section, m_al, - (a_kind == 4) ? m_global_var_name_idx_map[tmp_reg_f32] - : m_global_var_name_idx_map[tmp_reg_f64]); - } - - void emit_call_fd_write(int filetype, const std::string &str, int iov_vec_len, int return_val_mem_loc) { - wasm::emit_i32_const(m_code_section, m_al, filetype); // file type: 1 for stdout - wasm::emit_i32_const(m_code_section, m_al, m_string_to_iov_loc_map[str]); // iov location - wasm::emit_i32_const(m_code_section, m_al, iov_vec_len); // size of iov vector - wasm::emit_i32_const(m_code_section, m_al, return_val_mem_loc); // mem_loction to return no. of bytes written - // call WASI fd_write - wasm::emit_call(m_code_section, m_al, m_import_func_idx_map[fd_write]); - wasm::emit_drop(m_code_section, m_al); - } - - template - void handle_print(const T &x) { - for (size_t i = 0; i < x.n_values; i++) { - if (i > 0) { - // print " " - emit_call_fd_write(1, " ", 1, 0); - } - ASR::expr_t *v = x.m_values[i]; - ASR::ttype_t *t = ASRUtils::expr_type(v); - int a_kind = ASRUtils::extract_kind_from_ttype_t(t); - - if (ASRUtils::is_integer(*t) || ASRUtils::is_logical(*t)) { - if (m_rt_func_used_idx[print_i64] == -1) { - m_rt_func_used_idx[print_i64] = no_of_types++; - } - this->visit_expr(*x.m_values[i]); - switch (a_kind) { - case 4: { - wasm::emit_i64_extend_i32_s(m_code_section, m_al); - wasm::emit_call(m_code_section, m_al, m_rt_func_used_idx[print_i64]); - break; - } - case 8: { - wasm::emit_call(m_code_section, m_al, m_rt_func_used_idx[print_i64]); - break; - } - default: { - throw CodeGenError( - R"""(Printing support is currently available only - for 32, and 64 bit integer kinds.)"""); - } - } - } else if (ASRUtils::is_real(*t)) { - if (m_rt_func_used_idx[print_i64] == -1) { - m_rt_func_used_idx[print_i64] = no_of_types++; - } - if (m_rt_func_used_idx[print_f64] == -1) { - m_rt_func_used_idx[print_f64] = no_of_types++; - } - this->visit_expr(*x.m_values[i]); - switch (a_kind) { - case 4: { - wasm::emit_f64_promote_f32(m_code_section, m_al); - wasm::emit_call(m_code_section, m_al, m_rt_func_used_idx[print_f64]); - break; - } - case 8: { - wasm::emit_call(m_code_section, m_al, m_rt_func_used_idx[print_f64]); - break; - } - default: { - throw CodeGenError( - R"""(Printing support is available only - for 32, and 64 bit real kinds.)"""); - } - } - } else if (t->type == ASR::ttypeType::Character) { - wasm::emit_i32_const(m_code_section, m_al, 1); // file type: 1 for stdout - this->visit_expr(*x.m_values[i]); // iov location - wasm::emit_i32_const(m_code_section, m_al, 1); // size of iov vector - wasm::emit_i32_const(m_code_section, m_al, 0); // mem_loction to return no. of bytes written - - // call WASI fd_write - wasm::emit_call(m_code_section, m_al, m_import_func_idx_map[fd_write]); - wasm::emit_drop(m_code_section, m_al); - } else if (t->type == ASR::ttypeType::Complex) { - if (m_rt_func_used_idx[print_i64] == -1) { - m_rt_func_used_idx[print_i64] = no_of_types++; - } - if (m_rt_func_used_idx[print_f64] == -1) { - m_rt_func_used_idx[print_f64] = no_of_types++; - } - emit_call_fd_write(1, "(", 1, 0); - this->visit_expr(*x.m_values[i]); - if (a_kind == 4) { - wasm::emit_f64_promote_f32(m_code_section, m_al); - wasm::emit_set_global(m_code_section, m_al, m_global_var_name_idx_map[tmp_reg_f64]); - wasm::emit_f64_promote_f32(m_code_section, m_al); - } else { - wasm::emit_set_global(m_code_section, m_al, m_global_var_name_idx_map[tmp_reg_f64]); - } - wasm::emit_call(m_code_section, m_al, m_rt_func_used_idx[print_f64]); - emit_call_fd_write(1, ",", 1, 0); - wasm::emit_get_global(m_code_section, m_al, m_global_var_name_idx_map[tmp_reg_f64]); - wasm::emit_call(m_code_section, m_al, m_rt_func_used_idx[print_f64]); - emit_call_fd_write(1, ")", 1, 0); - } - } - - // print "\n" newline character - emit_call_fd_write(1, "\n", 1, 0); - } - - void visit_Print(const ASR::Print_t &x) { - if (x.m_fmt != nullptr) { - diag.codegen_warning_label( - "format string in `print` is not implemented yet and it is " - "currently treated as '*'", - {x.m_fmt->base.loc}, "treated as '*'"); - } - handle_print(x); - } - - void visit_FileWrite(const ASR::FileWrite_t &x) { - if (x.m_fmt != nullptr) { - diag.codegen_warning_label( - "format string in `print` is not implemented yet and it is " - "currently treated as '*'", - {x.m_fmt->base.loc}, "treated as '*'"); - } - if (x.m_unit != nullptr) { - diag.codegen_error_label("unit in write() is not implemented yet", - {x.m_unit->base.loc}, "not implemented"); - throw CodeGenAbort(); - } - handle_print(x); - } - - void visit_FileRead(const ASR::FileRead_t &x) { - if (x.m_fmt != nullptr) { - diag.codegen_warning_label( - "format string in read() is not implemented yet and it is " - "currently treated as '*'", - {x.m_fmt->base.loc}, "treated as '*'"); - } - if (x.m_unit != nullptr) { - diag.codegen_error_label("unit in read() is not implemented yet", - {x.m_unit->base.loc}, "not implemented"); - throw CodeGenAbort(); - } - diag.codegen_error_label( - "The intrinsic function read() is not implemented yet in the LLVM " - "backend", - {x.base.base.loc}, "not implemented"); - throw CodeGenAbort(); - } - - void print_msg(std::string msg) { - msg += "\n"; - emit_string(msg); - emit_call_fd_write(1, msg, 1, 0); - } - - void exit() { - // exit_code would be on stack, so set this exit code using - // proc_exit(). this exit code would be read by JavaScript glue code - wasm::emit_call(m_code_section, m_al, m_import_func_idx_map[proc_exit]); - wasm::emit_unreachable(m_code_section, m_al); // raise trap/exception - } - - void visit_ArrayBound(const ASR::ArrayBound_t& x) { - ASR::ttype_t *ttype = ASRUtils::expr_type(x.m_v); - uint32_t kind = ASRUtils::extract_kind_from_ttype_t(ttype); - ASR::dimension_t *m_dims; - int n_dims = ASRUtils::extract_dimensions_from_ttype(ttype, m_dims); - if (kind != 4) { - throw CodeGenError("ArrayBound: Kind 4 only supported currently"); - } - - if (x.m_dim) { - ASR::expr_t *val = ASRUtils::expr_value(x.m_dim); - - if (!ASR::is_a(*val)) { - throw CodeGenError("ArrayBound: Only constant dim values supported currently"); - } - ASR::IntegerConstant_t *dimDir = ASR::down_cast(val); - if (x.m_bound == ASR::arrayboundType::LBound) { - this->visit_expr(*m_dims[dimDir->m_n - 1].m_start); - } else { - this->visit_expr(*m_dims[dimDir->m_n - 1].m_start); - this->visit_expr(*m_dims[dimDir->m_n - 1].m_length); - wasm::emit_i32_add(m_code_section, m_al); - wasm::emit_i32_const(m_code_section, m_al, 1); - wasm::emit_i32_sub(m_code_section, m_al); - } - } else { - if (x.m_bound == ASR::arrayboundType::LBound) { - wasm::emit_i32_const(m_code_section, m_al, 1); - } else { - // emit the whole array size - if (!m_dims[0].m_length) { - throw CodeGenError( - "ArrayBound: Dimension length for index 0 does not exist"); - } - this->visit_expr(*(m_dims[0].m_length)); - for (int i = 1; i < n_dims; i++) { - this->visit_expr(*m_dims[i].m_length); - wasm::emit_i32_mul(m_code_section, m_al); - } - } - } - } - - void visit_Stop(const ASR::Stop_t &x) { - print_msg("STOP"); - if (x.m_code && - ASRUtils::expr_type(x.m_code)->type == ASR::ttypeType::Integer) { - this->visit_expr(*x.m_code); - } else { - wasm::emit_i32_const(m_code_section, m_al, 0); // zero exit code - } - exit(); - } - - void visit_ErrorStop(const ASR::ErrorStop_t & /* x */) { - print_msg("ERROR STOP"); - wasm::emit_i32_const(m_code_section, m_al, 1); // non-zero exit code - exit(); - } - - void visit_If(const ASR::If_t &x) { - emit_if_else([&](){ this->visit_expr(*x.m_test); }, [&](){ - for (size_t i = 0; i < x.n_body; i++) { - this->visit_stmt(*x.m_body[i]); - } - }, [&](){ - for (size_t i = 0; i < x.n_orelse; i++) { - this->visit_stmt(*x.m_orelse[i]); - } - }); - } - - void visit_WhileLoop(const ASR::WhileLoop_t &x) { - emit_loop([&](){ this->visit_expr(*x.m_test); }, [&](){ - for (size_t i = 0; i < x.n_body; i++) { - this->visit_stmt(*x.m_body[i]); - } - }); - } - - void visit_Exit(const ASR::Exit_t & /* x */) { - wasm::emit_branch(m_code_section, m_al, - nesting_level - cur_loop_nesting_level - - 2U); // branch to end of if - } - - void visit_Cycle(const ASR::Cycle_t & /* x */) { - wasm::emit_branch( - m_code_section, m_al, - nesting_level - cur_loop_nesting_level - 1U); // branch to start of loop - } - - void visit_Assert(const ASR::Assert_t &x) { - this->visit_expr(*x.m_test); - wasm::emit_b8(m_code_section, m_al, 0x04); // emit if start - wasm::emit_b8(m_code_section, m_al, 0x40); // empty block type - wasm::emit_b8(m_code_section, m_al, 0x05); // starting of else - if (x.m_msg) { - std::string msg = - ASR::down_cast(x.m_msg)->m_s; - print_msg("AssertionError: " + msg); - } else { - print_msg("AssertionError"); - } - wasm::emit_i32_const(m_code_section, m_al, 1); // non-zero exit code - exit(); - wasm::emit_expr_end(m_code_section, m_al); // emit if end - } -}; - -Result> asr_to_wasm_bytes_stream(ASR::TranslationUnit_t &asr, - Allocator &al, - diag::Diagnostics &diagnostics) { - ASRToWASMVisitor v(al, diagnostics); - Vec wasm_bytes; - - LCompilers::PassOptions pass_options; - pass_replace_do_loops(al, asr, pass_options); - pass_array_by_data(al, asr, pass_options); - pass_options.always_run = true; - pass_unused_functions(al, asr, pass_options); - -#ifdef SHOW_ASR - std::cout << pickle(asr, true /* use colors */, true /* indent */, - true /* with_intrinsic_modules */) - << std::endl; -#endif - try { - v.visit_asr((ASR::asr_t &)asr); - } catch (const CodeGenError &e) { - diagnostics.diagnostics.push_back(e.d); - return Error(); - } - - v.get_wasm(wasm_bytes); - - return wasm_bytes; -} - -Result asr_to_wasm(ASR::TranslationUnit_t &asr, Allocator &al, - const std::string &filename, bool time_report, - diag::Diagnostics &diagnostics) { - int time_visit_asr = 0; - int time_save = 0; - - auto t1 = std::chrono::high_resolution_clock::now(); - Result> wasm = asr_to_wasm_bytes_stream(asr, al, diagnostics); - auto t2 = std::chrono::high_resolution_clock::now(); - time_visit_asr = - std::chrono::duration_cast(t2 - t1).count(); - if (!wasm.ok) { - return wasm.error; - } - - { - auto t1 = std::chrono::high_resolution_clock::now(); - wasm::save_bin(wasm.result, filename); - auto t2 = std::chrono::high_resolution_clock::now(); - time_save = - std::chrono::duration_cast(t2 - t1) - .count(); - } - - if (time_report) { - std::cout << "Codegen Time report:" << std::endl; - std::cout << "ASR -> wasm: " << std::setw(5) << time_visit_asr - << std::endl; - std::cout << "Save: " << std::setw(5) << time_save << std::endl; - int total = time_visit_asr + time_save; - std::cout << "Total: " << std::setw(5) << total << std::endl; - } - return 0; -} - -} // namespace LCompilers diff --git a/src/libasr/codegen/asr_to_wasm.h b/src/libasr/codegen/asr_to_wasm.h deleted file mode 100644 index e6456f6737..0000000000 --- a/src/libasr/codegen/asr_to_wasm.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef LFORTRAN_ASR_TO_WASM_H -#define LFORTRAN_ASR_TO_WASM_H - -#include - -namespace LCompilers { - -// Generates a wasm binary stream from ASR -Result> asr_to_wasm_bytes_stream(ASR::TranslationUnit_t &asr, - Allocator &al, - diag::Diagnostics &diagnostics); - -// Generates a wasm binary to `filename` -Result asr_to_wasm(ASR::TranslationUnit_t &asr, Allocator &al, - const std::string &filename, bool time_report, - diag::Diagnostics &diagnostics); - -} // namespace LCompilers - -#endif // LFORTRAN_ASR_TO_WASM_H diff --git a/src/libasr/codegen/asr_to_x86.cpp b/src/libasr/codegen/asr_to_x86.cpp deleted file mode 100644 index e3002e5062..0000000000 --- a/src/libasr/codegen/asr_to_x86.cpp +++ /dev/null @@ -1,634 +0,0 @@ -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace LCompilers { - -namespace { - - // Local exception that is only used in this file to exit the visitor - // pattern and caught later (not propagated outside) - class CodeGenError - { - public: - diag::Diagnostic d; - public: - CodeGenError(const std::string &msg) - : d{diag::Diagnostic(msg, diag::Level::Error, diag::Stage::CodeGen)} - { } - }; - -} - -using ASR::down_cast; -using ASR::is_a; - -// Platform dependent fast unique hash: -uint64_t static get_hash(ASR::asr_t *node) -{ - return (uint64_t)node; -} - -class ASRToX86Visitor : public ASR::BaseVisitor -{ - struct Sym { - uint32_t stack_offset; // The local variable is [ebp-stack_offset] - std::string fn_label; // Subroutine / Function assembly label - bool pointer; // Is variable represented as a pointer (or value) - }; -public: - Allocator &m_al; - X86Assembler m_a; - std::map m_global_strings; - std::map x86_symtab; -public: - - ASRToX86Visitor(Allocator &al) : m_al{al}, m_a{al, false} {} - - void visit_TranslationUnit(const ASR::TranslationUnit_t &x) { - // All loose statements must be converted to a function, so the items - // must be empty: - LCOMPILERS_ASSERT(x.n_items == 0); - - emit_elf32_header(m_a); - - emit_data_string(m_a, "string_neg", "-"); // - symbol for printing negative ints/floats - // Add runtime library functions - emit_print_int(m_a, "print_int"); - emit_exit(m_a, "my_exit", 0); - emit_exit(m_a, "exit_error_stop", 1); - - - std::vector global_func_order = ASRUtils::determine_function_definition_order(x.m_global_scope); - for (size_t i = 0; i < global_func_order.size(); i++) { - ASR::symbol_t* sym = x.m_global_scope->get_symbol(global_func_order[i]); - // Ignore external symbols because they are already defined by the loop above. - if( !sym || ASR::is_a(*sym) ) { - continue; - } - visit_symbol(*sym); - } - - std::vector build_order = ASRUtils::determine_module_dependencies(x); - for (auto &item : build_order) { - ASR::symbol_t *mod = x.m_global_scope->get_symbol(item); - visit_symbol(*mod); - } - - // Then the main program: - for (auto &item : x.m_global_scope->get_scope()) { - if (ASR::is_a(*item.second)) { - visit_symbol(*item.second); - } - } - - emit_elf32_footer(m_a); - } - - void visit_Module(const ASR::Module_t &x) { - std::vector func_order - = ASRUtils::determine_function_definition_order(x.m_symtab); - for (size_t i = 0; i < func_order.size(); i++) { - ASR::symbol_t* sym = x.m_symtab->get_symbol(func_order[i]); - // Ignore external symbols because they are already defined by the loop above. - if( !sym || ASR::is_a(*sym) ) { - continue; - } - visit_symbol(*sym); - } - } - - void visit_Program(const ASR::Program_t &x) { - - - - std::vector func_order = ASRUtils::determine_function_definition_order(x.m_symtab); - // Generate code for nested subroutines and functions first: - for (auto &item : func_order) { - ASR::symbol_t* sym = x.m_symtab->get_symbol(item); - ASR::Function_t *s = ASR::down_cast(sym); - visit_Function(*s); - } - - // Generate code for the main program - m_a.add_label("_start"); - - // Initialize the stack - m_a.asm_push_r32(X86Reg::ebp); - m_a.asm_mov_r32_r32(X86Reg::ebp, X86Reg::esp); - - // Allocate stack space for local variables - uint32_t total_offset = 0; - for (auto &item : x.m_symtab->get_scope()) { - if (is_a(*item.second)) { - ASR::Variable_t *v = down_cast(item.second); - - if (v->m_type->type == ASR::ttypeType::Integer) { - total_offset += 4; - Sym s; - s.stack_offset = total_offset; - s.pointer = false; - uint32_t h = get_hash((ASR::asr_t*)v); - x86_symtab[h] = s; - } else { - throw CodeGenError("Variable type not supported"); - } - } - } - m_a.asm_sub_r32_imm8(X86Reg::esp, total_offset); - - for (size_t i=0; ivisit_stmt(*x.m_body[i]); - } - - m_a.asm_call_label("my_exit"); - - // Restore stack - m_a.asm_mov_r32_r32(X86Reg::esp, X86Reg::ebp); - m_a.asm_pop_r32(X86Reg::ebp); - //m_a.asm_ret(); - - for (auto &s : m_global_strings) { - emit_data_string(m_a, s.first, s.second); - } - - } - - void visit_Function(const ASR::Function_t &x) { - uint32_t h = get_hash((ASR::asr_t*)&x); - std::string id = std::to_string(h); - - // Generate code for the subroutine - Sym s; - s.stack_offset = 0; - s.pointer = false; - s.fn_label = x.m_name + id; - x86_symtab[h] = s; - m_a.add_label(s.fn_label); - - // Add arguments to x86_symtab with their correct offset - for (size_t i=0; im_intent)); - // TODO: we are assuming integer here: - LCOMPILERS_ASSERT(arg->m_type->type == ASR::ttypeType::Integer); - Sym s; - s.stack_offset = -(i*4+8); // TODO: reverse the sign of offset - // We pass intent(in) as value, otherwise as pointer - s.pointer = (arg->m_intent != ASR::intentType::In); - uint32_t h = get_hash((ASR::asr_t*)arg); - x86_symtab[h] = s; - } - - // Initialize the stack - m_a.asm_push_r32(X86Reg::ebp); - m_a.asm_mov_r32_r32(X86Reg::ebp, X86Reg::esp); - - // Allocate stack space for local variables - uint32_t total_offset = 0; - for (auto &item : x.m_symtab->get_scope()) { - if (is_a(*item.second)) { - ASR::Variable_t *v = down_cast(item.second); - - if (v->m_intent == ASRUtils::intent_local || - v->m_intent == ASRUtils::intent_return_var) { - if (v->m_type->type == ASR::ttypeType::Integer) { - total_offset += 4; - Sym s; - s.stack_offset = total_offset; - s.pointer = false; - uint32_t h = get_hash((ASR::asr_t*)v); - x86_symtab[h] = s; - } else { - throw CodeGenError("Variable type not supported"); - } - } - } - } - m_a.asm_sub_r32_imm8(X86Reg::esp, total_offset); - - for (size_t i=0; ivisit_stmt(*x.m_body[i]); - } - - // Leave return value in eax - if (x.m_return_var) { - ASR::Variable_t *retv = ASRUtils::EXPR2VAR(x.m_return_var); - - uint32_t h = get_hash((ASR::asr_t*)retv); - LCOMPILERS_ASSERT(x86_symtab.find(h) != x86_symtab.end()); - Sym s = x86_symtab[h]; - X86Reg base = X86Reg::ebp; - // mov eax, [ebp-s.stack_offset] - m_a.asm_mov_r32_m32(X86Reg::eax, &base, nullptr, 1, -s.stack_offset); - LCOMPILERS_ASSERT(!s.pointer); - } - - // Restore stack - m_a.asm_mov_r32_r32(X86Reg::esp, X86Reg::ebp); - m_a.asm_pop_r32(X86Reg::ebp); - m_a.asm_ret(); - } - - void visit_Return(const ASR::Return_t &/*x*/) { } - - // Expressions leave integer values in eax - - void visit_IntegerConstant(const ASR::IntegerConstant_t &x) { - m_a.asm_mov_r32_imm32(X86Reg::eax, x.m_n); - } - - void visit_LogicalConstant(const ASR::LogicalConstant_t &x) { - int val; - if (x.m_value == true) { - val = 1; - } else { - val = 0; - } - m_a.asm_mov_r32_imm32(X86Reg::eax, val); - } - - void visit_Var(const ASR::Var_t &x) { - ASR::Variable_t *v = ASR::down_cast(x.m_v); - uint32_t h = get_hash((ASR::asr_t*)v); - LCOMPILERS_ASSERT(x86_symtab.find(h) != x86_symtab.end()); - Sym s = x86_symtab[h]; - X86Reg base = X86Reg::ebp; - // mov eax, [ebp-s.stack_offset] - m_a.asm_mov_r32_m32(X86Reg::eax, &base, nullptr, 1, -s.stack_offset); - if (s.pointer) { - base = X86Reg::eax; - // Dereference a pointer - // mov eax, [eax] - m_a.asm_mov_r32_m32(X86Reg::eax, &base, nullptr, 1, 0); - } - } - - void visit_IntegerBinOp(const ASR::IntegerBinOp_t &x) { - this->visit_expr(*x.m_right); - m_a.asm_push_r32(X86Reg::eax); - this->visit_expr(*x.m_left); - m_a.asm_pop_r32(X86Reg::ecx); - // The left operand is in eax, the right operand is in ecx - // Leave the result in eax. - switch (x.m_op) { - case ASR::binopType::Add: { - m_a.asm_add_r32_r32(X86Reg::eax, X86Reg::ecx); - break; - }; - case ASR::binopType::Sub: { - m_a.asm_sub_r32_r32(X86Reg::eax, X86Reg::ecx); - break; - }; - case ASR::binopType::Mul: { - m_a.asm_mov_r32_imm32(X86Reg::edx, 0); - m_a.asm_mul_r32(X86Reg::ecx); - break; - }; - case ASR::binopType::Div: { - m_a.asm_mov_r32_imm32(X86Reg::edx, 0); - m_a.asm_div_r32(X86Reg::ecx); - break; - }; - default: { - throw CodeGenError("Binary operator '" + ASRUtils::binop_to_str_python(x.m_op) + "' not supported yet"); - } - } - } - - void visit_IntegerUnaryMinus(const ASR::IntegerUnaryMinus_t &x) { - this->visit_expr(*x.m_arg); - m_a.asm_neg_r32(X86Reg::eax); - } - - void visit_IntegerCompare(const ASR::IntegerCompare_t &x) { - std::string id = std::to_string(get_hash((ASR::asr_t*)&x)); - this->visit_expr(*x.m_right); - m_a.asm_push_r32(X86Reg::eax); - this->visit_expr(*x.m_left); - m_a.asm_pop_r32(X86Reg::ecx); - // The left operand is in eax, the right operand is in ecx - // Leave the result in eax. - m_a.asm_cmp_r32_r32(X86Reg::eax, X86Reg::ecx); - switch (x.m_op) { - case (ASR::cmpopType::Eq) : { - m_a.asm_je_label(".compare1" + id); - break; - } - case (ASR::cmpopType::Gt) : { - m_a.asm_jg_label(".compare1" + id); - break; - } - case (ASR::cmpopType::GtE) : { - m_a.asm_jge_label(".compare1" + id); - break; - } - case (ASR::cmpopType::Lt) : { - m_a.asm_jl_label(".compare1" + id); - break; - } - case (ASR::cmpopType::LtE) : { - m_a.asm_jle_label(".compare1" + id); - break; - } - case (ASR::cmpopType::NotEq) : { - m_a.asm_jne_label(".compare1" + id); - break; - } - default : { - throw CodeGenError("Comparison operator not implemented"); - } - } - m_a.asm_mov_r32_imm32(X86Reg::eax, 0); - m_a.asm_jmp_label(".compareend" + id); - m_a.add_label(".compare1" + id); - m_a.asm_mov_r32_imm32(X86Reg::eax, 1); - m_a.add_label(".compareend" + id); - } - - void visit_Assignment(const ASR::Assignment_t &x) { - this->visit_expr(*x.m_value); - // RHS is in eax - - ASR::Variable_t *v = ASRUtils::EXPR2VAR(x.m_target); - uint32_t h = get_hash((ASR::asr_t*)v); - LCOMPILERS_ASSERT(x86_symtab.find(h) != x86_symtab.end()); - Sym s = x86_symtab[h]; - X86Reg base = X86Reg::ebp; - if (s.pointer) { - // mov ecx, [ebp-s.stack_offset] - m_a.asm_mov_r32_m32(X86Reg::ecx, &base, nullptr, 1, -s.stack_offset); - // mov [ecx], eax - base = X86Reg::ecx; - m_a.asm_mov_m32_r32(&base, nullptr, 1, 0, X86Reg::eax); - } else { - // mov [ebp-s.stack_offset], eax - m_a.asm_mov_m32_r32(&base, nullptr, 1, -s.stack_offset, X86Reg::eax); - } - } - - void visit_Print(const ASR::Print_t &x) { - LCOMPILERS_ASSERT(x.n_values == 1); - ASR::expr_t *e = x.m_values[0]; - if (e->type == ASR::exprType::StringConstant) { - ASR::StringConstant_t *s = down_cast(e); - std::string msg = s->m_s; - msg += "\n"; - std::string id = "string" + std::to_string(get_hash((ASR::asr_t*)e)); - emit_print(m_a, id, msg.size()); - m_global_strings[id] = msg; - } else { - this->visit_expr(*e); - ASR::ttype_t *t = ASRUtils::expr_type(e); - if (t->type == ASR::ttypeType::Integer) { - m_a.asm_push_r32(X86Reg::eax); - m_a.asm_call_label("print_int"); - m_a.asm_add_r32_imm8(X86Reg::esp, 4); - } else if (t->type == ASR::ttypeType::Real) { - throw LCompilersException("Type not implemented"); - } else if (t->type == ASR::ttypeType::Character) { - throw LCompilersException("Type not implemented"); - } else { - throw LCompilersException("Type not implemented"); - } - - - std::string msg = "\n"; - std::string id = "string" + std::to_string(get_hash((ASR::asr_t*)e)); - emit_print(m_a, id, msg.size()); - m_global_strings[id] = msg; - } - } - - void visit_ErrorStop(const ASR::ErrorStop_t &x) { - std::string id = "err" + std::to_string(get_hash((ASR::asr_t*)&x)); - std::string msg = "ERROR STOP\n"; - emit_print(m_a, id, msg.size()); - m_global_strings[id] = msg; - - m_a.asm_call_label("exit_error_stop"); - } - - void visit_If(const ASR::If_t &x) { - std::string id = std::to_string(get_hash((ASR::asr_t*)&x)); - this->visit_expr(*x.m_test); - // eax contains the logical value (true=1, false=0) of the if condition - m_a.asm_cmp_r32_imm8(X86Reg::eax, 1); - m_a.asm_je_label(".then" + id); - m_a.asm_jmp_label(".else" + id); - m_a.add_label(".then" + id); - for (size_t i=0; ivisit_stmt(*x.m_body[i]); - } - m_a.asm_jmp_label(".endif" +id); - m_a.add_label(".else" + id); - for (size_t i=0; ivisit_stmt(*x.m_orelse[i]); - } - m_a.add_label(".endif" + id); - } - - void visit_WhileLoop(const ASR::WhileLoop_t &x) { - std::string id = std::to_string(get_hash((ASR::asr_t*)&x)); - - // head - m_a.add_label(".loop.head" + id); - this->visit_expr(*x.m_test); - // eax contains the logical value (true=1, false=0) of the while condition - m_a.asm_cmp_r32_imm8(X86Reg::eax, 1); - m_a.asm_je_label(".loop.body" + id); - m_a.asm_jmp_label(".loop.end" + id); - - // body - m_a.add_label(".loop.body" + id); - for (size_t i=0; ivisit_stmt(*x.m_body[i]); - } - m_a.asm_jmp_label(".loop.head" + id); - - // end - m_a.add_label(".loop.end" + id); - } - - // Push arguments to stack (last argument first) - template - uint8_t push_call_args(const T &x, const T2 &sub) { - LCOMPILERS_ASSERT(sub.n_args == x.n_args); - // Note: when counting down in a loop, we have to use signed ints - // for `i`, so that it can become negative and fail the i>=0 condition. - for (int i=x.n_args-1; i>=0; i--) { - bool pass_as_pointer; - { - ASR::Variable_t *arg = ASRUtils::EXPR2VAR(sub.m_args[i]); - LCOMPILERS_ASSERT(ASRUtils::is_arg_dummy(arg->m_intent)); - // TODO: we are assuming integer here: - LCOMPILERS_ASSERT(arg->m_type->type == ASR::ttypeType::Integer); - uint32_t h = get_hash((ASR::asr_t*)arg); - Sym &s = x86_symtab[h]; - pass_as_pointer = s.pointer; - } - if (x.m_args[i].m_value->type == ASR::exprType::Var) { - ASR::Variable_t *arg = ASRUtils::EXPR2VAR(x.m_args[i].m_value); - uint32_t h = get_hash((ASR::asr_t*)arg); - LCOMPILERS_ASSERT(x86_symtab.find(h) != x86_symtab.end()); - Sym s = x86_symtab[h]; - X86Reg base = X86Reg::ebp; - if (s.pointer) { - if (pass_as_pointer) { - // Copy over the stack variable (already a pointer) - // mov eax, [ebp-s.stack_offset] - m_a.asm_mov_r32_m32(X86Reg::eax, &base, nullptr, 1, -s.stack_offset); - } else { - // Copy and dereference the stack variable - - // Copy - // mov eax, [ebp-s.stack_offset] - m_a.asm_mov_r32_m32(X86Reg::eax, &base, nullptr, 1, -s.stack_offset); - - // Dereference a pointer - // mov eax, [eax] - m_a.asm_mov_r32_m32(X86Reg::eax, &base, nullptr, 1, 0); - } - m_a.asm_push_r32(X86Reg::eax); - } else { - if (pass_as_pointer) { - // Get a pointer to the stack variable - // lea eax, [ebp-s.stack_offset] - m_a.asm_lea_r32_m32(X86Reg::eax, &base, nullptr, 1, -s.stack_offset); - } else { - // Copy over the stack variable - // mov eax, [ebp-s.stack_offset] - m_a.asm_mov_r32_m32(X86Reg::eax, &base, nullptr, 1, -s.stack_offset); - } - m_a.asm_push_r32(X86Reg::eax); - } - } else { - LCOMPILERS_ASSERT(!pass_as_pointer); - this->visit_expr(*(x.m_args[i].m_value)); - // The value of the argument is in eax, push it onto the stack - m_a.asm_push_r32(X86Reg::eax); - } - } - return x.n_args*4; - } - - void visit_SubroutineCall(const ASR::SubroutineCall_t &x) { - ASR::Function_t *s = ASR::down_cast( - ASRUtils::symbol_get_past_external(x.m_name)); - - uint32_t h = get_hash((ASR::asr_t*)s); - if (x86_symtab.find(h) == x86_symtab.end()) { - throw CodeGenError("Subroutine code not generated for '" - + std::string(s->m_name) + "'"); - } - Sym &sym = x86_symtab[h]; - // Push arguments to stack (last argument first) - uint8_t arg_offset = push_call_args(x, *s); - // Call the subroutine - m_a.asm_call_label(sym.fn_label); - // Remove arguments from stack - m_a.asm_add_r32_imm8(X86Reg::esp, arg_offset); - } - - void visit_FunctionCall(const ASR::FunctionCall_t &x) { - ASR::Function_t *s = ASR::down_cast(x.m_name); - - uint32_t h = get_hash((ASR::asr_t*)s); - if (x86_symtab.find(h) == x86_symtab.end()) { - throw CodeGenError("Function code not generated for '" - + std::string(s->m_name) + "'"); - } - Sym &sym = x86_symtab[h]; - // Push arguments to stack (last argument first) - uint8_t arg_offset = push_call_args(x, *s); - // Call the function (the result is in eax, we leave it there) - m_a.asm_call_label(sym.fn_label); - // Remove arguments from stack - m_a.asm_add_r32_imm8(X86Reg::esp, arg_offset); - } - -}; - - -Result asr_to_x86(ASR::TranslationUnit_t &asr, Allocator &al, - const std::string &filename, bool time_report, - diag::Diagnostics &diagnostics) -{ - int time_pass_global=0; - int time_pass_do_loops=0; - int time_visit_asr=0; - int time_verify=0; - int time_save=0; - - ASRToX86Visitor v(al); - - LCompilers::PassOptions pass_options; - pass_options.run_fun = "f"; - - { - auto t1 = std::chrono::high_resolution_clock::now(); - pass_wrap_global_stmts_into_function(al, asr, pass_options); - auto t2 = std::chrono::high_resolution_clock::now(); - time_pass_global = std::chrono::duration_cast(t2 - t1).count(); - } - - { - auto t1 = std::chrono::high_resolution_clock::now(); - pass_replace_do_loops(al, asr, pass_options); - auto t2 = std::chrono::high_resolution_clock::now(); - time_pass_do_loops = std::chrono::duration_cast(t2 - t1).count(); - } - - { - auto t1 = std::chrono::high_resolution_clock::now(); - try { - v.visit_asr((ASR::asr_t &)asr); - } catch (const CodeGenError &e) { - diagnostics.diagnostics.push_back(e.d); - return Error(); - } - auto t2 = std::chrono::high_resolution_clock::now(); - time_visit_asr = std::chrono::duration_cast(t2 - t1).count(); - } - - { - auto t1 = std::chrono::high_resolution_clock::now(); - v.m_a.verify(); - auto t2 = std::chrono::high_resolution_clock::now(); - time_verify = std::chrono::duration_cast(t2 - t1).count(); - } - - { - auto t1 = std::chrono::high_resolution_clock::now(); - v.m_a.save_binary(filename); - auto t2 = std::chrono::high_resolution_clock::now(); - time_save = std::chrono::duration_cast(t2 - t1).count(); - } - - //! Helpful for debugging - // std::cout << v.m_a.get_asm() << std::endl; - - if (time_report) { - std::cout << "Codegen Time report:" << std::endl; - std::cout << "Global: " << std::setw(5) << time_pass_global << std::endl; - std::cout << "Do loops: " << std::setw(5) << time_pass_do_loops << std::endl; - std::cout << "ASR -> x86: " << std::setw(5) << time_visit_asr << std::endl; - std::cout << "Verify: " << std::setw(5) << time_verify << std::endl; - std::cout << "Save: " << std::setw(5) << time_save << std::endl; - int total = time_pass_global + time_pass_do_loops + time_visit_asr + time_verify + time_verify + time_save; - std::cout << "Total: " << std::setw(5) << total << std::endl; - } - return 0; -} - -} // namespace LCompilers diff --git a/src/libasr/codegen/asr_to_x86.h b/src/libasr/codegen/asr_to_x86.h deleted file mode 100644 index 415e663a4e..0000000000 --- a/src/libasr/codegen/asr_to_x86.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef LFORTRAN_ASR_TO_X86_H -#define LFORTRAN_ASR_TO_X86_H - -#include - -namespace LCompilers { - - // Generates a 32-bit x86 Linux executable binary `filename` - Result asr_to_x86(ASR::TranslationUnit_t &asr, Allocator &al, - const std::string &filename, bool time_report, - diag::Diagnostics &diagnostics); - -} // namespace LCompilers - -#endif // LFORTRAN_ASR_TO_X86_H diff --git a/src/libasr/codegen/c_utils.h b/src/libasr/codegen/c_utils.h deleted file mode 100644 index ffb9fb8717..0000000000 --- a/src/libasr/codegen/c_utils.h +++ /dev/null @@ -1,1382 +0,0 @@ -#ifndef LFORTRAN_C_UTILS_H -#define LFORTRAN_C_UTILS_H - -#include -#include - -namespace LCompilers { - - static inline std::string format_type_c(const std::string &dims, const std::string &type, - const std::string &name, bool use_ref, bool /*dummy*/) - { - std::string fmt; - std::string ref = ""; - if (use_ref) ref = "*"; - if( dims == "*" ) { - fmt = type + " " + dims + ref + name; - } else { - fmt = type + " " + ref + name + dims; - } - return fmt; - } - - // Local exception that is only used in this file to exit the visitor - // pattern and caught later (not propagated outside) - class CodeGenError - { - public: - diag::Diagnostic d; - public: - CodeGenError(const std::string &msg) - : d{diag::Diagnostic(msg, diag::Level::Error, diag::Stage::CodeGen)} - { } - - CodeGenError(const std::string &msg, const Location &loc) - : d{diag::Diagnostic(msg, diag::Level::Error, diag::Stage::CodeGen, { - diag::Label("", {loc}) - })} - { } - }; - - class Abort {}; - -namespace CUtils { - - static inline bool is_non_primitive_DT(ASR::ttype_t *t) { - return ASR::is_a(*t) || ASR::is_a(*t) || ASR::is_a(*t); - } - - class CUtilFunctions { - - private: - - SymbolTable* global_scope; - std::map util2func; - - int indentation_level, indentation_spaces; - - public: - - std::string util_func_decls; - std::string util_funcs; - - CUtilFunctions() { - util2func.clear(); - util_func_decls.clear(); - util_funcs.clear(); - } - - void set_indentation(int indendation_level_, int indendation_space_) { - indentation_level = indendation_level_; - indentation_spaces = indendation_space_; - } - - void set_global_scope(SymbolTable* global_scope_) { - global_scope = global_scope_; - } - - std::string get_generated_code() { - return util_funcs; - } - - std::string get_util_func_decls() { - return util_func_decls; - } - - void array_size() { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string array_size_func; - if( util2func.find("array_size") == util2func.end() ) { - array_size_func = global_scope->get_unique_name("array_size"); - util2func["array_size"] = array_size_func; - } else { - return ; - } - array_size_func = util2func["array_size"]; - std::string signature = "static inline int32_t " + array_size_func + "(struct dimension_descriptor dims[], size_t n)"; - util_func_decls += indent + signature + ";\n"; - std::string body = indent + signature + " {\n"; - body += indent + tab + "int32_t size = 1;\n"; - body += indent + tab + "for (size_t i = 0; i < n; i++) {\n"; - body += indent + tab + tab + "size *= dims[i].length;\n"; - body += indent + tab + "}\n"; - body += indent + tab + "return size;\n"; - body += indent + "}\n\n"; - util_funcs += body; - } - - void array_deepcopy(ASR::ttype_t* array_type_asr, std::string array_type_name, - std::string array_encoded_type_name, std::string array_type_str) { - LCOMPILERS_ASSERT(!is_non_primitive_DT(array_type_asr)); - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string array_dc_func; - if( util2func.find("array_deepcopy_" + array_encoded_type_name) == util2func.end() ) { - array_dc_func = global_scope->get_unique_name("array_deepcopy_" + array_encoded_type_name); - util2func["array_deepcopy_" + array_encoded_type_name] = array_dc_func; - } else { - return ; - } - array_dc_func = util2func["array_deepcopy_" + array_encoded_type_name]; - std::string array_types_decls = ""; - std::string signature = "void " + array_dc_func + "(" - + array_type_str + " src, " - + array_type_str + " dest)"; - util_func_decls += "inline " + signature + ";\n"; - std::string body = indent + signature + " {\n"; - body += indent + tab + "int32_t src_size = " + get_array_size() + "(src->dims, src->n_dims);\n"; - body += indent + tab + "memcpy(dest->data, src->data, src_size * sizeof(" + array_type_name +"));\n"; - body += indent + tab + "memcpy(dest->dims, src->dims, 32 * sizeof(struct dimension_descriptor));\n"; - body += indent + tab + "dest->n_dims = src->n_dims;\n"; - body += indent + tab + "dest->is_allocated = src->is_allocated;\n"; - body += indent + "}\n\n"; - util_funcs += body; - } - - void array_reshape(std::string array_type, std::string shape_type, - std::string return_type, std::string element_type, - std::string array_type_code) { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string array_reshape_func; - if( util2func.find("array_reshape_" + array_type_code) == util2func.end() ) { - array_reshape_func = global_scope->get_unique_name("array_reshape_" + array_type_code); - util2func["array_reshape_" + array_type_code] = array_reshape_func; - } else { - return ; - } - array_reshape_func = util2func["array_reshape_" + array_type_code]; - std::string signature = "static inline " + return_type + "* " + array_reshape_func + "(" + - array_type + " array" + ", " + shape_type + " shape)"; - util_func_decls += indent + signature + ";\n"; - std::string body = indent + signature + " {\n"; - body += indent + tab + "int32_t n = shape->dims[0].length;\n"; - body += indent + tab + return_type + "* reshaped = (" + return_type + "*) malloc(sizeof(" + return_type + "));\n"; - body += indent + tab + "int32_t array_size_ = " + get_array_size() + "(array->dims, array->n_dims);\n"; - body += indent + tab + "int32_t shape_size_ = " + get_array_size() + "(shape->dims, shape->n_dims);\n"; - body += indent + tab + "int32_t reshaped_size = 1;\n"; - body += indent + tab + "for (int32_t i = 0; i < shape_size_; i++) {\n"; - body += indent + tab + tab + "reshaped_size *= shape->data[i];\n"; - body += indent + tab + "}\n"; - body += indent + tab + "ASSERT(array_size_ == reshaped_size);\n"; - body += indent + tab + "reshaped->data = (" + element_type + "*) malloc(sizeof(" + element_type + ")*array_size_);\n"; - body += indent + tab + "reshaped->data = (" + element_type + "*) memcpy(reshaped->data, array->data, sizeof(" + element_type + ")*array_size_);\n"; - body += indent + tab + "reshaped->n_dims = shape_size_;\n"; - body += indent + tab + "for (int32_t i = 0; i < shape_size_; i++) {\n"; - body += indent + tab + tab + "reshaped->dims[i].lower_bound = 0;\n"; - body += indent + tab + tab + "reshaped->dims[i].length = shape->data[i];\n"; - body += indent + tab + "}\n"; - body += indent + tab + "return reshaped;\n"; - body += indent + "}\n\n"; - util_funcs += body; - } - - void array_constant(std::string return_type, std::string element_type, - std::string array_type_code) { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string array_const_func; - if( util2func.find("array_constant_" + array_type_code) == util2func.end() ) { - array_const_func = global_scope->get_unique_name("array_constant_" + array_type_code); - util2func["array_constant_" + array_type_code] = array_const_func; - } else { - return ; - } - array_const_func = util2func["array_constant_" + array_type_code]; - std::string signature = "static inline " + return_type + "* " + array_const_func + "(int32_t n, ...)"; - util_func_decls += indent + signature + ";\n"; - std::string body = indent + signature + " {\n"; - body += indent + tab + return_type + "* const_array = (" + return_type + "*) malloc(sizeof(" + return_type + "));\n"; - body += indent + tab + "va_list ap;\n"; - body += indent + tab + "va_start(ap, n);\n"; - body += indent + tab + "const_array->data = (" + element_type + "*) malloc(sizeof(" + element_type + ")*n);\n"; - body += indent + tab + "const_array->n_dims = 1;\n"; - body += indent + tab + "const_array->dims[0].lower_bound = 0;\n"; - body += indent + tab + "const_array->dims[0].length = n;\n"; - body += indent + tab + "for (int32_t i = 0; i < n; i++) {\n"; - body += indent + tab + tab + "const_array->data[i] = va_arg(ap, " + element_type +");\n"; - body += indent + tab + "}\n"; - body += indent + tab + "va_end(ap);\n"; - body += indent + tab + "return const_array;\n"; - body += indent + "}\n\n"; - util_funcs += body; - } - - std::string get_array_size() { - array_size(); - return util2func["array_size"]; - } - - std::string get_array_reshape( - std::string array_type, std::string shape_type, - std::string return_type, std::string element_type, - std::string array_type_code) { - array_reshape(array_type, shape_type, - return_type, element_type, - array_type_code); - return util2func["array_reshape_" + array_type_code]; - } - - std::string get_array_constant(std::string return_type, - std::string element_type, std::string encoded_type) { - array_constant(return_type, element_type, encoded_type); - return util2func["array_constant_" + encoded_type]; - } - - std::string get_array_deepcopy(ASR::ttype_t* array_type_asr, - std::string array_type_name, std::string array_encoded_type_name, - std::string array_type_str) { - array_deepcopy(array_type_asr, array_type_name, - array_encoded_type_name, array_type_str); - return util2func["array_deepcopy_" + array_encoded_type_name]; - } - }; - - static inline std::string get_tuple_type_code(ASR::Tuple_t *tup) { - std::string result = "tuple_"; - for (size_t i = 0; i < tup->n_type; i++) { - result += ASRUtils::get_type_code(tup->m_type[i], true); - if (i + 1 != tup->n_type) { - result += "_"; - } - } - return result; - } - - static inline std::string get_struct_type_code(ASR::Struct_t* struct_t) { - return ASRUtils::symbol_name(struct_t->m_derived_type); - } - - static inline std::string get_c_type_from_ttype_t(ASR::ttype_t* t, - bool is_c=true) { - int kind = ASRUtils::extract_kind_from_ttype_t(t); - std::string type_src = ""; - switch( t->type ) { - case ASR::ttypeType::Integer: { - type_src = "int" + std::to_string(kind * 8) + "_t"; - break; - } - case ASR::ttypeType::Logical: { - type_src = "bool"; - break; - } - case ASR::ttypeType::Real: { - if( kind == 4 ) { - type_src = "float"; - } else if( kind == 8 ) { - type_src = "double"; - } else { - throw CodeGenError(std::to_string(kind * 8) + "-bit floating points not yet supported."); - } - break; - } - case ASR::ttypeType::Character: { - type_src = "char*"; - break; - } - case ASR::ttypeType::Pointer: { - ASR::Pointer_t* ptr_type = ASR::down_cast(t); - type_src = get_c_type_from_ttype_t(ptr_type->m_type) + "*"; - break; - } - case ASR::ttypeType::CPtr: { - type_src = "void*"; - break; - } - case ASR::ttypeType::Struct: { - ASR::Struct_t* der_type = ASR::down_cast(t); - type_src = std::string("struct ") + ASRUtils::symbol_name(der_type->m_derived_type); - break; - } - case ASR::ttypeType::List: { - ASR::List_t* list_type = ASR::down_cast(t); - std::string list_element_type = get_c_type_from_ttype_t(list_type->m_type); - std::string list_type_code = ASRUtils::get_type_code(list_type->m_type, true); - type_src = "struct list_" + list_type_code; - break; - } - case ASR::ttypeType::Tuple: { - ASR::Tuple_t* tup_type = ASR::down_cast(t); - type_src = "struct " + get_tuple_type_code(tup_type); - break; - } - case ASR::ttypeType::Complex: { - if( kind == 4 ) { - if( is_c ) { - type_src = "float complex"; - } else { - type_src = "std::complex"; - } - } else if( kind == 8 ) { - if( is_c ) { - type_src = "double complex"; - } else { - type_src = "std::complex"; - } - } else { - throw CodeGenError(std::to_string(kind * 8) + "-bit floating points not yet supported."); - } - break; - } - default: { - throw CodeGenError("Type " + ASRUtils::type_to_str_python(t) + " not supported yet."); - } - } - return type_src; - } - -} // namespace CUtils - - -class CCPPDSUtils { - private: - - std::map typecodeToDStype; - std::map> typecodeToDSfuncs; - std::map compareTwoDS; - std::map printFuncs; - std::map eltypedims2arraytype; - CUtils::CUtilFunctions* c_utils_functions; - - int indentation_level, indentation_spaces; - - std::string generated_code; - std::string func_decls; - - SymbolTable* global_scope; - bool is_c; - Platform platform; - - public: - - CCPPDSUtils(bool is_c, Platform &platform): is_c{is_c}, platform{platform} { - generated_code.clear(); - func_decls.clear(); - } - - void set_c_utils_functions(CUtils::CUtilFunctions* c_utils_functions_) { - c_utils_functions = c_utils_functions_; - } - - void set_indentation(int indendation_level_, int indendation_space_) { - indentation_level = indendation_level_; - indentation_spaces = indendation_space_; - } - - void set_global_scope(SymbolTable* global_scope_) { - global_scope = global_scope_; - } - - std::string get_compare_func(ASR::ttype_t *t) { - std::string type_code = ASRUtils::get_type_code(t, true); - return compareTwoDS[type_code]; - } - - std::string get_print_func(ASR::ttype_t *t) { - std::string type_code = ASRUtils::get_type_code(t, true); - return printFuncs[type_code]; - } - - std::string get_deepcopy(ASR::ttype_t *t, std::string value, std::string target) { - std::string result; - switch (t->type) { - case ASR::ttypeType::List : { - ASR::List_t* list_type = ASR::down_cast(t); - std::string list_type_code = ASRUtils::get_type_code(list_type->m_type, true); - std::string func = typecodeToDSfuncs[list_type_code]["list_deepcopy"]; - result = func + "(&" + value + ", &" + target + ");"; - break; - } - case ASR::ttypeType::Tuple : { - ASR::Tuple_t* tup_type = ASR::down_cast(t); - std::string tup_type_code = CUtils::get_tuple_type_code(tup_type); - std::string func = typecodeToDSfuncs[tup_type_code]["tuple_deepcopy"]; - result = func + "(" + value + ", &" + target + ");"; - break; - } - case ASR::ttypeType::Dict : { - std::string d_type_code = ASRUtils::get_type_code(t, true); - std::string func = typecodeToDSfuncs[d_type_code]["dict_deepcopy"]; - result = func + "(&" + value + ", &" + target + ");"; - break; - } - case ASR::ttypeType::Character : { - if (is_c) { - result = "_lfortran_strcpy(&" + target + ", " + value + ");"; - } else { - result = target + " = " + value + ";"; - } - break; - } - case ASR::ttypeType::Struct: { - std::string func = get_struct_deepcopy_func(t); - result = func + "(" + value + ", " + target + ");"; - break; - } - case ASR::ttypeType::Integer: - case ASR::ttypeType::Real: - case ASR::ttypeType::Complex: - case ASR::ttypeType::Logical: { - if( !ASRUtils::is_array(t) ) { - result = target + " = " + value + ";"; - } else { - if( is_c ) { - std::string func = get_array_deepcopy_func(t); - result = func + "(" + value + ", " + target + ");"; - } else { - result = target + " = " + value + ";"; - } - } - break; - } - default: { - result = target + " = " + value + ";"; - } - } - return result; - } - - std::string get_type(ASR::ttype_t *t) { - LCOMPILERS_ASSERT(CUtils::is_non_primitive_DT(t)); - if (ASR::is_a(*t)) { - ASR::List_t* list_type = ASR::down_cast(t); - return get_list_type(list_type); - } else if (ASR::is_a(*t)) { - ASR::Tuple_t* tup_type = ASR::down_cast(t); - return get_tuple_type(tup_type); - } - LCOMPILERS_ASSERT(false); - } - - std::string get_print_type(ASR::ttype_t *t, bool deref_ptr) { - switch (t->type) { - case ASR::ttypeType::Integer: { - ASR::Integer_t *i = (ASR::Integer_t*)t; - switch (i->m_kind) { - case 1: { return "%d"; } - case 2: { return "%d"; } - case 4: { return "%d"; } - case 8: { - if (platform == Platform::Linux) { - return "%li"; - } else { - return "%lli"; - } - } - default: { throw LCompilersException("Integer kind not supported"); } - } - } - case ASR::ttypeType::Real: { - ASR::Real_t *r = (ASR::Real_t*)t; - switch (r->m_kind) { - case 4: { return "%f"; } - case 8: { return "%lf"; } - default: { throw LCompilersException("Float kind not supported"); } - } - } - case ASR::ttypeType::Logical: { - return "%d"; - } - case ASR::ttypeType::Character: { - return "%s"; - } - case ASR::ttypeType::CPtr: { - return "%p"; - } - case ASR::ttypeType::Complex: { - return "(%f, %f)"; - } - case ASR::ttypeType::Pointer: { - if( !deref_ptr ) { - return "%p"; - } else { - ASR::Pointer_t* type_ptr = ASR::down_cast(t); - return get_print_type(type_ptr->m_type, false); - } - } - case ASR::ttypeType::Enum: { - ASR::ttype_t* enum_underlying_type = ASRUtils::get_contained_type(t); - return get_print_type(enum_underlying_type, deref_ptr); - } - case ASR::ttypeType::Const: { - ASR::ttype_t* const_underlying_type = ASRUtils::get_contained_type(t); - return get_print_type(const_underlying_type, deref_ptr); - } - default : throw LCompilersException("Not implemented"); - } - } - - std::string get_array_type(std::string type_name, std::string encoded_type_name, - std::string& array_types_decls, bool make_ptr=true, - bool create_if_not_present=true) { - if( eltypedims2arraytype.find(encoded_type_name) != eltypedims2arraytype.end() ) { - if( make_ptr ) { - return eltypedims2arraytype[encoded_type_name] + "*"; - } else { - return eltypedims2arraytype[encoded_type_name]; - } - } - - LCOMPILERS_ASSERT(create_if_not_present); - - std::string struct_name; - std::string new_array_type; - struct_name = "struct " + encoded_type_name; - std::string array_data = format_type_c("*", type_name, "data", false, false); - new_array_type = struct_name + "\n{\n " + array_data + - ";\n struct dimension_descriptor dims[32];\n" + - " int32_t n_dims;\n" - " bool is_allocated;\n};\n"; - if( make_ptr ) { - type_name = struct_name + "*"; - } - eltypedims2arraytype[encoded_type_name] = struct_name; - array_types_decls += "\n" + new_array_type + "\n"; - return type_name; - } - - std::string get_list_type(ASR::List_t* list_type) { - std::string list_element_type = CUtils::get_c_type_from_ttype_t(list_type->m_type); - if (CUtils::is_non_primitive_DT(list_type->m_type)) { - // Make sure the nested types work - get_type(list_type->m_type); - } - std::string list_type_code = ASRUtils::get_type_code(list_type->m_type, true); - if( typecodeToDStype.find(list_type_code) != typecodeToDStype.end() ) { - return typecodeToDStype[list_type_code]; - } - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string list_struct_type = "struct list_" + list_type_code; - typecodeToDStype[list_type_code] = list_struct_type; - func_decls += indent + list_struct_type + " {\n"; - func_decls += indent + tab + "int32_t capacity;\n"; - func_decls += indent + tab + "int32_t current_end_point;\n"; - func_decls += indent + tab + list_element_type + "* data;\n"; - func_decls += indent + "};\n\n"; - generate_compare_funcs((ASR::ttype_t *)list_type); - generate_print_funcs((ASR::ttype_t *)list_type); - list_init(list_struct_type, list_type_code, list_element_type); - list_deepcopy(list_struct_type, list_type_code, list_element_type, list_type->m_type); - resize_if_needed(list_struct_type, list_type_code, list_element_type); - list_append(list_struct_type, list_type_code, list_element_type, list_type->m_type); - list_insert(list_struct_type, list_type_code, list_element_type, list_type->m_type); - list_find_item_position(list_struct_type, list_type_code, list_element_type, list_type->m_type); - list_remove(list_struct_type, list_type_code, list_element_type, list_type->m_type); - list_clear(list_struct_type, list_type_code, list_element_type); - list_concat(list_struct_type, list_type_code, list_element_type, list_type->m_type); - list_section(list_struct_type, list_type_code); - return list_struct_type; - } - - std::string get_list_deepcopy_func(ASR::List_t* list_type) { - std::string list_type_code = ASRUtils::get_type_code(list_type->m_type, true); - return typecodeToDSfuncs[list_type_code]["list_deepcopy"]; - } - - std::string get_struct_deepcopy_func(ASR::ttype_t* struct_type_asr) { - ASR::Struct_t* struct_type = ASR::down_cast(struct_type_asr); - std::string struct_type_code = CUtils::get_struct_type_code(struct_type); - if( typecodeToDSfuncs.find(struct_type_code) == typecodeToDSfuncs.end() ) { - struct_deepcopy(struct_type_asr); - } - return typecodeToDSfuncs[struct_type_code]["struct_deepcopy"]; - } - - std::string get_array_deepcopy_func(ASR::ttype_t* array_type_asr) { - LCOMPILERS_ASSERT(is_c); - std::string array_type_name = CUtils::get_c_type_from_ttype_t(array_type_asr); - std::string array_encoded_type_name = ASRUtils::get_type_code(array_type_asr, true, false, false); - std::string array_types_decls = ""; - std::string array_type_str = get_array_type(array_type_name, array_encoded_type_name, - array_types_decls, true, false); - return c_utils_functions->get_array_deepcopy(array_type_asr, array_type_name, - array_encoded_type_name, array_type_str); - } - - std::string get_list_init_func(ASR::List_t* list_type) { - std::string list_type_code = ASRUtils::get_type_code(list_type->m_type, true); - return typecodeToDSfuncs[list_type_code]["list_init"]; - } - - std::string get_list_append_func(ASR::List_t* list_type) { - std::string list_type_code = ASRUtils::get_type_code(list_type->m_type, true); - return typecodeToDSfuncs[list_type_code]["list_append"]; - } - - std::string get_list_insert_func(ASR::List_t* list_type) { - std::string list_type_code = ASRUtils::get_type_code(list_type->m_type, true); - return typecodeToDSfuncs[list_type_code]["list_insert"]; - } - - std::string get_list_resize_func(std::string list_type_code) { - return typecodeToDSfuncs[list_type_code]["list_resize"]; - } - - std::string get_list_remove_func(ASR::List_t* list_type) { - std::string list_type_code = ASRUtils::get_type_code(list_type->m_type, true); - return typecodeToDSfuncs[list_type_code]["list_remove"]; - } - - std::string get_list_concat_func(ASR::List_t* list_type) { - std::string list_type_code = ASRUtils::get_type_code(list_type->m_type, true); - return typecodeToDSfuncs[list_type_code]["list_concat"]; - } - - std::string get_list_find_item_position_function(std::string list_type_code) { - return typecodeToDSfuncs[list_type_code]["list_find_item"]; - } - - std::string get_list_clear_func(ASR::List_t* list_type) { - std::string list_type_code = ASRUtils::get_type_code(list_type->m_type, true); - return typecodeToDSfuncs[list_type_code]["list_clear"]; - } - - std::string get_list_section_func(ASR::List_t* list_type) { - std::string list_type_code = ASRUtils::get_type_code(list_type->m_type, true); - return typecodeToDSfuncs[list_type_code]["list_section"]; - } - - std::string get_generated_code() { - return generated_code; - } - - std::string get_func_decls() { - return func_decls; - } - - void generate_print_funcs(ASR::ttype_t *t) { - std::string type_code = ASRUtils::get_type_code(t, true); - if (printFuncs.find(type_code) != printFuncs.end()) { - return; - } - std::string element_type = CUtils::get_c_type_from_ttype_t(t); - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string p_func = global_scope->get_unique_name("print_" + type_code); - printFuncs[type_code] = p_func; - std::string tmp_gen = ""; - std::string signature = "void " + p_func + "(" + element_type + " a)"; - func_decls += indent + "inline " + signature + ";\n"; - signature = indent + signature; - if (ASR::is_a(*t)) { - ASR::ttype_t *tt = ASR::down_cast(t)->m_type; - generate_print_funcs(tt); - std::string ele_func = printFuncs[ASRUtils::get_type_code(tt, true)]; - tmp_gen += indent + signature + " {\n"; - tmp_gen += indent + tab + "printf(\"[\");\n"; - tmp_gen += indent + tab + "for (int i=0; i(*t)) { - ASR::Tuple_t *tt = ASR::down_cast(t); - tmp_gen += indent + signature + " {\n"; - tmp_gen += indent + tab + "printf(\"(\");\n"; - for (size_t i=0; in_type; i++) { - generate_print_funcs(tt->m_type[i]); - std::string ele_func = printFuncs[ASRUtils::get_type_code(tt->m_type[i], true)]; - std::string num = std::to_string(i); - tmp_gen += indent + tab + ele_func + "(a.element_" + num + ");\n"; - if (i+1 != tt->n_type) - tmp_gen += indent + tab + "printf(\", \");\n"; - } - tmp_gen += indent + tab + "printf(\")\");\n"; - } else if (ASR::is_a(*t)) { - tmp_gen += indent + signature + " {\n"; - std::string print_type = get_print_type(t, false); - tmp_gen += indent + tab + "printf(\"" + print_type + "\", creal(a), cimag(a));\n"; - } else if (ASR::is_a(*t)) { - tmp_gen += indent + signature + " {\n"; - std::string print_type = get_print_type(t, false); - tmp_gen += indent + tab + "printf(\"'" + print_type + "'\", a);\n"; - } else { - tmp_gen += indent + signature + " {\n"; - std::string print_type = get_print_type(t, false); - tmp_gen += indent + tab + "printf(\"" + print_type + "\", a);\n"; - } - tmp_gen += indent + "}\n\n"; - generated_code += tmp_gen; - } - - void generate_compare_funcs(ASR::ttype_t *t) { - std::string type_code = ASRUtils::get_type_code(t, true); - if (compareTwoDS.find(type_code) != compareTwoDS.end()) { - return; - } - std::string element_type = CUtils::get_c_type_from_ttype_t(t); - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string cmp_func = global_scope->get_unique_name("compare_" + type_code); - compareTwoDS[type_code] = cmp_func; - std::string tmp_gen = ""; - if (ASR::is_a(*t)) { - std::string signature = "bool " + cmp_func + "(" + element_type + " a, " + element_type + " b)"; - func_decls += indent + "inline " + signature + ";\n"; - signature = indent + signature; - tmp_gen += indent + signature + " {\n"; - ASR::ttype_t *tt = ASR::down_cast(t)->m_type; - generate_compare_funcs(tt); - std::string ele_func = compareTwoDS[ASRUtils::get_type_code(tt, true)]; - tmp_gen += indent + tab + "if (a.current_end_point != b.current_end_point)\n"; - tmp_gen += indent + tab + tab + "return false;\n"; - tmp_gen += indent + tab + "for (int i=0; i(*t)) { - ASR::Tuple_t *tt = ASR::down_cast(t); - std::string signature = "bool " + cmp_func + "(" + element_type + " a, " + element_type+ " b)"; - func_decls += indent + "inline " + signature + ";\n"; - signature = indent + signature; - tmp_gen += indent + signature + " {\n"; - tmp_gen += indent + tab + "if (a.length != b.length)\n"; - tmp_gen += indent + tab + tab + "return false;\n"; - tmp_gen += indent + tab + "bool ans = true;\n"; - for (size_t i=0; in_type; i++) { - generate_compare_funcs(tt->m_type[i]); - std::string ele_func = compareTwoDS[ASRUtils::get_type_code(tt->m_type[i], true)]; - std::string num = std::to_string(i); - tmp_gen += indent + tab + "ans &= " + ele_func + "(a.element_" + - num + ", " + "b.element_" + num + ");\n"; - } - tmp_gen += indent + tab + "return ans;\n"; - } else if (ASR::is_a(*t)) { - std::string signature = "bool " + cmp_func + "(" + element_type + " a, " + element_type + " b)"; - func_decls += indent + "inline " + signature + ";\n"; - signature = indent + signature; - tmp_gen += indent + signature + " {\n"; - tmp_gen += indent + tab + "return strcmp(a, b) == 0;\n"; - } else { - std::string signature = "bool " + cmp_func + "(" + element_type + " a, " + element_type + " b)"; - func_decls += indent + "inline " + signature + ";\n"; - signature = indent + signature; - tmp_gen += indent + signature + " {\n"; - tmp_gen += indent + tab + "return a == b;\n"; - } - tmp_gen += indent + "}\n\n"; - generated_code += tmp_gen; - } - - void list_init(std::string list_struct_type, - std::string list_type_code, - std::string list_element_type) { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string list_init_func = global_scope->get_unique_name("list_init_" + list_type_code); - typecodeToDSfuncs[list_type_code]["list_init"] = list_init_func; - std::string signature = "void " + list_init_func + "(" + list_struct_type + "* x, int32_t capacity)"; - func_decls += indent + "inline " + signature + ";\n"; - signature = indent + signature; - generated_code += indent + signature + " {\n"; - generated_code += indent + tab + "x->capacity = capacity;\n"; - generated_code += indent + tab + "x->current_end_point = 0;\n"; - generated_code += indent + tab + "x->data = (" + list_element_type + "*) " + - "malloc(capacity * sizeof(" + list_element_type + "));\n"; - generated_code += indent + "}\n\n"; - } - - void list_clear(std::string list_struct_type, - std::string list_type_code, - std::string list_element_type) { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string list_init_func = global_scope->get_unique_name("list_clear_" + list_type_code); - typecodeToDSfuncs[list_type_code]["list_clear"] = list_init_func; - std::string signature = "void " + list_init_func + "(" + list_struct_type + "* x)"; - func_decls += indent + "inline " + signature + ";\n"; - signature = indent + signature; - generated_code += indent + signature + " {\n"; - generated_code += indent + tab + "free(x->data);\n"; - generated_code += indent + tab + "x->capacity = 4;\n"; - generated_code += indent + tab + "x->current_end_point = 0;\n"; - generated_code += indent + tab + "x->data = (" + list_element_type + "*) " + - "malloc(x->capacity * sizeof(" + list_element_type + "));\n"; - generated_code += indent + "}\n\n"; - } - - void struct_deepcopy(ASR::ttype_t* struct_type_asr) { - ASR::Struct_t* struct_type = ASR::down_cast(struct_type_asr); - ASR::StructType_t* struct_type_t = ASR::down_cast( - ASRUtils::symbol_get_past_external(struct_type->m_derived_type)); - std::string struct_type_code = CUtils::get_struct_type_code(struct_type); - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string struct_dc_func = global_scope->get_unique_name("struct_deepcopy_" + struct_type_code); - typecodeToDSfuncs[struct_type_code]["struct_deepcopy"] = struct_dc_func; - std::string struct_type_str = CUtils::get_c_type_from_ttype_t(struct_type_asr); - std::string signature = "void " + struct_dc_func + "(" - + struct_type_str + "* src, " - + struct_type_str + "* dest)"; - func_decls += "inline " + signature + ";\n"; - generated_code += indent + signature + " {\n"; - for( auto item: struct_type_t->m_symtab->get_scope() ) { - ASR::ttype_t* member_type_asr = ASRUtils::symbol_type(item.second); - if( CUtils::is_non_primitive_DT(member_type_asr) || - ASR::is_a(*member_type_asr) ) { - generated_code += indent + tab + get_deepcopy(member_type_asr, "&(src->" + item.first + ")", - "&(dest->" + item.first + ")") + ";\n"; - } else if( ASRUtils::is_array(member_type_asr) ) { - ASR::dimension_t* m_dims = nullptr; - size_t n_dims = ASRUtils::extract_dimensions_from_ttype(member_type_asr, m_dims); - if( ASRUtils::is_fixed_size_array(m_dims, n_dims) ) { - std::string array_size = std::to_string(ASRUtils::get_fixed_size_of_array(m_dims, n_dims)); - array_size += "*sizeof(" + CUtils::get_c_type_from_ttype_t(member_type_asr) + ")"; - generated_code += indent + tab + "memcpy(dest->" + item.first + ", src->" + item.first + - ", " + array_size + ");\n"; - } else { - generated_code += indent + tab + get_deepcopy(member_type_asr, "src->" + item.first, - "dest->" + item.first) + ";\n"; - } - } else { - generated_code += indent + tab + "dest->" + item.first + " = " + " src->" + item.first + ";\n"; - } - } - generated_code += indent + "}\n\n"; - } - - void list_deepcopy(std::string list_struct_type, - std::string list_type_code, - std::string list_element_type, ASR::ttype_t *m_type) { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string list_dc_func = global_scope->get_unique_name("list_deepcopy_" + list_type_code); - typecodeToDSfuncs[list_type_code]["list_deepcopy"] = list_dc_func; - std::string signature = "void " + list_dc_func + "(" - + list_struct_type + "* src, " - + list_struct_type + "* dest)"; - func_decls += "inline " + signature + ";\n"; - generated_code += indent + signature + " {\n"; - generated_code += indent + tab + "dest->capacity = src->capacity;\n"; - generated_code += indent + tab + "dest->current_end_point = src->current_end_point;\n"; - generated_code += indent + tab + "dest->data = (" + list_element_type + "*) " + - "malloc(src->capacity * sizeof(" + list_element_type + "));\n"; - generated_code += indent + tab + "memcpy(dest->data, src->data, " + - "src->capacity * sizeof(" + list_element_type + "));\n"; - if (ASR::is_a(*m_type)) { - ASR::ttype_t *tt = ASR::down_cast(m_type)->m_type; - std::string deep_copy_func = typecodeToDSfuncs[ASRUtils::get_type_code(tt, true)]["list_deepcopy"]; - LCOMPILERS_ASSERT(deep_copy_func.size() > 0); - generated_code += indent + tab + "for(int i=0; icurrent_end_point; i++)\n"; - generated_code += indent + tab + tab + deep_copy_func + "(&src->data[i], &dest->data[i]);\n"; - } - generated_code += indent + "}\n\n"; - } - - void list_concat(std::string list_struct_type, - std::string list_type_code, - std::string list_element_type, ASR::ttype_t *m_type) { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string list_con_func = global_scope->get_unique_name("list_concat_" + list_type_code); - typecodeToDSfuncs[list_type_code]["list_concat"] = list_con_func; - std::string init_func = typecodeToDSfuncs[list_type_code]["list_init"]; - std::string signature = list_struct_type + "* " + list_con_func + "(" - + list_struct_type + "* left, " - + list_struct_type + "* right)"; - func_decls += "inline " + signature + ";\n"; - generated_code += indent + signature + " {\n"; - generated_code += indent + tab + list_struct_type + " *result = (" + list_struct_type + "*)malloc(sizeof(" + - list_struct_type + "));\n"; - generated_code += indent + tab + init_func + "(result, left->current_end_point + right->current_end_point);\n"; - if (ASR::is_a(*m_type)) { - ASR::ttype_t *tt = ASR::down_cast(m_type)->m_type; - std::string deep_copy_func = typecodeToDSfuncs[ASRUtils::get_type_code(tt, true)]["list_deepcopy"]; - LCOMPILERS_ASSERT(deep_copy_func.size() > 0); - generated_code += indent + tab + "for(int i=0; icurrent_end_point; i++)\n"; - generated_code += indent + tab + tab + deep_copy_func + "(&left->data[i], &result->data[i]);\n"; - generated_code += indent + tab + "for(int i=0; icurrent_end_point; i++)\n"; - generated_code += indent + tab + tab + deep_copy_func + "(&right->data[i], &result->data[i+left->current_end_point]);\n"; - } else { - generated_code += indent + tab + "memcpy(result->data, left->data, " + - "left->current_end_point * sizeof(" + list_element_type + "));\n"; - generated_code += indent + tab + "memcpy(result->data + left->current_end_point, right->data, " + - "right->current_end_point * sizeof(" + list_element_type + "));\n"; - } - generated_code += indent + tab + "result->current_end_point = left->current_end_point + right->current_end_point;\n"; - generated_code += indent + tab + "return result;\n"; - generated_code += indent + "}\n\n"; - } - - void resize_if_needed(std::string list_struct_type, - std::string list_type_code, - std::string list_element_type) { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string list_resize_func = global_scope->get_unique_name("resize_if_needed_" + list_type_code); - typecodeToDSfuncs[list_type_code]["list_resize"] = list_resize_func; - std::string signature = "void " + list_resize_func + "(" + list_struct_type + "* x)"; - func_decls += indent + "inline " + signature + ";\n"; - signature = indent + signature; - generated_code += indent + signature + " {\n"; - generated_code += indent + tab + "if (x->capacity == x->current_end_point) {\n"; - generated_code += indent + tab + tab + "x->capacity = 2 * x->capacity + 1;\n"; - generated_code += indent + tab + tab + "x->data = (" + list_element_type + "*) " + - "realloc(x->data, x->capacity * sizeof(" + list_element_type + "));\n"; - generated_code += indent + tab + "}\n"; - generated_code += indent + "}\n\n"; - } - - void list_append(std::string list_struct_type, - std::string list_type_code, - std::string list_element_type, ASR::ttype_t* m_type) { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string list_append_func = global_scope->get_unique_name("list_append_" + list_type_code); - typecodeToDSfuncs[list_type_code]["list_append"] = list_append_func; - std::string signature = "void " + list_append_func + "(" - + list_struct_type + "* x, " - + list_element_type + " element)"; - func_decls += "inline " + signature + ";\n"; - generated_code += indent + signature + " {\n"; - std::string list_resize_func = get_list_resize_func(list_type_code); - generated_code += indent + tab + list_resize_func + "(x);\n"; - if( ASR::is_a(*m_type) ) { - generated_code += indent + tab + "x->data[x->current_end_point] = NULL;\n"; - } - generated_code += indent + tab + \ - get_deepcopy(m_type, "element", "x->data[x->current_end_point]") + "\n"; - generated_code += indent + tab + "x->current_end_point += 1;\n"; - generated_code += indent + "}\n\n"; - } - - void list_insert(std::string list_struct_type, - std::string list_type_code, std::string list_element_type, - ASR::ttype_t* m_type) { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string list_insert_func = global_scope->get_unique_name("list_insert_" + list_type_code); - typecodeToDSfuncs[list_type_code]["list_insert"] = list_insert_func; - std::string signature = "void " + list_insert_func + "(" - + list_struct_type + "* x, " - + "int pos, " - + list_element_type + " element)"; - func_decls += "inline " + signature + ";\n"; - generated_code += indent + signature + " {\n"; - std::string list_resize_func = get_list_resize_func(list_type_code); - generated_code += indent + tab + list_resize_func + "(x);\n"; - generated_code += indent + tab + "int pos_ptr = pos;\n"; - generated_code += indent + tab + list_element_type + " tmp_ptr = x->data[pos];\n"; - generated_code += indent + tab + list_element_type + " tmp;\n"; - - generated_code += indent + tab + "while (x->current_end_point > pos_ptr) {\n"; - generated_code += indent + tab + tab + "tmp = x->data[pos_ptr + 1];\n"; - generated_code += indent + tab + tab + "x->data[pos_ptr + 1] = tmp_ptr;\n"; - generated_code += indent + tab + tab + "tmp_ptr = tmp;\n"; - generated_code += indent + tab + tab + "pos_ptr++;\n"; - generated_code += indent + tab + "}\n\n"; - - if( ASR::is_a(*m_type) ) { - generated_code += indent + tab + "x->data[pos] = NULL;\n"; - } - generated_code += indent + tab + get_deepcopy(m_type, "element", "x->data[pos]") + "\n"; - generated_code += indent + tab + "x->current_end_point += 1;\n"; - generated_code += indent + "}\n\n"; - } - - void list_find_item_position(std::string list_struct_type, - std::string list_type_code, std::string list_element_type, - ASR::ttype_t* /*m_type*/) { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string list_find_item_pos_func = global_scope->get_unique_name("list_find_item_" + list_type_code); - typecodeToDSfuncs[list_type_code]["list_find_item"] = list_find_item_pos_func; - std::string signature = "int " + list_find_item_pos_func + "(" - + list_struct_type + "* x, " - + list_element_type + " element)"; - std::string cmp_func = compareTwoDS[list_type_code]; - func_decls += "inline " + signature + ";\n"; - generated_code += indent + signature + " {\n"; - generated_code += indent + tab + "int el_pos = 0;\n"; - generated_code += indent + tab + "while (x->current_end_point > el_pos) {\n"; - generated_code += indent + tab + tab + "if (" + cmp_func + "(x->data[el_pos], element)) return el_pos;\n"; - generated_code += indent + tab + tab + "el_pos++;\n"; - generated_code += indent + tab + "}\n"; - generated_code += indent + tab + "return -1;\n"; - generated_code += indent + "}\n\n"; - } - - void list_remove(std::string list_struct_type, - std::string list_type_code, std::string list_element_type, - ASR::ttype_t* /*m_type*/) { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string list_remove_func = global_scope->get_unique_name("list_remove_" + list_type_code); - typecodeToDSfuncs[list_type_code]["list_remove"] = list_remove_func; - std::string signature = "void " + list_remove_func + "(" - + list_struct_type + "* x, " - + list_element_type + " element)"; - func_decls += "inline " + signature + ";\n"; - generated_code += indent + signature + " {\n"; - std::string find_item_pos_func = get_list_find_item_position_function(list_type_code); - generated_code += indent + tab + "int el_pos = " + find_item_pos_func + "(x, element);\n"; - generated_code += indent + tab + "while (x->current_end_point > el_pos) {\n"; - generated_code += indent + tab + tab + "int tmp = el_pos + 1;\n"; - generated_code += indent + tab + tab + "x->data[el_pos] = x->data[tmp];\n"; - generated_code += indent + tab + tab + "el_pos = tmp;\n"; - generated_code += indent + tab + "}\n"; - - generated_code += indent + tab + "x->current_end_point -= 1;\n"; - generated_code += indent + "}\n\n"; - } - - void list_section(std::string list_struct_type, std::string list_type_code) { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string list_section_func = global_scope->get_unique_name("list_section_" + list_type_code); - typecodeToDSfuncs[list_type_code]["list_section"] = list_section_func; - std::string signature = list_struct_type + "* " + list_section_func + "(" - + list_struct_type + "* x, " - + "int32_t idx1, int32_t idx2, int32_t step, bool i1_present, bool i2_present)"; - func_decls += "inline " + signature + ";\n"; - std::string tmp_gen = ""; - tmp_gen += indent + signature + " {\n"; - tmp_gen += indent + tab + "int s_len = x->current_end_point;\n"; - tmp_gen += indent + tab + "if (step == 0) {\n"; - tmp_gen += indent + tab + tab + "printf(\"slice step cannot be zero\");\n"; - tmp_gen += indent + tab + tab + "exit(1);\n" + tab + "}\n"; - tmp_gen += indent + tab + "idx1 = idx1 < 0 ? idx1 + s_len : idx1;\n"; - tmp_gen += indent + tab + "idx2 = idx2 < 0 ? idx2 + s_len : idx2;\n"; - tmp_gen += indent + tab + "idx1 = i1_present ? idx1 : (step > 0 ? 0 : s_len-1);\n"; - tmp_gen += indent + tab + "idx2 = i2_present ? idx2 : (step > 0 ? s_len : -1);\n"; - tmp_gen += indent + tab + "idx2 = step > 0 ? (idx2 > s_len ? s_len : idx2) : idx2;\n"; - tmp_gen += indent + tab + "idx1 = step < 0 ? (idx1 >= s_len ? s_len-1 : idx1) : idx1;\n"; - tmp_gen += indent + tab + list_struct_type + " *__tmp = (" + - list_struct_type + "*) malloc(sizeof(" + list_struct_type + "));\n"; - std::string list_init_func = typecodeToDSfuncs[list_type_code]["list_init"]; - tmp_gen += indent + tab + list_init_func + "(__tmp, 4);\n"; - tmp_gen += indent + tab + "int s_i = idx1;\n"; - tmp_gen += indent + tab + "while((step > 0 && s_i >= idx1 && s_i < idx2) ||\n"; - tmp_gen += indent + tab + " (step < 0 && s_i <= idx1 && s_i > idx2)) {\n"; - std::string list_append_func = typecodeToDSfuncs[list_type_code]["list_append"]; - tmp_gen += indent + tab + list_append_func + "(__tmp, x->data[s_i]);\n"; - tmp_gen += indent + tab + "s_i+=step;\n" + indent + tab + "}\n"; - tmp_gen += indent + tab + "return __tmp;\n}\n\n"; - generated_code += tmp_gen; - } - - std::string get_tuple_deepcopy_func(ASR::Tuple_t* tup_type) { - std::string tuple_type_code = CUtils::get_tuple_type_code(tup_type); - return typecodeToDSfuncs[tuple_type_code]["tuple_deepcopy"]; - } - - - std::string get_tuple_type(ASR::Tuple_t* tuple_type) { - std::string tuple_type_code = CUtils::get_tuple_type_code(tuple_type); - if (typecodeToDStype.find(tuple_type_code) != typecodeToDStype.end()) { - return typecodeToDStype[tuple_type_code]; - } - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string tuple_struct_type = "struct " + tuple_type_code; - typecodeToDStype[tuple_type_code] = tuple_struct_type; - std::string tmp_gen = ""; - tmp_gen += indent + tuple_struct_type + " {\n"; - tmp_gen += indent + tab + "int32_t length;\n"; - for (size_t i = 0; i < tuple_type->n_type; i++) { - if (CUtils::is_non_primitive_DT(tuple_type->m_type[i])) { - // Make sure the nested types work - get_type(tuple_type->m_type[i]); - } - tmp_gen += indent + tab + \ - CUtils::get_c_type_from_ttype_t(tuple_type->m_type[i]) + " element_" + std::to_string(i) + ";\n"; - } - tmp_gen += indent + "};\n\n"; - func_decls += tmp_gen; - generate_compare_funcs((ASR::ttype_t *)tuple_type); - generate_print_funcs((ASR::ttype_t *)tuple_type); - tuple_deepcopy(tuple_type, tuple_type_code); - return tuple_struct_type; - } - - void tuple_deepcopy(ASR::Tuple_t *t, std::string tuple_type_code) { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string tup_dc_func = global_scope->get_unique_name("tuple_deepcopy_" + tuple_type_code); - typecodeToDSfuncs[tuple_type_code]["tuple_deepcopy"] = tup_dc_func; - std::string tuple_struct_type = typecodeToDStype[tuple_type_code]; - std::string signature = "void " + tup_dc_func + "(" - + tuple_struct_type + " src, " - + tuple_struct_type + "* dest)"; - std::string tmp_def = "", tmp_gen = ""; - tmp_def += "inline " + signature + ";\n"; - tmp_gen += indent + signature + " {\n"; - for (size_t i=0; in_type; i++) { - std::string n = std::to_string(i); - if (ASR::is_a(*t->m_type[i])) { - tmp_gen += indent + tab + "dest->element_" + n + " = " + \ - "NULL;\n"; - } - tmp_gen += indent + tab + get_deepcopy(t->m_type[i], "src.element_" + n, - "dest->element_" + n) + "\n"; - } - tmp_gen += indent + tab + "dest->length = src.length;\n"; - tmp_gen += indent + "}\n\n"; - func_decls += tmp_def; - generated_code += tmp_gen; - } - - std::string get_dict_insert_func(ASR::Dict_t* d_type) { - std::string dict_type_code = ASRUtils::get_type_code((ASR::ttype_t*)d_type, true); - return typecodeToDSfuncs[dict_type_code]["dict_insert"]; - } - - std::string get_dict_get_func(ASR::Dict_t* d_type) { - std::string dict_type_code = ASRUtils::get_type_code((ASR::ttype_t*)d_type, true); - return typecodeToDSfuncs[dict_type_code]["dict_get"]; - } - - std::string get_dict_len_func(ASR::Dict_t* d_type) { - std::string dict_type_code = ASRUtils::get_type_code((ASR::ttype_t*)d_type, true); - return typecodeToDSfuncs[dict_type_code]["dict_len"]; - } - - std::string get_dict_pop_func(ASR::Dict_t* d_type) { - std::string dict_type_code = ASRUtils::get_type_code((ASR::ttype_t*)d_type, true); - return typecodeToDSfuncs[dict_type_code]["dict_pop"]; - } - - std::string get_dict_init_func(ASR::Dict_t* d_type) { - std::string dict_type_code = ASRUtils::get_type_code((ASR::ttype_t*)d_type, true); - return typecodeToDSfuncs[dict_type_code]["dict_init"]; - } - - std::string get_dict_deepcopy_func(ASR::Dict_t* d_type) { - std::string dict_type_code = ASRUtils::get_type_code((ASR::ttype_t*)d_type, true); - return typecodeToDSfuncs[dict_type_code]["dict_deepcopy"]; - } - - std::string get_dict_type(ASR::Dict_t* dict_type) { - if (!ASR::is_a(*dict_type->m_key_type)) { - throw CodeGenError("Only Integer keys supported for now in C-dictionary"); - } - std::string dict_type_code = ASRUtils::get_type_code((ASR::ttype_t*)dict_type, true); - if (typecodeToDStype.find(dict_type_code) != typecodeToDStype.end()) { - return typecodeToDStype[dict_type_code]; - } - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string dict_struct_type = "struct " + dict_type_code; - typecodeToDStype[dict_type_code] = dict_struct_type; - std::string tmp_gen = ""; - tmp_gen += indent + dict_struct_type + " {\n"; - tmp_gen += indent + tab + \ - CUtils::get_c_type_from_ttype_t(dict_type->m_key_type) + " *key;\n"; - tmp_gen += indent + tab + \ - CUtils::get_c_type_from_ttype_t(dict_type->m_value_type) + " *value;\n"; - tmp_gen += indent + tab + "int capacity;\n"; - tmp_gen += indent + tab + "bool *present;\n"; - tmp_gen += indent + "};\n\n"; - func_decls += tmp_gen; - dict_init(dict_type, dict_struct_type, dict_type_code); - dict_resize(dict_type, dict_struct_type, dict_type_code); - dict_insert(dict_type, dict_struct_type, dict_type_code); - dict_get_item(dict_type, dict_struct_type, dict_type_code); - dict_len(dict_type, dict_struct_type, dict_type_code); - dict_pop(dict_type, dict_struct_type, dict_type_code); - dict_deepcopy(dict_type, dict_struct_type, dict_type_code); - return dict_struct_type; - } - - void dict_init(ASR::Dict_t *dict_type, std::string dict_struct_type, - std::string dict_type_code) { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string dict_init_func = global_scope->get_unique_name("dict_init_" + dict_type_code); - typecodeToDSfuncs[dict_type_code]["dict_init"] = dict_init_func; - std::string signature = "void " + dict_init_func + "(" + dict_struct_type + "* x, int32_t capacity)"; - func_decls += indent + "inline " + signature + ";\n"; - signature = indent + signature; - std::string key = CUtils::get_c_type_from_ttype_t(dict_type->m_key_type); - std::string val = CUtils::get_c_type_from_ttype_t(dict_type->m_value_type); - generated_code += indent + signature + " {\n"; - generated_code += indent + tab + "x->capacity = capacity;\n"; - generated_code += indent + tab + "x->key = (" + key + "*) " + - "malloc(capacity * sizeof(" + key + "));\n"; - generated_code += indent + tab + "x->value = (" + val + "*) " + - "malloc(capacity * sizeof(" + val + "));\n"; - generated_code += indent + tab + "x->present = (bool*) " + \ - "malloc(capacity * sizeof(bool));\n"; - generated_code += indent + tab + "memset(x->present, false," +\ - "capacity * sizeof(bool));\n"; - generated_code += indent + "}\n\n"; - } - - void dict_resize(ASR::Dict_t *dict_type, std::string dict_struct_type, - std::string dict_type_code) { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string dict_rez_func = global_scope->get_unique_name("dict_resize_" + dict_type_code); - typecodeToDSfuncs[dict_type_code]["dict_resize"] = dict_rez_func; - std::string signature = "void " + dict_rez_func + "(" + dict_struct_type + "* x)"; - func_decls += indent + "inline " + signature + ";\n"; - signature = indent + signature; - std::string key = CUtils::get_c_type_from_ttype_t(dict_type->m_key_type); - std::string val = CUtils::get_c_type_from_ttype_t(dict_type->m_value_type); - generated_code += indent + signature + " {\n"; - generated_code += indent + tab + key + " *tmp_key = (" + key + " *) " + - "malloc(x->capacity * sizeof(" + key + "));\n"; - generated_code += indent + tab + "memcpy(tmp_key, x->key, x->capacity * sizeof(" +\ - key + "));\n"; - generated_code += indent + tab + val + " *tmp_val = (" + val + " *) " + - "malloc(x->capacity * sizeof(" + val + "));\n"; - generated_code += indent + tab + "memcpy(tmp_val, x->value, x->capacity * sizeof(" +\ - val + "));\n"; - generated_code += indent + tab + "bool *tmp_p = (bool *) " + - "malloc(x->capacity * sizeof(bool));\n"; - generated_code += indent + tab + \ - "memcpy(tmp_p, x->present, x->capacity * sizeof(bool));\n"; - generated_code += indent + tab + "x->capacity = 2*x->capacity+1;\n"; - generated_code += indent + tab + "free(x->key); free(x->value); free(x->present);\n"; - generated_code += indent + tab + "x->key = (" + key + "*) " + - "malloc(x->capacity * sizeof(" + key + "));\n"; - generated_code += indent + tab + "x->value = (" + val + "*) " + - "malloc(x->capacity * sizeof(" + val + "));\n"; - generated_code += indent + tab + "x->present = (bool*) " + \ - "malloc(x->capacity * sizeof(bool));\n"; - generated_code += indent + tab + "memset(x->present, false," +\ - "x->capacity * sizeof(bool));\n"; - generated_code += indent + tab + "for(size_t i=0; icapacity/2; i++) {\n"; - generated_code += indent + tab + tab + "if(tmp_p[i]) {\n"; - generated_code += indent + tab + tab + tab + "int j=tmp_key[i]\%x->capacity;\n"; - generated_code += indent + tab + tab + tab + "while(x->present[j]) j=(j+1)\%x->capacity;\n"; - generated_code += indent + tab + tab + tab + \ - "x->key[j] = tmp_key[i]; x->value[j] = tmp_val[i]; x->present[j] = true;\n"; - generated_code += indent + tab + tab + "}\n" + indent + tab + "}\n"; - generated_code += indent + tab + "free(tmp_key); free(tmp_val); free(tmp_p);\n"; - generated_code += indent + "}\n\n"; - } - - void dict_insert(ASR::Dict_t *dict_type, std::string dict_struct_type, - std::string dict_type_code) { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string dict_in_func = global_scope->get_unique_name("dict_insert_" + dict_type_code); - typecodeToDSfuncs[dict_type_code]["dict_insert"] = dict_in_func; - std::string dict_rz = typecodeToDSfuncs[dict_type_code]["dict_resize"]; - std::string key = CUtils::get_c_type_from_ttype_t(dict_type->m_key_type); - std::string val = CUtils::get_c_type_from_ttype_t(dict_type->m_value_type); - std::string signature = "void " + dict_in_func + "(" + dict_struct_type + "* x, " +\ - key + " k," + val + " v)" ; - func_decls += indent + "inline " + signature + ";\n"; - signature = indent + signature; - generated_code += indent + signature + " {\n"; - generated_code += indent + tab + "int j=k\%x->capacity; int c = 0;\n"; - generated_code += indent + tab + "while(c < x->capacity && x->present[j] && x->key[j]!=k) j=(j+1)\%x->capacity, c++;\n"; - generated_code += indent + tab + "if (c == x->capacity) {\n"; - generated_code += indent + tab + tab + dict_rz + "(x);\n"; - generated_code += indent + tab + tab + "j=k\%x->capacity;\n"; - generated_code += indent + tab + tab + "while(x->present[j]) j=(j+1)\%x->capacity;\n"; - generated_code += indent + tab + "}\n"; - generated_code += indent + tab + \ - "x->key[j] = k; x->value[j] = v; x->present[j] = true;\n"; - generated_code += indent + "}\n\n"; - } - - void dict_get_item(ASR::Dict_t *dict_type, std::string dict_struct_type, - std::string dict_type_code) { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string dict_get_func = global_scope->get_unique_name("dict_get_item_" + dict_type_code); - typecodeToDSfuncs[dict_type_code]["dict_get"] = dict_get_func; - std::string key = CUtils::get_c_type_from_ttype_t(dict_type->m_key_type); - std::string val = CUtils::get_c_type_from_ttype_t(dict_type->m_value_type); - std::string signature = val + " " + dict_get_func + "(" + dict_struct_type + "* x, " +\ - key + " k)" ; - func_decls += indent + "inline " + signature + ";\n"; - signature = indent + signature; - generated_code += indent + signature + " {\n"; - generated_code += indent + tab + "int j=k\%x->capacity, c = 0;\n"; - generated_code += indent + tab + "while(ccapacity && x->present[j] && !(x->key[j] == k)) j=(j+1)\%x->capacity, c++;\n"; - generated_code += indent + tab + "if (x->present[j] && x->key[j] == k) return x->value[j];\n"; - generated_code += indent + tab + "printf(\"Key not found\");\n"; - generated_code += indent + tab + "exit(1);\n"; - generated_code += indent + "}\n\n"; - } - - void dict_len(ASR::Dict_t *dict_type, std::string dict_struct_type, - std::string dict_type_code) { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string dict_get_func = global_scope->get_unique_name("dict_len_" + dict_type_code); - typecodeToDSfuncs[dict_type_code]["dict_len"] = dict_get_func; - std::string key = CUtils::get_c_type_from_ttype_t(dict_type->m_key_type); - std::string val = CUtils::get_c_type_from_ttype_t(dict_type->m_value_type); - std::string signature = "int32_t " + dict_get_func + "(" + dict_struct_type + "* x)"; - func_decls += indent + "inline " + signature + ";\n"; - signature = indent + signature; - generated_code += indent + signature + " {\n"; - generated_code += indent + tab + "int32_t len = 0;\n"; - generated_code += indent + tab + "for(int i=0; icapacity; i++) len += (int)x->present[i];\n"; - generated_code += indent + tab + "return len;\n"; - generated_code += indent + "}\n\n"; - } - - void dict_pop(ASR::Dict_t *dict_type, std::string dict_struct_type, - std::string dict_type_code) { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string dict_pop_func = global_scope->get_unique_name("dict_pop_" + dict_type_code); - typecodeToDSfuncs[dict_type_code]["dict_pop"] = dict_pop_func; - std::string key = CUtils::get_c_type_from_ttype_t(dict_type->m_key_type); - std::string val = CUtils::get_c_type_from_ttype_t(dict_type->m_value_type); - std::string signature = val + " " + dict_pop_func + "(" + dict_struct_type + "* x, " + key + " k)"; - func_decls += indent + "inline " + signature + ";\n"; - signature = indent + signature; - generated_code += indent + signature + " {\n"; - generated_code += indent + tab + "int j = k\%x->capacity;\n"; - generated_code += indent + tab + "for(int i=0; i < x->capacity; i++) {\n"; - generated_code += indent + tab + tab + "if (x->present[j] && x->key[j] == k) {\n"; - generated_code += indent + tab + tab + tab + "x->present[j] = false;\n"; - generated_code += indent + tab + tab + tab + "return x->value[j];\n"; - generated_code += indent + tab + tab + "}\n"; - generated_code += indent + tab + tab + "j = (j+1)\%x->capacity;\n"; - generated_code += indent + tab + "}\n"; - generated_code += indent + tab + "printf(\"Key not found\\n\"); exit(1);\n"; - generated_code += indent + "}\n\n"; - } - - void dict_deepcopy(ASR::Dict_t *dict_type, std::string dict_struct_type, - std::string dict_type_code) { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string dict_dc_func = global_scope->get_unique_name("dict_deepcopy_" + dict_type_code); - typecodeToDSfuncs[dict_type_code]["dict_deepcopy"] = dict_dc_func; - std::string key = CUtils::get_c_type_from_ttype_t(dict_type->m_key_type); - std::string val = CUtils::get_c_type_from_ttype_t(dict_type->m_value_type); - std::string signature = "void " + dict_dc_func + "(" - + dict_struct_type + "* src, " - + dict_struct_type + "* dest)"; - func_decls += "inline " + signature + ";\n"; - generated_code += indent + signature + " {\n"; - generated_code += indent + tab + "dest->capacity = src->capacity;\n"; - generated_code += indent + tab + "dest->key = (" + key + "*) " + - "malloc(dest->capacity * sizeof(" + key + "));\n"; - generated_code += indent + tab + "dest->value = (" + val + "*) " + - "malloc(dest->capacity * sizeof(" + val + "));\n"; - generated_code += indent + tab + "dest->present = (bool*) " + \ - "malloc(dest->capacity * sizeof(bool));\n"; - generated_code += indent + tab + "memcpy(dest->key, src->key, " + - "src->capacity * sizeof(" + key + "));\n"; - generated_code += indent + tab + "memcpy(dest->value, src->value, " + - "src->capacity * sizeof(" + val + "));\n"; - generated_code += indent + tab + "memcpy(dest->present, src->present, " + - "src->capacity * sizeof(bool));\n"; - generated_code += indent + "}\n\n"; - } - - ~CCPPDSUtils() { - typecodeToDStype.clear(); - generated_code.clear(); - compareTwoDS.clear(); - } -}; - -} // namespace LCompilers - -#endif // LFORTRAN_C_UTILS_H diff --git a/src/libasr/codegen/evaluator.cpp b/src/libasr/codegen/evaluator.cpp deleted file mode 100644 index 1068f1216a..0000000000 --- a/src/libasr/codegen/evaluator.cpp +++ /dev/null @@ -1,441 +0,0 @@ -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if LLVM_VERSION_MAJOR >= 14 -# include -#else -# include -#endif -#include -#include - -#include -#include -#include -#include -#include -#include - - -namespace LCompilers { - -// Extracts the integer from APInt. -// APInt does not seem to have this functionality, so we implement it here. -uint64_t APInt_getint(const llvm::APInt &i) { - // The APInt::isSingleWord() is private, but we can emulate it: - bool isSingleWord = !i.needsCleanup(); - if (isSingleWord) { - return *i.getRawData(); - } else { - throw std::runtime_error("APInt too large to fit uint64_t"); - } -} - -LLVMModule::LLVMModule(std::unique_ptr m) -{ - m_m = std::move(m); -} - -LLVMModule::~LLVMModule() = default; - -std::string LLVMModule::str() -{ - return LLVMEvaluator::module_to_string(*m_m); -} - -std::string LLVMModule::get_return_type(const std::string &fn_name) -{ - llvm::Module *m = m_m.get(); - llvm::Function *fn = m->getFunction(fn_name); - if (!fn) { - return "none"; - } - llvm::Type *type = fn->getReturnType(); - if (type->isFloatTy()) { - return "real4"; - } else if (type->isDoubleTy()) { - return "real8"; - } else if (type->isIntegerTy(32)) { - return "integer4"; - } else if (type->isIntegerTy(64)) { - return "integer8"; - } else if (type->isStructTy()) { - llvm::StructType *st = llvm::cast(type); - if (st->hasName()) { - if (startswith(std::string(st->getName()), "complex_4")) { - return "complex4"; - } else if (startswith(std::string(st->getName()), "complex_8")) { - return "complex8"; - } else { - throw LCompilersException("LLVMModule::get_return_type(): Struct return type `" + std::string(st->getName()) + "` not supported"); - } - } else { - throw LCompilersException("LLVMModule::get_return_type(): Noname struct return type not supported"); - } - } else if (type->isVectorTy()) { - // Used for passing complex_4 on some platforms - return "complex4"; - } else if (type->isVoidTy()) { - return "void"; - } else { - throw LCompilersException("LLVMModule::get_return_type(): Return type not supported"); - } -} - -extern "C" { - -float _lfortran_stan(float x); - -} - -LLVMEvaluator::LLVMEvaluator(const std::string &t) -{ - llvm::InitializeNativeTarget(); - llvm::InitializeNativeTargetAsmPrinter(); - llvm::InitializeNativeTargetAsmParser(); - -#ifdef HAVE_TARGET_AARCH64 - LLVMInitializeAArch64Target(); - LLVMInitializeAArch64TargetInfo(); - LLVMInitializeAArch64TargetMC(); - LLVMInitializeAArch64AsmPrinter(); - LLVMInitializeAArch64AsmParser(); -#endif -#ifdef HAVE_TARGET_X86 - LLVMInitializeX86Target(); - LLVMInitializeX86TargetInfo(); - LLVMInitializeX86TargetMC(); - LLVMInitializeX86AsmPrinter(); - LLVMInitializeX86AsmParser(); -#endif -#ifdef HAVE_TARGET_WASM - LLVMInitializeWebAssemblyTarget(); - LLVMInitializeWebAssemblyTargetInfo(); - LLVMInitializeWebAssemblyTargetMC(); - LLVMInitializeWebAssemblyAsmPrinter(); - LLVMInitializeWebAssemblyAsmParser(); -#endif - - context = std::make_unique(); - - if (t != "") - target_triple = t; - else - target_triple = LLVMGetDefaultTargetTriple(); - - std::string Error; - const llvm::Target *target = llvm::TargetRegistry::lookupTarget(target_triple, Error); - if (!target) { - throw LCompilersException(Error); - } - std::string CPU = "generic"; - std::string features = ""; - llvm::TargetOptions opt; - llvm::Optional RM = llvm::Reloc::Model::PIC_; - TM = target->createTargetMachine(target_triple, CPU, features, opt, RM); - - // For some reason the JIT requires a different TargetMachine - jit = cantFail(llvm::orc::KaleidoscopeJIT::Create()); - - _lfortran_stan(0.5); -} - -LLVMEvaluator::~LLVMEvaluator() -{ - jit.reset(); - context.reset(); -} - -std::unique_ptr LLVMEvaluator::parse_module(const std::string &source) -{ - llvm::SMDiagnostic err; - std::unique_ptr module - = llvm::parseAssemblyString(source, err, *context); - if (!module) { - throw LCompilersException("parse_module(): Invalid LLVM IR"); - } - bool v = llvm::verifyModule(*module); - if (v) { - throw LCompilersException("parse_module(): module failed verification."); - }; - module->setTargetTriple(target_triple); - module->setDataLayout(jit->getTargetMachine().createDataLayout()); - return module; -} - -void LLVMEvaluator::add_module(const std::string &source) { - std::unique_ptr module = parse_module(source); - // TODO: apply LLVM optimizations here - // Uncomment the below code to print the module to stdout: - /* - std::cout << "---------------------------------------------" << std::endl; - std::cout << "LLVM Module IR:" << std::endl; - std::cout << module_to_string(*module); - std::cout << "---------------------------------------------" << std::endl; - */ - add_module(std::move(module)); -} - -void LLVMEvaluator::add_module(std::unique_ptr mod) { - // These are already set in parse_module(), but we set it here again for - // cases when the Module was constructed directly, not via parse_module(). - mod->setTargetTriple(target_triple); - mod->setDataLayout(jit->getDataLayout()); - llvm::Error err = jit->addModule(std::move(mod)); - if (err) { - llvm::SmallVector buf; - llvm::raw_svector_ostream dest(buf); - llvm::logAllUnhandledErrors(std::move(err), dest, ""); - std::string msg = std::string(dest.str().data(), dest.str().size()); - if (msg[msg.size()-1] == '\n') msg = msg.substr(0, msg.size()-1); - throw LCompilersException("addModule() returned an error: " + msg); - } - -} - -void LLVMEvaluator::add_module(std::unique_ptr m) { - add_module(std::move(m->m_m)); -} - -intptr_t LLVMEvaluator::get_symbol_address(const std::string &name) { - llvm::Expected s = jit->lookup(name); - if (!s) { - llvm::Error e = s.takeError(); - llvm::SmallVector buf; - llvm::raw_svector_ostream dest(buf); - llvm::logAllUnhandledErrors(std::move(e), dest, ""); - std::string msg = std::string(dest.str().data(), dest.str().size()); - if (msg[msg.size()-1] == '\n') msg = msg.substr(0, msg.size()-1); - throw LCompilersException("lookup() failed to find the symbol '" - + name + "', error: " + msg); - } - llvm::Expected addr0 = s->getAddress(); - if (!addr0) { - llvm::Error e = addr0.takeError(); - llvm::SmallVector buf; - llvm::raw_svector_ostream dest(buf); - llvm::logAllUnhandledErrors(std::move(e), dest, ""); - std::string msg = std::string(dest.str().data(), dest.str().size()); - if (msg[msg.size()-1] == '\n') msg = msg.substr(0, msg.size()-1); - throw LCompilersException("JITSymbol::getAddress() returned an error: " + msg); - } - return (intptr_t)cantFail(std::move(addr0)); -} - -int32_t LLVMEvaluator::int32fn(const std::string &name) { - intptr_t addr = get_symbol_address(name); - int32_t (*f)() = (int32_t (*)())addr; - return f(); -} - -int64_t LLVMEvaluator::int64fn(const std::string &name) { - intptr_t addr = get_symbol_address(name); - int64_t (*f)() = (int64_t (*)())addr; - return f(); -} - -bool LLVMEvaluator::boolfn(const std::string &name) { - intptr_t addr = get_symbol_address(name); - bool (*f)() = (bool (*)())addr; - return f(); -} - -float LLVMEvaluator::floatfn(const std::string &name) { - intptr_t addr = get_symbol_address(name); - float (*f)() = (float (*)())addr; - return f(); -} - -double LLVMEvaluator::doublefn(const std::string &name) { - intptr_t addr = get_symbol_address(name); - double (*f)() = (double (*)())addr; - return f(); -} - -std::complex LLVMEvaluator::complex4fn(const std::string &name) { - intptr_t addr = get_symbol_address(name); - std::complex (*f)() = (std::complex (*)())addr; - return f(); -} - -std::complex LLVMEvaluator::complex8fn(const std::string &name) { - intptr_t addr = get_symbol_address(name); - std::complex (*f)() = (std::complex (*)())addr; - return f(); -} - -void LLVMEvaluator::voidfn(const std::string &name) { - intptr_t addr = get_symbol_address(name); - void (*f)() = (void (*)())addr; - f(); -} - -void write_file(const std::string &filename, const std::string &contents) -{ - std::ofstream out; - out.open(filename); - out << contents << std::endl; -} - -std::string LLVMEvaluator::get_asm(llvm::Module &m) -{ - llvm::legacy::PassManager pass; - llvm::CodeGenFileType ft = llvm::CGFT_AssemblyFile; - llvm::SmallVector buf; - llvm::raw_svector_ostream dest(buf); - if (jit->getTargetMachine().addPassesToEmitFile(pass, dest, nullptr, ft)) { - throw std::runtime_error("TargetMachine can't emit a file of this type"); - } - pass.run(m); - return std::string(dest.str().data(), dest.str().size()); -} - -void LLVMEvaluator::save_asm_file(llvm::Module &m, const std::string &filename) -{ - write_file(filename, get_asm(m)); -} - -void LLVMEvaluator::save_object_file(llvm::Module &m, const std::string &filename) { - m.setTargetTriple(target_triple); - m.setDataLayout(TM->createDataLayout()); - - llvm::legacy::PassManager pass; - llvm::CodeGenFileType ft = llvm::CGFT_ObjectFile; - std::error_code EC; - llvm::raw_fd_ostream dest(filename, EC, llvm::sys::fs::OF_None); - if (EC) { - throw std::runtime_error("raw_fd_ostream failed"); - } - if (TM->addPassesToEmitFile(pass, dest, nullptr, ft)) { - throw std::runtime_error("TargetMachine can't emit a file of this type"); - } - pass.run(m); - dest.flush(); -} - -void LLVMEvaluator::create_empty_object_file(const std::string &filename) { - std::string source; - std::unique_ptr module = parse_module(source); - save_object_file(*module, filename); -} - -void LLVMEvaluator::opt(llvm::Module &m) { - m.setTargetTriple(target_triple); - m.setDataLayout(TM->createDataLayout()); - - llvm::legacy::PassManager mpm; - mpm.add(new llvm::TargetLibraryInfoWrapperPass(TM->getTargetTriple())); - mpm.add(llvm::createTargetTransformInfoWrapperPass(TM->getTargetIRAnalysis())); - llvm::legacy::FunctionPassManager fpm(&m); - fpm.add(llvm::createTargetTransformInfoWrapperPass(TM->getTargetIRAnalysis())); - - int optLevel = 3; - int sizeLevel = 0; - llvm::PassManagerBuilder builder; - builder.OptLevel = optLevel; - builder.SizeLevel = sizeLevel; - builder.Inliner = llvm::createFunctionInliningPass(optLevel, sizeLevel, - false); - builder.DisableUnrollLoops = false; - builder.LoopVectorize = true; - builder.SLPVectorize = true; - builder.populateFunctionPassManager(fpm); - builder.populateModulePassManager(mpm); - - fpm.doInitialization(); - for (llvm::Function &func : m) { - fpm.run(func); - } - fpm.doFinalization(); - - mpm.add(llvm::createVerifierPass()); - mpm.run(m); -} - -std::string LLVMEvaluator::module_to_string(llvm::Module &m) { - std::string buf; - llvm::raw_string_ostream os(buf); - m.print(os, nullptr); - os.flush(); - return buf; -} - -void LLVMEvaluator::print_version_message() -{ - llvm::cl::PrintVersionMessage(); -} - -llvm::LLVMContext &LLVMEvaluator::get_context() -{ - return *context; -} - -void LLVMEvaluator::print_targets() -{ - llvm::InitializeNativeTarget(); -#ifdef HAVE_TARGET_AARCH64 - LLVMInitializeAArch64TargetInfo(); -#endif -#ifdef HAVE_TARGET_X86 - LLVMInitializeX86TargetInfo(); -#endif -#ifdef HAVE_TARGET_WASM - LLVMInitializeWebAssemblyTargetInfo(); -#endif - llvm::raw_ostream &os = llvm::outs(); - llvm::TargetRegistry::printRegisteredTargetsForVersion(os); -} - -std::string LLVMEvaluator::get_default_target_triple() -{ - return llvm::sys::getDefaultTargetTriple(); -} - -} // namespace LCompilers diff --git a/src/libasr/codegen/evaluator.h b/src/libasr/codegen/evaluator.h deleted file mode 100644 index 9c8e1a21c7..0000000000 --- a/src/libasr/codegen/evaluator.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef LFORTRAN_EVALUATOR_H -#define LFORTRAN_EVALUATOR_H - -#include -#include -#include - -#include -#include -#include -#include - -// Forward declare all needed LLVM classes without importing any LLVM header -// files. Those are only imported in evaluator.cpp and nowhere else, to speed -// up compilation. -namespace llvm { - class ExecutionEngine; - class LLVMContext; - class Module; - class Function; - class TargetMachine; - namespace orc { - class KaleidoscopeJIT; - } -} - -namespace LCompilers { - -class LLVMModule -{ -public: - std::unique_ptr m_m; - LLVMModule(std::unique_ptr m); - ~LLVMModule(); - std::string str(); - // Return a function return type as a string (real / integer) - std::string get_return_type(const std::string &fn_name); -}; - -class LLVMEvaluator -{ -private: - std::unique_ptr jit; - std::unique_ptr context; - std::string target_triple; - llvm::TargetMachine *TM; -public: - LLVMEvaluator(const std::string &t = ""); - ~LLVMEvaluator(); - std::unique_ptr parse_module(const std::string &source); - void add_module(const std::string &source); - void add_module(std::unique_ptr mod); - void add_module(std::unique_ptr m); - intptr_t get_symbol_address(const std::string &name); - int32_t int32fn(const std::string &name); - int64_t int64fn(const std::string &name); - bool boolfn(const std::string &name); - float floatfn(const std::string &name); - double doublefn(const std::string &name); - std::complex complex4fn(const std::string &name); - std::complex complex8fn(const std::string &name); - void voidfn(const std::string &name); - std::string get_asm(llvm::Module &m); - void save_asm_file(llvm::Module &m, const std::string &filename); - void save_object_file(llvm::Module &m, const std::string &filename); - void create_empty_object_file(const std::string &filename); - void opt(llvm::Module &m); - static std::string module_to_string(llvm::Module &m); - static void print_version_message(); - llvm::LLVMContext &get_context(); - static void print_targets(); - static std::string get_default_target_triple(); -}; - - -} // namespace LCompilers - -#endif // LFORTRAN_EVALUATOR_H diff --git a/src/libasr/codegen/llvm_array_utils.cpp b/src/libasr/codegen/llvm_array_utils.cpp deleted file mode 100644 index 2d52e81444..0000000000 --- a/src/libasr/codegen/llvm_array_utils.cpp +++ /dev/null @@ -1,664 +0,0 @@ -#include -#include -#include - -namespace LCompilers { - - namespace LLVMArrUtils { - - llvm::Value* lfortran_malloc(llvm::LLVMContext &context, llvm::Module &module, - llvm::IRBuilder<> &builder, llvm::Value* arg_size) { - std::string func_name = "_lfortran_malloc"; - llvm::Function *fn = module.getFunction(func_name); - if (!fn) { - llvm::FunctionType *function_type = llvm::FunctionType::get( - llvm::Type::getInt8PtrTy(context), { - llvm::Type::getInt32Ty(context) - }, true); - fn = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, func_name, module); - } - std::vector args = {arg_size}; - return builder.CreateCall(fn, args); - } - - bool compile_time_dimensions_t(ASR::dimension_t* m_dims, int n_dims) { - if( n_dims <= 0 ) { - return false; - } - bool is_ok = true; - for( int r = 0; r < n_dims; r++ ) { - if( m_dims[r].m_length == nullptr && - m_dims[r].m_start == nullptr ) { - is_ok = false; - break; - } - if( m_dims[r].m_length == nullptr ) { - is_ok = false; - break; - } - } - return is_ok; - } - - bool is_explicit_shape(ASR::Variable_t* v) { - ASR::dimension_t* m_dims; - int n_dims; - switch( v->m_type->type ) { - case ASR::ttypeType::Integer: { - ASR::Integer_t* v_type = ASR::down_cast(v->m_type); - m_dims = v_type->m_dims; - n_dims = v_type->n_dims; - break; - } - case ASR::ttypeType::Real: { - ASR::Real_t* v_type = ASR::down_cast(v->m_type); - m_dims = v_type->m_dims; - n_dims = v_type->n_dims; - break; - } - case ASR::ttypeType::Complex: { - ASR::Complex_t* v_type = ASR::down_cast(v->m_type); - m_dims = v_type->m_dims; - n_dims = v_type->n_dims; - break; - } - case ASR::ttypeType::Logical: { - ASR::Logical_t* v_type = ASR::down_cast(v->m_type); - m_dims = v_type->m_dims; - n_dims = v_type->n_dims; - break; - } - case ASR::ttypeType::Struct: { - ASR::Struct_t* v_type = ASR::down_cast(v->m_type); - m_dims = v_type->m_dims; - n_dims = v_type->n_dims; - break; - } - default: { - throw LCompilersException("Explicit shape checking supported only for integer, real, complex, logical and derived types."); - } - } - return compile_time_dimensions_t(m_dims, n_dims); - } - - std::unique_ptr - Descriptor::get_descriptor - (llvm::LLVMContext& context, - llvm::IRBuilder<>* builder, - LLVMUtils* llvm_utils, - DESCR_TYPE descr_type) { - switch( descr_type ) { - case DESCR_TYPE::_SimpleCMODescriptor: { - return std::make_unique(context, builder, llvm_utils); - } - } - return nullptr; - } - - SimpleCMODescriptor::SimpleCMODescriptor(llvm::LLVMContext& _context, - llvm::IRBuilder<>* _builder, - LLVMUtils* _llvm_utils): - context(_context), - llvm_utils(std::move(_llvm_utils)), - builder(std::move(_builder)), - dim_des(llvm::StructType::create( - context, - std::vector( - {llvm::Type::getInt32Ty(context), - llvm::Type::getInt32Ty(context), - llvm::Type::getInt32Ty(context)}), - "dimension_descriptor") - ) { - } - - bool SimpleCMODescriptor::is_array(ASR::ttype_t* asr_type) { - std::string asr_type_code = ASRUtils::get_type_code(asr_type, false, false); - return tkr2array.find(asr_type_code) != tkr2array.end(); - } - - llvm::Value* SimpleCMODescriptor:: - convert_to_argument(llvm::Value* tmp, ASR::ttype_t* asr_arg_type, - llvm::Type* arg_type, bool data_only) { - if( data_only ) { - return LLVM::CreateLoad(*builder, get_pointer_to_data(tmp)); - } - llvm::Value* arg_struct = builder->CreateAlloca(arg_type, nullptr); - llvm::Value* first_ele_ptr = nullptr; - std::string asr_arg_type_code = ASRUtils::get_type_code(ASRUtils::get_contained_type(asr_arg_type), false, false); - llvm::StructType* tmp_struct_type = tkr2array[asr_arg_type_code].first; - if( tmp_struct_type->getElementType(0)->isArrayTy() ) { - first_ele_ptr = llvm_utils->create_gep(get_pointer_to_data(tmp), 0); - } else if( tmp_struct_type->getNumElements() < 5 ) { - first_ele_ptr = LLVM::CreateLoad(*builder, get_pointer_to_data(tmp)); - } else if( tmp_struct_type->getNumElements() == 5 ) { - return tmp; - } - llvm::Value* first_arg_ptr = llvm_utils->create_gep(arg_struct, 0); - builder->CreateStore(first_ele_ptr, first_arg_ptr); - llvm::Value* sec_ele_ptr = get_offset(tmp); - llvm::Value* sec_arg_ptr = llvm_utils->create_gep(arg_struct, 1); - builder->CreateStore(sec_ele_ptr, sec_arg_ptr); - llvm::Value* third_ele_ptr = LLVM::CreateLoad(*builder, - get_pointer_to_dimension_descriptor_array(tmp)); - llvm::Value* third_arg_ptr = llvm_utils->create_gep(arg_struct, 2); - builder->CreateStore(third_ele_ptr, third_arg_ptr); - return arg_struct; - } - - llvm::Type* SimpleCMODescriptor::get_argument_type(llvm::Type* type, - std::uint32_t m_h, std::string arg_name, - std::unordered_map>& arr_arg_type_cache) { - llvm::StructType* type_struct = static_cast(type); - llvm::Type* first_ele_ptr_type = nullptr; - if( type_struct->getElementType(0)->isArrayTy() ) { - llvm::ArrayType* arr_type = static_cast(type_struct->getElementType(0)); - llvm::Type* ele_type = arr_type->getElementType(); - first_ele_ptr_type = ele_type->getPointerTo(); - } else if( type_struct->getElementType(0)->isPointerTy() && - type_struct->getNumElements() < 5 ) { - first_ele_ptr_type = type_struct->getElementType(0); - } else if( type_struct->getElementType(0)->isPointerTy() && - type_struct->getNumElements() == 5 ) { - arr_arg_type_cache[m_h][std::string(arg_name)] = type; - return type->getPointerTo(); - } - llvm::Type* new_arr_type = nullptr; - - if( arr_arg_type_cache.find(m_h) == arr_arg_type_cache.end() || ( - arr_arg_type_cache.find(m_h) != arr_arg_type_cache.end() && - arr_arg_type_cache[m_h].find(std::string(arg_name)) == arr_arg_type_cache[m_h].end() ) ) { - std::vector arg_des = {first_ele_ptr_type}; - for( size_t i = 1; i < type_struct->getNumElements(); i++ ) { - arg_des.push_back(static_cast(type)->getElementType(i)); - } - new_arr_type = llvm::StructType::create(context, arg_des, "array_call"); - arr_arg_type_cache[m_h][std::string(arg_name)] = new_arr_type; - } else { - new_arr_type = arr_arg_type_cache[m_h][std::string(arg_name)]; - } - return new_arr_type->getPointerTo(); - } - - llvm::Type* SimpleCMODescriptor::get_array_type - (ASR::ttype_t* m_type_, llvm::Type* el_type, - bool get_pointer) { - std::string array_key = ASRUtils::get_type_code(m_type_, false, false); - if( tkr2array.find(array_key) != tkr2array.end() ) { - if( get_pointer ) { - return tkr2array[array_key].first->getPointerTo(); - } - return tkr2array[array_key].first; - } - llvm::Type* dim_des_array = create_dimension_descriptor_array_type(); - std::vector array_type_vec; - array_type_vec = { el_type->getPointerTo(), - llvm::Type::getInt32Ty(context), - dim_des_array, - llvm::Type::getInt1Ty(context), - llvm::Type::getInt32Ty(context) }; - llvm::StructType* new_array_type = llvm::StructType::create(context, array_type_vec, "array"); - tkr2array[array_key] = std::make_pair(new_array_type, el_type); - if( get_pointer ) { - return tkr2array[array_key].first->getPointerTo(); - } - return (llvm::Type*) tkr2array[array_key].first; - } - - llvm::Type* SimpleCMODescriptor::create_dimension_descriptor_array_type() { - return dim_des->getPointerTo(); - } - - llvm::Type* SimpleCMODescriptor::get_malloc_array_type - (ASR::ttype_t* m_type_, llvm::Type* el_type, bool get_pointer) { - std::string array_key = ASRUtils::get_type_code(m_type_, false, false); - if( tkr2array.find(array_key) != tkr2array.end() ) { - if( get_pointer ) { - return tkr2array[array_key].first->getPointerTo(); - } - return tkr2array[array_key].first; - } - llvm::Type* dim_des_array = create_dimension_descriptor_array_type(); - std::vector array_type_vec = { - el_type->getPointerTo(), - llvm::Type::getInt32Ty(context), - dim_des_array, - llvm::Type::getInt1Ty(context), - llvm::Type::getInt32Ty(context)}; - llvm::StructType* new_array_type = llvm::StructType::create(context, array_type_vec, "array"); - tkr2array[array_key] = std::make_pair(new_array_type, el_type); - if( get_pointer ) { - return tkr2array[array_key].first->getPointerTo(); - } - return (llvm::Type*) tkr2array[array_key].first; - } - - llvm::Type* SimpleCMODescriptor::get_dimension_descriptor_type - (bool get_pointer) { - if( !get_pointer ) { - return dim_des; - } - return dim_des->getPointerTo(); - } - - llvm::Value* SimpleCMODescriptor:: - get_pointer_to_dimension_descriptor_array(llvm::Value* arr, bool load) { - llvm::Value* dim_des_arr_ptr = llvm_utils->create_gep(arr, 2); - if( !load ) { - return dim_des_arr_ptr; - } - return LLVM::CreateLoad(*builder, dim_des_arr_ptr); - } - - llvm::Value* SimpleCMODescriptor:: - get_rank(llvm::Value* arr, bool get_pointer) { - llvm::Value* rank_ptr = llvm_utils->create_gep(arr, 4); - if( get_pointer ) { - return rank_ptr; - } - return LLVM::CreateLoad(*builder, rank_ptr); - } - - void SimpleCMODescriptor:: - set_rank(llvm::Value* arr, llvm::Value* rank) { - llvm::Value* rank_ptr = llvm_utils->create_gep(arr, 4); - LLVM::CreateStore(*builder, rank, rank_ptr); - } - - llvm::Value* SimpleCMODescriptor:: - get_dimension_size(llvm::Value* dim_des_arr, llvm::Value* dim, bool load) { - llvm::Value* dim_size = llvm_utils->create_gep(llvm_utils->create_ptr_gep(dim_des_arr, dim), 2); - if( !load ) { - return dim_size; - } - return LLVM::CreateLoad(*builder, dim_size); - } - - void SimpleCMODescriptor::fill_array_details( - llvm::Value* arr, llvm::Type* llvm_data_type, int n_dims, - std::vector>& llvm_dims) { - llvm::Value* offset_val = llvm_utils->create_gep(arr, 1); - builder->CreateStore(llvm::ConstantInt::get(context, llvm::APInt(32, 0)), offset_val); - llvm::Value* dim_des_val = llvm_utils->create_gep(arr, 2); - llvm::Value* llvm_ndims = builder->CreateAlloca(llvm::Type::getInt32Ty(context), nullptr); - builder->CreateStore(llvm::ConstantInt::get(context, llvm::APInt(32, n_dims)), llvm_ndims); - llvm::Value* dim_des_first = builder->CreateAlloca(dim_des, - LLVM::CreateLoad(*builder, llvm_ndims)); - builder->CreateStore(llvm::ConstantInt::get(context, llvm::APInt(32, n_dims)), get_rank(arr, true)); - builder->CreateStore(dim_des_first, dim_des_val); - dim_des_val = LLVM::CreateLoad(*builder, dim_des_val); - for( int r = 0; r < n_dims; r++ ) { - llvm::Value* dim_val = llvm_utils->create_ptr_gep(dim_des_val, r); - llvm::Value* s_val = llvm_utils->create_gep(dim_val, 0); - llvm::Value* l_val = llvm_utils->create_gep(dim_val, 1); - llvm::Value* dim_size_ptr = llvm_utils->create_gep(dim_val, 2); - builder->CreateStore(llvm::ConstantInt::get(context, llvm::APInt(32, 1)), s_val); - builder->CreateStore(llvm_dims[r].first, l_val); - llvm::Value* dim_size = llvm_dims[r].second; - builder->CreateStore(dim_size, dim_size_ptr); - } - - llvm::Value* llvm_size = builder->CreateAlloca(llvm::Type::getInt32Ty(context), nullptr); - llvm::Value* const_1 = llvm::ConstantInt::get(context, llvm::APInt(32, 1)); - llvm::Value* prod = const_1; - for( int r = 0; r < n_dims; r++ ) { - llvm::Value* dim_size = llvm_dims[r].second; - prod = builder->CreateMul(prod, dim_size); - } - builder->CreateStore(prod, llvm_size); - llvm::Value* first_ptr = get_pointer_to_data(arr); - llvm::Value* arr_first = builder->CreateAlloca(llvm_data_type, - LLVM::CreateLoad(*builder, llvm_size)); - builder->CreateStore(arr_first, first_ptr); - } - - void SimpleCMODescriptor::fill_malloc_array_details( - llvm::Value* arr, llvm::Type* llvm_data_type, int n_dims, - std::vector>& llvm_dims, - llvm::Module* module) { - llvm::Value* num_elements = llvm::ConstantInt::get(context, llvm::APInt(32, 1)); - llvm::Value* offset_val = llvm_utils->create_gep(arr, 1); - builder->CreateStore(llvm::ConstantInt::get(context, llvm::APInt(32, 0)), - offset_val); - set_is_allocated_flag(arr, 1); - llvm::Value* dim_des_val = LLVM::CreateLoad(*builder, llvm_utils->create_gep(arr, 2)); - for( int r = 0; r < n_dims; r++ ) { - llvm::Value* dim_val = llvm_utils->create_ptr_gep(dim_des_val, r); - llvm::Value* s_val = llvm_utils->create_gep(dim_val, 0); - llvm::Value* l_val = llvm_utils->create_gep(dim_val, 1); - llvm::Value* dim_size_ptr = llvm_utils->create_gep(dim_val, 2); - builder->CreateStore(llvm::ConstantInt::get(context, llvm::APInt(32, 1)), s_val); - builder->CreateStore(llvm_dims[r].first, l_val); - llvm::Value* dim_size = llvm_dims[r].second; - num_elements = builder->CreateMul(num_elements, dim_size); - builder->CreateStore(dim_size, dim_size_ptr); - } - llvm::Value* ptr2firstptr = get_pointer_to_data(arr); - llvm::AllocaInst *arg_size = builder->CreateAlloca(llvm::Type::getInt32Ty(context), nullptr); - llvm::DataLayout data_layout(module); - llvm::Type* ptr_type = llvm_data_type->getPointerTo(); - uint64_t size = data_layout.getTypeAllocSize(llvm_data_type); - llvm::Value* llvm_size = llvm::ConstantInt::get(context, llvm::APInt(32, size)); - num_elements = builder->CreateMul(num_elements, llvm_size); - builder->CreateStore(num_elements, arg_size); - llvm::Value* ptr_as_char_ptr = lfortran_malloc(context, *module, *builder, LLVM::CreateLoad(*builder, arg_size)); - llvm::Value* first_ptr = builder->CreateBitCast(ptr_as_char_ptr, ptr_type); - builder->CreateStore(first_ptr, ptr2firstptr); - } - - void SimpleCMODescriptor::fill_dimension_descriptor( - llvm::Value* arr, int n_dims) { - llvm::Value* dim_des_val = llvm_utils->create_gep(arr, 2); - llvm::Value* llvm_ndims = builder->CreateAlloca(llvm::Type::getInt32Ty(context), nullptr); - builder->CreateStore(llvm::ConstantInt::get(context, llvm::APInt(32, n_dims)), llvm_ndims); - llvm::Value* dim_des_first = builder->CreateAlloca(dim_des, - LLVM::CreateLoad(*builder, llvm_ndims)); - builder->CreateStore(dim_des_first, dim_des_val); - builder->CreateStore(llvm::ConstantInt::get(context, llvm::APInt(32, n_dims)), get_rank(arr, true)); - } - - llvm::Value* SimpleCMODescriptor::get_pointer_to_dimension_descriptor(llvm::Value* dim_des_arr, - llvm::Value* dim) { - return llvm_utils->create_ptr_gep(dim_des_arr, dim); - } - - llvm::Value* SimpleCMODescriptor::get_pointer_to_data(llvm::Value* arr) { - return llvm_utils->create_gep(arr, 0); - } - - llvm::Value* SimpleCMODescriptor::get_offset(llvm::Value* arr) { - return LLVM::CreateLoad(*builder, llvm_utils->create_gep(arr, 1)); - } - - llvm::Value* SimpleCMODescriptor::get_lower_bound(llvm::Value* dim_des, bool load) { - llvm::Value* lb = llvm_utils->create_gep(dim_des, 1); - if( !load ) { - return lb; - } - return LLVM::CreateLoad(*builder, lb); - } - - llvm::Value* SimpleCMODescriptor::get_upper_bound(llvm::Value* dim_des) { - llvm::Value* lb = LLVM::CreateLoad(*builder, llvm_utils->create_gep(dim_des, 1)); - llvm::Value* dim_size = LLVM::CreateLoad(*builder, llvm_utils->create_gep(dim_des, 2)); - return builder->CreateSub(builder->CreateAdd(dim_size, lb), - llvm::ConstantInt::get(context, llvm::APInt(32, 1))); - } - - llvm::Value* SimpleCMODescriptor::get_stride(llvm::Value*) { - return nullptr; - } - - // TODO: Uncomment and implement later - // void check_single_element(llvm::Value* curr_idx, llvm::Value* arr) { - // } - - llvm::Value* SimpleCMODescriptor::cmo_convertor_single_element( - llvm::Value* arr, std::vector& m_args, - int n_args, bool check_for_bounds) { - llvm::Value* dim_des_arr_ptr = LLVM::CreateLoad(*builder, llvm_utils->create_gep(arr, 2)); - llvm::Value* prod = llvm::ConstantInt::get(context, llvm::APInt(32, 1)); - llvm::Value* idx = llvm::ConstantInt::get(context, llvm::APInt(32, 0)); - for( int r = 0; r < n_args; r++ ) { - llvm::Value* curr_llvm_idx = m_args[r]; - llvm::Value* dim_des_ptr = llvm_utils->create_ptr_gep(dim_des_arr_ptr, r); - llvm::Value* lval = LLVM::CreateLoad(*builder, llvm_utils->create_gep(dim_des_ptr, 1)); - curr_llvm_idx = builder->CreateSub(curr_llvm_idx, lval); - if( check_for_bounds ) { - // check_single_element(curr_llvm_idx, arr); TODO: To be implemented - } - idx = builder->CreateAdd(idx, builder->CreateMul(prod, curr_llvm_idx)); - llvm::Value* dim_size = LLVM::CreateLoad(*builder, llvm_utils->create_gep(dim_des_ptr, 2)); - prod = builder->CreateMul(prod, dim_size); - } - return idx; - } - - llvm::Value* SimpleCMODescriptor::cmo_convertor_single_element_data_only( - llvm::Value** llvm_diminfo, std::vector& m_args, - int n_args, bool check_for_bounds) { - llvm::Value* prod = llvm::ConstantInt::get(context, llvm::APInt(32, 1)); - llvm::Value* idx = llvm::ConstantInt::get(context, llvm::APInt(32, 0)); - for( int r = 0, r1 = 0; r < n_args; r++ ) { - llvm::Value* curr_llvm_idx = m_args[r]; - llvm::Value* lval = llvm_diminfo[r1]; - curr_llvm_idx = builder->CreateSub(curr_llvm_idx, lval); - if( check_for_bounds ) { - // check_single_element(curr_llvm_idx, arr); TODO: To be implemented - } - idx = builder->CreateAdd(idx, builder->CreateMul(prod, curr_llvm_idx)); - llvm::Value* dim_size = llvm_diminfo[r1 + 1]; - r1 += 2; - prod = builder->CreateMul(prod, dim_size); - } - return idx; - } - - llvm::Value* SimpleCMODescriptor::get_single_element(llvm::Value* array, - std::vector& m_args, int n_args, bool data_only, - bool is_fixed_size, llvm::Value** llvm_diminfo) { - llvm::Value* tmp = nullptr; - // TODO: Uncomment later - // bool check_for_bounds = is_explicit_shape(v); - bool check_for_bounds = false; - llvm::Value* idx = nullptr; - if( data_only ) { - LCOMPILERS_ASSERT(llvm_diminfo); - idx = cmo_convertor_single_element_data_only(llvm_diminfo, m_args, n_args, check_for_bounds); - if( is_fixed_size ) { - tmp = llvm_utils->create_gep(array, idx); - } else { - tmp = llvm_utils->create_ptr_gep(array, idx); - } - } else { - idx = cmo_convertor_single_element(array, m_args, n_args, check_for_bounds); - llvm::Value* full_array = get_pointer_to_data(array); - tmp = llvm_utils->create_ptr_gep(LLVM::CreateLoad(*builder, full_array), idx); - } - return tmp; - } - - llvm::Value* SimpleCMODescriptor::get_is_allocated_flag(llvm::Value* array) { - return LLVM::CreateLoad(*builder, llvm_utils->create_gep(array, 3)); - } - - void SimpleCMODescriptor::set_is_allocated_flag(llvm::Value* array, uint64_t status) { - llvm::Value* is_allocated_flag = llvm_utils->create_gep(array, 3); - builder->CreateStore(llvm::ConstantInt::get(context, llvm::APInt(1, status)), - is_allocated_flag); - } - - llvm::Value* SimpleCMODescriptor::get_array_size(llvm::Value* array, llvm::Value* dim, int kind, int dim_kind) { - llvm::Value* dim_des_val = this->get_pointer_to_dimension_descriptor_array(array); - llvm::Value* tmp = nullptr; - if( dim ) { - tmp = builder->CreateSub(dim, llvm::ConstantInt::get(context, llvm::APInt(dim_kind * 8, 1))); - tmp = this->get_dimension_size(dim_des_val, tmp); - tmp = builder->CreateSExt(tmp, llvm_utils->getIntType(kind)); - return tmp; - } - llvm::Value* rank = this->get_rank(array); - llvm::Value* llvm_size = builder->CreateAlloca(llvm_utils->getIntType(kind), nullptr); - builder->CreateStore(llvm::ConstantInt::get(context, llvm::APInt(kind * 8, 1)), llvm_size); - - llvm::BasicBlock *loophead = llvm::BasicBlock::Create(context, "loop.head"); - llvm::BasicBlock *loopbody = llvm::BasicBlock::Create(context, "loop.body"); - llvm::BasicBlock *loopend = llvm::BasicBlock::Create(context, "loop.end"); - - llvm::Value* r = builder->CreateAlloca(llvm_utils->getIntType(4), nullptr); - builder->CreateStore(llvm::ConstantInt::get(context, llvm::APInt(32, 0)), r); - // head - llvm_utils->start_new_block(loophead); - llvm::Value *cond = builder->CreateICmpSLT(LLVM::CreateLoad(*builder, r), rank); - builder->CreateCondBr(cond, loopbody, loopend); - - // body - llvm_utils->start_new_block(loopbody); - llvm::Value* r_val = LLVM::CreateLoad(*builder, r); - llvm::Value* ret_val = LLVM::CreateLoad(*builder, llvm_size); - llvm::Value* dim_size = this->get_dimension_size(dim_des_val, r_val); - dim_size = builder->CreateSExt(dim_size, llvm_utils->getIntType(kind)); - ret_val = builder->CreateMul(ret_val, dim_size); - builder->CreateStore(ret_val, llvm_size); - r_val = builder->CreateAdd(r_val, llvm::ConstantInt::get(context, llvm::APInt(32, 1))); - builder->CreateStore(r_val, r); - builder->CreateBr(loophead); - - // end - llvm_utils->start_new_block(loopend); - - tmp = LLVM::CreateLoad(*builder, llvm_size); - return tmp; - } - - llvm::Value* SimpleCMODescriptor::reshape(llvm::Value* array, llvm::Type* llvm_data_type, - llvm::Value* shape, ASR::ttype_t* asr_shape_type, - llvm::Module* module) { - llvm::Value* reshaped = builder->CreateAlloca(array->getType()->getContainedType(0), nullptr, "reshaped"); - - // Deep copy data from array to reshaped. - llvm::Value* num_elements = this->get_array_size(array, nullptr, 4); - - llvm::Value* first_ptr = this->get_pointer_to_data(reshaped); - llvm::Value* arr_first = builder->CreateAlloca(llvm_data_type, num_elements); - builder->CreateStore(arr_first, first_ptr); - - llvm::Value* ptr2firstptr = this->get_pointer_to_data(array); - llvm::DataLayout data_layout(module); - uint64_t size = data_layout.getTypeAllocSize(llvm_data_type); - llvm::Value* llvm_size = llvm::ConstantInt::get(context, llvm::APInt(32, size)); - num_elements = builder->CreateMul(num_elements, llvm_size); - builder->CreateMemCpy(LLVM::CreateLoad(*builder, first_ptr), llvm::MaybeAlign(), - LLVM::CreateLoad(*builder, ptr2firstptr), llvm::MaybeAlign(), - num_elements); - - if( this->is_array(asr_shape_type) ) { - llvm::Value* n_dims = this->get_array_size(shape, nullptr, 4); - llvm::Value* shape_data = LLVM::CreateLoad(*builder, this->get_pointer_to_data(shape)); - llvm::Value* dim_des_val = llvm_utils->create_gep(reshaped, 2); - llvm::Value* dim_des_first = builder->CreateAlloca(dim_des, n_dims); - builder->CreateStore(n_dims, this->get_rank(reshaped, true)); - builder->CreateStore(dim_des_first, dim_des_val); - dim_des_val = LLVM::CreateLoad(*builder, dim_des_val); - llvm::BasicBlock *loophead = llvm::BasicBlock::Create(context, "loop.head"); - llvm::BasicBlock *loopbody = llvm::BasicBlock::Create(context, "loop.body"); - llvm::BasicBlock *loopend = llvm::BasicBlock::Create(context, "loop.end"); - - llvm::Value* r = builder->CreateAlloca(llvm_utils->getIntType(4), nullptr); - builder->CreateStore(llvm::ConstantInt::get(context, llvm::APInt(32, 0)), r); - // head - llvm_utils->start_new_block(loophead); - llvm::Value *cond = builder->CreateICmpSLT(LLVM::CreateLoad(*builder, r), n_dims); - builder->CreateCondBr(cond, loopbody, loopend); - - // body - llvm_utils->start_new_block(loopbody); - llvm::Value* r_val = LLVM::CreateLoad(*builder, r); - llvm::Value* dim_val = llvm_utils->create_ptr_gep(dim_des_val, r_val); - llvm::Value* s_val = llvm_utils->create_gep(dim_val, 0); - llvm::Value* dim_size_ptr = llvm_utils->create_gep(dim_val, 2); - builder->CreateStore(llvm::ConstantInt::get(context, llvm::APInt(32, 1)), s_val); - llvm::Value* dim_size = LLVM::CreateLoad(*builder, llvm_utils->create_ptr_gep(shape_data, r_val)); - builder->CreateStore(dim_size, dim_size_ptr); - r_val = builder->CreateAdd(r_val, llvm::ConstantInt::get(context, llvm::APInt(32, 1))); - builder->CreateStore(r_val, r); - builder->CreateBr(loophead); - - // end - llvm_utils->start_new_block(loopend); - } - return reshaped; - } - - // Shallow copies source array descriptor to destination descriptor - void SimpleCMODescriptor::copy_array(llvm::Value* src, llvm::Value* dest, - llvm::Module* module, ASR::ttype_t* asr_data_type, bool create_dim_des_array, - bool reserve_memory) { - llvm::Value* num_elements = this->get_array_size(src, nullptr, 4); - - llvm::Value* first_ptr = this->get_pointer_to_data(dest); - llvm::Type* llvm_data_type = tkr2array[ASRUtils::get_type_code(asr_data_type, false, false)].second; - if( reserve_memory ) { - llvm::Value* arr_first = builder->CreateAlloca(llvm_data_type, num_elements); - builder->CreateStore(arr_first, first_ptr); - } - - llvm::Value* ptr2firstptr = this->get_pointer_to_data(src); - llvm::DataLayout data_layout(module); - uint64_t size = data_layout.getTypeAllocSize(llvm_data_type); - llvm::Value* llvm_size = llvm::ConstantInt::get(context, llvm::APInt(32, size)); - num_elements = builder->CreateMul(num_elements, llvm_size); - builder->CreateMemCpy(LLVM::CreateLoad(*builder, first_ptr), llvm::MaybeAlign(), - LLVM::CreateLoad(*builder, ptr2firstptr), llvm::MaybeAlign(), - num_elements); - - llvm::Value* src_offset_ptr = LLVM::CreateLoad(*builder, llvm_utils->create_gep(src, 1)); - builder->CreateStore(src_offset_ptr, llvm_utils->create_gep(dest, 1)); - llvm::Value* src_dim_des_val = this->get_pointer_to_dimension_descriptor_array(src, true); - llvm::Value* n_dims = this->get_rank(src, false); - llvm::Value* dest_dim_des_val = nullptr; - if( !create_dim_des_array ) { - dest_dim_des_val = this->get_pointer_to_dimension_descriptor_array(dest, true); - } else { - llvm::Value* dest_dim_des_ptr = this->get_pointer_to_dimension_descriptor_array(dest, false); - dest_dim_des_val = builder->CreateAlloca(dim_des, n_dims); - builder->CreateStore(dest_dim_des_val, dest_dim_des_ptr); - } - llvm::BasicBlock *loophead = llvm::BasicBlock::Create(context, "loop.head"); - llvm::BasicBlock *loopbody = llvm::BasicBlock::Create(context, "loop.body"); - llvm::BasicBlock *loopend = llvm::BasicBlock::Create(context, "loop.end"); - - llvm::Value* r = builder->CreateAlloca(llvm_utils->getIntType(4), nullptr); - builder->CreateStore(llvm::ConstantInt::get(context, llvm::APInt(32, 0)), r); - // head - llvm_utils->start_new_block(loophead); - llvm::Value *cond = builder->CreateICmpSLT(LLVM::CreateLoad(*builder, r), n_dims); - builder->CreateCondBr(cond, loopbody, loopend); - - // body - llvm_utils->start_new_block(loopbody); - llvm::Value* r_val = LLVM::CreateLoad(*builder, r); - llvm::Value* src_dim_val = llvm_utils->create_ptr_gep(src_dim_des_val, r_val); - llvm::Value* src_s_val = llvm_utils->create_gep(src_dim_val, 0); - llvm::Value* src_l_val = nullptr; - if( create_dim_des_array ) { - src_l_val = llvm_utils->create_gep(src_dim_val, 1); - } - llvm::Value* src_dim_size_ptr = llvm_utils->create_gep(src_dim_val, 2); - llvm::Value* dest_dim_val = llvm_utils->create_ptr_gep(dest_dim_des_val, r_val); - llvm::Value* dest_s_val = llvm_utils->create_gep(dest_dim_val, 0); - llvm::Value* dest_l_val = nullptr; - if( create_dim_des_array ) { - dest_l_val = llvm_utils->create_gep(dest_dim_val, 1); - } - llvm::Value* dest_dim_size_ptr = llvm_utils->create_gep(dest_dim_val, 2); - builder->CreateStore(LLVM::CreateLoad(*builder, src_s_val), dest_s_val); - if( create_dim_des_array ) { - builder->CreateStore(LLVM::CreateLoad(*builder, src_l_val), dest_l_val); - } - builder->CreateStore(LLVM::CreateLoad(*builder, src_dim_size_ptr), dest_dim_size_ptr); - r_val = builder->CreateAdd(r_val, llvm::ConstantInt::get(context, llvm::APInt(32, 1))); - builder->CreateStore(r_val, r); - builder->CreateBr(loophead); - - // end - llvm_utils->start_new_block(loopend); - - llvm::Value* src_is_allocated_ptr = this->get_is_allocated_flag(src); - builder->CreateStore(src_is_allocated_ptr, llvm_utils->create_gep(src, 3)); - builder->CreateStore(n_dims, this->get_rank(dest, true)); - } - - void SimpleCMODescriptor::copy_array_data_only(llvm::Value* src, llvm::Value* dest, - llvm::Module* module, ASR::ttype_t* asr_data_type, llvm::Value* num_elements) { - llvm::Type* llvm_data_type = tkr2array[ASRUtils::get_type_code(asr_data_type, false, false)].second; - llvm::DataLayout data_layout(module); - uint64_t size = data_layout.getTypeAllocSize(llvm_data_type); - llvm::Value* llvm_size = llvm::ConstantInt::get(context, llvm::APInt(32, size)); - num_elements = builder->CreateMul(num_elements, llvm_size); - builder->CreateMemCpy(src, llvm::MaybeAlign(), dest, llvm::MaybeAlign(), num_elements); - } - - } // LLVMArrUtils - -} // namespace LCompilers diff --git a/src/libasr/codegen/llvm_array_utils.h b/src/libasr/codegen/llvm_array_utils.h deleted file mode 100644 index f9216824c9..0000000000 --- a/src/libasr/codegen/llvm_array_utils.h +++ /dev/null @@ -1,421 +0,0 @@ -#ifndef LFORTRAN_LLVM_ARR_UTILS_H -#define LFORTRAN_LLVM_ARR_UTILS_H - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -namespace LCompilers { - - namespace LLVMArrUtils { - - llvm::Value* lfortran_malloc(llvm::LLVMContext &context, llvm::Module &module, - llvm::IRBuilder<> &builder, llvm::Value* arg_size); - - /* - * This function checks whether the - * dimensions are available at compile time. - * Returns true if all the dimensions reduce - * to constant integers and false otherwise. - */ - bool compile_time_dimensions_t( - ASR::dimension_t* m_dims, int n_dims); - - /* - * This function checks if the given - * an variable is an array and all the - * dimensions are available at compile time. - */ - bool is_explicit_shape(ASR::Variable_t* v); - - /* - * Available descriptors are listed - * under this enum. - */ - enum DESCR_TYPE - { - _SimpleCMODescriptor - }; - - /* - * Abstract class which defines the interface - * to be followed by any subclass intending - * to implement a specific array descriptor. - */ - class Descriptor { - - public: - - virtual ~Descriptor() {} - - /* - * Factory method which creates - * new descriptors and returns a - * pointer to it. It accepts one of - * the members DESCR_TYPE enum - * to create a new descriptor. - */ - static - std::unique_ptr - get_descriptor( - llvm::LLVMContext& context, - llvm::IRBuilder<>* builder, - LLVMUtils* llvm_utils, - DESCR_TYPE descr_type); - - /* - * Checks whether the given ASR::ttype_t* is an - * array and follows the same structure as - * the current descriptor. - */ - virtual - bool is_array(ASR::ttype_t* asr_type) = 0; - - /* - * Converts a given array llvm::Value* - * into an argument of the specified type. - */ - virtual - llvm::Value* convert_to_argument(llvm::Value* tmp, - ASR::ttype_t* asr_arg_type, llvm::Type* arg_type, - bool data_only=false) = 0; - - /* - * Returns the type of the argument to be - * used in LLVM functions for passing an array - * following the current descriptor structure. - */ - virtual - llvm::Type* get_argument_type(llvm::Type* type, - std::uint32_t, std::string, - std::unordered_map - >& - arr_arg_type_cache) = 0; - - /* - * Creates an array llvm::Type* following - * the same structure as the current descriptor. - * Uses element type, kind, rank and dimensions - * to create the array llvm::Type*. - */ - virtual - llvm::Type* get_array_type( - ASR::ttype_t* m_type_, - llvm::Type* el_type, - bool get_pointer=false) = 0; - - /* - * Same as get_array_type but for allocatable - * arrays. It doesn't require dimensions for - * creating array llvm::Type*. - */ - virtual - llvm::Type* get_malloc_array_type( - ASR::ttype_t* m_type_, - llvm::Type* el_type, - bool get_pointer=false) = 0; - - /* - * Creates an array of dimension descriptors - * whose each element describes structure - * of a dimension's information. - */ - virtual - llvm::Type* create_dimension_descriptor_array_type() = 0; - - /* - * Fills the elements of the input array descriptor - * for arrays on stack memory. - */ - virtual - void fill_array_details( - llvm::Value* arr, llvm::Type* llvm_data_type, int n_dims, - std::vector>& llvm_dims) = 0; - - /* - * Fills the elements of the input array descriptor - * for allocatable arrays. - */ - virtual - void fill_malloc_array_details( - llvm::Value* arr, llvm::Type* llvm_data_type, int n_dims, - std::vector>& llvm_dims, - llvm::Module* module) = 0; - - virtual - void fill_dimension_descriptor( - llvm::Value* arr, int n_dims) = 0; - - /* - * Returns the llvm::Type* associated with the - * dimension descriptor used by the current class. - */ - virtual - llvm::Type* get_dimension_descriptor_type(bool get_pointer=false) = 0; - - /* - * Returns pointer to data in the input - * array descriptor according to the rules - * implemented by current class. - */ - virtual - llvm::Value* get_pointer_to_data(llvm::Value* arr) = 0; - - /* - * Returns offset in the input - * array descriptor according to the rules - * implemented by current class). - */ - virtual - llvm::Value* get_offset(llvm::Value* dim_des) = 0; - - /* - * Returns lower bound in the input - * dimension descriptor according to the rules - * implemented by current class). - */ - virtual - llvm::Value* get_lower_bound(llvm::Value* dim_des, bool load=true) = 0; - - /* - * Returns upper bound in the input - * dimension descriptor according to the rules - * implemented by current class. - */ - virtual - llvm::Value* get_upper_bound(llvm::Value* dim_des) = 0; - - /* - * Returns stride in the input - * dimension descriptor according to the rules - * implemented by current class. - */ - virtual - llvm::Value* get_stride(llvm::Value* dim_des) = 0; - - /* - * Returns dimension size in the input - * dimension descriptor according to the rules - * implemented by current class. - */ - virtual - llvm::Value* get_dimension_size(llvm::Value* dim_des_arr, - llvm::Value* dim, bool load=true) = 0; - - virtual - llvm::Value* get_rank(llvm::Value* arr, bool get_pointer=false) = 0; - - virtual - void set_rank(llvm::Value* arr, llvm::Value* rank) = 0; - - /* - * Returns pointer to dimension descriptor array - * in the input array descriptor according to the rules - * implemented by current class. - */ - virtual - llvm::Value* get_pointer_to_dimension_descriptor_array(llvm::Value* arr, bool load=true) = 0; - - /* - * Returns pointer to the dimension descriptor - * in the input dimension descriptor array according - * to the rules implemented by current class. - */ - virtual - llvm::Value* get_pointer_to_dimension_descriptor(llvm::Value* dim_des_arr, - llvm::Value* dim) = 0; - - /* - * Returns the indexed element - * in the input dimension descriptor array according - * to the rules implemented by current class. - */ - virtual - llvm::Value* get_single_element(llvm::Value* array, - std::vector& m_args, int n_args, - bool data_only=false, bool is_fixed_size=false, - llvm::Value** llvm_diminfo=nullptr) = 0; - - virtual - llvm::Value* get_is_allocated_flag(llvm::Value* array) = 0; - - virtual - void set_is_allocated_flag(llvm::Value* array, uint64_t status) = 0; - - virtual - llvm::Value* reshape(llvm::Value* array, llvm::Type* llvm_data_type, - llvm::Value* shape, ASR::ttype_t* asr_shape_type, - llvm::Module* module) = 0; - - virtual - void copy_array(llvm::Value* src, llvm::Value* dest, - llvm::Module* module, ASR::ttype_t* asr_data_type, - bool create_dim_des_array, bool reserve_memory) = 0; - - virtual - void copy_array_data_only(llvm::Value* src, llvm::Value* dest, - llvm::Module* module, ASR::ttype_t* asr_data_type, - llvm::Value* num_elements) = 0; - - virtual - llvm::Value* get_array_size(llvm::Value* array, llvm::Value* dim, - int output_kind, int dim_kind=4) = 0; - - }; - - class SimpleCMODescriptor: public Descriptor { - - private: - - llvm::LLVMContext& context; - LLVMUtils* llvm_utils; - llvm::IRBuilder<>* builder; - - llvm::StructType* dim_des; - - std::map> tkr2array; - - llvm::Value* cmo_convertor_single_element( - llvm::Value* arr, std::vector& m_args, - int n_args, bool check_for_bounds); - - llvm::Value* cmo_convertor_single_element_data_only( - llvm::Value** llvm_diminfo, std::vector& m_args, - int n_args, bool check_for_bounds); - - public: - - SimpleCMODescriptor(llvm::LLVMContext& _context, - llvm::IRBuilder<>* _builder, - LLVMUtils* _llvm_utils); - - virtual - bool is_array(ASR::ttype_t* asr_type); - - virtual - llvm::Value* convert_to_argument(llvm::Value* tmp, - ASR::ttype_t* asr_arg_type, llvm::Type* arg_type, - bool data_only=false); - - virtual - llvm::Type* get_argument_type(llvm::Type* type, - std::uint32_t m_h, std::string arg_name, - std::unordered_map - >& - arr_arg_type_cache); - - virtual - llvm::Type* get_array_type( - ASR::ttype_t* m_type_, - llvm::Type* el_type, - bool get_pointer=false); - - virtual - llvm::Type* get_malloc_array_type( - ASR::ttype_t* m_type_, - llvm::Type* el_type, - bool get_pointer=false); - - virtual - llvm::Type* create_dimension_descriptor_array_type(); - - virtual - void fill_array_details( - llvm::Value* arr, llvm::Type* llvm_data_type, int n_dims, - std::vector>& llvm_dims); - - virtual - void fill_malloc_array_details( - llvm::Value* arr, llvm::Type* llvm_data_type, int n_dims, - std::vector>& llvm_dims, - llvm::Module* module); - - virtual - void fill_dimension_descriptor( - llvm::Value* arr, int n_dims); - - virtual - llvm::Type* get_dimension_descriptor_type(bool get_pointer=false); - - virtual - llvm::Value* get_pointer_to_data(llvm::Value* arr); - - virtual - llvm::Value* get_rank(llvm::Value* arr, bool get_pointer=false); - - virtual - void set_rank(llvm::Value* arr, llvm::Value* rank); - - virtual - llvm::Value* get_offset(llvm::Value* dim_des); - - virtual - llvm::Value* get_lower_bound(llvm::Value* dim_des, bool load=true); - - virtual - llvm::Value* get_upper_bound(llvm::Value* dim_des); - - virtual - llvm::Value* get_dimension_size(llvm::Value* dim_des_arr, - llvm::Value* dim, bool load=true); - - virtual - llvm::Value* get_pointer_to_dimension_descriptor_array(llvm::Value* arr, bool load=true); - - virtual - llvm::Value* get_pointer_to_dimension_descriptor(llvm::Value* dim_des_arr, - llvm::Value* dim); - - virtual - llvm::Value* get_stride(llvm::Value* dim_des); - - virtual - llvm::Value* get_single_element(llvm::Value* array, - std::vector& m_args, int n_args, - bool data_only=false, bool is_fixed_size=false, - llvm::Value** llvm_diminfo=nullptr); - - virtual - llvm::Value* get_is_allocated_flag(llvm::Value* array); - - virtual - void set_is_allocated_flag(llvm::Value* array, uint64_t status); - - virtual - llvm::Value* reshape(llvm::Value* array, llvm::Type* llvm_data_type, - llvm::Value* shape, ASR::ttype_t* asr_shape_type, - llvm::Module* module); - - virtual - void copy_array(llvm::Value* src, llvm::Value* dest, - llvm::Module* module, ASR::ttype_t* asr_data_type, - bool create_dim_des_array, bool reserve_memory); - - virtual - void copy_array_data_only(llvm::Value* src, llvm::Value* dest, - llvm::Module* module, ASR::ttype_t* asr_data_type, - llvm::Value* num_elements); - - virtual - llvm::Value* get_array_size(llvm::Value* array, llvm::Value* dim, - int output_kind, int dim_kind=4); - - }; - - } // LLVMArrUtils - -} // namespace LCompilers - -#endif // LFORTRAN_LLVM_ARR_UTILS_H diff --git a/src/libasr/codegen/llvm_utils.cpp b/src/libasr/codegen/llvm_utils.cpp deleted file mode 100644 index bc790d5974..0000000000 --- a/src/libasr/codegen/llvm_utils.cpp +++ /dev/null @@ -1,2700 +0,0 @@ -#include -#include -#include -#include - -namespace LCompilers { - - namespace LLVM { - - llvm::Value* CreateLoad(llvm::IRBuilder<> &builder, llvm::Value *x) { - llvm::Type *t = x->getType(); - LCOMPILERS_ASSERT(t->isPointerTy()); - llvm::Type *t2 = t->getContainedType(0); - return builder.CreateLoad(t2, x); - } - - llvm::Value* CreateStore(llvm::IRBuilder<> &builder, llvm::Value *x, llvm::Value *y) { - LCOMPILERS_ASSERT(y->getType()->isPointerTy()); - return builder.CreateStore(x, y); - } - - - llvm::Value* CreateGEP(llvm::IRBuilder<> &builder, llvm::Value *x, std::vector &idx) { - llvm::Type *t = x->getType(); - LCOMPILERS_ASSERT(t->isPointerTy()); - llvm::Type *t2 = t->getContainedType(0); - return builder.CreateGEP(t2, x, idx); - } - - llvm::Value* CreateInBoundsGEP(llvm::IRBuilder<> &builder, llvm::Value *x, std::vector &idx) { - llvm::Type *t = x->getType(); - LCOMPILERS_ASSERT(t->isPointerTy()); - llvm::Type *t2 = t->getContainedType(0); - return builder.CreateInBoundsGEP(t2, x, idx); - } - - llvm::Value* lfortran_malloc(llvm::LLVMContext &context, llvm::Module &module, - llvm::IRBuilder<> &builder, llvm::Value* arg_size) { - std::string func_name = "_lfortran_malloc"; - llvm::Function *fn = module.getFunction(func_name); - if (!fn) { - llvm::FunctionType *function_type = llvm::FunctionType::get( - llvm::Type::getInt8PtrTy(context), { - llvm::Type::getInt32Ty(context) - }, true); - fn = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, func_name, module); - } - std::vector args = {arg_size}; - return builder.CreateCall(fn, args); - } - - llvm::Value* lfortran_calloc(llvm::LLVMContext &context, llvm::Module &module, - llvm::IRBuilder<> &builder, llvm::Value* count, llvm::Value* type_size) { - std::string func_name = "_lfortran_calloc"; - llvm::Function *fn = module.getFunction(func_name); - if (!fn) { - llvm::FunctionType *function_type = llvm::FunctionType::get( - llvm::Type::getInt8PtrTy(context), { - llvm::Type::getInt32Ty(context), - llvm::Type::getInt32Ty(context) - }, true); - fn = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, func_name, module); - } - std::vector args = {count, type_size}; - return builder.CreateCall(fn, args); - } - - llvm::Value* lfortran_realloc(llvm::LLVMContext &context, llvm::Module &module, - llvm::IRBuilder<> &builder, llvm::Value* ptr, llvm::Value* arg_size) { - std::string func_name = "_lfortran_realloc"; - llvm::Function *fn = module.getFunction(func_name); - if (!fn) { - llvm::FunctionType *function_type = llvm::FunctionType::get( - llvm::Type::getInt8PtrTy(context), { - llvm::Type::getInt8PtrTy(context), - llvm::Type::getInt32Ty(context) - }, true); - fn = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, func_name, module); - } - std::vector args = { - builder.CreateBitCast(ptr, llvm::Type::getInt8PtrTy(context)), - arg_size - }; - return builder.CreateCall(fn, args); - } - - llvm::Value* lfortran_free(llvm::LLVMContext &context, llvm::Module &module, - llvm::IRBuilder<> &builder, llvm::Value* ptr) { - std::string func_name = "_lfortran_free"; - llvm::Function *fn = module.getFunction(func_name); - if (!fn) { - llvm::FunctionType *function_type = llvm::FunctionType::get( - llvm::Type::getVoidTy(context), { - llvm::Type::getInt8PtrTy(context) - }, true); - fn = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, func_name, module); - } - std::vector args = { - builder.CreateBitCast(ptr, llvm::Type::getInt8PtrTy(context)), - }; - return builder.CreateCall(fn, args); - } - } // namespace LLVM - - LLVMUtils::LLVMUtils(llvm::LLVMContext& context, - llvm::IRBuilder<>* _builder): - context(context), - builder(std::move(_builder)), - str_cmp_itr(nullptr), - are_iterators_set(false) { - } - - llvm::Value* LLVMUtils::create_gep(llvm::Value* ds, int idx) { - std::vector idx_vec = { - llvm::ConstantInt::get(context, llvm::APInt(32, 0)), - llvm::ConstantInt::get(context, llvm::APInt(32, idx))}; - return LLVM::CreateGEP(*builder, ds, idx_vec); - } - - llvm::Value* LLVMUtils::create_gep(llvm::Value* ds, llvm::Value* idx) { - std::vector idx_vec = { - llvm::ConstantInt::get(context, llvm::APInt(32, 0)), - idx}; - return LLVM::CreateGEP(*builder, ds, idx_vec); - } - - llvm::Value* LLVMUtils::create_ptr_gep(llvm::Value* ptr, int idx) { - std::vector idx_vec = { - llvm::ConstantInt::get(context, llvm::APInt(32, idx))}; - return LLVM::CreateInBoundsGEP(*builder, ptr, idx_vec); - } - - llvm::Value* LLVMUtils::create_ptr_gep(llvm::Value* ptr, llvm::Value* idx) { - std::vector idx_vec = {idx}; - return LLVM::CreateInBoundsGEP(*builder, ptr, idx_vec); - } - - llvm::Type* LLVMUtils::getIntType(int a_kind, bool get_pointer) { - llvm::Type* type_ptr = nullptr; - if( get_pointer ) { - switch(a_kind) - { - case 1: - type_ptr = llvm::Type::getInt8PtrTy(context); - break; - case 2: - type_ptr = llvm::Type::getInt16PtrTy(context); - break; - case 4: - type_ptr = llvm::Type::getInt32PtrTy(context); - break; - case 8: - type_ptr = llvm::Type::getInt64PtrTy(context); - break; - default: - LCOMPILERS_ASSERT(false); - } - } else { - switch(a_kind) - { - case 1: - type_ptr = llvm::Type::getInt8Ty(context); - break; - case 2: - type_ptr = llvm::Type::getInt16Ty(context); - break; - case 4: - type_ptr = llvm::Type::getInt32Ty(context); - break; - case 8: - type_ptr = llvm::Type::getInt64Ty(context); - break; - default: - LCOMPILERS_ASSERT(false); - } - } - return type_ptr; - } - - void LLVMUtils::start_new_block(llvm::BasicBlock *bb) { - llvm::BasicBlock *last_bb = builder->GetInsertBlock(); - llvm::Function *fn = last_bb->getParent(); - llvm::Instruction *block_terminator = last_bb->getTerminator(); - if (block_terminator == nullptr) { - // The previous block is not terminated --- terminate it by jumping - // to our new block - builder->CreateBr(bb); - } - fn->getBasicBlockList().push_back(bb); - builder->SetInsertPoint(bb); - } - - void LLVMUtils::set_iterators() { - if( are_iterators_set ) { - return ; - } - str_cmp_itr = builder->CreateAlloca(llvm::Type::getInt32Ty(context), nullptr, "str_cmp_itr"); - LLVM::CreateStore(*builder, llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), - llvm::APInt(32, 0)), str_cmp_itr); - are_iterators_set = true; - } - - void LLVMUtils::reset_iterators() { - str_cmp_itr = nullptr; - are_iterators_set = false; - } - - llvm::Value* LLVMUtils::lfortran_str_cmp(llvm::Value* left_arg, llvm::Value* right_arg, - std::string runtime_func_name, llvm::Module& module) - { - llvm::Type* character_type = llvm::Type::getInt8PtrTy(context); - llvm::Function *fn = module.getFunction(runtime_func_name); - if(!fn) { - llvm::FunctionType *function_type = llvm::FunctionType::get( - llvm::Type::getInt1Ty(context), { - character_type->getPointerTo(), - character_type->getPointerTo() - }, false); - fn = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, runtime_func_name, module); - } - llvm::AllocaInst *pleft_arg = builder->CreateAlloca(character_type, nullptr); - LLVM::CreateStore(*builder, left_arg, pleft_arg); - llvm::AllocaInst *pright_arg = builder->CreateAlloca(character_type, nullptr); - LLVM::CreateStore(*builder, right_arg, pright_arg); - std::vector args = {pleft_arg, pright_arg}; - return builder->CreateCall(fn, args); - } - - llvm::Value* LLVMUtils::is_equal_by_value(llvm::Value* left, llvm::Value* right, - llvm::Module& module, ASR::ttype_t* asr_type) { - switch( asr_type->type ) { - case ASR::ttypeType::Integer: { - return builder->CreateICmpEQ(left, right); - } - case ASR::ttypeType::Logical: { - return builder->CreateICmpEQ(left, right); - } - case ASR::ttypeType::Real: { - return builder->CreateFCmpOEQ(left, right); - } - case ASR::ttypeType::Character: { - if( !are_iterators_set ) { - str_cmp_itr = builder->CreateAlloca(llvm::Type::getInt32Ty(context), nullptr); - } - llvm::Value* null_char = llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), - llvm::APInt(8, '\0')); - llvm::Value* idx = str_cmp_itr; - LLVM::CreateStore(*builder, - llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), llvm::APInt(32, 0)), - idx); - llvm::BasicBlock *loophead = llvm::BasicBlock::Create(context, "loop.head"); - llvm::BasicBlock *loopbody = llvm::BasicBlock::Create(context, "loop.body"); - llvm::BasicBlock *loopend = llvm::BasicBlock::Create(context, "loop.end"); - - // head - start_new_block(loophead); - { - llvm::Value* i = LLVM::CreateLoad(*builder, idx); - llvm::Value* l = LLVM::CreateLoad(*builder, create_ptr_gep(left, i)); - llvm::Value* r = LLVM::CreateLoad(*builder, create_ptr_gep(right, i)); - llvm::Value *cond = builder->CreateAnd( - builder->CreateICmpNE(l, null_char), - builder->CreateICmpNE(r, null_char) - ); - cond = builder->CreateAnd(cond, builder->CreateICmpEQ(l, r)); - builder->CreateCondBr(cond, loopbody, loopend); - } - - // body - start_new_block(loopbody); - { - llvm::Value* i = LLVM::CreateLoad(*builder, idx); - i = builder->CreateAdd(i, llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), - llvm::APInt(32, 1))); - LLVM::CreateStore(*builder, i, idx); - } - - builder->CreateBr(loophead); - - // end - start_new_block(loopend); - llvm::Value* i = LLVM::CreateLoad(*builder, idx); - llvm::Value* l = LLVM::CreateLoad(*builder, create_ptr_gep(left, i)); - llvm::Value* r = LLVM::CreateLoad(*builder, create_ptr_gep(right, i)); - return builder->CreateICmpEQ(l, r); - } - case ASR::ttypeType::Tuple: { - ASR::Tuple_t* tuple_type = ASR::down_cast(asr_type); - return tuple_api->check_tuple_equality(left, right, tuple_type, context, - builder, module); - } - case ASR::ttypeType::List: { - ASR::List_t* list_type = ASR::down_cast(asr_type); - return list_api->check_list_equality(left, right, list_type->m_type, - context, builder, module); - } - default: { - throw LCompilersException("LLVMUtils::is_equal_by_value isn't implemented for " + - ASRUtils::type_to_str_python(asr_type)); - } - } - } - - void LLVMUtils::deepcopy(llvm::Value* src, llvm::Value* dest, - ASR::ttype_t* asr_type, llvm::Module* module, - std::map>& name2memidx) { - switch( asr_type->type ) { - case ASR::ttypeType::Integer: - case ASR::ttypeType::Real: - case ASR::ttypeType::Logical: - case ASR::ttypeType::Complex: { - if( ASRUtils::is_array(asr_type) ) { - arr_api->copy_array(src, dest, module, asr_type, false, false); - } else { - LLVM::CreateStore(*builder, src, dest); - } - break ; - }; - case ASR::ttypeType::Character: - case ASR::ttypeType::CPtr: { - LLVM::CreateStore(*builder, src, dest); - break ; - } - case ASR::ttypeType::Tuple: { - ASR::Tuple_t* tuple_type = ASR::down_cast(asr_type); - tuple_api->tuple_deepcopy(src, dest, tuple_type, module, name2memidx); - break ; - } - case ASR::ttypeType::List: { - ASR::List_t* list_type = ASR::down_cast(asr_type); - list_api->list_deepcopy(src, dest, list_type, module, name2memidx); - break ; - } - case ASR::ttypeType::Struct: { - ASR::Struct_t* struct_t = ASR::down_cast(asr_type); - ASR::StructType_t* struct_type_t = ASR::down_cast( - ASRUtils::symbol_get_past_external(struct_t->m_derived_type)); - std::string der_type_name = std::string(struct_type_t->m_name); - for( auto item: struct_type_t->m_symtab->get_scope() ) { - std::string mem_name = item.first; - int mem_idx = name2memidx[der_type_name][mem_name]; - llvm::Value* src_member = create_gep(src, mem_idx); - if( !LLVM::is_llvm_struct(ASRUtils::symbol_type(item.second)) && - !ASRUtils::is_array(ASRUtils::symbol_type(item.second)) ) { - src_member = LLVM::CreateLoad(*builder, src_member); - } - llvm::Value* dest_member = create_gep(dest, mem_idx); - deepcopy(src_member, dest_member, - ASRUtils::symbol_type(item.second), - module, name2memidx); - } - break ; - } - default: { - throw LCompilersException("LLVMUtils::deepcopy isn't implemented for " + - ASRUtils::type_to_str_python(asr_type)); - } - } - } - - LLVMList::LLVMList(llvm::LLVMContext& context_, - LLVMUtils* llvm_utils_, - llvm::IRBuilder<>* builder_): - context(context_), - llvm_utils(std::move(llvm_utils_)), - builder(std::move(builder_)) {} - - LLVMDictInterface::LLVMDictInterface(llvm::LLVMContext& context_, - LLVMUtils* llvm_utils_, - llvm::IRBuilder<>* builder_): - context(context_), - llvm_utils(std::move(llvm_utils_)), - builder(std::move(builder_)), - pos_ptr(nullptr), is_key_matching_var(nullptr), - idx_ptr(nullptr), hash_iter(nullptr), - hash_value(nullptr), polynomial_powers(nullptr), - chain_itr(nullptr), chain_itr_prev(nullptr), - old_capacity(nullptr), old_key_value_pairs(nullptr), - old_key_mask(nullptr), are_iterators_set(false), - is_dict_present_(false) { - } - - LLVMDict::LLVMDict(llvm::LLVMContext& context_, - LLVMUtils* llvm_utils_, - llvm::IRBuilder<>* builder_): - LLVMDictInterface(context_, llvm_utils_, builder_) { - } - - LLVMDictSeparateChaining::LLVMDictSeparateChaining( - llvm::LLVMContext& context_, - LLVMUtils* llvm_utils_, - llvm::IRBuilder<>* builder_): - LLVMDictInterface(context_, llvm_utils_, builder_) { - } - - LLVMDictOptimizedLinearProbing::LLVMDictOptimizedLinearProbing( - llvm::LLVMContext& context_, - LLVMUtils* llvm_utils_, - llvm::IRBuilder<>* builder_): - LLVMDict(context_, llvm_utils_, builder_) { - } - - llvm::Type* LLVMList::get_list_type(llvm::Type* el_type, std::string& type_code, - int32_t type_size) { - if( typecode2listtype.find(type_code) != typecode2listtype.end() ) { - return std::get<0>(typecode2listtype[type_code]); - } - std::vector list_type_vec = {llvm::Type::getInt32Ty(context), - llvm::Type::getInt32Ty(context), - el_type->getPointerTo()}; - llvm::StructType* list_desc = llvm::StructType::create(context, list_type_vec, "list"); - typecode2listtype[type_code] = std::make_tuple(list_desc, type_size, el_type); - return list_desc; - } - - llvm::Type* LLVMDict::get_dict_type(std::string key_type_code, std::string value_type_code, - int32_t key_type_size, int32_t value_type_size, - llvm::Type* key_type, llvm::Type* value_type) { - is_dict_present_ = true; - std::pair llvm_key = std::make_pair(key_type_code, value_type_code); - if( typecode2dicttype.find(llvm_key) != typecode2dicttype.end() ) { - return std::get<0>(typecode2dicttype[llvm_key]); - } - - llvm::Type* key_list_type = llvm_utils->list_api->get_list_type(key_type, - key_type_code, key_type_size); - llvm::Type* value_list_type = llvm_utils->list_api->get_list_type(value_type, - value_type_code, value_type_size); - std::vector dict_type_vec = {llvm::Type::getInt32Ty(context), - key_list_type, value_list_type, - llvm::Type::getInt8PtrTy(context)}; - llvm::Type* dict_desc = llvm::StructType::create(context, dict_type_vec, "dict"); - typecode2dicttype[llvm_key] = std::make_tuple(dict_desc, - std::make_pair(key_type_size, value_type_size), - std::make_pair(key_type, value_type)); - return dict_desc; - } - - llvm::Type* LLVMDictSeparateChaining::get_key_value_pair_type( - std::string key_type_code, std::string value_type_code) { - std::pair llvm_key = std::make_pair(key_type_code, value_type_code); - return typecode2kvstruct[llvm_key]; - } - - llvm::Type* LLVMDictSeparateChaining::get_key_value_pair_type( - ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type) { - std::string key_type_code = ASRUtils::get_type_code(key_asr_type); - std::string value_type_code = ASRUtils::get_type_code(value_asr_type); - return get_key_value_pair_type(key_type_code, value_type_code); - } - - llvm::Type* LLVMDictSeparateChaining::get_dict_type( - std::string key_type_code, std::string value_type_code, - int32_t key_type_size, int32_t value_type_size, - llvm::Type* key_type, llvm::Type* value_type) { - is_dict_present_ = true; - std::pair llvm_key = std::make_pair(key_type_code, value_type_code); - if( typecode2dicttype.find(llvm_key) != typecode2dicttype.end() ) { - return std::get<0>(typecode2dicttype[llvm_key]); - } - - std::vector key_value_vec = {key_type, value_type, - llvm::Type::getInt8PtrTy(context)}; - llvm::Type* key_value_pair = llvm::StructType::create(context, key_value_vec, "key_value"); - std::vector dict_type_vec = {llvm::Type::getInt32Ty(context), - llvm::Type::getInt32Ty(context), - llvm::Type::getInt32Ty(context), - key_value_pair->getPointerTo(), - llvm::Type::getInt8PtrTy(context), - llvm::Type::getInt1Ty(context)}; - llvm::Type* dict_desc = llvm::StructType::create(context, dict_type_vec, "dict"); - typecode2dicttype[llvm_key] = std::make_tuple(dict_desc, - std::make_pair(key_type_size, value_type_size), - std::make_pair(key_type, value_type)); - typecode2kvstruct[llvm_key] = key_value_pair; - return dict_desc; - } - - llvm::Value* LLVMList::get_pointer_to_list_data(llvm::Value* list) { - return llvm_utils->create_gep(list, 2); - } - - llvm::Value* LLVMList::get_pointer_to_current_end_point(llvm::Value* list) { - return llvm_utils->create_gep(list, 0); - } - - llvm::Value* LLVMList::get_pointer_to_current_capacity(llvm::Value* list) { - return llvm_utils->create_gep(list, 1); - } - - void LLVMList::list_init(std::string& type_code, llvm::Value* list, - llvm::Module& module, int32_t initial_capacity, int32_t n) { - if( typecode2listtype.find(type_code) == typecode2listtype.end() ) { - throw LCompilersException("list for " + type_code + " not declared yet."); - } - int32_t type_size = std::get<1>(typecode2listtype[type_code]); - llvm::Value* arg_size = llvm::ConstantInt::get(context, - llvm::APInt(32, type_size * initial_capacity)); - - llvm::Value* list_data = LLVM::lfortran_malloc(context, module, *builder, - arg_size); - llvm::Type* el_type = std::get<2>(typecode2listtype[type_code]); - list_data = builder->CreateBitCast(list_data, el_type->getPointerTo()); - llvm::Value* list_data_ptr = get_pointer_to_list_data(list); - builder->CreateStore(list_data, list_data_ptr); - llvm::Value* current_end_point = llvm::ConstantInt::get(context, llvm::APInt(32, n)); - llvm::Value* current_capacity = llvm::ConstantInt::get(context, llvm::APInt(32, initial_capacity)); - builder->CreateStore(current_end_point, get_pointer_to_current_end_point(list)); - builder->CreateStore(current_capacity, get_pointer_to_current_capacity(list)); - } - - void LLVMList::list_init(std::string& type_code, llvm::Value* list, - llvm::Module& module, llvm::Value* initial_capacity, - llvm::Value* n) { - if( typecode2listtype.find(type_code) == typecode2listtype.end() ) { - throw LCompilersException("list for " + type_code + " not declared yet."); - } - int32_t type_size = std::get<1>(typecode2listtype[type_code]); - llvm::Value* llvm_type_size = llvm::ConstantInt::get(context, llvm::APInt(32, type_size)); - llvm::Value* arg_size = builder->CreateMul(llvm_type_size, initial_capacity); - llvm::Value* list_data = LLVM::lfortran_malloc(context, module, *builder, arg_size); - - llvm::Type* el_type = std::get<2>(typecode2listtype[type_code]); - list_data = builder->CreateBitCast(list_data, el_type->getPointerTo()); - llvm::Value* list_data_ptr = get_pointer_to_list_data(list); - builder->CreateStore(list_data, list_data_ptr); - builder->CreateStore(n, get_pointer_to_current_end_point(list)); - builder->CreateStore(initial_capacity, get_pointer_to_current_capacity(list)); - } - - llvm::Value* LLVMDict::get_key_list(llvm::Value* dict) { - return llvm_utils->create_gep(dict, 1); - } - - llvm::Value* LLVMDictSeparateChaining::get_pointer_to_key_value_pairs(llvm::Value* dict) { - return llvm_utils->create_gep(dict, 3); - } - - llvm::Value* LLVMDictSeparateChaining::get_key_list(llvm::Value* /*dict*/) { - return nullptr; - } - - llvm::Value* LLVMDict::get_value_list(llvm::Value* dict) { - return llvm_utils->create_gep(dict, 2); - } - - llvm::Value* LLVMDictSeparateChaining::get_value_list(llvm::Value* /*dict*/) { - return nullptr; - } - - llvm::Value* LLVMDict::get_pointer_to_occupancy(llvm::Value* dict) { - return llvm_utils->create_gep(dict, 0); - } - - llvm::Value* LLVMDictSeparateChaining::get_pointer_to_occupancy(llvm::Value* dict) { - return llvm_utils->create_gep(dict, 0); - } - - llvm::Value* LLVMDictSeparateChaining::get_pointer_to_rehash_flag(llvm::Value* dict) { - return llvm_utils->create_gep(dict, 5); - } - - llvm::Value* LLVMDictSeparateChaining::get_pointer_to_number_of_filled_buckets(llvm::Value* dict) { - return llvm_utils->create_gep(dict, 1); - } - - llvm::Value* LLVMDict::get_pointer_to_capacity(llvm::Value* dict) { - return llvm_utils->list_api->get_pointer_to_current_capacity( - get_value_list(dict)); - } - - llvm::Value* LLVMDictSeparateChaining::get_pointer_to_capacity(llvm::Value* dict) { - return llvm_utils->create_gep(dict, 2); - } - - void LLVMDict::dict_init(std::string key_type_code, std::string value_type_code, - llvm::Value* dict, llvm::Module* module, size_t initial_capacity) { - llvm::Value* n_ptr = get_pointer_to_occupancy(dict); - LLVM::CreateStore(*builder, llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), - llvm::APInt(32, 0)), n_ptr); - llvm::Value* key_list = get_key_list(dict); - llvm::Value* value_list = get_value_list(dict); - llvm_utils->list_api->list_init(key_type_code, key_list, *module, - initial_capacity, initial_capacity); - llvm_utils->list_api->list_init(value_type_code, value_list, *module, - initial_capacity, initial_capacity); - llvm::DataLayout data_layout(module); - size_t mask_size = data_layout.getTypeAllocSize(llvm::Type::getInt8Ty(context)); - llvm::Value* llvm_capacity = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), - llvm::APInt(32, initial_capacity)); - llvm::Value* llvm_mask_size = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), - llvm::APInt(32, mask_size)); - llvm::Value* key_mask = LLVM::lfortran_calloc(context, *module, *builder, llvm_capacity, - llvm_mask_size); - LLVM::CreateStore(*builder, key_mask, get_pointer_to_keymask(dict)); - } - - void LLVMDictSeparateChaining::dict_init(std::string key_type_code, std::string value_type_code, - llvm::Value* dict, llvm::Module* module, size_t initial_capacity) { - llvm::Value* llvm_capacity = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), llvm::APInt(32, initial_capacity + 1)); - llvm::Value* rehash_flag_ptr = get_pointer_to_rehash_flag(dict); - LLVM::CreateStore(*builder, llvm::ConstantInt::get(llvm::Type::getInt1Ty(context), llvm::APInt(1, 1)), rehash_flag_ptr); - dict_init_given_initial_capacity(key_type_code, value_type_code, dict, module, llvm_capacity); - } - - void LLVMDictSeparateChaining::dict_init_given_initial_capacity( - std::string key_type_code, std::string value_type_code, - llvm::Value* dict, llvm::Module* module, llvm::Value* llvm_capacity) { - llvm::Value* rehash_flag_ptr = get_pointer_to_rehash_flag(dict); - llvm::Value* rehash_flag = LLVM::CreateLoad(*builder, rehash_flag_ptr); - llvm::Value* llvm_zero = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), llvm::APInt(32, 0)); - llvm::Value* occupancy_ptr = get_pointer_to_occupancy(dict); - LLVM::CreateStore(*builder, llvm_zero, occupancy_ptr); - llvm::Value* num_buckets_filled_ptr = get_pointer_to_number_of_filled_buckets(dict); - LLVM::CreateStore(*builder, llvm_zero, num_buckets_filled_ptr); - - llvm::DataLayout data_layout(module); - llvm::Type* key_value_pair_type = get_key_value_pair_type(key_type_code, value_type_code); - size_t key_value_type_size = data_layout.getTypeAllocSize(key_value_pair_type); - llvm::Value* llvm_key_value_size = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), llvm::APInt(32, key_value_type_size)); - llvm::Value* malloc_size = builder->CreateMul(llvm_capacity, llvm_key_value_size); - llvm::Value* key_value_ptr = LLVM::lfortran_malloc(context, *module, *builder, malloc_size); - rehash_flag = builder->CreateAnd(rehash_flag, - builder->CreateICmpNE(key_value_ptr, - llvm::ConstantPointerNull::get(llvm::Type::getInt8PtrTy(context))) - ); - key_value_ptr = builder->CreateBitCast(key_value_ptr, key_value_pair_type->getPointerTo()); - LLVM::CreateStore(*builder, key_value_ptr, get_pointer_to_key_value_pairs(dict)); - - size_t mask_size = data_layout.getTypeAllocSize(llvm::Type::getInt8Ty(context)); - llvm::Value* llvm_mask_size = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), - llvm::APInt(32, mask_size)); - llvm::Value* key_mask = LLVM::lfortran_calloc(context, *module, *builder, llvm_capacity, - llvm_mask_size); - rehash_flag = builder->CreateAnd(rehash_flag, - builder->CreateICmpNE(key_mask, - llvm::ConstantPointerNull::get(llvm::Type::getInt8PtrTy(context))) - ); - LLVM::CreateStore(*builder, key_mask, get_pointer_to_keymask(dict)); - - llvm::Value* capacity_ptr = get_pointer_to_capacity(dict); - LLVM::CreateStore(*builder, llvm_capacity, capacity_ptr); - LLVM::CreateStore(*builder, rehash_flag, rehash_flag_ptr); - } - - void LLVMList::list_deepcopy(llvm::Value* src, llvm::Value* dest, - ASR::List_t* list_type, llvm::Module* module, - std::map>& name2memidx) { - list_deepcopy(src, dest, list_type->m_type, module, name2memidx); - } - - void LLVMList::list_deepcopy(llvm::Value* src, llvm::Value* dest, - ASR::ttype_t* element_type, llvm::Module* module, - std::map>& name2memidx) { - LCOMPILERS_ASSERT(src->getType() == dest->getType()); - std::string src_type_code = ASRUtils::get_type_code(element_type); - llvm::Value* src_end_point = LLVM::CreateLoad(*builder, get_pointer_to_current_end_point(src)); - llvm::Value* src_capacity = LLVM::CreateLoad(*builder, get_pointer_to_current_capacity(src)); - llvm::Value* dest_end_point_ptr = get_pointer_to_current_end_point(dest); - llvm::Value* dest_capacity_ptr = get_pointer_to_current_capacity(dest); - builder->CreateStore(src_end_point, dest_end_point_ptr); - builder->CreateStore(src_capacity, dest_capacity_ptr); - llvm::Value* src_data = LLVM::CreateLoad(*builder, get_pointer_to_list_data(src)); - int32_t type_size = std::get<1>(typecode2listtype[src_type_code]); - llvm::Value* arg_size = builder->CreateMul(llvm::ConstantInt::get(context, - llvm::APInt(32, type_size)), src_capacity); - llvm::Value* copy_data = LLVM::lfortran_malloc(context, *module, *builder, - arg_size); - llvm::Type* el_type = std::get<2>(typecode2listtype[src_type_code]); - copy_data = builder->CreateBitCast(copy_data, el_type->getPointerTo()); - - // We consider the case when the element type of a list is defined by a struct - // which may also contain non-trivial structs (such as in case of list[list[f64]], - // list[tuple[f64]]). We need to make sure that all the data inside those structs - // is deepcopied and not just the address of the first element of those structs. - // Hence we dive deeper into the lowest level of nested types and deepcopy everything - // properly. If we don't consider this case then the data only from first level of nested types - // will be deep copied and rest will be shallow copied. The importance of this case - // can be figured out by goind through, integration_tests/test_list_06.py and - // integration_tests/test_list_07.py. - if( LLVM::is_llvm_struct(element_type) ) { - builder->CreateStore(copy_data, get_pointer_to_list_data(dest)); - // TODO: Should be created outside the user loop and not here. - // LLVMList should treat them as data members and create them - // only if they are NULL - llvm::AllocaInst *pos_ptr = builder->CreateAlloca(llvm::Type::getInt32Ty(context), - nullptr); - LLVM::CreateStore(*builder, llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), - llvm::APInt(32, 0)), pos_ptr); - - llvm::BasicBlock *loophead = llvm::BasicBlock::Create(context, "loop.head"); - llvm::BasicBlock *loopbody = llvm::BasicBlock::Create(context, "loop.body"); - llvm::BasicBlock *loopend = llvm::BasicBlock::Create(context, "loop.end"); - - // head - llvm_utils->start_new_block(loophead); - { - llvm::Value *cond = builder->CreateICmpSGT( - src_end_point, - LLVM::CreateLoad(*builder, pos_ptr)); - builder->CreateCondBr(cond, loopbody, loopend); - } - - // body - llvm_utils->start_new_block(loopbody); - { - llvm::Value* pos = LLVM::CreateLoad(*builder, pos_ptr); - llvm::Value* srci = read_item(src, pos, false, *module, true); - llvm::Value* desti = read_item(dest, pos, false, *module, true); - llvm_utils->deepcopy(srci, desti, element_type, module, name2memidx); - llvm::Value* tmp = builder->CreateAdd( - pos, - llvm::ConstantInt::get(context, llvm::APInt(32, 1))); - LLVM::CreateStore(*builder, tmp, pos_ptr); - } - - builder->CreateBr(loophead); - - // end - llvm_utils->start_new_block(loopend); - } else { - builder->CreateMemCpy(copy_data, llvm::MaybeAlign(), src_data, - llvm::MaybeAlign(), arg_size); - builder->CreateStore(copy_data, get_pointer_to_list_data(dest)); - } - } - - void LLVMDict::dict_deepcopy(llvm::Value* src, llvm::Value* dest, - ASR::Dict_t* dict_type, llvm::Module* module, - std::map>& name2memidx) { - LCOMPILERS_ASSERT(src->getType() == dest->getType()); - llvm::Value* src_occupancy = LLVM::CreateLoad(*builder, get_pointer_to_occupancy(src)); - llvm::Value* dest_occupancy_ptr = get_pointer_to_occupancy(dest); - LLVM::CreateStore(*builder, src_occupancy, dest_occupancy_ptr); - - llvm::Value* src_key_list = get_key_list(src); - llvm::Value* dest_key_list = get_key_list(dest); - llvm_utils->list_api->list_deepcopy(src_key_list, dest_key_list, - dict_type->m_key_type, module, - name2memidx); - - llvm::Value* src_value_list = get_value_list(src); - llvm::Value* dest_value_list = get_value_list(dest); - llvm_utils->list_api->list_deepcopy(src_value_list, dest_value_list, - dict_type->m_value_type, module, name2memidx); - - llvm::Value* src_key_mask = LLVM::CreateLoad(*builder, get_pointer_to_keymask(src)); - llvm::Value* dest_key_mask_ptr = get_pointer_to_keymask(dest); - llvm::DataLayout data_layout(module); - size_t mask_size = data_layout.getTypeAllocSize(llvm::Type::getInt8Ty(context)); - llvm::Value* llvm_mask_size = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), - llvm::APInt(32, mask_size)); - llvm::Value* src_capacity = LLVM::CreateLoad(*builder, get_pointer_to_capacity(src)); - llvm::Value* dest_key_mask = LLVM::lfortran_calloc(context, *module, *builder, src_capacity, - llvm_mask_size); - builder->CreateMemCpy(dest_key_mask, llvm::MaybeAlign(), src_key_mask, - llvm::MaybeAlign(), builder->CreateMul(src_capacity, llvm_mask_size)); - LLVM::CreateStore(*builder, dest_key_mask, dest_key_mask_ptr); - } - - void LLVMDictSeparateChaining::deepcopy_key_value_pair_linked_list( - llvm::Value* srci, llvm::Value* desti, llvm::Value* dest_key_value_pairs, - llvm::Value* src_capacity, ASR::Dict_t* dict_type, llvm::Module* module, - std::map>& name2memidx) { - if( !are_iterators_set ) { - src_itr = builder->CreateAlloca(llvm::Type::getInt8PtrTy(context), nullptr); - dest_itr = builder->CreateAlloca(llvm::Type::getInt8PtrTy(context), nullptr); - next_ptr = builder->CreateAlloca(llvm::Type::getInt32Ty(context), nullptr); - } - llvm::Type* key_value_pair_type = get_key_value_pair_type(dict_type->m_key_type, dict_type->m_value_type)->getPointerTo(); - LLVM::CreateStore(*builder, - builder->CreateBitCast(srci, llvm::Type::getInt8PtrTy(context)), - src_itr); - LLVM::CreateStore(*builder, - builder->CreateBitCast(desti, llvm::Type::getInt8PtrTy(context)), - dest_itr); - LLVM::CreateStore(*builder, src_capacity, next_ptr); - llvm::BasicBlock *loophead = llvm::BasicBlock::Create(context, "loop.head"); - llvm::BasicBlock *loopbody = llvm::BasicBlock::Create(context, "loop.body"); - llvm::BasicBlock *loopend = llvm::BasicBlock::Create(context, "loop.end"); - // head - llvm_utils->start_new_block(loophead); - { - llvm::Value *cond = builder->CreateICmpNE( - LLVM::CreateLoad(*builder, src_itr), - llvm::ConstantPointerNull::get(llvm::Type::getInt8PtrTy(context)) - ); - builder->CreateCondBr(cond, loopbody, loopend); - } - - // body - llvm_utils->start_new_block(loopbody); - { - llvm::Value* curr_src = builder->CreateBitCast(LLVM::CreateLoad(*builder, src_itr), - key_value_pair_type); - llvm::Value* curr_dest = builder->CreateBitCast(LLVM::CreateLoad(*builder, dest_itr), - key_value_pair_type); - llvm::Value* src_key_ptr = llvm_utils->create_gep(curr_src, 0); - llvm::Value* src_value_ptr = llvm_utils->create_gep(curr_src, 1); - llvm::Value *src_key = src_key_ptr, *src_value = src_value_ptr; - if( !LLVM::is_llvm_struct(dict_type->m_key_type) ) { - src_key = LLVM::CreateLoad(*builder, src_key_ptr); - } - if( !LLVM::is_llvm_struct(dict_type->m_value_type) ) { - src_value = LLVM::CreateLoad(*builder, src_value_ptr); - } - llvm::Value* dest_key_ptr = llvm_utils->create_gep(curr_dest, 0); - llvm::Value* dest_value_ptr = llvm_utils->create_gep(curr_dest, 1); - llvm_utils->deepcopy(src_key, dest_key_ptr, dict_type->m_key_type, module, name2memidx); - llvm_utils->deepcopy(src_value, dest_value_ptr, dict_type->m_value_type, module, name2memidx); - - llvm::Value* src_next_ptr = LLVM::CreateLoad(*builder, llvm_utils->create_gep(curr_src, 2)); - llvm::Value* curr_dest_next_ptr = llvm_utils->create_gep(curr_dest, 2); - LLVM::CreateStore(*builder, src_next_ptr, src_itr); - llvm::Function *fn = builder->GetInsertBlock()->getParent(); - llvm::BasicBlock *thenBB = llvm::BasicBlock::Create(context, "then", fn); - llvm::BasicBlock *elseBB = llvm::BasicBlock::Create(context, "else"); - llvm::BasicBlock *mergeBB = llvm::BasicBlock::Create(context, "ifcont"); - llvm::Value* src_next_exists = builder->CreateICmpNE(src_next_ptr, - llvm::ConstantPointerNull::get(llvm::Type::getInt8PtrTy(context))); - builder->CreateCondBr(src_next_exists, thenBB, elseBB); - builder->SetInsertPoint(thenBB); - { - llvm::Value* next_idx = LLVM::CreateLoad(*builder, next_ptr); - llvm::Value* dest_next_ptr = llvm_utils->create_ptr_gep(dest_key_value_pairs, next_idx); - dest_next_ptr = builder->CreateBitCast(dest_next_ptr, llvm::Type::getInt8PtrTy(context)); - LLVM::CreateStore(*builder, dest_next_ptr, curr_dest_next_ptr); - LLVM::CreateStore(*builder, dest_next_ptr, dest_itr); - next_idx = builder->CreateAdd(next_idx, llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), - llvm::APInt(32, 1))); - LLVM::CreateStore(*builder, next_idx, next_ptr); - } - builder->CreateBr(mergeBB); - llvm_utils->start_new_block(elseBB); - { - LLVM::CreateStore(*builder, - llvm::ConstantPointerNull::get(llvm::Type::getInt8PtrTy(context)), - curr_dest_next_ptr - ); - } - llvm_utils->start_new_block(mergeBB); - } - - builder->CreateBr(loophead); - - // end - llvm_utils->start_new_block(loopend); - } - - void LLVMDictSeparateChaining::write_key_value_pair_linked_list( - llvm::Value* kv_ll, llvm::Value* dict, llvm::Value* capacity, - ASR::ttype_t* m_key_type, ASR::ttype_t* m_value_type, llvm::Module* module, - std::map>& name2memidx) { - if( !are_iterators_set ) { - src_itr = builder->CreateAlloca(llvm::Type::getInt8PtrTy(context), nullptr); - } - llvm::Type* key_value_pair_type = get_key_value_pair_type(m_key_type, m_value_type)->getPointerTo(); - LLVM::CreateStore(*builder, - builder->CreateBitCast(kv_ll, llvm::Type::getInt8PtrTy(context)), - src_itr); - llvm::BasicBlock *loophead = llvm::BasicBlock::Create(context, "loop.head"); - llvm::BasicBlock *loopbody = llvm::BasicBlock::Create(context, "loop.body"); - llvm::BasicBlock *loopend = llvm::BasicBlock::Create(context, "loop.end"); - // head - llvm_utils->start_new_block(loophead); - { - llvm::Value *cond = builder->CreateICmpNE( - LLVM::CreateLoad(*builder, src_itr), - llvm::ConstantPointerNull::get(llvm::Type::getInt8PtrTy(context)) - ); - builder->CreateCondBr(cond, loopbody, loopend); - } - - // body - llvm_utils->start_new_block(loopbody); - { - llvm::Value* curr_src = builder->CreateBitCast(LLVM::CreateLoad(*builder, src_itr), - key_value_pair_type); - llvm::Value* src_key_ptr = llvm_utils->create_gep(curr_src, 0); - llvm::Value* src_value_ptr = llvm_utils->create_gep(curr_src, 1); - llvm::Value *src_key = src_key_ptr, *src_value = src_value_ptr; - if( !LLVM::is_llvm_struct(m_key_type) ) { - src_key = LLVM::CreateLoad(*builder, src_key_ptr); - } - if( !LLVM::is_llvm_struct(m_value_type) ) { - src_value = LLVM::CreateLoad(*builder, src_value_ptr); - } - llvm::Value* key_hash = get_key_hash(capacity, src_key, m_key_type, *module); - resolve_collision_for_write( - dict, key_hash, src_key, - src_value, module, - m_key_type, m_value_type, - name2memidx); - - llvm::Value* src_next_ptr = LLVM::CreateLoad(*builder, llvm_utils->create_gep(curr_src, 2)); - LLVM::CreateStore(*builder, src_next_ptr, src_itr); - } - - builder->CreateBr(loophead); - - // end - llvm_utils->start_new_block(loopend); - } - - void LLVMDictSeparateChaining::dict_deepcopy( - llvm::Value* src, llvm::Value* dest, - ASR::Dict_t* dict_type, llvm::Module* module, - std::map>& name2memidx) { - llvm::Value* src_occupancy = LLVM::CreateLoad(*builder, get_pointer_to_occupancy(src)); - llvm::Value* src_filled_buckets = LLVM::CreateLoad(*builder, get_pointer_to_number_of_filled_buckets(src)); - llvm::Value* src_capacity = LLVM::CreateLoad(*builder, get_pointer_to_capacity(src)); - llvm::Value* src_key_mask = LLVM::CreateLoad(*builder, get_pointer_to_keymask(src)); - llvm::Value* src_rehash_flag = LLVM::CreateLoad(*builder, get_pointer_to_rehash_flag(src)); - LLVM::CreateStore(*builder, src_occupancy, get_pointer_to_occupancy(dest)); - LLVM::CreateStore(*builder, src_filled_buckets, get_pointer_to_number_of_filled_buckets(dest)); - LLVM::CreateStore(*builder, src_capacity, get_pointer_to_capacity(dest)); - LLVM::CreateStore(*builder, src_rehash_flag, get_pointer_to_rehash_flag(dest)); - llvm::DataLayout data_layout(module); - size_t mask_size = data_layout.getTypeAllocSize(llvm::Type::getInt8Ty(context)); - llvm::Value* llvm_mask_size = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), - llvm::APInt(32, mask_size)); - llvm::Value* malloc_size = builder->CreateMul(src_capacity, llvm_mask_size); - llvm::Value* dest_key_mask = LLVM::lfortran_malloc(context, *module, *builder, malloc_size); - LLVM::CreateStore(*builder, dest_key_mask, get_pointer_to_keymask(dest)); - - malloc_size = builder->CreateSub(src_occupancy, src_filled_buckets); - malloc_size = builder->CreateAdd(src_capacity, malloc_size); - size_t kv_struct_size = data_layout.getTypeAllocSize(get_key_value_pair_type(dict_type->m_key_type, - dict_type->m_value_type)); - llvm::Value* llvm_kv_struct_size = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), llvm::APInt(32, kv_struct_size)); - malloc_size = builder->CreateMul(malloc_size, llvm_kv_struct_size); - llvm::Value* dest_key_value_pairs = LLVM::lfortran_malloc(context, *module, *builder, malloc_size); - dest_key_value_pairs = builder->CreateBitCast( - dest_key_value_pairs, - get_key_value_pair_type(dict_type->m_key_type, dict_type->m_value_type)->getPointerTo()); - if( !are_iterators_set ) { - copy_itr = builder->CreateAlloca(llvm::Type::getInt32Ty(context), nullptr); - } - llvm::Value* llvm_zero = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), llvm::APInt(32, 0)); - LLVM::CreateStore(*builder, llvm_zero, copy_itr); - - llvm::Value* src_key_value_pairs = LLVM::CreateLoad(*builder, get_pointer_to_key_value_pairs(src)); - llvm::BasicBlock *loophead = llvm::BasicBlock::Create(context, "loop.head"); - llvm::BasicBlock *loopbody = llvm::BasicBlock::Create(context, "loop.body"); - llvm::BasicBlock *loopend = llvm::BasicBlock::Create(context, "loop.end"); - - // head - llvm_utils->start_new_block(loophead); - { - llvm::Value *cond = builder->CreateICmpSGT( - src_capacity, - LLVM::CreateLoad(*builder, copy_itr)); - builder->CreateCondBr(cond, loopbody, loopend); - } - - // body - llvm_utils->start_new_block(loopbody); - { - llvm::Value* itr = LLVM::CreateLoad(*builder, copy_itr); - llvm::Value* key_mask_value = LLVM::CreateLoad(*builder, - llvm_utils->create_ptr_gep(src_key_mask, itr)); - LLVM::CreateStore(*builder, key_mask_value, - llvm_utils->create_ptr_gep(dest_key_mask, itr)); - llvm::Function *fn = builder->GetInsertBlock()->getParent(); - llvm::BasicBlock *thenBB = llvm::BasicBlock::Create(context, "then", fn); - llvm::BasicBlock *elseBB = llvm::BasicBlock::Create(context, "else"); - llvm::BasicBlock *mergeBB = llvm::BasicBlock::Create(context, "ifcont"); - llvm::Value* is_key_set = builder->CreateICmpEQ(key_mask_value, - llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), llvm::APInt(8, 1))); - builder->CreateCondBr(is_key_set, thenBB, elseBB); - builder->SetInsertPoint(thenBB); - { - - llvm::Value* srci = llvm_utils->create_ptr_gep(src_key_value_pairs, itr); - llvm::Value* desti = llvm_utils->create_ptr_gep(dest_key_value_pairs, itr); - deepcopy_key_value_pair_linked_list(srci, desti, dest_key_value_pairs, - src_capacity, dict_type, module, name2memidx); - } - builder->CreateBr(mergeBB); - llvm_utils->start_new_block(elseBB); - llvm_utils->start_new_block(mergeBB); - llvm::Value* tmp = builder->CreateAdd( - itr, - llvm::ConstantInt::get(context, llvm::APInt(32, 1))); - LLVM::CreateStore(*builder, tmp, copy_itr); - } - - builder->CreateBr(loophead); - - // end - llvm_utils->start_new_block(loopend); - LLVM::CreateStore(*builder, dest_key_value_pairs, get_pointer_to_key_value_pairs(dest)); - } - - void LLVMList::check_index_within_bounds(llvm::Value* list, - llvm::Value* pos, llvm::Module& module) { - llvm::Value* end_point = LLVM::CreateLoad(*builder, - get_pointer_to_current_end_point(list)); - llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), - llvm::APInt(32, 0)); - - llvm::Function *fn = builder->GetInsertBlock()->getParent(); - llvm::BasicBlock *thenBB = llvm::BasicBlock::Create(context, "then", fn); - llvm::BasicBlock *elseBB = llvm::BasicBlock::Create(context, "else"); - llvm::BasicBlock *mergeBB = llvm::BasicBlock::Create(context, "ifcont"); - - llvm::Value* cond = builder->CreateOr( - builder->CreateICmpSGE(pos, end_point), - builder->CreateICmpSLT(pos, zero)); - builder->CreateCondBr(cond, thenBB, elseBB); - builder->SetInsertPoint(thenBB); - { - std::string index_error = "IndexError: %s%d%s%d\n", - message1 = "List index is out of range. Index range is (0, ", - message2 = "), but the given index is "; - llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr(index_error); - llvm::Value *fmt_ptr1 = builder->CreateGlobalStringPtr(message1); - llvm::Value *fmt_ptr2 = builder->CreateGlobalStringPtr(message2); - llvm::Value *end_minus_one = builder->CreateSub(end_point, - llvm::ConstantInt::get(context, llvm::APInt(32, 1))); - print_error(context, module, *builder, {fmt_ptr, fmt_ptr1, - end_minus_one, fmt_ptr2, pos}); - int exit_code_int = 1; - llvm::Value *exit_code = llvm::ConstantInt::get(context, - llvm::APInt(32, exit_code_int)); - exit(context, module, *builder, exit_code); - } - builder->CreateBr(mergeBB); - - llvm_utils->start_new_block(elseBB); - llvm_utils->start_new_block(mergeBB); - } - - void LLVMList::write_item(llvm::Value* list, llvm::Value* pos, - llvm::Value* item, ASR::ttype_t* asr_type, - bool enable_bounds_checking, llvm::Module* module, - std::map>& name2memidx) { - if( enable_bounds_checking ) { - check_index_within_bounds(list, pos, *module); - } - llvm::Value* list_data = LLVM::CreateLoad(*builder, get_pointer_to_list_data(list)); - llvm::Value* element_ptr = llvm_utils->create_ptr_gep(list_data, pos); - llvm_utils->deepcopy(item, element_ptr, asr_type, module, name2memidx); - } - - void LLVMList::write_item(llvm::Value* list, llvm::Value* pos, - llvm::Value* item, bool enable_bounds_checking, - llvm::Module& module) { - if( enable_bounds_checking ) { - check_index_within_bounds(list, pos, module); - } - llvm::Value* list_data = LLVM::CreateLoad(*builder, get_pointer_to_list_data(list)); - llvm::Value* element_ptr = llvm_utils->create_ptr_gep(list_data, pos); - LLVM::CreateStore(*builder, item, element_ptr); - } - - llvm::Value* LLVMDict::get_pointer_to_keymask(llvm::Value* dict) { - return llvm_utils->create_gep(dict, 3); - } - - llvm::Value* LLVMDictSeparateChaining::get_pointer_to_keymask(llvm::Value* dict) { - return llvm_utils->create_gep(dict, 4); - } - - void LLVMDictInterface::set_iterators() { - if( are_iterators_set || !is_dict_present_ ) { - return ; - } - llvm_utils->set_iterators(); - pos_ptr = builder->CreateAlloca(llvm::Type::getInt32Ty(context), nullptr, "pos_ptr"); - LLVM::CreateStore(*builder, llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), - llvm::APInt(32, 0)), pos_ptr); - is_key_matching_var = builder->CreateAlloca(llvm::Type::getInt1Ty(context), nullptr, - "is_key_matching_var"); - LLVM::CreateStore(*builder, llvm::ConstantInt::get(llvm::Type::getInt1Ty(context), - llvm::APInt(1, 0)), is_key_matching_var); - idx_ptr = builder->CreateAlloca(llvm::Type::getInt32Ty(context), nullptr, "idx_ptr"); - LLVM::CreateStore(*builder, llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), - llvm::APInt(32, 0)), idx_ptr); - hash_value = builder->CreateAlloca(llvm::Type::getInt64Ty(context), nullptr, "hash_value"); - LLVM::CreateStore(*builder, llvm::ConstantInt::get(llvm::Type::getInt64Ty(context), - llvm::APInt(64, 0)), hash_value); - hash_iter = builder->CreateAlloca(llvm::Type::getInt64Ty(context), nullptr, "hash_iter"); - LLVM::CreateStore(*builder, llvm::ConstantInt::get(llvm::Type::getInt64Ty(context), - llvm::APInt(64, 0)), hash_iter); - polynomial_powers = builder->CreateAlloca(llvm::Type::getInt64Ty(context), nullptr, "p_pow"); - LLVM::CreateStore(*builder, llvm::ConstantInt::get(llvm::Type::getInt64Ty(context), - llvm::APInt(64, 1)), polynomial_powers); - chain_itr = builder->CreateAlloca(llvm::Type::getInt8PtrTy(context), nullptr); - LLVM::CreateStore(*builder, - llvm::ConstantPointerNull::get(llvm::Type::getInt8PtrTy(context)), chain_itr); - chain_itr_prev = builder->CreateAlloca(llvm::Type::getInt8PtrTy(context), nullptr); - LLVM::CreateStore(*builder, - llvm::ConstantPointerNull::get(llvm::Type::getInt8PtrTy(context)), chain_itr_prev); - old_capacity = builder->CreateAlloca(llvm::Type::getInt32Ty(context), nullptr); - LLVM::CreateStore(*builder, llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), - llvm::APInt(32, 0)), old_capacity); - old_occupancy = builder->CreateAlloca(llvm::Type::getInt32Ty(context), nullptr); - LLVM::CreateStore(*builder, llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), - llvm::APInt(32, 0)), old_occupancy); - old_number_of_buckets_filled = builder->CreateAlloca(llvm::Type::getInt32Ty(context), nullptr); - LLVM::CreateStore(*builder, llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), - llvm::APInt(32, 0)), old_number_of_buckets_filled); - old_key_value_pairs = builder->CreateAlloca(llvm::Type::getInt8PtrTy(context), nullptr); - LLVM::CreateStore(*builder, - llvm::ConstantPointerNull::get(llvm::Type::getInt8PtrTy(context)), old_key_value_pairs); - old_key_mask = builder->CreateAlloca(llvm::Type::getInt8PtrTy(context), nullptr); - LLVM::CreateStore(*builder, - llvm::ConstantPointerNull::get(llvm::Type::getInt8PtrTy(context)), old_key_mask); - src_itr = builder->CreateAlloca(llvm::Type::getInt8PtrTy(context), nullptr); - LLVM::CreateStore(*builder, - llvm::ConstantPointerNull::get(llvm::Type::getInt8PtrTy(context)), src_itr); - dest_itr = builder->CreateAlloca(llvm::Type::getInt8PtrTy(context), nullptr); - LLVM::CreateStore(*builder, - llvm::ConstantPointerNull::get(llvm::Type::getInt8PtrTy(context)), dest_itr); - next_ptr = builder->CreateAlloca(llvm::Type::getInt32Ty(context), nullptr); - LLVM::CreateStore(*builder, llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), - llvm::APInt(32, 0)), next_ptr); - copy_itr = builder->CreateAlloca(llvm::Type::getInt32Ty(context), nullptr); - LLVM::CreateStore(*builder, llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), - llvm::APInt(32, 0)), copy_itr); - tmp_value_ptr = builder->CreateAlloca(llvm::Type::getInt8Ty(context), nullptr); - are_iterators_set = true; - } - - void LLVMDictInterface::reset_iterators() { - llvm_utils->reset_iterators(); - pos_ptr = nullptr; - is_key_matching_var = nullptr; - idx_ptr = nullptr; - hash_iter = nullptr; - hash_value = nullptr; - polynomial_powers = nullptr; - chain_itr = nullptr; - chain_itr_prev = nullptr; - old_capacity = nullptr; - old_occupancy = nullptr; - old_number_of_buckets_filled = nullptr; - old_key_value_pairs = nullptr; - old_key_mask = nullptr; - src_itr = nullptr; - dest_itr = nullptr; - next_ptr = nullptr; - copy_itr = nullptr; - tmp_value_ptr = nullptr; - are_iterators_set = false; - } - - void LLVMDict::resolve_collision( - llvm::Value* capacity, llvm::Value* key_hash, - llvm::Value* key, llvm::Value* key_list, - llvm::Value* key_mask, llvm::Module& module, - ASR::ttype_t* key_asr_type, bool for_read) { - if( !are_iterators_set ) { - pos_ptr = builder->CreateAlloca(llvm::Type::getInt32Ty(context), nullptr); - is_key_matching_var = builder->CreateAlloca(llvm::Type::getInt1Ty(context), nullptr); - } - LLVM::CreateStore(*builder, key_hash, pos_ptr); - - - llvm::BasicBlock *loophead = llvm::BasicBlock::Create(context, "loop.head"); - llvm::BasicBlock *loopbody = llvm::BasicBlock::Create(context, "loop.body"); - llvm::BasicBlock *loopend = llvm::BasicBlock::Create(context, "loop.end"); - - - // head - llvm_utils->start_new_block(loophead); - { - llvm::Value* pos = LLVM::CreateLoad(*builder, pos_ptr); - llvm::Value* key_mask_value = LLVM::CreateLoad(*builder, - llvm_utils->create_ptr_gep(key_mask, pos)); - llvm::Value* is_key_skip = builder->CreateICmpEQ(key_mask_value, - llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), llvm::APInt(8, 3))); - llvm::Value* is_key_set = builder->CreateICmpNE(key_mask_value, - llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), llvm::APInt(8, 0))); - llvm::Value* is_key_matching = llvm::ConstantInt::get(llvm::Type::getInt1Ty(context), - llvm::APInt(1, 0)); - LLVM::CreateStore(*builder, is_key_matching, is_key_matching_var); - llvm::Function *fn = builder->GetInsertBlock()->getParent(); - llvm::BasicBlock *thenBB = llvm::BasicBlock::Create(context, "then", fn); - llvm::BasicBlock *elseBB = llvm::BasicBlock::Create(context, "else"); - llvm::BasicBlock *mergeBB = llvm::BasicBlock::Create(context, "ifcont"); - llvm::Value* compare_keys = builder->CreateAnd(is_key_set, - builder->CreateNot(is_key_skip)); - builder->CreateCondBr(compare_keys, thenBB, elseBB); - builder->SetInsertPoint(thenBB); - { - llvm::Value* original_key = llvm_utils->list_api->read_item(key_list, pos, - false, module, LLVM::is_llvm_struct(key_asr_type)); - is_key_matching = llvm_utils->is_equal_by_value(key, original_key, module, - key_asr_type); - LLVM::CreateStore(*builder, is_key_matching, is_key_matching_var); - } - builder->CreateBr(mergeBB); - - - llvm_utils->start_new_block(elseBB); - llvm_utils->start_new_block(mergeBB); - // TODO: Allow safe exit if pos becomes key_hash again. - // Ideally should not happen as dict will be resized once - // load factor touches a threshold (which will always be less than 1) - // so there will be some key which will not be set. However for safety - // we can add an exit from the loop with a error message. - llvm::Value *cond = nullptr; - if( for_read ) { - cond = builder->CreateAnd(is_key_set, builder->CreateNot( - LLVM::CreateLoad(*builder, is_key_matching_var))); - cond = builder->CreateOr(is_key_skip, cond); - } else { - cond = builder->CreateAnd(is_key_set, builder->CreateNot(is_key_skip)); - cond = builder->CreateAnd(cond, builder->CreateNot( - LLVM::CreateLoad(*builder, is_key_matching_var))); - } - builder->CreateCondBr(cond, loopbody, loopend); - } - - - // body - llvm_utils->start_new_block(loopbody); - { - llvm::Value* pos = LLVM::CreateLoad(*builder, pos_ptr); - pos = builder->CreateAdd(pos, llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), - llvm::APInt(32, 1))); - pos = builder->CreateSRem(pos, capacity); - LLVM::CreateStore(*builder, pos, pos_ptr); - } - - - builder->CreateBr(loophead); - - - // end - llvm_utils->start_new_block(loopend); - } - - void LLVMDictOptimizedLinearProbing::resolve_collision( - llvm::Value* capacity, llvm::Value* key_hash, - llvm::Value* key, llvm::Value* key_list, - llvm::Value* key_mask, llvm::Module& module, - ASR::ttype_t* key_asr_type, bool for_read) { - if( !are_iterators_set ) { - if( !for_read ) { - pos_ptr = builder->CreateAlloca(llvm::Type::getInt32Ty(context), nullptr); - } - is_key_matching_var = builder->CreateAlloca(llvm::Type::getInt1Ty(context), nullptr); - } - - LLVM::CreateStore(*builder, key_hash, pos_ptr); - - llvm::BasicBlock *loophead = llvm::BasicBlock::Create(context, "loop.head"); - llvm::BasicBlock *loopbody = llvm::BasicBlock::Create(context, "loop.body"); - llvm::BasicBlock *loopend = llvm::BasicBlock::Create(context, "loop.end"); - - // head - llvm_utils->start_new_block(loophead); - { - llvm::Value* pos = LLVM::CreateLoad(*builder, pos_ptr); - llvm::Value* key_mask_value = LLVM::CreateLoad(*builder, - llvm_utils->create_ptr_gep(key_mask, pos)); - llvm::Value* is_key_skip = builder->CreateICmpEQ(key_mask_value, - llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), llvm::APInt(8, 3))); - llvm::Value* is_key_set = builder->CreateICmpNE(key_mask_value, - llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), llvm::APInt(8, 0))); - llvm::Value* is_key_matching = llvm::ConstantInt::get(llvm::Type::getInt1Ty(context), - llvm::APInt(1, 0)); - LLVM::CreateStore(*builder, is_key_matching, is_key_matching_var); - llvm::Function *fn = builder->GetInsertBlock()->getParent(); - llvm::BasicBlock *thenBB = llvm::BasicBlock::Create(context, "then", fn); - llvm::BasicBlock *elseBB = llvm::BasicBlock::Create(context, "else"); - llvm::BasicBlock *mergeBB = llvm::BasicBlock::Create(context, "ifcont"); - llvm::Value* compare_keys = builder->CreateAnd(is_key_set, - builder->CreateNot(is_key_skip)); - builder->CreateCondBr(compare_keys, thenBB, elseBB); - builder->SetInsertPoint(thenBB); - { - llvm::Value* original_key = llvm_utils->list_api->read_item(key_list, pos, - false, module, LLVM::is_llvm_struct(key_asr_type)); - is_key_matching = llvm_utils->is_equal_by_value(key, original_key, module, - key_asr_type); - LLVM::CreateStore(*builder, is_key_matching, is_key_matching_var); - } - builder->CreateBr(mergeBB); - - llvm_utils->start_new_block(elseBB); - llvm_utils->start_new_block(mergeBB); - // TODO: Allow safe exit if pos becomes key_hash again. - // Ideally should not happen as dict will be resized once - // load factor touches a threshold (which will always be less than 1) - // so there will be some key which will not be set. However for safety - // we can add an exit from the loop with a error message. - llvm::Value *cond = nullptr; - if( for_read ) { - cond = builder->CreateAnd(is_key_set, builder->CreateNot( - LLVM::CreateLoad(*builder, is_key_matching_var))); - cond = builder->CreateOr(is_key_skip, cond); - } else { - cond = builder->CreateAnd(is_key_set, builder->CreateNot(is_key_skip)); - cond = builder->CreateAnd(cond, builder->CreateNot( - LLVM::CreateLoad(*builder, is_key_matching_var))); - } - builder->CreateCondBr(cond, loopbody, loopend); - } - - // body - llvm_utils->start_new_block(loopbody); - { - llvm::Value* pos = LLVM::CreateLoad(*builder, pos_ptr); - pos = builder->CreateAdd(pos, llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), - llvm::APInt(32, 1))); - pos = builder->CreateSRem(pos, capacity); - LLVM::CreateStore(*builder, pos, pos_ptr); - } - - builder->CreateBr(loophead); - - // end - llvm_utils->start_new_block(loopend); - } - - void LLVMDictSeparateChaining::resolve_collision( - llvm::Value* /*capacity*/, llvm::Value* key_hash, - llvm::Value* key, llvm::Value* key_value_pair_linked_list, - llvm::Type* kv_pair_type, llvm::Value* key_mask, - llvm::Module& module, ASR::ttype_t* key_asr_type) { - if( !are_iterators_set ) { - chain_itr = builder->CreateAlloca(llvm::Type::getInt8PtrTy(context), nullptr); - chain_itr_prev = builder->CreateAlloca(llvm::Type::getInt8PtrTy(context), nullptr); - is_key_matching_var = builder->CreateAlloca(llvm::Type::getInt1Ty(context), nullptr); - } - - LLVM::CreateStore(*builder, - llvm::ConstantPointerNull::get(llvm::Type::getInt8PtrTy(context)), chain_itr_prev); - llvm::Value* kv_ll_i8 = builder->CreateBitCast(key_value_pair_linked_list, llvm::Type::getInt8PtrTy(context)); - LLVM::CreateStore(*builder, kv_ll_i8, chain_itr); - llvm::Value* key_mask_value = LLVM::CreateLoad(*builder, - llvm_utils->create_ptr_gep(key_mask, key_hash)); - LLVM::CreateStore(*builder, - builder->CreateICmpEQ(key_mask_value, llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), llvm::APInt(8, 1))), - is_key_matching_var - ); - llvm::BasicBlock *loophead = llvm::BasicBlock::Create(context, "loop.head"); - llvm::BasicBlock *loopbody = llvm::BasicBlock::Create(context, "loop.body"); - llvm::BasicBlock *loopend = llvm::BasicBlock::Create(context, "loop.end"); - - // head - llvm_utils->start_new_block(loophead); - { - llvm::Value *cond = builder->CreateICmpNE( - LLVM::CreateLoad(*builder, chain_itr), - llvm::ConstantPointerNull::get(llvm::Type::getInt8PtrTy(context)) - ); - cond = builder->CreateAnd(cond, LLVM::CreateLoad(*builder, is_key_matching_var)); - builder->CreateCondBr(cond, loopbody, loopend); - } - - // body - llvm_utils->start_new_block(loopbody); - { - llvm::Value* kv_struct_i8 = LLVM::CreateLoad(*builder, chain_itr); - LLVM::CreateStore(*builder, kv_struct_i8, chain_itr_prev); - llvm::Value* kv_struct = builder->CreateBitCast(kv_struct_i8, kv_pair_type->getPointerTo()); - llvm::Value* kv_key = llvm_utils->create_gep(kv_struct, 0); - if( !LLVM::is_llvm_struct(key_asr_type) ) { - kv_key = LLVM::CreateLoad(*builder, kv_key); - } - llvm::Value* break_signal = llvm_utils->is_equal_by_value(key, kv_key, module, key_asr_type); - break_signal = builder->CreateNot(break_signal); - LLVM::CreateStore(*builder, break_signal, is_key_matching_var); - llvm::Function *fn = builder->GetInsertBlock()->getParent(); - llvm::BasicBlock *thenBB = llvm::BasicBlock::Create(context, "then", fn); - llvm::BasicBlock *elseBB = llvm::BasicBlock::Create(context, "else"); - llvm::BasicBlock *mergeBB = llvm::BasicBlock::Create(context, "ifcont"); - builder->CreateCondBr(break_signal, thenBB, elseBB); - builder->SetInsertPoint(thenBB); - { - llvm::Value* next_kv_struct = LLVM::CreateLoad(*builder, llvm_utils->create_gep(kv_struct, 2)); - LLVM::CreateStore(*builder, next_kv_struct, chain_itr); - } - builder->CreateBr(mergeBB); - - llvm_utils->start_new_block(elseBB); - llvm_utils->start_new_block(mergeBB); - } - - builder->CreateBr(loophead); - - // end - llvm_utils->start_new_block(loopend); - - } - - void LLVMDict::resolve_collision_for_write( - llvm::Value* dict, llvm::Value* key_hash, - llvm::Value* key, llvm::Value* value, - llvm::Module* module, ASR::ttype_t* key_asr_type, - ASR::ttype_t* value_asr_type, - std::map>& name2memidx) { - llvm::Value* key_list = get_key_list(dict); - llvm::Value* value_list = get_value_list(dict); - llvm::Value* key_mask = LLVM::CreateLoad(*builder, get_pointer_to_keymask(dict)); - llvm::Value* capacity = LLVM::CreateLoad(*builder, get_pointer_to_capacity(dict)); - this->resolve_collision(capacity, key_hash, key, key_list, key_mask, *module, key_asr_type); - llvm::Value* pos = LLVM::CreateLoad(*builder, pos_ptr); - llvm_utils->list_api->write_item(key_list, pos, key, - key_asr_type, false, module, name2memidx); - llvm_utils->list_api->write_item(value_list, pos, value, - value_asr_type, false, module, name2memidx); - llvm::Value* key_mask_value = LLVM::CreateLoad(*builder, - llvm_utils->create_ptr_gep(key_mask, pos)); - llvm::Value* is_slot_empty = builder->CreateICmpEQ(key_mask_value, - llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), llvm::APInt(8, 0))); - llvm::Value* occupancy_ptr = get_pointer_to_occupancy(dict); - is_slot_empty = builder->CreateZExt(is_slot_empty, llvm::Type::getInt32Ty(context)); - llvm::Value* occupancy = LLVM::CreateLoad(*builder, occupancy_ptr); - LLVM::CreateStore(*builder, builder->CreateAdd(occupancy, is_slot_empty), - occupancy_ptr); - LLVM::CreateStore(*builder, - llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), llvm::APInt(8, 1)), - llvm_utils->create_ptr_gep(key_mask, pos)); - } - - void LLVMDictOptimizedLinearProbing::resolve_collision_for_write( - llvm::Value* dict, llvm::Value* key_hash, - llvm::Value* key, llvm::Value* value, - llvm::Module* module, ASR::ttype_t* key_asr_type, - ASR::ttype_t* value_asr_type, - std::map>& name2memidx) { - llvm::Value* key_list = get_key_list(dict); - llvm::Value* value_list = get_value_list(dict); - llvm::Value* key_mask = LLVM::CreateLoad(*builder, get_pointer_to_keymask(dict)); - llvm::Value* capacity = LLVM::CreateLoad(*builder, get_pointer_to_capacity(dict)); - this->resolve_collision(capacity, key_hash, key, key_list, key_mask, *module, key_asr_type); - llvm::Value* pos = LLVM::CreateLoad(*builder, pos_ptr); - llvm_utils->list_api->write_item(key_list, pos, key, - key_asr_type, false, module, name2memidx); - llvm_utils->list_api->write_item(value_list, pos, value, - value_asr_type, false, module, name2memidx); - - llvm::Value* key_mask_value = LLVM::CreateLoad(*builder, - llvm_utils->create_ptr_gep(key_mask, pos)); - llvm::Value* is_slot_empty = builder->CreateICmpEQ(key_mask_value, - llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), llvm::APInt(8, 0))); - llvm::Value* occupancy_ptr = get_pointer_to_occupancy(dict); - is_slot_empty = builder->CreateZExt(is_slot_empty, llvm::Type::getInt32Ty(context)); - llvm::Value* occupancy = LLVM::CreateLoad(*builder, occupancy_ptr); - LLVM::CreateStore(*builder, builder->CreateAdd(occupancy, is_slot_empty), - occupancy_ptr); - - llvm::Value* linear_prob_happened = builder->CreateICmpNE(key_hash, pos); - linear_prob_happened = builder->CreateOr(linear_prob_happened, - builder->CreateICmpEQ( - LLVM::CreateLoad(*builder, llvm_utils->create_ptr_gep(key_mask, key_hash)), - llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), llvm::APInt(8, 2) - )) - ); - llvm::Value* set_max_2 = builder->CreateSelect(linear_prob_happened, - llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), llvm::APInt(8, 2)), - llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), llvm::APInt(8, 1))); - LLVM::CreateStore(*builder, set_max_2, llvm_utils->create_ptr_gep(key_mask, key_hash)); - LLVM::CreateStore(*builder, set_max_2, llvm_utils->create_ptr_gep(key_mask, pos)); - } - - void LLVMDictSeparateChaining::resolve_collision_for_write( - llvm::Value* dict, llvm::Value* key_hash, - llvm::Value* key, llvm::Value* value, - llvm::Module* module, ASR::ttype_t* key_asr_type, - ASR::ttype_t* value_asr_type, - std::map>& name2memidx) { - llvm::Value* capacity = LLVM::CreateLoad(*builder, get_pointer_to_capacity(dict)); - llvm::Value* key_value_pairs = LLVM::CreateLoad(*builder, get_pointer_to_key_value_pairs(dict)); - llvm::Value* key_value_pair_linked_list = llvm_utils->create_ptr_gep(key_value_pairs, key_hash); - llvm::Value* key_mask = LLVM::CreateLoad(*builder, get_pointer_to_keymask(dict)); - llvm::Type* kv_struct_type = get_key_value_pair_type(key_asr_type, value_asr_type); - this->resolve_collision(capacity, key_hash, key, key_value_pair_linked_list, - kv_struct_type, key_mask, *module, key_asr_type); - llvm::Value* kv_struct_i8 = LLVM::CreateLoad(*builder, chain_itr); - llvm::Function *fn = builder->GetInsertBlock()->getParent(); - llvm::BasicBlock *thenBB = llvm::BasicBlock::Create(context, "then", fn); - llvm::BasicBlock *elseBB = llvm::BasicBlock::Create(context, "else"); - llvm::BasicBlock *mergeBB = llvm::BasicBlock::Create(context, "ifcont"); - llvm::Value* do_insert = builder->CreateICmpEQ(kv_struct_i8, - llvm::ConstantPointerNull::get(llvm::Type::getInt8PtrTy(context))); - builder->CreateCondBr(do_insert, thenBB, elseBB); - builder->SetInsertPoint(thenBB); - { - llvm::DataLayout data_layout(module); - size_t kv_struct_size = data_layout.getTypeAllocSize(kv_struct_type); - llvm::Value* malloc_size = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), kv_struct_size); - llvm::Value* new_kv_struct_i8 = LLVM::lfortran_malloc(context, *module, *builder, malloc_size); - llvm::Value* new_kv_struct = builder->CreateBitCast(new_kv_struct_i8, kv_struct_type->getPointerTo()); - llvm_utils->deepcopy(key, llvm_utils->create_gep(new_kv_struct, 0), key_asr_type, module, name2memidx); - llvm_utils->deepcopy(value, llvm_utils->create_gep(new_kv_struct, 1), value_asr_type, module, name2memidx); - LLVM::CreateStore(*builder, - llvm::ConstantPointerNull::get(llvm::Type::getInt8PtrTy(context)), - llvm_utils->create_gep(new_kv_struct, 2)); - llvm::Value* kv_struct_prev_i8 = LLVM::CreateLoad(*builder, chain_itr_prev); - llvm::Value* kv_struct_prev = builder->CreateBitCast(kv_struct_prev_i8, kv_struct_type->getPointerTo()); - LLVM::CreateStore(*builder, new_kv_struct_i8, llvm_utils->create_gep(kv_struct_prev, 2)); - } - builder->CreateBr(mergeBB); - llvm_utils->start_new_block(elseBB); - { - llvm::Value* kv_struct = builder->CreateBitCast(kv_struct_i8, kv_struct_type->getPointerTo()); - llvm_utils->deepcopy(key, llvm_utils->create_gep(kv_struct, 0), key_asr_type, module, name2memidx); - llvm_utils->deepcopy(value, llvm_utils->create_gep(kv_struct, 1), value_asr_type, module, name2memidx); - } - llvm_utils->start_new_block(mergeBB); - llvm::Value* occupancy_ptr = get_pointer_to_occupancy(dict); - llvm::Value* buckets_filled_ptr = get_pointer_to_number_of_filled_buckets(dict); - llvm::Value* occupancy = LLVM::CreateLoad(*builder, occupancy_ptr); - occupancy = builder->CreateAdd(occupancy, - llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), llvm::APInt(32, 1))); - LLVM::CreateStore(*builder, occupancy, occupancy_ptr); - llvm::Value* key_mask_value_ptr = llvm_utils->create_ptr_gep(key_mask, key_hash); - llvm::Value* key_mask_value = LLVM::CreateLoad(*builder, key_mask_value_ptr); - llvm::Value* buckets_filled_delta = builder->CreateICmpEQ(key_mask_value, - llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), llvm::APInt(8, 0))); - llvm::Value* buckets_filled = LLVM::CreateLoad(*builder, buckets_filled_ptr); - buckets_filled = builder->CreateAdd( - buckets_filled, - builder->CreateZExt(buckets_filled_delta, llvm::Type::getInt32Ty(context)) - ); - LLVM::CreateStore(*builder, buckets_filled, buckets_filled_ptr); - LLVM::CreateStore(*builder, - llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), llvm::APInt(8, 1)), - key_mask_value_ptr); - } - - llvm::Value* LLVMDict::resolve_collision_for_read( - llvm::Value* dict, llvm::Value* key_hash, - llvm::Value* key, llvm::Module& module, - ASR::ttype_t* key_asr_type, ASR::ttype_t* /*value_asr_type*/) { - llvm::Value* key_list = get_key_list(dict); - llvm::Value* value_list = get_value_list(dict); - llvm::Value* key_mask = LLVM::CreateLoad(*builder, get_pointer_to_keymask(dict)); - llvm::Value* capacity = LLVM::CreateLoad(*builder, get_pointer_to_capacity(dict)); - this->resolve_collision(capacity, key_hash, key, key_list, key_mask, module, key_asr_type, true); - llvm::Value* pos = LLVM::CreateLoad(*builder, pos_ptr); - llvm::Value* item = llvm_utils->list_api->read_item(value_list, pos, false, module, true); - return item; - } - - llvm::Value* LLVMDictOptimizedLinearProbing::resolve_collision_for_read( - llvm::Value* dict, llvm::Value* key_hash, - llvm::Value* key, llvm::Module& module, - ASR::ttype_t* key_asr_type, ASR::ttype_t* /*value_asr_type*/) { - llvm::Value* key_list = get_key_list(dict); - llvm::Value* value_list = get_value_list(dict); - llvm::Value* key_mask = LLVM::CreateLoad(*builder, get_pointer_to_keymask(dict)); - llvm::Value* capacity = LLVM::CreateLoad(*builder, get_pointer_to_capacity(dict)); - if( !are_iterators_set ) { - pos_ptr = builder->CreateAlloca(llvm::Type::getInt32Ty(context), nullptr); - } - llvm::Function *fn = builder->GetInsertBlock()->getParent(); - llvm::BasicBlock *thenBB = llvm::BasicBlock::Create(context, "then", fn); - llvm::BasicBlock *elseBB = llvm::BasicBlock::Create(context, "else"); - llvm::BasicBlock *mergeBB = llvm::BasicBlock::Create(context, "ifcont"); - llvm::Value* key_mask_value = LLVM::CreateLoad(*builder, - llvm_utils->create_ptr_gep(key_mask, key_hash)); - llvm::Value* is_prob_not_neeeded = builder->CreateICmpEQ(key_mask_value, - llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), llvm::APInt(8, 1))); - builder->CreateCondBr(is_prob_not_neeeded, thenBB, elseBB); - builder->SetInsertPoint(thenBB); - { - // A single by value comparison is needed even though - // we don't need to do linear probing. This is because - // the user can provide a key which is absent in the dict - // but is giving the same hash value as one of the keys present in the dict. - // In the above case we will end up returning value for a key - // which is not present in the dict. Instead we should return an error - // which is done in the below code. - llvm::Function *fn_single_match = builder->GetInsertBlock()->getParent(); - llvm::BasicBlock *thenBB_single_match = llvm::BasicBlock::Create(context, "then", fn_single_match); - llvm::BasicBlock *elseBB_single_match = llvm::BasicBlock::Create(context, "else"); - llvm::BasicBlock *mergeBB_single_match = llvm::BasicBlock::Create(context, "ifcont"); - llvm::Value* is_key_matching = llvm_utils->is_equal_by_value(key, - llvm_utils->list_api->read_item(key_list, key_hash, false, module, - LLVM::is_llvm_struct(key_asr_type)), module, key_asr_type); - builder->CreateCondBr(is_key_matching, thenBB_single_match, elseBB_single_match); - builder->SetInsertPoint(thenBB_single_match); - LLVM::CreateStore(*builder, key_hash, pos_ptr); - builder->CreateBr(mergeBB_single_match); - llvm_utils->start_new_block(elseBB_single_match); - { - std::string message = "The dict does not contain the specified key"; - llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr("KeyError: %s\n"); - llvm::Value *fmt_ptr2 = builder->CreateGlobalStringPtr(message); - print_error(context, module, *builder, {fmt_ptr, fmt_ptr2}); - int exit_code_int = 1; - llvm::Value *exit_code = llvm::ConstantInt::get(context, - llvm::APInt(32, exit_code_int)); - exit(context, module, *builder, exit_code); - } - llvm_utils->start_new_block(mergeBB_single_match); - } - builder->CreateBr(mergeBB); - llvm_utils->start_new_block(elseBB); - { - this->resolve_collision(capacity, key_hash, key, key_list, key_mask, - module, key_asr_type, true); - } - llvm_utils->start_new_block(mergeBB); - llvm::Value* pos = LLVM::CreateLoad(*builder, pos_ptr); - llvm::Value* item = llvm_utils->list_api->read_item(value_list, pos, - false, module, true); - return item; - } - - llvm::Value* LLVMDictSeparateChaining::resolve_collision_for_read( - llvm::Value* dict, llvm::Value* key_hash, - llvm::Value* key, llvm::Module& module, - ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type) { - llvm::Value* capacity = LLVM::CreateLoad(*builder, get_pointer_to_capacity(dict)); - llvm::Value* key_value_pairs = LLVM::CreateLoad(*builder, get_pointer_to_key_value_pairs(dict)); - llvm::Value* key_value_pair_linked_list = llvm_utils->create_ptr_gep(key_value_pairs, key_hash); - llvm::Value* key_mask = LLVM::CreateLoad(*builder, get_pointer_to_keymask(dict)); - llvm::Type* kv_struct_type = get_key_value_pair_type(key_asr_type, value_asr_type); - this->resolve_collision(capacity, key_hash, key, key_value_pair_linked_list, - kv_struct_type, key_mask, module, key_asr_type); - std::pair llvm_key = std::make_pair( - ASRUtils::get_type_code(key_asr_type), - ASRUtils::get_type_code(value_asr_type) - ); - llvm::Type* value_type = std::get<2>(typecode2dicttype[llvm_key]).second; - llvm::Value* tmp_value_ptr_local = nullptr; - if( !are_iterators_set ) { - tmp_value_ptr = builder->CreateAlloca(value_type, nullptr); - tmp_value_ptr_local = tmp_value_ptr; - } else { - tmp_value_ptr_local = builder->CreateBitCast(tmp_value_ptr, value_type->getPointerTo()); - } - llvm::Function *fn_single_match = builder->GetInsertBlock()->getParent(); - llvm::BasicBlock *thenBB_single_match = llvm::BasicBlock::Create(context, "then", fn_single_match); - llvm::BasicBlock *elseBB_single_match = llvm::BasicBlock::Create(context, "else"); - llvm::BasicBlock *mergeBB_single_match = llvm::BasicBlock::Create(context, "ifcont"); - llvm::Value* key_mask_value = LLVM::CreateLoad(*builder, - llvm_utils->create_ptr_gep(key_mask, key_hash)); - llvm::Value* does_kv_exists = builder->CreateICmpEQ(key_mask_value, - llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), llvm::APInt(8, 1))); - does_kv_exists = builder->CreateAnd(does_kv_exists, - builder->CreateICmpNE(LLVM::CreateLoad(*builder, chain_itr), - llvm::ConstantPointerNull::get(llvm::Type::getInt8PtrTy(context))) - ); - builder->CreateCondBr(does_kv_exists, thenBB_single_match, elseBB_single_match); - builder->SetInsertPoint(thenBB_single_match); - { - llvm::Value* kv_struct_i8 = LLVM::CreateLoad(*builder, chain_itr); - llvm::Value* kv_struct = builder->CreateBitCast(kv_struct_i8, kv_struct_type->getPointerTo()); - llvm::Value* value = LLVM::CreateLoad(*builder, llvm_utils->create_gep(kv_struct, 1)); - LLVM::CreateStore(*builder, value, tmp_value_ptr_local); - - } - builder->CreateBr(mergeBB_single_match); - llvm_utils->start_new_block(elseBB_single_match); - { - std::string message = "The dict does not contain the specified key"; - llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr("KeyError: %s\n"); - llvm::Value *fmt_ptr2 = builder->CreateGlobalStringPtr(message); - print_error(context, module, *builder, {fmt_ptr, fmt_ptr2}); - int exit_code_int = 1; - llvm::Value *exit_code = llvm::ConstantInt::get(context, - llvm::APInt(32, exit_code_int)); - exit(context, module, *builder, exit_code); - } - llvm_utils->start_new_block(mergeBB_single_match); - return tmp_value_ptr; - } - - llvm::Value* LLVMDictInterface::get_key_hash(llvm::Value* capacity, llvm::Value* key, - ASR::ttype_t* key_asr_type, llvm::Module& module) { - // Write specialised hash functions for intrinsic types - // This is to avoid unnecessary calls to C-runtime and do - // as much as possible in LLVM directly. - switch( key_asr_type->type ) { - case ASR::ttypeType::Integer: { - // Simple modulo with the capacity of the dict. - // We can update it later to do a better hash function - // which produces lesser collisions. - - llvm::Value* int_hash = builder->CreateZExtOrTrunc( - builder->CreateURem(key, - builder->CreateZExtOrTrunc(capacity, key->getType())), - capacity->getType() - ); - return int_hash; - } - case ASR::ttypeType::Character: { - // Polynomial rolling hash function for strings - llvm::Value* null_char = llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), - llvm::APInt(8, '\0')); - llvm::Value* p = llvm::ConstantInt::get(llvm::Type::getInt64Ty(context), llvm::APInt(64, 31)); - llvm::Value* m = llvm::ConstantInt::get(llvm::Type::getInt64Ty(context), llvm::APInt(64, 100000009)); - if( !are_iterators_set ) { - hash_value = builder->CreateAlloca(llvm::Type::getInt64Ty(context), nullptr, "hash_value"); - hash_iter = builder->CreateAlloca(llvm::Type::getInt64Ty(context), nullptr, "hash_iter"); - polynomial_powers = builder->CreateAlloca(llvm::Type::getInt64Ty(context), nullptr, "p_pow"); - } - LLVM::CreateStore(*builder, - llvm::ConstantInt::get(llvm::Type::getInt64Ty(context), llvm::APInt(64, 0)), - hash_value); - LLVM::CreateStore(*builder, - llvm::ConstantInt::get(llvm::Type::getInt64Ty(context), llvm::APInt(64, 1)), - polynomial_powers); - LLVM::CreateStore(*builder, - llvm::ConstantInt::get(llvm::Type::getInt64Ty(context), llvm::APInt(64, 0)), - hash_iter); - llvm::BasicBlock *loophead = llvm::BasicBlock::Create(context, "loop.head"); - llvm::BasicBlock *loopbody = llvm::BasicBlock::Create(context, "loop.body"); - llvm::BasicBlock *loopend = llvm::BasicBlock::Create(context, "loop.end"); - - // head - llvm_utils->start_new_block(loophead); - { - llvm::Value* i = LLVM::CreateLoad(*builder, hash_iter); - llvm::Value* c = LLVM::CreateLoad(*builder, llvm_utils->create_ptr_gep(key, i)); - llvm::Value *cond = builder->CreateICmpNE(c, null_char); - builder->CreateCondBr(cond, loopbody, loopend); - } - - // body - llvm_utils->start_new_block(loopbody); - { - // for c in key: - // hash_value = (hash_value + (ord(c) + 1) * p_pow) % m - // p_pow = (p_pow * p) % m - llvm::Value* i = LLVM::CreateLoad(*builder, hash_iter); - llvm::Value* c = LLVM::CreateLoad(*builder, llvm_utils->create_ptr_gep(key, i)); - llvm::Value* p_pow = LLVM::CreateLoad(*builder, polynomial_powers); - llvm::Value* hash = LLVM::CreateLoad(*builder, hash_value); - c = builder->CreateZExt(c, llvm::Type::getInt64Ty(context)); - c = builder->CreateAdd(c, llvm::ConstantInt::get(llvm::Type::getInt64Ty(context), llvm::APInt(64, 1))); - c = builder->CreateMul(c, p_pow); - c = builder->CreateSRem(c, m); - hash = builder->CreateAdd(hash, c); - hash = builder->CreateSRem(hash, m); - LLVM::CreateStore(*builder, hash, hash_value); - p_pow = builder->CreateMul(p_pow, p); - p_pow = builder->CreateSRem(p_pow, m); - LLVM::CreateStore(*builder, p_pow, polynomial_powers); - i = builder->CreateAdd(i, llvm::ConstantInt::get(llvm::Type::getInt64Ty(context), llvm::APInt(64, 1))); - LLVM::CreateStore(*builder, i, hash_iter); - } - - builder->CreateBr(loophead); - - // end - llvm_utils->start_new_block(loopend); - llvm::Value* hash = LLVM::CreateLoad(*builder, hash_value); - hash = builder->CreateTrunc(hash, llvm::Type::getInt32Ty(context)); - return builder->CreateSRem(hash, capacity); - } - case ASR::ttypeType::Tuple: { - llvm::Value* tuple_hash = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), llvm::APInt(32, 0)); - ASR::Tuple_t* asr_tuple = ASR::down_cast(key_asr_type); - for( size_t i = 0; i < asr_tuple->n_type; i++ ) { - llvm::Value* llvm_tuple_i = llvm_utils->tuple_api->read_item(key, i, - LLVM::is_llvm_struct(asr_tuple->m_type[i])); - tuple_hash = builder->CreateAdd(tuple_hash, get_key_hash(capacity, llvm_tuple_i, - asr_tuple->m_type[i], module)); - tuple_hash = builder->CreateSRem(tuple_hash, capacity); - } - return tuple_hash; - } - default: { - throw LCompilersException("Hashing " + ASRUtils::type_to_str_python(key_asr_type) + - " isn't implemented yet."); - } - } - } - - void LLVMDict::rehash(llvm::Value* dict, llvm::Module* module, - ASR::ttype_t* key_asr_type, - ASR::ttype_t* value_asr_type, - std::map>& name2memidx) { - llvm::Value* capacity_ptr = get_pointer_to_capacity(dict); - llvm::Value* old_capacity = LLVM::CreateLoad(*builder, capacity_ptr); - llvm::Value* capacity = builder->CreateMul(old_capacity, llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), - llvm::APInt(32, 2))); - capacity = builder->CreateAdd(capacity, llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), - llvm::APInt(32, 1))); - LLVM::CreateStore(*builder, capacity, capacity_ptr); - - std::string key_type_code = ASRUtils::get_type_code(key_asr_type); - std::string value_type_code = ASRUtils::get_type_code(value_asr_type); - std::pair dict_type_key = std::make_pair(key_type_code, value_type_code); - llvm::Type* key_llvm_type = std::get<2>(typecode2dicttype[dict_type_key]).first; - llvm::Type* value_llvm_type = std::get<2>(typecode2dicttype[dict_type_key]).second; - int32_t key_type_size = std::get<1>(typecode2dicttype[dict_type_key]).first; - int32_t value_type_size = std::get<1>(typecode2dicttype[dict_type_key]).second; - - llvm::Value* key_list = get_key_list(dict); - llvm::Value* new_key_list = builder->CreateAlloca(llvm_utils->list_api->get_list_type(key_llvm_type, - key_type_code, key_type_size), nullptr); - llvm_utils->list_api->list_init(key_type_code, new_key_list, *module, capacity, capacity); - - llvm::Value* value_list = get_value_list(dict); - llvm::Value* new_value_list = builder->CreateAlloca(llvm_utils->list_api->get_list_type(value_llvm_type, - value_type_code, value_type_size), nullptr); - llvm_utils->list_api->list_init(value_type_code, new_value_list, *module, capacity, capacity); - - llvm::Value* key_mask = LLVM::CreateLoad(*builder, get_pointer_to_keymask(dict)); - llvm::DataLayout data_layout(module); - size_t mask_size = data_layout.getTypeAllocSize(llvm::Type::getInt8Ty(context)); - llvm::Value* llvm_mask_size = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), - llvm::APInt(32, mask_size)); - llvm::Value* new_key_mask = LLVM::lfortran_calloc(context, *module, *builder, capacity, - llvm_mask_size); - - llvm::Value* current_capacity = LLVM::CreateLoad(*builder, get_pointer_to_capacity(dict)); - if( !are_iterators_set ) { - idx_ptr = builder->CreateAlloca(llvm::Type::getInt32Ty(context), nullptr); - } - LLVM::CreateStore(*builder, llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), - llvm::APInt(32, 0)), idx_ptr); - - llvm::BasicBlock *loophead = llvm::BasicBlock::Create(context, "loop.head"); - llvm::BasicBlock *loopbody = llvm::BasicBlock::Create(context, "loop.body"); - llvm::BasicBlock *loopend = llvm::BasicBlock::Create(context, "loop.end"); - - // head - llvm_utils->start_new_block(loophead); - { - llvm::Value *cond = builder->CreateICmpSGT(old_capacity, LLVM::CreateLoad(*builder, idx_ptr)); - builder->CreateCondBr(cond, loopbody, loopend); - } - - // body - llvm_utils->start_new_block(loopbody); - { - llvm::Value* idx = LLVM::CreateLoad(*builder, idx_ptr); - llvm::Function *fn = builder->GetInsertBlock()->getParent(); - llvm::BasicBlock *thenBB = llvm::BasicBlock::Create(context, "then", fn); - llvm::BasicBlock *elseBB = llvm::BasicBlock::Create(context, "else"); - llvm::BasicBlock *mergeBB = llvm::BasicBlock::Create(context, "ifcont"); - llvm::Value* is_key_set = LLVM::CreateLoad(*builder, llvm_utils->create_ptr_gep(key_mask, idx)); - is_key_set = builder->CreateICmpNE(is_key_set, - llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), llvm::APInt(8, 0))); - builder->CreateCondBr(is_key_set, thenBB, elseBB); - builder->SetInsertPoint(thenBB); - { - llvm::Value* key = llvm_utils->list_api->read_item(key_list, idx, - false, *module, LLVM::is_llvm_struct(key_asr_type)); - llvm::Value* value = llvm_utils->list_api->read_item(value_list, - idx, false, *module, LLVM::is_llvm_struct(value_asr_type)); - llvm::Value* key_hash = get_key_hash(current_capacity, key, key_asr_type, *module); - this->resolve_collision(current_capacity, key_hash, key, new_key_list, - new_key_mask, *module, key_asr_type); - llvm::Value* pos = LLVM::CreateLoad(*builder, pos_ptr); - llvm::Value* key_dest = llvm_utils->list_api->read_item( - new_key_list, pos, false, *module, true); - llvm_utils->deepcopy(key, key_dest, key_asr_type, module, name2memidx); - llvm::Value* value_dest = llvm_utils->list_api->read_item( - new_value_list, pos, false, *module, true); - llvm_utils->deepcopy(value, value_dest, value_asr_type, module, name2memidx); - - llvm::Value* linear_prob_happened = builder->CreateICmpNE(key_hash, pos); - llvm::Value* set_max_2 = builder->CreateSelect(linear_prob_happened, - llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), llvm::APInt(8, 2)), - llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), llvm::APInt(8, 1))); - LLVM::CreateStore(*builder, set_max_2, llvm_utils->create_ptr_gep(new_key_mask, key_hash)); - LLVM::CreateStore(*builder, set_max_2, llvm_utils->create_ptr_gep(new_key_mask, pos)); - } - builder->CreateBr(mergeBB); - - llvm_utils->start_new_block(elseBB); - llvm_utils->start_new_block(mergeBB); - idx = builder->CreateAdd(idx, llvm::ConstantInt::get( - llvm::Type::getInt32Ty(context), llvm::APInt(32, 1))); - LLVM::CreateStore(*builder, idx, idx_ptr); - } - - builder->CreateBr(loophead); - - // end - llvm_utils->start_new_block(loopend); - - // TODO: Free key_list, value_list and key_mask - llvm_utils->list_api->free_data(key_list, *module); - llvm_utils->list_api->free_data(value_list, *module); - LLVM::lfortran_free(context, *module, *builder, key_mask); - LLVM::CreateStore(*builder, LLVM::CreateLoad(*builder, new_key_list), key_list); - LLVM::CreateStore(*builder, LLVM::CreateLoad(*builder, new_value_list), value_list); - LLVM::CreateStore(*builder, new_key_mask, get_pointer_to_keymask(dict)); - } - - void LLVMDictSeparateChaining::rehash( - llvm::Value* dict, llvm::Module* module, - ASR::ttype_t* key_asr_type, - ASR::ttype_t* value_asr_type, - std::map>& name2memidx) { - if( !are_iterators_set ) { - old_capacity = builder->CreateAlloca(llvm::Type::getInt32Ty(context), nullptr); - old_occupancy = builder->CreateAlloca(llvm::Type::getInt32Ty(context), nullptr); - old_number_of_buckets_filled = builder->CreateAlloca(llvm::Type::getInt32Ty(context), nullptr); - idx_ptr = builder->CreateAlloca(llvm::Type::getInt32Ty(context), nullptr); - old_key_value_pairs = builder->CreateAlloca(llvm::Type::getInt8PtrTy(context), nullptr); - old_key_mask = builder->CreateAlloca(llvm::Type::getInt8PtrTy(context), nullptr); - } - llvm::Value* capacity_ptr = get_pointer_to_capacity(dict); - llvm::Value* occupancy_ptr = get_pointer_to_occupancy(dict); - llvm::Value* number_of_buckets_filled_ptr = get_pointer_to_number_of_filled_buckets(dict); - llvm::Value* old_capacity_value = LLVM::CreateLoad(*builder, capacity_ptr); - LLVM::CreateStore(*builder, old_capacity_value, old_capacity); - LLVM::CreateStore(*builder, - LLVM::CreateLoad(*builder, occupancy_ptr), - old_occupancy - ); - LLVM::CreateStore(*builder, - LLVM::CreateLoad(*builder, number_of_buckets_filled_ptr), - old_number_of_buckets_filled - ); - llvm::Value* old_key_mask_value = LLVM::CreateLoad(*builder, get_pointer_to_keymask(dict)); - llvm::Value* old_key_value_pairs_value = LLVM::CreateLoad(*builder, get_pointer_to_key_value_pairs(dict)); - old_key_value_pairs_value = builder->CreateBitCast(old_key_value_pairs_value, llvm::Type::getInt8PtrTy(context)); - LLVM::CreateStore(*builder, old_key_mask_value, old_key_mask); - LLVM::CreateStore(*builder, old_key_value_pairs_value, old_key_value_pairs); - - llvm::Value* capacity = builder->CreateMul(old_capacity_value, llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), - llvm::APInt(32, 3))); - capacity = builder->CreateAdd(capacity, llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), - llvm::APInt(32, 1))); - dict_init_given_initial_capacity(ASRUtils::get_type_code(key_asr_type), - ASRUtils::get_type_code(value_asr_type), - dict, module, capacity); - llvm::Function *fn = builder->GetInsertBlock()->getParent(); - llvm::BasicBlock *thenBB_rehash = llvm::BasicBlock::Create(context, "then", fn); - llvm::BasicBlock *elseBB_rehash = llvm::BasicBlock::Create(context, "else"); - llvm::BasicBlock *mergeBB_rehash = llvm::BasicBlock::Create(context, "ifcont"); - llvm::Value* rehash_flag = LLVM::CreateLoad(*builder, get_pointer_to_rehash_flag(dict)); - builder->CreateCondBr(rehash_flag, thenBB_rehash, elseBB_rehash); - builder->SetInsertPoint(thenBB_rehash); - old_key_value_pairs_value = LLVM::CreateLoad(*builder, old_key_value_pairs); - old_key_value_pairs_value = builder->CreateBitCast(old_key_value_pairs_value, - get_key_value_pair_type(key_asr_type, value_asr_type)->getPointerTo()); - old_key_mask_value = LLVM::CreateLoad(*builder, old_key_mask); - old_capacity_value = LLVM::CreateLoad(*builder, old_capacity); - capacity = LLVM::CreateLoad(*builder, get_pointer_to_capacity(dict)); - LLVM::CreateStore(*builder, llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), llvm::APInt(32, 0)), idx_ptr); - llvm::BasicBlock *loophead = llvm::BasicBlock::Create(context, "loop.head"); - llvm::BasicBlock *loopbody = llvm::BasicBlock::Create(context, "loop.body"); - llvm::BasicBlock *loopend = llvm::BasicBlock::Create(context, "loop.end"); - - // head - llvm_utils->start_new_block(loophead); - { - llvm::Value *cond = builder->CreateICmpSGT( - old_capacity_value, - LLVM::CreateLoad(*builder, idx_ptr)); - builder->CreateCondBr(cond, loopbody, loopend); - } - - // body - llvm_utils->start_new_block(loopbody); - { - llvm::Value* itr = LLVM::CreateLoad(*builder, idx_ptr); - llvm::Value* key_mask_value = LLVM::CreateLoad(*builder, - llvm_utils->create_ptr_gep(old_key_mask_value, itr)); - llvm::Function *fn = builder->GetInsertBlock()->getParent(); - llvm::BasicBlock *thenBB = llvm::BasicBlock::Create(context, "then", fn); - llvm::BasicBlock *elseBB = llvm::BasicBlock::Create(context, "else"); - llvm::BasicBlock *mergeBB = llvm::BasicBlock::Create(context, "ifcont"); - llvm::Value* is_key_set = builder->CreateICmpEQ(key_mask_value, - llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), llvm::APInt(8, 1))); - builder->CreateCondBr(is_key_set, thenBB, elseBB); - builder->SetInsertPoint(thenBB); - { - - llvm::Value* srci = llvm_utils->create_ptr_gep(old_key_value_pairs_value, itr); - write_key_value_pair_linked_list(srci, dict, capacity, key_asr_type, value_asr_type, module, name2memidx); - } - builder->CreateBr(mergeBB); - llvm_utils->start_new_block(elseBB); - llvm_utils->start_new_block(mergeBB); - llvm::Value* tmp = builder->CreateAdd( - itr, - llvm::ConstantInt::get(context, llvm::APInt(32, 1))); - LLVM::CreateStore(*builder, tmp, idx_ptr); - } - - builder->CreateBr(loophead); - - // end - llvm_utils->start_new_block(loopend); - builder->CreateBr(mergeBB_rehash); - llvm_utils->start_new_block(elseBB_rehash); - { - LLVM::CreateStore(*builder, - LLVM::CreateLoad(*builder, old_capacity), - get_pointer_to_capacity(dict) - ); - LLVM::CreateStore(*builder, - LLVM::CreateLoad(*builder, old_occupancy), - get_pointer_to_occupancy(dict) - ); - LLVM::CreateStore(*builder, - LLVM::CreateLoad(*builder, old_number_of_buckets_filled), - get_pointer_to_number_of_filled_buckets(dict) - ); - LLVM::CreateStore(*builder, - builder->CreateBitCast( - LLVM::CreateLoad(*builder, old_key_value_pairs), - get_key_value_pair_type(key_asr_type, value_asr_type)->getPointerTo() - ), - get_pointer_to_key_value_pairs(dict) - ); - LLVM::CreateStore(*builder, - LLVM::CreateLoad(*builder, old_key_mask), - get_pointer_to_keymask(dict) - ); - } - llvm_utils->start_new_block(mergeBB_rehash); - } - - void LLVMDict::rehash_all_at_once_if_needed(llvm::Value* dict, llvm::Module* module, - ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type, - std::map>& name2memidx) { - llvm::Function *fn = builder->GetInsertBlock()->getParent(); - llvm::BasicBlock *thenBB = llvm::BasicBlock::Create(context, "then", fn); - llvm::BasicBlock *elseBB = llvm::BasicBlock::Create(context, "else"); - llvm::BasicBlock *mergeBB = llvm::BasicBlock::Create(context, "ifcont"); - - llvm::Value* occupancy = LLVM::CreateLoad(*builder, get_pointer_to_occupancy(dict)); - llvm::Value* capacity = LLVM::CreateLoad(*builder, get_pointer_to_capacity(dict)); - llvm::Value* rehash_condition = builder->CreateICmpEQ(capacity, - llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), llvm::APInt(32, 0))); - occupancy = builder->CreateAdd(occupancy, llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), - llvm::APInt(32, 1))); - occupancy = builder->CreateSIToFP(occupancy, llvm::Type::getFloatTy(context)); - capacity = builder->CreateSIToFP(capacity, llvm::Type::getFloatTy(context)); - llvm::Value* load_factor = builder->CreateFDiv(occupancy, capacity); - // Threshold hash is chosen from https://en.wikipedia.org/wiki/Hash_table#Load_factor - llvm::Value* load_factor_threshold = llvm::ConstantFP::get(llvm::Type::getFloatTy(context), - llvm::APFloat((float) 0.6)); - rehash_condition = builder->CreateOr(rehash_condition, builder->CreateFCmpOGE(load_factor, load_factor_threshold)); - builder->CreateCondBr(rehash_condition, thenBB, elseBB); - builder->SetInsertPoint(thenBB); - { - rehash(dict, module, key_asr_type, value_asr_type, name2memidx); - } - builder->CreateBr(mergeBB); - - llvm_utils->start_new_block(elseBB); - llvm_utils->start_new_block(mergeBB); - } - - void LLVMDictSeparateChaining::rehash_all_at_once_if_needed( - llvm::Value* dict, llvm::Module* module, - ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type, - std::map>& name2memidx) { - llvm::Function *fn = builder->GetInsertBlock()->getParent(); - llvm::BasicBlock *thenBB = llvm::BasicBlock::Create(context, "then", fn); - llvm::BasicBlock *elseBB = llvm::BasicBlock::Create(context, "else"); - llvm::BasicBlock *mergeBB = llvm::BasicBlock::Create(context, "ifcont"); - - llvm::Value* occupancy = LLVM::CreateLoad(*builder, get_pointer_to_occupancy(dict)); - llvm::Value* buckets_filled = LLVM::CreateLoad(*builder, get_pointer_to_number_of_filled_buckets(dict)); - llvm::Value* rehash_condition = LLVM::CreateLoad(*builder, get_pointer_to_rehash_flag(dict)); - rehash_condition = builder->CreateAnd(rehash_condition, builder->CreateICmpNE(buckets_filled, - llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), llvm::APInt(32, 0)))); - occupancy = builder->CreateSIToFP(occupancy, llvm::Type::getFloatTy(context)); - buckets_filled = builder->CreateSIToFP(buckets_filled, llvm::Type::getFloatTy(context)); - llvm::Value* avg_ll_length = builder->CreateFDiv(occupancy, buckets_filled); - llvm::Value* avg_ll_length_threshold = llvm::ConstantFP::get(llvm::Type::getFloatTy(context), - llvm::APFloat((float) 2.0)); - rehash_condition = builder->CreateAnd(rehash_condition, - builder->CreateFCmpOGE(avg_ll_length, avg_ll_length_threshold)); - builder->CreateCondBr(rehash_condition, thenBB, elseBB); - builder->SetInsertPoint(thenBB); - { - rehash(dict, module, key_asr_type, value_asr_type, name2memidx); - } - builder->CreateBr(mergeBB); - - llvm_utils->start_new_block(elseBB); - llvm_utils->start_new_block(mergeBB); - } - - void LLVMDict::write_item(llvm::Value* dict, llvm::Value* key, - llvm::Value* value, llvm::Module* module, - ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type, - std::map>& name2memidx) { - rehash_all_at_once_if_needed(dict, module, key_asr_type, value_asr_type, name2memidx); - llvm::Value* current_capacity = LLVM::CreateLoad(*builder, get_pointer_to_capacity(dict)); - llvm::Value* key_hash = get_key_hash(current_capacity, key, key_asr_type, *module); - this->resolve_collision_for_write(dict, key_hash, key, value, module, - key_asr_type, value_asr_type, name2memidx); - } - - void LLVMDictSeparateChaining::write_item(llvm::Value* dict, llvm::Value* key, - llvm::Value* value, llvm::Module* module, - ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type, - std::map>& name2memidx) { - rehash_all_at_once_if_needed(dict, module, key_asr_type, value_asr_type, name2memidx); - llvm::Value* current_capacity = LLVM::CreateLoad(*builder, get_pointer_to_capacity(dict)); - llvm::Value* key_hash = get_key_hash(current_capacity, key, key_asr_type, *module); - this->resolve_collision_for_write(dict, key_hash, key, value, module, - key_asr_type, value_asr_type, name2memidx); - } - - llvm::Value* LLVMDict::read_item(llvm::Value* dict, llvm::Value* key, - llvm::Module& module, ASR::Dict_t* dict_type, - bool get_pointer) { - llvm::Value* current_capacity = LLVM::CreateLoad(*builder, get_pointer_to_capacity(dict)); - llvm::Value* key_hash = get_key_hash(current_capacity, key, dict_type->m_key_type, module); - llvm::Value* value_ptr = this->resolve_collision_for_read(dict, key_hash, key, module, - dict_type->m_key_type, dict_type->m_value_type); - if( get_pointer ) { - return value_ptr; - } - return LLVM::CreateLoad(*builder, value_ptr); - } - - llvm::Value* LLVMDictSeparateChaining::read_item(llvm::Value* dict, llvm::Value* key, - llvm::Module& module, ASR::Dict_t* dict_type, bool get_pointer) { - llvm::Value* current_capacity = LLVM::CreateLoad(*builder, get_pointer_to_capacity(dict)); - llvm::Value* key_hash = get_key_hash(current_capacity, key, dict_type->m_key_type, module); - llvm::Value* value_ptr = this->resolve_collision_for_read(dict, key_hash, key, module, - dict_type->m_key_type, dict_type->m_value_type); - std::pair llvm_key = std::make_pair( - ASRUtils::get_type_code(dict_type->m_key_type), - ASRUtils::get_type_code(dict_type->m_value_type) - ); - llvm::Type* value_type = std::get<2>(typecode2dicttype[llvm_key]).second; - value_ptr = builder->CreateBitCast(value_ptr, value_type->getPointerTo()); - if( get_pointer ) { - return value_ptr; - } - return LLVM::CreateLoad(*builder, value_ptr); - } - - llvm::Value* LLVMDict::pop_item(llvm::Value* dict, llvm::Value* key, - llvm::Module& module, ASR::Dict_t* dict_type, - bool get_pointer) { - llvm::Value* current_capacity = LLVM::CreateLoad(*builder, get_pointer_to_capacity(dict)); - llvm::Value* key_hash = get_key_hash(current_capacity, key, dict_type->m_key_type, module); - llvm::Value* value_ptr = this->resolve_collision_for_read(dict, key_hash, key, module, - dict_type->m_key_type, dict_type->m_value_type); - llvm::Value* pos = LLVM::CreateLoad(*builder, pos_ptr); - llvm::Value* key_mask = LLVM::CreateLoad(*builder, get_pointer_to_keymask(dict)); - llvm::Value* key_mask_i = llvm_utils->create_ptr_gep(key_mask, pos); - llvm::Value* tombstone_marker = llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), llvm::APInt(8, 3)); - LLVM::CreateStore(*builder, tombstone_marker, key_mask_i); - - llvm::Value* occupancy_ptr = get_pointer_to_occupancy(dict); - llvm::Value* occupancy = LLVM::CreateLoad(*builder, occupancy_ptr); - occupancy = builder->CreateSub(occupancy, llvm::ConstantInt::get( - llvm::Type::getInt32Ty(context), llvm::APInt(32, 1))); - LLVM::CreateStore(*builder, occupancy, occupancy_ptr); - - if( get_pointer ) { - std::string key_type_code = ASRUtils::get_type_code(dict_type->m_key_type); - std::string value_type_code = ASRUtils::get_type_code(dict_type->m_value_type); - llvm::Type* llvm_value_type = std::get<2>(typecode2dicttype[std::make_pair( - key_type_code, value_type_code)]).second; - llvm::Value* return_ptr = builder->CreateAlloca(llvm_value_type, nullptr); - LLVM::CreateStore(*builder, LLVM::CreateLoad(*builder, value_ptr), return_ptr); - return return_ptr; - } - - return LLVM::CreateLoad(*builder, value_ptr); - } - - llvm::Value* LLVMDictSeparateChaining::pop_item( - llvm::Value* dict, llvm::Value* key, - llvm::Module& module, ASR::Dict_t* dict_type, - bool get_pointer) { - llvm::Value* current_capacity = LLVM::CreateLoad(*builder, get_pointer_to_capacity(dict)); - llvm::Value* key_hash = get_key_hash(current_capacity, key, dict_type->m_key_type, module); - llvm::Value* value_ptr = this->resolve_collision_for_read(dict, key_hash, key, module, - dict_type->m_key_type, dict_type->m_value_type); - std::pair llvm_key = std::make_pair( - ASRUtils::get_type_code(dict_type->m_key_type), - ASRUtils::get_type_code(dict_type->m_value_type) - ); - llvm::Type* value_type = std::get<2>(typecode2dicttype[llvm_key]).second; - value_ptr = builder->CreateBitCast(value_ptr, value_type->getPointerTo()); - llvm::Value* prev = LLVM::CreateLoad(*builder, chain_itr_prev); - llvm::Value* found = LLVM::CreateLoad(*builder, chain_itr); - - llvm::Function *fn = builder->GetInsertBlock()->getParent(); - llvm::BasicBlock *thenBB = llvm::BasicBlock::Create(context, "then", fn); - llvm::BasicBlock *elseBB = llvm::BasicBlock::Create(context, "else"); - llvm::BasicBlock *mergeBB = llvm::BasicBlock::Create(context, "ifcont"); - - builder->CreateCondBr( - builder->CreateICmpNE(prev, llvm::ConstantPointerNull::get(llvm::Type::getInt8PtrTy(context))), - thenBB, elseBB - ); - builder->SetInsertPoint(thenBB); - { - llvm::Type* kv_struct_type = get_key_value_pair_type(dict_type->m_key_type, dict_type->m_value_type); - found = builder->CreateBitCast(found, kv_struct_type->getPointerTo()); - llvm::Value* found_next = LLVM::CreateLoad(*builder, llvm_utils->create_gep(found, 2)); - prev = builder->CreateBitCast(prev, kv_struct_type->getPointerTo()); - LLVM::CreateStore(*builder, found_next, llvm_utils->create_gep(prev, 2)); - } - builder->CreateBr(mergeBB); - llvm_utils->start_new_block(elseBB); - { - llvm::Value* key_mask = LLVM::CreateLoad(*builder, get_pointer_to_keymask(dict)); - LLVM::CreateStore( - *builder, - llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), llvm::APInt(8, 0)), - llvm_utils->create_ptr_gep(key_mask, key_hash) - ); - llvm::Value* num_buckets_filled_ptr = get_pointer_to_number_of_filled_buckets(dict); - llvm::Value* num_buckets_filled = LLVM::CreateLoad(*builder, num_buckets_filled_ptr); - num_buckets_filled = builder->CreateSub(num_buckets_filled, llvm::ConstantInt::get( - llvm::Type::getInt32Ty(context), llvm::APInt(32, 1))); - LLVM::CreateStore(*builder, num_buckets_filled, num_buckets_filled_ptr); - } - llvm_utils->start_new_block(mergeBB); - - llvm::Value* occupancy_ptr = get_pointer_to_occupancy(dict); - llvm::Value* occupancy = LLVM::CreateLoad(*builder, occupancy_ptr); - occupancy = builder->CreateSub(occupancy, llvm::ConstantInt::get( - llvm::Type::getInt32Ty(context), llvm::APInt(32, 1))); - LLVM::CreateStore(*builder, occupancy, occupancy_ptr); - - if( get_pointer ) { - std::string key_type_code = ASRUtils::get_type_code(dict_type->m_key_type); - std::string value_type_code = ASRUtils::get_type_code(dict_type->m_value_type); - llvm::Type* llvm_value_type = std::get<2>(typecode2dicttype[std::make_pair( - key_type_code, value_type_code)]).second; - llvm::Value* return_ptr = builder->CreateAlloca(llvm_value_type, nullptr); - LLVM::CreateStore(*builder, LLVM::CreateLoad(*builder, value_ptr), return_ptr); - return return_ptr; - } - - return LLVM::CreateLoad(*builder, value_ptr); - } - - llvm::Value* LLVMList::read_item(llvm::Value* list, llvm::Value* pos, - bool enable_bounds_checking, - llvm::Module& module, bool get_pointer) { - if( enable_bounds_checking ) { - check_index_within_bounds(list, pos, module); - } - llvm::Value* list_data = LLVM::CreateLoad(*builder, get_pointer_to_list_data(list)); - llvm::Value* element_ptr = llvm_utils->create_ptr_gep(list_data, pos); - if( get_pointer ) { - return element_ptr; - } - return LLVM::CreateLoad(*builder, element_ptr); - } - - llvm::Value* LLVMList::len(llvm::Value* list) { - return LLVM::CreateLoad(*builder, get_pointer_to_current_end_point(list)); - } - - llvm::Value* LLVMDict::len(llvm::Value* dict) { - return LLVM::CreateLoad(*builder, get_pointer_to_occupancy(dict)); - } - - llvm::Value* LLVMDictSeparateChaining::len(llvm::Value* dict) { - return LLVM::CreateLoad(*builder, get_pointer_to_occupancy(dict)) ; - } - - bool LLVMDictInterface::is_dict_present() { - return is_dict_present_; - } - - void LLVMDictInterface::set_is_dict_present(bool value) { - is_dict_present_ = value; - } - - LLVMDictInterface::~LLVMDictInterface() { - typecode2dicttype.clear(); - } - - LLVMDict::~LLVMDict() { - } - - LLVMDictSeparateChaining::~LLVMDictSeparateChaining() { - } - - LLVMDictOptimizedLinearProbing::~LLVMDictOptimizedLinearProbing() {} - - void LLVMList::resize_if_needed(llvm::Value* list, llvm::Value* n, - llvm::Value* capacity, int32_t type_size, - llvm::Type* el_type, llvm::Module* module) { - llvm::Value *cond = builder->CreateICmpEQ(n, capacity); - llvm::Function *fn = builder->GetInsertBlock()->getParent(); - llvm::BasicBlock *thenBB = llvm::BasicBlock::Create(context, "then", fn); - llvm::BasicBlock *elseBB = llvm::BasicBlock::Create(context, "else"); - llvm::BasicBlock *mergeBB = llvm::BasicBlock::Create(context, "ifcont"); - builder->CreateCondBr(cond, thenBB, elseBB); - builder->SetInsertPoint(thenBB); - llvm::Value* new_capacity = builder->CreateMul(llvm::ConstantInt::get(context, - llvm::APInt(32, 2)), capacity); - new_capacity = builder->CreateAdd(new_capacity, llvm::ConstantInt::get(context, - llvm::APInt(32, 1))); - llvm::Value* arg_size = builder->CreateMul(llvm::ConstantInt::get(context, - llvm::APInt(32, type_size)), - new_capacity); - llvm::Value* copy_data_ptr = get_pointer_to_list_data(list); - llvm::Value* copy_data = LLVM::CreateLoad(*builder, copy_data_ptr); - copy_data = LLVM::lfortran_realloc(context, *module, *builder, - copy_data, arg_size); - copy_data = builder->CreateBitCast(copy_data, el_type->getPointerTo()); - builder->CreateStore(copy_data, copy_data_ptr); - builder->CreateStore(new_capacity, get_pointer_to_current_capacity(list)); - builder->CreateBr(mergeBB); - llvm_utils->start_new_block(elseBB); - llvm_utils->start_new_block(mergeBB); - } - - void LLVMList::shift_end_point_by_one(llvm::Value* list) { - llvm::Value* end_point_ptr = get_pointer_to_current_end_point(list); - llvm::Value* end_point = LLVM::CreateLoad(*builder, end_point_ptr); - end_point = builder->CreateAdd(end_point, llvm::ConstantInt::get(context, llvm::APInt(32, 1))); - builder->CreateStore(end_point, end_point_ptr); - } - - void LLVMList::append(llvm::Value* list, llvm::Value* item, - ASR::ttype_t* asr_type, llvm::Module* module, - std::map>& name2memidx) { - llvm::Value* current_end_point = LLVM::CreateLoad(*builder, get_pointer_to_current_end_point(list)); - llvm::Value* current_capacity = LLVM::CreateLoad(*builder, get_pointer_to_current_capacity(list)); - std::string type_code = ASRUtils::get_type_code(asr_type); - int type_size = std::get<1>(typecode2listtype[type_code]); - llvm::Type* el_type = std::get<2>(typecode2listtype[type_code]); - resize_if_needed(list, current_end_point, current_capacity, - type_size, el_type, module); - write_item(list, current_end_point, item, asr_type, false, module, name2memidx); - shift_end_point_by_one(list); - } - - void LLVMList::insert_item(llvm::Value* list, llvm::Value* pos, - llvm::Value* item, ASR::ttype_t* asr_type, - llvm::Module* module, - std::map>& name2memidx) { - std::string type_code = ASRUtils::get_type_code(asr_type); - llvm::Value* current_end_point = LLVM::CreateLoad(*builder, - get_pointer_to_current_end_point(list)); - llvm::Value* current_capacity = LLVM::CreateLoad(*builder, - get_pointer_to_current_capacity(list)); - int type_size = std::get<1>(typecode2listtype[type_code]); - llvm::Type* el_type = std::get<2>(typecode2listtype[type_code]); - resize_if_needed(list, current_end_point, current_capacity, - type_size, el_type, module); - - /* While loop equivalent in C++: - * end_point // nth index of list - * pos // ith index to insert the element - * pos_ptr = pos; - * tmp_ptr = list[pos]; - * tmp = 0; - * - * while(end_point > pos_ptr) { - * tmp = list[pos + 1]; - * list[pos + 1] = tmp_ptr; - * tmp_ptr = tmp; - * pos_ptr++; - * } - * - * list[pos] = item; - */ - - // TODO: Should be created outside the user loop and not here. - // LLVMList should treat them as data members and create them - // only if they are NULL - llvm::AllocaInst *tmp_ptr = builder->CreateAlloca(el_type, nullptr); - LLVM::CreateStore(*builder, read_item(list, pos, false, *module, false), tmp_ptr); - llvm::Value* tmp = nullptr; - - // TODO: Should be created outside the user loop and not here. - // LLVMList should treat them as data members and create them - // only if they are NULL - llvm::AllocaInst *pos_ptr = builder->CreateAlloca( - llvm::Type::getInt32Ty(context), nullptr); - LLVM::CreateStore(*builder, pos, pos_ptr); - - llvm::BasicBlock *loophead = llvm::BasicBlock::Create(context, "loop.head"); - llvm::BasicBlock *loopbody = llvm::BasicBlock::Create(context, "loop.body"); - llvm::BasicBlock *loopend = llvm::BasicBlock::Create(context, "loop.end"); - - // head - llvm_utils->start_new_block(loophead); - { - llvm::Value *cond = builder->CreateICmpSGT( - current_end_point, - LLVM::CreateLoad(*builder, pos_ptr)); - builder->CreateCondBr(cond, loopbody, loopend); - } - - // body - llvm_utils->start_new_block(loopbody); - { - llvm::Value* next_index = builder->CreateAdd( - LLVM::CreateLoad(*builder, pos_ptr), - llvm::ConstantInt::get(context, llvm::APInt(32, 1))); - tmp = read_item(list, next_index, false, *module, false); - write_item(list, next_index, LLVM::CreateLoad(*builder, tmp_ptr), false, *module); - LLVM::CreateStore(*builder, tmp, tmp_ptr); - - tmp = builder->CreateAdd( - LLVM::CreateLoad(*builder, pos_ptr), - llvm::ConstantInt::get(context, llvm::APInt(32, 1))); - LLVM::CreateStore(*builder, tmp, pos_ptr); - } - builder->CreateBr(loophead); - - // end - llvm_utils->start_new_block(loopend); - - write_item(list, pos, item, asr_type, false, module, name2memidx); - shift_end_point_by_one(list); - } - - llvm::Value* LLVMList::find_item_position(llvm::Value* list, - llvm::Value* item, ASR::ttype_t* item_type, llvm::Module& module) { - llvm::Type* pos_type = llvm::Type::getInt32Ty(context); - llvm::Value* current_end_point = LLVM::CreateLoad(*builder, - get_pointer_to_current_end_point(list)); - // TODO: Should be created outside the user loop and not here. - // LLVMList should treat them as data members and create them - // only if they are NULL - llvm::AllocaInst *i = builder->CreateAlloca(pos_type, nullptr); - LLVM::CreateStore(*builder, llvm::ConstantInt::get( - context, llvm::APInt(32, 0)), i); - llvm::Value* tmp = nullptr; - - /* Equivalent in C++: - * int i = 0; - * while(list[i] != item && end_point > i) { - * i++; - * } - * - * if (i == end_point) { - * std::cout << "The list does not contain the element"; - * } - */ - - llvm::BasicBlock *loophead = llvm::BasicBlock::Create(context, "loop.head"); - llvm::BasicBlock *loopbody = llvm::BasicBlock::Create(context, "loop.body"); - llvm::BasicBlock *loopend = llvm::BasicBlock::Create(context, "loop.end"); - - // head - llvm_utils->start_new_block(loophead); - { - llvm::Value* left_arg = read_item(list, LLVM::CreateLoad(*builder, i), - false, module, LLVM::is_llvm_struct(item_type)); - llvm::Value* is_item_not_equal = builder->CreateNot( - llvm_utils->is_equal_by_value( - left_arg, item, - module, item_type) - ); - llvm::Value *cond = builder->CreateAnd(is_item_not_equal, - builder->CreateICmpSGT(current_end_point, - LLVM::CreateLoad(*builder, i))); - builder->CreateCondBr(cond, loopbody, loopend); - } - - // body - llvm_utils->start_new_block(loopbody); - { - tmp = builder->CreateAdd( - LLVM::CreateLoad(*builder, i), - llvm::ConstantInt::get(context, llvm::APInt(32, 1))); - LLVM::CreateStore(*builder, tmp, i); - } - builder->CreateBr(loophead); - - // end - llvm_utils->start_new_block(loopend); - - - llvm::Function *fn = builder->GetInsertBlock()->getParent(); - llvm::BasicBlock *thenBB = llvm::BasicBlock::Create(context, "then", fn); - llvm::BasicBlock *elseBB = llvm::BasicBlock::Create(context, "else"); - llvm::BasicBlock *mergeBB = llvm::BasicBlock::Create(context, "ifcont"); - - llvm::Value* cond = builder->CreateICmpEQ( - LLVM::CreateLoad(*builder, i), current_end_point); - builder->CreateCondBr(cond, thenBB, elseBB); - builder->SetInsertPoint(thenBB); - { - std::string message = "The list does not contain the element: "; - llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr("ValueError: %s%d\n"); - llvm::Value *fmt_ptr2 = builder->CreateGlobalStringPtr(message); - print_error(context, module, *builder, {fmt_ptr, fmt_ptr2, item}); - int exit_code_int = 1; - llvm::Value *exit_code = llvm::ConstantInt::get(context, - llvm::APInt(32, exit_code_int)); - exit(context, module, *builder, exit_code); - } - builder->CreateBr(mergeBB); - - llvm_utils->start_new_block(elseBB); - llvm_utils->start_new_block(mergeBB); - - return LLVM::CreateLoad(*builder, i); - } - - void LLVMList::remove(llvm::Value* list, llvm::Value* item, - ASR::ttype_t* item_type, llvm::Module& module) { - llvm::Type* pos_type = llvm::Type::getInt32Ty(context); - llvm::Value* current_end_point = LLVM::CreateLoad(*builder, - get_pointer_to_current_end_point(list)); - // TODO: Should be created outside the user loop and not here. - // LLVMList should treat them as data members and create them - // only if they are NULL - llvm::AllocaInst *item_pos = builder->CreateAlloca(pos_type, nullptr); - llvm::Value* tmp = LLVMList::find_item_position(list, item, item_type, module); - LLVM::CreateStore(*builder, tmp, item_pos); - - /* While loop equivalent in C++: - * item_pos = find_item_position(); - * while(end_point > item_pos) { - * tmp = item_pos + 1; - * list[item_pos] = list[tmp]; - * item_pos = tmp; - * } - */ - - llvm::BasicBlock *loophead = llvm::BasicBlock::Create(context, "loop.head"); - llvm::BasicBlock *loopbody = llvm::BasicBlock::Create(context, "loop.body"); - llvm::BasicBlock *loopend = llvm::BasicBlock::Create(context, "loop.end"); - - // head - llvm_utils->start_new_block(loophead); - { - llvm::Value *cond = builder->CreateICmpSGT(current_end_point, - LLVM::CreateLoad(*builder, item_pos)); - builder->CreateCondBr(cond, loopbody, loopend); - } - - // body - llvm_utils->start_new_block(loopbody); - { - tmp = builder->CreateAdd( - LLVM::CreateLoad(*builder, item_pos), - llvm::ConstantInt::get(context, llvm::APInt(32, 1))); - write_item(list, LLVM::CreateLoad(*builder, item_pos), - read_item(list, tmp, false, module, false), false, module); - LLVM::CreateStore(*builder, tmp, item_pos); - } - builder->CreateBr(loophead); - - // end - llvm_utils->start_new_block(loopend); - - // Decrement end point by one - llvm::Value* end_point_ptr = get_pointer_to_current_end_point(list); - llvm::Value* end_point = LLVM::CreateLoad(*builder, end_point_ptr); - end_point = builder->CreateSub(end_point, llvm::ConstantInt::get( - context, llvm::APInt(32, 1))); - builder->CreateStore(end_point, end_point_ptr); - } - - void LLVMList::list_clear(llvm::Value* list) { - llvm::Value* end_point_ptr = get_pointer_to_current_end_point(list); - llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), - llvm::APInt(32, 0)); - LLVM::CreateStore(*builder, zero, end_point_ptr); - } - - void LLVMList::free_data(llvm::Value* list, llvm::Module& module) { - llvm::Value* data = LLVM::CreateLoad(*builder, get_pointer_to_list_data(list)); - LLVM::lfortran_free(context, module, *builder, data); - } - - llvm::Value* LLVMList::check_list_equality(llvm::Value* l1, llvm::Value* l2, - ASR::ttype_t* item_type, - llvm::LLVMContext& context, - llvm::IRBuilder<>* builder, - llvm::Module& module) { - llvm::AllocaInst *is_equal = builder->CreateAlloca(llvm::Type::getInt1Ty(context), nullptr); - LLVM::CreateStore(*builder, llvm::ConstantInt::get(context, llvm::APInt(1, 1)), is_equal); - llvm::Value *a_len = llvm_utils->list_api->len(l1); - llvm::Value *b_len = llvm_utils->list_api->len(l2); - llvm::Value *cond = builder->CreateICmpEQ(a_len, b_len); - llvm::Function *fn = builder->GetInsertBlock()->getParent(); - llvm::BasicBlock *thenBB = llvm::BasicBlock::Create(context, "then", fn); - llvm::BasicBlock *elseBB = llvm::BasicBlock::Create(context, "else"); - llvm::BasicBlock *mergeBB = llvm::BasicBlock::Create(context, "ifcont"); - builder->CreateCondBr(cond, thenBB, elseBB); - builder->SetInsertPoint(thenBB); - llvm::AllocaInst *idx = builder->CreateAlloca(llvm::Type::getInt32Ty(context), nullptr); - LLVM::CreateStore(*builder, llvm::ConstantInt::get( - context, llvm::APInt(32, 0)), idx); - llvm::BasicBlock *loophead = llvm::BasicBlock::Create(context, "loop.head"); - llvm::BasicBlock *loopbody = llvm::BasicBlock::Create(context, "loop.body"); - llvm::BasicBlock *loopend = llvm::BasicBlock::Create(context, "loop.end"); - - // head - llvm_utils->start_new_block(loophead); - { - llvm::Value* i = LLVM::CreateLoad(*builder, idx); - llvm::Value* cnd = builder->CreateICmpSLT(i, a_len); - builder->CreateCondBr(cnd, loopbody, loopend); - } - - // body - llvm_utils->start_new_block(loopbody); - { - llvm::Value* i = LLVM::CreateLoad(*builder, idx); - llvm::Value* left_arg = llvm_utils->list_api->read_item(l1, i, - false, module, LLVM::is_llvm_struct(item_type)); - llvm::Value* right_arg = llvm_utils->list_api->read_item(l2, i, - false, module, LLVM::is_llvm_struct(item_type)); - llvm::Value* res = llvm_utils->is_equal_by_value(left_arg, right_arg, module, - item_type); - res = builder->CreateAnd(LLVM::CreateLoad(*builder, is_equal), res); - LLVM::CreateStore(*builder, res, is_equal); - i = builder->CreateAdd(i, llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), - llvm::APInt(32, 1))); - LLVM::CreateStore(*builder, i, idx); - } - - builder->CreateBr(loophead); - - // end - llvm_utils->start_new_block(loopend); - - builder->CreateBr(mergeBB); - llvm_utils->start_new_block(elseBB); - LLVM::CreateStore(*builder, llvm::ConstantInt::get(context, llvm::APInt(1, 0)), is_equal); - llvm_utils->start_new_block(mergeBB); - return LLVM::CreateLoad(*builder, is_equal); - } - - LLVMTuple::LLVMTuple(llvm::LLVMContext& context_, - LLVMUtils* llvm_utils_, - llvm::IRBuilder<>* builder_) : - context(context_), llvm_utils(llvm_utils_), builder(builder_) {} - - llvm::Type* LLVMTuple::get_tuple_type(std::string& type_code, - std::vector& el_types) { - if( typecode2tupletype.find(type_code) != typecode2tupletype.end() ) { - return typecode2tupletype[type_code].first; - } - - llvm::Type* llvm_tuple_type = llvm::StructType::create(context, el_types, "tuple"); - typecode2tupletype[type_code] = std::make_pair(llvm_tuple_type, el_types.size()); - return llvm_tuple_type; - } - - llvm::Value* LLVMTuple::read_item(llvm::Value* llvm_tuple, llvm::Value* pos, - bool get_pointer) { - llvm::Value* item = llvm_utils->create_gep(llvm_tuple, pos); - if( get_pointer ) { - return item; - } - return LLVM::CreateLoad(*builder, item); - } - - llvm::Value* LLVMTuple::read_item(llvm::Value* llvm_tuple, size_t pos, - bool get_pointer) { - llvm::Value* llvm_pos = llvm::ConstantInt::get(context, llvm::APInt(32, pos)); - return read_item(llvm_tuple, llvm_pos, get_pointer); - } - - void LLVMTuple::tuple_init(llvm::Value* llvm_tuple, - std::vector& values) { - for( size_t i = 0; i < values.size(); i++ ) { - llvm::Value* item_ptr = read_item(llvm_tuple, i, true); - builder->CreateStore(values[i], item_ptr); - } - } - - void LLVMTuple::tuple_deepcopy(llvm::Value* src, llvm::Value* dest, - ASR::Tuple_t* tuple_type, llvm::Module* module, - std::map>& name2memidx) { - LCOMPILERS_ASSERT(src->getType() == dest->getType()); - for( size_t i = 0; i < tuple_type->n_type; i++ ) { - llvm::Value* src_item = read_item(src, i, LLVM::is_llvm_struct( - tuple_type->m_type[i])); - llvm::Value* dest_item_ptr = read_item(dest, i, true); - llvm_utils->deepcopy(src_item, dest_item_ptr, - tuple_type->m_type[i], module, - name2memidx); - } - } - - llvm::Value* LLVMTuple::check_tuple_equality(llvm::Value* t1, llvm::Value* t2, - ASR::Tuple_t* tuple_type, - llvm::LLVMContext& context, - llvm::IRBuilder<>* builder, - llvm::Module& module) { - llvm::Value* is_equal = llvm::ConstantInt::get(context, llvm::APInt(1, 1)); - for( size_t i = 0; i < tuple_type->n_type; i++ ) { - llvm::Value* t1i = llvm_utils->tuple_api->read_item(t1, i, LLVM::is_llvm_struct( - tuple_type->m_type[i])); - llvm::Value* t2i = llvm_utils->tuple_api->read_item(t2, i, LLVM::is_llvm_struct( - tuple_type->m_type[i])); - llvm::Value* is_t1_eq_t2 = llvm_utils->is_equal_by_value(t1i, t2i, module, - tuple_type->m_type[i]); - is_equal = builder->CreateAnd(is_equal, is_t1_eq_t2); - } - return is_equal; - } - -} // namespace LCompilers diff --git a/src/libasr/codegen/llvm_utils.h b/src/libasr/codegen/llvm_utils.h deleted file mode 100644 index 5a35bac52f..0000000000 --- a/src/libasr/codegen/llvm_utils.h +++ /dev/null @@ -1,597 +0,0 @@ -#ifndef LFORTRAN_LLVM_UTILS_H -#define LFORTRAN_LLVM_UTILS_H - -#include - -#include -#include -#include - -#include -#include - -namespace LCompilers { - - namespace LLVMArrUtils { - class Descriptor; - } - - static inline void printf(llvm::LLVMContext &context, llvm::Module &module, - llvm::IRBuilder<> &builder, const std::vector &args) - { - llvm::Function *fn_printf = module.getFunction("_lfortran_printf"); - if (!fn_printf) { - llvm::FunctionType *function_type = llvm::FunctionType::get( - llvm::Type::getVoidTy(context), {llvm::Type::getInt8PtrTy(context)}, true); - fn_printf = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, "_lfortran_printf", &module); - } - builder.CreateCall(fn_printf, args); - } - - static inline void print_error(llvm::LLVMContext &context, llvm::Module &module, - llvm::IRBuilder<> &builder, const std::vector &args) - { - llvm::Function *fn_printf = module.getFunction("_lcompilers_print_error"); - if (!fn_printf) { - llvm::FunctionType *function_type = llvm::FunctionType::get( - llvm::Type::getVoidTy(context), {llvm::Type::getInt8PtrTy(context)}, true); - fn_printf = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, "_lcompilers_print_error", &module); - } - builder.CreateCall(fn_printf, args); - } - - static inline void exit(llvm::LLVMContext &context, llvm::Module &module, - llvm::IRBuilder<> &builder, llvm::Value* exit_code) - { - llvm::Function *fn_exit = module.getFunction("exit"); - if (!fn_exit) { - llvm::FunctionType *function_type = llvm::FunctionType::get( - llvm::Type::getVoidTy(context), {llvm::Type::getInt32Ty(context)}, - false); - fn_exit = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, "exit", &module); - } - builder.CreateCall(fn_exit, {exit_code}); - } - - // Insert the following anywhere inside the LLVM backend to print - // addresses at runtime: - // call_print_stacktrace_addresses(context, *module, *builder, {filename, use_colors}); - static inline void call_print_stacktrace_addresses(llvm::LLVMContext &context, - llvm::Module &module, llvm::IRBuilder<> &builder, - const std::vector &args) - { - llvm::Function *fn = module.getFunction("print_stacktrace_addresses"); - if (!fn) { - llvm::FunctionType *function_type = llvm::FunctionType::get( - llvm::Type::getVoidTy(context), { - llvm::Type::getInt8PtrTy(context), - llvm::Type::getInt1Ty(context) - }, true); - fn = llvm::Function::Create(function_type, - llvm::Function::ExternalLinkage, "print_stacktrace_addresses", - &module); - } - builder.CreateCall(fn, args); - } - - namespace LLVM { - - llvm::Value* CreateLoad(llvm::IRBuilder<> &builder, llvm::Value *x); - llvm::Value* CreateStore(llvm::IRBuilder<> &builder, llvm::Value *x, llvm::Value *y); - llvm::Value* CreateGEP(llvm::IRBuilder<> &builder, llvm::Value *x, std::vector &idx); - llvm::Value* CreateInBoundsGEP(llvm::IRBuilder<> &builder, llvm::Value *x, std::vector &idx); - llvm::Value* lfortran_malloc(llvm::LLVMContext &context, llvm::Module &module, - llvm::IRBuilder<> &builder, llvm::Value* arg_size); - llvm::Value* lfortran_realloc(llvm::LLVMContext &context, llvm::Module &module, - llvm::IRBuilder<> &builder, llvm::Value* ptr, llvm::Value* arg_size); - llvm::Value* lfortran_calloc(llvm::LLVMContext &context, llvm::Module &module, - llvm::IRBuilder<> &builder, llvm::Value* count, llvm::Value* type_size); - llvm::Value* lfortran_free(llvm::LLVMContext &context, llvm::Module &module, - llvm::IRBuilder<> &builder, llvm::Value* ptr); - static inline bool is_llvm_struct(ASR::ttype_t* asr_type) { - return ASR::is_a(*asr_type) || - ASR::is_a(*asr_type) || - ASR::is_a(*asr_type) || - ASR::is_a(*asr_type); - } - } - - class LLVMList; - class LLVMTuple; - class LLVMDictInterface; - - class LLVMUtils { - - private: - - llvm::LLVMContext& context; - llvm::IRBuilder<>* builder; - llvm::AllocaInst *str_cmp_itr; - - bool are_iterators_set; - - public: - - LLVMTuple* tuple_api; - LLVMList* list_api; - LLVMDictInterface* dict_api; - LLVMArrUtils::Descriptor* arr_api; - - LLVMUtils(llvm::LLVMContext& context, - llvm::IRBuilder<>* _builder); - - llvm::Value* create_gep(llvm::Value* ds, int idx); - - llvm::Value* create_gep(llvm::Value* ds, llvm::Value* idx); - - llvm::Value* create_ptr_gep(llvm::Value* ptr, int idx); - - llvm::Value* create_ptr_gep(llvm::Value* ptr, llvm::Value* idx); - - llvm::Type* getIntType(int a_kind, bool get_pointer=false); - - void start_new_block(llvm::BasicBlock *bb); - - llvm::Value* lfortran_str_cmp(llvm::Value* left_arg, llvm::Value* right_arg, - std::string runtime_func_name, llvm::Module& module); - - llvm::Value* is_equal_by_value(llvm::Value* left, llvm::Value* right, - llvm::Module& module, ASR::ttype_t* asr_type); - - void set_iterators(); - - void reset_iterators(); - - void deepcopy(llvm::Value* src, llvm::Value* dest, - ASR::ttype_t* asr_type, llvm::Module* module, - std::map>& name2memidx); - - }; // LLVMUtils - - class LLVMList { - private: - - llvm::LLVMContext& context; - LLVMUtils* llvm_utils; - llvm::IRBuilder<>* builder; - - std::map> typecode2listtype; - - void resize_if_needed(llvm::Value* list, llvm::Value* n, - llvm::Value* capacity, int32_t type_size, - llvm::Type* el_type, llvm::Module* module); - - void shift_end_point_by_one(llvm::Value* list); - - public: - - LLVMList(llvm::LLVMContext& context_, LLVMUtils* llvm_utils, - llvm::IRBuilder<>* builder); - - llvm::Type* get_list_type(llvm::Type* el_type, std::string& type_code, - int32_t type_size); - - void list_init(std::string& type_code, llvm::Value* list, - llvm::Module& module, llvm::Value* initial_capacity, - llvm::Value* n); - - void list_init(std::string& type_code, llvm::Value* list, - llvm::Module& module, int32_t initial_capacity=1, - int32_t n=0); - - llvm::Value* get_pointer_to_list_data(llvm::Value* list); - - llvm::Value* get_pointer_to_current_end_point(llvm::Value* list); - - llvm::Value* get_pointer_to_current_capacity(llvm::Value* list); - - void list_deepcopy(llvm::Value* src, llvm::Value* dest, - ASR::List_t* list_type, llvm::Module* module, - std::map>& name2memidx); - - void list_deepcopy(llvm::Value* src, llvm::Value* dest, - ASR::ttype_t* element_type, llvm::Module* module, - std::map>& name2memidx); - - llvm::Value* read_item(llvm::Value* list, llvm::Value* pos, - bool enable_bounds_checking, - llvm::Module& module, bool get_pointer=false); - - llvm::Value* len(llvm::Value* list); - - void check_index_within_bounds(llvm::Value* list, llvm::Value* pos, - llvm::Module& module); - - void write_item(llvm::Value* list, llvm::Value* pos, - llvm::Value* item, ASR::ttype_t* asr_type, - bool enable_bounds_checking, llvm::Module* module, - std::map>& name2memidx); - - void write_item(llvm::Value* list, llvm::Value* pos, - llvm::Value* item, bool enable_bounds_checking, - llvm::Module& module); - - void append(llvm::Value* list, llvm::Value* item, - ASR::ttype_t* asr_type, llvm::Module* module, - std::map>& name2memidx); - - void insert_item(llvm::Value* list, llvm::Value* pos, - llvm::Value* item, ASR::ttype_t* asr_type, - llvm::Module* module, - std::map>& name2memidx); - - void remove(llvm::Value* list, llvm::Value* item, - ASR::ttype_t* item_type, llvm::Module& module); - - void list_clear(llvm::Value* list); - - llvm::Value* find_item_position(llvm::Value* list, - llvm::Value* item, ASR::ttype_t* item_type, - llvm::Module& module); - - void free_data(llvm::Value* list, llvm::Module& module); - - llvm::Value* check_list_equality(llvm::Value* l1, llvm::Value* l2, ASR::ttype_t *item_type, - llvm::LLVMContext& context, llvm::IRBuilder<>* builder, llvm::Module& module); - }; - - class LLVMTuple { - private: - - llvm::LLVMContext& context; - LLVMUtils* llvm_utils; - llvm::IRBuilder<>* builder; - - std::map> typecode2tupletype; - - public: - - LLVMTuple(llvm::LLVMContext& context_, - LLVMUtils* llvm_utils, - llvm::IRBuilder<>* builder); - - llvm::Type* get_tuple_type(std::string& type_code, - std::vector& el_types); - - void tuple_init(llvm::Value* llvm_tuple, std::vector& values); - - llvm::Value* read_item(llvm::Value* llvm_tuple, llvm::Value* pos, - bool get_pointer=false); - - llvm::Value* read_item(llvm::Value* llvm_tuple, size_t pos, - bool get_pointer=false); - - void tuple_deepcopy(llvm::Value* src, llvm::Value* dest, - ASR::Tuple_t* type_code, llvm::Module* module, - std::map>& name2memidx); - - llvm::Value* check_tuple_equality(llvm::Value* t1, llvm::Value* t2, - ASR::Tuple_t* tuple_type, llvm::LLVMContext& context, - llvm::IRBuilder<>* builder, llvm::Module& module); - }; - - class LLVMDictInterface { - - protected: - - llvm::LLVMContext& context; - LLVMUtils* llvm_utils; - llvm::IRBuilder<>* builder; - llvm::AllocaInst *pos_ptr, *is_key_matching_var; - llvm::AllocaInst *idx_ptr, *hash_iter, *hash_value; - llvm::AllocaInst *polynomial_powers; - llvm::AllocaInst *chain_itr, *chain_itr_prev; - llvm::AllocaInst *old_capacity, *old_key_value_pairs, *old_key_mask; - llvm::AllocaInst *old_occupancy, *old_number_of_buckets_filled; - llvm::AllocaInst *src_itr, *dest_itr, *next_ptr, *copy_itr; - llvm::Value *tmp_value_ptr; - bool are_iterators_set; - - std::map, - std::tuple, - std::pair>> typecode2dicttype; - - public: - - bool is_dict_present_; - - LLVMDictInterface( - llvm::LLVMContext& context_, - LLVMUtils* llvm_utils, - llvm::IRBuilder<>* builder); - - virtual - llvm::Type* get_dict_type(std::string key_type_code, std::string value_type_code, - int32_t key_type_size, int32_t value_type_size, - llvm::Type* key_type, llvm::Type* value_type) = 0; - - virtual - void dict_init(std::string key_type_code, std::string value_type_code, - llvm::Value* dict, llvm::Module* module, size_t initial_capacity) = 0; - - virtual - llvm::Value* get_key_list(llvm::Value* dict) = 0; - - virtual - llvm::Value* get_value_list(llvm::Value* dict) = 0; - - virtual - llvm::Value* get_pointer_to_occupancy(llvm::Value* dict) = 0; - - virtual - llvm::Value* get_pointer_to_capacity(llvm::Value* dict) = 0; - - virtual - llvm::Value* get_key_hash(llvm::Value* capacity, llvm::Value* key, - ASR::ttype_t* key_asr_type, llvm::Module& module); - - virtual - void resolve_collision_for_write(llvm::Value* dict, llvm::Value* key_hash, - llvm::Value* key, llvm::Value* value, - llvm::Module* module, ASR::ttype_t* key_asr_type, - ASR::ttype_t* value_asr_type, - std::map>& name2memidx) = 0; - - virtual - llvm::Value* resolve_collision_for_read(llvm::Value* dict, llvm::Value* key_hash, - llvm::Value* key, llvm::Module& module, - ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type) = 0; - - virtual - void rehash(llvm::Value* dict, llvm::Module* module, - ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type, - std::map>& name2memidx) = 0; - - virtual - void rehash_all_at_once_if_needed(llvm::Value* dict, - llvm::Module* module, - ASR::ttype_t* key_asr_type, - ASR::ttype_t* value_asr_type, - std::map>& name2memidx) = 0; - - virtual - void write_item(llvm::Value* dict, llvm::Value* key, - llvm::Value* value, llvm::Module* module, - ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type, - std::map>& name2memidx) = 0; - - virtual - llvm::Value* read_item(llvm::Value* dict, llvm::Value* key, - llvm::Module& module, ASR::Dict_t* dict_type, - bool get_pointer=false) = 0; - - virtual - llvm::Value* pop_item(llvm::Value* dict, llvm::Value* key, - llvm::Module& module, ASR::Dict_t* dict_type, - bool get_pointer=false) = 0; - - virtual - void set_iterators(); - - virtual - void reset_iterators(); - - virtual - void dict_deepcopy(llvm::Value* src, llvm::Value* dest, - ASR::Dict_t* dict_type, llvm::Module* module, - std::map>& name2memidx) = 0; - - virtual - llvm::Value* len(llvm::Value* dict) = 0; - - virtual - bool is_dict_present(); - - virtual - void set_is_dict_present(bool value); - - virtual ~LLVMDictInterface() = 0; - - }; - - class LLVMDict: public LLVMDictInterface { - - public: - - LLVMDict(llvm::LLVMContext& context_, - LLVMUtils* llvm_utils, - llvm::IRBuilder<>* builder); - - llvm::Type* get_dict_type(std::string key_type_code, std::string value_type_code, - int32_t key_type_size, int32_t value_type_size, - llvm::Type* key_type, llvm::Type* value_type); - - void dict_init(std::string key_type_code, std::string value_type_code, - llvm::Value* dict, llvm::Module* module, size_t initial_capacity); - - llvm::Value* get_key_list(llvm::Value* dict); - - llvm::Value* get_value_list(llvm::Value* dict); - - llvm::Value* get_pointer_to_occupancy(llvm::Value* dict); - - llvm::Value* get_pointer_to_capacity(llvm::Value* dict); - - virtual - void resolve_collision(llvm::Value* capacity, llvm::Value* key_hash, - llvm::Value* key, llvm::Value* key_list, - llvm::Value* key_mask, llvm::Module& module, - ASR::ttype_t* key_asr_type, bool for_read=false); - - void resolve_collision_for_write(llvm::Value* dict, llvm::Value* key_hash, - llvm::Value* key, llvm::Value* value, - llvm::Module* module, ASR::ttype_t* key_asr_type, - ASR::ttype_t* value_asr_type, - std::map>& name2memidx); - - llvm::Value* resolve_collision_for_read(llvm::Value* dict, llvm::Value* key_hash, - llvm::Value* key, llvm::Module& module, - ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type); - - void rehash(llvm::Value* dict, llvm::Module* module, - ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type, - std::map>& name2memidx); - - void rehash_all_at_once_if_needed(llvm::Value* dict, - llvm::Module* module, - ASR::ttype_t* key_asr_type, - ASR::ttype_t* value_asr_type, - std::map>& name2memidx); - - void write_item(llvm::Value* dict, llvm::Value* key, - llvm::Value* value, llvm::Module* module, - ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type, - std::map>& name2memidx); - - llvm::Value* read_item(llvm::Value* dict, llvm::Value* key, - llvm::Module& module, ASR::Dict_t* key_asr_type, - bool get_pointer=false); - - llvm::Value* pop_item(llvm::Value* dict, llvm::Value* key, - llvm::Module& module, ASR::Dict_t* dict_type, - bool get_pointer=false); - - virtual - llvm::Value* get_pointer_to_keymask(llvm::Value* dict); - - void dict_deepcopy(llvm::Value* src, llvm::Value* dest, - ASR::Dict_t* dict_type, llvm::Module* module, - std::map>& name2memidx); - - llvm::Value* len(llvm::Value* dict); - - virtual ~LLVMDict(); - }; - - class LLVMDictOptimizedLinearProbing: public LLVMDict { - - public: - - LLVMDictOptimizedLinearProbing(llvm::LLVMContext& context_, - LLVMUtils* llvm_utils, - llvm::IRBuilder<>* builder); - - void resolve_collision(llvm::Value* capacity, llvm::Value* key_hash, - llvm::Value* key, llvm::Value* key_list, - llvm::Value* key_mask, llvm::Module& module, - ASR::ttype_t* key_asr_type, bool for_read=false); - - void resolve_collision_for_write(llvm::Value* dict, llvm::Value* key_hash, - llvm::Value* key, llvm::Value* value, - llvm::Module* module, ASR::ttype_t* key_asr_type, - ASR::ttype_t* value_asr_type, - std::map>& name2memidx); - - llvm::Value* resolve_collision_for_read(llvm::Value* dict, llvm::Value* key_hash, - llvm::Value* key, llvm::Module& module, - ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type); - - virtual ~LLVMDictOptimizedLinearProbing(); - - }; - - class LLVMDictSeparateChaining: public LLVMDictInterface { - - protected: - - std::map, llvm::Type*> typecode2kvstruct; - - llvm::Value* get_pointer_to_number_of_filled_buckets(llvm::Value* dict); - - llvm::Value* get_pointer_to_key_value_pairs(llvm::Value* dict); - - llvm::Value* get_pointer_to_rehash_flag(llvm::Value* dict); - - void deepcopy_key_value_pair_linked_list(llvm::Value* srci, llvm::Value* desti, - llvm::Value* dest_key_value_pairs, llvm::Value* src_capacity, ASR::Dict_t* dict_type, - llvm::Module* module, std::map>& name2memidx); - - void write_key_value_pair_linked_list(llvm::Value* kv_ll, llvm::Value* dict, - llvm::Value* capacity, ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type, - llvm::Module* module, std::map>& name2memidx); - - void resolve_collision(llvm::Value* capacity, llvm::Value* key_hash, - llvm::Value* key, llvm::Value* key_value_pair_linked_list, - llvm::Type* kv_pair_type, llvm::Value* key_mask, - llvm::Module& module, ASR::ttype_t* key_asr_type); - - llvm::Type* get_key_value_pair_type(std::string key_type_code, std::string value_type_code); - - llvm::Type* get_key_value_pair_type(ASR::ttype_t* key_asr_type, ASR::ttype_t* value_pair_type); - - void dict_init_given_initial_capacity(std::string key_type_code, std::string value_type_code, - llvm::Value* dict, llvm::Module* module, llvm::Value* initial_capacity); - - public: - - LLVMDictSeparateChaining( - llvm::LLVMContext& context_, - LLVMUtils* llvm_utils_, - llvm::IRBuilder<>* builder_); - - llvm::Type* get_dict_type(std::string key_type_code, std::string value_type_code, - int32_t key_type_size, int32_t value_type_size, - llvm::Type* key_type, llvm::Type* value_type); - - void dict_init(std::string key_type_code, std::string value_type_code, - llvm::Value* dict, llvm::Module* module, size_t initial_capacity); - - llvm::Value* get_key_list(llvm::Value* dict); - - llvm::Value* get_value_list(llvm::Value* dict); - - llvm::Value* get_pointer_to_occupancy(llvm::Value* dict); - - llvm::Value* get_pointer_to_capacity(llvm::Value* dict); - - void resolve_collision_for_write(llvm::Value* dict, llvm::Value* key_hash, - llvm::Value* key, llvm::Value* value, - llvm::Module* module, ASR::ttype_t* key_asr_type, - ASR::ttype_t* value_asr_type, - std::map>& name2memidx); - - llvm::Value* resolve_collision_for_read(llvm::Value* dict, llvm::Value* key_hash, - llvm::Value* key, llvm::Module& module, - ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type); - - void rehash(llvm::Value* dict, llvm::Module* module, - ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type, - std::map>& name2memidx); - - void rehash_all_at_once_if_needed(llvm::Value* dict, - llvm::Module* module, - ASR::ttype_t* key_asr_type, - ASR::ttype_t* value_asr_type, - std::map>& name2memidx); - - void write_item(llvm::Value* dict, llvm::Value* key, - llvm::Value* value, llvm::Module* module, - ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type, - std::map>& name2memidx); - - llvm::Value* read_item(llvm::Value* dict, llvm::Value* key, - llvm::Module& module, ASR::Dict_t* dict_type, - bool get_pointer=false); - - llvm::Value* pop_item(llvm::Value* dict, llvm::Value* key, - llvm::Module& module, ASR::Dict_t* dict_type, - bool get_pointer=false); - - llvm::Value* get_pointer_to_keymask(llvm::Value* dict); - - void dict_deepcopy(llvm::Value* src, llvm::Value* dest, - ASR::Dict_t* dict_type, llvm::Module* module, - std::map>& name2memidx); - - llvm::Value* len(llvm::Value* dict); - - virtual ~LLVMDictSeparateChaining(); - - }; - -} // namespace LCompilers - -#endif // LFORTRAN_LLVM_UTILS_H diff --git a/src/libasr/codegen/wasm_assembler.h b/src/libasr/codegen/wasm_assembler.h deleted file mode 100644 index bda53a5426..0000000000 --- a/src/libasr/codegen/wasm_assembler.h +++ /dev/null @@ -1,1248 +0,0 @@ -#include - -#include -#include - -namespace LCompilers { - -namespace wasm { - -enum type { i32 = 0x7F, i64 = 0x7E, f32 = 0x7D, f64 = 0x7C }; - -enum mem_align { b8 = 0, b16 = 1, b32 = 2, b64 = 3 }; - -void emit_leb128_u32(Vec &code, Allocator &al, - uint32_t n) { // for u32 - do { - uint8_t byte = n & 0x7f; - n >>= 7; - if (n != 0) { - byte |= 0x80; - } - code.push_back(al, byte); - } while (n != 0); -} - -void emit_leb128_i32(Vec &code, Allocator &al, int32_t n) { // for i32 - bool more = true; - do { - uint8_t byte = n & 0x7f; - n >>= 7; - more = !((((n == 0) && ((byte & 0x40) == 0)) || - ((n == -1) && ((byte & 0x40) != 0)))); - if (more) { - byte |= 0x80; - } - code.push_back(al, byte); - } while (more); -} - -void emit_leb128_i64(Vec &code, Allocator &al, int64_t n) { // for i64 - bool more = true; - do { - uint8_t byte = n & 0x7f; - n >>= 7; - more = !((((n == 0) && ((byte & 0x40) == 0)) || - ((n == -1) && ((byte & 0x40) != 0)))); - if (more) { - byte |= 0x80; - } - code.push_back(al, byte); - } while (more); -} - -void emit_ieee754_f32(Vec &code, Allocator &al, float z) { // for f32 - uint8_t encoded_float[sizeof(z)]; - std::memcpy(&encoded_float, &z, sizeof(z)); - for (auto &byte : encoded_float) { - code.push_back(al, byte); - } -} - -void emit_ieee754_f64(Vec &code, Allocator &al, double z) { // for f64 - uint8_t encoded_float[sizeof(z)]; - std::memcpy(&encoded_float, &z, sizeof(z)); - for (auto &byte : encoded_float) { - code.push_back(al, byte); - } -} - -// function to emit header of Wasm Binary Format -void emit_header(Vec &code, Allocator &al) { - code.push_back(al, 0x00); - code.push_back(al, 0x61); - code.push_back(al, 0x73); - code.push_back(al, 0x6D); - code.push_back(al, 0x01); - code.push_back(al, 0x00); - code.push_back(al, 0x00); - code.push_back(al, 0x00); -} - -// function to append a given bytecode to the end of the code -void emit_b8(Vec &code, Allocator &al, uint8_t x) { - code.push_back(al, x); -} - -// function to emit unsigned 32 bit integer -void emit_u32(Vec &code, Allocator &al, uint32_t x) { - emit_leb128_u32(code, al, x); -} - -// function to emit signed 32 bit integer -void emit_i32(Vec &code, Allocator &al, int32_t x) { - emit_leb128_i32(code, al, x); -} - -// function to emit signed 64 bit integer -void emit_i64(Vec &code, Allocator &al, int64_t x) { - emit_leb128_i64(code, al, x); -} - -// function to emit 32 bit float -void emit_f32(Vec &code, Allocator &al, float x) { - emit_ieee754_f32(code, al, x); -} - -// function to emit 64 bit float -void emit_f64(Vec &code, Allocator &al, double x) { - emit_ieee754_f64(code, al, x); -} - -// function to emit string -void emit_str(Vec &code, Allocator &al, std::string text) { - std::vector text_bytes(text.size()); - std::memcpy(text_bytes.data(), text.data(), text.size()); - emit_u32(code, al, text_bytes.size()); - for (auto &byte : text_bytes) emit_b8(code, al, byte); -} - -void emit_u32_b32_idx(Vec &code, Allocator &al, uint32_t idx, - uint32_t section_size) { - /* - Encodes the integer `i` using LEB128 and adds trailing zeros to always - occupy 4 bytes. Stores the int `i` at the index `idx` in `code`. - */ - Vec num; - num.reserve(al, 4); - emit_leb128_u32(num, al, section_size); - std::vector num_4b = {0x80, 0x80, 0x80, 0x00}; - assert(num.size() <= 4); - for (uint32_t i = 0; i < num.size(); i++) { - num_4b[i] |= num[i]; - } - for (uint32_t i = 0; i < 4u; i++) { - code.p[idx + i] = num_4b[i]; - } -} - -// function to fixup length at the given length index -void fixup_len(Vec &code, Allocator &al, uint32_t len_idx) { - uint32_t section_len = code.size() - len_idx - 4u; - emit_u32_b32_idx(code, al, len_idx, section_len); -} - -// function to emit length placeholder -uint32_t emit_len_placeholder(Vec &code, Allocator &al) { - uint32_t len_idx = code.size(); - code.push_back(al, 0x00); - code.push_back(al, 0x00); - code.push_back(al, 0x00); - code.push_back(al, 0x00); - return len_idx; -} - -void emit_export_fn(Vec &code, Allocator &al, const std::string &name, - uint32_t idx) { - emit_str(code, al, name); - emit_b8(code, al, 0x00); // for exporting function - emit_u32(code, al, idx); -} - -void emit_import_fn(Vec &code, Allocator &al, - const std::string &mod_name, const std::string &fn_name, - uint32_t type_idx) { - emit_str(code, al, mod_name); - emit_str(code, al, fn_name); - emit_b8(code, al, 0x00); // for importing function - emit_u32(code, al, type_idx); -} - -void emit_declare_mem(Vec &code, Allocator &al, - uint32_t min_no_pages, uint32_t max_no_pages = 0) { - if (max_no_pages > 0) { - emit_b8(code, al, - 0x01); // for specifying min and max page limits of memory - emit_u32(code, al, min_no_pages); - emit_u32(code, al, max_no_pages); - } else { - emit_b8(code, al, - 0x00); // for specifying only min page limit of memory - emit_u32(code, al, min_no_pages); - } -} - -void emit_import_mem(Vec &code, Allocator &al, - const std::string &mod_name, const std::string &mem_name, - uint32_t min_no_pages, uint32_t max_no_pages = 0) { - emit_str(code, al, mod_name); - emit_str(code, al, mem_name); - emit_b8(code, al, 0x02); // for importing memory - if (max_no_pages > 0) { - emit_b8(code, al, - 0x01); // for specifying min and max page limits of memory - emit_u32(code, al, min_no_pages); - emit_u32(code, al, max_no_pages); - } else { - emit_b8(code, al, - 0x00); // for specifying only min page limit of memory - emit_u32(code, al, min_no_pages); - } -} - -void emit_export_mem(Vec &code, Allocator &al, const std::string &name, - uint32_t idx) { - emit_str(code, al, name); - emit_b8(code, al, 0x02); // for exporting memory - emit_u32(code, al, idx); -} - -void encode_section(Vec &des, Vec §ion_content, - Allocator &al, uint32_t section_id, - uint32_t no_of_elements) { - // every section in WebAssembly is encoded by adding its section id, - // followed by the content size and lastly the contents - emit_u32(des, al, section_id); - emit_u32(des, al, 4U /* size of no_of_elements */ + section_content.size()); - uint32_t len_idx = emit_len_placeholder(des, al); - emit_u32_b32_idx(des, al, len_idx, no_of_elements); - for (auto &byte : section_content) { - des.push_back(al, byte); - } -} - -// function to emit drop instruction (it throws away a single operand on stack) -void emit_drop(Vec &code, Allocator &al) { code.push_back(al, 0x1A); } - -// function to emit get local variable at given index -void emit_get_local(Vec &code, Allocator &al, uint32_t idx) { - code.push_back(al, 0x20); - emit_u32(code, al, idx); -} - -// function to emit set local variable at given index -void emit_set_local(Vec &code, Allocator &al, uint32_t idx) { - code.push_back(al, 0x21); - emit_u32(code, al, idx); -} - -// function to emit get global variable at given index -void emit_get_global(Vec &code, Allocator &al, uint32_t idx) { - code.push_back(al, 0x23); - emit_u32(code, al, idx); -} - -// function to emit set global variable at given index -void emit_set_global(Vec &code, Allocator &al, uint32_t idx) { - code.push_back(al, 0x24); - emit_u32(code, al, idx); -} - -// function to emit call instruction -void emit_call(Vec &code, Allocator &al, uint32_t idx) { - code.push_back(al, 0x10); - emit_u32(code, al, idx); -} - -// function to emit end of wasm expression -void emit_expr_end(Vec &code, Allocator &al) { - code.push_back(al, 0x0B); -} - -/**************************** Integer Operations ****************************/ - -// function to emit a i32.const instruction -void emit_i32_const(Vec &code, Allocator &al, int32_t x) { - code.push_back(al, 0x41); - emit_i32(code, al, x); -} - -// function to emit i32.clz instruction -void emit_i32_clz(Vec &code, Allocator &al) { - code.push_back(al, 0x67); -} - -// function to emit i32.ctz instruction -void emit_i32_ctz(Vec &code, Allocator &al) { - code.push_back(al, 0x68); -} - -// function to emit i32.popcnt instruction -void emit_i32_popcnt(Vec &code, Allocator &al) { - code.push_back(al, 0x69); -} - -// function to emit i32.add instruction -void emit_i32_add(Vec &code, Allocator &al) { - code.push_back(al, 0x6A); -} - -// function to emit i32.sub instruction -void emit_i32_sub(Vec &code, Allocator &al) { - code.push_back(al, 0x6B); -} - -// function to emit i32.mul instruction -void emit_i32_mul(Vec &code, Allocator &al) { - code.push_back(al, 0x6C); -} - -// function to emit i32.div_s instruction -void emit_i32_div_s(Vec &code, Allocator &al) { - code.push_back(al, 0x6D); -} - -// function to emit i32.div_u instruction -void emit_i32_div_u(Vec &code, Allocator &al) { - code.push_back(al, 0x6E); -} - -// function to emit i32.rem_s instruction -void emit_i32_rem_s(Vec &code, Allocator &al) { - code.push_back(al, 0x6F); -} - -// function to emit i32.rem_u instruction -void emit_i32_rem_u(Vec &code, Allocator &al) { - code.push_back(al, 0x70); -} - -// function to emit i32.and instruction -void emit_i32_and(Vec &code, Allocator &al) { - code.push_back(al, 0x71); -} - -// function to emit i32.or instruction -void emit_i32_or(Vec &code, Allocator &al) { - code.push_back(al, 0x72); -} - -// function to emit i32.xor instruction -void emit_i32_xor(Vec &code, Allocator &al) { - code.push_back(al, 0x73); -} - -// function to emit i32.shl instruction -void emit_i32_shl(Vec &code, Allocator &al) { - code.push_back(al, 0x74); -} - -// function to emit i32.shr_s instruction -void emit_i32_shr_s(Vec &code, Allocator &al) { - code.push_back(al, 0x75); -} - -// function to emit i32.shr_u instruction -void emit_i32_shr_u(Vec &code, Allocator &al) { - code.push_back(al, 0x76); -} - -// function to emit i32.rotl instruction -void emit_i32_rotl(Vec &code, Allocator &al) { - code.push_back(al, 0x77); -} - -// function to emit i32.rotr instruction -void emit_i32_rotr(Vec &code, Allocator &al) { - code.push_back(al, 0x78); -} - -// function to emit a i64.const instruction -void emit_i64_const(Vec &code, Allocator &al, int64_t x) { - code.push_back(al, 0x42); - emit_i64(code, al, x); -} - -// function to emit i64.clz instruction -void emit_i64_clz(Vec &code, Allocator &al) { - code.push_back(al, 0x79); -} - -// function to emit i64.ctz instruction -void emit_i64_ctz(Vec &code, Allocator &al) { - code.push_back(al, 0x7A); -} - -// function to emit i64.popcnt instruction -void emit_i64_popcnt(Vec &code, Allocator &al) { - code.push_back(al, 0x7B); -} - -// function to emit i64.add instruction -void emit_i64_add(Vec &code, Allocator &al) { - code.push_back(al, 0x7C); -} - -// function to emit i64.sub instruction -void emit_i64_sub(Vec &code, Allocator &al) { - code.push_back(al, 0x7D); -} - -// function to emit i64.mul instruction -void emit_i64_mul(Vec &code, Allocator &al) { - code.push_back(al, 0x7E); -} - -// function to emit i64.div_s instruction -void emit_i64_div_s(Vec &code, Allocator &al) { - code.push_back(al, 0x7F); -} - -// function to emit i64.div_u instruction -void emit_i64_div_u(Vec &code, Allocator &al) { - code.push_back(al, 0x80); -} - -// function to emit i64.rem_s instruction -void emit_i64_rem_s(Vec &code, Allocator &al) { - code.push_back(al, 0x81); -} - -// function to emit i64.rem_u instruction -void emit_i64_rem_u(Vec &code, Allocator &al) { - code.push_back(al, 0x82); -} - -// function to emit i64.and instruction -void emit_i64_and(Vec &code, Allocator &al) { - code.push_back(al, 0x83); -} - -// function to emit i64.or instruction -void emit_i64_or(Vec &code, Allocator &al) { - code.push_back(al, 0x84); -} - -// function to emit i64.xor instruction -void emit_i64_xor(Vec &code, Allocator &al) { - code.push_back(al, 0x85); -} - -// function to emit i64.shl instruction -void emit_i64_shl(Vec &code, Allocator &al) { - code.push_back(al, 0x86); -} - -// function to emit i64.shr_s instruction -void emit_i64_shr_s(Vec &code, Allocator &al) { - code.push_back(al, 0x87); -} - -// function to emit i64.shr_u instruction -void emit_i64_shr_u(Vec &code, Allocator &al) { - code.push_back(al, 0x88); -} - -// function to emit i64.rotl instruction -void emit_i64_rotl(Vec &code, Allocator &al) { - code.push_back(al, 0x89); -} - -// function to emit i64.rotr instruction -void emit_i64_rotr(Vec &code, Allocator &al) { - code.push_back(al, 0x8A); -} - -/******** Integer Relational Operations ********/ - -// function to emit i32.eqz instruction -void emit_i32_eqz(Vec &code, Allocator &al) { - code.push_back(al, 0x45); -} - -// function to emit i32.eq instruction -void emit_i32_eq(Vec &code, Allocator &al) { - code.push_back(al, 0x46); -} - -// function to emit i32.ne instruction -void emit_i32_ne(Vec &code, Allocator &al) { - code.push_back(al, 0x47); -} - -// function to emit i32.lt_s instruction -void emit_i32_lt_s(Vec &code, Allocator &al) { - code.push_back(al, 0x48); -} - -// function to emit i32.lt_u instruction -void emit_i32_lt_u(Vec &code, Allocator &al) { - code.push_back(al, 0x49); -} - -// function to emit i32.gt_s instruction -void emit_i32_gt_s(Vec &code, Allocator &al) { - code.push_back(al, 0x4A); -} - -// function to emit i32.gt_u instruction -void emit_i32_gt_u(Vec &code, Allocator &al) { - code.push_back(al, 0x4B); -} - -// function to emit i32.le_s instruction -void emit_i32_le_s(Vec &code, Allocator &al) { - code.push_back(al, 0x4C); -} - -// function to emit i32.le_u instruction -void emit_i32_le_u(Vec &code, Allocator &al) { - code.push_back(al, 0x4D); -} - -// function to emit i32.ge_s instruction -void emit_i32_ge_s(Vec &code, Allocator &al) { - code.push_back(al, 0x4E); -} - -// function to emit i32.ge_u instruction -void emit_i32_ge_u(Vec &code, Allocator &al) { - code.push_back(al, 0x4F); -} - -// function to emit i64.eqz instruction -void emit_i64_eqz(Vec &code, Allocator &al) { - code.push_back(al, 0x50); -} - -// function to emit i64.eq instruction -void emit_i64_eq(Vec &code, Allocator &al) { - code.push_back(al, 0x51); -} - -// function to emit i64.ne instruction -void emit_i64_ne(Vec &code, Allocator &al) { - code.push_back(al, 0x52); -} - -// function to emit i64.lt_s instruction -void emit_i64_lt_s(Vec &code, Allocator &al) { - code.push_back(al, 0x53); -} - -// function to emit i64.lt_u instruction -void emit_i64_lt_u(Vec &code, Allocator &al) { - code.push_back(al, 0x54); -} - -// function to emit i64.gt_s instruction -void emit_i64_gt_s(Vec &code, Allocator &al) { - code.push_back(al, 0x55); -} - -// function to emit i64.gt_u instruction -void emit_i64_gt_u(Vec &code, Allocator &al) { - code.push_back(al, 0x56); -} - -// function to emit i64.le_s instruction -void emit_i64_le_s(Vec &code, Allocator &al) { - code.push_back(al, 0x57); -} - -// function to emit i64.le_u instruction -void emit_i64_le_u(Vec &code, Allocator &al) { - code.push_back(al, 0x58); -} - -// function to emit i64.ge_s instruction -void emit_i64_ge_s(Vec &code, Allocator &al) { - code.push_back(al, 0x59); -} - -// function to emit i64.ge_u instruction -void emit_i64_ge_u(Vec &code, Allocator &al) { - code.push_back(al, 0x5A); -} - -/**************************** Floating Point Operations - * ****************************/ - -// function to emit a f32.const instruction -void emit_f32_const(Vec &code, Allocator &al, float x) { - code.push_back(al, 0x43); - emit_f32(code, al, x); -} - -// function to emit f32.abs instruction -void emit_f32_abs(Vec &code, Allocator &al) { - code.push_back(al, 0x8B); -} - -// function to emit f32.neg instruction -void emit_f32_neg(Vec &code, Allocator &al) { - code.push_back(al, 0x8C); -} - -// function to emit f32.ceil instruction -void emit_f32_ceil(Vec &code, Allocator &al) { - code.push_back(al, 0x8D); -} - -// function to emit f32.floor instruction -void emit_f32_floor(Vec &code, Allocator &al) { - code.push_back(al, 0x8E); -} - -// function to emit f32.trunc instruction -void emit_f32_trunc(Vec &code, Allocator &al) { - code.push_back(al, 0x8F); -} - -// function to emit f32.nearest instruction -void emit_f32_nearest(Vec &code, Allocator &al) { - code.push_back(al, 0x90); -} - -// function to emit f32.sqrt instruction -void emit_f32_sqrt(Vec &code, Allocator &al) { - code.push_back(al, 0x91); -} - -// function to emit f32.add instruction -void emit_f32_add(Vec &code, Allocator &al) { - code.push_back(al, 0x92); -} - -// function to emit f32.sub instruction -void emit_f32_sub(Vec &code, Allocator &al) { - code.push_back(al, 0x93); -} - -// function to emit f32.mul instruction -void emit_f32_mul(Vec &code, Allocator &al) { - code.push_back(al, 0x94); -} - -// function to emit f32.div instruction -void emit_f32_div(Vec &code, Allocator &al) { - code.push_back(al, 0x95); -} - -// function to emit f32.min instruction -void emit_f32_min(Vec &code, Allocator &al) { - code.push_back(al, 0x96); -} - -// function to emit f32.max instruction -void emit_f32_max(Vec &code, Allocator &al) { - code.push_back(al, 0x97); -} - -// function to emit f32.copysign instruction -void emit_f32_copysign(Vec &code, Allocator &al) { - code.push_back(al, 0x98); -} - -// function to emit a f64.const instruction -void emit_f64_const(Vec &code, Allocator &al, double x) { - code.push_back(al, 0x44); - emit_f64(code, al, x); -} - -// function to emit f64.abs instruction -void emit_f64_abs(Vec &code, Allocator &al) { - code.push_back(al, 0x99); -} - -// function to emit f64.neg instruction -void emit_f64_neg(Vec &code, Allocator &al) { - code.push_back(al, 0x9A); -} - -// function to emit f64.ceil instruction -void emit_f64_ceil(Vec &code, Allocator &al) { - code.push_back(al, 0x9B); -} - -// function to emit f64.floor instruction -void emit_f64_floor(Vec &code, Allocator &al) { - code.push_back(al, 0x9C); -} - -// function to emit f64.trunc instruction -void emit_f64_trunc(Vec &code, Allocator &al) { - code.push_back(al, 0x9D); -} - -// function to emit f64.nearest instruction -void emit_f64_nearest(Vec &code, Allocator &al) { - code.push_back(al, 0x9E); -} - -// function to emit f64.sqrt instruction -void emit_f64_sqrt(Vec &code, Allocator &al) { - code.push_back(al, 0x9F); -} - -// function to emit f64.add instruction -void emit_f64_add(Vec &code, Allocator &al) { - code.push_back(al, 0xA0); -} - -// function to emit f64.sub instruction -void emit_f64_sub(Vec &code, Allocator &al) { - code.push_back(al, 0xA1); -} - -// function to emit f64.mul instruction -void emit_f64_mul(Vec &code, Allocator &al) { - code.push_back(al, 0xA2); -} - -// function to emit f64.div instruction -void emit_f64_div(Vec &code, Allocator &al) { - code.push_back(al, 0xA3); -} - -// function to emit f64.min instruction -void emit_f64_min(Vec &code, Allocator &al) { - code.push_back(al, 0xA4); -} - -// function to emit f64.max instruction -void emit_f64_max(Vec &code, Allocator &al) { - code.push_back(al, 0xA5); -} - -// function to emit f64.copysign instruction -void emit_f64_copysign(Vec &code, Allocator &al) { - code.push_back(al, 0xA6); -} - -/******** Float Relational Operations ********/ - -// function to emit f32.eq instruction -void emit_f32_eq(Vec &code, Allocator &al) { - code.push_back(al, 0x5B); -} - -// function to emit f32.ne instruction -void emit_f32_ne(Vec &code, Allocator &al) { - code.push_back(al, 0x5C); -} - -// function to emit f32.lt instruction -void emit_f32_lt(Vec &code, Allocator &al) { - code.push_back(al, 0x5D); -} - -// function to emit f32.gt instruction -void emit_f32_gt(Vec &code, Allocator &al) { - code.push_back(al, 0x5E); -} - -// function to emit f32.le instruction -void emit_f32_le(Vec &code, Allocator &al) { - code.push_back(al, 0x5F); -} - -// function to emit f32.ge instruction -void emit_f32_ge(Vec &code, Allocator &al) { - code.push_back(al, 0x60); -} - -// function to emit f64.eq instruction -void emit_f64_eq(Vec &code, Allocator &al) { - code.push_back(al, 0x61); -} - -// function to emit f64.ne instruction -void emit_f64_ne(Vec &code, Allocator &al) { - code.push_back(al, 0x62); -} - -// function to emit f64.lt instruction -void emit_f64_lt(Vec &code, Allocator &al) { - code.push_back(al, 0x63); -} - -// function to emit f64.gt instruction -void emit_f64_gt(Vec &code, Allocator &al) { - code.push_back(al, 0x64); -} - -// function to emit f64.le instruction -void emit_f64_le(Vec &code, Allocator &al) { - code.push_back(al, 0x65); -} - -// function to emit f64.ge instruction -void emit_f64_ge(Vec &code, Allocator &al) { - code.push_back(al, 0x66); -} - -// function to emit string -void emit_str_const(Vec &code, Allocator &al, uint32_t mem_idx, - const std::string &text) { - emit_u32(code, al, - 0U); // for active mode of memory with default mem_idx of 0 - emit_i32_const( - code, al, - (int32_t)mem_idx); // specifying memory location as instructions - emit_expr_end(code, al); // end instructions - emit_str(code, al, text); -} - -void emit_unreachable(Vec &code, Allocator &al) { - code.push_back(al, 0x00); -} - -void emit_branch(Vec &code, Allocator &al, uint32_t label_idx) { - code.push_back(al, 0x0C); - emit_u32(code, al, label_idx); -} - -void emit_branch_if(Vec &code, Allocator &al, uint32_t label_idx) { - code.push_back(al, 0x0D); - emit_u32(code, al, label_idx); -} - -void save_js_glue(std::string filename) { - std::string js_glue = - R"(function define_imports(memory, outputBuffer, exit_code, stdout_print) { - const printNum = (num) => outputBuffer.push(num.toString()); - const printStr = (startIdx, strSize) => outputBuffer.push( - new TextDecoder("utf8").decode(new Uint8Array(memory.buffer, startIdx, strSize))); - const flushBuffer = () => { - stdout_print(outputBuffer.join(" ") + "\n"); - outputBuffer.length = 0; - } - const set_exit_code = (exit_code_val) => exit_code.val = exit_code_val; - const cpu_time = (time) => (Date.now() / 1000); // Date.now() returns milliseconds, so divide by 1000 - var imports = { - js: { - memory: memory, - /* functions */ - print_i32: printNum, - print_i64: printNum, - print_f32: printNum, - print_f64: printNum, - print_str: printStr, - flush_buf: flushBuffer, - set_exit_code: set_exit_code, - cpu_time: cpu_time - }, - }; - return imports; -} - -async function run_wasm(bytes, imports) { - try { - var res = await WebAssembly.instantiate(bytes, imports); - const { _lcompilers_main } = res.instance.exports; - _lcompilers_main(); - } catch(e) { console.log(e); } -} - -async function execute_code(bytes, stdout_print) { - var exit_code = {val: 1}; /* non-zero exit code */ - var outputBuffer = []; - var memory = new WebAssembly.Memory({ initial: 100, maximum: 100 }); // fixed 6.4 Mb memory currently - var imports = define_imports(memory, outputBuffer, exit_code, stdout_print); - await run_wasm(bytes, imports); - return exit_code.val; -} - -function main() { - const fs = require("fs"); - const wasmBuffer = fs.readFileSync(")" + - filename + R"("); - execute_code(wasmBuffer, (text) => process.stdout.write(text)) - .then((exit_code) => { - process.exit(exit_code); - }) - .catch((e) => console.log(e)) -} - -main(); -)"; - filename += ".js"; - std::ofstream out(filename); - out << js_glue; - out.close(); -} - -void save_js_glue_wasi(std::string filename) { - std::string js_glue = -R"(async function main() { - const fs = require("fs"); - const { WASI } = require("wasi"); - const wasi = new WASI(); - const importObject = { - wasi_snapshot_preview1: wasi.wasiImport, - js: { - cpu_time: (time) => (Date.now() / 1000) // Date.now() returns milliseconds, so divide by 1000 - } - }; - const wasm = await WebAssembly.compile(fs.readFileSync(")" + filename + R"(")); - const instance = await WebAssembly.instantiate(wasm, importObject); - wasi.start(instance); -} -main(); -)"; - filename += ".js"; - std::ofstream out(filename); - out << js_glue; - out.close(); -} - -void save_bin(Vec &code, std::string filename) { - std::ofstream out(filename); - out.write((const char *)code.p, code.size()); - out.close(); - save_js_glue_wasi(filename); -} - -/**************************** Type Conversion Operations - * ****************************/ - -// function to emit i32.wrap_i64 instruction -void emit_i32_wrap_i64(Vec &code, Allocator &al) { - code.push_back(al, 0xA7); -} - -// function to emit i32.trunc_f32_s instruction -void emit_i32_trunc_f32_s(Vec &code, Allocator &al) { - code.push_back(al, 0xA8); -} - -// function to emit i32.trunc_f32_u instruction -void emit_i32_trunc_f32_u(Vec &code, Allocator &al) { - code.push_back(al, 0xA9); -} - -// function to emit i32.trunc_f64_s instruction -void emit_i32_trunc_f64_s(Vec &code, Allocator &al) { - code.push_back(al, 0xAA); -} - -// function to emit i32.trunc_f64_u instruction -void emit_i32_trunc_f64_u(Vec &code, Allocator &al) { - code.push_back(al, 0xAB); -} - -// function to emit i64.extend_i32_s instruction -void emit_i64_extend_i32_s(Vec &code, Allocator &al) { - code.push_back(al, 0xAC); -} - -// function to emit i64.extend_i32_u instruction -void emit_i64_extend_i32_u(Vec &code, Allocator &al) { - code.push_back(al, 0xAD); -} - -// function to emit i64.trunc_f32_s instruction -void emit_i64_trunc_f32_s(Vec &code, Allocator &al) { - code.push_back(al, 0xAE); -} - -// function to emit i64.trunc_f32_u instruction -void emit_i64_trunc_f32_u(Vec &code, Allocator &al) { - code.push_back(al, 0xAF); -} - -// function to emit i64.trunc_f64_s instruction -void emit_i64_trunc_f64_s(Vec &code, Allocator &al) { - code.push_back(al, 0xB0); -} - -// function to emit i64.trunc_f64_u instruction -void emit_i64_trunc_f64_u(Vec &code, Allocator &al) { - code.push_back(al, 0xB1); -} - -// function to emit f32.convert_i32_s instruction -void emit_f32_convert_i32_s(Vec &code, Allocator &al) { - code.push_back(al, 0xB2); -} - -// function to emit f32.convert_i32_u instruction -void emit_f32_convert_i32_u(Vec &code, Allocator &al) { - code.push_back(al, 0xB3); -} - -// function to emit f32.convert_i64_s instruction -void emit_f32_convert_i64_s(Vec &code, Allocator &al) { - code.push_back(al, 0xB4); -} - -// function to emit f32.convert_i64_u instruction -void emit_f32_convert_i64_u(Vec &code, Allocator &al) { - code.push_back(al, 0xB5); -} - -// function to emit f32.demote_f64 instruction -void emit_f32_demote_f64(Vec &code, Allocator &al) { - code.push_back(al, 0xB6); -} - -// function to emit f64.convert_i32_s instruction -void emit_f64_convert_i32_s(Vec &code, Allocator &al) { - code.push_back(al, 0xB7); -} - -// function to emit f64.convert_i32_u instruction -void emit_f64_convert_i32_u(Vec &code, Allocator &al) { - code.push_back(al, 0xB8); -} - -// function to emit f64.convert_i64_s instruction -void emit_f64_convert_i64_s(Vec &code, Allocator &al) { - code.push_back(al, 0xB9); -} - -// function to emit f64.convert_i64_u instruction -void emit_f64_convert_i64_u(Vec &code, Allocator &al) { - code.push_back(al, 0xBA); -} - -// function to emit f64.promote_f32 instruction -void emit_f64_promote_f32(Vec &code, Allocator &al) { - code.push_back(al, 0xBB); -} - -// function to emit i32.reinterpret_f32 instruction -void emit_i32_reinterpret_f32(Vec &code, Allocator &al) { - code.push_back(al, 0xBC); -} - -// function to emit i64.reinterpret_f64 instruction -void emit_i64_reinterpret_f64(Vec &code, Allocator &al) { - code.push_back(al, 0xBD); -} - -// function to emit f32.reinterpret_i32 instruction -void emit_f32_reinterpret_i32(Vec &code, Allocator &al) { - code.push_back(al, 0xBE); -} - -// function to emit f64.reinterpret_i64 instruction -void emit_f64_reinterpret_i64(Vec &code, Allocator &al) { - code.push_back(al, 0xBF); -} - -// function to emit i32.extend8_s instruction -void emit_i32_extend8_s(Vec &code, Allocator &al) { - code.push_back(al, 0xC0); -} - -// function to emit i32.extend16_s instruction -void emit_i32_extend16_s(Vec &code, Allocator &al) { - code.push_back(al, 0xC1); -} - -// function to emit i64.extend8_s instruction -void emit_i64_extend8_s(Vec &code, Allocator &al) { - code.push_back(al, 0xC2); -} - -// function to emit i64.extend16_s instruction -void emit_i64_extend16_s(Vec &code, Allocator &al) { - code.push_back(al, 0xC3); -} - -// function to emit i64.extend32_s instruction -void emit_i64_extend32_s(Vec &code, Allocator &al) { - code.push_back(al, 0xC4); -} - -/**************************** Memory Instructions ****************************/ - -// function to emit i32.load instruction -void emit_i32_load(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x28); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} - -// function to emit i64.load instruction -void emit_i64_load(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x29); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} - -// function to emit f32.load instruction -void emit_f32_load(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x2A); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} - -// function to emit f64.load instruction -void emit_f64_load(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x2B); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} - -// function to emit i32.load8_s instruction -void emit_i32_load8_s(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x2C); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} - -// function to emit i32.load8_u instruction -void emit_i32_load8_u(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x2D); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} - -// function to emit i32.load16_s instruction -void emit_i32_load16_s(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x2E); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} - -// function to emit i32.load16_u instruction -void emit_i32_load16_u(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x2F); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} - -// function to emit i64.load8_s instruction -void emit_i64_load8_s(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x30); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} - -// function to emit i64.load8_u instruction -void emit_i64_load8_u(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x31); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} - -// function to emit i64.load16_s instruction -void emit_i64_load16_s(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x32); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} - -// function to emit i64.load16_u instruction -void emit_i64_load16_u(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x33); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} - -// function to emit i64.load32_s instruction -void emit_i64_load32_s(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x34); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} - -// function to emit i64.load32_u instruction -void emit_i64_load32_u(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x35); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} - -// function to emit i32.store instruction -void emit_i32_store(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x36); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} - -// function to emit i64.store instruction -void emit_i64_store(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x37); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} - -// function to emit f32.store instruction -void emit_f32_store(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x38); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} - -// function to emit f64.store instruction -void emit_f64_store(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x39); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} - -// function to emit i32.store8 instruction -void emit_i32_store8(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x3A); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} - -// function to emit i32.store16 instruction -void emit_i32_store16(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x3B); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} - -// function to emit i64.store8 instruction -void emit_i64_store8(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x3C); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} - -// function to emit i64.store16 instruction -void emit_i64_store16(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x3D); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} - -// function to emit i64.store32 instruction -void emit_i64_store32(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x3E); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} - -} // namespace wasm - -} // namespace LCompilers diff --git a/src/libasr/codegen/wasm_decoder.h b/src/libasr/codegen/wasm_decoder.h deleted file mode 100644 index 9edb61080d..0000000000 --- a/src/libasr/codegen/wasm_decoder.h +++ /dev/null @@ -1,405 +0,0 @@ -#ifndef LFORTRAN_WASM_DECODER_H -#define LFORTRAN_WASM_DECODER_H - -#include - -#include -#include -#include -#include - -// #define WAT_DEBUG - -#ifdef WAT_DEBUG -#define DEBUG(s) std::cout << s << std::endl -#else -#define DEBUG(s) -#endif - -namespace LCompilers { - -namespace { - -// This exception is used to abort the visitor pattern when an error occurs. -class CodeGenAbort {}; - -// Local exception that is only used in this file to exit the visitor -// pattern and caught later (not propagated outside) -class CodeGenError { - public: - diag::Diagnostic d; - - public: - CodeGenError(const std::string &msg) - : d{diag::Diagnostic(msg, diag::Level::Error, diag::Stage::CodeGen)} {} - - CodeGenError(const std::string &msg, const Location &loc) - : d{diag::Diagnostic(msg, diag::Level::Error, diag::Stage::CodeGen, - {diag::Label("", {loc})})} {} -}; - -} // namespace - -namespace wasm { - -template -class WASMDecoder { - private: - Struct &self() { return static_cast(*this); } - - public: - std::unordered_map var_type_to_string; - std::unordered_map kind_to_string; - - Allocator &al; - diag::Diagnostics &diag; - Vec wasm_bytes; - size_t PREAMBLE_SIZE; - - Vec func_types; - Vec imports; - Vec type_indices; - Vec> memories; - Vec globals; - Vec exports; - Vec codes; - Vec data_segments; - - WASMDecoder(Allocator &al, diag::Diagnostics &diagonostics) - : al(al), diag(diagonostics) { - var_type_to_string = { - {0x7F, "i32"}, {0x7E, "i64"}, {0x7D, "f32"}, {0x7C, "f64"}}; - kind_to_string = { - {0x00, "func"}, {0x01, "table"}, {0x02, "memory"}, {0x03, "global"}}; - - PREAMBLE_SIZE = 8 /* BYTES */; - // wasm_bytes.reserve(al, 1024 * 128); - // func_types.reserve(al, 1024 * 128); - // type_indices.reserve(al, 1024 * 128); - // exports.reserve(al, 1024 * 128); - // codes.reserve(al, 1024 * 128); - } - - void load_file(std::string filename) { - std::ifstream file(filename, std::ios::binary); - file.seekg(0, std::ios::end); - size_t size = file.tellg(); - file.seekg(0, std::ios::beg); - wasm_bytes.reserve(al, size); - file.read((char *)wasm_bytes.data(), size); - file.close(); - } - - bool is_preamble_ok(uint32_t offset) { - uint8_t expected_preamble[] = {0x00, 0x61, 0x73, 0x6D, - 0x01, 0x00, 0x00, 0x00}; - for (size_t i = 0; i < PREAMBLE_SIZE; i++) { - uint8_t cur_byte = read_b8(wasm_bytes, offset); - if (cur_byte != expected_preamble[i]) { - return false; - } - } - return true; - } - - void decode_type_section(uint32_t offset) { - // read type section contents - uint32_t no_of_func_types = read_u32(wasm_bytes, offset); - DEBUG("no_of_func_types: " + std::to_string(no_of_func_types)); - func_types.resize(al, no_of_func_types); - - for (uint32_t i = 0; i < no_of_func_types; i++) { - if (read_b8(wasm_bytes, offset) != 0x60) { - throw CodeGenError("Invalid type section"); - } - - // read result type 1 - uint32_t no_of_params = read_u32(wasm_bytes, offset); - func_types.p[i].param_types.resize(al, no_of_params); - - for (uint32_t j = 0; j < no_of_params; j++) { - func_types.p[i].param_types.p[j] = read_b8(wasm_bytes, offset); - } - - uint32_t no_of_results = read_u32(wasm_bytes, offset); - func_types.p[i].result_types.resize(al, no_of_results); - - for (uint32_t j = 0; j < no_of_results; j++) { - func_types.p[i].result_types.p[j] = read_b8(wasm_bytes, offset); - } - } - } - - void decode_imports_section(uint32_t offset) { - // read imports section contents - uint32_t no_of_imports = read_u32(wasm_bytes, offset); - DEBUG("no_of_imports: " + std::to_string(no_of_imports)); - imports.resize(al, no_of_imports); - - for (uint32_t i = 0; i < no_of_imports; i++) { - uint32_t mod_name_size = read_u32(wasm_bytes, offset); - imports.p[i].mod_name.resize( - mod_name_size); // do not pass al to this resize as it is - // std::string.resize() - for (uint32_t j = 0; j < mod_name_size; j++) { - imports.p[i].mod_name[j] = read_b8(wasm_bytes, offset); - } - - uint32_t name_size = read_u32(wasm_bytes, offset); - imports.p[i].name.resize( - name_size); // do not pass al to this resize as it is - // std::string.resize() - for (uint32_t j = 0; j < name_size; j++) { - imports.p[i].name[j] = read_b8(wasm_bytes, offset); - } - - imports.p[i].kind = read_b8(wasm_bytes, offset); - - switch (imports.p[i].kind) { - case 0x00: { - imports.p[i].type_idx = read_u32(wasm_bytes, offset); - break; - } - case 0x02: { - uint8_t byte = read_b8(wasm_bytes, offset); - if (byte == 0x00) { - imports.p[i].mem_page_size_limits.first = - read_u32(wasm_bytes, offset); - imports.p[i].mem_page_size_limits.second = - imports.p[i].mem_page_size_limits.first; - } else { - LCOMPILERS_ASSERT(byte == 0x01); - imports.p[i].mem_page_size_limits.first = - read_u32(wasm_bytes, offset); - imports.p[i].mem_page_size_limits.second = - read_u32(wasm_bytes, offset); - } - break; - } - - default: { - throw CodeGenError( - "Only importing functions and memory are currently " - "supported"); - } - } - } - } - - void decode_function_section(uint32_t offset) { - // read function section contents - uint32_t no_of_indices = read_u32(wasm_bytes, offset); - DEBUG("no_of_indices: " + std::to_string(no_of_indices)); - type_indices.resize(al, no_of_indices); - - for (uint32_t i = 0; i < no_of_indices; i++) { - type_indices.p[i] = read_u32(wasm_bytes, offset); - } - } - - void decode_memory_section(uint32_t offset) { - // read memory section contents - uint32_t no_of_memories = read_u32(wasm_bytes, offset); - DEBUG("no_of_memories: " + std::to_string(no_of_memories)); - memories.resize(al, no_of_memories); - - for (uint32_t i = 0; i < no_of_memories; i++) { - uint8_t flag = read_b8(wasm_bytes, offset); - switch (flag) { - case 0x00: { - memories.p[i].first = read_u32(wasm_bytes, offset); - memories.p[i].second = 0; - break; - } - case 0x01: { - memories.p[i].first = read_u32(wasm_bytes, offset); - memories.p[i].second = read_u32(wasm_bytes, offset); - break; - } - default: { - throw CodeGenError("Incorrect memory flag received."); - } - } - } - } - - void decode_global_section(uint32_t offset) { - // read global section contents - uint32_t no_of_globals = read_u32(wasm_bytes, offset); - DEBUG("no_of_globals: " + std::to_string(no_of_globals)); - globals.resize(al, no_of_globals); - - for (uint32_t i = 0; i < no_of_globals; i++) { - globals.p[i].type = read_b8(wasm_bytes, offset); - globals.p[i].mut = read_b8(wasm_bytes, offset); - globals.p[i].insts_start_idx = offset; - - wasm::read_b8(wasm_bytes, offset); - switch (globals[i].type) - { - case 0x7F: wasm::read_i32(wasm_bytes, offset); break; - case 0x7E: wasm::read_i64(wasm_bytes, offset); break; - case 0x7D: wasm::read_f32(wasm_bytes, offset); break; - case 0x7C: wasm::read_f64(wasm_bytes, offset); break; - default: throw CodeGenError("decode_global_section: Unsupport global type"); break; - } - - if (read_b8(wasm_bytes, offset) != 0x0B) { - throw AssemblerError("decode_global_section: Invalid byte for expr end"); - } - } - } - - void decode_export_section(uint32_t offset) { - // read export section contents - uint32_t no_of_exports = read_u32(wasm_bytes, offset); - DEBUG("no_of_exports: " + std::to_string(no_of_exports)); - exports.resize(al, no_of_exports); - - for (uint32_t i = 0; i < no_of_exports; i++) { - uint32_t name_size = read_u32(wasm_bytes, offset); - exports.p[i].name.resize( - name_size); // do not pass al to this resize as it is - // std::string.resize() - for (uint32_t j = 0; j < name_size; j++) { - exports.p[i].name[j] = read_b8(wasm_bytes, offset); - } - DEBUG("export name: " + exports.p[i].name); - exports.p[i].kind = read_b8(wasm_bytes, offset); - DEBUG("export kind: " + std::to_string(exports.p[i].kind)); - exports.p[i].index = read_u32(wasm_bytes, offset); - DEBUG("export index: " + std::to_string(exports.p[i].index)); - } - } - - void decode_code_section(uint32_t offset) { - // read code section contents - uint32_t no_of_codes = read_u32(wasm_bytes, offset); - DEBUG("no_of_codes: " + std::to_string(no_of_codes)); - codes.resize(al, no_of_codes); - - for (uint32_t i = 0; i < no_of_codes; i++) { - codes.p[i].size = read_u32(wasm_bytes, offset); - uint32_t code_start_offset = offset; - uint32_t no_of_locals = read_u32(wasm_bytes, offset); - DEBUG("no_of_locals: " + std::to_string(no_of_locals)); - codes.p[i].locals.resize(al, no_of_locals); - - DEBUG("Entering loop"); - for (uint32_t j = 0U; j < no_of_locals; j++) { - codes.p[i].locals.p[j].count = read_u32(wasm_bytes, offset); - DEBUG("count: " + std::to_string(codes.p[i].locals.p[j].count)); - codes.p[i].locals.p[j].type = read_b8(wasm_bytes, offset); - DEBUG("type: " + std::to_string(codes.p[i].locals.p[j].type)); - } - DEBUG("Exiting loop"); - - codes.p[i].insts_start_index = offset; - - // skip offset to directly the end of instructions - offset = code_start_offset + codes.p[i].size; - } - } - - void decode_data_section(uint32_t offset) { - // read code section contents - uint32_t no_of_data_segments = read_u32(wasm_bytes, offset); - DEBUG("no_of_data_segments: " + std::to_string(no_of_data_segments)); - data_segments.resize(al, no_of_data_segments); - - for (uint32_t i = 0; i < no_of_data_segments; i++) { - uint32_t num = read_u32(wasm_bytes, offset); - if (num != 0) { - throw CodeGenError( - "Only active default memory (index = 0) is currently " - "supported"); - } - - data_segments.p[i].insts_start_index = offset; - - // read i32.const - if (read_b8(wasm_bytes, offset) != 0x41) { - throw CodeGenError("DecodeDataSection: Invalid byte for i32.const"); - } - // read the integer (memory location) - read_i32(wasm_bytes, offset); - // read expr end - if (read_b8(wasm_bytes, offset) != 0x0B) { - throw CodeGenError("DecodeDataSection: Invalid byte for expr end"); - } - - uint32_t text_size = read_u32(wasm_bytes, offset); - data_segments.p[i].text.resize( - text_size); // do not pass al to this resize as it is - // std::string.resize() - for (uint32_t j = 0; j < text_size; j++) { - data_segments.p[i].text[j] = read_b8(wasm_bytes, offset); - } - } - } - void decode_wasm() { - // first 8 bytes are magic number and wasm version number - uint32_t index = 0; - if (!is_preamble_ok(index)) { - std::cerr << "Unexpected Preamble: "; - for (size_t i = 0; i < PREAMBLE_SIZE; i++) { - fprintf(stderr, "0x%.02X, ", wasm_bytes[i]); - } - throw CodeGenError( - "Expected: 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00"); - } - index += PREAMBLE_SIZE; - while (index < wasm_bytes.size()) { - uint32_t section_id = read_u32(wasm_bytes, index); - uint32_t section_size = read_u32(wasm_bytes, index); - switch (section_id) { - case 1U: - decode_type_section(index); - // exit(0); - break; - case 2U: - decode_imports_section(index); - // exit(0); - break; - case 3U: - decode_function_section(index); - // exit(0); - break; - case 5U: - decode_memory_section(index); - // exit(0); - break; - case 6U: - decode_global_section(index); - // exit(0); - break; - case 7U: - decode_export_section(index); - // exit(0); - break; - case 10U: - decode_code_section(index); - // exit(0) - break; - case 11U: - decode_data_section(index); - // exit(0) - break; - default: - std::cout << "Unknown section id: " << section_id - << std::endl; - break; - } - index += section_size; - } - - LCOMPILERS_ASSERT(index == wasm_bytes.size()); - LCOMPILERS_ASSERT(type_indices.size() == codes.size()); - } -}; - -} // namespace wasm - -} // namespace LCompilers - -#endif // LFORTRAN_WASM_DECODER_H diff --git a/src/libasr/codegen/wasm_to_wat.cpp b/src/libasr/codegen/wasm_to_wat.cpp deleted file mode 100644 index 25bff32dfb..0000000000 --- a/src/libasr/codegen/wasm_to_wat.cpp +++ /dev/null @@ -1,449 +0,0 @@ -#include - -#include -#include -#include - -namespace LCompilers { - -namespace wasm { - -class WATVisitor : public WASMDecoder, - public WASM_INSTS_VISITOR::BaseWASMVisitor { - - std::string src, indent; - - public: - WATVisitor(Allocator &al, diag::Diagnostics &diagonostics, Vec &code) - : WASMDecoder(al, diagonostics), BaseWASMVisitor(code, 0U /* temporary offset */), - src(""), indent("") { - // We are currently maintaining the two copies of code - // one is wasm_bytes and the other is code - // TODO: Use only single copy throughout - wasm_bytes.from_pointer_n(code.data(), code.size()); - } - - void visit_Unreachable() { src += indent + "unreachable"; } - void visit_Return() { src += indent + "return"; } - void visit_Call(uint32_t func_index) { - src += indent + "call " + std::to_string(func_index); - } - void visit_Br(uint32_t label_index) { - src += indent + "br " + std::to_string(label_index); - } - void visit_BrIf(uint32_t label_index) { - src += indent + "br_if " + std::to_string(label_index); - } - void visit_Drop() { src += indent + "drop"; } - void visit_LocalGet(uint32_t localidx) { - src += indent + "local.get " + std::to_string(localidx); - } - void visit_LocalSet(uint32_t localidx) { - src += indent + "local.set " + std::to_string(localidx); - } - void visit_GlobalGet(uint32_t globalidx) { - src += indent + "global.get " + std::to_string(globalidx); - } - void visit_GlobalSet(uint32_t globalidx) { - src += indent + "global.set " + std::to_string(globalidx); - } - void visit_EmtpyBlockType() {} - void visit_If() { - src += indent + "if"; - { - indent += " "; - decode_instructions(); - indent.resize(indent.length() - 4U); - } - src += indent + "end"; - } - void visit_Else() { - src += indent.substr(0, indent.length() - 4U) + "else"; - } - void visit_Loop() { - src += indent + "loop"; - { - indent += " "; - decode_instructions(); - indent.resize(indent.length() - 4U); - } - src += indent + "end"; - } - - void visit_I32Const(int32_t value) { - src += indent + "i32.const " + std::to_string(value); - } - void visit_I32Clz() { src += indent + "i32.clz"; } - void visit_I32Ctz() { src += indent + "i32.ctz"; } - void visit_I32Popcnt() { src += indent + "i32.popcnt"; } - void visit_I32Add() { src += indent + "i32.add"; } - void visit_I32Sub() { src += indent + "i32.sub"; } - void visit_I32Mul() { src += indent + "i32.mul"; } - void visit_I32DivS() { src += indent + "i32.div_s"; } - void visit_I32DivU() { src += indent + "i32.div_u"; } - void visit_I32RemS() { src += indent + "i32.rem_s"; } - void visit_I32RemU() { src += indent + "i32.rem_u"; } - void visit_I32And() { src += indent + "i32.and"; } - void visit_I32Or() { src += indent + "i32.or"; } - void visit_I32Xor() { src += indent + "i32.xor"; } - void visit_I32Shl() { src += indent + "i32.shl"; } - void visit_I32ShrS() { src += indent + "i32.shr_s"; } - void visit_I32ShrU() { src += indent + "i32.shr_u"; } - void visit_I32Rotl() { src += indent + "i32.rotl"; } - void visit_I32Rotr() { src += indent + "i32.rotr"; } - void visit_I32Eqz() { src += indent + "i32.eqz"; } - void visit_I32Eq() { src += indent + "i32.eq"; } - void visit_I32Ne() { src += indent + "i32.ne"; } - void visit_I32LtS() { src += indent + "i32.lt_s"; } - void visit_I32LtU() { src += indent + "i32.lt_u"; } - void visit_I32GtS() { src += indent + "i32.gt_s"; } - void visit_I32GtU() { src += indent + "i32.gt_u"; } - void visit_I32LeS() { src += indent + "i32.le_s"; } - void visit_I32LeU() { src += indent + "i32.le_u"; } - void visit_I32GeS() { src += indent + "i32.ge_s"; } - void visit_I32GeU() { src += indent + "i32.ge_u"; } - - void visit_I64Const(int64_t value) { - src += indent + "i64.const " + std::to_string(value); - } - void visit_I64Clz() { src += indent + "i64.clz"; } - void visit_I64Ctz() { src += indent + "i64.ctz"; } - void visit_I64Popcnt() { src += indent + "i64.popcnt"; } - void visit_I64Add() { src += indent + "i64.add"; } - void visit_I64Sub() { src += indent + "i64.sub"; } - void visit_I64Mul() { src += indent + "i64.mul"; } - void visit_I64DivS() { src += indent + "i64.div_s"; } - void visit_I64DivU() { src += indent + "i64.div_u"; } - void visit_I64RemS() { src += indent + "i64.rem_s"; } - void visit_I64RemU() { src += indent + "i64.rem_u"; } - void visit_I64And() { src += indent + "i64.and"; } - void visit_I64Or() { src += indent + "i64.or"; } - void visit_I64Xor() { src += indent + "i64.xor"; } - void visit_I64Shl() { src += indent + "i64.shl"; } - void visit_I64ShrS() { src += indent + "i64.shr_s"; } - void visit_I64ShrU() { src += indent + "i64.shr_u"; } - void visit_I64Rotl() { src += indent + "i64.rotl"; } - void visit_I64Rotr() { src += indent + "i64.rotr"; } - void visit_I64Eqz() { src += indent + "i64.eqz"; } - void visit_I64Eq() { src += indent + "i64.eq"; } - void visit_I64Ne() { src += indent + "i64.ne"; } - void visit_I64LtS() { src += indent + "i64.lt_s"; } - void visit_I64LtU() { src += indent + "i64.lt_u"; } - void visit_I64GtS() { src += indent + "i64.gt_s"; } - void visit_I64GtU() { src += indent + "i64.gt_u"; } - void visit_I64LeS() { src += indent + "i64.le_s"; } - void visit_I64LeU() { src += indent + "i64.le_u"; } - void visit_I64GeS() { src += indent + "i64.ge_s"; } - void visit_I64GeU() { src += indent + "i64.ge_u"; } - - void visit_F32Const(float value) { - src += indent + "f32.const " + std::to_string(value); - } - void visit_F32Add() { src += indent + "f32.add"; } - void visit_F32Sub() { src += indent + "f32.sub"; } - void visit_F32Mul() { src += indent + "f32.mul"; } - void visit_F32Div() { src += indent + "f32.div"; } - void visit_F32DivS() { src += indent + "f32.div_s"; } - void visit_F32Eq() { src += indent + "f32.eq"; } - void visit_F32Ne() { src += indent + "f32.ne"; } - void visit_F32Lt() { src += indent + "f32.lt"; } - void visit_F32Gt() { src += indent + "f32.gt"; } - void visit_F32Le() { src += indent + "f32.le"; } - void visit_F32Ge() { src += indent + "f32.ge"; } - void visit_F32Abs() { src += indent + "f32.abs"; } - void visit_F32Neg() { src += indent + "f32.neg"; } - void visit_F32Ceil() { src += indent + "f32.ceil"; } - void visit_F32Floor() { src += indent + "f32.floor"; } - void visit_F32Trunc() { src += indent + "f32.trunc"; } - void visit_F32Nearest() { src += indent + "f32.nearest"; } - void visit_F32Sqrt() { src += indent + "f32.sqrt"; } - void visit_F32Min() { src += indent + "f32.min"; } - void visit_F32Max() { src += indent + "f32.max"; } - void visit_F32Copysign() { src += indent + "f32.copysign"; } - - void visit_F64Const(double value) { - src += indent + "f64.const " + std::to_string(value); - } - void visit_F64Add() { src += indent + "f64.add"; } - void visit_F64Sub() { src += indent + "f64.sub"; } - void visit_F64Mul() { src += indent + "f64.mul"; } - void visit_F64Div() { src += indent + "f64.div"; } - void visit_F64Eq() { src += indent + "f64.eq"; } - void visit_F64Ne() { src += indent + "f64.ne"; } - void visit_F64Lt() { src += indent + "f64.lt"; } - void visit_F64Gt() { src += indent + "f64.gt"; } - void visit_F64Le() { src += indent + "f64.le"; } - void visit_F64Ge() { src += indent + "f64.ge"; } - void visit_F64Abs() { src += indent + "f64.abs"; } - void visit_F64Neg() { src += indent + "f64.neg"; } - void visit_F64Ceil() { src += indent + "f64.ceil"; } - void visit_F64Floor() { src += indent + "f64.floor"; } - void visit_F64Trunc() { src += indent + "f64.trunc"; } - void visit_F64Nearest() { src += indent + "f64.nearest"; } - void visit_F64Sqrt() { src += indent + "f64.sqrt"; } - void visit_F64Min() { src += indent + "f64.min"; } - void visit_F64Max() { src += indent + "f64.max"; } - void visit_F64Copysign() { src += indent + "f64.copysign"; } - - void visit_I32WrapI64() { src += indent + "i32.wrap_i64"; } - void visit_I32TruncF32S() { src += indent + "i32.trunc_f32_s"; } - void visit_I32TruncF64S() { src += indent + "i32.trunc_f64_s"; } - void visit_I64ExtendI32S() { src += indent + "i64.extend_i32_s"; } - void visit_I64TruncF32S() { src += indent + "i64.trunc_f32_s"; } - void visit_I64TruncF64S() { src += indent + "i64.trunc_f64_s"; } - void visit_F32ConvertI32S() { src += indent + "f32.convert_i32_s"; } - void visit_F32ConvertI64S() { src += indent + "f32.convert_i64_s"; } - void visit_F32DemoteF64() { src += indent + "f32.demote_f64"; } - void visit_F64ConvertI32S() { src += indent + "f64.convert_i32_s"; } - void visit_F64ConvertI64S() { src += indent + "f64.convert_i64_s"; } - void visit_F64PromoteF32() { src += indent + "f64.promote_f32"; } - void visit_F64DivS() { src += indent + "f64.div_s"; } - - void visit_I32Load(uint32_t mem_align, uint32_t mem_offset) { - src += indent + "i32.load offset=" + std::to_string(mem_offset) + - " align=" + std::to_string(1U << mem_align); - } - void visit_I64Load(uint32_t mem_align, uint32_t mem_offset) { - src += indent + "i64.load offset=" + std::to_string(mem_offset) + - " align=" + std::to_string(1U << mem_align); - } - void visit_F32Load(uint32_t mem_align, uint32_t mem_offset) { - src += indent + "f32.load offset=" + std::to_string(mem_offset) + - " align=" + std::to_string(1U << mem_align); - } - void visit_F64Load(uint32_t mem_align, uint32_t mem_offset) { - src += indent + "f64.load offset=" + std::to_string(mem_offset) + - " align=" + std::to_string(1U << mem_align); - } - void visit_I32Load8S(uint32_t mem_align, uint32_t mem_offset) { - src += indent + "i32.load8_s offset=" + std::to_string(mem_offset) + - " align=" + std::to_string(1U << mem_align); - } - void visit_I32Load8U(uint32_t mem_align, uint32_t mem_offset) { - src += indent + "i32.load8_u offset=" + std::to_string(mem_offset) + - " align=" + std::to_string(1U << mem_align); - } - void visit_I32Load16S(uint32_t mem_align, uint32_t mem_offset) { - src += indent + "i32.load16_s offset=" + std::to_string(mem_offset) + - " align=" + std::to_string(1U << mem_align); - } - void visit_I32Load16U(uint32_t mem_align, uint32_t mem_offset) { - src += indent + "i32.load16_u offset=" + std::to_string(mem_offset) + - " align=" + std::to_string(1U << mem_align); - } - void visit_I64Load8S(uint32_t mem_align, uint32_t mem_offset) { - src += indent + "i64.load8_s offset=" + std::to_string(mem_offset) + - " align=" + std::to_string(1U << mem_align); - } - void visit_I64Load8U(uint32_t mem_align, uint32_t mem_offset) { - src += indent + "i64.load8_u offset=" + std::to_string(mem_offset) + - " align=" + std::to_string(1U << mem_align); - } - void visit_I64Load16S(uint32_t mem_align, uint32_t mem_offset) { - src += indent + "i64.load16_s offset=" + std::to_string(mem_offset) + - " align=" + std::to_string(1U << mem_align); - } - void visit_I64Load16U(uint32_t mem_align, uint32_t mem_offset) { - src += indent + "i64.load16_u offset=" + std::to_string(mem_offset) + - " align=" + std::to_string(1U << mem_align); - } - void visit_I64Load32S(uint32_t mem_align, uint32_t mem_offset) { - src += indent + "i64.load32_s offset=" + std::to_string(mem_offset) + - " align=" + std::to_string(1U << mem_align); - } - void visit_I64Load32U(uint32_t mem_align, uint32_t mem_offset) { - src += indent + "i64.load32_u offset=" + std::to_string(mem_offset) + - " align=" + std::to_string(1U << mem_align); - } - void visit_I32Store(uint32_t mem_align, uint32_t mem_offset) { - src += indent + "i32.store offset=" + std::to_string(mem_offset) + - " align=" + std::to_string(1U << mem_align); - } - void visit_I64Store(uint32_t mem_align, uint32_t mem_offset) { - src += indent + "i64.store offset=" + std::to_string(mem_offset) + - " align=" + std::to_string(1U << mem_align); - } - void visit_F32Store(uint32_t mem_align, uint32_t mem_offset) { - src += indent + "f32.store offset=" + std::to_string(mem_offset) + - " align=" + std::to_string(1U << mem_align); - } - void visit_F64Store(uint32_t mem_align, uint32_t mem_offset) { - src += indent + "f64.store offset=" + std::to_string(mem_offset) + - " align=" + std::to_string(1U << mem_align); - } - void visit_I32Store8(uint32_t mem_align, uint32_t mem_offset) { - src += indent + "i32.store8 offset=" + std::to_string(mem_offset) + - " align=" + std::to_string(1U << mem_align); - } - void visit_I32Store16(uint32_t mem_align, uint32_t mem_offset) { - src += indent + "i32.store16 offset=" + std::to_string(mem_offset) + - " align=" + std::to_string(1U << mem_align); - } - void visit_I64Store8(uint32_t mem_align, uint32_t mem_offset) { - src += indent + "i64.store8 offset=" + std::to_string(mem_offset) + - " align=" + std::to_string(1U << mem_align); - } - void visit_I64Store16(uint32_t mem_align, uint32_t mem_offset) { - src += indent + "i64.store16 offset=" + std::to_string(mem_offset) + - " align=" + std::to_string(1U << mem_align); - } - void visit_I64Store32(uint32_t mem_align, uint32_t mem_offset) { - src += indent + "i64.store32 offset=" + std::to_string(mem_offset) + - " align=" + std::to_string(1U << mem_align); - } - - std::string get_escaped_str(const std::string &s, bool is_iov) { - std::string escaped_str = ""; - for (auto ch:s) { - if (!is_iov && ch >= 32) { - escaped_str += ch; - } else { - std::string byte(2, ' '); - snprintf(byte.data(), 3, "%02x", uint8_t(ch)); - escaped_str += "\\" + byte; - } - } - return escaped_str; - } - - std::string gen_wat() { - std::string result = "(module"; - std::string indent = "\n "; - for (uint32_t i = 0U; i < func_types.size(); i++) { - result += - indent + "(type (;" + std::to_string(i) + ";) (func (param"; - for (uint32_t j = 0; j < func_types[i].param_types.size(); j++) { - result += - " " + var_type_to_string[func_types[i].param_types.p[j]]; - } - result += ") (result"; - for (uint32_t j = 0; j < func_types[i].result_types.size(); j++) { - result += - " " + var_type_to_string[func_types[i].result_types.p[j]]; - } - result += ")))"; - } - - for (uint32_t i = 0; i < imports.size(); i++) { - result += indent + "(import \"" + imports[i].mod_name + "\" \"" + - imports[i].name + "\" "; - if (imports[i].kind == 0x00) { - result += "(func (;" + std::to_string(imports[i].type_idx) + - ";) (type " + std::to_string(imports[i].type_idx) + - ")))"; - } else if (imports[i].kind == 0x02) { - result += - "(memory (;0;) " + - std::to_string(imports[i].mem_page_size_limits.first) + - " " + - std::to_string(imports[i].mem_page_size_limits.second) + - "))"; - } - } - - for (uint32_t i = 0; i < globals.size(); i++) { - std::string global_initialization_insts = ""; - { - this->offset = globals.p[i].insts_start_idx; - this->indent = ""; - this->src = ""; - decode_instructions(); - global_initialization_insts = this->src; - } - std::string global_type = ((globals[i].mut == 0x00) ? var_type_to_string[globals[i].type]: - "(mut " + var_type_to_string[globals[i].type] + ")" ); - result += indent + "(global $" + std::to_string(i); - result += " " + global_type; - result += " (" + global_initialization_insts + "))"; - } - - for (uint32_t i = 0; i < type_indices.size(); i++) { - uint32_t func_index = type_indices.p[i]; - result += indent + "(func $" + std::to_string(func_index); - result += " (type " + std::to_string(func_index) + ") (param"; - for (uint32_t j = 0; j < func_types[func_index].param_types.size(); - j++) { - result += - " " + - var_type_to_string[func_types[func_index].param_types.p[j]]; - } - result += ") (result"; - for (uint32_t j = 0; j < func_types[func_index].result_types.size(); - j++) { - result += " " + var_type_to_string[func_types[func_index] - .result_types.p[j]]; - } - result += ")"; - result += indent + " (local"; - for (uint32_t j = 0; j < codes.p[i].locals.size(); j++) { - for (uint32_t k = 0; k < codes.p[i].locals.p[j].count; k++) { - result += - " " + var_type_to_string[codes.p[i].locals.p[j].type]; - } - } - result += ")"; - - { - this->offset = codes.p[i].insts_start_index; - this->indent = indent + " "; - this->src = ""; - decode_instructions(); - result += this->src; - } - - result += indent + ")"; - } - - for (uint32_t i = 0; i < memories.size(); i++) { - result += indent + "(memory (;" + std::to_string(i) + ";) " + - std::to_string(memories[i].first) + " " + - ((memories[i].second > 0) ? - std::to_string(memories[i].second) : "") + ")"; - } - - for (uint32_t i = 0; i < exports.size(); i++) { - result += indent + "(export \"" + exports.p[i].name + "\" (" + - kind_to_string[exports.p[i].kind] + " " + - std::to_string(exports.p[i].index) + "))"; - } - - for (uint32_t i = 0; i < data_segments.size(); i++) { - std::string date_segment_insts; - { - this->offset = data_segments.p[i].insts_start_index; - this->indent = ""; - this->src = ""; - decode_instructions(); - date_segment_insts = this->src; - } - result += indent + "(data (;" + std::to_string(i) + ";) (" + - date_segment_insts + ") \"" + - get_escaped_str(data_segments[i].text, (i % 2 == 0)) + "\")"; - } - - result += "\n)\n"; - - return result; - } -}; - -} // namespace wasm - -Result wasm_to_wat(Vec &wasm_bytes, Allocator &al, - diag::Diagnostics &diagnostics) { - wasm::WATVisitor wasm_generator(al, diagnostics, wasm_bytes); - std::string wat; - - try { - wasm_generator.decode_wasm(); - } catch (const CodeGenError &e) { - diagnostics.diagnostics.push_back(e.d); - return Error(); - } - - wat = wasm_generator.gen_wat(); - - return wat; -} - -} // namespace LCompilers diff --git a/src/libasr/codegen/wasm_to_wat.h b/src/libasr/codegen/wasm_to_wat.h deleted file mode 100644 index 51f1183f30..0000000000 --- a/src/libasr/codegen/wasm_to_wat.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef LFORTRAN_WASM_TO_WAT_H -#define LFORTRAN_WASM_TO_WAT_H - -#include - -namespace LCompilers { - -Result wasm_to_wat(Vec &wasm_bytes, Allocator &al, - diag::Diagnostics &diagnostics); - -} // namespace LCompilers - -#endif // LFORTRAN_WASM_TO_WAT_H diff --git a/src/libasr/codegen/wasm_to_x64.cpp b/src/libasr/codegen/wasm_to_x64.cpp deleted file mode 100644 index dd5fb4711b..0000000000 --- a/src/libasr/codegen/wasm_to_x64.cpp +++ /dev/null @@ -1,734 +0,0 @@ -#include -#include -#include - -#include -#include -#include -#include - -namespace LCompilers { - -namespace wasm { - -/* - -This X64Visitor uses stack to pass arguments and return values from functions. -Since in X64, instructions operate on registers (and not on stack), -for every instruction we pop elements from top of stack and store them into -registers. After operating on the registers, the result value is then -pushed back onto the stack. - -One of the reasons to use stack to pass function arguments is that, -it allows us to define and call functions with any number of parameters. -As registers are limited in number, if we use them to pass function arguments, -the number of arguments we could pass to a function would get limited by -the number of registers available with the CPU. - -*/ -enum Block { - LOOP = 0, - IF = 1 -}; - -class X64Visitor : public WASMDecoder, - public WASM_INSTS_VISITOR::BaseWASMVisitor { - public: - X86Assembler &m_a; - uint32_t cur_func_idx; - uint32_t block_id; - uint32_t NO_OF_IMPORTS; - std::vector> blocks; - std::map label_to_str; - std::map double_consts; - - X64Visitor(X86Assembler &m_a, Allocator &al, - diag::Diagnostics &diagonostics, Vec &code) - : WASMDecoder(al, diagonostics), - BaseWASMVisitor(code, 0U /* temporary offset */), - m_a(m_a) { - wasm_bytes.from_pointer_n(code.data(), code.size()); - block_id = 1; - NO_OF_IMPORTS = 0; - } - - void visit_Return() { - // Restore stack - m_a.asm_mov_r64_r64(X64Reg::rsp, X64Reg::rbp); - m_a.asm_pop_r64(X64Reg::rbp); - m_a.asm_ret(); - } - - void visit_Unreachable() {} - void visit_EmtpyBlockType() {} - void visit_Drop() { m_a.asm_pop_r64(X64Reg::rax); } - - void call_imported_function(uint32_t func_idx) { - - switch (func_idx) { - case 0: { // proc_exit - /* - TODO: This way increases the number of intructions. - There is a possibility that we can wrap these statements - with some add label and then just jump/call to that label - */ - m_a.asm_pop_r64(X64Reg::rdi); // get exit code from stack top - m_a.asm_mov_r64_imm64(X64Reg::rax, 60); // sys_exit - m_a.asm_syscall(); // syscall - break; - } - case 1: { // fd_write - /* - TODO: This way increases the number of intructions. - There is a possibility that we can wrap these statements - with some add label and then just jump/call to that label - */ - - m_a.asm_pop_r64(X64Reg::r11); // mem_loc to write return value (not usefull for us currently) - m_a.asm_pop_r64(X64Reg::r12); // no of iov vectors (always emitted 1 by wasm, not usefull for us currently) - m_a.asm_pop_r64(X64Reg::r13); // mem_loc to string iov vector - m_a.asm_pop_r64(X64Reg::r14); // filetypes (1 for stdout, not usefull for us currently) - - m_a.asm_mov_r64_label(X64Reg::rbx, "base_memory"); - m_a.asm_add_r64_r64(X64Reg::rbx, X64Reg::r13); - - m_a.asm_mov_r64_imm64(X64Reg::rax, 0); - m_a.asm_mov_r64_imm64(X64Reg::rdx, 0); - // TODO: Currently this uses a combination of i32 and i64 registers. Fix it in upcoming PRs. - X86Reg base = X86Reg::ebx; - m_a.asm_mov_r32_m32(X86Reg::eax, &base, nullptr, 1, 0); // location - m_a.asm_mov_r32_m32(X86Reg::edx, &base, nullptr, 1, 4); // length - - { - // write system call - m_a.asm_mov_r64_label(X64Reg::rsi, "base_memory"); - m_a.asm_add_r64_r64(X64Reg::rsi, X64Reg::rax); // base_memory + location - m_a.asm_mov_r64_imm64(X64Reg::rax, 1); // system call no (1 for write) - m_a.asm_mov_r64_imm64(X64Reg::rdi, 1); // stdout_file no - // rsi stores location, length is already stored in rdx - m_a.asm_syscall(); - - m_a.asm_push_r64(X64Reg::rax); // push return value onto stack - } - break; - } - default: { - std::cerr << "Unsupported func_idx\n"; - } - } - } - - void visit_Call(uint32_t func_idx) { - if (func_idx < NO_OF_IMPORTS) { - call_imported_function(func_idx); - return; - } - - func_idx -= NO_OF_IMPORTS; // adjust function index as per imports - m_a.asm_call_label(exports[func_idx + 1 /* offset by 1 becaz of mem export */].name); - - // Pop the passed function arguments - wasm::FuncType func_type = func_types[type_indices[func_idx]]; - m_a.asm_add_r64_imm32(X64Reg::rsp, 8 * func_type.param_types.size()); // pop the passed argument - - // Adjust the return values of the called function - X64Reg base = X64Reg::rsp; - for (uint32_t i = 0; i < func_type.result_types.size(); i++) { - // take value into eax - m_a.asm_mov_r64_m64(X64Reg::rax, &base, nullptr, 1, - -8 * (func_type.param_types.size() + 2 + - codes[func_idx].locals.size() + 1)); - - // push eax value onto stack - m_a.asm_push_r64(X64Reg::rax); - } - } - - void visit_Loop() { - std::string label = std::to_string(block_id); - blocks.push_back({block_id++, Block::LOOP}); - /* - The loop statement starts with `loop.head`. The `loop.body` and - `loop.branch` are enclosed within the `if.block`. If the condition - fails, the loop is exited through `else.block`. - .head - .If - # Statements - .Br to loop head - .Else - .endIf - .end - */ - m_a.add_label(".loop.head_" + label); - { - decode_instructions(); - } - // end - m_a.add_label(".loop.end_" + label); - blocks.pop_back(); - } - - void visit_Br(uint32_t labelidx) { - // Branch is used to jump to the `loop.head` or `loop.end`. - - uint32_t b_id; - Block block_type; - std::tie(b_id, block_type) = blocks[blocks.size() - 1 - labelidx]; - std::string label = std::to_string(b_id); - switch (block_type) { - /* - From WebAssembly Docs: - The exact effect of branch depends on that control construct. - In case of block or if, it is a forward jump, resuming execution after the matching end. - In case of loop, it is a backward jump to the beginning of the loop. - */ - case Block::LOOP: m_a.asm_jmp_label(".loop.head_" + label); break; - case Block::IF: m_a.asm_jmp_label(".endif_" + label); break; - } - } - - void visit_If() { - std::string label = std::to_string(block_id); - blocks.push_back({block_id++, Block::IF}); - m_a.asm_pop_r64(X64Reg::rax); // now `rax` contains the logical value (true = 1, false = 0) of the if condition - m_a.asm_cmp_r64_imm8(X64Reg::rax, 1); - m_a.asm_je_label(".then_" + label); - m_a.asm_jmp_label(".else_" + label); - m_a.add_label(".then_" + label); - { - decode_instructions(); - } - m_a.add_label(".endif_" + label); - blocks.pop_back(); - } - - void visit_Else() { - std::string label = std::to_string(blocks.back().first); - m_a.asm_jmp_label(".endif_" + label); - m_a.add_label(".else_" + label); - } - - void visit_GlobalGet(uint32_t globalidx) { - std::string loc = "global_" + std::to_string(globalidx); - std::string var_type = var_type_to_string[globals[globalidx].type]; - - X64Reg base = X64Reg::rbx; - m_a.asm_mov_r64_label(X64Reg::rbx, loc); - if (var_type == "i32" || var_type == "i64") { - m_a.asm_mov_r64_m64(X64Reg::rax, &base, nullptr, 1, 0); - m_a.asm_push_r64(X64Reg::rax); - } else if (var_type == "f32" || var_type == "f64") { - m_a.asm_movsd_r64_m64(X64FReg::xmm0, &base, nullptr, 1, 0); - m_a.asm_sub_r64_imm32(X64Reg::rsp, 8); // create space for value to be fetched - X64Reg stack_top = X64Reg::rsp; - m_a.asm_movsd_m64_r64(&stack_top, nullptr, 1, 0, X64FReg::xmm0); - } else { - throw AssemblerError("WASM_X64: Var type not supported"); - } - } - - void visit_GlobalSet(uint32_t globalidx) { - if (globals[globalidx].mut == 0) { - throw AssemblerError("Attempt to modify unmutable global variable"); - } - - std::string loc = "global_" + std::to_string(globalidx); - std::string var_type = var_type_to_string[globals[globalidx].type]; - - X64Reg base = X64Reg::rbx; - m_a.asm_mov_r64_label(X64Reg::rbx, loc); - if (var_type == "i32" || var_type == "i64") { - m_a.asm_pop_r64(X64Reg::rax); - m_a.asm_mov_m64_r64(&base, nullptr, 1, 0, X64Reg::rax); - } else if (var_type == "f32" || var_type == "f64") { - X64Reg stack_top = X64Reg::rsp; - m_a.asm_movsd_r64_m64(X64FReg::xmm0, &stack_top, nullptr, 1, 0); - m_a.asm_add_r64_imm32(X64Reg::rsp, 8); // deallocate space - m_a.asm_movsd_m64_r64(&base, nullptr, 1, 0, X64FReg::xmm0); - } else { - throw AssemblerError("WASM_X64: Var type not supported"); - } - } - - void visit_LocalGet(uint32_t localidx) { - X64Reg base = X64Reg::rbp; - auto cur_func_param_type = func_types[type_indices[cur_func_idx]]; - int no_of_params = (int)cur_func_param_type.param_types.size(); - if ((int)localidx < no_of_params) { - std::string var_type = var_type_to_string[cur_func_param_type.param_types[localidx]]; - if (var_type == "i32" || var_type == "i64") { - m_a.asm_mov_r64_m64(X64Reg::rax, &base, nullptr, 1, 8 * (2 + no_of_params - (int)localidx - 1)); - m_a.asm_push_r64(X64Reg::rax); - } else if (var_type == "f32" || var_type == "f64") { - m_a.asm_sub_r64_imm32(X64Reg::rsp, 8); // create space for value to be fetched - m_a.asm_movsd_r64_m64(X64FReg::xmm0, &base, nullptr, 1, 8 * (2 + no_of_params - (int)localidx - 1)); - X64Reg stack_top = X64Reg::rsp; - m_a.asm_movsd_m64_r64(&stack_top, nullptr, 1, 0, X64FReg::xmm0); - } else { - throw AssemblerError("WASM_X64: Var type not supported"); - } - } else { - localidx -= no_of_params; - std::string var_type = var_type_to_string[codes[cur_func_idx].locals[localidx].type]; - if (var_type == "i32" || var_type == "i64") { - m_a.asm_mov_r64_m64(X64Reg::rax, &base, nullptr, 1, -8 * (1 + (int)localidx)); - m_a.asm_push_r64(X64Reg::rax); - } else if (var_type == "f32" || var_type == "f64") { - m_a.asm_sub_r64_imm32(X64Reg::rsp, 8); // create space for value to be fetched - m_a.asm_movsd_r64_m64(X64FReg::xmm0, &base, nullptr, 1, -8 * (1 + (int)localidx)); - X64Reg stack_top = X64Reg::rsp; - m_a.asm_movsd_m64_r64(&stack_top, nullptr, 1, 0, X64FReg::xmm0); - } else { - throw AssemblerError("WASM_X64: Var type not supported"); - } - } - } - - void visit_LocalSet(uint32_t localidx) { - X64Reg base = X64Reg::rbp; - auto cur_func_param_type = func_types[type_indices[cur_func_idx]]; - int no_of_params = (int)cur_func_param_type.param_types.size(); - if ((int)localidx < no_of_params) { - std::string var_type = var_type_to_string[cur_func_param_type.param_types[localidx]]; - if (var_type == "i32" || var_type == "i64") { - m_a.asm_pop_r64(X64Reg::rax); - m_a.asm_mov_m64_r64(&base, nullptr, 1, 8 * (2 + no_of_params - (int)localidx - 1), X64Reg::rax); - } else if (var_type == "f32" || var_type == "f64") { - X64Reg stack_top = X64Reg::rsp; - m_a.asm_movsd_r64_m64(X64FReg::xmm0, &stack_top, nullptr, 1, 0); - m_a.asm_movsd_m64_r64(&base, nullptr, 1, 8 * (2 + no_of_params - (int)localidx - 1), X64FReg::xmm0); - m_a.asm_add_r64_imm32(X64Reg::rsp, 8); // remove from stack top - } else { - throw AssemblerError("WASM_X64: Var type not supported"); - } - } else { - localidx -= no_of_params; - std::string var_type = var_type_to_string[codes[cur_func_idx].locals[localidx].type]; - if (var_type == "i32" || var_type == "i64") { - m_a.asm_pop_r64(X64Reg::rax); - m_a.asm_mov_m64_r64(&base, nullptr, 1, -8 * (1 + (int)localidx), X64Reg::rax); - } else if (var_type == "f32" || var_type == "f64") { - X64Reg stack_top = X64Reg::rsp; - m_a.asm_movsd_r64_m64(X64FReg::xmm0, &stack_top, nullptr, 1, 0); - m_a.asm_movsd_m64_r64(&base, nullptr, 1, -8 * (1 + (int)localidx), X64FReg::xmm0); - m_a.asm_add_r64_imm32(X64Reg::rsp, 8); // remove from stack top - } else { - throw AssemblerError("WASM_X64: Var type not supported"); - } - } - } - - void visit_I32Const(int32_t value) { visit_I64Const(int64_t(value)); } - - void visit_I32Add() { visit_I64Add(); } - void visit_I32Sub() { visit_I64Sub(); } - void visit_I32Mul() { visit_I64Mul(); } - void visit_I32DivS() { visit_I64DivS(); } - - void visit_I32And() { visit_I64And(); } - void visit_I32Or() { visit_I64Or(); } - void visit_I32Xor() { visit_I64Xor(); } - void visit_I32Shl() { visit_I64Shl(); } - void visit_I32ShrS() { visit_I64ShrS(); } - - void visit_I32Eqz() { visit_I64Eqz(); } - void visit_I32Eq() { visit_I64Eq(); } - void visit_I32GtS() { visit_I64GtS(); } - void visit_I32GeS() { visit_I64GeS(); } - void visit_I32LtS() { visit_I64LtS(); } - void visit_I32LeS() { visit_I64LeS(); } - void visit_I32Ne() { visit_I64Ne(); } - - void visit_I32WrapI64() { } // empty, since i32's and i64's are considered similar currently. - - void visit_I64Const(int64_t value) { - m_a.asm_mov_r64_imm64(X64Reg::rax, labs((int64_t)value)); - if (value < 0) m_a.asm_neg_r64(X64Reg::rax); - m_a.asm_push_r64(X64Reg::rax); - } - - template - void handleI64Opt(F && f) { - m_a.asm_pop_r64(X64Reg::rbx); - m_a.asm_pop_r64(X64Reg::rax); - f(); - m_a.asm_push_r64(X64Reg::rax); - } - - void visit_I64Add() { - handleI64Opt([&](){ m_a.asm_add_r64_r64(X64Reg::rax, X64Reg::rbx);}); - } - void visit_I64Sub() { - handleI64Opt([&](){ m_a.asm_sub_r64_r64(X64Reg::rax, X64Reg::rbx);}); - } - void visit_I64Mul() { - handleI64Opt([&](){ m_a.asm_mul_r64(X64Reg::rbx);}); - } - void visit_I64DivS() { - handleI64Opt([&](){ - m_a.asm_mov_r64_imm64(X64Reg::rdx, 0); - m_a.asm_div_r64(X64Reg::rbx);}); - } - - void visit_I64And() { - handleI64Opt([&](){ m_a.asm_and_r64_r64(X64Reg::rax, X64Reg::rbx);}); - } - - void visit_I64Or() { - handleI64Opt([&](){ m_a.asm_or_r64_r64(X64Reg::rax, X64Reg::rbx);}); - } - - void visit_I64Xor() { - handleI64Opt([&](){ m_a.asm_xor_r64_r64(X64Reg::rax, X64Reg::rbx);}); - } - - void visit_I64RemS() { - m_a.asm_pop_r64(X64Reg::rbx); - m_a.asm_pop_r64(X64Reg::rax); - m_a.asm_mov_r64_imm64(X64Reg::rdx, 0); - m_a.asm_div_r64(X64Reg::rbx); - m_a.asm_push_r64(X64Reg::rdx); - } - - void visit_I64Store(uint32_t /*mem_align*/, uint32_t /*mem_offset*/) { - m_a.asm_pop_r64(X64Reg::rbx); - m_a.asm_pop_r64(X64Reg::rax); - // Store value rbx at location rax - X64Reg base = X64Reg::rax; - m_a.asm_mov_m64_r64(&base, nullptr, 1, 0, X64Reg::rbx); - } - - void visit_I64Shl() { - m_a.asm_pop_r64(X64Reg::rcx); - m_a.asm_pop_r64(X64Reg::rax); - m_a.asm_shl_r64_cl(X64Reg::rax); - m_a.asm_push_r64(X64Reg::rax); - } - void visit_I64ShrS() { - m_a.asm_pop_r64(X64Reg::rcx); - m_a.asm_pop_r64(X64Reg::rax); - m_a.asm_sar_r64_cl(X64Reg::rax); - m_a.asm_push_r64(X64Reg::rax); - } - - void visit_I64Eqz() { - m_a.asm_mov_r64_imm64(X64Reg::rax, 0); - m_a.asm_push_r64(X64Reg::rax); - handle_I64Compare<&X86Assembler::asm_je_label>(); - } - - using JumpFn = void(X86Assembler::*)(const std::string&); - template - void handle_I64Compare() { - std::string label = std::to_string(offset); - m_a.asm_pop_r64(X64Reg::rbx); - m_a.asm_pop_r64(X64Reg::rax); - // `rax` and `rbx` contain the left and right operands, respectively - m_a.asm_cmp_r64_r64(X64Reg::rax, X64Reg::rbx); - - (m_a.*T)(".compare_1" + label); - - // if the `compare` condition in `true`, jump to compare_1 - // and assign `1` else assign `0` - m_a.asm_push_imm8(0); - m_a.asm_jmp_label(".compare.end_" + label); - m_a.add_label(".compare_1" + label); - m_a.asm_push_imm8(1); - m_a.add_label(".compare.end_" + label); - } - - void visit_I64Eq() { handle_I64Compare<&X86Assembler::asm_je_label>(); } - void visit_I64GtS() { handle_I64Compare<&X86Assembler::asm_jg_label>(); } - void visit_I64GeS() { handle_I64Compare<&X86Assembler::asm_jge_label>(); } - void visit_I64LtS() { handle_I64Compare<&X86Assembler::asm_jl_label>(); } - void visit_I64LeS() { handle_I64Compare<&X86Assembler::asm_jle_label>(); } - void visit_I64Ne() { handle_I64Compare<&X86Assembler::asm_jne_label>(); } - - void visit_I64TruncF64S() { - X64Reg stack_top = X64Reg::rsp; - m_a.asm_movsd_r64_m64(X64FReg::xmm0, &stack_top, nullptr, 1, 0); // load into floating-point register - m_a.asm_add_r64_imm32(X64Reg::rsp, 8); // increment stack and deallocate space - m_a.asm_cvttsd2si_r64_r64(X64Reg::rax, X64FReg::xmm0); // rax now contains value int(xmm0) - m_a.asm_push_r64(X64Reg::rax); - } - - void visit_I64ExtendI32S() { } // empty, since all i32's are already considered as i64's currently. - - std::string float_to_str(double z) { - std::string float_str = ""; - std::ostringstream strs; - strs << z; - for (auto ch:strs.str()) { - if (ch == '-') { - float_str += "neg_"; - } else if (ch == '+') { - float_str += "_plus_"; - } else if (ch == '.') { - float_str += "_dot_"; - } else { - float_str += ch; - } - } - return float_str; - } - - void visit_F64Const(double z) { - std::string label = "float_" + float_to_str(z); - double_consts[label] = z; - m_a.asm_mov_r64_label(X64Reg::rax, label); - X64Reg label_reg = X64Reg::rax; - m_a.asm_movsd_r64_m64(X64FReg::xmm0, &label_reg, nullptr, 1, 0); // load into floating-point register - m_a.asm_sub_r64_imm32(X64Reg::rsp, 8); // decrement stack and create space - X64Reg stack_top = X64Reg::rsp; - m_a.asm_movsd_m64_r64(&stack_top, nullptr, 1, 0, X64FReg::xmm0); // store float on integer stack top; - } - - using F64OptFn = void(X86Assembler::*)(X64FReg, X64FReg); - template - void handleF64Operations() { - X64Reg stack_top = X64Reg::rsp; - // load second operand into floating-point register - m_a.asm_movsd_r64_m64(X64FReg::xmm1, &stack_top, nullptr, 1, 0); - m_a.asm_add_r64_imm32(X64Reg::rsp, 8); // pop the argument - // load first operand into floating-point register - m_a.asm_movsd_r64_m64(X64FReg::xmm0, &stack_top, nullptr, 1, 0); - m_a.asm_add_r64_imm32(X64Reg::rsp, 8); // pop the argument - - (m_a.*T)(X64FReg::xmm0, X64FReg::xmm1); - - m_a.asm_sub_r64_imm32(X64Reg::rsp, 8); // decrement stack and create space - // store float result back on stack top; - m_a.asm_movsd_m64_r64(&stack_top, nullptr, 1, 0, X64FReg::xmm0); - } - - void visit_F64Add() { handleF64Operations<&X86Assembler::asm_addsd_r64_r64>(); } - void visit_F64Sub() { handleF64Operations<&X86Assembler::asm_subsd_r64_r64>(); } - void visit_F64Mul() { handleF64Operations<&X86Assembler::asm_mulsd_r64_r64>(); } - void visit_F64Div() { handleF64Operations<&X86Assembler::asm_divsd_r64_r64>(); } - - void handleF64Compare(Fcmp cmp) { - X64Reg stack_top = X64Reg::rsp; - // load second operand into floating-point register - m_a.asm_movsd_r64_m64(X64FReg::xmm1, &stack_top, nullptr, 1, 0); - m_a.asm_add_r64_imm32(X64Reg::rsp, 8); // pop the argument - // load first operand into floating-point register - m_a.asm_movsd_r64_m64(X64FReg::xmm0, &stack_top, nullptr, 1, 0); - m_a.asm_add_r64_imm32(X64Reg::rsp, 8); // pop the argument - - m_a.asm_cmpsd_r64_r64(X64FReg::xmm0, X64FReg::xmm1, cmp); - /* From Assembly Docs: - The result of the compare is a 64-bit value of all 1s (TRUE) or all 0s (FALSE). - */ - m_a.asm_pmovmskb_r32_r64(X86Reg::eax, X64FReg::xmm0); - m_a.asm_and_r64_imm8(X64Reg::rax, 1); - m_a.asm_push_r64(X64Reg::rax); - } - - void visit_F64Eq() { handleF64Compare(Fcmp::eq); } - void visit_F64Gt() { handleF64Compare(Fcmp::gt); } - void visit_F64Ge() { handleF64Compare(Fcmp::ge); } - void visit_F64Lt() { handleF64Compare(Fcmp::lt); } - void visit_F64Le() { handleF64Compare(Fcmp::le); } - void visit_F64Ne() { handleF64Compare(Fcmp::ne); } - - void visit_F64ConvertI64S() { - m_a.asm_pop_r64(X64Reg::rax); - m_a.asm_cvtsi2sd_r64_r64(X64FReg::xmm0, X64Reg::rax); - m_a.asm_sub_r64_imm32(X64Reg::rsp, 8); // decrement stack and create space - X64Reg stack_top = X64Reg::rsp; - m_a.asm_movsd_m64_r64(&stack_top, nullptr, 1, 0, X64FReg::xmm0); // store float on integer stack top; - } - - void visit_F64ConvertI32S() { visit_F64ConvertI64S(); } // I32's considered as I64's currently - void visit_F64PromoteF32() { } // F32's considered as F64's currently - - void visit_F64Neg() { - visit_F64Const(double(-1.0)); - visit_F64Mul(); - } - - void visit_F64Sqrt() { - X64Reg stack_top = X64Reg::rsp; - // load operand into floating-point register - m_a.asm_movsd_r64_m64(X64FReg::xmm1, &stack_top, nullptr, 1, 0); - m_a.asm_add_r64_imm32(X64Reg::rsp, 8); // pop the argument - - m_a.asm_sqrtsd_r64_r64(X64FReg::xmm0, X64FReg::xmm1); // perform sqrt operation - - m_a.asm_sub_r64_imm32(X64Reg::rsp, 8); // decrement stack and create space - m_a.asm_movsd_m64_r64(&stack_top, nullptr, 1, 0, X64FReg::xmm0); // store the result on stack top; - } - - - void visit_F32Const(float z) { visit_F64Const(double(z)); } - - void visit_F32Add() { visit_F64Add(); } - void visit_F32Sub() { visit_F64Sub(); } - void visit_F32Mul() { visit_F64Mul(); } - void visit_F32Div() { visit_F64Div(); } - - void visit_F32Eq() { visit_F64Eq(); } - void visit_F32Gt() { visit_F64Gt(); } - void visit_F32Ge() { visit_F64Ge(); } - void visit_F32Lt() { visit_F64Lt(); } - void visit_F32Le() { visit_F64Le(); } - void visit_F32Ne() { visit_F64Ne(); } - - void visit_F32ConvertI64S() { visit_F64ConvertI32S(); } - void visit_F32Neg() { visit_F64Neg(); } - void visit_F32Sqrt() { visit_F64Sqrt(); } - - void gen_x64_bytes() { - emit_elf64_header(m_a); - - // declare compile-time strings - std::string base_memory = " "; /* in wasm backend, memory starts after 4 bytes*/ - for (uint32_t i = 0; i < data_segments.size(); i++) { - base_memory += data_segments[i].text; - } - label_to_str["base_memory"] = base_memory; - - NO_OF_IMPORTS = imports.size(); - - m_a.align_by_byte(0x1000); - m_a.add_label("text_segment_start"); - for (uint32_t idx = 0; idx < type_indices.size(); idx++) { - m_a.add_label(exports[idx + 1].name); - { - // Initialize the stack - m_a.asm_push_r64(X64Reg::rbp); - m_a.asm_mov_r64_r64(X64Reg::rbp, X64Reg::rsp); - - // Allocate space for local variables - // TODO: locals is an array where every element has a count (currently wasm emits count = 1 always) - m_a.asm_sub_r64_imm32(X64Reg::rsp, 8 * codes[idx].locals.size()); - - offset = codes[idx].insts_start_index; - cur_func_idx = idx; - decode_instructions(); - } - - } - - for (auto &d : double_consts) { - emit_double_const(m_a, d.first, d.second); - } - - m_a.add_label("text_segment_end"); - - m_a.align_by_byte(0x1000); - m_a.add_label("data_segment_start"); - for (auto &s : label_to_str) { - emit_data_string(m_a, s.first, s.second); - } - - for (size_t i = 0; i < globals.size(); i++) { - uint32_t tmp_offset = globals[i].insts_start_idx; - wasm::read_b8(wasm_bytes, tmp_offset); // read byte for i32/i64/f32/f64.const - - std::string global_loc = "global_" + std::to_string(i); - switch (globals[i].type) { - case 0x7F: { - int32_t val = wasm::read_i32(wasm_bytes, offset); - emit_i64_const(m_a, global_loc, val); - break; - } - case 0x7E: { - int64_t val = wasm::read_i64(wasm_bytes, offset); - emit_i64_const(m_a, global_loc, val); - break; - } - case 0x7D: { - float val = wasm::read_f32(wasm_bytes, offset); - emit_double_const(m_a, global_loc, val); - break; - } - case 0x7C: { - double val = wasm::read_f64(wasm_bytes, offset); - emit_double_const(m_a, global_loc, val); - break; - } - default: throw CodeGenError("decode_global_section: Unsupport global type"); break; - } - } - m_a.add_label("data_segment_end"); - - emit_elf64_footer(m_a); - } -}; - -} // namespace wasm - -Result wasm_to_x64(Vec &wasm_bytes, Allocator &al, - const std::string &filename, bool time_report, - diag::Diagnostics &diagnostics) { - int time_decode_wasm = 0; - int time_gen_x64_bytes = 0; - int time_save = 0; - int time_verify = 0; - - X86Assembler m_a(al, true /* bits 64 */); - - wasm::X64Visitor x64_visitor(m_a, al, diagnostics, wasm_bytes); - - { - auto t1 = std::chrono::high_resolution_clock::now(); - try { - x64_visitor.decode_wasm(); - } catch (const CodeGenError &e) { - diagnostics.diagnostics.push_back(e.d); - return Error(); - } - auto t2 = std::chrono::high_resolution_clock::now(); - time_decode_wasm = - std::chrono::duration_cast(t2 - t1) - .count(); - } - - { - auto t1 = std::chrono::high_resolution_clock::now(); - x64_visitor.gen_x64_bytes(); - auto t2 = std::chrono::high_resolution_clock::now(); - time_gen_x64_bytes = - std::chrono::duration_cast(t2 - t1) - .count(); - } - - { - auto t1 = std::chrono::high_resolution_clock::now(); - m_a.verify(); - auto t2 = std::chrono::high_resolution_clock::now(); - time_verify = - std::chrono::duration_cast(t2 - t1) - .count(); - } - - { - auto t1 = std::chrono::high_resolution_clock::now(); - m_a.save_binary(filename); - auto t2 = std::chrono::high_resolution_clock::now(); - time_save = - std::chrono::duration_cast(t2 - t1) - .count(); - } - - //! Helpful for debugging - // std::cout << x64_visitor.m_a.get_asm() << std::endl; - - if (time_report) { - std::cout << "Codegen Time report:" << std::endl; - std::cout << "Decode wasm: " << std::setw(5) << time_decode_wasm - << std::endl; - std::cout << "Generate asm: " << std::setw(5) << time_gen_x64_bytes - << std::endl; - std::cout << "Verify: " << std::setw(5) << time_verify - << std::endl; - std::cout << "Save: " << std::setw(5) << time_save << std::endl; - int total = - time_decode_wasm + time_gen_x64_bytes + time_verify + time_save; - std::cout << "Total: " << std::setw(5) << total << std::endl; - } - return 0; -} - -} // namespace LCompilers diff --git a/src/libasr/codegen/wasm_to_x64.h b/src/libasr/codegen/wasm_to_x64.h deleted file mode 100644 index ab19a4929c..0000000000 --- a/src/libasr/codegen/wasm_to_x64.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef LFORTRAN_WASM_TO_X64_H -#define LFORTRAN_WASM_TO_X64_H - -#include - -namespace LCompilers { - -Result wasm_to_x64(Vec &wasm_bytes, Allocator &al, - const std::string &filename, bool time_report, - diag::Diagnostics &diagnostics); - -} // namespace LCompilers - -#endif // LFORTRAN_WASM_TO_X64_H diff --git a/src/libasr/codegen/wasm_to_x86.cpp b/src/libasr/codegen/wasm_to_x86.cpp deleted file mode 100644 index 1c51cef3e3..0000000000 --- a/src/libasr/codegen/wasm_to_x86.cpp +++ /dev/null @@ -1,570 +0,0 @@ -#include -#include -#include - -#include -#include -#include -#include - -namespace LCompilers { - -namespace wasm { - -/* - -This X86Visitor uses stack to pass arguments and return values from functions. -Since in X86, instructions operate on registers (and not on stack), -for every instruction we pop elements from top of stack and store them into -registers. After operating on the registers, the result value is then -pushed back onto the stack. - -One of the reasons to use stack to pass function arguments is that, -it allows us to define and call functions with any number of parameters. -As registers are limited in number, if we use them to pass function arguments, -the number of arguments we could pass to a function would get limited by -the number of registers available with the CPU. - -*/ - -enum Block { - LOOP = 0, - IF = 1 -}; - -class X86Visitor : public WASMDecoder, - public WASM_INSTS_VISITOR::BaseWASMVisitor { - public: - X86Assembler &m_a; - uint32_t cur_func_idx; - uint32_t block_id; - uint32_t NO_OF_IMPORTS; - std::vector> blocks; - std::map label_to_str; - std::map float_consts; - - X86Visitor(X86Assembler &m_a, Allocator &al, - diag::Diagnostics &diagonostics, Vec &code) - : WASMDecoder(al, diagonostics), - BaseWASMVisitor(code, 0U /* temporary offset */), - m_a(m_a) { - wasm_bytes.from_pointer_n(code.data(), code.size()); - block_id = 1; - NO_OF_IMPORTS = 0; - } - - void visit_Unreachable() {} - - void visit_EmtpyBlockType() {} - - void visit_Drop() { m_a.asm_pop_r32(X86Reg::eax); } - - void visit_Return() { - // Restore stack - m_a.asm_mov_r32_r32(X86Reg::esp, X86Reg::ebp); - m_a.asm_pop_r32(X86Reg::ebp); - m_a.asm_ret(); - } - - void call_imported_function(uint32_t func_index) { - switch (func_index) { - case 0: { // proc_exit - m_a.asm_jmp_label("my_exit"); - break; - } - case 1: { // fd_write - /* - TODO: This way increases the number of intructions. - There is a possibility that we can wrap these statements - with some add label and then just jump/call to that label - */ - - m_a.asm_pop_r32(X86Reg::eax); // mem_loc to write return value (not usefull for us currently) - m_a.asm_pop_r32(X86Reg::eax); // no of iov vectors (always emitted 1 by wasm, not usefull for us currently) - m_a.asm_pop_r32(X86Reg::eax); // mem_loc to string iov vector - m_a.asm_pop_r32(X86Reg::ebx); // filetypes (1 for stdout) - - m_a.asm_mov_r32_label(X86Reg::esi, "base_memory"); - m_a.asm_add_r32_r32(X86Reg::esi, X86Reg::eax); - - X86Reg base = X86Reg::esi; - m_a.asm_mov_r32_m32(X86Reg::eax, &base, nullptr, 1, 0); // location - m_a.asm_mov_r32_m32(X86Reg::edx, &base, nullptr, 1, 4); // length - - { - // ssize_t write(int fd, const void *buf, size_t count); - m_a.asm_mov_r32_imm32(X86Reg::ebx, 1); // fd (stdout) - m_a.asm_mov_r32_label(X86Reg::ecx, "base_memory"); - m_a.asm_add_r32_r32(X86Reg::ecx, X86Reg::eax); - m_a.asm_mov_r32_imm32(X86Reg::eax, 4); // sys_write - // ecx stores location, length is already stored in edx - m_a.asm_int_imm8(0x80); - - m_a.asm_push_r32(X86Reg::eax); // push return value onto stack - } - - - break; - } - default: { - std::cerr << "Unsupported func_index: " << func_index << std::endl; - } - } - } - - void visit_Call(uint32_t func_index) { - if (func_index < NO_OF_IMPORTS) { - call_imported_function(func_index); - return; - } - - func_index -= NO_OF_IMPORTS; - m_a.asm_call_label(exports[func_index + 1 /* offset by 1 becaz of mem export */].name); - - // Pop the passed function arguments - wasm::FuncType func_type = - func_types[type_indices[func_index]]; - m_a.asm_add_r32_imm32(X86Reg::esp, 4 * func_type.param_types.size()); // pop the passed arguments - - // Adjust the return values of the called function - X86Reg base = X86Reg::esp; - for (uint32_t i = 0; i < func_type.result_types.size(); i++) { - // take value into eax - m_a.asm_mov_r32_m32( - X86Reg::eax, &base, nullptr, 1, - -(4 * (func_type.param_types.size() + 2 + - codes[func_index].locals.size() + 1))); - - // push eax value onto stack - m_a.asm_push_r32(X86Reg::eax); - } - } - - - void visit_Br(uint32_t labelidx) { - // Branch is used to jump to the `loop.head` or `loop.end`. - uint32_t b_id; - Block block_type; - std::tie(b_id, block_type) = blocks[blocks.size() - 1 - labelidx]; - std::string label = std::to_string(b_id); - switch (block_type) { - /* - From WebAssembly Docs: - The exact effect of branch depends on that control construct. - In case of block or if, it is a forward jump, resuming execution after the matching end. - In case of loop, it is a backward jump to the beginning of the loop. - */ - case Block::LOOP: m_a.asm_jmp_label(".loop.head_" + label); break; - case Block::IF: m_a.asm_jmp_label(".else_" + label); break; - } - } - - void visit_Loop() { - std::string label = std::to_string(block_id); - blocks.push_back({block_id++, Block::LOOP}); - /* - The loop statement starts with `loop.head`. The `loop.body` and - `loop.branch` are enclosed within the `if.block`. If the condition - fails, the loop is exited through `else.block`. - .head - .If - # Statements - .Br - .Else - .endIf - .end - */ - m_a.add_label(".loop.head_" + label); - { - decode_instructions(); - } - // end - m_a.add_label(".loop.end_" + label); - blocks.pop_back(); - } - - void visit_If() { - std::string label = std::to_string(block_id); - blocks.push_back({block_id++, Block::IF}); - m_a.asm_pop_r32(X86Reg::eax); // now `eax` contains the logical value (true = 1, false = 0) of the if condition - m_a.asm_cmp_r32_imm8(X86Reg::eax, 1); - m_a.asm_je_label(".then_" + label); - m_a.asm_jmp_label(".else_" + label); - m_a.add_label(".then_" + label); - { - decode_instructions(); - } - m_a.add_label(".endif_" + label); - blocks.pop_back(); - } - - void visit_Else() { - std::string label = std::to_string(blocks.back().first); - m_a.asm_jmp_label(".endif_" + label); - m_a.add_label(".else_" + label); - } - - void visit_LocalGet(uint32_t localidx) { - X86Reg base = X86Reg::ebp; - auto cur_func_param_type = func_types[type_indices[cur_func_idx]]; - int no_of_params = (int)cur_func_param_type.param_types.size(); - if ((int)localidx < no_of_params) { - std::string var_type = var_type_to_string[cur_func_param_type.param_types[localidx]]; - if (var_type == "i32") { - m_a.asm_mov_r32_m32(X86Reg::eax, &base, nullptr, 1, 4 * (2 + no_of_params - (int)localidx - 1)); - m_a.asm_push_r32(X86Reg::eax); - } else if (var_type == "i64") { - m_a.asm_mov_r32_m32(X86Reg::eax, &base, nullptr, 1, 4 * (2 + no_of_params - (int)localidx - 1)); - m_a.asm_push_r32(X86Reg::eax); - } else if (var_type == "f64") { - m_a.asm_sub_r32_imm32(X86Reg::esp, 4); // create space for value to be fetched - X86Reg stack_top = X86Reg::esp; - m_a.asm_fld_m32(&base, nullptr, 1, 4 * (2 + no_of_params - (int)localidx - 1)); - m_a.asm_fstp_m32(&stack_top, nullptr, 1, 0); - } else { - throw AssemblerError("WASM_X86: Var type not supported"); - } - - } else { - localidx -= no_of_params; - std::string var_type = var_type_to_string[codes[cur_func_idx].locals[localidx].type]; - if (var_type == "i32") { - m_a.asm_mov_r32_m32(X86Reg::eax, &base, nullptr, 1, -4 * (1 + localidx)); - m_a.asm_push_r32(X86Reg::eax); - } else if (var_type == "i64") { - m_a.asm_mov_r32_m32(X86Reg::eax, &base, nullptr, 1, -4 * (1 + localidx)); - m_a.asm_push_r32(X86Reg::eax); - } else if (var_type == "f64") { - m_a.asm_sub_r32_imm32(X86Reg::esp, 4); // create space for value to be fetched - X86Reg stack_top = X86Reg::esp; - m_a.asm_fld_m32(&base, nullptr, 1, -4 * (1 + localidx)); - m_a.asm_fstp_m32(&stack_top, nullptr, 1, 0); - } else { - throw AssemblerError("WASM_X86: Var type not supported"); - } - } - } - void visit_LocalSet(uint32_t localidx) { - X86Reg base = X86Reg::ebp; - auto cur_func_param_type = func_types[type_indices[cur_func_idx]]; - int no_of_params = (int)cur_func_param_type.param_types.size(); - if ((int)localidx < no_of_params) { - std::string var_type = var_type_to_string[cur_func_param_type.param_types[localidx]]; - if (var_type == "i32") { - m_a.asm_pop_r32(X86Reg::eax); - m_a.asm_mov_m32_r32(&base, nullptr, 1, 4 * (2 + no_of_params - (int)localidx - 1), X86Reg::eax); - } else if (var_type == "i64") { - m_a.asm_pop_r32(X86Reg::eax); - m_a.asm_mov_m32_r32(&base, nullptr, 1, 4 * (2 + no_of_params - (int)localidx - 1), X86Reg::eax); - } else if (var_type == "f64") { - X86Reg stack_top = X86Reg::esp; - m_a.asm_fld_m32(&stack_top, nullptr, 1, 0); // load stack top into floating register stack - m_a.asm_fstp_m32(&base, nullptr, 1, 4 * (2 + no_of_params - (int)localidx - 1)); // store float at variable location - m_a.asm_add_r32_imm32(X86Reg::esp, 4); // increment stack top and thus pop the value to be set - } else { - throw AssemblerError("WASM_X86: Var type not supported"); - } - - } else { - localidx -= no_of_params; - std::string var_type = var_type_to_string[codes[cur_func_idx].locals[localidx].type]; - if (var_type == "i32") { - m_a.asm_pop_r32(X86Reg::eax); - m_a.asm_mov_m32_r32(&base, nullptr, 1, -4 * (1 + (int)localidx), X86Reg::eax); - } else if (var_type == "i64") { - m_a.asm_pop_r32(X86Reg::eax); - m_a.asm_mov_m32_r32(&base, nullptr, 1, -4 * (1 + (int)localidx), X86Reg::eax); - } else if (var_type == "f64") { - X86Reg stack_top = X86Reg::esp; - m_a.asm_fld_m32(&stack_top, nullptr, 1, 0); // load stack top into floating register stack - m_a.asm_fstp_m32(&base, nullptr, 1, -4 * (1 + (int)localidx)); // store float at variable location - m_a.asm_add_r32_imm32(X86Reg::esp, 4); // increment stack top and thus pop the value to be set - } else { - throw AssemblerError("WASM_X86: Var type not supported"); - } - } - } - - void visit_I32Eqz() { - m_a.asm_push_imm32(0U); - handle_I32Compare<&X86Assembler::asm_je_label>(); - } - - void visit_I32Const(int32_t value) { - m_a.asm_push_imm32(value); - } - - void visit_I32WrapI64() { - // empty, since i32's and i64's are considered similar currently. - } - - template - void handleI32Opt(F && f) { - m_a.asm_pop_r32(X86Reg::ebx); - m_a.asm_pop_r32(X86Reg::eax); - f(); - m_a.asm_push_r32(X86Reg::eax); - } - - void visit_I32Add() { - handleI32Opt([&](){ m_a.asm_add_r32_r32(X86Reg::eax, X86Reg::ebx);}); - } - void visit_I32Sub() { - handleI32Opt([&](){ m_a.asm_sub_r32_r32(X86Reg::eax, X86Reg::ebx);}); - } - void visit_I32Mul() { - handleI32Opt([&](){ m_a.asm_mul_r32(X86Reg::ebx);}); - } - void visit_I32DivS() { - handleI32Opt([&](){ - m_a.asm_mov_r32_imm32(X86Reg::edx, 0); - m_a.asm_div_r32(X86Reg::ebx); - }); - } - - using JumpFn = void(X86Assembler::*)(const std::string&); - template - void handle_I32Compare() { - std::string label = std::to_string(offset); - m_a.asm_pop_r32(X86Reg::ebx); - m_a.asm_pop_r32(X86Reg::eax); - // `eax` and `ebx` contain the left and right operands, respectively - m_a.asm_cmp_r32_r32(X86Reg::eax, X86Reg::ebx); - - (m_a.*T)(".compare_1" + label); - // if the `compare` condition in `true`, jump to compare_1 - // and assign `1` else assign `0` - m_a.asm_push_imm8(0); - m_a.asm_jmp_label(".compare.end_" + label); - m_a.add_label(".compare_1" + label); - m_a.asm_push_imm8(1); - m_a.add_label(".compare.end_" + label); - } - - void visit_I32Eq() { handle_I32Compare<&X86Assembler::asm_je_label>(); } - void visit_I32GtS() { handle_I32Compare<&X86Assembler::asm_jg_label>(); } - void visit_I32GeS() { handle_I32Compare<&X86Assembler::asm_jge_label>(); } - void visit_I32LtS() { handle_I32Compare<&X86Assembler::asm_jl_label>(); } - void visit_I32LeS() { handle_I32Compare<&X86Assembler::asm_jle_label>(); } - void visit_I32Ne() { handle_I32Compare<&X86Assembler::asm_jne_label>(); } - - void visit_I64Const(int64_t value) { - m_a.asm_push_imm32(value); - } - - void visit_I64ExtendI32S() { - // empty, since all i32's are already considered as i64's currently. - } - - template - void handleI64Opt(F && f) { - m_a.asm_pop_r32(X86Reg::ebx); - m_a.asm_pop_r32(X86Reg::eax); - f(); - m_a.asm_push_r32(X86Reg::eax); - } - - void visit_I64Add() { - handleI64Opt([&](){ m_a.asm_add_r32_r32(X86Reg::eax, X86Reg::ebx);}); - } - void visit_I64Sub() { - handleI64Opt([&](){ m_a.asm_sub_r32_r32(X86Reg::eax, X86Reg::ebx);}); - } - void visit_I64Mul() { - handleI64Opt([&](){ m_a.asm_mul_r32(X86Reg::ebx);}); - } - void visit_I64DivS() { - handleI64Opt([&](){ - m_a.asm_mov_r32_imm32(X86Reg::edx, 0); - m_a.asm_div_r32(X86Reg::ebx); - }); - } - - void visit_I64RemS() { - m_a.asm_pop_r32(X86Reg::ebx); - m_a.asm_pop_r32(X86Reg::eax); - m_a.asm_mov_r32_imm32(X86Reg::edx, 0); - m_a.asm_div_r32(X86Reg::ebx); - m_a.asm_push_r32(X86Reg::edx); - } - - template - void handle_I64Compare() { - std::string label = std::to_string(offset); - m_a.asm_pop_r32(X86Reg::ebx); - m_a.asm_pop_r32(X86Reg::eax); - // `eax` and `ebx` contain the left and right operands, respectively - m_a.asm_cmp_r32_r32(X86Reg::eax, X86Reg::ebx); - - (m_a.*T)(".compare_1" + label); - // if the `compare` condition in `true`, jump to compare_1 - // and assign `1` else assign `0` - m_a.asm_push_imm8(0); - m_a.asm_jmp_label(".compare.end_" + label); - m_a.add_label(".compare_1" + label); - m_a.asm_push_imm8(1); - m_a.add_label(".compare.end_" + label); - } - - void visit_I64Eq() { handle_I64Compare<&X86Assembler::asm_je_label>(); } - void visit_I64GtS() { handle_I64Compare<&X86Assembler::asm_jg_label>(); } - void visit_I64GeS() { handle_I64Compare<&X86Assembler::asm_jge_label>(); } - void visit_I64LtS() { handle_I64Compare<&X86Assembler::asm_jl_label>(); } - void visit_I64LeS() { handle_I64Compare<&X86Assembler::asm_jle_label>(); } - void visit_I64Ne() { handle_I64Compare<&X86Assembler::asm_jne_label>(); } - - void visit_I64Eqz() { - m_a.asm_push_imm32(0U); - handle_I64Compare<&X86Assembler::asm_je_label>(); - } - - std::string float_to_str(float z) { - std::string float_str = ""; - for (auto ch:std::to_string(z)) { - if (ch == '-') { - float_str += "neg_"; - } else if (ch == '.') { - float_str += "_dot_"; - } else { - float_str += ch; - } - } - return float_str; - } - - void visit_F64Const(double z) { - std::string label = "float_" + float_to_str(z); - float_consts[label] = z; - m_a.asm_mov_r32_label(X86Reg::eax, label); - X86Reg label_reg = X86Reg::eax; - m_a.asm_fld_m32(&label_reg, nullptr, 1, 0); // loads into floating register stack - m_a.asm_sub_r32_imm32(X86Reg::esp, 4); // decrement stack and create space - X86Reg stack_top = X86Reg::esp; - m_a.asm_fstp_m32(&stack_top, nullptr, 1, 0); // store float on integer stack top; - } - - void gen_x86_bytes() { - emit_elf32_header(m_a); - - // Add runtime library functions - emit_exit2(m_a, "my_exit"); - - // declare compile-time strings - std::string base_memory = " "; /* in wasm backend, memory starts after 4 bytes*/ - for (uint32_t i = 0; i < data_segments.size(); i++) { - base_memory += data_segments[i].text; - } - label_to_str["base_memory"] = base_memory; - - NO_OF_IMPORTS = imports.size(); - for (uint32_t i = 0; i < type_indices.size(); i++) { - std::string func = exports[i + 1 /* offset by 1 becaz of mem export */].name; - if (func == "print_f64") { - // "print_f64" needs floating-point comparison support, which is - // not yet supported in the wasm_x86 backend, hence skipping it. - continue; - } - m_a.add_label(func); - - { - // Initialize the stack - m_a.asm_push_r32(X86Reg::ebp); - m_a.asm_mov_r32_r32(X86Reg::ebp, X86Reg::esp); - - // Allocate space for local variables - // TODO: locals is an array where every element has a count (currently wasm emits count = 1 always) - m_a.asm_sub_r32_imm32(X86Reg::esp, 4 * codes[i].locals.size()); - - offset = codes.p[i].insts_start_index; - cur_func_idx = i; - decode_instructions(); - } - } - - for (auto &s : label_to_str) { - emit_data_string(m_a, s.first, s.second); - } - - for (auto &f : float_consts) { - emit_float_const(m_a, f.first, f.second); - } - - emit_elf32_footer(m_a); - } -}; - -} // namespace wasm - -Result wasm_to_x86(Vec &wasm_bytes, Allocator &al, - const std::string &filename, bool time_report, - diag::Diagnostics &diagnostics) { - int time_decode_wasm = 0; - int time_gen_x86_bytes = 0; - int time_save = 0; - int time_verify = 0; - - X86Assembler m_a(al, false /* bits 64 */); - - wasm::X86Visitor x86_visitor(m_a, al, diagnostics, wasm_bytes); - - { - auto t1 = std::chrono::high_resolution_clock::now(); - try { - x86_visitor.decode_wasm(); - } catch (const CodeGenError &e) { - diagnostics.diagnostics.push_back(e.d); - return Error(); - } - auto t2 = std::chrono::high_resolution_clock::now(); - time_decode_wasm = - std::chrono::duration_cast(t2 - t1) - .count(); - } - - { - auto t1 = std::chrono::high_resolution_clock::now(); - x86_visitor.gen_x86_bytes(); - auto t2 = std::chrono::high_resolution_clock::now(); - time_gen_x86_bytes = - std::chrono::duration_cast(t2 - t1) - .count(); - } - - { - auto t1 = std::chrono::high_resolution_clock::now(); - m_a.verify(); - auto t2 = std::chrono::high_resolution_clock::now(); - time_verify = - std::chrono::duration_cast(t2 - t1) - .count(); - } - - { - auto t1 = std::chrono::high_resolution_clock::now(); - m_a.save_binary(filename); - auto t2 = std::chrono::high_resolution_clock::now(); - time_save = - std::chrono::duration_cast(t2 - t1) - .count(); - } - - //! Helpful for debugging - // std::cout << x86_visitor.m_a.get_asm() << std::endl; - - if (time_report) { - std::cout << "Codegen Time report:" << std::endl; - std::cout << "Decode wasm: " << std::setw(5) << time_decode_wasm - << std::endl; - std::cout << "Generate asm: " << std::setw(5) << time_gen_x86_bytes - << std::endl; - std::cout << "Verify: " << std::setw(5) << time_verify - << std::endl; - std::cout << "Save: " << std::setw(5) << time_save << std::endl; - int total = - time_decode_wasm + time_gen_x86_bytes + time_verify + time_save; - std::cout << "Total: " << std::setw(5) << total << std::endl; - } - return 0; -} - -} // namespace LCompilers diff --git a/src/libasr/codegen/wasm_to_x86.h b/src/libasr/codegen/wasm_to_x86.h deleted file mode 100644 index 11c456ab27..0000000000 --- a/src/libasr/codegen/wasm_to_x86.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef LFORTRAN_WASM_TO_X86_H -#define LFORTRAN_WASM_TO_X86_H - -#include - -namespace LCompilers { - -Result wasm_to_x86(Vec &wasm_bytes, Allocator &al, - const std::string &filename, bool time_report, - diag::Diagnostics &diagnostics); - -} // namespace LCompilers - -#endif // LFORTRAN_WASM_TO_X86_H diff --git a/src/libasr/codegen/wasm_utils.cpp b/src/libasr/codegen/wasm_utils.cpp deleted file mode 100644 index c4ddb8739b..0000000000 --- a/src/libasr/codegen/wasm_utils.cpp +++ /dev/null @@ -1,124 +0,0 @@ -#include - -namespace LCompilers { - -namespace wasm { - -uint32_t decode_leb128_u32(Vec &code, uint32_t &offset) { - uint32_t result = 0U; - uint32_t shift = 0U; - while (true) { - uint8_t byte = read_b8(code, offset); - uint32_t slice = byte & 0x7f; - result |= slice << shift; - if ((byte & 0x80) == 0) { - return result; - } - shift += 7; - } -} - -int32_t decode_leb128_i32(Vec &code, uint32_t &offset) { - int32_t result = 0; - uint32_t shift = 0U; - uint8_t byte; - - do { - byte = read_b8(code, offset); - uint32_t slice = byte & 0x7f; - result |= slice << shift; - shift += 7; - } while (byte & 0x80); - - // Sign extend negative numbers if needed. - if ((shift < 32U) && (byte & 0x40)) { - result |= (-1U << shift); - } - - return result; -} - -int64_t decode_leb128_i64(Vec &code, uint32_t &offset) { - int64_t result = 0; - uint32_t shift = 0U; - uint8_t byte; - - do { - byte = read_b8(code, offset); - uint64_t slice = byte & 0x7f; - result |= slice << shift; - shift += 7; - } while (byte & 0x80); - - // Sign extend negative numbers if needed. - if ((shift < 64U) && (byte & 0x40)) { - result |= (-1ULL << shift); - } - - return result; -} - -float decode_ieee754_f32(Vec &code, uint32_t &offset) { - float value = 0.0; - std::memcpy(&value, &code.p[offset], sizeof(value)); - offset += sizeof(value); - return value; -} - -double decode_ieee754_f64(Vec &code, uint32_t &offset) { - double value = 0.0; - std::memcpy(&value, &code.p[offset], sizeof(value)); - offset += sizeof(value); - return value; -} - -uint8_t read_b8(Vec &code, uint32_t &offset) { - LCOMPILERS_ASSERT(offset < code.size()); - return code.p[offset++]; -} - -float read_f32(Vec &code, uint32_t &offset) { - LCOMPILERS_ASSERT(offset + sizeof(float) <= code.size()); - return decode_ieee754_f32(code, offset); -} - -double read_f64(Vec &code, uint32_t &offset) { - LCOMPILERS_ASSERT(offset + sizeof(double) <= code.size()); - return decode_ieee754_f64(code, offset); -} - -uint32_t read_u32(Vec &code, uint32_t &offset) { - return decode_leb128_u32(code, offset); -} - -int32_t read_i32(Vec &code, uint32_t &offset) { - return decode_leb128_i32(code, offset); -} - -int64_t read_i64(Vec &code, uint32_t &offset) { - return decode_leb128_i64(code, offset); -} - -void hexdump(void *ptr, int buflen) { - unsigned char *buf = (unsigned char *)ptr; - int i, j; - for (i = 0; i < buflen; i += 16) { - printf("%06x: ", i); - for (j = 0; j < 16; j++) { - if (i + j < buflen) - printf("%02x ", buf[i + j]); - else - printf(" "); - } - printf(" "); - for (j = 0; j < 16; j++) { - if (i + j < buflen) - printf("%c", isprint(buf[i + j]) ? buf[i + j] : '.'); - } - printf("\n"); - } -} - -} // namespace wasm - -} // namespace LCompilers diff --git a/src/libasr/codegen/wasm_utils.h b/src/libasr/codegen/wasm_utils.h deleted file mode 100644 index c7e41cf002..0000000000 --- a/src/libasr/codegen/wasm_utils.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef LFORTRAN_WASM_UTILS_H -#define LFORTRAN_WASM_UTILS_H - -#include -#include - -#include -#include - -namespace LCompilers { - -namespace wasm { - -struct FuncType { - Vec param_types; - Vec result_types; -}; - -struct Global { - uint8_t type; - uint8_t mut; - uint32_t insts_start_idx; -}; - -struct Export { - std::string name; - uint8_t kind; - uint32_t index; -}; - -struct Local { - uint32_t count; - uint8_t type; -}; - -struct Code { - int size; - Vec locals; - uint32_t insts_start_index; -}; - -struct Import { - std::string mod_name; - std::string name; - uint8_t kind; - union { - uint32_t type_idx; - std::pair mem_page_size_limits; - }; -}; - -struct Data { - uint32_t insts_start_index; - std::string text; -}; - -uint32_t decode_leb128_u32(Vec &code, uint32_t &offset); -int32_t decode_leb128_i32(Vec &code, uint32_t &offset); -int64_t decode_leb128_i64(Vec &code, uint32_t &offset); - -uint8_t read_b8(Vec &code, uint32_t &offset); - -float read_f32(Vec &code, uint32_t &offset); - -double read_f64(Vec &code, uint32_t &offset); - -uint32_t read_u32(Vec &code, uint32_t &offset); - -int32_t read_i32(Vec &code, uint32_t &offset); - -int64_t read_i64(Vec &code, uint32_t &offset); - -void hexdump(void *ptr, int buflen); - -} // namespace wasm - -} // namespace LCompilers - -#endif // LFORTRAN_WASM_UTILS_H diff --git a/src/libasr/codegen/x86_assembler.cpp b/src/libasr/codegen/x86_assembler.cpp deleted file mode 100644 index 600239d2d8..0000000000 --- a/src/libasr/codegen/x86_assembler.cpp +++ /dev/null @@ -1,547 +0,0 @@ -#ifdef __unix__ -#define LFORTRAN_LINUX -#endif - -#ifdef LFORTRAN_LINUX -#include -#endif - -#include - -namespace LCompilers { - -void X86Assembler::save_binary(const std::string &filename) { - { - std::ofstream out; - out.open(filename); - out.write((const char*) m_code.p, m_code.size()); - } -#ifdef LFORTRAN_LINUX - std::string mode = "0755"; - int mod = strtol(mode.c_str(), 0, 8); - if (chmod(filename.c_str(),mod) < 0) { - throw AssemblerError("chmod failed"); - } -#endif -} - -void emit_elf32_header(X86Assembler &a, uint32_t p_flags) { - /* Elf32_Ehdr */ - a.add_label("ehdr"); - // e_ident - a.asm_db_imm8(0x7F); - a.asm_db_imm8('E'); - a.asm_db_imm8('L'); - a.asm_db_imm8('F'); - a.asm_db_imm8(1); - a.asm_db_imm8(1); - a.asm_db_imm8(1); - a.asm_db_imm8(0); - - a.asm_db_imm8(0); - a.asm_db_imm8(0); - a.asm_db_imm8(0); - a.asm_db_imm8(0); - - a.asm_db_imm8(0); - a.asm_db_imm8(0); - a.asm_db_imm8(0); - a.asm_db_imm8(0); - - a.asm_dw_imm16(2); // e_type - a.asm_dw_imm16(3); // e_machine - a.asm_dd_imm32(1); // e_version - a.asm_dd_label("_start"); // e_entry - a.asm_dd_label("e_phoff"); // e_phoff - a.asm_dd_imm32(0); // e_shoff - a.asm_dd_imm32(0); // e_flags - a.asm_dw_label("ehdrsize"); // e_ehsize - a.asm_dw_label("phdrsize"); // e_phentsize - a.asm_dw_imm16(1); // e_phnum - a.asm_dw_imm16(0); // e_shentsize - a.asm_dw_imm16(0); // e_shnum - a.asm_dw_imm16(0); // e_shstrndx - - - /* Elf32_Phdr */ - a.add_label("phdr"); - a.asm_dd_imm32(1); // p_type - a.asm_dd_imm32(0); // p_offset - a.asm_dd_imm32(a.origin()); // p_vaddr - a.asm_dd_imm32(a.origin()); // p_paddr - a.asm_dd_label("filesize"); // p_filesz - a.asm_dd_label("filesize"); // p_memsz - a.asm_dd_imm32(p_flags); // p_flags - a.asm_dd_imm32(0x1000); // p_align - a.add_label("phdr_end"); - - a.add_var("ehdrsize", "ehdr", "phdr"); - a.add_var("phdrsize", "phdr", "phdr_end"); - a.add_var("e_phoff", "ehdr", "phdr"); -} - -void emit_elf32_footer(X86Assembler &a) { - a.add_label("footer"); - a.add_var("filesize", "ehdr", "footer"); -} - -void emit_exit(X86Assembler &a, const std::string &name, - uint32_t exit_code) -{ - a.add_label(name); - // void exit(int status); - a.asm_mov_r32_imm32(X86Reg::eax, 1); // sys_exit - a.asm_mov_r32_imm32(X86Reg::ebx, exit_code); // exit code - a.asm_int_imm8(0x80); // syscall -} - -void emit_exit2(X86Assembler &a, const std::string &name) -{ - a.add_label(name); - // void exit(); - a.asm_mov_r32_imm32(X86Reg::eax, 1); // sys_exit - a.asm_pop_r32(X86Reg::ebx); // exit code on stack, move to register - a.asm_int_imm8(0x80); // syscall -} - -void emit_data_string(X86Assembler &a, const std::string &label, - const std::string &s) -{ - a.add_label(label); - a.asm_db_imm8(s.c_str(), s.size()); -} - -void emit_i32_const(X86Assembler &a, const std::string &label, - const int32_t z) { - uint8_t encoded_i32[sizeof(z)]; - std::memcpy(&encoded_i32, &z, sizeof(z)); - a.add_label(label); - a.asm_db_imm8(encoded_i32, sizeof(z)); -} - -void emit_i64_const(X86Assembler &a, const std::string &label, - const int64_t z) { - uint8_t encoded_i64[sizeof(z)]; - std::memcpy(&encoded_i64, &z, sizeof(z)); - a.add_label(label); - a.asm_db_imm8(encoded_i64, sizeof(z)); -} - -void emit_float_const(X86Assembler &a, const std::string &label, - const float z) { - uint8_t encoded_float[sizeof(z)]; - std::memcpy(&encoded_float, &z, sizeof(z)); - a.add_label(label); - a.asm_db_imm8(encoded_float, sizeof(z)); -} - -void emit_double_const(X86Assembler &a, const std::string &label, - const double z) { - uint8_t encoded_double[sizeof(z)]; - std::memcpy(&encoded_double, &z, sizeof(z)); - a.add_label(label); - a.asm_db_imm8(encoded_double, sizeof(z)); -} - -void emit_print(X86Assembler &a, const std::string &msg_label, - uint32_t size) -{ - // ssize_t write(int fd, const void *buf, size_t count); - a.asm_mov_r32_imm32(X86Reg::eax, 4); // sys_write - a.asm_mov_r32_imm32(X86Reg::ebx, 1); // fd (stdout) - a.asm_mov_r32_label(X86Reg::ecx, msg_label); // buf - a.asm_mov_r32_imm32(X86Reg::edx, size); // count - a.asm_int_imm8(0x80); -} - -void emit_print_int(X86Assembler &a, const std::string &name) -{ - // void print_int(uint32_t i); - a.add_label(name); - - // Initialize stack - a.asm_push_r32(X86Reg::ebp); - a.asm_mov_r32_r32(X86Reg::ebp, X86Reg::esp); - - X86Reg base = X86Reg::ebp; - // mov eax, [ebp+8] // argument "i" - a.asm_mov_r32_m32(X86Reg::eax, &base, nullptr, 1, 8); - - a.asm_mov_r32_r32(X86Reg::ecx, X86Reg::eax); // make a copy in ecx - a.asm_mov_r32_imm32(X86Reg::ebx, 0); - a.asm_cmp_r32_r32(X86Reg::eax, X86Reg::ebx); - a.asm_jge_label(".print_int_"); // if num >= 0 then print it - - // print "-" and then negate the integer - emit_print(a, "string_neg", 1U); - // ecx value changed during print so fetch back - a.asm_mov_r32_m32(X86Reg::ecx, &base, nullptr, 1, 8); - a.asm_neg_r32(X86Reg::ecx); - - a.add_label(".print_int_"); - - a.asm_mov_r32_r32(X86Reg::eax, X86Reg::ecx); // fetch the val in ecx back to eax - a.asm_xor_r32_r32(X86Reg::esi, X86Reg::esi); - - a.add_label(".loop"); -// mov edx, 0 - a.asm_mov_r32_imm32(X86Reg::edx, 0); -// mov ebx, 10 - a.asm_mov_r32_imm32(X86Reg::ebx, 10); -// div ebx - a.asm_div_r32(X86Reg::ebx); -// add edx, 48 - a.asm_add_r32_imm32(X86Reg::edx, 48); -// push edx - a.asm_push_r32(X86Reg::edx); -// inc esi - a.asm_inc_r32(X86Reg::esi); -// cmp eax, 0 - a.asm_cmp_r32_imm8(X86Reg::eax, 0); -// jz .print - a.asm_je_label(".print"); -// jmp .loop - a.asm_jmp_label(".loop"); - - a.add_label(".print"); -// cmp esi, 0 - a.asm_cmp_r32_imm8(X86Reg::esi, 0); -// jz end - a.asm_je_label(".end"); -// dec esi - a.asm_dec_r32(X86Reg::esi); -// mov eax, 4 - a.asm_mov_r32_imm32(X86Reg::eax, 4); -// mov ecx, esp - a.asm_mov_r32_r32(X86Reg::ecx, X86Reg::esp); -// mov ebx, 1 - a.asm_mov_r32_imm32(X86Reg::ebx, 1); -// mov edx, 1 - a.asm_mov_r32_imm32(X86Reg::edx, 1); -// int 0x80 - a.asm_int_imm8(0x80); -// add esp, 4 - a.asm_add_r32_imm32(X86Reg::esp, 4); -// jmp .print - a.asm_jmp_label(".print"); - - a.add_label(".end"); - - // Restore stack - a.asm_mov_r32_r32(X86Reg::esp, X86Reg::ebp); - a.asm_pop_r32(X86Reg::ebp); - a.asm_ret(); -} - -void emit_print_float(X86Assembler &a, const std::string &name) { - // void print_float(float z); - a.add_label(name); - - // Initialize stack - a.asm_push_r32(X86Reg::ebp); - a.asm_mov_r32_r32(X86Reg::ebp, X86Reg::esp); - - X86Reg base = X86Reg::ebp; - a.asm_fld_m32(&base, nullptr, 1, 8); // load argument into floating register stack - a.asm_push_imm32(0); // decrement stack pointer and create space - X86Reg stack_top = X86Reg::esp; - a.asm_fistp_m32(&stack_top, nullptr, 1, 0); - - // print the integral part - { - a.asm_call_label("print_i32"); - a.asm_add_r32_imm32(X86Reg::esp, 4); // increment stack top and thus pop the value to be set - } - - // print dot - emit_print(a, "string_dot", 1U); - - // print fractional part - { - a.asm_fld_m32(&base, nullptr, 1, 8); // load argument into floating register stack - a.asm_fld_m32(&base, nullptr, 1, 8); // load another copy of argument into floating register stack - a.asm_frndint(); // round st(0) to integral part - a.asm_fsubp(); - - // st(0) now contains only the fractional part - - a.asm_push_imm32(100000000); - a.asm_fimul_m32int(&stack_top, nullptr, 1, 0); - a.asm_fistp_m32(&stack_top, nullptr, 1, 0); - // print the fractional part - { - a.asm_call_label("print_i32"); - a.asm_add_r32_imm32(X86Reg::esp, 4); // increment stack top and thus pop the value to be set - } - } - - // Restore stack - a.asm_mov_r32_r32(X86Reg::esp, X86Reg::ebp); - a.asm_pop_r32(X86Reg::ebp); - a.asm_ret(); -} - -/************************* 64-bit functions **************************/ - -void emit_elf64_header(X86Assembler &a) { - /* Elf64_Ehdr */ - a.add_label("ehdr"); - // e_ident - a.asm_db_imm8(0x7F); - a.asm_db_imm8('E'); - a.asm_db_imm8('L'); - a.asm_db_imm8('F'); - a.asm_db_imm8(2); - a.asm_db_imm8(1); - a.asm_db_imm8(1); - a.asm_db_imm8(0); - - a.asm_db_imm8(0); - a.asm_db_imm8(0); - a.asm_db_imm8(0); - a.asm_db_imm8(0); - - a.asm_db_imm8(0); - a.asm_db_imm8(0); - a.asm_db_imm8(0); - a.asm_db_imm8(0); - - a.asm_dw_imm16(2); // e_type - a.asm_dw_imm16(0x3e); // e_machine - a.asm_dd_imm32(1); // e_version - a.asm_dq_label("_start"); // e_entry - a.asm_dq_label("e_phoff"); // e_phoff - a.asm_dq_imm64(0); // e_shoff - a.asm_dd_imm32(0); // e_flags - a.asm_dw_label("ehdrsize"); // e_ehsize - a.asm_dw_label("phdrsize"); // e_phentsize - a.asm_dw_imm16(3); // e_phnum - a.asm_dw_imm16(0); // e_shentsize - a.asm_dw_imm16(0); // e_shnum - a.asm_dw_imm16(0); // e_shstrndx - - /* Elf64_Phdr */ - a.add_label("phdr"); - a.asm_dd_imm32(1); // p_type - a.asm_dd_imm32(4); // p_flags (permission to read only) - a.asm_dq_imm64(0); // p_offset - a.asm_dq_imm64(a.origin()); // p_vaddr - a.asm_dq_imm64(a.origin()); // p_paddr - a.asm_dq_label("phdr_size"); // p_filesz - a.asm_dq_label("phdr_size"); // p_memsz - a.asm_dq_imm64(0x1000); // p_align - - /* text_segment_phdr */ - a.add_label("text_phdr"); - a.asm_dd_imm32(1); // p_type - a.asm_dd_imm32(5); // p_flags (permission to read and execute) - a.asm_dq_label("text_segment_offset"); // p_offset - a.asm_dq_label("text_segment_start"); // p_vaddr - a.asm_dq_label("text_segment_start"); // p_paddr - a.asm_dq_label("text_segment_size"); // p_filesz - a.asm_dq_label("text_segment_size"); // p_memsz - a.asm_dq_imm64(0x1000); // p_align - - /* data_segment_phdr */ - a.add_label("data_phdr"); - a.asm_dd_imm32(1); // p_type - a.asm_dd_imm32(6); // p_flags (permission to read and write) - a.asm_dq_label("data_segment_offset"); // p_offset - a.asm_dq_label("data_segment_start"); // p_vaddr - a.asm_dq_label("data_segment_start"); // p_paddr - a.asm_dq_label("data_segment_size"); // p_filesz - a.asm_dq_label("data_segment_size"); // p_memsz - a.asm_dq_imm64(0x1000); // p_align -} - -void emit_elf64_footer(X86Assembler &a) { - a.add_var("ehdrsize", "ehdr", "phdr"); - a.add_var("phdrsize", "phdr", "text_phdr"); - a.add_var64("e_phoff", "ehdr", "phdr"); - a.add_var64("phdr_size", "ehdr", "text_segment_start"); - a.add_var64("text_segment_offset", "ehdr", "text_segment_start"); - a.add_var64("text_segment_size", "text_segment_start", "text_segment_end"); - a.add_var64("data_segment_offset", "ehdr", "data_segment_start"); - a.add_var64("data_segment_size", "data_segment_start", "data_segment_end"); -} - -void emit_exit_64(X86Assembler &a, std::string name, int exit_code) { - a.add_label(name); - // void exit(int status); - a.asm_mov_r64_imm64(LCompilers::X64Reg::rax, 60); // sys_exit - a.asm_mov_r64_imm64(LCompilers::X64Reg::rdi, exit_code); // exit code - a.asm_syscall(); // syscall -} - -void emit_print_64(X86Assembler &a, const std::string &msg_label, uint64_t size) -{ - // mov rax, 1 ; write( - // mov rdi, 1 ; STDOUT_FILENO, - // mov rsi, msg ; "Hello, world!\n", - // mov rdx, msglen ; sizeof("Hello, world!\n") - // syscall ; ); - - a.asm_mov_r64_imm64(X64Reg::rax, 1); - a.asm_mov_r64_imm64(X64Reg::rdi, 1); - a.asm_mov_r64_label(X64Reg::rsi, msg_label); // buf - a.asm_mov_r64_imm64(X64Reg::rdx, size); - a.asm_syscall(); -} - -void emit_print_int_64(X86Assembler &a, const std::string &name) -{ - // void print_int_64(uint64_t i); - a.add_label(name); - // Initialize stack - a.asm_push_r64(X64Reg::rbp); - a.asm_mov_r64_r64(X64Reg::rbp, X64Reg::rsp); - - X64Reg base = X64Reg::rbp; - a.asm_mov_r64_m64(X64Reg::r8, &base, nullptr, 1, 16); // mov r8, [rbp+16] // argument "i" - a.asm_mov_r64_imm64(X64Reg::r9, 0); // r9 holds count of digits - - // if num >= 0 then print it - a.asm_cmp_r64_imm8(X64Reg::r8, 0); - a.asm_jge_label("_print_i64_loop_initialize"); - - // print "-" and then negate the integer - emit_print_64(a, "string_neg", 1); - a.asm_neg_r64(X64Reg::r8); - - a.add_label("_print_i64_loop_initialize"); - a.asm_mov_r64_r64(X64Reg::rax, X64Reg::r8); // rax as quotient - a.asm_mov_r64_imm64(X64Reg::r10, 10); // 10 as divisor - - a.add_label("_print_i64_loop"); - a.asm_mov_r64_imm64(X64Reg::rdx, 0); - a.asm_div_r64(X64Reg::r10); - a.asm_add_r64_imm32(X64Reg::rdx, 48); - a.asm_push_r64(X64Reg::rdx); - a.asm_inc_r64(X64Reg::r9); - a.asm_cmp_r64_imm8(X64Reg::rax, 0); - a.asm_je_label("_print_i64_digit"); - a.asm_jmp_label("_print_i64_loop"); - - a.add_label("_print_i64_digit"); - a.asm_cmp_r64_imm8(X64Reg::r9, 0); - a.asm_je_label("_print_i64_end"); - a.asm_dec_r64(X64Reg::r9); - { // write() syscall - a.asm_mov_r64_imm64(X64Reg::rax, 1); - a.asm_mov_r64_imm64(X64Reg::rdi, 1); - a.asm_mov_r64_r64(X64Reg::rsi, X64Reg::rsp); - a.asm_mov_r64_imm64(X64Reg::rdx, 1); - a.asm_syscall(); - } - a.asm_add_r64_imm32(X64Reg::rsp, 8); // pop and increment stack pointer - a.asm_jmp_label("_print_i64_digit"); - - a.add_label("_print_i64_end"); - // Restore stack - a.asm_mov_r64_r64(X64Reg::rsp, X64Reg::rbp); - a.asm_pop_r64(X64Reg::rbp); - a.asm_ret(); -} - -void emit_print_double(X86Assembler &a, const std::string &name) { - // void print_double(double z); - a.add_label(name); - - // Initialize stack - a.asm_push_r64(X64Reg::rbp); - a.asm_mov_r64_r64(X64Reg::rbp, X64Reg::rsp); - - X64Reg base = X64Reg::rbp; - a.asm_movsd_r64_m64(X64FReg::xmm0, &base, nullptr, 1, 16); // load argument into floating-point register - - // if z >= 0 then print it - a.asm_mov_r64_imm64(X64Reg::rax, 0); - a.asm_cvtsi2sd_r64_r64(X64FReg::xmm1, X64Reg::rax); - a.asm_cmpsd_r64_r64(X64FReg::xmm0, X64FReg::xmm1, Fcmp::ge); - a.asm_pmovmskb_r32_r64(X86Reg::eax, X64FReg::xmm0); - a.asm_and_r64_imm8(X64Reg::rax, 1); - a.asm_movsd_r64_m64(X64FReg::xmm0, &base, nullptr, 1, 16); // load argument back into floating-point register - a.asm_cmp_r64_imm8(X64Reg::rax, 1); - a.asm_je_label("_print_float_int_part"); - - { - // the float to be printed is < 0, so print '-' symbol and - // multiply the float with -1 - emit_print_64(a, "string_neg", 1); - - a.asm_mov_r64_imm64(X64Reg::rax, 1); - a.asm_neg_r64(X64Reg::rax); - a.asm_cvtsi2sd_r64_r64(X64FReg::xmm1, X64Reg::rax); - a.asm_mulsd_r64_r64(X64FReg::xmm0, X64FReg::xmm1); - } - - a.add_label("_print_float_int_part"); - a.asm_cvttsd2si_r64_r64(X64Reg::rax, X64FReg::xmm0); - a.asm_push_r64(X64Reg::rax); - - // print the integral part - { - a.asm_call_label("print_i64"); - a.asm_add_r64_imm32(X64Reg::rsp, 8); // pop and increment stack pointer - } - - // print dot - emit_print_64(a, "string_dot", 1U); - - // print fractional part - { - a.asm_cvttsd2si_r64_r64(X64Reg::rax, X64FReg::xmm0); // rax now contains value int(xmm0) - a.asm_cvtsi2sd_r64_r64(X64FReg::xmm1, X64Reg::rax); - a.asm_subsd_r64_r64(X64FReg::xmm0, X64FReg::xmm1); - a.asm_mov_r64_imm64(X64Reg::rax, 100000000); // to multiply by 10^8 - a.asm_cvtsi2sd_r64_r64(X64FReg::xmm1, X64Reg::rax); - a.asm_mulsd_r64_r64(X64FReg::xmm0, X64FReg::xmm1); - a.asm_cvttsd2si_r64_r64(X64Reg::rax, X64FReg::xmm0); - - a.asm_mov_r64_r64(X64Reg::r15, X64Reg::rax); // keep a safe copy in r15 - a.asm_mov_r64_imm64(X64Reg::r8, 8); // 8 digits after decimal point to be printed - a.asm_mov_r64_imm64(X64Reg::r10, 10); // 10 as divisor - - // count the number of digits available in the fractional part - a.add_label("_count_fract_part_digits_loop"); - a.asm_mov_r64_imm64(X64Reg::rdx, 0); - a.asm_div_r64(X64Reg::r10); - a.asm_dec_r64(X64Reg::r8); - a.asm_cmp_r64_imm8(X64Reg::rax, 0); - a.asm_je_label("_print_fract_part_initial_zeroes_loop_head"); - a.asm_jmp_label("_count_fract_part_digits_loop"); - - a.add_label("_print_fract_part_initial_zeroes_loop_head"); - a.asm_mov_r64_imm64(X64Reg::rax, 48); - a.asm_push_r64(X64Reg::rax); // push zero ascii value on stack top - - a.add_label("_print_fract_part_initial_zeroes_loop"); - a.asm_cmp_r64_imm8(X64Reg::r8, 0); - a.asm_je_label("_print_fract_part"); - { - // write() syscall - a.asm_mov_r64_imm64(X64Reg::rax, 1); - a.asm_mov_r64_imm64(X64Reg::rdi, 1); - a.asm_mov_r64_r64(X64Reg::rsi, X64Reg::rsp); - a.asm_mov_r64_imm64(X64Reg::rdx, 1); - a.asm_syscall(); - } - a.asm_dec_r64(X64Reg::r8); - a.asm_jmp_label("_print_fract_part_initial_zeroes_loop"); - - a.add_label("_print_fract_part"); - a.asm_pop_r64(X64Reg::rax); // pop the zero ascii value from stack top - a.asm_push_r64(X64Reg::r15); - // print the fractional part - { - a.asm_call_label("print_i64"); - a.asm_add_r64_imm32(X64Reg::rsp, 8); // pop and increment stack pointer - } - } - - // Restore stack - a.asm_mov_r64_r64(X64Reg::rsp, X64Reg::rbp); - a.asm_pop_r64(X64Reg::rbp); - a.asm_ret(); -} -} // namespace LFortran diff --git a/src/libasr/codegen/x86_assembler.h b/src/libasr/codegen/x86_assembler.h deleted file mode 100644 index 8f21f3a7f2..0000000000 --- a/src/libasr/codegen/x86_assembler.h +++ /dev/null @@ -1,1556 +0,0 @@ -#ifndef LFORTRAN_CODEGEN_X86_ASSEMBER_H -#define LFORTRAN_CODEGEN_X86_ASSEMBER_H - -/* - -X86 Assembler implementation in the X86Assembler class. - -The goal of the X86Assembler class is to emit machine code as quickly as -possible. For that reason the assembler is implemented as a two pass assembler: -in the first pass it emits all the instructions as fixed size byte code, and in -the second pass it fixes all references to labels (jumps). As a result, the -final machine code is not the shortest possible, because jumps could possibly be -encoded shorter if the final relative address is shorter, but it would require -more passes and thus slower compilation. - -For debugging purposes, one can enable the macro LFORTRAN_ASM_PRINT and one can -then obtain a human readable assembly printout of all instructions. Disable the -macro for best performance. - -References: - -[1] Intel 64 and IA-32 Architectures Software Developer's Manual -Link: https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf - -Old Link: https://www.systutorials.com/go/intel-x86-64-reference-manual/ - -*/ - -#include -#include -#include -#include -#include - -#include -#include - -// Define to allow the Assembler print the asm instructions -#define LFORTRAN_ASM_PRINT - -#ifdef LFORTRAN_ASM_PRINT -# define EMIT(s) emit(" ", s) -# define EMIT_LABEL(s) emit("", s) -# define EMIT_VAR(a, b, c) emit(" ", a + " equ " + c + " - " + b) -#else -# define EMIT(s) -# define EMIT_LABEL(s) -# define EMIT_VAR(a, b) -#endif - -namespace LCompilers { - -enum X86Reg : uint8_t { - eax = 0, - ecx = 1, - edx = 2, - ebx = 3, - esp = 4, - ebp = 5, - esi = 6, - edi = 7, -}; - -static std::string r2s(X86Reg r32) { - switch (r32) { - case (X86Reg::eax) : return "eax"; - case (X86Reg::ecx) : return "ecx"; - case (X86Reg::edx) : return "edx"; - case (X86Reg::ebx) : return "ebx"; - case (X86Reg::esp) : return "esp"; - case (X86Reg::ebp) : return "ebp"; - case (X86Reg::esi) : return "esi"; - case (X86Reg::edi) : return "edi"; - default : throw AssemblerError("Unknown instruction"); - } -} - -enum X64Reg : uint8_t { - rax = 0, - rcx = 1, - rdx = 2, - rbx = 3, - rsp = 4, - rbp = 5, - rsi = 6, - rdi = 7, - r8 = 8, - r9 = 9, - r10 = 10, - r11 = 11, - r12 = 12, - r13 = 13, - r14 = 14, - r15 = 15, -}; - -static std::string r2s(X64Reg r64) { - switch (r64) { - case (X64Reg::rax) : return "rax"; - case (X64Reg::rcx) : return "rcx"; - case (X64Reg::rdx) : return "rdx"; - case (X64Reg::rbx) : return "rbx"; - case (X64Reg::rsp) : return "rsp"; - case (X64Reg::rbp) : return "rbp"; - case (X64Reg::rsi) : return "rsi"; - case (X64Reg::rdi) : return "rdi"; - case (X64Reg::r8 ) : return "r8" ; - case (X64Reg::r9 ) : return "r9" ; - case (X64Reg::r10) : return "r10"; - case (X64Reg::r11) : return "r11"; - case (X64Reg::r12) : return "r12"; - case (X64Reg::r13) : return "r13"; - case (X64Reg::r14) : return "r14"; - case (X64Reg::r15) : return "r15"; - default : throw AssemblerError("Unknown instruction"); - } -} -// Not sure if this numbering is correct. Numbering info -// about these registers does not seem easily available. -enum X86FReg : uint8_t { - st0 = 0, - st1 = 1, - st2 = 2, - st3 = 3, - st4 = 4, - st5 = 5, - st6 = 6, - st7 = 7, -}; - - -static std::string r2s(X86FReg st) { - switch (st) { - case (X86FReg::st0) : return "st0"; - case (X86FReg::st1) : return "st1"; - case (X86FReg::st2) : return "st2"; - case (X86FReg::st3) : return "st3"; - case (X86FReg::st4) : return "st4"; - case (X86FReg::st5) : return "st5"; - case (X86FReg::st6) : return "st6"; - case (X86FReg::st7) : return "st7"; - default : throw AssemblerError("Unknown instruction"); - } -} - -enum X64FReg : uint8_t { - xmm0 = 0, - xmm1 = 1, - xmm2 = 2, - xmm3 = 3, - xmm4 = 4, - xmm5 = 5, - xmm6 = 6, - xmm7 = 7, - xmm8 = 8, - xmm9 = 9, - xmm10 = 10, - xmm11 = 11, - xmm12 = 12, - xmm13 = 13, - xmm14 = 14, - xmm15 = 15, -}; - - -static std::string r2s(X64FReg xmm) { - switch (xmm) { - case (X64FReg::xmm0) : return "xmm0"; - case (X64FReg::xmm1) : return "xmm1"; - case (X64FReg::xmm2) : return "xmm2"; - case (X64FReg::xmm3) : return "xmm3"; - case (X64FReg::xmm4) : return "xmm4"; - case (X64FReg::xmm5) : return "xmm5"; - case (X64FReg::xmm6) : return "xmm6"; - case (X64FReg::xmm7) : return "xmm7"; - case (X64FReg::xmm8) : return "xmm8"; - case (X64FReg::xmm9) : return "xmm9"; - case (X64FReg::xmm10) : return "xmm10"; - case (X64FReg::xmm11) : return "xmm11"; - case (X64FReg::xmm12) : return "xmm12"; - case (X64FReg::xmm13) : return "xmm13"; - case (X64FReg::xmm14) : return "xmm14"; - case (X64FReg::xmm15) : return "xmm15"; - default : throw AssemblerError("Unknown instruction"); - } -} - -enum Fcmp : uint8_t { - eq = 0, - gt = 6, // (NLE in docs) - ge = 5, // (NLT in docs) - lt = 1, - le = 2, - ne = 4 -}; - -static std::string m2s(X64Reg *base, X64Reg *index, uint8_t scale, int64_t disp) { - std::string r; - r = "["; - if (base) r += r2s(*base); - if (index) { - if (base) r += "+"; - if (scale == 1) { - r += r2s(*index); - } else { - r += std::to_string(scale) + "*" + r2s(*index); - } - } - if (disp) { - if ((base || index) && (disp > 0)) r += "+"; - r += std::to_string(disp); - } - r += "]"; - return r; -} - -static std::string m2s(X86Reg *base, X86Reg *index, uint8_t scale, int32_t disp) { - std::string r; - r = "["; - if (base) r += r2s(*base); - if (index) { - if (base) r += "+"; - if (scale == 1) { - r += r2s(*index); - } else { - r += std::to_string(scale) + "*" + r2s(*index); - } - } - if (disp) { - if ((base || index) && (disp > 0)) r += "+"; - r += std::to_string(disp); - } - r += "]"; - return r; -} - -template< typename T > -static std::string hexify(T i) -{ - std::stringbuf buf; - std::ostream os(&buf); - os << std::setfill('0') << std::setw(sizeof(T) * 2) << std::hex << i; - return buf.str(); -} - -static std::string i2s(uint64_t imm64) { - return "0x" + hexify(imm64); -} - -static std::string i2s(uint32_t imm32) { - return "0x" + hexify(imm32); -} - -static std::string i2s(uint16_t imm16) { - return "0x" + hexify(imm16); -} - -static std::string i2s(uint8_t imm8) { - // hexify() for some reason does not work with uint8_t, only with longer - // integers - std::string s = hexify((uint16_t)imm8); - // Strip the two leading zeros - return "0x" + s.substr(2,4); -} - -static void push_back_uint64(Vec &code, Allocator &al, uint32_t i64) { - for (size_t i = 0u; i < 8u; i++) { - code.push_back(al, i64 & 0xFF); - i64 >>= 8; - } -} - -static void push_back_uint32(Vec &code, Allocator &al, uint32_t i32) { - code.push_back(al, (i32 ) & 0xFF); - code.push_back(al, (i32 >> 8) & 0xFF); - code.push_back(al, (i32 >> 16) & 0xFF); - code.push_back(al, (i32 >> 24) & 0xFF); -} - -static void insert_uint64(Vec &code, size_t pos, uint64_t i64) { - for (size_t i = 0u; i < 8u; i++) { - code.p[pos + i] = (i64 & 0xFF); - i64 >>= 8; - } -} - -static void insert_uint32(Vec &code, size_t pos, uint32_t i32) { - code.p[pos ] = (i32 ) & 0xFF; - code.p[pos+1] = (i32 >> 8) & 0xFF; - code.p[pos+2] = (i32 >> 16) & 0xFF; - code.p[pos+3] = (i32 >> 24) & 0xFF; -} - -static void push_back_uint16(Vec &code, Allocator &al, uint16_t i16) { - code.push_back(al, (i16 ) & 0xFF); - code.push_back(al, (i16 >> 8) & 0xFF); -} - -static void insert_uint16(Vec &code, size_t pos, uint16_t i16) { - code.p[pos ] = (i16 ) & 0xFF; - code.p[pos+1] = (i16 >> 8) & 0xFF; -} - -// Implements table 2-2 in [1]. -static uint8_t ModRM_byte(uint8_t mode, uint8_t reg, uint8_t rm) { - LCOMPILERS_ASSERT(mode <= 3); - LCOMPILERS_ASSERT(reg <= 7); - LCOMPILERS_ASSERT(rm <= 7); - return (mode << 6) | (reg << 3) | rm; -} - -// Implements table 2-3 in [1]. -static uint8_t SIB_byte(uint8_t base, uint8_t index, uint8_t scale_index) { - LCOMPILERS_ASSERT(base <= 7); - LCOMPILERS_ASSERT(index <= 7); - LCOMPILERS_ASSERT(scale_index <= 3); - return (scale_index << 6) | (index << 3) | base; -} - -// Implements the logic of tables 2-2 and 2-3 in [1] and correctly appends the -// SIB and displacement bytes as appropriate. -static void ModRM_SIB_disp_bytes(Vec &code, Allocator &al, - uint8_t mod, uint8_t reg, uint8_t rm, - uint8_t base, uint8_t index, uint8_t scale_index, int32_t disp) { - code.push_back(al, ModRM_byte(mod, reg, rm)); - if (rm == 0b100 && (mod == 0b00 || mod == 0b01 || mod == 0b10)) { - // SIB byte is present - code.push_back(al, SIB_byte(base, index, scale_index)); - } - if (mod == 0b01) { - // disp8 is present - LCOMPILERS_ASSERT(-128 <= disp && disp < 128); - uint8_t disp8 = disp; - code.push_back(al, disp8); - } else if ((mod == 0b00 && (rm==0b101 || base==0b101)) || (mod == 0b10)) { - // disp32 is present - uint32_t disp32 = disp; - push_back_uint32(code, al, disp32); - } -} - -static void modrm_sib_disp(Vec &code, Allocator &al, - X86Reg reg, - X86Reg *base_opt, // nullptr if None - X86Reg *index_opt, // nullptr if None - uint8_t scale, // 1 if None - int32_t disp, // 0 if None - bool mem) { - uint8_t mod, rm, base, index, scale_index; - - if (mem) { - // Determine mod - if (!base_opt || (disp == 0 && *base_opt != 0b101)) { - mod = 0b00; - } else if (-128 <= disp && disp < 128) { - mod = 0b01; - } else { - mod = 0b10; - } - - // Determine rm - if (index_opt) { - rm = 0b100; - } else if (!base_opt) { - rm = 0b101; - } else { - rm = *base_opt; - } - - // Determine base - if (base_opt) { - base = *base_opt; - } else if (index_opt) { - base = 0b101; - } else { - throw AssemblerError("base_opt or index_opt must be supplied if mem=true"); - } - - // Determine index - if (index_opt) { - index = *index_opt; - } else if (base == 0b100) { - index = 0b100; - } else { - // index will not be used, but silence a compiler warning: - index = 0; - } - } else { - mod = 0b11; - if (base_opt) { - base = *base_opt; - } else { - throw AssemblerError("base_opt must be supplied if mem=false"); - } - rm = base; - // index will not be used, but silence a compiler warning: - index = 0; - } - - switch (scale) { - case (1) : scale_index = 0b00; break; - case (2) : scale_index = 0b01; break; - case (4) : scale_index = 0b10; break; - case (8) : scale_index = 0b11; break; - default : throw AssemblerError("Scale must be one of [1, 2, 4, 8]"); - } - - ModRM_SIB_disp_bytes(code, al, mod, reg, rm, - base, index, scale_index, disp); -} - -struct Symbol { - std::string name; - uint32_t value; - bool defined; - Vec undefined_positions; - Vec undefined_positions_imm16; - Vec undefined_positions_rel; - Vec undefined_positions_64_bit; -}; - -class X86Assembler { - Allocator &m_al; - Vec m_code; - std::map m_symbols; - uint32_t m_origin; -#ifdef LFORTRAN_ASM_PRINT - std::string m_asm_code; - void emit(const std::string &indent, const std::string &s) { - m_asm_code += indent + s + "\n"; - } -#endif -public: - X86Assembler(Allocator &al, bool bits64) : m_al{al} { - m_code.reserve(m_al, 1024*128); - m_origin = 0x08048000; -#ifdef LFORTRAN_ASM_PRINT - if (bits64) { - m_asm_code = "BITS 64\n"; - emit(" ", "org " + i2s((uint64_t)m_origin) + "\n"); // specify origin info - } else { - m_asm_code = "BITS 32\n"; - emit(" ", "org " + i2s(m_origin) + "\n"); // specify origin info - } -#endif - } - -#ifdef LFORTRAN_ASM_PRINT - std::string get_asm() { - return m_asm_code; - } - - // Saves the generated assembly into a file - // Can be compiled with: - // nasm -f bin filename.asm - void save_asm(const std::string &filename) { - std::ofstream out; - out.open(filename); - out << get_asm(); - } -#endif - - Vec& get_machine_code() { - return m_code; - } - - void align_by_byte(uint64_t alignment) { - uint64_t code_size = m_code.size() ; - uint64_t padding_size = (alignment * ceil(code_size / (double)alignment)) - code_size; - for (size_t i = 0; i < padding_size; i++) { - m_code.push_back(m_al, 0); - } - EMIT("\n\talign " + std::to_string(alignment) + ", db 0"); - } - - void define_symbol(const std::string &name, uint32_t value) { - if (m_symbols.find(name) == m_symbols.end()) { - Symbol s; - s.defined = true; - s.value = value; - s.name = name; - m_symbols[name] = s; - } else { - Symbol &s = m_symbols[name]; - s.defined = true; - s.value = value; - // Fix previous undefined positions - for (size_t i=0; i < s.undefined_positions.size(); i++) { - uint32_t pos = s.undefined_positions[i]; - insert_uint32(m_code, pos, s.value); - } - for (size_t i=0; i < s.undefined_positions_rel.size(); i++) { - uint32_t pos = s.undefined_positions_rel[i]; - insert_uint32(m_code, pos, s.value-pos-m_origin-4); - } - for (size_t i=0; i < s.undefined_positions_imm16.size(); i++) { - uint32_t pos = s.undefined_positions_imm16[i]; - insert_uint16(m_code, pos, s.value); - } - for (size_t i=0; i < s.undefined_positions_64_bit.size(); i++) { - uint64_t pos = s.undefined_positions_64_bit[i]; - insert_uint64(m_code, pos, s.value); - } - } - } - - // Adds to undefined_positions, creates a symbol if needed - // type = 0 imm32 - // type = 1 imm16 - // type = 2 relative - Symbol &reference_symbol(const std::string &name, int type=0) { - if (m_symbols.find(name) == m_symbols.end()) { - Symbol s; - s.defined = false; - s.value = 0; - s.name = name; - s.undefined_positions.reserve(m_al, 8); - s.undefined_positions_imm16.reserve(m_al, 8); - s.undefined_positions_rel.reserve(m_al, 8); - s.undefined_positions_64_bit.reserve(m_al, 8); - m_symbols[name] = s; - } - Symbol &s = m_symbols[name]; - if (!s.defined) { - switch (type) { - case (0) : - s.undefined_positions.push_back(m_al, pos()-m_origin); - break; - case (1) : - s.undefined_positions_imm16.push_back(m_al, pos()-m_origin); - break; - case (2) : - s.undefined_positions_rel.push_back(m_al, pos()-m_origin); - break; - case (3) : // for 64-bit label - s.undefined_positions_64_bit.push_back(m_al, pos()-m_origin); - break; - default : throw AssemblerError("Unknown label type"); - } - } - return s; - } - - uint32_t relative_symbol(const std::string &name) { - return reference_symbol(name, 2).value-pos()-4; - } - - // Does not touch undefined_positions, symbol must be defined - Symbol &get_defined_symbol(const std::string &name) { - LCOMPILERS_ASSERT(m_symbols.find(name) != m_symbols.end()); - return m_symbols[name]; - } - - void add_label(const std::string &label) { - define_symbol(label, pos()); - EMIT_LABEL(label + ":"); - } - - void add_var64(const std::string &var, const std::string &start, const std::string &end) { - // TODO: Support 64-bit or 8 byte parameter val in define_symbol() - uint64_t val = get_defined_symbol(end).value - get_defined_symbol(start).value; - define_symbol(var, val); - EMIT_VAR(var, start, end); - } - - void add_var(const std::string &var, const std::string &start, const std::string &end) { - uint32_t val = get_defined_symbol(end).value - get_defined_symbol(start).value; - define_symbol(var, val); - EMIT_VAR(var, start, end); - } - - uint32_t pos() { - return m_origin + m_code.size(); - } - - uint32_t origin() { - return m_origin; - } - - // Verifies that all symbols are defined (and thus resolved). - void verify() { - for (auto &s : m_symbols) { - if (!s.second.defined) { - throw AssemblerError("The symbol '" + s.first + "' is undefined."); - } - } - } - - // Saves the generated machine code into a binary file - void save_binary(const std::string &filename); - - void asm_pop_r64(X64Reg r64) { - X86Reg r32 = X86Reg(r64 & 7); - m_code.push_back(m_al, rex(1, 0, 0, r64 >> 3)); - m_code.push_back(m_al, 0x58 + r32); - EMIT("pop " + r2s(r64)); - } - - void asm_pop_r32(X86Reg r32) { - m_code.push_back(m_al, 0x58 + r32); - EMIT("pop " + r2s(r32)); - } - - void asm_pop_r16(X86Reg r16) { - m_code.push_back(m_al, 0x66); - m_code.push_back(m_al, 0x58 + r16); - EMIT("popl " + r2s(r16)); - } - - void asm_push_r64(X64Reg r64) { - X86Reg r32 = X86Reg(r64 & 7); - m_code.push_back(m_al, rex(1, 0, 0, r64 >> 3)); - m_code.push_back(m_al, 0x50 + r32); - EMIT("push " + r2s(r64)); - } - - void asm_push_r32(X86Reg r32) { - m_code.push_back(m_al, 0x50 + r32); - EMIT("push " + r2s(r32)); - } - - void asm_push_r16(X86Reg r16) { - m_code.push_back(m_al, 0x66); - m_code.push_back(m_al, 0x50 + r16); - EMIT("pushl " + r2s(r16)); - } - - void asm_push_imm8(uint8_t imm8) { - m_code.push_back(m_al, 0x6a); - m_code.push_back(m_al, imm8); - EMIT("push " + i2s(imm8)); - } - - void asm_push_imm32(uint32_t imm32) { - m_code.push_back(m_al, 0x68); - push_back_uint32(m_code, m_al, imm32); - EMIT("push " + i2s(imm32)); - } - - void asm_jz_imm8(uint8_t imm8) { - m_code.push_back(m_al, 0x74); - m_code.push_back(m_al, imm8); - EMIT("jz " + i2s(imm8)); - } - - void asm_jnz_imm8(uint8_t imm8) { - m_code.push_back(m_al, 0x75); - m_code.push_back(m_al, imm8); - EMIT("jnz " + i2s(imm8)); - } - - void asm_jle_imm8(uint8_t imm8) { - m_code.push_back(m_al, 0x7e); - m_code.push_back(m_al, imm8); - EMIT("jle " + i2s(imm8)); - } - - void asm_jl_imm8(uint8_t imm8) { - m_code.push_back(m_al, 0x7c); - m_code.push_back(m_al, imm8); - EMIT("jl " + i2s(imm8)); - } - - void asm_jne_imm8(uint8_t imm8) { - asm_jnz_imm8(imm8); - } - - void asm_jge_imm8(uint8_t imm8) { - m_code.push_back(m_al, 0x7d); - m_code.push_back(m_al, imm8); - EMIT("jge " + i2s(imm8)); - } - - void asm_jge_imm32(uint32_t imm32) { - m_code.push_back(m_al, 0x0F); - m_code.push_back(m_al, 0x8D); - push_back_uint32(m_code, m_al, imm32); - EMIT("jge " + i2s(imm32)); - } - - // Jump if == - void asm_je_label(const std::string &label) { - m_code.push_back(m_al, 0x0F); - m_code.push_back(m_al, 0x84); - uint32_t imm32 = relative_symbol(label); - push_back_uint32(m_code, m_al, imm32); - EMIT("je " + label); - } - - // Jump if != - void asm_jne_label(const std::string &label) { - m_code.push_back(m_al, 0x0F); - m_code.push_back(m_al, 0x85); - uint32_t imm32 = relative_symbol(label); - push_back_uint32(m_code, m_al, imm32); - EMIT("jne " + label); - } - - // Jump if < - void asm_jl_label(const std::string &label) { - m_code.push_back(m_al, 0x0F); - m_code.push_back(m_al, 0x8C); - uint32_t imm32 = relative_symbol(label); - push_back_uint32(m_code, m_al, imm32); - EMIT("jl " + label); - } - - // Jump if <= - void asm_jle_label(const std::string &label) { - m_code.push_back(m_al, 0x0F); - m_code.push_back(m_al, 0x8E); - uint32_t imm32 = relative_symbol(label); - push_back_uint32(m_code, m_al, imm32); - EMIT("jle " + label); - } - - // Jump if > - void asm_jg_label(const std::string &label) { - m_code.push_back(m_al, 0x0F); - m_code.push_back(m_al, 0x8F); - uint32_t imm32 = relative_symbol(label); - push_back_uint32(m_code, m_al, imm32); - EMIT("jg " + label); - } - - // Jump if >= - void asm_jge_label(const std::string &label) { - m_code.push_back(m_al, 0x0F); - m_code.push_back(m_al, 0x8D); - uint32_t imm32 = relative_symbol(label); - push_back_uint32(m_code, m_al, imm32); - EMIT("jge " + label); - } - - void asm_inc_r64(X64Reg r64) { - X86Reg r32 = X86Reg(r64 & 7); - m_code.push_back(m_al, rex(1, 0, 0, r64 >> 3)); - m_code.push_back(m_al, 0xFF); - modrm_sib_disp(m_code, m_al, - X86Reg::eax, &r32, nullptr, 1, 0, false); - EMIT("inc " + r2s(r64)); - } - - void asm_inc_r32(X86Reg r32) { - m_code.push_back(m_al, 0x40+r32); - EMIT("inc " + r2s(r32)); - } - - void asm_dec_r64(X64Reg r64) { - X86Reg r32 = X86Reg(r64 & 7); - m_code.push_back(m_al, rex(1, 0, 0, r64 >> 3)); - m_code.push_back(m_al, 0xFF); - modrm_sib_disp(m_code, m_al, - X86Reg::ecx, &r32, nullptr, 1, 0, false); - EMIT("dec " + r2s(r64)); - } - - void asm_dec_r32(X86Reg r32) { - m_code.push_back(m_al, 0x48+r32); - EMIT("dec " + r2s(r32)); - } - - void asm_inc_m32(X86Reg *base, X86Reg *index, uint8_t scale, int32_t disp) { - m_code.push_back(m_al, 0xff); - modrm_sib_disp(m_code, m_al, - X86Reg::eax, base, index, scale, disp, true); - EMIT("inc " + m2s(base, index, scale, disp)); - } - - void asm_int_imm8(uint8_t imm8) { - m_code.push_back(m_al, 0xcd); - m_code.push_back(m_al, imm8); - EMIT("int " + i2s(imm8)); - } - - void asm_ret() { - m_code.push_back(m_al, 0xc3); - EMIT("ret"); - } - - void asm_mov_r32_imm32(X86Reg r32, uint32_t imm32) { - m_code.push_back(m_al, 0xb8 + r32); - push_back_uint32(m_code, m_al, imm32); - EMIT("mov " + r2s(r32) + ", " + i2s(imm32)); - } - - uint8_t rex(uint8_t W, uint8_t R, uint8_t X, uint8_t B) { - LCOMPILERS_ASSERT(W <= 1); - LCOMPILERS_ASSERT(R <= 1); - LCOMPILERS_ASSERT(X <= 1); - LCOMPILERS_ASSERT(B <= 1); - return (0b01000000 | (W << 3) | (R << 2) | (X << 1) | B); - } - - void asm_mov_r64_imm64(X64Reg r64, uint64_t imm64) { - X86Reg r32 = X86Reg(r64 & 7); - m_code.push_back(m_al, rex(1, 0, 0, r64 >> 3)); - m_code.push_back(m_al, 0xb8 + r32); - push_back_uint64(m_code, m_al, imm64); - EMIT("mov " + r2s(r64) + ", " + i2s(imm64)); - } - - void asm_mov_r64_label(X64Reg r64, const std::string &label) { - X86Reg r32 = X86Reg(r64 & 7); - m_code.push_back(m_al, rex(1, 0, 0, r64 >> 3)); - m_code.push_back(m_al, 0xb8 + r32); - // TODO: reference_symbol().value should return 64-bit value - uint64_t imm64 = reference_symbol(label).value; - push_back_uint64(m_code, m_al, imm64); - EMIT("mov " + r2s(r64) + ", " + label); - } - - void asm_mov_r32_label(X86Reg r32, const std::string &label) { - m_code.push_back(m_al, 0xb8 + r32); - uint32_t imm32 = reference_symbol(label).value; - push_back_uint32(m_code, m_al, imm32); - EMIT("mov " + r2s(r32) + ", " + label); - } - - void asm_mov_r64_r64(X64Reg r64, X64Reg s64) { - X86Reg r32 = X86Reg(r64 & 7), s32 = X86Reg(s64 & 7); - m_code.push_back(m_al, rex(1, s64 >> 3, 0, r64 >> 3)); - m_code.push_back(m_al, 0x89); - modrm_sib_disp(m_code, m_al, - s32, &r32, nullptr, 1, 0, false); - EMIT("mov " + r2s(r64) + ", " + r2s(s64)); - } - - void asm_mov_r32_r32(X86Reg r32, X86Reg s32) { - m_code.push_back(m_al, 0x89); - modrm_sib_disp(m_code, m_al, - s32, &r32, nullptr, 1, 0, false); - EMIT("mov " + r2s(r32) + ", " + r2s(s32)); - } - - void asm_mov_r64_m64(X64Reg r64, X64Reg *base, X64Reg *index, - uint8_t scale, int64_t disp) { - X86Reg r32 = X86Reg(r64 & 7); - m_code.push_back(m_al, rex(1, r64 >> 3, (index ? (*index >> 3) : 0), (base ? (*base >> 3) : 0))); - m_code.push_back(m_al, 0x8b); - X86Reg base32, index32; - if (base) base32 = X86Reg(*base & 7); - if (index) index32 = X86Reg(*index & 7); - modrm_sib_disp(m_code, m_al, r32, (base ? &base32 : nullptr), - (index ? &index32 : nullptr), scale, (int32_t)disp, true); - EMIT("mov " + r2s(r64) + ", " + m2s(base, index, scale, disp)); - } - - void asm_mov_r32_m32(X86Reg r32, X86Reg *base, X86Reg *index, - uint8_t scale, int32_t disp) { - if (r32 == X86Reg::eax && !base && !index) { - m_code.push_back(m_al, 0xa1); - uint32_t disp32 = disp; - push_back_uint32(m_code, m_al, disp32); - } else { - m_code.push_back(m_al, 0x8b); - modrm_sib_disp(m_code, m_al, - r32, base, index, scale, disp, true); - } - EMIT("mov " + r2s(r32) + ", " + m2s(base, index, scale, disp)); - } - - void asm_mov_m64_r64(X64Reg *base, X64Reg *index, - uint8_t scale, int64_t disp, X64Reg r64) { - X86Reg r32 = X86Reg(r64 & 7); - m_code.push_back(m_al, rex(1, r64 >> 3, (index ? (*index >> 3) : 0), (base ? (*base >> 3) : 0))); - m_code.push_back(m_al, 0x89); - X86Reg base32, index32; - if (base) base32 = X86Reg(*base & 7); - if (index) index32 = X86Reg(*index & 7); - modrm_sib_disp(m_code, m_al, r32, (base ? &base32 : nullptr), - (index ? &index32 : nullptr), scale, (int32_t)disp, true); - EMIT("mov " + m2s(base, index, scale, disp) + ", " + r2s(r64)); - } - - void asm_mov_m32_r32(X86Reg *base, X86Reg *index, - uint8_t scale, int32_t disp, X86Reg r32) { - if (r32 == X86Reg::eax && !base && !index) { - m_code.push_back(m_al, 0xa3); - uint32_t disp32 = disp; - push_back_uint32(m_code, m_al, disp32); - } else { - m_code.push_back(m_al, 0x89); - modrm_sib_disp(m_code, m_al, - r32, base, index, scale, disp, true); - } - EMIT("mov " + m2s(base, index, scale, disp) + ", " + r2s(r32)); - } - - void asm_test_r32_r32(X86Reg r32, X86Reg s32) { - m_code.push_back(m_al, 0x85); - modrm_sib_disp(m_code, m_al, - s32, &r32, nullptr, 1, 0, false); - EMIT("test " + r2s(r32) + ", " + r2s(s32)); - } - - void asm_sub_r32_imm8(X86Reg r32, uint8_t imm8) { - m_code.push_back(m_al, 0x83); - modrm_sib_disp(m_code, m_al, - X86Reg::ebp, &r32, nullptr, 1, 0, false); - m_code.push_back(m_al, imm8); - EMIT("sub " + r2s(r32) + ", " + i2s(imm8)); - } - - void asm_sub_r32_imm32(X86Reg r32, uint32_t imm32) { - m_code.push_back(m_al, 0x81); - modrm_sib_disp(m_code, m_al, - X86Reg::ebp, &r32, nullptr, 1, 0, false); - push_back_uint32(m_code, m_al, imm32); - EMIT("sub " + r2s(r32) + ", " + i2s(imm32)); - } - - void asm_sub_r64_imm32(X64Reg r64, uint32_t imm32) { - X86Reg r32 = X86Reg(r64 & 7); - m_code.push_back(m_al, rex(1, 0, 0, r64 >> 3)); - m_code.push_back(m_al, 0x81); - modrm_sib_disp(m_code, m_al, - X86Reg::ebp, &r32, nullptr, 1, 0, false); - push_back_uint32(m_code, m_al, imm32); - EMIT("sub " + r2s(r64) + ", " + i2s(imm32)); - } - - void asm_sub_r64_r64(X64Reg r64, X64Reg s64) { - X86Reg r32 = X86Reg(r64 & 7), s32 = X86Reg(s64 & 7); - m_code.push_back(m_al, rex(1, s64 >> 3, 0, r64 >> 3)); - m_code.push_back(m_al, 0x29); - modrm_sib_disp(m_code, m_al, - s32, &r32, nullptr, 1, 0, false); - EMIT("sub " + r2s(r64) + ", " + r2s(s64)); - } - - void asm_sub_r32_r32(X86Reg r32, X86Reg s32) { - m_code.push_back(m_al, 0x29); - modrm_sib_disp(m_code, m_al, - s32, &r32, nullptr, 1, 0, false); - EMIT("sub " + r2s(r32) + ", " + r2s(s32)); - } - - void asm_sar_r32_imm8(X86Reg r32, uint8_t imm8) { - if (r32 == X86Reg::eax) { - m_code.push_back(m_al, 0xc1); - m_code.push_back(m_al, 0xf8); - m_code.push_back(m_al, imm8); - } else { - throw AssemblerError("Not implemented."); - } - EMIT("sar " + r2s(r32) + ", " + i2s(imm8)); - } - - void asm_cmp_r64_imm8(X64Reg r64, uint8_t imm8) { - X86Reg r32 = X86Reg(r64 & 7); - m_code.push_back(m_al, rex(1, 0, 0, r64 >> 3)); - m_code.push_back(m_al, 0x83); - modrm_sib_disp(m_code, m_al, - X86Reg::edi, &r32, nullptr, 1, 0, false); - m_code.push_back(m_al, imm8); - EMIT("cmp " + r2s(r64) + ", " + i2s(imm8)); - } - - void asm_cmp_r32_imm8(X86Reg r32, uint8_t imm8) { - m_code.push_back(m_al, 0x83); - modrm_sib_disp(m_code, m_al, - X86Reg::edi, &r32, nullptr, 1, 0, false); - m_code.push_back(m_al, imm8); - EMIT("cmp " + r2s(r32) + ", " + i2s(imm8)); - } - - void asm_cmp_r64_r64(X64Reg r64, X64Reg s64) { - X86Reg r32 = X86Reg(r64 & 7), s32 = X86Reg(s64 & 7); - m_code.push_back(m_al, rex(1, s64 >> 3, 0, r64 >> 3)); - m_code.push_back(m_al, 0x39); - modrm_sib_disp(m_code, m_al, - s32, &r32, nullptr, 1, 0, false); - EMIT("cmp " + r2s(r64) + ", " + r2s(s64)); - } - - void asm_cmp_r32_r32(X86Reg r32, X86Reg s32) { - m_code.push_back(m_al, 0x39); - modrm_sib_disp(m_code, m_al, - s32, &r32, nullptr, 1, 0, false); - EMIT("cmp " + r2s(r32) + ", " + r2s(s32)); - } - - // CMPSD—Compare Scalar Double Precision Floating-Point Value - void asm_cmpsd_r64_r64(X64FReg r64, X64FReg s64, uint8_t imm8) { - X86Reg r32 = X86Reg(r64 & 7), s32 = X86Reg(s64 & 7); - m_code.push_back(m_al, 0xf2); - m_code.push_back(m_al, rex(1, r64 >> 3, 0, s64 >> 3)); - m_code.push_back(m_al, 0x0f); - m_code.push_back(m_al, 0xc2); - modrm_sib_disp(m_code, m_al, - r32, &s32, nullptr, 1, 0, false); - m_code.push_back(m_al, imm8); - EMIT("cmpsd " + r2s(r64) + ", " + r2s(s64) + ", " + i2s(imm8)); - } - - void asm_jmp_imm8(uint8_t imm8) { - m_code.push_back(m_al, 0xeb); - m_code.push_back(m_al, imm8); - EMIT("jmp " + i2s(imm8)); - } - - void asm_jmp_imm32(uint32_t imm32) { - m_code.push_back(m_al, 0xe9); - push_back_uint32(m_code, m_al, imm32); - EMIT("jmp " + i2s(imm32)); - } - - void asm_jmp_label(const std::string &label) { - m_code.push_back(m_al, 0xe9); - uint32_t imm32 = relative_symbol(label); - push_back_uint32(m_code, m_al, imm32); - EMIT("jmp " + label); - } - - void asm_call_imm32(uint32_t imm32) { - m_code.push_back(m_al, 0xe8); - push_back_uint32(m_code, m_al, imm32); - EMIT("call " + i2s(imm32)); - } - - void asm_call_label(const std::string &label) { - m_code.push_back(m_al, 0xe8); - uint32_t imm32 = relative_symbol(label); - push_back_uint32(m_code, m_al, imm32); - EMIT("call " + label); - } - - void asm_shl_r32_imm8(X86Reg r32, uint8_t imm8) { - if (r32 == X86Reg::eax) { - m_code.push_back(m_al, 0xc1); - m_code.push_back(m_al, 0xe0); - m_code.push_back(m_al, imm8); - } else { - throw AssemblerError("Not implemented."); - } - EMIT("shl " + r2s(r32) + ", " + i2s(imm8)); - } - - void asm_db_imm8(uint8_t imm8) { - m_code.push_back(m_al, imm8); - EMIT("db " + i2s(imm8)); - } - - void asm_db_imm8(const void *data, size_t size) { - const uint8_t *data_char=(const uint8_t*)data; - for (size_t i=0; i < size; i++) { - asm_db_imm8(data_char[i]); - } - } - - void asm_dw_imm16(uint16_t imm16) { - push_back_uint16(m_code, m_al, imm16); - EMIT("dw " + i2s(imm16)); - } - - void asm_dd_imm32(uint32_t imm32) { - push_back_uint32(m_code, m_al, imm32); - EMIT("dd " + i2s(imm32)); - } - - void asm_dq_imm64(uint64_t imm64) { - push_back_uint64(m_code, m_al, imm64); - EMIT("dq " + i2s(imm64)); - } - - void asm_dw_label(const std::string &label) { - uint32_t imm16 = reference_symbol(label, 1).value; - push_back_uint16(m_code, m_al, imm16); - EMIT("dw " + label); - } - - void asm_dd_label(const std::string &label) { - uint32_t imm32 = reference_symbol(label).value; - push_back_uint32(m_code, m_al, imm32); - EMIT("dd " + label); - } - - void asm_dq_label(const std::string &label) { - uint64_t imm64 = reference_symbol(label, 3).value; - push_back_uint64(m_code, m_al, imm64); - EMIT("dq " + label); - } - - void asm_add_m32_r32(X86Reg *base, X86Reg *index, - uint8_t scale, int32_t disp, X86Reg r32) { - m_code.push_back(m_al, 0x01); - modrm_sib_disp(m_code, m_al, - r32, base, index, scale, disp, true); - EMIT("add " + m2s(base, index, scale, disp) + ", " + r2s(r32)); - } - - void asm_add_r64_r64(X64Reg s64, X64Reg r64) { - X86Reg r32 = X86Reg(r64 & 7), s32 = X86Reg(s64 & 7); - m_code.push_back(m_al, rex(1, r64 >> 3, 0, s64 >> 3)); - m_code.push_back(m_al, 0x01); - modrm_sib_disp(m_code, m_al, - r32, &s32, nullptr, 1, 0, false); - EMIT("add " + r2s(s64) + ", " + r2s(r64)); - } - - void asm_add_r32_r32(X86Reg s32, X86Reg r32) { - m_code.push_back(m_al, 0x01); - modrm_sib_disp(m_code, m_al, - r32, &s32, nullptr, 1, 0, false); - EMIT("add " + r2s(s32) + ", " + r2s(r32)); - } - - void asm_add_r32_imm8(X86Reg r32, uint8_t imm8) { - m_code.push_back(m_al, 0x83); - modrm_sib_disp(m_code, m_al, - X86Reg::eax, &r32, nullptr, 1, 0, false); - m_code.push_back(m_al, imm8); - EMIT("add " + r2s(r32) + ", " + i2s(imm8)); - } - - // Only 'ADD r/m64, imm32' is available in assembly - void asm_add_r64_imm32(X64Reg r64, uint32_t imm32) { - X86Reg r32 = X86Reg(r64 & 7); - m_code.push_back(m_al, rex(1, 0, 0, r64 >> 3)); - m_code.push_back(m_al, 0x81); - modrm_sib_disp(m_code, m_al, - X86Reg::eax, &r32, nullptr, 1, 0, false); - push_back_uint32(m_code, m_al, imm32); - EMIT("add " + r2s(r64) + ", " + i2s(imm32)); - } - - void asm_add_r32_imm32(X86Reg r32, uint32_t imm32) { - m_code.push_back(m_al, 0x81); - modrm_sib_disp(m_code, m_al, - X86Reg::eax, &r32, nullptr, 1, 0, false); - push_back_uint32(m_code, m_al, imm32); - EMIT("add " + r2s(r32) + ", " + i2s(imm32)); - } - - void asm_mul_r64(X64Reg r64) { - X86Reg r32 = X86Reg(r64 & 7); - m_code.push_back(m_al, rex(1, 0, 0, r64 >> 3)); - m_code.push_back(m_al, 0xF7); - modrm_sib_disp(m_code, m_al, - X86Reg::esp, &r32, nullptr, 1, 0, false); - EMIT("mul " + r2s(r64)); - } - - void asm_mul_r32(X86Reg r32) { - m_code.push_back(m_al, 0xF7); - modrm_sib_disp(m_code, m_al, - X86Reg::esp, &r32, nullptr, 1, 0, false); - EMIT("mul " + r2s(r32)); - } - - void asm_div_r64(X64Reg r64) { - X86Reg r32 = X86Reg(r64 & 7); - m_code.push_back(m_al, rex(1, 0, 0, r64 >> 3)); - m_code.push_back(m_al, 0xF7); - modrm_sib_disp(m_code, m_al, - X86Reg::esi, &r32, nullptr, 1, 0, false); - EMIT("div " + r2s(r64)); - } - - void asm_div_r32(X86Reg r32) { - m_code.push_back(m_al, 0xF7); - modrm_sib_disp(m_code, m_al, - X86Reg::esi, &r32, nullptr, 1, 0, false); - EMIT("div " + r2s(r32)); - } - - void asm_neg_r64(X64Reg r64) { - X86Reg r32 = X86Reg(r64 & 7); - m_code.push_back(m_al, rex(1, 0, 0, r64 >> 3)); - m_code.push_back(m_al, 0xF7); - modrm_sib_disp(m_code, m_al, - X86Reg::ebx, &r32, nullptr, 1, 0, false); - EMIT("neg " + r2s(r64)); - } - - void asm_neg_r32(X86Reg r32) { - m_code.push_back(m_al, 0xF7); - modrm_sib_disp(m_code, m_al, - X86Reg::ebx, &r32, nullptr, 1, 0, false); - EMIT("neg " + r2s(r32)); - } - - void asm_lea_r32_m32(X86Reg r32, X86Reg *base, X86Reg *index, - uint8_t scale, int32_t disp) { - m_code.push_back(m_al, 0x8d); - modrm_sib_disp(m_code, m_al, - r32, base, index, scale, disp, true); - EMIT("lea " + r2s(r32) + ", " + m2s(base, index, scale, disp)); - } - - void asm_and_r64_imm8(X64Reg r64, uint8_t imm8) { - X86Reg r32 = X86Reg(r64 & 7); - m_code.push_back(m_al, rex(1, 0, 0, r64 >> 3)); - m_code.push_back(m_al, 0x83); - modrm_sib_disp(m_code, m_al, X86Reg::esp, &r32, nullptr, 1, 0, false); - m_code.push_back(m_al, imm8); - EMIT("and " + r2s(r32) + ", " + i2s(imm8)); - } - - void asm_and_r32_imm32(X86Reg r32, uint32_t imm32) { - if (r32 == X86Reg::eax) { - m_code.push_back(m_al, 0x25); - push_back_uint32(m_code, m_al, imm32); - } else { - throw AssemblerError("Not implemented."); - } - EMIT("and " + r2s(r32) + ", " + i2s(imm32)); - } - - void asm_and_r64_r64(X64Reg r64, X64Reg s64) { - X86Reg r32 = X86Reg(r64 & 7), s32 = X86Reg(s64 & 7); - m_code.push_back(m_al, rex(1, r64 >> 3, 0, s64 >> 3)); - m_code.push_back(m_al, 0x23); - modrm_sib_disp(m_code, m_al, r32, &s32, nullptr, 1, 0, false); - EMIT("and " + r2s(r64) + ", " + r2s(s64)); - } - - void asm_and_r32_r32(X86Reg r32, X86Reg s32) { - m_code.push_back(m_al, 0x23); - modrm_sib_disp(m_code, m_al, r32, &s32, nullptr, 1, 0, false); - EMIT("and " + r2s(r32) + ", " + r2s(r32)); - } - - void asm_or_r64_r64(X64Reg r64, X64Reg s64) { - X86Reg r32 = X86Reg(r64 & 7), s32 = X86Reg(s64 & 7); - m_code.push_back(m_al, rex(1, r64 >> 3, 0, s64 >> 3)); - m_code.push_back(m_al, 0x0B); - modrm_sib_disp(m_code, m_al, r32, &s32, nullptr, 1, 0, false); - EMIT("or " + r2s(r64) + ", " + r2s(s64)); - } - - void asm_or_r32_r32(X86Reg r32, X86Reg s32) { - m_code.push_back(m_al, 0x0B); - modrm_sib_disp(m_code, m_al, r32, &s32, nullptr, 1, 0, false); - EMIT("or " + r2s(r32) + ", " + r2s(r32)); - } - - void asm_xor_r64_r64(X64Reg r64, X64Reg s64) { - X86Reg r32 = X86Reg(r64 & 7), s32 = X86Reg(s64 & 7); - m_code.push_back(m_al, rex(1, r64 >> 3, 0, s64 >> 3)); - m_code.push_back(m_al, 0x33); - modrm_sib_disp(m_code, m_al, r32, &s32, nullptr, 1, 0, false); - EMIT("xor " + r2s(r64) + ", " + r2s(s64)); - } - - void asm_xor_r32_r32(X86Reg r32, X86Reg s32) { - m_code.push_back(m_al, 0x31); - modrm_sib_disp(m_code, m_al, - s32, &r32, nullptr, 1, 0, false); - EMIT("xor " + r2s(r32) + ", " + r2s(s32)); - } - - void asm_syscall() { - m_code.push_back(m_al, 0x0F); - m_code.push_back(m_al, 0x05); - EMIT("syscall"); - } - - // SHL - Shift Logical/Unsigned Left - void asm_shl_r64_cl(X64Reg r64) { - X86Reg r32 = X86Reg(r64 & 7); - m_code.push_back(m_al, rex(1, 0, 0, r64 >> 3)); - m_code.push_back(m_al, 0xD3); - modrm_sib_disp(m_code, m_al, X86Reg::esp, &r32, nullptr, 1, 0, false); - EMIT("shl " + r2s(r64) + ", cl"); - } - - // SHL - Shift Logical/Unsigned Left - void asm_shl_r32_cl(X86Reg r32) { - m_code.push_back(m_al, 0xD3); - modrm_sib_disp(m_code, m_al, X86Reg::esp, &r32, nullptr, 1, 0, false); - EMIT("shl " + r2s(r32) + ", cl"); - } - - // SAR - Shift Arithmetic/Signed Right - void asm_sar_r64_cl(X64Reg r64) { - X86Reg r32 = X86Reg(r64 & 7); - m_code.push_back(m_al, rex(1, 0, 0, r64 >> 3)); - m_code.push_back(m_al, 0xD3); - modrm_sib_disp(m_code, m_al, X86Reg::edi, &r32, nullptr, 1, 0, false); - EMIT("sar " + r2s(r64) + ", cl"); - } - - // SAR - Shift Arithmetic/Signed Right - void asm_sar_r32_cl(X86Reg r32) { - m_code.push_back(m_al, 0xD3); - modrm_sib_disp(m_code, m_al, X86Reg::edi, &r32, nullptr, 1, 0, false); - EMIT("sar " + r2s(r32) + ", cl"); - } - - void asm_fld_m32(X86Reg *base, X86Reg *index, - uint8_t scale, int32_t disp) { - m_code.push_back(m_al, 0xd9); - modrm_sib_disp(m_code, m_al, - X86Reg::eax, base, index, scale, disp, true); - EMIT("fld dword " + m2s(base, index, scale, disp)); - } - - void asm_fst_m32(X86Reg *base, X86Reg *index, - uint8_t scale, int32_t disp) { - m_code.push_back(m_al, 0xd9); - modrm_sib_disp(m_code, m_al, - X86Reg::edx, base, index, scale, disp, true); - EMIT("fst dword " + m2s(base, index, scale, disp)); - } - - void asm_fstp_m32(X86Reg *base, X86Reg *index, - uint8_t scale, int32_t disp) { - m_code.push_back(m_al, 0xd9); - modrm_sib_disp(m_code, m_al, - X86Reg::ebx, base, index, scale, disp, true); - EMIT("fstp dword " + m2s(base, index, scale, disp)); - } - - void asm_fist_m32(X86Reg *base, X86Reg *index, - uint8_t scale, int32_t disp) { - m_code.push_back(m_al, 0xdb); - modrm_sib_disp(m_code, m_al, - X86Reg::edx, base, index, scale, disp, true); - EMIT("fist dword " + m2s(base, index, scale, disp)); - } - - void asm_fistp_m32(X86Reg *base, X86Reg *index, - uint8_t scale, int32_t disp) { - m_code.push_back(m_al, 0xdb); - modrm_sib_disp(m_code, m_al, - X86Reg::ebx, base, index, scale, disp, true); - EMIT("fistp dword " + m2s(base, index, scale, disp)); - } - - void asm_frndint() { - m_code.push_back(m_al, 0xd9); - m_code.push_back(m_al, 0xfc); - EMIT("frndint"); - } - - void asm_fsub(X86FReg st) { - m_code.push_back(m_al, 0xd8); - m_code.push_back(m_al, 0xe0 + st); - EMIT("fsub " + r2s(X86FReg::st0) + ", " + r2s(st)); - } - - void asm_fsubp() { - m_code.push_back(m_al, 0xde); - m_code.push_back(m_al, 0xe9); - EMIT("fsubp"); - } - - void asm_fimul_m32int(X86Reg *base, X86Reg *index, - uint8_t scale, int32_t disp) { - m_code.push_back(m_al, 0xda); - modrm_sib_disp(m_code, m_al, - X86Reg::ecx, base, index, scale, disp, true); - EMIT("fimul dword " + m2s(base, index, scale, disp)); - } - - // Move or Merge Scalar Double Precision Floating-Point Value - void asm_movsd_r64_m64(X64FReg r64, X64Reg *base, X64Reg *index, - uint8_t scale, int64_t disp) { - X86Reg r32 = X86Reg(r64 & 7); - m_code.push_back(m_al, 0xf2); - m_code.push_back(m_al, rex(1, r64 >> 3, (index ? (*index >> 3) : 0), (base ? (*base >> 3) : 0))); - m_code.push_back(m_al, 0x0f); - m_code.push_back(m_al, 0x10); - X86Reg base32, index32; - if (base) base32 = X86Reg(*base & 7); - if (index) index32 = X86Reg(*index & 7); - modrm_sib_disp(m_code, m_al, r32, (base ? &base32 : nullptr), - (index ? &index32 : nullptr), scale, (int32_t)disp, true); - EMIT("movsd " + r2s(r64) + ", " + m2s(base, index, scale, disp)); - } - - // Move or Merge Scalar Double Precision Floating-Point Value - void asm_movsd_m64_r64(X64Reg *base, X64Reg *index, - uint8_t scale, int64_t disp, X64FReg r64) { - X86Reg r32 = X86Reg(r64 & 7); - m_code.push_back(m_al, 0xf2); - m_code.push_back(m_al, rex(1, r64 >> 3, (index ? (*index >> 3) : 0), (base ? (*base >> 3) : 0))); - m_code.push_back(m_al, 0x0f); - m_code.push_back(m_al, 0x11); - X86Reg base32, index32; - if (base) base32 = X86Reg(*base & 7); - if (index) index32 = X86Reg(*index & 7); - modrm_sib_disp(m_code, m_al, r32, (base ? &base32 : nullptr), - (index ? &index32 : nullptr), scale, (int32_t)disp, true); - EMIT("movsd " + m2s(base, index, scale, disp) + ", " + r2s(r64)); - } - - // ADDSD—Add Scalar Double Precision Floating-Point Values - void asm_addsd_r64_r64(X64FReg r64, X64FReg s64) { - X86Reg r32 = X86Reg(r64 & 7), s32 = X86Reg(s64 & 7); - m_code.push_back(m_al, 0xf2); - m_code.push_back(m_al, rex(1, r64 >> 3, 0, s64 >> 3)); - m_code.push_back(m_al, 0x0f); - m_code.push_back(m_al, 0x58); - modrm_sib_disp(m_code, m_al, - r32, &s32, nullptr, 1, 0, false); - EMIT("addsd " + r2s(r64) + ", " + r2s(s64)); - } - - // Subtract Scalar Double Precision Floating-Point Value - void asm_subsd_r64_r64(X64FReg r64, X64FReg s64) { - X86Reg r32 = X86Reg(r64 & 7), s32 = X86Reg(s64 & 7); - m_code.push_back(m_al, 0xf2); - m_code.push_back(m_al, rex(1, r64 >> 3, 0, s64 >> 3)); - m_code.push_back(m_al, 0x0f); - m_code.push_back(m_al, 0x5c); - modrm_sib_disp(m_code, m_al, - r32, &s32, nullptr, 1, 0, false); - EMIT("subsd " + r2s(r64) + ", " + r2s(s64)); - } - - // Multiply Scalar Double Precision Floating-Point Value - void asm_mulsd_r64_r64(X64FReg r64, X64FReg s64) { - X86Reg r32 = X86Reg(r64 & 7), s32 = X86Reg(s64 & 7); - m_code.push_back(m_al, 0xf2); - m_code.push_back(m_al, rex(1, r64 >> 3, 0, s64 >> 3)); - m_code.push_back(m_al, 0x0f); - m_code.push_back(m_al, 0x59); - modrm_sib_disp(m_code, m_al, - r32, &s32, nullptr, 1, 0, false); - EMIT("mulsd " + r2s(r64) + ", " + r2s(s64)); - } - - // Divide Scalar Double Precision Floating-Point Value - void asm_divsd_r64_r64(X64FReg r64, X64FReg s64) { - X86Reg r32 = X86Reg(r64 & 7), s32 = X86Reg(s64 & 7); - m_code.push_back(m_al, 0xf2); - m_code.push_back(m_al, rex(1, r64 >> 3, 0, s64 >> 3)); - m_code.push_back(m_al, 0x0f); - m_code.push_back(m_al, 0x5e); - modrm_sib_disp(m_code, m_al, - r32, &s32, nullptr, 1, 0, false); - EMIT("divsd " + r2s(r64) + ", " + r2s(s64)); - } - - // Convert Doubleword Integer to Scalar Double Precision Floating-Point Value - void asm_cvtsi2sd_r64_r64(X64FReg r64, X64Reg s64) { - X86Reg r32 = X86Reg(r64 & 7), s32 = X86Reg(s64 & 7); - m_code.push_back(m_al, 0xf2); - m_code.push_back(m_al, rex(1, r64 >> 3, 0, s64 >> 3)); - m_code.push_back(m_al, 0x0f); - m_code.push_back(m_al, 0x2a); - modrm_sib_disp(m_code, m_al, - r32, &s32, nullptr, 1, 0, false); - EMIT("cvtsi2sd " + r2s(r64) + ", " + r2s(s64)); - } - - // Convert With Truncation Scalar Double Precision Floating-Point Value to Signed Integer - void asm_cvttsd2si_r64_r64(X64Reg r64, X64FReg s64) { - X86Reg r32 = X86Reg(r64 & 7), s32 = X86Reg(s64 & 7); - m_code.push_back(m_al, 0xf2); - m_code.push_back(m_al, rex(1, r64 >> 3, 0, s64 >> 3)); - m_code.push_back(m_al, 0x0f); - m_code.push_back(m_al, 0x2c); - modrm_sib_disp(m_code, m_al, - r32, &s32, nullptr, 1, 0, false); - EMIT("cvttsd2si " + r2s(r64) + ", " + r2s(s64)); - } - - // PMOVMSKB—Move Byte Mask - // Creates a mask made up of the most significant bit of each byte - // of the source operand (second operand) and stores the result in the low byte - // or word of the destination operand (first operand) - void asm_pmovmskb_r32_r64(X86Reg r32, X64FReg s64) { - X86Reg s32 = X86Reg(s64 & 7); - m_code.push_back(m_al, rex(1, 0, 0, s64 >> 3)); - m_code.push_back(m_al, 0x66); - m_code.push_back(m_al, 0x0f); - m_code.push_back(m_al, 0xd7); - modrm_sib_disp(m_code, m_al, r32, &s32, nullptr, 1, 0, false); - EMIT("pmovmskb " + r2s(r32) + ", " + r2s(s64)); - } - - // UCOMISD—Unordered Compare Scalar Double Precision Floating-Point Values and Set EFLAGS - void asm_ucomisd_r64_r64(X64FReg r64, X64FReg s64) { - X86Reg r32 = X86Reg(r64 & 7), s32 = X86Reg(s64 & 7); - m_code.push_back(m_al, rex(1, r64 >> 3, 0, s64 >> 3)); - m_code.push_back(m_al, 0x66); - m_code.push_back(m_al, 0x0f); - m_code.push_back(m_al, 0x2e); - modrm_sib_disp(m_code, m_al, r32, &s32, nullptr, 1, 0, false); - EMIT("ucomisd " + r2s(r64) + ", " + r2s(s64)); - } - - // COMISD—Compare Scalar Ordered Double Precision Floating-Point Values and Set EFLAGS - void asm_comisd_r64_r64(X64FReg r64, X64FReg s64) { - X86Reg r32 = X86Reg(r64 & 7), s32 = X86Reg(s64 & 7); - m_code.push_back(m_al, rex(1, r64 >> 3, 0, s64 >> 3)); - m_code.push_back(m_al, 0x66); - m_code.push_back(m_al, 0x0f); - m_code.push_back(m_al, 0x2f); - modrm_sib_disp(m_code, m_al, r32, &s32, nullptr, 1, 0, false); - EMIT("comisd " + r2s(r64) + ", " + r2s(s64)); - } - - // SQRTSD—Compute Square Root of Scalar Double Precision Floating-Point Value - void asm_sqrtsd_r64_r64(X64FReg r64, X64FReg s64) { - X86Reg r32 = X86Reg(r64 & 7), s32 = X86Reg(s64 & 7); - m_code.push_back(m_al, rex(1, r64 >> 3, 0, s64 >> 3)); - m_code.push_back(m_al, 0xf2); - m_code.push_back(m_al, 0x0f); - m_code.push_back(m_al, 0x51); - modrm_sib_disp(m_code, m_al, r32, &s32, nullptr, 1, 0, false); - EMIT("sqrtsd " + r2s(r64) + ", " + r2s(s64)); - } -}; - - -// Generate an ELF 32 bit header and footer -// With these two functions, one only must generate a `_start` assembly -// function to have a working binary on Linux. -void emit_elf32_header(X86Assembler &a, uint32_t p_flags=5); -void emit_elf32_footer(X86Assembler &a); - -void emit_exit(X86Assembler &a, const std::string &name, - uint32_t exit_code); - -// this is similar to emit_exit() but takes the argument (i.e. exit code) -// from top of stack. To call this exit2, one must jump to it -// instead of call it. (Because calling pushes the instruction address and -// base pointer value (ebp) of previous function and thus makes the -// exit code parameter less reachable) -void emit_exit2(X86Assembler &a, const std::string &name); - -void emit_data_string(X86Assembler &a, const std::string &label, - const std::string &s); -void emit_i32_const(X86Assembler &a, const std::string &label, - const int32_t z); -void emit_i64_const(X86Assembler &a, const std::string &label, - const int64_t z); -void emit_float_const(X86Assembler &a, const std::string &label, - const float z); -void emit_double_const(X86Assembler &a, const std::string &label, - const double z); -void emit_print(X86Assembler &a, const std::string &msg_label, - uint32_t size); -void emit_print_int(X86Assembler &a, const std::string &name); -void emit_print_float(X86Assembler &a, const std::string &name); - -// Generate an ELF 64 bit header and footer -// With these two functions, one only must generate a `_start` assembly -// function to have a working binary on Linux. -void emit_elf64_header(X86Assembler &a); -void emit_elf64_footer(X86Assembler &a); - -void emit_exit_64(X86Assembler &a, std::string label, int exit_code); - -void emit_print_64(X86Assembler &a, const std::string &msg_label, uint64_t size); -void emit_print_int_64(X86Assembler &a, const std::string &name); -void emit_print_double(X86Assembler &a, const std::string &name); - -} // namespace LFortran - -#endif // LFORTRAN_CODEGEN_X86_ASSEMBER_H diff --git a/src/libasr/colors.h b/src/libasr/colors.h deleted file mode 100644 index b5bf260086..0000000000 --- a/src/libasr/colors.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef LFORTRAN_COLORS_H -#define LFORTRAN_COLORS_H - -namespace LCompilers { - -enum class style { - reset = 0, - bold = 1, - dim = 2, - italic = 3, - underline = 4, - blink = 5, - rblink = 6, - reversed = 7, - conceal = 8, - crossed = 9 -}; - -enum class fg { - black = 30, - red = 31, - green = 32, - yellow = 33, - blue = 34, - magenta = 35, - cyan = 36, - gray = 37, - reset = 39 -}; - -enum class bg { - black = 40, - red = 41, - green = 42, - yellow = 43, - blue = 44, - magenta = 45, - cyan = 46, - gray = 47, - reset = 49 -}; - -enum class fgB { - black = 90, - red = 91, - green = 92, - yellow = 93, - blue = 94, - magenta = 95, - cyan = 96, - gray = 97 -}; - -enum class bgB { - black = 100, - red = 101, - green = 102, - yellow = 103, - blue = 104, - magenta = 105, - cyan = 106, - gray = 107 -}; - - -template -std::string color(T const value) -{ - return "\033[" + std::to_string(static_cast(value)) + "m"; -} - - -} // namespace LCompilers - -#endif // LFORTRAN_COLORS_H diff --git a/src/libasr/compiler_tester/tester.py b/src/libasr/compiler_tester/tester.py deleted file mode 100644 index c94ecb2539..0000000000 --- a/src/libasr/compiler_tester/tester.py +++ /dev/null @@ -1,454 +0,0 @@ -import argparse -from concurrent.futures import ThreadPoolExecutor -from functools import partial -import hashlib -import itertools -import json -import logging -import os -import re -import pathlib -import pprint -import shutil -import subprocess -import sys -import toml -from typing import Any, Mapping, List, Union - -level = logging.DEBUG -log = logging.getLogger(__name__) -handler = logging.StreamHandler(sys.stdout) -handler.setFormatter(logging.Formatter('%(message)s')) -handler.setLevel(level) -log.addHandler(handler) -log.setLevel(level) - - -TESTER_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__))) -LIBASR_DIR = os.path.dirname(TESTER_DIR) -SRC_DIR = os.path.dirname(LIBASR_DIR) -ROOT_DIR = os.path.dirname(SRC_DIR) - -no_color = False - -class RunException(Exception): - pass - - -class ExecuteException(Exception): - pass - - -class style: - reset = 0 - bold = 1 - dim = 2 - italic = 3 - underline = 4 - blink = 5 - rblink = 6 - reversed = 7 - conceal = 8 - crossed = 9 - - -class fg: - black = 30 - red = 31 - green = 32 - yellow = 33 - blue = 34 - magenta = 35 - cyan = 36 - gray = 37 - reset = 39 - - -def color(value): - return "\033[" + str(int(value)) + "m" - - -def check(): - return f"{(color(fg.green)+color(style.bold))}✓ {color(fg.reset)+color(style.reset)}" - - -def bname(base, cmd, filename): - hstring = cmd - if filename: - hstring += filename - h = hashlib.sha224(hstring.encode()).hexdigest()[:7] - if filename: - bname = os.path.basename(filename) - bname, _ = os.path.splitext(bname) - return f"{base}-{bname}-{h}" - else: - return f"{base}-{h}" - - -def _compare_eq_dict( - left: Mapping[Any, Any], right: Mapping[Any, Any], verbose: int = 0 -) -> List[str]: - explanation: List[str] = [] - set_left = set(left) - set_right = set(right) - common = set_left.intersection(set_right) - same = {k: left[k] for k in common if left[k] == right[k]} - if same and verbose < 2: - explanation += ["Omitting %s identical items" % len(same)] - elif same: - explanation += ["Common items:"] - explanation += pprint.pformat(same).splitlines() - diff = {k for k in common if left[k] != right[k]} - if diff: - explanation += ["Differing items:"] - for k in diff: - explanation += [repr({k: left[k]}) + " != " + repr({k: right[k]})] - extra_left = set_left - set_right - len_extra_left = len(extra_left) - if len_extra_left: - explanation.append( - "Left contains %d more item%s:" - % (len_extra_left, "" if len_extra_left == 1 else "s") - ) - explanation.extend( - pprint.pformat({k: left[k] for k in extra_left}).splitlines() - ) - extra_right = set_right - set_left - len_extra_right = len(extra_right) - if len_extra_right: - explanation.append( - "Right contains %d more item%s:" - % (len_extra_right, "" if len_extra_right == 1 else "s") - ) - explanation.extend( - pprint.pformat({k: right[k] for k in extra_right}).splitlines() - ) - return explanation - - -def fixdir(s: bytes) -> bytes: - local_dir = os.getcwd() - return s.replace(local_dir.encode(), "$DIR".encode()) - - -def unl_loop_del(b): - return b.replace(bytes('\r\n', encoding='utf-8'), - bytes('\n', encoding='utf-8')) - - -def run(basename: str, cmd: Union[pathlib.Path, str], - out_dir: Union[pathlib.Path, str], infile=None, extra_args=None): - """ - Runs the `cmd` and collects stdout, stderr, exit code. - - The stdout, stderr and outfile are saved in the `out_dir` directory and - all metadata is saved in a json file, whose path is returned from the - function. - - The idea is to use this function to test the compiler by running it with - an option to save the AST, ASR or LLVM IR or binary, and then ensure that - the output does not change. - - Arguments: - - basename ... name of the run - cmd ........ command to run, can use {infile} and {outfile} - out_dir .... output directory to store output - infile ..... optional input file. If present, it will check that it exists - and hash it. - extra_args . extra arguments, not part of the hash - - Examples: - - >>> run("cat2", "cat tests/cat.txt > {outfile}", "output", "tests/cat.txt") - >>> run("ls4", "ls --wrong-option", "output") - - """ - assert basename is not None and basename != "" - pathlib.Path(out_dir).mkdir(parents=True, exist_ok=True) - if infile and not os.path.exists(infile): - raise RunException("The input file %s does not exist" % (infile)) - outfile = os.path.join(out_dir, basename + "." + "out") - - infile = infile.replace("\\\\", "\\").replace("\\", "/") - - cmd2 = cmd.format(infile=infile, outfile=outfile) - if extra_args: - cmd2 += " " + extra_args - r = subprocess.run(cmd2, shell=True, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - if not os.path.exists(outfile): - outfile = None - if len(r.stdout): - stdout_file = os.path.join(out_dir, basename + "." + "stdout") - open(stdout_file, "wb").write(fixdir(r.stdout)) - else: - stdout_file = None - if len(r.stderr): - stderr_file = os.path.join(out_dir, basename + "." + "stderr") - open(stderr_file, "wb").write(fixdir(r.stderr)) - else: - stderr_file = None - - if infile: - temp = unl_loop_del(open(infile, "rb").read()) - infile_hash = hashlib.sha224(temp).hexdigest() - else: - infile_hash = None - if outfile: - temp = unl_loop_del(open(outfile, "rb").read()) - outfile_hash = hashlib.sha224(temp).hexdigest() - outfile = os.path.basename(outfile) - else: - outfile_hash = None - if stdout_file: - temp = unl_loop_del(open(stdout_file, "rb").read()) - stdout_hash = hashlib.sha224(temp).hexdigest() - stdout_file = os.path.basename(stdout_file) - else: - stdout_hash = None - if stderr_file: - temp = unl_loop_del(open(stderr_file, "rb").read()) - stderr_hash = hashlib.sha224(temp).hexdigest() - stderr_file = os.path.basename(stderr_file) - else: - stderr_hash = None - data = { - "basename": basename, - "cmd": cmd, - "infile": infile, - "infile_hash": infile_hash, - "outfile": outfile, - "outfile_hash": outfile_hash, - "stdout": stdout_file, - "stdout_hash": stdout_hash, - "stderr": stderr_file, - "stderr_hash": stderr_hash, - "returncode": r.returncode, - } - json_file = os.path.join(out_dir, basename + "." + "json") - json.dump(data, open(json_file, "w"), indent=4) - return json_file - - -def get_error_diff(reference_file, output_file, full_err_str) -> str: - diff_list = subprocess.Popen( - f"diff {reference_file} {output_file}", - stdout=subprocess.PIPE, - shell=True, - encoding='utf-8') - diff_str = "" - diffs = diff_list.stdout.readlines() - for d in diffs: - diff_str += d - full_err_str += f"\nDiff against: {reference_file}\n" - full_err_str += diff_str - return full_err_str - - -def do_update_reference(jo, jr, do): - shutil.copyfile(jo, jr) - for f in ["outfile", "stdout", "stderr"]: - if do[f]: - f_o = os.path.join(os.path.dirname(jo), do[f]) - f_r = os.path.join(os.path.dirname(jr), do[f]) - shutil.copyfile(f_o, f_r) - - -def run_test(testname, basename, cmd, infile, update_reference=False, - extra_args=None): - """ - Runs the test `cmd` and compare against reference results. - - The `cmd` is executed via `run` (passing in `basename` and `infile`) and - the output is saved in the `output` directory. The generated json file is - then compared against reference results and if it differs, the - RunException is thrown. - - Arguments: - - basename ........... name of the run - cmd ................ command to run, can use {infile} and {outfile} - infile ............. optional input file. If present, it will check that - it exists and hash it. - update_reference ... if True, it will copy the output into the reference - directory as reference results, overwriting old ones - extra_args ......... Extra arguments to append to the command that are not - part of the hash - - Examples: - - >>> run_test("cat12", "cat {infile} > {outfile}", "cat.txt", - ... update_reference=True) - >>> run_test("cat12", "cat {infile} > {outfile}", "cat.txt") - """ - s = f"{testname} * {basename}" - basename = bname(basename, cmd, infile) - infile = os.path.join("tests", infile) - jo = run(basename, cmd, os.path.join("tests", "output"), infile=infile, - extra_args=extra_args) - jr = os.path.join("tests", "reference", os.path.basename(jo)) - if not os.path.exists(jo): - raise FileNotFoundError( - f"The output json file '{jo}' for {testname} does not exist") - - do = json.load(open(jo)) - if update_reference: - do_update_reference(jo, jr, do) - return - - if not os.path.exists(jr): - raise FileNotFoundError( - f"The reference json file '{jr}' for {testname} does not exist") - - dr = json.load(open(jr)) - if do != dr: - # This string builds up the error message. Print test name in red in the beginning. - # More information is added afterwards. - full_err_str = f"\n{(color(fg.red)+color(style.bold))}{s}{color(fg.reset)+color(style.reset)}\n" - e = _compare_eq_dict(do, dr) - full_err_str += "The JSON metadata differs against reference results\n" - full_err_str += "Reference JSON: " + jr + "\n" - full_err_str += "Output JSON: " + jo + "\n" - full_err_str += "\n".join(e) - - for field in ["outfile", "stdout", "stderr"]: - hash_field = field + "_hash" - if not do[hash_field] and dr[hash_field]: - full_err_str += f"No output {hash_field} available for {testname}\n" - break - if not dr[hash_field] and do[hash_field]: - full_err_str += f"No reference {hash_field} available for {testname}\n" - break - if do[hash_field] != dr[hash_field]: - output_file = os.path.join("tests", "output", do[field]) - reference_file = os.path.join("tests", "reference", dr[field]) - full_err_str = get_error_diff( - reference_file, output_file, full_err_str) - break - raise RunException( - "Testing with reference output failed." + - full_err_str) - if no_color: - log.debug(s + " PASS") - else: - log.debug(s + " " + check()) - - -def tester_main(compiler, single_test): - parser = argparse.ArgumentParser(description=f"{compiler} Test Suite") - parser.add_argument("-u", "--update", action="store_true", - help="update all reference results") - parser.add_argument("-l", "--list", action="store_true", - help="list all tests") - parser.add_argument("-t", "--test", - action="append", nargs="*", - help="Run specific tests") - parser.add_argument("-b", "--backend", - action="append", nargs="*", - help="Run specific backends") - parser.add_argument("-v", "--verbose", action="store_true", - help="increase test verbosity") - parser.add_argument("--exclude-test", metavar="TEST", - action="append", nargs="*", - help="Exclude specific tests"), - parser.add_argument("--exclude-backend", metavar="BACKEND", - action="append", nargs="*", - help="Exclude specific backends, only works when -b is not specified"), - parser.add_argument("--no-llvm", action="store_true", - help="Skip LLVM tests") - parser.add_argument("--skip-run-with-dbg", action="store_true", - help="Skip runtime tests with debugging information enabled") - parser.add_argument("-s", "--sequential", action="store_true", - help="Run all tests sequentially") - parser.add_argument("--no-color", action="store_true", - help="Turn off colored tests output") - args = parser.parse_args() - update_reference = args.update - list_tests = args.list - specific_tests = list( - itertools.chain.from_iterable( - args.test)) if args.test else None - specific_backends = set( - itertools.chain.from_iterable( - args.backend)) if args.backend else None - excluded_tests = list(itertools.chain.from_iterable( - args.exclude_test)) if args.exclude_test else None - excluded_backends = set(itertools.chain.from_iterable( - args.exclude_backend)) if args.exclude_backend and specific_backends is None else None - verbose = args.verbose - no_llvm = args.no_llvm - skip_run_with_dbg = args.skip_run_with_dbg - global no_color - no_color = args.no_color - - # So that the tests find the `lcompiler` executable - os.environ["PATH"] = os.path.join(SRC_DIR, "bin") \ - + os.pathsep + os.environ["PATH"] - test_data = toml.load(open(os.path.join(ROOT_DIR, "tests", "tests.toml"))) - filtered_tests = test_data["test"] - if specific_tests: - filtered_tests = [test for test in filtered_tests if any( - re.search(t, test["filename"]) for t in specific_tests)] - if excluded_tests: - filtered_tests = [test for test in filtered_tests if not any( - re.search(t, test["filename"]) for t in excluded_tests)] - if specific_backends: - filtered_tests = [ - test for test in filtered_tests if any( - b in test for b in specific_backends)] - if excluded_backends: - filtered_tests = [test for test in filtered_tests if any( - b not in excluded_backends and b != "filename" for b in test)] - - for test in filtered_tests: - if 'extrafiles' in test: - single_test(test, - update_reference=update_reference, - specific_backends=specific_backends, - excluded_backends=excluded_backends, - verbose=verbose, - no_llvm=no_llvm, - skip_run_with_dbg=True, - no_color=True) - filtered_tests = [test for test in filtered_tests if 'extrafiles' not in test] - - if args.sequential: - for test in filtered_tests: - single_test(test, - update_reference=update_reference, - specific_backends=specific_backends, - excluded_backends=excluded_backends, - verbose=verbose, - no_llvm=no_llvm, - skip_run_with_dbg=skip_run_with_dbg, - no_color=no_color) - # run in parallel - else: - single_tester_partial_args = partial( - single_test, - update_reference=update_reference, - specific_backends=specific_backends, - excluded_backends=excluded_backends, - verbose=verbose, - no_llvm=no_llvm, - skip_run_with_dbg=skip_run_with_dbg, - no_color=no_color) - with ThreadPoolExecutor() as ex: - futures = ex.map(single_tester_partial_args, filtered_tests) - for f in futures: - if not f: - ex.shutdown(wait=False) - if list_tests: - return - - if update_reference: - log.info("Test references updated.") - else: - if no_color: - log.info("TESTS PASSED") - else: - log.info( - f"{(color(fg.green) + color(style.bold))}TESTS PASSED" - f"{color(fg.reset) + color(style.reset)}") diff --git a/src/libasr/config.h.in b/src/libasr/config.h.in deleted file mode 100644 index 292b593bb4..0000000000 --- a/src/libasr/config.h.in +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef LFORTRAN_CONFIG_H -#define LFORTRAN_CONFIG_H - -/* Define if you want to enable ASSERT testing in LFortran */ -#cmakedefine WITH_LFORTRAN_ASSERT - -/* LFortran version */ -#cmakedefine LFORTRAN_VERSION "@LFORTRAN_VERSION@" - -/* Define if LLVM is enabled */ -#cmakedefine HAVE_LFORTRAN_LLVM - -/* Define if RAPIDJSON is found */ -#cmakedefine HAVE_LFORTRAN_RAPIDJSON - -/* Define if stacktrace is enabled */ -#cmakedefine HAVE_LFORTRAN_STACKTRACE -#cmakedefine HAVE_RUNTIME_STACKTRACE -#cmakedefine HAVE_LFORTRAN_BFD -#cmakedefine HAVE_LFORTRAN_DWARFDUMP -#cmakedefine HAVE_LFORTRAN_LINK -#cmakedefine HAVE_LFORTRAN_MACHO -#cmakedefine HAVE_LFORTRAN_UNWIND - -/* Define if cxxabi.h is present */ -#cmakedefine HAVE_LFORTRAN_DEMANGLE - -/* Define if XEUS is enabled */ -#cmakedefine HAVE_LFORTRAN_XEUS - -/* Define if we should use binary modfiles */ -#cmakedefine WITH_LFORTRAN_BINARY_MODFILES - -#endif // LFORTRAN_CONFIG_H diff --git a/src/libasr/containers.h b/src/libasr/containers.h deleted file mode 100644 index 40b5292990..0000000000 --- a/src/libasr/containers.h +++ /dev/null @@ -1,204 +0,0 @@ -#ifndef LFORTRAN_CONTAINERS_H -#define LFORTRAN_CONTAINERS_H - -#include -#include - -namespace LCompilers { - -// Vector implementation - -template -struct Vec; - -template -class VecIterator -{ -public: - VecIterator(const Vec& c, size_t idx=0) - : m_container(c), m_index(idx) {} - - bool operator!=(const VecIterator& other) { - return (m_index != other.m_index); - } - - const VecIterator& operator++() { - m_index++; - return *this; - } - - const T& operator*() const { - return m_container[m_index]; - } -private: - const Vec& m_container; - size_t m_index; -}; - -#ifdef WITH_LFORTRAN_ASSERT -static int vec_called_const = 0xdeadbeef; -#endif - -template -struct Vec { - size_t n, max; - T* p; -#ifdef WITH_LFORTRAN_ASSERT - int reserve_called; -#endif - - // reserve() must be called before calling push_back() - void reserve(Allocator &al, size_t max) { - n = 0; - if (max == 0) max++; - LCOMPILERS_ASSERT(max > 0) - this->max = max; - p = al.allocate(max); -#ifdef WITH_LFORTRAN_ASSERT - reserve_called = vec_called_const; -#endif - } - - void push_back(Allocator &al, T x) { - // This can pass by accident even if reserve() is not called (if - // reserve_called happens to be equal to vec_called_const when Vec is - // allocated in memory), but the chance is small. It catches such bugs - // in practice. - LCOMPILERS_ASSERT(reserve_called == vec_called_const); - if (n == max) { - size_t max2 = 2*max; - T* p2 = al.allocate(max2); - std::memcpy(p2, p, sizeof(T) * max); - p = p2; - max = max2; - } - p[n] = x; - n++; - } - - size_t size() const { - return n; - } - - void resize(Allocator &al, size_t max){ - reserve(al, max); - n = max; - } - - size_t capacity() const { - return max; - } - - // return a direct access to the underlying array - T* data() const { - return p; - } - - T& back() const { - return p[n - 1]; - } - - const T& operator[](size_t pos) const { - return p[pos]; - } - - // Returns a copy of the data as std::vector - std::vector as_vector() const { - return std::vector(p, p+n); - } - - void from_pointer_n(T* p, size_t n) { - this->p = p; - this->n = n; - this->max = n; -#ifdef WITH_LFORTRAN_ASSERT - reserve_called = vec_called_const; -#endif - } - - void from_pointer_n_copy(Allocator &al, T* p, size_t n) { - this->reserve(al, n); - for (size_t i=0; ipush_back(al, p[i]); - } - } - - VecIterator begin() const { - return VecIterator(*this, 0); - } - - VecIterator end() const { - return VecIterator(*this, n); - } -}; - -static_assert(std::is_standard_layout>::value); -static_assert(std::is_trivial>::value); - -// String implementation (not null-terminated) -struct Str { - size_t n; - char* p; - - // Returns a copy of the string as a NULL terminated std::string - std::string str() const { return std::string(p, n); } - - // Initializes Str from std::string by making a copy excluding the null char - void from_str(Allocator &al, const std::string &s) { - n = s.size(); - p = al.allocate(n); - std::memcpy(p, &s[0], sizeof(char) * n); - } - - // Initializes Str from std::string by setting the pointer to point - // to the std::string (no copy), and the length excluding the null char. - // The original std::string cannot go out of scope if you are still using - // Str. This function is helpful if you want to allocate a null terminated - // C string using Allocator as follows: - // - // std::string s - // ... - // Str a; - // a.from_str_view(s); - // char *s2 = a.c_str(al); - void from_str_view(const std::string &s) { - n = s.size(); - p = const_cast(&s[0]); - } - - // Returns a copy of the string as a NULL terminated C string, - // allocated using Allocator - char* c_str(Allocator &al) const { - char *s = al.allocate(n+1); - std::memcpy(s, p, sizeof(char) * n); - s[n] = '\0'; - return s; - } - - size_t size() const { - return n; - } -}; - -static_assert(std::is_standard_layout::value); -static_assert(std::is_trivial::value); - -template -std::string string_format(const std::string& format, Args && ...args) -{ - auto size = std::snprintf(nullptr, 0, format.c_str(), std::forward(args)...); - std::string output(size, '\0'); - std::snprintf(&output[0], size + 1, format.c_str(), std::forward(args)...); - return output; -} - -static inline std::string double_to_scientific(double x) { - return string_format("%25.17e", x); -} - -} // namespace LCompilers - - - - -#endif diff --git a/src/libasr/diagnostics.cpp b/src/libasr/diagnostics.cpp deleted file mode 100644 index e6d8618ad0..0000000000 --- a/src/libasr/diagnostics.cpp +++ /dev/null @@ -1,401 +0,0 @@ -#include -#include - -#include -#include -#include -#include - -namespace LCompilers::diag { - -const static std::string redon = ColorsANSI::RED; -const static std::string redoff = ColorsANSI::RESET; - -std::string highlight_line(const std::string &line, - const size_t first_column, - const size_t last_column, - bool use_colors) -{ - if (first_column == 0 || last_column == 0) return ""; - if (last_column > line.size()+1) { - throw LCompilersException("The `last_column` in highlight_line is longer than the source line"); - } - LCOMPILERS_ASSERT(first_column >= 1) - LCOMPILERS_ASSERT(first_column <= last_column) - LCOMPILERS_ASSERT(last_column <= line.size()+1) - std::stringstream out; - if (line.size() > 0) { - out << line.substr(0, first_column-1); - if(use_colors) out << redon; - if (last_column <= line.size()) { - out << line.substr(first_column-1, - last_column-first_column+1); - } else { - // `last_column` points to the \n character - out << line.substr(first_column-1, - last_column-first_column+1-1); - } - if(use_colors) out << redoff; - if (last_column < line.size()) out << line.substr(last_column); - } - out << std::endl; - if (first_column > 0) { - for (size_t i=0; i < first_column-1; i++) { - out << " "; - } - } - if(use_colors) out << redon << "^"; - else out << "^"; - for (size_t i=first_column; i < last_column; i++) { - out << "~"; - } - if(use_colors) out << redoff; - out << std::endl; - return out.str(); -} - -bool Diagnostics::has_error() const { - for (auto &d : this->diagnostics) { - if (d.level == Level::Error) return true; - } - return false; -} - -std::string Diagnostics::render(LocationManager &lm, - const CompilerOptions &compiler_options) { - std::string out; - for (auto &d : this->diagnostics) { - if (compiler_options.no_warnings && d.level != Level::Error) { - continue; - } - if (compiler_options.error_format == "human") { - out += render_diagnostic_human(d, lm, compiler_options.use_colors, - compiler_options.show_stacktrace); - if (&d != &this->diagnostics.back()) out += "\n"; - } else if (compiler_options.error_format == "short") { - out += render_diagnostic_short(d, lm); - } else { - throw LCompilersException("Error format not supported."); - } - } - if (compiler_options.error_format == "human") { - if (this->diagnostics.size() > 0 && !compiler_options.no_error_banner) { - if (!compiler_options.no_warnings || has_error()) { - std::string bold = ColorsANSI::BOLD; - std::string reset = ColorsANSI::RESET; - if (!compiler_options.use_colors) { - bold = ""; - reset = ""; - } - out += "\n\n"; - out += bold + "Note" + reset - + ": if any of the above error or warning messages are not clear or are lacking\n"; - out += "context please report it to us (we consider that a bug that must be fixed).\n"; - } - } - } - return out; -} - -std::string render_diagnostic_short_nospan(const Diagnostic &d); - -std::string Diagnostics::render2() { - std::string out; - for (auto &d : this->diagnostics) { - out += render_diagnostic_short_nospan(d); - if (&d != &this->diagnostics.back()) out += "\n"; - } - return out; -} - -std::string get_line(std::string str, int n) -{ - std::string line; - std::stringstream s(str); - for (int i=0; i < n; i++) { - std::getline(s, line); - } - return line; -} - -void populate_span(diag::Span &s, const LocationManager &lm) { - lm.pos_to_linecol(lm.output_to_input_pos(s.loc.first, false), - s.first_line, s.first_column, s.filename); - lm.pos_to_linecol(lm.output_to_input_pos(s.loc.last, true), - s.last_line, s.last_column, s.filename); - std::string input; - read_file(s.filename, input); - for (uint32_t i = s.first_line; i <= s.last_line; i++) { - s.source_code.push_back(get_line(input, i)); - } - LCOMPILERS_ASSERT(s.source_code.size() > 0) -} - -// Loop over all labels and their spans, populate all of them -void populate_spans(diag::Diagnostic &d, const LocationManager &lm) { - for (auto &l : d.labels) { - for (auto &s : l.spans) { - populate_span(s, lm); - } - } -} - -// Fills Diagnostic with span details and renders it -std::string render_diagnostic_human(Diagnostic &d, const LocationManager &lm, - bool use_colors, bool show_stacktrace) { - std::string out; - if (show_stacktrace) { - out += error_stacktrace(d.stacktrace); - } - // Convert to line numbers and get source code strings - populate_spans(d, lm); - // Render the message - out += render_diagnostic_human(d, use_colors); - return out; -} - -// Fills Diagnostic with span details and renders it -std::string render_diagnostic_short(Diagnostic &d, const LocationManager &lm) { - std::string out; - // Convert to line numbers and get source code strings - populate_spans(d, lm); - // Render the message - out += render_diagnostic_short(d); - return out; -} - -std::string render_diagnostic_human(const Diagnostic &d, bool use_colors) { - std::string bold = ColorsANSI::BOLD; - std::string red_bold = ColorsANSI::BOLDCYAN; - std::string yellow_bold = ColorsANSI::BOLDYELLOW; - std::string green_bold = ColorsANSI::BOLDGREEN; - std::string blue_bold = ColorsANSI::BOLDBLUE; - std::string reset = ColorsANSI::RESET; - if (!use_colors) { - bold = ""; - red_bold = ""; - yellow_bold = ""; - green_bold = ""; - blue_bold = ""; - reset = ""; - } - std::stringstream out; - - auto [message_type, primary_color, type_color] = diag_level_to_str(d, use_colors); - out << type_color << message_type << reset << bold << ": " << d.message << reset << std::endl; - - if (d.labels.size() > 0) { - Label l = d.labels[0]; - Span s = l.spans[0]; - int line_num_width = 1; - if (s.last_line >= 10000) { - line_num_width = 5; - } else if (s.last_line >= 1000) { - line_num_width = 4; - } else if (s.last_line >= 100) { - line_num_width = 3; - } else if (s.last_line >= 10) { - line_num_width = 2; - } - // TODO: print the primary line+column here, not the first label: - out << std::string(line_num_width, ' ') << blue_bold << "-->" << reset << " " << s.filename << ":" << s.first_line << ":" << s.first_column; - if (s.first_line != s.last_line) { - out << " - " << s.last_line << ":" << s.last_column; - } - out << std::endl; - for (auto &l : d.labels) { - if (l.spans.size() == 0) { - throw LCompilersException("ICE: Label does not have a span"); - } - std::string color; - char symbol; - if (l.primary) { - color = primary_color; - symbol = '^'; - } else { - color = blue_bold; - symbol = '~'; - } - Span s0 = l.spans[0]; - for (size_t i=0; i < l.spans.size(); i++) { - Span s2=l.spans[i]; - // If the span is on the same line as the last span and to - // the right, we add it to the same line. Otherwise we start - // a new line. - if (i >= 1) { - if (s0.first_line == s0.last_line) { - // Previous span was single line - if (s2.first_line == s2.last_line && s2.first_line == s0.first_line) { - // Current span is single line and on the same line - if (s2.first_column > s0.last_column+1) { - // And it comes after the previous span - // Append the span and continue - out << std::string(s2.first_column-s0.last_column-1, ' '); - out << std::string(s2.last_column-s2.first_column+1, symbol); - s0 = s2; - continue; - } - } - // Otherwise finish the line - out << " " << l.message << reset << std::endl; - } - } - // and start a new one: - s0 = s2; - if (s0.filename != s.filename) { - out << std::endl; - // TODO: print the primary line+column here, not the first label: - out << std::string(line_num_width, ' ') << blue_bold; - out << "-->" << reset << " " << s0.filename << ":"; - out << s0.first_line << ":" << s0.first_column; - if (s0.first_line != s0.last_line) { - out << " - " << s0.last_line << ":" << s0.last_column; - } - out << std::endl; - } - - if (s0.first_line == s0.last_line) { - out << std::string(line_num_width+1, ' ') << blue_bold << "|" - << reset << std::endl; - std::string line = s0.source_code[0]; - std::replace(std::begin(line), std::end(line), '\t', ' '); - line.erase(std::remove(line.begin(), line.end(), '\r'), line.end()); - out << blue_bold << std::setw(line_num_width) - << std::to_string(s0.first_line) << " |" << reset << " " - << line << std::endl; - out << std::string(line_num_width+1, ' ') << blue_bold << "|" - << reset << " "; - out << std::string(s0.first_column-1, ' '); - out << color << std::string(s0.last_column-s0.first_column+1, symbol); - } else { - if (s0.first_line < s0.last_line) { - out << std::string(line_num_width+1, ' ') << blue_bold << "|" - << reset << std::endl; - std::string line = s0.source_code[0]; - std::replace(std::begin(line), std::end(line), '\t', ' '); - line.erase(std::remove(line.begin(), line.end(), '\r'), line.end()); - out << blue_bold << std::setw(line_num_width) - << std::to_string(s0.first_line) << " |" << reset << " " - << " " + line << std::endl; - out << std::string(line_num_width+1, ' ') << blue_bold << "|" - << reset << " "; - out << " " + std::string(s0.first_column-1, ' '); - int64_t repeat = (int64_t)line.size()-(int64_t)s0.first_column+1; - if (repeat > 0) { - out << color << std::string(repeat, symbol); - } - out << "..." << reset << std::endl; - - out << "..." << std::endl; - - out << std::string(line_num_width+1, ' ') << blue_bold << "|" - << reset << std::endl; - line = s0.source_code[s0.source_code.size()-1]; - std::replace(std::begin(line), std::end(line), '\t', ' '); - line.erase(std::remove(line.begin(), line.end(), '\r'), line.end()); - out << blue_bold << std::setw(line_num_width) - << std::to_string(s0.last_line) << " |" << reset << " " - << " " + line << std::endl; - out << std::string(line_num_width+1, ' ') << blue_bold << "|" - << reset << " "; - out << color << "..." + std::string(s0.last_column-1+1, symbol); - out << " " << l.message << reset << std::endl; - } else { - throw LCompilersException("location last_line < first_line"); - } - } - } - if (s0.first_line == s0.last_line) { - out << " " << l.message << reset << std::endl; - } - } // Labels - } - return out.str(); -} - -std::string render_diagnostic_short(const Diagnostic &d) { - std::stringstream out; - - // Message anatomy: - // :-:-: : - if (d.labels.size() > 0) { - Label l = d.labels[0]; - Span s = l.spans[0]; - // TODO: print the primary line+column here, not the first label: - out << s.filename << ":" << s.first_line << "-" << s.last_line << ":"; - out << s.first_column << "-" << s.last_column << ": "; - } - auto [message_type, primary, type] = diag_level_to_str(d, false); - out << message_type << ": " << d.message << std::endl; - - return out.str(); -} - -std::string render_diagnostic_short_nospan(const Diagnostic &d) { - std::stringstream out; - auto [message_type, primary, type] = diag_level_to_str(d, false); - out << message_type << ": " << d.message << std::endl; - return out.str(); -} - -std::tuple diag_level_to_str( - const Diagnostic &d, const bool use_color) { - std::string message_type = ""; - std::string primary_color = ""; - std::string type_color = ""; - switch (d.level) { - case (Level::Error): - primary_color = use_color ? ColorsANSI::BOLDRED : ""; - type_color = primary_color; - switch (d.stage) { - case (Stage::CPreprocessor): - message_type = "C preprocessor error"; - break; - case (Stage::Prescanner): - message_type = "prescanner error"; - break; - case (Stage::Tokenizer): - message_type = "tokenizer error"; - break; - case (Stage::Parser): - message_type = "syntax error"; - break; - case (Stage::Semantic): - message_type = "semantic error"; - break; - case (Stage::ASRPass): - message_type = "ASR pass error"; - break; - case (Stage::ASRVerify): - message_type = "ASR verify pass error"; - break; - case (Stage::CodeGen): - message_type = "code generation error"; - break; - } - break; - case (Level::Warning): - primary_color = use_color ? ColorsANSI::BOLDYELLOW : ""; - type_color = primary_color; - message_type = "warning"; - break; - case (Level::Note): - primary_color = use_color ? ColorsANSI::BOLD : ""; - type_color = primary_color; - message_type = "note"; - break; - case (Level::Help): - primary_color = use_color ? ColorsANSI::BOLD : ""; - type_color = primary_color; - message_type = "help"; - break; - case (Level::Style): - primary_color = use_color ? ColorsANSI::BOLDGREEN : ""; - type_color = use_color ? ColorsANSI::BOLDYELLOW : ""; - message_type = "style suggestion"; - break; - } - return std::make_tuple(message_type, primary_color, type_color); -} - -} // namespace LCompilers::diag diff --git a/src/libasr/diagnostics.h b/src/libasr/diagnostics.h deleted file mode 100644 index 63e1d832c3..0000000000 --- a/src/libasr/diagnostics.h +++ /dev/null @@ -1,259 +0,0 @@ -#ifndef LFORTRAN_DIAGNOSTICS_H -#define LFORTRAN_DIAGNOSTICS_H - -#include -#include -#include - -namespace LCompilers { - -struct LocationManager; -struct CompilerOptions; - -namespace diag { - -struct Span { - Location loc; // Linear location (span), must be filled out - - // Later the `loc` is used to populate these: - // Converted to line+columns - uint32_t first_line, first_column, last_line, last_column; - // Filename: - std::string filename; - // Lines of source code from first_line to last_line - std::vector source_code; - - Span(const Location &loc) : loc{loc} {} -}; - -/* - * Labels can be primary or secondary. - * - * An optional message can be attached to the label. - * - * * Primary: brief, but approachable description of *what* went wrong - * * Secondary: description of *why* the error happened - * - * Primary label uses ^^^, secondary uses ~~~ (or ---) - * - * There is one or more spans (Locations) attached to a label. - * - * Colors: - * - * * Error message: primary is red, secondary is blue - * * Warning message: primary is yellow - */ -struct Label { - bool primary; // primary or secondary label - std::string message; // message attached to the label - std::vector spans; // one or more spans - - Label(const std::string &message, const std::vector &locations, - bool primary=true) : primary{primary}, message{message} { - for (auto &loc : locations) { - spans.push_back(Span(loc)); - } - } -}; - -/* - * The diagnostic level is the type of the message. - * - * We can have errors, warnings, notes and help messages. - */ -enum Level { - Error, Warning, Note, Help, Style -}; - -/* - * Which stage of the compiler the error is coming from - */ -enum Stage { - CPreprocessor, Prescanner, Tokenizer, Parser, Semantic, ASRPass, - ASRVerify, CodeGen -}; - -/* - * A diagnostic message has a level and message and labels. - * - * Errors have zero or more primary and zero or more secondary labels. - * Help uses primary to show what should change. - * Notes may not have any labels attached. - * - * The message describes the overall error/warning/note. Labels are used - * to briefly but approachably describe what went wrong (primary label) and why - * it happened (secondary label). - * - * A progression of error messages: - * * a message with no label - * * a message with a primary label, no attached message - * * a message with a primary label and attached message - * * a message with a primary label and attached message and secondary labels - * * ... - * If there are labels attached, there must be at least one primary. - * - * The main diagnostic message is the parent. It can have children that can - * attach notes, help, etc. to the main error or warning message. - */ -struct Diagnostic { - Level level; - Stage stage; - std::string message; - std::vector