]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_codegen_llvm/src/allocator.rs
2d79b73cf9f519e921d2c50626c5228b093ae700
[rustc.git] / compiler / rustc_codegen_llvm / src / allocator.rs
1 use crate::attributes;
2 use libc::c_uint;
3 use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
4 use rustc_middle::bug;
5 use rustc_middle::ty::TyCtxt;
6 use rustc_span::symbol::sym;
7
8 use crate::llvm::{self, False, True};
9 use crate::ModuleLlvm;
10
11 pub(crate) unsafe fn codegen(
12 tcx: TyCtxt<'_>,
13 mods: &mut ModuleLlvm,
14 kind: AllocatorKind,
15 has_alloc_error_handler: bool,
16 ) {
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),
24 };
25 let i8 = llvm::LLVMInt8TypeInContext(llcx);
26 let i8p = llvm::LLVMPointerType(i8, 0);
27 let void = llvm::LLVMVoidTypeInContext(llcx);
28
29 for method in ALLOCATOR_METHODS {
30 let mut args = Vec::with_capacity(method.inputs.len());
31 for ty in method.inputs.iter() {
32 match *ty {
33 AllocatorTy::Layout => {
34 args.push(usize); // size
35 args.push(usize); // align
36 }
37 AllocatorTy::Ptr => args.push(i8p),
38 AllocatorTy::Usize => args.push(usize),
39
40 AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
41 }
42 }
43 let output = match method.output {
44 AllocatorTy::ResultPtr => Some(i8p),
45 AllocatorTy::Unit => None,
46
47 AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
48 panic!("invalid allocator output")
49 }
50 };
51 let ty = llvm::LLVMFunctionType(
52 output.unwrap_or(void),
53 args.as_ptr(),
54 args.len() as c_uint,
55 False,
56 );
57 let name = format!("__rust_{}", method.name);
58 let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr().cast(), name.len(), ty);
59
60 if tcx.sess.target.default_hidden_visibility {
61 llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
62 }
63 if tcx.sess.must_emit_unwind_tables() {
64 attributes::emit_uwtable(llfn, true);
65 }
66
67 let callee = kind.fn_name(method.name);
68 let callee =
69 llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty);
70 llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
71
72 let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast());
73
74 let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
75 llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);
76 let args = args
77 .iter()
78 .enumerate()
79 .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
80 .collect::<Vec<_>>();
81 let ret = llvm::LLVMRustBuildCall(
82 llbuilder,
83 ty,
84 callee,
85 args.as_ptr(),
86 args.len() as c_uint,
87 None,
88 );
89 llvm::LLVMSetTailCall(ret, True);
90 if output.is_some() {
91 llvm::LLVMBuildRet(llbuilder, ret);
92 } else {
93 llvm::LLVMBuildRetVoid(llbuilder);
94 }
95 llvm::LLVMDisposeBuilder(llbuilder);
96 }
97
98 // rust alloc error handler
99 let args = [usize, usize]; // size, align
100
101 let ty = llvm::LLVMFunctionType(void, args.as_ptr(), args.len() as c_uint, False);
102 let name = "__rust_alloc_error_handler";
103 let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr().cast(), name.len(), ty);
104 // -> ! DIFlagNoReturn
105 llvm::Attribute::NoReturn.apply_llfn(llvm::AttributePlace::Function, llfn);
106
107 if tcx.sess.target.default_hidden_visibility {
108 llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
109 }
110 if tcx.sess.must_emit_unwind_tables() {
111 attributes::emit_uwtable(llfn, true);
112 }
113
114 let kind = if has_alloc_error_handler { AllocatorKind::Global } else { AllocatorKind::Default };
115 let callee = kind.fn_name(sym::oom);
116 let callee = llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty);
117 // -> ! DIFlagNoReturn
118 llvm::Attribute::NoReturn.apply_llfn(llvm::AttributePlace::Function, callee);
119 llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
120
121 let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast());
122
123 let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
124 llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);
125 let args = args
126 .iter()
127 .enumerate()
128 .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
129 .collect::<Vec<_>>();
130 let ret =
131 llvm::LLVMRustBuildCall(llbuilder, ty, callee, args.as_ptr(), args.len() as c_uint, None);
132 llvm::LLVMSetTailCall(ret, True);
133 llvm::LLVMBuildRetVoid(llbuilder);
134 llvm::LLVMDisposeBuilder(llbuilder);
135 }