Jlm
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 
16 namespace jlm::tooling
17 {
18 
20 
21 std::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 
35 std::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 
54 void
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();
76  JlmOptOptimizations_.clear();
77 
78  Compilations_.clear();
79 }
80 
81 void
83 {
88  OptimizationIds_.clear();
89 }
90 
93 {
95  { OptimizationId::AAAndersenAgnostic, "AAAndersenAgnostic" },
96  { OptimizationId::AAAndersenRegionAware, "AAAndersenRegionAware" },
97  { OptimizationId::CommonNodeElimination, "CommonNodeElimination" },
98  { OptimizationId::DeadNodeElimination, "DeadNodeElimination" },
99  { OptimizationId::FunctionInlining, "FunctionInlining" },
100  { OptimizationId::IfConversion, "IfConversion" },
101  { OptimizationId::InvariantValueRedirection, "InvariantValueRedirection" },
102  { OptimizationId::LoadChainSeparation, "LoadChainSeparation" },
103  { OptimizationId::LoopUnrolling, "LoopUnrolling" },
104  { OptimizationId::LoopUnswitching, "LoopUnswitching" },
105  { OptimizationId::NodePullIn, "NodePullIn" },
106  { OptimizationId::NodePushOut, "NodePushOut" },
107  { OptimizationId::NodeReduction, "NodeReduction" },
108  { OptimizationId::PredicateCorrelation, "PredicateCorrelation" },
109  { OptimizationId::RvsdgTreePrinter, "RvsdgTreePrinter" },
110  { OptimizationId::ScalarEvolution, "ScalarEvolution" }
111  };
112 
113  auto firstIndex = static_cast<size_t>(OptimizationId::FirstEnumValue);
114  auto lastIndex = static_cast<size_t>(OptimizationId::LastEnumValue);
115  JLM_ASSERT(map.Size() == lastIndex - firstIndex - 1);
116  return map;
117 }
118 
121  std::string_view commandLineArgument)
122 {
123  // TODO: Deprecated, to be removed
124  if (commandLineArgument == "ThetaGammaInversion")
126 
127  const auto & map = GetOptimizationIdCommandLineMap();
128 
129  if (map.HasValue(commandLineArgument))
130  return map.LookupValue(commandLineArgument);
131 
132  throw util::Error(util::strfmt("Unknown command line argument: ", commandLineArgument));
133 }
134 
135 std::string_view
137 {
138  const auto & map = GetOptimizationIdCommandLineMap();
139 
140  if (map.HasKey(optimizationId))
141  return map.LookupKey(optimizationId);
142 
143  throw util::Error("Unknown optimization identifier");
144 }
145 
148  std::string_view commandLineArgument)
149 {
150  try
151  {
152  return GetStatisticsIdCommandLineArguments().LookupValue(commandLineArgument);
153  }
154  catch (...)
155  {
156  throw util::Error(util::strfmt("Unknown command line argument: ", commandLineArgument));
157  }
158 }
159 
160 std::string_view
162 {
163  try
164  {
165  return GetStatisticsIdCommandLineArguments().LookupKey(statisticsId);
166  }
167  catch (...)
168  {
169  throw util::Error("Unknown statistics identifier");
170  }
171 }
172 
173 std::string_view
175 {
176  static std::unordered_map<InputFormat, std::string_view> map(
177  { { InputFormat::Llvm, "llvm" }, { InputFormat::Mlir, "mlir" } });
178 
179  if (map.find(inputFormat) != map.end())
180  return map[inputFormat];
181 
182  throw util::Error("Unknown input format");
183 }
184 
185 std::string_view
187 {
188  auto & mapping = GetOutputFormatCommandLineArguments();
189  return mapping.at(outputFormat);
190 }
191 
194 {
196  { util::Statistics::Id::Aggregation, "print-aggregation-time" },
197  { util::Statistics::Id::AgnosticModRefSummarizer, "print-agnostic-mod-ref-summarization" },
198  { util::Statistics::Id::AliasAnalysisPrecisionEvaluation, "print-aa-precision-evaluation" },
199  { util::Statistics::Id::AndersenAnalysis, "print-andersen-analysis" },
200  { util::Statistics::Id::Annotation, "print-annotation-time" },
201  { util::Statistics::Id::CommonNodeElimination, "print-cne-stat" },
202  { util::Statistics::Id::ControlFlowRecovery, "print-cfr-time" },
203  { util::Statistics::Id::DataNodeToDelta, "printDataNodeToDelta" },
204  { util::Statistics::Id::DeadNodeElimination, "print-dne-stat" },
205  { util::Statistics::Id::FunctionInlining, "print-iln-stat" },
206  { util::Statistics::Id::IfConversion, "print-if-conversion" },
207  { util::Statistics::Id::InvariantValueRedirection, "printInvariantValueRedirection" },
208  { util::Statistics::Id::JlmToRvsdgConversion, "print-jlm-rvsdg-conversion" },
209  { util::Statistics::Id::LoopUnrolling, "print-unroll-stat" },
210  { util::Statistics::Id::LoopUnswitching, "print-ivt-stat" },
211  { util::Statistics::Id::MemoryStateEncoder, "print-basicencoder-encoding" },
212  { util::Statistics::Id::PullNodes, "print-pull-stat" },
213  { util::Statistics::Id::PushNodes, "print-push-stat" },
214  { util::Statistics::Id::ReduceNodes, "print-reduction-stat" },
215  { util::Statistics::Id::RegionAwareModRefSummarizer, "print-mod-ref-summarization" },
216  { util::Statistics::Id::RvsdgConstruction, "print-rvsdg-construction" },
217  { util::Statistics::Id::RvsdgDestruction, "print-rvsdg-destruction" },
218  { util::Statistics::Id::RvsdgOptimization, "print-rvsdg-optimization" },
219  { util::Statistics::Id::RvsdgTreePrinter, "print-rvsdg-tree" },
220  { util::Statistics::Id::ScalarEvolution, "print-scalar-evolution" },
221  };
222 
223  auto firstIndex = static_cast<size_t>(util::Statistics::Id::FirstEnumValue);
224  auto lastIndex = static_cast<size_t>(util::Statistics::Id::LastEnumValue);
225  JLM_ASSERT(mapping.Size() == lastIndex - firstIndex - 1);
226  return mapping;
227 }
228 
229 const std::unordered_map<JlmOptCommandLineOptions::OutputFormat, std::string_view> &
231 {
232  static std::unordered_map<OutputFormat, std::string_view> mapping = {
233  { OutputFormat::Ascii, "ascii" }, { OutputFormat::Dot, "dot" },
234  { OutputFormat::Llvm, "llvm" }, { OutputFormat::Mlir, "mlir" },
235  { OutputFormat::Tree, "tree" }, { OutputFormat::Xml, "xml" }
236  };
237 
238  auto firstIndex = static_cast<size_t>(OutputFormat::FirstEnumValue);
239  auto lastIndex = static_cast<size_t>(OutputFormat::LastEnumValue);
240  JLM_ASSERT(mapping.size() == lastIndex - firstIndex - 1);
241  return mapping;
242 }
243 
244 void
246 {
250  HlsFunction_ = "";
251  ExtractHlsFunction_ = false;
252  MemoryLatency_ = 10;
253 }
254 
255 void
257 {
258  *this = JhlsCommandLineOptions();
259 }
260 
261 static ::llvm::cl::OptionEnumValue
262 CreateStatisticsOption(util::Statistics::Id statisticsId, std::string_view description)
263 {
264  return ::clEnumValN(
265  statisticsId,
267  description);
268 }
269 
270 static ::llvm::cl::OptionEnumValue
273  std::string_view description)
274 {
275  return ::clEnumValN(
276  outputFormat,
278  description);
279 }
280 
281 CommandLineParser::~CommandLineParser() noexcept = default;
282 
283 CommandLineParser::Exception::~Exception() noexcept = default;
284 
285 JlcCommandLineParser::~JlcCommandLineParser() noexcept = default;
286 
287 const JlcCommandLineOptions &
288 JlcCommandLineParser::ParseCommandLineArguments(int argc, const char * const * argv)
289 {
290  auto checkAndConvertJlmOptOptimizations =
291  [](const ::llvm::cl::list<std::string> & optimizations,
293  {
294  if (optimizations.empty() && optimizationLevel == JlcCommandLineOptions::OptimizationLevel::O3)
295  {
296  return std::vector({
321  });
322  }
323 
324  std::vector<JlmOptCommandLineOptions::OptimizationId> optimizationIds;
325  for (auto & optimization : optimizations)
326  {
328  try
329  {
330  optimizationId =
332  }
333  catch (util::Error &)
334  {
335  throw CommandLineParser::Exception("Unknown jlm-opt optimization: " + optimization);
336  }
337 
338  optimizationIds.emplace_back(optimizationId);
339  }
340 
341  return optimizationIds;
342  };
343 
344  CommandLineOptions_.Reset();
345 
346  using namespace ::llvm;
347 
348  /*
349  FIXME: The command line parser setup is currently redone
350  for every invocation of parse_cmdline. We should be able
351  to do it only once and then reset the parser on every
352  invocation of parse_cmdline.
353  */
354 
355  cl::TopLevelSubCommand->reset();
356 
357  cl::opt<bool> onlyPrintCommands(
358  "###",
359  cl::ValueDisallowed,
360  cl::desc("Print (but do not run) the commands for this compilation."));
361 
362  cl::list<std::string> inputFiles(cl::Positional, cl::desc("<inputs>"));
363 
364  cl::list<std::string> includePaths(
365  "I",
366  cl::Prefix,
367  cl::desc("Add directory <dir> to include search paths."),
368  cl::value_desc("dir"));
369 
370  cl::list<std::string> libraryPaths(
371  "L",
372  cl::Prefix,
373  cl::desc("Add directory <dir> to library search paths."),
374  cl::value_desc("dir"));
375 
376  cl::list<std::string> libraries(
377  "l",
378  cl::Prefix,
379  cl::desc("Search the library <lib> when linking."),
380  cl::value_desc("lib"));
381 
382  cl::opt<std::string> outputFile("o", cl::desc("Write output to <file>."), cl::value_desc("file"));
383 
384  cl::opt<bool> generateDebugInformation(
385  "g",
386  cl::ValueDisallowed,
387  cl::desc("Generate source-level debug information."));
388 
389  cl::opt<bool> noLinking(
390  "c",
391  cl::ValueDisallowed,
392  cl::desc("Only run preprocess, compile, and assemble steps."));
393 
394  cl::opt<std::string> optimizationLevel(
395  "O",
396  cl::Prefix,
397  cl::ValueOptional,
398  cl::desc("Optimization level. [O0, O1, O2, O3]"),
399  cl::value_desc("#"));
400 
401  cl::list<std::string> macroDefinitions(
402  "D",
403  cl::Prefix,
404  cl::desc("Add <macro> to preprocessor macros."),
405  cl::value_desc("macro"));
406 
407  cl::list<std::string> warnings(
408  "W",
409  cl::Prefix,
410  cl::desc("Enable specified warning."),
411  cl::value_desc("warning"));
412 
413  cl::opt<std::string> languageStandard(
414  "std",
415  cl::desc("Language standard."),
416  cl::value_desc("standard"));
417 
418  cl::list<std::string> flags("f", cl::Prefix, cl::desc("Specify flags."), cl::value_desc("flag"));
419 
420  cl::list<std::string> jlmOptimizations(
421  "J",
422  cl::Prefix,
423  cl::desc("jlm-opt optimization. Run 'jlm-opt -help' for viable options."),
424  cl::value_desc("jlmopt"));
425 
426  cl::opt<bool> verbose(
427  "v",
428  cl::ValueDisallowed,
429  cl::desc("Show commands to run and use verbose output. (Affects only clang for now)"));
430 
431  cl::opt<bool> rDynamic(
432  "rdynamic",
433  cl::ValueDisallowed,
434  cl::desc("rDynamic option passed to clang"));
435 
436  cl::opt<bool> suppress("w", cl::ValueDisallowed, cl::desc("Suppress all warnings"));
437 
438  cl::opt<bool> usePthreads(
439  "pthread",
440  cl::ValueDisallowed,
441  cl::desc("Support POSIX threads in generated code"));
442 
443  cl::opt<bool> mD(
444  "MD",
445  cl::ValueDisallowed,
446  cl::desc("Write a depfile containing user and system headers"));
447 
448  cl::opt<std::string> mF(
449  "MF",
450  cl::desc("Write depfile output from -mD to <file>."),
451  cl::value_desc("file"));
452 
453  cl::opt<std::string> mT(
454  "MT",
455  cl::desc("Specify name of main file output in depfile."),
456  cl::value_desc("value"));
457 
458  cl::list<util::Statistics::Id> jlmOptPassStatistics(
459  "JlmOptPassStatistics",
460  cl::values(
463  "Collect control flow graph aggregation pass statistics."),
466  "Collect agnostic mod/ref summarizer pass statistics."),
469  "Collect Andersen alias analysis pass statistics."),
472  "Collect aggregation tree annotation pass statistics."),
475  "Collect memory state encoding pass statistics."),
478  "Collect common node elimination pass statistics."),
481  "Collect control flow recovery pass statistics."),
484  "Collect data node to delta node conversion pass statistics."),
487  "Collect dead node elimination pass statistics."),
490  "Collect function inlining pass statistics."),
493  "Collect invariant value redirection pass statistics."),
496  "Collect Jlm to RVSDG conversion pass statistics."),
499  "Collect loop unrolling pass statistics."),
502  "Collect loop unswitching pass statistics."),
505  "Collect node pull pass statistics."),
508  "Collect node push pass statistics."),
511  "Collect node reduction pass statistics."),
514  "Collect region-aware mod/ref summarizer pass statistics."),
517  "Collect RVSDG construction pass statistics."),
520  "Collect RVSDG destruction pass statistics."),
523  "Collect RVSDG optimization pass statistics."),
526  "Collect RVSDG tree printer pass statistics."),
529  "Collect scalar evolution analysis pass statistics.")),
530  cl::desc("Collect jlm-opt pass statistics"));
531 
532  cl::ParseCommandLineOptions(argc, argv);
533 
534  /* Process parsed options */
535 
536  static std::unordered_map<std::string, JlcCommandLineOptions::OptimizationLevel>
537  optimizationLevelMap({ { "0", JlcCommandLineOptions::OptimizationLevel::O0 },
541 
542  static std::unordered_map<std::string, JlcCommandLineOptions::LanguageStandard>
543  languageStandardMap({ { "gnu89", JlcCommandLineOptions::LanguageStandard::Gnu89 },
553 
554  if (!optimizationLevel.empty())
555  {
556  auto iterator = optimizationLevelMap.find(optimizationLevel);
557  if (iterator == optimizationLevelMap.end())
558  {
559  std::cerr << "Unknown optimization level.\n";
560  exit(EXIT_FAILURE);
561  }
562  CommandLineOptions_.OptimizationLevel_ = iterator->second;
563  }
564 
565  if (!languageStandard.empty())
566  {
567  auto iterator = languageStandardMap.find(languageStandard);
568  if (iterator == languageStandardMap.end())
569  {
570  std::cerr << "Unknown language standard.\n";
571  exit(EXIT_FAILURE);
572  }
573  CommandLineOptions_.LanguageStandard_ = iterator->second;
574  }
575 
576  if (inputFiles.empty())
577  {
578  std::cerr << "jlc: no input files.\n";
579  exit(EXIT_FAILURE);
580  }
581 
582  if (inputFiles.size() > 1 && noLinking && !outputFile.empty())
583  {
584  std::cerr << "jlc: cannot specify -o when generating multiple output files.\n";
585  exit(EXIT_FAILURE);
586  }
587 
588  auto jlmOptOptimizations =
589  checkAndConvertJlmOptOptimizations(jlmOptimizations, CommandLineOptions_.OptimizationLevel_);
590 
591  CommandLineOptions_.Libraries_ = libraries;
592  CommandLineOptions_.MacroDefinitions_ = macroDefinitions;
593  CommandLineOptions_.LibraryPaths_ = libraryPaths;
594  CommandLineOptions_.Warnings_ = warnings;
595  CommandLineOptions_.IncludePaths_ = includePaths;
596  CommandLineOptions_.OnlyPrintCommands_ = onlyPrintCommands;
597  CommandLineOptions_.GenerateDebugInformation_ = generateDebugInformation;
598  CommandLineOptions_.Flags_ = flags;
599  CommandLineOptions_.JlmOptOptimizations_ = jlmOptOptimizations;
600  CommandLineOptions_.JlmOptPassStatistics_ = util::HashSet<util::Statistics::Id>(
601  { jlmOptPassStatistics.begin(), jlmOptPassStatistics.end() });
602  CommandLineOptions_.Verbose_ = verbose;
603  CommandLineOptions_.Rdynamic_ = rDynamic;
604  CommandLineOptions_.Suppress_ = suppress;
605  CommandLineOptions_.UsePthreads_ = usePthreads;
606  CommandLineOptions_.Md_ = mD;
607 
608  for (auto & inputFile : inputFiles)
609  {
610  util::FilePath inputFilePath(inputFile);
611  if (IsObjectFile(inputFilePath))
612  {
613  /* FIXME: print a warning like clang if noLinking is true */
614  CommandLineOptions_.Compilations_.push_back(
615  { inputFilePath, util::FilePath(""), inputFilePath, "", false, false, false, true });
616 
617  continue;
618  }
619 
620  CommandLineOptions_.Compilations_.push_back(
621  { inputFilePath,
622  mF.empty() ? ToDependencyFile(inputFilePath) : util::FilePath(mF),
623  ToObjectFile(inputFilePath),
624  mT.empty() ? ToObjectFile(inputFilePath).name() : mT,
625  true,
626  true,
627  true,
628  !noLinking });
629  }
630 
631  if (!outputFile.empty())
632  {
633  util::FilePath outputFilePath(outputFile);
634  if (noLinking)
635  {
636  JLM_ASSERT(CommandLineOptions_.Compilations_.size() == 1);
637  CommandLineOptions_.Compilations_[0].SetOutputFile(outputFilePath);
638  }
639  else
640  {
641  CommandLineOptions_.OutputFile_ = outputFilePath;
642  }
643  }
644 
645  return CommandLineOptions_;
646 }
647 
649 
651 JlmOptCommandLineParser::ParseCommandLineArguments(int argc, const char * const * argv)
652 {
653  using namespace ::llvm;
654 
655  /*
656  FIXME: The command line parser setup is currently redone
657  for every invocation of parse_cmdline. We should be able
658  to do it only once and then reset the parser on every
659  invocation of parse_cmdline.
660  */
661 
662  cl::TopLevelSubCommand->reset();
663 
664  cl::opt<std::string> inputFile(cl::Positional, cl::desc("<input>"));
665 
666  cl::opt<std::string> outputFile(
667  "o",
668  cl::init(""),
669  cl::desc("Write output to <file>"),
670  cl::value_desc("file"));
671 
672  const auto statisticsDirectoryDefault = util::FilePath::TempDirectoryPath().Join("jlm");
673  const auto statisticDirectoryDescription =
674  "Write statistics and debug output to files in <dir>. Default is "
675  + statisticsDirectoryDefault.to_str() + ".";
676  cl::opt<std::string> statisticDirectory(
677  "s",
678  cl::init(statisticsDirectoryDefault.to_str()),
679  cl::desc(statisticDirectoryDescription),
680  cl::value_desc("dir"));
681 
682  cl::opt<bool> dumpRvsdgDotGraphs(
683  "dumpRvsdgDotGraphs",
684  cl::init(false),
685  cl::desc("Dump RVSDG as dot graphs after each transformation in debug folder."));
686 
687  cl::list<util::Statistics::Id> printStatistics(
688  cl::values(
691  "Write aggregation statistics to file."),
694  "Collect agnostic mod/ref summarization pass statistics."),
697  "Evaluate alias analysis precision and store to file"),
700  "Collect Andersen alias analysis pass statistics."),
703  "Write annotation statistics to file."),
706  "Write encoding statistics of basic encoder to file."),
709  "Write common node elimination statistics to file."),
712  "Write control flow recovery statistics to file."),
715  "Write data node to delta node conversion statistics to file."),
718  "Write dead node elimination statistics to file."),
721  "Write function inlining statistics to file."),
724  "Collect if-conversion transformation statistics"),
727  "Write invariant value redirection statistics to file."),
730  "Write Jlm to RVSDG conversion statistics to file."),
733  "Write loop unrolling statistics to file."),
736  "Collect loop unswitching pass statistics."),
739  "Write node pull statistics to file."),
742  "Write node push statistics to file."),
745  "Write node reduction statistics to file."),
748  "Collect region-aware mod/ref summarization statistics."),
751  "Write RVSDG construction statistics to file."),
754  "Write RVSDG destruction statistics to file."),
757  "Write RVSDG optimization statistics to file."),
760  "Write RVSDG tree printer pass statistics."),
763  "Write scalar evolution statistics to file.")),
764  cl::desc("Write statistics"));
765 
766 #ifdef ENABLE_MLIR
767  auto llvmInputFormat = JlmOptCommandLineOptions::InputFormat::Llvm;
768  auto mlirInputFormat = JlmOptCommandLineOptions::InputFormat::Mlir;
769 
770  cl::opt<JlmOptCommandLineOptions::InputFormat> inputFormat(
771  "input-format",
772  cl::desc("Select input format:"),
773  cl::values(
774  ::clEnumValN(
775  llvmInputFormat,
777  "Input LLVM IR [default]"),
778  ::clEnumValN(
779  mlirInputFormat,
781  "Input MLIR")),
782  cl::init(llvmInputFormat));
783 #else
785 #endif
786 
787  cl::opt<JlmOptCommandLineOptions::OutputFormat> outputFormat(
788  "output-format",
789  cl::desc("Select output format:"),
790  cl::values(
795  "Output LLVM IR [default]"),
796 #ifdef ENABLE_MLIR
798 #endif
801  "Output Rvsdg Tree"),
804 
811  auto invariantValueRedirection =
822 
823  cl::list<JlmOptCommandLineOptions::OptimizationId> optimizationIds(
824  cl::values(
825  ::clEnumValN(
826  aAAndersenAgnostic,
828  "Andersen alias analysis with agnostic memory state encoding"),
829  ::clEnumValN(
830  aAAndersenRegionAware,
832  "Andersen alias analysis with region-aware memory state encoding"),
833  ::clEnumValN(
834  commonNodeElimination,
836  "Common Node Elimination"),
837  ::clEnumValN(
838  deadNodeElimination,
840  "Dead Node Elimination"),
841  ::clEnumValN(
842  functionInlining,
844  "Function Inlining"),
845  ::clEnumValN(
846  ifConversion,
848  "Convert pass-through values of gamma nodes to select operations"),
849  ::clEnumValN(
850  invariantValueRedirection,
851  JlmOptCommandLineOptions::ToCommandLineArgument(invariantValueRedirection),
852  "Invariant Value Redirection"),
853  ::clEnumValN(
854  loadChainSeparation,
856  "Separate chains of load operations"),
857  ::clEnumValN(
858  loopUnrolling,
860  "Loop Unrolling"),
861  ::clEnumValN(
862  loopUnswitching,
864  "Move conditionals outside loops"),
865  ::clEnumValN(
866  nodePushOut,
868  "Node Push Out"),
869  ::clEnumValN(
870  nodePullIn,
872  "Node Pull In"),
873  ::clEnumValN(
874  nodeReduction,
876  "Node Reduction"),
877  ::clEnumValN(
878  predicateCorrelation,
880  "Correlate predicates between theta and gamma nodes"),
881  ::clEnumValN(
882  rvsdgTreePrinter,
884  "Rvsdg Tree Printer"),
885  ::clEnumValN(
886  scalarEvolution,
888  "Scalar evolution"),
889  ::clEnumValN(
890  loopUnswitching,
891  "ThetaGammaInversion",
892  "[DEPRECATED] Use --LoopUnswitching instead.")),
893  cl::desc("Perform optimization"));
894 
895  cl::list<llvm::RvsdgTreePrinter::Configuration::Annotation> rvsdgTreePrinterAnnotations(
896  "annotations",
897  cl::values(::clEnumValN(
899  "NumAllocaNodes",
900  "Annotate number of AllocaOperation nodes")),
901  cl::values(::clEnumValN(
903  "NumLoadNodes",
904  "Annotate number of LoadOperation nodes")),
905  cl::values(::clEnumValN(
907  "NumMemoryStateInputsOutputs",
908  "Annotate number of inputs/outputs with memory state type")),
909  cl::values(::clEnumValN(
911  "NumRvsdgNodes",
912  "Annotate number of RVSDG nodes")),
913  cl::values(::clEnumValN(
915  "NumStoreNodes",
916  "Annotate number of StoreOperation nodes")),
917  cl::CommaSeparated,
918  cl::desc("Comma separated list of RVSDG tree printer annotations"));
919 
920  cl::ParseCommandLineOptions(argc, argv);
921 
922  jlm::util::FilePath statisticsDirectoryFilePath(statisticDirectory);
923  jlm::util::FilePath inputFilePath(inputFile);
924 
925  util::HashSet<util::Statistics::Id> demandedStatistics(
926  { printStatistics.begin(), printStatistics.end() });
927 
928  util::StatisticsCollectorSettings statisticsCollectorSettings(
929  std::move(demandedStatistics),
930  statisticsDirectoryFilePath,
931  inputFilePath.base());
932 
934  { rvsdgTreePrinterAnnotations.begin(), rvsdgTreePrinterAnnotations.end() });
935 
936  llvm::RvsdgTreePrinter::Configuration treePrinterConfiguration(std::move(demandedAnnotations));
937 
938  CommandLineOptions_ = JlmOptCommandLineOptions::Create(
939  std::move(inputFilePath),
940  inputFormat,
941  util::FilePath(outputFile),
942  outputFormat,
943  std::move(statisticsCollectorSettings),
944  std::move(treePrinterConfiguration),
945  std::move(optimizationIds),
946  dumpRvsdgDotGraphs);
947 
948  return *CommandLineOptions_;
949 }
950 
952 JlmOptCommandLineParser::Parse(int argc, const char * const * argv)
953 {
954  static JlmOptCommandLineParser parser;
955  return parser.ParseCommandLineArguments(argc, argv);
956 }
957 
959 
961 JlmHlsCommandLineParser::ParseCommandLineArguments(int argc, const char * const * argv)
962 {
963  CommandLineOptions_.Reset();
964 
965  using namespace ::llvm;
966 
967  /*
968  FIXME: The command line parser setup is currently redone
969  for every invocation of parse_cmdline. We should be able
970  to do it only once and then reset the parser on every
971  invocation of parse_cmdline.
972  */
973 
974  cl::TopLevelSubCommand->reset();
975 
976  cl::opt<std::string> inputFile(cl::Positional, cl::desc("<input>"));
977 
978  cl::opt<std::string> outputFolder(
979  "o",
980  cl::desc("Write output to <folder>"),
981  cl::value_desc("folder"));
982 
983  cl::opt<std::string> hlsFunction(
984  "hls-function",
985  cl::Prefix,
986  cl::desc("Function that should be accelerated"),
987  cl::value_desc("hls-function"));
988 
989  cl::opt<int> latency(
990  "latency",
991  cl::Prefix,
992  cl::init(CommandLineOptions_.MemoryLatency_),
993  cl::desc("Memory latency"),
994  cl::value_desc("latency"));
995 
996  cl::opt<bool> extractHlsFunction(
997  "extract",
998  cl::Prefix,
999  cl::desc("Extracts function specified by hls-function"));
1000 
1001  cl::opt<bool> dumpRvsdgDotGraphs(
1002  "dumpRvsdgDotGraphs",
1003  cl::init(false),
1004  cl::desc("Dump RVSDG as dot graphs after each transformation in debug folder."));
1005 
1006  cl::opt<JlmHlsCommandLineOptions::OutputFormat> format(
1007  cl::values(
1008  ::clEnumValN(
1010  "fir",
1011  "Output FIRRTL [default]"),
1012  ::clEnumValN(JlmHlsCommandLineOptions::OutputFormat::Dot, "dot", "Output DOT graph")),
1013  cl::desc("Select output format"));
1014 
1015  cl::ParseCommandLineOptions(argc, argv);
1016 
1017  if (outputFolder.empty())
1018  throw util::Error("jlm-hls no output directory provided, i.e, -o.\n");
1019 
1020  if (extractHlsFunction && hlsFunction.empty())
1021  throw util::Error(
1022  "jlm-hls: --hls-function is not specified.\n which is required for --extract\n");
1023 
1024  CommandLineOptions_.InputFile_ = util::FilePath(inputFile);
1025  CommandLineOptions_.HlsFunction_ = std::move(hlsFunction);
1026  CommandLineOptions_.OutputFiles_ = util::FilePath(outputFolder);
1027  CommandLineOptions_.ExtractHlsFunction_ = extractHlsFunction;
1028  CommandLineOptions_.OutputFormat_ = format;
1029  CommandLineOptions_.dumpRvsdgDotGraphs_ = dumpRvsdgDotGraphs;
1030 
1031  if (latency < 1)
1032  {
1033  throw util::Error("The --latency must be set to a number larger than zero.");
1034  }
1035  CommandLineOptions_.MemoryLatency_ = latency;
1036 
1037  return CommandLineOptions_;
1038 }
1039 
1041 JlmHlsCommandLineParser::Parse(int argc, const char * const * argv)
1042 {
1043  static JlmHlsCommandLineParser parser;
1044  return parser.ParseCommandLineArguments(argc, argv);
1045 }
1046 
1048 
1049 const JhlsCommandLineOptions &
1050 JhlsCommandLineParser::ParseCommandLineArguments(int argc, const char * const * argv)
1051 {
1052  CommandLineOptions_.Reset();
1053 
1054  using namespace ::llvm;
1055 
1056  /*
1057  FIXME: The command line parser setup is currently redone
1058  for every invocation of parse_cmdline. We should be able
1059  to do it only once and then reset the parser on every
1060  invocation of parse_cmdline.
1061  */
1062 
1063  cl::TopLevelSubCommand->reset();
1064 
1065  cl::opt<bool> onlyPrintCommands(
1066  "###",
1067  cl::ValueDisallowed,
1068  cl::desc("Print (but do not run) the commands for this compilation."));
1069 
1070  cl::list<std::string> inputFiles(cl::Positional, cl::desc("<inputs>"));
1071 
1072  cl::list<std::string> includePaths(
1073  "I",
1074  cl::Prefix,
1075  cl::desc("Add directory <dir> to include search paths."),
1076  cl::value_desc("dir"));
1077 
1078  cl::list<std::string> libraryPaths(
1079  "L",
1080  cl::Prefix,
1081  cl::desc("Add directory <dir> to library search paths."),
1082  cl::value_desc("dir"));
1083 
1084  cl::list<std::string> libraries(
1085  "l",
1086  cl::Prefix,
1087  cl::desc("Search the library <lib> when linking."),
1088  cl::value_desc("lib"));
1089 
1090  cl::opt<std::string> outputFile("o", cl::desc("Write output to <file>."), cl::value_desc("file"));
1091 
1092  cl::opt<bool> generateDebugInformation(
1093  "g",
1094  cl::ValueDisallowed,
1095  cl::desc("Generate source-level debug information."));
1096 
1097  cl::opt<bool> noLinking(
1098  "c",
1099  cl::ValueDisallowed,
1100  cl::desc("Only run preprocess, compile, and assemble steps."));
1101 
1102  cl::opt<std::string> optimizationLevel(
1103  "O",
1104  cl::Prefix,
1105  cl::ValueOptional,
1106  cl::desc("Optimization level. [O0, O1, O2, O3]"),
1107  cl::value_desc("#"));
1108 
1109  cl::list<std::string> macroDefinitions(
1110  "D",
1111  cl::Prefix,
1112  cl::desc("Add <macro> to preprocessor macros."),
1113  cl::value_desc("macro"));
1114 
1115  cl::list<std::string> warnings(
1116  "W",
1117  cl::Prefix,
1118  cl::desc("Enable specified warning."),
1119  cl::value_desc("warning"));
1120 
1121  cl::opt<std::string> languageStandard(
1122  "std",
1123  cl::desc("Language standard."),
1124  cl::value_desc("standard"));
1125 
1126  cl::list<std::string> flags("f", cl::Prefix, cl::desc("Specify flags."), cl::value_desc("flag"));
1127 
1128  cl::list<std::string> jlmHlsOptimizations(
1129  "J",
1130  cl::Prefix,
1131  cl::desc("jlm-hls optimization. Run 'jlm-hls -help' for viable options."),
1132  cl::value_desc("jlmhls"));
1133 
1134  cl::opt<bool> verbose(
1135  "v",
1136  cl::ValueDisallowed,
1137  cl::desc("Show commands to run and use verbose output. (Affects only clang for now)"));
1138 
1139  cl::opt<bool> rdynamic(
1140  "rdynamic",
1141  cl::ValueDisallowed,
1142  cl::desc("rdynamic option passed to clang"));
1143 
1144  cl::opt<bool> suppress("w", cl::ValueDisallowed, cl::desc("Suppress all warnings"));
1145 
1146  cl::opt<bool> usePthreads(
1147  "pthread",
1148  cl::ValueDisallowed,
1149  cl::desc("Support POSIX threads in generated code"));
1150 
1151  cl::opt<bool> mD(
1152  "MD",
1153  cl::ValueDisallowed,
1154  cl::desc("Write a depfile containing user and system headers"));
1155 
1156  cl::opt<std::string> mF(
1157  "MF",
1158  cl::desc("Write depfile output from -MD to <file>."),
1159  cl::value_desc("file"));
1160 
1161  cl::opt<std::string> mT(
1162  "MT",
1163  cl::desc("Specify name of main file output in depfile."),
1164  cl::value_desc("value"));
1165 
1166  cl::list<std::string> hlsFunction(
1167  "hls-function",
1168  cl::Prefix,
1169  cl::desc("function that should be accelerated"),
1170  cl::value_desc("regex"));
1171 
1172  cl::opt<bool> generateFirrtl("firrtl", cl::ValueDisallowed, cl::desc("Generate firrtl"));
1173 
1174  cl::opt<bool> useCirct(
1175  "circt",
1176  cl::Prefix,
1177  cl::desc("DEPRACATED - CIRCT is always used to generate FIRRTL"));
1178 
1179  cl::ParseCommandLineOptions(argc, argv);
1180 
1181  /* Process parsed options */
1182 
1183  static std::unordered_map<std::string, JhlsCommandLineOptions::OptimizationLevel> Olvlmap(
1188 
1189  static std::unordered_map<std::string, JhlsCommandLineOptions::LanguageStandard> stdmap(
1199 
1200  if (!optimizationLevel.empty())
1201  {
1202  auto it = Olvlmap.find(optimizationLevel);
1203  if (it == Olvlmap.end())
1204  {
1205  std::cerr << "Unknown optimization level.\n";
1206  exit(EXIT_FAILURE);
1207  }
1208  CommandLineOptions_.OptimizationLevel_ = it->second;
1209  }
1210 
1211  if (!languageStandard.empty())
1212  {
1213  auto it = stdmap.find(languageStandard);
1214  if (it == stdmap.end())
1215  {
1216  std::cerr << "Unknown language standard.\n";
1217  exit(EXIT_FAILURE);
1218  }
1219  CommandLineOptions_.LanguageStandard_ = it->second;
1220  }
1221 
1222  if (inputFiles.empty())
1223  {
1224  std::cerr << "jlc: no input files.\n";
1225  exit(EXIT_FAILURE);
1226  }
1227 
1228  if (inputFiles.size() > 1 && noLinking && !outputFile.empty())
1229  {
1230  std::cerr << "jlc: cannot specify -o when generating multiple output files.\n";
1231  exit(EXIT_FAILURE);
1232  }
1233 
1234  if (!hlsFunction.empty())
1235  {
1236  CommandLineOptions_.Hls_ = true;
1237  CommandLineOptions_.HlsFunctionRegex_ = hlsFunction.front();
1238  }
1239 
1240  if (hlsFunction.size() > 1)
1241  {
1242  std::cerr << "jlc-hls: more than one function regex specified\n";
1243  exit(EXIT_FAILURE);
1244  }
1245 
1246  CommandLineOptions_.Libraries_ = libraries;
1247  CommandLineOptions_.MacroDefinitions_ = macroDefinitions;
1248  CommandLineOptions_.LibraryPaths_ = libraryPaths;
1249  CommandLineOptions_.Warnings_ = warnings;
1250  CommandLineOptions_.IncludePaths_ = includePaths;
1251  CommandLineOptions_.OnlyPrintCommands_ = onlyPrintCommands;
1252  CommandLineOptions_.GenerateDebugInformation_ = generateDebugInformation;
1253  CommandLineOptions_.Flags_ = flags;
1254  CommandLineOptions_.JlmHls_ = jlmHlsOptimizations;
1255  CommandLineOptions_.Verbose_ = verbose;
1256  CommandLineOptions_.Rdynamic_ = rdynamic;
1257  CommandLineOptions_.Suppress_ = suppress;
1258  CommandLineOptions_.UsePthreads_ = usePthreads;
1259  CommandLineOptions_.Md_ = mD;
1260  CommandLineOptions_.GenerateFirrtl_ = generateFirrtl;
1261 
1262  for (auto & inputFile : inputFiles)
1263  {
1264  util::FilePath inputFilePath(inputFile);
1265  if (IsObjectFile(inputFilePath))
1266  {
1267  /* FIXME: print a warning like clang if noLinking is true */
1268  CommandLineOptions_.Compilations_.push_back(
1269  { inputFilePath, util::FilePath(""), inputFilePath, "", false, false, false, true });
1270 
1271  continue;
1272  }
1273 
1274  CommandLineOptions_.Compilations_.push_back(
1275  { inputFilePath,
1276  mF.empty() ? CreateDependencyFileFromFile(inputFilePath) : util::FilePath(mF),
1277  CreateObjectFileFromFile(inputFilePath),
1278  mT.empty() ? CreateObjectFileFromFile(inputFilePath).name() : mT,
1279  true,
1280  true,
1281  true,
1282  !noLinking });
1283  }
1284 
1285  if (!outputFile.empty())
1286  {
1287  util::FilePath outputFilePath(outputFile);
1288  if (noLinking)
1289  {
1290  JLM_ASSERT(CommandLineOptions_.Compilations_.size() == 1);
1291  CommandLineOptions_.Compilations_[0].SetOutputFile(outputFilePath);
1292  }
1293  else
1294  {
1295  CommandLineOptions_.OutputFile_ = outputFilePath;
1296  }
1297  }
1298 
1299  return CommandLineOptions_;
1300 }
1301 
1302 bool
1304 {
1305  return file.suffix() == "o";
1306 }
1307 
1310 {
1311  return f.Dirname().Join(f.base() + ".o");
1312 }
1313 
1316 {
1317  return f.Dirname().Join(f.base() + ".d");
1318 }
1319 
1320 const JhlsCommandLineOptions &
1321 JhlsCommandLineParser::Parse(int argc, const char * const * argv)
1322 {
1323  static JhlsCommandLineParser parser;
1324  return parser.ParseCommandLineArguments(argc, argv);
1325 }
1326 
1327 }
virtual ~CommandLineParser() noexcept
void Reset() noexcept override
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
Definition: CommandLine.cpp:55
static std::string_view ToString(const OptimizationLevel &optimizationLevel)
Definition: CommandLine.cpp:22
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 dumpRvsdgDotGraphs)
void Reset() noexcept override
Definition: CommandLine.cpp:82
static const util::BijectiveMap< OptimizationId, std::string_view > & GetOptimizationIdCommandLineMap()
Definition: CommandLine.cpp:92
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
const std::string & to_str() const noexcept
Definition: file.hpp:275
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
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