Skip to content

Commit 1f05703

Browse files
pestctrljakevossen5evodius96
committed
[ARM][Thumb] Save FPSCR + FPEXC for save-vfp attribute
FPSCR and FPEXC will be stored in FPStatusRegs, after GPRCS2 has been saved. - GPRCS1 - GPRCS2 - FPStatusRegs (new) - DPRCS - GPRCS3 - DPRCS2 FPSCR is present on all targets with a VFP, but the FPEXC register is not present on Cortex-M devices, so different amounts of bytes are being pushed onto the stack depending on our target, which would affect alignment for subsequent saves. DPRCS1 will sum up all previous bytes that were saved, and will emit extra instructions to ensure that its alignment is correct. My assumption is that if DPRCS1 is able to correct its alignment to be correct, then all subsequent saves will also have correct alignment. Avoid annotating the saving of FPSCR and FPEXC for functions marked with the interrupt_save_fp attribute, even though this is done as part of frame setup. Since these are status registers, there really is no viable way of annotating this. Since these aren't GPRs or DPRs, they can't be used with .save or .vsave directives. Instead, just record that the intermediate registers r4 and r5 are saved to the stack again. Co-authored-by: Jake Vossen <[email protected]> Co-authored-by: Alan Phipps <[email protected]>
1 parent 83936f5 commit 1f05703

21 files changed

+1036
-29
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -994,6 +994,22 @@ def ARMInterrupt : InheritableAttr, TargetSpecificAttr<TargetARM> {
994994
let Documentation = [ARMInterruptDocs];
995995
}
996996

997+
def ARMInterruptSaveFP : InheritableAttr, TargetSpecificAttr<TargetARM> {
998+
let Spellings = [GNU<"interrupt_save_fp">];
999+
let Args = [EnumArgument<"Interrupt", "InterruptType", /*is_string=*/true,
1000+
["IRQ", "FIQ", "SWI", "ABORT", "UNDEF", ""],
1001+
["IRQ", "FIQ", "SWI", "ABORT", "UNDEF", "Generic"],
1002+
1>];
1003+
let HasCustomParsing = 0;
1004+
let Documentation = [ARMInterruptSaveFPDocs];
1005+
}
1006+
1007+
def ARMSaveFP : InheritableAttr, TargetSpecificAttr<TargetARM> {
1008+
let Spellings = [];
1009+
let Subjects = SubjectList<[Function]>;
1010+
let Documentation = [InternalOnly];
1011+
}
1012+
9971013
def AVRInterrupt : InheritableAttr, TargetSpecificAttr<TargetAVR> {
9981014
let Spellings = [GCC<"interrupt">];
9991015
let Subjects = SubjectList<[Function]>;

clang/include/clang/Basic/AttrDocs.td

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2662,6 +2662,19 @@ The semantics are as follows:
26622662
}];
26632663
}
26642664

