Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 127 additions & 0 deletions emulation/rocjitsu/tests/cdna5_dispatch_memory_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,133 @@ TEST(Gfx1250SimulationTest, SLoadB32DoesNotScaleImmediateOffset) {
EXPECT_EQ(sim.snapshot->snapshots().front().sgpr(4), kExpected);
}

TEST(Gfx1250SimulationTest, SLoadB32WritesVccHalves) {
using namespace rocr::llvm::amdhsa;

constexpr uint64_t kKernelAddr = 0x10000;
constexpr uint64_t kKernargAddr = 0x400000;
constexpr uint32_t kVccLo = 0x12345678u;
constexpr uint32_t kVccHi = 0xA5B6C7D8u;

std::vector<uint32_t> code;
append_instruction(
code, cdna5::build_smem(cdna5::kSLoadB32Smem, {.sbase = 0,
.sdata = amdgpu::kVccSelectorLast,
.ioffset = 4,
.scale_offset = 1,
.soffset = amdgpu::kModernNullSelector}));
append_instruction(code, S_WAIT_KMCNT_0_GFX12);
append_instruction(
code, cdna5::build_smem(cdna5::kSLoadB32Smem, {.sbase = 0,
.sdata = amdgpu::kVccSelectorFirst,
.scale_offset = 1,
.soffset = amdgpu::kModernNullSelector}));
append_instruction(code, S_WAIT_KMCNT_0_GFX12);
append_instruction(code, S_ENDPGM_GFX12);

uint32_t kernel_code_properties = 0;
AMDHSA_BITS_SET(kernel_code_properties, KERNEL_CODE_PROPERTY_ENABLE_SGPR_KERNARG_SEGMENT_PTR, 1);

Gfx1250Sim sim;
write_global_u32(*sim.memory, kKernargAddr, kVccLo);
write_global_u32(*sim.memory, kKernargAddr + 4, kVccHi);
uint64_t kernel_object = sim.write_kernel(kKernelAddr, code.data(), code.size(), 104, 32, 2,
false, false, false, kernel_code_properties, 8);

test::AqlQueue queue(sim.memory, sim.cp());
queue.dispatch(kernel_object, 32, 32, kKernargAddr);
step_until_halted(*sim.engine, *sim.cu());

ASSERT_EQ(sim.snapshot->snapshots().size(), 1u);
EXPECT_EQ(sim.snapshot->snapshots().front().vcc, (static_cast<uint64_t>(kVccHi) << 32) | kVccLo);
}

TEST(Gfx1250SimulationTest, SLoadB64WritesVccPair) {
using namespace rocr::llvm::amdhsa;

constexpr uint64_t kKernelAddr = 0x10000;
constexpr uint64_t kKernargAddr = 0x400000;
constexpr uint64_t kExpected = 0xA5B6C7D812345678ull;

std::vector<uint32_t> code;
append_instruction(
code, cdna5::build_smem(cdna5::kSLoadB64Smem, {.sbase = 0,
.sdata = amdgpu::kVccSelectorFirst,
.scale_offset = 1,
.soffset = amdgpu::kModernNullSelector}));
append_instruction(code, S_WAIT_KMCNT_0_GFX12);
append_instruction(code, S_ENDPGM_GFX12);

uint32_t kernel_code_properties = 0;
AMDHSA_BITS_SET(kernel_code_properties, KERNEL_CODE_PROPERTY_ENABLE_SGPR_KERNARG_SEGMENT_PTR, 1);

Gfx1250Sim sim;
sim.memory->load_image(reinterpret_cast<const uint8_t *>(&kExpected), sizeof(kExpected),
kKernargAddr);
uint64_t kernel_object = sim.write_kernel(kKernelAddr, code.data(), code.size(), 104, 32, 2,
false, false, false, kernel_code_properties, 8);

test::AqlQueue queue(sim.memory, sim.cp());
queue.dispatch(kernel_object, 32, 32, kKernargAddr);
step_until_halted(*sim.engine, *sim.cu());

ASSERT_EQ(sim.snapshot->snapshots().size(), 1u);
EXPECT_EQ(sim.snapshot->snapshots().front().vcc, kExpected);
}

