Skip to content

Commit

Permalink
Add s390x support
Browse files Browse the repository at this point in the history
This adds support for building the Rust compiler and standard
library for s390x-linux, allowing a full cross-bootstrap sequence
to complete.  This includes:

- Makefile/configure changes to allow native s390x builds
- Full Rust compiler support for the s390x C ABI
  (only the non-vector ABI is supported at this point)
- Port of the standard library to s390x
- Update the liblibc submodule to a version including s390x support
- Testsuite fixes to allow clean "make check" on s390x

Caveats:

- Resets base cpu to "z10" to bring support in sync with the default
  behaviour of other compilers on the platforms.  (Usually, upstream
  supports all older processors; a distribution build may then chose
  to require a more recent base version.)  (Also, using zEC12 causes
  failures in the valgrind tests since valgrind doesn't fully support
  this CPU yet.)

- z13 vector ABI is not yet supported.  To ensure compatible code
  generation, the -vector feature is passed to LLVM.  Note that this
  means that even when compiling for z13, no vector instructions
  will be used.  In the future, support for the vector ABI should be
  added (this will require common code support for different ABIs
  that need different data_layout strings on the same platform).

- Two test cases are (temporarily) ignored on s390x to allow passing
  the test suite.  The underlying issues still need to be fixed:
  * debuginfo/simd.rs fails because of incorrect debug information.
    This seems to be a LLVM bug (also seen with C code).
  * run-pass/union/union-basic.rs simply seems to be incorrect for
    all big-endian platforms.

Signed-off-by: Ulrich Weigand <ulrich.weigand@de.ibm.com>
  • Loading branch information
uweigand committed Sep 9, 2016
1 parent f1f40f8 commit 19b8408
Show file tree
Hide file tree
Showing 26 changed files with 253 additions and 14 deletions.
4 changes: 4 additions & 0 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,10 @@ case $CFG_CPUTYPE in
CFG_CPUTYPE=powerpc64le
;;

s390x)
CFG_CPUTYPE=s390x
;;

x86_64 | x86-64 | x64 | amd64)
CFG_CPUTYPE=x86_64
;;
Expand Down
25 changes: 24 additions & 1 deletion mk/cfg/s390x-unknown-linux-gnu.mk
Original file line number Diff line number Diff line change
@@ -1 +1,24 @@
# rustbuild-only target
# s390x-unknown-linux-gnu configuration
CROSS_PREFIX_s390x-unknown-linux-gnu=s390x-linux-gnu-
CC_s390x-unknown-linux-gnu=$(CC)
CXX_s390x-unknown-linux-gnu=$(CXX)
CPP_s390x-unknown-linux-gnu=$(CPP)
AR_s390x-unknown-linux-gnu=$(AR)
CFG_LIB_NAME_s390x-unknown-linux-gnu=lib$(1).so
CFG_STATIC_LIB_NAME_s390x-unknown-linux-gnu=lib$(1).a
CFG_LIB_GLOB_s390x-unknown-linux-gnu=lib$(1)-*.so
CFG_LIB_DSYM_GLOB_s390x-unknown-linux-gnu=lib$(1)-*.dylib.dSYM
CFG_CFLAGS_s390x-unknown-linux-gnu := -m64 $(CFLAGS)
CFG_GCCISH_CFLAGS_s390x-unknown-linux-gnu := -g -fPIC -m64 $(CFLAGS)
CFG_GCCISH_CXXFLAGS_s390x-unknown-linux-gnu := -fno-rtti $(CXXFLAGS)
CFG_GCCISH_LINK_FLAGS_s390x-unknown-linux-gnu := -shared -fPIC -ldl -pthread -lrt -g -m64
CFG_GCCISH_DEF_FLAG_s390x-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list=
CFG_LLC_FLAGS_s390x-unknown-linux-gnu :=
CFG_INSTALL_NAME_s390x-unknown-linux-gnu =
CFG_EXE_SUFFIX_s390x-unknown-linux-gnu =
CFG_WINDOWSY_s390x-unknown-linux-gnu :=
CFG_UNIXY_s390x-unknown-linux-gnu := 1
CFG_LDPATH_s390x-unknown-linux-gnu :=
CFG_RUN_s390x-unknown-linux-gnu=$(2)
CFG_RUN_TARG_s390x-unknown-linux-gnu=$(call CFG_RUN_s390x-unknown-linux-gnu,,$(2))
CFG_GNU_TRIPLE_s390x-unknown-linux-gnu := s390x-unknown-linux-gnu
3 changes: 2 additions & 1 deletion src/liballoc_jemalloc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ const MIN_ALIGN: usize = 8;
target_arch = "x86_64",
target_arch = "aarch64",
target_arch = "powerpc64",
target_arch = "mips64")))]
target_arch = "mips64",
target_arch = "s390x")))]
const MIN_ALIGN: usize = 16;

