Files
TheRock/rocm-systems/emulation/rocjitsu/lib/python/amdisa/sema_helpers.py
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

291 lines
14 KiB
Python

# Copyright (c) 2025-2026 Advanced Micro Devices, Inc.
# SPDX-License-Identifier: MIT
"""Registry mapping ``.call`` target names to C++ functions and treatment.
Each ``.call`` node in the SemaAST invokes a named helper function. This
module classifies every helper into one of three treatments:
- **INLINE_CPP**: Emit a C++ function call to an existing simulator helper.
- **OPAQUE_NOP**: System/microarchitectural function — emit a no-op comment.
- **RECURSIVE**: The callee is another instruction — inline its SemaAST or
emit a call to its execute function.
"""
from __future__ import annotations
from enum import Enum, auto
from typing import Protocol
from amdisa.sema_ast import SemaBlock, SemaNodeKind
class HelperTreatment(Enum):
INLINE_CPP = auto()
OPAQUE_NOP = auto()
RECURSIVE = auto()
class HelperResolver(Protocol):
"""Protocol for resolving ``.call`` helper functions."""
def resolve(
self,
name: str,
all_blocks: dict[str, SemaBlock] | None = None,
visited: set[str] | None = None,
depth: int = 0,
) -> tuple[HelperTreatment, str | None]:
"""Resolve a helper function name to its treatment and C++ target.
Args:
name: The ``.call`` target name (e.g., ``CalcBufferAddr``).
all_blocks: Full instruction SemaBlock dict for recursive lookup.
visited: Set of already-visited names for cycle detection.
depth: Current recursion depth (max 3).
Returns:
Tuple of (treatment, cpp_function_name_or_none).
Raises:
ValueError: If a cycle is detected or depth exceeds 3.
"""
...
# --------------------------------------------------------------------------
# Static registry: maps .call target -> (treatment, cpp_function_name)
# --------------------------------------------------------------------------
HELPER_REGISTRY: dict[str, tuple[HelperTreatment, str | None]] = {
# --- Address calculation (7) ---
'CalcBufferAddr': (HelperTreatment.INLINE_CPP, 'calc_buffer_addr'),
'CalcFlatAddr': (HelperTreatment.INLINE_CPP, 'calc_flat_addr'),
'CalcGlobalAddr': (HelperTreatment.INLINE_CPP, 'calc_global_addr'),
'CalcDsAddr': (HelperTreatment.INLINE_CPP, 'calc_ds_addr'),
'CalcScalarGlobalAddr': (HelperTreatment.INLINE_CPP, 'calc_scalar_global_addr'),
'CalcScalarBufferAddr': (HelperTreatment.INLINE_CPP, 'calc_scalar_buffer_addr'),
'CalcScratchAddr': (HelperTreatment.INLINE_CPP, 'calc_scratch_addr'),
# --- Type conversion: standard float/int (14) ---
'f16_to_f32': (HelperTreatment.INLINE_CPP, 'util::f16_to_f32'),
'f32_to_f16': (HelperTreatment.INLINE_CPP, 'util::f32_to_f16'),
'f32_to_bf16': (HelperTreatment.INLINE_CPP, 'util::f32_to_bf16'),
'bf16_to_f32': (HelperTreatment.INLINE_CPP, 'util::bf16_to_f32'),
'f32_to_f64': (HelperTreatment.INLINE_CPP, 'static_cast<double>'),
'f64_to_f32': (HelperTreatment.INLINE_CPP, 'static_cast<float>'),
'f32_to_i32': (HelperTreatment.INLINE_CPP, 'util::f32_to_i32'),
'i32_to_f32': (HelperTreatment.INLINE_CPP, 'util::i32_to_f32'),
'u32_to_f32': (HelperTreatment.INLINE_CPP, 'util::u32_to_f32'),
'f32_to_u32': (HelperTreatment.INLINE_CPP, 'util::f32_to_u32'),
'f64_to_i32': (HelperTreatment.INLINE_CPP, 'util::f64_to_i32'),
'f64_to_u32': (HelperTreatment.INLINE_CPP, 'util::f64_to_u32'),
'i32_to_f64': (HelperTreatment.INLINE_CPP, 'static_cast<double>'),
'u32_to_f64': (HelperTreatment.INLINE_CPP, 'static_cast<double>'),
# --- Type conversion: 16-bit int/float (6) ---
'i16_to_f16': (HelperTreatment.INLINE_CPP, 'util::i16_to_f16'),
'u16_to_f16': (HelperTreatment.INLINE_CPP, 'util::u16_to_f16'),
'f16_to_i16': (HelperTreatment.INLINE_CPP, 'util::f16_to_i16'),
'f16_to_u16': (HelperTreatment.INLINE_CPP, 'util::f16_to_u16'),
'i32_to_i16': (HelperTreatment.INLINE_CPP, 'static_cast<int16_t>'),
'u32_to_u16': (HelperTreatment.INLINE_CPP, 'static_cast<uint16_t>'),
# --- Type conversion: narrow widening (2) ---
'u4_to_u32': (HelperTreatment.INLINE_CPP, 'util::u4_to_u32'),
'u8_to_u32': (HelperTreatment.INLINE_CPP, 'static_cast<uint32_t>'),
# --- Type conversion: FP8/BF8 (4) ---
'fp8_to_f32': (HelperTreatment.INLINE_CPP, 'util::fp8_to_f32'),
'fp8_to_f16': (HelperTreatment.INLINE_CPP, 'util::fp8_to_f16'),
'bf8_to_f32': (HelperTreatment.INLINE_CPP, 'util::bf8_to_f32'),
'bf8_to_f16': (HelperTreatment.INLINE_CPP, 'util::bf8_to_f16'),
# --- Type conversion: F32/F16/BF16 to FP8/BF8 (6) ---
'f32_to_fp8': (HelperTreatment.INLINE_CPP, 'util::f32_to_fp8'),
'f32_to_bf8': (HelperTreatment.INLINE_CPP, 'util::f32_to_bf8'),
'f16_to_fp8': (HelperTreatment.INLINE_CPP, 'util::f16_to_fp8'),
'f16_to_bf8': (HelperTreatment.INLINE_CPP, 'util::f16_to_bf8'),
'f32_to_u8': (HelperTreatment.INLINE_CPP, 'util::f32_to_u8'),
# --- Type conversion: scaled FP8/BF8/FP6/FP4 (24) ---
'f32_to_fp8_scale': (HelperTreatment.INLINE_CPP, 'util::f32_to_fp8_scale'),
'f32_to_fp8_sr_scale': (HelperTreatment.INLINE_CPP, 'util::f32_to_fp8_sr_scale'),
'f32_to_bf8_scale': (HelperTreatment.INLINE_CPP, 'util::f32_to_bf8_scale'),
'f32_to_bf8_sr_scale': (HelperTreatment.INLINE_CPP, 'util::f32_to_bf8_sr_scale'),
'f32_to_fp6_scale': (HelperTreatment.INLINE_CPP, 'util::f32_to_fp6_scale'),
'f32_to_fp6_sr_scale': (HelperTreatment.INLINE_CPP, 'util::f32_to_fp6_sr_scale'),
'f32_to_bf6_scale': (HelperTreatment.INLINE_CPP, 'util::f32_to_bf6_scale'),
'f32_to_bf6_sr_scale': (HelperTreatment.INLINE_CPP, 'util::f32_to_bf6_sr_scale'),
'f32_to_fp4_scale': (HelperTreatment.INLINE_CPP, 'util::f32_to_fp4_scale'),
'f32_to_fp4_sr_scale': (HelperTreatment.INLINE_CPP, 'util::f32_to_fp4_sr_scale'),
'f16_to_fp8_scale': (HelperTreatment.INLINE_CPP, 'util::f16_to_fp8_scale'),
'f16_to_fp8_sr_scale': (HelperTreatment.INLINE_CPP, 'util::f16_to_fp8_sr_scale'),
'f16_to_bf8_scale': (HelperTreatment.INLINE_CPP, 'util::f16_to_bf8_scale'),
'f16_to_bf8_sr_scale': (HelperTreatment.INLINE_CPP, 'util::f16_to_bf8_sr_scale'),
'f16_to_fp6_scale': (HelperTreatment.INLINE_CPP, 'util::f16_to_fp6_scale'),
'f16_to_fp6_sr_scale': (HelperTreatment.INLINE_CPP, 'util::f16_to_fp6_sr_scale'),
'f16_to_bf6_scale': (HelperTreatment.INLINE_CPP, 'util::f16_to_bf6_scale'),
'f16_to_bf6_sr_scale': (HelperTreatment.INLINE_CPP, 'util::f16_to_bf6_sr_scale'),
'f16_to_fp4_scale': (HelperTreatment.INLINE_CPP, 'util::f16_to_fp4_scale'),
'f16_to_fp4_sr_scale': (HelperTreatment.INLINE_CPP, 'util::f16_to_fp4_sr_scale'),
'bf16_to_fp8_scale': (HelperTreatment.INLINE_CPP, 'util::bf16_to_fp8_scale'),
'bf16_to_fp8_sr_scale': (HelperTreatment.INLINE_CPP, 'util::bf16_to_fp8_sr_scale'),
'bf16_to_bf8_scale': (HelperTreatment.INLINE_CPP, 'util::bf16_to_bf8_scale'),
'bf16_to_bf8_sr_scale': (HelperTreatment.INLINE_CPP, 'util::bf16_to_bf8_sr_scale'),
'bf16_to_bf6_scale': (HelperTreatment.INLINE_CPP, 'util::bf16_to_bf6_scale'),
'bf16_to_bf6_sr_scale': (HelperTreatment.INLINE_CPP, 'util::bf16_to_bf6_sr_scale'),
'bf16_to_fp6_scale': (HelperTreatment.INLINE_CPP, 'util::bf16_to_fp6_scale'),
'bf16_to_fp6_sr_scale': (HelperTreatment.INLINE_CPP, 'util::bf16_to_fp6_sr_scale'),
'bf16_to_fp4_scale': (HelperTreatment.INLINE_CPP, 'util::bf16_to_fp4_scale'),
'bf16_to_fp4_sr_scale': (HelperTreatment.INLINE_CPP, 'util::bf16_to_fp4_sr_scale'),
# --- Type conversion: SNORM/UNORM (4) ---
'f32_to_snorm': (HelperTreatment.INLINE_CPP, 'util::f32_to_snorm'),
'f32_to_unorm': (HelperTreatment.INLINE_CPP, 'util::f32_to_unorm'),
'f16_to_snorm': (HelperTreatment.INLINE_CPP, 'util::f16_to_snorm'),
'f16_to_unorm': (HelperTreatment.INLINE_CPP, 'util::f16_to_unorm'),
# --- Numeric constructors (2) ---
'float16': (HelperTreatment.INLINE_CPP, 'util::make_f16'),
'float32': (HelperTreatment.INLINE_CPP, 'util::make_f32'),
# --- FP classification (4) ---
'isNAN': (HelperTreatment.INLINE_CPP, 'std::isnan'),
'isQuietNAN': (HelperTreatment.INLINE_CPP, 'util::is_quiet_nan'),
'isSignalNAN': (HelperTreatment.INLINE_CPP, 'util::is_signal_nan'),
'cvtToQuietNAN': (HelperTreatment.INLINE_CPP, 'util::cvt_to_quiet_nan'),
# --- Special ALU helpers ---
'ABSDIFF': (HelperTreatment.INLINE_CPP, 'util::absdiff'),
'BYTE_PERMUTE': (HelperTreatment.INLINE_CPP, 'util::byte_permute'),
'SAT4': (HelperTreatment.INLINE_CPP, 'util::sat4'),
'SAT8': (HelperTreatment.INLINE_CPP, 'util::sat8'),
'isEven': (HelperTreatment.INLINE_CPP, 'util::is_even'),
'IsM0': (HelperTreatment.INLINE_CPP, 'util::is_m0'),
'HwRegWriteMask': (HelperTreatment.INLINE_CPP, 'util::hwreg_write_mask'),
'TanhCubicApproximation': (HelperTreatment.INLINE_CPP, 'util::tanh_cubic_approx'),
'signed_add_overflows': (
HelperTreatment.INLINE_CPP,
'::rocjitsu::amdgpu::signed_add_overflows',
),
'signed_sub_overflows': (
HelperTreatment.INLINE_CPP,
'::rocjitsu::amdgpu::signed_sub_overflows',
),
# --- Type conversion: V_CVT helpers (2) ---
'v_cvt_i16_f32': (HelperTreatment.INLINE_CPP, 'util::v_cvt_i16_f32'),
'v_cvt_u16_f32': (HelperTreatment.INLINE_CPP, 'util::v_cvt_u16_f32'),
# --- System / microarchitectural (opaque) (7) ---
'CheckBarrierComplete': (HelperTreatment.OPAQUE_NOP, None),
'PrefetchScalarData': (HelperTreatment.OPAQUE_NOP, None),
'PrefetchScalarInst': (HelperTreatment.OPAQUE_NOP, None),
'ReallocVgprs': (HelperTreatment.OPAQUE_NOP, None),
'WaitIdleExceptStoreCnt': (HelperTreatment.OPAQUE_NOP, None),
'InCluster': (HelperTreatment.OPAQUE_NOP, None),
'InWorkgroup': (HelperTreatment.OPAQUE_NOP, None),
# --- NOPs (2) ---
'nop': (HelperTreatment.OPAQUE_NOP, None),
's_nop': (HelperTreatment.OPAQUE_NOP, None),
# --- Recursive: instruction cross-references (39) ---
's_ff1_i32_b32': (HelperTreatment.RECURSIVE, None),
's_ff1_i32_b64': (HelperTreatment.RECURSIVE, None),
'v_add_nc_i16': (HelperTreatment.RECURSIVE, None),
'v_add_nc_i32': (HelperTreatment.RECURSIVE, None),
'v_add_nc_u16': (HelperTreatment.RECURSIVE, None),
'v_add_nc_u32': (HelperTreatment.RECURSIVE, None),
'v_max3_i16': (HelperTreatment.RECURSIVE, None),
'v_max3_i32': (HelperTreatment.RECURSIVE, None),
'v_max3_num_f16': (HelperTreatment.RECURSIVE, None),
'v_max3_num_f32': (HelperTreatment.RECURSIVE, None),
'v_max3_u16': (HelperTreatment.RECURSIVE, None),
'v_max3_u32': (HelperTreatment.RECURSIVE, None),
'v_max_i16': (HelperTreatment.RECURSIVE, None),
'v_max_i32': (HelperTreatment.RECURSIVE, None),
'v_max_num_bf16': (HelperTreatment.RECURSIVE, None),
'v_max_num_f16': (HelperTreatment.RECURSIVE, None),
'v_max_num_f32': (HelperTreatment.RECURSIVE, None),
'v_max_u16': (HelperTreatment.RECURSIVE, None),
'v_max_u32': (HelperTreatment.RECURSIVE, None),
'v_maximum3_f16': (HelperTreatment.RECURSIVE, None),
'v_maximum_f16': (HelperTreatment.RECURSIVE, None),
'v_maximum_f32': (HelperTreatment.RECURSIVE, None),
'v_min3_num_f16': (HelperTreatment.RECURSIVE, None),
'v_min3_num_f32': (HelperTreatment.RECURSIVE, None),
'v_min_i16': (HelperTreatment.RECURSIVE, None),
'v_min_i32': (HelperTreatment.RECURSIVE, None),
'v_min_num_bf16': (HelperTreatment.RECURSIVE, None),
'v_min_num_f16': (HelperTreatment.RECURSIVE, None),
'v_min_num_f32': (HelperTreatment.RECURSIVE, None),
'v_min_u16': (HelperTreatment.RECURSIVE, None),
'v_min_u32': (HelperTreatment.RECURSIVE, None),
'v_minimum3_f16': (HelperTreatment.RECURSIVE, None),
'v_minimum_f16': (HelperTreatment.RECURSIVE, None),
'v_minimum_f32': (HelperTreatment.RECURSIVE, None),
'v_msad_u8': (HelperTreatment.RECURSIVE, None),
'v_prng_b32': (HelperTreatment.RECURSIVE, None),
'v_sad_u8': (HelperTreatment.RECURSIVE, None),
'v_tanh_f32': (HelperTreatment.RECURSIVE, None),
}
_MAX_RECURSIVE_DEPTH = 3
def resolve_helper(
name: str,
all_blocks: dict[str, SemaBlock] | None = None,
visited: set[str] | None = None,
depth: int = 0,
) -> tuple[HelperTreatment, str | None]:
"""Resolve a ``.call`` target name to its treatment and C++ target.
For RECURSIVE helpers, looks up the callee's SemaBlock in ``all_blocks``
and checks for cycles and depth limits.
Args:
name: The ``.call`` target name.
all_blocks: Full instruction dict for recursive lookup.
visited: Cycle detection set.
depth: Current recursion depth.
Returns:
``(treatment, cpp_name_or_none)``.
Raises:
ValueError: If a cycle is detected or depth exceeds the limit.
"""
if depth > _MAX_RECURSIVE_DEPTH:
raise ValueError(
f"Recursive helper depth exceeded ({depth} > {_MAX_RECURSIVE_DEPTH}) "
f"for '{name}'"
)
entry = HELPER_REGISTRY.get(name)
if entry is None:
return (HelperTreatment.INLINE_CPP, name)
treatment, cpp_name = entry
if treatment == HelperTreatment.RECURSIVE and all_blocks is not None:
if visited is None:
visited = set()
canonical = name.upper()
if canonical in visited:
raise ValueError(f"Cycle detected: {' -> '.join(visited)} -> {canonical}")
visited.add(canonical)
block = all_blocks.get(canonical)
if block is not None:
for node in block.body.walk():
if node.kind == SemaNodeKind.CALL and node.call_name:
sub_entry = HELPER_REGISTRY.get(node.call_name)
if sub_entry and sub_entry[0] == HelperTreatment.RECURSIVE:
resolve_helper(
node.call_name,
all_blocks,
visited.copy(),
depth + 1,
)
return entry
def list_unresolved(blocks: dict[str, SemaBlock]) -> list[str]:
"""Return ``.call`` target names not found in the registry."""
unresolved: set[str] = set()
for block in blocks.values():
for node in block.body.walk():
if node.kind == SemaNodeKind.CALL and node.call_name:
if node.call_name not in HELPER_REGISTRY:
unresolved.add(node.call_name)
return sorted(unresolved)