From 541e5f84d7ccbf02f8fdab6da0ff92f7ffbf0866 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sun, 20 Oct 2013 23:13:48 -0400 Subject: [PATCH] add support for the `cold` function attribute This allows a function to marked as infrequently called, resulting in any branch calling it to be considered colder. --- src/librustc/lib/llvm.rs | 2 ++ src/librustc/middle/trans/base.rs | 18 ++++++++++++------ src/libstd/rt/borrowck.rs | 1 + src/libstd/unstable/lang.rs | 2 ++ src/rustllvm/RustWrapper.cpp | 5 +++++ src/rustllvm/rustllvm.def.in | 1 + 6 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index aa899239d8b..64c6678ec5f 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -693,6 +693,8 @@ pub mod llvm { pub fn LLVMAddReturnAttribute(Fn: ValueRef, PA: c_uint); pub fn LLVMRemoveReturnAttribute(Fn: ValueRef, PA: c_uint); + pub fn LLVMAddColdAttribute(Fn: ValueRef); + pub fn LLVMRemoveFunctionAttr(Fn: ValueRef, PA: c_ulonglong, HighPA: c_ulonglong); diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 74f9e2114e1..2f60b2bebce 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -202,19 +202,21 @@ pub fn get_extern_fn(externs: &mut ExternMap, llmod: ModuleRef, name: &str, f } -pub fn get_extern_rust_fn(ccx: &mut CrateContext, inputs: &[ty::t], output: ty::t, - name: &str) -> ValueRef { +fn get_extern_rust_fn(ccx: &mut CrateContext, inputs: &[ty::t], output: ty::t, + name: &str, did: ast::DefId) -> ValueRef { match ccx.externs.find_equiv(&name) { Some(n) => return *n, None => () } let f = decl_rust_fn(ccx, inputs, output, name); + do csearch::get_item_attrs(ccx.tcx.cstore, did) |meta_items| { + set_llvm_fn_attrs(meta_items.iter().map(|&x| attr::mk_attr(x)).to_owned_vec(), f) + } ccx.externs.insert(name.to_owned(), f); f } -pub fn decl_rust_fn(ccx: &mut CrateContext, inputs: &[ty::t], output: ty::t, - name: &str) -> ValueRef { +fn decl_rust_fn(ccx: &mut CrateContext, inputs: &[ty::t], output: ty::t, name: &str) -> ValueRef { let llfty = type_of_rust_fn(ccx, inputs, output); let llfn = decl_cdecl_fn(ccx.llmod, name, llfty); @@ -481,6 +483,10 @@ pub fn set_llvm_fn_attrs(attrs: &[ast::Attribute], llfn: ValueRef) { if contains_name(attrs, "no_split_stack") { set_no_split_stack(llfn); } + + if contains_name(attrs, "cold") { + unsafe { llvm::LLVMAddColdAttribute(llfn) } + } } pub fn set_always_inline(f: ValueRef) { @@ -840,7 +846,7 @@ pub fn trans_external_path(ccx: &mut CrateContext, did: ast::DefId, t: ty::t) -> ty::ty_bare_fn(ref fn_ty) => { match fn_ty.abis.for_arch(ccx.sess.targ_cfg.arch) { Some(Rust) | Some(RustIntrinsic) => { - get_extern_rust_fn(ccx, fn_ty.sig.inputs, fn_ty.sig.output, name) + get_extern_rust_fn(ccx, fn_ty.sig.inputs, fn_ty.sig.output, name, did) } Some(*) | None => { let c = foreign::llvm_calling_convention(ccx, fn_ty.abis); @@ -851,7 +857,7 @@ pub fn trans_external_path(ccx: &mut CrateContext, did: ast::DefId, t: ty::t) -> } } ty::ty_closure(ref f) => { - get_extern_rust_fn(ccx, f.sig.inputs, f.sig.output, name) + get_extern_rust_fn(ccx, f.sig.inputs, f.sig.output, name, did) } _ => { let llty = type_of(ccx, t); diff --git a/src/libstd/rt/borrowck.rs b/src/libstd/rt/borrowck.rs index 9d13e79464a..7fcd674009d 100644 --- a/src/libstd/rt/borrowck.rs +++ b/src/libstd/rt/borrowck.rs @@ -57,6 +57,7 @@ pub fn clear_task_borrow_list() { let _ = try_take_task_borrow_list(); } +#[cold] unsafe fn fail_borrowed(box: *mut raw::Box<()>, file: *c_char, line: size_t) -> ! { debug_borrow("fail_borrowed: ", box, 0, 0, file, line); diff --git a/src/libstd/unstable/lang.rs b/src/libstd/unstable/lang.rs index 6dfb319d592..89126bf9c9c 100644 --- a/src/libstd/unstable/lang.rs +++ b/src/libstd/unstable/lang.rs @@ -16,11 +16,13 @@ use libc::{c_char, size_t, uintptr_t}; use rt::task; use rt::borrowck; +#[cold] #[lang="fail_"] pub fn fail_(expr: *c_char, file: *c_char, line: size_t) -> ! { task::begin_unwind(expr, file, line); } +#[cold] #[lang="fail_bounds_check"] pub fn fail_bounds_check(file: *c_char, line: size_t, index: size_t, len: size_t) -> ! { let msg = format!("index out of bounds: the len is {} but the index is {}", diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index f8d56f4e892..0a148d334ab 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -365,6 +365,11 @@ extern "C" void LLVMRemoveReturnAttribute(LLVMValueRef Fn, LLVMAttribute PA) { AttributeSet::get(A->getContext(), AttributeSet::ReturnIndex, B)); } +extern "C" void LLVMAddColdAttribute(LLVMValueRef Fn) { + Function *A = unwrap(Fn); + A->addAttribute(AttributeSet::FunctionIndex, Attribute::Cold); +} + extern "C" LLVMValueRef LLVMBuildAtomicLoad(LLVMBuilderRef B, LLVMValueRef source, const char* Name, diff --git a/src/rustllvm/rustllvm.def.in b/src/rustllvm/rustllvm.def.in index c1f1444fb4f..a6b887f058a 100644 --- a/src/rustllvm/rustllvm.def.in +++ b/src/rustllvm/rustllvm.def.in @@ -629,3 +629,4 @@ LLVMRustAddAlwaysInlinePass LLVMAddReturnAttribute LLVMRemoveReturnAttribute LLVMTypeToString +LLVMAddColdAttribute