This patch adds an `llc` option `-mroptr` to specify storage locations for constant pointers on AIX.
When the `-mroptr` option is specified, constant pointers, virtual function tables, and virtual type tables are placed in read-only storage. Otherwise, by default, pointers, virtual function tables, and virtual type tables are placed are placed in read/write storage.
https://reviews.llvm.org/D144190 enables the `-mroptr` option for `clang`.
Reviewed By: hubert.reinterpretcast, stephenpeckham, myhsu, MaskRay, serge-sans-paille
Differential Revision: https://reviews.llvm.org/D144189
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. This option should be used with the ``-fdata-sections``
+ option, and is not supported with ``-fno-data-sections``. The option is
+ only supported on AIX.
Changes to the RISC-V Backend
-----------------------------
bool getJMCInstrument();
+bool getXCOFFReadOnlyPointers();
+
/// Create this object with static storage to register codegen-related command
/// line options.
struct RegisterCodeGenFlags {
HonorSignDependentRoundingFPMathOption(false), NoZerosInBSS(false),
GuaranteedTailCallOpt(false), StackSymbolOrdering(true),
EnableFastISel(false), EnableGlobalISel(false), UseInitArray(false),
- DisableIntegratedAS(false),
- RelaxELFRelocations(true), FunctionSections(false),
- DataSections(false), IgnoreXCOFFVisibility(false),
- XCOFFTracebackTable(true), UniqueSectionNames(true),
- UniqueBasicBlockSectionNames(false), TrapUnreachable(false),
- NoTrapAfterNoreturn(false), TLSSize(0), EmulatedTLS(false),
- ExplicitEmulatedTLS(false), EnableIPRA(false),
+ DisableIntegratedAS(false), RelaxELFRelocations(true),
+ FunctionSections(false), DataSections(false),
+ IgnoreXCOFFVisibility(false), XCOFFTracebackTable(true),
+ UniqueSectionNames(true), UniqueBasicBlockSectionNames(false),
+ TrapUnreachable(false), NoTrapAfterNoreturn(false), TLSSize(0),
+ EmulatedTLS(false), ExplicitEmulatedTLS(false), EnableIPRA(false),
EmitStackSizeSection(false), EnableMachineOutliner(false),
EnableMachineFunctionSplitter(false), SupportsDefaultOutlining(false),
EmitAddrsig(false), EmitCallSiteInfo(false),
ValueTrackingVariableLocations(false), ForceDwarfFrameSection(false),
XRayOmitFunctionIndex(false), DebugStrictDwarf(false),
Hotpatch(false), PPCGenScalarMASSEntries(false), JMCInstrument(false),
- EnableCFIFixup(false), MisExpect(false),
+ EnableCFIFixup(false), MisExpect(false), XCOFFReadOnlyPointers(false),
FPDenormalMode(DenormalMode::IEEE, DenormalMode::IEEE) {}
/// DisableFramePointerElim - This returns true if frame pointer elimination
/// 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 XCOFFReadOnlyPointers : 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.
CGOPT(bool, DebugStrictDwarf)
CGOPT(unsigned, AlignLoops)
CGOPT(bool, JMCInstrument)
+CGOPT(bool, XCOFFReadOnlyPointers)
codegen::RegisterCodeGenFlags::RegisterCodeGenFlags() {
#define CGBINDOPT(NAME) \
cl::init(false));
CGBINDOPT(JMCInstrument);
+ static cl::opt<bool> XCOFFReadOnlyPointers(
+ "mroptr",
+ cl::desc("When set to true, const objects with relocatable address "
+ "values are put into the RO data section."),
+ cl::init(false));
+ CGBINDOPT(XCOFFReadOnlyPointers);
+
#undef CGBINDOPT
mc::RegisterMCTargetOptionsFlags();
Options.DebugStrictDwarf = getDebugStrictDwarf();
Options.LoopAlignment = getAlignLoops();
Options.JMCInstrument = getJMCInstrument();
+ Options.XCOFFReadOnlyPointers = getXCOFFReadOnlyPointers();
Options.MCOptions = mc::InitMCTargetOptionsFromFlags();
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.XCOFFReadOnlyPointers ? XCOFF::XMC_RO : XCOFF::XMC_RW;
else if (Kind.isReadOnly())
MappingClass = XCOFF::XMC_RO;
else
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.XCOFFReadOnlyPointers && Kind.isReadOnlyWithRel()) {
+ if (!TM.getDataSections())
+ report_fatal_error(
+ "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
--- /dev/null
+; 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: [[#]]) _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: [[#]]) 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: [[#]]) u[RO]
--- /dev/null
+; 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: [[#]]) _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: [[#]]) 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: [[#]]) u[RO]
TargetOptions Options;
auto InitializeOptions = [&](const Triple &TheTriple) {
Options = codegen::InitTargetOptionsFromCodeGenFlags(TheTriple);
+
+ if (Options.XCOFFReadOnlyPointers) {
+ if (!TheTriple.isOSAIX())
+ reportError("-mroptr option is only supported on AIX", InputFilename);
+
+ // Since the storage mapping class is specified per csect,
+ // without using data sections, it is less effective to use 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;