1#![allow(unused)]
3
4use crate::{
5 abi::{LLVMAbi, get_abi},
6 config::LLVM,
7 error::{err, err_nt},
8 object_file::{RkyvCompiledFunction, load_object_file},
9 translator::intrinsics::{Intrinsics, type_to_llvm},
10};
11use inkwell::{
12 AddressSpace, DLLStorageClass,
13 attributes::{Attribute, AttributeLoc},
14 context::Context,
15 module::{Linkage, Module},
16 passes::PassBuilderOptions,
17 targets::{FileType, TargetMachine},
18 types::FunctionType,
19 values::{BasicMetadataValueEnum, FunctionValue},
20};
21use std::{cmp, convert::TryInto};
22use target_lexicon::{BinaryFormat, Triple};
23use wasmer_compiler::{
24 misc::{CompiledFunctionExt, CompiledKind},
25 types::{
26 function::{CompiledFunctionBody, FunctionBody},
27 module::CompileModuleInfo,
28 relocation::{Relocation, RelocationTarget},
29 section::{CustomSection, CustomSectionProtection, SectionBody, SectionIndex},
30 },
31};
32use wasmer_types::{
33 CompileError, FunctionIndex, FunctionType as FuncType, LocalFunctionIndex, MemoryIndex,
34 entity::PrimaryMap,
35};
36use wasmer_vm::MemoryStyle;
37
38pub struct FuncTrampoline {
39 ctx: Context,
40 target_machine: TargetMachine,
41 target_triple: Triple,
42 abi: LLVMAbi,
43 binary_fmt: BinaryFormat,
44 func_section: String,
45}
46
47const FUNCTION_SECTION_ELF: &str = "__TEXT,wasmer_trmpl"; const FUNCTION_SECTION_MACHO: &str = "wasmer_trmpl"; fn enable_m0_optimization(compile_info: &CompileModuleInfo) -> bool {
51 compile_info
52 .memory_styles
53 .get(MemoryIndex::from_u32(0))
54 .is_some_and(|memory| matches!(memory, MemoryStyle::Static))
55}
56
57impl FuncTrampoline {
58 pub fn new(
59 target_machine: TargetMachine,
60 target_triple: Triple,
61 binary_fmt: BinaryFormat,
62 ) -> Result<Self, CompileError> {
63 let abi = get_abi(&target_machine)?;
64 Ok(Self {
65 ctx: Context::create(),
66 target_machine,
67 target_triple,
68 abi,
69 func_section: match binary_fmt {
70 BinaryFormat::Elf => FUNCTION_SECTION_ELF.to_string(),
71 BinaryFormat::Macho => FUNCTION_SECTION_MACHO.to_string(),
72 _ => {
73 return Err(CompileError::UnsupportedTarget(format!(
74 "Unsupported binary format: {binary_fmt:?}",
75 )));
76 }
77 },
78 binary_fmt,
79 })
80 }
81
82 pub fn trampoline_to_module(
83 &self,
84 ty: &FuncType,
85 config: &LLVM,
86 function: &CompiledKind,
87 compile_info: &CompileModuleInfo,
88 ) -> Result<Module<'_>, CompileError> {
89 let module = self.ctx.create_module("");
91 let target_machine = &self.target_machine;
92 let target_triple = target_machine.get_triple();
93 let target_data: inkwell::targets::TargetData = target_machine.get_target_data();
94 module.set_triple(&target_triple);
95 module.set_data_layout(&target_data.get_data_layout());
96 let intrinsics = Intrinsics::declare(
97 &module,
98 &self.ctx,
99 &target_data,
100 &self.target_triple,
101 &self.binary_fmt,
102 );
103
104 let m0_is_enabled = enable_m0_optimization(compile_info);
105 let (callee_ty, callee_attrs) =
106 self.abi
107 .func_type_to_llvm(&self.ctx, &intrinsics, None, ty, m0_is_enabled)?;
108 let trampoline_ty = intrinsics.void_ty.fn_type(
109 &[
110 intrinsics.ptr_ty.into(), intrinsics.ptr_ty.into(), intrinsics.ptr_ty.into(), ],
114 false,
115 );
116
117 let trampoline_func = module.add_function(
118 &function.linkage_name(),
119 trampoline_ty,
120 Some(Linkage::External),
121 );
122 if !config.experimental_artifact {
123 trampoline_func
124 .as_global_value()
125 .set_section(Some(&self.func_section));
126 }
127 trampoline_func
128 .as_global_value()
129 .set_linkage(Linkage::DLLExport);
130 trampoline_func
131 .as_global_value()
132 .set_dll_storage_class(DLLStorageClass::Export);
133 trampoline_func.add_attribute(AttributeLoc::Function, intrinsics.nounwind);
136 trampoline_func.add_attribute(AttributeLoc::Function, intrinsics.frame_pointer);
137 self.generate_trampoline(
138 config,
139 compile_info,
140 trampoline_func,
141 ty,
142 callee_ty,
143 &callee_attrs,
144 &self.ctx,
145 &intrinsics,
146 )?;
147
148 if let Some(ref callbacks) = config.callbacks {
149 callbacks.preopt_ir(function, &compile_info.module.hash_string(), &module);
150 }
151
152 let mut passes = vec![];
153
154 if config.enable_verifier {
155 passes.push("verify");
156 }
157
158 passes.push("instcombine");
159 module
160 .run_passes(
161 passes.join(",").as_str(),
162 target_machine,
163 PassBuilderOptions::create(),
164 )
165 .unwrap();
166
167 if let Some(ref callbacks) = config.callbacks {
168 callbacks.postopt_ir(function, &compile_info.module.hash_string(), &module);
169 }
170 Ok(module)
171 }
172
173 pub fn trampoline(
174 &self,
175 ty: &FuncType,
176 config: &LLVM,
177 function: &CompiledKind,
178 compile_info: &CompileModuleInfo,
179 ) -> Result<CompiledFunctionBody, CompileError> {
180 let module = self.trampoline_to_module(ty, config, function, compile_info)?;
181 let target_machine = &self.target_machine;
182
183 let memory_buffer = target_machine
184 .write_to_memory_buffer(&module, FileType::Object)
185 .unwrap();
186
187 if let Some(ref callbacks) = config.callbacks {
188 let module_hash = compile_info.module.hash_string();
189 callbacks.obj_memory_buffer(function, &module_hash, &memory_buffer);
190 let asm_buffer = target_machine
191 .write_to_memory_buffer(&module, FileType::Assembly)
192 .unwrap();
193 callbacks.asm_memory_buffer(function, &module_hash, &asm_buffer);
194 }
195
196 if config.experimental_artifact {
197 Ok(CompiledFunctionBody::Elf(memory_buffer.as_slice().to_vec()))
198 } else {
199 let dummy_reloc_target =
206 RelocationTarget::DynamicTrampoline(FunctionIndex::from_u32(u32::MAX - 1));
207
208 let RkyvCompiledFunction {
212 compiled_function,
213 custom_sections,
214 eh_frame_section_indices,
215 mut compact_unwind_section_indices,
216 ..
217 } = load_object_file(
218 memory_buffer.as_slice(),
219 &self.func_section,
220 dummy_reloc_target,
221 |name: &str| {
222 Err(CompileError::Codegen(format!(
223 "trampoline generation produced reference to unknown function {name}",
224 )))
225 },
226 self.binary_fmt,
227 &self.target_triple,
228 )?;
229 let mut all_sections_are_eh_sections = true;
230 let mut unwind_section_indices = eh_frame_section_indices;
231 unwind_section_indices.append(&mut compact_unwind_section_indices);
232 if unwind_section_indices.len() != custom_sections.len() {
233 all_sections_are_eh_sections = false;
234 } else {
235 unwind_section_indices.sort_unstable();
236 for (idx, section_idx) in unwind_section_indices.iter().enumerate() {
237 if idx as u32 != section_idx.as_u32() {
238 all_sections_are_eh_sections = false;
239 break;
240 }
241 }
242 }
243 if !all_sections_are_eh_sections {
244 return Err(CompileError::Codegen(
245 "trampoline generation produced non-eh custom sections".into(),
246 ));
247 }
248 if !compiled_function.relocations.is_empty() {
249 return Err(CompileError::Codegen(
250 "trampoline generation produced relocations".into(),
251 ));
252 }
253 Ok(CompiledFunctionBody::Rkyv(FunctionBody {
256 body: compiled_function.body.body,
257 unwind_info: compiled_function.body.unwind_info,
258 }))
259 }
260 }
261
262 pub fn dynamic_trampoline_to_module(
263 &self,
264 ty: &FuncType,
265 config: &LLVM,
266 function: &CompiledKind,
267 module_hash: &Option<String>,
268 ) -> Result<Module<'_>, CompileError> {
269 let module = self.ctx.create_module("");
271 let target_machine = &self.target_machine;
272 let target_data = target_machine.get_target_data();
273 let target_triple = target_machine.get_triple();
274 module.set_triple(&target_triple);
275 module.set_data_layout(&target_data.get_data_layout());
276 let intrinsics = Intrinsics::declare(
277 &module,
278 &self.ctx,
279 &target_data,
280 &self.target_triple,
281 &self.binary_fmt,
282 );
283
284 let (trampoline_ty, trampoline_attrs) =
285 self.abi
286 .func_type_to_llvm(&self.ctx, &intrinsics, None, ty, false)?;
287 let trampoline_func = module.add_function(
288 &function.linkage_name(),
289 trampoline_ty,
290 Some(Linkage::External),
291 );
292 trampoline_func.set_personality_function(intrinsics.personality);
293 trampoline_func.add_attribute(AttributeLoc::Function, intrinsics.frame_pointer);
294 for (attr, attr_loc) in trampoline_attrs {
295 trampoline_func.add_attribute(attr_loc, attr);
296 }
297 if !config.experimental_artifact {
298 trampoline_func
299 .as_global_value()
300 .set_section(Some(&self.func_section));
301 }
302 trampoline_func
303 .as_global_value()
304 .set_linkage(Linkage::DLLExport);
305 trampoline_func
306 .as_global_value()
307 .set_dll_storage_class(DLLStorageClass::Export);
308 self.generate_dynamic_trampoline(trampoline_func, ty, &self.ctx, &intrinsics)?;
309
310 if let Some(ref callbacks) = config.callbacks {
311 callbacks.preopt_ir(function, module_hash, &module);
312 }
313
314 let mut passes = vec![];
315
316 if config.enable_verifier {
317 passes.push("verify");
318 }
319
320 passes.push("early-cse");
321 module
322 .run_passes(
323 passes.join(",").as_str(),
324 target_machine,
325 PassBuilderOptions::create(),
326 )
327 .unwrap();
328
329 if let Some(ref callbacks) = config.callbacks {
330 callbacks.postopt_ir(function, module_hash, &module);
331 }
332
333 Ok(module)
334 }
335
336 #[allow(clippy::too_many_arguments)]
337 pub fn dynamic_trampoline(
338 &self,
339 ty: &FuncType,
340 config: &LLVM,
341 function: &CompiledKind,
342 dynamic_trampoline_index: u32,
343 final_module_custom_sections: &mut PrimaryMap<SectionIndex, CustomSection>,
344 eh_frame_section_bytes: &mut Vec<u8>,
345 eh_frame_section_relocations: &mut Vec<Relocation>,
346 compact_unwind_section_bytes: &mut Vec<u8>,
347 compact_unwind_section_relocations: &mut Vec<Relocation>,
348 module_hash: &Option<String>,
349 ) -> Result<CompiledFunctionBody, CompileError> {
350 let target_machine = &self.target_machine;
351
352 let module = self.dynamic_trampoline_to_module(ty, config, function, module_hash)?;
353
354 let memory_buffer = target_machine
355 .write_to_memory_buffer(&module, FileType::Object)
356 .unwrap();
357
358 if let Some(ref callbacks) = config.callbacks {
359 callbacks.obj_memory_buffer(function, module_hash, &memory_buffer);
360 let asm_buffer = target_machine
361 .write_to_memory_buffer(&module, FileType::Assembly)
362 .unwrap();
363 callbacks.asm_memory_buffer(function, module_hash, &asm_buffer)
364 }
365
366 if config.experimental_artifact {
367 Ok(CompiledFunctionBody::Elf(memory_buffer.as_slice().to_vec()))
368 } else {
369 let RkyvCompiledFunction {
370 compiled_function,
371 custom_sections,
372 eh_frame_section_indices,
373 compact_unwind_section_indices,
374 gcc_except_table_section_indices,
375 data_dw_ref_personality_section_indices,
376 } = load_object_file(
377 memory_buffer.as_slice(),
378 &self.func_section,
379 RelocationTarget::DynamicTrampoline(FunctionIndex::from_u32(
380 dynamic_trampoline_index,
381 )),
382 |name: &str| {
383 Err(CompileError::Codegen(format!(
384 "trampoline generation produced reference to unknown function {name}",
385 )))
386 },
387 self.binary_fmt,
388 &self.target_triple,
389 )?;
390
391 if !compiled_function.relocations.is_empty() {
392 return Err(CompileError::Codegen(
393 "trampoline generation produced relocations".into(),
394 ));
395 }
396 {
401 let first_section = final_module_custom_sections.len() as u32;
402 for (section_index, mut custom_section) in custom_sections.into_iter() {
403 for reloc in &mut custom_section.relocations {
404 if let RelocationTarget::CustomSection(index) = reloc.reloc_target {
405 reloc.reloc_target = RelocationTarget::CustomSection(
406 SectionIndex::from_u32(first_section + index.as_u32()),
407 )
408 }
409
410 if reloc.kind.needs_got() {
411 return Err(CompileError::Codegen(
412 "trampoline generation produced GOT relocation".into(),
413 ));
414 }
415 }
416
417 if eh_frame_section_indices.contains(§ion_index) {
418 let offset = eh_frame_section_bytes.len() as u32;
419 for reloc in &mut custom_section.relocations {
420 reloc.offset += offset;
421 }
422 eh_frame_section_bytes.extend_from_slice(custom_section.bytes.as_slice());
423 eh_frame_section_bytes.extend_from_slice(&[0, 0, 0, 0]);
425 eh_frame_section_relocations.extend(custom_section.relocations);
426 final_module_custom_sections.push(CustomSection {
428 protection: CustomSectionProtection::Read,
429 alignment: None,
430 bytes: SectionBody::new_with_vec(vec![]),
431 relocations: vec![],
432 });
433 } else if compact_unwind_section_indices.contains(§ion_index) {
434 let offset = compact_unwind_section_bytes.len() as u32;
435 for reloc in &mut custom_section.relocations {
436 reloc.offset += offset;
437 }
438 compact_unwind_section_bytes
439 .extend_from_slice(custom_section.bytes.as_slice());
440 compact_unwind_section_relocations.extend(custom_section.relocations);
441 final_module_custom_sections.push(CustomSection {
443 protection: CustomSectionProtection::Read,
444 alignment: None,
445 bytes: SectionBody::new_with_vec(vec![]),
446 relocations: vec![],
447 });
448 } else if gcc_except_table_section_indices.contains(§ion_index)
449 || data_dw_ref_personality_section_indices.contains(§ion_index)
450 {
451 final_module_custom_sections.push(custom_section);
452 } else {
453 return Err(CompileError::Codegen(
454 "trampoline generation produced non-eh custom sections".into(),
455 ));
456 }
457 }
458 }
459
460 Ok(CompiledFunctionBody::Rkyv(FunctionBody {
461 body: compiled_function.body.body,
462 unwind_info: compiled_function.body.unwind_info,
463 }))
464 }
465 }
466
467 #[allow(clippy::too_many_arguments)]
468 fn generate_trampoline<'ctx>(
469 &self,
470 config: &LLVM,
471 compile_info: &CompileModuleInfo,
472 trampoline_func: FunctionValue,
473 func_sig: &FuncType,
474 llvm_func_type: FunctionType,
475 func_attrs: &[(Attribute, AttributeLoc)],
476 context: &'ctx Context,
477 intrinsics: &Intrinsics<'ctx>,
478 ) -> Result<(), CompileError> {
479 let entry_block = context.append_basic_block(trampoline_func, "entry");
480 let builder = context.create_builder();
481 builder.position_at_end(entry_block);
482
483 let (callee_vmctx_ptr, func_ptr, args_rets_ptr) =
484 match *trampoline_func.get_params().as_slice() {
485 [callee_vmctx_ptr, func_ptr, args_rets_ptr] => (
486 callee_vmctx_ptr,
487 func_ptr.into_pointer_value(),
488 args_rets_ptr.into_pointer_value(),
489 ),
490 _ => {
491 return Err(CompileError::Codegen(
492 "trampoline function unimplemented".to_string(),
493 ));
494 }
495 };
496 func_ptr.set_name("func_ptr");
497
498 let mut args_vec = Vec::with_capacity(func_sig.params().len() + 3);
499
500 if self.abi.is_sret(func_sig)? {
501 let basic_types: Vec<_> = func_sig
502 .results()
503 .iter()
504 .map(|&ty| type_to_llvm(intrinsics, ty))
505 .collect::<Result<_, _>>()?;
506
507 let sret_ty = context.struct_type(&basic_types, false);
508 args_vec.push(err!(builder.build_alloca(sret_ty, "sret")).into());
509 }
510
511 callee_vmctx_ptr.set_name("vmctx");
512 args_vec.push(callee_vmctx_ptr.into());
513
514 if enable_m0_optimization(compile_info) {
515 let wasm_module = &compile_info.module;
516 let memory_styles = &compile_info.memory_styles;
517 let callee_vmctx_ptr_value = callee_vmctx_ptr.into_pointer_value();
518 let offsets = wasmer_vm::VMOffsets::new(8, wasm_module);
519
520 let memory_index = wasmer_types::MemoryIndex::from_u32(0);
522 let memory_definition_ptr = if let Some(local_memory_index) =
523 wasm_module.local_memory_index(memory_index)
524 {
525 let offset = offsets.vmctx_vmmemory_definition(local_memory_index);
526 let offset = intrinsics.i32_ty.const_int(offset.into(), false);
527 unsafe {
528 err!(builder.build_gep(intrinsics.i8_ty, callee_vmctx_ptr_value, &[offset], ""))
529 }
530 } else {
531 let offset = offsets.vmctx_vmmemory_import(memory_index);
532 let offset = intrinsics.i32_ty.const_int(offset.into(), false);
533 let memory_definition_ptr_ptr = unsafe {
534 err!(builder.build_gep(intrinsics.i8_ty, callee_vmctx_ptr_value, &[offset], ""))
535 };
536 let memory_definition_ptr_ptr =
537 err!(builder.build_bit_cast(memory_definition_ptr_ptr, intrinsics.ptr_ty, "",))
538 .into_pointer_value();
539
540 err!(builder.build_load(intrinsics.ptr_ty, memory_definition_ptr_ptr, ""))
541 .into_pointer_value()
542 };
543 let memory_definition_ptr =
544 err!(builder.build_bit_cast(memory_definition_ptr, intrinsics.ptr_ty, "",))
545 .into_pointer_value();
546 let base_ptr = err!(builder.build_struct_gep(
547 intrinsics.vmmemory_definition_ty,
548 memory_definition_ptr,
549 intrinsics.vmmemory_definition_base_element,
550 "",
551 ));
552
553 let memory_style = &memory_styles[memory_index];
554 let base_ptr = if let MemoryStyle::Dynamic { .. } = memory_style {
555 base_ptr
556 } else {
557 err!(builder.build_load(intrinsics.ptr_ty, base_ptr, "")).into_pointer_value()
558 };
559
560 base_ptr.set_name("trmpl_m0_base_ptr");
561
562 args_vec.push(base_ptr.into());
563 }
564
565 for (i, param_ty) in func_sig.params().iter().enumerate() {
566 let index = intrinsics.i32_ty.const_int(i as _, false);
567 let item_pointer = unsafe {
568 err!(builder.build_in_bounds_gep(
569 intrinsics.i128_ty,
570 args_rets_ptr,
571 &[index],
572 "arg_ptr"
573 ))
574 };
575
576 let casted_type = type_to_llvm(intrinsics, *param_ty)?;
577
578 let typed_item_pointer = err!(builder.build_pointer_cast(
579 item_pointer,
580 intrinsics.ptr_ty,
581 "typed_arg_pointer"
582 ));
583
584 let arg = err!(builder.build_load(casted_type, typed_item_pointer, "arg"));
585 args_vec.push(arg.into());
586 }
587
588 let call_site = err!(builder.build_indirect_call(
589 llvm_func_type,
590 func_ptr,
591 args_vec.as_slice(),
592 "call"
593 ));
594 for (attr, attr_loc) in func_attrs {
595 call_site.add_attribute(*attr_loc, *attr);
596 }
597
598 let rets = self
599 .abi
600 .rets_from_call(&builder, intrinsics, call_site, func_sig)?;
601 for (idx, v) in rets.into_iter().enumerate() {
602 let ptr = unsafe {
603 err!(builder.build_gep(
604 intrinsics.i128_ty,
605 args_rets_ptr,
606 &[intrinsics.i32_ty.const_int(idx as u64, false)],
607 "",
608 ))
609 };
610 let ptr = err!(builder.build_pointer_cast(
611 ptr,
612 self.ctx.ptr_type(AddressSpace::default()),
613 ""
614 ));
615 err!(builder.build_store(ptr, v));
616 }
617
618 err!(builder.build_return(None));
619 Ok(())
620 }
621
622 fn generate_dynamic_trampoline<'ctx>(
623 &self,
624 trampoline_func: FunctionValue,
625 func_sig: &FuncType,
626 context: &'ctx Context,
627 intrinsics: &Intrinsics<'ctx>,
628 ) -> Result<(), CompileError> {
629 let entry_block = context.append_basic_block(trampoline_func, "entry");
630 let builder = context.create_builder();
631 builder.position_at_end(entry_block);
632
633 let values = err!(builder.build_alloca(
635 intrinsics.i128_ty.array_type(cmp::max(
636 func_sig.params().len().try_into().unwrap(),
637 func_sig.results().len().try_into().unwrap(),
638 )),
639 "",
640 ));
641
642 let first_user_param = if self.abi.is_sret(func_sig)? { 2 } else { 1 };
644 for i in 0..func_sig.params().len() {
645 let ptr = unsafe {
646 err!(builder.build_in_bounds_gep(
647 intrinsics.i128_ty,
648 values,
649 &[intrinsics.i32_ty.const_int(i.try_into().unwrap(), false)],
650 "args",
651 ))
652 };
653 let ptr = err!(builder.build_bit_cast(ptr, intrinsics.ptr_ty, "")).into_pointer_value();
654 err!(
655 builder.build_store(
656 ptr,
657 trampoline_func
658 .get_nth_param(i as u32 + first_user_param)
659 .unwrap(),
660 )
661 );
662 }
663
664 let callee_ptr_ty = intrinsics.void_ty.fn_type(
665 &[
666 intrinsics.ptr_ty.into(), intrinsics.ptr_ty.into(), ],
669 false,
670 );
671 let vmctx = self.abi.get_vmctx_ptr_param(&trampoline_func);
672 let callee_ty =
673 err!(builder.build_bit_cast(vmctx, self.ctx.ptr_type(AddressSpace::default()), ""));
674 let callee =
675 err!(builder.build_load(intrinsics.ptr_ty, callee_ty.into_pointer_value(), ""))
676 .into_pointer_value();
677 callee.set_name("func_ptr");
678
679 let values_ptr = err!(builder.build_pointer_cast(values, intrinsics.ptr_ty, ""));
680 values_ptr.set_name("value_ptr");
681 err!(builder.build_indirect_call(
682 callee_ptr_ty,
683 callee,
684 &[vmctx.into(), values_ptr.into()],
685 "",
686 ));
687
688 if func_sig.results().is_empty() {
689 err!(builder.build_return(None));
690 } else {
691 let results = func_sig
692 .results()
693 .iter()
694 .enumerate()
695 .map(|(idx, ty)| {
696 let ptr = unsafe {
697 err!(builder.build_gep(
698 intrinsics.i128_ty,
699 values,
700 &[intrinsics.i32_ty.const_int(idx.try_into().unwrap(), false)],
701 "",
702 ))
703 };
704 let ptr = err!(builder.build_pointer_cast(ptr, intrinsics.ptr_ty, ""));
705 err_nt!(builder.build_load(type_to_llvm(intrinsics, *ty)?, ptr, ""))
706 })
707 .collect::<Result<Vec<_>, CompileError>>()?;
708
709 if self.abi.is_sret(func_sig)? {
710 let sret = trampoline_func
711 .get_first_param()
712 .unwrap()
713 .into_pointer_value();
714
715 let basic_types: Vec<_> = func_sig
716 .results()
717 .iter()
718 .map(|&ty| type_to_llvm(intrinsics, ty))
719 .collect::<Result<_, _>>()?;
720 let mut struct_value = context.struct_type(&basic_types, false).get_undef();
721
722 for (idx, value) in results.iter().enumerate() {
723 let value = err!(builder.build_bit_cast(
724 *value,
725 type_to_llvm(intrinsics, func_sig.results()[idx])?,
726 "",
727 ));
728 struct_value =
729 err!(builder.build_insert_value(struct_value, value, idx as u32, ""))
730 .into_struct_value();
731 }
732 err!(builder.build_store(sret, struct_value));
733 err!(builder.build_return(None));
734 } else {
735 err!(
736 builder.build_return(Some(&self.abi.pack_values_for_register_return(
737 intrinsics,
738 &builder,
739 results.as_slice(),
740 func_sig,
741 &trampoline_func.get_type(),
742 )?))
743 );
744 }
745 }
746
747 Ok(())
748 }
749}