about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/etc/platform-intrinsics/generator.py50
-rw-r--r--src/etc/platform-intrinsics/x86/avx.json2
-rw-r--r--src/etc/platform-intrinsics/x86/avx2.json14
-rw-r--r--src/etc/platform-intrinsics/x86/sse41.json4
-rw-r--r--src/etc/platform-intrinsics/x86/sse42.json28
-rwxr-xr-xsrc/librustc_platform_intrinsics/lib.rs9
-rw-r--r--src/librustc_platform_intrinsics/x86.rs48
-rw-r--r--src/librustc_trans/trans/intrinsic.rs47
-rw-r--r--src/librustc_typeck/check/intrinsic.rs3
9 files changed, 136 insertions, 69 deletions
diff --git a/src/etc/platform-intrinsics/generator.py b/src/etc/platform-intrinsics/generator.py
index 7f5a737e33e..97b2f57010b 100644
--- a/src/etc/platform-intrinsics/generator.py
+++ b/src/etc/platform-intrinsics/generator.py
@@ -16,7 +16,8 @@ import re
 import textwrap
 
 SPEC = re.compile(
-    r'^(?:(?P<id>[iusfIUSF])(?:\((?P<start>\d*)-(?P<end>\d*)\)|(?P<width>\d*))' +
+    r'^(?:(?P<id>[iusfIUSF])(?:\((?P<start>\d+)-(?P<end>\d+)\)|'
+    r'(?P<width>\d+)(:?/(?P<llvm_width>\d+))?)'
     r'|(?P<reference>\d+)(?P<modifiers>[vShdnwus]*)(?P<force_width>x\d+)?)$'
 )
 
@@ -111,27 +112,39 @@ class Number(Type):
         return platform_info.number_type_info(self)
 
 class Signed(Number):
-    def __init__(self, bitwidth):
+    def __init__(self, bitwidth, llvm_bitwidth = None):
         Number.__init__(self, bitwidth)
+        self._llvm_bitwidth = llvm_bitwidth
 
     def compiler_ctor(self):
-        return 'i({})'.format(self.bitwidth())
+        if self._llvm_bitwidth is None:
+            return 'i({})'.format(self.bitwidth())
+        else:
+            return 'i_({}, {})'.format(self.bitwidth(),
+                                       self._llvm_bitwidth)
 
     def llvm_name(self):
-        return 'i{}'.format(self.bitwidth())
+        bw = self._llvm_bitwidth or self.bitwidth()
+        return 'i{}'.format(bw)
 
     def rust_name(self):
         return 'i{}'.format(self.bitwidth())
 
 class Unsigned(Number):
-    def __init__(self, bitwidth):
+    def __init__(self, bitwidth, llvm_bitwidth = None):
         Number.__init__(self, bitwidth)
+        self._llvm_bitwidth = llvm_bitwidth
 
     def compiler_ctor(self):
-        return 'u({})'.format(self.bitwidth())
+        if self._llvm_bitwidth is None:
+            return 'u({})'.format(self.bitwidth())
+        else:
+            return 'u_({}, {})'.format(self.bitwidth(),
+                                       self._llvm_bitwidth)
 
     def llvm_name(self):
-        return 'i{}'.format(self.bitwidth())
+        bw = self._llvm_bitwidth or self.bitwidth()
+        return 'i{}'.format(bw)
 
     def rust_name(self):
         return 'u{}'.format(self.bitwidth())
@@ -220,18 +233,28 @@ class TypeSpec(object):
                 id = match.group('id')
                 is_vector = id.islower()
                 type_ctors = TYPE_ID_LOOKUP[id.lower()]
+
                 start = match.group('start')
                 if start is not None:
                     end = match.group('end')
+                    llvm_width = None
                 else:
                     start = end = match.group('width')
+                    llvm_width = match.group('llvm_width')
                 start = int(start)
                 end = int(end)
 
                 bitwidth = start
                 while bitwidth <= end:
                     for ctor in type_ctors:
