xref: /llvm-project/llvm/tools/llvm-cgdata/llvm-cgdata.cpp (revision 9cbd705e32bbb869c897696f4a6659f2ce00b64a)
19bb55568SKyungwoo Lee //===-- llvm-cgdata.cpp - LLVM CodeGen Data Tool --------------------------===//
29bb55568SKyungwoo Lee //
39bb55568SKyungwoo Lee // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
49bb55568SKyungwoo Lee // See https://llvm.org/LICENSE.txt for license information.
59bb55568SKyungwoo Lee // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
69bb55568SKyungwoo Lee //
79bb55568SKyungwoo Lee //===----------------------------------------------------------------------===//
89bb55568SKyungwoo Lee //
99bb55568SKyungwoo Lee // llvm-cgdata parses raw codegen data embedded in compiled binary files, and
109bb55568SKyungwoo Lee // merges them into a single .cgdata file. It can also inspect and maninuplate
119bb55568SKyungwoo Lee // a .cgdata file. This .cgdata can contain various codegen data like outlining
129bb55568SKyungwoo Lee // information, and it can be used to optimize the code in the subsequent build.
139bb55568SKyungwoo Lee //
149bb55568SKyungwoo Lee //===----------------------------------------------------------------------===//
159bb55568SKyungwoo Lee #include "llvm/ADT/StringRef.h"
169bb55568SKyungwoo Lee #include "llvm/CGData/CodeGenDataReader.h"
179bb55568SKyungwoo Lee #include "llvm/CGData/CodeGenDataWriter.h"
189bb55568SKyungwoo Lee #include "llvm/IR/LLVMContext.h"
199bb55568SKyungwoo Lee #include "llvm/Object/Archive.h"
209bb55568SKyungwoo Lee #include "llvm/Object/Binary.h"
219bb55568SKyungwoo Lee #include "llvm/Option/ArgList.h"
229bb55568SKyungwoo Lee #include "llvm/Option/Option.h"
239bb55568SKyungwoo Lee #include "llvm/Support/CommandLine.h"
249bb55568SKyungwoo Lee #include "llvm/Support/LLVMDriver.h"
259bb55568SKyungwoo Lee #include "llvm/Support/Path.h"
269bb55568SKyungwoo Lee #include "llvm/Support/VirtualFileSystem.h"
279bb55568SKyungwoo Lee #include "llvm/Support/WithColor.h"
289bb55568SKyungwoo Lee #include "llvm/Support/raw_ostream.h"
299bb55568SKyungwoo Lee 
309bb55568SKyungwoo Lee using namespace llvm;
319bb55568SKyungwoo Lee using namespace llvm::object;
329bb55568SKyungwoo Lee 
339bb55568SKyungwoo Lee enum CGDataFormat {
349bb55568SKyungwoo Lee   Invalid,
359bb55568SKyungwoo Lee   Text,
369bb55568SKyungwoo Lee   Binary,
379bb55568SKyungwoo Lee };
389bb55568SKyungwoo Lee 
399bb55568SKyungwoo Lee enum CGDataAction {
409bb55568SKyungwoo Lee   Convert,
419bb55568SKyungwoo Lee   Merge,
429bb55568SKyungwoo Lee   Show,
439bb55568SKyungwoo Lee };
449bb55568SKyungwoo Lee 
459bb55568SKyungwoo Lee // Command-line option boilerplate.
469bb55568SKyungwoo Lee namespace {
479bb55568SKyungwoo Lee enum ID {
489bb55568SKyungwoo Lee   OPT_INVALID = 0, // This is not an option ID.
499bb55568SKyungwoo Lee #define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
509bb55568SKyungwoo Lee #include "Opts.inc"
519bb55568SKyungwoo Lee #undef OPTION
529bb55568SKyungwoo Lee };
539bb55568SKyungwoo Lee 
54dd647e3eSChandler Carruth #define OPTTABLE_STR_TABLE_CODE
559bb55568SKyungwoo Lee #include "Opts.inc"
56dd647e3eSChandler Carruth #undef OPTTABLE_STR_TABLE_CODE
57dd647e3eSChandler Carruth 
58dd647e3eSChandler Carruth #define OPTTABLE_PREFIXES_TABLE_CODE
59dd647e3eSChandler Carruth #include "Opts.inc"
60dd647e3eSChandler Carruth #undef OPTTABLE_PREFIXES_TABLE_CODE
619bb55568SKyungwoo Lee 
629bb55568SKyungwoo Lee using namespace llvm::opt;
639bb55568SKyungwoo Lee static constexpr opt::OptTable::Info InfoTable[] = {
649bb55568SKyungwoo Lee #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
659bb55568SKyungwoo Lee #include "Opts.inc"
669bb55568SKyungwoo Lee #undef OPTION
679bb55568SKyungwoo Lee };
689bb55568SKyungwoo Lee 
699bb55568SKyungwoo Lee class CGDataOptTable : public opt::GenericOptTable {
709bb55568SKyungwoo Lee public:
71dd647e3eSChandler Carruth   CGDataOptTable()
72dd647e3eSChandler Carruth       : GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {}
739bb55568SKyungwoo Lee };
749bb55568SKyungwoo Lee } // end anonymous namespace
759bb55568SKyungwoo Lee 
769bb55568SKyungwoo Lee // Options
779bb55568SKyungwoo Lee static StringRef ToolName;
789bb55568SKyungwoo Lee static StringRef OutputFilename = "-";
799bb55568SKyungwoo Lee static StringRef Filename;
809bb55568SKyungwoo Lee static bool ShowCGDataVersion;
81d23c5c2dSKyungwoo Lee static bool SkipTrim;
829bb55568SKyungwoo Lee static CGDataAction Action;
839bb55568SKyungwoo Lee static std::optional<CGDataFormat> OutputFormat;
849bb55568SKyungwoo Lee static std::vector<std::string> InputFilenames;
859bb55568SKyungwoo Lee 
86*9cbd705eSAmr Hesham static void exitWithError(Twine Message, StringRef Whence = "",
87*9cbd705eSAmr Hesham                           StringRef Hint = "") {
889bb55568SKyungwoo Lee   WithColor::error();
899bb55568SKyungwoo Lee   if (!Whence.empty())
909bb55568SKyungwoo Lee     errs() << Whence << ": ";
919bb55568SKyungwoo Lee   errs() << Message << "\n";
929bb55568SKyungwoo Lee   if (!Hint.empty())
939bb55568SKyungwoo Lee     WithColor::note() << Hint << "\n";
949bb55568SKyungwoo Lee   ::exit(1);
959bb55568SKyungwoo Lee }
969bb55568SKyungwoo Lee 
979bb55568SKyungwoo Lee static void exitWithError(Error E, StringRef Whence = "") {
989bb55568SKyungwoo Lee   if (E.isA<CGDataError>()) {
999bb55568SKyungwoo Lee     handleAllErrors(std::move(E), [&](const CGDataError &IPE) {
100*9cbd705eSAmr Hesham       exitWithError(IPE.message(), Whence);
1019bb55568SKyungwoo Lee     });
1029bb55568SKyungwoo Lee     return;
1039bb55568SKyungwoo Lee   }
1049bb55568SKyungwoo Lee 
105*9cbd705eSAmr Hesham   exitWithError(toString(std::move(E)), Whence);
1069bb55568SKyungwoo Lee }
1079bb55568SKyungwoo Lee 
1089bb55568SKyungwoo Lee static void exitWithErrorCode(std::error_code EC, StringRef Whence = "") {
109*9cbd705eSAmr Hesham   exitWithError(EC.message(), Whence);
1109bb55568SKyungwoo Lee }
1119bb55568SKyungwoo Lee 
1129bb55568SKyungwoo Lee static int convert_main(int argc, const char *argv[]) {
1139bb55568SKyungwoo Lee   std::error_code EC;
1149bb55568SKyungwoo Lee   raw_fd_ostream OS(OutputFilename, EC,
1159bb55568SKyungwoo Lee                     OutputFormat == CGDataFormat::Text
1169bb55568SKyungwoo Lee                         ? sys::fs::OF_TextWithCRLF
1179bb55568SKyungwoo Lee                         : sys::fs::OF_None);
1189bb55568SKyungwoo Lee   if (EC)
1199bb55568SKyungwoo Lee     exitWithErrorCode(EC, OutputFilename);
1209bb55568SKyungwoo Lee 
1219bb55568SKyungwoo Lee   auto FS = vfs::getRealFileSystem();
1229bb55568SKyungwoo Lee   auto ReaderOrErr = CodeGenDataReader::create(Filename, *FS);
1239bb55568SKyungwoo Lee   if (Error E = ReaderOrErr.takeError())
1249bb55568SKyungwoo Lee     exitWithError(std::move(E), Filename);
1259bb55568SKyungwoo Lee 
1269bb55568SKyungwoo Lee   CodeGenDataWriter Writer;
1279bb55568SKyungwoo Lee   auto Reader = ReaderOrErr->get();
1289bb55568SKyungwoo Lee   if (Reader->hasOutlinedHashTree()) {
1299bb55568SKyungwoo Lee     OutlinedHashTreeRecord Record(Reader->releaseOutlinedHashTree());
1309bb55568SKyungwoo Lee     Writer.addRecord(Record);
1319bb55568SKyungwoo Lee   }
132ffcf3c86SKyungwoo Lee   if (Reader->hasStableFunctionMap()) {
133ffcf3c86SKyungwoo Lee     StableFunctionMapRecord Record(Reader->releaseStableFunctionMap());
134ffcf3c86SKyungwoo Lee     Writer.addRecord(Record);
135ffcf3c86SKyungwoo Lee   }
1369bb55568SKyungwoo Lee 
1379bb55568SKyungwoo Lee   if (OutputFormat == CGDataFormat::Text) {
1389bb55568SKyungwoo Lee     if (Error E = Writer.writeText(OS))
1399bb55568SKyungwoo Lee       exitWithError(std::move(E));
1409bb55568SKyungwoo Lee   } else {
1419bb55568SKyungwoo Lee     if (Error E = Writer.write(OS))
1429bb55568SKyungwoo Lee       exitWithError(std::move(E));
1439bb55568SKyungwoo Lee   }
1449bb55568SKyungwoo Lee 
1459bb55568SKyungwoo Lee   return 0;
1469bb55568SKyungwoo Lee }
1479bb55568SKyungwoo Lee 
1489bb55568SKyungwoo Lee static bool handleBuffer(StringRef Filename, MemoryBufferRef Buffer,
149ffcf3c86SKyungwoo Lee                          OutlinedHashTreeRecord &GlobalOutlineRecord,
150ffcf3c86SKyungwoo Lee                          StableFunctionMapRecord &GlobalFunctionMapRecord);
1519bb55568SKyungwoo Lee 
1529bb55568SKyungwoo Lee static bool handleArchive(StringRef Filename, Archive &Arch,
153ffcf3c86SKyungwoo Lee                           OutlinedHashTreeRecord &GlobalOutlineRecord,
154ffcf3c86SKyungwoo Lee                           StableFunctionMapRecord &GlobalFunctionMapRecord) {
1559bb55568SKyungwoo Lee   bool Result = true;
1569bb55568SKyungwoo Lee   Error Err = Error::success();
1579bb55568SKyungwoo Lee   for (const auto &Child : Arch.children(Err)) {
1589bb55568SKyungwoo Lee     auto BuffOrErr = Child.getMemoryBufferRef();
1599bb55568SKyungwoo Lee     if (Error E = BuffOrErr.takeError())
1609bb55568SKyungwoo Lee       exitWithError(std::move(E), Filename);
1619bb55568SKyungwoo Lee     auto NameOrErr = Child.getName();
1629bb55568SKyungwoo Lee     if (Error E = NameOrErr.takeError())
1639bb55568SKyungwoo Lee       exitWithError(std::move(E), Filename);
1649bb55568SKyungwoo Lee     std::string Name = (Filename + "(" + NameOrErr.get() + ")").str();
165ffcf3c86SKyungwoo Lee     Result &= handleBuffer(Name, BuffOrErr.get(), GlobalOutlineRecord,
166ffcf3c86SKyungwoo Lee                            GlobalFunctionMapRecord);
1679bb55568SKyungwoo Lee   }
1689bb55568SKyungwoo Lee   if (Err)
1699bb55568SKyungwoo Lee     exitWithError(std::move(Err), Filename);
1709bb55568SKyungwoo Lee   return Result;
1719bb55568SKyungwoo Lee }
1729bb55568SKyungwoo Lee 
1739bb55568SKyungwoo Lee static bool handleBuffer(StringRef Filename, MemoryBufferRef Buffer,
174ffcf3c86SKyungwoo Lee                          OutlinedHashTreeRecord &GlobalOutlineRecord,
175ffcf3c86SKyungwoo Lee                          StableFunctionMapRecord &GlobalFunctionMapRecord) {
1769bb55568SKyungwoo Lee   Expected<std::unique_ptr<object::Binary>> BinOrErr =
1779bb55568SKyungwoo Lee       object::createBinary(Buffer);
1789bb55568SKyungwoo Lee   if (Error E = BinOrErr.takeError())
1799bb55568SKyungwoo Lee     exitWithError(std::move(E), Filename);
1809bb55568SKyungwoo Lee 
1819bb55568SKyungwoo Lee   bool Result = true;
1829bb55568SKyungwoo Lee   if (auto *Obj = dyn_cast<ObjectFile>(BinOrErr->get())) {
183ffcf3c86SKyungwoo Lee     if (Error E = CodeGenDataReader::mergeFromObjectFile(
184ffcf3c86SKyungwoo Lee             Obj, GlobalOutlineRecord, GlobalFunctionMapRecord))
1859bb55568SKyungwoo Lee       exitWithError(std::move(E), Filename);
1869bb55568SKyungwoo Lee   } else if (auto *Arch = dyn_cast<Archive>(BinOrErr->get())) {
187ffcf3c86SKyungwoo Lee     Result &= handleArchive(Filename, *Arch, GlobalOutlineRecord,
188ffcf3c86SKyungwoo Lee                             GlobalFunctionMapRecord);
1899bb55568SKyungwoo Lee   } else {
1909bb55568SKyungwoo Lee     // TODO: Support for the MachO universal binary format.
1919bb55568SKyungwoo Lee     errs() << "Error: unsupported binary file: " << Filename << "\n";
1929bb55568SKyungwoo Lee     Result = false;
1939bb55568SKyungwoo Lee   }
1949bb55568SKyungwoo Lee 
1959bb55568SKyungwoo Lee   return Result;
1969bb55568SKyungwoo Lee }
1979bb55568SKyungwoo Lee 
1989bb55568SKyungwoo Lee static bool handleFile(StringRef Filename,
199ffcf3c86SKyungwoo Lee                        OutlinedHashTreeRecord &GlobalOutlineRecord,
200ffcf3c86SKyungwoo Lee                        StableFunctionMapRecord &GlobalFunctionMapRecord) {
2019bb55568SKyungwoo Lee   ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
2029bb55568SKyungwoo Lee       MemoryBuffer::getFileOrSTDIN(Filename);
2039bb55568SKyungwoo Lee   if (std::error_code EC = BuffOrErr.getError())
2049bb55568SKyungwoo Lee     exitWithErrorCode(EC, Filename);
205ffcf3c86SKyungwoo Lee   return handleBuffer(Filename, *BuffOrErr.get(), GlobalOutlineRecord,
206ffcf3c86SKyungwoo Lee                       GlobalFunctionMapRecord);
2079bb55568SKyungwoo Lee }
2089bb55568SKyungwoo Lee 
2099bb55568SKyungwoo Lee static int merge_main(int argc, const char *argv[]) {
2109bb55568SKyungwoo Lee   bool Result = true;
2119bb55568SKyungwoo Lee   OutlinedHashTreeRecord GlobalOutlineRecord;
212ffcf3c86SKyungwoo Lee   StableFunctionMapRecord GlobalFunctionMapRecord;
2139bb55568SKyungwoo Lee   for (auto &Filename : InputFilenames)
214ffcf3c86SKyungwoo Lee     Result &=
215ffcf3c86SKyungwoo Lee         handleFile(Filename, GlobalOutlineRecord, GlobalFunctionMapRecord);
2169bb55568SKyungwoo Lee 
2179bb55568SKyungwoo Lee   if (!Result)
2189bb55568SKyungwoo Lee     exitWithError("failed to merge codegen data files.");
2199bb55568SKyungwoo Lee 
220d23c5c2dSKyungwoo Lee   GlobalFunctionMapRecord.finalize(SkipTrim);
221ffcf3c86SKyungwoo Lee 
2229bb55568SKyungwoo Lee   CodeGenDataWriter Writer;
2239bb55568SKyungwoo Lee   if (!GlobalOutlineRecord.empty())
2249bb55568SKyungwoo Lee     Writer.addRecord(GlobalOutlineRecord);
225ffcf3c86SKyungwoo Lee   if (!GlobalFunctionMapRecord.empty())
226ffcf3c86SKyungwoo Lee     Writer.addRecord(GlobalFunctionMapRecord);
2279bb55568SKyungwoo Lee 
2289bb55568SKyungwoo Lee   std::error_code EC;
2299bb55568SKyungwoo Lee   raw_fd_ostream OS(OutputFilename, EC,
2309bb55568SKyungwoo Lee                     OutputFormat == CGDataFormat::Text
2319bb55568SKyungwoo Lee                         ? sys::fs::OF_TextWithCRLF
2329bb55568SKyungwoo Lee                         : sys::fs::OF_None);
2339bb55568SKyungwoo Lee   if (EC)
2349bb55568SKyungwoo Lee     exitWithErrorCode(EC, OutputFilename);
2359bb55568SKyungwoo Lee 
2369bb55568SKyungwoo Lee   if (OutputFormat == CGDataFormat::Text) {
2379bb55568SKyungwoo Lee     if (Error E = Writer.writeText(OS))
2389bb55568SKyungwoo Lee       exitWithError(std::move(E));
2399bb55568SKyungwoo Lee   } else {
2409bb55568SKyungwoo Lee     if (Error E = Writer.write(OS))
2419bb55568SKyungwoo Lee       exitWithError(std::move(E));
2429bb55568SKyungwoo Lee   }
2439bb55568SKyungwoo Lee 
2449bb55568SKyungwoo Lee   return 0;
2459bb55568SKyungwoo Lee }
2469bb55568SKyungwoo Lee 
2479bb55568SKyungwoo Lee static int show_main(int argc, const char *argv[]) {
2489bb55568SKyungwoo Lee   std::error_code EC;
2499bb55568SKyungwoo Lee   raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::OF_TextWithCRLF);
2509bb55568SKyungwoo Lee   if (EC)
2519bb55568SKyungwoo Lee     exitWithErrorCode(EC, OutputFilename);
2529bb55568SKyungwoo Lee 
2539bb55568SKyungwoo Lee   auto FS = vfs::getRealFileSystem();
2549bb55568SKyungwoo Lee   auto ReaderOrErr = CodeGenDataReader::create(Filename, *FS);
2559bb55568SKyungwoo Lee   if (Error E = ReaderOrErr.takeError())
2569bb55568SKyungwoo Lee     exitWithError(std::move(E), Filename);
2579bb55568SKyungwoo Lee 
2589bb55568SKyungwoo Lee   auto Reader = ReaderOrErr->get();
2599bb55568SKyungwoo Lee   if (ShowCGDataVersion)
2609bb55568SKyungwoo Lee     OS << "Version: " << Reader->getVersion() << "\n";
2619bb55568SKyungwoo Lee 
2629bb55568SKyungwoo Lee   if (Reader->hasOutlinedHashTree()) {
2639bb55568SKyungwoo Lee     auto Tree = Reader->releaseOutlinedHashTree();
2649bb55568SKyungwoo Lee     OS << "Outlined hash tree:\n";
2659bb55568SKyungwoo Lee     OS << "  Total Node Count: " << Tree->size() << "\n";
2669bb55568SKyungwoo Lee     OS << "  Terminal Node Count: " << Tree->size(/*GetTerminalCountOnly=*/true)
2679bb55568SKyungwoo Lee        << "\n";
2689bb55568SKyungwoo Lee     OS << "  Depth: " << Tree->depth() << "\n";
2699bb55568SKyungwoo Lee   }
270ffcf3c86SKyungwoo Lee   if (Reader->hasStableFunctionMap()) {
271ffcf3c86SKyungwoo Lee     auto Map = Reader->releaseStableFunctionMap();
272ffcf3c86SKyungwoo Lee     OS << "Stable function map:\n";
273ffcf3c86SKyungwoo Lee     OS << "  Unique hash Count: " << Map->size() << "\n";
274ffcf3c86SKyungwoo Lee     OS << "  Total function Count: "
275ffcf3c86SKyungwoo Lee        << Map->size(StableFunctionMap::TotalFunctionCount) << "\n";
276ffcf3c86SKyungwoo Lee     OS << "  Mergeable function Count: "
277ffcf3c86SKyungwoo Lee        << Map->size(StableFunctionMap::MergeableFunctionCount) << "\n";
278ffcf3c86SKyungwoo Lee   }
2799bb55568SKyungwoo Lee 
2809bb55568SKyungwoo Lee   return 0;
2819bb55568SKyungwoo Lee }
2829bb55568SKyungwoo Lee 
2839bb55568SKyungwoo Lee static void parseArgs(int argc, char **argv) {
2849bb55568SKyungwoo Lee   CGDataOptTable Tbl;
2859bb55568SKyungwoo Lee   ToolName = argv[0];
2869bb55568SKyungwoo Lee   llvm::BumpPtrAllocator A;
2879bb55568SKyungwoo Lee   llvm::StringSaver Saver{A};
2889bb55568SKyungwoo Lee   llvm::opt::InputArgList Args =
2899bb55568SKyungwoo Lee       Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) {
2909bb55568SKyungwoo Lee         llvm::errs() << Msg << '\n';
2919bb55568SKyungwoo Lee         std::exit(1);
2929bb55568SKyungwoo Lee       });
2939bb55568SKyungwoo Lee 
2949bb55568SKyungwoo Lee   if (Args.hasArg(OPT_help)) {
2959bb55568SKyungwoo Lee     Tbl.printHelp(
2969bb55568SKyungwoo Lee         llvm::outs(),
2979bb55568SKyungwoo Lee         "llvm-cgdata <action> [options] (<binary files>|<.cgdata file>)",
2989bb55568SKyungwoo Lee         ToolName.str().c_str());
2999bb55568SKyungwoo Lee     std::exit(0);
3009bb55568SKyungwoo Lee   }
3019bb55568SKyungwoo Lee   if (Args.hasArg(OPT_version)) {
3029bb55568SKyungwoo Lee     cl::PrintVersionMessage();
3039bb55568SKyungwoo Lee     std::exit(0);
3049bb55568SKyungwoo Lee   }
3059bb55568SKyungwoo Lee 
3069bb55568SKyungwoo Lee   ShowCGDataVersion = Args.hasArg(OPT_cgdata_version);
307d23c5c2dSKyungwoo Lee   SkipTrim = Args.hasArg(OPT_skip_trim);
3089bb55568SKyungwoo Lee 
3099bb55568SKyungwoo Lee   if (opt::Arg *A = Args.getLastArg(OPT_format)) {
3109bb55568SKyungwoo Lee     StringRef OF = A->getValue();
3119bb55568SKyungwoo Lee     OutputFormat = StringSwitch<CGDataFormat>(OF)
3129bb55568SKyungwoo Lee                        .Case("text", CGDataFormat::Text)
3139bb55568SKyungwoo Lee                        .Case("binary", CGDataFormat::Binary)
3149bb55568SKyungwoo Lee                        .Default(CGDataFormat::Invalid);
3159bb55568SKyungwoo Lee     if (OutputFormat == CGDataFormat::Invalid)
3169bb55568SKyungwoo Lee       exitWithError("unsupported format '" + OF + "'");
3179bb55568SKyungwoo Lee   }
3189bb55568SKyungwoo Lee 
3199bb55568SKyungwoo Lee   InputFilenames = Args.getAllArgValues(OPT_INPUT);
3209bb55568SKyungwoo Lee   if (InputFilenames.empty())
3219bb55568SKyungwoo Lee     exitWithError("No input file is specified.");
3229bb55568SKyungwoo Lee   Filename = InputFilenames[0];
3239bb55568SKyungwoo Lee 
3249bb55568SKyungwoo Lee   if (Args.hasArg(OPT_output)) {
3259bb55568SKyungwoo Lee     OutputFilename = Args.getLastArgValue(OPT_output);
3269bb55568SKyungwoo Lee     for (auto &Filename : InputFilenames)
3279bb55568SKyungwoo Lee       if (Filename == OutputFilename)
3289bb55568SKyungwoo Lee         exitWithError(
3299bb55568SKyungwoo Lee             "Input file name cannot be the same as the output file name!\n");
3309bb55568SKyungwoo Lee   }
3319bb55568SKyungwoo Lee 
3329bb55568SKyungwoo Lee   opt::Arg *ActionArg = nullptr;
3339bb55568SKyungwoo Lee   for (opt::Arg *Arg : Args.filtered(OPT_action_group)) {
3349bb55568SKyungwoo Lee     if (ActionArg)
3359bb55568SKyungwoo Lee       exitWithError("Only one action is allowed.");
3369bb55568SKyungwoo Lee     ActionArg = Arg;
3379bb55568SKyungwoo Lee   }
3389bb55568SKyungwoo Lee   if (!ActionArg)
3399bb55568SKyungwoo Lee     exitWithError("One action is required.");
3409bb55568SKyungwoo Lee 
3419bb55568SKyungwoo Lee   switch (ActionArg->getOption().getID()) {
3429bb55568SKyungwoo Lee   case OPT_show:
3439bb55568SKyungwoo Lee     if (InputFilenames.size() != 1)
3449bb55568SKyungwoo Lee       exitWithError("only one input file is allowed.");
3459bb55568SKyungwoo Lee     Action = CGDataAction::Show;
3469bb55568SKyungwoo Lee     break;
3479bb55568SKyungwoo Lee   case OPT_convert:
3489bb55568SKyungwoo Lee     // The default output format is text for convert.
3499bb55568SKyungwoo Lee     if (!OutputFormat)
3509bb55568SKyungwoo Lee       OutputFormat = CGDataFormat::Text;
3519bb55568SKyungwoo Lee     if (InputFilenames.size() != 1)
3529bb55568SKyungwoo Lee       exitWithError("only one input file is allowed.");
3539bb55568SKyungwoo Lee     Action = CGDataAction::Convert;
3549bb55568SKyungwoo Lee     break;
3559bb55568SKyungwoo Lee   case OPT_merge:
3569bb55568SKyungwoo Lee     // The default output format is binary for merge.
3579bb55568SKyungwoo Lee     if (!OutputFormat)
3589bb55568SKyungwoo Lee       OutputFormat = CGDataFormat::Binary;
3599bb55568SKyungwoo Lee     Action = CGDataAction::Merge;
3609bb55568SKyungwoo Lee     break;
3619bb55568SKyungwoo Lee   default:
3629bb55568SKyungwoo Lee     llvm_unreachable("unrecognized action");
3639bb55568SKyungwoo Lee   }
3649bb55568SKyungwoo Lee }
3659bb55568SKyungwoo Lee 
3669bb55568SKyungwoo Lee int llvm_cgdata_main(int argc, char **argvNonConst, const llvm::ToolContext &) {
3679bb55568SKyungwoo Lee   const char **argv = const_cast<const char **>(argvNonConst);
3689bb55568SKyungwoo Lee   parseArgs(argc, argvNonConst);
3699bb55568SKyungwoo Lee 
3709bb55568SKyungwoo Lee   switch (Action) {
3719bb55568SKyungwoo Lee   case CGDataAction::Convert:
3729bb55568SKyungwoo Lee     return convert_main(argc, argv);
3739bb55568SKyungwoo Lee   case CGDataAction::Merge:
3749bb55568SKyungwoo Lee     return merge_main(argc, argv);
3759bb55568SKyungwoo Lee   case CGDataAction::Show:
3769bb55568SKyungwoo Lee     return show_main(argc, argv);
3779bb55568SKyungwoo Lee   }
3789bb55568SKyungwoo Lee 
379723a9b87SJie Fu   llvm_unreachable("unrecognized action");
3809bb55568SKyungwoo Lee }
381