[libc-commits] [libc] 0f6fd1b - [libc] Add support for setjmp and longjmp in riscv

Mikhail R. Gadelha via libc-commits libc-commits at lists.llvm.org
Fri Mar 24 12:19:41 PDT 2023


Author: Mikhail R. Gadelha
Date: 2023-03-24T16:16:31-03:00
New Revision: 0f6fd1b704c014089f94271e08417a8179ee2b1c

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

LOG: [libc] Add support for setjmp and longjmp in riscv

This patch implements setjmp and longjmp in riscv using inline asm. The
following changes were required:

* Omit frame pointer: otherwise gcc won't allow us to use s0
* Use __attribute__((naked)): otherwise both gcc and clang will generate
function prologue and epilogue in both functions. This doesn't happen
in x86_64, so we guard it to only riscv

Furthermore, using __attribute__((naked)) causes two problems: we
can't use `return 0` (both gcc and clang) and the function arguments in
the function body (clang only), so we had to use a0 and a1 directly.

Reviewed By: sivachandra

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

Added: 
    libc/src/setjmp/riscv64/CMakeLists.txt
    libc/src/setjmp/riscv64/longjmp.cpp
    libc/src/setjmp/riscv64/setjmp.cpp
    libc/src/setjmp/x86_64/CMakeLists.txt
    libc/src/setjmp/x86_64/longjmp.cpp
    libc/src/setjmp/x86_64/setjmp.cpp

Modified: 
    clang/docs/tools/clang-formatted-files.txt
    libc/config/linux/riscv64/entrypoints.txt
    libc/config/linux/riscv64/headers.txt
    libc/include/llvm-libc-types/jmp_buf.h
    libc/src/setjmp/CMakeLists.txt

Removed: 
    libc/src/setjmp/longjmp.cpp
    libc/src/setjmp/setjmp.cpp


################################################################################
diff  --git a/clang/docs/tools/clang-formatted-files.txt b/clang/docs/tools/clang-formatted-files.txt
index 31d1dd7f365a2..4b70e78cb1131 100644
--- a/clang/docs/tools/clang-formatted-files.txt
+++ b/clang/docs/tools/clang-formatted-files.txt
@@ -2594,6 +2594,7 @@ libc/include/llvm-libc-types/fexcept_t.h
 libc/include/llvm-libc-types/FILE.h
 libc/include/llvm-libc-types/float_t.h
 libc/include/llvm-libc-types/imaxdiv_t.h
+libc/include/llvm-libc-types/jmp_buf.h
 libc/include/llvm-libc-types/ldiv_t.h
 libc/include/llvm-libc-types/lldiv_t.h
 libc/include/llvm-libc-types/mode_t.h

diff  --git a/libc/config/linux/riscv64/entrypoints.txt b/libc/config/linux/riscv64/entrypoints.txt
index 95e3c1e5bf509..b502df6d1ecf6 100644
--- a/libc/config/linux/riscv64/entrypoints.txt
+++ b/libc/config/linux/riscv64/entrypoints.txt
@@ -371,6 +371,10 @@ if(LLVM_LIBC_FULL_BUILD)
     # sched.h entrypoints
     libc.src.sched.__sched_getcpucount
 
+    # setjmp.h entrypoints
+    libc.src.setjmp.longjmp
+    libc.src.setjmp.setjmp
+
     # stdio.h entrypoints
     libc.src.stdio.clearerr
     libc.src.stdio.clearerr_unlocked

