tint: Add 'chromium_experimental_full_ptr_parameters' extension

Removes validation around pointer parameters.

Bug: tint:1758
Change-Id: I3adc48f780fc8c6f5525f9ecc280e2a406069b49
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/112286
Reviewed-by: James Price <jrprice@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
This commit is contained in:
Ben Clayton 2022-11-30 19:13:29 +00:00 committed by Dawn LUCI CQ
parent 53f646c55c
commit 94706ecba7
9 changed files with 241 additions and 81 deletions

View File

@ -34,6 +34,9 @@ Extension ParseExtension(std::string_view str) {
if (str == "chromium_experimental_dp4a") { if (str == "chromium_experimental_dp4a") {
return Extension::kChromiumExperimentalDp4A; return Extension::kChromiumExperimentalDp4A;
} }
if (str == "chromium_experimental_full_ptr_parameters") {
return Extension::kChromiumExperimentalFullPtrParameters;
}
if (str == "chromium_experimental_push_constant") { if (str == "chromium_experimental_push_constant") {
return Extension::kChromiumExperimentalPushConstant; return Extension::kChromiumExperimentalPushConstant;
} }
@ -51,6 +54,8 @@ std::ostream& operator<<(std::ostream& out, Extension value) {
return out << "chromium_disable_uniformity_analysis"; return out << "chromium_disable_uniformity_analysis";
case Extension::kChromiumExperimentalDp4A: case Extension::kChromiumExperimentalDp4A:
return out << "chromium_experimental_dp4a"; return out << "chromium_experimental_dp4a";
case Extension::kChromiumExperimentalFullPtrParameters:
return out << "chromium_experimental_full_ptr_parameters";
case Extension::kChromiumExperimentalPushConstant: case Extension::kChromiumExperimentalPushConstant:
return out << "chromium_experimental_push_constant"; return out << "chromium_experimental_push_constant";
case Extension::kF16: case Extension::kF16:

View File

@ -35,6 +35,7 @@ enum class Extension {
kUndefined, kUndefined,
kChromiumDisableUniformityAnalysis, kChromiumDisableUniformityAnalysis,
kChromiumExperimentalDp4A, kChromiumExperimentalDp4A,
kChromiumExperimentalFullPtrParameters,
kChromiumExperimentalPushConstant, kChromiumExperimentalPushConstant,
kF16, kF16,
}; };
@ -52,6 +53,7 @@ Extension ParseExtension(std::string_view str);
constexpr const char* kExtensionStrings[] = { constexpr const char* kExtensionStrings[] = {
"chromium_disable_uniformity_analysis", "chromium_disable_uniformity_analysis",
"chromium_experimental_dp4a", "chromium_experimental_dp4a",
"chromium_experimental_full_ptr_parameters",
"chromium_experimental_push_constant", "chromium_experimental_push_constant",
"f16", "f16",
}; };

View File

@ -45,20 +45,27 @@ void ExtensionParser(::benchmark::State& state) {
"chromium_exverimentiil_dp4a", "chromium_exverimentiil_dp4a",
"chro8ium_experimenWWal_dp4a", "chro8ium_experimenWWal_dp4a",
"chromiMm_eperimxxntal_dp4a", "chromiMm_eperimxxntal_dp4a",
"chrXmium_experimeggtal_ush_constant", "chromium_expeggimeXtal_full_ptr_paraeters",
"chromiu_experVmentalpusX_constant", "chromium_expVrimental_full_ptr_puraXeer",
"chro3ium_experimental_push_constant", "chromium_experimental_full_ptr3parameters",
"chromium_experimental_full_ptr_parameters",
"chromium_experimentalEfull_ptr_parameters",
"chromium_experimentalfull_ptr_PPaTTameters",
"chromium_ddxperimental_fullptrxxparameters",
"c44romium_experimental_push_constant",
"chromium_experimental_pSSsVV_constant",
"chrom22Rm_experimental_pushRonstant",
"chromium_experimental_push_constant", "chromium_experimental_push_constant",
"chromium_experEmental_push_constant", "chromium_exp9rimFntal_ush_constant",
"chPPomiumexperimental_push_conTTtant", "chrmium_experimental_push_constant",
"chromixxm_experimentddl_push_constnt", "cOOromium_experiVeHtal_puh_conRRtant",
"4416", "y1",
"fSVV6", "l77rrn6",
"RR2", "4016",
"f16", "f16",
"96", "5",
"f1", "u16",
"VOR6", "f",
}; };
for (auto _ : state) { for (auto _ : state) {
for (auto& str : kStrings) { for (auto& str : kStrings) {

View File

@ -44,6 +44,8 @@ inline std::ostream& operator<<(std::ostream& out, Case c) {
static constexpr Case kValidCases[] = { static constexpr Case kValidCases[] = {
{"chromium_disable_uniformity_analysis", Extension::kChromiumDisableUniformityAnalysis}, {"chromium_disable_uniformity_analysis", Extension::kChromiumDisableUniformityAnalysis},
{"chromium_experimental_dp4a", Extension::kChromiumExperimentalDp4A}, {"chromium_experimental_dp4a", Extension::kChromiumExperimentalDp4A},
{"chromium_experimental_full_ptr_parameters",
Extension::kChromiumExperimentalFullPtrParameters},
{"chromium_experimental_push_constant", Extension::kChromiumExperimentalPushConstant}, {"chromium_experimental_push_constant", Extension::kChromiumExperimentalPushConstant},
{"f16", Extension::kF16}, {"f16", Extension::kF16},
}; };
@ -55,12 +57,15 @@ static constexpr Case kInvalidCases[] = {
{"chro1ium_experimental_dp4a", Extension::kUndefined}, {"chro1ium_experimental_dp4a", Extension::kUndefined},
{"chrJmium_experiqqetal_dp4a", Extension::kUndefined}, {"chrJmium_experiqqetal_dp4a", Extension::kUndefined},
{"chromium_experimenll77l_dp4a", Extension::kUndefined}, {"chromium_experimenll77l_dp4a", Extension::kUndefined},
{"cppromium_experiHHenal_qqush_constant", Extension::kUndefined}, {"chroium_experimental_full_ptr_paqqppmetHHrs", Extension::kUndefined},
{"chromium_xpericental_sh_vonstant", Extension::kUndefined}, {"chrium_evperiental_full_ptr_paraceters", Extension::kUndefined},
{"chromium_experimental_Gsh_cbnstant", Extension::kUndefined}, {"chromium_expGimental_fullbptr_parameters", Extension::kUndefined},
{"f1vi", Extension::kUndefined}, {"chvomium_experimental_push_constiint", Extension::kUndefined},
{"f8WW", Extension::kUndefined}, {"chromiu8WWexperimental_push_constant", Extension::kUndefined},
{"fxx", Extension::kUndefined}, {"chromium_experiMental_push_costanxx", Extension::kUndefined},
{"fgg", Extension::kUndefined},
{"X", Extension::kUndefined},
{"316", Extension::kUndefined},
}; };
using ExtensionParseTest = testing::TestWithParam<Case>; using ExtensionParseTest = testing::TestWithParam<Case>;

View File

@ -51,6 +51,9 @@ enum extension {
chromium_disable_uniformity_analysis chromium_disable_uniformity_analysis
// A Chromium-specific extension for push constants // A Chromium-specific extension for push constants
chromium_experimental_push_constant chromium_experimental_push_constant
// A Chromium-specific extension that enables passing of uniform, storage and workgroup
// address-spaced pointers as parameters, as well as pointers into sub-objects.
chromium_experimental_full_ptr_parameters
} }
// https://gpuweb.github.io/gpuweb/wgsl/#storage-class // https://gpuweb.github.io/gpuweb/wgsl/#storage-class

View File

@ -62,7 +62,7 @@ TEST_F(EnableDirectiveTest, InvalidIdentifier) {
// Error when unknown extension found // Error when unknown extension found
EXPECT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), R"(1:8: expected extension EXPECT_EQ(p->error(), R"(1:8: expected extension
Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_push_constant', 'f16')"); Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_push_constant', 'f16')");
auto program = p->program(); auto program = p->program();
auto& ast = program.AST(); auto& ast = program.AST();
EXPECT_EQ(ast.Enables().Length(), 0u); EXPECT_EQ(ast.Enables().Length(), 0u);
@ -75,7 +75,7 @@ TEST_F(EnableDirectiveTest, InvalidIdentifierSuggest) {
// Error when unknown extension found // Error when unknown extension found
EXPECT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), R"(1:8: expected extension. Did you mean 'f16'? EXPECT_EQ(p->error(), R"(1:8: expected extension. Did you mean 'f16'?
Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_push_constant', 'f16')"); Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_push_constant', 'f16')");
auto program = p->program(); auto program = p->program();
auto& ast = program.AST(); auto& ast = program.AST();
EXPECT_EQ(ast.Enables().Length(), 0u); EXPECT_EQ(ast.Enables().Length(), 0u);
@ -123,7 +123,7 @@ TEST_F(EnableDirectiveTest, InvalidTokens) {
p->translation_unit(); p->translation_unit();
EXPECT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), R"(1:8: expected extension EXPECT_EQ(p->error(), R"(1:8: expected extension
Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_push_constant', 'f16')"); Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_push_constant', 'f16')");
auto program = p->program(); auto program = p->program();
auto& ast = program.AST(); auto& ast = program.AST();
EXPECT_EQ(ast.Enables().Length(), 0u); EXPECT_EQ(ast.Enables().Length(), 0u);
@ -134,7 +134,7 @@ Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_
p->translation_unit(); p->translation_unit();
EXPECT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), R"(1:8: expected extension EXPECT_EQ(p->error(), R"(1:8: expected extension
Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_push_constant', 'f16')"); Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_push_constant', 'f16')");
auto program = p->program(); auto program = p->program();
auto& ast = program.AST(); auto& ast = program.AST();
EXPECT_EQ(ast.Enables().Length(), 0u); EXPECT_EQ(ast.Enables().Length(), 0u);
@ -145,7 +145,7 @@ Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_
p->translation_unit(); p->translation_unit();
EXPECT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), R"(1:8: expected extension EXPECT_EQ(p->error(), R"(1:8: expected extension
Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_push_constant', 'f16')"); Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_push_constant', 'f16')");
auto program = p->program(); auto program = p->program();
auto& ast = program.AST(); auto& ast = program.AST();
EXPECT_EQ(ast.Enables().Length(), 0u); EXPECT_EQ(ast.Enables().Length(), 0u);

View File

@ -114,11 +114,29 @@ TEST_F(ResolverCallValidationTest, PointerArgument_VariableIdentExpr) {
EXPECT_TRUE(r()->Resolve()) << r()->error(); EXPECT_TRUE(r()->Resolve()) << r()->error();
} }
TEST_F(ResolverCallValidationTest, PointerArgument_NotWholeVar) { TEST_F(ResolverCallValidationTest, PointerArgument_LetIdentExpr) {
// fn foo(p: ptr<function, i32>) {}
// fn main() {
// let z: i32 = 1i;
// foo(&z);
// }
auto* param = Param("p", ty.pointer<i32>(ast::AddressSpace::kFunction));
Func("foo", utils::Vector{param}, ty.void_(), utils::Empty);
Func("main", utils::Empty, ty.void_(),
utils::Vector{
Decl(Let("z", ty.i32(), Expr(1_i))),
CallStmt(Call("foo", AddressOf(Expr(Source{{12, 34}}, "z")))),
});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: cannot take the address of expression");
}
TEST_F(ResolverCallValidationTest, PointerArgument_AddressOfFunctionMember) {
// struct S { m: i32; }; // struct S { m: i32; };
// fn foo(p: ptr<function, i32>) {} // fn foo(p: ptr<function, i32>) {}
// fn main() { // fn main() {
// var v: S; // var v : S;
// foo(&v.m); // foo(&v.m);
// } // }
auto* S = Structure("S", utils::Vector{ auto* S = Structure("S", utils::Vector{
@ -138,6 +156,51 @@ TEST_F(ResolverCallValidationTest, PointerArgument_NotWholeVar) {
"originating variable"); "originating variable");
} }
TEST_F(ResolverCallValidationTest,
PointerArgument_AddressOfFunctionMember_WithFullPtrParametersExt) {
// enable chromium_experimental_full_ptr_parameters;
// struct S { m: i32; };
// fn foo(p: ptr<function, i32>) {}
// fn main() {
// var v : S;
// foo(&v.m);
// }
Enable(ast::Extension::kChromiumExperimentalFullPtrParameters);
auto* S = Structure("S", utils::Vector{
Member("m", ty.i32()),
});
auto* param = Param("p", ty.pointer<i32>(ast::AddressSpace::kFunction));
Func("foo", utils::Vector{param}, ty.void_(), utils::Empty);
Func("main", utils::Empty, ty.void_(),
utils::Vector{
Decl(Var("v", ty.Of(S))),
CallStmt(Call("foo", AddressOf(Source{{12, 34}}, MemberAccessor("v", "m")))),
});
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
TEST_F(ResolverCallValidationTest, PointerArgument_AddressOfLetMember) {
// struct S { m: i32; };
// fn foo(p: ptr<function, i32>) {}
// fn main() {
// let v: S = S();
// foo(&v.m);
// }
auto* S = Structure("S", utils::Vector{
Member("m", ty.i32()),
});
auto* param = Param("p", ty.pointer<i32>(ast::AddressSpace::kFunction));
Func("foo", utils::Vector{param}, ty.void_(), utils::Empty);
Func("main", utils::Empty, ty.void_(),
utils::Vector{
Decl(Let("v", ty.Of(S), Construct(ty.Of(S)))),
CallStmt(Call("foo", AddressOf(MemberAccessor(Source{{12, 34}}, "v", "m")))),
});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: cannot take the address of expression");
}
TEST_F(ResolverCallValidationTest, PointerArgument_FunctionParam) { TEST_F(ResolverCallValidationTest, PointerArgument_FunctionParam) {
// fn foo(p: ptr<function, i32>) {} // fn foo(p: ptr<function, i32>) {}
// fn bar(p: ptr<function, i32>) { // fn bar(p: ptr<function, i32>) {
@ -181,12 +244,12 @@ TEST_F(ResolverCallValidationTest, PointerArgument_FunctionParamWithMain) {
}, },
ty.void_(), ty.void_(),
utils::Vector{ utils::Vector{
CallStmt(Call("foo", Expr("p"))), CallStmt(Call("foo", "p")),
}); });
Func("main", utils::Empty, ty.void_(), Func("main", utils::Empty, ty.void_(),
utils::Vector{ utils::Vector{
Decl(Var("v", ty.i32(), Expr(1_i))), Decl(Var("v", ty.i32(), Expr(1_i))),
CallStmt(Call("foo", AddressOf(Expr("v")))), CallStmt(Call("foo", AddressOf("v"))),
}, },
utils::Vector{ utils::Vector{
Stage(ast::PipelineStage::kFragment), Stage(ast::PipelineStage::kFragment),
@ -195,40 +258,15 @@ TEST_F(ResolverCallValidationTest, PointerArgument_FunctionParamWithMain) {
EXPECT_TRUE(r()->Resolve()) << r()->error(); EXPECT_TRUE(r()->Resolve()) << r()->error();
} }
TEST_F(ResolverCallValidationTest, PointerArgument_FunctionParam_NotWholeVar) {
// fn foo(p: ptr<function, i32>) {}
// fn bar(p: ptr<function, array<i32, 4>>) {
// foo(&(*p)[0]);
// }
Func("foo",
utils::Vector{
Param("p", ty.pointer<i32>(ast::AddressSpace::kFunction)),
},
ty.void_(), utils::Empty);
Func("bar",
utils::Vector{
Param("p", ty.pointer(ty.array<i32, 4>(), ast::AddressSpace::kFunction)),
},
ty.void_(),
utils::Vector{
CallStmt(Call("foo", AddressOf(Source{{12, 34}}, IndexAccessor(Deref("p"), 0_a)))),
});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"12:34 error: arguments of pointer type must not point to a subset of the "
"originating variable");
}
TEST_F(ResolverCallValidationTest, LetPointer) { TEST_F(ResolverCallValidationTest, LetPointer) {
// fn foo(p : ptr<function, i32>) {} // fn foo(p : ptr<function, i32>) {}
// @fragment // @fragment
// fn main() { // fn main() {
// var v: i32; // var v: i32;
// let p: ptr<function, i32> = &v; // let p: ptr<function, i32> = &v;
// foo(p); // x(p);
// } // }
Func("foo", Func("x",
utils::Vector{ utils::Vector{
Param("p", ty.pointer<i32>(ast::AddressSpace::kFunction)), Param("p", ty.pointer<i32>(ast::AddressSpace::kFunction)),
}, },
@ -237,7 +275,7 @@ TEST_F(ResolverCallValidationTest, LetPointer) {
utils::Vector{ utils::Vector{
Decl(Var("v", ty.i32())), Decl(Var("v", ty.i32())),
Decl(Let("p", ty.pointer(ty.i32(), ast::AddressSpace::kFunction), AddressOf("v"))), Decl(Let("p", ty.pointer(ty.i32(), ast::AddressSpace::kFunction), AddressOf("v"))),
CallStmt(Call("foo", Expr(Source{{12, 34}}, "p"))), CallStmt(Call("x", "p")),
}, },
utils::Vector{ utils::Vector{
Stage(ast::PipelineStage::kFragment), Stage(ast::PipelineStage::kFragment),
@ -247,10 +285,10 @@ TEST_F(ResolverCallValidationTest, LetPointer) {
TEST_F(ResolverCallValidationTest, LetPointerPrivate) { TEST_F(ResolverCallValidationTest, LetPointerPrivate) {
// fn foo(p : ptr<private, i32>) {} // fn foo(p : ptr<private, i32>) {}
// var<private> v: i32; // var v : i32;
// @fragment // @fragment
// fn main() { // fn main() {
// let p: ptr<private, i32> = &v; // let p : ptr<private, i32> = &v;
// foo(p); // foo(p);
// } // }
Func("foo", Func("foo",
@ -299,6 +337,34 @@ TEST_F(ResolverCallValidationTest, LetPointer_NotWholeVar) {
"originating variable"); "originating variable");
} }
TEST_F(ResolverCallValidationTest, LetPointer_NotWholeVar_WithFullPtrParametersExt) {
// enable chromium_experimental_full_ptr_parameters;
// fn foo(p : ptr<function, i32>) {}
// @fragment
// fn main() {
// var v: array<i32, 4>;
// let p: ptr<function, i32> = &(v[0]);
// x(p);
// }
Enable(ast::Extension::kChromiumExperimentalFullPtrParameters);
Func("foo",
utils::Vector{
Param("p", ty.pointer<i32>(ast::AddressSpace::kFunction)),
},
ty.void_(), utils::Empty);
Func("main", utils::Empty, ty.void_(),
utils::Vector{
Decl(Var("v", ty.array<i32, 4>())),
Decl(Let("p", ty.pointer(ty.i32(), ast::AddressSpace::kFunction),
AddressOf(IndexAccessor("v", 0_a)))),
CallStmt(Call("foo", Expr(Source{{12, 34}}, "p"))),
},
utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
EXPECT_TRUE(r()->Resolve());
}
TEST_F(ResolverCallValidationTest, ComplexPointerChain) { TEST_F(ResolverCallValidationTest, ComplexPointerChain) {
// fn foo(p : ptr<function, array<i32, 4>>) {} // fn foo(p : ptr<function, array<i32, 4>>) {}
// @fragment // @fragment
@ -360,6 +426,37 @@ TEST_F(ResolverCallValidationTest, ComplexPointerChain_NotWholeVar) {
"originating variable"); "originating variable");
} }
TEST_F(ResolverCallValidationTest, ComplexPointerChain_NotWholeVar_WithFullPtrParametersExt) {
// enable chromium_experimental_full_ptr_parameters;
// fn foo(p : ptr<function, i32>) {}
// @fragment
// fn main() {
// var v: array<i32, 4>;
// let p1 = &v;
// let p2 = p1;
// let p3 = &(*p2)[0];
// foo(&*p);
// }
Enable(ast::Extension::kChromiumExperimentalFullPtrParameters);
Func("foo",
utils::Vector{
Param("p", ty.pointer<i32>(ast::AddressSpace::kFunction)),
},
ty.void_(), utils::Empty);
Func("main", utils::Empty, ty.void_(),
utils::Vector{
Decl(Var("v", ty.array<i32, 4>())),
Decl(Let("p1", AddressOf("v"))),
Decl(Let("p2", Expr("p1"))),
Decl(Let("p3", AddressOf(IndexAccessor(Deref("p2"), 0_a)))),
CallStmt(Call("foo", AddressOf(Source{{12, 34}}, Deref("p3")))),
},
utils::Vector{
Stage(ast::PipelineStage::kFragment),
});
EXPECT_TRUE(r()->Resolve());
}
TEST_F(ResolverCallValidationTest, CallVariable) { TEST_F(ResolverCallValidationTest, CallVariable) {
// var v : i32; // var v : i32;
// fn f() { // fn f() {

View File

@ -1041,21 +1041,26 @@ TEST_F(ResolverFunctionValidationTest, ParameterMatrixNoType) {
EXPECT_EQ(r()->error(), "12:34 error: missing matrix element type"); EXPECT_EQ(r()->error(), "12:34 error: missing matrix element type");
} }
enum class Expectation {
kAlwaysPass,
kPassWithFullPtrParameterExtension,
kAlwaysFail,
};
struct TestParams { struct TestParams {
ast::AddressSpace address_space; ast::AddressSpace address_space;
bool should_pass; Expectation expectation;
}; };
struct TestWithParams : ResolverTestWithParam<TestParams> {}; struct TestWithParams : ResolverTestWithParam<TestParams> {};
using ResolverFunctionParameterValidationTest = TestWithParams; using ResolverFunctionParameterValidationTest = TestWithParams;
TEST_P(ResolverFunctionParameterValidationTest, AddressSpace) { TEST_P(ResolverFunctionParameterValidationTest, AddressSpaceNoExtension) {
auto& param = GetParam(); auto& param = GetParam();
auto* ptr_type = ty.pointer(Source{{12, 34}}, ty.i32(), param.address_space); auto* ptr_type = ty.pointer(Source{{12, 34}}, ty.i32(), param.address_space);
auto* arg = Param(Source{{12, 34}}, "p", ptr_type); auto* arg = Param(Source{{12, 34}}, "p", ptr_type);
Func("f", utils::Vector{arg}, ty.void_(), utils::Empty); Func("f", utils::Vector{arg}, ty.void_(), utils::Empty);
if (param.should_pass) { if (param.expectation == Expectation::kAlwaysPass) {
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
} else { } else {
std::stringstream ss; std::stringstream ss;
@ -1065,17 +1070,36 @@ TEST_P(ResolverFunctionParameterValidationTest, AddressSpace) {
ss.str() + "' address space"); ss.str() + "' address space");
} }
} }
INSTANTIATE_TEST_SUITE_P(ResolverTest, TEST_P(ResolverFunctionParameterValidationTest, AddressSpaceWithExtension) {
auto& param = GetParam();
auto* ptr_type = ty.pointer(Source{{12, 34}}, ty.i32(), param.address_space);
auto* arg = Param(Source{{12, 34}}, "p", ptr_type);
Enable(ast::Extension::kChromiumExperimentalFullPtrParameters);
Func("f", utils::Vector{arg}, ty.void_(), utils::Empty);
if (param.expectation != Expectation::kAlwaysFail) {
ASSERT_TRUE(r()->Resolve()) << r()->error();
} else {
std::stringstream ss;
ss << param.address_space;
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: function parameter of pointer type cannot be in '" +
ss.str() + "' address space");
}
}
INSTANTIATE_TEST_SUITE_P(
ResolverTest,
ResolverFunctionParameterValidationTest, ResolverFunctionParameterValidationTest,
testing::Values(TestParams{ast::AddressSpace::kNone, false}, testing::Values(
TestParams{ast::AddressSpace::kIn, false}, TestParams{ast::AddressSpace::kNone, Expectation::kAlwaysFail},
TestParams{ast::AddressSpace::kOut, false}, TestParams{ast::AddressSpace::kIn, Expectation::kAlwaysFail},
TestParams{ast::AddressSpace::kUniform, false}, TestParams{ast::AddressSpace::kOut, Expectation::kAlwaysFail},
TestParams{ast::AddressSpace::kWorkgroup, false}, TestParams{ast::AddressSpace::kUniform, Expectation::kPassWithFullPtrParameterExtension},
TestParams{ast::AddressSpace::kHandle, false}, TestParams{ast::AddressSpace::kWorkgroup, Expectation::kPassWithFullPtrParameterExtension},
TestParams{ast::AddressSpace::kStorage, false}, TestParams{ast::AddressSpace::kHandle, Expectation::kAlwaysFail},
TestParams{ast::AddressSpace::kPrivate, true}, TestParams{ast::AddressSpace::kStorage, Expectation::kPassWithFullPtrParameterExtension},
TestParams{ast::AddressSpace::kFunction, true})); TestParams{ast::AddressSpace::kPrivate, Expectation::kAlwaysPass},
TestParams{ast::AddressSpace::kFunction, Expectation::kAlwaysPass}));
} // namespace } // namespace
} // namespace tint::resolver } // namespace tint::resolver

View File

@ -800,17 +800,33 @@ bool Validator::Parameter(const ast::Function* func, const sem::Variable* var) c
} }
if (auto* ref = var->Type()->As<sem::Pointer>()) { if (auto* ref = var->Type()->As<sem::Pointer>()) {
auto address_space = ref->AddressSpace(); if (IsValidationEnabled(decl->attributes, ast::DisabledValidation::kIgnoreAddressSpace)) {
if (!(address_space == ast::AddressSpace::kFunction || bool ok = false;
address_space == ast::AddressSpace::kPrivate) &&
IsValidationEnabled(decl->attributes, ast::DisabledValidation::kIgnoreAddressSpace)) { auto sc = ref->AddressSpace();
switch (sc) {
case ast::AddressSpace::kFunction:
case ast::AddressSpace::kPrivate:
ok = true;
break;
case ast::AddressSpace::kStorage:
case ast::AddressSpace::kUniform:
case ast::AddressSpace::kWorkgroup:
ok = enabled_extensions_.Contains(
ast::Extension::kChromiumExperimentalFullPtrParameters);
break;
default:
break;
}
if (!ok) {
std::stringstream ss; std::stringstream ss;
ss << "function parameter of pointer type cannot be in '" << address_space ss << "function parameter of pointer type cannot be in '" << sc
<< "' address space"; << "' address space";
AddError(ss.str(), decl->source); AddError(ss.str(), decl->source);
return false; return false;
} }
} }
}
if (IsPlain(var->Type())) { if (IsPlain(var->Type())) {
if (!var->Type()->IsConstructible()) { if (!var->Type()->IsConstructible()) {
@ -1654,7 +1670,8 @@ bool Validator::FunctionCall(const sem::Call* call, sem::Statement* current_stat
return false; return false;
} }
if (param_type->Is<sem::Pointer>()) { if (param_type->Is<sem::Pointer>() &&
!enabled_extensions_.Contains(ast::Extension::kChromiumExperimentalFullPtrParameters)) {
// https://gpuweb.github.io/gpuweb/wgsl/#function-restriction // https://gpuweb.github.io/gpuweb/wgsl/#function-restriction
// Each argument of pointer type to a user-defined function must have the same memory // Each argument of pointer type to a user-defined function must have the same memory
// view as its root identifier. // view as its root identifier.