From 500d29b589a608357c1b82e4203dc1b77454c78c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Sat, 15 Feb 2014 21:31:20 +0100 Subject: [PATCH] Declare by-value on-stack parameters to be noalias Function parameters that are to be passed by value but don't fit into a single register are currently passed by creating a copy on the stack and passing a pointer to that copy to the callee. Since the copy is made just for the function call, there are no aliases. For example, this sometimes allows LLVM to eliminate unnecessary calls to drop glue. Given ````rust struct Foo { a: int, b: Option<~str>, } extern { fn eat(eat: Option<~str>); } pub fn foo(v: Foo) { match v { Foo { a: _, b } => unsafe { eat(b) } } } ```` LLVM currently can't eliminate the drop call for the string, because it only sees a _pointer_ to Foo, for which it has to expect an alias. So we get: ````llvm ; Function Attrs: uwtable define void @_ZN3foo20h9f32c90ae7201edbxaa4v0.0E(%struct.Foo* nocapture) unnamed_addr #0 { "_ZN34std..option..Option$LT$$UP$str$GT$9glue_drop17hc39b3015f3b9c69dE.exit": %1 = getelementptr inbounds %struct.Foo* %0, i64 0, i32 1, i32 0 %2 = load { i64, i64, [0 x i8] }** %1, align 8 store { i64, i64, [0 x i8] }* null, { i64, i64, [0 x i8] }** %1, align 8 %3 = ptrtoint { i64, i64, [0 x i8] }* %2 to i64 %.fca.0.insert = insertvalue { i64 } undef, i64 %3, 0 tail call void @eat({ i64 } %.fca.0.insert) %4 = load { i64, i64, [0 x i8] }** %1, align 8 %5 = icmp eq { i64, i64, [0 x i8] }* %4, null br i1 %5, label %_ZN3Foo9glue_drop17hf611996539d3036fE.exit, label %"_ZN8_$UP$str9glue_drop17h15dbdbe2b8897a98E.exit.i.i" "_ZN8_$UP$str9glue_drop17h15dbdbe2b8897a98E.exit.i.i": ; preds = %"_ZN34std..option..Option$LT$$UP$str$GT$9glue_drop17hc39b3015f3b9c69dE.exit" %6 = bitcast { i64, i64, [0 x i8] }* %4 to i8* tail call void @free(i8* %6) #1 br label %_ZN3Foo9glue_drop17hf611996539d3036fE.exit _ZN3Foo9glue_drop17hf611996539d3036fE.exit: ; preds = %"_ZN34std..option..Option$LT$$UP$str$GT$9glue_drop17hc39b3015f3b9c69dE.exit", %"_ZN8_$UP$str9glue_drop17h15dbdbe2b8897a98E.exit.i.i" ret void } ```` But with the `noalias` attribute, it can safely optimize that to: ````llvm define void @_ZN3foo20hd28431f929f0d6c4xaa4v0.0E(%struct.Foo* noalias nocapture) unnamed_addr #0 { _ZN3Foo9glue_drop17he9afbc09d4e9c851E.exit: %1 = getelementptr inbounds %struct.Foo* %0, i64 0, i32 1, i32 0 %2 = load { i64, i64, [0 x i8] }** %1, align 8 store { i64, i64, [0 x i8] }* null, { i64, i64, [0 x i8] }** %1, align 8 %3 = ptrtoint { i64, i64, [0 x i8] }* %2 to i64 %.fca.0.insert = insertvalue { i64 } undef, i64 %3, 0 tail call void @eat({ i64 } %.fca.0.insert) ret void } ```` --- src/librustc/middle/trans/base.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 69e7dd9f7fb2..dc8e786fba24 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -273,7 +273,15 @@ pub fn decl_rust_fn(ccx: &CrateContext, has_env: bool, llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint); } } - _ => {} + _ => { + // For non-immediate arguments the callee gets its own copy of + // the value on the stack, so there are no aliases + if !type_is_immediate(ccx, arg_ty) { + unsafe { + llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint); + } + } + } } }