mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 02:47:02 +02:00
shader: use native narrow storage for byte-aligned PS5 buffers
Co-authored-by: MehmetCambaz <mcambaz18@gmail.com>
This commit is contained in:
@@ -1311,7 +1311,7 @@ struct TestCase {
|
||||
bool has_user_data = false;
|
||||
u32 image_descriptor_swizzle = DstSel(4, 5, 6, 7);
|
||||
bool compile_only = false;
|
||||
size_t storage_buffer_range_dwords = 0;
|
||||
size_t storage_buffer_range_bytes = 0;
|
||||
std::vector<u32> storage_buffer_offsets;
|
||||
std::vector<BdaMapping> bda_mappings;
|
||||
bool expand_shader_data_storage = false;
|
||||
@@ -1700,7 +1700,7 @@ CompiledShader CompileCase(const TestCase &test, u32 host_subgroup_size = 64) {
|
||||
if (resource < test.storage_buffer_offsets.size()) {
|
||||
offset = test.storage_buffer_offsets[resource];
|
||||
}
|
||||
Require(test.name, "shader data", offset % sizeof(u32) == 0 && offset < 256,
|
||||
Require(test.name, "shader data", offset < 256,
|
||||
"storage buffer offset is not representable");
|
||||
packed_user_data[result.program.bindings.memory_offset_dword + i / 4u] |=
|
||||
offset << ((i % 4u) * 8u);
|
||||
@@ -11360,6 +11360,32 @@ public:
|
||||
"descriptor rebind lost its clamped guest range or retained a stale host owner");
|
||||
}
|
||||
|
||||
{
|
||||
const auto buffer_program = make_buffer_program(ShaderType::Compute, {.read = true});
|
||||
constexpr uint64_t buffer_address = base + 0xe0002;
|
||||
ShaderBufferResource descriptor{};
|
||||
descriptor.UpdateAddress48(buffer_address);
|
||||
descriptor.fields[1] |= 6u << 16u;
|
||||
descriptor.fields[2] = 2;
|
||||
descriptor.fields[3] = 0x5204;
|
||||
ShaderRecompiler::IR::ResourceSnapshot snapshot;
|
||||
auto &value = snapshot.buffers.emplace_back();
|
||||
std::copy_n(descriptor.fields, 4, value.dwords.begin());
|
||||
value.dword_count = 4;
|
||||
ShaderStageRuntime runtime{&buffer_program, &snapshot};
|
||||
PreparedBindings bindings;
|
||||
executor.PrepareBindings(runtime, bindings);
|
||||
executor.FindBuffers(bindings);
|
||||
executor.RebindBuffers(bindings);
|
||||
const auto &owner = resources.GetBufferCache().GetBuffer(bindings.buffer_sources[0].id);
|
||||
Require(name, "halfword buffer base and exact tail",
|
||||
bindings.buffers[0].buffer == owner.Handle() &&
|
||||
bindings.buffers[0].offset + 2 == owner.Offset(buffer_address) &&
|
||||
bindings.buffers[0].range == 14 &&
|
||||
bindings.shader_data[buffer_program.bindings.memory_offset_dword] == 2,
|
||||
"native binding lost the byte adjustment or rounded the final halfword range");
|
||||
}
|
||||
|
||||
constexpr auto stencil_format = Prospero::BufferFormat::k8UInt;
|
||||
constexpr auto linear = Prospero::TileMode::kLinear;
|
||||
TileSizeAlign stencil_layout{};
|
||||
@@ -14545,13 +14571,13 @@ public:
|
||||
info.buffer = buffer.buffer;
|
||||
info.offset = 0;
|
||||
info.range = buffer.size;
|
||||
if (test.storage_buffer_range_dwords != 0) {
|
||||
if (test.storage_buffer_range_bytes != 0) {
|
||||
const auto resource = buffers->resources[i];
|
||||
const auto offset = resource < test.storage_buffer_offsets.size()
|
||||
? test.storage_buffer_offsets[resource]
|
||||
: 0u;
|
||||
info.range = static_cast<vk::DeviceSize>(
|
||||
test.storage_buffer_range_dwords * sizeof(u32) + offset);
|
||||
test.storage_buffer_range_bytes + offset);
|
||||
Require(test.name, "dispatch", info.range <= buffer.size,
|
||||
"storage buffer descriptor range exceeds backing buffer");
|
||||
}
|
||||
@@ -17117,10 +17143,12 @@ private:
|
||||
if ((queues[i].queueFlags &
|
||||
(vk::QueueFlagBits::eCompute | vk::QueueFlagBits::eGraphics)) ==
|
||||
(vk::QueueFlagBits::eCompute | vk::QueueFlagBits::eGraphics)) {
|
||||
vk::PhysicalDeviceVulkan11Features features11{};
|
||||
vk::PhysicalDeviceVulkan12Features features12{};
|
||||
features12.sType = vk::StructureType::ePhysicalDeviceVulkan12Features;
|
||||
vk::PhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR workgroup_layout{};
|
||||
features12.pNext = &workgroup_layout;
|
||||
features12.pNext = &features11;
|
||||
features11.pNext = &workgroup_layout;
|
||||
vk::PhysicalDeviceShaderImageAtomicInt64FeaturesEXT image_atomic64{};
|
||||
workgroup_layout.pNext = &image_atomic64;
|
||||
vk::PhysicalDeviceFragmentShaderBarycentricFeaturesKHR barycentric{};
|
||||
@@ -17132,6 +17160,8 @@ private:
|
||||
physical.getFeatures2(&features);
|
||||
if (barycentric.fragmentShaderBarycentric != true ||
|
||||
features.features.shaderInt64 != true ||
|
||||
features11.storageBuffer16BitAccess != true ||
|
||||
features12.storageBuffer8BitAccess != true ||
|
||||
features12.samplerMirrorClampToEdge != true ||
|
||||
features12.shaderOutputViewportIndex != true ||
|
||||
features12.shaderBufferInt64Atomics != true ||
|
||||
@@ -17157,7 +17187,9 @@ private:
|
||||
|
||||
vk::PhysicalDeviceFeatures available_features{};
|
||||
m_physical_device.getFeatures(&available_features);
|
||||
vk::PhysicalDeviceVulkan11Features available_features11{};
|
||||
vk::PhysicalDeviceVulkan12Features available_features12{};
|
||||
available_features12.pNext = &available_features11;
|
||||
available_features12.sType =
|
||||
vk::StructureType::ePhysicalDeviceVulkan12Features;
|
||||
vk::PhysicalDeviceVulkan13Features available_features13{};
|
||||
@@ -17191,6 +17223,10 @@ private:
|
||||
available_features.shaderImageGatherExtended == true &&
|
||||
available_derivatives.computeDerivativeGroupQuads == true,
|
||||
"image gather or compute derivative quads are not supported");
|
||||
Require("VulkanHarness", "dispatch",
|
||||
available_features11.storageBuffer16BitAccess == true &&
|
||||
available_features12.storageBuffer8BitAccess == true,
|
||||
"8-bit and 16-bit storage buffer access are not supported");
|
||||
Require("VulkanHarness", "dispatch",
|
||||
available_features12.timelineSemaphore == true,
|
||||
"timeline semaphores are not supported");
|
||||
@@ -17240,11 +17276,13 @@ private:
|
||||
device_info.sType = vk::StructureType::eDeviceCreateInfo;
|
||||
device_info.queueCreateInfoCount = 1;
|
||||
device_info.pQueueCreateInfos = &queue_info;
|
||||
auto device_features11 = WindowContext::RequiredVulkan11Features();
|
||||
auto device_features12 = WindowContext::RequiredVulkan12Features();
|
||||
device_features12.shaderSharedInt64Atomics = true;
|
||||
vk::PhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR workgroup_layout{};
|
||||
workgroup_layout.workgroupMemoryExplicitLayout = true;
|
||||
device_features12.pNext = &workgroup_layout;
|
||||
device_features12.pNext = &device_features11;
|
||||
device_features11.pNext = &workgroup_layout;
|
||||
vk::PhysicalDeviceShaderImageAtomicInt64FeaturesEXT image_atomic64{};
|
||||
image_atomic64.shaderImageInt64Atomics = true;
|
||||
workgroup_layout.pNext = &image_atomic64;
|
||||
@@ -26186,7 +26224,7 @@ TestCase BufferStoreDwordAppliesHostOffset() {
|
||||
|
||||
std::vector<u32> code;
|
||||
AppendVMovLiteral(&code, 0, 0xabcdef01u);
|
||||
code.push_back(EncodeMubuf0(0x1cu, 0, false, false));
|
||||
code.push_back(EncodeMubuf0(0x1cu, 2, false, false));
|
||||
code.push_back(EncodeMubuf1(0, 0, 20));
|
||||
AppendEnd(&code);
|
||||
|
||||
@@ -26194,11 +26232,11 @@ TestCase BufferStoreDwordAppliesHostOffset() {
|
||||
test.name = "BufferStoreDwordAppliesHostOffset";
|
||||
test.code = code;
|
||||
test.initial = {0x11111111u, 0x22222222u, 0x33333333u, 0};
|
||||
test.expected = {0x11111111u, 0x22222222u, 0x33333333u, 0xabcdef01u};
|
||||
test.storage_buffer_range_dwords = 1;
|
||||
test.storage_buffer_offsets = {12};
|
||||
test.expected = {0x11111111u, 0xabcdef01u, 0x33333333u, 0};
|
||||
test.storage_buffer_range_bytes = 8;
|
||||
test.storage_buffer_offsets = {2};
|
||||
test.opcodes = {O::V_MOV_B32, O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||
test.user_data = MakeStructuredStorageBufferData(4, 1);
|
||||
test.user_data = MakeStructuredStorageBufferData(0, 8);
|
||||
test.has_user_data = true;
|
||||
return test;
|
||||
}
|
||||
@@ -26226,7 +26264,7 @@ TestCase BufferOffsetsUsePackedLaneAndStorageFallback() {
|
||||
test.code = std::move(code);
|
||||
test.initial = {0, 0, 0, 0};
|
||||
test.expected = {0x12345678u, 0, 0, 0xabcdef01u};
|
||||
test.storage_buffer_range_dwords = 1;
|
||||
test.storage_buffer_range_bytes = 4;
|
||||
test.storage_buffer_offsets = {0, 12};
|
||||
test.expand_shader_data_storage = true;
|
||||
test.opcodes = {O::S_MOV_B32, O::V_MOV_B32, O::BUFFER_STORE_DWORD,
|
||||
@@ -26269,6 +26307,99 @@ TestCase BufferLoadVariants() {
|
||||
O::BUFFER_STORE_DWORD, O::S_ENDPGM}};
|
||||
}
|
||||
|
||||
TestCase BufferSubwordLoadsAtHostOffset(u32 bytes, u32 component, bool sign) {
|
||||
using O = ShaderOpcode;
|
||||
TestCase test;
|
||||
test.name = bytes == 1 ? (sign ? "BufferSbyteHostOffsetTail" : "BufferUbyteHostOffsetTail")
|
||||
: sign ? "BufferSshortHostOffsetTail"
|
||||
: component == 0 ? "BufferUshortHostOffsetFirst"
|
||||
: component == 2 ? "BufferUshortHostOffsetCarry"
|
||||
: "BufferUshortHostOffsetTail";
|
||||
// The captured stride-six index buffer uses USHORT IDXEN offsets 4, 2, 0.
|
||||
test.code = {EncodeMubuf0((bytes == 1 ? 0x08u : 0x0au) + sign,
|
||||
component, true, false),
|
||||
EncodeMubuf1(1, 0, 0),
|
||||
EncodeMubuf0(0x1cu, 0, true, false), EncodeMubuf1(1, 12, 0)};
|
||||
AppendEnd(&test.code);
|
||||
test.initial = {0x800112abu, 0xfedc2345u, 0x80007fffu, 0xfaceffffu,
|
||||
0xccccccccu, 0xccccccccu, 0xccccccccu};
|
||||
test.expected = test.initial;
|
||||
for (u32 record = 0; record < 2; ++record) {
|
||||
u32 value = 0;
|
||||
std::memcpy(&value, reinterpret_cast<const uint8_t *>(test.initial.data()) +
|
||||
bytes + record * 6 + component, bytes);
|
||||
if (sign && (value & (1u << (bytes * 8u - 1u))) != 0) {
|
||||
value |= UINT32_MAX << (bytes * 8u);
|
||||
}
|
||||
test.expected[4 + record] = value;
|
||||
}
|
||||
test.expected[6] = 0;
|
||||
test.storage_buffer_range_bytes = 12;
|
||||
test.storage_buffer_offsets = {bytes, 16};
|
||||
test.user_data = MakeStructuredStorageBufferData(6, 2);
|
||||
test.user_data[0] = 0x1000u + bytes;
|
||||
test.user_data[48] = 0x2000u;
|
||||
test.user_data[49] = 4u << 16u;
|
||||
test.user_data[50] = 3;
|
||||
test.user_data[51] = 0x5204;
|
||||
test.has_user_data = true;
|
||||
test.compute_info.thread_ids_num = 1;
|
||||
test.compute_info.threads_num[0] = 3;
|
||||
test.compute_info.threads_num[1] = test.compute_info.threads_num[2] = 1;
|
||||
test.has_compute_info = true;
|
||||
test.opcodes = {bytes == 1 ? (sign ? O::BUFFER_LOAD_SBYTE : O::BUFFER_LOAD_UBYTE)
|
||||
: (sign ? O::BUFFER_LOAD_SSHORT : O::BUFFER_LOAD_USHORT),
|
||||
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||
return test;
|
||||
}
|
||||
|
||||
TestCase BufferSubwordHostOffsetOverflow() {
|
||||
auto test = BufferSubwordLoadsAtHostOffset(2, 0, false);
|
||||
test.name = "BufferSubwordHostOffsetOverflow";
|
||||
test.code.clear();
|
||||
AppendVMovLiteral(&test.code, 20, UINT32_MAX);
|
||||
test.code.insert(test.code.end(),
|
||||
{EncodeMubuf0(0x0au), EncodeMubuf1(1, 0, 20),
|
||||
EncodeMubuf0(0x1cu, 0, true, false), EncodeMubuf1(1, 12, 0)});
|
||||
AppendVMovLiteral(&test.code, 1, 0xbeef);
|
||||
test.code.insert(test.code.end(), {EncodeMubuf0(0x1au), EncodeMubuf1(1, 0, 20)});
|
||||
AppendEnd(&test.code);
|
||||
test.expected[4] = test.expected[5] = 0;
|
||||
test.opcodes.push_back(ShaderOpcode::V_MOV_B32);
|
||||
test.opcodes.push_back(ShaderOpcode::BUFFER_STORE_SHORT);
|
||||
return test;
|
||||
}
|
||||
|
||||
TestCase BufferSubwordStoresAtHostOffset(u32 bytes) {
|
||||
using O = ShaderOpcode;
|
||||
TestCase test;
|
||||
test.name = bytes == 1 ? "BufferByteStoreHostOffsetTail" : "BufferShortStoreHostOffsetTail";
|
||||
AppendVMovLiteral(&test.code, 1, bytes == 1 ? 0xa5u : 0xcafeu);
|
||||
test.code.push_back(EncodeMubuf0(bytes == 1 ? 0x18u : 0x1au,
|
||||
6u - bytes, true, false));
|
||||
test.code.push_back(EncodeMubuf1(1, 0, 0));
|
||||
AppendEnd(&test.code);
|
||||
test.initial = {0x800112abu, 0xfedc2345u, 0x80007fffu, 0xfaceffffu,
|
||||
0x13579bdfu, 0x2468ace0u};
|
||||
test.expected = bytes == 1
|
||||
? std::vector<u32>{0x800112abu, 0xfea52345u, 0x80007fffu, 0xfaceffa5u,
|
||||
0x13579bdfu, 0x2468ace0u}
|
||||
: std::vector<u32>{0x800112abu, 0xcafe2345u, 0x80007fffu, 0xfacecafeu,
|
||||
0x13579bdfu, 0x2468ace0u};
|
||||
test.storage_buffer_range_bytes = 12;
|
||||
test.storage_buffer_offsets = {bytes};
|
||||
test.user_data = MakeStructuredStorageBufferData(6, 2);
|
||||
test.user_data[0] = 0x1000u + bytes;
|
||||
test.has_user_data = true;
|
||||
test.compute_info.thread_ids_num = 1;
|
||||
test.compute_info.threads_num[0] = 3;
|
||||
test.compute_info.threads_num[1] = test.compute_info.threads_num[2] = 1;
|
||||
test.has_compute_info = true;
|
||||
test.opcodes = {O::V_MOV_B32, bytes == 1 ? O::BUFFER_STORE_BYTE : O::BUFFER_STORE_SHORT,
|
||||
O::S_ENDPGM};
|
||||
return test;
|
||||
}
|
||||
|
||||
TestCase BufferLoadDwordx4SnapshotsOverlappingAddress() {
|
||||
using O = ShaderOpcode;
|
||||
|
||||
@@ -26363,7 +26494,7 @@ TestCase BufferLoadDwordx4ZeroesOnlyOutOfBoundsTail() {
|
||||
test.code = std::move(code);
|
||||
test.initial = {0x11111111u, 0x22222222u, 0x33333333u, 0x44444444u};
|
||||
test.expected = {0x33333333u, 0x44444444u, 0u, 0u};
|
||||
test.storage_buffer_range_dwords = 4;
|
||||
test.storage_buffer_range_bytes = 16;
|
||||
test.opcodes = {O::V_MOV_B32, O::BUFFER_LOAD_DWORDX4, O::BUFFER_STORE_DWORD,
|
||||
O::S_ENDPGM};
|
||||
return test;
|
||||
@@ -26574,7 +26705,7 @@ TestCase BufferStoreDwordx4DropsOnlyOutOfBoundsTail() {
|
||||
test.code = std::move(code);
|
||||
test.initial = {0x11111111u, 0x22222222u, 0x33333333u, 0x44444444u};
|
||||
test.expected = {0x11111111u, 0x22222222u, 0xaaaaaaaau, 0xbbbbbbbbu};
|
||||
test.storage_buffer_range_dwords = 4;
|
||||
test.storage_buffer_range_bytes = 16;
|
||||
test.opcodes = {O::V_MOV_B32, O::BUFFER_STORE_DWORDX4, O::S_ENDPGM};
|
||||
return test;
|
||||
}
|
||||
@@ -26595,7 +26726,7 @@ TestCase BufferLoadFormatXyzwRejectsPartialRecord() {
|
||||
test.code = std::move(code);
|
||||
test.initial = {0x3f800000u, 0x40000000u, 0x40400000u, 0x40800000u};
|
||||
test.expected = {0u, 0u, 0u, 0u};
|
||||
test.storage_buffer_range_dwords = 4;
|
||||
test.storage_buffer_range_bytes = 16;
|
||||
test.user_data = MakeStructuredStorageBufferData(
|
||||
0, 4, false, BufferFormat(Prospero::BufferFormat::k32_32_32_32Float));
|
||||
test.has_user_data = true;
|
||||
@@ -26622,7 +26753,7 @@ TestCase BufferStoreFormatXyzwDropsPartialRecord() {
|
||||
test.code = std::move(code);
|
||||
test.initial = {0x11111111u, 0x22222222u, 0x33333333u, 0x44444444u};
|
||||
test.expected = test.initial;
|
||||
test.storage_buffer_range_dwords = 4;
|
||||
test.storage_buffer_range_bytes = 16;
|
||||
test.user_data = MakeStructuredStorageBufferData(
|
||||
0, 4, false, BufferFormat(Prospero::BufferFormat::k32_32_32_32Float));
|
||||
test.has_user_data = true;
|
||||
@@ -26648,7 +26779,7 @@ TestCase BufferLoadFormatXRejectsPartialRecord() {
|
||||
test.code = std::move(code);
|
||||
test.initial = {0x11111111u, 0x22222222u, 0x33333333u, 0x44444444u};
|
||||
test.expected = {0u, 0u, 0x33333333u, 0x44444444u};
|
||||
test.storage_buffer_range_dwords = 4;
|
||||
test.storage_buffer_range_bytes = 16;
|
||||
test.user_data = MakeStructuredStorageBufferData(
|
||||
0, 16, false, BufferFormat(Prospero::BufferFormat::k32_32_32_32Float));
|
||||
test.has_user_data = true;
|
||||
@@ -26672,7 +26803,7 @@ TestCase BufferStoreFormatXRejectsPartialRecord() {
|
||||
test.code = std::move(code);
|
||||
test.initial = {0x11111111u, 0x22222222u, 0x33333333u, 0x44444444u};
|
||||
test.expected = test.initial;
|
||||
test.storage_buffer_range_dwords = 4;
|
||||
test.storage_buffer_range_bytes = 16;
|
||||
test.user_data = MakeStructuredStorageBufferData(
|
||||
0, 4, false, BufferFormat(Prospero::BufferFormat::k32_32_32_32Float));
|
||||
test.has_user_data = true;
|
||||
@@ -26695,7 +26826,7 @@ TestCase BufferLoadFormatXyRejectsPartialRecord() {
|
||||
test.code = std::move(code);
|
||||
test.initial = {0x11111111u, 0x22222222u, 0x33333333u, 0x44444444u};
|
||||
test.expected = {0u, 0u, 0x33333333u, 0x44444444u};
|
||||
test.storage_buffer_range_dwords = 4;
|
||||
test.storage_buffer_range_bytes = 16;
|
||||
test.user_data = MakeStructuredStorageBufferData(
|
||||
0, 16, false, BufferFormat(Prospero::BufferFormat::k32_32_32_32Float));
|
||||
test.has_user_data = true;
|
||||
@@ -26720,7 +26851,7 @@ TestCase BufferStoreFormatXyRejectsPartialRecord() {
|
||||
test.code = std::move(code);
|
||||
test.initial = {0x11111111u, 0x22222222u, 0x33333333u, 0x44444444u};
|
||||
test.expected = test.initial;
|
||||
test.storage_buffer_range_dwords = 4;
|
||||
test.storage_buffer_range_bytes = 16;
|
||||
test.user_data = MakeStructuredStorageBufferData(
|
||||
0, 4, false, BufferFormat(Prospero::BufferFormat::k32_32_32_32Float));
|
||||
test.has_user_data = true;
|
||||
@@ -27030,7 +27161,7 @@ TestCase BufferStoreFormatXResource16UintPreservesAdjacentLanes() {
|
||||
test.has_compute_info = true;
|
||||
test.user_data = MakeStructuredStorageBufferData(2, 64, false, 11);
|
||||
test.has_user_data = true;
|
||||
test.required_spirv = {"OpAtomicLoad", "OpAtomicCompareExchange"};
|
||||
test.forbidden_spirv = {"OpAtomicLoad", "OpAtomicCompareExchange"};
|
||||
return test;
|
||||
}
|
||||
|
||||
@@ -27383,7 +27514,7 @@ TestCase BufferStoreFormatXDropsOutOfRangeRecord() {
|
||||
test.code = code;
|
||||
test.initial = {0x11111111u, 0x22222222u};
|
||||
test.expected = {0x11111111u, 0x22222222u};
|
||||
test.storage_buffer_range_dwords = 1;
|
||||
test.storage_buffer_range_bytes = 4;
|
||||
test.opcodes = {O::V_MOV_B32, O::BUFFER_STORE_FORMAT_X, O::S_ENDPGM};
|
||||
test.user_data = MakeStructuredStorageBufferData(4, 1, false, 20);
|
||||
test.has_user_data = true;
|
||||
@@ -31534,7 +31665,7 @@ void CheckIndirectBufferStore(VulkanHarness &vulkan) {
|
||||
TestCase test;
|
||||
test.name = "IndirectBufferStore";
|
||||
test.initial.assign(64, 0xdeadbeefu);
|
||||
test.storage_buffer_range_dwords = 16;
|
||||
test.storage_buffer_range_bytes = 64;
|
||||
test.storage_buffer_offsets = {12, 108};
|
||||
test.required_spirv = {"OpSwitch"};
|
||||
test.forbidden_spirv = {"PhysicalStorageBuffer"};
|
||||
@@ -33303,6 +33434,15 @@ std::vector<TestCase> MakeCases() {
|
||||
AddCase(BufferStoreDwordAppliesHostOffset);
|
||||
AddCase(BufferOffsetsUsePackedLaneAndStorageFallback);
|
||||
AddCase(BufferLoadVariants);
|
||||
for (const u32 component : {4u, 2u, 0u}) {
|
||||
cases.push_back(BufferSubwordLoadsAtHostOffset(2, component, false));
|
||||
}
|
||||
cases.push_back(BufferSubwordLoadsAtHostOffset(2, 4, true));
|
||||
cases.push_back(BufferSubwordLoadsAtHostOffset(1, 5, false));
|
||||
cases.push_back(BufferSubwordLoadsAtHostOffset(1, 5, true));
|
||||
AddCase(BufferSubwordHostOffsetOverflow);
|
||||
cases.push_back(BufferSubwordStoresAtHostOffset(2));
|
||||
cases.push_back(BufferSubwordStoresAtHostOffset(1));
|
||||
AddCase(BufferLoadDwordx2SnapshotsOverlappingAddress);
|
||||
AddCase(BufferLoadDwordx3SnapshotsOverlappingAddress);
|
||||
AddCase(BufferLoadDwordx4SnapshotsOverlappingAddress);
|
||||
|
||||
Reference in New Issue
Block a user