[spirv-reader] Set some source locations

Set source location on function variable declarations, const
declarations, and most normal instructions.

Bug: tint:3
Change-Id: I469afcdf1b7d8f6d1e64617189a6fa329056737f
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/27700
Commit-Queue: David Neto <dneto@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index f4ae488..f9a3ccb 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -426,6 +426,12 @@
   std::unordered_set<uint32_t> visited_;
 };
 
+/// @param src a source record
+/// @returns true if |src| is a non-default Source
+bool HasSource(const Source& src) {
+  return src.line != 0 || src.column != 0;
+}
+
 }  // namespace
 
 BlockInfo::BlockInfo(const spvtools::opt::BasicBlock& bb)
@@ -525,6 +531,14 @@
   return result;
 }
 
+ast::Statement* FunctionEmitter::AddStatementForInstruction(
+    std::unique_ptr<ast::Statement> statement,
+    const spvtools::opt::Instruction& inst) {
+  auto* node = AddStatement(std::move(statement));
+  ApplySourceForInstruction(node, inst);
+  return node;
+}
+
 ast::Statement* FunctionEmitter::LastStatement() {
   assert(!statements_stack_.empty());
   const auto& statement_list = statements_stack_.back().statements_;
@@ -1655,7 +1669,7 @@
     // TODO(dneto): Add the initializer via Variable::set_constructor.
     auto var_decl_stmt =
         std::make_unique<ast::VariableDeclStatement>(std::move(var));
-    AddStatement(std::move(var_decl_stmt));
+    AddStatementForInstruction(std::move(var_decl_stmt), inst);
     // Save this as an already-named value.
     identifier_values_.insert(inst.result_id());
   }
@@ -2430,7 +2444,6 @@
     // Only emit this part of the basic block once.
     return true;
   }
-
   // Returns the given list of local definition IDs, sorted by their index.
   auto sorted_by_index = [this](const std::vector<uint32_t>& ids) {
     auto sorted = ids;
@@ -2514,8 +2527,8 @@
   }
   ast_const->set_constructor(std::move(ast_expr.expr));
   ast_const->set_is_const(true);
-  AddStatement(
-      std::make_unique<ast::VariableDeclStatement>(std::move(ast_const)));
+  AddStatementForInstruction(
+      std::make_unique<ast::VariableDeclStatement>(std::move(ast_const)), inst);
   // Save this as an already-named value.
   identifier_values_.insert(inst.result_id());
   return success();
@@ -2528,9 +2541,11 @@
   const auto* def_info = GetDefInfo(result_id);
   if (def_info && def_info->requires_hoisted_def) {
     // Emit an assignment of the expression to the hoisted variable.
-    AddStatement(std::make_unique<ast::AssignmentStatement>(
-        std::make_unique<ast::IdentifierExpression>(namer_.Name(result_id)),
-        std::move(ast_expr.expr)));
+    AddStatementForInstruction(
+        std::make_unique<ast::AssignmentStatement>(
+            std::make_unique<ast::IdentifierExpression>(namer_.Name(result_id)),
+            std::move(ast_expr.expr)),
+        inst);
     return true;
   }
   return EmitConstDefinition(inst, std::move(ast_expr));
@@ -2593,8 +2608,9 @@
       // TODO(dneto): Order of evaluation?
       auto lhs = MakeExpression(ptr_id);
       auto rhs = MakeExpression(value_id);
-      AddStatement(std::make_unique<ast::AssignmentStatement>(
-          std::move(lhs.expr), std::move(rhs.expr)));
+      AddStatementForInstruction(std::make_unique<ast::AssignmentStatement>(
+                                     std::move(lhs.expr), std::move(rhs.expr)),
+                                 inst);
       return success();
     }
     case SpvOpLoad: {
@@ -3456,8 +3472,10 @@
   }
 
   if (result_type->IsVoid()) {
-    return nullptr != AddStatement(std::make_unique<ast::CallStatement>(
-                          std::move(call_expr)));
+    return nullptr !=
+           AddStatementForInstruction(
+               std::make_unique<ast::CallStatement>(std::move(call_expr)),
+               inst);
   }
 
   return EmitConstDefOrWriteToHoistedVar(inst,
@@ -3491,6 +3509,18 @@
   return {};
 }
 
