Index: include/clang/Basic/LangOptions.h =================================================================== --- include/clang/Basic/LangOptions.h +++ include/clang/Basic/LangOptions.h @@ -20,6 +20,7 @@ #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/Sanitizers.h" #include "clang/Basic/Visibility.h" +#include "llvm/Support/CodeGen.h" #include #include @@ -48,7 +49,8 @@ class LangOptions : public LangOptionsBase { public: typedef clang::Visibility Visibility; - + typedef llvm::Reloc::Model RelocModel; + enum GCMode { NonGC, GCOnly, HybridGC }; enum StackProtectorMode { SSPOff, SSPOn, SSPStrong, SSPReq }; Index: include/clang/Basic/LangOptions.def =================================================================== --- include/clang/Basic/LangOptions.def +++ include/clang/Basic/LangOptions.def @@ -223,6 +223,7 @@ LANGOPT(ObjCWeak , 1, 0, "Objective-C __weak in ARC and MRC files") LANGOPT(ObjCSubscriptingLegacyRuntime , 1, 0, "Subscripting support in legacy ObjectiveC runtime") LANGOPT(FakeAddressSpaceMap , 1, 0, "OpenCL fake address space map") +ENUM_LANGOPT(RelocationModel , RelocModel, 3, llvm::Reloc::PIC_, "Relocation model") ENUM_LANGOPT(AddressSpaceMapMangling , AddrSpaceMapMangling, 2, ASMM_Target, "OpenCL address space map mangling mode") LANGOPT(IncludeDefaultHeader, 1, 0, "Include default header file for OpenCL") BENIGN_LANGOPT(DelayedTemplateParsing , 1, 0, "delayed template parsing") Index: include/clang/Frontend/CodeGenOptions.h =================================================================== --- include/clang/Frontend/CodeGenOptions.h +++ include/clang/Frontend/CodeGenOptions.h @@ -142,9 +142,6 @@ /// in the backend for setting the name in the skeleton cu. std::string SplitDwarfFile; - /// The name of the relocation model to use. - std::string RelocationModel; - /// The thread model to use std::string ThreadModel; Index: lib/AST/ExprConstant.cpp =================================================================== --- lib/AST/ExprConstant.cpp +++ lib/AST/ExprConstant.cpp @@ -1544,7 +1544,6 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc, QualType Type, const LValue &LVal) { bool IsReferenceType = Type->isReferenceType(); - APValue::LValueBase Base = LVal.getLValueBase(); const SubobjectDesignator &Designator = LVal.getLValueDesignator(); @@ -1564,6 +1563,42 @@ // Don't allow references to temporaries to escape. return false; } + + auto RM = Info.getLangOpts().getRelocationModel(); + bool IsROPI = RM == llvm::Reloc::ROPI_RWPI || RM == llvm::Reloc::ROPI; + bool IsRWPI = RM == llvm::Reloc::ROPI_RWPI || RM == llvm::Reloc::RWPI; + if (Base && (IsROPI || IsRWPI)) { + if (const ValueDecl *D = Base.dyn_cast()) { + assert((isa(D) || isa(D)) && + "unexpected ValueDecl type"); + bool IsConstTyped = D->getType().isConstant(Info.Ctx); + if (isa(D)) { + if ((IsRWPI && !IsConstTyped) || (IsROPI && IsConstTyped)) + return false; + } else if (IsROPI) // Check ROPI with FunctionDecl. + return false; + } + // Check if Base is a read-only expr (e.g. StringLiteral) or compound + // literals that can be mutable or constant. Here only C related exprs are + // checked since C++ is disabled for ropi/rwpi. + if (const Expr *E = Base.dyn_cast()) { + bool IsConstTyped = E->getType().isConstant(Info.Ctx); + switch (E->getStmtClass()) { + case Expr::CompoundLiteralExprClass: + if ((IsROPI && IsConstTyped) || (IsRWPI && !IsConstTyped)) + return false; + break; + case Expr::StringLiteralClass: + case Expr::PredefinedExprClass: + case Expr::AddrLabelExprClass: + if (IsROPI) + return false; + default: + break; + } + } + } + assert((Info.checkingPotentialConstantExpression() || LVal.getLValueCallIndex() == 0) && "have call index for global lvalue"); Index: lib/CodeGen/BackendUtil.cpp =================================================================== --- lib/CodeGen/BackendUtil.cpp +++ lib/CodeGen/BackendUtil.cpp @@ -509,17 +509,6 @@ std::string FeaturesStr = llvm::join(TargetOpts.Features.begin(), TargetOpts.Features.end(), ","); - // Keep this synced with the equivalent code in tools/driver/cc1as_main.cpp. - llvm::Optional RM; - RM = llvm::StringSwitch(CodeGenOpts.RelocationModel) - .Case("static", llvm::Reloc::Static) - .Case("pic", llvm::Reloc::PIC_) - .Case("ropi", llvm::Reloc::ROPI) - .Case("rwpi", llvm::Reloc::RWPI) - .Case("ropi-rwpi", llvm::Reloc::ROPI_RWPI) - .Case("dynamic-no-pic", llvm::Reloc::DynamicNoPIC); - assert(RM.hasValue() && "invalid PIC model!"); - CodeGenOpt::Level OptLevel; switch (CodeGenOpts.OptimizationLevel) { default: @@ -616,8 +605,9 @@ Options.MCOptions.IASSearchPaths.push_back( Entry.IgnoreSysRoot ? Entry.Path : HSOpts.Sysroot + Entry.Path); - TM.reset(TheTarget->createTargetMachine(Triple, TargetOpts.CPU, FeaturesStr, - Options, RM, CM, OptLevel)); + TM.reset(TheTarget->createTargetMachine( + Triple, TargetOpts.CPU, FeaturesStr, Options, + LangOpts.getRelocationModel(), CM, OptLevel)); } bool EmitAssemblyHelper::AddEmitPasses(legacy::PassManager &CodeGenPasses, Index: lib/Frontend/CodeGenOptions.cpp =================================================================== --- lib/Frontend/CodeGenOptions.cpp +++ lib/Frontend/CodeGenOptions.cpp @@ -16,8 +16,6 @@ #define CODEGENOPT(Name, Bits, Default) Name = Default; #define ENUM_CODEGENOPT(Name, Type, Bits, Default) set##Name(Default); #include "clang/Frontend/CodeGenOptions.def" - - RelocationModel = "pic"; memcpy(CoverageVersion, "402*", 4); } Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -610,7 +610,6 @@ Args.hasArg(OPT_cl_unsafe_math_optimizations) || Args.hasArg(OPT_cl_fast_relaxed_math); Opts.UnwindTables = Args.hasArg(OPT_munwind_tables); - Opts.RelocationModel = Args.getLastArgValue(OPT_mrelocation_model, "pic"); Opts.ThreadModel = Args.getLastArgValue(OPT_mthread_model, "posix"); if (Opts.ThreadModel != "posix" && Opts.ThreadModel != "single") Diags.Report(diag::err_drv_invalid_value) @@ -2008,6 +2007,19 @@ Opts.AlignDouble = Args.hasArg(OPT_malign_double); Opts.PICLevel = getLastArgIntValue(Args, OPT_pic_level, 0, Diags); Opts.PIE = Args.hasArg(OPT_pic_is_pie); + // Keep this synced with the equivalent code in tools/driver/cc1as_main.cpp. + llvm::Reloc::Model RM; + RM = llvm::StringSwitch( + Args.getLastArgValue(OPT_mrelocation_model, "pic")) + .Case("static", llvm::Reloc::Static) + .Case("pic", llvm::Reloc::PIC_) + .Case("ropi", llvm::Reloc::ROPI) + .Case("rwpi", llvm::Reloc::RWPI) + .Case("ropi-rwpi", llvm::Reloc::ROPI_RWPI) + .Case("dynamic-no-pic", llvm::Reloc::DynamicNoPIC) + .Default(llvm::Reloc::PIC_); + Opts.setRelocationModel(RM); + Opts.Static = Args.hasArg(OPT_static_define); Opts.DumpRecordLayoutsSimple = Args.hasArg(OPT_fdump_record_layouts_simple); Opts.DumpRecordLayouts = Opts.DumpRecordLayoutsSimple Index: test/CodeGen/arm-ropi-rwpi.c =================================================================== --- /dev/null +++ test/CodeGen/arm-ropi-rwpi.c @@ -0,0 +1,32 @@ +// REQUIRES: arm-registered-target + +// Below tests check if memcpy is not generated with ropi/rwpi for local var initialization. +// RUN: %clang_cc1 -triple armv7 -S -emit-llvm -o - %s | FileCheck %s --check-prefix=DEFAULT +// RUN: %clang_cc1 -triple armv7 -S -emit-llvm -mrelocation-model ropi -o - %s | FileCheck %s --check-prefix=ROPI +// RUN: %clang_cc1 -triple armv7 -S -emit-llvm -mrelocation-model rwpi -o - %s | FileCheck %s --check-prefix=RWPI +// RUN: %clang_cc1 -triple armv7 -S -emit-llvm -mrelocation-model ropi-rwpi -o - %s | FileCheck %s --check-prefix=ROPI_RWPI + +extern int gv; +extern const int c_gv; + +void test_local() { +// DEFAULT-LABEL: @test_local +// DEFAULT: call void @{{llvm.memcpy.*@test_local.x}} +// DEFAULT: call void @{{llvm.memcpy.*@test_local.y}} + +// ROPI-LABEL: @test_local +// ROPI: call void @{{llvm.memcpy.*@test_local.x}} +// ROPI-NOT: call void@llvm.memcpy + +// RWPI-LABEL: @test_local +// RWPI-NOT: call void@{{llvm.memcpy.*@test_local.x}} +// RWPI: call void @{{llvm.memcpy.*@test_local.y}} + +// ROPI_RWPI-LABEL: @test_local +// ROPI_RWPI-NOT: call void @llvm.memcpy + + const int *x[] = {&gv, &gv, &gv}; // This is OK, no diagnostic. + func(x); + const int *y[] = {&c_gv, &c_gv, &c_gv}; // This is OK, no diagnostic. + func(y); +} Index: test/Sema/ropi-rwpi.c =================================================================== --- /dev/null +++ test/Sema/ropi-rwpi.c @@ -0,0 +1,65 @@ +// OK with local initialization, rwpi with const gv and ropi with non-const gv. +// RUN: %clang_cc1 -triple armv7 -DDEFAULT -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple armv7 -DROPI -mrelocation-model ropi -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple armv7 -DRWPI -mrelocation-model rwpi -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple armv7 -DROPI -DRWPI -mrelocation-model ropi-rwpi -fsyntax-only -verify %s + +extern int func(const int* const []); + +extern int gv; +extern const int c_gv; + +void *p1 = &func; +const void *p2 = &c_gv; +const int *p_compound_literal_c = &(const int){1}; + +void ropi_test() { + static void *sp1 = &func; + static const void *sp2 = &c_gv; + static char(*x)[7] = &"abcdef"; + static const void *x2 = &__func__; + static const int *const arr[2] = {&c_gv, &c_gv}; + static void *addr = &&label1; +label1: + return; +} + +void *p3 = &gv; +int *p_compound_literal = &(int){1}; + +void rwpi_test() { + static void *sp1 = &gv; + static int *const arr[2] = {&gv, &gv}; +} + +unsigned test() { + unsigned a = (unsigned)&func; + unsigned b = (unsigned)&gv; + unsigned c = (unsigned)&c_gv; + return a + b + c; +} + +#ifdef DEFAULT +// expected-no-diagnostics +#endif + +#if defined(ROPI) +// expected-error@12 {{initializer element is not a compile-time constant}} +// expected-error@13 {{initializer element is not a compile-time constant}} +// expected-error@14 {{initializer element is not a compile-time constant}} + +// expected-error@17 {{initializer element is not a compile-time constant}} +// expected-error@18 {{initializer element is not a compile-time constant}} +// expected-error@19 {{initializer element is not a compile-time constant}} +// expected-error@20 {{initializer element is not a compile-time constant}} +// expected-error@21 {{initializer element is not a compile-time constant}} +// expected-error@22 {{initializer element is not a compile-time constant}} +#endif + +#if defined(RWPI) +// expected-error@27 {{initializer element is not a compile-time constant}} +// expected-error@28 {{initializer element is not a compile-time constant}} + +// expected-error@31 {{initializer element is not a compile-time constant}} +// expected-error@32 {{initializer element is not a compile-time constant}} +#endif