Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 34 additions & 1 deletion llvm/lib/MC/MCWin64EH.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1051,7 +1051,9 @@ static bool tryARM64PackedUnwind(WinEH::FrameInfo *info, uint32_t FuncLength,
// the order - that would work fine when unwinding from within
// functions, but not be exactly right if unwinding happens within
// prologs/epilogs.
for (const WinEH::Instruction &Inst : info->Instructions) {
for (auto It = info->Instructions.begin(), EndIt = info->Instructions.end();
It != EndIt; It++) {
const WinEH::Instruction &Inst = *It;
switch (Inst.Operation) {
case Win64EH::UOP_End:
if (Location != Start)
Expand Down Expand Up @@ -1169,6 +1171,28 @@ static bool tryARM64PackedUnwind(WinEH::FrameInfo *info, uint32_t FuncLength,
Location != FloatRegs && Location != InputArgs &&
Location != StackAdjust)
return false;
// Becuase there's no save_lrpair_x opcode, the case of CR=01,
// RegI=1 is handled as a special case with a pair of instructions; an
// alloc followed by a regular save_lrpair. So when encountering an
// alloc here, check if this is the start of such an instruction pair.
if (Location == Start2) { // Can't have this at Start3, after PACSignLR
auto NextIt = It + 1;
if (NextIt != EndIt) {
const WinEH::Instruction &NextInst = *NextIt;
if (NextInst.Operation == Win64EH::UOP_SaveLRPair &&
NextInst.Offset == 0 && NextInst.Register == 19) {
assert(Predecrement == 0);
assert(RegI == 0);
assert(!StandaloneLR);
Predecrement = Inst.Offset;
RegI = 1;
StandaloneLR = true;
Location = FloatRegs;
It++; // Consume both the Alloc and the SaveLRPair
continue;
}
}
}
// Can have either a single decrement, or a pair of decrements with
// 4080 and another decrement.
if (StackOffset == 0)
Expand Down Expand Up @@ -1269,6 +1293,15 @@ static bool tryARM64PackedUnwind(WinEH::FrameInfo *info, uint32_t FuncLength,
// according to the documentation.
if (H)
return false;
// Older versions of Windows (at least in 10.0.22000.2176) incorrectly
// unwind packed unwind info with CR=01, RegI=1, RegF>0, see
// https://github.com/llvm/llvm-project/issues/169588#issuecomment-3584907886.
// This issue only exists in older versions; current versions
// (10.0.26100.6899) do handle it correctly. As long as we can't be sure
// that we won't run on older versions, avoid producing the packed form
// here.
if (StandaloneLR && RegI == 1 && RegF > 0)
return false;
int IntSZ = 8 * RegI;
if (StandaloneLR)
IntSZ += 8;
Expand Down
109 changes: 109 additions & 0 deletions llvm/test/MC/AArch64/seh-packed-unwind.s
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,26 @@
// CHECK-NEXT: end
// CHECK-NEXT: ]
// CHECK-NEXT: }
// CHECK-NEXT: RuntimeFunction {
// CHECK-NEXT: Function: func19
// CHECK-NEXT: Fragment: No
// CHECK-NEXT: FunctionLength: 32
// CHECK-NEXT: RegF: 0
// CHECK-NEXT: RegI: 1
// CHECK-NEXT: HomedParameters: No
// CHECK-NEXT: CR: 1
// CHECK-NEXT: FrameSize: 80
// CHECK-NEXT: Prologue [
// CHECK-NEXT: sub sp, sp, #64
// CHECK-NEXT: stp x19, lr, [sp]
// CHECK-NEXT: sub sp, sp, #16
// CHECK-NEXT: end
// CHECK-NEXT: ]
// CHECK-NEXT: }
// CHECK-NEXT: RuntimeFunction {
// CHECK-NEXT: Function: notpacked_func20
// CHECK-NEXT: ExceptionRecord:
// CHECK-NEXT: ExceptionData {
// CHECK: RuntimeFunction {
// CHECK-NEXT: Function: nonpacked1
// CHECK-NEXT: ExceptionRecord:
Expand Down Expand Up @@ -374,6 +394,11 @@
// CHECK-NEXT: Function: nonpacked16
// CHECK-NEXT: ExceptionRecord:
// CHECK-NEXT: ExceptionData {
// CHECK: EpiloguePacked: Yes
// CHECK: RuntimeFunction {
// CHECK-NEXT: Function: nonpacked17
// CHECK-NEXT: ExceptionRecord:
// CHECK-NEXT: ExceptionData {
// CHECK: EpiloguePacked: Yes


Expand Down Expand Up @@ -809,6 +834,59 @@ func18:
ret
.seh_endproc

func19:
.seh_proc func19
sub sp, sp, #16
.seh_stackalloc 16
stp x19, lr, [sp]
.seh_save_lrpair x19, 0
sub sp, sp, #64
.seh_stackalloc 64
.seh_endprologue
nop
.seh_startepilogue
add sp, sp, #64
.seh_stackalloc 64
ldp x19, lr, [sp]
.seh_save_lrpair x19, 0
add sp, sp, #16
.seh_stackalloc 16
.seh_endepilogue
ret
.seh_endproc

notpacked_func20:
// This function is expressible with packed unwind info, but older
// versions of Windows unwind cases with CR=01, RegI=1, RegF>0
// incorrectly; therefore, we choose not to pack this case.
.seh_proc notpacked_func20
sub sp, sp, #48
.seh_stackalloc 48
stp x19, lr, [sp]
.seh_save_lrpair x19, 0
stp d8, d9, [sp, #16]
.seh_save_fregp d8, 16
str d10, [sp, #32]
.seh_save_freg d10, 32
sub sp, sp, #64
.seh_stackalloc 64
.seh_endprologue
nop
.seh_startepilogue
add sp, sp, #64
.seh_stackalloc 64
ldr d10, [sp, #32]
.seh_save_freg d10, 32
ldp d8, d9, [sp, #16]
.seh_save_fregp d8, 16
ldp x19, lr, [sp]
.seh_save_lrpair x19, 0
add sp, sp, #48
.seh_stackalloc 48
.seh_endepilogue
ret
.seh_endproc

nonpacked1:
.seh_proc nonpacked1
// Can't be packed; can't save integer registers after float registers.
Expand Down Expand Up @@ -1157,3 +1235,34 @@ nonpacked16:
.seh_endepilogue
br x9
.seh_endproc

nonpacked17:
.seh_proc nonpacked17
// Can't be packed; more predecrement for SavSZ than used for
// corresponding RegI/RegF/LR saves
sub sp, sp, #64
.seh_stackalloc 64
stp x19, lr, [sp]
.seh_save_lrpair x19, 0
stp d8, d9, [sp, #16]
.seh_save_fregp d8, 16
str d10, [sp, #32]
.seh_save_freg d10, 32
sub sp, sp, #64
.seh_stackalloc 64
.seh_endprologue
nop
.seh_startepilogue
add sp, sp, #64
.seh_stackalloc 64
ldr d10, [sp, #32]
.seh_save_freg d10, 32
ldp d8, d9, [sp, #16]
.seh_save_fregp d8, 16
ldp x19, lr, [sp]
.seh_save_lrpair x19, 0
add sp, sp, #64
.seh_stackalloc 64
.seh_endepilogue
ret
.seh_endproc
Loading