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};
10
11use crate::builder::SBuilder;
12use crate::declare::declare_simple_fn;
13use crate::llvm::{self, False, True, Type};
14use crate::{SimpleCx, attributes, debuginfo};
15
16pub(crate) unsafe fn codegen(
17 tcx: TyCtxt<'_>,
18 cx: SimpleCx<'_>,
19 module_name: &str,
20 kind: AllocatorKind,
21 alloc_error_handler_kind: AllocatorKind,
22) {
23 let usize = match tcx.sess.target.pointer_width {
24 16 => cx.type_i16(),
25 32 => cx.type_i32(),
26 64 => cx.type_i64(),
27 tws => bug!("Unsupported target word size for int: {}", tws),
28 };
29 let i8 = cx.type_i8();
30 let i8p = cx.type_ptr();
31
32 if kind == AllocatorKind::Default {
33 for method in ALLOCATOR_METHODS {
34 let mut args = Vec::with_capacity(method.inputs.len());
35 for input in method.inputs.iter() {
36 match input.ty {
37 AllocatorTy::Layout => {
38 args.push(usize); args.push(usize); }
41 AllocatorTy::Ptr => args.push(i8p),
42 AllocatorTy::Usize => args.push(usize),
43
44 AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
45 }
46 }
47 let output = match method.output {
48 AllocatorTy::ResultPtr => Some(i8p),
49 AllocatorTy::Unit => None,
50
51 AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
52 panic!("invalid allocator output")
53 }
54 };
55
56 let from_name = global_fn_name(method.name);
57 let to_name = default_fn_name(method.name);
58
59 create_wrapper_function(tcx, &cx, &from_name, &to_name, &args, output, false);
60 }
61 }
62
63 create_wrapper_function(
65 tcx,
66 &cx,
67 "__rust_alloc_error_handler",
68 alloc_error_handler_name(alloc_error_handler_kind),
69 &[usize, usize], None,
71 true,
72 );
73
74 unsafe {
75 let name = OomStrategy::SYMBOL;
77 let ll_g = cx.declare_global(name, i8);
78 llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility()));
79 let val = tcx.sess.opts.unstable_opts.oom.should_panic();
80 let llval = llvm::LLVMConstInt(i8, val as u64, False);
81 llvm::set_initializer(ll_g, llval);
82
83 let name = NO_ALLOC_SHIM_IS_UNSTABLE;
84 let ll_g = cx.declare_global(name, i8);
85 llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility()));
86 let llval = llvm::LLVMConstInt(i8, 0, False);
87 llvm::set_initializer(ll_g, llval);
88 }
89
90 if tcx.sess.opts.debuginfo != DebugInfo::None {
91 let dbg_cx = debuginfo::CodegenUnitDebugContext::new(cx.llmod);
92 debuginfo::metadata::build_compile_unit_di_node(tcx, module_name, &dbg_cx);
93 dbg_cx.finalize(tcx.sess);
94 }
95}
96
97fn create_wrapper_function(
98 tcx: TyCtxt<'_>,
99 cx: &SimpleCx<'_>,
100 from_name: &str,
101 to_name: &str,
102 args: &[&Type],
103 output: Option<&Type>,
104 no_return: bool,
105) {
106 let ty = cx.type_func(args, output.unwrap_or_else(|| cx.type_void()));
107 let llfn = declare_simple_fn(
108 &cx,
109 from_name,
110 llvm::CallConv::CCallConv,
111 llvm::UnnamedAddr::Global,
112 llvm::Visibility::from_generic(tcx.sess.default_visibility()),
113 ty,
114 );
115 let no_return = if no_return {
116 let no_return = llvm::AttributeKind::NoReturn.create_attr(cx.llcx);
118 attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[no_return]);
119 Some(no_return)
120 } else {
121 None
122 };
123
124 if tcx.sess.must_emit_unwind_tables() {
125 let uwtable =
126 attributes::uwtable_attr(cx.llcx, tcx.sess.opts.unstable_opts.use_sync_unwind);
127 attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]);
128 }
129
130 let callee = declare_simple_fn(
131 &cx,
132 to_name,
133 llvm::CallConv::CCallConv,
134 llvm::UnnamedAddr::Global,
135 llvm::Visibility::Hidden,
136 ty,
137 );
138 if let Some(no_return) = no_return {
139 attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]);
141 }
142 llvm::set_visibility(callee, llvm::Visibility::Hidden);
143
144 let llbb = unsafe { llvm::LLVMAppendBasicBlockInContext(cx.llcx, llfn, c"entry".as_ptr()) };
145
146 let mut bx = SBuilder::build(&cx, llbb);
147 let args = args
148 .iter()
149 .enumerate()
150 .map(|(i, _)| llvm::get_param(llfn, i as c_uint))
151 .collect::<Vec<_>>();
152 let ret = bx.call(ty, callee, &args, None);
153 llvm::LLVMSetTailCall(ret, True);
154 if output.is_some() {
155 bx.ret(ret);
156 } else {
157 bx.ret_void()
158 }
159}