Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial support for RISC-V #56105

Merged
merged 1 commit into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion Make.inc
Original file line number Diff line number Diff line change
Expand Up @@ -938,8 +938,12 @@ endif

#If nothing is set default to native unless we are cross-compiling
ifeq ($(MARCH)$(MCPU)$(MTUNE)$(JULIA_CPU_TARGET)$(XC_HOST),)
ifeq ($(ARCH),aarch64) #ARM recommends only setting MCPU for AArch64
ifeq ($(ARCH),aarch64)
# ARM recommends only setting MCPU for AArch64
MCPU=native
else ifneq (,$(findstring riscv64,$(ARCH)))
# RISC-V doesn't have a native option
$(error Building for RISC-V requires a specific MARCH to be set))
else
MARCH=native
MTUNE=native
Expand Down Expand Up @@ -995,6 +999,9 @@ endif
ifneq (,$(findstring arm,$(ARCH)))
DIST_ARCH:=arm
endif
ifneq (,$(findstring riscv64,$(ARCH)))
DIST_ARCH:=riscv64
endif

JULIA_BINARYDIST_FILENAME := julia-$(JULIA_COMMIT)-$(DIST_OS)$(DIST_ARCH)
endif
Expand All @@ -1018,8 +1025,12 @@ ifneq ($(MARCH),)
CC += -march=$(MARCH)
CXX += -march=$(MARCH)
FC += -march=$(MARCH)
# On RISC-V, don't forward the MARCH ISA string to JULIA_CPU_TARGET,
# as it's always incompatible with LLVM's CPU target name parser.
ifeq (,$(findstring riscv64,$(ARCH)))
JULIA_CPU_TARGET ?= $(MARCH)
endif
endif

