Skip to content

Commit

Permalink
rustc_trans: use ty::layout for ABI computation instead of LLVM types.
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyb committed Apr 9, 2017
1 parent 43b227f commit f0636b6
Show file tree
Hide file tree
Showing 22 changed files with 992 additions and 1,672 deletions.
585 changes: 400 additions & 185 deletions src/librustc_trans/abi.rs

Large diffs are not rendered by default.

24 changes: 7 additions & 17 deletions src/librustc_trans/adt.rs
Expand Up @@ -95,15 +95,6 @@ pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
generic_type_of(cx, t, None, false, false)
}


// Pass dst=true if the type you are passing is a DST. Yes, we could figure
// this out, but if you call this on an unsized type without realising it, you
// are going to get the wrong type (it will not include the unsized parts of it).
pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
t: Ty<'tcx>, dst: bool) -> Type {
generic_type_of(cx, t, None, true, dst)
}

pub fn incomplete_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
t: Ty<'tcx>, name: &str) -> Type {
generic_type_of(cx, t, Some(name), false, false)
Expand Down Expand Up @@ -149,7 +140,11 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
};
let nnty = monomorphize::field_ty(cx.tcx(), substs,
&def.variants[nndiscr as usize].fields[0]);
type_of::sizing_type_of(cx, nnty)
if let layout::Scalar { value: layout::Pointer, .. } = *cx.layout_of(nnty) {
Type::i8p(cx)
} else {
type_of::type_of(cx, nnty)
}
}
layout::StructWrappedNullablePointer { nndiscr, ref nonnull, .. } => {
let fields = compute_fields(cx, t, nndiscr as usize, false);
Expand Down Expand Up @@ -181,10 +176,6 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
}
}
}
layout::Vector { element, count } => {
let elem_ty = Type::from_primitive(cx, element);
Type::vector(&elem_ty, count)
}
layout::UntaggedUnion { ref variants, .. }=> {
// Use alignment-sized ints to fill all the union storage.
let size = variants.stride().bytes();
Expand Down Expand Up @@ -258,11 +249,10 @@ fn union_fill(cx: &CrateContext, size: u64, align: u64) -> Type {

fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fields: &Vec<Ty<'tcx>>,
variant: &layout::Struct,
sizing: bool, dst: bool) -> Vec<Type> {
sizing: bool, _dst: bool) -> Vec<Type> {
let fields = variant.field_index_by_increasing_offset().map(|i| fields[i as usize]);
if sizing {
fields.filter(|ty| !dst || cx.shared().type_is_sized(*ty))
.map(|ty| type_of::sizing_type_of(cx, ty)).collect()
bug!()
} else {
fields.map(|ty| type_of::in_memory_type_of(cx, ty)).collect()
}
Expand Down
178 changes: 57 additions & 121 deletions src/librustc_trans/cabi_aarch64.rs
Expand Up @@ -8,163 +8,99 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(non_upper_case_globals)]

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

fn ty_size(ty: Type) -> usize {
abi::ty_size(ty, 8)
}

fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> {
fn check_array(ty: Type) -> Option<(Type, u64)> {
let len = ty.array_length() as u64;
if len == 0 {
return None
}
let elt = ty.element_type();

// if our element is an HFA/HVA, so are we; multiply members by our len
is_homogenous_aggregate_ty(elt).map(|(base_ty, members)| (base_ty, len * members))
}

fn check_struct(ty: Type) -> Option<(Type, u64)> {
let str_tys = ty.field_types();
if str_tys.len() == 0 {
return None
}

let mut prev_base_ty = None;
let mut members = 0;
for opt_homog_agg in str_tys.iter().map(|t| is_homogenous_aggregate_ty(*t)) {
match (prev_base_ty, opt_homog_agg) {
// field isn't itself an HFA, so we aren't either
(_, None) => return None,

// first field - store its type and number of members
(None, Some((field_ty, field_members))) => {
prev_base_ty = Some(field_ty);
members = field_members;
},

// 2nd or later field - give up if it's a different type; otherwise incr. members
(Some(prev_ty), Some((field_ty, field_members))) => {
if prev_ty != field_ty {
return None;
}
members += field_members;
}
}
}

// Because of previous checks, we know prev_base_ty is Some(...) because
// 1. str_tys has at least one element; and
// 2. prev_base_ty was filled in (or we would've returned early)
let (base_ty, members) = (prev_base_ty.unwrap(), members);
fn is_homogenous_aggregate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>)
-> Option<Uniform> {
arg.layout.homogenous_aggregate(ccx).and_then(|unit| {
let size = arg.layout.size(ccx);

// Ensure there is no padding.
if ty_size(ty) == ty_size(base_ty) * (members as usize) {
Some((base_ty, members))
} else {
None
// Ensure we have at most four uniquely addressable members.
if size > unit.size.checked_mul(4, ccx).unwrap() {
return None;
}
}

let homog_agg = match ty.kind() {
Float => Some((ty, 1)),
Double => Some((ty, 1)),
Array => check_array(ty),
Struct => check_struct(ty),
Vector => match ty_size(ty) {
4|8 => Some((ty, 1)),
_ => None
},
_ => None
};
let valid_unit = match unit.kind {
RegKind::Integer => false,
RegKind::Float => true,
RegKind::Vector => size.bits() == 64 || size.bits() == 128
};

// Ensure we have at most four uniquely addressable members
homog_agg.and_then(|(base_ty, members)| {
if members > 0 && members <= 4 {
Some((base_ty, members))
if valid_unit {
Some(Uniform {
unit,
total: size
})
} else {
None
}
})
}

fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
if is_reg_ty(ret.ty) {
fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
if !ret.layout.is_aggregate() {
ret.extend_integer_width_to(32);
return;
}
if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ret.ty) {
ret.cast = Some(Type::array(&base_ty, members));
if let Some(uniform) = is_homogenous_aggregate(ccx, ret) {
ret.cast_to(ccx, uniform);
return;
}
let size = ty_size(ret.ty);
if size <= 16 {
let llty = if size <= 1 {
Type::i8(ccx)
} else if size <= 2 {
Type::i16(ccx)
} else if size <= 4 {
Type::i32(ccx)
} else if size <= 8 {
Type::i64(ccx)
let size = ret.layout.size(ccx);
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 {
Type::array(&Type::i64(ccx), ((size + 7 ) / 8 ) as u64)
Reg::i64()
};
ret.cast = Some(llty);

ret.cast_to(ccx, Uniform {
unit,
total: size
});
return;
}
ret.make_indirect(ccx);
}

fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
if is_reg_ty(arg.ty) {
fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
if !arg.layout.is_aggregate() {
arg.extend_integer_width_to(32);
return;
}
if let Some((base_ty, members)) = is_homogenous_aggregate_ty(arg.ty) {
arg.cast = Some(Type::array(&base_ty, members));
if let Some(uniform) = is_homogenous_aggregate(ccx, arg) {
arg.cast_to(ccx, uniform);
return;
}
let size = ty_size(arg.ty);
if size <= 16 {
let llty = if size == 0 {
Type::array(&Type::i64(ccx), 0)
} else if size == 1 {
Type::i8(ccx)
} else if size == 2 {
Type::i16(ccx)
} else if size <= 4 {
Type::i32(ccx)
} else if size <= 8 {
Type::i64(ccx)
let size = arg.layout.size(ccx);
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 {
Type::array(&Type::i64(ccx), ((size + 7 ) / 8 ) as u64)
Reg::i64()
};
arg.cast = Some(llty);

arg.cast_to(ccx, Uniform {
unit,
total: size
});
return;
}
arg.make_indirect(ccx);
}

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

pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) {
if !fty.ret.is_ignore() {
classify_ret_ty(ccx, &mut fty.ret);
}
Expand Down

0 comments on commit f0636b6

Please sign in to comment.