Add support for converting bool to other types

The only non-trivial case is SPIR-V, which generates OpSelect to
choose between 1 or 0.

Fixed: tint:997
Change-Id: Ifda7b3ec1e0a713843a2da7ed59c3449d4eec8bd
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/58521
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: James Price <jrprice@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
This commit is contained in:
James Price
2021-07-19 17:35:39 +00:00
committed by Tint LUCI CQ
parent 93d4501e67
commit 1fa28acc7a
14 changed files with 279 additions and 157 deletions

View File

@@ -2752,11 +2752,7 @@ bool Resolver::ValidateVectorConstructor(
// A mismatch of vector type parameter T is only an error if multiple
// arguments are present. A single argument constructor constitutes a
// type conversion expression.
// NOTE: A conversion expression from a vec<bool> to any other vecN<T>
// is disallowed (see
// https://gpuweb.github.io/gpuweb/wgsl.html#conversion-expr).
if (elem_type != value_elem_type &&
(values.size() > 1u || value_vec->is_bool_vector())) {
if (elem_type != value_elem_type && values.size() > 1u) {
AddError(
"type in vector constructor does not match vector type: "
"expected '" +
@@ -2878,11 +2874,10 @@ bool Resolver::ValidateScalarConstructor(
using U32 = sem::U32;
using F32 = sem::F32;
const bool is_valid =
(type->Is<Bool>() && value_type->IsAnyOf<Bool, I32, U32, F32>()) ||
(type->Is<I32>() && value_type->IsAnyOf<I32, U32, F32>()) ||
(type->Is<U32>() && value_type->IsAnyOf<I32, U32, F32>()) ||
(type->Is<F32>() && value_type->IsAnyOf<I32, U32, F32>());
const bool is_valid = (type->Is<Bool>() && value_type->is_scalar()) ||
(type->Is<I32>() && value_type->is_scalar()) ||
(type->Is<U32>() && value_type->is_scalar()) ||
(type->Is<F32>() && value_type->is_scalar());
if (!is_valid) {
AddError("cannot construct '" + type_name + "' with a value of type '" +
TypeNameOf(value) + "'",

View File

@@ -255,27 +255,33 @@ static constexpr Params valid_cases[] = {
ParamsFor<bool, i32>(), //
ParamsFor<bool, f32>(), //
ParamsFor<i32, u32>(), //
ParamsFor<i32, f32>(), //
ParamsFor<i32, bool>(), //
ParamsFor<i32, u32>(), //
ParamsFor<i32, f32>(), //
ParamsFor<u32, i32>(), //
ParamsFor<u32, f32>(), //
ParamsFor<u32, bool>(), //
ParamsFor<u32, i32>(), //
ParamsFor<u32, f32>(), //
ParamsFor<f32, u32>(), //
ParamsFor<f32, i32>(), //
ParamsFor<f32, bool>(), //
ParamsFor<f32, u32>(), //
ParamsFor<f32, i32>(), //
ParamsFor<vec3<bool>, vec3<u32>>(), //
ParamsFor<vec3<bool>, vec3<i32>>(), //
ParamsFor<vec3<bool>, vec3<f32>>(), //
ParamsFor<vec3<i32>, vec3<u32>>(), //
ParamsFor<vec3<i32>, vec3<f32>>(), //
ParamsFor<vec3<i32>, vec3<bool>>(), //
ParamsFor<vec3<i32>, vec3<u32>>(), //
ParamsFor<vec3<i32>, vec3<f32>>(), //
ParamsFor<vec3<u32>, vec3<i32>>(), //
ParamsFor<vec3<u32>, vec3<f32>>(), //
ParamsFor<vec3<u32>, vec3<bool>>(), //
ParamsFor<vec3<u32>, vec3<i32>>(), //
ParamsFor<vec3<u32>, vec3<f32>>(), //
ParamsFor<vec3<f32>, vec3<u32>>(), //
ParamsFor<vec3<f32>, vec3<i32>>(), //
ParamsFor<vec3<f32>, vec3<bool>>(), //
ParamsFor<vec3<f32>, vec3<u32>>(), //
ParamsFor<vec3<f32>, vec3<i32>>(), //
};
using ConversionConstructorValidTest = ResolverTestWithParam<Params>;
@@ -388,13 +394,15 @@ TEST_F(ResolverTypeConstructorValidationTest,
TEST_F(ResolverTypeConstructorValidationTest,
ConversionConstructorInvalid_InvalidInitializer) {
auto* a = Var("a", ty.f32(), ast::StorageClass::kNone,
Construct(Source{{12, 34}}, ty.f32(), Expr(true)));
auto* a =
Var("a", ty.f32(), ast::StorageClass::kNone,
Construct(Source{{12, 34}}, ty.f32(), Construct(ty.array<f32, 4>())));
WrapInFunction(a);
ASSERT_FALSE(r()->Resolve());
ASSERT_EQ(r()->error(),
"12:34 error: cannot construct 'f32' with a value of type 'bool'");
"12:34 error: cannot construct 'f32' with a value of type "
"'array<f32, 4>'");
}
} // namespace ConversionConstructorTest
@@ -716,20 +724,6 @@ TEST_F(ResolverTypeConstructorValidationTest,
"12:34 error: attempted to construct 'vec2<f32>' with 3 component(s)");
}
TEST_F(ResolverTypeConstructorValidationTest,
Expr_Constructor_Vec2_Error_InvalidConversionFromVec2Bool) {
SetSource(Source::Location({12, 34}));
auto* tc = vec2<f32>(create<ast::TypeConstructorExpression>(
Source{{12, 34}}, ty.vec2<bool>(), ExprList()));
WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"12:34 error: type in vector constructor does not match vector "
"type: expected 'f32', found 'bool'");
}
TEST_F(ResolverTypeConstructorValidationTest,
Expr_Constructor_Vec2_Error_InvalidArgumentType) {
auto* tc = vec2<f32>(create<ast::TypeConstructorExpression>(
@@ -986,18 +980,6 @@ TEST_F(ResolverTypeConstructorValidationTest,
"12:34 error: attempted to construct 'vec3<f32>' with 4 component(s)");
}
TEST_F(ResolverTypeConstructorValidationTest,
Expr_Constructor_Vec3_Error_InvalidConversionFromVec3Bool) {
auto* tc = vec3<f32>(create<ast::TypeConstructorExpression>(
Source{{12, 34}}, ty.vec3<bool>(), ExprList()));
WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"12:34 error: type in vector constructor does not match vector "
"type: expected 'f32', found 'bool'");
}
TEST_F(ResolverTypeConstructorValidationTest,
Expr_Constructor_Vec3_Error_InvalidArgumentType) {
auto* tc = vec3<f32>(create<ast::TypeConstructorExpression>(
@@ -1348,18 +1330,6 @@ TEST_F(ResolverTypeConstructorValidationTest,
"12:34 error: attempted to construct 'vec4<f32>' with 6 component(s)");
}
TEST_F(ResolverTypeConstructorValidationTest,
Expr_Constructor_Vec4_Error_InvalidConversionFromVec4Bool) {
auto* tc = vec4<f32>(create<ast::TypeConstructorExpression>(
Source{{12, 34}}, ty.vec4<bool>(), ExprList()));
WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"12:34 error: type in vector constructor does not match vector "
"type: expected 'f32', found 'bool'");
}
TEST_F(ResolverTypeConstructorValidationTest,
Expr_Constructor_Vec4_Error_InvalidArgumentType) {
auto* tc = vec4<f32>(create<ast::TypeConstructorExpression>(