3 use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
5 use rustc_middle::ty::TyCtxt;
6 use rustc_session::config::{DebugInfo, OomStrategy};
7 use rustc_span::symbol::sym;
10 use crate::llvm::{self, False, True};
11 use crate::ModuleLlvm;
13 pub(crate) unsafe fn codegen(
15 module_llvm: &mut ModuleLlvm,
18 alloc_error_handler_kind: AllocatorKind,
20 let llcx = &*module_llvm.llcx;
21 let llmod = module_llvm.llmod();
22 let usize = match tcx.sess.target.pointer_width {
23 16 => llvm::LLVMInt16TypeInContext(llcx),
24 32 => llvm::LLVMInt32TypeInContext(llcx),
25 64 => llvm::LLVMInt64TypeInContext(llcx),
26 tws => bug!("Unsupported target word size for int: {}", tws),
28 let i8 = llvm::LLVMInt8TypeInContext(llcx);
29 let i8p = llvm::LLVMPointerType(i8, 0);
30 let void = llvm::LLVMVoidTypeInContext(llcx);
32 for method in ALLOCATOR_METHODS {
33 let mut args = Vec::with_capacity(method.inputs.len());
34 for ty in method.inputs.iter() {
36 AllocatorTy::Layout => {
37 args.push(usize); // size
38 args.push(usize); // align
40 AllocatorTy::Ptr => args.push(i8p),
41 AllocatorTy::Usize => args.push(usize),
43 AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
46 let output = match method.output {
47 AllocatorTy::ResultPtr => Some(i8p),
48 AllocatorTy::Unit => None,
50 AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
51 panic!("invalid allocator output")
54 let ty = llvm::LLVMFunctionType(
55 output.unwrap_or(void),
60 let name = format!("__rust_{}", method.name);
61 let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr().cast(), name.len(), ty);
63 if tcx.sess.target.default_hidden_visibility {
64 llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
66 if tcx.sess.must_emit_unwind_tables() {
67 let uwtable = attributes::uwtable_attr(llcx);
68 attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]);
71 let callee = kind.fn_name(method.name);
73 llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty);
74 llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
76 let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast());
78 let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
79 llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);
83 .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
85 let ret = llvm::LLVMRustBuildCall(
94 llvm::LLVMSetTailCall(ret, True);
96 llvm::LLVMBuildRet(llbuilder, ret);
98 llvm::LLVMBuildRetVoid(llbuilder);
100 llvm::LLVMDisposeBuilder(llbuilder);
103 // rust alloc error handler
104 let args = [usize, usize]; // size, align
106 let ty = llvm::LLVMFunctionType(void, args.as_ptr(), args.len() as c_uint, False);
107 let name = "__rust_alloc_error_handler";
108 let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr().cast(), name.len(), ty);
109 // -> ! DIFlagNoReturn
110 let no_return = llvm::AttributeKind::NoReturn.create_attr(llcx);
111 attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[no_return]);
113 if tcx.sess.target.default_hidden_visibility {
114 llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
116 if tcx.sess.must_emit_unwind_tables() {
117 let uwtable = attributes::uwtable_attr(llcx);
118 attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]);
121 let callee = alloc_error_handler_kind.fn_name(sym::oom);
122 let callee = llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty);
123 // -> ! DIFlagNoReturn
124 attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]);
125 llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
127 let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast());
129 let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
130 llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);
134 .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
135 .collect::<Vec<_>>();
136 let ret = llvm::LLVMRustBuildCall(
141 args.len() as c_uint,
145 llvm::LLVMSetTailCall(ret, True);
146 llvm::LLVMBuildRetVoid(llbuilder);
147 llvm::LLVMDisposeBuilder(llbuilder);
149 // __rust_alloc_error_handler_should_panic
150 let name = OomStrategy::SYMBOL;
151 let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8);
152 if tcx.sess.target.default_hidden_visibility {
153 llvm::LLVMRustSetVisibility(ll_g, llvm::Visibility::Hidden);
155 let val = tcx.sess.opts.unstable_opts.oom.should_panic();
156 let llval = llvm::LLVMConstInt(i8, val as u64, False);
157 llvm::LLVMSetInitializer(ll_g, llval);
159 if tcx.sess.opts.debuginfo != DebugInfo::None {
160 let dbg_cx = debuginfo::CodegenUnitDebugContext::new(llmod);
161 debuginfo::metadata::build_compile_unit_di_node(tcx, module_name, &dbg_cx);
162 dbg_cx.finalize(tcx.sess);