-                        scalar = ctor(bitwidth)
+                        if llvm_width is not None:
+                            assert not is_vector
+                            llvm_width = int(llvm_width)
+                            assert llvm_width < bitwidth
+                            scalar = ctor(bitwidth, llvm_width)
+                        else:
+                            scalar = ctor(bitwidth)
+
                         if is_vector:
                             yield Vector(scalar, width // bitwidth)
                         else:
@@ -351,8 +374,9 @@ def parse_args():
         vector := vector_elem width |
         vector_elem := 'i' | 'u' | 's' | 'f'
 
-        scalar := scalar_type number
+        scalar := scalar_type number llvm_width?
         scalar_type := 'U' | 'S' | 'F'
+        llvm_width := '/' number
 
         aggregate := '(' (type),* ')' 'f'?
 
@@ -387,7 +411,11 @@ def parse_args():
         ## Scalars
 
         Similar to vectors, but these describe a single concrete type,
-        not a range. The number is the bitwidth.
+        not a range. The number is the bitwidth. The optional
+        `llvm_width` is the bitwidth of the integer that should be
+        passed to LLVM (by truncating the Rust argument): this only
+        works with scalar integers and the LLVM width must be smaller
+        than the Rust width.
 
         ### Types
 
@@ -474,7 +502,7 @@ class CompilerDefs(object):
 
 #![allow(unused_imports)]
 
-use {{Intrinsic, i, u, f, v, agg}};
+use {{Intrinsic, i, i_, u, u_, f, v, agg}};
 use IntrinsicDef::Named;
 use rustc::middle::ty;
 
diff --git a/src/etc/platform-intrinsics/x86/avx.json b/src/etc/platform-intrinsics/x86/avx.json
index 7d6a07f7550..4ac82fb90e9 100644
--- a/src/etc/platform-intrinsics/x86/avx.json
+++ b/src/etc/platform-intrinsics/x86/avx.json
@@ -13,7 +13,7 @@
             "width": [256],
             "llvm": "dp.ps.256",
             "ret": "f32",
-            "args": ["0", "0", "S32"]
+            "args": ["0", "0", "S32/8"]
         },
         {
             "intrinsic": "256_hadd_{0.data_type}",
diff --git a/src/etc/platform-intrinsics/x86/avx2.json b/src/etc/platform-intrinsics/x86/avx2.json
index 8b0e53e48cf..bd260ec02e9 100644
--- a/src/etc/platform-intrinsics/x86/avx2.json
+++ b/src/etc/platform-intrinsics/x86/avx2.json
@@ -79,6 +79,20 @@
             "args": ["0", "0"]
         },
         {
+            "intrinsic": "256_movemask_epi8",
+            "width": [256],
+            "llvm": "pmovmskb",
+            "ret": "S32",
+            "args": ["s8"]
+        },
+        {
+            "intrinsic": "256_mpsadbw_epu8",
+            "width": [256],
+            "llvm": "mpsadbw",
+            "ret": "u16",
+            "args": ["u8", "u8", "S32/8"]
+        },
+        {
             "intrinsic": "256_mul_{0.data_type}",
             "width": [256],
             "llvm": "pmul{0.data_type_short}.dq",
diff --git a/src/etc/platform-intrinsics/x86/sse41.json b/src/etc/platform-intrinsics/x86/sse41.json
index 8610dc83bd6..e835320e5cd 100644
--- a/src/etc/platform-intrinsics/x86/sse41.json
+++ b/src/etc/platform-intrinsics/x86/sse41.json
@@ -6,7 +6,7 @@
             "width": [128],
             "llvm": "dp{0.data_type}",
             "ret": "f(32-64)",
-            "args": ["0", "0", "S32"]
+            "args": ["0", "0", "S32/8"]
         },
         {
             "intrinsic": "_max_{0.data_type}",
@@ -34,7 +34,7 @@
             "width": [128],
             "llvm": "mpsadbw",
             "ret": "u16",
-            "args": ["u8", "u8", "S32"]
+            "args": ["u8", "u8", "S32/8"]
         },
         {
             "intrinsic": "_mul_epi32",
diff --git a/src/etc/platform-intrinsics/x86/sse42.json b/src/etc/platform-intrinsics/x86/sse42.json
index e63182d4857..c43ffef0dc5 100644
--- a/src/etc/platform-intrinsics/x86/sse42.json
+++ b/src/etc/platform-intrinsics/x86/sse42.json
@@ -6,98 +6,98 @@
             "width": [128],
             "llvm": "pcmpestria128",
             "ret": "S32",
-            "args": ["s8", "S32", "s8", "S32", "S32"]
+            "args": ["s8", "S32", "s8", "S32", "S32/8"]
         },
         {
             "intrinsic": "_cmpestrc",
             "width": [128],
             "llvm": "pcmpestric128",
             "ret": "S32",
-            "args": ["s8", "S32", "s8", "S32", "S32"]
+            "args": ["s8", "S32", "s8", "S32", "S32/8"]
         },
         {
             "intrinsic": "_cmpestri",
             "width": [128],
             "llvm": "pcmpestri128",
             "ret": "S32",
-            "args": ["s8", "S32", "s8", "S32", "S32"]
+            "args": ["s8", "S32", "s8", "S32", "S32/8"]
         },
         {
             "intrinsic": "_cmpestrm",
             "width": [128],
             "llvm": "pcmpestrm128",
             "ret": "s8",
-            "args": ["s8", "S32", "s8", "S32", "S32"]
+            "args": ["s8", "S32", "s8", "S32", "S32/8"]
         },
         {
             "intrinsic": "_cmpestro",
             "width": [128],
             "llvm": "pcmpestrio128",
             "ret": "S32",
-            "args": ["s8", "S32", "s8", "S32", "S32"]
+            "args": ["s8", "S32", "s8", "S32", "S32/8"]
         },
         {
             "intrinsic": "_cmpestrs",
             "width": [128],
             "llvm": "pcmpestris128",
             "ret": "S32",
-            "args": ["s8", "S32", "s8", "S32", "S32"]
+            "args": ["s8", "S32", "s8", "S32", "S32/8"]
         },
         {
             "intrinsic": "_cmpestrz",
             "width": [128],
             "llvm": "pcmpestriz128",
             "ret": "S32",
-            "args": ["s8", "S32", "s8", "S32", "S32"]
+            "args": ["s8", "S32", "s8", "S32", "S32/8"]
         },
         {
             "intrinsic": "_cmpistra",
             "width": [128],
             "llvm": "pcmpistria128",
             "ret": "S32",
-            "args": ["s8", "s8", "S32"]
+            "args": ["s8", "s8", "S32/8"]
         },
         {
             "intrinsic": "_cmpistrc",
             "width": [128],
             "llvm": "pcmpistric128",
             "ret": "S32",
-            "args": ["s8", "s8", "S32"]
+            "args": ["s8", "s8", "S32/8"]
         },
         {
             "intrinsic": "_cmpistri",
             "width": [128],
             "llvm": "pcmpistri128",
             "ret": "S32",
-            "args": ["s8", "s8", "S32"]
+            "args": ["s8", "s8", "S32/8"]
         },
         {
             "intrinsic": "_cmpistrm",
             "width": [128],
             "llvm": "pcmpistrm128",
             "ret": "s8",
-            "args": ["s8", "s8", "S32"]
+            "args": ["s8", "s8", "S32/8"]
         },
         {
             "intrinsic": "_cmpistro",
             "width": [128],
             "llvm": "pcmpistrio128",
             "ret": "S32",
-            "args": ["s8", "s8", "S32"]
+            "args": ["s8", "s8", "S32/8"]
         },
         {
             "intrinsic": "_cmpistrs",
             "width": [128],
             "llvm": "pcmpistris128",
             "ret": "S32",
-            "args": ["s8", "s8", "S32"]
+            "args": ["s8", "s8", "S32/8"]
         },
         {
             "intrinsic": "_cmpistrz",
             "width": [128],
             "llvm": "pcmpistriz128",
             "ret": "S32",
-            "args": ["s8", "s8", "S32"]
+            "args": ["s8", "s8", "S32/8"]
         }
     ]
 }
