Index: clang/include/clang/AST/Attr.h =================================================================== --- clang/include/clang/AST/Attr.h +++ clang/include/clang/AST/Attr.h @@ -20,6 +20,7 @@ #include "clang/AST/Type.h" #include "clang/Basic/AttrKinds.h" #include "clang/Basic/AttributeCommonInfo.h" +#include "clang/Basic/CodeGenOptions.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/Sanitizers.h" Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -2114,12 +2114,21 @@ struct ParsedTargetAttr { std::vector Features; StringRef Architecture; + bool BranchProtectionAttr = 0; + StringRef BranchProtectionErr; + CodeGenOptions::SignReturnAddressScope SignRetAddr = + CodeGenOptions::SignReturnAddressScope::None; + CodeGenOptions::SignReturnAddressKeyValue SignRetAddrKey = + CodeGenOptions::SignReturnAddressKeyValue::AKey; + bool BranchTargetEnforcement = false; bool DuplicateArchitecture = false; + bool operator ==(const ParsedTargetAttr &Other) const { return DuplicateArchitecture == Other.DuplicateArchitecture && Architecture == Other.Architecture && Features == Other.Features; } }; + ParsedTargetAttr parse() const { return parse(getFeaturesStr()); } @@ -2186,6 +2195,22 @@ if (Feature.startswith("fpmath=") || Feature.startswith("tune=")) continue; + if (Feature.startswith("branch-protection=")) { + Ret.BranchProtectionAttr = true; + StringRef Value = Feature.split('=').second.trim(); + if (Value == "none") { + // Defaults are OK; + } else if (Value == "standard") { + Ret.SignRetAddr = CodeGenOptions::SignReturnAddressScope::NonLeaf; + Ret.BranchTargetEnforcement = true; + } else { + SmallVector ProtOpts; + Value.split(ProtOpts,"+"); + parseBranchProtection(ProtOpts, Ret); + } + continue; + } + // While we're here iterating check for a different target cpu. if (Feature.startswith("arch=")) { if (!Ret.Architecture.empty()) @@ -2199,6 +2224,38 @@ } return Ret; } + + private: + static void parseBranchProtection(const SmallVectorImpl &Opts, + ParsedTargetAttr &Attr) { + for (int I = 0, E = Opts.size(); I != E; ++I) { + StringRef Opt = Opts[I].trim(); + if (Opt == "bti") { + Attr.BranchTargetEnforcement = true; + continue; + } + if (Opt == "pac-ret") { + Attr.SignRetAddr = CodeGenOptions::SignReturnAddressScope::NonLeaf; + for (; I + 1 != E; ++I) { + StringRef PACOpt = Opts[I + 1].trim(); + if (PACOpt == "leaf") + Attr.SignRetAddr = CodeGenOptions::SignReturnAddressScope::All; + else if (PACOpt == "b-key") + Attr.SignRetAddrKey = + CodeGenOptions::SignReturnAddressKeyValue::BKey; + else + break; + } + continue; + } + if (Opt.empty()) + Attr.BranchProtectionErr = ""; + else + Attr.BranchProtectionErr = Opt; + break; + } + } + public: }]; } Index: clang/include/clang/Basic/AttrDocs.td =================================================================== --- clang/include/clang/Basic/AttrDocs.td +++ clang/include/clang/Basic/AttrDocs.td @@ -1793,6 +1793,10 @@ of the feature, as well as ``arch="CPU"`` which will change the default "CPU" for the function. +For AArch64, the attribute also allows the "branch-protection=" option, +where the permissible arguments and their effect on code generation are the same +as for the command-line option ``-mbranch-protection``. + Example "subtarget features" from the x86 backend include: "mmx", "sse", "sse4.2", "avx", "xop" and largely correspond to the machine specific options handled by the front end. Index: clang/include/clang/Basic/CodeGenOptions.h =================================================================== --- clang/include/clang/Basic/CodeGenOptions.h +++ clang/include/clang/Basic/CodeGenOptions.h @@ -109,13 +109,13 @@ Embed_Marker // Embed a marker as a placeholder for bitcode. }; - enum SignReturnAddressScope { + enum class SignReturnAddressScope { None, // No signing for any function NonLeaf, // Sign the return address of functions that spill LR All // Sign the return address of all functions }; - enum SignReturnAddressKeyValue { AKey, BKey }; + enum class SignReturnAddressKeyValue { AKey, BKey }; enum class FramePointerKind { None, // Omit all frame pointers. Index: clang/include/clang/Basic/CodeGenOptions.def =================================================================== --- clang/include/clang/Basic/CodeGenOptions.def +++ clang/include/clang/Basic/CodeGenOptions.def @@ -360,8 +360,8 @@ /// Whether to emit an address-significance table into the object file. CODEGENOPT(Addrsig, 1, 0) -ENUM_CODEGENOPT(SignReturnAddress, SignReturnAddressScope, 2, None) -ENUM_CODEGENOPT(SignReturnAddressKey, SignReturnAddressKeyValue, 1, AKey) +ENUM_CODEGENOPT(SignReturnAddress, SignReturnAddressScope, 2, SignReturnAddressScope::None) +ENUM_CODEGENOPT(SignReturnAddressKey, SignReturnAddressKeyValue, 1, SignReturnAddressKeyValue::AKey) CODEGENOPT(BranchTargetEnforcement, 1, 0) /// Whether to emit unused static constants. Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2591,6 +2591,8 @@ "integral compile time constant expression">; def err_attribute_requires_opencl_version : Error< "%0 attribute requires OpenCL version %1%select{| or above}2">; +def err_invalid_branch_protection_spec : Error< + "invalid or misplaced branch protection specification '%0'">; def warn_unsupported_target_attribute : Warning<"%select{unsupported|duplicate}0%select{| architecture}1 '%2' in" " the 'target' attribute string; 'target' attribute ignored">, Index: clang/lib/CodeGen/TargetInfo.cpp =================================================================== --- clang/lib/CodeGen/TargetInfo.cpp +++ clang/lib/CodeGen/TargetInfo.cpp @@ -5055,23 +5055,33 @@ const FunctionDecl *FD = dyn_cast_or_null(D); if (!FD) return; - llvm::Function *Fn = cast(GV); - auto Kind = CGM.getCodeGenOpts().getSignReturnAddress(); - if (Kind != CodeGenOptions::SignReturnAddressScope::None) { + CodeGenOptions::SignReturnAddressScope Scope = CGM.getCodeGenOpts().getSignReturnAddress(); + CodeGenOptions::SignReturnAddressKeyValue Key = CGM.getCodeGenOpts().getSignReturnAddressKey(); + bool BranchTargetEnforcement = CGM.getCodeGenOpts().BranchTargetEnforcement; + if (const auto *TA = FD->getAttr()) { + TargetAttr::ParsedTargetAttr Attr = TA->parse(); + if (Attr.BranchProtectionAttr) { + Scope = Attr.SignRetAddr; + Key = Attr.SignRetAddrKey; + BranchTargetEnforcement = Attr.BranchTargetEnforcement; + } + } + + auto *Fn = cast(GV); + if (Scope != CodeGenOptions::SignReturnAddressScope::None) { Fn->addFnAttr("sign-return-address", - Kind == CodeGenOptions::SignReturnAddressScope::All + Scope == CodeGenOptions::SignReturnAddressScope::All ? "all" : "non-leaf"); - auto Key = CGM.getCodeGenOpts().getSignReturnAddressKey(); Fn->addFnAttr("sign-return-address-key", Key == CodeGenOptions::SignReturnAddressKeyValue::AKey ? "a_key" : "b_key"); } - if (CGM.getCodeGenOpts().BranchTargetEnforcement) + if (BranchTargetEnforcement) Fn->addFnAttr("branch-target-enforcement"); } }; Index: clang/lib/Sema/SemaDeclAttr.cpp =================================================================== --- clang/lib/Sema/SemaDeclAttr.cpp +++ clang/lib/Sema/SemaDeclAttr.cpp @@ -2990,6 +2990,10 @@ << Unsupported << None << CurFeature; } + if (ParsedAttrs.BranchProtectionAttr && !ParsedAttrs.BranchProtectionErr.empty()) + return Diag(LiteralLoc, diag::err_invalid_branch_protection_spec) + << ParsedAttrs.BranchProtectionErr; + return false; } Index: clang/test/CodeGen/aarch64-branch-protection-attr.c =================================================================== --- /dev/null +++ clang/test/CodeGen/aarch64-branch-protection-attr.c @@ -0,0 +1,81 @@ +// REQUIRES: aarch64-registered-target +// RUN: %clang_cc1 -triple aarch64-unknown-unknown-eabi -emit-llvm -target-cpu generic -target-feature +v8.5a %s -o - \ +// RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=NO-OVERRIDE +// RUN: %clang_cc1 -triple aarch64-unknown-unknown-eabi -emit-llvm -target-cpu generic -target-feature +v8.5a %s -o - \ +// RUN: -msign-return-address=non-leaf -msign-return-address-key=a_key -mbranch-target-enforce \ +// RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=OVERRIDE + +void missing() {} +// NO-OVERRIDE: define void @missing() #[[#NONE:]] +// OVERRIDE: define void @missing() #[[#STD:]] + +__attribute__ ((target("branch-protection=none"))) +void none() {} +// NO-OVERRIDE: define void @none() #[[#NONE]] +// OVERRIDE: define void @none() #[[#NONE:]] + + __attribute__ ((target("branch-protection=standard"))) +void std() {} +// NO-OVERRIDE: define void @std() #[[#STD:]] +// OVERRIDE: define void @std() #[[#STD]] + +__attribute__ ((target("branch-protection=bti"))) +void btionly() {} +// NO-OVERRIDE: define void @btionly() #[[#BTI:]] +// OVERRIDE: define void @btionly() #[[#BTI:]] + +__attribute__ ((target("branch-protection=pac-ret"))) +void paconly() {} +// NO-OVERRIDE: define void @paconly() #[[#PAC:]] +// OVERRIDE: define void @paconly() #[[#PAC:]] + +__attribute__ ((target("branch-protection=pac-ret+bti"))) +void pacbti0() {} +// NO-OVERRIDE: define void @pacbti0() #[[#PACBTI:]] +// OVERRIDE: define void @pacbti0() #[[#PACBTI:]] + +__attribute__ ((target("branch-protection=bti+pac-ret"))) +void pacbti1() {} +// NO-OVERRIDE: define void @pacbti1() #[[#PACBTI]] +// OVERRIDE: define void @pacbti1() #[[#PACBTI]] + +__attribute__ ((target("branch-protection=pac-ret+leaf"))) +void leaf() {} +// NO-OVERRIDE: define void @leaf() #[[#PACLEAF:]] +// OVERRIDE: define void @leaf() #[[#PACLEAF:]] + +__attribute__ ((target("branch-protection=pac-ret+b-key"))) +void bkey() {} +// NO-OVERRIDE: define void @bkey() #[[#PACBKEY:]] +// OVERRIDE: define void @bkey() #[[#PACBKEY:]] + +__attribute__ ((target("branch-protection=pac-ret+b-key+leaf"))) +void bkeyleaf0() {} +// NO-OVERRIDE: define void @bkeyleaf0() #[[#PACBKEYLEAF:]] +// OVERRIDE: define void @bkeyleaf0() #[[#PACBKEYLEAF:]] + +__attribute__ ((target("branch-protection=pac-ret+leaf+b-key"))) +void bkeyleaf1() {} +// NO-OVERRIDE: define void @bkeyleaf1() #[[#PACBKEYLEAF]] +// OVERRIDE: define void @bkeyleaf1() #[[#PACBKEYLEAF]] + +__attribute__ ((target("branch-protection=pac-ret+leaf+bti"))) +void btileaf() {} +// NO-OVERRIDE: define void @btileaf() #[[#BTIPACLEAF:]] +// OVERRIDE: define void @btileaf() #[[#BTIPACLEAF:]] + +// CHECK-DAG: attributes #[[#NONE]] + +// CHECK-DAG: attributes #[[#STD]] = { {{.*}} "branch-target-enforcement" {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="a_key" + +// CHECK-DAG: attributes #[[#BTI]] = { {{.*}}"branch-target-enforcement" + +// CHECK-DAG: attributes #[[#PAC]] = { {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="a_key" + +// CHECK-DAG: attributes #[[#PACLEAF]] = { {{.*}} "sign-return-address"="all" "sign-return-address-key"="a_key" + +// CHECK-DAG: attributes #[[#PACBKEY]] = { {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="b_key" + +// CHECK-DAG: attributes #[[#PACBKEYLEAF]] = { {{.*}} "sign-return-address"="all" "sign-return-address-key"="b_key" + +// CHECK-DAG: attributes #[[#BTIPACLEAF]] = { {{.*}}"branch-target-enforcement" {{.*}} "sign-return-address"="all" "sign-return-address-key"="a_key" Index: clang/test/Sema/branch-protection-attr-err.c =================================================================== --- /dev/null +++ clang/test/Sema/branch-protection-attr-err.c @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -verify -fsyntax-only %s + +__attribute__((target("branch-protection=foo"))) // expected-error {{invalid or misplaced branch protection specification 'foo'}} +void badvalue0() {} + +__attribute__((target("branch-protection=+bti"))) // expected-error {{invalid or misplaced branch protection specification ''}} +void badvalue1() {} + +__attribute__((target("branch-protection=bti+"))) // expected-error {{invalid or misplaced branch protection specification ''}} +void badvalue2() {} + +__attribute__((target("branch-protection=pac-ret+bkey"))) // expected-error {{invalid or misplaced branch protection specification 'bkey'}} +void badvalue3() {} + +__attribute__((target("branch-protection=bti+leaf"))) // expected-error {{invalid or misplaced branch protection specification 'leaf'}} +void badoption0() {} + +__attribute__((target("branch-protection=bti+leaf+pac-ret"))) // expected-error {{invalid or misplaced branch protection specification 'leaf'}} +void badorder0() {} + +__attribute__ ((target("branch-protection=pac-ret+bti+leaf"))) // expected-error {{invalid or misplaced branch protection specification 'leaf'}} +void badorder1() {}