Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add function merger to be run during LTO link with gold plugin #121343

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

eleviant
Copy link
Contributor

Patch adds 'merge-functions' plugin option for this purpose.

Patch adds 'merge-functions' plugin option for this purpose.
@llvmbot llvmbot added the LTO Link time optimization (regular/full LTO or ThinLTO) label Dec 30, 2024
@llvmbot
Copy link
Member

llvmbot commented Dec 30, 2024

@llvm/pr-subscribers-lto

Author: None (eleviant)

Changes

Patch adds 'merge-functions' plugin option for this purpose.


Full diff: https://github.com/llvm/llvm-project/pull/121343.diff

3 Files Affected:

  • (added) llvm/test/tools/gold/X86/Inputs/merge-functions-foo.ll (+25)
  • (added) llvm/test/tools/gold/X86/merge-functions.ll (+49)
  • (modified) llvm/tools/gold/gold-plugin.cpp (+7)
diff --git a/llvm/test/tools/gold/X86/Inputs/merge-functions-foo.ll b/llvm/test/tools/gold/X86/Inputs/merge-functions-foo.ll
new file mode 100644
index 00000000000000..f2bcff89868e14
--- /dev/null
+++ b/llvm/test/tools/gold/X86/Inputs/merge-functions-foo.ll
@@ -0,0 +1,25 @@
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-linux-gnu"
+
+@_g = dso_local global i32 0, align 4
+@llvm.compiler.used = appending global [1 x ptr] [ptr @_g], section "llvm.metadata"
+
+define dso_local i32 @foo(i32 noundef %0) #0 {
+  %2 = add nsw i32 %0, 42
+  store i32 %2, ptr @_g, align 4
+  ret i32 %2
+}
+
+attributes #0 = { noinline }
+
+!llvm.module.flags = !{!0, !1}
+
+!0 = !{i32 1, !"ThinLTO", i32 0}
+!1 = !{i32 1, !"EnableSplitLTOUnit", i32 1}
+
+^0 = module: (path: "/tmp/func2.o", hash: (0, 0, 0, 0, 0))
+^1 = gv: (name: "foo", summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 1, live: 0, dsoLocal: 1, canAutoHide: 0), insts: 3, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 1, returnDoesNotAlias: 0, noInline: 1, alwaysInline: 0, noUnwind: 1, mayThrow: 0, hasUnknownCall: 0, mustBeUnreachable: 0), refs: (^3)))) ; guid = 6699318081062747564
+^2 = gv: (name: "llvm.compiler.used", summaries: (variable: (module: ^0, flags: (linkage: appending, visibility: default, notEligibleToImport: 1, live: 1, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0, constant: 0), refs: (^3)))) ; guid = 9610627770985738006
+^3 = gv: (name: "_g", summaries: (variable: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 1, live: 0, dsoLocal: 1, canAutoHide: 0), varFlags: (readonly: 1, writeonly: 1, constant: 0)))) ; guid = 9713702464056781075
+^4 = flags: 8
+^5 = blockcount: 0
diff --git a/llvm/test/tools/gold/X86/merge-functions.ll b/llvm/test/tools/gold/X86/merge-functions.ll
new file mode 100644
index 00000000000000..d4a49b1c40b477
--- /dev/null
+++ b/llvm/test/tools/gold/X86/merge-functions.ll
@@ -0,0 +1,49 @@
+; RUN: llvm-as %s -o %t.bc
+; RUN: llvm-as %p/Inputs/merge-functions-foo.ll -o %t-foo.bc
+; RUN: %gold -plugin %llvmshlibdir/LLVMgold%shlibext \
+; RUN:    -m elf_x86_64 \
+; RUN:    -plugin-opt=merge-functions \
+; RUN:    -plugin-opt=save-temps \
+; RUN:    -u main \
+; RUN:    %t.bc %t-foo.bc \
+; RUN:    -o %t-out
+; RUN: llvm-dis %t-out.0.5.precodegen.bc -o - | FileCheck %s
+
+; Check that we've merged foo and bar
+; CHECK:      define dso_local noundef i32 @main()
+; CHECK-NEXT:   tail call fastcc void @bar()
+; CHECK-NEXT:   tail call fastcc void @bar()
+
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-linux-gnu"
+
+@_g = external local_unnamed_addr global i32, align 4
+
+define dso_local i32 @bar(i32 noundef %0) #0 {
+  %2 = add nsw i32 %0, 42
+  store i32 %2, ptr @_g, align 4
+  ret i32 %2
+}
+
+define dso_local noundef i32 @main() {
+  %1 = tail call i32 @foo(i32 noundef 1)
+  %2 = tail call i32 @bar(i32 noundef 1)
+  ret i32 0
+}
+
+declare i32 @foo(i32 noundef) local_unnamed_addr #2
+
+attributes #0 = { noinline }
+
+!llvm.module.flags = !{!0, !1}
+
+!0 = !{i32 1, !"ThinLTO", i32 0}
+!1 = !{i32 1, !"EnableSplitLTOUnit", i32 1}
+
+^0 = module: (path: "merge-functions.o", hash: (0, 0, 0, 0, 0))
+^1 = gv: (name: "foo") ; guid = 6699318081062747564
+^2 = gv: (name: "_g") ; guid = 9713702464056781075
+^3 = gv: (name: "main", summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 1, live: 0, dsoLocal: 1, canAutoHide: 0), insts: 3, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 1, mayThrow: 0, hasUnknownCall: 0, mustBeUnreachable: 0), calls: ((callee: ^1, tail: 1), (callee: ^4, tail: 1))))) ; guid = 15822663052811949562
+^4 = gv: (name: "bar", summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 1, live: 0, dsoLocal: 1, canAutoHide: 0), insts: 3, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 1, returnDoesNotAlias: 0, noInline: 1, alwaysInline: 0, noUnwind: 1, mayThrow: 0, hasUnknownCall: 0, mustBeUnreachable: 0), refs: (^2)))) ; guid = 16434608426314478903
+^5 = flags: 8
+^6 = blockcount: 0
diff --git a/llvm/tools/gold/gold-plugin.cpp b/llvm/tools/gold/gold-plugin.cpp
index 6d0021c85f20fb..f6ca15a73115e0 100644
--- a/llvm/tools/gold/gold-plugin.cpp
+++ b/llvm/tools/gold/gold-plugin.cpp
@@ -222,6 +222,10 @@ namespace options {
   static std::string cs_profile_path;
   static bool cs_pgo_gen = false;
 
+  // When true, MergeFunctions pass is used
+  // in LTO link pipeline.
+  static bool merge_functions = false;
+
   // Time trace options.
   static std::string time_trace_file;
   static unsigned time_trace_granularity = 500;
@@ -288,6 +292,8 @@ namespace options {
       sample_profile = std::string(opt);
     } else if (opt == "cs-profile-generate") {
       cs_pgo_gen = true;
+    } else if (opt == "merge-functions") {
+      merge_functions = true;
     } else if (opt.consume_front("cs-profile-path=")) {
       cs_profile_path = std::string(opt);
     } else if (opt == "new-pass-manager") {
@@ -893,6 +899,7 @@ static std::unique_ptr<LTO> createLTO(IndexWriteCallback OnIndexWrite,
   Conf.OptLevel = options::OptLevel;
   Conf.PTO.LoopVectorization = options::OptLevel > 1;
   Conf.PTO.SLPVectorization = options::OptLevel > 1;
+  Conf.PTO.MergeFunctions = options::merge_functions;
   Conf.AlwaysEmitRegularLTOObj = !options::obj_path.empty();
 
   if (options::thinlto_index_only) {

Copy link
Contributor

@teresajohnson teresajohnson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change looks ok to me. However, should this pass be enabled by default instead, maybe at least when optimizing for size? It's unfortunate to have to wire through options for individual passes like this. cc @aeubanks for thoughts since he has done some pass pipeline work.

@@ -222,6 +222,10 @@ namespace options {
static std::string cs_profile_path;
static bool cs_pgo_gen = false;

// When true, MergeFunctions pass is used
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: these 2 comment lines can be combined

@eleviant eleviant changed the title All function merger to be run during LTO link with gold plugin Add function merger to be run during LTO link with gold plugin Dec 30, 2024
@eleviant
Copy link
Contributor Author

This change looks ok to me. However, should this pass be enabled by default instead, maybe at least when optimizing for size? It's unfortunate to have to wire through options for individual passes like this. cc @aeubanks for thoughts since he has done some pass pipeline work.

My understanding is that this option should be passed by clang driver when both -flto and -fmerge-functions are enabled and otherwise should be set to false, because at the moment function merger is not being implicitly enabled by Os or any other optimization level.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
LTO Link time optimization (regular/full LTO or ThinLTO)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants