diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst --- a/llvm/docs/ReleaseNotes.rst +++ b/llvm/docs/ReleaseNotes.rst @@ -99,7 +99,9 @@ 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 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,103 @@ +; RUN: llc -mtriple powerpc-ibm-aix-xcoff -mroptr < %s | FileCheck %s +; RUN: not llc -mtriple powerpc-ibm-aix-xcoff -mroptr -data-sections=false \ +; RUN: < %s 2>&1 | FileCheck %s --check-prefix=DS_ERR +; RUN: llc -mtriple powerpc-ibm-aix-xcoff -mroptr -filetype=obj -o %t.o < %s +; RUN: llvm-objdump -t %t.o | FileCheck %s --check-prefix=OBJ + +; DS_ERR: -mroptr option must be used with -data-sections. + +%union.U = type { %"struct.U::A" } +%"struct.U::A" = type { ptr } +%struct.DD = type { %struct.BB, %struct.CC } +%struct.BB = type { %struct.AA } +%struct.AA = type { ptr } +%struct.CC = type { %struct.AA } + +@_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: 000001a8 l .text 00000004 _ZL1p +;OBJ: 000001ac g .text 00000004 u +;OBJ: 00000294 g O .data 00000008 dd +@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: 0000030c l O .data 00000004 .q +;OBJ-NEXT: 00000310 l O .data 00000004 q +;OBJ-NEXT: 00000000 g O .tdata 00000004 q +@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] +@dd = global %struct.DD zeroinitializer, align 4 +;CHECK: .csect dd[RW],2 +;CHECK-NEXT: .globl dd[RW] +;CHECK-NEXT: .align 2 +;CHECK-NEXT: .space 8 +@_ZTV2DD = linkonce_odr unnamed_addr constant { [5 x ptr], [5 x ptr] } { [5 x ptr] [ptr null, ptr null, ptr null, ptr @_ZTI2DD, ptr @_ZN2DD1fEv], [5 x ptr] [ptr inttoptr (i32 -4 to ptr), ptr inttoptr (i32 -4 to ptr), ptr inttoptr (i32 -4 to ptr), ptr @_ZTI2DD, ptr @_ZThn4_N2DD1fEv] }, align 4 +@_ZTT2DD = linkonce_odr unnamed_addr constant [7 x ptr] [ptr getelementptr inbounds ({ [5 x ptr], [5 x ptr] }, ptr @_ZTV2DD, i32 0, inrange i32 0, i32 4), ptr getelementptr inbounds ({ [5 x ptr] }, ptr @_ZTC2DD0_2BB, i32 0, inrange i32 0, i32 4), ptr getelementptr inbounds ({ [5 x ptr] }, ptr @_ZTC2DD0_2BB, i32 0, inrange i32 0, i32 4), ptr getelementptr inbounds ({ [5 x ptr], [4 x ptr] }, ptr @_ZTC2DD4_2CC, i32 0, inrange i32 0, i32 4), ptr getelementptr inbounds ({ [5 x ptr], [4 x ptr] }, ptr @_ZTC2DD4_2CC, i32 0, inrange i32 1, i32 3), ptr getelementptr inbounds ({ [5 x ptr], [5 x ptr] }, ptr @_ZTV2DD, i32 0, inrange i32 0, i32 4), ptr getelementptr inbounds ({ [5 x ptr], [5 x ptr] }, ptr @_ZTV2DD, i32 0, inrange i32 1, i32 4)], align 4 +@_ZTC2DD0_2BB = linkonce_odr unnamed_addr constant { [5 x ptr] } { [5 x ptr] [ptr null, ptr null, ptr null, ptr @_ZTI2BB, ptr @_ZN2BB1fEv] }, align 4 +@_ZTVN10__cxxabiv121__vmi_class_type_infoE = external global ptr +@_ZTS2BB = linkonce_odr constant [4 x i8] c"2BB\00", align 1 +@_ZTVN10__cxxabiv117__class_type_infoE = external global ptr +@_ZTS2AA = linkonce_odr constant [4 x i8] c"2AA\00", align 1 +@_ZTI2AA = linkonce_odr constant { ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv117__class_type_infoE, i32 2), ptr @_ZTS2AA }, align 4 +@_ZTI2BB = linkonce_odr constant { ptr, ptr, i32, i32, ptr, i32 } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv121__vmi_class_type_infoE, i32 2), ptr @_ZTS2BB, i32 0, i32 1, ptr @_ZTI2AA, i32 -4093 }, align 4 +@_ZTC2DD4_2CC = linkonce_odr unnamed_addr constant { [5 x ptr], [4 x ptr] } { [5 x ptr] [ptr inttoptr (i32 -4 to ptr), ptr null, ptr null, ptr @_ZTI2CC, ptr @_ZN2CC1fEv], [4 x ptr] [ptr inttoptr (i32 4 to ptr), ptr inttoptr (i32 4 to ptr), ptr @_ZTI2CC, ptr @_ZTv0_n12_N2CC1fEv] }, align 4 +@_ZTS2CC = linkonce_odr constant [4 x i8] c"2CC\00", align 1 +@_ZTI2CC = linkonce_odr constant { ptr, ptr, i32, i32, ptr, i32 } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv121__vmi_class_type_infoE, i32 2), ptr @_ZTS2CC, i32 0, i32 1, ptr @_ZTI2AA, i32 -4093 }, align 4 +@_ZTS2DD = linkonce_odr constant [4 x i8] c"2DD\00", align 1 +@_ZTI2DD = linkonce_odr constant { ptr, ptr, i32, i32, ptr, i32, ptr, i32 } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv121__vmi_class_type_infoE, i32 2), ptr @_ZTS2DD, i32 2, i32 2, ptr @_ZTI2BB, i32 2, ptr @_ZTI2CC, i32 1026 }, align 4 +@llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__sub_I_roptr.cpp, ptr null }] + +declare void @_ZN2CCC2Ev(ptr noundef nonnull align 4 dereferenceable(4), ptr noundef) unnamed_addr + +define linkonce_odr void @_ZN2BB1fEv(ptr noundef nonnull align 4 dereferenceable(4) %this) unnamed_addr align 2 { +entry: + ret void +} + +define linkonce_odr void @_ZN2CC1fEv(ptr noundef nonnull align 4 dereferenceable(4) %this) unnamed_addr align 2 { +entry: + ret void +} + +define linkonce_odr void @_ZTv0_n12_N2CC1fEv(ptr noundef %this) unnamed_addr align 2 { +entry: + ret void +} + +define linkonce_odr void @_ZN2DD1fEv(ptr noundef nonnull align 4 dereferenceable(8) %this) unnamed_addr align 2 { +entry: + ret void +} + +define linkonce_odr void @_ZThn4_N2DD1fEv(ptr noundef %this) unnamed_addr align 2 { +entry: + ret void +} + +define internal void @_GLOBAL__sub_I_roptr.cpp() { +entry: + store ptr getelementptr inbounds ({ [5 x ptr] }, ptr @_ZTC2DD0_2BB, i32 0, inrange i32 0, i32 4), ptr @dd, align 4 + tail call void @_ZN2CCC2Ev(ptr noundef nonnull align 4 dereferenceable(4) getelementptr inbounds (%struct.DD, ptr @dd, i32 0, i32 1, i32 0, i32 0), ptr noundef nonnull getelementptr inbounds ([7 x ptr], ptr @_ZTT2DD, i32 0, i32 3)) + store ptr getelementptr inbounds ({ [5 x ptr], [5 x ptr] }, ptr @_ZTV2DD, i32 0, inrange i32 0, i32 4), ptr @dd, align 4 + store ptr getelementptr inbounds ({ [5 x ptr], [5 x ptr] }, ptr @_ZTV2DD, i32 0, inrange i32 1, i32 4), ptr getelementptr inbounds (%struct.DD, ptr @dd, i32 0, i32 1, i32 0, i32 0), align 4 + ret void +} + +define weak_odr hidden noundef ptr @_ZTW1q() local_unnamed_addr { + %1 = tail call align 4 ptr @llvm.threadlocal.address.p0(ptr align 4 @q) + ret ptr %1 +} + +define void @_ZTH1q() local_unnamed_addr { + ret void +} + +declare nonnull ptr @llvm.threadlocal.address.p0(ptr nonnull) 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,107 @@ +; 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 %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 } +%struct.DD = type { %struct.BB, %struct.CC } +%struct.BB = type { %struct.AA } +%struct.AA = type { ptr } +%struct.CC = type { %struct.AA } + +@_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: 00000000000001a8 l .text 0000000000000008 _ZL1p +;OBJ: 00000000000001b0 g .text 0000000000000008 u +;OBJ: 0000000000000360 g O .data 0000000000000010 dd +@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: 0000000000000450 l O .data 0000000000000008 .q +;OBJ-NEXT: 0000000000000458 l O .data 0000000000000008 q +;OBJ-NEXT: 0000000000000000 g O .tdata 0000000000000008 q +@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] +@dd = global %struct.DD zeroinitializer, align 8 +;CHECK: .csect dd[RW],3 +;CHECK-NEXT: .globl dd[RW] +;CHECK-NEXT: .align 3 +;CHECK-NEXT: .space 16 +@_ZTV2DD = linkonce_odr unnamed_addr constant { [5 x ptr], [5 x ptr] } { [5 x ptr] [ptr null, ptr null, ptr null, ptr @_ZTI2DD, ptr @_ZN2DD1fEv], [5 x ptr] [ptr inttoptr (i64 -8 to ptr), ptr inttoptr (i64 -8 to ptr), ptr inttoptr (i64 -8 to ptr), ptr @_ZTI2DD, ptr @_ZThn8_N2DD1fEv] }, align 8 +@_ZTT2DD = linkonce_odr unnamed_addr constant [7 x ptr] [ptr getelementptr inbounds ({ [5 x ptr], [5 x ptr] }, ptr @_ZTV2DD, i32 0, inrange i32 0, i32 4), ptr getelementptr inbounds ({ [5 x ptr] }, ptr @_ZTC2DD0_2BB, i32 0, inrange i32 0, i32 4), ptr getelementptr inbounds ({ [5 x ptr] }, ptr @_ZTC2DD0_2BB, i32 0, inrange i32 0, i32 4), ptr getelementptr inbounds ({ [5 x ptr], [4 x ptr] }, ptr @_ZTC2DD8_2CC, i32 0, inrange i32 0, i32 4), ptr getelementptr inbounds ({ [5 x ptr], [4 x ptr] }, ptr @_ZTC2DD8_2CC, i32 0, inrange i32 1, i32 3), ptr getelementptr inbounds ({ [5 x ptr], [5 x ptr] }, ptr @_ZTV2DD, i32 0, inrange i32 0, i32 4), ptr getelementptr inbounds ({ [5 x ptr], [5 x ptr] }, ptr @_ZTV2DD, i32 0, inrange i32 1, i32 4)], align 8 +@_ZTC2DD0_2BB = linkonce_odr unnamed_addr constant { [5 x ptr] } { [5 x ptr] [ptr null, ptr null, ptr null, ptr @_ZTI2BB, ptr @_ZN2BB1fEv] }, align 8 +@_ZTVN10__cxxabiv121__vmi_class_type_infoE = external global ptr +@_ZTS2BB = linkonce_odr constant [4 x i8] c"2BB\00", align 1 +@_ZTVN10__cxxabiv117__class_type_infoE = external global ptr +@_ZTS2AA = linkonce_odr constant [4 x i8] c"2AA\00", align 1 +@_ZTI2AA = linkonce_odr constant { ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv117__class_type_infoE, i64 2), ptr @_ZTS2AA }, align 8 +@_ZTI2BB = linkonce_odr constant { ptr, ptr, i32, i32, ptr, i64 } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv121__vmi_class_type_infoE, i64 2), ptr @_ZTS2BB, i32 0, i32 1, ptr @_ZTI2AA, i64 -8189 }, align 8 +@_ZTC2DD8_2CC = linkonce_odr unnamed_addr constant { [5 x ptr], [4 x ptr] } { [5 x ptr] [ptr inttoptr (i64 -8 to ptr), ptr null, ptr null, ptr @_ZTI2CC, ptr @_ZN2CC1fEv], [4 x ptr] [ptr inttoptr (i64 8 to ptr), ptr inttoptr (i64 8 to ptr), ptr @_ZTI2CC, ptr @_ZTv0_n24_N2CC1fEv] }, align 8 +@_ZTS2CC = linkonce_odr constant [4 x i8] c"2CC\00", align 1 +@_ZTI2CC = linkonce_odr constant { ptr, ptr, i32, i32, ptr, i64 } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv121__vmi_class_type_infoE, i64 2), ptr @_ZTS2CC, i32 0, i32 1, ptr @_ZTI2AA, i64 -8189 }, align 8 +@_ZTS2DD = linkonce_odr constant [4 x i8] c"2DD\00", align 1 +@_ZTI2DD = linkonce_odr constant { ptr, ptr, i32, i32, ptr, i64, ptr, i64 } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv121__vmi_class_type_infoE, i64 2), ptr @_ZTS2DD, i32 2, i32 2, ptr @_ZTI2BB, i64 2, ptr @_ZTI2CC, i64 2050 }, align 8 +@llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__sub_I_roptr.cpp, ptr null }] + +declare void @_ZN2CCC2Ev(ptr noundef nonnull align 8 dereferenceable(8), ptr noundef) unnamed_addr + +define linkonce_odr void @_ZN2BB1fEv(ptr noundef nonnull align 8 dereferenceable(8) %this) unnamed_addr align 2 { +entry: + ret void +} + +define linkonce_odr void @_ZN2CC1fEv(ptr noundef nonnull align 8 dereferenceable(8) %this) unnamed_addr align 2 { +entry: + ret void +} + +define linkonce_odr void @_ZTv0_n24_N2CC1fEv(ptr noundef %this) unnamed_addr align 2 { +entry: + ret void +} + +define linkonce_odr void @_ZN2DD1fEv(ptr noundef nonnull align 8 dereferenceable(16) %this) unnamed_addr align 2 { +entry: + ret void +} + +define linkonce_odr void @_ZThn8_N2DD1fEv(ptr noundef %this) unnamed_addr align 2 { +entry: + ret void +} + +define internal void @_GLOBAL__sub_I_roptr.cpp() { +entry: + store ptr getelementptr inbounds ({ [5 x ptr] }, ptr @_ZTC2DD0_2BB, i64 0, inrange i32 0, i64 4), ptr @dd, align 8 + tail call void @_ZN2CCC2Ev(ptr noundef nonnull align 8 dereferenceable(8) getelementptr inbounds (%struct.DD, ptr @dd, i64 0, i32 1, i32 0, i32 0), ptr noundef nonnull getelementptr inbounds ([7 x ptr], ptr @_ZTT2DD, i64 0, i64 3)) + store ptr getelementptr inbounds ({ [5 x ptr], [5 x ptr] }, ptr @_ZTV2DD, i64 0, inrange i32 0, i64 4), ptr @dd, align 8 + store ptr getelementptr inbounds ({ [5 x ptr], [5 x ptr] }, ptr @_ZTV2DD, i64 0, inrange i32 1, i64 4), ptr getelementptr inbounds (%struct.DD, ptr @dd, i64 0, i32 1, i32 0, i32 0), align 8 + ret void +} + +define weak_odr hidden noundef ptr @_ZTW1q() local_unnamed_addr { + %1 = tail call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 @q) + ret ptr %1 +} + +define void @_ZTH1q() local_unnamed_addr { + ret void +} + +declare nonnull ptr @llvm.threadlocal.address.p0(ptr nonnull) 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,16 @@ 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); + + if (!Options.DataSections) + reportError("-mroptr option must be used with -data-sections.", + InputFilename); + } + Options.BinutilsVersion = TargetMachine::parseBinutilsVersion(BinutilsVersion); Options.DisableIntegratedAS = NoIntegratedAssembler;