[libunwind] c507269 - [libunwind][LoongArch] Add 64-bit LoongArch support

Weining Lu via cfe-commits cfe-commits at lists.llvm.org
Mon Nov 14 22:37:46 PST 2022


Author: zhanglimin
Date: 2022-11-15T14:37:00+08:00
New Revision: c5072695127e767a76973cdbed683215df31fa40

URL: https://github.com/llvm/llvm-project/commit/c5072695127e767a76973cdbed683215df31fa40
DIFF: https://github.com/llvm/llvm-project/commit/c5072695127e767a76973cdbed683215df31fa40.diff

LOG: [libunwind][LoongArch] Add 64-bit LoongArch support

Defines enums for the LoongArch registers.
Adds the register class implementation for LoongArch.
Adds save and restore context functionality.

This only supports 64 bits integer and float-point register
implementation.

Fix https://github.com/llvm/llvm-project/issues/55398

Reviewed By: SixWeining

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

Added: 
    

Modified: 
    libunwind/include/__libunwind_config.h
    libunwind/include/libunwind.h
    libunwind/src/Registers.hpp
    libunwind/src/UnwindCursor.hpp
    libunwind/src/UnwindRegistersRestore.S
    libunwind/src/UnwindRegistersSave.S
    libunwind/src/config.h
    libunwind/src/libunwind.cpp

Removed: 
    


################################################################################
diff  --git a/libunwind/include/__libunwind_config.h b/libunwind/include/__libunwind_config.h
index 5e9de90f649f..f69fe89e9a26 100644
--- a/libunwind/include/__libunwind_config.h
+++ b/libunwind/include/__libunwind_config.h
@@ -30,6 +30,7 @@
 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_RISCV     64
 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_VE        143
 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_S390X     83
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_LOONGARCH 64
 
 #if defined(_LIBUNWIND_IS_NATIVE_ONLY)
 # if defined(__linux__)
@@ -166,6 +167,16 @@
 #  define _LIBUNWIND_CONTEXT_SIZE 34
 #  define _LIBUNWIND_CURSOR_SIZE 46
 #  define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_S390X
+#elif defined(__loongarch__)
+#define _LIBUNWIND_TARGET_LOONGARCH 1
+#if __loongarch_grlen == 64
+#define _LIBUNWIND_CONTEXT_SIZE 65
+#define _LIBUNWIND_CURSOR_SIZE 77
+#else
+#error "Unsupported LoongArch ABI"
+#endif
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER                                      \
+  _LIBUNWIND_HIGHEST_DWARF_REGISTER_LOONGARCH
 # else
 #  error "Unsupported architecture."
 # endif
@@ -185,6 +196,7 @@
 # define _LIBUNWIND_TARGET_RISCV 1
 # define _LIBUNWIND_TARGET_VE 1
 # define _LIBUNWIND_TARGET_S390X 1
+#define _LIBUNWIND_TARGET_LOONGARCH 1
 # define _LIBUNWIND_CONTEXT_SIZE 167
 # define _LIBUNWIND_CURSOR_SIZE 179
 # define _LIBUNWIND_HIGHEST_DWARF_REGISTER 287

diff  --git a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h
index f878b46f0348..8c8cf8f53338 100644
--- a/libunwind/include/libunwind.h
+++ b/libunwind/include/libunwind.h
@@ -1219,4 +1219,72 @@ enum {
   // 68-83 Vector Registers %v16-%v31
 };
 
