diff --git a/configure b/configure index 5094e5a764bdf..beb0a9d43a0cf 100755 --- a/configure +++ b/configure @@ -1822,7 +1822,7 @@ do CMAKE_ARGS="$CMAKE_ARGS -DLLVM_ENABLE_ASSERTIONS=ON" fi - CMAKE_ARGS="$CMAKE_ARGS -DLLVM_TARGETS_TO_BUILD='X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430'" + CMAKE_ARGS="$CMAKE_ARGS -DLLVM_TARGETS_TO_BUILD='X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430;Sparc'" CMAKE_ARGS="$CMAKE_ARGS -G '$CFG_CMAKE_GENERATOR'" CMAKE_ARGS="$CMAKE_ARGS $CFG_LLVM_SRC_DIR" diff --git a/mk/cfg/sparc64-unknown-netbsd.mk b/mk/cfg/sparc64-unknown-netbsd.mk new file mode 100644 index 0000000000000..a2b01ba0537c7 --- /dev/null +++ b/mk/cfg/sparc64-unknown-netbsd.mk @@ -0,0 +1,3 @@ +# This file is intentially left empty to indicate that, while this target is +# supported, it's not supported using plain GNU Make builds. Use a --rustbuild +# instead. diff --git a/mk/main.mk b/mk/main.mk index d01ec07b4244e..2c646450d018e 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -285,7 +285,7 @@ endif # LLVM macros ###################################################################### -LLVM_OPTIONAL_COMPONENTS=x86 arm aarch64 mips powerpc pnacl systemz jsbackend msp430 +LLVM_OPTIONAL_COMPONENTS=x86 arm aarch64 mips powerpc pnacl systemz jsbackend msp430 sparc LLVM_REQUIRED_COMPONENTS=ipo bitreader bitwriter linker asmparser mcjit \ interpreter instrumentation diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index 21e45f9c4b20c..f2df393ad777f 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -84,7 +84,8 @@ mod imp { target_arch = "aarch64", target_arch = "powerpc64", target_arch = "mips64", - target_arch = "s390x")))] + target_arch = "s390x", + target_arch = "sparc64")))] const MIN_ALIGN: usize = 16; // MALLOCX_ALIGN(a) macro diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index 4daa6cbb8465e..5f0b637656b7d 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -35,7 +35,8 @@ const MIN_ALIGN: usize = 8; #[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64", target_arch = "mips64", - target_arch = "s390x")))] + target_arch = "s390x", + target_arch = "sparc64")))] const MIN_ALIGN: usize = 16; #[no_mangle] diff --git a/src/libpanic_unwind/gcc.rs b/src/libpanic_unwind/gcc.rs index 73264fab69c26..e8b3a9a42c292 100644 --- a/src/libpanic_unwind/gcc.rs +++ b/src/libpanic_unwind/gcc.rs @@ -133,6 +133,9 @@ 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 +#[cfg(target_arch = "sparc64")] +const UNWIND_DATA_REG: (i32, i32) = (24, 25); // I0, I1 + // 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 diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 6a409edf0fecc..975bb6328c4e9 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -173,6 +173,7 @@ supported_targets! { ("i686-unknown-openbsd", i686_unknown_openbsd), ("x86_64-unknown-openbsd", x86_64_unknown_openbsd), + ("sparc64-unknown-netbsd", sparc64_unknown_netbsd), ("x86_64-unknown-netbsd", x86_64_unknown_netbsd), ("x86_64-rumprun-netbsd", x86_64_rumprun_netbsd), diff --git a/src/librustc_back/target/sparc64_unknown_netbsd.rs b/src/librustc_back/target/sparc64_unknown_netbsd.rs new file mode 100644 index 0000000000000..f30cebbc2d5a7 --- /dev/null +++ b/src/librustc_back/target/sparc64_unknown_netbsd.rs @@ -0,0 +1,30 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use target::{Target, TargetResult}; + +pub fn target() -> TargetResult { + let mut base = super::netbsd_base::opts(); + base.cpu = "v9".to_string(); + base.pre_link_args.push("-m64".to_string()); + base.max_atomic_width = Some(64); + + Ok(Target { + llvm_target: "sparc64-unknown-netbsd".to_string(), + target_endian: "big".to_string(), + target_pointer_width: "64".to_string(), + data_layout: "E-m:e-i64:64-n32:64-S128".to_string(), + arch: "sparc64".to_string(), + target_os: "netbsd".to_string(), + target_env: "".to_string(), + target_vendor: "unknown".to_string(), + options: base, + }) +} diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 81e4b4d1f21c7..121ad93a2ae10 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -25,6 +25,7 @@ use cabi_mips64; use cabi_asmjs; use cabi_msp430; use cabi_sparc; +use cabi_sparc64; use cabi_nvptx; use cabi_nvptx64; use machine::{llalign_of_min, llsize_of, llsize_of_alloc}; @@ -611,6 +612,7 @@ impl FnType { "wasm32" => cabi_asmjs::compute_abi_info(ccx, self), "msp430" => cabi_msp430::compute_abi_info(ccx, self), "sparc" => cabi_sparc::compute_abi_info(ccx, self), + "sparc64" => cabi_sparc64::compute_abi_info(ccx, self), "nvptx" => cabi_nvptx::compute_abi_info(ccx, self), "nvptx64" => cabi_nvptx64::compute_abi_info(ccx, self), a => ccx.sess().fatal(&format!("unrecognized arch \"{}\" in target specification", a)) diff --git a/src/librustc_trans/cabi_sparc64.rs b/src/librustc_trans/cabi_sparc64.rs new file mode 100644 index 0000000000000..e675cca33d1be --- /dev/null +++ b/src/librustc_trans/cabi_sparc64.rs @@ -0,0 +1,185 @@ +// Copyright 2014-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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// FIXME: This needs an audit for correctness and completeness. + +use llvm::{Integer, Pointer, Float, Double, Struct, Vector, Array}; +use abi::{self, FnType, ArgType}; +use context::CrateContext; +use type_::Type; + +fn ty_size(ty: Type) -> usize { + if ty.kind() == Vector { + bug!("ty_size: unhandled type") + } else { + abi::ty_size(ty, 8) + } +} + +fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> { + fn check_array(ty: Type) -> Option<(Type, u64)> { + let len = ty.array_length() as u64; + if len == 0 { + return None + } + let elt = ty.element_type(); + + // if our element is an HFA/HVA, so are we; multiply members by our len + is_homogenous_aggregate_ty(elt).map(|(base_ty, members)| (base_ty, len * members)) + } + + fn check_struct(ty: Type) -> Option<(Type, u64)> { + let str_tys = ty.field_types(); + if str_tys.len() == 0 { + return None + } + + let mut prev_base_ty = None; + let mut members = 0; + for opt_homog_agg in str_tys.iter().map(|t| is_homogenous_aggregate_ty(*t)) { + match (prev_base_ty, opt_homog_agg) { + // field isn't itself an HFA, so we aren't either + (_, None) => return None, + + // first field - store its type and number of members + (None, Some((field_ty, field_members))) => { + prev_base_ty = Some(field_ty); + members = field_members; + }, + + // 2nd or later field - give up if it's a different type; otherwise incr. members + (Some(prev_ty), Some((field_ty, field_members))) => { + if prev_ty != field_ty { + return None; + } + members += field_members; + } + } + } + + // Because of previous checks, we know prev_base_ty is Some(...) because + // 1. str_tys has at least one element; and + // 2. prev_base_ty was filled in (or we would've returned early) + let (base_ty, members) = (prev_base_ty.unwrap(), members); + + // Ensure there is no padding. + if ty_size(ty) == ty_size(base_ty) * (members as usize) { + Some((base_ty, members)) + } else { + None + } + } + + let homog_agg = match ty.kind() { + Float => Some((ty, 1)), + Double => Some((ty, 1)), + Array => check_array(ty), + Struct => check_struct(ty), + _ => None + }; + + // Ensure we have at most eight uniquely addressable members + homog_agg.and_then(|(base_ty, members)| { + if members > 0 && members <= 8 { + Some((base_ty, members)) + } else { + None + } + }) +} + +fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { + if is_reg_ty(ret.ty) { + ret.extend_integer_width_to(64); + return; + } + + // don't return aggregates in registers + ret.make_indirect(ccx); + + if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ret.ty) { + ret.cast = Some(Type::array(&base_ty, members)); + return; + } + let size = ty_size(ret.ty); + if size <= 16 { + let llty = if size <= 1 { + Type::i8(ccx) + } else if size <= 2 { + Type::i16(ccx) + } else if size <= 4 { + Type::i32(ccx) + } else if size <= 8 { + Type::i64(ccx) + } else { + Type::array(&Type::i64(ccx), ((size + 7 ) / 8 ) as u64) + }; + ret.cast = Some(llty); + return; + } +} + +fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) { + if is_reg_ty(arg.ty) { + arg.extend_integer_width_to(64); + return; + } + + if let Some((base_ty, members)) = is_homogenous_aggregate_ty(arg.ty) { + arg.cast = Some(Type::array(&base_ty, members)); + return; + } + + arg.cast = Some(struct_ty(ccx, arg.ty)); +} + +fn is_reg_ty(ty: Type) -> bool { + match ty.kind() { + Integer + | Pointer + | Float + | Double => true, + _ => false + } +} + +fn coerce_to_long(ccx: &CrateContext, size: usize) -> Vec { + let long_ty = Type::i64(ccx); + let mut args = Vec::new(); + + let mut n = size / 64; + while n > 0 { + args.push(long_ty); + n -= 1; + } + + let r = size % 64; + if r > 0 { + args.push(Type::ix(ccx, r as u64)); + } + + args +} + +fn struct_ty(ccx: &CrateContext, ty: Type) -> Type { + let size = ty_size(ty) * 8; + Type::struct_(ccx, &coerce_to_long(ccx, size), 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); + } +} diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 0d3e1853f011e..17a80835da1a8 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -109,6 +109,7 @@ mod cabi_powerpc; mod cabi_powerpc64; mod cabi_s390x; mod cabi_sparc; +mod cabi_sparc64; mod cabi_x86; mod cabi_x86_64; mod cabi_x86_win64; diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 0521f301321a7..d843d97420a18 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -712,6 +712,7 @@ pub mod consts { /// - powerpc /// - powerpc64 /// - s390x + /// - sparc64 #[stable(feature = "env", since = "1.0.0")] pub const ARCH: &'static str = super::arch::ARCH; @@ -843,6 +844,11 @@ mod arch { pub const ARCH: &'static str = "s390x"; } +#[cfg(target_arch = "sparc64")] +mod arch { + pub const ARCH: &'static str = "sparc64"; +} + #[cfg(target_arch = "le32")] mod arch { pub const ARCH: &'static str = "le32"; diff --git a/src/libunwind/libunwind.rs b/src/libunwind/libunwind.rs index bbac6c07c570a..269c2d65b6327 100644 --- a/src/libunwind/libunwind.rs +++ b/src/libunwind/libunwind.rs @@ -65,6 +65,9 @@ pub const unwinder_private_data_size: usize = 2; #[cfg(target_arch = "s390x")] pub const unwinder_private_data_size: usize = 2; +#[cfg(target_arch = "sparc64")] +pub const unwinder_private_data_size: usize = 2; + #[cfg(target_os = "emscripten")] pub const unwinder_private_data_size: usize = 20; diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index f71dac77caf09..7bc6e8b0ecb11 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -141,6 +141,12 @@ extern "C" void LLVMRustAddPass(LLVMPassManagerRef PM, LLVMPassRef rust_pass) { #define SUBTARGET_MSP430 #endif +#ifdef LLVM_COMPONENT_SPARC +#define SUBTARGET_SPARC SUBTARGET(Sparc) +#else +#define SUBTARGET_SPARC +#endif + #define GEN_SUBTARGETS \ SUBTARGET_X86 \ SUBTARGET_ARM \ @@ -148,7 +154,8 @@ extern "C" void LLVMRustAddPass(LLVMPassManagerRef PM, LLVMPassRef rust_pass) { SUBTARGET_MIPS \ SUBTARGET_PPC \ SUBTARGET_SYSTEMZ \ - SUBTARGET_MSP430 + SUBTARGET_MSP430 \ + SUBTARGET_SPARC #define SUBTARGET(x) \ namespace llvm { \