Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MIR: hide .rodata constants vs by-ref ABI clash in trans. #45996

Merged
merged 1 commit into from
Nov 17, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/librustc/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -684,9 +684,10 @@ pub enum TerminatorKind<'tcx> {
Call {
/// The function that’s being called
func: Operand<'tcx>,
/// Arguments the function is called with. These are owned by the callee, which is free to
/// modify them. This is important as "by-value" arguments might be passed by-reference at
/// the ABI level.
/// Arguments the function is called with.
/// These are owned by the callee, which is free to modify them.
/// This allows the memory occupied by "by-value" arguments to be
/// reused across function calls without duplicating the contents.
args: Vec<Operand<'tcx>>,
/// Destination for the return value. If some, the call is converging.
destination: Option<(Lvalue<'tcx>, BasicBlock)>,
Expand Down
8 changes: 1 addition & 7 deletions src/librustc_mir/build/expr/into.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,13 +247,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
} else {
let args: Vec<_> =
args.into_iter()
.map(|arg| {
let scope = this.local_scope();
// Function arguments are owned by the callee, so we need as_temp()
// instead of as_operand() to enforce copies
let operand = unpack!(block = this.as_temp(block, scope, arg));
Operand::Consume(Lvalue::Local(operand))
})
.map(|arg| unpack!(block = this.as_local_operand(block, arg)))
.collect();

let success = this.cfg.start_new_block();
Expand Down
11 changes: 10 additions & 1 deletion src/librustc_trans/mir/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,16 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
}
}

let op = self.trans_operand(&bcx, arg);
let mut op = self.trans_operand(&bcx, arg);

// The callee needs to own the argument memory if we pass it
// by-ref, so make a local copy of non-immediate constants.
if let (&mir::Operand::Constant(_), Ref(..)) = (arg, op.val) {
let tmp = LvalueRef::alloca(&bcx, op.ty, "const");
self.store_operand(&bcx, tmp.llval, tmp.alignment.to_align(), op);
op.val = Ref(tmp.llval, tmp.alignment);
}

self.trans_argument(&bcx, op, &mut llargs, &fn_ty,
&mut idx, &mut llfn, &def);
}
Expand Down
12 changes: 3 additions & 9 deletions src/test/mir-opt/nll/liveness-call-subtlety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,15 @@ fn main() {
// | Live variables at bb0[0]: []
// StorageLive(_1);
// | Live variables at bb0[1]: []
// StorageLive(_2);
// | Live variables at bb0[2]: []
// _2 = const 22usize;
// | Live variables at bb0[3]: [_2]
// _1 = const <std::boxed::Box<T>>::new(_2) -> bb1;
// _1 = const <std::boxed::Box<T>>::new(const 22usize) -> bb1;
// }
// END rustc.main.nll.0.mir
// START rustc.main.nll.0.mir
// | Live variables on entry to bb1: [_1 (drop)]
// bb1: {
// | Live variables at bb1[0]: [_1 (drop)]
// StorageDead(_2);
// StorageLive(_2);
// | Live variables at bb1[1]: [_1 (drop)]
// StorageLive(_3);
// | Live variables at bb1[2]: [_1 (drop)]
// _3 = const can_panic() -> [return: bb2, unwind: bb4];
// _2 = const can_panic() -> [return: bb2, unwind: bb4];
// }
// END rustc.main.nll.0.mir
2 changes: 1 addition & 1 deletion src/test/mir-opt/nll/region-liveness-drop-no-may-dangle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,5 @@ impl<T> Drop for Wrap<T> {

// END RUST SOURCE
// START rustc.main.nll.0.mir
// | '_#5r: {bb1[3], bb1[4], bb1[5], bb2[0], bb2[1], bb2[2], bb3[0], bb3[1], bb3[2], bb4[0], bb4[1], bb4[2], bb6[0], bb7[0], bb7[1], bb7[2], bb8[0]}
// | '_#5r: {bb1[3], bb1[4], bb1[5], bb2[0], bb2[1], bb2[2], bb3[0], bb4[0], bb4[1], bb4[2], bb6[0], bb7[0], bb7[1], bb8[0]}
// END rustc.main.nll.0.mir
2 changes: 1 addition & 1 deletion src/test/mir-opt/nll/region-liveness-two-disjoint-uses.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,5 @@ fn main() {
// ...
// _2 = &'_#1r _1[_3];
// ...
// _2 = &'_#3r (*_11);
// _2 = &'_#3r (*_10);
// END rustc.main.nll.0.mir
17 changes: 16 additions & 1 deletion src/test/run-pass/mir_trans_calls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(fn_traits)]
#![feature(fn_traits, test)]

extern crate test;

fn test1(a: isize, b: (i32, i32), c: &[i32]) -> (isize, (i32, i32), &[i32]) {
// Test passing a number of arguments including a fat pointer.
Expand Down Expand Up @@ -156,6 +158,16 @@ fn test_fn_nested_pair(x: &((f32, f32), u32)) -> (f32, f32) {
(z.0, z.1)
}

fn test_fn_const_arg_by_ref(mut a: [u64; 4]) -> u64 {
// Mutate the by-reference argument, which won't work with
// a non-immediate constant unless it's copied to the stack.
let a = test::black_box(&mut a);
a[0] += a[1];
a[0] += a[2];
a[0] += a[3];
a[0]
}

fn main() {
assert_eq!(test1(1, (2, 3), &[4, 5, 6]), (1, (2, 3), &[4, 5, 6][..]));
assert_eq!(test2(98), 98);
Expand All @@ -182,4 +194,7 @@ fn main() {
assert_eq!(test_fn_ignored_pair_0(), ());
assert_eq!(test_fn_ignored_pair_named(), (Foo, Foo));
assert_eq!(test_fn_nested_pair(&((1.0, 2.0), 0)), (1.0, 2.0));

const ARRAY: [u64; 4] = [1, 2, 3, 4];
assert_eq!(test_fn_const_arg_by_ref(ARRAY), 1 + 2 + 3 + 4);
}