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
38 changes: 32 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ uses standard Julia syntax and is overlaid on `Base`.
|-----------|-------------|
| `ct.load(arr; index, shape, ...)` | Load a tile from array |
| `ct.store(arr; index, tile, ...)` | Store a tile to array |
| `eachtile(arr, shape; step=...)` | Array-of-tiles view with controllable tile origins |
| `ct.gather(arr, indices; ...)` | Gather elements by index tile |
| `ct.scatter(arr, indices, tile; ...)` | Scatter elements by index tile |

Expand Down Expand Up @@ -324,12 +325,12 @@ end
| `@view arr[r1:r2, :, ...]` / `view(arr, ...)` | Sub-range view of a `TileArray` |

`@view` and `view` derive a sub-range `TileArray` from an existing one. Each
index must be `:` or a `UnitRange` (e.g. `i:j`); other forms (`StepRange`,
scalar `Int`, `CartesianIndex`, ...) are rejected at compile time. The result
is itself a `TileArray` and can be passed to `ct.load`/`ct.store` (or sliced
again). A runtime assert verifies that each range starts at ≥ 1; the upper
bound is not checked because Julia's range construction already clamps
`last(r) >= first(r) - 1`.
index must be `:`, a `UnitRange` (e.g. `i:j`), or a positive `StepRange` (e.g.
`i:s:j`); scalar `Int` and `CartesianIndex` forms are rejected at compile
time. A StepRange changes the element stride inside the resulting TileArray.
The result can be passed to `ct.load`/`ct.store` (or sliced again). Runtime
asserts verify that ranges start at ≥ 1 and have a positive step; negative
steps cannot be represented by Tile IR TensorViews.

```julia
function rowsum(a, b, r1::Int32, r2::Int32)
Expand All @@ -348,6 +349,31 @@ end
| `transpose(arr)` | 2D transpose (`permutedims(arr, (2, 1))`) |
| `reshape(arr, dims)` | Column-major reshape, requires contiguous source |

### Tile Windows

`eachtile` creates a small, indexable device-side collection of fixed-shape
tiles. Its indices are 1-based and `step` (one entry per tile dimension)
controls tile origins, not the element stride inside a tile. `size(tiles, d)`
is the number of tiles along `d`: on the host it computes
`cld(size(a, d), step[d])` for launch-grid sizing, while inside a kernel it
queries the Tile IR backend for the authoritative index-space count:

```julia
adjacent = eachtile(a, (8, 8)) # default: step == (8, 8)
overlap = eachtile(a, (8, 8); step=(4, 8)) # neighboring windows overlap
gapped = eachtile(a, (8, 8); step=(16, 8)) # gaps between row windows

