Skip to content

Commit 3c31841

Browse files
committed
rust_trans: struct argument over ffi were passed incorrectly in some situations on x86_64.
1 parent 56a1419 commit 3c31841

File tree

4 files changed

+395
-6
lines changed

4 files changed

+395
-6
lines changed

src/librustc_trans/trans/cabi_x86_64.rs

+41-6
Original file line numberDiff line numberDiff line change
@@ -410,18 +410,53 @@ pub fn compute_abi_info(ccx: &CrateContext,
410410
}
411411
}
412412

413-
let mut arg_tys = Vec::new();
414-
for t in atys {
415-
let ty = x86_64_ty(ccx, *t, |cls| cls.is_pass_byval(), Attribute::ByVal);
416-
arg_tys.push(ty);
417-
}
413+
let mut int_regs = 6; // RDI, RSI, RDX, RCX, R8, R9
414+
let mut sse_regs = 8;
418415

419416
let ret_ty = if ret_def {
420-
x86_64_ty(ccx, rty, |cls| cls.is_ret_bysret(), Attribute::StructRet)
417+
x86_64_ty(ccx, rty, |cls| {
418+
if cls.is_ret_bysret() {
419+
// `sret` parameter thus one less register available
420+
int_regs -= 1;
421+
true
422+
} else {
423+
false
424+
}
425+
}, Attribute::StructRet)
421426
} else {
422427
ArgType::direct(Type::void(ccx), None, None, None)
423428
};
424429

