3 use rustc_ast
::expand
::allocator
::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS}
;
5 use rustc_middle
::ty
::TyCtxt
;
6 use rustc_span
::symbol
::sym
;
8 use crate::llvm
::{self, False, True}
;
11 pub(crate) unsafe fn codegen(
13 mods
: &mut ModuleLlvm
,
15 has_alloc_error_handler
: bool
,
17 let llcx
= &*mods
.llcx
;
18 let llmod
= mods
.llmod();
19 let usize = match tcx
.sess
.target
.pointer_width
{
20 16 => llvm
::LLVMInt16TypeInContext(llcx
),
21 32 => llvm
::LLVMInt32TypeInContext(llcx
),
22 64 => llvm
::LLVMInt64TypeInContext(llcx
),
23 tws
=> bug
!("Unsupported target word size for int: {}", tws
),
25 let i8 = llvm
::LLVMInt8TypeInContext(llcx
);
26 let i8p
= llvm
::LLVMPointerType(i8, 0);
27 let void
= llvm
::LLVMVoidTypeInContext(llcx
);
29 for method
in ALLOCATOR_METHODS
{
30 let mut args
= Vec
::with_capacity(method
.inputs
.len());
31 for ty
in method
.inputs
.iter() {
33 AllocatorTy
::Layout
=> {
34 args
.push(usize); // size
35 args
.push(usize); // align
37 AllocatorTy
::Ptr
=> args
.push(i8p
),
38 AllocatorTy
::Usize
=> args
.push(usize),
40 AllocatorTy
::ResultPtr
| AllocatorTy
::Unit
=> panic
!("invalid allocator arg"),
43 let output
= match method
.output
{
44 AllocatorTy
::ResultPtr
=> Some(i8p
),
45 AllocatorTy
::Unit
=> None
,
47 AllocatorTy
::Layout
| AllocatorTy
::Usize
| AllocatorTy
::Ptr
=> {
48 panic
!("invalid allocator output")
51 let ty
= llvm
::LLVMFunctionType(
52 output
.unwrap_or(void
),
57 let name
= format
!("__rust_{}", method
.name
);
58 let llfn
= llvm
::LLVMRustGetOrInsertFunction(llmod
, name
.as_ptr().cast(), name
.len(), ty
);
60 if tcx
.sess
.target
.default_hidden_visibility
{
61 llvm
::LLVMRustSetVisibility(llfn
, llvm
::Visibility
::Hidden
);
63 if tcx
.sess
.must_emit_unwind_tables() {
64 attributes
::emit_uwtable(llfn
, true);
67 let callee
= kind
.fn_name(method
.name
);
69 llvm
::LLVMRustGetOrInsertFunction(llmod
, callee
.as_ptr().cast(), callee
.len(), ty
);
70 llvm
::LLVMRustSetVisibility(callee
, llvm
::Visibility
::Hidden
);
72 let llbb
= llvm
::LLVMAppendBasicBlockInContext(llcx
, llfn
, "entry\0".as_ptr().cast());
74 let llbuilder
= llvm
::LLVMCreateBuilderInContext(llcx
);
75 llvm
::LLVMPositionBuilderAtEnd(llbuilder
, llbb
);
79 .map(|(i
, _
)| llvm
::LLVMGetParam(llfn
, i
as c_uint
))
81 let ret
= llvm
::LLVMRustBuildCall(
89 llvm
::LLVMSetTailCall(ret
, True
);
91 llvm
::LLVMBuildRet(llbuilder
, ret
);
93 llvm
::LLVMBuildRetVoid(llbuilder
);
95 llvm
::LLVMDisposeBuilder(llbuilder
);
98 // rust alloc error handler
99 let args
= [usize, usize]; // size, align
101 let ty
= llvm
::LLVMFunctionType(void
, args
.as_ptr(), args
.len() as c_uint
, False
);
102 let name
= "__rust_alloc_error_handler";
103 let llfn
= llvm
::LLVMRustGetOrInsertFunction(llmod
, name
.as_ptr().cast(), name
.len(), ty
);
104 // -> ! DIFlagNoReturn
105 llvm
::Attribute
::NoReturn
.apply_llfn(llvm
::AttributePlace
::Function
, llfn
);
107 if tcx
.sess
.target
.default_hidden_visibility
{
108 llvm
::LLVMRustSetVisibility(llfn
, llvm
::Visibility
::Hidden
);
110 if tcx
.sess
.must_emit_unwind_tables() {
111 attributes
::emit_uwtable(llfn
, true);
114 let kind
= if has_alloc_error_handler { AllocatorKind::Global }
else { AllocatorKind::Default }
;
115 let callee
= kind
.fn_name(sym
::oom
);
116 let callee
= llvm
::LLVMRustGetOrInsertFunction(llmod
, callee
.as_ptr().cast(), callee
.len(), ty
);
117 // -> ! DIFlagNoReturn
118 llvm
::Attribute
::NoReturn
.apply_llfn(llvm
::AttributePlace
::Function
, callee
);
119 llvm
::LLVMRustSetVisibility(callee
, llvm
::Visibility
::Hidden
);
121 let llbb
= llvm
::LLVMAppendBasicBlockInContext(llcx
, llfn
, "entry\0".as_ptr().cast());
123 let llbuilder
= llvm
::LLVMCreateBuilderInContext(llcx
);
124 llvm
::LLVMPositionBuilderAtEnd(llbuilder
, llbb
);
128 .map(|(i
, _
)| llvm
::LLVMGetParam(llfn
, i
as c_uint
))
129 .collect
::<Vec
<_
>>();
131 llvm
::LLVMRustBuildCall(llbuilder
, ty
, callee
, args
.as_ptr(), args
.len() as c_uint
, None
);
132 llvm
::LLVMSetTailCall(ret
, True
);
133 llvm
::LLVMBuildRetVoid(llbuilder
);
134 llvm
::LLVMDisposeBuilder(llbuilder
);