Record trailing line dbg instructions (#2926)
There is nothing in the spir-v spec that says the last
instructions in a module cannot be OpLine or OpNoLine.
However, the code that parses the module will simply drop
these instructions.
We add code that will preserve these instructions.
Strip-debug-info is updated to remove these instructions.
Fixes https://crbug.com/1000689.
diff --git a/source/opt/ir_loader.cpp b/source/opt/ir_loader.cpp
index edd4832..c68b3e2 100644
--- a/source/opt/ir_loader.cpp
+++ b/source/opt/ir_loader.cpp
@@ -159,6 +159,9 @@
for (auto& function : *module_) {
for (auto& bb : function) bb.SetParent(&function);
}
+
+ // Copy any trailing Op*Line instruction into the module
+ module_->SetTrailingDbgLineInfo(std::move(dbg_line_info_));
}
} // namespace opt
diff --git a/source/opt/module.cpp b/source/opt/module.cpp
index 04e4e97..c7fc247 100644
--- a/source/opt/module.cpp
+++ b/source/opt/module.cpp
@@ -121,6 +121,9 @@
static_cast<const Function*>(i.get())->ForEachInst(f,
run_on_debug_line_insts);
}
+ if (run_on_debug_line_insts) {
+ for (auto& i : trailing_dbg_line_info_) DELEGATE(i);
+ }
#undef DELEGATE
}
diff --git a/source/opt/module.h b/source/opt/module.h
index bf23491..aefa2a5 100644
--- a/source/opt/module.h
+++ b/source/opt/module.h
@@ -245,6 +245,19 @@
// Gets the associated context for this module
IRContext* context() const { return context_; }
+ // Sets the trailing debug line info to |dbg_line_info|.
+ void SetTrailingDbgLineInfo(std::vector<Instruction>&& dbg_line_info) {
+ trailing_dbg_line_info_ = std::move(dbg_line_info);
+ }
+
+ std::vector<Instruction>& trailing_dbg_line_info() {
+ return trailing_dbg_line_info_;
+ }
+
+ const std::vector<Instruction>& trailing_dbg_line_info() const {
+ return trailing_dbg_line_info_;
+ }
+
private:
ModuleHeader header_; // Module header
@@ -265,6 +278,10 @@
// Type declarations, constants, and global variable declarations.
InstructionList types_values_;
std::vector<std::unique_ptr<Function>> functions_;
+
+ // If the module ends with Op*Line instruction, they will not be attached to
+ // any instruction. We record them here, so they will not be lost.
+ std::vector<Instruction> trailing_dbg_line_info_;
};
// Pretty-prints |module| to |str|. Returns |str|.
diff --git a/source/opt/strip_debug_info_pass.cpp b/source/opt/strip_debug_info_pass.cpp
index f5fb94f..9e7fad0 100644
--- a/source/opt/strip_debug_info_pass.cpp
+++ b/source/opt/strip_debug_info_pass.cpp
@@ -45,6 +45,11 @@
inst->dbg_line_insts().clear();
});
+ if (!get_module()->trailing_dbg_line_info().empty()) {
+ modified = true;
+ get_module()->trailing_dbg_line_info().clear();
+ }
+
return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
}
diff --git a/test/opt/module_test.cpp b/test/opt/module_test.cpp
index 569cf9b..406da09 100644
--- a/test/opt/module_test.cpp
+++ b/test/opt/module_test.cpp
@@ -21,6 +21,7 @@
#include "gtest/gtest.h"
#include "source/opt/build_module.h"
#include "source/opt/module.h"
+#include "source/opt/pass.h"
#include "spirv-tools/libspirv.hpp"
#include "test/opt/module_utils.h"
@@ -228,6 +229,72 @@
EXPECT_EQ(next_id_bound, 0);
EXPECT_EQ(current_bound, context->module()->id_bound());
}
+
+// Tests that "text" does not change when it is assembled, converted into a
+// module, converted back to a binary, and then disassembled.
+void AssembleAndDisassemble(const std::string& text) {
+ std::unique_ptr<IRContext> context = BuildModule(text);
+ std::vector<uint32_t> binary;
+
+ context->module()->ToBinary(&binary, false);
+
+ SpirvTools tools(SPV_ENV_UNIVERSAL_1_1);
+ std::string s;
+ tools.Disassemble(binary, &s);
+ EXPECT_EQ(s, text);
+}
+
+TEST(ModuleTest, TrailingOpLine) {
+ const std::string text = R"(OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+%5 = OpString "file.ext"
+%void = OpTypeVoid
+%2 = OpTypeFunction %void
+%3 = OpFunction %void None %2
+%4 = OpLabel
+OpReturn
+OpFunctionEnd
+OpLine %5 1 0
+)";
+
+ AssembleAndDisassemble(text);
+}
+
+TEST(ModuleTest, TrailingOpNoLine) {
+ const std::string text = R"(OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+%void = OpTypeVoid
+%2 = OpTypeFunction %void
+%3 = OpFunction %void None %2
+%4 = OpLabel
+OpReturn
+OpFunctionEnd
+OpNoLine
+)";
+
+ AssembleAndDisassemble(text);
+}
+
+TEST(ModuleTest, MulitpleTrailingOpLine) {
+ const std::string text = R"(OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+%5 = OpString "file.ext"
+%void = OpTypeVoid
+%2 = OpTypeFunction %void
+%3 = OpFunction %void None %2
+%4 = OpLabel
+OpReturn
+OpFunctionEnd
+OpLine %5 1 0
+OpNoLine
+OpLine %5 1 1
+)";
+
+ AssembleAndDisassemble(text);
+}
} // namespace
} // namespace opt
} // namespace spvtools
diff --git a/test/opt/strip_debug_info_test.cpp b/test/opt/strip_debug_info_test.cpp
index 330f29b..2f2ff46 100644
--- a/test/opt/strip_debug_info_test.cpp
+++ b/test/opt/strip_debug_info_test.cpp
@@ -51,6 +51,8 @@
"OpLine %3 4 4",
"OpNoLine",
"OpFunctionEnd",
+ "OpNoLine",
+ "OpLine %3 4 5"
// clang-format on
};
SinglePassRunAndCheck<StripDebugInfoPass>(JoinAllInsts(text),