diff --git a/src/librustc_platform_intrinsics/lib.rs b/src/librustc_platform_intrinsics/lib.rs
index 5eb09aeb0dc..d58feb4611c 100755
--- a/src/librustc_platform_intrinsics/lib.rs
+++ b/src/librustc_platform_intrinsics/lib.rs
@@ -30,7 +30,7 @@ pub struct Intrinsic {
 
 #[derive(Clone, Hash, Eq, PartialEq)]
 pub enum Type {
-    Integer(/* signed */ bool, u8),
+    Integer(/* signed */ bool, u8, /* llvm width */ u8),
     Float(u8),
     Pointer(Box<Type>),
     Vector(Box<Type>, u8),
@@ -41,8 +41,11 @@ pub enum IntrinsicDef {
     Named(&'static str),
 }
 
-fn i(width: u8) -> Type { Type::Integer(true, width) }
-fn u(width: u8) -> Type { Type::Integer(false, width) }
+fn i(width: u8) -> Type { Type::Integer(true, width, width) }
+fn i_(width: u8, llvm_width: u8) -> Type { Type::Integer(true, width, llvm_width) }
+fn u(width: u8) -> Type { Type::Integer(false, width, width) }
+#[allow(dead_code)]
+fn u_(width: u8, llvm_width: u8) -> Type { Type::Integer(false, width, llvm_width) }
 fn f(width: u8) -> Type { Type::Float(width) }
 fn v(x: Type, length: u8) -> Type { Type::Vector(Box::new(x), length) }
 fn agg(flatten: bool, types: Vec<Type>) -> Type {
diff --git a/src/librustc_platform_intrinsics/x86.rs b/src/librustc_platform_intrinsics/x86.rs
index d86afa7f41f..a6fe8aef0b4 100644
--- a/src/librustc_platform_intrinsics/x86.rs
+++ b/src/librustc_platform_intrinsics/x86.rs
@@ -13,7 +13,7 @@
 
 #![allow(unused_imports)]
 
-use {Intrinsic, i, u, f, v, agg};
+use {Intrinsic, i, i_, u, u_, f, v, agg};
 use IntrinsicDef::Named;
 use rustc::middle::ty;
 
@@ -286,12 +286,12 @@ pub fn find<'tcx>(_tcx: &ty::ctxt<'tcx>, name: &str) -> Option<Intrinsic> {
             definition: Named("llvm.x86.ssse3.psign.w.128")
         },
         "_dp_ps" => Intrinsic {
-            inputs: vec![v(f(32), 4), v(f(32), 4), i(32)],
+            inputs: vec![v(f(32), 4), v(f(32), 4), i_(32, 8)],
             output: v(f(32), 4),
             definition: Named("llvm.x86.sse41.dpps")
         },
         "_dp_pd" => Intrinsic {
-            inputs: vec![v(f(64), 2), v(f(64), 2), i(32)],
+            inputs: vec![v(f(64), 2), v(f(64), 2), i_(32, 8)],
             output: v(f(64), 2),
             definition: Named("llvm.x86.sse41.dppd")
         },
@@ -341,7 +341,7 @@ pub fn find<'tcx>(_tcx: &ty::ctxt<'tcx>, name: &str) -> Option<Intrinsic> {
             definition: Named("llvm.x86.sse41.phminposuw")
         },
         "_mpsadbw_epu8" => Intrinsic {
-            inputs: vec![v(u(8), 16), v(u(8), 16), i(32)],
+            inputs: vec![v(u(8), 16), v(u(8), 16), i_(32, 8)],
             output: v(u(16), 8),
             definition: Named("llvm.x86.sse41.mpsadbw")
         },
@@ -371,72 +371,72 @@ pub fn find<'tcx>(_tcx: &ty::ctxt<'tcx>, name: &str) -> Option<Intrinsic> {
             definition: Named("llvm.x86.sse41.ptestz")
         },
         "_cmpestra" => Intrinsic {
-            inputs: vec![v(i(8), 16), i(32), v(i(8), 16), i(32), i(32)],
+            inputs: vec![v(i(8), 16), i(32), v(i(8), 16), i(32), i_(32, 8)],
             output: i(32),
             definition: Named("llvm.x86.sse42.pcmpestria128")
         },
         "_cmpestrc" => Intrinsic {
-            inputs: vec![v(i(8), 16), i(32), v(i(8), 16), i(32), i(32)],
+            inputs: vec![v(i(8), 16), i(32), v(i(8), 16), i(32), i_(32, 8)],
             output: i(32),
             definition: Named("llvm.x86.sse42.pcmpestric128")
         },
         "_cmpestri" => Intrinsic {
-            inputs: vec![v(i(8), 16), i(32), v(i(8), 16), i(32), i(32)],
+            inputs: vec![v(i(8), 16), i(32), v(i(8), 16), i(32), i_(32, 8)],
             output: i(32),
             definition: Named("llvm.x86.sse42.pcmpestri128")
         },
         "_cmpestrm" => Intrinsic {
-            inputs: vec![v(i(8), 16), i(32), v(i(8), 16), i(32), i(32)],
+            inputs: vec![v(i(8), 16), i(32), v(i(8), 16), i(32), i_(32, 8)],
             output: v(i(8), 16),
             definition: Named("llvm.x86.sse42.pcmpestrm128")
         },
         "_cmpestro" => Intrinsic {
-            inputs: vec![v(i(8), 16), i(32), v(i(8), 16), i(32), i(32)],
+            inputs: vec![v(i(8), 16), i(32), v(i(8), 16), i(32), i_(32, 8)],
             output: i(32),
             definition: Named("llvm.x86.sse42.pcmpestrio128")
         },
         "_cmpestrs" => Intrinsic {
-            inputs: vec![v(i(8), 16), i(32), v(i(8), 16), i(32), i(32)],
+            inputs: vec![v(i(8), 16), i(32), v(i(8), 16), i(32), i_(32, 8)],
             output: i(32),
             definition: Named("llvm.x86.sse42.pcmpestris128")
         },
         "_cmpestrz" => Intrinsic {
-            inputs: vec![v(i(8), 16), i(32), v(i(8), 16), i(32), i(32)],
+            inputs: vec![v(i(8), 16), i(32), v(i(8), 16), i(32), i_(32, 8)],
             output: i(32),
             definition: Named("llvm.x86.sse42.pcmpestriz128")
         },
         "_cmpistra" => Intrinsic {
-            inputs: vec![v(i(8), 16), v(i(8), 16), i(32)],
+            inputs: vec![v(i(8), 16), v(i(8), 16), i_(32, 8)],
             output: i(32),
             definition: Named("llvm.x86.sse42.pcmpistria128")
         },
         "_cmpistrc" => Intrinsic {
-            inputs: vec![v(i(8), 16), v(i(8), 16), i(32)],
+            inputs: vec![v(i(8), 16), v(i(8), 16), i_(32, 8)],
             output: i(32),
             definition: Named("llvm.x86.sse42.pcmpistric128")
         },
         "_cmpistri" => Intrinsic {
-            inputs: vec![v(i(8), 16), v(i(8), 16), i(32)],
+            inputs: vec![v(i(8), 16), v(i(8), 16), i_(32, 8)],
             output: i(32),
             definition: Named("llvm.x86.sse42.pcmpistri128")
         },
         "_cmpistrm" => Intrinsic {
-            inputs: vec![v(i(8), 16), v(i(8), 16), i(32)],
+            inputs: vec![v(i(8), 16), v(i(8), 16), i_(32, 8)],
             output: v(i(8), 16),
             definition: Named("llvm.x86.sse42.pcmpistrm128")
         },
         "_cmpistro" => Intrinsic {
-            inputs: vec![v(i(8), 16), v(i(8), 16), i(32)],
+            inputs: vec![v(i(8), 16), v(i(8), 16), i_(32, 8)],
             output: i(32),
             definition: Named("llvm.x86.sse42.pcmpistrio128")
         },
         "_cmpistrs" => Intrinsic {
-            inputs: vec![v(i(8), 16), v(i(8), 16), i(32)],
+            inputs: vec![v(i(8), 16), v(i(8), 16), i_(32, 8)],
             output: i(32),
             definition: Named("llvm.x86.sse42.pcmpistris128")
         },
         "_cmpistrz" => Intrinsic {
-            inputs: vec![v(i(8), 16), v(i(8), 16), i(32)],
+            inputs: vec![v(i(8), 16), v(i(8), 16), i_(32, 8)],
             output: i(32),
             definition: Named("llvm.x86.sse42.pcmpistriz128")
         },
@@ -451,7 +451,7 @@ pub fn find<'tcx>(_tcx: &ty::ctxt<'tcx>, name: &str) -> Option<Intrinsic> {
             definition: Named("llvm.x86.avx.addsub.pd.256")
         },
         "256_dp_ps" => Intrinsic {
-            inputs: vec![v(f(32), 8), v(f(32), 8), i(32)],
+            inputs: vec![v(f(32), 8), v(f(32), 8), i_(32, 8)],
             output: v(f(32), 8),
             definition: Named("llvm.x86.avx.dp.ps.256")
         },
