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}
;
16 use session
::config
::NoDebugInfo
;
18 pub use syntax
::attr
::InlineAttr
;
23 use trans
::context
::CrateContext
;
27 /// Mark LLVM function to use provided inline heuristic.
29 pub fn inline(val
: ValueRef
, inline
: InlineAttr
) {
30 use self::InlineAttr
::*;
32 Hint
=> llvm
::SetFunctionAttribute(val
, llvm
::Attribute
::InlineHint
),
33 Always
=> llvm
::SetFunctionAttribute(val
, llvm
::Attribute
::AlwaysInline
),
34 Never
=> llvm
::SetFunctionAttribute(val
, llvm
::Attribute
::NoInline
),
36 let attr
= llvm
::Attribute
::InlineHint
|
37 llvm
::Attribute
::AlwaysInline
|
38 llvm
::Attribute
::NoInline
;
40 llvm
::LLVMRemoveFunctionAttr(val
, attr
.bits() as c_ulonglong
)
46 /// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function.
48 pub fn emit_uwtable(val
: ValueRef
, emit
: bool
) {
50 llvm
::SetFunctionAttribute(val
, llvm
::Attribute
::UWTable
);
53 llvm
::LLVMRemoveFunctionAttr(
55 llvm
::Attribute
::UWTable
.bits() as c_ulonglong
,
61 /// Tell LLVM whether the function can or cannot unwind.
63 pub fn unwind(val
: ValueRef
, can_unwind
: bool
) {
66 llvm
::LLVMRemoveFunctionAttr(
68 llvm
::Attribute
::NoUnwind
.bits() as c_ulonglong
,
72 llvm
::SetFunctionAttribute(val
, llvm
::Attribute
::NoUnwind
);
76 /// Tell LLVM whether it should optimise function for size.
78 #[allow(dead_code)] // possibly useful function
79 pub fn set_optimize_for_size(val
: ValueRef
, optimize
: bool
) {
81 llvm
::SetFunctionAttribute(val
, llvm
::Attribute
::OptimizeForSize
);
84 llvm
::LLVMRemoveFunctionAttr(
86 llvm
::Attribute
::OptimizeForSize
.bits() as c_ulonglong
,
92 /// Composite function which sets LLVM attributes for function depending on its AST (#[attribute])
94 pub fn from_fn_attrs(ccx
: &CrateContext
, attrs
: &[ast
::Attribute
], llfn
: ValueRef
) {
96 inline(llfn
, find_inline_attr(Some(ccx
.sess().diagnostic()), attrs
));
98 // FIXME: #11906: Omitting frame pointers breaks retrieving the value of a
100 let no_fp_elim
= (ccx
.sess().opts
.debuginfo
!= NoDebugInfo
) ||
101 !ccx
.sess().target
.target
.options
.eliminate_frame_pointer
;
104 let attr
= "no-frame-pointer-elim\0".as_ptr() as *const _
;
105 let val
= "true\0".as_ptr() as *const _
;
106 llvm
::LLVMAddFunctionAttrStringValue(llfn
,
107 llvm
::FunctionIndex
as c_uint
,
113 if attr
.check_name("cold") {
115 llvm
::LLVMAddFunctionAttribute(llfn
,
116 llvm
::FunctionIndex
as c_uint
,
117 llvm
::ColdAttribute
as u64)
119 } else if attr
.check_name("allocator") {
120 llvm
::Attribute
::NoAlias
.apply_llfn(llvm
::ReturnIndex
as c_uint
, llfn
);
121 } else if attr
.check_name("unwind") {
127 /// Composite function which converts function type into LLVM attributes for the function.
128 pub fn from_fn_type
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>, fn_type
: ty
::Ty
<'tcx
>)
129 -> llvm
::AttrBuilder
{
130 use middle
::ty
::{BrAnon, ReLateBound}
;
133 let (fn_sig
, abi
, env_ty
) = match fn_type
.sty
{
134 ty
::TyBareFn(_
, ref f
) => (&f
.sig
, f
.abi
, None
),
135 ty
::TyClosure(closure_did
, ref substs
) => {
136 let infcx
= infer
::normalizing_infer_ctxt(ccx
.tcx(), &ccx
.tcx().tables
);
137 function_type
= infcx
.closure_type(closure_did
, substs
);
138 let self_type
= base
::self_type_for_closure(ccx
, closure_did
, fn_type
);
139 (&function_type
.sig
, Abi
::RustCall
, Some(self_type
))
141 _
=> ccx
.sess().bug("expected closure or function.")
144 let fn_sig
= ccx
.tcx().erase_late_bound_regions(fn_sig
);
145 let fn_sig
= infer
::normalize_associated_type(ccx
.tcx(), &fn_sig
);
147 let mut attrs
= llvm
::AttrBuilder
::new();
148 let ret_ty
= fn_sig
.output
;
150 // These have an odd calling convention, so we need to manually
151 // unpack the input ty's
152 let input_tys
= match fn_type
.sty
{
153 ty
::TyClosure(..) => {
154 assert
!(abi
== Abi
::RustCall
);
156 match fn_sig
.inputs
[0].sty
{
157 ty
::TyTuple(ref inputs
) => {
158 let mut full_inputs
= vec
![env_ty
.expect("Missing closure environment")];
159 full_inputs
.extend_from_slice(inputs
);
162 _
=> ccx
.sess().bug("expected tuple'd inputs")
165 ty
::TyBareFn(..) if abi
== Abi
::RustCall
=> {
166 let mut inputs
= vec
![fn_sig
.inputs
[0]];
168 match fn_sig
.inputs
[1].sty
{
169 ty
::TyTuple(ref t_in
) => {
170 inputs
.extend_from_slice(&t_in
[..]);
173 _
=> ccx
.sess().bug("expected tuple'd inputs")
176 _
=> fn_sig
.inputs
.clone()
179 // Index 0 is the return value of the llvm func, so we start at 1
181 if let ty
::FnConverging(ret_ty
) = ret_ty
{
182 // A function pointer is called without the declaration
183 // available, so we have to apply any attributes with ABI
184 // implications directly to the call instruction. Right now,
185 // the only attribute we need to worry about is `sret`.
186 if type_of
::return_uses_outptr(ccx
, ret_ty
) {
187 let llret_sz
= machine
::llsize_of_real(ccx
, type_of
::type_of(ccx
, ret_ty
));
189 // The outptr can be noalias and nocapture because it's entirely
190 // invisible to the program. We also know it's nonnull as well
191 // as how many bytes we can dereference
192 attrs
.arg(1, llvm
::Attribute
::StructRet
)
193 .arg(1, llvm
::Attribute
::NoAlias
)
194 .arg(1, llvm
::Attribute
::NoCapture
)
195 .arg(1, llvm
::DereferenceableAttribute(llret_sz
));
197 // Add one more since there's an outptr
200 // The `noalias` attribute on the return value is useful to a
201 // function ptr caller.
203 // `Box` pointer return values never alias because ownership
205 ty
::TyBox(it
) if common
::type_is_sized(ccx
.tcx(), it
) => {
206 attrs
.ret(llvm
::Attribute
::NoAlias
);
211 // We can also mark the return value as `dereferenceable` in certain cases
213 // These are not really pointers but pairs, (pointer, len)
214 ty
::TyRef(_
, ty
::TypeAndMut { ty: inner, .. }
)
215 | ty
::TyBox(inner
) if common
::type_is_sized(ccx
.tcx(), inner
) => {
216 let llret_sz
= machine
::llsize_of_real(ccx
, type_of
::type_of(ccx
, inner
));
217 attrs
.ret(llvm
::DereferenceableAttribute(llret_sz
));
222 if let ty
::TyBool
= ret_ty
.sty
{
223 attrs
.ret(llvm
::Attribute
::ZExt
);
228 for &t
in input_tys
.iter() {
230 _
if type_of
::arg_is_indirect(ccx
, t
) => {
231 let llarg_sz
= machine
::llsize_of_real(ccx
, type_of
::type_of(ccx
, t
));
233 // For non-immediate arguments the callee gets its own copy of
234 // the value on the stack, so there are no aliases. It's also
235 // program-invisible so can't possibly capture
236 attrs
.arg(idx
, llvm
::Attribute
::NoAlias
)
237 .arg(idx
, llvm
::Attribute
::NoCapture
)
238 .arg(idx
, llvm
::DereferenceableAttribute(llarg_sz
));
242 attrs
.arg(idx
, llvm
::Attribute
::ZExt
);
245 // `Box` pointer parameters never alias because ownership is transferred
246 ty
::TyBox(inner
) => {
247 attrs
.arg(idx
, llvm
::Attribute
::NoAlias
);
249 if common
::type_is_sized(ccx
.tcx(), inner
) {
250 let llsz
= machine
::llsize_of_real(ccx
, type_of
::type_of(ccx
, inner
));
251 attrs
.arg(idx
, llvm
::DereferenceableAttribute(llsz
));
253 attrs
.arg(idx
, llvm
::NonNullAttribute
);
254 if inner
.is_trait() {
255 attrs
.arg(idx
+ 1, llvm
::NonNullAttribute
);
260 ty
::TyRef(b
, mt
) => {
261 // `&mut` pointer parameters never alias other parameters, or mutable global data
263 // `&T` where `T` contains no `UnsafeCell<U>` is immutable, and can be marked as
264 // both `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely
265 // on memory dependencies rather than pointer equality
266 let interior_unsafe
= mt
.ty
.type_contents(ccx
.tcx()).interior_unsafe();
268 if mt
.mutbl
!= hir
::MutMutable
&& !interior_unsafe
{
269 attrs
.arg(idx
, llvm
::Attribute
::NoAlias
);
272 if mt
.mutbl
== hir
::MutImmutable
&& !interior_unsafe
{
273 attrs
.arg(idx
, llvm
::Attribute
::ReadOnly
);
276 // & pointer parameters are also never null and for sized types we also know
277 // exactly how many bytes we can dereference
278 if common
::type_is_sized(ccx
.tcx(), mt
.ty
) {
279 let llsz
= machine
::llsize_of_real(ccx
, type_of
::type_of(ccx
, mt
.ty
));
280 attrs
.arg(idx
, llvm
::DereferenceableAttribute(llsz
));
282 attrs
.arg(idx
, llvm
::NonNullAttribute
);
283 if mt
.ty
.is_trait() {
284 attrs
.arg(idx
+ 1, llvm
::NonNullAttribute
);
288 // When a reference in an argument has no named lifetime, it's
289 // impossible for that reference to escape this function
290 // (returned or stored beyond the call by a closure).
291 if let ReLateBound(_
, BrAnon(_
)) = *b
{
292 attrs
.arg(idx
, llvm
::Attribute
::NoCapture
);
299 if common
::type_is_fat_ptr(ccx
.tcx(), t
) {