]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_cranelift/src/allocator.rs
Rollup merge of #80771 - thomcc:nonnull-refmut, r=dtolnay
[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 use rustc_span::symbol::sym;
8
9 /// Returns whether an allocator shim was created
10 pub(crate) fn codegen(
11     tcx: TyCtxt<'_>,
12     module: &mut impl Module,
13     unwind_context: &mut UnwindContext<'_>,
14 ) -> bool {
15     let any_dynamic_crate = tcx.dependency_formats(LOCAL_CRATE).iter().any(|(_, list)| {
16         use rustc_middle::middle::dependency_format::Linkage;
17         list.iter().any(|&linkage| linkage == Linkage::Dynamic)
18     });
19     if any_dynamic_crate {
20         false
21     } else if let Some(kind) = tcx.allocator_kind() {
22         codegen_inner(module, unwind_context, kind);
23         true
24     } else {
25         false
26     }
27 }
28
29 fn codegen_inner(
30     module: &mut impl Module,
31     unwind_context: &mut UnwindContext<'_>,
32     kind: AllocatorKind,
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         //eprintln!("Codegen allocator shim {} -> {} ({:?} -> {:?})", caller_name, callee_name, sig.params, sig.returns);
68
69         let func_id = module.declare_function(&caller_name, Linkage::Export, &sig).unwrap();
70
71         let callee_func_id = module.declare_function(&callee_name, Linkage::Import, &sig).unwrap();
72
73         let mut ctx = Context::new();
74         ctx.func = Function::with_name_signature(ExternalName::user(0, 0), sig.clone());
75         {
76             let mut func_ctx = FunctionBuilderContext::new();
77             let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);
78
79             let block = bcx.create_block();
80             bcx.switch_to_block(block);
81             let args = arg_tys
82                 .into_iter()
83                 .map(|ty| bcx.append_block_param(block, ty))
84                 .collect::<Vec<Value>>();
85
86             let callee_func_ref = module.declare_func_in_func(callee_func_id, &mut bcx.func);
87             let call_inst = bcx.ins().call(callee_func_ref, &args);
88             let results = bcx.inst_results(call_inst).to_vec(); // Clone to prevent borrow error
89
90             bcx.ins().return_(&results);
91             bcx.seal_all_blocks();
92             bcx.finalize();
93         }
94         module
95             .define_function(func_id, &mut ctx, &mut cranelift_codegen::binemit::NullTrapSink {})
96             .unwrap();
97         unwind_context.add_function(func_id, &ctx, module.isa());
98     }
99
100     let sig = Signature {
101         call_conv: CallConv::triple_default(module.isa().triple()),
102         params: vec![AbiParam::new(usize_ty), AbiParam::new(usize_ty)],
103         returns: vec![],
104     };
105
106     let callee_name = kind.fn_name(sym::oom);
107     //eprintln!("Codegen allocator shim {} -> {} ({:?} -> {:?})", caller_name, callee_name, sig.params, sig.returns);
108
109     let func_id =
110         module.declare_function("__rust_alloc_error_handler", Linkage::Export, &sig).unwrap();
111
112     let callee_func_id = module.declare_function(&callee_name, Linkage::Import, &sig).unwrap();
113
114     let mut ctx = Context::new();
115     ctx.func = Function::with_name_signature(ExternalName::user(0, 0), sig);
116     {
117         let mut func_ctx = FunctionBuilderContext::new();
118         let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);
119
120         let block = bcx.create_block();
121         bcx.switch_to_block(block);
122         let args = (&[usize_ty, usize_ty])
123             .iter()
124             .map(|&ty| bcx.append_block_param(block, ty))
125             .collect::<Vec<Value>>();
126
127         let callee_func_ref = module.declare_func_in_func(callee_func_id, &mut bcx.func);
128         bcx.ins().call(callee_func_ref, &args);
129
130         bcx.ins().trap(TrapCode::UnreachableCodeReached);
131         bcx.seal_all_blocks();
132         bcx.finalize();
133     }
134     module
135         .define_function(func_id, &mut ctx, &mut cranelift_codegen::binemit::NullTrapSink {})
136         .unwrap();
137     unwind_context.add_function(func_id, &ctx, module.isa());
138 }