Skip to content

Commit 81d3d71

Browse files
committed
Rollup merge of rust-lang#32732 - dotdash:ext_arg, r=eddyb
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.
2 parents ef39a8d + 4815f7e commit 81d3d71

11 files changed

+102
-21
lines changed

src/librustc_trans/abi.rs

+19
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ pub struct ArgType {
8080
/// Only later will `original_ty` aka `%Foo` be used in the LLVM function
8181
/// pointer type, without ever having introspected it.
8282
pub ty: Type,
83+
/// Signedness for integer types, None for other types
84+
pub signedness: Option<bool>,
8385
/// Coerced LLVM Type
8486
pub cast: Option<Type>,
8587
/// Dummy argument, which is emitted before the real argument
@@ -94,6 +96,7 @@ impl ArgType {
9496
kind: ArgKind::Direct,
9597
original_ty: original_ty,
9698
ty: ty,
99+
signedness: None,
97100
cast: None,
98101
pad: None,
99102
attrs: llvm::Attributes::default()
@@ -123,6 +126,19 @@ impl ArgType {
123126
self.kind = ArgKind::Ignore;
124127
}
125128

129+
pub fn extend_integer_width_to(&mut self, bits: u64) {
130+
// Only integers have signedness
131+
if let Some(signed) = self.signedness {
132+
if self.ty.int_width() < bits {
133+
self.attrs.set(if signed {
134+
llvm::Attribute::SExt
135+
} else {
136+
llvm::Attribute::ZExt
137+
});
138+
}
139+
}
140+
}
141+
126142
pub fn is_indirect(&self) -> bool {
127143
self.kind == ArgKind::Indirect
128144
}
@@ -268,6 +284,9 @@ impl FnType {
268284
} else {
269285
let mut arg = ArgType::new(type_of::type_of(ccx, ty),
270286
type_of::sizing_type_of(ccx, ty));
287+
if ty.is_integral() {
288+
arg.signedness = Some(ty.is_signed());
289+
}
271290
if llsize_of_real(ccx, arg.ty) == 0 {
272291
// For some forsaken reason, x86_64-pc-windows-gnu
273292
// doesn't ignore zero-sized struct arguments.

src/librustc_trans/cabi_aarch64.rs

+2
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> {
163163

164164
fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
165165
if is_reg_ty(ret.ty) {
166+
ret.extend_integer_width_to(32);
166167
return;
167168
}
168169
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) {
190191

191192
fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
192193
if is_reg_ty(arg.ty) {
194+
arg.extend_integer_width_to(32);
193195
return;
194196
}
195197
if let Some((base_ty, members)) = is_homogenous_aggregate_ty(arg.ty) {

src/librustc_trans/cabi_arm.rs

+2
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ fn ty_size(ty: Type, align_fn: TyAlignFn) -> usize {
131131

132132
fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType, align_fn: TyAlignFn) {
133133
if is_reg_ty(ret.ty) {
134+
ret.extend_integer_width_to(32);
134135
return;
135136
}
136137
let size = ty_size(ret.ty, align_fn);
@@ -150,6 +151,7 @@ fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType, align_fn: TyAlignFn) {
150151

151152
fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, align_fn: TyAlignFn) {
152153
if is_reg_ty(arg.ty) {
154+
arg.extend_integer_width_to(32);
153155
return;
154156
}
155157
let align = align_fn(arg.ty);

src/librustc_trans/cabi_mips.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,14 @@ fn ty_size(ty: Type) -> usize {
8686
}
8787
}
8888

89+
fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
90+
if is_reg_ty(ret.ty) {
91+
ret.extend_integer_width_to(32);
92+
} else {
93+
ret.make_indirect(ccx);
94+
}
95+
}
96+
8997
fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
9098
let orig_offset = *offset;
9199
let size = ty_size(arg.ty) * 8;
@@ -98,6 +106,8 @@ fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
98106
if !is_reg_ty(arg.ty) {
99107
arg.cast = Some(struct_ty(ccx, arg.ty));
100108
arg.pad = padding_ty(ccx, align, orig_offset);
109+
} else {
110+
arg.extend_integer_width_to(32);
101111
}
102112
}
103113

@@ -146,8 +156,8 @@ fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
146156
}
147157

148158
pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
149-
if !fty.ret.is_ignore() && !is_reg_ty(fty.ret.ty) {
150-
fty.ret.make_indirect(ccx);
159+
if !fty.ret.is_ignore() {
160+
classify_ret_ty(ccx, &mut fty.ret);
151161
}
152162

153163
let mut offset = if fty.ret.is_indirect() { 4 } else { 0 };

src/librustc_trans/cabi_powerpc.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,14 @@ fn ty_size(ty: Type) -> usize {
8282
}
8383
}
8484

85+
fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
86+
if is_reg_ty(ret.ty) {
87+
ret.extend_integer_width_to(32);
88+
} else {
89+
ret.make_indirect(ccx);
90+
}
91+
}
92+
8593
fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
8694
let orig_offset = *offset;
8795
let size = ty_size(arg.ty) * 8;
@@ -94,6 +102,8 @@ fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
94102
if !is_reg_ty(arg.ty) {
95103
arg.cast = Some(struct_ty(ccx, arg.ty));
96104
arg.pad = padding_ty(ccx, align, orig_offset);
105+
} else {
106+
arg.extend_integer_width_to(32);
97107
}
98108
}
99109

@@ -141,8 +151,8 @@ fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
141151
}
142152