// MALLOCX_ALIGN(a) macro
Expand Down
3 changes: 2 additions & 1 deletion src/liballoc_system/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@
const MIN_ALIGN: usize = 8;
#[cfg(all(any(target_arch = "x86_64",
target_arch = "aarch64",
target_arch = "mips64")))]
target_arch = "mips64",
target_arch = "s390x")))]
const MIN_ALIGN: usize = 16;

#[no_mangle]
Expand Down
3 changes: 3 additions & 0 deletions src/libpanic_unwind/gcc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ const UNWIND_DATA_REG: (i32, i32) = (4, 5); // A0, A1
#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
const UNWIND_DATA_REG: (i32, i32) = (3, 4); // R3, R4 / X3, X4

#[cfg(target_arch = "s390x")]
const UNWIND_DATA_REG: (i32, i32) = (6, 7); // R6, R7

// The following code is based on GCC's C and C++ personality routines. For reference, see:
// https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_personality.cc
// https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c
Expand Down
8 changes: 6 additions & 2 deletions src/librustc_back/target/s390x_unknown_linux_gnu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,12 @@ use target::{Target, TargetResult};

pub fn target() -> TargetResult {
let mut base = super::linux_base::opts();
// NOTE(zEC12) matches C toolchain
base.cpu = "zEC12".to_string();
// z10 is the oldest CPU supported by LLVM
base.cpu = "z10".to_string();
// FIXME: The data_layout string below and the ABI implementation in
// cabi_s390x.rs are for now hard-coded to assume the no-vector ABI.
// Pass the -vector feature string to LLVM to respect this assumption.
base.features = "-vector".to_string();
base.max_atomic_width = 64;

Ok(Target {
Expand Down
9 changes: 8 additions & 1 deletion src/librustc_trans/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use cabi_arm;
use cabi_aarch64;
use cabi_powerpc;
use cabi_powerpc64;
use cabi_s390x;
use cabi_mips;
use cabi_mips64;
use cabi_asmjs;
Expand Down Expand Up @@ -301,6 +302,9 @@ impl FnType {
let win_x64_gnu = target.target_os == "windows"
&& target.arch == "x86_64"
&& target.target_env == "gnu";
let linux_s390x = target.target_os == "linux"
&& target.arch == "s390x"
&& target.target_env == "gnu";
let rust_abi = match abi {
RustIntrinsic | PlatformIntrinsic | Rust | RustCall => true,
_ => false
Expand All @@ -326,7 +330,9 @@ impl FnType {
if llsize_of_real(ccx, arg.ty) == 0 {
// For some forsaken reason, x86_64-pc-windows-gnu
// doesn't ignore zero-sized struct arguments.
if is_return || rust_abi || !win_x64_gnu {
// The same is true for s390x-unknown-linux-gnu.
if is_return || rust_abi ||
(!win_x64_gnu && !linux_s390x) {
arg.ignore();
}
}
Expand Down Expand Up @@ -511,6 +517,7 @@ impl FnType {
"mips64" => cabi_mips64::compute_abi_info(ccx, self),
"powerpc" => cabi_powerpc::compute_abi_info(ccx, self),
"powerpc64" => cabi_powerpc64::compute_abi_info(ccx, self),
"s390x" => cabi_s390x::compute_abi_info(ccx, self),
"asmjs" => cabi_asmjs::compute_abi_info(ccx, self),
a => ccx.sess().fatal(&format!("unrecognized arch \"{}\" in target specification", a))
}
Expand Down
150 changes: 150 additions & 0 deletions src/librustc_trans/cabi_s390x.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// FIXME: The assumes we're using the non-vector ABI, i.e. compiling
// for a pre-z13 machine or using -mno-vx.

use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector};
use abi::{FnType, ArgType};
use context::CrateContext;
use type_::Type;

use std::cmp;

fn align_up_to(off: usize, a: usize) -> usize {
return (off + a - 1) / a * a;
}

fn align(off: usize, ty: Type) -> usize {
let a = ty_align(ty);
return align_up_to(off, a);
}

fn ty_align(ty: Type) -> usize {
match ty.kind() {
Integer => ((ty.int_width() as usize) + 7) / 8,
Pointer => 8,
Float => 4,
Double => 8,
Struct => {
if ty.is_packed() {
1
} else {
let str_tys = ty.field_types();
str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t)))
}
}
Array => {
let elt = ty.element_type();
ty_align(elt)
}
Vector => ty_size(ty),
_ => bug!("ty_align: unhandled type")
}
}

fn ty_size(ty: Type) -> usize {
match ty.kind() {
Integer => ((ty.int_width() as usize) + 7) / 8,
Pointer => 8,
Float => 4,
Double => 8,
Struct => {
if ty.is_packed() {
let str_tys = ty.field_types();
str_tys.iter().fold(0, |s, t| s + ty_size(*t))
} else {
let str_tys = ty.field_types();
let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t));
align(size, ty)
}
}
Array => {
let len = ty.array_length();
let elt = ty.element_type();
let eltsz = ty_size(elt);
len * eltsz
}
Vector => {
let len = ty.vector_length();
let elt = ty.element_type();
let eltsz = ty_size(elt);
len * eltsz
}
_ => bug!("ty_size: unhandled type")
}
}

fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
if is_reg_ty(ret.ty) {
ret.extend_integer_width_to(64);
} else {
ret.make_indirect(ccx);
}
}

fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
if arg.ty.kind() == Struct {
fn is_single_fp_element(tys: &[Type]) -> bool {
if tys.len() != 1 {
return false;
}
match tys[0].kind() {
Float | Double => true,
Struct => is_single_fp_element(&tys[0].field_types()),
_ => false
}
}

if is_single_fp_element(&arg.ty.field_types()) {
match ty_size(arg.ty) {
4 => arg.cast = Some(Type::f32(ccx)),
8 => arg.cast = Some(Type::f64(ccx)),
_ => arg.make_indirect(ccx)
}
} else {
match ty_size(arg.ty) {
1 => arg.cast = Some(Type::i8(ccx)),
2 => arg.cast = Some(Type::i16(ccx)),
4 => arg.cast = Some(Type::i32(ccx)),
8 => arg.cast = Some(Type::i64(ccx)),
_ => arg.make_indirect(ccx)
}
}
return;
}

if is_reg_ty(arg.ty) {
arg.extend_integer_width_to(64);
} else {
arg.make_indirect(ccx);
}
}

fn is_reg_ty(ty: Type) -> bool {
match ty.kind() {
Integer
| Pointer
| Float
| Double => ty_size(ty) <= 8,
_ => false
}
}

pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
if !fty.ret.is_ignore() {
classify_ret_ty(ccx, &mut fty.ret);
}