430+
let mut arg_tys = Vec::new();
431+
for t in atys {
432+
let ty = x86_64_ty(ccx, *t, |cls| {
433+
let needed_int = cls.iter().filter(|&&c| c == Int).count();
434+
let needed_sse = cls.iter().filter(|c| c.is_sse()).count();
435+
let in_mem = cls.is_pass_byval() ||
436+
int_regs < needed_int ||
437+
sse_regs < needed_sse;
438+
if in_mem {
439+
// `byval` parameter thus one less integer register available
440+
int_regs -= 1;
441+
} else {
442+
// split into sized chunks passed individually
443+
int_regs -= needed_int;
444+
sse_regs -= needed_sse;
445+
}
446+
in_mem
447+
}, Attribute::ByVal);
448+
arg_tys.push(ty);
449+
450+
// An integer, pointer, double or float parameter
451+
// thus the above closure passed to `x86_64_ty` won't
452+
// get called.
453+
if t.kind() == Integer || t.kind() == Pointer {
454+
int_regs -= 1;
455+
} else if t.kind() == Double || t.kind() == Float {
456+
sse_regs -= 1;
457+
}
458+
}
459+
425460
return FnType {
426461
arg_tys: arg_tys,
427462
ret_ty: ret_ty,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
-include ../tools.mk
2+
3+
all: $(call NATIVE_STATICLIB,test)
4+
$(RUSTC) test.rs
5+
$(call RUN,test) || exit 1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
// Copyright 2015 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+
#include <assert.h>
12+
#include <stdint.h>
13+
14+
struct Rect {
15+
int32_t a;
16+
int32_t b;
17+
int32_t c;
18+
int32_t d;
19+
};
20+
21+
struct BiggerRect {
22+
struct Rect s;
23+
int32_t a;
24+
int32_t b;
25+
};
26+
27+
struct FloatRect {
28+
int32_t a;
29+
int32_t b;
30+
double c;
31+
};
32+
33+
struct Huge {
34+
int32_t a;
35+
int32_t b;
36+
int32_t c;
37+
int32_t d;
38+
int32_t e;
39+
};
40+
41+
// SysV ABI:
42+
// a, b, c, d, e should be in registers
43+
// s should be byval pointer
44+
void byval_rect(int32_t a, int32_t b, int32_t c, int32_t d, int32_t e, struct Rect s) {
45+
assert(a == 1);
46+
assert(b == 2);
47+
assert(c == 3);
48+
assert(d == 4);
49+
assert(e == 5);
50+
assert(s.a == 553);
51+
assert(s.b == 554);
52+
assert(s.c == 555);
53+
assert(s.d == 556);
54+
}
55+
56+
// SysV ABI:
57+
// a, b, c, d, e, f, g should be in sse registers
58+
// s should be split across 2 registers
59+
// t should be byval pointer
60+
void byval_rect_floats(float a, float b, double c, float d, float e,
61+
float f, double g, struct Rect s, struct FloatRect t) {
62+
assert(a == 1.);
63+
assert(b == 2.);
64+
assert(c == 3.);
65+
assert(d == 4.);
66+
assert(e == 5.);
67+
assert(f == 6.);
68+
assert(g == 7.);
69+
assert(s.a == 553);
70+
assert(s.b == 554);
71+
assert(s.c == 555);
72+
assert(s.d == 556);
73+
assert(t.a == 3489);
74+
assert(t.b == 3490);
75+
assert(t.c == 8.);
76+
}
77+
78+
// SysV ABI:
79+
// a, b, d, e should be in registers
80+
// c passed via sse registers
81+
// s should be byval pointer
82+
void byval_rect_with_float(int32_t a, int32_t b, float c, int32_t d,
83+
int32_t e, int32_t f, struct Rect s) {
84+
assert(a == 1);
85+
assert(b == 2);
86+
assert(c == 3.);
87+
assert(d == 4);
88+
assert(e == 5);
89+
assert(f == 6);
90+
assert(s.a == 553);
91+
assert(s.b == 554);
92+
assert(s.c == 555);
93+
assert(s.d == 556);
94+
}
95+
96+
// SysV ABI:
97+
// a, b should be in registers
98+
// s should be split across 2 registers
99+
void split_rect(int32_t a, int32_t b, struct Rect s) {
100+
assert(a == 1);
101+
assert(b == 2);
102+
assert(s.a == 553);
103+
assert(s.b == 554);
104+
assert(s.c == 555);
105+
assert(s.d == 556);
106+
}
107+
108+
// SysV ABI:
109+
// a, b should be in sse registers
110+
// s should be split across int32_t & sse registers
111+
void split_rect_floats(float a, float b, struct FloatRect s) {
112+
assert(a == 1.);
113+
assert(b == 2.);
114+
assert(s.a == 3489);
115+
assert(s.b == 3490);
116+
assert(s.c == 8.);
117+
}
118+
119+
// SysV ABI:
120+
// a, b, d, f should be in registers
121+
// c, e passed via sse registers
122+
// s should be split across 2 registers
123+
void split_rect_with_floats(int32_t a, int32_t b, float c,
124+
int32_t d, float e, int32_t f, struct Rect s) {
125+
assert(a == 1);
126+
assert(b == 2);
127+
assert(c == 3.);
128+
assert(d == 4);
129+
assert(e == 5.);
130+
assert(f == 6);
131+
assert(s.a == 553);
132+
assert(s.b == 554);
133+
assert(s.c == 555);
134+
assert(s.d == 556);
135+
}
136+
137+
// SysV ABI:
138+
// a, b, c should be in registers
139+
// s should be split across 2 registers
140+
// t should be a byval pointer
141+
void split_and_byval_rect(int32_t a, int32_t b, int32_t c, struct Rect s, struct Rect t) {
142+
assert(a == 1);
143+
assert(b == 2);
144+
assert(c == 3);
145+
assert(s.a == 553);
146+
assert(s.b == 554);
147+
assert(s.c == 555);
148+
assert(s.d == 556);
149+
assert(t.a == 553);
150+
assert(t.b == 554);
151+
assert(t.c == 555);
152+
assert(t.d == 556);
153+
}
154+
155+
// SysV ABI:
156+
// a, b should in registers
157+
// s and return should be split across 2 registers
158+
struct Rect split_ret_byval_struct(int32_t a, int32_t b, struct Rect s) {
159+
assert(a == 1);
160+
assert(b == 2);
161+
assert(s.a == 553);
162+
assert(s.b == 554);
163+
assert(s.c == 555);
164+
assert(s.d == 556);
165+
return s;
166+
}
167+
168+
// SysV ABI:
169+
// a, b, c, d should be in registers
170+
// return should be in a hidden sret pointer
171+
// s should be a byval pointer
172+
struct BiggerRect sret_byval_struct(int32_t a, int32_t b, int32_t c, int32_t d, struct Rect s) {
173+
assert(a == 1);
174+
assert(b == 2);
175+
assert(c == 3);
176+
assert(d == 4);
177+
assert(s.a == 553);
178+
assert(s.b == 554);
179+
assert(s.c == 555);
180+
assert(s.d == 556);
181+
182+
struct BiggerRect t;
183+
t.s = s; t.a = 27834; t.b = 7657;
184+
return t;
185+
}
186+
187+
// SysV ABI:
188+
// a, b should be in registers
189+
// return should be in a hidden sret pointer
190+
// s should be split across 2 registers
191+
struct BiggerRect sret_split_struct(int32_t a, int32_t b, struct Rect s) {
192+
assert(a == 1);
193+
assert(b == 2);
194+
assert(s.a == 553);
195+
assert(s.b == 554);
196+
assert(s.c == 555);
197+
assert(s.d == 556);
198+
199+
struct BiggerRect t;
200+
t.s = s; t.a = 27834; t.b = 7657;
201+
return t;
202+
}
203+
204+
// SysV ABI:
205+
// s should be byval pointer (since sizeof(s) > 16)
206+
// return should in a hidden sret pointer
207+
struct Huge huge_struct(struct Huge s) {
208+
assert(s.a == 5647);
209+
assert(s.b == 5648);
210+
assert(s.c == 5649);
211+
assert(s.d == 5650);
212+
assert(s.e == 5651);
213+
214+
return s;
215+
}

0 commit comments

Comments
 (0)