if (MFnI.shouldSignWithBKey()) {
BuildMI(MBB, MBBI, DL, TII->get(AArch64::EMITBKEY))
.setMIFlag(MachineInstr::FrameSetup);
+ // No SEH opcode for this one; it doesn't materialize into an
+ // instruction on Windows.
PACI = Subtarget.hasPAuth() ? AArch64::PACIB : AArch64::PACIBSP;
} else {
PACI = Subtarget.hasPAuth() ? AArch64::PACIA : AArch64::PACIASP;
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
.setMIFlags(MachineInstr::FrameSetup);
+ } else if (NeedsWinCFI) {
+ HasWinCFI = true;
+ BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_PACSignLR))
+ .setMIFlag(MachineInstr::FrameSetup);
}
}
if (EmitCFI && MFnI.isMTETagged()) {
}
}
-static void InsertReturnAddressAuth(MachineFunction &MF,
- MachineBasicBlock &MBB) {
+static void InsertReturnAddressAuth(MachineFunction &MF, MachineBasicBlock &MBB,
+ bool NeedsWinCFI, bool *HasWinCFI) {
const auto &MFI = *MF.getInfo<AArch64FunctionInfo>();
if (!MFI.shouldSignReturnAddress())
return;
// DW_CFA_AARCH64_negate_ra_state can't be emitted.
if (Subtarget.hasPAuth() &&
!MF.getFunction().hasFnAttribute(Attribute::ShadowCallStack) &&
- MBBI != MBB.end() && MBBI->getOpcode() == AArch64::RET_ReallyLR) {
+ MBBI != MBB.end() && MBBI->getOpcode() == AArch64::RET_ReallyLR &&
+ !NeedsWinCFI) {
BuildMI(MBB, MBBI, DL,
TII->get(MFI.shouldSignWithBKey() ? AArch64::RETAB : AArch64::RETAA))
.copyImplicitOps(*MBBI);
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
.setMIFlags(MachineInstr::FrameDestroy);
+ if (NeedsWinCFI) {
+ *HasWinCFI = true;
+ BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_PACSignLR))
+ .setMIFlag(MachineInstr::FrameDestroy);
+ }
}
}
}
auto FinishingTouches = make_scope_exit([&]() {
- InsertReturnAddressAuth(MF, MBB);
+ InsertReturnAddressAuth(MF, MBB, NeedsWinCFI, &HasWinCFI);
if (needsShadowCallStackPrologueEpilogue(MF))
emitShadowCallStackEpilogue(*TII, MF, MBB, MBB.getFirstTerminator(), DL);
if (EmitCFI)
emitCalleeSavedGPRRestores(MBB, MBB.getFirstTerminator());
+ if (HasWinCFI)
+ BuildMI(MBB, MBB.getFirstTerminator(), DL,
+ TII->get(AArch64::SEH_EpilogEnd))
+ .setMIFlag(MachineInstr::FrameDestroy);
});
int64_t NumBytes = IsFunclet ? getWinEHFuncletFrameSize(MF)
StackOffset::getFixed(NumBytes + (int64_t)AfterCSRPopSize),
TII, MachineInstr::FrameDestroy, false, NeedsWinCFI,
&HasWinCFI, EmitCFI, StackOffset::getFixed(NumBytes));
- if (HasWinCFI)
- BuildMI(MBB, MBB.getFirstTerminator(), DL,
- TII->get(AArch64::SEH_EpilogEnd))
- .setMIFlag(MachineInstr::FrameDestroy);
return;
}
// If we were able to combine the local stack pop with the argument pop,
// then we're done.
if (NoCalleeSaveRestore || AfterCSRPopSize == 0) {
- if (HasWinCFI) {
- BuildMI(MBB, MBB.getFirstTerminator(), DL,
- TII->get(AArch64::SEH_EpilogEnd))
- .setMIFlag(MachineInstr::FrameDestroy);
- }
return;
}
false, NeedsWinCFI, &HasWinCFI, EmitCFI,
StackOffset::getFixed(CombineAfterCSRBump ? PrologueSaveSize : 0));
}
- if (HasWinCFI)
- BuildMI(MBB, MBB.getFirstTerminator(), DL, TII->get(AArch64::SEH_EpilogEnd))
- .setMIFlag(MachineInstr::FrameDestroy);
}
/// getFrameIndexReference - Provide a base+offset reference to an FI slot for
--- /dev/null
+; RUN: llc < %s -mtriple=aarch64-windows | FileCheck %s
+
+define dso_local i32 @func(ptr %g, i32 %a) {
+entry:
+ tail call void %g() #2
+ ret i32 %a
+}
+
+define dso_local i32 @func2(ptr %g, i32 %a) "target-features"="+v8.3a" {
+entry:
+ tail call void %g() #2
+ ret i32 %a
+}
+
+!llvm.module.flags = !{!0}
+
+!0 = !{i32 8, !"sign-return-address", i32 1}
+
+; CHECK-LABEL: func:
+; CHECK-NEXT: .seh_proc func
+; CHECK-NEXT: // %bb.0:
+; CHECK-NEXT: hint #27
+; CHECK-NEXT: .seh_pac_sign_lr
+; CHECK-NEXT: str x19, [sp, #-16]!
+; CHECK-NEXT: .seh_save_reg_x x19, 16
+; CHECK-NEXT: str x30, [sp, #8]
+; CHECK-NEXT: .seh_save_reg x30, 8
+; CHECK-NEXT: .seh_endprologue
+
+; CHECK: .seh_startepilogue
+; CHECK-NEXT: ldr x30, [sp, #8]
+; CHECK-NEXT: .seh_save_reg x30, 8
+; CHECK-NEXT: ldr x19, [sp], #16
+; CHECK-NEXT: .seh_save_reg_x x19, 16
+; CHECK-NEXT: hint #31
+; CHECK-NEXT: .seh_pac_sign_lr
+; CHECK-NEXT: .seh_endepilogue
+; CHECK-NEXT: ret
+; CHECK-NEXT: .seh_endfunclet
+; CHECK-NEXT: .seh_endproc
+
+;; For func2, check that the potentially folded autibsp+ret -> retab
+;; is handled correctly - currently we inhibit producing retab here.
+
+; CHECK-LABEL: func2:
+; CHECK-NEXT: .seh_proc func2
+; CHECK-NEXT: // %bb.0:
+; CHECK-NEXT: pacib x30, sp
+; CHECK-NEXT: .seh_pac_sign_lr
+; CHECK-NEXT: str x19, [sp, #-16]!
+; CHECK-NEXT: .seh_save_reg_x x19, 16
+; CHECK-NEXT: str x30, [sp, #8]
+; CHECK-NEXT: .seh_save_reg x30, 8
+; CHECK-NEXT: .seh_endprologue
+
+; CHECK: .seh_startepilogue
+; CHECK-NEXT: ldr x30, [sp, #8]
+; CHECK-NEXT: .seh_save_reg x30, 8
+; CHECK-NEXT: ldr x19, [sp], #16
+; CHECK-NEXT: .seh_save_reg_x x19, 16
+; CHECK-NEXT: autibsp
+; CHECK-NEXT: .seh_pac_sign_lr
+; CHECK-NEXT: .seh_endepilogue
+; CHECK-NEXT: ret
+; CHECK-NEXT: .seh_endfunclet
+; CHECK-NEXT: .seh_endproc