compile_subcommand.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912
  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 "common/vlog.h"
  6. #include "llvm/ADT/STLExtras.h"
  7. #include "llvm/ADT/ScopeExit.h"
  8. #include "toolchain/base/pretty_stack_trace_function.h"
  9. #include "toolchain/base/timings.h"
  10. #include "toolchain/check/check.h"
  11. #include "toolchain/codegen/codegen.h"
  12. #include "toolchain/diagnostics/diagnostic_emitter.h"
  13. #include "toolchain/diagnostics/sorting_diagnostic_consumer.h"
  14. #include "toolchain/lex/lex.h"
  15. #include "toolchain/lower/lower.h"
  16. #include "toolchain/parse/parse.h"
  17. #include "toolchain/parse/tree_and_subtrees.h"
  18. #include "toolchain/sem_ir/formatter.h"
  19. #include "toolchain/sem_ir/inst_namer.h"
  20. #include "toolchain/source/source_buffer.h"
  21. namespace Carbon {
  22. auto CompileOptions::Build(CommandLine::CommandBuilder& b) -> void {
  23. b.AddStringPositionalArg(
  24. {
  25. .name = "FILE",
  26. .help = R"""(
  27. The input Carbon source file to compile.
  28. )""",
  29. },
  30. [&](auto& arg_b) {
  31. arg_b.Required(true);
  32. arg_b.Append(&input_filenames);
  33. });
  34. b.AddOneOfOption(
  35. {
  36. .name = "phase",
  37. .help = R"""(
  38. Selects the compilation phase to run. These phases are always run in sequence,
  39. so every phase before the one selected will also be run. The default is to
  40. compile to machine code.
  41. )""",
  42. },
  43. [&](auto& arg_b) {
  44. arg_b.SetOneOf(
  45. {
  46. arg_b.OneOfValue("lex", Phase::Lex),
  47. arg_b.OneOfValue("parse", Phase::Parse),
  48. arg_b.OneOfValue("check", Phase::Check),
  49. arg_b.OneOfValue("lower", Phase::Lower),
  50. arg_b.OneOfValue("codegen", Phase::CodeGen).Default(true),
  51. },
  52. &phase);
  53. });
  54. // TODO: Rearrange the code setting this option and two related ones to
  55. // allow them to reference each other instead of hard-coding their names.
  56. b.AddStringOption(
  57. {
  58. .name = "output",
  59. .value_name = "FILE",
  60. .help = R"""(
  61. The output filename for codegen.
  62. When this is a file name, either textual assembly or a binary object will be
  63. written to it based on the flag `--asm-output`. The default is to write a binary
  64. object file.
  65. Passing `--output=-` will write the output to stdout. In that case, the flag
  66. `--asm-output` is ignored and the output defaults to textual assembly. Binary
  67. object output can be forced by enabling `--force-obj-output`.
  68. )""",
  69. },
  70. [&](auto& arg_b) { arg_b.Set(&output_filename); });
  71. // Include the common code generation options at this point to render it
  72. // after the more common options above, but before the more unusual options
  73. // below.
  74. codegen_options.Build(b);
  75. b.AddFlag(
  76. {
  77. .name = "asm-output",
  78. .help = R"""(
  79. Write textual assembly rather than a binary object file to the code generation
  80. output.
  81. This flag only applies when writing to a file. When writing to stdout, the
  82. default is textual assembly and this flag is ignored.
  83. )""",
  84. },
  85. [&](auto& arg_b) { arg_b.Set(&asm_output); });
  86. b.AddFlag(
  87. {
  88. .name = "force-obj-output",
  89. .help = R"""(
  90. Force binary object output, even with `--output=-`.
  91. When `--output=-` is set, the default is textual assembly; this forces printing
  92. of a binary object file instead. Ignored for other `--output` values.
  93. )""",
  94. },
  95. [&](auto& arg_b) { arg_b.Set(&force_obj_output); });
  96. b.AddFlag(
  97. {
  98. .name = "stream-errors",
  99. .help = R"""(
  100. Stream error messages to stderr as they are generated rather than sorting them
  101. and displaying them in source order.
  102. )""",
  103. },
  104. [&](auto& arg_b) { arg_b.Set(&stream_errors); });
  105. b.AddFlag(
  106. {
  107. .name = "dump-shared-values",
  108. .help = R"""(
  109. Dumps shared values. These aren't owned by any particular file or phase.
  110. )""",
  111. },
  112. [&](auto& arg_b) { arg_b.Set(&dump_shared_values); });
  113. b.AddFlag(
  114. {
  115. .name = "dump-tokens",
  116. .help = R"""(
  117. Dump the tokens to stdout when lexed.
  118. )""",
  119. },
  120. [&](auto& arg_b) { arg_b.Set(&dump_tokens); });
  121. b.AddFlag(
  122. {
  123. .name = "omit-file-boundary-tokens",
  124. .help = R"""(
  125. For `--dump-tokens`, omit file start and end boundary tokens.
  126. )""",
  127. },
  128. [&](auto& arg_b) { arg_b.Set(&omit_file_boundary_tokens); });
  129. b.AddFlag(
  130. {
  131. .name = "dump-parse-tree",
  132. .help = R"""(
  133. Dump the parse tree to stdout when parsed.
  134. )""",
  135. },
  136. [&](auto& arg_b) { arg_b.Set(&dump_parse_tree); });
  137. b.AddFlag(
  138. {
  139. .name = "preorder-parse-tree",
  140. .help = R"""(
  141. When dumping the parse tree, reorder it so that it is in preorder rather than
  142. postorder.
  143. )""",
  144. },
  145. [&](auto& arg_b) { arg_b.Set(&preorder_parse_tree); });
  146. b.AddFlag(
  147. {
  148. .name = "dump-raw-sem-ir",
  149. .help = R"""(
  150. Dump the raw JSON structure of SemIR to stdout when built.
  151. )""",
  152. },
  153. [&](auto& arg_b) { arg_b.Set(&dump_raw_sem_ir); });
  154. b.AddFlag(
  155. {
  156. .name = "dump-sem-ir",
  157. .help = R"""(
  158. Dump the SemIR to stdout when built.
  159. )""",
  160. },
  161. [&](auto& arg_b) { arg_b.Set(&dump_sem_ir); });
  162. b.AddFlag(
  163. {
  164. .name = "builtin-sem-ir",
  165. .help = R"""(
  166. Include the SemIR for builtins when dumping it.
  167. )""",
  168. },
  169. [&](auto& arg_b) { arg_b.Set(&builtin_sem_ir); });
  170. b.AddFlag(
  171. {
  172. .name = "dump-llvm-ir",
  173. .help = R"""(
  174. Dump the LLVM IR to stdout after lowering.
  175. )""",
  176. },
  177. [&](auto& arg_b) { arg_b.Set(&dump_llvm_ir); });
  178. b.AddFlag(
  179. {
  180. .name = "dump-asm",
  181. .help = R"""(
  182. Dump the generated assembly to stdout after codegen.
  183. )""",
  184. },
  185. [&](auto& arg_b) { arg_b.Set(&dump_asm); });
  186. b.AddFlag(
  187. {
  188. .name = "dump-mem-usage",
  189. .help = R"""(
  190. Dumps the amount of memory used.
  191. )""",
  192. },
  193. [&](auto& arg_b) { arg_b.Set(&dump_mem_usage); });
  194. b.AddFlag(
  195. {
  196. .name = "dump-timings",
  197. .help = R"""(
  198. Dumps the duration of each phase for each compilation unit.
  199. )""",
  200. },
  201. [&](auto& arg_b) { arg_b.Set(&dump_timings); });
  202. b.AddFlag(
  203. {
  204. .name = "prelude-import",
  205. .help = R"""(
  206. Whether to use the implicit prelude import. Enabled by default.
  207. )""",
  208. },
  209. [&](auto& arg_b) {
  210. arg_b.Default(true);
  211. arg_b.Set(&prelude_import);
  212. });
  213. b.AddStringOption(
  214. {
  215. .name = "exclude-dump-file-prefix",
  216. .value_name = "PREFIX",
  217. .help = R"""(
  218. Excludes files with the given prefix from dumps.
  219. )""",
  220. },
  221. [&](auto& arg_b) { arg_b.Set(&exclude_dump_file_prefix); });
  222. b.AddFlag(
  223. {
  224. .name = "debug-info",
  225. .help = R"""(
  226. Whether to emit DWARF debug information.
  227. )""",
  228. },
  229. [&](auto& arg_b) {
  230. arg_b.Default(true);
  231. arg_b.Set(&include_debug_info);
  232. });
  233. }
  234. static constexpr CommandLine::CommandInfo SubcommandInfo = {
  235. .name = "compile",
  236. .help = R"""(
  237. Compile Carbon source code.
  238. This subcommand runs the Carbon compiler over input source code, checking it for
  239. errors and producing the requested output.
  240. Error messages are written to the standard error stream.
  241. Different phases of the compiler can be selected to run, and intermediate state
  242. can be written to standard output as these phases progress.
  243. )""",
  244. };
  245. CompileSubcommand::CompileSubcommand() : DriverSubcommand(SubcommandInfo) {}
  246. // Returns a string for printing the phase in a diagnostic.
  247. static auto PhaseToString(CompileOptions::Phase phase) -> std::string {
  248. switch (phase) {
  249. case CompileOptions::Phase::Lex:
  250. return "lex";
  251. case CompileOptions::Phase::Parse:
  252. return "parse";
  253. case CompileOptions::Phase::Check:
  254. return "check";
  255. case CompileOptions::Phase::Lower:
  256. return "lower";
  257. case CompileOptions::Phase::CodeGen:
  258. return "codegen";
  259. }
  260. }
  261. auto CompileSubcommand::ValidateOptions(NoLocDiagnosticEmitter& emitter) const
  262. -> bool {
  263. CARBON_DIAGNOSTIC(
  264. CompilePhaseFlagConflict, Error,
  265. "requested dumping {0} but compile phase is limited to `{1}`",
  266. std::string, std::string);
  267. using Phase = CompileOptions::Phase;
  268. switch (options_.phase) {
  269. case Phase::Lex:
  270. if (options_.dump_parse_tree) {
  271. emitter.Emit(CompilePhaseFlagConflict, "parse tree",
  272. PhaseToString(options_.phase));
  273. return false;
  274. }
  275. [[fallthrough]];
  276. case Phase::Parse:
  277. if (options_.dump_sem_ir) {
  278. emitter.Emit(CompilePhaseFlagConflict, "SemIR",
  279. PhaseToString(options_.phase));
  280. return false;
  281. }
  282. [[fallthrough]];
  283. case Phase::Check:
  284. if (options_.dump_llvm_ir) {
  285. emitter.Emit(CompilePhaseFlagConflict, "LLVM IR",
  286. PhaseToString(options_.phase));
  287. return false;
  288. }
  289. [[fallthrough]];
  290. case Phase::Lower:
  291. case Phase::CodeGen:
  292. // Everything can be dumped in these phases.
  293. break;
  294. }
  295. return true;
  296. }
  297. namespace {
  298. // Ties together information for a file being compiled.
  299. class CompilationUnit {
  300. public:
  301. explicit CompilationUnit(DriverEnv& driver_env, const CompileOptions& options,
  302. DiagnosticConsumer* consumer,
  303. llvm::StringRef input_filename);
  304. // Loads source and lexes it. Returns true on success.
  305. auto RunLex() -> void;
  306. // Parses tokens. Returns true on success.
  307. auto RunParse() -> void;
  308. // Prepares per-IR lazy fetch functions which may come up in cross-IR
  309. // diagnostics.
  310. auto PreCheck() -> Parse::GetTreeAndSubtreesFn;
  311. // Returns information needed to check this unit.
  312. auto GetCheckUnit(
  313. SemIR::CheckIRId check_ir_id,
  314. llvm::ArrayRef<Parse::GetTreeAndSubtreesFn> all_trees_and_subtrees)
  315. -> Check::Unit;
  316. // Runs post-check logic. Returns true if checking succeeded for the IR.
  317. auto PostCheck() -> void;
  318. // Lower SemIR to LLVM IR.
  319. auto RunLower(std::optional<llvm::ArrayRef<Parse::GetTreeAndSubtreesFn>>
  320. all_trees_and_subtrees_for_debug_info) -> void;
  321. auto RunCodeGen() -> void;
  322. // Runs post-compile logic. This is always called, and called after all other
  323. // actions on the CompilationUnit.
  324. auto PostCompile() -> void;
  325. // Flushes diagnostics, specifically as part of generating stack trace
  326. // information.
  327. auto FlushForStackTrace() -> void { consumer_->Flush(); }
  328. auto input_filename() -> llvm::StringRef { return input_filename_; }
  329. auto success() -> bool { return success_; }
  330. auto has_source() -> bool { return source_.has_value(); }
  331. private:
  332. // Do codegen. Returns true on success.
  333. auto RunCodeGenHelper() -> bool;
  334. // The TreeAndSubtrees is mainly used for debugging and diagnostics, and has
  335. // significant overhead. Avoid constructing it when unused.
  336. auto GetParseTreeAndSubtrees() -> const Parse::TreeAndSubtrees&;
  337. // Wraps a call with log statements to indicate start and end. Typically logs
  338. // with the actual function name, but marks timings with the appropriate
  339. // phase.
  340. auto LogCall(llvm::StringLiteral logging_label,
  341. llvm::StringLiteral timing_label, llvm::function_ref<void()> fn)
  342. -> void;
  343. // Returns true if the current input file can be dumped.
  344. auto IncludeInDumps() const -> bool;
  345. // Returns true if the specified input file can be dumped.
  346. auto IncludeInDumps(llvm::StringRef filename) const -> bool;
  347. DriverEnv* driver_env_;
  348. SharedValueStores value_stores_;
  349. const CompileOptions& options_;
  350. // The input filename from the command line. For most diagnostics, we
  351. // typically use `source_->filename()`, which includes a `-` -> `<stdin>`
  352. // translation. However, logging and some diagnostics use the command line
  353. // argument.
  354. std::string input_filename_;
  355. // Copied from driver_ for CARBON_VLOG.
  356. llvm::raw_pwrite_stream* vlog_stream_;
  357. // Diagnostics are sent to consumer_, with optional sorting.
  358. std::optional<SortingDiagnosticConsumer> sorting_consumer_;
  359. DiagnosticConsumer* consumer_;
  360. bool success_ = true;
  361. // Tracks memory usage of the compile.
  362. std::optional<MemUsage> mem_usage_;
  363. // Tracks timings of the compile.
  364. std::optional<Timings> timings_;
  365. // These are initialized as steps are run.
  366. std::optional<SourceBuffer> source_;
  367. std::optional<Lex::TokenizedBuffer> tokens_;
  368. std::optional<Parse::Tree> parse_tree_;
  369. std::optional<Parse::TreeAndSubtrees> parse_tree_and_subtrees_;
  370. std::optional<std::function<const Parse::TreeAndSubtrees&()>>
  371. get_parse_tree_and_subtrees_;
  372. std::optional<Check::SemIRDiagnosticConverter> sem_ir_converter_;
  373. std::optional<SemIR::File> sem_ir_;
  374. std::unique_ptr<llvm::LLVMContext> llvm_context_;
  375. std::unique_ptr<llvm::Module> module_;
  376. };
  377. CompilationUnit::CompilationUnit(DriverEnv& driver_env,
  378. const CompileOptions& options,
  379. DiagnosticConsumer* consumer,
  380. llvm::StringRef input_filename)
  381. : driver_env_(&driver_env),
  382. options_(options),
  383. input_filename_(input_filename),
  384. vlog_stream_(driver_env_->vlog_stream) {
  385. if (vlog_stream_ != nullptr || options_.stream_errors) {
  386. consumer_ = consumer;
  387. } else {
  388. sorting_consumer_ = SortingDiagnosticConsumer(*consumer);
  389. consumer_ = &*sorting_consumer_;
  390. }
  391. if (options_.dump_mem_usage && IncludeInDumps()) {
  392. mem_usage_ = MemUsage();
  393. }
  394. if (options_.dump_timings && IncludeInDumps()) {
  395. timings_ = Timings();
  396. }
  397. }
  398. auto CompilationUnit::RunLex() -> void {
  399. CARBON_CHECK(!tokens_, "Called RunLex twice");
  400. LogCall("SourceBuffer::MakeFromFileOrStdin", "source", [&] {
  401. source_ = SourceBuffer::MakeFromFileOrStdin(*driver_env_->fs,
  402. input_filename_, *consumer_);
  403. });
  404. if (!source_) {
  405. success_ = false;
  406. return;
  407. }
  408. if (mem_usage_) {
  409. mem_usage_->Add("source_", source_->text().size(), source_->text().size());
  410. }
  411. CARBON_VLOG("*** SourceBuffer ***\n```\n{0}\n```\n", source_->text());
  412. LogCall("Lex::Lex", "lex",
  413. [&] { tokens_ = Lex::Lex(value_stores_, *source_, *consumer_); });
  414. if (options_.dump_tokens && IncludeInDumps()) {
  415. consumer_->Flush();
  416. tokens_->Print(*driver_env_->output_stream,
  417. options_.omit_file_boundary_tokens);
  418. }
  419. if (mem_usage_) {
  420. mem_usage_->Collect("tokens_", *tokens_);
  421. }
  422. CARBON_VLOG("*** Lex::TokenizedBuffer ***\n{0}", tokens_);
  423. if (tokens_->has_errors()) {
  424. success_ = false;
  425. }
  426. }
  427. auto CompilationUnit::RunParse() -> void {
  428. LogCall("Parse::Parse", "parse", [&] {
  429. parse_tree_ = Parse::Parse(*tokens_, *consumer_, vlog_stream_);
  430. });
  431. if (options_.dump_parse_tree && IncludeInDumps()) {
  432. consumer_->Flush();
  433. const auto& tree_and_subtrees = GetParseTreeAndSubtrees();
  434. if (options_.preorder_parse_tree) {
  435. tree_and_subtrees.PrintPreorder(*driver_env_->output_stream);
  436. } else {
  437. tree_and_subtrees.Print(*driver_env_->output_stream);
  438. }
  439. }
  440. if (mem_usage_) {
  441. mem_usage_->Collect("parse_tree_", *parse_tree_);
  442. }
  443. CARBON_VLOG("*** Parse::Tree ***\n{0}", parse_tree_);
  444. if (parse_tree_->has_errors()) {
  445. success_ = false;
  446. }
  447. }
  448. auto CompilationUnit::PreCheck() -> Parse::GetTreeAndSubtreesFn {
  449. CARBON_CHECK(parse_tree_, "Must call RunParse first");
  450. CARBON_CHECK(!get_parse_tree_and_subtrees_, "Called PreCheck twice");
  451. get_parse_tree_and_subtrees_ = [this]() -> const Parse::TreeAndSubtrees& {
  452. return this->GetParseTreeAndSubtrees();
  453. };
  454. return *get_parse_tree_and_subtrees_;
  455. }
  456. auto CompilationUnit::GetCheckUnit(
  457. SemIR::CheckIRId check_ir_id,
  458. llvm::ArrayRef<Parse::GetTreeAndSubtreesFn> all_trees_and_subtrees)
  459. -> Check::Unit {
  460. CARBON_CHECK(get_parse_tree_and_subtrees_, "Must call PreCheck first");
  461. CARBON_CHECK(!sem_ir_converter_, "Called GetCheckUnit twice");
  462. sem_ir_.emplace(&*parse_tree_, check_ir_id, parse_tree_->packaging_decl(),
  463. value_stores_, input_filename_);
  464. sem_ir_converter_.emplace(all_trees_and_subtrees, &*sem_ir_);
  465. return {.consumer = consumer_,
  466. .value_stores = &value_stores_,
  467. .timings = timings_ ? &*timings_ : nullptr,
  468. .get_parse_tree_and_subtrees = *get_parse_tree_and_subtrees_,
  469. .sem_ir = &*sem_ir_,
  470. .sem_ir_converter = &*sem_ir_converter_};
  471. }
  472. auto CompilationUnit::PostCheck() -> void {
  473. CARBON_CHECK(sem_ir_converter_, "Must call GetCheckUnit first");
  474. // We've finished all steps that can produce diagnostics. Emit the
  475. // diagnostics now, so that the developer sees them sooner and doesn't need
  476. // to wait for code generation.
  477. consumer_->Flush();
  478. if (mem_usage_) {
  479. mem_usage_->Collect("sem_ir_", *sem_ir_);
  480. }
  481. if (options_.dump_raw_sem_ir && IncludeInDumps()) {
  482. CARBON_VLOG("*** Raw SemIR::File ***\n{0}\n", *sem_ir_);
  483. sem_ir_->Print(*driver_env_->output_stream, options_.builtin_sem_ir);
  484. if (options_.dump_sem_ir) {
  485. *driver_env_->output_stream << "\n";
  486. }
  487. }
  488. bool print = options_.dump_sem_ir && IncludeInDumps();
  489. if (vlog_stream_ || print) {
  490. // Omit entities imported from files that we are not dumping.
  491. auto should_format_entity = [&](SemIR::InstId entity_inst_id) -> bool {
  492. // TODO: Reuse `GetCanonicalImportIRInst`. Currently it depends on
  493. // `Check::Context`, which we don't have access to here.
  494. const SemIR::File* file = &*sem_ir_;
  495. while (true) {
  496. auto loc_id = file->insts().GetLocId(entity_inst_id);
  497. if (!loc_id.is_import_ir_inst_id()) {
  498. return true;
  499. }
  500. auto import_ir_inst =
  501. file->import_ir_insts().Get(loc_id.import_ir_inst_id());
  502. const auto* import_file =
  503. file->import_irs().Get(import_ir_inst.ir_id).sem_ir;
  504. CARBON_CHECK(import_file);
  505. if (!IncludeInDumps(import_file->filename())) {
  506. return false;
  507. }
  508. file = import_file;
  509. entity_inst_id = import_ir_inst.inst_id;
  510. }
  511. };
  512. SemIR::Formatter formatter(&*sem_ir_, should_format_entity);
  513. if (vlog_stream_) {
  514. CARBON_VLOG("*** SemIR::File ***\n");
  515. formatter.Print(*vlog_stream_);
  516. }
  517. if (print) {
  518. formatter.Print(*driver_env_->output_stream);
  519. }
  520. }
  521. if (sem_ir_->has_errors()) {
  522. success_ = false;
  523. }
  524. }
  525. auto CompilationUnit::RunLower(
  526. std::optional<llvm::ArrayRef<Parse::GetTreeAndSubtreesFn>>
  527. all_trees_and_subtrees_for_debug_info) -> void {
  528. LogCall("Lower::LowerToLLVM", "lower", [&] {
  529. llvm_context_ = std::make_unique<llvm::LLVMContext>();
  530. // TODO: Consider disabling instruction naming by default if we're not
  531. // producing textual LLVM IR.
  532. SemIR::InstNamer inst_namer(&*sem_ir_);
  533. module_ = Lower::LowerToLLVM(
  534. *llvm_context_, all_trees_and_subtrees_for_debug_info, input_filename_,
  535. *sem_ir_, &inst_namer, vlog_stream_);
  536. });
  537. if (vlog_stream_) {
  538. CARBON_VLOG("*** llvm::Module ***\n");
  539. module_->print(*vlog_stream_, /*AAW=*/nullptr,
  540. /*ShouldPreserveUseListOrder=*/false,
  541. /*IsForDebug=*/true);
  542. }
  543. if (options_.dump_llvm_ir && IncludeInDumps()) {
  544. module_->print(*driver_env_->output_stream, /*AAW=*/nullptr,
  545. /*ShouldPreserveUseListOrder=*/true);
  546. }
  547. }
  548. auto CompilationUnit::RunCodeGen() -> void {
  549. CARBON_CHECK(module_, "Must call RunLower first");
  550. LogCall("CodeGen", "codegen", [&] { success_ = RunCodeGenHelper(); });
  551. }
  552. auto CompilationUnit::PostCompile() -> void {
  553. if (options_.dump_shared_values && IncludeInDumps()) {
  554. Yaml::Print(*driver_env_->output_stream,
  555. value_stores_.OutputYaml(input_filename_));
  556. }
  557. if (mem_usage_) {
  558. mem_usage_->Collect("value_stores_", value_stores_);
  559. Yaml::Print(*driver_env_->output_stream,
  560. mem_usage_->OutputYaml(input_filename_));
  561. }
  562. if (timings_) {
  563. Yaml::Print(*driver_env_->output_stream,
  564. timings_->OutputYaml(input_filename_));
  565. }
  566. // The diagnostics consumer must be flushed before compilation artifacts are
  567. // destructed, because diagnostics can refer to their state.
  568. consumer_->Flush();
  569. }
  570. auto CompilationUnit::RunCodeGenHelper() -> bool {
  571. std::optional<CodeGen> codegen = CodeGen::Make(
  572. *module_, options_.codegen_options.target, *driver_env_->error_stream);
  573. if (!codegen) {
  574. return false;
  575. }
  576. if (vlog_stream_) {
  577. CARBON_VLOG("*** Assembly ***\n");
  578. codegen->EmitAssembly(*vlog_stream_);
  579. }
  580. if (options_.output_filename == "-") {
  581. // TODO: The output file name, forcing object output, and requesting
  582. // textual assembly output are all somewhat linked flags. We should add
  583. // some validation that they are used correctly.
  584. if (options_.force_obj_output) {
  585. if (!codegen->EmitObject(*driver_env_->output_stream)) {
  586. return false;
  587. }
  588. } else {
  589. if (!codegen->EmitAssembly(*driver_env_->output_stream)) {
  590. return false;
  591. }
  592. }
  593. } else {
  594. llvm::SmallString<256> output_filename = options_.output_filename;
  595. if (output_filename.empty()) {
  596. if (!source_->is_regular_file()) {
  597. // Don't invent file names like `-.o` or `/dev/stdin.o`.
  598. // TODO: Consider rephrasing the diagnostic to use the file as the
  599. // `Emit` location.
  600. CARBON_DIAGNOSTIC(CompileInputNotRegularFile, Error,
  601. "output file name must be specified for input `{0}` "
  602. "that is not a regular file",
  603. std::string);
  604. driver_env_->emitter.Emit(CompileInputNotRegularFile, input_filename_);
  605. return false;
  606. }
  607. output_filename = input_filename_;
  608. llvm::sys::path::replace_extension(output_filename,
  609. options_.asm_output ? ".s" : ".o");
  610. } else {
  611. // TODO: Handle the case where multiple input files were specified
  612. // along with an output file name. That should either be an error or
  613. // should produce a single LLVM IR module containing all inputs.
  614. // Currently each unit overwrites the output from the previous one in
  615. // this case.
  616. }
  617. CARBON_VLOG("Writing output to: {0}\n", output_filename);
  618. std::error_code ec;
  619. llvm::raw_fd_ostream output_file(output_filename, ec,
  620. llvm::sys::fs::OF_None);
  621. if (ec) {
  622. // TODO: Consider rephrasing the diagnostic to use the file as the `Emit`
  623. // location.
  624. CARBON_DIAGNOSTIC(CompileOutputFileOpenError, Error,
  625. "could not open output file `{0}`: {1}", std::string,
  626. std::string);
  627. driver_env_->emitter.Emit(CompileOutputFileOpenError,
  628. output_filename.str().str(), ec.message());
  629. return false;
  630. }
  631. if (options_.asm_output) {
  632. if (!codegen->EmitAssembly(output_file)) {
  633. return false;
  634. }
  635. } else {
  636. if (!codegen->EmitObject(output_file)) {
  637. return false;
  638. }
  639. }
  640. }
  641. return true;
  642. }
  643. auto CompilationUnit::GetParseTreeAndSubtrees()
  644. -> const Parse::TreeAndSubtrees& {
  645. if (!parse_tree_and_subtrees_) {
  646. parse_tree_and_subtrees_ = Parse::TreeAndSubtrees(*tokens_, *parse_tree_);
  647. if (mem_usage_) {
  648. mem_usage_->Collect("parse_tree_and_subtrees_",
  649. *parse_tree_and_subtrees_);
  650. }
  651. }
  652. return *parse_tree_and_subtrees_;
  653. }
  654. auto CompilationUnit::LogCall(llvm::StringLiteral logging_label,
  655. llvm::StringLiteral timing_label,
  656. llvm::function_ref<void()> fn) -> void {
  657. CARBON_VLOG("*** {0}: {1} ***\n", logging_label, input_filename_);
  658. Timings::ScopedTiming timing(timings_ ? &*timings_ : nullptr, timing_label);
  659. fn();
  660. CARBON_VLOG("*** {0} done ***\n", logging_label);
  661. }
  662. auto CompilationUnit::IncludeInDumps() const -> bool {
  663. return IncludeInDumps(input_filename_);
  664. }
  665. auto CompilationUnit::IncludeInDumps(llvm::StringRef filename) const -> bool {
  666. return options_.exclude_dump_file_prefix.empty() ||
  667. !filename.starts_with(options_.exclude_dump_file_prefix);
  668. }
  669. } // namespace
  670. auto CompileSubcommand::Run(DriverEnv& driver_env) -> DriverResult {
  671. if (!ValidateOptions(driver_env.emitter)) {
  672. return {.success = false};
  673. }
  674. // Find the files comprising the prelude if we are importing it.
  675. // TODO: Replace this with a search for library api files in a
  676. // package-specific search path based on the library name.
  677. llvm::SmallVector<std::string> prelude;
  678. if (options_.prelude_import &&
  679. options_.phase >= CompileOptions::Phase::Check) {
  680. if (auto find = driver_env.installation->ReadPreludeManifest(); find.ok()) {
  681. prelude = std::move(*find);
  682. } else {
  683. // TODO: Change ReadPreludeManifest to produce diagnostics.
  684. CARBON_DIAGNOSTIC(CompilePreludeManifestError, Error, "{0}", std::string);
  685. driver_env.emitter.Emit(CompilePreludeManifestError,
  686. PrintToString(find.error()));
  687. return {.success = false};
  688. }
  689. }
  690. // Prepare CompilationUnits before building scope exit handlers.
  691. llvm::SmallVector<std::unique_ptr<CompilationUnit>> units;
  692. units.reserve(prelude.size() + options_.input_filenames.size());
  693. // Add the prelude files.
  694. for (const auto& input_filename : prelude) {
  695. units.push_back(std::make_unique<CompilationUnit>(
  696. driver_env, options_, &driver_env.consumer, input_filename));
  697. }
  698. // Add the input source files.
  699. for (const auto& input_filename : options_.input_filenames) {
  700. units.push_back(std::make_unique<CompilationUnit>(
  701. driver_env, options_, &driver_env.consumer, input_filename));
  702. }
  703. auto on_exit = llvm::make_scope_exit([&]() {
  704. // Finish compilation units. This flushes their diagnostics in the order in
  705. // which they were specified on the command line.
  706. for (auto& unit : units) {
  707. unit->PostCompile();
  708. }
  709. driver_env.consumer.Flush();
  710. });
  711. PrettyStackTraceFunction flush_on_crash([&](llvm::raw_ostream& out) {
  712. // When crashing, flush diagnostics. If sorting diagnostics, they can be
  713. // redirected to the crash stream; if streaming, the original stream is
  714. // flushed.
  715. // TODO: Eventually we'll want to limit the count.
  716. if (options_.stream_errors) {
  717. out << "Flushing diagnostics\n";
  718. } else {
  719. out << "Pending diagnostics:\n";
  720. driver_env.consumer.set_stream(&out);
  721. }
  722. for (auto& unit : units) {
  723. unit->FlushForStackTrace();
  724. }
  725. driver_env.consumer.Flush();
  726. driver_env.consumer.set_stream(driver_env.error_stream);
  727. });
  728. // Returns a DriverResult object. Called whenever Compile returns.
  729. auto make_result = [&]() {
  730. DriverResult result = {.success = true};
  731. for (const auto& unit : units) {
  732. result.success &= unit->success();
  733. result.per_file_success.push_back(
  734. {unit->input_filename().str(), unit->success()});
  735. }
  736. return result;
  737. };
  738. // Lex.
  739. for (auto& unit : units) {
  740. unit->RunLex();
  741. }
  742. if (options_.phase == CompileOptions::Phase::Lex) {
  743. return make_result();
  744. }
  745. // Parse and check phases examine `has_source` because they want to proceed if
  746. // lex failed, but not if source doesn't exist. Later steps are skipped if
  747. // anything failed, so don't need this.
  748. // Parse.
  749. for (auto& unit : units) {
  750. if (unit->has_source()) {
  751. unit->RunParse();
  752. }
  753. }
  754. if (options_.phase == CompileOptions::Phase::Parse) {
  755. return make_result();
  756. }
  757. // Pre-check assigns IR IDs and constructs node converters.
  758. llvm::SmallVector<Parse::GetTreeAndSubtreesFn> all_trees_and_subtrees;
  759. // This size may not match due to units that are missing source, but that's an
  760. // error case and not worth extra work.
  761. all_trees_and_subtrees.reserve(units.size());
  762. for (auto& unit : units) {
  763. if (unit->has_source()) {
  764. all_trees_and_subtrees.push_back(unit->PreCheck());
  765. }
  766. }
  767. // Gather Check::Units.
  768. llvm::SmallVector<Check::Unit> check_units;
  769. check_units.reserve(all_trees_and_subtrees.size());
  770. for (auto& unit : units) {
  771. if (unit->has_source()) {
  772. SemIR::CheckIRId check_ir_id(check_units.size());
  773. check_units.push_back(
  774. unit->GetCheckUnit(check_ir_id, all_trees_and_subtrees));
  775. }
  776. }
  777. // Execute the actual checking.
  778. CARBON_VLOG_TO(driver_env.vlog_stream, "*** Check::CheckParseTrees ***\n");
  779. Check::CheckParseTrees(check_units, options_.prelude_import, driver_env.fs,
  780. driver_env.vlog_stream, driver_env.fuzzing);
  781. CARBON_VLOG_TO(driver_env.vlog_stream,
  782. "*** Check::CheckParseTrees done ***\n");
  783. for (auto& unit : units) {
  784. if (unit->has_source()) {
  785. unit->PostCheck();
  786. }
  787. }
  788. if (options_.phase == CompileOptions::Phase::Check) {
  789. return make_result();
  790. }
  791. // Unlike previous steps, errors block further progress.
  792. if (llvm::any_of(units, [&](const auto& unit) { return !unit->success(); })) {
  793. CARBON_VLOG_TO(driver_env.vlog_stream,
  794. "*** Stopping before lowering due to errors ***\n");
  795. return make_result();
  796. }
  797. // Lower.
  798. std::optional<llvm::ArrayRef<Parse::GetTreeAndSubtreesFn>>
  799. all_trees_and_subtrees_for_debug_info;
  800. if (options_.include_debug_info) {
  801. all_trees_and_subtrees_for_debug_info = all_trees_and_subtrees;
  802. }
  803. for (const auto& unit : units) {
  804. unit->RunLower(all_trees_and_subtrees_for_debug_info);
  805. }
  806. if (options_.phase == CompileOptions::Phase::Lower) {
  807. return make_result();
  808. }
  809. CARBON_CHECK(options_.phase == CompileOptions::Phase::CodeGen,
  810. "CodeGen should be the last stage");
  811. // Codegen.
  812. for (auto& unit : units) {
  813. unit->RunCodeGen();
  814. }
  815. return make_result();
  816. }
  817. } // namespace Carbon