for arg in &mut fty.args {
if arg.is_ignore() { continue; }
classify_arg_ty(ccx, arg);
}
}
1 change: 1 addition & 0 deletions src/librustc_trans/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ mod cabi_mips;
mod cabi_mips64;
mod cabi_powerpc;
mod cabi_powerpc64;
mod cabi_s390x;
mod cabi_x86;
mod cabi_x86_64;
mod cabi_x86_win64;
Expand Down
6 changes: 6 additions & 0 deletions src/libstd/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,7 @@ pub mod consts {
/// - mips64
/// - powerpc
/// - powerpc64
/// - s390x
#[stable(feature = "env", since = "1.0.0")]
pub const ARCH: &'static str = super::arch::ARCH;

Expand Down Expand Up @@ -942,6 +943,11 @@ mod arch {
pub const ARCH: &'static str = "powerpc64";
}

#[cfg(target_arch = "s390x")]
mod arch {
pub const ARCH: &'static str = "s390x";
}

#[cfg(target_arch = "le32")]
mod arch {
pub const ARCH: &'static str = "le32";
Expand Down
5 changes: 5 additions & 0 deletions src/libstd/os/linux/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,11 @@ mod arch {
pub use libc::{off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t};
}

#[cfg(target_arch = "s390x")]
mod arch {
pub use libc::{off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t};
}

#[cfg(target_arch = "aarch64")]
mod arch {
use os::raw::{c_long, c_int};
Expand Down
6 changes: 4 additions & 2 deletions src/libstd/os/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,16 @@
all(target_os = "linux", any(target_arch = "aarch64",
target_arch = "arm",
target_arch = "powerpc",
target_arch = "powerpc64"))))]
target_arch = "powerpc64",
target_arch = "s390x"))))]
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8;
#[cfg(not(any(target_os = "android",
target_os = "emscripten",
all(target_os = "linux", any(target_arch = "aarch64",
target_arch = "arm",
target_arch = "powerpc",
target_arch = "powerpc64")))))]
target_arch = "powerpc64",
target_arch = "s390x")))))]
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8;
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_schar = i8;
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_uchar = u8;
Expand Down
14 changes: 10 additions & 4 deletions src/libstd/sys/unix/rand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,17 @@ mod imp {
target_arch = "arm",
target_arch = "aarch64",
target_arch = "powerpc",
target_arch = "powerpc64")))]
target_arch = "powerpc64",
target_arch = "s390x")))]
fn getrandom(buf: &mut [u8]) -> libc::c_long {
#[cfg(target_arch = "x86_64")]
const NR_GETRANDOM: libc::c_long = 318;
#[cfg(target_arch = "x86")]
const NR_GETRANDOM: libc::c_long = 355;
#[cfg(target_arch = "arm")]
const NR_GETRANDOM: libc::c_long = 384;
#[cfg(target_arch = "s390x")]
const NR_GETRANDOM: libc::c_long = 349;
#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
const NR_GETRANDOM: libc::c_long = 359;
#[cfg(target_arch = "aarch64")]
Expand All @@ -71,7 +74,8 @@ mod imp {
target_arch = "arm",
target_arch = "aarch64",
target_arch = "powerpc",
target_arch = "powerpc64"))))]
target_arch = "powerpc64",
target_arch = "s390x"))))]
fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }

fn getrandom_fill_bytes(v: &mut [u8]) {
Expand Down Expand Up @@ -110,7 +114,8 @@ mod imp {
target_arch = "arm",
target_arch = "aarch64",
target_arch = "powerpc",
target_arch = "powerpc64")))]
target_arch = "powerpc64",
target_arch = "s390x")))]
fn is_getrandom_available() -> bool {
use sync::atomic::{AtomicBool, Ordering};
use sync::Once;
Expand Down Expand Up @@ -139,7 +144,8 @@ mod imp {
target_arch = "arm",
target_arch = "aarch64",
target_arch = "powerpc",
target_arch = "powerpc64"))))]
target_arch = "powerpc64",
target_arch = "s390x"))))]
fn is_getrandom_available() -> bool { false }

pub struct OsRng {
Expand Down
3 changes: 3 additions & 0 deletions src/libunwind/libunwind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ pub const unwinder_private_data_size: usize = 2;
#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
pub const unwinder_private_data_size: usize = 2;

#[cfg(target_arch = "s390x")]
pub const unwinder_private_data_size: usize = 2;

#[cfg(target_arch = "asmjs")]
pub const unwinder_private_data_size: usize = 20;

Expand Down
1 change: 1 addition & 0 deletions src/test/compile-fail/asm-bad-clobber.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
// ignore-android
// ignore-arm
// ignore-aarch64
// ignore-s390x

#![feature(asm, rustc_attrs)]

Expand Down
Loading

0 comments on commit 19b8408

Please sign in to comment.