Skip to content

Commit

Permalink
[SOL] Make SBF target specific adjustments
Browse files Browse the repository at this point in the history
  • Loading branch information
dmakarov authored and LucasSte committed Jul 22, 2024
1 parent 9dd4dbf commit 82f3f95
Show file tree
Hide file tree
Showing 10 changed files with 284 additions and 6 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ jobs:
- target: powerpc64le-unknown-linux-gnu
os: ubuntu-latest
rust: nightly
- target: sbf-solana-solana
os: ubuntu-latest
rust: nightly
- target: thumbv6m-none-eabi
os: ubuntu-latest
rust: nightly
Expand Down Expand Up @@ -97,6 +100,7 @@ jobs:
run: rustup update ${{ matrix.rust }} --no-self-update && rustup default ${{ matrix.rust }}
shell: bash
- run: rustup target add ${{ matrix.target }}
if: matrix.target != 'sbf-solana-solana'
- run: rustup component add llvm-tools-preview
- name: Download compiler-rt reference sources
run: |
Expand Down
19 changes: 19 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ fn main() {
|| target.contains("i686")
|| target.contains("aarch64")
|| target.contains("bpf")
|| target.contains("sbf")
{
println!("cargo:rustc-cfg=feature=\"mem-unaligned\"");
}
Expand Down Expand Up @@ -272,6 +273,7 @@ mod c {
let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap();
let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap();
let target_feature = env::var("CARGO_CFG_TARGET_FEATURE").unwrap_or_default();
let mut consider_float_intrinsics = true;
let cfg = &mut cc::Build::new();

Expand Down Expand Up @@ -625,6 +627,23 @@ mod c {
sources.extend(&[("__emutls_get_address", "emutls.c")]);
}

if target_os == "solana" {
cfg.define("__ELF__", None);
// Use the static-syscall target feature to detect if we're
// compiling for sbfv2, in which case set the corresponding clang
// cpu flag.
if target_feature.contains("static-syscalls") {
cfg.flag("-mcpu=sbfv2");
}
// Remove the implementations that fail to build.
// This list should shrink to zero
sources.remove(&[
"__int_util", // Unsupported architecture error
"__mulvdi3", // Unsupported signed division
"__mulvsi3", // Unsupported signed division
]);
}

// When compiling the C code we require the user to tell us where the
// source code is, and this is largely done so when we're compiling as
// part of rust-lang/rust we can use the same llvm-project repository as
Expand Down
23 changes: 23 additions & 0 deletions ci/docker/sbf-solana-solana/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
FROM ubuntu:20.04
RUN apt-get update && \
apt-get install -y --no-install-recommends \
curl \
gcc libc6-dev ca-certificates

ENV RUSTUP_INIT_SKIP_PATH_CHECK="yes"
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -v --no-modify-path
RUN cp ${HOME}/.cargo/bin/* /usr/local/bin/

RUN cargo install --git https://github.com/solana-labs/cargo-run-solana-tests.git \
--rev df2f642924aee7bbd2566017b3d71cb0c389b015 \
--bin cargo-run-solana-tests --root /usr/local

RUN mkdir -p /tmp/.cache/solana/v1.38/platform-tools
RUN curl -L -o platform-tools-linux-x86_64.tar.bz2 https://github.com/solana-labs/platform-tools/releases/download/v1.38/platform-tools-linux-x86_64.tar.bz2
RUN tar -xjf platform-tools-linux-x86_64.tar.bz2 --strip-components 1 -C /tmp/.cache/solana/v1.38/platform-tools
RUN rustup toolchain link solana /tmp/.cache/solana/v1.38/platform-tools/rust
RUN cp -R ${HOME}/.rustup /tmp/

ENV CARGO_TARGET_SBF_SOLANA_SOLANA_RUNNER="cargo-run-solana-tests --heap-size 104857600"
ENV CC="/tmp/.cache/solana/v1.38/platform-tools/llvm/bin/clang"
ENV RUSTUP_TOOLCHAIN="solana"
7 changes: 6 additions & 1 deletion examples/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@

extern crate panic_handler;

#[cfg(all(not(thumb), not(windows), not(target_arch = "wasm32")))]
#[cfg(all(
not(thumb),
not(windows),
not(target_arch = "wasm32"),
not(target_os = "solana")
))]
#[link(name = "c")]
extern "C" {}

Expand Down
10 changes: 9 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#![cfg_attr(not(feature = "no-asm"), feature(global_asm))]
#![feature(cfg_target_has_atomic)]
#![feature(compiler_builtins)]
#![feature(core_ffi_c)]
#![cfg_attr(not(target_os = "solana"), feature(core_ffi_c))]
#![feature(core_intrinsics)]
#![feature(inline_const)]
#![feature(lang_items)]
Expand Down Expand Up @@ -78,4 +78,12 @@ pub mod x86;
#[cfg(target_arch = "x86_64")]
pub mod x86_64;

#[cfg(all(target_os = "solana", target_feature = "static-syscalls"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[linkage = "weak"]
pub unsafe extern "C" fn abort() -> ! {
let syscall: extern "C" fn() -> ! = core::mem::transmute(3069975057u64); // murmur32 hash of "abort"
syscall()
}

pub mod probestack;
210 changes: 210 additions & 0 deletions src/mem/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,22 @@ type c_int = i16;
#[cfg(not(target_pointer_width = "16"))]
type c_int = i32;

#[cfg(not(target_os = "solana"))]
use core::intrinsics::{atomic_load_unordered, atomic_store_unordered, exact_div};
#[cfg(not(target_os = "solana"))]
use core::mem;
#[cfg(not(target_os = "solana"))]
use core::ops::{BitOr, Shl};

// memcpy/memmove/memset have optimized implementations on some architectures
#[cfg(not(target_os = "solana"))]
#[cfg_attr(
all(not(feature = "no-asm"), target_arch = "x86_64"),
path = "x86_64.rs"
)]
mod impls;

#[cfg(not(target_os = "solana"))]
intrinsics! {
#[mem_builtin]
pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 {
Expand Down Expand Up @@ -62,6 +67,7 @@ intrinsics! {
}

// `bytes` must be a multiple of `mem::size_of::<T>()`
#[cfg(not(target_os = "solana"))]
#[cfg_attr(not(target_has_atomic_load_store = "8"), allow(dead_code))]
fn memcpy_element_unordered_atomic<T: Copy>(dest: *mut T, src: *const T, bytes: usize) {
unsafe {
Expand All @@ -75,6 +81,7 @@ fn memcpy_element_unordered_atomic<T: Copy>(dest: *mut T, src: *const T, bytes:
}

// `bytes` must be a multiple of `mem::size_of::<T>()`
#[cfg(not(target_os = "solana"))]
#[cfg_attr(not(target_has_atomic_load_store = "8"), allow(dead_code))]
fn memmove_element_unordered_atomic<T: Copy>(dest: *mut T, src: *const T, bytes: usize) {
unsafe {
Expand All @@ -98,6 +105,7 @@ fn memmove_element_unordered_atomic<T: Copy>(dest: *mut T, src: *const T, bytes:
}

// `T` must be a primitive integer type, and `bytes` must be a multiple of `mem::size_of::<T>()`
#[cfg(not(target_os = "solana"))]
#[cfg_attr(not(target_has_atomic_load_store = "8"), allow(dead_code))]
fn memset_element_unordered_atomic<T>(s: *mut T, c: u8, bytes: usize)
where
Expand All @@ -124,6 +132,7 @@ where
}
}

#[cfg(not(target_os = "solana"))]
intrinsics! {
#[cfg(target_has_atomic_load_store = "8")]
pub unsafe extern "C" fn __llvm_memcpy_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () {
Expand Down Expand Up @@ -188,3 +197,204 @@ intrinsics! {
memset_element_unordered_atomic(s, c, bytes);
}
}

// MEM functions have been rewritten to copy 8 byte chunks. No
// compensation for alignment is made here with the requirement that
// the underlying hardware supports unaligned loads/stores. If the
// number of store operations is greater than 8 the memory operation
// is performed in the run-time system instead, by calling the
// corresponding "C" function.

#[cfg(all(target_os = "solana", not(target_feature = "static-syscalls")))]
mod syscalls {
extern "C" {
pub fn sol_memcpy_(dest: *mut u8, src: *const u8, n: u64);
pub fn sol_memmove_(dest: *mut u8, src: *const u8, n: u64);
pub fn sol_memset_(s: *mut u8, c: u8, n: u64);
pub fn sol_memcmp_(s1: *const u8, s2: *const u8, n: u64, result: *mut i32);
}
}

#[cfg(all(target_os = "solana", target_feature = "static-syscalls"))]
mod syscalls {
pub(crate) fn sol_memcpy_(dest: *mut u8, src: *const u8, n: u64) {
let syscall: extern "C" fn(*mut u8, *const u8, u64) =
unsafe { core::mem::transmute(1904002211u64) }; // murmur32 hash of "sol_memcpy_"
syscall(dest, src, n)
}

pub(crate) fn sol_memmove_(dest: *mut u8, src: *const u8, n: u64) {
let syscall: extern "C" fn(*mut u8, *const u8, u64) =
unsafe { core::mem::transmute(1128493560u64) }; // murmur32 hash of "sol_memmove_"
syscall(dest, src, n)
}

pub(crate) fn sol_memcmp_(dest: *const u8, src: *const u8, n: u64, result: *mut i32) {
let syscall: extern "C" fn(*const u8, *const u8, u64, *mut i32) =
unsafe { core::mem::transmute(1608310321u64) }; // murmur32 hash of "sol_memcmp_"
syscall(dest, src, n, result)
}

pub(crate) fn sol_memset_(dest: *mut u8, c: u8, n: u64) {
let syscall: extern "C" fn(*mut u8, u8, u64) =
unsafe { core::mem::transmute(930151202u64) }; // murmur32 hash of "sol_memset_"
syscall(dest, c, n)
}
}

#[cfg(target_os = "solana")]
use self::syscalls::*;

#[cfg(target_os = "solana")]
const NSTORE_THRESHOLD: usize = 15;

#[cfg(target_os = "solana")]
#[cfg_attr(
all(feature = "mem-unaligned", not(feature = "mangled-names")),
no_mangle
)]
#[inline]
pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 {
let chunks = (n / 8) as isize;
let nstore = n - (7 * chunks) as usize;
if nstore > NSTORE_THRESHOLD {
sol_memcpy_(dest, src, n as u64);
return dest;
}
let mut i: isize = 0;
if chunks != 0 {
let dest_64 = dest as *mut _ as *mut u64;
let src_64 = src as *const _ as *const u64;
while i < chunks {
*dest_64.offset(i) = *src_64.offset(i);
i += 1;
}
i *= 8;
}
while i < n as isize {
*dest.offset(i) = *src.offset(i);
i += 1;
}
dest
}

#[cfg(target_os = "solana")]
#[cfg_attr(
all(feature = "mem-unaligned", not(feature = "mangled-names")),
no_mangle
)]
#[inline]
pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 {
let chunks = (n / 8) as isize;
let nstore = n - (7 * chunks) as usize;
if nstore > NSTORE_THRESHOLD {
sol_memmove_(dest, src, n as u64);
return dest;
}
if src < dest as *const u8 {
// copy from end
let mut i = n as isize;
while i > chunks * 8 {
i -= 1;
*dest.offset(i) = *src.offset(i);
}
i = chunks;
if i > 0 {
let dest_64 = dest as *mut _ as *mut u64;
let src_64 = src as *const _ as *const u64;
while i > 0 {
i -= 1;
*dest_64.offset(i) = *src_64.offset(i);
}
}
} else {
// copy from beginning
let mut i: isize = 0;
if chunks != 0 {
let dest_64 = dest as *mut _ as *mut u64;
let src_64 = src as *const _ as *const u64;
while i < chunks {
*dest_64.offset(i) = *src_64.offset(i);
i += 1;
}
i *= 8;
}
while i < n as isize {
*dest.offset(i) = *src.offset(i);
i += 1;
}
}
dest
}

#[cfg(target_os = "solana")]
#[cfg_attr(
all(feature = "mem-unaligned", not(feature = "mangled-names")),
no_mangle
)]
#[inline]
pub unsafe extern "C" fn memset(s: *mut u8, c: c_int, n: usize) -> *mut u8 {
let chunks = (n / 8) as isize;
let nstore = n - (7 * chunks) as usize;
if nstore > NSTORE_THRESHOLD {
sol_memset_(s, c as u8, n as u64);
return s;
}
let mut i: isize = 0;
if chunks != 0 {
let mut c_64 = c as u64 & 0xFF as u64;
c_64 |= c_64 << 8;
c_64 |= c_64 << 16;
c_64 |= c_64 << 32;
let s_64 = s as *mut _ as *mut u64;
while i < chunks {
*s_64.offset(i) = c_64;
i += 1;
}
i *= 8;
}
while i < n as isize {
*s.offset(i) = c as u8;
i += 1;
}
s
}

#[cfg(target_os = "solana")]
#[cfg_attr(
all(feature = "mem-unaligned", not(feature = "mangled-names")),
no_mangle
)]
#[inline]
pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 {
let chunks = (n / 8) as isize;
let nstore = n - (7 * chunks) as usize;
if nstore > NSTORE_THRESHOLD {
let mut result = 0;
sol_memcmp_(s1, s2, n as u64, &mut result as *mut i32);
return result;
}
let mut i: isize = 0;
if chunks != 0 {
let s1_64 = s1 as *const _ as *const u64;
let s2_64 = s2 as *const _ as *const u64;
while i < chunks {
let a = *s1_64.offset(i);
let b = *s2_64.offset(i);
if a != b {
break;
}
i += 1;
}
i *= 8;
}
while i < n as isize {
let a = *s1.offset(i);
let b = *s2.offset(i);
if a != b {
return a as i32 - b as i32;
}
i += 1;
}
0
}
3 changes: 2 additions & 1 deletion testcrate/tests/conv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ macro_rules! i_to_f {
if f0 != f1 && !cfg!(any(
target_arch = "x86",
target_arch = "powerpc",
target_arch = "powerpc64"
target_arch = "powerpc64",
target_family = "solana"
)) {
panic!(
"{}({}): std: {}, builtins: {}",
Expand Down
5 changes: 4 additions & 1 deletion testcrate/tests/div_rem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,10 @@ macro_rules! float {
};
}

#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))]
#[cfg(not(any(
all(target_arch = "x86", not(target_feature = "sse")),
target_family = "solana"
)))]
#[test]
fn float_div() {
use compiler_builtins::float::{
Expand Down
Loading

0 comments on commit 82f3f95

Please sign in to comment.