diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst --- a/llvm/docs/ReleaseNotes.rst +++ b/llvm/docs/ReleaseNotes.rst @@ -102,7 +102,10 @@ Changes to the PowerPC Backend ------------------------------ -* ... +* A new option ``-mroptr`` is added to ``clang`` and ``llc``. When this option + is present, constant objects with relocatable address values are put into the + RO data section. The option is intended to be used with the ``-fdata-sections`` + option. The option is available on AIX. Changes to the RISC-V Backend ----------------------------- diff --git a/llvm/include/llvm/CodeGen/CommandFlags.h b/llvm/include/llvm/CodeGen/CommandFlags.h --- a/llvm/include/llvm/CodeGen/CommandFlags.h +++ b/llvm/include/llvm/CodeGen/CommandFlags.h @@ -145,6 +145,8 @@ bool getJMCInstrument(); +bool getReadOnlyPointers(); + /// Create this object with static storage to register codegen-related command /// line options. struct RegisterCodeGenFlags { diff --git a/llvm/include/llvm/Target/TargetOptions.h b/llvm/include/llvm/Target/TargetOptions.h --- a/llvm/include/llvm/Target/TargetOptions.h +++ b/llvm/include/llvm/Target/TargetOptions.h @@ -144,7 +144,7 @@ ValueTrackingVariableLocations(false), ForceDwarfFrameSection(false), XRayOmitFunctionIndex(false), DebugStrictDwarf(false), Hotpatch(false), PPCGenScalarMASSEntries(false), JMCInstrument(false), - EnableCFIFixup(false), MisExpect(false), + EnableCFIFixup(false), MisExpect(false), ReadOnlyPointers(false), FPDenormalMode(DenormalMode::IEEE, DenormalMode::IEEE) {} /// DisableFramePointerElim - This returns true if frame pointer elimination @@ -364,6 +364,10 @@ /// By default, it is set to false unsigned MisExpect : 1; + /// When set to true, const objects with relocatable address values are put + /// into the RO data section. + unsigned ReadOnlyPointers : 1; + /// Name of the stack usage file (i.e., .su file) if user passes /// -fstack-usage. If empty, it can be implied that -fstack-usage is not /// passed on the command line. diff --git a/llvm/lib/CodeGen/CommandFlags.cpp b/llvm/lib/CodeGen/CommandFlags.cpp --- a/llvm/lib/CodeGen/CommandFlags.cpp +++ b/llvm/lib/CodeGen/CommandFlags.cpp @@ -104,6 +104,7 @@ CGOPT(bool, DebugStrictDwarf) CGOPT(unsigned, AlignLoops) CGOPT(bool, JMCInstrument) +CGOPT(bool, ReadOnlyPointers) codegen::RegisterCodeGenFlags::RegisterCodeGenFlags() { #define CGBINDOPT(NAME) \ @@ -485,6 +486,13 @@ cl::init(false)); CGBINDOPT(JMCInstrument); + static cl::opt ReadOnlyPointers( + "mroptr", + cl::desc("When set to true, const objects with relocatable address " + "values are put into the RO data section."), + cl::init(false)); + CGBINDOPT(ReadOnlyPointers); + #undef CGBINDOPT mc::RegisterMCTargetOptionsFlags(); @@ -562,6 +570,7 @@ Options.DebugStrictDwarf = getDebugStrictDwarf(); Options.LoopAlignment = getAlignLoops(); Options.JMCInstrument = getJMCInstrument(); + Options.ReadOnlyPointers = getReadOnlyPointers(); Options.MCOptions = mc::InitMCTargetOptionsFromFlags(); 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 @@ -2316,8 +2316,10 @@ XCOFF::StorageMappingClass MappingClass; if (Kind.isText()) MappingClass = XCOFF::XMC_PR; - else if (Kind.isData() || Kind.isReadOnlyWithRel() || Kind.isBSS()) + else if (Kind.isData() || Kind.isBSS()) MappingClass = XCOFF::XMC_RW; + else if (Kind.isReadOnlyWithRel()) + MappingClass = TM.Options.ReadOnlyPointers ? XCOFF::XMC_RO : XCOFF::XMC_RW; else if (Kind.isReadOnly()) MappingClass = XCOFF::XMC_RO; else @@ -2402,9 +2404,16 @@ return TextSection; } - // TODO: We may put Kind.isReadOnlyWithRel() under option control, because - // user may want to have read-only data with relocations placed into a - // read-only section by the compiler. + if (TM.Options.ReadOnlyPointers && Kind.isReadOnlyWithRel()) { + assert(TM.getDataSections() && + "ReadOnlyPointers is supported only if data sections is turned on"); + SmallString<128> Name; + getNameWithPrefix(Name, GO, TM); + return getContext().getXCOFFSection( + Name, SectionKind::getReadOnly(), + XCOFF::CsectProperties(XCOFF::XMC_RO, XCOFF::XTY_SD)); + } + // For BSS kind, zero initialized data must be emitted to the .data section // because external linkage control sections that get mapped to the .bss // section will be linked as tentative defintions, which is only appropriate diff --git a/llvm/test/CodeGen/PowerPC/aix-xcoff-roptr.ll b/llvm/test/CodeGen/PowerPC/aix-xcoff-roptr.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/aix-xcoff-roptr.ll @@ -0,0 +1,30 @@ +; RUN: llc -mtriple powerpc-ibm-aix-xcoff -mroptr < %s | FileCheck %s +; RUN: llc -mtriple powerpc-ibm-aix-xcoff -mroptr -filetype=obj -o %t.o < %s +; RUN: llvm-objdump -t --symbol-description %t.o | FileCheck %s --check-prefix=OBJ + +; RUN: not llc -mtriple powerpc-ibm-aix-xcoff -mroptr -data-sections=false \ +; RUN: < %s 2>&1 | FileCheck %s --check-prefix=DS_ERR + +; DS_ERR: -mroptr option must be used with -data-sections + +%union.U = type { %"struct.U::A" } +%"struct.U::A" = type { ptr } + +@_ZL1p = internal constant i32 ptrtoint (ptr @_ZL1p to i32), align 4 +;CHECK: .csect _ZL1p[RO],2 +;CHECK-NEXT: .lglobl _ZL1p[RO] +;CHECK-NEXT: .align 2 +;CHECK-NEXT: .vbyte 4, _ZL1p[RO] +;OBJ-DAG: {{([[:xdigit:]]{8})}} l .text {{([[:xdigit:]]{8})}} (idx: {{[0-9]+}}) _ZL1p[RO] +@q = thread_local constant ptr @_ZL1p, align 4 +;CHECK: .csect q[TL],2 +;CHECK-NEXT: .globl q[TL] +;CHECK-NEXT: .align 2 +;CHECK-NEXT: .vbyte 4, _ZL1p[RO] +;OBJ-DAG: {{([[:xdigit:]]{8})}} g O .tdata {{([[:xdigit:]]{8})}} (idx: {{[0-9]+}}) q[TL] +@u = local_unnamed_addr constant [1 x %union.U] [%union.U { %"struct.U::A" { ptr @_ZL1p } }], align 4 +;CHECK: .csect u[RO],2 +;CHECK-NEXT: .globl u[RO] +;CHECK-NEXT: .align 2 +;CHECK-NEXT: .vbyte 4, _ZL1p[RO] +;OBJ-DAG: {{([[:xdigit:]]{8})}} g .text {{([[:xdigit:]]{8})}} (idx: {{[0-9]+}}) u[RO] diff --git a/llvm/test/CodeGen/PowerPC/aix64-xcoff-roptr.ll b/llvm/test/CodeGen/PowerPC/aix64-xcoff-roptr.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/aix64-xcoff-roptr.ll @@ -0,0 +1,33 @@ +; RUN: llc -mtriple powerpc64-ibm-aix-xcoff -mroptr < %s | FileCheck %s +; RUN: llc -mtriple powerpc64-ibm-aix-xcoff -mroptr -filetype=obj -o %t.o < %s +; RUN: llvm-objdump -t --symbol-description %t.o | FileCheck %s --check-prefix=OBJ + +; RUN: not llc -mtriple powerpc64-ibm-aix-xcoff -mroptr -data-sections=false \ +; RUN: < %s 2>&1 | FileCheck %s --check-prefix=DS_ERR +; RUN: not llc -mtriple powerpc64le-unknown-linux-gnu -mroptr \ +; RUN: < %s 2>&1 | FileCheck %s --check-prefix=OS_ERR + +; DS_ERR: -mroptr option must be used with -data-sections +; OS_ERR: -mroptr option is only supported on AIX + +%union.U = type { %"struct.U::A" } +%"struct.U::A" = type { ptr } + +@_ZL1p = internal constant i64 ptrtoint (ptr @_ZL1p to i64), align 8 +;CHECK: .csect _ZL1p[RO],3 +;CHECK-NEXT: .lglobl _ZL1p[RO] +;CHECK-NEXT: .align 3 +;CHECK-NEXT: .vbyte 8, _ZL1p[RO] +;OBJ-DAG: {{([[:xdigit:]]{16})}} l .text {{([[:xdigit:]]{16})}} (idx: {{[0-9]+}}) _ZL1p[RO] +@q = thread_local constant ptr @_ZL1p, align 8 +;CHECK: .csect q[TL],3 +;CHECK-NEXT: .globl q[TL] +;CHECK-NEXT: .align 3 +;CHECK-NEXT: .vbyte 8, _ZL1p[RO] +;OBJ-DAG: {{([[:xdigit:]]{16})}} g O .tdata {{([[:xdigit:]]{16})}} (idx: {{[0-9]+}}) q[TL] +@u = local_unnamed_addr constant [1 x %union.U] [%union.U { %"struct.U::A" { ptr @_ZL1p } }], align 8 +;CHECK: .csect u[RO],3 +;CHECK-NEXT: .globl u[RO] +;CHECK-NEXT: .align 3 +;CHECK-NEXT: .vbyte 8, _ZL1p[RO] +;OBJ-DAG: {{([[:xdigit:]]{16})}} g .text {{([[:xdigit:]]{16})}} (idx: {{[0-9]+}}) u[RO] diff --git a/llvm/tools/llc/llc.cpp b/llvm/tools/llc/llc.cpp --- a/llvm/tools/llc/llc.cpp +++ b/llvm/tools/llc/llc.cpp @@ -496,6 +496,24 @@ TargetOptions Options; auto InitializeOptions = [&](const Triple &TheTriple) { Options = codegen::InitTargetOptionsFromCodeGenFlags(TheTriple); + + if (Options.ReadOnlyPointers) { + if (!TheTriple.isOSAIX()) + reportError("-mroptr option is only supported on AIX", InputFilename); + + // Since the stroage mapping class is specified per csect, + // without using data sections, it is ambiguous what exactly should + // be done for the read-only pointers. Using read-only pointers may cause + // other RO variables in the same csect to become RW when the linker acts + // upon `-bforceimprw`; therefore, we require that separate data sections + // are used in the presence of ReadOnlyPointers. We respect the setting of + // data-sections since we have not found reasons to do otherwise that + // overcome the user surprise of not respecting the setting. + if (!Options.DataSections) + reportError("-mroptr option must be used with -data-sections", + InputFilename); + } + Options.BinutilsVersion = TargetMachine::parseBinutilsVersion(BinutilsVersion); Options.DisableIntegratedAS = NoIntegratedAssembler;