TEST(Gfx1250SimulationTest, SLoadB32RoutesSgprTtmpAndNullDestinations) {
using namespace rocr::llvm::amdhsa;

constexpr uint64_t kKernelAddr = 0x10000;
constexpr uint64_t kKernargAddr = 0x400000;
constexpr uint32_t kSgprValue = 0x12345678u;
constexpr uint32_t kTtmpValue = 0xAABBCCDDu;
constexpr uint32_t kDiscardedValue = 0xDEADBEEFu;

std::vector<uint32_t> code;
append_instruction(
code,
cdna5::build_smem(
cdna5::kSLoadB32Smem,
{.sbase = 0, .sdata = 4, .scale_offset = 1, .soffset = amdgpu::kModernNullSelector}));
append_instruction(code, S_WAIT_KMCNT_0_GFX12);
append_instruction(
code, cdna5::build_smem(cdna5::kSLoadB32Smem, {.sbase = 0,
.sdata = amdgpu::kTtmpSelectorFirst,
.ioffset = 4,
.scale_offset = 1,
.soffset = amdgpu::kModernNullSelector}));
append_instruction(code, S_WAIT_KMCNT_0_GFX12);
append_instruction(
code, cdna5::build_smem(cdna5::kSLoadB32Smem, {.sbase = 0,
.sdata = amdgpu::kModernNullSelector,
.ioffset = 8,
.scale_offset = 1,
.soffset = amdgpu::kModernNullSelector}));
append_instruction(code, S_WAIT_KMCNT_0_GFX12);
append_instruction(code, S_ENDPGM_GFX12);

uint32_t kernel_code_properties = 0;
AMDHSA_BITS_SET(kernel_code_properties, KERNEL_CODE_PROPERTY_ENABLE_SGPR_KERNARG_SEGMENT_PTR, 1);

Gfx1250Sim sim;
write_global_u32(*sim.memory, kKernargAddr, kSgprValue);
write_global_u32(*sim.memory, kKernargAddr + 4, kTtmpValue);
write_global_u32(*sim.memory, kKernargAddr + 8, kDiscardedValue);
uint64_t kernel_object = sim.write_kernel(kKernelAddr, code.data(), code.size(), 104, 32, 2,
false, false, false, kernel_code_properties, 12);

test::AqlQueue queue(sim.memory, sim.cp());
queue.dispatch(kernel_object, 32, 32, kKernargAddr);
step_until_halted(*sim.engine, *sim.cu());

ASSERT_EQ(sim.snapshot->snapshots().size(), 1u);
const auto &wf = sim.snapshot->snapshots().front();
EXPECT_EQ(wf.sgpr(4), kSgprValue);
EXPECT_EQ(wf.ttmp(0), kTtmpValue);
EXPECT_EQ(wf.sgpr(amdgpu::kModernNullSelector), 0u);
}

TEST(Gfx1250SimulationTest, TtmpWorkgroupIdsUseGridCoordinatesFor2DDispatch) {
Gfx1250Sim sim;
const uint32_t code[] = {S_ENDPGM_GFX12};
Expand Down
86 changes: 86 additions & 0 deletions emulation/rocjitsu/tests/execution_plugin_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@
#include "rocjitsu/isa/arch/amdgpu/generated/cdna4/machine_insts.h"
#include "rocjitsu/isa/arch/amdgpu/generated/cdna4/opcodes.h"
#include "rocjitsu/isa/arch/amdgpu/generated/cdna4/vop1.h"
#include "rocjitsu/isa/arch/amdgpu/generated/cdna5/builders.h"
#include "rocjitsu/isa/arch/amdgpu/generated/cdna5/execution_backend.h"
#include "rocjitsu/isa/arch/amdgpu/generated/cdna5/machine_insts.h"
#include "rocjitsu/isa/arch/amdgpu/generated/cdna5/opcodes.h"
#include "rocjitsu/isa/arch/amdgpu/generated/cdna5/vop1.h"
#include "rocjitsu/isa/arch/amdgpu/generated/cdna5/vop3.h"
#include "rocjitsu/isa/arch/amdgpu/generated/rdna4/execution_backend.h"
Expand Down Expand Up @@ -2771,6 +2773,90 @@ TEST(ExecutionPluginTest, ScalarMemoryCompletionDoesNotObserveInstructionWrite)
[](const HookEvent &event) { return event.kind == HookEvent::WRITE_SGPR; }));
}

