Commit 1cc8fff4 authored by Sanne Wouda's avatar Sanne Wouda
Browse files

[AArch64] Fix save register pairing for Windows AAPCS

Summary:
On Windows, when a function does not have an unwind table (for example, EH
filtering funclets), we don't correctly pair FP and LR to form the frame record
in all circumstances.

Fix this by invalidating a pair when the second register is FP when compiling
for Windows, even when CFI is not needed.

Fixes PR44271 introduced by D65653.

Reviewers: efriedma, sdesmalen, rovka, rengolin, t.p.northover, thegameg, greened

Reviewed By: rengolin

Subscribers: kristof.beyls, hiraditya, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D71754
parent 192cce10
Loading
Loading
Loading
Loading
+16 −4
Original line number Diff line number Diff line
@@ -836,6 +836,10 @@ static bool isTargetDarwin(const MachineFunction &MF) {
  return MF.getSubtarget<AArch64Subtarget>().isTargetDarwin();
}

static bool isTargetWindows(const MachineFunction &MF) {
  return MF.getSubtarget<AArch64Subtarget>().isTargetWindows();
}

// Convenience function to determine whether I is an SVE callee save.
static bool IsSVECalleeSave(MachineBasicBlock::iterator I) {
  switch (I->getOpcode()) {
@@ -1870,6 +1874,8 @@ static bool invalidateWindowsRegisterPairing(unsigned Reg1, unsigned Reg2,

  // TODO: LR can be paired with any register.  We don't support this yet in
  // the MCLayer.  We need to add support for the save_lrpair unwind code.
  if (Reg2 == AArch64::FP)
    return true;
  if (!NeedsWinCFI)
    return false;
  if (Reg2 == Reg1 + 1)
@@ -1882,9 +1888,9 @@ static bool invalidateWindowsRegisterPairing(unsigned Reg1, unsigned Reg2,
/// LR and FP need to be allocated together when the frame needs to save
/// the frame-record. This means any other register pairing with LR is invalid.
static bool invalidateRegisterPairing(unsigned Reg1, unsigned Reg2,
                                      bool NeedsWinCFI, bool NeedsFrameRecord) {
  if (NeedsWinCFI)
    return invalidateWindowsRegisterPairing(Reg1, Reg2, true);
                                      bool UsesWinAAPCS, bool NeedsWinCFI, bool NeedsFrameRecord) {
  if (UsesWinAAPCS)
    return invalidateWindowsRegisterPairing(Reg1, Reg2, NeedsWinCFI);

  // If we need to store the frame record, don't pair any register
  // with LR other than FP.
@@ -1934,6 +1940,7 @@ static void computeCalleeSaveRegisterPairs(
  if (CSI.empty())
    return;

  bool IsWindows = isTargetWindows(MF);
  bool NeedsWinCFI = needsWinCFI(MF);
  AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
  MachineFrameInfo &MFI = MF.getFrameInfo();
@@ -1976,7 +1983,7 @@ static void computeCalleeSaveRegisterPairs(
      switch (RPI.Type) {
      case RegPairInfo::GPR:
        if (AArch64::GPR64RegClass.contains(NextReg) &&
            !invalidateRegisterPairing(RPI.Reg1, NextReg, NeedsWinCFI,
            !invalidateRegisterPairing(RPI.Reg1, NextReg, IsWindows, NeedsWinCFI,
                                       NeedsFrameRecord))
          RPI.Reg2 = NextReg;
        break;
@@ -2018,6 +2025,11 @@ static void computeCalleeSaveRegisterPairs(
            RPI.Reg1 == AArch64::LR) &&
           "FrameRecord must be allocated together with LR");

    // Windows AAPCS has FP and LR reversed.
    assert((!RPI.isPaired() || !NeedsFrameRecord || RPI.Reg1 != AArch64::FP ||
            RPI.Reg2 == AArch64::LR) &&
           "FrameRecord must be allocated together with LR");

    // MachO's compact unwind format relies on all registers being stored in
    // adjacent register pairs.
    assert((!produceCompactUnwindFrame(MF) ||
+35 −0
Original line number Diff line number Diff line
; RUN: llc -mtriple=arm64-windows -o - %s | FileCheck %s

declare void @f()
declare void @g()

; Function Attrs: nounwind
define dso_local void @SEHfilter() nounwind "frame-pointer"="all" {
; CHECK-LABEL: @SEHfilter
; CHECK:       %bb.0:
; CHECK-NEXT:  stp     x30, x29, [sp, #-32]!
; CHECK-NEXT:  str     x19, [sp, #16]
; CHECK-NEXT:  ldr     w19, [x8]
; CHECK-NEXT:  mov     x29, sp
; CHECK-NEXT:  bl      g
; CHECK-NEXT:  cbz     w19, .LBB0_2
; CHECK-NEXT:  ; %bb.1:
; CHECK-NEXT:  ldr     x19, [sp, #16]
; CHECK-NEXT:  ldp     x30, x29, [sp], #32
; CHECK-NEXT:  ret
; CHECK-NEXT:  .LBB0_2:                                ; %if.end.i
; CHECK-NEXT:  bl      f
; CHECK-NEXT:  brk     #0x1
  %1 = load i32, i32* undef, align 4
  tail call void @g()
  %tobool.i = icmp eq i32 %1, 0
  br i1 %tobool.i, label %if.end.i, label %exit

if.end.i:
  call void @f()
  unreachable

exit:
  ret void
}