Skip to content

Commit

Permalink
riscv(support,linux): use HWPROBE for ISE detection
Browse files Browse the repository at this point in the history
Current SIGILL handler appears to have weird issues with libluajit on
some platform. Considering 6.6 kernel is becoming more common, switch
to HWPROBE for better compatibility.
  • Loading branch information
infiWang committed Dec 29, 2024
1 parent 99afa85 commit f25e678
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 43 deletions.
79 changes: 36 additions & 43 deletions src/lib_jit.c
Original file line number Diff line number Diff line change
Expand Up @@ -698,23 +698,26 @@ JIT_PARAMDEF(JIT_PARAMINIT)
#endif

#if LJ_TARGET_RISCV64 && LJ_TARGET_POSIX
#include <setjmp.h>
#include <signal.h>
static sigjmp_buf sigbuf = {0};
static void detect_sigill(int sig)
{
siglongjmp(sigbuf, 1);
}

#if LJ_TARGET_LINUX
#include <unistd.h>

struct riscv_hwprobe hwprobe_requests[] = {
{RISCV_HWPROBE_KEY_IMA_EXT_0}
};

const uint64_t *hwprobe_ext = &hwprobe_requests[0].value;

int hwprobe_ret = 0;
#endif

static int riscv_compressed()
{
#if defined(__riscv_c) || defined(__riscv_compressed)
/* Don't bother checking for RVC -- would crash before getting here. */
return 1;
#elif defined(__GNUC__)
/* c.nop; c.nop; */
__asm__(".4byte 0x00010001");
return 1;
#elif LJ_TARGET_LINUX
return (hwprobe_ret == 0 && ((*hwprobe_ext) & RISCV_HWPROBE_IMA_C)) ? 1 : 0;
#else
return 0;
#endif
Expand All @@ -725,11 +728,8 @@ static int riscv_zba()
#if defined(__riscv_b) || defined(__riscv_zba)
/* Don't bother checking for Zba -- would crash before getting here. */
return 1;
#elif defined(__GNUC__)
/* Don't bother verifying the result, just check if the instruction exists. */
/* add.uw zero, zero, zero */
__asm__(".4byte 0x0800003b");
return 1;
#elif LJ_TARGET_LINUX
return (hwprobe_ret == 0 && ((*hwprobe_ext) & RISCV_HWPROBE_EXT_ZBA)) ? 1 : 0;
#else
return 0;
#endif
Expand All @@ -740,11 +740,8 @@ static int riscv_zbb()
#if defined(__riscv_b) || defined(__riscv_zbb)
/* Don't bother checking for Zbb -- would crash before getting here. */
return 1;
#elif defined(__GNUC__)
register int t asm ("a0");
/* addi a0, zero, 255; sext.b a0, a0; */
__asm__("addi a0, zero, 255\n\t.4byte 0x60451513");
return t < 0;
#elif LJ_TARGET_LINUX
return (hwprobe_ret == 0 && ((*hwprobe_ext) & RISCV_HWPROBE_EXT_ZBB)) ? 1 : 0;
#else
return 0;
#endif
Expand All @@ -755,34 +752,26 @@ static int riscv_zicond()
#if defined(__riscv_zicond)
/* Don't bother checking for Zicond -- would crash before getting here. */
return 1;
#elif defined(__GNUC__)
/* czero.eqz zero, zero, zero; */
__asm__(".4byte 0x0e005033");
return 1;
#elif LJ_TARGET_LINUX
return (hwprobe_ret == 0 && ((*hwprobe_ext) & RISCV_HWPROBE_EXT_ZICOND)) ? 1 : 0;
#else
return 0;
#endif
}

static int riscv_xthead()
{
#if defined(__GNUC__)
register int t asm ("a0");
/* C906 & C910 & C908 all have "xtheadc", XTheadBb subset "xtheadc". */
/* Therefore assume XThead* are present if XTheadBb is present. */
/* addi a0, zero, 255; th.ext a0, a0, 7, 0; */
__asm__("addi a0, zero, 255\n\t.4byte 0x1c05250b");
return t == -1; /* In case of collision with other vendor extensions. */
#else
return 0;
#endif
/*
** Hardcoded as there's no easy way of detection:
** - SIGILL have some trouble with libluajit as we speak
** - Checking mvendorid looks good, but might not be reliable.
*/
return 0;
}

static uint32_t riscv_probe(int (*func)(void), uint32_t flag)
{
if (sigsetjmp(sigbuf, 1) == 0) {
return func() ? flag : 0;
} else return 0;
return func() ? flag : 0;
}
#endif

Expand Down Expand Up @@ -861,16 +850,20 @@ static uint32_t jit_cpudetect(void)

#elif LJ_TARGET_RISCV64
#if LJ_HASJIT
/* SIGILL-based detection of RVC, Zba, Zbb and XThead. Welcome to the future. */
struct sigaction old = {0}, act = {0};
act.sa_handler = detect_sigill;
sigaction(SIGILL, &act, &old);

#if LJ_TARGET_LINUX
/* HWPROBE-based detection of RVC, Zba, Zbb and Zicond. */
hwprobe_ret = syscall(__NR_riscv_hwprobe, &hwprobe_requests,
sizeof(hwprobe_requests) / sizeof(struct riscv_hwprobe), 0,
NULL, 0);

flags |= riscv_probe(riscv_compressed, JIT_F_RVC);
flags |= riscv_probe(riscv_zba, JIT_F_RVZba);
flags |= riscv_probe(riscv_zbb, JIT_F_RVZbb);
flags |= riscv_probe(riscv_zicond, JIT_F_RVZicond);
flags |= riscv_probe(riscv_xthead, JIT_F_RVXThead);
sigaction(SIGILL, &old, NULL);

#endif

/* Detect V/P? */
/* V have no hardware available, P not ratified yet. */
Expand Down
28 changes: 28 additions & 0 deletions src/lj_jit.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,34 @@

#define JIT_F_CPUSTRING "\003RVC\003Zba\003Zbb\006Zicond\006XThead"

#if LJ_TARGET_LINUX
#include <sys/syscall.h>

#ifndef __NR_riscv_hwprobe
#ifndef __NR_arch_specific_syscall
#define __NR_arch_specific_syscall 244
#endif
#define __NR_riscv_hwprobe (__NR_arch_specific_syscall + 14)
#endif

struct riscv_hwprobe {
int64_t key;
uint64_t value;
};

#define RISCV_HWPROBE_KEY_MVENDORID 0
#define RISCV_HWPROBE_KEY_MARCHID 1
#define RISCV_HWPROBE_KEY_MIMPID 2
#define RISCV_HWPROBE_KEY_BASE_BEHAVIOR 3
#define RISCV_HWPROBE_KEY_IMA_EXT_0 4

#define RISCV_HWPROBE_IMA_C (1 << 1)
#define RISCV_HWPROBE_EXT_ZBA (1 << 3)
#define RISCV_HWPROBE_EXT_ZBB (1 << 4)
#define RISCV_HWPROBE_EXT_ZICOND (1ULL << 35)

#endif

#else

#define JIT_F_CPUSTRING ""
Expand Down

0 comments on commit f25e678

Please sign in to comment.