summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Northover <t.p.northover@gmail.com>2020-12-14 12:44:07 +0000
committerTim Northover <t.p.northover@gmail.com>2020-12-18 18:58:22 +0000
commitbdc0a1d6fda17a527fad86d5af7e49b4c0a9ad60 (patch)
treefefe1948f365ee98f4333ee45d787878a8e938d3
parent58b71bb621fedc9b3dc390647053468cbca293a9 (diff)
downloadllvm-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).
-rw-r--r--llvm/docs/LangRef.rst29
-rw-r--r--llvm/include/llvm/Bitcode/LLVMBitCodes.h1
-rw-r--r--llvm/include/llvm/CodeGen/TargetCallingConv.h14
-rw-r--r--llvm/include/llvm/CodeGen/TargetFrameLowering.h8
-rw-r--r--llvm/include/llvm/CodeGen/TargetLowering.h3
-rw-r--r--llvm/include/llvm/IR/Attributes.td3
-rw-r--r--llvm/include/llvm/IR/Intrinsics.td5
-rw-r--r--llvm/include/llvm/Target/TargetCallingConv.td5
-rw-r--r--llvm/lib/AsmParser/LLLexer.cpp1
-rw-r--r--llvm/lib/AsmParser/LLParser.cpp3
-rw-r--r--llvm/lib/AsmParser/LLToken.h1
-rw-r--r--llvm/lib/Bitcode/Reader/BitcodeReader.cpp2
-rw-r--r--llvm/lib/Bitcode/Writer/BitcodeWriter.cpp2
-rw-r--r--llvm/lib/CodeGen/GlobalISel/CallLowering.cpp2
-rw-r--r--llvm/lib/CodeGen/PrologEpilogInserter.cpp15
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/FastISel.cpp2
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp5
-rw-r--r--llvm/lib/IR/Attributes.cpp2
-rw-r--r--llvm/lib/IR/Verifier.cpp15
-rw-r--r--llvm/lib/Target/AArch64/AArch64CallingConvention.td6
-rw-r--r--llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp59
-rw-r--r--llvm/lib/Target/AArch64/AArch64FrameLowering.cpp95
-rw-r--r--llvm/lib/Target/AArch64/AArch64FrameLowering.h8
-rw-r--r--llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp12
-rw-r--r--llvm/lib/Target/AArch64/AArch64ISelLowering.cpp3
-rw-r--r--llvm/lib/Target/AArch64/AArch64InstrInfo.cpp5
-rw-r--r--llvm/lib/Target/AArch64/AArch64InstrInfo.td5
-rw-r--r--llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h27
-rw-r--r--llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp3
-rw-r--r--llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp10
-rw-r--r--llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp12
-rw-r--r--llvm/lib/Transforms/Utils/CodeExtractor.cpp1
-rw-r--r--llvm/test/CodeGen/AArch64/swift-async.ll141
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()