From a664801608dda48357c8d04ea7724019e3ed6105 Mon Sep 17 00:00:00 2001 From: Calvin Date: Tue, 21 Jan 2025 09:27:00 -0700 Subject: [PATCH] Reformat `CompilationUnit` function definitions out-of-line (#4825) The `Driver::CompilationUnit` class is defined with multiple long function definitions inline. This change moves those definitions out-of-line. --- toolchain/driver/compile_subcommand.cpp | 634 +++++++++++++----------- 1 file changed, 334 insertions(+), 300 deletions(-) diff --git a/toolchain/driver/compile_subcommand.cpp b/toolchain/driver/compile_subcommand.cpp index e102990261728..fd29a1af39d0e 100644 --- a/toolchain/driver/compile_subcommand.cpp +++ b/toolchain/driver/compile_subcommand.cpp @@ -336,237 +336,36 @@ auto CompileSubcommand::ValidateOptions(DriverEnv& driver_env) const -> bool { namespace { // Ties together information for a file being compiled. -// TODO: Refactor this because it's a long class to have function definitions -// inline. class CompilationUnit { public: explicit CompilationUnit(DriverEnv& driver_env, const CompileOptions& options, DiagnosticConsumer* consumer, - llvm::StringRef input_filename) - : driver_env_(&driver_env), - options_(options), - input_filename_(input_filename), - vlog_stream_(driver_env_->vlog_stream) { - if (vlog_stream_ != nullptr || options_.stream_errors) { - consumer_ = consumer; - } else { - sorting_consumer_ = SortingDiagnosticConsumer(*consumer); - consumer_ = &*sorting_consumer_; - } - if (options_.dump_mem_usage && IncludeInDumps()) { - mem_usage_ = MemUsage(); - } - if (options_.dump_timings && IncludeInDumps()) { - timings_ = Timings(); - } - } + llvm::StringRef input_filename); // Loads source and lexes it. Returns true on success. - auto RunLex() -> void { - CARBON_CHECK(!tokens_, "Called RunLex twice"); - - LogCall("SourceBuffer::MakeFromFileOrStdin", "source", [&] { - source_ = SourceBuffer::MakeFromFileOrStdin(*driver_env_->fs, - input_filename_, *consumer_); - }); - - if (!source_) { - success_ = false; - return; - } - - if (mem_usage_) { - mem_usage_->Add("source_", source_->text().size(), - source_->text().size()); - } - - CARBON_VLOG("*** SourceBuffer ***\n```\n{0}\n```\n", source_->text()); - - LogCall("Lex::Lex", "lex", - [&] { tokens_ = Lex::Lex(value_stores_, *source_, *consumer_); }); - if (options_.dump_tokens && IncludeInDumps()) { - consumer_->Flush(); - tokens_->Print(driver_env_->output_stream, - options_.omit_file_boundary_tokens); - } - if (mem_usage_) { - mem_usage_->Collect("tokens_", *tokens_); - } - CARBON_VLOG("*** Lex::TokenizedBuffer ***\n{0}", tokens_); - if (tokens_->has_errors()) { - success_ = false; - } - } + auto RunLex() -> void; // Parses tokens. Returns true on success. - auto RunParse() -> void { - CARBON_CHECK(tokens_, "Must call RunLex first"); - CARBON_CHECK(!parse_tree_, "Called RunParse twice"); - - LogCall("Parse::Parse", "parse", [&] { - parse_tree_ = Parse::Parse(*tokens_, *consumer_, vlog_stream_); - }); - if (options_.dump_parse_tree && IncludeInDumps()) { - consumer_->Flush(); - const auto& tree_and_subtrees = GetParseTreeAndSubtrees(); - if (options_.preorder_parse_tree) { - tree_and_subtrees.PrintPreorder(driver_env_->output_stream); - } else { - tree_and_subtrees.Print(driver_env_->output_stream); - } - } - if (mem_usage_) { - mem_usage_->Collect("parse_tree_", *parse_tree_); - } - CARBON_VLOG("*** Parse::Tree ***\n{0}", parse_tree_); - if (parse_tree_->has_errors()) { - success_ = false; - } - } + auto RunParse() -> void; - auto PreCheck() -> Parse::NodeLocConverter& { - CARBON_CHECK(parse_tree_, "Must call RunParse first"); - CARBON_CHECK(!node_converter_, "Called PreCheck twice"); - - get_parse_tree_and_subtrees_ = [this]() -> const Parse::TreeAndSubtrees& { - return this->GetParseTreeAndSubtrees(); - }; - node_converter_.emplace(&*tokens_, source_->filename(), - *get_parse_tree_and_subtrees_); - return *node_converter_; - } + auto PreCheck() -> Parse::NodeLocConverter&; // Returns information needed to check this unit. auto GetCheckUnit(SemIR::CheckIRId check_ir_id, llvm::ArrayRef node_converters) - -> Check::Unit { - CARBON_CHECK(node_converter_, "Must call PreCheck first"); - CARBON_CHECK(!sem_ir_converter_, "Called GetCheckUnit twice"); - - sem_ir_.emplace(&*parse_tree_, check_ir_id, parse_tree_->packaging_decl(), - value_stores_, input_filename_); - sem_ir_converter_.emplace(node_converters, &*sem_ir_); - return {.consumer = consumer_, - .value_stores = &value_stores_, - .timings = timings_ ? &*timings_ : nullptr, - .get_parse_tree_and_subtrees = *get_parse_tree_and_subtrees_, - .sem_ir = &*sem_ir_, - .node_converter = &*node_converter_, - .sem_ir_converter = &*sem_ir_converter_}; - } + -> Check::Unit; // Runs post-check logic. Returns true if checking succeeded for the IR. - auto PostCheck() -> void { - CARBON_CHECK(sem_ir_converter_, "Must call GetCheckUnit first"); - - // We've finished all steps that can produce diagnostics. Emit the - // diagnostics now, so that the developer sees them sooner and doesn't need - // to wait for code generation. - consumer_->Flush(); - - if (mem_usage_) { - mem_usage_->Collect("sem_ir_", *sem_ir_); - } - - if (options_.dump_raw_sem_ir && IncludeInDumps()) { - CARBON_VLOG("*** Raw SemIR::File ***\n{0}\n", *sem_ir_); - sem_ir_->Print(driver_env_->output_stream, options_.builtin_sem_ir); - if (options_.dump_sem_ir) { - driver_env_->output_stream << "\n"; - } - } - - bool print = options_.dump_sem_ir && IncludeInDumps(); - if (vlog_stream_ || print) { - // Omit entities imported from files that we are not dumping. - auto should_format_entity = [&](SemIR::InstId entity_inst_id) -> bool { - // TODO: Reuse `GetCanonicalImportIRInst`. Currently it depends on - // `Check::Context`, which we don't have access to here. - const SemIR::File* file = &*sem_ir_; - while (true) { - auto loc_id = file->insts().GetLocId(entity_inst_id); - if (!loc_id.is_import_ir_inst_id()) { - return true; - } - auto import_ir_inst = - file->import_ir_insts().Get(loc_id.import_ir_inst_id()); - const auto* import_file = - file->import_irs().Get(import_ir_inst.ir_id).sem_ir; - CARBON_CHECK(import_file); - if (!IncludeInDumps(import_file->filename())) { - return false; - } - file = import_file; - entity_inst_id = import_ir_inst.inst_id; - } - }; - - SemIR::Formatter formatter(&*sem_ir_, should_format_entity); - if (vlog_stream_) { - CARBON_VLOG("*** SemIR::File ***\n"); - formatter.Print(*vlog_stream_); - } - if (print) { - formatter.Print(driver_env_->output_stream); - } - } - if (sem_ir_->has_errors()) { - success_ = false; - } - } + auto PostCheck() -> void; // Lower SemIR to LLVM IR. - auto RunLower() -> void { - CARBON_CHECK(sem_ir_converter_, "Must call PostCheck first"); - CARBON_CHECK(!module_, "Called RunLower twice"); - - LogCall("Lower::LowerToLLVM", "lower", [&] { - llvm_context_ = std::make_unique(); - // TODO: Consider disabling instruction naming by default if we're not - // producing textual LLVM IR. - SemIR::InstNamer inst_namer(&*sem_ir_); - module_ = Lower::LowerToLLVM(*llvm_context_, options_.include_debug_info, - *sem_ir_converter_, input_filename_, - *sem_ir_, &inst_namer, vlog_stream_); - }); - if (vlog_stream_) { - CARBON_VLOG("*** llvm::Module ***\n"); - module_->print(*vlog_stream_, /*AAW=*/nullptr, - /*ShouldPreserveUseListOrder=*/false, - /*IsForDebug=*/true); - } - if (options_.dump_llvm_ir && IncludeInDumps()) { - module_->print(driver_env_->output_stream, /*AAW=*/nullptr, - /*ShouldPreserveUseListOrder=*/true); - } - } + auto RunLower() -> void; - auto RunCodeGen() -> void { - CARBON_CHECK(module_, "Must call RunLower first"); - LogCall("CodeGen", "codegen", [&] { success_ = RunCodeGenHelper(); }); - } + auto RunCodeGen() -> void; // Runs post-compile logic. This is always called, and called after all other // actions on the CompilationUnit. - auto PostCompile() -> void { - if (options_.dump_shared_values && IncludeInDumps()) { - Yaml::Print(driver_env_->output_stream, - value_stores_.OutputYaml(input_filename_)); - } - if (mem_usage_) { - mem_usage_->Collect("value_stores_", value_stores_); - Yaml::Print(driver_env_->output_stream, - mem_usage_->OutputYaml(input_filename_)); - } - if (timings_) { - Yaml::Print(driver_env_->output_stream, - timings_->OutputYaml(input_filename_)); - } - - // The diagnostics consumer must be flushed before compilation artifacts are - // destructed, because diagnostics can refer to their state. - consumer_->Flush(); - } + auto PostCompile() -> void; // Flushes diagnostics, specifically as part of generating stack trace // information. @@ -578,109 +377,24 @@ class CompilationUnit { private: // Do codegen. Returns true on success. - auto RunCodeGenHelper() -> bool { - std::optional codegen = CodeGen::Make( - *module_, options_.codegen_options.target, driver_env_->error_stream); - if (!codegen) { - return false; - } - if (vlog_stream_) { - CARBON_VLOG("*** Assembly ***\n"); - codegen->EmitAssembly(*vlog_stream_); - } - - if (options_.output_filename == "-") { - // TODO: The output file name, forcing object output, and requesting - // textual assembly output are all somewhat linked flags. We should add - // some validation that they are used correctly. - if (options_.force_obj_output) { - if (!codegen->EmitObject(driver_env_->output_stream)) { - return false; - } - } else { - if (!codegen->EmitAssembly(driver_env_->output_stream)) { - return false; - } - } - } else { - llvm::SmallString<256> output_filename = options_.output_filename; - if (output_filename.empty()) { - if (!source_->is_regular_file()) { - // Don't invent file names like `-.o` or `/dev/stdin.o`. - driver_env_->error_stream - << "error: output file name must be specified for input `" - << input_filename_ << "` that is not a regular file\n"; - return false; - } - output_filename = input_filename_; - llvm::sys::path::replace_extension(output_filename, - options_.asm_output ? ".s" : ".o"); - } else { - // TODO: Handle the case where multiple input files were specified - // along with an output file name. That should either be an error or - // should produce a single LLVM IR module containing all inputs. - // Currently each unit overwrites the output from the previous one in - // this case. - } - CARBON_VLOG("Writing output to: {0}\n", output_filename); - - std::error_code ec; - llvm::raw_fd_ostream output_file(output_filename, ec, - llvm::sys::fs::OF_None); - if (ec) { - driver_env_->error_stream << "error: could not open output file '" - << output_filename << "': " << ec.message() - << "\n"; - return false; - } - if (options_.asm_output) { - if (!codegen->EmitAssembly(output_file)) { - return false; - } - } else { - if (!codegen->EmitObject(output_file)) { - return false; - } - } - } - return true; - } + auto RunCodeGenHelper() -> bool; // The TreeAndSubtrees is mainly used for debugging and diagnostics, and has // significant overhead. Avoid constructing it when unused. - auto GetParseTreeAndSubtrees() -> const Parse::TreeAndSubtrees& { - if (!parse_tree_and_subtrees_) { - parse_tree_and_subtrees_ = Parse::TreeAndSubtrees(*tokens_, *parse_tree_); - if (mem_usage_) { - mem_usage_->Collect("parse_tree_and_subtrees_", - *parse_tree_and_subtrees_); - } - } - return *parse_tree_and_subtrees_; - } + auto GetParseTreeAndSubtrees() -> const Parse::TreeAndSubtrees&; // Wraps a call with log statements to indicate start and end. Typically logs // with the actual function name, but marks timings with the appropriate // phase. auto LogCall(llvm::StringLiteral logging_label, llvm::StringLiteral timing_label, llvm::function_ref fn) - -> void { - CARBON_VLOG("*** {0}: {1} ***\n", logging_label, input_filename_); - Timings::ScopedTiming timing(timings_ ? &*timings_ : nullptr, timing_label); - fn(); - CARBON_VLOG("*** {0} done ***\n", logging_label); - } + -> void; // Returns true if the current input file can be dumped. - auto IncludeInDumps() const -> bool { - return IncludeInDumps(input_filename_); - } + auto IncludeInDumps() const -> bool; // Returns true if the specified input file can be dumped. - auto IncludeInDumps(llvm::StringRef filename) const -> bool { - return options_.exclude_dump_file_prefix.empty() || - !filename.starts_with(options_.exclude_dump_file_prefix); - } + auto IncludeInDumps(llvm::StringRef filename) const -> bool; DriverEnv* driver_env_; SharedValueStores value_stores_; @@ -718,6 +432,326 @@ class CompilationUnit { std::unique_ptr llvm_context_; std::unique_ptr module_; }; + +CompilationUnit::CompilationUnit(DriverEnv& driver_env, + const CompileOptions& options, + DiagnosticConsumer* consumer, + llvm::StringRef input_filename) + : driver_env_(&driver_env), + options_(options), + input_filename_(input_filename), + vlog_stream_(driver_env_->vlog_stream) { + if (vlog_stream_ != nullptr || options_.stream_errors) { + consumer_ = consumer; + } else { + sorting_consumer_ = SortingDiagnosticConsumer(*consumer); + consumer_ = &*sorting_consumer_; + } + if (options_.dump_mem_usage && IncludeInDumps()) { + mem_usage_ = MemUsage(); + } + if (options_.dump_timings && IncludeInDumps()) { + timings_ = Timings(); + } +} + +auto CompilationUnit::RunLex() -> void { + CARBON_CHECK(!tokens_, "Called RunLex twice"); + + LogCall("SourceBuffer::MakeFromFileOrStdin", "source", [&] { + source_ = SourceBuffer::MakeFromFileOrStdin(*driver_env_->fs, + input_filename_, *consumer_); + }); + + if (!source_) { + success_ = false; + return; + } + + if (mem_usage_) { + mem_usage_->Add("source_", source_->text().size(), source_->text().size()); + } + + CARBON_VLOG("*** SourceBuffer ***\n```\n{0}\n```\n", source_->text()); + + LogCall("Lex::Lex", "lex", + [&] { tokens_ = Lex::Lex(value_stores_, *source_, *consumer_); }); + if (options_.dump_tokens && IncludeInDumps()) { + consumer_->Flush(); + tokens_->Print(driver_env_->output_stream, + options_.omit_file_boundary_tokens); + } + if (mem_usage_) { + mem_usage_->Collect("tokens_", *tokens_); + } + CARBON_VLOG("*** Lex::TokenizedBuffer ***\n{0}", tokens_); + if (tokens_->has_errors()) { + success_ = false; + } +} + +auto CompilationUnit::RunParse() -> void { + CARBON_CHECK(tokens_, "Must call RunLex first"); + CARBON_CHECK(!parse_tree_, "Called RunParse twice"); + + LogCall("Parse::Parse", "parse", [&] { + parse_tree_ = Parse::Parse(*tokens_, *consumer_, vlog_stream_); + }); + if (options_.dump_parse_tree && IncludeInDumps()) { + consumer_->Flush(); + const auto& tree_and_subtrees = GetParseTreeAndSubtrees(); + if (options_.preorder_parse_tree) { + tree_and_subtrees.PrintPreorder(driver_env_->output_stream); + } else { + tree_and_subtrees.Print(driver_env_->output_stream); + } + } + if (mem_usage_) { + mem_usage_->Collect("parse_tree_", *parse_tree_); + } + CARBON_VLOG("*** Parse::Tree ***\n{0}", parse_tree_); + if (parse_tree_->has_errors()) { + success_ = false; + } +} + +auto CompilationUnit::PreCheck() -> Parse::NodeLocConverter& { + CARBON_CHECK(parse_tree_, "Must call RunParse first"); + CARBON_CHECK(!node_converter_, "Called PreCheck twice"); + + get_parse_tree_and_subtrees_ = [this]() -> const Parse::TreeAndSubtrees& { + return this->GetParseTreeAndSubtrees(); + }; + node_converter_.emplace(&*tokens_, source_->filename(), + *get_parse_tree_and_subtrees_); + return *node_converter_; +} + +auto CompilationUnit::GetCheckUnit( + SemIR::CheckIRId check_ir_id, + llvm::ArrayRef node_converters) -> Check::Unit { + CARBON_CHECK(node_converter_, "Must call PreCheck first"); + CARBON_CHECK(!sem_ir_converter_, "Called GetCheckUnit twice"); + + sem_ir_.emplace(&*parse_tree_, check_ir_id, parse_tree_->packaging_decl(), + value_stores_, input_filename_); + sem_ir_converter_.emplace(node_converters, &*sem_ir_); + return {.consumer = consumer_, + .value_stores = &value_stores_, + .timings = timings_ ? &*timings_ : nullptr, + .get_parse_tree_and_subtrees = *get_parse_tree_and_subtrees_, + .sem_ir = &*sem_ir_, + .node_converter = &*node_converter_, + .sem_ir_converter = &*sem_ir_converter_}; +} + +auto CompilationUnit::PostCheck() -> void { + CARBON_CHECK(sem_ir_converter_, "Must call GetCheckUnit first"); + + // We've finished all steps that can produce diagnostics. Emit the + // diagnostics now, so that the developer sees them sooner and doesn't need + // to wait for code generation. + consumer_->Flush(); + + if (mem_usage_) { + mem_usage_->Collect("sem_ir_", *sem_ir_); + } + + if (options_.dump_raw_sem_ir && IncludeInDumps()) { + CARBON_VLOG("*** Raw SemIR::File ***\n{0}\n", *sem_ir_); + sem_ir_->Print(driver_env_->output_stream, options_.builtin_sem_ir); + if (options_.dump_sem_ir) { + driver_env_->output_stream << "\n"; + } + } + + bool print = options_.dump_sem_ir && IncludeInDumps(); + if (vlog_stream_ || print) { + // Omit entities imported from files that we are not dumping. + auto should_format_entity = [&](SemIR::InstId entity_inst_id) -> bool { + // TODO: Reuse `GetCanonicalImportIRInst`. Currently it depends on + // `Check::Context`, which we don't have access to here. + const SemIR::File* file = &*sem_ir_; + while (true) { + auto loc_id = file->insts().GetLocId(entity_inst_id); + if (!loc_id.is_import_ir_inst_id()) { + return true; + } + auto import_ir_inst = + file->import_ir_insts().Get(loc_id.import_ir_inst_id()); + const auto* import_file = + file->import_irs().Get(import_ir_inst.ir_id).sem_ir; + CARBON_CHECK(import_file); + if (!IncludeInDumps(import_file->filename())) { + return false; + } + file = import_file; + entity_inst_id = import_ir_inst.inst_id; + } + }; + + SemIR::Formatter formatter(&*sem_ir_, should_format_entity); + if (vlog_stream_) { + CARBON_VLOG("*** SemIR::File ***\n"); + formatter.Print(*vlog_stream_); + } + if (print) { + formatter.Print(driver_env_->output_stream); + } + } + if (sem_ir_->has_errors()) { + success_ = false; + } +} + +auto CompilationUnit::RunLower() -> void { + CARBON_CHECK(sem_ir_converter_, "Must call PostCheck first"); + CARBON_CHECK(!module_, "Called RunLower twice"); + + LogCall("Lower::LowerToLLVM", "lower", [&] { + llvm_context_ = std::make_unique(); + // TODO: Consider disabling instruction naming by default if we're not + // producing textual LLVM IR. + SemIR::InstNamer inst_namer(&*sem_ir_); + module_ = Lower::LowerToLLVM(*llvm_context_, options_.include_debug_info, + *sem_ir_converter_, input_filename_, *sem_ir_, + &inst_namer, vlog_stream_); + }); + if (vlog_stream_) { + CARBON_VLOG("*** llvm::Module ***\n"); + module_->print(*vlog_stream_, /*AAW=*/nullptr, + /*ShouldPreserveUseListOrder=*/false, + /*IsForDebug=*/true); + } + if (options_.dump_llvm_ir && IncludeInDumps()) { + module_->print(driver_env_->output_stream, /*AAW=*/nullptr, + /*ShouldPreserveUseListOrder=*/true); + } +} + +auto CompilationUnit::RunCodeGen() -> void { + CARBON_CHECK(module_, "Must call RunLower first"); + LogCall("CodeGen", "codegen", [&] { success_ = RunCodeGenHelper(); }); +} + +auto CompilationUnit::PostCompile() -> void { + if (options_.dump_shared_values && IncludeInDumps()) { + Yaml::Print(driver_env_->output_stream, + value_stores_.OutputYaml(input_filename_)); + } + if (mem_usage_) { + mem_usage_->Collect("value_stores_", value_stores_); + Yaml::Print(driver_env_->output_stream, + mem_usage_->OutputYaml(input_filename_)); + } + if (timings_) { + Yaml::Print(driver_env_->output_stream, + timings_->OutputYaml(input_filename_)); + } + + // The diagnostics consumer must be flushed before compilation artifacts are + // destructed, because diagnostics can refer to their state. + consumer_->Flush(); +} + +auto CompilationUnit::RunCodeGenHelper() -> bool { + std::optional codegen = CodeGen::Make( + *module_, options_.codegen_options.target, driver_env_->error_stream); + if (!codegen) { + return false; + } + if (vlog_stream_) { + CARBON_VLOG("*** Assembly ***\n"); + codegen->EmitAssembly(*vlog_stream_); + } + + if (options_.output_filename == "-") { + // TODO: The output file name, forcing object output, and requesting + // textual assembly output are all somewhat linked flags. We should add + // some validation that they are used correctly. + if (options_.force_obj_output) { + if (!codegen->EmitObject(driver_env_->output_stream)) { + return false; + } + } else { + if (!codegen->EmitAssembly(driver_env_->output_stream)) { + return false; + } + } + } else { + llvm::SmallString<256> output_filename = options_.output_filename; + if (output_filename.empty()) { + if (!source_->is_regular_file()) { + // Don't invent file names like `-.o` or `/dev/stdin.o`. + driver_env_->error_stream + << "error: output file name must be specified for input `" + << input_filename_ << "` that is not a regular file\n"; + return false; + } + output_filename = input_filename_; + llvm::sys::path::replace_extension(output_filename, + options_.asm_output ? ".s" : ".o"); + } else { + // TODO: Handle the case where multiple input files were specified + // along with an output file name. That should either be an error or + // should produce a single LLVM IR module containing all inputs. + // Currently each unit overwrites the output from the previous one in + // this case. + } + CARBON_VLOG("Writing output to: {0}\n", output_filename); + + std::error_code ec; + llvm::raw_fd_ostream output_file(output_filename, ec, + llvm::sys::fs::OF_None); + if (ec) { + driver_env_->error_stream << "error: could not open output file '" + << output_filename << "': " << ec.message() + << "\n"; + return false; + } + if (options_.asm_output) { + if (!codegen->EmitAssembly(output_file)) { + return false; + } + } else { + if (!codegen->EmitObject(output_file)) { + return false; + } + } + } + return true; +} + +auto CompilationUnit::GetParseTreeAndSubtrees() + -> const Parse::TreeAndSubtrees& { + if (!parse_tree_and_subtrees_) { + parse_tree_and_subtrees_ = Parse::TreeAndSubtrees(*tokens_, *parse_tree_); + if (mem_usage_) { + mem_usage_->Collect("parse_tree_and_subtrees_", + *parse_tree_and_subtrees_); + } + } + return *parse_tree_and_subtrees_; +} + +auto CompilationUnit::LogCall(llvm::StringLiteral logging_label, + llvm::StringLiteral timing_label, + llvm::function_ref fn) -> void { + CARBON_VLOG("*** {0}: {1} ***\n", logging_label, input_filename_); + Timings::ScopedTiming timing(timings_ ? &*timings_ : nullptr, timing_label); + fn(); + CARBON_VLOG("*** {0} done ***\n", logging_label); +} + +auto CompilationUnit::IncludeInDumps() const -> bool { + return IncludeInDumps(input_filename_); +} + +auto CompilationUnit::IncludeInDumps(llvm::StringRef filename) const -> bool { + return options_.exclude_dump_file_prefix.empty() || + !filename.starts_with(options_.exclude_dump_file_prefix); +} + } // namespace auto CompileSubcommand::Run(DriverEnv& driver_env) -> DriverResult {