tint: Implement `f16` keyword in Tint frontend
This patch:
1. Add the `f16` WGSL extension.
2. Add `f16` as keyword, and remove it from reserved word list.
3. Add ast::f16 and sem::f16, and implement validation that using `f16`
type must be with `f16` extension enabled.
4. Add `Number<NumberKindF16>` for f16 literal and constant, and add
`ast::FloatLiteralExpression::Suffix::kH`.
5. Add placeholder in all writer which report error when try to emit f16
type.
Bugs: tint:1473, tint:1502
Change-Id: Ifb363beeb2699ed7cac57e07227d1b2cfa8050b4
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/89922
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Zhaoming Jiang <zhaoming.jiang@intel.com>
diff --git a/src/tint/resolver/dependency_graph.cc b/src/tint/resolver/dependency_graph.cc
index 94efafb..7e66899 100644
--- a/src/tint/resolver/dependency_graph.cc
+++ b/src/tint/resolver/dependency_graph.cc
@@ -342,7 +342,7 @@
TraverseType(tex->type);
},
[&](Default) {
- if (!ty->IsAnyOf<ast::Void, ast::Bool, ast::I32, ast::U32, ast::F32,
+ if (!ty->IsAnyOf<ast::Void, ast::Bool, ast::I32, ast::U32, ast::F16, ast::F32,
ast::DepthTexture, ast::DepthMultisampledTexture,
ast::StorageTexture, ast::ExternalTexture, ast::Sampler>()) {
UnhandledNode(diagnostics_, ty);
diff --git a/src/tint/resolver/resolver.cc b/src/tint/resolver/resolver.cc
index 962dd02..38a5025 100644
--- a/src/tint/resolver/resolver.cc
+++ b/src/tint/resolver/resolver.cc
@@ -172,6 +172,14 @@
[&](const ast::Bool*) { return builder_->create<sem::Bool>(); },
[&](const ast::I32*) { return builder_->create<sem::I32>(); },
[&](const ast::U32*) { return builder_->create<sem::U32>(); },
+ [&](const ast::F16* t) -> sem::F16* {
+ // Validate if f16 type is allowed.
+ if (builder_->AST().Extensions().count(ast::Enable::ExtensionKind::kF16) == 0) {
+ AddError("f16 used without 'f16' extension enabled", t->source);
+ return nullptr;
+ }
+ return builder_->create<sem::F16>();
+ },
[&](const ast::F32*) { return builder_->create<sem::F32>(); },
[&](const ast::Vector* t) -> sem::Vector* {
if (!t->type) {
diff --git a/src/tint/resolver/resolver_constants.cc b/src/tint/resolver/resolver_constants.cc
index 2a8a1d1..3ec6f94 100644
--- a/src/tint/resolver/resolver_constants.cc
+++ b/src/tint/resolver/resolver_constants.cc
@@ -70,6 +70,10 @@
if (elem_type->Is<sem::U32>()) {
return sem::Constant(type, sem::Constant::Scalars(result_size, 0_u));
}
+ // Add f16 zero scalar here
+ if (elem_type->Is<sem::F16>()) {
+ return sem::Constant(type, sem::Constant::Scalars(result_size, f16{0.f}));
+ }
if (elem_type->Is<sem::F32>()) {
return sem::Constant(type, sem::Constant::Scalars(result_size, 0_f));
}
@@ -120,6 +124,11 @@
return u32(static_cast<uint32_t>(s));
});
},
+ [&](const sem::F16*) {
+ return value.WithScalarAt(i, [](auto&& s) { //
+ return f16{static_cast<float>(s)};
+ });
+ },
[&](const sem::F32*) {
return value.WithScalarAt(i, [](auto&& s) { //
return static_cast<f32>(s);
diff --git a/src/tint/resolver/type_validation_test.cc b/src/tint/resolver/type_validation_test.cc
index 90e18e1..4c2f56d 100644
--- a/src/tint/resolver/type_validation_test.cc
+++ b/src/tint/resolver/type_validation_test.cc
@@ -662,6 +662,24 @@
EXPECT_EQ(r()->error(), "error: cannot use builtin 'max' as type");
}
+TEST_F(ResolverTypeValidationTest, F16TypeUsedWithExtension) {
+ // enable f16;
+ // var<private> v : f16;
+ auto* ext = create<ast::Enable>("f16");
+ AST().AddEnable(ext);
+ Global("v", ty.f16(), ast::StorageClass::kPrivate);
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverTypeValidationTest, F16TypeUsedWithoutExtension) {
+ // var<private> v : f16;
+ Global("v", ty.f16(), ast::StorageClass::kPrivate);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "error: f16 used without 'f16' extension enabled");
+}
+
namespace GetCanonicalTests {
struct Params {
builder::ast_type_func_ptr create_ast_type;
diff --git a/src/tint/resolver/validator.cc b/src/tint/resolver/validator.cc
index 7a66ec4..df9c7c0 100644
--- a/src/tint/resolver/validator.cc
+++ b/src/tint/resolver/validator.cc
@@ -194,7 +194,7 @@
// https://gpuweb.github.io/gpuweb/wgsl.html#host-shareable-types
bool Validator::IsHostShareable(const sem::Type* type) const {
- if (type->IsAnyOf<sem::I32, sem::U32, sem::F32>()) {
+ if (type->IsAnyOf<sem::I32, sem::U32, sem::F32, sem::F16>()) {
return true;
}
return Switch(
@@ -1890,11 +1890,13 @@
using Bool = sem::Bool;
using I32 = sem::I32;
using U32 = sem::U32;
+ using F16 = sem::F16;
using F32 = sem::F32;
const bool is_valid =
(ty->Is<Bool>() && value_ty->is_scalar()) || (ty->Is<I32>() && value_ty->is_scalar()) ||
- (ty->Is<U32>() && value_ty->is_scalar()) || (ty->Is<F32>() && value_ty->is_scalar());
+ (ty->Is<U32>() && value_ty->is_scalar()) || (ty->Is<F16>() && value_ty->is_scalar()) ||
+ (ty->Is<F32>() && value_ty->is_scalar());
if (!is_valid) {
AddError("cannot construct '" + sem_.TypeNameOf(ty) + "' with a value of type '" +
sem_.TypeNameOf(value_ty) + "'",