Skip to content

Commit 99dc124

Browse files
committed
Auto merge of #27017 - luqmana:25594-sysv-abi-ffi, r=bkoropoff
Fixes #25594.
2 parents 785932f + 5eb4de1 commit 99dc124

File tree

4 files changed

+379
-6
lines changed

4 files changed

+379
-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,238 @@
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+
// System V x86_64 ABI:
42+
// a, b, c, d, e should be in registers
43+
// s should be byval pointer
44+
//
45+
// Win64 ABI:
46+
// a, b, c, d should be in registers
47+
// e should be on the stack
48+
// s should be byval pointer
49+
void byval_rect(int32_t a, int32_t b, int32_t c, int32_t d, int32_t e, struct Rect s) {
50+
assert(a == 1);
51+
assert(b == 2);
52+
assert(c == 3);
53+
assert(d == 4);
54+
assert(e == 5);
55+
assert(s.a == 553);
56+
assert(s.b == 554);
57+
assert(s.c == 555);
58+
assert(s.d == 556);
59+
}
60+
61+
// System V x86_64 ABI:
62+
// a, b, c, d, e, f, g should be in sse registers
63+
// s should be split across 2 registers
64+
// t should be byval pointer
65+
//
66+
// Win64 ABI:
67+
// a, b, c, d should be in sse registers
68+
// e, f, g should be on the stack
69+
// s should be on the stack (treated as 2 i64's)
70+
// t should be on the stack (treated as an i64 and a double)
71+
void byval_rect_floats(float a, float b, double c, float d, float e,
72+
float f, double g, struct Rect s, struct FloatRect t) {
73+
assert(a == 1.);
74+
assert(b == 2.);
75+
assert(c == 3.);
76+
assert(d == 4.);
77+
assert(e == 5.);
78+
assert(f == 6.);
79+
assert(g == 7.);
80+
assert(s.a == 553);
81+
assert(s.b == 554);
82+
assert(s.c == 555);
83+
assert(s.d == 556);
84+
assert(t.a == 3489);
85+
assert(t.b == 3490);
86+
assert(t.c == 8.);
87+
}
88+
89+
// System V x86_64 ABI:
90+
// a, b, d, e, f should be in registers
91+
// c passed via sse registers
92+
// s should be byval pointer
93+
//
94+
// Win64 ABI:
95+
// a, b, d should be in registers
96+
// c passed via sse registers
97+
// e, f should be on the stack
98+
// s should be byval pointer
99+
void byval_rect_with_float(int32_t a, int32_t b, float c, int32_t d,
100+
int32_t e, int32_t f, struct Rect s) {
101+
assert(a == 1);
102+
assert(b == 2);
103+
assert(c == 3.);
104+
assert(d == 4);
105+
assert(e == 5);
106+
assert(f == 6);
107+
assert(s.a == 553);
108+
assert(s.b == 554);
109+
assert(s.c == 555);
110+
assert(s.d == 556);
111+
}
112+
113+
// System V x86_64 & Win64 ABI:
114+
// a, b should be in registers
115+
// s should be split across 2 integer registers
116+
void split_rect(int32_t a, int32_t b, struct Rect s) {
117+
assert(a == 1);
118+
assert(b == 2);
119+
assert(s.a == 553);
120+
assert(s.b == 554);
121+
assert(s.c == 555);
122+
assert(s.d == 556);
123+
}
124+
125+
// System V x86_64 & Win64 ABI:
126+
// a, b should be in sse registers
127+
// s should be split across integer & sse registers
128+
void split_rect_floats(float a, float b, struct FloatRect s) {
129+
assert(a == 1.);
130+
assert(b == 2.);
131+
assert(s.a == 3489);
132+
assert(s.b == 3490);
133+
assert(s.c == 8.);
134+
}
135+
136+
// System V x86_64 ABI:
137+
// a, b, d, f should be in registers
138+
// c, e passed via sse registers
139+
// s should be split across 2 registers
140+
//
141+
// Win64 ABI:
142+
// a, b, d should be in registers
143+
// c passed via sse registers
144+
// e, f should be on the stack
145+
// s should be on the stack (treated as 2 i64's)
146+
void split_rect_with_floats(int32_t a, int32_t b, float c,
147+
int32_t d, float e, int32_t f, struct Rect s) {
148+
assert(a == 1);
149+
assert(b == 2);
150+
assert(c == 3.);
151+
assert(d == 4);
152+
assert(e == 5.);
153+
assert(f == 6);
154+
assert(s.a == 553);
155+
assert(s.b == 554);
156+
assert(s.c == 555);
157+
assert(s.d == 556);
158+
}
159+
160+
// System V x86_64 & Win64 ABI:
161+
// a, b, c should be in registers
162+
// s should be split across 2 registers
163+
// t should be a byval pointer
164+
void split_and_byval_rect(int32_t a, int32_t b, int32_t c, struct Rect s, struct Rect t) {
165+
assert(a == 1);
166+
assert(b == 2);
167+
assert(c == 3);
168+
assert(s.a == 553);
169+
assert(s.b == 554);
170+
assert(s.c == 555);
171+
assert(s.d == 556);
172+
assert(t.a == 553);
173+
assert(t.b == 554);
174+
assert(t.c == 555);
175+
assert(t.d == 556);
176+
}
177+
178+
// System V x86_64 & Win64 ABI:
179+
// a, b should in registers
180+
// s and return should be split across 2 registers
181+
struct Rect split_ret_byval_struct(int32_t a, int32_t b, struct Rect s) {
182+
assert(a == 1);
183+
assert(b == 2);
184+
assert(s.a == 553);
185+
assert(s.b == 554);
186+
assert(s.c == 555);
187+
assert(s.d == 556);
188+
return s;
189+
}
190+
191+
// System V x86_64 & Win64 ABI:
192+
// a, b, c, d should be in registers
193+
// return should be in a hidden sret pointer
194+
// s should be a byval pointer
195+
struct BiggerRect sret_byval_struct(int32_t a, int32_t b, int32_t c, int32_t d, struct Rect s) {
196+
assert(a == 1);
197+
assert(b == 2);
198+
assert(c == 3);
199+
assert(d == 4);
200+
assert(s.a == 553);
201+
assert(s.b == 554);
202+
assert(s.c == 555);
203+
assert(s.d == 556);
204+
205+
struct BiggerRect t;
206+
t.s = s; t.a = 27834; t.b = 7657;
207+
return t;
208+
}
209+
210+
// System V x86_64 & Win64 ABI:
211+
// a, b should be in registers
212+
// return should be in a hidden sret pointer
213+
// s should be split across 2 registers
214+
struct BiggerRect sret_split_struct(int32_t a, int32_t b, struct Rect s) {
215+
assert(a == 1);
216+
assert(b == 2);
217+
assert(s.a == 553);
218+
assert(s.b == 554);
219+
assert(s.c == 555);
220+
assert(s.d == 556);
221+
222+
struct BiggerRect t;
223+
t.s = s; t.a = 27834; t.b = 7657;
224+
return t;
225+
}
226+
227+
// System V x86_64 & Win64 ABI:
228+
// s should be byval pointer (since sizeof(s) > 16)
229+
// return should in a hidden sret pointer
230+
struct Huge huge_struct(struct Huge s) {
231+
assert(s.a == 5647);
232+
assert(s.b == 5648);
233+
assert(s.c == 5649);
234+
assert(s.d == 5650);
235+
assert(s.e == 5651);
236+
237+
return s;
238+
}

0 commit comments

Comments
 (0)