Skip to content

Commit dcc82b5

Browse files
committed
AArch64: support extended spills in SEH on WoS (llvm#166849)
When lowering code for Windows, we might be using a non-standard calling convention (e.g. `preserve_most`). In such a case, we might be spilling registers which are unexpected (i.e. x9-x15). Use the ARM64EC opcodes to indicate such spills. This adds support for the handling for these spills but is insufficient on its own. The encoded results are incorrect due to the expectation that the pair wise spills are always 16-byte aligned which we currently do not enforce. Fixing that is beyond the scope of emitting the SEH directives for the spill. (cherry picked from commit 77b9301)
1 parent 8c51074 commit dcc82b5

File tree

5 files changed

+79
-7
lines changed

5 files changed

+79
-7
lines changed

llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3406,6 +3406,22 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
34063406
TS->emitARM64WinCFIPACSignLR();
34073407
return;
34083408

3409+
case AArch64::SEH_SaveAnyRegI:
3410+
assert(MI->getOperand(1).getImm() <= 1008 &&
3411+
"SaveAnyRegQP SEH opcode offset must fit into 6 bits");
3412+
TS->emitARM64WinCFISaveAnyRegI(MI->getOperand(0).getImm(),
3413+
MI->getOperand(1).getImm());
3414+
return;
3415+
3416+
case AArch64::SEH_SaveAnyRegIP:
3417+
assert(MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1 &&
3418+
"Non-consecutive registers not allowed for save_any_reg");
3419+
assert(MI->getOperand(2).getImm() <= 1008 &&
3420+
"SaveAnyRegQP SEH opcode offset must fit into 6 bits");
3421+
TS->emitARM64WinCFISaveAnyRegIP(MI->getOperand(0).getImm(),
3422+
MI->getOperand(2).getImm());
3423+
return;
3424+
34093425
case AArch64::SEH_SaveAnyRegQP:
34103426
assert(MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1 &&
34113427
"Non-consecutive registers not allowed for save_any_reg");

llvm/lib/Target/AArch64/AArch64FrameLowering.cpp

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1407,25 +1407,41 @@ static MachineBasicBlock::iterator InsertSEH(MachineBasicBlock::iterator MBBI,
14071407
case AArch64::LDPXi: {
14081408
Register Reg0 = MBBI->getOperand(0).getReg();
14091409
Register Reg1 = MBBI->getOperand(1).getReg();
1410+
1411+
int SEHReg0 = RegInfo->getSEHRegNum(Reg0);
1412+
int SEHReg1 = RegInfo->getSEHRegNum(Reg1);
1413+
14101414
if (Reg0 == AArch64::FP && Reg1 == AArch64::LR)
14111415
MIB = BuildMI(MF, DL, TII.get(AArch64::SEH_SaveFPLR))
14121416
.addImm(Imm * 8)
14131417
.setMIFlag(Flag);
1414-
else
1418+
else if (SEHReg0 >= 19 && SEHReg1 >= 19)
14151419
MIB = BuildMI(MF, DL, TII.get(AArch64::SEH_SaveRegP))
1416-
.addImm(RegInfo->getSEHRegNum(Reg0))
1417-
.addImm(RegInfo->getSEHRegNum(Reg1))
1420+
.addImm(SEHReg0)
1421+
.addImm(SEHReg1)
1422+
.addImm(Imm * 8)
1423+
.setMIFlag(Flag);
1424+
else
1425+
MIB = BuildMI(MF, DL, TII.get(AArch64::SEH_SaveAnyRegIP))
1426+
.addImm(SEHReg0)
1427+
.addImm(SEHReg1)
14181428
.addImm(Imm * 8)
14191429
.setMIFlag(Flag);
14201430
break;
14211431
}
14221432
case AArch64::STRXui:
14231433
case AArch64::LDRXui: {
14241434
int Reg = RegInfo->getSEHRegNum(MBBI->getOperand(0).getReg());
1425-
MIB = BuildMI(MF, DL, TII.get(AArch64::SEH_SaveReg))
1426-
.addImm(Reg)
1427-
.addImm(Imm * 8)
1428-
.setMIFlag(Flag);
1435+
if (Reg >= 19)
1436+
MIB = BuildMI(MF, DL, TII.get(AArch64::SEH_SaveReg))
1437+
.addImm(Reg)
1438+
.addImm(Imm * 8)
1439+
.setMIFlag(Flag);
1440+
else
1441+
MIB = BuildMI(MF, DL, TII.get(AArch64::SEH_SaveAnyRegI))
1442+
.addImm(Reg)
1443+
.addImm(Imm * 8)
1444+
.setMIFlag(Flag);
14291445
break;
14301446
}
14311447
case AArch64::STRDui:
@@ -1479,6 +1495,8 @@ static void fixupSEHOpcode(MachineBasicBlock::iterator MBBI,
14791495
case AArch64::SEH_SaveReg:
14801496
case AArch64::SEH_SaveFRegP:
14811497
case AArch64::SEH_SaveFReg:
1498+
case AArch64::SEH_SaveAnyRegI:
1499+
case AArch64::SEH_SaveAnyRegIP:
14821500
case AArch64::SEH_SaveAnyRegQP:
14831501
case AArch64::SEH_SaveAnyRegQPX:
14841502
ImmOpnd = &MBBI->getOperand(ImmIdx);

llvm/lib/Target/AArch64/AArch64InstrInfo.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1174,6 +1174,8 @@ bool AArch64InstrInfo::isSEHInstruction(const MachineInstr &MI) {
11741174
case AArch64::SEH_EpilogStart:
11751175
case AArch64::SEH_EpilogEnd:
11761176
case AArch64::SEH_PACSignLR:
1177+
case AArch64::SEH_SaveAnyRegI:
1178+
case AArch64::SEH_SaveAnyRegIP:
11771179
case AArch64::SEH_SaveAnyRegQP:
11781180
case AArch64::SEH_SaveAnyRegQPX:
11791181
case AArch64::SEH_AllocZ:

llvm/lib/Target/AArch64/AArch64InstrInfo.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5634,6 +5634,8 @@ let isPseudo = 1 in {
56345634
def SEH_EpilogStart : Pseudo<(outs), (ins), []>, Sched<[]>;
56355635
def SEH_EpilogEnd : Pseudo<(outs), (ins), []>, Sched<[]>;
56365636
def SEH_PACSignLR : Pseudo<(outs), (ins), []>, Sched<[]>;
5637+
def SEH_SaveAnyRegI : Pseudo<(outs), (ins i32imm:$reg0, i32imm:$offs), []>, Sched<[]>;
5638+
def SEH_SaveAnyRegIP : Pseudo<(outs), (ins i32imm:$reg0, i32imm:$reg1, i32imm:$offs), []>, Sched<[]>;
56375639
def SEH_SaveAnyRegQP : Pseudo<(outs), (ins i32imm:$reg0, i32imm:$reg1, i32imm:$offs), []>, Sched<[]>;
56385640
def SEH_SaveAnyRegQPX : Pseudo<(outs), (ins i32imm:$reg0, i32imm:$reg1, i32imm:$offs), []>, Sched<[]>;
56395641
def SEH_AllocZ : Pseudo<(outs), (ins i32imm:$offs), []>, Sched<[]>;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
; RUN: llc -mtriple aarch64-unknown-windows-msvc -filetype asm -o - %s | FileCheck %s
2+
3+
declare dso_local void @g(ptr noundef)
4+
define dso_local preserve_mostcc void @f(ptr noundef %p) #0 {
5+
entry:
6+
%p.addr = alloca ptr, align 8
7+
store ptr %p, ptr %p.addr, align 8
8+
%0 = load ptr, ptr %p.addr, align 8
9+
call void @g(ptr noundef %0)
10+
ret void
11+
}
12+
13+
attributes #0 = { nounwind uwtable(sync) }
14+
15+
; CHECK: stp x9, x10, [sp, #[[OFFSET_0:[0-9]+]]]
16+
; CHECK-NEXT: .seh_save_any_reg_p x9, [[OFFSET_0]]
17+
; CHECK: stp x11, x12, [sp, #[[OFFSET_1:[0-9]+]]]
18+
; CHECK-NEXT: .seh_save_any_reg_p x11, [[OFFSET_1]]
19+
; CHECK: stp x13, x14, [sp, #[[OFFSET_2:[0-9]+]]]
20+
; CHECK-NEXT: .seh_save_any_reg_p x13, [[OFFSET_2]]
21+
; CHECK: str x15, [sp, #[[OFFSET_3:[0-9]+]]]
22+
; CHECK-NEXT: .seh_save_any_reg x15, [[OFFSET_3]]
23+
; CHECK: .seh_endprologue
24+
25+
; CHECK: .seh_startepilogue
26+
; CHECK: ldr x15, [sp, #[[OFFSET_3]]]
27+
; CHECK-NEXT: .seh_save_any_reg x15, [[OFFSET_3]]
28+
; CHECK: ldp x13, x14, [sp, #[[OFFSET_2]]]
29+
; CHECK-NEXT: .seh_save_any_reg_p x13, [[OFFSET_2]]
30+
; CHECK: ldp x11, x12, [sp, #[[OFFSET_1]]]
31+
; CHECK-NEXT: .seh_save_any_reg_p x11, [[OFFSET_1]]
32+
; CHECK: ldp x9, x10, [sp, #[[OFFSET_0]]]
33+
; CHECK-NEXT: .seh_save_any_reg_p x9, [[OFFSET_0]]
34+
; CHECK: .seh_endepilogue

0 commit comments

Comments
 (0)