]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_llvm/src/allocator.rs
Rollup merge of #104976 - WaffleLapkin:move_comments, 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             None,
92         );
93         llvm::LLVMSetTailCall(ret, True);
94         if output.is_some() {
95             llvm::LLVMBuildRet(llbuilder, ret);
96         } else {
97             llvm::LLVMBuildRetVoid(llbuilder);
98         }
99         llvm::LLVMDisposeBuilder(llbuilder);
100     }
101
102     // rust alloc error handler
103     let args = [usize, usize]; // size, align
104
105     let ty = llvm::LLVMFunctionType(void, args.as_ptr(), args.len() as c_uint, False);
106     let name = "__rust_alloc_error_handler";
107     let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr().cast(), name.len(), ty);
108     // -> ! DIFlagNoReturn
109     let no_return = llvm::AttributeKind::NoReturn.create_attr(llcx);
110     attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[no_return]);
111
112     if tcx.sess.target.default_hidden_visibility {
113         llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
114     }
115     if tcx.sess.must_emit_unwind_tables() {
116         let uwtable = attributes::uwtable_attr(llcx);
117         attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]);
118     }
119
120     let callee = alloc_error_handler_kind.fn_name(sym::oom);
121     let callee = llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty);
122     // -> ! DIFlagNoReturn
123     attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]);
124     llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
125
126     let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast());
127
128     let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
129     llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);
130     let args = args
131         .iter()
132         .enumerate()
133         .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
134         .collect::<Vec<_>>();
135     let ret =
136         llvm::LLVMRustBuildCall(llbuilder, ty, callee, args.as_ptr(), args.len() as c_uint, None);
137     llvm::LLVMSetTailCall(ret, True);
138     llvm::LLVMBuildRetVoid(llbuilder);
139     llvm::LLVMDisposeBuilder(llbuilder);
140
141     // __rust_alloc_error_handler_should_panic
142     let name = OomStrategy::SYMBOL;
143     let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8);
144     if tcx.sess.target.default_hidden_visibility {
145         llvm::LLVMRustSetVisibility(ll_g, llvm::Visibility::Hidden);
146     }
147     let val = tcx.sess.opts.unstable_opts.oom.should_panic();
148     let llval = llvm::LLVMConstInt(i8, val as u64, False);
149     llvm::LLVMSetInitializer(ll_g, llval);
150
151     if tcx.sess.opts.debuginfo != DebugInfo::None {
152         let dbg_cx = debuginfo::CodegenUnitDebugContext::new(llmod);
153         debuginfo::metadata::build_compile_unit_di_node(tcx, module_name, &dbg_cx);
154         dbg_cx.finalize(tcx.sess);
155     }
156 }