diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index bdd77ac84913c..9ae76fc307a56 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -174,7 +174,13 @@ static bool mustUseNonLeafFramePointerForTarget(const llvm::Triple &Triple) { // even if new frame records are not created. static bool mustMaintainValidFrameChain(const llvm::opt::ArgList &Args, const llvm::Triple &Triple) { - if (Triple.isARM() || Triple.isThumb()) { + switch (Triple.getArch()) { + default: + return false; + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: // For 32-bit Arm, the -mframe-chain=aapcs and -mframe-chain=aapcs+leaf // options require the frame pointer register to be reserved (or point to a // new AAPCS-compilant frame record), even with -fno-omit-frame-pointer. @@ -183,8 +189,13 @@ static bool mustMaintainValidFrameChain(const llvm::opt::ArgList &Args, return V != "none"; } return false; + + case llvm::Triple::aarch64: + // Arm64 Windows requires that the frame chain is valid, as there is no + // way to indicate during a stack walk that a frame has used the frame + // pointer as a general purpose register. + return Triple.isOSWindows(); } - return false; } // True if a target-specific option causes -fno-omit-frame-pointer to also diff --git a/clang/test/Driver/frame-pointer-elim.c b/clang/test/Driver/frame-pointer-elim.c index f64ff6efc7261..0dd7eb0c738db 100644 --- a/clang/test/Driver/frame-pointer-elim.c +++ b/clang/test/Driver/frame-pointer-elim.c @@ -4,6 +4,8 @@ // KEEP-NON-LEAF: "-mframe-pointer=non-leaf" // KEEP-NONE-NOT: warning: argument unused // KEEP-NONE: "-mframe-pointer=none" +// KEEP-RESERVED-NOT: warning: argument unused +// KEEP-RESERVED: "-mframe-pointer=reserved" // On Linux x86, omit frame pointer when optimization is enabled. // RUN: %clang -### --target=i386-linux -S -fomit-frame-pointer %s 2>&1 | \ @@ -215,5 +217,9 @@ // RUN: %clang -### --target=aarch64-none-elf -S -O1 -fno-omit-frame-pointer %s 2>&1 | \ // RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// AArch64 Windows requires that the frame pointer be reserved +// RUN: %clang -### --target=aarch64-pc-windows-msvc -S -fomit-frame-pointer %s 2>&1 | \ +// RUN: FileCheck --check-prefix=KEEP-RESERVED %s + void f0() {} void f1() { f0(); } diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp index 6f1ce5bdbe286..3ef7e5265c724 100644 --- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp @@ -518,6 +518,27 @@ bool AArch64FrameLowering::hasFPImpl(const MachineFunction &MF) const { return false; } +/// Should the Frame Pointer be reserved for the current function? +bool AArch64FrameLowering::isFPReserved(const MachineFunction &MF) const { + const TargetMachine &TM = MF.getTarget(); + const Triple &TT = TM.getTargetTriple(); + + // These OSes require the frame chain is valid, even if the current frame does + // not use a frame pointer. + if (TT.isOSDarwin() || TT.isOSWindows()) + return true; + + // If the function has a frame pointer, it is reserved. + if (hasFP(MF)) + return true; + + // Frontend has requested to preserve the frame pointer. + if (TM.Options.FramePointerIsReserved(MF)) + return true; + + return false; +} + /// hasReservedCallFrame - Under normal circumstances, when a frame pointer is /// not required, we reserve argument space for call sites in the function /// immediately on entry to the current function. This eliminates the need for diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.h b/llvm/lib/Target/AArch64/AArch64FrameLowering.h index e7d52bb350f13..ced69c9cd3699 100644 --- a/llvm/lib/Target/AArch64/AArch64FrameLowering.h +++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.h @@ -126,6 +126,8 @@ class AArch64FrameLowering : public TargetFrameLowering { orderFrameObjects(const MachineFunction &MF, SmallVectorImpl &ObjectsToAllocate) const override; + bool isFPReserved(const MachineFunction &MF) const; + protected: bool hasFPImpl(const MachineFunction &MF) const override; diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp b/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp index fb472ddc719fc..dd23bf51a98c4 100644 --- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp +++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp @@ -441,7 +441,7 @@ AArch64RegisterInfo::getStrictlyReservedRegs(const MachineFunction &MF) const { markSuperRegs(Reserved, AArch64::WSP); markSuperRegs(Reserved, AArch64::WZR); - if (TFI->hasFP(MF) || TT.isOSDarwin()) + if (TFI->isFPReserved(MF)) markSuperRegs(Reserved, AArch64::W29); if (MF.getSubtarget().isWindowsArm64EC()) { diff --git a/llvm/test/CodeGen/AArch64/regress-w29-reserved-with-fp.ll b/llvm/test/CodeGen/AArch64/regress-w29-reserved-with-fp.ll index 01943f40d41e8..347f777187af7 100644 --- a/llvm/test/CodeGen/AArch64/regress-w29-reserved-with-fp.ll +++ b/llvm/test/CodeGen/AArch64/regress-w29-reserved-with-fp.ll @@ -1,11 +1,26 @@ -; RUN: llc -mtriple=aarch64-none-linux-gnu -frame-pointer=all < %s | FileCheck %s +; RUN: llc -mtriple=aarch64-none-linux-gnu -frame-pointer=none < %s | \ +; RUN: FileCheck %s --check-prefixes=CHECK,NONE +; RUN: llc -mtriple=aarch64-none-linux-gnu -frame-pointer=reserved < %s | \ +; RUN: FileCheck %s --check-prefixes=CHECK,RESERVED +; RUN: llc -mtriple=aarch64-none-linux-gnu -frame-pointer=all < %s | \ +; RUN: FileCheck %s --check-prefixes=CHECK,ALL + +; By default, Darwin and Windows will reserve x29 +; RUN: llc -mtriple=aarch64-darwin -frame-pointer=none < %s | \ +; RUN: FileCheck %s --check-prefixes=CHECK,RESERVED +; RUN: llc -mtriple=aarch64-darwin -frame-pointer=none < %s | \ +; RUN: FileCheck %s --check-prefixes=CHECK,RESERVED @var = global i32 0 declare void @bar() define void @test_w29_reserved() { ; CHECK-LABEL: test_w29_reserved: -; CHECK: mov x29, sp +; ALL: add x29, sp +; NONE-NOT: add x29 +; NONE-NOT: mov x29 +; RESERVED-NOT: add x29 +; RESERVED-NOT: mov x29 %val1 = load volatile i32, ptr @var %val2 = load volatile i32, ptr @var @@ -16,8 +31,11 @@ define void @test_w29_reserved() { %val7 = load volatile i32, ptr @var %val8 = load volatile i32, ptr @var %val9 = load volatile i32, ptr @var + %val10 = load volatile i32, ptr @var -; CHECK-NOT: ldr w29, +; NONE: ldr w29, +; ALL-NOT: ldr w29, +; RESERVED-NOT: ldr w29, ; Call to prevent fp-elim that occurs regardless in leaf functions. call void @bar() @@ -31,6 +49,7 @@ define void @test_w29_reserved() { store volatile i32 %val7, ptr @var store volatile i32 %val8, ptr @var store volatile i32 %val9, ptr @var + store volatile i32 %val10, ptr @var ret void ; CHECK: ret diff --git a/llvm/test/CodeGen/AArch64/win-sve.ll b/llvm/test/CodeGen/AArch64/win-sve.ll index 691230af3e67d..53ac9344175a3 100644 --- a/llvm/test/CodeGen/AArch64/win-sve.ll +++ b/llvm/test/CodeGen/AArch64/win-sve.ll @@ -65,14 +65,18 @@ define i32 @f( %x) { ; CHECK-NEXT: .seh_save_zreg z22, 16 ; CHECK-NEXT: str z23, [sp, #17, mul vl] // 16-byte Folded Spill ; CHECK-NEXT: .seh_save_zreg z23, 17 -; CHECK-NEXT: stp x29, x30, [sp, #-16]! // 16-byte Folded Spill -; CHECK-NEXT: .seh_save_fplr_x 16 +; CHECK-NEXT: str x28, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .seh_save_reg_x x28, 16 +; CHECK-NEXT: str x30, [sp, #8] // 8-byte Folded Spill +; CHECK-NEXT: .seh_save_reg x30, 8 ; CHECK-NEXT: .seh_endprologue ; CHECK-NEXT: bl g ; CHECK-NEXT: mov w0, #3 // =0x3 ; CHECK-NEXT: .seh_startepilogue -; CHECK-NEXT: ldp x29, x30, [sp] // 16-byte Folded Reload -; CHECK-NEXT: .seh_save_fplr 0 +; CHECK-NEXT: ldr x30, [sp, #8] // 8-byte Folded Reload +; CHECK-NEXT: .seh_save_reg x30, 8 +; CHECK-NEXT: ldr x28, [sp] // 8-byte Folded Reload +; CHECK-NEXT: .seh_save_reg x28, 0 ; CHECK-NEXT: add sp, sp, #16 ; CHECK-NEXT: .seh_stackalloc 16 ; CHECK-NEXT: ldr z8, [sp, #2, mul vl] // 16-byte Folded Reload @@ -365,8 +369,10 @@ define void @f3(i64 %n, %x) { ; CHECK-NEXT: .seh_save_zreg z22, 16 ; CHECK-NEXT: str z23, [sp, #17, mul vl] // 16-byte Folded Spill ; CHECK-NEXT: .seh_save_zreg z23, 17 -; CHECK-NEXT: stp x29, x30, [sp, #-16]! // 16-byte Folded Spill -; CHECK-NEXT: .seh_save_fplr_x 16 +; CHECK-NEXT: str x28, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .seh_save_reg_x x28, 16 +; CHECK-NEXT: str x30, [sp, #8] // 8-byte Folded Spill +; CHECK-NEXT: .seh_save_reg x30, 8 ; CHECK-NEXT: sub sp, sp, #16 ; CHECK-NEXT: .seh_stackalloc 16 ; CHECK-NEXT: .seh_endprologue @@ -376,8 +382,10 @@ define void @f3(i64 %n, %x) { ; CHECK-NEXT: .seh_startepilogue ; CHECK-NEXT: add sp, sp, #16 ; CHECK-NEXT: .seh_stackalloc 16 -; CHECK-NEXT: ldp x29, x30, [sp] // 16-byte Folded Reload -; CHECK-NEXT: .seh_save_fplr 0 +; CHECK-NEXT: ldr x30, [sp, #8] // 8-byte Folded Reload +; CHECK-NEXT: .seh_save_reg x30, 8 +; CHECK-NEXT: ldr x28, [sp] // 8-byte Folded Reload +; CHECK-NEXT: .seh_save_reg x28, 0 ; CHECK-NEXT: add sp, sp, #16 ; CHECK-NEXT: .seh_stackalloc 16 ; CHECK-NEXT: ldr z8, [sp, #2, mul vl] // 16-byte Folded Reload @@ -511,8 +519,10 @@ define void @f4(i64 %n, %x) { ; CHECK-NEXT: .seh_save_zreg z22, 16 ; CHECK-NEXT: str z23, [sp, #17, mul vl] // 16-byte Folded Spill ; CHECK-NEXT: .seh_save_zreg z23, 17 -; CHECK-NEXT: stp x29, x30, [sp, #-16]! // 16-byte Folded Spill -; CHECK-NEXT: .seh_save_fplr_x 16 +; CHECK-NEXT: str x28, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .seh_save_reg_x x28, 16 +; CHECK-NEXT: str x30, [sp, #8] // 8-byte Folded Spill +; CHECK-NEXT: .seh_save_reg x30, 8 ; CHECK-NEXT: sub sp, sp, #16 ; CHECK-NEXT: .seh_stackalloc 16 ; CHECK-NEXT: addvl sp, sp, #-1 @@ -526,8 +536,10 @@ define void @f4(i64 %n, %x) { ; CHECK-NEXT: .seh_allocz 1 ; CHECK-NEXT: add sp, sp, #16 ; CHECK-NEXT: .seh_stackalloc 16 -; CHECK-NEXT: ldp x29, x30, [sp] // 16-byte Folded Reload -; CHECK-NEXT: .seh_save_fplr 0 +; CHECK-NEXT: ldr x30, [sp, #8] // 8-byte Folded Reload +; CHECK-NEXT: .seh_save_reg x30, 8 +; CHECK-NEXT: ldr x28, [sp] // 8-byte Folded Reload +; CHECK-NEXT: .seh_save_reg x28, 0 ; CHECK-NEXT: add sp, sp, #16 ; CHECK-NEXT: .seh_stackalloc 16 ; CHECK-NEXT: ldr z8, [sp, #2, mul vl] // 16-byte Folded Reload @@ -1093,8 +1105,10 @@ define void @f7(i64 %n) { ; CHECK-LABEL: f7: ; CHECK: .seh_proc f7 ; CHECK-NEXT: // %bb.0: -; CHECK-NEXT: stp x29, x30, [sp, #-16]! // 16-byte Folded Spill -; CHECK-NEXT: .seh_save_fplr_x 16 +; CHECK-NEXT: str x28, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .seh_save_reg_x x28, 16 +; CHECK-NEXT: str x30, [sp, #8] // 8-byte Folded Spill +; CHECK-NEXT: .seh_save_reg x30, 8 ; CHECK-NEXT: addvl sp, sp, #-1 ; CHECK-NEXT: .seh_allocz 1 ; CHECK-NEXT: .seh_endprologue @@ -1103,8 +1117,10 @@ define void @f7(i64 %n) { ; CHECK-NEXT: .seh_startepilogue ; CHECK-NEXT: addvl sp, sp, #1 ; CHECK-NEXT: .seh_allocz 1 -; CHECK-NEXT: ldp x29, x30, [sp], #16 // 16-byte Folded Reload -; CHECK-NEXT: .seh_save_fplr_x 16 +; CHECK-NEXT: ldr x30, [sp, #8] // 8-byte Folded Reload +; CHECK-NEXT: .seh_save_reg x30, 8 +; CHECK-NEXT: ldr x28, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: .seh_save_reg_x x28, 16 ; CHECK-NEXT: .seh_endepilogue ; CHECK-NEXT: ret ; CHECK-NEXT: .seh_endfunclet diff --git a/llvm/test/CodeGen/AArch64/wincfi-missing-seh-directives.ll b/llvm/test/CodeGen/AArch64/wincfi-missing-seh-directives.ll index 2002c37cb2528..6d14abdc2ed75 100644 --- a/llvm/test/CodeGen/AArch64/wincfi-missing-seh-directives.ll +++ b/llvm/test/CodeGen/AArch64/wincfi-missing-seh-directives.ll @@ -5,25 +5,23 @@ ; prologue has a corresponding seh directive. ; ; CHECK-NOT: error: Incorrect size for -; CHECK: foo: -; CHECK: .seh_proc foo -; CHECK: sub sp, sp, #288 -; CHECK: .seh_stackalloc 288 -; CHECK: str x19, [sp] // 8-byte Folded Spill -; CHECK: .seh_save_reg x19, 0 -; CHECK: str x21, [sp, #8] // 8-byte Folded Spill -; CHECK: .seh_save_reg x21, 8 -; CHECK: stp x23, x24, [sp, #16] // 16-byte Folded Spill -; CHECK: .seh_save_regp x23, 16 -; CHECK: stp x25, x26, [sp, #32] // 16-byte Folded Spill -; CHECK: .seh_save_regp x25, 32 -; CHECK: stp x27, x28, [sp, #48] // 16-byte Folded Spill -; CHECK: .seh_save_regp x27, 48 -; CHECK: stp x29, x30, [sp, #64] // 16-byte Folded Spill -; CHECK: .seh_save_fplr 64 -; CHECK: sub sp, sp, #224 -; CHECK: .seh_stackalloc 224 -; CHECK: .seh_endprologue +; CHECK-LABEL: foo: +; CHECK-NEXT: .seh_proc foo +; CHECK: sub sp, sp, #496 +; CHECK-NEXT: .seh_stackalloc 496 +; CHECK-NEXT: str x19, [sp, #208] // 8-byte Folded Spill +; CHECK-NEXT: .seh_save_reg x19, 208 +; CHECK-NEXT: str x21, [sp, #216] // 8-byte Folded Spill +; CHECK-NEXT: .seh_save_reg x21, 216 +; CHECK-NEXT: stp x23, x24, [sp, #224] // 16-byte Folded Spill +; CHECK-NEXT: .seh_save_regp x23, 224 +; CHECK-NEXT: stp x25, x26, [sp, #240] // 16-byte Folded Spill +; CHECK-NEXT: .seh_save_regp x25, 240 +; CHECK-NEXT: stp x27, x28, [sp, #256] // 16-byte Folded Spill +; CHECK-NEXT: .seh_save_regp x27, 256 +; CHECK-NEXT: str x30, [sp, #272] // 8-byte Folded Spill +; CHECK-NEXT: .seh_save_reg x30, 272 +; CHECK-NEXT: .seh_endprologue target datalayout = "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32" target triple = "aarch64-unknown-windows-msvc19.42.34436" diff --git a/llvm/test/CodeGen/AArch64/wineh-frame5.mir b/llvm/test/CodeGen/AArch64/wineh-frame5.mir index 180c20f0148f5..0589d97ca64a2 100644 --- a/llvm/test/CodeGen/AArch64/wineh-frame5.mir +++ b/llvm/test/CodeGen/AArch64/wineh-frame5.mir @@ -5,8 +5,10 @@ # CHECK-LABEL: bb.0.entry: # CHECK: early-clobber $sp = frame-setup STRXpre killed $x19, $sp, -32 # CHECK-NEXT: frame-setup SEH_SaveReg_X 19, -32 -# CHECK-NEXT: frame-setup STPXi killed $fp, killed $lr, $sp, 1 -# CHECK-NEXT: frame-setup SEH_SaveFPLR 8 +# CHECK-NEXT: frame-setup STRXui killed $x28, $sp, 1 +# CHECK-NEXT: frame-setup SEH_SaveReg 28, 8 +# CHECK-NEXT: frame-setup STRXui killed $lr, $sp, 2 +# CHECK-NEXT: frame-setup SEH_SaveReg 30, 16 # CHECK-NEXT: $sp = frame-setup SUBXri $sp, 496, 0 # CHECK-NEXT: frame-setup SEH_StackAlloc 496 # CHECK-NEXT: frame-setup SEH_PrologEnd @@ -15,8 +17,10 @@ # CHECK: frame-destroy SEH_EpilogStart # CHECK-NEXT: $sp = frame-destroy ADDXri $sp, 496, 0 # CHECK-NEXT: frame-destroy SEH_StackAlloc 496 -# CHECK-NEXT: $fp, $lr = frame-destroy LDPXi $sp, 1 -# CHECK-NEXT: frame-destroy SEH_SaveFPLR 8 +# CHECK-NEXT: $lr = frame-destroy LDRXui $sp, 2 +# CHECK-NEXT: frame-destroy SEH_SaveReg 30, 16 +# CHECK-NEXT: $x28 = frame-destroy LDRXui $sp, 1 +# CHECK-NEXT: frame-destroy SEH_SaveReg 28, 8 # CHECK-NEXT: early-clobber $sp, $x19 = frame-destroy LDRXpost $sp, 32 # CHECK-NEXT: frame-destroy SEH_SaveReg_X 19, -32 # CHECK-NEXT: frame-destroy SEH_EpilogEnd diff --git a/llvm/test/CodeGen/AArch64/wineh-frame7.mir b/llvm/test/CodeGen/AArch64/wineh-frame7.mir index 6d44ad3716111..b30afd2b57153 100644 --- a/llvm/test/CodeGen/AArch64/wineh-frame7.mir +++ b/llvm/test/CodeGen/AArch64/wineh-frame7.mir @@ -3,13 +3,15 @@ # Test that stack probe results in Nop unwind codes in the prologue. Test # save_fplr, save_reg_x and stack_alloc with multiple updates. -# CHECK: early-clobber $sp = frame-setup STPXpre killed $fp, killed $lr, $sp, -2 -# CHECK-NEXT: frame-setup SEH_SaveFPLR_X -16 +# CHECK: early-clobber $sp = frame-setup STRXpre killed $x28, $sp, -32 +# CHECK-NEXT: frame-setup SEH_SaveReg_X 28, -32 +# CHECK-NEXT: frame-setup STPXi killed $fp, killed $lr, $sp, 1 +# CHECK-NEXT: frame-setup SEH_SaveFPLR 8 # CHECK-NEXT: $x15 = frame-setup MOVZXi 56009, 0 # CHECK-NEXT: frame-setup SEH_Nop # CHECK-NEXT: $x15 = frame-setup MOVKXi $x15, 2, 16 # CHECK-NEXT: frame-setup SEH_Nop -# CHECK-NEXT: frame-setup BL &__chkstk, implicit-def $lr, implicit $sp, implicit $x15 +# CHECK-NEXT: frame-setup BL &__chkstk, implicit-def $lr, implicit $sp, implicit $x15, implicit-def dead $x16, implicit-def dead $x17, implicit-def dead $nzcv # CHECK-NEXT: frame-setup SEH_Nop # CHECK-NEXT: $sp = frame-setup SUBXrx64 killed $sp, killed $x15, 28 # CHECK-NEXT: frame-setup SEH_StackAlloc 2993296 @@ -19,8 +21,10 @@ # CHECK-NEXT: frame-destroy SEH_StackAlloc 2990080 # CHECK-NEXT: $sp = frame-destroy ADDXri $sp, 3216, 0 # CHECK-NEXT: frame-destroy SEH_StackAlloc 3216 -# CHECK-NEXT: early-clobber $sp, $fp, $lr = frame-destroy LDPXpost $sp, 2 -# CHECK-NEXT: frame-destroy SEH_SaveFPLR_X -16 +# CHECK-NEXT: $fp, $lr = frame-destroy LDPXi $sp, 1 +# CHECK-NEXT: frame-destroy SEH_SaveFPLR 8 +# CHECK-NEXT: early-clobber $sp, $x28 = frame-destroy LDRXpost $sp, 32 +# CHECK-NEXT: frame-destroy SEH_SaveReg_X 28, -32 # CHECK-NEXT: frame-destroy SEH_EpilogEnd # CHECK-NEXT: RET_ReallyLR implicit killed $w0 --- |