[spirv-reader][ir] Make AddOperandToTerminator smarter.

The only case where we need to fill in the terminator operand later is
if an `OpPhi` refers to a value after the phi. This means, we can just
add any constant value, or any known value to the terminator
immediately.

Bug: 429625248
Change-Id: I1d25fb70c4cfe03799a7e71517fac20b226d23f8
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/251635
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/tint/lang/spirv/reader/parser/parser.cc b/src/tint/lang/spirv/reader/parser/parser.cc
index 2436fe4..e1d253c 100644
--- a/src/tint/lang/spirv/reader/parser/parser.cc
+++ b/src/tint/lang/spirv/reader/parser/parser.cc
@@ -1201,6 +1201,10 @@
         return src;
     }
 
+    // Returns true if the value is a constant value
+    bool IdIsConstant(uint32_t id) { return SpvConstant(id) || spec_composites_.contains(id); }
+
+    // Returns true if this value is currently in scope
     bool IdIsInScope(uint32_t id) {
         for (auto iter = id_stack_.rbegin(); iter != id_stack_.rend(); ++iter) {
             if (iter->count(id) > 0) {
@@ -2208,10 +2212,22 @@
         EmitPhiInLoopContinue(inst);
     }
 
-    // Push a placeholder for the operand value. We store away the terminator/index pair along with
-    // the required value and then fill it in at the end of the block emission. This is because a
-    // PHI can refer to a value which is defined after the PHI itself.
     void AddOperandToTerminator(core::ir::Terminator* term, uint32_t id) {
+        // If the ID is a constant, then we just directly emit it, it isn't an OpPhi value
+        if (IdIsConstant(id)) {
+            term->PushOperand(Value(id));
+            return;
+        }
+        // If we've already seen the value, and it's still in scope, then we can just emit as it
+        // isn't referencing a later value.
+        if (values_.Contains(id) && IdIsInScope(id)) {
+            term->PushOperand(Value(id));
+            return;
+        }
+
+        // Value isn't known, or isn't in scope, push a placeholder for the operand value. We store
+        // away the terminator/index pair along with the required value and then fill it in at the
+        // end of the block emission.
         auto operand_idx = term->PushOperand(nullptr);
         values_to_replace_.back().push_back(ReplacementValue{
             .terminator = term,