]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_cranelift/src/allocator.rs
Auto merge of #94320 - GuillaumeGomez:sidebar-display, r=jsha
[rust.git] / compiler / rustc_codegen_cranelift / src / allocator.rs
1 //! Allocator shim
2 // Adapted from rustc
3
4 use crate::prelude::*;
5
6 use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
7
8 /// Returns whether an allocator shim was created
9 pub(crate) fn codegen(
10     tcx: TyCtxt<'_>,
11     module: &mut impl Module,
12     unwind_context: &mut UnwindContext,
13 ) -> bool {
14     let any_dynamic_crate = tcx.dependency_formats(()).iter().any(|(_, list)| {
15         use rustc_middle::middle::dependency_format::Linkage;
16         list.iter().any(|&linkage| linkage == Linkage::Dynamic)
17     });
18     if any_dynamic_crate {
19         false
20     } else if let Some(kind) = tcx.allocator_kind(()) {
21         codegen_inner(module, unwind_context, kind, tcx.lang_items().oom().is_some());
22         true
23     } else {
24         false
25     }
26 }
27
28 fn codegen_inner(
29     module: &mut impl Module,
30     unwind_context: &mut UnwindContext,
31     kind: AllocatorKind,
32     has_alloc_error_handler: bool,
33 ) {
34     let usize_ty = module.target_config().pointer_type();
35
36     for method in ALLOCATOR_METHODS {
37         let mut arg_tys = Vec::with_capacity(method.inputs.len());
38         for ty in method.inputs.iter() {
39             match *ty {
40                 AllocatorTy::Layout => {
41                     arg_tys.push(usize_ty); // size
42                     arg_tys.push(usize_ty); // align
43                 }
44                 AllocatorTy::Ptr => arg_tys.push(usize_ty),
45                 AllocatorTy::Usize => arg_tys.push(usize_ty),
46
47                 AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
48             }
49         }
50         let output = match method.output {
51             AllocatorTy::ResultPtr => Some(usize_ty),
52             AllocatorTy::Unit => None,
53
54             AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
55                 panic!("invalid allocator output")
56             }
57         };
58
59         let sig = Signature {
60             call_conv: CallConv::triple_default(module.isa().triple()),
61             params: arg_tys.iter().cloned().map(AbiParam::new).collect(),
62             returns: output.into_iter().map(AbiParam::new).collect(),
63         };
64
65         let caller_name = format!("__rust_{}", method.name);
66         let callee_name = kind.fn_name(method.name);
67
68         let func_id = module.declare_function(&caller_name, Linkage::Export, &sig).unwrap();
69
70         let callee_func_id = module.declare_function(&callee_name, Linkage::Import, &sig).unwrap();
71
72         let mut ctx = Context::new();
73         ctx.func = Function::with_name_signature(ExternalName::user(0, 0), sig.clone());
74         {
75             let mut func_ctx = FunctionBuilderContext::new();
76             let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);
77
78             let block = bcx.create_block();
79             bcx.switch_to_block(block);
80             let args = arg_tys
81                 .into_iter()
82                 .map(|ty| bcx.append_block_param(block, ty))
83                 .collect::<Vec<Value>>();
84
85             let callee_func_ref = module.declare_func_in_func(callee_func_id, &mut bcx.func);
86             let call_inst = bcx.ins().call(callee_func_ref, &args);
87             let results = bcx.inst_results(call_inst).to_vec(); // Clone to prevent borrow error
88
89             bcx.ins().return_(&results);
90             bcx.seal_all_blocks();
91             bcx.finalize();
92         }
93         module.define_function(func_id, &mut ctx).unwrap();
94         unwind_context.add_function(func_id, &ctx, module.isa());
95     }
96
97     let sig = Signature {
98         call_conv: CallConv::triple_default(module.isa().triple()),
99         params: vec![AbiParam::new(usize_ty), AbiParam::new(usize_ty)],
100         returns: vec![],
101     };
102
103     let callee_name = if has_alloc_error_handler { "__rg_oom" } else { "__rdl_oom" };
104
105     let func_id =
106         module.declare_function("__rust_alloc_error_handler", Linkage::Export, &sig).unwrap();
107
108     let callee_func_id = module.declare_function(callee_name, Linkage::Import, &sig).unwrap();
109
110     let mut ctx = Context::new();
111     ctx.func = Function::with_name_signature(ExternalName::user(0, 0), sig);
112     {
113         let mut func_ctx = FunctionBuilderContext::new();
114         let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);
115
116         let block = bcx.create_block();
117         bcx.switch_to_block(block);
118         let args = (&[usize_ty, usize_ty])
119             .iter()
120             .map(|&ty| bcx.append_block_param(block, ty))
121             .collect::<Vec<Value>>();
122
123         let callee_func_ref = module.declare_func_in_func(callee_func_id, &mut bcx.func);
124         bcx.ins().call(callee_func_ref, &args);
125
126         bcx.ins().trap(TrapCode::UnreachableCodeReached);
127         bcx.seal_all_blocks();
128         bcx.finalize();
129     }
130     module.define_function(func_id, &mut ctx).unwrap();
131     unwind_context.add_function(func_id, &ctx, module.isa());
132 }