]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_llvm/src/allocator.rs
Auto merge of #83357 - saethlin:vec-reserve-inlining, r=dtolnay
[rust.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 =
82             llvm::LLVMRustBuildCall(llbuilder, callee, args.as_ptr(), args.len() as c_uint, None);
83         llvm::LLVMSetTailCall(ret, True);
84         if output.is_some() {
85             llvm::LLVMBuildRet(llbuilder, ret);
86         } else {
87             llvm::LLVMBuildRetVoid(llbuilder);
88         }
89         llvm::LLVMDisposeBuilder(llbuilder);
90     }
91
92     // rust alloc error handler
93     let args = [usize, usize]; // size, align
94
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);
100
101     if tcx.sess.target.default_hidden_visibility {
102         llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
103     }
104     if tcx.sess.must_emit_unwind_tables() {
105         attributes::emit_uwtable(llfn, true);
106     }
107
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);
114
115     let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast());
116
117     let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
118     llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);
119     let args = args
120         .iter()
121         .enumerate()
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);
128 }