├── .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 |
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 |
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 |
--------------------------------------------------------------------------------