[clang] 0f6fd1b - [libc] Add support for setjmp and longjmp in riscv
Mikhail R. Gadelha via cfe-commits
cfe-commits at lists.llvm.org
Fri Mar 24 12:19:43 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 cfe-commits
mailing list