1use crate::abi::Abi;
2use crate::error::{err, err_nt};
3use crate::translator::intrinsics::{Intrinsics, type_to_llvm};
4use inkwell::{
5 AddressSpace,
6 attributes::{Attribute, AttributeLoc},
7 builder::Builder,
8 context::Context,
9 types::{AnyType, BasicMetadataTypeEnum, BasicType, FunctionType, StructType},
10 values::{
11 BasicValue, BasicValueEnum, CallSiteValue, FloatValue, FunctionValue, IntValue,
12 PointerValue, VectorValue,
13 },
14};
15use wasmer_types::{CompileError, FunctionType as FuncSig, Type};
16use wasmer_vm::VMOffsets;
17
18use std::convert::TryInto;
19
20use super::{G0M0FunctionKind, LocalFunctionG0M0params};
21
22pub struct X86_64SystemV {}
24
25impl Abi for X86_64SystemV {
26 fn get_vmctx_ptr_param<'ctx>(&self, func_value: &FunctionValue<'ctx>) -> PointerValue<'ctx> {
28 let param = func_value
29 .get_nth_param(u32::from(
30 func_value
31 .get_enum_attribute(
32 AttributeLoc::Param(0),
33 Attribute::get_named_enum_kind_id("sret"),
34 )
35 .is_some(),
36 ))
37 .unwrap();
38 param.into_pointer_value()
41 }
42
43 fn get_g0_ptr_param<'ctx>(&self, func_value: &FunctionValue<'ctx>) -> IntValue<'ctx> {
46 let vmctx_idx = u32::from(
48 func_value
49 .get_enum_attribute(
50 AttributeLoc::Param(0),
51 Attribute::get_named_enum_kind_id("sret"),
52 )
53 .is_some(),
54 );
55
56 let param = func_value.get_nth_param(vmctx_idx + 1).unwrap();
57 param.set_name("g0");
58
59 param.into_int_value()
60 }
61
62 fn get_m0_ptr_param<'ctx>(&self, func_value: &FunctionValue<'ctx>) -> PointerValue<'ctx> {
65 let vmctx_idx = u32::from(
67 func_value
68 .get_enum_attribute(
69 AttributeLoc::Param(0),
70 Attribute::get_named_enum_kind_id("sret"),
71 )
72 .is_some(),
73 );
74
75 let param = func_value.get_nth_param(vmctx_idx + 2).unwrap();
76 param.set_name("m0_base_ptr");
77
78 param.into_pointer_value()
79 }
80
81 fn func_type_to_llvm<'ctx>(
83 &self,
84 context: &'ctx Context,
85 intrinsics: &Intrinsics<'ctx>,
86 offsets: Option<&VMOffsets>,
87 sig: &FuncSig,
88 function_kind: Option<G0M0FunctionKind>,
89 ) -> Result<(FunctionType<'ctx>, Vec<(Attribute, AttributeLoc)>), CompileError> {
90 let user_param_types = sig.params().iter().map(|&ty| type_to_llvm(intrinsics, ty));
91
92 let mut param_types = vec![Ok(intrinsics.ptr_ty.as_basic_type_enum())];
93 if function_kind.is_some_and(|v| v.is_local()) {
94 param_types.push(Ok(intrinsics.i32_ty.as_basic_type_enum()));
96 param_types.push(Ok(intrinsics.ptr_ty.as_basic_type_enum()));
98 }
99
100 let param_types = param_types.into_iter().chain(user_param_types);
101
102 let vmctx_attributes = |i: u32| {
104 vec![
105 (
106 context.create_enum_attribute(Attribute::get_named_enum_kind_id("nofree"), 0),
107 AttributeLoc::Param(i),
108 ),
109 (
110 if let Some(offsets) = offsets {
111 context.create_enum_attribute(
112 Attribute::get_named_enum_kind_id("dereferenceable"),
113 offsets.size_of_vmctx().into(),
114 )
115 } else {
116 context
117 .create_enum_attribute(Attribute::get_named_enum_kind_id("nonnull"), 0)
118 },
119 AttributeLoc::Param(i),
120 ),
121 (
122 context.create_enum_attribute(
123 Attribute::get_named_enum_kind_id("align"),
124 std::mem::align_of::<wasmer_vm::VMContext>()
125 .try_into()
126 .unwrap(),
127 ),
128 AttributeLoc::Param(i),
129 ),
130 ]
131 };
132
133 let sig_returns_bitwidths = sig
134 .results()
135 .iter()
136 .map(|ty| match ty {
137 Type::I32 | Type::F32 => 32,
138 Type::I64 | Type::F64 => 64,
139 Type::V128 => 128,
140 Type::ExternRef | Type::FuncRef | Type::ExceptionRef => 64, })
142 .collect::<Vec<i32>>();
143
144 Ok(match sig_returns_bitwidths.as_slice() {
145 [] => (
146 intrinsics.void_ty.fn_type(
147 param_types
148 .map(|v| v.map(Into::into))
149 .collect::<Result<Vec<BasicMetadataTypeEnum>, _>>()?
150 .as_slice(),
151 false,
152 ),
153 vmctx_attributes(0),
154 ),
155 [_] => {
156 let single_value = sig.results()[0];
157 (
158 type_to_llvm(intrinsics, single_value)?.fn_type(
159 param_types
160 .map(|v| v.map(Into::into))
161 .collect::<Result<Vec<BasicMetadataTypeEnum>, _>>()?
162 .as_slice(),
163 false,
164 ),
165 vmctx_attributes(0),
166 )
167 }
168 [32, 64] | [64, 32] | [64, 64] => {
169 let basic_types: Vec<_> = sig
170 .results()
171 .iter()
172 .map(|&ty| type_to_llvm(intrinsics, ty))
173 .collect::<Result<_, _>>()?;
174
175 (
176 context.struct_type(&basic_types, false).fn_type(
177 param_types
178 .map(|v| v.map(Into::into))
179 .collect::<Result<Vec<BasicMetadataTypeEnum>, _>>()?
180 .as_slice(),
181 false,
182 ),
183 vmctx_attributes(0),
184 )
185 }
186 [32, 32] if sig.results()[0] == Type::F32 && sig.results()[1] == Type::F32 => (
187 intrinsics.f32_ty.vec_type(2).fn_type(
188 param_types
189 .map(|v| v.map(Into::into))
190 .collect::<Result<Vec<BasicMetadataTypeEnum>, _>>()?
191 .as_slice(),
192 false,
193 ),
194 vmctx_attributes(0),
195 ),
196 [32, 32] => (
197 intrinsics.i64_ty.fn_type(
198 param_types
199 .map(|v| v.map(Into::into))
200 .collect::<Result<Vec<BasicMetadataTypeEnum>, _>>()?
201 .as_slice(),
202 false,
203 ),
204 vmctx_attributes(0),
205 ),
206 [32, 32, _] if sig.results()[0] == Type::F32 && sig.results()[1] == Type::F32 => (
207 context
208 .struct_type(
209 &[
210 intrinsics.f32_ty.vec_type(2).as_basic_type_enum(),
211 type_to_llvm(intrinsics, sig.results()[2])?,
212 ],
213 false,
214 )
215 .fn_type(
216 param_types
217 .map(|v| v.map(Into::into))
218 .collect::<Result<Vec<BasicMetadataTypeEnum>, _>>()?
219 .as_slice(),
220 false,
221 ),
222 vmctx_attributes(0),
223 ),
224 [32, 32, _] => (
225 context
226 .struct_type(
227 &[
228 intrinsics.i64_ty.as_basic_type_enum(),
229 type_to_llvm(intrinsics, sig.results()[2])?,
230 ],
231 false,
232 )
233 .fn_type(
234 param_types
235 .map(|v| v.map(Into::into))
236 .collect::<Result<Vec<BasicMetadataTypeEnum>, _>>()?
237 .as_slice(),
238 false,
239 ),
240 vmctx_attributes(0),
241 ),
242 [64, 32, 32] if sig.results()[1] == Type::F32 && sig.results()[2] == Type::F32 => (
243 context
244 .struct_type(
245 &[
246 type_to_llvm(intrinsics, sig.results()[0])?,
247 intrinsics.f32_ty.vec_type(2).as_basic_type_enum(),
248 ],
249 false,
250 )
251 .fn_type(
252 param_types
253 .map(|v| v.map(Into::into))
254 .collect::<Result<Vec<BasicMetadataTypeEnum>, _>>()?
255 .as_slice(),
256 false,
257 ),
258 vmctx_attributes(0),
259 ),
260 [64, 32, 32] => (
261 context
262 .struct_type(
263 &[
264 type_to_llvm(intrinsics, sig.results()[0])?,
265 intrinsics.i64_ty.as_basic_type_enum(),
266 ],
267 false,
268 )
269 .fn_type(
270 param_types
271 .map(|v| v.map(Into::into))
272 .collect::<Result<Vec<BasicMetadataTypeEnum>, _>>()?
273 .as_slice(),
274 false,
275 ),
276 vmctx_attributes(0),
277 ),
278 [32, 32, 32, 32] => (
279 context
280 .struct_type(
281 &[
282 if sig.results()[0] == Type::F32 && sig.results()[1] == Type::F32 {
283 intrinsics.f32_ty.vec_type(2).as_basic_type_enum()
284 } else {
285 intrinsics.i64_ty.as_basic_type_enum()
286 },
287 if sig.results()[2] == Type::F32 && sig.results()[3] == Type::F32 {
288 intrinsics.f32_ty.vec_type(2).as_basic_type_enum()
289 } else {
290 intrinsics.i64_ty.as_basic_type_enum()
291 },
292 ],
293 false,
294 )
295 .fn_type(
296 param_types
297 .map(|v| v.map(Into::into))
298 .collect::<Result<Vec<BasicMetadataTypeEnum>, _>>()?
299 .as_slice(),
300 false,
301 ),
302 vmctx_attributes(0),
303 ),
304 _ => {
305 let basic_types: Vec<_> = sig
306 .results()
307 .iter()
308 .map(|&ty| type_to_llvm(intrinsics, ty))
309 .collect::<Result<_, _>>()?;
310
311 let sret = context.struct_type(&basic_types, false);
312 let sret_ptr = context.ptr_type(AddressSpace::default());
313
314 let param_types =
315 std::iter::once(Ok(sret_ptr.as_basic_type_enum())).chain(param_types);
316
317 let mut attributes = vec![(
318 context.create_type_attribute(
319 Attribute::get_named_enum_kind_id("sret"),
320 sret.as_any_type_enum(),
321 ),
322 AttributeLoc::Param(0),
323 )];
324 attributes.append(&mut vmctx_attributes(1));
325
326 (
327 intrinsics.void_ty.fn_type(
328 param_types
329 .map(|v| v.map(Into::into))
330 .collect::<Result<Vec<BasicMetadataTypeEnum>, _>>()?
331 .as_slice(),
332 false,
333 ),
334 attributes,
335 )
336 }
337 })
338 }
339
340 fn args_to_call<'ctx>(
342 &self,
343 alloca_builder: &Builder<'ctx>,
344 func_sig: &FuncSig,
345 llvm_fn_ty: &FunctionType<'ctx>,
346 ctx_ptr: PointerValue<'ctx>,
347 values: &[BasicValueEnum<'ctx>],
348 intrinsics: &Intrinsics<'ctx>,
349 g0m0: LocalFunctionG0M0params<'ctx>,
350 ) -> Result<Vec<BasicValueEnum<'ctx>>, CompileError> {
351 let sret = if llvm_fn_ty.get_return_type().is_none() && func_sig.results().len() > 1 {
353 let llvm_params: Vec<_> = func_sig
354 .results()
355 .iter()
356 .map(|x| type_to_llvm(intrinsics, *x).unwrap())
357 .collect();
358 let llvm_params = llvm_fn_ty
359 .get_context()
360 .struct_type(llvm_params.as_slice(), false);
361 Some(err!(alloca_builder.build_alloca(llvm_params, "sret")))
362 } else {
363 None
364 };
365
366 let mut args = vec![ctx_ptr.as_basic_value_enum()];
367
368 if let Some((g0, m0)) = g0m0 {
369 args.push(g0.into());
370 args.push(m0.into());
371 }
372
373 let args = args.into_iter().chain(values.iter().copied());
374
375 let ret = if let Some(sret) = sret {
376 std::iter::once(sret.as_basic_value_enum())
377 .chain(args)
378 .collect()
379 } else {
380 args.collect()
381 };
382
383 Ok(ret)
384 }
385
386 fn rets_from_call<'ctx>(
388 &self,
389 builder: &Builder<'ctx>,
390 intrinsics: &Intrinsics<'ctx>,
391 call_site: CallSiteValue<'ctx>,
392 func_sig: &FuncSig,
393 ) -> Result<Vec<BasicValueEnum<'ctx>>, CompileError> {
394 let split_i64 =
395 |value: IntValue<'ctx>| -> Result<(IntValue<'ctx>, IntValue<'ctx>), CompileError> {
396 assert!(value.get_type() == intrinsics.i64_ty);
397 let low = err!(builder.build_int_truncate(value, intrinsics.i32_ty, ""));
398 let lshr = err!(builder.build_right_shift(
399 value,
400 intrinsics.i64_ty.const_int(32, false),
401 false,
402 ""
403 ));
404 let high = err!(builder.build_int_truncate(lshr, intrinsics.i32_ty, ""));
405 Ok((low, high))
406 };
407
408 let f32x2_ty = intrinsics.f32_ty.vec_type(2).as_basic_type_enum();
409 let extract_f32x2 = |value: VectorValue<'ctx>| -> Result<(FloatValue<'ctx>, FloatValue<'ctx>), CompileError> {
410 assert!(value.get_type() == f32x2_ty.into_vector_type());
411 let ret0 = err!(builder
412 .build_extract_element(value, intrinsics.i32_ty.const_int(0, false), ""))
413 .into_float_value();
414 let ret1 = err!(builder
415 .build_extract_element(value, intrinsics.i32_ty.const_int(1, false), ""))
416 .into_float_value();
417 Ok((ret0, ret1))
418 };
419
420 let casted =
421 |value: BasicValueEnum<'ctx>, ty: Type| -> Result<BasicValueEnum<'ctx>, CompileError> {
422 match ty {
423 Type::I32 => {
424 assert!(
425 value.get_type() == intrinsics.i32_ty.as_basic_type_enum()
426 || value.get_type() == intrinsics.f32_ty.as_basic_type_enum()
427 );
428 err_nt!(builder.build_bit_cast(value, intrinsics.i32_ty, ""))
429 }
430 Type::F32 => {
431 assert!(
432 value.get_type() == intrinsics.i32_ty.as_basic_type_enum()
433 || value.get_type() == intrinsics.f32_ty.as_basic_type_enum()
434 );
435 err_nt!(builder.build_bit_cast(value, intrinsics.f32_ty, ""))
436 }
437 _ => panic!("should only be called to repack 32-bit values"),
438 }
439 };
440
441 if let Some(basic_value) = call_site.try_as_basic_value().left() {
442 if func_sig.results().len() > 1 {
443 if basic_value.get_type() == intrinsics.i64_ty.as_basic_type_enum() {
444 assert!(func_sig.results().len() == 2);
445 let value = basic_value.into_int_value();
446 let (low, high) = split_i64(value)?;
447 let low = casted(low.into(), func_sig.results()[0])?;
448 let high = casted(high.into(), func_sig.results()[1])?;
449 return Ok(vec![low, high]);
450 }
451 if basic_value.get_type() == f32x2_ty {
452 assert!(func_sig.results().len() == 2);
453 let (ret0, ret1) = extract_f32x2(basic_value.into_vector_value())?;
454 return Ok(vec![ret0.into(), ret1.into()]);
455 }
456 let struct_value = basic_value.into_struct_value();
457 let rets = (0..struct_value.get_type().count_fields())
458 .map(|i| builder.build_extract_value(struct_value, i, "").unwrap())
459 .collect::<Vec<_>>();
460 let func_sig_returns_bitwidths = func_sig
461 .results()
462 .iter()
463 .map(|ty| match ty {
464 Type::I32 | Type::F32 => 32,
465 Type::I64 | Type::F64 => 64,
466 Type::V128 => 128,
467 Type::ExternRef | Type::FuncRef | Type::ExceptionRef => 64, })
469 .collect::<Vec<i32>>();
470
471 let ret = match func_sig_returns_bitwidths.as_slice() {
472 [32, 64] | [64, 32] | [64, 64] => {
473 assert!(func_sig.results().len() == 2);
474 vec![rets[0], rets[1]]
475 }
476 [32, 32, _]
477 if rets[0].get_type()
478 == intrinsics.f32_ty.vec_type(2).as_basic_type_enum() =>
479 {
480 assert!(func_sig.results().len() == 3);
481 let (rets0, rets1) = extract_f32x2(rets[0].into_vector_value())?;
482 vec![rets0.into(), rets1.into(), rets[1]]
483 }
484 [32, 32, _] => {
485 assert!(func_sig.results().len() == 3);
486 let (low, high) = split_i64(rets[0].into_int_value())?;
487 let low = casted(low.into(), func_sig.results()[0])?;
488 let high = casted(high.into(), func_sig.results()[1])?;
489 vec![low, high, rets[1]]
490 }
491 [64, 32, 32]
492 if rets[1].get_type()
493 == intrinsics.f32_ty.vec_type(2).as_basic_type_enum() =>
494 {
495 assert!(func_sig.results().len() == 3);
496 let (rets1, rets2) = extract_f32x2(rets[1].into_vector_value())?;
497 vec![rets[0], rets1.into(), rets2.into()]
498 }
499 [64, 32, 32] => {
500 assert!(func_sig.results().len() == 3);
501 let (rets1, rets2) = split_i64(rets[1].into_int_value())?;
502 let rets1 = casted(rets1.into(), func_sig.results()[1])?;
503 let rets2 = casted(rets2.into(), func_sig.results()[2])?;
504 vec![rets[0], rets1, rets2]
505 }
506 [32, 32, 32, 32] => {
507 assert!(func_sig.results().len() == 4);
508 let (low0, high0) = if rets[0].get_type()
509 == intrinsics.f32_ty.vec_type(2).as_basic_type_enum()
510 {
511 let (x, y) = extract_f32x2(rets[0].into_vector_value())?;
512 (x.into(), y.into())
513 } else {
514 let (x, y) = split_i64(rets[0].into_int_value())?;
515 (x.into(), y.into())
516 };
517 let (low1, high1) = if rets[1].get_type()
518 == intrinsics.f32_ty.vec_type(2).as_basic_type_enum()
519 {
520 let (x, y) = extract_f32x2(rets[1].into_vector_value())?;
521 (x.into(), y.into())
522 } else {
523 let (x, y) = split_i64(rets[1].into_int_value())?;
524 (x.into(), y.into())
525 };
526 let low0 = casted(low0, func_sig.results()[0])?;
527 let high0 = casted(high0, func_sig.results()[1])?;
528 let low1 = casted(low1, func_sig.results()[2])?;
529 let high1 = casted(high1, func_sig.results()[3])?;
530 vec![low0, high0, low1, high1]
531 }
532 _ => unreachable!("expected an sret for this type"),
533 };
534
535 Ok(ret)
536 } else {
537 assert!(func_sig.results().len() == 1);
538 Ok(vec![basic_value])
539 }
540 } else {
541 assert!(call_site.count_arguments() > 0); if call_site
543 .get_enum_attribute(
544 AttributeLoc::Param(0),
545 Attribute::get_named_enum_kind_id("sret"),
546 )
547 .is_some()
548 {
549 let sret_ty = call_site
550 .try_as_basic_value()
551 .right()
552 .unwrap()
553 .get_operand(0)
554 .unwrap()
555 .left()
556 .unwrap();
557 let sret = sret_ty.into_pointer_value();
558 let llvm_results: Vec<_> = func_sig
560 .results()
561 .iter()
562 .map(|x| type_to_llvm(intrinsics, *x).unwrap())
563 .collect();
564 let struct_type = intrinsics
565 .i32_ty
566 .get_context()
567 .struct_type(llvm_results.as_slice(), false);
568
569 let struct_value =
570 err!(builder.build_load(struct_type, sret, "")).into_struct_value();
571 let mut rets: Vec<_> = Vec::new();
572 for i in 0..struct_value.get_type().count_fields() {
573 let value = builder.build_extract_value(struct_value, i, "").unwrap();
574 rets.push(value);
575 }
576 assert!(func_sig.results().len() == rets.len());
577 Ok(rets)
578 } else {
579 assert!(func_sig.results().is_empty());
580 Ok(vec![])
581 }
582 }
583 }
584
585 fn is_sret(&self, func_sig: &FuncSig) -> Result<bool, CompileError> {
586 let func_sig_returns_bitwidths = func_sig
587 .results()
588 .iter()
589 .map(|ty| match ty {
590 Type::I32 | Type::F32 => 32,
591 Type::I64 | Type::F64 => 64,
592 Type::V128 => 128,
593 Type::ExternRef | Type::FuncRef | Type::ExceptionRef => 64, })
595 .collect::<Vec<i32>>();
596
597 Ok(!matches!(
598 func_sig_returns_bitwidths.as_slice(),
599 [] | [_]
600 | [32, 32]
601 | [32, 64]
602 | [64, 32]
603 | [64, 64]
604 | [32, 32, 32]
605 | [32, 32, 64]
606 | [64, 32, 32]
607 | [32, 32, 32, 32]
608 ))
609 }
610
611 fn pack_values_for_register_return<'ctx>(
612 &self,
613 intrinsics: &Intrinsics<'ctx>,
614 builder: &Builder<'ctx>,
615 values: &[BasicValueEnum<'ctx>],
616 func_type: &FunctionType<'ctx>,
617 ) -> Result<BasicValueEnum<'ctx>, CompileError> {
618 let is_32 = |value: BasicValueEnum| {
619 (value.is_int_value() && value.into_int_value().get_type() == intrinsics.i32_ty)
620 || (value.is_float_value()
621 && value.into_float_value().get_type() == intrinsics.f32_ty)
622 };
623 let is_64 = |value: BasicValueEnum| {
624 (value.is_int_value() && value.into_int_value().get_type() == intrinsics.i64_ty)
625 || (value.is_float_value()
626 && value.into_float_value().get_type() == intrinsics.f64_ty)
627 };
628 let is_f32 = |value: BasicValueEnum| {
629 value.is_float_value() && value.into_float_value().get_type() == intrinsics.f32_ty
630 };
631
632 let pack_i32s = |low: BasicValueEnum<'ctx>, high: BasicValueEnum<'ctx>| {
633 assert!(low.get_type() == intrinsics.i32_ty.as_basic_type_enum());
634 assert!(high.get_type() == intrinsics.i32_ty.as_basic_type_enum());
635 let (low, high) = (low.into_int_value(), high.into_int_value());
636 let low = err!(builder.build_int_z_extend(low, intrinsics.i64_ty, ""));
637 let high = err!(builder.build_int_z_extend(high, intrinsics.i64_ty, ""));
638 let high =
639 err!(builder.build_left_shift(high, intrinsics.i64_ty.const_int(32, false), ""));
640 err_nt!(
641 builder
642 .build_or(low, high, "")
643 .map(|v| v.as_basic_value_enum())
644 )
645 };
646
647 let pack_f32s = |first: BasicValueEnum<'ctx>,
648 second: BasicValueEnum<'ctx>|
649 -> Result<BasicValueEnum<'ctx>, CompileError> {
650 assert!(first.get_type() == intrinsics.f32_ty.as_basic_type_enum());
651 assert!(second.get_type() == intrinsics.f32_ty.as_basic_type_enum());
652 let (first, second) = (first.into_float_value(), second.into_float_value());
653 let vec_ty = intrinsics.f32_ty.vec_type(2);
654 let vec = err!(builder.build_insert_element(
655 vec_ty.get_undef(),
656 first,
657 intrinsics.i32_zero,
658 ""
659 ));
660 err_nt!(
661 builder
662 .build_insert_element(vec, second, intrinsics.i32_ty.const_int(1, false), "")
663 .map(|v| v.as_basic_value_enum())
664 )
665 };
666
667 let build_struct = |ty: StructType<'ctx>, values: &[BasicValueEnum<'ctx>]| {
668 let mut struct_value = ty.get_undef();
669 for (i, v) in values.iter().enumerate() {
670 struct_value = builder
671 .build_insert_value(struct_value, *v, i as u32, "")
672 .unwrap()
673 .into_struct_value();
674 }
675 struct_value.as_basic_value_enum()
676 };
677
678 Ok(match *values {
679 [one_value] => one_value,
680 [v1, v2] if is_f32(v1) && is_f32(v2) => pack_f32s(v1, v2)?,
681 [v1, v2] if is_32(v1) && is_32(v2) => {
682 let v1 = err!(builder.build_bit_cast(v1, intrinsics.i32_ty, ""));
683 let v2 = err!(builder.build_bit_cast(v2, intrinsics.i32_ty, ""));
684 pack_i32s(v1, v2)?
685 }
686 [v1, v2] => {
687 assert!(!(is_32(v1) && is_32(v2)));
688 build_struct(
689 func_type.get_return_type().unwrap().into_struct_type(),
690 &[v1, v2],
691 )
692 }
693 [v1, v2, v3] if is_f32(v1) && is_f32(v2) => build_struct(
694 func_type.get_return_type().unwrap().into_struct_type(),
695 &[pack_f32s(v1, v2)?, v3],
696 ),
697 [v1, v2, v3] if is_32(v1) && is_32(v2) => {
698 let v1 = err!(builder.build_bit_cast(v1, intrinsics.i32_ty, ""));
699 let v2 = err!(builder.build_bit_cast(v2, intrinsics.i32_ty, ""));
700 build_struct(
701 func_type.get_return_type().unwrap().into_struct_type(),
702 &[pack_i32s(v1, v2)?, v3],
703 )
704 }
705 [v1, v2, v3] if is_64(v1) && is_f32(v2) && is_f32(v3) => build_struct(
706 func_type.get_return_type().unwrap().into_struct_type(),
707 &[v1, pack_f32s(v2, v3)?],
708 ),
709 [v1, v2, v3] if is_64(v1) && is_32(v2) && is_32(v3) => {
710 let v2 = err!(builder.build_bit_cast(v2, intrinsics.i32_ty, ""));
711 let v3 = err!(builder.build_bit_cast(v3, intrinsics.i32_ty, ""));
712 build_struct(
713 func_type.get_return_type().unwrap().into_struct_type(),
714 &[v1, pack_i32s(v2, v3)?],
715 )
716 }
717 [v1, v2, v3, v4] if is_32(v1) && is_32(v2) && is_32(v3) && is_32(v4) => {
718 let v1v2_pack = if is_f32(v1) && is_f32(v2) {
719 pack_f32s(v1, v2)?
720 } else {
721 let v1 = err!(builder.build_bit_cast(v1, intrinsics.i32_ty, ""));
722 let v2 = err!(builder.build_bit_cast(v2, intrinsics.i32_ty, ""));
723 pack_i32s(v1, v2)?
724 };
725 let v3v4_pack = if is_f32(v3) && is_f32(v4) {
726 pack_f32s(v3, v4)?
727 } else {
728 let v3 = err!(builder.build_bit_cast(v3, intrinsics.i32_ty, ""));
729 let v4 = err!(builder.build_bit_cast(v4, intrinsics.i32_ty, ""));
730 pack_i32s(v3, v4)?
731 };
732 build_struct(
733 func_type.get_return_type().unwrap().into_struct_type(),
734 &[v1v2_pack, v3v4_pack],
735 )
736 }
737 _ => {
738 unreachable!("called to perform register return on struct return or void function")
739 }
740 })
741 }
742}