1use std::collections::{HashMap, HashSet};
75
76use rucc_base::Symbol;
77use rucc_ir::{
78 Datum, Def, Extra, Facts, Flags, Func, FuncId, Inst, Linkage, Module, Opcode, Pic, Type, Value,
79};
80
81use crate::discharge::{Fact, about, alive, covers, derives, normal, settled};
82use crate::extents::extents;
83
84pub fn annotate(module: &mut Module, pic: Pic) -> usize {
91 let reachable = reachable(module);
92 let closed: Vec<FuncId> = module
93 .funcs()
94 .filter(|&id| {
95 let func = &module[id];
96 !func.is_declaration()
97 && func.linkage == Linkage::Internal
98 && !reachable.contains(&func.name)
99 })
100 .collect();
101 if closed.is_empty() {
102 return 0;
103 }
104 let mut where_defined: HashMap<_, FuncId> = HashMap::new();
105 for &id in &closed {
106 where_defined.insert(module[id].name, id);
107 }
108 let sites = sites(module, &where_defined);
109 let aligns = aligns(module, &closed, &sites);
110 write_aligns(module, &aligns);
111 let globals = extents(module, pic);
112 let handed = handed(module, &closed, &sites, &globals);
113 if handed.is_empty() {
114 return 0;
115 }
116 let mut marked = 0;
117 for id in closed {
118 let Some(sizes) = handed.get(&id) else { continue };
119 let func = &module[id];
120 let Some(entry) = func.entry() else { continue };
121 let object = |base: Value| -> Option<Fact> {
122 let Def::Param { block, index } = func[base].def else { return None };
123 if block != entry {
124 return None;
125 }
126 Some(Fact::whole(base, i128::from(*sizes.get(&index)?)))
127 };
128 let marks: Vec<Inst> = func
129 .blocks()
130 .flat_map(|block| func.insts(block).collect::<Vec<_>>())
131 .filter(|&inst| !func[inst].flags.contains(Flags::HANDED))
132 .filter(|&inst| inside(func, inst, &object))
133 .collect();
134 marked += marks.len();
135 let func = &mut module[id];
136 for inst in marks {
137 func[inst].flags |= Flags::HANDED;
138 }
139 }
140 marked
141}
142
143fn handed(
149 module: &Module,
150 closed: &[FuncId],
151 sites: &HashMap<FuncId, Vec<(FuncId, Inst)>>,
152 globals: &HashMap<Symbol, u64>,
153) -> HashMap<FuncId, HashMap<u32, u64>> {
154 let mut known: HashMap<FuncId, HashMap<u32, u64>> = HashMap::new();
155 loop {
156 let mut settled = true;
157 for &id in closed {
158 let Some(calls) = sites.get(&id) else { continue };
159 let count = module[id].signature().params.len();
160 let mut sizes = HashMap::new();
161 for index in 0..count {
162 if module[id].signature().params[index].ty != Type::PTR {
163 continue;
164 }
165 let Some(least) = least(module, calls, index, globals, &known) else { continue };
166 sizes.insert(u32::try_from(index).unwrap_or(u32::MAX), least);
167 }
168 if known.get(&id) != Some(&sizes) {
169 known.insert(id, sizes);
170 settled = false;
171 }
172 }
173 if settled {
174 known.retain(|_, sizes| !sizes.is_empty());
175 return known;
176 }
177 }
178}
179
180fn least(
187 module: &Module,
188 calls: &[(FuncId, Inst)],
189 index: usize,
190 globals: &HashMap<Symbol, u64>,
191 known: &HashMap<FuncId, HashMap<u32, u64>>,
192) -> Option<u64> {
193 let mut least = None;
194 for &(caller, inst) in calls {
195 let func = &module[caller];
196 let &value = func[func[inst].args].get(index)?;
197 let left = passed(caller, func, value, globals, known)?;
198 least = Some(least.map_or(left, |so_far: u64| so_far.min(left)));
199 }
200 least
201}
202
203fn passed(
209 caller: FuncId,
210 func: &Func,
211 value: Value,
212 globals: &HashMap<Symbol, u64>,
213 known: &HashMap<FuncId, HashMap<u32, u64>>,
214) -> Option<u64> {
215 let (base, offset) = normal(func, value);
216 let whole = i128::from(object(caller, func, base, globals, known)?);
217 if offset < 0 || offset > whole {
218 return None;
219 }
220 u64::try_from(whole - offset).ok()
221}
222
223fn object(
225 caller: FuncId,
226 func: &Func,
227 base: Value,
228 globals: &HashMap<Symbol, u64>,
229 known: &HashMap<FuncId, HashMap<u32, u64>>,
230) -> Option<u64> {
231 match func[base].def {
232 Def::Param { block, index } => {
236 if func.entry() != Some(block) {
237 return None;
238 }
239 known.get(&caller)?.get(&index).copied()
240 }
241 Def::Result { inst, .. } => match func[inst].opcode {
242 Opcode::Alloca if func[func[inst].args].is_empty() => {
243 let Extra::Mem(info) = func[inst].extra else { return None };
244 Some(func[info].size)
245 }
246 Opcode::GlobalAddr => {
247 let Extra::Symbol(name) = func[inst].extra else { return None };
248 globals.get(&name).copied()
249 }
250 _ => None,
251 },
252 }
253}
254
255fn aligns(
282 module: &Module,
283 closed: &[FuncId],
284 sites: &HashMap<FuncId, Vec<(FuncId, Inst)>>,
285) -> HashMap<FuncId, HashMap<u32, u32>> {
286 let mut known: HashMap<FuncId, HashMap<u32, u32>> = HashMap::new();
287 loop {
288 let mut stable = true;
289 for &id in closed {
290 let Some(calls) = sites.get(&id) else { continue };
291 let count = module[id].signature().params.len();
292 let mut alignments = HashMap::new();
293 for index in 0..count {
294 if module[id].signature().params[index].ty != Type::PTR {
295 continue;
296 }
297 let Some(least) = least_align(module, calls, index, &known) else { continue };
298 alignments.insert(u32::try_from(index).unwrap_or(u32::MAX), least);
299 }
300 if known.get(&id) != Some(&alignments) {
301 known.insert(id, alignments);
302 stable = false;
303 }
304 }
305 if stable {
306 known.retain(|_, alignments| !alignments.is_empty());
307 return known;
308 }
309 }
310}
311
312fn least_align(
321 module: &Module,
322 calls: &[(FuncId, Inst)],
323 index: usize,
324 known: &HashMap<FuncId, HashMap<u32, u32>>,
325) -> Option<u32> {
326 let mut least = None;
327 for &(caller, inst) in calls {
328 let func = &module[caller];
329 let &value = func[func[inst].args].get(index)?;
330 let carried = carried(func, caller, known);
331 let found = u32::try_from(settled(func, None, &carried, value)).ok()?;
332 if found <= 1 || !found.is_power_of_two() {
333 return None;
334 }
335 least = Some(least.map_or(found, |so_far: u32| so_far.min(found)));
336 }
337 least
338}
339
340fn carried(
345 func: &Func,
346 caller: FuncId,
347 known: &HashMap<FuncId, HashMap<u32, u32>>,
348) -> HashMap<Value, u64> {
349 let mut carried = HashMap::new();
350 let (Some(entry), Some(alignments)) = (func.entry(), known.get(&caller)) else {
351 return carried;
352 };
353 for (&index, &align) in alignments {
354 if let Some(¶m) = func[entry].params.get(index as usize) {
355 carried.insert(param, u64::from(align));
356 }
357 }
358 carried
359}
360
361fn write_aligns(module: &mut Module, table: &HashMap<FuncId, HashMap<u32, u32>>) {
373 for (&id, alignments) in table {
374 let func = &mut module[id];
375 let Some(entry) = func.entry() else { continue };
376 for (&index, &align) in alignments {
377 let Some(¶m) = func[entry].params.get(index as usize) else { continue };
378 if func[param].ty != Type::PTR {
379 continue;
380 }
381 let had = func.facts(param);
382 let align = align.max(had.align.unwrap_or(0));
383 func.set_facts(param, Facts { align: Some(align), ..had });
384 }
385 }
386}
387
388fn sites(
395 module: &Module,
396 where_defined: &HashMap<Symbol, FuncId>,
397) -> HashMap<FuncId, Vec<(FuncId, Inst)>> {
398 let mut sites: HashMap<FuncId, Vec<(FuncId, Inst)>> = HashMap::new();
399 for id in module.funcs() {
400 let func = &module[id];
401 if func.is_declaration() {
402 continue;
403 }
404 for block in func.blocks() {
405 for inst in func.insts(block) {
406 if !matches!(func[inst].opcode, Opcode::Call | Opcode::TailCall) {
407 continue;
408 }
409 let Extra::Call(at) = func[inst].extra else { continue };
410 let Some(callee) = func[at].callee else { continue };
411 let Some(&target) = where_defined.get(&callee) else { continue };
412 let signature = module[target].signature();
413 if signature.variadic || signature.params.len() != func[func[inst].args].len() {
414 continue;
415 }
416 sites.entry(target).or_default().push((id, inst));
417 }
418 }
419 }
420 sites
421}
422
423fn reachable(module: &Module) -> HashSet<Symbol> {
429 let mut taken = HashSet::new();
430 for id in module.funcs() {
431 let func = &module[id];
432 if func.is_declaration() {
433 continue;
434 }
435 for block in func.blocks() {
436 for inst in func.insts(block) {
437 if func[inst].opcode != Opcode::GlobalAddr {
438 continue;
439 }
440 if let Extra::Symbol(name) = func[inst].extra {
441 taken.insert(name);
442 }
443 }
444 }
445 }
446 for id in module.globals() {
447 let Some(init) = module[id].init else { continue };
448 for &datum in &module[init] {
449 if let Datum::Addr(at) | Datum::Away(at) = datum {
450 taken.insert(module[at].symbol);
451 }
452 }
453 }
454 for id in module.aliases() {
455 taken.insert(module[id].target);
456 }
457 taken
458}
459
460fn inside(func: &Func, inst: Inst, object: &impl Fn(Value) -> Option<Fact>) -> bool {
465 match func[inst].opcode {
466 Opcode::CheckBounds => {
467 if func[func[inst].args].len() > 2 {
468 return false;
469 }
470 let Some(asked) = about(func, inst) else { return false };
471 object(asked.base).is_some_and(|whole| covers(&whole, &asked))
472 }
473 Opcode::CheckLive => {
474 let Some(asked) = alive(func, inst) else { return false };
475 object(asked.base).is_some_and(|whole| covers(&whole, &asked))
476 }
477 Opcode::CheckDeriv => {
478 let Some((from, to)) = derives(func, inst) else { return false };
479 object(from.base).is_some_and(|whole| covers(&whole, &from) && covers(&whole, &to))
480 }
481 _ => false,
482 }
483}
484
485#[cfg(test)]
486mod tests {
487 use rucc_base::Interner;
488 use rucc_ir::{
489 Builder, Extra, Func, Global, InstData, Linkage, MemInfo, MemOrder, Module, Opcode, Pic,
490 Restrict, Signature, Type, Value,
491 };
492 use rucc_target::{TargetInfo, Triple};
493
494 use super::annotate;
495
496 fn module(names: &mut Interner) -> Module {
498 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse::<Triple>().unwrap());
499 Module::new(names.intern("t.c"), &target)
500 }
501
502 fn callee(names: &mut Interner, module: &mut Module, size: u64) {
505 let name = names.intern("g");
506 let mut func = Func::new(name, Signature::new().with_params(&[Type::PTR]));
507 func.linkage = Linkage::Internal;
508 let block = func.create_block();
509 let pointer = func.append_param(block, Type::PTR);
510 let mut build = Builder::new(&mut func, block);
511 check(&mut build, pointer, size);
512 live(&mut build, pointer);
513 build.ret(&[]);
514 module.add_func(func);
515 }
516
517 fn caller(
519 names: &mut Interner,
520 module: &mut Module,
521 name: &str,
522 argument: impl FnOnce(&mut Builder<'_>) -> Value,
523 ) {
524 let at = names.intern(name);
525 let called = names.intern("g");
526 let mut func = Func::new(at, Signature::new());
527 let block = func.create_block();
528 let mut build = Builder::new(&mut func, block);
529 let signature = build.func().add_signature(Signature::new().with_params(&[Type::PTR]));
530 let value = argument(&mut build);
531 build.call(called, signature, &[value]);
532 build.ret(&[]);
533 module.add_func(func);
534 }
535
536 fn local(build: &mut Builder<'_>, size: u64) -> Value {
538 let info = MemInfo {
539 size,
540 align: 8,
541 order: MemOrder::NotAtomic,
542 tbaa: None,
543 owns: 0,
544 restrict: Restrict::NONE,
545 };
546 let extra = Extra::Mem(build.func().add_mem(info));
547 build.value(InstData { extra, ..InstData::new(Opcode::Alloca) }, Type::PTR)
548 }
549
550 fn check(build: &mut Builder<'_>, pointer: Value, size: u64) {
552 let args = build.func().push_values(&[pointer]);
553 let capability = build.value(InstData { args, ..InstData::new(Opcode::CapOf) }, Type::CAP);
554 let info = MemInfo {
555 size,
556 align: 1,
557 order: MemOrder::NotAtomic,
558 tbaa: None,
559 owns: 0,
560 restrict: Restrict::NONE,
561 };
562 let args = build.func().push_values(&[capability, pointer]);
563 let extra = Extra::Mem(build.func().add_mem(info));
564 build.inst(InstData { args, extra, ..InstData::new(Opcode::CheckBounds) }, &[]);
565 }
566
567 fn live(build: &mut Builder<'_>, pointer: Value) {
569 let args = build.func().push_values(&[pointer]);
570 let capability = build.value(InstData { args, ..InstData::new(Opcode::CapOf) }, Type::CAP);
571 let args = build.func().push_values(&[capability, pointer]);
572 build.inst(InstData { args, ..InstData::new(Opcode::CheckLive) }, &[]);
573 }
574
575 fn past(build: &mut Builder<'_>, pointer: Value, bytes: i128) -> Value {
577 let offset = build.iconst(Type::int(64), bytes);
578 let args = build.func().push_values(&[pointer, offset]);
579 build.value(InstData { args, ..InstData::new(Opcode::PtrAdd) }, Type::PTR)
580 }
581
582 #[test]
583 fn a_check_on_a_parameter_every_call_hands_a_slot_big_enough_is_marked() {
584 let mut names = Interner::new();
585 let mut module = module(&mut names);
586 callee(&mut names, &mut module, 16);
587 caller(&mut names, &mut module, "f", |build| local(build, 32));
588 assert_eq!(
589 annotate(&mut module, Pic::Executable),
590 2,
591 "the bounds check and the lifetime one"
592 );
593 }
594
595 #[test]
596 fn a_call_handing_a_slot_too_small_marks_only_the_lifetime_check() {
597 let mut names = Interner::new();
601 let mut module = module(&mut names);
602 callee(&mut names, &mut module, 16);
603 caller(&mut names, &mut module, "f", |build| local(build, 8));
604 assert_eq!(annotate(&mut module, Pic::Executable), 1);
605 }
606
607 #[test]
608 fn the_fewest_bytes_any_call_hands_is_what_the_parameter_gets() {
609 let mut names = Interner::new();
613 let mut module = module(&mut names);
614 callee(&mut names, &mut module, 16);
615 caller(&mut names, &mut module, "f", |build| local(build, 32));
616 caller(&mut names, &mut module, "h", |build| local(build, 8));
617 assert_eq!(
618 annotate(&mut module, Pic::Executable),
619 1,
620 "the lifetime check, which eight bytes settle"
621 );
622 }
623
624 #[test]
625 fn a_call_handing_a_field_of_a_slot_leaves_what_is_past_the_field() {
626 let mut names = Interner::new();
629 let mut module = module(&mut names);
630 callee(&mut names, &mut module, 16);
631 caller(&mut names, &mut module, "f", |build| {
632 let slot = local(build, 32);
633 past(build, slot, 16)
634 });
635 assert_eq!(annotate(&mut module, Pic::Executable), 2);
636 }
637
638 #[test]
639 fn a_call_handing_a_field_that_leaves_too_little_marks_only_the_lifetime_check() {
640 let mut names = Interner::new();
643 let mut module = module(&mut names);
644 callee(&mut names, &mut module, 16);
645 caller(&mut names, &mut module, "f", |build| {
646 let slot = local(build, 32);
647 past(build, slot, 20)
648 });
649 assert_eq!(annotate(&mut module, Pic::Executable), 1);
650 }
651
652 #[test]
653 fn a_callee_anything_can_reach_is_left_alone() {
654 let mut names = Interner::new();
657 let mut module = module(&mut names);
658 callee(&mut names, &mut module, 16);
659 let id = module.funcs().next().expect("the callee");
660 module[id].linkage = Linkage::External;
661 caller(&mut names, &mut module, "f", |build| local(build, 32));
662 assert_eq!(annotate(&mut module, Pic::Executable), 0);
663 }
664
665 #[test]
666 fn a_callee_whose_address_is_taken_is_left_alone() {
667 let mut names = Interner::new();
670 let mut module = module(&mut names);
671 callee(&mut names, &mut module, 16);
672 caller(&mut names, &mut module, "f", |build| local(build, 32));
673 let called = names.intern("g");
674 caller(&mut names, &mut module, "h", |build| {
675 let extra = Extra::Symbol(called);
676 build.value(InstData { extra, ..InstData::new(Opcode::GlobalAddr) }, Type::PTR);
677 local(build, 32)
678 });
679 assert_eq!(annotate(&mut module, Pic::Executable), 0);
680 }
681
682 #[test]
683 fn a_callee_named_by_a_globals_image_is_left_alone() {
684 let mut names = Interner::new();
685 let mut module = module(&mut names);
686 callee(&mut names, &mut module, 16);
687 caller(&mut names, &mut module, "f", |build| local(build, 32));
688 let at = module.add_reloc(rucc_ir::Reloc { symbol: names.intern("g"), addend: 0, size: 8 });
689 let init = module.push_data(&[rucc_ir::Datum::Addr(at)]);
690 let mut global = Global::new(names.intern("table"), 8, 8);
691 global.init = Some(init);
692 module.add_global(global);
693 assert_eq!(annotate(&mut module, Pic::Executable), 0);
694 }
695
696 #[test]
697 fn a_callee_nothing_in_the_module_calls_is_left_alone() {
698 let mut names = Interner::new();
701 let mut module = module(&mut names);
702 callee(&mut names, &mut module, 16);
703 assert_eq!(annotate(&mut module, Pic::Executable), 0);
704 }
705
706 #[test]
707 fn a_chain_of_static_helpers_reaches_the_slot_at_the_top() {
708 let mut names = Interner::new();
712 let mut module = module(&mut names);
713 callee(&mut names, &mut module, 16);
714 let name = names.intern("h");
715 let called = names.intern("g");
716 let mut func = Func::new(name, Signature::new().with_params(&[Type::PTR]));
717 func.linkage = Linkage::Internal;
718 let block = func.create_block();
719 let pointer = func.append_param(block, Type::PTR);
720 let mut build = Builder::new(&mut func, block);
721 let signature = build.func().add_signature(Signature::new().with_params(&[Type::PTR]));
722 build.call(called, signature, &[pointer]);
723 build.ret(&[]);
724 module.add_func(func);
725 let at = names.intern("f");
726 let called = names.intern("h");
727 let mut func = Func::new(at, Signature::new());
728 let block = func.create_block();
729 let mut build = Builder::new(&mut func, block);
730 let signature = build.func().add_signature(Signature::new().with_params(&[Type::PTR]));
731 let slot = local(&mut build, 32);
732 build.call(called, signature, &[slot]);
733 build.ret(&[]);
734 module.add_func(func);
735 assert_eq!(annotate(&mut module, Pic::Executable), 2);
736 }
737
738 #[test]
739 fn two_functions_handing_each_other_their_own_parameter_hold_nothing_up() {
740 let mut names = Interner::new();
743 let mut module = module(&mut names);
744 relay(&mut names, &mut module, "g", "h", 16);
745 relay(&mut names, &mut module, "h", "g", 16);
746 assert_eq!(annotate(&mut module, Pic::Executable), 0);
747 }
748
749 fn fact(names: &mut Interner, module: &Module) -> Option<u32> {
751 let name = names.intern("g");
752 let id = module.funcs().find(|&id| module[id].name == name).expect("the callee");
753 let func = &module[id];
754 let entry = func.entry().expect("its entry block");
755 let ¶m = func[entry].params.first().expect("its pointer parameter");
756 func.facts(param).align
757 }
758
759 #[test]
760 fn an_alignment_every_call_hands_in_reaches_the_parameter() {
761 let mut names = Interner::new();
766 let mut module = module(&mut names);
767 callee(&mut names, &mut module, 16);
768 caller(&mut names, &mut module, "f", |build| local(build, 32));
769 annotate(&mut module, Pic::Executable);
770 assert_eq!(fact(&mut names, &module), Some(8));
771 }
772
773 #[test]
774 fn the_least_alignment_any_call_hands_is_what_the_parameter_gets() {
775 let mut names = Interner::new();
778 let mut module = module(&mut names);
779 callee(&mut names, &mut module, 16);
780 caller(&mut names, &mut module, "f", |build| local(build, 32));
781 caller(&mut names, &mut module, "h", |build| {
782 let slot = local(build, 32);
783 past(build, slot, 4)
784 });
785 annotate(&mut module, Pic::Executable);
786 assert_eq!(fact(&mut names, &module), Some(4));
787 }
788
789 #[test]
790 fn a_call_that_moves_a_pointer_off_its_alignment_leaves_the_parameter_with_nothing() {
791 let mut names = Interner::new();
796 let mut module = module(&mut names);
797 callee(&mut names, &mut module, 16);
798 caller(&mut names, &mut module, "f", |build| {
799 let slot = local(build, 32);
800 past(build, slot, 1)
801 });
802 annotate(&mut module, Pic::Executable);
803 assert_eq!(fact(&mut names, &module), None);
804 }
805
806 #[test]
807 fn one_call_this_cannot_read_leaves_the_parameter_with_nothing() {
808 let mut names = Interner::new();
811 let mut module = module(&mut names);
812 callee(&mut names, &mut module, 16);
813 caller(&mut names, &mut module, "f", |build| local(build, 32));
814 let outside = names.intern("somewhere");
815 caller(&mut names, &mut module, "h", |build| {
816 let extra = Extra::Symbol(outside);
817 let global =
818 build.value(InstData { extra, ..InstData::new(Opcode::GlobalAddr) }, Type::PTR);
819 let args = build.func().push_values(&[global]);
820 let info = MemInfo {
821 size: 8,
822 align: 8,
823 order: MemOrder::NotAtomic,
824 tbaa: None,
825 owns: 0,
826 restrict: Restrict::NONE,
827 };
828 let extra = Extra::Mem(build.func().add_mem(info));
829 build.value(InstData { args, extra, ..InstData::new(Opcode::Load) }, Type::PTR)
830 });
831 annotate(&mut module, Pic::Executable);
832 assert_eq!(fact(&mut names, &module), None);
833 }
834
835 #[test]
836 fn a_callee_anything_can_reach_gets_no_alignment_either() {
837 let mut names = Interner::new();
840 let mut module = module(&mut names);
841 callee(&mut names, &mut module, 16);
842 let id = module.funcs().next().expect("the callee");
843 module[id].linkage = Linkage::External;
844 caller(&mut names, &mut module, "f", |build| local(build, 32));
845 annotate(&mut module, Pic::Executable);
846 assert_eq!(fact(&mut names, &module), None);
847 }
848
849 #[test]
850 fn an_alignment_reaches_down_a_chain_of_static_helpers() {
851 let mut names = Interner::new();
855 let mut module = module(&mut names);
856 callee(&mut names, &mut module, 16);
857 relay(&mut names, &mut module, "h", "g", 16);
858 let at = names.intern("f");
859 let called = names.intern("h");
860 let mut func = Func::new(at, Signature::new());
861 let block = func.create_block();
862 let mut build = Builder::new(&mut func, block);
863 let signature = build.func().add_signature(Signature::new().with_params(&[Type::PTR]));
864 let slot = local(&mut build, 32);
865 build.call(called, signature, &[slot]);
866 build.ret(&[]);
867 module.add_func(func);
868 annotate(&mut module, Pic::Executable);
869 assert_eq!(fact(&mut names, &module), Some(8));
870 }
871
872 fn relay(names: &mut Interner, module: &mut Module, name: &str, on: &str, size: u64) {
874 let at = names.intern(name);
875 let called = names.intern(on);
876 let mut func = Func::new(at, Signature::new().with_params(&[Type::PTR]));
877 func.linkage = Linkage::Internal;
878 let block = func.create_block();
879 let pointer = func.append_param(block, Type::PTR);
880 let mut build = Builder::new(&mut func, block);
881 check(&mut build, pointer, size);
882 let signature = build.func().add_signature(Signature::new().with_params(&[Type::PTR]));
883 build.call(called, signature, &[pointer]);
884 build.ret(&[]);
885 module.add_func(func);
886 }
887}