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]