diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2790,7 +2790,7 @@ NegFlag>; def fbasic_block_sections_EQ : Joined<["-"], "fbasic-block-sections=">, Group, Flags<[CC1Option, CC1AsOption]>, - HelpText<"Place each function's basic blocks in unique sections (ELF Only) : all | labels | none | list=">, + HelpText<"Place each function's basic blocks in unique sections (ELF and COFF Only) : all | labels | none | list=">, DocBrief<[{Generate labels for each basic block or place each basic block or a subset of basic blocks in its own section.}]>, Values<"all,labels,none,list=">, MarshallingInfoString, [{"none"}]>; @@ -2810,7 +2810,7 @@ defm unique_basic_block_section_names : BoolFOption<"unique-basic-block-section-names", CodeGenOpts<"UniqueBasicBlockSectionNames">, DefaultFalse, - PosFlag, + PosFlag, NegFlag>; defm unique_internal_linkage_names : BoolFOption<"unique-internal-linkage-names", CodeGenOpts<"UniqueInternalLinkageNames">, DefaultFalse, diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -5319,7 +5319,8 @@ if (Arg *A = Args.getLastArg(options::OPT_fbasic_block_sections_EQ)) { StringRef Val = A->getValue(); - if (Triple.isX86() && Triple.isOSBinFormatELF()) { + if (Triple.isX86() && + (Triple.isOSBinFormatELF() || Triple.isOSBinFormatCOFF())) { if (Val != "all" && Val != "labels" && Val != "none" && !Val.startswith("list=")) D.Diag(diag::err_drv_invalid_value) diff --git a/clang/test/Driver/fbasic-block-sections.c b/clang/test/Driver/fbasic-block-sections.c --- a/clang/test/Driver/fbasic-block-sections.c +++ b/clang/test/Driver/fbasic-block-sections.c @@ -2,6 +2,7 @@ // RUN: %clang -### -target x86_64 -fbasic-block-sections=all %s -S 2>&1 | FileCheck -check-prefix=CHECK-OPT-ALL %s // RUN: %clang -### -target x86_64 -fbasic-block-sections=list=%s %s -S 2>&1 | FileCheck -check-prefix=CHECK-OPT-LIST %s // RUN: %clang -### -target x86_64 -fbasic-block-sections=labels %s -S 2>&1 | FileCheck -check-prefix=CHECK-OPT-LABELS %s +// RUN: %clang -### -target x86_64-windows-msvc -fbasic-block-sections=all %s -S 2>&1 | FileCheck -check-prefix=CHECK-OPT-ALL %s // RUN: not %clang -c -target arm-unknown-linux -fbasic-block-sections=all %s -S 2>&1 | FileCheck -check-prefix=CHECK-TRIPLE %s // RUN: %clang -### -target arm-unknown-linux -fbasic-block-sections=all -fbasic-block-sections=none %s -S 2>&1 \ // RUN: | FileCheck -check-prefix=CHECK-NOOPT %s diff --git a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h --- a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h +++ b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h @@ -174,6 +174,15 @@ MCSection *getSectionForJumpTable(const Function &F, const TargetMachine &TM) const override; + MCSection * + getSectionForMachineBasicBlock(const Function &F, + const MachineBasicBlock &MBB, + const TargetMachine &TM) const override; + + MCSection * + getUniqueSectionForFunction(const Function &F, + const TargetMachine &TM) const override; + /// Emit Obj-C garbage collection and linker options. void emitModuleMetadata(MCStreamer &Streamer, Module &M) const override; diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp --- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -1736,6 +1736,75 @@ COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE, UniqueID); } +/// Returns a unique section for the given machine basic block. +MCSection *TargetLoweringObjectFileCOFF::getSectionForMachineBasicBlock( + const Function &F, const MachineBasicBlock &MBB, + const TargetMachine &TM) const { + assert(MBB.isBeginSection() && "Basic block does not start a section!"); + SectionKind Kind = SectionKind::getText(); + unsigned Characteristics = getCOFFSectionFlags(Kind, TM); + // If we have -ffunction-sections then we should emit the global value to a + // uniqued section specifically for it. + if (TM.getFunctionSections() || F.hasComdat()) + Characteristics |= COFF::IMAGE_SCN_LNK_COMDAT; + unsigned UniqueID = MCContext::GenericSectionID; + + // Use a unique name, or a unique ID for the section. + StringRef COMDATSymName; + if (TM.getUniqueBasicBlockSectionNames()) + COMDATSymName = MBB.getSymbol()->getName(); + else { + UniqueID = NextUniqueID++; + COMDATSymName = MBB.getParent()->getName(); + } + + // TODO: construct cold section in the case of section ID of MBB is + // MBBSectionID::ColdSectionID + SmallString<128> Name; + Name += getCOFFSectionNameForUniqueGlobal(SectionKind::getText()); + + // Append "$symbol" to the section name *before* IR-level mangling is + // applied when targetting mingw. This is what GCC does, and the ld.bfd + // COFF linker will not properly handle comdats otherwise. + if (getContext().getTargetTriple().isWindowsGNUEnvironment()) { + Name += '$'; + Name += COMDATSymName; + } + + return getContext().getCOFFSection(Name, Characteristics, Kind, COMDATSymName, + COFF::IMAGE_COMDAT_SELECT_NODUPLICATES, + UniqueID); +} + +MCSection *TargetLoweringObjectFileCOFF::getUniqueSectionForFunction( + const Function &F, const TargetMachine &TM) const { + int Selection = 0; + SectionKind Kind = SectionKind::getText(); + unsigned Characteristics = getCOFFSectionFlags(Kind, TM); + // If we have -ffunction-sections then we should emit the global value to a + // uniqued section specifically for it. + if (TM.getFunctionSections() || F.hasComdat()) { + Characteristics |= COFF::IMAGE_SCN_LNK_COMDAT; + Selection = getSelectionForCOFF(&F); + if (!Selection) + Selection = COFF::IMAGE_COMDAT_SELECT_NODUPLICATES; + } + StringRef COMDATSymName = TM.getSymbol(&F)->getName(); + SmallString<128> Name; + Name += getCOFFSectionNameForUniqueGlobal(SectionKind::getText()); + + // Append "$symbol" to the section name *before* IR-level mangling is + // applied when targetting mingw. This is what GCC does, and the ld.bfd + // COFF linker will not properly handle comdats otherwise. + if (getContext().getTargetTriple().isWindowsGNUEnvironment()) { + Name += '$'; + Name += COMDATSymName; + } + + return getContext().getCOFFSection(Name, Characteristics, Kind, COMDATSymName, + Selection, NextUniqueID++); +} + void TargetLoweringObjectFileCOFF::emitModuleMetadata(MCStreamer &Streamer, Module &M) const { emitLinkerDirectives(Streamer, M); diff --git a/llvm/test/CodeGen/X86/basic-block-sections.ll b/llvm/test/CodeGen/X86/basic-block-sections.ll --- a/llvm/test/CodeGen/X86/basic-block-sections.ll +++ b/llvm/test/CodeGen/X86/basic-block-sections.ll @@ -3,6 +3,10 @@ ; RUN: llc < %s -mtriple=x86_64-pc-linux -function-sections -basic-block-sections=all -unique-basic-block-section-names -split-machine-functions | FileCheck %s -check-prefix=LINUX-SECTIONS ; RUN: llc < %s -mtriple=i386-unknown-linux-gnu -function-sections -basic-block-sections=all -unique-basic-block-section-names | FileCheck %s -check-prefix=LINUX-SECTIONS ; RUN: llc < %s -mtriple=i386-unknown-linux-gnu -basic-block-sections=all -unique-basic-block-section-names | FileCheck %s -check-prefix=LINUX-SECTIONS +; RUN: llc < %s -mtriple=x86_64-windows-msvc -function-sections -basic-block-sections=all -unique-basic-block-section-names | FileCheck %s -check-prefix=WINDOWS-MSVC-FUNCTION-SECTIONS +; RUN: llc < %s -mtriple=x86_64-windows-msvc -basic-block-sections=all -unique-basic-block-section-names | FileCheck %s -check-prefix=WINDOWS-MSVC-SECTIONS +; RUN: llc < %s -mtriple=x86_64-windows-gnu -function-sections -basic-block-sections=all -unique-basic-block-section-names | FileCheck %s -check-prefix=WINDOWS-GNU-FUNCTION-SECTIONS +; RUN: llc < %s -mtriple=x86_64-windows-gnu -basic-block-sections=all -unique-basic-block-section-names | FileCheck %s -check-prefix=WINDOWS-GNU-SECTIONS define void @_Z3bazb(i1 zeroext) nounwind { %2 = alloca i8, align 1 @@ -39,3 +43,27 @@ ; LINUX-SECTIONS: [[SECTION_LABEL_2]]: ; LINUX-SECTIONS: .LBB_END0_2: ; LINUX-SECTIONS-NEXT: .size [[SECTION_LABEL_2]], .LBB_END0_2-[[SECTION_LABEL_2]] +; WINDOWS-MSVC-FUNCTION-SECTIONS: .section .text,"xr",one_only,_Z3bazb +; WINDOWS-MSVC-FUNCTION-SECTIONS: _Z3bazb: +; WINDOWS-MSVC-FUNCTION-SECTIONS: .section .text,"xr",one_only,[[SECTION_LABEL_1:_Z3bazb.__part.[0-9]+]] +; WINDOWS-MSVC-FUNCTION-SECTIONS: [[SECTION_LABEL_1]]: +; WINDOWS-MSVC-FUNCTION-SECTIONS: .section .text,"xr",one_only,[[SECTION_LABEL_2:_Z3bazb.__part.[0-9]+]] +; WINDOWS-MSVC-FUNCTION-SECTIONS: [[SECTION_LABEL_2]]: +; WINDOWS-MSVC-SECTIONS: .section .text,"xr" +; WINDOWS-MSVC-SECTIONS: _Z3bazb: +; WINDOWS-MSVC-SECTIONS: je [[SECTION_LABEL_2:_Z3bazb.__part.[0-9]+]] +; WINDOWS-MSVC-SECTIONS: jmp [[SECTION_LABEL_1:_Z3bazb.__part.[0-9]+]] +; WINDOWS-MSVC-SECTIONS: [[SECTION_LABEL_1]]: +; WINDOWS-MSVC-SECTIONS: [[SECTION_LABEL_2]]: +; WINDOWS-GNU-FUNCTION-SECTIONS: .section .text$_Z3bazb,"xr",one_only,_Z3bazb +; WINDOWS-GNU-FUNCTION-SECTIONS: _Z3bazb: +; WINDOWS-GNU-FUNCTION-SECTIONS: .section .text$[[SECTION_LABEL_1:_Z3bazb.__part.[0-9]+]],"xr",one_only,[[SECTION_LABEL_1]] +; WINDOWS-GNU-FUNCTION-SECTIONS: [[SECTION_LABEL_1]]: +; WINDOWS-GNU-FUNCTION-SECTIONS: .section .text$[[SECTION_LABEL_2:_Z3bazb.__part.[0-9]+]],"xr",one_only,[[SECTION_LABEL_2]] +; WINDOWS-GNU-FUNCTION-SECTIONS: [[SECTION_LABEL_2]]: +; WINDOWS-GNU-SECTIONS: .section .text$_Z3bazb,"xr" +; WINDOWS-GNU-SECTIONS: _Z3bazb: +; WINDOWS-GNU-SECTIONS: .section .text$[[SECTION_LABEL_1:_Z3bazb.__part.[0-9]+]],"xr" +; WINDOWS-GNU-SECTIONS: [[SECTION_LABEL_1]]: +; WINDOWS-GNU-SECTIONS: .section .text$[[SECTION_LABEL_2:_Z3bazb.__part.[0-9]+]],"xr" +; WINDOWS-GNU-SECTIONS: [[SECTION_LABEL_2]]: