Index: clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- clang/lib/CodeGen/CodeGenModule.cpp +++ clang/lib/CodeGen/CodeGenModule.cpp @@ -590,6 +590,21 @@ 1); } + if (LangOpts.BranchTargetEnforcement) { + getModule().addModuleFlag(llvm::Module::Override, + "branch-target-enforcement", 1); + } + + if (LangOpts.hasSignReturnAddress()) { + getModule().addModuleFlag(llvm::Module::Override, "sign-return-address", 1); + if (LangOpts.isSignReturnAddressScopeAll()) + getModule().addModuleFlag(llvm::Module::Override, + "sign-return-address-all", 1); + if (!LangOpts.isSignReturnAddressWithAKey()) + getModule().addModuleFlag(llvm::Module::Override, + "sign-return-address-with-bkey", 1); + } + if (LangOpts.CUDAIsDevice && getTriple().isNVPTX()) { // Indicate whether __nvvm_reflect should be configured to flush denormal // floating point values to 0. (This corresponds to its "__CUDA_FTZ" Index: llvm/lib/Target/AArch64/AArch64BranchTargets.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64BranchTargets.cpp +++ llvm/lib/Target/AArch64/AArch64BranchTargets.cpp @@ -16,6 +16,7 @@ // //===----------------------------------------------------------------------===// +#include "AArch64MachineFunctionInfo.h" #include "AArch64Subtarget.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstrBuilder.h" @@ -57,13 +58,13 @@ } bool AArch64BranchTargets::runOnMachineFunction(MachineFunction &MF) { - const Function &F = MF.getFunction(); - if (!F.hasFnAttribute("branch-target-enforcement")) + if (!MF.getInfo()->branchTargetEnforcement()) return false; LLVM_DEBUG( dbgs() << "********** AArch64 Branch Targets **********\n" << "********** Function: " << MF.getName() << '\n'); + const Function &F = MF.getFunction(); // LLVM does not consider basic blocks which are the targets of jump tables // to be address-taken (the address can't escape anywhere else), but they are Index: llvm/lib/Target/AArch64/AArch64FrameLowering.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64FrameLowering.cpp +++ llvm/lib/Target/AArch64/AArch64FrameLowering.cpp @@ -375,31 +375,6 @@ return MBB.erase(I); } -static bool ShouldSignReturnAddress(MachineFunction &MF) { - // The function should be signed in the following situations: - // - sign-return-address=all - // - sign-return-address=non-leaf and the functions spills the LR - - const Function &F = MF.getFunction(); - if (!F.hasFnAttribute("sign-return-address")) - return false; - - StringRef Scope = F.getFnAttribute("sign-return-address").getValueAsString(); - if (Scope.equals("none")) - return false; - - if (Scope.equals("all")) - return true; - - assert(Scope.equals("non-leaf") && "Expected all, none or non-leaf"); - - for (const auto &Info : MF.getFrameInfo().getCalleeSavedInfo()) - if (Info.getReg() == AArch64::LR) - return true; - - return false; -} - // Convenience function to create a DWARF expression for // Expr + NumBytes + NumVGScaledBytes * AArch64::VG static void appendVGScaledOffsetExpr(SmallVectorImpl &Expr, @@ -1007,17 +982,6 @@ // } -static bool ShouldSignWithAKey(MachineFunction &MF) { - const Function &F = MF.getFunction(); - if (!F.hasFnAttribute("sign-return-address-key")) - return true; - - const StringRef Key = - F.getFnAttribute("sign-return-address-key").getValueAsString(); - assert(Key.equals_lower("a_key") || Key.equals_lower("b_key")); - return Key.equals_lower("a_key"); -} - static bool needsWinCFI(const MachineFunction &MF) { const Function &F = MF.getFunction(); return MF.getTarget().getMCAsmInfo()->usesWindowsCFI() && @@ -1074,15 +1038,16 @@ // to determine the end of the prologue. DebugLoc DL; - if (ShouldSignReturnAddress(MF)) { - if (ShouldSignWithAKey(MF)) - BuildMI(MBB, MBBI, DL, TII->get(AArch64::PACIASP)) - .setMIFlag(MachineInstr::FrameSetup); - else { + const auto &MFnI = *MF.getInfo(); + if (MFnI.shouldSignReturnAddress()) { + if (MFnI.shouldSignWithBKey()) { BuildMI(MBB, MBBI, DL, TII->get(AArch64::EMITBKEY)) .setMIFlag(MachineInstr::FrameSetup); BuildMI(MBB, MBBI, DL, TII->get(AArch64::PACIBSP)) .setMIFlag(MachineInstr::FrameSetup); + } else { + BuildMI(MBB, MBBI, DL, TII->get(AArch64::PACIASP)) + .setMIFlag(MachineInstr::FrameSetup); } unsigned CFIIndex = @@ -1514,7 +1479,8 @@ static void InsertReturnAddressAuth(MachineFunction &MF, MachineBasicBlock &MBB) { - if (!ShouldSignReturnAddress(MF)) + const auto &MFI = *MF.getInfo(); + if (!MFI.shouldSignReturnAddress()) return; const AArch64Subtarget &Subtarget = MF.getSubtarget(); const TargetInstrInfo *TII = Subtarget.getInstrInfo(); @@ -1531,13 +1497,13 @@ if (Subtarget.hasV8_3aOps() && MBBI != MBB.end() && MBBI->getOpcode() == AArch64::RET_ReallyLR) { BuildMI(MBB, MBBI, DL, - TII->get(ShouldSignWithAKey(MF) ? AArch64::RETAA : AArch64::RETAB)) + TII->get(MFI.shouldSignWithBKey() ? AArch64::RETAB : AArch64::RETAA)) .copyImplicitOps(*MBBI); MBB.erase(MBBI); } else { BuildMI( MBB, MBBI, DL, - TII->get(ShouldSignWithAKey(MF) ? AArch64::AUTIASP : AArch64::AUTIBSP)) + TII->get(MFI.shouldSignWithBKey() ? AArch64::AUTIBSP : AArch64::AUTIASP)) .setMIFlag(MachineInstr::FrameDestroy); } } Index: llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp +++ llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#include "AArch64MachineFunctionInfo.h" #include "AArch64TargetMachine.h" #include "MCTargetDesc/AArch64AddressingModes.h" #include "llvm/ADT/APSInt.h" Index: llvm/lib/Target/AArch64/AArch64InstrInfo.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64InstrInfo.cpp +++ llvm/lib/Target/AArch64/AArch64InstrInfo.cpp @@ -5760,84 +5760,20 @@ static bool outliningCandidatesSigningScopeConsensus(const outliner::Candidate &a, const outliner::Candidate &b) { - const Function &Fa = a.getMF()->getFunction(); - const Function &Fb = b.getMF()->getFunction(); + const auto &MFIa = a.getMF()->getInfo(); + const auto &MFIb = a.getMF()->getInfo(); - // If none of the functions have the "sign-return-address" attribute their - // signing behaviour is equal - if (!Fa.hasFnAttribute("sign-return-address") && - !Fb.hasFnAttribute("sign-return-address")) { - return true; - } - - // If both functions have the "sign-return-address" attribute their signing - // behaviour is equal, if the values of the attributes are equal - if (Fa.hasFnAttribute("sign-return-address") && - Fb.hasFnAttribute("sign-return-address")) { - StringRef ScopeA = - Fa.getFnAttribute("sign-return-address").getValueAsString(); - StringRef ScopeB = - Fb.getFnAttribute("sign-return-address").getValueAsString(); - return ScopeA.equals(ScopeB); - } - - // If function B doesn't have the "sign-return-address" attribute but A does, - // the functions' signing behaviour is equal if A's value for - // "sign-return-address" is "none" and vice versa. - if (Fa.hasFnAttribute("sign-return-address")) { - StringRef ScopeA = - Fa.getFnAttribute("sign-return-address").getValueAsString(); - return ScopeA.equals("none"); - } - - if (Fb.hasFnAttribute("sign-return-address")) { - StringRef ScopeB = - Fb.getFnAttribute("sign-return-address").getValueAsString(); - return ScopeB.equals("none"); - } - - llvm_unreachable("Unkown combination of sign-return-address attributes"); + return MFIa->shouldSignReturnAddress(false) == MFIb->shouldSignReturnAddress(false) && + MFIa->shouldSignReturnAddress(true) == MFIb->shouldSignReturnAddress(true); } static bool outliningCandidatesSigningKeyConsensus(const outliner::Candidate &a, const outliner::Candidate &b) { - const Function &Fa = a.getMF()->getFunction(); - const Function &Fb = b.getMF()->getFunction(); - - // If none of the functions have the "sign-return-address-key" attribute - // their keys are equal - if (!Fa.hasFnAttribute("sign-return-address-key") && - !Fb.hasFnAttribute("sign-return-address-key")) { - return true; - } - - // If both functions have the "sign-return-address-key" attribute their - // keys are equal if the values of "sign-return-address-key" are equal - if (Fa.hasFnAttribute("sign-return-address-key") && - Fb.hasFnAttribute("sign-return-address-key")) { - StringRef KeyA = - Fa.getFnAttribute("sign-return-address-key").getValueAsString(); - StringRef KeyB = - Fb.getFnAttribute("sign-return-address-key").getValueAsString(); - return KeyA.equals(KeyB); - } - - // If B doesn't have the "sign-return-address-key" attribute, both keys are - // equal, if function a has the default key (a_key) - if (Fa.hasFnAttribute("sign-return-address-key")) { - StringRef KeyA = - Fa.getFnAttribute("sign-return-address-key").getValueAsString(); - return KeyA.equals_lower("a_key"); - } - - if (Fb.hasFnAttribute("sign-return-address-key")) { - StringRef KeyB = - Fb.getFnAttribute("sign-return-address-key").getValueAsString(); - return KeyB.equals_lower("a_key"); - } + const auto &MFIa = a.getMF()->getInfo(); + const auto &MFIb = a.getMF()->getInfo(); - llvm_unreachable("Unkown combination of sign-return-address-key attributes"); + return MFIa->shouldSignWithBKey() == MFIb->shouldSignWithBKey(); } static bool outliningCandidatesV8_3OpsConsensus(const outliner::Candidate &a, @@ -5893,9 +5829,10 @@ // v8.3a RET can be replaced by RETAA/RETAB and no AUT instruction is // necessary. However, at this point we don't know if the outlined function // will have a RET instruction so we assume the worst. - const Function &FCF = FirstCand.getMF()->getFunction(); const TargetRegisterInfo &TRI = getRegisterInfo(); - if (FCF.hasFnAttribute("sign-return-address")) { + if (FirstCand.getMF() + ->getInfo() + ->shouldSignReturnAddress(true)) { // One PAC and one AUT instructions NumBytesToCreateFrame += 8; @@ -6024,7 +5961,7 @@ NumBytesToCreateFrame += 4; bool HasBTI = any_of(RepeatedSequenceLocs, [](outliner::Candidate &C) { - return C.getMF()->getFunction().hasFnAttribute("branch-target-enforcement"); + return C.getMF()->getInfo()->branchTargetEnforcement(); }); // We check to see if CFI Instructions are present, and if they are @@ -6672,27 +6609,11 @@ // If a bunch of candidates reach this point they must agree on their return // address signing. It is therefore enough to just consider the signing // behaviour of one of them - const Function &CF = OF.Candidates.front().getMF()->getFunction(); - bool ShouldSignReturnAddr = false; - if (CF.hasFnAttribute("sign-return-address")) { - StringRef Scope = - CF.getFnAttribute("sign-return-address").getValueAsString(); - if (Scope.equals("all")) - ShouldSignReturnAddr = true; - else if (Scope.equals("non-leaf") && !IsLeafFunction) - ShouldSignReturnAddr = true; - } + const auto &MFI = *OF.Candidates.front().getMF()->getInfo(); + bool ShouldSignReturnAddr = MFI.shouldSignReturnAddress(!IsLeafFunction); // a_key is the default - bool ShouldSignReturnAddrWithAKey = true; - if (CF.hasFnAttribute("sign-return-address-key")) { - const StringRef Key = - CF.getFnAttribute("sign-return-address-key").getValueAsString(); - // Key can either be a_key or b_key - assert((Key.equals_lower("a_key") || Key.equals_lower("b_key")) && - "Return address signing key must be either a_key or b_key"); - ShouldSignReturnAddrWithAKey = Key.equals_lower("a_key"); - } + bool ShouldSignReturnAddrWithAKey = !MFI.shouldSignWithBKey(); // If this is a tail call outlined function, then there's already a return. if (OF.FrameConstructionID == MachineOutlinerTailCall || Index: llvm/lib/Target/AArch64/AArch64InstrInfo.td =================================================================== --- llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -593,8 +593,8 @@ // Avoid generating STRQro if it is slow, unless we're optimizing for code size. def UseSTRQro : Predicate<"!Subtarget->isSTRQroSlow() || shouldOptForSize(MF)">; - def UseBTI : Predicate<[{ MF->getFunction().hasFnAttribute("branch-target-enforcement") }]>; - def NotUseBTI : Predicate<[{ !MF->getFunction().hasFnAttribute("branch-target-enforcement") }]>; + def UseBTI : Predicate<[{ MF->getInfo()->branchTargetEnforcement() }]>; + def NotUseBTI : Predicate<[{ !MF->getInfo()->branchTargetEnforcement() }]>; def SLSBLRMitigation : Predicate<[{ MF->getSubtarget().hardenSlsBlr() }]>; def NoSLSBLRMitigation : Predicate<[{ !MF->getSubtarget().hardenSlsBlr() }]>; Index: llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h =================================================================== --- llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h +++ llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h @@ -36,6 +36,13 @@ /// AArch64FunctionInfo - This class is derived from MachineFunctionInfo and /// contains private AArch64-specific information for each MachineFunction. class AArch64FunctionInfo final : public MachineFunctionInfo { +public: + enum SignReturnAddressTy { PACRetNone, PACRetNonLeaf, PACRetAll }; + +private: + /// Backreference to the machine function. + MachineFunction &MF; + /// Number of bytes of arguments this function has on the stack. If the callee /// is expected to restore the argument stack this should be a multiple of 16, /// all usable during a tail call. @@ -135,17 +142,19 @@ /// e.g. Tail Call, Thunk, or Function if none apply. Optional OutliningStyle; -public: - AArch64FunctionInfo() = default; + /// SignReturnAddress denotes what kind of PAC-RET is enabled; + SignReturnAddressTy SignReturnAddress; - explicit AArch64FunctionInfo(MachineFunction &MF) { - (void)MF; + /// SignWithBKey enables use of the B keyfor PAC-RET, otherwise use A key. + bool SignWithBKey; + + /// BranchTargetEnforcement enables placing BTI instructions at potential + /// indirect branch destinations. + bool BranchTargetEnforcement; + +public: + explicit AArch64FunctionInfo(MachineFunction &MF); - // If we already know that the function doesn't have a redzone, set - // HasRedZone here. - if (MF.getFunction().hasFnAttribute(Attribute::NoRedZone)) - HasRedZone = false; - } void initializeBaseYamlFields(const yaml::AArch64FunctionInfo &YamlMFI); unsigned getBytesInStackArgArea() const { return BytesInStackArgArea; } @@ -338,6 +347,13 @@ TaggedBasePointerOffset = Offset; } + bool shouldSignReturnAddress() const; + bool shouldSignReturnAddress(bool SpillsLR) const; + + bool shouldSignWithBKey() const { return SignWithBKey; } + + bool branchTargetEnforcement() const { return BranchTargetEnforcement; } + private: // Hold the lists of LOHs. MILOHContainer LOHContainerSet; Index: llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp +++ llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp @@ -14,6 +14,8 @@ //===----------------------------------------------------------------------===// #include "AArch64MachineFunctionInfo.h" +#include "AArch64InstrInfo.h" +#include using namespace llvm; @@ -30,3 +32,70 @@ if (YamlMFI.HasRedZone.hasValue()) HasRedZone = YamlMFI.HasRedZone; } + +static AArch64FunctionInfo::SignReturnAddressTy +GetSignReturnAddress(const Function &F) { + // The function should be signed in the following situations: + // - sign-return-address=all + // - sign-return-address=non-leaf and the functions spills the LR + if (!F.hasFnAttribute("sign-return-address")) { + const Module &M = *F.getParent(); + if (!M.getModuleFlag("sign-return-address")) + return AArch64FunctionInfo::PACRetNone; + if (M.getModuleFlag("sign-return-address-all")) + return AArch64FunctionInfo::PACRetAll; + return AArch64FunctionInfo::PACRetNonLeaf; + } + + StringRef Scope = F.getFnAttribute("sign-return-address").getValueAsString(); + if (Scope.equals("none")) + return AArch64FunctionInfo::PACRetNone; + + if (Scope.equals("all")) + return AArch64FunctionInfo::PACRetAll; + + assert(Scope.equals("non-leaf")); + return AArch64FunctionInfo::PACRetNonLeaf; +} + +static bool ShouldSignWithBKey(const Function &F) { + if (!F.hasFnAttribute("sign-return-address-key")) + return F.getParent()->getModuleFlag("sign-return-address-with-bkey") != nullptr; + + const StringRef Key = + F.getFnAttribute("sign-return-address-key").getValueAsString(); + assert(Key.equals_lower("a_key") || Key.equals_lower("b_key")); + return Key.equals_lower("b_key"); +} + +AArch64FunctionInfo::AArch64FunctionInfo(MachineFunction &MF) : MF(MF) { + // If we already know that the function doesn't have a redzone, set + // HasRedZone here. + if (MF.getFunction().hasFnAttribute(Attribute::NoRedZone)) + HasRedZone = false; + + const Function &F = MF.getFunction(); + SignReturnAddress = GetSignReturnAddress(F); + SignWithBKey = ShouldSignWithBKey(F); + BranchTargetEnforcement = + F.hasFnAttribute("branch-target-enforcement") || + F.getParent()->getModuleFlag("branch-target-enforcement") != nullptr; +} + +bool AArch64FunctionInfo::shouldSignReturnAddress(bool SpillsLR) const { + switch (SignReturnAddress) { + case AArch64FunctionInfo::PACRetNone: + return false; + case AArch64FunctionInfo::PACRetAll: + return true; + case AArch64FunctionInfo::PACRetNonLeaf: + return SpillsLR; + } + llvm_unreachable("Unexpected PAC-RET variant"); +} + +bool AArch64FunctionInfo::shouldSignReturnAddress() const { + return shouldSignReturnAddress(llvm::any_of( + MF.getFrameInfo().getCalleeSavedInfo(), + [](const auto &Info) { return Info.getReg() == AArch64::LR; })); +} Index: llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp =================================================================== --- llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp +++ llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp @@ -789,7 +789,7 @@ // When BTI is enabled, we need to use TCRETURNriBTI to make sure that we use // x16 or x17. - if (CallerF.getFunction().hasFnAttribute("branch-target-enforcement")) + if (CallerF.getInfo()->branchTargetEnforcement()) return AArch64::TCRETURNriBTI; return AArch64::TCRETURNri; @@ -809,7 +809,7 @@ // TODO: Right now, regbankselect doesn't know how to handle the rtcGPR64 // register class. Until we can do that, we should fall back here. - if (F.hasFnAttribute("branch-target-enforcement")) { + if (MF.getInfo()->branchTargetEnforcement()) { LLVM_DEBUG( dbgs() << "Cannot lower indirect tail calls with BTI enabled yet.\n"); return false; Index: llvm/test/CodeGen/AArch64/pacbti-llvm-generated-funcs-1.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/AArch64/pacbti-llvm-generated-funcs-1.ll @@ -0,0 +1,30 @@ +;; RUN: llc %s -o -| FileCheck %s +target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" +target triple = "aarch64-unknown-linux" + +@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 1, void ()* @asan.module_ctor, i8* null }] + +define dso_local i32 @f() #0 { +entry: + ret i32 0 +} +;; CHECK-LABEL: f: +;; CHECK: hint #34 + +declare void @__asan_init() +declare void @__asan_version_mismatch_check_v8() + +define internal void @asan.module_ctor() { + call void @__asan_init() + call void @__asan_version_mismatch_check_v8() + ret void +} +;; CHECK-LABEL: asan.module_ctor: +;; CHECK: hint #34 + +attributes #0 = { noinline nounwind optnone sanitize_address uwtable "branch-target-enforcement" "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="non-leaf" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+neon,+v8.3a" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.module.flags = !{!0, !1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 4, !"branch-target-enforcement", i32 1} \ No newline at end of file Index: llvm/test/CodeGen/AArch64/pacbti-llvm-generated-funcs-2.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/AArch64/pacbti-llvm-generated-funcs-2.ll @@ -0,0 +1,70 @@ +;; RUN: llc --mattr=+v8.3a %s -o - | FileCheck %s +target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" +target triple = "aarch64-unknown-linux" + +@__llvm_gcov_ctr = internal global [1 x i64] zeroinitializer +@0 = private unnamed_addr constant [7 x i8] c"m.gcda\00", align 1 +@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* @__llvm_gcov_init, i8* null }] + +define dso_local i32 @f() local_unnamed_addr #0 { +entry: + ret i32 0 +} +;; CHECK-LABEL: f: +;; CHECK: pacibsp + +declare void @llvm_gcda_start_file(i8*, i32, i32) local_unnamed_addr + +declare void @llvm_gcda_emit_function(i32, i32, i32) local_unnamed_addr + +declare void @llvm_gcda_emit_arcs(i32, i64*) local_unnamed_addr + +declare void @llvm_gcda_summary_info() local_unnamed_addr + +declare void @llvm_gcda_end_file() local_unnamed_addr + +define internal void @__llvm_gcov_writeout() unnamed_addr #1 { +entry: + tail call void @llvm_gcda_start_file(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @0, i64 0, i64 0), i32 875575338, i32 0) + tail call void @llvm_gcda_emit_function(i32 0, i32 0, i32 0) + tail call void @llvm_gcda_emit_arcs(i32 1, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__llvm_gcov_ctr, i64 0, i64 0)) + tail call void @llvm_gcda_summary_info() + tail call void @llvm_gcda_end_file() + ret void +} +;; CHECK-LABEL: __llvm_gcov_writeout: +;; CHECK: .cfi_b_key_frame +;; CHECK-NEXT: pacibsp +;; CHECK-NEXT: .cfi_negate_ra_state + +define internal void @__llvm_gcov_reset() unnamed_addr #2 { +entry: + store i64 0, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__llvm_gcov_ctr, i64 0, i64 0), align 8 + ret void +} +;; CHECK-LABEL: __llvm_gcov_reset: +;; CHECK: pacibsp + +declare void @llvm_gcov_init(void ()*, void ()*) local_unnamed_addr + +define internal void @__llvm_gcov_init() unnamed_addr #1 { +entry: + tail call void @llvm_gcov_init(void ()* nonnull @__llvm_gcov_writeout, void ()* nonnull @__llvm_gcov_reset) + ret void +} +;; CHECK-LABEL: __llvm_gcov_init: +;; CHECK: .cfi_b_key_frame +;; CHECK-NEXT: pacibsp +;; CHECK-NEXT: .cfi_negate_ra_state + +attributes #0 = { norecurse nounwind readnone "sign-return-address"="all" "sign-return-address-key"="b_key" } +attributes #1 = { noinline } +attributes #2 = { nofree noinline norecurse nounwind writeonly } + +!llvm.module.flags = !{!0, !1, !2, !3, !4} + +!0 = !{i32 2, !"Debug Info Version", i32 3} +!1 = !{i32 1, !"wchar_size", i32 4} +!2 = !{i32 4, !"sign-return-address", i32 1} +!3 = !{i32 4, !"sign-return-address-all", i32 1} +!4 = !{i32 4, !"sign-return-address-with-bkey", i32 1}