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
442 lines
17 KiB
Python
442 lines
17 KiB
Python
################################################################################
|
|
#
|
|
# Copyright (C) 2025 Advanced Micro Devices, Inc. All rights reserved.
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
# of this software and associated documentation files (the "Software"), to deal
|
|
# in the Software without restriction, including without limitation the rights
|
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell cop-
|
|
# ies of the Software, and to permit persons to whom the Software is furnished
|
|
# to do so, subject to the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be included in all
|
|
# copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM-
|
|
# PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNE-
|
|
# CTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
################################################################################
|
|
|
|
import rocisa
|
|
from rocisa.container import sgpr, vgpr
|
|
from copy import deepcopy
|
|
import math
|
|
|
|
def test_instruction_common():
|
|
from rocisa.instruction import SMovB32
|
|
|
|
inst = SMovB32(dst=sgpr(1), src=1.6)
|
|
assert str(inst) == "s_mov_b32 s1, 1.6000000000000001\n"
|
|
assert str(inst.dst) == "s1"
|
|
# Due to conversion between C++ and Python
|
|
assert math.isclose(inst.srcs[0], 1.6, abs_tol=0.000001)
|
|
# You cannot use srcs[0] = 1.3 because it may break the C++ memory layout
|
|
# so nanobind disabled it
|
|
inst.srcs = [1.3]
|
|
assert math.isclose(inst.srcs[0], 1.3, abs_tol=0.000001)
|
|
inst.setSrc(0, 1.4)
|
|
assert math.isclose(inst.srcs[0], 1.4, abs_tol=0.000001)
|
|
|
|
inst2 = deepcopy(inst)
|
|
inst.setSrc(0, 2.0)
|
|
assert math.isclose(inst2.srcs[0], 1.4, abs_tol=0.000001)
|
|
|
|
from rocisa.instruction import InstructionInputVector
|
|
iiv = InstructionInputVector()
|
|
iiv.append(1.0)
|
|
iiv.append("hello")
|
|
iiv.append(sgpr(1))
|
|
assert str(iiv[2]) == "s1"
|
|
|
|
from rocisa.code import Module
|
|
from rocisa.container import vgpr
|
|
from rocisa.instruction import BufferLoadB64
|
|
module = Module("Test")
|
|
module.add(BufferLoadB64(vgpr(1), vgpr(2), vgpr(3), 3))
|
|
assert rocisa.countGlobalRead(module) == 1
|
|
|
|
def test_instruction_cvt():
|
|
from rocisa.instruction import VCvtF16toF32, VCvtF32toF16, VCvtF32toU32, VCvtU32toF32, \
|
|
VCvtI32toF32, VCvtF32toI32, VCvtFP8toF32, VCvtBF8toF32, VCvtPkFP8toF32, VCvtPkBF8toF32, \
|
|
VCvtPkF32toFP8, VCvtPkF32toBF8, VCvtSRF32toFP8, VCvtSRF32toBF8
|
|
|
|
# Test VCvtF16toF32
|
|
inst = VCvtF16toF32(dst=vgpr(1), src=vgpr(2), comment="test comment")
|
|
assert str(inst) == "v_cvt_f32_f16 v1, v2 // test comment\n"
|
|
assert str(inst.dst) == "v1"
|
|
assert str(inst.srcs[0]) == "v2"
|
|
assert inst.comment == "test comment"
|
|
|
|
# Test VCvtF32toF16
|
|
inst = VCvtF32toF16(dst=vgpr(1), src=vgpr(2), comment="test comment")
|
|
assert str(inst) == "v_cvt_f16_f32 v1, v2 // test comment\n"
|
|
assert str(inst.dst) == "v1"
|
|
assert str(inst.srcs[0]) == "v2"
|
|
assert inst.comment == "test comment"
|
|
|
|
# Test VCvtF32toU32
|
|
inst = VCvtF32toU32(dst=vgpr(1), src=vgpr(2), comment="test comment")
|
|
assert str(inst) == "v_cvt_u32_f32 v1, v2 // test comment\n"
|
|
assert str(inst.dst) == "v1"
|
|
assert str(inst.srcs[0]) == "v2"
|
|
assert inst.comment == "test comment"
|
|
|
|
# Test VCvtU32toF32
|
|
inst = VCvtU32toF32(dst=vgpr(1), src=vgpr(2), comment="test comment")
|
|
assert str(inst) == "v_cvt_f32_u32 v1, v2 // test comment\n"
|
|
assert str(inst.dst) == "v1"
|
|
assert str(inst.srcs[0]) == "v2"
|
|
assert inst.comment == "test comment"
|
|
|
|
# Test VCvtI32toF32
|
|
inst = VCvtI32toF32(dst=vgpr(1), src=vgpr(2), comment="test comment")
|
|
assert str(inst) == "v_cvt_f32_i32 v1, v2 // test comment\n"
|
|
assert str(inst.dst) == "v1"
|
|
assert str(inst.srcs[0]) == "v2"
|
|
assert inst.comment == "test comment"
|
|
|
|
# Test VCvtF32toI32
|
|
inst = VCvtF32toI32(dst=vgpr(1), src=vgpr(2), comment="test comment")
|
|
assert str(inst) == "v_cvt_i32_f32 v1, v2 // test comment\n"
|
|
assert str(inst.dst) == "v1"
|
|
assert str(inst.srcs[0]) == "v2"
|
|
assert inst.comment == "test comment"
|
|
|
|
# Test VCvtFP8toF32
|
|
inst = VCvtFP8toF32(dst=vgpr(1), src=vgpr(2), comment="test comment")
|
|
assert str(inst) == "v_cvt_f32_fp8 v1, v2 // test comment\n"
|
|
assert str(inst.dst) == "v1"
|
|
assert str(inst.srcs[0]) == "v2"
|
|
assert inst.comment == "test comment"
|
|
|
|
# Test VCvtBF8toF32
|
|
inst = VCvtBF8toF32(dst=vgpr(1), src=vgpr(2), comment="test comment")
|
|
assert str(inst) == "v_cvt_f32_bf8 v1, v2 // test comment\n"
|
|
assert str(inst.dst) == "v1"
|
|
assert str(inst.srcs[0]) == "v2"
|
|
assert inst.comment == "test comment"
|
|
|
|
# Test VCvtPkFP8toF32
|
|
inst = VCvtPkFP8toF32(dst=vgpr(1), src=vgpr(2), comment="test comment")
|
|
assert str(inst) == "v_cvt_pk_f32_fp8 v1, v2 // test comment\n"
|
|
assert str(inst.dst) == "v1"
|
|
assert str(inst.srcs[0]) == "v2"
|
|
assert inst.comment == "test comment"
|
|
|
|
# Test VCvtPkBF8toF32
|
|
inst = VCvtPkBF8toF32(dst=vgpr(1), src=vgpr(2), comment="test comment")
|
|
assert str(inst) == "v_cvt_pk_f32_bf8 v1, v2 // test comment\n"
|
|
assert str(inst.dst) == "v1"
|
|
assert str(inst.srcs[0]) == "v2"
|
|
assert inst.comment == "test comment"
|
|
|
|
# Test VCvtPkF32toFP8
|
|
inst = VCvtPkF32toFP8(dst=vgpr(1), src0=vgpr(2), src1=vgpr(3), comment="test comment")
|
|
assert str(inst) == "v_cvt_pk_fp8_f32 v1, v2, v3 // test comment\n"
|
|
assert str(inst.dst) == "v1"
|
|
assert str(inst.srcs[0]) == "v2"
|
|
assert str(inst.srcs[1]) == "v3"
|
|
assert inst.comment == "test comment"
|
|
|
|
# Test VCvtPkF32toBF8
|
|
inst = VCvtPkF32toBF8(dst=vgpr(1), src0=vgpr(2), src1=vgpr(3), comment="test comment")
|
|
assert str(inst) == "v_cvt_pk_bf8_f32 v1, v2, v3 // test comment\n"
|
|
assert str(inst.dst) == "v1"
|
|
assert str(inst.srcs[0]) == "v2"
|
|
assert str(inst.srcs[1]) == "v3"
|
|
assert inst.comment == "test comment"
|
|
|
|
# Test VCvtSRF32toFP8
|
|
inst = VCvtSRF32toFP8(dst=vgpr(1), src0=vgpr(2), src1=vgpr(3), comment="test comment")
|
|
assert str(inst) == "v_cvt_sr_fp8_f32 v1, v2, v3 // test comment\n"
|
|
assert str(inst.dst) == "v1"
|
|
assert str(inst.srcs[0]) == "v2"
|
|
assert str(inst.srcs[1]) == "v3"
|
|
assert inst.comment == "test comment"
|
|
|
|
# Test VCvtSRF32toBF8
|
|
inst = VCvtSRF32toBF8(dst=vgpr(1), src0=vgpr(2), src1=vgpr(3), comment="test comment")
|
|
assert str(inst) == "v_cvt_sr_bf8_f32 v1, v2, v3 // test comment\n"
|
|
assert str(inst.dst) == "v1"
|
|
assert str(inst.srcs[0]) == "v2"
|
|
assert str(inst.srcs[1]) == "v3"
|
|
assert inst.comment == "test comment"
|
|
|
|
def test_instruction_tdm():
|
|
from rocisa.instruction import TensorLoadToLds
|
|
from rocisa.container import sgpr
|
|
inst = TensorLoadToLds(
|
|
group0=sgpr(0, 4),
|
|
group1=sgpr(0, 8),
|
|
group2=sgpr(0, 4),
|
|
group3=sgpr(0, 4),
|
|
comment=""
|
|
)
|
|
assert str(inst) == "tensor_load_to_lds s[0:3], s[0:7], s[0:3], s[0:3]\n"
|
|
|
|
try:
|
|
TensorLoadToLds(
|
|
group0=vgpr(0, 4),
|
|
group1=sgpr(0, 8),
|
|
group2=sgpr(0, 4),
|
|
group3=sgpr(0, 4),
|
|
comment=""
|
|
)
|
|
assert False, "Should have raised ValueError"
|
|
except ValueError as e:
|
|
pass
|
|
|
|
def test_instruction_tdm_2_sgprs():
|
|
from rocisa.instruction import TensorLoadToLds
|
|
from rocisa.container import sgpr
|
|
inst = TensorLoadToLds(
|
|
group0=sgpr(0, 4),
|
|
group1=sgpr(0, 8),
|
|
group2=None,
|
|
group3=None,
|
|
comment=""
|
|
)
|
|
assert str(inst) == "tensor_load_to_lds s[0:3], s[0:7]\n"
|
|
|
|
try:
|
|
TensorLoadToLds(
|
|
group0=vgpr(0, 4),
|
|
group1=sgpr(0, 8),
|
|
group2=None,
|
|
group3=None,
|
|
comment=""
|
|
)
|
|
assert False, "Should have raised ValueError"
|
|
except ValueError as e:
|
|
pass
|
|
|
|
def test_instruction_swait_xcnt():
|
|
from rocisa.instruction import SWaitXCnt
|
|
|
|
# Default constructor: xcnt=0, no comment -> "s_wait_xcnt 0\n"
|
|
inst = SWaitXCnt()
|
|
assert str(inst) == "s_wait_xcnt 0\n"
|
|
assert inst.comment == ""
|
|
|
|
# Explicit xcnt within range
|
|
inst = SWaitXCnt(xcnt=5)
|
|
assert str(inst) == "s_wait_xcnt 5\n"
|
|
|
|
# min(xcnt, 63) clamping: xcnt=100 should clamp to 63
|
|
inst = SWaitXCnt(xcnt=100)
|
|
assert str(inst) == "s_wait_xcnt 63\n"
|
|
|
|
# Boundary: xcnt=63 should also produce 63 (not clamped further)
|
|
inst = SWaitXCnt(xcnt=63)
|
|
assert str(inst) == "s_wait_xcnt 63\n"
|
|
|
|
# Comment formatting: use relaxed assertions to sidestep alignment math
|
|
inst = SWaitXCnt(xcnt=5, comment="test comment")
|
|
assert inst.comment == "test comment"
|
|
assert str(inst).startswith("s_wait_xcnt 5")
|
|
assert "// test comment" in str(inst)
|
|
assert str(inst).endswith("\n")
|
|
|
|
# deepcopy independence: mutate the original AFTER deepcopy and confirm
|
|
# the copy is unaffected (SWaitXCnt does not expose xcnt as a writable
|
|
# attribute, so we mutate the inherited `comment` field).
|
|
inst = SWaitXCnt(xcnt=7, comment="original")
|
|
inst2 = deepcopy(inst)
|
|
inst.comment = "mutated"
|
|
assert inst2.comment == "original"
|
|
assert str(inst2).startswith("s_wait_xcnt 7")
|
|
assert "// original" in str(inst2)
|
|
assert "// mutated" not in str(inst2)
|
|
|
|
# Embed in a Module and verify rendered text contains the instruction
|
|
from rocisa.code import Module
|
|
module = Module("Test")
|
|
module.add(SWaitXCnt(xcnt=3))
|
|
assert "s_wait_xcnt 3" in str(module)
|
|
|
|
|
|
def test_instruction_global_wb():
|
|
from rocisa.instruction import GlobalWb
|
|
from rocisa.enum import CacheScope
|
|
|
|
# Default constructor: SCOPE_DEV, no comment
|
|
inst = GlobalWb()
|
|
assert str(inst) == "global_wb scope:SCOPE_DEV\n"
|
|
assert inst.scope == CacheScope.SCOPE_DEV
|
|
assert inst.comment == ""
|
|
|
|
# SCOPE_NONE: scope modifier omitted
|
|
inst = GlobalWb(scope=CacheScope.SCOPE_NONE)
|
|
assert str(inst) == "global_wb\n"
|
|
assert inst.scope == CacheScope.SCOPE_NONE
|
|
|
|
# Alternate scopes: enum -> string conversion
|
|
inst = GlobalWb(scope=CacheScope.SCOPE_CU)
|
|
assert str(inst) == "global_wb scope:SCOPE_CU\n"
|
|
|
|
inst = GlobalWb(scope=CacheScope.SCOPE_SE)
|
|
assert str(inst) == "global_wb scope:SCOPE_SE\n"
|
|
|
|
inst = GlobalWb(scope=CacheScope.SCOPE_SYS)
|
|
assert str(inst) == "global_wb scope:SCOPE_SYS\n"
|
|
|
|
# Comment formatting (relaxed assertions to avoid alignment math)
|
|
inst = GlobalWb(scope=CacheScope.SCOPE_DEV, comment="release fence")
|
|
assert inst.comment == "release fence"
|
|
assert str(inst).startswith("global_wb scope:SCOPE_DEV")
|
|
assert "// release fence" in str(inst)
|
|
assert str(inst).endswith("\n")
|
|
|
|
# deepcopy independence: mutate the original `scope` (and comment) after
|
|
# deepcopy and confirm the copy is unaffected.
|
|
inst = GlobalWb(scope=CacheScope.SCOPE_DEV, comment="orig")
|
|
inst2 = deepcopy(inst)
|
|
inst.scope = CacheScope.SCOPE_SYS
|
|
inst.comment = "mutated"
|
|
assert inst2.scope == CacheScope.SCOPE_DEV
|
|
assert inst2.comment == "orig"
|
|
assert str(inst2).startswith("global_wb scope:SCOPE_DEV")
|
|
assert "// orig" in str(inst2)
|
|
assert "// mutated" not in str(inst2)
|
|
assert "SCOPE_SYS" not in str(inst2)
|
|
|
|
# Embed in a Module and verify rendered text contains the instruction
|
|
from rocisa.code import Module
|
|
module = Module("Test")
|
|
module.add(GlobalWb(scope=CacheScope.SCOPE_DEV))
|
|
assert "global_wb scope:SCOPE_DEV" in str(module)
|
|
|
|
|
|
def test_instruction_global_inv():
|
|
from rocisa.instruction import GlobalInv
|
|
from rocisa.enum import CacheScope
|
|
|
|
# Default constructor: SCOPE_DEV, no comment
|
|
inst = GlobalInv()
|
|
assert str(inst) == "global_inv scope:SCOPE_DEV\n"
|
|
assert inst.scope == CacheScope.SCOPE_DEV
|
|
assert inst.comment == ""
|
|
|
|
# SCOPE_NONE: scope modifier omitted
|
|
inst = GlobalInv(scope=CacheScope.SCOPE_NONE)
|
|
assert str(inst) == "global_inv\n"
|
|
assert inst.scope == CacheScope.SCOPE_NONE
|
|
|
|
# Alternate scope sanity check
|
|
inst = GlobalInv(scope=CacheScope.SCOPE_CU)
|
|
assert str(inst) == "global_inv scope:SCOPE_CU\n"
|
|
|
|
# Comment formatting (relaxed assertions to avoid alignment math)
|
|
inst = GlobalInv(scope=CacheScope.SCOPE_DEV, comment="acquire fence")
|
|
assert inst.comment == "acquire fence"
|
|
assert str(inst).startswith("global_inv scope:SCOPE_DEV")
|
|
assert "// acquire fence" in str(inst)
|
|
assert str(inst).endswith("\n")
|
|
|
|
# deepcopy independence: mutate the original `scope` (and comment) after
|
|
# deepcopy and confirm the copy is unaffected.
|
|
inst = GlobalInv(scope=CacheScope.SCOPE_DEV, comment="orig")
|
|
inst2 = deepcopy(inst)
|
|
inst.scope = CacheScope.SCOPE_NONE
|
|
inst.comment = "mutated"
|
|
assert inst2.scope == CacheScope.SCOPE_DEV
|
|
assert inst2.comment == "orig"
|
|
assert str(inst2).startswith("global_inv scope:SCOPE_DEV")
|
|
assert "// orig" in str(inst2)
|
|
assert "// mutated" not in str(inst2)
|
|
|
|
|
|
def test_instruction_scalar_float():
|
|
# gfx12+ scalar-float / scalar-u64 instruction wrappers. Each src is an
|
|
# InstructionInput variant (register | int | double | str); the cases below
|
|
# exercise those arms and assert the emitted mnemonic/operands.
|
|
from rocisa.instruction import SMulF32, SAddF32, SCvtF32U32, SCvtU32F32, \
|
|
VSRcpF32, SMulU64
|
|
|
|
# --- SMulF32: s_mul_f32 dst, src0, src1 ---
|
|
inst = SMulF32(sgpr(0), sgpr(1), sgpr(2))
|
|
assert str(inst) == "s_mul_f32 s0, s1, s2\n"
|
|
assert str(inst.dst) == "s0"
|
|
assert str(inst.srcs[0]) == "s1"
|
|
assert str(inst.srcs[1]) == "s2"
|
|
assert str(SMulF32(sgpr(0), sgpr(1), 2)) == "s_mul_f32 s0, s1, 2\n"
|
|
assert str(SMulF32(sgpr(0), "s1", sgpr(2))) == "s_mul_f32 s0, s1, s2\n"
|
|
|
|
# --- SAddF32: s_add_f32 dst, src0, src1 ---
|
|
inst = SAddF32(sgpr(0), sgpr(1), sgpr(2))
|
|
assert str(inst) == "s_add_f32 s0, s1, s2\n"
|
|
assert str(inst.dst) == "s0"
|
|
assert str(inst.srcs[0]) == "s1"
|
|
assert str(inst.srcs[1]) == "s2"
|
|
assert str(SAddF32(sgpr(0), sgpr(1), 3)) == "s_add_f32 s0, s1, 3\n"
|
|
# integral doubles get a ".0" suffix
|
|
assert str(SAddF32(sgpr(0), sgpr(1), 2.0)) == "s_add_f32 s0, s1, 2.0\n"
|
|
|
|
# --- SCvtF32U32: s_cvt_f32_u32 dst, src ---
|
|
inst = SCvtF32U32(sgpr(0), sgpr(1))
|
|
assert str(inst) == "s_cvt_f32_u32 s0, s1\n"
|
|
assert str(inst.dst) == "s0"
|
|
assert str(inst.srcs[0]) == "s1"
|
|
assert str(SCvtF32U32(sgpr(0), "s2")) == "s_cvt_f32_u32 s0, s2\n"
|
|
|
|
# --- SCvtU32F32: s_cvt_u32_f32 dst, src ---
|
|
inst = SCvtU32F32(sgpr(0), sgpr(1))
|
|
assert str(inst) == "s_cvt_u32_f32 s0, s1\n"
|
|
assert str(inst.dst) == "s0"
|
|
assert str(inst.srcs[0]) == "s1"
|
|
assert str(SCvtU32F32(sgpr(0), 1.5)) == "s_cvt_u32_f32 s0, 1.5\n"
|
|
|
|
# --- VSRcpF32: v_s_rcp_f32 dst, src (vgpr dst) ---
|
|
inst = VSRcpF32(vgpr(0), sgpr(1))
|
|
assert str(inst) == "v_s_rcp_f32 v0, s1\n"
|
|
assert str(inst.dst) == "v0"
|
|
assert str(inst.srcs[0]) == "s1"
|
|
# vgpr src must stay clean (no s_set_vgpr_msb) under the default ISA
|
|
assert str(VSRcpF32(vgpr(0), vgpr(1))) == "v_s_rcp_f32 v0, v1\n"
|
|
assert str(VSRcpF32(vgpr(0), 0.5)) == "v_s_rcp_f32 v0, 0.5\n"
|
|
|
|
# --- SMulU64: s_mul_u64 dst, src0, src1 (64-bit register pairs) ---
|
|
inst = SMulU64(sgpr(0, 2), sgpr(2, 2), sgpr(4, 2))
|
|
assert str(inst) == "s_mul_u64 s[0:1], s[2:3], s[4:5]\n"
|
|
assert str(inst.dst) == "s[0:1]"
|
|
assert str(inst.srcs[0]) == "s[2:3]"
|
|
assert str(inst.srcs[1]) == "s[4:5]"
|
|
assert str(SMulU64(sgpr(0, 2), sgpr(2, 2), 4)) == "s_mul_u64 s[0:1], s[2:3], 4\n"
|
|
|
|
# --- Comment formatting (relaxed to sidestep the 50-col alignment pad) ---
|
|
inst = SMulF32(sgpr(0), sgpr(1), sgpr(2), comment="scale")
|
|
assert str(inst).startswith("s_mul_f32 s0, s1, s2")
|
|
assert "// scale" in str(inst)
|
|
assert str(inst).endswith("\n")
|
|
assert inst.comment == "scale"
|
|
|
|
# --- deepcopy independence + comment accessor, one per class ---
|
|
for a in [
|
|
SMulF32(sgpr(0), sgpr(1), sgpr(2), comment="orig"),
|
|
SAddF32(sgpr(0), sgpr(1), sgpr(2), comment="orig"),
|
|
SCvtF32U32(sgpr(0), sgpr(1), comment="orig"),
|
|
SCvtU32F32(sgpr(0), sgpr(1), comment="orig"),
|
|
VSRcpF32(vgpr(0), sgpr(1), comment="orig"),
|
|
SMulU64(sgpr(0, 2), sgpr(2, 2), sgpr(4, 2), comment="orig"),
|
|
]:
|
|
assert a.comment == "orig"
|
|
b = deepcopy(a)
|
|
a.comment = "mutated"
|
|
assert b.comment == "orig"
|
|
assert "// orig" in str(b)
|
|
assert "// mutated" not in str(b)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
test_instruction_common()
|
|
test_instruction_cvt()
|
|
test_instruction_tdm()
|
|
test_instruction_tdm_2_sgprs()
|
|
test_instruction_swait_xcnt()
|
|
test_instruction_global_wb()
|
|
test_instruction_global_inv()
|
|
test_instruction_scalar_float()
|