spirv-reader: support OpArrayLength

Fixed: tint:431
Change-Id: I727ca8200118e0b93b42c5f7d9e97bc4afd97830
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/36460
Commit-Queue: David Neto <dneto@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Auto-Submit: David Neto <dneto@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
This commit is contained in:
David Neto 2021-01-05 21:21:50 +00:00 committed by Commit Bot service account
parent 9894867678
commit 6cad63c2ad
4 changed files with 112 additions and 1 deletions

View File

@ -3143,6 +3143,10 @@ TypedExpression FunctionEmitter::MaybeEmitCombinatorialValue(
return MakeSimpleSelect(inst); return MakeSimpleSelect(inst);
} }
if (opcode == SpvOpArrayLength) {
return MakeArrayLength(inst);
}
// builtin readonly function // builtin readonly function
// glsl.std.450 readonly function // glsl.std.450 readonly function
@ -4490,6 +4494,45 @@ TypedExpression FunctionEmitter::ToSignedIfUnsigned(TypedExpression value) {
return ToI32(value); return ToI32(value);
} }
TypedExpression FunctionEmitter::MakeArrayLength(
const spvtools::opt::Instruction& inst) {
if (inst.NumInOperands() != 2) {
// Binary parsing will fail on this anyway.
Fail() << "invalid array length: requires 2 operands: "
<< inst.PrettyPrint();
return {};
}
const auto struct_ptr_id = inst.GetSingleWordInOperand(0);
const auto field_index = inst.GetSingleWordInOperand(1);
const auto struct_ptr_type_id =
def_use_mgr_->GetDef(struct_ptr_id)->type_id();
// Trace through the pointer type to get to the struct type.
const auto struct_type_id =
def_use_mgr_->GetDef(struct_ptr_type_id)->GetSingleWordInOperand(1);
const auto field_name = namer_.GetMemberName(struct_type_id, field_index);
if (field_name.empty()) {
Fail() << "struct index out of bounds for array length: "
<< inst.PrettyPrint();
}
auto* member_ident = create<ast::IdentifierExpression>(
Source{}, ast_module_.RegisterSymbol(field_name), field_name);
auto* member_access = create<ast::MemberAccessorExpression>(
Source{}, MakeExpression(struct_ptr_id).expr, member_ident);
// Generate the intrinsic function call.
std::string call_ident_str = "arrayLength";
auto* call_ident = create<ast::IdentifierExpression>(
Source{}, ast_module_.RegisterSymbol(call_ident_str), call_ident_str);
call_ident->set_intrinsic(ast::Intrinsic::kArrayLength);
ast::ExpressionList params{member_access};
auto* call_expr =
create<ast::CallExpression>(Source{}, call_ident, std::move(params));
return {parser_impl_.ConvertType(inst.type_id()), call_expr};
}
FunctionEmitter::FunctionDeclaration::FunctionDeclaration() = default; FunctionEmitter::FunctionDeclaration::FunctionDeclaration() = default;
FunctionEmitter::FunctionDeclaration::~FunctionDeclaration() = default; FunctionEmitter::FunctionDeclaration::~FunctionDeclaration() = default;

View File

@ -834,6 +834,11 @@ class FunctionEmitter {
/// @returns an expression /// @returns an expression
TypedExpression MakeIntrinsicCall(const spvtools::opt::Instruction& inst); TypedExpression MakeIntrinsicCall(const spvtools::opt::Instruction& inst);
/// Returns an expression for a SPIR-V OpArrayLength instruction.
/// @param inst the SPIR-V instruction
/// @returns an expression
TypedExpression MakeArrayLength(const spvtools::opt::Instruction& inst);
/// Emits a texture builtin function call for a SPIR-V instruction that /// Emits a texture builtin function call for a SPIR-V instruction that
/// accesses an image or sampled image. /// accesses an image or sampled image.
/// @param inst the SPIR-V instruction /// @param inst the SPIR-V instruction

View File

@ -1011,6 +1011,69 @@ TEST_F(SpvParserTest, DISABLED_RemapStorageBuffer_ThroughFunctionParameter) {
// TODO(dneto): Blocked on OpFunctionCall support. // TODO(dneto): Blocked on OpFunctionCall support.
} }
std::string RuntimeArrayPreamble() {
return R"(
OpName %myvar "myvar"
OpMemberName %struct 0 "first"
OpMemberName %struct 1 "rtarr"
OpDecorate %struct Block
OpMemberDecorate %struct 0 Offset 0
OpMemberDecorate %struct 1 Offset 4
OpDecorate %arr ArrayStride 4
%void = OpTypeVoid
%voidfn = OpTypeFunction %void
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
%uint_1 = OpConstant %uint 1
%arr = OpTypeRuntimeArray %uint
%struct = OpTypeStruct %uint %arr
%ptr_struct = OpTypePointer StorageBuffer %struct
%ptr_uint = OpTypePointer StorageBuffer %uint
%myvar = OpVariable %ptr_struct StorageBuffer
)";
}
TEST_F(SpvParserTest, ArrayLength) {
const auto assembly = RuntimeArrayPreamble() + R"(
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%1 = OpArrayLength %uint %myvar 1
OpReturn
OpFunctionEnd
)";
auto p = parser(test::Assemble(assembly));
ASSERT_TRUE(p->BuildAndParseInternalModule()) << assembly << p->error();
FunctionEmitter fe(p.get(), *spirv_function(p.get(), 100));
EXPECT_TRUE(fe.EmitBody()) << p->error();
const auto body_str = ToString(p->get_module(), fe.ast_body());
EXPECT_THAT(body_str, HasSubstr(R"(VariableDeclStatement{
VariableConst{
x_1
none
__u32
{
Call[not set]{
Identifier[not set]{arrayLength}
(
MemberAccessor[not set]{
Identifier[not set]{myvar}
Identifier[not set]{rtarr}
}
)
}
}
}
}
)")) << body_str;
}
} // namespace } // namespace
} // namespace spirv } // namespace spirv
} // namespace reader } // namespace reader

View File

@ -78,7 +78,7 @@ class Namer {
/// Gets the registered name for a struct member. If no name has /// Gets the registered name for a struct member. If no name has
/// been registered for this member, then returns the empty string. /// been registered for this member, then returns the empty string.
/// member index is in bounds. /// member index is in bounds.
/// @param id the SPIR-V ID of the struct /// @param id the SPIR-V ID of the struct type
/// @param member_index the index of the member, counting from 0 /// @param member_index the index of the member, counting from 0
/// @returns the registered name for the ID, or an empty string if /// @returns the registered name for the ID, or an empty string if
/// nothing has been registered. /// nothing has been registered.