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:
parent
9894867678
commit
6cad63c2ad
|
@ -3143,6 +3143,10 @@ TypedExpression FunctionEmitter::MaybeEmitCombinatorialValue(
|
|||
return MakeSimpleSelect(inst);
|
||||
}
|
||||
|
||||
if (opcode == SpvOpArrayLength) {
|
||||
return MakeArrayLength(inst);
|
||||
}
|
||||
|
||||
// builtin readonly function
|
||||
// glsl.std.450 readonly function
|
||||
|
||||
|
@ -4490,6 +4494,45 @@ TypedExpression FunctionEmitter::ToSignedIfUnsigned(TypedExpression 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;
|
||||
|
||||
|
|
|
@ -834,6 +834,11 @@ class FunctionEmitter {
|
|||
/// @returns an expression
|
||||
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
|
||||
/// accesses an image or sampled image.
|
||||
/// @param inst the SPIR-V instruction
|
||||
|
|
|
@ -1011,6 +1011,69 @@ TEST_F(SpvParserTest, DISABLED_RemapStorageBuffer_ThroughFunctionParameter) {
|
|||
// 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 spirv
|
||||
} // namespace reader
|
||||
|
|
|
@ -78,7 +78,7 @@ class Namer {
|
|||
/// Gets the registered name for a struct member. If no name has
|
||||
/// been registered for this member, then returns the empty string.
|
||||
/// 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
|
||||
/// @returns the registered name for the ID, or an empty string if
|
||||
/// nothing has been registered.
|
||||
|
|
Loading…
Reference in New Issue