Skip to content

Commit a935c45

Browse files
jakevossen5Benson Chu
authored andcommitted
[ARM] Save floating point registers with save_fp function attribute
[ARM] and interrupt_save_fp attribute interupt_save_fp update name; fix bugs [ARM] fix typos and register class name used better push / pop instructions change epilog emitting order WIP with FPSCR save just d regs cleaned up docs and ARMRegisterInfo td change m3 to m4 fix reg tests Minor format changes on top of Jake Vossen's support for interrupt_save_fp function attribute which preserves VFP D registers at the moment. FPSCR and FPEXC registers to follow.
1 parent 4a92c27 commit a935c45

File tree

13 files changed

+369
-10
lines changed

13 files changed

+369
-10
lines changed

clang/include/clang/Basic/Attr.td

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

987+
def ARMInterruptSaveFP : InheritableAttr, TargetSpecificAttr<TargetARM> {
988+
let Spellings = [GNU<"interrupt_save_fp">];
989+
let Args = [EnumArgument<"Interrupt", "InterruptType", /*is_string=*/true,
990+
["IRQ", "FIQ", "SWI", "ABORT", "UNDEF", ""],
991+
["IRQ", "FIQ", "SWI", "ABORT", "UNDEF", "Generic"],
992+
1>];
993+
let HasCustomParsing = 0;
994+
let Documentation = [ARMInterruptSaveFPDocs];
995+
}
996+
997+
def ARMSaveFP : InheritableAttr, TargetSpecificAttr<TargetARM> {
998+
let Spellings = [];
999+
let Subjects = SubjectList<[Function]>;
1000+
let Documentation = [InternalOnly];
1001+
}
1002+
9871003
def AVRInterrupt : InheritableAttr, TargetSpecificAttr<TargetAVR> {
9881004
let Spellings = [GCC<"interrupt">];
9891005
let Subjects = SubjectList<[Function]>;

clang/include/clang/Basic/AttrDocs.td

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2484,6 +2484,20 @@ The semantics are as follows:
24842484
}];
24852485
}
24862486

2487+
def ARMInterruptSaveFPDocs : Documentation {
2488+
let Category = DocCatFunction;
2489+
let Heading = "interrupt_save_fp (ARM)";
2490+
let Content = [{
2491+
Clang supports the GNU style ``__attribute__((interrupt_save_fp("TYPE")))``
2492+
on ARM targets. This attribute behaves the same way as the ARM interrupt
2493+
attribute, except the general purpose floating point registers are also saved.
2494+
If the FPEXC or FPSCR are needed, that state must be saved manually. Note, even
2495+
on M-class CPUs, where the floating point context can be automatically saved
2496+
depending on the FPCCR, the general purpose floating point registers will be
2497+
saved.
2498+
}];
2499+
}
2500+
24872501
def BPFPreserveAccessIndexDocs : Documentation {
24882502
let Category = DocCatFunction;
24892503
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-save-fp-no-vfp-unit">>;
351357
def err_arm_interrupt_called : Error<
352358
"interrupt service routine cannot be called directly">;
353359
def warn_interrupt_attribute_invalid : Warning<

clang/include/clang/Sema/SemaARM.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ class SemaARM : public SemaBase {
7979
void handleNewAttr(Decl *D, const ParsedAttr &AL);
8080
void handleCmseNSEntryAttr(Decl *D, const ParsedAttr &AL);
8181
void handleInterruptAttr(Decl *D, const ParsedAttr &AL);
82+
void handleInterruptSaveFPAttr(Decl *D, const ParsedAttr &AL);
8283
};
8384

8485
SemaARM::ArmStreamingType getArmStreamingFnType(const FunctionDecl *FD);

clang/lib/CodeGen/Targets/ARM.cpp

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

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

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

clang/lib/Sema/SemaARM.cpp

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1320,12 +1320,37 @@ void SemaARM::handleInterruptAttr(Decl *D, const ParsedAttr &AL) {
13201320
return;
13211321
}
13221322

1323-
const TargetInfo &TI = getASTContext().getTargetInfo();
1324-
if (TI.hasFeature("vfp"))
1325-
Diag(D->getLocation(), diag::warn_arm_interrupt_vfp_clobber);
1323+
if (!D->hasAttr<ARMSaveFPAttr>()) {
1324+
const TargetInfo &TI = getASTContext().getTargetInfo();
1325+
if (TI.hasFeature("vfp"))
1326+
Diag(D->getLocation(), diag::warn_arm_interrupt_vfp_clobber);
1327+
}
13261328

13271329
D->addAttr(::new (getASTContext())
13281330
ARMInterruptAttr(getASTContext(), AL, Kind));
13291331
}
13301332

