Skip to content

Commit

Permalink
[libunwind][MIPS] Support MIPS floating-point registers for hard-floa…
Browse files Browse the repository at this point in the history
…t ABIs.

Summary:
For MIPS ABIs with 64-bit floating point registers including newabi
and O32 with 64-bit floating point registers, just save and restore the
32 floating-point registers as doubles.

For O32 MIPS with 32-bit floating-point registers, save and restore the
individual floating-point registers as "plain" registers.  These registers
are encoded as floats rather than doubles, but the DWARF unwinder
assumes that floating-point registers are stored as doubles when reading
them from memory (via AddressSpace::getDouble()).  Treating the
registers as "normal" registers instead causes the DWARF unwinder to
fetch them from memory as a 32-bit register.  This does mean that for
O32 with 32-bit floating-point registers unw_get_fpreg() and
unw_set_fpreg() do not work.  One would have to use unw_get_reg()
and unw_set_reg() instead.  However, DWARF unwinding works
correctly as the DWARF CFI emits records for individual 32-bit
floating-point registers even when they are treated as doubles stored
in paired registers.  If the lack of unw_get/set_fpreg() becomes a pressing
need in the future for O32 MIPS we could add in special handling to
make it work.

Reviewers: sdardis, compnerd

Reviewed By: sdardis

Differential Revision: https://reviews.llvm.org/D41968

llvm-svn: 332414
  • Loading branch information
bsdjhb committed May 15, 2018
1 parent 85d3a70 commit c3f240f
Show file tree
Hide file tree
Showing 6 changed files with 439 additions and 27 deletions.
33 changes: 24 additions & 9 deletions libunwind/include/__libunwind_config.h
Expand Up @@ -71,18 +71,33 @@
# define _LIBUNWIND_CURSOR_SIZE 24
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K
# elif defined(__mips__)
# if defined(_ABIO32) && _MIPS_SIM == _ABIO32 && defined(__mips_soft_float)
# if defined(_ABIO32) && _MIPS_SIM == _ABIO32
# define _LIBUNWIND_TARGET_MIPS_O32 1
# define _LIBUNWIND_CONTEXT_SIZE 18
# define _LIBUNWIND_CURSOR_SIZE 24
# elif defined(_ABIN32) && _MIPS_SIM == _ABIN32 && defined(__mips_soft_float)
# if defined(__mips_hard_float)
# define _LIBUNWIND_CONTEXT_SIZE 50
# define _LIBUNWIND_CURSOR_SIZE 57
# else
# define _LIBUNWIND_CONTEXT_SIZE 18
# define _LIBUNWIND_CURSOR_SIZE 24
# endif
# elif defined(_ABIN32) && _MIPS_SIM == _ABIN32
# define _LIBUNWIND_TARGET_MIPS_NEWABI 1
# define _LIBUNWIND_CONTEXT_SIZE 35
# define _LIBUNWIND_CURSOR_SIZE 42
# elif defined(_ABI64) && _MIPS_SIM == _ABI64 && defined(__mips_soft_float)
# if defined(__mips_hard_float)
# define _LIBUNWIND_CONTEXT_SIZE 67
# define _LIBUNWIND_CURSOR_SIZE 74
# else
# define _LIBUNWIND_CONTEXT_SIZE 35
# define _LIBUNWIND_CURSOR_SIZE 42
# endif
# elif defined(_ABI64) && _MIPS_SIM == _ABI64
# define _LIBUNWIND_TARGET_MIPS_NEWABI 1
# define _LIBUNWIND_CONTEXT_SIZE 35
# define _LIBUNWIND_CURSOR_SIZE 47
# if defined(__mips_hard_float)
# define _LIBUNWIND_CONTEXT_SIZE 67
# define _LIBUNWIND_CURSOR_SIZE 79
# else
# define _LIBUNWIND_CONTEXT_SIZE 35
# define _LIBUNWIND_CURSOR_SIZE 47
# endif
# else
# error "Unsupported MIPS ABI and/or environment"
# endif
Expand Down
32 changes: 32 additions & 0 deletions libunwind/include/libunwind.h
Expand Up @@ -781,6 +781,38 @@ enum {
UNW_MIPS_R29 = 29,
UNW_MIPS_R30 = 30,
UNW_MIPS_R31 = 31,
UNW_MIPS_F0 = 32,
UNW_MIPS_F1 = 33,
UNW_MIPS_F2 = 34,
UNW_MIPS_F3 = 35,
UNW_MIPS_F4 = 36,
UNW_MIPS_F5 = 37,
UNW_MIPS_F6 = 38,
UNW_MIPS_F7 = 39,
UNW_MIPS_F8 = 40,
UNW_MIPS_F9 = 41,
UNW_MIPS_F10 = 42,
UNW_MIPS_F11 = 43,
UNW_MIPS_F12 = 44,
UNW_MIPS_F13 = 45,
UNW_MIPS_F14 = 46,
UNW_MIPS_F15 = 47,
UNW_MIPS_F16 = 48,
UNW_MIPS_F17 = 49,
UNW_MIPS_F18 = 50,
UNW_MIPS_F19 = 51,
UNW_MIPS_F20 = 52,
UNW_MIPS_F21 = 53,
UNW_MIPS_F22 = 54,
UNW_MIPS_F23 = 55,
UNW_MIPS_F24 = 56,
UNW_MIPS_F25 = 57,
UNW_MIPS_F26 = 58,
UNW_MIPS_F27 = 59,
UNW_MIPS_F28 = 60,
UNW_MIPS_F29 = 61,
UNW_MIPS_F30 = 62,
UNW_MIPS_F31 = 63,
UNW_MIPS_HI = 64,
UNW_MIPS_LO = 65,
};
Expand Down
212 changes: 203 additions & 9 deletions libunwind/src/Registers.hpp
Expand Up @@ -2718,6 +2718,14 @@ class _LIBUNWIND_HIDDEN Registers_mips_o32 {
};

