about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJames Miller <james@aatch.net>2016-02-17 19:33:27 +1300
committerBjörn Steinbrink <bsteinbr@gmail.com>2016-04-04 22:14:10 +0200
commit4815f7e668640ae968418307909f41a7eaabf050 (patch)
treeab8fa6b63eeb27a7dfa55a62b71a230199b21a35
parentf92ce2e9fe56942e0fd6a18d0e11bc4a9bdf8ddd (diff)
downloadrust-4815f7e668640ae968418307909f41a7eaabf050.tar.gz
rust-4815f7e668640ae968418307909f41a7eaabf050.zip
Handle integer-extending for C ABI
We need to supply sext/zext attributes to LLVM to ensure that arguments
are extended to the appropriate width in the correct way.

Most platforms extend integers less than 32 bits, though not all.
-rw-r--r--src/librustc_trans/abi.rs19
-rw-r--r--src/librustc_trans/cabi_aarch64.rs2
-rw-r--r--src/librustc_trans/cabi_arm.rs2
-rw-r--r--src/librustc_trans/cabi_mips.rs14
-rw-r--r--src/librustc_trans/cabi_powerpc.rs14
-rw-r--r--src/librustc_trans/cabi_powerpc64.rs2
-rw-r--r--src/librustc_trans/cabi_x86.rs40
-rw-r--r--src/librustc_trans/cabi_x86_64.rs2
-rw-r--r--src/librustc_trans/cabi_x86_win64.rs2
-rw-r--r--src/rt/rust_test_helpers.c4
-rw-r--r--src/test/run-pass/cabi-int-widening.rs22
11 files changed, 102 insertions, 21 deletions
diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs
index 6edc26c7009..73bed8dc56a 100644
--- a/src/librustc_trans/abi.rs
+++ b/src/librustc_trans/abi.rs
@@ -80,6 +80,8 @@ pub struct ArgType {
     /// Only later will `original_ty` aka `%Foo` be used in the LLVM function
     /// pointer type, without ever having introspected it.
     pub ty: Type,
+    /// Signedness for integer types, None for other types
+    pub signedness: Option<bool>,
     /// Coerced LLVM Type
     pub cast: Option<Type>,
     /// Dummy argument, which is emitted before the real argument
@@ -94,6 +96,7 @@ impl ArgType {
             kind: ArgKind::Direct,
             original_ty: original_ty,
             ty: ty,
+            signedness: None,
             cast: None,
             pad: None,
             attrs: llvm::Attributes::default()
@@ -123,6 +126,19 @@ impl ArgType {
         self.kind = ArgKind::Ignore;
     }
 
+    pub fn extend_integer_width_to(&mut self, bits: u64) {
+        // Only integers have signedness
+        if let Some(signed) = self.signedness {
+            if self.ty.int_width() < bits {
+                self.attrs.set(if signed {
+                    llvm::Attribute::SExt
+                } else {
+                    llvm::Attribute::ZExt
+                });
+            }
+        }
+    }
+
     pub fn is_indirect(&self) -> bool {
         self.kind == ArgKind::Indirect
     }
@@ -268,6 +284,9 @@ impl FnType {
             } else {
                 let mut arg = ArgType::new(type_of::type_of(ccx, ty),
                                            type_of::sizing_type_of(ccx, ty));
+                if ty.is_integral() {
+                    arg.signedness = Some(ty.is_signed());
+                }
                 if llsize_of_real(ccx, arg.ty) == 0 {
                     // For some forsaken reason, x86_64-pc-windows-gnu
                     // doesn't ignore zero-sized struct arguments.
diff --git a/src/librustc_trans/cabi_aarch64.rs b/src/librustc_trans/cabi_aarch64.rs
index 4903af2a6ff..fc11e3888d3 100644
--- a/src/librustc_trans/cabi_aarch64.rs
+++ b/src/librustc_trans/cabi_aarch64.rs
@@ -163,6 +163,7 @@ fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> {
 
 fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
     if is_reg_ty(ret.ty) {
+        ret.extend_integer_width_to(32);
         return;
     }
     if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ret.ty) {
@@ -190,6 +191,7 @@ fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
 
 fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
     if is_reg_ty(arg.ty) {
+        arg.extend_integer_width_to(32);
         return;
     }
     if let Some((base_ty, members)) = is_homogenous_aggregate_ty(arg.ty) {
diff --git a/src/librustc_trans/cabi_arm.rs b/src/librustc_trans/cabi_arm.rs
index 35099399e31..68a2e8aa8ce 100644
--- a/src/librustc_trans/cabi_arm.rs
+++ b/src/librustc_trans/cabi_arm.rs
@@ -131,6 +131,7 @@ fn ty_size(ty: Type, align_fn: TyAlignFn) -> usize {
 
 fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType, align_fn: TyAlignFn) {
     if is_reg_ty(ret.ty) {
+        ret.extend_integer_width_to(32);
         return;
     }
     let size = ty_size(ret.ty, align_fn);
@@ -150,6 +151,7 @@ fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType, align_fn: TyAlignFn) {
 
 fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, align_fn: TyAlignFn) {
     if is_reg_ty(arg.ty) {
+        arg.extend_integer_width_to(32);
         return;
     }
     let align = align_fn(arg.ty);
diff --git a/src/librustc_trans/cabi_mips.rs b/src/librustc_trans/cabi_mips.rs
index be9d4cad1db..680310e195a 100644
--- a/src/librustc_trans/cabi_mips.rs
+++ b/src/librustc_trans/cabi_mips.rs
@@ -86,6 +86,14 @@ fn ty_size(ty: Type) -> usize {
     }
 }
 
+fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
+    if is_reg_ty(ret.ty) {
+        ret.extend_integer_width_to(32);
+    } else {
+        ret.make_indirect(ccx);
+    }
+}
+
 fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
     let orig_offset = *offset;
     let size = ty_size(arg.ty) * 8;
@@ -98,6 +106,8 @@ fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
     if !is_reg_ty(arg.ty) {
         arg.cast = Some(struct_ty(ccx, arg.ty));
         arg.pad = padding_ty(ccx, align, orig_offset);
+    } else {
+        arg.extend_integer_width_to(32);
     }
 }
 
@@ -146,8 +156,8 @@ fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
 }
 
 pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
-    if !fty.ret.is_ignore() && !is_reg_ty(fty.ret.ty) {
-        fty.ret.make_indirect(ccx);
+    if !fty.ret.is_ignore() {
+        classify_ret_ty(ccx, &mut fty.ret);
     }
 
     let mut offset = if fty.ret.is_indirect() { 4 } else { 0 };
diff --git a/src/librustc_trans/cabi_powerpc.rs b/src/librustc_trans/cabi_powerpc.rs
index d118cc86f24..efbdce67a8b 100644
--- a/src/librustc_trans/cabi_powerpc.rs
+++ b/src/librustc_trans/cabi_powerpc.rs
@@ -82,6 +82,14 @@ fn ty_size(ty: Type) -> usize {
     }
 }
 
+fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
+    if is_reg_ty(ret.ty) {
+        ret.extend_integer_width_to(32);
+    } else {
+        ret.make_indirect(ccx);
+    }
+}
+
 fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
     let orig_offset = *offset;
     let size = ty_size(arg.ty) * 8;
@@ -94,6 +102,8 @@ fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
     if !is_reg_ty(arg.ty) {
         arg.cast = Some(struct_ty(ccx, arg.ty));
         arg.pad = padding_ty(ccx, align, orig_offset);
+    } else {
+        arg.extend_integer_width_to(32);
     }
 }
 
@@ -141,8 +151,8 @@ fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
 }
 
 pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
