Skip to content

Commit c71970e

Browse files
committed
Extract attribute handling code into a module
This commit causes no change in trans semantics, it just moves some functions around and deduplicates them.
1 parent d36c4db commit c71970e

File tree

7 files changed

+172
-131
lines changed

7 files changed

+172
-131
lines changed

src/librustc_llvm/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ bitflags! {
157157
#[derive(Copy, Clone)]
158158
pub enum OtherAttribute {
159159
// The following are not really exposed in
160-
// the LLVM c api so instead to add these
160+
// the LLVM C api so instead to add these
161161
// we call a wrapper function in RustWrapper
162162
// that uses the C++ api.
163163
SanitizeAddressAttribute = 1 << 32,
@@ -958,6 +958,7 @@ extern {
958958
pub fn LLVMAddFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char);
959959
pub fn LLVMRemoveFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char);
960960
pub fn LLVMGetFunctionAttr(Fn: ValueRef) -> c_ulonglong;
961+
pub fn LLVMRemoveFunctionAttr(Fn: ValueRef, val: c_ulonglong);
961962

962963
/* Operations on parameters */
963964
pub fn LLVMCountParams(Fn: ValueRef) -> c_uint;
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
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.
4+
//
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.
11+
12+
use llvm::{self, ValueRef, AttrHelper};
13+
use syntax::ast;
14+
use syntax::attr::InlineAttr;
15+
pub use syntax::attr::InlineAttr::*;
16+
use trans::context::CrateContext;
17+
18+
use libc::{c_uint, c_ulonglong};
19+
20+
/// Mark LLVM function to use split stack.
21+
#[inline]
22+
pub fn split_stack(val: ValueRef, set: bool) {
23+
unsafe {
24+
let attr = "split-stack\0".as_ptr() as *const _;
25+
if set {
26+
llvm::LLVMAddFunctionAttrString(val, llvm::FunctionIndex as c_uint, attr);
27+
} else {
28+
llvm::LLVMRemoveFunctionAttrString(val, llvm::FunctionIndex as c_uint, attr);
29+
}
30+
}
31+
}
32+
33+
/// Mark LLVM function to use provided inline heuristic.
34+
#[inline]
35+
pub fn inline(val: ValueRef, inline: InlineAttr) {
36+
match inline {
37+
InlineHint => llvm::SetFunctionAttribute(val, llvm::InlineHintAttribute),
38+
InlineAlways => llvm::SetFunctionAttribute(val, llvm::AlwaysInlineAttribute),
39+
InlineNever => llvm::SetFunctionAttribute(val, llvm::NoInlineAttribute),
40+
InlineNone => {
41+
let attr = llvm::InlineHintAttribute |
42+
llvm::AlwaysInlineAttribute |
43+
llvm::NoInlineAttribute;
44+
unsafe {
45+
llvm::LLVMRemoveFunctionAttr(val, attr.bits() as c_ulonglong)
46+
}
47+
},
48+
};
49+
}
50+
51+
/// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function.
52+
#[inline]
53+
pub fn emit_uwtable(val: ValueRef, emit: bool) {
54+
if emit {
55+
llvm::SetFunctionAttribute(val, llvm::UWTableAttribute);
56+
} else {
57+
unsafe {
58+
llvm::LLVMRemoveFunctionAttr(val, llvm::UWTableAttribute.bits() as c_ulonglong);
59+
}
60+
}
61+
}
62+
63+
/// Tell LLVM whether the function can or cannot unwind.
64+
#[inline]
65+
#[allow(dead_code)] // possibly useful function
66+
pub fn unwind(val: ValueRef, can_unwind: bool) {
67+
if can_unwind {
68+
unsafe {
69+
llvm::LLVMRemoveFunctionAttr(val, llvm::NoUnwindAttribute.bits() as c_ulonglong);
70+
}
71+
} else {
72+
llvm::SetFunctionAttribute(val, llvm::NoUnwindAttribute);
73+
}
74+
}
75+
76+
/// Tell LLVM whether it should optimise function for size.
77+
#[inline]
78+
#[allow(dead_code)] // possibly useful function
79+
pub fn set_optimize_for_size(val: ValueRef, optimize: bool) {
80+
if optimize {
81+
llvm::SetFunctionAttribute(val, llvm::OptimizeForSizeAttribute);
82+
} else {
83+
unsafe {
84+
llvm::LLVMRemoveFunctionAttr(val, llvm::OptimizeForSizeAttribute.bits() as c_ulonglong);
85+
}
86+
}
87+
}
88+
89+
/// Composite function which sets LLVM attributes for function depending on its AST (#[attribute])
90+
/// attributes.
91+
pub fn convert_fn_attrs_to_llvm(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRef) {
92+
use syntax::attr::*;
93+
inline(llfn, find_inline_attr(Some(ccx.sess().diagnostic()), attrs));
94+
95+
for attr in attrs {
96+
if attr.check_name("no_stack_check") {
97+
split_stack(llfn, false);
98+
} else if attr.check_name("cold") {
99+
unsafe {
100+
llvm::LLVMAddFunctionAttribute(llfn,
101+
llvm::FunctionIndex as c_uint,
102+
llvm::ColdAttribute as u64)
103+
}
104+
} else if attr.check_name("allocator") {
105+
llvm::NoAliasAttribute.apply_llfn(llvm::ReturnIndex as c_uint, llfn);
106+
}
107+
}
108+
}

src/librustc_trans/trans/base.rs

Lines changed: 27 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
1+
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
22
// file at the top-level directory of this distribution and at
33
// http://rust-lang.org/COPYRIGHT.
44
//
@@ -7,21 +7,20 @@
77
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
10-
11-
// trans.rs: Translate the completed AST to the LLVM IR.
12-
//
13-
// Some functions here, such as trans_block and trans_expr, return a value --
14-
// the result of the translation to LLVM -- while others, such as trans_fn,
15-
// trans_impl, and trans_item, are called only for the side effect of adding a
16-
// particular definition to the LLVM IR output we're producing.
17-
//
18-
// Hopefully useful general knowledge about trans:
19-
//
20-
// * There's no way to find out the Ty type of a ValueRef. Doing so
21-
// would be "trying to get the eggs out of an omelette" (credit:
22-
// pcwalton). You can, instead, find out its TypeRef by calling val_ty,
23-
// but one TypeRef corresponds to many `Ty`s; for instance, tup(int, int,
24-
// int) and rec(x=int, y=int, z=int) will have the same TypeRef.
10+
//! Translate the completed AST to the LLVM IR.
11+
//!
12+
//! Some functions here, such as trans_block and trans_expr, return a value --
13+
//! the result of the translation to LLVM -- while others, such as trans_fn,
14+
//! trans_impl, and trans_item, are called only for the side effect of adding a
15+
//! particular definition to the LLVM IR output we're producing.
16+
//!
17+
//! Hopefully useful general knowledge about trans:
18+
//!
19+
//! * There's no way to find out the Ty type of a ValueRef. Doing so
20+
//! would be "trying to get the eggs out of an omelette" (credit:
21+
//! pcwalton). You can, instead, find out its TypeRef by calling val_ty,
22+
//! but one TypeRef corresponds to many `Ty`s; for instance, tup(int, int,
23+
//! int) and rec(x=int, y=int, z=int) will have the same TypeRef.
2524
2625
#![allow(non_camel_case_types)]
2726

@@ -33,7 +32,7 @@ use super::ModuleTranslation;
3332
use back::link::mangle_exported_name;
3433
use back::{link, abi};
3534
use lint;
36-
use llvm::{AttrHelper, BasicBlockRef, Linkage, ValueRef, Vector, get_param};
35+
use llvm::{BasicBlockRef, Linkage, ValueRef, Vector, get_param};
3736
use llvm;
3837
use metadata::{csearch, encoder, loader};
3938
use middle::astencode;
@@ -46,6 +45,7 @@ use session::config::{self, NoDebugInfo};
4645
use session::Session;
4746
use trans::_match;
4847
use trans::adt;
48+
use trans::attributes;
4949
use trans::build::*;
5050
use trans::builder::{Builder, noname};
5151
use trans::callee;
@@ -204,7 +204,7 @@ pub fn decl_fn(ccx: &CrateContext, name: &str, cc: llvm::CallConv,
204204
llvm::SetUnnamedAddr(llfn, true);
205205

206206
if ccx.is_split_stack_supported() && !ccx.sess().opts.cg.no_stack_check {
207-
set_split_stack(llfn);
207+
attributes::split_stack(llfn, true);
208208
}
209209

210210
llfn
@@ -245,7 +245,7 @@ fn get_extern_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<'tcx>,
245245
let f = decl_rust_fn(ccx, fn_ty, name);
246246

247247
let attrs = csearch::get_item_attrs(&ccx.sess().cstore, did);
248-
set_llvm_fn_attrs(ccx, &attrs[..], f);
248+
attributes::convert_fn_attrs_to_llvm(ccx, &attrs[..], f);
249249

250250
ccx.externs().borrow_mut().insert(name.to_string(), f);
251251
f
@@ -390,77 +390,6 @@ pub fn malloc_raw_dyn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
390390
Result::new(r.bcx, PointerCast(r.bcx, r.val, llty_ptr))
391391
}
392392

393-
#[allow(dead_code)] // useful
394-
pub fn set_optimize_for_size(f: ValueRef) {
395-
llvm::SetFunctionAttribute(f, llvm::OptimizeForSizeAttribute)
396-
}
397-
398-
pub fn set_no_inline(f: ValueRef) {
399-
llvm::SetFunctionAttribute(f, llvm::NoInlineAttribute)
400-
}
401-
402-
#[allow(dead_code)] // useful
403-
pub fn set_no_unwind(f: ValueRef) {
404-
llvm::SetFunctionAttribute(f, llvm::NoUnwindAttribute)
405-
}
406-
407-
// Tell LLVM to emit the information necessary to unwind the stack for the
408-
// function f.
409-
pub fn set_uwtable(f: ValueRef) {
410-
llvm::SetFunctionAttribute(f, llvm::UWTableAttribute)
411-
}
412-
413-
pub fn set_inline_hint(f: ValueRef) {
414-
llvm::SetFunctionAttribute(f, llvm::InlineHintAttribute)
415-
}
416-
417-
pub fn set_llvm_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRef) {
418-
use syntax::attr::{find_inline_attr, InlineAttr};
419-
// Set the inline hint if there is one
420-
match find_inline_attr(Some(ccx.sess().diagnostic()), attrs) {
421-
InlineAttr::Hint => set_inline_hint(llfn),
422-
InlineAttr::Always => set_always_inline(llfn),
423-
InlineAttr::Never => set_no_inline(llfn),
424-
InlineAttr::None => { /* fallthrough */ }
425-
}
426-
427-
for attr in attrs {
428-
let mut used = true;
429-
match &attr.name()[..] {
430-
"no_stack_check" => unset_split_stack(llfn),
431-
"cold" => unsafe {
432-
llvm::LLVMAddFunctionAttribute(llfn,
433-
llvm::FunctionIndex as c_uint,
434-
llvm::ColdAttribute as uint64_t)
435-
},
436-
"allocator" => {
437-
llvm::NoAliasAttribute.apply_llfn(llvm::ReturnIndex as c_uint, llfn);
438-
}
439-
_ => used = false,
440-
}
441-
if used {
442-
attr::mark_used(attr);
443-
}
444-
}
445-
}
446-
447-
pub fn set_always_inline(f: ValueRef) {
448-
llvm::SetFunctionAttribute(f, llvm::AlwaysInlineAttribute)
449-
}
450-
451-
pub fn set_split_stack(f: ValueRef) {
452-
unsafe {
453-
llvm::LLVMAddFunctionAttrString(f, llvm::FunctionIndex as c_uint,
454-
"split-stack\0".as_ptr() as *const _);
455-
}
456-
}
457-
458-
pub fn unset_split_stack(f: ValueRef) {
459-
unsafe {
460-
llvm::LLVMRemoveFunctionAttrString(f, llvm::FunctionIndex as c_uint,
461-
"split-stack\0".as_ptr() as *const _);
462-
}
463-
}
464393