diff  --git a/libc/config/linux/riscv64/headers.txt b/libc/config/linux/riscv64/headers.txt
index 6d7e53790ec12..223b9ea506892 100644
--- a/libc/config/linux/riscv64/headers.txt
+++ b/libc/config/linux/riscv64/headers.txt
@@ -10,6 +10,7 @@ set(TARGET_PUBLIC_HEADERS
     libc.include.sched
     libc.include.signal
     libc.include.spawn
+    libc.include.setjmp
     libc.include.stdio
     libc.include.stdlib
     libc.include.string

diff  --git a/libc/include/llvm-libc-types/jmp_buf.h b/libc/include/llvm-libc-types/jmp_buf.h
index e948a7f42248a..6af4e8ebad92c 100644
--- a/libc/include/llvm-libc-types/jmp_buf.h
+++ b/libc/include/llvm-libc-types/jmp_buf.h
@@ -19,6 +19,19 @@ typedef struct {
   __UINT64_TYPE__ r15;
   __UINTPTR_TYPE__ rsp;
   __UINTPTR_TYPE__ rip;
+#elif defined(__riscv)
+  /* Program counter.  */
+  long int __pc;
+  /* Callee-saved registers.  */
+  long int __regs[12];
+  /* Stack pointer.  */
+  long int __sp;
+  /* Callee-saved floating point registers.  */
+#if __riscv_float_abi_double
+  double __fpregs[12];
+#elif defined(__riscv_float_abi_single)
+#error "__jmp_buf not available for your target architecture."
+#endif
 #else
 #error "__jmp_buf not available for your target architecture."
 #endif

diff  --git a/libc/src/setjmp/CMakeLists.txt b/libc/src/setjmp/CMakeLists.txt
index 5b79155cb4f05..d85c532e8636c 100644
--- a/libc/src/setjmp/CMakeLists.txt
+++ b/libc/src/setjmp/CMakeLists.txt
@@ -1,24 +1,17 @@
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE})
+  add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE})
+endif()
+
 add_entrypoint_object(
   setjmp
-  SRCS
-    setjmp.cpp
-  HDRS
-    setjmp_impl.h
-  COMPILE_OPTIONS
-    -O3 # We do not want any local variables in setjmp
-    -fno-omit-frame-pointer # The implementation assumes frame pointer on to the stack
+  ALIAS
   DEPENDS
-    libc.include.setjmp
+    .${LIBC_TARGET_ARCHITECTURE}.setjmp
 )
 
 add_entrypoint_object(
   longjmp
-  SRCS
-    longjmp.cpp
-  HDRS
-    longjmp.h
-  COMPILE_OPTIONS
-    -O3 # We do not want any local variables in longjmp
+  ALIAS
   DEPENDS
-    libc.include.setjmp
+    .${LIBC_TARGET_ARCHITECTURE}.longjmp
 )

diff  --git a/libc/src/setjmp/riscv64/CMakeLists.txt b/libc/src/setjmp/riscv64/CMakeLists.txt
new file mode 100644
index 0000000000000..8c6c8e204abd7
--- /dev/null
+++ b/libc/src/setjmp/riscv64/CMakeLists.txt
@@ -0,0 +1,25 @@
+add_entrypoint_object(
+  setjmp
+  SRCS
+    setjmp.cpp
+  HDRS
+    ../setjmp_impl.h
+  DEPENDS
+    libc.include.setjmp
+  COMPILE_OPTIONS
+    -O3
+    -fomit-frame-pointer
+)
+
+add_entrypoint_object(
+  longjmp
+  SRCS
+    longjmp.cpp
+  HDRS
+    ../longjmp.h
+  DEPENDS
+    libc.include.setjmp
+  COMPILE_OPTIONS
+    -O3
+    -fomit-frame-pointer
+)

