diff options
author | Tim Northover <t.p.northover@gmail.com> | 2020-12-14 12:44:07 +0000 |
---|---|---|
committer | Tim Northover <t.p.northover@gmail.com> | 2020-12-18 18:58:22 +0000 |
commit | bdc0a1d6fda17a527fad86d5af7e49b4c0a9ad60 (patch) | |
tree | fefe1948f365ee98f4333ee45d787878a8e938d3 | |
parent | 58b71bb621fedc9b3dc390647053468cbca293a9 (diff) | |
download | llvm-bdc0a1d6fda17a527fad86d5af7e49b4c0a9ad60.tar.gz |
IR+AArch64: add a "swiftasync" argument attribute.
This extends any frame record created in the function to include that
parameter, passed in X22.
The new record looks like [X22, FP, LR] in memory, and FP is stored with 0b0001
stored in bits 63:60 (CodeGen assumes they are 0b0000 in normal operation). The
effect of this is that tools walking the stack should expect to see one of
three values there:
* 0b0000 => a normal, non-extended record with just [FP, LR]
* 0b0001 => the extended record [X22, FP, LR]
* 0b1111 => kernel space, and a non-extended record.
All other values are currently reserved.
If compiling for arm64e this context pointer is address-discriminated with the
discriminator 0xc31a and the DB (process-specific) key.
There is also an "i8** @llvm.swift.async.context.addr()" intrinsic providing
front-ends access to this slot (and forcing its creation initialized to nullptr
if necessary).
33 files changed, 488 insertions, 17 deletions
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index d085f4030b93..9403cad216a9 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -1225,6 +1225,12 @@ Currently, only the following parameter attributes are defined: a valid attribute for return values and can only be applied to one parameter. +``swiftasync`` + This indicates that the parameter is the asynchronous context parameter and + triggers the creation of a target-specific extended frame record to store + this pointer. This is not a valid attribute for return values and can only + be applied to one parameter. + ``swifterror`` This attribute is motivated to model and optimize Swift error handling. It can be applied to a parameter with pointer to pointer type or a @@ -11616,6 +11622,29 @@ Note that calling this intrinsic does not prevent function inlining or other aggressive transformations, so the value returned may not be that of the obvious source-language caller. +'``llvm.swift.async.context.addr``' Intrinsic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: +""""""" + +:: + + declare i8** @llvm.swift.async.context.addr() + +Overview: +""""""""" + +The '``llvm.swift.async.context.addr``' intrinsic returns a pointer to +the part of the extended frame record containing the asynchronous +context of a Swift execution. + +Semantics: +"""""""""" + +If the function has a ``swiftasync`` parameter, that argument will initially +be stored at the returned address. If not, it will be initialized to null. + '``llvm.localescape``' and '``llvm.localrecover``' Intrinsics ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h index de4fe6630324..a94e102c34c8 100644 --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -644,6 +644,7 @@ enum AttributeKindCodes { ATTR_KIND_NO_MERGE = 66, ATTR_KIND_NULL_POINTER_IS_VALID = 67, ATTR_KIND_NOUNDEF = 68, + ATTR_KIND_SWIFT_ASYNC = 72, }; enum ComdatSelectionKindCodes { diff --git a/llvm/include/llvm/CodeGen/TargetCallingConv.h b/llvm/include/llvm/CodeGen/TargetCallingConv.h index 347d7ff40404..44baf4b09cd6 100644 --- a/llvm/include/llvm/CodeGen/TargetCallingConv.h +++ b/llvm/include/llvm/CodeGen/TargetCallingConv.h @@ -38,6 +38,7 @@ namespace ISD { unsigned IsPreallocated : 1; ///< ByVal without the copy unsigned IsSplitEnd : 1; ///< Last part of a split unsigned IsSwiftSelf : 1; ///< Swift self parameter + unsigned IsSwiftAsync : 1; ///< Swift async context parameter unsigned IsSwiftError : 1; ///< Swift error parameter unsigned IsCFGuardTarget : 1; ///< Control Flow Guard target unsigned IsHva : 1; ///< HVA field for @@ -58,11 +59,11 @@ namespace ISD { ArgFlagsTy() : IsZExt(0), IsSExt(0), IsInReg(0), IsSRet(0), IsByVal(0), IsNest(0), IsReturned(0), IsSplit(0), IsInAlloca(0), IsPreallocated(0), - IsSplitEnd(0), IsSwiftSelf(0), IsSwiftError(0), IsCFGuardTarget(0), - IsHva(0), IsHvaStart(0), IsSecArgPass(0), ByValAlign(0), OrigAlign(0), - IsInConsecutiveRegsLast(0), IsInConsecutiveRegs(0), - IsCopyElisionCandidate(0), IsPointer(0), ByValSize(0), - PointerAddrSpace(0) { + IsSplitEnd(0), IsSwiftSelf(0), IsSwiftAsync(0), IsSwiftError(0), + IsCFGuardTarget(0), IsHva(0), IsHvaStart(0), IsSecArgPass(0), + ByValAlign(0), OrigAlign(0), IsInConsecutiveRegsLast(0), + IsInConsecutiveRegs(0), IsCopyElisionCandidate(0), IsPointer(0), + ByValSize(0), PointerAddrSpace(0) { static_assert(sizeof(*this) == 3 * sizeof(unsigned), "flags are too big"); } @@ -90,6 +91,9 @@ namespace ISD { bool isSwiftSelf() const { return IsSwiftSelf; } void setSwiftSelf() { IsSwiftSelf = 1; } + bool isSwiftAsync() const { return IsSwiftAsync; } + void setSwiftAsync() { IsSwiftAsync = 1; } + bool isSwiftError() const { return IsSwiftError; } void setSwiftError() { IsSwiftError = 1; } diff --git a/llvm/include/llvm/CodeGen/TargetFrameLowering.h b/llvm/include/llvm/CodeGen/TargetFrameLowering.h index d6580430daf7..f9655721af41 100644 --- a/llvm/include/llvm/CodeGen/TargetFrameLowering.h +++ b/llvm/include/llvm/CodeGen/TargetFrameLowering.h @@ -156,6 +156,14 @@ public: /// returns false, spill slots will be assigned using generic implementation. /// assignCalleeSavedSpillSlots() may add, delete or rearrange elements of /// CSI. + virtual bool assignCalleeSavedSpillSlots(MachineFunction &MF, + const TargetRegisterInfo *TRI, + std::vector<CalleeSavedInfo> &CSI, + unsigned &MinCSFrameIndex, + unsigned &MaxCSFrameIndex) const { + return assignCalleeSavedSpillSlots(MF, TRI, CSI); + } + virtual bool assignCalleeSavedSpillSlots(MachineFunction &MF, const TargetRegisterInfo *TRI, diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h index 62c4b0765b2f..78b7668330a5 100644 --- a/llvm/include/llvm/CodeGen/TargetLowering.h +++ b/llvm/include/llvm/CodeGen/TargetLowering.h @@ -282,6 +282,7 @@ public: bool IsPreallocated : 1; bool IsReturned : 1; bool IsSwiftSelf : 1; + bool IsSwiftAsync : 1; bool IsSwiftError : 1; bool IsCFGuardTarget : 1; MaybeAlign Alignment = None; @@ -292,7 +293,7 @@ public: : IsSExt(false), IsZExt(false), IsInReg(false), IsSRet(false), IsNest(false), IsByVal(false), IsInAlloca(false), IsPreallocated(false), IsReturned(false), IsSwiftSelf(false), - IsSwiftError(false), IsCFGuardTarget(false) {} + IsSwiftAsync(false), IsSwiftError(false), IsCFGuardTarget(false) {} void setAttributes(const CallBase *Call, unsigned ArgIdx); }; diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td index 395f9dbfb176..5524d697f7d8 100644 --- a/llvm/include/llvm/IR/Attributes.td +++ b/llvm/include/llvm/IR/Attributes.td @@ -220,6 +220,9 @@ def SwiftError : EnumAttr<"swifterror">; /// Argument is swift self/context. def SwiftSelf : EnumAttr<"swiftself">; +/// Argument is swift async context. +def SwiftAsync : EnumAttr<"swiftasync">; + /// Function must be in a unwind table. def UWTable : EnumAttr<"uwtable">; diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td index 2160c150590e..fe395b2fa66e 100644 --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -444,7 +444,12 @@ def int_objc_arc_annotation_bottomup_bbstart : Intrinsic<[], def int_objc_arc_annotation_bottomup_bbend : Intrinsic<[], [llvm_ptrptr_ty, llvm_ptrptr_ty]>; +//===--------------- Swift asynchronous context intrinsics ----------------===// +// Returns the location of the Swift asynchronous context (usually stored just +// before the frame pointer), and triggers the creation of a null context if it +// would otherwise be unneeded. +def int_swift_async_context_addr : Intrinsic<[llvm_ptrptr_ty], [], [IntrNoMem]>; //===--------------------- Code Generator Intrinsics ----------------------===// // diff --git a/llvm/include/llvm/Target/TargetCallingConv.td b/llvm/include/llvm/Target/TargetCallingConv.td index 057f33083e08..58b5741a744c 100644 --- a/llvm/include/llvm/Target/TargetCallingConv.td +++ b/llvm/include/llvm/Target/TargetCallingConv.td @@ -51,6 +51,11 @@ class CCIfPreallocated<CCAction A> : CCIf<"ArgFlags.isPreallocated()", A> { class CCIfSwiftSelf<CCAction A> : CCIf<"ArgFlags.isSwiftSelf()", A> { } +/// CCIfSwiftAsync - If the current argument has swiftasync parameter attribute, +/// apply Action A. +class CCIfSwiftAsync<CCAction A> : CCIf<"ArgFlags.isSwiftAsync()", A> { +} + /// CCIfSwiftError - If the current argument has swifterror parameter attribute, /// apply Action A. class CCIfSwiftError<CCAction A> : CCIf<"ArgFlags.isSwiftError()", A> { diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp index 777ce3abdddd..b4ceb6d4b91f 100644 --- a/llvm/lib/AsmParser/LLLexer.cpp +++ b/llvm/lib/AsmParser/LLLexer.cpp @@ -692,6 +692,7 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(speculative_load_hardening); KEYWORD(swifterror); KEYWORD(swiftself); + KEYWORD(swiftasync); KEYWORD(uwtable); KEYWORD(willreturn); KEYWORD(writeonly); diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index 659aa9eb3f0d..7e4270e1af5c 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -1381,6 +1381,7 @@ bool LLParser::ParseFnAttributeValuePairs(AttrBuilder &B, case lltok::kw_sret: case lltok::kw_swifterror: case lltok::kw_swiftself: + case lltok::kw_swiftasync: case lltok::kw_immarg: HaveError |= Error(Lex.getLoc(), @@ -1692,6 +1693,7 @@ bool LLParser::ParseOptionalParamAttrs(AttrBuilder &B) { case lltok::kw_sret: B.addAttribute(Attribute::StructRet); break; case lltok::kw_swifterror: B.addAttribute(Attribute::SwiftError); break; case lltok::kw_swiftself: B.addAttribute(Attribute::SwiftSelf); break; + case lltok::kw_swiftasync: B.addAttribute(Attribute::SwiftAsync); break; case lltok::kw_writeonly: B.addAttribute(Attribute::WriteOnly); break; case lltok::kw_zeroext: B.addAttribute(Attribute::ZExt); break; case lltok::kw_immarg: B.addAttribute(Attribute::ImmArg); break; @@ -1794,6 +1796,7 @@ bool LLParser::ParseOptionalReturnAttrs(AttrBuilder &B) { case lltok::kw_sret: case lltok::kw_swifterror: case lltok::kw_swiftself: + case lltok::kw_swiftasync: case lltok::kw_immarg: HaveError |= Error(Lex.getLoc(), "invalid use of parameter-only attribute"); break; diff --git a/llvm/lib/AsmParser/LLToken.h b/llvm/lib/AsmParser/LLToken.h index 0fb3bae77dd3..318c934be16e 100644 --- a/llvm/lib/AsmParser/LLToken.h +++ b/llvm/lib/AsmParser/LLToken.h @@ -235,6 +235,7 @@ enum Kind { kw_strictfp, kw_swifterror, kw_swiftself, + kw_swiftasync, kw_uwtable, kw_willreturn, kw_writeonly, diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index 659e26c2bd25..9e07a0bb4f22 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -1516,6 +1516,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) { return Attribute::SwiftError; case bitc::ATTR_KIND_SWIFT_SELF: return Attribute::SwiftSelf; + case bitc::ATTR_KIND_SWIFT_ASYNC: + return Attribute::SwiftAsync; case bitc::ATTR_KIND_UW_TABLE: return Attribute::UWTable; case bitc::ATTR_KIND_WILLRETURN: diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index 4fe9bf482ae0..f9c496a619c0 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -717,6 +717,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) { return bitc::ATTR_KIND_SWIFT_ERROR; case Attribute::SwiftSelf: return bitc::ATTR_KIND_SWIFT_SELF; + case Attribute::SwiftAsync: + return bitc::ATTR_KIND_SWIFT_ASYNC; case Attribute::UWTable: return bitc::ATTR_KIND_UW_TABLE; case Attribute::WillReturn: diff --git a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp index 1be0ca441205..c4c08d2e8931 100644 --- a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp @@ -93,6 +93,8 @@ void CallLowering::setArgFlags(CallLowering::ArgInfo &Arg, unsigned OpIdx, Flags.setSRet(); if (Attrs.hasAttribute(OpIdx, Attribute::SwiftSelf)) Flags.setSwiftSelf(); + if (Attrs.hasAttribute(OpIdx, Attribute::SwiftAsync)) + Flags.setSwiftAsync(); if (Attrs.hasAttribute(OpIdx, Attribute::SwiftError)) Flags.setSwiftError(); if (Attrs.hasAttribute(OpIdx, Attribute::ByVal)) diff --git a/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/llvm/lib/CodeGen/PrologEpilogInserter.cpp index a489f493d5ee..89bcef2cce47 100644 --- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp +++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp @@ -401,7 +401,8 @@ static void assignCalleeSavedSpillSlots(MachineFunction &F, const TargetFrameLowering *TFI = F.getSubtarget().getFrameLowering(); MachineFrameInfo &MFI = F.getFrameInfo(); - if (!TFI->assignCalleeSavedSpillSlots(F, RegInfo, CSI)) { + if (!TFI->assignCalleeSavedSpillSlots(F, RegInfo, CSI, MinCSFrameIndex, + MaxCSFrameIndex)) { // If target doesn't implement this, use generic code. if (CSI.empty()) @@ -679,10 +680,12 @@ computeFreeStackSlots(MachineFrameInfo &MFI, bool StackGrowsDown, // StackSlot scavenging is only implemented for the default stack. if (MFI.getStackID(i) == TargetStackID::Default) AllocatedFrameSlots.push_back(i); - // Add callee-save objects. - for (int i = MinCSFrameIndex; i <= (int)MaxCSFrameIndex; ++i) - if (MFI.getStackID(i) == TargetStackID::Default) - AllocatedFrameSlots.push_back(i); + // Add callee-save objects if there are any. + if (MinCSFrameIndex <= MaxCSFrameIndex) { + for (int i = MinCSFrameIndex; i <= (int)MaxCSFrameIndex; ++i) + if (MFI.getStackID(i) == TargetStackID::Default) + AllocatedFrameSlots.push_back(i); + } for (int i : AllocatedFrameSlots) { // These are converted from int64_t, but they should always fit in int @@ -837,7 +840,7 @@ void PEI::calculateFrameObjectOffsets(MachineFunction &MF) { // First assign frame offsets to stack objects that are used to spill // callee saved registers. - if (StackGrowsDown) { + if (StackGrowsDown && MaxCSFrameIndex >= MinCSFrameIndex) { for (unsigned i = MinCSFrameIndex; i <= MaxCSFrameIndex; ++i) { if (MFI.getStackID(i) != TargetStackID::Default) // Only allocate objects on the default stack. diff --git a/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp b/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp index f5948d2a20dc..df5a49bea3d7 100644 --- a/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp @@ -1205,6 +1205,8 @@ bool FastISel::lowerCallTo(CallLoweringInfo &CLI) { Flags.setSRet(); if (Arg.IsSwiftSelf) Flags.setSwiftSelf(); + if (Arg.IsSwiftAsync) + Flags.setSwiftAsync(); if (Arg.IsSwiftError) Flags.setSwiftError(); if (Arg.IsCFGuardTarget) diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 69d295266694..2c525145810c 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -9171,6 +9171,7 @@ TargetLowering::LowerCallTo(TargetLowering::CallLoweringInfo &CLI) const { Entry.IsByVal = false; Entry.IsReturned = false; Entry.IsSwiftSelf = false; + Entry.IsSwiftAsync = false; Entry.IsSwiftError = false; Entry.IsCFGuardTarget = false; Entry.Alignment = Alignment; @@ -9283,6 +9284,8 @@ TargetLowering::LowerCallTo(TargetLowering::CallLoweringInfo &CLI) const { Flags.setSRet(); if (Args[i].IsSwiftSelf) Flags.setSwiftSelf(); + if (Args[i].IsSwiftAsync) + Flags.setSwiftAsync(); if (Args[i].IsSwiftError) Flags.setSwiftError(); if (Args[i].IsCFGuardTarget) @@ -9798,6 +9801,8 @@ void SelectionDAGISel::LowerArguments(const Function &F) { Flags.setSRet(); if (Arg.hasAttribute(Attribute::SwiftSelf)) Flags.setSwiftSelf(); + if (Arg.hasAttribute(Attribute::SwiftAsync)) + Flags.setSwiftAsync(); if (Arg.hasAttribute(Attribute::SwiftError)) Flags.setSwiftError(); if (Arg.hasAttribute(Attribute::ByVal)) diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp index f67d96a854f4..286fe849c5e2 100644 --- a/llvm/lib/IR/Attributes.cpp +++ b/llvm/lib/IR/Attributes.cpp @@ -341,6 +341,8 @@ std::string Attribute::getAsString(bool InAttrGrp) const { return "swifterror"; if (hasAttribute(Attribute::SwiftSelf)) return "swiftself"; + if (hasAttribute(Attribute::SwiftAsync)) + return "swiftasync"; if (hasAttribute(Attribute::InaccessibleMemOnly)) return "inaccessiblememonly"; if (hasAttribute(Attribute::InaccessibleMemOrArgMemOnly)) diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 21723227686f..dd899196cbda 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -1764,6 +1764,7 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs, bool SawReturned = false; bool SawSRet = false; bool SawSwiftSelf = false; + bool SawSwiftAsync = false; bool SawSwiftError = false; // Verify return value attributes. @@ -1777,10 +1778,11 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs, !RetAttrs.hasAttribute(Attribute::InAlloca) && !RetAttrs.hasAttribute(Attribute::Preallocated) && !RetAttrs.hasAttribute(Attribute::SwiftSelf) && + !RetAttrs.hasAttribute(Attribute::SwiftAsync) && !RetAttrs.hasAttribute(Attribute::SwiftError)), "Attributes 'byval', 'inalloca', 'preallocated', 'nest', 'sret', " "'nocapture', 'nofree', " - "'returned', 'swiftself', and 'swifterror' do not apply to return " + "'returned', 'swiftself', 'swiftasync', and 'swifterror' do not apply to return " "values!", V); Assert((!RetAttrs.hasAttribute(Attribute::ReadOnly) && @@ -1829,6 +1831,11 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs, SawSwiftSelf = true; } + if (ArgAttrs.hasAttribute(Attribute::SwiftAsync)) { + Assert(!SawSwiftAsync, "Cannot have multiple 'swiftasync' parameters!", V); + SawSwiftAsync = true; + } + if (ArgAttrs.hasAttribute(Attribute::SwiftError)) { Assert(!SawSwiftError, "Cannot have multiple 'swifterror' parameters!", V); @@ -3200,9 +3207,9 @@ static bool isTypeCongruent(Type *L, Type *R) { static AttrBuilder getParameterABIAttributes(int I, AttributeList Attrs) { static const Attribute::AttrKind ABIAttrs[] = { - Attribute::StructRet, Attribute::ByVal, Attribute::InAlloca, - Attribute::InReg, Attribute::SwiftSelf, Attribute::SwiftError, - Attribute::Preallocated}; + Attribute::StructRet, Attribute::ByVal, Attribute::InAlloca, + Attribute::InReg, Attribute::SwiftSelf, Attribute::SwiftAsync, + Attribute::SwiftError, Attribute::Preallocated}; AttrBuilder Copy; for (auto AK : ABIAttrs) { if (Attrs.hasParamAttribute(I, AK)) diff --git a/llvm/lib/Target/AArch64/AArch64CallingConvention.td b/llvm/lib/Target/AArch64/AArch64CallingConvention.td index fdcc890bf589..48c8a2c46968 100644 --- a/llvm/lib/Target/AArch64/AArch64CallingConvention.td +++ b/llvm/lib/Target/AArch64/AArch64CallingConvention.td @@ -69,6 +69,9 @@ def CC_AArch64_AAPCS : CallingConv<[ // A SwiftError is passed in X21. CCIfSwiftError<CCIfType<[i64], CCAssignToRegWithShadow<[X21], [W21]>>>, + // Pass SwiftAsync in a callee saved register. + CCIfSwiftAsync<CCIfType<[i64], CCAssignToRegWithShadow<[X22], [W22]>>>, + CCIfConsecutiveRegs<CCCustom<"CC_AArch64_Custom_Block">>, CCIfType<[nxv16i8, nxv8i16, nxv4i32, nxv2i64, nxv2f16, nxv4f16, nxv8f16, @@ -202,6 +205,9 @@ def CC_AArch64_DarwinPCS : CallingConv<[ // A SwiftError is passed in X21. CCIfSwiftError<CCIfType<[i64], CCAssignToRegWithShadow<[X21], [W21]>>>, + // Pass SwiftAsync in a callee saved register. + CCIfSwiftAsync<CCIfType<[i64], CCAssignToRegWithShadow<[X22], [W22]>>>, + CCIfConsecutiveRegs<CCCustom<"CC_AArch64_Custom_Block">>, // Handle i1, i8, i16, i32, i64, f32, f64 and v2f64 by passing in registers, diff --git a/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp b/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp index d2bd91652c35..c631ab90e778 100644 --- a/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp +++ b/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp @@ -83,6 +83,8 @@ private: bool expandSVESpillFill(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, unsigned Opc, unsigned N); + bool expandStoreSwiftAsyncContext(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI); }; } // end anonymous namespace @@ -627,6 +629,61 @@ bool AArch64ExpandPseudo::expandSVESpillFill(MachineBasicBlock &MBB, return true; } +bool AArch64ExpandPseudo::expandStoreSwiftAsyncContext( + MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI) { + Register CtxReg = MBBI->getOperand(0).getReg(); + Register BaseReg = MBBI->getOperand(1).getReg(); + int Offset = MBBI->getOperand(2).getImm(); + DebugLoc DL(MBBI->getDebugLoc()); + auto &STI = MBB.getParent()->getSubtarget<AArch64Subtarget>(); + + if (STI.getTargetTriple().getArchName() != "arm64e") { + BuildMI(MBB, MBBI, DL, TII->get(AArch64::STRXui)) + .addUse(CtxReg) + .addUse(BaseReg) + .addImm(Offset / 8) + .setMIFlag(MachineInstr::FrameSetup); + MBBI->eraseFromParent(); + return true; + } + + // add x16, xBase, #Offset + // movk x16, #0xc31a, lsl #48 + // mov x17, x22 + // pacdb x17, x16 + // str x17, [xBase, #Offset] + unsigned Opc = Offset >= 0 ? AArch64::ADDXri : AArch64::SUBXri; + BuildMI(MBB, MBBI, DL, TII->get(Opc), AArch64::X16) + .addUse(BaseReg) + .addImm(abs(Offset)) + .addImm(0) + .setMIFlag(MachineInstr::FrameSetup); + BuildMI(MBB, MBBI, DL, TII->get(AArch64::MOVKXi), AArch64::X16) + .addUse(AArch64::X16) + .addImm(0xc31a) + .addImm(48) + .setMIFlag(MachineInstr::FrameSetup); + // We're not allowed to clobber X22 (and couldn't clobber XZR if we tried), so + // move it somewhere before signing. + BuildMI(MBB, MBBI, DL, TII->get(AArch64::ORRXrs), AArch64::X17) + .addUse(AArch64::XZR) + .addUse(CtxReg) + .addImm(0) + .setMIFlag(MachineInstr::FrameSetup); + BuildMI(MBB, MBBI, DL, TII->get(AArch64::PACDB), AArch64::X17) + .addUse(AArch64::X17) + .addUse(AArch64::X16) + .setMIFlag(MachineInstr::FrameSetup); + BuildMI(MBB, MBBI, DL, TII->get(AArch64::STRXui)) + .addUse(AArch64::X17) + .addUse(BaseReg) + .addImm(Offset / 8) + .setMIFlag(MachineInstr::FrameSetup); + + MBBI->eraseFromParent(); + return true; +} + /// If MBBI references a pseudo instruction that should be expanded here, /// do the expansion and return true. Otherwise return false. bool AArch64ExpandPseudo::expandMI(MachineBasicBlock &MBB, @@ -1045,6 +1102,8 @@ bool AArch64ExpandPseudo::expandMI(MachineBasicBlock &MBB, return expandSVESpillFill(MBB, MBBI, AArch64::LDR_ZXI, 3); case AArch64::LDR_ZZXI: return expandSVESpillFill(MBB, MBBI, AArch64::LDR_ZXI, 2); + case AArch64::StoreSwiftAsyncContext: + return expandStoreSwiftAsyncContext(MBB, MBBI); } return false; } diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp index 9cd3f3db75d7..421e8a14e79e 100644 --- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp @@ -1114,6 +1114,18 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF, } } + // We signal the presence of a Swift extended frame to external tools by + // storing FP with 0b0001 in bits 63:60. In normal userland operation a simple + // ORR is sufficient, it is assumed a Swift kernel would initialize the TBI + // bits so that is still true. + if (HasFP && AFI->hasSwiftAsyncContext()) { + // ORR x29, x29, #0x1000_0000_0000_0000 + BuildMI(MBB, MBBI, DL, TII->get(AArch64::ORRXri), AArch64::FP) + .addUse(AArch64::FP) + .addImm(0x1100) + .setMIFlag(MachineInstr::FrameSetup); + } + // All calls are tail calls in GHC calling conv, and functions have no // prologue/epilogue. if (MF.getFunction().getCallingConv() == CallingConv::GHC) @@ -1133,6 +1145,7 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF, // function, including the funclet. int64_t NumBytes = IsFunclet ? getWinEHFuncletFrameSize(MF) : MFI.getStackSize(); + if (!AFI->hasStackFrame() && !windowsRequiresStackProbe(MF, NumBytes)) { assert(!HasFP && "unexpected function without stack frame but with FP"); assert(!SVEStackSize && @@ -1179,7 +1192,9 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF, // All of the remaining stack allocations are for locals. AFI->setLocalStackSize(NumBytes - PrologueSaveSize); bool CombineSPBump = shouldCombineCSRLocalStackBump(MF, NumBytes); - if (CombineSPBump) { + // If we're going to combine SP updates then the stack adjustment must be less + // // than 512 bytes, hence stack probing in the prologue is unnecssary. + if (CombineSPBump || (HasFP && AFI->hasSwiftAsyncContext())) { assert(!SVEStackSize && "Cannot combine SP bump with SVE"); emitFrameOffset(MBB, MBBI, DL, AArch64::SP, AArch64::SP, {-NumBytes, MVT::i8}, TII, MachineInstr::FrameSetup, false, @@ -1212,6 +1227,20 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF, if (CombineSPBump) FPOffset += AFI->getLocalStackSize(); + // Before we update the live FP we have to ensure there's a valid (or null) + // asynchronous context in its slot just before FP in the frame record, so + // store it now. + if (AFI->hasSwiftAsyncContext()) { + const auto &Attrs = MF.getFunction().getAttributes(); + bool HaveInitialContext = Attrs.hasAttrSomewhere(Attribute::SwiftAsync); + + BuildMI(MBB, MBBI, DL, TII->get(AArch64::StoreSwiftAsyncContext)) + .addUse(HaveInitialContext ? AArch64::X22 : AArch64::XZR) + .addUse(AArch64::SP) + .addImm(FPOffset - 8) + .setMIFlags(MachineInstr::FrameSetup); + } + // Issue sub fp, sp, FPOffset or // mov fp,sp when FPOffset is zero. // Note: All stores of callee-saved registers are marked as "FrameSetup". @@ -1719,6 +1748,17 @@ void AArch64FrameLowering::emitEpilogue(MachineFunction &MF, .setMIFlag(MachineInstr::FrameDestroy); } + // We need to reset FP to its untagged state on return. Bit 60 is currently + // used to show the presence of an extended frame. + if (hasFP(MF) && AFI->hasSwiftAsyncContext()) { + // BIC x29, x29, #0x1000_0000_0000_0000 + BuildMI(MBB, MBB.getFirstTerminator(), DL, TII->get(AArch64::ANDXri), + AArch64::FP) + .addUse(AArch64::FP) + .addImm(0x10fe) + .setMIFlag(MachineInstr::FrameDestroy); + } + const StackOffset &SVEStackSize = getSVEStackSize(MF); // If there is a single SP update, insert it before the ret and we're done. @@ -2256,6 +2296,11 @@ static void computeCalleeSaveRegisterPairs( else ByteOffset -= RPI.isPaired() ? 2 * Scale : Scale; + // Swift's async context is directly before FP, so allocate an extra + // 8 bytes for it. + if (NeedsFrameRecord && AFI->hasSwiftAsyncContext() && RPI.Reg2 == AArch64::FP) + ByteOffset -= 8; + assert(!(RPI.isScalable() && RPI.isPaired()) && "Paired spill/fill instructions don't exist for SVE vectors"); @@ -2273,6 +2318,12 @@ static void computeCalleeSaveRegisterPairs( int Offset = RPI.isScalable() ? ScalableByteOffset : ByteOffset; assert(Offset % Scale == 0); + + // The FP, LR pair goes 8 bytes into our expanded 24-byte slot so that the + // Swift context can directly precede FP. + if (NeedsFrameRecord && AFI->hasSwiftAsyncContext() && RPI.Reg2 == AArch64::FP) + Offset += 8; + RPI.Offset = Offset / Scale; assert(((!RPI.isScalable() && RPI.Offset >= -64 && RPI.Offset <= 63) || @@ -2697,6 +2748,12 @@ void AArch64FrameLowering::determineCalleeSaves(MachineFunction &MF, // Adding the size of additional 64bit GPR saves. CSStackSize += 8 * (SavedRegs.count() - NumSavedRegs); + + // A Swift asynchronous context extends the frame record with a pointer + // directly before FP. + if (hasFP(MF) && AFI->hasSwiftAsyncContext()) + CSStackSize += 8; + uint64_t AlignedCSStackSize = alignTo(CSStackSize, 16); LLVM_DEBUG(dbgs() << "Estimated stack frame size: " << EstimatedStackSize + AlignedCSStackSize @@ -2713,6 +2770,42 @@ void AArch64FrameLowering::determineCalleeSaves(MachineFunction &MF, AFI->setSVECalleeSavedStackSize(alignTo(SVECSStackSize, 16)); } +bool AArch64FrameLowering::assignCalleeSavedSpillSlots( + MachineFunction &MF, const TargetRegisterInfo *RegInfo, + std::vector<CalleeSavedInfo> &CSI, unsigned &MinCSFrameIndex, + unsigned &MaxCSFrameIndex) const { + if (CSI.empty()) + return true; // Early exit if no callee saved registers are modified! + + // Now that we know which registers need to be saved and restored, allocate + // stack slots for them. + MachineFrameInfo &MFI = MF.getFrameInfo(); + auto AFI = MF.getInfo<AArch64FunctionInfo>(); + for (auto &CS : CSI) { + unsigned Reg = CS.getReg(); + const TargetRegisterClass *RC = RegInfo->getMinimalPhysRegClass(Reg); + + int FrameIdx; + unsigned Size = RegInfo->getSpillSize(*RC); + + Align Alignment(RegInfo->getSpillAlignment(*RC)); + FrameIdx = MFI.CreateStackObject(Size, Alignment, true); + CS.setFrameIdx(FrameIdx); + + if ((unsigned)FrameIdx < MinCSFrameIndex) MinCSFrameIndex = FrameIdx; + if ((unsigned)FrameIdx > MaxCSFrameIndex) MaxCSFrameIndex = FrameIdx; + + // Grab 8 bytes below FP for the extended asynchronous frame info. + if (hasFP(MF) && AFI->hasSwiftAsyncContext() && Reg == AArch64::FP) { + FrameIdx = MFI.CreateStackObject(8, Alignment, true); + AFI->setSwiftAsyncContextFrameIdx(FrameIdx); + if ((unsigned)FrameIdx < MinCSFrameIndex) MinCSFrameIndex = FrameIdx; + if ((unsigned)FrameIdx > MaxCSFrameIndex) MaxCSFrameIndex = FrameIdx; + } + } + return true; +} + bool AArch64FrameLowering::enableStackSlotScavenging( const MachineFunction &MF) const { const AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>(); diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.h b/llvm/lib/Target/AArch64/AArch64FrameLowering.h index f156cca91f4a..3682634c7c55 100644 --- a/llvm/lib/Target/AArch64/AArch64FrameLowering.h +++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.h @@ -67,6 +67,14 @@ public: bool hasFP(const MachineFunction &MF) const override; bool hasReservedCallFrame(const MachineFunction &MF) const override; + bool hasSwiftExtendedFrame(const MachineFunction &MF) const; + + bool assignCalleeSavedSpillSlots(MachineFunction &MF, + const TargetRegisterInfo *TRI, + std::vector<CalleeSavedInfo> &CSI, + unsigned &MinCSFrameIndex, + unsigned &MaxCSFrameIndex) const override; + void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs, RegScavenger *RS) const override; diff --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp index 5006022dc635..cb29d0b5eaab 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp +++ b/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" @@ -4033,6 +4034,17 @@ void AArch64DAGToDAGISel::Select(SDNode *Node) { return; } + case Intrinsic::swift_async_context_addr: + SDLoc DL(Node); + CurDAG->SelectNodeTo(Node, AArch64::SUBXri, MVT::i64, + CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, + AArch64::FP, MVT::i64), + CurDAG->getTargetConstant(8, DL, MVT::i32), + CurDAG->getTargetConstant(0, DL, MVT::i32)); + auto &MF = CurDAG->getMachineFunction(); + MF.getFrameInfo().setFrameAddressIsTaken(true); + MF.getInfo<AArch64FunctionInfo>()->setHasSwiftAsyncContext(true); + return; } break; } diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index 3d5b9595393d..4ed157c309ca 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -3756,6 +3756,9 @@ SDValue AArch64TargetLowering::LowerFormalArguments( continue; } + if (Ins[i].Flags.isSwiftAsync()) + MF.getInfo<AArch64FunctionInfo>()->setHasSwiftAsyncContext(true); + SDValue ArgValue; if (VA.isRegLoc()) { // Arguments stored in registers. diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp index ca2731946c36..44e5b65cd035 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp @@ -2164,6 +2164,11 @@ bool AArch64InstrInfo::getMemOpInfo(unsigned Opcode, TypeSize &Scale, case AArch64::LDURDi: case AArch64::STURXi: case AArch64::STURDi: + case AArch64::StoreSwiftAsyncContext: +#ifdef __IOS_DISCLOSED__ + case AArch64::LDAPURXi: + case AArch64::STLURXi: +#endif Width = 8; Scale = TypeSize::Fixed(1); MinOffset = -256; diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index 5a619d38b0a8..9199514f307b 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -7780,6 +7780,11 @@ def : Pat<(int_ptrauth_blend GPR64:$Rd, GPR64:$Rn), (BFMXri GPR64:$Rd, GPR64:$Rn, 16, 15)>; } +let Defs = [X16, X17], mayStore = 1, isCodeGenOnly = 1 in +def StoreSwiftAsyncContext + : Pseudo<(outs), (ins GPR64:$ctx, GPR64sp:$base, simm9:$offset), + []>, Sched<[]>; + include "AArch64InstrAtomics.td" include "AArch64SVEInstrInfo.td" diff --git a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h index 84aa53f2bece..635ed97d6452 100644 --- a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h +++ b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h @@ -135,6 +135,15 @@ class AArch64FunctionInfo final : public MachineFunctionInfo { /// e.g. Tail Call, Thunk, or Function if none apply. Optional<std::string> OutliningStyle; + + /// Whether this function has an extended frame record [Ctx, FP, LR]. If so, + /// bit 60 of the in-memory FP will be 1 to enable other tools to detect the + /// extended record. + bool HasSwiftAsyncContext = false; + + /// The stack slot where the Swift asynchronous context is stored. + int SwiftAsyncContextFrameIdx = std::numeric_limits<int>::max(); + public: AArch64FunctionInfo() = default; @@ -223,6 +232,13 @@ public: MaxOffset = std::max<int64_t>(Offset + ObjSize, MaxOffset); } + if (SwiftAsyncContextFrameIdx != std::numeric_limits<int>::max()) { + int64_t Offset = MFI.getObjectOffset(getSwiftAsyncContextFrameIdx()); + int64_t ObjSize = MFI.getObjectSize(getSwiftAsyncContextFrameIdx()); + MinOffset = std::min<int64_t>(Offset, MinOffset); + MaxOffset = std::max<int64_t>(Offset + ObjSize, MaxOffset); + } + unsigned Size = alignTo(MaxOffset - MinOffset, 16); assert((!HasCalleeSavedStackSize || getCalleeSavedStackSize() == Size) && "Invalid size calculated for callee saves"); @@ -338,6 +354,17 @@ public: TaggedBasePointerOffset = Offset; } + + void setHasSwiftAsyncContext(bool HasContext) { + HasSwiftAsyncContext = HasContext; + } + bool hasSwiftAsyncContext() const { return HasSwiftAsyncContext; } + + void setSwiftAsyncContextFrameIdx(int FI) { + SwiftAsyncContextFrameIdx = FI; + } + int getSwiftAsyncContextFrameIdx() const { return SwiftAsyncContextFrameIdx; } + private: // Hold the lists of LOHs. MILOHContainer LOHContainerSet; diff --git a/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp b/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp index 4832ae8f415f..96b3dc4436e1 100644 --- a/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp +++ b/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp @@ -457,6 +457,9 @@ bool AArch64CallLowering::lowerFormalArguments( ArgInfo OrigArg{VRegs[i], Arg.getType()}; setArgFlags(OrigArg, i + AttributeList::FirstArgIndex, DL, F); + if (Arg.hasAttribute(Attribute::SwiftAsync)) + MF.getInfo<AArch64FunctionInfo>()->setHasSwiftAsyncContext(true); + splitToValueTypes(OrigArg, SplitArgs, DL, MRI, F.getCallingConv()); ++i; } diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp index 55c5cc8a966a..2a3b1dc7b96f 100644 --- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp +++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp @@ -4747,6 +4747,16 @@ bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &I, I.eraseFromParent(); return true; } + case Intrinsic::swift_async_context_addr: + MIRBuilder + .buildInstr(AArch64::SUBXri, {I.getOperand(0).getReg()}, + {Register(AArch64::FP)}) + .addImm(8) + .addImm(0); + MF->getFrameInfo().setFrameAddressIsTaken(true); + MF->getInfo<AArch64FunctionInfo>()->setHasSwiftAsyncContext(true); + I.eraseFromParent(); + return true; } return false; } diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp index 9f7dfdf62482..e54746b6cfc0 100644 --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp @@ -602,6 +602,7 @@ public: unsigned StackSize = 0; uint32_t CompactUnwindEncoding = 0; + int CurOffset = 0; for (size_t i = 0, e = Instrs.size(); i != e; ++i) { const MCCFIInstruction &Inst = Instrs[i]; @@ -631,6 +632,9 @@ public: assert(FPPush.getOperation() == MCCFIInstruction::OpOffset && "Frame pointer not pushed!"); + assert(FPPush.getOffset() + 8 == LRPush.getOffset()); + CurOffset = FPPush.getOffset(); + unsigned LRReg = *MRI.getLLVMRegNum(LRPush.getRegister(), true); unsigned FPReg = *MRI.getLLVMRegNum(FPPush.getRegister(), true); @@ -657,11 +661,19 @@ public: if (i + 1 == e) return CU::UNWIND_ARM64_MODE_DWARF; + if (CurOffset != 0 && Inst.getOffset() != CurOffset - 8) + return CU::UNWIND_ARM64_MODE_DWARF; + CurOffset = Inst.getOffset(); + const MCCFIInstruction &Inst2 = Instrs[++i]; if (Inst2.getOperation() != MCCFIInstruction::OpOffset) return CU::UNWIND_ARM64_MODE_DWARF; unsigned Reg2 = *MRI.getLLVMRegNum(Inst2.getRegister(), true); + if (Inst2.getOffset() != CurOffset - 8) + return CU::UNWIND_ARM64_MODE_DWARF; + CurOffset = Inst2.getOffset(); + // N.B. The encodings must be in register number order, and the X // registers before the D registers. diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp index 8cdbb9d35652..214e1cf8154d 100644 --- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp +++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp @@ -891,6 +891,7 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs, case Attribute::StructRet: case Attribute::SwiftError: case Attribute::SwiftSelf: + case Attribute::SwiftAsync: case Attribute::WillReturn: case Attribute::WriteOnly: case Attribute::ZExt: diff --git a/llvm/test/CodeGen/AArch64/swift-async.ll b/llvm/test/CodeGen/AArch64/swift-async.ll new file mode 100644 index 000000000000..018919d44fb7 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/swift-async.ll @@ -0,0 +1,141 @@ +; RUN: llc -mtriple=arm64-apple-ios %s -o - | FileCheck %s --check-prefixes=CHECK-NOAUTH,CHECK +; RUN: llc -mtriple=arm64-apple-ios -mcpu=apple-a13 %s -o - | FileCheck %s --check-prefixes=CHECK-NOAUTH,CHECK +; RUN: llc -mtriple=arm64e-apple-ios %s -o - | FileCheck %s --check-prefixes=CHECK-AUTH,CHECK + +; Important details in prologue: +; * x22 is stored just below x29 +; * Enough stack space is allocated for everything +define void @simple(i8* swiftasync %ctx) "frame-pointer"="all" { +; CHECK-LABEL: simple: +; CHECK: orr x29, x29, #0x100000000000000 +; CHECK: sub sp, sp, #32 +; CHECK: stp x29, x30, [sp, #16] + +; CHECK-NOAUTH: str x22, [sp, #8] +; CHECK-AUTH: add x16, sp, #8 +; CHECK-AUTH: movk x16, #49946, lsl #48 +; CHECK-AUTH: mov x17, x22 +; CHECK-AUTH: pacdb x17, x16 +; CHECK-AUTH: str x17, [sp, #8] + +; CHECK: add x29, sp, #16 +; CHECK: .cfi_def_cfa w29, 16 +; CHECK: .cfi_offset w30, -8 +; CHECK: .cfi_offset w29, -16 + +;[...] + +; CHECK: ldp x29, x30, [sp, #16] +; CHECK: and x29, x29, #0xefffffffffffffff +; CHECK: add sp, sp, #32 + + ret void +} + +define void @more_csrs(i8* swiftasync %ctx) "frame-pointer"="all" { +; CHECK-LABEL: more_csrs: +; CHECK: orr x29, x29, #0x100000000000000 +; CHECK: sub sp, sp, #48 +; CHECK: stp x24, x23, [sp, #8] +; CHECK: stp x29, x30, [sp, #32] + +; CHECK-NOAUTH: str x22, [sp, #24] +; CHECK-AUTH: add x16, sp, #24 +; CHECK-AUTH: movk x16, #49946, lsl #48 +; CHECK-AUTH: mov x17, x22 +; CHECK-AUTH: pacdb x17, x16 +; CHECK-AUTH: str x17, [sp, #24] + +; CHECK: add x29, sp, #32 +; CHECK: .cfi_def_cfa w29, 16 +; CHECK: .cfi_offset w30, -8 +; CHECK: .cfi_offset w29, -16 +; CHECK: .cfi_offset w23, -32 +; CHECK: .cfi_offset w24, -40 + +; [...] + +; CHECK: ldp x29, x30, [sp, #32] +; CHECK: ldp x24, x23, [sp, #8] +; CHECK: and x29, x29, #0xefffffffffffffff +; CHECK: add sp, sp, #48 + call void asm sideeffect "", "~{x23}"() + ret void +} + +define void @locals(i8* swiftasync %ctx) "frame-pointer"="all" { +; CHECK-LABEL: locals: +; CHECK: orr x29, x29, #0x100000000000000 +; CHECK: sub sp, sp, #64 +; CHECK: stp x29, x30, [sp, #48] + +; CHECK-NOAUTH: str x22, [sp, #40] +; CHECK-AUTH: add x16, sp, #40 +; CHECK-AUTH: movk x16, #49946, lsl #48 +; CHECK-AUTH: mov x17, x22 +; CHECK-AUTH: pacdb x17, x16 +; CHECK-AUTH: str x17, [sp, #40] + +; CHECK: add x29, sp, #48 +; CHECK: .cfi_def_cfa w29, 16 +; CHECK: .cfi_offset w30, -8 +; CHECK: .cfi_offset w29, -16 + +; CHECK: mov x0, sp +; CHECK: bl _bar + +; [...] + +; CHECK: ldp x29, x30, [sp, #48] +; CHECK: and x29, x29, #0xefffffffffffffff +; CHECK: add sp, sp, #64 + %var = alloca i32, i32 10 + call void @bar(i32* %var) + ret void +} + +define void @use_input_context(i8* swiftasync %ctx, i8** %ptr) "frame-pointer"="all" { +; CHECK-LABEL: use_input_context: + +; CHECK-NOAUTH: str x22, [sp +; CHECK-AUTH: mov x17, x22 + +; CHECK-NOT: x22 +; CHECK: str x22, [x0] + + store i8* %ctx, i8** %ptr + ret void +} + +define i8** @context_in_func() "frame-pointer"="non-leaf" { +; CHECK-LABEL: context_in_func: + +; CHECK-NOAUTH: str xzr, [sp, #8] +; CHECK-AUTH: add x16, sp, #8 +; CHECK-AUTH: movk x16, #49946, lsl #48 +; CHECK-AUTH: mov x17, xzr +; CHECK-AUTH: pacdb x17, x16 +; CHECK-AUTH: str x17, [sp, #8] + + %ptr = call i8** @llvm.swift.async.context.addr() + ret i8** %ptr +} + +define void @write_frame_context(i8* swiftasync %ctx, i8* %newctx) "frame-pointer"="non-leaf" { +; CHECK-LABEL: write_frame_context: +; CHECK: sub x[[ADDR:[0-9]+]], x29, #8 +; CHECK: str x0, [x[[ADDR]]] + %ptr = call i8** @llvm.swift.async.context.addr() + store i8* %newctx, i8** %ptr + ret void +} + +define void @simple_fp_elim(i8* swiftasync %ctx) "frame-pointer"="non-leaf" { +; CHECK-LABEL: simple_fp_elim: +; CHECK-NOT: orr x29, x29, #0x100000000000000 + + ret void +} + +declare void @bar(i32*) +declare i8** @llvm.swift.async.context.addr() |