This is an automated email from the ASF dual-hosted git repository.

wwbmmm pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/brpc.git


The following commit(s) were added to refs/heads/master by this push:
     new d88f077d Add support for loongarch64 (#2364)
d88f077d is described below

commit d88f077de27f1ae05b34639a77d35a5a0c2c8516
Author: [email protected] 
<[email protected]>
AuthorDate: Wed Oct 25 15:02:40 2023 +0800

    Add support for loongarch64 (#2364)
---
 src/bthread/context.cpp                         |  90 ++++++++++
 src/bthread/context.h                           |   3 +
 src/bthread/processor.h                         |   2 +
 src/butil/atomicops.h                           |   2 +
 src/butil/atomicops_internals_loongarch64_gcc.h | 223 ++++++++++++++++++++++++
 src/butil/build_config.h                        |   5 +
 src/butil/debug/debugger_posix.cc               |   2 +
 src/butil/time.h                                |   8 +
 test/bthread_work_stealing_queue_unittest.cpp   |   2 +
 9 files changed, 337 insertions(+)

diff --git a/src/bthread/context.cpp b/src/bthread/context.cpp
index b89d432a..bafa927d 100644
--- a/src/bthread/context.cpp
+++ b/src/bthread/context.cpp
@@ -810,3 +810,93 @@ __asm (
 
 #endif
 
+#if defined(BTHREAD_CONTEXT_PLATFORM_linux_loongarch64) && 
defined(BTHREAD_CONTEXT_COMPILER_gcc)
+__asm (
+".text\n"
+".align  3\n"
+".global bthread_jump_fcontext\n"
+".type   bthread_jump_fcontext, %function\n"
+"bthread_jump_fcontext:\n"
+"      addi.d  $sp, $sp, -160\n"
+
+"      st.d    $s0, $sp, 64    # save S0\n"
+"      st.d    $s1, $sp, 72    # save S1\n"
+"      st.d    $s2, $sp, 80    # save S2\n"
+"      st.d    $s3, $sp, 88    # save S3\n"
+"      st.d    $s4, $sp, 96    # save S4\n"
+"      st.d    $s5, $sp, 104   # save S5\n"
+"      st.d    $s6, $sp, 112   # save S6\n"
+"      st.d    $s7, $sp, 120   # save S7\n"
+"      st.d    $s8, $sp, 128   # save S8\n"
+"      st.d    $fp, $sp, 136   # save FP\n"
+"      st.d    $ra, $sp, 144   # save RA\n"
+"      st.d    $ra, $sp, 152   # save RA as PC\n"
+
+"      fst.d   $fs0, $sp, 0    # save F24\n"
+"      fst.d   $fs1, $sp, 8    # save F25\n"
+"      fst.d   $fs2, $sp, 16   # save F26\n"
+"      fst.d   $fs3, $sp, 24   # save F27\n"
+"      fst.d   $fs4, $sp, 32   # save F28\n"
+"      fst.d   $fs5, $sp, 40   # save F29\n"
+"      fst.d   $fs6, $sp, 48   # save F30\n"
+"      fst.d   $fs7, $sp, 56   # save F31\n"
+
+"      # swap a0(new stack), sp(old stack)\n"
+" st.d $sp, $a0, 0\n"
+" or           $sp, $a1, $zero\n"
+
+"      fld.d   $fs0, $sp, 0    # restore F24\n"
+"      fld.d   $fs1, $sp, 8    # restore F25\n"
+"      fld.d   $fs2, $sp, 16   # restore F26\n"
+"      fld.d   $fs3, $sp, 24   # restore F27\n"
+"      fld.d   $fs4, $sp, 32   # restore F28\n"
+"      fld.d   $fs5, $sp, 40   # restore F29\n"
+"      fld.d   $fs6, $sp, 48   # restore F30\n"
+"      fld.d   $fs7, $sp, 56   # restore F31\n"
+
+"      ld.d    $s0, $sp, 64    # restore S0\n"
+"      ld.d    $s1, $sp, 72    # restore S1\n"
+"      ld.d    $s2, $sp, 80    # restore S2\n"
+"      ld.d    $s3, $sp, 88    # restore S3\n"
+"      ld.d    $s4, $sp, 96    # restore S4\n"
+"      ld.d    $s5, $sp, 104   # restore S5\n"
+"      ld.d    $s6, $sp, 112   # restore S6\n"
+"      ld.d    $s7, $sp, 120   # restore S7\n"
+"      ld.d    $s8, $sp, 128   # restore S8\n"
+"      ld.d    $fp, $sp, 136   # restore FP\n"
+"      ld.d    $ra, $sp, 144   # restore RA\n"
+
+" or           $a0, $a2, $zero \n"
+"      # load PC\n"
+"      ld.d    $a4, $sp, 152\n"
+
+"      # adjust stack\n"
+"      addi.d  $sp, $sp, 160\n"
+
+"      # jump to context\n"
+"      jirl    $zero, $a4, 0\n"
+);
+#endif
+
+#if defined(BTHREAD_CONTEXT_PLATFORM_linux_loongarch64) && 
defined(BTHREAD_CONTEXT_COMPILER_gcc)
+__asm (
+".text\n"
+".align  3\n"
+".global bthread_make_fcontext\n"
+".type   bthread_make_fcontext, %function\n"
+"bthread_make_fcontext:\n"
+//"    andi    $a0, $a0, ~0xF\n"
+"      addi.d  $a0, $a0, -160\n"
+
+"      st.d    $a2, $a0, 152\n"
+
+"      pcaddi  $a1, 3\n"
+"      st.d    $a1, $a0, 144\n"
+"      jirl $zero, $ra, 0\n"
+
+"finish:\n"
+" or   $a0, $zero, $zero\n"
+" bl _exit\n"
+);
+
+#endif
diff --git a/src/bthread/context.h b/src/bthread/context.h
index ef98e458..8de85af6 100644
--- a/src/bthread/context.h
+++ b/src/bthread/context.h
@@ -39,6 +39,9 @@
        #elif __aarch64__
            #define BTHREAD_CONTEXT_PLATFORM_linux_arm64
            #define BTHREAD_CONTEXT_CALL_CONVENTION
+        #elif __loongarch64
+            #define BTHREAD_CONTEXT_PLATFORM_linux_loongarch64
+            #define BTHREAD_CONTEXT_CALL_CONVENTION
        #endif
 
   #elif defined(__MINGW32__) || defined (__MINGW64__)
diff --git a/src/bthread/processor.h b/src/bthread/processor.h
index 2f5badf9..f8939234 100644
--- a/src/bthread/processor.h
+++ b/src/bthread/processor.h
@@ -28,6 +28,8 @@
 # ifndef cpu_relax
 #if defined(ARCH_CPU_ARM_FAMILY)
 # define cpu_relax() asm volatile("yield\n": : :"memory")
+#elif defined(ARCH_CPU_LOONGARCH64_FAMILY)
+# define cpu_relax() asm volatile("nop\n": : :"memory");
 #else
 # define cpu_relax() asm volatile("pause\n": : :"memory")
 #endif
diff --git a/src/butil/atomicops.h b/src/butil/atomicops.h
index ba6b0fd9..cda1529f 100644
--- a/src/butil/atomicops.h
+++ b/src/butil/atomicops.h
@@ -155,6 +155,8 @@ Atomic64 Release_Load(volatile const Atomic64* ptr);
 #include "butil/atomicops_internals_x86_gcc.h"
 #elif defined(COMPILER_GCC) && defined(ARCH_CPU_MIPS_FAMILY)
 #include "butil/atomicops_internals_mips_gcc.h"
+#elif defined(COMPILER_GCC) && defined(ARCH_CPU_LOONGARCH64_FAMILY)
+#include "butil/atomicops_internals_loongarch64_gcc.h"
 #else
 #error "Atomic operations are not supported on your platform"
 #endif
diff --git a/src/butil/atomicops_internals_loongarch64_gcc.h 
b/src/butil/atomicops_internals_loongarch64_gcc.h
new file mode 100644
index 00000000..07654c8a
--- /dev/null
+++ b/src/butil/atomicops_internals_loongarch64_gcc.h
@@ -0,0 +1,223 @@
+// Copyright (c) 2023 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is an internal atomic implementation, use butil/atomicops.h 
instead.
+
+#ifndef BUTIL_ATOMICOPS_INTERNALS_LOONGARCH64_GCC_H_
+#define BUTIL_ATOMICOPS_INTERNALS_LOONGARCH64_GCC_H_
+
+#include "butil/atomicops.h"
+#include "butil/atomicops_internals_loongarch64_gcc.h"
+
+namespace butil {
+namespace subtle {
+
+// 32bit
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+                                         Atomic32 old_value,
+                                         Atomic32 new_value) {
+  Atomic32 ret;
+  __asm__ __volatile__("1:\n"
+                       "ll.w %0, %1\n"
+                       "or   $t0, %3, $zero\n"            
+                       "bne  %0, %2, 2f\n"
+                       "sc.w $t0, %1\n"
+                       "beqz $t0, 1b\n"
+                       "2:\n"
+                       "dbar 0\n"
+                       : "=&r" (ret), "+ZB"(*ptr)
+                       : "r" (old_value), "r" (new_value)
+                       : "t0", "memory");
+  return ret;
+}
+
+// Atomically store new_value into *ptr, returning the previous value held in
+// *ptr.  This routine implies no memory barriers.
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+                                         Atomic32 new_value) {
+  Atomic32 ret;
+  __asm__ __volatile__("amswap_db.w %0, %2, %1\n"
+                       : "=&r"(ret), "+ZB"(*ptr)
+                       : "r"(new_value)
+                       : "memory");
+  return ret;
+}
+
+// Atomically increment *ptr by "increment".  Returns the new value of
+// *ptr with the increment applied.  This routine implies no memory barriers.
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+                                          Atomic32 increment) {
+  Atomic32 tmp;
+  __asm__ __volatile__("amadd_db.w  %1, %2, %0\n"
+                       : "+ZB"(*ptr), "=&r"(tmp)
+                       : "r"(increment)
+                       : "memory");
+  return tmp+increment;
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+                                        Atomic32 increment) {
+  MemoryBarrier();
+  Atomic32 res = NoBarrier_AtomicIncrement(ptr, increment);
+  MemoryBarrier();
+  return res;
+}
+
+// "Acquire" operations
+// ensure that no later memory access can be reordered ahead of the operation.
+// "Release" operations ensure that no previous memory access can be reordered
+// after the operation.  "Barrier" operations have both "Acquire" and "Release"
+// semantics.   A MemoryBarrier() has "Barrier" semantics, but does no memory
+// access.
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  Atomic32 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+  MemoryBarrier();
+  return res;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  MemoryBarrier();
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+  MemoryBarrier();
+  *ptr = value;
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+  return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+  Atomic32 value = *ptr;
+  MemoryBarrier();
+  return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+// 64bit
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+                                         Atomic64 old_value,
+                                         Atomic64 new_value) {
+  Atomic64 ret;
+  __asm__ __volatile__("1:\n"
+                       "ll.d %0, %1\n"
+                       "or   $t0, %3, $zero\n"            
+                       "bne  %0, %2, 2f\n"
+                       "sc.d $t0, %1\n"
+                       "beqz $t0, 1b\n"
+                       "2:\n"
+                       "dbar 0\n"
+                       : "=&r" (ret), "+ZB"(*ptr)
+                       : "r" (old_value), "r" (new_value)
+                       : "t0", "memory");
+  return ret;
+}
+
+// Atomically store new_value into *ptr, returning the previous value held in
+// *ptr.  This routine implies no memory barriers.
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+                                         Atomic64 new_value) {
+  Atomic64 ret;
+  __asm__ __volatile__("amswap_db.d %0, %2, %1\n"
+                       : "=&r"(ret), "+ZB"(*ptr)
+                       : "r"(new_value)
+                       : "memory");
+  return ret;
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+                                          Atomic64 increment) {
+  Atomic64 tmp;
+  __asm__ __volatile__("amadd_db.d  %1, %2, %0\n"
+                       : "+ZB"(*ptr), "=&r"(tmp)
+                       : "r"(increment)
+                       : "memory");
+  return tmp+increment;
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
+                                        Atomic64 increment) {
+  MemoryBarrier();
+  Atomic64 res = NoBarrier_AtomicIncrement(ptr, increment);
+  MemoryBarrier();
+  return res;
+}
+
+// "Acquire" operations
+// ensure that no later memory access can be reordered ahead of the operation.
+// "Release" operations ensure that no previous memory access can be reordered
+// after the operation.  "Barrier" operations have both "Acquire" and "Release"
+// semantics.   A MemoryBarrier() has "Barrier" semantics, but does no memory
+// access.
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  Atomic64 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+  MemoryBarrier();
+  return res;
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  MemoryBarrier();
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+  *ptr = value;
+}
+
+inline void MemoryBarrier() {
+  __asm__ __volatile__("dbar 0x0" : : : "memory");
+}
+
+inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
+  *ptr = value;
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+  MemoryBarrier();
+  *ptr = value;
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+  return *ptr;
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+  Atomic64 value = *ptr;
+  MemoryBarrier();
+  return value;
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+} // namespace butil::subtle
+} // namespace butil
+
+#endif  // BUTIL_ATOMICOPS_INTERNALS_LOONGARCH64_GCC_H_
diff --git a/src/butil/build_config.h b/src/butil/build_config.h
index 03e2cf74..5ddf3821 100644
--- a/src/butil/build_config.h
+++ b/src/butil/build_config.h
@@ -133,6 +133,11 @@
 #define ARCH_CPU_32_BITS 1
 #define ARCH_CPU_LITTLE_ENDIAN 1
 #endif
