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; } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits