Kernels

Grid

cuTile.bidFunction
bid(axis) -> Int32

Get the block ID along the given axis (1=x, 2=y, 3=z). Returns 1-indexed block ID.

source
cuTile.num_blocksFunction
num_blocks(axis) -> Int32

Get the grid size along the given axis (1=x, 2=y, 3=z).

source
cuTile.num_tilesFunction
num_tiles(arr::TileArray, axis::Integer, shape::NTuple{M, Int}) -> Int32

Get the number of tiles along a specific axis of an array, given the tile shape. Axis is 1-indexed. Equivalent to cld(size(arr, axis), shape[axis]).

Example

# For a 1024x768 matrix with 32x32 tiles:
# num_tiles(arr, 1, (32, 32)) returns cld(1024, 32) = 32
# num_tiles(arr, 2, (32, 32)) returns cld(768, 32) = 24
source

Compiling and launching

cuTile.launchFunction
launch(f, grid, args...; sm_arch=nothing, opt_level=nothing,
       num_ctas=nothing, occupancy=nothing, num_worker_warps=nothing, name=nothing)

Compile and launch a Tile IR kernel. args are converted via cuTileconvert (CuArray → TileArray, Type → Constant). Equivalent to @cuda backend=cuTile blocks=grid f(args...) modulo slight kwarg naming.

Example

using CUDA, cuTile

a = CUDA.zeros(Float32, 1024); b = CUDA.ones(Float32, 1024); c = similar(a)

function vadd_kernel(a::cuTile.TileArray{Float32,1}, b::cuTile.TileArray{Float32,1},
                     c::cuTile.TileArray{Float32,1})
    pid = cuTile.bid(1)
    ta = cuTile.load(a, (pid,), (16,))
    tb = cuTile.load(b, (pid,), (16,))
    cuTile.store(c, (pid,), ta + tb)
    return
end

cuTile.launch(vadd_kernel, 64, a, b, c)
source
cuTile.cufunctionFunction
cuTile.cufunction(f, tt=Tuple{}; sm_arch=nothing, opt_level=nothing,
                  num_ctas=nothing, occupancy=nothing, num_worker_warps=nothing,
                  name=nothing) -> TileKernel

Compile f for the cuTile backend. tt is the tuple of converted argument types (i.e. after cuTileconvert/Adapt.adapt(KernelAdaptor(), …)). Compilation is cached; calling cufunction repeatedly with the same (f, tt, opts) is O(1) after the first compile.

Mirrors CUDACore.cufunction but produces a TileKernel. Caching is delegated to CompilerCaching: the resulting TileKernel is stored in the CuTileResults attached to the underlying Julia CodeInstance, so invalidation rides on Julia's normal CI lifecycle.

source
cuTile.TileKernelType
TileKernel{F, TT}

A compiled cuTile kernel. Returned by cuTile.cufunction and the target of (::TileKernel)(args...; blocks, …) calls. Concrete subtype of CUDACore.AbstractKernel.

source
cuTile.TileBackendType
TileBackend()

cuTile backend for @cuda backend=.... Routes the call through cuTile.cufunction (Tile IR bytecode → tileiras → CUBIN) and returns a TileKernel for launch.

@cuda backend=cuTile blocks=N my_kernel(a, b, c)        # via DefaultBackend()
@cuda backend=cuTile.TileBackend() blocks=N my_kernel(a, b, c)
source
cuTile.DefaultBackendFunction
DefaultBackend() -> TileBackend

The default cuTile backend, looked up by @cuda backend=cuTile. Returns a TileBackend. Provided as the module-level resolution hook for CUDACore's @cuda dispatch.

source

Compiler options

cuTile.@compiler_optionsMacro
@compiler_options key=val...

Specify per-architecture optimization hints inside a kernel function body. Hints are embedded as :meta nodes and resolved at compile time based on the target sm_arch.

Supported options: num_ctas, occupancy, opt_level, num_worker_warps.

Values can be plain scalars or ByTarget(...) for per-architecture dispatch.

Examples

function my_kernel(A, B)
    ct.@compiler_options num_ctas=2
    ...
end

function my_kernel(A, B)
    ct.@compiler_options num_ctas=ByTarget(v"10.0" => 2, v"12.0" => 4) occupancy=8
    ...
end
source
cuTile.ByTargetType
ByTarget{T}

Per-architecture value that resolves to a concrete T based on the target GPU's compute capability. Use with @compiler_options to specify architecture-specific optimization hints.

Example

function my_kernel(...)
    ct.@compiler_options num_ctas=ByTarget(v"10.0" => 2, v"12.0" => 4)
    ...
end
source
cuTile.@fpmodeMacro
@fpmode [rounding_mode=Rounding.X] [flush_to_zero=bool] begin ... end

Set the floating-point mode for all FP operations in the block. Operations that support rounding mode and/or flush-to-zero will use the specified values. The mode applies to all operations in the block, including those inside inlined function calls.

Nested @fpmode blocks inherit unspecified fields from the outer scope.

Examples

ct.@fpmode rounding_mode=ct.Rounding.Approx flush_to_zero=true begin
    acc = acc ./ l_i   # uses Approx rounding + FTZ
    p = exp2.(qk)      # uses FTZ
end

# Nesting: inner inherits FTZ from outer
ct.@fpmode rounding_mode=ct.Rounding.Approx flush_to_zero=true begin
    x = a + b                                        # Approx + FTZ
    ct.@fpmode rounding_mode=ct.Rounding.NearestEven begin
        y = c + d                                    # NearestEven + FTZ (inherited)
    end
end
source
cuTile.RoundingModule

Rounding mode for floating-point operations. Use with @fpmode to set the rounding mode for a block of code.

source

Assertions and assumptions

cuTile.@assertMacro
@assert cond [message]

Assert that cond is true, aborting the kernel with message on failure. If no message is given, the stringified condition is used.

Works like Base.@assert but compiles to a Tile IR assert op. Failed assertions are fatal — they crash the kernel and corrupt the CUDA context (not a catchable exception).

Examples

ct.@assert bid > Int32(0)
ct.@assert bid > Int32(0) "bid must be positive"
source
cuTile.assume_divisible_byFunction
assume_divisible_by(x::Integer, divisor::Integer) -> typeof(x)

Declare that x is divisible by divisor, a compiler hint that propagates through arithmetic and can e.g. prove alignment for derived indices and pointer offsets, enabling wider memory operations.

The caller is responsible for the correctness of the claim; behavior is undefined if x is not actually divisible by divisor at runtime.

divisor must be a positive integer constant.

Examples

n = ct.assume_divisible_by(n, 128)
ptr_offset = base + n  # compiler knows this is 128-divisible
source