Jlm
Loading...
Searching...
No Matches
CommandLine.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2022 Nico Reißmann <nico.reissmann@gmail.com>
3 * See COPYING for terms of redistribution.
4 */
5
11
12#include <llvm/Support/CommandLine.h>
13
14#include <unordered_map>
15
16namespace jlm::tooling
17{
18
20
21std::string_view
23{
24 static std::unordered_map<OptimizationLevel, std::string_view> map({
25 { OptimizationLevel::O0, "O0" },
26 { OptimizationLevel::O1, "O1" },
27 { OptimizationLevel::O2, "O2" },
28 { OptimizationLevel::O3, "O3" },
29 });
30
31 JLM_ASSERT(map.find(optimizationLevel) != map.end());
32 return map[optimizationLevel];
33}
34
35std::string_view
37{
38 static std::unordered_map<LanguageStandard, std::string_view> map(
39 { { LanguageStandard::None, "" },
40 { LanguageStandard::Gnu89, "gnu89" },
41 { LanguageStandard::Gnu99, "gnu99" },
42 { LanguageStandard::C89, "c89" },
43 { LanguageStandard::C99, "c99" },
44 { LanguageStandard::C11, "c11" },
45 { LanguageStandard::Cpp98, "c++98" },
46 { LanguageStandard::Cpp03, "c++03" },
47 { LanguageStandard::Cpp11, "c++11" },
48 { LanguageStandard::Cpp14, "c++14" } });
49
50 JLM_ASSERT(map.find(languageStandard) != map.end());
51 return map[languageStandard];
52}
53
54void
56{
57 OnlyPrintCommands_ = false;
59 Verbose_ = false;
60 Rdynamic_ = false;
61 Suppress_ = false;
62 UsePthreads_ = false;
63
64 Md_ = false;
65
68
69 OutputFile_ = util::FilePath("a.out");
70 Libraries_.clear();
71 MacroDefinitions_.clear();
72 LibraryPaths_.clear();
73 Warnings_.clear();
74 IncludePaths_.clear();
75 Flags_.clear();
77
78 Compilations_.clear();
79}
80
81void
90
93{
95 { OptimizationId::AAAndersenAgnostic, "AAAndersenAgnostic" },
96 { OptimizationId::AAAndersenRegionAware, "AAAndersenRegionAware" },
97 { OptimizationId::AggregateAllocaSplitting, "AggregateAllocaSplitting" },
98 { OptimizationId::CommonNodeElimination, "CommonNodeElimination" },
99 { OptimizationId::DeadNodeElimination, "DeadNodeElimination" },
100 { OptimizationId::FunctionInlining, "FunctionInlining" },
101 { OptimizationId::IfConversion, "IfConversion" },
102 { OptimizationId::InvariantValueRedirection, "InvariantValueRedirection" },
103 { OptimizationId::IOBarrierElimination, "IOBarrierElimination" },
104 { OptimizationId::LoadChainSeparation, "LoadChainSeparation" },
105 { OptimizationId::LoopStrengthReduction, "LoopStrengthReduction" },
106 { OptimizationId::LoopUnrolling, "LoopUnrolling" },
107 { OptimizationId::LoopUnswitching, "LoopUnswitching" },
108 { OptimizationId::NodeHoisting, "NodeHoisting" },
109 { OptimizationId::NodePullIn, "NodePullIn" },
110 { OptimizationId::NodePushOut, "NodePushOut" },
111 { OptimizationId::NodeReduction, "NodeReduction" },
112 { OptimizationId::PredicateCorrelation, "PredicateCorrelation" },
113 { OptimizationId::RvsdgTreePrinter, "RvsdgTreePrinter" },
114 { OptimizationId::ScalarEvolution, "ScalarEvolution" },
115 { OptimizationId::StoreValueForwarding, "StoreValueForwarding" }
116 };
117
118 auto firstIndex = static_cast<size_t>(OptimizationId::FirstEnumValue);
119 auto lastIndex = static_cast<size_t>(OptimizationId::LastEnumValue);
120 JLM_ASSERT(map.Size() == lastIndex - firstIndex - 1);
121 return map;
122}
123
126 std::string_view commandLineArgument)
127{
128 // TODO: Deprecated, to be removed
129 if (commandLineArgument == "ThetaGammaInversion")
131
132 const auto & map = GetOptimizationIdCommandLineMap();
133
134 if (map.HasValue(commandLineArgument))
135 return map.LookupValue(commandLineArgument);
136
137 throw util::Error(util::strfmt("Unknown command line argument: ", commandLineArgument));
138}
139
140std::string_view
142{
143 const auto & map = GetOptimizationIdCommandLineMap();
144
145 if (map.HasKey(optimizationId))
146 return map.LookupKey(optimizationId);
147
148 throw util::Error("Unknown optimization identifier");
149}
150
153 std::string_view commandLineArgument)
154{
155 try
156 {
157 return GetStatisticsIdCommandLineArguments().LookupValue(commandLineArgument);
158 }
159 catch (...)
160 {
161 throw util::Error(util::strfmt("Unknown command line argument: ", commandLineArgument));
162 }
163}
164
165std::string_view
167{
168 try
169 {
170 return GetStatisticsIdCommandLineArguments().LookupKey(statisticsId);
171 }
172 catch (...)
173 {
174 throw util::Error("Unknown statistics identifier");
175 }
176}
177
178std::string_view
180{
181 static std::unordered_map<InputFormat, std::string_view> map(
182 { { InputFormat::Llvm, "llvm" }, { InputFormat::Mlir, "mlir" } });
183
184 if (map.find(inputFormat) != map.end())
185 return map[inputFormat];
186
187 throw util::Error("Unknown input format");
188}
189
190std::string_view
192{
193 auto & mapping = GetOutputFormatCommandLineArguments();
194 return mapping.at(outputFormat);
195}
196
199{
201 { util::Statistics::Id::AggregateAllocaSplitting, "print-aggregate-alloca-splitting" },
202 { util::Statistics::Id::Aggregation, "print-aggregation-time" },
203 { util::Statistics::Id::AgnosticModRefSummarizer, "print-agnostic-mod-ref-summarization" },
204 { util::Statistics::Id::AliasAnalysisPrecisionEvaluation, "print-aa-precision-evaluation" },
205 { util::Statistics::Id::AndersenAnalysis, "print-andersen-analysis" },
206 { util::Statistics::Id::Annotation, "print-annotation-time" },
208 { util::Statistics::Id::ControlFlowRecovery, "print-cfr-time" },
209 { util::Statistics::Id::DataNodeToDelta, "printDataNodeToDelta" },
210 { util::Statistics::Id::DeadNodeElimination, "print-dne-stat" },
211 { util::Statistics::Id::FunctionInlining, "print-iln-stat" },
212 { util::Statistics::Id::IfConversion, "print-if-conversion" },
213 { util::Statistics::Id::InvariantValueRedirection, "printInvariantValueRedirection" },
214 { util::Statistics::Id::IOBarrierElimination, "print-io-barrier-elimination" },
215 { util::Statistics::Id::JlmToRvsdgConversion, "print-jlm-rvsdg-conversion" },
216 { util::Statistics::Id::LoopStrengthReduction, "print-loop-strength-reduction" },
217 { util::Statistics::Id::LoopUnrolling, "print-unroll-stat" },
218 { util::Statistics::Id::LoopUnswitching, "print-ivt-stat" },
219 { util::Statistics::Id::MemoryStateEncoder, "print-basicencoder-encoding" },
220 { util::Statistics::Id::PullNodes, "print-pull-stat" },
221 { util::Statistics::Id::PushNodes, "print-push-stat" },
222 { util::Statistics::Id::ReduceNodes, "print-reduction-stat" },
223 { util::Statistics::Id::RegionAwareModRefSummarizer, "print-mod-ref-summarization" },
224 { util::Statistics::Id::RvsdgConstruction, "print-rvsdg-construction" },
225 { util::Statistics::Id::RvsdgDestruction, "print-rvsdg-destruction" },
226 { util::Statistics::Id::RvsdgOptimization, "print-rvsdg-optimization" },
227 { util::Statistics::Id::RvsdgTreePrinter, "print-rvsdg-tree" },
228 { util::Statistics::Id::ScalarEvolution, "print-scalar-evolution" },
229 { util::Statistics::Id::StoreValueForwarding, "print-store-value-forwarding" },
230 };
231
232 auto firstIndex = static_cast<size_t>(util::Statistics::Id::FirstEnumValue);
233 auto lastIndex = static_cast<size_t>(util::Statistics::Id::LastEnumValue);
234 JLM_ASSERT(mapping.Size() == lastIndex - firstIndex - 1);
235 return mapping;
236}
237
238const std::unordered_map<JlmOptCommandLineOptions::OutputFormat, std::string_view> &
240{
241 static std::unordered_map<OutputFormat, std::string_view> mapping = {
242 { OutputFormat::Ascii, "ascii" }, { OutputFormat::Dot, "dot" },
243 { OutputFormat::Json, "json" }, { OutputFormat::JsonTree, "jsonTree" },
244 { OutputFormat::Llvm, "llvm" }, { OutputFormat::Mlir, "mlir" },
245 { OutputFormat::Tree, "tree" },
246 };
247
248 auto firstIndex = static_cast<size_t>(OutputFormat::FirstEnumValue);
249 auto lastIndex = static_cast<size_t>(OutputFormat::LastEnumValue);
250 JLM_ASSERT(mapping.size() == lastIndex - firstIndex - 1);
251 return mapping;
252}
253
254void
264
265void
267{
268 *this = JhlsCommandLineOptions();
269}
270
271static ::llvm::cl::OptionEnumValue
272CreateStatisticsOption(util::Statistics::Id statisticsId, std::string_view description)
273{
274 return ::clEnumValN(
275 statisticsId,
277 description);
278}
279
280static ::llvm::cl::OptionEnumValue
283 std::string_view description)
284{
285 return ::clEnumValN(
286 outputFormat,
288 description);
289}
290
291CommandLineParser::~CommandLineParser() noexcept = default;
292
293CommandLineParser::Exception::~Exception() noexcept = default;
294
295JlcCommandLineParser::~JlcCommandLineParser() noexcept = default;
296
297const JlcCommandLineOptions &
298JlcCommandLineParser::ParseCommandLineArguments(int argc, const char * const * argv)
299{
300 auto checkAndConvertJlmOptOptimizations =
301 [](const ::llvm::cl::list<std::string> & optimizations,
303 {
304 if (optimizations.empty() && optimizationLevel == JlcCommandLineOptions::OptimizationLevel::O3)
305 {
306 return std::vector({
336 });
337 }
338
339 std::vector<JlmOptCommandLineOptions::OptimizationId> optimizationIds;
340 for (auto & optimization : optimizations)
341 {
343 try
344 {
345 optimizationId =
347 }
348 catch (util::Error &)
349 {
350 throw CommandLineParser::Exception("Unknown jlm-opt optimization: " + optimization);
351 }
352
353 optimizationIds.emplace_back(optimizationId);
354 }
355
356 return optimizationIds;
357 };
358
359 CommandLineOptions_.Reset();
360
361 using namespace ::llvm;
362
363 /*
364 FIXME: The command line parser setup is currently redone
365 for every invocation of parse_cmdline. We should be able
366 to do it only once and then reset the parser on every
367 invocation of parse_cmdline.
368 */
369
370 cl::TopLevelSubCommand->reset();
371
372 cl::opt<bool> onlyPrintCommands(
373 "###",
374 cl::ValueDisallowed,
375 cl::desc("Print (but do not run) the commands for this compilation."));
376
377 cl::list<std::string> inputFiles(cl::Positional, cl::desc("<inputs>"));
378
379 cl::list<std::string> includePaths(
380 "I",
381 cl::Prefix,
382 cl::desc("Add directory <dir> to include search paths."),
383 cl::value_desc("dir"));
384
385 cl::list<std::string> libraryPaths(
386 "L",
387 cl::Prefix,
388 cl::desc("Add directory <dir> to library search paths."),
389 cl::value_desc("dir"));
390
391 cl::list<std::string> libraries(
392 "l",
393 cl::Prefix,
394 cl::desc("Search the library <lib> when linking."),
395 cl::value_desc("lib"));
396
397 cl::opt<std::string> outputFile("o", cl::desc("Write output to <file>."), cl::value_desc("file"));
398
399 cl::opt<bool> generateDebugInformation(
400 "g",
401 cl::ValueDisallowed,
402 cl::desc("Generate source-level debug information."));
403
404 cl::opt<bool> noLinking(
405 "c",
406 cl::ValueDisallowed,
407 cl::desc("Only run preprocess, compile, and assemble steps."));
408
409 cl::opt<std::string> optimizationLevel(
410 "O",
411 cl::Prefix,
412 cl::ValueOptional,
413 cl::desc("Optimization level. [O0, O1, O2, O3]"),
414 cl::value_desc("#"));
415
416 cl::list<std::string> macroDefinitions(
417 "D",
418 cl::Prefix,
419 cl::desc("Add <macro> to preprocessor macros."),
420 cl::value_desc("macro"));
421
422 cl::list<std::string> warnings(
423 "W",
424 cl::Prefix,
425 cl::desc("Enable specified warning."),
426 cl::value_desc("warning"));
427
428 cl::opt<std::string> languageStandard(
429 "std",
430 cl::desc("Language standard."),
431 cl::value_desc("standard"));
432
433 cl::list<std::string> flags("f", cl::Prefix, cl::desc("Specify flags."), cl::value_desc("flag"));
434
435 cl::list<std::string> jlmOptimizations(
436 "J",
437 cl::Prefix,
438 cl::desc("jlm-opt optimization. Run 'jlm-opt -help' for viable options."),
439 cl::value_desc("jlmopt"));
440
441 cl::opt<bool> verbose(
442 "v",
443 cl::ValueDisallowed,
444 cl::desc("Show commands to run and use verbose output. (Affects only clang for now)"));
445
446 cl::opt<bool> rDynamic(
447 "rdynamic",
448 cl::ValueDisallowed,
449 cl::desc("rDynamic option passed to clang"));
450
451 cl::opt<bool> suppress("w", cl::ValueDisallowed, cl::desc("Suppress all warnings"));
452
453 cl::opt<bool> usePthreads(
454 "pthread",
455 cl::ValueDisallowed,
456 cl::desc("Support POSIX threads in generated code"));
457
458 cl::opt<bool> mD(
459 "MD",
460 cl::ValueDisallowed,
461 cl::desc("Write a depfile containing user and system headers"));
462
463 cl::opt<std::string> mF(
464 "MF",
465 cl::desc("Write depfile output from -mD to <file>."),
466 cl::value_desc("file"));
467
468 cl::opt<std::string> mT(
469 "MT",
470 cl::desc("Specify name of main file output in depfile."),
471 cl::value_desc("value"));
472
473 cl::list<util::Statistics::Id> jlmOptPassStatistics(
474 "JlmOptPassStatistics",
475 cl::values(
478 "Collect control flow graph aggregation pass statistics."),
481 "Collect agnostic mod/ref summarizer pass statistics."),
484 "Collect Andersen alias analysis pass statistics."),
487 "Collect aggregation tree annotation pass statistics."),
490 "Collect memory state encoding pass statistics."),
493 "Collect common node elimination pass statistics."),
496 "Collect control flow recovery pass statistics."),
499 "Collect data node to delta node conversion pass statistics."),
502 "Collect dead node elimination pass statistics."),
505 "Collect function inlining pass statistics."),
508 "Collect invariant value redirection pass statistics."),
511 "Collect Jlm to RVSDG conversion pass statistics."),
514 "Collect loop strength reduction pass statistics."),
517 "Collect loop unrolling pass statistics."),
520 "Collect loop unswitching pass statistics."),
523 "Collect node pull pass statistics."),
526 "Collect node push pass statistics."),
529 "Collect node reduction pass statistics."),
532 "Collect region-aware mod/ref summarizer pass statistics."),
535 "Collect RVSDG construction pass statistics."),
538 "Collect RVSDG destruction pass statistics."),
541 "Collect RVSDG optimization pass statistics."),
544 "Collect RVSDG tree printer pass statistics."),
547 "Collect scalar evolution analysis pass statistics.")),
548 cl::desc("Collect jlm-opt pass statistics"));
549
550 cl::ParseCommandLineOptions(argc, argv);
551
552 /* Process parsed options */
553
554 static std::unordered_map<std::string, JlcCommandLineOptions::OptimizationLevel>
555 optimizationLevelMap({ { "0", JlcCommandLineOptions::OptimizationLevel::O0 },
559
560 static std::unordered_map<std::string, JlcCommandLineOptions::LanguageStandard>
561 languageStandardMap({ { "gnu89", JlcCommandLineOptions::LanguageStandard::Gnu89 },
571
572 if (!optimizationLevel.empty())
573 {
574 auto iterator = optimizationLevelMap.find(optimizationLevel);
575 if (iterator == optimizationLevelMap.end())
576 {
577 std::cerr << "Unknown optimization level.\n";
578 exit(EXIT_FAILURE);
579 }
580 CommandLineOptions_.OptimizationLevel_ = iterator->second;
581 }
582
583 if (!languageStandard.empty())
584 {
585 auto iterator = languageStandardMap.find(languageStandard);
586 if (iterator == languageStandardMap.end())
587 {
588 std::cerr << "Unknown language standard.\n";
589 exit(EXIT_FAILURE);
590 }
591 CommandLineOptions_.LanguageStandard_ = iterator->second;
592 }
593
594 if (inputFiles.empty())
595 {
596 std::cerr << "jlc: no input files.\n";
597 exit(EXIT_FAILURE);
598 }
599
600 if (inputFiles.size() > 1 && noLinking && !outputFile.empty())
601 {
602 std::cerr << "jlc: cannot specify -o when generating multiple output files.\n";
603 exit(EXIT_FAILURE);
604 }
605
606 auto jlmOptOptimizations =
607 checkAndConvertJlmOptOptimizations(jlmOptimizations, CommandLineOptions_.OptimizationLevel_);
608
609 CommandLineOptions_.Libraries_ = libraries;
610 CommandLineOptions_.MacroDefinitions_ = macroDefinitions;
611 CommandLineOptions_.LibraryPaths_ = libraryPaths;
612 CommandLineOptions_.Warnings_ = warnings;
613 CommandLineOptions_.IncludePaths_ = includePaths;
614 CommandLineOptions_.OnlyPrintCommands_ = onlyPrintCommands;
615 CommandLineOptions_.GenerateDebugInformation_ = generateDebugInformation;
616 CommandLineOptions_.Flags_ = flags;
617 CommandLineOptions_.JlmOptOptimizations_ = jlmOptOptimizations;
618 CommandLineOptions_.JlmOptPassStatistics_ = util::HashSet<util::Statistics::Id>(
619 { jlmOptPassStatistics.begin(), jlmOptPassStatistics.end() });
620 CommandLineOptions_.Verbose_ = verbose;
621 CommandLineOptions_.Rdynamic_ = rDynamic;
622 CommandLineOptions_.Suppress_ = suppress;
623 CommandLineOptions_.UsePthreads_ = usePthreads;
624 CommandLineOptions_.Md_ = mD;
625
626 for (auto & inputFile : inputFiles)
627 {
628 util::FilePath inputFilePath(inputFile);
629 if (IsObjectFile(inputFilePath))
630 {
631 /* FIXME: print a warning like clang if noLinking is true */
632 CommandLineOptions_.Compilations_.push_back(
633 { inputFilePath, util::FilePath(""), inputFilePath, "", false, false, false, true });
634
635 continue;
636 }
637
638 CommandLineOptions_.Compilations_.push_back(
639 { inputFilePath,
640 mF.empty() ? ToDependencyFile(inputFilePath) : util::FilePath(mF),
641 ToObjectFile(inputFilePath),
642 mT.empty() ? ToObjectFile(inputFilePath).name() : mT,
643 true,
644 true,
645 true,
646 !noLinking });
647 }
648
649 if (!outputFile.empty())
650 {
651 util::FilePath outputFilePath(outputFile);
652 if (noLinking)
653 {
654 JLM_ASSERT(CommandLineOptions_.Compilations_.size() == 1);
655 CommandLineOptions_.Compilations_[0].SetOutputFile(outputFilePath);
656 }
657 else
658 {
659 CommandLineOptions_.OutputFile_ = outputFilePath;
660 }
661 }
662
663 return CommandLineOptions_;
664}
665
667
669JlmOptCommandLineParser::ParseCommandLineArguments(int argc, const char * const * argv)
670{
671 using namespace ::llvm;
672
673 /*
674 FIXME: The command line parser setup is currently redone
675 for every invocation of parse_cmdline. We should be able
676 to do it only once and then reset the parser on every
677 invocation of parse_cmdline.
678 */
679
680 cl::TopLevelSubCommand->reset();
681
682 cl::opt<std::string> inputFile(cl::Positional, cl::desc("<input>"));
683
684 cl::opt<std::string> outputFile(
685 "o",
686 cl::init(""),
687 cl::desc("Write output to <file>"),
688 cl::value_desc("file"));
689
690 const auto statisticsDirectoryDefault = util::FilePath::TempDirectoryPath().Join("jlm");
691 const auto statisticDirectoryDescription =
692 "Write statistics and debug output to files in <dir>. Default is "
693 + statisticsDirectoryDefault.to_str() + ".";
694 cl::opt<std::string> statisticDirectory(
695 "s",
696 cl::init(statisticsDirectoryDefault.to_str()),
697 cl::desc(statisticDirectoryDescription),
698 cl::value_desc("dir"));
699
700 cl::opt<bool> dumpRvsdgGraphs(
701 "dumpRvsdgGraphs",
702 cl::init(false),
703 cl::desc("Dump RVSDG as json graphs after each transformation in debug folder."));
704
705 cl::list<util::Statistics::Id> printStatistics(
706 cl::values(
709 "Write aggregate alloca splitting statistics to file."),
712 "Write aggregation statistics to file."),
715 "Collect agnostic mod/ref summarization pass statistics."),
718 "Evaluate alias analysis precision and store to file"),
721 "Collect Andersen alias analysis pass statistics."),
724 "Write annotation statistics to file."),
727 "Write encoding statistics of basic encoder to file."),
730 "Write common node elimination statistics to file."),
733 "Write control flow recovery statistics to file."),
736 "Write data node to delta node conversion statistics to file."),
739 "Write dead node elimination statistics to file."),
742 "Write function inlining statistics to file."),
745 "Collect if-conversion transformation statistics"),
748 "Write invariant value redirection statistics to file."),
751 "Write Jlm to RVSDG conversion statistics to file."),
754 "Write loop strength reduction statistics to file."),
757 "Write loop unrolling statistics to file."),
760 "Collect loop unswitching pass statistics."),
763 "Write node pull statistics to file."),
766 "Write node push statistics to file."),
769 "Write node reduction statistics to file."),
772 "Collect region-aware mod/ref summarization statistics."),
775 "Write RVSDG construction statistics to file."),
778 "Write RVSDG destruction statistics to file."),
781 "Write RVSDG optimization statistics to file."),
784 "Write RVSDG tree printer pass statistics."),
787 "Write scalar evolution statistics to file."),
790 "Write store value forwarding statistics to file.")),
791 cl::desc("Write statistics"));
792
793#ifdef ENABLE_MLIR
794 auto llvmInputFormat = JlmOptCommandLineOptions::InputFormat::Llvm;
795 auto mlirInputFormat = JlmOptCommandLineOptions::InputFormat::Mlir;
796
797 cl::opt<JlmOptCommandLineOptions::InputFormat> inputFormat(
798 "input-format",
799 cl::desc("Select input format:"),
800 cl::values(
801 ::clEnumValN(
802 llvmInputFormat,
804 "Input LLVM IR [default]"),
805 ::clEnumValN(
806 mlirInputFormat,
808 "Input MLIR")),
809 cl::init(llvmInputFormat));
810#else
812#endif
813
814 cl::opt<JlmOptCommandLineOptions::OutputFormat> outputFormat(
815 "output-format",
816 cl::desc("Select output format:"),
817 cl::values(
822 "Output json dump"),
825 "Output Rvsdg tree as JSON"),
828 "Output LLVM IR [default]"),
829#ifdef ENABLE_MLIR
831#endif
834 "Output Rvsdg Tree")),
836
839 auto aggregateAllocaSplitting =
845 auto invariantValueRedirection =
860
861 cl::list<JlmOptCommandLineOptions::OptimizationId> optimizationIds(
862 cl::values(
863 ::clEnumValN(
864 aAAndersenAgnostic,
866 "Andersen alias analysis with agnostic memory state encoding"),
867 ::clEnumValN(
868 aAAndersenRegionAware,
870 "Andersen alias analysis with region-aware memory state encoding"),
871 ::clEnumValN(
872 aggregateAllocaSplitting,
873 JlmOptCommandLineOptions::ToCommandLineArgument(aggregateAllocaSplitting),
874 "Split aggregate type alloca nodes"),
875 ::clEnumValN(
876 commonNodeElimination,
878 "Common Node Elimination"),
879 ::clEnumValN(
880 deadNodeElimination,
882 "Dead Node Elimination"),
883 ::clEnumValN(
884 functionInlining,
886 "Function Inlining"),
887 ::clEnumValN(
888 ifConversion,
890 "Convert pass-through values of gamma nodes to select operations"),
891 ::clEnumValN(
892 invariantValueRedirection,
893 JlmOptCommandLineOptions::ToCommandLineArgument(invariantValueRedirection),
894 "Invariant Value Redirection"),
895 ::clEnumValN(
896 ioBarrierElimination,
898 "Eliminate IOBarrier nodes"),
899 ::clEnumValN(
900 loadChainSeparation,
902 "Separate chains of load operations"),
903 ::clEnumValN(
904 loopStrengthReduction,
906 "Loop strength reduction"),
907 ::clEnumValN(
908 loopUnrolling,
910 "Loop Unrolling"),
911 ::clEnumValN(
912 loopUnswitching,
914 "Move conditionals outside loops"),
915 ::clEnumValN(
916 nodeHoisting,
918 "Hoist nodes out of conditionals and loops."),
919 ::clEnumValN(
920 nodePushOut,
922 "DEPRECATED - Use node hoisting instead."),
923 ::clEnumValN(
924 nodePullIn,
926 "Node Pull In"),
927 ::clEnumValN(
928 nodeReduction,
930 "Node Reduction"),
931 ::clEnumValN(
932 predicateCorrelation,
934 "Correlate predicates between theta and gamma nodes"),
935 ::clEnumValN(
936 rvsdgTreePrinter,
938 "Rvsdg Tree Printer"),
939 ::clEnumValN(
940 scalarEvolution,
942 "Scalar evolution"),
943 ::clEnumValN(
944 storeValueForwarding,
946 "Store Value Forwarding"),
947 ::clEnumValN(
948 loopUnswitching,
949 "ThetaGammaInversion",
950 "[DEPRECATED] Use --LoopUnswitching instead.")),
951 cl::desc("Perform optimization"));
952
953 cl::list<llvm::RvsdgTreePrinter::Configuration::Annotation> rvsdgTreePrinterAnnotations(
954 "annotations",
955 cl::values(::clEnumValN(
957 "DebugIds",
958 "Annotate region and node IDs")),
959 cl::values(::clEnumValN(
961 "NumAggregateAllocaNodes",
962 "Annotate number of AllocaOperation nodes with aggregate types.")),
963 cl::values(::clEnumValN(
965 "NumAllocaNodes",
966 "Annotate number of AllocaOperation nodes")),
967 cl::values(::clEnumValN(
969 "NumLoadNodes",
970 "Annotate number of LoadOperation nodes")),
971 cl::values(::clEnumValN(
973 "NumMemoryStateInputsOutputs",
974 "Annotate number of inputs/outputs with memory state type")),
975 cl::values(::clEnumValN(
977 "NumRvsdgNodes",
978 "Annotate number of RVSDG nodes")),
979 cl::values(::clEnumValN(
981 "NumStoreNodes",
982 "Annotate number of StoreOperation nodes")),
983 cl::CommaSeparated,
984 cl::desc("Comma separated list of RVSDG tree printer annotations"));
985
986 cl::ParseCommandLineOptions(argc, argv);
987
988 jlm::util::FilePath statisticsDirectoryFilePath(statisticDirectory);
989 jlm::util::FilePath inputFilePath(inputFile);
990
991 util::HashSet<util::Statistics::Id> demandedStatistics(
992 { printStatistics.begin(), printStatistics.end() });
993
994 util::StatisticsCollectorSettings statisticsCollectorSettings(
995 std::move(demandedStatistics),
996 statisticsDirectoryFilePath,
997 inputFilePath.base());
998
1000 { rvsdgTreePrinterAnnotations.begin(), rvsdgTreePrinterAnnotations.end() });
1001
1002 llvm::RvsdgTreePrinter::Configuration treePrinterConfiguration(std::move(demandedAnnotations));
1003
1004 CommandLineOptions_ = JlmOptCommandLineOptions::Create(
1005 std::move(inputFilePath),
1006 inputFormat,
1007 util::FilePath(outputFile),
1008 outputFormat,
1009 std::move(statisticsCollectorSettings),
1010 std::move(treePrinterConfiguration),
1011 std::move(optimizationIds),
1012 dumpRvsdgGraphs);
1013
1014 return *CommandLineOptions_;
1015}
1016
1018JlmOptCommandLineParser::Parse(int argc, const char * const * argv)
1019{
1020 static JlmOptCommandLineParser parser;
1021 return parser.ParseCommandLineArguments(argc, argv);
1022}
1023
1025
1027JlmHlsCommandLineParser::ParseCommandLineArguments(int argc, const char * const * argv)
1028{
1029 CommandLineOptions_.Reset();
1030
1031 using namespace ::llvm;
1032
1033 /*
1034 FIXME: The command line parser setup is currently redone
1035 for every invocation of parse_cmdline. We should be able
1036 to do it only once and then reset the parser on every
1037 invocation of parse_cmdline.
1038 */
1039
1040 cl::TopLevelSubCommand->reset();
1041
1042 cl::opt<std::string> inputFile(cl::Positional, cl::desc("<input>"));
1043
1044 cl::opt<std::string> outputFolder(
1045 "o",
1046 cl::desc("Write output to <folder>"),
1047 cl::value_desc("folder"));
1048
1049 cl::opt<std::string> hlsFunction(
1050 "hls-function",
1051 cl::Prefix,
1052 cl::desc("Function that should be accelerated"),
1053 cl::value_desc("hls-function"));
1054
1055 cl::opt<int> latency(
1056 "latency",
1057 cl::Prefix,
1058 cl::init(CommandLineOptions_.MemoryLatency_),
1059 cl::desc("Memory latency"),
1060 cl::value_desc("latency"));
1061
1062 cl::opt<bool> extractHlsFunction(
1063 "extract",
1064 cl::Prefix,
1065 cl::desc("Extracts function specified by hls-function"));
1066
1067 cl::opt<bool> dumpRvsdgGraphs(
1068 "dumpRvsdgGraphs",
1069 cl::init(false),
1070 cl::desc("Dump RVSDG as json graphs after each transformation in debug folder."));
1071
1072 cl::opt<JlmHlsCommandLineOptions::OutputFormat> format(
1073 cl::values(
1074 ::clEnumValN(
1076 "fir",
1077 "Output FIRRTL [default]"),
1078 ::clEnumValN(JlmHlsCommandLineOptions::OutputFormat::Dot, "dot", "Output DOT graph")),
1079 cl::desc("Select output format"));
1080
1081 cl::ParseCommandLineOptions(argc, argv);
1082
1083 if (outputFolder.empty())
1084 throw util::Error("jlm-hls no output directory provided, i.e, -o.\n");
1085
1086 if (extractHlsFunction && hlsFunction.empty())
1087 throw util::Error(
1088 "jlm-hls: --hls-function is not specified.\n which is required for --extract\n");
1089
1090 CommandLineOptions_.InputFile_ = util::FilePath(inputFile);
1091 CommandLineOptions_.HlsFunction_ = std::move(hlsFunction);
1092 CommandLineOptions_.OutputFiles_ = util::FilePath(outputFolder);
1093 CommandLineOptions_.ExtractHlsFunction_ = extractHlsFunction;
1094 CommandLineOptions_.OutputFormat_ = format;
1095 CommandLineOptions_.dumpRvsdgGraphs_ = dumpRvsdgGraphs;
1096
1097 if (latency < 1)
1098 {
1099 throw util::Error("The --latency must be set to a number larger than zero.");
1100 }
1101 CommandLineOptions_.MemoryLatency_ = latency;
1102
1103 return CommandLineOptions_;
1104}
1105
1107JlmHlsCommandLineParser::Parse(int argc, const char * const * argv)
1108{
1109 static JlmHlsCommandLineParser parser;
1110 return parser.ParseCommandLineArguments(argc, argv);
1111}
1112
1114
1116JhlsCommandLineParser::ParseCommandLineArguments(int argc, const char * const * argv)
1117{
1118 CommandLineOptions_.Reset();
1119
1120 using namespace ::llvm;
1121
1122 /*
1123 FIXME: The command line parser setup is currently redone
1124 for every invocation of parse_cmdline. We should be able
1125 to do it only once and then reset the parser on every
1126 invocation of parse_cmdline.
1127 */
1128
1129 cl::TopLevelSubCommand->reset();
1130
1131 cl::opt<bool> onlyPrintCommands(
1132 "###",
1133 cl::ValueDisallowed,
1134 cl::desc("Print (but do not run) the commands for this compilation."));
1135
1136 cl::list<std::string> inputFiles(cl::Positional, cl::desc("<inputs>"));
1137
1138 cl::list<std::string> includePaths(
1139 "I",
1140 cl::Prefix,
1141 cl::desc("Add directory <dir> to include search paths."),
1142 cl::value_desc("dir"));
1143
1144 cl::list<std::string> libraryPaths(
1145 "L",
1146 cl::Prefix,
1147 cl::desc("Add directory <dir> to library search paths."),
1148 cl::value_desc("dir"));
1149
1150 cl::list<std::string> libraries(
1151 "l",
1152 cl::Prefix,
1153 cl::desc("Search the library <lib> when linking."),
1154 cl::value_desc("lib"));
1155
1156 cl::opt<std::string> outputFile("o", cl::desc("Write output to <file>."), cl::value_desc("file"));
1157
1158 cl::opt<bool> generateDebugInformation(
1159 "g",
1160 cl::ValueDisallowed,
1161 cl::desc("Generate source-level debug information."));
1162
1163 cl::opt<bool> noLinking(
1164 "c",
1165 cl::ValueDisallowed,
1166 cl::desc("Only run preprocess, compile, and assemble steps."));
1167
1168 cl::opt<std::string> optimizationLevel(
1169 "O",
1170 cl::Prefix,
1171 cl::ValueOptional,
1172 cl::desc("Optimization level. [O0, O1, O2, O3]"),
1173 cl::value_desc("#"));
1174
1175 cl::list<std::string> macroDefinitions(
1176 "D",
1177 cl::Prefix,
1178 cl::desc("Add <macro> to preprocessor macros."),
1179 cl::value_desc("macro"));
1180
1181 cl::list<std::string> warnings(
1182 "W",
1183 cl::Prefix,
1184 cl::desc("Enable specified warning."),
1185 cl::value_desc("warning"));
1186
1187 cl::opt<std::string> languageStandard(
1188 "std",
1189 cl::desc("Language standard."),
1190 cl::value_desc("standard"));
1191
1192 cl::list<std::string> flags("f", cl::Prefix, cl::desc("Specify flags."), cl::value_desc("flag"));
1193
1194 cl::list<std::string> jlmHlsOptimizations(
1195 "J",
1196 cl::Prefix,
1197 cl::desc("jlm-hls optimization. Run 'jlm-hls -help' for viable options."),
1198 cl::value_desc("jlmhls"));
1199
1200 cl::opt<bool> verbose(
1201 "v",
1202 cl::ValueDisallowed,
1203 cl::desc("Show commands to run and use verbose output. (Affects only clang for now)"));
1204
1205 cl::opt<bool> rdynamic(
1206 "rdynamic",
1207 cl::ValueDisallowed,
1208 cl::desc("rdynamic option passed to clang"));
1209
1210 cl::opt<bool> suppress("w", cl::ValueDisallowed, cl::desc("Suppress all warnings"));
1211
1212 cl::opt<bool> usePthreads(
1213 "pthread",
1214 cl::ValueDisallowed,
1215 cl::desc("Support POSIX threads in generated code"));
1216
1217 cl::opt<bool> mD(
1218 "MD",
1219 cl::ValueDisallowed,
1220 cl::desc("Write a depfile containing user and system headers"));
1221
1222 cl::opt<std::string> mF(
1223 "MF",
1224 cl::desc("Write depfile output from -MD to <file>."),
1225 cl::value_desc("file"));
1226
1227 cl::opt<std::string> mT(
1228 "MT",
1229 cl::desc("Specify name of main file output in depfile."),
1230 cl::value_desc("value"));
1231
1232 cl::list<std::string> hlsFunction(
1233 "hls-function",
1234 cl::Prefix,
1235 cl::desc("function that should be accelerated"),
1236 cl::value_desc("regex"));
1237
1238 cl::opt<bool> generateFirrtl("firrtl", cl::ValueDisallowed, cl::desc("Generate firrtl"));
1239
1240 cl::opt<bool> useCirct(
1241 "circt",
1242 cl::Prefix,
1243 cl::desc("DEPRACATED - CIRCT is always used to generate FIRRTL"));
1244
1245 cl::ParseCommandLineOptions(argc, argv);
1246
1247 /* Process parsed options */
1248
1249 static std::unordered_map<std::string, JhlsCommandLineOptions::OptimizationLevel> Olvlmap(
1254
1255 static std::unordered_map<std::string, JhlsCommandLineOptions::LanguageStandard> stdmap(
1265
1266 if (!optimizationLevel.empty())
1267 {
1268 auto it = Olvlmap.find(optimizationLevel);
1269 if (it == Olvlmap.end())
1270 {
1271 std::cerr << "Unknown optimization level.\n";
1272 exit(EXIT_FAILURE);
1273 }
1274 CommandLineOptions_.OptimizationLevel_ = it->second;
1275 }
1276
1277 if (!languageStandard.empty())
1278 {
1279 auto it = stdmap.find(languageStandard);
1280 if (it == stdmap.end())
1281 {
1282 std::cerr << "Unknown language standard.\n";
1283 exit(EXIT_FAILURE);
1284 }
1285 CommandLineOptions_.LanguageStandard_ = it->second;
1286 }
1287
1288 if (inputFiles.empty())
1289 {
1290 std::cerr << "jlc: no input files.\n";
1291 exit(EXIT_FAILURE);
1292 }
1293
1294 if (inputFiles.size() > 1 && noLinking && !outputFile.empty())
1295 {
1296 std::cerr << "jlc: cannot specify -o when generating multiple output files.\n";
1297 exit(EXIT_FAILURE);
1298 }
1299
1300 if (!hlsFunction.empty())
1301 {
1302 CommandLineOptions_.Hls_ = true;
1303 CommandLineOptions_.HlsFunctionRegex_ = hlsFunction.front();
1304 }
1305
1306 if (hlsFunction.size() > 1)
1307 {
1308 std::cerr << "jlc-hls: more than one function regex specified\n";
1309 exit(EXIT_FAILURE);
1310 }
1311
1312 CommandLineOptions_.Libraries_ = libraries;
1313 CommandLineOptions_.MacroDefinitions_ = macroDefinitions;
1314 CommandLineOptions_.LibraryPaths_ = libraryPaths;
1315 CommandLineOptions_.Warnings_ = warnings;
1316 CommandLineOptions_.IncludePaths_ = includePaths;
1317 CommandLineOptions_.OnlyPrintCommands_ = onlyPrintCommands;
1318 CommandLineOptions_.GenerateDebugInformation_ = generateDebugInformation;
1319 CommandLineOptions_.Flags_ = flags;
1320 CommandLineOptions_.JlmHls_ = jlmHlsOptimizations;
1321 CommandLineOptions_.Verbose_ = verbose;
1322 CommandLineOptions_.Rdynamic_ = rdynamic;
1323 CommandLineOptions_.Suppress_ = suppress;
1324 CommandLineOptions_.UsePthreads_ = usePthreads;
1325 CommandLineOptions_.Md_ = mD;
1326 CommandLineOptions_.GenerateFirrtl_ = generateFirrtl;
1327
1328 for (auto & inputFile : inputFiles)
1329 {
1330 util::FilePath inputFilePath(inputFile);
1331 if (IsObjectFile(inputFilePath))
1332 {
1333 /* FIXME: print a warning like clang if noLinking is true */
1334 CommandLineOptions_.Compilations_.push_back(
1335 { inputFilePath, util::FilePath(""), inputFilePath, "", false, false, false, true });
1336
1337 continue;
1338 }
1339
1340 CommandLineOptions_.Compilations_.push_back(
1341 { inputFilePath,
1342 mF.empty() ? CreateDependencyFileFromFile(inputFilePath) : util::FilePath(mF),
1343 CreateObjectFileFromFile(inputFilePath),
1344 mT.empty() ? CreateObjectFileFromFile(inputFilePath).name() : mT,
1345 true,
1346 true,
1347 true,
1348 !noLinking });
1349 }
1350
1351 if (!outputFile.empty())
1352 {
1353 util::FilePath outputFilePath(outputFile);
1354 if (noLinking)
1355 {
1356 JLM_ASSERT(CommandLineOptions_.Compilations_.size() == 1);
1357 CommandLineOptions_.Compilations_[0].SetOutputFile(outputFilePath);
1358 }
1359 else
1360 {
1361 CommandLineOptions_.OutputFile_ = outputFilePath;
1362 }
1363 }
1364
1365 return CommandLineOptions_;
1366}
1367
1368bool
1370{
1371 return file.suffix() == "o";
1372}
1373
1376{
1377 return f.Dirname().Join(f.base() + ".o");
1378}
1379
1382{
1383 return f.Dirname().Join(f.base() + ".d");
1384}
1385
1387JhlsCommandLineParser::Parse(int argc, const char * const * argv)
1388{
1389 static JhlsCommandLineParser parser;
1390 return parser.ParseCommandLineArguments(argc, argv);
1391}
1392
1393}
static const jlm::tooling::JlcCommandLineOptions & ParseCommandLineArguments(const std::vector< std::string > &commandLineArguments)
virtual ~CommandLineParser() noexcept
const JhlsCommandLineOptions & ParseCommandLineArguments(int argc, const char *const *argv) override
static util::FilePath CreateDependencyFileFromFile(const util::FilePath &f)
static const JhlsCommandLineOptions & Parse(int argc, const char *const *arv)
static util::FilePath CreateObjectFileFromFile(const util::FilePath &f)
static bool IsObjectFile(const util::FilePath &file)
~JhlsCommandLineParser() noexcept override
std::vector< Compilation > Compilations_
void Reset() noexcept override
static std::string_view ToString(const OptimizationLevel &optimizationLevel)
std::vector< std::string > Warnings_
std::vector< JlmOptCommandLineOptions::OptimizationId > JlmOptOptimizations_
std::vector< std::string > LibraryPaths_
std::vector< std::string > Libraries_
std::vector< std::string > MacroDefinitions_
std::vector< std::string > Flags_
std::vector< std::string > IncludePaths_
static const JlmHlsCommandLineOptions & Parse(int argc, const char *const *argv)
const JlmHlsCommandLineOptions & ParseCommandLineArguments(int argc, const char *const *argv) override
~JlmHlsCommandLineParser() noexcept override
static const util::BijectiveMap< util::Statistics::Id, std::string_view > & GetStatisticsIdCommandLineArguments()
static OptimizationId FromCommandLineArgumentToOptimizationId(std::string_view commandLineArgument)
static std::string_view ToCommandLineArgument(OptimizationId optimizationId)
static util::Statistics::Id FromCommandLineArgumentToStatisticsId(std::string_view commandLineArgument)
static const std::unordered_map< OutputFormat, std::string_view > & GetOutputFormatCommandLineArguments()
static std::unique_ptr< JlmOptCommandLineOptions > Create(util::FilePath inputFile, InputFormat inputFormat, util::FilePath outputFile, OutputFormat outputFormat, util::StatisticsCollectorSettings statisticsCollectorSettings, llvm::RvsdgTreePrinter::Configuration rvsdgTreePrinterConfiguration, std::vector< OptimizationId > optimizations, bool dumpRvsdgGraphs)
static const util::BijectiveMap< OptimizationId, std::string_view > & GetOptimizationIdCommandLineMap()
std::vector< OptimizationId > OptimizationIds_
util::StatisticsCollectorSettings StatisticsCollectorSettings_
static const JlmOptCommandLineOptions & Parse(int argc, const char *const *argv)
const JlmOptCommandLineOptions & ParseCommandLineArguments(int argc, const char *const *argv) override
~JlmOptCommandLineParser() noexcept override
std::size_t Size() const noexcept
std::string name() const noexcept
Returns the name of the file, excluding the path.
Definition file.hpp:81
static FilePath TempDirectoryPath()
Definition file.hpp:317
FilePath Join(const std::string &other) const
Definition file.hpp:193
std::string base() const noexcept
Returns the base name of the file without the path.
Definition file.hpp:61
const std::string & to_str() const noexcept
Definition file.hpp:275
FilePath Dirname() const noexcept
Returns the path to the file or directory's parent directory. Emulates the behavior of the GNU coreut...
Definition file.hpp:148
std::string suffix() const noexcept
Returns the suffix (extension) of the file.
Definition file.hpp:116
#define JLM_ASSERT(x)
Definition common.hpp:16
::llvm::cl::OptionEnumValue CreateOutputFormatOption(JlmOptCommandLineOptions::OutputFormat outputFormat, std::string_view description)
::llvm::cl::OptionEnumValue CreateStatisticsOption(util::Statistics::Id statisticsId, std::string_view description)
static std::string strfmt(Args... args)
Definition strfmt.hpp:35