+// LoongArch registers.
+enum {
+  UNW_LOONGARCH_R0 = 0,
+  UNW_LOONGARCH_R1 = 1,
+  UNW_LOONGARCH_R2 = 2,
+  UNW_LOONGARCH_R3 = 3,
+  UNW_LOONGARCH_R4 = 4,
+  UNW_LOONGARCH_R5 = 5,
+  UNW_LOONGARCH_R6 = 6,
+  UNW_LOONGARCH_R7 = 7,
+  UNW_LOONGARCH_R8 = 8,
+  UNW_LOONGARCH_R9 = 9,
+  UNW_LOONGARCH_R10 = 10,
+  UNW_LOONGARCH_R11 = 11,
+  UNW_LOONGARCH_R12 = 12,
+  UNW_LOONGARCH_R13 = 13,
+  UNW_LOONGARCH_R14 = 14,
+  UNW_LOONGARCH_R15 = 15,
+  UNW_LOONGARCH_R16 = 16,
+  UNW_LOONGARCH_R17 = 17,
+  UNW_LOONGARCH_R18 = 18,
+  UNW_LOONGARCH_R19 = 19,
+  UNW_LOONGARCH_R20 = 20,
+  UNW_LOONGARCH_R21 = 21,
+  UNW_LOONGARCH_R22 = 22,
+  UNW_LOONGARCH_R23 = 23,
+  UNW_LOONGARCH_R24 = 24,
+  UNW_LOONGARCH_R25 = 25,
+  UNW_LOONGARCH_R26 = 26,
+  UNW_LOONGARCH_R27 = 27,
+  UNW_LOONGARCH_R28 = 28,
+  UNW_LOONGARCH_R29 = 29,
+  UNW_LOONGARCH_R30 = 30,
+  UNW_LOONGARCH_R31 = 31,
+  UNW_LOONGARCH_F0 = 32,
+  UNW_LOONGARCH_F1 = 33,
+  UNW_LOONGARCH_F2 = 34,
+  UNW_LOONGARCH_F3 = 35,
+  UNW_LOONGARCH_F4 = 36,
+  UNW_LOONGARCH_F5 = 37,
+  UNW_LOONGARCH_F6 = 38,
+  UNW_LOONGARCH_F7 = 39,
+  UNW_LOONGARCH_F8 = 40,
+  UNW_LOONGARCH_F9 = 41,
+  UNW_LOONGARCH_F10 = 42,
+  UNW_LOONGARCH_F11 = 43,
+  UNW_LOONGARCH_F12 = 44,
+  UNW_LOONGARCH_F13 = 45,
+  UNW_LOONGARCH_F14 = 46,
+  UNW_LOONGARCH_F15 = 47,
+  UNW_LOONGARCH_F16 = 48,
+  UNW_LOONGARCH_F17 = 49,
+  UNW_LOONGARCH_F18 = 50,
+  UNW_LOONGARCH_F19 = 51,
+  UNW_LOONGARCH_F20 = 52,
+  UNW_LOONGARCH_F21 = 53,
+  UNW_LOONGARCH_F22 = 54,
+  UNW_LOONGARCH_F23 = 55,
+  UNW_LOONGARCH_F24 = 56,
+  UNW_LOONGARCH_F25 = 57,
+  UNW_LOONGARCH_F26 = 58,
+  UNW_LOONGARCH_F27 = 59,
+  UNW_LOONGARCH_F28 = 60,
+  UNW_LOONGARCH_F29 = 61,
+  UNW_LOONGARCH_F30 = 62,
+  UNW_LOONGARCH_F31 = 63,
+};
+
 #endif

diff  --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp
index e5fde6888fe6..ff736ca9e8b3 100644
--- a/libunwind/src/Registers.hpp
+++ b/libunwind/src/Registers.hpp
@@ -40,6 +40,7 @@ enum {
   REGISTERS_RISCV,
   REGISTERS_VE,
   REGISTERS_S390X,
+  REGISTERS_LOONGARCH,
 };
 
 #if defined(_LIBUNWIND_TARGET_I386)
@@ -5031,6 +5032,271 @@ inline const char *Registers_s390x::getRegisterName(int regNum) {
 }
 #endif // _LIBUNWIND_TARGET_S390X
 
+#if defined(_LIBUNWIND_TARGET_LOONGARCH)
+/// Registers_loongarch holds the register state of a thread in a 64-bit
+/// LoongArch process.
+class _LIBUNWIND_HIDDEN Registers_loongarch {
+public:
+  Registers_loongarch();
+  Registers_loongarch(const void *registers);
+
+  bool validRegister(int num) const;
+  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);
+  bool validVectorRegister(int num) const;
+  v128 getVectorRegister(int num) const;
+  void setVectorRegister(int num, v128 value);
+  static const char *getRegisterName(int num);
+  void jumpto();
+  static constexpr int lastDwarfRegNum() {
+    return _LIBUNWIND_HIGHEST_DWARF_REGISTER_LOONGARCH;
+  }
+  static int getArch() { return REGISTERS_LOONGARCH; }
+
+  uint64_t getSP() const { return _registers.__r[3]; }
+  void setSP(uint64_t value) { _registers.__r[3] = value; }
+  uint64_t getIP() const { return _registers.__pc; }
+  void setIP(uint64_t value) { _registers.__pc = value; }
+
+private:
+  struct loongarch_thread_state_t {
+    uint64_t __r[32];
+    uint64_t __pc;
+  };
+
+  loongarch_thread_state_t _registers;
+#if __loongarch_frlen == 64
+  double _floats[32];
+#endif
+};
+
+inline Registers_loongarch::Registers_loongarch(const void *registers) {
+  static_assert((check_fit<Registers_loongarch, unw_context_t>::does_fit),
+                "loongarch registers do not fit into unw_context_t");
+  memcpy(&_registers, registers, sizeof(_registers));
+  static_assert(sizeof(_registers) == 0x108,
+                "expected float registers to be at offset 264");
+#if __loongarch_frlen == 64
+  memcpy(_floats, static_cast<const uint8_t *>(registers) + sizeof(_registers),
+         sizeof(_floats));
+#endif
+}
+
+inline Registers_loongarch::Registers_loongarch() {
+  memset(&_registers, 0, sizeof(_registers));
+#if __loongarch_frlen == 64
+  memset(&_floats, 0, sizeof(_floats));
+#endif
+}
+
+inline bool Registers_loongarch::validRegister(int regNum) const {
+  if (regNum == UNW_REG_IP || regNum == UNW_REG_SP)
+    return true;
+  if (regNum < 0 || regNum > UNW_LOONGARCH_F31)
+    return false;
+  return true;
+}
+
+inline uint64_t Registers_loongarch::getRegister(int regNum) const {
+  if (regNum >= UNW_LOONGARCH_R0 && regNum <= UNW_LOONGARCH_R31)
+    return _registers.__r[regNum - UNW_LOONGARCH_R0];
+
+  if (regNum == UNW_REG_IP)
+    return _registers.__pc;
+  if (regNum == UNW_REG_SP)
+    return _registers.__r[3];
+  _LIBUNWIND_ABORT("unsupported loongarch register");
+}
+
+inline void Registers_loongarch::setRegister(int regNum, uint64_t value) {
+  if (regNum >= UNW_LOONGARCH_R0 && regNum <= UNW_LOONGARCH_R31)
+    _registers.__r[regNum - UNW_LOONGARCH_R0] = value;
+  else if (regNum == UNW_REG_IP)
+    _registers.__pc = value;
+  else if (regNum == UNW_REG_SP)
+    _registers.__r[3] = value;
+  else
+    _LIBUNWIND_ABORT("unsupported loongarch register");
+}
+
+inline const char *Registers_loongarch::getRegisterName(int regNum) {
+  switch (regNum) {
+  case UNW_REG_IP:
+    return "$pc";
+  case UNW_REG_SP:
+    return "$sp";
+  case UNW_LOONGARCH_R0:
+    return "$r0";
+  case UNW_LOONGARCH_R1:
+    return "$r1";
+  case UNW_LOONGARCH_R2:
+    return "$r2";
+  case UNW_LOONGARCH_R3:
+    return "$r3";
+  case UNW_LOONGARCH_R4:
+    return "$r4";
+  case UNW_LOONGARCH_R5:
+    return "$r5";
+  case UNW_LOONGARCH_R6:
+    return "$r6";
+  case UNW_LOONGARCH_R7:
+    return "$r7";
+  case UNW_LOONGARCH_R8:
+    return "$r8";
+  case UNW_LOONGARCH_R9:
+    return "$r9";
+  case UNW_LOONGARCH_R10:
+    return "$r10";
+  case UNW_LOONGARCH_R11:
+    return "$r11";
+  case UNW_LOONGARCH_R12:
+    return "$r12";
+  case UNW_LOONGARCH_R13:
+    return "$r13";
+  case UNW_LOONGARCH_R14:
+    return "$r14";
+  case UNW_LOONGARCH_R15:
+    return "$r15";
+  case UNW_LOONGARCH_R16:
+    return "$r16";
+  case UNW_LOONGARCH_R17:
+    return "$r17";
+  case UNW_LOONGARCH_R18:
+    return "$r18";
+  case UNW_LOONGARCH_R19:
+    return "$r19";
+  case UNW_LOONGARCH_R20:
+    return "$r20";
+  case UNW_LOONGARCH_R21:
+    return "$r21";
+  case UNW_LOONGARCH_R22:
+    return "$r22";
+  case UNW_LOONGARCH_R23:
+    return "$r23";
+  case UNW_LOONGARCH_R24:
+    return "$r24";
+  case UNW_LOONGARCH_R25:
+    return "$r25";
+  case UNW_LOONGARCH_R26:
+    return "$r26";
+  case UNW_LOONGARCH_R27:
+    return "$r27";
+  case UNW_LOONGARCH_R28:
+    return "$r28";
+  case UNW_LOONGARCH_R29:
+    return "$r29";
+  case UNW_LOONGARCH_R30:
+    return "$r30";
+  case UNW_LOONGARCH_R31:
+    return "$r31";
+  case UNW_LOONGARCH_F0:
+    return "$f0";
+  case UNW_LOONGARCH_F1:
+    return "$f1";
+  case UNW_LOONGARCH_F2:
+    return "$f2";
+  case UNW_LOONGARCH_F3:
+    return "$f3";
+  case UNW_LOONGARCH_F4:
+    return "$f4";
+  case UNW_LOONGARCH_F5:
+    return "$f5";
+  case UNW_LOONGARCH_F6:
+    return "$f6";
+  case UNW_LOONGARCH_F7:
+    return "$f7";
+  case UNW_LOONGARCH_F8:
+    return "$f8";
+  case UNW_LOONGARCH_F9:
+    return "$f9";
+  case UNW_LOONGARCH_F10:
+    return "$f10";
+  case UNW_LOONGARCH_F11:
+    return "$f11";
+  case UNW_LOONGARCH_F12:
+    return "$f12";
+  case UNW_LOONGARCH_F13:
+    return "$f13";
+  case UNW_LOONGARCH_F14:
+    return "$f14";
+  case UNW_LOONGARCH_F15:
+    return "$f15";
+  case UNW_LOONGARCH_F16:
+    return "$f16";
+  case UNW_LOONGARCH_F17:
+    return "$f17";
+  case UNW_LOONGARCH_F18:
+    return "$f18";
+  case UNW_LOONGARCH_F19:
+    return "$f19";
+  case UNW_LOONGARCH_F20:
+    return "$f20";
+  case UNW_LOONGARCH_F21:
+    return "$f21";
+  case UNW_LOONGARCH_F22:
+    return "$f22";
+  case UNW_LOONGARCH_F23:
+    return "$f23";
+  case UNW_LOONGARCH_F24:
+    return "$f24";
+  case UNW_LOONGARCH_F25:
+    return "$f25";
+  case UNW_LOONGARCH_F26:
+    return "$f26";
+  case UNW_LOONGARCH_F27:
+    return "$f27";
+  case UNW_LOONGARCH_F28:
+    return "$f28";
+  case UNW_LOONGARCH_F29:
+    return "$f29";
+  case UNW_LOONGARCH_F30:
+    return "$f30";
+  case UNW_LOONGARCH_F31:
+    return "$f31";
+  default:
+    return "unknown register";
+  }
+}
+
+inline bool Registers_loongarch::validFloatRegister(int regNum) const {
+  if (regNum < UNW_LOONGARCH_F0 || regNum > UNW_LOONGARCH_F31)
+    return false;
+  return true;
+}
+
+inline double Registers_loongarch::getFloatRegister(int regNum) const {
+#if __loongarch_frlen == 64
+  assert(validFloatRegister(regNum));
+  return _floats[regNum - UNW_LOONGARCH_F0];
+#else
+  _LIBUNWIND_ABORT("libunwind not built with float support");
+#endif
+}
+
+inline void Registers_loongarch::setFloatRegister(int regNum, double value) {
+#if __loongarch_frlen == 64
+  assert(validFloatRegister(regNum));
+  _floats[regNum - UNW_LOONGARCH_F0] = value;
+#else
+  _LIBUNWIND_ABORT("libunwind not built with float support");
+#endif
+}
+
+inline bool Registers_loongarch::validVectorRegister(int) const {
+  return false;
+}
+
+inline v128 Registers_loongarch::getVectorRegister(int) const {
+  _LIBUNWIND_ABORT("loongarch vector support not implemented");
+}
+
+inline void Registers_loongarch::setVectorRegister(int, v128) {
+  _LIBUNWIND_ABORT("loongarch vector support not implemented");
+}
+#endif //_LIBUNWIND_TARGET_LOONGARCH
 
 } // namespace libunwind
 

