diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index c58c45416107e5dabd6d210b063aa2b118512a8f..5d7fd36723e20ff18a0417ddd28abf8ef3149298 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -434,6 +434,8 @@ ENUM_LANGOPT(SignReturnAddressScope, SignReturnAddressScopeKind, 2, SignReturnAd "Scope of return address signing") ENUM_LANGOPT(SignReturnAddressKey, SignReturnAddressKeyKind, 1, SignReturnAddressKeyKind::AKey, "Key used for return address signing") +ENUM_LANGOPT(SignReturnAddressType, SignReturnAddressTypeKind, 2, + SignReturnAddressTypeKind::None, "Type of return address signing") LANGOPT(BranchTargetEnforcement, 1, 0, "Branch-target enforcement enabled") LANGOPT(SpeculativeLoadHardening, 1, 0, "Speculative load hardening enabled") diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index 10b8260b34895e73cd20fb10f4b04b348a81f43d..85642b658cf67a1ed1b9b1fcf631b6c0b97cd378 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -324,6 +324,12 @@ public: All }; + enum class SignReturnAddressTypeKind { + None, + PacRet, + PacRetStrong + }; + enum class SignReturnAddressKeyKind { /// Return address signing uses APIA key. AKey, @@ -563,11 +569,26 @@ public: return getSignReturnAddressScope() != SignReturnAddressScopeKind::None; } + /// Check if return address type signing is enabled. + bool hasSignReturnAddressType() const { + return getSignReturnAddressType() != SignReturnAddressTypeKind::None; + } + /// Check if return address signing uses AKey. bool isSignReturnAddressWithAKey() const { return getSignReturnAddressKey() == SignReturnAddressKeyKind::AKey; } + /// Check if return address signing uses PacRetStrong. + bool isSignReturnAddressTypePacRetStrong() const { + return getSignReturnAddressType() == SignReturnAddressTypeKind::PacRetStrong; + } + + /// Check if return address signing uses PacRet. + bool isSignReturnAddressTypePacRet() const { + return getSignReturnAddressType() == SignReturnAddressTypeKind::PacRet; + } + /// Check if leaf functions are also signed. bool isSignReturnAddressScopeAll() const { return getSignReturnAddressScope() == SignReturnAddressScopeKind::All; diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index b4f3a69259fad3de0e0e4d867ab08e3a63d223ee..c473cececbc57a42e5fe6541fefa6b4e57ddecab 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -1309,12 +1309,75 @@ public: return true; } - struct BranchProtectionInfo { - LangOptions::SignReturnAddressScopeKind SignReturnAddr = - LangOptions::SignReturnAddressScopeKind::None; - LangOptions::SignReturnAddressKeyKind SignKey = - LangOptions::SignReturnAddressKeyKind::AKey; - bool BranchTargetEnforcement = false; + class BranchProtectionInfo { + public: + BranchProtectionInfo() + : SignReturnAddr(LangOptions::SignReturnAddressScopeKind::None), + SignKey(LangOptions::SignReturnAddressKeyKind::AKey), + SignType(LangOptions::SignReturnAddressTypeKind::None), + BranchTargetEnforcement(false) {} + + BranchProtectionInfo(const LangOptions &LangOpts) { + SignReturnAddr = + LangOpts.hasSignReturnAddress() + ? (LangOpts.isSignReturnAddressScopeAll() + ? LangOptions::SignReturnAddressScopeKind::All + : LangOptions::SignReturnAddressScopeKind::NonLeaf) + : LangOptions::SignReturnAddressScopeKind::None; + SignKey = LangOpts.isSignReturnAddressWithAKey() + ? LangOptions::SignReturnAddressKeyKind::AKey + : LangOptions::SignReturnAddressKeyKind::BKey; + + SignType = + LangOpts.hasSignReturnAddressType() + ? (LangOpts.isSignReturnAddressTypePacRetStrong() + ? LangOptions::SignReturnAddressTypeKind::PacRetStrong + : LangOptions::SignReturnAddressTypeKind::PacRet) + : LangOptions::SignReturnAddressTypeKind::None; + BranchTargetEnforcement = LangOpts.BranchTargetEnforcement; + } + + const char *getSignReturnAddrStr() const { + switch (SignReturnAddr) { + case LangOptions::SignReturnAddressScopeKind::None: + return "none"; + case LangOptions::SignReturnAddressScopeKind::NonLeaf: + return "non-leaf"; + case LangOptions::SignReturnAddressScopeKind::All: + return "all"; + default: + llvm_unreachable("Unexpected SignReturnAddressScopeKind"); + } + } + + const char *getSignKeyStr() const { + switch (SignKey) { + case LangOptions::SignReturnAddressKeyKind::AKey: + return "a_key"; + case LangOptions::SignReturnAddressKeyKind::BKey: + return "b_key"; + default: + llvm_unreachable("Unexpected SignReturnAddressKeyKind"); + } + } + + const char *getSignTypeStr() const { + switch (SignType) { + case LangOptions::SignReturnAddressTypeKind::None: + return "none"; + case LangOptions::SignReturnAddressTypeKind::PacRet: + return "pac_ret"; + case LangOptions::SignReturnAddressTypeKind::PacRetStrong: + return "pac_ret_strong"; + default: + llvm_unreachable("Unexpected SignReturnAddressTypeKind"); + } + } + + LangOptions::SignReturnAddressScopeKind SignReturnAddr; + LangOptions::SignReturnAddressKeyKind SignKey; + LangOptions::SignReturnAddressTypeKind SignType; + bool BranchTargetEnforcement; }; /// Determine if the Architecture in this TargetInfo supports branch diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index ac89e170da94596e58a70f7e92e3a0d8dbc307ce..6f3a3cb8d6d989105ff9fc0bb58c0e43f3c18a63 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -5564,6 +5564,8 @@ def fwarn_stack_size_EQ // don't have to parse the parameter twice. def msign_return_address_key_EQ : Joined<["-"], "msign-return-address-key=">, Values<"a_key,b_key">; +def msign_return_address_type_EQ : Joined<["-"], "msign-return-address-type=">, + Values<"none,pac_ret,pac_ret_strong">; def mbranch_target_enforce : Flag<["-"], "mbranch-target-enforce">, MarshallingInfoFlag>; def fno_dllexport_inlines : Flag<["-"], "fno-dllexport-inlines">, diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp index 8d8972c1613a9bdb60aa90fad412fa69a1b65791..932fb28b36bc9006b8ca56a80f305948771601ec 100644 --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -156,6 +156,13 @@ bool AArch64TargetInfo::validateBranchProtection(StringRef Spec, StringRef, else BPI.SignKey = LangOptions::SignReturnAddressKeyKind::BKey; + BPI.SignType = + llvm::StringSwitch(PBP.Type) + .Case("pac-ret", LangOptions::SignReturnAddressTypeKind::PacRet) + .Case("pac-ret-strong", + LangOptions::SignReturnAddressTypeKind::PacRetStrong) + .Default(LangOptions::SignReturnAddressTypeKind::None); + BPI.BranchTargetEnforcement = PBP.BranchTargetEnforcement; return true; } diff --git a/clang/lib/Basic/Targets/ARM.cpp b/clang/lib/Basic/Targets/ARM.cpp index fd005a6570fb545172ad11a51cbb5334bbc96f03..fb2f88b1208aa72f4ff2760e64d2f081b16fd17d 100644 --- a/clang/lib/Basic/Targets/ARM.cpp +++ b/clang/lib/Basic/Targets/ARM.cpp @@ -410,6 +410,12 @@ bool ARMTargetInfo::validateBranchProtection(StringRef Spec, StringRef Arch, Err = "b-key"; BPI.SignKey = LangOptions::SignReturnAddressKeyKind::AKey; + BPI.SignType = + llvm::StringSwitch(PBP.Type) + .Case("pac-ret", LangOptions::SignReturnAddressTypeKind::PacRet) + .Case("pac-ret-strong", + LangOptions::SignReturnAddressTypeKind::PacRetStrong) + .Default(LangOptions::SignReturnAddressTypeKind::None); BPI.BranchTargetEnforcement = PBP.BranchTargetEnforcement; return true; } diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index a334bb616d5345491eb2b68d8129703d1bd19b74..8b1fd5c3610fd9f60f28b6c2382a3e8ccfec9cf9 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -1977,6 +1977,8 @@ void CodeGenModule::getDefaultFunctionAttributes(StringRef Name, std::tie(Var, Value) = Attr.split('='); FuncAttrs.addAttribute(Var, Value); } + TargetInfo::BranchProtectionInfo BPI(LangOpts); + TargetCodeGenInfo::initBranchProtectionFnAttributes(BPI, FuncAttrs); } void CodeGenModule::addDefaultFunctionDefinitionAttributes(llvm::Function &F) { diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index e840ce85c2645259092f27c9b8346e44dd8eeabd..4a5115078270b84c8bcbc1013dee28fab1687539 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -815,7 +815,8 @@ void CodeGenModule::Release() { if (LangOpts.BranchTargetEnforcement) getModule().addModuleFlag(llvm::Module::Min, "branch-target-enforcement", 1); - if (LangOpts.hasSignReturnAddress()) + if (!LangOpts.isSignReturnAddressTypePacRetStrong() && + LangOpts.hasSignReturnAddress()) getModule().addModuleFlag(llvm::Module::Min, "sign-return-address", 1); if (LangOpts.isSignReturnAddressScopeAll()) getModule().addModuleFlag(llvm::Module::Min, "sign-return-address-all", diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index dabbd516b820e14269c9fdb153445174d7f7453c..fc8fca3fe46322bb0a9c85590ff44c844d0e08ad 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -12361,6 +12361,27 @@ TargetCodeGenInfo::createEnqueuedBlockKernel(CodeGenFunction &CGF, return F; } +void TargetCodeGenInfo::initBranchProtectionFnAttributes( + const TargetInfo::BranchProtectionInfo &BPI, llvm::AttrBuilder &FuncAttrs) { + if (BPI.SignReturnAddr == LangOptions::SignReturnAddressScopeKind::None) + return; + switch (BPI.SignType) { + case LangOptions::SignReturnAddressTypeKind::PacRet: { + FuncAttrs.addAttribute("sign-return-address", BPI.getSignReturnAddrStr()); + FuncAttrs.addAttribute("sign-return-address-key", BPI.getSignKeyStr()); + return; + } + case clang::LangOptions::SignReturnAddressTypeKind::PacRetStrong: { + std::string values = + std::string(BPI.getSignReturnAddrStr()) + ";" + BPI.getSignKeyStr(); + FuncAttrs.addAttribute("sign-return-address-strong", values); + return; + }; + default: + return; + } +} + /// Create an OpenCL kernel for an enqueued block. /// /// The type of the first argument (the block literal) is the struct type diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h index 30421612015b6fc6519661fc84a5029eb5ec7094..9b2b7e170573d6086dc6ea6bf0833549b9504852 100644 --- a/clang/lib/CodeGen/TargetInfo.h +++ b/clang/lib/CodeGen/TargetInfo.h @@ -363,6 +363,10 @@ public: // DO NOTHING by default. return false; } + // Add the Branch Protection Attributes of the FuncAttrs. + static void + initBranchProtectionFnAttributes(const TargetInfo::BranchProtectionInfo &BPI, + llvm::AttrBuilder &FuncAttrs); }; } // namespace CodeGen diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 93001072a32a104d94042c701585238607febfbd..21699557075ad77e1b12be96464e0e4fe5bbecec 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -1677,12 +1677,41 @@ void AddUnalignedAccessWarning(ArgStringList &CmdArgs) { } } +static Arg *GetHighestPriorityOfARMPACArg(const ArgList &Args, bool isAArch64) { + Arg *A = nullptr; + bool hasPacRet = false; + std::vector filteredArgs; + if (isAArch64) { + for (auto *arg : Args.filtered(options::OPT_msign_return_address_EQ, + options::OPT_mbranch_protection_EQ)) { + filteredArgs.push_back(arg); + } + } else { + for (auto *arg : Args.filtered(options::OPT_mbranch_protection_EQ)) { + filteredArgs.push_back(arg); + } + } + for (auto *arg : filteredArgs) { + arg->claim(); + StringRef value = arg->getValue(); + if (value.contains("pac-ret")) { + if (!value.contains("pac-ret-strong")) { + hasPacRet = true; + A = arg; + } else if (!hasPacRet) { + A = arg; + } + } else { + hasPacRet = false; + A = arg; + } + } + return A; +} + 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, - options::OPT_mbranch_protection_EQ) - : Args.getLastArg(options::OPT_mbranch_protection_EQ); + const Arg *A = GetHighestPriorityOfARMPACArg(Args, isAArch64); if (!A) return; @@ -1692,7 +1721,7 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args, D.Diag(diag::warn_incompatible_branch_protection_option) << Triple.getArchName(); - StringRef Scope, Key; + StringRef Scope, Key, Type; bool IndirectBranches; if (A->getOption().matches(options::OPT_msign_return_address_EQ)) { @@ -1713,11 +1742,14 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args, << "b-key" << A->getAsString(Args); Scope = PBP.Scope; Key = PBP.Key; + Type = PBP.Type; IndirectBranches = PBP.BranchTargetEnforcement; } - CmdArgs.push_back( Args.MakeArgString(Twine("-msign-return-address=") + Scope)); + if (!Type.equals("none")) + CmdArgs.push_back( + Args.MakeArgString(Twine("-msign-return-address-type=") + Type)); if (!Scope.equals("none")) CmdArgs.push_back( Args.MakeArgString(Twine("-msign-return-address-key=") + Key)); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 2dd96e68bb92fe19691f642f9fca4c3b44fbd2a8..17c8951ebd65d4e2c53b8cb72db88994d6681bc9 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -3538,6 +3538,13 @@ void CompilerInvocation::GenerateLangArgs(const LangOptions &Opts, LangOptions::SignReturnAddressKeyKind::BKey) GenerateArg(Args, OPT_msign_return_address_key_EQ, "b_key", SA); + if (Opts.getSignReturnAddressType() == + LangOptions::SignReturnAddressTypeKind::PacRet) + GenerateArg(Args, OPT_msign_return_address_type_EQ, "pac_ret", SA); + else if (Opts.getSignReturnAddressType() == + LangOptions::SignReturnAddressTypeKind::PacRetStrong) + GenerateArg(Args, OPT_msign_return_address_type_EQ, "pac_ret_strong", SA); + if (Opts.CXXABI) GenerateArg(Args, OPT_fcxx_abi_EQ, TargetCXXABI::getSpelling(*Opts.CXXABI), SA); @@ -4054,6 +4061,18 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args, << A->getAsString(Args) << SignKey; } } + + if (Arg *A = Args.getLastArg(OPT_msign_return_address_type_EQ)) { + StringRef SignType = A->getValue(); + if (!SignScope.empty() && !SignType.empty()) { + if (SignType.equals_insensitive("pac_ret")) + Opts.setSignReturnAddressType( + LangOptions::SignReturnAddressTypeKind::PacRet); + else if (SignType.equals_insensitive("pac_ret_strong")) + Opts.setSignReturnAddressType( + LangOptions::SignReturnAddressTypeKind::PacRetStrong); + } + } } // The value can be empty, which indicates the system default should be used. diff --git a/clang/test/CodeGen/aarch64-sign-return-address.c b/clang/test/CodeGen/aarch64-sign-return-address.c index 8717b428805c90e5465529539f7c0427d92c6b4d..01cb201e5b03b2626415ec4356306a893cd2e16c 100644 --- a/clang/test/CodeGen/aarch64-sign-return-address.c +++ b/clang/test/CodeGen/aarch64-sign-return-address.c @@ -3,7 +3,7 @@ // RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -msign-return-address=non-leaf %s | FileCheck %s --check-prefix=CHECK --check-prefix=PART // RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -mbranch-protection=none %s | FileCheck %s --check-prefix=CHECK --check-prefix=NONE -// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -mbranch-protection=pac-ret+leaf %s | FileCheck %s --check-prefix=CHECK --check-prefix=ALL +// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -mbranch-protection=pac-ret+leaf %s | FileCheck %s --check-prefix=CHECK --check-prefix=PAC_ALL // RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -mbranch-protection=pac-ret+b-key %s | FileCheck %s --check-prefix=CHECK --check-prefix=B-KEY // RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -mbranch-protection=bti %s | FileCheck %s --check-prefix=CHECK --check-prefix=BTE @@ -13,32 +13,40 @@ // CHECK-LABEL: @foo() #[[#ATTR:]] -// CHECK-NOT: attributes #[[#ATTR]] = { {{.*}} "sign-return-address" -// CHECK-NOT: attributes #[[#ATTR]] = { {{.*}} "sign-return-address-key" // CHECK-NOT: attributes #[[#ATTR]] = { {{.*}} "branch-target-enforcement" +// NONE-NOT: attributes #[[#ATTR]] = { {{.*}} "sign-return-address" +// NONE-NOT: attributes #[[#ATTR]] = { {{.*}} "sign-return-address-key" + +// PAC_ALL: attributes #[[#ATTR]] = { {{.*}} "sign-return-address" +// B-KEY: attributes #[[#ATTR]] = { {{.*}} "sign-return-address-key"="b_key" + // Check module attributes // NONE-NOT: !"branch-target-enforcement" // ALL-NOT: !"branch-target-enforcement" +// PAC_ALL-NOT: !"branch-target-enforcement" // PART-NOT: !"branch-target-enforcement" // BTE: !{i32 8, !"branch-target-enforcement", i32 1} // B-KEY-NOT: !"branch-target-enforcement" // NONE-NOT: !"sign-return-address" // ALL: !{i32 8, !"sign-return-address", i32 1} +// PAC_ALL: !{i32 8, !"sign-return-address", i32 1} // PART: !{i32 8, !"sign-return-address", i32 1} // BTE-NOT: !"sign-return-address" // B-KEY: !{i32 8, !"sign-return-address", i32 1} // NONE-NOT: !"sign-return-address-all" // ALL: !{i32 8, !"sign-return-address-all", i32 1} +// PAC_ALL: !{i32 8, !"sign-return-address-all", i32 1} // PART-NOT: !"sign-return-address-all" // BTE-NOT: !"sign-return-address-all" // B-KEY-NOT: !"sign-return-address-all" // NONE-NOT: !"sign-return-address-with-bkey" // ALL-NOT: !"sign-return-address-with-bkey" +// PAC_ALL-NOT: !"sign-return-address-with-bkey" // PART-NOT: !"sign-return-address-with-bkey" // BTE-NOT: !"sign-return-address-with-bkey" // B-KEY: !{i32 8, !"sign-return-address-with-bkey", i32 1} diff --git a/clang/test/CodeGen/arm-branch-protection-attr-2.c b/clang/test/CodeGen/arm-branch-protection-attr-2.c index 1f3c00873043e8ee80ab4082082bea16a85a129b..0d145c7f62d1dfd408266a7b114dbd62996ab8a1 100644 --- a/clang/test/CodeGen/arm-branch-protection-attr-2.c +++ b/clang/test/CodeGen/arm-branch-protection-attr-2.c @@ -9,10 +9,15 @@ // CHECK-LABEL: @foo() #[[#ATTR:]] -// CHECK-NOT: attributes #[[#ATTR]] = { {{.*}} "sign-return-address" -// CHECK-NOT: attributes #[[#ATTR]] = { {{.*}} "sign-return-address-key" // CHECK-NOT: attributes #[[#ATTR]] = { {{.*}} "branch-target-enforcement" +// NONE-NOT: attributes #[[#ATTR]] = { {{.*}} "sign-return-address" +// NONE-NOT: attributes #[[#ATTR]] = { {{.*}} "sign-return-address-key" + +// ALL: attributes #[[#ATTR]] = { {{.*}} "sign-return-address"="all" +// PART: attributes #[[#ATTR]] = { {{.*}} "sign-return-address"="non-leaf" + + // Check module attributes // NONE-NOT: !"branch-target-enforcement" diff --git a/llvm/include/llvm/Support/TargetParser.h b/llvm/include/llvm/Support/TargetParser.h index c3a6cceaee6bedfb9c959edf784f407715e86197..bf33476af97f57507832efced5579f29bafb412a 100644 --- a/llvm/include/llvm/Support/TargetParser.h +++ b/llvm/include/llvm/Support/TargetParser.h @@ -184,6 +184,7 @@ namespace ARM { struct ParsedBranchProtection { StringRef Scope; StringRef Key; + StringRef Type; bool BranchTargetEnforcement; }; diff --git a/llvm/lib/Support/TargetParser.cpp b/llvm/lib/Support/TargetParser.cpp index e5590d458fedcd9d89b7117f454d550fd4f34110..8da67fc0b4137e5581bf152b185f0f9b1b02b57d 100644 --- a/llvm/lib/Support/TargetParser.cpp +++ b/llvm/lib/Support/TargetParser.cpp @@ -351,7 +351,7 @@ bool getCPUFeaturesExceptStdExt(CPUKind Kind, // an erroneous part of the spec. bool ARM::parseBranchProtection(StringRef Spec, ParsedBranchProtection &PBP, StringRef &Err) { - PBP = {"none", "a_key", false}; + PBP = {"none", "a_key", "none",false}; if (Spec == "none") return true; // defaults are ok @@ -369,7 +369,8 @@ bool ARM::parseBranchProtection(StringRef Spec, ParsedBranchProtection &PBP, PBP.BranchTargetEnforcement = true; continue; } - if (Opt == "pac-ret") { + if (Opt == "pac-ret" || Opt == "pac-ret-strong") { + PBP.Type = Opt == "pac-ret" ? "pac_ret" : "pac_ret_strong"; PBP.Scope = "non-leaf"; for (; I + 1 != E; ++I) { StringRef PACOpt = Opts[I + 1].trim();