[tint][ir][val] Check results and operands for bitcasts
Checking for sizes matching is deferred to crbug.com/359253674
- Also adds in a couple test cases for CheckConvert, since they follow
the same pattern
Fixes: 358393348
Change-Id: I8aa593157b9b8ef69c344142a7c20105d0a6257f
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/201974
Auto-Submit: Ryan Harrison <rharrison@chromium.org>
Commit-Queue: Ryan Harrison <rharrison@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/tint/lang/core/ir/bitcast.h b/src/tint/lang/core/ir/bitcast.h
index fa28388..a6f5cd1 100644
--- a/src/tint/lang/core/ir/bitcast.h
+++ b/src/tint/lang/core/ir/bitcast.h
@@ -41,6 +41,12 @@
/// The offset in Operands() for the value
static constexpr size_t kValueOperandOffset = 0;
+ /// The fixed number of results returned by this instruction
+ static constexpr size_t kNumResults = 1;
+
+ /// The fixed number of operands expected for this instruction
+ static constexpr size_t kNumOperands = 1;
+
/// Constructor (no results, no operands)
/// @param id the instruction id
explicit Bitcast(Id id);
diff --git a/src/tint/lang/core/ir/validator.cc b/src/tint/lang/core/ir/validator.cc
index 4bb4bd2..44f9ed9 100644
--- a/src/tint/lang/core/ir/validator.cc
+++ b/src/tint/lang/core/ir/validator.cc
@@ -365,6 +365,10 @@
/// @param call the call to validate
void CheckCall(const Call* call);
+ /// Validates the given bitcast
+ /// @param bitcast the bitcast to validate
+ void CheckBitcast(const Bitcast* bitcast);
+
/// Validates the given builtin call
/// @param call the call to validate
void CheckBuiltinCall(const BuiltinCall* call);
@@ -1284,7 +1288,7 @@
void Validator::CheckCall(const Call* call) {
tint::Switch(
call, //
- [&](const Bitcast*) {}, //
+ [&](const Bitcast* b) { CheckBitcast(b); }, //
[&](const BuiltinCall* c) { CheckBuiltinCall(c); }, //
[&](const MemberBuiltinCall* c) { CheckMemberBuiltinCall(c); }, //
[&](const Construct* c) { CheckConstruct(c); }, //
@@ -1296,6 +1300,10 @@
});
}
+void Validator::CheckBitcast(const Bitcast* bitcast) {
+ CheckResultsAndOperands(bitcast, Bitcast::kNumResults, Bitcast::kNumOperands);
+}
+
void Validator::CheckBuiltinCall(const BuiltinCall* call) {
auto args =
Transform<8>(call->Args(), [&](const ir::Value* v) { return v ? v->Type() : nullptr; });
diff --git a/src/tint/lang/core/ir/validator_test.cc b/src/tint/lang/core/ir/validator_test.cc
index 6a36917..05d9681 100644
--- a/src/tint/lang/core/ir/validator_test.cc
+++ b/src/tint/lang/core/ir/validator_test.cc
@@ -922,6 +922,129 @@
)");
}
+TEST_F(IR_ValidatorTest, Bitcast_MissingArg) {
+ auto* f = b.Function("f", ty.void_());
+ b.Append(f->Block(), [&] {
+ auto* bitcast = b.Bitcast(ty.i32(), 1_u);
+ bitcast->ClearOperands();
+ b.Return(f);
+ });
+
+ auto res = ir::Validate(mod);
+ ASSERT_NE(res, Success);
+ EXPECT_EQ(res.Failure().reason.Str(),
+ R"(:3:14 error: bitcast: expected exactly 1 operands, got 0
+ %2:i32 = bitcast
+ ^^^^^^^
+
+:2:3 note: in block
+ $B1: {
+ ^^^
+
+note: # Disassembly
+%f = func():void {
+ $B1: {
+ %2:i32 = bitcast
+ ret
+ }
+}
+)");
+}
+
+TEST_F(IR_ValidatorTest, Bitcast_NullArg) {
+ auto* f = b.Function("f", ty.void_());
+ b.Append(f->Block(), [&] {
+ b.Bitcast(ty.i32(), nullptr);
+ b.Return(f);
+ });
+
+ auto res = ir::Validate(mod);
+ ASSERT_NE(res, Success);
+ EXPECT_EQ(res.Failure().reason.Str(),
+ R"(:3:22 error: bitcast: operand is undefined
+ %2:i32 = bitcast undef
+ ^^^^^
+
+:2:3 note: in block
+ $B1: {
+ ^^^
+
+note: # Disassembly
+%f = func():void {
+ $B1: {
+ %2:i32 = bitcast undef
+ ret
+ }
+}
+)");
+}
+
+TEST_F(IR_ValidatorTest, Bitcast_MissingResult) {
+ auto* f = b.Function("f", ty.void_());
+ b.Append(f->Block(), [&] {
+ auto* bitcast = b.Bitcast(ty.i32(), 1_u);
+ bitcast->ClearResults();
+ b.Return(f);
+ });
+
+ auto res = ir::Validate(mod);
+ ASSERT_NE(res, Success);
+ EXPECT_EQ(res.Failure().reason.Str(),
+ R"(:3:13 error: bitcast: expected exactly 1 results, got 0
+ undef = bitcast 1u
+ ^^^^^^^
+
+:2:3 note: in block
+ $B1: {
+ ^^^
+
+note: # Disassembly
+%f = func():void {
+ $B1: {
+ undef = bitcast 1u
+ ret
+ }
+}
+)");
+}
+
+TEST_F(IR_ValidatorTest, Bitcast_NullResult) {
+ auto* f = b.Function("f", ty.void_());
+ b.Append(f->Block(), [&] {
+ auto* c = b.Bitcast(ty.i32(), 1_u);
+ c->SetResults(Vector<InstructionResult*, 1>{nullptr});
+ b.Return(f);
+ });
+
+ auto res = ir::Validate(mod);
+ ASSERT_NE(res, Success);
+ EXPECT_EQ(res.Failure().reason.Str(),
+ R"(:3:5 error: bitcast: result is undefined
+ undef = bitcast 1u
+ ^^^^^
+
+:2:3 note: in block
+ $B1: {
+ ^^^
+
+:3:5 error: bitcast: result is undefined
+ undef = bitcast 1u
+ ^^^^^
+
+:2:3 note: in block
+ $B1: {
+ ^^^
+
+note: # Disassembly
+%f = func():void {
+ $B1: {
+ undef = bitcast 1u
+ ret
+ }
+}
+)");
+}
+
TEST_F(IR_ValidatorTest, Construct_Struct_ZeroValue) {
auto* str_ty = ty.Struct(mod.symbols.New("MyStruct"), {
{mod.symbols.New("a"), ty.i32()},
@@ -1209,10 +1332,39 @@
)");
}
+TEST_F(IR_ValidatorTest, Convert_MissingArg) {
+ auto* f = b.Function("f", ty.void_());
+ b.Append(f->Block(), [&] {
+ auto* c = b.Convert(ty.i32(), 1_f);
+ c->ClearOperands();
+ b.Return(f);
+ });
+
+ auto res = ir::Validate(mod);
+ ASSERT_NE(res, Success);
+ EXPECT_EQ(res.Failure().reason.Str(),
+ R"(:3:14 error: convert: expected exactly 1 operands, got 0
+ %2:i32 = convert
+ ^^^^^^^
+
+:2:3 note: in block
+ $B1: {
+ ^^^
+
+note: # Disassembly
+%f = func():void {
+ $B1: {
+ %2:i32 = convert
+ ret
+ }
+}
+)");
+}
+
TEST_F(IR_ValidatorTest, Convert_NullArg) {
auto* f = b.Function("f", ty.void_());
b.Append(f->Block(), [&] {
- b.Convert(ty.f32(), nullptr);
+ b.Convert(ty.i32(), nullptr);
b.Return(f);
});
@@ -1220,7 +1372,7 @@
ASSERT_NE(res, Success);
EXPECT_EQ(res.Failure().reason.Str(),
R"(:3:22 error: convert: operand is undefined
- %2:f32 = convert undef
+ %2:i32 = convert undef
^^^^^
:2:3 note: in block
@@ -1230,7 +1382,36 @@
note: # Disassembly
%f = func():void {
$B1: {
- %2:f32 = convert undef
+ %2:i32 = convert undef
+ ret
+ }
+}
+)");
+}
+
+TEST_F(IR_ValidatorTest, Convert_MissingResult) {
+ auto* f = b.Function("f", ty.void_());
+ b.Append(f->Block(), [&] {
+ auto* c = b.Convert(ty.i32(), 1_f);
+ c->ClearResults();
+ b.Return(f);
+ });
+
+ auto res = ir::Validate(mod);
+ ASSERT_NE(res, Success);
+ EXPECT_EQ(res.Failure().reason.Str(),
+ R"(:3:13 error: convert: expected exactly 1 results, got 0
+ undef = convert 1.0f
+ ^^^^^^^
+
+:2:3 note: in block
+ $B1: {
+ ^^^
+
+note: # Disassembly
+%f = func():void {
+ $B1: {
+ undef = convert 1.0f
ret
}
}