1use crate::lib::std::vec::Vec;
4use itertools::Itertools;
5use wasmer_types::Type;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum ReturnSlot {
10 Natural(Type),
12 Raw(Type),
16}
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub enum PairSlot {
21 F32Vector(Type, Type),
23 Raw(Type, Type),
25}
26
27#[derive(Debug, Clone, PartialEq, Eq)]
32pub enum ReturnAbi {
33 Void,
35 Single(Type),
37 Pair(ReturnSlot, ReturnSlot),
39 PackedPair(PairSlot),
41 PackedFirst(PairSlot, ReturnSlot),
43 PackedLast(ReturnSlot, PairSlot),
45 PackedQuads(PairSlot, PairSlot),
47 Unpacked(Vec<Type>),
49 Sret(Vec<Type>),
51}
52
53fn pair_slot(t0: Type, t1: Type) -> PairSlot {
56 if t0 == Type::F32 && t1 == Type::F32 {
57 PairSlot::F32Vector(t0, t1)
58 } else {
59 PairSlot::Raw(t0, t1)
60 }
61}
62
63pub fn classify_return_type_x86_64(types: &[Type]) -> ReturnAbi {
65 let widths = types.iter().map(|ty| ty.bit_size(64)).collect_vec();
66
67 match (types, widths.as_slice()) {
68 ([], []) => ReturnAbi::Void,
69 ([value], [_]) => ReturnAbi::Single(*value),
70 ([first, second], [32, 64] | [64, 32] | [64, 64]) => {
71 ReturnAbi::Pair(ReturnSlot::Natural(*first), ReturnSlot::Natural(*second))
72 }
73 ([first, second], [32, 32]) => ReturnAbi::PackedPair(pair_slot(*first, *second)),
74 ([first, second, third], [32, 32, 32 | 64]) => {
75 ReturnAbi::PackedFirst(pair_slot(*first, *second), ReturnSlot::Natural(*third))
76 }
77 ([first, second, third], [64, 32, 32]) => {
78 ReturnAbi::PackedLast(ReturnSlot::Natural(*first), pair_slot(*second, *third))
79 }
80 ([first, second, third, fourth], [32, 32, 32, 32]) => {
81 ReturnAbi::PackedQuads(pair_slot(*first, *second), pair_slot(*third, *fourth))
82 }
83 _ => ReturnAbi::Sret(types.to_vec()),
84 }
85}
86
87pub fn classify_return_type_aarch64(types: &[Type]) -> ReturnAbi {
92 let widths = types.iter().map(|ty| ty.bit_size(64)).collect_vec();
93 if (2..=4).contains(&types.len())
94 && (types.iter().all(|ty| ty == &Type::F32) || types.iter().all(|ty| ty == &Type::F64))
95 {
96 return ReturnAbi::Unpacked(types.to_vec());
97 }
98
99 if let [first, second] = types
100 && matches!(
101 first,
102 Type::I32 | Type::I64 | Type::F32 | Type::F64 | Type::ExceptionRef
103 )
104 && matches!(second, Type::FuncRef | Type::ExternRef)
105 {
106 return ReturnAbi::Pair(ReturnSlot::Raw(*first), ReturnSlot::Raw(*second));
107 }
108
109 match (types, widths.as_slice()) {
110 ([], []) => ReturnAbi::Void,
111 ([value], [_]) => ReturnAbi::Single(*value),
112 ([first, second], [32, 64] | [64, 32] | [64, 64]) => {
113 ReturnAbi::Pair(ReturnSlot::Raw(*first), ReturnSlot::Raw(*second))
114 }
115 ([first, second], [32, 32]) => ReturnAbi::PackedPair(PairSlot::Raw(*first, *second)),
116 ([first, second, third], [32, 32, 32 | 64]) => {
117 ReturnAbi::PackedFirst(PairSlot::Raw(*first, *second), ReturnSlot::Raw(*third))
118 }
119 ([first, second, third], [64, 32, 32]) => {
120 ReturnAbi::PackedLast(ReturnSlot::Raw(*first), PairSlot::Raw(*second, *third))
121 }
122 ([first, second, third, fourth], [32, 32, 32, 32]) => ReturnAbi::PackedQuads(
123 PairSlot::Raw(*first, *second),
124 PairSlot::Raw(*third, *fourth),
125 ),
126 _ => ReturnAbi::Sret(types.to_vec()),
127 }
128}
129
130pub fn classify_return_type_loongarch64(types: &[Type]) -> ReturnAbi {
134 classify_return_type_riscv64(types)
135}
136
137pub fn classify_return_type_riscv64(types: &[Type]) -> ReturnAbi {
139 let widths = types.iter().map(|ty| ty.bit_size(64)).collect_vec();
140
141 if let [first, second] = types {
144 let is_float = |ty| matches!(ty, Type::F32 | Type::F64);
145 let eligible = |ty, width| is_float(ty) || width <= 64;
146 if (is_float(*first) || is_float(*second))
147 && eligible(*first, widths[0])
148 && eligible(*second, widths[1])
149 {
150 return ReturnAbi::Pair(ReturnSlot::Natural(*first), ReturnSlot::Natural(*second));
151 }
152 }
153
154 match (types, widths.as_slice()) {
155 ([], []) => ReturnAbi::Void,
156 ([value], [_]) => ReturnAbi::Single(*value),
157
158 ([first, second], [32, 64] | [64, 32] | [64, 64]) => {
160 ReturnAbi::Pair(ReturnSlot::Raw(*first), ReturnSlot::Raw(*second))
161 }
162 ([first, second], [32, 32]) => ReturnAbi::PackedPair(PairSlot::Raw(*first, *second)),
163 ([first, second, third], [32, 32, 32 | 64]) => {
164 ReturnAbi::PackedFirst(PairSlot::Raw(*first, *second), ReturnSlot::Raw(*third))
165 }
166 ([first, second, third], [64, 32, 32]) => {
167 ReturnAbi::PackedLast(ReturnSlot::Raw(*first), PairSlot::Raw(*second, *third))
168 }
169 ([first, second, third, fourth], [32, 32, 32, 32]) => ReturnAbi::PackedQuads(
170 PairSlot::Raw(*first, *second),
171 PairSlot::Raw(*third, *fourth),
172 ),
173 _ => ReturnAbi::Sret(types.to_vec()),
174 }
175}
176
177#[cfg(test)]
178mod tests {
179 use super::classify_return_type_x86_64;
180 use crate::abi::{PairSlot, ReturnAbi, ReturnSlot};
181 use wasmer_types::Type;
182
183 #[test]
184 fn classify_x86_64_return_type_abi() {
185 assert_eq!(classify_return_type_x86_64(&[]), ReturnAbi::Void);
186 assert_eq!(
187 classify_return_type_x86_64(&[Type::I64]),
188 ReturnAbi::Single(Type::I64)
189 );
190 assert_eq!(
191 classify_return_type_x86_64(&[Type::I32, Type::F64]),
192 ReturnAbi::Pair(
193 ReturnSlot::Natural(Type::I32),
194 ReturnSlot::Natural(Type::F64)
195 )
196 );
197 assert_eq!(
198 classify_return_type_x86_64(&[Type::I32, Type::F32]),
199 ReturnAbi::PackedPair(PairSlot::Raw(Type::I32, Type::F32))
200 );
201 assert_eq!(
202 classify_return_type_x86_64(&[Type::F32, Type::F32, Type::I64]),
203 ReturnAbi::PackedFirst(
204 PairSlot::F32Vector(Type::F32, Type::F32),
205 ReturnSlot::Natural(Type::I64)
206 )
207 );
208 assert_eq!(
209 classify_return_type_x86_64(&[Type::F64, Type::I32, Type::F32]),
210 ReturnAbi::PackedLast(
211 ReturnSlot::Natural(Type::F64),
212 PairSlot::Raw(Type::I32, Type::F32)
213 )
214 );
215 assert_eq!(
216 classify_return_type_x86_64(&[Type::I32, Type::F32, Type::F32, Type::I32]),
217 ReturnAbi::PackedQuads(
218 PairSlot::Raw(Type::I32, Type::F32),
219 PairSlot::Raw(Type::F32, Type::I32)
220 )
221 );
222 assert_eq!(
223 classify_return_type_x86_64(&[Type::V128, Type::I32]),
224 ReturnAbi::Sret(vec![Type::V128, Type::I32])
225 );
226 }
227}