465394
// Double-check that we never ask LLVM to declare the same symbol twice. It
466395
// silently mangles such symbols, breaking our linkage model.
@@ -898,7 +827,7 @@ pub fn trans_external_path<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
898827
_ => {
899828
let llfn = foreign::register_foreign_item_fn(ccx, fn_ty.abi, t, &name[..]);
900829
let attrs = csearch::get_item_attrs(&ccx.sess().cstore, did);
901-
set_llvm_fn_attrs(ccx, &attrs, llfn);
830+
attributes::convert_fn_attrs_to_llvm(ccx, &attrs, llfn);
902831
llfn
903832
}
904833
}
@@ -1708,7 +1637,7 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
17081637
ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1);
17091638

17101639
let _icx = push_ctxt("trans_closure");
1711-
set_uwtable(llfndecl);
1640+
attributes::emit_uwtable(llfndecl, true);
17121641

17131642
debug!("trans_closure(..., param_substs={})",
17141643
param_substs.repr(ccx.tcx()));
@@ -2312,7 +2241,7 @@ fn finish_register_fn(ccx: &CrateContext, sp: Span, sym: String, node_id: ast::N
23122241
// eh_personality functions need to be externally linkable.
23132242
let def = ast_util::local_def(node_id);
23142243
if ccx.tcx().lang_items.stack_exhausted() == Some(def) {
2315-
unset_split_stack(llfn);
2244+
attributes::split_stack(llfn, false);
23162245
llvm::SetLinkage(llfn, llvm::ExternalLinkage);
23172246
}
23182247
if ccx.tcx().lang_items.eh_personality() == Some(def) {
@@ -2733,7 +2662,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
27332662
sym,
27342663
i.id)
27352664
};
2736-
set_llvm_fn_attrs(ccx, &i.attrs, llfn);
2665+
attributes::convert_fn_attrs_to_llvm(ccx, &i.attrs, llfn);
27372666
llfn
27382667
}
27392668

