diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Basic/Targets/ARM.cpp | 32 | ||||
-rw-r--r-- | clang/lib/Basic/Targets/ARM.h | 3 | ||||
-rw-r--r-- | clang/lib/Driver/ToolChains/Arch/ARM.cpp | 38 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 2 |
4 files changed, 70 insertions, 5 deletions
diff --git a/clang/lib/Basic/Targets/ARM.cpp b/clang/lib/Basic/Targets/ARM.cpp index 437a77afdc9..92e5e26eba3 100644 --- a/clang/lib/Basic/Targets/ARM.cpp +++ b/clang/lib/Basic/Targets/ARM.cpp @@ -879,6 +879,38 @@ ArrayRef<TargetInfo::GCCRegAlias> ARMTargetInfo::getGCCRegAliases() const { return llvm::makeArrayRef(GCCRegAliases); } +bool ARMTargetInfo::validateGlobalRegisterVariable( + StringRef RegName, unsigned RegSize, bool &HasSizeMismatch) const { + bool isValid = llvm::StringSwitch<bool>(RegName) + .Case("r6", true) + .Case("r7", true) + .Case("r8", true) + .Case("r9", true) + .Case("r10", true) + .Case("r11", true) + .Case("sp", true) + .Default(false); + HasSizeMismatch = false; + return isValid; +} + +bool ARMTargetInfo::isRegisterReservedGlobally(StringRef RegName) const { + // The "sp" register does not have a -ffixed-sp option, + // so reserve it unconditionally. + if (RegName.equals("sp")) + return true; + + // reserve rN (N:6-11) registers only if the corresponding + // +reserve-rN feature is found + const std::vector<std::string> &Features = getTargetOpts().Features; + const std::string SearchFeature = "+reserve-" + RegName.str(); + for (const std::string &Feature : Features) { + if (Feature.compare(SearchFeature) == 0) + return true; + } + return false; +} + bool ARMTargetInfo::validateAsmConstraint( const char *&Name, TargetInfo::ConstraintInfo &Info) const { switch (*Name) { diff --git a/clang/lib/Basic/Targets/ARM.h b/clang/lib/Basic/Targets/ARM.h index ce87a626593..90fb20f8f7a 100644 --- a/clang/lib/Basic/Targets/ARM.h +++ b/clang/lib/Basic/Targets/ARM.h @@ -161,6 +161,9 @@ public: ArrayRef<const char *> getGCCRegNames() const override; ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override; + bool validateGlobalRegisterVariable(StringRef RegName, unsigned RegSize, + bool &HasSizeMismatch) const override; + bool isRegisterReservedGlobally(StringRef RegName) const override; bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override; std::string convertConstraint(const char *&Constraint) const override; diff --git a/clang/lib/Driver/ToolChains/Arch/ARM.cpp b/clang/lib/Driver/ToolChains/Arch/ARM.cpp index 68a57310ad4..cca47722c20 100644 --- a/clang/lib/Driver/ToolChains/Arch/ARM.cpp +++ b/clang/lib/Driver/ToolChains/Arch/ARM.cpp @@ -592,11 +592,39 @@ fp16_fml_fallthrough: Features.push_back("+strict-align"); } - // llvm does not support reserving registers in general. There is support - // for reserving r9 on ARM though (defined as a platform-specific register - // in ARM EABI). - if (Args.hasArg(options::OPT_ffixed_r9)) - Features.push_back("+reserve-r9"); + // Do not allow r9 reservation with -frwpi. + if (Args.hasArg(options::OPT_ffixed_r9) && Args.hasArg(options::OPT_frwpi)) { + Arg *A = Args.getLastArg(options::OPT_ffixed_r9); + Arg *B = Args.getLastArg(options::OPT_frwpi); + D.Diag(diag::err_opt_not_valid_with_opt) + << A->getAsString(Args) << B->getAsString(Args); + } + + // The compiler can still use a FP in certain circumstances, + // even when frame pointer elimination is enabled. Thus we should + // not allow to reserve a target's FP register. + const llvm::opt::OptSpecifier RestrictFPOpt = + (Triple.isOSDarwin() || (!Triple.isOSWindows() && Triple.isThumb())) + ? options::OPT_ffixed_r7 + : options::OPT_ffixed_r11; + if (Args.hasArg(RestrictFPOpt)) { + const std::string OptStr = + Args.getLastArg(RestrictFPOpt)->getAsString(Args); + const unsigned int SubStrIndex = strlen("ffixed-r"); + D.Diag(diag::err_reserved_frame_pointer) + << OptStr << OptStr.substr(SubStrIndex); + } + +// Reservation of general purpose registers. +#define HANDLE_FFIXED_R(n) \ + if (Args.hasArg(options::OPT_ffixed_r##n)) \ + Features.push_back("+reserve-r" #n) + HANDLE_FFIXED_R(6); + HANDLE_FFIXED_R(7); + HANDLE_FFIXED_R(8); + HANDLE_FFIXED_R(9); + HANDLE_FFIXED_R(10); + HANDLE_FFIXED_R(11); // The kext linker doesn't know how to deal with movw/movt. if (KernelOrKext || Args.hasArg(options::OPT_mno_movt)) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index aba7049b0a5..b469217108c 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -7009,6 +7009,8 @@ NamedDecl *Sema::ActOnVariableDeclarator( Diag(E->getExprLoc(), diag::err_asm_invalid_global_var_reg) << Label; else if (HasSizeMismatch) Diag(E->getExprLoc(), diag::err_asm_register_size_mismatch) << Label; + else if (!TI.isRegisterReservedGlobally(Label)) + Diag(E->getExprLoc(), diag::err_asm_missing_fixed_reg_opt) << Label; } if (!R->isIntegralType(Context) && !R->isPointerType()) { |