Files
TheRock/rocm-libraries/dnn-providers/hip-kernel-provider/rocke/platform/cpp/helpers/layouts.cpp
T
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

190 lines
6.8 KiB
C++

// Copyright (c) Advanced Micro Devices, Inc., or its affiliates.
// SPDX-License-Identifier: MIT
/*
* helper_rocke.helpers.layouts.c -- C99 port of TransposeLdsReader (and its
* bound view _BoundTransposeLdsReader) from rocke/helpers/layouts.py.
*
* Byte-faithful: the bind()/row() emitters issue the rocke_b_* builder calls in
* the exact same order and with the exact same operands as the Python:
*
* def bind(self, b, lane):
* return _BoundTransposeLdsReader(
* reader=self,
* lane=lane,
* lane_div_16=b.div(lane, b.const_i32(16)),
* lane_div_4_mod_4=b.mod(b.div(lane, b.const_i32(4)), b.const_i32(4)),
* col=b.mul(b.mod(lane, b.const_i32(4)), b.const_i32(4)),
* )
*
* def row(self, b, *, k_offset, read=0):
* return b.add(
* b.const_i32(k_offset + read * 4),
* b.add(
* b.mul(self.lane_div_16, b.const_i32(self.reader.k_lanes)),
* self.lane_div_4_mod_4,
* ),
* )
*
* Note the field-init evaluation order of the dataclass call mirrors Python's
* left-to-right keyword-argument evaluation: lane_div_16, then lane_div_4_mod_4
* (whose own b.div is evaluated before its b.mod), then col.
*/
#include <stdarg.h>
#include <stdio.h>
#include "rocke/arena.h"
#include "rocke/error.hpp"
#include "rocke/helper_rocke.helpers.layouts.h"
#include "rocke/ir.h"
/* ----------------------------------------------------------------- helpers */
/* Set the builder's sticky error (first failure wins) and return NULL. Bound
* only to rocke/ir.h's public struct fields (status + err); mirrors the private
* rocke_i_set_err. */
/* Raise the failure as a ckc::Error (mirroring the Python `raise`); the public
* entry boundary catches it and records status + message on the builder, so the
* C ABI is unchanged. [[noreturn]] keeps the existing `return (T*)rocke_lay_set_err(...)`
* call sites valid -- the cast/return is simply never reached. */
[[noreturn]] static void*
rocke_lay_set_err(rocke_ir_builder_t* b, rocke_status_t st, const char* fmt, ...)
{
(void)b;
char msg[ROCKE_ERR_MSG_CAP];
va_list ap;
va_start(ap, fmt);
(void)vsnprintf(msg, sizeof(msg), fmt, ap);
va_end(ap);
msg[sizeof(msg) - 1] = '\0';
ckc::raise_status(st, msg);
}
static bool rocke_lay_live(const rocke_ir_builder_t* b)
{
return b != NULL && b->status == ROCKE_OK;
}
/* ----------------------------------------------------- TransposeLdsReader */
rocke_transpose_lds_reader_t rocke_transpose_lds_reader_make(int K)
{
rocke_transpose_lds_reader_t r;
r.K = K;
r.M = 16; /* dataclass default */
return r;
}
int rocke_transpose_lds_reader_k_lanes(const rocke_transpose_lds_reader_t* r)
{
/* @property k_lanes: return self.K // 4
* (K_L = K / (64 / M) = K / 4 for the M == 16 shape these kernels use). */
return r->K / 4;
}
int rocke_transpose_lds_reader_reads_per_k_iter(const rocke_transpose_lds_reader_t* r, int k_step)
{
/* return max(1, k_step // self.K) */
int q = k_step / r->K;
return q > 1 ? q : 1;
}
/* -------------------------------------------------- _BoundTransposeLdsReader */
rocke_bound_transpose_lds_reader_t* rocke_transpose_lds_reader_bind(
rocke_ir_builder_t* b, const rocke_transpose_lds_reader_t* r, rocke_value_t* lane)
{
rocke_bound_transpose_lds_reader_t* bound;
if(!rocke_lay_live(b))
{
return NULL;
}
if(r == NULL || lane == NULL)
{
return (rocke_bound_transpose_lds_reader_t*)rocke_lay_set_err(
b, ROCKE_ERR_VALUE, "TransposeLdsReader.bind: NULL reader/lane");
}
bound = (rocke_bound_transpose_lds_reader_t*)rocke_arena_alloc(
&b->arena, sizeof(rocke_bound_transpose_lds_reader_t));
if(bound == NULL)
{
return (rocke_bound_transpose_lds_reader_t*)rocke_lay_set_err(
b, ROCKE_ERR_OOM, "TransposeLdsReader.bind: arena OOM");
}
bound->reader = *r; /* frozen dataclass captured by value */
bound->lane = lane;
/* lane_div_16 = b.div(lane, b.const_i32(16)) */
bound->lane_div_16 = rocke_b_div(b, lane, rocke_b_const_i32(b, 16));
/* lane_div_4_mod_4 = b.mod(b.div(lane, b.const_i32(4)), b.const_i32(4))
* Python evaluates left-to-right: the inner b.div (and its const_i32(4)
* operand) is created BEFORE the outer b.mod's const_i32(4) operand. C
* argument evaluation order is unspecified (gcc evaluates right-to-left,
* which would create the outer const before the inner div and shift every
* value id below by one). Sequence the inner div via an explicit temporary
* so the const/div/const/mod creation order matches Python exactly. */
{
rocke_value_t* inner_div = rocke_b_div(b, lane, rocke_b_const_i32(b, 4));
bound->lane_div_4_mod_4 = rocke_b_mod(b, inner_div, rocke_b_const_i32(b, 4));
}
/* col = b.mul(b.mod(lane, b.const_i32(4)), b.const_i32(4))
* Same left-to-right sequencing requirement as lane_div_4_mod_4 above:
* Python creates the inner b.mod (and its const operand) before the outer
* b.mul's const operand. Force the order with an explicit temporary. */
{
rocke_value_t* inner_mod = rocke_b_mod(b, lane, rocke_b_const_i32(b, 4));
bound->col = rocke_b_mul(b, inner_mod, rocke_b_const_i32(b, 4));
}
if(!rocke_lay_live(b))
{
return NULL;
}
return bound;
}
rocke_value_t* rocke_bound_transpose_lds_reader_row(rocke_ir_builder_t* b,
const rocke_bound_transpose_lds_reader_t* self,
int k_offset,
int read)
{
int k_lanes;
rocke_value_t* inner;
if(!rocke_lay_live(b))
{
return NULL;
}
if(self == NULL)
{
return (rocke_value_t*)rocke_lay_set_err(
b, ROCKE_ERR_VALUE, "_BoundTransposeLdsReader.row: NULL self");
}
k_lanes = rocke_transpose_lds_reader_k_lanes(&self->reader);
/* b.add(
* b.const_i32(k_offset + read * 4),
* b.add(
* b.mul(self.lane_div_16, b.const_i32(self.reader.k_lanes)),
* self.lane_div_4_mod_4))
*
* Python evaluates the outer call's first arg (b.const_i32) before the
* second (the inner b.add); the inner b.add's first arg (b.mul, whose own
* b.const_i32 operand) is evaluated before lane_div_4_mod_4 (already an SSA
* value, no new op). To match the op order, emit const_i32 first, then the
* b.mul, then the adds. */
{
rocke_value_t* outer_const = rocke_b_const_i32(b, (int64_t)(k_offset + read * 4));
rocke_value_t* mul
= rocke_b_mul(b, self->lane_div_16, rocke_b_const_i32(b, (int64_t)k_lanes));
inner = rocke_b_add(b, mul, self->lane_div_4_mod_4);
return rocke_b_add(b, outer_const, inner);
}
}