]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_codegen_llvm/src/allocator.rs
New upstream version 1.52.0~beta.3+dfsg1
[rustc.git] / compiler / rustc_codegen_llvm / src / allocator.rs
CommitLineData
9fa01778 1use crate::attributes;
041b39d2 2use libc::c_uint;
74b04a01 3use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
ba9703b0
XL
4use rustc_middle::bug;
5use rustc_middle::ty::TyCtxt;
29967ef6 6use rustc_span::symbol::sym;
041b39d2 7
9fa01778 8use crate::llvm::{self, False, True};
dfeec247 9use crate::ModuleLlvm;
041b39d2 10
29967ef6
XL
11pub(crate) unsafe fn codegen(
12 tcx: TyCtxt<'_>,
13 mods: &mut ModuleLlvm,
14 kind: AllocatorKind,
15 has_alloc_error_handler: bool,
16) {
b7449926
XL
17 let llcx = &*mods.llcx;
18 let llmod = mods.llmod();
29967ef6
XL
19 let usize = match tcx.sess.target.pointer_width {
20 16 => llvm::LLVMInt16TypeInContext(llcx),
21 32 => llvm::LLVMInt32TypeInContext(llcx),
22 64 => llvm::LLVMInt64TypeInContext(llcx),
041b39d2
XL
23 tws => bug!("Unsupported target word size for int: {}", tws),
24 };
25 let i8 = llvm::LLVMInt8TypeInContext(llcx);
26 let i8p = llvm::LLVMPointerType(i8, 0);
041b39d2
XL
27 let void = llvm::LLVMVoidTypeInContext(llcx);
28
29 for method in ALLOCATOR_METHODS {
0bf4aa26 30 let mut args = Vec::with_capacity(method.inputs.len());
041b39d2
XL
31 for ty in method.inputs.iter() {
32 match *ty {
33 AllocatorTy::Layout => {
34 args.push(usize); // size
35 args.push(usize); // align
36 }
041b39d2 37 AllocatorTy::Ptr => args.push(i8p),
83c7162d 38 AllocatorTy::Usize => args.push(usize),
041b39d2 39
dfeec247 40 AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
041b39d2
XL
41 }
42 }
43 let output = match method.output {
83c7162d 44 AllocatorTy::ResultPtr => Some(i8p),
041b39d2
XL
45 AllocatorTy::Unit => None,
46
dfeec247
XL
47 AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
48 panic!("invalid allocator output")
49 }
041b39d2 50 };
dfeec247
XL
51 let ty = llvm::LLVMFunctionType(
52 output.unwrap_or(void),
53 args.as_ptr(),
54 args.len() as c_uint,
55 False,
56 );
ba9703b0
XL
57 let name = format!("__rust_{}", method.name);
58 let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr().cast(), name.len(), ty);
041b39d2 59
29967ef6 60 if tcx.sess.target.default_hidden_visibility {
2c00a5a8
XL
61 llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
62 }
f9f354fc 63 if tcx.sess.must_emit_unwind_tables() {
b7449926
XL
64 attributes::emit_uwtable(llfn, true);
65 }
2c00a5a8 66
ba9703b0
XL
67 let callee = kind.fn_name(method.name);
68 let callee =
69 llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty);
b7449926 70 llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
041b39d2 71
dfeec247 72 let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast());
041b39d2
XL
73
74 let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
75 llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);
dfeec247
XL
76 let args = args
77 .iter()
78 .enumerate()
79 .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
80 .collect::<Vec<_>>();
ba9703b0
XL
81 let ret =
82 llvm::LLVMRustBuildCall(llbuilder, callee, args.as_ptr(), args.len() as c_uint, None);
041b39d2
XL
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 }
29967ef6
XL
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);
6a06907d 96 let name = "__rust_alloc_error_handler";
29967ef6
XL
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);
041b39d2 128}