From 768582d8d3f7e0de72671c11ca4250c8add68cec Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Tue, 17 Feb 2026 19:14:31 -0800 Subject: [PATCH] Propagate some target options from Clang to Carbon's target. (#6759) Turn a few section options on by default in Clang's options, and propagate the setting from Clang to Carbon. These settings can't be different between the two sides of the compilation, so merging the behavior of Carbon's defaults and Clang's flags seems best. --- toolchain/base/clang_invocation.cpp | 7 +++++ toolchain/driver/compile_subcommand.cpp | 28 ++++++++++++++----- .../driver/testdata/compile/init_array.carbon | 24 ++++++++++++++++ .../testdata/compile/no_init_array.carbon | 23 +++++++++++++++ 4 files changed, 75 insertions(+), 7 deletions(-) create mode 100644 toolchain/driver/testdata/compile/init_array.carbon create mode 100644 toolchain/driver/testdata/compile/no_init_array.carbon diff --git a/toolchain/base/clang_invocation.cpp b/toolchain/base/clang_invocation.cpp index b34d43f70db1..1677c5a9d0a1 100644 --- a/toolchain/base/clang_invocation.cpp +++ b/toolchain/base/clang_invocation.cpp @@ -118,6 +118,13 @@ auto AppendDefaultClangArgs(const InstallPaths& install_paths, // TODO: Decide if we want this. "-fPIE", + // Enable function and data sections by default, and don't waste object + // file size on unique section names. Allow these to be overridden by + // Clang arguments. + "-ffunction-sections", + "-fdata-sections", + "-fno-unique-section-names", + // Override runtime library defaults. // // TODO: We should consider if there is a reasonable way to build Clang diff --git a/toolchain/driver/compile_subcommand.cpp b/toolchain/driver/compile_subcommand.cpp index 26fe55a229cb..9467f9e6b41c 100644 --- a/toolchain/driver/compile_subcommand.cpp +++ b/toolchain/driver/compile_subcommand.cpp @@ -492,7 +492,7 @@ class CompilationUnit { auto RunLower() -> void; // Runs the optimization pipeline. - auto RunOptimize() -> void; + auto RunOptimize(const clang::CompilerInvocation& clang_invocation) -> void; // Runs post-lowering-to-LLVM-IR logic. This is always called if we do any // lowering work, after we've finished building the IR in RunLower() and, @@ -538,7 +538,8 @@ class CompilationUnit { auto IncludeInDumps() -> bool; // Builds the LLVM target machine. - auto MakeTargetMachine() -> void; + auto MakeTargetMachine(const clang::CompilerInvocation& clang_invocation) + -> void; // The index of the unit amongst all units. SemIR::CheckIRId check_ir_id_; @@ -814,7 +815,8 @@ auto CompilationUnit::RunLower() -> void { }); } -auto CompilationUnit::MakeTargetMachine() -> void { +auto CompilationUnit::MakeTargetMachine( + const clang::CompilerInvocation& clang_invocation) -> void { CARBON_CHECK(module_, "Must call RunLower first"); CARBON_CHECK(!target_machine_, "Should not call this multiple times"); @@ -828,7 +830,16 @@ auto CompilationUnit::MakeTargetMachine() -> void { constexpr llvm::StringLiteral CPU = "generic"; constexpr llvm::StringLiteral Features = ""; + const auto& codegen_opts = clang_invocation.getCodeGenOpts(); + + // TODO: Make the code in Clang's BackendUtil.cpp externally accessible and + // call it from here. This is doing a subset of the same work to translate + // Clang code generation options into target options. llvm::TargetOptions target_opts; + target_opts.UseInitArray = codegen_opts.UseInitArray; + target_opts.FunctionSections = codegen_opts.FunctionSections; + target_opts.DataSections = codegen_opts.DataSections; + target_opts.UniqueSectionNames = codegen_opts.UniqueSectionNames; target_machine_.reset(target_->createTargetMachine( target_triple, CPU, Features, target_opts, llvm::Reloc::PIC_)); } @@ -863,7 +874,8 @@ static auto GetClangOptimizationFlag(Lower::OptimizationLevel opt_level) } } -auto CompilationUnit::RunOptimize() -> void { +auto CompilationUnit::RunOptimize( + const clang::CompilerInvocation& clang_invocation) -> void { CARBON_CHECK(module_, "Must call RunLower first"); // TODO: A lot of the work done here duplicates work done by Clang setting up @@ -873,7 +885,7 @@ auto CompilationUnit::RunOptimize() -> void { // pipeline rather than building one of our own, or factoring out enough of // Clang's pipeline builder that we can reuse and further customize it. - MakeTargetMachine(); + MakeTargetMachine(clang_invocation); // TODO: There's no way to set these automatically from an // llvm::OptimizationLevel. Add such a mechanism to LLVM and use it from @@ -1094,7 +1106,9 @@ auto CompileSubcommand::Run(DriverEnv& driver_env) -> DriverResult { // Build a clang invocation. We do this regardless of whether we're running // check, because this is essentially performing further option validation, // and we generally validate all options even if we're not using them for the - // selected phases of compilation. + // selected phases of compilation. We also use Clang's target option handling + // to configure our target, to ensure that we are using the same ABI for both + // the C++ and Carbon parts of the compilation. // TODO: Share any arguments we specify here with the `carbon clang` // subcommand. { @@ -1283,7 +1297,7 @@ auto CompileSubcommand::Run(DriverEnv& driver_env) -> DriverResult { unit->RunLower(); if (options_.phase != CompileOptions::Phase::Lower) { - unit->RunOptimize(); + unit->RunOptimize(*clang_invocation); } unit->PostLower(); diff --git a/toolchain/driver/testdata/compile/init_array.carbon b/toolchain/driver/testdata/compile/init_array.carbon new file mode 100644 index 000000000000..76ee574803ca --- /dev/null +++ b/toolchain/driver/testdata/compile/init_array.carbon @@ -0,0 +1,24 @@ +// 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 +// +// ARGS: compile foo.carbon --asm-output --output=- --target=x86_64-linux-gnu +// +// NOAUTOUPDATE +// SET-CHECK-SUBSET +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/driver/testdata/compile/target_machine.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/driver/testdata/compile/target_machine.carbon + +// --- foo.carbon + +import Cpp inline ''' +int f(); +inline int n = f(); +'''; + +// We should use init_array, overriding LLVM's default of using ctors, as Clang +// does. +// CHECK:STDOUT: {{\s*}}.section{{\s+}}.init_array,{{.*}} +// CHECK:STDOUT: {{\s*}}.quad{{\s+}}__cxx_global_var_init diff --git a/toolchain/driver/testdata/compile/no_init_array.carbon b/toolchain/driver/testdata/compile/no_init_array.carbon new file mode 100644 index 000000000000..6107c01e9f8e --- /dev/null +++ b/toolchain/driver/testdata/compile/no_init_array.carbon @@ -0,0 +1,23 @@ +// 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 +// +// ARGS: compile foo.carbon --asm-output --output=- --target=x86_64-linux-gnu -- -fno-use-init-array +// +// NOAUTOUPDATE +// SET-CHECK-SUBSET +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/driver/testdata/compile/target_machine.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/driver/testdata/compile/target_machine.carbon + +// --- foo.carbon + +import Cpp inline ''' +int f(); +inline int n = f(); +'''; + +// We should not use init_array, following the command-line flag. +// CHECK:STDOUT: {{\s*}}.section{{\s+}}.ctors,{{.*}} +// CHECK:STDOUT: {{\s*}}.quad{{\s+}}__cxx_global_var_init