TEST(ExecutionPluginTest, Gfx1250ScalarMemoryRoutesSpecialSelectorsAtNonzeroSgprBase) {
Comment thread
amd-eochoalo marked this conversation as resolved.
Resolved
constexpr uint32_t kSgprsPerWave = 128;
PluginFixture f(/*num_wf_slots=*/2, /*arch=*/"cdna5", /*wavefront_size=*/32, kSgprsPerWave);
auto *cu = f.cu();
auto *first = cu->dispatch_wf(/*wg_id=*/0, /*pc=*/0, kSgprsPerWave, /*vgprs=*/32);
auto *wf = cu->dispatch_wf(/*wg_id=*/1, /*pc=*/0, kSgprsPerWave, /*vgprs=*/32);
ASSERT_NE(first, nullptr);
ASSERT_NE(wf, nullptr);
ASSERT_EQ(first->sgpr_alloc().base, 0u);
ASSERT_EQ(wf->sgpr_alloc().base, kSgprsPerWave);

constexpr uint32_t kVccLoSlotSentinel = 0x10610610u;
constexpr uint32_t kVccHiSlotSentinel = 0x10710710u;
constexpr uint32_t kNullSlotSentinel = 0x12412410u;
const uint32_t base = wf->sgpr_alloc().base;
cu->write_sgpr(base + kVccSelectorFirst, kVccLoSlotSentinel);
cu->write_sgpr(base + kVccSelectorLast, kVccHiSlotSentinel);
cu->write_sgpr(base + kModernNullSelector, kNullSlotSentinel);

constexpr uint64_t kDataAddress = 0x8800;
constexpr std::array<uint32_t, 7> kData = {
0x12345678u, 0xA5B6C7D8u, 0x89ABCDEFu, 0x01234567u, 0xCAFEBABEu, 0x0BADF00Du, 0xDEADBEEFu,
};
f.mem->load_image(reinterpret_cast<const uint8_t *>(kData.data()), sizeof(kData), kDataAddress);

auto decoder = Decoder::create(ROCJITSU_CODE_ARCH_CDNA5);
ASSERT_NE(decoder, nullptr);
TestScalarMemPipeline pipeline(&cu->l1_scalar());
auto issue_load = [&](uint16_t op, uint8_t sdata, uint64_t address, uint8_t sbase = 0) {
cu->write_sgpr(base, static_cast<uint32_t>(address));
cu->write_sgpr(base + 1, static_cast<uint32_t>(address >> 32));
const auto words =
cdna5::build_smem(op, {.sbase = sbase,
.sdata = sdata,
.scale_offset = 1,
.soffset = static_cast<uint8_t>(kModernNullSelector)});
std::unique_ptr<Instruction> load(decode_valid(*decoder, words.data()));
EXPECT_NE(load, nullptr);
if (!load)
return;
cu->execute_instruction(load.get(), *wf);
EXPECT_NE(load->data(), nullptr);
if (!load->data())
return;
pipeline.issue(load.release(), *wf);
};

wf->set_vcc_raw(0x1122334455667788ull);
issue_load(cdna5::kSLoadB32Smem, kVccSelectorFirst, kDataAddress);
EXPECT_EQ(wf->vcc(), 0x1122334412345678ull);
issue_load(cdna5::kSLoadB32Smem, kVccSelectorLast, kDataAddress + 4);
EXPECT_EQ(wf->vcc(), 0xA5B6C7D812345678ull);
issue_load(cdna5::kSLoadB64Smem, kVccSelectorFirst, kDataAddress + 8);
EXPECT_EQ(wf->vcc(), 0x0123456789ABCDEFull);

issue_load(cdna5::kSLoadB32Smem, kTtmpSelectorFirst, kDataAddress + 16);
EXPECT_EQ(wf->ttmp(0), kData[4]);
issue_load(cdna5::kSLoadB32Smem, 4, kDataAddress + 20);
EXPECT_EQ(cu->read_sgpr_storage(base + 4), kData[5]);
issue_load(cdna5::kSLoadB32Smem, kModernNullSelector, kDataAddress + 24);

EXPECT_EQ(cu->read_sgpr_storage(base + kVccSelectorFirst), kVccLoSlotSentinel);
EXPECT_EQ(cu->read_sgpr_storage(base + kVccSelectorLast), kVccHiSlotSentinel);
EXPECT_EQ(cu->read_sgpr_storage(base + kModernNullSelector), kNullSlotSentinel);

constexpr uint64_t kVccBaseAddress = 0x8900;
constexpr uint64_t kTtmpBaseAddress = 0x8A00;
constexpr uint32_t kVccBaseValue = 0x13579BDFu;
constexpr uint32_t kTtmpBaseValue = 0x2468ACE0u;
f.mem->load_image(reinterpret_cast<const uint8_t *>(&kVccBaseValue), sizeof(kVccBaseValue),
kVccBaseAddress);
f.mem->load_image(reinterpret_cast<const uint8_t *>(&kTtmpBaseValue), sizeof(kTtmpBaseValue),
kTtmpBaseAddress);

wf->set_vcc_raw(kVccBaseAddress);
issue_load(cdna5::kSLoadB32Smem, 5, /*address=*/0, static_cast<uint8_t>(kVccSelectorFirst / 2));
EXPECT_EQ(cu->read_sgpr_storage(base + 5), kVccBaseValue);

wf->set_ttmp(0, static_cast<uint32_t>(kTtmpBaseAddress));
wf->set_ttmp(1, static_cast<uint32_t>(kTtmpBaseAddress >> 32));
issue_load(cdna5::kSLoadB32Smem, 6, /*address=*/0, static_cast<uint8_t>(kTtmpSelectorFirst / 2));
EXPECT_EQ(cu->read_sgpr_storage(base + 6), kTtmpBaseValue);
}

TEST(ExecutionPluginTest, ScalarMemoryRejectsDestinationThatCrossesTtmpFile) {
PluginFixture f(/*num_wf_slots=*/2);
auto *cu = f.cu();
Expand Down
Loading