diff  --git a/libc/src/setjmp/riscv64/longjmp.cpp b/libc/src/setjmp/riscv64/longjmp.cpp
new file mode 100644
index 0000000000000..e1432b5438119
--- /dev/null
+++ b/libc/src/setjmp/riscv64/longjmp.cpp
@@ -0,0 +1,58 @@
+//===-- Implementation of longjmp -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/setjmp/longjmp.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/properties/architectures.h"
+
+#include <setjmp.h>
+
+#if !defined(LIBC_TARGET_ARCH_IS_RISCV64)
+#error "Invalid file include"
+#endif
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(void, longjmp, (__jmp_buf * buf, int val)) {
+  LIBC_INLINE_ASM("ld ra, %0\n\t" : : "m"(buf->__pc) :);
+  LIBC_INLINE_ASM("ld s0, %0\n\t" : : "m"(buf->__regs[0]) :);
+  LIBC_INLINE_ASM("ld s1, %0\n\t" : : "m"(buf->__regs[1]) :);
+  LIBC_INLINE_ASM("ld s2, %0\n\t" : : "m"(buf->__regs[2]) :);
+  LIBC_INLINE_ASM("ld s3, %0\n\t" : : "m"(buf->__regs[3]) :);
+  LIBC_INLINE_ASM("ld s4, %0\n\t" : : "m"(buf->__regs[4]) :);
+  LIBC_INLINE_ASM("ld s5, %0\n\t" : : "m"(buf->__regs[5]) :);
+  LIBC_INLINE_ASM("ld s6, %0\n\t" : : "m"(buf->__regs[6]) :);
+  LIBC_INLINE_ASM("ld s7, %0\n\t" : : "m"(buf->__regs[7]) :);
+  LIBC_INLINE_ASM("ld s8, %0\n\t" : : "m"(buf->__regs[8]) :);
+  LIBC_INLINE_ASM("ld s9, %0\n\t" : : "m"(buf->__regs[9]) :);
+  LIBC_INLINE_ASM("ld s10, %0\n\t" : : "m"(buf->__regs[10]) :);
+  LIBC_INLINE_ASM("ld s11, %0\n\t" : : "m"(buf->__regs[11]) :);
+  LIBC_INLINE_ASM("ld sp, %0\n\t" : : "m"(buf->__sp) :);
+
+#if __riscv_float_abi_double
+  LIBC_INLINE_ASM("fld fs0, %0\n\t" : : "m"(buf->__fpregs[0]) :);
+  LIBC_INLINE_ASM("fld fs1, %0\n\t" : : "m"(buf->__fpregs[1]) :);
+  LIBC_INLINE_ASM("fld fs2, %0\n\t" : : "m"(buf->__fpregs[2]) :);
+  LIBC_INLINE_ASM("fld fs3, %0\n\t" : : "m"(buf->__fpregs[3]) :);
+  LIBC_INLINE_ASM("fld fs4, %0\n\t" : : "m"(buf->__fpregs[4]) :);
+  LIBC_INLINE_ASM("fld fs5, %0\n\t" : : "m"(buf->__fpregs[5]) :);
+  LIBC_INLINE_ASM("fld fs6, %0\n\t" : : "m"(buf->__fpregs[6]) :);
+  LIBC_INLINE_ASM("fld fs7, %0\n\t" : : "m"(buf->__fpregs[7]) :);
+  LIBC_INLINE_ASM("fld fs8, %0\n\t" : : "m"(buf->__fpregs[8]) :);
+  LIBC_INLINE_ASM("fld fs9, %0\n\t" : : "m"(buf->__fpregs[9]) :);
+  LIBC_INLINE_ASM("fld fs10, %0\n\t" : : "m"(buf->__fpregs[10]) :);
+  LIBC_INLINE_ASM("fld fs11, %0\n\t" : : "m"(buf->__fpregs[11]) :);
+#elif defined(__riscv_float_abi_single)
+#error "longjmp implementation not available for the target architecture."
+#endif
+
+  val = val == 0 ? 1 : val;
+  LIBC_INLINE_ASM("add a0, %0, zero\n\t" : : "r"(val) :);
+}
+
+} // namespace __llvm_libc