@@ -765,6 +765,16 @@ pub fn find<'tcx>(_tcx: &ty::ctxt<'tcx>, name: &str) -> Option<Intrinsic> {
             output: v(u(32), 8),
             definition: Named("llvm.x86.avx2.pminu.d")
         },
+        "256_movemask_epi8" => Intrinsic {
+            inputs: vec![v(i(8), 32)],
+            output: i(32),
+            definition: Named("llvm.x86.avx2.pmovmskb")
+        },
+        "256_mpsadbw_epu8" => Intrinsic {
+            inputs: vec![v(u(8), 32), v(u(8), 32), i_(32, 8)],
+            output: v(u(16), 16),
+            definition: Named("llvm.x86.avx2.mpsadbw")
+        },
         "256_mul_epi64" => Intrinsic {
             inputs: vec![v(i(32), 8), v(i(32), 8)],
             output: v(i(64), 4),
diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs
index 267a8a15f69..b883bad7d41 100644
--- a/src/librustc_trans/trans/intrinsic.rs
+++ b/src/librustc_trans/trans/intrinsic.rs
@@ -930,10 +930,13 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                 x.into_iter().next().unwrap()
             }
             fn ty_to_type(ccx: &CrateContext, t: &intrinsics::Type,
-                          any_flattened_aggregate: &mut bool) -> Vec<Type> {
+                          any_changes_needed: &mut bool) -> Vec<Type> {
                 use intrinsics::Type::*;
                 match *t {
-                    Integer(_signed, x) => vec![Type::ix(ccx, x as u64)],
+                    Integer(_signed, width, llvm_width) => {
+                        *any_changes_needed |= width != llvm_width;
+                        vec![Type::ix(ccx, llvm_width as u64)]
+                    }
                     Float(x) => {
                         match x {
                             32 => vec![Type::f32(ccx)],
@@ -944,27 +947,28 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                     Pointer(_) => unimplemented!(),
                     Vector(ref t, length) => {
                         let elem = one(ty_to_type(ccx, t,
-                                                  any_flattened_aggregate));
+                                                  any_changes_needed));
                         vec![Type::vector(&elem,
                                           length as u64)]
                     }
                     Aggregate(false, _) => unimplemented!(),
                     Aggregate(true, ref contents) => {
-                        *any_flattened_aggregate = true;
+                        *any_changes_needed = true;
                         contents.iter()
-                                .flat_map(|t| ty_to_type(ccx, t, any_flattened_aggregate))
+                                .flat_map(|t| ty_to_type(ccx, t, any_changes_needed))
                                 .collect()
                     }
                 }
             }
 
             // This allows an argument list like `foo, (bar, baz),
