@@ -3712,14 +3712,28 @@ fn join_results(&@block_ctxt parent_cx,
3712
3712
ret res( join_cx, phi) ;
3713
3713
}
3714
3714
3715
+ fn join_branches( & @block_ctxt parent_cx, & vec[ result] ins) -> @block_ctxt {
3716
+ auto out = new_sub_block_ctxt( parent_cx, "join") ;
3717
+ for ( result r in ins) {
3718
+ if ( !is_terminated( r. bcx) ) {
3719
+ r. bcx. build. Br ( out. llbb) ;
3720
+ }
3721
+ }
3722
+ ret out;
3723
+ }
3724
+
3725
+ tag out_method {
3726
+ return ;
3727
+ save_in( ValueRef ) ;
3728
+ }
3729
+
3715
3730
fn trans_if( & @block_ctxt cx, & @ast:: expr cond,
3716
3731
& ast:: block thn, & option:: t[ @ast:: expr] els,
3717
- & ast:: ann ann) -> result {
3718
-
3732
+ & ast:: ann ann, & out_method output) -> result {
3719
3733
auto cond_res = trans_expr( cx, cond) ;
3720
3734
3721
3735
auto then_cx = new_scope_block_ctxt( cx, "then") ;
3722
- auto then_res = trans_block( then_cx, thn) ;
3736
+ auto then_res = trans_block( then_cx, thn, output ) ;
3723
3737
3724
3738
auto else_cx = new_scope_block_ctxt( cx, "else ") ;
3725
3739
@@ -3739,14 +3753,14 @@ fn trans_if(&@block_ctxt cx, &@ast::expr cond,
3739
3753
a = ann) ;
3740
3754
auto elseif_blk = rec( node = elseif_blk_,
3741
3755
span = elexpr. span) ;
3742
- else_res = trans_block( else_cx, elseif_blk) ;
3756
+ else_res = trans_block( else_cx, elseif_blk, output ) ;
3743
3757
}
3744
3758
case ( ast:: expr_block( ?blk, _) ) {
3745
3759
// Calling trans_block directly instead of trans_expr
3746
3760
// because trans_expr will create another scope block
3747
3761
// context for the block, but we've already got the
3748
3762
// 'else' context
3749
- else_res = trans_block( else_cx, blk) ;
3763
+ else_res = trans_block( else_cx, blk, output ) ;
3750
3764
}
3751
3765
}
3752
3766
@@ -3771,9 +3785,7 @@ fn trans_if(&@block_ctxt cx, &@ast::expr cond,
3771
3785
cond_res. bcx. build. CondBr ( cond_res. val,
3772
3786
then_cx. llbb,
3773
3787
else_cx. llbb) ;
3774
-
3775
- ret join_results( cx, expr_llty,
3776
- [ then_res, else_res] ) ;
3788
+ ret res( join_branches( cx, [ then_res, else_res] ) , C_nil ( ) ) ;
3777
3789
}
3778
3790
3779
3791
fn trans_for( & @block_ctxt cx,
@@ -3795,7 +3807,7 @@ fn trans_for(&@block_ctxt cx,
3795
3807
auto bcx = copy_val( local_res. bcx, INIT , local_res. val, curr, t) . bcx;
3796
3808
scope_cx. cleanups +=
3797
3809
[ clean( bind drop_slot( _, local_res. val, t) ) ] ;
3798
- bcx = trans_block( bcx, body) . bcx;
3810
+ bcx = trans_block( bcx, body, return ) . bcx;
3799
3811
bcx. build. Br ( next_cx. llbb) ;
3800
3812
ret res( next_cx, C_nil ( ) ) ;
3801
3813
}
@@ -4053,7 +4065,7 @@ fn trans_for_each(&@block_ctxt cx,
4053
4065
4054
4066
auto bcx = new_top_block_ctxt ( fcx) ;
4055
4067
auto lltop = bcx. llbb ;
4056
- auto r = trans_block ( bcx, body) ;
4068
+ auto r = trans_block ( bcx, body, return ) ;
4057
4069
4058
4070
finish_fn ( fcx, lltop) ;
4059
4071
@@ -4099,7 +4111,7 @@ fn trans_while(&@block_ctxt cx, &@ast::expr cond,
4099
4111
auto body_cx = new_loop_scope_block_ctxt ( cx, option:: none[ @block_ctxt] ,
4100
4112
next_cx, "while loop body" ) ;
4101
4113
4102
- auto body_res = trans_block ( body_cx, body) ;
4114
+ auto body_res = trans_block ( body_cx, body, return ) ;
4103
4115
auto cond_res = trans_expr ( cond_cx, cond) ;
4104
4116
4105
4117
body_res. bcx . build . Br ( cond_cx. llbb ) ;
@@ -4118,7 +4130,7 @@ fn trans_do_while(&@block_ctxt cx, &ast::block body,
4118
4130
auto body_cx = new_loop_scope_block_ctxt ( cx, option:: none[ @block_ctxt] ,
4119
4131
next_cx, "do-while loop body" ) ;
4120
4132
4121
- auto body_res = trans_block ( body_cx, body) ;
4133
+ auto body_res = trans_block ( body_cx, body, return ) ;
4122
4134
auto cond_res = trans_expr ( body_res. bcx , cond) ;
4123
4135
4124
4136
cond_res. bcx . build . CondBr ( cond_res. val ,
@@ -4259,7 +4271,8 @@ fn trans_pat_binding(&@block_ctxt cx, &@ast::pat pat,
4259
4271
}
4260
4272
4261
4273
fn trans_alt( & @block_ctxt cx, & @ast:: expr expr,
4262
- & vec[ ast:: arm] arms, & ast:: ann ann) -> result {
4274
+ & vec[ ast:: arm] arms, & ast:: ann ann,
4275
+ & out_method output) -> result {
4263
4276
auto expr_res = trans_expr( cx, expr) ;
4264
4277
4265
4278
auto this_cx = expr_res. bcx;
@@ -4275,12 +4288,13 @@ fn trans_alt(&@block_ctxt cx, &@ast::expr expr,
4275
4288
auto binding_res = trans_pat_binding( binding_cx, arm. pat,
4276
4289
expr_res. val, false ) ;
4277
4290
4278
- auto block_res = trans_block( binding_res. bcx, arm. block) ;
4291
+ auto block_res = trans_block( binding_res. bcx, arm. block, output ) ;
4279
4292
arm_results += [ block_res] ;
4280
4293
4281
4294
this_cx = next_cx;
4282
4295
}
4283
4296
4297
+
4284
4298
auto default_cx = this_cx;
4285
4299
auto default_res = trans_fail( default_cx, some[ common:: span] ( expr. span) ,
4286
4300
"non-exhaustive match failure" ) ;
@@ -4297,7 +4311,7 @@ fn trans_alt(&@block_ctxt cx, &@ast::expr expr,
4297
4311
}
4298
4312
}
4299
4313
4300
- ret join_results ( cx, expr_llty , arm_results ) ;
4314
+ ret res ( join_branches ( cx, arm_results ) , C_nil ( ) ) ;
4301
4315
}
4302
4316
4303
4317
type generic_info = rec( ty:: t item_type,
@@ -4454,7 +4468,7 @@ fn trans_path(&@block_ctxt cx, &ast::path p, &ast::ann ann) -> lval_result {
4454
4468
4455
4469
auto lltagty;
4456
4470
if ( ty:: type_has_dynamic_size( cx. fcx. lcx. ccx. tcx,
4457
- tag_ty) ) {
4471
+ tag_ty) ) {
4458
4472
lltagty = T_opaque_tag ( cx. fcx. lcx. ccx. tn) ;
4459
4473
} else {
4460
4474
lltagty = type_of( cx. fcx. lcx. ccx, p. span, tag_ty) ;
@@ -5428,6 +5442,11 @@ fn trans_rec(&@block_ctxt cx, &vec[ast::field] fields,
5428
5442
}
5429
5443
5430
5444
fn trans_expr( & @block_ctxt cx, & @ast:: expr e) -> result {
5445
+ be trans_expr_out( cx, e, return) ;
5446
+ }
5447
+
5448
+ fn trans_expr_out( & @block_ctxt cx, & @ast:: expr e, out_method output)
5449
+ -> result {
5431
5450
* cx = rec( sp=e. span with * cx) ;
5432
5451
alt ( e. node) {
5433
5452
case ( ast : : expr_lit( ?lit, ?ann) ) {
@@ -5445,7 +5464,8 @@ fn trans_expr(&@block_ctxt cx, &@ast::expr e) -> result {
5445
5464
}
5446
5465
5447
5466
case ( ast:: expr_if( ?cond, ?thn, ?els, ?ann) ) {
5448
- ret trans_if( cx, cond, thn, els, ann) ;
5467
+ ret with_out_method( bind trans_if( cx, cond, thn, els, ann, _) ,
5468
+ cx, ann, output) ;
5449
5469
}
5450
5470
5451
5471
case ( ast:: expr_for( ?decl, ?seq, ?body, _) ) {
@@ -5465,18 +5485,18 @@ fn trans_expr(&@block_ctxt cx, &@ast::expr e) -> result {
5465
5485
}
5466
5486
5467
5487
case ( ast:: expr_alt( ?expr, ?arms, ?ann) ) {
5468
- ret trans_alt( cx, expr, arms, ann) ;
5488
+ ret with_out_method( bind trans_alt( cx, expr, arms, ann, _) ,
5489
+ cx, ann, output) ;
5469
5490
}
5470
5491
5471
- case ( ast:: expr_block( ?blk, _ ) ) {
5492
+ case ( ast:: expr_block( ?blk, ?ann ) ) {
5472
5493
* cx = rec( sp=blk. span with * cx) ;
5473
5494
auto sub_cx = new_scope_block_ctxt( cx, "block-expr body" ) ;
5474
5495
auto next_cx = new_sub_block_ctxt( cx, "next" ) ;
5475
- auto sub = trans_block( sub_cx, blk) ;
5476
-
5496
+ auto sub = with_out_method ( bind trans_block( sub_cx, blk, _ ) ,
5497
+ cx , ann , output ) ;
5477
5498
cx. build. Br ( sub_cx. llbb) ;
5478
5499
sub. bcx. build. Br ( next_cx. llbb) ;
5479
-
5480
5500
ret res( next_cx, sub. val) ;
5481
5501
}
5482
5502
@@ -5617,6 +5637,34 @@ fn trans_expr(&@block_ctxt cx, &@ast::expr e) -> result {
5617
5637
ret res( sub. res. bcx, load_if_immediate( sub. res. bcx, sub. res. val, t) ) ;
5618
5638
}
5619
5639
5640
+ fn with_out_method( fn( & out_method) -> result work, & @block_ctxt cx,
5641
+ & ast:: ann ann, & out_method outer_output) -> result {
5642
+ auto ccx = cx. fcx. lcx. ccx;
5643
+ if ( outer_output ! = return ) {
5644
+ ret work( outer_output) ;
5645
+ } else {
5646
+ auto tp = node_ann_type( ccx, ann) ;
5647
+ if ( ty:: type_is_nil( ccx. tcx, tp) ) {
5648
+ ret work( return) ;
5649
+ }
5650
+ auto res_alloca = alloc_ty( cx, tp) ;
5651
+ cx = zero_alloca( res_alloca. bcx, res_alloca. val, tp) . bcx;
5652
+
5653
+ fn drop_hoisted_ty( & @block_ctxt cx,
5654
+ ValueRef target,
5655
+ ty:: t t) -> result {
5656
+ auto reg_val = load_if_immediate( cx, target, t) ;
5657
+ ret drop_ty( cx, reg_val, t) ;
5658
+ }
5659
+ auto cleanup = bind drop_hoisted_ty( _, res_alloca. val, tp) ;
5660
+ find_scope_cx( cx) . cleanups += [ clean( cleanup) ] ;
5661
+
5662
+ auto done = work( save_in( res_alloca. val) ) ;
5663
+ done. val = load_if_immediate( done. bcx, res_alloca. val, tp) ;
5664
+ ret done;
5665
+ }
5666
+ }
5667
+
5620
5668
// We pass structural values around the compiler "by pointer" and
5621
5669
// non-structural values (scalars, boxes, pointers) "by value". We call the
5622
5670
// latter group "immediates" and, in some circumstances when we know we have a
@@ -6472,9 +6520,8 @@ fn alloc_local(&@block_ctxt cx, &@ast::local local) -> result {
6472
6520
ret r;
6473
6521
}
6474
6522
6475
- fn trans_block ( & @block_ctxt cx , & ast:: block b) -> result {
6523
+ fn trans_block ( & @block_ctxt cx , & ast:: block b, & out_method output ) -> result {
6476
6524
auto bcx = cx;
6477
-
6478
6525
for each ( @ast:: local local in block_locals ( b) ) {
6479
6526
* bcx = rec ( sp=local_rhs_span ( local, cx. sp ) with * bcx) ;
6480
6527
bcx = alloc_local ( bcx, local) . bcx ;
@@ -6491,58 +6538,43 @@ fn trans_block(&@block_ctxt cx, &ast::block b) -> result {
6491
6538
}
6492
6539
}
6493
6540
6541
+ fn accept_out_method ( & @ast:: expr expr) -> bool {
6542
+ ret alt ( expr. node ) {
6543
+ case ( ast:: expr_if ( _, _, _, _) ) { true }
6544
+ case ( ast:: expr_alt ( _, _, _) ) { true }
6545
+ case ( ast:: expr_block ( _, _) ) { true }
6546
+ case ( _) { false }
6547
+ } ;
6548
+ }
6549
+
6494
6550
alt ( b. node . expr ) {
6495
6551
case ( some ( ?e) ) {
6496
- // Hold onto the context for this scope since we'll need it to
6497
- // find the outer scope
6498
- auto scope_bcx = bcx;
6499
- r = trans_expr ( bcx, e) ;
6552
+ auto pass = output != return && accept_out_method ( e) ;
6553
+ if ( pass) {
6554
+ r = trans_expr_out ( bcx, e, output) ;
6555
+ } else {
6556
+ r = trans_expr ( bcx, e) ;
6557
+ }
6500
6558
bcx = r. bcx ;
6501
6559
6502
- if ( is_terminated ( bcx) ) {
6560
+ auto ccx = cx. fcx . lcx . ccx ;
6561
+ auto r_ty = ty:: expr_ty ( ccx. tcx , e) ;
6562
+ if ( is_terminated ( bcx) ||
6563
+ ty:: type_is_bot ( ccx. tcx , r_ty) ) {
6503
6564
ret r;
6504
- } else {
6505
- auto r_ty = ty:: expr_ty ( cx. fcx . lcx . ccx . tcx , e) ;
6506
- if ( !ty:: type_is_nil ( cx. fcx . lcx . ccx . tcx , r_ty)
6507
- && !ty:: type_is_bot ( cx. fcx . lcx . ccx . tcx , r_ty) ) {
6508
- // The value resulting from the block gets copied into an
6509
- // alloca created in an outer scope and its refcount
6510
- // bumped so that it can escape this block. This means
6511
- // that it will definitely live until the end of the
6512
- // enclosing scope, even if nobody uses it, which may be
6513
- // something of a surprise.
6514
-
6515
- // It's possible we never hit this block, so the alloca
6516
- // must be initialized to null, then when the potential
6517
- // value finally goes out of scope the drop glue will see
6518
- // that it was never used and ignore it.
6519
-
6520
- // NB: Here we're building and initalizing the alloca in
6521
- // the alloca context, not this block's context.
6522
- auto res_alloca = alloc_ty ( bcx, r_ty) ;
6523
- auto llbcx = llallocas_block_ctxt ( bcx. fcx ) ;
6524
- zero_alloca ( llbcx, res_alloca. val , r_ty) ;
6525
-
6526
- // Now we're working in our own block context again
6527
- auto res_copy = copy_val ( bcx, INIT ,
6528
- res_alloca. val , r. val , r_ty) ;
6529
- bcx = res_copy. bcx ;
6530
-
6531
- fn drop_hoisted_ty ( & @block_ctxt cx ,
6532
- ValueRef alloca_val ,
6533
- ty:: t t) -> result {
6534
- auto reg_val = load_if_immediate ( cx,
6535
- alloca_val, t) ;
6536
- ret drop_ty ( cx, reg_val, t) ;
6565
+ } else if ( !pass) {
6566
+ alt ( output) {
6567
+ case ( save_in ( ?target) ) {
6568
+ // The output method is to save the value at target,
6569
+ // and we didn't pass it to the recursive trans_expr
6570
+ // call.
6571
+ // FIXME Use move semantics!
6572
+ auto res_copy = copy_val ( bcx, INIT , target,
6573
+ r. val , r_ty) ;
6574
+ bcx = res_copy. bcx ;
6575
+ r = res ( bcx, C_nil ( ) ) ;
6537
6576
}
6538
-
6539
- auto cleanup = bind drop_hoisted_ty ( _, res_alloca. val ,
6540
- r_ty) ;
6541
- auto outer_scope_cx = find_outer_scope_cx ( scope_bcx) ;
6542
- outer_scope_cx. cleanups += [ clean ( cleanup) ] ;
6543
-
6544
- r = res ( bcx, load_if_immediate ( bcx,
6545
- res_alloca. val , r_ty) ) ;
6577
+ case ( return ) { }
6546
6578
}
6547
6579
}
6548
6580
}
@@ -6860,7 +6892,7 @@ fn trans_fn(@local_ctxt cx, &ast::span sp, &ast::_fn f, ast::def_id fid,
6860
6892
6861
6893
auto lltop = bcx. llbb;
6862
6894
6863
- auto res = trans_block( bcx, f. body) ;
6895
+ auto res = trans_block( bcx, f. body, return ) ;
6864
6896
if ( !is_terminated( res. bcx) ) {
6865
6897
// FIXME: until LLVM has a unit type, we are moving around
6866
6898
// C_nil values rather than their void type.
0 commit comments