diff  --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index f1184970f3ce..0c6cda3604a2 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -1064,6 +1064,10 @@ class UnwindCursor : public AbstractUnwindCursor{
   }
 #endif
 
+#if defined(_LIBUNWIND_TARGET_LOONGARCH)
+  int stepWithCompactEncoding(Registers_loongarch &) { return UNW_EINVAL; }
+#endif
+
 #if defined(_LIBUNWIND_TARGET_SPARC)
   int stepWithCompactEncoding(Registers_sparc &) { return UNW_EINVAL; }
 #endif
@@ -1140,6 +1144,12 @@ class UnwindCursor : public AbstractUnwindCursor{
   }
 #endif
 
+#if defined(_LIBUNWIND_TARGET_LOONGARCH)
+  bool compactSaysUseDwarf(Registers_loongarch &, uint32_t *) const {
+    return true;
+  }
+#endif
+
 #if defined(_LIBUNWIND_TARGET_SPARC)
   bool compactSaysUseDwarf(Registers_sparc &, uint32_t *) const { return true; }
 #endif
@@ -1224,6 +1234,12 @@ class UnwindCursor : public AbstractUnwindCursor{
   }
 #endif
 
+#if defined(_LIBUNWIND_TARGET_LOONGARCH)
+  compact_unwind_encoding_t dwarfEncoding(Registers_loongarch &) const {
+    return 0;
+  }
+#endif
+
 #if defined(_LIBUNWIND_TARGET_SPARC)
   compact_unwind_encoding_t dwarfEncoding(Registers_sparc &) const { return 0; }
 #endif

