diff options
| author | bors <bors@rust-lang.org> | 2013-02-20 16:58:34 -0800 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2013-02-20 16:58:34 -0800 |
| commit | 8f8f0ec2c6761b096eea1f8dceb42c2618f5a196 (patch) | |
| tree | 34ff06ab322c6cd89332b3b1dd4b5e3270e9ac4f | |
| parent | 62f2b4943a223ff7dc168d8fed5ebc50f34150db (diff) | |
| parent | 423843e54bdbd6e32a0a75b7502904458e20c480 (diff) | |
| download | rust-8f8f0ec2c6761b096eea1f8dceb42c2618f5a196.tar.gz rust-8f8f0ec2c6761b096eea1f8dceb42c2618f5a196.zip | |
auto merge of #5043 : brson/rust/swap, r=brson
r?
| -rw-r--r-- | src/librustc/middle/trans/expr.rs | 26 | ||||
| -rw-r--r-- | src/test/run-pass/swap-overlapping.rs | 45 |
2 files changed, 67 insertions, 4 deletions
diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 6af6adbf68d..5b57ccc9ad4 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -491,11 +491,29 @@ fn trans_rvalue_stmt_unadjusted(bcx: block, expr: @ast::expr) -> block { ast::expr_swap(dst, src) => { let dst_datum = unpack_datum!(bcx, trans_lvalue(bcx, dst)); let src_datum = unpack_datum!(bcx, trans_lvalue(bcx, src)); - let scratch = scratch_datum(bcx, dst_datum.ty, false); - let bcx = dst_datum.move_to_datum(bcx, INIT, scratch); - let bcx = src_datum.move_to_datum(bcx, INIT, dst_datum); - return scratch.move_to_datum(bcx, INIT, src_datum); + // If the source and destination are the same, then don't swap. + // Avoids performing an overlapping memcpy + let dst_datum_ref = dst_datum.to_ref_llval(bcx); + let src_datum_ref = src_datum.to_ref_llval(bcx); + let cmp = ICmp(bcx, lib::llvm::IntEQ, + src_datum_ref, + dst_datum_ref); + + let swap_cx = base::sub_block(bcx, ~"swap"); + let next_cx = base::sub_block(bcx, ~"next"); + + CondBr(bcx, cmp, next_cx.llbb, swap_cx.llbb); + + let scratch = scratch_datum(swap_cx, dst_datum.ty, false); + + let swap_cx = dst_datum.move_to_datum(swap_cx, INIT, scratch); + let swap_cx = src_datum.move_to_datum(swap_cx, INIT, dst_datum); + let swap_cx = scratch.move_to_datum(swap_cx, INIT, src_datum); + + Br(swap_cx, next_cx.llbb); + + return next_cx; } ast::expr_assign_op(op, dst, src) => { return trans_assign_op(bcx, expr, op, dst, src); diff --git a/src/test/run-pass/swap-overlapping.rs b/src/test/run-pass/swap-overlapping.rs new file mode 100644 index 00000000000..90b2ceef71a --- /dev/null +++ b/src/test/run-pass/swap-overlapping.rs @@ -0,0 +1,45 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Issue #5041 - avoid overlapping memcpy when src and dest of a swap are the same + +pub fn main() { + let mut test = TestDescAndFn { + desc: TestDesc { + name: DynTestName(~"test"), + should_fail: false + }, + testfn: DynTestFn(|| ()), + }; + do_swap(&mut test); +} + +fn do_swap(test: &mut TestDescAndFn) { + *test <-> *test; +} + +pub enum TestName { + DynTestName(~str) +} + +pub enum TestFn { + DynTestFn(~fn()), + DynBenchFn(~fn(&mut int)) +} + +pub struct TestDesc { + name: TestName, + should_fail: bool +} + +pub struct TestDescAndFn { + desc: TestDesc, + testfn: TestFn, +} |
