Skip to content

Commit 98d114b

Browse files
committed
AArch64: support extended spills in SEH on WoS
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.
1 parent ecddaae commit 98d114b

File tree

6 files changed

+67
-7
lines changed

6 files changed

+67
-7
lines changed

llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp

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

3367+
case AArch64::SEH_SaveAnyRegI:
3368+
assert(MI->getOperand(1).getImm() <= 1008 &&
3369+
"SaveAnyRegQP SEH opcode offset must fit into 6 bits");
3370+
TS->emitARM64WinCFISaveAnyRegI(MI->getOperand(0).getImm(),
3371+
MI->getOperand(1).getImm());
3372+
return;
3373+
3374+
case AArch64::SEH_SaveAnyRegIP:
3375+
assert(MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1 &&
3376+
"Non-consecutive registers not allowed for save_any_reg");
3377+
assert(MI->getOperand(2).getImm() <= 1008 &&
3378+
"SaveAnyRegQP SEH opcode offset must fit into 6 bits");
3379+
TS->emitARM64WinCFISaveAnyRegIP(MI->getOperand(0).getImm(),
3380+
MI->getOperand(2).getImm());
3381+
return;
3382+
33673383
case AArch64::SEH_SaveAnyRegQP:
33683384
assert(MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1 &&
33693385
"Non-consecutive registers not allowed for save_any_reg");

llvm/lib/Target/AArch64/AArch64FrameLowering.cpp

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1082,25 +1082,41 @@ AArch64FrameLowering::insertSEH(MachineBasicBlock::iterator MBBI,
10821082
case AArch64::LDPXi: {
10831083
Register Reg0 = MBBI->getOperand(0).getReg();
10841084
Register Reg1 = MBBI->getOperand(1).getReg();
1085+
1086+
int SEHReg0 = RegInfo->getSEHRegNum(Reg0);
1087+
int SEHReg1 = RegInfo->getSEHRegNum(Reg1);
1088+
10851089
if (Reg0 == AArch64::FP && Reg1 == AArch64::LR)
10861090
MIB = BuildMI(MF, DL, TII.get(AArch64::SEH_SaveFPLR))
10871091
.addImm(Imm * 8)
10881092
.setMIFlag(Flag);
1089-
else
1093+
else if (SEHReg0 >= 19 && SEHReg1 >= 19)
10901094
MIB = BuildMI(MF, DL, TII.get(AArch64::SEH_SaveRegP))
1091-
.addImm(RegInfo->getSEHRegNum(Reg0))
1092-
.addImm(RegInfo->getSEHRegNum(Reg1))
1095+
.addImm(SEHReg0)
1096+
.addImm(SEHReg1)
1097+
.addImm(Imm * 8)
1098+
.setMIFlag(Flag);
1099+
else
1100+
MIB = BuildMI(MF, DL, TII.get(AArch64::SEH_SaveAnyRegIP))
1101+
.addImm(SEHReg0)
1102+
.addImm(SEHReg1)
10931103
.addImm(Imm * 8)
10941104
.setMIFlag(Flag);
10951105
break;
10961106
}
10971107
case AArch64::STRXui:
10981108
case AArch64::LDRXui: {
10991109
int Reg = RegInfo->getSEHRegNum(MBBI->getOperand(0).getReg());
1100-
MIB = BuildMI(MF, DL, TII.get(AArch64::SEH_SaveReg))
1101-
.addImm(Reg)
1102-
.addImm(Imm * 8)
1103-
.setMIFlag(Flag);
1110+
if (Reg >= 19)
1111+
MIB = BuildMI(MF, DL, TII.get(AArch64::SEH_SaveReg))
1112+
.addImm(Reg)
1113+
.addImm(Imm * 8)
1114+
.setMIFlag(Flag);
1115+
else
1116+
MIB = BuildMI(MF, DL, TII.get(AArch64::SEH_SaveAnyRegI))
1117+
.addImm(Reg)
1118+
.addImm(Imm * 8)
1119+
.setMIFlag(Flag);
11041120
break;
11051121
}
11061122
case AArch64::STRDui:

llvm/lib/Target/AArch64/AArch64InstrInfo.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1217,6 +1217,8 @@ bool AArch64InstrInfo::isSEHInstruction(const MachineInstr &MI) {
12171217
case AArch64::SEH_EpilogStart:
12181218
case AArch64::SEH_EpilogEnd:
12191219
case AArch64::SEH_PACSignLR:
1220+
case AArch64::SEH_SaveAnyRegI:
1221+
case AArch64::SEH_SaveAnyRegIP:
12201222
case AArch64::SEH_SaveAnyRegQP:
12211223
case AArch64::SEH_SaveAnyRegQPX:
12221224
case AArch64::SEH_AllocZ:

llvm/lib/Target/AArch64/AArch64InstrInfo.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5666,6 +5666,8 @@ let isPseudo = 1 in {
56665666
def SEH_EpilogStart : Pseudo<(outs), (ins), []>, Sched<[]>;
56675667
def SEH_EpilogEnd : Pseudo<(outs), (ins), []>, Sched<[]>;
56685668
def SEH_PACSignLR : Pseudo<(outs), (ins), []>, Sched<[]>;
5669+
def SEH_SaveAnyRegI : Pseudo<(outs), (ins i32imm:$reg0, i32imm:$offs), []>, Sched<[]>;
5670+
def SEH_SaveAnyRegIP : Pseudo<(outs), (ins i32imm:$reg0, i32imm:$reg1, i32imm:$offs), []>, Sched<[]>;
56695671
def SEH_SaveAnyRegQP : Pseudo<(outs), (ins i32imm:$reg0, i32imm:$reg1, i32imm:$offs), []>, Sched<[]>;
56705672
def SEH_SaveAnyRegQPX : Pseudo<(outs), (ins i32imm:$reg0, i32imm:$reg1, i32imm:$offs), []>, Sched<[]>;
56715673
def SEH_AllocZ : Pseudo<(outs), (ins i32imm:$offs), []>, Sched<[]>;

llvm/lib/Target/AArch64/AArch64PrologueEpilogue.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,8 @@ static void fixupSEHOpcode(MachineBasicBlock::iterator MBBI,
253253
case AArch64::SEH_SaveReg:
254254
case AArch64::SEH_SaveFRegP:
255255
case AArch64::SEH_SaveFReg:
256+
case AArch64::SEH_SaveAnyRegI:
257+
case AArch64::SEH_SaveAnyRegIP:
256258
case AArch64::SEH_SaveAnyRegQP:
257259
case AArch64::SEH_SaveAnyRegQPX:
258260
ImmOpnd = &MBBI->getOperand(ImmIdx);
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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]]

0 commit comments

Comments
 (0)