@@ -2794,7 +2723,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
27942723
let ty = ty::node_id_to_type(ccx.tcx(), ni.id);
27952724
let name = foreign::link_name(&*ni);
27962725
let llfn = foreign::register_foreign_item_fn(ccx, abi, ty, &name);
2797-
set_llvm_fn_attrs(ccx, &ni.attrs, llfn);
2726+
attributes::convert_fn_attrs_to_llvm(ccx, &ni.attrs, llfn);
27982727
llfn
27992728
}
28002729
ast::ForeignItemStatic(..) => {
@@ -2826,7 +2755,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
28262755
}
28272756
_ => ccx.sess().bug("NodeVariant, shouldn't happen")
28282757
};
2829-
set_inline_hint(llfn);
2758+
attributes::inline(llfn, attributes::InlineHint);
28302759
llfn
28312760
}
28322761

@@ -2848,7 +2777,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
28482777
&struct_item.attrs);
28492778
let llfn = register_fn(ccx, struct_item.span,
28502779
sym, ctor_id, ty);
2851-
set_inline_hint(llfn);
2780+
attributes::inline(llfn, attributes::InlineHint);
28522781
llfn
28532782
}
28542783

@@ -2883,7 +2812,7 @@ fn register_method(ccx: &CrateContext, id: ast::NodeId,
28832812
} else {
28842813
foreign::register_rust_fn_with_foreign_abi(ccx, span, sym, id)
28852814
};
2886-
set_llvm_fn_attrs(ccx, &attrs, llfn);
2815+
attributes::convert_fn_attrs_to_llvm(ccx, &attrs, llfn);
28872816
return llfn;
28882817
} else {
28892818
ccx.sess().span_bug(span, "expected bare rust function");

src/librustc_trans/trans/closure.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use back::link::{self, mangle_internal_name_by_path_and_seq};
1313
use llvm::{ValueRef, get_param};
1414
use middle::mem_categorization::Typer;
1515
use trans::adt;
16+
use trans::attributes;
1617
use trans::base::*;
1718
use trans::build::*;
1819
use trans::callee::{self, ArgVals, Callee, TraitItem, MethodData};
@@ -164,7 +165,7 @@ pub fn get_or_create_declaration_if_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tc
164165
let llfn = decl_internal_rust_fn(ccx, function_type, &symbol[..]);
165166

166167
// set an inline hint for all closures
167-
set_inline_hint(llfn);
168+
attributes::inline(llfn, attributes::InlineHint);
168169

169170
debug!("get_or_create_declaration_if_closure(): inserting new \
170171
closure {:?} (type {})",

src/librustc_trans/trans/foreign.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use back::link;
1313
use llvm::{ValueRef, CallConv, get_param};
1414
use llvm;
1515
use middle::weak_lang_items;
16+
use trans::attributes;
1617
use trans::base::{llvm_linkage_by_name, push_ctxt};
1718
use trans::base;
1819
use trans::build::*;
@@ -612,7 +613,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
612613
id, t.repr(tcx));
613614

614615
let llfn = base::decl_internal_rust_fn(ccx, t, &ps[..]);
615-
base::set_llvm_fn_attrs(ccx, attrs, llfn);
616+
attributes::convert_fn_attrs_to_llvm(ccx, attrs, llfn);
616617
base::trans_fn(ccx, decl, body, llfn, param_substs, id, &[]);
617618
llfn
618619
}

0 commit comments

Comments
 (0)