[ir] Add source information to the IR.

This CL adds a value to source map to the IR module and populates it
during the program to IR translation.

Change-Id: If0a9a32c4ff52580cf539b7c9b3da2314d8cb374
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/213174
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/tint/lang/core/ir/module.cc b/src/tint/lang/core/ir/module.cc
index 31e7363..58bece3 100644
--- a/src/tint/lang/core/ir/module.cc
+++ b/src/tint/lang/core/ir/module.cc
@@ -150,6 +150,26 @@
     value_to_name_.Remove(value);
 }
 
+void Module::SetSource(Instruction* inst, Source src) {
+    TINT_ASSERT(inst->Results().Length() == 1);
+    SetSource(inst->Result(0), src);
+}
+
+void Module::SetSource(Value* value, Source src) {
+    value_to_source_.Replace(value, src);
+}
+
+Source Module::SourceOf(const Instruction* inst) const {
+    if (inst->Results().Length() != 1) {
+        return Source{};
+    }
+    return SourceOf(inst->Result(0));
+}
+
+Source Module::SourceOf(const Value* value) const {
+    return value_to_source_.GetOr(value, Source{});
+}
+
 Vector<Function*, 16> Module::DependencyOrderedFunctions() {
     return FunctionSorter<Function>::SortFunctions(*this);
 }
diff --git a/src/tint/lang/core/ir/module.h b/src/tint/lang/core/ir/module.h
index c77cc36..5ef2b7f 100644
--- a/src/tint/lang/core/ir/module.h
+++ b/src/tint/lang/core/ir/module.h
@@ -58,6 +58,9 @@
     /// Map of value to name
     Hashmap<const Value*, Symbol, 32> value_to_name_;
 
+    // The source information for a value
+    Hashmap<const Value*, Source, 32> value_to_source_;
+
     /// A predicate function that returns true if the instruction or value is alive.
     struct IsAlive {
         bool operator()(const Instruction* instruction) const { return instruction->Alive(); }
@@ -123,6 +126,25 @@
     /// @param value the value to remove the name from
     void ClearName(Value* value);
 
+    /// @param inst the instruction to set the source of
+    /// @param src the source
+    /// @note requires the instruction be a single result instruction.
+    void SetSource(Instruction* inst, Source src);
+
+    /// @param value the value to set the source
+    /// @param src the source
+    void SetSource(Value* value, Source src);
+
+    /// @param inst the instruction
+    /// @return the source of the given instruction, or an empty source if the instruction does not
+    /// have a source or does not have a single return value.
+    Source SourceOf(const Instruction* inst) const;
+
+    /// @param value the value
+    /// @return the source of the given value, or an empty source if the value does not have a
+    /// source.
+    Source SourceOf(const Value* value) const;
+
     /// @return the type manager for the module
     core::type::Manager& Types() { return constant_values.types; }
 
diff --git a/src/tint/lang/core/ir/value.h b/src/tint/lang/core/ir/value.h
index f1b3f50..c2475b6 100644
--- a/src/tint/lang/core/ir/value.h
+++ b/src/tint/lang/core/ir/value.h
@@ -158,6 +158,7 @@
     /// Bitset of value flags
     tint::EnumSet<Flag> flags_;
 };
+
 }  // namespace tint::core::ir
 
 #endif  // SRC_TINT_LANG_CORE_IR_VALUE_H_
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc b/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc
index 673889e..66ae2d4 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc
+++ b/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc
@@ -267,7 +267,6 @@
         auto* ir_func = builder_.Function(ast_func->name->symbol.NameView(),
                                           sem->ReturnType()->Clone(clone_ctx_.type_ctx));
         current_function_ = ir_func;
-
         scopes_.Set(ast_func->name->symbol, ir_func);
 
         if (ast_func->IsEntryPoint()) {
@@ -718,10 +717,7 @@
     // the code has to continue as before it just predicates writes. If WGSL grows some kind of
     // terminating discard that would probably make sense as a Block but would then require
     // figuring out the multi-level exit that is triggered.
-    void EmitDiscard(const ast::DiscardStatement*) {
-        auto* inst = builder_.Discard();
-        current_block_->Append(inst);
-    }
+    void EmitDiscard(const ast::DiscardStatement*) { current_block_->Append(builder_.Discard()); }
 
     void EmitBreakIf(const ast::BreakIfStatement* stmt) {
         auto* current_control = FindEnclosingControl(ControlFlags::kExcludeSwitch);
@@ -1162,6 +1158,7 @@
     core::ir::Value* EmitValueExpression(const ast::Expression* root) {
         auto res = EmitExpression(root);
         if (auto** val = std::get_if<core::ir::Value*>(&res)) {
+            builder_.ir.SetSource(*val, root->source);
             return *val;
         }
         TINT_ICE() << "expression did not resolve to a value";
@@ -1204,8 +1201,9 @@
                 // Store the declaration so we can get the instruction to store too
                 scopes_.Set(v->name->symbol, val->Result(0));
 
-                // Record the original name of the var
+                // Record the original name and source of the var
                 builder_.ir.SetName(val, v->name->symbol.Name());
+                builder_.ir.SetSource(val, v->source);
             },
             [&](const ast::Let* l) {
                 auto init = EmitValueExpression(l->initializer);
@@ -1217,6 +1215,7 @@
 
                 // Store the results of the initialization
                 scopes_.Set(l->name->symbol, let->Result(0));
+                builder_.ir.SetSource(let, l->source);
             },
             [&](const ast::Override* o) {
                 auto* o_sem = program_.Sem().Get(o);
@@ -1238,8 +1237,9 @@
                 // Store the declaration so we can get the instruction to store too
                 scopes_.Set(o->name->symbol, override->Result(0));
 
-                // Record the original name of the var
+                // Record the original name and source of the var
                 builder_.ir.SetName(override, o->name->symbol.Name());
+                builder_.ir.SetSource(override, o->source);
             },
             [&](const ast::Const*) {
                 // Skip. This should be handled by const-eval already, so the const will be a
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir_test.cc b/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir_test.cc
index 57457f5..60722d7 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir_test.cc
+++ b/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir_test.cc
@@ -78,7 +78,6 @@
 
     core::ir::Function* f = m->functions[0];
     ASSERT_NE(f->Block(), nullptr);
-
     EXPECT_EQ(m->functions[0]->Stage(), core::ir::Function::PipelineStage::kUndefined);
 
     EXPECT_EQ(core::ir::Disassembler(m.Get()).Plain(), R"(%f = func():void {
@@ -1181,16 +1180,19 @@
 }
 
 TEST_F(IR_FromProgramTest, OverrideNoInitializer) {
-    Override("a", ty.i32());
+    Override(Source{{1, 2}}, "a", ty.i32());
 
     auto res = Build();
     ASSERT_EQ(res, Success);
 
     auto m = res.Move();
-    auto* overide = FindSingleInstruction<core::ir::Override>(m);
+    auto* override = FindSingleInstruction<core::ir::Override>(m);
 
-    ASSERT_NE(overide, nullptr);
-    ASSERT_EQ(overide->Initializer(), nullptr);
+    ASSERT_NE(override, nullptr);
+    ASSERT_EQ(override->Initializer(), nullptr);
+
+    Source::Location loc{1u, 2u};
+    EXPECT_EQ(m.SourceOf(override).range.begin, loc);
 
     EXPECT_EQ(core::ir::Disassembler(m).Plain(), R"($B1: {  # root
   %a:i32 = override @id(0)