graphics: add RDNA2 FLAT BDA buffer cache and faults

This commit is contained in:
nmzik
2026-08-27 03:45:41 +02:00
parent 8072718462
commit e738535294
37 changed files with 1002 additions and 684 deletions
+195 -54
View File
@@ -919,6 +919,11 @@ void CheckLeastRecentlyUsedCacheOrdering() {
std::printf("[host] %-32s ok\n", "LeastRecentlyUsedCache");
}
struct BdaMapping {
uint64_t guest_base = 0;
u32 backing_offset = 0;
};
struct TestCase {
const char *name = "";
std::vector<u32> code;
@@ -959,15 +964,15 @@ struct TestCase {
bool compile_only = false;
size_t storage_buffer_range_dwords = 0;
std::vector<u32> storage_buffer_offsets;
std::vector<u32> address_memory_offsets;
std::vector<BdaMapping> bda_mappings;
bool expand_shader_data_storage = false;
bool expected_force_point_sampler = false;
std::optional<uint64_t> flat_memory_base;
std::vector<u32> gds_initial;
std::vector<u32> expected_gds;
std::vector<std::pair<std::string, size_t>> decoded_counts;
std::vector<std::pair<std::string, size_t>> ir_counts;
u32 expected_storage_mip_descriptors = 0;
std::string expected_compile_error;
};
struct GraphicsCase {
@@ -1168,7 +1173,6 @@ CompiledShader CompileCase(const TestCase &test) {
options.user_data = user_data.data();
options.read_memory = ReadTestMemory;
options.read_memory_data = const_cast<std::vector<u32> *>(&test.initial);
options.flat_memory_base = test.flat_memory_base;
options.scratch_dwords = test.compute_info.scratch_size_dwords;
if (test.has_compute_info) {
options.wave_size = test.compute_info.wave_size;
@@ -1177,8 +1181,14 @@ CompiledShader CompileCase(const TestCase &test) {
ShaderRecompiler::CompileResult result;
std::string error;
if (!ShaderRecompiler::TryRecompile(test.code, options, result, &error)) {
if (!test.expected_compile_error.empty() &&
error.find(test.expected_compile_error) != std::string::npos) {
return {};
}
Fail(test.name, "decode/IR", error.c_str());
}
Require(test.name, "decode/IR", test.expected_compile_error.empty(),
"shader unexpectedly compiled despite the required rejection");
for (const auto &[text, expected] : test.decoded_counts) {
const auto actual = CountText(result.decoded_dump, text);
Require(test.name, "decoded RDNA2", actual == expected,
@@ -1267,17 +1277,6 @@ CompiledShader CompileCase(const TestCase &test) {
packed_user_data[result.program.bindings.memory_offset_dword + i / 4u] |=
offset << ((i % 4u) * 8u);
}
for (u32 i = 0; i < result.program.info.addresses.size(); i++) {
u32 offset = 0;
if (i < test.address_memory_offsets.size()) {
offset = test.address_memory_offsets[i];
}
Require(test.name, "shader data", offset < 256,
"address-memory offset is not representable");
const auto index = buffer_count + i;
packed_user_data[result.program.bindings.memory_offset_dword +
index / 4u] |= offset << ((index % 4u) * 8u);
}
return {std::move(result.spirv), std::move(result.program),
std::move(result.resources.flattened_srt),
std::move(packed_user_data)};
@@ -1469,6 +1468,7 @@ public:
struct Buffer {
vk::Buffer buffer = nullptr;
vk::DeviceMemory memory = nullptr;
vk::DeviceAddress device_address = 0;
vk::DeviceSize size = 0;
bool coherent = false;
};
@@ -3157,7 +3157,7 @@ public:
"chunked host copy lost bytes across its scratch boundary");
constexpr uint64_t index_offset = 0x180000;
constexpr uint64_t index_page = BufferCache::CACHING_PAGE_SIZE;
constexpr uint64_t index_page = BufferCache::CACHING_PAGESIZE;
constexpr uint64_t index_span = 3 * index_page;
const uint64_t index_begin = base + index_offset;
Require(name, "registered-range empty lookup",
@@ -3386,7 +3386,7 @@ public:
"Buffer ownership");
constexpr uint64_t starvation_offset = 0x100000;
constexpr uint64_t starvation_stride = 2 * BufferCache::CACHING_PAGE_SIZE;
constexpr uint64_t starvation_stride = 2 * BufferCache::CACHING_PAGESIZE;
constexpr uint32_t starvation_count = 33;
constexpr uint32_t starvation_value = 0x31415926u;
BufferCacheTestAccess::SetGarbageCollectionThresholds(
@@ -3443,7 +3443,7 @@ public:
constexpr uint64_t lookup_only_offset = 0x218000;
constexpr uint64_t obtained_offset = 0x220000;
constexpr uint64_t residency_size =
2 * BufferCache::CACHING_PAGE_SIZE;
2 * BufferCache::CACHING_PAGESIZE;
BufferCacheTestAccess::SetGarbageCollectionThresholds(
cache, std::numeric_limits<uint64_t>::max(),
std::numeric_limits<uint64_t>::max());
@@ -4199,7 +4199,7 @@ public:
const uint64_t mip_guest_size = mip_total.size + 256;
Require(name, "formatted mip fixture",
mip_sizes[0].offset == 0 &&
mip_prefix_size > BufferCache::CACHING_PAGE_SIZE &&
mip_prefix_size > BufferCache::CACHING_PAGESIZE &&
mip_prefix_size < mip_guest_size &&
mip_guest_size % sizeof(uint32_t) == 0,
"single-mip fixture did not expose a cache-sized fitting backing "
@@ -8946,7 +8946,7 @@ public:
Buffer CreateStorageBuffer(const char *shader_name,
const std::vector<u32> &initial,
size_t dword_count) {
size_t dword_count, bool device_address = false) {
Buffer ret;
ret.size = static_cast<vk::DeviceSize>(std::max<size_t>(dword_count, 1u) *
sizeof(u32));
@@ -8955,6 +8955,9 @@ public:
buffer_info.sType = vk::StructureType::eBufferCreateInfo;
buffer_info.size = ret.size;
buffer_info.usage = vk::BufferUsageFlagBits::eStorageBuffer;
if (device_address) {
buffer_info.usage |= vk::BufferUsageFlagBits::eShaderDeviceAddress;
}
buffer_info.sharingMode = vk::SharingMode::eExclusive;
RequireVk(shader_name, "dispatch",
m_device.createBuffer(&buffer_info, nullptr, &ret.buffer),
@@ -8979,12 +8982,26 @@ public:
alloc.sType = vk::StructureType::eMemoryAllocateInfo;
alloc.allocationSize = req.size;
alloc.memoryTypeIndex = memory_type;
vk::MemoryAllocateFlagsInfo flags{};
if (device_address) {
flags.sType = vk::StructureType::eMemoryAllocateFlagsInfo;
flags.flags = vk::MemoryAllocateFlagBits::eDeviceAddress;
alloc.pNext = &flags;
}
RequireVk(shader_name, "dispatch",
m_device.allocateMemory(&alloc, nullptr, &ret.memory),
"vkAllocateMemory");
RequireVk(shader_name, "dispatch",
m_device.bindBufferMemory(ret.buffer, ret.memory, 0),
"vkBindBufferMemory");
if (device_address) {
vk::BufferDeviceAddressInfo address_info{};
address_info.sType = vk::StructureType::eBufferDeviceAddressInfo;
address_info.buffer = ret.buffer;
ret.device_address = m_device.getBufferAddress(address_info);
Require(shader_name, "dispatch", ret.device_address != 0,
"storage buffer has no device address");
}
std::vector<u32> contents(dword_count, 0);
for (size_t i = 0; i < initial.size() && i < contents.size(); i++) {
@@ -9366,7 +9383,9 @@ public:
pool_sizes.push_back({type, count});
};
add_pool_size(vk::DescriptorType::eStorageBuffer,
Count(Kind::Buffers) + Count(Kind::AddressMemory) +
Count(Kind::Buffers) +
(Binding(Kind::BdaPagetable) != nullptr ? 1u : 0u) +
(Binding(Kind::FaultBuffer) != nullptr ? 1u : 0u) +
Count(Kind::Gds) +
(Binding(Kind::FlattenedSrt) != nullptr ? 1u : 0u) +
(Binding(Kind::UserData) != nullptr ? 1u : 0u));
@@ -9411,7 +9430,6 @@ public:
std::vector<vk::WriteDescriptorSet> writes;
std::vector<vk::DescriptorBufferInfo> buffer_infos;
std::vector<vk::DescriptorBufferInfo> address_memory_infos;
std::vector<vk::DescriptorImageInfo> sampled_infos;
std::vector<vk::DescriptorImageInfo> storage_infos;
std::vector<vk::DescriptorImageInfo> storage_uint_infos;
@@ -9422,6 +9440,33 @@ public:
vk::DescriptorBufferInfo flattened_info{};
vk::DescriptorBufferInfo user_data_info{};
vk::DescriptorBufferInfo gds_info{};
vk::DescriptorBufferInfo bda_pagetable_info{};
vk::DescriptorBufferInfo fault_buffer_info{};
const bool uses_bda = Binding(Kind::BdaPagetable) != nullptr;
Require(test.name, "dispatch",
uses_bda == (Binding(Kind::FaultBuffer) != nullptr),
"BDA page table and fault buffer must be bound together");
if (uses_bda) {
EnsureBdaBuffers(test.name);
bda_pagetable_info = {m_bda_pagetable_buffer.buffer, 0,
m_bda_pagetable_buffer.size};
fault_buffer_info = {m_fault_buffer.buffer, 0, m_fault_buffer.size};
const std::array special_buffers{
std::pair{Kind::BdaPagetable, &bda_pagetable_info},
std::pair{Kind::FaultBuffer, &fault_buffer_info},
};
for (const auto &[kind, info] : special_buffers) {
vk::WriteDescriptorSet write{};
write.sType = vk::StructureType::eWriteDescriptorSet;
write.dstSet = descriptor_set;
write.dstBinding = Native(kind);
write.descriptorCount = 1;
write.descriptorType = vk::DescriptorType::eStorageBuffer;
write.pBufferInfo = info;
writes.push_back(write);
}
}
const auto *buffers = Binding(Kind::Buffers);
if (buffers != nullptr) {
@@ -9450,21 +9495,6 @@ public:
write.pBufferInfo = buffer_infos.data();
writes.push_back(write);
}
if (const auto *address = Binding(Kind::AddressMemory);
address != nullptr) {
address_memory_infos.resize(address->resources.size());
for (auto &info : address_memory_infos) {
info = {buffer.buffer, 0, buffer.size};
}
vk::WriteDescriptorSet write{};
write.sType = vk::StructureType::eWriteDescriptorSet;
write.dstSet = descriptor_set;
write.dstBinding = Native(Kind::AddressMemory);
write.descriptorCount = static_cast<u32>(address_memory_infos.size());
write.descriptorType = vk::DescriptorType::eStorageBuffer;
write.pBufferInfo = address_memory_infos.data();
writes.push_back(write);
}
if (const auto *flattened = Binding(Kind::FlattenedSrt);
flattened != nullptr) {
flattened_buffer = CreateStorageBuffer(test.name, compiled.flattened_srt,
@@ -9590,6 +9620,52 @@ public:
}
vk::CommandBuffer cmd = BeginCommands(test.name, "dispatch");
if (uses_bda) {
Require(test.name, "dispatch", buffer.device_address != 0,
"BDA test backing has no device address");
Require(test.name, "dispatch", !test.bda_mappings.empty(),
"BDA test has no explicit guest mapping");
cmd.fillBuffer(m_bda_pagetable_buffer.buffer, 0,
m_bda_pagetable_buffer.size, 0);
cmd.fillBuffer(m_fault_buffer.buffer, 0, m_fault_buffer.size, 0);
for (const auto &[guest_base, backing] : test.bda_mappings) {
const auto page_offset = guest_base &
(BufferCache::CACHING_PAGESIZE - 1);
Require(test.name, "dispatch",
backing >= page_offset && backing < buffer.size,
"BDA test mapping begins outside its backing buffer");
const auto bytes = page_offset + buffer.size - backing;
const auto pages =
(bytes + BufferCache::CACHING_PAGESIZE - 1) /
BufferCache::CACHING_PAGESIZE;
auto address = buffer.device_address + backing - page_offset;
auto page = guest_base >> BufferCache::CACHING_PAGEBITS;
for (uint64_t mapped = 0; mapped < pages; mapped++) {
cmd.updateBuffer(m_bda_pagetable_buffer.buffer,
(page + mapped) * sizeof(vk::DeviceAddress),
sizeof(address), &address);
address += BufferCache::CACHING_PAGESIZE;
}
}
std::array<vk::BufferMemoryBarrier, 2> barriers{};
barriers[0].sType = vk::StructureType::eBufferMemoryBarrier;
barriers[0].srcAccessMask = vk::AccessFlagBits::eTransferWrite;
barriers[0].dstAccessMask = vk::AccessFlagBits::eShaderRead;
barriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barriers[0].buffer = m_bda_pagetable_buffer.buffer;
barriers[0].offset = 0;
barriers[0].size = m_bda_pagetable_buffer.size;
barriers[1] = barriers[0];
barriers[1].dstAccessMask = vk::AccessFlagBits::eShaderRead |
vk::AccessFlagBits::eShaderWrite;
barriers[1].buffer = m_fault_buffer.buffer;
barriers[1].size = m_fault_buffer.size;
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer,
vk::PipelineStageFlagBits::eComputeShader, {}, 0,
nullptr, static_cast<u32>(barriers.size()),
barriers.data(), 0, nullptr);
}
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline);
cmd.bindDescriptorSets(vk::PipelineBindPoint::eCompute, pipeline_layout, 0,
1, &descriptor_set, 0, nullptr);
@@ -10951,6 +11027,7 @@ private:
allocator_info.device = m_device;
allocator_info.pVulkanFunctions = &functions;
allocator_info.vulkanApiVersion = VK_API_VERSION_1_3;
allocator_info.flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT;
RequireVk("VulkanHarness", "runtime context",
static_cast<vk::Result>(vmaCreateAllocator(
&allocator_info, &m_runtime_context.allocator)),
@@ -11001,13 +11078,18 @@ private:
if ((queues[i].queueFlags &
(vk::QueueFlagBits::eCompute | vk::QueueFlagBits::eGraphics)) ==
(vk::QueueFlagBits::eCompute | vk::QueueFlagBits::eGraphics)) {
vk::PhysicalDeviceVulkan12Features features12{};
features12.sType = vk::StructureType::ePhysicalDeviceVulkan12Features;
vk::PhysicalDeviceFragmentShaderBarycentricFeaturesKHR barycentric{};
barycentric.sType = vk::StructureType::ePhysicalDeviceFragmentShaderBarycentricFeaturesKHR;
barycentric.pNext = &features12;
vk::PhysicalDeviceFeatures2 features{};
features.sType = vk::StructureType::ePhysicalDeviceFeatures2;
features.pNext = &barycentric;
physical.getFeatures2(&features);
if (barycentric.fragmentShaderBarycentric != true) {
if (barycentric.fragmentShaderBarycentric != true ||
features.features.shaderInt64 != true ||
features12.bufferDeviceAddress != true) {
continue;
}
m_physical_device = physical;
@@ -11051,6 +11133,11 @@ private:
Require("VulkanHarness", "dispatch",
available_features.sampleRateShading == true,
"sample-rate shading is not supported");
Require("VulkanHarness", "dispatch", available_features.shaderInt64 == true,
"shaderInt64 is not supported");
Require("VulkanHarness", "dispatch",
available_features12.bufferDeviceAddress == true,
"bufferDeviceAddress is not supported");
float priority = 1.0f;
vk::DeviceQueueCreateInfo queue_info{};
@@ -11067,6 +11154,7 @@ private:
device_features12.sType =
vk::StructureType::ePhysicalDeviceVulkan12Features;
device_features12.timelineSemaphore = true;
device_features12.bufferDeviceAddress = true;
vk::PhysicalDeviceFragmentShaderBarycentricFeaturesKHR barycentric{};
barycentric.sType = vk::StructureType::ePhysicalDeviceFragmentShaderBarycentricFeaturesKHR;
barycentric.pNext = &device_features12;
@@ -11081,6 +11169,7 @@ private:
vk::PhysicalDeviceFeatures device_features{};
device_features.shaderStorageImageWriteWithoutFormat = true;
device_features.sampleRateShading = true;
device_features.shaderInt64 = true;
device_info.pEnabledFeatures = &device_features;
constexpr const char *device_extensions[] = {
VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME,
@@ -11105,6 +11194,8 @@ private:
void Destroy() {
if (m_device != nullptr) {
RequireVulkanSuccess(m_device.waitIdle(), "vkDeviceWaitIdle");
DestroyBuffer(&m_fault_buffer);
DestroyBuffer(&m_bda_pagetable_buffer);
if (m_runtime_context.allocator != nullptr) {
m_renderer.reset();
vmaDestroyAllocator(m_runtime_context.allocator);
@@ -11276,6 +11367,53 @@ private:
image->layout = final_layout;
}
Buffer CreateDeviceBuffer(const char *shader_name, vk::DeviceSize size,
vk::BufferUsageFlags usage) {
Buffer ret;
ret.size = size;
vk::BufferCreateInfo buffer_info{};
buffer_info.sType = vk::StructureType::eBufferCreateInfo;
buffer_info.size = size;
buffer_info.usage = usage;
buffer_info.sharingMode = vk::SharingMode::eExclusive;
RequireVk(shader_name, "dispatch",
m_device.createBuffer(&buffer_info, nullptr, &ret.buffer),
"vkCreateBuffer");
vk::MemoryRequirements requirements{};
m_device.getBufferMemoryRequirements(ret.buffer, &requirements);
u32 memory_type = 0;
Require(shader_name, "dispatch",
FindMemoryType(requirements.memoryTypeBits,
vk::MemoryPropertyFlagBits::eDeviceLocal,
&memory_type) ||
FindMemoryType(requirements.memoryTypeBits, {}, &memory_type),
"no memory type for BDA support buffer");
vk::MemoryAllocateInfo allocation{};
allocation.sType = vk::StructureType::eMemoryAllocateInfo;
allocation.allocationSize = requirements.size;
allocation.memoryTypeIndex = memory_type;
RequireVk(shader_name, "dispatch",
m_device.allocateMemory(&allocation, nullptr, &ret.memory),
"vkAllocateMemory");
RequireVk(shader_name, "dispatch",
m_device.bindBufferMemory(ret.buffer, ret.memory, 0),
"vkBindBufferMemory");
return ret;
}
void EnsureBdaBuffers(const char *shader_name) {
if (m_bda_pagetable_buffer.buffer != nullptr) {
return;
}
const auto usage = vk::BufferUsageFlagBits::eStorageBuffer |
vk::BufferUsageFlagBits::eTransferDst;
m_bda_pagetable_buffer =
CreateDeviceBuffer(shader_name, BufferCache::BDA_PAGETABLE_SIZE, usage);
m_fault_buffer = CreateDeviceBuffer(
shader_name, BufferCache::CACHING_NUMPAGES / 8, usage);
}
Buffer CreateHostBuffer(const char *shader_name, vk::DeviceSize size,
vk::BufferUsageFlags usage,
const std::vector<u32> &contents) {
@@ -11349,6 +11487,8 @@ private:
vk::CommandPool m_command_pool = nullptr;
u32 m_queue_family = 0;
vk::PhysicalDeviceMemoryProperties m_memory_properties{};
Buffer m_bda_pagetable_buffer;
Buffer m_fault_buffer;
GraphicContext m_runtime_context{};
std::unique_ptr<RenderContext> m_renderer;
};
@@ -11392,6 +11532,10 @@ void CompareGraphicsWords(const GraphicsCase &test,
void RunCase(VulkanHarness *vulkan, const TestCase &test) {
auto compiled = CompileCase(test);
if (!test.expected_compile_error.empty()) {
std::printf("[compute] %-32s ok\n", test.name);
return;
}
if (test.image_descriptor_swizzle != DstSel(4, 5, 6, 7)) {
Require(test.name, "resource specialization",
!compiled.program.info.images.empty() &&
@@ -11410,15 +11554,15 @@ void RunCase(VulkanHarness *vulkan, const TestCase &test) {
std::printf("[compute] %-32s ok\n", test.name);
return;
}
const auto dwords = std::max<size_t>(
{test.initial.size(), test.expected.size(), static_cast<size_t>(1)});
auto buffer = vulkan->CreateStorageBuffer(test.name, test.initial, dwords);
using Kind = ShaderRecompiler::IR::DescriptorBindingKind;
auto Has = [&](Kind kind) {
return ShaderRecompiler::IR::FindBinding(compiled.program.bindings, kind) !=
nullptr;
};
const auto dwords = std::max<size_t>(
{test.initial.size(), test.expected.size(), static_cast<size_t>(1)});
auto buffer = vulkan->CreateStorageBuffer(
test.name, test.initial, dwords, Has(Kind::BdaPagetable));
VulkanHarness::Image sampled_image;
VulkanHarness::Image storage_image;
VulkanHarness::Image storage_image_uint;
@@ -17341,16 +17485,16 @@ TestCase FlatLoadVariants() {
O::FLAT_LOAD_USHORT, O::FLAT_LOAD_SSHORT, O::FLAT_LOAD_DWORD,
O::FLAT_LOAD_DWORDX2, O::FLAT_LOAD_DWORDX3,
O::FLAT_LOAD_DWORDX4, O::BUFFER_STORE_DWORD, O::S_ENDPGM}};
test.flat_memory_base = 0;
test.address_memory_offsets = {static_cast<u32>(byte_offset)};
test.bda_mappings = {{0, static_cast<u32>(byte_offset)}};
return test;
}
TestCase FlatSubdwordLoadsApplyByteOffset() {
using O = ShaderOpcode;
constexpr size_t byte_offset = 3;
std::vector<u32> code;
AppendVMovU32(&code, 20, 0);
AppendVMovU32(&code, 20, static_cast<u32>(byte_offset));
AppendVMovU32(&code, 21, 0);
code.push_back(EncodeFlat0(0x08, 0, 0));
code.push_back(EncodeFlat1(0, 0x7d, 0, 20));
@@ -17360,7 +17504,6 @@ TestCase FlatSubdwordLoadsApplyByteOffset() {
AppendStoreVgpr(&code, 1, 1);
AppendEnd(&code);
constexpr size_t byte_offset = 3;
constexpr u32 guest_word = 0x80ff7f01u;
std::vector<u32> host_memory(
(byte_offset + sizeof(guest_word) + sizeof(u32) - 1u) / sizeof(u32));
@@ -17372,8 +17515,7 @@ TestCase FlatSubdwordLoadsApplyByteOffset() {
test.code = std::move(code);
test.initial = std::move(host_memory);
test.expected = {0x01u, 0x0000ff7fu};
test.flat_memory_base = 0;
test.address_memory_offsets = {static_cast<u32>(byte_offset)};
test.bda_mappings = {{0, 0}};
test.opcodes = {O::V_MOV_B32, O::FLAT_LOAD_UBYTE, O::FLAT_LOAD_USHORT,
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
return test;
@@ -17457,8 +17599,7 @@ TestCase FlatVirtualAddressRebasesGuestAllocation() {
test.code = std::move(code);
test.initial = {0xfeedfaceu, 0xcafebabeu, 0, 0x12345678u};
test.expected = {0x12345678u, 0x12345678u, 0};
test.flat_memory_base = GuestBase;
test.address_memory_offsets = {8, 8, 8};
test.bda_mappings = {{GuestBase, 8}};
test.opcodes = {O::V_MOV_B32, O::FLAT_LOAD_DWORD, O::BUFFER_STORE_DWORD,
O::S_ENDPGM};
return test;
@@ -17480,10 +17621,9 @@ TestCase GlobalSignedImmediateRebasesBeforeSaddr() {
TestCase test;
test.name = "GlobalSignedImmediateRebasesBeforeSaddr";
test.code = std::move(code);
test.initial = {0xfeedfaceu, 0xcafebabeu, 0x11111111u, 0x22222222u,
0x12345678u};
test.initial = {0xfeedfaceu, 0xcafebabeu, 0x11111111u, 0x12345678u};
test.expected = {0x12345678u};
test.address_memory_offsets = {8};
test.bda_mappings = {{GuestBase, 8}};
test.opcodes = {O::S_MOV_B32, O::V_MOV_B32, O::FLAT_LOAD_DWORD,
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
return test;
@@ -17517,7 +17657,7 @@ TestCase FlatSegmentIgnoresSaddrAndMasksOffsetMsb() {
test.expected = {0x11111111u, 0x11111111u};
test.opcodes = {O::S_MOV_B32, O::V_MOV_B32, O::FLAT_LOAD_DWORD,
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
test.flat_memory_base = 0;
test.bda_mappings = {{0, 0}};
return test;
}
@@ -17596,7 +17736,8 @@ TestCase FlatStoreVariants() {
{O::V_MOV_B32, O::FLAT_STORE_BYTE, O::FLAT_STORE_SHORT,
O::FLAT_STORE_DWORD, O::FLAT_STORE_DWORDX2,
O::FLAT_STORE_DWORDX3, O::FLAT_STORE_DWORDX4, O::S_ENDPGM}};
test.flat_memory_base = 0;
test.expected_compile_error =
"writable FLAT/GLOBAL addresses require GPU ownership tracking";
return test;
}