Skip to content

Commit 7ceb34e

Browse files
[lang] Introduce cl.Array.from_parts
Replaces `cl.reinterpret_pointer_as_array` with `Array.from_parts`. ai-use: updating callsites. Signed-off-by: Asher Mancinelli <amancinelli@nvidia.com>
1 parent c458a11 commit 7ceb34e

17 files changed

Lines changed: 160 additions & 131 deletions

File tree

‎experimental/cuda-lang/src/cuda/lang/__init__.py‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,6 @@
155155
map_shared_to_cluster,
156156
map_shared_to_leader_block,
157157
shared_cluster_leader_bit_mask,
158-
reinterpret_pointer_as_array,
159158
_inline_ptx,
160159
ptx_comment,
161160
shfl_sync,
@@ -361,7 +360,6 @@
361360
"map_shared_to_cluster",
362361
"map_shared_to_leader_block",
363362
"shared_cluster_leader_bit_mask",
364-
"reinterpret_pointer_as_array",
365363
"_inline_ptx",
366364
"ptx_comment",
367365
"Array",

‎experimental/cuda-lang/src/cuda/lang/_ir/op_defs.py‎

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -205,11 +205,6 @@ def has_observable_effect(self) -> bool:
205205
return self.mmio or self.memory_order is MemoryOrder.ACQUIRE
206206

207207

208-
@dataclass(eq=False)
209-
class ReinterpretPointerAsArray(Operation, opcode="reinterpret_ptr_as_array"):
210-
pointer: Var = operand()
211-
212-
213208
@dataclass
214209
class TensorMapAsOpaquePtr(Operation, opcode="tensor_map_as_opaque_ptr"):
215210
tensor_map: Var = operand()

‎experimental/cuda-lang/src/cuda/lang/_ir/op_impl/pointer_impl.py‎

