Only lower files we are going to emit. (#7611)

Move `--output-last-file-only` and output filename synthesis logic out
of the general-purpose compile driver and into the `carbon compile`
subcommand, which is the only thing that should be using them. Track on
CompilationUnit whether it is being lowered, or whether it exists only
to be imported into other units.

`carbon compile` now never lowers inputs that it discovered for itself,
only inputs that were specified on the command line. In particular, it
doesn't lower (and throw away the result of lowering) the prelude any
more. This makes the toolchain tests about 10% faster in my crude
measurements.

Also, we now do not create a clang `CodeGenerator` for input files that
we are not lowering, similarly saving compilation time for units that
exist only to be imported, not lowered.

One minor change: we use the same mechanism to determine whether an
input is being lowered and to determine what the output filename is.
This means that `--phase=lower` and `--phase=optimize`, which lower but
don't produce an output file, still need an output filename to be
specified now in some cases. Given those are just debugging tools, I
think that's fine.

Assisted-by: Gemini via Antigravity
This commit is contained in:
Richard Smith
2026-08-05 12:52:24 +00:00
committed by GitHub
parent f776cf0744
commit dea290db81
14 changed files with 181 additions and 119 deletions
+80 -4
View File
@@ -4,6 +4,10 @@
#include "toolchain/driver/compile_subcommand.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Path.h"
#include "toolchain/diagnostics/emitter.h"
#include "toolchain/diagnostics/format_providers.h"
#include "toolchain/driver/compile_driver.h"
namespace Carbon {
@@ -35,12 +39,84 @@ auto CompileSubcommand::Run(DriverEnv& driver_env) -> DriverResult {
return {.success = false};
}
// If we're lowering and have an output file name, we can only support a
// single input filename.
// TODO: Produce an error in this case rather than skipping all files but the
// last, and remove the `--output-last-input-only` flag.
if (options_.compile_options.phase >= CompileOptions::Phase::Lower &&
options_.compile_options.input_filenames.size() > 1 &&
!options_.output_last_input_only &&
!options_.compile_options.output_filename.empty() &&
options_.compile_options.output_filename != "-") {
CARBON_DIAGNOSTIC(
CompileMultipleInputsWithOutput, Warning,
"only outputting {0} to {1}, skipping output of {2} input "
"file{2:s}; pass `--output-last-input-only` to silence this "
"warning",
std::string, std::string, Diagnostics::IntAsSelect);
driver_env.emitter.Emit(
CompileMultipleInputsWithOutput,
options_.compile_options.input_filenames.back().str(),
options_.compile_options.output_filename.str(),
options_.compile_options.input_filenames.size() - 1);
}
llvm::StringSet<> input_filenames(llvm::from_range,
options_.compile_options.input_filenames);
auto compile_driver = CompileDriver(&options_.compile_options);
if (!compile_driver.Initialize(
driver_env, [&](llvm::StringRef) -> std::string {
return options_.compile_options.output_filename.str();
})) {
bool init_success = true;
auto get_output_filename =
[&](llvm::StringRef input_filename) -> std::string {
// We only generate output for inputs specified on the command line,
// not for inputs discovered through imports.
if (!input_filenames.contains(input_filename)) {
return "";
}
// If the output filename is "-", that's used for all inputs.
if (options_.compile_options.output_filename == "-") {
return "-";
}
// If single output filename was specified, it's used for the final
// input filename only.
if (!options_.compile_options.output_filename.empty()) {
if (input_filename == options_.compile_options.input_filenames.back()) {
return options_.compile_options.output_filename.str();
}
return "";
}
// Otherwise, generate an output filename for each explicitly-specified
// input file.
bool is_regular_file = true;
if (input_filename == "-") {
// TODO: If we would produce textual output, using "-" as the default
// output filename here would be reasonable and useful.
is_regular_file = false;
} else if (auto status = driver_env.fs->status(input_filename);
status && status->isOther()) {
is_regular_file = false;
}
if (!is_regular_file) {
CARBON_DIAGNOSTIC(CompileInputNotRegularFile, Error,
"output file name must be specified for input "
"`{0}` that is not a regular file",
std::string);
driver_env.emitter.Emit(CompileInputNotRegularFile, input_filename.str());
init_success = false;
return "";
}
llvm::SmallString<256> output_filename = input_filename;
llvm::sys::path::replace_extension(
output_filename, options_.compile_options.asm_output ? ".s" : ".o");
return output_filename.str().str();
};
if (!compile_driver.Initialize(driver_env, get_output_filename) ||
!init_success) {
return {.success = false};
}