--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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);
+ }
+ }
+}
-// 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.
//
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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)]
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;
use session::Session;
use trans::_match;
use trans::adt;
+use trans::attributes;
use trans::build::*;
use trans::builder::{Builder, noname};
use trans::callee;
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
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
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.
_ => {
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
}
}
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()));
// 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) {
sym,
i.id)
};
- set_llvm_fn_attrs(ccx, &i.attrs, llfn);
+ attributes::convert_fn_attrs_to_llvm(ccx, &i.attrs, llfn);
llfn
}
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(..) => {
}
_ => ccx.sess().bug("NodeVariant, shouldn't happen")
};
- set_inline_hint(llfn);
+ attributes::inline(llfn, attributes::InlineHint);
llfn
}
&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
}
} 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");