From 38e435895779c6f0e6c47a171f3b300ad99828b3 Mon Sep 17 00:00:00 2001 From: Arthur Eubanks Date: Tue, 28 Nov 2023 12:55:17 -0800 Subject: [PATCH] [X86] With large code model, put functions into .ltext with large section flag (#73037) So that when mixing small and large text, large text stays out of the way of the rest of the binary. This is useful for mixing precompiled small code model object files and built-from-source large code model binaries so that the the text sections don't get merged. --- llvm/include/llvm/Target/TargetMachine.h | 2 +- .../CodeGen/TargetLoweringObjectFileImpl.cpp | 15 ++------ llvm/lib/Target/TargetMachine.cpp | 12 +++++- llvm/lib/Target/X86/X86Subtarget.cpp | 38 ++++++------------- .../X86/code-model-elf-text-sections.ll | 25 ++++++++++++ llvm/test/CodeGen/X86/pcsections.ll | 22 +++++------ .../OrcLazy/debug-objects-elf-minimal.ll | 2 +- 7 files changed, 64 insertions(+), 52 deletions(-) create mode 100644 llvm/test/CodeGen/X86/code-model-elf-text-sections.ll diff --git a/llvm/include/llvm/Target/TargetMachine.h b/llvm/include/llvm/Target/TargetMachine.h index c1d05b25ea21f8..4830ecbe1cd634 100644 --- a/llvm/include/llvm/Target/TargetMachine.h +++ b/llvm/include/llvm/Target/TargetMachine.h @@ -239,7 +239,7 @@ class TargetMachine { void setCodeModel(CodeModel::Model CM) { CMModel = CM; } void setLargeDataThreshold(uint64_t LDT) { LargeDataThreshold = LDT; } - bool isLargeData(const GlobalVariable *GV) const; + bool isLargeGlobalObject(const GlobalObject *GO) const; bool isPositionIndependent() const; diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp index f3ba380818901c..143a4951c1361b 100644 --- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -616,7 +616,7 @@ static unsigned getEntrySizeForKind(SectionKind Kind) { /// DataSections. static StringRef getSectionPrefixForGlobal(SectionKind Kind, bool IsLarge) { if (Kind.isText()) - return ".text"; + return IsLarge ? ".ltext" : ".text"; if (Kind.isReadOnly()) return IsLarge ? ".lrodata" : ".rodata"; if (Kind.isBSS()) @@ -650,10 +650,7 @@ getELFSectionNameForGlobal(const GlobalObject *GO, SectionKind Kind, Name = ".rodata.cst"; Name += utostr(EntrySize); } else { - bool IsLarge = false; - if (auto *GV = dyn_cast(GO)) - IsLarge = TM.isLargeData(GV); - Name = getSectionPrefixForGlobal(Kind, IsLarge); + Name = getSectionPrefixForGlobal(Kind, TM.isLargeGlobalObject(GO)); } bool HasPrefix = false; @@ -773,12 +770,8 @@ getGlobalObjectInfo(const GlobalObject *GO, const TargetMachine &TM) { Group = C->getName(); IsComdat = C->getSelectionKind() == Comdat::Any; } - if (auto *GV = dyn_cast(GO)) { - if (TM.isLargeData(GV)) { - assert(TM.getTargetTriple().getArch() == Triple::x86_64); - Flags |= ELF::SHF_X86_64_LARGE; - } - } + if (TM.isLargeGlobalObject(GO)) + Flags |= ELF::SHF_X86_64_LARGE; return {Group, IsComdat, Flags}; } diff --git a/llvm/lib/Target/TargetMachine.cpp b/llvm/lib/Target/TargetMachine.cpp index 1cba8cf8004bfb..f7096b708b39de 100644 --- a/llvm/lib/Target/TargetMachine.cpp +++ b/llvm/lib/Target/TargetMachine.cpp @@ -39,13 +39,21 @@ TargetMachine::TargetMachine(const Target &T, StringRef DataLayoutString, TargetMachine::~TargetMachine() = default; -bool TargetMachine::isLargeData(const GlobalVariable *GV) const { - if (getTargetTriple().getArch() != Triple::x86_64 || GV->isThreadLocal()) +bool TargetMachine::isLargeGlobalObject(const GlobalObject *GO) const { + if (getTargetTriple().getArch() != Triple::x86_64) return false; if (getCodeModel() != CodeModel::Medium && getCodeModel() != CodeModel::Large) return false; + if (isa(GO)) + return getCodeModel() == CodeModel::Large; + + auto *GV = cast(GO); + + if (GV->isThreadLocal()) + return false; + // Allowing large metadata sections in the presence of an explicit section is // useful, even if GCC does not allow them. However, we should not mark // certain well-known prefixes as large, because it would make the whole diff --git a/llvm/lib/Target/X86/X86Subtarget.cpp b/llvm/lib/Target/X86/X86Subtarget.cpp index 085fdafa6b9f2c..a29801a96ca6ca 100644 --- a/llvm/lib/Target/X86/X86Subtarget.cpp +++ b/llvm/lib/Target/X86/X86Subtarget.cpp @@ -83,32 +83,18 @@ X86Subtarget::classifyLocalReference(const GlobalValue *GV) const { if (is64Bit()) { // 64-bit ELF PIC local references may use GOTOFF relocations. if (isTargetELF()) { - switch (TM.getCodeModel()) { - // 64-bit small code model is simple: All rip-relative. - case CodeModel::Tiny: - llvm_unreachable("Tiny codesize model not supported on X86"); - case CodeModel::Small: - case CodeModel::Kernel: - return X86II::MO_NO_FLAG; - - // The large PIC code model uses GOTOFF. - case CodeModel::Large: - return X86II::MO_GOTOFF; - - // Medium is a hybrid: RIP-rel for code and non-large data, GOTOFF for - // remaining DSO local data. - case CodeModel::Medium: - // Constant pool and jump table handling pass a nullptr to this - // function so we need to use isa_and_nonnull. - if (isa_and_nonnull(GV)) - return X86II::MO_NO_FLAG; // All code is RIP-relative - if (auto *GVar = dyn_cast_or_null(GV)) { - if (TM.isLargeData(GVar)) - return X86II::MO_GOTOFF; - } - return X86II::MO_NO_FLAG; // Local symbols use GOTOFF. - } - llvm_unreachable("invalid code model"); + CodeModel::Model CM = TM.getCodeModel(); + assert(CM != CodeModel::Tiny && + "Tiny codesize model not supported on X86"); + // Large objects use GOTOFF, otherwise use RIP-rel access. + if (auto *GO = dyn_cast_or_null(GV)) + return TM.isLargeGlobalObject(GO) ? X86II::MO_GOTOFF + : X86II::MO_NO_FLAG; + + // For non-GlobalObjects, the small and medium code models treat them as + // accessible with a RIP-rel access. The large code model uses GOTOFF to + // access everything that's not explicitly small. + return CM == CodeModel::Large ? X86II::MO_GOTOFF : X86II::MO_NO_FLAG; } // Otherwise, this is either a RIP-relative reference or a 64-bit movabsq, diff --git a/llvm/test/CodeGen/X86/code-model-elf-text-sections.ll b/llvm/test/CodeGen/X86/code-model-elf-text-sections.ll new file mode 100644 index 00000000000000..016c9a4d7b8390 --- /dev/null +++ b/llvm/test/CodeGen/X86/code-model-elf-text-sections.ll @@ -0,0 +1,25 @@ +; RUN: llc < %s -relocation-model=pic -filetype=obj -code-model=small -o %t +; RUN: llvm-readelf -S %t | FileCheck %s --check-prefix=SMALL +; RUN: llc < %s -relocation-model=pic -filetype=obj -code-model=medium -o %t +; RUN: llvm-readelf -S %t | FileCheck %s --check-prefix=SMALL +; RUN: llc < %s -relocation-model=pic -filetype=obj -code-model=large -o %t +; RUN: llvm-readelf -S %t | FileCheck %s --check-prefix=LARGE + +; RUN: llc < %s -relocation-model=pic -filetype=obj -code-model=small -function-sections -o %t +; RUN: llvm-readelf -S %t | FileCheck %s --check-prefix=SMALL-DS +; RUN: llc < %s -relocation-model=pic -filetype=obj -code-model=medium -function-sections -o %t +; RUN: llvm-readelf -S %t | FileCheck %s --check-prefix=SMALL-DS +; RUN: llc < %s -relocation-model=pic -filetype=obj -code-model=large -function-sections -o %t +; RUN: llvm-readelf -S %t | FileCheck %s --check-prefix=LARGE-DS + +; SMALL: .text {{.*}} AX {{.*}} +; SMALL-DS: .text.func {{.*}} AX {{.*}} +; LARGE: .ltext {{.*}} AXl {{.*}} +; LARGE-DS: .ltext.func {{.*}} AXl {{.*}} + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64--linux" + +define void @func() { + ret void +} diff --git a/llvm/test/CodeGen/X86/pcsections.ll b/llvm/test/CodeGen/X86/pcsections.ll index 00c1aba18cb43f..4fe70d93cf347b 100644 --- a/llvm/test/CodeGen/X86/pcsections.ll +++ b/llvm/test/CodeGen/X86/pcsections.ll @@ -19,12 +19,12 @@ define void @empty_no_aux() !pcsections !0 { ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: retq ; CHECK-NEXT: .Lfunc_end0: -; CHECK: .section section_no_aux,"awo",@progbits,.text +; CHECK: .section section_no_aux,"awo",@progbits,.{{l?}}text ; CHECK-NEXT: .Lpcsection_base0: ; DEFCM-NEXT: .long .Lfunc_begin0-.Lpcsection_base0 ; LARGE-NEXT: .quad .Lfunc_begin0-.Lpcsection_base0 ; CHECK-NEXT: .long .Lfunc_end0-.Lfunc_begin0 -; CHECK-NEXT: .text +; CHECK-NEXT: .{{l?}}text entry: ret void } @@ -35,7 +35,7 @@ define void @empty_aux() !pcsections !1 { ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: retq ; CHECK-NEXT: .Lfunc_end1: -; CHECK: .section section_aux,"awo",@progbits,.text +; CHECK: .section section_aux,"awo",@progbits,.{{l?}}text ; CHECK-NEXT: .Lpcsection_base1: ; DEFCM-NEXT: .long .Lfunc_begin1-.Lpcsection_base1 ; LARGE-NEXT: .quad .Lfunc_begin1-.Lpcsection_base1 @@ -43,7 +43,7 @@ define void @empty_aux() !pcsections !1 { ; CHECK-NEXT: .long 10 ; CHECK-NEXT: .long 20 ; CHECK-NEXT: .long 30 -; CHECK-NEXT: .text +; CHECK-NEXT: .{{l?}}text entry: ret void } @@ -56,22 +56,22 @@ define i64 @multiple() !pcsections !0 { ; CHECK-NEXT: movq ; CHECK-NEXT: retq ; CHECK-NEXT: .Lfunc_end2: -; CHECK: .section section_no_aux,"awo",@progbits,.text +; CHECK: .section section_no_aux,"awo",@progbits,.{{l?}}text ; CHECK-NEXT: .Lpcsection_base2: ; DEFCM-NEXT: .long .Lfunc_begin2-.Lpcsection_base2 ; LARGE-NEXT: .quad .Lfunc_begin2-.Lpcsection_base2 ; CHECK-NEXT: .long .Lfunc_end2-.Lfunc_begin2 -; CHECK-NEXT: .section section_aux_42,"awo",@progbits,.text +; CHECK-NEXT: .section section_aux_42,"awo",@progbits,.{{l?}}text ; CHECK-NEXT: .Lpcsection_base3: ; DEFCM-NEXT: .long .Lpcsection0-.Lpcsection_base3 ; LARGE-NEXT: .quad .Lpcsection0-.Lpcsection_base3 ; CHECK-NEXT: .long 42 -; CHECK-NEXT: .section section_aux_21264,"awo",@progbits,.text +; CHECK-NEXT: .section section_aux_21264,"awo",@progbits,.{{l?}}text ; CHECK-NEXT: .Lpcsection_base4: ; DEFCM-NEXT: .long .Lpcsection0-.Lpcsection_base4 ; LARGE-NEXT: .quad .Lpcsection0-.Lpcsection_base4 ; CHECK-NEXT: .long 21264 -; CHECK-NEXT: .text +; CHECK-NEXT: .{{l?}}text entry: %0 = load i64, ptr @bar, align 8, !pcsections !2 ret i64 %0 @@ -79,7 +79,7 @@ entry: define void @multiple_uleb128() !pcsections !6 { ; CHECK-LABEL: multiple_uleb128: -; CHECK: .section section_aux,"awo",@progbits,.text +; CHECK: .section section_aux,"awo",@progbits,.{{l?}}text ; CHECK-NEXT: .Lpcsection_base5: ; DEFCM-NEXT: .long .Lfunc_begin3-.Lpcsection_base5 ; LARGE-NEXT: .quad .Lfunc_begin3-.Lpcsection_base5 @@ -87,13 +87,13 @@ define void @multiple_uleb128() !pcsections !6 { ; CHECK-NEXT: .byte 42 ; CHECK-NEXT: .ascii "\345\216&" ; CHECK-NEXT: .byte 255 -; CHECK-NEXT: .section section_aux_21264,"awo",@progbits,.text +; CHECK-NEXT: .section section_aux_21264,"awo",@progbits,.{{l?}}text ; CHECK-NEXT: .Lpcsection_base6: ; DEFCM-NEXT: .long .Lfunc_begin3-.Lpcsection_base6 ; LARGE-NEXT: .quad .Lfunc_begin3-.Lpcsection_base6 ; CHECK-NEXT: .long .Lfunc_end3-.Lfunc_begin3 ; CHECK-NEXT: .long 21264 -; CHECK-NEXT: .text +; CHECK-NEXT: .{{l?}}text entry: ret void } diff --git a/llvm/test/ExecutionEngine/OrcLazy/debug-objects-elf-minimal.ll b/llvm/test/ExecutionEngine/OrcLazy/debug-objects-elf-minimal.ll index 0d5aba376080a3..d7bc2dc117b7f7 100644 --- a/llvm/test/ExecutionEngine/OrcLazy/debug-objects-elf-minimal.ll +++ b/llvm/test/ExecutionEngine/OrcLazy/debug-objects-elf-minimal.ll @@ -44,7 +44,7 @@ ; RUN: --generate=__dump_jit_debug_objects %s | llvm-objdump --section-headers - | \ ; RUN: FileCheck --check-prefix=CHECK_LOAD_ADDR %s ; -; CHECK_LOAD_ADDR-NOT: {{[0-9]*}} .text {{.*}} 0000000000000000 TEXT +; CHECK_LOAD_ADDR-NOT: {{[0-9]*}} .ltext {{.*}} 0000000000000000 TEXT target triple = "x86_64-unknown-unknown-elf"