diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td --- a/clang/include/clang/Basic/DiagnosticCommonKinds.td +++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -145,6 +145,13 @@ def err_nullability_conflicting : Error< "nullability specifier %0 conflicts with existing specifier %1">; +def warn_target_unsupported_branch_protection_option: Warning < + "ignoring '-mbranch-protection=' option because the '%0' architecture does not support it">, + InGroup; + +def warn_target_unsupported_branch_protection_attribute: Warning < + "ignoring the 'branch-protection' attribute because the '%0' architecture does not support it">, + InGroup; } // OpenCL Section 6.8.g diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -1285,9 +1285,15 @@ bool BranchTargetEnforcement = false; }; + /// Determine if the Architecture in this TargetInfo supports branch + /// protection + virtual bool isBranchProtectionSupportedArch(StringRef Arch) const { + return false; + } + /// Determine if this TargetInfo supports the given branch protection /// specification - virtual bool validateBranchProtection(StringRef Spec, + virtual bool validateBranchProtection(StringRef Spec, StringRef Arch, BranchProtectionInfo &BPI, StringRef &Err) const { Err = ""; diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h --- a/clang/lib/Basic/Targets/AArch64.h +++ b/clang/lib/Basic/Targets/AArch64.h @@ -67,8 +67,9 @@ StringRef getABI() const override; bool setABI(const std::string &Name) override; - bool validateBranchProtection(StringRef, BranchProtectionInfo &, - StringRef &) const override; + bool validateBranchProtection(StringRef Spec, StringRef Arch, + BranchProtectionInfo &BPI, + StringRef &Err) const override; bool isValidCPUName(StringRef Name) const override; void fillValidCPUList(SmallVectorImpl &Values) const override; diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -138,7 +138,7 @@ return true; } -bool AArch64TargetInfo::validateBranchProtection(StringRef Spec, +bool AArch64TargetInfo::validateBranchProtection(StringRef Spec, StringRef, BranchProtectionInfo &BPI, StringRef &Err) const { llvm::ARM::ParsedBranchProtection PBP; diff --git a/clang/lib/Basic/Targets/ARM.h b/clang/lib/Basic/Targets/ARM.h --- a/clang/lib/Basic/Targets/ARM.h +++ b/clang/lib/Basic/Targets/ARM.h @@ -125,8 +125,10 @@ StringRef getABI() const override; bool setABI(const std::string &Name) override; - bool validateBranchProtection(StringRef, BranchProtectionInfo &, - StringRef &) const override; + bool isBranchProtectionSupportedArch(StringRef Arch) const override; + bool validateBranchProtection(StringRef Spec, StringRef Arch, + BranchProtectionInfo &BPI, + StringRef &Err) const override; // FIXME: This should be based on Arch attributes, not CPU names. bool diff --git a/clang/lib/Basic/Targets/ARM.cpp b/clang/lib/Basic/Targets/ARM.cpp --- a/clang/lib/Basic/Targets/ARM.cpp +++ b/clang/lib/Basic/Targets/ARM.cpp @@ -371,13 +371,32 @@ return false; } -bool ARMTargetInfo::validateBranchProtection(StringRef Spec, +bool ARMTargetInfo::isBranchProtectionSupportedArch(StringRef Arch) const { + llvm::ARM::ArchKind CPUArch = llvm::ARM::parseCPUArch(Arch); + if (CPUArch == llvm::ARM::ArchKind::INVALID) + CPUArch = llvm::ARM::parseArch(getTriple().getArchName()); + + if (CPUArch == llvm::ARM::ArchKind::INVALID) + return false; + + StringRef ArchFeature = llvm::ARM::getArchName(CPUArch); + auto a = llvm::Triple(ArchFeature, getTriple().getVendorName(), + getTriple().getOSName(), + getTriple().getEnvironmentName()); + + return a.isArmT32(); +} + +bool ARMTargetInfo::validateBranchProtection(StringRef Spec, StringRef Arch, BranchProtectionInfo &BPI, StringRef &Err) const { llvm::ARM::ParsedBranchProtection PBP; if (!llvm::ARM::parseBranchProtection(Spec, PBP, Err)) return false; + if (!isBranchProtectionSupportedArch(Arch)) + return false; + BPI.SignReturnAddr = llvm::StringSwitch(PBP.Scope) .Case("non-leaf", LangOptions::SignReturnAddressScopeKind::NonLeaf) diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -726,6 +726,7 @@ "tag-stack-memory-buildattr", 1); if (Arch == llvm::Triple::thumb || Arch == llvm::Triple::thumbeb || + Arch == llvm::Triple::arm || Arch == llvm::Triple::armeb || Arch == llvm::Triple::aarch64 || Arch == llvm::Triple::aarch64_32 || Arch == llvm::Triple::aarch64_be) { getModule().addModuleFlag(llvm::Module::Error, "branch-target-enforcement", @@ -737,11 +738,9 @@ getModule().addModuleFlag(llvm::Module::Error, "sign-return-address-all", LangOpts.isSignReturnAddressScopeAll()); - if (Arch != llvm::Triple::thumb && Arch != llvm::Triple::thumbeb) { - getModule().addModuleFlag(llvm::Module::Error, - "sign-return-address-with-bkey", - !LangOpts.isSignReturnAddressWithAKey()); - } + getModule().addModuleFlag(llvm::Module::Error, + "sign-return-address-with-bkey", + !LangOpts.isSignReturnAddressWithAKey()); } if (!CodeGenOpts.MemoryProfileOutput.empty()) { diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -5563,8 +5563,8 @@ TargetInfo::BranchProtectionInfo BPI; StringRef Error; - (void)CGM.getTarget().validateBranchProtection(Attr.BranchProtection, - BPI, Error); + (void)CGM.getTarget().validateBranchProtection( + Attr.BranchProtection, Attr.Architecture, BPI, Error); assert(Error.empty()); auto *Fn = cast(GV); @@ -6377,17 +6377,37 @@ if (!Attr.BranchProtection.empty()) { TargetInfo::BranchProtectionInfo BPI; StringRef DiagMsg; - (void)CGM.getTarget().validateBranchProtection(Attr.BranchProtection, - BPI, DiagMsg); - - static const char *SignReturnAddrStr[] = {"none", "non-leaf", "all"}; - assert(static_cast(BPI.SignReturnAddr) <= 2 && - "Unexpected SignReturnAddressScopeKind"); - Fn->addFnAttr("sign-return-address", - SignReturnAddrStr[static_cast(BPI.SignReturnAddr)]); - - Fn->addFnAttr("branch-target-enforcement", - BPI.BranchTargetEnforcement ? "true" : "false"); + StringRef Arch = Attr.Architecture.empty() + ? CGM.getTarget().getTargetOpts().CPU + : Attr.Architecture; + if (!CGM.getTarget().validateBranchProtection(Attr.BranchProtection, + Arch, BPI, DiagMsg)) { + CGM.getDiags().Report( + D->getLocation(), + diag::warn_target_unsupported_branch_protection_attribute) + << Arch; + } else { + static const char *SignReturnAddrStr[] = {"none", "non-leaf", "all"}; + assert(static_cast(BPI.SignReturnAddr) <= 2 && + "Unexpected SignReturnAddressScopeKind"); + Fn->addFnAttr( + "sign-return-address", + SignReturnAddrStr[static_cast(BPI.SignReturnAddr)]); + + Fn->addFnAttr("branch-target-enforcement", + BPI.BranchTargetEnforcement ? "true" : "false"); + } + } else if (CGM.getLangOpts().BranchTargetEnforcement || + CGM.getLangOpts().hasSignReturnAddress() || + CGM.getLangOpts().isSignReturnAddressScopeAll()) { + // If the Branch Protection attribute is missing, validate the target + // Architecture attribute against Branch Protection command line + // settings. + if (!CGM.getTarget().isBranchProtectionSupportedArch(Attr.Architecture)) + CGM.getDiags().Report( + D->getLocation(), + diag::warn_target_unsupported_branch_protection_attribute) + << Attr.Architecture; } } diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -1625,7 +1625,7 @@ } } -static void CollectARMPACBTIOptions(const Driver &D, const ArgList &Args, +static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs, bool isAArch64) { const Arg *A = isAArch64 ? Args.getLastArg(options::OPT_msign_return_address_EQ, @@ -1634,6 +1634,12 @@ if (!A) return; + const Driver &D = TC.getDriver(); + const llvm::Triple &Triple = TC.getEffectiveTriple(); + if (!Triple.isArmT32()) + D.Diag(diag::warn_target_unsupported_branch_protection_option) + << Triple.getArchName(); + StringRef Scope, Key; bool IndirectBranches; @@ -1711,8 +1717,7 @@ AddAAPCSVolatileBitfieldArgs(Args, CmdArgs); // Enable/disable return address signing and indirect branch targets. - CollectARMPACBTIOptions(getToolChain().getDriver(), Args, CmdArgs, - false /*isAArch64*/); + CollectARMPACBTIOptions(getToolChain(), Args, CmdArgs, false /*isAArch64*/); } void Clang::RenderTargetOptions(const llvm::Triple &EffectiveTriple, @@ -1839,8 +1844,7 @@ } // Enable/disable return address signing and indirect branch targets. - CollectARMPACBTIOptions(getToolChain().getDriver(), Args, CmdArgs, - true /*isAArch64*/); + CollectARMPACBTIOptions(getToolChain(), Args, CmdArgs, true /*isAArch64*/); // Handle -msve_vector_bits= if (Arg *A = Args.getLastArg(options::OPT_msve_vector_bits_EQ)) { diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3353,7 +3353,8 @@ if (ParsedAttrs.BranchProtection.empty()) return false; if (!Context.getTargetInfo().validateBranchProtection( - ParsedAttrs.BranchProtection, BPI, DiagMsg)) { + ParsedAttrs.BranchProtection, ParsedAttrs.Architecture, BPI, + DiagMsg)) { if (DiagMsg.empty()) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) << Unsupported << None << "branch-protection" << Target; diff --git a/clang/test/CodeGen/arm-branch-protection-attr-2.c b/clang/test/CodeGen/arm-branch-protection-attr-2.c --- a/clang/test/CodeGen/arm-branch-protection-attr-2.c +++ b/clang/test/CodeGen/arm-branch-protection-attr-2.c @@ -1,9 +1,9 @@ // REQUIRES: arm-registered-target -// RUN: %clang -target arm-arm-none-eabi -march=armv7-m -S -emit-llvm -o - -mbranch-protection=none %s | FileCheck %s --check-prefix=CHECK --check-prefix=NONE -// RUN: %clang -target arm-arm-none-eabi -march=armv7-m -S -emit-llvm -o - -mbranch-protection=pac-ret %s | FileCheck %s --check-prefix=CHECK --check-prefix=PART -// RUN: %clang -target arm-arm-none-eabi -march=armv7-m -S -emit-llvm -o - -mbranch-protection=pac-ret+leaf %s | FileCheck %s --check-prefix=CHECK --check-prefix=ALL -// RUN: %clang -target arm-arm-none-eabi -march=armv7-m -S -emit-llvm -o - -mbranch-protection=pac-ret+b-key %s | FileCheck %s --check-prefix=CHECK --check-prefix=PART -// RUN: %clang -target arm-arm-none-eabi -march=armv7-m -S -emit-llvm -o - -mbranch-protection=bti %s | FileCheck %s --check-prefix=CHECK --check-prefix=BTE +// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main -S -emit-llvm -o - -mbranch-protection=none %s | FileCheck %s --check-prefix=CHECK --check-prefix=NONE +// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main -S -emit-llvm -o - -mbranch-protection=pac-ret %s | FileCheck %s --check-prefix=CHECK --check-prefix=PART +// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main -S -emit-llvm -o - -mbranch-protection=pac-ret+leaf %s | FileCheck %s --check-prefix=CHECK --check-prefix=ALL +// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main -S -emit-llvm -o - -mbranch-protection=pac-ret+b-key %s | FileCheck %s --check-prefix=CHECK --check-prefix=PART +// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main -S -emit-llvm -o - -mbranch-protection=bti %s | FileCheck %s --check-prefix=CHECK --check-prefix=BTE // Check there are no branch protection function attributes diff --git a/clang/test/CodeGen/arm_acle.c b/clang/test/CodeGen/arm_acle.c --- a/clang/test/CodeGen/arm_acle.c +++ b/clang/test/CodeGen/arm_acle.c @@ -1535,12 +1535,12 @@ /* 10.1 Special register intrinsics */ // AArch32-LABEL: @test_rsr( // AArch32-NEXT: entry: -// AArch32-NEXT: [[TMP0:%.*]] = call i32 @llvm.read_volatile_register.i32(metadata !5) +// AArch32-NEXT: [[TMP0:%.*]] = call i32 @llvm.read_volatile_register.i32(metadata [[A32RSR32:!.*]]) // AArch32-NEXT: ret i32 [[TMP0]] // // AArch64-LABEL: @test_rsr( // AArch64-NEXT: entry: -// AArch64-NEXT: [[TMP0:%.*]] = call i64 @llvm.read_volatile_register.i64(metadata !8) +// AArch64-NEXT: [[TMP0:%.*]] = call i64 @llvm.read_volatile_register.i64(metadata [[A64RSR:!.*]]) // AArch64-NEXT: [[TMP1:%.*]] = trunc i64 [[TMP0]] to i32 // AArch64-NEXT: ret i32 [[TMP1]] // @@ -1554,12 +1554,12 @@ // AArch32-LABEL: @test_rsr64( // AArch32-NEXT: entry: -// AArch32-NEXT: [[TMP0:%.*]] = call i64 @llvm.read_volatile_register.i64(metadata !6) +// AArch32-NEXT: [[TMP0:%.*]] = call i64 @llvm.read_volatile_register.i64(metadata [[A32RSR64:!.*]]) // AArch32-NEXT: ret i64 [[TMP0]] // // AArch64-LABEL: @test_rsr64( // AArch64-NEXT: entry: -// AArch64-NEXT: [[TMP0:%.*]] = call i64 @llvm.read_volatile_register.i64(metadata !8) +// AArch64-NEXT: [[TMP0:%.*]] = call i64 @llvm.read_volatile_register.i64(metadata [[A64RSR]]) // AArch64-NEXT: ret i64 [[TMP0]] // uint64_t test_rsr64() { @@ -1572,13 +1572,13 @@ // AArch32-LABEL: @test_rsrp( // AArch32-NEXT: entry: -// AArch32-NEXT: [[TMP0:%.*]] = call i32 @llvm.read_volatile_register.i32(metadata !7) +// AArch32-NEXT: [[TMP0:%.*]] = call i32 @llvm.read_volatile_register.i32(metadata [[A32SYSREG:!.*]]) // AArch32-NEXT: [[TMP1:%.*]] = inttoptr i32 [[TMP0]] to i8* // AArch32-NEXT: ret i8* [[TMP1]] // // AArch64-LABEL: @test_rsrp( // AArch64-NEXT: entry: -// AArch64-NEXT: [[TMP0:%.*]] = call i64 @llvm.read_volatile_register.i64(metadata !9) +// AArch64-NEXT: [[TMP0:%.*]] = call i64 @llvm.read_volatile_register.i64(metadata [[A64SYSREG:!.*]]) // AArch64-NEXT: [[TMP1:%.*]] = inttoptr i64 [[TMP0]] to i8* // AArch64-NEXT: ret i8* [[TMP1]] // @@ -1588,13 +1588,13 @@ // AArch32-LABEL: @test_wsr( // AArch32-NEXT: entry: -// AArch32-NEXT: call void @llvm.write_register.i32(metadata !5, i32 [[V:%.*]]) +// AArch32-NEXT: call void @llvm.write_register.i32(metadata [[A32RSR32]], i32 [[V:%.*]]) // AArch32-NEXT: ret void // // AArch64-LABEL: @test_wsr( // AArch64-NEXT: entry: // AArch64-NEXT: [[TMP0:%.*]] = zext i32 [[V:%.*]] to i64 -// AArch64-NEXT: call void @llvm.write_register.i64(metadata !8, i64 [[TMP0]]) +// AArch64-NEXT: call void @llvm.write_register.i64(metadata [[A64RSR]], i64 [[TMP0]]) // AArch64-NEXT: ret void // void test_wsr(uint32_t v) { @@ -1607,12 +1607,12 @@ // AArch32-LABEL: @test_wsr64( // AArch32-NEXT: entry: -// AArch32-NEXT: call void @llvm.write_register.i64(metadata !6, i64 [[V:%.*]]) +// AArch32-NEXT: call void @llvm.write_register.i64(metadata [[A32RSR64]], i64 [[V:%.*]]) // AArch32-NEXT: ret void // // AArch64-LABEL: @test_wsr64( // AArch64-NEXT: entry: -// AArch64-NEXT: call void @llvm.write_register.i64(metadata !8, i64 [[V:%.*]]) +// AArch64-NEXT: call void @llvm.write_register.i64(metadata [[A64RSR]], i64 [[V:%.*]]) // AArch64-NEXT: ret void // void test_wsr64(uint64_t v) { @@ -1626,13 +1626,13 @@ // AArch32-LABEL: @test_wsrp( // AArch32-NEXT: entry: // AArch32-NEXT: [[TMP0:%.*]] = ptrtoint i8* [[V:%.*]] to i32 -// AArch32-NEXT: call void @llvm.write_register.i32(metadata !7, i32 [[TMP0]]) +// AArch32-NEXT: call void @llvm.write_register.i32(metadata [[A32SYSREG]], i32 [[TMP0]]) // AArch32-NEXT: ret void // // AArch64-LABEL: @test_wsrp( // AArch64-NEXT: entry: // AArch64-NEXT: [[TMP0:%.*]] = ptrtoint i8* [[V:%.*]] to i64 -// AArch64-NEXT: call void @llvm.write_register.i64(metadata !9, i64 [[TMP0]]) +// AArch64-NEXT: call void @llvm.write_register.i64(metadata [[A64SYSREG]], i64 [[TMP0]]) // AArch64-NEXT: ret void // void test_wsrp(void *v) { @@ -1642,7 +1642,7 @@ // AArch32-LABEL: @test_rsrf( // AArch32-NEXT: entry: // AArch32-NEXT: [[REF_TMP:%.*]] = alloca i32, align 4 -// AArch32-NEXT: [[TMP0:%.*]] = call i32 @llvm.read_volatile_register.i32(metadata !5) +// AArch32-NEXT: [[TMP0:%.*]] = call i32 @llvm.read_volatile_register.i32(metadata [[A32RSR32]]) // AArch32-NEXT: store i32 [[TMP0]], i32* [[REF_TMP]], align 4 // AArch32-NEXT: [[TMP1:%.*]] = bitcast i32* [[REF_TMP]] to float* // AArch32-NEXT: [[TMP2:%.*]] = load float, float* [[TMP1]], align 4 @@ -1651,7 +1651,7 @@ // AArch64-LABEL: @test_rsrf( // AArch64-NEXT: entry: // AArch64-NEXT: [[REF_TMP:%.*]] = alloca i32, align 4 -// AArch64-NEXT: [[TMP0:%.*]] = call i64 @llvm.read_volatile_register.i64(metadata !8) +// AArch64-NEXT: [[TMP0:%.*]] = call i64 @llvm.read_volatile_register.i64(metadata [[A64RSR]]) // AArch64-NEXT: [[TMP1:%.*]] = trunc i64 [[TMP0]] to i32 // AArch64-NEXT: store i32 [[TMP1]], i32* [[REF_TMP]], align 4 // AArch64-NEXT: [[TMP2:%.*]] = bitcast i32* [[REF_TMP]] to float* @@ -1669,7 +1669,7 @@ // AArch32-LABEL: @test_rsrf64( // AArch32-NEXT: entry: // AArch32-NEXT: [[REF_TMP:%.*]] = alloca i64, align 8 -// AArch32-NEXT: [[TMP0:%.*]] = call i64 @llvm.read_volatile_register.i64(metadata !6) +// AArch32-NEXT: [[TMP0:%.*]] = call i64 @llvm.read_volatile_register.i64(metadata [[A32RSR64]]) // AArch32-NEXT: store i64 [[TMP0]], i64* [[REF_TMP]], align 8 // AArch32-NEXT: [[TMP1:%.*]] = bitcast i64* [[REF_TMP]] to double* // AArch32-NEXT: [[TMP2:%.*]] = load double, double* [[TMP1]], align 8 @@ -1678,7 +1678,7 @@ // AArch64-LABEL: @test_rsrf64( // AArch64-NEXT: entry: // AArch64-NEXT: [[REF_TMP:%.*]] = alloca i64, align 8 -// AArch64-NEXT: [[TMP0:%.*]] = call i64 @llvm.read_volatile_register.i64(metadata !8) +// AArch64-NEXT: [[TMP0:%.*]] = call i64 @llvm.read_volatile_register.i64(metadata [[A64RSR]]) // AArch64-NEXT: store i64 [[TMP0]], i64* [[REF_TMP]], align 8 // AArch64-NEXT: [[TMP1:%.*]] = bitcast i64* [[REF_TMP]] to double* // AArch64-NEXT: [[TMP2:%.*]] = load double, double* [[TMP1]], align 8 @@ -1698,7 +1698,7 @@ // AArch32-NEXT: store float [[V:%.*]], float* [[V_ADDR]], align 4 // AArch32-NEXT: [[TMP0:%.*]] = bitcast float* [[V_ADDR]] to i32* // AArch32-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP0]], align 4 -// AArch32-NEXT: call void @llvm.write_register.i32(metadata !5, i32 [[TMP1]]) +// AArch32-NEXT: call void @llvm.write_register.i32(metadata [[A32RSR32]], i32 [[TMP1]]) // AArch32-NEXT: ret void // // AArch64-LABEL: @test_wsrf( @@ -1708,7 +1708,7 @@ // AArch64-NEXT: [[TMP0:%.*]] = bitcast float* [[V_ADDR]] to i32* // AArch64-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP0]], align 4 // AArch64-NEXT: [[TMP2:%.*]] = zext i32 [[TMP1]] to i64 -// AArch64-NEXT: call void @llvm.write_register.i64(metadata !8, i64 [[TMP2]]) +// AArch64-NEXT: call void @llvm.write_register.i64(metadata [[A64RSR]], i64 [[TMP2]]) // AArch64-NEXT: ret void // void test_wsrf(float v) { @@ -1725,7 +1725,7 @@ // AArch32-NEXT: store double [[V:%.*]], double* [[V_ADDR]], align 8 // AArch32-NEXT: [[TMP0:%.*]] = bitcast double* [[V_ADDR]] to i64* // AArch32-NEXT: [[TMP1:%.*]] = load i64, i64* [[TMP0]], align 8 -// AArch32-NEXT: call void @llvm.write_register.i64(metadata !6, i64 [[TMP1]]) +// AArch32-NEXT: call void @llvm.write_register.i64(metadata [[A32RSR64]], i64 [[TMP1]]) // AArch32-NEXT: ret void // // AArch64-LABEL: @test_wsrf64( @@ -1734,7 +1734,7 @@ // AArch64-NEXT: store double [[V:%.*]], double* [[V_ADDR]], align 8 // AArch64-NEXT: [[TMP0:%.*]] = bitcast double* [[V_ADDR]] to i64* // AArch64-NEXT: [[TMP1:%.*]] = load i64, i64* [[TMP0]], align 8 -// AArch64-NEXT: call void @llvm.write_register.i64(metadata !8, i64 [[TMP1]]) +// AArch64-NEXT: call void @llvm.write_register.i64(metadata [[A64RSR]], i64 [[TMP1]]) // AArch64-NEXT: ret void // void test_wsrf64(double v) { @@ -1786,9 +1786,9 @@ } #endif -// AArch32: !5 = !{!"cp1:2:c3:c4:5"} -// AArch32: !6 = !{!"cp1:2:c3"} -// AArch32: !7 = !{!"sysreg"} +// AArch32: [[A32RSR32]] = !{!"cp1:2:c3:c4:5"} +// AArch32: [[A32RSR64]] = !{!"cp1:2:c3"} +// AArch32: [[A32SYSREG]] = !{!"sysreg"} -// AArch64: !8 = !{!"1:2:3:4:5"} -// AArch64: !9 = !{!"sysreg"} +// AArch64: [[A64RSR]] = !{!"1:2:3:4:5"} +// AArch64: [[A64SYSREG]] = !{!"sysreg"} diff --git a/clang/test/Driver/arm-security-options.c b/clang/test/Driver/arm-security-options.c --- a/clang/test/Driver/arm-security-options.c +++ b/clang/test/Driver/arm-security-options.c @@ -1,48 +1,77 @@ // Check the -mbranch-protection=option -// RUN: %clang -target arm-arm-none-eabi -c %s -### -mbranch-protection=pac-ret 2>&1 | \ +// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main -c %s -### -mbranch-protection=pac-ret 2>&1 | \ // RUN: FileCheck %s --check-prefix=RA-NON-LEAF --check-prefix=KEY-A --check-prefix=BTE-OFF -// RUN: %clang -target arm-arm-none-eabi -c %s -### -mbranch-protection=pac-ret+leaf 2>&1 | \ +// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main -c %s -### -mbranch-protection=pac-ret+leaf 2>&1 | \ // RUN: FileCheck %s --check-prefix=RA-ALL --check-prefix=KEY-A --check-prefix=BTE-OFF -// RUN: %clang -target arm-arm-none-eabi -c %s -### -mbranch-protection=pac-ret+leaf+b-key 2>&1 | \ +// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main -c %s -### -mbranch-protection=pac-ret+leaf+b-key 2>&1 | \ // RUN: FileCheck %s --check-prefix=RA-ALL --check-prefix=KEY-B --check-prefix=BTE-OFF -// RUN: %clang -target arm-arm-none-eabi -c %s -### -mbranch-protection=pac-ret+b-key 2>&1 | \ +// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main -c %s -### -mbranch-protection=pac-ret+b-key 2>&1 | \ // RUN: FileCheck %s --check-prefix=RA-NON-LEAF --check-prefix=KEY-B --check-prefix=BTE-OFF -// RUN: %clang -target arm-arm-none-eabi -c %s -### -mbranch-protection=bti 2>&1 | \ +// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main -c %s -### -mbranch-protection=bti 2>&1 | \ // RUN: FileCheck %s --check-prefix=RA-OFF --check-prefix=BTE-ON -// RUN: %clang -target arm-arm-none-eabi -c %s -### -mbranch-protection=bti+pac-ret 2>&1 | \ +// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main -c %s -### -mbranch-protection=bti+pac-ret 2>&1 | \ // RUN: FileCheck %s --check-prefix=RA-NON-LEAF --check-prefix=KEY-A --check-prefix=BTE-ON -// RUN: %clang -target arm-arm-none-eabi -c %s -### -mbranch-protection=bti+pac-ret+leaf 2>&1 | \ +// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main -c %s -### -mbranch-protection=bti+pac-ret+leaf 2>&1 | \ // RUN: FileCheck %s --check-prefix=RA-ALL --check-prefix=KEY-A --check-prefix=BTE-ON -// RUN: %clang -target arm-arm-none-eabi -c %s -### -mbranch-protection=bti 2>&1 | \ +// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main -c %s -### -mbranch-protection=bti 2>&1 | \ // RUN: FileCheck %s --check-prefix=RA-OFF --check-prefix=BTE-ON -// RUN: %clang -target arm-arm-none-eabi -c %s -### -mbranch-protection=bti+pac-ret+b-key 2>&1 | \ +// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main -c %s -### -mbranch-protection=bti+pac-ret+b-key 2>&1 | \ // RUN: FileCheck %s --check-prefix=RA-NON-LEAF --check-prefix=KEY-B --check-prefix=BTE-ON -// RUN: %clang -target arm-arm-none-eabi -c %s -### -mbranch-protection=bti+pac-ret+leaf+b-key 2>&1 | \ +// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main -c %s -### -mbranch-protection=bti+pac-ret+leaf+b-key 2>&1 | \ // RUN: FileCheck %s --check-prefix=RA-ALL --check-prefix=KEY-B --check-prefix=BTE-ON // -mbranch-protection with standard -// RUN: %clang -target arm-arm-none-eabi -c %s -### -mbranch-protection=standard 2>&1 | \ +// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main -c %s -### -mbranch-protection=standard 2>&1 | \ // RUN: FileCheck %s --check-prefix=RA-NON-LEAF --check-prefix=KEY-A --check-prefix=BTE-ON -// RUN: %clang -target arm-arm-none-eabi -c %s -### -mbranch-protection=bar 2>&1 | \ +// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main -c %s -### -mbranch-protection=bar 2>&1 | \ // RUN: FileCheck %s --check-prefix=BAD-BP-PROTECTION -// RUN: %clang -target arm-arm-none-eabi -c %s -### -mbranch-protection=pac-ret+bti+b-key 2>&1 | \ +// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main -c %s -### -mbranch-protection=pac-ret+bti+b-key 2>&1 | \ // RUN: FileCheck %s --check-prefix=BAD-B-KEY-COMBINATION -// RUN: %clang -target arm-arm-none-eabi -c %s -### -mbranch-protection=pac-ret+bti+leaf 2>&1 | \ +// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main -c %s -### -mbranch-protection=pac-ret+bti+leaf 2>&1 | \ // RUN: FileCheck %s --check-prefix=BAD-LEAF-COMBINATION +// -mbranch-protection with supported architectures other than v8.1-m.main +// RUN: %clang -target arm-arm-none-eabi -march=armv8-m.main -c %s -### -mbranch-protection=pac-ret 2>&1 | \ +// RUN: FileCheck %s --check-prefix=RA-NON-LEAF --check-prefix=KEY-A --check-prefix=BTE-OFF + +// RUN: %clang -target arm-arm-none-eabi -march=armv7-m -c %s -### -mbranch-protection=pac-ret 2>&1 | \ +// RUN: FileCheck %s --check-prefix=RA-NON-LEAF --check-prefix=KEY-A --check-prefix=BTE-OFF + +// RUN: %clang -target arm-arm-none-eabi -march=armv7e-m -c %s -### -mbranch-protection=pac-ret 2>&1 | \ +// RUN: FileCheck %s --check-prefix=RA-NON-LEAF --check-prefix=KEY-A --check-prefix=BTE-OFF + +// -mbranch-protection with unsupported architectures +// RUN: %clang -target arm-arm-none-eabi -march=armv6-m -c %s -### -mbranch-protection=bti 2>&1 | \ +// RUN: FileCheck %s --check-prefix=INCOMPATIBLE-ARCH + +// RUN: %clang -target arm-arm-none-eabi -march=armv8-m.base -c %s -### -mbranch-protection=bti 2>&1 | \ +// RUN: FileCheck %s --check-prefix=INCOMPATIBLE-ARCH + +// RUN: %clang -target arm-arm-none-eabi -march=armv8-a -c %s -### -mbranch-protection=bti 2>&1 | \ +// RUN: FileCheck %s --check-prefix=INCOMPATIBLE-ARCH + +// RUN: %clang -target arm-arm-none-eabi -march=armv8-r -c %s -### -mbranch-protection=bti 2>&1 | \ +// RUN: FileCheck %s --check-prefix=INCOMPATIBLE-ARCH + +// RUN: %clang -target arm-arm-none-eabi -march=armv7-a -c %s -### -mbranch-protection=bti 2>&1 | \ +// RUN: FileCheck %s --check-prefix=INCOMPATIBLE-ARCH + +// RUN: %clang -target arm-arm-none-eabi -march=armv7-r -c %s -### -mbranch-protection=bti 2>&1 | \ +// RUN: FileCheck %s --check-prefix=INCOMPATIBLE-ARCH + // RA-OFF: "-msign-return-address=none" // RA-NON-LEAF: "-msign-return-address=non-leaf" // RA-ALL: "-msign-return-address=all" @@ -57,3 +86,5 @@ // BAD-B-KEY-COMBINATION: invalid branch protection option 'b-key' in '-mbranch-protection={{.*}}' // BAD-LEAF-COMBINATION: invalid branch protection option 'leaf' in '-mbranch-protection={{.*}}' + +// INCOMPATIBLE-ARCH: ignoring '-mbranch-protection=' option because the '{{.*}}' architecture does not support it diff --git a/clang/test/Frontend/arm-branch-protection-default-arch.c b/clang/test/Frontend/arm-branch-protection-default-arch.c new file mode 100644 --- /dev/null +++ b/clang/test/Frontend/arm-branch-protection-default-arch.c @@ -0,0 +1,27 @@ +// REQUIRES: arm-registered-target + +/// Check warning for +// RUN: %clang -target arm-arm-none-eabi %s -S -o - 2>&1 | FileCheck %s + +__attribute__((target("branch-protection=bti"))) void f1() {} +__attribute__((target("branch-protection=pac-ret"))) void f2() {} +__attribute__((target("branch-protection=bti+pac-ret"))) void f3() {} +__attribute__((target("branch-protection=bti+pac-ret+leaf"))) void f4() {} + +// CHECK: warning: unsupported 'branch-protection' in the 'target' attribute string; 'target' attribute ignored [-Wignored-attributes] +// CHECK-NEXT: __attribute__((target("branch-protection=bti"))) void f1() {} + +// CHECK: warning: unsupported 'branch-protection' in the 'target' attribute string; 'target' attribute ignored [-Wignored-attributes] +// CHECK-NEXT: __attribute__((target("branch-protection=pac-ret"))) void f2() {} + +// CHECK: warning: unsupported 'branch-protection' in the 'target' attribute string; 'target' attribute ignored [-Wignored-attributes] +// CHECK-NEXT: __attribute__((target("branch-protection=bti+pac-ret"))) void f3() {} + +// CHECK: warning: unsupported 'branch-protection' in the 'target' attribute string; 'target' attribute ignored [-Wignored-attributes] +// CHECK-NEXT: __attribute__((target("branch-protection=bti+pac-ret+leaf"))) void f4() {} + +/// Check there are no branch protection function attributes + +// CHECK-NOT: attributes { {{.*}} "sign-return-address" +// CHECK-NOT: attributes { {{.*}} "sign-return-address-key" +// CHECK-NOT: attributes { {{.*}} "branch-target-enforcement" diff --git a/clang/test/Frontend/arm-ignore-branch-protection-option.c b/clang/test/Frontend/arm-ignore-branch-protection-option.c new file mode 100644 --- /dev/null +++ b/clang/test/Frontend/arm-ignore-branch-protection-option.c @@ -0,0 +1,18 @@ +// REQUIRES: arm-registered-target + +/// Check warning for +// RUN: %clang -target arm-arm-none-eabi -march=armv7-m -mbranch-protection=bti %s -S -emit-llvm -o - 2>&1 | FileCheck %s + +__attribute__((target("arch=cortex-m0"))) void f() {} + +// CHECK: warning: ignoring the 'branch-protection' attribute because the 'cortex-m0' architecture does not support it [-Wbranch-protection] +// CHECK-NEXT: __attribute__((target("arch=cortex-m0"))) void f() {} + +/// Check there are no branch protection function attributes + +// CHECK-NOT: attributes { {{.*}} "sign-return-address" +// CHECK-NOT: attributes { {{.*}} "sign-return-address-key" +// CHECK-NOT: attributes { {{.*}} "branch-target-enforcement" + +/// Check that there are branch protection module attributes despite the warning. +// CHECK: !{i32 1, !"branch-target-enforcement", i32 1} diff --git a/clang/test/Frontend/arm-invalid-branch-protection.c b/clang/test/Frontend/arm-invalid-branch-protection.c --- a/clang/test/Frontend/arm-invalid-branch-protection.c +++ b/clang/test/Frontend/arm-invalid-branch-protection.c @@ -1,7 +1,7 @@ // REQUIRES: arm-registered-target -// RUN: %clang -target arm-arm-none-eabi -mbranch-protection=pac-ret+b-key -c %s -o /dev/null 2>&1 | FileCheck %s -// RUN: %clang -target arm-arm-none-eabi -mbranch-protection=pac-ret+b-key+leaf -c %s -o /dev/null 2>&1 | FileCheck %s -// RUN: %clang -target arm-arm-none-eabi -mbranch-protection=bti+pac-ret+b-key -c %s -o /dev/null 2>&1 | FileCheck %s -// RUN: %clang -target arm-arm-none-eabi -mbranch-protection=bti+pac-ret+b-key+leaf -c %s -o /dev/null 2>&1 | FileCheck %s +// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main -mbranch-protection=pac-ret+b-key -c %s -o /dev/null 2>&1 | FileCheck %s +// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main -mbranch-protection=pac-ret+b-key+leaf -c %s -o /dev/null 2>&1 | FileCheck %s +// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main -mbranch-protection=bti+pac-ret+b-key -c %s -o /dev/null 2>&1 | FileCheck %s +// RUN: %clang -target arm-arm-none-eabi -march=armv8.1-m.main -mbranch-protection=bti+pac-ret+b-key+leaf -c %s -o /dev/null 2>&1 | FileCheck %s // CHECK: warning: invalid branch protection option 'b-key' in '-mbranch-protection={{[a-z+-]*}}' [-Wbranch-protection] diff --git a/clang/test/Sema/arm-branch-protection-attr-warn.c b/clang/test/Sema/arm-branch-protection-attr-warn.c new file mode 100644 --- /dev/null +++ b/clang/test/Sema/arm-branch-protection-attr-warn.c @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -triple thumbv6m -verify -fsyntax-only %s + +// expected-warning@+1 {{unsupported 'branch-protection' in the 'target' attribute string; 'target' attribute ignored}} +__attribute__((target("arch=cortex-m0,branch-protection=bti"))) void f1() {} + +// expected-warning@+1 {{unsupported 'branch-protection' in the 'target' attribute string; 'target' attribute ignored}} +__attribute__((target("arch=cortex-m0,branch-protection=pac-ret"))) void f2() {} + +// expected-warning@+1 {{unsupported 'branch-protection' in the 'target' attribute string; 'target' attribute ignored}} +__attribute__((target("arch=cortex-m0,branch-protection=bti+pac-ret"))) void f3() {} + +// expected-warning@+1 {{unsupported 'branch-protection' in the 'target' attribute string; 'target' attribute ignored}} +__attribute__((target("arch=cortex-m0,branch-protection=bti+pac-ret+leaf"))) void f4() {} diff --git a/clang/test/Sema/arm-branch-protection.c b/clang/test/Sema/arm-branch-protection.c new file mode 100644 --- /dev/null +++ b/clang/test/Sema/arm-branch-protection.c @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -triple thumbv6m -verify -fsyntax-only %s + +// expected-no-diagnostics +// Armv8.1-M.Main +__attribute__((target("arch=cortex-m55,branch-protection=bti"))) void f1() {} +__attribute__((target("arch=cortex-m55,branch-protection=pac-ret"))) void f2() {} +__attribute__((target("arch=cortex-m55,branch-protection=bti+pac-ret"))) void f3() {} +__attribute__((target("arch=cortex-m55,branch-protection=bti+pac-ret+leaf"))) void f4() {} +// Armv8-M.Main +__attribute__((target("arch=cortex-m33,branch-protection=bti"))) void f5() {} +__attribute__((target("arch=cortex-m33,branch-protection=pac-ret"))) void f6() {} +__attribute__((target("arch=cortex-m33,branch-protection=bti+pac-ret"))) void f7() {} +__attribute__((target("arch=cortex-m33,branch-protection=bti+pac-ret+leaf"))) void f8() {} +// Armv7-M +__attribute__((target("arch=cortex-m3,branch-protection=bti"))) void f9() {} +__attribute__((target("arch=cortex-m3,branch-protection=pac-ret"))) void f10() {} +__attribute__((target("arch=cortex-m3,branch-protection=bti+pac-ret"))) void f11() {} +__attribute__((target("arch=cortex-m3,branch-protection=bti+pac-ret+leaf"))) void f12() {} +// Armv7E-M +__attribute__((target("arch=cortex-m4,branch-protection=bti"))) void f13() {} +__attribute__((target("arch=cortex-m4,branch-protection=pac-ret"))) void f14() {} +__attribute__((target("arch=cortex-m4,branch-protection=bti+pac-ret"))) void f15() {} +__attribute__((target("arch=cortex-m4,branch-protection=bti+pac-ret+leaf"))) void f16() {} diff --git a/llvm/include/llvm/ADT/Triple.h b/llvm/include/llvm/ADT/Triple.h --- a/llvm/include/llvm/ADT/Triple.h +++ b/llvm/include/llvm/ADT/Triple.h @@ -721,6 +721,22 @@ isOSBinFormatELF(); } + /// Tests whether the target is T32. + bool isArmT32() const { + if (!isARM()) + return false; + + if (getArch() == Triple::aarch64) + return true; + + if (isThumb()) + return true; + + return (getSubArch() == Triple::ARMSubArch_v8_1m_mainline) || + (getSubArch() == Triple::ARMSubArch_v8m_mainline) || + (getSubArch() == Triple::ARMSubArch_v7m) || + (getSubArch() == Triple::ARMSubArch_v7em); + } /// Tests whether the target is AArch64 (little and big endian). bool isAArch64() const { return getArch() == Triple::aarch64 || getArch() == Triple::aarch64_be ||