spirv-reader: refactor getting handle type

Rename ParserImpl::GetTypeForHandleMemObjDecl to
ParserImpl::GetHandleTypeForSpirvHandle

More importantly, it now returns the texture or sampler type rather
than the pointer type to the texture or sampler.

Most usages only wanted the store type.

Change-Id: I875e11d97e6d3ecb10fdb3317b860c05fc5fe406
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/109760
Auto-Submit: David Neto <dneto@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
Commit-Queue: David Neto <dneto@google.com>
This commit is contained in:
David Neto 2022-11-14 21:13:30 +00:00 committed by Dawn LUCI CQ
parent 8cd34f8425
commit 208fc35471
3 changed files with 71 additions and 79 deletions

View File

@ -1522,12 +1522,8 @@ bool FunctionEmitter::ParseFunctionDeclaration(FunctionDeclaration* decl) {
(static_cast<spv::StorageClass>(spirv_type->AsPointer()->storage_class()) == (static_cast<spv::StorageClass>(spirv_type->AsPointer()->storage_class()) ==
spv::StorageClass::UniformConstant))) { spv::StorageClass::UniformConstant))) {
// When we see image, sampler, pointer-to-image, or pointer-to-sampler, use the // When we see image, sampler, pointer-to-image, or pointer-to-sampler, use the
// handle type deduced according to usage. Handle types are automatically generated as // handle type deduced according to usage.
// pointer-to-handle. Extract the handle type itself. type = parser_impl_.GetHandleTypeForSpirvHandle(*param);
const auto* ptr_type = parser_impl_.GetTypeForHandleMemObjDecl(*param);
TINT_ASSERT(Reader, ptr_type);
// In WGSL, pass handles instead of pointers to them.
type = ptr_type->type;
} else { } else {
type = parser_impl_.ConvertType(param->type_id()); type = parser_impl_.ConvertType(param->type_id());
} }
@ -5424,21 +5420,17 @@ const spvtools::opt::Instruction* FunctionEmitter::GetImage(
} }
const Texture* FunctionEmitter::GetImageType(const spvtools::opt::Instruction& image) { const Texture* FunctionEmitter::GetImageType(const spvtools::opt::Instruction& image) {
const Pointer* ptr_type = parser_impl_.GetTypeForHandleMemObjDecl(image); const Type* type = parser_impl_.GetHandleTypeForSpirvHandle(image);
if (!parser_impl_.success()) { if (!parser_impl_.success()) {
Fail(); Fail();
return {}; return {};
} }
if (!ptr_type) { TINT_ASSERT(Reader, type != nullptr);
Fail() << "invalid texture type for " << image.PrettyPrint(); if (auto* result = type->UnwrapAll()->As<Texture>()) {
return {}; return result;
} }
auto* result = ptr_type->type->UnwrapAll()->As<Texture>(); Fail() << "invalid texture type for " << image.PrettyPrint();
if (!result) { return {};
Fail() << "invalid texture type for " << image.PrettyPrint();
return {};
}
return result;
} }
const ast::Expression* FunctionEmitter::GetImageExpression(const spvtools::opt::Instruction& inst) { const ast::Expression* FunctionEmitter::GetImageExpression(const spvtools::opt::Instruction& inst) {
@ -5488,12 +5480,7 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
} }
// Find the texture type. // Find the texture type.
const Pointer* texture_ptr_type = parser_impl_.GetTypeForHandleMemObjDecl(*image); const auto* texture_type = parser_impl_.GetHandleTypeForSpirvHandle(*image)->As<Texture>();
if (!texture_ptr_type) {
return Fail();
}
const Texture* texture_type = texture_ptr_type->type->UnwrapAll()->As<Texture>();
if (!texture_type) { if (!texture_type) {
return Fail(); return Fail();
} }

View File

