driver.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720
  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/driver.h"
  5. #include <memory>
  6. #include <optional>
  7. #include "common/command_line.h"
  8. #include "common/vlog.h"
  9. #include "llvm/ADT/ArrayRef.h"
  10. #include "llvm/ADT/ScopeExit.h"
  11. #include "llvm/ADT/StringExtras.h"
  12. #include "llvm/ADT/StringRef.h"
  13. #include "llvm/IR/LLVMContext.h"
  14. #include "llvm/Support/Path.h"
  15. #include "llvm/TargetParser/Host.h"
  16. #include "toolchain/base/value_store.h"
  17. #include "toolchain/check/check.h"
  18. #include "toolchain/codegen/codegen.h"
  19. #include "toolchain/diagnostics/diagnostic_emitter.h"
  20. #include "toolchain/diagnostics/sorting_diagnostic_consumer.h"
  21. #include "toolchain/lex/lex.h"
  22. #include "toolchain/lower/lower.h"
  23. #include "toolchain/parse/parse.h"
  24. #include "toolchain/sem_ir/formatter.h"
  25. #include "toolchain/source/source_buffer.h"
  26. namespace Carbon {
  27. struct Driver::CompileOptions {
  28. static constexpr CommandLine::CommandInfo Info = {
  29. .name = "compile",
  30. .help = R"""(
  31. Compile Carbon source code.
  32. This subcommand runs the Carbon compiler over input source code, checking it for
  33. errors and producing the requested output.
  34. Error messages are written to the standard error stream.
  35. Different phases of the compiler can be selected to run, and intermediate state
  36. can be written to standard output as these phases progress.
  37. )""",
  38. };
  39. enum class Phase : int8_t {
  40. Lex,
  41. Parse,
  42. Check,
  43. Lower,
  44. CodeGen,
  45. };
  46. friend auto operator<<(llvm::raw_ostream& out, Phase phase)
  47. -> llvm::raw_ostream& {
  48. switch (phase) {
  49. case Phase::Lex:
  50. out << "lex";
  51. break;
  52. case Phase::Parse:
  53. out << "parse";
  54. break;
  55. case Phase::Check:
  56. out << "check";
  57. break;
  58. case Phase::Lower:
  59. out << "lower";
  60. break;
  61. case Phase::CodeGen:
  62. out << "codegen";
  63. break;
  64. }
  65. return out;
  66. }
  67. void Build(CommandLine::CommandBuilder& b) {
  68. b.AddStringPositionalArg(
  69. {
  70. .name = "FILE",
  71. .help = R"""(
  72. The input Carbon source file to compile.
  73. )""",
  74. },
  75. [&](auto& arg_b) {
  76. arg_b.Required(true);
  77. arg_b.Append(&input_file_names);
  78. });
  79. b.AddOneOfOption(
  80. {
  81. .name = "phase",
  82. .help = R"""(
  83. Selects the compilation phase to run. These phases are always run in sequence,
  84. so every phase before the one selected will also be run. The default is to
  85. compile to machine code.
  86. )""",
  87. },
  88. [&](auto& arg_b) {
  89. arg_b.SetOneOf(
  90. {
  91. arg_b.OneOfValue("lex", Phase::Lex),
  92. arg_b.OneOfValue("parse", Phase::Parse),
  93. arg_b.OneOfValue("check", Phase::Check),
  94. arg_b.OneOfValue("lower", Phase::Lower),
  95. arg_b.OneOfValue("codegen", Phase::CodeGen).Default(true),
  96. },
  97. &phase);
  98. });
  99. // TODO: Rearrange the code setting this option and two related ones to
  100. // allow them to reference each other instead of hard-coding their names.
  101. b.AddStringOption(
  102. {
  103. .name = "output",
  104. .value_name = "FILE",
  105. .help = R"""(
  106. The output filename for codegen.
  107. When this is a file name, either textual assembly or a binary object will be
  108. written to it based on the flag `--asm-output`. The default is to write a binary
  109. object file.
  110. Passing `--output=-` will write the output to stdout. In that case, the flag
  111. `--asm-output` is ignored and the output defaults to textual assembly. Binary
  112. object output can be forced by enabling `--force-obj-output`.
  113. )""",
  114. },
  115. [&](auto& arg_b) { arg_b.Set(&output_file_name); });
  116. b.AddStringOption(
  117. {
  118. .name = "target",
  119. .help = R"""(
  120. Select a target platform. Uses the LLVM target syntax. Also known as a "triple"
  121. for historical reasons.
  122. This corresponds to the `target` flag to Clang and accepts the same strings
  123. documented there:
  124. https://clang.llvm.org/docs/CrossCompilation.html#target-triple
  125. )""",
  126. },
  127. [&](auto& arg_b) {
  128. arg_b.Default(host);
  129. arg_b.Set(&target);
  130. });
  131. b.AddFlag(
  132. {
  133. .name = "asm-output",
  134. .help = R"""(
  135. Write textual assembly rather than a binary object file to the code generation
  136. output.
  137. This flag only applies when writing to a file. When writing to stdout, the
  138. default is textual assembly and this flag is ignored.
  139. )""",
  140. },
  141. [&](auto& arg_b) { arg_b.Set(&asm_output); });
  142. b.AddFlag(
  143. {
  144. .name = "force-obj-output",
  145. .help = R"""(
  146. Force binary object output, even with `--output=-`.
  147. When `--output=-` is set, the default is textual assembly; this forces printing
  148. of a binary object file instead. Ignored for other `--output` values.
  149. )""",
  150. },
  151. [&](auto& arg_b) { arg_b.Set(&force_obj_output); });
  152. b.AddFlag(
  153. {
  154. .name = "stream-errors",
  155. .help = R"""(
  156. Stream error messages to stderr as they are generated rather than sorting them
  157. and displaying them in source order.
  158. )""",
  159. },
  160. [&](auto& arg_b) { arg_b.Set(&stream_errors); });
  161. b.AddFlag(
  162. {
  163. .name = "dump-shared-values",
  164. .help = R"""(
  165. Dumps shared values. These aren't owned by any particular file or phase.
  166. )""",
  167. },
  168. [&](auto& arg_b) { arg_b.Set(&dump_shared_values); });
  169. b.AddFlag(
  170. {
  171. .name = "dump-tokens",
  172. .help = R"""(
  173. Dump the tokens to stdout when lexed.
  174. )""",
  175. },
  176. [&](auto& arg_b) { arg_b.Set(&dump_tokens); });
  177. b.AddFlag(
  178. {
  179. .name = "dump-parse-tree",
  180. .help = R"""(
  181. Dump the parse tree to stdout when parsed.
  182. )""",
  183. },
  184. [&](auto& arg_b) { arg_b.Set(&dump_parse_tree); });
  185. b.AddFlag(
  186. {
  187. .name = "preorder-parse-tree",
  188. .help = R"""(
  189. When dumping the parse tree, reorder it so that it is in preorder rather than
  190. postorder.
  191. )""",
  192. },
  193. [&](auto& arg_b) { arg_b.Set(&preorder_parse_tree); });
  194. b.AddFlag(
  195. {
  196. .name = "dump-raw-sem-ir",
  197. .help = R"""(
  198. Dump the raw JSON structure of SemIR to stdout when built.
  199. )""",
  200. },
  201. [&](auto& arg_b) { arg_b.Set(&dump_raw_sem_ir); });
  202. b.AddFlag(
  203. {
  204. .name = "dump-sem-ir",
  205. .help = R"""(
  206. Dump the SemIR to stdout when built.
  207. )""",
  208. },
  209. [&](auto& arg_b) { arg_b.Set(&dump_sem_ir); });
  210. b.AddFlag(
  211. {
  212. .name = "builtin-sem-ir",
  213. .help = R"""(
  214. Include the SemIR for builtins when dumping it.
  215. )""",
  216. },
  217. [&](auto& arg_b) { arg_b.Set(&builtin_sem_ir); });
  218. b.AddFlag(
  219. {
  220. .name = "dump-llvm-ir",
  221. .help = R"""(
  222. Dump the LLVM IR to stdout after lowering.
  223. )""",
  224. },
  225. [&](auto& arg_b) { arg_b.Set(&dump_llvm_ir); });
  226. b.AddFlag(
  227. {
  228. .name = "dump-asm",
  229. .help = R"""(
  230. Dump the generated assembly to stdout after codegen.
  231. )""",
  232. },
  233. [&](auto& arg_b) { arg_b.Set(&dump_asm); });
  234. }
  235. Phase phase;
  236. std::string host = llvm::sys::getDefaultTargetTriple();
  237. llvm::StringRef target;
  238. llvm::StringRef output_file_name;
  239. llvm::SmallVector<llvm::StringRef> input_file_names;
  240. bool asm_output = false;
  241. bool force_obj_output = false;
  242. bool dump_shared_values = false;
  243. bool dump_tokens = false;
  244. bool dump_parse_tree = false;
  245. bool dump_raw_sem_ir = false;
  246. bool dump_sem_ir = false;
  247. bool dump_llvm_ir = false;
  248. bool dump_asm = false;
  249. bool stream_errors = false;
  250. bool preorder_parse_tree = false;
  251. bool builtin_sem_ir = false;
  252. };
  253. struct Driver::Options {
  254. static constexpr CommandLine::CommandInfo Info = {
  255. .name = "carbon",
  256. // TODO: Set up more detailed version information and use that here.
  257. .version = R"""(
  258. Carbon Language toolchain -- version 0.0.0
  259. )""",
  260. .help = R"""(
  261. This is the unified Carbon Language toolchain driver. Its subcommands provide
  262. all of the core behavior of the toolchain, including compilation, linking, and
  263. developer tools. Each of these has its own subcommand, and you can pass a
  264. specific subcommand to the `help` subcommand to get details about its usage.
  265. )""",
  266. .help_epilogue = R"""(
  267. For questions, issues, or bug reports, please use our GitHub project:
  268. https://github.com/carbon-language/carbon-lang
  269. )""",
  270. };
  271. enum class Subcommand : int8_t {
  272. Compile,
  273. };
  274. void Build(CommandLine::CommandBuilder& b) {
  275. b.AddFlag(
  276. {
  277. .name = "verbose",
  278. .short_name = "v",
  279. .help = "Enable verbose logging to the stderr stream.",
  280. },
  281. [&](CommandLine::FlagBuilder& arg_b) { arg_b.Set(&verbose); });
  282. b.AddSubcommand(CompileOptions::Info,
  283. [&](CommandLine::CommandBuilder& sub_b) {
  284. compile_options.Build(sub_b);
  285. sub_b.Do([&] { subcommand = Subcommand::Compile; });
  286. });
  287. b.RequiresSubcommand();
  288. }
  289. bool verbose;
  290. Subcommand subcommand;
  291. CompileOptions compile_options;
  292. };
  293. auto Driver::ParseArgs(llvm::ArrayRef<llvm::StringRef> args, Options& options)
  294. -> CommandLine::ParseResult {
  295. return CommandLine::Parse(
  296. args, output_stream_, error_stream_, Options::Info,
  297. [&](CommandLine::CommandBuilder& b) { options.Build(b); });
  298. }
  299. auto Driver::RunCommand(llvm::ArrayRef<llvm::StringRef> args) -> bool {
  300. Options options;
  301. CommandLine::ParseResult result = ParseArgs(args, options);
  302. if (result == CommandLine::ParseResult::Error) {
  303. return false;
  304. } else if (result == CommandLine::ParseResult::MetaSuccess) {
  305. return true;
  306. }
  307. if (options.verbose) {
  308. // Note this implies streamed output in order to interleave.
  309. vlog_stream_ = &error_stream_;
  310. }
  311. switch (options.subcommand) {
  312. case Options::Subcommand::Compile:
  313. return Compile(options.compile_options);
  314. }
  315. llvm_unreachable("All subcommands handled!");
  316. }
  317. auto Driver::ValidateCompileOptions(const CompileOptions& options) const
  318. -> bool {
  319. using Phase = CompileOptions::Phase;
  320. switch (options.phase) {
  321. case Phase::Lex:
  322. if (options.dump_parse_tree) {
  323. error_stream_ << "ERROR: Requested dumping the parse tree but compile "
  324. "phase is limited to '"
  325. << options.phase << "'.\n";
  326. return false;
  327. }
  328. [[clang::fallthrough]];
  329. case Phase::Parse:
  330. if (options.dump_sem_ir) {
  331. error_stream_ << "ERROR: Requested dumping the SemIR but compile phase "
  332. "is limited to '"
  333. << options.phase << "'.\n";
  334. return false;
  335. }
  336. [[clang::fallthrough]];
  337. case Phase::Check:
  338. if (options.dump_llvm_ir) {
  339. error_stream_ << "ERROR: Requested dumping the LLVM IR but compile "
  340. "phase is limited to '"
  341. << options.phase << "'.\n";
  342. return false;
  343. }
  344. [[clang::fallthrough]];
  345. case Phase::Lower:
  346. case Phase::CodeGen:
  347. // Everything can be dumped in these phases.
  348. break;
  349. }
  350. return true;
  351. }
  352. // Ties together information for a file being compiled.
  353. class Driver::CompilationUnit {
  354. public:
  355. explicit CompilationUnit(Driver* driver, const CompileOptions& options,
  356. llvm::StringRef input_file_name)
  357. : driver_(driver),
  358. options_(options),
  359. input_file_name_(input_file_name),
  360. vlog_stream_(driver_->vlog_stream_),
  361. stream_consumer_(driver_->error_stream_) {
  362. if (vlog_stream_ != nullptr || options_.stream_errors) {
  363. consumer_ = &stream_consumer_;
  364. } else {
  365. sorting_consumer_ = SortingDiagnosticConsumer(stream_consumer_);
  366. consumer_ = &*sorting_consumer_;
  367. }
  368. }
  369. // Loads source and lexes it. Returns true on success.
  370. auto RunLex() -> bool {
  371. LogCall("SourceBuffer::CreateFromFile", [&] {
  372. if (input_file_name_ == "-") {
  373. source_ = SourceBuffer::CreateFromStdin(*consumer_);
  374. } else {
  375. source_ = SourceBuffer::CreateFromFile(driver_->fs_, input_file_name_,
  376. *consumer_);
  377. }
  378. });
  379. if (!source_) {
  380. return false;
  381. }
  382. CARBON_VLOG() << "*** SourceBuffer ***\n```\n"
  383. << source_->text() << "\n```\n";
  384. LogCall("Lex::Lex",
  385. [&] { tokens_ = Lex::Lex(value_stores_, *source_, *consumer_); });
  386. if (options_.dump_tokens) {
  387. consumer_->Flush();
  388. driver_->output_stream_ << tokens_;
  389. }
  390. CARBON_VLOG() << "*** Lex::TokenizedBuffer ***\n" << tokens_;
  391. return !tokens_->has_errors();
  392. }
  393. // Parses tokens. Returns true on success.
  394. auto RunParse() -> bool {
  395. CARBON_CHECK(tokens_);
  396. LogCall("Parse::Parse", [&] {
  397. parse_tree_ = Parse::Parse(*tokens_, *consumer_, vlog_stream_);
  398. });
  399. if (options_.dump_parse_tree) {
  400. consumer_->Flush();
  401. parse_tree_->Print(driver_->output_stream_, options_.preorder_parse_tree);
  402. }
  403. CARBON_VLOG() << "*** Parse::Tree ***\n" << parse_tree_;
  404. return !parse_tree_->has_errors();
  405. }
  406. // Returns information needed to check this unit.
  407. auto GetCheckUnit() -> Check::Unit {
  408. CARBON_CHECK(parse_tree_);
  409. return {.value_stores = &value_stores_,
  410. .tokens = &*tokens_,
  411. .parse_tree = &*parse_tree_,
  412. .consumer = consumer_,
  413. .sem_ir = &sem_ir_};
  414. }
  415. // Runs post-check logic. Returns true if checking succeeded for the IR.
  416. auto PostCheck() -> bool {
  417. CARBON_CHECK(sem_ir_);
  418. // We've finished all steps that can produce diagnostics. Emit the
  419. // diagnostics now, so that the developer sees them sooner and doesn't need
  420. // to wait for code generation.
  421. consumer_->Flush();
  422. CARBON_VLOG() << "*** Raw SemIR::File ***\n" << *sem_ir_ << "\n";
  423. if (options_.dump_raw_sem_ir) {
  424. sem_ir_->Print(driver_->output_stream_, options_.builtin_sem_ir);
  425. if (options_.dump_sem_ir) {
  426. driver_->output_stream_ << "\n";
  427. }
  428. }
  429. if (vlog_stream_) {
  430. CARBON_VLOG() << "*** SemIR::File ***\n";
  431. SemIR::FormatFile(*tokens_, *parse_tree_, *sem_ir_, *vlog_stream_);
  432. }
  433. if (options_.dump_sem_ir) {
  434. SemIR::FormatFile(*tokens_, *parse_tree_, *sem_ir_,
  435. driver_->output_stream_);
  436. }
  437. return !sem_ir_->has_errors();
  438. }
  439. // Lower SemIR to LLVM IR.
  440. auto RunLower() -> void {
  441. CARBON_CHECK(sem_ir_);
  442. LogCall("Lower::LowerToLLVM", [&] {
  443. llvm_context_ = std::make_unique<llvm::LLVMContext>();
  444. module_ = Lower::LowerToLLVM(*llvm_context_, input_file_name_, *sem_ir_,
  445. vlog_stream_);
  446. });
  447. if (vlog_stream_) {
  448. CARBON_VLOG() << "*** llvm::Module ***\n";
  449. module_->print(*vlog_stream_, /*AAW=*/nullptr,
  450. /*ShouldPreserveUseListOrder=*/false,
  451. /*IsForDebug=*/true);
  452. }
  453. if (options_.dump_llvm_ir) {
  454. module_->print(driver_->output_stream_, /*AAW=*/nullptr,
  455. /*ShouldPreserveUseListOrder=*/true);
  456. }
  457. }
  458. // Do codegen. Returns true on success.
  459. auto RunCodeGen() -> bool {
  460. CARBON_CHECK(module_);
  461. CARBON_VLOG() << "*** CodeGen ***\n";
  462. std::optional<CodeGen> codegen =
  463. CodeGen::Create(*module_, options_.target, driver_->error_stream_);
  464. if (!codegen) {
  465. return false;
  466. }
  467. if (vlog_stream_) {
  468. CARBON_VLOG() << "*** Assembly ***\n";
  469. codegen->EmitAssembly(*vlog_stream_);
  470. }
  471. if (options_.output_file_name == "-") {
  472. // TODO: the output file name, forcing object output, and requesting
  473. // textual assembly output are all somewhat linked flags. We should add
  474. // some validation that they are used correctly.
  475. if (options_.force_obj_output) {
  476. if (!codegen->EmitObject(driver_->output_stream_)) {
  477. return false;
  478. }
  479. } else {
  480. if (!codegen->EmitAssembly(driver_->output_stream_)) {
  481. return false;
  482. }
  483. }
  484. } else {
  485. llvm::SmallString<256> output_file_name = options_.output_file_name;
  486. if (output_file_name.empty()) {
  487. if (!source_->is_regular_file()) {
  488. // Don't invent file names like `-.o` or `/dev/stdin.o`.
  489. driver_->error_stream_
  490. << "ERROR: Output file name must be specified for input '"
  491. << input_file_name_ << "' that is not a regular file.\n";
  492. return false;
  493. }
  494. output_file_name = input_file_name_;
  495. llvm::sys::path::replace_extension(output_file_name,
  496. options_.asm_output ? ".s" : ".o");
  497. } else {
  498. // TODO: Handle the case where multiple input files were specified
  499. // along with an output file name. That should either be an error or
  500. // should produce a single LLVM IR module containing all inputs.
  501. // Currently each unit overwrites the output from the previous one in
  502. // this case.
  503. }
  504. CARBON_VLOG() << "Writing output to: " << output_file_name << "\n";
  505. std::error_code ec;
  506. llvm::raw_fd_ostream output_file(output_file_name, ec,
  507. llvm::sys::fs::OF_None);
  508. if (ec) {
  509. driver_->error_stream_ << "ERROR: Could not open output file '"
  510. << output_file_name << "': " << ec.message()
  511. << "\n";
  512. return false;
  513. }
  514. if (options_.asm_output) {
  515. if (!codegen->EmitAssembly(output_file)) {
  516. return false;
  517. }
  518. } else {
  519. if (!codegen->EmitObject(output_file)) {
  520. return false;
  521. }
  522. }
  523. }
  524. CARBON_VLOG() << "*** CodeGen done ***\n";
  525. return true;
  526. }
  527. // Flushes output.
  528. auto Flush() -> void { consumer_->Flush(); }
  529. auto PrintSharedValues() const -> void {
  530. Yaml::Print(driver_->output_stream_,
  531. value_stores_.OutputYaml(input_file_name_));
  532. }
  533. auto has_source() -> bool { return source_.has_value(); }
  534. private:
  535. // Wraps a call with log statements to indicate start and end.
  536. auto LogCall(llvm::StringLiteral label, llvm::function_ref<void()> fn)
  537. -> void {
  538. CARBON_VLOG() << "*** " << label << ": " << input_file_name_ << " ***\n";
  539. fn();
  540. CARBON_VLOG() << "*** " << label << " done ***\n";
  541. }
  542. Driver* driver_;
  543. SharedValueStores value_stores_;
  544. const CompileOptions& options_;
  545. llvm::StringRef input_file_name_;
  546. // Copied from driver_ for CARBON_VLOG.
  547. llvm::raw_pwrite_stream* vlog_stream_;
  548. // Diagnostics are sent to consumer_, with optional sorting.
  549. StreamDiagnosticConsumer stream_consumer_;
  550. std::optional<SortingDiagnosticConsumer> sorting_consumer_;
  551. DiagnosticConsumer* consumer_;
  552. // These are initialized as steps are run.
  553. std::optional<SourceBuffer> source_;
  554. std::optional<Lex::TokenizedBuffer> tokens_;
  555. std::optional<Parse::Tree> parse_tree_;
  556. std::optional<SemIR::File> sem_ir_;
  557. std::unique_ptr<llvm::LLVMContext> llvm_context_;
  558. std::unique_ptr<llvm::Module> module_;
  559. };
  560. auto Driver::Compile(const CompileOptions& options) -> bool {
  561. if (!ValidateCompileOptions(options)) {
  562. return false;
  563. }
  564. llvm::SmallVector<std::unique_ptr<CompilationUnit>> units;
  565. auto flush = llvm::make_scope_exit([&]() {
  566. // The diagnostics consumer must be flushed before compilation artifacts are
  567. // destructed, because diagnostics can refer to their state. This ensures
  568. // they're flushed in order of arguments, rather than order of destruction.
  569. for (auto& unit : units) {
  570. unit->Flush();
  571. }
  572. });
  573. // Shared values will always be printed last.
  574. auto dump_shared_values = llvm::make_scope_exit([&]() {
  575. if (options.dump_shared_values) {
  576. for (const auto& unit : units) {
  577. unit->PrintSharedValues();
  578. }
  579. }
  580. });
  581. for (const auto& input_file_name : options.input_file_names) {
  582. units.push_back(
  583. std::make_unique<CompilationUnit>(this, options, input_file_name));
  584. }
  585. // Lex.
  586. bool success_before_lower = true;
  587. for (auto& unit : units) {
  588. success_before_lower &= unit->RunLex();
  589. }
  590. if (options.phase == CompileOptions::Phase::Lex) {
  591. return success_before_lower;
  592. }
  593. // Parse and check phases examine `has_source` because they want to proceed if
  594. // lex failed, but not if source doesn't exist. Later steps are skipped if
  595. // anything failed, so don't need this.
  596. // Parse.
  597. for (auto& unit : units) {
  598. if (unit->has_source()) {
  599. success_before_lower &= unit->RunParse();
  600. }
  601. }
  602. if (options.phase == CompileOptions::Phase::Parse) {
  603. return success_before_lower;
  604. }
  605. // Check.
  606. SharedValueStores builtin_value_stores;
  607. auto builtins = Check::MakeBuiltins(builtin_value_stores);
  608. llvm::SmallVector<Check::Unit> check_units;
  609. for (auto& unit : units) {
  610. if (unit->has_source()) {
  611. check_units.push_back(unit->GetCheckUnit());
  612. }
  613. }
  614. CARBON_VLOG() << "*** Check::CheckParseTrees ***\n";
  615. Check::CheckParseTrees(builtins, llvm::MutableArrayRef(check_units),
  616. vlog_stream_);
  617. CARBON_VLOG() << "*** Check::CheckParseTrees done ***\n";
  618. for (auto& unit : units) {
  619. if (unit->has_source()) {
  620. success_before_lower &= unit->PostCheck();
  621. }
  622. }
  623. if (options.phase == CompileOptions::Phase::Check) {
  624. return success_before_lower;
  625. }
  626. // Unlike previous steps, errors block further progress.
  627. if (!success_before_lower) {
  628. CARBON_VLOG() << "*** Stopping before lowering due to errors ***";
  629. return false;
  630. }
  631. // Lower.
  632. for (auto& unit : units) {
  633. unit->RunLower();
  634. }
  635. if (options.phase == CompileOptions::Phase::Lower) {
  636. return true;
  637. }
  638. CARBON_CHECK(options.phase == CompileOptions::Phase::CodeGen)
  639. << "CodeGen should be the last stage";
  640. // Codegen.
  641. bool codegen_success = true;
  642. for (auto& unit : units) {
  643. codegen_success &= unit->RunCodeGen();
  644. }
  645. return codegen_success;
  646. }
  647. } // namespace Carbon