-    if !fty.ret.is_ignore() && !is_reg_ty(fty.ret.ty) {
-        fty.ret.make_indirect(ccx);
+    if !fty.ret.is_ignore() {
+        classify_ret_ty(ccx, &mut fty.ret);
     }
 
     let mut offset = if fty.ret.is_indirect() { 4 } else { 0 };
diff --git a/src/librustc_trans/cabi_powerpc64.rs b/src/librustc_trans/cabi_powerpc64.rs
index 7bc41d26f8b..ba54e369fd8 100644
--- a/src/librustc_trans/cabi_powerpc64.rs
+++ b/src/librustc_trans/cabi_powerpc64.rs
@@ -153,6 +153,7 @@ fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> {
 
 fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
     if is_reg_ty(ret.ty) {
+        ret.extend_integer_width_to(64);
         return;
     }
 
@@ -187,6 +188,7 @@ fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
 
 fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
     if is_reg_ty(arg.ty) {
+        arg.extend_integer_width_to(64);
         return;
     }
 
diff --git a/src/librustc_trans/cabi_x86.rs b/src/librustc_trans/cabi_x86.rs
index 415579eb221..b52231fa6b4 100644
--- a/src/librustc_trans/cabi_x86.rs
+++ b/src/librustc_trans/cabi_x86.rs
@@ -15,25 +15,29 @@ use super::common::*;
 use super::machine::*;
 
 pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
-    if !fty.ret.is_ignore() && fty.ret.ty.kind() == Struct {
-        // Returning a structure. Most often, this will use
-        // a hidden first argument. On some platforms, though,
-        // small structs are returned as integers.
-        //
-        // Some links:
-        // http://www.angelcode.com/dev/callconv/callconv.html
-        // Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp
-        let t = &ccx.sess().target.target;
-        if t.options.is_like_osx || t.options.is_like_windows {
-            match llsize_of_alloc(ccx, fty.ret.ty) {
-                1 => fty.ret.cast = Some(Type::i8(ccx)),
-                2 => fty.ret.cast = Some(Type::i16(ccx)),
-                4 => fty.ret.cast = Some(Type::i32(ccx)),
-                8 => fty.ret.cast = Some(Type::i64(ccx)),
-                _ => fty.ret.make_indirect(ccx)
+    if !fty.ret.is_ignore() {
+        if fty.ret.ty.kind() == Struct {
+            // Returning a structure. Most often, this will use
+            // a hidden first argument. On some platforms, though,
+            // small structs are returned as integers.
+            //
+            // Some links:
+            // http://www.angelcode.com/dev/callconv/callconv.html
+            // Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp
+            let t = &ccx.sess().target.target;
+            if t.options.is_like_osx || t.options.is_like_windows {
+                match llsize_of_alloc(ccx, fty.ret.ty) {
+                    1 => fty.ret.cast = Some(Type::i8(ccx)),
+                    2 => fty.ret.cast = Some(Type::i16(ccx)),
+                    4 => fty.ret.cast = Some(Type::i32(ccx)),
+                    8 => fty.ret.cast = Some(Type::i64(ccx)),
+                    _ => fty.ret.make_indirect(ccx)
+                }
+            } else {
+                fty.ret.make_indirect(ccx);
             }
         } else {
-            fty.ret.make_indirect(ccx);
+            fty.ret.extend_integer_width_to(32);
         }
     }
 
@@ -42,6 +46,8 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
         if arg.ty.kind() == Struct {
             arg.make_indirect(ccx);
             arg.attrs.set(Attribute::ByVal);
+        } else {
+            arg.extend_integer_width_to(32);
         }
     }
 }
diff --git a/src/librustc_trans/cabi_x86_64.rs b/src/librustc_trans/cabi_x86_64.rs
index e9e9e266c77..805c7d345a0 100644
--- a/src/librustc_trans/cabi_x86_64.rs
+++ b/src/librustc_trans/cabi_x86_64.rs
@@ -400,6 +400,8 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
             } else {
                 arg.cast = Some(llreg_ty(ccx, &cls));
             }
+        } else {
+            arg.extend_integer_width_to(32);
         }
     }
 
