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 std
::ffi
::{CStr, CString}
;
14 use rustc
::session
::config
::Sanitizer
;
16 use llvm
::{self, Attribute, ValueRef}
;
17 use llvm
::AttributePlace
::Function
;
18 pub use syntax
::attr
::{self, InlineAttr}
;
20 use context
::CrateContext
;
22 /// Mark LLVM function to use provided inline heuristic.
24 pub fn inline(val
: ValueRef
, inline
: InlineAttr
) {
25 use self::InlineAttr
::*;
27 Hint
=> Attribute
::InlineHint
.apply_llfn(Function
, val
),
28 Always
=> Attribute
::AlwaysInline
.apply_llfn(Function
, val
),
29 Never
=> Attribute
::NoInline
.apply_llfn(Function
, val
),
31 Attribute
::InlineHint
.unapply_llfn(Function
, val
);
32 Attribute
::AlwaysInline
.unapply_llfn(Function
, val
);
33 Attribute
::NoInline
.unapply_llfn(Function
, val
);
38 /// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function.
40 pub fn emit_uwtable(val
: ValueRef
, emit
: bool
) {
41 Attribute
::UWTable
.toggle_llfn(Function
, val
, emit
);
44 /// Tell LLVM whether the function can or cannot unwind.
46 pub fn unwind(val
: ValueRef
, can_unwind
: bool
) {
47 Attribute
::NoUnwind
.toggle_llfn(Function
, val
, !can_unwind
);
50 /// Tell LLVM whether it should optimize function for size.
52 #[allow(dead_code)] // possibly useful function
53 pub fn set_optimize_for_size(val
: ValueRef
, optimize
: bool
) {
54 Attribute
::OptimizeForSize
.toggle_llfn(Function
, val
, optimize
);
57 /// Tell LLVM if this function should be 'naked', i.e. skip the epilogue and prologue.
59 pub fn naked(val
: ValueRef
, is_naked
: bool
) {
60 Attribute
::Naked
.toggle_llfn(Function
, val
, is_naked
);
63 pub fn set_frame_pointer_elimination(ccx
: &CrateContext
, llfn
: ValueRef
) {
64 // FIXME: #11906: Omitting frame pointers breaks retrieving the value of a
66 if ccx
.sess().must_not_eliminate_frame_pointers() {
67 llvm
::AddFunctionAttrStringValue(
68 llfn
, llvm
::AttributePlace
::Function
,
69 cstr("no-frame-pointer-elim\0"), cstr("true\0"));
73 pub fn set_probestack(ccx
: &CrateContext
, llfn
: ValueRef
) {
74 // Only use stack probes if the target specification indicates that we
75 // should be using stack probes
76 if !ccx
.sess().target
.target
.options
.stack_probes
{
80 // Currently stack probes seem somewhat incompatible with the address
81 // sanitizer. With asan we're already protected from stack overflow anyway
82 // so we don't really need stack probes regardless.
83 match ccx
.sess().opts
.debugging_opts
.sanitizer
{
84 Some(Sanitizer
::Address
) => return,
88 // Flag our internal `__rust_probestack` function as the stack probe symbol.
89 // This is defined in the `compiler-builtins` crate for each architecture.
90 llvm
::AddFunctionAttrStringValue(
91 llfn
, llvm
::AttributePlace
::Function
,
92 cstr("probe-stack\0"), cstr("__rust_probestack\0"));
95 /// Composite function which sets LLVM attributes for function depending on its AST (#[attribute])
97 pub fn from_fn_attrs(ccx
: &CrateContext
, attrs
: &[ast
::Attribute
], llfn
: ValueRef
) {
99 inline(llfn
, find_inline_attr(Some(ccx
.sess().diagnostic()), attrs
));
101 set_frame_pointer_elimination(ccx
, llfn
);
102 set_probestack(ccx
, llfn
);
103 let mut target_features
= vec
![];
105 if attr
.check_name("target_feature") {
106 if let Some(val
) = attr
.value_str() {
107 for feat
in val
.as_str().split(",").map(|f
| f
.trim()) {
108 if !feat
.is_empty() && !feat
.contains('
\0'
) {
109 target_features
.push(feat
.to_string());
113 } else if attr
.check_name("cold") {
114 Attribute
::Cold
.apply_llfn(Function
, llfn
);
115 } else if attr
.check_name("naked") {
117 } else if attr
.check_name("allocator") {
118 Attribute
::NoAlias
.apply_llfn(
119 llvm
::AttributePlace
::ReturnValue
, llfn
);
120 } else if attr
.check_name("unwind") {
122 } else if attr
.check_name("rustc_allocator_nounwind") {
126 if !target_features
.is_empty() {
127 let val
= CString
::new(target_features
.join(",")).unwrap();
128 llvm
::AddFunctionAttrStringValue(
129 llfn
, llvm
::AttributePlace
::Function
,
130 cstr("target-features\0"), &val
);
134 fn cstr(s
: &'
static str) -> &CStr
{
135 CStr
::from_bytes_with_nul(s
.as_bytes()).expect("null-terminated string")