-            // qux` to be converted into `foo, bar, baz, qux`.
-            fn flatten_aggregate<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                             t: &intrinsics::Type,
-                                             arg_type: Ty<'tcx>,
-                                             llarg: ValueRef)
-                                             -> Vec<ValueRef>
+            // qux` to be converted into `foo, bar, baz, qux`, and
+            // integer arguments to be truncated as needed.
+            fn modify_as_needed<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+                                            t: &intrinsics::Type,
+                                            arg_type: Ty<'tcx>,
+                                            llarg: ValueRef)
+                                            -> Vec<ValueRef>
             {
                 match *t {
                     intrinsics::Type::Aggregate(true, ref contents) => {
@@ -984,22 +988,28 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                             })
                             .collect()
                     }
+                    intrinsics::Type::Integer(_, width, llvm_width) if width != llvm_width => {
+                        // the LLVM intrinsic uses a smaller integer
+                        // size than the C intrinsic's signature, so
+                        // we have to trim it down here.
+                        vec![Trunc(bcx, llarg, Type::ix(bcx.ccx(), llvm_width as u64))]
+                    }
                     _ => vec![llarg],
                 }
             }
 
 
-            let mut any_flattened_aggregate = false;
+            let mut any_changes_needed = false;
             let inputs = intr.inputs.iter()
