├── .clang-format ├── .clang-tidy ├── .github ├── actions │ └── setup_base │ │ └── action.yml └── workflows │ ├── build_llvm.yml │ ├── build_test_release_eudsl.yml │ └── bump_llvm.yml ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── README.md ├── build_tools ├── build_llvm.sh ├── build_llvm_wasi.sh └── cmake │ ├── llvm_cache.cmake │ └── llvm_wasm_cache.cmake ├── docs └── images │ └── eudslpurple.svg ├── projects ├── CMakeLists.txt ├── common │ └── eudsl │ │ ├── bind_vec_like.h │ │ ├── helpers.h │ │ ├── type_casters.h │ │ └── util.h ├── eudsl-llvmpy │ ├── CMakeLists.txt │ ├── eudsl-llvmpy-generate.py │ ├── pyproject.toml │ ├── src │ │ ├── eudslllvm_ext.cpp │ │ ├── llvm │ │ │ ├── .gitignore │ │ │ ├── __init__.py │ │ │ ├── context.py │ │ │ ├── function.py │ │ │ ├── instructions.py │ │ │ ├── types_.py │ │ │ └── util.py │ │ └── types.h │ └── tests │ │ └── test_bindings.py ├── eudsl-nbgen │ ├── CMakeLists.txt │ ├── cmake │ │ └── eudsl_nbgen-config.cmake │ ├── pyproject.toml │ └── src │ │ ├── __init__.py │ │ ├── __main__.py │ │ └── eudsl-nbgen.cpp ├── eudsl-py │ ├── CMakeLists.txt │ ├── pyproject.toml │ ├── src │ │ ├── eudsl │ │ │ ├── .gitignore │ │ │ ├── __init__.py │ │ │ ├── dialects │ │ │ │ ├── __init__.py │ │ │ │ └── arith │ │ │ │ │ └── __init__.py │ │ │ └── ir │ │ │ │ └── __init__.py │ │ ├── eudslpy_ext.cpp │ │ └── ir.cpp.inc │ └── tests │ │ └── test_bindings.py └── eudsl-tblgen │ ├── CMakeLists.txt │ ├── pyproject.toml │ ├── src │ ├── TGLexer.cpp │ ├── TGLexer.h │ ├── TGParser.cpp │ ├── TGParser.h │ ├── eudsl_tblgen │ │ ├── .gitignore │ │ ├── __init__.py │ │ ├── __main__.py │ │ ├── cmake │ │ │ └── eudsl_tblgen-config.cmake │ │ └── mlir │ │ │ ├── __init__.py │ │ │ └── __main__.py │ └── eudsl_tblgen_ext.cpp │ └── tests │ ├── td │ ├── AttrTypeBase.td │ ├── BuiltinTypeInterfaces.td │ ├── CommonAttrConstraints.td │ ├── CommonTypeConstraints.td │ ├── Constraints.td │ ├── DialectBase.td │ ├── InferTypeOpInterface.td │ ├── Interfaces.td │ ├── JSON.td │ ├── OpBase.td │ ├── Properties.td │ ├── TestDialect.td │ ├── Traits.td │ ├── TritonDialect.td │ ├── TritonGPUAttrDefs.td │ ├── TritonGPUDialect.td │ ├── TritonGPUTypes.td │ ├── TritonInterfaces.td │ ├── TritonTypes.td │ └── Utils.td │ ├── test_bindings.py │ └── test_c_api_emission.py └── requirements-dev.txt /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM 2 | AlwaysBreakTemplateDeclarations: Yes 3 | -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | Checks: '-*,clang-diagnostic-*,llvm-*,misc-*,-misc-const-correctness,-misc-unused-parameters,-misc-non-private-member-variables-in-classes,-misc-no-recursion,-misc-use-anonymous-namespace,readability-identifier-naming,-misc-include-cleaner' 2 | CheckOptions: 3 | - key: readability-identifier-naming.ClassCase 4 | value: CamelCase 5 | - key: readability-identifier-naming.EnumCase 6 | value: CamelCase 7 | - key: readability-identifier-naming.FunctionCase 8 | value: camelBack 9 | - key: readability-identifier-naming.MemberCase 10 | value: CamelCase 11 | - key: readability-identifier-naming.ParameterCase 12 | value: CamelCase 13 | - key: readability-identifier-naming.UnionCase 14 | value: CamelCase 15 | - key: readability-identifier-naming.VariableCase 16 | value: CamelCase 17 | - key: readability-identifier-naming.IgnoreMainLikeFunctions 18 | value: 1 19 | - key: readability-redundant-member-init.IgnoreBaseInCopyConstructors 20 | value: 1 21 | - key: modernize-use-default-member-init.UseAssignment 22 | value: 1 23 | # MLIR 24 | - key: readability-identifier-naming.MemberCase 25 | value: camelBack 26 | - key: readability-identifier-naming.ParameterCase 27 | value: camelBack 28 | - key: readability-identifier-naming.VariableCase 29 | value: camelBack 30 | -------------------------------------------------------------------------------- /.github/actions/setup_base/action.yml: -------------------------------------------------------------------------------- 1 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 | # See https://llvm.org/LICENSE.txt for license information. 3 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 | # Copyright (c) 2024. 5 | 6 | name: "Setup base" 7 | description: '' 8 | 9 | inputs: 10 | os: 11 | required: true 12 | description: '' 13 | arch: 14 | required: true 15 | description: '' 16 | cache-key: 17 | required: true 18 | description: '' 19 | restore-key: 20 | required: true 21 | description: '' 22 | python-version: 23 | required: false 24 | description: '' 25 | default: '3.12' 26 | 27 | outputs: 28 | cache-dir: 29 | description: '' 30 | value: ${{ steps.canonicalize-cache-dir.outputs.cache-dir }} 31 | 32 | runs: 33 | using: "composite" 34 | steps: 35 | - name: "Set unified TZ" 36 | uses: szenius/set-timezone@v2.0 37 | with: 38 | # this is an arbitrary choice 39 | timezoneLinux: "Asia/Singapore" 40 | timezoneMacos: "Asia/Singapore" 41 | timezoneWindows: "Singapore Standard Time" 42 | 43 | # notes for next time i bash my head against this: 44 | # 1. github.workspace and $GITHUB_WORKSPACE are different between container actions and non-container actions 45 | # 2. action/save-restore claims it expands ~ but that's a lie 46 | # 3. macos root (/) is read only 47 | # 4. you have to use windows style paths on windows even though we set shell: bash because 48 | # `with: path: ....` is not executed in our chosen shell (and so findind the dir will fail) 49 | # 5. action/save-restore will tell you there's no cache matching the key when the paths differ 50 | # (even if the cache key does exist) 51 | # 6. on almalinux8, ccache distribution is very old 52 | # 7. action/save-restore needs a subdir in the cached dir (that's why CCACHE_DIR=.container-cache/ccache) 53 | - name: "Canonicalize cache dir" 54 | id: canonicalize-cache-dir 55 | shell: bash 56 | run: | 57 | if [[ "${{ inputs.os }}" == "almalinux" ]] || [[ "${{ inputs.os }}" == "ubuntu" ]]; then 58 | echo "cache-dir=/tmp/.container-cache" >> $GITHUB_OUTPUT 59 | elif [[ "${{ inputs.os }}" == "macos" ]]; then 60 | echo "cache-dir=/tmp/.container-cache" >> $GITHUB_OUTPUT 61 | elif [[ "${{ inputs.os }}" == "windows" ]]; then 62 | echo "cache-dir=D:\a\.container-cache" >> $GITHUB_OUTPUT 63 | fi 64 | 65 | - name: "Restore cache" 66 | uses: actions/cache/restore@v3 67 | with: 68 | path: ${{ steps.canonicalize-cache-dir.outputs.cache-dir }} 69 | key: ${{ inputs.cache-key }} 70 | restore-keys: ${{ inputs.restore-key }} 71 | 72 | - name: "Install OS deps" 73 | shell: bash 74 | run: | 75 | 76 | if [[ "${{ inputs.os }}" == "almalinux" ]]; then 77 | dnf install -y epel-release 78 | dnf install -y sudo ncurses-compat-libs tmate python3-pip git 79 | 80 | # install ccache 81 | if [[ "${{ inputs.arch }}" == "x86_64" ]]; then 82 | curl -sLO https://github.com/ccache/ccache/releases/download/v4.10.2/ccache-4.10.2-linux-x86_64.tar.xz 83 | tar -xf ccache-4.10.2-linux-x86_64.tar.xz 84 | pushd ccache-4.10.2-linux-x86_64 && make install && popd 85 | elif [[ "${{ inputs.arch }}" == "aarch64" ]]; then 86 | dnf install -y ccache 87 | fi 88 | 89 | # install gh-cli 90 | if [[ "${{ inputs.arch }}" == "x86_64" ]]; then 91 | rpm_arch=amd64 92 | elif [[ "${{ inputs.arch }}" == "aarch64" ]]; then 93 | rpm_arch=arm64 94 | fi 95 | curl -sLO https://github.com/cli/cli/releases/download/v2.61.0/gh_2.61.0_linux_${rpm_arch}.rpm 96 | rpm -i gh_2.61.0_linux_${rpm_arch}.rpm 97 | 98 | # lol: failed to run git: fatal: detected dubious ownership in repository at '/__w/eudsl/eudsl' 99 | git config --global --add safe.directory /__w/eudsl/eudsl 100 | elif [[ "${{ inputs.os }}" == macos* ]]; then 101 | brew install ccache ninja 102 | fi 103 | 104 | - name: "Install Python" 105 | uses: actions/setup-python@v4 106 | if: ${{ startsWith(inputs.os, 'macos') || startsWith(inputs.os, 'windows') || startsWith(inputs.os, 'ubuntu') }} 107 | with: 108 | python-version: ${{ inputs.python-version }} 109 | 110 | - name: "Setup compiler/toolchain" 111 | uses: aminya/setup-cpp@v1 112 | if: ${{ startsWith(inputs.os, 'almalinux') || startsWith(inputs.os, 'ubuntu') || startsWith(inputs.os, 'windows') }} 113 | with: 114 | compiler: llvm-18 115 | cmake: true 116 | ninja: true 117 | ccache: ${{ startsWith(inputs.os, 'windows') || startsWith(inputs.os, 'ubuntu') }} 118 | vcvarsall: ${{ startsWith(inputs.os, 'windows') }} 119 | 120 | - name: "Set CC/CXX" 121 | shell: bash 122 | run: | 123 | if [[ "${{ inputs.os }}" == "almalinux" ]]; then 124 | echo "CC=/github/home/llvm/bin/clang" >> $GITHUB_ENV 125 | echo "CXX=/github/home/llvm/bin/clang++" >> $GITHUB_ENV 126 | elif [[ "${{ inputs.os }}" == "ubuntu" ]]; then 127 | echo "CC=/usr/lib/llvm-18/bin/clang" >> $GITHUB_ENV 128 | echo "CXX=/usr/lib/llvm-18/bin/clang++" >> $GITHUB_ENV 129 | elif [[ "${{ inputs.os }}" == "windows" ]]; then 130 | echo "CC=/C/Users/runneradmin/llvm/bin/clang-cl.exe" >> $GITHUB_ENV 131 | echo "CXX=/C/Users/runneradmin/llvm/bin/clang-cl.exe" >> $GITHUB_ENV 132 | elif [[ "${{ inputs.os }}" == "macos" ]]; then 133 | echo "CC=/usr/bin/clang" >> $GITHUB_ENV 134 | echo "CXX=/usr/bin/clang++" >> $GITHUB_ENV 135 | fi 136 | 137 | - name: "Python deps" 138 | shell: bash 139 | run: | 140 | python3_command="" 141 | if (command -v python${{ inputs.python-version }} &> /dev/null); then 142 | python3_command="python${{ inputs.python-version }}" 143 | elif (command -v python3 &> /dev/null); then 144 | python3_command="python3" 145 | elif (command -v python &> /dev/null); then 146 | python3_command="python" 147 | fi 148 | echo "python3_command=$python3_command" >> $GITHUB_ENV 149 | 150 | - name: Setup Emscripten 151 | if: contains(inputs.arch, 'wasm') 152 | uses: mymindstorm/setup-emsdk@v14 153 | with: 154 | version: 3.1.71 155 | 156 | - name: "Set CMake/ccache env vars" 157 | shell: bash 158 | run: | 159 | export CCACHE_DIR="${{ steps.canonicalize-cache-dir.outputs.cache-dir }}/ccache" 160 | mkdir -p $CCACHE_DIR 161 | echo "CCACHE_DIR=$CCACHE_DIR" >> $GITHUB_ENV 162 | echo "CCACHE_COMPILERCHECK=string:$($CC --version | head -n 1)" >> $GITHUB_ENV 163 | echo $CCACHE_COMPILERCHECK 164 | echo "CCACHE_MAXSIZE=700M" >> $GITHUB_ENV 165 | echo "CCACHE_SLOPPINESS=include_file_ctime,include_file_mtime,time_macros" >> $GITHUB_ENV 166 | echo "CCACHE_CPP2=true" >> $GITHUB_ENV 167 | echo "CCACHE_NOHASHDIR=true" >> $GITHUB_ENV 168 | echo "CCACHE_UMASK=002" >> $GITHUB_ENV 169 | if [[ "${{ inputs.os }}" == "almalinux" ]] || [[ "${{ inputs.os }}" == "ubuntu" ]] || [[ "${{ inputs.os }}" == "macos" ]]; then 170 | echo "CCACHE_LOGFILE=/tmp/ccache.log" >> $GITHUB_ENV 171 | elif [[ "${{ inputs.os }}" == "windows" ]]; then 172 | echo "CCACHE_LOGFILE=D:\a\ccache.log" >> $GITHUB_ENV 173 | fi 174 | 175 | ccache -z 176 | 177 | echo "CMAKE_GENERATOR=Ninja" >> $GITHUB_ENV 178 | echo "CMAKE_MAKE_PROGRAM=Ninja" >> $GITHUB_ENV 179 | echo "CMAKE_C_COMPILER_LAUNCHER=ccache" >> $GITHUB_ENV 180 | echo "CMAKE_CXX_COMPILER_LAUNCHER=ccache" >> $GITHUB_ENV 181 | echo "Python3_EXECUTABLE=$(which $python3_command)" >> $GITHUB_ENV 182 | 183 | if [[ "${{ inputs.os }}" == "ubuntu" ]] || [[ "${{ inputs.os }}" == "windows" ]]; then 184 | echo "CMAKE_EXE_LINKER_FLAGS_INIT=-fuse-ld=lld" >> $GITHUB_ENV 185 | echo "CMAKE_SHARED_LINKER_FLAGS_INIT=-fuse-ld=lld" >> $GITHUB_ENV 186 | echo "CMAKE_MODULE_LINKER_FLAGS_INIT=-fuse-ld=lld" >> $GITHUB_ENV 187 | fi 188 | 189 | if [[ "${{ matrix.os }}" == "macos" ]]; then 190 | echo MACOSX_DEPLOYMENT_TARGET=11.0 >> $GITHUB_ENV 191 | echo CMAKE_OSX_DEPLOYMENT_TARGET=11.0 >> $GITHUB_ENV 192 | fi 193 | -------------------------------------------------------------------------------- /.github/workflows/build_llvm.yml: -------------------------------------------------------------------------------- 1 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 | # See https://llvm.org/LICENSE.txt for license information. 3 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 | # Copyright (c) 2024. 5 | 6 | name: "Build LLVM and MLIR" 7 | 8 | on: 9 | workflow_dispatch: 10 | inputs: 11 | force_debug_with_tmate: 12 | type: boolean 13 | description: 'Run the build with tmate session' 14 | required: false 15 | default: false 16 | debug_with_tmate: 17 | type: boolean 18 | description: 'Run the build with a tmate session ONLY in case of failure' 19 | required: false 20 | default: false 21 | pull_request: 22 | paths: 23 | - ".github/actions/setup_base" 24 | - ".github/workflows/build_llvm.yml" 25 | - "build_tools/cmake/llvm_cache.cmake" 26 | - "build_tools/cmake/llvm_wasm_cache.cmake" 27 | - "build_tools/build_llvm.sh" 28 | - "build_tools/build_llvm_wasi.sh" 29 | - "third_party/llvm-project" 30 | push: 31 | branches: 32 | - main 33 | paths: 34 | - "build_tools/cmake/llvm_cache.cmake" 35 | - "build_tools/cmake/llvm_wasm_cache.cmake" 36 | - "build_tools/build_llvm.sh" 37 | - "build_tools/build_llvm_wasi.sh" 38 | - "third_party/llvm-project" 39 | 40 | concurrency: 41 | # A PR number if a pull request and otherwise the commit hash. This cancels 42 | # queued and in-progress runs for the same PR (presubmit) or commit 43 | # (postsubmit). The workflow name is prepended to avoid conflicts between 44 | # different workflows. 45 | group: ${{ github.workflow }}-${{ github.event.number || github.sha }} 46 | cancel-in-progress: true 47 | 48 | jobs: 49 | build: 50 | 51 | strategy: 52 | fail-fast: false 53 | matrix: 54 | include: 55 | - name: "manylinux_x86_64" 56 | runs-on: "ubuntu-22.04" 57 | container: "quay.io/pypa/manylinux_2_28_x86_64" 58 | os: "almalinux" 59 | arch: x86_64 60 | - name: "manylinux_aarch64" 61 | runs-on: "ubuntu-22.04-arm" 62 | container: "quay.io/pypa/manylinux_2_34_aarch64" 63 | os: "almalinux" 64 | arch: aarch64 65 | # - name: "ubuntu_aarch64" 66 | # runs-on: "ubuntu-22.04-arm" 67 | # os: "ubuntu" 68 | # arch: aarch64 69 | # - name: "wasm_wasi" 70 | # runs-on: "ubuntu-22.04" 71 | # container: "quay.io/pypa/manylinux_2_28_x86_64" 72 | # os: "almalinux" 73 | # arch: "wasm32-wasi" 74 | - name: "windows_x86_64" 75 | runs-on: "windows-2019" 76 | os: "windows" 77 | arch: x86_64 78 | - name: "macos_arm64" 79 | runs-on: "macos-14" 80 | os: "macos" 81 | arch: arm64 82 | - name: "macos_x86_64" 83 | runs-on: "macos-13" 84 | os: "macos" 85 | arch: x86_64 86 | 87 | runs-on: ${{ matrix.runs-on }} 88 | 89 | name: ${{ matrix.name }} 90 | 91 | defaults: 92 | run: 93 | shell: bash 94 | 95 | permissions: 96 | id-token: write 97 | contents: write 98 | 99 | env: 100 | # either the PR number or `branch-N` where N always increments 101 | cache-key: "mlir_${{ matrix.name }}_clang_${{ format('{0}-{1}', github.ref_name, github.run_number) }}" 102 | 103 | container: 104 | image: ${{ matrix.container }} 105 | 106 | steps: 107 | - name: "Check out repository" 108 | uses: actions/checkout@v4.2.2 109 | with: 110 | submodules: true 111 | 112 | - name: "Setup base" 113 | uses: ./.github/actions/setup_base 114 | id: setup_base 115 | with: 116 | cache-key: ${{ env.cache-key }} 117 | restore-key: "mlir_${{ matrix.name }}_clang" 118 | os: ${{ matrix.os }} 119 | arch: ${{ matrix.arch }} 120 | 121 | - name: "Build LLVM and MLIR" 122 | id: build 123 | run: | 124 | 125 | export LLVM_SOURCE_DIR="$PWD/third_party/llvm-project" 126 | export LLVM_BUILD_DIR="$PWD/llvm-build" 127 | # double nested so that upload artifacts uploads a folder 128 | export LLVM_INSTALL_DIR="$PWD/llvm-install/llvm-install" 129 | 130 | ccache -z 131 | $python3_command -m pip install -r third_party/llvm-project/mlir/python/requirements.txt 132 | 133 | if [[ "${{ matrix.arch }}" == "wasm32-wasi" ]]; then 134 | build_tools/build_llvm_wasi.sh 135 | else 136 | build_tools/build_llvm.sh 137 | echo "*********************** SMOKE TEST *********************************" 138 | "$LLVM_INSTALL_DIR/bin/mlir-tblgen" --version 139 | echo "*********************** SMOKE TEST *********************************" 140 | fi 141 | ccache -s 142 | 143 | pushd $LLVM_SOURCE_DIR && LLVM_SHA_SHORT=$(git rev-parse --short HEAD) && popd 144 | tar -czf mlir_${{ matrix.name }}_$(date +'%Y%m%d')_$LLVM_SHA_SHORT.tar.gz -C "$LLVM_INSTALL_DIR/.." llvm-install 145 | rm -rf "$LLVM_BUILD_DIR" "$LLVM_SOURCE_DIR" 146 | 147 | - name: Upload artifacts 148 | uses: actions/upload-artifact@v4 149 | with: 150 | name: mlir_${{ matrix.name }}_artifact 151 | path: llvm-install 152 | if-no-files-found: warn 153 | 154 | - name: Upload ccache log 155 | uses: actions/upload-artifact@v4 156 | with: 157 | name: ccache_log_${{ matrix.name }} 158 | path: ${{ startsWith(matrix.os, 'windows') && 'D:\a\ccache.log' || '/tmp/ccache.log' }} 159 | 160 | - name: Release current commit 161 | if: ${{ !cancelled() && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.ref_name == 'main' }} 162 | uses: ncipollo/release-action@v1.12.0 163 | with: 164 | artifacts: "*.tar.gz" 165 | token: "${{ secrets.GITHUB_TOKEN }}" 166 | tag: "llvm" 167 | name: "llvm" 168 | removeArtifacts: false 169 | allowUpdates: true 170 | replacesArtifacts: true 171 | makeLatest: true 172 | 173 | - name: "Save cache" 174 | uses: actions/cache/save@v3 175 | if: ${{ !cancelled() && github.event_name == 'push' && github.ref_name == 'main' }} 176 | with: 177 | path: ${{ steps.setup_base.outputs.cache-dir }} 178 | key: ${{ env.cache-key }} 179 | 180 | - name: "Setup tmate session" 181 | if: ${{ (failure() && inputs.debug_with_tmate) || inputs.force_debug_with_tmate }} 182 | uses: mxschmitt/action-tmate@v3.18 183 | with: 184 | limit-access-to-actor: true 185 | install-dependencies: ${{ startsWith(matrix.runs-on, 'macos') || startsWith(matrix.runs-on, 'windows') }} 186 | -------------------------------------------------------------------------------- /.github/workflows/bump_llvm.yml: -------------------------------------------------------------------------------- 1 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 | # See https://llvm.org/LICENSE.txt for license information. 3 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 | # Copyright (c) 2024. 5 | 6 | name: Auto bump LLVM 7 | on: 8 | workflow_dispatch: 9 | pull_request: 10 | paths: 11 | - ".github/workflows/bump_llvm.yml" 12 | schedule: 13 | # At minute 0 past hour 1. (see https://crontab.guru) 14 | - cron: '00 01 * * *' 15 | jobs: 16 | update-dep: 17 | 18 | name: "Bump LLVM and send PR" 19 | 20 | runs-on: ubuntu-latest 21 | 22 | permissions: 23 | contents: write 24 | pull-requests: write 25 | 26 | steps: 27 | - name: "Check out repository" 28 | uses: actions/checkout@v4.2.2 29 | with: 30 | submodules: true 31 | 32 | - name: "Sync third-party/llvm-project" 33 | id: sync-llvm-project 34 | run: | 35 | pushd third_party/llvm-project 36 | git checkout main && git pull 37 | echo "LLVM_SHA_SHORT=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT 38 | popd 39 | 40 | - uses: actions/create-github-app-token@v1 41 | id: generate-token 42 | with: 43 | app-id: ${{ secrets.BUMP_LLVM_CREATE_PR_APP_ID }} 44 | private-key: ${{ secrets.BUMP_LLVM_CREATE_PR_APP_PRIVATE_KEY }} 45 | 46 | - name: "Create Pull Request" 47 | uses: peter-evans/create-pull-request@v7 48 | with: 49 | token: ${{ steps.generate-token.outputs.token }} 50 | commit-message: "[LLVM] Bump to ${{ steps.sync-llvm-project.outputs.LLVM_SHA_SHORT }}" 51 | title: "[LLVM] Bump to ${{ steps.sync-llvm-project.outputs.LLVM_SHA_SHORT }}" 52 | body: "Bump LLVM to https://github.com/llvm/llvm-project/commit/${{ steps.sync-llvm-project.outputs.LLVM_SHA_SHORT }}" 53 | author: 'github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>' 54 | base: main 55 | branch: update-llvm 56 | delete-branch: true 57 | assignees: makslevental 58 | reviewers: makslevental 59 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | .idea -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "third_party/llvm-project"] 2 | path = third_party/llvm-project 3 | url = https://github.com/llvm/llvm-project.git 4 | ignore = dirty 5 | shallow = true 6 | branch = main 7 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 | # See https://llvm.org/LICENSE.txt for license information. 3 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 | # Copyright (c) 2024. 5 | 6 | cmake_minimum_required(VERSION 3.29) 7 | set(CMAKE_CXX_STANDARD 17) 8 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 9 | 10 | set(LLVM_SUBPROJECT_TITLE "EUDSL") 11 | set(EUDSL_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) 12 | 13 | if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) 14 | message("Building ${LLVM_SUBPROJECT_TITLE} as a standalone project.") 15 | project(${LLVM_SUBPROJECT_TITLE} CXX C) 16 | set(EUDSL_STANDALONE_BUILD ON) 17 | else() 18 | enable_language(CXX C) 19 | set(EUDSL_STANDALONE_BUILD OFF) 20 | endif() 21 | 22 | if(EUDSL_STANDALONE_BUILD) 23 | find_package(LLVM REQUIRED CONFIG) 24 | find_package(MLIR REQUIRED CONFIG) 25 | find_package(Clang REQUIRED CONFIG PATHS "${LLVM_BINARY_DIR}" NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH) 26 | 27 | message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") 28 | message(STATUS "Using MLIRConfig.cmake in: ${MLIR_DIR}") 29 | message(STATUS "Using ClangConfig.cmake in: ${Clang_DIR}") 30 | 31 | set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/bin) 32 | set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/lib) 33 | set(MLIR_BINARY_DIR ${CMAKE_BINARY_DIR}) 34 | set(MLIR_INCLUDE_DIR ${MLIR_INCLUDE_DIRS}) 35 | 36 | list(APPEND CMAKE_MODULE_PATH "${MLIR_CMAKE_DIR}") 37 | list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") 38 | list(APPEND CMAKE_MODULE_PATH "${CLANG_CMAKE_DIR}") 39 | 40 | include(TableGen) 41 | include(AddLLVM) 42 | include(AddMLIR) 43 | include(AddClang) 44 | else() 45 | # turning LLVM -DLLVM_OPTIMIZED_TABLEGEN=ON builds some stuff in the NATIVE dir 46 | # but not everything so LLVM_BINARY_DIR isn't correct 47 | string(REPLACE "NATIVE" "" LLVM_BINARY_DIR "${LLVM_BINARY_DIR}") 48 | # Build via external projects mechanism 49 | set(LLVM_INCLUDE_DIR ${LLVM_MAIN_SRC_DIR}/include) 50 | set(LLVM_GENERATED_INCLUDE_DIR ${LLVM_BINARY_DIR}/include) 51 | set(LLVM_INCLUDE_DIRS "${LLVM_INCLUDE_DIR};${LLVM_GENERATED_INCLUDE_DIR}") 52 | 53 | set(MLIR_MAIN_SRC_DIR ${LLVM_MAIN_SRC_DIR}/../mlir) 54 | set(MLIR_INCLUDE_DIR ${MLIR_MAIN_SRC_DIR}/include) 55 | set(MLIR_GENERATED_INCLUDE_DIR ${LLVM_BINARY_DIR}/tools/mlir/include) 56 | set(MLIR_INCLUDE_DIRS "${MLIR_INCLUDE_DIR};${MLIR_GENERATED_INCLUDE_DIR}") 57 | 58 | set(CLANG_MAIN_SRC_DIR ${LLVM_MAIN_SRC_DIR}/../clang) 59 | set(CLANG_INCLUDE_DIR ${CLANG_MAIN_SRC_DIR}/include) 60 | set(CLANG_GENERATED_INCLUDE_DIR ${LLVM_BINARY_DIR}/tools/clang/include) 61 | set(CLANG_INCLUDE_DIRS "${CLANG_INCLUDE_DIR};${CLANG_GENERATED_INCLUDE_DIR}") 62 | endif() 63 | 64 | include_directories(${LLVM_INCLUDE_DIRS}) 65 | include_directories(${MLIR_INCLUDE_DIRS}) 66 | include_directories(${CLANG_INCLUDE_DIRS}) 67 | link_directories(${LLVM_BUILD_LIBRARY_DIR}) 68 | add_definitions(${LLVM_DEFINITIONS}) 69 | 70 | if(NOT TARGET LLVMSupport) 71 | message(FATAL_ERROR "LLVMSupport not found") 72 | endif() 73 | 74 | add_subdirectory(projects) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | image 3 |

