From 8c9c673d1d19a531587408cfb72573d98e5854b0 Mon Sep 17 00:00:00 2001 From: Oleg Kuptsov Date: Wed, 12 Oct 2022 10:22:57 +0300 Subject: [PATCH] [OHOS][MIPS] Add mips o32 fpxx support in libunwind Support for fp32 and fp64 mips o32 modes was initially added in D41968. That patch proposed different handling of fp32 and fp64 cases depending on the __mips_fpr value (32 or 64). In case of fpxx, __mips_fpr is 0, and no special case was implemented for it. Instead of creating a 3rd separate case for that, this patch tries to unify the logic for fp32, fp64 and fpxx. There are some key points: - FPU registers size for fpxx is determined in runtime. See the documentation in p.5.6 of "MIPS Architecture For Programmers Volume I-B: Introduction to the microMIPS32TM Architecture". The document is available at https://www.mips.com/products/architectures/mips32-2/. - unw_fpr_t is float for fp32, double for fp64 and uint64_t for fpxx. For fpxx, if FPU registers are 32-bit, we only use the first 4 bytes of uint64_t to store the register value. - FPU registers are stored in a buffer of 256 = 32 * 8 bytes. In case if size of the registers is 32 bit, they are stored in pairs: f0 f0 f0 f0 f1 f1 f1 f1 .. .. .. .. .. .. .. .. f2 f2 f2 f2 f3 f3 f3 f3 etc - The case of 32-bit FPU registers is not tested yet. Qemu only supports mips CPUs with either 64-bit FPU register size or no FPU at all. There is also no hardware available with such specs. Signed-off-by: Oleg Kuptsov --- .../clang/Basic/DiagnosticCommonKinds.td | 1 - clang/lib/Basic/Targets/Mips.cpp | 6 - clang/lib/Basic/Targets/Mips.h | 5 +- clang/lib/Driver/ToolChains/Arch/Mips.cpp | 7 - clang/test/Preprocessor/init-mips.c | 8 - libunwind/include/libunwind.h | 12 + libunwind/src/AddressSpace.hpp | 8 +- libunwind/src/DwarfInstructions.hpp | 4 +- libunwind/src/Registers.hpp | 234 +++++++++++------- libunwind/src/UnwindRegistersRestore.S | 64 ++++- libunwind/src/UnwindRegistersSave.S | 140 ++++++++--- libunwind/src/libunwind.cpp | 2 +- 12 files changed, 330 insertions(+), 161 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td index aee16705676d..a4f96a97991e 100644 --- a/clang/include/clang/Basic/DiagnosticCommonKinds.td +++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -278,7 +278,6 @@ def err_target_unsupported_abi_for_triple : Error< def err_unsupported_abi_for_opt : Error<"'%0' can only be used with the '%1' ABI">; def err_mips_fp64_req : Error< "'%0' can only be used if the target supports the mfhc1 and mthc1 instructions">; -def err_unsupported_fpxx_ohos : Error<"fpxx is currently unsupported on OHOS">; def err_target_unknown_fpmath : Error<"unknown FP unit '%0'">; def err_target_unsupported_fpmath : Error< "the '%0' unit is not supported with this instruction set">; diff --git a/clang/lib/Basic/Targets/Mips.cpp b/clang/lib/Basic/Targets/Mips.cpp index 37110d8da9b6..3a32fd492c6b 100644 --- a/clang/lib/Basic/Targets/Mips.cpp +++ b/clang/lib/Basic/Targets/Mips.cpp @@ -269,12 +269,6 @@ bool MipsTargetInfo::validateTarget(DiagnosticsEngine &Diags) const { return false; } - // TODO: remove this if entry when fpxx is supported on OHOS - if (getTriple().isOpenHOS() && FPMode == FPXX) { - Diags.Report(diag::err_unsupported_fpxx_ohos); - return false; - } - // -fpxx is valid only for the o32 ABI if (FPMode == FPXX && (ABI == "n32" || ABI == "n64")) { Diags.Report(diag::err_unsupported_abi_for_opt) << "-mfpxx" << "o32"; diff --git a/clang/lib/Basic/Targets/Mips.h b/clang/lib/Basic/Targets/Mips.h index 82cdaf704716..b475c03889a1 100644 --- a/clang/lib/Basic/Targets/Mips.h +++ b/clang/lib/Basic/Targets/Mips.h @@ -86,10 +86,7 @@ public: } bool isFP64Default() const { - // TODO: remove getTriple().isOpenHOS() case - // when fpxx is supported on OHOS - return getTriple().isOpenHOS() || CPU == "mips32r6" || - ABI == "n32" || ABI == "n64" || ABI == "64"; + return CPU == "mips32r6" || ABI == "n32" || ABI == "n64" || ABI == "64"; } bool isNan2008() const override { return IsNan2008; } diff --git a/clang/lib/Driver/ToolChains/Arch/Mips.cpp b/clang/lib/Driver/ToolChains/Arch/Mips.cpp index 889a983f2257..5a509dbb2bd3 100644 --- a/clang/lib/Driver/ToolChains/Arch/Mips.cpp +++ b/clang/lib/Driver/ToolChains/Arch/Mips.cpp @@ -362,9 +362,6 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, } else if (mips::isFP64ADefault(Triple, CPUName)) { Features.push_back("+fp64"); Features.push_back("+nooddspreg"); - } else if (Triple.isOpenHOS()) { - // TODO: remove this else if entry when fpxx is supported on OHOS - Features.push_back("+fp64"); } AddTargetFeature(Args, Features, options::OPT_mno_odd_spreg, @@ -469,10 +466,6 @@ bool mips::isFP64ADefault(const llvm::Triple &Triple, StringRef CPUName) { bool mips::isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName, StringRef ABIName, mips::FloatABI FloatABI) { - // TODO: remove this if entry when fpxx is supported on OHOS - if (Triple.isOpenHOS()) - return false; - if (Triple.getVendor() != llvm::Triple::ImaginationTechnologies && Triple.getVendor() != llvm::Triple::MipsTechnologies && !Triple.isAndroid()) diff --git a/clang/test/Preprocessor/init-mips.c b/clang/test/Preprocessor/init-mips.c index 258acfacde23..d76396aa35c9 100644 --- a/clang/test/Preprocessor/init-mips.c +++ b/clang/test/Preprocessor/init-mips.c @@ -1,7 +1,4 @@ -// RUN: %clang_cc1 -E -dM -triple=mipsel-linux-ohos < /dev/null | FileCheck -match-full-lines -check-prefix MIPS32EL-OHOS %s // -// MIPS32EL-OHOS:#define __mips_fpr 64 - // RUN: %clang_cc1 -E -dM -ffreestanding -fgnuc-version=4.2.1 -triple=mips-none-none < /dev/null | FileCheck -match-full-lines -check-prefix MIPS32BE -check-prefix MIPS32BE-C %s // RUN: %clang_cc1 -x c++ -E -dM -ffreestanding -fgnuc-version=4.2.1 -triple=mips-none-none < /dev/null | FileCheck -match-full-lines -check-prefix MIPS32BE -check-prefix MIPS32BE-CXX %s // @@ -1706,11 +1703,6 @@ // RUN: | FileCheck -match-full-lines -check-prefix MIPS64-NOFP %s // MIPS64-NOFP:#define __mips_fpr 64 -// RUN: not %clang_cc1 -target-feature +fpxx \ -// RUN: -E -dM -triple=mipsel-linux-ohos < /dev/null 2>&1 \ -// RUN: | FileCheck -match-full-lines -check-prefix MIPS32EL-OHOS-MFPXX %s -// MIPS32EL-OHOS-MFPXX:error: fpxx is currently unsupported on OHOS - // RUN: not %clang_cc1 -target-feature -fp64 \ // RUN: -E -dM -triple=mips64-none-none < /dev/null 2>&1 \ // RUN: | FileCheck -match-full-lines -check-prefix MIPS64-MFP32 %s diff --git a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h index 5bae8d02f799..c36a94e8754d 100644 --- a/libunwind/include/libunwind.h +++ b/libunwind/include/libunwind.h @@ -84,7 +84,19 @@ typedef uintptr_t unw_word_t; #if defined(__arm__) && !defined(__ARM_DWARF_EH__) typedef uint64_t unw_fpreg_t; #else +# if defined(_LIBUNWIND_TARGET_MIPS_O32) && defined(__mips_hard_float) +# if __mips_fpr == 0 +typedef uint64_t unw_fpreg_t; +# elif __mips_fpr == 32 +typedef float unw_fpreg_t; +# elif __mips_fpr == 64 +typedef double unw_fpreg_t; +# else +# error "Unknown __mips_fpr value" +# endif +# else typedef double unw_fpreg_t; +# endif #endif struct unw_proc_info_t { diff --git a/libunwind/src/AddressSpace.hpp b/libunwind/src/AddressSpace.hpp index 171318ff6370..578f383f1d3b 100644 --- a/libunwind/src/AddressSpace.hpp +++ b/libunwind/src/AddressSpace.hpp @@ -169,9 +169,13 @@ public: memcpy(&val, (void *)addr, sizeof(val)); return val; } - double getDouble(pint_t addr) { - double val; + unw_fpreg_t getDouble(pint_t addr) { + unw_fpreg_t val; +#if defined(_LIBUNWIND_TARGET_MIPS_O32) + memcpy(&val, (void *)addr, Registers_mips_o32::getFpuRegsSize()); +#else memcpy(&val, (void *)addr, sizeof(val)); +#endif return val; } v128 getVector(pint_t addr) { diff --git a/libunwind/src/DwarfInstructions.hpp b/libunwind/src/DwarfInstructions.hpp index c39cabe1f783..9a88577eb06b 100644 --- a/libunwind/src/DwarfInstructions.hpp +++ b/libunwind/src/DwarfInstructions.hpp @@ -56,7 +56,7 @@ private: pint_t initialStackValue); static pint_t getSavedRegister(A &addressSpace, const R ®isters, pint_t cfa, const RegisterLocation &savedReg); - static double getSavedFloatRegister(A &addressSpace, const R ®isters, + static unw_fpreg_t getSavedFloatRegister(A &addressSpace, const R ®isters, pint_t cfa, const RegisterLocation &savedReg); static v128 getSavedVectorRegister(A &addressSpace, const R ®isters, pint_t cfa, const RegisterLocation &savedReg); @@ -104,7 +104,7 @@ typename A::pint_t DwarfInstructions::getSavedRegister( } template -double DwarfInstructions::getSavedFloatRegister( +unw_fpreg_t DwarfInstructions::getSavedFloatRegister( A &addressSpace, const R ®isters, pint_t cfa, const RegisterLocation &savedReg) { switch (savedReg.location) { diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp index efeaf435591e..d2e2ac86cb0d 100644 --- a/libunwind/src/Registers.hpp +++ b/libunwind/src/Registers.hpp @@ -53,8 +53,8 @@ public: uint32_t getRegister(int num) const; void setRegister(int num, uint32_t value); bool validFloatRegister(int) const { return false; } - double getFloatRegister(int num) const; - void setFloatRegister(int num, double value); + unw_fpreg_t getFloatRegister(int num) const; + void setFloatRegister(int num, unw_fpreg_t value); bool validVectorRegister(int) const { return false; } v128 getVectorRegister(int num) const; void setVectorRegister(int num, v128 value); @@ -230,11 +230,11 @@ inline const char *Registers_x86::getRegisterName(int regNum) { } } -inline double Registers_x86::getFloatRegister(int) const { +inline unw_fpreg_t Registers_x86::getFloatRegister(int) const { _LIBUNWIND_ABORT("no x86 float registers"); } -inline void Registers_x86::setFloatRegister(int, double) { +inline void Registers_x86::setFloatRegister(int, unw_fpreg_t) { _LIBUNWIND_ABORT("no x86 float registers"); } @@ -262,8 +262,8 @@ public: uint64_t getRegister(int num) const; void setRegister(int num, uint64_t value); bool validFloatRegister(int) const { return false; } - double getFloatRegister(int num) const; - void setFloatRegister(int num, double value); + unw_fpreg_t getFloatRegister(int num) const; + void setFloatRegister(int num, unw_fpreg_t value); bool validVectorRegister(int) const; v128 getVectorRegister(int num) const; void setVectorRegister(int num, v128 value); @@ -521,11 +521,11 @@ inline const char *Registers_x86_64::getRegisterName(int regNum) { } } -inline double Registers_x86_64::getFloatRegister(int) const { +inline unw_fpreg_t Registers_x86_64::getFloatRegister(int) const { _LIBUNWIND_ABORT("no x86_64 float registers"); } -inline void Registers_x86_64::setFloatRegister(int, double) { +inline void Registers_x86_64::setFloatRegister(int, unw_fpreg_t) { _LIBUNWIND_ABORT("no x86_64 float registers"); } @@ -576,8 +576,8 @@ public: uint32_t getRegister(int num) const; void setRegister(int num, uint32_t value); bool validFloatRegister(int num) const; - double getFloatRegister(int num) const; - void setFloatRegister(int num, double value); + unw_fpreg_t getFloatRegister(int num) const; + void setFloatRegister(int num, unw_fpreg_t value); bool validVectorRegister(int num) const; v128 getVectorRegister(int num) const; void setVectorRegister(int num, v128 value); @@ -958,12 +958,12 @@ inline bool Registers_ppc::validFloatRegister(int regNum) const { return true; } -inline double Registers_ppc::getFloatRegister(int regNum) const { +inline unw_fpreg_t Registers_ppc::getFloatRegister(int regNum) const { assert(validFloatRegister(regNum)); return _floatRegisters.__fpregs[regNum - UNW_PPC_F0]; } -inline void Registers_ppc::setFloatRegister(int regNum, double value) { +inline void Registers_ppc::setFloatRegister(int regNum, unw_fpreg_t value) { assert(validFloatRegister(regNum)); _floatRegisters.__fpregs[regNum - UNW_PPC_F0] = value; } @@ -1142,8 +1142,8 @@ public: uint64_t getRegister(int num) const; void setRegister(int num, uint64_t value); bool validFloatRegister(int num) const; - double getFloatRegister(int num) const; - void setFloatRegister(int num, double value); + unw_fpreg_t getFloatRegister(int num) const; + void setFloatRegister(int num, unw_fpreg_t value); bool validVectorRegister(int num) const; v128 getVectorRegister(int num) const; void setVectorRegister(int num, v128 value); @@ -1504,12 +1504,12 @@ inline bool Registers_ppc64::validFloatRegister(int regNum) const { return regNum >= UNW_PPC64_F0 && regNum <= UNW_PPC64_F31; } -inline double Registers_ppc64::getFloatRegister(int regNum) const { +inline unw_fpreg_t Registers_ppc64::getFloatRegister(int regNum) const { assert(validFloatRegister(regNum)); return _vectorScalarRegisters[regNum - UNW_PPC64_F0].asfloat.f; } -inline void Registers_ppc64::setFloatRegister(int regNum, double value) { +inline void Registers_ppc64::setFloatRegister(int regNum, unw_fpreg_t value) { assert(validFloatRegister(regNum)); _vectorScalarRegisters[regNum - UNW_PPC64_F0].asfloat.f = value; } @@ -1787,8 +1787,8 @@ public: uint64_t getRegister(int num) const; void setRegister(int num, uint64_t value); bool validFloatRegister(int num) const; - double getFloatRegister(int num) const; - void setFloatRegister(int num, double value); + unw_fpreg_t getFloatRegister(int num) const; + void setFloatRegister(int num, unw_fpreg_t value); bool validVectorRegister(int num) const; v128 getVectorRegister(int num) const; void setVectorRegister(int num, v128 value); @@ -2026,12 +2026,12 @@ inline bool Registers_arm64::validFloatRegister(int regNum) const { return true; } -inline double Registers_arm64::getFloatRegister(int regNum) const { +inline unw_fpreg_t Registers_arm64::getFloatRegister(int regNum) const { assert(validFloatRegister(regNum)); return _vectorHalfRegisters[regNum - UNW_ARM64_D0]; } -inline void Registers_arm64::setFloatRegister(int regNum, double value) { +inline void Registers_arm64::setFloatRegister(int regNum, unw_fpreg_t value) { assert(validFloatRegister(regNum)); _vectorHalfRegisters[regNum - UNW_ARM64_D0] = value; } @@ -2545,8 +2545,8 @@ public: uint32_t getRegister(int num) const; void setRegister(int num, uint32_t value); bool validFloatRegister(int num) const; - double getFloatRegister(int num) const; - void setFloatRegister(int num, double value); + unw_fpreg_t getFloatRegister(int num) const; + void setFloatRegister(int num, unw_fpreg_t value); bool validVectorRegister(int num) const; v128 getVectorRegister(int num) const; void setVectorRegister(int num, v128 value); @@ -2634,12 +2634,12 @@ inline bool Registers_or1k::validFloatRegister(int /* regNum */) const { return false; } -inline double Registers_or1k::getFloatRegister(int /* regNum */) const { +inline unw_fpreg_t Registers_or1k::getFloatRegister(int /* regNum */) const { _LIBUNWIND_ABORT("or1k float support not implemented"); } inline void Registers_or1k::setFloatRegister(int /* regNum */, - double /* value */) { + unw_fpreg_t /* value */) { _LIBUNWIND_ABORT("or1k float support not implemented"); } @@ -2731,19 +2731,32 @@ inline const char *Registers_or1k::getRegisterName(int regNum) { #endif // _LIBUNWIND_TARGET_OR1K #if defined(_LIBUNWIND_TARGET_MIPS_O32) + +// TODO: check the following for FPU with 32-bit registers: +// - fpxx code works properly +// - fp32 code remains working properly + /// Registers_mips_o32 holds the register state of a thread in a 32-bit MIPS /// process. class _LIBUNWIND_HIDDEN Registers_mips_o32 { public: Registers_mips_o32(); Registers_mips_o32(const void *registers); +#ifdef __mips_hard_float + Registers_mips_o32(const Registers_mips_o32 &) = default; + Registers_mips_o32 &operator=(const Registers_mips_o32 &src) { + memcpy(&_registers, &src._registers, sizeof(_registers)); + memcpy(&_floatsBuffer, &src._floatsBuffer, sizeof(_floatsBuffer)); + return *this; + } +#endif bool validRegister(int num) const; uint32_t getRegister(int num) const; void setRegister(int num, uint32_t value); bool validFloatRegister(int num) const; - double getFloatRegister(int num) const; - void setFloatRegister(int num, double value); + unw_fpreg_t getFloatRegister(int num) const; + void setFloatRegister(int num, unw_fpreg_t value); bool validVectorRegister(int num) const; v128 getVectorRegister(int num) const; void setVectorRegister(int num, v128 value); @@ -2751,6 +2764,9 @@ public: void jumpto(); static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS; } static int getArch() { return REGISTERS_MIPS_O32; } +#ifdef __mips_hard_float + static uint32_t getFpuRegsSize(); +#endif uint32_t getSP() const { return _registers.__r[29]; } void setSP(uint32_t value) { _registers.__r[29] = value; } @@ -2771,19 +2787,50 @@ private: /// space. However, using the same layout for 32-bit vs 64-bit /// floating point registers results in a single context size for /// O32 with hard float. - uint32_t _padding; - double _floats[32]; + const uint32_t _fpuRegsSize; + char _floatsBuffer[32 * 8] = {0}; + + char *getFpuRegLocation(int regNum); + const char *getFpuRegLocation(int regNum) const; #endif }; -inline Registers_mips_o32::Registers_mips_o32(const void *registers) { +inline Registers_mips_o32::Registers_mips_o32(const void *registers) +#ifdef __mips_hard_float + : _fpuRegsSize(getFpuRegsSize()) +#endif +{ static_assert((check_fit::does_fit), "mips_o32 registers do not fit into unw_context_t"); memcpy(&_registers, static_cast(registers), sizeof(_registers)); } -inline Registers_mips_o32::Registers_mips_o32() { +#ifdef __mips_hard_float +inline uint32_t Registers_mips_o32::getFpuRegsSize() { +#if __mips_fpr == 32 + return 4; +#elif __mips_fpr == 64 + return 8; +#elif __mips_fpr == 0 + unsigned fpuID; + __asm__ __volatile__(" .set push \n" + " cfc1 %0,$0 \n" + " .set pop \n" + : "=r"(fpuID)); + constexpr unsigned MIPS_FPIR_F64 = (1 << 22); + return (fpuID & MIPS_FPIR_F64) ? 8 : 4; +#else +#error "Unknown __mips_fpr value" +#endif +} +#endif + +inline Registers_mips_o32::Registers_mips_o32() +#ifdef __mips_hard_float + : _fpuRegsSize(getFpuRegsSize()) +#endif +{ memset(&_registers, 0, sizeof(_registers)); } @@ -2801,10 +2848,6 @@ inline bool Registers_mips_o32::validRegister(int regNum) const { return true; if (regNum == UNW_MIPS_LO) return true; -#endif -#if defined(__mips_hard_float) && __mips_fpr == 32 - if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31) - return true; #endif // FIXME: DSP accumulator registers, MSA registers return false; @@ -2813,17 +2856,6 @@ inline bool Registers_mips_o32::validRegister(int regNum) const { inline uint32_t Registers_mips_o32::getRegister(int regNum) const { if (regNum >= UNW_MIPS_R0 && regNum <= UNW_MIPS_R31) return _registers.__r[regNum - UNW_MIPS_R0]; -#if defined(__mips_hard_float) && __mips_fpr == 32 - if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31) { - uint32_t *p; - - if (regNum % 2 == 0) - p = (uint32_t *)&_floats[regNum - UNW_MIPS_F0]; - else - p = (uint32_t *)&_floats[(regNum - 1) - UNW_MIPS_F0] + 1; - return *p; - } -#endif switch (regNum) { case UNW_REG_IP: @@ -2843,19 +2875,6 @@ inline void Registers_mips_o32::setRegister(int regNum, uint32_t value) { _registers.__r[regNum - UNW_MIPS_R0] = value; return; } -#if defined(__mips_hard_float) && __mips_fpr == 32 - if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31) { - uint32_t *p; - - if (regNum % 2 == 0) - p = (uint32_t *)&_floats[regNum - UNW_MIPS_F0]; - else - p = (uint32_t *)&_floats[(regNum - 1) - UNW_MIPS_F0] + 1; - *p = value; - return; - } -#endif - switch (regNum) { case UNW_REG_IP: _registers.__pc = value; @@ -2873,20 +2892,51 @@ inline void Registers_mips_o32::setRegister(int regNum, uint32_t value) { _LIBUNWIND_ABORT("unsupported mips_o32 register"); } +#ifdef __mips_hard_float +inline const char *Registers_mips_o32::getFpuRegLocation(int regNum) const { + const char *regLocation = _floatsBuffer; + int fpuRegNum = regNum - UNW_MIPS_F0; + if (_fpuRegsSize == 4 && fpuRegNum % 2 == 1) + regLocation += (fpuRegNum - 1) * 8 + 4; + else + regLocation += fpuRegNum * 8; + return regLocation; +} + +inline char *Registers_mips_o32::getFpuRegLocation(int regNum) { + char *regLocation = _floatsBuffer; + int fpuRegNum = regNum - UNW_MIPS_F0; + if (_fpuRegsSize == 4 && fpuRegNum % 2 == 1) + regLocation += (fpuRegNum - 1) * 8 + 4; + else + regLocation += fpuRegNum * 8; + return regLocation; +} +#endif + inline bool Registers_mips_o32::validFloatRegister(int regNum) const { -#if defined(__mips_hard_float) && __mips_fpr == 64 - if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31) - return true; +#if defined(__mips_hard_float) + return (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31); #else (void)regNum; -#endif return false; +#endif } -inline double Registers_mips_o32::getFloatRegister(int regNum) const { -#if defined(__mips_hard_float) && __mips_fpr == 64 +inline unw_fpreg_t Registers_mips_o32::getFloatRegister(int regNum) const { +#if defined(__mips_hard_float) assert(validFloatRegister(regNum)); - return _floats[regNum - UNW_MIPS_F0]; +#if __mips_fpr == 0 + const char *regLocation = getFpuRegLocation(regNum); + unw_fpreg_t regValue = 0; + memcpy(reinterpret_cast(®Value), regLocation, _fpuRegsSize); + return regValue; +#elif __mips_fpr == 32 || __mips_fpr == 64 + const char *regLocation = getFpuRegLocation(regNum); + return *reinterpret_cast(regLocation); +#else +#error "Unknown __mips_fpr value" +#endif #else (void)regNum; _LIBUNWIND_ABORT("mips_o32 float support not implemented"); @@ -2894,10 +2944,18 @@ inline double Registers_mips_o32::getFloatRegister(int regNum) const { } inline void Registers_mips_o32::setFloatRegister(int regNum, - double value) { -#if defined(__mips_hard_float) && __mips_fpr == 64 + unw_fpreg_t value) { +#if defined(__mips_hard_float) assert(validFloatRegister(regNum)); - _floats[regNum - UNW_MIPS_F0] = value; +#if __mips_fpr == 0 + char *regLocation = getFpuRegLocation(regNum); + memcpy(regLocation, reinterpret_cast(&value), _fpuRegsSize); +#elif __mips_fpr == 32 || __mips_fpr == 64 + char *regLocation = getFpuRegLocation(regNum); + *reinterpret_cast(regLocation) = value; +#else +#error "Unknown __mips_fpr value" +#endif #else (void)regNum; (void)value; @@ -3069,8 +3127,8 @@ public: uint64_t getRegister(int num) const; void setRegister(int num, uint64_t value); bool validFloatRegister(int num) const; - double getFloatRegister(int num) const; - void setFloatRegister(int num, double value); + unw_fpreg_t getFloatRegister(int num) const; + void setFloatRegister(int num, unw_fpreg_t value); bool validVectorRegister(int num) const; v128 getVectorRegister(int num) const; void setVectorRegister(int num, v128 value); @@ -3178,7 +3236,7 @@ inline bool Registers_mips_newabi::validFloatRegister(int regNum) const { return false; } -inline double Registers_mips_newabi::getFloatRegister(int regNum) const { +inline unw_fpreg_t Registers_mips_newabi::getFloatRegister(int regNum) const { #ifdef __mips_hard_float assert(validFloatRegister(regNum)); return _floats[regNum - UNW_MIPS_F0]; @@ -3189,7 +3247,7 @@ inline double Registers_mips_newabi::getFloatRegister(int regNum) const { } inline void Registers_mips_newabi::setFloatRegister(int regNum, - double value) { + unw_fpreg_t value) { #ifdef __mips_hard_float assert(validFloatRegister(regNum)); _floats[regNum - UNW_MIPS_F0] = value; @@ -3364,8 +3422,8 @@ public: uint32_t getRegister(int num) const; void setRegister(int num, uint32_t value); bool validFloatRegister(int num) const; - double getFloatRegister(int num) const; - void setFloatRegister(int num, double value); + unw_fpreg_t getFloatRegister(int num) const; + void setFloatRegister(int num, unw_fpreg_t value); bool validVectorRegister(int num) const; v128 getVectorRegister(int num) const; void setVectorRegister(int num, v128 value); @@ -3443,11 +3501,11 @@ inline void Registers_sparc::setRegister(int regNum, uint32_t value) { inline bool Registers_sparc::validFloatRegister(int) const { return false; } -inline double Registers_sparc::getFloatRegister(int) const { +inline unw_fpreg_t Registers_sparc::getFloatRegister(int) const { _LIBUNWIND_ABORT("no Sparc float registers"); } -inline void Registers_sparc::setFloatRegister(int, double) { +inline void Registers_sparc::setFloatRegister(int, unw_fpreg_t) { _LIBUNWIND_ABORT("no Sparc float registers"); } @@ -3548,8 +3606,8 @@ public: uint32_t getRegister(int num) const; void setRegister(int num, uint32_t value); bool validFloatRegister(int num) const; - double getFloatRegister(int num) const; - void setFloatRegister(int num, double value); + unw_fpreg_t getFloatRegister(int num) const; + void setFloatRegister(int num, unw_fpreg_t value); bool validVectorRegister(int num) const; v128 getVectorRegister(int num) const; void setVectorRegister(int num, v128 value); @@ -3622,12 +3680,12 @@ inline bool Registers_hexagon::validFloatRegister(int /* regNum */) const { return false; } -inline double Registers_hexagon::getFloatRegister(int /* regNum */) const { +inline unw_fpreg_t Registers_hexagon::getFloatRegister(int /* regNum */) const { _LIBUNWIND_ABORT("hexagon float support not implemented"); } inline void Registers_hexagon::setFloatRegister(int /* regNum */, - double /* value */) { + unw_fpreg_t /* value */) { _LIBUNWIND_ABORT("hexagon float support not implemented"); } @@ -3729,8 +3787,8 @@ public: uint64_t getRegister(int num) const; void setRegister(int num, uint64_t value); bool validFloatRegister(int num) const; - double getFloatRegister(int num) const; - void setFloatRegister(int num, double value); + unw_fpreg_t getFloatRegister(int num) const; + void setFloatRegister(int num, unw_fpreg_t value); bool validVectorRegister(int num) const; v128 getVectorRegister(int num) const; void setVectorRegister(int num, v128 value); @@ -3951,7 +4009,7 @@ inline bool Registers_riscv::validFloatRegister(int regNum) const { return true; } -inline double Registers_riscv::getFloatRegister(int regNum) const { +inline unw_fpreg_t Registers_riscv::getFloatRegister(int regNum) const { #if defined(__riscv_flen) && __riscv_flen == 64 assert(validFloatRegister(regNum)); return _floats[regNum - UNW_RISCV_F0]; @@ -3961,7 +4019,7 @@ inline double Registers_riscv::getFloatRegister(int regNum) const { #endif } -inline void Registers_riscv::setFloatRegister(int regNum, double value) { +inline void Registers_riscv::setFloatRegister(int regNum, unw_fpreg_t value) { #if defined(__riscv_flen) && __riscv_flen == 64 assert(validFloatRegister(regNum)); _floats[regNum - UNW_RISCV_F0] = value; @@ -3996,8 +4054,8 @@ public: uint64_t getRegister(int num) const; void setRegister(int num, uint64_t value); bool validFloatRegister(int num) const; - double getFloatRegister(int num) const; - void setFloatRegister(int num, double value); + unw_fpreg_t getFloatRegister(int num) const; + void setFloatRegister(int num, unw_fpreg_t value); bool validVectorRegister(int num) const; v128 getVectorRegister(int num) const; void setVectorRegister(int num, v128 value); @@ -4100,12 +4158,12 @@ inline bool Registers_ve::validFloatRegister(int /* regNum */) const { return false; } -inline double Registers_ve::getFloatRegister(int /* regNum */) const { +inline unw_fpreg_t Registers_ve::getFloatRegister(int /* regNum */) const { _LIBUNWIND_ABORT("VE doesn't have float registers"); } inline void Registers_ve::setFloatRegister(int /* regNum */, - double /* value */) { + unw_fpreg_t /* value */) { _LIBUNWIND_ABORT("VE doesn't have float registers"); } diff --git a/libunwind/src/UnwindRegistersRestore.S b/libunwind/src/UnwindRegistersRestore.S index 289afe98b0b2..43902767ab30 100644 --- a/libunwind/src/UnwindRegistersRestore.S +++ b/libunwind/src/UnwindRegistersRestore.S @@ -865,7 +865,7 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind18Registers_mips_o326jumptoEv) .set noreorder .set nomacro #ifdef __mips_hard_float -#if __mips_fpr != 64 +#if __mips_fpr == 32 ldc1 $f0, (4 * 36 + 8 * 0)($4) ldc1 $f2, (4 * 36 + 8 * 2)($4) ldc1 $f4, (4 * 36 + 8 * 4)($4) @@ -882,7 +882,46 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind18Registers_mips_o326jumptoEv) ldc1 $f26, (4 * 36 + 8 * 26)($4) ldc1 $f28, (4 * 36 + 8 * 28)($4) ldc1 $f30, (4 * 36 + 8 * 30)($4) -#else +#elif __mips_fpr == 64 + ldc1 $f0, (4 * 36 + 8 * 0)($4) + ldc1 $f1, (4 * 36 + 8 * 1)($4) + ldc1 $f2, (4 * 36 + 8 * 2)($4) + ldc1 $f3, (4 * 36 + 8 * 3)($4) + ldc1 $f4, (4 * 36 + 8 * 4)($4) + ldc1 $f5, (4 * 36 + 8 * 5)($4) + ldc1 $f6, (4 * 36 + 8 * 6)($4) + ldc1 $f7, (4 * 36 + 8 * 7)($4) + ldc1 $f8, (4 * 36 + 8 * 8)($4) + ldc1 $f9, (4 * 36 + 8 * 9)($4) + ldc1 $f10, (4 * 36 + 8 * 10)($4) + ldc1 $f11, (4 * 36 + 8 * 11)($4) + ldc1 $f12, (4 * 36 + 8 * 12)($4) + ldc1 $f13, (4 * 36 + 8 * 13)($4) + ldc1 $f14, (4 * 36 + 8 * 14)($4) + ldc1 $f15, (4 * 36 + 8 * 15)($4) + ldc1 $f16, (4 * 36 + 8 * 16)($4) + ldc1 $f17, (4 * 36 + 8 * 17)($4) + ldc1 $f18, (4 * 36 + 8 * 18)($4) + ldc1 $f19, (4 * 36 + 8 * 19)($4) + ldc1 $f20, (4 * 36 + 8 * 20)($4) + ldc1 $f21, (4 * 36 + 8 * 21)($4) + ldc1 $f22, (4 * 36 + 8 * 22)($4) + ldc1 $f23, (4 * 36 + 8 * 23)($4) + ldc1 $f24, (4 * 36 + 8 * 24)($4) + ldc1 $f25, (4 * 36 + 8 * 25)($4) + ldc1 $f26, (4 * 36 + 8 * 26)($4) + ldc1 $f27, (4 * 36 + 8 * 27)($4) + ldc1 $f28, (4 * 36 + 8 * 28)($4) + ldc1 $f29, (4 * 36 + 8 * 29)($4) + ldc1 $f30, (4 * 36 + 8 * 30)($4) + ldc1 $f31, (4 * 36 + 8 * 31)($4) +#elif __mips_fpr == 0 + cfc1 $t0, $0 + li $t1, 1 + sll $t1, $t1, 22 + and $t0, $t0, $t1 + beq $t0, $0, _fp32 +_fp64: ldc1 $f0, (4 * 36 + 8 * 0)($4) ldc1 $f1, (4 * 36 + 8 * 1)($4) ldc1 $f2, (4 * 36 + 8 * 2)($4) @@ -915,8 +954,29 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind18Registers_mips_o326jumptoEv) ldc1 $f29, (4 * 36 + 8 * 29)($4) ldc1 $f30, (4 * 36 + 8 * 30)($4) ldc1 $f31, (4 * 36 + 8 * 31)($4) + j _after_float +_fp32: + ldc1 $f0, (4 * 36 + 8 * 0)($4) + ldc1 $f2, (4 * 36 + 8 * 2)($4) + ldc1 $f4, (4 * 36 + 8 * 4)($4) + ldc1 $f6, (4 * 36 + 8 * 6)($4) + ldc1 $f8, (4 * 36 + 8 * 8)($4) + ldc1 $f10, (4 * 36 + 8 * 10)($4) + ldc1 $f12, (4 * 36 + 8 * 12)($4) + ldc1 $f14, (4 * 36 + 8 * 14)($4) + ldc1 $f16, (4 * 36 + 8 * 16)($4) + ldc1 $f18, (4 * 36 + 8 * 18)($4) + ldc1 $f20, (4 * 36 + 8 * 20)($4) + ldc1 $f22, (4 * 36 + 8 * 22)($4) + ldc1 $f24, (4 * 36 + 8 * 24)($4) + ldc1 $f26, (4 * 36 + 8 * 26)($4) + ldc1 $f28, (4 * 36 + 8 * 28)($4) + ldc1 $f30, (4 * 36 + 8 * 30)($4) +#else +#error "Unknown __mips_fpr value" #endif #endif +_after_float: // restore hi and lo lw $8, (4 * 33)($4) mthi $8 diff --git a/libunwind/src/UnwindRegistersSave.S b/libunwind/src/UnwindRegistersSave.S index 94fc8365455d..bfaf3530166a 100644 --- a/libunwind/src/UnwindRegistersSave.S +++ b/libunwind/src/UnwindRegistersSave.S @@ -128,46 +128,8 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) .set noat .set noreorder .set nomacro - sw $1, (4 * 1)($4) - sw $2, (4 * 2)($4) - sw $3, (4 * 3)($4) - sw $4, (4 * 4)($4) - sw $5, (4 * 5)($4) - sw $6, (4 * 6)($4) - sw $7, (4 * 7)($4) - sw $8, (4 * 8)($4) - sw $9, (4 * 9)($4) - sw $10, (4 * 10)($4) - sw $11, (4 * 11)($4) - sw $12, (4 * 12)($4) - sw $13, (4 * 13)($4) - sw $14, (4 * 14)($4) - sw $15, (4 * 15)($4) - sw $16, (4 * 16)($4) - sw $17, (4 * 17)($4) - sw $18, (4 * 18)($4) - sw $19, (4 * 19)($4) - sw $20, (4 * 20)($4) - sw $21, (4 * 21)($4) - sw $22, (4 * 22)($4) - sw $23, (4 * 23)($4) - sw $24, (4 * 24)($4) - sw $25, (4 * 25)($4) - sw $26, (4 * 26)($4) - sw $27, (4 * 27)($4) - sw $28, (4 * 28)($4) - sw $29, (4 * 29)($4) - sw $30, (4 * 30)($4) - sw $31, (4 * 31)($4) - # Store return address to pc - sw $31, (4 * 32)($4) - # hi and lo - mfhi $8 - sw $8, (4 * 33)($4) - mflo $8 - sw $8, (4 * 34)($4) #ifdef __mips_hard_float -#if __mips_fpr != 64 +#if __mips_fpr == 32 sdc1 $f0, (4 * 36 + 8 * 0)($4) sdc1 $f2, (4 * 36 + 8 * 2)($4) sdc1 $f4, (4 * 36 + 8 * 4)($4) @@ -184,7 +146,46 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) sdc1 $f26, (4 * 36 + 8 * 26)($4) sdc1 $f28, (4 * 36 + 8 * 28)($4) sdc1 $f30, (4 * 36 + 8 * 30)($4) -#else +#elif __mips_fpr == 64 + sdc1 $f0, (4 * 36 + 8 * 0)($4) + sdc1 $f1, (4 * 36 + 8 * 1)($4) + sdc1 $f2, (4 * 36 + 8 * 2)($4) + sdc1 $f3, (4 * 36 + 8 * 3)($4) + sdc1 $f4, (4 * 36 + 8 * 4)($4) + sdc1 $f5, (4 * 36 + 8 * 5)($4) + sdc1 $f6, (4 * 36 + 8 * 6)($4) + sdc1 $f7, (4 * 36 + 8 * 7)($4) + sdc1 $f8, (4 * 36 + 8 * 8)($4) + sdc1 $f9, (4 * 36 + 8 * 9)($4) + sdc1 $f10, (4 * 36 + 8 * 10)($4) + sdc1 $f11, (4 * 36 + 8 * 11)($4) + sdc1 $f12, (4 * 36 + 8 * 12)($4) + sdc1 $f13, (4 * 36 + 8 * 13)($4) + sdc1 $f14, (4 * 36 + 8 * 14)($4) + sdc1 $f15, (4 * 36 + 8 * 15)($4) + sdc1 $f16, (4 * 36 + 8 * 16)($4) + sdc1 $f17, (4 * 36 + 8 * 17)($4) + sdc1 $f18, (4 * 36 + 8 * 18)($4) + sdc1 $f19, (4 * 36 + 8 * 19)($4) + sdc1 $f20, (4 * 36 + 8 * 20)($4) + sdc1 $f21, (4 * 36 + 8 * 21)($4) + sdc1 $f22, (4 * 36 + 8 * 22)($4) + sdc1 $f23, (4 * 36 + 8 * 23)($4) + sdc1 $f24, (4 * 36 + 8 * 24)($4) + sdc1 $f25, (4 * 36 + 8 * 25)($4) + sdc1 $f26, (4 * 36 + 8 * 26)($4) + sdc1 $f27, (4 * 36 + 8 * 27)($4) + sdc1 $f28, (4 * 36 + 8 * 28)($4) + sdc1 $f29, (4 * 36 + 8 * 29)($4) + sdc1 $f30, (4 * 36 + 8 * 30)($4) + sdc1 $f31, (4 * 36 + 8 * 31)($4) +#elif __mips_fpr == 0 + cfc1 $t0, $0 + li $t1, 1 + sll $t1, $t1, 22 + and $t0, $t0, $t1 + beq $t0, $0, _fp32 +_fp64: sdc1 $f0, (4 * 36 + 8 * 0)($4) sdc1 $f1, (4 * 36 + 8 * 1)($4) sdc1 $f2, (4 * 36 + 8 * 2)($4) @@ -217,8 +218,67 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) sdc1 $f29, (4 * 36 + 8 * 29)($4) sdc1 $f30, (4 * 36 + 8 * 30)($4) sdc1 $f31, (4 * 36 + 8 * 31)($4) + j _after_float +_fp32: + sdc1 $f0, (4 * 36 + 8 * 0)($4) + sdc1 $f2, (4 * 36 + 8 * 2)($4) + sdc1 $f4, (4 * 36 + 8 * 4)($4) + sdc1 $f6, (4 * 36 + 8 * 6)($4) + sdc1 $f8, (4 * 36 + 8 * 8)($4) + sdc1 $f10, (4 * 36 + 8 * 10)($4) + sdc1 $f12, (4 * 36 + 8 * 12)($4) + sdc1 $f14, (4 * 36 + 8 * 14)($4) + sdc1 $f16, (4 * 36 + 8 * 16)($4) + sdc1 $f18, (4 * 36 + 8 * 18)($4) + sdc1 $f20, (4 * 36 + 8 * 20)($4) + sdc1 $f22, (4 * 36 + 8 * 22)($4) + sdc1 $f24, (4 * 36 + 8 * 24)($4) + sdc1 $f26, (4 * 36 + 8 * 26)($4) + sdc1 $f28, (4 * 36 + 8 * 28)($4) + sdc1 $f30, (4 * 36 + 8 * 30)($4) +#else +#error "Unknown __mips_fpr value" #endif #endif +_after_float: + sw $1, (4 * 1)($4) + sw $2, (4 * 2)($4) + sw $3, (4 * 3)($4) + sw $4, (4 * 4)($4) + sw $5, (4 * 5)($4) + sw $6, (4 * 6)($4) + sw $7, (4 * 7)($4) + sw $8, (4 * 8)($4) + sw $9, (4 * 9)($4) + sw $10, (4 * 10)($4) + sw $11, (4 * 11)($4) + sw $12, (4 * 12)($4) + sw $13, (4 * 13)($4) + sw $14, (4 * 14)($4) + sw $15, (4 * 15)($4) + sw $16, (4 * 16)($4) + sw $17, (4 * 17)($4) + sw $18, (4 * 18)($4) + sw $19, (4 * 19)($4) + sw $20, (4 * 20)($4) + sw $21, (4 * 21)($4) + sw $22, (4 * 22)($4) + sw $23, (4 * 23)($4) + sw $24, (4 * 24)($4) + sw $25, (4 * 25)($4) + sw $26, (4 * 26)($4) + sw $27, (4 * 27)($4) + sw $28, (4 * 28)($4) + sw $29, (4 * 29)($4) + sw $30, (4 * 30)($4) + sw $31, (4 * 31)($4) + # Store return address to pc + sw $31, (4 * 32)($4) + # hi and lo + mfhi $8 + sw $8, (4 * 33)($4) + mflo $8 + sw $8, (4 * 34)($4) jr $31 # return UNW_ESUCCESS or $2, $0, $0 diff --git a/libunwind/src/libunwind.cpp b/libunwind/src/libunwind.cpp index c21461b1f480..c3861f3abed0 100644 --- a/libunwind/src/libunwind.cpp +++ b/libunwind/src/libunwind.cpp @@ -144,7 +144,7 @@ _LIBUNWIND_WEAK_ALIAS(__unw_get_fpreg, unw_get_fpreg) /// Set value of specified float register at cursor position in stack frame. _LIBUNWIND_HIDDEN int __unw_set_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum, unw_fpreg_t value) { -#if defined(_LIBUNWIND_ARM_EHABI) +#if defined(_LIBUNWIND_ARM_EHABI) || (defined(__mips__) && __mips_fpr == 0) _LIBUNWIND_TRACE_API("__unw_set_fpreg(cursor=%p, regNum=%d, value=%llX)", static_cast(cursor), regNum, value); #else -- Gitee