diff  --git a/libunwind/src/UnwindRegistersRestore.S b/libunwind/src/UnwindRegistersRestore.S
index 62f8f82b8391..08f208ec7c2d 100644
--- a/libunwind/src/UnwindRegistersRestore.S
+++ b/libunwind/src/UnwindRegistersRestore.S
@@ -1289,6 +1289,88 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_s390x6jumptoEv)
   // Return to PSWA (was loaded into %r1 above)
   br %r1
 
+#elif defined(__loongarch__) && __loongarch_grlen == 64
+
+//
+// void libunwind::Registers_loongarch::jumpto()
+//
+// On entry:
+//  thread_state pointer is in $a0($r4)
+//
+  .p2align 2
+DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind19Registers_loongarch6jumptoEv)
+# if __loongarch_frlen == 64
+  fld.d    $f0, $a0, (8 * 33 + 8 * 0)
+  fld.d    $f1, $a0, (8 * 33 + 8 * 1)
+  fld.d    $f2, $a0, (8 * 33 + 8 * 2)
+  fld.d    $f3, $a0, (8 * 33 + 8 * 3)
+  fld.d    $f4, $a0, (8 * 33 + 8 * 4)
+  fld.d    $f5, $a0, (8 * 33 + 8 * 5)
+  fld.d    $f6, $a0, (8 * 33 + 8 * 6)
+  fld.d    $f7, $a0, (8 * 33 + 8 * 7)
+  fld.d    $f8, $a0, (8 * 33 + 8 * 8)
+  fld.d    $f9, $a0, (8 * 33 + 8 * 9)
+  fld.d    $f10, $a0, (8 * 33 + 8 * 10)
+  fld.d    $f11, $a0, (8 * 33 + 8 * 11)
+  fld.d    $f12, $a0, (8 * 33 + 8 * 12)
+  fld.d    $f13, $a0, (8 * 33 + 8 * 13)
+  fld.d    $f14, $a0, (8 * 33 + 8 * 14)
+  fld.d    $f15, $a0, (8 * 33 + 8 * 15)
+  fld.d    $f16, $a0, (8 * 33 + 8 * 16)
+  fld.d    $f17, $a0, (8 * 33 + 8 * 17)
+  fld.d    $f18, $a0, (8 * 33 + 8 * 18)
+  fld.d    $f19, $a0, (8 * 33 + 8 * 19)
+  fld.d    $f20, $a0, (8 * 33 + 8 * 20)
+  fld.d    $f21, $a0, (8 * 33 + 8 * 21)
+  fld.d    $f22, $a0, (8 * 33 + 8 * 22)
+  fld.d    $f23, $a0, (8 * 33 + 8 * 23)
+  fld.d    $f24, $a0, (8 * 33 + 8 * 24)
+  fld.d    $f25, $a0, (8 * 33 + 8 * 25)
+  fld.d    $f26, $a0, (8 * 33 + 8 * 26)
+  fld.d    $f27, $a0, (8 * 33 + 8 * 27)
+  fld.d    $f28, $a0, (8 * 33 + 8 * 28)
+  fld.d    $f29, $a0, (8 * 33 + 8 * 29)
+  fld.d    $f30, $a0, (8 * 33 + 8 * 30)
+  fld.d    $f31, $a0, (8 * 33 + 8 * 31)
+# endif
+
+  // $r0 is zero
+  ld.d    $r1, $a0, (8 * 1)
+  ld.d    $r2, $a0, (8 * 2)
+  ld.d    $r3, $a0, (8 * 3)
+  // skip $a0 for now
+  ld.d    $r5, $a0, (8 * 5)
+  ld.d    $r6, $a0, (8 * 6)
+  ld.d    $r7, $a0, (8 * 7)
+  ld.d    $r8, $a0, (8 * 8)
+  ld.d    $r9, $a0, (8 * 9)
+  ld.d    $r10, $a0, (8 * 10)
+  ld.d    $r11, $a0, (8 * 11)
+  ld.d    $r12, $a0, (8 * 12)
+  ld.d    $r13, $a0, (8 * 13)
+  ld.d    $r14, $a0, (8 * 14)
+  ld.d    $r15, $a0, (8 * 15)
+  ld.d    $r16, $a0, (8 * 16)
+  ld.d    $r17, $a0, (8 * 17)
+  ld.d    $r18, $a0, (8 * 18)
+  ld.d    $r19, $a0, (8 * 19)
+  ld.d    $r20, $a0, (8 * 20)
+  ld.d    $r21, $a0, (8 * 21)
+  ld.d    $r22, $a0, (8 * 22)
+  ld.d    $r23, $a0, (8 * 23)
+  ld.d    $r24, $a0, (8 * 24)
+  ld.d    $r25, $a0, (8 * 25)
+  ld.d    $r26, $a0, (8 * 26)
+  ld.d    $r27, $a0, (8 * 27)
+  ld.d    $r28, $a0, (8 * 28)
+  ld.d    $r29, $a0, (8 * 29)
+  ld.d    $r30, $a0, (8 * 30)
+  ld.d    $r31, $a0, (8 * 31)
+  ld.d    $r4,  $a0, (8 * 4)   // restore $a0 last
+  ld.d    $r1,  $a0, (8 * 32)  // load new pc into $ra
+
+  jr      $ra
+
 #endif
 
 #endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */

diff  --git a/libunwind/src/UnwindRegistersSave.S b/libunwind/src/UnwindRegistersSave.S
index f57dd637dd9d..b3899bf12204 100644
--- a/libunwind/src/UnwindRegistersSave.S
+++ b/libunwind/src/UnwindRegistersSave.S
@@ -1222,6 +1222,86 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
   lghi %r2, 0
   br %r14
 
+#elif defined(__loongarch__) && __loongarch_grlen == 64
+
+#
+# extern int __unw_getcontext(unw_context_t* thread_state)
+#
+# On entry:
+#  thread_state pointer is in $a0($r4)
+#
+DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
+  st.d    $r1, $a0, (8 * 1)
+  st.d    $r2, $a0, (8 * 2)
+  st.d    $r3, $a0, (8 * 3)
+  st.d    $r4, $a0, (8 * 4)
+  st.d    $r5, $a0, (8 * 5)
+  st.d    $r6, $a0, (8 * 6)
+  st.d    $r7, $a0, (8 * 7)
+  st.d    $r8, $a0, (8 * 8)
+  st.d    $r9, $a0, (8 * 9)
+  st.d    $r10, $a0, (8 * 10)
+  st.d    $r11, $a0, (8 * 11)
+  st.d    $r12, $a0, (8 * 12)
+  st.d    $r13, $a0, (8 * 13)
+  st.d    $r14, $a0, (8 * 14)
+  st.d    $r15, $a0, (8 * 15)
+  st.d    $r16, $a0, (8 * 16)
+  st.d    $r17, $a0, (8 * 17)
+  st.d    $r18, $a0, (8 * 18)
+  st.d    $r19, $a0, (8 * 19)
+  st.d    $r20, $a0, (8 * 20)
+  st.d    $r21, $a0, (8 * 21)
+  st.d    $r22, $a0, (8 * 22)
+  st.d    $r23, $a0, (8 * 23)
+  st.d    $r24, $a0, (8 * 24)
+  st.d    $r25, $a0, (8 * 25)
+  st.d    $r26, $a0, (8 * 26)
+  st.d    $r27, $a0, (8 * 27)
+  st.d    $r28, $a0, (8 * 28)
+  st.d    $r29, $a0, (8 * 29)
+  st.d    $r30, $a0, (8 * 30)
+  st.d    $r31, $a0, (8 * 31)
+  st.d    $r1,  $a0, (8 * 32) // store $ra to pc
+
+# if __loongarch_frlen == 64
+  fst.d    $f0, $a0, (8 * 33 + 8 * 0)
+  fst.d    $f1, $a0, (8 * 33 + 8 * 1)
+  fst.d    $f2, $a0, (8 * 33 + 8 * 2)
+  fst.d    $f3, $a0, (8 * 33 + 8 * 3)
+  fst.d    $f4, $a0, (8 * 33 + 8 * 4)
+  fst.d    $f5, $a0, (8 * 33 + 8 * 5)
+  fst.d    $f6, $a0, (8 * 33 + 8 * 6)
+  fst.d    $f7, $a0, (8 * 33 + 8 * 7)
+  fst.d    $f8, $a0, (8 * 33 + 8 * 8)
+  fst.d    $f9, $a0, (8 * 33 + 8 * 9)
+  fst.d    $f10, $a0, (8 * 33 + 8 * 10)
+  fst.d    $f11, $a0, (8 * 33 + 8 * 11)
+  fst.d    $f12, $a0, (8 * 33 + 8 * 12)
+  fst.d    $f13, $a0, (8 * 33 + 8 * 13)
+  fst.d    $f14, $a0, (8 * 33 + 8 * 14)
+  fst.d    $f15, $a0, (8 * 33 + 8 * 15)
+  fst.d    $f16, $a0, (8 * 33 + 8 * 16)
+  fst.d    $f17, $a0, (8 * 33 + 8 * 17)
+  fst.d    $f18, $a0, (8 * 33 + 8 * 18)
+  fst.d    $f19, $a0, (8 * 33 + 8 * 19)
+  fst.d    $f20, $a0, (8 * 33 + 8 * 20)
+  fst.d    $f21, $a0, (8 * 33 + 8 * 21)
+  fst.d    $f22, $a0, (8 * 33 + 8 * 22)
+  fst.d    $f23, $a0, (8 * 33 + 8 * 23)
+  fst.d    $f24, $a0, (8 * 33 + 8 * 24)
+  fst.d    $f25, $a0, (8 * 33 + 8 * 25)
+  fst.d    $f26, $a0, (8 * 33 + 8 * 26)
+  fst.d    $f27, $a0, (8 * 33 + 8 * 27)
+  fst.d    $f28, $a0, (8 * 33 + 8 * 28)
+  fst.d    $f29, $a0, (8 * 33 + 8 * 29)
+  fst.d    $f30, $a0, (8 * 33 + 8 * 30)
+  fst.d    $f31, $a0, (8 * 33 + 8 * 31)
+# endif
+
+  move     $a0, $zero  // UNW_ESUCCESS
+  jr       $ra
+
 #endif
 
   WEAK_ALIAS(__unw_getcontext, unw_getcontext)

