Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@ exclude =
.git,
__pycache__,
build,
**/build,
env,
.venv,
dist,
deps,
.llvm-project,
*docs/build,
*docs/source/generated,
*docs/source/stubs,
Expand Down
123 changes: 123 additions & 0 deletions .github/workflows/ci-cpu.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# SPDX-FileCopyrightText: Copyright (c) <2025> NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

name: CPU CI

on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
lint:
name: Lint
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.12"

- name: Install lint dependencies
run: python -m pip install flake8

- name: Run flake8
run: flake8

- name: Run cpplint
run: python scripts/cpplint.py

- name: Check license headers
run: python scripts/check_license.py

- name: Check inline samples are up to date
run: python test/tools/inline_samples.py --check

build:
name: Build CPU Wheel (Python 3.12)
runs-on: ubuntu-24.04
timeout-minutes: 360
env:
CUTILE_BUILD_VARIANT: cpu
steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.12"

- name: Install native build dependencies
run: |
sudo apt-get update
sudo apt-get install --yes clang lld g++

- name: Set up uv
uses: astral-sh/setup-uv@v7
with:
enable-cache: true

- name: Install CPU build dependencies
run: uv sync --group cpu --no-install-project

- name: Build CPU wheel
run: uv build --wheel --no-build-isolation --python .venv/bin/python

