spirv-reader: add GetMemoryObjectDeclarationForHandle
Bug: tint:109 Change-Id: Ifb437ce9a39db7f92ca081e7ea551a576b0ecb2b Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/32740 Reviewed-by: David Neto <dneto@google.com> Reviewed-by: dan sinclair <dsinclair@chromium.org> Commit-Queue: David Neto <dneto@google.com> Auto-Submit: David Neto <dneto@google.com>
This commit is contained in:
parent
0ae939bc0c
commit
cebde298f9
1
BUILD.gn
1
BUILD.gn
|
@ -846,6 +846,7 @@ source_set("tint_unittests_spv_reader_src") {
|
|||
"src/reader/spirv/parser_impl_convert_type_test.cc",
|
||||
"src/reader/spirv/parser_impl_function_decl_test.cc",
|
||||
"src/reader/spirv/parser_impl_get_decorations_test.cc",
|
||||
"src/reader/spirv/parser_impl_handle_test.cc",
|
||||
"src/reader/spirv/parser_impl_import_test.cc",
|
||||
"src/reader/spirv/parser_impl_module_var_test.cc",
|
||||
"src/reader/spirv/parser_impl_named_types_test.cc",
|
||||
|
|
|
@ -450,6 +450,7 @@ if(${TINT_BUILD_SPV_READER})
|
|||
reader/spirv/parser_impl_convert_type_test.cc
|
||||
reader/spirv/parser_impl_function_decl_test.cc
|
||||
reader/spirv/parser_impl_get_decorations_test.cc
|
||||
reader/spirv/parser_impl_handle_test.cc
|
||||
reader/spirv/parser_impl_import_test.cc
|
||||
reader/spirv/parser_impl_module_var_test.cc
|
||||
reader/spirv/parser_impl_named_types_test.cc
|
||||
|
|
|
@ -1503,6 +1503,88 @@ bool ParserImpl::EmitFunctions() {
|
|||
return success_;
|
||||
}
|
||||
|
||||
const spvtools::opt::Instruction*
|
||||
ParserImpl::GetMemoryObjectDeclarationForHandle(uint32_t id,
|
||||
bool follow_image) {
|
||||
auto local_fail = [this, id,
|
||||
follow_image]() -> const spvtools::opt::Instruction* {
|
||||
const auto* inst = def_use_mgr_->GetDef(id);
|
||||
Fail() << "Could not find memory object declaration for the "
|
||||
<< (follow_image ? "image" : "sampler") << " underlying id " << id
|
||||
<< (inst ? inst->PrettyPrint() : std::string());
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
auto& memo_table =
|
||||
(follow_image ? mem_obj_decl_image_ : mem_obj_decl_sampler_);
|
||||
|
||||
// Use a visited set to defend against bad input which might have long
|
||||
// chains or even loops.
|
||||
std::unordered_set<uint32_t> visited;
|
||||
|
||||
// Trace backward in the SSA data flow until we hit a memory object
|
||||
// declaration.
|
||||
while (true) {
|
||||
auto where = memo_table.find(id);
|
||||
if (where != memo_table.end()) {
|
||||
return where->second;
|
||||
}
|
||||
// Protect against loops.
|
||||
auto visited_iter = visited.find(id);
|
||||
if (visited_iter != visited.end()) {
|
||||
// We've hit a loop. Mark all the visited nodes
|
||||
// as dead ends.
|
||||
for (auto iter : visited) {
|
||||
memo_table[iter] = nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
visited.insert(id);
|
||||
|
||||
const auto* inst = def_use_mgr_->GetDef(id);
|
||||
if (inst == nullptr) {
|
||||
return local_fail();
|
||||
}
|
||||
switch (inst->opcode()) {
|
||||
case SpvOpFunctionParameter:
|
||||
case SpvOpVariable:
|
||||
// We found the memory object declaration.
|
||||
// Remember it as the answer for the whole path.
|
||||
for (auto iter : visited) {
|
||||
memo_table[iter] = inst;
|
||||
}
|
||||
return inst;
|
||||
case SpvOpLoad:
|
||||
// Follow the pointer being loaded
|
||||
id = inst->GetSingleWordInOperand(0);
|
||||
break;
|
||||
case SpvOpCopyObject:
|
||||
// Follow the object being copied.
|
||||
id = inst->GetSingleWordInOperand(0);
|
||||
break;
|
||||
case SpvOpAccessChain:
|
||||
case SpvOpInBoundsAccessChain:
|
||||
case SpvOpPtrAccessChain:
|
||||
case SpvOpInBoundsPtrAccessChain:
|
||||
// Follow the base pointer.
|
||||
id = inst->GetSingleWordInOperand(0);
|
||||
break;
|
||||
case SpvOpSampledImage:
|
||||
// Follow the image or the sampler, depending on the follow_image
|
||||
// parameter.
|
||||
id = inst->GetSingleWordInOperand(follow_image ? 0 : 1);
|
||||
break;
|
||||
case SpvOpImage:
|
||||
// Follow the sampled image
|
||||
id = inst->GetSingleWordInOperand(0);
|
||||
break;
|
||||
default:
|
||||
// This is not valid.
|
||||
return local_fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace spirv
|
||||
} // namespace reader
|
||||
} // namespace tint
|
||||
|
|
|
@ -375,6 +375,22 @@ class ParserImpl : Reader {
|
|||
return scalar_spec_constants_.find(id) != scalar_spec_constants_.end();
|
||||
}
|
||||
|
||||
/// For a SPIR-V ID that defines a sampler, image, or sampled image value,
|
||||
/// return the SPIR-V instruction that represents the memory object
|
||||
/// declaration for the object. If we encounter an OpSampledImage along the
|
||||
/// way, follow the image operand when follow_image is true; otherwise follow
|
||||
/// the sampler operand. Returns null and emits an error if it can't trace
|
||||
/// back to a memory object declaration.
|
||||
/// This method can be used any time after BuildInternalModule has been
|
||||
/// invoked.
|
||||
/// @param id the SPIR-V ID of the sampler, image, or sampled image
|
||||
/// @param follow_image indicates whether to follow the image operand of
|
||||
/// OpSampledImage
|
||||
/// @returns the memory object declaration for the handle, or nullptr on error
|
||||
const spvtools::opt::Instruction* GetMemoryObjectDeclarationForHandle(
|
||||
uint32_t id,
|
||||
bool follow_image);
|
||||
|
||||
private:
|
||||
/// Converts a specific SPIR-V type to a Tint type. Integer case
|
||||
ast::type::Type* ConvertType(const spvtools::opt::analysis::Integer* int_ty);
|
||||
|
@ -497,6 +513,18 @@ class ParserImpl : Reader {
|
|||
// Maps function_id to a list of entrypoint information
|
||||
std::unordered_map<uint32_t, std::vector<EntryPointInfo>>
|
||||
function_to_ep_info_;
|
||||
|
||||
// Maps from a SPIR-V ID to its underlying memory object declaration,
|
||||
// following image paths. This a memoization table for
|
||||
// GetMemoryObjectDeclarationForHandle. (A SPIR-V memory object declaration is
|
||||
// an OpVariable or an OpFunctinParameter with pointer type).
|
||||
std::unordered_map<uint32_t, const spvtools::opt::Instruction*>
|
||||
mem_obj_decl_image_;
|
||||
// Maps from a SPIR-V ID to its underlying memory object declaration,
|
||||
// following sampler paths. This a memoization table for
|
||||
// GetMemoryObjectDeclarationForHandle.
|
||||
std::unordered_map<uint32_t, const spvtools::opt::Instruction*>
|
||||
mem_obj_decl_sampler_;
|
||||
};
|
||||
|
||||
} // namespace spirv
|
||||
|
|
|
@ -0,0 +1,749 @@
|
|||
// Copyright 2020 The Tint Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "src/reader/spirv/function.h"
|
||||
#include "src/reader/spirv/parser_impl.h"
|
||||
#include "src/reader/spirv/parser_impl_test_helper.h"
|
||||
#include "src/reader/spirv/spirv_tools_helpers_test.h"
|
||||
|
||||
namespace tint {
|
||||
namespace reader {
|
||||
namespace spirv {
|
||||
namespace {
|
||||
|
||||
using ::testing::Eq;
|
||||
using ::testing::HasSubstr;
|
||||
using ::testing::Not;
|
||||
|
||||
std::string Preamble() {
|
||||
return R"(
|
||||
OpCapability Shader
|
||||
OpCapability Sampled1D
|
||||
OpCapability Image1D
|
||||
OpCapability StorageImageExtendedFormats
|
||||
OpMemoryModel Logical Simple
|
||||
)";
|
||||
}
|
||||
|
||||
std::string CommonTypes() {
|
||||
return R"(
|
||||
%void = OpTypeVoid
|
||||
%voidfn = OpTypeFunction %void
|
||||
|
||||
%float = OpTypeFloat 32
|
||||
%uint = OpTypeInt 32 0
|
||||
%int = OpTypeInt 32 1
|
||||
|
||||
%uint_1 = OpConstant %uint 1
|
||||
%uint_2 = OpConstant %uint 2
|
||||
%uint_100 = OpConstant %uint 100
|
||||
|
||||
%v4uint = OpTypeVector %uint 4
|
||||
%v4int = OpTypeVector %int 4
|
||||
%v4float = OpTypeVector %float 4
|
||||
|
||||
; Define types for all sampler and texture types that can map to WGSL,
|
||||
; modulo texel formats for storage textures. For now, we limit
|
||||
; ourselves to 2-channel 32-bit texel formats.
|
||||
|
||||
; Because the SPIR-V reader also already generalizes so it can work with
|
||||
; combined image-samplers, we also test that too.
|
||||
|
||||
%sampler = OpTypeSampler
|
||||
|
||||
; sampled images
|
||||
%f_texture_1d = OpTypeImage %float 1D 0 0 0 1 Unknown
|
||||
%f_texture_1d_array = OpTypeImage %float 1D 0 1 0 1 Unknown
|
||||
%f_texture_2d = OpTypeImage %float 2D 0 0 0 1 Unknown
|
||||
%f_texture_2d_ms = OpTypeImage %float 2D 0 0 1 1 Unknown
|
||||
%f_texture_2d_array = OpTypeImage %float 2D 0 1 0 1 Unknown
|
||||
%f_texture_2d_ms_array = OpTypeImage %float 2D 0 1 1 1 Unknown ; not in WebGPU
|
||||
%f_texture_3d = OpTypeImage %float 3D 0 0 0 1 Unknown
|
||||
%f_texture_cube = OpTypeImage %float Cube 0 0 0 1 Unknown
|
||||
%f_texture_cube_array = OpTypeImage %float Cube 0 1 0 1 Unknown
|
||||
|
||||
; storage images
|
||||
%f_storage_1d = OpTypeImage %float 1D 0 0 0 1 Rg32f
|
||||
%f_storage_1d_array = OpTypeImage %float 1D 0 1 0 1 Rg32f
|
||||
%f_storage_2d = OpTypeImage %float 2D 0 0 0 1 Rg32f
|
||||
%f_storage_2d_array = OpTypeImage %float 2D 0 1 0 1 Rg32f
|
||||
%f_storage_3d = OpTypeImage %float 3D 0 0 0 1 Rg32f
|
||||
|
||||
; Now all the same, but for unsigned integer sampled type.
|
||||
|
||||
%u_texture_1d = OpTypeImage %uint 1D 0 0 0 1 Unknown
|
||||
%u_texture_1d_array = OpTypeImage %uint 1D 0 1 0 1 Unknown
|
||||
%u_texture_2d = OpTypeImage %uint 2D 0 0 0 1 Unknown
|
||||
%u_texture_2d_ms = OpTypeImage %uint 2D 0 0 1 1 Unknown
|
||||
%u_texture_2d_array = OpTypeImage %uint 2D 0 1 0 1 Unknown
|
||||
%u_texture_2d_ms_array = OpTypeImage %uint 2D 0 1 1 1 Unknown ; not in WebGPU
|
||||
%u_texture_3d = OpTypeImage %uint 3D 0 0 0 1 Unknown
|
||||
%u_texture_cube = OpTypeImage %uint Cube 0 0 0 1 Unknown
|
||||
%u_texture_cube_array = OpTypeImage %uint Cube 0 1 0 1 Unknown
|
||||
|
||||
%u_storage_1d = OpTypeImage %uint 1D 0 0 0 1 Rg32ui
|
||||
%u_storage_1d_array = OpTypeImage %uint 1D 0 1 0 1 Rg32ui
|
||||
%u_storage_2d = OpTypeImage %uint 2D 0 0 0 1 Rg32ui
|
||||
%u_storage_2d_array = OpTypeImage %uint 2D 0 1 0 1 Rg32ui
|
||||
%u_storage_3d = OpTypeImage %uint 3D 0 0 0 1 Rg32ui
|
||||
|
||||
; Now all the same, but for signed integer sampled type.
|
||||
|
||||
%i_texture_1d = OpTypeImage %int 1D 0 0 0 1 Unknown
|
||||
%i_texture_1d_array = OpTypeImage %int 1D 0 1 0 1 Unknown
|
||||
%i_texture_2d = OpTypeImage %int 2D 0 0 0 1 Unknown
|
||||
%i_texture_2d_ms = OpTypeImage %int 2D 0 0 1 1 Unknown
|
||||
%i_texture_2d_array = OpTypeImage %int 2D 0 1 0 1 Unknown
|
||||
%i_texture_2d_ms_array = OpTypeImage %int 2D 0 1 1 1 Unknown ; not in WebGPU
|
||||
%i_texture_3d = OpTypeImage %int 3D 0 0 0 1 Unknown
|
||||
%i_texture_cube = OpTypeImage %int Cube 0 0 0 1 Unknown
|
||||
%i_texture_cube_array = OpTypeImage %int Cube 0 1 0 1 Unknown
|
||||
|
||||
%i_storage_1d = OpTypeImage %int 1D 0 0 0 1 Rg32i
|
||||
%i_storage_1d_array = OpTypeImage %int 1D 0 1 0 1 Rg32i
|
||||
%i_storage_2d = OpTypeImage %int 2D 0 0 0 1 Rg32i
|
||||
%i_storage_2d_array = OpTypeImage %int 2D 0 1 0 1 Rg32i
|
||||
%i_storage_3d = OpTypeImage %int 3D 0 0 0 1 Rg32i
|
||||
|
||||
;; Now pointers to each of the above, so we can declare variables for them.
|
||||
|
||||
%ptr_sampler = OpTypePointer UniformConstant %sampler
|
||||
|
||||
%ptr_f_texture_1d = OpTypePointer UniformConstant %f_texture_1d
|
||||
%ptr_f_texture_1d_array = OpTypePointer UniformConstant %f_texture_1d_array
|
||||
%ptr_f_texture_2d = OpTypePointer UniformConstant %f_texture_2d
|
||||
%ptr_f_texture_2d_ms = OpTypePointer UniformConstant %f_texture_2d_ms
|
||||
%ptr_f_texture_2d_array = OpTypePointer UniformConstant %f_texture_2d_array
|
||||
%ptr_f_texture_2d_ms_array = OpTypePointer UniformConstant %f_texture_2d_ms_array
|
||||
%ptr_f_texture_3d = OpTypePointer UniformConstant %f_texture_3d
|
||||
%ptr_f_texture_cube = OpTypePointer UniformConstant %f_texture_cube
|
||||
%ptr_f_texture_cube_array = OpTypePointer UniformConstant %f_texture_cube_array
|
||||
|
||||
; storage images
|
||||
%ptr_f_storage_1d = OpTypePointer UniformConstant %f_storage_1d
|
||||
%ptr_f_storage_1d_array = OpTypePointer UniformConstant %f_storage_1d_array
|
||||
%ptr_f_storage_2d = OpTypePointer UniformConstant %f_storage_2d
|
||||
%ptr_f_storage_2d_array = OpTypePointer UniformConstant %f_storage_2d_array
|
||||
%ptr_f_storage_3d = OpTypePointer UniformConstant %f_storage_3d
|
||||
|
||||
; Now all the same, but for unsigned integer sampled type.
|
||||
|
||||
%ptr_u_texture_1d = OpTypePointer UniformConstant %u_texture_1d
|
||||
%ptr_u_texture_1d_array = OpTypePointer UniformConstant %u_texture_1d_array
|
||||
%ptr_u_texture_2d = OpTypePointer UniformConstant %u_texture_2d
|
||||
%ptr_u_texture_2d_ms = OpTypePointer UniformConstant %u_texture_2d_ms
|
||||
%ptr_u_texture_2d_array = OpTypePointer UniformConstant %u_texture_2d_array
|
||||
%ptr_u_texture_2d_ms_array = OpTypePointer UniformConstant %u_texture_2d_ms_array
|
||||
%ptr_u_texture_3d = OpTypePointer UniformConstant %u_texture_3d
|
||||
%ptr_u_texture_cube = OpTypePointer UniformConstant %u_texture_cube
|
||||
%ptr_u_texture_cube_array = OpTypePointer UniformConstant %u_texture_cube_array
|
||||
|
||||
%ptr_u_storage_1d = OpTypePointer UniformConstant %u_storage_1d
|
||||
%ptr_u_storage_1d_array = OpTypePointer UniformConstant %u_storage_1d_array
|
||||
%ptr_u_storage_2d = OpTypePointer UniformConstant %u_storage_2d
|
||||
%ptr_u_storage_2d_array = OpTypePointer UniformConstant %u_storage_2d_array
|
||||
%ptr_u_storage_3d = OpTypePointer UniformConstant %u_storage_3d
|
||||
|
||||
; Now all the same, but for signed integer sampled type.
|
||||
|
||||
%ptr_i_texture_1d = OpTypePointer UniformConstant %i_texture_1d
|
||||
%ptr_i_texture_1d_array = OpTypePointer UniformConstant %i_texture_1d_array
|
||||
%ptr_i_texture_2d = OpTypePointer UniformConstant %i_texture_2d
|
||||
%ptr_i_texture_2d_ms = OpTypePointer UniformConstant %i_texture_2d_ms
|
||||
%ptr_i_texture_2d_array = OpTypePointer UniformConstant %i_texture_2d_array
|
||||
%ptr_i_texture_2d_ms_array = OpTypePointer UniformConstant %i_texture_2d_ms_array
|
||||
%ptr_i_texture_3d = OpTypePointer UniformConstant %i_texture_3d
|
||||
%ptr_i_texture_cube = OpTypePointer UniformConstant %i_texture_cube
|
||||
%ptr_i_texture_cube_array = OpTypePointer UniformConstant %i_texture_cube_array
|
||||
|
||||
%ptr_i_storage_1d = OpTypePointer UniformConstant %i_storage_1d
|
||||
%ptr_i_storage_1d_array = OpTypePointer UniformConstant %i_storage_1d_array
|
||||
%ptr_i_storage_2d = OpTypePointer UniformConstant %i_storage_2d
|
||||
%ptr_i_storage_2d_array = OpTypePointer UniformConstant %i_storage_2d_array
|
||||
%ptr_i_storage_3d = OpTypePointer UniformConstant %i_storage_3d
|
||||
|
||||
)";
|
||||
}
|
||||
|
||||
TEST_F(SpvParserTest, GetMemoryObjectDeclarationForHandle_Variable_Direct) {
|
||||
const auto assembly = Preamble() + CommonTypes() + R"(
|
||||
%10 = OpVariable %ptr_sampler UniformConstant
|
||||
%20 = OpVariable %ptr_f_texture_1d UniformConstant
|
||||
)";
|
||||
auto* p = parser(test::Assemble(assembly));
|
||||
ASSERT_TRUE(p->BuildInternalModule());
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
const auto* sampler = p->GetMemoryObjectDeclarationForHandle(10, false);
|
||||
const auto* image = p->GetMemoryObjectDeclarationForHandle(20, true);
|
||||
|
||||
ASSERT_TRUE(sampler != nullptr);
|
||||
EXPECT_EQ(sampler->result_id(), 10u);
|
||||
|
||||
ASSERT_TRUE(image != nullptr);
|
||||
EXPECT_EQ(image->result_id(), 20u);
|
||||
}
|
||||
|
||||
TEST_F(SpvParserTest,
|
||||
GetMemoryObjectDeclarationForHandle_Variable_AccessChain) {
|
||||
// Show that we would generalize to arrays of handles, even though that
|
||||
// is not supported in WGSL MVP.
|
||||
const auto assembly = Preamble() + CommonTypes() + R"(
|
||||
|
||||
%sampler_array = OpTypeArray %sampler %uint_100
|
||||
%image_array = OpTypeArray %f_texture_1d %uint_100
|
||||
|
||||
%ptr_sampler_array = OpTypePointer UniformConstant %sampler_array
|
||||
%ptr_image_array = OpTypePointer UniformConstant %image_array
|
||||
|
||||
%10 = OpVariable %ptr_sampler_array UniformConstant
|
||||
%20 = OpVariable %ptr_image_array UniformConstant
|
||||
|
||||
%main = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
|
||||
%110 = OpAccessChain %ptr_sampler %10 %uint_1
|
||||
%120 = OpAccessChain %ptr_f_texture_1d %20 %uint_2
|
||||
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
auto* p = parser(test::Assemble(assembly));
|
||||
ASSERT_TRUE(p->BuildInternalModule());
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
|
||||
const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
|
||||
|
||||
ASSERT_TRUE(sampler != nullptr);
|
||||
EXPECT_EQ(sampler->result_id(), 10u);
|
||||
|
||||
ASSERT_TRUE(image != nullptr);
|
||||
EXPECT_EQ(image->result_id(), 20u);
|
||||
}
|
||||
|
||||
TEST_F(SpvParserTest,
|
||||
GetMemoryObjectDeclarationForHandle_Variable_InBoundsAccessChain) {
|
||||
const auto assembly = Preamble() + CommonTypes() + R"(
|
||||
|
||||
%sampler_array = OpTypeArray %sampler %uint_100
|
||||
%image_array = OpTypeArray %f_texture_1d %uint_100
|
||||
|
||||
%ptr_sampler_array = OpTypePointer UniformConstant %sampler_array
|
||||
%ptr_image_array = OpTypePointer UniformConstant %image_array
|
||||
|
||||
%10 = OpVariable %ptr_sampler_array UniformConstant
|
||||
%20 = OpVariable %ptr_image_array UniformConstant
|
||||
|
||||
%main = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
|
||||
%110 = OpInBoundsAccessChain %ptr_sampler %10 %uint_1
|
||||
%120 = OpInBoundsAccessChain %ptr_f_texture_1d %20 %uint_2
|
||||
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
auto* p = parser(test::Assemble(assembly));
|
||||
ASSERT_TRUE(p->BuildInternalModule());
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
|
||||
const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
|
||||
|
||||
ASSERT_TRUE(sampler != nullptr);
|
||||
EXPECT_EQ(sampler->result_id(), 10u);
|
||||
|
||||
ASSERT_TRUE(image != nullptr);
|
||||
EXPECT_EQ(image->result_id(), 20u);
|
||||
}
|
||||
|
||||
TEST_F(SpvParserTest,
|
||||
GetMemoryObjectDeclarationForHandle_Variable_PtrAccessChain) {
|
||||
// Show that we would generalize to arrays of handles, even though that
|
||||
// is not supported in WGSL MVP.
|
||||
const auto assembly = Preamble() + CommonTypes() + R"(
|
||||
|
||||
%sampler_array = OpTypeArray %sampler %uint_100
|
||||
%image_array = OpTypeArray %f_texture_1d %uint_100
|
||||
|
||||
%ptr_sampler_array = OpTypePointer UniformConstant %sampler_array
|
||||
%ptr_image_array = OpTypePointer UniformConstant %image_array
|
||||
|
||||
%10 = OpVariable %ptr_sampler_array UniformConstant
|
||||
%20 = OpVariable %ptr_image_array UniformConstant
|
||||
|
||||
%main = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
|
||||
%110 = OpPtrAccessChain %ptr_sampler %10 %uint_1 %uint_1
|
||||
%120 = OpPtrAccessChain %ptr_f_texture_1d %20 %uint_1 %uint_2
|
||||
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
auto* p = parser(test::Assemble(assembly));
|
||||
ASSERT_TRUE(p->BuildInternalModule());
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
|
||||
const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
|
||||
|
||||
ASSERT_TRUE(sampler != nullptr);
|
||||
EXPECT_EQ(sampler->result_id(), 10u);
|
||||
|
||||
ASSERT_TRUE(image != nullptr);
|
||||
EXPECT_EQ(image->result_id(), 20u);
|
||||
}
|
||||
|
||||
TEST_F(SpvParserTest,
|
||||
GetMemoryObjectDeclarationForHandle_Variable_InBoundsPtrAccessChain) {
|
||||
const auto assembly = Preamble() + CommonTypes() + R"(
|
||||
|
||||
%sampler_array = OpTypeArray %sampler %uint_100
|
||||
%image_array = OpTypeArray %f_texture_1d %uint_100
|
||||
|
||||
%ptr_sampler_array = OpTypePointer UniformConstant %sampler_array
|
||||
%ptr_image_array = OpTypePointer UniformConstant %image_array
|
||||
|
||||
%10 = OpVariable %ptr_sampler_array UniformConstant
|
||||
%20 = OpVariable %ptr_image_array UniformConstant
|
||||
|
||||
%main = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
|
||||
%110 = OpInBoundsPtrAccessChain %ptr_sampler %10 %uint_1 %uint_1
|
||||
%120 = OpInBoundsPtrAccessChain %ptr_f_texture_1d %20 %uint_1 %uint_2
|
||||
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
auto* p = parser(test::Assemble(assembly));
|
||||
ASSERT_TRUE(p->BuildInternalModule());
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
|
||||
const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
|
||||
|
||||
ASSERT_TRUE(sampler != nullptr);
|
||||
EXPECT_EQ(sampler->result_id(), 10u);
|
||||
|
||||
ASSERT_TRUE(image != nullptr);
|
||||
EXPECT_EQ(image->result_id(), 20u);
|
||||
}
|
||||
|
||||
TEST_F(SpvParserTest, GetMemoryObjectDeclarationForHandle_Variable_CopyObject) {
|
||||
const auto assembly = Preamble() + CommonTypes() + R"(
|
||||
|
||||
%10 = OpVariable %ptr_sampler UniformConstant
|
||||
%20 = OpVariable %ptr_f_texture_1d UniformConstant
|
||||
|
||||
%main = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
|
||||
%110 = OpCopyObject %ptr_sampler %10
|
||||
%120 = OpCopyObject %ptr_f_texture_1d %20
|
||||
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
auto* p = parser(test::Assemble(assembly));
|
||||
ASSERT_TRUE(p->BuildInternalModule());
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
|
||||
const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
|
||||
|
||||
ASSERT_TRUE(sampler != nullptr);
|
||||
EXPECT_EQ(sampler->result_id(), 10u);
|
||||
|
||||
ASSERT_TRUE(image != nullptr);
|
||||
EXPECT_EQ(image->result_id(), 20u);
|
||||
}
|
||||
|
||||
TEST_F(SpvParserTest, GetMemoryObjectDeclarationForHandle_Variable_Load) {
|
||||
const auto assembly = Preamble() + CommonTypes() + R"(
|
||||
|
||||
%10 = OpVariable %ptr_sampler UniformConstant
|
||||
%20 = OpVariable %ptr_f_texture_1d UniformConstant
|
||||
|
||||
%main = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
|
||||
%110 = OpLoad %sampler %10
|
||||
%120 = OpLoad %f_texture_1d %20
|
||||
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
auto* p = parser(test::Assemble(assembly));
|
||||
ASSERT_TRUE(p->BuildInternalModule());
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
|
||||
const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
|
||||
|
||||
ASSERT_TRUE(sampler != nullptr);
|
||||
EXPECT_EQ(sampler->result_id(), 10u);
|
||||
|
||||
ASSERT_TRUE(image != nullptr);
|
||||
EXPECT_EQ(image->result_id(), 20u);
|
||||
}
|
||||
|
||||
TEST_F(SpvParserTest,
|
||||
GetMemoryObjectDeclarationForHandle_Variable_SampledImage) {
|
||||
// Trace through the sampled image instruction, but in two different
|
||||
// directions.
|
||||
const auto assembly = Preamble() + CommonTypes() + R"(
|
||||
%sampled_image_type = OpTypeSampledImage %f_texture_1d
|
||||
|
||||
%10 = OpVariable %ptr_sampler UniformConstant
|
||||
%20 = OpVariable %ptr_f_texture_1d UniformConstant
|
||||
|
||||
%main = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
|
||||
%s = OpLoad %sampler %10
|
||||
%im = OpLoad %f_texture_1d %20
|
||||
%100 = OpSampledImage %sampled_image_type %im %s
|
||||
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
auto* p = parser(test::Assemble(assembly));
|
||||
ASSERT_TRUE(p->BuildInternalModule());
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
const auto* sampler = p->GetMemoryObjectDeclarationForHandle(100, false);
|
||||
const auto* image = p->GetMemoryObjectDeclarationForHandle(100, true);
|
||||
|
||||
ASSERT_TRUE(sampler != nullptr);
|
||||
EXPECT_EQ(sampler->result_id(), 10u);
|
||||
|
||||
ASSERT_TRUE(image != nullptr);
|
||||
EXPECT_EQ(image->result_id(), 20u);
|
||||
}
|
||||
|
||||
TEST_F(SpvParserTest, GetMemoryObjectDeclarationForHandle_Variable_Image) {
|
||||
const auto assembly = Preamble() + CommonTypes() + R"(
|
||||
%sampled_image_type = OpTypeSampledImage %f_texture_1d
|
||||
|
||||
%10 = OpVariable %ptr_sampler UniformConstant
|
||||
%20 = OpVariable %ptr_f_texture_1d UniformConstant
|
||||
|
||||
%main = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
|
||||
%s = OpLoad %sampler %10
|
||||
%im = OpLoad %f_texture_1d %20
|
||||
%100 = OpSampledImage %sampled_image_type %im %s
|
||||
%200 = OpImage %im %100
|
||||
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
auto* p = parser(test::Assemble(assembly));
|
||||
ASSERT_TRUE(p->BuildInternalModule());
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
|
||||
const auto* image = p->GetMemoryObjectDeclarationForHandle(200, true);
|
||||
ASSERT_TRUE(image != nullptr);
|
||||
EXPECT_EQ(image->result_id(), 20u);
|
||||
}
|
||||
|
||||
TEST_F(SpvParserTest, GetMemoryObjectDeclarationForHandle_FuncParam_Direct) {
|
||||
const auto assembly = Preamble() + CommonTypes() + R"(
|
||||
%fty = OpTypeFunction %void %ptr_sampler %ptr_f_texture_1d
|
||||
|
||||
%func = OpFunction %void None %fty
|
||||
%10 = OpFunctionParameter %ptr_sampler
|
||||
%20 = OpFunctionParameter %ptr_f_texture_1d
|
||||
%entry = OpLabel
|
||||
OpReturn
|
||||
)";
|
||||
auto* p = parser(test::Assemble(assembly));
|
||||
ASSERT_TRUE(p->BuildInternalModule());
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
const auto* sampler = p->GetMemoryObjectDeclarationForHandle(10, false);
|
||||
const auto* image = p->GetMemoryObjectDeclarationForHandle(20, true);
|
||||
|
||||
ASSERT_TRUE(sampler != nullptr);
|
||||
EXPECT_EQ(sampler->result_id(), 10u);
|
||||
|
||||
ASSERT_TRUE(image != nullptr);
|
||||
EXPECT_EQ(image->result_id(), 20u);
|
||||
}
|
||||
|
||||
TEST_F(SpvParserTest,
|
||||
GetMemoryObjectDeclarationForHandle_FuncParam_AccessChain) {
|
||||
// Show that we would generalize to arrays of handles, even though that
|
||||
// is not supported in WGSL MVP.
|
||||
const auto assembly = Preamble() + CommonTypes() + R"(
|
||||
%sampler_array = OpTypeArray %sampler %uint_100
|
||||
%image_array = OpTypeArray %f_texture_1d %uint_100
|
||||
|
||||
%ptr_sampler_array = OpTypePointer UniformConstant %sampler_array
|
||||
%ptr_image_array = OpTypePointer UniformConstant %image_array
|
||||
|
||||
%fty = OpTypeFunction %void %ptr_sampler_array %ptr_image_array
|
||||
|
||||
%func = OpFunction %void None %fty
|
||||
%10 = OpFunctionParameter %ptr_sampler_array
|
||||
%20 = OpFunctionParameter %ptr_image_array
|
||||
%entry = OpLabel
|
||||
|
||||
%110 = OpAccessChain %ptr_sampler %10 %uint_1
|
||||
%120 = OpAccessChain %ptr_f_texture_1d %20 %uint_2
|
||||
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
auto* p = parser(test::Assemble(assembly));
|
||||
ASSERT_TRUE(p->BuildInternalModule());
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
|
||||
const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
|
||||
|
||||
ASSERT_TRUE(sampler != nullptr);
|
||||
EXPECT_EQ(sampler->result_id(), 10u);
|
||||
|
||||
ASSERT_TRUE(image != nullptr);
|
||||
EXPECT_EQ(image->result_id(), 20u);
|
||||
}
|
||||
|
||||
TEST_F(SpvParserTest,
|
||||
GetMemoryObjectDeclarationForHandle_FuncParam_InBoundsAccessChain) {
|
||||
const auto assembly = Preamble() + CommonTypes() + R"(
|
||||
%sampler_array = OpTypeArray %sampler %uint_100
|
||||
%image_array = OpTypeArray %f_texture_1d %uint_100
|
||||
|
||||
%ptr_sampler_array = OpTypePointer UniformConstant %sampler_array
|
||||
%ptr_image_array = OpTypePointer UniformConstant %image_array
|
||||
|
||||
%fty = OpTypeFunction %void %ptr_sampler_array %ptr_image_array
|
||||
|
||||
%func = OpFunction %void None %fty
|
||||
%10 = OpFunctionParameter %ptr_sampler_array
|
||||
%20 = OpFunctionParameter %ptr_image_array
|
||||
%entry = OpLabel
|
||||
|
||||
%110 = OpInBoundsAccessChain %ptr_sampler %10 %uint_1
|
||||
%120 = OpInBoundsAccessChain %ptr_f_texture_1d %20 %uint_2
|
||||
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
auto* p = parser(test::Assemble(assembly));
|
||||
ASSERT_TRUE(p->BuildInternalModule());
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
|
||||
const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
|
||||
|
||||
ASSERT_TRUE(sampler != nullptr);
|
||||
EXPECT_EQ(sampler->result_id(), 10u);
|
||||
|
||||
ASSERT_TRUE(image != nullptr);
|
||||
EXPECT_EQ(image->result_id(), 20u);
|
||||
}
|
||||
|
||||
TEST_F(SpvParserTest,
|
||||
GetMemoryObjectDeclarationForHandle_FuncParam_PtrAccessChain) {
|
||||
// Show that we would generalize to arrays of handles, even though that
|
||||
// is not supported in WGSL MVP.
|
||||
const auto assembly = Preamble() + CommonTypes() + R"(
|
||||
%sampler_array = OpTypeArray %sampler %uint_100
|
||||
%image_array = OpTypeArray %f_texture_1d %uint_100
|
||||
|
||||
%ptr_sampler_array = OpTypePointer UniformConstant %sampler_array
|
||||
%ptr_image_array = OpTypePointer UniformConstant %image_array
|
||||
|
||||
%fty = OpTypeFunction %void %ptr_sampler_array %ptr_image_array
|
||||
|
||||
%func = OpFunction %void None %fty
|
||||
%10 = OpFunctionParameter %ptr_sampler_array
|
||||
%20 = OpFunctionParameter %ptr_image_array
|
||||
%entry = OpLabel
|
||||
|
||||
%110 = OpPtrAccessChain %ptr_sampler %10 %uint_1 %uint_1
|
||||
%120 = OpPtrAccessChain %ptr_f_texture_1d %20 %uint_1 %uint_2
|
||||
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
auto* p = parser(test::Assemble(assembly));
|
||||
ASSERT_TRUE(p->BuildInternalModule());
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
|
||||
const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
|
||||
|
||||
ASSERT_TRUE(sampler != nullptr);
|
||||
EXPECT_EQ(sampler->result_id(), 10u);
|
||||
|
||||
ASSERT_TRUE(image != nullptr);
|
||||
EXPECT_EQ(image->result_id(), 20u);
|
||||
}
|
||||
|
||||
TEST_F(SpvParserTest,
|
||||
GetMemoryObjectDeclarationForHandle_FuncParam_InBoundsPtrAccessChain) {
|
||||
const auto assembly = Preamble() + CommonTypes() + R"(
|
||||
%sampler_array = OpTypeArray %sampler %uint_100
|
||||
%image_array = OpTypeArray %f_texture_1d %uint_100
|
||||
|
||||
%ptr_sampler_array = OpTypePointer UniformConstant %sampler_array
|
||||
%ptr_image_array = OpTypePointer UniformConstant %image_array
|
||||
|
||||
%fty = OpTypeFunction %void %ptr_sampler_array %ptr_image_array
|
||||
|
||||
%func = OpFunction %void None %fty
|
||||
%10 = OpFunctionParameter %ptr_sampler_array
|
||||
%20 = OpFunctionParameter %ptr_image_array
|
||||
%entry = OpLabel
|
||||
|
||||
%110 = OpInBoundsPtrAccessChain %ptr_sampler %10 %uint_1 %uint_1
|
||||
%120 = OpInBoundsPtrAccessChain %ptr_f_texture_1d %20 %uint_1 %uint_2
|
||||
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
auto* p = parser(test::Assemble(assembly));
|
||||
ASSERT_TRUE(p->BuildInternalModule());
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
|
||||
const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
|
||||
|
||||
ASSERT_TRUE(sampler != nullptr);
|
||||
EXPECT_EQ(sampler->result_id(), 10u);
|
||||
|
||||
ASSERT_TRUE(image != nullptr);
|
||||
EXPECT_EQ(image->result_id(), 20u);
|
||||
}
|
||||
|
||||
TEST_F(SpvParserTest,
|
||||
GetMemoryObjectDeclarationForHandle_FuncParam_CopyObject) {
|
||||
const auto assembly = Preamble() + CommonTypes() + R"(
|
||||
%fty = OpTypeFunction %void %ptr_sampler %ptr_f_texture_1d
|
||||
|
||||
%func = OpFunction %void None %fty
|
||||
%10 = OpFunctionParameter %ptr_sampler
|
||||
%20 = OpFunctionParameter %ptr_f_texture_1d
|
||||
%entry = OpLabel
|
||||
|
||||
%110 = OpCopyObject %ptr_sampler %10
|
||||
%120 = OpCopyObject %ptr_f_texture_1d %20
|
||||
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
auto* p = parser(test::Assemble(assembly));
|
||||
ASSERT_TRUE(p->BuildInternalModule());
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
|
||||
const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
|
||||
|
||||
ASSERT_TRUE(sampler != nullptr);
|
||||
EXPECT_EQ(sampler->result_id(), 10u);
|
||||
|
||||
ASSERT_TRUE(image != nullptr);
|
||||
EXPECT_EQ(image->result_id(), 20u);
|
||||
}
|
||||
|
||||
TEST_F(SpvParserTest, GetMemoryObjectDeclarationForHandle_FuncParam_Load) {
|
||||
const auto assembly = Preamble() + CommonTypes() + R"(
|
||||
%fty = OpTypeFunction %void %ptr_sampler %ptr_f_texture_1d
|
||||
|
||||
%func = OpFunction %void None %fty
|
||||
%10 = OpFunctionParameter %ptr_sampler
|
||||
%20 = OpFunctionParameter %ptr_f_texture_1d
|
||||
%entry = OpLabel
|
||||
|
||||
%110 = OpLoad %sampler %10
|
||||
%120 = OpLoad %f_texture_1d %20
|
||||
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
auto* p = parser(test::Assemble(assembly));
|
||||
ASSERT_TRUE(p->BuildInternalModule());
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
|
||||
const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
|
||||
|
||||
ASSERT_TRUE(sampler != nullptr);
|
||||
EXPECT_EQ(sampler->result_id(), 10u);
|
||||
|
||||
ASSERT_TRUE(image != nullptr);
|
||||
EXPECT_EQ(image->result_id(), 20u);
|
||||
}
|
||||
|
||||
TEST_F(SpvParserTest,
|
||||
GetMemoryObjectDeclarationForHandle_FuncParam_SampledImage) {
|
||||
// Trace through the sampled image instruction, but in two different
|
||||
// directions.
|
||||
const auto assembly = Preamble() + CommonTypes() + R"(
|
||||
%sampled_image_type = OpTypeSampledImage %f_texture_1d
|
||||
|
||||
%fty = OpTypeFunction %void %ptr_sampler %ptr_f_texture_1d
|
||||
|
||||
%func = OpFunction %void None %fty
|
||||
%10 = OpFunctionParameter %ptr_sampler
|
||||
%20 = OpFunctionParameter %ptr_f_texture_1d
|
||||
%entry = OpLabel
|
||||
|
||||
%s = OpLoad %sampler %10
|
||||
%im = OpLoad %f_texture_1d %20
|
||||
%100 = OpSampledImage %sampled_image_type %im %s
|
||||
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
auto* p = parser(test::Assemble(assembly));
|
||||
ASSERT_TRUE(p->BuildInternalModule());
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
const auto* sampler = p->GetMemoryObjectDeclarationForHandle(100, false);
|
||||
const auto* image = p->GetMemoryObjectDeclarationForHandle(100, true);
|
||||
|
||||
ASSERT_TRUE(sampler != nullptr);
|
||||
EXPECT_EQ(sampler->result_id(), 10u);
|
||||
|
||||
ASSERT_TRUE(image != nullptr);
|
||||
EXPECT_EQ(image->result_id(), 20u);
|
||||
}
|
||||
|
||||
TEST_F(SpvParserTest, GetMemoryObjectDeclarationForHandle_FuncParam_Image) {
|
||||
const auto assembly = Preamble() + CommonTypes() + R"(
|
||||
%sampled_image_type = OpTypeSampledImage %f_texture_1d
|
||||
|
||||
%fty = OpTypeFunction %void %ptr_sampler %ptr_f_texture_1d
|
||||
|
||||
%func = OpFunction %void None %fty
|
||||
%10 = OpFunctionParameter %ptr_sampler
|
||||
%20 = OpFunctionParameter %ptr_f_texture_1d
|
||||
%entry = OpLabel
|
||||
|
||||
%s = OpLoad %sampler %10
|
||||
%im = OpLoad %f_texture_1d %20
|
||||
%100 = OpSampledImage %sampled_image_type %im %s
|
||||
%200 = OpImage %im %100
|
||||
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
auto* p = parser(test::Assemble(assembly));
|
||||
ASSERT_TRUE(p->BuildInternalModule());
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
|
||||
const auto* image = p->GetMemoryObjectDeclarationForHandle(200, true);
|
||||
ASSERT_TRUE(image != nullptr);
|
||||
EXPECT_EQ(image->result_id(), 20u);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace spirv
|
||||
} // namespace reader
|
||||
} // namespace tint
|
Loading…
Reference in New Issue