spirv-reader: infer function storage class on OpAccessChain without indices
Fixed: tint:941 Bug: tint:807 Change-Id: I37bec630c1b83dbb56d2f8937322a5b5be81f407 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/56660 Auto-Submit: David Neto <dneto@google.com> Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: David Neto <dneto@google.com> Reviewed-by: Ben Clayton <bclayton@google.com>
This commit is contained in:
parent
37cabbb468
commit
9bf951eee5
|
@ -3786,6 +3786,21 @@ TypedExpression FunctionEmitter::MakeOperand(
|
||||||
return parser_impl_.RectifyOperandSignedness(inst, std::move(expr));
|
return parser_impl_.RectifyOperandSignedness(inst, std::move(expr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TypedExpression FunctionEmitter::InferFunctionStorageClass(
|
||||||
|
TypedExpression expr) {
|
||||||
|
TypedExpression result(expr);
|
||||||
|
if (const auto* ref = expr.type->UnwrapAlias()->As<Reference>()) {
|
||||||
|
if (ref->storage_class == ast::StorageClass::kNone) {
|
||||||
|
expr.type = ty_.Reference(ref->type, ast::StorageClass::kFunction);
|
||||||
|
}
|
||||||
|
} else if (const auto* ptr = expr.type->UnwrapAlias()->As<Pointer>()) {
|
||||||
|
if (ptr->storage_class == ast::StorageClass::kNone) {
|
||||||
|
expr.type = ty_.Pointer(ptr->type, ast::StorageClass::kFunction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
TypedExpression FunctionEmitter::MaybeEmitCombinatorialValue(
|
TypedExpression FunctionEmitter::MaybeEmitCombinatorialValue(
|
||||||
const spvtools::opt::Instruction& inst) {
|
const spvtools::opt::Instruction& inst) {
|
||||||
if (inst.result_id() == 0) {
|
if (inst.result_id() == 0) {
|
||||||
|
@ -4118,7 +4133,7 @@ TypedExpression FunctionEmitter::MakeAccessChain(
|
||||||
// ever-deeper nested indexing expressions. Start off with an expression
|
// ever-deeper nested indexing expressions. Start off with an expression
|
||||||
// for the base, and then bury that inside nested indexing expressions.
|
// for the base, and then bury that inside nested indexing expressions.
|
||||||
if (!current_expr) {
|
if (!current_expr) {
|
||||||
current_expr = MakeOperand(inst, 0);
|
current_expr = InferFunctionStorageClass(MakeOperand(inst, 0));
|
||||||
if (current_expr.type->Is<Pointer>()) {
|
if (current_expr.type->Is<Pointer>()) {
|
||||||
current_expr = Dereference(current_expr);
|
current_expr = Dereference(current_expr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -964,6 +964,13 @@ class FunctionEmitter {
|
||||||
TypedExpression MakeOperand(const spvtools::opt::Instruction& inst,
|
TypedExpression MakeOperand(const spvtools::opt::Instruction& inst,
|
||||||
uint32_t operand_index);
|
uint32_t operand_index);
|
||||||
|
|
||||||
|
/// Copies a typed expression to the result, but when the type is a pointer
|
||||||
|
/// or reference type, ensures the storage class is not defaulted. That is,
|
||||||
|
/// it changes a storage class of "none" to "function".
|
||||||
|
/// @param expr a typed expression
|
||||||
|
/// @results a copy of the expression, with possibly updated type
|
||||||
|
TypedExpression InferFunctionStorageClass(TypedExpression expr);
|
||||||
|
|
||||||
/// Returns an expression for a SPIR-V OpAccessChain or OpInBoundsAccessChain
|
/// Returns an expression for a SPIR-V OpAccessChain or OpInBoundsAccessChain
|
||||||
/// instruction.
|
/// instruction.
|
||||||
/// @param inst the SPIR-V instruction
|
/// @param inst the SPIR-V instruction
|
||||||
|
|
|
@ -903,6 +903,76 @@ TEST_F(SpvParserMemoryTest, EmitStatement_AccessChain_DereferenceBase) {
|
||||||
EXPECT_EQ(got, expected) << got;
|
EXPECT_EQ(got, expected) << got;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(SpvParserMemoryTest,
|
||||||
|
EmitStatement_AccessChain_InferFunctionStorageClass) {
|
||||||
|
// An access chain can have no indices. When the base is a Function variable,
|
||||||
|
// the reference type has no explicit storage class in the AST representation.
|
||||||
|
// But the pointer type for the let declaration must have an explicit
|
||||||
|
// 'function' storage class. From crbug.com/tint/807
|
||||||
|
const std::string assembly = R"(
|
||||||
|
OpCapability Shader
|
||||||
|
OpMemoryModel Logical Simple
|
||||||
|
OpEntryPoint Fragment %main "main"
|
||||||
|
OpExecutionMode %main OriginUpperLeft
|
||||||
|
|
||||||
|
%uint = OpTypeInt 32 0
|
||||||
|
%ptr_ty = OpTypePointer Function %uint
|
||||||
|
|
||||||
|
%void = OpTypeVoid
|
||||||
|
%voidfn = OpTypeFunction %void
|
||||||
|
%main = OpFunction %void None %voidfn
|
||||||
|
%entry = OpLabel
|
||||||
|
%1 = OpVariable %ptr_ty Function
|
||||||
|
%2 = OpAccessChain %ptr_ty %1
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
||||||
|
)";
|
||||||
|
auto p = parser(test::Assemble(assembly));
|
||||||
|
ASSERT_TRUE(p->BuildAndParseInternalModule()) << assembly;
|
||||||
|
const auto got = p->program().to_str();
|
||||||
|
const std::string expected = R"(Module{
|
||||||
|
Function main_1 -> __void
|
||||||
|
()
|
||||||
|
{
|
||||||
|
VariableDeclStatement{
|
||||||
|
Variable{
|
||||||
|
x_1
|
||||||
|
none
|
||||||
|
undefined
|
||||||
|
__u32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VariableDeclStatement{
|
||||||
|
VariableConst{
|
||||||
|
x_2
|
||||||
|
none
|
||||||
|
undefined
|
||||||
|
__ptr_function__u32
|
||||||
|
{
|
||||||
|
UnaryOp[not set]{
|
||||||
|
address-of
|
||||||
|
Identifier[not set]{x_1}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Return{}
|
||||||
|
}
|
||||||
|
Function main -> __void
|
||||||
|
StageDecoration{fragment}
|
||||||
|
()
|
||||||
|
{
|
||||||
|
Call[not set]{
|
||||||
|
Identifier[not set]{main_1}
|
||||||
|
(
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
EXPECT_EQ(got, expected) << got;
|
||||||
|
}
|
||||||
|
|
||||||
std::string OldStorageBufferPreamble() {
|
std::string OldStorageBufferPreamble() {
|
||||||
return Preamble() + R"(
|
return Preamble() + R"(
|
||||||
OpName %myvar "myvar"
|
OpName %myvar "myvar"
|
||||||
|
|
Loading…
Reference in New Issue