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::AggregateAllocaSplitting, "AggregateAllocaSplitting" },
98  { OptimizationId::CommonNodeElimination, "CommonNodeElimination" },
99  { OptimizationId::DeadNodeElimination, "DeadNodeElimination" },
100  { OptimizationId::FunctionInlining, "FunctionInlining" },
101  { OptimizationId::IfConversion, "IfConversion" },
102  { OptimizationId::InvariantValueRedirection, "InvariantValueRedirection" },
103  { OptimizationId::LoadChainSeparation, "LoadChainSeparation" },
104  { OptimizationId::LoopStrengthReduction, "LoopStrengthReduction" },
105  { OptimizationId::LoopUnrolling, "LoopUnrolling" },
106  { OptimizationId::LoopUnswitching, "LoopUnswitching" },
107  { OptimizationId::NodePullIn, "NodePullIn" },
108  { OptimizationId::NodePushOut, "NodePushOut" },
109  { OptimizationId::NodeReduction, "NodeReduction" },
110  { OptimizationId::PredicateCorrelation, "PredicateCorrelation" },
111  { OptimizationId::RvsdgTreePrinter, "RvsdgTreePrinter" },
112  { OptimizationId::ScalarEvolution, "ScalarEvolution" },
113  { OptimizationId::StoreValueForwarding, "StoreValueForwarding" }
114  };
115 
116  auto firstIndex = static_cast<size_t>(OptimizationId::FirstEnumValue);
117  auto lastIndex = static_cast<size_t>(OptimizationId::LastEnumValue);
118  JLM_ASSERT(map.Size() == lastIndex - firstIndex - 1);
119  return map;
120 }
121 
124  std::string_view commandLineArgument)
125 {
126  // TODO: Deprecated, to be removed
127  if (commandLineArgument == "ThetaGammaInversion")
129 
130  const auto & map = GetOptimizationIdCommandLineMap();
131 
132  if (map.HasValue(commandLineArgument))
133  return map.LookupValue(commandLineArgument);
134 
135  throw util::Error(util::strfmt("Unknown command line argument: ", commandLineArgument));
136 }
137 
138 std::string_view
140 {
141  const auto & map = GetOptimizationIdCommandLineMap();
142 
143  if (map.HasKey(optimizationId))
144  return map.LookupKey(optimizationId);
145 
146  throw util::Error("Unknown optimization identifier");
147 }
148 
151  std::string_view commandLineArgument)
152 {
153  try
154  {
155  return GetStatisticsIdCommandLineArguments().LookupValue(commandLineArgument);
156  }
157  catch (...)
158  {
159  throw util::Error(util::strfmt("Unknown command line argument: ", commandLineArgument));
160  }
161 }
162 
163 std::string_view
165 {
166  try
167  {
168  return GetStatisticsIdCommandLineArguments().LookupKey(statisticsId);
169  }
170  catch (...)
171  {
172  throw util::Error("Unknown statistics identifier");
173  }
174 }
175 
176 std::string_view
178 {
179  static std::unordered_map<InputFormat, std::string_view> map(
180  { { InputFormat::Llvm, "llvm" }, { InputFormat::Mlir, "mlir" } });
181 
182  if (map.find(inputFormat) != map.end())
183  return map[inputFormat];
184 
185  throw util::Error("Unknown input format");
186 }
187 
188 std::string_view
190 {
191  auto & mapping = GetOutputFormatCommandLineArguments();
192  return mapping.at(outputFormat);
193 }
194 
197 {
199  { util::Statistics::Id::AggregateAllocaSplitting, "print-aggregate-alloca-splitting" },
200  { util::Statistics::Id::Aggregation, "print-aggregation-time" },
201  { util::Statistics::Id::AgnosticModRefSummarizer, "print-agnostic-mod-ref-summarization" },
202  { util::Statistics::Id::AliasAnalysisPrecisionEvaluation, "print-aa-precision-evaluation" },
203  { util::Statistics::Id::AndersenAnalysis, "print-andersen-analysis" },
204  { util::Statistics::Id::Annotation, "print-annotation-time" },
205  { util::Statistics::Id::CommonNodeElimination, "print-cne-stat" },
206  { util::Statistics::Id::ControlFlowRecovery, "print-cfr-time" },
207  { util::Statistics::Id::DataNodeToDelta, "printDataNodeToDelta" },
208  { util::Statistics::Id::DeadNodeElimination, "print-dne-stat" },
209  { util::Statistics::Id::FunctionInlining, "print-iln-stat" },
210  { util::Statistics::Id::IfConversion, "print-if-conversion" },
211  { util::Statistics::Id::InvariantValueRedirection, "printInvariantValueRedirection" },
212  { util::Statistics::Id::JlmToRvsdgConversion, "print-jlm-rvsdg-conversion" },
213  { util::Statistics::Id::LoopStrengthReduction, "print-loop-strength-reduction" },
214  { util::Statistics::Id::LoopUnrolling, "print-unroll-stat" },
215  { util::Statistics::Id::LoopUnswitching, "print-ivt-stat" },
216  { util::Statistics::Id::MemoryStateEncoder, "print-basicencoder-encoding" },
217  { util::Statistics::Id::PullNodes, "print-pull-stat" },
218  { util::Statistics::Id::PushNodes, "print-push-stat" },
219  { util::Statistics::Id::ReduceNodes, "print-reduction-stat" },
220  { util::Statistics::Id::RegionAwareModRefSummarizer, "print-mod-ref-summarization" },
221  { util::Statistics::Id::RvsdgConstruction, "print-rvsdg-construction" },
222  { util::Statistics::Id::RvsdgDestruction, "print-rvsdg-destruction" },
223  { util::Statistics::Id::RvsdgOptimization, "print-rvsdg-optimization" },
224  { util::Statistics::Id::RvsdgTreePrinter, "print-rvsdg-tree" },
225  { util::Statistics::Id::ScalarEvolution, "print-scalar-evolution" },
226  { util::Statistics::Id::StoreValueForwarding, "print-store-value-forwarding" },
227  };
228 
229  auto firstIndex = static_cast<size_t>(util::Statistics::Id::FirstEnumValue);
230  auto lastIndex = static_cast<size_t>(util::Statistics::Id::LastEnumValue);
231  JLM_ASSERT(mapping.Size() == lastIndex - firstIndex - 1);
232  return mapping;
233 }
234 
235 const std::unordered_map<JlmOptCommandLineOptions::OutputFormat, std::string_view> &
237 {
238  static std::unordered_map<OutputFormat, std::string_view> mapping = {
239  { OutputFormat::Ascii, "ascii" }, { OutputFormat::Dot, "dot" },
240  { OutputFormat::Json, "json" }, { OutputFormat::JsonTree, "jsonTree" },
241  { OutputFormat::Llvm, "llvm" }, { OutputFormat::Mlir, "mlir" },
242  { OutputFormat::Tree, "tree" },
243  };
244 
245  auto firstIndex = static_cast<size_t>(OutputFormat::FirstEnumValue);
246  auto lastIndex = static_cast<size_t>(OutputFormat::LastEnumValue);
247  JLM_ASSERT(mapping.size() == lastIndex - firstIndex - 1);
248  return mapping;
249 }
250 
251 void
253 {
257  HlsFunction_ = "";
258  ExtractHlsFunction_ = false;
259  MemoryLatency_ = 10;
260 }
261 
262 void
264 {
265  *this = JhlsCommandLineOptions();
266 }
267 
268 static ::llvm::cl::OptionEnumValue
269 CreateStatisticsOption(util::Statistics::Id statisticsId, std::string_view description)
270 {
271  return ::clEnumValN(
272  statisticsId,
274  description);
275 }
276 
277 static ::llvm::cl::OptionEnumValue
280  std::string_view description)
281 {
282  return ::clEnumValN(
283  outputFormat,
285  description);
286 }
287 
288 CommandLineParser::~CommandLineParser() noexcept = default;
289 
290 CommandLineParser::Exception::~Exception() noexcept = default;
291 
292 JlcCommandLineParser::~JlcCommandLineParser() noexcept = default;
293 
294 const JlcCommandLineOptions &
295 JlcCommandLineParser::ParseCommandLineArguments(int argc, const char * const * argv)
296 {
297  auto checkAndConvertJlmOptOptimizations =
298  [](const ::llvm::cl::list<std::string> & optimizations,
300  {
301  if (optimizations.empty() && optimizationLevel == JlcCommandLineOptions::OptimizationLevel::O3)
302  {
303  return std::vector({
332  });
333  }
334 
335  std::vector<JlmOptCommandLineOptions::OptimizationId> optimizationIds;
336  for (auto & optimization : optimizations)
337  {
339  try
340  {
341  optimizationId =
343  }
344  catch (util::Error &)
345  {
346  throw CommandLineParser::Exception("Unknown jlm-opt optimization: " + optimization);
347  }
348 
349  optimizationIds.emplace_back(optimizationId);
350  }
351 
352  return optimizationIds;
353  };
354 
355  CommandLineOptions_.Reset();
356 
357  using namespace ::llvm;
358 
359  /*
360  FIXME: The command line parser setup is currently redone
361  for every invocation of parse_cmdline. We should be able
362  to do it only once and then reset the parser on every
363  invocation of parse_cmdline.
364  */
365 
366  cl::TopLevelSubCommand->reset();
367 
368  cl::opt<bool> onlyPrintCommands(
369  "###",
370  cl::ValueDisallowed,
371  cl::desc("Print (but do not run) the commands for this compilation."));
372 
373  cl::list<std::string> inputFiles(cl::Positional, cl::desc("<inputs>"));
374 
375  cl::list<std::string> includePaths(
376  "I",
377  cl::Prefix,
378  cl::desc("Add directory <dir> to include search paths."),
379  cl::value_desc("dir"));
380 
381  cl::list<std::string> libraryPaths(
382  "L",
383  cl::Prefix,
384  cl::desc("Add directory <dir> to library search paths."),
385  cl::value_desc("dir"));
386 
387  cl::list<std::string> libraries(
388  "l",
389  cl::Prefix,
390  cl::desc("Search the library <lib> when linking."),
391  cl::value_desc("lib"));
392 
393  cl::opt<std::string> outputFile("o", cl::desc("Write output to <file>."), cl::value_desc("file"));
394 
395  cl::opt<bool> generateDebugInformation(
396  "g",
397  cl::ValueDisallowed,
398  cl::desc("Generate source-level debug information."));
399 
400  cl::opt<bool> noLinking(
401  "c",
402  cl::ValueDisallowed,
403  cl::desc("Only run preprocess, compile, and assemble steps."));
404 
405  cl::opt<std::string> optimizationLevel(
406  "O",
407  cl::Prefix,
408  cl::ValueOptional,
409  cl::desc("Optimization level. [O0, O1, O2, O3]"),
410  cl::value_desc("#"));
411 
412  cl::list<std::string> macroDefinitions(
413  "D",
414  cl::Prefix,
415  cl::desc("Add <macro> to preprocessor macros."),
416  cl::value_desc("macro"));
417 
418  cl::list<std::string> warnings(
419  "W",
420  cl::Prefix,
421  cl::desc("Enable specified warning."),
422  cl::value_desc("warning"));
423 
424  cl::opt<std::string> languageStandard(
425  "std",
426  cl::desc("Language standard."),
427  cl::value_desc("standard"));
428 
429  cl::list<std::string> flags("f", cl::Prefix, cl::desc("Specify flags."), cl::value_desc("flag"));
430 
431  cl::list<std::string> jlmOptimizations(
432  "J",
433  cl::Prefix,
434  cl::desc("jlm-opt optimization. Run 'jlm-opt -help' for viable options."),
435  cl::value_desc("jlmopt"));
436 
437  cl::opt<bool> verbose(
438  "v",
439  cl::ValueDisallowed,
440  cl::desc("Show commands to run and use verbose output. (Affects only clang for now)"));
441 
442  cl::opt<bool> rDynamic(
443  "rdynamic",
444  cl::ValueDisallowed,
445  cl::desc("rDynamic option passed to clang"));
446 
447  cl::opt<bool> suppress("w", cl::ValueDisallowed, cl::desc("Suppress all warnings"));
448 
449  cl::opt<bool> usePthreads(
450  "pthread",
451  cl::ValueDisallowed,
452  cl::desc("Support POSIX threads in generated code"));
453 
454  cl::opt<bool> mD(
455  "MD",
456  cl::ValueDisallowed,
457  cl::desc("Write a depfile containing user and system headers"));
458 
459  cl::opt<std::string> mF(
460  "MF",
461  cl::desc("Write depfile output from -mD to <file>."),
462  cl::value_desc("file"));
463 
464  cl::opt<std::string> mT(
465  "MT",
466  cl::desc("Specify name of main file output in depfile."),
467  cl::value_desc("value"));
468 
469  cl::list<util::Statistics::Id> jlmOptPassStatistics(
470  "JlmOptPassStatistics",
471  cl::values(
474  "Collect control flow graph aggregation pass statistics."),
477  "Collect agnostic mod/ref summarizer pass statistics."),
480  "Collect Andersen alias analysis pass statistics."),
483  "Collect aggregation tree annotation pass statistics."),
486  "Collect memory state encoding pass statistics."),
489  "Collect common node elimination pass statistics."),
492  "Collect control flow recovery pass statistics."),
495  "Collect data node to delta node conversion pass statistics."),
498  "Collect dead node elimination pass statistics."),
501  "Collect function inlining pass statistics."),
504  "Collect invariant value redirection pass statistics."),
507  "Collect Jlm to RVSDG conversion pass statistics."),
510  "Collect loop strength reduction pass statistics."),
513  "Collect loop unrolling pass statistics."),
516  "Collect loop unswitching pass statistics."),
519  "Collect node pull pass statistics."),
522  "Collect node push pass statistics."),
525  "Collect node reduction pass statistics."),
528  "Collect region-aware mod/ref summarizer pass statistics."),
531  "Collect RVSDG construction pass statistics."),
534  "Collect RVSDG destruction pass statistics."),
537  "Collect RVSDG optimization pass statistics."),
540  "Collect RVSDG tree printer pass statistics."),
543  "Collect scalar evolution analysis pass statistics.")),
544  cl::desc("Collect jlm-opt pass statistics"));
545 
546  cl::ParseCommandLineOptions(argc, argv);
547 
548  /* Process parsed options */
549 
550  static std::unordered_map<std::string, JlcCommandLineOptions::OptimizationLevel>
551  optimizationLevelMap({ { "0", JlcCommandLineOptions::OptimizationLevel::O0 },
555 
556  static std::unordered_map<std::string, JlcCommandLineOptions::LanguageStandard>
557  languageStandardMap({ { "gnu89", JlcCommandLineOptions::LanguageStandard::Gnu89 },
567 
568  if (!optimizationLevel.empty())
569  {
570  auto iterator = optimizationLevelMap.find(optimizationLevel);
571  if (iterator == optimizationLevelMap.end())
572  {
573  std::cerr << "Unknown optimization level.\n";
574  exit(EXIT_FAILURE);
575  }
576  CommandLineOptions_.OptimizationLevel_ = iterator->second;
577  }
578 
579  if (!languageStandard.empty())
580  {
581  auto iterator = languageStandardMap.find(languageStandard);
582  if (iterator == languageStandardMap.end())
583  {
584  std::cerr << "Unknown language standard.\n";
585  exit(EXIT_FAILURE);
586  }
587  CommandLineOptions_.LanguageStandard_ = iterator->second;
588  }
589 
590  if (inputFiles.empty())
591  {
592  std::cerr << "jlc: no input files.\n";
593  exit(EXIT_FAILURE);
594  }
595 
596  if (inputFiles.size() > 1 && noLinking && !outputFile.empty())
597  {
598  std::cerr << "jlc: cannot specify -o when generating multiple output files.\n";
599  exit(EXIT_FAILURE);
600  }
601 
602  auto jlmOptOptimizations =
603  checkAndConvertJlmOptOptimizations(jlmOptimizations, CommandLineOptions_.OptimizationLevel_);
604 
605  CommandLineOptions_.Libraries_ = libraries;
606  CommandLineOptions_.MacroDefinitions_ = macroDefinitions;
607  CommandLineOptions_.LibraryPaths_ = libraryPaths;
608  CommandLineOptions_.Warnings_ = warnings;
609  CommandLineOptions_.IncludePaths_ = includePaths;
610  CommandLineOptions_.OnlyPrintCommands_ = onlyPrintCommands;
611  CommandLineOptions_.GenerateDebugInformation_ = generateDebugInformation;
612  CommandLineOptions_.Flags_ = flags;
613  CommandLineOptions_.JlmOptOptimizations_ = jlmOptOptimizations;
614  CommandLineOptions_.JlmOptPassStatistics_ = util::HashSet<util::Statistics::Id>(
615  { jlmOptPassStatistics.begin(), jlmOptPassStatistics.end() });
616  CommandLineOptions_.Verbose_ = verbose;
617  CommandLineOptions_.Rdynamic_ = rDynamic;
618  CommandLineOptions_.Suppress_ = suppress;
619  CommandLineOptions_.UsePthreads_ = usePthreads;
620  CommandLineOptions_.Md_ = mD;
621 
622  for (auto & inputFile : inputFiles)
623  {
624  util::FilePath inputFilePath(inputFile);
625  if (IsObjectFile(inputFilePath))
626  {
627  /* FIXME: print a warning like clang if noLinking is true */
628  CommandLineOptions_.Compilations_.push_back(
629  { inputFilePath, util::FilePath(""), inputFilePath, "", false, false, false, true });
630 
631  continue;
632  }
633 
634  CommandLineOptions_.Compilations_.push_back(
635  { inputFilePath,
636  mF.empty() ? ToDependencyFile(inputFilePath) : util::FilePath(mF),
637  ToObjectFile(inputFilePath),
638  mT.empty() ? ToObjectFile(inputFilePath).name() : mT,
639  true,
640  true,
641  true,
642  !noLinking });
643  }
644 
645  if (!outputFile.empty())
646  {
647  util::FilePath outputFilePath(outputFile);
648  if (noLinking)
649  {
650  JLM_ASSERT(CommandLineOptions_.Compilations_.size() == 1);
651  CommandLineOptions_.Compilations_[0].SetOutputFile(outputFilePath);
652  }
653  else
654  {
655  CommandLineOptions_.OutputFile_ = outputFilePath;
656  }
657  }
658 
659  return CommandLineOptions_;
660 }
661 
663 
665 JlmOptCommandLineParser::ParseCommandLineArguments(int argc, const char * const * argv)
666 {
667  using namespace ::llvm;
668 
669  /*
670  FIXME: The command line parser setup is currently redone
671  for every invocation of parse_cmdline. We should be able
672  to do it only once and then reset the parser on every
673  invocation of parse_cmdline.
674  */
675 
676  cl::TopLevelSubCommand->reset();
677 
678  cl::opt<std::string> inputFile(cl::Positional, cl::desc("<input>"));
679 
680  cl::opt<std::string> outputFile(
681  "o",
682  cl::init(""),
683  cl::desc("Write output to <file>"),
684  cl::value_desc("file"));
685 
686  const auto statisticsDirectoryDefault = util::FilePath::TempDirectoryPath().Join("jlm");
687  const auto statisticDirectoryDescription =
688  "Write statistics and debug output to files in <dir>. Default is "
689  + statisticsDirectoryDefault.to_str() + ".";
690  cl::opt<std::string> statisticDirectory(
691  "s",
692  cl::init(statisticsDirectoryDefault.to_str()),
693  cl::desc(statisticDirectoryDescription),
694  cl::value_desc("dir"));
695 
696  cl::opt<bool> dumpRvsdgGraphs(
697  "dumpRvsdgGraphs",
698  cl::init(false),
699  cl::desc("Dump RVSDG as json graphs after each transformation in debug folder."));
700 
701  cl::list<util::Statistics::Id> printStatistics(
702  cl::values(
705  "Write aggregate alloca splitting statistics to file."),
708  "Write aggregation statistics to file."),
711  "Collect agnostic mod/ref summarization pass statistics."),
714  "Evaluate alias analysis precision and store to file"),
717  "Collect Andersen alias analysis pass statistics."),
720  "Write annotation statistics to file."),
723  "Write encoding statistics of basic encoder to file."),
726  "Write common node elimination statistics to file."),
729  "Write control flow recovery statistics to file."),
732  "Write data node to delta node conversion statistics to file."),
735  "Write dead node elimination statistics to file."),
738  "Write function inlining statistics to file."),
741  "Collect if-conversion transformation statistics"),
744  "Write invariant value redirection statistics to file."),
747  "Write Jlm to RVSDG conversion statistics to file."),
750  "Write loop strength reduction statistics to file."),
753  "Write loop unrolling statistics to file."),
756  "Collect loop unswitching pass statistics."),
759  "Write node pull statistics to file."),
762  "Write node push statistics to file."),
765  "Write node reduction statistics to file."),
768  "Collect region-aware mod/ref summarization statistics."),
771  "Write RVSDG construction statistics to file."),
774  "Write RVSDG destruction statistics to file."),
777  "Write RVSDG optimization statistics to file."),
780  "Write RVSDG tree printer pass statistics."),
783  "Write scalar evolution statistics to file."),
786  "Write store value forwarding statistics to file.")),
787  cl::desc("Write statistics"));
788 
789 #ifdef ENABLE_MLIR
790  auto llvmInputFormat = JlmOptCommandLineOptions::InputFormat::Llvm;
791  auto mlirInputFormat = JlmOptCommandLineOptions::InputFormat::Mlir;
792 
793  cl::opt<JlmOptCommandLineOptions::InputFormat> inputFormat(
794  "input-format",
795  cl::desc("Select input format:"),
796  cl::values(
797  ::clEnumValN(
798  llvmInputFormat,
800  "Input LLVM IR [default]"),
801  ::clEnumValN(
802  mlirInputFormat,
804  "Input MLIR")),
805  cl::init(llvmInputFormat));
806 #else
808 #endif
809 
810  cl::opt<JlmOptCommandLineOptions::OutputFormat> outputFormat(
811  "output-format",
812  cl::desc("Select output format:"),
813  cl::values(
818  "Output json dump"),
821  "Output Rvsdg tree as JSON"),
824  "Output LLVM IR [default]"),
825 #ifdef ENABLE_MLIR
827 #endif
830  "Output Rvsdg Tree")),
832 
835  auto aggregateAllocaSplitting =
841  auto invariantValueRedirection =
854 
855  cl::list<JlmOptCommandLineOptions::OptimizationId> optimizationIds(
856  cl::values(
857  ::clEnumValN(
858  aAAndersenAgnostic,
860  "Andersen alias analysis with agnostic memory state encoding"),
861  ::clEnumValN(
862  aAAndersenRegionAware,
864  "Andersen alias analysis with region-aware memory state encoding"),
865  ::clEnumValN(
866  aggregateAllocaSplitting,
867  JlmOptCommandLineOptions::ToCommandLineArgument(aggregateAllocaSplitting),
868  "Split aggregate type alloca nodes"),
869  ::clEnumValN(
870  commonNodeElimination,
872  "Common Node Elimination"),
873  ::clEnumValN(
874  deadNodeElimination,
876  "Dead Node Elimination"),
877  ::clEnumValN(
878  functionInlining,
880  "Function Inlining"),
881  ::clEnumValN(
882  ifConversion,
884  "Convert pass-through values of gamma nodes to select operations"),
885  ::clEnumValN(
886  invariantValueRedirection,
887  JlmOptCommandLineOptions::ToCommandLineArgument(invariantValueRedirection),
888  "Invariant Value Redirection"),
889  ::clEnumValN(
890  loadChainSeparation,
892  "Separate chains of load operations"),
893  ::clEnumValN(
894  loopStrengthReduction,
896  "Loop strength reduction"),
897  ::clEnumValN(
898  loopUnrolling,
900  "Loop Unrolling"),
901  ::clEnumValN(
902  loopUnswitching,
904  "Move conditionals outside loops"),
905  ::clEnumValN(
906  nodePushOut,
908  "Node Push Out"),
909  ::clEnumValN(
910  nodePullIn,
912  "Node Pull In"),
913  ::clEnumValN(
914  nodeReduction,
916  "Node Reduction"),
917  ::clEnumValN(
918  predicateCorrelation,
920  "Correlate predicates between theta and gamma nodes"),
921  ::clEnumValN(
922  rvsdgTreePrinter,
924  "Rvsdg Tree Printer"),
925  ::clEnumValN(
926  scalarEvolution,
928  "Scalar evolution"),
929  ::clEnumValN(
930  storeValueForwarding,
932  "Store Value Forwarding"),
933  ::clEnumValN(
934  loopUnswitching,
935  "ThetaGammaInversion",
936  "[DEPRECATED] Use --LoopUnswitching instead.")),
937  cl::desc("Perform optimization"));
938 
939  cl::list<llvm::RvsdgTreePrinter::Configuration::Annotation> rvsdgTreePrinterAnnotations(
940  "annotations",
941  cl::values(::clEnumValN(
943  "DebugIds",
944  "Annotate region and node IDs")),
945  cl::values(::clEnumValN(
947  "NumAggregateAllocaNodes",
948  "Annotate number of AllocaOperation nodes with aggregate types.")),
949  cl::values(::clEnumValN(
951  "NumAllocaNodes",
952  "Annotate number of AllocaOperation nodes")),
953  cl::values(::clEnumValN(
955  "NumLoadNodes",
956  "Annotate number of LoadOperation nodes")),
957  cl::values(::clEnumValN(
959  "NumMemoryStateInputsOutputs",
960  "Annotate number of inputs/outputs with memory state type")),
961  cl::values(::clEnumValN(
963  "NumRvsdgNodes",
964  "Annotate number of RVSDG nodes")),
965  cl::values(::clEnumValN(
967  "NumStoreNodes",
968  "Annotate number of StoreOperation nodes")),
969  cl::CommaSeparated,
970  cl::desc("Comma separated list of RVSDG tree printer annotations"));
971 
972  cl::ParseCommandLineOptions(argc, argv);
973 
974  jlm::util::FilePath statisticsDirectoryFilePath(statisticDirectory);
975  jlm::util::FilePath inputFilePath(inputFile);
976 
977  util::HashSet<util::Statistics::Id> demandedStatistics(
978  { printStatistics.begin(), printStatistics.end() });
979 
980  util::StatisticsCollectorSettings statisticsCollectorSettings(
981  std::move(demandedStatistics),
982  statisticsDirectoryFilePath,
983  inputFilePath.base());
984 
986  { rvsdgTreePrinterAnnotations.begin(), rvsdgTreePrinterAnnotations.end() });
987 
988  llvm::RvsdgTreePrinter::Configuration treePrinterConfiguration(std::move(demandedAnnotations));
989 
990  CommandLineOptions_ = JlmOptCommandLineOptions::Create(
991  std::move(inputFilePath),
992  inputFormat,
993  util::FilePath(outputFile),
994  outputFormat,
995  std::move(statisticsCollectorSettings),
996  std::move(treePrinterConfiguration),
997  std::move(optimizationIds),
998  dumpRvsdgGraphs);
999 
1000  return *CommandLineOptions_;
1001 }
1002 
1004 JlmOptCommandLineParser::Parse(int argc, const char * const * argv)
1005 {
1006  static JlmOptCommandLineParser parser;
1007  return parser.ParseCommandLineArguments(argc, argv);
1008 }
1009 
1011 
1013 JlmHlsCommandLineParser::ParseCommandLineArguments(int argc, const char * const * argv)
1014 {
1015  CommandLineOptions_.Reset();
1016 
1017  using namespace ::llvm;
1018 
1019  /*
1020  FIXME: The command line parser setup is currently redone
1021  for every invocation of parse_cmdline. We should be able
1022  to do it only once and then reset the parser on every
1023  invocation of parse_cmdline.
1024  */
1025 
1026  cl::TopLevelSubCommand->reset();
1027 
1028  cl::opt<std::string> inputFile(cl::Positional, cl::desc("<input>"));
1029 
1030  cl::opt<std::string> outputFolder(
1031  "o",
1032  cl::desc("Write output to <folder>"),
1033  cl::value_desc("folder"));
1034 
1035  cl::opt<std::string> hlsFunction(
1036  "hls-function",
1037  cl::Prefix,
1038  cl::desc("Function that should be accelerated"),
1039  cl::value_desc("hls-function"));
1040 
1041  cl::opt<int> latency(
1042  "latency",
1043  cl::Prefix,
1044  cl::init(CommandLineOptions_.MemoryLatency_),
1045  cl::desc("Memory latency"),
1046  cl::value_desc("latency"));
1047 
1048  cl::opt<bool> extractHlsFunction(
1049  "extract",
1050  cl::Prefix,
1051  cl::desc("Extracts function specified by hls-function"));
1052 
1053  cl::opt<bool> dumpRvsdgGraphs(
1054  "dumpRvsdgGraphs",
1055  cl::init(false),
1056  cl::desc("Dump RVSDG as json graphs after each transformation in debug folder."));
1057 
1058  cl::opt<JlmHlsCommandLineOptions::OutputFormat> format(
1059  cl::values(
1060  ::clEnumValN(
1062  "fir",
1063  "Output FIRRTL [default]"),
1064  ::clEnumValN(JlmHlsCommandLineOptions::OutputFormat::Dot, "dot", "Output DOT graph")),
1065  cl::desc("Select output format"));
1066 
1067  cl::ParseCommandLineOptions(argc, argv);
1068 
1069  if (outputFolder.empty())
1070  throw util::Error("jlm-hls no output directory provided, i.e, -o.\n");
1071 
1072  if (extractHlsFunction && hlsFunction.empty())
1073  throw util::Error(
1074  "jlm-hls: --hls-function is not specified.\n which is required for --extract\n");
1075 
1076  CommandLineOptions_.InputFile_ = util::FilePath(inputFile);
1077  CommandLineOptions_.HlsFunction_ = std::move(hlsFunction);
1078  CommandLineOptions_.OutputFiles_ = util::FilePath(outputFolder);
1079  CommandLineOptions_.ExtractHlsFunction_ = extractHlsFunction;
1080  CommandLineOptions_.OutputFormat_ = format;
1081  CommandLineOptions_.dumpRvsdgGraphs_ = dumpRvsdgGraphs;
1082 
1083  if (latency < 1)
1084  {
1085  throw util::Error("The --latency must be set to a number larger than zero.");
1086  }
1087  CommandLineOptions_.MemoryLatency_ = latency;
1088 
1089  return CommandLineOptions_;
1090 }
1091 
1093 JlmHlsCommandLineParser::Parse(int argc, const char * const * argv)
1094 {
1095  static JlmHlsCommandLineParser parser;
1096  return parser.ParseCommandLineArguments(argc, argv);
1097 }
1098 
1100 
1101 const JhlsCommandLineOptions &
1102 JhlsCommandLineParser::ParseCommandLineArguments(int argc, const char * const * argv)
1103 {
1104  CommandLineOptions_.Reset();
1105 
1106  using namespace ::llvm;
1107 
1108  /*
1109  FIXME: The command line parser setup is currently redone
1110  for every invocation of parse_cmdline. We should be able
1111  to do it only once and then reset the parser on every
1112  invocation of parse_cmdline.
1113  */
1114 
1115  cl::TopLevelSubCommand->reset();
1116 
1117  cl::opt<bool> onlyPrintCommands(
1118  "###",
1119  cl::ValueDisallowed,
1120  cl::desc("Print (but do not run) the commands for this compilation."));
1121 
1122  cl::list<std::string> inputFiles(cl::Positional, cl::desc("<inputs>"));
1123 
1124  cl::list<std::string> includePaths(
1125  "I",
1126  cl::Prefix,
1127  cl::desc("Add directory <dir> to include search paths."),
1128  cl::value_desc("dir"));
1129 
1130  cl::list<std::string> libraryPaths(
1131  "L",
1132  cl::Prefix,
1133  cl::desc("Add directory <dir> to library search paths."),
1134  cl::value_desc("dir"));
1135 
1136  cl::list<std::string> libraries(
1137  "l",
1138  cl::Prefix,
1139  cl::desc("Search the library <lib> when linking."),
1140  cl::value_desc("lib"));
1141 
1142  cl::opt<std::string> outputFile("o", cl::desc("Write output to <file>."), cl::value_desc("file"));
1143 
1144  cl::opt<bool> generateDebugInformation(
1145  "g",
1146  cl::ValueDisallowed,
1147  cl::desc("Generate source-level debug information."));
1148 
1149  cl::opt<bool> noLinking(
1150  "c",
1151  cl::ValueDisallowed,
1152  cl::desc("Only run preprocess, compile, and assemble steps."));
1153 
1154  cl::opt<std::string> optimizationLevel(
1155  "O",
1156  cl::Prefix,
1157  cl::ValueOptional,
1158  cl::desc("Optimization level. [O0, O1, O2, O3]"),
1159  cl::value_desc("#"));
1160 
1161  cl::list<std::string> macroDefinitions(
1162  "D",
1163  cl::Prefix,
1164  cl::desc("Add <macro> to preprocessor macros."),
1165  cl::value_desc("macro"));
1166 
1167  cl::list<std::string> warnings(
1168  "W",
1169  cl::Prefix,
1170  cl::desc("Enable specified warning."),
1171  cl::value_desc("warning"));
1172 
1173  cl::opt<std::string> languageStandard(
1174  "std",
1175  cl::desc("Language standard."),
1176  cl::value_desc("standard"));
1177 
1178  cl::list<std::string> flags("f", cl::Prefix, cl::desc("Specify flags."), cl::value_desc("flag"));
1179 
1180  cl::list<std::string> jlmHlsOptimizations(
1181  "J",
1182  cl::Prefix,
1183  cl::desc("jlm-hls optimization. Run 'jlm-hls -help' for viable options."),
1184  cl::value_desc("jlmhls"));
1185 
1186  cl::opt<bool> verbose(
1187  "v",
1188  cl::ValueDisallowed,
1189  cl::desc("Show commands to run and use verbose output. (Affects only clang for now)"));
1190 
1191  cl::opt<bool> rdynamic(
1192  "rdynamic",
1193  cl::ValueDisallowed,
1194  cl::desc("rdynamic option passed to clang"));
1195 
1196  cl::opt<bool> suppress("w", cl::ValueDisallowed, cl::desc("Suppress all warnings"));
1197 
1198  cl::opt<bool> usePthreads(
1199  "pthread",
1200  cl::ValueDisallowed,
1201  cl::desc("Support POSIX threads in generated code"));
1202 
1203  cl::opt<bool> mD(
1204  "MD",
1205  cl::ValueDisallowed,
1206  cl::desc("Write a depfile containing user and system headers"));
1207 
1208  cl::opt<std::string> mF(
1209  "MF",
1210  cl::desc("Write depfile output from -MD to <file>."),
1211  cl::value_desc("file"));
1212 
1213  cl::opt<std::string> mT(
1214  "MT",
1215  cl::desc("Specify name of main file output in depfile."),
1216  cl::value_desc("value"));
1217 
1218  cl::list<std::string> hlsFunction(
1219  "hls-function",
1220  cl::Prefix,
1221  cl::desc("function that should be accelerated"),
1222  cl::value_desc("regex"));
1223 
1224  cl::opt<bool> generateFirrtl("firrtl", cl::ValueDisallowed, cl::desc("Generate firrtl"));
1225 
1226  cl::opt<bool> useCirct(
1227  "circt",
1228  cl::Prefix,
1229  cl::desc("DEPRACATED - CIRCT is always used to generate FIRRTL"));
1230 
1231  cl::ParseCommandLineOptions(argc, argv);
1232 
1233  /* Process parsed options */
1234 
1235  static std::unordered_map<std::string, JhlsCommandLineOptions::OptimizationLevel> Olvlmap(
1240 
1241  static std::unordered_map<std::string, JhlsCommandLineOptions::LanguageStandard> stdmap(
1251 
1252  if (!optimizationLevel.empty())
1253  {
1254  auto it = Olvlmap.find(optimizationLevel);
1255  if (it == Olvlmap.end())
1256  {
1257  std::cerr << "Unknown optimization level.\n";
1258  exit(EXIT_FAILURE);
1259  }
1260  CommandLineOptions_.OptimizationLevel_ = it->second;
1261  }
1262 
1263  if (!languageStandard.empty())
1264  {
1265  auto it = stdmap.find(languageStandard);
1266  if (it == stdmap.end())
1267  {
1268  std::cerr << "Unknown language standard.\n";
1269  exit(EXIT_FAILURE);
1270  }
1271  CommandLineOptions_.LanguageStandard_ = it->second;
1272  }
1273 
1274  if (inputFiles.empty())
1275  {
1276  std::cerr << "jlc: no input files.\n";
1277  exit(EXIT_FAILURE);
1278  }
1279 
1280  if (inputFiles.size() > 1 && noLinking && !outputFile.empty())
1281  {
1282  std::cerr << "jlc: cannot specify -o when generating multiple output files.\n";
1283  exit(EXIT_FAILURE);
1284  }
1285 
1286  if (!hlsFunction.empty())
1287  {
1288  CommandLineOptions_.Hls_ = true;
1289  CommandLineOptions_.HlsFunctionRegex_ = hlsFunction.front();
1290  }
1291 
1292  if (hlsFunction.size() > 1)
1293  {
1294  std::cerr << "jlc-hls: more than one function regex specified\n";
1295  exit(EXIT_FAILURE);
1296  }
1297 
1298  CommandLineOptions_.Libraries_ = libraries;
1299  CommandLineOptions_.MacroDefinitions_ = macroDefinitions;
1300  CommandLineOptions_.LibraryPaths_ = libraryPaths;
1301  CommandLineOptions_.Warnings_ = warnings;
1302  CommandLineOptions_.IncludePaths_ = includePaths;
1303  CommandLineOptions_.OnlyPrintCommands_ = onlyPrintCommands;
1304  CommandLineOptions_.GenerateDebugInformation_ = generateDebugInformation;
1305  CommandLineOptions_.Flags_ = flags;
1306  CommandLineOptions_.JlmHls_ = jlmHlsOptimizations;
1307  CommandLineOptions_.Verbose_ = verbose;
1308  CommandLineOptions_.Rdynamic_ = rdynamic;
1309  CommandLineOptions_.Suppress_ = suppress;
1310  CommandLineOptions_.UsePthreads_ = usePthreads;
1311  CommandLineOptions_.Md_ = mD;
1312  CommandLineOptions_.GenerateFirrtl_ = generateFirrtl;
1313 
1314  for (auto & inputFile : inputFiles)
1315  {
1316  util::FilePath inputFilePath(inputFile);
1317  if (IsObjectFile(inputFilePath))
1318  {
1319  /* FIXME: print a warning like clang if noLinking is true */
1320  CommandLineOptions_.Compilations_.push_back(
1321  { inputFilePath, util::FilePath(""), inputFilePath, "", false, false, false, true });
1322 
1323  continue;
1324  }
1325 
1326  CommandLineOptions_.Compilations_.push_back(
1327  { inputFilePath,
1328  mF.empty() ? CreateDependencyFileFromFile(inputFilePath) : util::FilePath(mF),
1329  CreateObjectFileFromFile(inputFilePath),
1330  mT.empty() ? CreateObjectFileFromFile(inputFilePath).name() : mT,
1331  true,
1332  true,
1333  true,
1334  !noLinking });
1335  }
1336 
1337  if (!outputFile.empty())
1338  {
1339  util::FilePath outputFilePath(outputFile);
1340  if (noLinking)
1341  {
1342  JLM_ASSERT(CommandLineOptions_.Compilations_.size() == 1);
1343  CommandLineOptions_.Compilations_[0].SetOutputFile(outputFilePath);
1344  }
1345  else
1346  {
1347  CommandLineOptions_.OutputFile_ = outputFilePath;
1348  }
1349  }
1350 
1351  return CommandLineOptions_;
1352 }
1353 
1354 bool
1356 {
1357  return file.suffix() == "o";
1358 }
1359 
1362 {
1363  return f.Dirname().Join(f.base() + ".o");
1364 }
1365 
1368 {
1369  return f.Dirname().Join(f.base() + ".d");
1370 }
1371 
1372 const JhlsCommandLineOptions &
1373 JhlsCommandLineParser::Parse(int argc, const char * const * argv)
1374 {
1375  static JhlsCommandLineParser parser;
1376  return parser.ParseCommandLineArguments(argc, argv);
1377 }
1378 
1379 }
static const jlm::tooling::JlcCommandLineOptions & ParseCommandLineArguments(const std::vector< std::string > &commandLineArguments)
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 dumpRvsdgGraphs)
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