143153
pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
144-
if !fty.ret.is_ignore() && !is_reg_ty(fty.ret.ty) {
145-
fty.ret.make_indirect(ccx);
154+
if !fty.ret.is_ignore() {
155+
classify_ret_ty(ccx, &mut fty.ret);
146156
}
147157

148158
let mut offset = if fty.ret.is_indirect() { 4 } else { 0 };

src/librustc_trans/cabi_powerpc64.rs

+2
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> {
153153

154154
fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
155155
if is_reg_ty(ret.ty) {
156+
ret.extend_integer_width_to(64);
156157
return;
157158
}
158159

@@ -187,6 +188,7 @@ fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
187188

188189
fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
189190
if is_reg_ty(arg.ty) {
191+
arg.extend_integer_width_to(64);
190192
return;
191193
}
192194

src/librustc_trans/cabi_x86.rs

+23-17
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,29 @@ use super::common::*;
1515
use super::machine::*;
1616

1717
pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
18-
if !fty.ret.is_ignore() && fty.ret.ty.kind() == Struct {
19-
// Returning a structure. Most often, this will use
20-
// a hidden first argument. On some platforms, though,
21-
// small structs are returned as integers.
22-
//
23-
// Some links:
24-
// http://www.angelcode.com/dev/callconv/callconv.html
25-
// Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp
26-
let t = &ccx.sess().target.target;
27-
if t.options.is_like_osx || t.options.is_like_windows {
28-
match llsize_of_alloc(ccx, fty.ret.ty) {
29-
1 => fty.ret.cast = Some(Type::i8(ccx)),
30-
2 => fty.ret.cast = Some(Type::i16(ccx)),
31-
4 => fty.ret.cast = Some(Type::i32(ccx)),
32-
8 => fty.ret.cast = Some(Type::i64(ccx)),
33-
_ => fty.ret.make_indirect(ccx)
18+
if !fty.ret.is_ignore() {
19+
if fty.ret.ty.kind() == Struct {
20+
// Returning a structure. Most often, this will use
21+
// a hidden first argument. On some platforms, though,
22+
// small structs are returned as integers.
23+
//
24+
// Some links:
25+
// http://www.angelcode.com/dev/callconv/callconv.html
26+
// Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp
27+
let t = &ccx.sess().target.target;
28+
if t.options.is_like_osx || t.options.is_like_windows {
29+
match llsize_of_alloc(ccx, fty.ret.ty) {
30+
1 => fty.ret.cast = Some(Type::i8(ccx)),
31+
2 => fty.ret.cast = Some(Type::i16(ccx)),
32+
4 => fty.ret.cast = Some(Type::i32(ccx)),
33+
8 => fty.ret.cast = Some(Type::i64(ccx)),
34+
_ => fty.ret.make_indirect(ccx)
35+
}
36+
} else {
37+
fty.ret.make_indirect(ccx);
3438
}
3539
} else {
36-
fty.ret.make_indirect(ccx);
40+
fty.ret.extend_integer_width_to(32);
3741
}
3842
}
3943

@@ -42,6 +46,8 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
4246
if arg.ty.kind() == Struct {
4347
arg.make_indirect(ccx);
4448
arg.attrs.set(Attribute::ByVal);
49+
} else {
50+
arg.extend_integer_width_to(32);
4551
}
4652
}
4753
}

src/librustc_trans/cabi_x86_64.rs

+2
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,8 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
400400
} else {
401401
arg.cast = Some(llreg_ty(ccx, &cls));
402402
}
403+
} else {
404+
arg.extend_integer_width_to(32);
403405
}
404406
}
405407

src/librustc_trans/cabi_x86_win64.rs

+2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
2626
8 => a.cast = Some(Type::i64(ccx)),
2727
_ => a.make_indirect(ccx)
2828
}
29+
} else {
30+
a.extend_integer_width_to(32);
2931
}
3032
};
3133

src/rt/rust_test_helpers.c

+4
Original file line numberDiff line numberDiff line change
@@ -243,3 +243,7 @@ double rust_interesting_average(uint64_t n, ...) {
243243
va_end(pairs);
244244
return sum / n;
245245
}
246+
247+
int32_t rust_int8_to_int32(int8_t x) {
248+
return (int32_t)x;
249+
}
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#[link(name = "rust_test_helpers")]
12+
extern {
13+
fn rust_int8_to_int32(_: i8) -> i32;
14+
}
15+
16+
fn main() {
17+
let x = unsafe {
18+
rust_int8_to_int32(-1)
19+
};
20+
21+
assert!(x == -1);
22+
}

0 commit comments

Comments
 (0)