llvm-reduce.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. //===- llvm-reduce.cpp - The LLVM Delta Reduction utility -----------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This program tries to reduce an IR test case for a given interesting-ness
  10. // test. It runs multiple delta debugging passes in order to minimize the input
  11. // file. It's worth noting that this is a part of the bugpoint redesign
  12. // proposal, and thus a *temporary* tool that will eventually be integrated
  13. // into the bugpoint tool itself.
  14. //
  15. //===----------------------------------------------------------------------===//
  16. #include "DeltaManager.h"
  17. #include "ReducerWorkItem.h"
  18. #include "TestRunner.h"
  19. #include "llvm/Bitcode/BitcodeReader.h"
  20. #include "llvm/CodeGen/CommandFlags.h"
  21. #include "llvm/Support/CommandLine.h"
  22. #include "llvm/Support/InitLLVM.h"
  23. #include "llvm/Support/MemoryBufferRef.h"
  24. #include "llvm/Support/Process.h"
  25. #include "llvm/Support/WithColor.h"
  26. #include "llvm/Support/raw_ostream.h"
  27. #include <system_error>
  28. #include <vector>
  29. #ifdef _WIN32
  30. #include <windows.h>
  31. #endif
  32. using namespace llvm;
  33. cl::OptionCategory LLVMReduceOptions("llvm-reduce options");
  34. static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden,
  35. cl::cat(LLVMReduceOptions));
  36. static cl::opt<bool> Version("v", cl::desc("Alias for -version"), cl::Hidden,
  37. cl::cat(LLVMReduceOptions));
  38. static cl::opt<bool> PreserveDebugEnvironment(
  39. "preserve-debug-environment",
  40. cl::desc("Don't disable features used for crash "
  41. "debugging (crash reports, llvm-symbolizer and core dumps)"),
  42. cl::cat(LLVMReduceOptions));
  43. static cl::opt<bool>
  44. PrintDeltaPasses("print-delta-passes",
  45. cl::desc("Print list of delta passes, passable to "
  46. "--delta-passes as a comma separated list"),
  47. cl::cat(LLVMReduceOptions));
  48. static cl::opt<std::string> InputFilename(cl::Positional,
  49. cl::desc("<input llvm ll/bc file>"),
  50. cl::cat(LLVMReduceOptions));
  51. static cl::opt<std::string>
  52. TestFilename("test",
  53. cl::desc("Name of the interesting-ness test to be run"),
  54. cl::cat(LLVMReduceOptions));
  55. static cl::list<std::string>
  56. TestArguments("test-arg",
  57. cl::desc("Arguments passed onto the interesting-ness test"),
  58. cl::cat(LLVMReduceOptions));
  59. static cl::opt<std::string> OutputFilename(
  60. "output",
  61. cl::desc("Specify the output file. default: reduced.ll|.bc|.mir"));
  62. static cl::alias OutputFileAlias("o", cl::desc("Alias for -output"),
  63. cl::aliasopt(OutputFilename),
  64. cl::cat(LLVMReduceOptions));
  65. static cl::opt<bool>
  66. ReplaceInput("in-place",
  67. cl::desc("WARNING: This option will replace your input file "
  68. "with the reduced version!"),
  69. cl::cat(LLVMReduceOptions));
  70. enum class InputLanguages { None, IR, MIR };
  71. static cl::opt<InputLanguages>
  72. InputLanguage("x", cl::ValueOptional,
  73. cl::desc("Input language ('ir' or 'mir')"),
  74. cl::init(InputLanguages::None),
  75. cl::values(clEnumValN(InputLanguages::IR, "ir", ""),
  76. clEnumValN(InputLanguages::MIR, "mir", "")),
  77. cl::cat(LLVMReduceOptions));
  78. static cl::opt<bool> ForceOutputBitcode(
  79. "output-bitcode",
  80. cl::desc("Emit final result as bitcode instead of text IR"), cl::Hidden,
  81. cl::cat(LLVMReduceOptions));
  82. static cl::opt<int>
  83. MaxPassIterations("max-pass-iterations",
  84. cl::desc("Maximum number of times to run the full set "
  85. "of delta passes (default=5)"),
  86. cl::init(5), cl::cat(LLVMReduceOptions));
  87. static codegen::RegisterCodeGenFlags CGF;
  88. /// Turn off crash debugging features
  89. ///
  90. /// Crash is expected, so disable crash reports and symbolization to reduce
  91. /// output clutter and avoid potentially slow symbolization.
  92. static void disableEnvironmentDebugFeatures() {
  93. sys::Process::PreventCoreFiles();
  94. // TODO: Copied from not. Should have a wrapper around setenv.
  95. #ifdef _WIN32
  96. SetEnvironmentVariableA("LLVM_DISABLE_CRASH_REPORT", "1");
  97. SetEnvironmentVariableA("LLVM_DISABLE_SYMBOLIZATION", "1");
  98. #else
  99. setenv("LLVM_DISABLE_CRASH_REPORT", "1", /*overwrite=*/1);
  100. setenv("LLVM_DISABLE_SYMBOLIZATION", "1", /*overwrite=*/1);
  101. #endif
  102. }
  103. static std::pair<StringRef, bool> determineOutputType(bool IsMIR,
  104. bool InputIsBitcode) {
  105. bool OutputBitcode = ForceOutputBitcode || InputIsBitcode;
  106. if (ReplaceInput) { // In-place
  107. OutputFilename = InputFilename.c_str();
  108. } else if (OutputFilename.empty()) {
  109. // Default to producing bitcode if the input was bitcode, if not explicitly
  110. // requested.
  111. OutputFilename =
  112. IsMIR ? "reduced.mir" : (OutputBitcode ? "reduced.bc" : "reduced.ll");
  113. }
  114. return {OutputFilename, OutputBitcode};
  115. }
  116. int main(int Argc, char **Argv) {
  117. InitLLVM X(Argc, Argv);
  118. const StringRef ToolName(Argv[0]);
  119. cl::HideUnrelatedOptions({&LLVMReduceOptions, &getColorCategory()});
  120. cl::ParseCommandLineOptions(Argc, Argv, "LLVM automatic testcase reducer.\n");
  121. if (Argc == 1) {
  122. cl::PrintHelpMessage();
  123. return 0;
  124. }
  125. if (PrintDeltaPasses) {
  126. printDeltaPasses(outs());
  127. return 0;
  128. }
  129. bool ReduceModeMIR = false;
  130. if (InputLanguage != InputLanguages::None) {
  131. if (InputLanguage == InputLanguages::MIR)
  132. ReduceModeMIR = true;
  133. } else if (StringRef(InputFilename).endswith(".mir")) {
  134. ReduceModeMIR = true;
  135. }
  136. if (InputFilename.empty()) {
  137. WithColor::error(errs(), ToolName)
  138. << "reduction testcase positional argument must be specified\n";
  139. return 1;
  140. }
  141. if (TestFilename.empty()) {
  142. WithColor::error(errs(), ToolName) << "--test option must be specified\n";
  143. return 1;
  144. }
  145. if (!PreserveDebugEnvironment)
  146. disableEnvironmentDebugFeatures();
  147. LLVMContext Context;
  148. std::unique_ptr<TargetMachine> TM;
  149. auto [OriginalProgram, InputIsBitcode] =
  150. parseReducerWorkItem(ToolName, InputFilename, Context, TM, ReduceModeMIR);
  151. if (!OriginalProgram) {
  152. return 1;
  153. }
  154. StringRef OutputFilename;
  155. bool OutputBitcode;
  156. std::tie(OutputFilename, OutputBitcode) =
  157. determineOutputType(ReduceModeMIR, InputIsBitcode);
  158. // Initialize test environment
  159. TestRunner Tester(TestFilename, TestArguments, std::move(OriginalProgram),
  160. std::move(TM), ToolName, OutputFilename, InputIsBitcode,
  161. OutputBitcode);
  162. // This parses and writes out the testcase into a temporary file copy for the
  163. // test, rather than evaluating the source IR directly. This is for the
  164. // convenience of lit tests; the stripped out comments may have broken the
  165. // interestingness checks.
  166. if (!Tester.getProgram().isReduced(Tester)) {
  167. errs() << "\nInput isn't interesting! Verify interesting-ness test\n";
  168. return 1;
  169. }
  170. // Try to reduce code
  171. runDeltaPasses(Tester, MaxPassIterations);
  172. // Print reduced file to STDOUT
  173. if (OutputFilename == "-")
  174. Tester.getProgram().print(outs(), nullptr);
  175. else
  176. Tester.writeOutput("Done reducing! Reduced testcase: ");
  177. return 0;
  178. }