diff --git a/mk/cfg/mips64-unknown-linux-gnuabi64.mk b/mk/cfg/mips64-unknown-linux-gnuabi64.mk new file mode 100644 index 00000000000..34aee77ae21 --- /dev/null +++ b/mk/cfg/mips64-unknown-linux-gnuabi64.mk @@ -0,0 +1 @@ +# rustbuild-only target diff --git a/mk/cfg/mips64el-unknown-linux-gnuabi64.mk b/mk/cfg/mips64el-unknown-linux-gnuabi64.mk new file mode 100644 index 00000000000..34aee77ae21 --- /dev/null +++ b/mk/cfg/mips64el-unknown-linux-gnuabi64.mk @@ -0,0 +1 @@ +# rustbuild-only target diff --git a/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs b/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs new file mode 100644 index 00000000000..7e45b320653 --- /dev/null +++ b/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs @@ -0,0 +1,31 @@ +// 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, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + Ok(Target { + llvm_target: "mips64-unknown-linux-gnuabi64".to_string(), + target_endian: "big".to_string(), + target_pointer_width: "64".to_string(), + data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(), + arch: "mips64".to_string(), + target_os: "linux".to_string(), + target_env: "gnu".to_string(), + target_vendor: "unknown".to_string(), + options: TargetOptions { + // NOTE(mips64r2) matches C toolchain + cpu: "mips64r2".to_string(), + features: "+mips64r2".to_string(), + max_atomic_width: 64, + ..super::linux_base::opts() + }, + }) +} diff --git a/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs b/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs new file mode 100644 index 00000000000..338a5da1e1d --- /dev/null +++ b/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs @@ -0,0 +1,31 @@ +// 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, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + Ok(Target { + llvm_target: "mips64el-unknown-linux-gnuabi64".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "64".to_string(), + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(), + arch: "mips64".to_string(), + target_os: "linux".to_string(), + target_env: "gnu".to_string(), + target_vendor: "unknown".to_string(), + options: TargetOptions { + // NOTE(mips64r2) matches C toolchain + cpu: "mips64r2".to_string(), + features: "+mips64r2".to_string(), + max_atomic_width: 64, + ..super::linux_base::opts() + }, + }) +} diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 86cd86d282c..3c5ec84a8fa 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -128,6 +128,8 @@ supported_targets! { ("i686-unknown-linux-gnu", i686_unknown_linux_gnu), ("i586-unknown-linux-gnu", i586_unknown_linux_gnu), ("mips-unknown-linux-gnu", mips_unknown_linux_gnu), + ("mips64-unknown-linux-gnuabi64", mips64_unknown_linux_gnuabi64), + ("mips64el-unknown-linux-gnuabi64", mips64el_unknown_linux_gnuabi64), ("mipsel-unknown-linux-gnu", mipsel_unknown_linux_gnu), ("powerpc-unknown-linux-gnu", powerpc_unknown_linux_gnu), ("powerpc64-unknown-linux-gnu", powerpc64_unknown_linux_gnu), diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 3a7fde6a36b..5e264c80c4c 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -21,6 +21,7 @@ use cabi_aarch64; use cabi_powerpc; use cabi_powerpc64; use cabi_mips; +use cabi_mips64; use cabi_asmjs; use machine::{llalign_of_min, llsize_of, llsize_of_real, llsize_of_store}; use type_::Type; @@ -498,6 +499,7 @@ impl FnType { cabi_arm::compute_abi_info(ccx, self, flavor); }, "mips" => cabi_mips::compute_abi_info(ccx, self), + "mips64" => cabi_mips64::compute_abi_info(ccx, self), "powerpc" => cabi_powerpc::compute_abi_info(ccx, self), "powerpc64" => cabi_powerpc64::compute_abi_info(ccx, self), "asmjs" => cabi_asmjs::compute_abi_info(ccx, self), diff --git a/src/librustc_trans/cabi_mips64.rs b/src/librustc_trans/cabi_mips64.rs new file mode 100644 index 00000000000..d3d3f83eac4 --- /dev/null +++ b/src/librustc_trans/cabi_mips64.rs @@ -0,0 +1,168 @@ +// 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. + +#![allow(non_upper_case_globals)] + +use libc::c_uint; +use std::cmp; +use llvm; +use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector}; +use abi::{ArgType, FnType}; +use context::CrateContext; +use type_::Type; + +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 => { + let len = ty.vector_length(); + let elt = ty.element_type(); + ty_align(elt) * len + } + _ => 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, offset: &mut usize) { + let orig_offset = *offset; + let size = ty_size(arg.ty) * 8; + let mut align = ty_align(arg.ty); + + align = cmp::min(cmp::max(align, 4), 8); + *offset = align_up_to(*offset, align); + *offset += align_up_to(size, align * 8) / 8; + + if !is_reg_ty(arg.ty) { + arg.cast = Some(struct_ty(ccx, arg.ty)); + arg.pad = padding_ty(ccx, align, orig_offset); + } else { + arg.extend_integer_width_to(64); + } +} + +fn is_reg_ty(ty: Type) -> bool { + return match ty.kind() { + Integer + | Pointer + | Float + | Double + | Vector => true, + _ => false + }; +} + +fn padding_ty(ccx: &CrateContext, align: usize, offset: usize) -> Option { + if ((align - 1 ) & offset) > 0 { + Some(Type::i32(ccx)) + } else { + None + } +} + +fn coerce_to_int(ccx: &CrateContext, size: usize) -> Vec { + let int_ty = Type::i32(ccx); + let mut args = Vec::new(); + + let mut n = size / 64; + while n > 0 { + args.push(int_ty); + n -= 1; + } + + let r = size % 64; + if r > 0 { + unsafe { + args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx(), r as c_uint))); + } + } + + args +} + +fn struct_ty(ccx: &CrateContext, ty: Type) -> Type { + let size = ty_size(ty) * 8; + Type::struct_(ccx, &coerce_to_int(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); + } + + let mut offset = if fty.ret.is_indirect() { 8 } else { 0 }; + for arg in &mut fty.args { + if arg.is_ignore() { continue; } + classify_arg_ty(ccx, arg, &mut offset); + } +} diff --git a/src/librustc_trans/cabi_powerpc.rs b/src/librustc_trans/cabi_powerpc.rs index efbdce67a8b..e05c31b1d88 100644 --- a/src/librustc_trans/cabi_powerpc.rs +++ b/src/librustc_trans/cabi_powerpc.rs @@ -28,11 +28,7 @@ fn align(off: usize, ty: Type) -> usize { fn ty_align(ty: Type) -> usize { match ty.kind() { - Integer => { - unsafe { - ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as usize) + 7) / 8 - } - } + Integer => ((ty.int_width() as usize) + 7) / 8, Pointer => 4, Float => 4, Double => 8, @@ -54,11 +50,7 @@ fn ty_align(ty: Type) -> usize { fn ty_size(ty: Type) -> usize { match ty.kind() { - Integer => { - unsafe { - ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as usize) + 7) / 8 - } - } + Integer => ((ty.int_width() as usize) + 7) / 8, Pointer => 4, Float => 4, Double => 8, diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 1286df7b97e..6ede55d5ff4 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -98,6 +98,7 @@ mod cabi_aarch64; mod cabi_arm; mod cabi_asmjs; mod cabi_mips; +mod cabi_mips64; mod cabi_powerpc; mod cabi_powerpc64; mod cabi_x86;