Files
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

168 lines
6.0 KiB
C++

// Copyright (c) Advanced Micro Devices, Inc., or its affiliates.
// SPDX-License-Identifier: MIT
/*
* C99 port of rocke/helpers/preshuffle.py: PreshuffleBSpec,
* emit_preshuffleb_offset, host_preshuffle_layout.
*
* See the header for the original Python and the contract. The single
* builder-emitting symbol (emit_preshuffleb_offset) reproduces the const_i32 /
* mul / add call sequence byte-faithfully so the downstream IR is identical to
* the Python.
*/
#include "rocke/helper_rocke.helpers.preshuffle.h"
#include "rocke/ir_internal.h" /* rocke_i_set_err */
/* ------------------------------------------------------------------ *
* PreshuffleBSpec.tile_bytes
* ------------------------------------------------------------------ */
int rocke_preshuffleb_spec_tile_bytes(const rocke_preshuffleb_spec_t* spec)
{
/* Python: block_n * block_k * elem_bytes.
* The fields are small Python ints whose product fits in 32 bits for every
* real tile shape, so a plain int multiply reproduces the value exactly. */
if(spec == NULL)
{
return 0;
}
return spec->block_n * spec->block_k * spec->elem_bytes;
}
/* ------------------------------------------------------------------ *
* emit_preshuffleb_offset
* ------------------------------------------------------------------ */
rocke_value_t* rocke_emit_preshuffleb_offset(rocke_ir_builder_t* b,
const rocke_preshuffleb_spec_t* spec,
rocke_value_t* n_tile,
rocke_value_t* k_tile,
rocke_value_t* n_in_tile,
rocke_value_t* k_in_tile,
rocke_value_t* n_tile_count)
{
rocke_value_t* c_tile_bytes;
rocke_value_t* c_block_k;
rocke_value_t* c_elem_bytes;
rocke_value_t* tile_id;
rocke_value_t* tile_base;
rocke_value_t* inner;
rocke_value_t* inner_bytes;
if(b != NULL && b->status != ROCKE_OK)
{
return NULL; /* already in error: no-op */
}
if(spec == NULL)
{
rocke_i_set_err(b, ROCKE_ERR_VALUE, "emit_preshuffleb_offset: NULL spec");
return NULL;
}
/* Python, in this exact order:
* c_tile_bytes = b.const_i32(spec.tile_bytes)
* c_block_k = b.const_i32(spec.block_k)
* c_elem_bytes = b.const_i32(spec.elem_bytes)
* tile_id = b.add(b.mul(k_tile, n_tile_count), n_tile)
* tile_base = b.mul(tile_id, c_tile_bytes)
* inner = b.add(b.mul(n_in_tile, c_block_k), k_in_tile)
* inner_bytes = b.mul(inner, c_elem_bytes)
* return b.add(tile_base, inner_bytes)
*/
c_tile_bytes = rocke_b_const_i32(b, rocke_preshuffleb_spec_tile_bytes(spec));
c_block_k = rocke_b_const_i32(b, spec->block_k);
c_elem_bytes = rocke_b_const_i32(b, spec->elem_bytes);
tile_id = rocke_b_add(b, rocke_b_mul(b, k_tile, n_tile_count), n_tile);
tile_base = rocke_b_mul(b, tile_id, c_tile_bytes);
inner = rocke_b_add(b, rocke_b_mul(b, n_in_tile, c_block_k), k_in_tile);
inner_bytes = rocke_b_mul(b, inner, c_elem_bytes);
return rocke_b_add(b, tile_base, inner_bytes);
}
/* ------------------------------------------------------------------ *
* host_preshuffle_layout
* ------------------------------------------------------------------ */
rocke_status_t rocke_host_preshuffle_layout(
const rocke_preshuffleb_spec_t* spec, int n, int k, int out_shape[4], int out_strides[4])
{
int n_tiles;
int k_tiles;
if(spec == NULL)
{
return ROCKE_ERR_VALUE;
}
/* Python: floor-division on positive ints == ceil((n)/block) given the
* +block-1 numerator. The real specs always have block_n / block_k > 0. */
n_tiles = (n + spec->block_n - 1) / spec->block_n;
k_tiles = (k + spec->block_k - 1) / spec->block_k;
/* Python:
* if n_tiles*block_n != n or k_tiles*block_k != k: raise ValueError(...)
*/
if(n_tiles * spec->block_n != n || k_tiles * spec->block_k != k)
{
return ROCKE_ERR_VALUE;
}
/* shape = (k_tiles, n_tiles, block_n, block_k) */
if(out_shape != NULL)
{
out_shape[0] = k_tiles;
out_shape[1] = n_tiles;
out_shape[2] = spec->block_n;
out_shape[3] = spec->block_k;
}
/* strides = (n_tiles*block_n*block_k, block_n*block_k, block_k, 1) */
if(out_strides != NULL)
{
out_strides[0] = n_tiles * spec->block_n * spec->block_k;
out_strides[1] = spec->block_n * spec->block_k;
out_strides[2] = spec->block_k;
out_strides[3] = 1;
}
return ROCKE_OK;
}
rocke_status_t rocke_b_host_preshuffle_layout(rocke_ir_builder_t* b,
const rocke_preshuffleb_spec_t* spec,
int n,
int k,
int out_shape[4],
int out_strides[4])
{
rocke_status_t st;
if(b != NULL && b->status != ROCKE_OK)
{
return b->status; /* already in error: no-op */
}
if(spec == NULL)
{
rocke_i_set_err(b, ROCKE_ERR_VALUE, "host_preshuffle_layout: NULL spec");
return ROCKE_ERR_VALUE;
}
st = rocke_host_preshuffle_layout(spec, n, k, out_shape, out_strides);
if(st != ROCKE_OK)
{
/* Python:
* raise ValueError(
* "preshuffle requires N / K to divide block_n / block_k "
* "(got N=..., block_n=..., K=..., block_k=...)") */
rocke_i_set_err(b,
ROCKE_ERR_VALUE,
"preshuffle requires N / K to divide block_n / block_k "
"(got N=%d, block_n=%d, K=%d, block_k=%d)",
n,
spec->block_n,
k,
spec->block_k);
return st;
}
return ROCKE_OK;
}