diff --git a/src/librustc_trans/cabi_x86_win64.rs b/src/librustc_trans/cabi_x86_win64.rs
index a5077f68fb5..71ecb6e9ca1 100644
--- a/src/librustc_trans/cabi_x86_win64.rs
+++ b/src/librustc_trans/cabi_x86_win64.rs
@@ -26,6 +26,8 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
                 8 => a.cast = Some(Type::i64(ccx)),
                 _ => a.make_indirect(ccx)
             }
+        } else {
+            a.extend_integer_width_to(32);
         }
     };
 
diff --git a/src/rt/rust_test_helpers.c b/src/rt/rust_test_helpers.c
index 00bfa63e6fe..d2ebdcca80c 100644
--- a/src/rt/rust_test_helpers.c
+++ b/src/rt/rust_test_helpers.c
@@ -243,3 +243,7 @@ double rust_interesting_average(uint64_t n, ...) {
     va_end(pairs);
     return sum / n;
 }
+
+int32_t rust_int8_to_int32(int8_t x) {
+    return (int32_t)x;
+}
diff --git a/src/test/run-pass/cabi-int-widening.rs b/src/test/run-pass/cabi-int-widening.rs
new file mode 100644
index 00000000000..c7a22759333
--- /dev/null
+++ b/src/test/run-pass/cabi-int-widening.rs
@@ -0,0 +1,22 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[link(name = "rust_test_helpers")]
+extern {
+    fn rust_int8_to_int32(_: i8) -> i32;
+}
+
+fn main() {
+    let x = unsafe {
+        rust_int8_to_int32(-1)
+    };
+
+    assert!(x == -1);
+}