3 use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
5 use rustc_middle::ty::TyCtxt;
6 use rustc_session::config::DebugInfo;
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 has_alloc_error_handler: bool,
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 attributes::emit_uwtable(llfn, true);
70 let callee = kind.fn_name(method.name);
72 llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty);
73 llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
75 let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast());
77 let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
78 llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);
82 .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
84 let ret = llvm::LLVMRustBuildCall(
92 llvm::LLVMSetTailCall(ret, True);
94 llvm::LLVMBuildRet(llbuilder, ret);
96 llvm::LLVMBuildRetVoid(llbuilder);
98 llvm::LLVMDisposeBuilder(llbuilder);
101 // rust alloc error handler
102 let args = [usize, usize]; // size, align
104 let ty = llvm::LLVMFunctionType(void, args.as_ptr(), args.len() as c_uint, False);
105 let name = "__rust_alloc_error_handler";
106 let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr().cast(), name.len(), ty);
107 // -> ! DIFlagNoReturn
108 llvm::Attribute::NoReturn.apply_llfn(llvm::AttributePlace::Function, llfn);
110 if tcx.sess.target.default_hidden_visibility {
111 llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
113 if tcx.sess.must_emit_unwind_tables() {
114 attributes::emit_uwtable(llfn, true);
117 let kind = if has_alloc_error_handler { AllocatorKind::Global } else { AllocatorKind::Default };
118 let callee = kind.fn_name(sym::oom);
119 let callee = llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty);
120 // -> ! DIFlagNoReturn
121 llvm::Attribute::NoReturn.apply_llfn(llvm::AttributePlace::Function, callee);
122 llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
124 let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast());
126 let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
127 llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);
131 .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
132 .collect::<Vec<_>>();
134 llvm::LLVMRustBuildCall(llbuilder, ty, callee, args.as_ptr(), args.len() as c_uint, None);
135 llvm::LLVMSetTailCall(ret, True);
136 llvm::LLVMBuildRetVoid(llbuilder);
137 llvm::LLVMDisposeBuilder(llbuilder);
139 if tcx.sess.opts.debuginfo != DebugInfo::None {
140 let dbg_cx = debuginfo::CrateDebugContext::new(llmod);
141 debuginfo::metadata::compile_unit_metadata(tcx, module_name, &dbg_cx);
142 dbg_cx.finalize(tcx.sess);