-                                    .flat_map(|t| ty_to_type(ccx, t, &mut any_flattened_aggregate))
+                                    .flat_map(|t| ty_to_type(ccx, t, &mut any_changes_needed))
                                     .collect::<Vec<_>>();
 
-            let mut out_flattening = false;
-            let outputs = one(ty_to_type(ccx, &intr.output, &mut out_flattening));
+            let mut out_changes = false;
+            let outputs = one(ty_to_type(ccx, &intr.output, &mut out_changes));
             // outputting a flattened aggregate is nonsense
-            assert!(!out_flattening);
+            assert!(!out_changes);
 
-            let llargs = if !any_flattened_aggregate {
+            let llargs = if !any_changes_needed {
                 // no aggregates to flatten, so no change needed
                 llargs
             } else {
@@ -1009,9 +1019,10 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                 intr.inputs.iter()
                            .zip(&llargs)
                            .zip(&arg_tys)
-                           .flat_map(|((t, llarg), ty)| flatten_aggregate(bcx, t, ty, *llarg))
+                           .flat_map(|((t, llarg), ty)| modify_as_needed(bcx, t, ty, *llarg))
                            .collect()
             };
+            assert_eq!(inputs.len(), llargs.len());
 
             match intr.definition {
                 intrinsics::IntrinsicDef::Named(name) => {
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index 74a1926916b..4bca474f922 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -456,7 +456,8 @@ fn match_intrinsic_type_to_type<'tcx, 'a>(
     };
 
     match *expected {
-        Integer(signed, bits) => match (signed, bits, &t.sty) {
+        // (The width we pass to LLVM doesn't concern the type checker.)
+        Integer(signed, bits, _llvm_width) => match (signed, bits, &t.sty) {
             (true, 8, &ty::TyInt(ast::TyI8)) | (false, 8, &ty::TyUint(ast::TyU8)) |
             (true, 16, &ty::TyInt(ast::TyI16)) | (false, 16, &ty::TyUint(ast::TyU16)) |
             (true, 32, &ty::TyInt(ast::TyI32)) | (false, 32, &ty::TyUint(ast::TyU32)) |