xref: /llvm-project/llvm/tools/llvm-split/llvm-split.cpp (revision a2692ac23f1421097f0d51c7325045ed38db6408)
1 //===-- llvm-split: command line tool for testing module splitting --------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This program can be used to test the llvm::SplitModule and
10 // TargetMachine::splitModule functions.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "llvm/ADT/StringExtras.h"
15 #include "llvm/Bitcode/BitcodeWriter.h"
16 #include "llvm/IR/LLVMContext.h"
17 #include "llvm/IR/Verifier.h"
18 #include "llvm/IRReader/IRReader.h"
19 #include "llvm/MC/TargetRegistry.h"
20 #include "llvm/Support/CommandLine.h"
21 #include "llvm/Support/FileSystem.h"
22 #include "llvm/Support/InitLLVM.h"
23 #include "llvm/Support/SourceMgr.h"
24 #include "llvm/Support/TargetSelect.h"
25 #include "llvm/Support/ToolOutputFile.h"
26 #include "llvm/Support/WithColor.h"
27 #include "llvm/Support/raw_ostream.h"
28 #include "llvm/Target/TargetMachine.h"
29 #include "llvm/TargetParser/Triple.h"
30 #include "llvm/Transforms/Utils/SplitModule.h"
31 
32 using namespace llvm;
33 
34 static cl::OptionCategory SplitCategory("Split Options");
35 
36 static cl::opt<std::string> InputFilename(cl::Positional,
37                                           cl::desc("<input bitcode file>"),
38                                           cl::init("-"),
39                                           cl::value_desc("filename"),
40                                           cl::cat(SplitCategory));
41 
42 static cl::opt<std::string> OutputFilename("o",
43                                            cl::desc("Override output filename"),
44                                            cl::value_desc("filename"),
45                                            cl::cat(SplitCategory));
46 
47 static cl::opt<unsigned> NumOutputs("j", cl::Prefix, cl::init(2),
48                                     cl::desc("Number of output files"),
49                                     cl::cat(SplitCategory));
50 
51 static cl::opt<bool>
52     PreserveLocals("preserve-locals", cl::Prefix, cl::init(false),
53                    cl::desc("Split without externalizing locals"),
54                    cl::cat(SplitCategory));
55 
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 
67 int main(int argc, char **argv) {
68   InitLLVM X(argc, argv);
69 
70   LLVMContext Context;
71   SMDiagnostic Err;
72   cl::HideUnrelatedOptions({&SplitCategory, &getColorCategory()});
73   cl::ParseCommandLineOptions(argc, argv, "LLVM module splitter\n");
74 
75   std::unique_ptr<TargetMachine> TM;
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 = std::unique_ptr<TargetMachine>(T->createTargetMachine(
89         MTriple, MCPU, /*FS*/ "", Options, std::nullopt, std::nullopt));
90   }
91 
92   std::unique_ptr<Module> M = parseIRFile(InputFilename, Err, Context);
93 
94   if (!M) {
95     Err.print(argv[0], errs());
96     return 1;
97   }
98 
99   unsigned I = 0;
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   }
133 
134   SplitModule(*M, NumOutputs, HandleModulePart, PreserveLocals);
135   return 0;
136 }
137