diff  --git a/libunwind/src/config.h b/libunwind/src/config.h
index cc41b817acf6..4bbac951624f 100644
--- a/libunwind/src/config.h
+++ b/libunwind/src/config.h
@@ -115,7 +115,7 @@
 #if defined(__i386__) || defined(__x86_64__) || defined(__powerpc__) ||        \
     (!defined(__APPLE__) && defined(__arm__)) || defined(__aarch64__) ||       \
     defined(__mips__) || defined(__riscv) || defined(__hexagon__) ||           \
-    defined(__sparc__) || defined(__s390x__)
+    defined(__sparc__) || defined(__s390x__) || defined(__loongarch__)
 #if !defined(_LIBUNWIND_BUILD_SJLJ_APIS)
 #define _LIBUNWIND_BUILD_ZERO_COST_APIS
 #endif

diff  --git a/libunwind/src/libunwind.cpp b/libunwind/src/libunwind.cpp
index 292544d91429..0faea2b78570 100644
--- a/libunwind/src/libunwind.cpp
+++ b/libunwind/src/libunwind.cpp
@@ -77,6 +77,8 @@ _LIBUNWIND_HIDDEN int __unw_init_local(unw_cursor_t *cursor,
 # define REGISTER_KIND Registers_ve
 #elif defined(__s390x__)
 # define REGISTER_KIND Registers_s390x
+#elif defined(__loongarch__) && __loongarch_grlen == 64
+#define REGISTER_KIND Registers_loongarch
 #else
 # error Architecture not supported
 #endif


        


More information about the cfe-commits mailing list