4 | 5 | # Embedded Universal DSL: a good DSL for us, by us 6 | 7 | This repository contains the source code for `EUDSL`, a toolkit for the construction of 8 | embedded DSLs, in arbitrary languages, for targeting [MLIR](https://mlir.llvm.org). 9 | 10 | FYI: this project is currently "alpha" quality. 11 | 12 | Currently, there are three components: 13 | 14 | 1. [eudsl-tblgen](./projects/eudsl-tblgen): Python bindings to [LLVM's TableGen library](https://github.com/llvm/llvm-project/tree/659192b1843c4af180700783caca4cdc7afa3eab/llvm/lib/TableGen); 15 | 2. [eudsl-nbgen](./projects/eudsl-nbgen): A source-to-source translator that translates MLIR headers[^1] into direct `nanobind` bindings; 16 | 3. [eudsl-py](./projects/eudsl-py): Direct Python bindings to MLIR, generated using `eudsl-nbgen`; 17 | * Currently only TableGen outputs (various `*.h.inc` files generated by `mlir-tblgen`) are automatically translated but the `eudsl-nbgen` tool can be manually run to translate any MLIR header (to varying degrees of success); 18 | * See [projects/eudsl-py/tests](./projects/eudsl-py/tests) for a few examples of what these bindings look like. 19 | 20 | ## Getting started 21 | 22 | Python wheels of all the tools are available at the [`latest` release page](https://github.com/llvm/eudsl/releases/tag/latest). 23 | They are also `pip install`-able with .e.g 24 | 25 | ```shell 26 | $ cd 27 | $ pip install eudsl-py -f https://github.com/llvm/eudsl/releases/expanded_assets/latest 28 | ``` 29 | 30 | `eudsl-py` has a slowly growing set of tests @ [projects/eudsl-py/tests](./projects/eudsl-py/tests). 31 | 32 | If you don't want to install locally, here is a [colab notebook minimal working example](https://colab.research.google.com/drive/1l-6rVnsUM3ypn7rKcaF_V6XVdopEM4Df?usp=sharing). 33 | 34 | ## Developing/building 35 | 36 | **Strong recommendation**: check the CI scripts @ [.github/workflows](.github/workflows) - they do a fresh checkout and build on every commit and are written to be read by a non-CI expert. 37 | 38 | Firstly, you need a distribution of LLVM. You can build LLVM from source using our submodule by doing (on Mac/Linux or mingw): 39 | 40 | ```shell 41 | $ cd 42 | $ ./build_tools/build_llvm.sh 43 | ``` 44 | 45 | Alternatively you can download a distribution for your platform from the [`llvm` release page](https://github.com/llvm/eudsl/releases/tag/llvm). 46 | 47 | Then each of the above tools can both be built as a conventional, standalone, CMake project and as a Python wheel. 48 | The wheel build looks something like: 49 | 50 | ```shell 51 | $ cd 52 | $ export CMAKE_PREFIX_PATH=$PWD/llvm-install 53 | $ pip wheel projects/eudsl-nbgen -w wheelhouse -v 54 | $ pip wheel projects/eudsl-py -w wheelhouse -v --find-links $PWD/wheelhouse 55 | ``` 56 | 57 | Note, the trailing `--find-links $PWD/wheelhouse` on `pip wheel projects/eudsl-py` is because `eudsl-nbgen` is a dependency of `eudsl-py` (that can be satisfied using the `eudsl-nbgen` wheel). 58 | 59 | If you want to build an individual tool via CMake you can do something like: 60 | 61 | ```shell 62 | $ cd 63 | $ pip install -r requirements.txt 64 | $ export CMAKE_PREFIX_PATH=$PWD/llvm-install 65 | $ cmake -B $PWD/eudsl-nbgen-build -S $PWD/projects/eudsl-nbgen -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$PWD/eudsl-nbgen-install 66 | $ cmake --build "$PWD/eudsl-build" --target install 67 | ``` 68 | 69 | If you want to build all the tools at once using CMake you can use the root [`CMakeLists.txt`](./CMakeLists.txt). 70 | Note, in this case, `eudsl-nbgen` will automatically be built prior to `eudsl-py`. 71 | 72 | ## Footnotes 73 | 74 | [^1]: Yes C++ headers... -------------------------------------------------------------------------------- /build_tools/build_llvm.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 | # See https://llvm.org/LICENSE.txt for license information. 5 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | # Copyright (c) 2024. 7 | 8 | TD="$(cd $(dirname $0) && pwd)" 9 | REPO_ROOT="$(cd $TD/.. && pwd)" 10 | 11 | LLVM_SOURCE_DIR="${LLVM_SOURCE_DIR:-${REPO_ROOT}/third_party/llvm-project}" 12 | LLVM_BUILD_DIR="${LLVM_BUILD_DIR:-${REPO_ROOT}/llvm-build}" 13 | LLVM_INSTALL_DIR="${LLVM_INSTALL_DIR:-${REPO_ROOT}/llvm-install}" 14 | 15 | mkdir -p $LLVM_BUILD_DIR 16 | mkdir -p $LLVM_INSTALL_DIR 17 | 18 | LLVM_SOURCE_DIR="$(realpath "${LLVM_SOURCE_DIR}")" 19 | LLVM_BUILD_DIR="$(realpath "${LLVM_BUILD_DIR}")" 20 | LLVM_INSTALL_DIR="$(realpath "${LLVM_INSTALL_DIR}")" 21 | 22 | echo "Paths canonicalized as:" 23 | echo "LLVM_SOURCE_DIR=${LLVM_SOURCE_DIR}" 24 | echo "LLVM_BUILD_DIR=${LLVM_BUILD_DIR}" 25 | echo "LLVM_INSTALL_DIR=${LLVM_INSTALL_DIR}" 26 | 27 | python3_command="python" 28 | if (command -v python3 &> /dev/null); then 29 | python3_command="python3" 30 | fi 31 | 32 | Python3_EXECUTABLE="${Python3_EXECUTABLE:-$(which $python3_command)}" 33 | 34 | set -euo pipefail 35 | 36 | echo "*********************** BUILDING LLVM *********************************" 37 | 38 | cmake_options=( 39 | -GNinja 40 | -S "${LLVM_SOURCE_DIR}/llvm" 41 | -B "${LLVM_BUILD_DIR}" 42 | -DCMAKE_BUILD_TYPE=Release 43 | # this flag keeps changing names in CMake... 44 | -DPython3_EXECUTABLE="$Python3_EXECUTABLE" 45 | -DPython_EXECUTABLE="$Python3_EXECUTABLE" 46 | -DPYTHON_EXECUTABLE="$Python3_EXECUTABLE" 47 | -DCMAKE_INSTALL_PREFIX="${LLVM_INSTALL_DIR}" 48 | ) 49 | 50 | if [ -x "$(command -v ccache)" ]; then 51 | echo 'using ccache' >&2 52 | export CCACHE_SLOPPINESS=include_file_ctime,include_file_mtime,time_macros 53 | export CCACHE_CPP2=true 54 | export CCACHE_UMASK=002 55 | cmake_options+=( 56 | -DCMAKE_C_COMPILER_LAUNCHER=ccache 57 | -DCMAKE_CXX_COMPILER_LAUNCHER=ccache 58 | ) 59 | fi 60 | 61 | # last so that C/CXX flags get set first 62 | cmake_options+=(-C "$TD/cmake/llvm_cache.cmake") 63 | 64 | echo "Source Directory: ${LLVM_SOURCE_DIR}" 65 | echo "Build Directory: ${LLVM_BUILD_DIR}" 66 | echo "CMake Options: ${cmake_options[*]}" 67 | 68 | cmake "${cmake_options[@]}" 69 | cmake --build "${LLVM_BUILD_DIR}" \ 70 | --target install-mlirdevelopment-distribution 71 | -------------------------------------------------------------------------------- /build_tools/build_llvm_wasi.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 | # See https://llvm.org/LICENSE.txt for license information. 5 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | # Copyright (c) 2024. 7 | 8 | TD="$(cd $(dirname $0) && pwd)" 9 | REPO_ROOT="$(cd $TD/.. && pwd)" 10 | 11 | LLVM_SOURCE_DIR="${LLVM_SOURCE_DIR:-${REPO_ROOT}/third_party/llvm-project}" 12 | LLVM_BUILD_DIR="${LLVM_BUILD_DIR:-${REPO_ROOT}/llvm-build}" 13 | LLVM_INSTALL_DIR="${LLVM_INSTALL_DIR:-${REPO_ROOT}/llvm-install}" 14 | 15 | mkdir -p $LLVM_BUILD_DIR 16 | mkdir -p $LLVM_INSTALL_DIR 17 | 18 | LLVM_SOURCE_DIR="$(realpath "${LLVM_SOURCE_DIR}")" 19 | LLVM_BUILD_DIR="$(realpath "${LLVM_BUILD_DIR}")" 20 | LLVM_INSTALL_DIR="$(realpath "${LLVM_INSTALL_DIR}")" 21 | EMSDK="$(realpath "${EMSDK}")" 22 | 23 | echo "Paths canonicalized as:" 24 | echo "LLVM_SOURCE_DIR=${LLVM_SOURCE_DIR}" 25 | echo "LLVM_BUILD_DIR=${LLVM_BUILD_DIR}" 26 | echo "LLVM_INSTALL_DIR=${LLVM_INSTALL_DIR}" 27 | 28 | $EMSDK/emsdk activate 29 | source $EMSDK/emsdk_env.sh 30 | export CCACHE_COMPILERCHECK="string:$(emcc --version | head -n 1)" 31 | 32 | set -euo pipefail 33 | 34 | echo "*********************** BUILDING LLVM *********************************" 35 | 36 | # hack to emit html wrappers 37 | # https://stackoverflow.com/a/75596433/9045206 38 | sed -i.bak 's/CMAKE_EXECUTABLE_SUFFIX ".js"/CMAKE_EXECUTABLE_SUFFIX ".html"/g' "$EMSDK/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake" 39 | 40 | cmake_options=( 41 | -GNinja 42 | -S "${LLVM_SOURCE_DIR}/llvm" 43 | -B "${LLVM_BUILD_DIR}" 44 | # optimize for size 45 | -DCMAKE_C_FLAGS="-Os" 46 | -DCMAKE_CXX_FLAGS="-Os" 47 | -DCMAKE_BUILD_TYPE=Release 48 | -DCMAKE_EXE_LINKER_FLAGS="--emit-symbol-map -sSTANDALONE_WASM=1 -sWASM=1 -sWASM_BIGINT=1 -sEXPORT_ALL=0 -sEXPORTED_RUNTIME_METHODS=cwrap,ccall,getValue,setValue,writeAsciiToMemory,wasmTable -lembind" 49 | -DCMAKE_INSTALL_PREFIX="${LLVM_INSTALL_DIR}" 50 | -DCMAKE_SYSTEM_NAME=Emscripten 51 | -DCMAKE_TOOLCHAIN_FILE="$EMSDK/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake" 52 | -DCROSS_TOOLCHAIN_FLAGS_NATIVE="-DCMAKE_C_COMPILER=$CC;-DCMAKE_CXX_COMPILER=$CXX" 53 | -C "$TD/cmake/llvm_wasm_cache.cmake" 54 | ) 55 | 56 | echo "Source Directory: ${LLVM_SOURCE_DIR}" 57 | echo "Build Directory: ${LLVM_BUILD_DIR}" 58 | echo "CMake Options: ${cmake_options[*]}" 59 | 60 | cmake "${cmake_options[@]}" 61 | cmake --build "${LLVM_BUILD_DIR}" \ 62 | --target install-mlirdevelopment-distribution 63 | 64 | sed -i.bak 's/CMAKE_EXECUTABLE_SUFFIX ".html"/CMAKE_EXECUTABLE_SUFFIX ".js"/g' "$EMSDK/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake" 65 | 66 | # wasi files aren't installed for some reason 67 | cp "${LLVM_BUILD_DIR}"/bin/* "${LLVM_INSTALL_DIR}/bin" 68 | -------------------------------------------------------------------------------- /build_tools/cmake/llvm_cache.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 3 | # See https://llvm.org/LICENSE.txt for license information. 4 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 5 | # Copyright (c) 2024. 6 | # 7 | 8 | include(CMakePrintHelpers) 9 | 10 | set(LLVM_ENABLE_PROJECTS "llvm;mlir;clang" CACHE STRING "") 11 | 12 | # LLVM options 13 | 14 | set(LLVM_BUILD_TOOLS ON CACHE BOOL "") 15 | set(LLVM_BUILD_UTILS ON CACHE BOOL "") 16 | set(LLVM_INCLUDE_TOOLS ON CACHE BOOL "") 17 | set(LLVM_INSTALL_UTILS ON CACHE BOOL "") 18 | set(LLVM_ENABLE_DUMP ON CACHE BOOL "") 19 | 20 | set(LLVM_BUILD_LLVM_DYLIB ON CACHE BOOL "") 21 | # All the tools will use libllvm shared library 22 | # (but doesn't work on windows) 23 | if (NOT WIN32) 24 | set(LLVM_LINK_LLVM_DYLIB ON CACHE BOOL "") 25 | set(MLIR_LINK_MLIR_DYLIB ON CACHE BOOL "") 26 | endif() 27 | 28 | # useful things 29 | set(LLVM_ENABLE_ASSERTIONS ON CACHE BOOL "") 30 | set(LLVM_ENABLE_WARNINGS ON CACHE BOOL "") 31 | set(LLVM_FORCE_ENABLE_STATS ON CACHE BOOL "") 32 | # because AMD target td files are insane... 33 | set(LLVM_TARGETS_TO_BUILD "host;NVPTX;AMDGPU" CACHE STRING "") 34 | set(LLVM_OPTIMIZED_TABLEGEN ON CACHE BOOL "") 35 | set(LLVM_ENABLE_RTTI ON CACHE BOOL "") 36 | 37 | # MLIR options 38 | 39 | set(MLIR_ENABLE_BINDINGS_PYTHON ON CACHE BOOL "") 40 | set(MLIR_ENABLE_EXECUTION_ENGINE ON CACHE BOOL "") 41 | set(MLIR_ENABLE_SPIRV_CPU_RUNNER ON CACHE BOOL "") 42 | 43 | # space savings 44 | 45 | set(LLVM_BUILD_DOCS OFF CACHE BOOL "") 46 | set(LLVM_ENABLE_OCAMLDOC OFF CACHE BOOL "") 47 | set(LLVM_ENABLE_BINDINGS OFF CACHE BOOL "") 48 | set(LLVM_BUILD_BENCHMARKS OFF CACHE BOOL "") 49 | set(LLVM_BUILD_EXAMPLES OFF CACHE BOOL "") 50 | set(LLVM_ENABLE_LIBCXX OFF CACHE BOOL "") 51 | set(LLVM_ENABLE_LIBCXX OFF CACHE BOOL "") 52 | set(LLVM_ENABLE_LIBEDIT OFF CACHE BOOL "") 53 | set(LLVM_ENABLE_LIBXML2 OFF CACHE BOOL "") 54 | set(LLVM_ENABLE_TERMINFO OFF CACHE BOOL "") 55 | 56 | set(LLVM_ENABLE_CRASH_OVERRIDES OFF CACHE BOOL "") 57 | set(LLVM_ENABLE_Z3_SOLVER OFF CACHE BOOL "") 58 | set(LLVM_ENABLE_ZLIB OFF CACHE BOOL "") 59 | set(LLVM_ENABLE_ZSTD OFF CACHE BOOL "") 60 | set(LLVM_INCLUDE_BENCHMARKS OFF CACHE BOOL "") 61 | set(LLVM_INCLUDE_DOCS OFF CACHE BOOL "") 62 | set(LLVM_INCLUDE_EXAMPLES OFF CACHE BOOL "") 63 | set(LLVM_INCLUDE_GO_TESTS OFF CACHE BOOL "") 64 | 65 | # tests 66 | 67 | option(RUN_TESTS "" OFF) 68 | set(LLVM_INCLUDE_TESTS ${RUN_TESTS} CACHE BOOL "") 69 | set(LLVM_BUILD_TESTS ${RUN_TESTS} CACHE BOOL "") 70 | set(MLIR_INCLUDE_INTEGRATION_TESTS ${RUN_TESTS} CACHE BOOL "") 71 | set(MLIR_INCLUDE_TESTS ${RUN_TESTS} CACHE BOOL "") 72 | 73 | ### Distributions ### 74 | 75 | set(LLVM_INSTALL_TOOLCHAIN_ONLY OFF CACHE BOOL "") 76 | 77 | set(LLVM_DISTRIBUTIONS MlirDevelopment CACHE STRING "") 78 | set(LLVM_MlirDevelopment_DISTRIBUTION_COMPONENTS 79 | clang-libraries 80 | clang-headers 81 | # triggers ClangConfig.cmake and etc 82 | clang-cmake-exports 83 | # triggers ClangMlirDevelopmentTargets.cmake 84 | clang-mlirdevelopment-cmake-exports 85 | 86 | # triggers ClangConfig.cmake and etc 87 | cmake-exports 88 | # triggers LLVMMlirDevelopmentExports.cmake 89 | mlirdevelopment-cmake-exports 90 | llvm-config 91 | llvm-headers 92 | llvm-libraries 93 | 94 | FileCheck 95 | not 96 | MLIRPythonModules 97 | # triggers MLIRMlirDevelopmentTargets.cmake 98 | mlir-mlirdevelopment-cmake-exports 99 | # triggers MLIRConfig.cmake and etc 100 | mlir-cmake-exports 101 | mlir-headers 102 | mlir-libraries 103 | mlir-opt 104 | mlir-python-sources 105 | mlir-reduce 106 | mlir-tblgen 107 | mlir-translate 108 | CACHE STRING "") 109 | 110 | if (NOT WIN32) 111 | list(APPEND LLVM_MlirDevelopment_DISTRIBUTION_COMPONENTS LLVM MLIR) 112 | endif() 113 | 114 | get_cmake_property(_variableNames VARIABLES) 115 | list(SORT _variableNames) 116 | cmake_print_variables(${_variableNames}) 117 | -------------------------------------------------------------------------------- /build_tools/cmake/llvm_wasm_cache.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 3 | # See https://llvm.org/LICENSE.txt for license information. 4 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 5 | # Copyright (c) 2024. 6 | # 7 | 8 | set(LLVM_ENABLE_PROJECTS "mlir;llvm" CACHE STRING "") 9 | set(LLVM_BUILD_TOOLS ON CACHE BOOL "") 10 | set(LLVM_INCLUDE_TOOLS ON CACHE BOOL "") 11 | set(LLVM_TARGETS_TO_BUILD "WebAssembly" CACHE STRING "") 12 | set(LLVM_TARGET_ARCH "wasm32-wasi" CACHE STRING "") 13 | set(LLVM_DEFAULT_TARGET_TRIPLE "wasm32-wasi" CACHE STRING "") 14 | 15 | set(LLVM_BUILD_DOCS OFF CACHE BOOL "") 16 | set(LLVM_ENABLE_BACKTRACES OFF CACHE BOOL "") 17 | set(LLVM_ENABLE_BINDINGS OFF CACHE BOOL "") 18 | set(LLVM_ENABLE_CRASH_OVERRIDES OFF CACHE BOOL "") 19 | set(LLVM_ENABLE_LIBEDIT OFF CACHE BOOL "") 20 | set(LLVM_ENABLE_LIBPFM OFF CACHE BOOL "") 21 | set(LLVM_ENABLE_LIBXML2 OFF CACHE BOOL "") 22 | set(LLVM_ENABLE_OCAMLDOC OFF CACHE BOOL "") 23 | set(LLVM_ENABLE_PIC OFF CACHE BOOL "") 24 | set(LLVM_ENABLE_THREADS OFF CACHE BOOL "") 25 | set(LLVM_ENABLE_UNWIND_TABLES OFF CACHE BOOL "") 26 | set(LLVM_ENABLE_ZLIB OFF CACHE BOOL "") 27 | set(LLVM_ENABLE_ZSTD OFF CACHE BOOL "") 28 | set(LLVM_INCLUDE_BENCHMARKS OFF CACHE BOOL "") 29 | set(LLVM_INCLUDE_EXAMPLES OFF CACHE BOOL "") 30 | set(LLVM_INCLUDE_TESTS OFF CACHE BOOL "") 31 | set(LLVM_INCLUDE_UTILS OFF CACHE BOOL "") 32 | 33 | ### Distributions ### 34 | 35 | set(LLVM_INSTALL_TOOLCHAIN_ONLY OFF CACHE BOOL "") 36 | 37 | set(LLVM_DISTRIBUTIONS MlirDevelopment CACHE STRING "") 38 | set(LLVM_MlirDevelopment_DISTRIBUTION_COMPONENTS 39 | llvm-config 40 | llvm-headers 41 | llvm-libraries 42 | cmake-exports 43 | opt 44 | # triggers LLVMMlirDevelopmentExports.cmake 45 | mlirdevelopment-cmake-exports 46 | # triggers MLIRMlirDevelopmentTargets.cmake 47 | mlir-mlirdevelopment-cmake-exports 48 | # triggers MLIRConfig.cmake and etc 49 | mlir-cmake-exports 50 | mlir-headers 51 | mlir-libraries 52 | mlir-opt 53 | mlir-reduce 54 | mlir-tblgen 55 | mlir-translate 56 | CACHE STRING "") -------------------------------------------------------------------------------- /docs/images/eudslpurple.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /projects/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 | # See https://llvm.org/LICENSE.txt for license information. 3 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 | # Copyright (c) 2024. 5 | 6 | include_directories(common) 7 | 8 | add_subdirectory(eudsl-nbgen) 9 | add_subdirectory(eudsl-tblgen) 10 | if(NOT WIN32) 11 | add_subdirectory(eudsl-py) 12 | endif() 13 | add_subdirectory(eudsl-llvmpy) 14 | -------------------------------------------------------------------------------- /projects/common/eudsl/helpers.h: -------------------------------------------------------------------------------- 1 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 | // See https://llvm.org/LICENSE.txt for license information. 3 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 | // Copyright (c) 2025. 5 | 6 | #ifndef HELPERS_H 7 | #define HELPERS_H 8 | 9 | #include 10 | 11 | template 12 | struct non_copying_non_moving_class_ : nanobind::class_ { 13 | template 14 | NB_INLINE non_copying_non_moving_class_(nanobind::handle scope, 15 | const char *name, 16 | const Extra &...extra) { 17 | nanobind::detail::type_init_data d; 18 | 19 | d.flags = 0; 20 | d.align = (uint8_t)alignof(typename nanobind::class_::Alias); 21 | d.size = (uint32_t)sizeof(typename nanobind::class_::Alias); 22 | d.name = name; 23 | d.scope = scope.ptr(); 24 | d.type = &typeid(T); 25 | 26 | if constexpr (!std::is_same_v::Base, 27 | T>) { 28 | d.base = &typeid(typename nanobind::class_::Base); 29 | d.flags |= (uint32_t)nanobind::detail::type_init_flags::has_base; 30 | } 31 | 32 | if constexpr (std::is_destructible_v) { 33 | d.flags |= (uint32_t)nanobind::detail::type_flags::is_destructible; 34 | 35 | if constexpr (!std::is_trivially_destructible_v) { 36 | d.flags |= (uint32_t)nanobind::detail::type_flags::has_destruct; 37 | d.destruct = nanobind::detail::wrap_destruct; 38 | } 39 | } 40 | 41 | if constexpr (nanobind::detail::has_shared_from_this_v) { 42 | d.flags |= (uint32_t)nanobind::detail::type_flags::has_shared_from_this; 43 | d.keep_shared_from_this_alive = [](PyObject *self) noexcept { 44 | if (auto sp = nanobind::inst_ptr(self)->weak_from_this().lock()) { 45 | nanobind::detail::keep_alive( 46 | self, new auto(std::move(sp)), 47 | [](void *p) noexcept { delete (decltype(sp) *)p; }); 48 | return true; 49 | } 50 | return false; 51 | }; 52 | } 53 | 54 | (nanobind::detail::type_extra_apply(d, extra), ...); 55 | 56 | this->m_ptr = nanobind::detail::nb_type_new(&d); 57 | } 58 | }; 59 | 60 | #endif // HELPERS_H 61 | -------------------------------------------------------------------------------- /projects/common/eudsl/type_casters.h: -------------------------------------------------------------------------------- 1 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 | // See https://llvm.org/LICENSE.txt for license information. 3 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 | // Copyright (c) 2024-2025. 5 | 6 | #pragma once 7 | 8 | #include 9 | // ReSharper disable once CppUnusedIncludeDirective 10 | #include 11 | #include 12 | // ReSharper disable once CppUnusedIncludeDirective 13 | #include 14 | // ReSharper disable once CppUnusedIncludeDirective 15 | #include 16 | // ReSharper disable once CppUnusedIncludeDirective 17 | #include "eudsl/bind_vec_like.h" 18 | 19 | template <> 20 | struct nanobind::detail::type_caster { 21 | NB_TYPE_CASTER(llvm::StringRef, const_name("str")) 22 | 23 | bool from_python(handle src, uint8_t, cleanup_list *) noexcept { 24 | Py_ssize_t size; 25 | const char *str = PyUnicode_AsUTF8AndSize(src.ptr(), &size); 26 | if (!str) { 27 | PyErr_Clear(); 28 | return false; 29 | } 30 | value = llvm::StringRef(str, (size_t)size); 31 | return true; 32 | } 33 | 34 | static handle from_cpp(llvm::StringRef value, rv_policy, 35 | cleanup_list *) noexcept { 36 | return PyUnicode_FromStringAndSize(value.data(), value.size()); 37 | } 38 | }; 39 | 40 | template <> 41 | struct nanobind::detail::type_caster { 42 | NB_TYPE_CASTER(llvm::StringLiteral, const_name("str")) 43 | 44 | static handle from_cpp(llvm::StringLiteral value, rv_policy, 45 | cleanup_list *) noexcept { 46 | return PyUnicode_FromStringAndSize(value.data(), value.size()); 47 | } 48 | }; 49 | 50 | template <> 51 | struct nanobind::detail::type_caster { 52 | using Value = llvm::Twine; 53 | static constexpr auto Name = const_name("str"); 54 | template 55 | using Cast = movable_cast_t; 56 | 57 | template 58 | static constexpr bool can_cast() { 59 | return true; 60 | } 61 | 62 | template , Value>> = 0> 64 | static handle from_cpp(T_ *p, rv_policy policy, cleanup_list *list) { 65 | if (!p) 66 | return none().release(); 67 | return from_cpp(*p, policy, list); 68 | } 69 | 70 | explicit operator Value *() { return &*value; } 71 | explicit operator Value &() { return (Value &)*value; } 72 | explicit operator Value &&() { return (Value &&)*value; } 73 | 74 | // hack because Twine::operator= is deleted 75 | std::optional value; 76 | 77 | bool from_python(handle src, uint8_t, cleanup_list *) noexcept { 78 | Py_ssize_t size; 79 | const char *str = PyUnicode_AsUTF8AndSize(src.ptr(), &size); 80 | if (!str) { 81 | PyErr_Clear(); 82 | return false; 83 | } 84 | std::string_view s{str, (size_t)size}; 85 | value.emplace(s); 86 | return true; 87 | } 88 | 89 | static handle from_cpp(llvm::Twine value, rv_policy, 90 | cleanup_list *) noexcept { 91 | llvm::StringRef s = value.getSingleStringRef(); 92 | return PyUnicode_FromStringAndSize(s.data(), s.size()); 93 | } 94 | }; 95 | -------------------------------------------------------------------------------- /projects/common/eudsl/util.h: -------------------------------------------------------------------------------- 1 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 | // See https://llvm.org/LICENSE.txt for license information. 3 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 | // Copyright (c) 2025. 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | namespace eudsl { 11 | template 12 | struct non_copying_non_moving_class_ : nanobind::class_ { 13 | template 14 | NB_INLINE non_copying_non_moving_class_(nanobind::handle scope, 15 | const char *name, 16 | const Extra &...extra) { 17 | nanobind::detail::type_init_data d; 18 | 19 | d.flags = 0; 20 | d.align = (uint8_t)alignof(typename nanobind::class_::Alias); 21 | d.size = (uint32_t)sizeof(typename nanobind::class_::Alias); 22 | d.name = name; 23 | d.scope = scope.ptr(); 24 | d.type = &typeid(T); 25 | 26 | if constexpr (!std::is_same_v::Base, 27 | T>) { 28 | d.base = &typeid(typename nanobind::class_::Base); 29 | d.flags |= (uint32_t)nanobind::detail::type_init_flags::has_base; 30 | } 31 | 32 | if constexpr (std::is_destructible_v) { 33 | d.flags |= (uint32_t)nanobind::detail::type_flags::is_destructible; 34 | 35 | if constexpr (!std::is_trivially_destructible_v) { 36 | d.flags |= (uint32_t)nanobind::detail::type_flags::has_destruct; 37 | d.destruct = nanobind::detail::wrap_destruct; 38 | } 39 | } 40 | 41 | if constexpr (nanobind::detail::has_shared_from_this_v) { 42 | d.flags |= (uint32_t)nanobind::detail::type_flags::has_shared_from_this; 43 | d.keep_shared_from_this_alive = [](PyObject *self) noexcept { 44 | if (auto sp = nanobind::inst_ptr(self)->weak_from_this().lock()) { 45 | nanobind::detail::keep_alive( 46 | self, new auto(std::move(sp)), 47 | [](void *p) noexcept { delete (decltype(sp) *)p; }); 48 | return true; 49 | } 50 | return false; 51 | }; 52 | } 53 | 54 | (nanobind::detail::type_extra_apply(d, extra), ...); 55 | 56 | this->m_ptr = nanobind::detail::nb_type_new(&d); 57 | } 58 | }; 59 | 60 | template 61 | constexpr auto coerceReturn(Return (*pf)(Args...)) noexcept { 62 | return [&pf](Args &&...args) -> NewReturn { 63 | return pf(std::forward(args)...); 64 | }; 65 | } 66 | 67 | template 68 | constexpr auto coerceReturn(Return (Class::*pmf)(Args...), 69 | std::false_type = {}) noexcept { 70 | return [&pmf](Class *cls, Args &&...args) -> NewReturn { 71 | return (cls->*pmf)(std::forward(args)...); 72 | }; 73 | } 74 | 75 | /* 76 | * If you get 77 | * ``` 78 | * Called object type 'void(MyClass::*)(vector&,int)' is not a function or 79 | * function pointer 80 | * ``` 81 | * it's because you're calling a member function without 82 | * passing the `this` pointer as the first arg 83 | */ 84 | template 85 | constexpr auto coerceReturn(Return (Class::*pmf)(Args...) const, 86 | std::true_type) noexcept { 87 | // copy the *pmf, not capture by ref 88 | return [pmf](const Class &cls, Args &&...args) -> NewReturn { 89 | return (cls.*pmf)(std::forward(args)...); 90 | }; 91 | } 92 | 93 | inline size_t wrap(Py_ssize_t i, size_t n) { 94 | if (i < 0) 95 | i += (Py_ssize_t)n; 96 | 97 | if (i < 0 || (size_t)i >= n) 98 | throw nanobind::index_error(); 99 | 100 | return (size_t)i; 101 | } 102 | 103 | } // namespace eudsl 104 | -------------------------------------------------------------------------------- /projects/eudsl-llvmpy/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 | # See https://llvm.org/LICENSE.txt for license information. 3 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 | # Copyright (c) 2024. 5 | 6 | cmake_minimum_required(VERSION 3.29) 7 | set(CMAKE_CXX_STANDARD 17) 8 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 9 | 10 | set(LLVM_SUBPROJECT_TITLE "EUDSLLLVM") 11 | set(EUDSLLLVM_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) 12 | 13 | if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) 14 | message("Building ${LLVM_SUBPROJECT_TITLE} as a standalone project.") 15 | project(${LLVM_SUBPROJECT_TITLE} CXX C) 16 | set(EUDSLLLVM_STANDALONE_BUILD ON) 17 | else() 18 | enable_language(CXX C) 19 | set(EUDSLLLVM_STANDALONE_BUILD OFF) 20 | endif() 21 | 22 | find_package(Python 3.9...<3.14 REQUIRED 23 | REQUIRED COMPONENTS Interpreter Development.Module 24 | OPTIONAL_COMPONENTS Development.SABIModule) 25 | 26 | if(EUDSLLLVM_STANDALONE_BUILD) 27 | find_package(LLVM REQUIRED CONFIG) 28 | 29 | message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") 30 | 31 | set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/bin) 32 | list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") 33 | include(AddLLVM) 34 | endif() 35 | 36 | include_directories(${LLVM_INCLUDE_DIRS}) 37 | link_directories(${LLVM_BUILD_LIBRARY_DIR}) 38 | add_definitions(${LLVM_DEFINITIONS}) 39 | 40 | if(NOT TARGET LLVMSupport) 41 | message(FATAL_ERROR "LLVMSupport not found") 42 | endif() 43 | 44 | execute_process( 45 | COMMAND "${Python_EXECUTABLE}" -m nanobind --cmake_dir 46 | OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE nanobind_DIR) 47 | find_package(nanobind CONFIG REQUIRED) 48 | 49 | set(nanobind_options 50 | -Wno-cast-qual 51 | -Wno-deprecated-literal-operator 52 | -Wno-covered-switch-default 53 | -Wno-nested-anon-types 54 | -Wno-zero-length-array 55 | -Wno-c++98-compat-extra-semi 56 | -Wno-c++20-extensions 57 | $<$:-fexceptions -frtti> 58 | $<$:-fexceptions -frtti> 59 | $<$:/EHsc /GR> 60 | ) 61 | 62 | set(EUDSLLLVM_SRC_DIR "${CMAKE_CURRENT_LIST_DIR}/src") 63 | include_directories(${EUDSLLLVM_BINARY_DIR}) 64 | include_directories(${EUDSLLLVM_SRC_DIR}) 65 | 66 | #set(ENV{PYTHONPATH} "${CMAKE_CURRENT_LIST_DIR}/../eudsl-tblgen/src:$ENV{PYTHONPATH}") 67 | execute_process( 68 | COMMAND "${Python_EXECUTABLE}" "${CMAKE_CURRENT_LIST_DIR}/eudsl-llvmpy-generate.py" 69 | ${LLVM_INCLUDE_DIRS} 70 | "${EUDSLLLVM_BINARY_DIR}/generated" 71 | "${EUDSLLLVM_SRC_DIR}/llvm" 72 | RESULT_VARIABLE _has_err_generate 73 | COMMAND_ECHO STDOUT 74 | ) 75 | if (_has_err_generate AND NOT _has_err_generate EQUAL 0) 76 | message(FATAL_ERROR "couldn't generate sources: ${_has_err_generate}") 77 | endif() 78 | include_directories("${EUDSLLLVM_BINARY_DIR}/generated") 79 | file(GLOB _gen_src CONFIGURE_DEPENDS "${EUDSLLLVM_BINARY_DIR}/generated/*.cpp") 80 | 81 | nanobind_add_module(eudslllvm_ext 82 | NB_STATIC STABLE_ABI 83 | NB_DOMAIN eudslllvm 84 | src/eudslllvm_ext.cpp 85 | ${_gen_src} 86 | ) 87 | set(eudslllvm_ext_libs 88 | LLVMCore 89 | LLVMExecutionEngine 90 | LLVMOrcJIT 91 | LLVMOrcDebugging 92 | LLVMInterpreter 93 | LLVMMCDisassembler 94 | LLVMMCJIT 95 | # AMDGPU 96 | LLVMAMDGPUCodeGen 97 | LLVMAMDGPUAsmParser 98 | LLVMAMDGPUDisassembler 99 | LLVMAMDGPUTargetMCA 100 | LLVMAMDGPUDesc 101 | LLVMAMDGPUInfo 102 | LLVMAMDGPUUtils 103 | # NVPTX 104 | LLVMNVPTXCodeGen 105 | LLVMNVPTXDesc 106 | LLVMNVPTXInfo) 107 | if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64") 108 | list(APPEND eudslllvm_ext_libs 109 | LLVMX86Info 110 | LLVMX86CodeGen 111 | LLVMX86AsmParser 112 | LLVMX86Disassembler) 113 | elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm64|aarch64") 114 | list(APPEND eudslllvm_ext_libs 115 | LLVMAArch64Info 116 | LLVMAArch64Desc 117 | LLVMAArch64CodeGen 118 | LLVMAArch64AsmParser 119 | LLVMAArch64Disassembler) 120 | endif() 121 | 122 | if(APPLE) 123 | list(APPEND eudslllvm_ext_libs ${LLVM_AVAILABLE_LIBS}) 124 | list(REMOVE_ITEM eudslllvm_ext_libs Remarks LTO LLVM LLVMTableGen) 125 | list(REMOVE_DUPLICATES eudslllvm_ext_libs) 126 | target_link_directories(eudslllvm_ext PRIVATE "${LLVM_LIBRARY_DIR}") 127 | list(TRANSFORM eudslllvm_ext_libs PREPEND "-Wl,-hidden-l") 128 | endif() 129 | target_link_libraries(eudslllvm_ext PRIVATE ${eudslllvm_ext_libs}) 130 | 131 | set_target_properties(eudslllvm_ext 132 | PROPERTIES 133 | LIBRARY_OUTPUT_DIRECTORY "${EUDSLLLVM_SRC_DIR}/llvm" 134 | ) 135 | 136 | target_compile_options(eudslllvm_ext PRIVATE ${nanobind_options}) 137 | set(_nanobind_tgt) 138 | if(TARGET nanobind-static) 139 | set(_nanobind_tgt nanobind-static) 140 | elseif(TARGET nanobind-static-abi3) 141 | set(_nanobind_tgt nanobind-static-abi3) 142 | endif() 143 | target_compile_options(${_nanobind_tgt} PRIVATE ${nanobind_options}) 144 | 145 | # note WORKING_DIRECTORY 146 | set(NB_STUBGEN_CMD "${Python_EXECUTABLE}" "-m" "nanobind.stubgen" 147 | --module eudslllvm_ext --recursive --include-private --output-dir .) 148 | set(NB_STUBGEN_OUTPUTS "__init__.pyi") 149 | add_custom_command( 150 | OUTPUT ${NB_STUBGEN_OUTPUTS} 151 | COMMAND ${NB_STUBGEN_CMD} 152 | WORKING_DIRECTORY "${EUDSLLLVM_SRC_DIR}/llvm" 153 | DEPENDS eudslllvm_ext 154 | ) 155 | add_custom_target(eudslllvm_ext_stub ALL DEPENDS ${NB_STUBGEN_OUTPUTS}) 156 | 157 | install(TARGETS eudslllvm_ext LIBRARY DESTINATION llvm) 158 | install( 159 | DIRECTORY "${EUDSLLLVM_SRC_DIR}/llvm" 160 | DESTINATION ${CMAKE_INSTALL_PREFIX} 161 | PATTERN "*.pyc" EXCLUDE 162 | PATTERN "*.so" EXCLUDE 163 | PATTERN "*.a" EXCLUDE 164 | PATTERN "__pycache__" EXCLUDE 165 | PATTERN ".gitignore" EXCLUDE 166 | ) 167 | -------------------------------------------------------------------------------- /projects/eudsl-llvmpy/pyproject.toml: -------------------------------------------------------------------------------- 1 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 | # See https://llvm.org/LICENSE.txt for license information. 3 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 | # Copyright (c) 2024. 5 | 6 | [project] 7 | name = "eudsl-llvmpy" 8 | version = "0.0.1" 9 | requires-python = ">=3.10" 10 | 11 | [project.urls] 12 | Homepage = "https://github.com/llvm/eudsl" 13 | 14 | [build-system] 15 | requires = [ 16 | "eudsl-tblgen", 17 | "litgen @ git+https://github.com/pthom/litgen@f5d154c6f7679e755baa1047563d7c340309bc00", 18 | "nanobind==2.4.0", 19 | "ninja", 20 | "scikit-build-core==0.10.7", 21 | "typing_extensions==4.12.2", 22 | ] 23 | build-backend = "scikit_build_core.build" 24 | 25 | [tool.scikit-build] 26 | minimum-version = "0.10" 27 | build-dir = "build/{wheel_tag}" 28 | cmake.source-dir = "." 29 | wheel.packages = ["src/llvm"] 30 | wheel.py-api = "cp312" 31 | editable.mode = "inplace" 32 | editable.verbose = true 33 | editable.rebuild = false 34 | 35 | [tool.scikit-build.cmake.define] 36 | CMAKE_PREFIX_PATH = { env = "CMAKE_PREFIX_PATH", default = "" } 37 | CMAKE_C_FLAGS = { env = "CMAKE_C_FLAGS", default = "" } 38 | CMAKE_CXX_FLAGS = { env = "CMAKE_CXX_FLAGS", default = "" } 39 | CMAKE_C_COMPILER_LAUNCHER = { env = "CMAKE_C_COMPILER_LAUNCHER", default = "" } 40 | CMAKE_CXX_COMPILER_LAUNCHER = { env = "CMAKE_CXX_COMPILER_LAUNCHER", default = "" } 41 | CMAKE_EXE_LINKER_FLAGS_INIT = { env = "CMAKE_EXE_LINKER_FLAGS_INIT", default = "" } 42 | CMAKE_SHARED_LINKER_FLAGS_INIT = { env = "CMAKE_SHARED_LINKER_FLAGS_INIT", default = "" } 43 | CMAKE_MODULE_LINKER_FLAGS_INIT = { env = "CMAKE_MODULE_LINKER_FLAGS_INIT", default = "" } 44 | CMAKE_OSX_DEPLOYMENT_TARGET = { env = "CMAKE_OSX_DEPLOYMENT_TARGET", default = "11.0" } 45 | CMAKE_C_VISIBILITY_PRESET = "hidden" 46 | CMAKE_CXX_VISIBILITY_PRESET = "hidden" 47 | CMAKE_VISIBILITY_INLINES_HIDDEN = "ON" 48 | CMAKE_INSTALL_DO_STRIP = "ON" 49 | CMAKE_VERBOSE_MAKEFILE = "ON" 50 | LLVM_DIR = { env = "LLVM_DIR", default = "EMPTY" } 51 | LLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN = "ON" 52 | 53 | [tool.cibuildwheel] 54 | build-verbosity = 1 55 | skip = ["*-manylinux_i686", "*-musllinux*", "pp*", "*-win32"] 56 | archs = ["auto64"] 57 | manylinux-x86_64-image = "manylinux_2_28" 58 | manylinux-aarch64-image = "quay.io/pypa/manylinux_2_34_aarch64" 59 | environment-pass = [ 60 | "CMAKE_PREFIX_PATH", 61 | "CMAKE_C_FLAGS", 62 | "CMAKE_CXX_FLAGS", 63 | "CMAKE_C_COMPILER_LAUNCHER", 64 | "CMAKE_CXX_COMPILER_LAUNCHER", 65 | "CMAKE_GENERATOR", 66 | "CC", 67 | "CXX", 68 | "LLVM_DIR", 69 | # ccache 70 | "CCACHE_DIR", 71 | "CCACHE_MAXSIZE=700M", 72 | "CCACHE_SLOPPINESS", 73 | "CCACHE_CPP2", 74 | "CCACHE_UMASK", 75 | "CCACHE_NOHASHDIR", 76 | "PIP_FIND_LINKS", 77 | ] 78 | # uncomment to make sure ccache is working inside containers 79 | test-command = "ccache -sv" 80 | 81 | [tool.cibuildwheel.linux] 82 | before-all = [ 83 | "yum install -y clang libarchive-devel antlr-tool libxml2-devel libxslt-devel libcurl-devel", 84 | # ccache 85 | "echo $(if [ \"$(arch)\" == \"x86_64\" ]; then curl -sLO https://github.com/ccache/ccache/releases/download/v4.10.2/ccache-4.10.2-linux-x86_64.tar.xz && tar -xf ccache-4.10.2-linux-x86_64.tar.xz && pushd ccache-4.10.2-linux-x86_64 && make install && popd; fi)", 86 | "echo $(if [ \"$(arch)\" == \"aarch64\" ]; then dnf install -y ccache; fi)", 87 | "ccache -z" 88 | ] 89 | # synchronize TZ with host so ccache files have correct timestamp 90 | container-engine = { name = "docker", create-args = ["-v", "/etc/timezone:/etc/timezone:ro", "-v", "/etc/localtime:/etc/localtime:ro"] } 91 | 92 | [tool.cibuildwheel.macos] 93 | before-build = [ 94 | "ccache -z", 95 | ] 96 | -------------------------------------------------------------------------------- /projects/eudsl-llvmpy/src/eudslllvm_ext.cpp: -------------------------------------------------------------------------------- 1 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 | // See https://llvm.org/LICENSE.txt for license information. 3 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 | // Copyright (c) 2025. 5 | 6 | #include "pp/Core.h" 7 | #include "pp/IRReader.h" 8 | #include "pp/TargetMachine.h" 9 | 10 | #include 11 | #include 12 | 13 | namespace nb = nanobind; 14 | 15 | NB_MODULE(eudslllvm_ext, m) { 16 | nb::set_leak_warnings(false); 17 | 18 | extern void populate_LLJIT(nb::module_ & m); 19 | populate_LLJIT(m); 20 | extern void populate_BitReader(nb::module_ & m); 21 | populate_BitReader(m); 22 | extern void populate_ErrorHandling(nb::module_ & m); 23 | populate_ErrorHandling(m); 24 | extern void populate_BitWriter(nb::module_ & m); 25 | populate_BitWriter(m); 26 | extern void populate_DisassemblerTypes(nb::module_ & m); 27 | populate_DisassemblerTypes(m); 28 | extern void populate_Orc(nb::module_ & m); 29 | populate_Orc(m); 30 | extern void populate_IRReader(nb::module_ & m); 31 | populate_IRReader(m); 32 | extern void populate_PassBuilder(nb::module_ & m); 33 | populate_PassBuilder(m); 34 | extern void populate_Types(nb::module_ & m); 35 | populate_Types(m); 36 | extern void populate_DebugInfo(nb::module_ & m); 37 | populate_DebugInfo(m); 38 | extern void populate_ExecutionEngine(nb::module_ & m); 39 | populate_ExecutionEngine(m); 40 | extern void populate_Object(nb::module_ & m); 41 | populate_Object(m); 42 | extern void populate_Comdat(nb::module_ & m); 43 | populate_Comdat(m); 44 | extern void populate_Analysis(nb::module_ & m); 45 | populate_Analysis(m); 46 | extern void populate_Support(nb::module_ & m); 47 | populate_Support(m); 48 | extern void populate_blake3(nb::module_ & m); 49 | populate_blake3(m); 50 | extern void populate_LLJITUtils(nb::module_ & m); 51 | populate_LLJITUtils(m); 52 | extern void populate_Linker(nb::module_ & m); 53 | populate_Linker(m); 54 | extern void populate_Remarks(nb::module_ & m); 55 | populate_Remarks(m); 56 | extern void populate_TargetMachine(nb::module_ & m); 57 | populate_TargetMachine(m); 58 | extern void populate_Error(nb::module_ & m); 59 | populate_Error(m); 60 | extern void populate_OrcEE(nb::module_ & m); 61 | populate_OrcEE(m); 62 | extern void populate_Core(nb::module_ & m); 63 | populate_Core(m); 64 | extern void populate_Disassembler(nb::module_ & m); 65 | populate_Disassembler(m); 66 | extern void populate_Target(nb::module_ & m); 67 | populate_Target(m); 68 | 69 | m.def("parse_ir_in_context", 70 | [](LLVMContextRef ContextRef, LLVMMemoryBufferRef MemBuf, 71 | LLVMModuleRef *OutM) { 72 | char *OutMessage; 73 | return LLVMParseIRInContext(ContextRef, MemBuf, OutM, &OutMessage); 74 | }); 75 | 76 | m.def( 77 | "function_type", 78 | [](LLVMTypeRef ReturnType, std::vector ParamTypes, 79 | LLVMBool IsVarArg) { 80 | return LLVMFunctionType(ReturnType, ParamTypes.data(), 81 | ParamTypes.size(), IsVarArg); 82 | }, 83 | nb::arg("return_type"), nb::arg("param_types"), nb::arg("is_var_arg"), 84 | " * Obtain a function type consisting of a specified signature.\n *\n " 85 | "* The function is defined as a tuple of a return Type, a list of\n * " 86 | "parameter types, and whether the function is variadic."); 87 | 88 | m.def( 89 | "get_param_types", 90 | [](LLVMTypeRef FunctionTy, std::vector Dest) { 91 | LLVMGetParamTypes(FunctionTy, Dest.data()); 92 | }, 93 | nb::arg("function_ty"), nb::arg("dest"), 94 | " * Obtain the types of a function's parameters.\n *\n * The Dest " 95 | "parameter should point to a pre-allocated array of\n * LLVMTypeRef at " 96 | "least LLVMCountParamTypes() large. On return, the\n * first " 97 | "LLVMCountParamTypes() entries in the array will be populated\n * with " 98 | "LLVMTypeRef instances.\n *\n * @param FunctionTy The function type to " 99 | "operate on.\n * @param Dest Memory address of an array to be filled " 100 | "with result."); 101 | 102 | m.def( 103 | "struct_type_in_context", 104 | [](LLVMContextRef C, std::vector ElementTypes, 105 | LLVMBool Packed) { 106 | return LLVMStructTypeInContext(C, ElementTypes.data(), 107 | ElementTypes.size(), Packed); 108 | }, 109 | nb::arg("c"), nb::arg("element_types"), nb::arg("packed"), 110 | " * Create a new structure type in a context.\n *\n * A structure is " 111 | "specified by a list of inner elements/types and\n * whether these can " 112 | "be packed together.\n *\n * @see llvm::StructType::create()"); 113 | 114 | m.def( 115 | "struct_type", 116 | [](std::vector ElementTypes, LLVMBool Packed) { 117 | return LLVMStructType(ElementTypes.data(), ElementTypes.size(), Packed); 118 | }, 119 | nb::arg("element_types"), nb::arg("packed"), 120 | " * Create a new structure type in the global context.\n *\n * @see " 121 | "llvm::StructType::create()"); 122 | 123 | m.def( 124 | "struct_set_body", 125 | [](LLVMTypeRef StructTy, std::vector ElementTypes, 126 | LLVMBool Packed) { 127 | LLVMStructSetBody(StructTy, ElementTypes.data(), ElementTypes.size(), 128 | Packed); 129 | }, 130 | nb::arg("struct_ty"), nb::arg("element_types"), nb::arg("packed"), 131 | " * Set the contents of a structure type.\n *\n * @see " 132 | "llvm::StructType::setBody()"); 133 | 134 | m.def( 135 | "const_gep2", 136 | [](LLVMTypeRef Ty, LLVMValueRef ConstantVal, 137 | std::vector ConstantIndices) { 138 | return LLVMConstGEP2(Ty, ConstantVal, ConstantIndices.data(), 139 | ConstantIndices.size()); 140 | }, 141 | nb::arg("ty"), nb::arg("constant_val"), nb::arg("constant_indices")); 142 | 143 | m.def( 144 | "const_in_bounds_gep2", 145 | [](LLVMTypeRef Ty, LLVMValueRef ConstantVal, 146 | std::vector ConstantIndices) { 147 | return LLVMConstInBoundsGEP2(Ty, ConstantVal, ConstantIndices.data(), 148 | ConstantIndices.size()); 149 | }, 150 | nb::arg("ty"), nb::arg("constant_val"), nb::arg("constant_indices")); 151 | 152 | m.def( 153 | "const_gep_with_no_wrap_flags", 154 | [](LLVMTypeRef Ty, LLVMValueRef ConstantVal, 155 | std::vector ConstantIndices, 156 | LLVMGEPNoWrapFlags NoWrapFlags) { 157 | return LLVMConstGEPWithNoWrapFlags(Ty, ConstantVal, 158 | ConstantIndices.data(), 159 | ConstantIndices.size(), NoWrapFlags); 160 | }, 161 | nb::arg("ty"), nb::arg("constant_val"), nb::arg("constant_indices"), 162 | nb::arg("no_wrap_flags")); 163 | 164 | m.def( 165 | "get_intrinsic_declaration", 166 | [](LLVMModuleRef Mod, unsigned ID, std::vector ParamTypes) { 167 | return LLVMGetIntrinsicDeclaration(Mod, ID, ParamTypes.data(), 168 | ParamTypes.size()); 169 | }, 170 | nb::arg("mod"), nb::arg("id"), nb::arg("param_types"), 171 | " * Get or insert the declaration of an intrinsic. For overloaded " 172 | "intrinsics,\n * parameter types must be provided to uniquely identify " 173 | "an overload.\n *\n * @see llvm::Intrinsic::getOrInsertDeclaration()"); 174 | 175 | m.def( 176 | "intrinsic_get_type", 177 | [](LLVMContextRef Ctx, unsigned ID, std::vector ParamTypes) { 178 | return LLVMIntrinsicGetType(Ctx, ID, ParamTypes.data(), 179 | ParamTypes.size()); 180 | }, 181 | nb::arg("ctx"), nb::arg("id"), nb::arg("param_types"), 182 | " * Retrieves the type of an intrinsic. For overloaded intrinsics, " 183 | "parameter\n * types must be provided to uniquely identify an " 184 | "overload.\n *\n * @see llvm::Intrinsic::getType()"); 185 | 186 | m.def( 187 | "intrinsic_copy_overloaded_name", 188 | [](unsigned ID, std::vector ParamTypes, size_t *NameLength) { 189 | return LLVMIntrinsicCopyOverloadedName(ID, ParamTypes.data(), 190 | ParamTypes.size(), NameLength); 191 | }, 192 | nb::arg("id"), nb::arg("param_types"), nb::arg("name_length"), 193 | "Deprecated: Use LLVMIntrinsicCopyOverloadedName2 instead."); 194 | 195 | m.def( 196 | "intrinsic_copy_overloaded_name2", 197 | [](LLVMModuleRef Mod, unsigned ID, std::vector ParamTypes, 198 | size_t *NameLength) { 199 | return LLVMIntrinsicCopyOverloadedName2(Mod, ID, ParamTypes.data(), 200 | ParamTypes.size(), NameLength); 201 | }, 202 | nb::arg("mod"), nb::arg("id"), nb::arg("param_types"), 203 | nb::arg("name_length"), 204 | " * Copies the name of an overloaded intrinsic identified by a given " 205 | "list of\n * parameter types.\n *\n * Unlike LLVMIntrinsicGetName, the " 206 | "caller is responsible for freeing the\n * returned string.\n *\n * " 207 | "This version also supports unnamed types.\n *\n * @see " 208 | "llvm::Intrinsic::getName()"); 209 | 210 | m.def( 211 | "build_call2", 212 | [](LLVMBuilderRef builder, LLVMTypeRef fn_type, LLVMValueRef Fn, 213 | std::vector Args, const char *Name) { 214 | return LLVMBuildCall2(builder, fn_type, Fn, Args.data(), Args.size(), 215 | Name); 216 | }, 217 | nb::arg("param_0"), nb::arg("fn_type"), nb::arg("fn"), nb::arg("args"), 218 | nb::arg("name")); 219 | 220 | m.def( 221 | "get_target_from_triple", 222 | [](const char *triple) { 223 | LLVMTargetRef T; 224 | char *Error; 225 | if (LLVMGetTargetFromTriple(triple, &T, &Error)) 226 | throw std::runtime_error(Error); 227 | return T; 228 | }, 229 | nb::arg("triple")); 230 | 231 | m.def( 232 | "get_attributes_at_index", 233 | [](LLVMValueRef F, LLVMAttributeIndex Idx) { 234 | std::vector Attrs; 235 | LLVMGetAttributesAtIndex(F, Idx, Attrs.data()); 236 | return Attrs; 237 | }, 238 | nb::arg("f"), nb::arg("idx")); 239 | } 240 | -------------------------------------------------------------------------------- /projects/eudsl-llvmpy/src/llvm/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyi 2 | amdgcn.py -------------------------------------------------------------------------------- /projects/eudsl-llvmpy/src/llvm/__init__.py: -------------------------------------------------------------------------------- 1 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 | # See https://llvm.org/LICENSE.txt for license information. 3 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 | # Copyright (c) 2025. 5 | 6 | from .eudslllvm_ext import * 7 | -------------------------------------------------------------------------------- /projects/eudsl-llvmpy/src/llvm/context.py: -------------------------------------------------------------------------------- 1 | import threading 2 | from contextlib import contextmanager 3 | from dataclasses import dataclass 4 | from typing import Optional 5 | 6 | from . import ( 7 | ContextRef, 8 | ModuleRef, 9 | BuilderRef, 10 | print_module_to_string, 11 | context_create, 12 | module_create_with_name_in_context, 13 | create_memory_buffer_with_memory_range, 14 | parse_ir_in_context, 15 | create_builder_in_context, 16 | dispose_builder, 17 | ) 18 | 19 | 20 | @dataclass 21 | class Context: 22 | context: ContextRef 23 | module: ModuleRef 24 | builder: BuilderRef 25 | 26 | def __str__(self): 27 | return print_module_to_string(self.module) 28 | 29 | 30 | __tls = threading.local() 31 | 32 | 33 | def current_context() -> Context: 34 | return __tls.current_context 35 | 36 | 37 | def set_current_context(ctx: Context): 38 | __tls.current_context = ctx 39 | 40 | 41 | def reset_current_context(): 42 | ctx = current_context() 43 | set_current_context(None) 44 | dispose_builder(ctx.builder) 45 | 46 | 47 | @contextmanager 48 | def context( 49 | mod_name: Optional[str] = None, src: Optional[str] = None, buffer_name="" 50 | ): 51 | ctx = context_create() 52 | if mod_name is None: 53 | mod_name = buffer_name 54 | mod = module_create_with_name_in_context(mod_name, ctx) 55 | if src is not None: 56 | buf = create_memory_buffer_with_memory_range(src, len(src), buffer_name, True) 57 | parse_ir_in_context(ctx, buf, mod) 58 | builder = create_builder_in_context(ctx) 59 | _ctx = Context(ctx, mod, builder) 60 | set_current_context(_ctx) 61 | yield _ctx 62 | reset_current_context() 63 | -------------------------------------------------------------------------------- /projects/eudsl-llvmpy/src/llvm/function.py: -------------------------------------------------------------------------------- 1 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 | # See https://llvm.org/LICENSE.txt for license information. 3 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 | # Copyright (c) 2025. 5 | 6 | import inspect 7 | import sys 8 | from functools import update_wrapper, wraps 9 | from typing import TypeVar 10 | 11 | from . import ( 12 | add_function, 13 | append_basic_block, 14 | position_builder_at_end, 15 | TypeRef, 16 | type_of, 17 | get_param, 18 | types_, 19 | ) 20 | from .context import current_context 21 | 22 | 23 | def prep_func_types(sig, return_type): 24 | assert not ( 25 | not sig.return_annotation is inspect.Signature.empty and return_type 26 | ), f"func can use return annotation or explicit return_type but not both" 27 | return_type = ( 28 | sig.return_annotation 29 | if not sig.return_annotation is inspect.Signature.empty 30 | else return_type 31 | ) 32 | assert isinstance(return_type, (str, TypeRef, TypeVar)) or inspect.isfunction( 33 | return_type 34 | ), f"return type must be llvm type or string or TypeVar or lambda; {return_type=}" 35 | 36 | input_types = [ 37 | p.annotation 38 | for p in sig.parameters.values() 39 | if not p.annotation is inspect.Signature.empty 40 | ] 41 | assert all( 42 | isinstance(r, (str, TypeRef, TypeVar)) or inspect.isfunction(r) 43 | for r in input_types 44 | ), f"all input types must be mlir types or strings or TypeVars or lambdas {input_types=}" 45 | return input_types, return_type 46 | 47 | 48 | class FuncOp: 49 | def __init__(self, body_builder, *, return_type=None, entry_bb_name="entry"): 50 | assert inspect.isfunction(body_builder), body_builder 51 | 52 | self.body_builder = body_builder 53 | self.func_name = self.body_builder.__name__ 54 | self.entry_bb_name = entry_bb_name 55 | self._emitted = False 56 | 57 | sig = inspect.signature(self.body_builder) 58 | self.input_types, self.return_type = prep_func_types(sig, return_type) 59 | 60 | if self._is_decl(): 61 | assert len(self.input_types) == len( 62 | sig.parameters 63 | ), f"func decl needs all input types annotated" 64 | self.emit() 65 | 66 | def _is_decl(self): 67 | # magic constant found from looking at the code for an empty fn 68 | if sys.version_info.minor == 13: 69 | return self.body_builder.__code__.co_code == b"\x95\x00g\x00" 70 | elif sys.version_info.minor == 12: 71 | return self.body_builder.__code__.co_code == b"\x97\x00y\x00" 72 | elif sys.version_info.minor == 11: 73 | return self.body_builder.__code__.co_code == b"\x97\x00d\x00S\x00" 74 | elif sys.version_info.minor in {8, 9, 10}: 75 | return self.body_builder.__code__.co_code == b"d\x00S\x00" 76 | else: 77 | raise NotImplementedError(f"{sys.version_info.minor} not supported.") 78 | 79 | def __str__(self): 80 | return str(f"{self.__class__} {self.__dict__}") 81 | 82 | def emit(self, *call_args): 83 | if self._emitted: 84 | return 85 | ctx = current_context() 86 | if len(call_args) == 0: 87 | input_types = self.input_types[:] 88 | locals = {"T": types_} 89 | for i, v in enumerate(input_types): 90 | if isinstance(v, TypeVar): 91 | v = v.__name__ 92 | if isinstance(v, str): 93 | input_types[i] = eval(v, self.body_builder.__globals__, locals) 94 | elif inspect.isfunction(v): 95 | input_types[i] = v() 96 | else: 97 | raise ValueError(f"unknown input_type {v=}") 98 | else: 99 | input_types = [type_of(a) for a in call_args] 100 | 101 | return_type = self.return_type 102 | if inspect.isfunction(return_type): 103 | return_type = return_type() 104 | 105 | function_ty = types_.function(return_type, input_types) 106 | function = add_function(ctx.module, self.func_name, function_ty) 107 | if self._is_decl(): 108 | return 109 | 110 | entry_bb = append_basic_block(function, self.entry_bb_name) 111 | position_builder_at_end(ctx.builder, entry_bb) 112 | 113 | params = [get_param(function, i) for i in range(len(input_types))] 114 | self.body_builder(*params) 115 | self._emitted = True 116 | 117 | 118 | def make_maybe_no_args_decorator(decorator): 119 | """ 120 | a decorator decorator, allowing the decorator to be used as: 121 | @decorator(with, arguments, and=kwargs) 122 | or 123 | @decorator 124 | """ 125 | 126 | @wraps(decorator) 127 | def new_dec(*args, **kwargs): 128 | if len(args) == 1 and len(kwargs) == 0 and callable(args[0]): 129 | # actual decorated function 130 | return decorator(args[0]) 131 | else: 132 | # decorator arguments 133 | return lambda realf: decorator(realf, *args, **kwargs) 134 | 135 | return new_dec 136 | 137 | 138 | @make_maybe_no_args_decorator 139 | def function(f, *, emit=False, entry_bb_name="entry") -> FuncOp: 140 | func_ = FuncOp(body_builder=f, entry_bb_name=entry_bb_name) 141 | func_ = update_wrapper(func_, f) 142 | if emit: 143 | func_.emit() 144 | return func_ 145 | -------------------------------------------------------------------------------- /projects/eudsl-llvmpy/src/llvm/types_.py: -------------------------------------------------------------------------------- 1 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 | # See https://llvm.org/LICENSE.txt for license information. 3 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 | # Copyright (c) 2025. 5 | from typing import Sequence 6 | 7 | from . import ( 8 | array_type2, 9 | TypeRef, 10 | b_float_type_in_context, 11 | double_type_in_context, 12 | float_type_in_context, 13 | fp128_type_in_context, 14 | function_type, 15 | half_type_in_context, 16 | int_type_in_context, 17 | int1_type_in_context, 18 | int8_type_in_context, 19 | int16_type_in_context, 20 | int32_type_in_context, 21 | int64_type_in_context, 22 | int_ptr_type_in_context, 23 | int128_type_in_context, 24 | TargetDataRef, 25 | label_type_in_context, 26 | metadata_type_in_context, 27 | pointer_type_in_context, 28 | ppcfp128_type_in_context, 29 | scalable_vector_type, 30 | struct_type_in_context, 31 | token_type_in_context, 32 | vector_type, 33 | void_type_in_context, 34 | x86_amx_type_in_context, 35 | x86_fp80_type_in_context, 36 | ) 37 | from .context import current_context 38 | 39 | 40 | def array(element_type: TypeRef, element_count: int): 41 | return array_type2(element_type, element_count) 42 | 43 | 44 | def bfloat(): 45 | return b_float_type_in_context(current_context().context) 46 | 47 | 48 | def double(): 49 | return double_type_in_context(current_context().context) 50 | 51 | 52 | def float(): 53 | return float_type_in_context(current_context().context) 54 | 55 | 56 | def fp128(): 57 | return fp128_type_in_context(current_context().context) 58 | 59 | 60 | def function( 61 | return_type: TypeRef, 62 | param_types: Sequence[TypeRef], 63 | is_var_arg: bool = False, 64 | ): 65 | return function_type(return_type, param_types, is_var_arg) 66 | 67 | 68 | def half(): 69 | return half_type_in_context(current_context().context) 70 | 71 | 72 | def int128(): 73 | return int128_type_in_context(current_context().context) 74 | 75 | 76 | def int16(): 77 | return int16_type_in_context(current_context().context) 78 | 79 | 80 | def int1(): 81 | return int1_type_in_context(current_context().context) 82 | 83 | 84 | def int32(): 85 | return int32_type_in_context(current_context().context) 86 | 87 | 88 | def int64(): 89 | return int64_type_in_context(current_context().context) 90 | 91 | 92 | def int8(): 93 | return int8_type_in_context(current_context().context) 94 | 95 | 96 | def int_ptr(td: TargetDataRef): 97 | return int_ptr_type_in_context(current_context().context, td) 98 | 99 | 100 | def int(num_bits: int): 101 | return int_type_in_context(current_context().context, num_bits) 102 | 103 | 104 | def label(): 105 | return label_type_in_context(current_context().context) 106 | 107 | 108 | def metadata(): 109 | return metadata_type_in_context(current_context().context) 110 | 111 | 112 | def pointer(address_space: int): 113 | return pointer_type_in_context(current_context().context, address_space) 114 | 115 | 116 | def ppcfp128_type(): 117 | return ppcfp128_type_in_context(current_context().context) 118 | 119 | 120 | def scalable_vector(element_type: TypeRef, element_count: int): 121 | return scalable_vector_type(element_type, element_count) 122 | 123 | 124 | def struct(element_types: Sequence[TypeRef], packed: bool): 125 | return struct_type_in_context( 126 | current_context().context, element_types, packed 127 | ) 128 | 129 | 130 | def token(): 131 | return token_type_in_context(current_context().context) 132 | 133 | 134 | def vector(element_type: TypeRef, element_count: int): 135 | return vector_type(element_type, element_count) 136 | 137 | 138 | def void(): 139 | return void_type_in_context(current_context().context) 140 | 141 | 142 | def x86_amx(): 143 | return x86_amx_type_in_context(current_context().context) 144 | 145 | 146 | def x86_fp80(): 147 | return x86_fp80_type_in_context(current_context().context) 148 | -------------------------------------------------------------------------------- /projects/eudsl-llvmpy/src/llvm/util.py: -------------------------------------------------------------------------------- 1 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 | # See https://llvm.org/LICENSE.txt for license information. 3 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 | # Copyright (c) 2025. 5 | 6 | from . import ( 7 | get_intrinsic_declaration, 8 | lookup_intrinsic_id, 9 | type_of, 10 | build_call2, 11 | intrinsic_is_overloaded, 12 | intrinsic_get_type, 13 | ) 14 | from .context import current_context 15 | 16 | 17 | def call_intrinsic(*args, **kwargs): 18 | intr_id = kwargs.pop("intr_id", None) 19 | if intr_id is None: 20 | intr_name = kwargs.pop("intr_name") 21 | intr_id = lookup_intrinsic_id(intr_name, len(intr_name)) 22 | is_overloaded = kwargs.pop("is_overloaded", None) 23 | if is_overloaded is None: 24 | is_overloaded = intrinsic_is_overloaded(intr_id) 25 | types = [type_of(a) for a in args] 26 | if is_overloaded: 27 | intr_decl_fn = get_intrinsic_declaration( 28 | current_context().module, intr_id, types 29 | ) 30 | intr_decl_fn_ty = intrinsic_get_type(current_context().context, intr_id, types) 31 | else: 32 | intr_decl_fn = get_intrinsic_declaration(current_context().module, intr_id, []) 33 | intr_decl_fn_ty = intrinsic_get_type(current_context().context, intr_id, []) 34 | 35 | name = kwargs.pop("name", "") 36 | return build_call2( 37 | current_context().builder, 38 | intr_decl_fn_ty, 39 | intr_decl_fn, 40 | args, 41 | name, 42 | ) 43 | -------------------------------------------------------------------------------- /projects/eudsl-llvmpy/src/types.h: -------------------------------------------------------------------------------- 1 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 | // See https://llvm.org/LICENSE.txt for license information. 3 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 | // Copyright (c) 2025. 5 | 6 | #pragma once 7 | 8 | #include "pp/Core.h" 9 | #include "pp/Types.h" 10 | 11 | struct LLVMModuleFlagEntry { 12 | LLVMModuleFlagBehavior Behavior; 13 | const char *Key; 14 | size_t KeyLen; 15 | LLVMMetadataRef Metadata; 16 | }; 17 | 18 | struct LLVMValueMetadataEntry { 19 | unsigned Kind; 20 | LLVMMetadataRef Metadata; 21 | }; 22 | -------------------------------------------------------------------------------- /projects/eudsl-llvmpy/tests/test_bindings.py: -------------------------------------------------------------------------------- 1 | # Part of the Project, under the Apache License v2.0 with Exceptions. 2 | # See https:#llvm.org/LICENSE.txt for license information. 3 | # SPDX-License-Identifier: Apache-2.0 WITH -exception 4 | # Copyright (c) 2024. 5 | from textwrap import dedent 6 | 7 | from llvm import types_ as T, ModuleRef, print_module_to_string 8 | from llvm.context import context 9 | from llvm.function import function 10 | from llvm.instructions import add, ret 11 | import llvm.amdgcn 12 | 13 | 14 | def test_symbol_collision(): 15 | # noinspection PyUnresolvedReferences 16 | import eudsl_tblgen 17 | 18 | 19 | def test_smoke(): 20 | src = dedent( 21 | """ 22 | declare i32 @foo() 23 | declare i32 @bar() 24 | define i32 @entry(i32 %argc) { 25 | entry: 26 | %and = and i32 %argc, 1 27 | %tobool = icmp eq i32 %and, 0 28 | br i1 %tobool, label %if.end, label %if.then 29 | if.then: 30 | %call = tail call i32 @foo() 31 | br label %return 32 | if.end: 33 | %call1 = tail call i32 @bar() 34 | br label %return 35 | return: 36 | %retval.0 = phi i32 [ %call, %if.then ], [ %call1, %if.end ] 37 | ret i32 %retval.0 38 | } 39 | """ 40 | ) 41 | with context(src=src, buffer_name="test_smoke") as ctx: 42 | print(ctx) 43 | 44 | 45 | def test_builder(): 46 | with context(mod_name="test_builder") as ctx: 47 | 48 | @function(emit=True) 49 | def sum(a: T.int32, b: T.int32, c: T.float) -> T.int32: 50 | e = llvm.amdgcn.cvt_pk_i16(a, b) 51 | f = llvm.amdgcn.frexp_mant(c) 52 | result = add(a, b) 53 | ret(result) 54 | 55 | mod_str = str(ctx) 56 | 57 | correct = dedent( 58 | """\ 59 | ; ModuleID = 'test_builder' 60 | source_filename = "test_builder" 61 | 62 | define i32 @sum(i32 %0, i32 %1, float %2) { 63 | entry: 64 | %3 = call <2 x i16> @llvm.amdgcn.cvt.pk.i16(i32 %0, i32 %1) 65 | %4 = call float @llvm.amdgcn.frexp.mant.f32(float %2) 66 | %5 = add i32 %0, %1 67 | ret i32 %5 68 | } 69 | 70 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 71 | declare <2 x i16> @llvm.amdgcn.cvt.pk.i16(i32, i32) #0 72 | 73 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 74 | declare float @llvm.amdgcn.frexp.mant.f32(float) #0 75 | 76 | attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } 77 | """ 78 | ) 79 | 80 | assert correct == mod_str 81 | 82 | 83 | def test_from_capsule(): 84 | src = dedent( 85 | """ 86 | ; ModuleID = 'test_smoke' 87 | source_filename = "test_smoke" 88 | 89 | declare i32 @foo() 90 | 91 | declare i32 @bar() 92 | 93 | define i32 @entry(i32 %argc) { 94 | entry: 95 | %and = and i32 %argc, 1 96 | %tobool = icmp eq i32 %and, 0 97 | br i1 %tobool, label %if.end, label %if.then 98 | 99 | if.then: ; preds = %entry 100 | %call = tail call i32 @foo() 101 | br label %return 102 | 103 | if.end: ; preds = %entry 104 | %call1 = tail call i32 @bar() 105 | br label %return 106 | 107 | return: ; preds = %if.end, %if.then 108 | %retval.0 = phi i32 [ %call, %if.then ], [ %call1, %if.end ] 109 | ret i32 %retval.0 110 | } 111 | """ 112 | ) 113 | with context(src=src, buffer_name="test_smoke") as ctx: 114 | copied_mod = ModuleRef.from_capsule(ctx.module.ptr) 115 | mod_str = print_module_to_string(copied_mod) 116 | assert src.strip() == mod_str.strip() 117 | 118 | 119 | if __name__ == "__main__": 120 | test_smoke() 121 | test_builder() 122 | test_symbol_collision() 123 | test_from_capsule() 124 | -------------------------------------------------------------------------------- /projects/eudsl-nbgen/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.29) 2 | set(CMAKE_CXX_STANDARD 17) 3 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 4 | 5 | set(LLVM_SUBPROJECT_TITLE "EUDSL_NBGEN") 6 | set(EUDSL_NBGEN_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) 7 | 8 | if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) 9 | message("Building ${LLVM_SUBPROJECT_TITLE} as a standalone project.") 10 | project(${LLVM_SUBPROJECT_TITLE} CXX C) 11 | set(EUDSL_NBGEN_STANDALONE_BUILD ON) 12 | else() 13 | enable_language(CXX C) 14 | set(EUDSL_NBGEN_STANDALONE_BUILD OFF) 15 | endif() 16 | 17 | if(EUDSL_NBGEN_STANDALONE_BUILD) 18 | find_package(LLVM REQUIRED CONFIG) 19 | find_package(Clang REQUIRED CONFIG PATHS "${LLVM_BINARY_DIR}" NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH) 20 | 21 | message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") 22 | message(STATUS "Using ClangConfig.cmake in: ${Clang_DIR}") 23 | 24 | set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/bin) 25 | set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/lib) 26 | 27 | list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") 28 | list(APPEND CMAKE_MODULE_PATH "${CLANG_CMAKE_DIR}") 29 | 30 | include(TableGen) 31 | include(AddLLVM) 32 | include(AddClang) 33 | include(HandleLLVMOptions) 34 | endif() 35 | 36 | include_directories(${LLVM_INCLUDE_DIRS}) 37 | include_directories(${CLANG_INCLUDE_DIRS}) 38 | link_directories(${LLVM_BUILD_LIBRARY_DIR}) 39 | add_definitions(${LLVM_DEFINITIONS}) 40 | 41 | if(NOT TARGET LLVMSupport) 42 | message(FATAL_ERROR "LLVMSupport not found") 43 | endif() 44 | 45 | # this will set the rpath of the exe to be `../lib`, where is where we deposit libLLVM.so below 46 | add_llvm_executable(eudsl-nbgen src/eudsl-nbgen.cpp) 47 | target_link_libraries(eudsl-nbgen 48 | PRIVATE 49 | clangAST 50 | clangBasic 51 | clangFrontend 52 | clangSerialization 53 | clangTooling 54 | ) 55 | 56 | string(TOLOWER ${LLVM_SUBPROJECT_TITLE} EUDSL_NBGEN_INSTALL_DATADIR) 57 | if (NOT "$ENV{PIP_BUILD_TRACKER}" STREQUAL "") 58 | # pip install 59 | # actually installs to venv/bin 60 | # https://github.com/scikit-build/scikit-build-core/blob/a887a9b6c057b4ce9d3cfd53ae24e73caf1395a2/docs/build.md?plain=1#L139-L148 61 | install(TARGETS eudsl-nbgen RUNTIME DESTINATION "${EUDSL_NBGEN_INSTALL_DATADIR}.data/scripts") 62 | if (NOT WIN32) 63 | # this actually installs into venv/lib 64 | install(IMPORTED_RUNTIME_ARTIFACTS LLVM LIBRARY DESTINATION "${EUDSL_NBGEN_INSTALL_DATADIR}.data/data/lib") 65 | endif() 66 | else() 67 | # pip cmake install 68 | install(TARGETS eudsl-nbgen RUNTIME DESTINATION "${EUDSL_NBGEN_INSTALL_DATADIR}/bin") 69 | if (NOT WIN32) 70 | install(IMPORTED_RUNTIME_ARTIFACTS LLVM LIBRARY DESTINATION "${EUDSL_NBGEN_INSTALL_DATADIR}/lib") 71 | endif() 72 | endif() 73 | 74 | install( 75 | # the slash is load-bearing... 76 | DIRECTORY src/ 77 | DESTINATION "${EUDSL_NBGEN_INSTALL_DATADIR}" 78 | FILES_MATCHING PATTERN "*\.py" 79 | ) 80 | 81 | install( 82 | DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/../common/eudsl/" 83 | DESTINATION "${EUDSL_NBGEN_INSTALL_DATADIR}/includes/eudsl" 84 | FILES_MATCHING PATTERN "*\.h" 85 | ) 86 | 87 | install( 88 | FILES 89 | cmake/eudsl_nbgen-config.cmake 90 | DESTINATION "${EUDSL_NBGEN_INSTALL_DATADIR}/cmake" 91 | ) 92 | -------------------------------------------------------------------------------- /projects/eudsl-nbgen/cmake/eudsl_nbgen-config.cmake: -------------------------------------------------------------------------------- 1 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 | # See https://llvm.org/LICENSE.txt for license information. 3 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 | # Copyright (c) 2024. 5 | 6 | # copy-pasta from AddMLIR.cmake/AddLLVM.cmake/TableGen.cmake 7 | 8 | get_filename_component(EUDSL_NBGEN_INSTALL_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH) 9 | get_filename_component(EUDSL_NBGEN_INSTALL_PREFIX "${EUDSL_NBGEN_INSTALL_PREFIX}" PATH) 10 | set(EUDSL_NBGEN_INCLUDE_DIR "${EUDSL_NBGEN_INSTALL_PREFIX}/includes") 11 | 12 | function(eudsl_nbgen target input_file) 13 | set(EUDSL_NBGEN_TARGET_DEFINITIONS ${input_file}) 14 | cmake_parse_arguments(ARG "" "" "LINK_LIBS;EXTRA_INCLUDES;NAMESPACES;DEPENDS" ${ARGN}) 15 | if (IS_ABSOLUTE ${EUDSL_NBGEN_TARGET_DEFINITIONS}) 16 | set(EUDSL_NBGEN_TARGET_DEFINITIONS_ABSOLUTE ${input_file}) 17 | else() 18 | set(EUDSL_NBGEN_TARGET_DEFINITIONS_ABSOLUTE ${CMAKE_CURRENT_SOURCE_DIR}/${input_file}) 19 | endif() 20 | 21 | if (NOT EXISTS "${EUDSL_NBGEN_TARGET_DEFINITIONS_ABSOLUTE}") 22 | message(FATAL_ERROR "${input_file} does not exist") 23 | endif() 24 | 25 | get_directory_property(eudsl_nbgen_includes INCLUDE_DIRECTORIES) 26 | list(TRANSFORM ARG_EXTRA_INCLUDES PREPEND -I) 27 | list(APPEND eudsl_nbgen_includes ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}) 28 | list(REMOVE_ITEM eudsl_nbgen_includes "") 29 | list(TRANSFORM eudsl_nbgen_includes PREPEND -I) 30 | list(APPEND eudsl_nbgen_includes ${ARG_EXTRA_INCLUDES}) 31 | 32 | set(_gen_target_dir "${CMAKE_CURRENT_BINARY_DIR}/generated/${target}") 33 | file(MAKE_DIRECTORY ${_gen_target_dir}) 34 | set(_full_gen_file "${_gen_target_dir}/${target}.cpp.gen") 35 | set(_depfile ${_full_gen_file}.d) 36 | 37 | # hack but most of the time we're loading headers that are downstream of tds anyway 38 | # this could be smarter by asking people to list td targets or something but that's too onerous 39 | file(GLOB_RECURSE global_tds "${MLIR_INCLUDE_DIR}/mlir/*.td") 40 | if (NOT EXISTS ${_depfile}) 41 | # use cc -MM to collect all transitive headers 42 | set(clang_command ${CMAKE_CXX_COMPILER} 43 | # -v 44 | -xc++ "-std=c++${CMAKE_CXX_STANDARD}" 45 | -MM ${EUDSL_NBGEN_TARGET_DEFINITIONS_ABSOLUTE} 46 | -MT ${_full_gen_file} 47 | ${eudsl_nbgen_includes} 48 | -o ${_depfile} 49 | ) 50 | execute_process(COMMAND ${clang_command} RESULT_VARIABLE _had_error_depfile 51 | # COMMAND_ECHO STDOUT 52 | ERROR_QUIET 53 | ) 54 | endif() 55 | 56 | if (IS_ABSOLUTE ${EUDSL_NBGEN_TARGET_DEFINITIONS}) 57 | set(EUDSL_NBGEN_TARGET_DEFINITIONS_ABSOLUTE ${EUDSL_NBGEN_TARGET_DEFINITIONS}) 58 | else() 59 | set(EUDSL_NBGEN_TARGET_DEFINITIONS_ABSOLUTE 60 | ${CMAKE_CURRENT_SOURCE_DIR}/${EUDSL_NBGEN_TARGET_DEFINITIONS}) 61 | endif() 62 | 63 | string(REPLACE " " ";" eudsl_nbgen_defines "${LLVM_DEFINITIONS}") 64 | list(JOIN ARG_NAMESPACES "," namespaces) 65 | 66 | set(eudsl_nbgen_generate_cmd 67 | ${EUDSL_NBGEN_TARGET_DEFINITIONS_ABSOLUTE} 68 | -I${CMAKE_CURRENT_LIST_DIR} -namespaces=${namespaces} 69 | ${eudsl_nbgen_includes} ${eudsl_nbgen_defines} 70 | -o "${_full_gen_file}" 71 | ) 72 | set(eudsl_nbgen_shardify_cmd 73 | -shardify ${_full_gen_file} 74 | # ARG_EXTRA_INCLUDES has already had -I prepended 75 | -shard-target ${target} ${ARG_EXTRA_INCLUDES} -I ${EUDSL_NBGEN_TARGET_DEFINITIONS_ABSOLUTE} 76 | ) 77 | 78 | find_program(EUDSL_NBGEN_EXE NAMES "eudsl-nbgen" "eudsl-nbgen.exe") 79 | if (EUDSL_NBGEN_EXE STREQUAL "EUDSL_NBGEN_EXE-NOTFOUND" OR ARG_DEPENDS) 80 | ################################## 81 | # not standalone build 82 | ################################## 83 | if (EUDSL_NBGEN_EXE STREQUAL "EUDSL_NBGEN_EXE-NOTFOUND") 84 | if (WIN32) 85 | set(EUDSL_NBGEN_EXE "eudsl-nbgen.exe") 86 | else() 87 | set(EUDSL_NBGEN_EXE "eudsl-nbgen") 88 | endif() 89 | set(_eudsl_nbgen_exe_depends ${EUDSL_NBGEN_EXE}) 90 | else() 91 | message(STATUS "found EUDSL_NBGEN_EXE @ ${EUDSL_NBGEN_EXE}") 92 | set(_eudsl_nbgen_exe_depends) 93 | endif() 94 | 95 | string(REPLACE " " ";" eudsl_nbgen_defines "${LLVM_DEFINITIONS}") 96 | list(JOIN ARG_NAMESPACES "," namespaces) 97 | 98 | add_custom_command(OUTPUT ${_full_gen_file} 99 | COMMAND ${EUDSL_NBGEN_EXE} ${eudsl_nbgen_generate_cmd} 100 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 101 | DEPENDS ${_eudsl_nbgen_exe_depends} ${global_tds} ${ARG_DEPENDS} 102 | DEPFILE ${_depfile} 103 | COMMENT "eudsl-nbgen: Generating ${_full_gen_file}..." 104 | ) 105 | # epic hack to specify all shards that will be generated even though we don't know them before hand 106 | set(_shards) 107 | # lol spirv has 260 ops 108 | set(_max_num_shards 30) 109 | # note this count [0, 30] <- inclusive 110 | foreach(i RANGE ${_max_num_shards}) 111 | list(APPEND _shards "${_full_gen_file}.shard.${i}.cpp") 112 | endforeach() 113 | 114 | add_custom_command(OUTPUT "${_full_gen_file}.sharded.cpp" 115 | COMMAND ${EUDSL_NBGEN_EXE} ${eudsl_nbgen_shardify_cmd} 116 | -max-number-shards ${_max_num_shards} 117 | BYPRODUCTS ${_shards} 118 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 119 | DEPENDS ${_full_gen_file} ${_eudsl_nbgen_exe_depends} 120 | COMMENT "eudsl-nbgen: Generating ${_full_gen_file}.sharded.cpp..." 121 | ) 122 | else() 123 | message(STATUS "found EUDSL_NBGEN_EXE @ ${EUDSL_NBGEN_EXE}") 124 | ################################## 125 | # standalone build 126 | ################################## 127 | execute_process( 128 | COMMAND ${EUDSL_NBGEN_EXE} ${eudsl_nbgen_generate_cmd} 129 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 130 | RESULT_VARIABLE _had_error_gen_cpp 131 | # COMMAND_ECHO STDOUT 132 | ) 133 | if ((_had_error_gen_cpp AND NOT _had_error_gen_cpp EQUAL 0) OR NOT EXISTS "${_full_gen_file}") 134 | message(FATAL_ERROR "failed to create ${_full_gen_file}: ${_had_error_gen_cpp}") 135 | endif() 136 | execute_process( 137 | COMMAND ${EUDSL_NBGEN_EXE} ${eudsl_nbgen_shardify_cmd} 138 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 139 | RESULT_VARIABLE _had_error_gen_sharded 140 | # COMMAND_ECHO STDOUT 141 | ) 142 | if ((_had_error_gen_sharded AND NOT _had_error_gen_sharded EQUAL 0) OR NOT EXISTS "${_full_gen_file}.sharded.cpp") 143 | message(FATAL_ERROR "failed to create ${_full_gen_file}.sharded.cpp: ${_had_error_gen_sharded}") 144 | endif() 145 | file(GLOB _shards CONFIGURE_DEPENDS "${_gen_target_dir}/*shard*cpp") 146 | if (NOT _shards) 147 | message(FATAL_ERROR "no shards created") 148 | endif() 149 | endif() 150 | 151 | add_library(${target} STATIC "${_full_gen_file}.sharded.cpp" ${_shards}) 152 | execute_process( 153 | COMMAND "${Python_EXECUTABLE}" -m nanobind --include_dir 154 | OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE nanobind_include_dir 155 | RESULT_VARIABLE _has_err_find_nanobind 156 | ) 157 | if ((_has_err_find_nanobind AND NOT _has_err_find_nanobind EQUAL 0) OR NOT EXISTS "${nanobind_include_dir}") 158 | message(FATAL_ERROR "couldn't find nanobind include dir: ${_has_err_find_nanobind}") 159 | endif() 160 | target_include_directories(${target} PRIVATE 161 | ${eudsl_nbgen_includes} 162 | ${Python_INCLUDE_DIRS} 163 | ${nanobind_include_dir} 164 | ${EUDSL_NBGEN_INCLUDE_DIR} 165 | ) 166 | # not sure why unix needs this buy not apple (and really only in root-cmake build...) 167 | if(UNIX AND NOT APPLE) 168 | set_property(TARGET ${target} PROPERTY POSITION_INDEPENDENT_CODE ON) 169 | endif() 170 | set(_link_libs ${ARG_LINK_LIBS}) 171 | target_link_libraries(${target} PUBLIC ${_link_libs}) 172 | target_compile_options(${target} PUBLIC -Wno-cast-qual) 173 | 174 | # `make clean' must remove all those generated files: 175 | # TODO(max): clean up dep files 176 | set_property(DIRECTORY ${CMAKE_CURRENT_LIST_DIR} 177 | APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${_shards} ${_depfile}) 178 | set_source_files_properties(${_shards} PROPERTIES GENERATED 1) 179 | endfunction() 180 | 181 | function(set_install_rpath_origin target) 182 | set(_origin_prefix "\$ORIGIN") 183 | if (APPLE) 184 | set(_origin_prefix "@loader_path") 185 | endif() 186 | set_target_properties(${target} PROPERTIES INSTALL_RPATH "${_origin_prefix}") 187 | endfunction() 188 | 189 | function(patch_llvm_rpath target) 190 | cmake_parse_arguments(ARG "STANDALONE" "" "" ${ARGN}) 191 | # hack so we can move libLLVM into the wheel 192 | # see AddLLVM.cmake#llvm_setup_rpath 193 | if (APPLE OR UNIX) 194 | set(_origin_prefix "\$ORIGIN") 195 | if (APPLE) 196 | set(_origin_prefix "@loader_path") 197 | endif() 198 | if (STANDALONE) 199 | get_target_property(_llvm_loc ${target} LOCATION) 200 | else() 201 | set(_llvm_loc "$") 202 | endif() 203 | set(_old_rpath "${_origin_prefix}/../lib${LLVM_LIBDIR_SUFFIX}") 204 | if (APPLE) 205 | if (EXISTS ${_llvm_loc}) 206 | execute_process(COMMAND install_name_tool -rpath "${_old_rpath}" ${_origin_prefix} "${_llvm_loc}" ERROR_VARIABLE rpath_err) 207 | endif() 208 | # maybe already updated... 209 | if (rpath_err AND NOT rpath_err MATCHES "no LC_RPATH load command with path: ${_old_rpath}") 210 | message(FATAL_ERROR "couldn't update rpath because: ${rpath_err}") 211 | endif() 212 | else() 213 | # sneaky sneaky - undocumented 214 | if (EXISTS ${_llvm_loc}) 215 | file(RPATH_CHANGE FILE "${_llvm_loc}" OLD_RPATH "${_old_rpath}" NEW_RPATH "${_origin_prefix}") 216 | endif() 217 | endif() 218 | endif() 219 | endfunction() 220 | 221 | macro(maybe_add_eudsl_nbgen_to_path) 222 | find_program(EUDSL_NBGEN_EXE NAMES "eudsl-nbgen" "eudsl-nbgen.exe") 223 | if (EUDSL_NBGEN_EXE STREQUAL "EUDSL_NBGEN_EXE-NOTFOUND") 224 | execute_process( 225 | COMMAND "${Python_EXECUTABLE}" -c "import sysconfig; print(sysconfig.get_path('scripts'))" 226 | OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE eudsl_nbgen_exe_path) 227 | set(ENV{PATH} "${eudsl_nbgen_exe_path}:$ENV{PATH}") 228 | endif() 229 | find_program(EUDSL_NBGEN_EXE NAMES "eudsl-nbgen" "eudsl-nbgen.exe") 230 | if (EUDSL_NBGEN_EXE STREQUAL "EUDSL_NBGEN_EXE-NOTFOUND") 231 | message(WARNING "couldn't find EUDSL_NBGEN_EXE") 232 | endif() 233 | endmacro() 234 | -------------------------------------------------------------------------------- /projects/eudsl-nbgen/pyproject.toml: -------------------------------------------------------------------------------- 1 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 | # See https://llvm.org/LICENSE.txt for license information. 3 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 | # Copyright (c) 2024. 5 | 6 | [project] 7 | name = "eudsl-nbgen" 8 | version = "0.0.1" 9 | requires-python = ">=3.9" 10 | 11 | [project.urls] 12 | Homepage = "https://github.com/llvm/eudsl" 13 | 14 | [build-system] 15 | requires = [ 16 | "nanobind==2.4.0", 17 | "scikit-build-core==0.10.7", 18 | "typing_extensions==4.12.2" 19 | ] 20 | build-backend = "scikit_build_core.build" 21 | 22 | [tool.scikit-build] 23 | minimum-version = "0.10" 24 | build-dir = "build/{wheel_tag}" 25 | # gives you a wheel tagged py3-none 26 | wheel.py-api = "py3" 27 | cmake.source-dir = "." 28 | 29 | [tool.scikit-build.cmake.define] 30 | CMAKE_BUILD_TYPE = { env = "CMAKE_BUILD_TYPE", default = "Release" } 31 | CMAKE_PREFIX_PATH = { env = "CMAKE_PREFIX_PATH", default = "" } 32 | CMAKE_C_FLAGS = { env = "CMAKE_C_FLAGS", default = "" } 33 | CMAKE_CXX_FLAGS = { env = "CMAKE_CXX_FLAGS", default = "" } 34 | CMAKE_C_COMPILER_LAUNCHER = { env = "CMAKE_C_COMPILER_LAUNCHER", default = "" } 35 | CMAKE_CXX_COMPILER_LAUNCHER = { env = "CMAKE_CXX_COMPILER_LAUNCHER", default = "" } 36 | CMAKE_EXE_LINKER_FLAGS_INIT = { env = "CMAKE_EXE_LINKER_FLAGS_INIT", default = "" } 37 | CMAKE_SHARED_LINKER_FLAGS_INIT = { env = "CMAKE_SHARED_LINKER_FLAGS_INIT", default = "" } 38 | CMAKE_MODULE_LINKER_FLAGS_INIT = { env = "CMAKE_MODULE_LINKER_FLAGS_INIT", default = "" } 39 | CMAKE_OSX_DEPLOYMENT_TARGET = { env = "CMAKE_OSX_DEPLOYMENT_TARGET", default = "11.0" } 40 | CMAKE_C_VISIBILITY_PRESET = "hidden" 41 | CMAKE_CXX_VISIBILITY_PRESET = "hidden" 42 | CMAKE_VISIBILITY_INLINES_HIDDEN = "ON" 43 | CMAKE_VERBOSE_MAKEFILE = "ON" 44 | LLVM_DIR = { env = "LLVM_DIR", default = "EMPTY" } 45 | Clang_DIR = { env = "Clang_DIR", default = "EMPTY" } 46 | LLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN = "ON" 47 | 48 | [tool.cibuildwheel] 49 | build-verbosity = 1 50 | # build only one version 51 | build = ["cp39*"] 52 | skip = ["*-manylinux_i686", "*-musllinux*", "pp*", "*-win32"] 53 | archs = ["auto64"] 54 | manylinux-x86_64-image = "manylinux_2_28" 55 | manylinux-aarch64-image = "quay.io/pypa/manylinux_2_34_aarch64" 56 | environment-pass = [ 57 | "CMAKE_PREFIX_PATH", 58 | "CMAKE_C_FLAGS", 59 | "CMAKE_CXX_FLAGS", 60 | "CMAKE_C_COMPILER_LAUNCHER", 61 | "CMAKE_CXX_COMPILER_LAUNCHER", 62 | "CMAKE_GENERATOR", 63 | "LLVM_DIR", 64 | "Clang_DIR", 65 | "CC", 66 | "CXX", 67 | # ccache 68 | "CCACHE_DIR", 69 | "CCACHE_MAXSIZE=700M", 70 | "CCACHE_SLOPPINESS", 71 | "CCACHE_CPP2", 72 | "CCACHE_UMASK", 73 | "CCACHE_NOHASHDIR", 74 | "PIP_FIND_LINKS", 75 | ] 76 | before-build = [ 77 | "export CCACHE_DIR=$CCACHE_DIR/$(python -c 'import platform; print(platform.python_version())')", 78 | "mkdir -p $CCACHE_DIR", 79 | "ccache -z" 80 | ] 81 | # uncomment to make sure ccache is working inside containers 82 | test-command = "ccache -s" 83 | repair-wheel-command = [] 84 | 85 | [tool.cibuildwheel.linux] 86 | before-all = [ 87 | "yum install -y clang", 88 | # ccache 89 | "echo $(if [ \"$(arch)\" == \"x86_64\" ]; then curl -sLO https://github.com/ccache/ccache/releases/download/v4.10.2/ccache-4.10.2-linux-x86_64.tar.xz && tar -xf ccache-4.10.2-linux-x86_64.tar.xz && pushd ccache-4.10.2-linux-x86_64 && make install && popd; fi)", 90 | "echo $(if [ \"$(arch)\" == \"aarch64\" ]; then dnf install -y ccache; fi)", 91 | "ccache -z" 92 | ] 93 | # synchronize TZ with host so ccache files have correct timestamp 94 | container-engine = { name = "docker", create-args = ["-v", "/etc/timezone:/etc/timezone:ro", "-v", "/etc/localtime:/etc/localtime:ro"] } 95 | 96 | [tool.cibuildwheel.macos] 97 | before-build = [ 98 | "ccache -z" 99 | ] 100 | 101 | [tool.cibuildwheel.windows] 102 | before-build = [ 103 | "ccache -z" 104 | ] 105 | -------------------------------------------------------------------------------- /projects/eudsl-nbgen/src/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025. 2 | # 3 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 | # See https://llvm.org/LICENSE.txt for license information. 5 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | from pathlib import Path 7 | 8 | 9 | def cmake_dir() -> str: 10 | return str(Path(__file__).parent / "cmake") 11 | 12 | 13 | def includes_dir() -> str: 14 | return str(Path(__file__).parent / "includes") 15 | 16 | 17 | __all__ = ["cmake_dir", "includes_dir"] 18 | -------------------------------------------------------------------------------- /projects/eudsl-nbgen/src/__main__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025. 2 | # 3 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 | # See https://llvm.org/LICENSE.txt for license information. 5 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | 7 | import argparse 8 | import sys 9 | 10 | from . import cmake_dir 11 | 12 | 13 | def main() -> None: 14 | parser = argparse.ArgumentParser("eudsl-nbgen") 15 | parser.add_argument( 16 | "--cmake_dir", 17 | action="store_true", 18 | help="Print the path to the eudsl-nbgen CMake module directory.", 19 | ) 20 | args = parser.parse_args() 21 | if not sys.argv[1:]: 22 | parser.print_help() 23 | if args.cmake_dir: 24 | print(cmake_dir()) 25 | 26 | 27 | if __name__ == "__main__": 28 | main() 29 | -------------------------------------------------------------------------------- /projects/eudsl-py/pyproject.toml: -------------------------------------------------------------------------------- 1 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 | # See https://llvm.org/LICENSE.txt for license information. 3 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 | # Copyright (c) 2024. 5 | 6 | [project] 7 | name = "eudsl-py" 8 | version = "0.0.1" 9 | requires-python = ">=3.9" 10 | dependencies = [ 11 | "numpy==2.0.2" 12 | ] 13 | 14 | [project.urls] 15 | Homepage = "https://github.com/llvm/eudsl" 16 | 17 | [build-system] 18 | requires = [ 19 | "eudsl-nbgen", 20 | "nanobind==2.4.0", 21 | "numpy==2.0.2", 22 | "scikit-build-core==0.10.7", 23 | "typing_extensions==4.12.2" 24 | ] 25 | build-backend = "scikit_build_core.build" 26 | 27 | [tool.scikit-build] 28 | minimum-version = "0.10" 29 | build-dir = "build" 30 | wheel.py-api = "cp312" 31 | cmake.source-dir = "." 32 | 33 | [tool.scikit-build.cmake.define] 34 | CMAKE_PREFIX_PATH = { env = "CMAKE_PREFIX_PATH", default = "" } 35 | CMAKE_C_FLAGS = { env = "CMAKE_C_FLAGS", default = "" } 36 | CMAKE_CXX_FLAGS = { env = "CMAKE_CXX_FLAGS", default = "" } 37 | CMAKE_C_COMPILER_LAUNCHER = { env = "CMAKE_C_COMPILER_LAUNCHER", default = "" } 38 | CMAKE_CXX_COMPILER_LAUNCHER = { env = "CMAKE_CXX_COMPILER_LAUNCHER", default = "" } 39 | CMAKE_EXE_LINKER_FLAGS_INIT = { env = "CMAKE_EXE_LINKER_FLAGS_INIT", default = "" } 40 | CMAKE_SHARED_LINKER_FLAGS_INIT = { env = "CMAKE_SHARED_LINKER_FLAGS_INIT", default = "" } 41 | CMAKE_MODULE_LINKER_FLAGS_INIT = { env = "CMAKE_MODULE_LINKER_FLAGS_INIT", default = "" } 42 | CMAKE_OSX_DEPLOYMENT_TARGET = { env = "CMAKE_OSX_DEPLOYMENT_TARGET", default = "11.0" } 43 | CMAKE_C_VISIBILITY_PRESET = "hidden" 44 | CMAKE_CXX_VISIBILITY_PRESET = "hidden" 45 | CMAKE_VISIBILITY_INLINES_HIDDEN = "ON" 46 | CMAKE_VERBOSE_MAKEFILE = "ON" 47 | LLVM_DIR = { env = "LLVM_DIR", default = "EMPTY" } 48 | MLIR_DIR = { env = "MLIR_DIR", default = "EMPTY" } 49 | Clang_DIR = { env = "Clang_DIR", default = "EMPTY" } 50 | LLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN = "ON" 51 | 52 | [tool.cibuildwheel] 53 | build-verbosity = 1 54 | skip = ["*-manylinux_i686", "*-musllinux*", "pp*", "*-win32"] 55 | archs = ["auto64"] 56 | manylinux-x86_64-image = "manylinux_2_28" 57 | manylinux-aarch64-image = "quay.io/pypa/manylinux_2_34_aarch64" 58 | environment-pass = [ 59 | "CMAKE_PREFIX_PATH", 60 | "CMAKE_C_FLAGS", 61 | "CMAKE_CXX_FLAGS", 62 | "CMAKE_C_COMPILER_LAUNCHER", 63 | "CMAKE_CXX_COMPILER_LAUNCHER", 64 | "CMAKE_GENERATOR", 65 | "LLVM_DIR", 66 | "MLIR_DIR", 67 | "Clang_DIR", 68 | "CC", 69 | "CXX", 70 | "PIP_FIND_LINKS", 71 | # ccache 72 | "CCACHE_DIR", 73 | "CCACHE_MAXSIZE=700M", 74 | "CCACHE_SLOPPINESS", 75 | "CCACHE_CPP2", 76 | "CCACHE_UMASK", 77 | "CCACHE_NOHASHDIR", 78 | "PIP_FIND_LINKS", 79 | ] 80 | before-build = [ 81 | "export CCACHE_DIR=$CCACHE_DIR/$(python -c 'import platform; print(platform.python_version())')", 82 | "mkdir -p $CCACHE_DIR", 83 | "ccache -z" 84 | ] 85 | # uncomment to make sure ccache is working inside containers 86 | test-command = "ccache -s" 87 | 88 | [tool.cibuildwheel.linux] 89 | before-all = [ 90 | "yum install -y clang", 91 | # ccache 92 | "echo $(if [ \"$(arch)\" == \"x86_64\" ]; then curl -sLO https://github.com/ccache/ccache/releases/download/v4.10.2/ccache-4.10.2-linux-x86_64.tar.xz && tar -xf ccache-4.10.2-linux-x86_64.tar.xz && pushd ccache-4.10.2-linux-x86_64 && make install && popd; fi)", 93 | "echo $(if [ \"$(arch)\" == \"aarch64\" ]; then dnf install -y ccache; fi)", 94 | "ccache -z" 95 | ] 96 | # synchronize TZ with host so ccache files have correct timestamp 97 | container-engine = { name = "docker", create-args = ["-v", "/etc/timezone:/etc/timezone:ro", "-v", "/etc/localtime:/etc/localtime:ro"] } 98 | 99 | [tool.cibuildwheel.macos] 100 | before-build = [ 101 | "ccache -z" 102 | ] 103 | 104 | [tool.cibuildwheel.windows] 105 | before-build = [ 106 | "ccache -z" 107 | ] 108 | -------------------------------------------------------------------------------- /projects/eudsl-py/src/eudsl/.gitignore: -------------------------------------------------------------------------------- 1 | *.so 2 | *.a 3 | *.pyi 4 | -------------------------------------------------------------------------------- /projects/eudsl-py/src/eudsl/__init__.py: -------------------------------------------------------------------------------- 1 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 | # See https://llvm.org/LICENSE.txt for license information. 3 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 | # Copyright (c) 2024. 5 | 6 | from .eudslpy_ext import * -------------------------------------------------------------------------------- /projects/eudsl-py/src/eudsl/dialects/__init__.py: -------------------------------------------------------------------------------- 1 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 | # See https://llvm.org/LICENSE.txt for license information. 3 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 | # Copyright (c) 2024. 5 | 6 | from ..eudslpy_ext.dialects import * -------------------------------------------------------------------------------- /projects/eudsl-py/src/eudsl/dialects/arith/__init__.py: -------------------------------------------------------------------------------- 1 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 | # See https://llvm.org/LICENSE.txt for license information. 3 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 | # Copyright (c) 2025. 5 | 6 | from ...eudslpy_ext.dialects.arith import * 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/eudsl-py/src/eudsl/ir/__init__.py: -------------------------------------------------------------------------------- 1 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 | # See https://llvm.org/LICENSE.txt for license information. 3 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 | # Copyright (c) 2024. 5 | 6 | from ..eudslpy_ext.ir import * -------------------------------------------------------------------------------- /projects/eudsl-py/tests/test_bindings.py: -------------------------------------------------------------------------------- 1 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 | # See https://llvm.org/LICENSE.txt for license information. 3 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 | # Copyright (c) 2024. 5 | 6 | import numpy as np 7 | from eudsl import ArrayRef, SmallVector 8 | from eudsl.dialects.arith import ArithDialect, ConstantOp 9 | from eudsl.ir import ( 10 | MLIRContext, 11 | Threading, 12 | ModuleOp, 13 | OpBuilder, 14 | OperationState, 15 | FloatAttr, 16 | Float32Type, 17 | StringAttr, 18 | Type, 19 | Attribute, 20 | MemRefType, 21 | ) 22 | 23 | 24 | def test_array_ref(): 25 | v = SmallVector[int]([666, 2, 1]) 26 | for vv in v: 27 | print(vv) 28 | tys = ArrayRef(v) 29 | for t in tys: 30 | print(t) 31 | 32 | v = SmallVector[float]([666.0, 2.0, 1.0]) 33 | for vv in v: 34 | print(vv) 35 | tys = ArrayRef(v) 36 | for t in tys: 37 | print(t) 38 | 39 | v = SmallVector[bool]([True, False, True]) 40 | for vv in v: 41 | print(vv) 42 | tys = ArrayRef(v) 43 | for t in tys: 44 | print(t) 45 | 46 | print(SmallVector["int16"]) 47 | print(SmallVector["int32"]) 48 | print(SmallVector["int64"]) 49 | print(SmallVector[np.int16]) 50 | print(SmallVector[np.int32]) 51 | print(SmallVector[np.int64]) 52 | 53 | ctx = MLIRContext(Threading.DISABLED) 54 | f32_ty = Float32Type.get(ctx) 55 | v = SmallVector[Type]([f32_ty]) 56 | tys = ArrayRef(v) 57 | for t in tys: 58 | print(t) 59 | 60 | attrs = [Attribute(), Attribute(), Attribute()] 61 | v = SmallVector[Attribute](attrs) 62 | tys = ArrayRef(v) 63 | for t in tys: 64 | print(t) 65 | 66 | 67 | def test_arith_dialect(): 68 | ctx = MLIRContext(Threading.DISABLED) 69 | ArithDialect.insert_into_registry(ctx.dialect_registry) 70 | ctx.load_all_available_dialects() 71 | l = OpBuilder.Listener() 72 | b = OpBuilder(ctx, l) 73 | mod1 = ModuleOp.create(b.unknown_loc, "foo") 74 | b.set_insertion_point_to_start(mod1.body_region.blocks[0]) 75 | f32_ty = Float32Type.get(ctx) 76 | f32_attr = FloatAttr.get(f32_ty, 1.0) 77 | str_attr = StringAttr.get(ctx, "value") 78 | 79 | op_state = OperationState(b.unknown_loc, ConstantOp.get_operation_name()) 80 | op_state.add_attribute(str_attr, f32_attr) 81 | v = SmallVector[Type]([f32_ty]) 82 | tys = ArrayRef(v) 83 | op_state.add_types(tys) 84 | op = b.create(op_state) 85 | 86 | op_state = OperationState(b.unknown_loc, ConstantOp.get_operation_name()) 87 | op_state.add_attribute(str_attr, f32_attr) 88 | v = SmallVector[Type]([f32_ty]) 89 | op_state.add_types(v) 90 | op = b.create(op_state) 91 | 92 | print(mod1.operation) 93 | assert mod1.verify() 94 | 95 | 96 | # def test_types(): 97 | # ctx = MLIRContext(Threading.DISABLED) 98 | # nvgpu.NVGPUDialect.insert_into_registry(ctx.dialect_registry) 99 | # ctx.load_all_available_dialects() 100 | # shape = SmallVector[np.int64]([10, 10]) 101 | # f32_ty = Float32Type.get(ctx) 102 | # shape_ = ArrayRef(shape) 103 | # memref_ty = MemRefType.Builder(shape_, f32_ty).memref_type() 104 | # print(memref_ty) 105 | # td = nvgpu.TensorMapDescriptorType.get( 106 | # ctx, 107 | # memref_ty, 108 | # nvgpu.TensorMapSwizzleKind.SWIZZLE_64B, 109 | # nvgpu.TensorMapL2PromoKind.L2PROMO_64B, 110 | # nvgpu.TensorMapOOBKind.OOB_NAN, 111 | # nvgpu.TensorMapInterleaveKind.INTERLEAVE_16B, 112 | # ) 113 | # print(td) 114 | 115 | 116 | if __name__ == "__main__": 117 | test_array_ref() 118 | test_arith_dialect() 119 | # test_types() 120 | -------------------------------------------------------------------------------- /projects/eudsl-tblgen/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 | # See https://llvm.org/LICENSE.txt for license information. 3 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 | # Copyright (c) 2024. 5 | 6 | cmake_minimum_required(VERSION 3.29) 7 | set(CMAKE_CXX_STANDARD 17) 8 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 9 | 10 | set(LLVM_SUBPROJECT_TITLE "EUDSL_TBLGEN") 11 | set(EUDSL_TBLGEN_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) 12 | set(EUDSL_TBLGEN_SRC_DIR "${CMAKE_CURRENT_LIST_DIR}/src") 13 | 14 | if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_LIST_DIR) 15 | message("Building ${LLVM_SUBPROJECT_TITLE} as a standalone project.") 16 | project(${LLVM_SUBPROJECT_TITLE} CXX C) 17 | find_package(LLVM REQUIRED CONFIG) 18 | find_package(MLIR REQUIRED CONFIG) 19 | 20 | message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") 21 | message(STATUS "Using MLIRConfig.cmake in: ${MLIR_DIR}") 22 | 23 | set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/bin) 24 | set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/lib) 25 | 26 | list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") 27 | list(APPEND CMAKE_MODULE_PATH "${MLIR_CMAKE_DIR}") 28 | 29 | include(TableGen) 30 | include(AddLLVM) 31 | include(AddMLIR) 32 | include(HandleLLVMOptions) 33 | 34 | include_directories(${CMAKE_CURRENT_LIST_DIR}/../common) 35 | endif() 36 | 37 | include_directories(${MLIR_INCLUDE_DIRS}) 38 | include_directories(${LLVM_INCLUDE_DIRS}) 39 | link_directories(${LLVM_BUILD_LIBRARY_DIR}) 40 | add_definitions(${LLVM_DEFINITIONS}) 41 | 42 | if(NOT TARGET LLVMSupport) 43 | message(FATAL_ERROR "LLVMSupport not found") 44 | endif() 45 | 46 | find_package(Python 3.8 47 | REQUIRED COMPONENTS Interpreter Development.Module 48 | OPTIONAL_COMPONENTS Development.SABIModule) 49 | 50 | execute_process( 51 | COMMAND "${Python_EXECUTABLE}" -m nanobind --cmake_dir 52 | OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE nanobind_DIR) 53 | find_package(nanobind CONFIG REQUIRED) 54 | 55 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${EUDSL_TBLGEN_SRC_DIR}/eudsl_tblgen) 56 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 57 | 58 | nanobind_add_module(eudsl_tblgen_ext NB_STATIC STABLE_ABI 59 | src/eudsl_tblgen_ext.cpp 60 | src/TGParser.cpp 61 | src/TGLexer.cpp 62 | ) 63 | set_property(TARGET eudsl_tblgen_ext PROPERTY POSITION_INDEPENDENT_CODE ON) 64 | set(eudsl_tblgen_ext_libs 65 | LLVMTableGenCommon LLVMTableGen LLVMCore MLIRTableGen) 66 | if(APPLE) 67 | list(APPEND eudsl_tblgen_ext_libs ${LLVM_AVAILABLE_LIBS}) 68 | list(REMOVE_ITEM eudsl_tblgen_ext_libs Remarks LTO LLVM) 69 | list(REMOVE_DUPLICATES eudsl_tblgen_ext_libs) 70 | target_link_directories(eudsl_tblgen_ext PRIVATE "${LLVM_LIBRARY_DIR}") 71 | list(TRANSFORM eudsl_tblgen_ext_libs PREPEND "-Wl,-hidden-l") 72 | endif() 73 | target_link_libraries(eudsl_tblgen_ext PRIVATE ${eudsl_tblgen_ext_libs}) 74 | 75 | set(nanobind_options 76 | -Wno-cast-qual 77 | -Wno-deprecated-literal-operator 78 | -Wno-covered-switch-default 79 | -Wno-nested-anon-types 80 | -Wno-zero-length-array 81 | -Wno-c++98-compat-extra-semi 82 | -Wno-c++20-extensions 83 | $<$:-fexceptions -frtti> 84 | $<$:-fexceptions -frtti> 85 | $<$:/EHsc /GR>) 86 | target_compile_options(eudsl_tblgen_ext PRIVATE ${nanobind_options}) 87 | set(_nanobind_tgt) 88 | if(TARGET nanobind-static) 89 | set(_nanobind_tgt nanobind-static) 90 | elseif(TARGET nanobind-static-abi3) 91 | set(_nanobind_tgt nanobind-static-abi3) 92 | endif() 93 | target_compile_options(${_nanobind_tgt} PRIVATE ${nanobind_options}) 94 | 95 | # note WORKING_DIRECTORY 96 | set(NB_STUBGEN_CMD "${Python_EXECUTABLE}" "-m" "nanobind.stubgen" 97 | --module eudsl_tblgen_ext --recursive --include-private --output-dir .) 98 | set(NB_STUBGEN_OUTPUTS "eudsl_tblgen_ext.pyi") 99 | add_custom_command( 100 | OUTPUT ${NB_STUBGEN_OUTPUTS} 101 | COMMAND ${NB_STUBGEN_CMD} 102 | WORKING_DIRECTORY "${EUDSL_TBLGEN_SRC_DIR}/eudsl_tblgen" 103 | DEPENDS eudsl_tblgen_ext 104 | ) 105 | add_custom_target(eudsl_tblgen_ext_stub ALL DEPENDS ${NB_STUBGEN_OUTPUTS}) 106 | 107 | install(TARGETS eudsl_tblgen_ext LIBRARY DESTINATION eudsl_tblgen) 108 | install( 109 | DIRECTORY "${EUDSL_TBLGEN_SRC_DIR}/eudsl_tblgen" 110 | DESTINATION ${CMAKE_INSTALL_PREFIX} 111 | PATTERN "*.pyc" EXCLUDE 112 | PATTERN "*.so" EXCLUDE 113 | PATTERN "*.a" EXCLUDE 114 | PATTERN "__pycache__" EXCLUDE 115 | PATTERN ".gitignore" EXCLUDE 116 | ) 117 | 118 | install( 119 | FILES src/eudsl_tblgen/cmake/eudsl_tblgen-config.cmake 120 | DESTINATION "${CMAKE_INSTALL_PREFIX}/cmake" 121 | ) 122 | -------------------------------------------------------------------------------- /projects/eudsl-tblgen/pyproject.toml: -------------------------------------------------------------------------------- 1 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 | # See https://llvm.org/LICENSE.txt for license information. 3 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 | # Copyright (c) 2024. 5 | 6 | [project] 7 | name = "eudsl-tblgen" 8 | version = "0.0.1" 9 | requires-python = ">=3.9" 10 | 11 | [project.urls] 12 | Homepage = "https://github.com/llvm/eudsl" 13 | 14 | [build-system] 15 | requires = [ 16 | "nanobind>=2.2.0", 17 | "scikit-build-core>=0.10.7", 18 | "typing_extensions==4.12.2" 19 | ] 20 | build-backend = "scikit_build_core.build" 21 | 22 | [tool.scikit-build] 23 | minimum-version = "0.10" 24 | build-dir = "build/{wheel_tag}" 25 | cmake.source-dir = "." 26 | wheel.packages = ["src/eudsl_tblgen"] 27 | wheel.py-api = "cp312" 28 | 29 | [tool.scikit-build.cmake.define] 30 | CMAKE_PREFIX_PATH = { env = "CMAKE_PREFIX_PATH", default = "" } 31 | CMAKE_C_FLAGS = { env = "CMAKE_C_FLAGS", default = "" } 32 | CMAKE_CXX_FLAGS = { env = "CMAKE_CXX_FLAGS", default = "" } 33 | CMAKE_C_COMPILER_LAUNCHER = { env = "CMAKE_C_COMPILER_LAUNCHER", default = "" } 34 | CMAKE_CXX_COMPILER_LAUNCHER = { env = "CMAKE_CXX_COMPILER_LAUNCHER", default = "" } 35 | CMAKE_EXE_LINKER_FLAGS_INIT = { env = "CMAKE_EXE_LINKER_FLAGS_INIT", default = "" } 36 | CMAKE_SHARED_LINKER_FLAGS_INIT = { env = "CMAKE_SHARED_LINKER_FLAGS_INIT", default = "" } 37 | CMAKE_MODULE_LINKER_FLAGS_INIT = { env = "CMAKE_MODULE_LINKER_FLAGS_INIT", default = "" } 38 | CMAKE_OSX_DEPLOYMENT_TARGET = { env = "CMAKE_OSX_DEPLOYMENT_TARGET", default = "11.0" } 39 | CMAKE_C_VISIBILITY_PRESET = "hidden" 40 | CMAKE_CXX_VISIBILITY_PRESET = "hidden" 41 | CMAKE_VISIBILITY_INLINES_HIDDEN = "ON" 42 | CMAKE_VERBOSE_MAKEFILE = "ON" 43 | LLVM_DIR = { env = "LLVM_DIR", default = "EMPTY" } 44 | MLIR_DIR = { env = "MLIR_DIR", default = "EMPTY" } 45 | LLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN = "ON" 46 | 47 | [tool.cibuildwheel] 48 | build-verbosity = 1 49 | skip = ["*-manylinux_i686", "*-musllinux*", "pp*", "*-win32"] 50 | archs = ["auto64"] 51 | manylinux-x86_64-image = "manylinux_2_28" 52 | manylinux-aarch64-image = "quay.io/pypa/manylinux_2_34_aarch64" 53 | environment-pass = [ 54 | "CMAKE_PREFIX_PATH", 55 | "CMAKE_C_FLAGS", 56 | "CMAKE_CXX_FLAGS", 57 | "CMAKE_C_COMPILER_LAUNCHER", 58 | "CMAKE_CXX_COMPILER_LAUNCHER", 59 | "CMAKE_GENERATOR", 60 | "CC", 61 | "CXX", 62 | "LLVM_DIR", 63 | "MLIR_DIR", 64 | # ccache 65 | "CCACHE_DIR", 66 | "CCACHE_MAXSIZE=700M", 67 | "CCACHE_SLOPPINESS", 68 | "CCACHE_CPP2", 69 | "CCACHE_UMASK", 70 | "CCACHE_NOHASHDIR", 71 | "PIP_FIND_LINKS", 72 | ] 73 | before-build = [ 74 | "export CCACHE_DIR=$CCACHE_DIR/$(python -c 'import platform; print(platform.python_version())')", 75 | "mkdir -p $CCACHE_DIR", 76 | "ccache -z" 77 | ] 78 | # uncomment to make sure ccache is working inside containers 79 | test-command = "ccache -s" 80 | 81 | [tool.cibuildwheel.linux] 82 | before-all = [ 83 | "set -x", 84 | "yum install -y clang", 85 | # ccache 86 | "echo $(if [ \"$(arch)\" == \"x86_64\" ]; then curl -sLO https://github.com/ccache/ccache/releases/download/v4.10.2/ccache-4.10.2-linux-x86_64.tar.xz && tar -xf ccache-4.10.2-linux-x86_64.tar.xz && pushd ccache-4.10.2-linux-x86_64 && make install && popd; fi)", 87 | "echo $(if [ \"$(arch)\" == \"aarch64\" ]; then dnf install -y ccache; fi)", 88 | "ccache -z" 89 | ] 90 | # synchronize TZ with host so ccache files have correct timestamp 91 | container-engine = { name = "docker", create-args = ["-v", "/etc/timezone:/etc/timezone:ro", "-v", "/etc/localtime:/etc/localtime:ro"] } 92 | 93 | [tool.cibuildwheel.macos] 94 | before-build = [ 95 | "ccache -z" 96 | ] 97 | 98 | [tool.cibuildwheel.windows] 99 | before-build = [ 100 | "ccache -z" 101 | ] 102 | -------------------------------------------------------------------------------- /projects/eudsl-tblgen/src/eudsl_tblgen/.gitignore: -------------------------------------------------------------------------------- 1 | *.so 2 | *.a 3 | *.pyi 4 | -------------------------------------------------------------------------------- /projects/eudsl-tblgen/src/eudsl_tblgen/__init__.py: -------------------------------------------------------------------------------- 1 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 | # See https://llvm.org/LICENSE.txt for license information. 3 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 | # Copyright (c) 2024. 5 | from pathlib import Path 6 | from typing import List, Optional 7 | 8 | from .eudsl_tblgen_ext import * 9 | 10 | 11 | import re 12 | 13 | 14 | def get_operation_name(def_record): 15 | prefix = def_record.get_value_as_def("opDialect").get_value_as_string("name") 16 | op_name = def_record.get_value_as_string("opName") 17 | 18 | if not prefix: 19 | return op_name 20 | return f"{prefix}.{op_name}" 21 | 22 | 23 | def get_requested_op_definitions(records, op_inc_filter=None, op_exc_filter=None): 24 | class_def = records.get_class("Op") 25 | if not class_def: 26 | raise RuntimeError("ERROR: Couldn't find the 'Op' class!") 27 | 28 | if op_inc_filter: 29 | include_regex = re.compile(op_inc_filter) 30 | if op_exc_filter: 31 | exclude_regex = re.compile(op_exc_filter) 32 | defs = [] 33 | 34 | for def_name in records.get_defs(): 35 | def_record = records.get_defs()[def_name] 36 | if not def_record.is_sub_class_of(class_def): 37 | continue 38 | # Include if no include filter or include filter matches. 39 | if op_inc_filter and not include_regex.match(get_operation_name(def_record)): 40 | continue 41 | # Unless there is an exclude filter and it matches. 42 | if op_exc_filter and exclude_regex.match(get_operation_name(def_record)): 43 | continue 44 | defs.append(def_record) 45 | 46 | return defs 47 | 48 | 49 | def collect_all_defs( 50 | record_keeper: RecordKeeper, 51 | selected_dialect: Optional[str] = None, 52 | ) -> List[Record]: 53 | records = record_keeper.get_defs() 54 | records = [records[d] for d in records] 55 | # Nothing to do if no defs were found. 56 | if not records: 57 | return [] 58 | 59 | defs = [rec for rec in records if rec.get_value("dialect")] 60 | result_defs = [] 61 | 62 | if not selected_dialect: 63 | # If a dialect was not specified, ensure that all found defs belong to the same dialect. 64 | dialects = {d.get_value("dialect").get_value().get_as_string() for d in defs} 65 | if len(dialects) > 1: 66 | raise RuntimeError( 67 | "Defs belong to more than one dialect. Must select one via '--(attr|type)defs-dialect'" 68 | ) 69 | result_defs.extend(defs) 70 | else: 71 | # Otherwise, generate the defs that belong to the selected dialect. 72 | dialect_defs = [ 73 | d 74 | for d in defs 75 | if d.get_value("dialect").get_value().get_as_string() == selected_dialect 76 | ] 77 | result_defs.extend(dialect_defs) 78 | 79 | return result_defs 80 | 81 | 82 | def collect_all_attr_or_type_defs(records: List[Record]): 83 | return [ 84 | AttrOrTypeDef(rec) 85 | for rec in records 86 | if rec.get_value("builders") and rec.get_value("parameters") 87 | ] 88 | 89 | 90 | def get_all_type_constraints(records: RecordKeeper): 91 | result = [] 92 | for record in records.get_all_derived_definitions_if_defined("TypeConstraint"): 93 | # Ignore constraints defined outside of the top-level file. 94 | constr = Constraint(record) 95 | # Generate C++ function only if "cppFunctionName" is set. 96 | if not constr.get_cpp_function_name(): 97 | continue 98 | result.append(constr) 99 | return result 100 | 101 | 102 | def cmake_dir() -> str: 103 | return str(Path(__file__).parent / "cmake") 104 | -------------------------------------------------------------------------------- /projects/eudsl-tblgen/src/eudsl_tblgen/__main__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025. 2 | # 3 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 | # See https://llvm.org/LICENSE.txt for license information. 5 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | 7 | import argparse 8 | import sys 9 | 10 | from . import cmake_dir 11 | 12 | 13 | def main() -> None: 14 | parser = argparse.ArgumentParser("eudsl-tblgen") 15 | parser.add_argument( 16 | "--cmake_dir", 17 | action="store_true", 18 | help="Print the path to the eudsl-tblgen CMake module directory.", 19 | ) 20 | args = parser.parse_args() 21 | if not sys.argv[1:]: 22 | parser.print_help() 23 | if args.cmake_dir: 24 | print(cmake_dir()) 25 | 26 | 27 | if __name__ == "__main__": 28 | main() 29 | -------------------------------------------------------------------------------- /projects/eudsl-tblgen/src/eudsl_tblgen/cmake/eudsl_tblgen-config.cmake: -------------------------------------------------------------------------------- 1 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 | # See https://llvm.org/LICENSE.txt for license information. 3 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 | # Copyright (c) 2024. 5 | 6 | # copy-pasta from AddMLIR.cmake/AddLLVM.cmake/TableGen.cmake 7 | 8 | function(eudsl_tblgen target) 9 | cmake_parse_arguments(ARG "" "TD_FILE;OUTPUT_DIRECTORY;KIND" "INCLUDES;DEPENDS;INCLUDE;EXCLUDE" ${ARGN}) 10 | if (IS_ABSOLUTE ${ARG_TD_FILE}) 11 | set(EUDSL_TBLGEN_TD_FILE_INPUT_ABSOLUTE ${ARG_TD_FILE}) 12 | else() 13 | set(EUDSL_TBLGEN_TD_FILE_INPUT_ABSOLUTE ${CMAKE_CURRENT_SOURCE_DIR}/${ARG_TD_FILE}) 14 | endif() 15 | 16 | if (NOT EXISTS "${EUDSL_TBLGEN_TD_FILE_INPUT_ABSOLUTE}") 17 | message(FATAL_ERROR "${ARG_TD_FILE} @ ${EUDSL_TBLGEN_TD_FILE_INPUT_ABSOLUTE} does not exist") 18 | endif() 19 | 20 | get_directory_property(eudsl_tblgen_includes INCLUDE_DIRECTORIES) 21 | list(APPEND eudsl_tblgen_includes ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}) 22 | list(REMOVE_ITEM eudsl_tblgen_includes "") 23 | list(APPEND eudsl_tblgen_includes ${ARG_INCLUDES}) 24 | # list(TRANSFORM eudsl_tblgen_includes PREPEND -I) 25 | 26 | set(eudsl_tblgen_generate_cmd 27 | ${Python_EXECUTABLE} -Wignore -m eudsl_tblgen.mlir ${EUDSL_TBLGEN_TD_FILE_INPUT_ABSOLUTE} 28 | -k ${ARG_KIND} -I ${eudsl_tblgen_includes} 29 | -o "${ARG_OUTPUT_DIRECTORY}" 30 | --include ${ARG_INCLUDE} 31 | --exclude ${ARG_EXCLUDE} 32 | ) 33 | 34 | get_filename_component(_prefix ${EUDSL_TBLGEN_TD_FILE_INPUT_ABSOLUTE} NAME_WE) 35 | set(_output_files 36 | "${_prefix}_${ARG_KIND}_decls.h.inc" 37 | "${_prefix}_${ARG_KIND}_defns.cpp.inc" 38 | "${_prefix}_${ARG_KIND}_nbclasses.cpp.inc" 39 | ) 40 | list(TRANSFORM _output_files PREPEND "${ARG_OUTPUT_DIRECTORY}/") 41 | 42 | execute_process( 43 | COMMAND "${Python_EXECUTABLE}" -m eudsl_tblgen.mlir --help 44 | RESULT_VARIABLE _has_err_generate 45 | OUTPUT_QUIET 46 | # COMMAND_ECHO STDOUT 47 | ) 48 | if (_has_err_generate AND NOT _has_err_generate EQUAL 0) 49 | message(FATAL_ERROR "couldn't generate sources: ${_has_err_generate}") 50 | endif() 51 | if (_has_err_generate AND NOT _has_err_generate EQUAL 0) 52 | ################################## 53 | # not standalone build 54 | ################################## 55 | 56 | add_custom_command(OUTPUT ${_output_files} 57 | COMMAND ${eudsl_tblgen_generate_cmd} 58 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 59 | DEPENDS eudsl_tblgen_ext ${ARG_DEPENDS} 60 | COMMENT "eudsl-tblgen: Generating ${_output_files}..." 61 | ) 62 | else() 63 | message(STATUS "found EUDSL_TBLGEN_EXE") 64 | ################################## 65 | # standalone build 66 | ################################## 67 | execute_process( 68 | COMMAND ${eudsl_tblgen_generate_cmd} 69 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 70 | RESULT_VARIABLE _had_error_gen_cpp 71 | # COMMAND_ECHO STDOUT 72 | ) 73 | if (_had_error_gen_cpp AND NOT _had_error_gen_cpp EQUAL 0) 74 | message(FATAL_ERROR "failed to create ${_output_files}: ${_had_error_gen_cpp}") 75 | endif() 76 | endif() 77 | 78 | add_custom_target(${target} ALL DEPENDS ${_output_files}) 79 | 80 | # `make clean' must remove all those generated files: 81 | # TODO(max): clean up dep files 82 | set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 83 | APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${_output_files}) 84 | set_source_files_properties(${_output_files} PROPERTIES GENERATED 1) 85 | endfunction() 86 | -------------------------------------------------------------------------------- /projects/eudsl-tblgen/src/eudsl_tblgen/mlir/__init__.py: -------------------------------------------------------------------------------- 1 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 | # See https://llvm.org/LICENSE.txt for license information. 3 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 | # Copyright (c) 2025. 5 | import warnings 6 | from dataclasses import dataclass 7 | import re 8 | from functools import lru_cache 9 | from textwrap import dedent 10 | 11 | from .. import AttrOrTypeParameter 12 | 13 | 14 | # stolen from inflection 15 | def underscore(word: str) -> str: 16 | word = re.sub(r"([A-Z]+)([A-Z][a-z])", r"\1_\2", word) 17 | word = re.sub(r"([a-z\d])([A-Z])", r"\1_\2", word) 18 | word = word.replace("-", "_") 19 | return word.lower() 20 | 21 | 22 | def map_cpp_to_c_type(t): 23 | if t in {"unsigned", "bool", "int8_t", "int16_t", "int32_t", "int64_t"}: 24 | return t 25 | if t in {"RankedTensorType", "Type"}: 26 | return "MlirType" 27 | if t in {"Attribute", "CTALayoutAttr"}: 28 | return "MlirAttribute" 29 | warnings.warn(f"unrecognized cpp type {t}") 30 | return t 31 | 32 | 33 | element_ty_reg = re.compile(r"ArrayRef<(\w+)>") 34 | 35 | 36 | @dataclass(frozen=True) 37 | class Param: 38 | class_name: str 39 | param_name: str 40 | c_type: str 41 | cpp_type: str 42 | param_def: AttrOrTypeParameter 43 | 44 | @lru_cache(maxsize=1) 45 | def c_param_str(self): 46 | return f"{self.c_type} {self.param_name}" 47 | 48 | @property 49 | @lru_cache(maxsize=1) 50 | def getter_name(self): 51 | return f"mlir{self.class_name}Get{self.param_name}" 52 | 53 | # TODO(max): bad heuristic - should look inside param_def 54 | @lru_cache(maxsize=1) 55 | def needs_wrap_unwrap(self): 56 | return self.cpp_type != self.c_type 57 | 58 | @property 59 | @lru_cache(maxsize=1) 60 | def is_optional(self): 61 | return self.param_def.is_optional() 62 | 63 | @property 64 | @lru_cache(maxsize=1) 65 | def default_value(self): 66 | return self.param_def.get_default_value() 67 | 68 | 69 | @dataclass(frozen=True) 70 | class ArrayRefParam(Param): 71 | c_element_type: str 72 | 73 | @lru_cache(maxsize=1) 74 | def c_param_str(self): 75 | return f"{self.c_element_type} *{self.param_name}, unsigned n{self.param_name}s" 76 | 77 | 78 | def map_params(class_name, params: list[AttrOrTypeParameter]): 79 | mapped_params = [] 80 | for p in params: 81 | cpp_ty = p.get_cpp_type() 82 | p_name = p.get_name() 83 | if "ArrayRef" in cpp_ty: 84 | element_ty = element_ty_reg.findall(cpp_ty) 85 | assert len(element_ty) == 1, f"couldn't find unique element_ty for {cpp_ty}" 86 | element_ty = element_ty[0] 87 | mapped_params.append( 88 | ArrayRefParam( 89 | class_name, p_name, None, cpp_ty, p, map_cpp_to_c_type(element_ty) 90 | ) 91 | ) 92 | else: 93 | mapped_params.append( 94 | Param(class_name, p_name, map_cpp_to_c_type(cpp_ty), cpp_ty, p) 95 | ) 96 | 97 | return mapped_params 98 | 99 | 100 | try: 101 | from enum import StrEnum 102 | except ImportError: 103 | from enum import Enum 104 | 105 | class StrEnum(str, Enum): 106 | pass 107 | 108 | 109 | class CClassKind(StrEnum): 110 | ATTRIBUTE = "MlirAttribute" 111 | TYPE = "MlirType" 112 | 113 | 114 | def emit_c_attr_or_type_builder( 115 | cclass_kind: CClassKind, class_name, params: list[AttrOrTypeParameter] 116 | ): 117 | mapped_params = map_params(class_name, params) 118 | sig = f"""{cclass_kind} mlir{class_name}{cclass_kind.replace('Mlir', '')}Get({', '.join([p.c_param_str() for p in mapped_params])}, MlirContext mlirContext)""" 119 | decl = f"""MLIR_CAPI_EXPORTED {sig};""" 120 | defn = dedent( 121 | f""" 122 | {sig} {{ 123 | mlir::MLIRContext* context = unwrap(mlirContext); 124 | """ 125 | ) 126 | for p in mapped_params: 127 | if isinstance(p, ArrayRefParam): 128 | defn += f" {p.cpp_type} {p.param_name}_ = {{{p.param_name}, n{p.param_name}s}};\n" 129 | else: 130 | rhs = ( 131 | f"llvm::cast<{p.cpp_type}>(unwrap({p.param_name}))" 132 | if p.needs_wrap_unwrap() 133 | else p.param_name 134 | ) 135 | defn += f" {p.cpp_type} {p.param_name}_ = {rhs};\n" 136 | defn += f" return wrap({class_name}::get(context, {', '.join([p.param_name + '_' for p in mapped_params])}));\n" 137 | defn += "}" 138 | 139 | return decl, defn 140 | 141 | 142 | def emit_c_attr_or_type_field_getter( 143 | cclass_kind: CClassKind, class_name, param: AttrOrTypeParameter 144 | ): 145 | mapped_param = map_params(class_name, [param])[0] 146 | if isinstance(mapped_param, ArrayRefParam): 147 | sig = f"""void {mapped_param.getter_name}({cclass_kind} mlir{class_name}, {mapped_param.c_element_type}** {mapped_param.param_name}Ptr, unsigned *n{mapped_param.param_name}s)""" 148 | decl = f"MLIR_CAPI_EXPORTED {sig};" 149 | defn = dedent( 150 | f""" 151 | {sig} {{ 152 | {mapped_param.param_def.get_cpp_accessor_type()} {mapped_param.param_name} = llvm::cast<{class_name}>(unwrap(mlir{class_name})).{mapped_param.param_def.get_accessor_name()}(); 153 | *n{mapped_param.param_name}s = {mapped_param.param_name}.size(); 154 | *{mapped_param.param_name}Ptr = const_cast<{mapped_param.c_element_type}*>({mapped_param.param_name}.data()); 155 | }} 156 | """ 157 | ) 158 | else: 159 | sig = f"""{mapped_param.c_type} {mapped_param.getter_name}({cclass_kind} mlir{class_name})""" 160 | decl = f"""MLIR_CAPI_EXPORTED {sig};""" 161 | ret = f"llvm::cast<{class_name}>(unwrap(mlir{class_name})).{mapped_param.param_def.get_accessor_name()}()" 162 | if mapped_param.needs_wrap_unwrap(): 163 | ret = f"wrap({ret})" 164 | defn = dedent( 165 | f""" 166 | {sig} {{ 167 | return {ret}; 168 | }} 169 | """ 170 | ) 171 | 172 | return decl, defn 173 | 174 | 175 | def emit_attr_or_type_nanobind_class( 176 | cclass_kind: CClassKind, class_name, params: list[AttrOrTypeParameter] 177 | ): 178 | mapped_params = map_params(class_name, params) 179 | 180 | helper_decls = [] 181 | helper_defns = [] 182 | helper_decls.append( 183 | f"MLIR_CAPI_EXPORTED MlirTypeID mlir{class_name}GetTypeID(void);" 184 | ) 185 | helper_defns.append( 186 | dedent( 187 | f"""\ 188 | MlirTypeID mlir{class_name}GetTypeID() {{ 189 | return wrap({class_name}::getTypeID()); 190 | }} 191 | """ 192 | ) 193 | ) 194 | helper_decls.append( 195 | f"MLIR_CAPI_EXPORTED bool isaMlir{class_name}({cclass_kind} thing);" 196 | ) 197 | helper_defns.append( 198 | dedent( 199 | f"""\ 200 | bool isaMlir{class_name}({cclass_kind} thing) {{ 201 | return isa<{class_name}>(unwrap(thing)); 202 | }} 203 | """ 204 | ) 205 | ) 206 | 207 | params_str = [] 208 | for mp in mapped_params: 209 | if isinstance(mp, ArrayRefParam): 210 | typ = f"std::vector<{mp.c_element_type}>&" 211 | else: 212 | typ = f"{mp.c_type}" 213 | if mp.is_optional: 214 | typ = f"std::optional<{typ}>" 215 | params_str.append(f"{typ} {mp.param_name}") 216 | params_str = ", ".join(params_str) 217 | s = dedent( 218 | f""" 219 | auto nb{class_name} = {underscore(cclass_kind)}_subclass(m, "{class_name}", isaMlir{class_name}, mlir{class_name}GetTypeID); 220 | nb{class_name}.def_staticmethod("get", []({params_str}, MlirContext context) {{ 221 | """ 222 | ) 223 | 224 | arg_str = [] 225 | help_str = [] 226 | for mp in mapped_params: 227 | if isinstance(mp, ArrayRefParam): 228 | if mp.is_optional: 229 | arg_str.append( 230 | f"{mp.param_name}.has_value() ? {mp.param_name}->data() : nullptr, {mp.param_name}.has_value() ? {mp.param_name}->size() : 0" 231 | ) 232 | else: 233 | arg_str.append(f"{mp.param_name}.data(), {mp.param_name}.size()") 234 | else: 235 | if (default_val := mp.default_value) and mp.needs_wrap_unwrap(): 236 | default_val = f"wrap({default_val})" 237 | arg_str.append( 238 | f"{mp.param_name}.has_value() ? *{mp.param_name} : {default_val}" 239 | ) 240 | elif mp.default_value and not mp.needs_wrap_unwrap(): 241 | arg_str.append(f"*{mp.param_name}") 242 | else: 243 | arg_str.append(f"{mp.param_name}") 244 | 245 | if (default_val := mp.default_value) and not mp.needs_wrap_unwrap(): 246 | help_str.append(f'"{underscore(mp.param_name)}"_a = {default_val}') 247 | elif mp.is_optional: 248 | help_str.append(f'"{underscore(mp.param_name)}"_a = nb::none()') 249 | else: 250 | help_str.append(f'"{underscore(mp.param_name)}"_a') 251 | arg_str.append("context") 252 | arg_str = ", ".join(arg_str) 253 | 254 | help_str.append('"context"_a = nb::none()') 255 | help_str = ", ".join(help_str) 256 | 257 | s += dedent( 258 | f"""\ 259 | return mlir{class_name}{cclass_kind.replace('Mlir', '')}Get({arg_str}); 260 | }}, {help_str}); 261 | """ 262 | ) 263 | 264 | for mp in mapped_params: 265 | if isinstance(mp, ArrayRefParam): 266 | s += dedent( 267 | f""" 268 | nb{class_name}.def_property_readonly("{underscore(mp.param_name)}", []({cclass_kind} self) {{ 269 | unsigned n{mp.param_name}s; 270 | {mp.c_element_type}* {mp.param_name}Ptr; 271 | {mp.getter_name}(self, &{mp.param_name}Ptr, &n{mp.param_name}s); 272 | return std::vector<{mp.c_element_type}>{{{mp.param_name}Ptr, {mp.param_name}Ptr + n{mp.param_name}s}}; 273 | }}); 274 | """ 275 | ) 276 | else: 277 | s += dedent( 278 | f""" 279 | nb{class_name}.def_property_readonly("{underscore(mp.param_name)}", []({cclass_kind} self) {{ 280 | return {mp.getter_name}(self); 281 | }}); 282 | """ 283 | ) 284 | 285 | return helper_decls, helper_defns, s 286 | 287 | 288 | def emit_decls_defns_nbclasses( 289 | cclass_kind: CClassKind, defs, include=None, exclude=None 290 | ): 291 | if include or exclude: 292 | assert not (include and exclude), f"only include or exclude allowed" 293 | if exclude is None: 294 | exclude = set() 295 | decls = [] 296 | defns = [] 297 | nbclasses = [] 298 | for d in defs: 299 | name = d.get_name() 300 | if include is not None and name not in include: 301 | continue 302 | if d.get_name() in exclude: 303 | continue 304 | base_class_name = d.get_cpp_base_class_name() 305 | assert base_class_name in {"::mlir::Attribute", "::mlir::Type"} 306 | class_name = d.get_cpp_class_name() 307 | params = list(d.get_parameters()) 308 | if params: 309 | decl, defn = emit_c_attr_or_type_builder(cclass_kind, class_name, params) 310 | decls.append(decl) 311 | defns.append(defn) 312 | for p in params: 313 | decl, defn = emit_c_attr_or_type_field_getter( 314 | cclass_kind, class_name, p 315 | ) 316 | decls.append(decl) 317 | defns.append(defn) 318 | nbclass = emit_attr_or_type_nanobind_class(cclass_kind, class_name, params) 319 | nbclasses.append(nbclass) 320 | 321 | return decls, defns, nbclasses 322 | -------------------------------------------------------------------------------- /projects/eudsl-tblgen/src/eudsl_tblgen/mlir/__main__.py: -------------------------------------------------------------------------------- 1 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 | # See https://llvm.org/LICENSE.txt for license information. 3 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 | # Copyright (c) 2025. 5 | import argparse 6 | import enum 7 | from pathlib import Path 8 | 9 | from .. import ( 10 | RecordKeeper, 11 | collect_all_defs, 12 | collect_all_attr_or_type_defs, 13 | ) 14 | from . import emit_decls_defns_nbclasses, CClassKind 15 | 16 | 17 | # https://stackoverflow.com/a/60750535 18 | class EnumAction(argparse.Action): 19 | """ 20 | Argparse action for handling Enums 21 | """ 22 | 23 | def __init__(self, **kwargs): 24 | # Pop off the type value 25 | enum_type = kwargs.pop("type", None) 26 | 27 | # Ensure an Enum subclass is provided 28 | if enum_type is None: 29 | raise ValueError("type must be assigned an Enum when using EnumAction") 30 | if not issubclass(enum_type, enum.Enum): 31 | raise TypeError("type must be an Enum when using EnumAction") 32 | 33 | # Generate choices from the Enum 34 | kwargs.setdefault("choices", tuple(e.value for e in enum_type)) 35 | 36 | super(EnumAction, self).__init__(**kwargs) 37 | 38 | self._enum = enum_type 39 | 40 | def __call__(self, parser, namespace, values, option_string=None): 41 | # Convert value back into an Enum 42 | value = self._enum(values) 43 | setattr(namespace, self.dest, value) 44 | 45 | 46 | def emit_attrs_or_types( 47 | kind, rk, output_dir, output_prefix, include=None, exclude=None 48 | ): 49 | all_defs = collect_all_attr_or_type_defs(collect_all_defs(rk)) 50 | decls, defns, nbclasses = emit_decls_defns_nbclasses( 51 | kind, all_defs, include, exclude 52 | ) 53 | 54 | attr_decls = open(output_dir / f"{output_prefix}_{kind}_decls.h.inc", "w") 55 | attr_defns = open(output_dir / f"{output_prefix}_{kind}_defns.cpp.inc", "w") 56 | attr_nbclasses = open(output_dir / f"{output_prefix}_{kind}_nbclasses.cpp.inc", "w") 57 | for d in decls: 58 | if "LinearLayout" in d: 59 | continue 60 | print(d, file=attr_decls) 61 | for d in defns: 62 | if "LinearLayout" in d: 63 | continue 64 | print(d, file=attr_defns) 65 | for hdecls, hdefns, n in nbclasses: 66 | if "LinearLayout" in n: 67 | continue 68 | for h in hdecls: 69 | print(h, file=attr_decls) 70 | for h in hdefns: 71 | print(h, file=attr_defns) 72 | 73 | print(n, file=attr_nbclasses) 74 | 75 | 76 | def main(args): 77 | defs_rk = RecordKeeper().parse_td( 78 | str(args.td_file), 79 | [str(ip) for ip in args.include_paths], 80 | ) 81 | emit_attrs_or_types( 82 | args.kind, 83 | defs_rk, 84 | args.output_dir, 85 | args.output_prefix, 86 | include=args.include, 87 | exclude=args.exclude, 88 | ) 89 | 90 | 91 | if __name__ == "__main__": 92 | args = argparse.ArgumentParser() 93 | args.add_argument("td_file", type=Path) 94 | args.add_argument("-o", "--output-dir", type=Path, required=True) 95 | args.add_argument("-k", "--kind", type=CClassKind, action=EnumAction, required=True) 96 | args.add_argument("-I", "--include-paths", nargs="+", type=Path, required=True) 97 | args.add_argument("--exclude", nargs="*") 98 | args.add_argument("--include", nargs="*") 99 | 100 | args = args.parse_args() 101 | if args.include: 102 | args.include = set(args.include) 103 | else: 104 | args.include = None 105 | if args.exclude: 106 | args.exclude = set(args.exclude) 107 | else: 108 | args.exclude = None 109 | args.output_prefix = Path(args.td_file).stem 110 | 111 | main(args) 112 | -------------------------------------------------------------------------------- /projects/eudsl-tblgen/tests/td/BuiltinTypeInterfaces.td: -------------------------------------------------------------------------------- 1 | //===- BuiltinTypeInterfaces.td - Builtin type interfaces --*- tablegen -*-===// 2 | // 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 | // See https://llvm.org/LICENSE.txt for license information. 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | // 7 | //===----------------------------------------------------------------------===// 8 | // 9 | // This file contains definitions for type interfaces that closely interact with 10 | // attributes, types, and operations in the builtin dialect. 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #ifndef MLIR_IR_BUILTINTYPEINTERFACES_TD_ 15 | #define MLIR_IR_BUILTINTYPEINTERFACES_TD_ 16 | 17 | include "OpBase.td" 18 | 19 | def FloatTypeInterface : TypeInterface<"FloatType"> { 20 | let cppNamespace = "::mlir"; 21 | let description = [{ 22 | This type interface should be implemented by all floating-point types. It 23 | defines the LLVM APFloat semantics and provides a few helper functions. 24 | }]; 25 | 26 | let methods = [ 27 | InterfaceMethod< 28 | /*desc=*/[{ 29 | Returns the APFloat semantics for this floating-point type. 30 | }], 31 | /*retTy=*/"const ::llvm::fltSemantics &", 32 | /*methodName=*/"getFloatSemantics", 33 | /*args=*/(ins) 34 | >, 35 | InterfaceMethod< 36 | /*desc=*/[{ 37 | Returns a float type with bitwidth scaled by `scale`. Returns a "null" 38 | float type if the scaled element type cannot be represented. 39 | }], 40 | /*retTy=*/"::mlir::FloatType", 41 | /*methodName=*/"scaleElementBitwidth", 42 | /*args=*/(ins "unsigned":$scale), 43 | /*methodBody=*/"", 44 | /*defaultImplementation=*/"return ::mlir::FloatType();" 45 | > 46 | ]; 47 | 48 | let extraClassDeclaration = [{ 49 | /// Return the bitwidth of this float type. 50 | unsigned getWidth(); 51 | 52 | /// Return the width of the mantissa of this type. 53 | /// The width includes the integer bit. 54 | unsigned getFPMantissaWidth(); 55 | }]; 56 | } 57 | 58 | //===----------------------------------------------------------------------===// 59 | // MemRefElementTypeInterface 60 | //===----------------------------------------------------------------------===// 61 | 62 | def MemRefElementTypeInterface : TypeInterface<"MemRefElementTypeInterface"> { 63 | let cppNamespace = "::mlir"; 64 | let description = [{ 65 | Indication that this type can be used as element in memref types. 66 | 67 | Implementing this interface establishes a contract between this type and the 68 | memref type indicating that this type can be used as element of ranked or 69 | unranked memrefs. The type is expected to: 70 | 71 | - model an entity stored in memory; 72 | - have non-zero size. 73 | 74 | For example, scalar values such as integers can implement this interface, 75 | but indicator types such as `void` or `unit` should not. 76 | 77 | The interface currently has no methods and is used by types to opt into 78 | being memref elements. This may change in the future, in particular to 79 | require types to provide their size or alignment given a data layout. 80 | }]; 81 | } 82 | 83 | //===----------------------------------------------------------------------===// 84 | // ShapedType 85 | //===----------------------------------------------------------------------===// 86 | 87 | def ShapedTypeInterface : TypeInterface<"ShapedType"> { 88 | let cppNamespace = "::mlir"; 89 | let description = [{ 90 | This interface provides a common API for interacting with multi-dimensional 91 | container types. These types contain a shape and an element type. 92 | 93 | A shape is a list of sizes corresponding to the dimensions of the container. 94 | If the number of dimensions in the shape is unknown, the shape is "unranked". 95 | If the number of dimensions is known, the shape "ranked". The sizes of the 96 | dimensions of the shape must be positive, or kDynamic (in which case the 97 | size of the dimension is dynamic, or not statically known). 98 | }]; 99 | let methods = [ 100 | InterfaceMethod<[{ 101 | Returns a clone of this type with the given shape and element type. 102 | 103 | If no shape is provided, the shape of this type is used. In that case, if 104 | this type is unranked, so is the resulting type. 105 | 106 | If a shape is provided, the resulting type is always ranked, even if this 107 | type is unranked. 108 | }], 109 | "::mlir::ShapedType", "cloneWith", (ins 110 | "::std::optional<::llvm::ArrayRef>":$shape, 111 | "::mlir::Type":$elementType 112 | )>, 113 | 114 | InterfaceMethod<[{ 115 | Returns the element type of this shaped type. 116 | }], 117 | "::mlir::Type", "getElementType">, 118 | 119 | InterfaceMethod<[{ 120 | Returns if this type is ranked, i.e. it has a known number of dimensions. 121 | }], 122 | "bool", "hasRank">, 123 | 124 | InterfaceMethod<[{ 125 | Returns the shape of this type if it is ranked, otherwise asserts. 126 | }], 127 | "::llvm::ArrayRef", "getShape">, 128 | ]; 129 | 130 | let extraClassDeclaration = [{ 131 | static constexpr int64_t kDynamic = 132 | std::numeric_limits::min(); 133 | 134 | /// Whether the given dimension size indicates a dynamic dimension. 135 | static constexpr bool isDynamic(int64_t dValue) { 136 | return dValue == kDynamic; 137 | } 138 | 139 | /// Whether the given shape has any size that indicates a dynamic dimension. 140 | static bool isDynamicShape(ArrayRef dSizes) { 141 | return any_of(dSizes, [](int64_t dSize) { return isDynamic(dSize); }); 142 | } 143 | 144 | /// Return the number of elements present in the given shape. 145 | static int64_t getNumElements(ArrayRef shape); 146 | 147 | /// Return a clone of this type with the given new shape and element type. 148 | /// The returned type is ranked, even if this type is unranked. 149 | auto clone(::llvm::ArrayRef shape, Type elementType) { 150 | return cloneWith(shape, elementType); 151 | } 152 | 153 | /// Return a clone of this type with the given new shape. The returned type 154 | /// is ranked, even if this type is unranked. 155 | auto clone(::llvm::ArrayRef shape) { 156 | return cloneWith(shape, getElementType()); 157 | } 158 | }]; 159 | 160 | let extraSharedClassDeclaration = [{ 161 | /// Return a clone of this type with the given new element type. The 162 | /// returned type is ranked if and only if this type is ranked. In that 163 | /// case, the returned type has the same shape as this type. 164 | auto clone(::mlir::Type elementType) { 165 | return $_type.cloneWith(/*shape=*/std::nullopt, elementType); 166 | } 167 | 168 | /// If an element type is an integer or a float, return its width. Otherwise, 169 | /// abort. 170 | unsigned getElementTypeBitWidth() const { 171 | return $_type.getElementType().getIntOrFloatBitWidth(); 172 | } 173 | 174 | /// If this is a ranked type, return the rank. Otherwise, abort. 175 | int64_t getRank() const { 176 | assert($_type.hasRank() && "cannot query rank of unranked shaped type"); 177 | return $_type.getShape().size(); 178 | } 179 | 180 | /// If it has static shape, return the number of elements. Otherwise, abort. 181 | int64_t getNumElements() const { 182 | assert(hasStaticShape() && "cannot get element count of dynamic shaped type"); 183 | return ::mlir::ShapedType::getNumElements($_type.getShape()); 184 | } 185 | 186 | /// Returns true if this dimension has a dynamic size (for ranked types); 187 | /// aborts for unranked types. 188 | bool isDynamicDim(unsigned idx) const { 189 | assert(idx < getRank() && "invalid index for shaped type"); 190 | return ::mlir::ShapedType::isDynamic($_type.getShape()[idx]); 191 | } 192 | 193 | /// Returns if this type has a static shape, i.e. if the type is ranked and 194 | /// all dimensions have known size (>= 0). 195 | bool hasStaticShape() const { 196 | return $_type.hasRank() && 197 | !::mlir::ShapedType::isDynamicShape($_type.getShape()); 198 | } 199 | 200 | /// Returns if this type has a static shape and the shape is equal to 201 | /// `shape` return true. 202 | bool hasStaticShape(::llvm::ArrayRef shape) const { 203 | return hasStaticShape() && $_type.getShape() == shape; 204 | } 205 | 206 | /// If this is a ranked type, return the number of dimensions with dynamic 207 | /// size. Otherwise, abort. 208 | size_t getNumDynamicDims() const { 209 | return llvm::count_if($_type.getShape(), ::mlir::ShapedType::isDynamic); 210 | } 211 | 212 | /// If this is ranked type, return the size of the specified dimension. 213 | /// Otherwise, abort. 214 | int64_t getDimSize(unsigned idx) const { 215 | assert(idx < getRank() && "invalid index for shaped type"); 216 | return $_type.getShape()[idx]; 217 | } 218 | 219 | /// Returns the position of the dynamic dimension relative to just the dynamic 220 | /// dimensions, given its `index` within the shape. 221 | unsigned getDynamicDimIndex(unsigned index) const { 222 | assert(index < getRank() && "invalid index"); 223 | assert(::mlir::ShapedType::isDynamic(getDimSize(index)) && "invalid index"); 224 | return llvm::count_if($_type.getShape().take_front(index), 225 | ::mlir::ShapedType::isDynamic); 226 | } 227 | }]; 228 | } 229 | 230 | #endif // MLIR_IR_BUILTINTYPEINTERFACES_TD_ 231 | -------------------------------------------------------------------------------- /projects/eudsl-tblgen/tests/td/Constraints.td: -------------------------------------------------------------------------------- 1 | //===-- Constraints.td - Constraints definition file ----------------*- tablegen -*-===// 2 | // 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 | // See https://llvm.org/LICENSE.txt for license information. 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | // 7 | //===----------------------------------------------------------------------===// 8 | // 9 | // This file defines constraints/predicates for verifiers. 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #ifndef CONSTRAINTS 14 | #define CONSTRAINTS 15 | 16 | include "Utils.td" 17 | 18 | 19 | //===----------------------------------------------------------------------===// 20 | // Predicate definitions 21 | //===----------------------------------------------------------------------===// 22 | 23 | // Base class for logical predicates. 24 | // 25 | // Predicates are used to compose constraints (see next section for details). 26 | // There are two categories of predicates: 27 | // 28 | // 1. CPred: the primitive leaf predicate. 29 | // 2. Compound predicate: a predicate composed from child predicates using 30 | // predicate combiners ("conjunction", "disjunction", "negation" or 31 | // "substitution"). 32 | class Pred; 33 | 34 | // A logical predicate wrapping any C expression. 35 | // 36 | // This is the basis for composing more complex predicates. It is the "atom" 37 | // predicate from the perspective of TableGen and the "interface" between 38 | // TableGen and C++. What is inside is already C++ code, which will be treated 39 | // as opaque strings with special placeholders to be substituted. 40 | // 41 | // ## Special placeholders 42 | // 43 | // Special placeholders can be used to refer to entities in the context where 44 | // this predicate is used. They serve as "hooks" to the enclosing environment. 45 | // The following special placeholders are supported in constraints for an op: 46 | // 47 | // * `$_builder` will be replaced by a mlir::Builder instance. 48 | // * `$_op` will be replaced by the current operation. 49 | // * `$_self` will be replaced with the entity this predicate is attached to. 50 | // E.g., `BoolAttr` is an attribute constraint that wraps a 51 | // `CPred<"::llvm::isa($_self)">` (see the following sections for details). 52 | // Then for `F32:$attr`,`$_self` will be replaced by `$attr`. 53 | // For type constraints, it's a little bit special since we want the 54 | // constraints on each type definition reads naturally and we want to attach 55 | // type constraints directly to an operand/result, $_self will be replaced 56 | // by the operand/result's type. E.g., for `F32` in `F32:$operand`, its 57 | // `$_self` will be expanded as `getOperand(...).getType()`. 58 | // 59 | // One thing to be noticed, while using these placeholders in the C expression, 60 | // the type of placeholder is only guaranteed to be the base type. For example, 61 | // if you have a predicate in the form `CPred<"CheckType($_self)">, the argument 62 | // type of the function `CheckType` should be `mlir::Type`. 63 | class CPred : Pred { 64 | code predExpr = "(" # pred # ")"; 65 | } 66 | 67 | // Kinds of predicate combiners. These must closely match the predicates 68 | // implemented by the C++ backend (tblgen::PredCombinerKind). 69 | class PredCombinerKind; 70 | def PredCombinerAnd : PredCombinerKind; 71 | def PredCombinerOr : PredCombinerKind; 72 | def PredCombinerNot : PredCombinerKind; 73 | def PredCombinerSubstLeaves : PredCombinerKind; 74 | def PredCombinerConcat : PredCombinerKind; 75 | 76 | // A predicate that combines other predicates as defined by PredCombinerKind. 77 | // Instantiated below. 78 | class CombinedPred c> : Pred { 79 | PredCombinerKind kind = k; 80 | list children = c; 81 | } 82 | 83 | // Predicate combiners 84 | 85 | // A predicate that holds if all of its children hold. Always holds for zero 86 | // children. 87 | class And children> : CombinedPred; 88 | 89 | // A predicate that holds if any of its children hold. Never holds for zero 90 | // children. 91 | class Or children> : CombinedPred; 92 | 93 | // A predicate that holds if its child does not. 94 | class Neg : CombinedPred; 95 | 96 | // A predicate that substitutes "pat" with "repl" in predicate calls of the 97 | // leaves of the predicate tree (i.e., not CombinedPred). 98 | // 99 | // This is plain string substitution without regular expressions or captures. 100 | // New predicates with more complex logical can be introduced should the need 101 | // arise. 102 | class SubstLeaves 103 | : CombinedPred { 104 | string pattern = pat; 105 | string replacement = repl; 106 | } 107 | 108 | // A predicate that prepends `pre` and appends `suf` to the final predicate 109 | // string composed from `child`. This is plain string concatenation and there 110 | // will be no substitution happening for `pre` and `suf`. 111 | class Concat : 112 | CombinedPred { 113 | string prefix = pre; 114 | string suffix = suf; 115 | } 116 | 117 | //===----------------------------------------------------------------------===// 118 | // Constraint definitions 119 | //===----------------------------------------------------------------------===// 120 | 121 | // TODO: Merge Constraints into Pred. 122 | 123 | // Base class for named constraints. 124 | // 125 | // An op's operands/attributes/results can have various requirements, e.g., 126 | // having certain types, having values inside a certain range, and so on. 127 | // Besides, for a graph rewrite rule, the source pattern used to match against 128 | // the existing graph has conditions, like the op's operand must be of a more 129 | // constrained subtype, the attribute must have a certain value, and so on. 130 | // 131 | // These requirements and conditions are modeled using this class. Records of 132 | // this class are used to generate verification code in op verifier, and 133 | // matching code in pattern matcher. 134 | // 135 | // Constraints are predicates with descriptive names, to facilitate inspection, 136 | // provide nice error messages, etc. 137 | class Constraint { 138 | // The predicates that this constraint requires. 139 | Pred predicate = pred; 140 | // User-readable one line summary used in error reporting messages. If empty, 141 | // a generic message will be used. 142 | string summary = desc; 143 | } 144 | 145 | // Subclasses used to differentiate different constraint kinds. These are used 146 | // as markers for the TableGen backend to handle different constraint kinds 147 | // differently if needed. Constraints not deriving from the following subclasses 148 | // are considered as uncategorized constraints. 149 | 150 | // Subclass for constraints on a type. 151 | class TypeConstraint : 154 | Constraint { 155 | // The name of the C++ Type class if known, or Type if not. 156 | string cppType = cppTypeParam; 157 | // The name of the C++ function that is generated for this type constraint. 158 | // If empty, no C++ function is generated. 159 | string cppFunctionName = cppFunctionNameParam; 160 | } 161 | 162 | // Subclass for constraints on an attribute. 163 | class AttrConstraint : 164 | Constraint; 165 | 166 | // Subclass for constraints on a region. 167 | class RegionConstraint : 168 | Constraint; 169 | 170 | // Subclass for constraints on a successor. 171 | class SuccessorConstraint : 172 | Constraint; 173 | 174 | // How to use these constraint categories: 175 | // 176 | // * Use TypeConstraint to specify 177 | // * Constraints on an op's operand/result definition 178 | // * Further constraints to match an op's operand/result in source pattern 179 | // 180 | // * Use Attr (a subclass for AttrConstraint) for 181 | // * Constraints on an op's attribute definition 182 | // * Use AttrConstraint to specify 183 | // * Further constraints to match an op's attribute in source pattern 184 | // 185 | // * Use uncategorized constraint to specify 186 | // * Multi-entity constraints in rewrite rules 187 | 188 | #endif // CONSTRAINTS 189 | -------------------------------------------------------------------------------- /projects/eudsl-tblgen/tests/td/DialectBase.td: -------------------------------------------------------------------------------- 1 | //===-- DialectBase.td - Base Dialect definition file ------*- tablegen -*-===// 2 | // 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 | // See https://llvm.org/LICENSE.txt for license information. 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | // 7 | //===----------------------------------------------------------------------===// 8 | // 9 | // This file contains the base set of constructs for defining Dialect classes. 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #ifndef DIALECTBASE_TD 14 | #define DIALECTBASE_TD 15 | 16 | include "Utils.td" 17 | 18 | //===----------------------------------------------------------------------===// 19 | // Dialect definitions 20 | //===----------------------------------------------------------------------===// 21 | 22 | class Dialect { 23 | // The name of the dialect. 24 | string name = ?; 25 | 26 | // Short summary of the dialect. 27 | string summary = ?; 28 | 29 | // The description of the dialect. 30 | string description = ?; 31 | 32 | // A list of dialects this dialect will load on construction as dependencies. 33 | // These are dialects that this dialect may involve in canonicalization 34 | // pattern or interfaces. 35 | list dependentDialects = []; 36 | 37 | // A list of key/value pair representing an attribute type and a name. 38 | // This will generate helper classes on the dialect to be able to 39 | // manage discardable attributes on operations in a type safe way. 40 | dag discardableAttrs = (ins); 41 | 42 | // The C++ namespace that ops of this dialect should be placed into. 43 | // 44 | // By default, uses the name of the dialect as the only namespace. To avoid 45 | // placing in any namespace, use "". To specify nested namespaces, use "::" 46 | // as the delimiter, e.g., given "A::B", ops will be placed in 47 | // `namespace A { namespace B { } }`. 48 | // 49 | // Note that this works in conjunction with dialect C++ code. Depending on how 50 | // the generated files are included into the dialect, you may want to specify 51 | // a full namespace path or a partial one. 52 | string cppNamespace = name; 53 | 54 | // An optional code block containing extra declarations to place in the 55 | // dialect declaration. 56 | code extraClassDeclaration = ""; 57 | 58 | // If this dialect overrides the hook for materializing constants. 59 | bit hasConstantMaterializer = 0; 60 | 61 | /// If the dialect definition provides a non-default destructor. 62 | /// If false, a default destructor implementation will be generated. 63 | bit hasNonDefaultDestructor = 0; 64 | 65 | // If this dialect overrides the hook for verifying operation attributes. 66 | bit hasOperationAttrVerify = 0; 67 | 68 | // If this dialect overrides the hook for verifying region argument 69 | // attributes. 70 | bit hasRegionArgAttrVerify = 0; 71 | 72 | // If this dialect overrides the hook for verifying region result attributes. 73 | bit hasRegionResultAttrVerify = 0; 74 | 75 | // If this dialect overrides the hook for op interface fallback. 76 | bit hasOperationInterfaceFallback = 0; 77 | 78 | // If this dialect should use default generated attribute parser boilerplate. 79 | // When set, ODS will generate declarations for the attribute parsing and 80 | // printing hooks in the dialect and default implementations that dispatch to 81 | // each individual attribute directly. 82 | bit useDefaultAttributePrinterParser = 0; 83 | 84 | // If this dialect should use default generated type parser boilerplate: 85 | // When set, ODS will generate declarations for the type parsing and printing 86 | // hooks in the dialect and default implementations that dispatch to each 87 | // individual type directly. 88 | bit useDefaultTypePrinterParser = 0; 89 | 90 | // If this dialect overrides the hook for canonicalization patterns. 91 | bit hasCanonicalizer = 0; 92 | 93 | // If this dialect can be extended at runtime with new operations or types. 94 | bit isExtensible = 0; 95 | 96 | // Whether inherent Attributes defined in ODS will be stored as Properties. 97 | bit usePropertiesForAttributes = 1; 98 | } 99 | 100 | #endif // DIALECTBASE_TD 101 | -------------------------------------------------------------------------------- /projects/eudsl-tblgen/tests/td/Interfaces.td: -------------------------------------------------------------------------------- 1 | //===-- Interfaces.td - Interfaces defination file ------------------*- tablegen -*-===// 2 | // 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 | // See https://llvm.org/LICENSE.txt for license information. 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | // 7 | //===----------------------------------------------------------------------===// 8 | // 9 | // This file contains definations for Interfaces. 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #ifndef INTERFACES_TD 14 | #define INTERFACES_TD 15 | 16 | include "AttrTypeBase.td" 17 | include "Constraints.td" 18 | include "Traits.td" 19 | 20 | //===----------------------------------------------------------------------===// 21 | // Interface definitions 22 | //===----------------------------------------------------------------------===// 23 | 24 | // InterfaceTrait corresponds to a specific 'Interface' class defined in C++. 25 | // The purpose to wrap around C++ symbol string with this class is to make 26 | // interfaces specified for ops in TableGen less alien and more integrated. 27 | class InterfaceTrait : NativeTrait<"", ""> { 28 | let trait = name # "::Trait"; 29 | let cppNamespace = ""; 30 | 31 | // An optional code block containing extra declarations to place in the 32 | // interface trait declaration. 33 | code extraTraitClassDeclaration = ""; 34 | } 35 | 36 | // OpInterfaceTrait corresponds to a specific 'OpInterface' class defined in 37 | // C++. The purpose to wrap around C++ symbol string with this class is to make 38 | // interfaces specified for ops in TableGen less alien and more integrated. 39 | class OpInterfaceTrait traits = []> 41 | : InterfaceTrait { 42 | // Specify the body of the verification function. `$_op` will be replaced with 43 | // the operation being verified. 44 | code verify = verifyBody; 45 | 46 | // A bit indicating if the verifier needs to access the ops in the regions. If 47 | // it set to `1`, the region ops will be verified before invoking this 48 | // verifier. 49 | bit verifyWithRegions = 0; 50 | 51 | // Specify the list of traits that need to be verified before the verification 52 | // of this OpInterfaceTrait. 53 | list dependentTraits = traits; 54 | } 55 | 56 | // This class represents a single, optionally static, interface method. 57 | // Note: non-static interface methods have an implicit parameter, either 58 | // $_op/$_attr/$_type corresponding to an instance of the derived value. 59 | class InterfaceMethod { 62 | // A human-readable description of what this method does. 63 | string description = desc; 64 | 65 | // The name of the interface method. 66 | string name = methodName; 67 | 68 | // The c++ type-name of the return type. 69 | string returnType = retTy; 70 | 71 | // A dag of string that correspond to the arguments of the method. 72 | dag arguments = args; 73 | 74 | // An optional body to the method. 75 | code body = methodBody; 76 | 77 | // An optional default implementation of the method. 78 | code defaultBody = defaultImplementation; 79 | } 80 | 81 | // This class represents a single static interface method. 82 | class StaticInterfaceMethod 85 | : InterfaceMethod; 87 | 88 | // Interface represents a base interface. 89 | class Interface baseInterfacesArg = []> { 90 | // A human-readable description of what this interface does. 91 | string description = ""; 92 | 93 | // The name given to the c++ interface class. 94 | string cppInterfaceName = name; 95 | 96 | // The C++ namespace that this interface should be placed into. 97 | // 98 | // To specify nested namespaces, use "::" as the delimiter, e.g., given 99 | // "A::B", ops will be placed in `namespace A { namespace B { } }`. 100 | string cppNamespace = ""; 101 | 102 | // The list of methods defined by this interface. 103 | list methods = []; 104 | 105 | // An optional code block containing extra declarations to place in the 106 | // interface declaration. 107 | code extraClassDeclaration = ""; 108 | 109 | // An optional code block containing extra declarations to place in both 110 | // the interface and trait declaration. 111 | code extraSharedClassDeclaration = ""; 112 | 113 | // An optional code block for adding additional "classof" logic. This can 114 | // be used to better enable "optional" interfaces, where an entity only 115 | // implements the interface if some dynamic characteristic holds. 116 | // `$_attr`/`$_op`/`$_type` may be used to refer to an instance of the 117 | // interface instance being checked. 118 | code extraClassOf = ""; 119 | 120 | // An optional set of base interfaces that this interface 121 | // "derives" from. 122 | list baseInterfaces = baseInterfacesArg; 123 | } 124 | 125 | // AttrInterface represents an interface registered to an attribute. 126 | class AttrInterface baseInterfaces = []> 127 | : Interface, InterfaceTrait, 128 | Attr($_self)">, 130 | name # " instance" 131 | > { 132 | let storageType = !if(!empty(cppNamespace), "", cppNamespace # "::") # name; 133 | let returnType = storageType; 134 | let convertFromStorage = "$_self"; 135 | } 136 | 137 | // OpInterface represents an interface registered to an operation. 138 | class OpInterface baseInterfaces = []> 139 | : Interface, OpInterfaceTrait; 140 | 141 | // TypeInterface represents an interface registered to a type. 142 | class TypeInterface baseInterfaces = []> 143 | : Interface, InterfaceTrait, 144 | Type($_self)">, 146 | name # " instance", 147 | !if(!empty(cppNamespace),"", cppNamespace # "::") # name 148 | >; 149 | 150 | // Whether to declare the interface methods in the user entity's header. This 151 | // class simply wraps an Interface but is used to indicate that the method 152 | // declarations should be generated. This class takes an optional set of methods 153 | // that should have declarations generated even if the method has a default 154 | // implementation. 155 | class DeclareInterfaceMethods overridenMethods = []> { 156 | // This field contains a set of method names that should always have their 157 | // declarations generated. This allows for generating declarations for 158 | // methods with default implementations that need to be overridden. 159 | list alwaysOverriddenMethods = overridenMethods; 160 | } 161 | class DeclareAttrInterfaceMethods overridenMethods = []> 163 | : DeclareInterfaceMethods, 164 | AttrInterface { 165 | let description = interface.description; 166 | let cppInterfaceName = interface.cppInterfaceName; 167 | let cppNamespace = interface.cppNamespace; 168 | let methods = interface.methods; 169 | let baseInterfaces = interface.baseInterfaces; 170 | } 171 | class DeclareOpInterfaceMethods overridenMethods = []> 173 | : DeclareInterfaceMethods, 174 | OpInterface { 175 | let description = interface.description; 176 | let cppInterfaceName = interface.cppInterfaceName; 177 | let cppNamespace = interface.cppNamespace; 178 | let methods = interface.methods; 179 | let baseInterfaces = interface.baseInterfaces; 180 | } 181 | class DeclareTypeInterfaceMethods overridenMethods = []> 183 | : DeclareInterfaceMethods, 184 | TypeInterface { 185 | let description = interface.description; 186 | let cppInterfaceName = interface.cppInterfaceName; 187 | let cppNamespace = interface.cppNamespace; 188 | let methods = interface.methods; 189 | let baseInterfaces = interface.baseInterfaces; 190 | } 191 | 192 | #endif // INTERFACES_TD 193 | -------------------------------------------------------------------------------- /projects/eudsl-tblgen/tests/td/JSON.td: -------------------------------------------------------------------------------- 1 | // adapted from llvm/test/TableGen/JSON.td 2 | 3 | class Base {} 4 | class Intermediate : Base {} 5 | class Derived : Intermediate {} 6 | 7 | def D : Intermediate {} 8 | 9 | def ExampleDagOp; 10 | 11 | def FieldKeywordTest { 12 | int a; 13 | field int b; 14 | } 15 | 16 | class Variables { 17 | int i; 18 | string s; 19 | bit b; 20 | bits<8> bs; 21 | code c; 22 | list li; 23 | Base base; 24 | dag d; 25 | } 26 | def VarNull : Variables {} 27 | def VarPrim : Variables { 28 | int i = 3; 29 | int enormous_pos = 9123456789123456789; 30 | int enormous_neg = -9123456789123456789; 31 | string s = "hello, world"; 32 | bit b = 0; 33 | bits<8> bs = { 0,0,0,1,0,1,1,1 }; 34 | code c = [{ void }]; 35 | list li = [ 1, 2, 3, 4 ]; 36 | } 37 | def VarObj : Variables { 38 | Base base = D; 39 | dag d = (ExampleDagOp 22, "hello":$foo); 40 | int undef_int; 41 | field int ref_int = undef_int; 42 | bits<2> undef_bits; 43 | bits<4> ref_bits; 44 | let ref_bits{3...2} = 0b10; 45 | let ref_bits{1...0} = undef_bits{1...0}; 46 | field int complex_ref_int = !add(undef_int, 2); 47 | } 48 | 49 | def Named { int AnonTestField = 1; } 50 | def { int AnonTestField = 2; } 51 | -------------------------------------------------------------------------------- /projects/eudsl-tblgen/tests/td/TestDialect.td: -------------------------------------------------------------------------------- 1 | include "OpBase.td" 2 | include "AttrTypeBase.td" 3 | 4 | def Test_Dialect : Dialect { 5 | let name = "test"; 6 | } 7 | 8 | class Test_Type traits = []> 9 | : TypeDef { 10 | let mnemonic = typeMnemonic; 11 | } 12 | 13 | class Test_Attr : AttrDef { 14 | let mnemonic = attrMnemonic; 15 | } 16 | 17 | class Test_Op traits = []> 18 | : Op; 19 | 20 | def Test_SingletonAType : Test_Type<"SingletonAType", "singleton_a"> {} 21 | def Test_SingletonBType : Test_Type<"SingletonBType", "singleton_b"> {} 22 | def Test_SingletonCType : Test_Type<"SingletonCType", "singleton_c"> {} 23 | def Test_TestAttr : Test_Attr<"Test", "test"> {} 24 | 25 | 26 | def Test_AndOp : Test_Op<"and"> { 27 | let arguments = (ins AllOfType<[Test_SingletonAType, AnyType]>:$in); 28 | } 29 | 30 | 31 | def Test_AnyOp : Test_Op<"any"> { 32 | let arguments = (ins AnyType:$in); 33 | } 34 | 35 | def Test_AttributesOp : Test_Op<"attributes"> { 36 | let arguments = (ins I16Attr:$int_attr, 37 | Test_TestAttr:$test_attr); 38 | } 39 | 40 | def Test_ConfinedOp : Test_Op<"confined"> { 41 | let arguments = (ins ConfinedType($_self)">]>:$tensor, 42 | ConfinedType($_self)"> 43 | , CPred<"::llvm::cast<::mlir::VectorType>($_self).getRank() > 0">]>]>:$vector); 44 | } 45 | 46 | def Test_Integers : Test_Op<"integers"> { 47 | let arguments = (ins AnyI8:$any_int, 48 | AnyInteger:$any_integer); 49 | } 50 | 51 | def Test_OrOp : Test_Op<"or"> { 52 | let arguments = (ins AnyTypeOf<[Test_SingletonAType, Test_SingletonBType, Test_SingletonCType]>:$in); 53 | } 54 | 55 | def Test_RegionsOp : Test_Op<"regions"> { 56 | let regions = (region AnyRegion:$any_region, 57 | SizedRegion<1>:$single_block_region); 58 | } 59 | 60 | def Test_TypesOp : Test_Op<"types"> { 61 | let arguments = (ins I32:$a, 62 | SI64:$b, 63 | UI8:$c, 64 | Index:$d, 65 | F32:$e, 66 | NoneType:$f, 67 | Complex); 68 | } 69 | 70 | def Test_VariadicityOp : Test_Op<"variadicity"> { 71 | let arguments = (ins Variadic:$variadic, 72 | Optional:$optional, 73 | Test_SingletonCType:$required); 74 | } 75 | -------------------------------------------------------------------------------- /projects/eudsl-tblgen/tests/td/Traits.td: -------------------------------------------------------------------------------- 1 | //===-- Traits.td - Trait definations file ------------------*- tablegen -*-===// 2 | // 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 | // See https://llvm.org/LICENSE.txt for license information. 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | // 7 | //===----------------------------------------------------------------------===// 8 | // 9 | // This file contains definations for traits. 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #ifndef TRAITS_TD 14 | #define TRAITS_TD 15 | 16 | include "Constraints.td" 17 | 18 | //===----------------------------------------------------------------------===// 19 | // Trait definitions 20 | //===----------------------------------------------------------------------===// 21 | 22 | // Trait represents a trait regarding an attribute, operation, or type. 23 | class Trait; 24 | 25 | // Define a Trait corresponding to a list of Traits, this allows for specifying 26 | // a list of traits as trait. Avoids needing to do `[Traits, ...] # ListOfTraits 27 | // # [Others, ...]` while still allowing providing convenient groupings. 28 | class TraitList props> : Trait { 29 | list traits = props; 30 | } 31 | 32 | // NativeTrait corresponds to the MLIR C++ trait mechanism. The purpose to wrap 33 | // around C++ symbol string with this class is to make traits specified for 34 | // entities in TableGen less alien and more integrated. 35 | // `extraConcreteClassDeclaration` and `extraConcreteClassDefinition` code 36 | // get injected into the entities in which the NativeTrait is specified for. 37 | class NativeTrait : Trait { 40 | string trait = name; 41 | string cppNamespace = "::mlir::" # entityType # "Trait"; 42 | 43 | code extraConcreteClassDeclaration = extraClassDeclaration; 44 | code extraConcreteClassDefinition = extraClassDefinition; 45 | } 46 | 47 | // ParamNativeTrait corresponds to the template-parameterized traits in the C++ 48 | // implementation. MLIR uses nested class templates to implement such traits 49 | // leading to constructs of the form "TraitName::Impl". Use the 50 | // value in `prop` as the trait name and the value in `params` as parameters to 51 | // construct the native trait class name. 52 | class ParamNativeTrait 53 | : NativeTrait::Impl", entityType>; 54 | 55 | // GenInternalTrait is a trait that does not have direct C++ mapping but affects 56 | // an entities definition generator internals, like how operation builders and 57 | // operand/attribute/result getters are generated. 58 | class GenInternalTrait : Trait { 59 | string trait = "::mlir::" # entityType # "Trait::" # prop; 60 | } 61 | 62 | // PredTrait is a trait implemented by way of a predicate on an entity. 63 | class PredTrait : Trait { 64 | string summary = descr; 65 | Pred predicate = pred; 66 | } 67 | 68 | #endif // TRAITS_TD 69 | -------------------------------------------------------------------------------- /projects/eudsl-tblgen/tests/td/TritonDialect.td: -------------------------------------------------------------------------------- 1 | #ifndef TRITON_DIALECT 2 | #define TRITON_DIALECT 3 | 4 | include "OpBase.td" 5 | 6 | def Triton_Dialect : Dialect { 7 | let name = "tt"; 8 | 9 | let cppNamespace = "::mlir::triton"; 10 | 11 | let summary = "The Triton IR in MLIR"; 12 | 13 | let description = [{ 14 | Triton Dialect. 15 | 16 | Dependent Dialects: 17 | * Arith: 18 | * addf, addi, andi, cmpf, cmpi, divf, fptosi, ... 19 | * Math: 20 | * exp, sin, cos, log, ... 21 | * StructuredControlFlow: 22 | * for, if, while, yield, condition 23 | * ControlFlow: 24 | * br, cond_br 25 | }]; 26 | 27 | let dependentDialects = [ 28 | "arith::ArithDialect", 29 | "math::MathDialect", 30 | "scf::SCFDialect", 31 | "cf::ControlFlowDialect", 32 | "ub::UBDialect" 33 | ]; 34 | 35 | let extraClassDeclaration = [{ 36 | void registerTypes(); 37 | }]; 38 | 39 | let hasConstantMaterializer = 1; 40 | let useDefaultTypePrinterParser = 1; 41 | let usePropertiesForAttributes = 1; 42 | } 43 | 44 | include "triton/Dialect/Triton/IR/TritonTypes.td" 45 | 46 | 47 | #endif // TRITON_DIALECT 48 | -------------------------------------------------------------------------------- /projects/eudsl-tblgen/tests/td/TritonGPUDialect.td: -------------------------------------------------------------------------------- 1 | #ifndef TRITONGPU_DIALECT 2 | #define TRITONGPU_DIALECT 3 | 4 | include "OpBase.td" 5 | 6 | def TritonGPU_Dialect : Dialect { 7 | let name = "ttg"; 8 | 9 | let cppNamespace = "::mlir::triton::gpu"; 10 | 11 | let hasOperationAttrVerify = 1; 12 | 13 | let description = [{ 14 | Triton GPU Dialect. 15 | }]; 16 | 17 | let dependentDialects = [ 18 | "triton::TritonDialect", 19 | "mlir::gpu::GPUDialect", 20 | ]; 21 | 22 | let extraClassDeclaration = [{ 23 | void registerTypes(); 24 | 25 | LinearLayout toLinearLayout(ArrayRef shape, Attribute layout); 26 | 27 | static int getNumCTAs(ModuleOp mod); 28 | static int getThreadsPerWarp(ModuleOp mod); 29 | 30 | private: 31 | LinearLayoutCache llCache; 32 | }]; 33 | 34 | let useDefaultTypePrinterParser = 1; 35 | let useDefaultAttributePrinterParser = 1; 36 | let usePropertiesForAttributes = 1; 37 | } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /projects/eudsl-tblgen/tests/td/TritonGPUTypes.td: -------------------------------------------------------------------------------- 1 | #ifndef TRITONGPU_TYPES 2 | #define TRITONGPU_TYPES 3 | 4 | include "AttrTypeBase.td" 5 | include "BuiltinTypeInterfaces.td" 6 | include "TritonGPUDialect.td" 7 | 8 | class TTG_TypeDef traits = []> 9 | : TypeDef { 10 | let mnemonic = _mnemonic; 11 | } 12 | 13 | def TTG_AsyncToken : TTG_TypeDef<"AsyncToken", "async.token", []> { 14 | } 15 | 16 | // Memory descriptor type. 17 | def TTG_MemDescType : TTG_TypeDef<"MemDesc", "memdesc", [ShapedTypeInterface]> { 18 | let parameters = (ins 19 | ArrayRefParameter<"int64_t">:$shape, 20 | "Type":$elementType, 21 | "Attribute":$encoding, 22 | "Attribute":$memorySpace, 23 | "bool":$mutableMemory, 24 | ArrayRefParameter<"int64_t">:$allocShape 25 | ); 26 | 27 | let extraClassDeclaration = [{ 28 | MemDescType cloneWith(std::optional> shape, 29 | Type elementType) const { 30 | return MemDescType::get(shape.value_or(getShape()), elementType, getEncoding(), getMemorySpace(), getMutableMemory(), getAllocShape()); 31 | } 32 | 33 | bool hasRank() const { return true; } 34 | }]; 35 | 36 | let builders = [ 37 | TypeBuilderWithInferredContext<(ins 38 | "llvm::ArrayRef":$shape, 39 | "Type":$elementType, 40 | "Attribute":$encoding, 41 | "Attribute":$memorySpace 42 | ), [{ 43 | return $_get(elementType.getContext(), shape, elementType, encoding, memorySpace, /*mutableMemory=*/false, /*allocShape=*/shape); 44 | }]>, 45 | TypeBuilderWithInferredContext<(ins 46 | "llvm::ArrayRef":$shape, 47 | "Type":$elementType, 48 | "Attribute":$encoding, 49 | "Attribute":$memorySpace, 50 | "bool":$mutableMemory 51 | ), [{ 52 | return $_get(elementType.getContext(), shape, elementType, encoding, memorySpace, mutableMemory, /*allocShape=*/shape); 53 | }]>, 54 | TypeBuilderWithInferredContext<(ins 55 | "llvm::ArrayRef":$shape, 56 | "Type":$elementType, 57 | "Attribute":$encoding, 58 | "Attribute":$memorySpace, 59 | "bool":$mutableMemory, 60 | "llvm::ArrayRef":$allocShape 61 | ), [{ 62 | return $_get(elementType.getContext(), shape, elementType, encoding, memorySpace, mutableMemory, allocShape); 63 | }]> 64 | 65 | ]; 66 | 67 | let hasCustomAssemblyFormat = 1; 68 | let genVerifyDecl = 1; 69 | } 70 | 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /projects/eudsl-tblgen/tests/td/TritonInterfaces.td: -------------------------------------------------------------------------------- 1 | #ifndef TRITON_INTERFACES 2 | #define TRITON_INTERFACES 3 | 4 | include "OpBase.td" 5 | include "InferTypeOpInterface.td" 6 | 7 | def TensorSizeTrait : NativeOpTrait<"TensorSizeTrait">; 8 | def VerifyTensorLayoutsTrait : NativeOpTrait<"VerifyTensorLayoutsTrait">; 9 | def SameOperandsEncoding : NativeOpTrait<"SameOperandsEncoding">; 10 | def SameOperandsAndResultEncoding : NativeOpTrait<"SameOperandsAndResultEncoding">; 11 | def SameLoadStoreOperandsShape : NativeOpTrait<"SameLoadStoreOperandsShape">; 12 | def SameLoadStoreOperandsAndResultShape : NativeOpTrait<"SameLoadStoreOperandsAndResultShape">; 13 | def SameLoadStoreOperandsEncoding : NativeOpTrait<"SameLoadStoreOperandsEncoding">; 14 | def SameLoadStoreOperandsAndResultEncoding : NativeOpTrait<"SameLoadStoreOperandsAndResultEncoding">; 15 | 16 | // A trait equivalent to InferTypeOpAdaptor, but that checks for structural 17 | // equivalence of the layouts of the result rather than just layout equality. 18 | def InferTypeOpWithLayoutEquivalence : InferTypeOpAdaptorBase<[{ 19 | static bool isCompatibleReturnTypes(TypeRange lhs, TypeRange rhs) { 20 | if (lhs.size() != rhs.size()) 21 | return false; 22 | return llvm::all_of(llvm::zip(lhs, rhs), [](auto tup) { 23 | auto [lhs, rhs] = tup; 24 | return succeeded(OpTrait::impl::verifyEquivalentType(lhs, rhs)); 25 | }); 26 | } 27 | }]>; 28 | 29 | #endif // TRITON_INTERFACES 30 | -------------------------------------------------------------------------------- /projects/eudsl-tblgen/tests/td/TritonTypes.td: -------------------------------------------------------------------------------- 1 | #ifndef TRITON_TYPES 2 | #define TRITON_TYPES 3 | 4 | include "AttrTypeBase.td" 5 | include "BuiltinTypeInterfaces.td" 6 | include "TritonDialect.td" 7 | 8 | // 9 | // Types 10 | // 11 | class TritonTypeDef traits = []> 12 | : TypeDef { 13 | // Used by printer/parser 14 | let mnemonic = _mnemonic; 15 | } 16 | 17 | // Floating-point Type 18 | def TT_Float : AnyTypeOf<[F8E4M3FN, F8E4M3FNUZ, F8E5M2, F8E5M2FNUZ, F16, BF16, F32, F64], "floating-point">; 19 | def TT_FloatTensor : RankedTensorOf<[TT_Float]>; 20 | def TT_FloatLike : AnyTypeOf<[TT_Float, TT_FloatTensor]>; 21 | 22 | // Boolean Type 23 | // TT_Bool -> I1 24 | def TT_BoolTensor : RankedTensorOf<[I1]>; 25 | def TT_BoolLike : AnyTypeOf<[I1, TT_BoolTensor]>; 26 | 27 | // Integer Type 28 | def I4 : I<4>; 29 | def TT_Int : AnyTypeOf<[I1, I4, I8, I16, I32, I64], "integer">; 30 | def TT_IntTensor : RankedTensorOf<[TT_Int]>; 31 | def TT_IntLike : AnyTypeOf<[TT_Int, TT_IntTensor]>; 32 | 33 | // I32 Type 34 | // TT_I32 -> I32 35 | // TT_I32Tensor -> I32Tensor 36 | def TT_I32Like : AnyTypeOf<[I32, I32Tensor]>; 37 | 38 | // I64 Type 39 | // TT_I64 -> I64 40 | // TT_I64Tensor -> I64Tensor 41 | def TT_I64Like : AnyTypeOf<[I64, I64Tensor]>; 42 | 43 | // Pointer Type in TableGen 44 | class TT_PtrOf pointeeTypes> : 45 | DialectType($_self)">, 47 | Concat<"[](::mlir::Type pointeeType) { return ", 48 | SubstLeaves<"$_self", "pointeeType", AnyTypeOf.predicate>, 49 | "; }(::mlir::cast<::mlir::triton::PointerType>($_self).getPointeeType())">]>, 50 | "ptr", "::mlir::triton::PointerType">; 51 | 52 | // Pointer Type in C++ (corresponding to `TT_PtrOf`) 53 | def TT_PtrType : TritonTypeDef<"Pointer", "ptr"> { 54 | let summary = "Pointer type (`::mlir::triton::PointerType`) in Triton IR type system"; 55 | 56 | let description = [{ 57 | Pointer type in Triton IR type system, which could be pointing to scalars or tensors. 58 | }]; 59 | 60 | let parameters = (ins "Type":$pointeeType, "int":$addressSpace); 61 | 62 | let builders = [ 63 | TypeBuilderWithInferredContext<(ins 64 | "Type":$pointeeType, 65 | "int":$addressSpace 66 | ), [{ 67 | return $_get(pointeeType.getContext(), pointeeType, addressSpace); 68 | }]> 69 | ]; 70 | 71 | let hasCustomAssemblyFormat = 1; 72 | 73 | let skipDefaultBuilders = 1; 74 | } 75 | 76 | // Scalar Pointer Type: `ptr<>` 77 | def TT_Ptr : TT_PtrOf<[AnyType]>; 78 | 79 | // Tensor of Pointer Type: `tensor>` 80 | def TT_PtrTensor : RankedTensorOf<[TT_Ptr]>; 81 | 82 | // Tensor of Pointer Type or Pointer type: `tensor>` or `ptr<>` 83 | def TT_PtrLike : AnyTypeOf<[TT_Ptr, TT_PtrTensor]>; 84 | 85 | // Tensor Type 86 | def TT_FpIntTensor : RankedTensorOf<[TT_Float, TT_Int]>; 87 | def TT_Tensor : RankedTensorOf<[TT_Float, TT_Int, TT_Ptr]>; 88 | 89 | // Pointer Type to Tensor Type: `ptr>` 90 | def TT_TensorPtr : TT_PtrOf<[TT_Tensor]>; 91 | 92 | // Any Type in Triton IR 93 | def TT_Type : AnyTypeOf<[TT_FloatLike, TT_IntLike, TT_PtrLike, TT_TensorPtr]>; 94 | 95 | // Result type of ExperimentalMakeTensorDescriptor 96 | def TT_TensorDescType : TritonTypeDef<"TensorDesc", "tensordesc", []> { 97 | let summary = "Tensor descriptor type (`::mlir::triton::TensorDescType`) in Triton IR type system"; 98 | 99 | let description = [{ 100 | A portable abstraction for nvidia-TMA descriptors. 101 | }]; 102 | 103 | let parameters = (ins "RankedTensorType":$blockType); 104 | let assemblyFormat = "`<` $blockType `>`"; 105 | } 106 | 107 | #endif 108 | -------------------------------------------------------------------------------- /projects/eudsl-tblgen/tests/td/Utils.td: -------------------------------------------------------------------------------- 1 | //===-- Utils.td - General utilities file ------------------*- tablegen -*-===// 2 | // 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 | // See https://llvm.org/LICENSE.txt for license information. 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | // 7 | //===----------------------------------------------------------------------===// 8 | // 9 | // This file contains a number of utilities which can be used across tablegen 10 | // files. 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #ifndef UTILS_TD 15 | #define UTILS_TD 16 | 17 | // Helper for marking deprecated classes or defs in TableGen. To mark a def as 18 | // deprecated, mix in the `Deprecate` class with a reason. 19 | // Usage of a deprecated def within TableGen will cause a warning with the 20 | // given message. 21 | class Deprecated { 22 | string odsDeprecated = reason; 23 | } 24 | 25 | // Helper for marking entities in ODS generated C++ as deprecated. 26 | // Usage of such an entity from C++ code will cause a warning being emitted by 27 | // the C++ compiler with the given message. 28 | // 29 | // Note: Support has to be implemented by the code generator of a given 30 | // entity. 31 | class CppDeprecated { 32 | string odsCppDeprecated = reason; 33 | } 34 | 35 | // A workaround for the inability to define functions in Tablegen. 36 | // 37 | // The template parameter defines a string that can be extracted from an 38 | // instance of this class by accessing the "result" member. Subclasses can take 39 | // their own template parameters as function "arguments" and use them to 40 | // populate result. 41 | // For example, if it didn't already exist, a concat function could be defined 42 | // like: 43 | // 44 | // class StrConcat strings> : 45 | // StrFunc 46 | // 47 | // and then called like 48 | // 49 | // StrConcat<["a", "b", "c"]>.result 50 | // 51 | // to get the string "abc" 52 | class StrFunc { 53 | string result = r; 54 | } 55 | 56 | // Marker used to identify the argument list. 57 | def ins; 58 | 59 | // Marker used to identify the result list. 60 | def outs; 61 | 62 | // This class represents a typed argument with optional default value for C 63 | // function signatures, e.g. builders or methods. 64 | class CArg { 65 | string type = ty; 66 | string defaultValue = value; 67 | } 68 | 69 | // Helper which makes the first letter of a string uppercase. 70 | // e.g. cat -> Cat 71 | class firstCharToUpper 72 | { 73 | string ret = !if(!gt(!size(str), 0), 74 | !toupper(!substr(str, 0, 1)) # !substr(str, 1), 75 | ""); 76 | } 77 | 78 | class _snakeCaseHelper { 79 | int idx = !find(str, "_"); 80 | string ret = !if(!ge(idx, 0), 81 | !substr(str, 0, idx) # firstCharToUpper.ret, 82 | str); 83 | } 84 | 85 | // Converts a snake_case string to CamelCase. 86 | // TODO: Replace with a !tocamelcase bang operator. 87 | class snakeCaseToCamelCase 88 | { 89 | string ret = !foldl(firstCharToUpper.ret, 90 | !range(0, !size(str)), acc, idx, _snakeCaseHelper.ret); 91 | } 92 | 93 | #endif // UTILS_TD 94 | -------------------------------------------------------------------------------- /projects/eudsl-tblgen/tests/test_bindings.py: -------------------------------------------------------------------------------- 1 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 | # See https://llvm.org/LICENSE.txt for license information. 3 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 | # Copyright (c) 2024. 5 | 6 | from pathlib import Path 7 | 8 | import pytest 9 | from eudsl_tblgen import ( 10 | RecordKeeper, 11 | get_requested_op_definitions, 12 | get_all_type_constraints, 13 | collect_all_defs, 14 | ) 15 | 16 | 17 | @pytest.fixture(scope="function") 18 | def json_record_keeper(): 19 | return RecordKeeper().parse_td(str(Path(__file__).parent / "td" / "JSON.td")) 20 | 21 | 22 | def test_json_record_keeper(json_record_keeper): 23 | assert json_record_keeper.get_input_filename() == str( 24 | Path(__file__).parent / "td" / "JSON.td" 25 | ) 26 | 27 | assert set(json_record_keeper.get_classes()) == { 28 | "Base", 29 | "Derived", 30 | "Intermediate", 31 | "Variables", 32 | } 33 | 34 | assert set(json_record_keeper.get_defs().keys()) == { 35 | "D", 36 | "ExampleDagOp", 37 | "FieldKeywordTest", 38 | "Named", 39 | "VarNull", 40 | "VarObj", 41 | "VarPrim", 42 | "anonymous_0", 43 | } 44 | 45 | assert len(json_record_keeper.get_all_derived_definitions("Base")) == 1 46 | assert len(json_record_keeper.get_all_derived_definitions("Intermediate")) == 1 47 | assert len(json_record_keeper.get_all_derived_definitions("Derived")) == 0 48 | 49 | assert json_record_keeper.get_all_derived_definitions("Base")[0].get_name() == "D" 50 | assert ( 51 | json_record_keeper.get_all_derived_definitions("Intermediate")[0].get_name() 52 | == "D" 53 | ) 54 | 55 | 56 | def test_record(json_record_keeper): 57 | assert json_record_keeper.get_classes()["Base"] 58 | assert json_record_keeper.get_classes()["Intermediate"] 59 | assert json_record_keeper.get_classes()["Derived"] 60 | assert json_record_keeper.get_classes()["Variables"] 61 | 62 | base_cl = json_record_keeper.get_classes()["Base"] 63 | interm_cl = json_record_keeper.get_classes()["Intermediate"] 64 | deriv_cl = json_record_keeper.get_classes()["Derived"] 65 | variab_cl = json_record_keeper.get_classes()["Variables"] 66 | 67 | assert len(base_cl.get_direct_super_classes()) == 0 68 | assert len(interm_cl.get_direct_super_classes()) == 1 69 | assert len(deriv_cl.get_direct_super_classes()) == 1 70 | assert len(variab_cl.get_direct_super_classes()) == 0 71 | 72 | assert interm_cl.get_direct_super_classes()[0].get_name() == "Base" 73 | assert deriv_cl.get_direct_super_classes()[0].get_name() == "Intermediate" 74 | 75 | assert base_cl.get_name() == "Base" 76 | assert base_cl.get_name_init_as_string() == "Base" 77 | assert base_cl.get_records() is json_record_keeper 78 | assert base_cl.get_type() 79 | 80 | assert repr(base_cl.get_values()) == "RecordValues()" 81 | assert ( 82 | repr(variab_cl.get_values()) 83 | == "RecordValues(i=?, s=?, b=?, bs={ ?, ?, ?, ?, ?, ?, ?, ? }, c=?, li=?, base=?, d=?)" 84 | ) 85 | 86 | assert interm_cl.has_direct_super_class(interm_cl.get_direct_super_classes()[0]) 87 | assert interm_cl.has_direct_super_class(base_cl) 88 | 89 | assert base_cl.is_anonymous() is False 90 | assert base_cl.is_class() is True 91 | assert base_cl.is_multi_class() is False 92 | 93 | assert interm_cl.is_sub_class_of(base_cl) 94 | assert not interm_cl.is_sub_class_of(variab_cl) 95 | assert not interm_cl.is_sub_class_of("Variables") 96 | 97 | 98 | def test_record_val_classes(json_record_keeper): 99 | variab_cl = json_record_keeper.get_classes()["Variables"] 100 | assert variab_cl.get_value("i") 101 | i_val = variab_cl.get_value("i") 102 | assert i_val.get_name() == "i" 103 | assert i_val.get_name_init_as_string() == "i" 104 | assert i_val.get_print_type() == "int" 105 | assert i_val.get_record_keeper() is json_record_keeper 106 | assert i_val.is_nonconcrete_ok() is False 107 | assert i_val.is_template_arg() is False 108 | assert i_val.is_used() is False 109 | 110 | 111 | def test_record_val_defs(json_record_keeper): 112 | var_prim_def = json_record_keeper.get_defs()["VarPrim"] 113 | assert var_prim_def.get_value_as_int("i") == 3 114 | assert var_prim_def.get_value_as_int("enormous_pos") == 9123456789123456789 115 | assert var_prim_def.get_value_as_int("enormous_neg") == -9123456789123456789 116 | assert var_prim_def.get_value_as_string("s") == "hello, world" 117 | assert var_prim_def.get_value_as_bit("b") is False 118 | assert var_prim_def.get_value_as_string("c") == " void " 119 | assert var_prim_def.get_value_as_list_of_ints("li") == [1, 2, 3, 4] 120 | 121 | 122 | def test_init(json_record_keeper): 123 | variab_cl = json_record_keeper.get_classes()["Variables"] 124 | assert variab_cl.get_value("i") 125 | assert variab_cl.get_value("i").get_value() 126 | i_val_init = variab_cl.get_value("i").get_value() 127 | assert str(i_val_init) == "?" 128 | assert i_val_init.get_as_string() == "?" 129 | assert i_val_init.is_complete() is False 130 | assert i_val_init.is_concrete() is True 131 | 132 | 133 | def test_record_rec_ty(json_record_keeper): 134 | base_cl = json_record_keeper.get_classes()["Base"] 135 | interm_cl = json_record_keeper.get_classes()["Intermediate"] 136 | deriv_cl = json_record_keeper.get_classes()["Derived"] 137 | 138 | assert not base_cl.get_type().get_classes() 139 | assert interm_cl.get_type().get_classes() 140 | assert deriv_cl.get_type().get_classes() 141 | assert len(interm_cl.get_type().get_classes()) == 1 142 | assert len(deriv_cl.get_type().get_classes()) == 1 143 | assert interm_cl.get_type().get_classes()[0].get_name() == "Base" 144 | assert deriv_cl.get_type().get_classes()[0].get_name() == "Intermediate" 145 | 146 | assert interm_cl.get_type().is_sub_class_of(base_cl) 147 | assert deriv_cl.get_type().is_sub_class_of(interm_cl) 148 | 149 | 150 | @pytest.fixture(scope="function") 151 | def record_keeper_test_dialect(): 152 | here = Path(__file__).parent 153 | return RecordKeeper().parse_td( 154 | str(here / "td" / "TestDialect.td"), [str(here / "td")] 155 | ) 156 | 157 | 158 | def test_init_complex(record_keeper_test_dialect): 159 | op = record_keeper_test_dialect.get_defs()["Test_TypesOp"] 160 | assert str(op.get_values().opName) == "types" 161 | assert str(op.get_values().cppNamespace) == "test" 162 | assert str(op.get_values().opDocGroup) == "?" 163 | assert str(op.get_values().results) == "(outs)" 164 | assert str(op.get_values().regions) == "(region)" 165 | assert str(op.get_values().successors) == "(successor)" 166 | assert str(op.get_values().builders) == "?" 167 | assert bool(op.get_values().skipDefaultBuilders.get_value()) is False 168 | assert str(op.get_values().assemblyFormat) == "?" 169 | assert bool(op.get_values().hasCustomAssemblyFormat.get_value()) is False 170 | assert bool(op.get_values().hasVerifier.get_value()) is False 171 | assert bool(op.get_values().hasRegionVerifier.get_value()) is False 172 | assert bool(op.get_values().hasCanonicalizer.get_value()) is False 173 | assert bool(op.get_values().hasCanonicalizeMethod.get_value()) is False 174 | assert bool(op.get_values().hasFolder.get_value()) is False 175 | assert bool(op.get_values().useCustomPropertiesEncoding.get_value()) is False 176 | assert len(op.get_values().traits.get_value()) == 0 177 | assert str(op.get_values().extraClassDeclaration) == "?" 178 | assert str(op.get_values().extraClassDefinition) == "?" 179 | 180 | assert ( 181 | repr(op.get_values()) 182 | == "RecordValues(opDialect=Test_Dialect, opName=types, cppNamespace=test, summary=, description=, opDocGroup=?, arguments=(ins I32:$a, SI64:$b, UI8:$c, Index:$d, F32:$e, NoneType:$f, anonymous_348), results=(outs), regions=(region), successors=(successor), builders=?, skipDefaultBuilders=0, assemblyFormat=?, hasCustomAssemblyFormat=0, hasVerifier=0, hasRegionVerifier=0, hasCanonicalizer=0, hasCanonicalizeMethod=0, hasFolder=0, useCustomPropertiesEncoding=0, traits=[], extraClassDeclaration=?, extraClassDefinition=?)" 183 | ) 184 | 185 | arguments = op.get_values().arguments 186 | assert arguments.get_value().get_arg_name_str(0) == "a" 187 | assert arguments.get_value().get_arg_name_str(1) == "b" 188 | assert arguments.get_value().get_arg_name_str(2) == "c" 189 | assert arguments.get_value().get_arg_name_str(3) == "d" 190 | assert arguments.get_value().get_arg_name_str(4) == "e" 191 | assert arguments.get_value().get_arg_name_str(5) == "f" 192 | 193 | assert str(arguments.get_value()[0]) == "I32" 194 | assert str(arguments.get_value()[1]) == "SI64" 195 | assert str(arguments.get_value()[2]) == "UI8" 196 | assert str(arguments.get_value()[3]) == "Index" 197 | assert str(arguments.get_value()[4]) == "F32" 198 | assert str(arguments.get_value()[5]) == "NoneType" 199 | 200 | attr = record_keeper_test_dialect.get_defs()["Test_TestAttr"] 201 | assert str(attr.get_values().predicate) == "anonymous_335" 202 | assert str(attr.get_values().storageType) == "test::TestAttr" 203 | assert str(attr.get_values().returnType) == "test::TestAttr" 204 | assert ( 205 | str(attr.get_values().convertFromStorage.get_value()) 206 | == "::llvm::cast($_self)" 207 | ) 208 | assert str(attr.get_values().constBuilderCall) == "?" 209 | assert str(attr.get_values().defaultValue) == "?" 210 | assert str(attr.get_values().valueType) == "?" 211 | assert bool(attr.get_values().isOptional.get_value()) is False 212 | assert str(attr.get_values().baseAttr) == "?" 213 | assert str(attr.get_values().cppNamespace) == "test" 214 | assert str(attr.get_values().dialect) == "Test_Dialect" 215 | assert str(attr.get_values().cppBaseClassName.get_value()) == "::mlir::Attribute" 216 | assert str(attr.get_values().storageClass) == "TestAttrStorage" 217 | assert str(attr.get_values().storageNamespace) == "detail" 218 | assert bool(attr.get_values().genStorageClass.get_value()) is True 219 | assert bool(attr.get_values().hasStorageCustomConstructor.get_value()) is False 220 | assert str(attr.get_values().parameters) == "(ins)" 221 | assert str(attr.get_values().builders) == "?" 222 | assert len(attr.get_values().traits.get_value()) == 0 223 | assert str(attr.get_values().mnemonic) == "test" 224 | assert str(attr.get_values().assemblyFormat) == "?" 225 | assert bool(attr.get_values().hasCustomAssemblyFormat.get_value()) is False 226 | assert bool(attr.get_values().genAccessors.get_value()) is True 227 | assert bool(attr.get_values().skipDefaultBuilders.get_value()) is False 228 | assert bool(attr.get_values().genVerifyDecl.get_value()) is False 229 | assert str(attr.get_values().cppClassName) == "TestAttr" 230 | assert str(attr.get_values().cppType) == "test::TestAttr" 231 | assert str(attr.get_values().attrName) == "test.test" 232 | 233 | 234 | def test_mlir_tblgen(record_keeper_test_dialect): 235 | for op in get_requested_op_definitions(record_keeper_test_dialect): 236 | print(op.get_name()) 237 | for constraint in get_all_type_constraints(record_keeper_test_dialect): 238 | print(constraint.get_def_name()) 239 | print(constraint.get_summary()) 240 | 241 | all_defs = collect_all_defs(record_keeper_test_dialect) 242 | for d in all_defs: 243 | print(d.get_name()) 244 | -------------------------------------------------------------------------------- /projects/eudsl-tblgen/tests/test_c_api_emission.py: -------------------------------------------------------------------------------- 1 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 | # See https://llvm.org/LICENSE.txt for license information. 3 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 | # Copyright (c) 2024. 5 | 6 | from pathlib import Path 7 | 8 | import pytest 9 | from eudsl_tblgen import ( 10 | RecordKeeper, 11 | collect_all_defs, 12 | collect_all_attr_or_type_defs, 13 | ) 14 | from eudsl_tblgen.mlir import ( 15 | emit_c_attr_or_type_builder, 16 | emit_c_attr_or_type_field_getter, 17 | emit_attr_or_type_nanobind_class, 18 | emit_decls_defns_nbclasses, 19 | CClassKind, 20 | ) 21 | 22 | 23 | @pytest.fixture(scope="function") 24 | def record_keeper_triton_gpu_attrs(): 25 | here = Path(__file__).parent 26 | return RecordKeeper().parse_td( 27 | str(here / "td" / "TritonGPUAttrDefs.td"), [str(here / "td")] 28 | ) 29 | 30 | 31 | @pytest.fixture(scope="function") 32 | def record_keeper_triton_gpu_types(): 33 | here = Path(__file__).parent 34 | return RecordKeeper().parse_td( 35 | str(here / "td" / "TritonGPUTypes.td"), [str(here / "td")] 36 | ) 37 | 38 | 39 | def test_attrs(record_keeper_triton_gpu_attrs): 40 | all_defs = collect_all_attr_or_type_defs( 41 | collect_all_defs(record_keeper_triton_gpu_attrs) 42 | ) 43 | decls, defns, nbclasses = emit_decls_defns_nbclasses( 44 | CClassKind.ATTRIBUTE, all_defs, exclude={"BlockedEncodingAttr", "SliceEncodingAttr"} 45 | ) 46 | 47 | dump_dir = Path(__file__).parent 48 | 49 | with open(f"{dump_dir}/TritonGPUAttrDefs_MlirAttribute_decls.h.inc", "w") as f: 50 | for d in decls: 51 | print(d, file=f) 52 | with open(f"{dump_dir}/TritonGPUAttrDefs_MlirAttribute_defns.cpp.inc", "w") as f: 53 | for d in defns: 54 | print(d, file=f) 55 | for hdecl, hdefn, n in nbclasses: 56 | with open(f"{dump_dir}/TritonGPUAttrDefs_MlirAttribute_decls.h.inc", "a") as f: 57 | for h in hdecl: 58 | print(h, file=f) 59 | with open( 60 | f"{dump_dir}/TritonGPUAttrDefs_MlirAttribute_defns.cpp.inc", "a" 61 | ) as f: 62 | for h in hdefn: 63 | print(h, file=f) 64 | with open( 65 | f"{dump_dir}/TritonGPUAttrDefs_MlirAttribute_nbclasses.cpp.inc", "w" 66 | ) as f: 67 | for *_, n in nbclasses: 68 | print(n, file=f) 69 | 70 | 71 | def test_types(record_keeper_triton_gpu_types): 72 | all_defs = collect_all_attr_or_type_defs( 73 | collect_all_defs(record_keeper_triton_gpu_types) 74 | ) 75 | decls, defns, nbclasses = emit_decls_defns_nbclasses(CClassKind.TYPE, all_defs) 76 | dump_dir = Path(__file__).parent 77 | 78 | with open(f"{dump_dir}/TritonGPUTypes_MlirType_decls.h.inc", "w") as f: 79 | for d in decls: 80 | print(d, file=f) 81 | with open(f"{dump_dir}/TritonGPUTypes_MlirType_defns.cpp.inc", "w") as f: 82 | for d in defns: 83 | print(d, file=f) 84 | for hdecl, hdefn, n in nbclasses: 85 | with open(f"{dump_dir}/TritonGPUTypes_MlirType_decls.h.inc", "a") as f: 86 | for h in hdecl: 87 | print(h, file=f) 88 | with open(f"{dump_dir}/TritonGPUTypes_MlirType_defns.cpp.inc", "a") as f: 89 | for h in hdefn: 90 | print(h, file=f) 91 | with open(f"{dump_dir}/TritonGPUTypes_MlirType_nbclasses.cpp.inc", "w") as f: 92 | for *_, n in nbclasses: 93 | print(n, file=f) 94 | -------------------------------------------------------------------------------- /requirements-dev.txt: -------------------------------------------------------------------------------- 1 | litgen @ git+https://github.com/pthom/litgen@f5d154c6f7679e755baa1047563d7c340309bc00 2 | nanobind==2.4.0 3 | numpy==2.0.2 4 | scikit-build-core==0.10.7 5 | --------------------------------------------------------------------------------