1
Fork 0

Implement an address_insignificant attribute

This can be applied to statics and it will indicate that LLVM will attempt to
merge the constant in .data with other statics.

I have preliminarily applied this to all of the statics generated by the new
`ifmt!` syntax extension. I compiled a file with 1000 calls to `ifmt!` and a
separate file with 1000 calls to `fmt!` to compare the sizes, and the results
were:

fmt           310k
ifmt (before) 529k
ifmt (after)  202k

This now means that ifmt! is both faster and smaller than fmt!, yay!
This commit is contained in:
Alex Crichton 2013-08-09 13:47:00 -07:00
parent 74efdf6197
commit 2f3fde60c3
5 changed files with 47 additions and 16 deletions

View file

@ -2080,6 +2080,9 @@ pub mod llvm {
Elements: ValueRef,
RunTimeLang: c_uint)
-> ValueRef;
#[fast_ffi]
pub fn LLVMSetUnnamedAddr(GlobalVar: ValueRef, UnnamedAddr: Bool);
}
}
@ -2099,6 +2102,12 @@ pub fn SetLinkage(Global: ValueRef, Link: Linkage) {
}
}
pub fn SetUnnamedAddr(Global: ValueRef, Unnamed: bool) {
unsafe {
llvm::LLVMSetUnnamedAddr(Global, Unnamed as Bool);
}
}
pub fn ConstICmp(Pred: IntPredicate, V1: ValueRef, V2: ValueRef) -> ValueRef {
unsafe {
llvm::LLVMConstICmp(Pred as c_ushort, V1, V2)

View file

@ -2159,19 +2159,18 @@ pub fn trans_item(ccx: @mut CrateContext, item: &ast::item) {
}
ast::item_static(_, m, expr) => {
consts::trans_const(ccx, m, item.id);
// Do static_assert checking. It can't really be done much earlier because we need to get
// the value of the bool out of LLVM
for attr in item.attrs.iter() {
if "static_assert" == attr.name() {
if m == ast::m_mutbl {
ccx.sess.span_fatal(expr.span,
"cannot have static_assert on a mutable static");
}
let v = ccx.const_values.get_copy(&item.id);
unsafe {
if !(llvm::LLVMConstIntGetZExtValue(v) as bool) {
ccx.sess.span_fatal(expr.span, "static assertion failed");
}
// Do static_assert checking. It can't really be done much earlier
// because we need to get the value of the bool out of LLVM
if attr::contains_name(item.attrs, "static_assert") {
if m == ast::m_mutbl {
ccx.sess.span_fatal(expr.span,
"cannot have static_assert on a mutable \
static");
}
let v = ccx.const_values.get_copy(&item.id);
unsafe {
if !(llvm::LLVMConstIntGetZExtValue(v) as bool) {
ccx.sess.span_fatal(expr.span, "static assertion failed");
}
}
}
@ -2432,6 +2431,15 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::NodeId) -> ValueRef {
llvm::LLVMAddGlobal(ccx.llmod, llty, buf)
};
// Apply the `unnamed_addr` attribute if
// requested
if attr::contains_name(i.attrs,
"address_insignificant"){
lib::llvm::SetUnnamedAddr(g, true);
lib::llvm::SetLinkage(g,
lib::llvm::InternalLinkage);
}
ccx.item_symbols.insert(i.id, sym);
g
}

View file

@ -429,7 +429,12 @@ impl Context {
let st = ast::item_static(ty, ast::m_imm, method);
let static_name = self.ecx.ident_of(fmt!("__static_method_%u",
self.method_statics.len()));
let item = self.ecx.item(sp, static_name, ~[], st);
// Flag these statics as `address_insignificant` so LLVM can
// merge duplicate globals as much as possible (which we're
// generating a whole lot of).
let unnamed = self.ecx.meta_word(self.fmtsp, @"address_insignificant");
let unnamed = self.ecx.attribute(self.fmtsp, unnamed);
let item = self.ecx.item(sp, static_name, ~[unnamed], st);
self.method_statics.push(item);
self.ecx.expr_ident(sp, static_name)
};
@ -550,7 +555,10 @@ impl Context {
let ty = self.ecx.ty(self.fmtsp, ty);
let st = ast::item_static(ty, ast::m_imm, fmt);
let static_name = self.ecx.ident_of("__static_fmtstr");
let item = self.ecx.item(self.fmtsp, static_name, ~[], st);
// see above comment for `address_insignificant` and why we do it
let unnamed = self.ecx.meta_word(self.fmtsp, @"address_insignificant");
let unnamed = self.ecx.attribute(self.fmtsp, unnamed);
let item = self.ecx.item(self.fmtsp, static_name, ~[unnamed], st);
let decl = respan(self.fmtsp, ast::decl_item(item));
lets.push(@respan(self.fmtsp, ast::stmt_decl(@decl, self.ecx.next_id())));
@ -613,6 +621,7 @@ impl Context {
if ty == Unknown {
ty = Known(@"?");
}
let argptr = self.ecx.expr_addr_of(sp, self.ecx.expr_ident(sp, ident));
match ty {
Known(tyname) => {
@ -685,7 +694,7 @@ pub fn expand_syntax_ext(ecx: @ExtCtxt, sp: span,
};
cx.fmtsp = efmt.span;
let fmt = expr_to_str(ecx, efmt,
~"first argument to ifmt! must be a string literal.");
"first argument to ifmt! must be a string literal.");
let mut err = false;
do parse::parse_error::cond.trap(|m| {

View file

@ -833,3 +833,7 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateUnionType(
unwrapDI<DIArray>(Elements),
RunTimeLang));
}
extern "C" void LLVMSetUnnamedAddr(LLVMValueRef Value, LLVMBool Unnamed) {
unwrap<GlobalValue>(Value)->setUnnamedAddr(Unnamed);
}

View file

@ -613,3 +613,4 @@ LLVMDIBuilderInsertDeclareBefore
LLVMDIBuilderCreateEnumerator
LLVMDIBuilderCreateEnumerationType
LLVMDIBuilderCreateUnionType
LLVMSetUnnamedAddr