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