# Set MCPU-specific flags
ifneq ($(MCPU),)
Expand Down
5 changes: 4 additions & 1 deletion base/binaryplatforms.jl
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,7 @@ const arch_mapping = Dict(
"armv7l" => "arm(v7l)?", # if we just see `arm-linux-gnueabihf`, we assume it's `armv7l`
"armv6l" => "armv6l",
"powerpc64le" => "p(ower)?pc64le",
"riscv64" => "riscv64",
"riscv64" => "(rv64|riscv64)",
)
# Keep this in sync with `CPUID.ISAs_by_family`
# These are the CPUID side of the microarchitectures targeted by GCC flags in BinaryBuilder.jl
Expand Down Expand Up @@ -631,6 +631,9 @@ const arch_march_isa_mapping = let
"a64fx" => get_set("aarch64", "a64fx"),
"apple_m1" => get_set("aarch64", "apple_m1"),
],
"riscv64" => [
"riscv64" => get_set("riscv64", "riscv64")
],
"powerpc64le" => [
"power8" => get_set("powerpc64le", "power8"),
],
Expand Down
3 changes: 3 additions & 0 deletions base/cpuid.jl
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ const ISAs_by_family = Dict(
"a64fx" => ISA(Set((JL_AArch64_v8_2a, JL_AArch64_lse, JL_AArch64_crc, JL_AArch64_rdm, JL_AArch64_sha2, JL_AArch64_ccpp, JL_AArch64_complxnum, JL_AArch64_fullfp16, JL_AArch64_sve))),
"apple_m1" => ISA(Set((JL_AArch64_v8_5a, JL_AArch64_lse, JL_AArch64_crc, JL_AArch64_rdm, JL_AArch64_aes, JL_AArch64_sha2, JL_AArch64_sha3, JL_AArch64_ccpp, JL_AArch64_complxnum, JL_AArch64_fp16fml, JL_AArch64_fullfp16, JL_AArch64_dotprod, JL_AArch64_rcpc, JL_AArch64_altnzcv))),
],
"riscv64" => [
"riscv64" => ISA(Set{UInt32}()),
],
"powerpc64le" => [
# We have no way to test powerpc64le features yet, so we're only going to declare the lowest ISA:
"power8" => ISA(Set{UInt32}()),
Expand Down
20 changes: 20 additions & 0 deletions cli/trampolines/trampolines_riscv64.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// This file is a part of Julia. License is MIT: https://julialang.org/license

#include "common.h"
#include "../../src/jl_exported_funcs.inc"

#define SEP ;

#define XX(name) \
.global CNAME(name) SEP \
.cfi_startproc SEP \
.p2align 2 SEP \
CNAME(name)##: SEP \
auipc t3, %pcrel_hi(CNAMEADDR(name)) SEP \
ld t3, %pcrel_lo(CNAME(name))(t3) SEP \
jr t3 SEP \
.cfi_endproc SEP \

JL_RUNTIME_EXPORTED_FUNCS(XX)
JL_CODEGEN_EXPORTED_FUNCS(XX)
#undef XX
9 changes: 6 additions & 3 deletions contrib/generate_precompile.jl
Original file line number Diff line number Diff line change
Expand Up @@ -202,12 +202,15 @@ if Artifacts !== nothing
using Artifacts, Base.BinaryPlatforms, Libdl
artifacts_toml = abspath(joinpath(Sys.STDLIB, "Artifacts", "test", "Artifacts.toml"))
artifact_hash("HelloWorldC", artifacts_toml)
oldpwd = pwd(); cd(dirname(artifacts_toml))
macroexpand(Main, :(@artifact_str("HelloWorldC")))
cd(oldpwd)
artifacts = Artifacts.load_artifacts_toml(artifacts_toml)
platforms = [Artifacts.unpack_platform(e, "HelloWorldC", artifacts_toml) for e in artifacts["HelloWorldC"]]
best_platform = select_platform(Dict(p => triplet(p) for p in platforms))
if best_platform !== nothing
# @artifact errors for unsupported platforms
oldpwd = pwd(); cd(dirname(artifacts_toml))
macroexpand(Main, :(@artifact_str("HelloWorldC")))
cd(oldpwd)
end
dlopen("libjulia$(Base.isdebugbuild() ? "-debug" : "")", RTLD_LAZY | RTLD_DEEPBIND)
"""
end
Expand Down
1 change: 1 addition & 0 deletions contrib/normalize_triplet.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
'i686': "i\\d86",
'aarch64': "(arm|aarch)64",
'armv7l': "arm(v7l)?",
'riscv64': "(rv64|riscv64)",
'powerpc64le': "p(ower)?pc64le",
}
platform_mapping = {
Expand Down
1 change: 1 addition & 0 deletions doc/src/devdocs/build/build.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ Notes for various operating systems:
Notes for various architectures:

* [ARM](https://github.com/JuliaLang/julia/blob/master/doc/src/devdocs/build/arm.md)
* [RISC-V](https://github.com/JuliaLang/julia/blob/master/doc/src/devdocs/build/riscv.md)

## Required Build Tools and External Libraries

Expand Down
103 changes: 103 additions & 0 deletions doc/src/devdocs/build/riscv.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# RISC-V (Linux)

Julia has experimental support for 64-bit RISC-V (RV64) processors running
Linux. This file provides general guidelines for compilation, in addition to
instructions for specific devices.

A list of [known issues](https://github.com/JuliaLang/julia/labels/system:riscv)
for RISC-V is available. If you encounter difficulties, please create an issue
including the output from `cat /proc/cpuinfo`.


## Compiling Julia

For now, Julia will need to be compiled entirely from source, i.e., including
all of its dependencies. This can be accomplished with the following
`Make.user`:

```make
USE_BINARYBUILDER := 0
```

Additionally, it is required to indicate what architecture, and optionally which
CPU to build for. This can be done by setting the `MARCH` and `MCPU` variables
in `Make.user`

The `MARCH` variable needs to be set to a RISC-V ISA string, which can be found by
looking at the documentation of your device, or by inspecting `/proc/cpuinfo`. Only
use flags that your compiler supports, e.g., run `gcc -march=help` to see a list of
supported flags. A common value is `rv64gc`, which is a good starting point.

The `MCPU` variable is optional, and can be used to further optimize the
generated code for a specific CPU. If you are unsure, it is recommended to leave
it unset. You can find a list of supported values by running `gcc --target-help`.

For example, if you are using a StarFive VisionFive2, which contains a JH7110
processor based on the SiFive U74, you can set these flags as follows:

```make
MARCH := rv64gc_zba_zbb
MCPU := sifive-u74
```

If you prefer a portable build, you could use:

```make
MARCH := rv64gc

# also set JULIA_CPU_TARGET to the expanded form of rv64gc
# (it normally copies the value of MCPU, which we don't set)
JULIA_CPU_TARGET := generic-rv64,i,m,a,f,d,zicsr,zifencei,c
```

### Cross-compilation

A native build on a RISC-V device may take a very long time, so it's also
possible to cross-compile Julia on a faster machine.

First, get a hold of a RISC-V cross-compilation toolchain that provides
support for C, C++ and Fortran. This can be done by checking-out the
[riscv-gnu-toolchain](https://github.com/riscv-collab/riscv-gnu-toolchain)
repository and building it as follows:

```sh
sudo mkdir /opt/riscv && sudo chown $USER /opt/riscv
./configure --prefix=/opt/riscv --with-languages=c,c++,fortran
make linux -j$(nproc)
```

Then, install the QEMU user-mode emulator for RISC-V, along with `binfmt`
support to enable execution of RISC-V binaries on the host machine. The
exact steps depend on your distribution, e.g., on Arch Linux it involves
installing the `qemu-user-static` and `qemu-user-static-binfmt` packages.
Note that to actually execute RISC-V binaries, QEMU will need to be able to
find the RISC-V system root, which can be achieved by setting the
`QEMU_LD_PREFIX` environment variable to the path of the root filesystem.

Finally, compile Julia with the following `Make.user` variables (in addition to
the ones from the previous section):

```make
XC_HOST=riscv64-unknown-linux-gnu
OS=Linux
export QEMU_LD_PREFIX=/opt/riscv/sysroot
```

Note that you will have to execute `make` with `PATH` set to include the
cross-compilation toolchain, e.g., by running:

```sh
PATH=/opt/riscv/bin:$PATH make -j$(nproc)
```

Because of the RISC-V sysroot we use being very barren, you may need to
add additional libraries that the Julia build system currently expects
to be available system-wide. For example, the build currently relies on
a system-provided `libz`, so you may need to copy this library from the
Julia build into the system root:

```sh
make -C deps install-zlib
cp -v usr/lib/libz.* /opt/riscv/sysroot/usr/lib
cp -v usr/include/z*.h /opt/riscv/sysroot/usr/include
```
Loading