@@ -409,7 +409,13 @@ int X86FrameLowering::mergeSPUpdates(MachineBasicBlock &MBB,
409409 return 0 ;
410410
411411 PI = MBB.erase (PI);
412- if (PI != MBB.end () && PI->isCFIInstruction ()) PI = MBB.erase (PI);
412+ if (PI != MBB.end () && PI->isCFIInstruction ()) {
413+ auto CIs = MBB.getParent ()->getFrameInstructions ();
414+ MCCFIInstruction CI = CIs[PI->getOperand (0 ).getCFIIndex ()];
415+ if (CI.getOperation () == MCCFIInstruction::OpDefCfaOffset ||
416+ CI.getOperation () == MCCFIInstruction::OpAdjustCfaOffset)
417+ PI = MBB.erase (PI);
418+ }
413419 if (!doMergeWithPrevious)
414420 MBBI = skipDebugInstructionsForward (PI, MBB.end ());
415421
@@ -1356,6 +1362,14 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
13561362 STI.getTargetLowering ()->hasStackProbeSymbol (MF);
13571363 unsigned StackProbeSize = STI.getTargetLowering ()->getStackProbeSize (MF);
13581364
1365+ if (HasFP && X86FI->hasSwiftAsyncContext ()) {
1366+ BuildMI (MBB, MBBI, DL, TII.get (X86::BTS64ri8),
1367+ MachineFramePtr)
1368+ .addUse (MachineFramePtr)
1369+ .addImm (60 )
1370+ .setMIFlag (MachineInstr::FrameSetup);
1371+ }
1372+
13591373 // Re-align the stack on 64-bit if the x86-interrupt calling convention is
13601374 // used and an error code was pushed, since the x86-64 ABI requires a 16-byte
13611375 // stack alignment.
@@ -1470,11 +1484,44 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
14701484
14711485 if (!IsWin64Prologue && !IsFunclet) {
14721486 // Update EBP with the new base value.
1473- BuildMI (MBB, MBBI, DL,
1474- TII.get (Uses64BitFramePtr ? X86::MOV64rr : X86::MOV32rr),
1475- FramePtr)
1476- .addReg (StackPtr)
1477- .setMIFlag (MachineInstr::FrameSetup);
1487+ if (!X86FI->hasSwiftAsyncContext ()) {
1488+ BuildMI (MBB, MBBI, DL,
1489+ TII.get (Uses64BitFramePtr ? X86::MOV64rr : X86::MOV32rr),
1490+ FramePtr)
1491+ .addReg (StackPtr)
1492+ .setMIFlag (MachineInstr::FrameSetup);
1493+ } else {
1494+ // Before we update the live frame pointer we have to ensure there's a
1495+ // valid (or null) asynchronous context in its slot just before FP in
1496+ // the frame record, so store it now.
1497+ const auto &Attrs = MF.getFunction ().getAttributes ();
1498+
1499+ if (Attrs.hasAttrSomewhere (Attribute::SwiftAsync)) {
1500+ // We have an initial context in r14, store it just before the frame
1501+ // pointer.
1502+ MBB.addLiveIn (X86::R14);
1503+ BuildMI (MBB, MBBI, DL, TII.get (X86::PUSH64r))
1504+ .addReg (X86::R14)
1505+ .setMIFlag (MachineInstr::FrameSetup);
1506+ } else {
1507+ // No initial context, store null so that there's no pointer that
1508+ // could be misused.
1509+ BuildMI (MBB, MBBI, DL, TII.get (X86::PUSH64i8))
1510+ .addImm (0 )
1511+ .setMIFlag (MachineInstr::FrameSetup);
1512+ }
1513+ BuildMI (MBB, MBBI, DL, TII.get (X86::LEA64r), FramePtr)
1514+ .addUse (X86::RSP)
1515+ .addImm (1 )
1516+ .addUse (X86::NoRegister)
1517+ .addImm (8 )
1518+ .addUse (X86::NoRegister)
1519+ .setMIFlag (MachineInstr::FrameSetup);
1520+ BuildMI (MBB, MBBI, DL, TII.get (X86::SUB64ri8), X86::RSP)
1521+ .addUse (X86::RSP)
1522+ .addImm (8 )
1523+ .setMIFlag (MachineInstr::FrameSetup);
1524+ }
14781525
14791526 if (NeedsDwarfCFI) {
14801527 // Mark effective beginning of when frame pointer becomes valid.
@@ -1979,10 +2026,26 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
19792026 // AfterPop is the position to insert .cfi_restore.
19802027 MachineBasicBlock::iterator AfterPop = MBBI;
19812028 if (HasFP) {
2029+ if (X86FI->hasSwiftAsyncContext ()) {
2030+ // Discard the context.
2031+ int Offset = 16 + mergeSPUpdates (MBB, MBBI, true );
2032+ emitSPUpdate (MBB, MBBI, DL, Offset, /* InEpilogue*/ true );
2033+ }
19822034 // Pop EBP.
19832035 BuildMI (MBB, MBBI, DL, TII.get (Is64Bit ? X86::POP64r : X86::POP32r),
19842036 MachineFramePtr)
19852037 .setMIFlag (MachineInstr::FrameDestroy);
2038+
2039+ // We need to reset FP to its untagged state on return. Bit 60 is currently
2040+ // used to show the presence of an extended frame.
2041+ if (X86FI->hasSwiftAsyncContext ()) {
2042+ BuildMI (MBB, MBBI, DL, TII.get (X86::BTR64ri8),
2043+ MachineFramePtr)
2044+ .addUse (MachineFramePtr)
2045+ .addImm (60 )
2046+ .setMIFlag (MachineInstr::FrameDestroy);
2047+ }
2048+
19862049 if (NeedsDwarfCFI) {
19872050 unsigned DwarfStackPtr =
19882051 TRI->getDwarfRegNum (Is64Bit ? X86::RSP : X86::ESP, true );
@@ -2007,7 +2070,9 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
20072070
20082071 if (Opc != X86::DBG_VALUE && !PI->isTerminator ()) {
20092072 if ((Opc != X86::POP32r || !PI->getFlag (MachineInstr::FrameDestroy)) &&
2010- (Opc != X86::POP64r || !PI->getFlag (MachineInstr::FrameDestroy)))
2073+ (Opc != X86::POP64r || !PI->getFlag (MachineInstr::FrameDestroy)) &&
2074+ (Opc != X86::BTR64ri8 || !PI->getFlag (MachineInstr::FrameDestroy)) &&
2075+ (Opc != X86::ADD64ri8 || !PI->getFlag (MachineInstr::FrameDestroy)))
20112076 break ;
20122077 FirstCSPop = PI;
20132078 }
@@ -2039,6 +2104,9 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
20392104 uint64_t LEAAmount =
20402105 IsWin64Prologue ? SEHStackAllocAmt - SEHFrameOffset : -CSSize;
20412106
2107+ if (X86FI->hasSwiftAsyncContext ())
2108+ LEAAmount -= 16 ;
2109+
20422110 // There are only two legal forms of epilogue:
20432111 // - add SEHAllocationSize, %rsp
20442112 // - lea SEHAllocationSize(%FramePtr), %rsp
@@ -2367,6 +2435,14 @@ bool X86FrameLowering::assignCalleeSavedSpillSlots(
23672435 SpillSlotOffset -= SlotSize;
23682436 MFI.CreateFixedSpillStackObject (SlotSize, SpillSlotOffset);
23692437
2438+ // The async context lives directly before the frame pointer, and we
2439+ // allocate a second slot to preserve stack alignment.
2440+ if (X86FI->hasSwiftAsyncContext ()) {
2441+ SpillSlotOffset -= SlotSize;
2442+ MFI.CreateFixedSpillStackObject (SlotSize, SpillSlotOffset);
2443+ SpillSlotOffset -= SlotSize;
2444+ }
2445+
23702446 // Since emitPrologue and emitEpilogue will handle spilling and restoring of
23712447 // the frame register, we can delete it from CSI list and not have to worry
23722448 // about avoiding it later.
@@ -3267,7 +3343,11 @@ eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
32673343bool X86FrameLowering::canUseAsPrologue (const MachineBasicBlock &MBB) const {
32683344 assert (MBB.getParent () && " Block is not attached to a function!" );
32693345 const MachineFunction &MF = *MBB.getParent ();
3270- return !TRI->hasStackRealignment (MF) || !MBB.isLiveIn (X86::EFLAGS);
3346+ if (!MBB.isLiveIn (X86::EFLAGS))
3347+ return true ;
3348+
3349+ const X86MachineFunctionInfo *X86FI = MF.getInfo <X86MachineFunctionInfo>();
3350+ return !TRI->hasStackRealignment (MF) && !X86FI->hasSwiftAsyncContext ();
32713351}
32723352
32733353bool X86FrameLowering::canUseAsEpilogue (const MachineBasicBlock &MBB) const {
@@ -3280,6 +3360,12 @@ bool X86FrameLowering::canUseAsEpilogue(const MachineBasicBlock &MBB) const {
32803360 if (STI.isTargetWin64 () && !MBB.succ_empty () && !MBB.isReturnBlock ())
32813361 return false ;
32823362
3363+ // Swift async context epilogue has a BTR instruction that clobbers parts of
3364+ // EFLAGS.
3365+ const MachineFunction &MF = *MBB.getParent ();
3366+ if (MF.getInfo <X86MachineFunctionInfo>()->hasSwiftAsyncContext ())
3367+ return !flagsNeedToBePreservedBeforeTheTerminators (MBB);
3368+
32833369 if (canUseLEAForSPInEpilogue (*MBB.getParent ()))
32843370 return true ;
32853371
0 commit comments