From 423843e54bdbd6e32a0a75b7502904458e20c480 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 19 Feb 2013 16:12:12 -0800 Subject: [PATCH] Don't perform swap when src == dst. #5041 --- src/librustc/middle/trans/expr.rs | 26 +++++++++++++--- src/test/run-pass/swap-overlapping.rs | 45 +++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 4 deletions(-) create mode 100644 src/test/run-pass/swap-overlapping.rs diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 6af6adbf68dca..5b57ccc9ad430 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 0000000000000..90b2ceef71a76 --- /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 or the MIT license +// , 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, +}