[ir] Validate store instructions
Bug: tint:1952
Change-Id: I6ca60336c7b0f6cc0c134f5f0c742ac62d12b504
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/152461
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/tint/lang/core/ir/disassembler.cc b/src/tint/lang/core/ir/disassembler.cc
index a7682b3..079fe43 100644
--- a/src/tint/lang/core/ir/disassembler.cc
+++ b/src/tint/lang/core/ir/disassembler.cc
@@ -449,9 +449,9 @@
[&](Store* s) {
EmitInstructionName(s);
out_ << " ";
- EmitValue(s->To());
+ EmitOperand(s, Store::kToOperandOffset);
out_ << ", ";
- EmitValue(s->From());
+ EmitOperand(s, Store::kFromOperandOffset);
},
[&](StoreVectorElement* s) {
EmitInstructionName(s);
diff --git a/src/tint/lang/core/ir/transform/block_decorated_structs_test.cc b/src/tint/lang/core/ir/transform/block_decorated_structs_test.cc
index 4ef9c26..5526360 100644
--- a/src/tint/lang/core/ir/transform/block_decorated_structs_test.cc
+++ b/src/tint/lang/core/ir/transform/block_decorated_structs_test.cc
@@ -249,7 +249,8 @@
b.RootBlock()->Append(private_var);
auto* func = b.Function("foo", ty.void_());
- func->Block()->Append(b.Store(buffer, private_var));
+ auto* load = func->Block()->Append(b.Load(private_var));
+ func->Block()->Append(b.Store(buffer, load));
func->Block()->Append(b.Return(func));
auto* expect = R"(
@@ -269,8 +270,9 @@
%foo = func():void -> %b2 {
%b2 = block {
- %4:ptr<storage, MyStruct, read_write> = access %1, 0u
- store %4, %2
+ %4:MyStruct = load %2
+ %5:ptr<storage, MyStruct, read_write> = access %1, 0u
+ store %5, %4
ret
}
}
diff --git a/src/tint/lang/core/ir/validator.cc b/src/tint/lang/core/ir/validator.cc
index c2ffd81..b40e9bc 100644
--- a/src/tint/lang/core/ir/validator.cc
+++ b/src/tint/lang/core/ir/validator.cc
@@ -246,6 +246,10 @@
/// @param l the exit loop to validate
void CheckExitLoop(ExitLoop* l);
+ /// Validates the given store
+ /// @param s the store to validate
+ void CheckStore(Store* s);
+
/// Validates the given load vector element
/// @param l the load vector element to validate
void CheckLoadVectorElement(LoadVectorElement* l);
@@ -483,7 +487,7 @@
[&](Load*) {}, //
[&](LoadVectorElement* l) { CheckLoadVectorElement(l); }, //
[&](Loop* l) { CheckLoop(l); }, //
- [&](Store*) {}, //
+ [&](Store* s) { CheckStore(s); }, //
[&](StoreVectorElement* s) { CheckStoreVectorElement(s); }, //
[&](Switch* s) { CheckSwitch(s); }, //
[&](Swizzle*) {}, //
@@ -794,6 +798,19 @@
}
}
+void Validator::CheckStore(Store* s) {
+ CheckOperandsNotNull(s, Store::kToOperandOffset, Store::kFromOperandOffset);
+
+ if (auto* from = s->From()) {
+ if (auto* to = s->To()) {
+ if (from->Type() != to->Type()->UnwrapPtr()) {
+ AddError(s, Store::kFromOperandOffset,
+ "value type does not match pointer element type");
+ }
+ }
+ }
+}
+
void Validator::CheckLoadVectorElement(LoadVectorElement* l) {
CheckOperandsNotNull(l, //
LoadVectorElement::kFromOperandOffset,
diff --git a/src/tint/lang/core/ir/validator_test.cc b/src/tint/lang/core/ir/validator_test.cc
index 52aad79..777cd01 100644
--- a/src/tint/lang/core/ir/validator_test.cc
+++ b/src/tint/lang/core/ir/validator_test.cc
@@ -2735,6 +2735,94 @@
)");
}
+TEST_F(IR_ValidatorTest, Store_NullTo) {
+ auto* f = b.Function("my_func", ty.void_());
+
+ b.Append(f->Block(), [&] {
+ b.Append(mod.instructions.Create<ir::Store>(nullptr, b.Constant(42_i)));
+ b.Return(f);
+ });
+
+ auto res = ir::Validate(mod);
+ ASSERT_FALSE(res);
+ EXPECT_EQ(res.Failure().str(), R"(:3:11 error: store: operand is undefined
+ store undef, 42i
+ ^^^^^
+
+:2:3 note: In block
+ %b1 = block {
+ ^^^^^^^^^^^
+
+note: # Disassembly
+%my_func = func():void -> %b1 {
+ %b1 = block {
+ store undef, 42i
+ ret
+ }
+}
+)");
+}
+
+TEST_F(IR_ValidatorTest, Store_NullFrom) {
+ auto* f = b.Function("my_func", ty.void_());
+
+ b.Append(f->Block(), [&] {
+ auto* var = b.Var(ty.ptr<function, i32>());
+ b.Append(mod.instructions.Create<ir::Store>(var->Result(), nullptr));
+ b.Return(f);
+ });
+
+ auto res = ir::Validate(mod);
+ ASSERT_FALSE(res);
+ EXPECT_EQ(res.Failure().str(), R"(:4:15 error: store: operand is undefined
+ store %2, undef
+ ^^^^^
+
+:2:3 note: In block
+ %b1 = block {
+ ^^^^^^^^^^^
+
+note: # Disassembly
+%my_func = func():void -> %b1 {
+ %b1 = block {
+ %2:ptr<function, i32, read_write> = var
+ store %2, undef
+ ret
+ }
+}
+)");
+}
+
+TEST_F(IR_ValidatorTest, Store_TypeMismatch) {
+ auto* f = b.Function("my_func", ty.void_());
+
+ b.Append(f->Block(), [&] {
+ auto* var = b.Var(ty.ptr<function, i32>());
+ b.Append(mod.instructions.Create<ir::Store>(var->Result(), b.Constant(42_u)));
+ b.Return(f);
+ });
+
+ auto res = ir::Validate(mod);
+ ASSERT_FALSE(res);
+ EXPECT_EQ(res.Failure().str(), R"(:4:15 error: value type does not match pointer element type
+ store %2, 42u
+ ^^^
+
+:2:3 note: In block
+ %b1 = block {
+ ^^^^^^^^^^^
+
+note: # Disassembly
+%my_func = func():void -> %b1 {
+ %b1 = block {
+ %2:ptr<function, i32, read_write> = var
+ store %2, 42u
+ ret
+ }
+}
+)");
+}
+
TEST_F(IR_ValidatorTest, LoadVectorElement_NullResult) {
auto* f = b.Function("my_func", ty.void_());
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.cc b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.cc
index a479310..d4d758b 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.cc
+++ b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.cc
@@ -2386,7 +2386,7 @@
b.Append(loop->Initializer(), [&] {
auto* load_i = b.Load(i);
- auto* inc_i = b.Add(ty.i32(), load_i, 1_u);
+ auto* inc_i = b.Add(ty.u32(), load_i, 1_u);
b.Store(i, inc_i);
b.NextIteration(loop);
});