diff  --git a/libc/src/setjmp/riscv64/setjmp.cpp b/libc/src/setjmp/riscv64/setjmp.cpp
new file mode 100644
index 0000000000000..f2c5e1951645e
--- /dev/null
+++ b/libc/src/setjmp/riscv64/setjmp.cpp
@@ -0,0 +1,56 @@
+//===-- Implementation of setjmp ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/common.h"
+#include "src/setjmp/setjmp_impl.h"
+
+#include <setjmp.h>
+
+#if !defined(LIBC_TARGET_ARCH_IS_RISCV64)
+#error "Invalid file include"
+#endif
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, setjmp, (__jmp_buf * buf)) {
+  LIBC_INLINE_ASM("sd ra, %0\n\t" : : "m"(buf->__pc) :);
+  LIBC_INLINE_ASM("sd s0, %0\n\t" : : "m"(buf->__regs[0]) :);
+  LIBC_INLINE_ASM("sd s1, %0\n\t" : : "m"(buf->__regs[1]) :);
+  LIBC_INLINE_ASM("sd s2, %0\n\t" : : "m"(buf->__regs[2]) :);
+  LIBC_INLINE_ASM("sd s3, %0\n\t" : : "m"(buf->__regs[3]) :);
+  LIBC_INLINE_ASM("sd s4, %0\n\t" : : "m"(buf->__regs[4]) :);
+  LIBC_INLINE_ASM("sd s5, %0\n\t" : : "m"(buf->__regs[5]) :);
+  LIBC_INLINE_ASM("sd s6, %0\n\t" : : "m"(buf->__regs[6]) :);
+  LIBC_INLINE_ASM("sd s7, %0\n\t" : : "m"(buf->__regs[7]) :);
+  LIBC_INLINE_ASM("sd s8, %0\n\t" : : "m"(buf->__regs[8]) :);
+  LIBC_INLINE_ASM("sd s9, %0\n\t" : : "m"(buf->__regs[9]) :);
+  LIBC_INLINE_ASM("sd s10, %0\n\t" : : "m"(buf->__regs[10]) :);
+  LIBC_INLINE_ASM("sd s11, %0\n\t" : : "m"(buf->__regs[11]) :);
+  LIBC_INLINE_ASM("sd sp, %0\n\t" : : "m"(buf->__sp) :);
+
+#if __riscv_float_abi_double
+  LIBC_INLINE_ASM("fsd fs0, %0\n\t" : : "m"(buf->__fpregs[0]) :);
+  LIBC_INLINE_ASM("fsd fs1, %0\n\t" : : "m"(buf->__fpregs[1]) :);
+  LIBC_INLINE_ASM("fsd fs2, %0\n\t" : : "m"(buf->__fpregs[2]) :);
+  LIBC_INLINE_ASM("fsd fs3, %0\n\t" : : "m"(buf->__fpregs[3]) :);
+  LIBC_INLINE_ASM("fsd fs4, %0\n\t" : : "m"(buf->__fpregs[4]) :);
+  LIBC_INLINE_ASM("fsd fs5, %0\n\t" : : "m"(buf->__fpregs[5]) :);
+  LIBC_INLINE_ASM("fsd fs6, %0\n\t" : : "m"(buf->__fpregs[6]) :);
+  LIBC_INLINE_ASM("fsd fs7, %0\n\t" : : "m"(buf->__fpregs[7]) :);
+  LIBC_INLINE_ASM("fsd fs8, %0\n\t" : : "m"(buf->__fpregs[8]) :);
+  LIBC_INLINE_ASM("fsd fs9, %0\n\t" : : "m"(buf->__fpregs[9]) :);
+  LIBC_INLINE_ASM("fsd fs10, %0\n\t" : : "m"(buf->__fpregs[10]) :);
+  LIBC_INLINE_ASM("fsd fs11, %0\n\t" : : "m"(buf->__fpregs[11]) :);
+#elif defined(__riscv_float_abi_single)
+#error "setjmp implementation not available for the target architecture."
+#endif
+
+  return 0;
+}
+
+} // namespace __llvm_libc

diff  --git a/libc/src/setjmp/x86_64/CMakeLists.txt b/libc/src/setjmp/x86_64/CMakeLists.txt
new file mode 100644
index 0000000000000..141d1205fd557
--- /dev/null
+++ b/libc/src/setjmp/x86_64/CMakeLists.txt
@@ -0,0 +1,25 @@
+add_entrypoint_object(
+  setjmp
+  SRCS
+    setjmp.cpp
+  HDRS
+    ../setjmp_impl.h
+  DEPENDS
+    libc.include.setjmp
+  COMPILE_OPTIONS
+    -O3
+    -fno-omit-frame-pointer
+)
+
+add_entrypoint_object(
+  longjmp
+  SRCS
+    longjmp.cpp
+  HDRS
+    ../longjmp.h
+  DEPENDS
+    libc.include.setjmp
+  COMPILE_OPTIONS
+    -O3
+    -fno-omit-frame-pointer
+)