@ -1535,28 +1535,33 @@ bool ParserImpl::EmitModuleScopeVariables() {
if (!success_) { if (!success_) {
return false; return false;
} }
const Type* ast_type = nullptr; const Type* ast_store_type = nullptr;
ast::AddressSpace ast_address_space = ast::AddressSpace::kNone;
if (spirv_storage_class == spv::StorageClass::UniformConstant) { if (spirv_storage_class == spv::StorageClass::UniformConstant) {
// These are opaque handles: samplers or textures // These are opaque handles: samplers or textures
ast_type = GetTypeForHandleMemObjDecl(var); ast_store_type = GetHandleTypeForSpirvHandle(var);
if (!ast_type) { if (!ast_store_type) {
return false; return false;
} }
// ast_storage_class should remain kNone because handle variables
// are never declared with an explicit address space.
} else { } else {
ast_type = ConvertType(type_id); const Type* ast_type = ConvertType(type_id);
if (ast_type == nullptr) { if (ast_type == nullptr) {
return Fail() << "internal error: failed to register Tint AST type for " return Fail() << "internal error: failed to register Tint AST type for "
"SPIR-V type with ID: " "SPIR-V type with ID: "
<< var.type_id(); << var.type_id();
} }
if (!ast_type->Is<Pointer>()) { if (auto* ast_ptr_type = ast_type->As<Pointer>()) {
ast_store_type = ast_ptr_type->type;
ast_address_space = ast_ptr_type->address_space;
} else {
return Fail() << "variable with ID " << var.result_id() << " has non-pointer type " return Fail() << "variable with ID " << var.result_id() << " has non-pointer type "
<< var.type_id(); << var.type_id();
} }
} }
TINT_ASSERT(Reader, ast_store_type != nullptr);
auto* ast_store_type = ast_type->As<Pointer>()->type;
auto ast_address_space = ast_type->As<Pointer>()->address_space;
const ast::Expression* ast_initializer = nullptr; const ast::Expression* ast_initializer = nullptr;
if (var.NumInOperands() > 1) { if (var.NumInOperands() > 1) {
// SPIR-V initializers are always constants. // SPIR-V initializers are always constants.
@ -2356,7 +2361,7 @@ const spvtools::opt::Instruction* ParserImpl::GetMemoryObjectDeclarationForHandl
} }
const spvtools::opt::Instruction* ParserImpl::GetSpirvTypeForHandleOrHandleMemoryObjectDeclaration( const spvtools::opt::Instruction* ParserImpl::GetSpirvTypeForHandleOrHandleMemoryObjectDeclaration(
const spvtools::opt::Instruction& mem_obj_decl) { const spvtools::opt::Instruction& obj) {
if (!success()) { if (!success()) {
return nullptr; return nullptr;
} }
@ -2371,9 +2376,11 @@ const spvtools::opt::Instruction* ParserImpl::GetSpirvTypeForHandleOrHandleMemor
// are the only SPIR-V handles supported by WGSL. // are the only SPIR-V handles supported by WGSL.
// Get the SPIR-V handle type. // Get the SPIR-V handle type.
const auto* type = def_use_mgr_->GetDef(mem_obj_decl.type_id()); const auto* type = def_use_mgr_->GetDef(obj.type_id());
if (!type) { if (!type) {
Fail() << "Invalid type for variable or function parameter " << mem_obj_decl.PrettyPrint(); Fail() << "Invalid type for image, sampler, variable or function parameter to image or "
"sampler "
<< obj.PrettyPrint();
return nullptr; return nullptr;
} }
switch (opcode(type)) { switch (opcode(type)) {
@ -2384,16 +2391,16 @@ const spvtools::opt::Instruction* ParserImpl::GetSpirvTypeForHandleOrHandleMemor
// The remaining cases. // The remaining cases.
break; break;
default: default:
Fail() << "Invalid type for variable or function parameter " Fail() << "Invalid type for image, sampler, variable or function parameter to image or "
<< mem_obj_decl.PrettyPrint(); "sampler "
<< obj.PrettyPrint();
return nullptr; return nullptr;
} }
// Look at the pointee type instead. // Look at the pointee type instead.
const auto* raw_handle_type = def_use_mgr_->GetDef(type->GetSingleWordInOperand(1)); const auto* raw_handle_type = def_use_mgr_->GetDef(type->GetSingleWordInOperand(1));
if (!raw_handle_type) { if (!raw_handle_type) {
Fail() << "Invalid pointer type for variable or function parameter " Fail() << "Invalid pointer type for variable or function parameter " << obj.PrettyPrint();
<< mem_obj_decl.PrettyPrint();
return nullptr; return nullptr;
} }
switch (opcode(raw_handle_type)) { switch (opcode(raw_handle_type)) {
@ -2405,30 +2412,28 @@ const spvtools::opt::Instruction* ParserImpl::GetSpirvTypeForHandleOrHandleMemor
case spv::Op::OpTypeRuntimeArray: case spv::Op::OpTypeRuntimeArray:
Fail() << "arrays of textures or samplers are not supported in WGSL; can't " Fail() << "arrays of textures or samplers are not supported in WGSL; can't "
"translate variable or function parameter: " "translate variable or function parameter: "
<< mem_obj_decl.PrettyPrint(); << obj.PrettyPrint();
return nullptr; return nullptr;
case spv::Op::OpTypeSampledImage: case spv::Op::OpTypeSampledImage:
Fail() << "WGSL does not support combined image-samplers: " Fail() << "WGSL does not support combined image-samplers: " << obj.PrettyPrint();
<< mem_obj_decl.PrettyPrint();
return nullptr; return nullptr;
default: default:
Fail() << "invalid type for image or sampler variable or function " Fail() << "invalid type for image or sampler variable or function "
"parameter: " "parameter: "
<< mem_obj_decl.PrettyPrint(); << obj.PrettyPrint();
return nullptr; return nullptr;
} }
return raw_handle_type; return raw_handle_type;
} }
const Pointer* ParserImpl::GetTypeForHandleMemObjDecl( const Type* ParserImpl::GetHandleTypeForSpirvHandle(const spvtools::opt::Instruction& obj) {
const spvtools::opt::Instruction& mem_obj_decl) { auto where = handle_type_.find(&obj);
auto where = handle_type_.find(&mem_obj_decl);
if (where != handle_type_.end()) { if (where != handle_type_.end()) {
return where->second; return where->second;
} }
const spvtools::opt::Instruction* raw_handle_type = const spvtools::opt::Instruction* raw_handle_type =
GetSpirvTypeForHandleOrHandleMemoryObjectDeclaration(mem_obj_decl); GetSpirvTypeForHandleOrHandleMemoryObjectDeclaration(obj);
if (!raw_handle_type) { if (!raw_handle_type) {
return nullptr; return nullptr;
} }
@ -2436,10 +2441,10 @@ const Pointer* ParserImpl::GetTypeForHandleMemObjDecl(
// The memory object declaration could be a sampler or image. // The memory object declaration could be a sampler or image.
// Where possible, determine which one it is from the usage inferred // Where possible, determine which one it is from the usage inferred
// for the variable. // for the variable.
Usage usage = handle_usage_[&mem_obj_decl]; Usage usage = handle_usage_[&obj];
if (!usage.IsValid()) { if (!usage.IsValid()) {
Fail() << "Invalid sampler or texture usage for variable or function parameter " Fail() << "Invalid sampler or texture usage for variable or function parameter "
<< mem_obj_decl.PrettyPrint() << "\n" << obj.PrettyPrint() << "\n"
<< usage; << usage;
return nullptr; return nullptr;
} }
@ -2465,7 +2470,7 @@ const Pointer* ParserImpl::GetTypeForHandleMemObjDecl(
// Get NonWritable and NonReadable attributes of the variable. // Get NonWritable and NonReadable attributes of the variable.
bool is_nonwritable = false; bool is_nonwritable = false;
bool is_nonreadable = false; bool is_nonreadable = false;
for (const auto& deco : GetDecorationsFor(mem_obj_decl.result_id())) { for (const auto& deco : GetDecorationsFor(obj.result_id())) {
if (deco.size() != 1) { if (deco.size() != 1) {
continue; continue;
} }
@ -2478,11 +2483,11 @@ const Pointer* ParserImpl::GetTypeForHandleMemObjDecl(
} }
if (is_nonwritable && is_nonreadable) { if (is_nonwritable && is_nonreadable) {
Fail() << "storage image variable is both NonWritable and NonReadable" Fail() << "storage image variable is both NonWritable and NonReadable"
<< mem_obj_decl.PrettyPrint(); << obj.PrettyPrint();
} }
if (!is_nonwritable && !is_nonreadable) { if (!is_nonwritable && !is_nonreadable) {
Fail() << "storage image variable is neither NonWritable nor NonReadable" Fail() << "storage image variable is neither NonWritable nor NonReadable"
<< mem_obj_decl.PrettyPrint(); << obj.PrettyPrint();
} }
// Let's make it one of the storage textures. // Let's make it one of the storage textures.
if (is_nonwritable) { if (is_nonwritable) {
@ -2502,9 +2507,9 @@ const Pointer* ParserImpl::GetTypeForHandleMemObjDecl(
} }
// Construct the Tint handle type. // Construct the Tint handle type.
const Type* ast_store_type = nullptr; const Type* ast_handle_type = nullptr;
if (usage.IsSampler()) { if (usage.IsSampler()) {
ast_store_type = ast_handle_type =
ty_.Sampler(usage.IsComparisonSampler() ? ast::SamplerKind::kComparisonSampler ty_.Sampler(usage.IsComparisonSampler() ? ast::SamplerKind::kComparisonSampler
: ast::SamplerKind::kSampler); : ast::SamplerKind::kSampler);
} else if (usage.IsTexture()) { } else if (usage.IsTexture()) {
@ -2526,8 +2531,7 @@ const Pointer* ParserImpl::GetTypeForHandleMemObjDecl(
default: default:
Fail() << "WGSL arrayed textures must be 2d_array or cube_array: " Fail() << "WGSL arrayed textures must be 2d_array or cube_array: "
"invalid multisampled texture variable or function parameter " "invalid multisampled texture variable or function parameter "
<< namer_.Name(mem_obj_decl.result_id()) << ": " << namer_.Name(obj.result_id()) << ": " << obj.PrettyPrint();
<< mem_obj_decl.PrettyPrint();
return nullptr; return nullptr;
} }
} }
@ -2552,21 +2556,20 @@ const Pointer* ParserImpl::GetTypeForHandleMemObjDecl(
// treat that as a depth texture. // treat that as a depth texture.
if (image_type->depth() || usage.IsDepthTexture()) { if (image_type->depth() || usage.IsDepthTexture()) {
if (image_type->is_multisampled()) { if (image_type->is_multisampled()) {
ast_store_type = ty_.DepthMultisampledTexture(dim); ast_handle_type = ty_.DepthMultisampledTexture(dim);
} else { } else {
ast_store_type = ty_.DepthTexture(dim); ast_handle_type = ty_.DepthTexture(dim);
} }
} else if (image_type->is_multisampled()) { } else if (image_type->is_multisampled()) {
if (dim != ast::TextureDimension::k2d) { if (dim != ast::TextureDimension::k2d) {
Fail() << "WGSL multisampled textures must be 2d and non-arrayed: " Fail() << "WGSL multisampled textures must be 2d and non-arrayed: "
"invalid multisampled texture variable or function parameter " "invalid multisampled texture variable or function parameter "
<< namer_.Name(mem_obj_decl.result_id()) << ": " << namer_.Name(obj.result_id()) << ": " << obj.PrettyPrint();
<< mem_obj_decl.PrettyPrint();
} }
// Multisampled textures are never depth textures. // Multisampled textures are never depth textures.
ast_store_type = ty_.MultisampledTexture(dim, ast_sampled_component_type); ast_handle_type = ty_.MultisampledTexture(dim, ast_sampled_component_type);
} else { } else {
ast_store_type = ty_.SampledTexture(dim, ast_sampled_component_type); ast_handle_type = ty_.SampledTexture(dim, ast_sampled_component_type);
} }
} else { } else {
const auto access = ast::Access::kWrite; const auto access = ast::Access::kWrite;
@ -2574,20 +2577,18 @@ const Pointer* ParserImpl::GetTypeForHandleMemObjDecl(
if (format == ast::TexelFormat::kUndefined) { if (format == ast::TexelFormat::kUndefined) {
return nullptr; return nullptr;
} }
ast_store_type = ty_.StorageTexture(dim, format, access); ast_handle_type = ty_.StorageTexture(dim, format, access);
} }
} else { } else {
Fail() << "unsupported: UniformConstant variable or function parameter is not a recognized " Fail() << "unsupported: UniformConstant variable or function parameter is not a recognized "
"sampler or texture " "sampler or texture "
<< mem_obj_decl.PrettyPrint(); << obj.PrettyPrint();
return nullptr; return nullptr;
} }
// Form the pointer type.
auto* result = ty_.Pointer(ast_store_type, ast::AddressSpace::kHandle);
// Remember it for later. // Remember it for later.
handle_type_[&mem_obj_decl] = result; handle_type_[&obj] = ast_handle_type;
return result; return ast_handle_type;
} }
const Type* ParserImpl::GetComponentTypeForFormat(ast::TexelFormat format) { const Type* ParserImpl::GetComponentTypeForFormat(ast::TexelFormat format) {

View File

@ -640,23 +640,26 @@ class ParserImpl : Reader {
/// @returns the handle usage, or an empty usage object. /// @returns the handle usage, or an empty usage object.
Usage GetHandleUsage(uint32_t id) const; Usage GetHandleUsage(uint32_t id) const;
/// Returns the SPIR-V type for the sampler or image type for the given /// Returns the SPIR-V OpTypeImage or OpTypeSampler for the given:
/// variable in UniformConstant address space, or function parameter pointing /// image object,
/// into the UniformConstant address space, or image or sampler type. /// sampler object,
/// memory object declaration image or sampler (i.e. a variable or
/// function parameter with type being a pointer to UniformConstant)
/// Returns null and emits an error on failure. /// Returns null and emits an error on failure.
/// @param mem_obj_decl the OpVariable instruction or OpFunctionParameter /// @param obj the given image, sampler, or memory object declaration for an
/// @returns the Tint AST type for the sampler or texture, or null on error /// image or sampler
/// @returns the SPIR-V instruction declaring the corresponding OpTypeImage
/// or OpTypeSampler
const spvtools::opt::Instruction* GetSpirvTypeForHandleOrHandleMemoryObjectDeclaration( const spvtools::opt::Instruction* GetSpirvTypeForHandleOrHandleMemoryObjectDeclaration(
const spvtools::opt::Instruction& mem_obj_decl); const spvtools::opt::Instruction& obj);
/// Returns the AST type for the pointer-to-sampler or pointer-to-texture type /// Returns the AST type for the texture or sampler type for the given
/// for the given variable in UniformConstant address space or function /// SPIR-V image, sampler, or memory object declaration for an image or
/// parameter of type pointer-to-UniformConstant. Returns null and /// sampler. Returns null and emits an error on failure.
/// emits an error on failure. /// @param obj the OpVariable instruction
/// @param mem_obj_decl the OpVariable instruction
/// @returns the Tint AST type for the poiner-to-{sampler|texture} or null on /// @returns the Tint AST type for the poiner-to-{sampler|texture} or null on
/// error /// error
const Pointer* GetTypeForHandleMemObjDecl(const spvtools::opt::Instruction& mem_obj_decl); const Type* GetHandleTypeForSpirvHandle(const spvtools::opt::Instruction& obj);
/// Returns the AST variable for the SPIR-V ID of a module-scope variable, /// Returns the AST variable for the SPIR-V ID of a module-scope variable,
/// or null if there isn't one. /// or null if there isn't one.
@ -879,8 +882,9 @@ class ParserImpl : Reader {
// Maps a memory-object-declaration instruction to any sampler or texture // Maps a memory-object-declaration instruction to any sampler or texture
// usages implied by usages of the memory-object-declaration. // usages implied by usages of the memory-object-declaration.
std::unordered_map<const spvtools::opt::Instruction*, Usage> handle_usage_; std::unordered_map<const spvtools::opt::Instruction*, Usage> handle_usage_;
// The inferred pointer type for the given handle variable. // The inferred WGSL handle type for the given SPIR-V image, sampler, or
std::unordered_map<const spvtools::opt::Instruction*, const Pointer*> handle_type_; // memory object declaration for an image or sampler.
std::unordered_map<const spvtools::opt::Instruction*, const Type*> handle_type_;
/// Maps the SPIR-V ID of a module-scope variable to its AST variable. /// Maps the SPIR-V ID of a module-scope variable to its AST variable.
utils::Hashmap<uint32_t, ast::Var*, 16> module_variable_; utils::Hashmap<uint32_t, ast::Var*, 16> module_variable_;