- name: Upload CPU wheel
uses: actions/upload-artifact@v6
with:
name: wheel-cpu-py3.12-linux-x86_64
path: dist/*.whl
if-no-files-found: error
retention-days: 7

test-cpu:
name: CPU Tests (Python 3.12)
needs: build
runs-on: ubuntu-24.04
timeout-minutes: 360
steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.12"

- name: Download CPU wheel
uses: actions/download-artifact@v7
with:
name: wheel-cpu-py3.12-linux-x86_64
path: dist/

- name: Install test dependencies
run: |
python -m pip install torch --index-url https://download.pytorch.org/whl/cpu
python -m pip install dist/*.whl numpy pytest pytest-benchmark pytest-env
python -m pip install setuptools==84.0.0 'cmake>=3.24,<4' ninja

- name: Run CPU backend tests
run: python -m pytest --durations=10 --junitxml=test-results.xml -m "not benchmark" backends/cpu backends/test

- name: Upload test results
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v6
with:
name: cpu-test-results
path: test-results.xml
retention-days: 7
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
# push:
# branches: [main]
# pull_request:
# branches: [main]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ deps
*.nsys-rep
*.so
build/
.llvm-project/
.cache
.idea
.rgignore
Expand Down
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ endif()
add_subdirectory(cext)
add_subdirectory(experimental/cuda-lang/)

# The non-CUDA variant (cpu) additionally builds its backend; see backends/README.md.
if (CUTILE_BUILD_VARIANT AND NOT CUTILE_BUILD_VARIANT STREQUAL "cuda")
add_subdirectory(backends)
endif()


option(DISABLE_INTERNAL "disable internal" OFF)
if (NOT DISABLE_INTERNAL)
Expand Down
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,46 @@ cuTile Python is a programming language for NVIDIA GPUs. The official documentat
on [docs.nvidia.com](https://docs.nvidia.com/cuda/cutile-python),
or built from source located in the [docs](docs/) folder.

> [!NOTE]
> Non-CUDA Backends (Experimental)
> --------------------------------
>
> Non-CUDA backend support on Linux is experimental. The CPU backend is available,
> and Intel GPU (XPU) support is planned. Backends integrate by intercepting
> TileIR, a design that could also support other platforms.
>
> To build the CPU backend from source, install the prerequisites below, then run
> these commands from the repository root:
>
> ```bash
> uv venv --python 3.12
> source .venv/bin/activate
>
> CUTILE_BUILD_VARIANT=cpu uv sync --group cpu --no-build-isolation-package cuda-tile
> ```
>
> - **CPU:** requires GCC with OpenMP, Clang, and LLD. See the
> [CPU guide](backends/cpu/README.md) for prerequisites, sample runs, and usage.
>
> The CPU build does not require an NVIDIA GPU or CUDA driver. Each environment supports
> one build variant. See the [backend overview](backends/README.md) for runtime
> selection and shared behavior.
>
> Autotuning (New Feature)
>------------------------
>
> `ct.autotune` benchmarks candidate compile-time configurations
> on the first launch, then reuses the fastest configuration for inputs with the same layout.
>
> ```python
> @ct.autotune(
> configs=[ct.tune.Config({"TILE": 128}), ct.tune.Config({"TILE": 256})],
> grid=lambda meta: (ct.cdiv(meta["N"], meta["TILE"]),),
> )
> @ct.kernel
> def my_kernel(x, N: ct.Constant[int], TILE: ct.Constant[int]):
> ...
> ```

Example
-------
Expand Down
52 changes: 52 additions & 0 deletions backends/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# SPDX-FileCopyrightText: Copyright (c) <2026> Intel Corporation. All rights reserved.
#
# SPDX-License-Identifier: Apache-2.0

# LLVM builds the compiler as an external project, separately from the launchers.
if(TARGET TileIRToMLIR)
include("${CMAKE_CURRENT_SOURCE_DIR}/compiler.cmake")
return()
endif()

# Builds the native parts of the non-CUDA backend selected by CUTILE_BUILD_VARIANT:
# the native compiler and the backend's launcher extension. Installing
# the build (`cmake --install <build> --prefix <site> --component cuTileBackend`)
# stages them and their runtime files into <site>/cuda/tile/_backends, next to the
# Python backend in src/cuda/tile/_backends.

if(NOT CMAKE_SYSTEM_NAME STREQUAL "Linux")
message(FATAL_ERROR "The native CPU compiler currently supports Linux only")
endif()

if (NOT CUTILE_BUILD_VARIANT STREQUAL "cpu")
message(FATAL_ERROR "CUTILE_BUILD_VARIANT must be one of: cuda, cpu")
endif()

# Installing only this component skips the install rules of cuTile's other
# dependencies, such as dlpack.
set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME cuTileBackend)

find_package(Python REQUIRED COMPONENTS Interpreter Development.Module)
execute_process(
COMMAND "${Python_EXECUTABLE}" -m nanobind --cmake_dir
OUTPUT_VARIABLE nanobind_ROOT
OUTPUT_STRIP_TRAILING_WHITESPACE
COMMAND_ERROR_IS_FATAL ANY)
find_package(nanobind CONFIG REQUIRED)

# Package directory of the backends, relative to the install prefix.
set(CUTILE_BACKEND_INSTALL_DIR cuda/tile/_backends)

include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/FetchTileIRToMLIR.cmake")
fetch_tileir_to_mlir()
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/TileIRToMLIR.cmake")

install(FILES "${CUTILE_COMPILER_PATH}" DESTINATION "${CUTILE_BACKEND_INSTALL_DIR}")
install(FILES "${CUTILE_LLVM_LICENSE_PATH}"
DESTINATION "${CUTILE_BACKEND_INSTALL_DIR}/_licenses/llvm")
install(FILES "${CUTILE_TILEIR_TO_MLIR_DIR}/LICENSE"
DESTINATION "${CUTILE_BACKEND_INSTALL_DIR}/_licenses/tileir-to-mlir")
install(FILES "${CUTILE_CUDA_TILE_SOURCE_DIR}/LICENSE.txt"
DESTINATION "${CUTILE_BACKEND_INSTALL_DIR}/_licenses/cuda-tile")

add_subdirectory("${CUTILE_BUILD_VARIANT}")
43 changes: 43 additions & 0 deletions backends/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<!--- SPDX-FileCopyrightText: Copyright (c) <2026> Intel Corporation. All rights reserved. -->
<!--- SPDX-License-Identifier: Apache-2.0 -->

# Non-CUDA backends

The built-in CPU backend runs cuTile kernels on Linux host arrays and CPU
PyTorch tensors. It is experimental; see the [CPU guide](cpu/README.md) for
requirements, installation, and a sample.

## Select a backend

```python
import cuda.tile as ct

ct.set_backend("cpu")
ct.launch(None, grid, kernel, args)
ct.set_backend(None) # Restore the CUDA launch path.
```

Backend selection applies to the whole process and is not inferred from the
arguments. Coordinate changes between threads. CPU launches are synchronous;
pass CPU arrays and `None` for the stream. CUDA-only launch options are not
available on the CPU path.

The CPU backend must be installed in the environment before selecting it.
Runtime selection does not change the installed compiler or build variant.

## Options and limits

Use `ct.backend_options({...})` to scope backend options to a block of code.
Options apply to the current thread, and unknown options are rejected. The CPU
backend supports `num_cpu_threads` and `assume_in_bounds`; see the
[CPU guide](cpu/README.md#use-in-a-program).

Compiled kernels are cached. Changing a code-generation option selects a
different compiled kernel; changing the CPU thread count does not recompile.
CUDA-specific hints such as `num_ctas` and `occupancy` do not apply.

## Tests

Run the backend tests from the repository root with `python -m pytest backends`.
The CPU-specific guide has instructions for installing the test
dependencies and running only CPU tests.
36 changes: 36 additions & 0 deletions backends/cmake/BuildLLVM.cmake.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# SPDX-FileCopyrightText: Copyright (c) <2026> Intel Corporation. All rights reserved.
#
# SPDX-License-Identifier: Apache-2.0

cmake_minimum_required(VERSION 3.20)
set(_source [==[@CUTILE_LLVM_SOURCE_DIR@/llvm]==])
set(_binary [==[@CUTILE_LLVM_BINARY_DIR@]==])
set(_args [==[@_cutile_llvm_cmake_args@]==])
set(_targets [==[@_cutile_llvm_build_targets@]==])
string(REPLACE "|" "\\;" _args "${_args}")
string(SHA256 _request "${CMAKE_COMMAND};${_source};${_args}")

set(_cache "${_binary}/CMakeCache.txt")
set(_stamp "${_binary}/cutile-configure.stamp")
set(_state "")
if(EXISTS "${_cache}" AND EXISTS "${_binary}/build.ninja")
file(SHA256 "${_cache}" _cache_hash)
set(_state "${_request}\n${_cache_hash}\n")
endif()
set(_saved "")
if(EXISTS "${_stamp}")
file(READ "${_stamp}" _saved)
endif()
# The shared LLVM tree may have been reconfigured by another outer build or
# manually. Ninja handles source/CMake-file changes on otherwise matching builds.
if(NOT _state OR NOT _state STREQUAL _saved)
file(REMOVE "${_stamp}")
execute_process(
COMMAND "${CMAKE_COMMAND}" -S "${_source}" -B "${_binary}" -G Ninja ${_args}
COMMAND_ERROR_IS_FATAL ANY)
endif()
execute_process(
COMMAND "${CMAKE_COMMAND}" --build "${_binary}" --target ${_targets}
COMMAND_ERROR_IS_FATAL ANY)
file(SHA256 "${_cache}" _cache_hash)
file(WRITE "${_stamp}" "${_request}\n${_cache_hash}\n")
Loading