Files
carbon-lang/toolchain/driver/build_runtimes_subcommand.cpp
Chandler Carruth 0546b48a7d Support --target-cpu, --target-cpu-tune, and --target-cpu-features (#7903)
Add support to the driver for CLI flags that select which CPU to target,
which CPU to tune performance for, and which CPU features to enable.

- `--target-cpu` selects the architecture of CPU to target, similar to
`-march` on x86. This combines `-march` with `armv*` strings and `-mcpu`
on Arm for specific CPU names. Similarly for RISC-V (if/when we support
and test it), etc. Notably, `--target-cpu=native` targets the current
native CPU.
- `--target-cpu-tune` maps to `-mtune`. This is expected to be rarely if
ever desirable, and I'm open to removing it, but if folks are relying on
this for performance I didn't want to hide the option.
- `--target-cpu-features` allows a "standard" (for LLVM) comma-separated
list of LLVM subtarget features, including `+feature` and `-feature`
syntax.

These flags, when provided, establish the default baseline for CPU
targeting and control how on-demand runtimes are built. They can be
changed or overridden by additional Clang flags when using
`--clang-arg`.

A critical part of this is building runtimes on demand using these
features. For that, we need to do some amount of canonicalization
(re-using Clang's canonicalization to ensure consistent behavior), and
extend the runtimes cache features to recognize these customizations.
Note that only the top-level Carbon flags impact runtimes, any
particular Clang arguments are only used by the specific compiles that
receive those arguments.

There is some nascent RISC-V support here, but it is incomplete and only
minimally tested. Still, it seemed better to record the parts we could
test than remove them.

Assisted-by: Antigravity with Gemini
2026-10-21 00:43:54 +00:00

123 lines
4.4 KiB
C++

// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "toolchain/driver/build_runtimes_subcommand.h"
#include "llvm/TargetParser/Triple.h"
#include "toolchain/driver/carbon_runtimes.h"
#include "toolchain/driver/clang_runner.h"
#include "toolchain/driver/clang_runtimes.h"
namespace Carbon {
auto BuildRuntimesOptions::Build(CommandLine::CommandBuilder& b) -> void {
b.AddStringOption(
{
.name = "output-directory",
.value_name = "DIR",
.help = R"""(
The directory to populate with runtime libraries suitable for the selected code
generation options.
)""",
},
[&](auto& arg_b) { arg_b.Set(&directory); });
b.AddFlag(
{
.name = "force",
.help = R"""(
Force re-creating the provided output path from scratch
This will **remove** the provided output path and re-create it from scratch.
)""",
},
[&](CommandLine::FlagBuilder& arg_b) { arg_b.Set(&force); });
codegen_options.Build(b);
}
static constexpr CommandLine::CommandInfo SubcommandInfo = {
.name = "build-runtimes",
.help = R"""(
Build Carbon's runtime libraries.
This subcommand builds Carbon's runtime libraries for a particular code
generation target, either in their default location or a specified one.
Running this command directly is not necessary as Carbon will build and cache
runtimes as needed when linking, but building them directly can aid in
debugging issues or allow them to be prebuilt, possibly with customized code
generation flags, and used explicitly when linking.
)""",
};
BuildRuntimesSubcommand::BuildRuntimesSubcommand()
: DriverSubcommand(SubcommandInfo) {}
auto BuildRuntimesSubcommand::Run(DriverEnv& driver_env) -> DriverResult {
// Don't run Clang when fuzzing, it is known to not be reliable under fuzzing
// due to many unfixed issues.
if (TestAndDiagnoseIfFuzzingExternalLibraries(driver_env, "clang")) {
return {.success = false};
}
// For diagnosing filesystem or other errors when building runtimes.
CARBON_DIAGNOSTIC(FailureBuildingRuntimes, Error,
"failure building runtimes: {0}", std::string);
auto run_result = RunInternal(driver_env);
if (!run_result.ok()) {
driver_env.emitter.Emit(FailureBuildingRuntimes,
run_result.error().message());
return {.success = false};
}
llvm::outs() << "Built runtimes: " << *run_result << "\n";
return {.success = true};
}
auto BuildRuntimesSubcommand::RunInternal(DriverEnv& driver_env)
-> ErrorOr<std::filesystem::path> {
ClangRunner runner(driver_env.installation, driver_env.fs,
driver_env.vlog_stream);
CARBON_ASSIGN_OR_RETURN(Runtimes::Cache::Features features,
runner.ComputeRuntimesFeatures(
options_.codegen_options, *driver_env.consumer));
bool is_cache = options_.directory.empty();
std::filesystem::path output_path = options_.directory.str();
CARBON_ASSIGN_OR_RETURN(
auto runtimes, is_cache
? driver_env.runtimes_cache.Lookup(features)
: Runtimes::Make(output_path, driver_env.vlog_stream));
if (options_.force) {
// Remove existing runtimes to force a rebuild.
CARBON_RETURN_IF_ERROR(runtimes.Remove(Runtimes::ClangResourceDir));
CARBON_RETURN_IF_ERROR(runtimes.Remove(Runtimes::LibUnwind));
CARBON_RETURN_IF_ERROR(runtimes.Remove(Runtimes::Libcxx));
CARBON_RETURN_IF_ERROR(runtimes.Remove(Runtimes::CarbonCore));
}
ClangResourceDirBuilder resource_dir_builder(&runner, driver_env.thread_pool,
&runtimes, features);
ClangArchiveRuntimesBuilder<Runtimes::LibUnwind> lib_unwind_builder(
&runner, driver_env.thread_pool, &runtimes, features);
ClangArchiveRuntimesBuilder<Runtimes::Libcxx> libcxx_builder(
&runner, driver_env.thread_pool, &runtimes, features);
CarbonPreludeBuilder prelude_builder(&driver_env, &runtimes,
&options_.codegen_options);
CARBON_RETURN_IF_ERROR(std::move(resource_dir_builder).Wait());
CARBON_RETURN_IF_ERROR(std::move(lib_unwind_builder).Wait());
CARBON_RETURN_IF_ERROR(std::move(libcxx_builder).Wait());
CARBON_RETURN_IF_ERROR(std::move(prelude_builder).Build());
return runtimes.base_path();
}
} // namespace Carbon