[ir] Check for duplicate result usage.

Update the validator to catch a duplicate result usage in a single
instruction.

Fixed: 440157913
Change-Id: I3a85c83870d5627542117f6db501dfc0b94f4df7
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/259054
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
diff --git a/src/tint/lang/core/ir/validator.cc b/src/tint/lang/core/ir/validator.cc
index f3e2491..82b765d 100644
--- a/src/tint/lang/core/ir/validator.cc
+++ b/src/tint/lang/core/ir/validator.cc
@@ -1732,10 +1732,16 @@
     }
 
     bool passed = true;
+    Hashset<const InstructionResult*, 4> seen_instruction_results;
     for (size_t i = 0; i < inst->Results().Length(); i++) {
         if (DAWN_UNLIKELY(!CheckResult(inst, i))) {
             passed = false;
         }
+
+        if (!seen_instruction_results.Add(inst->Result(i))) {
+            AddResultError(inst, i) << "result was seen previously as a result";
+            passed = false;
+        }
     }
     return passed;
 }
diff --git a/src/tint/lang/core/ir/validator_test.cc b/src/tint/lang/core/ir/validator_test.cc
index ab3fb26..5a5cdc5 100644
--- a/src/tint/lang/core/ir/validator_test.cc
+++ b/src/tint/lang/core/ir/validator_test.cc
@@ -1075,6 +1075,26 @@
 )")) << res.Failure();
 }
 
+TEST_F(IR_ValidatorTest, Instruction_DuplicateResultOneCall) {
+    auto* f = b.Function("my_func", ty.void_());
+
+    b.Append(f->Block(), [&] {
+        auto* l = b.Loop();
+        auto* r1 = b.InstructionResult(ty.u32());
+        l->SetResults(Vector{r1, r1});
+        b.Append(l->Body(), [&] { b.Unreachable(); });
+        b.Return(f);
+    });
+
+    auto res = ir::Validate(mod);
+    ASSERT_NE(res, Success);
+    EXPECT_THAT(res.Failure().reason,
+                testing::HasSubstr(R"(:3:13 error: loop: result was seen previously as a result
+    %2:u32, %2:u32 = loop [b: $B2] {  # loop_1
+            ^^^^^^)"))
+        << res.Failure();
+}
+
 TEST_F(IR_ValidatorTest, Instruction_WrongInstructionResultInstruction) {
     auto* f = b.Function("my_func", ty.void_());