[spirv-writer] Allow emitting an array stride.
This CL adds the ability to attach a stride to an array type and have it
emitted during SPIR-V generation.
Bug: tint:5
Change-Id: I9c0f0a6afef6ae6662b64f4da2c150ba3f8da29f
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/23223
Reviewed-by: David Neto <dneto@google.com>
diff --git a/src/ast/type/array_type.cc b/src/ast/type/array_type.cc
index 2c840d3..6fb5f95 100644
--- a/src/ast/type/array_type.cc
+++ b/src/ast/type/array_type.cc
@@ -37,6 +37,8 @@
std::string type_name = "__array" + subtype_->type_name();
if (!IsRuntimeArray())
type_name += "_" + std::to_string(size_);
+ if (has_array_stride())
+ type_name += "_" + std::to_string(array_stride_);
return type_name;
}
diff --git a/src/ast/type/array_type.h b/src/ast/type/array_type.h
index 7bc8023..e89684c 100644
--- a/src/ast/type/array_type.h
+++ b/src/ast/type/array_type.h
@@ -45,6 +45,14 @@
/// i.e. the size is determined at runtime
bool IsRuntimeArray() const { return size_ == 0; }
+ /// Sets the array stride
+ /// @param stride the stride to set
+ void set_array_stride(uint32_t stride) { array_stride_ = stride; }
+ /// @returns the array stride or 0 if none set.
+ uint32_t array_stride() const { return array_stride_; }
+ /// @returns true if the array has a stride set
+ bool has_array_stride() const { return array_stride_ != 0; }
+
/// @returns the array type
Type* type() const { return subtype_; }
/// @returns the array size. Size is 0 for a runtime array
@@ -56,6 +64,7 @@
private:
Type* subtype_ = nullptr;
uint32_t size_ = 0;
+ uint32_t array_stride_ = 0;
};
} // namespace type
diff --git a/src/ast/type/array_type_test.cc b/src/ast/type/array_type_test.cc
index b7ff819..a4e4eae 100644
--- a/src/ast/type/array_type_test.cc
+++ b/src/ast/type/array_type_test.cc
@@ -61,10 +61,23 @@
TEST_F(ArrayTypeTest, TypeName) {
I32Type i32;
+ ArrayType arr{&i32};
+ EXPECT_EQ(arr.type_name(), "__array__i32");
+}
+
+TEST_F(ArrayTypeTest, TypeName_RuntimeArray) {
+ I32Type i32;
ArrayType arr{&i32, 3};
EXPECT_EQ(arr.type_name(), "__array__i32_3");
}
+TEST_F(ArrayTypeTest, TypeName_WithStride) {
+ I32Type i32;
+ ArrayType arr{&i32, 3};
+ arr.set_array_stride(16);
+ EXPECT_EQ(arr.type_name(), "__array__i32_3_16");
+}
+
} // namespace
} // namespace type
} // namespace ast
diff --git a/src/ast/type/struct_type.h b/src/ast/type/struct_type.h
index 18ce296..97cb4f2 100644
--- a/src/ast/type/struct_type.h
+++ b/src/ast/type/struct_type.h
@@ -41,6 +41,11 @@
/// @returns the struct name
const std::string& name() const { return name_; }
+ /// @returns true if the struct has a block decoration
+ bool IsBlockDecorated() const {
+ return struct_->decoration() == StructDecoration::kBlock;
+ }
+
/// @returns true if the type is a struct type
bool IsStruct() const override;
diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc
index cf3ee87..607f2ce 100644
--- a/src/writer/spirv/builder.cc
+++ b/src/writer/spirv/builder.cc
@@ -1681,6 +1681,7 @@
return false;
}
+ auto result_id = result.to_i();
if (ary->IsRuntimeArray()) {
push_type(spv::Op::OpTypeRuntimeArray, {result, Operand::Int(elem_type)});
} else {
@@ -1692,6 +1693,17 @@
push_type(spv::Op::OpTypeArray,
{result, Operand::Int(elem_type), Operand::Int(len_id)});
}
+
+ // SPIR-V explicitly requires no array stride if the array contains a struct
+ // which has a Block decoration.
+ if (ary->type()->IsStruct() && ary->type()->AsStruct()->IsBlockDecorated()) {
+ return true;
+ }
+ if (ary->has_array_stride()) {
+ push_annot(spv::Op::OpDecorate,
+ {Operand::Int(result_id), Operand::Int(SpvDecorationArrayStride),
+ Operand::Int(ary->array_stride())});
+ }
return true;
}
diff --git a/src/writer/spirv/builder_type_test.cc b/src/writer/spirv/builder_type_test.cc
index b49e987..b554b31 100644
--- a/src/writer/spirv/builder_type_test.cc
+++ b/src/writer/spirv/builder_type_test.cc
@@ -118,6 +118,27 @@
)");
}
+TEST_F(BuilderTest_Type, GenerateArray_WithStride) {
+ ast::type::I32Type i32;
+ ast::type::ArrayType ary(&i32, 4);
+ ary.set_array_stride(16u);
+
+ ast::Module mod;
+ Builder b(&mod);
+ auto id = b.GenerateTypeIfNeeded(&ary);
+ ASSERT_FALSE(b.has_error()) << b.error();
+ EXPECT_EQ(1u, id);
+
+ EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %1 ArrayStride 16
+)");
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
+%3 = OpTypeInt 32 0
+%4 = OpConstant %3 4
+%1 = OpTypeArray %2 %4
+)");
+}
+
TEST_F(BuilderTest_Type, ReturnsGeneratedArray) {
ast::type::I32Type i32;
ast::type::ArrayType ary(&i32, 4);