]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_llvm/src/allocator.rs
Rollup merge of #90942 - JohnTitor:should-os-error-3, r=m-ou-se
[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;
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     has_alloc_error_handler: bool,
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             attributes::emit_uwtable(llfn, true);
68         }
69
70         let callee = kind.fn_name(method.name);
71         let callee =
72             llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty);
73         llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
74
75         let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast());
76
77         let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
78         llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);
79         let args = args
80             .iter()
81             .enumerate()
82             .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
83             .collect::<Vec<_>>();
84         let ret = llvm::LLVMRustBuildCall(
85             llbuilder,
86             ty,
87             callee,
88             args.as_ptr(),
89             args.len() as c_uint,
90             None,
91         );
92         llvm::LLVMSetTailCall(ret, True);
93         if output.is_some() {
94             llvm::LLVMBuildRet(llbuilder, ret);
95         } else {
96             llvm::LLVMBuildRetVoid(llbuilder);
97         }
98         llvm::LLVMDisposeBuilder(llbuilder);
99     }
100
101     // rust alloc error handler
102     let args = [usize, usize]; // size, align
103
104     let ty = llvm::LLVMFunctionType(void, args.as_ptr(), args.len() as c_uint, False);
105     let name = "__rust_alloc_error_handler";
106     let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr().cast(), name.len(), ty);
107     // -> ! DIFlagNoReturn
108     llvm::Attribute::NoReturn.apply_llfn(llvm::AttributePlace::Function, llfn);
109
110     if tcx.sess.target.default_hidden_visibility {
111         llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
112     }
113     if tcx.sess.must_emit_unwind_tables() {
114         attributes::emit_uwtable(llfn, true);
115     }
116
117     let kind = if has_alloc_error_handler { AllocatorKind::Global } else { AllocatorKind::Default };
118     let callee = kind.fn_name(sym::oom);
119     let callee = llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty);
120     // -> ! DIFlagNoReturn
121     llvm::Attribute::NoReturn.apply_llfn(llvm::AttributePlace::Function, callee);
122     llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
123
124     let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast());
125
126     let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
127     llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);
128     let args = args
129         .iter()
130         .enumerate()
131         .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
132         .collect::<Vec<_>>();
133     let ret =
134         llvm::LLVMRustBuildCall(llbuilder, ty, callee, args.as_ptr(), args.len() as c_uint, None);
135     llvm::LLVMSetTailCall(ret, True);
136     llvm::LLVMBuildRetVoid(llbuilder);
137     llvm::LLVMDisposeBuilder(llbuilder);
138
139     if tcx.sess.opts.debuginfo != DebugInfo::None {
140         let dbg_cx = debuginfo::CrateDebugContext::new(llmod);
141         debuginfo::metadata::compile_unit_metadata(tcx, module_name, &dbg_cx);
142         dbg_cx.finalize(tcx.sess);
143     }
144 }