]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_llvm/src/allocator.rs
Auto merge of #106975 - tmiasko:basic-blocks-cache, r=cjgillot
[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_session::config::{DebugInfo, OomStrategy};
7 use rustc_span::symbol::sym;
8
9 use crate::debuginfo;
10 use crate::llvm::{self, False, True};
11 use crate::ModuleLlvm;
12
13 pub(crate) unsafe fn codegen(
14     tcx: TyCtxt<'_>,
15     module_llvm: &mut ModuleLlvm,
16     module_name: &str,
17     kind: AllocatorKind,
18     alloc_error_handler_kind: AllocatorKind,
19 ) {
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),
27     };
28     let i8 = llvm::LLVMInt8TypeInContext(llcx);
29     let i8p = llvm::LLVMPointerType(i8, 0);
30     let void = llvm::LLVMVoidTypeInContext(llcx);
31
32     for method in ALLOCATOR_METHODS {
33         let mut args = Vec::with_capacity(method.inputs.len());
34         for ty in method.inputs.iter() {
35             match *ty {
36                 AllocatorTy::Layout => {
37                     args.push(usize); // size
38                     args.push(usize); // align
39                 }
40                 AllocatorTy::Ptr => args.push(i8p),
41                 AllocatorTy::Usize => args.push(usize),
42
43                 AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
44             }
45         }
46         let output = match method.output {
47             AllocatorTy::ResultPtr => Some(i8p),
48             AllocatorTy::Unit => None,
49
50             AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
51                 panic!("invalid allocator output")
52             }
53         };
54         let ty = llvm::LLVMFunctionType(
55             output.unwrap_or(void),
56             args.as_ptr(),
57             args.len() as c_uint,
58             False,
59         );
60         let name = format!("__rust_{}", method.name);
61         let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr().cast(), name.len(), ty);
62
63         if tcx.sess.target.default_hidden_visibility {
64             llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
65         }
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]);
69         }
70
71         let callee = kind.fn_name(method.name);
72         let callee =
73             llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty);
74         llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
75
76         let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast());
77
78         let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
79         llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);
80         let args = args
81             .iter()
82             .enumerate()
83             .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
84             .collect::<Vec<_>>();
85         let ret = llvm::LLVMRustBuildCall(
86             llbuilder,
87             ty,
88             callee,
89             args.as_ptr(),
90             args.len() as c_uint,
91             [].as_ptr(),
92             0 as c_uint,
93         );
94         llvm::LLVMSetTailCall(ret, True);
95         if output.is_some() {
96             llvm::LLVMBuildRet(llbuilder, ret);
97         } else {
98             llvm::LLVMBuildRetVoid(llbuilder);
99         }
100         llvm::LLVMDisposeBuilder(llbuilder);
101     }
102
103     // rust alloc error handler
104     let args = [usize, usize]; // size, align
105
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]);
112
113     if tcx.sess.target.default_hidden_visibility {
114         llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
115     }
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]);
119     }
120
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);
126
127     let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast());
128
129     let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
130     llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);
131     let args = args
132         .iter()
133         .enumerate()
134         .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
135         .collect::<Vec<_>>();
136     let ret = llvm::LLVMRustBuildCall(
137         llbuilder,
138         ty,
139         callee,
140         args.as_ptr(),
141         args.len() as c_uint,
142         [].as_ptr(),
143         0 as c_uint,
144     );
145     llvm::LLVMSetTailCall(ret, True);
146     llvm::LLVMBuildRetVoid(llbuilder);
147     llvm::LLVMDisposeBuilder(llbuilder);
148
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);
154     }
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);
158
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);
163     }
164 }