diff --git a/emulation/rocjitsu/lib/rocjitsu/src/rocjitsu/vm/amdgpu/compute_unit.h b/emulation/rocjitsu/lib/rocjitsu/src/rocjitsu/vm/amdgpu/compute_unit.h index 26dbdd2eb0a..7a990c16f80 100644 --- a/emulation/rocjitsu/lib/rocjitsu/src/rocjitsu/vm/amdgpu/compute_unit.h +++ b/emulation/rocjitsu/lib/rocjitsu/src/rocjitsu/vm/amdgpu/compute_unit.h @@ -1339,7 +1339,8 @@ class RJ_API_TYPE_EXPORT ComputeUnitCore : public simdojo::CompositeComponent { /// `UnimplementedInst::what()` when that legacy exception is translated. /// Otherwise the pointed-to string is unchanged. /// @returns Failure for an unimplemented instruction stub or a reported operand - /// failure. The wavefront retains the reason for caller-owned diagnostics. + /// or register-access failure. The wavefront retains the reason for caller-owned + /// diagnostics. /// Each call clears the previous error; a failed call does not halt the wavefront. /// Other host failures inside implemented instructions still raise exceptions. util::Result execute_instruction(Instruction *inst, Wavefront &wf, diff --git a/emulation/rocjitsu/lib/rocjitsu/src/rocjitsu/vm/amdgpu/register_access.h b/emulation/rocjitsu/lib/rocjitsu/src/rocjitsu/vm/amdgpu/register_access.h index b8eb013a54d..7d21d460b0b 100644 --- a/emulation/rocjitsu/lib/rocjitsu/src/rocjitsu/vm/amdgpu/register_access.h +++ b/emulation/rocjitsu/lib/rocjitsu/src/rocjitsu/vm/amdgpu/register_access.h @@ -806,6 +806,9 @@ class RegisterAccess { }); } + /// @brief Return raw lane words for one register in the region. + /// @returns Failure for a partial-byte region, reporting InvalidRegisterAccess + /// through the wavefront's instruction-execution error channel. FailureOr> lanes(uint32_t relative_reg = 0) const { assert(relative_reg < reg_count_ && "relative VGPR outside read region"); if (byte_mask_ != rocjitsu::ExecutionPlugin::kFullByteMask) diff --git a/emulation/rocjitsu/tests/register_access_test.cpp b/emulation/rocjitsu/tests/register_access_test.cpp index 9aa6a6bde03..005683bf13a 100644 --- a/emulation/rocjitsu/tests/register_access_test.cpp +++ b/emulation/rocjitsu/tests/register_access_test.cpp @@ -1883,6 +1883,29 @@ TEST(RegisterAccessTest, PartialByteRawRegionOperationsRejectBeforeSideEffects) expect_failure([&] { return region.copy_dwords_lane_major(bytes, 1); }); } +TEST(RegisterAccessTest, OversizedRawRegionCopyRejectsBeforeSideEffects) { + Fixture fx(ROCJITSU_CODE_ARCH_CDNA4, kSgprsPerWave, /*wavefront_slots=*/1, kVgprsPerWave, + /*wave_size=*/64); + ASSERT_NE(fx.wf, nullptr); + ASSERT_EQ(fx.wf->wf_size(), 64u); + for (uint32_t lane = 0; lane < fx.wf->wf_size(); ++lane) + fx.cu->write_vgpr(fx.vgpr_base(), lane, 0x12340000u + lane); + auto region = RegisterAccess(*fx.wf).read_vgpr_region( + fx.vgpr_base(), /*reg_count=*/1, /*lane_mask=*/~uint64_t{0}, ExecutionPlugin::kFullByteMask); + ASSERT_TRUE(region.valid()); + std::array words; + words.fill(0xAABBCCDDu); + const auto original_words = words; + + fx.wf->clear_instruction_execution_error(); + ASSERT_EQ(fx.wf->instruction_execution_error(), InstructionExecutionError::None); + ASSERT_EQ(fx.wf->instruction_execution_error_detail(), nullptr); + EXPECT_TRUE(region.copy_to(words).failed()); + EXPECT_EQ(fx.wf->instruction_execution_error(), InstructionExecutionError::InvalidRegisterAccess); + EXPECT_STREQ(fx.wf->instruction_execution_error_detail(), "destination exceeds read region"); + EXPECT_EQ(words, original_words); +} + TEST(RegisterAccessTest, ScalarBackedPartialByteStoresRejectBeforeObservation) { Fixture fx; ASSERT_NE(fx.wf, nullptr);