Skip to content

Commit e86ebe4

Browse files
authored
[LTO] Allow target-specific module splittting (#83128)
Allow targets to implement custom module splitting logic for --lto-partitions, see #89245 https://discourse.llvm.org/t/rfc-lto-target-specific-module-splittting/77252
1 parent 2a47ee0 commit e86ebe4

File tree

5 files changed

+111
-29
lines changed

5 files changed

+111
-29
lines changed

llvm/include/llvm/Target/TargetMachine.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,18 @@ class TargetMachine {
418418
virtual unsigned getAddressSpaceForPseudoSourceKind(unsigned Kind) const {
419419
return 0;
420420
}
421+
422+
/// Entry point for module splitting. Targets can implement custom module
423+
/// splitting logic, mainly used by LTO for --lto-partitions.
424+
///
425+
/// \returns `true` if the module was split, `false` otherwise. When `false`
426+
/// is returned, it is assumed that \p ModuleCallback has never been called
427+
/// and \p M has not been modified.
428+
virtual bool splitModule(
429+
Module &M, unsigned NumParts,
430+
function_ref<void(std::unique_ptr<Module> MPart)> ModuleCallback) const {
431+
return false;
432+
}
421433
};
422434

423435
/// This class describes a target machine that is implemented with the LLVM

llvm/lib/LTO/LTOBackend.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -436,8 +436,7 @@ static void splitCodeGen(const Config &C, TargetMachine *TM,
436436
unsigned ThreadCount = 0;
437437
const Target *T = &TM->getTarget();
438438

439-
SplitModule(
440-
Mod, ParallelCodeGenParallelismLevel,
439+
const auto HandleModulePartition =
441440
[&](std::unique_ptr<Module> MPart) {
442441
// We want to clone the module in a new context to multi-thread the
443442
// codegen. We do it by serializing partition modules to bitcode
@@ -469,8 +468,14 @@ static void splitCodeGen(const Config &C, TargetMachine *TM,
469468
// Pass BC using std::move to ensure that it get moved rather than
470469
// copied into the thread's context.
471470
std::move(BC), ThreadCount++);
472-
},
473-
false);
471+
};
472+
473+
// Try target-specific module splitting first, then fallback to the default.
474+
if (!TM->splitModule(Mod, ParallelCodeGenParallelismLevel,
475+
HandleModulePartition)) {
476+
SplitModule(Mod, ParallelCodeGenParallelismLevel, HandleModulePartition,
477+
false);
478+
}
474479

475480
// Because the inner lambda (which runs in a worker thread) captures our local
476481
// variables, we need to wait for the worker threads to terminate before we
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
; RUN: llvm-split -o %t %s -mtriple x86_64 -preserve-locals 2>&1 | FileCheck %s
2+
3+
; Basic test for a target that doesn't support target-specific module splitting.
4+
5+
; CHECK: warning: -preserve-locals has no effect when using TargetMachine::splitModule
6+
; CHECK: warning: TargetMachine::splitModule failed, falling back to default splitModule implementation
7+
8+
define void @bar() {
9+
ret void
10+
}

llvm/tools/llvm-split/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
set(LLVM_LINK_COMPONENTS
2+
AllTargetsAsmParsers
3+
AllTargetsCodeGens
4+
AllTargetsDescs
5+
AllTargetsInfos
26
TransformUtils
37
BitWriter
8+
CodeGen
49
Core
510
IRReader
11+
MC
612
Support
13+
Target
714
)
815

916
add_llvm_tool(llvm-split

llvm/tools/llvm-split/llvm-split.cpp

Lines changed: 73 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
//===-- llvm-split: command line tool for testing module splitter ---------===//
1+
//===-- llvm-split: command line tool for testing module splitting --------===//
22
//
33
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44
// See https://llvm.org/LICENSE.txt for license information.
55
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66
//
77
//===----------------------------------------------------------------------===//
88
//
9-
// This program can be used to test the llvm::SplitModule function.
9+
// This program can be used to test the llvm::SplitModule and
10+
// TargetMachine::splitModule functions.
1011
//
1112
//===----------------------------------------------------------------------===//
1213

@@ -15,12 +16,17 @@
1516
#include "llvm/IR/LLVMContext.h"
1617
#include "llvm/IR/Verifier.h"
1718
#include "llvm/IRReader/IRReader.h"
19+
#include "llvm/MC/TargetRegistry.h"
1820
#include "llvm/Support/CommandLine.h"
1921
#include "llvm/Support/FileSystem.h"
22+
#include "llvm/Support/InitLLVM.h"
2023
#include "llvm/Support/SourceMgr.h"
24+
#include "llvm/Support/TargetSelect.h"
2125
#include "llvm/Support/ToolOutputFile.h"
22-
#include "llvm/Support/raw_ostream.h"
2326
#include "llvm/Support/WithColor.h"
27+
#include "llvm/Support/raw_ostream.h"
28+
#include "llvm/Target/TargetMachine.h"
29+
#include "llvm/TargetParser/Triple.h"
2430
#include "llvm/Transforms/Utils/SplitModule.h"
2531

2632
using namespace llvm;
@@ -47,12 +53,42 @@ static cl::opt<bool>
4753
cl::desc("Split without externalizing locals"),
4854
cl::cat(SplitCategory));
4955

56+
static cl::opt<std::string>
57+
MTriple("mtriple",
58+
cl::desc("Target triple. When present, a TargetMachine is created "
59+
"and TargetMachine::splitModule is used instead of the "
60+
"common SplitModule logic."),
61+
cl::value_desc("triple"), cl::cat(SplitCategory));
62+
63+
static cl::opt<std::string>
64+
MCPU("mcpu", cl::desc("Target CPU, ignored if -mtriple is not used"),
65+
cl::value_desc("cpu"), cl::cat(SplitCategory));
66+
5067
int main(int argc, char **argv) {
68+
InitLLVM X(argc, argv);
69+
5170
LLVMContext Context;
5271
SMDiagnostic Err;
5372
cl::HideUnrelatedOptions({&SplitCategory, &getColorCategory()});
5473
cl::ParseCommandLineOptions(argc, argv, "LLVM module splitter\n");
5574

75+
TargetMachine *TM = nullptr;
76+
if (!MTriple.empty()) {
77+
InitializeAllTargets();
78+
InitializeAllTargetMCs();
79+
80+
std::string Error;
81+
const Target *T = TargetRegistry::lookupTarget(MTriple, Error);
82+
if (!T) {
83+
errs() << "unknown target '" << MTriple << "': " << Error << "\n";
84+
return 1;
85+
}
86+
87+
TargetOptions Options;
88+
TM = T->createTargetMachine(MTriple, MCPU, /*FS*/ "", Options, std::nullopt,
89+
std::nullopt);
90+
}
91+
5692
std::unique_ptr<Module> M = parseIRFile(InputFilename, Err, Context);
5793

5894
if (!M) {
@@ -61,28 +97,40 @@ int main(int argc, char **argv) {
6197
}
6298

6399
unsigned I = 0;
64-
SplitModule(
65-
*M, NumOutputs,
66-
[&](std::unique_ptr<Module> MPart) {
67-
std::error_code EC;
68-
std::unique_ptr<ToolOutputFile> Out(new ToolOutputFile(
69-
OutputFilename + utostr(I++), EC, sys::fs::OF_None));
70-
if (EC) {
71-
errs() << EC.message() << '\n';
72-
exit(1);
73-
}
74-
75-
if (verifyModule(*MPart, &errs())) {
76-
errs() << "Broken module!\n";
77-
exit(1);
78-
}
79-
80-
WriteBitcodeToFile(*MPart, Out->os());
81-
82-
// Declare success.
83-
Out->keep();
84-
},
85-
PreserveLocals);
100+
const auto HandleModulePart = [&](std::unique_ptr<Module> MPart) {
101+
std::error_code EC;
102+
std::unique_ptr<ToolOutputFile> Out(
103+
new ToolOutputFile(OutputFilename + utostr(I++), EC, sys::fs::OF_None));
104+
if (EC) {
105+
errs() << EC.message() << '\n';
106+
exit(1);
107+
}
108+
109+
if (verifyModule(*MPart, &errs())) {
110+
errs() << "Broken module!\n";
111+
exit(1);
112+
}
113+
114+
WriteBitcodeToFile(*MPart, Out->os());
115+
116+
// Declare success.
117+
Out->keep();
118+
};
119+
120+
if (TM) {
121+
if (PreserveLocals) {
122+
errs() << "warning: -preserve-locals has no effect when using "
123+
"TargetMachine::splitModule\n";
124+
}
125+
126+
if (TM->splitModule(*M, NumOutputs, HandleModulePart))
127+
return 0;
128+
129+
errs() << "warning: "
130+
"TargetMachine::splitModule failed, falling back to default "
131+
"splitModule implementation\n";
132+
}
86133

134+
SplitModule(*M, NumOutputs, HandleModulePart, PreserveLocals);
87135
return 0;
88136
}

0 commit comments

Comments
 (0)