2665+
def ARMInterruptSaveFPDocs : Documentation {
2666+
let Category = DocCatFunction;
2667+
let Heading = "interrupt_save_fp (ARM)";
2668+
let Content = [{
2669+
Clang supports the GNU style ``__attribute__((interrupt_save_fp("TYPE")))``
2670+
on ARM targets. This attribute behaves the same way as the ARM interrupt
2671+
attribute, except the general purpose floating point registers are also saved,
2672+
along with FPEXC and FPSCR. Note, even on M-class CPUs, where the floating
2673+
point context can be automatically saved depending on the FPCCR, the general
2674+
purpose floating point registers will be saved.
2675+
}];
2676+
}
2677+
26652678
def BPFPreserveAccessIndexDocs : Documentation {
26662679
let Category = DocCatFunction;
26672680
let Content = [{

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,8 +346,14 @@ def warn_anyx86_excessive_regsave : Warning<
346346
InGroup<DiagGroup<"excessive-regsave">>;
347347
def warn_arm_interrupt_vfp_clobber : Warning<
348348
"interrupt service routine with vfp enabled may clobber the "
349-
"interruptee's vfp state">,
349+
"interruptee's vfp state; "
350+
"consider using the `interrupt_save_fp` attribute to prevent this behavior">,
350351
InGroup<DiagGroup<"arm-interrupt-vfp-clobber">>;
352+
def warn_arm_interrupt_save_fp_without_vfp_unit : Warning<
353+
"`interrupt_save_fp` only applies to targets that have a VFP unit enabled "
354+
"for this compilation; this will be treated as a regular `interrupt` "
355+
"attribute">,
356+
InGroup<DiagGroup<"arm-interrupt-vfp-clobber">>;
351357
def err_arm_interrupt_called : Error<
352358
"interrupt service routine cannot be called directly">;
353359
def warn_interrupt_signal_attribute_invalid : Warning<

clang/lib/CodeGen/Targets/ARM.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,12 @@ class ARMTargetCodeGenInfo : public TargetCodeGenInfo {
190190

191191
Fn->addFnAttr("interrupt", Kind);
192192

193+
// Note: the ARMSaveFPAttr can only exist if we also have an interrupt
194+
// attribute
195+
const ARMSaveFPAttr *SaveFPAttr = FD->getAttr<ARMSaveFPAttr>();
196+
if (SaveFPAttr)
197+
Fn->addFnAttr("save-fp");
198+
193199
ARMABIKind ABI = getABIInfo<ARMABIInfo>().getABIKind();
194200
if (ABI == ARMABIKind::APCS)
195201
return;

clang/lib/Sema/SemaARM.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1307,9 +1307,11 @@ void SemaARM::handleInterruptAttr(Decl *D, const ParsedAttr &AL) {
13071307
return;
13081308
}
13091309

1310-
const TargetInfo &TI = getASTContext().getTargetInfo();
1311-
if (TI.hasFeature("vfp"))
1312-
Diag(D->getLocation(), diag::warn_arm_interrupt_vfp_clobber);
1310+
if (!D->hasAttr<ARMSaveFPAttr>()) {
1311+
const TargetInfo &TI = getASTContext().getTargetInfo();
1312+
if (TI.hasFeature("vfp"))
1313+
Diag(D->getLocation(), diag::warn_arm_interrupt_vfp_clobber);
1314+
}
13131315

13141316
D->addAttr(::new (getASTContext())
13151317
ARMInterruptAttr(getASTContext(), AL, Kind));

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5993,6 +5993,20 @@ static void handleAbiTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
59935993
AbiTagAttr(S.Context, AL, Tags.data(), Tags.size()));
59945994
}
59955995

5996+
static void handleARMInterruptSaveFPAttr(Sema &S, Decl *D,
5997+
const ParsedAttr &AL) {
5998+
handleARMInterruptAttr(S, D, AL);
5999+
6000+
bool VFP = S.Context.getTargetInfo().hasFeature("vfp");
6001+
6002+
if (!VFP) {
6003+
S.Diag(D->getLocation(), diag::warn_arm_interrupt_save_fp_without_vfp_unit);
6004+
return;
6005+
}
6006+
6007+
D->addAttr(::new (S.Context) ARMSaveFPAttr(S.Context, AL));
6008+
}
6009+
59966010
static bool hasBTFDeclTagAttr(Decl *D, StringRef Tag) {
59976011
for (const auto *I : D->specific_attrs<BTFDeclTagAttr>()) {
59986012
if (I->getBTFDeclTag() == Tag)
@@ -6897,6 +6911,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
68976911
case ParsedAttr::AT_Interrupt:
68986912
handleInterruptAttr(S, D, AL);
68996913
break;
6914+
case ParsedAttr::AT_ARMInterruptSaveFP:
6915+
handleARMInterruptSaveFPAttr(S, D, AL);
6916+
break;
69006917
case ParsedAttr::AT_X86ForceAlignArgPointer:
69016918
S.X86().handleForceAlignArgPointerAttr(D, AL);
69026919
break;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// REQUIRES: arm-registered-target
2+
// RUN: %clang -target arm-none-none-eabihf -mcpu=cortex-r5 -mfpu=vfpv3-d16 -marm -S -o - %s \
3+
// RUN: | FileCheck %s --check-prefix=CHECK-R
4+
// RUN: %clang -target arm-none-none-eabihf -mcpu=cortex-r5 -mfpu=vfpv3-d16 -mthumb -S -o - %s \
5+
// RUN: | FileCheck %s --check-prefix=CHECK-R
6+
// RUN: %clang -target arm-none-none-eabihf -mcpu=cortex-r4 -mfpu=vfpv3-d16 -marm -S -o - %s \
7+
// RUN: | FileCheck %s --check-prefix=CHECK-R
8+
// RUN: %clang -target arm-none-none-eabihf -mcpu=cortex-r4 -mfpu=vfpv3-d16 -mthumb -S -o - %s \
9+
// RUN: | FileCheck %s --check-prefix=CHECK-R
10+
// RUN: %clang -target arm-none-none-eabihf -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -S -o - %s \
11+
// RUN: | FileCheck %s --check-prefix=CHECK-M
12+
// RUN: %clang -target arm-none-none-eabihf -mcpu=cortex-m33 -mfpu=fpv5-sp-d16 -S -o - %s \
13+
// RUN: | FileCheck %s --check-prefix=CHECK-M
14+
15+
void bar();
16+
17+
__attribute__((interrupt_save_fp)) void test_generic_interrupt() {
18+
// CHECK-R: vmrs r4, fpscr
19+
// CHECK-R-NEXT: vmrs r5, fpexc
20+
// CHECK-R-NEXT: .save {r4, r5}
21+
// CHECK-R-NEXT: push {r4, r5}
22+
// .....
23+
// CHECK-R: pop {r4, r5}
24+
// CHECK-R-NEXT: vmsr fpscr, r4
25+
// CHECK-R-NEXT: vmsr fpexc, r5
26+
27+
// CHECK-M: vmrs r4, fpscr
28+
// CHECK-M-NEXT: .save {r4}
29+
// CHECK-M-NEXT: push {r4}
30+
// .....
31+
// CHECK-M: pop {r4}
32+
// CHECK-M-NEXT: vmsr fpscr, r4
33+
bar();
34+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// RUN: %clang_cc1 -triple thumb-apple-darwin -target-abi aapcs -target-feature +vfp4 -target-cpu cortex-m3 -emit-llvm -o - %s | FileCheck %s
2+
// RUN: %clang_cc1 -triple arm-apple-darwin -target-abi apcs-gnu -target-feature +vfp4 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-APCS
3+
4+
__attribute__((interrupt_save_fp)) void test_generic_interrupt() {
5+
// CHECK: define{{.*}} arm_aapcscc void @test_generic_interrupt() [[GENERIC_ATTR:#[0-9]+]]
6+
7+
// CHECK-APCS: define{{.*}} void @test_generic_interrupt() [[GENERIC_ATTR:#[0-9]+]]
8+
}
9+
10+
__attribute__((interrupt_save_fp("IRQ"))) void test_irq_interrupt() {
11+
// CHECK: define{{.*}} arm_aapcscc void @test_irq_interrupt() [[IRQ_ATTR:#[0-9]+]]
12+
}
13+
14+
__attribute__((interrupt_save_fp("FIQ"))) void test_fiq_interrupt() {
15+
// CHECK: define{{.*}} arm_aapcscc void @test_fiq_interrupt() [[FIQ_ATTR:#[0-9]+]]
16+
}
17+
18+
__attribute__((interrupt_save_fp("SWI"))) void test_swi_interrupt() {
19+
// CHECK: define{{.*}} arm_aapcscc void @test_swi_interrupt() [[SWI_ATTR:#[0-9]+]]
20+
}
21+
22+
__attribute__((interrupt_save_fp("ABORT"))) void test_abort_interrupt() {
23+
// CHECK: define{{.*}} arm_aapcscc void @test_abort_interrupt() [[ABORT_ATTR:#[0-9]+]]
24+
}
25+
26+
27+
__attribute__((interrupt_save_fp("UNDEF"))) void test_undef_interrupt() {
28+
// CHECK: define{{.*}} arm_aapcscc void @test_undef_interrupt() [[UNDEF_ATTR:#[0-9]+]]
29+
}
30+
31+
32+
// CHECK: attributes [[GENERIC_ATTR]] = { {{.*}} {{"interrupt"[^=]}}{{.*}} "save-fp"
33+
// CHECK: attributes [[IRQ_ATTR]] = { {{.*}} "interrupt"="IRQ" {{.*}} "save-fp"
34+
// CHECK: attributes [[FIQ_ATTR]] = { {{.*}} "interrupt"="FIQ" {{.*}} "save-fp"
35+
// CHECK: attributes [[SWI_ATTR]] = { {{.*}} "interrupt"="SWI" {{.*}} "save-fp"
36+
// CHECK: attributes [[ABORT_ATTR]] = { {{.*}} "interrupt"="ABORT" {{.*}} "save-fp"
37+
// CHECK: attributes [[UNDEF_ATTR]] = { {{.*}} "interrupt"="UNDEF" {{.*}} "save-fp"
38+
39+
// CHECK-APCS: attributes [[GENERIC_ATTR]] = { {{.*}} "interrupt" {{.*}} "save-fp"

clang/test/Sema/arm-interrupt-attr.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44

55
#ifdef __ARM_FP
6-
__attribute__((interrupt("IRQ"))) void float_irq(void); // expected-warning {{interrupt service routine with vfp enabled may clobber the interruptee's vfp state}}
6+
__attribute__((interrupt("IRQ"))) void float_irq(void); // expected-warning {{interrupt service routine with vfp enabled may clobber the interruptee's vfp state; consider using the `interrupt_save_fp` attribute to prevent this behavior}}
77
#else // !defined(__ARM_FP)
88
__attribute__((interrupt("irq"))) void foo1(void) {} // expected-warning {{'interrupt' attribute argument not supported: irq}}
99
__attribute__((interrupt(IRQ))) void foo(void) {} // expected-error {{'interrupt' attribute requires a string}}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// RUN: %clang_cc1 %s -triple arm-apple-darwin -target-feature +vfp2 -verify -fsyntax-only
2+
// RUN: %clang_cc1 %s -triple thumb-apple-darwin -target-feature +vfp3 -verify -fsyntax-only
3+
// RUN: %clang_cc1 %s -triple armeb-none-eabi -target-feature +vfp4 -verify -fsyntax-only
4+
// RUN: %clang_cc1 %s -triple thumbeb-none-eabi -target-feature +neon -verify -fsyntax-only
5+
// RUN: %clang_cc1 %s -triple thumbeb-none-eabi -target-feature +neon -target-feature +soft-float -DSOFT -verify -fsyntax-only
6+
7+
#ifndef SOFT
8+
__attribute__((interrupt_save_fp(IRQ))) void foo() {} // expected-error {{'interrupt_save_fp' attribute requires a string}}
9+
__attribute__((interrupt_save_fp("irq"))) void foo1() {} // expected-warning {{'interrupt_save_fp' attribute argument not supported: irq}}
10+
11+
__attribute__((interrupt_save_fp("IRQ", 1))) void foo2() {} // expected-error {{'interrupt_save_fp' attribute takes no more than 1 argument}}
12+
__attribute__((interrupt_save_fp("IRQ"))) void foo3() {}
13+
__attribute__((interrupt_save_fp("FIQ"))) void foo4() {}
14+
__attribute__((interrupt_save_fp("SWI"))) void foo5() {}
15+
__attribute__((interrupt_save_fp("ABORT"))) void foo6() {}
16+
__attribute__((interrupt_save_fp("UNDEF"))) void foo7() {}
17+
__attribute__((interrupt_save_fp)) void foo8() {}
18+
__attribute__((interrupt_save_fp())) void foo9() {}
19+
__attribute__((interrupt_save_fp(""))) void foo10() {}
20+
void callee1();
21+
__attribute__((interrupt_save_fp("IRQ"))) void callee2();
22+
void caller1() {
23+
callee1();
24+
callee2();
25+
}
26+
__attribute__((interrupt_save_fp("IRQ"))) void caller2() {
27+
callee1();
28+
callee2();
29+
}
30+
31+
void (*callee3)();
32+
__attribute__((interrupt_save_fp("IRQ"))) void caller3() {
33+
callee3();
34+
}
35+
#else
36+
__attribute__((interrupt_save_fp("IRQ"))) void foo3() {} // expected-warning {{`interrupt_save_fp` only applies to targets that have a VFP unit enabled for this compilation; this will be treated as a regular `interrupt` attribute}}
37+
__attribute__((interrupt_save_fp("FIQ"))) void foo4() {} // expected-warning {{`interrupt_save_fp` only applies to targets that have a VFP unit enabled for this compilation; this will be treated as a regular `interrupt` attribute}}
38+
__attribute__((interrupt_save_fp("SWI"))) void foo5() {} // expected-warning {{`interrupt_save_fp` only applies to targets that have a VFP unit enabled for this compilation; this will be treated as a regular `interrupt` attribute}}
39+
__attribute__((interrupt_save_fp("ABORT"))) void foo6() {} // expected-warning {{`interrupt_save_fp` only applies to targets that have a VFP unit enabled for this compilation; this will be treated as a regular `interrupt` attribute}}
40+
__attribute__((interrupt_save_fp("UNDEF"))) void foo7() {} // expected-warning {{`interrupt_save_fp` only applies to targets that have a VFP unit enabled for this compilation; this will be treated as a regular `interrupt` attribute}}
41+
__attribute__((interrupt_save_fp)) void foo8() {} // expected-warning {{`interrupt_save_fp` only applies to targets that have a VFP unit enabled for this compilation; this will be treated as a regular `interrupt` attribute}}
42+
__attribute__((interrupt_save_fp())) void foo9() {} // expected-warning {{`interrupt_save_fp` only applies to targets that have a VFP unit enabled for this compilation; this will be treated as a regular `interrupt` attribute}}
43+
__attribute__((interrupt_save_fp(""))) void foo10() {} // expected-warning {{`interrupt_save_fp` only applies to targets that have a VFP unit enabled for this compilation; this will be treated as a regular `interrupt` attribute}}
44+
void callee1();
45+
__attribute__((interrupt_save_fp("IRQ"))) void callee2(); // expected-warning {{`interrupt_save_fp` only applies to targets that have a VFP unit enabled for this compilation; this will be treated as a regular `interrupt` attribute}}
46+
void caller1() {
47+
callee1();
48+
callee2();
49+
}
50+
__attribute__((interrupt_save_fp("IRQ"))) void caller2() { // expected-warning {{`interrupt_save_fp` only applies to targets that have a VFP unit enabled for this compilation; this will be treated as a regular `interrupt` attribute}}
51+
callee1();
52+
callee2();
53+
}
54+
55+
void (*callee3)();
56+
__attribute__((interrupt_save_fp("IRQ"))) void caller3() { // expected-warning {{`interrupt_save_fp` only applies to targets that have a VFP unit enabled for this compilation; this will be treated as a regular `interrupt` attribute}}
57+
callee3();
58+
}
59+
#endif

llvm/include/llvm/IR/IntrinsicsARM.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ def int_arm_isb : ClangBuiltin<"__builtin_arm_isb">, MSBuiltin<"__isb">,
311311
// VFP
312312

313313
def int_arm_get_fpscr : ClangBuiltin<"__builtin_arm_get_fpscr">,
314-
DefaultAttrsIntrinsic<[llvm_i32_ty], [], []>;
314+
DefaultAttrsIntrinsic<[llvm_i32_ty], [], [IntrReadMem]>;
315315
def int_arm_set_fpscr : ClangBuiltin<"__builtin_arm_set_fpscr">,
316316
DefaultAttrsIntrinsic<[], [llvm_i32_ty], []>;
317317
def int_arm_vcvtr : DefaultAttrsIntrinsic<[llvm_float_ty],

llvm/lib/Target/ARM/ARMAsmPrinter.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1207,6 +1207,14 @@ void ARMAsmPrinter::EmitUnwindingInstruction(const MachineInstr *MI) {
12071207
SrcReg = ~0U;
12081208
DstReg = MI->getOperand(0).getReg();
12091209
break;
1210+
case ARM::VMRS:
1211+
SrcReg = ARM::FPSCR;
1212+
DstReg = MI->getOperand(0).getReg();
1213+
break;
1214+
case ARM::VMRS_FPEXC:
1215+
SrcReg = ARM::FPEXC;
1216+
DstReg = MI->getOperand(0).getReg();
1217+
break;
12101218
default:
12111219
SrcReg = MI->getOperand(1).getReg();
12121220
DstReg = MI->getOperand(0).getReg();
@@ -1373,6 +1381,14 @@ void ARMAsmPrinter::EmitUnwindingInstruction(const MachineInstr *MI) {
13731381
// correct ".save" later.
13741382
AFI->EHPrologueRemappedRegs[DstReg] = SrcReg;
13751383
break;
1384+
case ARM::VMRS:
1385+
case ARM::VMRS_FPEXC:
1386+
// If a function spills FPSCR or FPEXC, we copy the values to low
1387+
// registers before pushing them. However, we can't issue annotations
1388+
// for FP status registers because ".save" requires GPR registers, and
1389+
// ".vsave" requires DPR registers, so don't record the copy and simply
1390+
// emit annotations for the source registers used for the store.
1391+
break;
13761392
case ARM::tLDRpci: {
13771393
// Grab the constpool index and check, whether it corresponds to
13781394
// original or cloned constpool entry.

llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,47 @@ ARMBaseRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
8080
? CSR_ATPCS_SplitPush_SwiftTail_SaveList
8181
: CSR_AAPCS_SwiftTail_SaveList);
8282
} else if (F.hasFnAttribute("interrupt")) {
83+
84+
// Don't bother saving the floating point registers if target is not hard
85+
// float. This will prevent the Thumb1FrameLowering (cortex-m0) from
86+
// crashing due to an llvm_unreachable being triggered when a D-class
87+
// register is in the calling convention.
88+
if (STI.isTargetHardFloat() && F.hasFnAttribute("save-fp")) {
89+
bool HasNEON = STI.hasNEON();
90+
91+
if (STI.isMClass()) {
92+
assert(!HasNEON && "NEON is only for Cortex-R/A");
93+
return UseSplitPush ? CSR_ATPCS_SplitPush_FP_SaveList
94+
: CSR_AAPCS_FP_SaveList;
95+
}
96+
if (F.getFnAttribute("interrupt").getValueAsString() == "FIQ") {
97+
return HasNEON ? CSR_FIQ_FP_NEON_SaveList : CSR_FIQ_FP_SaveList;
98+
}
99+
return HasNEON ? CSR_GenericInt_FP_NEON_SaveList
100+
: CSR_GenericInt_FP_SaveList;
101+
}
102+
83103
if (STI.isMClass()) {
84104
// M-class CPUs have hardware which saves the registers needed to allow a
85105
// function conforming to the AAPCS to function as a handler.
86-
return PushPopSplit == ARMSubtarget::SplitR7
87-
? CSR_ATPCS_SplitPush_SaveList
88-
: CSR_AAPCS_SaveList;
89-
} else if (F.getFnAttribute("interrupt").getValueAsString() == "FIQ") {
106+
// Additionally, M Class has hardware support for saving VFP registers,
107+
// but the option can be disabled
108+
if (SaveFP) {
109+
if (HasNEON) {
110+
return UseSplitPush ? CSR_AAPCS_SplitPush_FP_NEON_SaveList
111+
: CSR_AAPCS_FP_NEON_SaveList;
112+
} else {
113+
return UseSplitPush ? CSR_AAPCS_SplitPush_FP_SaveList
114+
: CSR_AAPCS_FP_SaveList;
115+
}
116+
} else {
117+
return PushPopSplit == ARMSubtarget::SplitR7
118+
? CSR_ATPCS_SplitPush_SaveList
119+
: CSR_AAPCS_SaveList;
120+
}
121+
}
122+
123+
if (F.getFnAttribute("interrupt").getValueAsString() == "FIQ") {
90124
// Fast interrupt mode gives the handler a private copy of R8-R14, so less
91125
// need to be saved to restore user-mode state.
92126
return CSR_FIQ_SaveList;

0 commit comments

Comments
 (0)