[hlsl-writer] Extract storage buffer index generation. This CL extracts the index string for a storage buffer access. Bug: tint:7 Change-Id: Ibc0d7dd5b532bbd6141cce4a82495732452d1414 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/27441 Commit-Queue: dan sinclair <dsinclair@chromium.org> Reviewed-by: Sarah Mashayekhi <sarahmashay@google.com> Reviewed-by: David Neto <dneto@google.com>
diff --git a/src/writer/hlsl/generator_impl.cc b/src/writer/hlsl/generator_impl.cc index c2b90a3..1ffda9d 100644 --- a/src/writer/hlsl/generator_impl.cc +++ b/src/writer/hlsl/generator_impl.cc
@@ -14,6 +14,8 @@ #include "src/writer/hlsl/generator_impl.h" +#include <sstream> + #include "spirv/unified1/GLSL.std.450.h" #include "src/ast/array_accessor_expression.h" #include "src/ast/as_expression.h" @@ -1489,6 +1491,87 @@ return true; } +std::string GeneratorImpl::generate_storage_buffer_index_expression( + ast::Expression* expr) { + std::ostringstream out; + bool first = true; + for (;;) { + if (expr->IsIdentifier()) { + break; + } + + if (!first) { + out << " + "; + } + first = false; + if (expr->IsMemberAccessor()) { + auto* mem = expr->AsMemberAccessor(); + auto* res_type = mem->structure()->result_type()->UnwrapAliasPtrAlias(); + + if (res_type->IsStruct()) { + auto* str_type = res_type->AsStruct()->impl(); + auto* str_member = str_type->get_member(mem->member()->name()); + + if (!str_member->has_offset_decoration()) { + error_ = "missing offset decoration for struct member"; + return ""; + } + out << str_member->offset(); + } else if (res_type->IsVector()) { + // This must be a single element swizzle if we've got a vector at this + // point. + if (mem->member()->name().size() != 1) { + error_ = + "Encountered multi-element swizzle when should have only one " + "level"; + return ""; + } + + // TODO(dsinclair): All our types are currently 4 bytes (f32, i32, u32) + // so this is assuming 4. This will need to be fixed when we get f16 or + // f64 types. + out << "(4 * " << convert_swizzle_to_index(mem->member()->name()) + << ")"; + } else { + error_ = + "Invalid result type for member accessor: " + res_type->type_name(); + return ""; + } + + expr = mem->structure(); + } else if (expr->IsArrayAccessor()) { + auto* ary = expr->AsArrayAccessor(); + auto* ary_type = ary->array()->result_type()->UnwrapAliasPtrAlias(); + + out << "("; + // TODO(dsinclair): Handle matrix case + if (ary_type->IsArray()) { + out << ary_type->AsArray()->array_stride(); + } else if (ary_type->IsVector()) { + // TODO(dsinclair): This is a hack. Our vectors can only be f32, i32 + // or u32 which are all 4 bytes. When we get f16 or other types we'll + // have to ask the type for the byte size. + out << "4"; + } else { + error_ = "Invalid array type in storage buffer access"; + return ""; + } + out << " * "; + if (!EmitExpression(out, ary->idx_expr())) { + return ""; + } + out << ")"; + + expr = ary->array(); + } else { + error_ = "error emitting storage buffer access"; + return ""; + } + } + + return out.str(); +} + // TODO(dsinclair): This currently only handles loading of 4, 8, 12 or 16 byte // members. If we need to support larger we'll need to do the loading into // chunks. @@ -1523,81 +1606,11 @@ } out << buffer_name << "." << access_method << "("; - auto* ptr = expr; - bool first = true; - for (;;) { - if (ptr->IsIdentifier()) { - break; - } - - if (!first) { - out << " + "; - } - first = false; - if (ptr->IsMemberAccessor()) { - auto* mem = ptr->AsMemberAccessor(); - auto* res_type = mem->structure()->result_type()->UnwrapAliasPtrAlias(); - - if (res_type->IsStruct()) { - auto* str_type = res_type->AsStruct()->impl(); - auto* str_member = str_type->get_member(mem->member()->name()); - - if (!str_member->has_offset_decoration()) { - error_ = "missing offset decoration for struct member"; - return false; - } - out << str_member->offset(); - } else if (res_type->IsVector()) { - // This must be a single element swizzle if we've got a vector at this - // point. - if (mem->member()->name().size() != 1) { - error_ = - "Encountered multi-element swizzle when should have only one " - "level"; - return false; - } - - // TODO(dsinclair): All our types are currently 4 bytes (f32, i32, u32) - // so this is assuming 4. This will need to be fixed when we get f16 or - // f64 types. - out << "(4 * " << convert_swizzle_to_index(mem->member()->name()) - << ")"; - } else { - error_ = - "Invalid result type for member accessor: " + res_type->type_name(); - return false; - } - - ptr = mem->structure(); - } else if (ptr->IsArrayAccessor()) { - auto* ary = ptr->AsArrayAccessor(); - auto* ary_type = ary->array()->result_type()->UnwrapAliasPtrAlias(); - - out << "("; - // TODO(dsinclair): Handle matrix case and struct case. - if (ary_type->IsArray()) { - out << ary_type->AsArray()->array_stride(); - } else if (ary_type->IsVector()) { - // TODO(dsinclair): This is a hack. Our vectors can only be f32, i32 - // or u32 which are all 4 bytes. When we get f16 or other types we'll - // have to ask the type for the byte size. - out << "4"; - } else { - error_ = "Invalid array type in storage buffer access"; - return false; - } - out << " * "; - if (!EmitExpression(out, ary->idx_expr())) { - return false; - } - out << ")"; - - ptr = ary->array(); - } else { - error_ = "error emitting storage buffer access"; - return false; - } + auto idx = generate_storage_buffer_index_expression(expr); + if (idx.empty()) { + return false; } + out << idx; if (rhs != nullptr) { out << ", asuint(";
diff --git a/src/writer/hlsl/generator_impl.h b/src/writer/hlsl/generator_impl.h index 7908e42..e087c77 100644 --- a/src/writer/hlsl/generator_impl.h +++ b/src/writer/hlsl/generator_impl.h
@@ -279,6 +279,10 @@ /// @param var the variable to check /// @returns true if the global is in an input or output struct bool global_is_in_struct(ast::Variable* var) const; + /// Creates a text string representing the index into a storage buffer + /// @param expr the expression to use as the index + /// @returns the index string, or blank if unable to generate + std::string generate_storage_buffer_index_expression(ast::Expression* expr); /// Generates a name for the prefix /// @param prefix the prefix of the name to generate /// @returns the name