1333+
void SemaARM::handleInterruptSaveFPAttr(Decl *D, const ParsedAttr &AL) {
1334+
// Go ahead and add ARMSaveFPAttr because handleInterruptAttr() checks for
1335+
// it when deciding to issue a diagnostic about clobbering floating point
1336+
// registers, which ARMSaveFPAttr prevents.
1337+
D->addAttr(::new (SemaRef.Context) ARMSaveFPAttr(SemaRef.Context, AL));
1338+
SemaRef.ARM().handleInterruptAttr(D, AL);
1339+
1340+
// If ARM().handleInterruptAttr() failed, remove ARMSaveFPAttr.
1341+
if (!D->hasAttr<ARMInterruptAttr>()) {
1342+
D->dropAttr<ARMSaveFPAttr>();
1343+
return;
1344+
}
1345+
1346+
// If VFP not enabled, remove ARMSaveFPAttr but leave ARMInterruptAttr.
1347+
bool VFP = SemaRef.Context.getTargetInfo().hasFeature("vfp");
1348+
1349+
if (!VFP) {
1350+
SemaRef.Diag(D->getLocation(), diag::warn_arm_interrupt_save_fp_without_vfp_unit);
1351+
D->dropAttr<ARMSaveFPAttr>();
1352+
return;
1353+
}
1354+
}
1355+
13311356
} // namespace clang

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6645,6 +6645,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
66456645
case ParsedAttr::AT_Interrupt:
66466646
handleInterruptAttr(S, D, AL);
66476647
break;
6648+
case ParsedAttr::AT_ARMInterruptSaveFP:
6649+
S.ARM().handleInterruptSaveFPAttr(D, AL);
6650+
break;
66486651
case ParsedAttr::AT_X86ForceAlignArgPointer:
66496652
S.X86().handleForceAlignArgPointerAttr(D, AL);
66506653
break;
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: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: %clang_cc1 %s -triple arm-none-eabi -verify -fsyntax-only
2+
// RUN: %clang_cc1 %s -triple arm-none-eabi -target-feature +vfp2 -verify -fsyntax-only
3+
4+
5+
#if !defined(__ARM_FP)
6+
__attribute__((interrupt_save_fp("IRQ"))) void float_irq(void); // 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}}
7+
#else // defined(__ARM_FP)
8+
__attribute__((interrupt_save_fp("irq"))) void foo1(void) {} // expected-warning {{'interrupt_save_fp' attribute argument not supported: irq}}
9+
__attribute__((interrupt_save_fp(IRQ))) void foo(void) {} // expected-error {{'interrupt_save_fp' attribute requires a string}}
10+
__attribute__((interrupt_save_fp("IRQ", 1))) void foo2(void) {} // expected-error {{'interrupt_save_fp' attribute takes no more than 1 argument}}
11+
__attribute__((interrupt_save_fp("IRQ"))) void foo3(void) {}
12+
__attribute__((interrupt_save_fp("FIQ"))) void foo4(void) {}
13+
__attribute__((interrupt_save_fp("SWI"))) void foo5(void) {}
14+
__attribute__((interrupt_save_fp("ABORT"))) void foo6(void) {}
15+
__attribute__((interrupt_save_fp("UNDEF"))) void foo7(void) {}
16+
__attribute__((interrupt_save_fp)) void foo8(void) {}
17+
__attribute__((interrupt_save_fp())) void foo9(void) {}
18+
__attribute__((interrupt_save_fp(""))) void foo10(void) {}
19+
20+
__attribute__((interrupt_save_fp("IRQ"))) void callee(void) {}
21+
22+
void caller(void)
23+
{
24+
callee(); // expected-error {{interrupt service routine cannot be called directly}}
25+
}
26+
#endif // __ARM_FP

0 commit comments

Comments
 (0)