From b1294b0a993a8d3e59f6b6ae9bb6b4ca2ff349f3 Mon Sep 17 00:00:00 2001 From: nihalpasham Date: Sun, 18 Oct 2026 14:48:36 +0530 Subject: [PATCH 1/3] feat(cuda-oxide): add #[tile_export] for Rust functions called from Tile kernels `#[tile_export(shape = N, ...)]` marks a device function as an entry of a cuTile tile library. The attribute leaves the function as it is and generates two items beside it: a `#[device] extern "C"` wrapper on the native SIMT ABI the Tile compiler calls (`in` scalars by value, `&T`, `&mut T`, `&[T; N]` and `&mut [T; N]` as pointers, a scalar return as a trailing `out` pointer), and a host-only metadata function whose body is the export's JSON description. - `oxide-tile-export` (new crate): the description vocabulary shared by the macro, the backend and `cargo oxide tilelib`, with the rules a library entry must satisfy (one dimension, one footprint for every parameter, one contiguous run of written parameters, whole warps for `sync = "warp"`). - `reserved-oxide-symbols`: the `cuda_oxide_tile_export_246e25db_` prefix of the metadata functions. - `rustc-codegen-cuda`: the collector reads each description out of the metadata function's MIR, roots the wrapper even when the crate has kernels, rejects duplicate names and symbols and device-side calls of the metadata function, and writes `.tileexports.json` next to the device artifact. - trybuild tests for the accepted forms and every rejection; the example lockfiles pick up the new dependency of cuda-macros. Signed-off-by: nihalpasham --- .github/workflows/unit-tests.yml | 3 + cuda-oxide/Cargo.lock | 10 + cuda-oxide/Cargo.toml | 4 + cuda-oxide/Justfile | 2 +- cuda-oxide/README.md | 4 + cuda-oxide/crates/cuda-device/README.md | 1 + cuda-oxide/crates/cuda-device/src/lib.rs | 2 +- cuda-oxide/crates/cuda-macros/Cargo.toml | 3 + cuda-oxide/crates/cuda-macros/src/common.rs | 8 +- cuda-oxide/crates/cuda-macros/src/lib.rs | 105 ++ .../crates/cuda-macros/src/tests/mod.rs | 1 + .../cuda-macros/src/tests/tile_export.rs | 385 ++++++ .../crates/cuda-macros/src/tile_export.rs | 679 +++++++++++ .../tests/compile_fail/tile_export_generic.rs | 11 + .../compile_fail/tile_export_generic.stderr | 5 + .../compile_fail/tile_export_missing_shape.rs | 11 + .../tile_export_missing_shape.stderr | 5 + .../tile_export_mixed_footprints.rs | 13 + .../tile_export_mixed_footprints.stderr | 5 + .../compile_fail/tile_export_no_outputs.rs | 11 + .../tile_export_no_outputs.stderr | 5 + .../compile_fail/tile_export_outputs_split.rs | 13 + .../tile_export_outputs_split.stderr | 5 + .../tile_export_unknown_argument.rs | 11 + .../tile_export_unknown_argument.stderr | 5 + .../tile_export_unsupported_param.rs | 11 + .../tile_export_unsupported_param.stderr | 5 + .../tile_export_warp_footprint.rs | 13 + .../tile_export_warp_footprint.stderr | 5 + .../compile_fail/tile_export_warp_shape.rs | 11 + .../tile_export_warp_shape.stderr | 5 + .../cuda-macros/tests/device-only/Cargo.lock | 104 +- .../tests/pass/tile_export_forms.rs | 70 ++ .../cuda-macros/tests/tile_export_guard.rs | 21 + .../crates/oxide-tile-export/Cargo.toml | 17 + cuda-oxide/crates/oxide-tile-export/README.md | 21 + .../crates/oxide-tile-export/src/lib.rs | 1068 +++++++++++++++++ .../crates/reserved-oxide-symbols/README.md | 3 +- .../crates/reserved-oxide-symbols/src/lib.rs | 129 ++ .../crates/rustc-codegen-cuda/.gitignore | 8 + .../crates/rustc-codegen-cuda/Cargo.lock | 10 + .../crates/rustc-codegen-cuda/Cargo.toml | 2 + .../examples/abi_hmm/Cargo.lock | 35 + .../examples/addressof_sharedarray/Cargo.lock | 35 + .../examples/aligned_field_loads/Cargo.lock | 35 + .../examples/aligned_field_stores/Cargo.lock | 35 + .../examples/array_constants/Cargo.lock | 35 + .../examples/array_for_loop/Cargo.lock | 35 + .../examples/array_index/Cargo.lock | 35 + .../examples/array_init/Cargo.lock | 35 + .../examples/asin_acos_smoke/Cargo.lock | 35 + .../assume_init_uninhabited_trap/Cargo.lock | 35 + .../examples/async_mlp/Cargo.lock | 35 + .../examples/async_vecadd/Cargo.lock | 35 + .../examples/atomic_f16/Cargo.lock | 35 + .../examples/atomics/Cargo.lock | 35 + .../examples/barrier/Cargo.lock | 35 + .../examples/bf16x2_arith/Cargo.lock | 35 + .../examples/bf16x2_fma/Cargo.lock | 35 + .../examples/bool_phi_cmp/Cargo.lock | 35 + .../examples/carrying_mul_add/Cargo.lock | 35 + .../examples/cast_chunks/Cargo.lock | 35 + .../examples/cast_tests/Cargo.lock | 35 + .../examples/cbrt_smoke/Cargo.lock | 35 + .../examples/checked_arith/Cargo.lock | 35 + .../examples/clc/Cargo.lock | 35 + .../examples/cluster/Cargo.lock | 35 + .../examples/compiler_features/Cargo.lock | 35 + .../examples/complex_mul/Cargo.lock | 35 + .../examples/const_aggregate/Cargo.lock | 35 + .../const_bool_dead_branch/Cargo.lock | 35 + .../examples/const_generic/Cargo.lock | 35 + .../examples/const_table_lookup/Cargo.lock | 35 + .../const_tuple_table_lookup/Cargo.lock | 35 + .../constant_index_from_end/Cargo.lock | 35 + .../examples/constant_memory/Cargo.lock | 35 + .../constant_memory_coeffs/Cargo.lock | 35 + .../constant_memory_simple/Cargo.lock | 35 + .../examples/constant_memory_table/Cargo.lock | 35 + .../examples/coop_groups_demo/Cargo.lock | 35 + .../examples/copy_aggregate_borrow/Cargo.lock | 35 + .../examples/copy_nonoverlapping/Cargo.lock | 35 + .../examples/counted_barrier/Cargo.lock | 35 + .../examples/cp_async_small/Cargo.lock | 35 + .../examples/cp_async_zfill/Cargo.lock | 35 + .../cpp_consumes_rust_device/Cargo.lock | 35 + .../examples/cross_crate_embedded/Cargo.lock | 35 + .../examples/cross_crate_kernel/Cargo.lock | 35 + .../cross_crate_merged_symbols/Cargo.lock | 35 + .../examples/cross_crate_recursion/Cargo.lock | 35 + .../examples/cuda_module_contract/Cargo.lock | 35 + .../examples/cuda_module_in_lib/Cargo.lock | 35 + .../examples/cuda_module_nested/Cargo.lock | 35 + .../examples/cutile_inter_kernel/Cargo.lock | 8 +- .../cutile_inter_kernel/simt/Cargo.lock | 35 + .../examples/cvt_f16x2/Cargo.lock | 35 + .../examples/cvt_packed/Cargo.lock | 35 + .../examples/debug-tests/Cargo.lock | 35 + .../examples/debug/Cargo.lock | 35 + .../examples/debug_pointer_locals/Cargo.lock | 35 + .../examples/device_closures/Cargo.lock | 35 + .../examples/device_ffi_test/Cargo.lock | 35 + .../examples/device_global/Cargo.lock | 35 + .../examples/device_panic_trap/Cargo.lock | 35 + .../disjoint_from_raw_parts/Cargo.lock | 35 + .../examples/disjoint_slice_len/Cargo.lock | 35 + .../examples/dotprod/Cargo.lock | 35 + .../examples/dpx_minmax_chains/Cargo.lock | 35 + .../examples/drop_glue/Cargo.lock | 35 + .../examples/dst_metadata/Cargo.lock | 35 + .../examples/dynamic_smem/Cargo.lock | 35 + .../examples/elect_leader/Cargo.lock | 35 + .../enum_abi_multi_payload/Cargo.lock | 35 + .../examples/enum_array_match/Cargo.lock | 35 + .../enum_constant_provenance/Cargo.lock | 35 + .../examples/enum_payload_addr/Cargo.lock | 35 + .../enum_state_transitions/Cargo.lock | 35 + .../examples/enum_table_lookup/Cargo.lock | 35 + .../examples/error/Cargo.lock | 35 + .../error_enum_bool_payload_addr/Cargo.lock | 35 + .../error_enum_pointer_overlap/Cargo.lock | 35 + .../Cargo.lock | 35 + .../error_generated_intrinsic_abi/Cargo.lock | 35 + .../Cargo.lock | 35 + .../Cargo.lock | 35 + .../Cargo.lock | 35 + .../examples/error_heap_alloc/Cargo.lock | 35 + .../error_host_arch_intrinsic/Cargo.lock | 35 + .../error_host_target_feature/Cargo.lock | 35 + .../error_kernel_shared_param/Cargo.lock | 35 + .../error_missing_device_attr/Cargo.lock | 35 + .../Cargo.lock | 35 + .../examples/ex2_approx_f16/Cargo.lock | 35 + .../examples/exact_div_chunks/Cargo.lock | 35 + .../examples/export_name_policy/Cargo.lock | 35 + .../examples/extern_crate_closure/Cargo.lock | 35 + .../examples/extern_libdevice/Cargo.lock | 35 + .../examples/f16_stress/Cargo.lock | 35 + .../examples/f16x2_arith/Cargo.lock | 35 + .../examples/f32x2_arith/Cargo.lock | 35 + .../examples/fcmp_ne_nan_smoke/Cargo.lock | 35 + .../examples/field_array_assign/Cargo.lock | 35 + .../examples/float_rounding/Cargo.lock | 35 + .../examples/fmaxmin_smoke/Cargo.lock | 35 + .../examples/fn_ptr_naming/Cargo.lock | 35 + .../fp_special_literal_smoke/Cargo.lock | 35 + .../examples/function_item_call/Cargo.lock | 35 + .../examples/future_apis/Cargo.lock | 35 + .../examples/gemm/Cargo.lock | 35 + .../examples/gemm_sol/Cargo.lock | 35 + .../examples/gemm_sol_final/Cargo.lock | 35 + .../examples/gemm_views/Cargo.lock | 35 + .../examples/generated_intrinsics/Cargo.lock | 35 + .../generated_intrinsics_blackwell/Cargo.lock | 35 + .../examples/generated_ldmatrix/Cargo.lock | 35 + .../examples/generic/Cargo.lock | 35 + .../examples/hashmap/Cargo.lock | 35 + .../examples/hashmap_v2/Cargo.lock | 35 + .../examples/hashmap_v3/Cargo.lock | 35 + .../examples/hello_constant/Cargo.lock | 35 + .../examples/helper_fn/Cargo.lock | 35 + .../examples/host_closure/Cargo.lock | 35 + .../host_closure_target_feature/Cargo.lock | 35 + .../examples/iket_trace/Cargo.lock | 35 + .../examples/image_convolution/Cargo.lock | 35 + .../examples/index2d_const/Cargo.lock | 35 + .../examples/index_field_assign/Cargo.lock | 35 + .../examples/inline_ptx/Cargo.lock | 35 + .../examples/integer_minmax/Cargo.lock | 35 + .../examples/interior_mutability/Cargo.lock | 35 + .../interop_cubin_identity/device/Cargo.lock | 35 + .../kernel_reference_validity/Cargo.lock | 35 + .../examples/lanemask_scan/Cargo.lock | 35 + .../examples/legacy_atomic_fadd/Cargo.lock | 35 + .../examples/legacy_atomic_rmw_cas/Cargo.lock | 35 + .../legacy_nvvm_pointer_shapes/Cargo.lock | 35 + .../examples/libdevice_math/Cargo.lock | 35 + .../examples/libm_math/Cargo.lock | 35 + .../examples/manual_launch_generic/Cargo.lock | 35 + .../manual_launch_libdevice/Cargo.lock | 35 + .../examples/map_sum/Cargo.lock | 35 + .../examples/math_atan/Cargo.lock | 35 + .../examples/math_hyperbolic/Cargo.lock | 35 + .../examples/math_no_mir_inline/Cargo.lock | 35 + .../examples/math_tan/Cargo.lock | 35 + .../examples/mathdx_ffi_test/Cargo.lock | 35 + .../examples/mcast_barrier_test/Cargo.lock | 35 + .../examples/mem_swap/Cargo.lock | 35 + .../mir_projected_call_destination/Cargo.lock | 35 + .../examples/mma_mxf8f6f4/Cargo.lock | 35 + .../examples/ne_bytes_transmute/Cargo.lock | 35 + .../nested_index_assignment/Cargo.lock | 35 + .../examples/numeric_stress/Cargo.lock | 35 + .../examples/nvls_all_reduce/Cargo.lock | 35 + .../examples/option_ref_transmute/Cargo.lock | 35 + .../examples/option_ref_unwrap_or/Cargo.lock | 35 + .../examples/option_unwrap_trap/Cargo.lock | 35 + .../examples/ord_cmp/Cargo.lock | 35 + .../examples/packed_aggregate_abi/Cargo.lock | 35 + .../examples/packed_atomic_add/Cargo.lock | 35 + .../examples/padded_constants/Cargo.lock | 35 + .../examples/partial_warp_reduce/Cargo.lock | 35 + .../examples/pinned_overlap/Cargo.lock | 35 + .../examples/place_read_fallbacks/Cargo.lock | 35 + .../examples/policy_config/Cargo.lock | 35 + .../examples/primitive_stress/Cargo.lock | 35 + .../examples/printf/Cargo.lock | 35 + .../examples/projected_place_read/Cargo.lock | 35 + .../examples/proof_carrying_views/Cargo.lock | 35 + .../examples/ptr_copy/Cargo.lock | 35 + .../examples/ptr_offset_from/Cargo.lock | 35 + .../ptr_without_provenance/Cargo.lock | 35 + .../examples/reborrow/Cargo.lock | 35 + .../examples/redux_f32/Cargo.lock | 35 + .../examples/redux_minmax/Cargo.lock | 35 + .../examples/redux_sum/Cargo.lock | 35 + .../examples/ref_index_projections/Cargo.lock | 35 + .../examples/ref_operand_mul/Cargo.lock | 35 + .../examples/repr_align_block_args/Cargo.lock | 35 + .../examples/repr_transparent_abi/Cargo.lock | 35 + .../examples/repr_u32_enum_stride/Cargo.lock | 35 + .../examples/row_width_slice/Cargo.lock | 35 + .../examples/rustlantis-smoke/Cargo.lock | 35 + .../scoped_atomic_load_store/Cargo.lock | 35 + .../examples/select_unpredictable/Cargo.lock | 35 + .../examples/set_discriminant/Cargo.lock | 35 + .../set_discriminant_niche/Cargo.lock | 35 + .../examples/shared_debug/Cargo.lock | 35 + .../examples/shared_memory_helper/Cargo.lock | 35 + .../examples/shared_ptr_transmute/Cargo.lock | 35 + .../examples/shared_slice_unsize/Cargo.lock | 35 + .../examples/shared_stage_select/Cargo.lock | 35 + .../examples/sharedmem/Cargo.lock | 35 + .../examples/shuffle_64/Cargo.lock | 35 + .../slice_from_raw_parts_cast/Cargo.lock | 35 + .../examples/slice_get_mut/Cargo.lock | 35 + .../slice_index_bounds_check/Cargo.lock | 35 + .../examples/slice_iterators/Cargo.lock | 35 + .../examples/slice_reslice/Cargo.lock | 35 + .../examples/small_type_ffi_test/Cargo.lock | 35 + .../examples/sparse_mma_fp8/Cargo.lock | 35 + .../sparse_mma_ordered_float/Cargo.lock | 35 + .../examples/split_at_mut/Cargo.lock | 35 + .../examples/standalone_device_fn/Cargo.lock | 35 + .../examples/static_slice_addend/Cargo.lock | 35 + .../examples/static_slice_unsize/Cargo.lock | 35 + .../examples/step_by/Cargo.lock | 35 + .../struct_constant_provenance/Cargo.lock | 35 + .../examples/struct_field_layout/Cargo.lock | 35 + .../examples/subslice_projection/Cargo.lock | 35 + .../examples/switchint_128bit/Cargo.lock | 35 + .../examples/swizzle_smem/Cargo.lock | 35 + .../examples/tcgen05/Cargo.lock | 35 + .../examples/tcgen05_matmul/Cargo.lock | 35 + .../examples/thread_runs/Cargo.lock | 35 + .../examples/tiled_gemm/Cargo.lock | 35 + .../examples/tma_copy/Cargo.lock | 35 + .../examples/tma_multicast/Cargo.lock | 35 + .../toolchain_pairing_smoke/Cargo.lock | 35 + .../transmute_scalar_struct/Cargo.lock | 35 + .../tuple_array_provenance/Cargo.lock | 35 + .../tuple_constant_provenance/Cargo.lock | 35 + .../examples/tuple_field_lookup/Cargo.lock | 35 + .../examples/tuple_return/Cargo.lock | 35 + .../examples/unaligned_memory/Cargo.lock | 35 + .../examples/unchecked_indexing/Cargo.lock | 35 + .../examples/uninit_const/Cargo.lock | 35 + .../examples/union_aggregate/Cargo.lock | 35 + .../examples/unroll_bounds_check/Cargo.lock | 35 + .../examples/unroll_smoke/Cargo.lock | 35 + .../examples/vecadd/Cargo.lock | 35 + .../examples/vectorization/Cargo.lock | 35 + .../examples/volatile_memory/Cargo.lock | 35 + .../examples/warp_reduce/Cargo.lock | 35 + .../examples/warp_sums/Cargo.lock | 35 + .../examples/wgmma/Cargo.lock | 35 + .../examples/wgmma_mma_bf16/Cargo.lock | 35 + .../rustc-codegen-cuda/src/collector.rs | 241 +++- .../crates/rustc-codegen-cuda/src/lib.rs | 38 + .../compiler/architecture-overview.md | 1 + cuda-oxide/dependency-licenses.csv | 1 + 281 files changed, 11275 insertions(+), 14 deletions(-) create mode 100644 cuda-oxide/crates/cuda-macros/src/tests/tile_export.rs create mode 100644 cuda-oxide/crates/cuda-macros/src/tile_export.rs create mode 100644 cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_generic.rs create mode 100644 cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_generic.stderr create mode 100644 cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_missing_shape.rs create mode 100644 cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_missing_shape.stderr create mode 100644 cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_mixed_footprints.rs create mode 100644 cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_mixed_footprints.stderr create mode 100644 cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_no_outputs.rs create mode 100644 cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_no_outputs.stderr create mode 100644 cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_outputs_split.rs create mode 100644 cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_outputs_split.stderr create mode 100644 cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_unknown_argument.rs create mode 100644 cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_unknown_argument.stderr create mode 100644 cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_unsupported_param.rs create mode 100644 cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_unsupported_param.stderr create mode 100644 cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_warp_footprint.rs create mode 100644 cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_warp_footprint.stderr create mode 100644 cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_warp_shape.rs create mode 100644 cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_warp_shape.stderr create mode 100644 cuda-oxide/crates/cuda-macros/tests/pass/tile_export_forms.rs create mode 100644 cuda-oxide/crates/cuda-macros/tests/tile_export_guard.rs create mode 100644 cuda-oxide/crates/oxide-tile-export/Cargo.toml create mode 100644 cuda-oxide/crates/oxide-tile-export/README.md create mode 100644 cuda-oxide/crates/oxide-tile-export/src/lib.rs diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index cf9a33179b..3c8515c891 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -68,6 +68,9 @@ jobs: # tests that cover the configuration actually built. - package: oxide-artifacts test_args: --all-targets --features object + # `#[tile_export]` descriptions and their validation rules, shared + # by cuda-macros, the backend and cargo-oxide. Pure Rust, no CUDA. + - package: oxide-tile-export - package: reserved-oxide-symbols # launch_requires_unsafe trybuild fixture dev-depends on # cuda-host/cuda-core, which transitively pull cuda-bindings diff --git a/cuda-oxide/Cargo.lock b/cuda-oxide/Cargo.lock index 2436a0edbf..4826c46343 100644 --- a/cuda-oxide/Cargo.lock +++ b/cuda-oxide/Cargo.lock @@ -466,6 +466,7 @@ dependencies = [ "cuda-core", "cuda-device", "cuda-host", + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -1101,6 +1102,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror 2.0.18", +] + [[package]] name = "parking_lot_core" version = "0.9.12" diff --git a/cuda-oxide/Cargo.toml b/cuda-oxide/Cargo.toml index 1e296a90a7..d4f6b8fc72 100644 --- a/cuda-oxide/Cargo.toml +++ b/cuda-oxide/Cargo.toml @@ -24,6 +24,7 @@ members = [ "crates/nvvm-transforms", "crates/cargo-oxide", "crates/oxide-artifacts", + "crates/oxide-tile-export", # FFI bindings "crates/libnvvm-sys", "crates/nvjitlink-sys", @@ -97,6 +98,9 @@ reserved-oxide-symbols = { path = "crates/reserved-oxide-symbols" } # publish, then move this line. # scripts/check-oxide-artifacts-parity.sh keeps them equal. oxide-artifacts = "0.2.1" +# Tile export descriptions shared by `#[tile_export]`, the backend, and +# `cargo oxide tilelib`. +oxide-tile-export = { path = "crates/oxide-tile-export" } ptx-parse = { path = "crates/ptx-parse" } ptx-schedule = { path = "crates/ptx-schedule" } diff --git a/cuda-oxide/Justfile b/cuda-oxide/Justfile index 36d083ba5c..71f9333506 100644 --- a/cuda-oxide/Justfile +++ b/cuda-oxide/Justfile @@ -61,7 +61,7 @@ test: -p cuda-intrinsics-gen -p cuda-target-spec -p cuda-intrinsics -p llvm-export \ -p dialect-mir -p dialect-nvvm -p mir-importer -p mir-lower \ -p mir-transforms -p nvvm-transforms -p reserved-oxide-symbols \ - -p cuda-device -p libnvvm-sys -p nvjitlink-sys \ + -p oxide-tile-export -p cuda-device -p libnvvm-sys -p nvjitlink-sys \ -p cuda-artifact-finalizer -p cargo-oxide \ -p dialect-iket -p iket-lower -p ptx-parse -p dialect-ptx \ -p ptx-schedule diff --git a/cuda-oxide/README.md b/cuda-oxide/README.md index 586f936a72..2c3c98a44b 100644 --- a/cuda-oxide/README.md +++ b/cuda-oxide/README.md @@ -139,6 +139,9 @@ cargo oxide test # Compile a crate's device code to a binary LTOIR artifact in one step cargo oxide emit-ltoir +# Package a crate's #[tile_export] functions as a cuTile tile library +cargo oxide tilelib + # Refresh the cached codegen backend cargo oxide update ``` @@ -335,6 +338,7 @@ cargo oxide run gemm_sol_final | `cuda-intrinsics-gen` | Extractor and deterministic source generator for the intrinsics | | `cuda-artifact-finalizer` | Driver-independent NVVM IR, LTOIR, and PTX finalization | | `oxide-artifacts` | Architecture-neutral embedded device artifact metadata | +| `oxide-tile-export` | `#[tile_export]` descriptions shared by the macro, the backend and `cargo oxide tilelib` | | `reserved-oxide-symbols` | Workspace-private `cuda_oxide_*` symbol-name contract | | `fuzzer` | Differential codegen fuzzer support (rustlantis adapter) | | `ptx-schedule` | PTX schedule-perturbation fuzzing (nanosleep injection campaigns) | diff --git a/cuda-oxide/crates/cuda-device/README.md b/cuda-oxide/crates/cuda-device/README.md index 9b43073eb6..0dbfe22e22 100644 --- a/cuda-oxide/crates/cuda-device/README.md +++ b/cuda-oxide/crates/cuda-device/README.md @@ -223,6 +223,7 @@ convenience. The table is the whole `pub use cuda_macros::{...}` list in | `#[pure]` | Mark as pure (no side effects) | | `#[readonly]` | Mark as read-only | | `#[constant]` | Place a `ConstantMemory` static in constant memory, plus a host `set_` setter | +| `#[tile_export]` | Export a device function to cuTile through a tile library | | `gpu_printf!` | Device-side printf | | `ptx_asm!` | Unsafe CUDA inline PTX | diff --git a/cuda-oxide/crates/cuda-device/src/lib.rs b/cuda-oxide/crates/cuda-device/src/lib.rs index a3171afbcf..a0b85677ce 100644 --- a/cuda-oxide/crates/cuda-device/src/lib.rs +++ b/cuda-oxide/crates/cuda-device/src/lib.rs @@ -12,7 +12,7 @@ extern crate self as cuda_device; pub use cuda_macros::{ cluster_launch, constant, convergent, cooperative_launch, cuda_module, device, gpu_printf, - kernel, launch_bounds, launch_contract, ptx_asm, pure, readonly, + kernel, launch_bounds, launch_contract, ptx_asm, pure, readonly, tile_export, }; // Re-export for convenience diff --git a/cuda-oxide/crates/cuda-macros/Cargo.toml b/cuda-oxide/crates/cuda-macros/Cargo.toml index a4cc3fbf4c..16a25c8459 100644 --- a/cuda-oxide/crates/cuda-macros/Cargo.toml +++ b/cuda-oxide/crates/cuda-macros/Cargo.toml @@ -40,6 +40,9 @@ quote = { workspace = true } syn = { workspace = true } proc-macro2 = { workspace = true } reserved-oxide-symbols = { workspace = true } +# `#[tile_export]` builds its description with the shared vocabulary and embeds +# it as JSON at expansion time; the serialization goes through that crate. +oxide-tile-export = { workspace = true } [dev-dependencies] trybuild = "1" diff --git a/cuda-oxide/crates/cuda-macros/src/common.rs b/cuda-oxide/crates/cuda-macros/src/common.rs index 5634dd9ec2..86602f5a6b 100644 --- a/cuda-oxide/crates/cuda-macros/src/common.rs +++ b/cuda-oxide/crates/cuda-macros/src/common.rs @@ -82,6 +82,12 @@ pub(crate) fn call_site_ident_avoiding_item(name: &str, item: &ItemFn) -> Ident /// Returns `Some(compile_error)` to be returned from the macro entry point, /// or `None` if the name is safe. pub(crate) fn reject_reserved_name(name: &Ident) -> Option { + reserved_name_error(name).map(|err| err.to_compile_error().into()) +} + +/// [`reject_reserved_name`] as a `syn::Error`, for macros that compose their +/// diagnostics before converting to a token stream. +pub(crate) fn reserved_name_error(name: &Ident) -> Option { let name_str = name.to_string(); if name_str.starts_with(RESERVED_ROOT) { let msg = format!( @@ -90,7 +96,7 @@ pub(crate) fn reject_reserved_name(name: &Ident) -> Option { is reserved for cuda-oxide internal symbol mangling \ (see cuda-oxide/crates/reserved-oxide-symbols)" ); - Some(syn::Error::new(name.span(), msg).to_compile_error().into()) + Some(syn::Error::new(name.span(), msg)) } else { None } diff --git a/cuda-oxide/crates/cuda-macros/src/lib.rs b/cuda-oxide/crates/cuda-macros/src/lib.rs index f7f1ac29ae..4c7d086d3b 100644 --- a/cuda-oxide/crates/cuda-macros/src/lib.rs +++ b/cuda-oxide/crates/cuda-macros/src/lib.rs @@ -39,6 +39,7 @@ mod launch; mod launch_attrs; mod printf; mod ptx_asm; +mod tile_export; #[cfg(test)] mod tests; @@ -872,6 +873,110 @@ pub fn device(_attr: TokenStream, item: TokenStream) -> TokenStream { device::device_entry(_attr, item) } +/// Exports a device function to cuTile programs through a tile library. +/// +/// A cuTile kernel calls the function with `foreign_call`, naming the +/// declaration; `cargo oxide tilelib` packages a crate's exports into the +/// `.tilelib` that call resolves against. The attribute leaves the annotated +/// function unchanged, so other device code keeps calling it, and generates +/// two items next to it: +/// +/// 1. `#[device] pub unsafe extern "C" fn (...)`: the implementation +/// the Tile IR call resolves to, on the native SIMT ABI below. It turns the +/// pointer parameters back into the references the function takes, calls +/// the function, and stores the return value through the trailing out +/// pointer. +/// 2. A host-only `#[no_mangle]` metadata function that returns the export's +/// JSON description. The codegen backend reads the string out of its MIR, +/// compiles the wrapper as a device root even when the crate also has +/// kernels, and writes `.tileexports.json` next to the device +/// artifact. The metadata function itself is never compiled for the device. +/// +/// # Arguments +/// +/// | Argument | Meaning | Default | +/// |-----------------------------|-------------------------------------------------|-------------------| +/// | `tile_shape = N` | 1-D tile extent (required) | none | +/// | `name = "..."` | declaration name the cuTile caller uses | the function name | +/// | `symbol = "..."` | implementation symbol in the device artifact | `_impl` | +/// | `sync = "none"` / `"warp"` | threads that must call the function together | `"none"` | +/// | `arch = ["sm_120", ...]` | compute capabilities the implementation supports| every architecture| +/// +/// `tile_shape` is required because this version ships concrete implementations: +/// a parametric one would need one mangled symbol per specialization in the +/// device artifact. `sync = "warp"` needs a tile shape that is a multiple of 32 +/// times the parameter footprint, so every invocation group fills whole +/// warps. `arch` is normally omitted, which matches every target; when given, +/// names are compared after stripping `_` and lowercasing, and a portable name +/// such as `"sm_120"` also matches the arch-conditional `sm_120a` the Tile +/// compiler builds for. +/// +/// # Signature +/// +/// The function cannot be generic or take `self`, and every parameter is a +/// plain identifier with one of these types, where `T` is one of `f16`, +/// `f32`, `f64`, `i8`, `i16`, `i32`, `i64`, `u8`, `u16`, `u32`, `u64`: +/// +/// | Rust parameter | access | footprint | ABI parameter | +/// |------------------|---------|-----------|---------------| +/// | `x: T` | `in` | 1 | `T` by value | +/// | `x: &T` | `in` | 1 | `*const T` | +/// | `x: &[T; N]` | `in` | N | `*const T` | +/// | `x: &mut T` | `inout` | 1 | `*mut T` | +/// | `x: &mut [T; N]` | `inout` | N | `*mut T` | +/// +/// The footprint is the number of contiguous tile elements one invocation +/// owns, and every parameter of one export has the same footprint: the +/// fragmaps of one implementation share their invocation count, so +/// `fn window(acc: &mut [i32; 4], bias: &i32)` is rejected and +/// `bias: &[i32; 4]` is the accepted form. +/// +/// A scalar return type `-> T` becomes an appended `out` parameter named +/// `_out`, passed as `*mut T`. Returning nothing is accepted only when some +/// parameter is `&mut`, because a declaration's results are its `out` and +/// `inout` arguments. Slices, raw pointers, tuples, structs, and `bool` are +/// not accepted. `bf16` is not an accepted element type either: `cuda-device` +/// carries bf16 values as `u16` bit patterns, so pass such tiles as `u16`. +/// +/// Thread identity inside the function is the hardware `threadIdx.x`. The +/// function may not allocate shared memory; a scratch buffer is not part of +/// this version of the description. +/// +/// # Example +/// +/// ```ignore +/// use cuda_device::tile_export; +/// +/// #[tile_export(tile_shape = 128)] +/// pub fn relu(x: f32) -> f32 { +/// if x > 0.0 { x } else { 0.0 } +/// } +/// +/// #[tile_export(tile_shape = 128, name = "scale_in_place", symbol = "scale_in_place_impl")] +/// pub fn scale(x: &mut f32, factor: f32) { +/// *x *= factor; +/// } +/// +/// #[tile_export(tile_shape = 128, sync = "warp", arch = ["sm_120"])] +/// pub fn warp_sum(x: f32) -> f32 { +/// // 32 lanes call this together, so shuffles are legal here. +/// let mut total = x; +/// let mut offset = 16; +/// while offset > 0 { +/// total += cuda_device::warp::shuffle_xor_f32_sync(u32::MAX, total, offset); +/// offset /= 2; +/// } +/// total +/// } +/// ``` +/// +/// `relu` becomes `define void @relu_impl(float, ptr)` and `scale` becomes +/// `define void @scale_in_place_impl(ptr, float)` in the device artifact. +#[proc_macro_attribute] +pub fn tile_export(attr: TokenStream, item: TokenStream) -> TokenStream { + tile_export::tile_export_entry(attr, item) +} + // ============================================================================ // NVVM Attributes for Device FFI // ============================================================================ diff --git a/cuda-oxide/crates/cuda-macros/src/tests/mod.rs b/cuda-oxide/crates/cuda-macros/src/tests/mod.rs index 8e7851e3b5..819c2218f1 100644 --- a/cuda-oxide/crates/cuda-macros/src/tests/mod.rs +++ b/cuda-oxide/crates/cuda-macros/src/tests/mod.rs @@ -6,3 +6,4 @@ mod cuda_module; mod kernel; mod launch; +mod tile_export; diff --git a/cuda-oxide/crates/cuda-macros/src/tests/tile_export.rs b/cuda-oxide/crates/cuda-macros/src/tests/tile_export.rs new file mode 100644 index 0000000000..cbc39bb858 --- /dev/null +++ b/cuda-oxide/crates/cuda-macros/src/tests/tile_export.rs @@ -0,0 +1,385 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use crate::tile_export::{TileExportArgs, expand_tile_export}; +use oxide_tile_export::{TileAccess, TileElem, TileExportDesc, TileSync}; +use proc_macro2::TokenStream as TokenStream2; +use quote::quote; +use reserved_oxide_symbols::tile_export_meta_symbol; +use syn::{ItemFn, parse_quote}; + +fn expand(args: TokenStream2, func: ItemFn) -> syn::Result { + let args: TileExportArgs = syn::parse2(args)?; + expand_tile_export(args, func).map(|tokens| tokens.to_string().replace(' ', "")) +} + +fn expand_err(args: TokenStream2, func: ItemFn) -> String { + match expand(args, func) { + Ok(expanded) => panic!("expected an error, got {expanded}"), + Err(err) => err.to_string(), + } +} + +/// Pull the embedded JSON back out of the expansion through the metadata +/// function's string literal. +fn embedded_desc(expanded: &str, symbol: &str) -> TileExportDesc { + let meta = tile_export_meta_symbol(symbol); + let start = expanded + .find(&format!("fn{meta}()")) + .unwrap_or_else(|| panic!("no metadata function `{meta}` in {expanded}")); + let rest = &expanded[start..]; + let open = rest.find('"').expect("string literal"); + let json: String = syn::parse_str::( + &rest[open..rest[open..].find("\"}").map(|end| open + end + 1).unwrap()], + ) + .expect("the metadata body is a string literal") + .value(); + TileExportDesc::from_json(&json).expect("embedded JSON parses") +} + +#[test] +fn scalar_in_and_returned_out_follow_the_table() { + let func: ItemFn = parse_quote! { + pub fn relu(x: f32) -> f32 { if x > 0.0 { x } else { 0.0 } } + }; + let expanded = expand(quote! { tile_shape = 128 }, func).unwrap(); + + // The original function survives unchanged. + assert!(expanded.contains("pubfnrelu(x:f32)->f32"), "{expanded}"); + // The wrapper is a `#[device]` extern "C" function on the native ABI. + assert!( + expanded.contains("#[::cuda_device::device]pubunsafeextern\"C\"fnrelu_impl("), + "{expanded}" + ); + assert!(expanded.contains(":f32,"), "{expanded}"); + assert!(expanded.contains(":*mutf32)"), "{expanded}"); + assert!(expanded.contains("=relu("), "{expanded}"); + + let desc = embedded_desc(&expanded, "relu_impl"); + desc.validate().unwrap(); + assert_eq!(desc.decl, "relu"); + assert_eq!(desc.symbol, "relu_impl"); + assert_eq!(desc.shape, vec![128]); + assert_eq!(desc.sync, TileSync::None); + assert!(desc.arch.is_empty()); + assert_eq!(desc.params.len(), 2); + assert_eq!(desc.params[0].name, "x"); + assert_eq!(desc.params[0].access, TileAccess::In); + assert!(desc.params[0].by_value); + assert_eq!(desc.params[1].name, "relu_out"); + assert_eq!(desc.params[1].access, TileAccess::Out); + assert_eq!(desc.params[1].elem, TileElem::F32); + assert!(!desc.params[1].by_value); +} + +#[test] +fn name_symbol_sync_and_arch_override_the_defaults() { + let func: ItemFn = parse_quote! { + pub fn scale(x: &mut f32, factor: f32) { *x *= factor; } + }; + let expanded = expand( + quote! { tile_shape = 128, name = "scale_in_place", symbol = "scale_impl_v2", sync = "warp", arch = ["sm_100", "sm_120"] }, + func, + ) + .unwrap(); + assert!( + expanded.contains("pubunsafeextern\"C\"fnscale_impl_v2("), + "{expanded}" + ); + assert!(expanded.contains(":*mutf32,"), "{expanded}"); + assert!(expanded.contains(":f32)"), "{expanded}"); + // `&mut T` is rebuilt from the pointer before the call. + assert!(expanded.contains("&mut*"), "{expanded}"); + + let desc = embedded_desc(&expanded, "scale_impl_v2"); + desc.validate().unwrap(); + assert_eq!(desc.decl, "scale_in_place"); + assert_eq!(desc.symbol, "scale_impl_v2"); + assert_eq!(desc.sync, TileSync::Warp); + assert_eq!(desc.arch, vec!["sm_100".to_string(), "sm_120".to_string()]); + assert_eq!(desc.params[0].access, TileAccess::InOut); + assert!(!desc.params[0].by_value); + assert_eq!(desc.params[1].access, TileAccess::In); + assert!(desc.params[1].by_value); +} + +#[test] +fn symbol_defaults_to_the_declaration_name() { + let func: ItemFn = parse_quote! { + pub fn scale(x: &mut f32) { *x *= 2.0; } + }; + let expanded = expand(quote! { tile_shape = 64, name = "double" }, func).unwrap(); + let desc = embedded_desc(&expanded, "double_impl"); + assert_eq!(desc.decl, "double"); + assert_eq!(desc.symbol, "double_impl"); +} + +#[test] +fn array_parameters_carry_their_footprint() { + let func: ItemFn = parse_quote! { + pub fn window(acc: &mut [i32; 4], bias: &[i32; 4]) { + let _ = (acc, bias); + } + }; + let expanded = expand(quote! { tile_shape = 64 }, func).unwrap(); + assert!(expanded.contains(":*muti32,"), "{expanded}"); + assert!(expanded.contains(":*consti32)"), "{expanded}"); + // Both arrays are rebuilt from their pointers before the call. + assert!(expanded.contains("as*mut[i32;4]"), "{expanded}"); + assert!(expanded.contains("as*const[i32;4]"), "{expanded}"); + + let desc = embedded_desc(&expanded, "window_impl"); + desc.validate().unwrap(); + let shapes: Vec<_> = desc + .params + .iter() + .map(|p| (p.name.as_str(), p.elem, p.access, p.footprint, p.by_value)) + .collect(); + assert_eq!( + shapes, + vec![ + ("acc", TileElem::I32, TileAccess::InOut, 4, false), + ("bias", TileElem::I32, TileAccess::In, 4, false), + ] + ); +} + +#[test] +fn scalar_references_and_halves_carry_footprint_one() { + let func: ItemFn = parse_quote! { + pub fn mix(scale: &'_ u16, half: f16, out: &mut u16) { + let _ = (scale, half, out); + } + }; + let expanded = expand(quote! { tile_shape = 64 }, func).unwrap(); + assert!(expanded.contains(":*constu16,"), "{expanded}"); + assert!(expanded.contains(":f16,"), "{expanded}"); + assert!(expanded.contains(":*mutu16)"), "{expanded}"); + + let desc = embedded_desc(&expanded, "mix_impl"); + desc.validate().unwrap(); + let shapes: Vec<_> = desc + .params + .iter() + .map(|p| (p.name.as_str(), p.elem, p.access, p.footprint, p.by_value)) + .collect(); + assert_eq!( + shapes, + vec![ + ("scale", TileElem::U16, TileAccess::In, 1, false), + ("half", TileElem::F16, TileAccess::In, 1, true), + ("out", TileElem::U16, TileAccess::InOut, 1, false), + ] + ); +} + +#[test] +fn mixed_footprints_are_rejected_at_the_differing_parameter() { + // The window needs 16 invocations of a 64-element tile, the scalar 64: + // one implementation cannot have both. + let func: ItemFn = parse_quote! { + pub fn window(acc: &mut [i32; 4], bias: &i32) { + let _ = (acc, bias); + } + }; + let err = expand_err(quote! { tile_shape = 64 }, func); + assert!( + err.contains("`acc` (footprint 4) and `bias` (footprint 1) differ"), + "{err}" + ); + // A by-value scalar is footprint 1 too, so it cannot sit beside a window. + let func: ItemFn = parse_quote! { + pub fn scale4(x: &mut [f32; 4], factor: f32) { + let _ = (x, factor); + } + }; + let err = expand_err(quote! { tile_shape = 128 }, func); + assert!( + err.contains("`x` (footprint 4) and `factor` (footprint 1) differ"), + "{err}" + ); +} + +#[test] +fn warp_sync_with_a_footprint_needs_whole_warps_of_footprints() { + let func: ItemFn = parse_quote! { + pub fn scale4(x: &mut [f32; 4]) { + let _ = x; + } + }; + // 64 is a multiple of 32, but a warp of 4-element footprints owns 128. + let err = expand_err(quote! { tile_shape = 64, sync = "warp" }, func.clone()); + assert!( + err.contains("footprint 4") && err.contains("multiple of 128") && err.contains("64"), + "{err}" + ); + expand(quote! { tile_shape = 128, sync = "warp" }, func.clone()).unwrap(); + // Without synchronization the footprint only has to divide the shape. + expand(quote! { tile_shape = 64 }, func).unwrap(); +} + +#[test] +fn primitive_module_paths_are_element_types() { + let func: ItemFn = parse_quote! { + pub fn add(a: core::primitive::f64, b: ::std::primitive::f64) -> f64 { a + b } + }; + let desc = embedded_desc( + &expand(quote! { tile_shape = 32 }, func).unwrap(), + "add_impl", + ); + assert!(desc.params.iter().all(|p| p.elem == TileElem::F64)); +} + +#[test] +fn the_out_parameter_avoids_a_user_parameter_of_the_same_name() { + let func: ItemFn = parse_quote! { + pub fn f(f_out: f32) -> f32 { f_out } + }; + let desc = embedded_desc(&expand(quote! { tile_shape = 32 }, func).unwrap(), "f_impl"); + assert_eq!(desc.params[1].name, "f_out_"); + desc.validate().unwrap(); +} + +#[test] +fn generics_self_and_async_are_rejected() { + let generic: ItemFn = parse_quote! { pub fn relu(x: T) -> T { x } }; + assert!(expand_err(quote! { tile_shape = 128 }, generic).contains("cannot be generic")); + + let lifetime: ItemFn = parse_quote! { pub fn relu<'a>(x: &'a f32) -> f32 { *x } }; + assert!(expand_err(quote! { tile_shape = 128 }, lifetime).contains("cannot be generic")); + + let method: ItemFn = parse_quote! { pub fn relu(self, x: f32) -> f32 { x } }; + assert!(expand_err(quote! { tile_shape = 128 }, method).contains("cannot take self")); + + let asynchronous: ItemFn = parse_quote! { pub async fn relu(x: f32) -> f32 { x } }; + assert!(expand_err(quote! { tile_shape = 128 }, asynchronous).contains("cannot be async")); +} + +#[test] +fn shape_is_required_positive_and_literal() { + let func: ItemFn = parse_quote! { pub fn relu(x: f32) -> f32 { x } }; + assert!(expand_err(quote! {}, func.clone()).contains("requires `tile_shape = N`")); + assert!(expand_err(quote! { tile_shape = 0 }, func.clone()).contains("positive integer")); + let err = syn::parse2::(quote! { tile_shape = N }) + .err() + .expect("a non-literal shape is a parse error") + .to_string(); + assert!(err.contains("integer literal"), "{err}"); + let err = syn::parse2::(quote! { tile_shape = 128, tile_shape = 64 }) + .err() + .expect("duplicate keys are rejected") + .to_string(); + assert!(err.contains("duplicate"), "{err}"); +} + +#[test] +fn unknown_and_malformed_arguments_are_rejected() { + let err = syn::parse2::(quote! { tile_shape = 128, foo = 1 }) + .err() + .expect("unknown keys are rejected") + .to_string(); + assert!( + err.contains("unknown #[tile_export] argument `foo`") + && err.contains("shape, name, symbol, sync, arch"), + "{err}" + ); + let err = syn::parse2::(quote! { tile_shape = 128, arch = "sm_120" }) + .err() + .expect("arch must be a list") + .to_string(); + assert!(err.contains("list of string literals"), "{err}"); + let err = syn::parse2::(quote! { tile_shape = 128, name = relu }) + .err() + .expect("name must be a string literal") + .to_string(); + assert!(err.contains("string literal"), "{err}"); + + let func: ItemFn = parse_quote! { pub fn relu(x: f32) -> f32 { x } }; + assert!( + expand_err(quote! { tile_shape = 128, sync = "cta" }, func.clone()) + .contains("must be \"none\" or \"warp\"") + ); + assert!( + expand_err(quote! { tile_shape = 128, symbol = "re-lu" }, func.clone()) + .contains("must be an identifier") + ); + assert!( + expand_err( + quote! { tile_shape = 128, name = "cuda_oxide_relu" }, + func.clone() + ) + .contains("reserved cuda-oxide prefix") + ); + assert!(expand_err(quote! { tile_shape = 128, arch = [""] }, func).contains("non-empty")); +} + +#[test] +fn unsupported_parameter_and_return_types_say_what_is_accepted() { + for func in [ + parse_quote! { pub fn bad(x: &[f32]) -> f32 { x[0] } }, + parse_quote! { pub fn bad(x: *mut f32) -> f32 { 0.0 } }, + parse_quote! { pub fn bad(x: bool) -> f32 { 0.0 } }, + parse_quote! { pub fn bad(x: usize) -> f32 { 0.0 } }, + parse_quote! { pub fn bad(x: &mut [f32]) -> f32 { 0.0 } }, + parse_quote! { pub fn bad(x: &[bool; 4]) -> f32 { 0.0 } }, + parse_quote! { pub fn bad(x: (f32, f32)) -> f32 { x.0 } }, + ] { + let err = expand_err(quote! { tile_shape = 128 }, func); + assert!( + err.contains( + "parameters must be `x: T`, `x: &T`, `x: &mut T`, `x: &[T; N]`, or \ + `x: &mut [T; N]`" + ), + "{err}" + ); + assert!( + err.contains("f16, f32, f64, i8, i16, i32, i64, u8, u16, u32, u64"), + "{err}" + ); + } + + let pattern: ItemFn = parse_quote! { pub fn bad((a, b): (f32, f32)) -> f32 { a } }; + assert!(expand_err(quote! { tile_shape = 128 }, pattern).contains("plain identifiers")); + + let const_len: ItemFn = parse_quote! { pub fn bad(x: &mut [f32; N]) {} }; + assert!(expand_err(quote! { tile_shape = 128 }, const_len).contains("integer literal length")); + + for func in [ + parse_quote! { pub fn bad(x: f32) -> &'static f32 { &0.0 } }, + parse_quote! { pub fn bad(x: f32) -> (f32, f32) { (x, x) } }, + parse_quote! { pub fn bad(x: f32) -> bool { x > 0.0 } }, + ] { + let err = expand_err(quote! { tile_shape = 128 }, func); + assert!(err.contains("must return a scalar"), "{err}"); + } +} + +#[test] +fn an_export_needs_an_output() { + let sink: ItemFn = parse_quote! { pub fn sink(x: f32, y: &f32) { let _ = (x, y); } }; + let err = expand_err(quote! { tile_shape = 128 }, sink); + assert!(err.contains("has no output"), "{err}"); + + // `()` is fine once something is written in place. + let in_place: ItemFn = parse_quote! { pub fn scale(x: &mut f32) -> () { *x *= 2.0; } }; + expand(quote! { tile_shape = 128 }, in_place).unwrap(); +} + +#[test] +fn warp_sync_needs_a_multiple_of_32() { + let func: ItemFn = parse_quote! { pub fn s(x: f32) -> f32 { x } }; + let err = expand_err(quote! { tile_shape = 100, sync = "warp" }, func.clone()); + assert!( + err.contains("multiple of 32") && err.contains("100"), + "{err}" + ); + expand(quote! { tile_shape = 96, sync = "warp" }, func).unwrap(); +} + +#[test] +fn reserved_function_names_are_rejected() { + let func: ItemFn = parse_quote! { pub fn cuda_oxide_relu(x: f32) -> f32 { x } }; + assert!(expand_err(quote! { tile_shape = 128 }, func).contains("reserved cuda-oxide")); +} diff --git a/cuda-oxide/crates/cuda-macros/src/tile_export.rs b/cuda-oxide/crates/cuda-macros/src/tile_export.rs new file mode 100644 index 0000000000..491e7d87b0 --- /dev/null +++ b/cuda-oxide/crates/cuda-macros/src/tile_export.rs @@ -0,0 +1,679 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +//! `#[tile_export]`: export a device function to cuTile through a tile +//! library. +//! +//! The attribute leaves the annotated function alone and adds two items next +//! to it: a `#[device] extern "C"` wrapper on the native SIMT ABI, and a +//! host-only `#[no_mangle]` metadata function whose body is the JSON +//! [`TileExportDesc`] of the export. The ABI rules live in `oxide-tile-export`; +//! this module maps Rust signatures onto them and emits the wrapper body. + +use crate::common::{internal_ident, reserved_name_error, track_codegen_environment}; +use oxide_tile_export::{ + CURRENT_VERSION, TileAccess, TileElem, TileExportDesc, TileExportError, TileParamDesc, + TileSync, is_identifier, +}; +use proc_macro::TokenStream; +use proc_macro2::{Span, TokenStream as TokenStream2}; +use quote::{ToTokens, quote}; +use reserved_oxide_symbols::{RESERVED_ROOT, tile_export_meta_symbol}; +use syn::{ + Expr, ExprArray, ExprLit, FnArg, Ident, ItemFn, Lit, LitInt, LitStr, Pat, ReturnType, + Signature, Token, Type, + parse::{Parse, ParseStream}, + parse_macro_input, +}; + +/// The Rust element types `#[tile_export]` accepts, as the diagnostics list +/// them. +const ELEMENT_TYPES: &str = "f16, f32, f64, i8, i16, i32, i64, u8, u16, u32, u64"; + +/// The attribute's parsed arguments. Every field is optional at parse time; +/// `expand_tile_export` reports the missing `tile_shape`. +#[derive(Default)] +pub(crate) struct TileExportArgs { + pub(crate) tile_shape: Option, + pub(crate) name: Option, + pub(crate) symbol: Option, + pub(crate) sync: Option, + pub(crate) arch: Option>, +} + +fn set_once(slot: &mut Option, key: &Ident, value: T) -> syn::Result<()> { + if slot.is_some() { + return Err(syn::Error::new( + key.span(), + format!("duplicate #[tile_export] argument `{key}`"), + )); + } + *slot = Some(value); + Ok(()) +} + +fn string_argument(key: &Ident, value: Expr) -> syn::Result { + match value { + Expr::Lit(ExprLit { + lit: Lit::Str(lit), .. + }) => Ok(lit), + other => Err(syn::Error::new_spanned( + other, + format!("#[tile_export] `{key}` takes a string literal such as `{key} = \"...\"`"), + )), + } +} + +impl Parse for TileExportArgs { + fn parse(input: ParseStream) -> syn::Result { + let mut args = Self::default(); + while !input.is_empty() { + let key: Ident = input.parse()?; + input.parse::()?; + match key.to_string().as_str() { + "tile_shape" => { + let value: Expr = input.parse()?; + let lit = match value { + Expr::Lit(ExprLit { + lit: Lit::Int(lit), .. + }) => lit, + other => { + return Err(syn::Error::new_spanned( + other, + "#[tile_export] `tile_shape` must be an integer literal such as \ + `tile_shape = 128`; a static tile library cannot ship a \ + parametric implementation, so a constant or expression is \ + not accepted", + )); + } + }; + set_once(&mut args.tile_shape, &key, lit)?; + } + "name" => { + let value = string_argument(&key, input.parse()?)?; + set_once(&mut args.name, &key, value)?; + } + "symbol" => { + let value = string_argument(&key, input.parse()?)?; + set_once(&mut args.symbol, &key, value)?; + } + "sync" => { + let value = string_argument(&key, input.parse()?)?; + set_once(&mut args.sync, &key, value)?; + } + "arch" => { + let array: ExprArray = input.parse().map_err(|err| { + syn::Error::new( + err.span(), + "#[tile_export] `arch` takes a list of string literals such as \ + `arch = [\"sm_100\", \"sm_120\"]`", + ) + })?; + let mut entries = Vec::with_capacity(array.elems.len()); + for elem in array.elems { + match elem { + Expr::Lit(ExprLit { + lit: Lit::Str(lit), .. + }) => entries.push(lit), + other => { + return Err(syn::Error::new_spanned( + other, + "#[tile_export] `arch` entries must be string literals \ + such as \"sm_120\"", + )); + } + } + } + set_once(&mut args.arch, &key, entries)?; + } + other => { + return Err(syn::Error::new( + key.span(), + format!( + "unknown #[tile_export] argument `{other}`; accepted arguments \ + are tile_shape, name, symbol, sync, arch" + ), + )); + } + } + if input.is_empty() { + break; + } + input.parse::()?; + } + Ok(args) + } +} + +pub(crate) fn tile_export_entry(attr: TokenStream, item: TokenStream) -> TokenStream { + track_codegen_environment(); + let args = parse_macro_input!(attr as TileExportArgs); + let input = parse_macro_input!(item as ItemFn); + match expand_tile_export(args, input) { + Ok(tokens) => tokens.into(), + Err(err) => err.to_compile_error().into(), + } +} + +/// How one Rust parameter travels across the native ABI. +enum ParamShape { + /// `x: T`: `in`, by value. + Scalar(TileElem), + /// `x: &T`: `in`, behind `*const T`. + Ref(TileElem), + /// `x: &[T; F]`: `in` with footprint `F`, behind `*const T`. + RefArray(TileElem, u32, LitInt), + /// `x: &mut T`: `inout`, behind `*mut T`. + RefMut(TileElem), + /// `x: &mut [T; F]`: `inout` with footprint `F`, behind `*mut T`. + RefMutArray(TileElem, u32, LitInt), +} + +impl ParamShape { + fn elem(&self) -> TileElem { + match self { + ParamShape::Scalar(elem) + | ParamShape::Ref(elem) + | ParamShape::RefArray(elem, _, _) + | ParamShape::RefMut(elem) + | ParamShape::RefMutArray(elem, _, _) => *elem, + } + } + + fn access(&self) -> TileAccess { + match self { + ParamShape::Scalar(_) | ParamShape::Ref(_) | ParamShape::RefArray(..) => TileAccess::In, + ParamShape::RefMut(_) | ParamShape::RefMutArray(..) => TileAccess::InOut, + } + } + + fn footprint(&self) -> u32 { + match self { + ParamShape::RefArray(_, footprint, _) | ParamShape::RefMutArray(_, footprint, _) => { + *footprint + } + _ => 1, + } + } + + fn by_value(&self) -> bool { + matches!(self, ParamShape::Scalar(_)) + } +} + +/// A type as the user would write it, for diagnostics: token printing puts +/// spaces around `&`, `;`, and `::` that no one types. +fn type_text(ty: &Type) -> String { + ty.to_token_stream() + .to_string() + .replace("& mut ", "&mut ") + .replace("& ", "&") + .replace(" ;", ";") + .replace(" ::", "::") + .replace(":: ", "::") + .replace(" <", "<") + .replace("< ", "<") + .replace(" >", ">") + .replace(" ,", ",") +} + +/// Peel `(T)` and macro-generated groups so a type written through another +/// macro classifies like one written by hand. +fn unwrap_type(mut ty: &Type) -> &Type { + loop { + match ty { + Type::Paren(paren) => ty = &paren.elem, + Type::Group(group) => ty = &group.elem, + _ => return ty, + } + } +} + +/// The element type a scalar type path names, if it is one of the eleven. +/// +/// Accepts the bare name (`f32`) and the primitive module paths +/// (`core::primitive::f32`, `::std::primitive::f32`). Anything with generic +/// arguments or any other path is not an element type. +fn scalar_elem(ty: &Type) -> Option { + let Type::Path(path) = unwrap_type(ty) else { + return None; + }; + if path.qself.is_some() { + return None; + } + let segments = &path.path.segments; + if segments.iter().any(|segment| !segment.arguments.is_none()) { + return None; + } + let last = segments.last()?; + match segments.len() { + 1 => {} + 3 => { + let crate_name = segments[0].ident.to_string(); + if !matches!(crate_name.as_str(), "core" | "std") || segments[1].ident != "primitive" { + return None; + } + } + _ => return None, + } + TileElem::from_rust_name(&last.ident.to_string()) +} + +fn classify_param_type(ty: &Type) -> syn::Result { + let unsupported = || { + syn::Error::new_spanned( + ty, + format!( + "#[tile_export] parameters must be `x: T`, `x: &T`, `x: &mut T`, \ + `x: &[T; N]`, or `x: &mut [T; N]` with T one of {ELEMENT_TYPES} and N an \ + integer literal; found `{}`. Slices, raw pointers, tuples, structs, \ + generics, and other element types are not accepted", + type_text(ty) + ), + ) + }; + if let Some(elem) = scalar_elem(ty) { + return Ok(ParamShape::Scalar(elem)); + } + let Type::Reference(reference) = unwrap_type(ty) else { + return Err(unsupported()); + }; + let mutable = reference.mutability.is_some(); + let pointee = unwrap_type(&reference.elem); + if let Some(elem) = scalar_elem(pointee) { + return Ok(if mutable { + ParamShape::RefMut(elem) + } else { + ParamShape::Ref(elem) + }); + } + let Type::Array(array) = pointee else { + return Err(unsupported()); + }; + let Some(elem) = scalar_elem(&array.elem) else { + return Err(unsupported()); + }; + let Expr::Lit(ExprLit { + lit: Lit::Int(len), .. + }) = &array.len + else { + return Err(syn::Error::new_spanned( + &array.len, + "#[tile_export] array parameters need an integer literal length such as \ + `&[f32; 4]` or `&mut [f32; 4]`; the footprint must be known to the macro, so \ + a constant or expression is not accepted", + )); + }; + let footprint: u32 = len.base10_parse()?; + if footprint == 0 { + return Err(syn::Error::new_spanned( + len, + "#[tile_export] array parameters need at least one element", + )); + } + Ok(if mutable { + ParamShape::RefMutArray(elem, footprint, len.clone()) + } else { + ParamShape::RefArray(elem, footprint, len.clone()) + }) +} + +fn classify_return_type(output: &ReturnType) -> syn::Result> { + let ty = match output { + ReturnType::Default => return Ok(None), + ReturnType::Type(_, ty) => ty, + }; + if let Type::Tuple(tuple) = unwrap_type(ty) + && tuple.elems.is_empty() + { + return Ok(None); + } + scalar_elem(ty).map(Some).ok_or_else(|| { + syn::Error::new_spanned( + ty, + format!( + "#[tile_export] functions must return a scalar (one of {ELEMENT_TYPES}) or \ + nothing; found `{}`. References, pointers, arrays, tuples, and other \ + element types are not accepted as return types", + type_text(ty) + ), + ) + }) +} + +/// Reject a declaration or symbol name that cannot be a Tile IR symbol or +/// that lands in the reserved namespace. +fn check_symbol_literal(lit: &LitStr, what: &str) -> syn::Result { + let value = lit.value(); + if !is_identifier(&value) { + return Err(syn::Error::new_spanned( + lit, + format!( + "#[tile_export] {what} `{value}` must be an identifier (ASCII letters, digits \ + and `_`, not starting with a digit)" + ), + )); + } + if value.starts_with(RESERVED_ROOT) { + return Err(syn::Error::new_spanned( + lit, + format!( + "#[tile_export] {what} `{value}` starts with the reserved cuda-oxide prefix \ + `{RESERVED_ROOT}`; choose another name" + ), + )); + } + Ok(value) +} + +/// A shared-rule violation as a diagnostic, pointed at the part of the +/// signature that breaks the rule: the parameter whose footprint differs, the +/// shape a warp export cannot split, or the function name for the rest. +fn validation_error( + err: TileExportError, + sig: &Signature, + shape_lit: &LitInt, + fn_ident: &Ident, +) -> syn::Error { + let message = format!("#[tile_export]: {err}"); + match &err { + TileExportError::MixedFootprints { other, .. } => { + let offending = sig.inputs.iter().find_map(|arg| match arg { + FnArg::Typed(pat_type) => match &*pat_type.pat { + Pat::Ident(pat_ident) if pat_ident.ident == other => Some(&pat_type.ty), + _ => None, + }, + FnArg::Receiver(_) => None, + }); + match offending { + Some(ty) => syn::Error::new_spanned(ty, message), + None => syn::Error::new(fn_ident.span(), message), + } + } + TileExportError::WarpFootprintShape { .. } | TileExportError::WarpShape { .. } => { + syn::Error::new_spanned(shape_lit, message) + } + _ => syn::Error::new(fn_ident.span(), message), + } +} + +/// Expand `#[tile_export(args)] fn ...` into the original function, the +/// `#[device] extern "C"` wrapper, and the metadata function. +pub(crate) fn expand_tile_export(args: TileExportArgs, input: ItemFn) -> syn::Result { + let sig = &input.sig; + let fn_ident = sig.ident.clone(); + if let Some(err) = reserved_name_error(&fn_ident) { + return Err(err); + } + if !sig.generics.params.is_empty() || sig.generics.where_clause.is_some() { + return Err(syn::Error::new_spanned( + &sig.generics, + "#[tile_export] functions cannot be generic: lifetime, type, and const \ + parameters are not accepted because a static tile library needs one concrete \ + symbol per export", + )); + } + if let Some(asyncness) = &sig.asyncness { + return Err(syn::Error::new_spanned( + asyncness, + "#[tile_export] functions cannot be async; only plain `fn` items run on the device", + )); + } + if let Some(variadic) = &sig.variadic { + return Err(syn::Error::new_spanned( + variadic, + "#[tile_export] functions cannot be variadic", + )); + } + + let Some(shape_lit) = args.tile_shape else { + return Err(syn::Error::new( + fn_ident.span(), + "#[tile_export] requires `tile_shape = N`, the 1-D tile extent; a static tile library \ + cannot ship a parametric implementation, so every export names one extent", + )); + }; + let shape: i64 = shape_lit.base10_parse()?; + if shape <= 0 { + return Err(syn::Error::new_spanned( + &shape_lit, + format!("#[tile_export] `tile_shape` must be a positive integer, found {shape}"), + )); + } + let sync = match &args.sync { + None => TileSync::None, + Some(lit) => match lit.value().as_str() { + "none" => TileSync::None, + "warp" => TileSync::Warp, + other => { + return Err(syn::Error::new_spanned( + lit, + format!( + "#[tile_export] `sync` must be \"none\" or \"warp\", found \"{other}\"" + ), + )); + } + }, + }; + // The footprint-1 form of the warp rule, reported before the parameters + // are read so the message points at the shape. The footprint-aware form + // comes from `validate` once the parameters are known. + if sync == TileSync::Warp && shape % 32 != 0 { + return Err(syn::Error::new_spanned( + &shape_lit, + format!( + "#[tile_export] sync = \"warp\" needs a tile_shape that is a multiple of 32 so \ + every invocation group fills whole warps, found {shape}" + ), + )); + } + let decl = match &args.name { + Some(lit) => check_symbol_literal(lit, "name")?, + None => fn_ident.to_string(), + }; + let symbol = match &args.symbol { + Some(lit) => check_symbol_literal(lit, "symbol")?, + None => format!("{decl}_impl"), + }; + let arch: Vec = args + .arch + .iter() + .flatten() + .map(|lit| { + let value = lit.value(); + if value.trim().is_empty() { + Err(syn::Error::new_spanned( + lit, + "#[tile_export] `arch` entries must be non-empty names such as \"sm_120\"", + )) + } else { + Ok(value) + } + }) + .collect::>()?; + + // Parameters: plain identifiers with one of the four accepted types. + let mut shapes = Vec::with_capacity(sig.inputs.len()); + let mut params = Vec::with_capacity(sig.inputs.len() + 1); + let mut types = Vec::with_capacity(sig.inputs.len()); + for arg in &sig.inputs { + let FnArg::Typed(pat_type) = arg else { + return Err(syn::Error::new_spanned( + arg, + "#[tile_export] functions cannot take self; export a free function", + )); + }; + if let Some(attr) = pat_type.attrs.first() { + return Err(syn::Error::new_spanned( + attr, + "#[tile_export] parameters cannot carry attributes", + )); + } + let Pat::Ident(pat_ident) = &*pat_type.pat else { + return Err(syn::Error::new_spanned( + &pat_type.pat, + "#[tile_export] parameters must be plain identifiers such as `x: f32`; \ + patterns are not accepted because each parameter names one Tile IR argument", + )); + }; + if pat_ident.subpat.is_some() || pat_ident.by_ref.is_some() { + return Err(syn::Error::new_spanned( + pat_ident, + "#[tile_export] parameters must be plain identifiers such as `x: f32`; \ + `ref` bindings and subpatterns are not accepted", + )); + } + let name = pat_ident.ident.to_string(); + if !is_identifier(&name) { + return Err(syn::Error::new_spanned( + &pat_ident.ident, + format!( + "#[tile_export] parameter `{name}` must be an ASCII identifier without \ + the `r#` prefix; it names a Tile IR argument" + ), + )); + } + let shape = classify_param_type(&pat_type.ty)?; + params.push(TileParamDesc { + name, + elem: shape.elem(), + access: shape.access(), + footprint: shape.footprint(), + by_value: shape.by_value(), + }); + types.push((*pat_type.ty).clone()); + shapes.push(shape); + } + + let return_elem = classify_return_type(&sig.output)?; + if return_elem.is_none() && !params.iter().any(|param| param.access.is_output()) { + return Err(syn::Error::new_spanned( + sig, + "#[tile_export] function has no output: return a scalar value or take at least \ + one `&mut T` or `&mut [T; N]` parameter, because a tile library declaration's \ + results are its `out` and `inout` arguments", + )); + } + if let Some(elem) = return_elem { + // The declaration argument that carries the return value. Keep the + // conventional `_out` unless a parameter already took it. + let mut out_name = format!("{fn_ident}_out"); + while params.iter().any(|param| param.name == out_name) { + out_name.push('_'); + } + params.push(TileParamDesc { + name: out_name, + elem, + access: TileAccess::Out, + footprint: 1, + by_value: false, + }); + } + + let desc = TileExportDesc { + version: CURRENT_VERSION, + decl, + symbol, + shape: vec![shape], + params, + sync, + arch, + }; + desc.validate() + .map_err(|err| validation_error(err, sig, &shape_lit, &fn_ident))?; + + // The wrapper: pointer parameters are turned back into the references + // the original function takes, the return value is stored through the + // trailing out pointer. + let mut abi_inputs = Vec::with_capacity(shapes.len() + 1); + let mut call_args = Vec::with_capacity(shapes.len()); + for (index, (shape, ty)) in shapes.iter().zip(&types).enumerate() { + let ident = internal_ident(&format!("__cuda_oxide_tile_arg_{index}")); + match shape { + ParamShape::Scalar(_) => { + abi_inputs.push(quote! { #ident: #ty }); + call_args.push(quote! { #ident }); + } + ParamShape::Ref(_) => { + let Type::Reference(reference) = unwrap_type(ty) else { + unreachable!("classified as a reference"); + }; + let pointee = &reference.elem; + abi_inputs.push(quote! { #ident: *const #pointee }); + call_args.push(quote! { unsafe { &*#ident } }); + } + ParamShape::RefMut(_) => { + let Type::Reference(reference) = unwrap_type(ty) else { + unreachable!("classified as a reference"); + }; + let pointee = &reference.elem; + abi_inputs.push(quote! { #ident: *mut #pointee }); + call_args.push(quote! { unsafe { &mut *#ident } }); + } + ParamShape::RefArray(_, _, len) => { + let Type::Reference(reference) = unwrap_type(ty) else { + unreachable!("classified as a reference"); + }; + let Type::Array(array) = unwrap_type(&reference.elem) else { + unreachable!("classified as an array reference"); + }; + let elem_ty = &array.elem; + abi_inputs.push(quote! { #ident: *const #elem_ty }); + call_args.push(quote! { unsafe { &*(#ident as *const [#elem_ty; #len]) } }); + } + ParamShape::RefMutArray(_, _, len) => { + let Type::Reference(reference) = unwrap_type(ty) else { + unreachable!("classified as a reference"); + }; + let Type::Array(array) = unwrap_type(&reference.elem) else { + unreachable!("classified as an array reference"); + }; + let elem_ty = &array.elem; + abi_inputs.push(quote! { #ident: *mut #elem_ty }); + call_args.push(quote! { unsafe { &mut *(#ident as *mut [#elem_ty; #len]) } }); + } + } + } + let call = quote! { #fn_ident(#(#call_args),*) }; + let body = match &sig.output { + ReturnType::Type(_, ret_ty) if return_elem.is_some() => { + let out_ident = internal_ident("__cuda_oxide_tile_out"); + let result_ident = internal_ident("__cuda_oxide_tile_result"); + abi_inputs.push(quote! { #out_ident: *mut #ret_ty }); + quote! { + let #result_ident: #ret_ty = #call; + unsafe { *#out_ident = #result_ident; } + } + } + _ => quote! { #call; }, + }; + + let wrapper_ident = Ident::new(&desc.symbol, fn_ident.span()); + let meta_ident = Ident::new(&tile_export_meta_symbol(&desc.symbol), fn_ident.span()); + let json = LitStr::new(&desc.to_json(), Span::call_site()); + let wrapper_doc = format!( + "Tile library implementation of `{}`, on the native SIMT ABI.", + desc.decl + ); + + Ok(quote! { + #input + + #[doc = #wrapper_doc] + #[doc(hidden)] + #[allow(non_snake_case, clippy::missing_safety_doc, improper_ctypes_definitions)] + #[::cuda_device::device] + pub unsafe extern "C" fn #wrapper_ident(#(#abi_inputs),*) { + #body + } + + #[doc(hidden)] + #[allow(non_snake_case)] + #[unsafe(no_mangle)] + pub fn #meta_ident() -> &'static str { + #json + } + }) +} diff --git a/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_generic.rs b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_generic.rs new file mode 100644 index 0000000000..aa9f403c35 --- /dev/null +++ b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_generic.rs @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +use cuda_macros::tile_export; + +#[tile_export(tile_shape = 128)] +pub fn relu(x: T) -> T { + x +} + +fn main() {} diff --git a/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_generic.stderr b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_generic.stderr new file mode 100644 index 0000000000..2b3433b290 --- /dev/null +++ b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_generic.stderr @@ -0,0 +1,5 @@ +error: #[tile_export] functions cannot be generic: lifetime, type, and const parameters are not accepted because a static tile library needs one concrete symbol per export + --> tests/compile_fail/tile_export_generic.rs:7:12 + | +7 | pub fn relu(x: T) -> T { + | ^^^^^^^^^ diff --git a/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_missing_shape.rs b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_missing_shape.rs new file mode 100644 index 0000000000..d92422c42a --- /dev/null +++ b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_missing_shape.rs @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +use cuda_macros::tile_export; + +#[tile_export] +pub fn relu(x: f32) -> f32 { + x +} + +fn main() {} diff --git a/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_missing_shape.stderr b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_missing_shape.stderr new file mode 100644 index 0000000000..c6bda38223 --- /dev/null +++ b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_missing_shape.stderr @@ -0,0 +1,5 @@ +error: #[tile_export] requires `tile_shape = N`, the 1-D tile extent; a static tile library cannot ship a parametric implementation, so every export names one extent + --> tests/compile_fail/tile_export_missing_shape.rs:7:8 + | +7 | pub fn relu(x: f32) -> f32 { + | ^^^^ diff --git a/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_mixed_footprints.rs b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_mixed_footprints.rs new file mode 100644 index 0000000000..9bb6edc906 --- /dev/null +++ b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_mixed_footprints.rs @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +use cuda_macros::tile_export; + +#[tile_export(tile_shape = 64)] +pub fn window(acc: &mut [i32; 4], bias: &i32) { + for value in acc.iter_mut() { + *value += *bias; + } +} + +fn main() {} diff --git a/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_mixed_footprints.stderr b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_mixed_footprints.stderr new file mode 100644 index 0000000000..323f78f903 --- /dev/null +++ b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_mixed_footprints.stderr @@ -0,0 +1,5 @@ +error: #[tile_export]: parameters `acc` (footprint 4) and `bias` (footprint 1) differ; every parameter of one export shares the invocation count, so all footprints must be equal + --> tests/compile_fail/tile_export_mixed_footprints.rs:7:41 + | +7 | pub fn window(acc: &mut [i32; 4], bias: &i32) { + | ^^^^ diff --git a/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_no_outputs.rs b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_no_outputs.rs new file mode 100644 index 0000000000..a654191668 --- /dev/null +++ b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_no_outputs.rs @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +use cuda_macros::tile_export; + +#[tile_export(tile_shape = 128)] +pub fn sink(x: f32, y: &f32) { + let _ = (x, y); +} + +fn main() {} diff --git a/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_no_outputs.stderr b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_no_outputs.stderr new file mode 100644 index 0000000000..c58c08c60d --- /dev/null +++ b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_no_outputs.stderr @@ -0,0 +1,5 @@ +error: #[tile_export] function has no output: return a scalar value or take at least one `&mut T` or `&mut [T; N]` parameter, because a tile library declaration's results are its `out` and `inout` arguments + --> tests/compile_fail/tile_export_no_outputs.rs:7:5 + | +7 | pub fn sink(x: f32, y: &f32) { + | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_outputs_split.rs b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_outputs_split.rs new file mode 100644 index 0000000000..e7220abc4b --- /dev/null +++ b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_outputs_split.rs @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +use cuda_macros::tile_export; + +// [inout, in, out]: the appended return slot is separated from `a` by `b`. +#[tile_export(tile_shape = 128)] +pub fn split(a: &mut f32, b: f32) -> f32 { + *a *= b; + *a +} + +fn main() {} diff --git a/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_outputs_split.stderr b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_outputs_split.stderr new file mode 100644 index 0000000000..a23ce382d6 --- /dev/null +++ b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_outputs_split.stderr @@ -0,0 +1,5 @@ +error: #[tile_export]: `out` and `inout` parameters must be one contiguous run, but `b` is `in` and sits between `a` and `split_out`; move `in` parameters before the `&mut` ones + --> tests/compile_fail/tile_export_outputs_split.rs:8:8 + | +8 | pub fn split(a: &mut f32, b: f32) -> f32 { + | ^^^^^ diff --git a/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_unknown_argument.rs b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_unknown_argument.rs new file mode 100644 index 0000000000..4db9fd79ef --- /dev/null +++ b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_unknown_argument.rs @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +use cuda_macros::tile_export; + +#[tile_export(tile_shape = 128, shap = 64)] +pub fn relu(x: f32) -> f32 { + x +} + +fn main() {} diff --git a/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_unknown_argument.stderr b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_unknown_argument.stderr new file mode 100644 index 0000000000..cac0df871b --- /dev/null +++ b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_unknown_argument.stderr @@ -0,0 +1,5 @@ +error: unknown #[tile_export] argument `shap`; accepted arguments are tile_shape, name, symbol, sync, arch + --> tests/compile_fail/tile_export_unknown_argument.rs:6:33 + | +6 | #[tile_export(tile_shape = 128, shap = 64)] + | ^^^^ diff --git a/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_unsupported_param.rs b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_unsupported_param.rs new file mode 100644 index 0000000000..9c7dd58627 --- /dev/null +++ b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_unsupported_param.rs @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +use cuda_macros::tile_export; + +#[tile_export(tile_shape = 128)] +pub fn first(x: &[f32]) -> f32 { + x[0] +} + +fn main() {} diff --git a/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_unsupported_param.stderr b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_unsupported_param.stderr new file mode 100644 index 0000000000..bd7f56cfa5 --- /dev/null +++ b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_unsupported_param.stderr @@ -0,0 +1,5 @@ +error: #[tile_export] parameters must be `x: T`, `x: &T`, `x: &mut T`, `x: &[T; N]`, or `x: &mut [T; N]` with T one of f16, f32, f64, i8, i16, i32, i64, u8, u16, u32, u64 and N an integer literal; found `&[f32]`. Slices, raw pointers, tuples, structs, generics, and other element types are not accepted + --> tests/compile_fail/tile_export_unsupported_param.rs:7:17 + | +7 | pub fn first(x: &[f32]) -> f32 { + | ^^^^^^ diff --git a/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_warp_footprint.rs b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_warp_footprint.rs new file mode 100644 index 0000000000..f52d1b2137 --- /dev/null +++ b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_warp_footprint.rs @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +use cuda_macros::tile_export; + +#[tile_export(tile_shape = 64, sync = "warp")] +pub fn scale4(x: &mut [f32; 4]) { + for value in x.iter_mut() { + *value *= 2.0; + } +} + +fn main() {} diff --git a/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_warp_footprint.stderr b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_warp_footprint.stderr new file mode 100644 index 0000000000..89fa47f5b3 --- /dev/null +++ b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_warp_footprint.stderr @@ -0,0 +1,5 @@ +error: #[tile_export]: sync = warp with footprint 4 needs a shape that is a multiple of 128 (32 lanes times the footprint), found 64 + --> tests/compile_fail/tile_export_warp_footprint.rs:6:28 + | +6 | #[tile_export(tile_shape = 64, sync = "warp")] + | ^^ diff --git a/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_warp_shape.rs b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_warp_shape.rs new file mode 100644 index 0000000000..cf98bcafec --- /dev/null +++ b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_warp_shape.rs @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +use cuda_macros::tile_export; + +#[tile_export(tile_shape = 100, sync = "warp")] +pub fn partial_warp(x: f32) -> f32 { + x +} + +fn main() {} diff --git a/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_warp_shape.stderr b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_warp_shape.stderr new file mode 100644 index 0000000000..0987548c1e --- /dev/null +++ b/cuda-oxide/crates/cuda-macros/tests/compile_fail/tile_export_warp_shape.stderr @@ -0,0 +1,5 @@ +error: #[tile_export] sync = "warp" needs a tile_shape that is a multiple of 32 so every invocation group fills whole warps, found 100 + --> tests/compile_fail/tile_export_warp_shape.rs:6:28 + | +6 | #[tile_export(tile_shape = 100, sync = "warp")] + | ^^^ diff --git a/cuda-oxide/crates/cuda-macros/tests/device-only/Cargo.lock b/cuda-oxide/crates/cuda-macros/tests/device-only/Cargo.lock index f7fdc1eff6..4a78f429b9 100644 --- a/cuda-oxide/crates/cuda-macros/tests/device-only/Cargo.lock +++ b/cuda-oxide/crates/cuda-macros/tests/device-only/Cargo.lock @@ -13,10 +13,11 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", - "syn", + "syn 2.0.119", ] [[package]] @@ -27,6 +28,27 @@ dependencies = [ "cuda-macros", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "proc-macro2" version = "1.0.107" @@ -49,6 +71,49 @@ dependencies = [ name = "reserved-oxide-symbols" version = "0.2.1" +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "syn" version = "2.0.119" @@ -60,8 +125,45 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "3.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "2.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + [[package]] name = "unicode-ident" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/cuda-macros/tests/pass/tile_export_forms.rs b/cuda-oxide/crates/cuda-macros/tests/pass/tile_export_forms.rs new file mode 100644 index 0000000000..38a53fc6db --- /dev/null +++ b/cuda-oxide/crates/cuda-macros/tests/pass/tile_export_forms.rs @@ -0,0 +1,70 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Every parameter and return form `#[tile_export]` accepts, expanded +//! against the real `cuda_device::device` so the generated wrapper +//! type-checks. + +#![allow(dead_code)] +#![feature(f16)] + +use cuda_device::tile_export; + +#[tile_export(tile_shape = 128)] +pub fn relu(x: f32) -> f32 { + if x > 0.0 { x } else { 0.0 } +} + +#[tile_export(tile_shape = 128, name = "scale_in_place", symbol = "scale_in_place_impl")] +pub fn scale(x: &mut f32, factor: f32) { + *x *= factor; +} + +#[tile_export(tile_shape = 256, sync = "warp", arch = ["sm_100", "sm_120"])] +pub fn warp_sum(x: f32) -> f32 { + x +} + +// Every parameter of one export shares its footprint, so the bias is a +// 4-element window too. +#[tile_export(tile_shape = 64)] +pub fn window(acc: &mut [i32; 4], bias: &[i32; 4]) { + for (value, bias) in acc.iter_mut().zip(bias) { + *value += *bias; + } +} + +// A warp of 4-element footprints owns 128 elements; 256 holds two. +#[tile_export(tile_shape = 256, sync = "warp")] +pub fn warp_scale4(x: &mut [f32; 4], factor: &[f32; 4]) { + for (value, factor) in x.iter_mut().zip(factor) { + *value *= *factor; + } +} + +#[tile_export(tile_shape = 32)] +pub fn half_add(a: f16, b: f16) -> f16 { + a + b +} + +#[tile_export(tile_shape = 32)] +pub fn widen(x: u8, y: i64) -> u64 { + (x as u64).wrapping_add(y as u64) +} + +mod nested { + use cuda_device::tile_export; + + #[tile_export(tile_shape = 128, name = "nested_negate")] + pub fn negate(x: &mut f64) { + *x = -*x; + } +} + +fn main() { + // The original functions stay ordinary Rust functions. + assert_eq!(relu(-1.0), 0.0); + let mut value = 2.0; + scale(&mut value, 3.0); + assert_eq!(value, 6.0); +} diff --git a/cuda-oxide/crates/cuda-macros/tests/tile_export_guard.rs b/cuda-oxide/crates/cuda-macros/tests/tile_export_guard.rs new file mode 100644 index 0000000000..c220ffd819 --- /dev/null +++ b/cuda-oxide/crates/cuda-macros/tests/tile_export_guard.rs @@ -0,0 +1,21 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! `#[tile_export]` signature and argument contracts: every accepted form +//! expands against the real `cuda_device::device`, and each rejected form +//! fails with a macro diagnostic that says what is accepted instead. + +#[test] +fn tile_export_contracts() { + let t = trybuild::TestCases::new(); + t.pass("tests/pass/tile_export_forms.rs"); + t.compile_fail("tests/compile_fail/tile_export_generic.rs"); + t.compile_fail("tests/compile_fail/tile_export_missing_shape.rs"); + t.compile_fail("tests/compile_fail/tile_export_unsupported_param.rs"); + t.compile_fail("tests/compile_fail/tile_export_no_outputs.rs"); + t.compile_fail("tests/compile_fail/tile_export_warp_shape.rs"); + t.compile_fail("tests/compile_fail/tile_export_warp_footprint.rs"); + t.compile_fail("tests/compile_fail/tile_export_mixed_footprints.rs"); + t.compile_fail("tests/compile_fail/tile_export_unknown_argument.rs"); + t.compile_fail("tests/compile_fail/tile_export_outputs_split.rs"); +} diff --git a/cuda-oxide/crates/oxide-tile-export/Cargo.toml b/cuda-oxide/crates/oxide-tile-export/Cargo.toml new file mode 100644 index 0000000000..35058dd5bd --- /dev/null +++ b/cuda-oxide/crates/oxide-tile-export/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "oxide-tile-export" +version = "0.2.1" +edition.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true +description = "Descriptions of Rust device functions exported to cuTile tile libraries" +readme = "README.md" + +[dependencies] +serde = { workspace = true } +serde_json = { workspace = true } +thiserror = { workspace = true } + +[lints.rust] +missing_docs = { level = "deny" } diff --git a/cuda-oxide/crates/oxide-tile-export/README.md b/cuda-oxide/crates/oxide-tile-export/README.md new file mode 100644 index 0000000000..b94760e86d --- /dev/null +++ b/cuda-oxide/crates/oxide-tile-export/README.md @@ -0,0 +1,21 @@ +# oxide-tile-export + +`oxide-tile-export` defines the description of a Rust device function that a +cuTile program calls through a tile library. + +Three parts of cuda-oxide exchange these descriptions: + +- `#[tile_export]` in `cuda-macros` builds one `TileExportDesc` per exported + function at macro-expansion time and embeds its JSON in a host-only + metadata function. +- The `rustc-codegen-cuda` backend reads the JSON back out of that + function's MIR, validates it, compiles the exported wrapper as a device + root, and writes every description of a crate to + `.tileexports.json` next to the device artifact. +- `cargo oxide` turns that file into the Tile IR interface and implementation + modules of a tile library. + +The crate owns the vocabulary (element types, access modes, synchronization +levels), the validation rules, and the mapping from a description to the +native SIMT ABI that the exported function must have. It performs no file IO +and knows nothing about rustc or MIR. diff --git a/cuda-oxide/crates/oxide-tile-export/src/lib.rs b/cuda-oxide/crates/oxide-tile-export/src/lib.rs new file mode 100644 index 0000000000..dea32f95c1 --- /dev/null +++ b/cuda-oxide/crates/oxide-tile-export/src/lib.rs @@ -0,0 +1,1068 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +//! Descriptions of Rust device functions exported to cuTile tile libraries. +//! +//! `#[tile_export]` (in `cuda-macros`) serializes one [`TileExportDesc`] per +//! exported function at macro-expansion time and embeds it as the body of a +//! host-only metadata function. The codegen backend reads that JSON back out +//! of MIR, validates it, and writes every description of a crate to +//! `.tileexports.json` next to the device artifact. `cargo oxide` +//! turns the file into the Tile IR interface and implementation modules a +//! tile library needs. All three sides share this crate so the vocabulary and +//! the rules are defined once. +//! +//! # The native SIMT ABI +//! +//! A tile library implementation is a plain `void` function. Each declaration +//! argument becomes one parameter, in order, and the result of an exported +//! Rust function becomes a trailing `out` parameter (destination-passing +//! style). The implementation symbol is what the Tile IR call resolves to, so +//! the Rust wrapper must have this signature and no other: +//! +//! | Rust parameter | access | footprint | ABI parameter | +//! |-----------------------|---------|-----------|--------------------------| +//! | `x: T` | `in` | 1 | `T` by value | +//! | `x: &T` | `in` | 1 | `*const T` | +//! | `x: &[T; F]` | `in` | F | `*const T` | +//! | `x: &mut T` | `inout` | 1 | `*mut T` | +//! | `x: &mut [T; F]` | `inout` | F | `*mut T` | +//! | `-> T` (return value) | `out` | 1 | `*mut T`, appended last | +//! +//! Only `x: T` travels by value; every other parameter is a pointer to the +//! invocation's elements, and the function returns nothing. +//! [`TileExportDesc::abi_params`] applies these rules and nothing else. +//! +//! Every parameter of one export has the same footprint: the fragmaps of one +//! implementation share their invocation count, so a 4-element window beside +//! a scalar would need 32 invocations for one argument and 128 for the other. +//! With `sync = warp` the shape must be a multiple of `32 * footprint`, so +//! every invocation group fills whole warps. +//! +//! Thread identity inside the function is the hardware `threadIdx.x`. The +//! callee may not allocate shared memory; version 1 of the description has no +//! scratch buffer. + +#![forbid(unsafe_code)] + +use serde::{Deserialize, Serialize}; + +/// The description format version this crate reads and writes. +/// +/// Version 1 describes one-dimensional tiles, by-value or pointer parameters +/// with a per-invocation footprint, and the `none` and `warp` synchronization +/// levels. [`TileExportDesc::validate`] rejects any other version. +pub const CURRENT_VERSION: u32 = 1; + +/// File suffix of the per-crate description file the backend writes next to +/// the device artifact: `.tileexports.json` holds a JSON array of +/// [`TileExportDesc`]. +pub const DESCRIPTIONS_SUFFIX: &str = "tileexports.json"; + +/// Element type of a tile, named by its Rust type. +/// +/// Tile IR has no unsigned integer types, so the unsigned variants map to the +/// signless `i`-types of the same width in [`TileElem::tile_ir_name`] and to +/// the same LLVM integer types in [`TileElem::llvm_name`]. The Rust name is +/// kept in the description so the wrapper signature and the host-side +/// element interpretation stay recoverable. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum TileElem { + /// IEEE half precision, Rust `f16`, LLVM `half`. + F16, + /// Brain floating point. `cuda-device` carries bf16 values as `u16` bit + /// patterns, so a by-value bf16 is LLVM `i16` in the native ABI (see + /// [`TileElem::llvm_name`]). `#[tile_export]` does not accept `bf16` as + /// an element type; the variant is part of the vocabulary for + /// descriptions written by other tools. + BF16, + /// Rust `f32`, LLVM `float`. + F32, + /// Rust `f64`, LLVM `double`. + F64, + /// Rust `i8`. + I8, + /// Rust `i16`. + I16, + /// Rust `i32`. + I32, + /// Rust `i64`. + I64, + /// Rust `u8`; signless `i8` in Tile IR and LLVM. + U8, + /// Rust `u16`; signless `i16` in Tile IR and LLVM. + U16, + /// Rust `u32`; signless `i32` in Tile IR and LLVM. + U32, + /// Rust `u64`; signless `i64` in Tile IR and LLVM. + U64, +} + +impl TileElem { + /// Every element type, in declaration order. + pub const ALL: [TileElem; 12] = [ + TileElem::F16, + TileElem::BF16, + TileElem::F32, + TileElem::F64, + TileElem::I8, + TileElem::I16, + TileElem::I32, + TileElem::I64, + TileElem::U8, + TileElem::U16, + TileElem::U32, + TileElem::U64, + ]; + + /// The element type whose Rust name is `name`, if any. + /// + /// ``` + /// use oxide_tile_export::TileElem; + /// assert_eq!(TileElem::from_rust_name("f32"), Some(TileElem::F32)); + /// assert_eq!(TileElem::from_rust_name("usize"), None); + /// ``` + pub fn from_rust_name(name: &str) -> Option { + Self::ALL.into_iter().find(|elem| elem.rust_name() == name) + } + + /// The Rust name of the element type (`"f16"`, `"u32"`, ...). + pub fn rust_name(self) -> &'static str { + match self { + TileElem::F16 => "f16", + TileElem::BF16 => "bf16", + TileElem::F32 => "f32", + TileElem::F64 => "f64", + TileElem::I8 => "i8", + TileElem::I16 => "i16", + TileElem::I32 => "i32", + TileElem::I64 => "i64", + TileElem::U8 => "u8", + TileElem::U16 => "u16", + TileElem::U32 => "u32", + TileElem::U64 => "u64", + } + } + + /// The Tile IR name: floats keep their name, integers are signless. + pub fn tile_ir_name(self) -> &'static str { + match self { + TileElem::F16 => "f16", + TileElem::BF16 => "bf16", + TileElem::F32 => "f32", + TileElem::F64 => "f64", + TileElem::I8 | TileElem::U8 => "i8", + TileElem::I16 | TileElem::U16 => "i16", + TileElem::I32 | TileElem::U32 => "i32", + TileElem::I64 | TileElem::U64 => "i64", + } + } + + /// The LLVM IR type the element has in the native ABI. + /// + /// `bf16` is `i16`, not `bfloat`: `cuda-device` has no bf16 scalar type + /// and carries bf16 values as `u16` bit patterns, so that is what the + /// wrapper's parameter lowers to. The Tile IR element stays `bf16`, and + /// `cargo oxide tilelib` records the difference as the implementation's + /// `frontendABI` entry `{bf16 = i16}`. + pub fn llvm_name(self) -> &'static str { + match self { + TileElem::F16 => "half", + TileElem::BF16 => "i16", + TileElem::F32 => "float", + TileElem::F64 => "double", + TileElem::I8 | TileElem::U8 => "i8", + TileElem::I16 | TileElem::U16 => "i16", + TileElem::I32 | TileElem::U32 => "i32", + TileElem::I64 | TileElem::U64 => "i64", + } + } + + /// Width of one element in bits. + pub fn bit_width(self) -> u32 { + match self { + TileElem::I8 | TileElem::U8 => 8, + TileElem::F16 | TileElem::BF16 | TileElem::I16 | TileElem::U16 => 16, + TileElem::F32 | TileElem::I32 | TileElem::U32 => 32, + TileElem::F64 | TileElem::I64 | TileElem::U64 => 64, + } + } + + /// True for the floating-point element types. + pub fn is_float(self) -> bool { + matches!( + self, + TileElem::F16 | TileElem::BF16 | TileElem::F32 | TileElem::F64 + ) + } +} + +/// How the implementation touches one declaration argument. +/// +/// The declaration's results are the tile types of its `out` and `inout` +/// arguments, in order, so every export needs at least one of those. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum TileAccess { + /// Read only. + In, + /// Written, never read; the return value of a Rust function. + Out, + /// Read and written in place. + InOut, +} + +impl TileAccess { + /// The Tile IR name of the access mode (`in`, `out`, `inout`). + pub fn tile_ir_name(self) -> &'static str { + match self { + TileAccess::In => "in", + TileAccess::Out => "out", + TileAccess::InOut => "inout", + } + } + + /// True when the parameter is a result of the declaration. + pub fn is_output(self) -> bool { + matches!(self, TileAccess::Out | TileAccess::InOut) + } +} + +/// How many threads must call the implementation together. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum TileSync { + /// Every invocation is independent. + #[default] + None, + /// Whole warps participate; the shape must be a multiple of 32 times the + /// footprint. + Warp, +} + +impl TileSync { + /// The Tile IR name of the synchronization level. + pub fn tile_ir_name(self) -> &'static str { + match self { + TileSync::None => "none", + TileSync::Warp => "warp", + } + } +} + +/// One parameter of an exported function. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct TileParamDesc { + /// Parameter name; the Rust parameter name, or `_out` for the return + /// value. + pub name: String, + /// Element type of the tile this parameter is a fragment of. + pub elem: TileElem, + /// Read, write, or both. + pub access: TileAccess, + /// Number of contiguous elements one invocation owns; at least 1, and the + /// same for every parameter of the export. + pub footprint: u32, + /// True when the element travels by value instead of behind a pointer. + /// Only legal for `in` parameters with footprint 1. + pub by_value: bool, +} + +/// A `#[tile_export]` function as the tile library sees it. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct TileExportDesc { + /// Format version; see [`CURRENT_VERSION`]. + pub version: u32, + /// Declaration name: what the cuTile caller names in `foreign_call`. + pub decl: String, + /// Implementation symbol: the `extern "C"` device function the call + /// resolves to. + pub symbol: String, + /// Static tile extents; one positive entry in version 1. + pub shape: Vec, + /// Declaration arguments, in ABI order. + pub params: Vec, + /// Synchronization the implementation requires. + #[serde(default)] + pub sync: TileSync, + /// Compute capabilities the implementation supports (`sm_120`, ...). + /// Empty means every architecture. + #[serde(default)] + pub arch: Vec, +} + +/// What a description can get wrong. +#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)] +pub enum TileExportError { + /// The description was written by a newer or older format. + #[error( + "tile export description version {found} is not supported; this build reads version {CURRENT_VERSION}" + )] + UnsupportedVersion { + /// The version found in the description. + found: u32, + }, + /// A name that must be an identifier is not one. + #[error( + "{field} `{value}` is not a valid identifier (ASCII letters, digits and `_`, not starting with a digit)" + )] + InvalidIdentifier { + /// Which name: `decl`, `symbol`, or `parameter name`. + field: &'static str, + /// The offending text. + value: String, + }, + /// The shape has the wrong number of dimensions. + #[error("shape must have one dimension in version {CURRENT_VERSION}, found {0}")] + ShapeRank(usize), + /// A shape extent is zero or negative. + #[error("shape extents must be positive, found {0}")] + ShapeNotPositive(i64), + /// The export has no parameters at all. + #[error("a tile export needs at least one parameter")] + NoParams, + /// Nothing is written: no `out` and no `inout` parameter. + #[error("a tile export needs at least one output: return a value or take an `inout` parameter")] + NoOutputs, + /// An `in` parameter sits between two written parameters. The Tile + /// compiler requires the `out` and `inout` arguments of a declaration to + /// be one contiguous run (PreviewOps.cpp, "out/inout fragment args must + /// form a single ..."). + #[error( + "`out` and `inout` parameters must be one contiguous run, but `{between}` is `in` and sits between `{first}` and `{last}`; move `in` parameters before the `&mut` ones" + )] + OutputsNotContiguous { + /// The first written parameter. + first: String, + /// The `in` parameter inside the run. + between: String, + /// The last written parameter (the appended return slot, when present). + last: String, + }, + /// Two parameters share a name. + #[error("parameter `{name}` is declared twice")] + DuplicateParam { + /// The repeated name. + name: String, + }, + /// A footprint of zero elements. + #[error( + "parameter `{name}` has footprint 0; a footprint counts elements and must be at least 1" + )] + ZeroFootprint { + /// The parameter. + name: String, + }, + /// By-value passing on something that is written. + #[error( + "parameter `{name}` is `{access}` and cannot travel by value; only `in` parameters are passed by value" + )] + ByValueNotIn { + /// The parameter. + name: String, + /// Its access mode. + access: &'static str, + }, + /// By-value passing of more than one element. + #[error( + "parameter `{name}` has footprint {footprint} and cannot travel by value; a footprint above 1 needs pointer passing" + )] + ByValueFootprint { + /// The parameter. + name: String, + /// Its footprint. + footprint: u32, + }, + /// Two parameters own a different number of elements per invocation. The + /// fragmaps of one implementation share their invocation count, so this + /// has no Tile IR form. + #[error( + "parameters `{first}` (footprint {first_footprint}) and `{other}` (footprint {other_footprint}) differ; every parameter of one export shares the invocation count, so all footprints must be equal" + )] + MixedFootprints { + /// The first parameter, whose footprint the others were compared to. + first: String, + /// Its footprint. + first_footprint: u32, + /// The first parameter with another footprint. + other: String, + /// That footprint. + other_footprint: u32, + }, + /// Warp synchronization over a shape that does not fill whole warps; the + /// footprint-1 case of [`TileExportError::WarpFootprintShape`]. + #[error("sync = warp needs a shape that is a multiple of 32, found {shape}")] + WarpShape { + /// The offending extent. + shape: i64, + }, + /// Warp synchronization over a shape that does not fill whole warps of + /// footprints: each lane owns `footprint` elements, so a warp owns + /// `32 * footprint` of them. + #[error( + "sync = warp with footprint {footprint} needs a shape that is a multiple of {} (32 lanes times the footprint), found {shape}", + 32 * i64::from(*.footprint) + )] + WarpFootprintShape { + /// The shared footprint. + footprint: u32, + /// The offending extent. + shape: i64, + }, + /// An empty architecture string. + #[error("arch entries must be non-empty names such as `sm_120`")] + EmptyArch, +} + +/// How one ABI parameter is passed. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum AbiParamKind { + /// The element itself, by value. + Scalar(TileElem), + /// A pointer to the invocation's buffer of this element type. + Pointer(TileElem), +} + +impl AbiParamKind { + /// The LLVM IR type of the parameter: the element type, or `ptr`. + pub fn llvm_type(self) -> &'static str { + match self { + AbiParamKind::Scalar(elem) => elem.llvm_name(), + AbiParamKind::Pointer(_) => "ptr", + } + } + + /// The element type behind the parameter. + pub fn elem(self) -> TileElem { + match self { + AbiParamKind::Scalar(elem) | AbiParamKind::Pointer(elem) => elem, + } + } +} + +/// One parameter of the implementation symbol. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct AbiParam { + /// The description parameter this ABI parameter carries. + pub name: String, + /// By value or by pointer. + pub kind: AbiParamKind, +} + +/// True for an ASCII identifier: `[A-Za-z_][A-Za-z0-9_]*`. +/// +/// Both Tile IR symbol names and the LLVM symbols the wrapper gets have this +/// form; a Rust raw identifier or a non-ASCII name would not survive the +/// trip. +pub fn is_identifier(text: &str) -> bool { + let mut chars = text.chars(); + match chars.next() { + Some(first) if first.is_ascii_alphabetic() || first == '_' => {} + _ => return false, + } + chars.all(|c| c.is_ascii_alphanumeric() || c == '_') +} + +impl TileExportDesc { + /// Check every rule of version 1. + /// + /// The rules, in the order they are checked: + /// + /// - `version` is [`CURRENT_VERSION`]; + /// - `decl`, `symbol`, and every parameter name are identifiers, and no + /// parameter name repeats; + /// - `shape` has one positive extent; + /// - there is at least one parameter and at least one `out` or `inout` + /// parameter, and the `out`/`inout` parameters are one contiguous run; + /// - every footprint is at least 1, and every parameter has the same + /// footprint; + /// - `by_value` appears only on `in` parameters with footprint 1; + /// - `sync = warp` needs a shape that is a multiple of `32 * footprint`; + /// - every `arch` entry is non-empty. + pub fn validate(&self) -> Result<(), TileExportError> { + if self.version != CURRENT_VERSION { + return Err(TileExportError::UnsupportedVersion { + found: self.version, + }); + } + for (field, value) in [("decl", &self.decl), ("symbol", &self.symbol)] { + if !is_identifier(value) { + return Err(TileExportError::InvalidIdentifier { + field, + value: value.clone(), + }); + } + } + if self.shape.len() != 1 { + return Err(TileExportError::ShapeRank(self.shape.len())); + } + let extent = self.shape[0]; + if extent <= 0 { + return Err(TileExportError::ShapeNotPositive(extent)); + } + if self.params.is_empty() { + return Err(TileExportError::NoParams); + } + let mut seen = std::collections::HashSet::new(); + for param in &self.params { + if !is_identifier(¶m.name) { + return Err(TileExportError::InvalidIdentifier { + field: "parameter name", + value: param.name.clone(), + }); + } + if !seen.insert(param.name.as_str()) { + return Err(TileExportError::DuplicateParam { + name: param.name.clone(), + }); + } + if param.footprint == 0 { + return Err(TileExportError::ZeroFootprint { + name: param.name.clone(), + }); + } + if param.by_value { + if param.access != TileAccess::In { + return Err(TileExportError::ByValueNotIn { + name: param.name.clone(), + access: param.access.tile_ir_name(), + }); + } + if param.footprint != 1 { + return Err(TileExportError::ByValueFootprint { + name: param.name.clone(), + footprint: param.footprint, + }); + } + } + } + // One invocation count per implementation: every fragmap of it maps + // `shape / footprint` invocations, so the footprints cannot differ. + let first = &self.params[0]; + if let Some(other) = self + .params + .iter() + .find(|param| param.footprint != first.footprint) + { + return Err(TileExportError::MixedFootprints { + first: first.name.clone(), + first_footprint: first.footprint, + other: other.name.clone(), + other_footprint: other.footprint, + }); + } + let footprint = first.footprint; + if !self.params.iter().any(|param| param.access.is_output()) { + return Err(TileExportError::NoOutputs); + } + // The written arguments must be adjacent: the Tile compiler ties a + // declaration's results to one contiguous run of out/inout arguments. + let written: Vec = self + .params + .iter() + .enumerate() + .filter(|(_, param)| param.access.is_output()) + .map(|(index, _)| index) + .collect(); + if let (Some(&first), Some(&last)) = (written.first(), written.last()) + && last - first + 1 != written.len() + { + let between = self.params[first + 1..last] + .iter() + .find(|param| !param.access.is_output()) + .expect("a gap in the written run holds an `in` parameter"); + return Err(TileExportError::OutputsNotContiguous { + first: self.params[first].name.clone(), + between: between.name.clone(), + last: self.params[last].name.clone(), + }); + } + // A warp is one invocation of 32 lanes, each owning `footprint` + // elements, so the tile must split into whole `32 * footprint` runs. + if self.sync == TileSync::Warp && extent % (32 * i64::from(footprint)) != 0 { + return Err(if footprint == 1 { + TileExportError::WarpShape { shape: extent } + } else { + TileExportError::WarpFootprintShape { + footprint, + shape: extent, + } + }); + } + if self.arch.iter().any(|arch| arch.trim().is_empty()) { + return Err(TileExportError::EmptyArch); + } + Ok(()) + } + + /// The implementation symbol's parameters, in order. + /// + /// Follows the ABI table in the crate documentation: an `in` parameter + /// marked `by_value` is passed as its element type, and everything else + /// (pointer inputs, `inout` buffers, and the trailing `out` result) is a + /// pointer to the element type. The description is assumed to have passed + /// [`TileExportDesc::validate`]. + pub fn abi_params(&self) -> Vec { + self.params + .iter() + .map(|param| { + let kind = if param.access == TileAccess::In && param.by_value { + AbiParamKind::Scalar(param.elem) + } else { + AbiParamKind::Pointer(param.elem) + }; + AbiParam { + name: param.name.clone(), + kind, + } + }) + .collect() + } + + /// The description as compact JSON, the form the macro embeds. + pub fn to_json(&self) -> String { + serde_json::to_string(self).expect("a tile export description always serializes") + } + + /// The description as indented JSON. + pub fn to_json_pretty(&self) -> String { + serde_json::to_string_pretty(self).expect("a tile export description always serializes") + } + + /// Parse one description. Syntax only; call [`TileExportDesc::validate`] + /// for the semantic rules. + pub fn from_json(text: &str) -> Result { + serde_json::from_str(text) + } +} + +/// Serialize a crate's descriptions as the indented JSON array the +/// description file holds. +pub fn descriptions_to_json_pretty(descs: &[TileExportDesc]) -> String { + serde_json::to_string_pretty(descs).expect("tile export descriptions always serialize") +} + +/// Parse a description file's JSON array. +pub fn descriptions_from_json(text: &str) -> Result, serde_json::Error> { + serde_json::from_str(text) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn param(name: &str, access: TileAccess, footprint: u32, by_value: bool) -> TileParamDesc { + TileParamDesc { + name: name.to_string(), + elem: TileElem::F32, + access, + footprint, + by_value, + } + } + + /// `fn relu(x: f32) -> f32` with `shape = 128`. + fn relu() -> TileExportDesc { + TileExportDesc { + version: CURRENT_VERSION, + decl: "relu".into(), + symbol: "relu_impl".into(), + shape: vec![128], + params: vec![ + param("x", TileAccess::In, 1, true), + param("relu_out", TileAccess::Out, 1, false), + ], + sync: TileSync::None, + arch: Vec::new(), + } + } + + /// `fn scale(x: &mut f32, factor: f32)` exported as `scale_in_place`. + fn scale_in_place() -> TileExportDesc { + TileExportDesc { + version: CURRENT_VERSION, + decl: "scale_in_place".into(), + symbol: "scale_in_place_impl".into(), + shape: vec![128], + params: vec![ + param("x", TileAccess::InOut, 1, false), + param("factor", TileAccess::In, 1, true), + ], + sync: TileSync::None, + arch: vec!["sm_120".into()], + } + } + + #[test] + fn the_examples_validate() { + relu().validate().unwrap(); + scale_in_place().validate().unwrap(); + let mut warp = relu(); + warp.sync = TileSync::Warp; + warp.validate().unwrap(); + } + + #[test] + fn version_is_pinned() { + assert_eq!(CURRENT_VERSION, 1); + let mut desc = relu(); + desc.version = 2; + assert_eq!( + desc.validate(), + Err(TileExportError::UnsupportedVersion { found: 2 }) + ); + } + + #[test] + fn names_must_be_identifiers() { + for (field, mutate) in [ + ( + "decl", + (|d: &mut TileExportDesc| d.decl = "re-lu".into()) as fn(&mut TileExportDesc), + ), + ("symbol", |d: &mut TileExportDesc| d.symbol = "1impl".into()), + ("parameter name", |d: &mut TileExportDesc| { + d.params[0].name = "x y".into() + }), + ] { + let mut desc = relu(); + mutate(&mut desc); + match desc.validate() { + Err(TileExportError::InvalidIdentifier { field: found, .. }) => { + assert_eq!(found, field) + } + other => panic!("{field}: expected an identifier error, got {other:?}"), + } + } + assert!(is_identifier("_x1")); + assert!(!is_identifier("")); + assert!(!is_identifier("9x")); + assert!(!is_identifier("r#type")); + } + + #[test] + fn duplicate_parameter_names_are_rejected() { + let mut desc = relu(); + desc.params[1].name = "x".into(); + assert_eq!( + desc.validate(), + Err(TileExportError::DuplicateParam { name: "x".into() }) + ); + } + + #[test] + fn shape_is_one_positive_extent() { + let mut desc = relu(); + desc.shape = vec![128, 1]; + assert_eq!(desc.validate(), Err(TileExportError::ShapeRank(2))); + desc.shape = Vec::new(); + assert_eq!(desc.validate(), Err(TileExportError::ShapeRank(0))); + desc.shape = vec![0]; + assert_eq!(desc.validate(), Err(TileExportError::ShapeNotPositive(0))); + desc.shape = vec![-4]; + assert_eq!(desc.validate(), Err(TileExportError::ShapeNotPositive(-4))); + } + + #[test] + fn every_export_has_a_parameter_and_an_output() { + let mut desc = relu(); + desc.params.clear(); + assert_eq!(desc.validate(), Err(TileExportError::NoParams)); + let mut desc = relu(); + desc.params.pop(); + assert_eq!(desc.validate(), Err(TileExportError::NoOutputs)); + } + + #[test] + fn written_parameters_form_one_contiguous_run() { + // `fn f(a: &mut f32, b: f32) -> f32` is [inout, in, out]: the Tile + // compiler ties results to one adjacent run of written arguments. + let mut desc = relu(); + desc.params = vec![ + param("a", TileAccess::InOut, 1, false), + param("b", TileAccess::In, 1, true), + param("f_out", TileAccess::Out, 1, false), + ]; + assert_eq!( + desc.validate(), + Err(TileExportError::OutputsNotContiguous { + first: "a".into(), + between: "b".into(), + last: "f_out".into(), + }) + ); + // Grouping the written parameters last is accepted. + desc.params = vec![ + param("b", TileAccess::In, 1, true), + param("a", TileAccess::InOut, 1, false), + param("f_out", TileAccess::Out, 1, false), + ]; + assert_eq!(desc.validate(), Ok(())); + // Written parameters first and `in` parameters after them are also + // one run. + desc.params = vec![ + param("a", TileAccess::InOut, 1, false), + param("c", TileAccess::InOut, 1, false), + param("b", TileAccess::In, 1, true), + ]; + assert_eq!(desc.validate(), Ok(())); + } + + #[test] + fn footprints_start_at_one() { + let mut desc = scale_in_place(); + desc.params[0].footprint = 0; + assert_eq!( + desc.validate(), + Err(TileExportError::ZeroFootprint { name: "x".into() }) + ); + // `fn scale4(x: &mut [f32; 4], factor: &[f32; 4])`. + for param in &mut desc.params { + param.footprint = 4; + param.by_value = false; + } + desc.validate().unwrap(); + } + + #[test] + fn footprints_are_the_same_for_every_parameter() { + // `fn window(acc: &mut [i32; 4], bias: &i32)`: the window needs 16 + // invocations of a 64-element tile, the scalar 64. + let mut desc = scale_in_place(); + desc.params[0].footprint = 4; + assert_eq!( + desc.validate(), + Err(TileExportError::MixedFootprints { + first: "x".into(), + first_footprint: 4, + other: "factor".into(), + other_footprint: 1, + }) + ); + let message = desc.validate().unwrap_err().to_string(); + assert!( + message.contains("`x` (footprint 4) and `factor` (footprint 1) differ"), + "{message}" + ); + // The comparison is against the first parameter, whichever it is. + desc.params[0].footprint = 1; + desc.params[1].footprint = 2; + desc.params[1].by_value = false; + assert_eq!( + desc.validate(), + Err(TileExportError::MixedFootprints { + first: "x".into(), + first_footprint: 1, + other: "factor".into(), + other_footprint: 2, + }) + ); + } + + #[test] + fn by_value_needs_in_and_footprint_one() { + let mut desc = scale_in_place(); + desc.params[0].by_value = true; + assert_eq!( + desc.validate(), + Err(TileExportError::ByValueNotIn { + name: "x".into(), + access: "inout", + }) + ); + let mut desc = relu(); + desc.params[1].by_value = true; + assert_eq!( + desc.validate(), + Err(TileExportError::ByValueNotIn { + name: "relu_out".into(), + access: "out", + }) + ); + let mut desc = relu(); + desc.params[0].footprint = 2; + assert_eq!( + desc.validate(), + Err(TileExportError::ByValueFootprint { + name: "x".into(), + footprint: 2, + }) + ); + } + + #[test] + fn warp_sync_needs_whole_warps() { + let mut desc = relu(); + desc.sync = TileSync::Warp; + desc.shape = vec![100]; + assert_eq!( + desc.validate(), + Err(TileExportError::WarpShape { shape: 100 }) + ); + desc.shape = vec![32]; + desc.validate().unwrap(); + // `none` has no shape rule. + desc.sync = TileSync::None; + desc.shape = vec![100]; + desc.validate().unwrap(); + } + + #[test] + fn warp_sync_with_a_footprint_needs_whole_warps_of_footprints() { + // `fn scale4(x: &mut [f32; 4], factor: &[f32; 4])` with `sync = + // warp`: a warp owns 128 elements, so a 64-element tile holds half + // a warp even though 64 is a multiple of 32. + let mut desc = scale_in_place(); + desc.sync = TileSync::Warp; + for param in &mut desc.params { + param.footprint = 4; + param.by_value = false; + } + desc.shape = vec![64]; + assert_eq!( + desc.validate(), + Err(TileExportError::WarpFootprintShape { + footprint: 4, + shape: 64, + }) + ); + let message = desc.validate().unwrap_err().to_string(); + assert!(message.contains("multiple of 128"), "{message}"); + desc.shape = vec![256]; + desc.validate().unwrap(); + // Footprint 1 keeps the plain multiple-of-32 rule and its message. + for param in &mut desc.params { + param.footprint = 1; + } + desc.shape = vec![100]; + assert_eq!( + desc.validate(), + Err(TileExportError::WarpShape { shape: 100 }) + ); + // Without synchronization only the footprint rules apply. + desc.sync = TileSync::None; + for param in &mut desc.params { + param.footprint = 4; + } + desc.shape = vec![64]; + desc.validate().unwrap(); + } + + #[test] + fn arch_entries_are_non_empty() { + let mut desc = relu(); + desc.arch = vec!["sm_120".into(), " ".into()]; + assert_eq!(desc.validate(), Err(TileExportError::EmptyArch)); + } + + #[test] + fn abi_params_follow_the_table() { + let abi = relu().abi_params(); + assert_eq!( + abi, + vec![ + AbiParam { + name: "x".into(), + kind: AbiParamKind::Scalar(TileElem::F32), + }, + AbiParam { + name: "relu_out".into(), + kind: AbiParamKind::Pointer(TileElem::F32), + }, + ] + ); + assert_eq!(abi[0].kind.llvm_type(), "float"); + assert_eq!(abi[1].kind.llvm_type(), "ptr"); + + let abi = scale_in_place().abi_params(); + assert_eq!(abi[0].kind, AbiParamKind::Pointer(TileElem::F32)); + assert_eq!(abi[1].kind, AbiParamKind::Scalar(TileElem::F32)); + + // `x: &[T; F]` is `in` behind a pointer, `x: &mut [T; F]` is `inout` + // behind a pointer; neither is by value. + let mut desc = relu(); + desc.params[0].by_value = false; + desc.params[0].footprint = 8; + desc.params[1].footprint = 8; + desc.params + .insert(1, param("window", TileAccess::InOut, 8, false)); + desc.validate().unwrap(); + let abi = desc.abi_params(); + assert_eq!(abi[0].kind, AbiParamKind::Pointer(TileElem::F32)); + assert_eq!(abi[1].kind, AbiParamKind::Pointer(TileElem::F32)); + assert_eq!(abi[1].name, "window"); + assert_eq!(abi[2].kind, AbiParamKind::Pointer(TileElem::F32)); + + // A by-value bf16 is the `u16` bit pattern cuda-device carries, so + // the ABI parameter is `i16`; the Tile IR element stays `bf16`. + let mut desc = relu(); + desc.params[0].elem = TileElem::BF16; + assert_eq!(desc.abi_params()[0].kind.llvm_type(), "i16"); + assert_eq!(TileElem::BF16.tile_ir_name(), "bf16"); + } + + #[test] + fn element_names_agree_across_rust_tile_ir_and_llvm() { + let expected = [ + (TileElem::F16, "f16", "f16", "half", 16), + (TileElem::BF16, "bf16", "bf16", "i16", 16), + (TileElem::F32, "f32", "f32", "float", 32), + (TileElem::F64, "f64", "f64", "double", 64), + (TileElem::I8, "i8", "i8", "i8", 8), + (TileElem::I16, "i16", "i16", "i16", 16), + (TileElem::I32, "i32", "i32", "i32", 32), + (TileElem::I64, "i64", "i64", "i64", 64), + (TileElem::U8, "u8", "i8", "i8", 8), + (TileElem::U16, "u16", "i16", "i16", 16), + (TileElem::U32, "u32", "i32", "i32", 32), + (TileElem::U64, "u64", "i64", "i64", 64), + ]; + assert_eq!(expected.len(), TileElem::ALL.len()); + for (elem, rust, tile_ir, llvm, bits) in expected { + assert_eq!(elem.rust_name(), rust); + assert_eq!(elem.tile_ir_name(), tile_ir); + assert_eq!(elem.llvm_name(), llvm); + assert_eq!(elem.bit_width(), bits); + assert_eq!(TileElem::from_rust_name(rust), Some(elem)); + assert_eq!( + elem.is_float(), + matches!(tile_ir, "f16" | "bf16" | "f32" | "f64") + ); + } + assert_eq!(TileElem::from_rust_name("usize"), None); + assert_eq!(TileElem::from_rust_name("bool"), None); + } + + #[test] + fn json_round_trips_and_uses_lowercase_vocabulary() { + let desc = scale_in_place(); + let json = desc.to_json(); + assert!(json.contains("\"access\":\"inout\""), "{json}"); + assert!(json.contains("\"elem\":\"f32\""), "{json}"); + assert!(json.contains("\"sync\":\"none\""), "{json}"); + assert!(json.contains("\"arch\":[\"sm_120\"]"), "{json}"); + assert_eq!(TileExportDesc::from_json(&json).unwrap(), desc); + + let mut warp = relu(); + warp.sync = TileSync::Warp; + warp.params[0].elem = TileElem::BF16; + let json = warp.to_json(); + assert!(json.contains("\"sync\":\"warp\""), "{json}"); + assert!(json.contains("\"elem\":\"bf16\""), "{json}"); + assert_eq!(TileExportDesc::from_json(&json).unwrap(), warp); + + // `sync` and `arch` default when absent. + let minimal = r#"{"version":1,"decl":"relu","symbol":"relu_impl","shape":[128], + "params":[{"name":"x","elem":"f32","access":"in","footprint":1,"by_value":true}, + {"name":"relu_out","elem":"f32","access":"out","footprint":1,"by_value":false}]}"#; + assert_eq!(TileExportDesc::from_json(minimal).unwrap(), relu()); + + let all = vec![relu(), scale_in_place()]; + let text = descriptions_to_json_pretty(&all); + assert!(text.starts_with('['), "{text}"); + assert_eq!(descriptions_from_json(&text).unwrap(), all); + } +} diff --git a/cuda-oxide/crates/reserved-oxide-symbols/README.md b/cuda-oxide/crates/reserved-oxide-symbols/README.md index cc8e0ad98d..0acc711a93 100644 --- a/cuda-oxide/crates/reserved-oxide-symbols/README.md +++ b/cuda-oxide/crates/reserved-oxide-symbols/README.md @@ -17,7 +17,7 @@ Every symbol prefix here contains the magic component `246e25db_`, which is exists purely to make accidental collisions impossible — a user is never going to write `fn cuda_oxide_codegen_v1_cuda_oxide_kernel_246e25db_foo()` by accident. -The crate owns these ten symbol constants. The `naming-guard` CI job keeps +The crate owns these eleven symbol constants. The `naming-guard` CI job keeps reserved-prefix literals out of their consumers: | Constant | Value | What it names | @@ -27,6 +27,7 @@ reserved-prefix literals out of their consumers: | `DEVICE_EXTERN_PREFIX` | `cuda_oxide_device_extern_246e25db_` | `extern` device declarations | | `INSTANTIATE_PREFIX` | `cuda_oxide_instantiate_246e25db_` | forced generic instantiations | | `CONSTANT_PREFIX` | `cuda_oxide_const_246e25db_` | `#[constant]` statics, for `cuModuleGetGlobal` lookup | +| `TILE_EXPORT_META_PREFIX` | `cuda_oxide_tile_export_246e25db_` | host-only `#[tile_export]` metadata functions whose body returns the export's JSON description | | `KERNEL_SCOPE_LOCAL` | `cuda_oxide_kernel_scope_246e25db` | the hidden thread-index scope token injected by `#[kernel]` / `#[device]` | | `ARTIFACT_ANCHOR_PREFIX` | `cuda_oxide_artifact_anchor_246e25db_` | the link anchor pinning a crate's `.oxart` section into the binary | | `PTX_MERGE_REQUIRED_PREFIX` | `cuda_oxide_ptx_merge_required_246e25db_` | statics marking modules whose generic kernels need PTX-bundle merging | diff --git a/cuda-oxide/crates/reserved-oxide-symbols/src/lib.rs b/cuda-oxide/crates/reserved-oxide-symbols/src/lib.rs index f21877ee87..010bc715d2 100644 --- a/cuda-oxide/crates/reserved-oxide-symbols/src/lib.rs +++ b/cuda-oxide/crates/reserved-oxide-symbols/src/lib.rs @@ -161,6 +161,22 @@ pub const INSTANTIATE_PREFIX: &str = "cuda_oxide_instantiate_246e25db_"; /// `set_coeffs` methods generated by `#[cuda_module]` resolve that exact name. pub const CONSTANT_PREFIX: &str = "cuda_oxide_const_246e25db_"; +/// Prefix of the host-only metadata function emitted by `#[tile_export]`. +/// +/// `tile_export_meta_symbol("relu_impl")` produces +/// `cuda_oxide_tile_export_246e25db_relu_impl`. The macro emits one such +/// `#[no_mangle] fn` per exported function; its body returns the JSON +/// description of the export as a `&'static str`. The codegen backend reads +/// that constant out of the function's MIR, writes the collected descriptions +/// to `.tileexports.json` next to the device artifact, and never +/// compiles the function itself for the device. +/// +/// The prefix contains neither [`LEGACY_KERNEL_PREFIX`] nor +/// [`LEGACY_DEVICE_PREFIX`] as a substring, so [`is_kernel_symbol`] and +/// [`is_device_symbol`] can never classify a metadata function as device +/// code. A unit test below pins that property. +pub const TILE_EXPORT_META_PREFIX: &str = "cuda_oxide_tile_export_246e25db_"; + /// Local binding name injected by `#[kernel]` and `#[device]` for the /// hidden thread-index scope token. pub const KERNEL_SCOPE_LOCAL: &str = "cuda_oxide_kernel_scope_246e25db"; @@ -266,6 +282,20 @@ pub fn constant_symbol(base: &str) -> String { format!("{CONSTANT_PREFIX}{base}") } +/// Build the `#[tile_export]` metadata-function symbol for an implementation +/// symbol. +/// +/// ``` +/// use reserved_oxide_symbols::tile_export_meta_symbol; +/// assert_eq!( +/// tile_export_meta_symbol("relu_impl"), +/// "cuda_oxide_tile_export_246e25db_relu_impl", +/// ); +/// ``` +pub fn tile_export_meta_symbol(base: &str) -> String { + format!("{TILE_EXPORT_META_PREFIX}{base}") +} + /// Build the compiler marker associated with one generic kernel. pub fn ptx_merge_required_marker(base: &str) -> String { let mut symbol = String::from(PTX_MERGE_REQUIRED_PREFIX); @@ -459,6 +489,26 @@ pub fn is_constant_symbol(name: &str) -> bool { name.contains(CONSTANT_PREFIX) } +/// Returns `true` if the last path component of `name` is a `#[tile_export]` +/// metadata function. +/// +/// Matches the final `::` component only, like +/// [`is_ptx_merge_required_marker`]: the backend looks these functions up by +/// definition path, and an enclosing module named after the prefix must not +/// turn its contents into metadata functions. +/// +/// ``` +/// use reserved_oxide_symbols::{is_tile_export_meta_symbol, tile_export_meta_symbol}; +/// assert!(is_tile_export_meta_symbol(&tile_export_meta_symbol("relu_impl"))); +/// assert!(is_tile_export_meta_symbol( +/// "tilelib::cuda_oxide_tile_export_246e25db_relu_impl" +/// )); +/// assert!(!is_tile_export_meta_symbol("relu_impl")); +/// ``` +pub fn is_tile_export_meta_symbol(name: &str) -> bool { + tile_export_meta_base_name(name).is_some() +} + /// Strip the kernel prefix from a possibly-FQDN symbol name. /// /// Returns the part of `name` after [`KERNEL_PREFIX`], or `None` if `name` @@ -551,6 +601,8 @@ pub fn display_name(name: &str) -> Option { Some(format!("{base} (device)")) } else if let Some(base) = constant_base_name(name) { Some(format!("{base} (constant)")) + } else if let Some(base) = tile_export_meta_base_name(name) { + Some(format!("{base} (tile export metadata)")) } else { instantiate_base_name(name).map(|base| format!("{base} (instantiate helper)")) } @@ -589,6 +641,29 @@ pub fn constant_base_name(name: &str) -> Option<&str> { .map(|pos| &name[pos + CONSTANT_PREFIX.len()..]) } +/// Strip the `#[tile_export]` metadata prefix from the last path component +/// of `name`, returning the implementation symbol it describes. +/// +/// ``` +/// use reserved_oxide_symbols::tile_export_meta_base_name; +/// assert_eq!( +/// tile_export_meta_base_name("cuda_oxide_tile_export_246e25db_relu_impl"), +/// Some("relu_impl"), +/// ); +/// assert_eq!( +/// tile_export_meta_base_name("tilelib::kernels::cuda_oxide_tile_export_246e25db_scale_impl"), +/// Some("scale_impl"), +/// ); +/// assert_eq!(tile_export_meta_base_name("relu_impl"), None); +/// assert_eq!(tile_export_meta_base_name("cuda_oxide_tile_export_246e25db_"), None); +/// ``` +pub fn tile_export_meta_base_name(name: &str) -> Option<&str> { + name.rsplit("::") + .next() + .and_then(|component| component.strip_prefix(TILE_EXPORT_META_PREFIX)) + .filter(|base| !base.is_empty()) +} + // ============================================================================ // Tests — pin the constant values, verify mutual-exclusion, round-trip // ============================================================================ @@ -617,6 +692,7 @@ mod tests { assert_eq!(DEVICE_EXTERN_PREFIX, "cuda_oxide_device_extern_246e25db_"); assert_eq!(INSTANTIATE_PREFIX, "cuda_oxide_instantiate_246e25db_"); assert_eq!(CONSTANT_PREFIX, "cuda_oxide_const_246e25db_"); + assert_eq!(TILE_EXPORT_META_PREFIX, "cuda_oxide_tile_export_246e25db_"); assert_eq!( PTX_MERGE_REQUIRED_PREFIX, "cuda_oxide_ptx_merge_required_246e25db_" @@ -660,6 +736,7 @@ mod tests { DEVICE_EXTERN_PREFIX, INSTANTIATE_PREFIX, CONSTANT_PREFIX, + TILE_EXPORT_META_PREFIX, PTX_MERGE_REQUIRED_PREFIX, ARTIFACT_ANCHOR_PREFIX, KERNEL_SCOPE_LOCAL, @@ -683,6 +760,45 @@ mod tests { assert!(!DEVICE_PREFIX.contains(DEVICE_EXTERN_PREFIX)); } + /// The backend finds `#[tile_export]` metadata functions by definition + /// path and must never hand one to device codegen. That holds because + /// the prefix contains no kernel or device prefix, current or legacy, + /// so the device predicates cannot match a metadata symbol, and because + /// the metadata predicate only looks at the final path component. + #[test] + fn tile_export_meta_symbols_are_neither_kernels_nor_device_functions() { + for device_like in [ + KERNEL_PREFIX, + LEGACY_KERNEL_PREFIX, + DEVICE_PREFIX, + LEGACY_DEVICE_PREFIX, + DEVICE_EXTERN_PREFIX, + ] { + assert!(!TILE_EXPORT_META_PREFIX.contains(device_like)); + assert!(!device_like.contains(TILE_EXPORT_META_PREFIX)); + } + + let meta = tile_export_meta_symbol("relu_impl"); + assert!(is_tile_export_meta_symbol(&meta)); + assert!(!is_kernel_symbol(&meta)); + assert!(!is_device_symbol(&meta)); + assert!(!is_device_extern_symbol(&meta)); + assert!(!is_constant_symbol(&meta)); + assert_eq!(tile_export_meta_base_name(&meta), Some("relu_impl")); + + // A device function and a kernel are not metadata functions. + assert!(!is_tile_export_meta_symbol(&device_symbol("relu_impl"))); + assert!(!is_tile_export_meta_symbol(&kernel_symbol("relu"))); + + // Only the final path component counts. + assert!(is_tile_export_meta_symbol(&format!( + "tilelib::kernels::{meta}" + ))); + assert!(!is_tile_export_meta_symbol(&format!("{meta}::child"))); + assert!(!is_tile_export_meta_symbol(&format!("prefix_{meta}"))); + assert!(!is_tile_export_meta_symbol(TILE_EXPORT_META_PREFIX)); + } + #[test] fn ptx_merge_markers_are_per_kernel_and_sanitized() { let marker = ptx_merge_required_marker("nested::map-value"); @@ -738,6 +854,10 @@ mod tests { ); assert_eq!(instantiate_base_name(&instantiate_symbol(base)), Some(base),); assert_eq!(constant_base_name(&constant_symbol(base)), Some(base)); + assert_eq!( + tile_export_meta_base_name(&tile_export_meta_symbol(base)), + Some(base) + ); } } @@ -851,6 +971,10 @@ mod tests { display_name(&constant_symbol("COEFFS")).as_deref(), Some("COEFFS (constant)"), ); + assert_eq!( + display_name(&tile_export_meta_symbol("relu_impl")).as_deref(), + Some("relu_impl (tile export metadata)"), + ); assert_eq!(display_name("std::vec::Vec::new"), None); } @@ -865,12 +989,17 @@ mod tests { "cuda_oxide_device_extern_evil", "cuda_oxide_instantiate_evil", "cuda_oxide_const_evil", + "cuda_oxide_tile_export_evil", ] { assert!(!is_kernel_symbol(evil), "unexpected match: {evil}"); assert!(!is_device_symbol(evil), "unexpected match: {evil}"); assert!(!is_device_extern_symbol(evil), "unexpected match: {evil}"); assert!(!is_instantiate_symbol(evil), "unexpected match: {evil}"); assert!(!is_constant_symbol(evil), "unexpected match: {evil}"); + assert!( + !is_tile_export_meta_symbol(evil), + "unexpected match: {evil}" + ); assert_eq!(display_name(evil), None); } } diff --git a/cuda-oxide/crates/rustc-codegen-cuda/.gitignore b/cuda-oxide/crates/rustc-codegen-cuda/.gitignore index f528657c89..e80f489098 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/.gitignore +++ b/cuda-oxide/crates/rustc-codegen-cuda/.gitignore @@ -7,6 +7,14 @@ rustc-ice-*.txt # Generated PTX/LLVM files *.ptx *.ll +# Tile export descriptions written next to them +*.tileexports.json +# Tile library descriptions and the library itself (cargo oxide tilelib) +*.tilebc +*.tilelib +*.tilelib.mlir +# Mock Tile-compiler callers that tile library examples generate when they run +examples/*/mock/ # Implementation log (internal notes) IMPLEMENTATION.md diff --git a/cuda-oxide/crates/rustc-codegen-cuda/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/Cargo.lock index 67a4e596a7..30afd8262e 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/Cargo.lock @@ -588,6 +588,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "pliron" version = "0.20.0" @@ -746,6 +755,7 @@ dependencies = [ "mir-lower", "once_cell", "oxide-artifacts", + "oxide-tile-export", "pliron", "pliron-derive", "reserved-oxide-symbols", diff --git a/cuda-oxide/crates/rustc-codegen-cuda/Cargo.toml b/cuda-oxide/crates/rustc-codegen-cuda/Cargo.toml index 2d724fb74c..c20211c939 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/Cargo.toml +++ b/cuda-oxide/crates/rustc-codegen-cuda/Cargo.toml @@ -24,6 +24,8 @@ llvm-export = { path = "../llvm-export" } dialect-mir = { path = "../dialect-mir" } dialect-nvvm = { path = "../dialect-nvvm" } reserved-oxide-symbols = { path = "../reserved-oxide-symbols" } +# `#[tile_export]` descriptions, read back out of the metadata functions' MIR. +oxide-tile-export = { path = "../oxide-tile-export" } oxide-artifacts = { version = "0.2.1", features = ["object-write"] } # Shared driver-independent libNVVM + nvJitLink finalization policy. This # crate loads CUDA compiler libraries at run time and never links libcuda. diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/abi_hmm/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/abi_hmm/Cargo.lock index 1d51a50e54..ce0fdb7a46 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/abi_hmm/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/abi_hmm/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/addressof_sharedarray/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/addressof_sharedarray/Cargo.lock index b8e441c59e..298682ebe7 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/addressof_sharedarray/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/addressof_sharedarray/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/aligned_field_loads/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/aligned_field_loads/Cargo.lock index 0b75539022..f5335376d4 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/aligned_field_loads/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/aligned_field_loads/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/aligned_field_stores/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/aligned_field_stores/Cargo.lock index 502e06c899..4c5f7cb96a 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/aligned_field_stores/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/aligned_field_stores/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/array_constants/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/array_constants/Cargo.lock index 708068528d..ef1ecaa2a8 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/array_constants/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/array_constants/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/array_for_loop/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/array_for_loop/Cargo.lock index 0c024bb8a5..3d737175ef 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/array_for_loop/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/array_for_loop/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/array_index/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/array_index/Cargo.lock index e83e8a8704..d3a3501bfa 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/array_index/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/array_index/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/array_init/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/array_init/Cargo.lock index b93c70c05f..86fba05561 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/array_init/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/array_init/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/asin_acos_smoke/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/asin_acos_smoke/Cargo.lock index 0401eff7d5..802b3b906e 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/asin_acos_smoke/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/asin_acos_smoke/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/assume_init_uninhabited_trap/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/assume_init_uninhabited_trap/Cargo.lock index 248ff82b0f..3adf8ffba8 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/assume_init_uninhabited_trap/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/assume_init_uninhabited_trap/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/async_mlp/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/async_mlp/Cargo.lock index 22a8b4bc2c..7028e34dbe 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/async_mlp/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/async_mlp/Cargo.lock @@ -217,6 +217,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -443,6 +444,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -558,6 +565,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror 2.0.18", +] + [[package]] name = "parking_lot_core" version = "0.9.12" @@ -712,6 +728,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -950,3 +979,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/async_vecadd/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/async_vecadd/Cargo.lock index 902af286c7..2174866807 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/async_vecadd/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/async_vecadd/Cargo.lock @@ -217,6 +217,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -443,6 +444,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -558,6 +565,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror 2.0.18", +] + [[package]] name = "parking_lot_core" version = "0.9.12" @@ -712,6 +728,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -950,3 +979,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/atomic_f16/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/atomic_f16/Cargo.lock index 25e548ea3b..b9a5b8237d 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/atomic_f16/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/atomic_f16/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/atomics/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/atomics/Cargo.lock index 011e726425..88b7fea84b 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/atomics/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/atomics/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/barrier/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/barrier/Cargo.lock index f17829532f..8b838a20e4 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/barrier/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/barrier/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/bf16x2_arith/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/bf16x2_arith/Cargo.lock index 31c36820b6..de59e51102 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/bf16x2_arith/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/bf16x2_arith/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/bf16x2_fma/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/bf16x2_fma/Cargo.lock index 4edfd7f252..251e9a2a67 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/bf16x2_fma/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/bf16x2_fma/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/bool_phi_cmp/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/bool_phi_cmp/Cargo.lock index 876fb8c273..670e54de0c 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/bool_phi_cmp/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/bool_phi_cmp/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/carrying_mul_add/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/carrying_mul_add/Cargo.lock index c41a3f5c30..c07608a163 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/carrying_mul_add/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/carrying_mul_add/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/cast_chunks/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/cast_chunks/Cargo.lock index 0476d620a1..7354ec93d3 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/cast_chunks/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/cast_chunks/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/cast_tests/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/cast_tests/Cargo.lock index a885f34945..5a0f4f1248 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/cast_tests/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/cast_tests/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/cbrt_smoke/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/cbrt_smoke/Cargo.lock index 6250c3b0b7..3dac7b1997 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/cbrt_smoke/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/cbrt_smoke/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/checked_arith/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/checked_arith/Cargo.lock index 22a605d5c9..aef438f58d 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/checked_arith/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/checked_arith/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/clc/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/clc/Cargo.lock index 6409d9f788..b2358c8f96 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/clc/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/clc/Cargo.lock @@ -194,6 +194,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -312,6 +313,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -418,6 +425,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -532,6 +548,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -717,3 +746,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/cluster/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/cluster/Cargo.lock index 53a895695a..428561d84b 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/cluster/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/cluster/Cargo.lock @@ -194,6 +194,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -312,6 +313,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -418,6 +425,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -532,6 +548,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -717,3 +746,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/compiler_features/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/compiler_features/Cargo.lock index 70deb8c7c7..33acd7147e 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/compiler_features/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/compiler_features/Cargo.lock @@ -194,6 +194,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -312,6 +313,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -418,6 +425,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -532,6 +548,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -717,3 +746,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/complex_mul/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/complex_mul/Cargo.lock index 60eb1baa31..c4fa3cf464 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/complex_mul/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/complex_mul/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/const_aggregate/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/const_aggregate/Cargo.lock index 3ef71976cc..6ea623f850 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/const_aggregate/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/const_aggregate/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/const_bool_dead_branch/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/const_bool_dead_branch/Cargo.lock index 41fabb1728..91b2876e08 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/const_bool_dead_branch/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/const_bool_dead_branch/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/const_generic/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/const_generic/Cargo.lock index ccc08f96f2..b15a635b4c 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/const_generic/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/const_generic/Cargo.lock @@ -194,6 +194,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -312,6 +313,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -418,6 +425,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -532,6 +548,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -717,3 +746,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/const_table_lookup/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/const_table_lookup/Cargo.lock index 26fb53caca..8ae82696df 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/const_table_lookup/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/const_table_lookup/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/const_tuple_table_lookup/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/const_tuple_table_lookup/Cargo.lock index 12a18ab687..53037c381d 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/const_tuple_table_lookup/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/const_tuple_table_lookup/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/constant_index_from_end/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/constant_index_from_end/Cargo.lock index 4470121240..ab06a74fe1 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/constant_index_from_end/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/constant_index_from_end/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/constant_memory/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/constant_memory/Cargo.lock index 6e8890fbf5..441dc70016 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/constant_memory/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/constant_memory/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/constant_memory_coeffs/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/constant_memory_coeffs/Cargo.lock index ac248d8bb3..cbd2c4a773 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/constant_memory_coeffs/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/constant_memory_coeffs/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/constant_memory_simple/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/constant_memory_simple/Cargo.lock index 98e2a8c034..8656b34c60 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/constant_memory_simple/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/constant_memory_simple/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/constant_memory_table/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/constant_memory_table/Cargo.lock index 7c62ceae52..e1b980e909 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/constant_memory_table/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/constant_memory_table/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/coop_groups_demo/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/coop_groups_demo/Cargo.lock index dcca83bb32..cd1195cbd1 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/coop_groups_demo/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/coop_groups_demo/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/copy_aggregate_borrow/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/copy_aggregate_borrow/Cargo.lock index fdaba39cbd..0ef4472db0 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/copy_aggregate_borrow/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/copy_aggregate_borrow/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/copy_nonoverlapping/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/copy_nonoverlapping/Cargo.lock index e583f5fddb..03fc3fb565 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/copy_nonoverlapping/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/copy_nonoverlapping/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/counted_barrier/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/counted_barrier/Cargo.lock index d6e529758d..ee38589b3f 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/counted_barrier/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/counted_barrier/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/cp_async_small/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/cp_async_small/Cargo.lock index 0641ecb7ab..8884ed45e2 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/cp_async_small/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/cp_async_small/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/cp_async_zfill/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/cp_async_zfill/Cargo.lock index 19b846ea77..4c768d4fe9 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/cp_async_zfill/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/cp_async_zfill/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/cpp_consumes_rust_device/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/cpp_consumes_rust_device/Cargo.lock index 059f389beb..51381eb264 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/cpp_consumes_rust_device/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/cpp_consumes_rust_device/Cargo.lock @@ -192,6 +192,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -310,6 +311,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -416,6 +423,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -530,6 +546,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -715,3 +744,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/cross_crate_embedded/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/cross_crate_embedded/Cargo.lock index 5d37f456da..58f9f47452 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/cross_crate_embedded/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/cross_crate_embedded/Cargo.lock @@ -194,6 +194,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -321,6 +322,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -427,6 +434,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -541,6 +557,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -726,3 +755,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/cross_crate_kernel/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/cross_crate_kernel/Cargo.lock index 8aa5c60c45..4142ea1aa4 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/cross_crate_kernel/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/cross_crate_kernel/Cargo.lock @@ -195,6 +195,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -313,6 +314,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "kernel-lib" version = "0.1.0" @@ -428,6 +435,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -542,6 +558,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -727,3 +756,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/cross_crate_merged_symbols/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/cross_crate_merged_symbols/Cargo.lock index 7d6afea4d1..12297db68c 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/cross_crate_merged_symbols/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/cross_crate_merged_symbols/Cargo.lock @@ -194,6 +194,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -312,6 +313,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -427,6 +434,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -541,6 +557,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -726,3 +755,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/cross_crate_recursion/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/cross_crate_recursion/Cargo.lock index 304d4f8738..8f2b797d96 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/cross_crate_recursion/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/cross_crate_recursion/Cargo.lock @@ -194,6 +194,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -312,6 +313,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -418,6 +425,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -536,6 +552,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -721,3 +750,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/cuda_module_contract/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/cuda_module_contract/Cargo.lock index b7ccbf3cd6..08be6237f6 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/cuda_module_contract/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/cuda_module_contract/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -312,6 +313,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -418,6 +425,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -532,6 +548,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -717,3 +746,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/cuda_module_in_lib/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/cuda_module_in_lib/Cargo.lock index aedf8ee1f5..ed02b84ccf 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/cuda_module_in_lib/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/cuda_module_in_lib/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -312,6 +313,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -427,6 +434,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -541,6 +557,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -726,3 +755,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/cuda_module_nested/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/cuda_module_nested/Cargo.lock index 15fa7deaa9..971388c6c3 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/cuda_module_nested/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/cuda_module_nested/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/cutile_inter_kernel/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/cutile_inter_kernel/Cargo.lock index 79a4f6425a..fe8a69f59d 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/cutile_inter_kernel/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/cutile_inter_kernel/Cargo.lock @@ -905,9 +905,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.150" +version = "1.0.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" dependencies = [ "itoa", "memchr", @@ -1403,6 +1403,6 @@ dependencies = [ [[package]] name = "zmij" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/cutile_inter_kernel/simt/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/cutile_inter_kernel/simt/Cargo.lock index b6bb84c873..35aaf4c667 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/cutile_inter_kernel/simt/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/cutile_inter_kernel/simt/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/cvt_f16x2/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/cvt_f16x2/Cargo.lock index 41761b8893..818576913e 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/cvt_f16x2/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/cvt_f16x2/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/cvt_packed/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/cvt_packed/Cargo.lock index be34c2de32..94d0618251 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/cvt_packed/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/cvt_packed/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/debug-tests/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/debug-tests/Cargo.lock index f66d568a2c..f5df8eec21 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/debug-tests/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/debug-tests/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -312,6 +313,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -418,6 +425,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -532,6 +548,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -717,3 +746,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/debug/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/debug/Cargo.lock index c45afc11ea..06c9f62bfd 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/debug/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/debug/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -312,6 +313,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -418,6 +425,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -532,6 +548,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -717,3 +746,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/debug_pointer_locals/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/debug_pointer_locals/Cargo.lock index ff0ba980c8..a163c07916 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/debug_pointer_locals/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/debug_pointer_locals/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/device_closures/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/device_closures/Cargo.lock index fbfc3fe9d0..a71448a33a 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/device_closures/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/device_closures/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/device_ffi_test/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/device_ffi_test/Cargo.lock index f9a370b1fd..a158e03b8d 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/device_ffi_test/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/device_ffi_test/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/device_global/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/device_global/Cargo.lock index d9f51af73f..35ee0cd474 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/device_global/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/device_global/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/device_panic_trap/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/device_panic_trap/Cargo.lock index abbccc4d8d..6407c721d4 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/device_panic_trap/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/device_panic_trap/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/disjoint_from_raw_parts/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/disjoint_from_raw_parts/Cargo.lock index 99e58cf0fa..16f5eeea64 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/disjoint_from_raw_parts/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/disjoint_from_raw_parts/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/disjoint_slice_len/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/disjoint_slice_len/Cargo.lock index b57449f344..dd634310c2 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/disjoint_slice_len/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/disjoint_slice_len/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/dotprod/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/dotprod/Cargo.lock index 927e35e5b9..6eae6d938e 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/dotprod/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/dotprod/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/dpx_minmax_chains/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/dpx_minmax_chains/Cargo.lock index 3986154648..e089b4e94a 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/dpx_minmax_chains/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/dpx_minmax_chains/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/drop_glue/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/drop_glue/Cargo.lock index 092d9bad63..266b7f6694 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/drop_glue/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/drop_glue/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/dst_metadata/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/dst_metadata/Cargo.lock index 663fe0e1e4..9c6fb2bc3e 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/dst_metadata/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/dst_metadata/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/dynamic_smem/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/dynamic_smem/Cargo.lock index f1f4b2c026..d00f6456ab 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/dynamic_smem/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/dynamic_smem/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/elect_leader/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/elect_leader/Cargo.lock index f5ce40a552..24b95937f2 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/elect_leader/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/elect_leader/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/enum_abi_multi_payload/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/enum_abi_multi_payload/Cargo.lock index 55fa067ced..6139e1050f 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/enum_abi_multi_payload/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/enum_abi_multi_payload/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/enum_array_match/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/enum_array_match/Cargo.lock index 34e21c7c8e..4985ca6d9f 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/enum_array_match/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/enum_array_match/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/enum_constant_provenance/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/enum_constant_provenance/Cargo.lock index 24abb1e836..8af4e5d135 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/enum_constant_provenance/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/enum_constant_provenance/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/enum_payload_addr/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/enum_payload_addr/Cargo.lock index 1966983afe..c952ef0989 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/enum_payload_addr/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/enum_payload_addr/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/enum_state_transitions/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/enum_state_transitions/Cargo.lock index 4d1eb8f254..3a6c6a60cc 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/enum_state_transitions/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/enum_state_transitions/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/enum_table_lookup/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/enum_table_lookup/Cargo.lock index 795acb9cd4..984dd1bb34 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/enum_table_lookup/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/enum_table_lookup/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/error/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/error/Cargo.lock index ae7af048ac..aaa54e5982 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/error/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/error/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -312,6 +313,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -418,6 +425,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -532,6 +548,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -717,3 +746,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/error_enum_bool_payload_addr/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/error_enum_bool_payload_addr/Cargo.lock index c7bd9ac758..ce15431ac5 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/error_enum_bool_payload_addr/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/error_enum_bool_payload_addr/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/error_enum_pointer_overlap/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/error_enum_pointer_overlap/Cargo.lock index 5e1649b078..0fa3b0a4ee 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/error_enum_pointer_overlap/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/error_enum_pointer_overlap/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/error_enum_shared_pointer_layout/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/error_enum_shared_pointer_layout/Cargo.lock index a8d8bd3db7..f06797a06b 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/error_enum_shared_pointer_layout/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/error_enum_shared_pointer_layout/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/error_generated_intrinsic_abi/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/error_generated_intrinsic_abi/Cargo.lock index 4d24441cc8..4c5a1cecc5 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/error_generated_intrinsic_abi/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/error_generated_intrinsic_abi/Cargo.lock @@ -188,6 +188,7 @@ version = "99.0.2" name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -315,6 +316,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -421,6 +428,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -535,6 +551,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -720,3 +749,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/error_generated_intrinsic_callable/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/error_generated_intrinsic_callable/Cargo.lock index ac775b6804..edd815e111 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/error_generated_intrinsic_callable/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/error_generated_intrinsic_callable/Cargo.lock @@ -188,6 +188,7 @@ version = "0.1.0" name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -315,6 +316,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -421,6 +428,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -535,6 +551,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -720,3 +749,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/error_generated_intrinsic_fn_pointer/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/error_generated_intrinsic_fn_pointer/Cargo.lock index a471e93a9f..d5446db5d0 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/error_generated_intrinsic_fn_pointer/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/error_generated_intrinsic_fn_pointer/Cargo.lock @@ -188,6 +188,7 @@ version = "0.1.0" name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -315,6 +316,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -421,6 +428,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -535,6 +551,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -720,3 +749,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/error_generated_intrinsic_unknown_id/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/error_generated_intrinsic_unknown_id/Cargo.lock index 25462fd135..9b25129d83 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/error_generated_intrinsic_unknown_id/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/error_generated_intrinsic_unknown_id/Cargo.lock @@ -188,6 +188,7 @@ version = "99.0.1" name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -315,6 +316,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -421,6 +428,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -535,6 +551,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -720,3 +749,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/error_heap_alloc/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/error_heap_alloc/Cargo.lock index 25827662ff..1a466544e6 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/error_heap_alloc/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/error_heap_alloc/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/error_host_arch_intrinsic/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/error_host_arch_intrinsic/Cargo.lock index 5319a897c1..7191053847 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/error_host_arch_intrinsic/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/error_host_arch_intrinsic/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/error_host_target_feature/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/error_host_target_feature/Cargo.lock index 360a02431e..3219ee0d34 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/error_host_target_feature/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/error_host_target_feature/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/error_kernel_shared_param/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/error_kernel_shared_param/Cargo.lock index c04672d297..44916f1a99 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/error_kernel_shared_param/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/error_kernel_shared_param/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/error_missing_device_attr/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/error_missing_device_attr/Cargo.lock index 91997eec33..649e784194 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/error_missing_device_attr/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/error_missing_device_attr/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/error_set_discriminant_uninhabited/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/error_set_discriminant_uninhabited/Cargo.lock index 2a2d387203..5c81d90910 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/error_set_discriminant_uninhabited/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/error_set_discriminant_uninhabited/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/ex2_approx_f16/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/ex2_approx_f16/Cargo.lock index 2b169c6980..33cd0aa21e 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/ex2_approx_f16/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/ex2_approx_f16/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/exact_div_chunks/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/exact_div_chunks/Cargo.lock index 87a392571e..93a2a2860b 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/exact_div_chunks/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/exact_div_chunks/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/export_name_policy/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/export_name_policy/Cargo.lock index a5cf5dbb4b..ad50057c7b 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/export_name_policy/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/export_name_policy/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/extern_crate_closure/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/extern_crate_closure/Cargo.lock index e45f61411e..a3de61cf65 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/extern_crate_closure/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/extern_crate_closure/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -316,6 +317,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -422,6 +429,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -536,6 +552,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -721,3 +750,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/extern_libdevice/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/extern_libdevice/Cargo.lock index e35322740d..676af798d0 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/extern_libdevice/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/extern_libdevice/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/f16_stress/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/f16_stress/Cargo.lock index ba6233de9b..1981d414f2 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/f16_stress/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/f16_stress/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/f16x2_arith/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/f16x2_arith/Cargo.lock index d3dc0ec184..31579841ea 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/f16x2_arith/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/f16x2_arith/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/f32x2_arith/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/f32x2_arith/Cargo.lock index 9df6fbcb48..9bc296863f 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/f32x2_arith/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/f32x2_arith/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/fcmp_ne_nan_smoke/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/fcmp_ne_nan_smoke/Cargo.lock index 472983a662..71b0d21466 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/fcmp_ne_nan_smoke/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/fcmp_ne_nan_smoke/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/field_array_assign/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/field_array_assign/Cargo.lock index de8cbf89e1..b198305b8e 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/field_array_assign/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/field_array_assign/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/float_rounding/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/float_rounding/Cargo.lock index 82a53311d6..80dfa026eb 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/float_rounding/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/float_rounding/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/fmaxmin_smoke/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/fmaxmin_smoke/Cargo.lock index d9f5a36d7b..a3233b3c21 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/fmaxmin_smoke/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/fmaxmin_smoke/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/fn_ptr_naming/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/fn_ptr_naming/Cargo.lock index 81d4b2aeb3..2a909c83ac 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/fn_ptr_naming/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/fn_ptr_naming/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/fp_special_literal_smoke/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/fp_special_literal_smoke/Cargo.lock index cc7a0b49d8..86eb3f25e8 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/fp_special_literal_smoke/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/fp_special_literal_smoke/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/function_item_call/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/function_item_call/Cargo.lock index 0aecde78e5..fc1c163579 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/function_item_call/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/function_item_call/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/future_apis/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/future_apis/Cargo.lock index 6acb192412..cbfd3853ea 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/future_apis/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/future_apis/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -312,6 +313,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -418,6 +425,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -532,6 +548,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -717,3 +746,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/gemm/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/gemm/Cargo.lock index 056047ee7d..d83a865a01 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/gemm/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/gemm/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/gemm_sol/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/gemm_sol/Cargo.lock index 0aa6bf7395..4ce39a1971 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/gemm_sol/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/gemm_sol/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -312,6 +313,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -418,6 +425,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -532,6 +548,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -717,3 +746,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/gemm_sol_final/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/gemm_sol_final/Cargo.lock index 99a1c1c813..ad956f3af4 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/gemm_sol_final/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/gemm_sol_final/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -313,6 +314,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -419,6 +426,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -533,6 +549,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -718,3 +747,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/gemm_views/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/gemm_views/Cargo.lock index 6b48d2b29b..9a3324ea0b 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/gemm_views/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/gemm_views/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -312,6 +313,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -418,6 +425,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -532,6 +548,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -717,3 +746,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/generated_intrinsics/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/generated_intrinsics/Cargo.lock index e965b3570e..cd9f2ba0b2 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/generated_intrinsics/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/generated_intrinsics/Cargo.lock @@ -188,6 +188,7 @@ version = "0.1.0" name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -316,6 +317,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -422,6 +429,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -536,6 +552,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -721,3 +750,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/generated_intrinsics_blackwell/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/generated_intrinsics_blackwell/Cargo.lock index 65176bc3a3..04de2c5f8b 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/generated_intrinsics_blackwell/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/generated_intrinsics_blackwell/Cargo.lock @@ -188,6 +188,7 @@ version = "0.1.0" name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -316,6 +317,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -422,6 +429,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -536,6 +552,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -721,3 +750,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/generated_ldmatrix/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/generated_ldmatrix/Cargo.lock index 0e5a302952..bb356b611b 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/generated_ldmatrix/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/generated_ldmatrix/Cargo.lock @@ -188,6 +188,7 @@ version = "0.1.0" name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -316,6 +317,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -422,6 +429,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -536,6 +552,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -721,3 +750,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/generic/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/generic/Cargo.lock index cf06cdd05d..6a78ca4f12 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/generic/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/generic/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/hashmap/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/hashmap/Cargo.lock index e44dd77b0c..86b24f7d2a 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/hashmap/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/hashmap/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/hashmap_v2/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/hashmap_v2/Cargo.lock index 6a872c48e4..0fb7f0e99e 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/hashmap_v2/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/hashmap_v2/Cargo.lock @@ -215,6 +215,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -346,6 +347,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -452,6 +459,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -586,6 +602,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -771,3 +800,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/hashmap_v3/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/hashmap_v3/Cargo.lock index f5ae4facdd..b781c994c5 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/hashmap_v3/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/hashmap_v3/Cargo.lock @@ -215,6 +215,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -346,6 +347,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -452,6 +459,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -586,6 +602,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -771,3 +800,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/hello_constant/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/hello_constant/Cargo.lock index 5279c6e7ef..f3fe99746f 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/hello_constant/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/hello_constant/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/helper_fn/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/helper_fn/Cargo.lock index f6d933ccbc..7de74fdb2b 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/helper_fn/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/helper_fn/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/host_closure/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/host_closure/Cargo.lock index 2add398677..05cdf65074 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/host_closure/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/host_closure/Cargo.lock @@ -206,6 +206,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -442,6 +443,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -557,6 +564,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror 2.0.18", +] + [[package]] name = "parking_lot_core" version = "0.9.12" @@ -711,6 +727,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -928,3 +957,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/host_closure_target_feature/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/host_closure_target_feature/Cargo.lock index df77869652..6c77a5ff67 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/host_closure_target_feature/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/host_closure_target_feature/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/iket_trace/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/iket_trace/Cargo.lock index 781249726e..86c75b8ff3 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/iket_trace/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/iket_trace/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/image_convolution/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/image_convolution/Cargo.lock index 6cb6944b5c..d5aa2ae65e 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/image_convolution/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/image_convolution/Cargo.lock @@ -196,6 +196,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -344,6 +345,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -470,6 +477,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "png" version = "0.17.16" @@ -597,6 +613,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -794,3 +823,9 @@ name = "zlib-rs" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b268e58e7c693d7c271f93ffc4ba3b380412554231c85bf61ca7af91042a4112" + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/index2d_const/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/index2d_const/Cargo.lock index 0686ce42dd..3836acca0b 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/index2d_const/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/index2d_const/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/index_field_assign/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/index_field_assign/Cargo.lock index 34f5c2907d..1a1e93d7b5 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/index_field_assign/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/index_field_assign/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/inline_ptx/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/inline_ptx/Cargo.lock index ebaeb8b7e0..53bc623360 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/inline_ptx/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/inline_ptx/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/integer_minmax/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/integer_minmax/Cargo.lock index ea07c279ad..fe88f463bb 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/integer_minmax/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/integer_minmax/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/interior_mutability/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/interior_mutability/Cargo.lock index b9c688b9c5..a6f716be40 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/interior_mutability/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/interior_mutability/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/interop_cubin_identity/device/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/interop_cubin_identity/device/Cargo.lock index 5b1e7cd88d..f22694c1a4 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/interop_cubin_identity/device/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/interop_cubin_identity/device/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/kernel_reference_validity/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/kernel_reference_validity/Cargo.lock index 421a8e618e..6100df50d1 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/kernel_reference_validity/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/kernel_reference_validity/Cargo.lock @@ -206,6 +206,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -432,6 +433,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "kernel_reference_validity" version = "0.1.0" @@ -556,6 +563,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror 2.0.18", +] + [[package]] name = "parking_lot_core" version = "0.9.12" @@ -710,6 +726,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -927,3 +956,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/lanemask_scan/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/lanemask_scan/Cargo.lock index e0a335f508..394622c351 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/lanemask_scan/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/lanemask_scan/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lanemask_scan" version = "0.1.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/legacy_atomic_fadd/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/legacy_atomic_fadd/Cargo.lock index acedcabc8b..1e2ee59815 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/legacy_atomic_fadd/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/legacy_atomic_fadd/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/legacy_atomic_rmw_cas/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/legacy_atomic_rmw_cas/Cargo.lock index 904c9c5d51..ecfb175d50 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/legacy_atomic_rmw_cas/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/legacy_atomic_rmw_cas/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/legacy_nvvm_pointer_shapes/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/legacy_nvvm_pointer_shapes/Cargo.lock index 41da688d10..1aa0595d80 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/legacy_nvvm_pointer_shapes/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/legacy_nvvm_pointer_shapes/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/libdevice_math/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/libdevice_math/Cargo.lock index 285c0c6c88..d285772669 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/libdevice_math/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/libdevice_math/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/libm_math/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/libm_math/Cargo.lock index fe87b406fb..460643529b 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/libm_math/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/libm_math/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -424,6 +431,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -538,6 +554,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -723,3 +752,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/manual_launch_generic/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/manual_launch_generic/Cargo.lock index 175db3a78e..3f172b6f05 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/manual_launch_generic/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/manual_launch_generic/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/manual_launch_libdevice/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/manual_launch_libdevice/Cargo.lock index f402402704..4118e90b10 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/manual_launch_libdevice/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/manual_launch_libdevice/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/map_sum/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/map_sum/Cargo.lock index 8c33481722..9924014ffa 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/map_sum/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/map_sum/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/math_atan/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/math_atan/Cargo.lock index b60d260cf3..8ce1894329 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/math_atan/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/math_atan/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/math_hyperbolic/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/math_hyperbolic/Cargo.lock index bf4fc4cda4..f7f1e6c274 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/math_hyperbolic/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/math_hyperbolic/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/math_no_mir_inline/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/math_no_mir_inline/Cargo.lock index 9cbbb86a02..b7718a33a7 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/math_no_mir_inline/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/math_no_mir_inline/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/math_tan/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/math_tan/Cargo.lock index d32db3b7d9..552212e5e4 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/math_tan/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/math_tan/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/mathdx_ffi_test/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/mathdx_ffi_test/Cargo.lock index 8d14b54b1c..76fc9daba6 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/mathdx_ffi_test/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/mathdx_ffi_test/Cargo.lock @@ -204,6 +204,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -331,6 +332,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -454,6 +461,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -574,6 +590,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -759,3 +788,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/mcast_barrier_test/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/mcast_barrier_test/Cargo.lock index f8bd26cdd5..47eec7302e 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/mcast_barrier_test/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/mcast_barrier_test/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/mem_swap/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/mem_swap/Cargo.lock index 9f0b7f6203..611d7a182b 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/mem_swap/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/mem_swap/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/mir_projected_call_destination/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/mir_projected_call_destination/Cargo.lock index 3fd8bac65e..8791af0505 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/mir_projected_call_destination/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/mir_projected_call_destination/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -424,6 +431,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -538,6 +554,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -723,3 +752,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/mma_mxf8f6f4/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/mma_mxf8f6f4/Cargo.lock index 1e680c9900..da7974c0f7 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/mma_mxf8f6f4/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/mma_mxf8f6f4/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/ne_bytes_transmute/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/ne_bytes_transmute/Cargo.lock index 978743e322..4bd0371e5b 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/ne_bytes_transmute/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/ne_bytes_transmute/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/nested_index_assignment/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/nested_index_assignment/Cargo.lock index 2be4cddb5c..c52786e005 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/nested_index_assignment/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/nested_index_assignment/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/numeric_stress/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/numeric_stress/Cargo.lock index 3de95b53ce..bfd2fa4115 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/numeric_stress/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/numeric_stress/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/nvls_all_reduce/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/nvls_all_reduce/Cargo.lock index 816249364b..781a8d3f06 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/nvls_all_reduce/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/nvls_all_reduce/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/option_ref_transmute/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/option_ref_transmute/Cargo.lock index 74b48892c7..b5af8f30b4 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/option_ref_transmute/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/option_ref_transmute/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/option_ref_unwrap_or/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/option_ref_unwrap_or/Cargo.lock index 8f05005c91..f5893ba8a7 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/option_ref_unwrap_or/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/option_ref_unwrap_or/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/option_unwrap_trap/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/option_unwrap_trap/Cargo.lock index 5dce21dac4..85a0cbe346 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/option_unwrap_trap/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/option_unwrap_trap/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/ord_cmp/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/ord_cmp/Cargo.lock index 31ced58282..b80b1f9dcb 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/ord_cmp/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/ord_cmp/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/packed_aggregate_abi/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/packed_aggregate_abi/Cargo.lock index 09dddb0199..f4c8348b24 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/packed_aggregate_abi/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/packed_aggregate_abi/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "packed_aggregate_abi" version = "0.1.0" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/packed_atomic_add/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/packed_atomic_add/Cargo.lock index b3709e011e..5c9aae69d3 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/packed_atomic_add/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/packed_atomic_add/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "packed_atomic_add" version = "0.1.0" @@ -532,6 +548,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -717,3 +746,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/padded_constants/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/padded_constants/Cargo.lock index 393991e170..7621003859 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/padded_constants/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/padded_constants/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "padded_constants" version = "0.1.0" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/partial_warp_reduce/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/partial_warp_reduce/Cargo.lock index ba0ebf3c83..1dd0ec55a8 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/partial_warp_reduce/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/partial_warp_reduce/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "partial_warp_reduce" version = "0.1.0" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/pinned_overlap/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/pinned_overlap/Cargo.lock index f819cd7b3b..f00ea7f41c 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/pinned_overlap/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/pinned_overlap/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "pinned_overlap" version = "0.1.0" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/place_read_fallbacks/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/place_read_fallbacks/Cargo.lock index 78b2f77a2a..63206cdbab 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/place_read_fallbacks/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/place_read_fallbacks/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "place_read_fallbacks" version = "0.1.0" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/policy_config/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/policy_config/Cargo.lock index 713f0777ab..ac860e426a 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/policy_config/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/policy_config/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "policy_config" version = "0.1.0" @@ -532,6 +548,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -717,3 +746,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/primitive_stress/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/primitive_stress/Cargo.lock index c84a6e15e3..f07ca73faa 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/primitive_stress/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/primitive_stress/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/printf/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/printf/Cargo.lock index a06ac1675b..cfaa742b4f 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/printf/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/printf/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -532,6 +548,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -717,3 +746,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/projected_place_read/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/projected_place_read/Cargo.lock index 88cde29662..30bc83e4e5 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/projected_place_read/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/projected_place_read/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/proof_carrying_views/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/proof_carrying_views/Cargo.lock index 3ec04b9e64..42b08210f7 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/proof_carrying_views/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/proof_carrying_views/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -532,6 +548,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -717,3 +746,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/ptr_copy/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/ptr_copy/Cargo.lock index 5b4640b69b..de5ac4ae48 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/ptr_copy/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/ptr_copy/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/ptr_offset_from/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/ptr_offset_from/Cargo.lock index c17c3d7a1c..0ec7cfb44f 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/ptr_offset_from/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/ptr_offset_from/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/ptr_without_provenance/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/ptr_without_provenance/Cargo.lock index b9d72525d5..fa5df66742 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/ptr_without_provenance/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/ptr_without_provenance/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/reborrow/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/reborrow/Cargo.lock index c6112cebe8..8d7de86367 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/reborrow/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/reborrow/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/redux_f32/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/redux_f32/Cargo.lock index fbe1e8cb36..a74777042e 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/redux_f32/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/redux_f32/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/redux_minmax/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/redux_minmax/Cargo.lock index ecbeeb54f8..bbb321da29 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/redux_minmax/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/redux_minmax/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/redux_sum/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/redux_sum/Cargo.lock index 45927fe620..3495a7289a 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/redux_sum/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/redux_sum/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/ref_index_projections/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/ref_index_projections/Cargo.lock index 74c888841a..58a388e07a 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/ref_index_projections/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/ref_index_projections/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/ref_operand_mul/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/ref_operand_mul/Cargo.lock index 94d0fa2102..ec2404f932 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/ref_operand_mul/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/ref_operand_mul/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/repr_align_block_args/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/repr_align_block_args/Cargo.lock index 159dcc98f3..cc0078e643 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/repr_align_block_args/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/repr_align_block_args/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/repr_transparent_abi/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/repr_transparent_abi/Cargo.lock index 10231a6158..fa4c02c424 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/repr_transparent_abi/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/repr_transparent_abi/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -532,6 +548,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -717,3 +746,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/repr_u32_enum_stride/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/repr_u32_enum_stride/Cargo.lock index c2f3be4056..6af97378f8 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/repr_u32_enum_stride/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/repr_u32_enum_stride/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/row_width_slice/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/row_width_slice/Cargo.lock index 9cf1089479..85b2f5f477 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/row_width_slice/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/row_width_slice/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/rustlantis-smoke/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/rustlantis-smoke/Cargo.lock index 9d24a6b8d4..67e55271c0 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/rustlantis-smoke/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/rustlantis-smoke/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -306,6 +307,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -412,6 +419,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -536,6 +552,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -721,3 +750,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/scoped_atomic_load_store/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/scoped_atomic_load_store/Cargo.lock index 26d379b8e3..013a3379fb 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/scoped_atomic_load_store/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/scoped_atomic_load_store/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/select_unpredictable/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/select_unpredictable/Cargo.lock index b1cb5d2039..86eafa2b6e 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/select_unpredictable/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/select_unpredictable/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/set_discriminant/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/set_discriminant/Cargo.lock index a623091819..bbd354e38b 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/set_discriminant/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/set_discriminant/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "set_discriminant" version = "0.1.0" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/set_discriminant_niche/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/set_discriminant_niche/Cargo.lock index 158ecda0ac..e157fea2ac 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/set_discriminant_niche/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/set_discriminant_niche/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "set_discriminant_niche" version = "0.1.0" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/shared_debug/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/shared_debug/Cargo.lock index b790ed2ca1..3195c5052d 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/shared_debug/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/shared_debug/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/shared_memory_helper/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/shared_memory_helper/Cargo.lock index 881232eacb..e72dcc60f5 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/shared_memory_helper/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/shared_memory_helper/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -724,3 +753,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/shared_ptr_transmute/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/shared_ptr_transmute/Cargo.lock index 6b72183413..42647acf94 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/shared_ptr_transmute/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/shared_ptr_transmute/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/shared_slice_unsize/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/shared_slice_unsize/Cargo.lock index 0a11acde77..7517a55603 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/shared_slice_unsize/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/shared_slice_unsize/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/shared_stage_select/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/shared_stage_select/Cargo.lock index b3f2de5290..98f07a9a47 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/shared_stage_select/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/shared_stage_select/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/sharedmem/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/sharedmem/Cargo.lock index e9f87595fa..e60e6cf190 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/sharedmem/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/sharedmem/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/shuffle_64/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/shuffle_64/Cargo.lock index 7e138e6546..46b3b08f05 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/shuffle_64/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/shuffle_64/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/slice_from_raw_parts_cast/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/slice_from_raw_parts_cast/Cargo.lock index 205c918587..52b8d52887 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/slice_from_raw_parts_cast/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/slice_from_raw_parts_cast/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/slice_get_mut/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/slice_get_mut/Cargo.lock index 9edf3c367b..20152e80f8 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/slice_get_mut/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/slice_get_mut/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/slice_index_bounds_check/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/slice_index_bounds_check/Cargo.lock index 5f89a85bdc..e28e9d5ddf 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/slice_index_bounds_check/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/slice_index_bounds_check/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/slice_iterators/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/slice_iterators/Cargo.lock index a0b6344167..0ac8bde6f2 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/slice_iterators/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/slice_iterators/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/slice_reslice/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/slice_reslice/Cargo.lock index 1a2c8f2fad..fe2e92d2b2 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/slice_reslice/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/slice_reslice/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/small_type_ffi_test/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/small_type_ffi_test/Cargo.lock index 4f6f48790e..d446e6625f 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/small_type_ffi_test/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/small_type_ffi_test/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/sparse_mma_fp8/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/sparse_mma_fp8/Cargo.lock index 9b2a168a17..c781eb7524 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/sparse_mma_fp8/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/sparse_mma_fp8/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/sparse_mma_ordered_float/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/sparse_mma_ordered_float/Cargo.lock index 337858588b..03d67c5e3a 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/sparse_mma_ordered_float/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/sparse_mma_ordered_float/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/split_at_mut/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/split_at_mut/Cargo.lock index 60eb51980e..4324edf483 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/split_at_mut/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/split_at_mut/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/standalone_device_fn/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/standalone_device_fn/Cargo.lock index bd369b09ad..bbf2681720 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/standalone_device_fn/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/standalone_device_fn/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -715,3 +744,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/static_slice_addend/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/static_slice_addend/Cargo.lock index 651695d697..15f0537070 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/static_slice_addend/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/static_slice_addend/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/static_slice_unsize/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/static_slice_unsize/Cargo.lock index 3b9c78d986..c074858de1 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/static_slice_unsize/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/static_slice_unsize/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/step_by/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/step_by/Cargo.lock index 8433420962..84cba98cab 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/step_by/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/step_by/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/struct_constant_provenance/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/struct_constant_provenance/Cargo.lock index 00a570174e..690c24a327 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/struct_constant_provenance/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/struct_constant_provenance/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/struct_field_layout/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/struct_field_layout/Cargo.lock index 3fdd686f8a..fe53acdb76 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/struct_field_layout/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/struct_field_layout/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/subslice_projection/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/subslice_projection/Cargo.lock index b4cc31859f..7ef72e0da5 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/subslice_projection/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/subslice_projection/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/switchint_128bit/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/switchint_128bit/Cargo.lock index 2ce3306137..03811356e6 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/switchint_128bit/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/switchint_128bit/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/swizzle_smem/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/swizzle_smem/Cargo.lock index 3b56442154..f152cecc4c 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/swizzle_smem/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/swizzle_smem/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/tcgen05/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/tcgen05/Cargo.lock index 1f5d931f29..8c6054ce23 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/tcgen05/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/tcgen05/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/tcgen05_matmul/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/tcgen05_matmul/Cargo.lock index 8c2269f5d1..651ffe661e 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/tcgen05_matmul/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/tcgen05_matmul/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -717,3 +746,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/thread_runs/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/thread_runs/Cargo.lock index 34faff57b2..75c208fc87 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/thread_runs/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/thread_runs/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/tiled_gemm/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/tiled_gemm/Cargo.lock index 4ba660c11e..cf9576c158 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/tiled_gemm/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/tiled_gemm/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/tma_copy/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/tma_copy/Cargo.lock index d4c75a0b72..5a9c81ad8f 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/tma_copy/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/tma_copy/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/tma_multicast/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/tma_multicast/Cargo.lock index 7af886b9bc..3977ab9ddc 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/tma_multicast/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/tma_multicast/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/toolchain_pairing_smoke/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/toolchain_pairing_smoke/Cargo.lock index d07a8d2fa7..29f8b4dec6 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/toolchain_pairing_smoke/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/toolchain_pairing_smoke/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/transmute_scalar_struct/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/transmute_scalar_struct/Cargo.lock index 3c965c977f..0e2998f8d5 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/transmute_scalar_struct/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/transmute_scalar_struct/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/tuple_array_provenance/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/tuple_array_provenance/Cargo.lock index ba512ea61c..de10cae507 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/tuple_array_provenance/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/tuple_array_provenance/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/tuple_constant_provenance/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/tuple_constant_provenance/Cargo.lock index a32429c09f..48212e960c 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/tuple_constant_provenance/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/tuple_constant_provenance/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/tuple_field_lookup/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/tuple_field_lookup/Cargo.lock index 44984c38b3..47aad8a282 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/tuple_field_lookup/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/tuple_field_lookup/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/tuple_return/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/tuple_return/Cargo.lock index ec8eee26e6..2ac68321ee 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/tuple_return/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/tuple_return/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/unaligned_memory/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/unaligned_memory/Cargo.lock index f063fd2267..4affc8b321 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/unaligned_memory/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/unaligned_memory/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/unchecked_indexing/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/unchecked_indexing/Cargo.lock index b3ee031b9c..53f368594d 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/unchecked_indexing/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/unchecked_indexing/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -717,3 +746,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/uninit_const/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/uninit_const/Cargo.lock index 0dae26617c..1517384a3b 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/uninit_const/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/uninit_const/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/union_aggregate/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/union_aggregate/Cargo.lock index 0ff48d9e4c..c2a4fec2d7 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/union_aggregate/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/union_aggregate/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/unroll_bounds_check/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/unroll_bounds_check/Cargo.lock index 5262ec59b0..71e089c287 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/unroll_bounds_check/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/unroll_bounds_check/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/unroll_smoke/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/unroll_smoke/Cargo.lock index 8d0cce9016..780f6f3e9d 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/unroll_smoke/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/unroll_smoke/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/vecadd/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/vecadd/Cargo.lock index dead9d09ff..9d76a571bd 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/vecadd/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/vecadd/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/vectorization/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/vectorization/Cargo.lock index 07061c7cb4..6cb5e3d2a9 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/vectorization/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/vectorization/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -717,3 +746,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/volatile_memory/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/volatile_memory/Cargo.lock index 31a9923785..51689b847a 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/volatile_memory/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/volatile_memory/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/warp_reduce/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/warp_reduce/Cargo.lock index 6225903e18..49805d2fe3 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/warp_reduce/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/warp_reduce/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/warp_sums/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/warp_sums/Cargo.lock index cfffc70730..1b446984c3 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/warp_sums/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/warp_sums/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/wgmma/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/wgmma/Cargo.lock index 288c97ac06..11fbfa1d79 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/wgmma/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/wgmma/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/wgmma_mma_bf16/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/wgmma_mma_bf16/Cargo.lock index 2fe046b8aa..e5e504178f 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/wgmma_mma_bf16/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/wgmma_mma_bf16/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -302,6 +303,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -408,6 +415,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -522,6 +538,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/src/collector.rs b/cuda-oxide/crates/rustc-codegen-cuda/src/collector.rs index 0b2bb713ab..4fcbf51b3e 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/src/collector.rs +++ b/cuda-oxide/crates/rustc-codegen-cuda/src/collector.rs @@ -246,10 +246,11 @@ enum CollectDecision { // match. The mutual-exclusion guarantee between `DEVICE_PREFIX` and // `DEVICE_EXTERN_PREFIX` means we no longer need the historical // "test extern first" ordering dance that lived here previously. +use oxide_tile_export::TileExportDesc; use reserved_oxide_symbols::{ - device_extern_base_name, is_current_device_symbol, is_current_kernel_symbol, + device_base_name, device_extern_base_name, is_current_device_symbol, is_current_kernel_symbol, is_device_extern_symbol, is_device_symbol, is_kernel_symbol, is_legacy_kernel_symbol, - is_ptx_merge_required_marker, kernel_base_name, + is_ptx_merge_required_marker, is_tile_export_meta_symbol, kernel_base_name, }; /// Sanitize a symbol name for use as a PTX identifier. @@ -396,6 +397,12 @@ pub struct CollectionResult<'tcx> { /// dependency. Cubin materialization must reject this case until it can /// reproduce the same cross-crate linking semantics. pub requires_ptx_bundle_merge: bool, + + /// `#[tile_export]` descriptions read from this crate's metadata + /// functions, sorted by implementation symbol. Each one's implementation + /// is a root in `functions`; the backend writes them to + /// `.tileexports.json` beside the device artifact. + pub tile_exports: Vec, } /// Counts kernel functions across all codegen units. @@ -916,6 +923,145 @@ impl DiscoveryCtx { } } +/// Read every `#[tile_export]` description embedded in this crate. +/// +/// The macro emits one host-only `#[no_mangle] fn +/// cuda_oxide_tile_export__() -> &'static str` per export whose +/// body returns the JSON description. That shape needs no file IO or side +/// channel: `#[no_mangle]` items are always codegened, so the function is in +/// the CGUs even though nothing calls it, and its description is a constant +/// in MIR. The function is never compiled for the device; see the explicit +/// skips in [`collect_device_functions`] and `process_call_operand`. +/// +/// Malformed metadata is fatal rather than skipped: a description that does +/// not parse or validate means the macro and this backend disagree, and a +/// silently missing export would surface much later as a tile library +/// without the symbol the caller asked for. +fn collect_tile_exports<'tcx>( + tcx: TyCtxt<'tcx>, + cgus: &[CodegenUnit<'tcx>], + verbose: bool, +) -> Vec { + let mut descs: Vec = Vec::new(); + let mut seen = HashSet::new(); + for cgu in cgus { + for (item, _data) in cgu.items() { + let MonoItem::Fn(instance) = item else { + continue; + }; + let def_id = instance.def_id(); + let def_path = tcx.def_path_str(def_id); + if !is_tile_export_meta_symbol(&def_path) { + continue; + } + // Partitioning can place one item in several CGUs. + if !seen.insert(def_id) { + continue; + } + let Some(text) = tile_export_meta_text(tcx, *instance) else { + tcx.dcx().span_fatal( + tcx.def_span(def_id), + format!( + "[rustc_codegen_cuda] `{def_path}` carries the reserved tile export \ + metadata prefix but does not return one constant string; only \ + `#[tile_export]` may define functions with this prefix" + ), + ); + }; + let desc = TileExportDesc::from_json(&text).unwrap_or_else(|error| { + tcx.dcx().span_fatal( + tcx.def_span(def_id), + format!( + "[rustc_codegen_cuda] tile export metadata in `{def_path}` is not a \ + description this backend understands ({error}); rebuild with \ + cuda-macros from the same cuda-oxide revision as the backend" + ), + ) + }); + if let Err(error) = desc.validate() { + tcx.dcx().span_fatal( + tcx.def_span(def_id), + format!( + "[rustc_codegen_cuda] tile export `{}` is invalid: {error}", + desc.decl + ), + ); + } + if let Some(previous) = descs.iter().find(|other| other.symbol == desc.symbol) { + tcx.dcx().span_fatal( + tcx.def_span(def_id), + format!( + "[rustc_codegen_cuda] tile exports `{}` and `{}` both use the \ + implementation symbol `{}`; give one of them a distinct `symbol`", + previous.decl, desc.decl, desc.symbol + ), + ); + } + // The declaration name is what a cuTile caller resolves, so two + // exports sharing one would collide in the tile library; catch it + // here rather than when `cargo oxide tilelib` builds the modules. + if let Some(previous) = descs.iter().find(|other| other.decl == desc.decl) { + tcx.dcx().span_fatal( + tcx.def_span(def_id), + format!( + "[rustc_codegen_cuda] tile exports `{}` and `{}` both declare the \ + name `{}` to cuTile; give one of them a distinct `name`", + previous.symbol, desc.symbol, desc.decl + ), + ); + } + if verbose { + eprintln!( + "[collector] Found tile export: {} -> {} (shape {:?}, {} params, sync {})", + desc.decl, + desc.symbol, + desc.shape, + desc.params.len(), + desc.sync.tile_ir_name() + ); + } + descs.push(desc); + } + } + // Stable output regardless of CGU partitioning. + descs.sort_by(|a, b| a.symbol.cmp(&b.symbol)); + descs +} + +/// The constant `&str` a tile export metadata function returns. +/// +/// The optimized body is `_0 = const ""; return`, so the description is +/// the constant operand assigned to `RETURN_PLACE`. The constant evaluates to +/// a `ConstValue::Slice` (or `Indirect`) of UTF-8 bytes; `const_str_text` +/// reads both representations. Anything else (no such assignment, a +/// non-constant, or more than one) returns `None` and the caller reports it. +fn tile_export_meta_text<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Option { + use rustc_middle::mir::{Operand, RETURN_PLACE, Rvalue, StatementKind}; + + let mir = tcx.instance_mir(instance.def); + let mut found = None; + for block in mir.basic_blocks.iter() { + for statement in &block.statements { + let StatementKind::Assign(assign) = &statement.kind else { + continue; + }; + let (place, rvalue) = &**assign; + if place.as_local() != Some(RETURN_PLACE) { + continue; + } + // The second field is the retag marker, irrelevant to a constant. + let Rvalue::Use(Operand::Constant(constant), _) = rvalue else { + return None; + }; + let text = const_str_text(tcx, constant)?; + if found.replace(text).is_some() { + return None; + } + } + } + found +} + /// Collects all device-reachable functions starting from kernel entry points. /// /// This is the main entry point for device function collection. It: @@ -941,6 +1087,7 @@ pub fn collect_device_functions<'tcx>( verbose: bool, ) -> CollectionResult<'tcx> { let mut collector = DeviceCollector::new(tcx, verbose); + let tile_exports = collect_tile_exports(tcx, cgus, verbose); let mut requires_ptx_bundle_merge = cgus.iter().any(|cgu| { cgu.items().iter().any(|(item, _data)| match item { MonoItem::Static(def_id) => is_ptx_merge_required_marker(&tcx.def_path_str(*def_id)), @@ -948,10 +1095,13 @@ pub fn collect_device_functions<'tcx>( }) }); - // Find all kernel entry points + // Find all kernel entry points. `#[tile_export]` metadata functions are + // host-only (their descriptions were read above) and never device code; + // the prefix cannot match a kernel, but say so here rather than rely on it. for cgu in cgus { for (item, _data) in cgu.items() { if let MonoItem::Fn(instance) = item + && !is_tile_export_meta_symbol(&tcx.def_path_str(instance.def_id())) && is_kernel_function(tcx, instance.def_id()) { // Skip generic (non-monomorphized) instances. @@ -1005,15 +1155,67 @@ pub fn collect_device_functions<'tcx>( } } + let has_kernels = !collector.worklist.is_empty(); + + // `#[tile_export]` implementations are roots whether or not the crate has + // kernels: no device code calls them, and the standalone scan below only + // runs for kernel-less crates. The description's `symbol` is the base + // name of the `#[device]` wrapper, which is also what the symbol becomes + // in the device artifact once llvm-export strips the device prefix. + for desc in &tile_exports { + let mut found = false; + for cgu in cgus { + for (item, _data) in cgu.items() { + let MonoItem::Fn(instance) = item else { + continue; + }; + let raw_name = tcx.def_path_str(instance.def_id()); + if device_base_name(&raw_name) != Some(desc.symbol.as_str()) + || !is_device_function(tcx, instance.def_id()) + || !is_fully_monomorphized(tcx, *instance) + // The macro rejects generics, so a generic device function + // sharing the base name is not the implementation. + || !instance.args.is_empty() + { + continue; + } + let name = collector.fqdn(*instance); + let export_name = collector.compute_export_name(&name, *instance); + if verbose { + eprintln!( + "[collector] Found tile export implementation: {} -> {}", + name, export_name + ); + } + collector.add_root(*instance, false, export_name); + found = true; + } + } + if !found { + tcx.dcx().fatal(format!( + "[rustc_codegen_cuda] tile export `{}` names the implementation symbol `{}`, \ + but this crate has no `#[device]` function with that name. `#[tile_export]` \ + generates the implementation next to the exported function; keep the two \ + together and do not rename the generated item", + desc.decl, desc.symbol + )); + } + } + // Find standalone device function roots (Phase 2: device functions without kernels). // Only scan when there are NO kernels — when kernels exist, device functions are - // already collected transitively via the call graph walk. - if collector.worklist.is_empty() { + // already collected transitively via the call graph walk. Tile export + // implementations were rooted above and are skipped here so their export + // names are not computed twice. + if !has_kernels { for cgu in cgus { for (item, _data) in cgu.items() { if let MonoItem::Fn(instance) = item + // Host-only metadata, never device code (see the kernel scan). + && !is_tile_export_meta_symbol(&tcx.def_path_str(instance.def_id())) && is_device_function(tcx, instance.def_id()) && is_fully_monomorphized(tcx, *instance) + && !collector.is_seen(*instance) { let raw_name = tcx.def_path_str(instance.def_id()); @@ -1045,6 +1247,7 @@ pub fn collect_device_functions<'tcx>( // Process the worklist to collect all reachable functions let mut result = collector.collect(); result.requires_ptx_bundle_merge = requires_ptx_bundle_merge; + result.tile_exports = tile_exports; result } @@ -1120,6 +1323,11 @@ impl<'tcx> DeviceCollector<'tcx> { ) } + /// True once `instance` has been rooted or discovered. + fn is_seen(&self, instance: Instance<'tcx>) -> bool { + self.seen.contains(self.tcx.symbol_name(instance).name) + } + /// Adds a root function (kernel) to start collection from. fn add_root(&mut self, instance: Instance<'tcx>, is_kernel: bool, export_name: String) { // Use mangled name as the unique key - this distinguishes different @@ -1254,6 +1462,7 @@ impl<'tcx> DeviceCollector<'tcx> { functions: self.result, device_externs: self.device_externs, requires_ptx_bundle_merge: false, + tile_exports: Vec::new(), } } @@ -1498,6 +1707,28 @@ impl<'tcx> DeviceCollector<'tcx> { return; }; let fn_path = self.tcx.def_path_str(*def_id); + + // `#[tile_export]` metadata functions are host-only: their body is + // the JSON description the collector already consumed. A device-side + // call means user code reached for the generated item. Refuse it + // here instead of skipping: a skipped call would leave a dangling + // symbol that fails later at module verification. + if is_tile_export_meta_symbol(&fn_path) { + self.tcx + .dcx() + .struct_span_fatal( + call_span, + format!( + "device code in `{}` calls `{fn_path}`, a `#[tile_export]` metadata \ + function; it is host-only and holds the export's JSON description, \ + not device code", + caller.export_name + ), + ) + .with_help("call the exported function itself, or its `` wrapper") + .emit() + } + if fn_path.contains("DynamicSharedArray") && (fn_path.contains("::get") || fn_path.contains("::get_raw") diff --git a/cuda-oxide/crates/rustc-codegen-cuda/src/lib.rs b/cuda-oxide/crates/rustc-codegen-cuda/src/lib.rs index fc5fc48e74..97d5e41dd5 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/src/lib.rs +++ b/cuda-oxide/crates/rustc-codegen-cuda/src/lib.rs @@ -772,6 +772,25 @@ impl CodegenBackend for CudaCodegenBackend { "[rustc_codegen_cuda] Device codegen did not produce an embeddable artifact", ); } + if !collection_result.tile_exports.is_empty() { + match write_tile_export_descriptions( + &device_config.output_dir, + &device_config.output_name, + &collection_result.tile_exports, + ) { + Ok(path) => { + if self.config.verbose { + eprintln!( + "[rustc_codegen_cuda] Tile export descriptions written: {}", + path.display() + ); + } + } + Err(e) => tcx.dcx().fatal(format!( + "[rustc_codegen_cuda] Failed to write tile export descriptions: {e}" + )), + } + } Some(result) } Ok(Err(e)) => { @@ -849,6 +868,25 @@ impl CodegenBackend for CudaCodegenBackend { } } +/// Write `.tileexports.json` next to the `.ll`/`.ptx`: the JSON +/// array of this crate's `#[tile_export]` descriptions. `cargo oxide tilelib` +/// reads it to build the Tile IR interface and implementation modules; the +/// device artifact itself carries nothing from it. +fn write_tile_export_descriptions( + output_dir: &Path, + output_name: &str, + tile_exports: &[oxide_tile_export::TileExportDesc], +) -> std::io::Result { + let path = output_dir.join(format!( + "{output_name}.{}", + oxide_tile_export::DESCRIPTIONS_SUFFIX + )); + let mut text = oxide_tile_export::descriptions_to_json_pretty(tile_exports); + text.push('\n'); + std::fs::write(&path, text)?; + Ok(path) +} + #[allow(clippy::too_many_arguments)] fn write_device_artifact_object( tcx: TyCtxt<'_>, diff --git a/cuda-oxide/cuda-oxide-book/compiler/architecture-overview.md b/cuda-oxide/cuda-oxide-book/compiler/architecture-overview.md index 60ca175d69..173660b5ec 100644 --- a/cuda-oxide/cuda-oxide-book/compiler/architecture-overview.md +++ b/cuda-oxide/cuda-oxide-book/compiler/architecture-overview.md @@ -146,6 +146,7 @@ cuda-oxide is split into focused crates. Here is every one and its role: | `cuda-intrinsics-gen`| Extractor and deterministic source generator for the intrinsics | | `cuda-artifact-finalizer` | Driver-independent NVVM IR, LTOIR, and PTX finalization | | `oxide-artifacts` | Architecture-neutral embedded device artifact metadata | +| `oxide-tile-export` | `#[tile_export]` descriptions shared by the macro, the backend and `cargo oxide tilelib` | | `dialect-iket` | pliron dialect modelling in-kernel event tracing | | `iket-lower` | `dialect-iket` profiles + instrumentation lowering | | `dialect-ptx` | pliron dialect modelling structured PTX | diff --git a/cuda-oxide/dependency-licenses.csv b/cuda-oxide/dependency-licenses.csv index e6b8722489..bb3b3fca36 100644 --- a/cuda-oxide/dependency-licenses.csv +++ b/cuda-oxide/dependency-licenses.csv @@ -82,6 +82,7 @@ nvvm-transforms,0.2.1,Apache-2.0,Yes,local (workspace),1st Party (workspace),htt object,0.36.7,Apache-2.0 OR MIT,Yes,registry+https://github.com/rust-lang/crates.io-index,3rd Party (crates.io),https://github.com/gimli-rs/object,A unified interface for reading and writing object file formats.,ELF reading and writing behind oxide-artifacts' object features. once_cell,1.21.3,MIT OR Apache-2.0,Yes,registry+https://github.com/rust-lang/crates.io-index,3rd Party (crates.io),https://github.com/matklad/once_cell,Single assignment cells and lazy values., oxide-artifacts,0.2.1,Apache-2.0,Yes,registry+https://github.com/rust-lang/crates.io-index,1st Party (crates.io),https://github.com/NVIDIA/cuda-rust,Architecture-neutral embedded device artifact metadata for cuda-oxide,"Consumed from crates.io by the backend (writer) and by the shared cuda-core (reader) so both see one crate; crates/oxide-artifacts in this workspace is the source it is published from." +oxide-tile-export,0.2.1,Apache-2.0,Yes,local (workspace),1st Party (workspace),https://github.com/NVIDIA/cuda-rust,Descriptions of Rust device functions exported to cuTile tile libraries,Shared by #[tile_export] (cuda-macros) and the rustc-codegen-cuda backend; cargo oxide tilelib reads the .tileexports.json it describes. pliron,0.20.0,Apache-2.0,Yes,registry+https://github.com/rust-lang/crates.io-index,3rd Party (crates.io),https://github.com/pliron-org/pliron,Programming Languages Intermediate RepresentatiON,"Primary dependency: MLIR-inspired IR framework. Custom MLIR dialects (MIR, LLVM, NVVM) built on this. Exact published release shared by the compiler workspaces." pliron-derive,0.20.0,Apache-2.0,Yes,registry+https://github.com/rust-lang/crates.io-index,3rd Party (crates.io),https://github.com/pliron-org/pliron,Derive macros for pliron,Proc-macro companion pinned to the same published release as pliron. pliron-llvm,0.20.0,Apache-2.0,Yes,registry+https://github.com/rust-lang/crates.io-index,3rd Party (crates.io),https://github.com/pliron-org/pliron,LLVM dialect for pliron,Upstream LLVM dialect modeling; re-exported by llvm-export with std enabled and the llvm-sys FFI bridge disabled. Same published release as pliron. From 72951b25742120afe63f9a36b3e0c7c117293f2e Mon Sep 17 00:00:00 2001 From: nihalpasham Date: Sun, 18 Oct 2026 19:12:56 +0530 Subject: [PATCH 2/3] feat(oxide-tilebc): write Tile IR bytecode for tile library descriptions A tile library lets a Tile kernel call a SIMT function. cuda-oxide is the SIMT provider: it ships the code as LTOIR and describes it twice, as the declaration a Tile kernel calls and as the native symbol with the fragment each parameter receives. This crate writes those two descriptions as Tile IR bytecode and nothing else in the format: header, function table with bodiless `preview$func extern` and `preview$extern_impl` entries, type and string tables, and the one-entry debug table. - A small model (`Declaration`, `Implementation`, tiles, fragments, layouts, the synchronization, arch and frontendABI clauses) with a verifier for the rules the Tile compiler applies when the halves meet. - `interface_bytecode` and `implementation_bytecode` take the version the consuming assembler calls current; preview content is readable at no other version, and anything below 13.5 is an error. - A readable textual form of both modules. Every encoding was derived from the Tile IR compiler sources and checked against the CUDA 13.6 assembler: `tileiras --preview-create-tile-lib` packs this crate's output into a library a Tile C++ kernel then calls. Signed-off-by: nihalpasham --- .github/workflows/unit-tests.yml | 2 + cuda-oxide/Cargo.lock | 11 +- cuda-oxide/Cargo.toml | 5 + cuda-oxide/Justfile | 2 +- cuda-oxide/crates/oxide-tilebc/Cargo.toml | 15 + cuda-oxide/crates/oxide-tilebc/README.md | 56 +++ .../crates/oxide-tilebc/src/encoding.rs | 201 ++++++++ cuda-oxide/crates/oxide-tilebc/src/lib.rs | 358 ++++++++++++++ cuda-oxide/crates/oxide-tilebc/src/model.rs | 465 ++++++++++++++++++ cuda-oxide/crates/oxide-tilebc/src/text.rs | 134 +++++ cuda-oxide/crates/oxide-tilebc/src/verify.rs | 360 ++++++++++++++ cuda-oxide/crates/oxide-tilebc/src/writer.rs | 379 ++++++++++++++ .../compiler/architecture-overview.md | 1 + cuda-oxide/dependency-licenses.csv | 1 + 14 files changed, 1988 insertions(+), 2 deletions(-) create mode 100644 cuda-oxide/crates/oxide-tilebc/Cargo.toml create mode 100644 cuda-oxide/crates/oxide-tilebc/README.md create mode 100644 cuda-oxide/crates/oxide-tilebc/src/encoding.rs create mode 100644 cuda-oxide/crates/oxide-tilebc/src/lib.rs create mode 100644 cuda-oxide/crates/oxide-tilebc/src/model.rs create mode 100644 cuda-oxide/crates/oxide-tilebc/src/text.rs create mode 100644 cuda-oxide/crates/oxide-tilebc/src/verify.rs create mode 100644 cuda-oxide/crates/oxide-tilebc/src/writer.rs diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 3c8515c891..65fa016743 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -71,6 +71,8 @@ jobs: # `#[tile_export]` descriptions and their validation rules, shared # by cuda-macros, the backend and cargo-oxide. Pure Rust, no CUDA. - package: oxide-tile-export + # The Tile IR bytecode writer for those descriptions. Pure Rust. + - package: oxide-tilebc - package: reserved-oxide-symbols # launch_requires_unsafe trybuild fixture dev-depends on # cuda-host/cuda-core, which transitively pull cuda-bindings diff --git a/cuda-oxide/Cargo.lock b/cuda-oxide/Cargo.lock index 4826c46343..cdef05af07 100644 --- a/cuda-oxide/Cargo.lock +++ b/cuda-oxide/Cargo.lock @@ -212,6 +212,8 @@ dependencies = [ "libnvvm-sys", "nvjitlink-sys", "oxide-artifacts 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "oxide-tile-export", + "oxide-tilebc", "ptx-parse", "ptx-schedule", "reserved-oxide-symbols", @@ -1108,7 +1110,14 @@ version = "0.2.1" dependencies = [ "serde", "serde_json", - "thiserror 2.0.18", + "thiserror 2.0.21", +] + +[[package]] +name = "oxide-tilebc" +version = "0.2.1" +dependencies = [ + "thiserror 2.0.21", ] [[package]] diff --git a/cuda-oxide/Cargo.toml b/cuda-oxide/Cargo.toml index d4f6b8fc72..6aeea9929e 100644 --- a/cuda-oxide/Cargo.toml +++ b/cuda-oxide/Cargo.toml @@ -25,6 +25,7 @@ members = [ "crates/cargo-oxide", "crates/oxide-artifacts", "crates/oxide-tile-export", + "crates/oxide-tilebc", # FFI bindings "crates/libnvvm-sys", "crates/nvjitlink-sys", @@ -101,6 +102,10 @@ oxide-artifacts = "0.2.1" # Tile export descriptions shared by `#[tile_export]`, the backend, and # `cargo oxide tilelib`. oxide-tile-export = { path = "crates/oxide-tile-export" } +# Tile IR bytecode for those descriptions: `cargo oxide tilelib` writes a +# tile library's interface and implementation halves with it. Pure Rust, so +# cargo-oxide stays toolkit-free. +oxide-tilebc = { path = "crates/oxide-tilebc" } ptx-parse = { path = "crates/ptx-parse" } ptx-schedule = { path = "crates/ptx-schedule" } diff --git a/cuda-oxide/Justfile b/cuda-oxide/Justfile index 71f9333506..ac37ec18d3 100644 --- a/cuda-oxide/Justfile +++ b/cuda-oxide/Justfile @@ -61,7 +61,7 @@ test: -p cuda-intrinsics-gen -p cuda-target-spec -p cuda-intrinsics -p llvm-export \ -p dialect-mir -p dialect-nvvm -p mir-importer -p mir-lower \ -p mir-transforms -p nvvm-transforms -p reserved-oxide-symbols \ - -p oxide-tile-export -p cuda-device -p libnvvm-sys -p nvjitlink-sys \ + -p oxide-tile-export -p oxide-tilebc -p cuda-device -p libnvvm-sys -p nvjitlink-sys \ -p cuda-artifact-finalizer -p cargo-oxide \ -p dialect-iket -p iket-lower -p ptx-parse -p dialect-ptx \ -p ptx-schedule diff --git a/cuda-oxide/crates/oxide-tilebc/Cargo.toml b/cuda-oxide/crates/oxide-tilebc/Cargo.toml new file mode 100644 index 0000000000..6b2cd1fc43 --- /dev/null +++ b/cuda-oxide/crates/oxide-tilebc/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "oxide-tilebc" +version = "0.2.1" +edition.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true +description = "Tile IR bytecode writer for the tile library descriptions cuda-oxide ships" +readme = "README.md" + +[dependencies] +thiserror = { workspace = true } + +[lints.rust] +missing_docs = { level = "deny" } diff --git a/cuda-oxide/crates/oxide-tilebc/README.md b/cuda-oxide/crates/oxide-tilebc/README.md new file mode 100644 index 0000000000..ecc78100b0 --- /dev/null +++ b/cuda-oxide/crates/oxide-tilebc/README.md @@ -0,0 +1,56 @@ +# oxide-tilebc + +Tile IR bytecode for the tile libraries cuda-oxide ships. + +A tile library lets a Tile kernel call a SIMT function. cuda-oxide is the +SIMT provider: it compiles the Rust function to LTOIR and describes it twice, +once as the declaration a Tile kernel calls (the interface) and once as the +native symbol with the fragment each parameter receives (the implementation). +`tileiras --preview-create-tile-lib` packs the three into one `.tilelib`. This +crate writes the two descriptions; nothing else in the Tile IR format. + +```text +#[tile_export] descriptions ──> Library { declarations, implementations } + │ + interface_bytecode(v) ───┼──> .iface.tilebc (preview$func extern ...) + implementation_bytecode(v)┴──> .impl.tilebc (preview$extern_impl ...) + │ + tileiras --preview-create-tile-lib + .ltoir ──> .tilelib +``` + +The descriptions are public-preview content, which exists from Tile IR 13.5 +on and which an assembler reads only at the version it calls current, the +newest numbered version its `--list-versions` prints. `BytecodeVersion::parse` +reads that listing; pass the newest version to the two writers. + +```rust +use oxide_tilebc::*; + +let tile = TileType::new(vec![128], ScalarType::F32); +let decl = Declaration::new("relu", vec![ + TileArg::new("x", tile.clone(), Access::In), + TileArg::new("relu_out", tile, Access::Out), +]); +let imp = Implementation::new("relu_impl", "relu", vec![ + FragmentArg::new("x", FragmentType::new(vec![1], ScalarType::F32, MemorySpace::Local, + Layout::scalar_mem(), Layout::elementwise(128)), Access::In), + FragmentArg::new("relu_out", FragmentType::new(vec![1], ScalarType::F32, MemorySpace::Local, + Layout::contiguous_mem(1), Layout::elementwise(128)), Access::Out), +]); +let library = Library::new("relu", vec![decl], vec![imp]); +library.verify()?; +let interface = library.interface_bytecode(BytecodeVersion::new(13, 5))?; +let implementation = library.implementation_bytecode(BytecodeVersion::new(13, 5))?; +println!("{}{}", library.interface_text(), library.implementation_text()); +# Ok::<(), oxide_tilebc::Error>(()) +``` + +`verify` applies the rules the Tile compiler's own verifier applies when the +two halves meet: one contiguous run of written arguments, one fragment per +argument with the same access and element type, fragmaps that cover the tile +with the participants the synchronization clause promises, and a rank-0 +buffer layout (a scalar passed by value) only for a read-only local fragment. + +The wire format was derived from the Tile IR compiler sources and checked +against an assembler that reads 13.5 content: its `--preview-create-tile-lib` +packs this crate's output into a library that a Tile C++ kernel then calls. diff --git a/cuda-oxide/crates/oxide-tilebc/src/encoding.rs b/cuda-oxide/crates/oxide-tilebc/src/encoding.rs new file mode 100644 index 0000000000..50816429bf --- /dev/null +++ b/cuda-oxide/crates/oxide-tilebc/src/encoding.rs @@ -0,0 +1,201 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +//! The byte-level primitives of Tile IR bytecode: LEB128 varints, zigzag +//! signed varints, little-endian words, alignment padding and section +//! framing. These are the same primitives every Tile IR producer uses; the +//! reference reader documents them in its bytecode grammar. + +/// The eight magic bytes every Tile IR bytecode file starts with. +pub const MAGIC: [u8; 8] = [0x7F, b'T', b'i', b'l', b'e', b'I', b'R', 0x00]; + +/// Padding byte used to reach a section's alignment. +pub const ALIGNMENT_BYTE: u8 = 0xCB; + +/// Header tag bit set when a module carries public-preview content. +pub const CONTAINS_PREVIEW: u16 = 0x1; + +/// Section identifiers. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u8)] +pub enum Section { + /// Marks the end of the file. + EndOfBytecode = 0x00, + /// The string table. + String = 0x01, + /// The function table. + Func = 0x02, + /// Debug locations and attributes. + Debug = 0x03, + /// The type table. + Type = 0x05, +} + +/// An append-only byte buffer with the bytecode's integer encodings. +#[derive(Debug, Default)] +pub struct Writer { + buf: Vec, +} + +impl Writer { + /// An empty buffer. + pub fn new() -> Self { + Self::default() + } + + /// One raw byte. + pub fn byte(&mut self, value: u8) { + self.buf.push(value); + } + + /// Raw bytes. + pub fn bytes(&mut self, data: &[u8]) { + self.buf.extend_from_slice(data); + } + + /// An unsigned LEB128 varint: seven bits per byte, high bit set while + /// more bytes follow. Tags at or above 0x80 therefore take two bytes. + pub fn varint(&mut self, mut value: u64) { + loop { + let mut byte = (value & 0x7F) as u8; + value >>= 7; + if value != 0 { + byte |= 0x80; + } + self.buf.push(byte); + if value == 0 { + return; + } + } + } + + /// A zigzag-encoded signed varint, used for `int64_t` parameters. + pub fn signed_varint(&mut self, value: i64) { + self.varint(((value << 1) ^ (value >> 63)) as u64); + } + + /// A little-endian `u32`. + pub fn le_u32(&mut self, value: u32) { + self.buf.extend_from_slice(&value.to_le_bytes()); + } + + /// A little-endian `u64`. + pub fn le_u64(&mut self, value: u64) { + self.buf.extend_from_slice(&value.to_le_bytes()); + } + + /// `varint(count)` followed by each value as a little-endian `i64`: the + /// encoding of a shape. + pub fn le_var_size_i64(&mut self, values: &[i64]) { + self.varint(values.len() as u64); + for &value in values { + self.buf.extend_from_slice(&value.to_le_bytes()); + } + } + + /// Pad with [`ALIGNMENT_BYTE`] until the length is a multiple of + /// `alignment`. + pub fn align_to(&mut self, alignment: usize) { + if alignment < 2 { + return; + } + while !self.buf.len().is_multiple_of(alignment) { + self.buf.push(ALIGNMENT_BYTE); + } + } + + /// The current length. + #[allow(clippy::len_without_is_empty)] + pub fn len(&self) -> usize { + self.buf.len() + } + + /// Overwrite a little-endian `u32` written earlier (an offset table slot). + pub fn patch_u32(&mut self, offset: usize, value: u32) { + self.buf[offset..offset + 4].copy_from_slice(&value.to_le_bytes()); + } + + /// The bytes. + pub fn into_bytes(self) -> Vec { + self.buf + } +} + +/// Append a section to `out`: the id byte (bit 7 set when aligned), the +/// payload length, then for an aligned section the alignment and padding +/// relative to the whole file, then the payload. +pub fn write_section(out: &mut Vec, section: Section, payload: &[u8], alignment: usize) { + let mut id = section as u8; + if alignment > 1 { + id |= 0x80; + } + let mut header = Writer::new(); + header.byte(id); + header.varint(payload.len() as u64); + if alignment > 1 { + header.varint(alignment as u64); + } + out.extend_from_slice(&header.into_bytes()); + if alignment > 1 { + while !out.len().is_multiple_of(alignment) { + out.push(ALIGNMENT_BYTE); + } + } + out.extend_from_slice(payload); +} + +/// Write `count`, align to four, reserve `count` little-endian `u32` offset +/// slots and return the position of the first one. Tables of strings, types +/// and debug entries all start this way. +pub fn begin_offset_table(w: &mut Writer, count: usize) -> usize { + w.varint(count as u64); + w.align_to(4); + let first = w.len(); + for _ in 0..count { + w.le_u32(0); + } + first +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn varints_follow_leb128() { + let mut w = Writer::new(); + w.varint(0); + w.varint(127); + w.varint(128); + w.varint(0xD2); + w.varint(300); + assert_eq!( + w.into_bytes(), + [0x00, 0x7F, 0x80, 0x01, 0xD2, 0x01, 0xAC, 0x02] + ); + } + + #[test] + fn signed_varints_are_zigzag() { + let mut w = Writer::new(); + w.signed_varint(0); + w.signed_varint(1); + w.signed_varint(-1); + w.signed_varint(128); + assert_eq!(w.into_bytes(), [0x00, 0x02, 0x01, 0x80, 0x02]); + } + + #[test] + fn aligned_sections_pad_relative_to_the_file() { + let mut out = MAGIC.to_vec(); + out.extend_from_slice(&[13, 5, 1, 0]); + write_section(&mut out, Section::Func, &[0xAA; 3], 8); + // id, length, alignment at 12..15, then padding to 16. + assert_eq!(&out[12..16], &[0x82, 0x03, 0x08, ALIGNMENT_BYTE]); + assert_eq!(&out[16..19], &[0xAA; 3]); + write_section(&mut out, Section::EndOfBytecode, &[], 1); + assert_eq!(out.last(), Some(&0x00)); + } +} diff --git a/cuda-oxide/crates/oxide-tilebc/src/lib.rs b/cuda-oxide/crates/oxide-tilebc/src/lib.rs new file mode 100644 index 0000000000..3d9300e197 --- /dev/null +++ b/cuda-oxide/crates/oxide-tilebc/src/lib.rs @@ -0,0 +1,358 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +//! Tile IR bytecode for the tile libraries cuda-oxide ships. +//! +//! A tile library lets a Tile kernel call a SIMT function. cuda-oxide is the +//! SIMT provider: it compiles the function to LTOIR and describes it twice, +//! once as the declaration a Tile kernel calls (the interface) and once as +//! the native symbol with the fragment each parameter receives (the +//! implementation). `tileiras --preview-create-tile-lib` packs the three into +//! one `.tilelib`. This crate writes the two descriptions. +//! +//! ```text +//! Library { declarations, implementations } +//! |-- interface_bytecode(version) -> .iface.tilebc +//! |-- implementation_bytecode(version) -> .impl.tilebc +//! `-- interface_text(), implementation_text() readable form +//! ``` +//! +//! The descriptions are public-preview content (Tile IR 13.5 and newer). +//! An assembler reads such content only at the version it calls current, +//! the newest numbered version its `--list-versions` prints, so the caller +//! passes that version; [`BytecodeVersion::parse`] reads the listing. +//! +//! ``` +//! use oxide_tilebc::*; +//! +//! let tile = TileType::new(vec![128], ScalarType::F32); +//! let decl = Declaration::new("relu", vec![ +//! TileArg::new("x", tile.clone(), Access::In), +//! TileArg::new("relu_out", tile, Access::Out), +//! ]); +//! let by_value = FragmentType::new(vec![1], ScalarType::F32, MemorySpace::Local, +//! Layout::scalar_mem(), Layout::elementwise(128)); +//! let by_pointer = FragmentType::new(vec![1], ScalarType::F32, MemorySpace::Local, +//! Layout::contiguous_mem(1), Layout::elementwise(128)); +//! let imp = Implementation::new("relu_impl", "relu", vec![ +//! FragmentArg::new("x", by_value, Access::In), +//! FragmentArg::new("relu_out", by_pointer, Access::Out), +//! ]); +//! let library = Library::new("relu", vec![decl], vec![imp]); +//! library.verify().unwrap(); +//! let interface = library.interface_bytecode(BytecodeVersion::PREVIEW_FIRST).unwrap(); +//! assert_eq!(&interface[8..12], &[13, 5, 1, 0]); +//! ``` + +mod encoding; +mod model; +mod text; +mod verify; +mod writer; + +pub use model::{ + Access, BytecodeVersion, Declaration, FragmentArg, FragmentType, Implementation, Layout, + Library, MemorySpace, ScalarType, Synchronization, TileArg, TileType, +}; + +/// What can go wrong when describing a library. +#[derive(Debug, thiserror::Error, PartialEq, Eq)] +pub enum Error { + /// The library breaks a structural rule; the message names the part. + #[error("{0}")] + Verify(String), + /// Preview content needs bytecode 13.5 or newer. + #[error("bytecode version {0} is older than 13.5, the first with public-preview content")] + Version(BytecodeVersion), +} + +#[cfg(test)] +mod tests { + use super::*; + + /// `(section id, payload)` in file order, with the framing checked. + fn sections(bytes: &[u8]) -> Vec<(u8, Vec)> { + assert_eq!(&bytes[..8], b"\x7fTileIR\0"); + let mut pos = 12; + let mut out = Vec::new(); + loop { + let id_byte = bytes[pos]; + pos += 1; + if id_byte & 0x7F == 0 { + assert_eq!(pos, bytes.len()); + return out; + } + let len = read_varint(bytes, &mut pos) as usize; + if id_byte & 0x80 != 0 { + let alignment = read_varint(bytes, &mut pos) as usize; + while pos % alignment != 0 { + assert_eq!(bytes[pos], 0xCB); + pos += 1; + } + } + out.push((id_byte & 0x7F, bytes[pos..pos + len].to_vec())); + pos += len; + } + } + + fn read_varint(bytes: &[u8], pos: &mut usize) -> u64 { + let mut value = 0u64; + let mut shift = 0; + loop { + let byte = bytes[*pos]; + *pos += 1; + value |= u64::from(byte & 0x7F) << shift; + if byte & 0x80 == 0 { + return value; + } + shift += 7; + } + } + + fn section(bytes: &[u8], id: u8) -> Vec { + sections(bytes) + .into_iter() + .find(|(s, _)| *s == id) + .map(|(_, payload)| payload) + .unwrap_or_else(|| panic!("no section {id}")) + } + + fn strings(bytes: &[u8]) -> Vec { + let payload = section(bytes, 1); + let mut pos = 0; + let count = read_varint(&payload, &mut pos) as usize; + while pos % 4 != 0 { + pos += 1; + } + let offsets: Vec = (0..count) + .map(|i| { + u32::from_le_bytes(payload[pos + 4 * i..pos + 4 * i + 4].try_into().unwrap()) + as usize + }) + .collect(); + let data = &payload[pos + 4 * count..]; + (0..count) + .map(|i| { + let end = offsets.get(i + 1).copied().unwrap_or(data.len()); + String::from_utf8(data[offsets[i]..end].to_vec()).unwrap() + }) + .collect() + } + + fn index(table: &[String], text: &str) -> u8 { + u8::try_from(table.iter().position(|t| t == text).expect(text)).unwrap() + } + + fn tile() -> TileType { + TileType::new(vec![128], ScalarType::F32) + } + + fn scale_library() -> Library { + let decl = Declaration::new( + "tilelib_scale", + vec![TileArg::new("arg0", tile(), Access::InOut)], + ); + let fragment = FragmentType::new( + vec![1], + ScalarType::F32, + MemorySpace::Local, + Layout::contiguous_mem(1), + Layout::elementwise(128), + ); + let imp = Implementation::new( + "tilelib_scale_impl", + "tilelib_scale", + vec![FragmentArg::new("arg0", fragment, Access::InOut)], + ); + Library::new("tilelib", vec![decl], vec![imp]) + } + + #[test] + fn header_carries_the_version_and_the_preview_tag() { + let lib = scale_library(); + let bytes = lib.interface_bytecode(BytecodeVersion::new(13, 6)).unwrap(); + assert_eq!(&bytes[8..12], &[13, 6, 1, 0]); + assert_eq!( + lib.interface_bytecode(BytecodeVersion::new(13, 4)), + Err(Error::Version(BytecodeVersion::new(13, 4))) + ); + let ids: Vec = sections(&bytes).into_iter().map(|(id, _)| id).collect(); + assert_eq!(ids, [2, 3, 5, 1], "function, debug, type, string"); + } + + /// Extern declaration: normal form, private, body length 0, then the + /// empty constant parameters. The upstream fixture `tilelib_interface`. + #[test] + fn declaration_entry_layout() { + let bytes = scale_library() + .interface_bytecode(BytecodeVersion::PREVIEW_FIRST) + .unwrap(); + let table = strings(&bytes); + let name = index(&table, "tilelib_scale"); + let access = index(&table, "cuda_tile.preview$access"); + assert_eq!( + section(&bytes, 2), + vec![ + 0x01, name, 0x02, // one function, name, signature type index + 0x01, // flags: private, not a kernel, normal form + 0x01, // debug list index + 0x06, 0x01, 0x0A, 0x01, access, 0xDF, 0x01, + 0x02, // arg_attrs: [{access = inout}] + 0x00, // body length 0: a declaration + 0x06, 0x00, // const_params: empty array + ] + ); + // Types: f32, tile<128xf32>, then (tile) -> (tile). + let types = section(&bytes, 5); + let mut pos = 0; + assert_eq!(read_varint(&types, &mut pos), 3); + let entries = &types[4 + 4 * 3..]; + assert_eq!(entries[0], 0x07, "f32"); + assert_eq!( + &entries[1..12], + &[0x0D, 0x00, 0x01, 128, 0, 0, 0, 0, 0, 0, 0], + "tile<128xf32>" + ); + assert_eq!( + &entries[12..], + &[0x10, 0x01, 0x01, 0x01, 0x01], + "(tile) -> (tile)" + ); + } + + /// Implementation: form bits 01, private, the op payload in place of a + /// body, body length 0. The upstream fixture `tilelib_implementation`. + #[test] + fn implementation_entry_layout() { + let lib = scale_library(); + let bytes = lib + .implementation_bytecode(BytecodeVersion::PREVIEW_FIRST) + .unwrap(); + let table = strings(&bytes); + let symbol = index(&table, "tilelib_scale_impl"); + let implements = index(&table, "tilelib_scale"); + let access = index(&table, "cuda_tile.preview$access"); + let mut expected = vec![ + 0x01, symbol, 0x02, // one function, symbol, signature type index + 0x05, // flags: private, form extern_impl + 0x01, // debug list index + 0x04, // payload flags: arg_attrs only + symbol, implements, // sym_name, implements + 0x02, // function_type index + 0x01, 0x0A, 0x01, access, 0xDF, 0x01, + 0x02, // arg_attrs inline: [{access = inout}] + 0x01, 0x00, // one region, zero blocks + 0x00, // body length 0 + ]; + expected.resize(24, 0xCB); + assert_eq!(section(&bytes, 2), expected); + + // The fragment type entry: tagged empty symbolic shape, static shape + // [1], element f32 (index 0), local, (1):(1), (128, 1, 1):(1, 0, 0), + // alignment 1. + let types = section(&bytes, 5); + let entries = &types[4 + 4 * 3..]; + assert_eq!( + &entries[1..], + &[ + 0xD2, 0x01, 0xD8, 0x01, 0x00, 0x01, 1, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x00, // + 0xD9, 0x01, 0x01, 0xD1, 0x01, 0x02, 0x01, 0xD1, 0x01, 0x02, // + 0xD9, 0x01, 0x03, 0xD1, 0x01, 0x80, 0x02, 0xD1, 0x01, 0x02, 0xD1, 0x01, + 0x02, // + 0x03, 0xD1, 0x01, 0x02, 0xD1, 0x01, 0x00, 0xD1, 0x01, 0x00, // + 0xD1, 0x01, 0x02, // + 0x10, 0x01, 0x01, 0x00, // (fragment) -> () + ] + ); + } + + /// A warp-synchronous implementation sets bit 8 and writes the value + /// after the argument attributes; arch and frontendABI take bits 6 and 7. + #[test] + fn optional_clauses_set_their_flag_bits() { + let mut lib = scale_library(); + let imp = &mut lib.implementations[0]; + imp.args[0].fragment.fragmap = Layout::warp_lanes(128); + imp.synchronization = Some(Synchronization::Warp); + imp.arch = vec!["sm_120".into()]; + imp.frontend_abi = vec![("bf16".into(), "i16".into())]; + lib.verify().unwrap(); + let bytes = lib + .implementation_bytecode(BytecodeVersion::PREVIEW_FIRST) + .unwrap(); + let table = strings(&bytes); + let func = section(&bytes, 2); + // flags = bits 2, 6, 7, 8 = 0x1C4 -> varint C4 03 + assert_eq!(&func[5..7], &[0xC4, 0x03]); + let after_attrs = 7 + 3 + 7; + assert_eq!( + &func[after_attrs..after_attrs + 10], + &[ + 0x01, + 0x05, + index(&table, "sm_120"), // arch: one tagged string + 0x01, + index(&table, "bf16"), + 0x05, + index(&table, "i16"), // frontendABI + 0x01, // synchronization = warp + 0x01, + 0x00, // region + ] + ); + } + + #[test] + fn debug_section_holds_one_unknown_location_per_function() { + let bytes = scale_library() + .interface_bytecode(BytecodeVersion::PREVIEW_FIRST) + .unwrap(); + assert_eq!( + section(&bytes, 3), + vec![ + 0x01, 0xCB, 0xCB, 0xCB, // one function, aligned + 0, 0, 0, 0, // its id list starts at 0 + 0x01, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, // one id, aligned to 8 + 0, 0, 0, 0, 0, 0, 0, 0, // id 0: unknown location + 0x01, 0xCB, 0xCB, 0xCB, // one attribute entry + 0, 0, 0, 0, // at offset 0 + 0x00, // tag 0: unknown + ] + ); + } + + #[test] + fn text_matches_the_reference_form() { + let lib = scale_library(); + assert_eq!( + lib.interface_text(), + "cuda_tile.module @tilelib {\n cuda_tile.preview$func extern @tilelib_scale(%arg0: \ + !cuda_tile.tile<128xf32> {cuda_tile.preview$access = #cuda_tile.preview$access}) \ + -> !cuda_tile.tile<128xf32>\n}\n" + ); + assert!(lib.implementation_text().contains( + "@tilelib_scale_impl implements @tilelib_scale(%arg0: !cuda_tile.preview$fragment<1xf32, \ + local, mem_layout = #cuda_tile.preview$layout<(1):(1)>, fragmap = \ + #cuda_tile.preview$layout<(128, 1, 1):(1, 0, 0)>> {cuda_tile.preview$access = \ + #cuda_tile.preview$access})\n" + )); + } + + #[test] + fn versions_parse_from_the_assembler_listing() { + assert_eq!( + BytecodeVersion::parse("13.5"), + Some(BytecodeVersion::new(13, 5)) + ); + assert_eq!( + BytecodeVersion::parse(" 13.6.1 "), + Some(BytecodeVersion::new(13, 6)) + ); + assert_eq!(BytecodeVersion::parse("internal"), None); + assert_eq!(BytecodeVersion::parse("13"), None); + assert!(BytecodeVersion::new(13, 6) > BytecodeVersion::PREVIEW_FIRST); + assert_eq!(BytecodeVersion::new(13, 6).to_string(), "13.6"); + } +} diff --git a/cuda-oxide/crates/oxide-tilebc/src/model.rs b/cuda-oxide/crates/oxide-tilebc/src/model.rs new file mode 100644 index 0000000000..d6ef3991fc --- /dev/null +++ b/cuda-oxide/crates/oxide-tilebc/src/model.rs @@ -0,0 +1,465 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +//! The vocabulary of a tile library description: the tiles a declaration +//! takes, the fragments an implementation receives, and the clauses that +//! tell the Tile compiler how to call the native function. + +use std::fmt; + +/// A Tile IR bytecode version (`major.minor`). The header tag bits are not +/// part of a version. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct BytecodeVersion { + /// Major version, 13 for every Tile IR release so far. + pub major: u8, + /// Minor version. + pub minor: u8, +} + +impl BytecodeVersion { + /// The first version with public-preview content, and the version the + /// descriptions are written at when no assembler can be asked. + pub const PREVIEW_FIRST: Self = Self { + major: 13, + minor: 5, + }; + + /// A version from its two numbers. + pub const fn new(major: u8, minor: u8) -> Self { + Self { major, minor } + } + + /// Parse one line of `tileiras --list-versions`: `13.5` or `13.5.1` + /// (the header tag is ignored). Lines that are not versions, such as a + /// named build an assembler may list, give `None`. + pub fn parse(text: &str) -> Option { + let mut parts = text.trim().split('.'); + let major = parts.next()?.parse().ok()?; + let minor = parts.next()?.parse().ok()?; + if let Some(tag) = parts.next() { + tag.parse::().ok()?; + } + if parts.next().is_some() { + return None; + } + Some(Self { major, minor }) + } +} + +impl fmt::Display for BytecodeVersion { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}.{}", self.major, self.minor) + } +} + +/// Element types a description can name. Tile IR has no unsigned integers: +/// the unsigned Rust types are the signless `iN` of the same width. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum ScalarType { + /// `f16` + F16, + /// `bf16` + BF16, + /// `f32` + F32, + /// `f64` + F64, + /// `i8` + I8, + /// `i16` + I16, + /// `i32` + I32, + /// `i64` + I64, +} + +impl ScalarType { + /// The type-table tag. + pub(crate) fn tag(self) -> u8 { + match self { + Self::I8 => 1, + Self::I16 => 2, + Self::I32 => 3, + Self::I64 => 4, + Self::F16 => 5, + Self::BF16 => 6, + Self::F32 => 7, + Self::F64 => 9, + } + } + + /// The textual name. + pub fn name(self) -> &'static str { + match self { + Self::F16 => "f16", + Self::BF16 => "bf16", + Self::F32 => "f32", + Self::F64 => "f64", + Self::I8 => "i8", + Self::I16 => "i16", + Self::I32 => "i32", + Self::I64 => "i64", + } + } +} + +/// A concrete tile type, the value a declaration argument carries. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct TileType { + /// Extents, one per dimension. + pub shape: Vec, + /// Element type. + pub element: ScalarType, +} + +impl TileType { + /// A tile of `shape` by `element`. + pub fn new(shape: Vec, element: ScalarType) -> Self { + Self { shape, element } + } + + /// Number of elements. + pub fn size(&self) -> i64 { + self.shape.iter().product() + } +} + +/// How a callee uses an argument. `out` and `inout` arguments are also the +/// declaration's results, in argument order. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Access { + /// Read only. + In, + /// Written, not read. + Out, + /// Read and written. + InOut, +} + +impl Access { + /// The bytecode value. + pub(crate) fn value(self) -> u64 { + match self { + Self::In => 0, + Self::Out => 1, + Self::InOut => 2, + } + } + + /// The textual name. + pub fn name(self) -> &'static str { + match self { + Self::In => "in", + Self::Out => "out", + Self::InOut => "inout", + } + } + + /// Whether the callee writes the argument. + pub fn is_written(self) -> bool { + !matches!(self, Self::In) + } +} + +/// Where a fragment's buffer lives. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum MemorySpace { + /// Per-thread storage. + Local, + /// CTA shared memory. + Smem, +} + +impl MemorySpace { + pub(crate) fn value(self) -> u64 { + match self { + Self::Local => 0, + Self::Smem => 1, + } + } + + /// The textual name. + pub fn name(self) -> &'static str { + match self { + Self::Local => "local", + Self::Smem => "smem", + } + } +} + +/// The threads that call the native function together. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Synchronization { + /// One thread per invocation. + None, + /// The 32 lanes of a warp. + Warp, + /// Four warps. + Warpgroup, + /// The whole CTA. + Cta, +} + +impl Synchronization { + pub(crate) fn value(self) -> u64 { + match self { + Self::None => 0, + Self::Warp => 1, + Self::Warpgroup => 2, + Self::Cta => 3, + } + } + + /// The textual name. + pub fn name(self) -> &'static str { + match self { + Self::None => "none", + Self::Warp => "warp", + Self::Warpgroup => "warpgroup", + Self::Cta => "cta", + } + } + + /// How many threads one invocation spans. + pub fn participants(self) -> i64 { + match self { + Self::None => 1, + Self::Warp => 32, + Self::Warpgroup => 128, + Self::Cta => 0, + } + } +} + +/// A concrete layout: `(shapes):(strides)`, integers only. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Layout { + /// Mode extents. + pub shapes: Vec, + /// Mode strides. + pub strides: Vec, +} + +impl Layout { + /// A layout from its shapes and strides. + pub fn flat(shapes: &[i64], strides: &[i64]) -> Self { + Self { + shapes: shapes.to_vec(), + strides: strides.to_vec(), + } + } + + /// The rank-0 buffer layout `():()` of a scalar passed by value. + pub fn scalar_mem() -> Self { + Self::flat(&[], &[]) + } + + /// The buffer layout `(F):(1)` of `footprint` contiguous elements. + pub fn contiguous_mem(footprint: i64) -> Self { + Self::flat(&[footprint], &[1]) + } + + /// One invocation per element, no participants: `(N, 1, 1):(1, 0, 0)`. + pub fn elementwise(tile_size: i64) -> Self { + Self::flat(&[tile_size, 1, 1], &[1, 0, 0]) + } + + /// Warp-synchronous, one element per lane: `(N/32, 32, 1):(32, 1, 0)`. + pub fn warp_lanes(tile_size: i64) -> Self { + Self::flat(&[tile_size / 32, 32, 1], &[32, 1, 0]) + } + + /// One invocation per block of `footprint` contiguous elements: + /// `(N/F, 1, F):(F, 0, 1)`. + pub fn footprint_blocks(tile_size: i64, footprint: i64) -> Self { + Self::flat(&[tile_size / footprint, 1, footprint], &[footprint, 0, 1]) + } + + /// Number of dimensions. + pub fn rank(&self) -> usize { + self.shapes.len() + } + + /// Product of the shapes. + pub fn size(&self) -> i64 { + self.shapes.iter().product() + } +} + +/// The fragment the native function receives for one declaration argument. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct FragmentType { + /// Elements one invocation owns (its footprint), one extent per dimension. + pub shape: Vec, + /// Element type. + pub element: ScalarType, + /// Where the buffer lives. + pub memory_space: MemorySpace, + /// How the footprint sits in the buffer; rank 0 means passed by value. + pub mem_layout: Layout, + /// `(invocations, participants, footprint):(strides)` onto the tile. + pub fragmap: Layout, +} + +impl FragmentType { + /// A fragment from its parts. The alignment the bytecode carries is + /// always the default of one. + pub fn new( + shape: Vec, + element: ScalarType, + memory_space: MemorySpace, + mem_layout: Layout, + fragmap: Layout, + ) -> Self { + Self { + shape, + element, + memory_space, + mem_layout, + fragmap, + } + } + + /// Elements per invocation. + pub fn footprint(&self) -> i64 { + self.shape.iter().product() + } +} + +/// One argument of a declaration. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct TileArg { + /// Argument name, printed as `%name`. + pub name: String, + /// The tile at the call boundary. + pub ty: TileType, + /// How the callee uses it. + pub access: Access, +} + +impl TileArg { + /// An argument from its parts. + pub fn new(name: impl Into, ty: TileType, access: Access) -> Self { + Self { + name: name.into(), + ty, + access, + } + } +} + +/// One argument of an implementation. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct FragmentArg { + /// Argument name, printed as `%name`. + pub name: String, + /// The fragment the native function receives. + pub fragment: FragmentType, + /// Must equal the access of the matching declaration argument. + pub access: Access, +} + +impl FragmentArg { + /// An argument from its parts. + pub fn new(name: impl Into, fragment: FragmentType, access: Access) -> Self { + Self { + name: name.into(), + fragment, + access, + } + } +} + +/// An extern declaration: what a Tile kernel can call. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Declaration { + /// The symbol a `preview$call` names. + pub name: String, + /// Arguments in order; at least one. + pub args: Vec, +} + +impl Declaration { + /// A declaration from its name and arguments. + pub fn new(name: impl Into, args: Vec) -> Self { + Self { + name: name.into(), + args, + } + } + + /// The tiles the declaration returns: its written arguments, in order. + pub fn results(&self) -> impl Iterator { + self.args + .iter() + .filter(|arg| arg.access.is_written()) + .map(|arg| &arg.ty) + } +} + +/// An implementation: the native symbol the code payload defines and how +/// its parameters map onto a declaration's tiles. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Implementation { + /// The linked symbol. + pub symbol: String, + /// The declaration this implements. + pub implements: String, + /// One fragment per declaration argument, in order. + pub args: Vec, + /// The `synchronization` clause; `None` leaves the clause out, which + /// means one thread per invocation. + pub synchronization: Option, + /// Target names such as `sm_120`; empty matches every target. + pub arch: Vec, + /// `frontendABI` entries: printed type to native type. + pub frontend_abi: Vec<(String, String)>, +} + +impl Implementation { + /// An implementation with no optional clauses. + pub fn new( + symbol: impl Into, + implements: impl Into, + args: Vec, + ) -> Self { + Self { + symbol: symbol.into(), + implements: implements.into(), + args, + synchronization: None, + arch: Vec::new(), + frontend_abi: Vec::new(), + } + } +} + +/// A tile library's two halves, under one module name. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Library { + /// The `cuda_tile.module` name of both halves. + pub name: String, + /// The interface: what can be called. + pub declarations: Vec, + /// The catalog: how each declaration is implemented. + pub implementations: Vec, +} + +impl Library { + /// A library from its parts. + pub fn new( + name: impl Into, + declarations: Vec, + implementations: Vec, + ) -> Self { + Self { + name: name.into(), + declarations, + implementations, + } + } +} diff --git a/cuda-oxide/crates/oxide-tilebc/src/text.rs b/cuda-oxide/crates/oxide-tilebc/src/text.rs new file mode 100644 index 0000000000..32073f2b6e --- /dev/null +++ b/cuda-oxide/crates/oxide-tilebc/src/text.rs @@ -0,0 +1,134 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +//! The readable form of a library: the Tile IR textual syntax of both +//! modules, as the reference tools print it. It is written next to the +//! bytecode so a reader can see what the assembler will read. + +use std::fmt::Write as _; + +use crate::model::{Declaration, FragmentType, Implementation, Layout, Library, TileType}; + +fn layout(layout: &Layout) -> String { + let list = |values: &[i64]| { + values + .iter() + .map(|v| v.to_string()) + .collect::>() + .join(", ") + }; + format!( + "#cuda_tile.preview$layout<({}):({})>", + list(&layout.shapes), + list(&layout.strides) + ) +} + +fn tile(ty: &TileType) -> String { + let dims: Vec = ty.shape.iter().map(|d| d.to_string()).collect(); + format!("!cuda_tile.tile<{}x{}>", dims.join("x"), ty.element.name()) +} + +fn fragment(ty: &FragmentType) -> String { + let dims: Vec = ty.shape.iter().map(|d| d.to_string()).collect(); + format!( + "!cuda_tile.preview$fragment<{}x{}, {}, mem_layout = {}, fragmap = {}>", + dims.join("x"), + ty.element.name(), + ty.memory_space.name(), + layout(&ty.mem_layout), + layout(&ty.fragmap) + ) +} + +fn access(access: crate::model::Access) -> String { + format!( + "{{cuda_tile.preview$access = #cuda_tile.preview$access<{}>}}", + access.name() + ) +} + +fn declaration(decl: &Declaration) -> String { + let args: Vec = decl + .args + .iter() + .map(|arg| format!("%{}: {} {}", arg.name, tile(&arg.ty), access(arg.access))) + .collect(); + let results: Vec = decl.results().map(tile).collect(); + let results = match results.len() { + 1 => results[0].clone(), + _ => format!("({})", results.join(", ")), + }; + format!( + " cuda_tile.preview$func extern @{}({}) -> {}\n", + decl.name, + args.join(", "), + results + ) +} + +fn implementation(imp: &Implementation) -> String { + let args: Vec = imp + .args + .iter() + .map(|arg| { + format!( + "%{}: {} {}", + arg.name, + fragment(&arg.fragment), + access(arg.access) + ) + }) + .collect(); + let mut text = format!( + " cuda_tile.preview$extern_impl @{} implements @{}({})", + imp.symbol, + imp.implements, + args.join(", ") + ); + if let Some(sync) = imp.synchronization { + let _ = write!( + text, + "\n synchronization = #cuda_tile.preview$synchronization<{}>", + sync.name() + ); + } + if !imp.arch.is_empty() { + let names: Vec = imp.arch.iter().map(|name| format!("\"{name}\"")).collect(); + let _ = write!(text, "\n arch = [{}]", names.join(", ")); + } + if !imp.frontend_abi.is_empty() { + let entries: Vec = imp + .frontend_abi + .iter() + .map(|(key, value)| format!("{key} = \"{value}\"")) + .collect(); + let _ = write!(text, "\n {{frontendABI = {{{}}}}}", entries.join(", ")); + } + text.push('\n'); + text +} + +impl Library { + /// The interface module in textual Tile IR. + pub fn interface_text(&self) -> String { + let mut text = format!("cuda_tile.module @{} {{\n", self.name); + for decl in &self.declarations { + text.push_str(&declaration(decl)); + } + text.push_str("}\n"); + text + } + + /// The implementation module in textual Tile IR. + pub fn implementation_text(&self) -> String { + let mut text = format!("cuda_tile.module @{} {{\n", self.name); + for imp in &self.implementations { + text.push_str(&implementation(imp)); + } + text.push_str("}\n"); + text + } +} diff --git a/cuda-oxide/crates/oxide-tilebc/src/verify.rs b/cuda-oxide/crates/oxide-tilebc/src/verify.rs new file mode 100644 index 0000000000..3cc124448b --- /dev/null +++ b/cuda-oxide/crates/oxide-tilebc/src/verify.rs @@ -0,0 +1,360 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +//! The structural rules the Tile compiler's verifier applies when a library's +//! two halves meet, checked here before any bytecode is written so a mistake +//! is reported in terms of the description rather than of a deserialized +//! module. + +use std::collections::HashSet; + +use crate::Error; +use crate::model::{Access, Declaration, FragmentArg, Implementation, Library, MemorySpace}; + +fn is_identifier(text: &str) -> bool { + let mut chars = text.chars(); + matches!(chars.next(), Some(c) if c == '_' || c.is_ascii_alphabetic()) + && chars.all(|c| c == '_' || c.is_ascii_alphanumeric()) +} + +impl Library { + /// Check the library against the rules below; the first violation is + /// the error. + /// + /// - names are identifiers, unique among declarations and among symbols; + /// - a declaration has at least one argument, one dimension per tile, + /// and its written arguments form one contiguous run (the native + /// implementation path needs destination-passing results in order); + /// - every implementation names a declaration, with one fragment per + /// argument, the same access and element type; + /// - a fragment covers the tile: invocations times participants times + /// footprint equals the tile size, the footprint equals the fragment's + /// shape, a rank-0 buffer layout only for a read-only local fragment; + /// - the participants of every fragmap equal what the synchronization + /// clause promises (1 without a clause, 32 for a warp). + pub fn verify(&self) -> Result<(), Error> { + if !is_identifier(&self.name) { + return Err(Error::Verify(format!( + "module name `{}` is not an identifier", + self.name + ))); + } + let mut names = HashSet::new(); + for decl in &self.declarations { + verify_declaration(decl)?; + if !names.insert(decl.name.as_str()) { + return Err(Error::Verify(format!( + "declaration @{} appears twice", + decl.name + ))); + } + } + let mut symbols = HashSet::new(); + for imp in &self.implementations { + if !symbols.insert(imp.symbol.as_str()) { + return Err(Error::Verify(format!( + "implementation @{} appears twice", + imp.symbol + ))); + } + let decl = self + .declarations + .iter() + .find(|decl| decl.name == imp.implements) + .ok_or_else(|| { + Error::Verify(format!( + "implementation @{} implements @{}, which the interface does not declare", + imp.symbol, imp.implements + )) + })?; + verify_implementation(imp, decl)?; + } + Ok(()) + } +} + +fn verify_declaration(decl: &Declaration) -> Result<(), Error> { + let at = |message: String| Error::Verify(format!("declaration @{}: {message}", decl.name)); + if !is_identifier(&decl.name) { + return Err(Error::Verify(format!( + "declaration name `{}` is not an identifier", + decl.name + ))); + } + if decl.args.is_empty() { + return Err(at("a declaration needs at least one argument".into())); + } + let mut seen = HashSet::new(); + for arg in &decl.args { + if !is_identifier(&arg.name) { + return Err(at(format!( + "argument name `{}` is not an identifier", + arg.name + ))); + } + if !seen.insert(arg.name.as_str()) { + return Err(at(format!("argument `{}` appears twice", arg.name))); + } + if arg.ty.shape.len() != 1 { + return Err(at(format!( + "argument `{}` has {} dimensions; this writer emits one-dimensional tiles", + arg.name, + arg.ty.shape.len() + ))); + } + if arg.ty.shape[0] <= 0 { + return Err(at(format!( + "argument `{}` has a non-positive extent", + arg.name + ))); + } + } + let written: Vec = decl + .args + .iter() + .enumerate() + .filter(|(_, arg)| arg.access.is_written()) + .map(|(i, _)| i) + .collect(); + if written.is_empty() { + return Err(at( + "no argument is written; a declaration's results are its out and inout arguments" + .into(), + )); + } + if written.last().unwrap() - written[0] + 1 != written.len() { + return Err(at(format!( + "written arguments must form one contiguous run; `{}` sits between them", + decl.args[written[0] + 1..*written.last().unwrap()] + .iter() + .find(|arg| !arg.access.is_written()) + .map(|arg| arg.name.as_str()) + .unwrap_or("?") + ))); + } + Ok(()) +} + +fn verify_implementation(imp: &Implementation, decl: &Declaration) -> Result<(), Error> { + let at = |message: String| Error::Verify(format!("implementation @{}: {message}", imp.symbol)); + if !is_identifier(&imp.symbol) { + return Err(Error::Verify(format!( + "implementation symbol `{}` is not an identifier", + imp.symbol + ))); + } + if imp.args.len() != decl.args.len() { + return Err(at(format!( + "{} fragment arguments for the {} arguments of @{}", + imp.args.len(), + decl.args.len(), + decl.name + ))); + } + let participants = imp.synchronization.map_or(1, |sync| sync.participants()); + for (arg, decl_arg) in imp.args.iter().zip(&decl.args) { + verify_fragment(arg, decl_arg.ty.size(), decl_arg.ty.element, participants) + .map_err(|message| at(format!("argument `{}`: {message}", arg.name)))?; + if arg.access != decl_arg.access { + return Err(at(format!( + "argument `{}` is `{}` but the declaration says `{}`", + arg.name, + arg.access.name(), + decl_arg.access.name() + ))); + } + } + for name in &imp.arch { + if name.is_empty() { + return Err(at("an empty arch name".into())); + } + } + Ok(()) +} + +fn verify_fragment( + arg: &FragmentArg, + tile_size: i64, + element: crate::model::ScalarType, + participants: i64, +) -> Result<(), String> { + let fragment = &arg.fragment; + if fragment.element != element { + return Err(format!( + "fragment element type {} differs from the tile element type {}", + fragment.element.name(), + element.name() + )); + } + if fragment.shape.is_empty() || fragment.shape.iter().any(|d| *d <= 0) { + return Err("fragment shape must have positive extents".into()); + } + let footprint = fragment.footprint(); + let fragmap = &fragment.fragmap; + if fragmap.rank() != 3 || fragmap.strides.len() != 3 { + return Err(format!( + "fragmap must have three modes (invocations, participants, footprint), found {}", + fragmap.rank() + )); + } + if fragmap.shapes[2] != footprint { + return Err(format!( + "fragmap footprint {} differs from the fragment's {} elements", + fragmap.shapes[2], footprint + )); + } + if fragmap.size() != tile_size { + return Err(format!( + "fragmap covers {} elements of a {tile_size}-element tile", + fragmap.size() + )); + } + if participants != 0 && fragmap.shapes[1] != participants { + return Err(format!( + "fragmap has {} participants but the synchronization clause promises {participants}", + fragmap.shapes[1] + )); + } + let mem = &fragment.mem_layout; + if mem.shapes.len() != mem.strides.len() { + return Err("mem_layout shapes and strides differ in length".into()); + } + if mem.rank() == 0 { + if footprint != 1 { + return Err("a rank-0 mem_layout needs a one-element footprint".into()); + } + if arg.access != Access::In || fragment.memory_space != MemorySpace::Local { + return Err( + "a rank-0 mem_layout (passed by value) is only valid for a read-only local fragment" + .into(), + ); + } + } else if mem.size() != footprint { + return Err(format!( + "mem_layout spans {} elements but the footprint is {footprint}", + mem.size() + )); + } + Ok(()) +} + +#[cfg(test)] +mod tests { + use crate::model::*; + + fn tile() -> TileType { + TileType::new(vec![128], ScalarType::F32) + } + + fn scalar_fragment() -> FragmentType { + FragmentType::new( + vec![1], + ScalarType::F32, + MemorySpace::Local, + Layout::scalar_mem(), + Layout::elementwise(128), + ) + } + + fn pointer_fragment() -> FragmentType { + FragmentType::new( + vec![1], + ScalarType::F32, + MemorySpace::Local, + Layout::contiguous_mem(1), + Layout::elementwise(128), + ) + } + + fn relu() -> Library { + Library::new( + "lib", + vec![Declaration::new( + "relu", + vec![ + TileArg::new("x", tile(), Access::In), + TileArg::new("relu_out", tile(), Access::Out), + ], + )], + vec![Implementation::new( + "relu_impl", + "relu", + vec![ + FragmentArg::new("x", scalar_fragment(), Access::In), + FragmentArg::new("relu_out", pointer_fragment(), Access::Out), + ], + )], + ) + } + + #[test] + fn the_relu_library_verifies() { + relu().verify().unwrap(); + } + + #[test] + fn written_arguments_must_be_contiguous() { + let mut lib = relu(); + lib.declarations[0] + .args + .push(TileArg::new("y", tile(), Access::In)); + lib.declarations[0] + .args + .push(TileArg::new("z", tile(), Access::Out)); + let error = lib.verify().unwrap_err().to_string(); + assert!( + error.contains("contiguous run") && error.contains("`y`"), + "{error}" + ); + } + + #[test] + fn an_implementation_needs_its_declaration() { + let mut lib = relu(); + lib.implementations[0].implements = "gelu".into(); + let error = lib.verify().unwrap_err().to_string(); + assert!(error.contains("does not declare"), "{error}"); + } + + #[test] + fn access_and_coverage_are_checked() { + let mut lib = relu(); + lib.implementations[0].args[1].access = Access::InOut; + assert!( + lib.verify() + .unwrap_err() + .to_string() + .contains("`relu_out` is `inout`") + ); + + let mut lib = relu(); + lib.implementations[0].args[1].fragment.fragmap = Layout::elementwise(64); + assert!( + lib.verify() + .unwrap_err() + .to_string() + .contains("covers 64 elements") + ); + + let mut lib = relu(); + lib.implementations[0].synchronization = Some(Synchronization::Warp); + let error = lib.verify().unwrap_err().to_string(); + assert!( + error.contains("1 participants") && error.contains("promises 32"), + "{error}" + ); + lib.implementations[0].args[0].fragment.fragmap = Layout::warp_lanes(128); + lib.implementations[0].args[1].fragment.fragmap = Layout::warp_lanes(128); + lib.verify().unwrap(); + } + + #[test] + fn by_value_is_only_for_read_only_local_scalars() { + let mut lib = relu(); + lib.implementations[0].args[1].fragment.mem_layout = Layout::scalar_mem(); + let error = lib.verify().unwrap_err().to_string(); + assert!(error.contains("rank-0 mem_layout"), "{error}"); + } +} diff --git a/cuda-oxide/crates/oxide-tilebc/src/writer.rs b/cuda-oxide/crates/oxide-tilebc/src/writer.rs new file mode 100644 index 0000000000..1b787bf141 --- /dev/null +++ b/cuda-oxide/crates/oxide-tilebc/src/writer.rs @@ -0,0 +1,379 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +//! Serialize a library's two halves as Tile IR bytecode. +//! +//! The two modules only ever contain bodiless functions, so the file has +//! four sections: the function table (one entry per declaration or +//! implementation), the debug table (one unknown location per function), the +//! type table and the string table. Every encoding below was checked against +//! the reference reader's sources and against an assembler that reads 13.5 +//! content, which packs the output into a `.tilelib` with +//! `--preview-create-tile-lib`. +//! +//! ```text +//! header: 7F 'T' 'i' 'l' 'e' 'I' 'R' 00 | major | minor | tag u16 (bit 0: preview) +//! section Func (aligned 8): varint(n) then entries, padded to 8 +//! section Debug (aligned 8): per-function id lists, one unknown entry +//! section Type (aligned 4): varint(n), offsets, entries +//! section String(aligned 4): varint(n), offsets, bytes +//! end byte 00 +//! ``` + +use std::collections::HashMap; + +use crate::Error; +use crate::encoding::{ + CONTAINS_PREVIEW, MAGIC, Section, Writer, begin_offset_table, write_section, +}; +use crate::model::{ + Access, BytecodeVersion, Declaration, FragmentType, Implementation, Layout, Library, + ScalarType, TileType, +}; + +// Type-table tags. +const TAG_TILE: u64 = 13; +const TAG_FUNC: u64 = 16; +const TAG_FRAGMENT: u64 = 0xD2; + +// Attribute tags. +const ATTR_STRING: u64 = 5; +const ATTR_ARRAY: u64 = 6; +const ATTR_DICTIONARY: u64 = 10; +const ATTR_SYMBOLIC_INT: u64 = 0xD1; +const ATTR_SYMBOLIC_TUPLE: u64 = 0xD8; +const ATTR_LAYOUT: u64 = 0xD9; +const ATTR_ACCESS: u64 = 0xDF; + +/// The argument attribute that carries an access. +const ACCESS_ATTR: &str = "cuda_tile.preview$access"; + +// Function-table entry flags: bit 0 private, bit 1 kernel, bits 3:2 form. +const FLAG_PRIVATE: u8 = 0x01; +const FORM_EXTERN_IMPL: u8 = 0x04; + +// `preview$extern_impl` payload flag bits, in the op's declaration order. +const IMPL_ARG_ATTRS: u64 = 1 << 2; +const IMPL_ARCH: u64 = 1 << 6; +const IMPL_FRONTEND_ABI: u64 = 1 << 7; +const IMPL_SYNCHRONIZATION: u64 = 1 << 8; + +/// A type the type table can hold. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +enum Type { + Scalar(ScalarType), + Tile(TileType), + Fragment(FragmentType), + Func(Vec, Vec), +} + +/// Interning tables, filled in first-use order. +#[derive(Default)] +struct Tables { + strings: Vec, + string_index: HashMap, + types: Vec, + type_index: HashMap, +} + +impl Tables { + fn string(&mut self, text: &str) -> u64 { + if let Some(&index) = self.string_index.get(text) { + return index; + } + let index = self.strings.len() as u64; + self.strings.push(text.to_owned()); + self.string_index.insert(text.to_owned(), index); + index + } + + /// Register `ty`, its dependencies first, and return its index. + fn ty(&mut self, ty: &Type) -> u64 { + if let Some(&index) = self.type_index.get(ty) { + return index; + } + match ty { + Type::Scalar(_) => {} + Type::Tile(tile) => { + self.ty(&Type::Scalar(tile.element)); + } + Type::Fragment(fragment) => { + self.ty(&Type::Scalar(fragment.element)); + } + Type::Func(inputs, results) => { + for input in inputs { + self.ty(input); + } + for result in results { + self.ty(result); + } + } + } + let index = self.types.len() as u64; + self.types.push(ty.clone()); + self.type_index.insert(ty.clone(), index); + index + } +} + +/// `varint(count)` then each value as a tagged symbolic integer: the +/// payload of a `SymbolicTuple` and the inline form of a layout's modes. +fn write_int_tuple(w: &mut Writer, values: &[i64]) { + w.varint(values.len() as u64); + for &value in values { + w.varint(ATTR_SYMBOLIC_INT); + w.signed_varint(value); + } +} + +/// A layout attribute: tag, then the shapes and strides tuples inline. +fn write_layout(w: &mut Writer, layout: &Layout) { + w.varint(ATTR_LAYOUT); + write_int_tuple(w, &layout.shapes); + write_int_tuple(w, &layout.strides); +} + +/// The dictionary `{cuda_tile.preview$access = #access<..>}`, tagged. +fn write_access_dictionary(w: &mut Writer, tables: &mut Tables, access: Access) { + w.varint(ATTR_DICTIONARY); + w.varint(1); + w.varint(tables.string(ACCESS_ATTR)); + w.varint(ATTR_ACCESS); + w.varint(access.value()); +} + +/// `arg_attrs`: one access dictionary per argument. Tagged as an array for +/// a declaration (a positional field of the function table), inline (count +/// first, no array tag) inside an implementation's payload. +fn write_arg_attrs(w: &mut Writer, tables: &mut Tables, accesses: &[Access], tagged: bool) { + if tagged { + w.varint(ATTR_ARRAY); + } + w.varint(accesses.len() as u64); + for &access in accesses { + write_access_dictionary(w, tables, access); + } +} + +/// One type-table entry. +fn write_type(w: &mut Writer, tables: &mut Tables, ty: &Type) { + match ty { + Type::Scalar(scalar) => w.varint(u64::from(scalar.tag())), + Type::Tile(tile) => { + w.varint(TAG_TILE); + w.varint(tables.ty(&Type::Scalar(tile.element))); + w.le_var_size_i64(&tile.shape); + } + Type::Func(inputs, results) => { + w.varint(TAG_FUNC); + w.varint(inputs.len() as u64); + for input in inputs { + w.varint(tables.ty(input)); + } + w.varint(results.len() as u64); + for result in results { + w.varint(tables.ty(result)); + } + } + // Tagged empty symbolic shape (the shape is static), the static + // shape, element type, memory space, both layouts tagged, then the + // alignment as a tagged symbolic integer, always 1. + Type::Fragment(fragment) => { + w.varint(TAG_FRAGMENT); + w.varint(ATTR_SYMBOLIC_TUPLE); + w.varint(0); + w.le_var_size_i64(&fragment.shape); + w.varint(tables.ty(&Type::Scalar(fragment.element))); + w.varint(fragment.memory_space.value()); + write_layout(w, &fragment.mem_layout); + write_layout(w, &fragment.fragmap); + w.varint(ATTR_SYMBOLIC_INT); + w.signed_varint(1); + } + } +} + +fn declaration_signature(decl: &Declaration) -> Type { + Type::Func( + decl.args + .iter() + .map(|arg| Type::Tile(arg.ty.clone())) + .collect(), + decl.results().map(|ty| Type::Tile(ty.clone())).collect(), + ) +} + +fn implementation_signature(imp: &Implementation) -> Type { + Type::Func( + imp.args + .iter() + .map(|arg| Type::Fragment(arg.fragment.clone())) + .collect(), + Vec::new(), + ) +} + +/// A `preview$func extern` entry: normal form, private, body length zero, +/// then its (empty) constant parameters. +fn write_declaration(w: &mut Writer, tables: &mut Tables, decl: &Declaration, debug: u64) { + w.varint(tables.string(&decl.name)); + w.varint(tables.ty(&declaration_signature(decl))); + w.byte(FLAG_PRIVATE); + w.varint(debug); + let accesses: Vec = decl.args.iter().map(|arg| arg.access).collect(); + write_arg_attrs(w, tables, &accesses, true); + w.varint(0); + w.varint(ATTR_ARRAY); + w.varint(0); +} + +/// A `preview$extern_impl` entry: form bits 01, private, then the op +/// payload in place of a body (flags, symbols, type, the present optional +/// clauses, one empty region) and a body length of zero. +fn write_implementation(w: &mut Writer, tables: &mut Tables, imp: &Implementation, debug: u64) { + w.varint(tables.string(&imp.symbol)); + w.varint(tables.ty(&implementation_signature(imp))); + w.byte(FLAG_PRIVATE | FORM_EXTERN_IMPL); + w.varint(debug); + + let mut flags = IMPL_ARG_ATTRS; + if !imp.arch.is_empty() { + flags |= IMPL_ARCH; + } + if !imp.frontend_abi.is_empty() { + flags |= IMPL_FRONTEND_ABI; + } + if imp.synchronization.is_some() { + flags |= IMPL_SYNCHRONIZATION; + } + w.varint(flags); + w.varint(tables.string(&imp.symbol)); + w.varint(tables.string(&imp.implements)); + w.varint(tables.ty(&implementation_signature(imp))); + let accesses: Vec = imp.args.iter().map(|arg| arg.access).collect(); + write_arg_attrs(w, tables, &accesses, false); + if !imp.arch.is_empty() { + w.varint(imp.arch.len() as u64); + for name in &imp.arch { + w.varint(ATTR_STRING); + w.varint(tables.string(name)); + } + } + if !imp.frontend_abi.is_empty() { + w.varint(imp.frontend_abi.len() as u64); + for (key, value) in &imp.frontend_abi { + w.varint(tables.string(key)); + w.varint(ATTR_STRING); + w.varint(tables.string(value)); + } + } + if let Some(sync) = imp.synchronization { + w.varint(sync.value()); + } + // One region with zero blocks, then the zero body length. + w.varint(1); + w.varint(0); + w.varint(0); +} + +/// Per-function id lists (each holds one id 0, an unknown location) and the +/// single unknown attribute the reader expects a non-empty table to hold. +fn debug_section(functions: usize) -> Vec { + let mut w = Writer::new(); + w.varint(functions as u64); + w.align_to(4); + for index in 0..functions { + w.le_u32(index as u32); + } + w.varint(functions as u64); + w.align_to(8); + for _ in 0..functions { + w.le_u64(0); + } + w.varint(1); + w.align_to(4); + w.le_u32(0); + w.byte(0); + w.into_bytes() +} + +fn type_section(tables: &mut Tables) -> Vec { + let mut w = Writer::new(); + let count = tables.types.len(); + let offsets = begin_offset_table(&mut w, count); + let start = w.len(); + // Writing an entry can only reference types registered before it, so + // the table does not grow while it is serialized. + let types = tables.types.clone(); + for (index, ty) in types.iter().enumerate() { + w.patch_u32(offsets + 4 * index, (w.len() - start) as u32); + write_type(&mut w, tables, ty); + } + debug_assert_eq!(tables.types.len(), count); + w.into_bytes() +} + +fn string_section(tables: &Tables) -> Vec { + let mut w = Writer::new(); + let offsets = begin_offset_table(&mut w, tables.strings.len()); + let mut running = 0u32; + for (index, text) in tables.strings.iter().enumerate() { + w.patch_u32(offsets + 4 * index, running); + w.bytes(text.as_bytes()); + running += text.len() as u32; + } + w.into_bytes() +} + +fn write_module( + version: BytecodeVersion, + entries: usize, + mut write_entries: impl FnMut(&mut Writer, &mut Tables), +) -> Result, Error> { + if version < BytecodeVersion::PREVIEW_FIRST { + return Err(Error::Version(version)); + } + let mut tables = Tables::default(); + let mut functions = Writer::new(); + functions.varint(entries as u64); + write_entries(&mut functions, &mut tables); + functions.align_to(8); + + let mut out = MAGIC.to_vec(); + out.push(version.major); + out.push(version.minor); + out.extend_from_slice(&CONTAINS_PREVIEW.to_le_bytes()); + write_section(&mut out, Section::Func, &functions.into_bytes(), 8); + write_section(&mut out, Section::Debug, &debug_section(entries), 8); + write_section(&mut out, Section::Type, &type_section(&mut tables), 4); + write_section(&mut out, Section::String, &string_section(&tables), 4); + out.push(Section::EndOfBytecode as u8); + Ok(out) +} + +impl Library { + /// The interface half: every declaration as a `preview$func extern`. + /// + /// `version` must be the one the consuming assembler calls current; + /// preview content is readable at no other version. Anything below + /// 13.5 is an error. + pub fn interface_bytecode(&self, version: BytecodeVersion) -> Result, Error> { + write_module(version, self.declarations.len(), |w, tables| { + for (index, decl) in self.declarations.iter().enumerate() { + write_declaration(w, tables, decl, index as u64 + 1); + } + }) + } + + /// The implementation half: every implementation as a + /// `preview$extern_impl`. + pub fn implementation_bytecode(&self, version: BytecodeVersion) -> Result, Error> { + write_module(version, self.implementations.len(), |w, tables| { + for (index, imp) in self.implementations.iter().enumerate() { + write_implementation(w, tables, imp, index as u64 + 1); + } + }) + } +} diff --git a/cuda-oxide/cuda-oxide-book/compiler/architecture-overview.md b/cuda-oxide/cuda-oxide-book/compiler/architecture-overview.md index 173660b5ec..efe28cf34e 100644 --- a/cuda-oxide/cuda-oxide-book/compiler/architecture-overview.md +++ b/cuda-oxide/cuda-oxide-book/compiler/architecture-overview.md @@ -147,6 +147,7 @@ cuda-oxide is split into focused crates. Here is every one and its role: | `cuda-artifact-finalizer` | Driver-independent NVVM IR, LTOIR, and PTX finalization | | `oxide-artifacts` | Architecture-neutral embedded device artifact metadata | | `oxide-tile-export` | `#[tile_export]` descriptions shared by the macro, the backend and `cargo oxide tilelib` | +| `oxide-tilebc` | Tile IR bytecode writer for the tile library descriptions `cargo oxide tilelib` emits | | `dialect-iket` | pliron dialect modelling in-kernel event tracing | | `iket-lower` | `dialect-iket` profiles + instrumentation lowering | | `dialect-ptx` | pliron dialect modelling structured PTX | diff --git a/cuda-oxide/dependency-licenses.csv b/cuda-oxide/dependency-licenses.csv index bb3b3fca36..57b9c14f47 100644 --- a/cuda-oxide/dependency-licenses.csv +++ b/cuda-oxide/dependency-licenses.csv @@ -83,6 +83,7 @@ object,0.36.7,Apache-2.0 OR MIT,Yes,registry+https://github.com/rust-lang/crates once_cell,1.21.3,MIT OR Apache-2.0,Yes,registry+https://github.com/rust-lang/crates.io-index,3rd Party (crates.io),https://github.com/matklad/once_cell,Single assignment cells and lazy values., oxide-artifacts,0.2.1,Apache-2.0,Yes,registry+https://github.com/rust-lang/crates.io-index,1st Party (crates.io),https://github.com/NVIDIA/cuda-rust,Architecture-neutral embedded device artifact metadata for cuda-oxide,"Consumed from crates.io by the backend (writer) and by the shared cuda-core (reader) so both see one crate; crates/oxide-artifacts in this workspace is the source it is published from." oxide-tile-export,0.2.1,Apache-2.0,Yes,local (workspace),1st Party (workspace),https://github.com/NVIDIA/cuda-rust,Descriptions of Rust device functions exported to cuTile tile libraries,Shared by #[tile_export] (cuda-macros) and the rustc-codegen-cuda backend; cargo oxide tilelib reads the .tileexports.json it describes. +oxide-tilebc,0.2.1,Apache-2.0,Yes,local (workspace),1st Party (workspace),https://github.com/NVIDIA/cuda-rust,Tile IR bytecode writer for the tile library descriptions cuda-oxide ships,cargo oxide tilelib writes a library's interface and implementation bytecode with it; no CUDA dependency. pliron,0.20.0,Apache-2.0,Yes,registry+https://github.com/rust-lang/crates.io-index,3rd Party (crates.io),https://github.com/pliron-org/pliron,Programming Languages Intermediate RepresentatiON,"Primary dependency: MLIR-inspired IR framework. Custom MLIR dialects (MIR, LLVM, NVVM) built on this. Exact published release shared by the compiler workspaces." pliron-derive,0.20.0,Apache-2.0,Yes,registry+https://github.com/rust-lang/crates.io-index,3rd Party (crates.io),https://github.com/pliron-org/pliron,Derive macros for pliron,Proc-macro companion pinned to the same published release as pliron. pliron-llvm,0.20.0,Apache-2.0,Yes,registry+https://github.com/rust-lang/crates.io-index,3rd Party (crates.io),https://github.com/pliron-org/pliron,LLVM dialect for pliron,Upstream LLVM dialect modeling; re-exported by llvm-export with std enabled and the llvm-sys FFI bridge disabled. Same published release as pliron. From a7c465e9d2bf4841082bf5f5bdec567e30c937fb Mon Sep 17 00:00:00 2001 From: nihalpasham Date: Sun, 18 Oct 2026 19:12:56 +0530 Subject: [PATCH 3/3] feat(cargo-oxide): add `cargo oxide tilelib` and the tilelib_relu example `cargo oxide tilelib --arch sm_XX` packages a crate's `#[tile_export]` functions as a cuTile tile library. It runs emit-ltoir, checks that the NVVM IR defines every implementation symbol with the parameter list the native SIMT ABI predicts, maps the descriptions to the oxide-tilebc model, writes the interface and implementation bytecode plus a readable `.tilelib.mlir`, and asks `tileiras --preview-create-tile-lib` for the `.tilelib`. An assembler reads preview content only at the version it calls current, so the descriptions are written at the newest version the installed tileiras lists (13.5 when none can read them yet). An older assembler stops after the descriptions with exit 2, or exit 0 with `--library-optional`; the summary ends with a "written to" or "skipped" line that scripts read. The `tilelib_relu` example is a three-export library (`relu`, `scale_in_place`, `warp_sum`) with three consumers: a host program that proves the ABI on the installed toolkit (a CUDA C++ caller generated from the descriptions, linked with nvJitLink, checked on the GPU), a Tile C++ kernel in `cpp/tile_caller.cu` built with nvcc's `--enable-tile` and `--tile-preview simt`, and a cuTile Python kernel in `python/call_from_cutile.py` with a dry run that stops at the bytecode. Also: the smoketest `tilelib` lane and the book chapter on tile libraries. Signed-off-by: nihalpasham --- cuda-oxide/README.md | 1 + cuda-oxide/crates/cargo-oxide/Cargo.toml | 2 + cuda-oxide/crates/cargo-oxide/README.md | 85 +- .../cargo-oxide/src/commands/artifacts.rs | 9 + .../crates/cargo-oxide/src/commands/mod.rs | 2 + .../crates/cargo-oxide/src/commands/tests.rs | 662 +++++++++++++ .../cargo-oxide/src/commands/tilelib.rs | 928 ++++++++++++++++++ cuda-oxide/crates/cargo-oxide/src/main.rs | 155 +++ .../Cargo.lock | 35 + .../Cargo.lock | 35 + .../examples/tilelib_relu/Cargo.lock | 735 ++++++++++++++ .../examples/tilelib_relu/Cargo.toml | 29 + .../examples/tilelib_relu/README.md | 136 +++ .../examples/tilelib_relu/cpp/tile_caller.cu | 123 +++ .../tilelib_relu/python/call_from_cutile.py | 215 ++++ .../examples/tilelib_relu/src/main.rs | 593 +++++++++++ .../examples/tilelib_relu/tile_caller | Bin 0 -> 1152560 bytes .../images/tilelib-direct-linkage.svg | 107 ++ .../advanced/tile-libraries.md | 434 ++++++++ .../appendix/supported-features.md | 2 +- .../getting-started/installation.md | 1 + cuda-oxide/cuda-oxide-book/index.md | 1 + .../check-example-smoketest-contract.sh | 1 + cuda-oxide/scripts/smoketest.sh | 168 ++++ 24 files changed, 4446 insertions(+), 13 deletions(-) create mode 100644 cuda-oxide/crates/cargo-oxide/src/commands/tilelib.rs create mode 100644 cuda-oxide/crates/rustc-codegen-cuda/examples/tilelib_relu/Cargo.lock create mode 100644 cuda-oxide/crates/rustc-codegen-cuda/examples/tilelib_relu/Cargo.toml create mode 100644 cuda-oxide/crates/rustc-codegen-cuda/examples/tilelib_relu/README.md create mode 100644 cuda-oxide/crates/rustc-codegen-cuda/examples/tilelib_relu/cpp/tile_caller.cu create mode 100644 cuda-oxide/crates/rustc-codegen-cuda/examples/tilelib_relu/python/call_from_cutile.py create mode 100644 cuda-oxide/crates/rustc-codegen-cuda/examples/tilelib_relu/src/main.rs create mode 100755 cuda-oxide/crates/rustc-codegen-cuda/examples/tilelib_relu/tile_caller create mode 100644 cuda-oxide/cuda-oxide-book/advanced/images/tilelib-direct-linkage.svg create mode 100644 cuda-oxide/cuda-oxide-book/advanced/tile-libraries.md diff --git a/cuda-oxide/README.md b/cuda-oxide/README.md index 2c3c98a44b..57ee3befa0 100644 --- a/cuda-oxide/README.md +++ b/cuda-oxide/README.md @@ -339,6 +339,7 @@ cargo oxide run gemm_sol_final | `cuda-artifact-finalizer` | Driver-independent NVVM IR, LTOIR, and PTX finalization | | `oxide-artifacts` | Architecture-neutral embedded device artifact metadata | | `oxide-tile-export` | `#[tile_export]` descriptions shared by the macro, the backend and `cargo oxide tilelib` | +| `oxide-tilebc` | Tile IR bytecode writer for the tile library descriptions `cargo oxide tilelib` emits | | `reserved-oxide-symbols` | Workspace-private `cuda_oxide_*` symbol-name contract | | `fuzzer` | Differential codegen fuzzer support (rustlantis adapter) | | `ptx-schedule` | PTX schedule-perturbation fuzzing (nanosleep injection campaigns) | diff --git a/cuda-oxide/crates/cargo-oxide/Cargo.toml b/cuda-oxide/crates/cargo-oxide/Cargo.toml index 7c34766a0c..45e2a16cbe 100644 --- a/cuda-oxide/crates/cargo-oxide/Cargo.toml +++ b/cuda-oxide/crates/cargo-oxide/Cargo.toml @@ -23,6 +23,8 @@ cuda-artifact-finalizer = { workspace = true } libnvvm-sys = { workspace = true } nvjitlink-sys = { workspace = true } oxide-artifacts = { workspace = true } +oxide-tile-export = { workspace = true } +oxide-tilebc = { workspace = true } ptx-parse = { workspace = true } ptx-schedule = { workspace = true } reserved-oxide-symbols = { workspace = true } diff --git a/cuda-oxide/crates/cargo-oxide/README.md b/cuda-oxide/crates/cargo-oxide/README.md index 75d4c914d6..f1e01c8c48 100644 --- a/cuda-oxide/crates/cargo-oxide/README.md +++ b/cuda-oxide/crates/cargo-oxide/README.md @@ -28,6 +28,7 @@ cargo oxide build vecadd # compile only (no run) cargo oxide build vecadd --debug-assertions # keep release optimization, compile debug assertions cargo oxide build vecadd --materialize-cubin --arch sm_120 # embed native cubin cargo oxide emit-ltoir vecadd --arch sm_100 # device code -> .ltoir (Tile/SIMT interop) +cargo oxide tilelib tilelib_relu --arch sm_120 # #[tile_export] crate -> cuTile tile library cargo oxide build -- -p my_app # arbitrary cargo build through cuda-oxide cargo oxide test # cargo test with cuda-oxide defaults cargo oxide test -- -p my_app # arbitrary cargo test through cuda-oxide @@ -53,20 +54,22 @@ cargo oxide update --force # inside the workspace, run setup via update |------------------------------|----------------------------------|-------------------------------------------------| | `--materialize-cubin` | run, sanitize, build, test, pipeline, debug | Finalize and embed target-specific native GPU code during the host build | | `--emit-nvvm-ir` | run, build, pipeline | Generate NVVM IR for libNVVM | -| `--arch ` | run, sanitize, build, test, pipeline, emit-ltoir, inspect, debug | Target architecture override | -| `--features ` | run, sanitize, debug, build, build passthrough, emit-ltoir, inspect | Comma-separated cargo features to enable | +| `--arch ` | run, sanitize, build, test, pipeline, emit-ltoir, tilelib, inspect, debug | Target architecture override | +| `--features ` | run, sanitize, debug, build, build passthrough, emit-ltoir, tilelib, inspect | Comma-separated cargo features to enable | | `--device-features ` | run, build | Comma-separated features for metadata-declared device crates only | | `--bin ` | run, sanitize, debug | Specific binary target to build/run | | `--tool ` | sanitize | Compute Sanitizer tool: `memcheck`, `racecheck`, `initcheck`, or `synccheck` | -| `-o, --output

` | emit-ltoir | Output path for the `.ltoir` artifact | +| `-o, --output

` | emit-ltoir, tilelib | Output path for the `.ltoir` or `.tilelib` artifact | +| `--library-optional` | tilelib | Succeed when the installed tileiras cannot build the `.tilelib`; the descriptions and LTOIR are still written | +| `--print` | tilelib | Print the readable form of the interface and implementation modules | | `--cargo-target-dir ` | build/test passthrough | Cargo target directory | | `--device-codegen-crate ` | build/test passthrough | Comma-separated device owner crate filter | | `--device-cfg ` | build/test passthrough | Append `--cfg NAME` to rustflags | -| `-v, --verbose` | run, sanitize, build, test, emit-ltoir, inspect | Show detailed compilation output | -| `--no-fmad` | run, sanitize, build, test, emit-ltoir, pipeline, inspect | Keep ordinary multiply and add/subtract operations separate | -| `--unchecked-indexing` | run, sanitize, build, test, emit-ltoir, pipeline, inspect | Elide device slice/array bounds checks (UB on OOB) | -| `--lineinfo` | run, sanitize, build, test, emit-ltoir, pipeline, inspect | Emit device line-number info for profilers (nvcc `-lineinfo`) | -| `--device-debug` | run, sanitize, build, test, emit-ltoir, pipeline, inspect | Emit full device debug info; disables libNVVM optimization (nvcc `-G`) | +| `-v, --verbose` | run, sanitize, build, test, emit-ltoir, tilelib, inspect | Show detailed compilation output | +| `--no-fmad` | run, sanitize, build, test, emit-ltoir, tilelib, pipeline, inspect | Keep ordinary multiply and add/subtract operations separate | +| `--unchecked-indexing` | run, sanitize, build, test, emit-ltoir, tilelib, pipeline, inspect | Elide device slice/array bounds checks (UB on OOB) | +| `--lineinfo` | run, sanitize, build, test, emit-ltoir, tilelib, pipeline, inspect | Emit device line-number info for profilers (nvcc `-lineinfo`) | +| `--device-debug` | run, sanitize, build, test, emit-ltoir, tilelib, pipeline, inspect | Emit full device debug info; disables libNVVM optimization (nvcc `-G`) | | `--debug-assertions` | build | Compile `debug_assert!` / `cfg(debug_assertions)` with release-like optimization and overflow checks disabled | | `--force` | update | Inside the workspace, run `setup` instead of advising it | | `--async` | new | Use the async template | @@ -75,8 +78,8 @@ cargo oxide update --force # inside the workspace, run setup via update | `--check` | fmt | Check formatting only | | `--json` | list | Emit stable machine-readable output | -`--arch` is required for `emit-ltoir` and explicit NVVM IR output because those -artifacts are architecture-specific. Without an override, `run` detects the +`--arch` is required for `emit-ltoir`, `tilelib` and explicit NVVM IR output +because those artifacts are architecture-specific. Without an override, `run` detects the local GPU, while `build` and `pipeline` use the compiler's feature-based target so they remain useful for cross-compilation. @@ -124,8 +127,8 @@ multi-artifact linking is not yet represented by this single-cubin path. Metadata-interop projects keep rejecting this global flag; they can instead request one independently finalized cubin per declared device crate with `artifact-kind = "cubin"`, as described below. Materialization is also a -final-output mode, so it cannot be combined with `--emit-nvvm-ir` or -`emit-ltoir`. +final-output mode, so it cannot be combined with `--emit-nvvm-ir`, +`emit-ltoir` or `tilelib`. ## Commands @@ -314,6 +317,64 @@ Pre-Blackwell targets use LLVM 7 typed pointers; `compute_100` and newer targets use modern opaque pointers. The target is checked before export and recorded alongside the artifact so the runtime uses the same format. +### `cargo oxide tilelib ` + +Packages a crate's `#[tile_export]` functions as a cuTile tile library: the +other direction of the interop, where a cuTile program calls Rust device +functions through `foreign_call`. + +```text +emit-ltoir ──> .ltoir .ll .tileexports.json + │ │ + define @(...) checked against the ABI table + │ + descriptions ──> oxide-tilebc Declaration + Implementation + │ + .iface.tilebc .impl.tilebc .tilelib.mlir + │ + tileiras --preview-create-tile-lib (lists 13.5 or newer) ──> .tilelib +``` + +The command runs `emit-ltoir` for the device half, then checks that the +emitted NVVM IR defines every implementation symbol the descriptions name +with the parameter list the native SIMT ABI predicts (`in` scalars by value, +everything else a pointer, `void` return), because the assembler never looks +inside the code payload and a missing symbol would otherwise surface only +when a cuTile program is compiled against the library. The descriptions then +become the two halves of the library through the `oxide-tilebc` crate: the +interface (`preview$func extern` declarations with tile-typed arguments) and +the implementation catalog (`preview$extern_impl` entries whose fragments +describe each parameter's buffer and its map onto the tile). Both are +written as Tile IR bytecode with the preview tag, at the version the resolved +assembler calls current (its newest listed version, 13.5 when none can read +them yet), next to a readable `.tilelib.mlir`; `--print` shows that +text. + +`tileiras --preview-create-tile-lib` exists from the CUDA 13.5 assembler on, +the first one whose `--list-versions` names bytecode 13.5. An assembler reads +preview content only at its current version, which is why the descriptions +are written at that version. When the resolved tileiras lists 13.5 or newer, +the library is assembled from the interface, the implementation catalog and +the LTOIR into `.tilelib` (or `-o`). +Otherwise the command explains what the installed assembler can read, points +at the files a newer one needs, and exits 2; `--library-optional` makes that +outcome exit 0, for toolkits that can build the descriptions but not the +library yet. The summary ends with one of two lines a script can read instead +of probing tileiras itself: `Tile library written to ` or +`Tile library skipped: lists bytecode versions ...`. The assembler +is resolved from `CUTILE_TILEIRAS_PATH` (cuTile's own override), then like +every other toolkit tool: PATH, the configured CUDA toolkit root, the standard +install locations. A tileiras that is configured but cannot be run is an +error (exit 1) naming the path and the OS error; only an assembler that runs +and lists no bytecode versions is treated as one that predates +`--list-versions`. + +```bash +cargo oxide tilelib tilelib_relu --arch sm_120 --print +cargo oxide tilelib tilelib_relu --arch sm_120 --library-optional # CUDA 13.4: descriptions and LTOIR +cargo oxide tilelib my_lib --arch sm_120 -o build/my_lib.tilelib +``` + ### `cargo oxide test` Runs `cargo test` through the cuda-oxide backend. With no extra arguments it diff --git a/cuda-oxide/crates/cargo-oxide/src/commands/artifacts.rs b/cuda-oxide/crates/cargo-oxide/src/commands/artifacts.rs index 85ddd2eaf1..94e2caaa36 100644 --- a/cuda-oxide/crates/cargo-oxide/src/commands/artifacts.rs +++ b/cuda-oxide/crates/cargo-oxide/src/commands/artifacts.rs @@ -112,6 +112,15 @@ pub(super) const GENERATED_ARTIFACT_SUFFIXES: &[&str] = &[ "target", "options", "cubin.target", + // `#[tile_export]` descriptions the backend writes next to the `.ll` + // (`oxide_tile_export::DESCRIPTIONS_SUFFIX`). + "tileexports.json", + // What `cargo oxide tilelib` writes from those descriptions: the two + // Tile IR bytecode halves, their readable dump, and the library itself. + TILELIB_INTERFACE_SUFFIX, + TILELIB_IMPLEMENTATION_SUFFIX, + TILELIB_DUMP_SUFFIX, + TILELIB_LIBRARY_SUFFIX, ]; pub(super) fn generated_artifact_paths(project_dir: &Path, package_name: &str) -> Vec { diff --git a/cuda-oxide/crates/cargo-oxide/src/commands/mod.rs b/cuda-oxide/crates/cargo-oxide/src/commands/mod.rs index f0a94b187d..10bc374ee6 100644 --- a/cuda-oxide/crates/cargo-oxide/src/commands/mod.rs +++ b/cuda-oxide/crates/cargo-oxide/src/commands/mod.rs @@ -28,6 +28,7 @@ mod scaffold; mod setup_update; #[cfg(test)] mod tests; +mod tilelib; mod toolkit; use artifacts::*; @@ -47,4 +48,5 @@ pub use passthrough::*; pub use pipeline_debug::*; pub use scaffold::*; pub use setup_update::*; +pub use tilelib::*; use toolkit::*; diff --git a/cuda-oxide/crates/cargo-oxide/src/commands/tests.rs b/cuda-oxide/crates/cargo-oxide/src/commands/tests.rs index 49d11a1e52..30cb03e83a 100644 --- a/cuda-oxide/crates/cargo-oxide/src/commands/tests.rs +++ b/cuda-oxide/crates/cargo-oxide/src/commands/tests.rs @@ -34,6 +34,7 @@ const COMMANDS_SOURCE: &str = concat!( include_str!("scaffold.rs"), include_str!("setup_update.rs"), include_str!("tests.rs"), + include_str!("tilelib.rs"), include_str!("toolkit.rs"), ); @@ -5189,3 +5190,664 @@ fn doctor_backend_source_check_covers_every_branch() { ); } } + +// ============================================================================= +// cargo oxide tilelib +// ============================================================================= + +/// The three exports of the `tilelib_relu` example, as the backend's +/// descriptions file records them. +fn tilelib_relu_descriptions() -> Vec { + use oxide_tile_export::{TileAccess, TileElem, TileExportDesc, TileParamDesc, TileSync}; + let param = |name: &str, access: TileAccess, by_value: bool| TileParamDesc { + name: name.to_string(), + elem: TileElem::F32, + access, + footprint: 1, + by_value, + }; + vec![ + TileExportDesc { + version: oxide_tile_export::CURRENT_VERSION, + decl: "relu".into(), + symbol: "relu_impl".into(), + shape: vec![128], + params: vec![ + param("x", TileAccess::In, true), + param("relu_out", TileAccess::Out, false), + ], + sync: TileSync::None, + arch: Vec::new(), + }, + TileExportDesc { + version: oxide_tile_export::CURRENT_VERSION, + decl: "scale_in_place".into(), + symbol: "scale_in_place_impl".into(), + shape: vec![128], + params: vec![ + param("x", TileAccess::InOut, false), + param("factor", TileAccess::In, true), + ], + sync: TileSync::None, + arch: Vec::new(), + }, + TileExportDesc { + version: oxide_tile_export::CURRENT_VERSION, + decl: "warp_sum".into(), + symbol: "warp_sum_impl".into(), + shape: vec![128], + params: vec![ + param("x", TileAccess::In, true), + param("warp_sum_out", TileAccess::Out, false), + ], + sync: TileSync::Warp, + arch: Vec::new(), + }, + ] +} + +/// Whitespace-insensitive form of a Tile IR text, the rule the upstream +/// fixture tests apply: a whitespace run survives, as one space, only between +/// two word characters, so the hand-written multi-line layout below compares +/// equal to the printer's one-line form while a missing space between two +/// words still differs. +fn normalize_tile_ir(text: &str) -> String { + let is_word = |c: char| c.is_alphanumeric() || "_$.@%!#\"?".contains(c); + let mut out = String::new(); + let mut pending_space = false; + for c in text.chars() { + if c.is_whitespace() { + pending_space = true; + continue; + } + if pending_space { + if let Some(prev) = out.chars().last() + && is_word(prev) + && is_word(c) + { + out.push(' '); + } + pending_space = false; + } + out.push(c); + } + out +} + +/// The interface of `tilelib_relu` in the upstream textual syntax: one +/// extern declaration per export, every argument carrying its access, the +/// results being the out/inout tiles. +const TILELIB_RELU_INTERFACE: &str = r#" +cuda_tile.module @tilelib_relu { + cuda_tile.preview$func extern @relu( + %x: !cuda_tile.tile<128xf32> + {cuda_tile.preview$access = #cuda_tile.preview$access}, + %relu_out: !cuda_tile.tile<128xf32> + {cuda_tile.preview$access = #cuda_tile.preview$access}) + -> !cuda_tile.tile<128xf32> + cuda_tile.preview$func extern @scale_in_place( + %x: !cuda_tile.tile<128xf32> + {cuda_tile.preview$access = #cuda_tile.preview$access}, + %factor: !cuda_tile.tile<128xf32> + {cuda_tile.preview$access = #cuda_tile.preview$access}) + -> !cuda_tile.tile<128xf32> + cuda_tile.preview$func extern @warp_sum( + %x: !cuda_tile.tile<128xf32> + {cuda_tile.preview$access = #cuda_tile.preview$access}, + %warp_sum_out: !cuda_tile.tile<128xf32> + {cuda_tile.preview$access = #cuda_tile.preview$access}) + -> !cuda_tile.tile<128xf32> +} +"#; + +/// The implementation catalog of `tilelib_relu`: by-value scalars are the +/// rank-0 `():()` buffer, pointers the contiguous `(1):(1)` one; the two +/// elementwise exports map one invocation per element and `warp_sum` one +/// element per lane with a whole warp per invocation, which is what its +/// `synchronization = warp` clause requires. +const TILELIB_RELU_IMPLEMENTATION: &str = r#" +cuda_tile.module @tilelib_relu { + cuda_tile.preview$extern_impl @relu_impl implements @relu + (%x: !cuda_tile.preview$fragment<1xf32, local, + mem_layout = #cuda_tile.preview$layout<():()>, + fragmap = #cuda_tile.preview$layout<(128, 1, 1):(1, 0, 0)>> + {cuda_tile.preview$access = #cuda_tile.preview$access}, + %relu_out: !cuda_tile.preview$fragment<1xf32, local, + mem_layout = #cuda_tile.preview$layout<(1):(1)>, + fragmap = #cuda_tile.preview$layout<(128, 1, 1):(1, 0, 0)>> + {cuda_tile.preview$access = #cuda_tile.preview$access}) + cuda_tile.preview$extern_impl @scale_in_place_impl implements @scale_in_place + (%x: !cuda_tile.preview$fragment<1xf32, local, + mem_layout = #cuda_tile.preview$layout<(1):(1)>, + fragmap = #cuda_tile.preview$layout<(128, 1, 1):(1, 0, 0)>> + {cuda_tile.preview$access = #cuda_tile.preview$access}, + %factor: !cuda_tile.preview$fragment<1xf32, local, + mem_layout = #cuda_tile.preview$layout<():()>, + fragmap = #cuda_tile.preview$layout<(128, 1, 1):(1, 0, 0)>> + {cuda_tile.preview$access = #cuda_tile.preview$access}) + cuda_tile.preview$extern_impl @warp_sum_impl implements @warp_sum + (%x: !cuda_tile.preview$fragment<1xf32, local, + mem_layout = #cuda_tile.preview$layout<():()>, + fragmap = #cuda_tile.preview$layout<(4, 32, 1):(32, 1, 0)>> + {cuda_tile.preview$access = #cuda_tile.preview$access}, + %warp_sum_out: !cuda_tile.preview$fragment<1xf32, local, + mem_layout = #cuda_tile.preview$layout<(1):(1)>, + fragmap = #cuda_tile.preview$layout<(4, 32, 1):(32, 1, 0)>> + {cuda_tile.preview$access = #cuda_tile.preview$access}) + synchronization = #cuda_tile.preview$synchronization +} +"#; + +#[test] +fn tilelib_relu_descriptions_print_as_the_upstream_modules() { + let library = TileLibrary::from_descriptions(&tilelib_relu_descriptions()) + .unwrap() + .library("tilelib_relu"); + library.verify().unwrap(); + let interface = library.interface_text(); + assert_eq!( + normalize_tile_ir(&interface), + normalize_tile_ir(TILELIB_RELU_INTERFACE), + "printed interface:\n{interface}" + ); + let implementation = library.implementation_text(); + assert_eq!( + normalize_tile_ir(&implementation), + normalize_tile_ir(TILELIB_RELU_IMPLEMENTATION), + "printed implementation:\n{implementation}" + ); + // Both halves are preview content, written at the version the + // assembler calls current with the header tag set. + let version = oxide_tilebc::BytecodeVersion::PREVIEW_FIRST; + for bytes in [ + library.interface_bytecode(version).unwrap(), + library.implementation_bytecode(version).unwrap(), + ] { + assert_eq!(&bytes[8..12], &[13, 5, 1, 0]); + } + // The readable dump names the file each module ends up in. + let dump = library_dump(&library, "tilelib_relu"); + assert!(dump.starts_with("// tilelib_relu.iface.tilebc"), "{dump}"); + assert!(dump.contains("\n// tilelib_relu.impl.tilebc"), "{dump}"); + assert_eq!(dump.matches("cuda_tile.module @tilelib_relu {").count(), 2); +} + +#[test] +fn fragmaps_follow_the_synchronization_and_the_footprint() { + use oxide_tile_export::TileSync; + use oxide_tilebc::Layout; + // One invocation per element; a footprint of F gives N/F invocations of + // F contiguous elements. + assert_eq!( + fragmap(TileSync::None, 128, 1).unwrap(), + Layout::flat(&[128, 1, 1], &[1, 0, 0]) + ); + assert_eq!( + fragmap(TileSync::None, 128, 4).unwrap(), + Layout::flat(&[32, 1, 4], &[4, 0, 1]) + ); + // A warp per invocation: 32 participants, one element each, or F + // contiguous elements each with adjacent lanes adjacent in the tile. + assert_eq!( + fragmap(TileSync::Warp, 128, 1).unwrap(), + Layout::flat(&[4, 32, 1], &[32, 1, 0]) + ); + assert_eq!( + fragmap(TileSync::Warp, 256, 4).unwrap(), + Layout::flat(&[2, 32, 4], &[128, 4, 1]) + ); + // The footprint must divide the tile size. + assert!( + fragmap(TileSync::None, 128, 3) + .unwrap_err() + .contains("does not divide") + ); + assert!( + fragmap(TileSync::Warp, 64, 4) + .unwrap_err() + .contains("multiple of 128") + ); + assert!( + fragmap(TileSync::None, 128, 0) + .unwrap_err() + .contains("positive") + ); + + // Footprints above one verify against the declaration's tile like the + // one-element case does, when every parameter shares them: `fn + // scale4(x: &mut [f32; 4], factor: &[f32; 4])`. + let mut descriptions = tilelib_relu_descriptions(); + let scale = &mut descriptions[1]; + for param in &mut scale.params { + param.footprint = 4; + param.by_value = false; + } + let library = TileLibrary::from_descriptions(&descriptions) + .unwrap() + .library("lib"); + library.verify().unwrap(); + let text = library.implementation_text(); + assert!( + text.contains( + "%x: !cuda_tile.preview$fragment<4xf32, local, mem_layout = \ + #cuda_tile.preview$layout<(4):(1)>, fragmap = \ + #cuda_tile.preview$layout<(32, 1, 4):(4, 0, 1)>>" + ), + "{text}" + ); + assert!( + text.contains( + "%factor: !cuda_tile.preview$fragment<4xf32, local, mem_layout = \ + #cuda_tile.preview$layout<(4):(1)>, fragmap = \ + #cuda_tile.preview$layout<(32, 1, 4):(4, 0, 1)>>" + ), + "{text}" + ); + // A window beside a scalar cannot share one invocation count, so the + // description is refused before the verifier would reject the fragmaps. + descriptions[1].params[1].footprint = 1; + descriptions[1].params[1].by_value = true; + let error = TileLibrary::from_descriptions(&descriptions).unwrap_err(); + assert!( + error.contains("`x` (footprint 4) and `factor` (footprint 1) differ"), + "{error}" + ); +} + +#[test] +fn a_bf16_scalar_passed_by_value_adds_the_frontend_abi_entry() { + use oxide_tile_export::TileElem; + // cuda-device's bf16 is a u16 wrapper, so the LLVM parameter is i16 + // while the tile element is bf16: the implementation has to say so. + let mut descriptions = tilelib_relu_descriptions(); + let relu = &mut descriptions[0]; + for param in &mut relu.params { + param.elem = TileElem::BF16; + } + let (_, implementation) = describe_export(relu).unwrap(); + assert_eq!( + implementation.frontend_abi, + vec![("bf16".to_string(), "i16".to_string())] + ); + // No `sync` means no clause at all, not an explicit `synchronization`. + assert_eq!(implementation.synchronization, None); + let library = TileLibrary::from_descriptions(&descriptions[..1]) + .unwrap() + .library("lib"); + library.verify().unwrap(); + let text = library.implementation_text(); + assert!( + normalize_tile_ir(&text).contains("{frontendABI={bf16=\"i16\"}}"), + "{text}" + ); + assert!(text.contains("preview$fragment<1xbf16, local"), "{text}"); + + // A bf16 behind a pointer travels as a pointer and needs no entry. + let scale = &mut descriptions[1]; + scale.params[0].elem = TileElem::BF16; + let (_, implementation) = describe_export(scale).unwrap(); + assert!(implementation.frontend_abi.is_empty()); + + // Unsigned Rust integers are the signless Tile IR integers. + let warp_sum = &mut descriptions[2]; + for param in &mut warp_sum.params { + param.elem = TileElem::U32; + } + let (func, implementation) = describe_export(warp_sum).unwrap(); + assert_eq!(func.args[0].ty.element, oxide_tilebc::ScalarType::I32); + assert_eq!( + implementation.args[1].fragment.element, + oxide_tilebc::ScalarType::I32 + ); + assert_eq!( + implementation.synchronization, + Some(oxide_tilebc::Synchronization::Warp) + ); +} + +/// The NVVM IR the backend emits for `tilelib_relu` on a modern target, +/// reduced to its function definitions. +const TILELIB_RELU_LL: &str = "\ +; ModuleID = 'builtin.module' +source_filename = \"tilelib_relu\" +target triple = \"nvptx64-nvidia-cuda\" + +define void @relu_impl(float %v0, ptr %v1) #0 { +entry: + ret void +} + +define void @scale_in_place_impl(ptr %v0, float %v1) #0 { +entry: + ret void +} + +define void @warp_sum_impl(float %v0, ptr %v1) #0 { +entry: + ret void +} + +declare float @llvm.nvvm.shfl.sync.bfly.f32(i32, float, i32, i32) #0 + +define float @tilelib_relu__warp_sum(float %v0) #0 { +entry: + ret float %v0 +} +"; + +#[test] +fn ll_defines_are_read_with_their_return_and_parameter_types() { + let defines = ll_defines(TILELIB_RELU_LL); + assert_eq!( + defines.keys().collect::>(), + [ + "relu_impl", + "scale_in_place_impl", + "tilelib_relu__warp_sum", + "warp_sum_impl" + ] + ); + assert_eq!( + defines["relu_impl"], + LlDefine { + ret: "void".into(), + params: vec!["float".into(), "ptr".into()], + local_linkage: None, + } + ); + assert_eq!(defines["tilelib_relu__warp_sum"].ret, "float"); + // `declare` lines are not definitions. + assert!(!defines.contains_key("llvm.nvvm.shfl.sync.bfly.f32")); + + // Linkage, calling convention and parameter attributes do not change + // the types; address spaces and legacy typed pointers survive intact. A + // linkage that keeps the symbol out of the module's exports is kept + // aside for the symbol check to report. + let defines = ll_defines( + "define internal fastcc void @k(ptr noundef %a, i64 %n, ptr addrspace(3) %s, i8* %p, { ptr, i64 } %slice) #0 {\n\ + define dso_local weak_odr void @w() {\n\ + define private void @p() {\n\ + define linkonce_odr void @l() {\n\ + define ptx_kernel void @\"quoted name\"() {\n", + ); + assert_eq!( + defines["k"], + LlDefine { + ret: "void".into(), + params: vec![ + "ptr".into(), + "i64".into(), + "ptr addrspace(3)".into(), + "i8*".into(), + "{ ptr, i64 }".into(), + ], + local_linkage: Some("internal".into()), + } + ); + assert_eq!(defines["w"].ret, "void"); + assert_eq!(defines["w"].local_linkage, None); + assert_eq!(defines["p"].local_linkage.as_deref(), Some("private")); + assert_eq!(defines["l"].local_linkage.as_deref(), Some("linkonce_odr")); + assert_eq!(defines["quoted name"].params, Vec::::new()); + assert_eq!(defines["quoted name"].local_linkage, None); +} + +#[test] +fn implementation_symbols_are_checked_against_the_abi_table() { + let descriptions = tilelib_relu_descriptions(); + check_implementation_symbols(TILELIB_RELU_LL, &descriptions).unwrap(); + + // The legacy LLVM 7 dialect spells every pointer `i8*`. + let legacy = TILELIB_RELU_LL.replace("ptr %v", "i8* %v"); + check_implementation_symbols(&legacy, &descriptions).unwrap(); + + // A missing symbol names what the module does define. + let renamed = TILELIB_RELU_LL.replace("@relu_impl(", "@relu("); + let problems = check_implementation_symbols(&renamed, &descriptions).unwrap_err(); + assert_eq!(problems.len(), 1, "{problems:?}"); + assert!( + problems[0].contains("no `define ... @relu_impl(`"), + "{problems:?}" + ); + assert!(problems[0].contains("@scale_in_place_impl"), "{problems:?}"); + + // Every mismatch is reported, symbol by symbol: a wrong scalar type, a + // by-value parameter where a pointer is predicted, a non-void return. + let wrong = TILELIB_RELU_LL + .replace( + "@relu_impl(float %v0, ptr %v1)", + "@relu_impl(double %v0, ptr %v1)", + ) + .replace( + "void @scale_in_place_impl(ptr %v0, float %v1)", + "float @scale_in_place_impl(float %v0, float %v1)", + ); + let problems = check_implementation_symbols(&wrong, &descriptions).unwrap_err(); + assert_eq!(problems.len(), 3, "{problems:?}"); + assert!( + problems[0].contains("`relu_impl`: parameter 0 (`x`) is `double`") + && problems[0].contains("predicts `float`"), + "{problems:?}" + ); + assert!( + problems[1].contains("`scale_in_place_impl`: returns `float`"), + "{problems:?}" + ); + assert!( + problems[2].contains("`scale_in_place_impl`: parameter 0 (`x`) is `float`") + && problems[2].contains("predicts `ptr"), + "{problems:?}" + ); + + // A parameter count mismatch is one problem with both lists. + let short = TILELIB_RELU_LL.replace( + "@warp_sum_impl(float %v0, ptr %v1)", + "@warp_sum_impl(float %v0)", + ); + let problems = check_implementation_symbols(&short, &descriptions).unwrap_err(); + assert_eq!(problems.len(), 1, "{problems:?}"); + assert!( + problems[0].contains("`warp_sum_impl`: 1 parameter(s) in the module (float), 2 in the description (float, ptr"), + "{problems:?}" + ); + + // A definition the module does not export cannot be linked as + // `.extern .func`, however right its signature is. + let hidden = TILELIB_RELU_LL + .replace( + "define void @relu_impl(", + "define internal void @relu_impl(", + ) + .replace( + "define void @warp_sum_impl(", + "define linkonce_odr void @warp_sum_impl(", + ); + let problems = check_implementation_symbols(&hidden, &descriptions).unwrap_err(); + assert_eq!(problems.len(), 2, "{problems:?}"); + assert!( + problems[0].contains("`relu_impl`: defined with `internal` linkage") + && problems[0].contains("not externally visible") + && problems[0].contains(".extern .func"), + "{problems:?}" + ); + assert!( + problems[1].contains("`warp_sum_impl`: defined with `linkonce_odr` linkage"), + "{problems:?}" + ); +} + +/// The capability decision reads `tileiras --list-versions` through +/// the command's own lookup, so the stand-ins here are executables, not +/// listings: that is the seam the command uses. +#[cfg(unix)] +#[test] +fn tileiras_capability_follows_the_listed_bytecode_versions() { + use super::tilelib::list_bytecode_versions; + use oxide_tilebc::BytecodeVersion; + use std::os::unix::fs::PermissionsExt; + + let root = unique_temp_dir("cargo_oxide_tileiras"); + fs::create_dir_all(&root).unwrap(); + let stand_in = |name: &str, body: &str| -> PathBuf { + let path = root.join(name); + fs::write(&path, format!("#!/bin/sh\n{body}\n")).unwrap(); + fs::set_permissions(&path, fs::Permissions::from_mode(0o755)).unwrap(); + path + }; + + // CUDA 13.4's assembler. + let old = stand_in("tileiras-13.4", "printf '13.1\\n13.2\\n13.3\\n13.4\\n'"); + let versions = list_bytecode_versions(&old).unwrap(); + assert_eq!( + versions.iter().map(ToString::to_string).collect::>(), + ["13.1", "13.2", "13.3", "13.4"] + ); + assert!(super::tilelib::description_version(&versions).is_none()); + // The first assembler that reads the preview content; the header tag + // bits are not part of a release. + let new = stand_in( + "tileiras-13.5", + "printf '13.1\\n13.2\\n13.3\\n13.4\\n13.5\\n'", + ); + assert_eq!( + super::tilelib::description_version(&list_bytecode_versions(&new).unwrap()), + Some(BytecodeVersion::PREVIEW_FIRST) + ); + assert_eq!(BytecodeVersion::PREVIEW_FIRST.to_string(), "13.5"); + // The descriptions are written at the assembler's current version, the + // newest numbered one it lists: a newer assembler gets its own version + // (a named build such as `internal` is not a version), a 13.5.1 listing + // names 13.5, and a 13.4 listing names nothing. + let dev = stand_in( + "tileiras-newer", + "printf '13.1\\n13.2\\n13.3\\n13.4\\n13.5\\n13.6\\ninternal\\n'", + ); + assert_eq!( + super::tilelib::description_version(&list_bytecode_versions(&dev).unwrap()) + .map(|version| version.to_string()), + Some("13.6".to_string()) + ); + assert_eq!( + super::tilelib::description_version(&[BytecodeVersion::new(13, 5)]), + Some(BytecodeVersion::PREVIEW_FIRST) + ); + assert_eq!( + super::tilelib::description_version(&list_bytecode_versions(&old).unwrap()), + None + ); + // An assembler without the flag prints a usage message and exits 1: it + // lists nothing, which is not an error. + let legacy = stand_in( + "tileiras-13.1", + "echo 'tileiras: unknown option --list-versions' >&2; exit 1", + ); + assert_eq!(list_bytecode_versions(&legacy).unwrap(), Vec::new()); + assert!(super::tilelib::description_version(&[]).is_none()); + // A configured tileiras that cannot be run is an error naming the path + // and the OS error, not an old assembler. + let missing = root.join("no-such-tileiras"); + let error = list_bytecode_versions(&missing).unwrap_err(); + assert_eq!(error.kind(), std::io::ErrorKind::NotFound); + let message = error.to_string(); + assert!( + message.contains(&missing.display().to_string()) + && message.contains("--list-versions") + && message.contains("os error"), + "{message}" + ); + // The exit policy when no library was created. + assert_eq!(no_library_exit_code(true), 0); + assert_eq!(no_library_exit_code(false), 2); + fs::remove_dir_all(root).unwrap(); +} + +#[test] +fn tilelib_paths_and_the_tileiras_invocation_follow_the_crate_stem() { + let dir = Path::new("/tmp/cargo-oxide-tilelib"); + let paths = TileLibraryPaths::new(dir, "my-lib", None); + assert_eq!(paths.ll, dir.join("my_lib.ll")); + assert_eq!(paths.descriptions, dir.join("my_lib.tileexports.json")); + assert_eq!(paths.ltoir, dir.join("my_lib.ltoir")); + assert_eq!(paths.interface, dir.join("my_lib.iface.tilebc")); + assert_eq!(paths.implementation, dir.join("my_lib.impl.tilebc")); + assert_eq!(paths.dump, dir.join("my_lib.tilelib.mlir")); + assert_eq!(paths.library, dir.join("my_lib.tilelib")); + let custom = TileLibraryPaths::new(dir, "my-lib", Some(Path::new("out/lib.tilelib"))); + assert_eq!(custom.library, PathBuf::from("out/lib.tilelib")); + + // The invocation the Tile IR repository documents for creating a + // library: interface, implementation catalog, code payload, output. + assert_eq!( + create_tile_lib_command(Path::new("/opt/cuda/bin/tileiras"), &custom), + [ + "/opt/cuda/bin/tileiras", + "--preview-create-tile-lib", + "--preview-interface=/tmp/cargo-oxide-tilelib/my_lib.iface.tilebc", + "--preview-implementation=/tmp/cargo-oxide-tilelib/my_lib.impl.tilebc", + "--preview-implementation=/tmp/cargo-oxide-tilelib/my_lib.ltoir", + "-o", + "out/lib.tilelib", + ] + ); + // tileiras resolves like every other toolkit tool. + for path in TILEIRAS_FALLBACK_PATHS { + assert_eq!( + Path::new(path).file_name().and_then(|n| n.to_str()), + Some("tileiras") + ); + } +} + +#[test] +fn tilelib_artifacts_are_cleaned_between_builds() { + // A stale library or description must not outlive the build that + // produced it, so every suffix the command writes is a generated + // artifact. + for suffix in [ + TILELIB_INTERFACE_SUFFIX, + TILELIB_IMPLEMENTATION_SUFFIX, + TILELIB_DUMP_SUFFIX, + TILELIB_LIBRARY_SUFFIX, + ] { + assert!(GENERATED_ARTIFACT_SUFFIXES.contains(&suffix), "{suffix}"); + } + let root = unique_temp_dir("cargo_oxide_tilelib_clean"); + std::fs::create_dir_all(&root).unwrap(); + let files: Vec<_> = ["iface.tilebc", "impl.tilebc", "tilelib.mlir", "tilelib"] + .iter() + .map(|suffix| root.join(format!("my_lib.{suffix}"))) + .collect(); + for file in &files { + std::fs::write(file, b"stale").unwrap(); + } + clean_generated_files(&root, "my-lib"); + for file in &files { + assert!(!file.exists(), "{} survived the clean", file.display()); + } + std::fs::remove_dir_all(root).unwrap(); +} + +/// The smoketest's tilelib lane greps the summary lines: the descriptions +/// marker for proof that the descriptions were written before the host +/// program ran, and the two library markers to decide whether a `.tilelib` +/// is required, instead of probing tileiras itself. The script and the +/// command have to name the same text. +#[test] +fn the_smoketest_greps_the_summary_markers_this_command_prints() { + const SMOKETEST: &str = include_str!("../../../../scripts/smoketest.sh"); + for marker in [ + DESCRIPTIONS_WRITTEN_MARKER, + LIBRARY_WRITTEN_MARKER, + LIBRARY_SKIPPED_MARKER, + ] { + assert!( + SMOKETEST.contains(&format!("grep -qF '{marker}'")), + "scripts/smoketest.sh no longer greps {marker:?}" + ); + } + // Each grep must hit only its own line: the library markers must not be + // substrings of the descriptions line, which every run prints. + assert!(!DESCRIPTIONS_WRITTEN_MARKER.contains(LIBRARY_WRITTEN_MARKER)); + assert!(!DESCRIPTIONS_WRITTEN_MARKER.contains(LIBRARY_SKIPPED_MARKER)); + assert!(!LIBRARY_WRITTEN_MARKER.contains(LIBRARY_SKIPPED_MARKER)); +} diff --git a/cuda-oxide/crates/cargo-oxide/src/commands/tilelib.rs b/cuda-oxide/crates/cargo-oxide/src/commands/tilelib.rs new file mode 100644 index 0000000000..025d33dbc8 --- /dev/null +++ b/cuda-oxide/crates/cargo-oxide/src/commands/tilelib.rs @@ -0,0 +1,928 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +//! `cargo oxide tilelib`: package a crate's `#[tile_export]` functions as a +//! cuTile tile library. +//! +//! ```text +//! emit-ltoir ──> .ltoir .ll .tileexports.json +//! │ │ +//! define @(...) checked against abi_params() +//! │ +//! TileExportDesc ──> oxide-tilebc Declaration + Implementation +//! │ +//! .iface.tilebc .impl.tilebc .tilelib.mlir +//! │ +//! tileiras --preview-create-tile-lib (lists 13.5 or newer) ──> .tilelib +//! ``` +//! +//! The descriptions are Tile IR public-preview content, which exists from +//! bytecode 13.5 on and which an assembler reads only at the version it +//! calls current, the newest numbered version its `--list-versions` prints. +//! The command therefore asks the installed tileiras first and writes the +//! descriptions at that version (13.5 for the CUDA 13.5 assembler, and the +//! newer version a newer one names), or at 13.5 when no assembler can read +//! them yet. An older +//! assembler stops the command after the descriptions with an explanation; +//! `--library-optional` makes that outcome a success. Either way the summary +//! ends with one of two lines scripts can read: [`LIBRARY_WRITTEN_MARKER`] +//! or [`LIBRARY_SKIPPED_MARKER`]. + +use std::collections::BTreeMap; +use std::path::{Path, PathBuf}; +use std::process::Command; + +use oxide_tile_export::{ + AbiParamKind, DESCRIPTIONS_SUFFIX, TileAccess, TileElem, TileExportDesc, TileSync, +}; +use oxide_tilebc::{ + Access, BytecodeVersion, Declaration, FragmentArg, FragmentType, Implementation, Layout, + Library, MemorySpace, ScalarType, Synchronization, TileArg, TileType, +}; + +use super::*; + +/// cuTile's own override for the assembler, honoured here so one variable +/// selects the same `tileiras` for both tools. +pub(super) const TILEIRAS_PATH_ENV: &str = "CUTILE_TILEIRAS_PATH"; + +/// Suffix of the interface bytecode (`preview$func extern` declarations). +pub(super) const TILELIB_INTERFACE_SUFFIX: &str = "iface.tilebc"; +/// Suffix of the implementation catalog bytecode (`preview$extern_impl`). +pub(super) const TILELIB_IMPLEMENTATION_SUFFIX: &str = "impl.tilebc"; +/// Suffix of the readable dump of both modules. +pub(super) const TILELIB_DUMP_SUFFIX: &str = "tilelib.mlir"; +/// Suffix of the library `tileiras` assembles from the three inputs. +pub(super) const TILELIB_LIBRARY_SUFFIX: &str = "tilelib"; + +/// Fallback locations probed for `tileiras`, in the idiom of the other +/// toolkit tools. It ships in the toolkit's `bin/` beside `nvcc`. +pub(super) const TILEIRAS_FALLBACK_PATHS: &[&str] = &[ + "/usr/local/cuda/bin/tileiras", + "/opt/cuda/bin/tileiras", + "/usr/bin/tileiras", +]; + +/// The line the summary prints once both bytecode halves exist. Scripts +/// grep for it (the smoketest's tilelib lane), so it is a constant here. +pub(super) const DESCRIPTIONS_WRITTEN_MARKER: &str = "Tile library descriptions written"; + +/// The line the summary ends with when tileiras wrote the `.tilelib`; the +/// path and size follow it. The smoketest requires the library when it +/// sees this line, so the script and the command share the text. +pub(super) const LIBRARY_WRITTEN_MARKER: &str = "Tile library written to"; + +/// The line the summary ends with when no library was written, followed by +/// the tileiras that was found and the bytecode versions it lists (or that +/// none was found). The smoketest accepts the lane without a `.tilelib` only +/// when it sees this line. +pub(super) const LIBRARY_SKIPPED_MARKER: &str = "Tile library skipped"; + +// ============================================================================= +// tilelib command +// ============================================================================= + +/// Package a crate's `#[tile_export]` functions as a cuTile tile library. +/// +/// Runs [`emit_ltoir`] for the device half, checks that the emitted NVVM IR +/// defines every implementation symbol with the parameter list the ABI table +/// predicts, maps the descriptions to oxide-tilebc's model, writes the +/// interface and implementation bytecode plus a readable dump, and asks +/// `tileiras --preview-create-tile-lib` for the library when the installed +/// assembler lists bytecode 13.5 or newer, writing the descriptions at its +/// current version. Exits 1 on any error, including a tileiras that cannot +/// be run; exits 2 when no library could be created and `library_optional` +/// was not passed. +#[allow(clippy::too_many_arguments)] +pub fn tilelib( + ctx: &Context, + example: &str, + arch: &str, + features: Option<&str>, + output: Option<&Path>, + library_optional: bool, + print: bool, + verbose: bool, + no_fmad: bool, + unchecked_indexing: bool, + device_debug: DeviceDebug, +) { + let example_dir = if ctx.is_workspace { + resolve_example_dir(ctx, example) + } else { + ctx.workspace_root.clone() + }; + + // Step 1: the device half. Exits on a build or libNVVM failure, and + // clears stale descriptions and libraries before building. + emit_ltoir( + ctx, + example, + arch, + features, + None, + verbose, + no_fmad, + unchecked_indexing, + device_debug, + ); + + let paths = TileLibraryPaths::new(&example_dir, example, output); + let descriptions = read_descriptions(&paths.descriptions, example).unwrap_or_else(|error| { + eprintln!("Error: {error}"); + std::process::exit(1); + }); + + // Step 2: the LTOIR must define what the descriptions promise. The + // producer side of tileiras never looks inside the code payload, so a + // missing or misdeclared symbol would otherwise surface only when a + // cuTile program is compiled against the library. + let ll = std::fs::read_to_string(&paths.ll).unwrap_or_else(|error| { + eprintln!( + "Error: could not read the emitted NVVM IR at {}: {error}", + paths.ll.display() + ); + std::process::exit(1); + }); + if let Err(problems) = check_implementation_symbols(&ll, &descriptions) { + eprintln!( + "Error: {} does not define every implementation the descriptions name:", + paths.ll.display() + ); + for problem in problems { + eprintln!(" {problem}"); + } + std::process::exit(1); + } + + // Step 3: descriptions to Tile IR, verified the way the consumer will. + let stem = artifact_stem(example); + let library = TileLibrary::from_descriptions(&descriptions) + .unwrap_or_else(|error| { + eprintln!("Error: {error}"); + std::process::exit(1); + }) + .library(&stem); + library.verify().unwrap_or_else(|error| { + eprintln!("Error: the tile library does not verify: {error}"); + std::process::exit(1); + }); + + // The assembler decides the bytecode version. Preview content is read + // only at the version an assembler calls current (the newest numbered + // version it lists), so the descriptions are written at that version + // when the installed tileiras can build a library, and at 13.5, the + // first version with preview content, when no assembler can read them + // yet. A tileiras that was named (CUTILE_TILEIRAS_PATH, the toolkit + // root) or found but cannot be started is a configuration error, not an + // old assembler: only a run that lists nothing means "predates + // --list-versions". The error names the path and the OS error. + let tileiras = find_tileiras(ctx); + let versions = match &tileiras { + Some(tileiras) => list_bytecode_versions(tileiras).unwrap_or_else(|error| { + eprintln!("Error: {error}"); + std::process::exit(1); + }), + None => Vec::new(), + }; + let library_version = description_version(&versions); + let version = library_version.unwrap_or(BytecodeVersion::PREVIEW_FIRST); + let interface_bytes = library.interface_bytecode(version).unwrap_or_else(|error| { + eprintln!("Error: could not serialize the interface module: {error}"); + std::process::exit(1); + }); + let implementation_bytes = library + .implementation_bytecode(version) + .unwrap_or_else(|error| { + eprintln!("Error: could not serialize the implementation module: {error}"); + std::process::exit(1); + }); + let dump = library_dump(&library, &stem); + for (path, bytes) in [ + (&paths.interface, interface_bytes.as_slice()), + (&paths.implementation, implementation_bytes.as_slice()), + (&paths.dump, dump.as_bytes()), + ] { + std::fs::write(path, bytes).unwrap_or_else(|error| { + eprintln!("Error: could not write {}: {error}", path.display()); + std::process::exit(1); + }); + } + if print { + println!(); + print!("{dump}"); + } + + println!(); + println!( + "✓ {DESCRIPTIONS_WRITTEN_MARKER}: {} export(s), Tile IR {version} with the preview tag", + descriptions.len(), + ); + println!( + " {} ({} bytes)", + paths.interface.display(), + interface_bytes.len() + ); + println!( + " {} ({} bytes)", + paths.implementation.display(), + implementation_bytes.len() + ); + println!(" {} (readable form of both)", paths.dump.display()); + + // Step 4: the library itself, when the installed assembler can build one. + let (Some(tileiras), Some(version)) = (tileiras.as_deref(), library_version) else { + explain_no_library(&paths, tileiras.as_deref(), &versions); + std::process::exit(no_library_exit_code(library_optional)); + }; + + let command = create_tile_lib_command(tileiras, &paths); + println!(); + println!( + "tileiras {} lists bytecode {version} as its current version; creating the tile library:", + tileiras.display(), + ); + println!(" {}", render_command(&command)); + let output = Command::new(&command[0]) + .args(&command[1..]) + .output() + .unwrap_or_else(|error| { + eprintln!("Error: could not run {}: {error}", tileiras.display()); + std::process::exit(1); + }); + if !output.status.success() { + eprintln!( + "Error: tileiras --preview-create-tile-lib exited with {}", + output.status + ); + eprint!("{}", String::from_utf8_lossy(&output.stderr)); + std::process::exit(1); + } + let size = std::fs::metadata(&paths.library) + .map(|meta| meta.len()) + .unwrap_or(0); + println!(); + println!( + "✓ {LIBRARY_WRITTEN_MARKER} {} ({size} bytes)", + paths.library.display() + ); +} + +/// Every file the command reads or writes for one crate. +pub(super) struct TileLibraryPaths { + /// The NVVM IR the backend emitted, checked for the implementation symbols. + pub(super) ll: PathBuf, + /// The `#[tile_export]` descriptions the backend wrote next to the `.ll`. + pub(super) descriptions: PathBuf, + /// The LTOIR `emit_ltoir` wrote; the code payload of the library. + pub(super) ltoir: PathBuf, + /// The interface bytecode. + pub(super) interface: PathBuf, + /// The implementation catalog bytecode. + pub(super) implementation: PathBuf, + /// The readable dump of both modules. + pub(super) dump: PathBuf, + /// The library `tileiras` writes; `-o` overrides the default. + pub(super) library: PathBuf, +} + +impl TileLibraryPaths { + pub(super) fn new(example_dir: &Path, example: &str, library: Option<&Path>) -> Self { + let stem = artifact_stem(example); + Self { + ll: emitted_ll_path(example_dir, example), + descriptions: example_dir.join(format!("{stem}.{DESCRIPTIONS_SUFFIX}")), + ltoir: default_ltoir_path(example_dir, example), + interface: example_dir.join(format!("{stem}.{TILELIB_INTERFACE_SUFFIX}")), + implementation: example_dir.join(format!("{stem}.{TILELIB_IMPLEMENTATION_SUFFIX}")), + dump: example_dir.join(format!("{stem}.{TILELIB_DUMP_SUFFIX}")), + library: library + .map(Path::to_path_buf) + .unwrap_or_else(|| example_dir.join(format!("{stem}.{TILELIB_LIBRARY_SUFFIX}"))), + } + } +} + +/// The descriptions the backend wrote, validated. A crate without +/// `#[tile_export]` functions has no descriptions file at all, which is the +/// common mistake and gets the direct message. +fn read_descriptions(path: &Path, example: &str) -> Result, String> { + let text = match std::fs::read_to_string(path) { + Ok(text) => text, + Err(error) if error.kind() == std::io::ErrorKind::NotFound => { + return Err(format!( + "no #[tile_export] functions in {example}: the build wrote no {} (a tile \ + library needs at least one exported function)", + path.display() + )); + } + Err(error) => return Err(format!("could not read {}: {error}", path.display())), + }; + let descriptions = oxide_tile_export::descriptions_from_json(&text) + .map_err(|error| format!("could not parse {}: {error}", path.display()))?; + if descriptions.is_empty() { + return Err(format!( + "no #[tile_export] functions in {example}: {} describes no exports", + path.display() + )); + } + for description in &descriptions { + description.validate().map_err(|error| { + format!( + "description of `{}` in {}: {error}", + description.decl, + path.display() + ) + })?; + } + Ok(descriptions) +} + +// ============================================================================= +// Descriptions to Tile IR +// ============================================================================= + +/// A crate's exports as the two halves of a tile library. +#[derive(Debug)] +pub(super) struct TileLibrary { + /// One `preview$func extern` declaration per export. + pub(super) funcs: Vec, + /// One `preview$extern_impl` per export. + pub(super) impls: Vec, +} + +impl TileLibrary { + /// Map every description; the first one that cannot be described stops + /// the command with its reason. + pub(super) fn from_descriptions(descriptions: &[TileExportDesc]) -> Result { + let mut funcs = Vec::with_capacity(descriptions.len()); + let mut impls = Vec::with_capacity(descriptions.len()); + for description in descriptions { + let (func, implementation) = describe_export(description) + .map_err(|error| format!("export `{}`: {error}", description.decl))?; + funcs.push(func); + impls.push(implementation); + } + Ok(Self { funcs, impls }) + } + + /// Both halves under one module name, ready to verify and write. + pub(super) fn library(&self, name: &str) -> Library { + Library::new(name, self.funcs.clone(), self.impls.clone()) + } +} + +/// One export as its declaration and its implementation. +/// +/// Every parameter becomes a tile of the export's shape on the declaration +/// and a fragment on the implementation: a by-value scalar is the rank-0 +/// `():()` buffer, everything else a contiguous footprint `(F):(1)`. The +/// fragmap is shared by all parameters, see [`fragmap`]. A `bf16` scalar +/// passed by value needs the `bf16 = i16` frontend ABI entry because +/// cuda-device's bf16 is a `u16` wrapper, so the LLVM parameter is `i16` +/// while the tile element is `bf16`. +pub(super) fn describe_export( + desc: &TileExportDesc, +) -> Result<(Declaration, Implementation), String> { + desc.validate().map_err(|error| error.to_string())?; + let tile_size = desc.shape[0]; + // Every parameter is a fragment of a tile of the same shape and the + // fragmaps of one implementation share their invocation count, so the + // footprints have to agree: a 4-element window beside a scalar would + // need 32 invocations for one argument and 128 for the other. + let footprint = desc.params[0].footprint; + if let Some(other) = desc + .params + .iter() + .find(|param| param.footprint != footprint) + { + return Err(format!( + "parameters `{}` (footprint {}) and `{}` (footprint {}) differ; every parameter \ + of one export shares the invocation count, so all footprints must be equal", + desc.params[0].name, footprint, other.name, other.footprint + )); + } + let mut args = Vec::with_capacity(desc.params.len()); + let mut fragments = Vec::with_capacity(desc.params.len()); + for param in &desc.params { + let element = scalar_type(param.elem); + let access = access(param.access); + args.push(TileArg::new( + param.name.clone(), + TileType::new(desc.shape.clone(), element), + access, + )); + let footprint = i64::from(param.footprint); + let fragmap = fragmap(desc.sync, tile_size, footprint) + .map_err(|error| format!("parameter `{}`: {error}", param.name))?; + let (shape, mem_layout) = if param.by_value { + (vec![1], Layout::scalar_mem()) + } else { + (vec![footprint], Layout::contiguous_mem(footprint)) + }; + fragments.push(FragmentArg::new( + param.name.clone(), + FragmentType::new(shape, element, MemorySpace::Local, mem_layout, fragmap), + access, + )); + } + let mut implementation = Implementation::new(desc.symbol.clone(), desc.decl.clone(), fragments); + implementation.synchronization = synchronization(desc.sync); + implementation.arch = desc.arch.clone(); + if desc + .params + .iter() + .any(|param| param.by_value && param.elem == TileElem::BF16) + { + implementation.frontend_abi = vec![("bf16".to_string(), "i16".to_string())]; + } + Ok((Declaration::new(desc.decl.clone(), args), implementation)) +} + +/// How one invocation's footprint maps onto the tile. +/// +/// Without synchronization every invocation owns `footprint` contiguous +/// elements: `(N, 1, 1):(1, 0, 0)` for a footprint of one, `(N/F, 1, F):(F, +/// 0, 1)` otherwise. With `sync = warp` the 32 lanes of a warp are the +/// participants of one invocation: `(N/32, 32, 1):(32, 1, 0)` for a footprint +/// of one, and `(N/(32F), 32, F):(32F, F, 1)` for a footprint of `F`, so each +/// lane keeps a contiguous footprint and adjacent lanes are adjacent in the +/// tile. The footprint must divide the tile size in either case. +pub(super) fn fragmap(sync: TileSync, tile_size: i64, footprint: i64) -> Result { + if footprint <= 0 { + return Err(format!("footprint {footprint} must be positive")); + } + if tile_size % footprint != 0 { + return Err(format!( + "footprint {footprint} does not divide the tile size {tile_size}" + )); + } + match sync { + TileSync::None if footprint == 1 => Ok(Layout::elementwise(tile_size)), + TileSync::None => Ok(Layout::footprint_blocks(tile_size, footprint)), + TileSync::Warp => { + let per_warp = 32 * footprint; + if tile_size % per_warp != 0 { + return Err(format!( + "sync = warp with footprint {footprint} needs a tile size that is a \ + multiple of {per_warp}, found {tile_size}" + )); + } + if footprint == 1 { + Ok(Layout::warp_lanes(tile_size)) + } else { + Ok(Layout::flat( + &[tile_size / per_warp, 32, footprint], + &[per_warp, footprint, 1], + )) + } + } + } +} + +/// Tile IR has no unsigned integers; the unsigned Rust types are the signless +/// `iN` of the same width. +fn scalar_type(elem: TileElem) -> ScalarType { + match elem { + TileElem::F16 => ScalarType::F16, + TileElem::BF16 => ScalarType::BF16, + TileElem::F32 => ScalarType::F32, + TileElem::F64 => ScalarType::F64, + TileElem::I8 | TileElem::U8 => ScalarType::I8, + TileElem::I16 | TileElem::U16 => ScalarType::I16, + TileElem::I32 | TileElem::U32 => ScalarType::I32, + TileElem::I64 | TileElem::U64 => ScalarType::I64, + } +} + +fn access(access: TileAccess) -> Access { + match access { + TileAccess::In => Access::In, + TileAccess::Out => Access::Out, + TileAccess::InOut => Access::InOut, + } +} + +/// The implementation's `synchronization` clause. An export without `sync` +/// gets no clause at all rather than an explicit `synchronization`: +/// the two mean the same thing, and leaving it out keeps the printed and +/// written form identical to an upstream module parsed without the clause. +fn synchronization(sync: TileSync) -> Option { + match sync { + TileSync::None => None, + TileSync::Warp => Some(Synchronization::Warp), + } +} + +/// The readable form of both modules, one dump so a reader sees the +/// declaration and its implementation together. Lines starting with `//` +/// are comments in the Tile IR textual syntax. +pub(super) fn library_dump(library: &Library, stem: &str) -> String { + format!( + "// {stem}.{TILELIB_INTERFACE_SUFFIX}: the interface a cuTile program calls\n{}\ + // {stem}.{TILELIB_IMPLEMENTATION_SUFFIX}: the implementations the LTOIR defines\n{}", + library.interface_text(), + library.implementation_text() + ) +} + +/// The bytecode versions `tileiras --list-versions` names, one per line. +/// +/// A launch failure is returned as the error it is, with the path in the +/// message. An assembler that ran but predates the flag exits non-zero or +/// prints a usage message instead of versions; both give an empty list. +/// Lines that are not versions (an assembler may list a named build next +/// to the numbers) are skipped. +pub(super) fn list_bytecode_versions(tileiras: &Path) -> std::io::Result> { + let output = Command::new(tileiras) + .arg("--list-versions") + .output() + .map_err(|error| { + std::io::Error::new( + error.kind(), + format!( + "could not run {} --list-versions: {error}", + tileiras.display() + ), + ) + })?; + if !output.status.success() { + return Ok(Vec::new()); + } + Ok(String::from_utf8_lossy(&output.stdout) + .lines() + .filter_map(BytecodeVersion::parse) + .collect()) +} + +// ============================================================================= +// Implementation symbols in the emitted NVVM IR +// ============================================================================= + +/// One `define` of an LLVM IR module, reduced to what the ABI check reads. +#[derive(Debug, Clone, PartialEq, Eq)] +pub(super) struct LlDefine { + /// The return type, with linkage and calling-convention keywords removed. + pub(super) ret: String, + /// One type per parameter, names and parameter attributes removed. + pub(super) params: Vec, + /// A linkage keyword from [`LL_LOCAL_LINKAGE`] on the define, if any. + pub(super) local_linkage: Option, +} + +/// Linkages that keep a definition out of what the module exports. The Tile +/// compiler reaches an implementation as `.extern .func`, so a definition +/// with one of these is a reported problem, not a stripped keyword. +const LL_LOCAL_LINKAGE: &[&str] = &["private", "internal", "linkonce", "linkonce_odr"]; + +/// Keywords that can sit between `define` and the return type without +/// changing whether the symbol can be linked. +const LL_DEFINE_KEYWORDS: &[&str] = &[ + "available_externally", + "weak", + "common", + "appending", + "extern_weak", + "weak_odr", + "external", + "dso_local", + "dso_preemptable", + "default", + "hidden", + "protected", + "ptx_kernel", + "ptx_device", + "fastcc", + "coldcc", + "ccc", +]; + +/// Every `define ... @name(params)` of `ll`, keyed by symbol. Textual IR is +/// the robust place to check symbols: the LTOIR is an NVVM bitcode container +/// with no stable public reader, and the `.ll` beside it is what libNVVM +/// compiled. +pub(super) fn ll_defines(ll: &str) -> BTreeMap { + let mut defines = BTreeMap::new(); + for line in ll.lines() { + let Some(rest) = line.trim_start().strip_prefix("define ") else { + continue; + }; + let Some(at) = rest.find('@') else { + continue; + }; + let (prefix, after_at) = rest.split_at(at); + let after_at = &after_at[1..]; + let Some(open) = after_at.find('(') else { + continue; + }; + let name = after_at[..open].trim().trim_matches('"').to_string(); + let Some(params) = balanced_parameter_list(&after_at[open..]) else { + continue; + }; + let local_linkage = prefix + .split_whitespace() + .find(|token| LL_LOCAL_LINKAGE.contains(token)) + .map(str::to_string); + let ret = prefix + .split_whitespace() + .filter(|token| { + !LL_DEFINE_KEYWORDS.contains(token) && !LL_LOCAL_LINKAGE.contains(token) + }) + .collect::>() + .join(" "); + defines.insert( + name, + LlDefine { + ret, + params: split_top_level(params) + .into_iter() + .map(parameter_type) + .collect(), + local_linkage, + }, + ); + } + defines +} + +/// The text inside the parentheses that open `text`, honoring nesting. +fn balanced_parameter_list(text: &str) -> Option<&str> { + let mut depth = 0i32; + for (index, c) in text.char_indices() { + match c { + '(' | '[' | '{' | '<' => depth += 1, + ')' | ']' | '}' | '>' => { + depth -= 1; + if depth == 0 { + return Some(&text[1..index]); + } + } + _ => {} + } + } + None +} + +/// Split on commas outside any bracket pair. +fn split_top_level(text: &str) -> Vec<&str> { + let mut parts = Vec::new(); + let mut depth = 0i32; + let mut start = 0; + for (index, c) in text.char_indices() { + match c { + '(' | '[' | '{' | '<' => depth += 1, + ')' | ']' | '}' | '>' => depth -= 1, + ',' if depth == 0 => { + parts.push(&text[start..index]); + start = index + 1; + } + _ => {} + } + } + let last = &text[start..]; + if !last.trim().is_empty() { + parts.push(last); + } + parts +} + +/// The type of one parameter: its tokens without the `%name` and without +/// parameter attributes. +fn parameter_type(param: &str) -> String { + const ATTRIBUTES: &[&str] = &[ + "noundef", + "nonnull", + "noalias", + "nocapture", + "readonly", + "writeonly", + "readnone", + "signext", + "zeroext", + "inreg", + "returned", + "nofree", + "nest", + "immarg", + ]; + param + .split_whitespace() + .filter(|token| !token.starts_with('%')) + .filter(|token| !ATTRIBUTES.contains(token)) + .filter(|token| !token.starts_with("align") && !token.starts_with("dereferenceable")) + .collect::>() + .join(" ") +} + +/// Whether an LLVM parameter type is the one the ABI predicts. A pointer is +/// the opaque `ptr` on the modern NVVM path and a typed pointer (`i8*`) in +/// the legacy LLVM 7 dialect of pre-Blackwell targets; the pointee type +/// carries no ABI information, so any typed pointer passes. +fn llvm_type_matches(actual: &str, kind: AbiParamKind) -> bool { + match kind { + AbiParamKind::Scalar(elem) => actual == elem.llvm_name(), + AbiParamKind::Pointer(_) => actual == "ptr" || actual.ends_with('*'), + } +} + +/// The type text the message quotes for an expected parameter. +fn expected_type_text(kind: AbiParamKind) -> String { + match kind { + AbiParamKind::Scalar(elem) => elem.llvm_name().to_string(), + AbiParamKind::Pointer(_) => "ptr (i8* on the legacy path)".to_string(), + } +} + +/// Check that `ll` defines every description's implementation symbol as a +/// `void` function whose parameters are the ones [`TileExportDesc::abi_params`] +/// predicts. Every mismatch is reported, symbol by symbol. +pub(super) fn check_implementation_symbols( + ll: &str, + descriptions: &[TileExportDesc], +) -> Result<(), Vec> { + let defines = ll_defines(ll); + let mut problems = Vec::new(); + for desc in descriptions { + let Some(define) = defines.get(&desc.symbol) else { + let defined: Vec<_> = defines.keys().map(|name| format!("@{name}")).collect(); + problems.push(format!( + "`{}` (implementation of `{}`): no `define ... @{}(` in the module; it defines {}", + desc.symbol, + desc.decl, + desc.symbol, + if defined.is_empty() { + "no functions".to_string() + } else { + defined.join(", ") + } + )); + continue; + }; + if let Some(linkage) = &define.local_linkage { + problems.push(format!( + "`{}`: defined with `{linkage}` linkage, so it is not externally visible; \ + the Tile compiler links it as .extern .func", + desc.symbol + )); + } + if define.ret != "void" { + problems.push(format!( + "`{}`: returns `{}`, but a tile library implementation returns void and \ + writes its result through the trailing out pointer", + desc.symbol, define.ret + )); + } + let expected = desc.abi_params(); + if define.params.len() != expected.len() { + problems.push(format!( + "`{}`: {} parameter(s) in the module ({}), {} in the description ({})", + desc.symbol, + define.params.len(), + define.params.join(", "), + expected.len(), + expected + .iter() + .map(|param| expected_type_text(param.kind)) + .collect::>() + .join(", ") + )); + continue; + } + for (index, (actual, param)) in define.params.iter().zip(&expected).enumerate() { + if !llvm_type_matches(actual, param.kind) { + problems.push(format!( + "`{}`: parameter {index} (`{}`) is `{actual}` in the module, but the \ + description predicts `{}`", + desc.symbol, + param.name, + expected_type_text(param.kind) + )); + } + } + } + if problems.is_empty() { + Ok(()) + } else { + Err(problems) + } +} + +// ============================================================================= +// tileiras +// ============================================================================= + +/// `tileiras` from cuTile's override variable (also honoured as +/// [`TILEIRAS_PATH_ENV`], so one variable selects the same assembler for +/// both products), then the toolkit lookup every other CUDA tool uses +/// (PATH, the configured toolkit root, the standard install roots). An +/// override is returned as given: whether it runs is for +/// [`list_bytecode_versions`] to report. +pub(super) fn find_tileiras(ctx: &Context) -> Option { + if let Some(path) = std::env::var_os(TILEIRAS_PATH_ENV).filter(|value| !value.is_empty()) { + return Some(PathBuf::from(path)); + } + find_cuda_toolkit_executable(ctx, "tileiras", TILEIRAS_FALLBACK_PATHS) +} + +/// The bytecode version to write the descriptions at for an assembler that +/// lists `versions`: its current version, the newest numbered one it lists, +/// when that is 13.5 or newer. An assembler reads preview content only at +/// its current version, so an older listing (CUDA 13.4 and before) means no +/// library can be built. The header tag bits are not part of a release, so +/// `13.5` and `13.5.1` both name 13.5. +pub(super) fn description_version(versions: &[BytecodeVersion]) -> Option { + versions + .iter() + .copied() + .filter(|version| *version >= BytecodeVersion::PREVIEW_FIRST) + .max() +} + +/// Exit status when no library was created because the installed assembler +/// cannot build one: a success when the caller said the library is optional, +/// and a shortfall otherwise. +pub(super) fn no_library_exit_code(library_optional: bool) -> i32 { + if library_optional { 0 } else { 2 } +} + +/// The `tileiras --preview-create-tile-lib` invocation, argv form. +pub(super) fn create_tile_lib_command(tileiras: &Path, paths: &TileLibraryPaths) -> Vec { + vec![ + tileiras.display().to_string(), + "--preview-create-tile-lib".to_string(), + format!("--preview-interface={}", paths.interface.display()), + format!( + "--preview-implementation={}", + paths.implementation.display() + ), + format!("--preview-implementation={}", paths.ltoir.display()), + "-o".to_string(), + paths.library.display().to_string(), + ] +} + +fn render_command(command: &[String]) -> String { + command.join(" ") +} + +/// The [`LIBRARY_SKIPPED_MARKER`] line naming the assembler that was found +/// and what it lists, then why that is not enough and everything a reader +/// needs to finish the job on a newer toolkit. +fn explain_no_library( + paths: &TileLibraryPaths, + tileiras: Option<&Path>, + versions: &[BytecodeVersion], +) { + let needed = BytecodeVersion::PREVIEW_FIRST; + println!(); + match tileiras { + Some(tileiras) => { + let lists = if versions.is_empty() { + "no bytecode versions (it predates --list-versions)".to_string() + } else { + format!( + "bytecode versions {}", + versions + .iter() + .map(ToString::to_string) + .collect::>() + .join(", ") + ) + }; + println!( + "{LIBRARY_SKIPPED_MARKER}: {} lists {lists}; the descriptions need {needed} or newer", + tileiras.display() + ); + println!( + "The installed tileiras cannot create tile libraries: the descriptions are \ + Tile IR public-preview content, which exists from bytecode {needed} on and \ + needs the CUDA 13.5 or newer assembler." + ); + } + None => { + println!("{LIBRARY_SKIPPED_MARKER}: no tileiras found"); + println!( + "No tileiras was found on PATH, under {TILEIRAS_PATH_ENV}, the configured CUDA \ + toolkit root or the standard install roots; creating a tile library needs the \ + CUDA 13.5 or newer assembler, the first one that lists bytecode {needed}." + ); + } + } + println!( + "The LTOIR and the descriptions were written to {}; a capable tileiras turns them \ + into {} with:", + paths + .interface + .parent() + .unwrap_or_else(|| Path::new(".")) + .display(), + paths.library.display() + ); + let placeholder = Path::new("tileiras"); + println!( + " {}", + render_command(&create_tile_lib_command(placeholder, paths)) + ); +} diff --git a/cuda-oxide/crates/cargo-oxide/src/main.rs b/cuda-oxide/crates/cargo-oxide/src/main.rs index 292bed15cd..f962661ea1 100644 --- a/cuda-oxide/crates/cargo-oxide/src/main.rs +++ b/cuda-oxide/crates/cargo-oxide/src/main.rs @@ -19,6 +19,7 @@ //! cargo oxide debug vecadd --tui # build + cuda-gdb //! cargo oxide inspect vecadd # build + print generated PTX //! cargo oxide fuzz-schedule barrier # perturb generated PTX and watchdog it +//! cargo oxide tilelib relu --arch sm_120 # #[tile_export] crate -> cuTile tile library //! cargo oxide new my_kernel # scaffold a standalone project //! cargo oxide new my_kernel --async # scaffold with async template //! cargo oxide list # list bundled examples @@ -344,6 +345,60 @@ enum Commands { #[arg(long)] unchecked_indexing: bool, }, + /// Package a crate's `#[tile_export]` functions as a cuTile tile library. + /// + /// Runs `emit-ltoir`, checks that the LTOIR defines every implementation + /// symbol with the parameters the native SIMT ABI predicts, writes the + /// Tile IR 13.5 interface and implementation bytecode + /// (`.iface.tilebc`, `.impl.tilebc`) plus a readable + /// `.tilelib.mlir`, and asks `tileiras --preview-create-tile-lib` + /// for `.tilelib` when the installed assembler lists bytecode 13.5 + /// (CUDA 13.5 or newer). An older assembler stops the command after the + /// descriptions with exit code 2 unless `--library-optional` is passed. + Tilelib { + /// Crate name (required in workspace, optional for standalone projects) + example: Option, + /// Target architecture (e.g. sm_90, sm_100, sm_120). Required: the + /// LTOIR inside the library is architecture-specific. + #[arg(long)] + arch: String, + /// Comma-separated list of features to enable + #[arg(long)] + features: Option, + /// Output path for the `.tilelib` file (default: `/.tilelib`) + #[arg(long, short)] + output: Option, + /// Succeed when the installed tileiras cannot build the .tilelib; + /// the descriptions and LTOIR are still written (without this flag + /// that case exits 2) + #[arg(long)] + library_optional: bool, + /// Print the readable form of the interface and implementation modules + #[arg(long)] + print: bool, + /// Show verbose compilation output + #[arg(short, long)] + verbose: bool, + /// Disable implicit FMA contraction in both libNVVM and nvJitLink. + /// Also settable via CUDA_OXIDE_NO_FMA=1. + #[arg(long)] + no_fmad: bool, + /// Emit device line-number information for profilers and Compute + /// Sanitizer, leaving optimization intact (nvcc `-lineinfo`). + /// Also settable via CUDA_OXIDE_DEBUG=line. + #[arg(long)] + lineinfo: bool, + /// Emit full device debug information; libNVVM finalization runs + /// unoptimized (nvcc `-G`). Supersedes --lineinfo. + /// Also settable via CUDA_OXIDE_DEBUG=full. + #[arg(long)] + device_debug: bool, + /// Elide slice/array bounds checks in every device kernel + /// (out-of-bounds indexing becomes UB, like get_unchecked). + /// Also settable via CUDA_OXIDE_UNCHECKED_INDEXING=1. + #[arg(long)] + unchecked_indexing: bool, + }, /// Show the full compilation pipeline (MIR -> PTX/NVVM IR) with verbose output Pipeline { /// Example name (required in workspace, optional for standalone projects) @@ -585,6 +640,10 @@ fn validate_materialization_cli(cli: &Cli) -> Result<(), String> { "--materialize-cubin cannot be combined with emit-ltoir; one emits a final cubin and the other emits linkable LTOIR" .to_string(), ), + Commands::Tilelib { .. } => Err( + "--materialize-cubin cannot be combined with tilelib; a tile library carries linkable LTOIR, not a final cubin" + .to_string(), + ), Commands::List { .. } => Err( "--materialize-cubin cannot be used with list because list does not compile device code" .to_string(), @@ -985,6 +1044,35 @@ fn main() { commands::DeviceDebug::from_flags(lineinfo, device_debug), ); } + Commands::Tilelib { + example, + arch, + features, + output, + library_optional, + print, + verbose, + no_fmad, + unchecked_indexing, + lineinfo, + device_debug, + } => { + let ctx = commands::resolve_context(); + let example = resolve_example_name(example, &ctx, "tilelib"); + commands::tilelib( + &ctx, + &example, + &arch, + features.as_deref(), + output.as_deref(), + library_optional, + print, + verbose, + no_fmad, + unchecked_indexing, + commands::DeviceDebug::from_flags(lineinfo, device_debug), + ); + } Commands::Pipeline { example, emit_nvvm_ir, @@ -1326,6 +1414,14 @@ mod tests { "--materialize-cubin", ], &["cargo-oxide", "inspect", "demo", "--materialize-cubin"], + &[ + "cargo-oxide", + "tilelib", + "demo", + "--arch", + "sm_120", + "--materialize-cubin", + ], ] { let cli = Cli::try_parse_from(args).expect("global flag should parse first"); let error = validate_materialization_cli(&cli) @@ -1679,6 +1775,65 @@ mod tests { assert!(!device_debug, "--device-debug must default off"); } + #[test] + fn tilelib_parser_requires_arch_and_accepts_its_flags() { + assert!( + Cli::try_parse_from(["cargo-oxide", "tilelib", "relu"]).is_err(), + "the LTOIR inside a tile library is architecture-specific, so --arch is required" + ); + + let cli = Cli::try_parse_from([ + "cargo-oxide", + "tilelib", + "relu", + "--arch", + "sm_120", + "--library-optional", + "--print", + "-o", + "out/relu.tilelib", + ]) + .expect("tilelib command should parse"); + let Commands::Tilelib { + example, + arch, + output, + library_optional, + print, + verbose, + no_fmad, + lineinfo, + device_debug, + .. + } = cli.command + else { + panic!("expected tilelib command"); + }; + assert_eq!(example.as_deref(), Some("relu")); + assert_eq!(arch, "sm_120"); + assert_eq!(output, Some(PathBuf::from("out/relu.tilelib"))); + assert!(library_optional); + assert!(print); + assert!(!verbose); + assert!(!no_fmad); + assert!(!lineinfo, "--lineinfo must default off"); + assert!(!device_debug, "--device-debug must default off"); + + // Without the two flags the command insists on a library. + let cli = Cli::try_parse_from(["cargo-oxide", "tilelib", "relu", "--arch", "sm_120"]) + .expect("tilelib command should parse"); + let Commands::Tilelib { + library_optional, + print, + .. + } = cli.command + else { + panic!("expected tilelib command"); + }; + assert!(!library_optional); + assert!(!print); + } + #[test] fn parser_accepts_device_debug_flags() { let cli = Cli::try_parse_from(["cargo-oxide", "build", "vecadd", "--lineinfo"]) diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/error_union_shared_pointer_addr/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/error_union_shared_pointer_addr/Cargo.lock index afe82ce12d..746e3e1063 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/error_union_shared_pointer_addr/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/error_union_shared_pointer_addr/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/error_union_shared_pointer_layout/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/error_union_shared_pointer_layout/Cargo.lock index 5710aaf5ca..ac804086d6 100644 --- a/cuda-oxide/crates/rustc-codegen-cuda/examples/error_union_shared_pointer_layout/Cargo.lock +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/error_union_shared_pointer_layout/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ name = "cuda-macros" version = "0.2.1" dependencies = [ + "oxide-tile-export", "proc-macro2", "quote", "reserved-oxide-symbols", @@ -311,6 +312,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -417,6 +424,15 @@ dependencies = [ "object", ] +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -531,6 +547,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha2" version = "0.10.9" @@ -716,3 +745,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/tilelib_relu/Cargo.lock b/cuda-oxide/crates/rustc-codegen-cuda/examples/tilelib_relu/Cargo.lock new file mode 100644 index 0000000000..c86e4ed6e2 --- /dev/null +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/tilelib_relu/Cargo.lock @@ -0,0 +1,735 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "bindgen" +version = "0.69.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools", + "lazy_static", + "lazycell", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn", + "which", +] + +[[package]] +name = "bitflags" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "cuda-artifact-finalizer" +version = "0.2.1" +dependencies = [ + "libnvvm-sys", + "nvjitlink-sys", + "serde", + "sha2", + "thiserror", +] + +[[package]] +name = "cuda-bindings" +version = "0.4.0" +dependencies = [ + "bindgen", + "libloading", + "prettyplease", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "cuda-core" +version = "0.4.0" +dependencies = [ + "anyhow", + "cuda-bindings", + "cuda-core-derive", + "half", + "oxide-artifacts", +] + +[[package]] +name = "cuda-core-derive" +version = "0.4.0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "cuda-device" +version = "0.2.1" +dependencies = [ + "cuda-macros", +] + +[[package]] +name = "cuda-macros" +version = "0.2.1" +dependencies = [ + "oxide-tile-export", + "proc-macro2", + "quote", + "reserved-oxide-symbols", + "syn", +] + +[[package]] +name = "cuda-target-spec" +version = "0.1.0" + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "either" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "zerocopy", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "home" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + +[[package]] +name = "libnvvm-sys" +version = "0.2.1" +dependencies = [ + "cuda-target-spec", + "libloading", + "thiserror", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nvjitlink-sys" +version = "0.2.1" +dependencies = [ + "libloading", + "thiserror", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "crc32fast", + "hashbrown 0.15.5", + "indexmap", + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "oxide-artifacts" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d9a941c0c43d2dceaf25f5c9ca4c9f9cceb28dfa5e4e3cfd14e476f003e7c9" +dependencies = [ + "object", +] + +[[package]] +name = "oxide-tile-export" +version = "0.2.1" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "reserved-oxide-symbols" +version = "0.2.1" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tilelib_relu" +version = "0.1.0" +dependencies = [ + "cuda-artifact-finalizer", + "cuda-core", + "cuda-device", + "oxide-tile-export", +] + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "zerocopy" +version = "0.8.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/tilelib_relu/Cargo.toml b/cuda-oxide/crates/rustc-codegen-cuda/examples/tilelib_relu/Cargo.toml new file mode 100644 index 0000000000..4ca1afc7b9 --- /dev/null +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/tilelib_relu/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "tilelib_relu" +version = "0.1.0" +edition = "2024" +authors = ["Nihal Pasham "] +license = "Apache-2.0" + +# Mark as standalone crate (not part of parent workspace) +[workspace] + +# A tile library written in Rust: #[tile_export] functions a cuTile program +# calls through `foreign_call`. The host program proves the native SIMT ABI on +# this machine's GPU through a generated CUDA C++ caller: +# cargo oxide run tilelib_relu --emit-nvvm-ir --arch sm_120 + +[dependencies] +# Device-side intrinsics (#[tile_export], warp shuffles, etc.). +cuda-device = { path = "../../../cuda-device" } + +# The descriptions the backend writes next to the device artifact. The host +# derives the C++ prototypes from them instead of restating the ABI by hand. +oxide-tile-export = { path = "../../../oxide-tile-export" } + +# libNVVM and nvJitLink without the CUDA driver: NVVM IR to LTOIR, then the +# two-input LTOIR link into a cubin, the same calls cuda-host makes. +cuda-artifact-finalizer = { path = "../../../cuda-artifact-finalizer" } + +# Host-side CUDA runtime: context, device buffers, raw kernel launches. +cuda-core = { path = "../../../../../cuda-core" } diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/tilelib_relu/README.md b/cuda-oxide/crates/rustc-codegen-cuda/examples/tilelib_relu/README.md new file mode 100644 index 0000000000..95bff63d19 --- /dev/null +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/tilelib_relu/README.md @@ -0,0 +1,136 @@ +# tilelib_relu + +A tile library written in Rust. Three `#[tile_export]` functions compile to +one LTOIR module on the native SIMT ABI, and `tilelib_relu.tileexports.json` +describes them. A Tile kernel reaches them once the two are packaged as +`tilelib_relu.tilelib`, which needs a CUDA 13.5 or newer tileiras: from Tile +C++ through a foreign declaration (`cpp/tile_caller.cu`), or from cuTile +Python through `foreign_call` (`python/call_from_cutile.py`). The host +program here proves the ABI on any CUDA 13.4 machine, through a generated +CUDA C++ caller that declares the implementations the way the Tile compiler +would. + +```text +src/main.rs: #[tile_export] relu, scale_in_place, warp_sum + | + | cargo oxide run tilelib_relu --emit-nvvm-ir --arch sm_120 + v +tilelib_relu.ll ---libNVVM---> tilelib_relu.ltoir tilelib_relu.tileexports.json + (NVVM IR, SIMT ABI) (device code) (one description per export) + | | + +---------------------------+------------------------------+ + | | + v v +consumer 1: this host program (CUDA 13.4 is enough) consumer 2: cuTile (CUDA 13.5+) + descriptions -> mock/caller.cu cargo oxide tilelib tilelib_relu + nvcc -dc --keep -gencode arch=compute_120,code=lto_120 -> tilelib_relu.tilelib + nvJitLink(tilelib_relu.ltoir + caller.ltoir) -> cubin python/call_from_cutile.py + launch call_, compare, PASS x3 tp.foreign_call(symbol_name="relu") +``` + +## The exports + +| cuTile name | Rust | implementation the call resolves to | +|------------------|-----------------------------------------|----------------------------------------------------| +| `relu` | `fn relu(x: f32) -> f32` | `void relu_impl(float x, float *relu_out)` | +| `scale_in_place` | `fn scale(x: &mut f32, factor: f32)` | `void scale_in_place_impl(float *x, float factor)` | +| `warp_sum` | `fn warp_sum(x: f32) -> f32`, warp sync | `void warp_sum_impl(float x, float *warp_sum_out)` | + +`in` scalars travel by value, `&mut` parameters as pointers, and a return +value becomes a trailing `out` pointer. The host program does not restate +that table: it derives every prototype in `mock/caller.cu` from the +descriptions through `oxide_tile_export::TileExportDesc::abi_params`, so the +generated file is the ABI as the tooling understands it. It is written when +the program runs and is not tracked, like the other generated artifacts. + +The generated kernels launch one thread per invocation, tile size divided by +the export's footprint, and pass each thread the first of its footprint +elements; the three exports here have footprint 1. An export with `f16` +elements is skipped with a `SKIP` line and counted in the `SUCCESS` line +rather than failed, because nvcc has no scalar type that lowers to LLVM +`half`. + +## Run + +```bash +# 1. Build the library and prove the ABI on the GPU (needs nvcc, libNVVM, +# nvJitLink and a GPU matching --arch; CUDA 13.4 is enough). +cargo oxide run tilelib_relu --emit-nvvm-ir --arch sm_120 + +# 2. Package it as a tile library (needs a tileiras that lists 13.5 or newer). +cargo oxide tilelib tilelib_relu --arch sm_120 + +# 3. Call it from a Tile C++ kernel (needs the same toolkit's nvcc, which +# knows --enable-tile; the kernel runs on the GPU and checks all three exports). +nvcc --enable-tile --tile-preview simt -Xtileiras=-l=tilelib_relu.tilelib \ + -std=c++20 -arch=sm_120 -o tile_caller cpp/tile_caller.cu && ./tile_caller + +# 4. Or call it from cuTile Python (checked against cuTile Python 1.7). +python python/call_from_cutile.py --dry-run # bytecode only, no tileiras +python python/call_from_cutile.py # full run, needs step 2 +``` + +Step 1 is not a Tile kernel. The host program stands in for the Tile +compiler: it writes a CUDA C++ caller from the descriptions and links it +against the LTOIR, which proves the ABI on CUDA 13.4. The end-to-end test, a +Tile kernel calling the Rust functions, is step 2 followed by step 3 or 4. +Run step 2 after step 1: `cargo oxide run` and `cargo oxide build` clear the +example's generated artifacts, the `.tilelib` among them. When the toolkit +that brings the 13.5 assembler is not the one on `PATH`, point +`CUTILE_TILEIRAS_PATH` at its `tileiras` for step 2 and run its `nvcc` for +step 3. + +Step 3 prints one `PASS` line per export and then +`SUCCESS: 3/3 tile exports called from a Tile C++ kernel`. Each foreign +declaration in `cpp/tile_caller.cu` mirrors a declaration of the library: +parameters the library reads carry no attribute, parameters it writes carry +`[[cutile::experimental_inout]]` and come back as the result, the way the +MathDx tile libraries declare theirs. + +Step 1 prints one line per export and then the marker: + +```text +PASS relu: 128 elements through `relu_impl`, relu of a ramp from -4 to 4 +PASS scale_in_place: 128 elements through `scale_in_place_impl`, the ramp scaled in place by 0.5 +PASS warp_sum: 128 elements through `warp_sum_impl`, 32-lane sums over 0..128, every lane holding its warp's total +SUCCESS: 3/3 tile exports verified through the native ABI +``` + +Without nvcc it prints `skipping: nvcc not found` and exits 0. + +## What PASS proves + +- The wrapper `#[tile_export]` generates has the calling convention the Tile + compiler derives from the same description: a C++ caller written from the + description alone links against it and gets the right numbers. +- The link works the way a tile library is consumed: two LTOIR inputs, + symbols resolved by nvJitLink, no PTX in between. +- `sync = warp` behaves when every lane of a warp calls together: all 32 + lanes receive the warp total. + +All three checks compare bit for bit; the inputs are chosen so f32 cannot +round (relu copies or zeroes, 0.5 halves, the warp sums are small integers). + +## What still needs CUDA 13.5 or newer + +- `tilelib_relu.tilelib` itself: `tileiras --preview-create-tile-lib` exists + from 13.5 on, and an assembler reads preview content only at the version + it calls current, so the descriptions are written at the resolved + assembler's newest listed version. When the installed tileiras lists only + 13.4, + `cargo oxide tilelib` stops after writing the descriptions, says so, and + exits 2; with `--library-optional` the descriptions alone count as + success and it exits 0, which is how the smoketest runs it. +- The Tile C++ caller: nvcc gains `--enable-tile` and `--tile-preview simt` + with the same toolkit that brings the assembler, and the program and the + library then agree on the bytecode version by construction. +- The cuTile side: `foreign_call` is a 13.5 bytecode feature. The dry run + compiles it on 13.4 because it never calls tileiras. It was checked + against cuTile Python 1.7 (checkout 770b493) with the `cuda-tile-preview` + package built from that checkout's `experimental/tile_preview` folder: + `cuda.tile_preview` is not on PyPI, and `call_from_cutile.py` imports + private `cuda.tile._*` modules (`_bytecode`, `_cext`, `_compile`) that can + move between releases. The full run also needs a cuTile Python that lists + the assembler's current bytecode version: the script lists every version + its encoder knows, and the probe against tileiras picks the newest one it + accepts. diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/tilelib_relu/cpp/tile_caller.cu b/cuda-oxide/crates/rustc-codegen-cuda/examples/tilelib_relu/cpp/tile_caller.cu new file mode 100644 index 0000000000..31e4942713 --- /dev/null +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/tilelib_relu/cpp/tile_caller.cu @@ -0,0 +1,123 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +// A Tile C++ kernel that calls the three Rust exports of tilelib_relu.tilelib. +// +// nvcc --enable-tile --tile-preview simt -Xtileiras=-l=tilelib_relu.tilelib \ +// -std=c++20 -arch=sm_120 -o tile_caller cpp/tile_caller.cu +// +// Needs a toolkit whose nvcc knows `--enable-tile` and whose tileiras built +// the library (CUDA 13.5 or newer). Each foreign declaration mirrors one +// declaration in the library's interface: parameters the library reads carry +// no attribute, parameters it writes carry `[[cutile::experimental_inout]]` +// and come back as the result. The kernel runs one 128-element tile through +// each export; the host checks every element bit for bit. + +#include +#include + +#include +#include +#include + +namespace ct = cuda::tiles; + +inline constexpr int tile_size = 128; +using tile_f32 = ct::tile>; + +// @relu(%x: tile<128xf32> in, %relu_out: tile<128xf32> out) -> tile<128xf32> +__experimental_foreign_decl__ __experimental_foreign_name__("relu") + tile_f32 relu(tile_f32 x, [[cutile::experimental_inout]] tile_f32 relu_out); + +// @scale_in_place(%x: tile<128xf32> inout, %factor: tile<128xf32> in) -> tile<128xf32> +__experimental_foreign_decl__ __experimental_foreign_name__("scale_in_place") + tile_f32 scale_in_place([[cutile::experimental_inout]] tile_f32 x, tile_f32 factor); + +// @warp_sum(%x: tile<128xf32> in, %warp_sum_out: tile<128xf32> out) -> tile<128xf32>, +// implemented with synchronization: 32 lanes call the Rust function together. +__experimental_foreign_decl__ __experimental_foreign_name__("warp_sum") + tile_f32 warp_sum(tile_f32 x, [[cutile::experimental_inout]] tile_f32 warp_sum_out); + +[[cutile::hint(0, num_worker_warps_per_cta = 4)]] __tile_global__ void call_exports( + float* ramp, float* factor, float* lanes, float* relu_out, float* scale_out, float* warp_out) { + auto view = [](float* data) { + return ct::partition_view { ct::tensor_span { data, ct::shape {} }, ct::shape {} }; + }; + auto relu_view = view(relu_out); + auto scale_view = view(scale_out); + auto warp_view = view(warp_out); + + relu_view.store(relu(view(ramp).load(0), relu_view.load(0)), 0); + scale_view.store(scale_in_place(view(ramp).load(0), view(factor).load(0)), 0); + warp_view.store(warp_sum(view(lanes).load(0), warp_view.load(0)), 0); +} + +#define CHECK_CUDA(expression) \ + do { \ + const cudaError_t cuda_status = (expression); \ + if (cuda_status != cudaSuccess) { \ + std::fprintf(stderr, "%s failed: %s\n", #expression, cudaGetErrorString(cuda_status)); \ + return EXIT_FAILURE; \ + } \ + } while (0) + +int main() { + std::array ramp {}; + std::array factor {}; + std::array lanes {}; + for (int i = 0; i < tile_size; ++i) { + ramp[i] = -4.0f + 8.0f * float(i) / float(tile_size - 1); + factor[i] = 0.5f; + lanes[i] = float(i); + } + + float* device[6] = {}; + for (float*& pointer : device) CHECK_CUDA(cudaMalloc(&pointer, sizeof(ramp))); + CHECK_CUDA(cudaMemcpy(device[0], ramp.data(), sizeof(ramp), cudaMemcpyHostToDevice)); + CHECK_CUDA(cudaMemcpy(device[1], factor.data(), sizeof(factor), cudaMemcpyHostToDevice)); + CHECK_CUDA(cudaMemcpy(device[2], lanes.data(), sizeof(lanes), cudaMemcpyHostToDevice)); + for (int i = 3; i < 6; ++i) CHECK_CUDA(cudaMemset(device[i], 0, sizeof(ramp))); + + call_exports<<<1>>>(device[0], device[1], device[2], device[3], device[4], device[5]); + CHECK_CUDA(cudaGetLastError()); + CHECK_CUDA(cudaDeviceSynchronize()); + + std::array relu_out {}; + std::array scale_out {}; + std::array warp_out {}; + CHECK_CUDA(cudaMemcpy(relu_out.data(), device[3], sizeof(relu_out), cudaMemcpyDeviceToHost)); + CHECK_CUDA(cudaMemcpy(scale_out.data(), device[4], sizeof(scale_out), cudaMemcpyDeviceToHost)); + CHECK_CUDA(cudaMemcpy(warp_out.data(), device[5], sizeof(warp_out), cudaMemcpyDeviceToHost)); + + int failures = 0; + for (int i = 0; i < tile_size; ++i) { + const float expected_relu = ramp[i] > 0.0f ? ramp[i] : 0.0f; + const float expected_scale = ramp[i] * 0.5f; + // Lane values 32w .. 32w+31 sum to 32 * 32w + 496. + const float expected_warp = float(32 * 32 * (i / 32) + 496); + if (relu_out[i] != expected_relu) { + std::fprintf(stderr, "relu mismatch at %d: got %f expected %f\n", i, relu_out[i], expected_relu); + ++failures; + } + if (scale_out[i] != expected_scale) { + std::fprintf(stderr, "scale_in_place mismatch at %d: got %f expected %f\n", i, scale_out[i], expected_scale); + ++failures; + } + if (warp_out[i] != expected_warp) { + std::fprintf(stderr, "warp_sum mismatch at %d: got %f expected %f\n", i, warp_out[i], expected_warp); + ++failures; + } + } + for (float* pointer : device) CHECK_CUDA(cudaFree(pointer)); + if (failures != 0) { + std::fprintf(stderr, "FAIL: %d mismatches\n", failures); + return EXIT_FAILURE; + } + std::printf("PASS relu: 128 elements through the tile library\n"); + std::printf("PASS scale_in_place: 128 elements through the tile library\n"); + std::printf("PASS warp_sum: 128 elements through the tile library, every lane holding its warp's total\n"); + std::printf("SUCCESS: 3/3 tile exports called from a Tile C++ kernel\n"); + return EXIT_SUCCESS; +} diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/tilelib_relu/python/call_from_cutile.py b/cuda-oxide/crates/rustc-codegen-cuda/examples/tilelib_relu/python/call_from_cutile.py new file mode 100644 index 0000000000..7a9b6e4beb --- /dev/null +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/tilelib_relu/python/call_from_cutile.py @@ -0,0 +1,215 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Call tilelib_relu's `relu` from a cuTile kernel through `foreign_call`. + + python call_from_cutile.py --dry-run # bytecode only; runs on CUDA 13.4 + python call_from_cutile.py [path/to.tilelib] # full run; needs the CUDA 13.5 tileiras + +The kernel loads one 128-float tile, hands it to the library's `relu` +declaration together with a zero tile for the result slot, and stores what +comes back. `--dry-run` compiles that kernel to Tile IR bytecode without +tileiras (`return_cubin=False`) and checks that the program really calls +`relu`: the caller half of the contract, produced on this machine. The full +run also needs the library half, `tilelib_relu.tilelib`, which only a CUDA +13.5 tileiras can build (`cargo oxide tilelib tilelib_relu --arch sm_120`), +and a cuTile Python whose supported bytecode versions include 13.5. + +Checked against cuTile Python 1.7 (checkout 770b493) with the +`cuda-tile-preview` package from that checkout's experimental/tile_preview +folder; `cuda.tile_preview` is not on PyPI. The dry run reaches into private +`cuda.tile._*` modules (`_bytecode`, `_cext`, `_compile`), which can move +between releases. +""" + +from __future__ import annotations + +import argparse +import os +import pathlib +import shutil +import subprocess +import sys +import tempfile + +import numpy as np + +import cuda.tile as ct +from cuda import tile_preview as tp + +TILE = 128 +LIBRARY_VERSION = "0.1.0" +HERE = pathlib.Path(__file__).resolve().parent +DEFAULT_TILELIB = HERE.parent / "tilelib_relu.tilelib" +# preview$call in the bytecode opcode table; upstream's test_foreign_call.py +# looks for the same varint-encoded value. +PREVIEW_CALL_OPCODE = 0x4002 + +# Set by main() before the kernel is traced. foreign_call reads the library +# as a compile-time constant, so it has to be a module global, not an argument. +PROVIDER: tp.Tilelib | None = None + + +def relu_tile(x, y): + """One block runs `relu` over one 128-float tile of `x` into `y`.""" + pid = ct.bid(0) + tile = ct.load(x, index=(pid,), shape=(TILE,)) + # Every declaration argument needs an input tile, the `out` slot included. + result_slot = ct.zeros((TILE,), dtype=ct.float32) + (out,) = tp.foreign_call( + tilelibs=(PROVIDER,), + symbol_name="relu", + constant_params=(), + inputs=(tile, result_slot), + output_types=((ct.float32, (TILE,)),), + ) + ct.store(y, index=(pid,), tile=out) + + +def dry_run() -> None: + """Compile the kernel to 13.5 bytecode and show the preview$call to `relu` is in it.""" + from cuda.tile._bytecode.basic import encode_varint + from cuda.tile._bytecode.version import BytecodeVersion + from cuda.tile._cext import CallingConvention + from cuda.tile._compile import compile_tile + from cuda.tile.compilation import ArrayConstraint, KernelSignature + + constraint = ArrayConstraint( + dtype=ct.float32, + ndim=1, + index_dtype=ct.int32, + stride_lower_bound_incl=0, + alias_groups=(), + may_alias_internally=False, + ) + signature = KernelSignature( + [constraint, constraint], CallingConvention.cutile_python_v2(), symbol="relu_tile" + ) + result = compile_tile( + relu_tile, + [signature], + bytecode_version=BytecodeVersion.V_13_5, + return_final_ir=True, + return_bytecode=True, + return_cubin=False, + ) + bytecode = bytes(result.bytecode) + major, minor = bytecode[8], bytecode[9] + preview = int.from_bytes(bytecode[10:12], "little") & 1 + opcode = bytearray() + encode_varint(PREVIEW_CALL_OPCODE, opcode) + has_call_op = bytes(opcode) in bytecode + # The callee's name is read from the final IR, not from the bytecode's + # string table: the kernel symbol `relu_tile` contains `relu`, so a bare + # search of the bytes would pass without any call. + ir_text = "\n".join(str(block) for block in result.final_ir) + calls_relu = "preview_foreign_call" in ir_text and 'symbol_name="relu"' in ir_text + print(f"bytecode: {len(bytecode)} bytes, header {bytecode[8:12].hex()} " + f"(version {major}.{minor}, preview flag {'set' if preview else 'clear'}), " + f"preview$call opcode {'present' if has_call_op else 'absent'}; " + f"final IR {'calls' if calls_relu else 'does not call'} `relu`") + if (major, minor) != (13, 5) or not preview or not has_call_op or not calls_relu: + print("FAIL: the program does not carry a 13.5 preview call to `relu`") + sys.exit(1) + print("PASS: the caller side compiles; the program calls `relu` through " + "preview$call (dry run, no cubin)") + + +def full_run() -> None: + """Link the library with tileiras, run on the GPU, compare with numpy.""" + import cupy as cp + from cuda.tile import _compile as compile_module + from cuda.tile._bytecode.version import BytecodeVersion + + # A launched kernel is compiled at the newest bytecode version this cuTile + # Python lists and the installed tileiras accepts. The 1.7 checkout lists + # versions above 13.4 only when its extension is built with development + # features, so every version its encoder knows is listed here; the probe + # against tileiras still decides which one is used. foreign_call needs + # 13.5, and an assembler reads preview content only at the version it + # calls current, so this cuTile Python must encode that version too. A + # release that lists these versions itself needs no such lines. + for version in BytecodeVersion: + if (version > BytecodeVersion.V_13_4 + and version not in compile_module._SUPPORTED_VERSIONS): + compile_module._SUPPORTED_VERSIONS.append(version) + + relu_kernel = ct.kernel(relu_tile) + n = 32 * TILE + x = cp.linspace(-4.0, 4.0, n, dtype=cp.float32) + y = cp.zeros_like(x) + try: + ct.launch(cp.cuda.get_current_stream(), (n // TILE, 1, 1), relu_kernel, (x, y)) + except Exception as error: # noqa: BLE001 (every failure here is reported, not hidden) + explain(error) + sys.exit(1) + expected = np.maximum(cp.asnumpy(x), 0.0) + got = cp.asnumpy(y) + np.testing.assert_array_equal(got, expected) + print(f"PASS: relu from the tile library matches numpy on {n} elements") + + +def explain(error: Exception) -> None: + """Report the failure and, when it is the toolkit, say so plainly.""" + print(f"FAIL: {type(error).__name__}: {error}") + versions = tileiras_versions() + if versions and "13.5" not in versions: + print(f"The installed tileiras lists bytecode versions {', '.join(versions)}. " + "foreign_call needs 13.5, which ships with CUDA 13.5 or newer; until then " + "only --dry-run can run on this machine.") + else: + print("A 13.5 tileiras is also only used when this cuTile Python lists 13.5 " + "among its supported bytecode versions.") + + +def tileiras_versions() -> list[str]: + """The bytecode versions the tileiras on this machine accepts, or [].""" + candidates = [shutil.which("tileiras")] + for root in (os.environ.get("CUDA_HOME"), os.environ.get("CUDA_PATH"), "/usr/local/cuda"): + if root: + candidates.append(os.path.join(root, "bin", "tileiras")) + for path in candidates: + if not path or not os.path.isfile(path): + continue + try: + output = subprocess.run([path, "--list-versions"], capture_output=True, + text=True, check=True, timeout=30).stdout + except (OSError, subprocess.SubprocessError): + continue + return [line.strip() for line in output.splitlines() if line.strip()] + return [] + + +def main() -> None: + global PROVIDER + parser = argparse.ArgumentParser(description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument("tilelib", nargs="?", default=DEFAULT_TILELIB, type=pathlib.Path, + help="the tile library (default: ../tilelib_relu.tilelib)") + parser.add_argument("--dry-run", action="store_true", + help="compile to bytecode only; no tileiras, no GPU") + args = parser.parse_args() + + if args.dry_run and not args.tilelib.is_file(): + # Tilelib() insists that the file exists; the bytecode only records + # its path, so a placeholder stands in for the real library. + with tempfile.TemporaryDirectory() as scratch: + placeholder = pathlib.Path(scratch) / args.tilelib.name + placeholder.write_bytes(b"placeholder") + print(f"{args.tilelib} is not built yet; using a placeholder for the dry run") + PROVIDER = tp.Tilelib(path=placeholder, version=LIBRARY_VERSION) + dry_run() + return + + if not args.tilelib.is_file(): + print(f"FAIL: {args.tilelib} does not exist; build it with " + "`cargo oxide tilelib tilelib_relu --arch sm_120` (CUDA 13.5 tileiras)") + sys.exit(1) + PROVIDER = tp.Tilelib(path=args.tilelib, version=LIBRARY_VERSION) + if args.dry_run: + dry_run() + else: + full_run() + + +if __name__ == "__main__": + main() diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/tilelib_relu/src/main.rs b/cuda-oxide/crates/rustc-codegen-cuda/examples/tilelib_relu/src/main.rs new file mode 100644 index 0000000000..c6168616d6 --- /dev/null +++ b/cuda-oxide/crates/rustc-codegen-cuda/examples/tilelib_relu/src/main.rs @@ -0,0 +1,593 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +//! tilelib_relu: a tile library written in Rust, checked on the GPU. +//! +//! The device half is the three `#[tile_export]` functions below. Each one +//! becomes an implementation a cuTile program calls through `foreign_call`, +//! on the native SIMT ABI: `in` scalars by value, everything else behind a +//! pointer, the return value as a trailing `out` pointer. +//! +//! The host half proves that ABI without a CUDA 13.5 or newer tileiras. It reads the +//! descriptions the backend wrote, generates `mock/caller.cu` with the +//! prototypes the Tile compiler derives, compiles it with nvcc, links it with +//! the Rust LTOIR through nvJitLink, and checks the numbers on the GPU: +//! +//! cargo oxide run tilelib_relu --emit-nvvm-ir --arch sm_120 + +use cuda_artifact_finalizer::{ + CudaArch, DebugPolicy, FinalizationOptions, FinalizerOutput, LtoLinker, NamedInput, + NvvmCompiler, +}; +use cuda_core::embedded::{ArtifactCompileOptions, ArtifactDebugPolicy}; +use cuda_core::{CudaContext, CudaModule, DeviceBuffer, launch_kernel_on_stream}; +use cuda_device::{tile_export, warp}; +use oxide_tile_export::{ + AbiParamKind, DESCRIPTIONS_SUFFIX, TileAccess, TileElem, TileExportDesc, descriptions_from_json, +}; +use std::error::Error; +use std::ffi::c_void; +use std::fmt::Write as _; +use std::path::{Path, PathBuf}; +use std::process::Command; +use std::sync::Arc; + +// ============================================================================ +// Device half: the tile library +// ============================================================================ + +/// Elementwise `max(x, 0)`. +#[tile_export(tile_shape = 128)] +pub fn relu(x: f32) -> f32 { + if x > 0.0 { x } else { 0.0 } +} + +/// Scale a tile in place. The cuTile side knows it as `scale_in_place`. +#[tile_export( + tile_shape = 128, + name = "scale_in_place", + symbol = "scale_in_place_impl" +)] +pub fn scale(x: &mut f32, factor: f32) { + *x *= factor; +} + +/// Sum over the 32 lanes of each warp; every lane gets the warp total. +#[tile_export(tile_shape = 128, sync = "warp")] +pub fn warp_sum(x: f32) -> f32 { + let mut total = x; + let mut offset = 16; + while offset > 0 { + total += warp::shuffle_xor_f32_sync(u32::MAX, total, offset); + offset /= 2; + } + total +} + +// ============================================================================ +// Host half: prove the ABI through a generated CUDA C++ caller +// ============================================================================ + +const CRATE: &str = "tilelib_relu"; + +type Fallible = Result>; + +/// How the run ended when nothing went wrong. +enum Outcome { + /// The exports that were called through the native ABI and checked, plus + /// the ones the generated caller cannot declare, each with its reason. + Verified { + verified: usize, + skipped: Vec<(String, String)>, + }, + /// The check cannot run on this machine; the reason is printed. + Skipped(String), +} + +fn main() { + match run() { + Ok(Outcome::Verified { verified, skipped }) => { + let total = verified + skipped.len(); + let mut line = + format!("SUCCESS: {verified}/{total} tile exports verified through the native ABI"); + if !skipped.is_empty() { + let names: Vec<&str> = skipped.iter().map(|(decl, _)| decl.as_str()).collect(); + let _ = write!(line, ", {} skipped ({})", skipped.len(), names.join(", ")); + } + println!("{line}"); + } + Ok(Outcome::Skipped(reason)) => println!("skipping: {reason}"), + Err(error) => { + println!("FAIL: {error}"); + std::process::exit(1); + } + } +} + +fn run() -> Fallible { + let dir = Path::new(env!("CARGO_MANIFEST_DIR")); + let (exports, skipped) = partition_callable(read_descriptions(dir)?); + if exports.is_empty() { + return Ok(Outcome::Skipped( + "every export uses half precision, which the generated caller cannot declare" + .to_string(), + )); + } + let options = read_build_policy(dir)?; + let Some(nvcc) = find_nvcc() else { + return Ok(Outcome::Skipped("nvcc not found".to_string())); + }; + + let caller_cu = dir.join("mock").join("caller.cu"); + write_if_changed(&caller_cu, &caller_source(&exports)?)?; + + let rust_ltoir = rust_ltoir(dir, &options)?; + let caller_ltoir = compile_caller(&nvcc, &caller_cu, options.target())?; + // Both halves are LTOIR, so nvJitLink resolves the implementation symbols + // at link time, the same way a real tile library is consumed. + let cubin = LtoLinker::discover()?.link_ltoir( + &[ + NamedInput::new("tilelib_relu.ltoir", &rust_ltoir), + NamedInput::new("caller.ltoir", &caller_ltoir), + ], + &options, + FinalizerOutput::Cubin, + )?; + println!( + "nvJitLink: {} bytes of cubin for {}", + cubin.len(), + options.target().sm() + ); + + let ctx = match CudaContext::new(0) { + Ok(ctx) => ctx, + Err(error) => return Ok(Outcome::Skipped(format!("no CUDA device: {error}"))), + }; + let (major, minor) = ctx.compute_capability()?; + let gpu = u32::try_from(major * 10 + minor)?; + if gpu != options.target().capability() { + return Ok(Outcome::Skipped(format!( + "the device code targets {}, this GPU is sm_{gpu}", + options.target().sm() + ))); + } + let module = ctx.load_module_from_image(&cubin)?; + for desc in &exports { + check_export(&ctx, &module, desc)?; + } + Ok(Outcome::Verified { + verified: exports.len(), + skipped, + }) +} + +/// Split the exports into the ones the generated caller can declare and the +/// ones it cannot, printing one `SKIP` line per export left out. nvcc has no +/// scalar type that lowers to LLVM `half` or `bfloat` (its `__half` is a +/// struct), so a half-precision export is reported and counted rather than +/// failed: the ABI defect that would be is in the mock, not in the export. +fn partition_callable( + exports: Vec, +) -> (Vec, Vec<(String, String)>) { + let mut callable = Vec::with_capacity(exports.len()); + let mut skipped = Vec::new(); + for desc in exports { + match desc + .params + .iter() + .find_map(|param| c_type(param.elem).err()) + { + Some(reason) => { + println!("SKIP {}: {reason}", desc.decl); + skipped.push((desc.decl, reason)); + } + None => callable.push(desc), + } + } + (callable, skipped) +} + +/// The descriptions the backend wrote next to the device artifact, validated +/// so the generated C++ can rely on the ABI rules. +fn read_descriptions(dir: &Path) -> Fallible> { + let path = dir.join(format!("{CRATE}.{DESCRIPTIONS_SUFFIX}")); + let text = std::fs::read_to_string(&path).map_err(|error| { + format!( + "could not read {} (build with `cargo oxide run {CRATE} --emit-nvvm-ir --arch sm_120`): {error}", + path.display() + ) + })?; + let exports = descriptions_from_json(&text)?; + if exports.is_empty() { + return Err(format!("{} describes no tile exports", path.display()).into()); + } + for desc in &exports { + desc.validate() + .map_err(|error| format!("description of `{}`: {error}", desc.decl))?; + } + Ok(exports) +} + +/// The target and compile policy recorded with the NVVM IR. The link must use +/// the same architecture and FMA setting as the build, or nvJitLink rejects +/// the input or changes the arithmetic. +fn read_build_policy(dir: &Path) -> Fallible { + let target_path = dir.join(format!("{CRATE}.target")); + let text = std::fs::read_to_string(&target_path) + .map_err(|error| format!("could not read {}: {error}", target_path.display()))?; + let target: CudaArch = text.lines().next().unwrap_or_default().trim().parse()?; + + let options_path = dir.join(format!("{CRATE}.options")); + let compile = match std::fs::read_to_string(&options_path) { + Ok(text) => ArtifactCompileOptions::from_sidecar_text(&text) + .map_err(|error| format!("invalid {}: {error}", options_path.display()))?, + Err(error) if error.kind() == std::io::ErrorKind::NotFound => ArtifactCompileOptions::new(), + Err(error) => { + return Err(format!("could not read {}: {error}", options_path.display()).into()); + } + }; + let debug = match compile.debug_policy() { + ArtifactDebugPolicy::None => DebugPolicy::None, + ArtifactDebugPolicy::LineTables => DebugPolicy::LineTables, + ArtifactDebugPolicy::Full => DebugPolicy::Full, + }; + Ok(FinalizationOptions::new(target) + .with_fma_contraction(compile.fma_contraction_enabled()) + .with_debug_policy(debug)) +} + +/// The Rust half as LTOIR. `cargo oxide tilelib` and `emit-ltoir` leave a +/// `.ltoir` next to the `.ll`; a plain `--emit-nvvm-ir` build leaves only the +/// `.ll`, so it is compiled here with libNVVM, the call cargo oxide makes. A +/// `.ltoir` older than the `.ll` is stale and gets recompiled too. +fn rust_ltoir(dir: &Path, options: &FinalizationOptions) -> Fallible> { + let ll = dir.join(format!("{CRATE}.ll")); + let ltoir = dir.join(format!("{CRATE}.ltoir")); + if ltoir.is_file() && !older_than(<oir, &ll) { + println!("libNVVM: using {}", ltoir.display()); + return Ok(std::fs::read(<oir)?); + } + let ir = std::fs::read(&ll).map_err(|error| { + format!( + "could not read {} (build with `cargo oxide run {CRATE} --emit-nvvm-ir --arch sm_120`): {error}", + ll.display() + ) + })?; + let ltoir = + NvvmCompiler::discover()?.compile_nvvm_ir_to_ltoir(&format!("{CRATE}.ll"), &ir, options)?; + println!( + "libNVVM: {} compiled to LTOIR ({} bytes)", + ll.display(), + ltoir.len() + ); + Ok(ltoir) +} + +fn older_than(file: &Path, other: &Path) -> bool { + let modified = |path: &Path| std::fs::metadata(path).and_then(|meta| meta.modified()); + match (modified(file), modified(other)) { + (Ok(file_time), Ok(other_time)) => file_time < other_time, + _ => false, + } +} + +/// nvcc from `PATH`, then from the toolkit roots libNVVM is also looked up in. +fn find_nvcc() -> Option { + let on_path = std::env::var_os("PATH") + .map(|path| std::env::split_paths(&path).collect::>()) + .unwrap_or_default() + .into_iter() + .map(|dir| dir.join("nvcc")); + let in_toolkit = ["CUDA_TOOLKIT_PATH", "CUDA_HOME", "CUDA_PATH"] + .into_iter() + .filter_map(std::env::var_os) + .map(PathBuf::from) + .chain([PathBuf::from("/usr/local/cuda"), PathBuf::from("/opt/cuda")]) + .map(|root| root.join("bin").join("nvcc")); + on_path + .chain(in_toolkit) + .find(|candidate| candidate.is_file()) +} + +/// Generate `mock/caller.cu`: the implementation prototypes the Tile compiler +/// derives from the descriptions, and one kernel per export that calls the +/// implementation the way the compiler does over one tile. +fn caller_source(exports: &[TileExportDesc]) -> Fallible { + let mut out = String::new(); + out.push_str( + "// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n\ + // SPDX-License-Identifier: Apache-2.0\n\ + //\n\ + // Generated by the tilelib_relu host program from tilelib_relu.tileexports.json.\n\ + // Do not edit: it is rewritten whenever the descriptions change.\n\ + //\n\ + // Each kernel stands in for the Tile compiler: one thread per invocation of\n\ + // the implementation, launched as one block of tile-size / footprint threads.\n\ + // Scalar `in` parameters arrive by value, every other parameter as a pointer\n\ + // to the first of the invocation's footprint elements. A `sync = warp` export\n\ + // is called by every lane of each warp, which the full block provides.\n\n", + ); + for desc in exports { + // `validate` holds every parameter of an export to one footprint, so + // the first parameter's is the export's. + let footprint = desc.params[0].footprint; + let abi = desc.abi_params(); + let mut prototype = Vec::new(); + let mut kernel_params = Vec::new(); + let mut call_args = Vec::new(); + for (param, info) in abi.iter().zip(&desc.params) { + let c_type = c_type(param.kind.elem()).map_err(|reason| { + format!("`{}`: parameter `{}`: {reason}", desc.decl, param.name) + })?; + let constness = if info.access == TileAccess::In { + "const " + } else { + "" + }; + // Every parameter is a tile-size buffer to the kernel; by-value + // parameters are loaded from it, pointer parameters point into it. + kernel_params.push(format!("{constness}{c_type} *{}", param.name)); + match param.kind { + AbiParamKind::Scalar(_) => { + prototype.push(format!("{c_type} {}", param.name)); + call_args.push(format!("{}[i]", param.name)); + } + AbiParamKind::Pointer(_) => { + prototype.push(format!("{constness}{c_type} *{}", param.name)); + call_args.push(format!("&{}[i]", param.name)); + } + } + } + writeln!( + out, + "// {}: {} elements, footprint {footprint}, sync {}", + desc.decl, + desc.shape[0], + desc.sync.tile_ir_name() + )?; + writeln!( + out, + "extern \"C\" __device__ void {}({});", + desc.symbol, + prototype.join(", ") + )?; + writeln!( + out, + "extern \"C\" __global__ void call_{}({}) {{", + desc.decl, + kernel_params.join(", ") + )?; + if footprint == 1 { + writeln!( + out, + " const int i = blockIdx.x * blockDim.x + threadIdx.x;" + )?; + } else { + // Thread t owns elements [t * F, (t + 1) * F). + writeln!( + out, + " const int i = (blockIdx.x * blockDim.x + threadIdx.x) * {footprint};" + )?; + } + writeln!(out, " {}({});", desc.symbol, call_args.join(", "))?; + writeln!(out, "}}\n")?; + } + Ok(out) +} + +/// The C type of a tile element, or why nvcc has none: it has no scalar type +/// that lowers to LLVM `half` or `bfloat` (its `__half` is a struct), so +/// those two cannot be declared in the generated caller. +fn c_type(elem: TileElem) -> Result<&'static str, String> { + Ok(match elem { + TileElem::F32 => "float", + TileElem::F64 => "double", + TileElem::I8 => "signed char", + TileElem::I16 => "short", + TileElem::I32 => "int", + TileElem::I64 => "long long", + TileElem::U8 => "unsigned char", + TileElem::U16 => "unsigned short", + TileElem::U32 => "unsigned int", + TileElem::U64 => "unsigned long long", + TileElem::F16 | TileElem::BF16 => { + return Err(format!( + "{} has no by-value C type in nvcc; the mock covers f32, f64 and the integers", + elem.rust_name() + )); + } + }) +} + +/// Write `text` to `path` only when it differs, so a run that changes nothing +/// leaves the generated file alone. +fn write_if_changed(path: &Path, text: &str) -> Fallible<()> { + if std::fs::read_to_string(path).is_ok_and(|current| current == text) { + println!("caller: {} is current", path.display()); + return Ok(()); + } + if let Some(parent) = path.parent() { + std::fs::create_dir_all(parent)?; + } + std::fs::write(path, text)?; + println!("caller: wrote {}", path.display()); + Ok(()) +} + +/// Compile the generated caller to LTOIR for `target` in a scratch directory, +/// removed on success and kept for inspection on failure. `-dc` leaves the +/// Rust symbols unresolved for the link; `--keep` makes nvcc leave the +/// `.ltoir` behind. +fn compile_caller(nvcc: &Path, caller_cu: &Path, target: &CudaArch) -> Fallible> { + let work = std::env::temp_dir().join(format!("{CRATE}-nvcc-{}", std::process::id())); + std::fs::create_dir_all(&work)?; + let sm = target.sm(); + let code = sm.trim_start_matches("sm_"); + + let mut command = Command::new(nvcc); + // The same host-compiler override the other LTOIR examples honor. + if let Some(ccbin) = std::env::var_os("NVCC_CCBIN").or_else(|| std::env::var_os("CUDAHOSTCXX")) + { + command.arg("-ccbin").arg(ccbin); + } + let output = command + .args(["-dc", "--keep", "--keep-dir"]) + .arg(&work) + .arg("-gencode") + .arg(format!("arch={},code=lto_{code}", target.compute())) + .arg(caller_cu) + .arg("-o") + .arg(work.join("caller.o")) + .current_dir(&work) + .output()?; + if !output.status.success() { + return Err(format!( + "nvcc failed ({}); intermediates kept in {}\n{}", + output.status, + work.display(), + String::from_utf8_lossy(&output.stderr) + ) + .into()); + } + let ltoir = std::fs::read(work.join("caller.ltoir"))?; + std::fs::remove_dir_all(&work)?; + println!("nvcc: caller.ltoir ({} bytes, lto_{code})", ltoir.len()); + Ok(ltoir) +} + +/// The data fed to one export and the result expected back. +struct HostCase { + /// One tile of values per ABI parameter, in description order; result + /// slots start zeroed. + buffers: Vec>, + /// Index of the parameter whose buffer is read back and checked. + checked: usize, + expected: Vec, + what: &'static str, +} + +/// What the host feeds each export and what it expects back. Every case is +/// exact in f32: relu copies or zeroes, 0.5 halves without rounding, and the +/// warp sums are small integers. +fn host_model(desc: &TileExportDesc, n: usize) -> Fallible { + // A ramp from -4 to 4 crosses zero without landing on it. + let last = (n.max(2) - 1) as f32; + let ramp: Vec = (0..n).map(|i| -4.0 + 8.0 * (i as f32) / last).collect(); + let case = match desc.decl.as_str() { + "relu" => HostCase { + buffers: vec![ramp.clone(), vec![0.0; n]], + checked: 1, + expected: ramp + .iter() + .map(|&x| if x > 0.0 { x } else { 0.0 }) + .collect(), + what: "relu of a ramp from -4 to 4", + }, + "scale_in_place" => HostCase { + buffers: vec![ramp.clone(), vec![0.5; n]], + checked: 0, + expected: ramp.iter().map(|x| x * 0.5).collect(), + what: "the ramp scaled in place by 0.5", + }, + "warp_sum" => { + let lanes: Vec = (0..n).map(|i| i as f32).collect(); + let expected = (0..n) + .map(|i| { + let first = i - i % 32; + lanes[first..(first + 32).min(n)].iter().sum() + }) + .collect(); + HostCase { + buffers: vec![lanes, vec![0.0; n]], + checked: 1, + expected, + what: "32-lane sums over 0..128, every lane holding its warp's total", + } + } + other => return Err(format!("no host model for export `{other}`").into()), + }; + if case.buffers.len() != desc.params.len() || !desc.params[case.checked].access.is_output() { + return Err(format!( + "`{}`: the host model does not match the described parameters", + desc.decl + ) + .into()); + } + Ok(case) +} + +/// Run `call_` over one tile, one thread per footprint, and compare +/// every element of the checked buffer with the host model. +fn check_export( + ctx: &Arc, + module: &Arc, + desc: &TileExportDesc, +) -> Fallible<()> { + let n = usize::try_from(desc.shape[0])?; + let footprint = usize::try_from(desc.params[0].footprint)?; + if n % footprint != 0 { + return Err(format!( + "`{}`: footprint {footprint} does not divide the tile size {n}", + desc.decl + ) + .into()); + } + let invocations = n / footprint; + let case = host_model(desc, n)?; + + let stream = ctx.default_stream(); + let buffers = case + .buffers + .iter() + .map(|data| DeviceBuffer::from_host(&stream, data)) + .collect::, _>>()?; + let mut pointers: Vec<_> = buffers.iter().map(DeviceBuffer::cu_deviceptr).collect(); + let mut args: Vec<*mut c_void> = pointers + .iter_mut() + .map(|pointer| std::ptr::from_mut(pointer).cast::()) + .collect(); + let function = module.load_function(&format!("call_{}", desc.decl))?; + // SAFETY: the generated kernel takes one device pointer per ABI parameter + // in description order, which is how `args` was built; every buffer holds + // `n` elements, one footprint for each of the `n / footprint` threads + // launched, and outlives the launch; the stream belongs to the module's + // context. + unsafe { + launch_kernel_on_stream( + &function, + (1, 1, 1), + (u32::try_from(invocations)?, 1, 1), + 0, + &stream, + &mut args, + )?; + } + + let got = buffers[case.checked].to_host_vec(&stream)?; + let mismatches: Vec<_> = got + .iter() + .zip(&case.expected) + .enumerate() + .filter(|(_, (got, expected))| got != expected) + .collect(); + if let Some((index, (got, expected))) = mismatches.first() { + return Err(format!( + "`{}`: {} of {n} elements differ, first at [{index}]: got {got}, expected {expected}", + desc.decl, + mismatches.len() + ) + .into()); + } + let footprints = if footprint == 1 { + String::new() + } else { + format!(" in {invocations} footprints of {footprint}") + }; + println!( + "PASS {}: {n} elements{footprints} through `{}`, {}", + desc.decl, desc.symbol, case.what + ); + Ok(()) +} diff --git a/cuda-oxide/crates/rustc-codegen-cuda/examples/tilelib_relu/tile_caller b/cuda-oxide/crates/rustc-codegen-cuda/examples/tilelib_relu/tile_caller new file mode 100755 index 0000000000000000000000000000000000000000..b17e0e6b9e21680d92cad9306910123bb8eeb7bb GIT binary patch literal 1152560 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

HWOFBZ?(Af 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�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�gNzT-euzNveZ#u29Z6Z>h(+lKM=Q~UZ# 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 z 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 UqyEeFzsSF=RyR8r?EH20hqWwCK>z>% literal 0 HcmV?d00001 diff --git a/cuda-oxide/cuda-oxide-book/advanced/images/tilelib-direct-linkage.svg b/cuda-oxide/cuda-oxide-book/advanced/images/tilelib-direct-linkage.svg new file mode 100644 index 0000000000..b6ee2b4305 --- /dev/null +++ b/cuda-oxide/cuda-oxide-book/advanced/images/tilelib-direct-linkage.svg @@ -0,0 +1,107 @@ + + + + +Direct linkage: a Tile kernel calls a Rust function through a .tilelib +cuda-oxide is the SIMT provider. It ships code plus a description; the Tile compiler matches, marshals and links. +RUST SIDE (cuda-oxide) +TILE COMPILER (tileiras, CUDA 13.5 or newer) +TILE SIDE (Tile C++, cuTile Python or cutile-rs) + +#[tile_export(tile_shape = 128)] +pub fn relu(x: f32) -> f32 { .. } + +cargo oxide tilelib relu --arch sm_120 + +relu.ltoir +code: LLVM bitcode for nvJitLink + +relu.iface.tilebc +declaration: what can be called + +relu.impl.tilebc +implementation: how to call it + +tileiras --preview-create-tile-lib + +relu.tilelib +one host object file + +.nvtlifc +declaration + +.nvtl.0 +implementation + +.nvtl.1 +LTOIR + +tileiras --preview=simt prog.tilebc + -l relu.tilelib -o kernel.cubin + + +1 +splice the declaration from .nvtlifc +into the program + +2 +pick an implementation whose fragment +layout fits the call site + +3 +lower the boundary: spill the tile to +per-thread buffers, call relu_impl per invocation + +4 +nvJitLink: tile code + relu.ltoir +cross-module LTO, then SASS + +-l + +program + + +one cubin +tile kernel and relu_impl linked together + +tp.foreign_call(tilelibs=(relu_lib,), + symbol_name="relu", inputs=(x, zeros), + output_types=((f32, (128,)),)) + +the frontend emits + +prog.tilebc +preview$call @relu(%x, %out) + +The Tile frontend's half. It only emits the call +and passes the library on. It never sees Rust. + +THREE FILES, TWO KINDS + +.tilebc +metadata the Tile compiler reads: names, tile types, fragment layouts, scope. +No code inside. Written by oxide-tilebc from the #[tile_export] description. + +.ltoir +the code: LLVM bitcode, finalized to SASS by nvJitLink at link time. +The Tile compiler never looks inside it. Our existing emit-ltoir pipeline. +THE ABI THE MACRO GENERATES +fn relu(x: f32) -> f32 +becomes +extern "C" fn relu_impl(x: f32, out: *mut f32) +scalar in: by value · out and inout: a pointer · results travel through pointers +no logical thread id: threadIdx.x is the real one · shared memory only through scratch +Later: a linkage provider .so answers the same two things on demand. + diff --git a/cuda-oxide/cuda-oxide-book/advanced/tile-libraries.md b/cuda-oxide/cuda-oxide-book/advanced/tile-libraries.md new file mode 100644 index 0000000000..80098f03d9 --- /dev/null +++ b/cuda-oxide/cuda-oxide-book/advanced/tile-libraries.md @@ -0,0 +1,434 @@ +# Tile Libraries + +A Tile kernel works on whole tiles and never names a thread. A SIMT function +works on one element from one thread. A **tile library** joins the two. It +packages Rust device functions so the Tile compiler can call them from inside +a cuTile kernel, once per element or once per warp, and link them into the +kernel's cubin. The Rust side is `#[tile_export]`, the packaging is +`cargo oxide tilelib`, and the caller is cuTile Python's `foreign_call` today, +with [cutile-rs](https://nvidia.github.io/cuda-rust/cutile/) to follow. + +```text +#[tile_export(tile_shape = 128)] +pub fn relu(x: f32) -> f32 { .. } your Rust function + | + | cargo oxide tilelib --arch sm_120 + v +.ltoir device code void relu_impl(float x, float *relu_out) +.iface.tilebc declaration @relu(tile<128xf32> in, tile<128xf32> out) -> tile<128xf32> +.impl.tilebc implementation @relu_impl implements @relu, one invocation per element + | + | tileiras --preview-create-tile-lib (CUDA 13.5 or newer) + v +.tilelib + | + | tp.foreign_call(symbol_name="relu", ...) inside a cuTile kernel + v +the Tile compiler links relu_impl into the kernel's cubin +``` + +:::{seealso} +[Kernels and Device Functions](../gpu-programming/kernels-and-device-functions.md) +covers `#[device]` and the LTOIR route to CUDA C++. A tile library is the same +route with the Tile compiler as the caller. +::: + +```{figure} images/tilelib-direct-linkage.svg +:align: center +:width: 100% + +The direct-linkage path. cuda-oxide ships the code (LTOIR) and two +descriptions (interface and implementation bytecode); tileiras packs them +into one `.tilelib`, and a Tile kernel calls the Rust function from inside +its body. +``` + +## Writing an export + +Put `#[tile_export(tile_shape = N)]` on an ordinary function. `N` is the tile size +the caller will pass. The function stays as written, so the rest of your +device code keeps calling it. The attribute adds two items next to it: an +`extern "C"` implementation on the native SIMT ABI, named `_impl` by +default, and a host-only description that the compiler writes out as JSON. + +The +[`tilelib_relu`](https://github.com/NVIDIA/cuda-rust/tree/main/cuda-oxide/crates/rustc-codegen-cuda/examples/tilelib_relu) +example exports three functions, and this chapter follows them: + +```rust +use cuda_device::{tile_export, warp}; + +/// Elementwise `max(x, 0)`. +#[tile_export(tile_shape = 128)] +pub fn relu(x: f32) -> f32 { + if x > 0.0 { x } else { 0.0 } +} + +/// Scale a tile in place. The cuTile side knows it as `scale_in_place`. +#[tile_export( + tile_shape = 128, + name = "scale_in_place", + symbol = "scale_in_place_impl" +)] +pub fn scale(x: &mut f32, factor: f32) { + *x *= factor; +} + +/// Sum over the 32 lanes of each warp; every lane gets the warp total. +#[tile_export(tile_shape = 128, sync = "warp")] +pub fn warp_sum(x: f32) -> f32 { + let mut total = x; + let mut offset = 16; + while offset > 0 { + total += warp::shuffle_xor_f32_sync(u32::MAX, total, offset); + offset /= 2; + } + total +} +``` + +What each one becomes in the device artifact: + +| cuTile name | Rust | Implementation the call resolves to | +|:-----------------|:----------------------------------------|:---------------------------------------------------| +| `relu` | `fn relu(x: f32) -> f32` | `void relu_impl(float x, float *relu_out)` | +| `scale_in_place` | `fn scale(x: &mut f32, factor: f32)` | `void scale_in_place_impl(float *x, float factor)` | +| `warp_sum` | `fn warp_sum(x: f32) -> f32`, warp sync | `void warp_sum_impl(float x, float *warp_sum_out)` | + +`warp_sum` uses warp shuffles, which are legal because `sync = "warp"` makes +all 32 lanes of a warp call it together. The +[Warp-Level Programming](warp-level-programming.md) chapter explains the +shuffle pattern. + +### Attribute arguments + +| Argument | Meaning | Default | +|:----------------------------|:-------------------------------------------------|:-------------------| +| `tile_shape = N` | 1-D tile size, an integer literal (required) | none | +| `name = "..."` | declaration name the cuTile caller uses | the function name | +| `symbol = "..."` | implementation symbol in the device artifact | `_impl` | +| `sync = "none"` or `"warp"` | threads that must call the function together | `"none"` | +| `arch = ["sm_120", ...]` | compute capabilities the implementation supports | every architecture | + +`arch` is normally omitted, which matches every target. When given, names are +compared after stripping `_` and lowercasing, so `"sm_120"` also matches the +`sm_120a` the Tile compiler builds for. + +### Parameters and the ABI + +Every parameter is a plain identifier with one of four types. `T` is one of +`f16`, `f32`, `f64`, `i8`, `i16`, `i32`, `i64`, `u8`, `u16`, `u32`, `u64`. +Tile IR has no unsigned integers, so a `u32` parameter is an `i32` tile on the +Tile side, same bits. + +| Rust parameter | Access | Footprint | ABI parameter | +|:----------------------|:--------|:----------|:--------------------------------------| +| `x: T` | `in` | 1 | `T` by value | +| `x: &T` | `in` | 1 | `*const T` | +| `x: &[T; F]` | `in` | F | `*const T` | +| `x: &mut T` | `inout` | 1 | `*mut T` | +| `x: &mut [T; F]` | `inout` | F | `*mut T` | +| `-> T` (return value) | `out` | 1 | `*mut T`, appended last as `_out` | + +The footprint is the number of contiguous tile elements one invocation owns. +Only an `in` scalar travels by value. Everything else is a pointer to the +invocation's own elements, and the implementation returns nothing: a return +value is stored through the trailing `out` pointer. On the Tile side every +parameter, the return slot included, is one argument of the declaration, typed +as a tile of the export's size. Slices, raw pointers, tuples, structs, `bool`, +generics, `self`, and patterns in parameter position are rejected. + +### Rules the tooling enforces + +The attribute reports these at compile time: + +- `tile_shape` is present, an integer literal, and positive. A constant or an + expression is not accepted: a static library ships one concrete symbol per + export. +- The export has an output: a return value, or at least one `&mut` parameter. + A declaration's results are its `out` and `inout` arguments. +- The `out` and `inout` parameters form one contiguous run. + `fn f(a: &mut f32, b: f32) -> f32` is `[inout, in, out]` and is rejected; + write `fn f(b: f32, a: &mut f32) -> f32`, with the `in` parameters first. +- Every parameter of one export has the same footprint, because the + fragments of one implementation share their invocation count. A + `&mut [i32; 4]` next to a `&i32` would need 32 invocations for one argument + and 128 for the other, so `fn window(acc: &mut [i32; 4], bias: &i32)` is + rejected and `bias: &[i32; 4]` is the accepted form. +- `sync = "warp"` needs a tile size that is a multiple of 32 times the + footprint, so every invocation fills whole warps. +- `name` and `symbol` are ASCII identifiers outside the reserved + `cuda_oxide_` prefix. + +`cargo oxide tilelib` repeats the same checks when it reads the descriptions +back, so a hand-edited description cannot slip past them. + +## Building the library + +```bash +cargo oxide tilelib tilelib_relu --arch sm_120 --print +``` + +`--arch` is required because the LTOIR inside a library is built for one +architecture. In a standalone project, such as one made with `cargo oxide new`, +the crate name can be omitted. The command runs `emit-ltoir`, then writes the +description modules next to the device artifact: + +```text +tilelib_relu.ltoir device code for sm_120 +tilelib_relu.tileexports.json one description per export, written by the compiler +tilelib_relu.iface.tilebc declarations, Tile IR bytecode at the assembler's version +tilelib_relu.impl.tilebc implementations, same version +tilelib_relu.tilelib.mlir readable form of both; --print shows it +tilelib_relu.tilelib the library, when tileiras can build it +``` + +Before writing the modules it checks the emitted NVVM IR: every implementation +symbol must be a `define void` with the parameter list the ABI table predicts, +for example `define void @relu_impl(float, ptr)`. The assembler never looks +inside the code payload, so a missing or misdeclared symbol would otherwise +surface only when a cuTile program is compiled against the library. The two +bytecode modules are built by the `oxide-tilebc` crate, cuda-oxide's own +writer for these two kinds of module; the Tile stack's crates are not +involved. +writes its own Tile IR with. + +### Reading the dump + +`--print` shows both modules in Tile IR syntax. The text is the same as +`tilelib_relu.tilelib.mlir`. For `tilelib_relu`: + +```text +// tilelib_relu.iface.tilebc: the interface a cuTile program calls +cuda_tile.module @tilelib_relu { + cuda_tile.preview$func extern @relu(%x: !cuda_tile.tile<128xf32> {cuda_tile.preview$access = #cuda_tile.preview$access}, %relu_out: !cuda_tile.tile<128xf32> {cuda_tile.preview$access = #cuda_tile.preview$access}) -> !cuda_tile.tile<128xf32> + cuda_tile.preview$func extern @scale_in_place(%x: !cuda_tile.tile<128xf32> {cuda_tile.preview$access = #cuda_tile.preview$access}, %factor: !cuda_tile.tile<128xf32> {cuda_tile.preview$access = #cuda_tile.preview$access}) -> !cuda_tile.tile<128xf32> + cuda_tile.preview$func extern @warp_sum(%x: !cuda_tile.tile<128xf32> {cuda_tile.preview$access = #cuda_tile.preview$access}, %warp_sum_out: !cuda_tile.tile<128xf32> {cuda_tile.preview$access = #cuda_tile.preview$access}) -> !cuda_tile.tile<128xf32> +} +// tilelib_relu.impl.tilebc: the implementations the LTOIR defines +cuda_tile.module @tilelib_relu { + cuda_tile.preview$extern_impl @relu_impl implements @relu(%x: !cuda_tile.preview$fragment<1xf32, local, mem_layout = #cuda_tile.preview$layout<():()>, fragmap = #cuda_tile.preview$layout<(128, 1, 1):(1, 0, 0)>> {cuda_tile.preview$access = #cuda_tile.preview$access}, %relu_out: !cuda_tile.preview$fragment<1xf32, local, mem_layout = #cuda_tile.preview$layout<(1):(1)>, fragmap = #cuda_tile.preview$layout<(128, 1, 1):(1, 0, 0)>> {cuda_tile.preview$access = #cuda_tile.preview$access}) + cuda_tile.preview$extern_impl @scale_in_place_impl implements @scale_in_place(%x: !cuda_tile.preview$fragment<1xf32, local, mem_layout = #cuda_tile.preview$layout<(1):(1)>, fragmap = #cuda_tile.preview$layout<(128, 1, 1):(1, 0, 0)>> {cuda_tile.preview$access = #cuda_tile.preview$access}, %factor: !cuda_tile.preview$fragment<1xf32, local, mem_layout = #cuda_tile.preview$layout<():()>, fragmap = #cuda_tile.preview$layout<(128, 1, 1):(1, 0, 0)>> {cuda_tile.preview$access = #cuda_tile.preview$access}) + cuda_tile.preview$extern_impl @warp_sum_impl implements @warp_sum(%x: !cuda_tile.preview$fragment<1xf32, local, mem_layout = #cuda_tile.preview$layout<():()>, fragmap = #cuda_tile.preview$layout<(4, 32, 1):(32, 1, 0)>> {cuda_tile.preview$access = #cuda_tile.preview$access}, %warp_sum_out: !cuda_tile.preview$fragment<1xf32, local, mem_layout = #cuda_tile.preview$layout<(1):(1)>, fragmap = #cuda_tile.preview$layout<(4, 32, 1):(32, 1, 0)>> {cuda_tile.preview$access = #cuda_tile.preview$access}) + synchronization = #cuda_tile.preview$synchronization +} +``` + +How to read it: + +- The interface has one `preview$func extern` per export. Every Rust parameter + is a `tile<128xf32>` argument with its access, and the results are the + `out` and `inout` arguments in order. `relu` returns one tile, its + `relu_out` slot. +- The implementation has one `preview$extern_impl` per export, naming the + symbol it `implements`. Every argument is a `fragment`: the piece of the tile + one invocation sees. `mem_layout` is the buffer's own layout: `():()` for a + by-value scalar, `(1):(1)` for one element behind a pointer. +- `fragmap` maps `(invocations, participants, footprint)` onto the tile. + `(128, 1, 1):(1, 0, 0)` is one invocation per element, 128 of them. + `(4, 32, 1):(32, 1, 0)` is 4 invocations of 32 lanes each, which is what + `synchronization = warp` requires. + +The summary line names the artifacts and their sizes: + +```text +✓ Tile library descriptions written: 3 export(s), Tile IR 13.5 with the preview tag +``` + +### The tileiras requirement + +The descriptions are Tile IR public-preview content, which exists from +bytecode 13.5 on. An assembler reads preview content only at the version it +calls current, the newest numbered version its `--list-versions` prints, so +the command asks the resolved `tileiras` first and writes the descriptions at +that version: 13.5 for the CUDA 13.5 assembler, the newer version a newer +assembler names, and 13.5 when no assembler can read them yet. +`tileiras --preview-create-tile-lib` arrives with CUDA 13.5, the first +assembler whose `--list-versions` names 13.5. When the resolved `tileiras` +lists 13.5 or newer, the command assembles the interface, the +implementations, and the LTOIR into `tilelib_relu.tilelib` (or the path given +with `-o`) and prints the `tileiras` invocation it used. + +On CUDA 13.4 the command stops after the descriptions and says why: + +```text +Tile library skipped: /usr/local/cuda/bin/tileiras lists bytecode versions 13.1, 13.2, 13.3, 13.4; the descriptions need 13.5 or newer +The installed tileiras cannot create tile libraries: the descriptions are Tile IR public-preview content, which exists from bytecode 13.5 on and needs the CUDA 13.5 or newer assembler. +``` + +It then prints the `tileiras --preview-create-tile-lib` command that turns the +written files into the library on a newer toolkit, and exits 2 so a script +notices the missing library. `--library-optional` makes that outcome exit 0 +when the LTOIR and the descriptions are all you need. Both outcomes print a +line a script can match: `Tile library written to` on success, +`Tile library skipped:` otherwise. The assembler is resolved from +`CUTILE_TILEIRAS_PATH` first, then from `PATH`, the configured CUDA toolkit +root, and the standard install locations. The +[installation guide](../getting-started/installation.md) covers toolkit +selection. + +## Calling it from cuTile Python + +A cuTile kernel reaches the export through `cuda.tile_preview.foreign_call`. +This is the kernel from the example's `python/call_from_cutile.py`: + +```python +import cuda.tile as ct +from cuda import tile_preview as tp + +TILE = 128 +PROVIDER = tp.Tilelib(path="tilelib_relu.tilelib", version="0.1.0") + + +def relu_tile(x, y): + """One block runs `relu` over one 128-float tile of `x` into `y`.""" + pid = ct.bid(0) + tile = ct.load(x, index=(pid,), shape=(TILE,)) + # Every declaration argument needs an input tile, the `out` slot included. + result_slot = ct.zeros((TILE,), dtype=ct.float32) + (out,) = tp.foreign_call( + tilelibs=(PROVIDER,), + symbol_name="relu", + constant_params=(), + inputs=(tile, result_slot), + output_types=((ct.float32, (TILE,)),), + ) + ct.store(y, index=(pid,), tile=out) +``` + +Three things to get right: + +- `symbol_name` is the declaration name, `relu`, not the implementation symbol + `relu_impl`. The Tile compiler resolves the call to the implementation when + it links the library. +- Every declaration argument takes a tile, the `out` ones included. `relu` has + two arguments, so `inputs` has two tiles; a zero tile stands in for the + result slot. A scalar needs a 0-d tile, and a Python literal is rejected. +- `output_types` lists the results, one `(dtype, shape)` per `out` or `inout` + argument in declaration order. `relu` has one. + +`foreign_call` reads the library as a compile-time constant, so the `Tilelib` +is a module global rather than a kernel argument, and its file has to exist +when the kernel is traced. The script's `--dry-run` compiles the kernel to +bytecode without `tileiras`, which works on CUDA 13.4 today: + +```text +bytecode: 844 bytes, header 0d050100 (version 13.5, preview flag set) +PASS: the caller side compiles; the program calls `relu` through preview$call (dry run, no cubin) +``` + +The full run needs the `.tilelib` from a CUDA 13.5 or newer `tileiras` and +a cuTile Python that lists that assembler's current bytecode version, because +preview content is read only at that version. + +## Calling it from Tile C++ + +The same toolkit that brings the assembler teaches nvcc `--enable-tile` and +`--tile-preview simt`, and a Tile C++ kernel calls the library through a +foreign declaration. The example's `cpp/tile_caller.cu` declares all three +exports; this is the `relu` one: + +```text +namespace ct = cuda::tiles; +using tile_f32 = ct::tile>; + +// @relu(%x: tile<128xf32> in, %relu_out: tile<128xf32> out) -> tile<128xf32> +__experimental_foreign_decl__ __experimental_foreign_name__("relu") + tile_f32 relu(tile_f32 x, [[cutile::experimental_inout]] tile_f32 relu_out); + +[[cutile::hint(0, num_worker_warps_per_cta = 4)]] __tile_global__ void kernel(float* x, float* y) { + auto xs = ct::partition_view { ct::tensor_span { x, ct::shape<128> {} }, ct::shape<128> {} }; + auto ys = ct::partition_view { ct::tensor_span { y, ct::shape<128> {} }, ct::shape<128> {} }; + ys.store(relu(xs.load(0), ys.load(0)), 0); +} +``` + +A parameter the library reads carries no attribute; one it writes carries +`[[cutile::experimental_inout]]` and comes back as the call's result, in +argument order. The declaration's name is the library's declaration name, +not the implementation symbol. Compile and run: + +```bash +nvcc --enable-tile --tile-preview simt -Xtileiras=-l=tilelib_relu.tilelib \ + -std=c++20 -arch=sm_120 -o tile_caller cpp/tile_caller.cu +./tile_caller +``` + +```text +PASS relu: 128 elements through the tile library +PASS scale_in_place: 128 elements through the tile library +PASS warp_sum: 128 elements through the tile library, every lane holding its warp's total +SUCCESS: 3/3 tile exports called from a Tile C++ kernel +``` + +Because nvcc, tileiras and the Tile C++ front end come from one toolkit, the +program and the library always agree on the bytecode version. That is the +shortest path to a running Tile kernel on top of a Rust library; the cuTile +Python path needs a cuTile Python that lists the same assembler's version. + +## What happens at the boundary + +The Tile compiler never hands your function a whole tile. It splits each tile +argument into fragments, one per invocation, and calls the implementation once +per fragment. With `sync = "none"` a fragment is one element, so a 128-element +tile means 128 calls, each from one thread. With `sync = "warp"` an invocation +is a whole warp: 32 lanes call together, each with its own element, and warp +intrinsics are legal inside. The calling thread is a real thread of the Tile +kernel, and `threadIdx.x` reads the hardware register, so lane and warp +identity work as in any SIMT kernel (see the +[Execution Model](../gpu-programming/execution-model.md)). + +The pointers you receive point at the invocation's own buffer and nothing +else. `&mut f32` is one element and `&mut [f32; 4]` is four contiguous +elements; the function may not reach past them, and nothing outside the +invocation aliases them during the call. The function cannot allocate shared +memory, so do not declare a `SharedArray` in an export: the shared memory of a +Tile kernel is the Tile compiler's to place, and this release has no way to +request a scratch buffer from it (see +[Shared Memory and Synchronization](shared-memory-and-synchronization.md) +for what shared memory means in a SIMT kernel). Keep exports to registers, +the parameters they receive, and warp traffic. + +## Not in this release + +- Parametric tile sizes. `tile_shape` is one integer literal, so a library ships one + export per tile size. +- Warpgroup and CTA scope. `sync` accepts `"none"` and `"warp"` only. +- Scratch memory. An export cannot ask for a shared-memory buffer. +- `bf16` parameters. The attribute accepts `f16` but not `bf16` yet. +- 2-D tiles. `tile_shape` has one extent. +- Linkage providers, the form of a library that compiles implementations on + demand while the Tile compiler runs. They are not a public CUDA 13.5 + surface. A static library ships one implementation per declaration. +- A cutile-rs caller. Only cuTile Python has `foreign_call` today. + +The [Supported Features](../appendix/supported-features.md) appendix tracks +the interop status alongside the rest of the compiler. + +### Verifying the ABI on CUDA 13.4 + +The `.tilelib` needs the CUDA 13.5 or newer assembler, but the ABI can be +proven today. The example's +host program stands in for the Tile compiler: + +```bash +cargo oxide run tilelib_relu --emit-nvvm-ir --arch sm_120 +``` + +It reads `tilelib_relu.tileexports.json`, generates `mock/caller.cu` with the +prototypes the ABI table predicts and one kernel per export, compiles that with +`nvcc` to LTOIR, links it with the Rust LTOIR through nvJitLink, the same +two-input link a consumed library gets, and runs one block of 128 threads per +export on the GPU. Every result is compared bit for bit: + +```text +PASS relu: 128 elements through `relu_impl`, relu of a ramp from -4 to 4 +PASS scale_in_place: 128 elements through `scale_in_place_impl`, the ramp scaled in place by 0.5 +PASS warp_sum: 128 elements through `warp_sum_impl`, 32-lane sums over 0..128, every lane holding its warp's total +SUCCESS: 3/3 tile exports verified through the native ABI +``` + +The prototypes in `mock/caller.cu` are derived from the descriptions, not +written by hand, so the generated file is the ABI as the tooling understands +it. Without `nvcc`, or on a GPU that does not match `--arch`, the program +prints `skipping:` with the reason and exits 0. diff --git a/cuda-oxide/cuda-oxide-book/appendix/supported-features.md b/cuda-oxide/cuda-oxide-book/appendix/supported-features.md index 5081ab5e30..c038225a85 100644 --- a/cuda-oxide/cuda-oxide-book/appendix/supported-features.md +++ b/cuda-oxide/cuda-oxide-book/appendix/supported-features.md @@ -160,7 +160,7 @@ Anonymous promoted allocations remain unsupported. | Bi-directional LTOIR Support | **Full** | Rust kernels call CUDA C++ device functions **and** C++ calls Rust device functions. Via NVVM IR → libNVVM → LTOIR → nvJitLink. | | Device FFI (`extern "C"`) | **Full** | `#[device] extern "C" { fn ... }` declarations for external LTOIR functions. CUB/CCCL integration demonstrated. | | MathDx FFI (cuFFTDx / cuBLASDx) | **Full** | cuFFTDx (8/16/32-point thread-level FFT), cuBLASDx (32x32x32 block-level GEMM) via LTOIR. | -| Tile interop | **Partial** | Inter-kernel interop works today: a [cutile-rs Tile kernel](https://github.com/NVIDIA/cuda-rust/tree/main/cutile-rs) and a cuda-oxide SIMT PTX kernel can run in one host process on the same CUDA stream over shared device tensors. Intra-kernel Tile interop is work in progress and tracked in [#96](https://github.com/NVlabs/cuda-oxide/issues/96). | +| Tile interop | **Partial** | Inter-kernel interop works today: a [cutile-rs Tile kernel](https://github.com/NVIDIA/cuda-rust/tree/main/cutile-rs) and a cuda-oxide SIMT PTX kernel can run in one host process on the same CUDA stream over shared device tensors. Intra-kernel interop is built as a [tile library](../advanced/tile-libraries.md): `#[tile_export]` and `cargo oxide tilelib` produce the LTOIR and the Tile IR descriptions today (at the installed assembler's current bytecode version, 13.5 or newer), packaging them into a `.tilelib` needs the CUDA 13.5 or newer `tileiras`, and the caller is cuTile Python's `foreign_call`. Tracked in [#96](https://github.com/NVlabs/cuda-oxide/issues/96). | | Cross-Crate Kernels | **Full** | Kernels and device functions defined in library crates with monomorphization at the binary crate use site. | ## Compiler: Functions diff --git a/cuda-oxide/cuda-oxide-book/getting-started/installation.md b/cuda-oxide/cuda-oxide-book/getting-started/installation.md index eb929a4eaf..5a6740b18d 100644 --- a/cuda-oxide/cuda-oxide-book/getting-started/installation.md +++ b/cuda-oxide/cuda-oxide-book/getting-started/installation.md @@ -327,6 +327,7 @@ The full set, as `cargo oxide --help` reports it: | `fuzz-schedule` | Find schedule-sensitive failures by perturbing an example's generated PTX | | `test` | Run Cargo tests through the cuda-oxide backend | | `emit-ltoir` | Compile a crate's device code to a binary LTOIR artifact in one step | +| `tilelib` | Package a crate's `#[tile_export]` functions as a cuTile tile library | | `pipeline` | Show the full compilation pipeline (MIR -> PTX/NVVM IR) with verbose output | | `debug` | Build with debug info and launch `cuda-gdb` | | `list` | List the examples bundled with the cuda-oxide workspace | diff --git a/cuda-oxide/cuda-oxide-book/index.md b/cuda-oxide/cuda-oxide-book/index.md index 5c15827081..1529d376cb 100644 --- a/cuda-oxide/cuda-oxide-book/index.md +++ b/cuda-oxide/cuda-oxide-book/index.md @@ -178,6 +178,7 @@ advanced/warp-level-programming advanced/tensor-memory-accelerator advanced/matrix-multiply-accelerators advanced/cluster-programming +advanced/tile-libraries ``` ```{toctree} diff --git a/cuda-oxide/scripts/check-example-smoketest-contract.sh b/cuda-oxide/scripts/check-example-smoketest-contract.sh index 6ec700e8f0..710032d4e8 100644 --- a/cuda-oxide/scripts/check-example-smoketest-contract.sh +++ b/cuda-oxide/scripts/check-example-smoketest-contract.sh @@ -309,6 +309,7 @@ CATEGORY_LISTS = ( "BLACKWELL_MMA_EXAMPLES", "LTOIR_EXAMPLES", "LTOIR_MODERN_EXAMPLES", + "TILELIB_EXAMPLES", "AUTO_NVVM_EXAMPLES", "IKET_EXAMPLES", "BLACKWELL_COMPILE_EXAMPLES", diff --git a/cuda-oxide/scripts/smoketest.sh b/cuda-oxide/scripts/smoketest.sh index 92823ad212..0d23fca93e 100755 --- a/cuda-oxide/scripts/smoketest.sh +++ b/cuda-oxide/scripts/smoketest.sh @@ -40,6 +40,20 @@ # Blackwell+ (CC >= 10.0) and requires full execution # there; elsewhere compiles for the sm_100 floor and # requires the NVVM IR (`.ll`) plus its `.target` sidecar. +# tilelib -- a tile library written in Rust (`#[tile_export]`). +# `cargo oxide tilelib --arch= --library-optional` +# must exit 0 and leave the LTOIR, the interface and the +# implementation bytecode (`.iface.tilebc`, `.impl.tilebc`) +# and the readable `.tilelib.mlir`. cargo-oxide decides +# itself whether the installed tileiras can build the +# `.tilelib` (it lists bytecode 13.5, CUDA 13.5+) and ends +# its summary with one of two lines: after "Tile library +# written to" the `.tilelib` must exist too, after "Tile +# library skipped" it is not required; neither line fails +# the lane. Then the example's host program runs through +# `cargo oxide run --emit-nvvm-ir --arch=` and must +# print the SUCCESS marker, or opt out with `skipping:`. +# --compile-only stops after the first step. # auto-nvvm -- runs without NVVM or architecture flags to check automatic # libdevice and target selection. Compile-only CI supplies a # target because no GPU is available. @@ -78,6 +92,7 @@ WGMMA_EXAMPLES=(wgmma) BLACKWELL_MMA_EXAMPLES=(mma_mxf8f6f4) LTOIR_EXAMPLES=(addressof_sharedarray cpp_consumes_rust_device device_ffi_test legacy_atomic_fadd legacy_atomic_rmw_cas legacy_nvvm_pointer_shapes manual_launch_libdevice mathdx_ffi_test primitive_stress) LTOIR_MODERN_EXAMPLES=(small_type_ffi_test) +TILELIB_EXAMPLES=(tilelib_relu) AUTO_NVVM_EXAMPLES=(libdevice_math) IKET_EXAMPLES=(iket_trace) BLACKWELL_COMPILE_EXAMPLES=(generated_intrinsics_blackwell) @@ -126,6 +141,7 @@ classify() { for cat in "${BLACKWELL_MMA_EXAMPLES[@]}"; do [[ "$ex" == "$cat" ]] && { echo blackwell-mma; return; }; done for cat in "${LTOIR_EXAMPLES[@]}"; do [[ "$ex" == "$cat" ]] && { echo ltoir; return; }; done for cat in "${LTOIR_MODERN_EXAMPLES[@]}"; do [[ "$ex" == "$cat" ]] && { echo ltoir-modern; return; }; done + for cat in "${TILELIB_EXAMPLES[@]}"; do [[ "$ex" == "$cat" ]] && { echo tilelib; return; }; done for cat in "${AUTO_NVVM_EXAMPLES[@]}"; do [[ "$ex" == "$cat" ]] && { echo auto-nvvm; return; }; done for cat in "${IKET_EXAMPLES[@]}"; do [[ "$ex" == "$cat" ]] && { echo iket; return; }; done for cat in "${BLACKWELL_COMPILE_EXAMPLES[@]}"; do [[ "$ex" == "$cat" ]] && { echo blackwell-compile; return; }; done @@ -150,6 +166,45 @@ example_never_launches() { return 1 } +example_is_tilelib() { + local ex="$1" candidate + for candidate in "${TILELIB_EXAMPLES[@]}"; do + [[ "${ex}" == "${candidate}" ]] && return 0 + done + return 1 +} + +# The two summary lines `cargo oxide tilelib` ends with, one of which every +# successful run prints: the library was written, or skipped because the +# resolved tileiras cannot build one. They are constants in +# crates/cargo-oxide/src/commands/tilelib.rs (LIBRARY_WRITTEN_MARKER, +# LIBRARY_SKIPPED_MARKER) and a unit test there pins the text grepped here. +# cargo-oxide resolves tileiras and reads its `--list-versions` itself, so the +# lane takes its verdict from the log instead of probing the assembler a +# second time with a search order of its own. +tilelib_library_written() { + grep -qF 'Tile library written to' "$1" +} + +tilelib_library_skipped() { + grep -qF 'Tile library skipped' "$1" +} + +# Names, space separated, of the tilelib artifacts `cargo oxide tilelib` must +# have left for ${1} given its log ${2}; empty when every one is present. The +# LTOIR, the two bytecode halves and the readable dump are always required; +# the `.tilelib` itself when the log says it was written. +tilelib_missing_artifacts() { + local ex_dir="crates/rustc-codegen-cuda/examples/$1" artifact="${1//-/_}" log="$2" missing="" file + for file in "${artifact}.ltoir" "${artifact}.iface.tilebc" "${artifact}.impl.tilebc" "${artifact}.tilelib.mlir"; do + [[ -s "${ex_dir}/${file}" ]] || missing="${missing} ${file}" + done + if tilelib_library_written "${log}" && [[ ! -s "${ex_dir}/${artifact}.tilelib" ]]; then + missing="${missing} ${artifact}.tilelib" + fi + printf '%s' "${missing# }" +} + full_debug_uses_configured_route() { local ex="$1" candidate for candidate in "${FULL_DEBUG_CONFIGURED_ROUTE_EXAMPLES[@]}"; do @@ -872,6 +927,40 @@ verdict_ltoir_modern() { return 1 } +verdict_tilelib() { + local ex="$1" log="$2" ec="$3" + if [[ ${ec} -gt 128 ]]; then echo "FAIL (crashed, signal $((ec - 128)))"; return 1; fi + # The descriptions come first. `cargo oxide tilelib` prints this line + # once both bytecode halves are on disk, and run_tilelib records a + # missing artifact in the log with a failing exit code, so the marker is + # the proof that the library half finished before the host program ran. + if ! grep -qF 'Tile library descriptions written' "${log}"; then + echo "FAIL (tilelib, descriptions not written)" + return 1 + fi + if [[ ${ec} -ne 0 ]]; then echo "FAIL (tilelib, exit=${ec})"; return 1; fi + # The host program opts out without nvcc or a matching GPU; the + # descriptions still had to be written. + if grep -qE '^[[:space:]]*skipping:' "${log}"; then + echo "PASS (tilelib, descriptions written, host check skipped)" + return 0 + fi + if grep_failure_markers "${log}"; then + echo "FAIL (tilelib, failure marker in output)" + return 1 + fi + if grep -qE 'SUCCESS|PASS|Complete' "${log}"; then + if tilelib_library_written "${log}"; then + echo "PASS (tilelib, .tilelib built, ABI verified on ${LTOIR_ARCH})" + else + echo "PASS (tilelib, descriptions written, ABI verified on ${LTOIR_ARCH})" + fi + return 0 + fi + echo "FAIL (tilelib, no success marker)" + return 1 +} + verdict_iket() { local ex="$1" log="$2" ec="$3" local ex_dir="crates/rustc-codegen-cuda/examples/${ex}" @@ -975,6 +1064,24 @@ verdict_compile() { echo "FAIL (libNVVM compile produced no fresh LTOIR)" return 1 fi + if [[ ${FULL_DEBUG} -eq 0 ]] && example_is_tilelib "${ex}"; then + # run_tilelib ran the library step only. It already failed the exit + # code on a missing artifact or a missing summary line; naming the + # artifacts here tells a built library apart from descriptions alone + # in the summary, with cargo-oxide's own reason for skipping it. + local missing + missing="$(tilelib_missing_artifacts "${ex}" "${log}")" + if [[ -n "${missing}" ]]; then + echo "FAIL (tilelib, missing ${missing})" + return 1 + fi + if tilelib_library_written "${log}"; then + echo "PASS (tilelib descriptions and .tilelib for ${LTOIR_ARCH})" + else + echo "PASS (tilelib descriptions for ${LTOIR_ARCH}; $(grep -F 'Tile library skipped' "${log}" | head -1))" + fi + return 0 + fi if [[ -s "${ex_dir}/${artifact}.ptx" ]]; then # Nothing executes in compile-only mode, so every emitted PTX must # at least assemble: driver-JIT-only errors (e.g. .shared symbols @@ -1228,6 +1335,7 @@ run_full_debug_build() { blackwell-mma) arch="sm_120a" ;; ltoir) arch="${LTOIR_ARCH}" ;; ltoir-modern) arch="${LTOIR_MODERN_ARCH}" ;; + tilelib) arch="${LTOIR_ARCH}" ;; auto-nvvm) arch="${LTOIR_ARCH}" ;; iket) arch="sm_90" ;; blackwell-compile) arch="sm_120a" ;; @@ -2035,6 +2143,12 @@ run_cargo() { return fi + # Tile libraries have their own two-step lane in every mode. + if [[ "${cat}" == "tilelib" ]]; then + run_tilelib "${ex}" "${log}" + return + fi + # Designated NVVM examples use `emit-ltoir` in compile-only mode so CI # checks both textual export and real libNVVM compilation. Other examples # use `build`. @@ -2223,6 +2337,59 @@ run_cargo() { fi } +# The tilelib lane: the library half first, then the example's own host +# program, both through `cargo oxide` the way the example's README runs +# them. `--library-optional` lets the first step exit 0 on a toolkit whose +# tileiras cannot build a `.tilelib`; whether that step had to leave one is +# read from its own summary line (tilelib_library_written). The second step +# rebuilds the device half, and a rebuild clears every generated artifact, +# so the artifacts are checked in between and a gap is recorded in the log +# with a failing CARGO_EC, as the other lanes do. +run_tilelib() { + local ex="$1" log="$2" note="" + local -a args=("tilelib" "${ex}" "--arch=${LTOIR_ARCH}" "--library-optional") + if [[ ${VERBOSE} -eq 1 ]]; then + cargo oxide "${args[@]}" 2>&1 | tee "${log}" + CARGO_EC=${PIPESTATUS[0]} + else + cargo oxide "${args[@]}" >"${log}" 2>&1 + CARGO_EC=$? + fi + if [[ ${CARGO_EC} -ne 0 ]]; then + return + fi + # Exit 0 without either summary line means the command's contract + # changed under this lane, not that a library is optional. + if ! tilelib_library_written "${log}" && ! tilelib_library_skipped "${log}"; then + note="${ex}: cargo oxide tilelib --library-optional exited 0 without reporting the tile library as written or skipped" + else + local missing + missing="$(tilelib_missing_artifacts "${ex}" "${log}")" + if [[ -n "${missing}" ]]; then + note="${ex}: cargo oxide tilelib --library-optional exited 0 but left no ${missing}" + fi + fi + if [[ -n "${note}" ]]; then + printf '%s\n' "${note}" >>"${log}" + if [[ ${VERBOSE} -eq 1 ]]; then + printf '%s\n' "${note}" + fi + CARGO_EC=1 + return + fi + if [[ ${COMPILE_ONLY} -eq 1 ]]; then + return + fi + local -a run_args=("run" "${ex}" "--emit-nvvm-ir" "--arch=${LTOIR_ARCH}") + if [[ ${VERBOSE} -eq 1 ]]; then + cargo oxide "${run_args[@]}" 2>&1 | tee -a "${log}" + CARGO_EC=${PIPESTATUS[0]} + else + cargo oxide "${run_args[@]}" >>"${log}" 2>&1 + CARGO_EC=$? + fi +} + # ---- Shared example target dir ------------------------------------------- # # Each example under crates/rustc-codegen-cuda/examples/ is its own standalone @@ -2332,6 +2499,7 @@ for ex in "${selected[@]}"; do blackwell-mma) verdict="$(verdict_blackwell_mma "${ex}" "${log}" "${ec}")" && status=0 || status=$? ;; ltoir) verdict="$(verdict_ltoir "${ex}" "${log}" "${ec}")" && status=0 || status=$? ;; ltoir-modern) verdict="$(verdict_ltoir_modern "${ex}" "${log}" "${ec}")" && status=0 || status=$? ;; + tilelib) verdict="$(verdict_tilelib "${ex}" "${log}" "${ec}")" && status=0 || status=$? ;; auto-nvvm) verdict="$(verdict_ltoir "${ex}" "${log}" "${ec}")" && status=0 || status=$? ;; iket) verdict="$(verdict_iket "${ex}" "${log}" "${ec}")" && status=0 || status=$? ;; standard) verdict="$(verdict_standard "${log}" "${ec}" "${ex}")" && status=0 || status=$? ;;