mips_o32_thread_state_t _registers;
#ifdef __mips_hard_float
/// O32 with 32-bit floating point registers only uses half of this
/// 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];
#endif
};

inline Registers_mips_o32::Registers_mips_o32(const void *registers) {
Expand All @@ -2744,13 +2752,28 @@ inline bool Registers_mips_o32::validRegister(int regNum) const {
return true;
if (regNum == UNW_MIPS_LO)
return true;
// FIXME: Hard float, DSP accumulator registers, MSA registers
#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;
}

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:
Expand All @@ -2770,6 +2793,18 @@ 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:
Expand All @@ -2788,17 +2823,31 @@ inline void Registers_mips_o32::setRegister(int regNum, uint32_t value) {
_LIBUNWIND_ABORT("unsupported mips_o32 register");
}

inline bool Registers_mips_o32::validFloatRegister(int /* regNum */) const {
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;
#endif
return false;
}

inline double Registers_mips_o32::getFloatRegister(int /* regNum */) const {
inline double Registers_mips_o32::getFloatRegister(int regNum) const {
#if defined(__mips_hard_float) && __mips_fpr == 64
assert(validFloatRegister(regNum));
return _floats[regNum - UNW_MIPS_F0];
#else
_LIBUNWIND_ABORT("mips_o32 float support not implemented");
#endif
}

inline void Registers_mips_o32::setFloatRegister(int /* regNum */,
double /* value */) {
inline void Registers_mips_o32::setFloatRegister(int regNum,
double value) {
#if defined(__mips_hard_float) && __mips_fpr == 64
assert(validFloatRegister(regNum));
_floats[regNum - UNW_MIPS_F0] = value;
#else
_LIBUNWIND_ABORT("mips_o32 float support not implemented");
#endif
}

inline bool Registers_mips_o32::validVectorRegister(int /* regNum */) const {
Expand Down Expand Up @@ -2879,6 +2928,70 @@ inline const char *Registers_mips_o32::getRegisterName(int regNum) {
return "$30";
case UNW_MIPS_R31:
return "$31";
case UNW_MIPS_F0:
return "$f0";
case UNW_MIPS_F1:
return "$f1";
case UNW_MIPS_F2:
return "$f2";
case UNW_MIPS_F3:
return "$f3";
case UNW_MIPS_F4:
return "$f4";
case UNW_MIPS_F5:
return "$f5";
case UNW_MIPS_F6:
return "$f6";
case UNW_MIPS_F7:
return "$f7";
case UNW_MIPS_F8:
return "$f8";
case UNW_MIPS_F9:
return "$f9";
case UNW_MIPS_F10:
return "$f10";
case UNW_MIPS_F11:
return "$f11";
case UNW_MIPS_F12:
return "$f12";
case UNW_MIPS_F13:
return "$f13";
case UNW_MIPS_F14:
return "$f14";
case UNW_MIPS_F15:
return "$f15";
case UNW_MIPS_F16:
return "$f16";
case UNW_MIPS_F17:
return "$f17";
case UNW_MIPS_F18:
return "$f18";
case UNW_MIPS_F19:
return "$f19";
case UNW_MIPS_F20:
return "$f20";
case UNW_MIPS_F21:
return "$f21";
case UNW_MIPS_F22:
return "$f22";
case UNW_MIPS_F23:
return "$f23";
case UNW_MIPS_F24:
return "$f24";
case UNW_MIPS_F25:
return "$f25";
case UNW_MIPS_F26:
return "$f26";
case UNW_MIPS_F27:
return "$f27";
case UNW_MIPS_F28:
return "$f28";
case UNW_MIPS_F29:
return "$f29";
case UNW_MIPS_F30:
return "$f30";
case UNW_MIPS_F31:
return "$f31";
case UNW_MIPS_HI:
return "$hi";
case UNW_MIPS_LO:
Expand Down Expand Up @@ -2924,6 +3037,9 @@ class _LIBUNWIND_HIDDEN Registers_mips_newabi {
};

mips_newabi_thread_state_t _registers;
#ifdef __mips_hard_float
double _floats[32];
#endif
};

inline Registers_mips_newabi::Registers_mips_newabi(const void *registers) {
Expand Down Expand Up @@ -2994,17 +3110,31 @@ inline void Registers_mips_newabi::setRegister(int regNum, uint64_t value) {
_LIBUNWIND_ABORT("unsupported mips_newabi register");
}

inline bool Registers_mips_newabi::validFloatRegister(int /* regNum */) const {
inline bool Registers_mips_newabi::validFloatRegister(int regNum) const {
#ifdef __mips_hard_float
if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31)
return true;
#endif
return false;
}

inline double Registers_mips_newabi::getFloatRegister(int /* regNum */) const {
inline double Registers_mips_newabi::getFloatRegister(int regNum) const {
#ifdef __mips_hard_float
assert(validFloatRegister(regNum));
return _floats[regNum - UNW_MIPS_F0];
#else
_LIBUNWIND_ABORT("mips_newabi float support not implemented");
#endif
}

inline void Registers_mips_newabi::setFloatRegister(int /* regNum */,
double /* value */) {
inline void Registers_mips_newabi::setFloatRegister(int regNum,
double value) {
#ifdef __mips_hard_float
assert(validFloatRegister(regNum));
_floats[regNum - UNW_MIPS_F0] = value;
#else
_LIBUNWIND_ABORT("mips_newabi float support not implemented");
#endif
}

inline bool Registers_mips_newabi::validVectorRegister(int /* regNum */) const {
Expand Down Expand Up @@ -3085,6 +3215,70 @@ inline const char *Registers_mips_newabi::getRegisterName(int regNum) {
return "$30";
case UNW_MIPS_R31:
return "$31";
case UNW_MIPS_F0:
return "$f0";
case UNW_MIPS_F1:
return "$f1";
case UNW_MIPS_F2:
return "$f2";
case UNW_MIPS_F3:
return "$f3";
case UNW_MIPS_F4:
return "$f4";
case UNW_MIPS_F5:
return "$f5";
case UNW_MIPS_F6:
return "$f6";
case UNW_MIPS_F7:
return "$f7";
case UNW_MIPS_F8:
return "$f8";
case UNW_MIPS_F9:
return "$f9";
case UNW_MIPS_F10:
return "$f10";
case UNW_MIPS_F11:
return "$f11";
case UNW_MIPS_F12:
return "$f12";
case UNW_MIPS_F13:
return "$f13";
case UNW_MIPS_F14:
return "$f14";
case UNW_MIPS_F15:
return "$f15";
case UNW_MIPS_F16:
return "$f16";
case UNW_MIPS_F17:
return "$f17";
case UNW_MIPS_F18:
return "$f18";
case UNW_MIPS_F19:
return "$f19";
case UNW_MIPS_F20:
return "$f20";
case UNW_MIPS_F21:
return "$f21";
case UNW_MIPS_F22:
return "$f22";
case UNW_MIPS_F23:
return "$f23";
case UNW_MIPS_F24:
return "$f24";
case UNW_MIPS_F25:
return "$f25";
case UNW_MIPS_F26:
return "$f26";
case UNW_MIPS_F27:
return "$f27";
case UNW_MIPS_F28:
return "$f28";
case UNW_MIPS_F29:
return "$f29";
case UNW_MIPS_F30:
return "$f30";
case UNW_MIPS_F31:
return "$f31";
case UNW_MIPS_HI:
return "$hi";
case UNW_MIPS_LO:
Expand Down

0 comments on commit c3f240f

Please sign in to comment.