rustc_trans: add chunked prefix fields to CastTarget
This commit is contained in:
parent
68042ba0d3
commit
05d66dc7a4
@ -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};
|
||||
@ -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> {
|
||||
@ -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 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();
|
||||
|
||||
let int_ll_type = Reg { kind: RegKind::Integer, size: chunk }.llvm_type(cx);
|
||||
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);
|
||||
}
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
||||
Type::struct_(cx, &args, false)
|
||||
// Simplify to array when all chunks are the same size and type
|
||||
if rem_bytes == 0 {
|
||||
return Type::array(&rest_ll_unit, rest_count);
|
||||
}
|
||||
}
|
||||
|
||||
// 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();
|
||||
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user