From d5d761e2610f5860c6d8305bf6fbb33ef09e6709 Mon Sep 17 00:00:00 2001 From: Abid Qadeer Date: Tue, 26 May 2026 17:17:34 +0100 Subject: [PATCH 1/2] [flang] Support -ffunction-sections and -fdata-sections Wire the flags through the driver, frontend, and TargetMachine, and add driver and codegen lit tests. --- clang/include/clang/Options/Options.td | 8 ++-- clang/lib/Driver/ToolChains/Flang.cpp | 12 ++++++ .../include/flang/Frontend/CodeGenOptions.def | 3 ++ flang/lib/Frontend/CompilerInstance.cpp | 2 + flang/lib/Frontend/CompilerInvocation.cpp | 8 ++++ .../Driver/code-gen-function-sections.f90 | 32 +++++++++++++++ flang/test/Driver/function-sections.f90 | 39 +++++++++++++++++++ 7 files changed, 100 insertions(+), 4 deletions(-) create mode 100644 flang/test/Driver/code-gen-function-sections.f90 create mode 100644 flang/test/Driver/function-sections.f90 diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 025e8e7d7d761..8451a3698ef17 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -4832,9 +4832,9 @@ defm zero_initialized_in_bss : BoolFOption<"zero-initialized-in-bss", PosFlag>; defm function_sections : BoolFOption<"function-sections", CodeGenOpts<"FunctionSections">, DefaultFalse, - PosFlag, - NegFlag>; + NegFlag>; defm basic_block_address_map : BoolFOption<"basic-block-address-map", CodeGenOpts<"BBAddrMap">, DefaultFalse, PosFlag, @@ -4847,9 +4847,9 @@ def fbasic_block_sections_EQ : Joined<["-"], "fbasic-block-sections=">, Group, [{"none"}]>; defm data_sections : BoolFOption<"data-sections", CodeGenOpts<"DataSections">, DefaultFalse, - PosFlag, - NegFlag>; + NegFlag>; defm experimental_call_graph_section : BoolFOption<"experimental-call-graph-section", CodeGenOpts<"CallGraphSection">, DefaultFalse, diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp index 892a455167205..255c9e9414ea8 100644 --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -262,6 +262,18 @@ void Flang::addCodegenOptions(const ArgList &Args, options::OPT_fstack_repack_arrays, options::OPT_fno_stack_repack_arrays, options::OPT_ftime_report, options::OPT_ftime_report_EQ, options::OPT_funroll_loops, options::OPT_fno_unroll_loops}); + + const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); + bool UseSeparateSections = isUseSeparateSections(Triple); + if (Args.hasFlag(options::OPT_ffunction_sections, + options::OPT_fno_function_sections, UseSeparateSections)) + CmdArgs.push_back("-ffunction-sections"); + + bool HasDefaultDataSections = Triple.isOSBinFormatXCOFF(); + if (Args.hasFlag(options::OPT_fdata_sections, options::OPT_fno_data_sections, + UseSeparateSections || HasDefaultDataSections)) + CmdArgs.push_back("-fdata-sections"); + if (Args.hasArg(options::OPT_fcoarray)) CmdArgs.push_back("-fcoarray"); } diff --git a/flang/include/flang/Frontend/CodeGenOptions.def b/flang/include/flang/Frontend/CodeGenOptions.def index 17b8e61649da9..d8bbb94bd8cde 100644 --- a/flang/include/flang/Frontend/CodeGenOptions.def +++ b/flang/include/flang/Frontend/CodeGenOptions.def @@ -35,6 +35,9 @@ CODEGENOPT(InstrumentFunctions, 1, 0) ///< Set when -finstrument_functions is CODEGENOPT(DisableIntegratedAS, 1, 0) ///< -no-integrated-as +CODEGENOPT(FunctionSections, 1, 0) ///< -ffunction-sections +CODEGENOPT(DataSections, 1, 0) ///< -fdata-sections + CODEGENOPT(IsPIE, 1, 0) ///< PIE level is the same as PIC Level. CODEGENOPT(PICLevel, 2, 0) ///< PIC level of the LLVM module. CODEGENOPT(PrepareForFatLTO , 1, 0) ///< Set when -ffat-lto-objects is enabled. diff --git a/flang/lib/Frontend/CompilerInstance.cpp b/flang/lib/Frontend/CompilerInstance.cpp index 3e820d386f8a9..7f562b1c39027 100644 --- a/flang/lib/Frontend/CompilerInstance.cpp +++ b/flang/lib/Frontend/CompilerInstance.cpp @@ -385,6 +385,8 @@ bool CompilerInstance::setUpTargetMachine() { tOpts.EnableAIXExtendedAltivecABI = targetOpts.EnableAIXExtendedAltivecABI; tOpts.VecLib = convertDriverVectorLibraryToVectorLibrary(CGOpts.getVecLib()); tOpts.DisableIntegratedAS = CGOpts.DisableIntegratedAS; + tOpts.FunctionSections = CGOpts.FunctionSections; + tOpts.DataSections = CGOpts.DataSections; targetMachine.reset(theTarget->createTargetMachine( triple, /*CPU=*/targetOpts.cpu, diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp index 9853fc600ff6a..cb6a7a85ad55f 100644 --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -360,6 +360,14 @@ static void parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts, clang::options::OPT_fno_integrated_as, true)) opts.DisableIntegratedAS = 1; + opts.FunctionSections = + args.hasFlag(clang::options::OPT_ffunction_sections, + clang::options::OPT_fno_function_sections, + /*Default=*/false); + opts.DataSections = args.hasFlag(clang::options::OPT_fdata_sections, + clang::options::OPT_fno_data_sections, + /*Default=*/false); + if (const llvm::opt::Arg *a = args.getLastArg(clang::options::OPT_mcode_object_version_EQ)) { llvm::StringRef s = a->getValue(); diff --git a/flang/test/Driver/code-gen-function-sections.f90 b/flang/test/Driver/code-gen-function-sections.f90 new file mode 100644 index 0000000000000..722d2537ee8d9 --- /dev/null +++ b/flang/test/Driver/code-gen-function-sections.f90 @@ -0,0 +1,32 @@ +! Test -ffunction-sections and -fdata-sections codegen (X86). + +! REQUIRES: x86-registered-target + +! RUN: %flang_fc1 -triple x86_64-unknown-linux-gnu -S -ffunction-sections \ +! RUN: -o - %s | FileCheck %s --check-prefix=FUNC-SECT +! RUN: %flang_fc1 -triple x86_64-unknown-linux-gnu -S -o - %s \ +! RUN: | FileCheck %s --check-prefix=FUNC-PLAIN + +! RUN: %flang_fc1 -triple x86_64-unknown-linux-gnu -S -fdata-sections \ +! RUN: -o - %s | FileCheck %s --check-prefix=DATA-SECT +! RUN: %flang_fc1 -triple x86_64-unknown-linux-gnu -S -o - %s \ +! RUN: | FileCheck %s --check-prefix=DATA-PLAIN + +module data_sect_mod + integer, save :: g = 1 +end module + +subroutine foo +end subroutine + +program test + use data_sect_mod + call foo +end program + +! FUNC-SECT: .section{{.*}}.text. +! FUNC-PLAIN-NOT: .section{{.*}}.text. + +! DATA-SECT: .section{{.*}}.data. +! DATA-PLAIN: .data +! DATA-PLAIN-NOT: .section{{.*}}.data. diff --git a/flang/test/Driver/function-sections.f90 b/flang/test/Driver/function-sections.f90 new file mode 100644 index 0000000000000..ff6a5fff1d13e --- /dev/null +++ b/flang/test/Driver/function-sections.f90 @@ -0,0 +1,39 @@ +! Test handling of -f(no-)function-sections and -f(no-)data-sections (driver). +! +! CHECK-FS: "-ffunction-sections" +! CHECK-NOFS-NOT: "-ffunction-sections" +! CHECK-DS: "-fdata-sections" +! CHECK-NODS-NOT: "-fdata-sections" + +! RUN: %flang -### -c --target=x86_64-unknown-linux-gnu %s 2>&1 \ +! RUN: | FileCheck %s --check-prefix=CHECK-NOFS --check-prefix=CHECK-NODS + +! RUN: %flang -### -c --target=x86_64-unknown-linux-gnu %s \ +! RUN: -ffunction-sections 2>&1 | FileCheck %s --check-prefix=CHECK-FS + +! RUN: %flang -### -c --target=x86_64-unknown-linux-gnu %s \ +! RUN: -fno-function-sections 2>&1 | FileCheck %s --check-prefix=CHECK-NOFS + +! RUN: %flang -### -c --target=x86_64-unknown-linux-gnu %s \ +! RUN: -ffunction-sections -fno-function-sections 2>&1 \ +! RUN: | FileCheck %s --check-prefix=CHECK-NOFS + +! RUN: %flang -### -c --target=x86_64-unknown-linux-gnu %s \ +! RUN: -fno-function-sections -ffunction-sections 2>&1 \ +! RUN: | FileCheck %s --check-prefix=CHECK-FS + +! RUN: %flang -### -c --target=x86_64-unknown-linux-gnu %s \ +! RUN: -fdata-sections 2>&1 | FileCheck %s --check-prefix=CHECK-DS + +! RUN: %flang -### -c --target=x86_64-unknown-linux-gnu %s \ +! RUN: -fno-data-sections 2>&1 | FileCheck %s --check-prefix=CHECK-NODS + +! RUN: %flang -### -c --target=x86_64-unknown-linux-gnu %s \ +! RUN: -fdata-sections -fno-data-sections 2>&1 \ +! RUN: | FileCheck %s --check-prefix=CHECK-NODS + +! RUN: %flang -### -c --target=x86_64-unknown-linux-gnu %s \ +! RUN: -fno-data-sections -fdata-sections 2>&1 \ +! RUN: | FileCheck %s --check-prefix=CHECK-DS + +end program From 857ccaf2ed35fecd225a0b6c065e7eff7c129dc7 Mon Sep 17 00:00:00 2001 From: Abid Qadeer Date: Fri, 29 May 2026 20:34:20 +0100 Subject: [PATCH 2/2] Handle review comments. 1. Use a shared helper to process -ffunction-sections and -fdata-sections that is used by both clang and flang. 2. Moved a test to Integratoin folder and also test aarch64 in it. 3. Remove target triple from driver test. Co-authored-by: Cursor --- clang/include/clang/Driver/CommonArgs.h | 5 +++ clang/lib/Driver/ToolChains/Clang.cpp | 13 +------ clang/lib/Driver/ToolChains/CommonArgs.cpp | 14 +++++++ clang/lib/Driver/ToolChains/Flang.cpp | 10 +---- .../Driver/code-gen-function-sections.f90 | 32 ---------------- flang/test/Driver/function-sections.f90 | 30 +++++++-------- flang/test/Integration/function-sections.f90 | 38 +++++++++++++++++++ 7 files changed, 72 insertions(+), 70 deletions(-) delete mode 100644 flang/test/Driver/code-gen-function-sections.f90 create mode 100644 flang/test/Integration/function-sections.f90 diff --git a/clang/include/clang/Driver/CommonArgs.h b/clang/include/clang/Driver/CommonArgs.h index 34b3d302fe189..cdadb824a8ac3 100644 --- a/clang/include/clang/Driver/CommonArgs.h +++ b/clang/include/clang/Driver/CommonArgs.h @@ -161,6 +161,11 @@ llvm::StringRef getLTOParallelism(const llvm::opt::ArgList &Args, bool areOptimizationsEnabled(const llvm::opt::ArgList &Args); bool isUseSeparateSections(const llvm::Triple &Triple); +/// Append -ffunction-sections / -fdata-sections to \p CmdArgs when the +/// corresponding flags are enabled (explicitly or by target default). +void addSeparateSectionFlags(const llvm::Triple &Triple, + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs); // Parse -mtls-dialect=. Return true if the target supports both general-dynamic // and TLSDESC, and TLSDESC is requested. bool isTLSDESCEnabled(const ToolChain &TC, const llvm::opt::ArgList &Args); diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 207b9e519a8ea..5468e26c87fa2 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -6356,12 +6356,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString("-crash-diagnostics-dir=" + Dir)); } - bool UseSeparateSections = isUseSeparateSections(Triple); - - if (Args.hasFlag(options::OPT_ffunction_sections, - options::OPT_fno_function_sections, UseSeparateSections)) { - CmdArgs.push_back("-ffunction-sections"); - } + addSeparateSectionFlags(Triple, Args, CmdArgs); if (Arg *A = Args.getLastArg(options::OPT_fbasic_block_address_map, options::OPT_fno_basic_block_address_map)) { @@ -6407,12 +6402,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } - bool HasDefaultDataSections = Triple.isOSBinFormatXCOFF(); - if (Args.hasFlag(options::OPT_fdata_sections, options::OPT_fno_data_sections, - UseSeparateSections || HasDefaultDataSections)) { - CmdArgs.push_back("-fdata-sections"); - } - Args.addOptOutFlag(CmdArgs, options::OPT_funique_section_names, options::OPT_fno_unique_section_names); Args.addOptInFlag(CmdArgs, options::OPT_fseparate_named_sections, diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index d0dab119fa6d8..47953bc3a23b5 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -946,6 +946,20 @@ bool tools::isUseSeparateSections(const llvm::Triple &Triple) { return Triple.isPS(); } +void tools::addSeparateSectionFlags(const llvm::Triple &Triple, + const ArgList &Args, + ArgStringList &CmdArgs) { + bool UseSeparateSections = isUseSeparateSections(Triple); + if (Args.hasFlag(options::OPT_ffunction_sections, + options::OPT_fno_function_sections, UseSeparateSections)) + CmdArgs.push_back("-ffunction-sections"); + + bool HasDefaultDataSections = Triple.isOSBinFormatXCOFF(); + if (Args.hasFlag(options::OPT_fdata_sections, options::OPT_fno_data_sections, + UseSeparateSections || HasDefaultDataSections)) + CmdArgs.push_back("-fdata-sections"); +} + bool tools::isTLSDESCEnabled(const ToolChain &TC, const llvm::opt::ArgList &Args) { const llvm::Triple &Triple = TC.getEffectiveTriple(); diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp index 255c9e9414ea8..6711be6e75da4 100644 --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -264,15 +264,7 @@ void Flang::addCodegenOptions(const ArgList &Args, options::OPT_funroll_loops, options::OPT_fno_unroll_loops}); const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); - bool UseSeparateSections = isUseSeparateSections(Triple); - if (Args.hasFlag(options::OPT_ffunction_sections, - options::OPT_fno_function_sections, UseSeparateSections)) - CmdArgs.push_back("-ffunction-sections"); - - bool HasDefaultDataSections = Triple.isOSBinFormatXCOFF(); - if (Args.hasFlag(options::OPT_fdata_sections, options::OPT_fno_data_sections, - UseSeparateSections || HasDefaultDataSections)) - CmdArgs.push_back("-fdata-sections"); + addSeparateSectionFlags(Triple, Args, CmdArgs); if (Args.hasArg(options::OPT_fcoarray)) CmdArgs.push_back("-fcoarray"); diff --git a/flang/test/Driver/code-gen-function-sections.f90 b/flang/test/Driver/code-gen-function-sections.f90 deleted file mode 100644 index 722d2537ee8d9..0000000000000 --- a/flang/test/Driver/code-gen-function-sections.f90 +++ /dev/null @@ -1,32 +0,0 @@ -! Test -ffunction-sections and -fdata-sections codegen (X86). - -! REQUIRES: x86-registered-target - -! RUN: %flang_fc1 -triple x86_64-unknown-linux-gnu -S -ffunction-sections \ -! RUN: -o - %s | FileCheck %s --check-prefix=FUNC-SECT -! RUN: %flang_fc1 -triple x86_64-unknown-linux-gnu -S -o - %s \ -! RUN: | FileCheck %s --check-prefix=FUNC-PLAIN - -! RUN: %flang_fc1 -triple x86_64-unknown-linux-gnu -S -fdata-sections \ -! RUN: -o - %s | FileCheck %s --check-prefix=DATA-SECT -! RUN: %flang_fc1 -triple x86_64-unknown-linux-gnu -S -o - %s \ -! RUN: | FileCheck %s --check-prefix=DATA-PLAIN - -module data_sect_mod - integer, save :: g = 1 -end module - -subroutine foo -end subroutine - -program test - use data_sect_mod - call foo -end program - -! FUNC-SECT: .section{{.*}}.text. -! FUNC-PLAIN-NOT: .section{{.*}}.text. - -! DATA-SECT: .section{{.*}}.data. -! DATA-PLAIN: .data -! DATA-PLAIN-NOT: .section{{.*}}.data. diff --git a/flang/test/Driver/function-sections.f90 b/flang/test/Driver/function-sections.f90 index ff6a5fff1d13e..7072d62a9d3e2 100644 --- a/flang/test/Driver/function-sections.f90 +++ b/flang/test/Driver/function-sections.f90 @@ -5,35 +5,31 @@ ! CHECK-DS: "-fdata-sections" ! CHECK-NODS-NOT: "-fdata-sections" -! RUN: %flang -### -c --target=x86_64-unknown-linux-gnu %s 2>&1 \ +! RUN: %flang -### %s 2>&1 \ ! RUN: | FileCheck %s --check-prefix=CHECK-NOFS --check-prefix=CHECK-NODS -! RUN: %flang -### -c --target=x86_64-unknown-linux-gnu %s \ -! RUN: -ffunction-sections 2>&1 | FileCheck %s --check-prefix=CHECK-FS +! RUN: %flang -### %s -ffunction-sections 2>&1 \ +! RUN: | FileCheck %s --check-prefix=CHECK-FS -! RUN: %flang -### -c --target=x86_64-unknown-linux-gnu %s \ -! RUN: -fno-function-sections 2>&1 | FileCheck %s --check-prefix=CHECK-NOFS +! RUN: %flang -### %s -fno-function-sections 2>&1 \ +! RUN: | FileCheck %s --check-prefix=CHECK-NOFS -! RUN: %flang -### -c --target=x86_64-unknown-linux-gnu %s \ -! RUN: -ffunction-sections -fno-function-sections 2>&1 \ +! RUN: %flang -### %s -ffunction-sections -fno-function-sections 2>&1 \ ! RUN: | FileCheck %s --check-prefix=CHECK-NOFS -! RUN: %flang -### -c --target=x86_64-unknown-linux-gnu %s \ -! RUN: -fno-function-sections -ffunction-sections 2>&1 \ +! RUN: %flang -### %s -fno-function-sections -ffunction-sections 2>&1 \ ! RUN: | FileCheck %s --check-prefix=CHECK-FS -! RUN: %flang -### -c --target=x86_64-unknown-linux-gnu %s \ -! RUN: -fdata-sections 2>&1 | FileCheck %s --check-prefix=CHECK-DS +! RUN: %flang -### %s -fdata-sections 2>&1 \ +! RUN: | FileCheck %s --check-prefix=CHECK-DS -! RUN: %flang -### -c --target=x86_64-unknown-linux-gnu %s \ -! RUN: -fno-data-sections 2>&1 | FileCheck %s --check-prefix=CHECK-NODS +! RUN: %flang -### %s -fno-data-sections 2>&1 \ +! RUN: | FileCheck %s --check-prefix=CHECK-NODS -! RUN: %flang -### -c --target=x86_64-unknown-linux-gnu %s \ -! RUN: -fdata-sections -fno-data-sections 2>&1 \ +! RUN: %flang -### %s -fdata-sections -fno-data-sections 2>&1 \ ! RUN: | FileCheck %s --check-prefix=CHECK-NODS -! RUN: %flang -### -c --target=x86_64-unknown-linux-gnu %s \ -! RUN: -fno-data-sections -fdata-sections 2>&1 \ +! RUN: %flang -### %s -fno-data-sections -fdata-sections 2>&1 \ ! RUN: | FileCheck %s --check-prefix=CHECK-DS end program diff --git a/flang/test/Integration/function-sections.f90 b/flang/test/Integration/function-sections.f90 new file mode 100644 index 0000000000000..02f5035fea034 --- /dev/null +++ b/flang/test/Integration/function-sections.f90 @@ -0,0 +1,38 @@ +! Test -ffunction-sections and -fdata-sections codegen. + +! DEFINE: %{triple} = +! DEFINE: %{check-func-sect} = %flang_fc1 -triple %{triple} -S -ffunction-sections -o - %s | FileCheck %s --check-prefix=FUNC-SECT +! DEFINE: %{check-func-plain} = %flang_fc1 -triple %{triple} -S -o - %s | FileCheck %s --check-prefix=FUNC-PLAIN +! DEFINE: %{check-data-sect} = %flang_fc1 -triple %{triple} -S -fdata-sections -o - %s | FileCheck %s --check-prefix=DATA-SECT +! DEFINE: %{check-data-plain} = %flang_fc1 -triple %{triple} -S -o - %s | FileCheck %s --check-prefix=DATA-PLAIN + +! REDEFINE: %{triple} = aarch64-unknown-linux-gnu +! RUN: %if aarch64-registered-target %{ %{check-func-sect} %} +! RUN: %if aarch64-registered-target %{ %{check-func-plain} %} +! RUN: %if aarch64-registered-target %{ %{check-data-sect} %} +! RUN: %if aarch64-registered-target %{ %{check-data-plain} %} + +! REDEFINE: %{triple} = x86_64-unknown-linux-gnu +! RUN: %if x86-registered-target %{ %{check-func-sect} %} +! RUN: %if x86-registered-target %{ %{check-func-plain} %} +! RUN: %if x86-registered-target %{ %{check-data-sect} %} +! RUN: %if x86-registered-target %{ %{check-data-plain} %} + +module data_sect_mod + integer, save :: g = 1 +end module + +subroutine foo +end subroutine + +program test + use data_sect_mod + call foo +end program + +! FUNC-SECT: .section{{.*}}.text. +! FUNC-PLAIN-NOT: .section{{.*}}.text. + +! DATA-SECT: .section{{.*}}.data. +! DATA-PLAIN: .data +! DATA-PLAIN-NOT: .section{{.*}}.data.