compile_subcommand.cpp 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #include "toolchain/driver/compile_subcommand.h"
  5. #include <functional>
  6. #include <memory>
  7. #include <optional>
  8. #include <string>
  9. #include <system_error>
  10. #include <utility>
  11. #include "common/pretty_stack_trace_function.h"
  12. #include "common/vlog.h"
  13. #include "llvm/ADT/STLExtras.h"
  14. #include "llvm/ADT/ScopeExit.h"
  15. #include "llvm/MC/TargetRegistry.h"
  16. #include "llvm/Passes/OptimizationLevel.h"
  17. #include "llvm/Passes/PassBuilder.h"
  18. #include "llvm/Passes/StandardInstrumentations.h"
  19. #include "toolchain/base/clang_invocation.h"
  20. #include "toolchain/base/timings.h"
  21. #include "toolchain/check/check.h"
  22. #include "toolchain/codegen/codegen.h"
  23. #include "toolchain/diagnostics/emitter.h"
  24. #include "toolchain/diagnostics/format_providers.h"
  25. #include "toolchain/diagnostics/sorting_consumer.h"
  26. #include "toolchain/lex/lex.h"
  27. #include "toolchain/lower/lower.h"
  28. #include "toolchain/parse/parse.h"
  29. #include "toolchain/parse/tree_and_subtrees.h"
  30. #include "toolchain/sem_ir/ids.h"
  31. #include "toolchain/source/source_buffer.h"
  32. namespace Carbon {
  33. auto CompileOptions::Build(CommandLine::CommandBuilder& b) -> void {
  34. b.AddStringPositionalArg(
  35. {
  36. .name = "FILE",
  37. .help = R"""(
  38. The input Carbon source file to compile.
  39. )""",
  40. },
  41. [&](auto& arg_b) {
  42. arg_b.Required(true);
  43. arg_b.Append(&input_filenames);
  44. });
  45. b.AddOneOfOption(
  46. {
  47. .name = "phase",
  48. .help = R"""(
  49. Selects the compilation phase to run. These phases are always run in sequence,
  50. so every phase before the one selected will also be run. The default is to
  51. compile to machine code.
  52. )""",
  53. },
  54. [&](auto& arg_b) {
  55. arg_b.SetOneOf(
  56. {
  57. arg_b.OneOfValue("lex", Phase::Lex),
  58. arg_b.OneOfValue("parse", Phase::Parse),
  59. arg_b.OneOfValue("check", Phase::Check),
  60. arg_b.OneOfValue("lower", Phase::Lower),
  61. arg_b.OneOfValue("optimize", Phase::Optimize),
  62. arg_b.OneOfValue("codegen", Phase::CodeGen).Default(true),
  63. },
  64. &phase);
  65. });
  66. b.AddStringOption(
  67. {
  68. .name = "clang-arg",
  69. .value_name = "CLANG-ARG",
  70. .help = R"""(
  71. An argument to pass to the Clang compiler for use when compiling imported C++
  72. code.
  73. All flags that are accepted by the Clang driver are supported. However, you
  74. cannot specify arguments that would result in additional compilations being
  75. performed. Use `carbon clang` instead to compile additional source files.
  76. )""",
  77. },
  78. [&](auto& arg_b) { arg_b.Append(&clang_args); });
  79. b.AddStringPositionalArg(
  80. {
  81. .name = "CLANG-ARG",
  82. .help = R"""(
  83. Additional Clang arguments. See help for `--clang-arg` for details.
  84. )""",
  85. },
  86. [&](auto& arg_b) { arg_b.Append(&clang_args); });
  87. // TODO: Rearrange the code setting this option and two related ones to
  88. // allow them to reference each other instead of hard-coding their names.
  89. b.AddStringOption(
  90. {
  91. .name = "output",
  92. .value_name = "FILE",
  93. .help = R"""(
  94. The output filename for codegen.
  95. When this is a file name, either textual assembly or a binary object will be
  96. written to it based on the flag `--asm-output`. The default is to write a binary
  97. object file.
  98. Passing `--output=-` will write the output to stdout. In that case, the flag
  99. `--asm-output` is ignored and the output defaults to textual assembly. Binary
  100. object output can be forced by enabling `--force-obj-output`.
  101. )""",
  102. },
  103. [&](auto& arg_b) { arg_b.Set(&output_filename); });
  104. b.AddOneOfOption(
  105. {
  106. .name = "optimize",
  107. .help = R"""(
  108. Selects the amount of optimization to perform.
  109. )""",
  110. },
  111. [&](auto& arg_b) {
  112. arg_b.SetOneOf(
  113. {
  114. // We intentionally don't expose O2 and Os. The difference
  115. // between these levels tends to reflect what achieves the
  116. // best speed for a specific application, as they all
  117. // largely optimize for speed as the primary factor.
  118. //
  119. // Instead of controlling this with more nuanced flags, we
  120. // plan to support profile and in-source hints to the
  121. // optimizer to adjust its strategy in the specific places
  122. // where the default doesn't have the desired results.
  123. arg_b.OneOfValue("none", Lower::OptimizationLevel::None),
  124. arg_b.OneOfValue("debug", Lower::OptimizationLevel::Debug),
  125. arg_b.OneOfValue("speed", Lower::OptimizationLevel::Speed),
  126. arg_b.OneOfValue("size", Lower::OptimizationLevel::Size),
  127. },
  128. &opt_level);
  129. });
  130. // Include the common code generation options at this point to render it
  131. // after the more common options above, but before the more unusual options
  132. // below.
  133. codegen_options.Build(b);
  134. b.AddFlag(
  135. {
  136. .name = "asm-output",
  137. .help = R"""(
  138. Write textual assembly rather than a binary object file to the code generation
  139. output.
  140. This flag only applies when writing to a file. When writing to stdout, the
  141. default is textual assembly and this flag is ignored.
  142. )""",
  143. },
  144. [&](auto& arg_b) { arg_b.Set(&asm_output); });
  145. b.AddFlag(
  146. {
  147. .name = "force-obj-output",
  148. .help = R"""(
  149. Force binary object output, even with `--output=-`.
  150. When `--output=-` is set, the default is textual assembly; this forces printing
  151. of a binary object file instead. Ignored for other `--output` values.
  152. )""",
  153. },
  154. [&](auto& arg_b) { arg_b.Set(&force_obj_output); });
  155. b.AddFlag(
  156. {
  157. .name = "stream-errors",
  158. .help = R"""(
  159. Stream error messages to stderr as they are generated rather than sorting them
  160. and displaying them in source order.
  161. )""",
  162. },
  163. [&](auto& arg_b) { arg_b.Set(&stream_errors); });
  164. b.AddFlag(
  165. {
  166. .name = "dump-shared-values",
  167. .help = R"""(
  168. Dumps shared values. These aren't owned by any particular file or phase.
  169. )""",
  170. },
  171. [&](auto& arg_b) { arg_b.Set(&dump_shared_values); });
  172. b.AddFlag(
  173. {
  174. .name = "dump-tokens",
  175. .help = R"""(
  176. Dump the tokens to stdout when lexed.
  177. )""",
  178. },
  179. [&](auto& arg_b) { arg_b.Set(&dump_tokens); });
  180. b.AddFlag(
  181. {
  182. .name = "omit-file-boundary-tokens",
  183. .help = R"""(
  184. For `--dump-tokens`, omit file start and end boundary tokens.
  185. )""",
  186. },
  187. [&](auto& arg_b) { arg_b.Set(&omit_file_boundary_tokens); });
  188. b.AddFlag(
  189. {
  190. .name = "dump-parse-tree",
  191. .help = R"""(
  192. Dump the parse tree to stdout when parsed.
  193. )""",
  194. },
  195. [&](auto& arg_b) { arg_b.Set(&dump_parse_tree); });
  196. b.AddFlag(
  197. {
  198. .name = "preorder-parse-tree",
  199. .help = R"""(
  200. When dumping the parse tree, reorder it so that it is in preorder rather than
  201. postorder.
  202. )""",
  203. },
  204. [&](auto& arg_b) { arg_b.Set(&preorder_parse_tree); });
  205. b.AddFlag(
  206. {
  207. .name = "dump-raw-sem-ir",
  208. .help = R"""(
  209. Dump the raw JSON structure of SemIR to stdout when built.
  210. )""",
  211. },
  212. [&](auto& arg_b) { arg_b.Set(&dump_raw_sem_ir); });
  213. b.AddFlag(
  214. {
  215. .name = "dump-sem-ir",
  216. .help = R"""(
  217. Dump the full SemIR to stdout when built.
  218. )""",
  219. },
  220. [&](auto& arg_b) { arg_b.Set(&dump_sem_ir); });
  221. b.AddFlag(
  222. {
  223. .name = "dump-cpp-ast",
  224. .help = R"""(
  225. Dump the full C++ AST to stdout when built.
  226. )""",
  227. },
  228. [&](auto& arg_b) { arg_b.Set(&dump_cpp_ast); });
  229. b.AddOneOfOption(
  230. {
  231. .name = "dump-sem-ir-ranges",
  232. .help = R"""(
  233. Selects handling of `//@dump-sem-ir-[begin|end]` markers when dumping SemIR.
  234. By default, `if-present` prints ranges for files that have them, and full SemIR
  235. for files that don't. `only` skips files with no ranges, and `ignore` always
  236. prints full SemIR.
  237. )""",
  238. },
  239. [&](auto& arg_b) {
  240. using DumpSemIRRanges = Check::CheckParseTreesOptions::DumpSemIRRanges;
  241. arg_b.SetOneOf(
  242. {
  243. arg_b.OneOfValue("if-present", DumpSemIRRanges::IfPresent)
  244. .Default(true),
  245. arg_b.OneOfValue("only", DumpSemIRRanges::Only),
  246. arg_b.OneOfValue("ignore", DumpSemIRRanges::Ignore),
  247. },
  248. &dump_sem_ir_ranges);
  249. });
  250. b.AddFlag(
  251. {
  252. .name = "builtin-sem-ir",
  253. .help = R"""(
  254. Include the SemIR for builtins when dumping it.
  255. )""",
  256. },
  257. [&](auto& arg_b) { arg_b.Set(&builtin_sem_ir); });
  258. b.AddFlag(
  259. {
  260. .name = "dump-llvm-ir",
  261. .help = R"""(
  262. Dump the LLVM IR to stdout after lowering.
  263. )""",
  264. },
  265. [&](auto& arg_b) { arg_b.Set(&dump_llvm_ir); });
  266. b.AddFlag(
  267. {
  268. .name = "dump-asm",
  269. .help = R"""(
  270. Dump the generated assembly to stdout after codegen.
  271. )""",
  272. },
  273. [&](auto& arg_b) { arg_b.Set(&dump_asm); });
  274. b.AddFlag(
  275. {
  276. .name = "dump-mem-usage",
  277. .help = R"""(
  278. Dumps the amount of memory used.
  279. )""",
  280. },
  281. [&](auto& arg_b) { arg_b.Set(&dump_mem_usage); });
  282. b.AddFlag(
  283. {
  284. .name = "dump-timings",
  285. .help = R"""(
  286. Dumps the duration of each phase for each compilation unit.
  287. )""",
  288. },
  289. [&](auto& arg_b) { arg_b.Set(&dump_timings); });
  290. b.AddFlag(
  291. {
  292. .name = "prelude-import",
  293. .help = R"""(
  294. Whether to use the implicit prelude import. Enabled by default.
  295. )""",
  296. },
  297. [&](auto& arg_b) {
  298. arg_b.Default(true);
  299. arg_b.Set(&prelude_import);
  300. });
  301. b.AddFlag(
  302. {
  303. .name = "custom-core",
  304. .value_name = "CUSTOM_CORE",
  305. .help = R"""(
  306. Whether to use a custom Core package, the files for which must all be included
  307. in the compile command line.
  308. The prelude library in the Core package is imported automatically. By default,
  309. the Core package shipped with the toolchain is used, and its files do not need
  310. to be specified in the compile command line.
  311. )""",
  312. },
  313. [&](auto& arg_b) {
  314. arg_b.Default(false);
  315. arg_b.Set(&custom_core);
  316. });
  317. b.AddStringOption(
  318. {
  319. .name = "exclude-dump-file-prefix",
  320. .value_name = "PREFIX",
  321. .help = R"""(
  322. Excludes files with the given prefix from dumps.
  323. )""",
  324. },
  325. [&](auto& arg_b) { arg_b.Append(&exclude_dump_file_prefixes); });
  326. b.AddFlag(
  327. {
  328. .name = "debug-info",
  329. .help = R"""(
  330. Whether to emit DWARF debug information.
  331. )""",
  332. },
  333. [&](auto& arg_b) {
  334. arg_b.Default(true);
  335. arg_b.Set(&include_debug_info);
  336. });
  337. b.AddFlag(
  338. {
  339. .name = "output-last-input-only",
  340. .help = R"""(
  341. Only write output for the last input file, ignoring all others.
  342. TODO: This is a temporary workaround and should be removed once separate
  343. compilation is better implemented.
  344. )""",
  345. },
  346. [&](auto& arg_b) { arg_b.Set(&output_last_input_only); });
  347. b.AddFlag(
  348. {
  349. .name = "verify-llvm-ir",
  350. .help = R"""(
  351. Whether to run the LLVM verifier on modules.
  352. )""",
  353. },
  354. [&](auto& arg_b) {
  355. arg_b.Default(true);
  356. arg_b.Set(&run_llvm_verifier);
  357. });
  358. b.AddStringOption(
  359. {
  360. .name = "sem-ir-crash-dump",
  361. .value_name = "PATH",
  362. .help = R"""(
  363. Where to write a dump of the raw SemIR emitted so far, in the event of a crash
  364. in the check phase. If empty, the dump is not written.
  365. )""",
  366. },
  367. [&](auto& arg_b) { arg_b.Set(&sem_ir_crash_dump); });
  368. }
  369. static constexpr CommandLine::CommandInfo SubcommandInfo = {
  370. .name = "compile",
  371. .help = R"""(
  372. Compile Carbon source code.
  373. This subcommand runs the Carbon compiler over input source code, checking it for
  374. errors and producing the requested output.
  375. Error messages are written to the standard error stream.
  376. Different phases of the compiler can be selected to run, and intermediate state
  377. can be written to standard output as these phases progress.
  378. )""",
  379. };
  380. CompileSubcommand::CompileSubcommand() : DriverSubcommand(SubcommandInfo) {}
  381. // Returns a string for printing the phase in a diagnostic.
  382. static auto PhaseToString(CompileOptions::Phase phase) -> std::string {
  383. switch (phase) {
  384. case CompileOptions::Phase::Lex:
  385. return "lex";
  386. case CompileOptions::Phase::Parse:
  387. return "parse";
  388. case CompileOptions::Phase::Check:
  389. return "check";
  390. case CompileOptions::Phase::Lower:
  391. return "lower";
  392. case CompileOptions::Phase::Optimize:
  393. return "optimize";
  394. case CompileOptions::Phase::CodeGen:
  395. return "codegen";
  396. }
  397. }
  398. auto CompileSubcommand::ValidateOptions(
  399. Diagnostics::NoLocEmitter& emitter) const -> bool {
  400. CARBON_DIAGNOSTIC(
  401. CompilePhaseFlagConflict, Error,
  402. "requested dumping {0} but compile phase is limited to `{1}`",
  403. std::string, std::string);
  404. using Phase = CompileOptions::Phase;
  405. switch (options_.phase) {
  406. case Phase::Lex:
  407. if (options_.dump_parse_tree) {
  408. emitter.Emit(CompilePhaseFlagConflict, "parse tree",
  409. PhaseToString(options_.phase));
  410. return false;
  411. }
  412. [[fallthrough]];
  413. case Phase::Parse:
  414. if (options_.dump_sem_ir) {
  415. emitter.Emit(CompilePhaseFlagConflict, "SemIR",
  416. PhaseToString(options_.phase));
  417. return false;
  418. }
  419. if (options_.dump_cpp_ast) {
  420. emitter.Emit(CompilePhaseFlagConflict, "C++ AST",
  421. PhaseToString(options_.phase));
  422. return false;
  423. }
  424. [[fallthrough]];
  425. case Phase::Check:
  426. if (options_.dump_llvm_ir) {
  427. emitter.Emit(CompilePhaseFlagConflict, "LLVM IR",
  428. PhaseToString(options_.phase));
  429. return false;
  430. }
  431. [[fallthrough]];
  432. case Phase::Lower:
  433. case Phase::Optimize:
  434. case Phase::CodeGen:
  435. // Everything can be dumped in these phases.
  436. break;
  437. }
  438. return true;
  439. }
  440. namespace {
  441. class MultiUnitCache;
  442. // Ties together information for a file being compiled.
  443. class CompilationUnit {
  444. public:
  445. // `driver_env`, `options`, `consumer`, and `target` must be non-null.
  446. explicit CompilationUnit(SemIR::CheckIRId check_ir_id, int total_ir_count,
  447. DriverEnv* driver_env, const CompileOptions* options,
  448. Diagnostics::Consumer* consumer,
  449. llvm::StringRef input_filename,
  450. const llvm::Target* target);
  451. // Sets the multi-unit cache and initializes dependent member state.
  452. auto SetMultiUnitCache(MultiUnitCache* cache) -> void;
  453. // Loads source and lexes it. Returns true on success.
  454. auto RunLex() -> void;
  455. // Parses tokens. Returns true on success.
  456. auto RunParse() -> void;
  457. // Returns information needed to check this unit.
  458. auto GetCheckUnit() -> Check::Unit;
  459. // Runs post-check logic. Returns true if checking succeeded for the IR.
  460. auto PostCheck() -> void;
  461. // Lower SemIR to LLVM IR.
  462. auto RunLower() -> void;
  463. // Runs the optimization pipeline.
  464. auto RunOptimize(const clang::CompilerInvocation& clang_invocation) -> void;
  465. // Runs post-lowering-to-LLVM-IR logic. This is always called if we do any
  466. // lowering work, after we've finished building the IR in RunLower() and,
  467. // optionally, RunOptimize().
  468. auto PostLower() -> void;
  469. auto RunCodeGen() -> void;
  470. // Runs post-compile logic. This is always called, and called after all other
  471. // actions on the CompilationUnit.
  472. auto PostCompile() -> void;
  473. // Flushes diagnostics, specifically as part of generating stack trace
  474. // information.
  475. auto FlushForStackTrace() -> void { consumer_->Flush(); }
  476. auto input_filename() -> llvm::StringRef { return input_filename_; }
  477. auto has_include_in_dumps() -> bool {
  478. return tokens_ && tokens_->has_include_in_dumps();
  479. }
  480. auto success() -> bool { return success_; }
  481. auto has_source() -> bool { return source_.has_value(); }
  482. auto get_trees_and_subtrees() -> Parse::GetTreeAndSubtreesFn {
  483. return *tree_and_subtrees_getter_;
  484. }
  485. private:
  486. // Do codegen. Returns true on success.
  487. auto RunCodeGenHelper() -> bool;
  488. // The TreeAndSubtrees is mainly used for debugging and diagnostics, and has
  489. // significant overhead. Avoid constructing it when unused.
  490. auto GetParseTreeAndSubtrees() -> const Parse::TreeAndSubtrees&;
  491. // Wraps a call with log statements to indicate start and end. Typically logs
  492. // with the actual function name, but marks timings with the appropriate
  493. // phase.
  494. auto LogCall(llvm::StringLiteral logging_label,
  495. llvm::StringLiteral timing_label,
  496. llvm::function_ref<auto()->void> fn) -> void;
  497. // Returns true if the current file should be included in debug dumps.
  498. auto IncludeInDumps() -> bool;
  499. // Builds the LLVM target machine.
  500. auto MakeTargetMachine(const clang::CompilerInvocation& clang_invocation)
  501. -> void;
  502. // The index of the unit amongst all units.
  503. SemIR::CheckIRId check_ir_id_;
  504. // The number of units in total.
  505. int total_ir_count_;
  506. DriverEnv* driver_env_;
  507. const CompileOptions* options_;
  508. const llvm::Target* target_;
  509. SharedValueStores value_stores_;
  510. // The input filename from the command line. For most diagnostics, we
  511. // typically use `source_->filename()`, which includes a `-` -> `<stdin>`
  512. // translation. However, logging and some diagnostics use the command line
  513. // argument.
  514. std::string input_filename_;
  515. // Copied from driver_ for CARBON_VLOG.
  516. llvm::raw_pwrite_stream* vlog_stream_;
  517. // Diagnostics are sent to consumer_, with optional sorting.
  518. std::optional<Diagnostics::SortingConsumer> sorting_consumer_;
  519. Diagnostics::Consumer* consumer_;
  520. bool success_ = true;
  521. // Initialized by `SetMultiUnitCache`.
  522. MultiUnitCache* cache_ = nullptr;
  523. // Tracks memory usage of the compile.
  524. std::optional<MemUsage> mem_usage_;
  525. // Tracks timings of the compile.
  526. std::optional<Timings> timings_;
  527. // These are initialized as steps are run.
  528. std::optional<SourceBuffer> source_;
  529. std::optional<Lex::TokenizedBuffer> tokens_;
  530. std::optional<Parse::Tree> parse_tree_;
  531. std::optional<Parse::TreeAndSubtrees> parse_tree_and_subtrees_;
  532. std::optional<std::function<auto()->const Parse::TreeAndSubtrees&>>
  533. tree_and_subtrees_getter_;
  534. std::unique_ptr<llvm::LLVMContext> llvm_context_;
  535. std::optional<SemIR::File> sem_ir_;
  536. std::unique_ptr<llvm::Module> module_;
  537. std::unique_ptr<llvm::TargetMachine> target_machine_;
  538. };
  539. // Caches lists that are shared cross-unit. Accessors do lazy caching because
  540. // they may not be used.
  541. class MultiUnitCache {
  542. public:
  543. using IncludeInDumpsStore = FixedSizeValueStore<SemIR::CheckIRId, bool>;
  544. using TreeAndSubtreesGettersStore = Parse::GetTreeAndSubtreesStore;
  545. // This relies on construction after `units` are all initialized, which is
  546. // reflected by the `ArrayRef` here.
  547. explicit MultiUnitCache(
  548. const CompileOptions* options,
  549. llvm::ArrayRef<std::unique_ptr<CompilationUnit>> units)
  550. : options_(options), units_(units) {}
  551. // If `include_in_dumps` is in use, we need to apply per-file include
  552. // settings.
  553. auto ApplyPerFileIncludeInDumps() -> void {
  554. if (!include_in_dumps_) {
  555. // No cached value to update.
  556. return;
  557. }
  558. for (const auto& [i, unit] : llvm::enumerate(units_)) {
  559. if (unit->has_include_in_dumps()) {
  560. include_in_dumps_->Set(SemIR::CheckIRId(i), true);
  561. }
  562. }
  563. }
  564. auto include_in_dumps() -> const IncludeInDumpsStore& {
  565. if (!include_in_dumps_) {
  566. include_in_dumps_.emplace(
  567. IncludeInDumpsStore::MakeWithExplicitSize(units_.size(), false));
  568. for (const auto& [i, unit] : llvm::enumerate(units_)) {
  569. // If this is first accessed after lexing is complete, we need to apply
  570. // per-file includes. Otherwise, this is based only on the exclude
  571. // option.
  572. bool include =
  573. unit->has_include_in_dumps() ||
  574. llvm::none_of(options_->exclude_dump_file_prefixes,
  575. [&](auto prefix) {
  576. return unit->input_filename().starts_with(prefix);
  577. });
  578. include_in_dumps_->Set(SemIR::CheckIRId(i), include);
  579. }
  580. }
  581. return *include_in_dumps_;
  582. }
  583. auto tree_and_subtrees_getters() -> const TreeAndSubtreesGettersStore& {
  584. if (!tree_and_subtrees_getters_) {
  585. tree_and_subtrees_getters_.emplace(
  586. TreeAndSubtreesGettersStore::MakeWithExplicitSize(units_.size(),
  587. nullptr));
  588. for (const auto& [i, unit] : llvm::enumerate(units_)) {
  589. if (unit->has_source()) {
  590. tree_and_subtrees_getters_->Set(SemIR::CheckIRId(i),
  591. unit->get_trees_and_subtrees());
  592. }
  593. }
  594. }
  595. return *tree_and_subtrees_getters_;
  596. }
  597. private:
  598. const CompileOptions* options_;
  599. // The units being compiled.
  600. llvm::ArrayRef<std::unique_ptr<CompilationUnit>> units_;
  601. // For each unit, whether it's included in dumps. Used cross-phase.
  602. std::optional<IncludeInDumpsStore> include_in_dumps_;
  603. // For each unit, the `TreeAndSubtrees` getter. Used by lowering.
  604. std::optional<TreeAndSubtreesGettersStore> tree_and_subtrees_getters_;
  605. };
  606. } // namespace
  607. CompilationUnit::CompilationUnit(SemIR::CheckIRId check_ir_id,
  608. int total_ir_count, DriverEnv* driver_env,
  609. const CompileOptions* options,
  610. Diagnostics::Consumer* consumer,
  611. llvm::StringRef input_filename,
  612. const llvm::Target* target)
  613. : check_ir_id_(check_ir_id),
  614. total_ir_count_(total_ir_count),
  615. driver_env_(driver_env),
  616. options_(options),
  617. target_(target),
  618. input_filename_(input_filename),
  619. vlog_stream_(driver_env_->vlog_stream) {
  620. if (vlog_stream_ != nullptr || options_->stream_errors) {
  621. consumer_ = consumer;
  622. } else {
  623. sorting_consumer_ = Diagnostics::SortingConsumer(*consumer);
  624. consumer_ = &*sorting_consumer_;
  625. }
  626. }
  627. auto CompilationUnit::IncludeInDumps() -> bool {
  628. return cache_->include_in_dumps().Get(check_ir_id_);
  629. }
  630. auto CompilationUnit::SetMultiUnitCache(MultiUnitCache* cache) -> void {
  631. CARBON_CHECK(!cache_, "Called SetMultiUnitCache twice");
  632. cache_ = cache;
  633. if (options_->dump_mem_usage && IncludeInDumps()) {
  634. CARBON_CHECK(!mem_usage_);
  635. mem_usage_ = MemUsage();
  636. }
  637. if (options_->dump_timings && IncludeInDumps()) {
  638. CARBON_CHECK(!timings_);
  639. timings_ = Timings();
  640. }
  641. }
  642. auto CompilationUnit::RunLex() -> void {
  643. CARBON_CHECK(cache_, "Must call SetMultiUnitCache first");
  644. CARBON_CHECK(!tokens_, "Called RunLex twice");
  645. LogCall("SourceBuffer::MakeFromFileOrStdin", "source", [&] {
  646. source_ = SourceBuffer::MakeFromFileOrStdin(*driver_env_->fs,
  647. input_filename_, *consumer_);
  648. });
  649. if (!source_) {
  650. success_ = false;
  651. return;
  652. }
  653. if (mem_usage_) {
  654. mem_usage_->Add("source_", source_->text().size(), source_->text().size());
  655. }
  656. CARBON_VLOG("*** SourceBuffer ***\n```\n{0}\n```\n", source_->text());
  657. LogCall("Lex::Lex", "lex", [&] {
  658. Lex::LexOptions options;
  659. options.consumer = consumer_;
  660. options.vlog_stream = vlog_stream_;
  661. if (options_->dump_tokens && IncludeInDumps()) {
  662. options.dump_stream = driver_env_->output_stream;
  663. options.omit_file_boundary_tokens = options_->omit_file_boundary_tokens;
  664. }
  665. tokens_ = Lex::Lex(value_stores_, *source_, options);
  666. });
  667. if (mem_usage_) {
  668. mem_usage_->Collect("tokens_", *tokens_);
  669. }
  670. if (tokens_->has_errors()) {
  671. success_ = false;
  672. }
  673. }
  674. auto CompilationUnit::RunParse() -> void {
  675. LogCall("Parse::Parse", "parse", [&] {
  676. Parse::ParseOptions options;
  677. options.consumer = consumer_;
  678. options.vlog_stream = vlog_stream_;
  679. if (options_->dump_parse_tree && IncludeInDumps()) {
  680. options.dump_stream = driver_env_->output_stream;
  681. options.dump_preorder_parse_tree = options_->preorder_parse_tree;
  682. }
  683. parse_tree_ = Parse::Parse(*tokens_, options);
  684. });
  685. if (mem_usage_) {
  686. mem_usage_->Collect("parse_tree_", *parse_tree_);
  687. }
  688. if (parse_tree_->has_errors()) {
  689. success_ = false;
  690. }
  691. }
  692. auto CompilationUnit::GetCheckUnit() -> Check::Unit {
  693. CARBON_CHECK(parse_tree_, "Must call RunParse first");
  694. CARBON_CHECK(!sem_ir_, "Called GetCheckUnit twice");
  695. tree_and_subtrees_getter_ = [this]() -> const Parse::TreeAndSubtrees& {
  696. return this->GetParseTreeAndSubtrees();
  697. };
  698. sem_ir_.emplace(&*parse_tree_, check_ir_id_, parse_tree_->packaging_decl(),
  699. value_stores_, input_filename_);
  700. if (!llvm_context_) {
  701. llvm_context_ = std::make_unique<llvm::LLVMContext>();
  702. }
  703. return {.consumer = consumer_,
  704. .value_stores = &value_stores_,
  705. .timings = timings_ ? &*timings_ : nullptr,
  706. .sem_ir = &*sem_ir_,
  707. .llvm_context = llvm_context_.get(),
  708. .total_ir_count = total_ir_count_};
  709. }
  710. auto CompilationUnit::PostCheck() -> void {
  711. CARBON_CHECK(sem_ir_, "Must call GetCheckUnit first");
  712. // We've finished all steps that can produce diagnostics. Emit the
  713. // diagnostics now, so that the developer sees them sooner and doesn't need
  714. // to wait for code generation.
  715. consumer_->Flush();
  716. if (mem_usage_) {
  717. mem_usage_->Collect("sem_ir_", *sem_ir_);
  718. }
  719. if (sem_ir_->has_errors()) {
  720. success_ = false;
  721. }
  722. }
  723. auto CompilationUnit::RunLower() -> void {
  724. LogCall("Lower::LowerToLLVM", "lower", [&] {
  725. if (!llvm_context_) {
  726. llvm_context_ = std::make_unique<llvm::LLVMContext>();
  727. }
  728. Lower::LowerToLLVMOptions options;
  729. options.llvm_verifier_stream =
  730. options_->run_llvm_verifier ? driver_env_->error_stream : nullptr;
  731. options.want_debug_info = options_->include_debug_info;
  732. options.vlog_stream = vlog_stream_;
  733. options.opt_level = options_->opt_level;
  734. module_ = Lower::LowerToLLVM(*llvm_context_, driver_env_->fs,
  735. cache_->tree_and_subtrees_getters(), *sem_ir_,
  736. total_ir_count_, options);
  737. });
  738. }
  739. auto CompilationUnit::MakeTargetMachine(
  740. const clang::CompilerInvocation& clang_invocation) -> void {
  741. CARBON_CHECK(module_, "Must call RunLower first");
  742. CARBON_CHECK(!target_machine_, "Should not call this multiple times");
  743. // Set the target on the module.
  744. // TODO: We should do this earlier. Lower should be passed the target triple
  745. // so it can create the module with this already set.
  746. llvm::Triple target_triple(options_->codegen_options.target);
  747. module_->setTargetTriple(target_triple);
  748. // TODO: Provide flags to control these.
  749. constexpr llvm::StringLiteral CPU = "generic";
  750. constexpr llvm::StringLiteral Features = "";
  751. const auto& codegen_opts = clang_invocation.getCodeGenOpts();
  752. // TODO: Make the code in Clang's BackendUtil.cpp externally accessible and
  753. // call it from here. This is doing a subset of the same work to translate
  754. // Clang code generation options into target options.
  755. llvm::TargetOptions target_opts;
  756. target_opts.UseInitArray = codegen_opts.UseInitArray;
  757. target_opts.FunctionSections = codegen_opts.FunctionSections;
  758. target_opts.DataSections = codegen_opts.DataSections;
  759. target_opts.UniqueSectionNames = codegen_opts.UniqueSectionNames;
  760. target_machine_.reset(target_->createTargetMachine(
  761. target_triple, CPU, Features, target_opts, llvm::Reloc::PIC_));
  762. }
  763. // Get the LLVM optimization level corresponding to a Carbon optimization level.
  764. static auto GetLLVMOptimizationLevel(Lower::OptimizationLevel opt_level)
  765. -> llvm::OptimizationLevel {
  766. switch (opt_level) {
  767. case Lower::OptimizationLevel::None:
  768. return llvm::OptimizationLevel::O0;
  769. case Lower::OptimizationLevel::Debug:
  770. return llvm::OptimizationLevel::O1;
  771. case Lower::OptimizationLevel::Size:
  772. return llvm::OptimizationLevel::Oz;
  773. case Lower::OptimizationLevel::Speed:
  774. return llvm::OptimizationLevel::O3;
  775. }
  776. }
  777. // Get the `-O` flag corresponding to an optimization level.
  778. static auto GetClangOptimizationFlag(Lower::OptimizationLevel opt_level)
  779. -> llvm::StringLiteral {
  780. switch (opt_level) {
  781. case Lower::OptimizationLevel::None:
  782. return "-O0";
  783. case Lower::OptimizationLevel::Debug:
  784. return "-O1";
  785. case Lower::OptimizationLevel::Size:
  786. return "-Oz";
  787. case Lower::OptimizationLevel::Speed:
  788. return "-O3";
  789. }
  790. }
  791. auto CompilationUnit::RunOptimize(
  792. const clang::CompilerInvocation& clang_invocation) -> void {
  793. CARBON_CHECK(module_, "Must call RunLower first");
  794. // TODO: A lot of the work done here duplicates work done by Clang setting up
  795. // its pass manager. Moreover, we probably want to pick up Clang's
  796. // customizations and make use of its flags for controlling LLVM passes. We
  797. // should consider whether we would be better off running Clang's pass
  798. // pipeline rather than building one of our own, or factoring out enough of
  799. // Clang's pipeline builder that we can reuse and further customize it.
  800. MakeTargetMachine(clang_invocation);
  801. // TODO: There's no way to set these automatically from an
  802. // llvm::OptimizationLevel. Add such a mechanism to LLVM and use it from
  803. // here. For now we reconstruct what Clang does by default.
  804. llvm::PipelineTuningOptions pto;
  805. bool opt_for_speed = options_->opt_level == Lower::OptimizationLevel::Speed;
  806. bool opt_for_size_or_speed =
  807. opt_for_speed || options_->opt_level == Lower::OptimizationLevel::Size;
  808. // Loop unrolling is enabled by `--optimize=size` but isn't actually performed
  809. // because we add `optsize` attributes to the function definitions we emit.
  810. pto.LoopUnrolling = opt_for_size_or_speed;
  811. pto.LoopInterleaving = opt_for_size_or_speed;
  812. pto.LoopVectorization = opt_for_speed;
  813. pto.SLPVectorization = opt_for_size_or_speed;
  814. llvm::LoopAnalysisManager lam;
  815. llvm::FunctionAnalysisManager fam;
  816. llvm::CGSCCAnalysisManager cgam;
  817. llvm::ModuleAnalysisManager mam;
  818. llvm::PassInstrumentationCallbacks pic;
  819. // Register standard pass instrumentations. This adds support for things like
  820. // `-print-after-all`.
  821. llvm::StandardInstrumentations si(module_->getContext(),
  822. /*DebugLogging=*/false);
  823. si.registerCallbacks(pic);
  824. llvm::PassBuilder builder(target_machine_.get(), pto,
  825. /*PGOOpt=*/std::nullopt, &pic);
  826. // TODO: Add an AssignmentTrackingPass for at least `--optimize=debug`.
  827. // Set up target library information and add an analysis pass to supply it.
  828. std::unique_ptr<llvm::TargetLibraryInfoImpl> tlii(llvm::driver::createTLII(
  829. module_->getTargetTriple(), llvm::driver::VectorLibrary::NoLibrary));
  830. fam.registerPass([&] { return llvm::TargetLibraryAnalysis(*tlii); });
  831. builder.registerModuleAnalyses(mam);
  832. builder.registerCGSCCAnalyses(cgam);
  833. builder.registerFunctionAnalyses(fam);
  834. builder.registerLoopAnalyses(lam);
  835. builder.crossRegisterProxies(lam, fam, cgam, mam);
  836. llvm::ModulePassManager pass_manager = builder.buildPerModuleDefaultPipeline(
  837. GetLLVMOptimizationLevel(options_->opt_level));
  838. if (vlog_stream_) {
  839. CARBON_VLOG("*** Running pass pipeline: ");
  840. pass_manager.printPipeline(
  841. *vlog_stream_, [&pic](llvm::StringRef class_name) {
  842. auto pass_name = pic.getPassNameForClassName(class_name);
  843. return pass_name.empty() ? class_name : pass_name;
  844. });
  845. CARBON_VLOG(" ***\n");
  846. }
  847. LogCall("ModulePassManager::run", "optimize",
  848. [&] { pass_manager.run(*module_, mam); });
  849. if (vlog_stream_) {
  850. CARBON_VLOG("*** Optimized llvm::Module ***\n");
  851. module_->print(*vlog_stream_, /*AAW=*/nullptr,
  852. /*ShouldPreserveUseListOrder=*/false,
  853. /*IsForDebug=*/true);
  854. }
  855. }
  856. auto CompilationUnit::PostLower() -> void {
  857. CARBON_CHECK(module_, "Must call RunLower first");
  858. if (options_->dump_llvm_ir && IncludeInDumps()) {
  859. module_->print(*driver_env_->output_stream, /*AAW=*/nullptr,
  860. /*ShouldPreserveUseListOrder=*/true);
  861. }
  862. }
  863. auto CompilationUnit::RunCodeGen() -> void {
  864. CARBON_CHECK(module_, "Must call RunLower first");
  865. LogCall("CodeGen", "codegen", [&] { success_ = RunCodeGenHelper(); });
  866. }
  867. auto CompilationUnit::PostCompile() -> void {
  868. if (options_->dump_shared_values && IncludeInDumps()) {
  869. Yaml::Print(*driver_env_->output_stream,
  870. value_stores_.OutputYaml(input_filename_));
  871. }
  872. if (mem_usage_) {
  873. mem_usage_->Collect("value_stores_", value_stores_);
  874. Yaml::Print(*driver_env_->output_stream,
  875. mem_usage_->OutputYaml(input_filename_));
  876. }
  877. if (timings_) {
  878. Yaml::Print(*driver_env_->output_stream,
  879. timings_->OutputYaml(input_filename_));
  880. }
  881. // The diagnostics consumer must be flushed before compilation artifacts are
  882. // destructed, because diagnostics can refer to their state.
  883. consumer_->Flush();
  884. }
  885. auto CompilationUnit::RunCodeGenHelper() -> bool {
  886. CARBON_CHECK(module_, "Must call RunLower first");
  887. CARBON_CHECK(target_machine_, "Must call MakeTargetMachine first");
  888. CodeGen codegen(module_.get(), target_machine_.get(), consumer_);
  889. if (vlog_stream_) {
  890. CARBON_VLOG("*** Assembly ***\n");
  891. codegen.EmitAssembly(*vlog_stream_);
  892. }
  893. if (options_->output_filename == "-") {
  894. // TODO: The output file name, forcing object output, and requesting
  895. // textual assembly output are all somewhat linked flags. We should add
  896. // some validation that they are used correctly.
  897. if (options_->force_obj_output) {
  898. if (!codegen.EmitObject(*driver_env_->output_stream)) {
  899. return false;
  900. }
  901. } else {
  902. if (!codegen.EmitAssembly(*driver_env_->output_stream)) {
  903. return false;
  904. }
  905. }
  906. } else {
  907. llvm::SmallString<256> output_filename = options_->output_filename;
  908. if (output_filename.empty()) {
  909. if (!source_->is_regular_file()) {
  910. // Don't invent file names like `-.o` or `/dev/stdin.o`.
  911. // TODO: Consider rephrasing the diagnostic to use the file as the
  912. // `Emit` location.
  913. CARBON_DIAGNOSTIC(CompileInputNotRegularFile, Error,
  914. "output file name must be specified for input `{0}` "
  915. "that is not a regular file",
  916. std::string);
  917. driver_env_->emitter.Emit(CompileInputNotRegularFile, input_filename_);
  918. return false;
  919. }
  920. output_filename = input_filename_;
  921. llvm::sys::path::replace_extension(output_filename,
  922. options_->asm_output ? ".s" : ".o");
  923. }
  924. CARBON_VLOG("Writing output to: {0}\n", output_filename);
  925. std::error_code ec;
  926. llvm::raw_fd_ostream output_file(output_filename, ec,
  927. llvm::sys::fs::OF_None);
  928. if (ec) {
  929. // TODO: Consider rephrasing the diagnostic to use the file as the `Emit`
  930. // location.
  931. CARBON_DIAGNOSTIC(CompileOutputFileOpenError, Error,
  932. "could not open output file `{0}`: {1}", std::string,
  933. std::string);
  934. driver_env_->emitter.Emit(CompileOutputFileOpenError,
  935. output_filename.str().str(), ec.message());
  936. return false;
  937. }
  938. if (options_->asm_output) {
  939. if (!codegen.EmitAssembly(output_file)) {
  940. return false;
  941. }
  942. } else {
  943. if (!codegen.EmitObject(output_file)) {
  944. return false;
  945. }
  946. }
  947. }
  948. return true;
  949. }
  950. auto CompilationUnit::GetParseTreeAndSubtrees()
  951. -> const Parse::TreeAndSubtrees& {
  952. if (!parse_tree_and_subtrees_) {
  953. parse_tree_and_subtrees_ = Parse::TreeAndSubtrees(*tokens_, *parse_tree_);
  954. if (mem_usage_) {
  955. mem_usage_->Collect("parse_tree_and_subtrees_",
  956. *parse_tree_and_subtrees_);
  957. }
  958. }
  959. return *parse_tree_and_subtrees_;
  960. }
  961. auto CompilationUnit::LogCall(llvm::StringLiteral logging_label,
  962. llvm::StringLiteral timing_label,
  963. llvm::function_ref<auto()->void> fn) -> void {
  964. PrettyStackTraceFunction trace_file([&](llvm::raw_ostream& out) {
  965. out << "Filename: " << input_filename_ << "\n";
  966. });
  967. CARBON_VLOG("*** {0}: {1} ***\n", logging_label, input_filename_);
  968. Timings::ScopedTiming timing(timings_ ? &*timings_ : nullptr, timing_label);
  969. fn();
  970. CARBON_VLOG("*** {0} done ***\n", logging_label);
  971. }
  972. auto CompileSubcommand::Run(DriverEnv& driver_env) -> DriverResult {
  973. if (!ValidateOptions(driver_env.emitter)) {
  974. return {.success = false};
  975. }
  976. // Validate the target before passing it to Clang.
  977. std::string target_error;
  978. const llvm::Target* target = llvm::TargetRegistry::lookupTarget(
  979. llvm::Triple(options_.codegen_options.target), target_error);
  980. if (!target) {
  981. CARBON_DIAGNOSTIC(CompileTargetInvalid, Error, "invalid target: {0}",
  982. std::string);
  983. driver_env.emitter.Emit(CompileTargetInvalid, target_error);
  984. return {.success = false};
  985. }
  986. std::shared_ptr<clang::CompilerInvocation> clang_invocation;
  987. // Build a clang invocation. We do this regardless of whether we're running
  988. // check, because this is essentially performing further option validation,
  989. // and we generally validate all options even if we're not using them for the
  990. // selected phases of compilation. We also use Clang's target option handling
  991. // to configure our target, to ensure that we are using the same ABI for both
  992. // the C++ and Carbon parts of the compilation.
  993. // TODO: Share any arguments we specify here with the `carbon clang`
  994. // subcommand.
  995. {
  996. if (driver_env.fuzzing && !options_.clang_args.empty()) {
  997. // Parsing specific Clang arguments can reach deep into
  998. // external libraries that aren't fuzz clean.
  999. TestAndDiagnoseIfFuzzingExternalLibraries(driver_env, "compile");
  1000. return {.success = false};
  1001. }
  1002. // TODO: Move this into `BuildClangInvocation` when it can accept an
  1003. // optimization level.
  1004. llvm::SmallVector<llvm::StringRef> clang_args = {
  1005. // Propagate our optimization level to Clang as a default. This can be
  1006. // overridden by Clang arguments, but doing so will only have an effect
  1007. // if those arguments affect Clang's IR, not its pass pipeline.
  1008. GetClangOptimizationFlag(options_.opt_level),
  1009. };
  1010. clang_args.append(options_.clang_args);
  1011. clang_invocation = BuildClangInvocation(
  1012. driver_env.consumer, driver_env.fs, *driver_env.installation,
  1013. options_.codegen_options.target, clang_args);
  1014. if (!clang_invocation) {
  1015. return {.success = false};
  1016. }
  1017. // We will run our own pass pipeline over the IR in the `Optimize` phase, so
  1018. // disable Clang's pipeline to avoid optimizing C++ code twice.
  1019. clang_invocation->getCodeGenOpts().DisableLLVMPasses = true;
  1020. }
  1021. // Find the files comprising the prelude if we are importing it.
  1022. // TODO: Replace this with a search for library api files in a
  1023. // package-specific search path based on the library name.
  1024. llvm::SmallVector<std::string> prelude;
  1025. if (options_.prelude_import && !options_.custom_core &&
  1026. options_.phase >= CompileOptions::Phase::Check) {
  1027. if (auto find = driver_env.installation->ReadPreludeManifest(); find.ok()) {
  1028. prelude = std::move(*find);
  1029. } else {
  1030. // TODO: Change ReadPreludeManifest to produce diagnostics.
  1031. CARBON_DIAGNOSTIC(CompilePreludeManifestError, Error, "{0}", std::string);
  1032. driver_env.emitter.Emit(CompilePreludeManifestError,
  1033. PrintToString(find.error()));
  1034. return {.success = false};
  1035. }
  1036. }
  1037. // Prepare CompilationUnits before building scope exit handlers.
  1038. llvm::SmallVector<std::unique_ptr<CompilationUnit>> units;
  1039. int unit_index = -1;
  1040. int total_unit_count = prelude.size() + options_.input_filenames.size();
  1041. auto unit_builder = [&](llvm::StringRef filename) {
  1042. ++unit_index;
  1043. return std::make_unique<CompilationUnit>(
  1044. SemIR::CheckIRId(unit_index), total_unit_count, &driver_env, &options_,
  1045. &driver_env.consumer, filename, target);
  1046. };
  1047. llvm::append_range(units, llvm::map_range(prelude, unit_builder));
  1048. llvm::append_range(units,
  1049. llvm::map_range(options_.input_filenames, unit_builder));
  1050. CARBON_CHECK(units.size() == static_cast<size_t>(total_unit_count));
  1051. // Add the cache to all units. This must be done after all units are created.
  1052. MultiUnitCache cache(&options_, units);
  1053. for (auto& unit : units) {
  1054. unit->SetMultiUnitCache(&cache);
  1055. }
  1056. auto on_exit = llvm::scope_exit([&]() {
  1057. // Finish compilation units. This flushes their diagnostics in the order in
  1058. // which they were specified on the command line.
  1059. for (auto& unit : units) {
  1060. unit->PostCompile();
  1061. }
  1062. driver_env.consumer.Flush();
  1063. });
  1064. PrettyStackTraceFunction flush_on_crash([&](llvm::raw_ostream& out) {
  1065. // When crashing, flush diagnostics. If sorting diagnostics, they can be
  1066. // redirected to the crash stream; if streaming, the original stream is
  1067. // flushed.
  1068. // TODO: Eventually we'll want to limit the count.
  1069. if (options_.stream_errors) {
  1070. out << "Flushing diagnostics\n";
  1071. } else {
  1072. out << "Pending diagnostics:\n";
  1073. driver_env.consumer.set_stream(&out);
  1074. }
  1075. for (auto& unit : units) {
  1076. unit->FlushForStackTrace();
  1077. }
  1078. driver_env.consumer.Flush();
  1079. driver_env.consumer.set_stream(driver_env.error_stream);
  1080. });
  1081. // Returns a DriverResult object. Called whenever Compile returns.
  1082. auto make_result = [&]() {
  1083. DriverResult result = {.success = true};
  1084. for (const auto& unit : units) {
  1085. result.success &= unit->success();
  1086. result.per_file_success.push_back(
  1087. {unit->input_filename().str(), unit->success()});
  1088. }
  1089. return result;
  1090. };
  1091. // Lex.
  1092. for (auto& unit : units) {
  1093. unit->RunLex();
  1094. }
  1095. if (options_.phase == CompileOptions::Phase::Lex) {
  1096. return make_result();
  1097. }
  1098. cache.ApplyPerFileIncludeInDumps();
  1099. // Parse and check phases examine `has_source` because they want to proceed if
  1100. // lex failed, but not if source doesn't exist. Later steps are skipped if
  1101. // anything failed, so don't need this.
  1102. // Parse.
  1103. for (auto& unit : units) {
  1104. if (unit->has_source()) {
  1105. unit->RunParse();
  1106. }
  1107. }
  1108. if (options_.phase == CompileOptions::Phase::Parse) {
  1109. return make_result();
  1110. }
  1111. // Gather Check::Units.
  1112. llvm::SmallVector<Check::Unit> check_units;
  1113. check_units.reserve(units.size());
  1114. for (auto& unit : units) {
  1115. if (unit->has_source()) {
  1116. check_units.push_back(unit->GetCheckUnit());
  1117. }
  1118. }
  1119. // Execute the actual checking.
  1120. CARBON_VLOG_TO(driver_env.vlog_stream, "*** Check::CheckParseTrees ***\n");
  1121. Check::CheckParseTreesOptions options;
  1122. options.prelude_import = options_.prelude_import;
  1123. options.vlog_stream = driver_env.vlog_stream;
  1124. options.fuzzing = driver_env.fuzzing;
  1125. if (options.vlog_stream || options_.dump_sem_ir || options_.dump_cpp_ast ||
  1126. options_.dump_raw_sem_ir) {
  1127. options.include_in_dumps = &cache.include_in_dumps();
  1128. if (options_.dump_sem_ir) {
  1129. options.dump_stream = driver_env.output_stream;
  1130. }
  1131. if (options_.dump_cpp_ast) {
  1132. options.dump_cpp_ast_stream = driver_env.output_stream;
  1133. }
  1134. if (options.vlog_stream || options_.dump_sem_ir) {
  1135. options.dump_sem_ir_ranges = options_.dump_sem_ir_ranges;
  1136. }
  1137. if (options_.dump_raw_sem_ir) {
  1138. options.raw_dump_stream = driver_env.output_stream;
  1139. options.dump_raw_sem_ir_builtins = options_.builtin_sem_ir;
  1140. }
  1141. options.sem_ir_crash_dump = options_.sem_ir_crash_dump;
  1142. }
  1143. Check::CheckParseTrees(check_units, cache.tree_and_subtrees_getters(),
  1144. driver_env.fs, options, clang_invocation);
  1145. CARBON_VLOG_TO(driver_env.vlog_stream,
  1146. "*** Check::CheckParseTrees done ***\n");
  1147. for (auto& unit : units) {
  1148. if (unit->has_source()) {
  1149. unit->PostCheck();
  1150. }
  1151. }
  1152. if (options_.phase == CompileOptions::Phase::Check) {
  1153. return make_result();
  1154. }
  1155. // Unlike previous steps, errors block further progress.
  1156. if (llvm::any_of(units, [&](const auto& unit) { return !unit->success(); })) {
  1157. CARBON_VLOG_TO(driver_env.vlog_stream,
  1158. "*** Stopping before lowering due to errors ***\n");
  1159. return make_result();
  1160. }
  1161. // Lower and optimize.
  1162. for (const auto& unit : units) {
  1163. unit->RunLower();
  1164. if (options_.phase != CompileOptions::Phase::Lower) {
  1165. unit->RunOptimize(*clang_invocation);
  1166. }
  1167. unit->PostLower();
  1168. }
  1169. if (options_.phase == CompileOptions::Phase::Lower ||
  1170. options_.phase == CompileOptions::Phase::Optimize) {
  1171. return make_result();
  1172. }
  1173. CARBON_CHECK(options_.phase == CompileOptions::Phase::CodeGen,
  1174. "CodeGen should be the last stage");
  1175. bool output_last_input_only = options_.output_last_input_only;
  1176. if (!output_last_input_only && units.size() > 1 &&
  1177. !options_.output_filename.empty() && options_.output_filename != "-") {
  1178. // TODO: Command line structure should change to make this implicit (passing
  1179. // non-compiling inputs differently), and the warning should be removed.
  1180. CARBON_DIAGNOSTIC(
  1181. CompileMultipleInputsWithOutput, Warning,
  1182. "only outputting {0} to {1}, skipping output of {2} input "
  1183. "file{2:s}; pass `--output-last-input-only` to silence this warning",
  1184. std::string, std::string, Diagnostics::IntAsSelect);
  1185. driver_env.emitter.Emit(CompileMultipleInputsWithOutput,
  1186. units.back()->input_filename().str(),
  1187. options_.output_filename.str(), units.size() - 1);
  1188. output_last_input_only = true;
  1189. }
  1190. // Codegen.
  1191. if (output_last_input_only) {
  1192. units.back()->RunCodeGen();
  1193. } else {
  1194. for (const auto& unit : units) {
  1195. unit->RunCodeGen();
  1196. }
  1197. }
  1198. return make_result();
  1199. }
  1200. } // namespace Carbon