]>
Commit | Line | Data |
---|---|---|
9fa01778 | 1 | use crate::attributes; |
041b39d2 | 2 | use libc::c_uint; |
74b04a01 | 3 | use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS}; |
ba9703b0 XL |
4 | use rustc_middle::bug; |
5 | use rustc_middle::ty::TyCtxt; | |
29967ef6 | 6 | use rustc_span::symbol::sym; |
041b39d2 | 7 | |
9fa01778 | 8 | use crate::llvm::{self, False, True}; |
dfeec247 | 9 | use crate::ModuleLlvm; |
041b39d2 | 10 | |
29967ef6 XL |
11 | pub(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 | } |