tile = overlap[2, 1]
overlap[2, 1] = tile
```

`eachtile` also accepts the same `order` kwarg as `ct.load`/`ct.store` to
permute which array dimension each tile dimension walks. Use `ct.load` and
`ct.store` for `check_bounds`, `latency`, and `allow_tma` controls. Equal shape and step use the ordinary Tile IR partition view;
unequal values require Tile IR bytecode v13.3 or newer. This is distinct from
`@view a[1:2:end, :]`, which steps individual elements rather than tile
origins.

### Atomics
| Operation | Description |
|-----------|-------------|
Expand Down
16 changes: 16 additions & 0 deletions src/bytecode/encodings.jl
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ module Opcode
const UnpackOp = 112 # since 13.3
# 113 (AllocaOp) not implemented
const MmaFScaledOp = 114 # since 13.3
const MakeStridedViewOp = 116 # since 13.3
const InsertOp = 118 # since 13.4
end

Expand Down Expand Up @@ -462,6 +463,21 @@ function encode_MakePartitionViewOp!(cb::CodeBuilder, result_type::TypeId, tenso
return new_op!(cb)
end

"""
encode_MakeStridedViewOp!(cb, result_type, tensor_view) -> Value

Create a strided view from a tensor view.
Opcode: 116 (Tile IR v13.3+)
"""
function encode_MakeStridedViewOp!(cb::CodeBuilder, result_type::TypeId, tensor_view::Value)
cb.version >= v"13.3" ||
throw(IRError("MakeStridedViewOp requires Tile IR v13.3+, got v$(cb.version)"))
encode_varint!(cb.buf, Opcode.MakeStridedViewOp)
encode_typeid!(cb.buf, result_type)
encode_operand!(cb.buf, tensor_view)
return new_op!(cb)
end

"""
encode_GetIndexSpaceShapeOp!(cb, result_types, partition_view) -> Tuple{Value...}

Expand Down
19 changes: 19 additions & 0 deletions src/bytecode/types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ module CompositeType
const TensorView = UInt8(0x0e)
const PartitionView = UInt8(0x0f)
const Func = UInt8(0x10)
const StridedView = UInt8(0x15) # since 13.3
end

# Dynamic shape marker
Expand Down Expand Up @@ -206,6 +207,24 @@ function partition_view_type!(table::TypeTable,
_get_or_create!(table, buf)
end

function strided_view_type!(table::TypeTable,
tile_shape::TileShape,
traversal_strides::TileShape,
tensor_view::TypeId,
dim_map::AbstractVector{<:Integer},
padding_value::PaddingValue.T)
table.version >= v"13.3" ||
throw(IRError("StridedView requires Tile IR bytecode v13.3+, got v$(table.version)"))
buf = UInt8[CompositeType.StridedView]
encode_optional_flags!(buf, padding_value)
encode_int_list!(buf, collect(tile_shape), 4)
encode_int_list!(buf, collect(traversal_strides), 4)
encode_varint!(buf, tensor_view.id)
encode_int_list!(buf, dim_map, 4)
encode_optional_padding_byte!(buf, padding_value)
_get_or_create!(table, buf)
end

function function_type!(table::TypeTable,
param_types::AbstractVector{TypeId},
result_types::AbstractVector{TypeId})
Expand Down
6 changes: 4 additions & 2 deletions src/compiler/analysis/alias.jl
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ function transfer(a::AliasAnalysis, r::DataflowResult, @nospecialize(func),

# View constructors and pointer passthroughs: propagate from the source
# operand. `make_tensor_view(::Type{T}, ptr, sizes, strides)` — alias source
# is the ptr (operand 2). `make_partition_view(tv, ...)` — operand 1.
# is the ptr (operand 2). Tile-view constructors take their TensorView as
# operand 1.
if is_view_constructor(func) || is_pointer_passthrough(func)
src_idx = func === Intrinsics.make_tensor_view ? 2 : 1
length(ops) >= src_idx && return operand_value(a, r, ops[src_idx])
Expand All @@ -101,7 +102,8 @@ These propagate alias identity from their first operand.
"""
function is_view_constructor(func)
return func === Intrinsics.make_tensor_view ||
func === Intrinsics.make_partition_view
func === Intrinsics.make_partition_view ||
func === Intrinsics.make_strided_view
end

function is_pointer_passthrough(func)
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/analysis/effects.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ externally observable side effect).
"""
function classify_memory_op(resolved_func)
if resolved_func === Intrinsics.load_partition_view ||
resolved_func === Intrinsics.load_strided_view ||
resolved_func === Intrinsics.load_ptr_tko
return MEM_LOAD
elseif resolved_func === Intrinsics.store_partition_view ||
resolved_func === Intrinsics.store_strided_view ||
resolved_func === Intrinsics.store_ptr_tko
return MEM_STORE
elseif resolved_func === Intrinsics.print_tko
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/intrinsics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
module Intrinsics

using Base: compilerbarrier, inferencebarrier
using ..cuTile: Tile, TileArray, Constant, TensorView, PartitionView
using ..cuTile: Tile, TileArray, Constant, TensorView, PartitionView, StridedView
using ..cuTile: Signedness, ComparisonPredicate, ComparisonOrdering
using ..cuTile: IdentityVal, FloatIdentityVal, IntegerIdentityVal

Expand Down
Loading