diff --git a/libc/config/linux/riscv64/entrypoints.txt b/libc/config/linux/riscv64/entrypoints.txt --- a/libc/config/linux/riscv64/entrypoints.txt +++ b/libc/config/linux/riscv64/entrypoints.txt @@ -387,8 +387,8 @@ # libc.src.sched.__sched_getcpucount # setjmp.h entrypoints - # libc.src.setjmp.longjmp - # libc.src.setjmp.setjmp + libc.src.setjmp.longjmp + libc.src.setjmp.setjmp # stdio.h entrypoints # libc.src.stdio.clearerr diff --git a/libc/include/llvm-libc-types/jmp_buf.h b/libc/include/llvm-libc-types/jmp_buf.h --- a/libc/include/llvm-libc-types/jmp_buf.h +++ b/libc/include/llvm-libc-types/jmp_buf.h @@ -19,6 +19,19 @@ __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 --- a/libc/src/setjmp/CMakeLists.txt +++ b/libc/src/setjmp/CMakeLists.txt @@ -1,3 +1,10 @@ +if(LIBC_TARGET_ARCHITECTURE_IS_RISCV64) + set(FRAME_POINTER -fomit-frame-pointer) +else() + # The implementation assumes frame pointer on to the stack + set(FRAME_POINTER -fno-omit-frame-pointer) +endif() + add_entrypoint_object( setjmp SRCS @@ -6,7 +13,7 @@ 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 + "${FRAME_POINTER}" DEPENDS libc.include.setjmp ) diff --git a/libc/src/setjmp/longjmp.h b/libc/src/setjmp/longjmp.h --- a/libc/src/setjmp/longjmp.h +++ b/libc/src/setjmp/longjmp.h @@ -13,7 +13,7 @@ namespace __llvm_libc { -void longjmp(__jmp_buf *buf, int val); +void longjmp(__jmp_buf *buf, int val) __NOEXCEPT; } // namespace __llvm_libc diff --git a/libc/src/setjmp/longjmp.cpp b/libc/src/setjmp/longjmp.cpp --- a/libc/src/setjmp/longjmp.cpp +++ b/libc/src/setjmp/longjmp.cpp @@ -14,7 +14,10 @@ namespace __llvm_libc { -LLVM_LIBC_FUNCTION(void, longjmp, (__jmp_buf * buf, int val)) { +#if defined(LIBC_TARGET_ARCH_IS_RISCV64) +__attribute__((naked)) // Don't generate function epilogue and prologue +#endif +LLVM_LIBC_FUNCTION(void, longjmp, (__jmp_buf * buf, int val)) __NOEXCEPT { #ifdef LIBC_TARGET_ARCH_IS_X86_64 register __UINT64_TYPE__ rbx __asm__("rbx"); register __UINT64_TYPE__ rbp __asm__("rbp"); @@ -38,7 +41,76 @@ 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 +#elif defined(LIBC_TARGET_ARCH_IS_RISCV64) + register long a0 __asm__("a0"); + register long a1 __asm__("a1"); + register long ra __asm__("ra"); + register long s0 __asm__("s0"); + register long s1 __asm__("s1"); + register long s2 __asm__("s2"); + register long s3 __asm__("s3"); + register long s4 __asm__("s4"); + register long s5 __asm__("s5"); + register long s6 __asm__("s6"); + register long s7 __asm__("s7"); + register long s8 __asm__("s8"); + register long s9 __asm__("s9"); + register long s10 __asm__("s10"); + register long s11 __asm__("s11"); + register long sp __asm__("sp"); + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wuninitialized" + LIBC_INLINE_ASM("ld %0, 0(%1)\n\t" : "=r"(ra) : "r"(a0) :); + LIBC_INLINE_ASM("ld %0, 8(%1)\n\t" : "=r"(s0) : "r"(a0) :); + LIBC_INLINE_ASM("ld %0, 16(%1)\n\t" : "=r"(s1) : "r"(a0) :); + LIBC_INLINE_ASM("ld %0, 24(%1)\n\t" : "=r"(s2) : "r"(a0) :); + LIBC_INLINE_ASM("ld %0, 32(%1)\n\t" : "=r"(s3) : "r"(a0) :); + LIBC_INLINE_ASM("ld %0, 40(%1)\n\t" : "=r"(s4) : "r"(a0) :); + LIBC_INLINE_ASM("ld %0, 48(%1)\n\t" : "=r"(s5) : "r"(a0) :); + LIBC_INLINE_ASM("ld %0, 56(%1)\n\t" : "=r"(s6) : "r"(a0) :); + LIBC_INLINE_ASM("ld %0, 64(%1)\n\t" : "=r"(s7) : "r"(a0) :); + LIBC_INLINE_ASM("ld %0, 72(%1)\n\t" : "=r"(s8) : "r"(a0) :); + LIBC_INLINE_ASM("ld %0, 80(%1)\n\t" : "=r"(s9) : "r"(a0) :); + LIBC_INLINE_ASM("ld %0, 88(%1)\n\t" : "=r"(s10) : "r"(a0) :); + LIBC_INLINE_ASM("ld %0, 96(%1)\n\t" : "=r"(s11) : "r"(a0) :); + LIBC_INLINE_ASM("ld %0, 104(%1)\n\t" : "=r"(sp) : "r"(a0) :); + +#if __riscv_float_abi_double + register double fs0 __asm__("fs0"); + register double fs1 __asm__("fs1"); + register double fs2 __asm__("fs2"); + register double fs3 __asm__("fs3"); + register double fs4 __asm__("fs4"); + register double fs5 __asm__("fs5"); + register double fs6 __asm__("fs6"); + register double fs7 __asm__("fs7"); + register double fs8 __asm__("fs8"); + register double fs9 __asm__("fs9"); + register double fs10 __asm__("fs10"); + register double fs11 __asm__("fs11"); + + LIBC_INLINE_ASM("fld %0, 112(%1)\n\t" : "=f"(fs0) : "r"(a0) :); + LIBC_INLINE_ASM("fld %0, 120(%1)\n\t" : "=f"(fs1) : "r"(a0) :); + LIBC_INLINE_ASM("fld %0, 128(%1)\n\t" : "=f"(fs2) : "r"(a0) :); + LIBC_INLINE_ASM("fld %0, 136(%1)\n\t" : "=f"(fs3) : "r"(a0) :); + LIBC_INLINE_ASM("fld %0, 144(%1)\n\t" : "=f"(fs4) : "r"(a0) :); + LIBC_INLINE_ASM("fld %0, 152(%1)\n\t" : "=f"(fs5) : "r"(a0) :); + LIBC_INLINE_ASM("fld %0, 160(%1)\n\t" : "=f"(fs6) : "r"(a0) :); + LIBC_INLINE_ASM("fld %0, 168(%1)\n\t" : "=f"(fs7) : "r"(a0) :); + LIBC_INLINE_ASM("fld %0, 176(%1)\n\t" : "=f"(fs8) : "r"(a0) :); + LIBC_INLINE_ASM("fld %0, 184(%1)\n\t" : "=f"(fs9) : "r"(a0) :); + LIBC_INLINE_ASM("fld %0, 192(%1)\n\t" : "=f"(fs10) : "r"(a0) :); + LIBC_INLINE_ASM("fld %0, 200(%1)\n\t" : "=f"(fs11) : "r"(a0) :); +#elif defined(__riscv_float_abi_single) +#error "longjmp implementation not available for the target architecture." +#endif + + LIBC_INLINE_ASM("seqz %0, %1" : "=r"(a0) : "r"(a1) :); + LIBC_INLINE_ASM("add %0, %0, %1" : "=r"(a0) : "r"(a1), "r"(a0) :); + LIBC_INLINE_ASM("ret" : : :); +#pragma GCC diagnostic pop +#else #error "longjmp implementation not available for the target architecture." #endif } diff --git a/libc/src/setjmp/setjmp.cpp b/libc/src/setjmp/setjmp.cpp --- a/libc/src/setjmp/setjmp.cpp +++ b/libc/src/setjmp/setjmp.cpp @@ -14,7 +14,10 @@ namespace __llvm_libc { -LLVM_LIBC_FUNCTION(int, setjmp, (__jmp_buf * buf)) { +#if defined(LIBC_TARGET_ARCH_IS_RISCV64) +__attribute__((naked)) // Don't generate function epilogue and prologue +#endif +LLVM_LIBC_FUNCTION(int, setjmp, (__jmp_buf * buf)) __NOEXCEPT { #ifdef LIBC_TARGET_ARCH_IS_X86_64 register __UINT64_TYPE__ rbx __asm__("rbx"); register __UINT64_TYPE__ r12 __asm__("r12"); @@ -50,11 +53,76 @@ 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 + return 0; +#elif defined(LIBC_TARGET_ARCH_IS_RISCV64) + register long a0 __asm__("a0"); + register long ra __asm__("ra"); + register long s0 __asm__("s0"); + register long s1 __asm__("s1"); + register long s2 __asm__("s2"); + register long s3 __asm__("s3"); + register long s4 __asm__("s4"); + register long s5 __asm__("s5"); + register long s6 __asm__("s6"); + register long s7 __asm__("s7"); + register long s8 __asm__("s8"); + register long s9 __asm__("s9"); + register long s10 __asm__("s10"); + register long s11 __asm__("s11"); + register long sp __asm__("sp"); + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wuninitialized" + LIBC_INLINE_ASM("sd %0, 0(%1)\n\t" : "=r"(ra) : "r"(a0) :); + LIBC_INLINE_ASM("sd %0, 8(%1)\n\t" : "=r"(s0) : "r"(a0) :); + LIBC_INLINE_ASM("sd %0, 16(%1)\n\t" : "=r"(s1) : "r"(a0) :); + LIBC_INLINE_ASM("sd %0, 24(%1)\n\t" : "=r"(s2) : "r"(a0) :); + LIBC_INLINE_ASM("sd %0, 32(%1)\n\t" : "=r"(s3) : "r"(a0) :); + LIBC_INLINE_ASM("sd %0, 40(%1)\n\t" : "=r"(s4) : "r"(a0) :); + LIBC_INLINE_ASM("sd %0, 48(%1)\n\t" : "=r"(s5) : "r"(a0) :); + LIBC_INLINE_ASM("sd %0, 56(%1)\n\t" : "=r"(s6) : "r"(a0) :); + LIBC_INLINE_ASM("sd %0, 64(%1)\n\t" : "=r"(s7) : "r"(a0) :); + LIBC_INLINE_ASM("sd %0, 72(%1)\n\t" : "=r"(s8) : "r"(a0) :); + LIBC_INLINE_ASM("sd %0, 80(%1)\n\t" : "=r"(s9) : "r"(a0) :); + LIBC_INLINE_ASM("sd %0, 88(%1)\n\t" : "=r"(s10) : "r"(a0) :); + LIBC_INLINE_ASM("sd %0, 96(%1)\n\t" : "=r"(s11) : "r"(a0) :); + LIBC_INLINE_ASM("sd %0, 104(%1)\n\t" : "=r"(sp) : "r"(a0) :); + +#if __riscv_float_abi_double + register double fs0 __asm__("fs0"); + register double fs1 __asm__("fs1"); + register double fs2 __asm__("fs2"); + register double fs3 __asm__("fs3"); + register double fs4 __asm__("fs4"); + register double fs5 __asm__("fs5"); + register double fs6 __asm__("fs6"); + register double fs7 __asm__("fs7"); + register double fs8 __asm__("fs8"); + register double fs9 __asm__("fs9"); + register double fs10 __asm__("fs10"); + register double fs11 __asm__("fs11"); + + LIBC_INLINE_ASM("fsd %0, 112(%1)\n\t" : "=f"(fs0) : "r"(a0) :); + LIBC_INLINE_ASM("fsd %0, 120(%1)\n\t" : "=f"(fs1) : "r"(a0) :); + LIBC_INLINE_ASM("fsd %0, 128(%1)\n\t" : "=f"(fs2) : "r"(a0) :); + LIBC_INLINE_ASM("fsd %0, 136(%1)\n\t" : "=f"(fs3) : "r"(a0) :); + LIBC_INLINE_ASM("fsd %0, 144(%1)\n\t" : "=f"(fs4) : "r"(a0) :); + LIBC_INLINE_ASM("fsd %0, 152(%1)\n\t" : "=f"(fs5) : "r"(a0) :); + LIBC_INLINE_ASM("fsd %0, 160(%1)\n\t" : "=f"(fs6) : "r"(a0) :); + LIBC_INLINE_ASM("fsd %0, 168(%1)\n\t" : "=f"(fs7) : "r"(a0) :); + LIBC_INLINE_ASM("fsd %0, 176(%1)\n\t" : "=f"(fs8) : "r"(a0) :); + LIBC_INLINE_ASM("fsd %0, 184(%1)\n\t" : "=f"(fs9) : "r"(a0) :); + LIBC_INLINE_ASM("fsd %0, 192(%1)\n\t" : "=f"(fs10) : "r"(a0) :); + LIBC_INLINE_ASM("fsd %0, 200(%1)\n\t" : "=f"(fs11) : "r"(a0) :); +#elif defined(__riscv_float_abi_single) #error "setjmp implementation not available for the target architecture." #endif - return 0; + LIBC_INLINE_ASM("li %0, 0" : "=r"(a0) : :); +#pragma GCC diagnostic pop +#else +#error "setjmp implementation not available for the target architecture." +#endif } } // namespace __llvm_libc diff --git a/libc/src/setjmp/setjmp_impl.h b/libc/src/setjmp/setjmp_impl.h --- a/libc/src/setjmp/setjmp_impl.h +++ b/libc/src/setjmp/setjmp_impl.h @@ -15,7 +15,7 @@ namespace __llvm_libc { -int setjmp(__jmp_buf *buf); +int setjmp(__jmp_buf *buf) __NOEXCEPT; } // namespace __llvm_libc