tint: Support dot4I8Packed and dot4U8Packed in sem

This patch adds the support of dot4I8Packed and dot4U8Packed in
semantics under the extension "chromium_experimental_dp4a".

Bug: tint:1497
Test: tint_unittests
Change-Id: I659172fcb8953ba13b49664c6c9ad75724ff5957
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/88962
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
Jiawei Shao 2022-05-10 09:05:54 +00:00 committed by Dawn LUCI CQ
parent 4b6d3f4346
commit 6c9e475211
14 changed files with 2921 additions and 2724 deletions

View File

@ -22,6 +22,10 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::Enable);
namespace tint::ast {
Enable::ExtensionKind Enable::NameToKind(const std::string& name) {
if (name == "chromium_experimental_dp4a") {
return Enable::ExtensionKind::kChromiumExperimentalDP4a;
}
// The reserved internal extension name for testing
if (name == "InternalExtensionForTesting") {
return Enable::ExtensionKind::kInternalExtensionForTesting;
@ -32,6 +36,8 @@ Enable::ExtensionKind Enable::NameToKind(const std::string& name) {
std::string Enable::KindToName(ExtensionKind kind) {
switch (kind) {
case ExtensionKind::kChromiumExperimentalDP4a:
return "chromium_experimental_dp4a";
// The reserved internal extension for testing
case ExtensionKind::kInternalExtensionForTesting:
return "InternalExtensionForTesting";

View File

@ -32,6 +32,11 @@ class Enable : public Castable<Enable, Node> {
public:
/// The enum class identifing each supported WGSL extension
enum class ExtensionKind {
/// An extension for the experimental feature
/// "chromium_experimental_dp4a".
/// See crbug.com/tint/1497 for more details
kChromiumExperimentalDP4a,
/// An internal reserved extension for test, named
/// "InternalExtensionForTesting"
kInternalExtensionForTesting = -2,

View File

@ -300,6 +300,8 @@ fn determinant<N: num>(mat<N, N, f32>) -> f32
fn distance(f32, f32) -> f32
fn distance<N: num>(vec<N, f32>, vec<N, f32>) -> f32
fn dot<N: num, T: fiu32>(vec<N, T>, vec<N, T>) -> T
fn dot4I8Packed(u32, u32) -> i32
fn dot4U8Packed(u32, u32) -> u32
[[stage("fragment")]] fn dpdx(f32) -> f32
[[stage("fragment")]] fn dpdx<N: num>(vec<N, f32>) -> vec<N, f32>
[[stage("fragment")]] fn dpdxCoarse(f32) -> f32

View File

@ -371,5 +371,71 @@ INSTANTIATE_TEST_SUITE_P(
} // namespace texture_constexpr_args
// TODO(crbug.com/tint/1497): Update or remove ResolverDP4aExtensionValidationTest when the
// experimental extension chromium_experimental_dp4a is not needed.
using ResolverDP4aExtensionValidationTest = ResolverTest;
TEST_F(ResolverDP4aExtensionValidationTest, Dot4I8PackedWithExtension) {
// enable chromium_experimental_dp4a;
// fn func { return dot4I8Packed(1u, 2u); }
auto* ext =
create<ast::Enable>(Source{Source::Range{Source::Location{10, 2}, Source::Location{10, 5}}},
"chromium_experimental_dp4a");
AST().AddEnable(ext);
Func("func", {}, ty.i32(),
{
Return(Call(Source{Source::Location{12, 34}}, "dot4I8Packed",
ast::ExpressionList{Expr(1_u), Expr(2_u)})),
});
EXPECT_TRUE(r()->Resolve());
}
TEST_F(ResolverDP4aExtensionValidationTest, Dot4I8PackedWithoutExtension) {
// fn func { return dot4I8Packed(1u, 2u); }
Func("func", {}, ty.i32(),
{
Return(Call(Source{Source::Location{12, 34}}, "dot4I8Packed",
ast::ExpressionList{Expr(1_u), Expr(2_u)})),
});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
R"(12:34 error: cannot call built-in function 'dot4I8Packed' without extension chromium_experimental_dp4a)");
}
TEST_F(ResolverDP4aExtensionValidationTest, Dot4U8PackedWithExtension) {
// enable chromium_experimental_dp4a;
// fn func { return dot4U8Packed(1u, 2u); }
auto* ext =
create<ast::Enable>(Source{Source::Range{Source::Location{10, 2}, Source::Location{10, 5}}},
"chromium_experimental_dp4a");
AST().AddEnable(ext);
Func("func", {}, ty.u32(),
{
Return(Call(Source{Source::Location{12, 34}}, "dot4U8Packed",
ast::ExpressionList{Expr(1_u), Expr(2_u)})),
});
EXPECT_TRUE(r()->Resolve());
}
TEST_F(ResolverDP4aExtensionValidationTest, Dot4U8PackedWithoutExtension) {
// fn func { return dot4U8Packed(1u, 2u); }
Func("func", {}, ty.u32(),
{
Return(Call(Source{Source::Location{12, 34}}, "dot4U8Packed",
ast::ExpressionList{Expr(1_u), Expr(2_u)})),
});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
R"(12:34 error: cannot call built-in function 'dot4U8Packed' without extension chromium_experimental_dp4a)");
}
} // namespace
} // namespace tint::resolver

File diff suppressed because it is too large Load Diff

View File

@ -1309,6 +1309,10 @@ sem::Call* Resolver::BuiltinCall(const ast::CallExpression* expr,
current_function_->AddDirectlyCalledBuiltin(builtin);
if (!validator_.RequiredExtensionForBuiltinFunction(call, builder_->AST().Extensions())) {
return nullptr;
}
if (IsTextureBuiltin(builtin_type)) {
if (!validator_.TextureBuiltinFunction(call)) {
return nullptr;

View File

@ -1517,6 +1517,28 @@ bool Validator::TextureBuiltinFunction(const sem::Call* call) const {
check_arg_is_constexpr(sem::ParameterUsage::kComponent, 0, 3);
}
bool Validator::RequiredExtensionForBuiltinFunction(const sem::Call* call,
const ast::ExtensionSet& extensionSet) const {
const auto* builtin = call->Target()->As<sem::Builtin>();
if (!builtin) {
return true;
}
const auto extension = builtin->RequiredExtension();
if (extension == ast::Enable::ExtensionKind::kNotAnExtension) {
return true;
}
if (extensionSet.find(extension) == extensionSet.cend()) {
AddError("cannot call built-in function '" + std::string(builtin->str()) +
"' without extension " + ast::Enable::KindToName(extension),
call->Declaration()->source);
return false;
}
return true;
}
bool Validator::FunctionCall(const sem::Call* call, sem::Statement* current_statement) const {
auto* decl = call->Declaration();
auto* target = call->Target()->As<sem::Function>();

View File

@ -373,6 +373,13 @@ class Validator {
/// @returns true on success, false otherwise
bool TextureBuiltinFunction(const sem::Call* call) const;
/// Validates an optional builtin function and its required extension.
/// @param call the builtin call to validate
/// @param extensionSet all the extensions declared in current module
/// @returns true on success, false otherwise
bool RequiredExtensionForBuiltinFunction(const sem::Call* call,
const ast::ExtensionSet& extensionSet) const;
/// Validates there are no duplicate attributes
/// @param attributes the list of attributes to validate
/// @returns true on success, false otherwise.

View File

@ -145,6 +145,16 @@ bool Builtin::HasSideEffects() const {
return false;
}
ast::Enable::ExtensionKind Builtin::RequiredExtension() const {
switch (type_) {
case sem::BuiltinType::kDot4I8Packed:
case sem::BuiltinType::kDot4U8Packed:
return ast::Enable::ExtensionKind::kChromiumExperimentalDP4a;
default:
return ast::Enable::ExtensionKind::kNotAnExtension;
}
}
} // namespace tint::sem
//! @endcond

View File

@ -134,6 +134,10 @@ class Builtin final : public Castable<Builtin, CallTarget> {
/// one of its inputs)
bool HasSideEffects() const;
/// @returns the required extension of this builtin function. Returns
/// ast::Enable::ExtensionKind::kNotAnExtension if no extension is required.
ast::Enable::ExtensionKind RequiredExtension() const;
private:
const BuiltinType type_;
const PipelineStageSet supported_stages_;

View File

@ -56,6 +56,8 @@ INSTANTIATE_TEST_SUITE_P(
BuiltinData{"determinant", BuiltinType::kDeterminant},
BuiltinData{"distance", BuiltinType::kDistance},
BuiltinData{"dot", BuiltinType::kDot},
BuiltinData{"dot4I8Packed", BuiltinType::kDot4I8Packed},
BuiltinData{"dot4U8Packed", BuiltinType::kDot4U8Packed},
BuiltinData{"dpdx", BuiltinType::kDpdx},
BuiltinData{"dpdxCoarse", BuiltinType::kDpdxCoarse},
BuiltinData{"dpdxFine", BuiltinType::kDpdxFine},

View File

@ -89,6 +89,12 @@ BuiltinType ParseBuiltinType(const std::string& name) {
if (name == "dot") {
return BuiltinType::kDot;
}
if (name == "dot4I8Packed") {
return BuiltinType::kDot4I8Packed;
}
if (name == "dot4U8Packed") {
return BuiltinType::kDot4U8Packed;
}
if (name == "dpdx") {
return BuiltinType::kDpdx;
}
@ -391,6 +397,10 @@ const char* str(BuiltinType i) {
return "distance";
case BuiltinType::kDot:
return "dot";
case BuiltinType::kDot4I8Packed:
return "dot4I8Packed";
case BuiltinType::kDot4U8Packed:
return "dot4U8Packed";
case BuiltinType::kDpdx:
return "dpdx";
case BuiltinType::kDpdxCoarse:

View File

@ -53,6 +53,8 @@ enum class BuiltinType {
kDeterminant,
kDistance,
kDot,
kDot4I8Packed,
kDot4U8Packed,
kDpdx,
kDpdxCoarse,
kDpdxFine,

View File

@ -9,10 +9,11 @@ See:
--------------------------------------------------------------------------------
*/ -}}
{{- /* For each permutation of each overload of each builtin... */ -}}
{{- /* For each permutation of each overload of each function... */ -}}
{{- range .Sem.Builtins -}}
{{- /* TODO(crbug.com/tint/1483): Remove the bodge below after smoothStep is removed from builtins.def */}}
{{- if not (eq .Name "smoothStep") }}
{{- /* TODO(crbug.com/tint/1483): Remove the bodge below after smoothStep is removed from intrinsics.def */}}
{{- /* TODO(crbug.com/tint/1536): Remove the bodge below after we support [[extension("extension_name")]] in intrinsics.def */}}
{{- if not (or (eq .Name "smoothStep") (eq .Name "dot4I8Packed") (eq .Name "dot4U8Packed"))}}
{{- range .Overloads -}}
{{- range Permute . -}}
{{- /* Generate a ./gen/<function>/<permuataion-hash>.wgsl file using