3 use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
5 use rustc_middle::ty::TyCtxt;
6 use rustc_span::symbol::sym;
8 use crate::llvm::{self, False, True};
11 pub(crate) unsafe fn codegen(
13 mods: &mut ModuleLlvm,
15 has_alloc_error_handler: bool,
17 let llcx = &*mods.llcx;
18 let llmod = mods.llmod();
19 let usize = match tcx.sess.target.pointer_width {
20 16 => llvm::LLVMInt16TypeInContext(llcx),
21 32 => llvm::LLVMInt32TypeInContext(llcx),
22 64 => llvm::LLVMInt64TypeInContext(llcx),
23 tws => bug!("Unsupported target word size for int: {}", tws),
25 let i8 = llvm::LLVMInt8TypeInContext(llcx);
26 let i8p = llvm::LLVMPointerType(i8, 0);
27 let void = llvm::LLVMVoidTypeInContext(llcx);
29 for method in ALLOCATOR_METHODS {
30 let mut args = Vec::with_capacity(method.inputs.len());
31 for ty in method.inputs.iter() {
33 AllocatorTy::Layout => {
34 args.push(usize); // size
35 args.push(usize); // align
37 AllocatorTy::Ptr => args.push(i8p),
38 AllocatorTy::Usize => args.push(usize),
40 AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
43 let output = match method.output {
44 AllocatorTy::ResultPtr => Some(i8p),
45 AllocatorTy::Unit => None,
47 AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
48 panic!("invalid allocator output")
51 let ty = llvm::LLVMFunctionType(
52 output.unwrap_or(void),
57 let name = format!("__rust_{}", method.name);
58 let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr().cast(), name.len(), ty);
60 if tcx.sess.target.default_hidden_visibility {
61 llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
63 if tcx.sess.must_emit_unwind_tables() {
64 attributes::emit_uwtable(llfn, true);
67 let callee = kind.fn_name(method.name);
69 llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty);
70 llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
72 let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast());
74 let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
75 llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);
79 .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
82 llvm::LLVMRustBuildCall(llbuilder, callee, args.as_ptr(), args.len() as c_uint, None);
83 llvm::LLVMSetTailCall(ret, True);
85 llvm::LLVMBuildRet(llbuilder, ret);
87 llvm::LLVMBuildRetVoid(llbuilder);
89 llvm::LLVMDisposeBuilder(llbuilder);
92 // rust alloc error handler
93 let args = [usize, usize]; // size, align
95 let ty = llvm::LLVMFunctionType(void, args.as_ptr(), args.len() as c_uint, False);
96 let name = "__rust_alloc_error_handler";
97 let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr().cast(), name.len(), ty);
98 // -> ! DIFlagNoReturn
99 llvm::Attribute::NoReturn.apply_llfn(llvm::AttributePlace::Function, llfn);
101 if tcx.sess.target.default_hidden_visibility {
102 llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
104 if tcx.sess.must_emit_unwind_tables() {
105 attributes::emit_uwtable(llfn, true);
108 let kind = if has_alloc_error_handler { AllocatorKind::Global } else { AllocatorKind::Default };
109 let callee = kind.fn_name(sym::oom);
110 let callee = llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty);
111 // -> ! DIFlagNoReturn
112 llvm::Attribute::NoReturn.apply_llfn(llvm::AttributePlace::Function, callee);
113 llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
115 let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast());
117 let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
118 llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);
122 .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
123 .collect::<Vec<_>>();
124 let ret = llvm::LLVMRustBuildCall(llbuilder, callee, args.as_ptr(), args.len() as c_uint, None);
125 llvm::LLVMSetTailCall(ret, True);
126 llvm::LLVMBuildRetVoid(llbuilder);
127 llvm::LLVMDisposeBuilder(llbuilder);