Skip to content

Commit b1925a9

Browse files
committed
Fix Hexagon ABI calling convention for aggregates
Correct the handling of aggregate types in extern "C" functions to match the Hexagon ABI specification: - Aggregates up to 32 bits: passed/returned in a single register (R0) - Aggregates 33-64 bits: passed/returned in a register pair (R1:R0) - Aggregates > 64 bits: passed on stack via byval, returned via sret This fixes all tests/ui/abi/extern/ tests for Hexagon, including: - extern-pass-TwoU8s, extern-pass-TwoU16s, extern-pass-TwoU32s - extern-pass-TwoU64s, extern-pass-FiveU16s - extern-return-TwoU8s, extern-return-TwoU16s, extern-return-TwoU32s - extern-return-TwoU64s, extern-return-FiveU16s
1 parent f1d5fde commit b1925a9

1 file changed

Lines changed: 21 additions & 19 deletions

File tree

compiler/rustc_target/src/callconv/hexagon.rs

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,25 @@ where
1010
if !ret.layout.is_sized() {
1111
return;
1212
}
13+
1314
if !ret.layout.is_aggregate() {
1415
ret.extend_integer_width_to(32);
1516
return;
1617
}
1718

19+
// Per the Hexagon ABI:
20+
// - Aggregates up to 32 bits are returned in R0
21+
// - Aggregates 33-64 bits are returned in R1:R0
22+
// - Aggregates > 64 bits are returned indirectly via hidden first argument
1823
let size = ret.layout.size;
1924
let bits = size.bits();
20-
21-
// Aggregates larger than 64 bits are returned indirectly
22-
if bits > 64 {
25+
if bits <= 32 {
26+
ret.cast_to(Uniform::new(Reg::i32(), size));
27+
} else if bits <= 64 {
28+
ret.cast_to(Uniform::new(Reg::i64(), size));
29+
} else {
2330
ret.make_indirect();
24-
return;
2531
}
26-
27-
// Small aggregates are returned in registers
28-
// Cast to appropriate register type to ensure proper ABI
29-
let align = ret.layout.align.bytes();
30-
ret.cast_to(Uniform::consecutive(if align <= 4 { Reg::i32() } else { Reg::i64() }, size));
3132
}
3233

3334
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
@@ -42,24 +43,25 @@ where
4243
arg.make_indirect();
4344
return;
4445
}
46+
4547
if !arg.layout.is_aggregate() {
4648
arg.extend_integer_width_to(32);
4749
return;
4850
}
4951

52+
// Per the Hexagon ABI:
53+
// - Aggregates up to 32 bits are passed in a single register
54+
// - Aggregates 33-64 bits are passed in a register pair
55+
// - Aggregates > 64 bits are passed on the stack
5056
let size = arg.layout.size;
5157
let bits = size.bits();
52-
53-
// Aggregates larger than 64 bits are passed indirectly
54-
if bits > 64 {
55-
arg.make_indirect();
56-
return;
58+
if bits <= 32 {
59+
arg.cast_to(Uniform::new(Reg::i32(), size));
60+
} else if bits <= 64 {
61+
arg.cast_to(Uniform::new(Reg::i64(), size));
62+
} else {
63+
arg.pass_by_stack_offset(None);
5764
}
58-
59-
// Small aggregates are passed in registers
60-
// Cast to consecutive register-sized chunks to match the C ABI
61-
let align = arg.layout.align.bytes();
62-
arg.cast_to(Uniform::consecutive(if align <= 4 { Reg::i32() } else { Reg::i64() }, size));
6365
}
6466

6567
pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)

0 commit comments

Comments
 (0)