1 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10 //! Set and unset common attributes on LLVM values.
12 use libc
::{c_uint, c_ulonglong}
;
13 use llvm
::{self, ValueRef, AttrHelper}
;
14 use middle
::ty
::{self, ClosureTyper}
;
15 use session
::config
::NoDebugInfo
;
18 pub use syntax
::attr
::InlineAttr
;
21 use trans
::context
::CrateContext
;
25 /// Mark LLVM function to use split stack.
27 pub fn split_stack(val
: ValueRef
, set
: bool
) {
29 let attr
= "split-stack\0".as_ptr() as *const _
;
31 llvm
::LLVMAddFunctionAttrString(val
, llvm
::FunctionIndex
as c_uint
, attr
);
33 llvm
::LLVMRemoveFunctionAttrString(val
, llvm
::FunctionIndex
as c_uint
, attr
);
38 /// Mark LLVM function to use provided inline heuristic.
40 pub fn inline(val
: ValueRef
, inline
: InlineAttr
) {
41 use self::InlineAttr
::*;
43 Hint
=> llvm
::SetFunctionAttribute(val
, llvm
::Attribute
::InlineHint
),
44 Always
=> llvm
::SetFunctionAttribute(val
, llvm
::Attribute
::AlwaysInline
),
45 Never
=> llvm
::SetFunctionAttribute(val
, llvm
::Attribute
::NoInline
),
47 let attr
= llvm
::Attribute
::InlineHint
|
48 llvm
::Attribute
::AlwaysInline
|
49 llvm
::Attribute
::NoInline
;
51 llvm
::LLVMRemoveFunctionAttr(val
, attr
.bits() as c_ulonglong
)
57 /// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function.
59 pub fn emit_uwtable(val
: ValueRef
, emit
: bool
) {
61 llvm
::SetFunctionAttribute(val
, llvm
::Attribute
::UWTable
);
64 llvm
::LLVMRemoveFunctionAttr(
66 llvm
::Attribute
::UWTable
.bits() as c_ulonglong
,
72 /// Tell LLVM whether the function can or cannot unwind.
74 #[allow(dead_code)] // possibly useful function
75 pub fn unwind(val
: ValueRef
, can_unwind
: bool
) {
78 llvm
::LLVMRemoveFunctionAttr(
80 llvm
::Attribute
::NoUnwind
.bits() as c_ulonglong
,
84 llvm
::SetFunctionAttribute(val
, llvm
::Attribute
::NoUnwind
);
88 /// Tell LLVM whether it should optimise function for size.
90 #[allow(dead_code)] // possibly useful function
91 pub fn set_optimize_for_size(val
: ValueRef
, optimize
: bool
) {
93 llvm
::SetFunctionAttribute(val
, llvm
::Attribute
::OptimizeForSize
);
96 llvm
::LLVMRemoveFunctionAttr(
98 llvm
::Attribute
::OptimizeForSize
.bits() as c_ulonglong
,
104 /// Composite function which sets LLVM attributes for function depending on its AST (#[attribute])
106 pub fn from_fn_attrs(ccx
: &CrateContext
, attrs
: &[ast
::Attribute
], llfn
: ValueRef
) {
108 inline(llfn
, find_inline_attr(Some(ccx
.sess().diagnostic()), attrs
));
110 // FIXME: #11906: Omitting frame pointers breaks retrieving the value of a
112 let no_fp_elim
= (ccx
.sess().opts
.debuginfo
!= NoDebugInfo
) ||
113 !ccx
.sess().target
.target
.options
.eliminate_frame_pointer
;
116 let attr
= "no-frame-pointer-elim\0".as_ptr() as *const _
;
117 let val
= "true\0".as_ptr() as *const _
;
118 llvm
::LLVMAddFunctionAttrStringValue(llfn
,
119 llvm
::FunctionIndex
as c_uint
,
125 if attr
.check_name("no_stack_check") {
126 split_stack(llfn
, false);
127 } else if attr
.check_name("cold") {
129 llvm
::LLVMAddFunctionAttribute(llfn
,
130 llvm
::FunctionIndex
as c_uint
,
131 llvm
::ColdAttribute
as u64)
133 } else if attr
.check_name("allocator") {
134 llvm
::Attribute
::NoAlias
.apply_llfn(llvm
::ReturnIndex
as c_uint
, llfn
);
139 /// Composite function which converts function type into LLVM attributes for the function.
140 pub fn from_fn_type
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>, fn_type
: ty
::Ty
<'tcx
>)
141 -> llvm
::AttrBuilder
{
142 use middle
::ty
::{BrAnon, ReLateBound}
;
145 let (fn_sig
, abi
, env_ty
) = match fn_type
.sty
{
146 ty
::TyBareFn(_
, ref f
) => (&f
.sig
, f
.abi
, None
),
147 ty
::TyClosure(closure_did
, substs
) => {
148 let typer
= common
::NormalizingClosureTyper
::new(ccx
.tcx());
149 function_type
= typer
.closure_type(closure_did
, substs
);
150 let self_type
= base
::self_type_for_closure(ccx
, closure_did
, fn_type
);
151 (&function_type
.sig
, abi
::RustCall
, Some(self_type
))
153 _
=> ccx
.sess().bug("expected closure or function.")
156 let fn_sig
= ty
::erase_late_bound_regions(ccx
.tcx(), fn_sig
);
158 let mut attrs
= llvm
::AttrBuilder
::new();
159 let ret_ty
= fn_sig
.output
;
161 // These have an odd calling convention, so we need to manually
162 // unpack the input ty's
163 let input_tys
= match fn_type
.sty
{
164 ty
::TyClosure(..) => {
165 assert
!(abi
== abi
::RustCall
);
167 match fn_sig
.inputs
[0].sty
{
168 ty
::TyTuple(ref inputs
) => {
169 let mut full_inputs
= vec
![env_ty
.expect("Missing closure environment")];
170 full_inputs
.push_all(inputs
);
173 _
=> ccx
.sess().bug("expected tuple'd inputs")
176 ty
::TyBareFn(..) if abi
== abi
::RustCall
=> {
177 let mut inputs
= vec
![fn_sig
.inputs
[0]];
179 match fn_sig
.inputs
[1].sty
{
180 ty
::TyTuple(ref t_in
) => {
181 inputs
.push_all(&t_in
[..]);
184 _
=> ccx
.sess().bug("expected tuple'd inputs")
187 _
=> fn_sig
.inputs
.clone()
190 // Index 0 is the return value of the llvm func, so we start at 1
192 if let ty
::FnConverging(ret_ty
) = ret_ty
{
193 // A function pointer is called without the declaration
194 // available, so we have to apply any attributes with ABI
195 // implications directly to the call instruction. Right now,
196 // the only attribute we need to worry about is `sret`.
197 if type_of
::return_uses_outptr(ccx
, ret_ty
) {
198 let llret_sz
= machine
::llsize_of_real(ccx
, type_of
::type_of(ccx
, ret_ty
));
200 // The outptr can be noalias and nocapture because it's entirely
201 // invisible to the program. We also know it's nonnull as well
202 // as how many bytes we can dereference
203 attrs
.arg(1, llvm
::Attribute
::StructRet
)
204 .arg(1, llvm
::Attribute
::NoAlias
)
205 .arg(1, llvm
::Attribute
::NoCapture
)
206 .arg(1, llvm
::DereferenceableAttribute(llret_sz
));
208 // Add one more since there's an outptr
211 // The `noalias` attribute on the return value is useful to a
212 // function ptr caller.
214 // `Box` pointer return values never alias because ownership
216 ty
::TyBox(it
) if common
::type_is_sized(ccx
.tcx(), it
) => {
217 attrs
.ret(llvm
::Attribute
::NoAlias
);
222 // We can also mark the return value as `dereferenceable` in certain cases
224 // These are not really pointers but pairs, (pointer, len)
225 ty
::TyRef(_
, ty
::mt { ty: inner, .. }
)
226 | ty
::TyBox(inner
) if common
::type_is_sized(ccx
.tcx(), inner
) => {
227 let llret_sz
= machine
::llsize_of_real(ccx
, type_of
::type_of(ccx
, inner
));
228 attrs
.ret(llvm
::DereferenceableAttribute(llret_sz
));
233 if let ty
::TyBool
= ret_ty
.sty
{
234 attrs
.ret(llvm
::Attribute
::ZExt
);
239 for &t
in input_tys
.iter() {
241 _
if type_of
::arg_is_indirect(ccx
, t
) => {
242 let llarg_sz
= machine
::llsize_of_real(ccx
, type_of
::type_of(ccx
, t
));
244 // For non-immediate arguments the callee gets its own copy of
245 // the value on the stack, so there are no aliases. It's also
246 // program-invisible so can't possibly capture
247 attrs
.arg(idx
, llvm
::Attribute
::NoAlias
)
248 .arg(idx
, llvm
::Attribute
::NoCapture
)
249 .arg(idx
, llvm
::DereferenceableAttribute(llarg_sz
));
253 attrs
.arg(idx
, llvm
::Attribute
::ZExt
);
256 // `Box` pointer parameters never alias because ownership is transferred
257 ty
::TyBox(inner
) => {
258 attrs
.arg(idx
, llvm
::Attribute
::NoAlias
);
260 if common
::type_is_sized(ccx
.tcx(), inner
) {
261 let llsz
= machine
::llsize_of_real(ccx
, type_of
::type_of(ccx
, inner
));
262 attrs
.arg(idx
, llvm
::DereferenceableAttribute(llsz
));
264 attrs
.arg(idx
, llvm
::NonNullAttribute
);
265 if ty
::type_is_trait(inner
) {
266 attrs
.arg(idx
+ 1, llvm
::NonNullAttribute
);
271 ty
::TyRef(b
, mt
) => {
272 // `&mut` pointer parameters never alias other parameters, or mutable global data
274 // `&T` where `T` contains no `UnsafeCell<U>` is immutable, and can be marked as
275 // both `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely
276 // on memory dependencies rather than pointer equality
277 let interior_unsafe
= ty
::type_contents(ccx
.tcx(), mt
.ty
).interior_unsafe();
279 if mt
.mutbl
== ast
::MutMutable
|| !interior_unsafe
{
280 attrs
.arg(idx
, llvm
::Attribute
::NoAlias
);
283 if mt
.mutbl
== ast
::MutImmutable
&& !interior_unsafe
{
284 attrs
.arg(idx
, llvm
::Attribute
::ReadOnly
);
287 // & pointer parameters are also never null and for sized types we also know
288 // exactly how many bytes we can dereference
289 if common
::type_is_sized(ccx
.tcx(), mt
.ty
) {
290 let llsz
= machine
::llsize_of_real(ccx
, type_of
::type_of(ccx
, mt
.ty
));
291 attrs
.arg(idx
, llvm
::DereferenceableAttribute(llsz
));
293 attrs
.arg(idx
, llvm
::NonNullAttribute
);
294 if ty
::type_is_trait(mt
.ty
) {
295 attrs
.arg(idx
+ 1, llvm
::NonNullAttribute
);
299 // When a reference in an argument has no named lifetime, it's
300 // impossible for that reference to escape this function
301 // (returned or stored beyond the call by a closure).
302 if let ReLateBound(_
, BrAnon(_
)) = *b
{
303 attrs
.arg(idx
, llvm
::Attribute
::NoCapture
);
310 if common
::type_is_fat_ptr(ccx
.tcx(), t
) {