[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