diff options
| author | James Miller <james@aatch.net> | 2016-02-17 19:33:27 +1300 |
|---|---|---|
| committer | Björn Steinbrink <bsteinbr@gmail.com> | 2016-04-04 22:14:10 +0200 |
| commit | 4815f7e668640ae968418307909f41a7eaabf050 (patch) | |
| tree | ab8fa6b63eeb27a7dfa55a62b71a230199b21a35 /src | |
| parent | f92ce2e9fe56942e0fd6a18d0e11bc4a9bdf8ddd (diff) | |
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.
Diffstat (limited to 'src')
| -rw-r--r-- | src/librustc_trans/abi.rs | 19 | ||||
| -rw-r--r-- | src/librustc_trans/cabi_aarch64.rs | 2 | ||||
| -rw-r--r-- | src/librustc_trans/cabi_arm.rs | 2 | ||||
| -rw-r--r-- | src/librustc_trans/cabi_mips.rs | 14 | ||||
| -rw-r--r-- | src/librustc_trans/cabi_powerpc.rs | 14 | ||||
| -rw-r--r-- | src/librustc_trans/cabi_powerpc64.rs | 2 | ||||
| -rw-r--r-- | src/librustc_trans/cabi_x86.rs | 40 | ||||
| -rw-r--r-- | src/librustc_trans/cabi_x86_64.rs | 2 | ||||
| -rw-r--r-- | src/librustc_trans/cabi_x86_win64.rs | 2 | ||||
| -rw-r--r-- | src/rt/rust_test_helpers.c | 4 | ||||
| -rw-r--r-- | src/test/run-pass/cabi-int-widening.rs | 22 |
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); +} |
