From 16479cec41afdbc301addedb6f4ef5cd650e5351 Mon Sep 17 00:00:00 2001 From: eleviant <56861949+eleviant@users.noreply.github.com> Date: Sun, 12 Jan 2025 17:31:45 +0100 Subject: [PATCH] Add function merger to be run during LTO link with gold plugin (#121343) Patch adds 'merge-functions' plugin option for this purpose. --- .../gold/X86/Inputs/merge-functions-foo.ll | 25 ++++++++++ llvm/test/tools/gold/X86/merge-functions.ll | 49 +++++++++++++++++++ llvm/tools/gold/gold-plugin.cpp | 6 +++ 3 files changed, 80 insertions(+) create mode 100644 llvm/test/tools/gold/X86/Inputs/merge-functions-foo.ll create mode 100644 llvm/test/tools/gold/X86/merge-functions.ll 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 000000000000000..f2bcff89868e14d --- /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 000000000000000..d4a49b1c40b4772 --- /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 ac2e9d4252aa38b..ae965e6f486aa63 100644 --- a/llvm/tools/gold/gold-plugin.cpp +++ b/llvm/tools/gold/gold-plugin.cpp @@ -224,6 +224,9 @@ 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; @@ -292,6 +295,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") { @@ -897,6 +902,7 @@ static std::unique_ptr 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.PTO.UnifiedLTO = options::unifiedlto; Conf.AlwaysEmitRegularLTOObj = !options::obj_path.empty();