+#elif defined(__loongarch64)
+#define ARCH_CPU_LOONGARCH64_FAMILY 1
+#define ARCH_CPU_LOONGARCH64 1
+#define ARCH_CPU_64_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
 #else
 #error Please add support for your architecture in butil/build_config.h
 #endif
diff --git a/src/butil/debug/debugger_posix.cc 
b/src/butil/debug/debugger_posix.cc
index 18529b78..0e463533 100644
--- a/src/butil/debug/debugger_posix.cc
+++ b/src/butil/debug/debugger_posix.cc
@@ -185,6 +185,8 @@ bool BeingDebugged() {
 #define DEBUG_BREAK_ASM() asm("bkpt 0")
 #elif defined(ARCH_CPU_ARM64)
 #define DEBUG_BREAK_ASM() asm("brk 0")
+#elif defined(ARCH_CPU_LOONGARCH64_FAMILY)
+#define DEBUG_BREAK_ASM() asm("break 0")
 #elif defined(ARCH_CPU_MIPS_FAMILY)
 #define DEBUG_BREAK_ASM() asm("break 2")
 #elif defined(ARCH_CPU_X86_FAMILY)
diff --git a/src/butil/time.h b/src/butil/time.h
index 00949f8e..005f551b 100644
--- a/src/butil/time.h
+++ b/src/butil/time.h
@@ -246,6 +246,14 @@ inline uint64_t clock_cycles() {
   #else
     #error "unsupported arm_arch"
   #endif
+#elif defined(__loongarch64)
+    uint64_t stable_counter;
+    uint64_t counter_id;
+    __asm__ __volatile__ (
+        "rdtime.d %1, %0"
+        : "=r" (stable_counter), "=r" (counter_id)
+        );
+    return stable_counter;
 #else
   #error "unsupported arch"
 #endif
diff --git a/test/bthread_work_stealing_queue_unittest.cpp 
b/test/bthread_work_stealing_queue_unittest.cpp
index 19514cdf..82897533 100644
--- a/test/bthread_work_stealing_queue_unittest.cpp
+++ b/test/bthread_work_stealing_queue_unittest.cpp
@@ -41,6 +41,8 @@ void* steal_thread(void* arg) {
         } else {
 #if defined(ARCH_CPU_ARM_FAMILY)
             asm volatile("yield\n": : :"memory");
+#elif defined(ARCH_CPU_LOONGARCH64_FAMILY)
+            asm volatile("nop\n": : :"memory");
 #else
             asm volatile("pause\n": : :"memory");
 #endif


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to