Files
carbon-lang/toolchain/driver/codegen_options.cpp
T
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

157 lines
5.0 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/codegen_options.h"
#include <string>
#include "llvm/Support/Error.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/TargetParser/AArch64TargetParser.h"
#include "llvm/TargetParser/RISCVISAInfo.h"
#include "llvm/TargetParser/RISCVTargetParser.h"
#include "llvm/TargetParser/Triple.h"
namespace Carbon {
auto CodegenOptions::Build(CommandLine::CommandBuilder& b) -> void {
b.AddStringOption(
{
.name = "target",
.help = R"""(
Select a target platform. Uses the LLVM target syntax. Also known as a "triple"
for historical reasons.
This corresponds to the `target` flag to Clang and accepts the same strings
documented there:
https://clang.llvm.org/docs/CrossCompilation.html#target-triple
)""",
},
[&](auto& arg_b) {
arg_b.Default(host);
arg_b.Set(&target);
});
b.AddStringOption(
{
.name = "target-cpu",
.value_name = "CPU",
.help = R"""(
Select a target CPU or architecture level.
Accepts CPU names (such as `znver4`, `apple-m1`, `spacemit-x60`, or `native`) as
well as architecture strings or profiles (such as `x86-64-v3`, `armv9-a`,
`rv64gc`, or `rva22u64`). This corresponds to Clang's `-march` and `-mcpu`
flags, selecting the appropriate underlying flag for the target architecture.
)""",
},
[&](auto& arg_b) { arg_b.Set(&target_cpu); });
b.AddStringOption(
{
.name = "target-cpu-tune",
.value_name = "CPU",
.help = R"""(
Select a target CPU to tune code generation for without enabling new
instruction set extensions.
Accepts CPU names (such as `znver4`, `apple-m1`, `spacemit-x60`, `generic`, or
`native`). This corresponds to Clang's `-mtune` flag.
)""",
},
[&](auto& arg_b) { arg_b.Set(&target_cpu_tune); });
b.AddStringOption(
{
.name = "target-cpu-features",
.value_name = "FEATURES",
.help = R"""(
Select target CPU features to enable or disable.
Accepts a comma-separated list of LLVM target feature names, optionally prefixed
with `+` to enable or `-` to disable (such as `+avx2,-fma` or `sve,crc`). Bare
feature names without a prefix are enabled.
)""",
},
[&](auto& arg_b) { arg_b.Set(&target_cpu_features); });
}
static auto AppendTargetCpuClangArgs(llvm::StringRef target,
llvm::StringRef target_cpu,
llvm::SmallVectorImpl<std::string>& args)
-> void {
if (target_cpu.empty()) {
return;
}
llvm::Triple triple(target);
if (triple.isX86()) {
// On x86, Clang uses `-march=` for both microarchitecture levels (such as
// `x86-64-v3`) and specific CPUs (such as `znver4` or `native`), and does
// not support `-mcpu=`.
args.push_back(llvm::formatv("-march={0}", target_cpu).str());
return;
}
if (triple.isAArch64()) {
auto [base, _] = target_cpu.split('+');
bool is_arch =
llvm::AArch64::parseArch(base) != nullptr || base.starts_with("armv");
args.push_back(
llvm::formatv(is_arch ? "-march={0}" : "-mcpu={0}", target_cpu).str());
return;
}
if (triple.isRISCV()) {
auto isa_info = llvm::RISCVISAInfo::parseArchString(
target_cpu, /*EnableExperimentalExtension=*/true);
bool is_arch = static_cast<bool>(isa_info);
if (!isa_info) {
llvm::consumeError(isa_info.takeError());
is_arch =
!llvm::RISCV::parseCPU(target_cpu, triple.isRISCV64()) &&
(target_cpu.starts_with("rv32") || target_cpu.starts_with("rv64") ||
target_cpu.starts_with("rva") || target_cpu.starts_with("rvb") ||
target_cpu.starts_with("rvi") || target_cpu.starts_with("rvm"));
}
args.push_back(
llvm::formatv(is_arch ? "-march={0}" : "-mcpu={0}", target_cpu).str());
return;
}
args.push_back(llvm::formatv("-mcpu={0}", target_cpu).str());
}
auto CodegenOptions::AppendClangArgs(
llvm::SmallVectorImpl<std::string>& args) const -> void {
AppendTargetCpuClangArgs(target, target_cpu, args);
if (!target_cpu_tune.empty()) {
args.push_back(llvm::formatv("-mtune={0}", target_cpu_tune).str());
}
if (!target_cpu_features.empty()) {
llvm::SmallVector<llvm::StringRef> features;
target_cpu_features.split(features, ',', /*MaxSplit=*/-1,
/*KeepEmpty=*/false);
for (llvm::StringRef feature : features) {
args.push_back("-Xclang");
args.push_back("-target-feature");
args.push_back("-Xclang");
if (feature.size() > 1 &&
(feature.starts_with('+') || feature.starts_with('-'))) {
args.push_back(feature.str());
} else {
args.push_back(llvm::formatv("+{0}", feature).str());
}
}
}
}
auto CodegenOptions::GetClangArgs() const -> llvm::SmallVector<std::string> {
llvm::SmallVector<std::string> args;
AppendClangArgs(args);
return args;
}
} // namespace Carbon