diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index ae4687eac2fac..3eaa354c5e6da 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -157,7 +157,7 @@ bitflags! { #[derive(Copy, Clone)] pub enum OtherAttribute { // The following are not really exposed in - // the LLVM c api so instead to add these + // the LLVM C api so instead to add these // we call a wrapper function in RustWrapper // that uses the C++ api. SanitizeAddressAttribute = 1 << 32, @@ -958,6 +958,7 @@ extern { pub fn LLVMAddFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char); pub fn LLVMRemoveFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char); pub fn LLVMGetFunctionAttr(Fn: ValueRef) -> c_ulonglong; + pub fn LLVMRemoveFunctionAttr(Fn: ValueRef, val: c_ulonglong); /* Operations on parameters */ pub fn LLVMCountParams(Fn: ValueRef) -> c_uint; diff --git a/src/librustc_trans/trans/attributes.rs b/src/librustc_trans/trans/attributes.rs new file mode 100644 index 0000000000000..76034420e4b97 --- /dev/null +++ b/src/librustc_trans/trans/attributes.rs @@ -0,0 +1,108 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +//! Set and unset common attributes on LLVM values. + +use llvm::{self, ValueRef, AttrHelper}; +use syntax::ast; +use syntax::attr::InlineAttr; +pub use syntax::attr::InlineAttr::*; +use trans::context::CrateContext; + +use libc::{c_uint, c_ulonglong}; + +/// Mark LLVM function to use split stack. +#[inline] +pub fn split_stack(val: ValueRef, set: bool) { + unsafe { + let attr = "split-stack\0".as_ptr() as *const _; + if set { + llvm::LLVMAddFunctionAttrString(val, llvm::FunctionIndex as c_uint, attr); + } else { + llvm::LLVMRemoveFunctionAttrString(val, llvm::FunctionIndex as c_uint, attr); + } + } +} + +/// Mark LLVM function to use provided inline heuristic. +#[inline] +pub fn inline(val: ValueRef, inline: InlineAttr) { + match inline { + InlineHint => llvm::SetFunctionAttribute(val, llvm::InlineHintAttribute), + InlineAlways => llvm::SetFunctionAttribute(val, llvm::AlwaysInlineAttribute), + InlineNever => llvm::SetFunctionAttribute(val, llvm::NoInlineAttribute), + InlineNone => { + let attr = llvm::InlineHintAttribute | + llvm::AlwaysInlineAttribute | + llvm::NoInlineAttribute; + unsafe { + llvm::LLVMRemoveFunctionAttr(val, attr.bits() as c_ulonglong) + } + }, + }; +} + +/// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function. +#[inline] +pub fn emit_uwtable(val: ValueRef, emit: bool) { + if emit { + llvm::SetFunctionAttribute(val, llvm::UWTableAttribute); + } else { + unsafe { + llvm::LLVMRemoveFunctionAttr(val, llvm::UWTableAttribute.bits() as c_ulonglong); + } + } +} + +/// Tell LLVM whether the function can or cannot unwind. +#[inline] +#[allow(dead_code)] // possibly useful function +pub fn unwind(val: ValueRef, can_unwind: bool) { + if can_unwind { + unsafe { + llvm::LLVMRemoveFunctionAttr(val, llvm::NoUnwindAttribute.bits() as c_ulonglong); + } + } else { + llvm::SetFunctionAttribute(val, llvm::NoUnwindAttribute); + } +} + +/// Tell LLVM whether it should optimise function for size. +#[inline] +#[allow(dead_code)] // possibly useful function +pub fn set_optimize_for_size(val: ValueRef, optimize: bool) { + if optimize { + llvm::SetFunctionAttribute(val, llvm::OptimizeForSizeAttribute); + } else { + unsafe { + llvm::LLVMRemoveFunctionAttr(val, llvm::OptimizeForSizeAttribute.bits() as c_ulonglong); + } + } +} + +/// Composite function which sets LLVM attributes for function depending on its AST (#[attribute]) +/// attributes. +pub fn convert_fn_attrs_to_llvm(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRef) { + use syntax::attr::*; + inline(llfn, find_inline_attr(Some(ccx.sess().diagnostic()), attrs)); + + for attr in attrs { + if attr.check_name("no_stack_check") { + split_stack(llfn, false); + } else if attr.check_name("cold") { + unsafe { + llvm::LLVMAddFunctionAttribute(llfn, + llvm::FunctionIndex as c_uint, + llvm::ColdAttribute as u64) + } + } else if attr.check_name("allocator") { + llvm::NoAliasAttribute.apply_llfn(llvm::ReturnIndex as c_uint, llfn); + } + } +} diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 321cd33bbeb2f..25750b6ec0e14 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -1,4 +1,4 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -7,21 +7,20 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. - -// trans.rs: Translate the completed AST to the LLVM IR. -// -// Some functions here, such as trans_block and trans_expr, return a value -- -// the result of the translation to LLVM -- while others, such as trans_fn, -// trans_impl, and trans_item, are called only for the side effect of adding a -// particular definition to the LLVM IR output we're producing. -// -// Hopefully useful general knowledge about trans: -// -// * There's no way to find out the Ty type of a ValueRef. Doing so -// would be "trying to get the eggs out of an omelette" (credit: -// pcwalton). You can, instead, find out its TypeRef by calling val_ty, -// but one TypeRef corresponds to many `Ty`s; for instance, tup(int, int, -// int) and rec(x=int, y=int, z=int) will have the same TypeRef. +//! Translate the completed AST to the LLVM IR. +//! +//! Some functions here, such as trans_block and trans_expr, return a value -- +//! the result of the translation to LLVM -- while others, such as trans_fn, +//! trans_impl, and trans_item, are called only for the side effect of adding a +//! particular definition to the LLVM IR output we're producing. +//! +//! Hopefully useful general knowledge about trans: +//! +//! * There's no way to find out the Ty type of a ValueRef. Doing so +//! would be "trying to get the eggs out of an omelette" (credit: +//! pcwalton). You can, instead, find out its TypeRef by calling val_ty, +//! but one TypeRef corresponds to many `Ty`s; for instance, tup(int, int, +//! int) and rec(x=int, y=int, z=int) will have the same TypeRef. #![allow(non_camel_case_types)] @@ -33,7 +32,7 @@ use super::ModuleTranslation; use back::link::mangle_exported_name; use back::{link, abi}; use lint; -use llvm::{AttrHelper, BasicBlockRef, Linkage, ValueRef, Vector, get_param}; +use llvm::{BasicBlockRef, Linkage, ValueRef, Vector, get_param}; use llvm; use metadata::{csearch, encoder, loader}; use middle::astencode; @@ -46,6 +45,7 @@ use session::config::{self, NoDebugInfo}; use session::Session; use trans::_match; use trans::adt; +use trans::attributes; use trans::build::*; use trans::builder::{Builder, noname}; use trans::callee; @@ -204,7 +204,7 @@ pub fn decl_fn(ccx: &CrateContext, name: &str, cc: llvm::CallConv, llvm::SetUnnamedAddr(llfn, true); if ccx.is_split_stack_supported() && !ccx.sess().opts.cg.no_stack_check { - set_split_stack(llfn); + attributes::split_stack(llfn, true); } llfn @@ -245,7 +245,7 @@ fn get_extern_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<'tcx>, let f = decl_rust_fn(ccx, fn_ty, name); let attrs = csearch::get_item_attrs(&ccx.sess().cstore, did); - set_llvm_fn_attrs(ccx, &attrs[..], f); + attributes::convert_fn_attrs_to_llvm(ccx, &attrs[..], f); ccx.externs().borrow_mut().insert(name.to_string(), f); f @@ -390,77 +390,6 @@ pub fn malloc_raw_dyn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, Result::new(r.bcx, PointerCast(r.bcx, r.val, llty_ptr)) } -#[allow(dead_code)] // useful -pub fn set_optimize_for_size(f: ValueRef) { - llvm::SetFunctionAttribute(f, llvm::OptimizeForSizeAttribute) -} - -pub fn set_no_inline(f: ValueRef) { - llvm::SetFunctionAttribute(f, llvm::NoInlineAttribute) -} - -#[allow(dead_code)] // useful -pub fn set_no_unwind(f: ValueRef) { - llvm::SetFunctionAttribute(f, llvm::NoUnwindAttribute) -} - -// Tell LLVM to emit the information necessary to unwind the stack for the -// function f. -pub fn set_uwtable(f: ValueRef) { - llvm::SetFunctionAttribute(f, llvm::UWTableAttribute) -} - -pub fn set_inline_hint(f: ValueRef) { - llvm::SetFunctionAttribute(f, llvm::InlineHintAttribute) -} - -pub fn set_llvm_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRef) { - use syntax::attr::{find_inline_attr, InlineAttr}; - // Set the inline hint if there is one - match find_inline_attr(Some(ccx.sess().diagnostic()), attrs) { - InlineAttr::Hint => set_inline_hint(llfn), - InlineAttr::Always => set_always_inline(llfn), - InlineAttr::Never => set_no_inline(llfn), - InlineAttr::None => { /* fallthrough */ } - } - - for attr in attrs { - let mut used = true; - match &attr.name()[..] { - "no_stack_check" => unset_split_stack(llfn), - "cold" => unsafe { - llvm::LLVMAddFunctionAttribute(llfn, - llvm::FunctionIndex as c_uint, - llvm::ColdAttribute as uint64_t) - }, - "allocator" => { - llvm::NoAliasAttribute.apply_llfn(llvm::ReturnIndex as c_uint, llfn); - } - _ => used = false, - } - if used { - attr::mark_used(attr); - } - } -} - -pub fn set_always_inline(f: ValueRef) { - llvm::SetFunctionAttribute(f, llvm::AlwaysInlineAttribute) -} - -pub fn set_split_stack(f: ValueRef) { - unsafe { - llvm::LLVMAddFunctionAttrString(f, llvm::FunctionIndex as c_uint, - "split-stack\0".as_ptr() as *const _); - } -} - -pub fn unset_split_stack(f: ValueRef) { - unsafe { - llvm::LLVMRemoveFunctionAttrString(f, llvm::FunctionIndex as c_uint, - "split-stack\0".as_ptr() as *const _); - } -} // Double-check that we never ask LLVM to declare the same symbol twice. It // silently mangles such symbols, breaking our linkage model. @@ -898,7 +827,7 @@ pub fn trans_external_path<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, _ => { let llfn = foreign::register_foreign_item_fn(ccx, fn_ty.abi, t, &name[..]); let attrs = csearch::get_item_attrs(&ccx.sess().cstore, did); - set_llvm_fn_attrs(ccx, &attrs, llfn); + attributes::convert_fn_attrs_to_llvm(ccx, &attrs, llfn); llfn } } @@ -1708,7 +1637,7 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1); let _icx = push_ctxt("trans_closure"); - set_uwtable(llfndecl); + attributes::emit_uwtable(llfndecl, true); debug!("trans_closure(..., param_substs={})", param_substs.repr(ccx.tcx())); @@ -2312,7 +2241,7 @@ fn finish_register_fn(ccx: &CrateContext, sp: Span, sym: String, node_id: ast::N // eh_personality functions need to be externally linkable. let def = ast_util::local_def(node_id); if ccx.tcx().lang_items.stack_exhausted() == Some(def) { - unset_split_stack(llfn); + attributes::split_stack(llfn, false); llvm::SetLinkage(llfn, llvm::ExternalLinkage); } if ccx.tcx().lang_items.eh_personality() == Some(def) { @@ -2733,7 +2662,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { sym, i.id) }; - set_llvm_fn_attrs(ccx, &i.attrs, llfn); + attributes::convert_fn_attrs_to_llvm(ccx, &i.attrs, llfn); llfn } @@ -2794,7 +2723,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { let ty = ty::node_id_to_type(ccx.tcx(), ni.id); let name = foreign::link_name(&*ni); let llfn = foreign::register_foreign_item_fn(ccx, abi, ty, &name); - set_llvm_fn_attrs(ccx, &ni.attrs, llfn); + attributes::convert_fn_attrs_to_llvm(ccx, &ni.attrs, llfn); llfn } ast::ForeignItemStatic(..) => { @@ -2826,7 +2755,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { } _ => ccx.sess().bug("NodeVariant, shouldn't happen") }; - set_inline_hint(llfn); + attributes::inline(llfn, attributes::InlineHint); llfn } @@ -2848,7 +2777,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { &struct_item.attrs); let llfn = register_fn(ccx, struct_item.span, sym, ctor_id, ty); - set_inline_hint(llfn); + attributes::inline(llfn, attributes::InlineHint); llfn } @@ -2883,7 +2812,7 @@ fn register_method(ccx: &CrateContext, id: ast::NodeId, } else { foreign::register_rust_fn_with_foreign_abi(ccx, span, sym, id) }; - set_llvm_fn_attrs(ccx, &attrs, llfn); + attributes::convert_fn_attrs_to_llvm(ccx, &attrs, llfn); return llfn; } else { ccx.sess().span_bug(span, "expected bare rust function"); diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index c1aade3663e6e..e83ac8a5e0c9c 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -13,6 +13,7 @@ use back::link::{self, mangle_internal_name_by_path_and_seq}; use llvm::{ValueRef, get_param}; use middle::mem_categorization::Typer; use trans::adt; +use trans::attributes; use trans::base::*; use trans::build::*; 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 let llfn = decl_internal_rust_fn(ccx, function_type, &symbol[..]); // set an inline hint for all closures - set_inline_hint(llfn); + attributes::inline(llfn, attributes::InlineHint); debug!("get_or_create_declaration_if_closure(): inserting new \ closure {:?} (type {})", diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index e154bc1d579ff..ce80c72b84785 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -13,6 +13,7 @@ use back::link; use llvm::{ValueRef, CallConv, get_param}; use llvm; use middle::weak_lang_items; +use trans::attributes; use trans::base::{llvm_linkage_by_name, push_ctxt}; use trans::base; use trans::build::*; @@ -612,7 +613,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, id, t.repr(tcx)); let llfn = base::decl_internal_rust_fn(ccx, t, &ps[..]); - base::set_llvm_fn_attrs(ccx, attrs, llfn); + attributes::convert_fn_attrs_to_llvm(ccx, attrs, llfn); base::trans_fn(ccx, decl, body, llfn, param_substs, id, &[]); llfn } diff --git a/src/librustc_trans/trans/mod.rs b/src/librustc_trans/trans/mod.rs index c7857d6a775f3..0face6860dce5 100644 --- a/src/librustc_trans/trans/mod.rs +++ b/src/librustc_trans/trans/mod.rs @@ -19,43 +19,44 @@ pub use self::common::gensym_name; #[macro_use] mod macros; -mod inline; -mod monomorphize; -mod controlflow; -mod glue; -mod datum; -mod callee; -mod expr; -mod common; -mod context; -mod consts; -mod type_of; +mod adt; +mod asm; +mod attributes; +mod base; +mod basic_block; mod build; mod builder; -mod base; -mod _match; -mod closure; -mod tvec; -mod meth; mod cabi; -mod cabi_x86; -mod cabi_x86_64; -mod cabi_x86_win64; -mod cabi_arm; mod cabi_aarch64; +mod cabi_arm; mod cabi_mips; mod cabi_powerpc; +mod cabi_x86; +mod cabi_x86_64; +mod cabi_x86_win64; +mod callee; +mod cleanup; +mod closure; +mod common; +mod consts; +mod context; +mod controlflow; +mod datum; +mod debuginfo; +mod expr; mod foreign; +mod glue; +mod inline; mod intrinsic; -mod debuginfo; +mod llrepr; mod machine; -mod adt; -mod asm; +mod _match; +mod meth; +mod monomorphize; +mod tvec; mod type_; +mod type_of; mod value; -mod basic_block; -mod llrepr; -mod cleanup; #[derive(Copy, Clone)] pub struct ModuleTranslation { diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index dcb21c5cd93b1..fc08b1a107944 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -17,7 +17,7 @@ use middle::subst; use middle::subst::{Subst, Substs}; use middle::traits; use middle::ty_fold::{TypeFolder, TypeFoldable}; -use trans::base::{set_llvm_fn_attrs, set_inline_hint}; +use trans::attributes; use trans::base::{trans_enum_variant, push_ctxt, get_item_val}; use trans::base::{trans_fn, decl_internal_rust_fn}; use trans::base; @@ -151,7 +151,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, }; let setup_lldecl = |lldecl, attrs: &[ast::Attribute]| { base::update_linkage(ccx, lldecl, None, base::OriginalTranslation); - set_llvm_fn_attrs(ccx, attrs, lldecl); + attributes::convert_fn_attrs_to_llvm(ccx, attrs, lldecl); let is_first = !ccx.available_monomorphizations().borrow().contains(&s); if is_first { @@ -200,7 +200,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let tvs = ty::enum_variants(ccx.tcx(), local_def(parent)); let this_tv = tvs.iter().find(|tv| { tv.id.node == fn_id.node}).unwrap(); let d = mk_lldecl(abi::Rust); - set_inline_hint(d); + attributes::inline(d, attributes::InlineHint); match v.node.kind { ast::TupleVariantKind(ref args) => { trans_enum_variant(ccx, @@ -259,7 +259,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } ast_map::NodeStructCtor(struct_def) => { let d = mk_lldecl(abi::Rust); - set_inline_hint(d); + attributes::inline(d, attributes::InlineHint); base::trans_tuple_struct(ccx, &struct_def.fields, struct_def.ctor_id.expect("ast-mapped tuple struct \