about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJames Cowgill <jcowgill@debian.org>2018-02-14 12:47:38 +0000
committerJames Cowgill <jcowgill@debian.org>2018-02-14 14:38:55 +0000
commit05d66dc7a4ff053b5cbfa5ddafa890af291f4fc2 (patch)
treeb656c0202d7288fcb048f43983670e55eaddf53f
parent68042ba0d35f16d66dadf62334ca6bbf20d97268 (diff)
downloadrust-05d66dc7a4ff053b5cbfa5ddafa890af291f4fc2.tar.gz
rust-05d66dc7a4ff053b5cbfa5ddafa890af291f4fc2.zip
rustc_trans: add chunked prefix fields to CastTarget
-rw-r--r--src/librustc_trans/abi.rs138
-rw-r--r--src/librustc_trans/cabi_x86_64.rs2
2 files changed, 53 insertions, 87 deletions
diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs
index 60f3105170b..ee0f2415bd8 100644
--- a/src/librustc_trans/abi.rs
+++ b/src/librustc_trans/abi.rs
@@ -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 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)
     }
 }
 
diff --git a/src/librustc_trans/cabi_x86_64.rs b/src/librustc_trans/cabi_x86_64.rs
index b8144a3ca7a..7eadaa7f493 100644
--- a/src/librustc_trans/cabi_x86_64.rs
+++ b/src/librustc_trans/cabi_x86_64.rs
@@ -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);