Lines changed: 17 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
AtomicLoad,
2626
AtomicStore,
2727
LoadPointer,
28-
ReinterpretPointerAsArray,
2928
StorePointer,
3029
)
3130
from cuda.lang._ir.type_checking_helpers import (
@@ -44,9 +43,9 @@
4443
uint64,
4544
)
4645
from cuda.tile._ir.arithmetic_ops import astype, binary_arithmetic_tensorlike_raw
47-
from cuda.tile._ir.cast_ops import address_space_cast, implicit_cast, reinterpret_pointer
46+
from cuda.tile._ir.cast_ops import address_space_cast, implicit_cast
4847
from cuda.tile._ir.core_ops import bind_method, loosely_typed_const, strictly_typed_const
49-
from cuda.tile._ir.ir import add_operation_variadic
48+
from cuda.tile._ir.ir import add_operation_variadic, make_aggregate
5049
from cuda.tile._ir.op_impl import (
5150
ImplRegistry,
5251
WILDCARD,
@@ -460,39 +459,29 @@ def address_space_cast_impl(value: Var, memory_space: Var) -> Var:
460459
return address_space_cast(value, memory_space)
461460

462461

463-
@impl(core_api.reinterpret_pointer_as_array)
464-
def reinterpret_pointer_as_array_impl(pointer: Var, dtype: Var, shape: Var, strides: Var) -> Var:
465-
if not strides.is_constant() or strides.get_constant() is not None:
466-
raise TypeCheckingError(
467-
"Reinterpreting a pointer as an array with "
468-
"non-default strides is not yet implemented."
469-
)
470-
pointer_ty = require_pointer_type(pointer)
462+
@impl(Array.from_parts)
463+
def array_from_parts_impl(pointer: Var, shape: Var, strides: Var) -> Var:
464+
pointer_ty = require_concrete_pointer_type(pointer)
471465
shape = require_constant_int_tuple(shape, allow_single_int=True)
472-
dtype = require_dtype_spec(dtype)
473-
strides = contiguous_strides_from_shape(shape)
474-
memory_space = pointer_ty.memory_space
475-
476-
typed_pointer_ty = PointerTy(pointer_dtype(dtype, memory_space))
477-
if pointer.get_type() != typed_pointer_ty:
478-
pointer = reinterpret_pointer(pointer, typed_pointer_ty.pointer_dtype)
466+
if strides.is_constant() and strides.get_constant() is None:
467+
strides = contiguous_strides_from_shape(shape)
468+
else:
469+
strides = require_constant_int_tuple(strides, allow_single_int=True)
470+
if len(strides) != len(shape):
471+
raise TypeCheckingError(
472+
f"Shape and strides must have the same rank, got {len(shape)} and {len(strides)}"
473+
)
479474
index_dtype = datatype.int32
480475
array_ty = ArrayTy(
481-
dtype,
476+
pointer_ty.pointee_dtype,
482477
shape=shape,
483478
strides=strides,
484479
typing_hooks=pointer.ctx.typing_hooks,
485480
index_dtype=index_dtype,
486-
memory_space=memory_space,
487-
)
488-
result = add_operation(
489-
ReinterpretPointerAsArray,
490-
array_ty,
491-
pointer=pointer,
481+
memory_space=pointer_ty.memory_space,
492482
)
493-
# FIXME: it seems that the index dtype should be derived from the dtype of shape/strides instead
483+
# FIXME: Derive the index dtype from the shape and stride dtypes.
494484
size_ty = ScalarTy(index_dtype)
495485
shape_vars = tuple(strictly_typed_const(extent, size_ty) for extent in shape)
496486
stride_vars = tuple(strictly_typed_const(extent, size_ty) for extent in strides)
497-
result.set_aggregate(ArrayValue(pointer, shape_vars, stride_vars))
498-
return result
487+
return make_aggregate(ArrayValue(pointer, shape_vars, stride_vars), array_ty)

‎experimental/cuda-lang/src/cuda/lang/_ir/ops.py‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,6 @@
105105
VectorReduce,
106106
StorePointer,
107107
LoadPointer,
108-
ReinterpretPointerAsArray,
109108
BitCast,
110109
FmaOperation,
111110
)
@@ -958,7 +957,6 @@ def _unflatten_aggregate_array_impl(val: ArrayValue, ty: ArrayTy, result_var: Va
958957
"PointerOffset",
959958
"LoadPointer",
960959
"ReinterpretPointer",
961-
"ReinterpretPointerAsArray",
962960
"StorePointer",
963961
"RawWhereOperation",
964962
"Unary",

‎experimental/cuda-lang/src/cuda/lang/_passes/handle_dyn_shared_mem.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
from cuda.lang._ir._host_program import HostProgram, host_program_to_ir
88
from cuda.lang._ir.ops import AllocDynSharedMemory, GetDynSharedMemoryBasePtr, \
99
get_dyn_shared_memory_base_ptr
10-
from cuda.lang._ir.op_impl.pointer_impl import reinterpret_pointer, pointer_with_offset
10+
from cuda.lang._ir.op_impl.pointer_impl import pointer_with_offset
11+
from cuda.tile._ir.cast_ops import reinterpret_pointer
1112
from cuda.lang._datatype import int32
1213
from cuda.lang._exception import TypeCheckingError
1314
from cuda.lang._ir.type import PointerTy, ScalarTy

‎experimental/cuda-lang/src/cuda/lang/_passes/ir2mlir/pass_definition.py‎

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -353,13 +353,6 @@ def _get_mlir_comparison_op(
353353
return None
354354

355355

356-
# These operations have aggregate results. The RHS's elements are stored to
357-
# the LHS's when lowering Assign operations and are no-ops at the MLIR level.
358-
_NOOP_LOWERINGS = frozenset([
359-
ops.ReinterpretPointerAsArray,
360-
])
361-
362-
363356
@dataclass(kw_only=True)
364357
class MLIRLoweringContext:
365358
"""Mutable data shared by host and device MLIR operation lowering."""
@@ -945,9 +938,6 @@ def lower_block(self, ir_block: ir.Block) -> None:
945938
for operation in ir_block.operations:
946939
context.current_op = operation
947940

948-
if isinstance(operation, tuple(_NOOP_LOWERINGS)):
949-
continue
950-
951941
operation_loc = None
952942
if self.compiler_options.debug_info == "line":
953943
operation_loc = ir_loc_to_mlir_location(operation.loc)

‎experimental/cuda-lang/src/cuda/lang/_stub/core_api.py‎

Lines changed: 41 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,47 @@ class Array(TileArray, Generic[T]):
3434
N-dimensional array type.
3535
"""
3636

37+
@staticmethod
38+
@stub
39+
def from_parts(
40+
pointer: Pointer[T],
41+
shape: int | tuple[int, ...],
42+
strides: int | tuple[int, ...] | None = None,
43+
) -> "Array[T]":
44+
"""Create an array from a pointer, shape, and optional strides.
45+
46+
The pointer sets the array data type, so the pointer must be typed.
47+
If ``strides`` is ``None``, the array uses contiguous row-major strides.
48+
49+
Args:
50+
pointer: Typed pointer to the first array element.
51+
shape: Number of elements in each array dimension.
52+
strides: Step in elements for each dimension.
53+
54+
Returns:
55+
Array that refers to the memory at ``pointer``.
56+
57+
Examples:
58+
59+
.. testcode::
60+
:template: kernel_wrapper.py
61+
62+
smem_array = cl.shared_array(1, cl.int32)
63+
smem_array[0] = 5
64+
65+
smem_ptr = smem_array.pointer()
66+
smem_array_2 = cl.Array.from_parts(smem_ptr, 1)
67+
68+
# Assignment through the new array changes memory referenced by the
69+
# original array.
70+
smem_array_2[0] = 7
71+
print(smem_array[0])
72+
73+
.. testoutput::
74+
75+
7
76+
"""
77+
3778
@stub
3879
@property
3980
def dtype(self): ...
@@ -1077,46 +1118,6 @@ def map_shared_to_leader_block(pointer: Pointer[T]) -> Pointer[T]:
10771118
"""
10781119

10791120

1080-
@stub
1081-
def reinterpret_pointer_as_array(
1082-
pointer: Pointer[T],
1083-
dtype: DType,
1084-
shape: tuple[int, ...],
1085-
strides: tuple[int, ...] | None = None,
1086-
) -> Array[T]:
1087-
"""
1088-
Args:
1089-
pointer: Pointer[T]
1090-
dtype: DType
1091-
shape: tuple[int, ...]
1092-
strides: tuple[int, ...] | None = None
1093-
1094-
Returns:
1095-
Array with the specified base pointer, dtype, shape, and strides.
1096-
1097-
Examples:
1098-
1099-
.. testcode::
1100-
:template: kernel_wrapper.py
1101-
1102-
smem_array = cl.shared_array(1, cl.int32)
1103-
smem_array[0] = 5
1104-
1105-
smem_ptr = smem_array.pointer()
1106-
smem_array_2 = cl.reinterpret_pointer_as_array(smem_ptr, shape=1, dtype=cl.int32)
1107-
1108-
# Assignment through the reconstructed array is equivalent
1109-
# to assignment through the original.
1110-
smem_array_2[0] = 7
1111-
print(smem_array[0])
1112-
1113-
.. testoutput::
1114-
1115-
7
1116-
1117-
"""
1118-
1119-
11201121
def nanosleep(nanoseconds: int):
11211122
"""
11221123
Sleep for ``nanoseconds`` nanoseconds.

‎experimental/cuda-lang/test/examples/test_histogram64.py‎

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,8 @@ def histogram64_kernel(d_PartialHistograms, d_Data, dataCount):
5555
shape=(HISTOGRAM64_THREADBLOCK_SIZE * HISTOGRAM64_BIN_COUNT,),
5656
dtype=cl.uint8,
5757
)
58-
s_ThreadBase = cl.reinterpret_pointer_as_array(
59-
s_Hist.pointer((threadPos,)),
60-
cl.uint8,
61-
1,
58+
s_ThreadBase = cl.Array.from_parts(
59+
s_Hist.pointer(threadPos), 1
6260
)
6361

6462
for i in cl.static_iter(range(HISTOGRAM64_BIN_COUNT)):
@@ -76,10 +74,8 @@ def histogram64_kernel(d_PartialHistograms, d_Data, dataCount):
7674
cl.barrier_sync_block()
7775

7876
if tx < HISTOGRAM64_BIN_COUNT:
79-
s_HistBase = cl.reinterpret_pointer_as_array(
80-
s_Hist.pointer((tx * HISTOGRAM64_THREADBLOCK_SIZE,)),
81-
cl.uint8,
82-
1,
77+
s_HistBase = cl.Array.from_parts(
78+
s_Hist.pointer(tx * HISTOGRAM64_THREADBLOCK_SIZE), 1
8379
)
8480
sum = cl.uint32(0)
8581
pos = 4 * (tx & (SHARED_MEMORY_BANKS - 1))

‎experimental/cuda-lang/test/test_nvvm_intrinsics.py‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ def test_smem_pointer_arg_intrinsic():
7676
def kern(y):
7777
smem = cl.shared_array(1, dtype=cl.int32)
7878
p = cl._nvvm.mapa_shared_cluster(smem.pointer(), 0)
79-
a = cl.reinterpret_pointer_as_array(p, cl.int32, (1,))
79+
p = cl.bitcast(p, cl.pointer_dtype(cl.int32, p.memory_space))
80+
a = cl.Array.from_parts(p, 1)
8081
a[0] = 13
8182
y[0] = smem[0]
8283

@@ -91,7 +92,8 @@ def test_generic_pointer_arg_intrinsic():
9192
def kern(y):
9293
smem = cl.shared_array(1, dtype=cl.int32)
9394
p = cl._nvvm.mapa(smem.pointer(), 0)
94-
a = cl.reinterpret_pointer_as_array(p, cl.int32, (1,))
95+
p = cl.bitcast(p, cl.pointer_dtype(cl.int32, p.memory_space))
96+
a = cl.Array.from_parts(p, 1)
9597
a[0] = 13
9698
y[0] = smem[0]
9799

‎experimental/cuda-lang/test/test_pointers.py‎

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ def test_ptr_roundtrip():
382382
def kernel(A):
383383
B = cl.shared_array(shape=(3, 3), dtype=cl.int32)
384384
smem = B.pointer()
385-
B2 = cl.reinterpret_pointer_as_array(smem, cl.int32, 1)
385+
B2 = cl.Array.from_parts(smem, 1)
386386
B2[0] = 1
387387
A[0] = B[0, 0]
388388
B2[0] = 2
@@ -393,6 +393,68 @@ def kernel(A):
393393
assert A.cpu().tolist() == [1, 2]
394394

395395

396+
def test_array_from_parts_with_strides():
397+
@cl.kernel
398+
def kernel(array):
399+
view = cl.Array.from_parts(array.pointer(), (2, 2), (3, 1))
400+
cl.static_assert(view.shape == (2, 2))
401+
cl.static_assert(view.strides == (3, 1))
402+
cl.static_assert(view.dtype == cl.int32)
403+
view[0, 0] = 10
404+
view[0, 1] = 11
405+
view[1, 0] = 12
406+
view[1, 1] = 13
407+
408+
array = torch.zeros(5, dtype=torch.int32, device="cuda")
409+
cl.launch(torch.cuda.current_stream(), (1,), (1,), kernel, (array,))
410+
assert array.cpu().tolist() == [10, 11, 0, 12, 13]
411+
412+
413+
def test_array_from_parts_uses_pointer_dtype():
414+
@cl.kernel
415+
def kernel(array):
416+
pointer = cl.bitcast(
417+
array.pointer(),
418+
cl.pointer_dtype(cl.float32, cl.MemorySpace.GLOBAL),
419+
)
420+
view = cl.Array.from_parts(pointer, 1)
421+
cl.static_assert(view.dtype == cl.float32)
422+
view[0] = 1.5
423+
424+
array = torch.zeros(1, dtype=torch.int32, device="cuda")
425+
cl.launch(torch.cuda.current_stream(), (1,), (1,), kernel, (array,))
426+
assert array.cpu().item() == 0x3FC00000
427+
428+
429+
def test_array_from_parts_rejects_stride_rank_mismatch():
430+
def kernel(array):
431+
cl.Array.from_parts(array.pointer(), (2, 2), (1,))
432+
433+
compile_kernel(
434+
kernel,
435+
signature=KernelSignature((make_symbolic_tensor(4, cl.int32),)),
436+
raises=pytest.raises(
437+
TypeCheckingError,
438+
match="Shape and strides must have the same rank, got 2 and 1",
439+
),
440+
)
441+
442+
443+
def test_array_from_parts_rejects_opaque_pointer():
444+
def kernel(array):
445+
pointer = cl.bitcast(array.pointer(), cl.opaque_pointer_dtype())
446+
cl.Array.from_parts(pointer, 1)
447+
448+
compile_kernel(
449+
kernel,
450+
signature=KernelSignature((make_symbolic_tensor(1, cl.int32),)),
451+
raises=pytest.raises(
452+
TypeCheckingError,
453+
match="Expected concrete pointer type but got opaque_pointer",
454+
),
455+
)
456+
457+
396458
def test_pointer_smem():
397459
@cl.kernel
398460
def kernel(A):

0 commit comments

Comments
 (0)