Browse Source

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.
Richard Smith 2 months ago
parent
commit
768582d8d3

+ 7 - 0
toolchain/base/clang_invocation.cpp

@@ -118,6 +118,13 @@ auto AppendDefaultClangArgs(const InstallPaths& install_paths,
       // TODO: Decide if we want this.
       // TODO: Decide if we want this.
       "-fPIE",
       "-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.
       // Override runtime library defaults.
       //
       //
       // TODO: We should consider if there is a reasonable way to build Clang
       // TODO: We should consider if there is a reasonable way to build Clang

+ 21 - 7
toolchain/driver/compile_subcommand.cpp

@@ -492,7 +492,7 @@ class CompilationUnit {
   auto RunLower() -> void;
   auto RunLower() -> void;
 
 
   // Runs the optimization pipeline.
   // 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
   // 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,
   // lowering work, after we've finished building the IR in RunLower() and,
@@ -538,7 +538,8 @@ class CompilationUnit {
   auto IncludeInDumps() -> bool;
   auto IncludeInDumps() -> bool;
 
 
   // Builds the LLVM target machine.
   // Builds the LLVM target machine.
-  auto MakeTargetMachine() -> void;
+  auto MakeTargetMachine(const clang::CompilerInvocation& clang_invocation)
+      -> void;
 
 
   // The index of the unit amongst all units.
   // The index of the unit amongst all units.
   SemIR::CheckIRId check_ir_id_;
   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(module_, "Must call RunLower first");
   CARBON_CHECK(!target_machine_, "Should not call this multiple times");
   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 CPU = "generic";
   constexpr llvm::StringLiteral Features = "";
   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;
   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_machine_.reset(target_->createTargetMachine(
       target_triple, CPU, Features, target_opts, llvm::Reloc::PIC_));
       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");
   CARBON_CHECK(module_, "Must call RunLower first");
 
 
   // TODO: A lot of the work done here duplicates work done by Clang setting up
   // 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
   // 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.
   // 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
   // TODO: There's no way to set these automatically from an
   // llvm::OptimizationLevel. Add such a mechanism to LLVM and use it from
   // 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
   // Build a clang invocation. We do this regardless of whether we're running
   // check, because this is essentially performing further option validation,
   // check, because this is essentially performing further option validation,
   // and we generally validate all options even if we're not using them for the
   // 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`
   // TODO: Share any arguments we specify here with the `carbon clang`
   // subcommand.
   // subcommand.
   {
   {
@@ -1283,7 +1297,7 @@ auto CompileSubcommand::Run(DriverEnv& driver_env) -> DriverResult {
     unit->RunLower();
     unit->RunLower();
 
 
     if (options_.phase != CompileOptions::Phase::Lower) {
     if (options_.phase != CompileOptions::Phase::Lower) {
-      unit->RunOptimize();
+      unit->RunOptimize(*clang_invocation);
     }
     }
 
 
     unit->PostLower();
     unit->PostLower();

+ 24 - 0
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

+ 23 - 0
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