1use libc::c_uint;
2use rustc_ast::expand::allocator::{
3 ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE,
4 alloc_error_handler_name, default_fn_name, global_fn_name,
5};
6use rustc_codegen_ssa::traits::BaseTypeCodegenMethods as _;
7use rustc_middle::bug;
8use rustc_middle::ty::TyCtxt;
9use rustc_session::config::{DebugInfo, OomStrategy};
10use rustc_symbol_mangling::mangle_internal_symbol;
11
12use crate::builder::SBuilder;
13use crate::declare::declare_simple_fn;
14use crate::llvm::{self, False, True, Type, Value};
15use crate::{SimpleCx, attributes, debuginfo};
16
17pub(crate) unsafe fn codegen(
18 tcx: TyCtxt<'_>,
19 cx: SimpleCx<'_>,
20 module_name: &str,
21 kind: AllocatorKind,
22 alloc_error_handler_kind: AllocatorKind,
23) {
24 let usize = match tcx.sess.target.pointer_width {
25 16 => cx.type_i16(),
26 32 => cx.type_i32(),
27 64 => cx.type_i64(),
28 tws => bug!("Unsupported target word size for int: {}", tws),
29 };
30 let i8 = cx.type_i8();
31 let i8p = cx.type_ptr();
32
33 if kind == AllocatorKind::Default {
34 for method in ALLOCATOR_METHODS {
35 let mut args = Vec::with_capacity(method.inputs.len());
36 for input in method.inputs.iter() {
37 match input.ty {
38 AllocatorTy::Layout => {
39 args.push(usize); args.push(usize); }
42 AllocatorTy::Ptr => args.push(i8p),
43 AllocatorTy::Usize => args.push(usize),
44
45 AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
46 }
47 }
48 let output = match method.output {
49 AllocatorTy::ResultPtr => Some(i8p),
50 AllocatorTy::Unit => None,
51
52 AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
53 panic!("invalid allocator output")
54 }
55 };
56
57 let from_name = mangle_internal_symbol(tcx, &global_fn_name(method.name));
58 let to_name = mangle_internal_symbol(tcx, &default_fn_name(method.name));
59
60 create_wrapper_function(tcx, &cx, &from_name, Some(&to_name), &args, output, false);
61 }
62 }
63
64 create_wrapper_function(
66 tcx,
67 &cx,
68 &mangle_internal_symbol(tcx, "__rust_alloc_error_handler"),
69 Some(&mangle_internal_symbol(tcx, alloc_error_handler_name(alloc_error_handler_kind))),
70 &[usize, usize], None,
72 true,
73 );
74
75 unsafe {
76 create_const_value_function(
78 tcx,
79 &cx,
80 &mangle_internal_symbol(tcx, OomStrategy::SYMBOL),
81 &i8,
82 &llvm::LLVMConstInt(i8, tcx.sess.opts.unstable_opts.oom.should_panic() as u64, False),
83 );
84
85 create_wrapper_function(
87 tcx,
88 &cx,
89 &mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE),
90 None,
91 &[],
92 None,
93 false,
94 );
95 }
96
97 if tcx.sess.opts.debuginfo != DebugInfo::None {
98 let dbg_cx = debuginfo::CodegenUnitDebugContext::new(cx.llmod);
99 debuginfo::metadata::build_compile_unit_di_node(tcx, module_name, &dbg_cx);
100 dbg_cx.finalize(tcx.sess);
101 }
102}
103
104fn create_const_value_function(
105 tcx: TyCtxt<'_>,
106 cx: &SimpleCx<'_>,
107 name: &str,
108 output: &Type,
109 value: &Value,
110) {
111 let ty = cx.type_func(&[], output);
112 let llfn = declare_simple_fn(
113 &cx,
114 name,
115 llvm::CallConv::CCallConv,
116 llvm::UnnamedAddr::Global,
117 llvm::Visibility::from_generic(tcx.sess.default_visibility()),
118 ty,
119 );
120
121 attributes::apply_to_llfn(
122 llfn,
123 llvm::AttributePlace::Function,
124 &[llvm::AttributeKind::AlwaysInline.create_attr(cx.llcx)],
125 );
126
127 let llbb = unsafe { llvm::LLVMAppendBasicBlockInContext(cx.llcx, llfn, c"entry".as_ptr()) };
128 let mut bx = SBuilder::build(&cx, llbb);
129 bx.ret(value);
130}
131
132fn create_wrapper_function(
133 tcx: TyCtxt<'_>,
134 cx: &SimpleCx<'_>,
135 from_name: &str,
136 to_name: Option<&str>,
137 args: &[&Type],
138 output: Option<&Type>,
139 no_return: bool,
140) {
141 let ty = cx.type_func(args, output.unwrap_or_else(|| cx.type_void()));
142 let llfn = declare_simple_fn(
143 &cx,
144 from_name,
145 llvm::CallConv::CCallConv,
146 llvm::UnnamedAddr::Global,
147 llvm::Visibility::from_generic(tcx.sess.default_visibility()),
148 ty,
149 );
150 let no_return = if no_return {
151 let no_return = llvm::AttributeKind::NoReturn.create_attr(cx.llcx);
153 attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[no_return]);
154 Some(no_return)
155 } else {
156 None
157 };
158
159 if tcx.sess.must_emit_unwind_tables() {
160 let uwtable =
161 attributes::uwtable_attr(cx.llcx, tcx.sess.opts.unstable_opts.use_sync_unwind);
162 attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]);
163 }
164
165 let llbb = unsafe { llvm::LLVMAppendBasicBlockInContext(cx.llcx, llfn, c"entry".as_ptr()) };
166 let mut bx = SBuilder::build(&cx, llbb);
167
168 if let Some(to_name) = to_name {
169 let callee = declare_simple_fn(
170 &cx,
171 to_name,
172 llvm::CallConv::CCallConv,
173 llvm::UnnamedAddr::Global,
174 llvm::Visibility::Hidden,
175 ty,
176 );
177 if let Some(no_return) = no_return {
178 attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]);
180 }
181 llvm::set_visibility(callee, llvm::Visibility::Hidden);
182
183 let args = args
184 .iter()
185 .enumerate()
186 .map(|(i, _)| llvm::get_param(llfn, i as c_uint))
187 .collect::<Vec<_>>();
188 let ret = bx.call(ty, callee, &args, None);
189 llvm::LLVMSetTailCall(ret, True);
190 if output.is_some() {
191 bx.ret(ret);
192 } else {
193 bx.ret_void()
194 }
195 } else {
196 assert!(output.is_none());
197 bx.ret_void()
198 }
199}