From 030244cd4a76914af7dc2939ed1a16f394ceda48 Mon Sep 17 00:00:00 2001 From: Irina Popa Date: Wed, 25 Apr 2018 16:45:29 +0300 Subject: [PATCH] rustc_target: move in cabi_* from rustc_trans. --- src/librustc_target/abi/call.rs | 214 -------- .../abi/call/aarch64.rs} | 4 +- .../abi/call/arm.rs} | 9 +- .../abi/call/asmjs.rs} | 4 +- .../abi/call/hexagon.rs} | 2 +- .../abi/call/mips.rs} | 5 +- .../abi/call/mips64.rs} | 4 +- src/librustc_target/abi/call/mod.rs | 511 ++++++++++++++++++ .../abi/call/msp430.rs} | 2 +- .../abi/call/nvptx.rs} | 2 +- .../abi/call/nvptx64.rs} | 2 +- .../abi/call/powerpc.rs} | 5 +- .../abi/call/powerpc64.rs} | 5 +- .../abi/call/s390x.rs} | 5 +- .../abi/call/sparc.rs} | 5 +- .../abi/call/sparc64.rs} | 4 +- .../abi/call/wasm32.rs} | 2 +- .../abi/call/x86.rs} | 8 +- .../abi/call/x86_64.rs} | 16 +- .../abi/call/x86_win64.rs} | 15 +- src/librustc_trans/abi.rs | 384 +++---------- src/librustc_trans/declare.rs | 4 +- src/librustc_trans/intrinsic.rs | 2 +- src/librustc_trans/lib.rs | 18 - src/librustc_trans/meth.rs | 4 +- src/librustc_trans/mir/block.rs | 14 +- src/librustc_trans/mir/mod.rs | 6 +- src/librustc_trans/type_of.rs | 2 +- 28 files changed, 645 insertions(+), 613 deletions(-) delete mode 100644 src/librustc_target/abi/call.rs rename src/{librustc_trans/cabi_aarch64.rs => librustc_target/abi/call/aarch64.rs} (96%) rename src/{librustc_trans/cabi_arm.rs => librustc_target/abi/call/arm.rs} (93%) rename src/{librustc_trans/cabi_asmjs.rs => librustc_target/abi/call/asmjs.rs} (93%) rename src/{librustc_trans/cabi_hexagon.rs => librustc_target/abi/call/hexagon.rs} (96%) rename src/{librustc_trans/cabi_mips.rs => librustc_target/abi/call/mips.rs} (93%) rename src/{librustc_trans/cabi_mips64.rs => librustc_target/abi/call/mips64.rs} (96%) create mode 100644 src/librustc_target/abi/call/mod.rs rename src/{librustc_trans/cabi_msp430.rs => librustc_target/abi/call/msp430.rs} (97%) rename src/{librustc_trans/cabi_nvptx.rs => librustc_target/abi/call/nvptx.rs} (97%) rename src/{librustc_trans/cabi_nvptx64.rs => librustc_target/abi/call/nvptx64.rs} (97%) rename src/{librustc_trans/cabi_powerpc.rs => librustc_target/abi/call/powerpc.rs} (93%) rename src/{librustc_trans/cabi_powerpc64.rs => librustc_target/abi/call/powerpc64.rs} (96%) rename src/{librustc_trans/cabi_s390x.rs => librustc_target/abi/call/s390x.rs} (95%) rename src/{librustc_trans/cabi_sparc.rs => librustc_target/abi/call/sparc.rs} (93%) rename src/{librustc_trans/cabi_sparc64.rs => librustc_target/abi/call/sparc64.rs} (95%) rename src/{librustc_trans/cabi_wasm32.rs => librustc_target/abi/call/wasm32.rs} (96%) rename src/{librustc_trans/cabi_x86.rs => librustc_target/abi/call/x86.rs} (94%) rename src/{librustc_trans/cabi_x86_64.rs => librustc_target/abi/call/x86_64.rs} (94%) rename src/{librustc_trans/cabi_x86_win64.rs => librustc_target/abi/call/x86_win64.rs} (85%) diff --git a/src/librustc_target/abi/call.rs b/src/librustc_target/abi/call.rs deleted file mode 100644 index bea705b9ece2f..0000000000000 --- 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 or the MIT license -// , 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 -} - -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(&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 for Uniform { - fn from(unit: Reg) -> Uniform { - Uniform { - unit, - total: unit.size - } - } -} - -impl Uniform { - pub fn align(&self, cx: C) -> Align { - self.unit.align(cx) - } -} - -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub struct CastTarget { - pub prefix: [Option; 8], - pub prefix_chunk: Size, - pub rest: Uniform, -} - -impl From for CastTarget { - fn from(unit: Reg) -> CastTarget { - CastTarget::from(Uniform::from(unit)) - } -} - -impl From 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(&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(&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_trans/cabi_aarch64.rs b/src/librustc_target/abi/call/aarch64.rs similarity index 96% rename from src/librustc_trans/cabi_aarch64.rs rename to src/librustc_target/abi/call/aarch64.rs index 127f2dd194fe4..a665f9f6fe39b 100644 --- a/src/librustc_trans/cabi_aarch64.rs +++ b/src/librustc_target/abi/call/aarch64.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use abi::{FnType, ArgType, LayoutExt, Reg, RegKind, Uniform}; -use rustc_target::abi::{HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods}; +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 diff --git a/src/librustc_trans/cabi_arm.rs b/src/librustc_target/abi/call/arm.rs similarity index 93% rename from src/librustc_trans/cabi_arm.rs rename to src/librustc_target/abi/call/arm.rs index 395a1db754f8e..fb8f4aaf38e31 100644 --- a/src/librustc_trans/cabi_arm.rs +++ b/src/librustc_target/abi/call/arm.rs @@ -8,10 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use abi::{FnType, ArgType, LayoutExt, Reg, RegKind, Uniform}; -use rustc_target::abi::{HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods}; -use rustc_target::spec::HasTargetSpec; -use llvm::CallConv; +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 @@ -109,7 +108,7 @@ pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<'a, Ty>) // 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.cconv != CallConv::ArmAapcsCallConv + && fty.conv != Conv::ArmAapcs && !fty.variadic; if !fty.ret.is_ignore() { diff --git a/src/librustc_trans/cabi_asmjs.rs b/src/librustc_target/abi/call/asmjs.rs similarity index 93% rename from src/librustc_trans/cabi_asmjs.rs rename to src/librustc_target/abi/call/asmjs.rs index 82879fcf03240..15f48a31652f8 100644 --- a/src/librustc_trans/cabi_asmjs.rs +++ b/src/librustc_target/abi/call/asmjs.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use abi::{FnType, ArgType, LayoutExt, Uniform}; -use rustc_target::abi::{HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods}; +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 diff --git a/src/librustc_trans/cabi_hexagon.rs b/src/librustc_target/abi/call/hexagon.rs similarity index 96% rename from src/librustc_trans/cabi_hexagon.rs rename to src/librustc_target/abi/call/hexagon.rs index 45252c2517590..d37d5584591c4 100644 --- a/src/librustc_trans/cabi_hexagon.rs +++ b/src/librustc_target/abi/call/hexagon.rs @@ -10,7 +10,7 @@ #![allow(non_upper_case_globals)] -use abi::{FnType, ArgType, LayoutExt}; +use abi::call::{FnType, ArgType}; fn classify_ret_ty(ret: &mut ArgType) { if ret.layout.is_aggregate() && ret.layout.size.bits() > 64 { diff --git a/src/librustc_trans/cabi_mips.rs b/src/librustc_target/abi/call/mips.rs similarity index 93% rename from src/librustc_trans/cabi_mips.rs rename to src/librustc_target/abi/call/mips.rs index 77297480136a5..39f9e7d8b7d20 100644 --- a/src/librustc_trans/cabi_mips.rs +++ b/src/librustc_target/abi/call/mips.rs @@ -8,9 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use abi::{ArgType, FnType, LayoutExt, Reg, Uniform}; - -use rustc_target::abi::{HasDataLayout, LayoutOf, Size, TyLayoutMethods}; +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, offset: &mut Size) where Ty: TyLayoutMethods<'a, C>, C: LayoutOf + HasDataLayout diff --git a/src/librustc_trans/cabi_mips64.rs b/src/librustc_target/abi/call/mips64.rs similarity index 96% rename from src/librustc_trans/cabi_mips64.rs rename to src/librustc_target/abi/call/mips64.rs index 9a42f56d919c4..fe9b861e2030d 100644 --- a/src/librustc_trans/cabi_mips64.rs +++ b/src/librustc_target/abi/call/mips64.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use abi::{ArgAttribute, ArgType, CastTarget, FnType, LayoutExt, PassMode, Reg, RegKind, Uniform}; -use rustc_target::abi::{self, HasDataLayout, LayoutOf, Size, TyLayout, TyLayoutMethods}; +use abi::call::{ArgAttribute, ArgType, CastTarget, FnType, PassMode, Reg, RegKind, Uniform}; +use abi::{self, HasDataLayout, LayoutOf, Size, TyLayout, TyLayoutMethods}; fn extend_integer_width_mips(arg: &mut ArgType, bits: u64) { // Always sign extend u32 values on 64-bit mips diff --git a/src/librustc_target/abi/call/mod.rs b/src/librustc_target/abi/call/mod.rs new file mode 100644 index 0000000000000..3fad7926e1fac --- /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 or the MIT license +// , 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 +} + +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(&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 for Uniform { + fn from(unit: Reg) -> Uniform { + Uniform { + unit, + total: unit.size + } + } +} + +impl Uniform { + pub fn align(&self, cx: C) -> Align { + self.unit.align(cx) + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub struct CastTarget { + pub prefix: [Option; 8], + pub prefix_chunk: Size, + pub rest: Uniform, +} + +impl From for CastTarget { + fn from(unit: Reg) -> CastTarget { + CastTarget::from(Uniform::from(unit)) + } +} + +impl From 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(&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(&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(&self, cx: C) -> Option + where Ty: TyLayoutMethods<'a, C> + Copy, C: LayoutOf + 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, + + 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>(&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>, + + /// 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(&mut self, cx: C, abi: ::syntax::abi::Abi) -> Result<(), String> + where Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf> + 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_trans/cabi_msp430.rs b/src/librustc_target/abi/call/msp430.rs similarity index 97% rename from src/librustc_trans/cabi_msp430.rs rename to src/librustc_target/abi/call/msp430.rs index 309465a802626..e57ca03da6007 100644 --- a/src/librustc_trans/cabi_msp430.rs +++ b/src/librustc_target/abi/call/msp430.rs @@ -11,7 +11,7 @@ // Reference: MSP430 Embedded Application Binary Interface // http://www.ti.com/lit/an/slaa534/slaa534.pdf -use abi::{ArgType, FnType, LayoutExt}; +use abi::call::{ArgType, FnType}; // 3.5 Structures or Unions Passed and Returned by Reference // diff --git a/src/librustc_trans/cabi_nvptx.rs b/src/librustc_target/abi/call/nvptx.rs similarity index 97% rename from src/librustc_trans/cabi_nvptx.rs rename to src/librustc_target/abi/call/nvptx.rs index d245ca8c21bb2..f23f7ddf2abcc 100644 --- a/src/librustc_trans/cabi_nvptx.rs +++ b/src/librustc_target/abi/call/nvptx.rs @@ -11,7 +11,7 @@ // Reference: PTX Writer's Guide to Interoperability // http://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability -use abi::{ArgType, FnType, LayoutExt}; +use abi::call::{ArgType, FnType}; fn classify_ret_ty(ret: &mut ArgType) { if ret.layout.is_aggregate() && ret.layout.size.bits() > 32 { diff --git a/src/librustc_trans/cabi_nvptx64.rs b/src/librustc_target/abi/call/nvptx64.rs similarity index 97% rename from src/librustc_trans/cabi_nvptx64.rs rename to src/librustc_target/abi/call/nvptx64.rs index c938b944f46b8..4399a2fec6caf 100644 --- a/src/librustc_trans/cabi_nvptx64.rs +++ b/src/librustc_target/abi/call/nvptx64.rs @@ -11,7 +11,7 @@ // Reference: PTX Writer's Guide to Interoperability // http://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability -use abi::{ArgType, FnType, LayoutExt}; +use abi::call::{ArgType, FnType}; fn classify_ret_ty(ret: &mut ArgType) { if ret.layout.is_aggregate() && ret.layout.size.bits() > 64 { diff --git a/src/librustc_trans/cabi_powerpc.rs b/src/librustc_target/abi/call/powerpc.rs similarity index 93% rename from src/librustc_trans/cabi_powerpc.rs rename to src/librustc_target/abi/call/powerpc.rs index d85f6875d14cc..8c3c2422d7f41 100644 --- a/src/librustc_trans/cabi_powerpc.rs +++ b/src/librustc_target/abi/call/powerpc.rs @@ -8,9 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use abi::{ArgType, FnType, LayoutExt, Reg, Uniform}; - -use rustc_target::abi::{HasDataLayout, LayoutOf, Size, TyLayoutMethods}; +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, offset: &mut Size) where Ty: TyLayoutMethods<'a, C>, C: LayoutOf + HasDataLayout diff --git a/src/librustc_trans/cabi_powerpc64.rs b/src/librustc_target/abi/call/powerpc64.rs similarity index 96% rename from src/librustc_trans/cabi_powerpc64.rs rename to src/librustc_target/abi/call/powerpc64.rs index a8120e47cbf17..b0e27ebc7baaa 100644 --- a/src/librustc_trans/cabi_powerpc64.rs +++ b/src/librustc_target/abi/call/powerpc64.rs @@ -12,9 +12,8 @@ // Alignment of 128 bit types is not currently handled, this will // need to be fixed when PowerPC vector support is added. -use abi::{FnType, ArgType, LayoutExt, Reg, RegKind, Uniform}; - -use rustc_target::abi::{Align, Endian, HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods}; +use abi::call::{FnType, ArgType, Reg, RegKind, Uniform}; +use abi::{Align, Endian, HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods}; #[derive(Debug, Clone, Copy, PartialEq)] enum ABI { diff --git a/src/librustc_trans/cabi_s390x.rs b/src/librustc_target/abi/call/s390x.rs similarity index 95% rename from src/librustc_trans/cabi_s390x.rs rename to src/librustc_target/abi/call/s390x.rs index d18ceda2397cd..2fbe1c608d833 100644 --- a/src/librustc_trans/cabi_s390x.rs +++ b/src/librustc_target/abi/call/s390x.rs @@ -11,9 +11,8 @@ // FIXME: The assumes we're using the non-vector ABI, i.e. compiling // for a pre-z13 machine or using -mno-vx. -use abi::{FnType, ArgType, LayoutExt, Reg}; - -use rustc_target::abi::{self, HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods}; +use abi::call::{FnType, ArgType, Reg}; +use abi::{self, HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods}; fn classify_ret_ty<'a, Ty, C>(ret: &mut ArgType) where Ty: TyLayoutMethods<'a, C>, C: LayoutOf + HasDataLayout diff --git a/src/librustc_trans/cabi_sparc.rs b/src/librustc_target/abi/call/sparc.rs similarity index 93% rename from src/librustc_trans/cabi_sparc.rs rename to src/librustc_target/abi/call/sparc.rs index a2580189bb40e..1e7bd15886481 100644 --- a/src/librustc_trans/cabi_sparc.rs +++ b/src/librustc_target/abi/call/sparc.rs @@ -8,9 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use abi::{ArgType, FnType, LayoutExt, Reg, Uniform}; - -use rustc_target::abi::{HasDataLayout, LayoutOf, Size, TyLayoutMethods}; +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, offset: &mut Size) where Ty: TyLayoutMethods<'a, C>, C: LayoutOf + HasDataLayout diff --git a/src/librustc_trans/cabi_sparc64.rs b/src/librustc_target/abi/call/sparc64.rs similarity index 95% rename from src/librustc_trans/cabi_sparc64.rs rename to src/librustc_target/abi/call/sparc64.rs index c8a7e646cd854..a583613a50120 100644 --- a/src/librustc_trans/cabi_sparc64.rs +++ b/src/librustc_target/abi/call/sparc64.rs @@ -10,8 +10,8 @@ // FIXME: This needs an audit for correctness and completeness. -use abi::{FnType, ArgType, LayoutExt, Reg, RegKind, Uniform}; -use rustc_target::abi::{HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods}; +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 diff --git a/src/librustc_trans/cabi_wasm32.rs b/src/librustc_target/abi/call/wasm32.rs similarity index 96% rename from src/librustc_trans/cabi_wasm32.rs rename to src/librustc_target/abi/call/wasm32.rs index 873c2a1b40521..7109eea535d4a 100644 --- a/src/librustc_trans/cabi_wasm32.rs +++ b/src/librustc_target/abi/call/wasm32.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use abi::{FnType, ArgType}; +use abi::call::{FnType, ArgType}; fn classify_ret_ty(ret: &mut ArgType) { ret.extend_integer_width_to(32); diff --git a/src/librustc_trans/cabi_x86.rs b/src/librustc_target/abi/call/x86.rs similarity index 94% rename from src/librustc_trans/cabi_x86.rs rename to src/librustc_target/abi/call/x86.rs index 874ceb0be9185..dd4373de72c53 100644 --- a/src/librustc_trans/cabi_x86.rs +++ b/src/librustc_target/abi/call/x86.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use abi::{ArgAttribute, FnType, LayoutExt, PassMode, Reg, RegKind}; -use rustc_target::abi::{self, HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods}; -use rustc_target::spec::HasTargetSpec; +use abi::call::{ArgAttribute, FnType, PassMode, Reg, RegKind}; +use abi::{self, HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods}; +use spec::HasTargetSpec; #[derive(PartialEq)] pub enum Flavor { @@ -108,7 +108,7 @@ pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<'a, Ty>, flavor: Flav PassMode::Direct(ref mut attrs) => attrs, PassMode::Pair(..) | PassMode::Cast(_) => { - bug!("x86 shouldn't be passing arguments by {:?}", arg.mode) + unreachable!("x86 shouldn't be passing arguments by {:?}", arg.mode) } }; diff --git a/src/librustc_trans/cabi_x86_64.rs b/src/librustc_target/abi/call/x86_64.rs similarity index 94% rename from src/librustc_trans/cabi_x86_64.rs rename to src/librustc_target/abi/call/x86_64.rs index cde6133f756f7..388d0eca5c4e1 100644 --- a/src/librustc_trans/cabi_x86_64.rs +++ b/src/librustc_target/abi/call/x86_64.rs @@ -11,8 +11,8 @@ // 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::{ArgType, CastTarget, FnType, LayoutExt, Reg, RegKind}; -use rustc_target::abi::{self, HasDataLayout, LayoutOf, Size, TyLayout, TyLayoutMethods}; +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, @@ -49,9 +49,9 @@ fn classify_arg<'a, Ty, C>(cx: C, arg: &ArgType<'a, Ty>) } let mut c = match layout.abi { - abi::Abi::Uninhabited => return Ok(()), + Abi::Uninhabited => return Ok(()), - abi::Abi::Scalar(ref scalar) => { + Abi::Scalar(ref scalar) => { match scalar.value { abi::Int(..) | abi::Pointer => Class::Int, @@ -60,10 +60,10 @@ fn classify_arg<'a, Ty, C>(cx: C, arg: &ArgType<'a, Ty>) } } - abi::Abi::Vector { .. } => Class::Sse, + Abi::Vector { .. } => Class::Sse, - abi::Abi::ScalarPair(..) | - abi::Abi::Aggregate { .. } => { + Abi::ScalarPair(..) | + Abi::Aggregate { .. } => { match layout.variants { abi::Variants::Single { .. } => { for i in 0..layout.fields.count() { @@ -161,7 +161,7 @@ fn reg_component(cls: &[Option], i: &mut usize, size: Size) -> Option bug!("reg_component: unhandled class {:?}", c) + Some(c) => unreachable!("reg_component: unhandled class {:?}", c) } } diff --git a/src/librustc_trans/cabi_x86_win64.rs b/src/librustc_target/abi/call/x86_win64.rs similarity index 85% rename from src/librustc_trans/cabi_x86_win64.rs rename to src/librustc_target/abi/call/x86_win64.rs index 12578162fa12a..1ee069e2bbbbf 100644 --- a/src/librustc_trans/cabi_x86_win64.rs +++ b/src/librustc_target/abi/call/x86_win64.rs @@ -8,18 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use abi::{ArgType, FnType, Reg}; - -use rustc_target::abi; +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(fty: &mut FnType) { let fixup = |a: &mut ArgType| { match a.layout.abi { - abi::Abi::Uninhabited => {} - abi::Abi::ScalarPair(..) | - abi::Abi::Aggregate { .. } => { + Abi::Uninhabited => {} + Abi::ScalarPair(..) | + Abi::Aggregate { .. } => { match a.layout.size.bits() { 8 => a.cast_to(Reg::i8()), 16 => a.cast_to(Reg::i16()), @@ -28,11 +27,11 @@ pub fn compute_abi_info(fty: &mut FnType) { _ => a.make_indirect() } } - abi::Abi::Vector { .. } => { + Abi::Vector { .. } => { // FIXME(eddyb) there should be a size cap here // (probably what clang calls "illegal vectors"). } - abi::Abi::Scalar(_) => { + Abi::Scalar(_) => { if a.layout.size.bytes() > 8 { a.make_indirect(); } else { diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 51e3921a543ee..73c72a15b05a3 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -13,36 +13,16 @@ use base; use builder::Builder; use common::{ty_fn_sig, C_usize}; use context::CodegenCx; -use cabi_x86; -use cabi_x86_64; -use cabi_x86_win64; -use cabi_arm; -use cabi_aarch64; -use cabi_powerpc; -use cabi_powerpc64; -use cabi_s390x; -use cabi_mips; -use cabi_mips64; -use cabi_asmjs; -use cabi_msp430; -use cabi_sparc; -use cabi_sparc64; -use cabi_nvptx; -use cabi_nvptx64; -use cabi_hexagon; -use cabi_wasm32; use mir::place::PlaceRef; use mir::operand::OperandValue; use type_::Type; use type_of::{LayoutLlvmExt, PointerKind}; -use rustc_target::abi::{HasDataLayout, LayoutOf, Size, TyLayout, TyLayoutMethods}; -use rustc_target::spec::HasTargetSpec; +use rustc_target::abi::{LayoutOf, Size, TyLayout}; use rustc::ty::{self, Ty}; use rustc::ty::layout; use libc::c_uint; -use std::cmp; pub use syntax::abi::Abi; pub use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA}; @@ -144,108 +124,6 @@ impl LlvmType for Reg { } } -pub trait LayoutExt<'a, Ty>: Sized { - fn is_aggregate(&self) -> bool; - fn homogeneous_aggregate(&self, cx: C) -> Option - where Ty: TyLayoutMethods<'a, C> + Copy, C: LayoutOf + Copy; -} - -impl<'a, Ty> LayoutExt<'a, Ty> for TyLayout<'a, Ty> { - fn is_aggregate(&self) -> bool { - match self.abi { - layout::Abi::Uninhabited | - layout::Abi::Scalar(_) | - layout::Abi::Vector { .. } => false, - layout::Abi::ScalarPair(..) | - layout::Abi::Aggregate { .. } => true - } - } - - fn homogeneous_aggregate(&self, cx: C) -> Option - where Ty: TyLayoutMethods<'a, C> + Copy, C: LayoutOf + Copy - { - match self.abi { - layout::Abi::Uninhabited => None, - - // The primitive for this algorithm. - layout::Abi::Scalar(ref scalar) => { - let kind = match scalar.value { - layout::Int(..) | - layout::Pointer => RegKind::Integer, - layout::F32 | - layout::F64 => RegKind::Float - }; - Some(Reg { - kind, - size: self.size - }) - } - - layout::Abi::Vector { .. } => { - Some(Reg { - kind: RegKind::Vector, - size: self.size - }) - } - - layout::Abi::ScalarPair(..) | - layout::Abi::Aggregate { .. } => { - let mut total = Size::from_bytes(0); - let mut result = None; - - let is_union = match self.fields { - layout::FieldPlacement::Array { count, .. } => { - if count > 0 { - return self.field(cx, 0).homogeneous_aggregate(cx); - } else { - return None; - } - } - layout::FieldPlacement::Union(_) => true, - layout::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 = cmp::max(total, size); - } else { - total += size; - } - } - - // There needs to be no padding. - if total != self.size { - None - } else { - result - } - } - } - } -} - impl LlvmType for CastTarget { fn llvm_type(&self, cx: &CodegenCx) -> Type { let rest_ll_unit = self.rest.unit.llvm_type(cx); @@ -282,99 +160,16 @@ impl LlvmType for CastTarget { } } -/// Information about how to pass an argument to, -/// or return a value from, a function, under some ABI. -#[derive(Debug)] -pub struct ArgType<'tcx, Ty = ty::Ty<'tcx>> { - pub layout: TyLayout<'tcx, Ty>, - - /// Dummy argument, which is emitted before the real argument. - pub pad: Option, - - pub mode: PassMode, +pub trait ArgTypeExt<'a, 'tcx> { + fn memory_ty(&self, cx: &CodegenCx<'a, 'tcx>) -> Type; + fn store(&self, bx: &Builder<'a, 'tcx>, val: ValueRef, dst: PlaceRef<'tcx>); + fn store_fn_arg(&self, bx: &Builder<'a, 'tcx>, idx: &mut usize, dst: PlaceRef<'tcx>); } -impl<'a, 'tcx, Ty> ArgType<'tcx, Ty> { - fn new(layout: TyLayout<'tcx, 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); - } - _ => bug!() - } - } - - pub fn extend_integer_width_to(&mut self, bits: u64) { - // Only integers have signedness - if let layout::Abi::Scalar(ref scalar) = self.layout.abi { - if let layout::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>(&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 - } -} - -impl<'a, 'tcx> ArgType<'tcx> { +impl<'a, 'tcx> ArgTypeExt<'a, 'tcx> for ArgType<'tcx, Ty<'tcx>> { /// Get the LLVM type for a place of the original Rust type of /// this argument/return, i.e. the result of `type_of::type_of`. - pub fn memory_ty(&self, cx: &CodegenCx<'a, 'tcx>) -> Type { + fn memory_ty(&self, cx: &CodegenCx<'a, 'tcx>) -> Type { self.layout.llvm_type(cx) } @@ -382,7 +177,7 @@ impl<'a, 'tcx> ArgType<'tcx> { /// place for the original Rust type of this argument/return. /// Can be used for both storing formal arguments into Rust variables /// or results of call/invoke instructions into their destinations. - pub fn store(&self, bx: &Builder<'a, 'tcx>, val: ValueRef, dst: PlaceRef<'tcx>) { + fn store(&self, bx: &Builder<'a, 'tcx>, val: ValueRef, dst: PlaceRef<'tcx>) { if self.is_ignore() { return; } @@ -434,7 +229,7 @@ impl<'a, 'tcx> ArgType<'tcx> { } } - pub fn store_fn_arg(&self, bx: &Builder<'a, 'tcx>, idx: &mut usize, dst: PlaceRef<'tcx>) { + fn store_fn_arg(&self, bx: &Builder<'a, 'tcx>, idx: &mut usize, dst: PlaceRef<'tcx>) { let mut next = || { let val = llvm::get_param(bx.llfn(), *idx as c_uint); *idx += 1; @@ -452,26 +247,29 @@ impl<'a, 'tcx> ArgType<'tcx> { } } -/// 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<'tcx, Ty = ty::Ty<'tcx>> { - /// The LLVM types of each argument. - pub args: Vec>, - - /// LLVM return type. - pub ret: ArgType<'tcx, Ty>, - - pub variadic: bool, - - pub cconv: llvm::CallConv +pub trait FnTypeExt<'a, 'tcx> { + fn of_instance(cx: &CodegenCx<'a, 'tcx>, instance: &ty::Instance<'tcx>) + -> Self; + fn new(cx: &CodegenCx<'a, 'tcx>, + sig: ty::FnSig<'tcx>, + extra_args: &[Ty<'tcx>]) -> Self; + fn new_vtable(cx: &CodegenCx<'a, 'tcx>, + sig: ty::FnSig<'tcx>, + extra_args: &[Ty<'tcx>]) -> Self; + fn unadjusted(cx: &CodegenCx<'a, 'tcx>, + sig: ty::FnSig<'tcx>, + extra_args: &[Ty<'tcx>]) -> Self; + fn adjust_for_abi(&mut self, + cx: &CodegenCx<'a, 'tcx>, + abi: Abi); + fn llvm_type(&self, cx: &CodegenCx<'a, 'tcx>) -> Type; + fn llvm_cconv(&self) -> llvm::CallConv; + fn apply_attrs_llfn(&self, llfn: ValueRef); + fn apply_attrs_callsite(&self, callsite: ValueRef); } -impl<'a, 'tcx> FnType<'tcx> { - pub fn of_instance(cx: &CodegenCx<'a, 'tcx>, instance: &ty::Instance<'tcx>) +impl<'a, 'tcx> FnTypeExt<'a, 'tcx> for FnType<'tcx, Ty<'tcx>> { + fn of_instance(cx: &CodegenCx<'a, 'tcx>, instance: &ty::Instance<'tcx>) -> Self { let fn_ty = instance.ty(cx.tcx); let sig = ty_fn_sig(cx, fn_ty); @@ -479,7 +277,7 @@ impl<'a, 'tcx> FnType<'tcx> { FnType::new(cx, sig, &[]) } - pub fn new(cx: &CodegenCx<'a, 'tcx>, + fn new(cx: &CodegenCx<'a, 'tcx>, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self { let mut fn_ty = FnType::unadjusted(cx, sig, extra_args); @@ -487,7 +285,7 @@ impl<'a, 'tcx> FnType<'tcx> { fn_ty } - pub fn new_vtable(cx: &CodegenCx<'a, 'tcx>, + fn new_vtable(cx: &CodegenCx<'a, 'tcx>, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self { let mut fn_ty = FnType::unadjusted(cx, sig, extra_args); @@ -512,34 +310,34 @@ impl<'a, 'tcx> FnType<'tcx> { fn_ty } - pub fn unadjusted(cx: &CodegenCx<'a, 'tcx>, + fn unadjusted(cx: &CodegenCx<'a, 'tcx>, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self { debug!("FnType::unadjusted({:?}, {:?})", sig, extra_args); use self::Abi::*; - let cconv = match cx.sess().target.target.adjust_abi(sig.abi) { + let conv = match cx.sess().target.target.adjust_abi(sig.abi) { RustIntrinsic | PlatformIntrinsic | - Rust | RustCall => llvm::CCallConv, + Rust | RustCall => Conv::C, // It's the ABI's job to select this, not us. System => bug!("system abi should be selected elsewhere"), - Stdcall => llvm::X86StdcallCallConv, - Fastcall => llvm::X86FastcallCallConv, - Vectorcall => llvm::X86_VectorCall, - Thiscall => llvm::X86_ThisCall, - C => llvm::CCallConv, - Unadjusted => llvm::CCallConv, - Win64 => llvm::X86_64_Win64, - SysV64 => llvm::X86_64_SysV, - Aapcs => llvm::ArmAapcsCallConv, - PtxKernel => llvm::PtxKernel, - Msp430Interrupt => llvm::Msp430Intr, - X86Interrupt => llvm::X86_Intr, + Stdcall => Conv::X86Stdcall, + Fastcall => Conv::X86Fastcall, + Vectorcall => Conv::X86VectorCall, + Thiscall => Conv::X86ThisCall, + C => Conv::C, + Unadjusted => Conv::C, + Win64 => Conv::X86_64Win64, + SysV64 => Conv::X86_64SysV, + Aapcs => Conv::ArmAapcs, + PtxKernel => Conv::PtxKernel, + Msp430Interrupt => Conv::Msp430Intr, + X86Interrupt => Conv::X86Intr, // These API constants ought to be more specific... - Cdecl => llvm::CCallConv, + Cdecl => Conv::C, }; let mut inputs = sig.inputs(); @@ -682,7 +480,7 @@ impl<'a, 'tcx> FnType<'tcx> { arg_of(ty, false) }).collect(), variadic: sig.variadic, - cconv, + conv, } } @@ -693,7 +491,7 @@ impl<'a, 'tcx> FnType<'tcx> { if abi == Abi::Rust || abi == Abi::RustCall || abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { - let fixup = |arg: &mut ArgType<'tcx>| { + let fixup = |arg: &mut ArgType<'tcx, Ty<'tcx>>| { if arg.is_ignore() { return; } match arg.layout.abi { @@ -753,63 +551,8 @@ impl<'a, 'tcx> FnType<'tcx> { cx.sess().fatal(&msg); } } -} -impl<'a, Ty> FnType<'a, Ty> { - fn adjust_for_cabi(&mut self, cx: C, abi: Abi) -> Result<(), String> - where Ty: TyLayoutMethods<'a, C> + Copy, - C: LayoutOf> + HasDataLayout + HasTargetSpec - { - match &cx.target_spec().arch[..] { - "x86" => { - let flavor = if abi == Abi::Fastcall { - cabi_x86::Flavor::Fastcall - } else { - cabi_x86::Flavor::General - }; - cabi_x86::compute_abi_info(cx, self, flavor); - }, - "x86_64" => if abi == Abi::SysV64 { - cabi_x86_64::compute_abi_info(cx, self); - } else if abi == Abi::Win64 || cx.target_spec().options.is_like_windows { - cabi_x86_win64::compute_abi_info(self); - } else { - cabi_x86_64::compute_abi_info(cx, self); - }, - "aarch64" => cabi_aarch64::compute_abi_info(cx, self), - "arm" => cabi_arm::compute_abi_info(cx, self), - "mips" => cabi_mips::compute_abi_info(cx, self), - "mips64" => cabi_mips64::compute_abi_info(cx, self), - "powerpc" => cabi_powerpc::compute_abi_info(cx, self), - "powerpc64" => cabi_powerpc64::compute_abi_info(cx, self), - "s390x" => cabi_s390x::compute_abi_info(cx, self), - "asmjs" => cabi_asmjs::compute_abi_info(cx, self), - "wasm32" => { - if cx.target_spec().llvm_target.contains("emscripten") { - cabi_asmjs::compute_abi_info(cx, self) - } else { - cabi_wasm32::compute_abi_info(self) - } - } - "msp430" => cabi_msp430::compute_abi_info(self), - "sparc" => cabi_sparc::compute_abi_info(cx, self), - "sparc64" => cabi_sparc64::compute_abi_info(cx, self), - "nvptx" => cabi_nvptx::compute_abi_info(self), - "nvptx64" => cabi_nvptx64::compute_abi_info(self), - "hexagon" => cabi_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(()) - } -} - -impl<'a, 'tcx> FnType<'tcx> { - pub fn llvm_type(&self, cx: &CodegenCx<'a, 'tcx>) -> Type { + fn llvm_type(&self, cx: &CodegenCx<'a, 'tcx>) -> Type { let mut llargument_tys = Vec::new(); let llreturn_ty = match self.ret.mode { @@ -851,7 +594,23 @@ impl<'a, 'tcx> FnType<'tcx> { } } - pub fn apply_attrs_llfn(&self, llfn: ValueRef) { + fn llvm_cconv(&self) -> llvm::CallConv { + match self.conv { + Conv::C => llvm::CCallConv, + Conv::ArmAapcs => llvm::ArmAapcsCallConv, + Conv::Msp430Intr => llvm::Msp430Intr, + Conv::PtxKernel => llvm::PtxKernel, + Conv::X86Fastcall => llvm::X86FastcallCallConv, + Conv::X86Intr => llvm::X86_Intr, + Conv::X86Stdcall => llvm::X86StdcallCallConv, + Conv::X86ThisCall => llvm::X86_ThisCall, + Conv::X86VectorCall => llvm::X86_VectorCall, + Conv::X86_64SysV => llvm::X86_64_SysV, + Conv::X86_64Win64 => llvm::X86_64_Win64, + } + } + + fn apply_attrs_llfn(&self, llfn: ValueRef) { let mut i = 0; let mut apply = |attrs: &ArgAttributes| { attrs.apply_llfn(llvm::AttributePlace::Argument(i), llfn); @@ -881,7 +640,7 @@ impl<'a, 'tcx> FnType<'tcx> { } } - pub fn apply_attrs_callsite(&self, callsite: ValueRef) { + fn apply_attrs_callsite(&self, callsite: ValueRef) { let mut i = 0; let mut apply = |attrs: &ArgAttributes| { attrs.apply_callsite(llvm::AttributePlace::Argument(i), callsite); @@ -910,8 +669,9 @@ impl<'a, 'tcx> FnType<'tcx> { } } - if self.cconv != llvm::CCallConv { - llvm::SetInstructionCallConv(callsite, self.cconv); + let cconv = self.llvm_cconv(); + if cconv != llvm::CCallConv { + llvm::SetInstructionCallConv(callsite, cconv); } } } diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs index 200c4c270e775..bbe4e18b18cb1 100644 --- a/src/librustc_trans/declare.rs +++ b/src/librustc_trans/declare.rs @@ -25,7 +25,7 @@ use llvm::AttributePlace::Function; use rustc::ty::{self, Ty}; use rustc::session::config::Sanitizer; use rustc_target::spec::PanicStrategy; -use abi::{Abi, FnType}; +use abi::{Abi, FnType, FnTypeExt}; use attributes; use context::CodegenCx; use common; @@ -131,7 +131,7 @@ pub fn declare_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, name: &str, debug!("declare_rust_fn (after region erasure) sig={:?}", sig); let fty = FnType::new(cx, sig, &[]); - let llfn = declare_raw_fn(cx, name, fty.cconv, fty.llvm_type(cx)); + let llfn = declare_raw_fn(cx, name, fty.llvm_cconv(), fty.llvm_type(cx)); // FIXME(canndrew): This is_never should really be an is_uninhabited if sig.output().is_never() { diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 7594085488ff0..103b04e6f135b 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -87,7 +87,7 @@ fn get_simple_intrinsic(cx: &CodegenCx, name: &str) -> Option { /// add them to librustc_trans/trans/context.rs pub fn trans_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, callee_ty: Ty<'tcx>, - fn_ty: &FnType<'tcx>, + fn_ty: &FnType<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx>], llresult: ValueRef, span: Span) { diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 2fa43e4440b4e..dab01abd3353a 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -102,24 +102,6 @@ mod asm; mod attributes; mod base; mod builder; -mod cabi_aarch64; -mod cabi_arm; -mod cabi_asmjs; -mod cabi_hexagon; -mod cabi_mips; -mod cabi_mips64; -mod cabi_msp430; -mod cabi_nvptx; -mod cabi_nvptx64; -mod cabi_powerpc; -mod cabi_powerpc64; -mod cabi_s390x; -mod cabi_sparc; -mod cabi_sparc64; -mod cabi_x86; -mod cabi_x86_64; -mod cabi_x86_win64; -mod cabi_wasm32; mod callee; mod common; mod consts; diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index 6b542ae2e9364..21bbdf31dcb52 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -9,7 +9,7 @@ // except according to those terms. use llvm::ValueRef; -use abi::FnType; +use abi::{FnType, FnTypeExt}; use callee; use common::*; use builder::Builder; @@ -35,7 +35,7 @@ impl<'a, 'tcx> VirtualIndex { pub fn get_fn(self, bx: &Builder<'a, 'tcx>, llvtable: ValueRef, - fn_ty: &FnType<'tcx>) -> ValueRef { + fn_ty: &FnType<'tcx, Ty<'tcx>>) -> ValueRef { // Load the data pointer from the object. debug!("get_fn({:?}, {:?})", Value(llvtable), self); diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 973bd3d5baad6..36f03605feabd 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -10,10 +10,10 @@ use llvm::{self, ValueRef, BasicBlockRef}; use rustc::middle::lang_items; -use rustc::ty::{self, TypeFoldable}; +use rustc::ty::{self, Ty, TypeFoldable}; use rustc::ty::layout::{self, LayoutOf}; use rustc::mir; -use abi::{Abi, FnType, ArgType, LlvmType, PassMode}; +use abi::{Abi, ArgType, ArgTypeExt, FnType, FnTypeExt, LlvmType, PassMode}; use base; use callee; use builder::Builder; @@ -110,7 +110,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { let do_call = | this: &mut Self, bx: Builder<'a, 'tcx>, - fn_ty: FnType<'tcx>, + fn_ty: FnType<'tcx, Ty<'tcx>>, fn_ptr: ValueRef, llargs: &[ValueRef], destination: Option<(ReturnDest<'tcx>, mir::BasicBlock)>, @@ -604,7 +604,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { bx: &Builder<'a, 'tcx>, op: OperandRef<'tcx>, llargs: &mut Vec, - arg: &ArgType<'tcx>) { + arg: &ArgType<'tcx, Ty<'tcx>>) { // Fill padding with undef value, where applicable. if let Some(ty) = arg.pad { llargs.push(C_undef(ty.llvm_type(bx.cx))); @@ -683,7 +683,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { bx: &Builder<'a, 'tcx>, operand: &mir::Operand<'tcx>, llargs: &mut Vec, - args: &[ArgType<'tcx>]) { + args: &[ArgType<'tcx, Ty<'tcx>>]) { let tuple = self.trans_operand(bx, operand); // Handle both by-ref and immediate tuples. @@ -776,7 +776,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { } fn make_return_dest(&mut self, bx: &Builder<'a, 'tcx>, - dest: &mir::Place<'tcx>, fn_ret: &ArgType<'tcx>, + dest: &mir::Place<'tcx>, fn_ret: &ArgType<'tcx, Ty<'tcx>>, llargs: &mut Vec, is_intrinsic: bool) -> ReturnDest<'tcx> { // If the return is ignored, we can just return a do-nothing ReturnDest @@ -873,7 +873,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { fn store_return(&mut self, bx: &Builder<'a, 'tcx>, dest: ReturnDest<'tcx>, - ret_ty: &ArgType<'tcx>, + ret_ty: &ArgType<'tcx, Ty<'tcx>>, llval: ValueRef) { use self::ReturnDest::*; diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index c55836919a97f..a074f25dfc9ba 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -12,7 +12,7 @@ use common::{C_i32, C_null}; use libc::c_uint; use llvm::{self, ValueRef, BasicBlockRef}; use llvm::debuginfo::DIScope; -use rustc::ty::{self, TypeFoldable}; +use rustc::ty::{self, Ty, TypeFoldable}; use rustc::ty::layout::{LayoutOf, TyLayout}; use rustc::mir::{self, Mir}; use rustc::ty::subst::Substs; @@ -22,7 +22,7 @@ use builder::Builder; use common::{CodegenCx, Funclet}; use debuginfo::{self, declare_local, VariableAccess, VariableKind, FunctionDebugContext}; use monomorphize::Instance; -use abi::{ArgAttribute, FnType, PassMode}; +use abi::{ArgAttribute, ArgTypeExt, FnType, FnTypeExt, PassMode}; use type_::Type; use syntax_pos::{DUMMY_SP, NO_EXPANSION, BytePos, Span}; @@ -53,7 +53,7 @@ pub struct FunctionCx<'a, 'tcx:'a> { cx: &'a CodegenCx<'a, 'tcx>, - fn_ty: FnType<'tcx>, + fn_ty: FnType<'tcx, Ty<'tcx>>, /// When unwinding is initiated, we have to store this personality /// value somewhere so that we can load it and re-use it in the diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index 7cad0e73db25b..5e6b276495764 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use abi::FnType; +use abi::{FnType, FnTypeExt}; use common::*; use rustc::hir; use rustc::ty::{self, Ty, TypeFoldable};