diff options
author | Bernhard Urban <bernhard.urban@xamarin.com> | 2018-11-07 23:04:00 +0300 |
---|---|---|
committer | monojenkins <jo.shields+jenkins@xamarin.com> | 2018-11-07 23:04:00 +0300 |
commit | e8aa7a2b73b34e09fabd15a1f332943b1093e7d5 (patch) | |
tree | b59f1ab5006f4b5dadf8bac71ad02ad56d251389 | |
parent | f0fe3fc42615e5c63630f80911cf9c0aef084f13 (diff) |
initial RISC-V support (#11593)
initial RISC-V support
I rebased @alexrp's work (https://github.com/alexrp/mono/commits/riscv) and added stubs so this minimal example works in the interpreter:
```console
$ qemu-riscv64 ./mono/mini/mono-sgen --version
Mono JIT compiler version 5.21.0 (riscv/f4802305009 Wed Nov 7 02:58:20 PST 2018)
Copyright (C) 2002-2014 Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com
TLS: __thread
SIGSEGV: normal
Notifications: epoll
Architecture: riscv64,double-fp
Disabled: none
Misc:
Interpreter: yes
Suspend: preemptive
GC: sgen (concurrent by default)
$ export MONO_PATH=../mono-riscv-bclbuild/b/lib/mono/4.5
$ grep -A 2 test_0_return mono/mini/basic.cs
public static int test_0_return () {
return 0;
}
$ INTERP_FILTER_METHOD=test_0_return qemu-riscv64 ./mono/mini/mono-sgen --interp --regression basic.exe
Test run: image=/home/lewurm/work/mono-riscv/basic.exe
Results: total tests: 1, all pass
Elapsed time: 0.002441 secs (0.002441, 0.000000)
Overall results: tests: 1, 100% pass
```
38 files changed, 3474 insertions, 10 deletions
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 284cef89272..1a2ba002ff6 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -22,6 +22,7 @@ /data/lldb @lewurm @vargaz /docs @luhenry @marek-safar @akoeplinger +/docs/riscv.md @alexrp @lewurm /docs/sources/mono-api-profiler.html @alexrp /external @akoeplinger @marek-safar @@ -75,6 +76,8 @@ /mono @luhenry +/mono/arch/riscv @alexrp @lewurm + /mono/btls @baulig /mono/dis @lambdageek @vargaz /mono/eglib @vargaz @luhenry @@ -93,6 +96,7 @@ /mono/mini/*cfgdump* @lewurm /mono/mini/*exceptions* @lewurm /mono/mini/*ppc* @lewurm +/mono/mini/*riscv* @alexrp @lewurm /mono/mini/*type-check* @lewurm /mono/mini/interp/* @lewurm @BrzVlad /mono/mini/*profiler* @alexrp diff --git a/configure.ac b/configure.ac index 54b567bd6e4..2b6b6ae1a38 100644 --- a/configure.ac +++ b/configure.ac @@ -292,6 +292,10 @@ case "$host" in # https://bugzilla.novell.com/show_bug.cgi?id=504411 disable_munmap=yes ;; + riscv*) + support_boehm=no + with_gc=sgen + ;; esac with_sgen_default_concurrent=yes ;; @@ -4094,6 +4098,24 @@ case "$host" in BTLS_PLATFORM=s390x CFLAGS="$CFLAGS -mbackchain -D__USE_STRING_INLINES" ;; + riscv32-*) + TARGET=RISCV32 + ACCESS_UNALIGNED=no + AOT_SUPPORTED=no + BTLS_SUPPORTED=yes + BTLS_PLATFORM=riscv32 + arch_target=riscv32 + boehm_supported=false + ;; + riscv64*) + TARGET=RISCV64 + ACCESS_UNALIGNED=no + AOT_SUPPORTED=no + BTLS_SUPPORTED=yes + BTLS_PLATFORM=riscv64 + arch_target=riscv64 + boehm_supported=false + ;; esac HOST=$TARGET @@ -4173,6 +4195,22 @@ if test "x$host" != "x$target"; then aarch64-*) TARGET=ARM64 ;; + riscv32*) + TARGET=RISCV32 + AC_DEFINE([TARGET_RISCV], [1], [Target is RISC-V]) + AC_DEFINE([TARGET_RISCV32], [1], [Target is 32-bit RISC-V]) + arch_target=riscv32 + target_mach=no + with_tls=pthread + ;; + riscv64*) + TARGET=RISCV64 + AC_DEFINE([TARGET_RISCV], [1], [Target is RISC-V]) + AC_DEFINE([TARGET_RISCV64], [1], [Target is 64-bit RISC-V]) + arch_target=riscv64 + target_mach=no + with_tls=pthread + ;; *) AC_MSG_ERROR([Cross compiling is not supported for target $target]) esac @@ -4231,6 +4269,14 @@ SPARC) SPARC64) AC_DEFINE(TARGET_SPARC64, 1, [...]) ;; +RISCV32) + AC_DEFINE([TARGET_RISCV], [1], [Target is RISC-V]) + AC_DEFINE([TARGET_RISCV32], [1], [Target is 32-bit RISC-V]) + ;; +RISCV64) + AC_DEFINE([TARGET_RISCV], [1], [Target is RISC-V]) + AC_DEFINE([TARGET_RISCV64], [1], [Target is 64-bit RISC-V]) + ;; esac case "$HOST" in @@ -4268,6 +4314,14 @@ SPARC) SPARC64) AC_DEFINE(HOST_SPARC64, 1, [...]) ;; +RISCV32) + AC_DEFINE([HOST_RISCV], [1], [Host is RISC-V]) + AC_DEFINE([HOST_RISCV32], [1], [Host is 32-bit RISC-V]) + ;; +RISCV64) + AC_DEFINE([HOST_RISCV], [1], [Host is RISC-V]) + AC_DEFINE([HOST_RISCV64], [1], [Host is 64-bit RISC-V]) + ;; esac MONO_ARCH_GSHAREDVT_SUPPORTED=0 @@ -4323,7 +4377,7 @@ fi dnl Use GCC atomic ops if they work on the target. if test x$GCC = "xyes"; then case $TARGET in - X86 | AMD64 | ARM | ARM64 | POWERPC | POWERPC64 | MIPS | S390X | SPARC | SPARC64) + X86 | AMD64 | ARM | ARM64 | POWERPC | POWERPC64 | MIPS | S390X | SPARC | SPARC64 | RISCV32 | RISCV64) AC_DEFINE(USE_GCC_ATOMIC_OPS, 1, [...]) ;; esac @@ -4526,7 +4580,7 @@ case $host in esac case $target in -arm*-darwin*|aarch64*-*) +arm*-darwin*|aarch64*-*|riscv*) CFLAGS="$CFLAGS -U_FORTIFY_SOURCE" ;; i*86-*-darwin*) @@ -4900,6 +4954,66 @@ if test ${TARGET} = ARM; then fi fi +if test ${TARGET} = RISCV32 -o ${TARGET} = RISCV64; then + AC_ARG_WITH([riscv-fpabi], [ --with-riscv-fpabi=auto,double,soft Select RISC-V floating point ABI (auto)], [fpabi=$withval], [fpabi=double]) + + AC_MSG_CHECKING([which RISC-V floating point ABI to use]) + + if test x$fpabi = xauto; then + AC_TRY_COMPILE([], [ + #ifdef __riscv_float_abi_double + #error "double" + #endif + ], [ + ], [ + fpabi=double + ]) + fi + + if test x$fpabi = xauto; then + AC_TRY_COMPILE([], [ + #ifdef __riscv_float_abi_single + #error "single" + #endif + ], [ + ], [ + fpabi=single + ]) + fi + + if test x$fpabi = xauto; then + AC_TRY_COMPILE([], [ + #ifdef __riscv_float_abi_soft + #error "soft" + #endif + ], [ + ], [ + fpabi=soft + ]) + fi + + case $fpabi in + double) + AC_DEFINE([RISCV_FPABI_DOUBLE], [1], [RISC-V FPABI is double-precision]) + AC_MSG_RESULT([double-precision]) + ;; + single) + AC_DEFINE([RISCV_FPABI_SINGLE], [1], [RISC-V FPABI is single-precision]) + AC_MSG_ERROR([single-precision, not supported]) + ;; + soft) + AC_DEFINE([RISCV_FPABI_SOFT], [1], [RISC-V FPABI is soft float]) + AC_MSG_RESULT([soft float]) + ;; + auto) + AC_MSG_ERROR([unknown]) + ;; + *) + AC_MSG_ERROR([invalid option: $fpabi]) + ;; + esac +fi + if test ${TARGET} = unknown; then CPPFLAGS="$CPPFLAGS -DNO_PORT" AC_MSG_WARN("mono has not been ported to $host: some things may not work.") @@ -5262,6 +5376,12 @@ if test "x$enable_btls" = "xyes"; then android-x64) BTLS_CMAKE_ARGS="-DANDROID_ABI=\"x86_64\" -DANDROID_NATIVE_API_LEVEL=21" ;; + riscv32) + btls_arch=riscv32 + ;; + riscv64) + btls_arch=riscv64 + ;; *) AC_MSG_ERROR(Invalid BTLS platform) esac @@ -5318,11 +5438,17 @@ AM_CONDITIONAL(POWERPC64, test x$TARGET = xPOWERPC64) AM_CONDITIONAL(ARM, test x$TARGET = xARM) AM_CONDITIONAL(ARM64, test x$TARGET = xARM64) AM_CONDITIONAL(S390X, test x$TARGET = xS390X) +AM_CONDITIONAL([RISCV], [test x$TARGET = xRISCV32 -o x$TARGET = xRISCV64]) +AM_CONDITIONAL([RISCV32], [test x$TARGET = xRISCV32]) +AM_CONDITIONAL([RISCV64], [test x$TARGET = xRISCV64]) AM_CONDITIONAL(WASM, test x$TARGET = xWASM) AM_CONDITIONAL(HOST_X86, test x$HOST = xX86) AM_CONDITIONAL(HOST_AMD64, test x$HOST = xAMD64) AM_CONDITIONAL(HOST_ARM, test x$HOST = xARM) AM_CONDITIONAL(HOST_ARM64, test x$HOST = xARM64) +AM_CONDITIONAL([HOST_RISCV], [test x$HOST = xRISCV32 -o x$HOST = xRISCV64]) +AM_CONDITIONAL([HOST_RISCV32], [test x$HOST = xRISCV32]) +AM_CONDITIONAL([HOST_RISCV64], [test x$HOST = xRISCV64]) AM_CONDITIONAL(HOST_WASM, test x$HOST = xWASM) AM_CONDITIONAL(CROSS_COMPILE, test "x$host" != "x$target") @@ -5818,6 +5944,7 @@ mono/arch/s390x/Makefile mono/arch/arm/Makefile mono/arch/arm64/Makefile mono/arch/mips/Makefile +mono/arch/riscv/Makefile mono/sgen/Makefile mono/native/platform-type.c mono/native/platform-type-compat.c diff --git a/docs/riscv.md b/docs/riscv.md new file mode 100644 index 00000000000..53e42761514 --- /dev/null +++ b/docs/riscv.md @@ -0,0 +1,116 @@ +# Mono RISC-V Port + +These are some useful links and notes pertaining to the RISC-V port of Mono. + +## Useful RISC-V documents + +* [RISC-V User-Level ISA Specification](https://riscv.org/specifications/) +* [RISC-V Privileged ISA Specification](https://riscv.org/specifications/privileged-isa/) +* [RISC-V Debug Specification Standard](https://github.com/riscv/riscv-debug-spec/blob/master/riscv-debug-spec.pdf) +* [RISC-V Assembly Programmer's Manual](https://github.com/riscv/riscv-asm-manual/blob/master/riscv-asm.md) +* [RISC-V ELF psABI Specification](https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md) + +## Useful RISC-V repositories + +* [RISC-V Organization](https://github.com/riscv) + * [RISC-V Linux](https://github.com/riscv/riscv-linux) + * [RISC-V LLD](https://github.com/riscv/riscv-lld) + * [RISC-V Tools](https://github.com/riscv/riscv-tools) + * [RISC-V GNU Toolchain](https://github.com/riscv/riscv-gnu-toolchain) + * [RISC-V Binutils](https://github.com/riscv/riscv-binutils-gdb) + * [RISC-V GCC](https://github.com/riscv/riscv-gcc) + * [RISC-V Glibc](https://github.com/riscv/riscv-glibc) + * [RISC-V Newlib](https://github.com/riscv/riscv-newlib) + * [RISC-V QEMU](https://github.com/riscv/riscv-qemu) + * [RISC-V Opcodes](https://github.com/riscv/riscv-opcodes) + * [RISC-V Tests](https://github.com/riscv/riscv-tests) +* [lowRISC Organization](https://github.com/lowrisc) + * [RISC-V LLVM](https://github.com/lowrisc/riscv-llvm) + +## Setting up a cross environment + +Setting up a cross environment with a Linux toolchain and QEMU is quite easy. + +First, add these to your `.bashrc` (or some other script that you run): + +```bash +export RISCV=$HOME/riscv +export PATH=$RISCV/bin:$PATH +export QEMU_LD_PREFIX=$RISCV/sysroot +``` + +Install some dependencies needed to build the toolchain: + +```console +# apt install autoconf automake autotools-dev curl libmpc-dev libmpfr-dev libgmp-dev libusb-1.0-0-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev device-tree-compiler pkg-config libexpat-dev libglib2.0-dev libpixman-1-dev +``` + +Now you can build the toolchain: + +```console +$ git clone --recursive git@github.com:riscv/riscv-tools.git +$ cd riscv-tools +$ ./build.sh +$ cd riscv-gnu-toolchain +$ ./configure --prefix=$RISCV --enable-multilib +$ make linux +$ cd ../.. +$ git clone --recursive git@github.com:riscv/riscv-qemu.git +$ cd riscv-qemu +$ mkdir build +$ cd build +$ ../configure --prefix=$RISCV --disable-werror +$ make +$ make install +``` + +## Building Mono with a cross toolchain + +Building Mono is quite straightforward: + +```console +$ ./autogen.sh --prefix=$RISCV/sysroot --host=riscv64-unknown-linux-gnu +$ make +$ make install +``` + +You can set `CFLAGS` as appropriate to change the RISC-V options, such as which +standard extensions and ABI to use. For example, to use the 64-bit soft float +ABI: + +```console +$ CFLAGS="-mabi=lp64" ./autogen.sh --prefix=$RISCV/sysroot --host=riscv64-unknown-linux-gnu +``` + +Note that, since this is a cross build, the `mcs` directory won't be built. You +will have to build the managed libraries and tools through a native build of +Mono and copy them into `$RISCV/sysroot`. + +You can run Mono with QEMU like this: + +```console +$ qemu-riscv64 $RISCV/sysroot/bin/mono hello.exe +``` + +## Debugging + +```console +$ qemu-riscv64 -g 12345 ./mono/mini/mono-sgen --interp basic.exe & +$ riscv64-unknown-elf-gdb -ex 'target remote localhost:12345' -ex 'b main' -ex 'c' ./mono/mini/mono-sgen +``` + +## Things to be done + +In no particular order: + +* Complete the soft float port. +* Complete the 32-bit port. +* Add unwind info to trampolines. +* Implement AOT support. +* Implement interpreter support. +* Implement LLVM support. +* Implement SDB support. +* Implement `dyn_call` support. +* Ensure all runtime tests pass. +* Ensure all corlib tests pass. +* Set up CI on Jenkins. diff --git a/mono/arch/Makefile.am b/mono/arch/Makefile.am index 9f136d32473..61f5522ee1c 100644 --- a/mono/arch/Makefile.am +++ b/mono/arch/Makefile.am @@ -1,6 +1,6 @@ include $(top_srcdir)/mk/common.mk -DIST_SUBDIRS = x86 ppc sparc arm arm64 s390x amd64 mips +DIST_SUBDIRS = x86 ppc sparc arm arm64 s390x amd64 mips riscv AM_CPPFLAGS = $(GLIB_CFLAGS) -I$(top_srcdir) @@ -9,4 +9,6 @@ if ARM SUBDIRS = arm endif - +if RISCV +SUBDIRS = riscv +endif diff --git a/mono/arch/riscv/.gitignore b/mono/arch/riscv/.gitignore new file mode 100644 index 00000000000..f1e931fc770 --- /dev/null +++ b/mono/arch/riscv/.gitignore @@ -0,0 +1,5 @@ +/Makefile +/riscv-codegen-test +/riscv-codegen +/riscv-codegen.elf +/riscv-codegen.s diff --git a/mono/arch/riscv/Makefile.am b/mono/arch/riscv/Makefile.am new file mode 100644 index 00000000000..16505ff8e5a --- /dev/null +++ b/mono/arch/riscv/Makefile.am @@ -0,0 +1,19 @@ +AM_CPPFLAGS = $(GLIB_CFLAGS) + +EXTRA_DIST = riscv-codegen.h + +bin_PROGRAMS = riscv-codegen-test + +riscv_codegen_test_SOURCES = riscv-codegen-test.c + +if RISCV64 +bits = 64 +else +bits = 32 +endif + +check-local: riscv-codegen-test + ./riscv-codegen-test > riscv-codegen.s + $(AS) riscv-codegen.s -o riscv-codegen.elf + $(OBJDUMP) -D -M numeric,no-aliases riscv-codegen.elf > riscv-codegen.res + diff -u riscv-codegen.exp$(bits) riscv-codegen.res diff --git a/mono/arch/riscv/riscv-codegen-test.c b/mono/arch/riscv/riscv-codegen-test.c new file mode 100644 index 00000000000..722dc0f820e --- /dev/null +++ b/mono/arch/riscv/riscv-codegen-test.c @@ -0,0 +1,238 @@ +/* + * Licensed to the .NET Foundation under one or more agreements. + * The .NET Foundation licenses this file to you under the MIT license. + * See the LICENSE file in the project root for more information. + */ + +#define MONO_RISCV_CODEGEN_TEST + +#include "riscv-codegen.h" +#include <stdio.h> + +static guint8 code [4096 * 16]; + +int +main (void) +{ + guint8 *p = code; + + { + // R + + riscv_add (p, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_sub (p, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_sll (p, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_slt (p, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_sltu (p, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_xor (p, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_srl (p, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_sra (p, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_or (p, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_and (p, RISCV_X0, RISCV_X1, RISCV_X2); +#ifdef TARGET_RISCV64 + riscv_addw (p, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_subw (p, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_sllw (p, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_srlw (p, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_sraw (p, RISCV_X0, RISCV_X1, RISCV_X2); +#endif + riscv_mul (p, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_mulh (p, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_mulhsu (p, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_mulhu (p, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_div (p, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_divu (p, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_rem (p, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_remu (p, RISCV_X0, RISCV_X1, RISCV_X2); +#ifdef TARGET_RISCV64 + riscv_mulw (p, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_divw (p, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_divuw (p, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_remw (p, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_remuw (p, RISCV_X0, RISCV_X1, RISCV_X2); +#endif + riscv_fadd_s (p, RISCV_ROUND_NE, RISCV_F0, RISCV_F1, RISCV_F2); + riscv_fsub_s (p, RISCV_ROUND_TZ, RISCV_F0, RISCV_F1, RISCV_F2); + riscv_fmul_s (p, RISCV_ROUND_DN, RISCV_F0, RISCV_F1, RISCV_F2); + riscv_fdiv_s (p, RISCV_ROUND_UP, RISCV_F0, RISCV_F1, RISCV_F2); + riscv_fsqrt_s (p, RISCV_ROUND_MM, RISCV_F0, RISCV_F1); + riscv_fsgnj_s (p, RISCV_F0, RISCV_F1, RISCV_F2); + riscv_fsgnjn_s (p, RISCV_F0, RISCV_F1, RISCV_F2); + riscv_fsgnjx_s (p, RISCV_F0, RISCV_F1, RISCV_F2); + riscv_fmin_s (p, RISCV_F0, RISCV_F1, RISCV_F2); + riscv_fmax_s (p, RISCV_F0, RISCV_F1, RISCV_F2); + riscv_fcvt_w_s (p, RISCV_ROUND_DY, RISCV_X0, RISCV_F1); + riscv_fcvt_wu_s (p, RISCV_ROUND_NE, RISCV_X0, RISCV_F1); + riscv_fmv_x_w (p, RISCV_X0, RISCV_F1); + riscv_feq_s (p, RISCV_X0, RISCV_F1, RISCV_F2); + riscv_flt_s (p, RISCV_X0, RISCV_F1, RISCV_F2); + riscv_fle_s (p, RISCV_X0, RISCV_F1, RISCV_F2); + riscv_fclass_s (p, RISCV_X0, RISCV_F1); + riscv_fcvt_s_w (p, RISCV_ROUND_TZ, RISCV_F0, RISCV_X1); + riscv_fcvt_s_wu (p, RISCV_ROUND_DN, RISCV_F0, RISCV_X1); + riscv_fmv_w_x (p, RISCV_F0, RISCV_X1); +#ifdef TARGET_RISCV64 + riscv_fcvt_l_s (p, RISCV_ROUND_UP, RISCV_X0, RISCV_F1); + riscv_fcvt_lu_s (p, RISCV_ROUND_MM, RISCV_X0, RISCV_F1); + riscv_fcvt_s_l (p, RISCV_ROUND_DY, RISCV_F0, RISCV_X1); + riscv_fcvt_s_lu (p, RISCV_ROUND_NE, RISCV_F0, RISCV_X1); +#endif + riscv_fadd_d (p, RISCV_ROUND_TZ, RISCV_F0, RISCV_F1, RISCV_F2); + riscv_fsub_d (p, RISCV_ROUND_DN, RISCV_F0, RISCV_F1, RISCV_F2); + riscv_fmul_d (p, RISCV_ROUND_UP, RISCV_F0, RISCV_F1, RISCV_F2); + riscv_fdiv_d (p, RISCV_ROUND_MM, RISCV_F0, RISCV_F1, RISCV_F2); + riscv_fsqrt_d (p, RISCV_ROUND_DY, RISCV_F0, RISCV_F1); + riscv_fsgnj_d (p, RISCV_F0, RISCV_F1, RISCV_F2); + riscv_fsgnjn_d (p, RISCV_F0, RISCV_F1, RISCV_F2); + riscv_fsgnjx_d (p, RISCV_F0, RISCV_F1, RISCV_F2); + riscv_fmin_d (p, RISCV_F0, RISCV_F1, RISCV_F2); + riscv_fmax_d (p, RISCV_F0, RISCV_F1, RISCV_F2); + riscv_fcvt_s_d (p, RISCV_ROUND_NE, RISCV_F0, RISCV_F1); + riscv_fcvt_d_s (p, RISCV_F0, RISCV_F1); + riscv_feq_d (p, RISCV_X0, RISCV_F1, RISCV_F2); + riscv_flt_d (p, RISCV_X0, RISCV_F1, RISCV_F2); + riscv_fle_d (p, RISCV_X0, RISCV_F1, RISCV_F2); + riscv_fclass_d (p, RISCV_X0, RISCV_F1); + riscv_fcvt_w_d (p, RISCV_ROUND_TZ, RISCV_X0, RISCV_F1); + riscv_fcvt_wu_d (p, RISCV_ROUND_DN, RISCV_X0, RISCV_F1); + riscv_fcvt_d_w (p, RISCV_F0, RISCV_X1); + riscv_fcvt_d_wu (p, RISCV_F0, RISCV_X1); +#ifdef TARGET_RISCV64 + riscv_fcvt_l_d (p, RISCV_ROUND_UP, RISCV_X0, RISCV_F1); + riscv_fcvt_lu_d (p, RISCV_ROUND_MM, RISCV_X0, RISCV_F1); + riscv_fmv_x_d (p, RISCV_X0, RISCV_F1); + riscv_fcvt_d_l (p, RISCV_ROUND_DY, RISCV_F0, RISCV_X1); + riscv_fcvt_d_lu (p, RISCV_ROUND_NE, RISCV_F0, RISCV_X1); + riscv_fmv_d_x (p, RISCV_F0, RISCV_X1); +#endif + + // R4 + + riscv_fmadd_s (p, RISCV_ROUND_NE, RISCV_F0, RISCV_F1, RISCV_F2, RISCV_F3); + riscv_fmsub_s (p, RISCV_ROUND_TZ, RISCV_F0, RISCV_F1, RISCV_F2, RISCV_F3); + riscv_fnmadd_s (p, RISCV_ROUND_DN, RISCV_F0, RISCV_F1, RISCV_F2, RISCV_F3); + riscv_fnmadd_s (p, RISCV_ROUND_UP, RISCV_F0, RISCV_F1, RISCV_F2, RISCV_F3); + riscv_fmadd_d (p, RISCV_ROUND_MM, RISCV_F0, RISCV_F1, RISCV_F2, RISCV_F3); + riscv_fmsub_d (p, RISCV_ROUND_DY, RISCV_F0, RISCV_F1, RISCV_F2, RISCV_F3); + riscv_fnmadd_d (p, RISCV_ROUND_NE, RISCV_F0, RISCV_F1, RISCV_F2, RISCV_F3); + riscv_fnmadd_d (p, RISCV_ROUND_TZ, RISCV_F0, RISCV_F1, RISCV_F2, RISCV_F3); + + // I + + riscv_jalr (p, RISCV_X0, RISCV_X1, 123); + riscv_jalr (p, RISCV_X0, RISCV_X1, -123); + riscv_lb (p, RISCV_X0, RISCV_X1, 321); + riscv_lh (p, RISCV_X0, RISCV_X1, -321); + riscv_lw (p, RISCV_X0, RISCV_X1, 123); + riscv_lbu (p, RISCV_X0, RISCV_X1, -123); + riscv_lhu (p, RISCV_X0, RISCV_X1, 321); + riscv_addi (p, RISCV_X0, RISCV_X1, -321); + riscv_slti (p, RISCV_X0, RISCV_X1, 123); + riscv_sltiu (p, RISCV_X0, RISCV_X1, -123); + riscv_xori (p, RISCV_X0, RISCV_X1, 321); + riscv_ori (p, RISCV_X0, RISCV_X1, -321); + riscv_andi (p, RISCV_X0, RISCV_X1, 123); + riscv_ecall (p); + riscv_ebreak (p); +#ifdef TARGET_RISCV64 + riscv_lwu (p, RISCV_X0, RISCV_X1, -123); + riscv_ld (p, RISCV_X0, RISCV_X1, 321); + riscv_addiw (p, RISCV_X0, RISCV_X1, -321); +#endif + riscv_flw (p, RISCV_F0, RISCV_X1, 123); + riscv_fld (p, RISCV_F0, RISCV_X1, -123); + + // IS/LS + + riscv_slli (p, RISCV_X0, RISCV_X1, 1); + riscv_srli (p, RISCV_X0, RISCV_X1, 2); + riscv_srai (p, RISCV_X0, RISCV_X1, 3); +#ifdef TARGET_RISCV64 + riscv_slliw (p, RISCV_X0, RISCV_X1, 1); + riscv_srliw (p, RISCV_X0, RISCV_X1, 2); + riscv_sraiw (p, RISCV_X0, RISCV_X1, 3); +#endif + + // IC + + riscv_csrrw (p, RISCV_X0, RISCV_CSR_FFLAGS, RISCV_X1); + riscv_csrrs (p, RISCV_X0, RISCV_CSR_FRM, RISCV_X1); + riscv_csrrc (p, RISCV_X0, RISCV_CSR_FCSR, RISCV_X1); + riscv_csrrwi (p, RISCV_X0, RISCV_CSR_CYCLE, 1); + riscv_csrrsi (p, RISCV_X0, RISCV_CSR_TIME, 2); + riscv_csrrci (p, RISCV_X0, RISCV_CSR_INSTRET, 3); + + // S + + riscv_sb (p, RISCV_X0, RISCV_X1, 123); + riscv_sh (p, RISCV_X0, RISCV_X1, -123); + riscv_sw (p, RISCV_X0, RISCV_X1, 321); +#ifdef TARGET_RISCV64 + riscv_sd (p, RISCV_X0, RISCV_X1, -321); +#endif + riscv_fsw (p, RISCV_F0, RISCV_X1, 123); + riscv_fsd (p, RISCV_F0, RISCV_X1, -123); + + // B + + riscv_beq (p, RISCV_X0, RISCV_X1, 128); + riscv_bne (p, RISCV_X0, RISCV_X1, -128); + riscv_blt (p, RISCV_X0, RISCV_X1, 256); + riscv_bge (p, RISCV_X0, RISCV_X1, -256); + riscv_bltu (p, RISCV_X0, RISCV_X1, 512); + riscv_bgeu (p, RISCV_X0, RISCV_X1, -512); + + // U + + riscv_lui (p, RISCV_X0, 123); + riscv_auipc (p, RISCV_X0, 321); + + // J + + riscv_jal (p, RISCV_X0, 128); + riscv_jal (p, RISCV_X0, -128); + + // F + + riscv_fence (p, RISCV_FENCE_W, RISCV_FENCE_R); + riscv_fence (p, RISCV_FENCE_O, RISCV_FENCE_I); + riscv_fence (p, RISCV_FENCE_MEM, RISCV_FENCE_DEV); + riscv_fence (p, RISCV_FENCE_NONE, RISCV_FENCE_ALL); + riscv_fence_i (p); + + // A + + riscv_lr_w (p, RISCV_ORDER_RL, RISCV_X0, RISCV_X1); + riscv_sc_w (p, RISCV_ORDER_AQ, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_amoswap_w (p, RISCV_ORDER_ALL, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_amoadd_w (p, RISCV_ORDER_RL, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_amoxor_w (p, RISCV_ORDER_AQ, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_amoand_w (p, RISCV_ORDER_ALL, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_amoor_w (p, RISCV_ORDER_RL, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_amomin_w (p, RISCV_ORDER_AQ, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_amomax_w (p, RISCV_ORDER_ALL, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_amominu_w (p, RISCV_ORDER_RL, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_amomaxu_w (p, RISCV_ORDER_AQ, RISCV_X0, RISCV_X1, RISCV_X2); +#ifdef TARGET_RISCV64 + riscv_lr_d (p, RISCV_ORDER_RL, RISCV_X0, RISCV_X1); + riscv_sc_d (p, RISCV_ORDER_AQ, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_amoswap_d (p, RISCV_ORDER_ALL, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_amoadd_d (p, RISCV_ORDER_RL, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_amoxor_d (p, RISCV_ORDER_AQ, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_amoand_d (p, RISCV_ORDER_ALL, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_amoor_d (p, RISCV_ORDER_RL, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_amomin_d (p, RISCV_ORDER_AQ, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_amomax_d (p, RISCV_ORDER_ALL, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_amominu_d (p, RISCV_ORDER_RL, RISCV_X0, RISCV_X1, RISCV_X2); + riscv_amomaxu_d (p, RISCV_ORDER_AQ, RISCV_X0, RISCV_X1, RISCV_X2); +#endif + } + + guint8 *p2 = code; + + do { + printf (".byte %d\n", *p2); + } while (++p2 != p); + + return 0; +} diff --git a/mono/arch/riscv/riscv-codegen-test.sh b/mono/arch/riscv/riscv-codegen-test.sh new file mode 100755 index 00000000000..22c565b4da4 --- /dev/null +++ b/mono/arch/riscv/riscv-codegen-test.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +# This can be used to test instruction encodings when cross-compiling. + +if grep "#define TARGET_RISCV64 1" ../../../config.h > /dev/null; then + bits=64 +else + bits=32 +fi + +gcc -I../../.. -I../../eglib riscv-codegen-test.c -o riscv-codegen-test $@ || exit 1 +./riscv-codegen-test > riscv-codegen.s || exit 1 +riscv64-unknown-linux-gnu-as riscv-codegen.s -o riscv-codegen.elf || exit 1 +riscv64-unknown-linux-gnu-objdump -D -M numeric,no-aliases riscv-codegen.elf > riscv-codegen.res || exit 1 +diff -u riscv-codegen.exp${bits} riscv-codegen.res || exit 1 diff --git a/mono/arch/riscv/riscv-codegen.exp32 b/mono/arch/riscv/riscv-codegen.exp32 new file mode 100644 index 00000000000..3966ea39d8f --- /dev/null +++ b/mono/arch/riscv/riscv-codegen.exp32 @@ -0,0 +1,130 @@ + +riscv-codegen.elf: file format elf32-littleriscv + + +Disassembly of section .text: + +00000000 <.text>: + 0: 00208033 add x0,x1,x2 + 4: 40208033 sub x0,x1,x2 + 8: 00209033 sll x0,x1,x2 + c: 0020a033 slt x0,x1,x2 + 10: 0020b033 sltu x0,x1,x2 + 14: 0020c033 xor x0,x1,x2 + 18: 0020d033 srl x0,x1,x2 + 1c: 4020d033 sra x0,x1,x2 + 20: 0020e033 or x0,x1,x2 + 24: 0020f033 and x0,x1,x2 + 28: 02208033 mul x0,x1,x2 + 2c: 02209033 mulh x0,x1,x2 + 30: 0220a033 mulhsu x0,x1,x2 + 34: 0220b033 mulhu x0,x1,x2 + 38: 0220c033 div x0,x1,x2 + 3c: 0220d033 divu x0,x1,x2 + 40: 0220e033 rem x0,x1,x2 + 44: 0220f033 remu x0,x1,x2 + 48: 00208053 fadd.s f0,f1,f2,rne + 4c: 08209053 fsub.s f0,f1,f2,rtz + 50: 1020a053 fmul.s f0,f1,f2,rdn + 54: 1820b053 fdiv.s f0,f1,f2,rup + 58: 5800c053 fsqrt.s f0,f1,rmm + 5c: 20208053 fsgnj.s f0,f1,f2 + 60: 20209053 fsgnjn.s f0,f1,f2 + 64: 2020a053 fsgnjx.s f0,f1,f2 + 68: 28208053 fmin.s f0,f1,f2 + 6c: 28209053 fmax.s f0,f1,f2 + 70: c000f053 fcvt.w.s x0,f1 + 74: c0108053 fcvt.wu.s x0,f1,rne + 78: e0008053 fmv.x.w x0,f1 + 7c: a020a053 feq.s x0,f1,f2 + 80: a0209053 flt.s x0,f1,f2 + 84: a0208053 fle.s x0,f1,f2 + 88: e0009053 fclass.s x0,f1 + 8c: d0009053 fcvt.s.w f0,x1,rtz + 90: d010a053 fcvt.s.wu f0,x1,rdn + 94: f0008053 fmv.w.x f0,x1 + 98: 02209053 fadd.d f0,f1,f2,rtz + 9c: 0a20a053 fsub.d f0,f1,f2,rdn + a0: 1220b053 fmul.d f0,f1,f2,rup + a4: 1a20c053 fdiv.d f0,f1,f2,rmm + a8: 5a00f053 fsqrt.d f0,f1 + ac: 22208053 fsgnj.d f0,f1,f2 + b0: 22209053 fsgnjn.d f0,f1,f2 + b4: 2220a053 fsgnjx.d f0,f1,f2 + b8: 2a208053 fmin.d f0,f1,f2 + bc: 2a209053 fmax.d f0,f1,f2 + c0: 40108053 fcvt.s.d f0,f1,rne + c4: 42008053 fcvt.d.s f0,f1 + c8: a220a053 feq.d x0,f1,f2 + cc: a2209053 flt.d x0,f1,f2 + d0: a2208053 fle.d x0,f1,f2 + d4: e2009053 fclass.d x0,f1 + d8: c2009053 fcvt.w.d x0,f1,rtz + dc: c210a053 fcvt.wu.d x0,f1,rdn + e0: d2008053 fcvt.d.w f0,x1 + e4: d2108053 fcvt.d.wu f0,x1 + e8: 18208043 fmadd.s f0,f1,f2,f3,rne + ec: 18209047 fmsub.s f0,f1,f2,f3,rtz + f0: 1820a04b fnmsub.s f0,f1,f2,f3,rdn + f4: 1820b04b fnmsub.s f0,f1,f2,f3,rup + f8: 1a20c043 fmadd.d f0,f1,f2,f3,rmm + fc: 1a20f047 fmsub.d f0,f1,f2,f3 + 100: 1a20804b fnmsub.d f0,f1,f2,f3,rne + 104: 1a20904b fnmsub.d f0,f1,f2,f3,rtz + 108: 07b08067 jalr x0,123(x1) + 10c: f8508067 jalr x0,-123(x1) + 110: 14108003 lb x0,321(x1) + 114: ebf09003 lh x0,-321(x1) + 118: 07b0a003 lw x0,123(x1) + 11c: f850c003 lbu x0,-123(x1) + 120: 1410d003 lhu x0,321(x1) + 124: ebf08013 addi x0,x1,-321 + 128: 07b0a013 slti x0,x1,123 + 12c: f850b013 sltiu x0,x1,-123 + 130: 1410c013 xori x0,x1,321 + 134: ebf0e013 ori x0,x1,-321 + 138: 07b0f013 andi x0,x1,123 + 13c: 00000073 ecall + 140: 00100073 ebreak + 144: 07b0a007 flw f0,123(x1) + 148: f850b007 fld f0,-123(x1) + 14c: 00109013 slli x0,x1,0x1 + 150: 0020d013 srli x0,x1,0x2 + 154: 4030d013 srai x0,x1,0x3 + 158: 00109073 fsflags x1 + 15c: 0020a073 csrrs x0,frm,x1 + 160: 0030b073 csrrc x0,fcsr,x1 + 164: c000d073 csrrwi x0,cycle,1 + 168: c0116073 csrrsi x0,time,2 + 16c: c021f073 csrrci x0,instret,3 + 170: 06008da3 sb x0,123(x1) + 174: f80092a3 sh x0,-123(x1) + 178: 1400a0a3 sw x0,321(x1) + 17c: 0600ada7 fsw f0,123(x1) + 180: f800b2a7 fsd f0,-123(x1) + 184: 08100063 beq x0,x1,0x204 + 188: f81010e3 bne x0,x1,0x108 + 18c: 10104063 blt x0,x1,0x28c + 190: f01050e3 bge x0,x1,0x90 + 194: 20106063 bltu x0,x1,0x394 + 198: e01070e3 bgeu x0,x1,0xffffff98 + 19c: 0007b037 lui x0,0x7b + 1a0: 00141017 auipc x0,0x141 + 1a4: 0800006f jal x0,0x224 + 1a8: f81ff06f jal x0,0x128 + 1ac: 0120000f fence w,r + 1b0: 0480000f fence o,i + 1b4: 03c0000f fence rw,io + 1b8: 00f0000f fence unknown,iorw + 1bc: 0000100f fence.i + 1c0: 1200a02f lr.w.rl x0,(x1) + 1c4: 1c11202f sc.w.aq x0,x1,(x2) + 1c8: 0e11202f amoswap.w.aqrl x0,x1,(x2) + 1cc: 0211202f amoadd.w.rl x0,x1,(x2) + 1d0: 2411202f amoxor.w.aq x0,x1,(x2) + 1d4: 6611202f amoand.w.aqrl x0,x1,(x2) + 1d8: 4211202f amoor.w.rl x0,x1,(x2) + 1dc: 8411202f amomin.w.aq x0,x1,(x2) + 1e0: a611202f amomax.w.aqrl x0,x1,(x2) + 1e4: c211202f amominu.w.rl x0,x1,(x2) + 1e8: e411202f amomaxu.w.aq x0,x1,(x2) diff --git a/mono/arch/riscv/riscv-codegen.exp64 b/mono/arch/riscv/riscv-codegen.exp64 new file mode 100644 index 00000000000..68e9b78c077 --- /dev/null +++ b/mono/arch/riscv/riscv-codegen.exp64 @@ -0,0 +1,168 @@ + +riscv-codegen.elf: file format elf64-littleriscv + + +Disassembly of section .text: + +0000000000000000 <.text>: + 0: 00208033 add x0,x1,x2 + 4: 40208033 sub x0,x1,x2 + 8: 00209033 sll x0,x1,x2 + c: 0020a033 slt x0,x1,x2 + 10: 0020b033 sltu x0,x1,x2 + 14: 0020c033 xor x0,x1,x2 + 18: 0020d033 srl x0,x1,x2 + 1c: 4020d033 sra x0,x1,x2 + 20: 0020e033 or x0,x1,x2 + 24: 0020f033 and x0,x1,x2 + 28: 0020803b addw x0,x1,x2 + 2c: 4020803b subw x0,x1,x2 + 30: 0020903b sllw x0,x1,x2 + 34: 0020d03b srlw x0,x1,x2 + 38: 4020d03b sraw x0,x1,x2 + 3c: 02208033 mul x0,x1,x2 + 40: 02209033 mulh x0,x1,x2 + 44: 0220a033 mulhsu x0,x1,x2 + 48: 0220b033 mulhu x0,x1,x2 + 4c: 0220c033 div x0,x1,x2 + 50: 0220d033 divu x0,x1,x2 + 54: 0220e033 rem x0,x1,x2 + 58: 0220f033 remu x0,x1,x2 + 5c: 0220803b mulw x0,x1,x2 + 60: 0220c03b divw x0,x1,x2 + 64: 0220d03b divuw x0,x1,x2 + 68: 0220e03b remw x0,x1,x2 + 6c: 0220f03b remuw x0,x1,x2 + 70: 00208053 fadd.s f0,f1,f2,rne + 74: 08209053 fsub.s f0,f1,f2,rtz + 78: 1020a053 fmul.s f0,f1,f2,rdn + 7c: 1820b053 fdiv.s f0,f1,f2,rup + 80: 5800c053 fsqrt.s f0,f1,rmm + 84: 20208053 fsgnj.s f0,f1,f2 + 88: 20209053 fsgnjn.s f0,f1,f2 + 8c: 2020a053 fsgnjx.s f0,f1,f2 + 90: 28208053 fmin.s f0,f1,f2 + 94: 28209053 fmax.s f0,f1,f2 + 98: c000f053 fcvt.w.s x0,f1 + 9c: c0108053 fcvt.wu.s x0,f1,rne + a0: e0008053 fmv.x.w x0,f1 + a4: a020a053 feq.s x0,f1,f2 + a8: a0209053 flt.s x0,f1,f2 + ac: a0208053 fle.s x0,f1,f2 + b0: e0009053 fclass.s x0,f1 + b4: d0009053 fcvt.s.w f0,x1,rtz + b8: d010a053 fcvt.s.wu f0,x1,rdn + bc: f0008053 fmv.w.x f0,x1 + c0: c020b053 fcvt.l.s x0,f1,rup + c4: c030c053 fcvt.lu.s x0,f1,rmm + c8: d020f053 fcvt.s.l f0,x1 + cc: d0308053 fcvt.s.lu f0,x1,rne + d0: 02209053 fadd.d f0,f1,f2,rtz + d4: 0a20a053 fsub.d f0,f1,f2,rdn + d8: 1220b053 fmul.d f0,f1,f2,rup + dc: 1a20c053 fdiv.d f0,f1,f2,rmm + e0: 5a00f053 fsqrt.d f0,f1 + e4: 22208053 fsgnj.d f0,f1,f2 + e8: 22209053 fsgnjn.d f0,f1,f2 + ec: 2220a053 fsgnjx.d f0,f1,f2 + f0: 2a208053 fmin.d f0,f1,f2 + f4: 2a209053 fmax.d f0,f1,f2 + f8: 40108053 fcvt.s.d f0,f1,rne + fc: 42008053 fcvt.d.s f0,f1 + 100: a220a053 feq.d x0,f1,f2 + 104: a2209053 flt.d x0,f1,f2 + 108: a2208053 fle.d x0,f1,f2 + 10c: e2009053 fclass.d x0,f1 + 110: c2009053 fcvt.w.d x0,f1,rtz + 114: c210a053 fcvt.wu.d x0,f1,rdn + 118: d2008053 fcvt.d.w f0,x1 + 11c: d2108053 fcvt.d.wu f0,x1 + 120: c220b053 fcvt.l.d x0,f1,rup + 124: c230c053 fcvt.lu.d x0,f1,rmm + 128: e2008053 fmv.x.d x0,f1 + 12c: d220f053 fcvt.d.l f0,x1 + 130: d2308053 fcvt.d.lu f0,x1,rne + 134: f2008053 fmv.d.x f0,x1 + 138: 18208043 fmadd.s f0,f1,f2,f3,rne + 13c: 18209047 fmsub.s f0,f1,f2,f3,rtz + 140: 1820a04b fnmsub.s f0,f1,f2,f3,rdn + 144: 1820b04b fnmsub.s f0,f1,f2,f3,rup + 148: 1a20c043 fmadd.d f0,f1,f2,f3,rmm + 14c: 1a20f047 fmsub.d f0,f1,f2,f3 + 150: 1a20804b fnmsub.d f0,f1,f2,f3,rne + 154: 1a20904b fnmsub.d f0,f1,f2,f3,rtz + 158: 07b08067 jalr x0,123(x1) + 15c: f8508067 jalr x0,-123(x1) + 160: 14108003 lb x0,321(x1) + 164: ebf09003 lh x0,-321(x1) + 168: 07b0a003 lw x0,123(x1) + 16c: f850c003 lbu x0,-123(x1) + 170: 1410d003 lhu x0,321(x1) + 174: ebf08013 addi x0,x1,-321 + 178: 07b0a013 slti x0,x1,123 + 17c: f850b013 sltiu x0,x1,-123 + 180: 1410c013 xori x0,x1,321 + 184: ebf0e013 ori x0,x1,-321 + 188: 07b0f013 andi x0,x1,123 + 18c: 00000073 ecall + 190: 00100073 ebreak + 194: f850e003 lwu x0,-123(x1) + 198: 1410b003 ld x0,321(x1) + 19c: ebf0801b addiw x0,x1,-321 + 1a0: 07b0a007 flw f0,123(x1) + 1a4: f850b007 fld f0,-123(x1) + 1a8: 00109013 slli x0,x1,0x1 + 1ac: 0020d013 srli x0,x1,0x2 + 1b0: 4030d013 srai x0,x1,0x3 + 1b4: 0010901b slliw x0,x1,0x1 + 1b8: 0020d01b srliw x0,x1,0x2 + 1bc: 4030d01b sraiw x0,x1,0x3 + 1c0: 00109073 fsflags x1 + 1c4: 0020a073 csrrs x0,frm,x1 + 1c8: 0030b073 csrrc x0,fcsr,x1 + 1cc: c000d073 csrrwi x0,cycle,1 + 1d0: c0116073 csrrsi x0,time,2 + 1d4: c021f073 csrrci x0,instret,3 + 1d8: 06008da3 sb x0,123(x1) + 1dc: f80092a3 sh x0,-123(x1) + 1e0: 1400a0a3 sw x0,321(x1) + 1e4: ea00bfa3 sd x0,-321(x1) + 1e8: 0600ada7 fsw f0,123(x1) + 1ec: f800b2a7 fsd f0,-123(x1) + 1f0: 08100063 beq x0,x1,0x270 + 1f4: f81010e3 bne x0,x1,0x174 + 1f8: 10104063 blt x0,x1,0x2f8 + 1fc: f01050e3 bge x0,x1,0xfc + 200: 20106063 bltu x0,x1,0x400 + 204: e01070e3 bgeu x0,x1,0x4 + 208: 0007b037 lui x0,0x7b + 20c: 00141017 auipc x0,0x141 + 210: 0800006f jal x0,0x290 + 214: f81ff06f jal x0,0x194 + 218: 0120000f fence w,r + 21c: 0480000f fence o,i + 220: 03c0000f fence rw,io + 224: 00f0000f fence unknown,iorw + 228: 0000100f fence.i + 22c: 1200a02f lr.w.rl x0,(x1) + 230: 1c11202f sc.w.aq x0,x1,(x2) + 234: 0e11202f amoswap.w.aqrl x0,x1,(x2) + 238: 0211202f amoadd.w.rl x0,x1,(x2) + 23c: 2411202f amoxor.w.aq x0,x1,(x2) + 240: 6611202f amoand.w.aqrl x0,x1,(x2) + 244: 4211202f amoor.w.rl x0,x1,(x2) + 248: 8411202f amomin.w.aq x0,x1,(x2) + 24c: a611202f amomax.w.aqrl x0,x1,(x2) + 250: c211202f amominu.w.rl x0,x1,(x2) + 254: e411202f amomaxu.w.aq x0,x1,(x2) + 258: 1200b02f lr.d.rl x0,(x1) + 25c: 1c11302f sc.d.aq x0,x1,(x2) + 260: 0e11302f amoswap.d.aqrl x0,x1,(x2) + 264: 0211302f amoadd.d.rl x0,x1,(x2) + 268: 2411302f amoxor.d.aq x0,x1,(x2) + 26c: 6611302f amoand.d.aqrl x0,x1,(x2) + 270: 4211302f amoor.d.rl x0,x1,(x2) + 274: 8411302f amomin.d.aq x0,x1,(x2) + 278: a611302f amomax.d.aqrl x0,x1,(x2) + 27c: c211302f amominu.d.rl x0,x1,(x2) + 280: e411302f amomaxu.d.aq x0,x1,(x2) diff --git a/mono/arch/riscv/riscv-codegen.h b/mono/arch/riscv/riscv-codegen.h new file mode 100644 index 00000000000..9bd4b4a5822 --- /dev/null +++ b/mono/arch/riscv/riscv-codegen.h @@ -0,0 +1,824 @@ +/* + * Licensed to the .NET Foundation under one or more agreements. + * The .NET Foundation licenses this file to you under the MIT license. + * See the LICENSE file in the project root for more information. + */ + +#ifndef __MONO_RISCV_CODEGEN_H__ +#define __MONO_RISCV_CODEGEN_H__ + +#include "config.h" +#include <glib.h> + +#ifdef MONO_RISCV_CODEGEN_TEST + +#include <stdio.h> +#include <stdlib.h> + +/* + * Avoid having to link with eglib in the codegen test program so that it can + * be built with a native toolchain even if we're building Mono with a cross + * toolchain. + */ + +#undef g_assert +#define g_assert(expr) \ + do { \ + if (G_UNLIKELY (!(expr))) { \ + fprintf (stderr, "* Assertion at %s:%d, condition `%s' not met\n", __FILE__, __LINE__, #expr); \ + abort (); \ + } \ + } while (0) + +#endif + +enum { + RISCV_X0 = 0, + RISCV_X1 = 1, + RISCV_X2 = 2, + RISCV_X3 = 3, + RISCV_X4 = 4, + RISCV_X5 = 5, + RISCV_X6 = 6, + RISCV_X7 = 7, + RISCV_X8 = 8, + RISCV_X9 = 9, + RISCV_X10 = 10, + RISCV_X11 = 11, + RISCV_X12 = 12, + RISCV_X13 = 13, + RISCV_X14 = 14, + RISCV_X15 = 15, + RISCV_X16 = 16, + RISCV_X17 = 17, + RISCV_X18 = 18, + RISCV_X19 = 19, + RISCV_X20 = 20, + RISCV_X21 = 21, + RISCV_X22 = 22, + RISCV_X23 = 23, + RISCV_X24 = 24, + RISCV_X25 = 25, + RISCV_X26 = 26, + RISCV_X27 = 27, + RISCV_X28 = 28, + RISCV_X29 = 29, + RISCV_X30 = 30, + RISCV_X31 = 31, + + RISCV_ZERO = RISCV_X0, + + // Argument and return registers. + + RISCV_A0 = RISCV_X10, + RISCV_A1 = RISCV_X11, + RISCV_A2 = RISCV_X12, + RISCV_A3 = RISCV_X13, + RISCV_A4 = RISCV_X14, + RISCV_A5 = RISCV_X15, + RISCV_A6 = RISCV_X16, + RISCV_A7 = RISCV_X17, + + // Callee-saved registers. + + RISCV_S0 = RISCV_X8, + RISCV_S1 = RISCV_X9, + RISCV_S2 = RISCV_X18, + RISCV_S3 = RISCV_X19, + RISCV_S4 = RISCV_X20, + RISCV_S5 = RISCV_X21, + RISCV_S6 = RISCV_X22, + RISCV_S7 = RISCV_X23, + RISCV_S8 = RISCV_X24, + RISCV_S9 = RISCV_X25, + RISCV_S10 = RISCV_X26, + RISCV_S11 = RISCV_X27, + + // Temporary registers. + + RISCV_T0 = RISCV_X5, + RISCV_T1 = RISCV_X6, + RISCV_T2 = RISCV_X7, + RISCV_T3 = RISCV_X28, + RISCV_T4 = RISCV_X29, + RISCV_T5 = RISCV_X30, + RISCV_T6 = RISCV_X31, + + // Call stack registers. + + RISCV_SP = RISCV_X2, // Stack pointer. + RISCV_RA = RISCV_X1, // Return address (AKA link register). + RISCV_FP = RISCV_S0, // Frame pointer (AKA base pointer). + + // ABI implementation registers. + + RISCV_GP = RISCV_X3, + RISCV_TP = RISCV_X4, +}; + +#define RISCV_N_GREGS (32) +#define RISCV_N_GAREGS (8) +#define RISCV_N_GSREGS (12) +#define RISCV_N_GTREGS (7) + +enum { + RISCV_F0 = 0, + RISCV_F1 = 1, + RISCV_F2 = 2, + RISCV_F3 = 3, + RISCV_F4 = 4, + RISCV_F5 = 5, + RISCV_F6 = 6, + RISCV_F7 = 7, + RISCV_F8 = 8, + RISCV_F9 = 9, + RISCV_F10 = 10, + RISCV_F11 = 11, + RISCV_F12 = 12, + RISCV_F13 = 13, + RISCV_F14 = 14, + RISCV_F15 = 15, + RISCV_F16 = 16, + RISCV_F17 = 17, + RISCV_F18 = 18, + RISCV_F19 = 19, + RISCV_F20 = 20, + RISCV_F21 = 21, + RISCV_F22 = 22, + RISCV_F23 = 23, + RISCV_F24 = 24, + RISCV_F25 = 25, + RISCV_F26 = 26, + RISCV_F27 = 27, + RISCV_F28 = 28, + RISCV_F29 = 29, + RISCV_F30 = 30, + RISCV_F31 = 31, + + // Argument and return registers. + + RISCV_FA0 = RISCV_F10, + RISCV_FA1 = RISCV_F11, + RISCV_FA2 = RISCV_F12, + RISCV_FA3 = RISCV_F13, + RISCV_FA4 = RISCV_F14, + RISCV_FA5 = RISCV_F15, + RISCV_FA6 = RISCV_F16, + RISCV_FA7 = RISCV_F17, + + // Callee-saved registers. + + RISCV_FS0 = RISCV_F8, + RISCV_FS1 = RISCV_F9, + RISCV_FS2 = RISCV_F18, + RISCV_FS3 = RISCV_F19, + RISCV_FS4 = RISCV_F20, + RISCV_FS5 = RISCV_F21, + RISCV_FS6 = RISCV_F22, + RISCV_FS7 = RISCV_F23, + RISCV_FS8 = RISCV_F24, + RISCV_FS9 = RISCV_F25, + RISCV_FS10 = RISCV_F26, + RISCV_FS11 = RISCV_F27, + + // Temporary registers. + + RISCV_FT0 = RISCV_F0, + RISCV_FT1 = RISCV_F1, + RISCV_FT2 = RISCV_F2, + RISCV_FT3 = RISCV_F3, + RISCV_FT4 = RISCV_F4, + RISCV_FT5 = RISCV_F5, + RISCV_FT6 = RISCV_F6, + RISCV_FT7 = RISCV_F7, + RISCV_FT8 = RISCV_F28, + RISCV_FT9 = RISCV_F29, + RISCV_FT10 = RISCV_F30, + RISCV_FT11 = RISCV_F31, +}; + +#define RISCV_N_FREGS (32) +#define RISCV_N_FAREGS (8) +#define RISCV_N_FSREGS (12) +#define RISCV_N_FTREGS (12) + +enum { + // Floating point. + + RISCV_CSR_FFLAGS = 0x001, // Accrued exceptions. + RISCV_CSR_FRM = 0x002, // Rounding mode. + RISCV_CSR_FCSR = 0x003, // Combination of FFLAGS and FRM. + + // Counters and timers. + + RISCV_CSR_CYCLE = 0xc00, // Cycle counter. + RISCV_CSR_TIME = 0xc01, // Wall clock time. + RISCV_CSR_INSTRET = 0xc02, // Instruction counter. + +#ifdef TARGET_RISCV32 + RISCV_CSR_CYCLEH = 0xc80, // Upper 32 bits of CYCLE. + RISCV_CSR_TIMEH = 0xc81, // Upper 32 bits of TIME. + RISCV_CSR_INSTRETH = 0xc82, // Upper 32 bits of INSTRET. +#endif +}; + +enum { + RISCV_FENCE_NONE = 0b0000, + + RISCV_FENCE_W = 0b0001, // Memory writes. + RISCV_FENCE_R = 0b0010, // Memory reads. + RISCV_FENCE_O = 0b0100, // Device outputs. + RISCV_FENCE_I = 0b1000, // Device inputs. + + RISCV_FENCE_MEM = RISCV_FENCE_W | RISCV_FENCE_R, + RISCV_FENCE_DEV = RISCV_FENCE_O | RISCV_FENCE_I, + RISCV_FENCE_ALL = RISCV_FENCE_DEV | RISCV_FENCE_MEM, +}; + +enum { + RISCV_ORDER_NONE = 0b00, + + RISCV_ORDER_RL = 0b01, // Release semantics. + RISCV_ORDER_AQ = 0b10, // Acquire semantics. + + RISCV_ORDER_ALL = RISCV_ORDER_RL | RISCV_ORDER_AQ, +}; + +enum { + RISCV_ROUND_NE = 0b000, // Round to nearest (ties to even). + RISCV_ROUND_TZ = 0b001, // Round towards zero. + RISCV_ROUND_DN = 0b010, // Round down (towards negative infinity). + RISCV_ROUND_UP = 0b011, // Round up (towards positive infinity). + RISCV_ROUND_MM = 0b100, // Round to nearest (ties to max magnitude). + RISCV_ROUND_DY = 0b111, // Use current rounding mode in the FRM CSR. +}; + +#define _riscv_emit(p, insn) \ + do { \ + *(guint32 *) (p) = (insn); \ + (p) += sizeof (guint32); \ + } while (0) + +#define RISCV_BITS(value, start, count) (((value) >> (start)) & ((1 << (count)) - 1)) +#define RISCV_SIGN(value) (-(((value) >> (sizeof (guint32) * 8 - 1)) & 1)) + +// Encode an imemdiate for use in an instruction. + +#define RISCV_ENCODE_I_IMM(imm) \ + (RISCV_BITS ((imm), 0, 12) << 20) +#define RISCV_ENCODE_S_IMM(imm) \ + ((RISCV_BITS ((imm), 0, 5) << 7) | (RISCV_BITS ((imm), 5, 7) << 25)) +#define RISCV_ENCODE_B_IMM(imm) \ + ((RISCV_BITS ((imm), 11, 1) << 7) | (RISCV_BITS ((imm), 1, 4) << 8) | \ + (RISCV_BITS ((imm), 5, 6) << 25) | (RISCV_BITS ((imm), 12, 1) << 31)) +#define RISCV_ENCODE_U_IMM(imm) \ + (RISCV_BITS ((imm), 0, 20) << 12) +#define RISCV_ENCODE_J_IMM(imm) \ + ((RISCV_BITS ((imm), 1, 10) << 21) | (RISCV_BITS ((imm), 11, 1) << 20) | \ + (RISCV_BITS ((imm), 12, 8) << 12) | (RISCV_BITS ((imm), 20, 1) << 31)) + +// Decode an immediate from an instruction. + +#define RISCV_DECODE_I_IMM(ins) \ + ((RISCV_BITS ((ins), 20, 12) << 0) | (RISCV_SIGN ((ins)) << 12)) +#define RISCV_DECODE_S_IMM(ins) \ + ((RISCV_BITS ((ins), 7, 5) << 0) | (RISCV_BITS ((ins), 25, 7) << 5) | \ + (RISCV_SIGN ((ins)) << 12)) +#define RISCV_DECODE_B_IMM(ins) \ + ((RISCV_BITS ((ins), 8, 4) << 1) | (RISCV_BITS ((ins), 25, 6) << 5) | \ + (RISCV_BITS ((ins), 7, 1) << 11) | (RISCV_SIGN((ins)) << 12)) +#define RISCV_DECODE_U_IMM(ins) \ + (RISCV_BITS ((ins), 12, 20) << 0) +#define RISCV_DECODE_J_IMM(ins) \ + ((RISCV_BITS ((ins), 21, 10) << 1) | (RISCV_BITS ((ins), 20, 1) << 11) | \ + (RISCV_BITS ((ins), 12, 8) << 12) | (RISCV_SIGN ((ins)) << 20)) + +// Check a value for validity as an immediate. + +#define RISCV_VALID_I_IMM(value) \ + (RISCV_DECODE_I_IMM (RISCV_ENCODE_I_IMM ((value))) == (value)) +#define RISCV_VALID_S_IMM(value) \ + (RISCV_DECODE_S_IMM (RISCV_ENCODE_S_IMM ((value))) == (value)) +#define RISCV_VALID_B_IMM(value) \ + (RISCV_DECODE_B_IMM (RISCV_ENCODE_B_IMM ((value))) == (value)) +#define RISCV_VALID_U_IMM(value) \ + (RISCV_DECODE_U_IMM (RISCV_ENCODE_U_IMM ((value))) == (value)) +#define RISCV_VALID_J_IMM(value) \ + (RISCV_DECODE_J_IMM (RISCV_ENCODE_J_IMM ((value))) == (value)) + +// Check various values for validity in an instruction. + +#define RISCV_VALID_REG(value) \ + (RISCV_BITS ((value), 0, 5) == (value)) +#define RISCV_VALID_CSR(value) \ + (RISCV_BITS ((value), 0, 12) == (value)) +#define RISCV_VALID_IS_AMOUNT(value) \ + (RISCV_BITS ((value), 0, 5) == (value)) +#define RISCV_VALID_LS_AMOUNT(value) \ + (RISCV_BITS ((value), 0, 6) == (value)) +#define RISCV_VALID_FENCE(value) \ + (RISCV_BITS ((value), 0, 4) == (value)) +#define RISCV_VALID_ORDERING(value) \ + (RISCV_BITS ((value), 0, 2) == (value)) + +/* + * The R-type encoding is used for a variety of instructions that operate on + * registers only, such as most integer instructions, atomic instructions, and + * some floating point instructions. + * + * [0....6] opcode + * [7...11] rd + * [12..14] funct3 + * [15..19] rs1 + * [20..24] rs2 + * [25..31] funct7 + */ + +#define _riscv_r_op(p, opcode, funct3, funct7, rd, rs1, rs2) \ + do { \ + g_assert (RISCV_VALID_REG ((rd))); \ + g_assert (RISCV_VALID_REG ((rs1))); \ + g_assert (RISCV_VALID_REG ((rs2))); \ + _riscv_emit ((p), ((opcode) << 0) | \ + ((rd) << 7) | \ + ((funct3) << 12) | \ + ((rs1) << 15) | \ + ((rs2) << 20) | \ + ((funct7) << 25)); \ + } while (0) + +/* + * The R4-type encoding is used for floating point fused multiply-add + * instructions. + * + * [0....6] opcode + * [7...11] rd + * [12..14] funct3 + * [15..19] rs1 + * [20..24] rs2 + * [25..26] funct2 + * [27..31] rs3 + */ + +#define _riscv_r4_op(p, opcode, funct3, funct2, rd, rs1, rs2, rs3) \ + do { \ + g_assert (RISCV_VALID_REG ((rd))); \ + g_assert (RISCV_VALID_REG ((rs1))); \ + g_assert (RISCV_VALID_REG ((rs2))); \ + g_assert (RISCV_VALID_REG ((rs3))); \ + _riscv_emit ((p), ((opcode) << 0) | \ + ((rd) << 7) | \ + ((funct3) << 12) | \ + ((rs1) << 15) | \ + ((rs2) << 20) | \ + ((funct2) << 25) | \ + ((rs3) << 27)); \ + } while (0) + +/* + * The I-type encoding is used for a variety of instructions, such as JALR, + * loads, and most integer instructions that operate on immediates. + * + * [0....6] opcode + * [7...11] rd + * [12..14] funct3 + * [15..19] rs1 + * [20..31] imm[0..11] + */ + +#define _riscv_i_op(p, opcode, funct3, rd, rs1, imm) \ + do { \ + g_assert (RISCV_VALID_REG ((rd))); \ + g_assert (RISCV_VALID_REG ((rs1))); \ + g_assert (RISCV_VALID_I_IMM ((gint32) (gssize) (imm))); \ + _riscv_emit ((p), ((opcode) << 0) | \ + ((rd) << 7) | \ + ((funct3) << 12) | \ + ((rs1) << 15) | \ + (RISCV_ENCODE_I_IMM ((gint32) (gssize) (imm)))); \ + } while (0) + +/* + * This is a specialization of the I-type encoding used for shifts by immediate + * values. The shift amount and right shift type are encoded into separate + * parts of the imm field. + * + * [0....6] opcode + * [7...11] rd + * [12..14] funct3 + * [15..19] rs1 + * [20..24] shamt + * [25..31] rstype + */ + +#define _riscv_is_op(p, opcode, funct3, rstype, rd, rs1, shamt) \ + do { \ + g_assert (RISCV_VALID_REG ((rd))); \ + g_assert (RISCV_VALID_REG ((rs1))); \ + g_assert (RISCV_VALID_IS_AMOUNT ((shamt))); \ + _riscv_emit ((p), ((opcode) << 0) | \ + ((rd) << 7) | \ + ((funct3) << 12) | \ + ((rs1) << 15) | \ + (RISCV_BITS ((shamt), 0, 5) << 20) | \ + ((rstype) << 25)); \ + } while (0) + +/* + * A further specialization of the I-type encoding used for shifts by immediate + * values in RV64I. The shift amount field is larger. + * + * [0....6] opcode + * [7...11] rd + * [12..14] funct3 + * [15..19] rs1 + * [20..25] shamt + * [26..31] rstype + */ + +#define _riscv_ls_op(p, opcode, funct3, rstype, rd, rs1, shamt) \ + do { \ + g_assert (RISCV_VALID_REG ((rd))); \ + g_assert (RISCV_VALID_REG ((rs1))); \ + g_assert (RISCV_VALID_LS_AMOUNT ((shamt))); \ + _riscv_emit ((p), ((opcode) << 0) | \ + ((rd) << 7) | \ + ((funct3) << 12) | \ + ((rs1) << 15) | \ + (RISCV_BITS ((shamt), 0, 6) << 20) | \ + ((rstype) << 26)); \ + } while (0) + +/* + * This is a specialization of the I-type encoding used for accessing control + * and status registers. + * + * [0....6] opcode + * [7...11] rd + * [12..14] funct3 + * [15..19] rs1/zimm + * [20..31] csr + */ + +#define _riscv_ic_op(p, opcode, funct3, rd, csr, rs1) \ + do { \ + g_assert (RISCV_VALID_REG ((rd))); \ + g_assert (RISCV_VALID_REG ((rs1))); \ + g_assert (RISCV_VALID_CSR ((csr))); \ + _riscv_emit ((p), ((opcode) << 0) | \ + ((rd) << 7) | \ + ((funct3) << 12) | \ + ((rs1) << 15) | \ + (RISCV_BITS ((csr), 0, 12) << 20)); \ + } while (0) + +/* + * The S-type encoding is used for stores with signed offsets. + * + * [0....6] opcode + * [7...11] imm[0..4] + * [12..14] funct3 + * [15..19] rs1 + * [20..24] rs2 + * [25..31] imm[5..11] + */ + +#define _riscv_s_op(p, opcode, funct3, rs2, rs1, imm) \ + do { \ + g_assert (RISCV_VALID_REG ((rs1))); \ + g_assert (RISCV_VALID_REG ((rs2))); \ + g_assert (RISCV_VALID_S_IMM ((gint32) (gssize) (imm))); \ + _riscv_emit ((p), ((opcode) << 0) | \ + ((funct3) << 12) | \ + ((rs1) << 15) | \ + ((rs2) << 20) | \ + (RISCV_ENCODE_S_IMM ((gint32) (gssize) (imm)))); \ + } while (0) + +/* + * The B-type encoding is used for conditional branches with signed offsets. + * + * [0....6] opcode + * [7....7] imm[11] + * [8...11] imm[1..4] + * [12..14] funct3 + * [15..19] rs1 + * [20..24] rs2 + * [25..30] imm[5..10] + * [31..31] imm[12] + */ + +#define _riscv_b_op(p, opcode, funct3, rs1, rs2, imm) \ + do { \ + g_assert (RISCV_VALID_REG ((rs1))); \ + g_assert (RISCV_VALID_REG ((rs2))); \ + g_assert (RISCV_VALID_B_IMM ((gint32) (gssize) (imm))); \ + _riscv_emit ((p), ((opcode) << 0) | \ + ((funct3) << 12) | \ + ((rs1) << 15) | \ + ((rs2) << 20) | \ + (RISCV_ENCODE_B_IMM ((gint32) (gssize) (imm)))); \ + } while (0) + +/* + * The U-type encoding is used for LUI and AUIPC only, i.e. for instructions + * that create 32-bit values from 20-bit immediates. + * + * [0....6] opcode + * [7...11] rd + * [12..31] imm[12..31] + */ + +#define _riscv_u_op(p, opcode, rd, imm) \ + do { \ + g_assert (RISCV_VALID_REG ((rd))); \ + g_assert (RISCV_VALID_U_IMM ((guint32) (gsize) (imm))); \ + _riscv_emit ((p), ((opcode) << 0) | \ + ((rd) << 7) | \ + (RISCV_ENCODE_U_IMM ((guint32) (gsize) (imm)))); \ + } while (0) + +/* + * The J-type encoding is used exclusively for JAL. + * + * [0....6] opcode + * [7...11] rd + * [12..19] imm[12..19] + * [20..20] imm[11] + * [21..30] imm[1..10] + * [31..31] imm[20] + */ + +#define _riscv_j_op(p, opcode, rd, imm) \ + do { \ + g_assert (RISCV_VALID_REG ((rd))); \ + g_assert (RISCV_VALID_J_IMM ((gint32) (gssize) (imm))); \ + _riscv_emit ((p), ((opcode) << 0) | \ + ((rd) << 7) | \ + (RISCV_ENCODE_J_IMM ((gint32) (gssize) (imm)))); \ + } while (0) + +/* + * Fence instructions have a peculiar encoding that isn't quite like any of the + * other formal encoding categories. + * + * [0....6] opcode + * [7...11] rd + * [12..14] funct3 + * [15..19] rs1 + * [20..23] succ + * [24..27] pred + * [28..31] imm[0..3] + */ + +#define _riscv_f_op(p, opcode, funct3, rd, rs1, pred, succ, imm) \ + do { \ + g_assert (RISCV_VALID_REG ((rd))); \ + g_assert (RISCV_VALID_REG ((rs1))); \ + g_assert (RISCV_VALID_FENCE ((pred))); \ + g_assert (RISCV_VALID_FENCE ((succ))); \ + _riscv_emit ((p), ((opcode) << 0) | \ + ((rd) << 7) | \ + ((funct3) << 12) | \ + ((rs1) << 15) | \ + (RISCV_BITS ((succ), 0, 4) << 20) | \ + (RISCV_BITS ((pred), 0, 4) << 24) | \ + (RISCV_BITS ((guint32) (gsize) (imm), 0, 4) << 28)); \ + } while (0) + +/* + * Atomic instructions have a peculiar encoding that isn't quite like any of + * the other formal encoding categories. + * + * [0....6] opcode + * [7...11] rd + * [12..14] funct3 + * [15..19] rs1 + * [20..24] rs2 + * [25..26] ordering + * [27..31] funct5 + */ + +#define _riscv_a_op(p, opcode, funct3, funct5, ordering, rd, rs2, rs1) \ + do { \ + g_assert (RISCV_VALID_REG ((rd))); \ + g_assert (RISCV_VALID_REG ((rs1))); \ + g_assert (RISCV_VALID_REG ((rs2))); \ + g_assert (RISCV_VALID_ORDERING ((ordering))); \ + _riscv_emit ((p), ((opcode) << 0) | \ + ((rd) << 7) | \ + ((funct3) << 12) | \ + ((rs1) << 15) | \ + ((rs2) << 20) | \ + (RISCV_BITS ((ordering), 0, 2) << 25) | \ + ((funct5) << 27)); \ + } while (0) + +/* + * NOTE: When you add new codegen macros or change existing ones, you must + * expand riscv-codegen-test.c to cover them, and update riscv-codegen.exp32 + * and riscv-codegen.exp64 as needed. + */ + +// RV32I + +#define riscv_lui(p, rd, imm) _riscv_u_op ((p), 0b0110111, (rd), (imm)) +#define riscv_auipc(p, rd, imm) _riscv_u_op ((p), 0b0010111, (rd), (imm)) +#define riscv_jal(p, rd, imm) _riscv_j_op ((p), 0b1101111, (rd), (imm)) +#define riscv_jalr(p, rd, rs1, imm) _riscv_i_op ((p), 0b1100111, 0b000, (rd), (rs1), (imm)) +#define riscv_beq(p, rs1, rs2, imm) _riscv_b_op ((p), 0b1100011, 0b000, (rs1), (rs2), (imm)) +#define riscv_bne(p, rs1, rs2, imm) _riscv_b_op ((p), 0b1100011, 0b001, (rs1), (rs2), (imm)) +#define riscv_blt(p, rs1, rs2, imm) _riscv_b_op ((p), 0b1100011, 0b100, (rs1), (rs2), (imm)) +#define riscv_bge(p, rs1, rs2, imm) _riscv_b_op ((p), 0b1100011, 0b101, (rs1), (rs2), (imm)) +#define riscv_bltu(p, rs1, rs2, imm) _riscv_b_op ((p), 0b1100011, 0b110, (rs1), (rs2), (imm)) +#define riscv_bgeu(p, rs1, rs2, imm) _riscv_b_op ((p), 0b1100011, 0b111, (rs1), (rs2), (imm)) +#define riscv_lb(p, rd, rs1, imm) _riscv_i_op ((p), 0b0000011, 0b000, (rd), (rs1), (imm)) +#define riscv_lh(p, rd, rs1, imm) _riscv_i_op ((p), 0b0000011, 0b001, (rd), (rs1), (imm)) +#define riscv_lw(p, rd, rs1, imm) _riscv_i_op ((p), 0b0000011, 0b010, (rd), (rs1), (imm)) +#define riscv_lbu(p, rd, rs1, imm) _riscv_i_op ((p), 0b0000011, 0b100, (rd), (rs1), (imm)) +#define riscv_lhu(p, rd, rs1, imm) _riscv_i_op ((p), 0b0000011, 0b101, (rd), (rs1), (imm)) +#define riscv_sb(p, rs2, rs1, imm) _riscv_s_op ((p), 0b0100011, 0b000, (rs2), (rs1), (imm)) +#define riscv_sh(p, rs2, rs1, imm) _riscv_s_op ((p), 0b0100011, 0b001, (rs2), (rs1), (imm)) +#define riscv_sw(p, rs2, rs1, imm) _riscv_s_op ((p), 0b0100011, 0b010, (rs2), (rs1), (imm)) +#define riscv_addi(p, rd, rs1, imm) _riscv_i_op ((p), 0b0010011, 0b000, (rd), (rs1), (imm)) +#define riscv_slti(p, rd, rs1, imm) _riscv_i_op ((p), 0b0010011, 0b010, (rd), (rs1), (imm)) +#define riscv_sltiu(p, rd, rs1, imm) _riscv_i_op ((p), 0b0010011, 0b011, (rd), (rs1), (imm)) +#define riscv_xori(p, rd, rs1, imm) _riscv_i_op ((p), 0b0010011, 0b100, (rd), (rs1), (imm)) +#define riscv_ori(p, rd, rs1, imm) _riscv_i_op ((p), 0b0010011, 0b110, (rd), (rs1), (imm)) +#define riscv_andi(p, rd, rs1, imm) _riscv_i_op ((p), 0b0010011, 0b111, (rd), (rs1), (imm)) +#ifdef TARGET_RISCV32 +#define riscv_slli(p, rd, rs1, shamt) _riscv_is_op ((p), 0b0010011, 0b001, 0b0000000, (rd), (rs1), (shamt)) +#define riscv_srli(p, rd, rs1, shamt) _riscv_is_op ((p), 0b0010011, 0b101, 0b0000000, (rd), (rs1), (shamt)) +#define riscv_srai(p, rd, rs1, shamt) _riscv_is_op ((p), 0b0010011, 0b101, 0b0100000, (rd), (rs1), (shamt)) +#endif +#define riscv_add(p, rd, rs1, rs2) _riscv_r_op ((p), 0b0110011, 0b000, 0b0000000, (rd), (rs1), (rs2)) +#define riscv_sub(p, rd, rs1, rs2) _riscv_r_op ((p), 0b0110011, 0b000, 0b0100000, (rd), (rs1), (rs2)) +#define riscv_sll(p, rd, rs1, rs2) _riscv_r_op ((p), 0b0110011, 0b001, 0b0000000, (rd), (rs1), (rs2)) +#define riscv_slt(p, rd, rs1, rs2) _riscv_r_op ((p), 0b0110011, 0b010, 0b0000000, (rd), (rs1), (rs2)) +#define riscv_sltu(p, rd, rs1, rs2) _riscv_r_op ((p), 0b0110011, 0b011, 0b0000000, (rd), (rs1), (rs2)) +#define riscv_xor(p, rd, rs1, rs2) _riscv_r_op ((p), 0b0110011, 0b100, 0b0000000, (rd), (rs1), (rs2)) +#define riscv_srl(p, rd, rs1, rs2) _riscv_r_op ((p), 0b0110011, 0b101, 0b0000000, (rd), (rs1), (rs2)) +#define riscv_sra(p, rd, rs1, rs2) _riscv_r_op ((p), 0b0110011, 0b101, 0b0100000, (rd), (rs1), (rs2)) +#define riscv_or(p, rd, rs1, rs2) _riscv_r_op ((p), 0b0110011, 0b110, 0b0000000, (rd), (rs1), (rs2)) +#define riscv_and(p, rd, rs1, rs2) _riscv_r_op ((p), 0b0110011, 0b111, 0b0000000, (rd), (rs1), (rs2)) +#define riscv_fence(p, pred, succ) _riscv_f_op ((p), 0b0001111, 0b000, 0b00000, 0b00000, (pred), (succ), 0b0000) +#define riscv_fence_i(p) _riscv_f_op ((p), 0b0001111, 0b001, 0b00000, 0b00000, 0b0000, 0b0000, 0b0000) +#define riscv_ecall(p) _riscv_i_op ((p), 0b1110011, 0b000, 0b00000, 0b00000, 0b000000000000) +#define riscv_ebreak(p) _riscv_i_op ((p), 0b1110011, 0b000, 0b00000, 0b00000, 0b000000000001) +#define riscv_csrrw(p, rd, csr, rs1) _riscv_ic_op ((p), 0b1110011, 0b001, (rd), (csr), (rs1)) +#define riscv_csrrs(p, rd, csr, rs1) _riscv_ic_op ((p), 0b1110011, 0b010, (rd), (csr), (rs1)) +#define riscv_csrrc(p, rd, csr, rs1) _riscv_ic_op ((p), 0b1110011, 0b011, (rd), (csr), (rs1)) +#define riscv_csrrwi(p, rd, csr, imm) _riscv_ic_op ((p), 0b1110011, 0b101, (rd), (csr), (imm)) +#define riscv_csrrsi(p, rd, csr, imm) _riscv_ic_op ((p), 0b1110011, 0b110, (rd), (csr), (imm)) +#define riscv_csrrci(p, rd, csr, imm) _riscv_ic_op ((p), 0b1110011, 0b111, (rd), (csr), (imm)) + +// RV64I + +#ifdef TARGET_RISCV64 +#define riscv_lwu(p, rd, rs1, imm) _riscv_i_op ((p), 0b0000011, 0b110, (rd), (rs1), (imm)) +#define riscv_ld(p, rd, rs1, imm) _riscv_i_op ((p), 0b0000011, 0b011, (rd), (rs1), (imm)) +#define riscv_sd(p, rs2, rs1, imm) _riscv_s_op ((p), 0b0100011, 0b011, (rs2), (rs1), (imm)) +#define riscv_slli(p, rd, rs1, shamt) _riscv_ls_op ((p), 0b0010011, 0b001, 0b000000, (rd), (rs1), (shamt)) +#define riscv_srli(p, rd, rs1, shamt) _riscv_ls_op ((p), 0b0010011, 0b101, 0b000000, (rd), (rs1), (shamt)) +#define riscv_srai(p, rd, rs1, shamt) _riscv_ls_op ((p), 0b0010011, 0b101, 0b010000, (rd), (rs1), (shamt)) +#define riscv_addiw(p, rd, rs1, imm) _riscv_i_op ((p), 0b0011011, 0b000, (rd), (rs1), (imm)) +#define riscv_slliw(p, rd, rs1, shamt) _riscv_is_op ((p), 0b0011011, 0b001, 0b0000000, (rd), (rs1), (shamt)) +#define riscv_srliw(p, rd, rs1, shamt) _riscv_is_op ((p), 0b0011011, 0b101, 0b0000000, (rd), (rs1), (shamt)) +#define riscv_sraiw(p, rd, rs1, shamt) _riscv_is_op ((p), 0b0011011, 0b101, 0b0100000, (rd), (rs1), (shamt)) +#define riscv_addw(p, rd, rs1, rs2) _riscv_r_op ((p), 0b0111011, 0b000, 0b0000000, (rd), (rs1), (rs2)) +#define riscv_subw(p, rd, rs1, rs2) _riscv_r_op ((p), 0b0111011, 0b000, 0b0100000, (rd), (rs1), (rs2)) +#define riscv_sllw(p, rd, rs1, rs2) _riscv_r_op ((p), 0b0111011, 0b001, 0b0000000, (rd), (rs1), (rs2)) +#define riscv_srlw(p, rd, rs1, rs2) _riscv_r_op ((p), 0b0111011, 0b101, 0b0000000, (rd), (rs1), (rs2)) +#define riscv_sraw(p, rd, rs1, rs2) _riscv_r_op ((p), 0b0111011, 0b101, 0b0100000, (rd), (rs1), (rs2)) +#endif + +// RV32M + +#define riscv_mul(p, rd, rs1, rs2) _riscv_r_op ((p), 0b0110011, 0b000, 0b0000001, (rd), (rs1), (rs2)) +#define riscv_mulh(p, rd, rs1, rs2) _riscv_r_op ((p), 0b0110011, 0b001, 0b0000001, (rd), (rs1), (rs2)) +#define riscv_mulhsu(p, rd, rs1, rs2) _riscv_r_op ((p), 0b0110011, 0b010, 0b0000001, (rd), (rs1), (rs2)) +#define riscv_mulhu(p, rd, rs1, rs2) _riscv_r_op ((p), 0b0110011, 0b011, 0b0000001, (rd), (rs1), (rs2)) +#define riscv_div(p, rd, rs1, rs2) _riscv_r_op ((p), 0b0110011, 0b100, 0b0000001, (rd), (rs1), (rs2)) +#define riscv_divu(p, rd, rs1, rs2) _riscv_r_op ((p), 0b0110011, 0b101, 0b0000001, (rd), (rs1), (rs2)) +#define riscv_rem(p, rd, rs1, rs2) _riscv_r_op ((p), 0b0110011, 0b110, 0b0000001, (rd), (rs1), (rs2)) +#define riscv_remu(p, rd, rs1, rs2) _riscv_r_op ((p), 0b0110011, 0b111, 0b0000001, (rd), (rs1), (rs2)) + +// RV64M + +#ifdef TARGET_RISCV64 +#define riscv_mulw(p, rd, rs1, rs2) _riscv_r_op ((p), 0b0111011, 0b000, 0b0000001, (rd), (rs1), (rs2)) +#define riscv_divw(p, rd, rs1, rs2) _riscv_r_op ((p), 0b0111011, 0b100, 0b0000001, (rd), (rs1), (rs2)) +#define riscv_divuw(p, rd, rs1, rs2) _riscv_r_op ((p), 0b0111011, 0b101, 0b0000001, (rd), (rs1), (rs2)) +#define riscv_remw(p, rd, rs1, rs2) _riscv_r_op ((p), 0b0111011, 0b110, 0b0000001, (rd), (rs1), (rs2)) +#define riscv_remuw(p, rd, rs1, rs2) _riscv_r_op ((p), 0b0111011, 0b111, 0b0000001, (rd), (rs1), (rs2)) +#endif + +// RV32A + +#define riscv_lr_w(p, ordering, rd, rs1) _riscv_a_op ((p), 0b0101111, 0b010, 0b00010, (ordering), (rd), 0b00000, (rs1)) +#define riscv_sc_w(p, ordering, rd, rs2, rs1) _riscv_a_op ((p), 0b0101111, 0b010, 0b00011, (ordering), (rd), (rs2), (rs1)) +#define riscv_amoswap_w(p, ordering, rd, rs2, rs1) _riscv_a_op ((p), 0b0101111, 0b010, 0b00001, (ordering), (rd), (rs2), (rs1)) +#define riscv_amoadd_w(p, ordering, rd, rs2, rs1) _riscv_a_op ((p), 0b0101111, 0b010, 0b00000, (ordering), (rd), (rs2), (rs1)) +#define riscv_amoxor_w(p, ordering, rd, rs2, rs1) _riscv_a_op ((p), 0b0101111, 0b010, 0b00100, (ordering), (rd), (rs2), (rs1)) +#define riscv_amoand_w(p, ordering, rd, rs2, rs1) _riscv_a_op ((p), 0b0101111, 0b010, 0b01100, (ordering), (rd), (rs2), (rs1)) +#define riscv_amoor_w(p, ordering, rd, rs2, rs1) _riscv_a_op ((p), 0b0101111, 0b010, 0b01000, (ordering), (rd), (rs2), (rs1)) +#define riscv_amomin_w(p, ordering, rd, rs2, rs1) _riscv_a_op ((p), 0b0101111, 0b010, 0b10000, (ordering), (rd), (rs2), (rs1)) +#define riscv_amomax_w(p, ordering, rd, rs2, rs1) _riscv_a_op ((p), 0b0101111, 0b010, 0b10100, (ordering), (rd), (rs2), (rs1)) +#define riscv_amominu_w(p, ordering, rd, rs2, rs1) _riscv_a_op ((p), 0b0101111, 0b010, 0b11000, (ordering), (rd), (rs2), (rs1)) +#define riscv_amomaxu_w(p, ordering, rd, rs2, rs1) _riscv_a_op ((p), 0b0101111, 0b010, 0b11100, (ordering), (rd), (rs2), (rs1)) + +// RV64A + +#ifdef TARGET_RISCV64 +#define riscv_lr_d(p, ordering, rd, rs1) _riscv_a_op ((p), 0b0101111, 0b011, 0b00010, (ordering), (rd), 0b00000, (rs1)) +#define riscv_sc_d(p, ordering, rd, rs2, rs1) _riscv_a_op ((p), 0b0101111, 0b011, 0b00011, (ordering), (rd), (rs2), (rs1)) +#define riscv_amoswap_d(p, ordering, rd, rs2, rs1) _riscv_a_op ((p), 0b0101111, 0b011, 0b00001, (ordering), (rd), (rs2), (rs1)) +#define riscv_amoadd_d(p, ordering, rd, rs2, rs1) _riscv_a_op ((p), 0b0101111, 0b011, 0b00000, (ordering), (rd), (rs2), (rs1)) +#define riscv_amoxor_d(p, ordering, rd, rs2, rs1) _riscv_a_op ((p), 0b0101111, 0b011, 0b00100, (ordering), (rd), (rs2), (rs1)) +#define riscv_amoand_d(p, ordering, rd, rs2, rs1) _riscv_a_op ((p), 0b0101111, 0b011, 0b01100, (ordering), (rd), (rs2), (rs1)) +#define riscv_amoor_d(p, ordering, rd, rs2, rs1) _riscv_a_op ((p), 0b0101111, 0b011, 0b01000, (ordering), (rd), (rs2), (rs1)) +#define riscv_amomin_d(p, ordering, rd, rs2, rs1) _riscv_a_op ((p), 0b0101111, 0b011, 0b10000, (ordering), (rd), (rs2), (rs1)) +#define riscv_amomax_d(p, ordering, rd, rs2, rs1) _riscv_a_op ((p), 0b0101111, 0b011, 0b10100, (ordering), (rd), (rs2), (rs1)) +#define riscv_amominu_d(p, ordering, rd, rs2, rs1) _riscv_a_op ((p), 0b0101111, 0b011, 0b11000, (ordering), (rd), (rs2), (rs1)) +#define riscv_amomaxu_d(p, ordering, rd, rs2, rs1) _riscv_a_op ((p), 0b0101111, 0b011, 0b11100, (ordering), (rd), (rs2), (rs1)) +#endif + +// RV32F + +#define riscv_flw(p, rd, rs1, imm) _riscv_i_op ((p), 0b0000111, 0b010, (rd), (rs1), (imm)) +#define riscv_fsw(p, rs2, rs1, imm) _riscv_s_op ((p), 0b0100111, 0b010, (rs2), (rs1), (imm)) +#define riscv_fmadd_s(p, rm, rd, rs1, rs2, rs3) _riscv_r4_op ((p), 0b1000011, (rm), 0b00, (rd), (rs1), (rs2), (rs3)) +#define riscv_fmsub_s(p, rm, rd, rs1, rs2, rs3) _riscv_r4_op ((p), 0b1000111, (rm), 0b00, (rd), (rs1), (rs2), (rs3)) +#define riscv_fnmadd_s(p, rm, rd, rs1, rs2, rs3) _riscv_r4_op ((p), 0b1001011, (rm), 0b00, (rd), (rs1), (rs2), (rs3)) +#define riscv_fnmsub_s(p, rm, rd, rs1, rs2, rs3) _riscv_r4_op ((p), 0b1001111, (rm), 0b00, (rd), (rs1), (rs2), (rs3)) +#define riscv_fadd_s(p, rm, rd, rs1, rs2) _riscv_r_op ((p), 0b1010011, (rm), 0b0000000, (rd), (rs1), (rs2)) +#define riscv_fsub_s(p, rm, rd, rs1, rs2) _riscv_r_op ((p), 0b1010011, (rm), 0b0000100, (rd), (rs1), (rs2)) +#define riscv_fmul_s(p, rm, rd, rs1, rs2) _riscv_r_op ((p), 0b1010011, (rm), 0b0001000, (rd), (rs1), (rs2)) +#define riscv_fdiv_s(p, rm, rd, rs1, rs2) _riscv_r_op ((p), 0b1010011, (rm), 0b0001100, (rd), (rs1), (rs2)) +#define riscv_fsqrt_s(p, rm, rd, rs1) _riscv_r_op ((p), 0b1010011, (rm), 0b0101100, (rd), (rs1), 0b00000) +#define riscv_fsgnj_s(p, rd, rs1, rs2) _riscv_r_op ((p), 0b1010011, 0b000, 0b0010000, (rd), (rs1), (rs2)) +#define riscv_fsgnjn_s(p, rd, rs1, rs2) _riscv_r_op ((p), 0b1010011, 0b001, 0b0010000, (rd), (rs1), (rs2)) +#define riscv_fsgnjx_s(p, rd, rs1, rs2) _riscv_r_op ((p), 0b1010011, 0b010, 0b0010000, (rd), (rs1), (rs2)) +#define riscv_fmin_s(p, rd, rs1, rs2) _riscv_r_op ((p), 0b1010011, 0b000, 0b0010100, (rd), (rs1), (rs2)) +#define riscv_fmax_s(p, rd, rs1, rs2) _riscv_r_op ((p), 0b1010011, 0b001, 0b0010100, (rd), (rs1), (rs2)) +#define riscv_fcvt_w_s(p, rm, rd, rs1) _riscv_r_op ((p), 0b1010011, (rm), 0b1100000, (rd), (rs1), 0b00000) +#define riscv_fcvt_wu_s(p, rm, rd, rs1) _riscv_r_op ((p), 0b1010011, (rm), 0b1100000, (rd), (rs1), 0b00001) +#define riscv_fmv_x_w(p, rd, rs1) _riscv_r_op ((p), 0b1010011, 0b000, 0b1110000, (rd), (rs1), 0b00000) +#define riscv_feq_s(p, rd, rs1, rs2) _riscv_r_op ((p), 0b1010011, 0b010, 0b1010000, (rd), (rs1), (rs2)) +#define riscv_flt_s(p, rd, rs1, rs2) _riscv_r_op ((p), 0b1010011, 0b001, 0b1010000, (rd), (rs1), (rs2)) +#define riscv_fle_s(p, rd, rs1, rs2) _riscv_r_op ((p), 0b1010011, 0b000, 0b1010000, (rd), (rs1), (rs2)) +#define riscv_fclass_s(p, rd, rs1) _riscv_r_op ((p), 0b1010011, 0b001, 0b1110000, (rd), (rs1), 0b00000) +#define riscv_fcvt_s_w(p, rm, rd, rs1) _riscv_r_op ((p), 0b1010011, (rm), 0b1101000, (rd), (rs1), 0b00000) +#define riscv_fcvt_s_wu(p, rm, rd, rs1) _riscv_r_op ((p), 0b1010011, (rm), 0b1101000, (rd), (rs1), 0b00001) +#define riscv_fmv_w_x(p, rd, rs1) _riscv_r_op ((p), 0b1010011, 0b000, 0b1111000, (rd), (rs1), 0b00000) + +// RV64F + +#ifdef TARGET_RISCV64 +#define riscv_fcvt_l_s(p, rm, rd, rs1) _riscv_r_op ((p), 0b1010011, (rm), 0b1100000, (rd), (rs1), 0b00010) +#define riscv_fcvt_lu_s(p, rm, rd, rs1) _riscv_r_op ((p), 0b1010011, (rm), 0b1100000, (rd), (rs1), 0b00011) +#define riscv_fcvt_s_l(p, rm, rd, rs1) _riscv_r_op ((p), 0b1010011, (rm), 0b1101000, (rd), (rs1), 0b00010) +#define riscv_fcvt_s_lu(p, rm, rd, rs1) _riscv_r_op ((p), 0b1010011, (rm), 0b1101000, (rd), (rs1), 0b00011) +#endif + +// RV32D + +#define riscv_fld(p, rd, rs1, imm) _riscv_i_op ((p), 0b0000111, 0b011, (rd), (rs1), (imm)) +#define riscv_fsd(p, rs2, rs1, imm) _riscv_s_op ((p), 0b0100111, 0b011, (rs2), (rs1), (imm)) +#define riscv_fmadd_d(p, rm, rd, rs1, rs2, rs3) _riscv_r4_op ((p), 0b1000011, (rm), 0b01, (rd), (rs1), (rs2), (rs3)) +#define riscv_fmsub_d(p, rm, rd, rs1, rs2, rs3) _riscv_r4_op ((p), 0b1000111, (rm), 0b01, (rd), (rs1), (rs2), (rs3)) +#define riscv_fnmadd_d(p, rm, rd, rs1, rs2, rs3) _riscv_r4_op ((p), 0b1001011, (rm), 0b01, (rd), (rs1), (rs2), (rs3)) +#define riscv_fnmsub_d(p, rm, rd, rs1, rs2, rs3) _riscv_r4_op ((p), 0b1001111, (rm), 0b01, (rd), (rs1), (rs2), (rs3)) +#define riscv_fadd_d(p, rm, rd, rs1, rs2) _riscv_r_op ((p), 0b1010011, (rm), 0b0000001, (rd), (rs1), (rs2)) +#define riscv_fsub_d(p, rm, rd, rs1, rs2) _riscv_r_op ((p), 0b1010011, (rm), 0b0000101, (rd), (rs1), (rs2)) +#define riscv_fmul_d(p, rm, rd, rs1, rs2) _riscv_r_op ((p), 0b1010011, (rm), 0b0001001, (rd), (rs1), (rs2)) +#define riscv_fdiv_d(p, rm, rd, rs1, rs2) _riscv_r_op ((p), 0b1010011, (rm), 0b0001101, (rd), (rs1), (rs2)) +#define riscv_fsqrt_d(p, rm, rd, rs1) _riscv_r_op ((p), 0b1010011, (rm), 0b0101101, (rd), (rs1), 0b00000) +#define riscv_fsgnj_d(p, rd, rs1, rs2) _riscv_r_op ((p), 0b1010011, 0b000, 0b0010001, (rd), (rs1), (rs2)) +#define riscv_fsgnjn_d(p, rd, rs1, rs2) _riscv_r_op ((p), 0b1010011, 0b001, 0b0010001, (rd), (rs1), (rs2)) +#define riscv_fsgnjx_d(p, rd, rs1, rs2) _riscv_r_op ((p), 0b1010011, 0b010, 0b0010001, (rd), (rs1), (rs2)) +#define riscv_fmin_d(p, rd, rs1, rs2) _riscv_r_op ((p), 0b1010011, 0b000, 0b0010101, (rd), (rs1), (rs2)) +#define riscv_fmax_d(p, rd, rs1, rs2) _riscv_r_op ((p), 0b1010011, 0b001, 0b0010101, (rd), (rs1), (rs2)) +#define riscv_fcvt_s_d(p, rm, rd, rs1) _riscv_r_op ((p), 0b1010011, (rm), 0b0100000, (rd), (rs1), 0b00001) +#define riscv_fcvt_d_s(p, rd, rs1) _riscv_r_op ((p), 0b1010011, 0b000, 0b0100001, (rd), (rs1), 0b00000) +#define riscv_feq_d(p, rd, rs1, rs2) _riscv_r_op ((p), 0b1010011, 0b010, 0b1010001, (rd), (rs1), (rs2)) +#define riscv_flt_d(p, rd, rs1, rs2) _riscv_r_op ((p), 0b1010011, 0b001, 0b1010001, (rd), (rs1), (rs2)) +#define riscv_fle_d(p, rd, rs1, rs2) _riscv_r_op ((p), 0b1010011, 0b000, 0b1010001, (rd), (rs1), (rs2)) +#define riscv_fclass_d(p, rd, rs1) _riscv_r_op ((p), 0b1010011, 0b001, 0b1110001, (rd), (rs1), 0b00000) +#define riscv_fcvt_w_d(p, rm, rd, rs1) _riscv_r_op ((p), 0b1010011, (rm), 0b1100001, (rd), (rs1), 0b00000) +#define riscv_fcvt_wu_d(p, rm, rd, rs1) _riscv_r_op ((p), 0b1010011, (rm), 0b1100001, (rd), (rs1), 0b00001) +#define riscv_fcvt_d_w(p, rd, rs1) _riscv_r_op ((p), 0b1010011, 0b000, 0b1101001, (rd), (rs1), 0b00000) +#define riscv_fcvt_d_wu(p, rd, rs1) _riscv_r_op ((p), 0b1010011, 0b000, 0b1101001, (rd), (rs1), 0b00001) + +// RV64D + +#ifdef TARGET_RISCV64 +#define riscv_fcvt_l_d(p, rm, rd, rs1) _riscv_r_op ((p), 0b1010011, (rm), 0b1100001, (rd), (rs1), 0b00010) +#define riscv_fcvt_lu_d(p, rm, rd, rs1) _riscv_r_op ((p), 0b1010011, (rm), 0b1100001, (rd), (rs1), 0b00011) +#define riscv_fmv_x_d(p, rd, rs1) _riscv_r_op ((p), 0b1010011, 0b000, 0b1110001, (rd), (rs1), 0b00000) +#define riscv_fcvt_d_l(p, rm, rd, rs1) _riscv_r_op ((p), 0b1010011, (rm), 0b1101001, (rd), (rs1), 0b00010) +#define riscv_fcvt_d_lu(p, rm, rd, rs1) _riscv_r_op ((p), 0b1010011, (rm), 0b1101001, (rd), (rs1), 0b00011) +#define riscv_fmv_d_x(p, rd, rs1) _riscv_r_op ((p), 0b1010011, 0b000, 0b1111001, (rd), (rs1), 0b00000) +#endif + +#endif diff --git a/mono/metadata/icall.c b/mono/metadata/icall.c index 4cf792555e4..420a02d7862 100644 --- a/mono/metadata/icall.c +++ b/mono/metadata/icall.c @@ -6833,7 +6833,7 @@ mono_icall_is_64bit_os (void) struct utsname name; if (uname (&name) >= 0) { - return strcmp (name.machine, "x86_64") == 0 || strncmp (name.machine, "aarch64", 7) == 0 || strncmp (name.machine, "ppc64", 5) == 0; + return strcmp (name.machine, "x86_64") == 0 || strncmp (name.machine, "aarch64", 7) == 0 || strncmp (name.machine, "ppc64", 5) == 0 || strncmp (name.machine, "riscv64", 7) == 0; } #endif return FALSE; diff --git a/mono/metadata/metadata-cross-helpers.c b/mono/metadata/metadata-cross-helpers.c index 003c888b675..d153fc970ab 100644 --- a/mono/metadata/metadata-cross-helpers.c +++ b/mono/metadata/metadata-cross-helpers.c @@ -34,6 +34,10 @@ dump_arch (void) g_print ("#ifdef TARGET_ARM\n"); #elif defined (TARGET_ARM64) g_print ("#ifdef TARGET_ARM64\n"); +#elif defined (TARGET_RISCV32) + g_print ("#ifdef TARGET_RISCV32\n"); +#elif defined (TARGET_RISCV64) + g_print ("#ifdef TARGET_RISCV64\n"); #else return 0; #endif diff --git a/mono/metadata/mono-config.c b/mono/metadata/mono-config.c index 5c1058d5a8d..b44c84556b5 100644 --- a/mono/metadata/mono-config.c +++ b/mono/metadata/mono-config.c @@ -84,6 +84,12 @@ #elif defined(mips) || defined(__mips) || defined(_mips) #define CONFIG_CPU "mips" #define CONFIG_WORDSIZE "32" +#elif defined (TARGET_RISCV32) +#define CONFIG_CPU "riscv32" +#define CONFIG_WORDSIZE "32" +#elif defined (TARGET_RISCV64) +#define CONFIG_CPU "riscv64" +#define CONFIG_WORDSIZE "64" #elif defined(TARGET_WASM) #define CONFIG_CPU "wasm" #define CONFIG_WORDSIZE "32" diff --git a/mono/metadata/sgen-client-mono.h b/mono/metadata/sgen-client-mono.h index a26014d4488..b3773f8bb98 100644 --- a/mono/metadata/sgen-client-mono.h +++ b/mono/metadata/sgen-client-mono.h @@ -700,7 +700,7 @@ sgen_client_binary_protocol_collection_end_stats (long long major_scan, long lon * * TODO: Query the JIT instead of this ifdef hack. */ -#if defined (TARGET_X86) || defined (TARGET_AMD64) || (defined (TARGET_ARM) && defined (HAVE_ARMV7)) || defined (TARGET_ARM64) +#if defined (TARGET_X86) || defined (TARGET_AMD64) || (defined (TARGET_ARM) && defined (HAVE_ARMV7)) || defined (TARGET_ARM64) || defined (TARGET_RISCV) #define MANAGED_ALLOCATOR_CAN_USE_CRITICAL_REGION #endif #endif diff --git a/mono/mini/Makefile.am.in b/mono/mini/Makefile.am.in index 6c840f88b8d..97478cb44b7 100755 --- a/mono/mini/Makefile.am.in +++ b/mono/mini/Makefile.am.in @@ -364,6 +364,12 @@ s390x_sources = \ exceptions-s390x.c \ tramp-s390x.c +riscv_sources = \ + mini-riscv.c \ + mini-riscv.h \ + exceptions-riscv.c \ + tramp-riscv.c + darwin_sources = \ mini-darwin.c @@ -627,6 +633,20 @@ arch_define=__s390__ target_define=TARGET_S390X endif +if RISCV32 +arch_sources = $(riscv_sources) +arch_built = cpu-riscv32.h +arch_define = __riscv +target_define = TARGET_RISCV32 +endif + +if RISCV64 +arch_sources = $(riscv_sources) +arch_built = cpu-riscv64.h +arch_define = __riscv +target_define = TARGET_RISCV64 +endif + if HOST_WIN32 os_sources = $(windows_sources) monobin_platform_ldflags= @@ -774,6 +794,12 @@ cpu-s390x.h: mini-ops.h cpu-s390x.md cpu-mips.h: mini-ops.h cpu-mips.md $(GENMDESC_PRG) cpu-mips.h mips_desc $(srcdir)/cpu-mips.md +cpu-riscv32.h: cpu-riscv32.md + $(GENMDESC_PRG) cpu-riscv32.h riscv32_cpu_desc $(srcdir)/cpu-riscv32.md + +cpu-riscv64.h: cpu-riscv64.md + $(GENMDESC_PRG) cpu-riscv64.h riscv64_cpu_desc $(srcdir)/cpu-riscv64.md + testi: mono test.exe $(MINI_RUNTIME) -v -v --ncompile 1 --compile Test:$(mtest) test.exe @@ -957,6 +983,7 @@ EXTRA_DIST = TestDriver.cs \ $(mips_sources) cpu-mips.md \ $(sparc_sources) cpu-sparc.md \ $(s390x_sources) cpu-s390x.md \ + $(riscv_sources) cpu-riscv32.md cpu-riscv64.md \ $(windows_sources) \ $(darwin_sources) Info.plist \ $(posix_sources) \ diff --git a/mono/mini/aot-compiler.c b/mono/mini/aot-compiler.c index 52ec2ae2c38..70334e99220 100644 --- a/mono/mini/aot-compiler.c +++ b/mono/mini/aot-compiler.c @@ -948,7 +948,7 @@ emit_code_bytes (MonoAotCompile *acfg, const guint8* buf, int size) /* ARCHITECTURE SPECIFIC CODE */ -#if defined(TARGET_X86) || defined(TARGET_AMD64) || defined(TARGET_ARM) || defined(TARGET_POWERPC) || defined(TARGET_ARM64) +#if defined(TARGET_X86) || defined(TARGET_AMD64) || defined(TARGET_ARM) || defined(TARGET_POWERPC) || defined(TARGET_ARM64) || defined (TARGET_RISCV) #define EMIT_DWARF_INFO 1 #endif @@ -1048,6 +1048,14 @@ arch_emit_unwind_info_sections (MonoAotCompile *acfg, const char *function_start #endif #endif +#ifdef TARGET_RISCV32 +#define AOT_TARGET_STR "RISCV32" +#endif + +#ifdef TARGET_RISCV64 +#define AOT_TARGET_STR "RISCV64" +#endif + #ifdef TARGET_X86 #ifdef TARGET_WIN32 #define AOT_TARGET_STR "X86 (WIN32)" @@ -1131,6 +1139,32 @@ arch_init (MonoAotCompile *acfg) acfg->need_pt_gnu_stack = TRUE; #endif +#ifdef TARGET_RISCV + if (acfg->aot_opts.mtriple) + mono_arch_set_target (acfg->aot_opts.mtriple); + +#ifdef TARGET_RISCV64 + + g_string_append (acfg->as_args, " -march=rv64i "); +#ifdef RISCV_FPABI_DOUBLE + g_string_append (acfg->as_args, " -mabi=lp64d"); +#else + g_string_append (acfg->as_args, " -mabi=lp64"); +#endif + +#else + + g_string_append (acfg->as_args, " -march=rv32i "); +#ifdef RISCV_FPABI_DOUBLE + g_string_append (acfg->as_args, " -mabi=ilp32d "); +#else + g_string_append (acfg->as_args, " -mabi=ilp32 "); +#endif + +#endif + +#endif + #ifdef MONOTOUCH acfg->global_symbols = TRUE; #endif diff --git a/mono/mini/cpu-riscv32.md b/mono/mini/cpu-riscv32.md new file mode 100644 index 00000000000..65b602cc530 --- /dev/null +++ b/mono/mini/cpu-riscv32.md @@ -0,0 +1,30 @@ +# Licensed to the .NET Foundation under one or more agreements. +# The .NET Foundation licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. +# +# RISC-V RV32 Machine Description +# +# This file describes various properties of Mini instructions for RV32 and is +# read by genmdesc.py to generate a C header file used by various parts of the +# JIT. +# +# Lines are of the form: +# +# <name>: len:<length> [dest:<rspec>] [src1:<rspec>] [src2:<rspec>] [src3:<rspec>] [clob:<cspec>] +# +# Here, <name> is the name of the instruction as specified in mini-ops.h. +# length is the maximum number of bytes that could be needed to generate native +# code for the instruction. dest, src1, src2, and src3 specify output and input +# registers needed by the instruction. <rspec> can be one of: +# +# a a0 +# i any integer register +# b any integer register (used as a pointer) +# f any float register (a0..a1 pair in soft float) +# l a0..a1 pair +# +# clob specifies which registers are clobbered (i.e. overwritten with garbage) +# by the instruction. <cspec> can be one of: +# +# a a0 +# c all caller-saved registers diff --git a/mono/mini/cpu-riscv64.md b/mono/mini/cpu-riscv64.md new file mode 100644 index 00000000000..e8c29d3824c --- /dev/null +++ b/mono/mini/cpu-riscv64.md @@ -0,0 +1,29 @@ +# Licensed to the .NET Foundation under one or more agreements. +# The .NET Foundation licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. +# +# RISC-V RV64 Machine Description +# +# This file describes various properties of Mini instructions for RV64 and is +# read by genmdesc.py to generate a C header file used by various parts of the +# JIT. +# +# Lines are of the form: +# +# <name>: len:<length> [dest:<rspec>] [src1:<rspec>] [src2:<rspec>] [src3:<rspec>] [clob:<cspec>] +# +# Here, <name> is the name of the instruction as specified in mini-ops.h. +# length is the maximum number of bytes that could be needed to generate native +# code for the instruction. dest, src1, src2, and src3 specify output and input +# registers needed by the instruction. <rspec> can be one of: +# +# a a0 +# i any integer register +# b any integer register (used as a pointer) +# f any float register (a0 in soft float) +# +# clob specifies which registers are clobbered (i.e. overwritten with garbage) +# by the instruction. <cspec> can be one of: +# +# a a0 +# c all caller-saved registers diff --git a/mono/mini/exceptions-riscv.c b/mono/mini/exceptions-riscv.c new file mode 100644 index 00000000000..815375b340d --- /dev/null +++ b/mono/mini/exceptions-riscv.c @@ -0,0 +1,188 @@ +/* + * Licensed to the .NET Foundation under one or more agreements. + * The .NET Foundation licenses this file to you under the MIT license. + * See the LICENSE file in the project root for more information. + */ + +#include "mini-runtime.h" + +#include <mono/metadata/abi-details.h> +#include <mono/utils/mono-sigcontext.h> + +#ifndef DISABLE_JIT + + +static gpointer +nop_stub (void) +{ + guint8 *code, *start; + + start = code = mono_global_codeman_reserve (0x50); + + /* nop */ + riscv_addi (code, RISCV_X0, RISCV_X0, 0); + + mono_arch_flush_icache (start, code - start); + + return start; +} + +gpointer +mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) +{ + *info = NULL; + return nop_stub (); +} + +gpointer +mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) +{ + *info = NULL; + return nop_stub (); +} + +gpointer +mono_arch_get_throw_exception (MonoTrampInfo **info, gboolean aot) +{ + *info = NULL; + return nop_stub (); +} + +gpointer +mono_arch_get_rethrow_exception (MonoTrampInfo **info, gboolean aot) +{ + *info = NULL; + return nop_stub (); +} + +gpointer +mono_arch_get_rethrow_preserve_exception (MonoTrampInfo **info, gboolean aot) +{ + *info = NULL; + return nop_stub (); +} + +gpointer +mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot) +{ + *info = NULL; + return nop_stub (); +} + +#else + +gpointer +mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) +{ + g_assert_not_reached (); + return NULL; +} + +gpointer +mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) +{ + g_assert_not_reached (); + return NULL; +} + +gpointer +mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) +{ + g_assert_not_reached (); + return NULL; +} + +gpointer +mono_arch_get_throw_exception (MonoTrampInfo **info, gboolean aot) +{ + g_assert_not_reached (); + return NULL; +} + +gpointer +mono_arch_get_rethrow_exception (MonoTrampInfo **info, gboolean aot) +{ + g_assert_not_reached (); + return NULL; +} + +gpointer +mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot) +{ + g_assert_not_reached (); + return NULL; +} + +#endif + +void +mono_arch_exceptions_init (void) +{ + // NOT_IMPLEMENTED; +} + +gboolean +mono_arch_unwind_frame (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *ji, + MonoContext *ctx, MonoContext *new_ctx, MonoLMF **lmf, + mgreg_t **save_locations, StackFrameInfo *frame) +{ + NOT_IMPLEMENTED; + return FALSE; +} + +static void +handle_signal_exception (gpointer obj) +{ + MonoJitTlsData *jit_tls = mono_tls_get_jit_tls (); + MonoContext ctx = jit_tls->ex_ctx; + + mono_handle_exception (&ctx, obj); + mono_restore_context (&ctx); +} + +gboolean +mono_arch_handle_exception (void *ctx, gpointer obj) +{ + MonoJitTlsData *jit_tls = mono_tls_get_jit_tls (); + + mono_sigctx_to_monoctx (ctx, &jit_tls->ex_ctx); + + // Call handle_signal_exception () on the normal stack. + UCONTEXT_GREGS (ctx) [RISCV_A0] = (long) obj; + UCONTEXT_REG_PC (ctx) = (long) handle_signal_exception; + + return TRUE; +} + +gpointer +mono_arch_ip_from_context (void *sigctx) +{ + return (gpointer) UCONTEXT_REG_PC (sigctx); +} + +void +mono_arch_setup_async_callback (MonoContext *ctx, void (*async_cb)(void *fun), gpointer user_data) +{ + // Allocate a stack frame and redirect PC. + MONO_CONTEXT_SET_SP (ctx, (mgreg_t) MONO_CONTEXT_GET_SP (ctx) - 32); + + mono_arch_setup_resume_sighandler_ctx (ctx, async_cb); +} + +void +mono_arch_setup_resume_sighandler_ctx (MonoContext *ctx, gpointer func) +{ + MONO_CONTEXT_SET_IP (ctx, func); +} + +void +mono_arch_undo_ip_adjustment (MonoContext *context) +{ + NOT_IMPLEMENTED; +} + +void +mono_arch_do_ip_adjustment (MonoContext *context) +{ + g_assert_not_reached (); +} diff --git a/mono/mini/genmdesc.py b/mono/mini/genmdesc.py index 987332bdf1a..624088944bb 100755 --- a/mono/mini/genmdesc.py +++ b/mono/mini/genmdesc.py @@ -26,6 +26,9 @@ allowed_defines = { "TARGET_X86" : 1, "TARGET_SPARC" : 1, "TARGET_S390X" : 1, "TARGET_MIPS" : 1, + "TARGET_RISCV" : 1, + "TARGET_RISCV32" : 1, + "TARGET_RISCV64" : 1, "TARGET_WASM" : 1 } diff --git a/mono/mini/helpers.c b/mono/mini/helpers.c index f1644dbc4b2..a4364fe6a9d 100644 --- a/mono/mini/helpers.c +++ b/mono/mini/helpers.c @@ -239,6 +239,10 @@ mono_disassemble_code (MonoCompile *cfg, guint8 *code, int size, char *id) #define AS_CMD "as -arch ppc64" #elif defined(__powerpc64__) #define AS_CMD "as -mppc64" +#elif defined (TARGET_RISCV64) +#define AS_CMD "as -march=rv64ima" +#elif defined (TARGET_RISCV32) +#define AS_CMD "as -march=rv32ima" #else #define AS_CMD "as" #endif diff --git a/mono/mini/mini-arch.h b/mono/mini/mini-arch.h index c49ed5a41d5..da89dbb0439 100644 --- a/mono/mini/mini-arch.h +++ b/mono/mini/mini-arch.h @@ -25,6 +25,8 @@ #include "mini-arm64.h" #elif defined(__mips__) #include "mini-mips.h" +#elif defined (TARGET_RISCV) +#include "mini-riscv.h" #elif TARGET_WASM #include "mini-wasm.h" #else diff --git a/mono/mini/mini-codegen.c b/mono/mini/mini-codegen.c index 3a1cdd03901..91b756f37fc 100644 --- a/mono/mini/mini-codegen.c +++ b/mono/mini/mini-codegen.c @@ -1148,7 +1148,7 @@ mono_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb) desc_to_fixed_reg_inited = TRUE; /* Validate the cpu description against the info in mini-ops.h */ -#if defined(TARGET_AMD64) || defined(TARGET_X86) || defined(TARGET_ARM) || defined(TARGET_ARM64) +#if defined(TARGET_AMD64) || defined(TARGET_X86) || defined(TARGET_ARM) || defined(TARGET_ARM64) || defined (TARGET_RISCV) for (i = OP_LOAD; i < OP_LAST; ++i) { const char *ispec; diff --git a/mono/mini/mini-gc.c b/mono/mini/mini-gc.c index c44898c84f3..754938c14fc 100644 --- a/mono/mini/mini-gc.c +++ b/mono/mini/mini-gc.c @@ -408,6 +408,11 @@ encode_frame_reg (int frame_reg) return 0; else if (frame_reg == S390_FP) return 1; +#elif defined (TARGET_RISCV) + if (frame_reg == RISCV_SP) + return 0; + else if (frame_reg == RISCV_FP) + return 1; #else NOT_IMPLEMENTED; #endif @@ -438,6 +443,11 @@ decode_frame_reg (int encoded) return S390_SP; else if (encoded == 1) return S390_FP; +#elif defined (TARGET_RISCV) + if (encoded == 0) + return RISCV_SP; + else if (encoded == 1) + return RISCV_FP; #else NOT_IMPLEMENTED; #endif @@ -469,6 +479,11 @@ static int callee_saved_regs [] = { ppc_r29, ppc_r30, ppc_r31 }; #elif defined(TARGET_POWERPC) static int callee_saved_regs [] = { ppc_r6, ppc_r7, ppc_r8, ppc_r9, ppc_r10, ppc_r11, ppc_r12, ppc_r13, ppc_r14 }; +#elif defined (TARGET_RISCV) +static int callee_saved_regs [] = { + RISCV_S0, RISCV_S1, RISCV_S2, RISCV_S3, RISCV_S4, RISCV_S5, + RISCV_S6, RISCV_S7, RISCV_S8, RISCV_S9, RISCV_S10, RISCV_S11, +}; #endif static guint32 @@ -721,6 +736,11 @@ get_frame_pointer (MonoContext *ctx, int frame_reg) return (host_mgreg_t)MONO_CONTEXT_GET_SP (ctx); else if (frame_reg == S390_FP) return (host_mgreg_t)MONO_CONTEXT_GET_BP (ctx); +#elif defined (TARGET_RISCV) + if (frame_reg == RISCV_SP) + return MONO_CONTEXT_GET_SP (ctx); + else if (frame_reg == RISCV_FP) + return MONO_CONTEXT_GET_BP (ctx); #endif g_assert_not_reached (); return 0; diff --git a/mono/mini/mini-riscv.c b/mono/mini/mini-riscv.c new file mode 100644 index 00000000000..ab0203e7ac0 --- /dev/null +++ b/mono/mini/mini-riscv.c @@ -0,0 +1,690 @@ +/* + * Licensed to the .NET Foundation under one or more agreements. + * The .NET Foundation licenses this file to you under the MIT license. + * See the LICENSE file in the project root for more information. + */ + +#include <mono/utils/mono-hwcap.h> + +#include "mini-runtime.h" + +#ifdef TARGET_RISCV64 +#include "cpu-riscv64.h" +#else +#include "cpu-riscv32.h" +#endif + +static gboolean riscv_stdext_a, riscv_stdext_b, riscv_stdext_c, + riscv_stdext_d, riscv_stdext_f, riscv_stdext_j, + riscv_stdext_l, riscv_stdext_m, riscv_stdext_n, + riscv_stdext_p, riscv_stdext_q, riscv_stdext_t, + riscv_stdext_v; + +void +mono_arch_cpu_init (void) +{ +} + +void +mono_arch_init (void) +{ + riscv_stdext_a = mono_hwcap_riscv_has_stdext_a; + riscv_stdext_c = mono_hwcap_riscv_has_stdext_c; + riscv_stdext_d = mono_hwcap_riscv_has_stdext_d; + riscv_stdext_f = mono_hwcap_riscv_has_stdext_f; + riscv_stdext_m = mono_hwcap_riscv_has_stdext_m; +} + +void +mono_arch_finish_init (void) +{ +} + +void +mono_arch_register_lowlevel_calls (void) +{ +} + +void +mono_arch_free_jit_tls_data (MonoJitTlsData *tls) +{ +} + +void +mono_arch_cleanup (void) +{ +} + +void +mono_arch_set_target (char *mtriple) +{ + // riscv{32,64}[extensions]-[<vendor>-]<system>-<abi> + + size_t len = strlen (MONO_RISCV_ARCHITECTURE); + + if (!strncmp (mtriple, MONO_RISCV_ARCHITECTURE, len)) { + mtriple += len; + + for (;;) { + char c = *mtriple; + + if (!c || c == '-') + break; + + // ISA manual says upper and lower case are both OK. + switch (c) { + case 'A': + case 'a': + riscv_stdext_a = TRUE; + break; + case 'B': + case 'b': + riscv_stdext_b = TRUE; + break; + case 'C': + case 'c': + riscv_stdext_c = TRUE; + break; + case 'D': + case 'd': + riscv_stdext_d = TRUE; + break; + case 'F': + case 'f': + riscv_stdext_f = TRUE; + break; + case 'J': + case 'j': + riscv_stdext_j = TRUE; + break; + case 'L': + case 'l': + riscv_stdext_l = TRUE; + break; + case 'M': + case 'm': + riscv_stdext_m = TRUE; + break; + case 'N': + case 'n': + riscv_stdext_n = TRUE; + break; + case 'P': + case 'p': + riscv_stdext_p = TRUE; + break; + case 'Q': + case 'q': + riscv_stdext_q = TRUE; + break; + case 'T': + case 't': + riscv_stdext_t = TRUE; + break; + case 'V': + case 'v': + riscv_stdext_v = TRUE; + break; + default: + break; + } + + mtriple++; + } + } +} + +guint32 +mono_arch_cpu_optimizations (guint32 *exclude_mask) +{ + *exclude_mask = 0; + return 0; +} + +guint32 +mono_arch_cpu_enumerate_simd_versions (void) +{ + return 0; +} + +gboolean +mono_arch_have_fast_tls (void) +{ + return TRUE; +} + +gboolean +mono_arch_opcode_supported (int opcode) +{ + switch (opcode) { + case OP_ATOMIC_ADD_I4: + case OP_ATOMIC_EXCHANGE_I4: + case OP_ATOMIC_CAS_I4: + case OP_ATOMIC_LOAD_I1: + case OP_ATOMIC_LOAD_I2: + case OP_ATOMIC_LOAD_I4: + case OP_ATOMIC_LOAD_U1: + case OP_ATOMIC_LOAD_U2: + case OP_ATOMIC_LOAD_U4: + case OP_ATOMIC_STORE_I1: + case OP_ATOMIC_STORE_I2: + case OP_ATOMIC_STORE_I4: + case OP_ATOMIC_STORE_U1: + case OP_ATOMIC_STORE_U2: + case OP_ATOMIC_STORE_U4: +#ifdef TARGET_RISCV64 + case OP_ATOMIC_ADD_I8: + case OP_ATOMIC_EXCHANGE_I8: + case OP_ATOMIC_CAS_I8: + case OP_ATOMIC_LOAD_I8: + case OP_ATOMIC_LOAD_U8: + case OP_ATOMIC_STORE_I8: + case OP_ATOMIC_STORE_U8: +#endif + return riscv_stdext_a; + case OP_ATOMIC_LOAD_R4: + case OP_ATOMIC_STORE_R4: +#ifdef TARGET_RISCV64 + case OP_ATOMIC_LOAD_R8: + case OP_ATOMIC_STORE_R8: +#endif + return riscv_stdext_a && riscv_stdext_d; + default: + return FALSE; + } +} + +const char * +mono_arch_regname (int reg) +{ + static const char *names [RISCV_N_GREGS] = { + "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", + "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5", + "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", + "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6", + }; + + if (reg >= 0 && reg < G_N_ELEMENTS (names)) + return names [reg]; + + return "x?"; +} + +const char* +mono_arch_fregname (int reg) +{ + static const char *names [RISCV_N_FREGS] = { + "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7", + "fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5", + "fa6", "fa7", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7", + "fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11", + }; + + if (reg >= 0 && reg < G_N_ELEMENTS (names)) + return names [reg]; + + return "f?"; +} + +gpointer +mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code) +{ + return (gpointer) regs [RISCV_A0]; +} + +MonoMethod * +mono_arch_find_imt_method (mgreg_t *regs, guint8 *code) +{ + return (MonoMethod *) regs [MONO_ARCH_IMT_REG]; +} + +MonoVTable * +mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code) +{ + return (MonoVTable *) regs [MONO_ARCH_VTABLE_REG]; +} + +mgreg_t +mono_arch_context_get_int_reg (MonoContext *ctx, int reg) +{ + return ctx->gregs [reg]; +} + +void +mono_arch_context_set_int_reg (MonoContext *ctx, int reg, mgreg_t val) +{ + ctx->gregs [reg] = val; +} + +void +mono_arch_flush_register_windows (void) +{ +} + +void +mono_arch_flush_icache (guint8 *code, gint size) +{ +#ifndef MONO_CROSS_COMPILE + __builtin___clear_cache (code, code + size); +#endif +} + +MonoDynCallInfo * +mono_arch_dyn_call_prepare (MonoMethodSignature *sig) +{ + NOT_IMPLEMENTED; + return NULL; +} + +void +mono_arch_dyn_call_free (MonoDynCallInfo *info) +{ + NOT_IMPLEMENTED; +} + +int +mono_arch_dyn_call_get_buf_size (MonoDynCallInfo *info) +{ + NOT_IMPLEMENTED; + return 0; +} + +void +mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, + guint8 *buf) +{ + NOT_IMPLEMENTED; +} + +void +mono_arch_finish_dyn_call (MonoDynCallInfo *info, guint8 *buf) +{ + NOT_IMPLEMENTED; +} + +int +mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, + MonoJitArgumentInfo *arg_info) +{ + NOT_IMPLEMENTED; + return 0; +} + +void +mono_arch_patch_code_new (MonoCompile *cfg, MonoDomain *domain, guint8 *code, + MonoJumpInfo *ji, gpointer target) +{ + NOT_IMPLEMENTED; +} + +/* Set arguments in the ccontext (for i2n entry) */ +void +mono_arch_set_native_call_context_args (CallContext *ccontext, gpointer frame, MonoMethodSignature *sig) +{ + NOT_IMPLEMENTED; +} + +/* Set return value in the ccontext (for n2i return) */ +void +mono_arch_set_native_call_context_ret (CallContext *ccontext, gpointer frame, MonoMethodSignature *sig) +{ + NOT_IMPLEMENTED; +} + +/* Gets the arguments from ccontext (for n2i entry) */ +void +mono_arch_get_native_call_context_args (CallContext *ccontext, gpointer frame, MonoMethodSignature *sig) +{ + NOT_IMPLEMENTED; +} + +/* Gets the return value from ccontext (for i2n exit) */ +void +mono_arch_get_native_call_context_ret (CallContext *ccontext, gpointer frame, MonoMethodSignature *sig) +{ + NOT_IMPLEMENTED; +} + +#ifndef DISABLE_JIT + +#ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK + +gboolean +mono_arch_is_soft_float (void) +{ + return !riscv_stdext_d; +} + +#endif + +gboolean +mono_arch_opcode_needs_emulation (MonoCompile *cfg, int opcode) +{ + switch (opcode) { + case OP_IDIV: + case OP_IDIV_UN: + case OP_IREM: + case OP_IREM_UN: +#ifdef TARGET_RISCV64 + case OP_LDIV: + case OP_LDIV_UN: + case OP_LREM: + case OP_LREM_UN: +#endif + return !riscv_stdext_m; + default: + return TRUE; + } +} + +gboolean +mono_arch_tailcall_supported (MonoCompile *cfg, MonoMethodSignature *caller_sig, MonoMethodSignature *callee_sig, gboolean virtual_) +{ + NOT_IMPLEMENTED; +} + +gboolean +mono_arch_is_inst_imm (int opcode, int imm_opcode, gint64 imm) +{ + // TODO: Make a proper decision based on opcode. + return TRUE; +} + +GList * +mono_arch_get_allocatable_int_vars (MonoCompile *cfg) +{ + GList *vars = NULL; + + for (guint i = 0; i < cfg->num_varinfo; i++) { + MonoInst *ins = cfg->varinfo [i]; + MonoMethodVar *vmv = MONO_VARINFO (cfg, i); + + if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos) + continue; + + if ((ins->flags & (MONO_INST_IS_DEAD | MONO_INST_VOLATILE | MONO_INST_INDIRECT)) || + (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG)) + continue; + + if (!mono_is_regsize_var (ins->inst_vtype)) + continue; + + vars = g_list_prepend (vars, vmv); + } + + vars = mono_varlist_sort (cfg, vars, 0); + + return vars; +} + +GList * +mono_arch_get_global_int_regs (MonoCompile *cfg) +{ + GList *regs = NULL; + + for (int i = RISCV_S0; i <= RISCV_S11; i++) + regs = g_list_prepend (regs, GUINT_TO_POINTER (i)); + + return regs; +} + +guint32 +mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv) +{ + return cfg->varinfo [vmv->idx]->opcode == OP_ARG ? 1 : 2; +} + +#ifdef ENABLE_LLVM + +LLVMCallInfo* +mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig) +{ + NOT_IMPLEMENTED; +} + +#endif + +void +mono_arch_create_vars (MonoCompile *cfg) +{ + NOT_IMPLEMENTED; +} + +MonoInst * +mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, + MonoMethodSignature *fsig, MonoInst **args) +{ + return NULL; +} + +void +mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) +{ + NOT_IMPLEMENTED; +} + +void +mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src) +{ + NOT_IMPLEMENTED; +} + +void +mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val) +{ + NOT_IMPLEMENTED; +} + +void +mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins) +{ + NOT_IMPLEMENTED; +} + +void +mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *long_ins) +{ +#ifdef TARGET_RISCV32 + NOT_IMPLEMENTED; +#endif +} + +void +mono_arch_allocate_vars (MonoCompile *cfg) +{ + NOT_IMPLEMENTED; +} + +void +mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) +{ + NOT_IMPLEMENTED; +} + +void +mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb) +{ +} + +void +mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) +{ +} + +// Uses at most 8 bytes on RV32I and 16 bytes on RV64I. +guint8 * +mono_riscv_emit_imm (guint8 *code, int rd, gsize imm) +{ +#ifdef TARGET_RISCV64 + if (RISCV_VALID_I_IMM (imm)) { + riscv_addi (code, rd, RISCV_ZERO, imm); + return code; + } + + /* + * This is not pretty, but RV64I doesn't make it easy to load constants. + * Need to figure out something better. + */ + riscv_jal (code, rd, sizeof (guint64)); + *(guint64 *) code = imm; + code += sizeof (guint64); + riscv_ld (code, rd, rd, 0); +#else + if (RISCV_VALID_I_IMM (imm)) { + riscv_addi (code, rd, RISCV_ZERO, imm); + return code; + } + + riscv_lui (code, rd, RISCV_BITS (imm, 12, 20)); + + if (!RISCV_VALID_U_IMM (imm)) + riscv_ori (code, rd, rd, RISCV_BITS (imm, 0, 12)); +#endif + + return code; +} + +// Uses at most 16 bytes on RV32I and 24 bytes on RV64I. +guint8 * +mono_riscv_emit_load (guint8 *code, int rd, int rs1, gint32 imm) +{ + if (RISCV_VALID_I_IMM (imm)) { +#ifdef TARGET_RISCV64 + riscv_ld (code, rd, rs1, imm); +#else + riscv_lw (code, rd, rs1, imm); +#endif + } else { + code = mono_riscv_emit_imm (code, rd, imm); + riscv_add (code, rd, rs1, rd); +#ifdef TARGET_RISCV64 + riscv_ld (code, rd, rd, 0); +#else + riscv_lw (code, rd, rd, 0); +#endif + } + + return code; +} + +// May clobber t1. Uses at most 16 bytes on RV32I and 24 bytes on RV64I. +guint8 * +mono_riscv_emit_store (guint8 *code, int rs1, int rs2, gint32 imm) +{ + if (RISCV_VALID_S_IMM (imm)) { +#ifdef TARGET_RISCV64 + riscv_sd (code, rs1, rs2, imm); +#else + riscv_sw (code, rs1, rs2, imm); +#endif + } else { + code = mono_riscv_emit_imm (code, RISCV_T1, imm); + riscv_add (code, RISCV_T1, rs2, RISCV_T1); +#ifdef TARGET_RISCV64 + riscv_sd (code, rs1, RISCV_T1, 0); +#else + riscv_sw (code, rs1, RISCV_T1, 0); +#endif + } + + return code; +} + +guint8 * +mono_arch_emit_prolog (MonoCompile *cfg) +{ + NOT_IMPLEMENTED; +} + +void +mono_arch_emit_epilog (MonoCompile *cfg) +{ + NOT_IMPLEMENTED; +} + +void +mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) +{ + NOT_IMPLEMENTED; +} + +void +mono_arch_emit_exceptions (MonoCompile *cfg) +{ + NOT_IMPLEMENTED; +} + +guint32 +mono_arch_get_patch_offset (guint8 *code) +{ + NOT_IMPLEMENTED; + return 0; +} + +GSList * +mono_arch_get_trampolines (gboolean aot) +{ + NOT_IMPLEMENTED; + return NULL; +} + +#endif + +#if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) +void +mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip) +{ + NOT_IMPLEMENTED; +} + +void +mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip) +{ + NOT_IMPLEMENTED; +} + +void +mono_arch_start_single_stepping (void) +{ + NOT_IMPLEMENTED; +} + +void +mono_arch_stop_single_stepping (void) +{ + NOT_IMPLEMENTED; +} + +gboolean +mono_arch_is_single_step_event (void *info, void *sigctx) +{ + NOT_IMPLEMENTED; + return FALSE; +} + +gboolean +mono_arch_is_breakpoint_event (void *info, void *sigctx) +{ + NOT_IMPLEMENTED; + return FALSE; +} + +void +mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji) +{ + NOT_IMPLEMENTED; +} + +void +mono_arch_skip_single_step (MonoContext *ctx) +{ + NOT_IMPLEMENTED; +} + +gpointer +mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code) +{ + NOT_IMPLEMENTED; + return NULL; +} +#endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */ diff --git a/mono/mini/mini-riscv.h b/mono/mini/mini-riscv.h new file mode 100644 index 00000000000..eb431743a8e --- /dev/null +++ b/mono/mini/mini-riscv.h @@ -0,0 +1,211 @@ +/* + * Licensed to the .NET Foundation under one or more agreements. + * The .NET Foundation licenses this file to you under the MIT license. + * See the LICENSE file in the project root for more information. + */ + +#ifndef __MONO_MINI_RISCV_H__ +#define __MONO_MINI_RISCV_H__ + +#include <mono/arch/riscv/riscv-codegen.h> + +#ifdef TARGET_RISCV64 +#define MONO_RISCV_ARCHITECTURE "riscv64" +#else +#define MONO_RISCV_ARCHITECTURE "riscv32" +#endif + +#if defined (RISCV_FPABI_SOFT) +#define MONO_ARCH_SOFT_FLOAT_FALLBACK +#define RISCV_FP_MODEL "soft-fp" +#elif defined (RISCV_FPABI_DOUBLE) +#define RISCV_FP_MODEL "double-fp" +#elif defined (RISCV_FPABI_SINGLE) +#define RISCV_FP_MODEL "single-fp" +#error "The single-precision RISC-V hard float ABI is not currently supported." +#else +#error "Unknown RISC-V FPABI. This is probably a bug in configure.ac." +#endif + +#define MONO_ARCH_ARCHITECTURE MONO_RISCV_ARCHITECTURE "," RISCV_FP_MODEL + +#ifdef TARGET_RISCV64 +#define MONO_ARCH_CPU_SPEC mono_riscv64_cpu_desc +#else +#define MONO_ARCH_CPU_SPEC mono_riscv32_cpu_desc +#endif + +#define MONO_MAX_IREGS (RISCV_N_GREGS) +#define MONO_MAX_FREGS (RISCV_N_FREGS) + +/* + * Register usage conventions: + * + * - a0..a7 and fa0..fa7 are argument/return registers. + * - s0..11 and fs0..fs11 are callee-saved registers. + * - a0..a1 are used as fixed registers (for the 'a' spec, soft float, and + * longs on 32-bit, as appropriate). + * - t0..t1, ra, and ft0..ft2 are used as scratch registers and can't be + * allocated by the register allocator. + * - t2 is used as the RGCTX/IMT register and can't be allocated by the + * register allocator. + * - a0 is used as the VTable register for lazy fetch trampolines. + * - sp, fp, gp, and tp are all reserved by the ABI and can't be allocated by + * the register allocator. + * - x0 is hard-wired to zero and can't be allocated by the register allocator. + */ + +#define MONO_ARCH_CALLEE_REGS (0b11110000000000111111110000000000) +#define MONO_ARCH_CALLEE_SAVED_REGS (0b00001111111111000000001100000000) + +#ifdef RISCV_FPABI_SOFT + +#define MONO_ARCH_CALLEE_FREGS (0b11111111111111111111111111111000) +#define MONO_ARCH_CALLEE_SAVED_FREGS (0b00000000000000000000000000000000) + +#else + +#define MONO_ARCH_CALLEE_FREGS (0b11110000000000111111110011111000) +#define MONO_ARCH_CALLEE_SAVED_FREGS (0b00001111111111000000001100000000) + +#endif + +#define MONO_ARCH_INST_SREG2_MASK(ins) \ + (0) +#define MONO_ARCH_INST_IS_FLOAT(desc) \ + (!mono_arch_is_soft_float () && (desc) == 'f') + +#ifdef TARGET_RISCV64 + +#define MONO_ARCH_INST_FIXED_REG(desc) \ + ((desc) == 'a' || (mono_arch_is_soft_float () && (desc) == 'f') ? RISCV_A0 : -1) +#define MONO_ARCH_INST_IS_REGPAIR(desc) \ + (FALSE) +#define MONO_ARCH_INST_REGPAIR_REG2(desc, hreg1) \ + (-1) + +#else + +#define MONO_ARCH_INST_FIXED_REG(desc) \ + ((desc) == 'a' || (desc) == 'l' || (mono_arch_is_soft_float () && (desc) == 'f') ? RISCV_A0 : -1) +#define MONO_ARCH_INST_IS_REGPAIR(desc) \ + ((desc) == 'l' || (mono_arch_is_soft_float () && (desc) == 'f')) +#define MONO_ARCH_INST_REGPAIR_REG2(desc, hreg1) \ + (RISCV_A1) + +#endif + +#define MONO_ARCH_RGCTX_REG (RISCV_T2) +#define MONO_ARCH_IMT_REG (RISCV_T2) +#define MONO_ARCH_VTABLE_REG (RISCV_A0) + +#define MONO_ARCH_HAVE_VOLATILE_NON_PARAM_REGISTER 0 + +#define MONO_ARCH_USE_FPSTACK (FALSE) + +#define MONO_ARCH_FRAME_ALIGNMENT (16) +#define MONO_ARCH_CODE_ALIGNMENT (32) + +#define MONO_ARCH_EMULATE_MUL_DIV (1) +#define MONO_ARCH_EMULATE_FREM (1) + +#ifdef TARGET_RISCV64 + +#define MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS (1) + +#endif + +#define MONO_ARCH_EMULATE_CONV_R8_UN (1) +#define MONO_ARCH_EMULATE_FCONV_TO_I8 (1) +#define MONO_ARCH_EMULATE_LCONV_TO_R8 (1) +#define MONO_ARCH_EMULATE_LCONV_TO_R4 (1) +#define MONO_ARCH_EMULATE_LCONV_TO_R8_UN (1) + +#define MONO_ARCH_NEED_DIV_CHECK (1) + +#define MONO_ARCH_HAVE_OP_TAIL_CALL (1) +#define MONO_ARCH_HAVE_OP_GENERIC_CLASS_INIT (1) +#define MONO_ARCH_HAVE_CARD_TABLE_WBARRIER (1) + +#define MONO_ARCH_HAVE_GENERALIZED_IMT_TRAMPOLINE (1) +#define MONO_ARCH_HAVE_GENERAL_RGCTX_LAZY_FETCH_TRAMPOLINE (1) +#define MONO_ARCH_HAVE_SDB_TRAMPOLINES (1) +#define MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP (1) +#define MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES (1) + +#define MONO_ARCH_USE_SIGACTION (1) +#define MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX (1) + +#define MONO_ARCH_HAVE_CONTEXT_SET_INT_REG (1) +#define MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS (1) +#define MONO_ARCH_HAVE_DECOMPOSE_OPTS (1) +#define MONO_ARCH_HAVE_EXCEPTIONS_INIT (1) +#define MONO_ARCH_HAVE_GET_TRAMPOLINES (1) +#define MONO_ARCH_HAVE_OPCODE_NEEDS_EMULATION (1) +#define MONO_ARCH_HAVE_PATCH_CODE_NEW (1) +#define MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK (1) +#define MONO_ARCH_HAVE_SETUP_RESUME_FROM_SIGNAL_HANDLER_CTX (1) + +#define MONO_ARCH_GSHARED_SUPPORTED (1) +#define MONO_ARCH_INTERPRETER_SUPPORTED (1) +//#define MONO_ARCH_AOT_SUPPORTED (1) +//#define MONO_ARCH_LLVM_SUPPORTED (1) +//#define MONO_ARCH_SOFT_DEBUG_SUPPORTED (1) + + +// #define MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE (1) +// #define MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP (1) +// #define MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED (1) + +typedef struct { +} MonoCompileArch; + +#define MONO_CONTEXT_SET_LLVM_EXC_REG(ctx, exc) \ + do { \ + (ctx)->gregs [RISCV_A0] = (mgreg_t) exc; \ + } while (0) + +#define MONO_INIT_CONTEXT_FROM_FUNC(ctx, func) \ + do { \ + MONO_CONTEXT_SET_IP ((ctx), (func)); \ + MONO_CONTEXT_SET_SP ((ctx), __builtin_frame_address (0)); \ + MONO_CONTEXT_SET_BP ((ctx), __builtin_frame_address (0)); \ + } while (0) + +struct MonoLMF { + // If the second-lowest bit of this field is set, this is a MonoLMFExt. + gpointer previous_lmf; + gpointer lmf_addr; + mgreg_t pc; + mgreg_t sp; + mgreg_t ra; + mgreg_t gregs [RISCV_N_GSREGS]; // s0..s11 + double fregs [RISCV_N_FSREGS]; // fs0..fs11 +}; + +#define MONO_ARCH_INIT_TOP_LMF_ENTRY(lmf) + +typedef struct { +} CallContext; + +enum { + MONO_R_RISCV_IMM = 1, + MONO_R_RISCV_B = 2, + MONO_R_RISCV_BEQ = 3, + MONO_R_RISCV_BNE = 4, + MONO_R_RISCV_BLT = 5, + MONO_R_RISCV_BGE = 6, + MONO_R_RISCV_BLTU = 7, + MONO_R_RISCV_BGEU = 8, +}; + +__attribute__ ((warn_unused_result)) guint8 * +mono_riscv_emit_imm (guint8 *code, int rd, gsize imm); + +__attribute__ ((warn_unused_result)) guint8 * +mono_riscv_emit_load (guint8 *code, int rd, int rs1, gint32 imm); + +__attribute__ ((warn_unused_result)) guint8 * +mono_riscv_emit_store (guint8 *code, int rs1, int rs2, gint32 imm); + +#endif diff --git a/mono/mini/tramp-riscv.c b/mono/mini/tramp-riscv.c new file mode 100644 index 00000000000..f6f2f421d0f --- /dev/null +++ b/mono/mini/tramp-riscv.c @@ -0,0 +1,303 @@ +/* + * Licensed to the .NET Foundation under one or more agreements. + * The .NET Foundation licenses this file to you under the MIT license. + * See the LICENSE file in the project root for more information. + */ + +#include "mini-runtime.h" + +#include <mono/metadata/abi-details.h> + +void +mono_arch_patch_callsite (guint8 *method_start, guint8 *code_ptr, guint8 *addr) +{ + NOT_IMPLEMENTED; +} + +void +mono_arch_patch_plt_entry (guint8 *code, gpointer *got, mgreg_t *regs, guint8 *addr) +{ + NOT_IMPLEMENTED; +} + +guint8 * +mono_arch_get_call_target (guint8 *code) +{ + NOT_IMPLEMENTED; + return NULL; +} + +guint32 +mono_arch_get_plt_info_offset (guint8 *plt_entry, mgreg_t *regs, guint8 *code) +{ + NOT_IMPLEMENTED; + return 0; +} + +GSList * +mono_arch_get_delegate_invoke_impls (void) +{ + NOT_IMPLEMENTED; + return NULL; +} + +gpointer +mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target) +{ + NOT_IMPLEMENTED; + return NULL; +} + +gpointer +mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, + MonoMethod *method, int offset, + gboolean load_imt_reg) +{ + NOT_IMPLEMENTED; + return NULL; +} + +#ifndef DISABLE_JIT + +guchar * +mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInfo **info, + gboolean aot) +{ + if (aot) + NOT_IMPLEMENTED; + + guint8 *buf = mono_global_codeman_reserve (1024), *code = buf; + + if (info) { + char *name = mono_get_generic_trampoline_name (tramp_type); + *info = mono_tramp_info_create (name, buf, code - buf, NULL, NULL); + g_free (name); + } + + return buf; +} + +gpointer +mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, + MonoDomain *domain, guint32 *code_len) +{ + guint8 *buf = mono_domain_code_reserve (domain, 64), *code = buf; + guint8 *tramp = mono_get_trampoline_code (tramp_type); + + // Pass the argument in scratch t0. + code = mono_riscv_emit_imm (code, RISCV_T0, (gsize) arg1); + code = mono_riscv_emit_imm (code, RISCV_T1, (gsize) tramp); + riscv_jalr (code, RISCV_ZERO, RISCV_T1, 0); + + mono_arch_flush_icache (buf, code - buf); + + if (code_len) + *code_len = code - buf; + + return buf; +} + +gpointer +mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr) +{ + guint8 *buf = mono_domain_code_reserve (mono_domain_get (), 64), *code = buf; + + // Pass the argument in a0. + code = mono_riscv_emit_imm (code, RISCV_A0, sizeof (MonoObject)); + code = mono_riscv_emit_imm (code, RISCV_T0, (gsize) addr); + riscv_jalr (code, RISCV_ZERO, RISCV_T0, 0); + + mono_arch_flush_icache (buf, code - buf); + + return buf; +} + +gpointer +mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, + MonoIMTCheckItem **imt_entries, int count, + gpointer fail_tramp) +{ + NOT_IMPLEMENTED; + return NULL; +} + +gpointer +mono_arch_get_static_rgctx_trampoline (gpointer arg, gpointer addr) +{ + guint8 *buf = mono_domain_code_reserve (mono_domain_get (), 64), *code = buf; + + // Pass the argument in the RGCTX register. + code = mono_riscv_emit_imm (code, MONO_ARCH_RGCTX_REG, (gsize) arg); + code = mono_riscv_emit_imm (code, RISCV_T0, (gsize) addr); + riscv_jalr (code, RISCV_ZERO, RISCV_T0, 0); + + mono_arch_flush_icache (buf, code - buf); + + return buf; +} + +gpointer +mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info, + gboolean aot) +{ + if (aot) + NOT_IMPLEMENTED; + + gboolean is_mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot); + int index = MONO_RGCTX_SLOT_INDEX (slot); + + if (is_mrgctx) + index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer); + + int depth; + + for (depth = 0; ; depth++) { + int size = mono_class_rgctx_get_array_size (depth, is_mrgctx); + + if (index < size - 1) + break; + + index -= size - 1; + } + + guint8 *buf = mono_global_codeman_reserve (128 * depth), *code = buf; + guint8 **null_jumps = g_malloc0 (sizeof (guint8 *) * (depth + 2)); + + if (!is_mrgctx) { + } else + riscv_addi (code, RISCV_T1, RISCV_A0, 0); + + mono_arch_flush_icache (buf, code - buf); + + if (info) { + char *name = mono_get_rgctx_fetch_trampoline_name (slot); + *info = mono_tramp_info_create (name, buf, code - buf, NULL, NULL); + g_free (name); + } + + return buf; +} + +gpointer +mono_arch_create_general_rgctx_lazy_fetch_trampoline (MonoTrampInfo **info, gboolean aot) +{ + if (aot) + NOT_IMPLEMENTED; + + guint8 *buf = mono_global_codeman_reserve (64), *code = buf; + + /* + * The RGCTX register holds a pointer to a <slot, trampoline address> pair. + * Load the trampoline address and branch to it. a0 holds the actual + * (M)RGCTX or VTable. + */ + code = mono_riscv_emit_load (code, RISCV_T0, MONO_ARCH_RGCTX_REG, sizeof (gpointer)); + riscv_jalr (code, RISCV_ZERO, RISCV_T0, 0); + + mono_arch_flush_icache (buf, code - buf); + + if (info) + *info = mono_tramp_info_create ("rgctx_fetch_trampoline_general", buf, code - buf, NULL, NULL); + + return buf; +} + +guint8 * +mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gboolean aot) +{ + NOT_IMPLEMENTED; + return NULL; +} + +gpointer +mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) +{ + NOT_IMPLEMENTED; + return NULL; +} + +gpointer +mono_arch_get_native_to_interp_trampoline (MonoTrampInfo **info) +{ + NOT_IMPLEMENTED; + return NULL; +} + +#else + +guchar * +mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInfo **info, + gboolean aot) +{ + g_assert_not_reached (); + return NULL; +} + +gpointer +mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, + MonoDomain *domain, guint32 *code_len) +{ + g_assert_not_reached (); + return NULL; +} + +gpointer +mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr) +{ + g_assert_not_reached (); + return NULL; +} + +gpointer +mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, + MonoIMTCheckItem **imt_entries, int count, + gpointer fail_tramp) +{ + g_assert_not_reached (); + return NULL; +} + +gpointer +mono_arch_get_static_rgctx_trampoline (gpointer arg, gpointer addr) +{ + g_assert_not_reached (); + return NULL; +} + +gpointer +mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info, + gboolean aot) +{ + g_assert_not_reached (); + return NULL; +} + +gpointer +mono_arch_create_general_rgctx_lazy_fetch_trampoline (MonoTrampInfo **info, gboolean aot) +{ + g_assert_not_reached (); + return NULL; +} + +guint8 * +mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gboolean aot) +{ + g_assert_not_reached (); + return NULL; +} + +gpointer +mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) +{ + g_assert_not_reached (); + return NULL; +} + +gpointer +mono_arch_get_native_to_interp_trampoline (MonoTrampInfo **info) +{ + g_assert_not_reached (); + return NULL; +} + +#endif diff --git a/mono/mini/unwind.c b/mono/mini/unwind.c index 263cba2505c..03f88149f31 100644 --- a/mono/mini/unwind.c +++ b/mono/mini/unwind.c @@ -113,6 +113,26 @@ static int map_hw_reg_to_dwarf_reg [32] = { #define NUM_DWARF_REGS 32 #define DWARF_DATA_ALIGN (-(gint32)sizeof (mgreg_t)) #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (mips_ra)) +#elif defined(TARGET_RISCV) + +/* + * These values have not currently been formalized in the RISC-V psABI. See + * instead gcc/config/riscv/riscv.h in the GCC source tree. + */ + +#define NUM_DWARF_REGS (RISCV_N_GREGS + RISCV_N_FREGS) +#define DWARF_DATA_ALIGN (-4) +#define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (RISCV_RA)) + +static int map_hw_reg_to_dwarf_reg [NUM_DWARF_REGS] = { + // x0..x31 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + // f0..f31 + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, +}; + #else static int map_hw_reg_to_dwarf_reg [16]; #define NUM_DWARF_REGS 16 diff --git a/mono/sgen/sgen-archdep.h b/mono/sgen/sgen-archdep.h index 9a3ad015704..008c0943884 100644 --- a/mono/sgen/sgen-archdep.h +++ b/mono/sgen/sgen-archdep.h @@ -65,6 +65,10 @@ #define REDZONE_SIZE 0 +#elif defined (TARGET_RISCV) + +#define REDZONE_SIZE (0) + #elif defined (TARGET_WASM) #define REDZONE_SIZE 0 diff --git a/mono/sgen/sgen-cardtable.c b/mono/sgen/sgen-cardtable.c index 4c8a94fe1a3..f03da24ab0a 100644 --- a/mono/sgen/sgen-cardtable.c +++ b/mono/sgen/sgen-cardtable.c @@ -524,9 +524,9 @@ static inline int find_card_offset (mword card) { /*XXX Use assembly as this generates some pretty bad code */ -#if (defined(__i386__) || defined(__arm__)) && defined(__GNUC__) +#if (defined(__i386__) || defined(__arm__) || (defined (__riscv) && __riscv_xlen == 32)) && defined(__GNUC__) return (__builtin_ffs (card) - 1) / 8; -#elif (defined(__x86_64__) || defined(__aarch64__)) && defined(__GNUC__) +#elif (defined(__x86_64__) || defined(__aarch64__) || (defined (__riscv) && __riscv_xlen == 64)) && defined(__GNUC__) return (__builtin_ffsll (card) - 1) / 8; #elif defined(__s390x__) return (__builtin_ffsll (GUINT64_TO_LE(card)) - 1) / 8; diff --git a/mono/utils/Makefile.am b/mono/utils/Makefile.am index d5ed57941ad..b44d399ba44 100644 --- a/mono/utils/Makefile.am +++ b/mono/utils/Makefile.am @@ -292,6 +292,10 @@ if S390X arch_sources += mono-hwcap-s390x.c endif +if RISCV +arch_sources += mono-hwcap-riscv.c +endif + if HOST_WASM arch_sources += mono-hwcap-wasm.c endif diff --git a/mono/utils/mono-context.c b/mono/utils/mono-context.c index 17982731a01..706dab8e2b2 100644 --- a/mono/utils/mono-context.c +++ b/mono/utils/mono-context.c @@ -566,4 +566,34 @@ mono_monoctx_to_sigctx (MonoContext *mctx, void *sigctx) g_error ("MonoContext not supported"); } +#elif ((defined (HOST_RISCV) || defined (HOST_RISCV64)) && !defined (MONO_CROSS_COMPILE)) || defined (TARGET_RISCV) + +#include <mono/utils/mono-context.h> + +void +mono_sigctx_to_monoctx (void *sigctx, MonoContext *mctx) +{ +#ifdef MONO_CROSS_COMPILE + g_assert_not_reached (); +#else + ucontext_t *uctx = sigctx; + + memcpy (&mctx->gregs, &uctx->uc_mcontext.gregs, sizeof (mgreg_t) * G_N_ELEMENTS (mctx->gregs)); + memcpy (&mctx->fregs, &uctx->uc_mcontext.fpregs, sizeof (double) * G_N_ELEMENTS (mctx->fregs)); +#endif +} + +void +mono_monoctx_to_sigctx (MonoContext *mctx, void *sigctx) +{ +#ifdef MONO_CROSS_COMPILE + g_assert_not_reached (); +#else + ucontext_t *uctx = sigctx; + + memcpy (&uctx->uc_mcontext.gregs, &mctx->gregs, sizeof (mgreg_t) * G_N_ELEMENTS (mctx->gregs)); + memcpy (&uctx->uc_mcontext.fpregs, &mctx->fregs, sizeof (double) * G_N_ELEMENTS (mctx->fregs)); +#endif +} + #endif /* #if defined(__i386__) */ diff --git a/mono/utils/mono-context.h b/mono/utils/mono-context.h index 9bfb607565d..59e84aafbfd 100644 --- a/mono/utils/mono-context.h +++ b/mono/utils/mono-context.h @@ -892,6 +892,119 @@ typedef struct ucontext MonoContext; : "memory" \ ) +#elif (defined (HOST_RISCV) && !defined (MONO_CROSS_COMPILE)) || defined (TARGET_RISCV) + +#include <mono/arch/riscv/riscv-codegen.h> + +typedef struct { + mgreg_t gregs [RISCV_N_GREGS]; // [0] contains pc since x0 is hard-wired to zero anyway. + double fregs [RISCV_N_FREGS * 2 + 2]; // [32] contains fcsr (32 bits), the rest is for quad-precision values (currently unused). +} MonoContext; + +#define MONO_CONTEXT_SET_IP(ctx, ip) do { (ctx)->gregs [RISCV_ZERO] = (mgreg_t) (ip); } while (0) +#define MONO_CONTEXT_SET_BP(ctx, bp) do { (ctx)->gregs [RISCV_FP] = (mgreg_t) (bp); } while (0) +#define MONO_CONTEXT_SET_SP(ctx, sp) do { (ctx)->gregs [RISCV_SP] = (mgreg_t) (sp); } while (0) + +#define MONO_CONTEXT_GET_IP(ctx) ((gpointer) ((ctx)->gregs [RISCV_ZERO])) +#define MONO_CONTEXT_GET_BP(ctx) ((gpointer) ((ctx)->gregs [RISCV_FP])) +#define MONO_CONTEXT_GET_SP(ctx) ((gpointer) ((ctx)->gregs [RISCV_SP])) + +#ifdef TARGET_RISCV64 +#define _RISCV_STR "sd" +#define _RISCV_SZ "8" +#else +#define _RISCV_STR "sw" +#define _RISCV_SZ "4" +#endif + +#define MONO_CONTEXT_GET_CURRENT(ctx) \ + do { \ + __asm__ __volatile__ ( \ + _RISCV_STR " x1, " _RISCV_SZ "*1(%0)\n" \ + _RISCV_STR " x2, " _RISCV_SZ "*2(%0)\n" \ + _RISCV_STR " x3, " _RISCV_SZ "*3(%0)\n" \ + _RISCV_STR " x4, " _RISCV_SZ "*4(%0)\n" \ + _RISCV_STR " x5, " _RISCV_SZ "*5(%0)\n" \ + _RISCV_STR " x6, " _RISCV_SZ "*6(%0)\n" \ + _RISCV_STR " x7, " _RISCV_SZ "*7(%0)\n" \ + _RISCV_STR " x8, " _RISCV_SZ "*8(%0)\n" \ + _RISCV_STR " x9, " _RISCV_SZ "*9(%0)\n" \ + _RISCV_STR " x10, " _RISCV_SZ "*10(%0)\n" \ + _RISCV_STR " x11, " _RISCV_SZ "*11(%0)\n" \ + _RISCV_STR " x12, " _RISCV_SZ "*12(%0)\n" \ + _RISCV_STR " x13, " _RISCV_SZ "*13(%0)\n" \ + _RISCV_STR " x14, " _RISCV_SZ "*14(%0)\n" \ + _RISCV_STR " x15, " _RISCV_SZ "*15(%0)\n" \ + _RISCV_STR " x16, " _RISCV_SZ "*16(%0)\n" \ + _RISCV_STR " x17, " _RISCV_SZ "*17(%0)\n" \ + _RISCV_STR " x18, " _RISCV_SZ "*18(%0)\n" \ + _RISCV_STR " x19, " _RISCV_SZ "*19(%0)\n" \ + _RISCV_STR " x20, " _RISCV_SZ "*20(%0)\n" \ + _RISCV_STR " x21, " _RISCV_SZ "*21(%0)\n" \ + _RISCV_STR " x22, " _RISCV_SZ "*22(%0)\n" \ + _RISCV_STR " x23, " _RISCV_SZ "*23(%0)\n" \ + _RISCV_STR " x24, " _RISCV_SZ "*24(%0)\n" \ + _RISCV_STR " x25, " _RISCV_SZ "*25(%0)\n" \ + _RISCV_STR " x26, " _RISCV_SZ "*26(%0)\n" \ + _RISCV_STR " x27, " _RISCV_SZ "*27(%0)\n" \ + _RISCV_STR " x28, " _RISCV_SZ "*28(%0)\n" \ + _RISCV_STR " x29, " _RISCV_SZ "*29(%0)\n" \ + _RISCV_STR " x30, " _RISCV_SZ "*30(%0)\n" \ + _RISCV_STR " x31, " _RISCV_SZ "*31(%0)\n" \ + : \ + : "r" (&(ctx).gregs) \ + : "memory" \ + ); \ + __asm__ __volatile__ ( \ + "frcsr t0\n" \ + "fsd f0, 8*0(%0)\n" \ + "fsd f1, 8*1(%0)\n" \ + "fsd f2, 8*2(%0)\n" \ + "fsd f3, 8*3(%0)\n" \ + "fsd f4, 8*4(%0)\n" \ + "fsd f5, 8*5(%0)\n" \ + "fsd f6, 8*6(%0)\n" \ + "fsd f7, 8*7(%0)\n" \ + "fsd f8, 8*8(%0)\n" \ + "fsd f9, 8*9(%0)\n" \ + "fsd f10, 8*10(%0)\n" \ + "fsd f11, 8*11(%0)\n" \ + "fsd f12, 8*12(%0)\n" \ + "fsd f13, 8*13(%0)\n" \ + "fsd f14, 8*14(%0)\n" \ + "fsd f15, 8*15(%0)\n" \ + "fsd f16, 8*16(%0)\n" \ + "fsd f17, 8*17(%0)\n" \ + "fsd f18, 8*18(%0)\n" \ + "fsd f19, 8*19(%0)\n" \ + "fsd f20, 8*20(%0)\n" \ + "fsd f21, 8*21(%0)\n" \ + "fsd f22, 8*22(%0)\n" \ + "fsd f23, 8*23(%0)\n" \ + "fsd f24, 8*24(%0)\n" \ + "fsd f25, 8*25(%0)\n" \ + "fsd f26, 8*26(%0)\n" \ + "fsd f27, 8*27(%0)\n" \ + "fsd f28, 8*28(%0)\n" \ + "fsd f29, 8*29(%0)\n" \ + "fsd f30, 8*30(%0)\n" \ + "fsd f31, 8*31(%0)\n" \ + "sw t0, 8*32(%0)\n" \ + : \ + : "r" (&(ctx).fregs) \ + : "t0", "memory" \ + ); \ + __asm__ __volatile__ ( \ + "auipc t0, 0\n" \ + _RISCV_STR " t0, (%0)\n" \ + : \ + : "r" (&(ctx).gregs [0]) \ + : "t0", "memory" \ + ); \ + } while (0) + +#define MONO_ARCH_HAS_MONO_CONTEXT (1) + #else #error "Implement mono-context for the current arch" diff --git a/mono/utils/mono-hwcap-riscv.c b/mono/utils/mono-hwcap-riscv.c new file mode 100644 index 00000000000..b2f5dbcfe40 --- /dev/null +++ b/mono/utils/mono-hwcap-riscv.c @@ -0,0 +1,41 @@ +/* + * Licensed to the .NET Foundation under one or more agreements. + * The .NET Foundation licenses this file to you under the MIT license. + * See the LICENSE file in the project root for more information. + */ + +#include <mono/utils/mono-hwcap.h> + +#include <sys/auxv.h> + +void +mono_hwcap_arch_init (void) +{ + // See arch/riscv/include/uapi/asm/hwcap.h in the kernel source tree. + + unsigned long hwcap; + + if ((hwcap = getauxval (AT_HWCAP))) { + // COMPAT_HWCAP_ISA_A + if (hwcap & (1 << ('A' - 'A'))) + mono_hwcap_riscv_has_stdext_a = TRUE; + + // COMPAT_HWCAP_ISA_C + if (hwcap & (1 << ('C' - 'A'))) + mono_hwcap_riscv_has_stdext_c = TRUE; + + // COMPAT_HWCAP_ISA_D + if (hwcap & (1 << ('D' - 'A'))) + mono_hwcap_riscv_has_stdext_d = TRUE; + + // COMPAT_HWCAP_ISA_F + if (hwcap & (1 << ('F' - 'A'))) + mono_hwcap_riscv_has_stdext_f = TRUE; + + // Why does COMPAT_HWCAP_ISA_I even exist...? + + // COMPAT_HWCAP_ISA_M + if (hwcap & (1 << ('M' - 'A'))) + mono_hwcap_riscv_has_stdext_m = TRUE; + } +} diff --git a/mono/utils/mono-hwcap-vars.h b/mono/utils/mono-hwcap-vars.h index 05f89a34ef9..5fefe5ca5e4 100644 --- a/mono/utils/mono-hwcap-vars.h +++ b/mono/utils/mono-hwcap-vars.h @@ -31,6 +31,22 @@ MONO_HWCAP_VAR(ppc_is_isa_64) MONO_HWCAP_VAR(ppc_has_move_fpr_gpr) MONO_HWCAP_VAR(ppc_has_multiple_ls_units) +#elif defined (TARGET_RISCV) + +MONO_HWCAP_VAR(riscv_has_stdext_a) +MONO_HWCAP_VAR(riscv_has_stdext_b) +MONO_HWCAP_VAR(riscv_has_stdext_c) +MONO_HWCAP_VAR(riscv_has_stdext_d) +MONO_HWCAP_VAR(riscv_has_stdext_f) +MONO_HWCAP_VAR(riscv_has_stdext_j) +MONO_HWCAP_VAR(riscv_has_stdext_l) +MONO_HWCAP_VAR(riscv_has_stdext_m) +MONO_HWCAP_VAR(riscv_has_stdext_n) +MONO_HWCAP_VAR(riscv_has_stdext_p) +MONO_HWCAP_VAR(riscv_has_stdext_q) +MONO_HWCAP_VAR(riscv_has_stdext_t) +MONO_HWCAP_VAR(riscv_has_stdext_v) + #elif defined (TARGET_S390X) MONO_HWCAP_VAR(s390x_has_fpe) diff --git a/mono/utils/mono-sigcontext.h b/mono/utils/mono-sigcontext.h index 04eab4ba910..f21598d6f03 100644 --- a/mono/utils/mono-sigcontext.h +++ b/mono/utils/mono-sigcontext.h @@ -533,4 +533,26 @@ typedef struct ucontext # define UCONTEXT_GREGS(ctx) (((ucontext_t *)(ctx))->uc_mcontext.gregs) #endif +#elif defined (TARGET_RISCV) + +#if defined(MONO_CROSS_COMPILE) + +#define UCONTEXT_GREGS(ctx) (NULL) +#define UCONTEXT_FREGS(ctx) (NULL) +#define UCONTEXT_REG_PC(ctx) (NULL) +#define UCONTEXT_REG_BP(ctx) (NULL) +#define UCONTEXT_REG_SP(ctx) (NULL) + +#else + +#include <ucontext.h> + +#define UCONTEXT_GREGS(ctx) (((ucontext_t *) (ctx))->uc_mcontext.gregs) +#define UCONTEXT_FREGS(ctx) (((ucontext_t *) (ctx))->uc_mcontext.fpregs) +#define UCONTEXT_REG_PC(ctx) (UCONTEXT_GREGS ((ctx)) [REG_PC]) +#define UCONTEXT_REG_BP(ctx) (UCONTEXT_GREGS ((ctx)) [REG_S0]) +#define UCONTEXT_REG_SP(ctx) (UCONTEXT_GREGS ((ctx)) [REG_SP]) + +#endif + #endif diff --git a/mono/utils/mono-tls.c b/mono/utils/mono-tls.c index 10c57b02801..8162e8a5704 100644 --- a/mono/utils/mono-tls.c +++ b/mono/utils/mono-tls.c @@ -152,6 +152,21 @@ : "=r" (foo) : : "1"); \ offset = foo; } while (0) # endif + +#elif defined (TARGET_RISCV) && !defined (PIC) + +#define MONO_THREAD_VAR_OFFSET(var, offset) \ + do { \ + guint32 temp; \ + __asm__ ( \ + "lui %0, %%tprel_hi(" #var ")\n" \ + "add %0, %0, tp, %%tprel_add(" #var ")\n" \ + "addi %0, %0, %%tprel_lo(" #var ")\n" \ + : "=r" (temp) \ + ); \ + offset = temp; \ + } while (0) + #else #define MONO_THREAD_VAR_OFFSET(var,offset) (offset) = -1 |