llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-backend-arm @llvm/pr-subscribers-clang Author: Benson Chu (pestctrl) <details> <summary>Changes</summary> The interrupt attribute currently doesn't save floating-point related registers in the frame setup and destroy. This patch adds a new interrupt_save_fp attribute that will save floating-point registers as well. --- Patch is 76.18 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/89654.diff 22 Files Affected: - (modified) clang/include/clang/Basic/Attr.td (+16) - (modified) clang/include/clang/Basic/AttrDocs.td (+14) - (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+8-1) - (modified) clang/lib/CodeGen/Targets/ARM.cpp (+6) - (modified) clang/lib/Sema/SemaDeclAttr.cpp (+20-4) - (modified) clang/lib/Sema/SemaExpr.cpp (+2-1) - (added) clang/test/CodeGen/arm-interrupt-save-fp-attr-status-regs.c (+34) - (added) clang/test/CodeGen/arm-interrupt-save-fp-attr.c (+39) - (modified) clang/test/Sema/arm-interrupt-attr.c (+2-2) - (added) clang/test/Sema/arm-interrupt-save-fp-attr.c (+59) - (modified) llvm/include/llvm/IR/IntrinsicsARM.td (+1-1) - (modified) llvm/lib/Target/ARM/ARMAsmPrinter.cpp (+15) - (modified) llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp (+25-1) - (modified) llvm/lib/Target/ARM/ARMCallingConv.td (+32-10) - (modified) llvm/lib/Target/ARM/ARMFrameLowering.cpp (+234-111) - (modified) llvm/lib/Target/ARM/ARMFrameLowering.h (+9) - (modified) llvm/lib/Target/ARM/ARMInstrVFP.td (+3) - (modified) llvm/lib/Target/ARM/ARMMachineFunctionInfo.h (+9-3) - (modified) llvm/lib/Target/ARM/ARMRegisterInfo.td (+7) - (modified) llvm/lib/Target/ARM/Thumb1FrameLowering.cpp (+2-2) - (added) llvm/test/CodeGen/ARM/interrupt-save-fp-attr-status-regs.mir (+277) - (added) llvm/test/CodeGen/ARM/interrupt-save-fp-attr.ll (+303) ``````````diff diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index dc87a8c6f022dc..71775ce1e12461 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -914,6 +914,22 @@ def ARMInterrupt : InheritableAttr, TargetSpecificAttr<TargetARM> { let Documentation = [ARMInterruptDocs]; } +def ARMInterruptSaveFP : InheritableAttr, TargetSpecificAttr<TargetARM> { + let Spellings = [GNU<"interrupt_save_fp">]; + let Args = [EnumArgument<"Interrupt", "InterruptType", + ["IRQ", "FIQ", "SWI", "ABORT", "UNDEF", ""], + ["IRQ", "FIQ", "SWI", "ABORT", "UNDEF", "Generic"], + 1>]; + let HasCustomParsing = 0; + let Documentation = [ARMInterruptSaveFPDocs]; +} + +def ARMSaveFP : InheritableAttr, TargetSpecificAttr<TargetARM> { + let Spellings = []; + let Subjects = SubjectList<[Function]>; + let Documentation = [ARMInterruptSaveFPDocs]; +} + def AVRInterrupt : InheritableAttr, TargetSpecificAttr<TargetAVR> { let Spellings = [GCC<"interrupt">]; let Subjects = SubjectList<[Function]>; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index a0bbe5861c5722..1cd642ba90aa9e 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -2239,6 +2239,20 @@ The semantics are as follows: }]; } +def ARMInterruptSaveFPDocs : Documentation { + let Category = DocCatFunction; + let Heading = "interrupt_save_fp (ARM)"; + let Content = [{ +Clang supports the GNU style ``__attribute__((interrupt_save_fp("TYPE")))`` +on ARM targets. This attribute behaves the same way as the ARM interrupt +attribute, except the general purpose floating point registers are also saved. +If the FPEXC or FPSCR are needed, that state must be saved manually. Note, even +on M-class CPUs, where the floating point context can be automatically saved +depending on the FPCCR, the general purpose floating point registers will be +saved. + }]; +} + def BPFPreserveAccessIndexDocs : Documentation { let Category = DocCatFunction; let Content = [{ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 63e951daec7477..1f519d0fc1cc35 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -335,7 +335,14 @@ def warn_anyx86_excessive_regsave : Warning< " or be compiled with '-mgeneral-regs-only'">, InGroup<DiagGroup<"excessive-regsave">>; def warn_arm_interrupt_calling_convention : Warning< - "call to function without interrupt attribute could clobber interruptee's VFP registers">, + "call to function without interrupt attribute could clobber interruptee's " + "VFP registers; consider using the `interrupt_save_fp` attribute to prevent " + "this behavior">, + InGroup<Extra>; +def warn_arm_interrupt_save_fp_without_vfp_unit : 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">, InGroup<Extra>; def warn_interrupt_attribute_invalid : Warning< "%select{MIPS|MSP430|RISC-V}0 'interrupt' attribute only applies to " diff --git a/clang/lib/CodeGen/Targets/ARM.cpp b/clang/lib/CodeGen/Targets/ARM.cpp index 885d9c77d0e76f..a45858e2e2e586 100644 --- a/clang/lib/CodeGen/Targets/ARM.cpp +++ b/clang/lib/CodeGen/Targets/ARM.cpp @@ -185,6 +185,12 @@ class ARMTargetCodeGenInfo : public TargetCodeGenInfo { Fn->addFnAttr("interrupt", Kind); + // Note: the ARMSaveFPAttr can only exist if we also have an interrupt + // attribute + const ARMSaveFPAttr *SaveFPAttr = FD->getAttr<ARMSaveFPAttr>(); + if (SaveFPAttr) + Fn->addFnAttr("save-fp"); + ARMABIKind ABI = getABIInfo<ARMABIInfo>().getABIKind(); if (ABI == ARMABIKind::APCS) return; diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 363ae93cb62df1..086f0c8daa36c3 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -7524,6 +7524,19 @@ static void handleARMInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { D->addAttr(::new (S.Context) ARMInterruptAttr(S.Context, AL, Kind)); } +static void handleARMInterruptSaveFPAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + handleARMInterruptAttr(S, D, AL); + + bool VFP = S.Context.getTargetInfo().hasFeature("vfp"); + + if (!VFP) { + S.Diag(D->getLocation(), diag::warn_arm_interrupt_save_fp_without_vfp_unit); + return; + } + + D->addAttr(::new (S.Context) ARMSaveFPAttr(S.Context, AL)); +} + static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // MSP430 'interrupt' attribute is applied to // a function with no parameters and void return type. @@ -9134,9 +9147,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, if (AL.isCXX11Attribute() && !Options.IncludeCXX11Attributes) return; - // Unknown attributes are automatically warned on. Target-specific attributes - // which do not apply to the current target architecture are treated as - // though they were unknown attributes. + // Unknown attributes are automatically warned on. Target-specific + // attributes which do not apply to the current target architecture are + // treated as though they were unknown attributes. if (AL.getKind() == ParsedAttr::UnknownAttribute || !AL.existsInTarget(S.Context.getTargetInfo())) { S.Diag(AL.getLoc(), @@ -9145,7 +9158,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, : AL.isDeclspecAttribute() ? (unsigned)diag::warn_unhandled_ms_attribute_ignored : (unsigned)diag::warn_unknown_attribute_ignored) - << AL << AL.getRange(); + << AL << AL.getRange(); return; } @@ -9241,6 +9254,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_Interrupt: handleInterruptAttr(S, D, AL); break; + case ParsedAttr::AT_ARMInterruptSaveFP: + handleARMInterruptSaveFPAttr(S, D, AL); + break; case ParsedAttr::AT_X86ForceAlignArgPointer: handleX86ForceAlignArgPointerAttr(S, D, AL); break; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 5c861467bc1023..72be89dbc53cf3 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -6931,7 +6931,8 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, // no_caller_saved_registers since there is no efficient way to // save and restore the non-GPR state. if (auto *Caller = getCurFunctionDecl()) { - if (Caller->hasAttr<ARMInterruptAttr>()) { + if (Caller->hasAttr<ARMInterruptAttr>() && + !Caller->hasAttr<ARMSaveFPAttr>()) { bool VFP = Context.getTargetInfo().hasFeature("vfp"); if (VFP && (!FDecl || !FDecl->hasAttr<ARMInterruptAttr>())) { Diag(Fn->getExprLoc(), diag::warn_arm_interrupt_calling_convention); diff --git a/clang/test/CodeGen/arm-interrupt-save-fp-attr-status-regs.c b/clang/test/CodeGen/arm-interrupt-save-fp-attr-status-regs.c new file mode 100644 index 00000000000000..457f725f8d3af6 --- /dev/null +++ b/clang/test/CodeGen/arm-interrupt-save-fp-attr-status-regs.c @@ -0,0 +1,34 @@ +// REQUIRES: arm-registered-target +// RUN: %clang -target arm-none-none-eabihf -mcpu=cortex-r5 -mfpu=vfpv3-d16 -marm -S -o - %s \ +// RUN: | FileCheck %s --check-prefix=CHECK-R +// RUN: %clang -target arm-none-none-eabihf -mcpu=cortex-r5 -mfpu=vfpv3-d16 -mthumb -S -o - %s \ +// RUN: | FileCheck %s --check-prefix=CHECK-R +// RUN: %clang -target arm-none-none-eabihf -mcpu=cortex-r4 -mfpu=vfpv3-d16 -marm -S -o - %s \ +// RUN: | FileCheck %s --check-prefix=CHECK-R +// RUN: %clang -target arm-none-none-eabihf -mcpu=cortex-r4 -mfpu=vfpv3-d16 -mthumb -S -o - %s \ +// RUN: | FileCheck %s --check-prefix=CHECK-R +// RUN: %clang -target arm-none-none-eabihf -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -S -o - %s \ +// RUN: | FileCheck %s --check-prefix=CHECK-M +// RUN: %clang -target arm-none-none-eabihf -mcpu=cortex-m33 -mfpu=fpv5-sp-d16 -S -o - %s \ +// RUN: | FileCheck %s --check-prefix=CHECK-M + +void bar(); + +__attribute__((interrupt_save_fp)) void test_generic_interrupt() { + // CHECK-R: vmrs r4, fpscr + // CHECK-R-NEXT: vmrs r5, fpexc + // CHECK-R-NEXT: .save {fpscr, fpexc} + // CHECK-R-NEXT: push {r4, r5} + // ..... + // CHECK-R: pop {r4, r5} + // CHECK-R-NEXT: vmsr fpscr, r4 + // CHECK-R-NEXT: vmsr fpexc, r5 + + // CHECK-M: vmrs r4, fpscr + // CHECK-M-NEXT: .save {fpscr} + // CHECK-M-NEXT: push {r4} + // ..... + // CHECK-M: pop {r4} + // CHECK-M-NEXT: vmsr fpscr, r4 + bar(); +} diff --git a/clang/test/CodeGen/arm-interrupt-save-fp-attr.c b/clang/test/CodeGen/arm-interrupt-save-fp-attr.c new file mode 100644 index 00000000000000..5db8b3daa72126 --- /dev/null +++ b/clang/test/CodeGen/arm-interrupt-save-fp-attr.c @@ -0,0 +1,39 @@ +// RUN: %clang_cc1 -triple thumb-apple-darwin -target-abi aapcs -target-feature +vfp4 -target-cpu cortex-m3 -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple arm-apple-darwin -target-abi apcs-gnu -target-feature +vfp4 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-APCS + +__attribute__((interrupt_save_fp)) void test_generic_interrupt() { + // CHECK: define{{.*}} arm_aapcscc void @test_generic_interrupt() [[GENERIC_ATTR:#[0-9]+]] + + // CHECK-APCS: define{{.*}} void @test_generic_interrupt() [[GENERIC_ATTR:#[0-9]+]] +} + +__attribute__((interrupt_save_fp("IRQ"))) void test_irq_interrupt() { + // CHECK: define{{.*}} arm_aapcscc void @test_irq_interrupt() [[IRQ_ATTR:#[0-9]+]] +} + +__attribute__((interrupt_save_fp("FIQ"))) void test_fiq_interrupt() { + // CHECK: define{{.*}} arm_aapcscc void @test_fiq_interrupt() [[FIQ_ATTR:#[0-9]+]] +} + +__attribute__((interrupt_save_fp("SWI"))) void test_swi_interrupt() { + // CHECK: define{{.*}} arm_aapcscc void @test_swi_interrupt() [[SWI_ATTR:#[0-9]+]] +} + +__attribute__((interrupt_save_fp("ABORT"))) void test_abort_interrupt() { + // CHECK: define{{.*}} arm_aapcscc void @test_abort_interrupt() [[ABORT_ATTR:#[0-9]+]] +} + + +__attribute__((interrupt_save_fp("UNDEF"))) void test_undef_interrupt() { + // CHECK: define{{.*}} arm_aapcscc void @test_undef_interrupt() [[UNDEF_ATTR:#[0-9]+]] +} + + +// CHECK: attributes [[GENERIC_ATTR]] = { {{.*}} {{"interrupt"[^=]}}{{.*}} "save-fp" +// CHECK: attributes [[IRQ_ATTR]] = { {{.*}} "interrupt"="IRQ" {{.*}} "save-fp" +// CHECK: attributes [[FIQ_ATTR]] = { {{.*}} "interrupt"="FIQ" {{.*}} "save-fp" +// CHECK: attributes [[SWI_ATTR]] = { {{.*}} "interrupt"="SWI" {{.*}} "save-fp" +// CHECK: attributes [[ABORT_ATTR]] = { {{.*}} "interrupt"="ABORT" {{.*}} "save-fp" +// CHECK: attributes [[UNDEF_ATTR]] = { {{.*}} "interrupt"="UNDEF" {{.*}} "save-fp" + +// CHECK-APCS: attributes [[GENERIC_ATTR]] = { {{.*}} "interrupt" {{.*}} "save-fp" \ No newline at end of file diff --git a/clang/test/Sema/arm-interrupt-attr.c b/clang/test/Sema/arm-interrupt-attr.c index 3537fba8521ad9..937fd929483da0 100644 --- a/clang/test/Sema/arm-interrupt-attr.c +++ b/clang/test/Sema/arm-interrupt-attr.c @@ -31,13 +31,13 @@ void caller1(void) { #ifndef SOFT __attribute__((interrupt("IRQ"))) void caller2(void) { - callee1(); // expected-warning {{call to function without interrupt attribute could clobber interruptee's VFP registers}} + callee1(); // expected-warning {{call to function without interrupt attribute could clobber interruptee's VFP registers; consider using the `interrupt_save_fp` attribute to prevent this behavior}} callee2(); } void (*callee3)(void); __attribute__((interrupt("IRQ"))) void caller3(void) { - callee3(); // expected-warning {{call to function without interrupt attribute could clobber interruptee's VFP registers}} + callee3(); // expected-warning {{call to function without interrupt attribute could clobber interruptee's VFP registers; consider using the `interrupt_save_fp` attribute to prevent this behavior}} } #else __attribute__((interrupt("IRQ"))) void caller2(void) { diff --git a/clang/test/Sema/arm-interrupt-save-fp-attr.c b/clang/test/Sema/arm-interrupt-save-fp-attr.c new file mode 100644 index 00000000000000..e0fd4e2c4d1288 --- /dev/null +++ b/clang/test/Sema/arm-interrupt-save-fp-attr.c @@ -0,0 +1,59 @@ +// RUN: %clang_cc1 %s -triple arm-apple-darwin -target-feature +vfp2 -verify -fsyntax-only +// RUN: %clang_cc1 %s -triple thumb-apple-darwin -target-feature +vfp3 -verify -fsyntax-only +// RUN: %clang_cc1 %s -triple armeb-none-eabi -target-feature +vfp4 -verify -fsyntax-only +// RUN: %clang_cc1 %s -triple thumbeb-none-eabi -target-feature +neon -verify -fsyntax-only +// RUN: %clang_cc1 %s -triple thumbeb-none-eabi -target-feature +neon -target-feature +soft-float -DSOFT -verify -fsyntax-only + +#ifndef SOFT +__attribute__((interrupt_save_fp(IRQ))) void foo() {} // expected-error {{'interrupt_save_fp' attribute requires a string}} +__attribute__((interrupt_save_fp("irq"))) void foo1() {} // expected-warning {{'interrupt_save_fp' attribute argument not supported: irq}} + +__attribute__((interrupt_save_fp("IRQ", 1))) void foo2() {} // expected-error {{'interrupt_save_fp' attribute takes no more than 1 argument}} +__attribute__((interrupt_save_fp("IRQ"))) void foo3() {} +__attribute__((interrupt_save_fp("FIQ"))) void foo4() {} +__attribute__((interrupt_save_fp("SWI"))) void foo5() {} +__attribute__((interrupt_save_fp("ABORT"))) void foo6() {} +__attribute__((interrupt_save_fp("UNDEF"))) void foo7() {} +__attribute__((interrupt_save_fp)) void foo8() {} +__attribute__((interrupt_save_fp())) void foo9() {} +__attribute__((interrupt_save_fp(""))) void foo10() {} +void callee1(); +__attribute__((interrupt_save_fp("IRQ"))) void callee2(); +void caller1() { + callee1(); + callee2(); +} +__attribute__((interrupt_save_fp("IRQ"))) void caller2() { + callee1(); + callee2(); +} + +void (*callee3)(); +__attribute__((interrupt_save_fp("IRQ"))) void caller3() { + callee3(); +} +#else +__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}} +__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}} +__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}} +__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}} +__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}} +__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}} +__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}} +__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}} +void callee1(); +__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}} +void caller1() { + callee1(); + callee2(); +} +__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}} + callee1(); + callee2(); +} + +void (*callee3)(); +__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}} + callee3(); +} +#endif \ No newline at end of file diff --git a/llvm/include/llvm/IR/IntrinsicsARM.td b/llvm/include/llvm/IR/IntrinsicsARM.td index 11b9877091a8ed..91f9d40f2e05f0 100644 --- a/llvm/include/llvm/IR/IntrinsicsARM.td +++ b/llvm/include/llvm/IR/IntrinsicsARM.td @@ -311,7 +311,7 @@ def int_arm_isb : ClangBuiltin<"__builtin_arm_isb">, MSBuiltin<"__isb">, // VFP def int_arm_get_fpscr : ClangBuiltin<"__builtin_arm_get_fpscr">, - DefaultAttrsIntrinsic<[llvm_i32_ty], [], []>; + DefaultAttrsIntrinsic<[llvm_i32_ty], [], [IntrReadMem]>; def int_arm_set_fpscr : ClangBuiltin<"__builtin_arm_set_fpscr">, DefaultAttrsIntrinsic<[], [llvm_i32_ty], []>; def int_arm_vcvtr : DefaultAttrsIntrinsic<[llvm_float_ty], diff --git a/llvm/lib/Target/ARM/ARMAsmPrinter.cpp b/llvm/lib/Target/ARM/ARMAsmPrinter.cpp index 642739a29d6b06..353f5d1a57540d 100644 --- a/llvm/lib/Target/ARM/ARMAsmPrinter.cpp +++ b/llvm/lib/Target/ARM/ARMAsmPrinter.cpp @@ -1207,6 +1207,14 @@ void ARMAsmPrinter::EmitUnwindingInstruction(const MachineInstr *MI) { SrcReg = ~0U; DstReg = MI->getOperand(0).getReg(); break; + case ARM::VMRS: + SrcReg = ARM::FPSCR; + DstReg = MI->getOperand(0).getReg(); + break; + case ARM::VMRS_FPEXC: + SrcReg = ARM::FPEXC; + DstReg = MI->getOperand(0).getReg(); + break; default: SrcReg = MI->getOperand(1).getReg(); DstReg = MI->getOperand(0).getReg(); @@ -1369,6 +1377,13 @@ void ARMAsmPrinter::EmitUnwindingInstruction(const MachineInstr *MI) { // correct ".save" later. AFI->EHPrologueRemappedRegs[DstReg] = SrcReg; break; + case ARM::VMRS: + case ARM::VMRS_FPEXC: + // If a function spills FPSCR or FPEXC, we copy the values to low + // registers before pushing them. Record the copy so we can emit the + // correct ".save" later. + AFI->EHPrologueRemappedRegs[DstReg] = SrcReg; + break; case ARM::tLDRpci: { // Grab the constpool index and check, whether it corresponds to // original or cloned constpool entry. diff --git a/llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp b/llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp index 9adf758b46c481..ed774ea185f855 100644 --- a/llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp +++ b/llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp @@ -79,11 +79,35 @@ ARMBaseRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { : (UseSplitPush ? CSR_ATPCS_SplitPush_SwiftTail_SaveList : CSR_AAPCS_SwiftTail_SaveList); } else if (F.hasFnAttribute("interrupt")) { + + // Don't bother saving the floating point registers if target is not hard + // float. This will prevent the Thumb1FrameLowering (cortex-m0) from + // crashing due to an llvm_unreachable being triggered when a D-class + // register is in the calling convention. + if (STI.isTargetHardFloat() && F.hasFnAttribute("save-fp")) { + bool HasNEON = STI.hasNEON(); + + if (STI.isMClass()) { + assert(!HasNEON && "NEON is only for Cortex-R/A"); + return UseSplitPush ? CSR_ATPCS_SplitPush_FP_SaveList + : CSR_AAPCS_FP_SaveList; + } + if (F.getFnAttribute("interrupt").getValueAsString() == "FIQ") { + return HasNEON ? CSR_FIQ_FP_NEON_SaveList : CSR_FIQ_FP_SaveList; + } + return HasNEON ? CSR_GenericInt_FP_NEON_SaveList + : CSR_GenericInt_FP_SaveList; + } + if (STI.isMClass()) { ... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/89654 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits