Skip to content

Commit

Permalink
rustc_trans: add chunked prefix fields to CastTarget
Browse files Browse the repository at this point in the history
  • Loading branch information
jcowgill committed Feb 14, 2018
1 parent 68042ba commit 05d66dc
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 87 deletions.
138 changes: 52 additions & 86 deletions src/librustc_trans/abi.rs
Expand Up @@ -40,7 +40,7 @@ use rustc::ty::layout::{self, Align, Size, TyLayout};
use rustc::ty::layout::{HasDataLayout, LayoutOf};

use libc::c_uint;
use std::{cmp, iter};
use std::cmp;

pub use syntax::abi::Abi;
pub use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
Expand Down Expand Up @@ -279,30 +279,6 @@ impl Uniform {
pub fn align(&self, cx: &CodegenCx) -> Align {
self.unit.align(cx)
}

pub fn llvm_type(&self, cx: &CodegenCx) -> Type {
let llunit = self.unit.llvm_type(cx);

if self.total <= self.unit.size {
return llunit;
}

let count = self.total.bytes() / self.unit.size.bytes();
let rem_bytes = self.total.bytes() % self.unit.size.bytes();

if rem_bytes == 0 {
return Type::array(&llunit, count);
}

// Only integers can be really split further.
assert_eq!(self.unit.kind, RegKind::Integer);

let args: Vec<_> = (0..count).map(|_| llunit)
.chain(iter::once(Type::ix(cx, rem_bytes * 8)))
.collect();

Type::struct_(cx, &args, false)
}
}

pub trait LayoutExt<'tcx> {
Expand Down Expand Up @@ -405,91 +381,81 @@ impl<'tcx> LayoutExt<'tcx> for TyLayout<'tcx> {
}

#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum CastTarget {
Uniform(Uniform),
Pair(Reg, Reg),
ChunkedPrefix { prefix: [RegKind; 8], chunk: Size, total: Size }
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::Uniform(Uniform::from(unit))
CastTarget::from(Uniform::from(unit))
}
}

impl From<Uniform> for CastTarget {
fn from(uniform: Uniform) -> CastTarget {
CastTarget::Uniform(uniform)
CastTarget {
prefix: [None; 8],
prefix_chunk: Size::from_bytes(0),
rest: uniform
}
}
}

impl CastTarget {
pub fn size(&self, cx: &CodegenCx) -> Size {
match *self {
CastTarget::Uniform(u) => u.total,
CastTarget::Pair(a, b) => {
(a.size.abi_align(a.align(cx)) + b.size)
.abi_align(self.align(cx))
},
CastTarget::ChunkedPrefix { total, .. } => total
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: &CodegenCx) -> 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: &CodegenCx) -> Align {
match *self {
CastTarget::Uniform(u) => u.align(cx),
CastTarget::Pair(a, b) => {
cx.data_layout().aggregate_align
.max(a.align(cx))
.max(b.align(cx))
},
CastTarget::ChunkedPrefix { chunk, .. } => {
cx.data_layout().aggregate_align
.max(Reg { kind: RegKind::Integer, size: chunk }.align(cx))
.max(Reg { kind: RegKind::Float, size: chunk }.align(cx))
.max(Reg { kind: RegKind::Vector, size: chunk }.align(cx))
}
}
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))
}

pub fn llvm_type(&self, cx: &CodegenCx) -> Type {
match *self {
CastTarget::Uniform(u) => u.llvm_type(cx),
CastTarget::Pair(a, b) => {
Type::struct_(cx, &[
a.llvm_type(cx),
b.llvm_type(cx)
], false)
},
CastTarget::ChunkedPrefix { prefix, chunk, total } => {
let total_chunks = total.bytes() / chunk.bytes();
let rem_bytes = total.bytes() % chunk.bytes();
let prefix_chunks = total_chunks.min(prefix.len() as u64);

let int_ll_type = Reg { kind: RegKind::Integer, size: chunk }.llvm_type(cx);
let rest_ll_unit = self.rest.unit.llvm_type(cx);
let rest_count = self.rest.total.bytes() / self.rest.unit.size.bytes();
let rem_bytes = self.rest.total.bytes() % self.rest.unit.size.bytes();

if self.prefix.iter().all(|x| x.is_none()) {
// Simplify to a single unit when there is no prefix and size <= unit size
if self.rest.total <= self.rest.unit.size {
return rest_ll_unit;
}

// Simple cases simplify to an array
if rem_bytes == 0 && prefix.into_iter().all(|&kind| kind == RegKind::Integer) {
return Type::array(&int_ll_type, total_chunks);
}
// Simplify to array when all chunks are the same size and type
if rem_bytes == 0 {
return Type::array(&rest_ll_unit, rest_count);
}
}

// The final structure is made up of:
// Up to 8 chunks of the type specified in the prefix
// Any other complete chunks as integers
// One final integer needed to make up the total structure size
let mut args: Vec<_> =
prefix.into_iter().take(prefix_chunks as usize)
.map(|&kind| Reg { kind: kind, size: chunk }.llvm_type(cx))
.chain((0..total_chunks - prefix_chunks).map(|_| int_ll_type))
.collect();

if rem_bytes > 0 {
args.push(Type::ix(cx, rem_bytes * 8));
}
// Create list of fields in the main structure
let mut args: Vec<_> =
self.prefix.iter().flat_map(|option_kind| option_kind.map(
|kind| Reg { kind: kind, size: self.prefix_chunk }.llvm_type(cx)))
.chain((0..rest_count).map(|_| rest_ll_unit))
.collect();

Type::struct_(cx, &args, false)
}
// Append final integer
if rem_bytes != 0 {
// Only integers can be really split further.
assert_eq!(self.rest.unit.kind, RegKind::Integer);
args.push(Type::ix(cx, rem_bytes * 8));
}

Type::struct_(cx, &args, false)
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trans/cabi_x86_64.rs
Expand Up @@ -171,7 +171,7 @@ fn cast_target(cls: &[Option<Class>], size: Size) -> CastTarget {
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);
target = CastTarget::pair(lo, hi);
}
}
assert_eq!(reg_component(cls, &mut i, Size::from_bytes(0)), None);
Expand Down

0 comments on commit 05d66dc

Please sign in to comment.