about summary refs log tree commit diff
path: root/src/librustc_target
diff options
context:
space:
mode:
authorIrina Popa <irinagpopa@gmail.com>2018-04-25 16:45:29 +0300
committerIrina Popa <irinagpopa@gmail.com>2018-04-26 16:50:31 +0300
commit030244cd4a76914af7dc2939ed1a16f394ceda48 (patch)
tree24e4a255042bf0d4f82f64e3e42810a6c02382d4 /src/librustc_target
parentfb15d447009f7b32cf435e0ad63bbbed5961e243 (diff)
downloadrust-030244cd4a76914af7dc2939ed1a16f394ceda48.tar.gz
rust-030244cd4a76914af7dc2939ed1a16f394ceda48.zip
rustc_target: move in cabi_* from rustc_trans.
Diffstat (limited to 'src/librustc_target')
-rw-r--r--src/librustc_target/abi/call.rs214
-rw-r--r--src/librustc_target/abi/call/aarch64.rs124
-rw-r--r--src/librustc_target/abi/call/arm.rs122
-rw-r--r--src/librustc_target/abi/call/asmjs.rs57
-rw-r--r--src/librustc_target/abi/call/hexagon.rs42
-rw-r--r--src/librustc_target/abi/call/mips.rs59
-rw-r--r--src/librustc_target/abi/call/mips64.rs166
-rw-r--r--src/librustc_target/abi/call/mod.rs511
-rw-r--r--src/librustc_target/abi/call/msp430.rs49
-rw-r--r--src/librustc_target/abi/call/nvptx.rs43
-rw-r--r--src/librustc_target/abi/call/nvptx64.rs43
-rw-r--r--src/librustc_target/abi/call/powerpc.rs59
-rw-r--r--src/librustc_target/abi/call/powerpc64.rs154
-rw-r--r--src/librustc_target/abi/call/s390x.rs87
-rw-r--r--src/librustc_target/abi/call/sparc.rs59
-rw-r--r--src/librustc_target/abi/call/sparc64.rs119
-rw-r--r--src/librustc_target/abi/call/wasm32.rs30
-rw-r--r--src/librustc_target/abi/call/x86.rs143
-rw-r--r--src/librustc_target/abi/call/x86_64.rs244
-rw-r--r--src/librustc_target/abi/call/x86_win64.rs51
20 files changed, 2162 insertions, 214 deletions
diff --git a/src/librustc_target/abi/call.rs b/src/librustc_target/abi/call.rs
deleted file mode 100644
index bea705b9ece..00000000000
--- a/src/librustc_target/abi/call.rs
+++ /dev/null
@@ -1,214 +0,0 @@
-// Copyright 2017 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.
-
-use abi::{Align, HasDataLayout, Size};
-
-#[derive(Clone, Copy, PartialEq, Eq, Debug)]
-pub enum PassMode {
-    /// Ignore the argument (useful for empty struct).
-    Ignore,
-    /// Pass the argument directly.
-    Direct(ArgAttributes),
-    /// Pass a pair's elements directly in two arguments.
-    Pair(ArgAttributes, ArgAttributes),
-    /// Pass the argument after casting it, to either
-    /// a single uniform or a pair of registers.
-    Cast(CastTarget),
-    /// Pass the argument indirectly via a hidden pointer.
-    Indirect(ArgAttributes),
-}
-
-// Hack to disable non_upper_case_globals only for the bitflags! and not for the rest
-// of this module
-pub use self::attr_impl::ArgAttribute;
-
-#[allow(non_upper_case_globals)]
-#[allow(unused)]
-mod attr_impl {
-    // The subset of llvm::Attribute needed for arguments, packed into a bitfield.
-    bitflags! {
-        #[derive(Default)]
-        pub struct ArgAttribute: u16 {
-            const ByVal     = 1 << 0;
-            const NoAlias   = 1 << 1;
-            const NoCapture = 1 << 2;
-            const NonNull   = 1 << 3;
-            const ReadOnly  = 1 << 4;
-            const SExt      = 1 << 5;
-            const StructRet = 1 << 6;
-            const ZExt      = 1 << 7;
-            const InReg     = 1 << 8;
-        }
-    }
-}
-
-/// A compact representation of LLVM attributes (at least those relevant for this module)
-/// that can be manipulated without interacting with LLVM's Attribute machinery.
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub struct ArgAttributes {
-    pub regular: ArgAttribute,
-    pub pointee_size: Size,
-    pub pointee_align: Option<Align>
-}
-
-impl ArgAttributes {
-    pub fn new() -> Self {
-        ArgAttributes {
-            regular: ArgAttribute::default(),
-            pointee_size: Size::from_bytes(0),
-            pointee_align: None,
-        }
-    }
-
-    pub fn set(&mut self, attr: ArgAttribute) -> &mut Self {
-        self.regular = self.regular | attr;
-        self
-    }
-
-    pub fn contains(&self, attr: ArgAttribute) -> bool {
-        self.regular.contains(attr)
-    }
-}
-
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub enum RegKind {
-    Integer,
-    Float,
-    Vector
-}
-
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub struct Reg {
-    pub kind: RegKind,
-    pub size: Size,
-}
-
-macro_rules! reg_ctor {
-    ($name:ident, $kind:ident, $bits:expr) => {
-        pub fn $name() -> Reg {
-            Reg {
-                kind: RegKind::$kind,
-                size: Size::from_bits($bits)
-            }
-        }
-    }
-}
-
-impl Reg {
-    reg_ctor!(i8, Integer, 8);
-    reg_ctor!(i16, Integer, 16);
-    reg_ctor!(i32, Integer, 32);
-    reg_ctor!(i64, Integer, 64);
-
-    reg_ctor!(f32, Float, 32);
-    reg_ctor!(f64, Float, 64);
-}
-
-impl Reg {
-    pub fn align<C: HasDataLayout>(&self, cx: C) -> Align {
-        let dl = cx.data_layout();
-        match self.kind {
-            RegKind::Integer => {
-                match self.size.bits() {
-                    1 => dl.i1_align,
-                    2...8 => dl.i8_align,
-                    9...16 => dl.i16_align,
-                    17...32 => dl.i32_align,
-                    33...64 => dl.i64_align,
-                    65...128 => dl.i128_align,
-                    _ => panic!("unsupported integer: {:?}", self)
-                }
-            }
-            RegKind::Float => {
-                match self.size.bits() {
-                    32 => dl.f32_align,
-                    64 => dl.f64_align,
-                    _ => panic!("unsupported float: {:?}", self)
-                }
-            }
-            RegKind::Vector => dl.vector_align(self.size)
-        }
-    }
-}
-
-/// An argument passed entirely registers with the
-/// same kind (e.g. HFA / HVA on PPC64 and AArch64).
-#[derive(Clone, Copy, PartialEq, Eq, Debug)]
-pub struct Uniform {
-    pub unit: Reg,
-
-    /// The total size of the argument, which can be:
-    /// * equal to `unit.size` (one scalar/vector)
-    /// * a multiple of `unit.size` (an array of scalar/vectors)
-    /// * if `unit.kind` is `Integer`, the last element
-    ///   can be shorter, i.e. `{ i64, i64, i32 }` for
-    ///   64-bit integers with a total size of 20 bytes
-    pub total: Size,
-}
-
-impl From<Reg> for Uniform {
-    fn from(unit: Reg) -> Uniform {
-        Uniform {
-            unit,
-            total: unit.size
-        }
-    }
-}
-
-impl Uniform {
-    pub fn align<C: HasDataLayout>(&self, cx: C) -> Align {
-        self.unit.align(cx)
-    }
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, Debug)]
-pub struct CastTarget {
-    pub prefix: [Option<RegKind>; 8],
-    pub prefix_chunk: Size,
-    pub rest: Uniform,
-}
-
-impl From<Reg> for CastTarget {
-    fn from(unit: Reg) -> CastTarget {
-        CastTarget::from(Uniform::from(unit))
-    }
-}
-
-impl From<Uniform> for CastTarget {
-    fn from(uniform: Uniform) -> CastTarget {
-        CastTarget {
-            prefix: [None; 8],
-            prefix_chunk: Size::from_bytes(0),
-            rest: uniform
-        }
-    }
-}
-
-impl CastTarget {
-    pub fn pair(a: Reg, b: Reg) -> CastTarget {
-        CastTarget {
-            prefix: [Some(a.kind), None, None, None, None, None, None, None],
-            prefix_chunk: a.size,
-            rest: Uniform::from(b)
-        }
-    }
-
-    pub fn size<C: HasDataLayout>(&self, cx: C) -> Size {
-        (self.prefix_chunk * self.prefix.iter().filter(|x| x.is_some()).count() as u64)
-             .abi_align(self.rest.align(cx)) + self.rest.total
-    }
-
-    pub fn align<C: HasDataLayout>(&self, cx: C) -> Align {
-        self.prefix.iter()
-            .filter_map(|x| x.map(|kind| Reg { kind: kind, size: self.prefix_chunk }.align(cx)))
-            .fold(cx.data_layout().aggregate_align.max(self.rest.align(cx)),
-                |acc, align| acc.max(align))
-    }
-}
\ No newline at end of file
diff --git a/src/librustc_target/abi/call/aarch64.rs b/src/librustc_target/abi/call/aarch64.rs
new file mode 100644
index 00000000000..a665f9f6fe3
--- /dev/null
+++ b/src/librustc_target/abi/call/aarch64.rs
@@ -0,0 +1,124 @@
+// Copyright 2015 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.
+
+use abi::call::{FnType, ArgType, Reg, RegKind, Uniform};
+use abi::{HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods};
+
+fn is_homogeneous_aggregate<'a, Ty, C>(cx: C, arg: &mut ArgType<'a, Ty>)
+                                     -> Option<Uniform> 
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+{
+    arg.layout.homogeneous_aggregate(cx).and_then(|unit| {
+        let size = arg.layout.size;
+
+        // Ensure we have at most four uniquely addressable members.
+        if size > unit.size.checked_mul(4, cx).unwrap() {
+            return None;
+        }
+
+        let valid_unit = match unit.kind {
+            RegKind::Integer => false,
+            RegKind::Float => true,
+            RegKind::Vector => size.bits() == 64 || size.bits() == 128
+        };
+
+        if valid_unit {
+            Some(Uniform {
+                unit,
+                total: size
+            })
+        } else {
+            None
+        }
+    })
+}
+
+fn classify_ret_ty<'a, Ty, C>(cx: C, ret: &mut ArgType<'a, Ty>) 
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+{
+    if !ret.layout.is_aggregate() {
+        ret.extend_integer_width_to(32);
+        return;
+    }
+    if let Some(uniform) = is_homogeneous_aggregate(cx, ret) {
+        ret.cast_to(uniform);
+        return;
+    }
+    let size = ret.layout.size;
+    let bits = size.bits();
+    if bits <= 128 {
+        let unit = if bits <= 8 {
+            Reg::i8()
+        } else if bits <= 16 {
+            Reg::i16()
+        } else if bits <= 32 {
+            Reg::i32()
+        } else {
+            Reg::i64()
+        };
+
+        ret.cast_to(Uniform {
+            unit,
+            total: size
+        });
+        return;
+    }
+    ret.make_indirect();
+}
+
+fn classify_arg_ty<'a, Ty, C>(cx: C, arg: &mut ArgType<'a, Ty>) 
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+{
+    if !arg.layout.is_aggregate() {
+        arg.extend_integer_width_to(32);
+        return;
+    }
+    if let Some(uniform) = is_homogeneous_aggregate(cx, arg) {
+        arg.cast_to(uniform);
+        return;
+    }
+    let size = arg.layout.size;
+    let bits = size.bits();
+    if bits <= 128 {
+        let unit = if bits <= 8 {
+            Reg::i8()
+        } else if bits <= 16 {
+            Reg::i16()
+        } else if bits <= 32 {
+            Reg::i32()
+        } else {
+            Reg::i64()
+        };
+
+        arg.cast_to(Uniform {
+            unit,
+            total: size
+        });
+        return;
+    }
+    arg.make_indirect();
+}
+
+pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<'a, Ty>) 
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+{
+    if !fty.ret.is_ignore() {
+        classify_ret_ty(cx, &mut fty.ret);
+    }
+
+    for arg in &mut fty.args {
+        if arg.is_ignore() { continue; }
+        classify_arg_ty(cx, arg);
+    }
+}
diff --git a/src/librustc_target/abi/call/arm.rs b/src/librustc_target/abi/call/arm.rs
new file mode 100644
index 00000000000..fb8f4aaf38e
--- /dev/null
+++ b/src/librustc_target/abi/call/arm.rs
@@ -0,0 +1,122 @@
+// Copyright 2012-2013 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.
+
+use abi::call::{Conv, FnType, ArgType, Reg, RegKind, Uniform};
+use abi::{HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods};
+use spec::HasTargetSpec;
+
+fn is_homogeneous_aggregate<'a, Ty, C>(cx: C, arg: &mut ArgType<'a, Ty>)
+                                     -> Option<Uniform> 
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+{
+    arg.layout.homogeneous_aggregate(cx).and_then(|unit| {
+        let size = arg.layout.size;
+
+        // Ensure we have at most four uniquely addressable members.
+        if size > unit.size.checked_mul(4, cx).unwrap() {
+            return None;
+        }
+
+        let valid_unit = match unit.kind {
+            RegKind::Integer => false,
+            RegKind::Float => true,
+            RegKind::Vector => size.bits() == 64 || size.bits() == 128
+        };
+
+        if valid_unit {
+            Some(Uniform {
+                unit,
+                total: size
+            })
+        } else {
+            None
+        }
+    })
+}
+
+fn classify_ret_ty<'a, Ty, C>(cx: C, ret: &mut ArgType<'a, Ty>, vfp: bool)
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+{
+    if !ret.layout.is_aggregate() {
+        ret.extend_integer_width_to(32);
+        return;
+    }
+
+    if vfp {
+        if let Some(uniform) = is_homogeneous_aggregate(cx, ret) {
+            ret.cast_to(uniform);
+            return;
+        }
+    }
+
+    let size = ret.layout.size;
+    let bits = size.bits();
+    if bits <= 32 {
+        let unit = if bits <= 8 {
+            Reg::i8()
+        } else if bits <= 16 {
+            Reg::i16()
+        } else {
+            Reg::i32()
+        };
+        ret.cast_to(Uniform {
+            unit,
+            total: size
+        });
+        return;
+    }
+    ret.make_indirect();
+}
+
+fn classify_arg_ty<'a, Ty, C>(cx: C, arg: &mut ArgType<'a, Ty>, vfp: bool) 
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+{
+    if !arg.layout.is_aggregate() {
+        arg.extend_integer_width_to(32);
+        return;
+    }
+
+    if vfp {
+        if let Some(uniform) = is_homogeneous_aggregate(cx, arg) {
+            arg.cast_to(uniform);
+            return;
+        }
+    }
+
+    let align = arg.layout.align.abi();
+    let total = arg.layout.size;
+    arg.cast_to(Uniform {
+        unit: if align <= 4 { Reg::i32() } else { Reg::i64() },
+        total
+    });
+}
+
+pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<'a, Ty>) 
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout + HasTargetSpec
+{
+    // If this is a target with a hard-float ABI, and the function is not explicitly
+    // `extern "aapcs"`, then we must use the VFP registers for homogeneous aggregates.
+    let vfp = cx.target_spec().llvm_target.ends_with("hf")
+        && fty.conv != Conv::ArmAapcs
+        && !fty.variadic;
+
+    if !fty.ret.is_ignore() {
+        classify_ret_ty(cx, &mut fty.ret, vfp);
+    }
+
+    for arg in &mut fty.args {
+        if arg.is_ignore() { continue; }
+        classify_arg_ty(cx, arg, vfp);
+    }
+}
diff --git a/src/librustc_target/abi/call/asmjs.rs b/src/librustc_target/abi/call/asmjs.rs
new file mode 100644
index 00000000000..15f48a31652
--- /dev/null
+++ b/src/librustc_target/abi/call/asmjs.rs
@@ -0,0 +1,57 @@
+// Copyright 2012-2013 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.
+
+use abi::call::{FnType, ArgType, Uniform};
+use abi::{HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods};
+
+// Data layout: e-p:32:32-i64:64-v128:32:128-n32-S128
+
+// See the https://github.com/kripken/emscripten-fastcomp-clang repository.
+// The class `EmscriptenABIInfo` in `/lib/CodeGen/TargetInfo.cpp` contains the ABI definitions.
+
+fn classify_ret_ty<'a, Ty, C>(cx: C, ret: &mut ArgType<'a, Ty>) 
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+{
+    if ret.layout.is_aggregate() {
+        if let Some(unit) = ret.layout.homogeneous_aggregate(cx) {
+            let size = ret.layout.size;
+            if unit.size == size {
+                ret.cast_to(Uniform {
+                    unit,
+                    total: size
+                });
+                return;
+            }
+        }
+
+        ret.make_indirect();
+    }
+}
+
+fn classify_arg_ty<Ty>(arg: &mut ArgType<Ty>) {
+    if arg.layout.is_aggregate() {
+        arg.make_indirect_byval();
+    }
+}
+
+pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<'a, Ty>) 
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+{
+    if !fty.ret.is_ignore() {
+        classify_ret_ty(cx, &mut fty.ret);
+    }
+
+    for arg in &mut fty.args {
+        if arg.is_ignore() { continue; }
+        classify_arg_ty(arg);
+    }
+}
diff --git a/src/librustc_target/abi/call/hexagon.rs b/src/librustc_target/abi/call/hexagon.rs
new file mode 100644
index 00000000000..d37d5584591
--- /dev/null
+++ b/src/librustc_target/abi/call/hexagon.rs
@@ -0,0 +1,42 @@
+// Copyright 2012-2013 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.
+
+#![allow(non_upper_case_globals)]
+
+use abi::call::{FnType, ArgType};
+
+fn classify_ret_ty<Ty>(ret: &mut ArgType<Ty>) {
+    if ret.layout.is_aggregate() && ret.layout.size.bits() > 64 {
+        ret.make_indirect();
+    } else {
+        ret.extend_integer_width_to(32);
+    }
+}
+
+fn classify_arg_ty<Ty>(arg: &mut ArgType<Ty>) {
+    if arg.layout.is_aggregate() && arg.layout.size.bits() > 64 {
+        arg.make_indirect();
+    } else {
+        arg.extend_integer_width_to(32);
+    }
+}
+
+pub fn compute_abi_info<Ty>(fty: &mut FnType<Ty>) {
+    if !fty.ret.is_ignore() {
+        classify_ret_ty(&mut fty.ret);
+    }
+
+    for arg in &mut fty.args {
+        if arg.is_ignore() {
+            continue;
+        }
+        classify_arg_ty(arg);
+    }
+}
diff --git a/src/librustc_target/abi/call/mips.rs b/src/librustc_target/abi/call/mips.rs
new file mode 100644
index 00000000000..39f9e7d8b7d
--- /dev/null
+++ b/src/librustc_target/abi/call/mips.rs
@@ -0,0 +1,59 @@
+// Copyright 2012-2013 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.
+
+use abi::call::{ArgType, FnType, Reg, Uniform};
+use abi::{HasDataLayout, LayoutOf, Size, TyLayoutMethods};
+
+fn classify_ret_ty<'a, Ty, C>(cx: C, ret: &mut ArgType<Ty>, offset: &mut Size)
+    where Ty: TyLayoutMethods<'a, C>, C: LayoutOf<Ty = Ty> + HasDataLayout
+{
+    if !ret.layout.is_aggregate() {
+        ret.extend_integer_width_to(32);
+    } else {
+        ret.make_indirect();
+        *offset += cx.data_layout().pointer_size;
+    }
+}
+
+fn classify_arg_ty<'a, Ty, C>(cx: C, arg: &mut ArgType<Ty>, offset: &mut Size)
+    where Ty: TyLayoutMethods<'a, C>, C: LayoutOf<Ty = Ty> + HasDataLayout
+{
+    let dl = cx.data_layout();
+    let size = arg.layout.size;
+    let align = arg.layout.align.max(dl.i32_align).min(dl.i64_align);
+
+    if arg.layout.is_aggregate() {
+        arg.cast_to(Uniform {
+            unit: Reg::i32(),
+            total: size
+        });
+        if !offset.is_abi_aligned(align) {
+            arg.pad_with(Reg::i32());
+        }
+    } else {
+        arg.extend_integer_width_to(32);
+    }
+
+    *offset = offset.abi_align(align) + size.abi_align(align);
+}
+
+pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<Ty>) 
+    where Ty: TyLayoutMethods<'a, C>, C: LayoutOf<Ty = Ty> + HasDataLayout
+{
+    let mut offset = Size::from_bytes(0);
+    if !fty.ret.is_ignore() {
+        classify_ret_ty(cx, &mut fty.ret, &mut offset);
+    }
+
+    for arg in &mut fty.args {
+        if arg.is_ignore() { continue; }
+        classify_arg_ty(cx, arg, &mut offset);
+    }
+}
diff --git a/src/librustc_target/abi/call/mips64.rs b/src/librustc_target/abi/call/mips64.rs
new file mode 100644
index 00000000000..fe9b861e203
--- /dev/null
+++ b/src/librustc_target/abi/call/mips64.rs
@@ -0,0 +1,166 @@
+// 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.
+
+use abi::call::{ArgAttribute, ArgType, CastTarget, FnType, PassMode, Reg, RegKind, Uniform};
+use abi::{self, HasDataLayout, LayoutOf, Size, TyLayout, TyLayoutMethods};
+
+fn extend_integer_width_mips<Ty>(arg: &mut ArgType<Ty>, bits: u64) {
+    // Always sign extend u32 values on 64-bit mips
+    if let abi::Abi::Scalar(ref scalar) = arg.layout.abi {
+        if let abi::Int(i, signed) = scalar.value {
+            if !signed && i.size().bits() == 32 {
+                if let PassMode::Direct(ref mut attrs) = arg.mode {
+                    attrs.set(ArgAttribute::SExt);
+                    return;
+                }
+            }
+        }
+    }
+
+    arg.extend_integer_width_to(bits);
+}
+
+fn float_reg<'a, Ty, C>(cx: C, ret: &ArgType<'a, Ty>, i: usize) -> Option<Reg> 
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+{
+    match ret.layout.field(cx, i).abi {
+        abi::Abi::Scalar(ref scalar) => match scalar.value {
+            abi::F32 => Some(Reg::f32()),
+            abi::F64 => Some(Reg::f64()),
+            _ => None
+        },
+        _ => None
+    }
+}
+
+fn classify_ret_ty<'a, Ty, C>(cx: C, ret: &mut ArgType<'a, Ty>) 
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+{
+    if !ret.layout.is_aggregate() {
+        extend_integer_width_mips(ret, 64);
+        return;
+    }
+
+    let size = ret.layout.size;
+    let bits = size.bits();
+    if bits <= 128 {
+        // Unlike other architectures which return aggregates in registers, MIPS n64 limits the
+        // use of float registers to structures (not unions) containing exactly one or two
+        // float fields.
+
+        if let abi::FieldPlacement::Arbitrary { .. } = ret.layout.fields {
+            if ret.layout.fields.count() == 1 {
+                if let Some(reg) = float_reg(cx, ret, 0) {
+                    ret.cast_to(reg);
+                    return;
+                }
+            } else if ret.layout.fields.count() == 2 {
+                if let Some(reg0) = float_reg(cx, ret, 0) {
+                    if let Some(reg1) = float_reg(cx, ret, 1) {
+                        ret.cast_to(CastTarget::pair(reg0, reg1));
+                        return;
+                    }
+                }
+            }
+        }
+
+        // Cast to a uniform int structure
+        ret.cast_to(Uniform {
+            unit: Reg::i64(),
+            total: size
+        });
+    } else {
+        ret.make_indirect();
+    }
+}
+
+fn classify_arg_ty<'a, Ty, C>(cx: C, arg: &mut ArgType<'a, Ty>) 
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+{
+    if !arg.layout.is_aggregate() {
+        extend_integer_width_mips(arg, 64);
+        return;
+    }
+
+    let dl = cx.data_layout();
+    let size = arg.layout.size;
+    let mut prefix = [None; 8];
+    let mut prefix_index = 0;
+
+    match arg.layout.fields {
+        abi::FieldPlacement::Array { .. } => {
+            // Arrays are passed indirectly
+            arg.make_indirect();
+            return;
+        }
+        abi::FieldPlacement::Union(_) => {
+            // Unions and are always treated as a series of 64-bit integer chunks
+        },
+        abi::FieldPlacement::Arbitrary { .. } => {
+            // Structures are split up into a series of 64-bit integer chunks, but any aligned
+            // doubles not part of another aggregate are passed as floats.
+            let mut last_offset = Size::from_bytes(0);
+
+            for i in 0..arg.layout.fields.count() {
+                let field = arg.layout.field(cx, i);
+                let offset = arg.layout.fields.offset(i);
+
+                // We only care about aligned doubles
+                if let abi::Abi::Scalar(ref scalar) = field.abi {
+                    if let abi::F64 = scalar.value {
+                        if offset.is_abi_aligned(dl.f64_align) {
+                            // Insert enough integers to cover [last_offset, offset)
+                            assert!(last_offset.is_abi_aligned(dl.f64_align));
+                            for _ in 0..((offset - last_offset).bits() / 64)
+                                .min((prefix.len() - prefix_index) as u64) {
+
+                                prefix[prefix_index] = Some(RegKind::Integer);
+                                prefix_index += 1;
+                            }
+
+                            if prefix_index == prefix.len() {
+                                break;
+                            }
+
+                            prefix[prefix_index] = Some(RegKind::Float);
+                            prefix_index += 1;
+                            last_offset = offset + Reg::f64().size;
+                        }
+                    }
+                }
+            }
+        }
+    };
+
+    // Extract first 8 chunks as the prefix
+    let rest_size = size - Size::from_bytes(8) * prefix_index as u64;
+    arg.cast_to(CastTarget {
+        prefix: prefix,
+        prefix_chunk: Size::from_bytes(8),
+        rest: Uniform { unit: Reg::i64(), total: rest_size }
+    });
+}
+
+pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<'a, Ty>) 
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+{
+    if !fty.ret.is_ignore() {
+        classify_ret_ty(cx, &mut fty.ret);
+    }
+
+    for arg in &mut fty.args {
+        if arg.is_ignore() { continue; }
+        classify_arg_ty(cx, arg);
+    }
+}
diff --git a/src/librustc_target/abi/call/mod.rs b/src/librustc_target/abi/call/mod.rs
new file mode 100644
index 00000000000..3fad7926e1f
--- /dev/null
+++ b/src/librustc_target/abi/call/mod.rs
@@ -0,0 +1,511 @@
+// Copyright 2017 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.
+
+use abi::{self, Abi, Align, FieldPlacement, Size};
+use abi::{HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods};
+use spec::HasTargetSpec;
+
+mod aarch64;
+mod arm;
+mod asmjs;
+mod hexagon;
+mod mips;
+mod mips64;
+mod msp430;
+mod nvptx;
+mod nvptx64;
+mod powerpc;
+mod powerpc64;
+mod s390x;
+mod sparc;
+mod sparc64;
+mod x86;
+mod x86_64;
+mod x86_win64;
+mod wasm32;
+
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub enum PassMode {
+    /// Ignore the argument (useful for empty struct).
+    Ignore,
+    /// Pass the argument directly.
+    Direct(ArgAttributes),
+    /// Pass a pair's elements directly in two arguments.
+    Pair(ArgAttributes, ArgAttributes),
+    /// Pass the argument after casting it, to either
+    /// a single uniform or a pair of registers.
+    Cast(CastTarget),
+    /// Pass the argument indirectly via a hidden pointer.
+    Indirect(ArgAttributes),
+}
+
+// Hack to disable non_upper_case_globals only for the bitflags! and not for the rest
+// of this module
+pub use self::attr_impl::ArgAttribute;
+
+#[allow(non_upper_case_globals)]
+#[allow(unused)]
+mod attr_impl {
+    // The subset of llvm::Attribute needed for arguments, packed into a bitfield.
+    bitflags! {
+        #[derive(Default)]
+        pub struct ArgAttribute: u16 {
+            const ByVal     = 1 << 0;
+            const NoAlias   = 1 << 1;
+            const NoCapture = 1 << 2;
+            const NonNull   = 1 << 3;
+            const ReadOnly  = 1 << 4;
+            const SExt      = 1 << 5;
+            const StructRet = 1 << 6;
+            const ZExt      = 1 << 7;
+            const InReg     = 1 << 8;
+        }
+    }
+}
+
+/// A compact representation of LLVM attributes (at least those relevant for this module)
+/// that can be manipulated without interacting with LLVM's Attribute machinery.
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub struct ArgAttributes {
+    pub regular: ArgAttribute,
+    pub pointee_size: Size,
+    pub pointee_align: Option<Align>
+}
+
+impl ArgAttributes {
+    pub fn new() -> Self {
+        ArgAttributes {
+            regular: ArgAttribute::default(),
+            pointee_size: Size::from_bytes(0),
+            pointee_align: None,
+        }
+    }
+
+    pub fn set(&mut self, attr: ArgAttribute) -> &mut Self {
+        self.regular = self.regular | attr;
+        self
+    }
+
+    pub fn contains(&self, attr: ArgAttribute) -> bool {
+        self.regular.contains(attr)
+    }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum RegKind {
+    Integer,
+    Float,
+    Vector
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub struct Reg {
+    pub kind: RegKind,
+    pub size: Size,
+}
+
+macro_rules! reg_ctor {
+    ($name:ident, $kind:ident, $bits:expr) => {
+        pub fn $name() -> Reg {
+            Reg {
+                kind: RegKind::$kind,
+                size: Size::from_bits($bits)
+            }
+        }
+    }
+}
+
+impl Reg {
+    reg_ctor!(i8, Integer, 8);
+    reg_ctor!(i16, Integer, 16);
+    reg_ctor!(i32, Integer, 32);
+    reg_ctor!(i64, Integer, 64);
+
+    reg_ctor!(f32, Float, 32);
+    reg_ctor!(f64, Float, 64);
+}
+
+impl Reg {
+    pub fn align<C: HasDataLayout>(&self, cx: C) -> Align {
+        let dl = cx.data_layout();
+        match self.kind {
+            RegKind::Integer => {
+                match self.size.bits() {
+                    1 => dl.i1_align,
+                    2...8 => dl.i8_align,
+                    9...16 => dl.i16_align,
+                    17...32 => dl.i32_align,
+                    33...64 => dl.i64_align,
+                    65...128 => dl.i128_align,
+                    _ => panic!("unsupported integer: {:?}", self)
+                }
+            }
+            RegKind::Float => {
+                match self.size.bits() {
+                    32 => dl.f32_align,
+                    64 => dl.f64_align,
+                    _ => panic!("unsupported float: {:?}", self)
+                }
+            }
+            RegKind::Vector => dl.vector_align(self.size)
+        }
+    }
+}
+
+/// An argument passed entirely registers with the
+/// same kind (e.g. HFA / HVA on PPC64 and AArch64).
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub struct Uniform {
+    pub unit: Reg,
+
+    /// The total size of the argument, which can be:
+    /// * equal to `unit.size` (one scalar/vector)
+    /// * a multiple of `unit.size` (an array of scalar/vectors)
+    /// * if `unit.kind` is `Integer`, the last element
+    ///   can be shorter, i.e. `{ i64, i64, i32 }` for
+    ///   64-bit integers with a total size of 20 bytes
+    pub total: Size,
+}
+
+impl From<Reg> for Uniform {
+    fn from(unit: Reg) -> Uniform {
+        Uniform {
+            unit,
+            total: unit.size
+        }
+    }
+}
+
+impl Uniform {
+    pub fn align<C: HasDataLayout>(&self, cx: C) -> Align {
+        self.unit.align(cx)
+    }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub struct CastTarget {
+    pub prefix: [Option<RegKind>; 8],
+    pub prefix_chunk: Size,
+    pub rest: Uniform,
+}
+
+impl From<Reg> for CastTarget {
+    fn from(unit: Reg) -> CastTarget {
+        CastTarget::from(Uniform::from(unit))
+    }
+}
+
+impl From<Uniform> for CastTarget {
+    fn from(uniform: Uniform) -> CastTarget {
+        CastTarget {
+            prefix: [None; 8],
+            prefix_chunk: Size::from_bytes(0),
+            rest: uniform
+        }
+    }
+}
+
+impl CastTarget {
+    pub fn pair(a: Reg, b: Reg) -> CastTarget {
+        CastTarget {
+            prefix: [Some(a.kind), None, None, None, None, None, None, None],
+            prefix_chunk: a.size,
+            rest: Uniform::from(b)
+        }
+    }
+
+    pub fn size<C: HasDataLayout>(&self, cx: C) -> Size {
+        (self.prefix_chunk * self.prefix.iter().filter(|x| x.is_some()).count() as u64)
+             .abi_align(self.rest.align(cx)) + self.rest.total
+    }
+
+    pub fn align<C: HasDataLayout>(&self, cx: C) -> Align {
+        self.prefix.iter()
+            .filter_map(|x| x.map(|kind| Reg { kind: kind, size: self.prefix_chunk }.align(cx)))
+            .fold(cx.data_layout().aggregate_align.max(self.rest.align(cx)),
+                |acc, align| acc.max(align))
+    }
+}
+
+impl<'a, Ty> TyLayout<'a, Ty> {
+    fn is_aggregate(&self) -> bool {
+        match self.abi {
+            Abi::Uninhabited |
+            Abi::Scalar(_) |
+            Abi::Vector { .. } => false,
+            Abi::ScalarPair(..) |
+            Abi::Aggregate { .. } => true
+        }
+    }
+
+    fn homogeneous_aggregate<C>(&self, cx: C) -> Option<Reg> 
+        where Ty: TyLayoutMethods<'a, C> + Copy, C: LayoutOf<Ty = Ty, TyLayout = Self> + Copy
+    {
+        match self.abi {
+            Abi::Uninhabited => None,
+
+            // The primitive for this algorithm.
+            Abi::Scalar(ref scalar) => {
+                let kind = match scalar.value {
+                    abi::Int(..) |
+                    abi::Pointer => RegKind::Integer,
+                    abi::F32 |
+                    abi::F64 => RegKind::Float
+                };
+                Some(Reg {
+                    kind,
+                    size: self.size
+                })
+            }
+
+            Abi::Vector { .. } => {
+                Some(Reg {
+                    kind: RegKind::Vector,
+                    size: self.size
+                })
+            }
+
+            Abi::ScalarPair(..) |
+            Abi::Aggregate { .. } => {
+                let mut total = Size::from_bytes(0);
+                let mut result = None;
+
+                let is_union = match self.fields {
+                    FieldPlacement::Array { count, .. } => {
+                        if count > 0 {
+                            return self.field(cx, 0).homogeneous_aggregate(cx);
+                        } else {
+                            return None;
+                        }
+                    }
+                    FieldPlacement::Union(_) => true,
+                    FieldPlacement::Arbitrary { .. } => false
+                };
+
+                for i in 0..self.fields.count() {
+                    if !is_union && total != self.fields.offset(i) {
+                        return None;
+                    }
+
+                    let field = self.field(cx, i);
+                    match (result, field.homogeneous_aggregate(cx)) {
+                        // The field itself must be a homogeneous aggregate.
+                        (_, None) => return None,
+                        // If this is the first field, record the unit.
+                        (None, Some(unit)) => {
+                            result = Some(unit);
+                        }
+                        // For all following fields, the unit must be the same.
+                        (Some(prev_unit), Some(unit)) => {
+                            if prev_unit != unit {
+                                return None;
+                            }
+                        }
+                    }
+
+                    // Keep track of the offset (without padding).
+                    let size = field.size;
+                    if is_union {
+                        total = total.max(size);
+                    } else {
+                        total += size;
+                    }
+                }
+
+                // There needs to be no padding.
+                if total != self.size {
+                    None
+                } else {
+                    result
+                }
+            }
+        }
+    }
+}
+
+/// Information about how to pass an argument to,
+/// or return a value from, a function, under some ABI.
+#[derive(Debug)]
+pub struct ArgType<'a, Ty> {
+    pub layout: TyLayout<'a, Ty>,
+
+    /// Dummy argument, which is emitted before the real argument.
+    pub pad: Option<Reg>,
+
+    pub mode: PassMode,
+}
+
+impl<'a, Ty> ArgType<'a, Ty> {
+    pub fn new(layout: TyLayout<'a, Ty>) -> Self {
+        ArgType {
+            layout,
+            pad: None,
+            mode: PassMode::Direct(ArgAttributes::new()),
+        }
+    }
+
+    pub fn make_indirect(&mut self) {
+        assert_eq!(self.mode, PassMode::Direct(ArgAttributes::new()));
+
+        // Start with fresh attributes for the pointer.
+        let mut attrs = ArgAttributes::new();
+
+        // For non-immediate arguments the callee gets its own copy of
+        // the value on the stack, so there are no aliases. It's also
+        // program-invisible so can't possibly capture
+        attrs.set(ArgAttribute::NoAlias)
+             .set(ArgAttribute::NoCapture)
+             .set(ArgAttribute::NonNull);
+        attrs.pointee_size = self.layout.size;
+        // FIXME(eddyb) We should be doing this, but at least on
+        // i686-pc-windows-msvc, it results in wrong stack offsets.
+        // attrs.pointee_align = Some(self.layout.align);
+
+        self.mode = PassMode::Indirect(attrs);
+    }
+
+    pub fn make_indirect_byval(&mut self) {
+        self.make_indirect();
+        match self.mode {
+            PassMode::Indirect(ref mut attrs) => {
+                attrs.set(ArgAttribute::ByVal);
+            }
+            _ => unreachable!()
+        }
+    }
+
+    pub fn extend_integer_width_to(&mut self, bits: u64) {
+        // Only integers have signedness
+        if let Abi::Scalar(ref scalar) = self.layout.abi {
+            if let abi::Int(i, signed) = scalar.value {
+                if i.size().bits() < bits {
+                    if let PassMode::Direct(ref mut attrs) = self.mode {
+                        attrs.set(if signed {
+                            ArgAttribute::SExt
+                        } else {
+                            ArgAttribute::ZExt
+                        });
+                    }
+                }
+            }
+        }
+    }
+
+    pub fn cast_to<T: Into<CastTarget>>(&mut self, target: T) {
+        assert_eq!(self.mode, PassMode::Direct(ArgAttributes::new()));
+        self.mode = PassMode::Cast(target.into());
+    }
+
+    pub fn pad_with(&mut self, reg: Reg) {
+        self.pad = Some(reg);
+    }
+
+    pub fn is_indirect(&self) -> bool {
+        match self.mode {
+            PassMode::Indirect(_) => true,
+            _ => false
+        }
+    }
+
+    pub fn is_ignore(&self) -> bool {
+        self.mode == PassMode::Ignore
+    }
+}
+
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub enum Conv {
+    C,
+
+    ArmAapcs,
+
+    Msp430Intr,
+
+    PtxKernel,
+
+    X86Fastcall,
+    X86Intr,
+    X86Stdcall,
+    X86ThisCall,
+    X86VectorCall,
+
+    X86_64SysV,
+    X86_64Win64,
+}
+
+/// Metadata describing how the arguments to a native function
+/// should be passed in order to respect the native ABI.
+///
+/// I will do my best to describe this structure, but these
+/// comments are reverse-engineered and may be inaccurate. -NDM
+#[derive(Debug)]
+pub struct FnType<'a, Ty> {
+    /// The LLVM types of each argument.
+    pub args: Vec<ArgType<'a, Ty>>,
+
+    /// LLVM return type.
+    pub ret: ArgType<'a, Ty>,
+
+    pub variadic: bool,
+
+    pub conv: Conv,
+}
+
+impl<'a, Ty> FnType<'a, Ty> {
+    pub fn adjust_for_cabi<C>(&mut self, cx: C, abi: ::syntax::abi::Abi) -> Result<(), String>
+        where Ty: TyLayoutMethods<'a, C> + Copy,
+              C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout + HasTargetSpec
+    {
+        match &cx.target_spec().arch[..] {
+            "x86" => {
+                let flavor = if abi == ::syntax::abi::Abi::Fastcall {
+                    x86::Flavor::Fastcall
+                } else {
+                    x86::Flavor::General
+                };
+                x86::compute_abi_info(cx, self, flavor);
+            },
+            "x86_64" => if abi == ::syntax::abi::Abi::SysV64 {
+                x86_64::compute_abi_info(cx, self);
+            } else if abi == ::syntax::abi::Abi::Win64 || cx.target_spec().options.is_like_windows {
+                x86_win64::compute_abi_info(self);
+            } else {
+                x86_64::compute_abi_info(cx, self);
+            },
+            "aarch64" => aarch64::compute_abi_info(cx, self),
+            "arm" => arm::compute_abi_info(cx, self),
+            "mips" => mips::compute_abi_info(cx, self),
+            "mips64" => mips64::compute_abi_info(cx, self),
+            "powerpc" => powerpc::compute_abi_info(cx, self),
+            "powerpc64" => powerpc64::compute_abi_info(cx, self),
+            "s390x" => s390x::compute_abi_info(cx, self),
+            "asmjs" => asmjs::compute_abi_info(cx, self),
+            "wasm32" => {
+                if cx.target_spec().llvm_target.contains("emscripten") {
+                    asmjs::compute_abi_info(cx, self)
+                } else {
+                    wasm32::compute_abi_info(self)
+                }
+            }
+            "msp430" => msp430::compute_abi_info(self),
+            "sparc" => sparc::compute_abi_info(cx, self),
+            "sparc64" => sparc64::compute_abi_info(cx, self),
+            "nvptx" => nvptx::compute_abi_info(self),
+            "nvptx64" => nvptx64::compute_abi_info(self),
+            "hexagon" => hexagon::compute_abi_info(self),
+            a => return Err(format!("unrecognized arch \"{}\" in target specification", a))
+        }
+
+        if let PassMode::Indirect(ref mut attrs) = self.ret.mode {
+            attrs.set(ArgAttribute::StructRet);
+        }
+
+        Ok(())
+    }
+}
diff --git a/src/librustc_target/abi/call/msp430.rs b/src/librustc_target/abi/call/msp430.rs
new file mode 100644
index 00000000000..e57ca03da60
--- /dev/null
+++ b/src/librustc_target/abi/call/msp430.rs
@@ -0,0 +1,49 @@
+// Copyright 2012-2013 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.
+
+// Reference: MSP430 Embedded Application Binary Interface
+// http://www.ti.com/lit/an/slaa534/slaa534.pdf
+
+use abi::call::{ArgType, FnType};
+
+// 3.5 Structures or Unions Passed and Returned by Reference
+//
+// "Structures (including classes) and unions larger than 32 bits are passed and
+// returned by reference. To pass a structure or union by reference, the caller
+// places its address in the appropriate location: either in a register or on
+// the stack, according to its position in the argument list. (..)"
+fn classify_ret_ty<Ty>(ret: &mut ArgType<Ty>) {
+    if ret.layout.is_aggregate() && ret.layout.size.bits() > 32 {
+        ret.make_indirect();
+    } else {
+        ret.extend_integer_width_to(16);
+    }
+}
+
+fn classify_arg_ty<Ty>(arg: &mut ArgType<Ty>) {
+    if arg.layout.is_aggregate() && arg.layout.size.bits() > 32 {
+        arg.make_indirect();
+    } else {
+        arg.extend_integer_width_to(16);
+    }
+}
+
+pub fn compute_abi_info<Ty>(fty: &mut FnType<Ty>) {
+    if !fty.ret.is_ignore() {
+        classify_ret_ty(&mut fty.ret);
+    }
+
+    for arg in &mut fty.args {
+        if arg.is_ignore() {
+            continue;
+        }
+        classify_arg_ty(arg);
+    }
+}
diff --git a/src/librustc_target/abi/call/nvptx.rs b/src/librustc_target/abi/call/nvptx.rs
new file mode 100644
index 00000000000..f23f7ddf2ab
--- /dev/null
+++ b/src/librustc_target/abi/call/nvptx.rs
@@ -0,0 +1,43 @@
+// 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.
+
+// Reference: PTX Writer's Guide to Interoperability
+// http://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability
+
+use abi::call::{ArgType, FnType};
+
+fn classify_ret_ty<Ty>(ret: &mut ArgType<Ty>) {
+    if ret.layout.is_aggregate() && ret.layout.size.bits() > 32 {
+        ret.make_indirect();
+    } else {
+        ret.extend_integer_width_to(32);
+    }
+}
+
+fn classify_arg_ty<Ty>(arg: &mut ArgType<Ty>) {
+    if arg.layout.is_aggregate() && arg.layout.size.bits() > 32 {
+        arg.make_indirect();
+    } else {
+        arg.extend_integer_width_to(32);
+    }
+}
+
+pub fn compute_abi_info<Ty>(fty: &mut FnType<Ty>) {
+    if !fty.ret.is_ignore() {
+        classify_ret_ty(&mut fty.ret);
+    }
+
+    for arg in &mut fty.args {
+        if arg.is_ignore() {
+            continue;
+        }
+        classify_arg_ty(arg);
+    }
+}
diff --git a/src/librustc_target/abi/call/nvptx64.rs b/src/librustc_target/abi/call/nvptx64.rs
new file mode 100644
index 00000000000..4399a2fec6c
--- /dev/null
+++ b/src/librustc_target/abi/call/nvptx64.rs
@@ -0,0 +1,43 @@
+// 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.
+
+// Reference: PTX Writer's Guide to Interoperability
+// http://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability
+
+use abi::call::{ArgType, FnType};
+
+fn classify_ret_ty<Ty>(ret: &mut ArgType<Ty>) {
+    if ret.layout.is_aggregate() && ret.layout.size.bits() > 64 {
+        ret.make_indirect();
+    } else {
+        ret.extend_integer_width_to(64);
+    }
+}
+
+fn classify_arg_ty<Ty>(arg: &mut ArgType<Ty>) {
+    if arg.layout.is_aggregate() && arg.layout.size.bits() > 64 {
+        arg.make_indirect();
+    } else {
+        arg.extend_integer_width_to(64);
+    }
+}
+
+pub fn compute_abi_info<Ty>(fty: &mut FnType<Ty>) {
+    if !fty.ret.is_ignore() {
+        classify_ret_ty(&mut fty.ret);
+    }
+
+    for arg in &mut fty.args {
+        if arg.is_ignore() {
+            continue;
+        }
+        classify_arg_ty(arg);
+    }
+}
diff --git a/src/librustc_target/abi/call/powerpc.rs b/src/librustc_target/abi/call/powerpc.rs
new file mode 100644
index 00000000000..8c3c2422d7f
--- /dev/null
+++ b/src/librustc_target/abi/call/powerpc.rs
@@ -0,0 +1,59 @@
+// Copyright 2014-2015 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.
+
+use abi::call::{ArgType, FnType, Reg, Uniform};
+use abi::{HasDataLayout, LayoutOf, Size, TyLayoutMethods};
+
+fn classify_ret_ty<'a, Ty, C>(cx: C, ret: &mut ArgType<Ty>, offset: &mut Size)
+    where Ty: TyLayoutMethods<'a, C>, C: LayoutOf<Ty = Ty> + HasDataLayout
+{
+    if !ret.layout.is_aggregate() {
+        ret.extend_integer_width_to(32);
+    } else {
+        ret.make_indirect();
+        *offset += cx.data_layout().pointer_size;
+    }
+}
+
+fn classify_arg_ty<'a, Ty, C>(cx: C, arg: &mut ArgType<Ty>, offset: &mut Size)
+    where Ty: TyLayoutMethods<'a, C>, C: LayoutOf<Ty = Ty> + HasDataLayout
+{
+    let dl = cx.data_layout();
+    let size = arg.layout.size;
+    let align = arg.layout.align.max(dl.i32_align).min(dl.i64_align);
+
+    if arg.layout.is_aggregate() {
+        arg.cast_to(Uniform {
+            unit: Reg::i32(),
+            total: size
+        });
+        if !offset.is_abi_aligned(align) {
+            arg.pad_with(Reg::i32());
+        }
+    } else {
+        arg.extend_integer_width_to(32);
+    }
+
+    *offset = offset.abi_align(align) + size.abi_align(align);
+}
+
+pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<Ty>)
+    where Ty: TyLayoutMethods<'a, C>, C: LayoutOf<Ty = Ty> + HasDataLayout
+{
+    let mut offset = Size::from_bytes(0);
+    if !fty.ret.is_ignore() {
+        classify_ret_ty(cx, &mut fty.ret, &mut offset);
+    }
+
+    for arg in &mut fty.args {
+        if arg.is_ignore() { continue; }
+        classify_arg_ty(cx, arg, &mut offset);
+    }
+}
diff --git a/src/librustc_target/abi/call/powerpc64.rs b/src/librustc_target/abi/call/powerpc64.rs
new file mode 100644
index 00000000000..b0e27ebc7ba
--- /dev/null
+++ b/src/librustc_target/abi/call/powerpc64.rs
@@ -0,0 +1,154 @@
+// 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 <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:
+// Alignment of 128 bit types is not currently handled, this will
+// need to be fixed when PowerPC vector support is added.
+
+use abi::call::{FnType, ArgType, Reg, RegKind, Uniform};
+use abi::{Align, Endian, HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods};
+
+#[derive(Debug, Clone, Copy, PartialEq)]
+enum ABI {
+    ELFv1, // original ABI used for powerpc64 (big-endian)
+    ELFv2, // newer ABI used for powerpc64le
+}
+use self::ABI::*;
+
+fn is_homogeneous_aggregate<'a, Ty, C>(cx: C, arg: &mut ArgType<'a, Ty>, abi: ABI) 
+                                       -> Option<Uniform>
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+{                                   
+    arg.layout.homogeneous_aggregate(cx).and_then(|unit| {
+        // ELFv1 only passes one-member aggregates transparently.
+        // ELFv2 passes up to eight uniquely addressable members.
+        if (abi == ELFv1 && arg.layout.size > unit.size)
+                || arg.layout.size > unit.size.checked_mul(8, cx).unwrap() {
+            return None;
+        }
+
+        let valid_unit = match unit.kind {
+            RegKind::Integer => false,
+            RegKind::Float => true,
+            RegKind::Vector => arg.layout.size.bits() == 128
+        };
+
+        if valid_unit {
+            Some(Uniform {
+                unit,
+                total: arg.layout.size
+            })
+        } else {
+            None
+        }
+    })
+}
+
+fn classify_ret_ty<'a, Ty, C>(cx: C, ret: &mut ArgType<'a, Ty>, abi: ABI)
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+{
+    if !ret.layout.is_aggregate() {
+        ret.extend_integer_width_to(64);
+        return;
+    }
+
+    // The ELFv1 ABI doesn't return aggregates in registers
+    if abi == ELFv1 {
+        ret.make_indirect();
+        return;
+    }
+
+    if let Some(uniform) = is_homogeneous_aggregate(cx, ret, abi) {
+        ret.cast_to(uniform);
+        return;
+    }
+
+    let size = ret.layout.size;
+    let bits = size.bits();
+    if bits <= 128 {
+        let unit = if bits <= 8 {
+            Reg::i8()
+        } else if bits <= 16 {
+            Reg::i16()
+        } else if bits <= 32 {
+            Reg::i32()
+        } else {
+            Reg::i64()
+        };
+
+        ret.cast_to(Uniform {
+            unit,
+            total: size
+        });
+        return;
+    }
+
+    ret.make_indirect();
+}
+
+fn classify_arg_ty<'a, Ty, C>(cx: C, arg: &mut ArgType<'a, Ty>, abi: ABI)
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+{
+    if !arg.layout.is_aggregate() {
+        arg.extend_integer_width_to(64);
+        return;
+    }
+
+    if let Some(uniform) = is_homogeneous_aggregate(cx, arg, abi) {
+        arg.cast_to(uniform);
+        return;
+    }
+
+    let size = arg.layout.size;
+    let (unit, total) = match abi {
+        ELFv1 => {
+            // In ELFv1, aggregates smaller than a doubleword should appear in
+            // the least-significant bits of the parameter doubleword.  The rest
+            // should be padded at their tail to fill out multiple doublewords.
+            if size.bits() <= 64 {
+                (Reg { kind: RegKind::Integer, size }, size)
+            } else {
+                let align = Align::from_bits(64, 64).unwrap();
+                (Reg::i64(), size.abi_align(align))
+            }
+        },
+        ELFv2 => {
+            // In ELFv2, we can just cast directly.
+            (Reg::i64(), size)
+        },
+    };
+
+    arg.cast_to(Uniform {
+        unit,
+        total
+    });
+}
+
+pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<'a, Ty>)
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+{
+    let abi = match cx.data_layout().endian {
+        Endian::Big => ELFv1,
+        Endian::Little => ELFv2,
+    };
+
+    if !fty.ret.is_ignore() {
+        classify_ret_ty(cx, &mut fty.ret, abi);
+    }
+
+    for arg in &mut fty.args {
+        if arg.is_ignore() { continue; }
+        classify_arg_ty(cx, arg, abi);
+    }
+}
diff --git a/src/librustc_target/abi/call/s390x.rs b/src/librustc_target/abi/call/s390x.rs
new file mode 100644
index 00000000000..2fbe1c608d8
--- /dev/null
+++ b/src/librustc_target/abi/call/s390x.rs
@@ -0,0 +1,87 @@
+// 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 abi::call::{FnType, ArgType, Reg};
+use abi::{self, HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods};
+
+fn classify_ret_ty<'a, Ty, C>(ret: &mut ArgType<Ty>) 
+    where Ty: TyLayoutMethods<'a, C>, C: LayoutOf<Ty = Ty> + HasDataLayout
+{
+    if !ret.layout.is_aggregate() && ret.layout.size.bits() <= 64 {
+        ret.extend_integer_width_to(64);
+    } else {
+        ret.make_indirect();
+    }
+}
+
+fn is_single_fp_element<'a, Ty, C>(cx: C, layout: TyLayout<'a, Ty>) -> bool
+    where Ty: TyLayoutMethods<'a, C>,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+{
+    match layout.abi {
+        abi::Abi::Scalar(ref scalar) => {
+            match scalar.value {
+                abi::F32 | abi::F64 => true,
+                _ => false
+            }
+        }
+        abi::Abi::Aggregate { .. } => {
+            if layout.fields.count() == 1 && layout.fields.offset(0).bytes() == 0 {
+                is_single_fp_element(cx, layout.field(cx, 0))
+            } else {
+                false
+            }
+        }
+        _ => false
+    }
+}
+
+fn classify_arg_ty<'a, Ty, C>(cx: C, arg: &mut ArgType<'a, Ty>) 
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+{
+    if !arg.layout.is_aggregate() && arg.layout.size.bits() <= 64 {
+        arg.extend_integer_width_to(64);
+        return;
+    }
+
+    if is_single_fp_element(cx, arg.layout) {
+        match arg.layout.size.bytes() {
+            4 => arg.cast_to(Reg::f32()),
+            8 => arg.cast_to(Reg::f64()),
+            _ => arg.make_indirect()
+        }
+    } else {
+        match arg.layout.size.bytes() {
+            1 => arg.cast_to(Reg::i8()),
+            2 => arg.cast_to(Reg::i16()),
+            4 => arg.cast_to(Reg::i32()),
+            8 => arg.cast_to(Reg::i64()),
+            _ => arg.make_indirect()
+        }
+    }
+}
+
+pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<'a, Ty>) 
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+{
+    if !fty.ret.is_ignore() {
+        classify_ret_ty(&mut fty.ret);
+    }
+
+    for arg in &mut fty.args {
+        if arg.is_ignore() { continue; }
+        classify_arg_ty(cx, arg);
+    }
+}
diff --git a/src/librustc_target/abi/call/sparc.rs b/src/librustc_target/abi/call/sparc.rs
new file mode 100644
index 00000000000..1e7bd158864
--- /dev/null
+++ b/src/librustc_target/abi/call/sparc.rs
@@ -0,0 +1,59 @@
+// Copyright 2012-2013 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.
+
+use abi::call::{ArgType, FnType, Reg, Uniform};
+use abi::{HasDataLayout, LayoutOf, Size, TyLayoutMethods};
+
+fn classify_ret_ty<'a, Ty, C>(cx: C, ret: &mut ArgType<Ty>, offset: &mut Size) 
+    where Ty: TyLayoutMethods<'a, C>, C: LayoutOf<Ty = Ty> + HasDataLayout
+{
+    if !ret.layout.is_aggregate() {
+        ret.extend_integer_width_to(32);
+    } else {
+        ret.make_indirect();
+        *offset += cx.data_layout().pointer_size;
+    }
+}
+
+fn classify_arg_ty<'a, Ty, C>(cx: C, arg: &mut ArgType<Ty>, offset: &mut Size)
+    where Ty: TyLayoutMethods<'a, C>, C: LayoutOf<Ty = Ty> + HasDataLayout
+{
+    let dl = cx.data_layout();
+    let size = arg.layout.size;
+    let align = arg.layout.align.max(dl.i32_align).min(dl.i64_align);
+
+    if arg.layout.is_aggregate() {
+        arg.cast_to(Uniform {
+            unit: Reg::i32(),
+            total: size
+        });
+        if !offset.is_abi_aligned(align) {
+            arg.pad_with(Reg::i32());
+        }
+    } else {
+        arg.extend_integer_width_to(32);
+    }
+
+    *offset = offset.abi_align(align) + size.abi_align(align);
+}
+
+pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<Ty>)
+    where Ty: TyLayoutMethods<'a, C>, C: LayoutOf<Ty = Ty> + HasDataLayout
+{
+    let mut offset = Size::from_bytes(0);
+    if !fty.ret.is_ignore() {
+        classify_ret_ty(cx, &mut fty.ret, &mut offset);
+    }
+
+    for arg in &mut fty.args {
+        if arg.is_ignore() { continue; }
+        classify_arg_ty(cx, arg, &mut offset);
+    }
+}
diff --git a/src/librustc_target/abi/call/sparc64.rs b/src/librustc_target/abi/call/sparc64.rs
new file mode 100644
index 00000000000..a583613a501
--- /dev/null
+++ b/src/librustc_target/abi/call/sparc64.rs
@@ -0,0 +1,119 @@
+// 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 <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: This needs an audit for correctness and completeness.
+
+use abi::call::{FnType, ArgType, Reg, RegKind, Uniform};
+use abi::{HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods};
+
+fn is_homogeneous_aggregate<'a, Ty, C>(cx: C, arg: &mut ArgType<'a, Ty>)
+                                     -> Option<Uniform>
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout 
+{
+    arg.layout.homogeneous_aggregate(cx).and_then(|unit| {
+        // Ensure we have at most eight uniquely addressable members.
+        if arg.layout.size > unit.size.checked_mul(8, cx).unwrap() {
+            return None;
+        }
+
+        let valid_unit = match unit.kind {
+            RegKind::Integer => false,
+            RegKind::Float => true,
+            RegKind::Vector => arg.layout.size.bits() == 128
+        };
+
+        if valid_unit {
+            Some(Uniform {
+                unit,
+                total: arg.layout.size
+            })
+        } else {
+            None
+        }
+    })
+}
+
+fn classify_ret_ty<'a, Ty, C>(cx: C, ret: &mut ArgType<'a, Ty>) 
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout 
+{
+    if !ret.layout.is_aggregate() {
+        ret.extend_integer_width_to(64);
+        return;
+    }
+
+    if let Some(uniform) = is_homogeneous_aggregate(cx, ret) {
+        ret.cast_to(uniform);
+        return;
+    }
+    let size = ret.layout.size;
+    let bits = size.bits();
+    if bits <= 256 {
+        let unit = if bits <= 8 {
+            Reg::i8()
+        } else if bits <= 16 {
+            Reg::i16()
+        } else if bits <= 32 {
+            Reg::i32()
+        } else {
+            Reg::i64()
+        };
+
+        ret.cast_to(Uniform {
+            unit,
+            total: size
+        });
+        return;
+    }
+
+    // don't return aggregates in registers
+    ret.make_indirect();
+}
+
+fn classify_arg_ty<'a, Ty, C>(cx: C, arg: &mut ArgType<'a, Ty>) 
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout 
+{
+    if !arg.layout.is_aggregate() {
+        arg.extend_integer_width_to(64);
+        return;
+    }
+
+    if let Some(uniform) = is_homogeneous_aggregate(cx, arg) {
+        arg.cast_to(uniform);
+        return;
+    }
+
+    let total = arg.layout.size;
+    if total.bits() > 128 {
+        arg.make_indirect();
+        return;
+    }
+
+    arg.cast_to(Uniform {
+        unit: Reg::i64(),
+        total
+    });
+}
+
+pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<'a, Ty>)  
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout 
+{
+    if !fty.ret.is_ignore() {
+        classify_ret_ty(cx, &mut fty.ret);
+    }
+
+    for arg in &mut fty.args {
+        if arg.is_ignore() { continue; }
+        classify_arg_ty(cx, arg);
+    }
+}
diff --git a/src/librustc_target/abi/call/wasm32.rs b/src/librustc_target/abi/call/wasm32.rs
new file mode 100644
index 00000000000..7109eea535d
--- /dev/null
+++ b/src/librustc_target/abi/call/wasm32.rs
@@ -0,0 +1,30 @@
+// Copyright 2018 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.
+
+use abi::call::{FnType, ArgType};
+
+fn classify_ret_ty<Ty>(ret: &mut ArgType<Ty>) {
+    ret.extend_integer_width_to(32);
+}
+
+fn classify_arg_ty<Ty>(arg: &mut ArgType<Ty>) {
+    arg.extend_integer_width_to(32);
+}
+
+pub fn compute_abi_info<Ty>(fty: &mut FnType<Ty>) {
+    if !fty.ret.is_ignore() {
+        classify_ret_ty(&mut fty.ret);
+    }
+
+    for arg in &mut fty.args {
+        if arg.is_ignore() { continue; }
+        classify_arg_ty(arg);
+    }
+}
diff --git a/src/librustc_target/abi/call/x86.rs b/src/librustc_target/abi/call/x86.rs
new file mode 100644
index 00000000000..dd4373de72c
--- /dev/null
+++ b/src/librustc_target/abi/call/x86.rs
@@ -0,0 +1,143 @@
+// Copyright 2013 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.
+
+use abi::call::{ArgAttribute, FnType, PassMode, Reg, RegKind};
+use abi::{self, HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods};
+use spec::HasTargetSpec;
+
+#[derive(PartialEq)]
+pub enum Flavor {
+    General,
+    Fastcall
+}
+
+fn is_single_fp_element<'a, Ty, C>(cx: C, layout: TyLayout<'a, Ty>) -> bool
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+{
+    match layout.abi {
+        abi::Abi::Scalar(ref scalar) => {
+            match scalar.value {
+                abi::F32 | abi::F64 => true,
+                _ => false
+            }
+        }
+        abi::Abi::Aggregate { .. } => {
+            if layout.fields.count() == 1 && layout.fields.offset(0).bytes() == 0 {
+                is_single_fp_element(cx, layout.field(cx, 0))
+            } else {
+                false
+            }
+        }
+        _ => false
+    }
+}
+
+pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<'a, Ty>, flavor: Flavor) 
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout + HasTargetSpec
+{
+    if !fty.ret.is_ignore() {
+        if fty.ret.layout.is_aggregate() {
+            // Returning a structure. Most often, this will use
+            // a hidden first argument. On some platforms, though,
+            // small structs are returned as integers.
+            //
+            // Some links:
+            // http://www.angelcode.com/dev/callconv/callconv.html
+            // Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp
+            let t = cx.target_spec();
+            if t.options.abi_return_struct_as_int {
+                // According to Clang, everyone but MSVC returns single-element
+                // float aggregates directly in a floating-point register.
+                if !t.options.is_like_msvc && is_single_fp_element(cx, fty.ret.layout) {
+                    match fty.ret.layout.size.bytes() {
+                        4 => fty.ret.cast_to(Reg::f32()),
+                        8 => fty.ret.cast_to(Reg::f64()),
+                        _ => fty.ret.make_indirect()
+                    }
+                } else {
+                    match fty.ret.layout.size.bytes() {
+                        1 => fty.ret.cast_to(Reg::i8()),
+                        2 => fty.ret.cast_to(Reg::i16()),
+                        4 => fty.ret.cast_to(Reg::i32()),
+                        8 => fty.ret.cast_to(Reg::i64()),
+                        _ => fty.ret.make_indirect()
+                    }
+                }
+            } else {
+                fty.ret.make_indirect();
+            }
+        } else {
+            fty.ret.extend_integer_width_to(32);
+        }
+    }
+
+    for arg in &mut fty.args {
+        if arg.is_ignore() { continue; }
+        if arg.layout.is_aggregate() {
+            arg.make_indirect_byval();
+        } else {
+            arg.extend_integer_width_to(32);
+        }
+    }
+
+    if flavor == Flavor::Fastcall {
+        // Mark arguments as InReg like clang does it,
+        // so our fastcall is compatible with C/C++ fastcall.
+
+        // Clang reference: lib/CodeGen/TargetInfo.cpp
+        // See X86_32ABIInfo::shouldPrimitiveUseInReg(), X86_32ABIInfo::updateFreeRegs()
+
+        // IsSoftFloatABI is only set to true on ARM platforms,
+        // which in turn can't be x86?
+
+        let mut free_regs = 2;
+
+        for arg in &mut fty.args {
+            let attrs = match arg.mode {
+                PassMode::Ignore |
+                PassMode::Indirect(_) => continue,
+                PassMode::Direct(ref mut attrs) => attrs,
+                PassMode::Pair(..) |
+                PassMode::Cast(_) => {
+                    unreachable!("x86 shouldn't be passing arguments by {:?}", arg.mode)
+                }
+            };
+
+            // At this point we know this must be a primitive of sorts.
+            let unit = arg.layout.homogeneous_aggregate(cx).unwrap();
+            assert_eq!(unit.size, arg.layout.size);
+            if unit.kind == RegKind::Float {
+                continue;
+            }
+
+            let size_in_regs = (arg.layout.size.bits() + 31) / 32;
+
+            if size_in_regs == 0 {
+                continue;
+            }
+
+            if size_in_regs > free_regs {
+                break;
+            }
+
+            free_regs -= size_in_regs;
+
+            if arg.layout.size.bits() <= 32 && unit.kind == RegKind::Integer {
+                attrs.set(ArgAttribute::InReg);
+            }
+
+            if free_regs == 0 {
+                break;
+            }
+        }
+    }
+}
diff --git a/src/librustc_target/abi/call/x86_64.rs b/src/librustc_target/abi/call/x86_64.rs
new file mode 100644
index 00000000000..388d0eca5c4
--- /dev/null
+++ b/src/librustc_target/abi/call/x86_64.rs
@@ -0,0 +1,244 @@
+// Copyright 2012-2013 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.
+
+// The classification code for the x86_64 ABI is taken from the clay language
+// https://github.com/jckarter/clay/blob/master/compiler/src/externals.cpp
+
+use abi::call::{ArgType, CastTarget, FnType, Reg, RegKind};
+use abi::{self, Abi, HasDataLayout, LayoutOf, Size, TyLayout, TyLayoutMethods};
+
+/// Classification of "eightbyte" components.
+// NB: the order of the variants is from general to specific,
+// such that `unify(a, b)` is the "smaller" of `a` and `b`.
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
+enum Class {
+    Int,
+    Sse,
+    SseUp
+}
+
+#[derive(Clone, Copy, Debug)]
+struct Memory;
+
+// Currently supported vector size (AVX-512).
+const LARGEST_VECTOR_SIZE: usize = 512;
+const MAX_EIGHTBYTES: usize = LARGEST_VECTOR_SIZE / 64;
+
+fn classify_arg<'a, Ty, C>(cx: C, arg: &ArgType<'a, Ty>)
+                          -> Result<[Option<Class>; MAX_EIGHTBYTES], Memory> 
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+{
+    fn classify<'a, Ty, C>(cx: C, layout: TyLayout<'a, Ty>,
+                          cls: &mut [Option<Class>], off: Size) -> Result<(), Memory> 
+        where Ty: TyLayoutMethods<'a, C> + Copy,
+            C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+    {
+        if !off.is_abi_aligned(layout.align) {
+            if !layout.is_zst() {
+                return Err(Memory);
+            }
+            return Ok(());
+        }
+
+        let mut c = match layout.abi {
+            Abi::Uninhabited => return Ok(()),
+
+            Abi::Scalar(ref scalar) => {
+                match scalar.value {
+                    abi::Int(..) |
+                    abi::Pointer => Class::Int,
+                    abi::F32 |
+                    abi::F64 => Class::Sse
+                }
+            }
+
+            Abi::Vector { .. } => Class::Sse,
+
+            Abi::ScalarPair(..) |
+            Abi::Aggregate { .. } => {
+                match layout.variants {
+                    abi::Variants::Single { .. } => {
+                        for i in 0..layout.fields.count() {
+                            let field_off = off + layout.fields.offset(i);
+                            classify(cx, layout.field(cx, i), cls, field_off)?;
+                        }
+                        return Ok(());
+                    }
+                    abi::Variants::Tagged { .. } |
+                    abi::Variants::NicheFilling { .. } => return Err(Memory),
+                }
+            }
+
+        };
+
+        // Fill in `cls` for scalars (Int/Sse) and vectors (Sse).
+        let first = (off.bytes() / 8) as usize;
+        let last = ((off.bytes() + layout.size.bytes() - 1) / 8) as usize;
+        for cls in &mut cls[first..=last] {
+            *cls = Some(cls.map_or(c, |old| old.min(c)));
+
+            // Everything after the first Sse "eightbyte"
+            // component is the upper half of a register.
+            if c == Class::Sse {
+                c = Class::SseUp;
+            }
+        }
+
+        Ok(())
+    }
+
+    let n = ((arg.layout.size.bytes() + 7) / 8) as usize;
+    if n > MAX_EIGHTBYTES {
+        return Err(Memory);
+    }
+
+    let mut cls = [None; MAX_EIGHTBYTES];
+    classify(cx, arg.layout, &mut cls, Size::from_bytes(0))?;
+    if n > 2 {
+        if cls[0] != Some(Class::Sse) {
+            return Err(Memory);
+        }
+        if cls[1..n].iter().any(|&c| c != Some(Class::SseUp)) {
+            return Err(Memory);
+        }
+    } else {
+        let mut i = 0;
+        while i < n {
+            if cls[i] == Some(Class::SseUp) {
+                cls[i] = Some(Class::Sse);
+            } else if cls[i] == Some(Class::Sse) {
+                i += 1;
+                while i != n && cls[i] == Some(Class::SseUp) { i += 1; }
+            } else {
+                i += 1;
+            }
+        }
+    }
+
+    Ok(cls)
+}
+
+fn reg_component(cls: &[Option<Class>], i: &mut usize, size: Size) -> Option<Reg> {
+    if *i >= cls.len() {
+        return None;
+    }
+
+    match cls[*i] {
+        None => None,
+        Some(Class::Int) => {
+            *i += 1;
+            Some(if size.bytes() < 8 {
+                Reg {
+                    kind: RegKind::Integer,
+                    size
+                }
+            } else {
+                Reg::i64()
+            })
+        }
+        Some(Class::Sse) => {
+            let vec_len = 1 + cls[*i+1..].iter()
+                .take_while(|&&c| c == Some(Class::SseUp))
+                .count();
+            *i += vec_len;
+            Some(if vec_len == 1 {
+                match size.bytes() {
+                    4 => Reg::f32(),
+                    _ => Reg::f64()
+                }
+            } else {
+                Reg {
+                    kind: RegKind::Vector,
+                    size: Size::from_bytes(8) * (vec_len as u64)
+                }
+            })
+        }
+        Some(c) => unreachable!("reg_component: unhandled class {:?}", c)
+    }
+}
+
+fn cast_target(cls: &[Option<Class>], size: Size) -> CastTarget {
+    let mut i = 0;
+    let lo = reg_component(cls, &mut i, size).unwrap();
+    let offset = Size::from_bytes(8) * (i as u64);
+    let mut target = CastTarget::from(lo);
+    if size > offset {
+        if let Some(hi) = reg_component(cls, &mut i, size - offset) {
+            target = CastTarget::pair(lo, hi);
+        }
+    }
+    assert_eq!(reg_component(cls, &mut i, Size::from_bytes(0)), None);
+    target
+}
+
+pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<'a, Ty>) 
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+{
+    let mut int_regs = 6; // RDI, RSI, RDX, RCX, R8, R9
+    let mut sse_regs = 8; // XMM0-7
+
+    let mut x86_64_ty = |arg: &mut ArgType<'a, Ty>, is_arg: bool| {
+        let mut cls_or_mem = classify_arg(cx, arg);
+
+        let mut needed_int = 0;
+        let mut needed_sse = 0;
+        if is_arg {
+            if let Ok(cls) = cls_or_mem {
+                for &c in &cls {
+                    match c {
+                        Some(Class::Int) => needed_int += 1,
+                        Some(Class::Sse) => needed_sse += 1,
+                        _ => {}
+                    }
+                }
+                if arg.layout.is_aggregate() {
+                    if int_regs < needed_int || sse_regs < needed_sse {
+                        cls_or_mem = Err(Memory);
+                    }
+                }
+            }
+        }
+
+        match cls_or_mem {
+            Err(Memory) => {
+                if is_arg {
+                    arg.make_indirect_byval();
+                } else {
+                    // `sret` parameter thus one less integer register available
+                    arg.make_indirect();
+                    int_regs -= 1;
+                }
+            }
+            Ok(ref cls) => {
+                // split into sized chunks passed individually
+                int_regs -= needed_int;
+                sse_regs -= needed_sse;
+
+                if arg.layout.is_aggregate() {
+                    let size = arg.layout.size;
+                    arg.cast_to(cast_target(cls, size))
+                } else {
+                    arg.extend_integer_width_to(32);
+                }
+            }
+        }
+    };
+
+    if !fty.ret.is_ignore() {
+        x86_64_ty(&mut fty.ret, false);
+    }
+
+    for arg in &mut fty.args {
+        if arg.is_ignore() { continue; }
+        x86_64_ty(arg, true);
+    }
+}
diff --git a/src/librustc_target/abi/call/x86_win64.rs b/src/librustc_target/abi/call/x86_win64.rs
new file mode 100644
index 00000000000..1ee069e2bbb
--- /dev/null
+++ b/src/librustc_target/abi/call/x86_win64.rs
@@ -0,0 +1,51 @@
+// Copyright 2013 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.
+
+use abi::call::{ArgType, FnType, Reg};
+use abi::Abi;
+
+// Win64 ABI: http://msdn.microsoft.com/en-us/library/zthk2dkh.aspx
+
+pub fn compute_abi_info<Ty>(fty: &mut FnType<Ty>) {
+    let fixup = |a: &mut ArgType<Ty>| {
+        match a.layout.abi {
+            Abi::Uninhabited => {}
+            Abi::ScalarPair(..) |
+            Abi::Aggregate { .. } => {
+                match a.layout.size.bits() {
+                    8 => a.cast_to(Reg::i8()),
+                    16 => a.cast_to(Reg::i16()),
+                    32 => a.cast_to(Reg::i32()),
+                    64 => a.cast_to(Reg::i64()),
+                    _ => a.make_indirect()
+                }
+            }
+            Abi::Vector { .. } => {
+                // FIXME(eddyb) there should be a size cap here
+                // (probably what clang calls "illegal vectors").
+            }
+            Abi::Scalar(_) => {
+                if a.layout.size.bytes() > 8 {
+                    a.make_indirect();
+                } else {
+                    a.extend_integer_width_to(32);
+                }
+            }
+        }
+    };
+
+    if !fty.ret.is_ignore() {
+        fixup(&mut fty.ret);
+    }
+    for arg in &mut fty.args {
+        if arg.is_ignore() { continue; }
+        fixup(arg);
+    }
+}