@@ -491,11 +491,29 @@ fn trans_rvalue_stmt_unadjusted(bcx: block, expr: @ast::expr) -> block {
491
491
ast:: expr_swap( dst, src) => {
492
492
let dst_datum = unpack_datum ! ( bcx, trans_lvalue( bcx, dst) ) ;
493
493
let src_datum = unpack_datum ! ( bcx, trans_lvalue( bcx, src) ) ;
494
- let scratch = scratch_datum ( bcx, dst_datum. ty , false ) ;
495
494
496
- let bcx = dst_datum. move_to_datum ( bcx, INIT , scratch) ;
497
- let bcx = src_datum. move_to_datum ( bcx, INIT , dst_datum) ;
498
- return scratch. move_to_datum ( bcx, INIT , src_datum) ;
495
+ // If the source and destination are the same, then don't swap.
496
+ // Avoids performing an overlapping memcpy
497
+ let dst_datum_ref = dst_datum. to_ref_llval ( bcx) ;
498
+ let src_datum_ref = src_datum. to_ref_llval ( bcx) ;
499
+ let cmp = ICmp ( bcx, lib:: llvm:: IntEQ ,
500
+ src_datum_ref,
501
+ dst_datum_ref) ;
502
+
503
+ let swap_cx = base:: sub_block ( bcx, ~"swap") ;
504
+ let next_cx = base:: sub_block ( bcx, ~"next") ;
505
+
506
+ CondBr ( bcx, cmp, next_cx. llbb , swap_cx. llbb ) ;
507
+
508
+ let scratch = scratch_datum ( swap_cx, dst_datum. ty , false ) ;
509
+
510
+ let swap_cx = dst_datum. move_to_datum ( swap_cx, INIT , scratch) ;
511
+ let swap_cx = src_datum. move_to_datum ( swap_cx, INIT , dst_datum) ;
512
+ let swap_cx = scratch. move_to_datum ( swap_cx, INIT , src_datum) ;
513
+
514
+ Br ( swap_cx, next_cx. llbb ) ;
515
+
516
+ return next_cx;
499
517
}
500
518
ast:: expr_assign_op( op, dst, src) => {
501
519
return trans_assign_op ( bcx, expr, op, dst, src) ;
0 commit comments