+void FunctionEmitter::ApplySourceForInstruction(
+    ast::Node* node,
+    const spvtools::opt::Instruction& inst) {
+  if (!node) {
+    return;
+  }
+  const Source& existing = node->source();
+  if (!HasSource(existing)) {
+    node->set_source(parser_impl_.GetSourceForInst(&inst));
+  }
+}
+
 }  // namespace spirv
 }  // namespace reader
 }  // namespace tint
diff --git a/src/reader/spirv/function.h b/src/reader/spirv/function.h
index 007c756..b62994f 100644
--- a/src/reader/spirv/function.h
+++ b/src/reader/spirv/function.h
@@ -705,6 +705,23 @@
   /// @returns a pointer to the statement.
   ast::Statement* AddStatement(std::unique_ptr<ast::Statement> statement);
 
+  /// Appends a new statement to the top of the statement stack, and attaches
+  /// source location information from the given instruction. Does nothing if
+  /// the statement is null.
+  /// @param statement the new statement
+  /// @returns a pointer to the statement.
+  ast::Statement* AddStatementForInstruction(
+      std::unique_ptr<ast::Statement> statement,
+      const spvtools::opt::Instruction& inst);
+
+  /// Sets the source information for the given instruction to the given
+  /// node, if the node doesn't already have a source record.  Does nothing
+  /// if |nodes| is null.
+  /// @param node the AST node
+  /// @param inst the SPIR-V instruction
+  void ApplySourceForInstruction(ast::Node* node,
+                                 const spvtools::opt::Instruction& inst);
+
   /// @returns the last statetment in the top of the statement stack.
   ast::Statement* LastStatement();
 
diff --git a/src/reader/spirv/parser_impl.cc b/src/reader/spirv/parser_impl.cc
index ee755f2..70aed3b 100644
--- a/src/reader/spirv/parser_impl.cc
+++ b/src/reader/spirv/parser_impl.cc
@@ -502,8 +502,12 @@
       run_on_debug_insts);
 }
 
-Source ParserImpl::GetSourceForResultIdForTest(uint32_t id) {
-  const auto* inst = def_use_mgr_->GetDef(id);
+Source ParserImpl::GetSourceForResultIdForTest(uint32_t id) const {
+  return GetSourceForInst(def_use_mgr_->GetDef(id));
+}
+
+Source ParserImpl::GetSourceForInst(
+    const spvtools::opt::Instruction* inst) const {
   auto where = inst_source_.find(inst);
   if (where == inst_source_.end()) {
     return {};
diff --git a/src/reader/spirv/parser_impl.h b/src/reader/spirv/parser_impl.h
index 28c3523..deeed0a 100644
--- a/src/reader/spirv/parser_impl.h
+++ b/src/reader/spirv/parser_impl.h
@@ -362,11 +362,15 @@
     return builtin_position_;
   }
 
-  /// Look up the source record for the SPIR-V instruction with the given
+  /// Returns the source record for the SPIR-V instruction with the given
   /// result ID.
   /// @param id the SPIR-V result id.
   /// @return the Source record, or a default one
-  Source GetSourceForResultIdForTest(uint32_t id);
+  Source GetSourceForResultIdForTest(uint32_t id) const;
+  /// Returns the soruce record for the given instruction.
+  /// @param inst the SPIR-V instruction
+  /// @return the Source record, or a default one
+  Source GetSourceForInst(const spvtools::opt::Instruction* inst) const;
 
  private:
   /// Converts a specific SPIR-V type to a Tint type. Integer case