[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)