Skip to content

Commit 0315417

Browse files
mstorsjokcloudy0717
authored andcommitted
[MC] [Win64EH] Produce packed unwind for the special case of X19+LR (llvm#169697)
1 parent bc624c7 commit 0315417

File tree

2 files changed

+143
-1
lines changed

2 files changed

+143
-1
lines changed

llvm/lib/MC/MCWin64EH.cpp

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1051,7 +1051,9 @@ static bool tryARM64PackedUnwind(WinEH::FrameInfo *info, uint32_t FuncLength,
10511051
// the order - that would work fine when unwinding from within
10521052
// functions, but not be exactly right if unwinding happens within
10531053
// prologs/epilogs.
1054-
for (const WinEH::Instruction &Inst : info->Instructions) {
1054+
for (auto It = info->Instructions.begin(), EndIt = info->Instructions.end();
1055+
It != EndIt; It++) {
1056+
const WinEH::Instruction &Inst = *It;
10551057
switch (Inst.Operation) {
10561058
case Win64EH::UOP_End:
10571059
if (Location != Start)
@@ -1169,6 +1171,28 @@ static bool tryARM64PackedUnwind(WinEH::FrameInfo *info, uint32_t FuncLength,
11691171
Location != FloatRegs && Location != InputArgs &&
11701172
Location != StackAdjust)
11711173
return false;
1174+
// Becuase there's no save_lrpair_x opcode, the case of CR=01,
1175+
// RegI=1 is handled as a special case with a pair of instructions; an
1176+
// alloc followed by a regular save_lrpair. So when encountering an
1177+
// alloc here, check if this is the start of such an instruction pair.
1178+
if (Location == Start2) { // Can't have this at Start3, after PACSignLR
1179+
auto NextIt = It + 1;
1180+
if (NextIt != EndIt) {
1181+
const WinEH::Instruction &NextInst = *NextIt;
1182+
if (NextInst.Operation == Win64EH::UOP_SaveLRPair &&
1183+
NextInst.Offset == 0 && NextInst.Register == 19) {
1184+
assert(Predecrement == 0);
1185+
assert(RegI == 0);
1186+
assert(!StandaloneLR);
1187+
Predecrement = Inst.Offset;
1188+
RegI = 1;
1189+
StandaloneLR = true;
1190+
Location = FloatRegs;
1191+
It++; // Consume both the Alloc and the SaveLRPair
1192+
continue;
1193+
}
1194+
}
1195+
}
11721196
// Can have either a single decrement, or a pair of decrements with
11731197
// 4080 and another decrement.
11741198
if (StackOffset == 0)
@@ -1269,6 +1293,15 @@ static bool tryARM64PackedUnwind(WinEH::FrameInfo *info, uint32_t FuncLength,
12691293
// according to the documentation.
12701294
if (H)
12711295
return false;
1296+
// Older versions of Windows (at least in 10.0.22000.2176) incorrectly
1297+
// unwind packed unwind info with CR=01, RegI=1, RegF>0, see
1298+
// https://github.com/llvm/llvm-project/issues/169588#issuecomment-3584907886.
1299+
// This issue only exists in older versions; current versions
1300+
// (10.0.26100.6899) do handle it correctly. As long as we can't be sure
1301+
// that we won't run on older versions, avoid producing the packed form
1302+
// here.
1303+
if (StandaloneLR && RegI == 1 && RegF > 0)
1304+
return false;
12721305
int IntSZ = 8 * RegI;
12731306
if (StandaloneLR)
12741307
IntSZ += 8;

llvm/test/MC/AArch64/seh-packed-unwind.s

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,26 @@
295295
// CHECK-NEXT: end
296296
// CHECK-NEXT: ]
297297
// CHECK-NEXT: }
298+
// CHECK-NEXT: RuntimeFunction {
299+
// CHECK-NEXT: Function: func19
300+
// CHECK-NEXT: Fragment: No
301+
// CHECK-NEXT: FunctionLength: 32
302+
// CHECK-NEXT: RegF: 0
303+
// CHECK-NEXT: RegI: 1
304+
// CHECK-NEXT: HomedParameters: No
305+
// CHECK-NEXT: CR: 1
306+
// CHECK-NEXT: FrameSize: 80
307+
// CHECK-NEXT: Prologue [
308+
// CHECK-NEXT: sub sp, sp, #64
309+
// CHECK-NEXT: stp x19, lr, [sp]
310+
// CHECK-NEXT: sub sp, sp, #16
311+
// CHECK-NEXT: end
312+
// CHECK-NEXT: ]
313+
// CHECK-NEXT: }
314+
// CHECK-NEXT: RuntimeFunction {
315+
// CHECK-NEXT: Function: notpacked_func20
316+
// CHECK-NEXT: ExceptionRecord:
317+
// CHECK-NEXT: ExceptionData {
298318
// CHECK: RuntimeFunction {
299319
// CHECK-NEXT: Function: nonpacked1
300320
// CHECK-NEXT: ExceptionRecord:
@@ -374,6 +394,11 @@
374394
// CHECK-NEXT: Function: nonpacked16
375395
// CHECK-NEXT: ExceptionRecord:
376396
// CHECK-NEXT: ExceptionData {
397+
// CHECK: EpiloguePacked: Yes
398+
// CHECK: RuntimeFunction {
399+
// CHECK-NEXT: Function: nonpacked17
400+
// CHECK-NEXT: ExceptionRecord:
401+
// CHECK-NEXT: ExceptionData {
377402
// CHECK: EpiloguePacked: Yes
378403

379404

@@ -809,6 +834,59 @@ func18:
809834
ret
810835
.seh_endproc
811836

837+
func19:
838+
.seh_proc func19
839+
sub sp, sp, #16
840+
.seh_stackalloc 16
841+
stp x19, lr, [sp]
842+
.seh_save_lrpair x19, 0
843+
sub sp, sp, #64
844+
.seh_stackalloc 64
845+
.seh_endprologue
846+
nop
847+
.seh_startepilogue
848+
add sp, sp, #64
849+
.seh_stackalloc 64
850+
ldp x19, lr, [sp]
851+
.seh_save_lrpair x19, 0
852+
add sp, sp, #16
853+
.seh_stackalloc 16
854+
.seh_endepilogue
855+
ret
856+
.seh_endproc
857+
858+
notpacked_func20:
859+
// This function is expressible with packed unwind info, but older
860+
// versions of Windows unwind cases with CR=01, RegI=1, RegF>0
861+
// incorrectly; therefore, we choose not to pack this case.
862+
.seh_proc notpacked_func20
863+
sub sp, sp, #48
864+
.seh_stackalloc 48
865+
stp x19, lr, [sp]
866+
.seh_save_lrpair x19, 0
867+
stp d8, d9, [sp, #16]
868+
.seh_save_fregp d8, 16
869+
str d10, [sp, #32]
870+
.seh_save_freg d10, 32
871+
sub sp, sp, #64
872+
.seh_stackalloc 64
873+
.seh_endprologue
874+
nop
875+
.seh_startepilogue
876+
add sp, sp, #64
877+
.seh_stackalloc 64
878+
ldr d10, [sp, #32]
879+
.seh_save_freg d10, 32
880+
ldp d8, d9, [sp, #16]
881+
.seh_save_fregp d8, 16
882+
ldp x19, lr, [sp]
883+
.seh_save_lrpair x19, 0
884+
add sp, sp, #48
885+
.seh_stackalloc 48
886+
.seh_endepilogue
887+
ret
888+
.seh_endproc
889+
812890
nonpacked1:
813891
.seh_proc nonpacked1
814892
// Can't be packed; can't save integer registers after float registers.
@@ -1157,3 +1235,34 @@ nonpacked16:
11571235
.seh_endepilogue
11581236
br x9
11591237
.seh_endproc
1238+
1239+
nonpacked17:
1240+
.seh_proc nonpacked17
1241+
// Can't be packed; more predecrement for SavSZ than used for
1242+
// corresponding RegI/RegF/LR saves
1243+
sub sp, sp, #64
1244+
.seh_stackalloc 64
1245+
stp x19, lr, [sp]
1246+
.seh_save_lrpair x19, 0
1247+
stp d8, d9, [sp, #16]
1248+
.seh_save_fregp d8, 16
1249+
str d10, [sp, #32]
1250+
.seh_save_freg d10, 32
1251+
sub sp, sp, #64
1252+
.seh_stackalloc 64
1253+
.seh_endprologue
1254+
nop
1255+
.seh_startepilogue
1256+
add sp, sp, #64
1257+
.seh_stackalloc 64
1258+
ldr d10, [sp, #32]
1259+
.seh_save_freg d10, 32
1260+
ldp d8, d9, [sp, #16]
1261+
.seh_save_fregp d8, 16
1262+
ldp x19, lr, [sp]
1263+
.seh_save_lrpair x19, 0
1264+
add sp, sp, #64
1265+
.seh_stackalloc 64
1266+
.seh_endepilogue
1267+
ret
1268+
.seh_endproc

0 commit comments

Comments
 (0)