diff  --git a/libc/src/setjmp/longjmp.cpp b/libc/src/setjmp/x86_64/longjmp.cpp
similarity index 88%
rename from libc/src/setjmp/longjmp.cpp
rename to libc/src/setjmp/x86_64/longjmp.cpp
index 999151e4d550d..f2a2529d30050 100644
--- a/libc/src/setjmp/longjmp.cpp
+++ b/libc/src/setjmp/x86_64/longjmp.cpp
@@ -8,14 +8,14 @@
 
 #include "src/setjmp/longjmp.h"
 #include "src/__support/common.h"
-#include "src/__support/macros/properties/architectures.h"
 
-#include <setjmp.h>
+#if !defined(LIBC_TARGET_ARCH_IS_X86_64)
+#error "Invalid file include"
+#endif
 
 namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(void, longjmp, (__jmp_buf * buf, int val)) {
-#ifdef LIBC_TARGET_ARCH_IS_X86_64
   register __UINT64_TYPE__ rbx __asm__("rbx");
   register __UINT64_TYPE__ rbp __asm__("rbp");
   register __UINT64_TYPE__ r12 __asm__("r12");
@@ -38,9 +38,6 @@ LLVM_LIBC_FUNCTION(void, longjmp, (__jmp_buf * buf, int val)) {
   LIBC_INLINE_ASM("mov %1, %0\n\t" : "=r"(r15) : "m"(buf->r15) :);
   LIBC_INLINE_ASM("mov %1, %0\n\t" : "=r"(rsp) : "m"(buf->rsp) :);
   LIBC_INLINE_ASM("jmp *%0\n\t" : : "m"(buf->rip));
-#else // LIBC_TARGET_ARCH_IS_X86_64
-#error "longjmp implementation not available for the target architecture."
-#endif
 }
 
 } // namespace __llvm_libc

diff  --git a/libc/src/setjmp/setjmp.cpp b/libc/src/setjmp/x86_64/setjmp.cpp
similarity index 91%
rename from libc/src/setjmp/setjmp.cpp
rename to libc/src/setjmp/x86_64/setjmp.cpp
index 8b3493e9f38cf..988db6452571d 100644
--- a/libc/src/setjmp/setjmp.cpp
+++ b/libc/src/setjmp/x86_64/setjmp.cpp
@@ -7,15 +7,15 @@
 //===----------------------------------------------------------------------===//
 
 #include "src/__support/common.h"
-#include "src/__support/macros/properties/architectures.h"
 #include "src/setjmp/setjmp_impl.h"
 
-#include <setjmp.h>
+#if !defined(LIBC_TARGET_ARCH_IS_X86_64)
+#error "Invalid file include"
+#endif
 
 namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(int, setjmp, (__jmp_buf * buf)) {
-#ifdef LIBC_TARGET_ARCH_IS_X86_64
   register __UINT64_TYPE__ rbx __asm__("rbx");
   register __UINT64_TYPE__ r12 __asm__("r12");
   register __UINT64_TYPE__ r13 __asm__("r13");
@@ -50,10 +50,6 @@ LLVM_LIBC_FUNCTION(int, setjmp, (__jmp_buf * buf)) {
   buf->rsp = reinterpret_cast<__UINTPTR_TYPE__>(__builtin_frame_address(0)) +
              sizeof(__UINTPTR_TYPE__) * 2;
   buf->rip = reinterpret_cast<__UINTPTR_TYPE__>(__builtin_return_address(0));
-#else // LIBC_TARGET_ARCH_IS_X86_64
-#error "setjmp implementation not available for the target architecture."
-#endif
-
   return 0;
 }
 


        


More information about the libc-commits mailing list