diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.h b/llvm/lib/Target/AArch64/AArch64FrameLowering.h --- a/llvm/lib/Target/AArch64/AArch64FrameLowering.h +++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.h @@ -67,6 +67,11 @@ bool hasFP(const MachineFunction &MF) const override; bool hasReservedCallFrame(const MachineFunction &MF) const override; + bool + assignCalleeSavedSpillSlots(MachineFunction &MF, + const TargetRegisterInfo *TRI, + std::vector &CSI) const override; + void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs, RegScavenger *RS) const override; diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp --- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp @@ -2077,14 +2077,22 @@ (Count & 1) == 0) && "Odd number of callee-saved regs to spill!"); int ByteOffset = AFI->getCalleeSavedStackSize(); + int StackFillDir = -1; + int RegInc = 1; + unsigned FirstReg = 0; + if (NeedsWinCFI) { + // For WinCFI, fill the stack from the bottom up. + ByteOffset = 0; + StackFillDir = 1; + // As the CSI array is reversed to match PrologEpilogInserter, iterate + // backwards, to pair up registers starting from lower numbered registers. + RegInc = -1; + FirstReg = Count - 1; + } int ScalableByteOffset = AFI->getSVECalleeSavedStackSize(); - // On Linux, we will have either one or zero non-paired register. On Windows - // with CFI, we can have multiple unpaired registers in order to utilize the - // available unwind codes. This flag assures that the alignment fixup is done - // only once, as intened. - bool FixupDone = false; - for (unsigned i = 0; i < Count; ++i) { + // When iterating backwards, the loop condition relies on unsigned wraparound. + for (unsigned i = FirstReg; i < Count; i += RegInc) { RegPairInfo RPI; RPI.Reg1 = CSI[i].getReg(); @@ -2102,8 +2110,8 @@ llvm_unreachable("Unsupported register class."); // Add the next reg to the pair if it is in the same register class. - if (i + 1 < Count) { - unsigned NextReg = CSI[i + 1].getReg(); + if (unsigned(i + RegInc) < Count) { + unsigned NextReg = CSI[i + RegInc].getReg(); switch (RPI.Type) { case RegPairInfo::GPR: if (AArch64::GPR64RegClass.contains(NextReg) && @@ -2142,7 +2150,7 @@ // The order of the registers in the list is controlled by // getCalleeSavedRegs(), so they will always be in-order, as well. assert((!RPI.isPaired() || - (CSI[i].getFrameIdx() + 1 == CSI[i + 1].getFrameIdx())) && + (CSI[i].getFrameIdx() + RegInc == CSI[i + RegInc].getFrameIdx())) && "Out of order callee saved regs!"); assert((!RPI.isPaired() || !NeedsFrameRecord || RPI.Reg2 != AArch64::FP || @@ -2164,30 +2172,43 @@ "Callee-save registers not saved as adjacent register pair!"); RPI.FrameIdx = CSI[i].getFrameIdx(); + if (NeedsWinCFI && + RPI.isPaired()) // RPI.FrameIdx must be the lower index of the pair + RPI.FrameIdx = CSI[i + RegInc].getFrameIdx(); int Scale = RPI.getScale(); + + int OffsetPre = RPI.isScalable() ? ScalableByteOffset : ByteOffset; + assert(OffsetPre % Scale == 0); + if (RPI.isScalable()) - ScalableByteOffset -= Scale; + ScalableByteOffset += StackFillDir * Scale; else - ByteOffset -= RPI.isPaired() ? 2 * Scale : Scale; + ByteOffset += StackFillDir * (RPI.isPaired() ? 2 * Scale : Scale); assert(!(RPI.isScalable() && RPI.isPaired()) && "Paired spill/fill instructions don't exist for SVE vectors"); // Round up size of non-pair to pair size if we need to pad the // callee-save area to ensure 16-byte alignment. - if (AFI->hasCalleeSaveStackFreeSpace() && !FixupDone && + if (AFI->hasCalleeSaveStackFreeSpace() && !NeedsWinCFI && !RPI.isScalable() && RPI.Type != RegPairInfo::FPR128 && !RPI.isPaired()) { - FixupDone = true; - ByteOffset -= 8; + ByteOffset += 8 * StackFillDir; assert(ByteOffset % 16 == 0); assert(MFI.getObjectAlign(RPI.FrameIdx) <= Align(16)); + // A stack frame with a gap looks like this, bottom up: + // d9, d8. x21, gap, x20, x19. + // Set extra alignment on the x21 object (the only unpaired register) + // to create the gap above it. MFI.setObjectAlignment(RPI.FrameIdx, Align(16)); } - int Offset = RPI.isScalable() ? ScalableByteOffset : ByteOffset; - assert(Offset % Scale == 0); + int OffsetPost = RPI.isScalable() ? ScalableByteOffset : ByteOffset; + assert(OffsetPost % Scale == 0); + // If filling top down (default), we want the offset after incrementing it. + // If fillibg bootom up (WinCFI) we need the original offset. + int Offset = NeedsWinCFI ? OffsetPre : OffsetPost; RPI.Offset = Offset / Scale; assert(((!RPI.isScalable() && RPI.Offset >= -64 && RPI.Offset <= 63) || @@ -2204,7 +2225,19 @@ RegPairs.push_back(RPI); if (RPI.isPaired()) - ++i; + i += RegInc; + } + if (NeedsWinCFI) { + // If we need an alignment gap in the stack, align the topmost stack + // object. A stack frame with a gap looks like this, bottom up: + // x19, d8. d9, gap. + // Set extra alignment on the topmost stack object (the first element in + // CSI, which goes top down), to create the gap above it. + if (AFI->hasCalleeSaveStackFreeSpace()) + MFI.setObjectAlignment(CSI[0].getFrameIdx(), Align(16)); + // We iterated bottom up over the registers; flip RegPairs back to top + // down order. + std::reverse(RegPairs.begin(), RegPairs.end()); } } @@ -2636,6 +2669,21 @@ AFI->setSVECalleeSavedStackSize(alignTo(SVECSStackSize, 16)); } +bool AArch64FrameLowering::assignCalleeSavedSpillSlots( + MachineFunction &MF, const TargetRegisterInfo *TRI, + std::vector &CSI) const { + bool NeedsWinCFI = needsWinCFI(MF); + // To match the canonical windows frame layout, reverse the list of + // callee saved registers to get them laid out by PrologEpilogInserter + // in the right order. (PrologEpilogInserter allocates stack objects top + // down. Windows canonical prologs store higher numbered registers at + // the top, thus have the CSI array start from the highest registers.) + if (NeedsWinCFI) + std::reverse(CSI.begin(), CSI.end()); + // Let the generic code do the rest of the setup. + return false; +} + bool AArch64FrameLowering::enableStackSlotScavenging( const MachineFunction &MF) const { const AArch64FunctionInfo *AFI = MF.getInfo(); diff --git a/llvm/test/CodeGen/AArch64/seh-finally.ll b/llvm/test/CodeGen/AArch64/seh-finally.ll --- a/llvm/test/CodeGen/AArch64/seh-finally.ll +++ b/llvm/test/CodeGen/AArch64/seh-finally.ll @@ -86,12 +86,12 @@ define void @stack_realign() #0 personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) { entry: ; CHECK-LABEL: stack_realign -; CHECK: mov x29, sp +; CHECK: add x29, sp, #8 ; CHECK: sub x9, sp, #16 ; CHECK: and sp, x9, #0xffffffffffffffe0 ; CHECK: mov x19, sp ; CHECK: mov x0, #-2 -; CHECK: stur x0, [x29, #32] +; CHECK: stur x0, [x29, #24] ; CHECK: .set .Lstack_realign$frame_escape_0, 0 ; CHECK: ldr w0, [x19] ; CHECK: bl foo @@ -205,17 +205,17 @@ define void @vla_and_realign(i32 %n) #0 personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) { entry: ; CHECK-LABEL: vla_and_realign -; CHECK: mov x29, sp +; CHECK: add x29, sp, #8 ; CHECK: sub x9, sp, #48 ; CHECK: and sp, x9, #0xffffffffffffffe0 ; CHECK: mov x19, sp ; CHECK: mov x1, #-2 -; CHECK: stur x1, [x29, #32] +; CHECK: stur x1, [x29, #24] ; CHECK: .set .Lvla_and_realign$frame_escape_0, 32 -; CHECK: str w0, [x29, #44] -; CHECK: ldr w8, [x29, #44] +; CHECK: str w0, [x29, #36] +; CHECK: ldr w8, [x29, #36] ; CHECK: mov x9, sp -; CHECK: str x9, [x29, #24] +; CHECK: str x9, [x29, #16] ; CHECK: str x8, [x19, #24] ; CHECK: ldr w0, [x19, #32] ; CHECK: bl foo diff --git a/llvm/test/CodeGen/AArch64/sponentry.ll b/llvm/test/CodeGen/AArch64/sponentry.ll --- a/llvm/test/CodeGen/AArch64/sponentry.ll +++ b/llvm/test/CodeGen/AArch64/sponentry.ll @@ -38,8 +38,8 @@ ; CHECK: foo: ; CHECK: sub sp, sp, #448 -; CHECK: add x29, sp, #416 -; CHECK: add x1, x29, #32 +; CHECK: add x29, sp, #424 +; CHECK: add x1, x29, #24 ; CHECK: bl _setjmpex ; NOFP: sub sp, sp, #432 diff --git a/llvm/test/CodeGen/AArch64/win64_vararg.ll b/llvm/test/CodeGen/AArch64/win64_vararg.ll --- a/llvm/test/CodeGen/AArch64/win64_vararg.ll +++ b/llvm/test/CodeGen/AArch64/win64_vararg.ll @@ -103,21 +103,21 @@ declare i64* @__local_stdio_printf_options() local_unnamed_addr #4 ; CHECK-LABEL: fp -; CHECK: stp x29, x30, [sp, #-96] +; CHECK: stp x19, x20, [sp, #-96] ; CHECK: str x21, [sp, #16] -; CHECK: stp x19, x20, [sp, #32] -; CHECK: mov x29, sp -; CHECK: add x8, x29, #56 +; CHECK: stp x29, x30, [sp, #24] +; CHECK: add x29, sp, #24 +; CHECK: add x8, x29, #32 ; CHECK: mov x19, x2 ; CHECK: mov x20, x1 ; CHECK: mov x21, x0 -; CHECK: stp x3, x4, [x29, #56] -; CHECK: stp x5, x6, [x29, #72] -; CHECK: str x7, [x29, #88] -; CHECK: str x8, [x29, #24] +; CHECK: stp x3, x4, [x29, #32] +; CHECK: stp x5, x6, [x29, #48] +; CHECK: str x7, [x29, #64] +; CHECK: str x8, [x29, #16] ; CHECK: bl __local_stdio_printf_options ; CHECK: ldr x8, [x0] -; CHECK: add x5, x29, #56 +; CHECK: add x5, x29, #32 ; CHECK: mov x1, x21 ; CHECK: mov x2, x20 ; CHECK: orr x0, x8, #0x2 @@ -126,9 +126,9 @@ ; CHECK: bl __stdio_common_vsprintf ; CHECK: cmp w0, #0 ; CHECK: csinv w0, w0, wzr, ge -; CHECK: ldp x19, x20, [sp, #32] +; CHECK: ldp x29, x30, [sp, #24] ; CHECK: ldr x21, [sp, #16] -; CHECK: ldp x29, x30, [sp], #96 +; CHECK: ldp x19, x20, [sp], #96 ; CHECK: ret define i32 @fp(i8*, i64, i8*, ...) local_unnamed_addr #6 { %4 = alloca i8*, align 8 @@ -150,26 +150,26 @@ attributes #6 = { "frame-pointer"="all" } ; CHECK-LABEL: vla -; CHECK: stp x29, x30, [sp, #-112]! -; CHECK: str x23, [sp, #16] -; CHECK: stp x21, x22, [sp, #32] -; CHECK: stp x19, x20, [sp, #48] -; CHECK: mov x29, sp -; CHECK: add x8, x29, #64 -; CHECK: str x8, [x29, #24] +; CHECK: stp x19, x20, [sp, #-112]! +; CHECK: stp x21, x22, [sp, #16] +; CHECK: str x23, [sp, #32] +; CHECK: stp x29, x30, [sp, #40] +; CHECK: add x29, sp, #40 +; CHECK: add x8, x29, #24 +; CHECK: str x8, [x29, #16] ; CHECK: mov w8, w0 ; CHECK: add x8, x8, #15 ; CHECK: lsr x15, x8, #4 ; CHECK: mov x19, x1 ; CHECK: mov [[REG2:x[0-9]+]], sp -; CHECK: stp x2, x3, [x29, #64] -; CHECK: stp x4, x5, [x29, #80] -; CHECK: stp x6, x7, [x29, #96] +; CHECK: stp x2, x3, [x29, #24] +; CHECK: stp x4, x5, [x29, #40] +; CHECK: stp x6, x7, [x29, #56] ; CHECK: bl __chkstk ; CHECK: mov x8, sp ; CHECK: sub [[REG:x[0-9]+]], x8, x15, lsl #4 ; CHECK: mov sp, [[REG]] -; CHECK: ldr [[REG3:x[0-9]+]], [x29, #24] +; CHECK: ldr [[REG3:x[0-9]+]], [x29, #16] ; CHECK: sxtw [[REG4:x[0-9]+]], w0 ; CHECK: bl __local_stdio_printf_options ; CHECK: ldr x8, [x0] @@ -181,11 +181,11 @@ ; CHECK: mov x5, [[REG3]] ; CHECK: bl __stdio_common_vsprintf ; CHECK: mov sp, [[REG2]] -; CHECK: mov sp, x29 -; CHECK: ldp x19, x20, [sp, #48] -; CHECK: ldp x21, x22, [sp, #32] -; CHECK: ldr x23, [sp, #16] -; CHECK: ldp x29, x30, [sp], #112 +; CHECK: sub sp, x29, #40 +; CHECK: ldp x29, x30, [sp, #40] +; CHECK: ldr x23, [sp, #32] +; CHECK: ldp x21, x22, [sp, #16] +; CHECK: ldp x19, x20, [sp], #112 ; CHECK: ret define void @vla(i32, i8*, ...) local_unnamed_addr { %3 = alloca i8*, align 8 @@ -212,9 +212,9 @@ ; CHECK-LABEL: snprintf ; CHECK-DAG: sub sp, sp, #96 -; CHECK-DAG: str x30, [sp, #16] -; CHECK-DAG: str x21, [sp, #24] -; CHECK-DAG: stp x19, x20, [sp, #32] +; CHECK-DAG: stp x19, x20, [sp, #16] +; CHECK-DAG: str x21, [sp, #32] +; CHECK-DAG: str x30, [sp, #40] ; CHECK-DAG: add x8, sp, #56 ; CHECK-DAG: mov x19, x2 ; CHECK-DAG: mov x20, x1 @@ -232,9 +232,9 @@ ; CHECK-DAG: mov x3, x19 ; CHECK-DAG: mov x4, xzr ; CHECK-DAG: bl __stdio_common_vsprintf -; CHECK-DAG: ldr x30, [sp, #16] -; CHECK-DAG: ldr x21, [sp, #24] -; CHECK-DAG: ldp x19, x20, [sp, #32] +; CHECK-DAG: ldr x30, [sp, #40] +; CHECK-DAG: ldr x21, [sp, #32] +; CHECK-DAG: ldp x19, x20, [sp, #16] ; CHECK-DAG: cmp w0, #0 ; CHECK-DAG: csinv w0, w0, wzr, ge ; CHECK-DAG: add sp, sp, #96 diff --git a/llvm/test/CodeGen/AArch64/wineh-frame-scavenge.mir b/llvm/test/CodeGen/AArch64/wineh-frame-scavenge.mir new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/wineh-frame-scavenge.mir @@ -0,0 +1,89 @@ +# RUN: llc -o - %s -mtriple=aarch64-windows -start-before=prologepilog \ +# RUN: -stop-after=prologepilog | FileCheck %s +# Check where the stack variable is placed + +# CHECK: - { id: 0, name: '', type: default, offset: -4, size: 4, alignment: 4, +# CHECK-NEXT: stack-id: default, callee-saved-register: '', callee-saved-restored: true, +# CHECK-NEXT: local-offset: -4, debug-info-variable: '', debug-info-expression: '', +# CHECK-NEXT: debug-info-location: '' } +# CHECK-NEXT: - { id: 1, name: '', type: spill-slot, offset: -16, size: 8, alignment: 16, +# CHECK-NEXT: stack-id: default, callee-saved-register: '$x23', callee-saved-restored: true, +# CHECK-NEXT: debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } +# CHECK-NEXT: - { id: 2, name: '', type: spill-slot, offset: -24, size: 8, alignment: 8, +# CHECK-NEXT: stack-id: default, callee-saved-register: '$x22', callee-saved-restored: true, +# CHECK-NEXT: debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } +# CHECK-NEXT: - { id: 3, name: '', type: spill-slot, offset: -32, size: 8, alignment: 8, +# CHECK-NEXT: stack-id: default, callee-saved-register: '$x21', callee-saved-restored: true, +# CHECK-NEXT: debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } +# CHECK-NEXT: - { id: 4, name: '', type: spill-slot, offset: -40, size: 8, alignment: 8, +# CHECK-NEXT: stack-id: default, callee-saved-register: '$x20', callee-saved-restored: true, +# CHECK-NEXT: debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } +# CHECK-NEXT: - { id: 5, name: '', type: spill-slot, offset: -48, size: 8, alignment: 8, +# CHECK-NEXT: stack-id: default, callee-saved-register: '$x19', callee-saved-restored: true, +# CHECK-NEXT: debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } + +# CHECK: early-clobber $sp = frame-setup STPXpre killed $x19, killed $x20, $sp, -6 :: (store 8 into %stack.4), (store 8 into %stack.5) +# CHECK-NEXT: frame-setup SEH_SaveRegP_X 19, 20, -48 +# CHECK-NEXT: frame-setup STPXi killed $x21, killed $x22, $sp, 2 :: (store 8 into %stack.2), (store 8 into %stack.3) +# CHECK-NEXT: frame-setup SEH_SaveRegP 21, 22, 16 +# CHECK-NEXT: frame-setup STRXui killed $x23, $sp, 4 :: (store 8 into %stack.1) +# CHECK-NEXT: frame-setup SEH_SaveReg 23, 32 +# CHECK-NEXT: frame-setup SEH_PrologEnd + + +... +--- +name: func +alignment: 4 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +failedISel: false +tracksRegLiveness: true +hasWinCFI: false +registers: [] +liveins: [] +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 0 + offsetAdjustment: 0 + maxAlignment: 4 + adjustsStack: false + hasCalls: false + stackProtector: '' + maxCallFrameSize: 0 + cvBytesOfCalleeSavedRegisters: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false + localFrameSize: 4 + savePoint: '' + restorePoint: '' +fixedStack: [] +stack: + - { id: 0, name: '', type: default, offset: 0, size: 4, alignment: 4, + stack-id: default, callee-saved-register: '', callee-saved-restored: true, + local-offset: -4, debug-info-variable: '', debug-info-expression: '', + debug-info-location: '' } +callSites: [] +constants: [] +machineFunctionInfo: {} +body: | + bb.0.entry: + liveins: $x0, $x23, $x21, $x22, $x19, $x20 + + renamable $x8 = ADDXri %stack.0, 0, 0 + $x19 = ADDXrr $x0, $x8 + $x20 = ADDXrr $x19, $x0 + $x21 = ADDXrr $x20, killed $x19 + $x22 = ADDXrr $x21, killed $x20 + $x23 = ADDXrr $x22, killed $x21 + $x0 = ADDXrr $x0, killed $x23 + + RET_ReallyLR + +... diff --git a/llvm/test/CodeGen/AArch64/wineh-frame0.mir b/llvm/test/CodeGen/AArch64/wineh-frame0.mir --- a/llvm/test/CodeGen/AArch64/wineh-frame0.mir +++ b/llvm/test/CodeGen/AArch64/wineh-frame0.mir @@ -2,28 +2,28 @@ # RUN: -stop-after=prologepilog | FileCheck %s # Check save_regp_x, save_regp -# CHECK: early-clobber $sp = frame-setup STPXpre killed $x27, killed $x28, $sp, -10 -# CHECK-NEXT: frame-setup SEH_SaveRegP_X 27, 28, -80 -# CHECK-NEXT: frame-setup STPXi killed $x25, killed $x26, $sp, 2 -# CHECK-NEXT: frame-setup SEH_SaveRegP 25, 26, 16 +# CHECK: early-clobber $sp = frame-setup STPXpre killed $x19, killed $x20, $sp, -10 +# CHECK-NEXT: frame-setup SEH_SaveRegP_X 19, 20, -80 +# CHECK-NEXT: frame-setup STPXi killed $x21, killed $x22, $sp, 2 +# CHECK-NEXT: frame-setup SEH_SaveRegP 21, 22, 16 # CHECK-NEXT: frame-setup STPXi killed $x23, killed $x24, $sp, 4 # CHECK-NEXT: frame-setup SEH_SaveRegP 23, 24, 32 -# CHECK-NEXT: frame-setup STPXi killed $x21, killed $x22, $sp, 6 -# CHECK-NEXT: frame-setup SEH_SaveRegP 21, 22, 48 -# CHECK-NEXT: frame-setup STPXi killed $x19, killed $x20, $sp, 8 -# CHECK-NEXT: frame-setup SEH_SaveRegP 19, 20, 64 +# CHECK-NEXT: frame-setup STPXi killed $x25, killed $x26, $sp, 6 +# CHECK-NEXT: frame-setup SEH_SaveRegP 25, 26, 48 +# CHECK-NEXT: frame-setup STPXi killed $x27, killed $x28, $sp, 8 +# CHECK-NEXT: frame-setup SEH_SaveRegP 27, 28, 64 # CHECK-NEXT: frame-setup SEH_PrologEnd # CHECK: frame-destroy SEH_EpilogStart -# CHECK-NEXT: $x19, $x20 = frame-destroy LDPXi $sp, 8 -# CHECK-NEXT: frame-destroy SEH_SaveRegP 19, 20, 64 -# CHECK-NEXT: $x21, $x22 = frame-destroy LDPXi $sp, 6 -# CHECK-NEXT: frame-destroy SEH_SaveRegP 21, 22, 48 +# CHECK-NEXT: $x27, $x28 = frame-destroy LDPXi $sp, 8 +# CHECK-NEXT: frame-destroy SEH_SaveRegP 27, 28, 64 +# CHECK-NEXT: $x25, $x26 = frame-destroy LDPXi $sp, 6 +# CHECK-NEXT: frame-destroy SEH_SaveRegP 25, 26, 48 # CHECK-NEXT: $x23, $x24 = frame-destroy LDPXi $sp, 4 # CHECK-NEXT: frame-destroy SEH_SaveRegP 23, 24, 32 -# CHECK-NEXT: $x25, $x26 = frame-destroy LDPXi $sp, 2 -# CHECK-NEXT: frame-destroy SEH_SaveRegP 25, 26, 16 -# CHECK-NEXT: early-clobber $sp, $x27, $x28 = frame-destroy LDPXpost $sp, 10 -# CHECK-NEXT: frame-destroy SEH_SaveRegP_X 27, 28, -80 +# CHECK-NEXT: $x21, $x22 = frame-destroy LDPXi $sp, 2 +# CHECK-NEXT: frame-destroy SEH_SaveRegP 21, 22, 16 +# CHECK-NEXT: early-clobber $sp, $x19, $x20 = frame-destroy LDPXpost $sp, 10 +# CHECK-NEXT: frame-destroy SEH_SaveRegP_X 19, 20, -80 # CHECK-NEXT: frame-destroy SEH_EpilogEnd # CHECK-NEXT: RET_ReallyLR implicit $x0 diff --git a/llvm/test/CodeGen/AArch64/wineh-frame1.mir b/llvm/test/CodeGen/AArch64/wineh-frame1.mir --- a/llvm/test/CodeGen/AArch64/wineh-frame1.mir +++ b/llvm/test/CodeGen/AArch64/wineh-frame1.mir @@ -2,36 +2,36 @@ # RUN: -stop-after=prologepilog | FileCheck %s # Check save_fregp_x, save_fregp -# CHECK: early-clobber $sp = frame-setup STPDpre killed $d10, killed $d11, $sp, -14 -# CHECK-NEXT: frame-setup SEH_SaveFRegP_X 10, 11, -112 -# CHECK-NEXT: frame-setup STPDi killed $d8, killed $d9, $sp, 2 -# CHECK-NEXT: frame-setup SEH_SaveFRegP 8, 9, 16 -# CHECK-NEXT: frame-setup STPXi killed $x27, killed $x28, $sp, 4 -# CHECK-NEXT: frame-setup SEH_SaveRegP 27, 28, 32 +# CHECK: early-clobber $sp = frame-setup STPXpre killed $x19, killed $x20, $sp, -14 +# CHECK-NEXT: frame-setup SEH_SaveRegP_X 19, 20, -112 +# CHECK-NEXT: frame-setup STPXi killed $x21, killed $x22, $sp, 2 +# CHECK-NEXT: frame-setup SEH_SaveRegP 21, 22, 16 +# CHECK-NEXT: frame-setup STPXi killed $x23, killed $x24, $sp, 4 +# CHECK-NEXT: frame-setup SEH_SaveRegP 23, 24, 32 # CHECK-NEXT: frame-setup STPXi killed $x25, killed $x26, $sp, 6 # CHECK-NEXT: frame-setup SEH_SaveRegP 25, 26, 48 -# CHECK-NEXT: frame-setup STPXi killed $x23, killed $x24, $sp, 8 -# CHECK-NEXT: frame-setup SEH_SaveRegP 23, 24, 64 -# CHECK-NEXT: frame-setup STPXi killed $x21, killed $x22, $sp, 10 -# CHECK-NEXT: frame-setup SEH_SaveRegP 21, 22, 80 -# CHECK-NEXT: frame-setup STPXi killed $x19, killed $x20, $sp, 12 -# CHECK-NEXT: frame-setup SEH_SaveRegP 19, 20, 96 +# CHECK-NEXT: frame-setup STPXi killed $x27, killed $x28, $sp, 8 +# CHECK-NEXT: frame-setup SEH_SaveRegP 27, 28, 64 +# CHECK-NEXT: frame-setup STPDi killed $d8, killed $d9, $sp, 10 +# CHECK-NEXT: frame-setup SEH_SaveFRegP 8, 9, 80 +# CHECK-NEXT: frame-setup STPDi killed $d10, killed $d11, $sp, 12 +# CHECK-NEXT: frame-setup SEH_SaveFRegP 10, 11, 96 # CHECK-NEXT: frame-setup SEH_PrologEnd # CHECK: frame-destroy SEH_EpilogStart -# CHECK-NEXT: $x19, $x20 = frame-destroy LDPXi $sp, 12 -# CHECK-NEXT: frame-destroy SEH_SaveRegP 19, 20, 96 -# CHECK-NEXT: $x21, $x22 = frame-destroy LDPXi $sp, 10 -# CHECK-NEXT: frame-destroy SEH_SaveRegP 21, 22, 80 -# CHECK-NEXT: $x23, $x24 = frame-destroy LDPXi $sp, 8 -# CHECK-NEXT: frame-destroy SEH_SaveRegP 23, 24, 64 +# CHECK-NEXT: $d10, $d11 = frame-destroy LDPDi $sp, 12 +# CHECK-NEXT: frame-destroy SEH_SaveFRegP 10, 11, 96 +# CHECK-NEXT: $d8, $d9 = frame-destroy LDPDi $sp, 10 +# CHECK-NEXT: frame-destroy SEH_SaveFRegP 8, 9, 80 +# CHECK-NEXT: $x27, $x28 = frame-destroy LDPXi $sp, 8 +# CHECK-NEXT: frame-destroy SEH_SaveRegP 27, 28, 64 # CHECK-NEXT: $x25, $x26 = frame-destroy LDPXi $sp, 6 # CHECK-NEXT: frame-destroy SEH_SaveRegP 25, 26, 48 -# CHECK-NEXT: $x27, $x28 = frame-destroy LDPXi $sp, 4 -# CHECK-NEXT: frame-destroy SEH_SaveRegP 27, 28, 32 -# CHECK-NEXT: $d8, $d9 = frame-destroy LDPDi $sp, 2 -# CHECK-NEXT: frame-destroy SEH_SaveFRegP 8, 9, 16 -# CHECK-NEXT: early-clobber $sp, $d10, $d11 = frame-destroy LDPDpost $sp, 14 -# CHECK-NEXT: frame-destroy SEH_SaveFRegP_X 10, 11, -112 +# CHECK-NEXT: $x23, $x24 = frame-destroy LDPXi $sp, 4 +# CHECK-NEXT: frame-destroy SEH_SaveRegP 23, 24, 32 +# CHECK-NEXT: $x21, $x22 = frame-destroy LDPXi $sp, 2 +# CHECK-NEXT: frame-destroy SEH_SaveRegP 21, 22, 16 +# CHECK-NEXT: early-clobber $sp, $x19, $x20 = frame-destroy LDPXpost $sp, 14 +# CHECK-NEXT: frame-destroy SEH_SaveRegP_X 19, 20, -112 # CHECK-NEXT: frame-destroy SEH_EpilogEnd # CHECK-NEXT: RET_ReallyLR implicit $x0 ... diff --git a/llvm/test/CodeGen/AArch64/wineh-frame2.mir b/llvm/test/CodeGen/AArch64/wineh-frame2.mir --- a/llvm/test/CodeGen/AArch64/wineh-frame2.mir +++ b/llvm/test/CodeGen/AArch64/wineh-frame2.mir @@ -2,24 +2,24 @@ # RUN: -stop-after=prologepilog | FileCheck %s # Check save_freg_x, save_frep, save_reg -# CHECK: early-clobber $sp = frame-setup STRDpre killed $d12, $sp, -48 -# CHECK-NEXT: frame-setup SEH_SaveFReg_X 12, -48 -# CHECK-NEXT: frame-setup STPDi killed $d10, killed $d11, $sp, 1 -# CHECK-NEXT: frame-setup SEH_SaveFRegP 10, 11, 8 -# CHECK-NEXT: frame-setup STPDi killed $d8, killed $d9, $sp, 3 -# CHECK-NEXT: frame-setup SEH_SaveFRegP 8, 9, 24 -# CHECK-NEXT: frame-setup STRXui killed $x19, $sp, 5 -# CHECK-NEXT: frame-setup SEH_SaveReg 19, 40 +# CHECK: early-clobber $sp = frame-setup STRXpre killed $x19, $sp, -48 +# CHECK-NEXT: frame-setup SEH_SaveReg_X 19, -48 +# CHECK-NEXT: frame-setup STPDi killed $d8, killed $d9, $sp, 1 +# CHECK-NEXT: frame-setup SEH_SaveFRegP 8, 9, 8 +# CHECK-NEXT: frame-setup STPDi killed $d10, killed $d11, $sp, 3 +# CHECK-NEXT: frame-setup SEH_SaveFRegP 10, 11, 24 +# CHECK-NEXT: frame-setup STRDui killed $d12, $sp, 5 +# CHECK-NEXT: frame-setup SEH_SaveFReg 12, 40 # CHECK-NEXT: frame-setup SEH_PrologEnd # CHECK: frame-destroy SEH_EpilogStart -# CHECK-NEXT: $x19 = frame-destroy LDRXui $sp, 5 -# CHECK-NEXT: frame-destroy SEH_SaveReg 19, 40 -# CHECK-NEXT: $d8, $d9 = frame-destroy LDPDi $sp, 3 -# CHECK-NEXT: frame-destroy SEH_SaveFRegP 8, 9, 24 -# CHECK-NEXT: $d10, $d11 = frame-destroy LDPDi $sp, 1 -# CHECK-NEXT: frame-destroy SEH_SaveFRegP 10, 11, 8 -# CHECK-NEXT: early-clobber $sp, $d12 = frame-destroy LDRDpost $sp, 48 -# CHECK-NEXT: frame-destroy SEH_SaveFReg_X 12, -48 +# CHECK-NEXT: $d12 = frame-destroy LDRDui $sp, 5 +# CHECK-NEXT: frame-destroy SEH_SaveFReg 12, 40 +# CHECK-NEXT: $d10, $d11 = frame-destroy LDPDi $sp, 3 +# CHECK-NEXT: frame-destroy SEH_SaveFRegP 10, 11, 24 +# CHECK-NEXT: $d8, $d9 = frame-destroy LDPDi $sp, 1 +# CHECK-NEXT: frame-destroy SEH_SaveFRegP 8, 9, 8 +# CHECK-NEXT: early-clobber $sp, $x19 = frame-destroy LDRXpost $sp, 48 +# CHECK-NEXT: frame-destroy SEH_SaveReg_X 19, -48 # CHECK-NEXT: frame-destroy SEH_EpilogEnd # CHECK-NEXT: RET_ReallyLR implicit $x0 ... diff --git a/llvm/test/CodeGen/AArch64/wineh-frame3.mir b/llvm/test/CodeGen/AArch64/wineh-frame3.mir --- a/llvm/test/CodeGen/AArch64/wineh-frame3.mir +++ b/llvm/test/CodeGen/AArch64/wineh-frame3.mir @@ -2,16 +2,16 @@ # RUN: -stop-after=prologepilog | FileCheck %s # Check save_reg_x, save_reg -# CHECK: early-clobber $sp = frame-setup STRXpre killed $x22, $sp, -16 -# CHECK-NEXT: frame-setup SEH_SaveReg_X 22, -16 -# CHECK-NEXT: frame-setup STRXui killed $x19, $sp, 1 -# CHECK-NEXT: frame-setup SEH_SaveReg 19, 8 +# CHECK: early-clobber $sp = frame-setup STRXpre killed $x19, $sp, -16 +# CHECK-NEXT: frame-setup SEH_SaveReg_X 19, -16 +# CHECK-NEXT: frame-setup STRXui killed $x22, $sp, 1 +# CHECK-NEXT: frame-setup SEH_SaveReg 22, 8 # CHECK-NEXT: frame-setup SEH_PrologEnd # CHECK: frame-destroy SEH_EpilogStart -# CHECK-NEXT: $x19 = frame-destroy LDRXui $sp, 1 -# CHECK-NEXT: frame-destroy SEH_SaveReg 19, 8 -# CHECK-NEXT: early-clobber $sp, $x22 = frame-destroy LDRXpost $sp, 16 -# CHECK-NEXT: frame-destroy SEH_SaveReg_X 22, -16 +# CHECK-NEXT: $x22 = frame-destroy LDRXui $sp, 1 +# CHECK-NEXT: frame-destroy SEH_SaveReg 22, 8 +# CHECK-NEXT: early-clobber $sp, $x19 = frame-destroy LDRXpost $sp, 16 +# CHECK-NEXT: frame-destroy SEH_SaveReg_X 19, -16 # CHECK-NEXT: frame-destroy SEH_EpilogEnd # CHECK-NEXT: RET_ReallyLR implicit $x0 ... diff --git a/llvm/test/CodeGen/AArch64/wineh-frame4.mir b/llvm/test/CodeGen/AArch64/wineh-frame4.mir --- a/llvm/test/CodeGen/AArch64/wineh-frame4.mir +++ b/llvm/test/CodeGen/AArch64/wineh-frame4.mir @@ -2,16 +2,16 @@ # RUN: -stop-after=prologepilog | FileCheck %s # Check save_freg_x, save_freg -# CHECK: early-clobber $sp = frame-setup STRDpre killed $d10, $sp, -16 -# CHECK-NEXT: frame-setup SEH_SaveFReg_X 10, -16 -# CHECK-NEXT: frame-setup STRDui killed $d8, $sp, 1 :: (store 8 into %stack.0) -# CHECK-NEXT: frame-setup SEH_SaveFReg 8, 8 +# CHECK: early-clobber $sp = frame-setup STRDpre killed $d8, $sp, -16 +# CHECK-NEXT: frame-setup SEH_SaveFReg_X 8, -16 +# CHECK-NEXT: frame-setup STRDui killed $d10, $sp, 1 :: (store 8 into %stack.0) +# CHECK-NEXT: frame-setup SEH_SaveFReg 10, 8 # CHECK-NEXT: frame-setup SEH_PrologEnd # CHECK: frame-destroy SEH_EpilogStart -# CHECK-NEXT: $d8 = frame-destroy LDRDui $sp, 1 :: (load 8 from %stack.0) -# CHECK-NEXT: frame-destroy SEH_SaveFReg 8, 8 -# CHECK-NEXT: early-clobber $sp, $d10 = frame-destroy LDRDpost $sp, 16 :: (load 8 from %stack.1) -# CHECK-NEXT: frame-destroy SEH_SaveFReg_X 10, -16 +# CHECK-NEXT: $d10 = frame-destroy LDRDui $sp, 1 :: (load 8 from %stack.0) +# CHECK-NEXT: frame-destroy SEH_SaveFReg 10, 8 +# CHECK-NEXT: early-clobber $sp, $d8 = frame-destroy LDRDpost $sp, 16 :: (load 8 from %stack.1) +# CHECK-NEXT: frame-destroy SEH_SaveFReg_X 8, -16 # CHECK-NEXT: frame-destroy SEH_EpilogEnd # CHECK-NEXT: RET_ReallyLR implicit $x0 ... diff --git a/llvm/test/CodeGen/AArch64/wineh-frame5.mir b/llvm/test/CodeGen/AArch64/wineh-frame5.mir --- a/llvm/test/CodeGen/AArch64/wineh-frame5.mir +++ b/llvm/test/CodeGen/AArch64/wineh-frame5.mir @@ -3,10 +3,10 @@ # Check multiple epilogues, save_reg, save_reg_x. # CHECK-LABEL: bb.0.entry: -# CHECK: early-clobber $sp = frame-setup STPXpre killed $fp, killed $lr, $sp, -4 -# CHECK-NEXT: frame-setup SEH_SaveFPLR_X -32 -# CHECK-NEXT: frame-setup STRXui killed $x19, $sp, 2 -# CHECK-NEXT: frame-setup SEH_SaveReg 19, 16 +# 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: $sp = frame-setup SUBXri $sp, 496, 0 # CHECK-NEXT: frame-setup SEH_StackAlloc 496 # CHECK-NEXT: frame-setup SEH_PrologEnd @@ -15,10 +15,10 @@ # CHECK: frame-destroy SEH_EpilogStart # CHECK-NEXT: $sp = frame-destroy ADDXri $sp, 496, 0 # CHECK-NEXT: frame-destroy SEH_StackAlloc 496 -# CHECK-NEXT: $x19 = frame-destroy LDRXui $sp, 2 -# CHECK-NEXT: frame-destroy SEH_SaveReg 19, 16 -# CHECK-NEXT: early-clobber $sp, $fp, $lr = frame-destroy LDPXpost $sp, 4 -# CHECK-NEXT: frame-destroy SEH_SaveFPLR_X -32 +# CHECK-NEXT: $fp, $lr = frame-destroy LDPXi $sp, 1 +# CHECK-NEXT: frame-destroy SEH_SaveFPLR 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 # CHECK-NEXT: TCRETURNdi @"?func2@@YAHXZ", 0, csr_aarch64_aapcs, implicit $sp diff --git a/llvm/test/CodeGen/AArch64/wineh-try-catch-realign.ll b/llvm/test/CodeGen/AArch64/wineh-try-catch-realign.ll --- a/llvm/test/CodeGen/AArch64/wineh-try-catch-realign.ll +++ b/llvm/test/CodeGen/AArch64/wineh-try-catch-realign.ll @@ -9,12 +9,12 @@ ; it shouldn't access the parent's frame via sp, and the prologue and ; epilogue should be symmetrical. ; CHECK-LABEL: "?catch$2@?0??a@@YAXXZ@4HA": -; CHECK: stp x29, x30, [sp, #-32]! -; CHECK-NEXT: .seh_save_fplr_x 32 -; CHECK-NEXT: str x28, [sp, #16] -; CHECK-NEXT: .seh_save_reg x28, 16 -; CHECK-NEXT: str x19, [sp, #24] -; CHECK-NEXT: .seh_save_reg x19, 24 +; CHECK: str x19, [sp, #-32]! +; CHECK-NEXT: .seh_save_reg_x x19, 32 +; CHECK-NEXT: str x28, [sp, #8] +; CHECK-NEXT: .seh_save_reg x28, 8 +; CHECK-NEXT: stp x29, x30, [sp, #16] +; CHECK-NEXT: .seh_save_fplr 16 ; CHECK-NEXT: .seh_endprologue ; CHECK-NEXT: add x0, x19, #0 ; CHECK-NEXT: mov w1, wzr @@ -22,12 +22,12 @@ ; CHECK-NEXT: adrp x0, .LBB0_1 ; CHECK-NEXT: add x0, x0, .LBB0_1 ; CHECK-NEXT: .seh_startepilogue -; CHECK-NEXT: ldr x19, [sp, #24] -; CHECK-NEXT: .seh_save_reg x19, 24 -; CHECK-NEXT: ldr x28, [sp, #16] -; CHECK-NEXT: .seh_save_reg x28, 16 -; CHECK-NEXT: ldp x29, x30, [sp], #32 -; CHECK-NEXT: .seh_save_fplr_x 32 +; CHECK-NEXT: ldp x29, x30, [sp, #16] +; CHECK-NEXT: .seh_save_fplr 16 +; CHECK-NEXT: ldr x28, [sp, #8] +; CHECK-NEXT: .seh_save_reg x28, 8 +; CHECK-NEXT: ldr x19, [sp], #32 +; CHECK-NEXT: .seh_save_reg_x x19, 32 ; CHECK-NEXT: .seh_endepilogue ; CHECK-NEXT: ret diff --git a/llvm/test/CodeGen/AArch64/wineh-try-catch.ll b/llvm/test/CodeGen/AArch64/wineh-try-catch.ll --- a/llvm/test/CodeGen/AArch64/wineh-try-catch.ll +++ b/llvm/test/CodeGen/AArch64/wineh-try-catch.ll @@ -15,15 +15,15 @@ ; We check this offset in the table later on. ; CHECK-LABEL: "?func@@YAHXZ": -; CHECK: stp x29, x30, [sp, #-64]! -; CHECK: str x28, [sp, #16] -; CHECK: str x21, [sp, #24] -; CHECK: stp x19, x20, [sp, #32] -; CHECK: mov x29, sp +; CHECK: stp x19, x20, [sp, #-64]! +; CHECK: str x21, [sp, #16] +; CHECK: str x28, [sp, #24] +; CHECK: stp x29, x30, [sp, #32] +; CHECK: add x29, sp, #32 ; CHECK: sub sp, sp, #624 ; CHECK: mov x19, sp ; CHECK: mov x0, #-2 -; CHECK: stur x0, [x29, #48] +; CHECK: stur x0, [x29, #16] ; Now check that x is stored at fp - 20. We check that this is the same ; location accessed from the funclet to retrieve x. @@ -47,10 +47,10 @@ ; CHECK-LABEL: "?catch$2@?0??func@@YAHXZ@4HA": ; Check that the stack space is allocated only for the callee saved registers. -; CHECK: stp x29, x30, [sp, #-48]! -; CHECK: str x28, [sp, #16] -; CHECK: str x21, [sp, #24] -; CHECK: stp x19, x20, [sp, #32] +; CHECK: stp x19, x20, [sp, #-48]! +; CHECK: str x21, [sp, #16] +; CHECK: str x28, [sp, #24] +; CHECK: stp x29, x30, [sp, #32] ; CHECK: add x20, x19, #12 ; Check that there are no further stack updates. @@ -87,18 +87,18 @@ ; UNWIND: Prologue [ ; UNWIND-NEXT: ; nop ; UNWIND-NEXT: ; sub sp, #624 -; UNWIND-NEXT: ; mov fp, sp -; UNWIND-NEXT: ; stp x19, x20, [sp, #32] -; UNWIND-NEXT: ; str x21, [sp, #24] -; UNWIND-NEXT: ; str x28, [sp, #16] -; UNWIND-NEXT: ; stp x29, x30, [sp, #-64]! +; UNWIND-NEXT: ; add fp, sp, #32 +; UNWIND-NEXT: ; stp x29, x30, [sp, #32] +; UNWIND-NEXT: ; str x28, [sp, #24] +; UNWIND-NEXT: ; str x21, [sp, #16] +; UNWIND-NEXT: ; stp x19, x20, [sp, #-64]! ; UNWIND-NEXT: ; end ; UNWIND: Function: ?catch$2@?0??func@@YAHXZ@4HA ; UNWIND: Prologue [ -; UNWIND-NEXT: ; stp x19, x20, [sp, #32] -; UNWIND-NEXT: ; str x21, [sp, #24] -; UNWIND-NEXT: ; str x28, [sp, #16] -; UNWIND-NEXT: ; stp x29, x30, [sp, #-48]! +; UNWIND-NEXT: ; stp x29, x30, [sp, #32] +; UNWIND-NEXT: ; str x28, [sp, #24] +; UNWIND-NEXT: ; str x21, [sp, #16] +; UNWIND-NEXT: ; stp x19, x20, [sp, #-48]! ; UNWIND-NEXT: ; end target datalayout = "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128" diff --git a/llvm/test/CodeGen/AArch64/wineh_shrinkwrap.mir b/llvm/test/CodeGen/AArch64/wineh_shrinkwrap.mir --- a/llvm/test/CodeGen/AArch64/wineh_shrinkwrap.mir +++ b/llvm/test/CodeGen/AArch64/wineh_shrinkwrap.mir @@ -9,7 +9,7 @@ # The same test gets shrink wrapped on Linux ARM64. # WIN64-LABEL: bb.0.entry: -# WIN64: early-clobber $sp = frame-setup STPXpre killed $fp, killed $lr, $sp, -4 +# WIN64: early-clobber $sp = frame-setup STRXpre killed $x19, $sp, -32 # WIN64-LABEL: bb.1: # WIN64-LABEL: bb.2.if.then: