]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_cranelift/src/allocator.rs
Merge commit '928e72dd10749875cbd412f74bfbfd7765dbcd8a' into clippyup
[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
70             .declare_function(&caller_name, Linkage::Export, &sig)
71             .unwrap();
72
73         let callee_func_id = module
74             .declare_function(&callee_name, Linkage::Import, &sig)
75             .unwrap();
76
77         let mut ctx = Context::new();
78         ctx.func = Function::with_name_signature(ExternalName::user(0, 0), sig.clone());
79         {
80             let mut func_ctx = FunctionBuilderContext::new();
81             let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);
82
83             let block = bcx.create_block();
84             bcx.switch_to_block(block);
85             let args = arg_tys
86                 .into_iter()
87                 .map(|ty| bcx.append_block_param(block, ty))
88                 .collect::<Vec<Value>>();
89
90             let callee_func_ref = module.declare_func_in_func(callee_func_id, &mut bcx.func);
91             let call_inst = bcx.ins().call(callee_func_ref, &args);
92             let results = bcx.inst_results(call_inst).to_vec(); // Clone to prevent borrow error
93
94             bcx.ins().return_(&results);
95             bcx.seal_all_blocks();
96             bcx.finalize();
97         }
98         module
99             .define_function(
100                 func_id,
101                 &mut ctx,
102                 &mut cranelift_codegen::binemit::NullTrapSink {},
103             )
104             .unwrap();
105         unwind_context.add_function(func_id, &ctx, module.isa());
106     }
107
108     let sig = Signature {
109         call_conv: CallConv::triple_default(module.isa().triple()),
110         params: vec![AbiParam::new(usize_ty), AbiParam::new(usize_ty)],
111         returns: vec![],
112     };
113
114     let callee_name = kind.fn_name(sym::oom);
115     //eprintln!("Codegen allocator shim {} -> {} ({:?} -> {:?})", caller_name, callee_name, sig.params, sig.returns);
116
117     let func_id = module
118         .declare_function("__rust_alloc_error_handler", Linkage::Export, &sig)
119         .unwrap();
120
121     let callee_func_id = module
122         .declare_function(&callee_name, Linkage::Import, &sig)
123         .unwrap();
124
125     let mut ctx = Context::new();
126     ctx.func = Function::with_name_signature(ExternalName::user(0, 0), sig);
127     {
128         let mut func_ctx = FunctionBuilderContext::new();
129         let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);
130
131         let block = bcx.create_block();
132         bcx.switch_to_block(block);
133         let args = (&[usize_ty, usize_ty])
134             .iter()
135             .map(|&ty| bcx.append_block_param(block, ty))
136             .collect::<Vec<Value>>();
137
138         let callee_func_ref = module.declare_func_in_func(callee_func_id, &mut bcx.func);
139         bcx.ins().call(callee_func_ref, &args);
140
141         bcx.ins().trap(TrapCode::UnreachableCodeReached);
142         bcx.seal_all_blocks();
143         bcx.finalize();
144     }
145     module
146         .define_function(
147             func_id,
148             &mut ctx,
149             &mut cranelift_codegen::binemit::NullTrapSink {},
150         )
151         .unwrap();
152     unwind_context.add_function(func_id, &ctx, module.isa());
153 }