Remove names and decorations of imported symbols (#3081)
* Remove names and decorations of imported symbols
* Added test case
diff --git a/source/link/linker.cpp b/source/link/linker.cpp
index d99a1e8..14e61a8 100644
--- a/source/link/linker.cpp
+++ b/source/link/linker.cpp
@@ -137,8 +137,6 @@
// TODO(pierremoreau): Linkage attributes applied by a group decoration are
// currently not handled. (You could have a group being
// applied to a single ID.)
-// TODO(pierremoreau): Run a pass for removing dead instructions, for example
-// OpName for prototypes of imported funcions.
spv_result_t RemoveLinkageSpecificInstructions(
const MessageConsumer& consumer, const LinkerOptions& options,
const LinkageTable& linkings_to_do, DecorationManager* decoration_manager,
@@ -531,24 +529,6 @@
// TODO(pierremoreau): Remove FuncParamAttr decorations of imported
// functions' return type.
- // Remove FuncParamAttr decorations of imported functions' parameters.
- // From the SPIR-V specification, Sec. 2.13:
- // When resolving imported functions, the Function Control and all Function
- // Parameter Attributes are taken from the function definition, and not
- // from the function declaration.
- for (const auto& linking_entry : linkings_to_do) {
- for (const auto parameter_id :
- linking_entry.imported_symbol.parameter_ids) {
- decoration_manager->RemoveDecorationsFrom(
- parameter_id, [](const Instruction& inst) {
- return (inst.opcode() == SpvOpDecorate ||
- inst.opcode() == SpvOpMemberDecorate) &&
- inst.GetSingleWordInOperand(1u) ==
- SpvDecorationFuncParamAttr;
- });
- }
- }
-
// Remove prototypes of imported functions
for (const auto& linking_entry : linkings_to_do) {
for (auto func_iter = linked_context->module()->begin();
@@ -746,24 +726,34 @@
opt::Pass::Status pass_res = manager.Run(&linked_context);
if (pass_res == opt::Pass::Status::Failure) return SPV_ERROR_INVALID_DATA;
- // Phase 7: Rematch import variables/functions to export variables/functions
- for (const auto& linking_entry : linkings_to_do)
+ // Phase 7: Remove all names and decorations of import variables/functions
+ for (const auto& linking_entry : linkings_to_do) {
+ linked_context.KillNamesAndDecorates(linking_entry.imported_symbol.id);
+ for (const auto parameter_id :
+ linking_entry.imported_symbol.parameter_ids) {
+ linked_context.KillNamesAndDecorates(parameter_id);
+ }
+ }
+
+ // Phase 8: Rematch import variables/functions to export variables/functions
+ for (const auto& linking_entry : linkings_to_do) {
linked_context.ReplaceAllUsesWith(linking_entry.imported_symbol.id,
linking_entry.exported_symbol.id);
+ }
- // Phase 8: Remove linkage specific instructions, such as import/export
+ // Phase 9: Remove linkage specific instructions, such as import/export
// attributes, linkage capability, etc. if applicable
res = RemoveLinkageSpecificInstructions(consumer, options, linkings_to_do,
linked_context.get_decoration_mgr(),
&linked_context);
if (res != SPV_SUCCESS) return res;
- // Phase 9: Compact the IDs used in the module
+ // Phase 10: Compact the IDs used in the module
manager.AddPass<opt::CompactIdsPass>();
pass_res = manager.Run(&linked_context);
if (pass_res == opt::Pass::Status::Failure) return SPV_ERROR_INVALID_DATA;
- // Phase 10: Output the module
+ // Phase 11: Output the module
linked_context.module()->ToBinary(linked_binary, true);
return SPV_SUCCESS;
diff --git a/test/link/matching_imports_to_exports_test.cpp b/test/link/matching_imports_to_exports_test.cpp
index 59e62d5..e76c69f 100644
--- a/test/link/matching_imports_to_exports_test.cpp
+++ b/test/link/matching_imports_to_exports_test.cpp
@@ -399,5 +399,78 @@
EXPECT_EQ(expected_res, res_body);
}
+TEST_F(MatchingImportsToExports, NamesAndDecorations) {
+ const std::string body1 = R"(
+OpCapability Kernel
+OpCapability Linkage
+OpName %1 "foo"
+OpName %3 "param"
+OpDecorate %1 LinkageAttributes "foo" Import
+OpDecorate %2 Restrict
+OpDecorate %4 NonWritable
+%2 = OpDecorationGroup
+OpGroupDecorate %2 %3 %4
+%5 = OpTypeVoid
+%6 = OpTypeInt 32 0
+%9 = OpTypePointer Function %6
+%7 = OpTypeFunction %5 %9
+%1 = OpFunction %5 None %7
+%3 = OpFunctionParameter %9
+OpFunctionEnd
+%8 = OpFunction %5 None %7
+%4 = OpFunctionParameter %9
+OpFunctionEnd
+)";
+ const std::string body2 = R"(
+OpCapability Kernel
+OpCapability Linkage
+OpName %1 "foo"
+OpName %2 "param"
+OpDecorate %1 LinkageAttributes "foo" Export
+OpDecorate %2 Restrict
+%3 = OpTypeVoid
+%4 = OpTypeInt 32 0
+%7 = OpTypePointer Function %4
+%5 = OpTypeFunction %3 %7
+%1 = OpFunction %3 None %5
+%2 = OpFunctionParameter %7
+%6 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ spvtest::Binary linked_binary;
+ EXPECT_EQ(SPV_SUCCESS, AssembleAndLink({body1, body2}, &linked_binary))
+ << GetErrorMessage();
+
+ const std::string expected_res = R"(OpCapability Kernel
+OpName %1 "foo"
+OpName %2 "param"
+OpModuleProcessed "Linked by SPIR-V Tools Linker"
+OpDecorate %3 Restrict
+OpDecorate %4 NonWritable
+%3 = OpDecorationGroup
+OpGroupDecorate %3 %4
+OpDecorate %2 Restrict
+%5 = OpTypeVoid
+%6 = OpTypeInt 32 0
+%7 = OpTypePointer Function %6
+%8 = OpTypeFunction %5 %7
+%9 = OpFunction %5 None %8
+%4 = OpFunctionParameter %7
+OpFunctionEnd
+%1 = OpFunction %5 None %8
+%2 = OpFunctionParameter %7
+%10 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+ std::string res_body;
+ SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
+ EXPECT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body))
+ << GetErrorMessage();
+ EXPECT_EQ(expected_res, res_body);
+}
+
} // namespace
} // namespace spvtools