@@ -2412,6 +2412,7 @@ fn join_results(parent_cx: @block_ctxt, t: TypeRef, ins: [result]) -> result {
2412
2412
ret rslt( join_cx, phi) ;
2413
2413
}
2414
2414
2415
+ // FIXME remove once all uses have been converted to join_returns
2415
2416
fn join_branches ( parent_cx : @block_ctxt , ins : [ result ] ) -> @block_ctxt {
2416
2417
let out = new_sub_block_ctxt ( parent_cx, "join" ) ;
2417
2418
let branched = false ;
@@ -2422,38 +2423,107 @@ fn join_branches(parent_cx: @block_ctxt, ins: [result]) -> @block_ctxt {
2422
2423
ret out;
2423
2424
}
2424
2425
2425
- tag out_method { return; save_in ( ValueRef ) ; }
2426
+ tag dest {
2427
+ by_val( @mutable ValueRef ) ;
2428
+ by_ref ( @mutable ValueRef ) ;
2429
+ save_in ( ValueRef ) ;
2430
+ ignore;
2431
+ }
2432
+
2433
+ fn empty_dest_cell ( ) -> @mutable ValueRef {
2434
+ ret @mutable llvm:: LLVMGetUndef ( T_nil ( ) ) ;
2435
+ }
2436
+
2437
+ fn dup_for_join ( dest : dest ) -> dest {
2438
+ alt dest {
2439
+ by_val( _) { by_val ( empty_dest_cell ( ) ) }
2440
+ by_ref ( _) { by_ref ( empty_dest_cell ( ) ) }
2441
+ _ { dest }
2442
+ }
2443
+ }
2444
+
2445
+ fn join_returns ( parent_cx : @block_ctxt , in_cxs : [ @block_ctxt ] ,
2446
+ in_ds : [ dest ] , out_dest : dest ) -> @block_ctxt {
2447
+ let out = new_sub_block_ctxt ( parent_cx, "join" ) ;
2448
+ let reachable = false , i = 0 u, phi = none;
2449
+ for cx in in_cxs {
2450
+ if !cx. unreachable {
2451
+ Br ( cx, out. llbb ) ;
2452
+ reachable = true ;
2453
+ alt in_ds[ i] {
2454
+ by_val ( cell) | by_ref ( cell) {
2455
+ if option:: is_none ( phi) {
2456
+ phi = some ( EmptyPhi ( out, val_ty ( * cell) ) ) ;
2457
+ }
2458
+ AddIncomingToPhi ( option:: get ( phi) , [ * cell] , [ cx. llbb ] ) ;
2459
+ }
2460
+ _ { }
2461
+ }
2462
+ }
2463
+ i += 1 u;
2464
+ }
2465
+ if !reachable {
2466
+ Unreachable ( out) ;
2467
+ } else {
2468
+ alt out_dest {
2469
+ by_val( cell) | by_ref ( cell) { * cell = option:: get ( phi) ; }
2470
+ _ { }
2471
+ }
2472
+ }
2473
+ ret out;
2474
+ }
2475
+
2476
+ // Wrapper through which legacy non-DPS code can use DPS functions
2477
+ fn dps_to_result ( bcx : @block_ctxt ,
2478
+ work : block ( @block_ctxt , dest ) -> @block_ctxt ,
2479
+ ty : ty:: t ) -> result {
2480
+ let tcx = bcx_tcx ( bcx) ;
2481
+ if ty:: type_is_nil ( tcx, ty) || ty:: type_is_bot ( tcx, ty) {
2482
+ ret rslt ( work ( bcx, ignore) , C_nil ( ) ) ;
2483
+ } else if type_is_immediate ( bcx_ccx ( bcx) , ty) {
2484
+ let cell = empty_dest_cell ( ) ;
2485
+ bcx = work ( bcx, by_val ( cell) ) ;
2486
+ add_clean_temp ( bcx, * cell, ty) ;
2487
+ ret rslt( bcx, * cell) ;
2488
+ } else {
2489
+ let { bcx, val: alloca } = alloc_ty ( bcx, ty) ;
2490
+ bcx = zero_alloca ( bcx, alloca, ty) ;
2491
+ bcx = work ( bcx, save_in ( alloca) ) ;
2492
+ add_clean_temp ( bcx, alloca, ty) ;
2493
+ ret rslt( bcx, alloca) ;
2494
+ }
2495
+ }
2426
2496
2427
2497
fn trans_if ( cx : @block_ctxt , cond : @ast:: expr , thn : ast:: blk ,
2428
- els : option:: t < @ast:: expr > , output : out_method ) -> result {
2498
+ els : option:: t < @ast:: expr > , dest : dest )
2499
+ -> @block_ctxt {
2429
2500
let { bcx, val: cond_val } = trans_expr ( cx, cond) ;
2430
2501
2502
+ let then_dest = dup_for_join ( dest) ;
2503
+ let else_dest = dup_for_join ( dest) ;
2431
2504
let then_cx = new_scope_block_ctxt ( bcx, "then" ) ;
2432
- let then_res = trans_block ( then_cx, thn, output) ;
2433
2505
let else_cx = new_scope_block_ctxt ( bcx, "else" ) ;
2434
- // Synthesize a block here to act as the else block
2435
- // containing an if expression. Needed in order for the
2436
- // else scope to behave like a normal block scope. A tad
2437
- // ugly.
2506
+ CondBr ( bcx, cond_val, then_cx. llbb , else_cx. llbb ) ;
2507
+ then_cx = trans_block_dps ( then_cx, thn, then_dest) ;
2438
2508
// Calling trans_block directly instead of trans_expr
2439
2509
// because trans_expr will create another scope block
2440
2510
// context for the block, but we've already got the
2441
2511
// 'else' context
2442
- let else_res =
2443
- alt els {
2444
- some( elexpr) {
2445
- alt elexpr. node {
2446
- ast:: expr_if ( _, _, _) {
2447
- let elseif_blk = ast_util:: block_from_expr ( elexpr) ;
2448
- trans_block ( else_cx, elseif_blk, output)
2449
- }
2450
- ast:: expr_block ( blk) { trans_block ( else_cx, blk, output) }
2451
- }
2512
+ alt els {
2513
+ some( elexpr) {
2514
+ alt elexpr. node {
2515
+ ast:: expr_if ( _, _, _) {
2516
+ let elseif_blk = ast_util:: block_from_expr ( elexpr) ;
2517
+ else_cx = trans_block_dps ( else_cx, elseif_blk, else_dest) ;
2452
2518
}
2453
- _ { rslt( else_cx, C_nil ( ) ) }
2454
- } ;
2455
- CondBr ( bcx, cond_val, then_cx. llbb , else_cx. llbb ) ;
2456
- ret rslt( join_branches ( cx, [ then_res, else_res] ) , C_nil ( ) ) ;
2519
+ ast:: expr_block ( blk) {
2520
+ else_cx = trans_block_dps ( else_cx, blk, else_dest) ;
2521
+ }
2522
+ }
2523
+ }
2524
+ _ { }
2525
+ }
2526
+ ret join_returns ( cx, [ then_cx, else_cx] , [ then_dest, else_dest] , dest) ;
2457
2527
}
2458
2528
2459
2529
fn trans_for ( cx : @block_ctxt , local : @ast:: local , seq : @ast:: expr ,
@@ -2468,7 +2538,7 @@ fn trans_for(cx: @block_ctxt, local: @ast::local, seq: @ast::expr,
2468
2538
curr = PointerCast ( bcx, curr, T_ptr ( type_of_or_i8 ( bcx, t) ) ) ;
2469
2539
bcx = trans_alt:: bind_irrefutable_pat ( scope_cx, local. node . pat , curr,
2470
2540
bcx. fcx . lllocals , false ) ;
2471
- bcx = trans_block ( bcx, body, return ) . bcx ;
2541
+ bcx = trans_block_dps ( bcx, body, ignore ) ;
2472
2542
Br ( bcx, next_cx. llbb ) ;
2473
2543
ret next_cx;
2474
2544
}
@@ -2771,7 +2841,7 @@ fn trans_for_each(cx: @block_ctxt, local: @ast::local, seq: @ast::expr,
2771
2841
llvm:: LLVMGetParam ( fcx. llfn , 3 u) ,
2772
2842
bcx. fcx . lllocals , false ) ;
2773
2843
let lltop = bcx. llbb ;
2774
- let r = trans_block ( bcx, body, return ) ;
2844
+ let r = trans_block ( bcx, body) ;
2775
2845
finish_fn ( fcx, lltop) ;
2776
2846
2777
2847
build_return ( r. bcx ) ;
@@ -2793,7 +2863,7 @@ fn trans_while(cx: @block_ctxt, cond: @ast::expr, body: ast::blk) -> result {
2793
2863
new_loop_scope_block_ctxt ( cx, option:: none :: < @block_ctxt > , next_cx,
2794
2864
"while cond" ) ;
2795
2865
let body_cx = new_scope_block_ctxt ( cond_cx, "while loop body" ) ;
2796
- let body_res = trans_block ( body_cx, body, return ) ;
2866
+ let body_res = trans_block ( body_cx, body) ;
2797
2867
let cond_res = trans_expr ( cond_cx, cond) ;
2798
2868
Br ( body_res. bcx , cond_cx. llbb ) ;
2799
2869
let cond_bcx = trans_block_cleanups ( cond_res. bcx , cond_cx) ;
@@ -2808,7 +2878,7 @@ fn trans_do_while(cx: @block_ctxt, body: ast::blk, cond: @ast::expr) ->
2808
2878
let body_cx =
2809
2879
new_loop_scope_block_ctxt ( cx, option:: none :: < @block_ctxt > , next_cx,
2810
2880
"do-while loop body" ) ;
2811
- let body_res = trans_block ( body_cx, body, return ) ;
2881
+ let body_res = trans_block ( body_cx, body) ;
2812
2882
let cond_res = trans_expr ( body_res. bcx , cond) ;
2813
2883
CondBr ( cond_res. bcx , cond_res. val , body_cx. llbb , next_cx. llbb ) ;
2814
2884
Br ( cx, body_cx. llbb ) ;
@@ -4034,36 +4104,16 @@ fn trans_rec(cx: @block_ctxt, fields: [ast::field],
4034
4104
}
4035
4105
4036
4106
fn trans_expr ( cx : @block_ctxt , e : @ast:: expr ) -> result {
4037
- trans_expr_out ( cx, e, return )
4038
- }
4039
-
4040
- fn trans_expr_out ( cx : @block_ctxt , e : @ast:: expr , output : out_method ) ->
4041
- result {
4042
4107
// Fixme Fill in cx.sp
4043
4108
alt e. node {
4044
4109
ast:: expr_lit ( lit) { ret trans_lit ( cx, * lit) ; }
4045
4110
ast:: expr_binary ( op, x, y) { ret trans_binary ( cx, op, x, y) ; }
4046
- ast:: expr_if ( cond, thn, els) {
4047
- ret with_out_method ( bind trans_if ( cx, cond, thn, els, _) , cx, e. id ,
4048
- output) ;
4049
- }
4050
- ast:: expr_if_check ( cond, thn, els) {
4051
- ret with_out_method ( bind trans_if ( cx, cond, thn, els, _) , cx, e. id ,
4052
- output) ;
4053
- }
4054
- ast:: expr_ternary ( _, _, _) {
4055
- ret trans_expr_out ( cx, ast_util:: ternary_to_if ( e) , output) ;
4056
- }
4057
4111
ast:: expr_for ( decl, seq, body) { ret trans_for ( cx, decl, seq, body) ; }
4058
4112
ast:: expr_for_each ( decl, seq, body) {
4059
4113
ret trans_for_each ( cx, decl, seq, body) ;
4060
4114
}
4061
4115
ast:: expr_while ( cond, body) { ret trans_while ( cx, cond, body) ; }
4062
4116
ast:: expr_do_while ( body, cond) { ret trans_do_while ( cx, body, cond) ; }
4063
- ast:: expr_alt ( expr, arms) {
4064
- ret with_out_method ( bind trans_alt:: trans_alt ( cx, expr, arms, _) , cx,
4065
- e. id , output) ;
4066
- }
4067
4117
ast:: expr_fn ( f) {
4068
4118
let ccx = bcx_ccx ( cx) ;
4069
4119
let fty = node_id_type ( ccx, e. id ) ;
@@ -4088,17 +4138,6 @@ fn trans_expr_out(cx: @block_ctxt, e: @ast::expr, output: out_method) ->
4088
4138
} ;
4089
4139
ret rslt( fn_pair. bcx , fn_pair. fn_pair ) ;
4090
4140
}
4091
- ast:: expr_block ( blk) {
4092
- let sub_cx = new_scope_block_ctxt ( cx, "block-expr body" ) ;
4093
- let next_cx = new_sub_block_ctxt ( cx, "next" ) ;
4094
- let sub =
4095
- with_out_method ( bind trans_block ( sub_cx, blk, _) , cx, e. id ,
4096
- output) ;
4097
- Br ( cx, sub_cx. llbb ) ;
4098
- Br ( sub. bcx , next_cx. llbb ) ;
4099
- if sub. bcx . unreachable { Unreachable ( next_cx) ; }
4100
- ret rslt( next_cx, sub. val ) ;
4101
- }
4102
4141
ast:: expr_copy ( a) {
4103
4142
let e_ty = ty:: expr_ty ( bcx_tcx ( cx) , a) ;
4104
4143
let lv = trans_lval ( cx, a) ;
@@ -4256,27 +4295,62 @@ fn trans_expr_out(cx: @block_ctxt, e: @ast::expr, output: out_method) ->
4256
4295
ast:: expr_unary ( op, x) {
4257
4296
ret trans_unary ( cx, op, x, e. id ) ;
4258
4297
}
4298
+ // Fall through to DPS-style
4299
+ _ {
4300
+ ret dps_to_result( cx, { |bcx, dest| trans_expr_dps ( bcx, e, dest) } ,
4301
+ ty:: expr_ty ( bcx_tcx ( cx) , e) ) ;
4302
+ }
4259
4303
}
4260
4304
}
4261
4305
4262
- fn with_out_method ( work : fn ( out_method ) -> result , cx : @block_ctxt ,
4263
- id : ast:: node_id , outer_output : out_method ) -> result {
4264
- let ccx = bcx_ccx ( cx) ;
4265
- if outer_output != return {
4266
- ret work ( outer_output) ;
4267
- } else {
4268
- let tp = node_id_type ( ccx, id) ;
4269
- if ty:: type_is_nil ( ccx. tcx , tp) { ret work ( return ) ; }
4270
- let res_alloca = alloc_ty ( cx, tp) ;
4271
- cx = zero_alloca ( res_alloca. bcx , res_alloca. val , tp) ;
4272
- let done = work ( save_in ( res_alloca. val ) ) ;
4273
- let loaded = load_if_immediate ( done. bcx , res_alloca. val , tp) ;
4274
- add_clean_temp ( cx, loaded, tp) ;
4275
- ret rslt( done. bcx , loaded) ;
4306
+ fn trans_expr_dps ( bcx : @block_ctxt , e : @ast:: expr , dest : dest )
4307
+ -> @block_ctxt {
4308
+ alt e. node {
4309
+ ast:: expr_if ( cond, thn, els) | ast:: expr_if_check ( cond, thn, els) {
4310
+ ret trans_if ( bcx, cond, thn, els, dest) ;
4311
+ }
4312
+ ast:: expr_ternary ( _, _, _) {
4313
+ ret trans_expr_dps ( bcx, ast_util:: ternary_to_if ( e) , dest) ;
4314
+ }
4315
+ ast:: expr_alt ( expr, arms) {
4316
+ ret trans_alt:: trans_alt ( bcx, expr, arms, dest) ;
4317
+ }
4318
+ ast:: expr_block ( blk) {
4319
+ let sub_cx = new_scope_block_ctxt ( bcx, "block-expr body" ) ;
4320
+ Br ( bcx, sub_cx. llbb ) ;
4321
+ sub_cx = trans_block_dps ( sub_cx, blk, dest) ;
4322
+ let next_cx = new_sub_block_ctxt ( bcx, "next" ) ;
4323
+ Br ( sub_cx, next_cx. llbb ) ;
4324
+ if sub_cx. unreachable { Unreachable ( next_cx) ; }
4325
+ ret next_cx;
4326
+ }
4327
+ // Convert back from result to DPS
4328
+ _ {
4329
+ let lv = trans_lval ( bcx, e) ;
4330
+ let { bcx, val, is_mem} = lv;
4331
+ let ty = ty:: expr_ty ( bcx_tcx ( bcx) , e) ;
4332
+ alt dest {
4333
+ by_val( cell) {
4334
+ if is_mem {
4335
+ bcx = take_ty ( bcx, val, ty) ;
4336
+ * cell = Load ( bcx, val) ;
4337
+ } else {
4338
+ revoke_clean ( bcx, val) ;
4339
+ * cell = val;
4340
+ }
4341
+ }
4342
+ by_ref ( cell) {
4343
+ assert is_mem;
4344
+ * cell = val;
4345
+ }
4346
+ save_in ( loc) { bcx = move_val_if_temp ( bcx, INIT , loc, lv, ty) ; }
4347
+ ignore. { }
4348
+ }
4349
+ ret bcx;
4350
+ }
4276
4351
}
4277
4352
}
4278
4353
4279
-
4280
4354
// We pass structural values around the compiler "by pointer" and
4281
4355
// non-structural values (scalars, boxes, pointers) "by value". We call the
4282
4356
// latter group "immediates" and, in some circumstances when we know we have a
@@ -4900,54 +4974,27 @@ fn alloc_local(cx: @block_ctxt, local: @ast::local) -> result {
4900
4974
ret r;
4901
4975
}
4902
4976
4903
- fn trans_block ( cx : @block_ctxt , b : ast:: blk , output : out_method ) -> result {
4904
- let bcx = cx;
4977
+ fn trans_block ( bcx : @block_ctxt , b : ast:: blk ) -> result {
4978
+ dps_to_result ( bcx, { |bcx, dest| trans_block_dps ( bcx, b, dest) } ,
4979
+ ty:: node_id_to_type ( bcx_tcx ( bcx) , b. node . id ) )
4980
+ }
4981
+
4982
+ fn trans_block_dps ( bcx : @block_ctxt , b : ast:: blk , dest : dest )
4983
+ -> @block_ctxt {
4905
4984
for each local: @ast:: local in block_locals ( b) {
4906
4985
// FIXME Update bcx.sp
4907
4986
let r = alloc_local ( bcx, local) ;
4908
4987
bcx = r. bcx ;
4909
4988
bcx. fcx . lllocals . insert ( local. node . id , r. val ) ;
4910
4989
}
4911
- let r = rslt ( bcx, C_nil ( ) ) ;
4912
4990
for s: @ast:: stmt in b. node . stmts {
4913
4991
bcx = trans_stmt ( bcx, * s) ;
4914
4992
}
4915
- fn accept_out_method ( expr : @ast:: expr ) -> bool {
4916
- ret alt expr. node {
4917
- ast:: expr_if ( _, _, _) { true }
4918
- ast:: expr_alt ( _, _) { true }
4919
- ast:: expr_block ( _) { true }
4920
- _ { false }
4921
- } ;
4922
- }
4923
4993
alt b. node . expr {
4924
- some ( e) {
4925
- let ccx = bcx_ccx ( cx) ;
4926
- let r_ty = ty:: expr_ty ( ccx. tcx , e) ;
4927
- let pass = output != return && accept_out_method ( e) ;
4928
- if pass {
4929
- r = trans_expr_out ( bcx, e, output) ;
4930
- bcx = r. bcx ;
4931
- } else {
4932
- let lv = trans_lval ( bcx, e) ;
4933
- r = { bcx: lv. bcx , val: lv. val } ;
4934
- bcx = r. bcx ;
4935
- alt output {
4936
- save_in( target) {
4937
- // The output method is to save the value at target,
4938
- // and we didn't pass it to the recursive trans_expr
4939
- // call.
4940
- bcx = move_val_if_temp ( bcx, INIT , target, lv, r_ty) ;
4941
- r = rslt ( bcx, C_nil ( ) ) ;
4942
- }
4943
- return . { }
4944
- }
4945
- }
4946
- }
4947
- none. { r = rslt ( bcx, C_nil ( ) ) ; }
4994
+ some ( e) { bcx = trans_expr_dps ( bcx, e, dest) ; }
4995
+ _ { assert dest == ignore || bcx. unreachable ; }
4948
4996
}
4949
- bcx = trans_block_cleanups ( bcx, find_scope_cx ( bcx) ) ;
4950
- ret rslt( bcx, r. val ) ;
4997
+ ret trans_block_cleanups ( bcx, find_scope_cx ( bcx) ) ;
4951
4998
}
4952
4999
4953
5000
fn new_local_ctxt ( ccx : @crate_ctxt ) -> @local_ctxt {
@@ -5238,13 +5285,13 @@ fn trans_closure(bcx_maybe: option::t<@block_ctxt>,
5238
5285
// translation calls that don't have a return value (trans_crate,
5239
5286
// trans_mod, trans_item, trans_obj, et cetera) and those that do
5240
5287
// (trans_block, trans_expr, et cetera).
5241
- let rslt =
5242
- if !ty:: type_is_bot ( cx. ccx . tcx , block_ty) &&
5243
- !ty :: type_is_nil ( cx . ccx . tcx , block_ty ) &&
5244
- f . proto != ast :: proto_iter {
5245
- trans_block ( bcx , f . body , save_in ( fcx. llretptr ) )
5246
- } else { trans_block ( bcx , f . body , return ) } ;
5247
- bcx = rslt . bcx ;
5288
+ let dest = if !ty :: type_is_bot ( cx . ccx . tcx , block_ty ) &&
5289
+ !ty:: type_is_nil ( cx. ccx . tcx , block_ty) &&
5290
+ f . proto != ast :: proto_iter &&
5291
+ option :: is_some ( f . body . node . expr ) {
5292
+ save_in ( fcx. llretptr )
5293
+ } else { ignore } ;
5294
+ bcx = trans_block_dps ( bcx, f . body , dest ) ;
5248
5295
5249
5296
if !bcx. unreachable {
5250
5297
// FIXME: until LLVM has a unit type, we are moving around
0 commit comments