Skip to content

Commit

Permalink
Rollup merge of rust-lang#32732 - dotdash:ext_arg, r=eddyb
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Manishearth committed Apr 7, 2016
2 parents 6e360e5 + 4815f7e commit 02acff6
Show file tree
Hide file tree
Showing 11 changed files with 102 additions and 21 deletions.
19 changes: 19 additions & 0 deletions src/librustc_trans/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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()
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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.
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_trans/cabi_aarch64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_trans/cabi_arm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down
14 changes: 12 additions & 2 deletions src/librustc_trans/cabi_mips.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
}
}

Expand Down Expand Up @@ -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 };
Expand Down
14 changes: 12 additions & 2 deletions src/librustc_trans/cabi_powerpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
}
}

Expand Down Expand Up @@ -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 };
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_trans/cabi_powerpc64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}

Expand Down
40 changes: 23 additions & 17 deletions src/librustc_trans/cabi_x86.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand All @@ -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);
}
}
}
2 changes: 2 additions & 0 deletions src/librustc_trans/cabi_x86_64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/librustc_trans/cabi_x86_win64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
};

Expand Down
4 changes: 4 additions & 0 deletions src/rt/rust_test_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
22 changes: 22 additions & 0 deletions src/test/run-pass/cabi-int-widening.rs
Original file line number Diff line number Diff line change
@@ -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);
}

0 comments on commit 02acff6

Please sign in to comment.