Skip to content

Commit 4af28c9

Browse files
committed
auto merge of #12296 : dotdash/rust/byval_noalias, r=cmr
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 } ````
2 parents adea48a + 500d29b commit 4af28c9

File tree

1 file changed

+9
-1
lines changed

1 file changed

+9
-1
lines changed

src/librustc/middle/trans/base.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,15 @@ pub fn decl_rust_fn(ccx: &CrateContext, has_env: bool,
273273
llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint);
274274
}
275275
}
276-
_ => {}
276+
_ => {
277+
// For non-immediate arguments the callee gets its own copy of
278+
// the value on the stack, so there are no aliases
279+
if !type_is_immediate(ccx, arg_ty) {
280+
unsafe {
281+
llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint);
282+
}
283+
}
284+
}
277285
}
278286
}
279287

0 commit comments

Comments
 (0)