Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit8fbd6bf

Browse files
dsymeKevinRansom
authored andcommitted
minimize use of state machine variables (dotnet#5097)
* minimize use of state machine variables* fix bug* update baselines* baseline updates
1 parent80cd1a1 commit8fbd6bf

File tree

22 files changed

+5292
-6465
lines changed

22 files changed

+5292
-6465
lines changed

‎src/fsharp/LowerCallsAndSeqs.fs‎

Lines changed: 84 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,18 @@ type LoweredSeqFirstPhaseResult =
8484
{/// The code to run in the second phase, to rebuild the expressions, once all code labels and their mapping to program counters have been determined
8585
/// 'nextVar' is the argument variable for the GenerateNext method that represents the byref argument that holds the "goto" destination for a tailcalling sequence expression
8686
phase2:((* pc:*) ValRef*(* current:*) ValRef*(* nextVar:*) ValRef* Map<ILCodeLabel,int>-> Expr* Expr* Expr)
87+
8788
/// The labels allocated for one portion of the sequence expression
8889
labels:int list
90+
8991
/// any actual work done in Close
9092
significantClose:bool
9193

9294
/// The state variables allocated for one portion of the sequence expression (i.e. the local let-bound variables which become state variables)
93-
stateVars:ValRef list}
95+
stateVars:ValRef list
96+
97+
/// The vars captured by the non-synchronous path
98+
capturedVars:FreeVars}
9499

95100
letisVarFreeInExpr v e= Zset.contains v(freeInExpr CollectTyparsAndLocals e).FreeLocals
96101

@@ -174,6 +179,17 @@ let LowerSeqExpr g amap overallExpr =
174179
| Expr.App(Expr.Val(vref,_,_),_f0ty,[elemTy],[e],_m)when valRefEq g vref g.seq_vref-> Some(e,elemTy)
175180
|_-> None
176181

182+
letRepresentBindingAsLocal(bind:Binding)res2 m=
183+
// printfn "found letrec state variable %s" bind.Var.DisplayName
184+
{ res2with
185+
phase2=(fun ctxt->
186+
letgenerate2,dispose2,checkDispose2= res2.phase2 ctxt
187+
letgenerate= mkLetBind m bind generate2
188+
letdispose= dispose2
189+
letcheckDispose= checkDispose2
190+
generate,dispose,checkDispose)
191+
stateVars= res2.stateVars}
192+
177193
letRepresentBindingAsStateMachineLocal(bind:Binding)res2 m=
178194
// printfn "found letrec state variable %s" bind.Var.DisplayName
179195
let(TBind(v,e,sp))= bind
@@ -243,17 +259,28 @@ let LowerSeqExpr g amap overallExpr =
243259
labels=[label]
244260
stateVars=[]
245261
significantClose=false
262+
capturedVars= emptyFreeVars
246263
}
247264

248-
| SeqDelay(e,_elemTy)->
265+
| SeqDelay(delayedExpr,_elemTy)->
249266
// printfn "found Seq.delay"
250-
Lower isWholeExpr isTailCall noDisposeContinuationLabel currentDisposeContinuationLabel e// note, using 'isWholeExpr' here prevents 'seq { yield! e }' and 'seq { 0 .. 1000 }' from being compiled
267+
// note, using 'isWholeExpr' here prevents 'seq { yield! e }' and 'seq { 0 .. 1000 }' from being compiled
268+
Lower isWholeExpr isTailCall noDisposeContinuationLabel currentDisposeContinuationLabel delayedExpr
251269

252270
| SeqAppend(e1,e2,m)->
253271
// printfn "found Seq.append"
254-
match Lowerfalsefalse noDisposeContinuationLabel currentDisposeContinuationLabel e1,
255-
Lowerfalse isTailCall noDisposeContinuationLabel currentDisposeContinuationLabel e2with
272+
letres1= Lowerfalsefalse noDisposeContinuationLabel currentDisposeContinuationLabel e1
273+
letres2= Lowerfalse isTailCall noDisposeContinuationLabel currentDisposeContinuationLabel e2
274+
match res1, res2with
256275
| Some res1, Some res2->
276+
277+
letcapturedVars=
278+
if res1.labels.IsEmptythen
279+
res2.capturedVars
280+
else
281+
// All of 'e2' is needed after resuming at any of the labels
282+
unionFreeVars res1.capturedVars(freeInExpr CollectLocals e2)
283+
257284
Some{ phase2=(fun ctxt->
258285
letgenerate1,dispose1,checkDispose1= res1.phase2 ctxt
259286
letgenerate2,dispose2,checkDispose2= res2.phase2 ctxt
@@ -265,29 +292,43 @@ let LowerSeqExpr g amap overallExpr =
265292
generate,dispose,checkDispose)
266293
labels= res1.labels@ res2.labels
267294
stateVars= res1.stateVars@ res2.stateVars
268-
significantClose= res1.significantClose|| res2.significantClose}
295+
significantClose= res1.significantClose|| res2.significantClose
296+
capturedVars= capturedVars}
269297
|_->
270298
None
271299

272-
| SeqWhile(e1,e2,m)->
300+
| SeqWhile(guardExpr,bodyExpr,m)->
273301
// printfn "found Seq.while"
274-
match Lowerfalsefalse noDisposeContinuationLabel currentDisposeContinuationLabel e2with
302+
letresBody= Lowerfalsefalse noDisposeContinuationLabel currentDisposeContinuationLabel bodyExpr
303+
match resBodywith
275304
| Some res2->
305+
letcapturedVars=
306+
if res2.labels.IsEmptythen
307+
res2.capturedVars// the whole loopis synchronous, no labels
308+
else
309+
freeInExpr CollectLocals expr// everything is needed on subsequent iterations
310+
276311
Some{ phase2=(fun ctxt->
277312
letgenerate2,dispose2,checkDispose2= res2.phase2 ctxt
278-
letgenerate= mkWhile g(SequencePointAtWhileLoope1.Range,NoSpecialWhileLoopMarker,e1,generate2,m)
313+
letgenerate= mkWhile g(SequencePointAtWhileLoopguardExpr.Range,NoSpecialWhileLoopMarker,guardExpr,generate2,m)
279314
letdispose= dispose2
280315
letcheckDispose= checkDispose2
281316
generate,dispose,checkDispose)
282317
labels= res2.labels
283318
stateVars= res2.stateVars
284-
significantClose= res2.significantClose}
319+
significantClose= res2.significantClose
320+
capturedVars= capturedVars}
285321
|_->
286322
None
287323

288324
| SeqUsing(resource,v,body,elemTy,m)->
289325
// printfn "found Seq.using"
290-
Lowerfalse isTailCall noDisposeContinuationLabel currentDisposeContinuationLabel(mkLet(SequencePointAtBinding body.Range) m v resource(mkCallSeqFinally g m elemTy body(mkUnitDelayLambda g m(mkCallDispose g m v.Type(exprForVal m v)))))
326+
letreduction=
327+
mkLet(SequencePointAtBinding body.Range) m v resource
328+
(mkCallSeqFinally g m elemTy body
329+
(mkUnitDelayLambda g m
330+
(mkCallDispose g m v.Type(exprForVal m v))))
331+
Lowerfalse isTailCall noDisposeContinuationLabel currentDisposeContinuationLabel reduction
291332

292333
| SeqFor(inp,v,body,genElemTy,m)->
293334
// printfn "found Seq.for"
@@ -298,18 +339,21 @@ let LowerSeqExpr g amap overallExpr =
298339
// while enum.MoveNext() do
299340
// let v = enum.Current
300341
// body ]]
301-
Lowerfalse isTailCall noDisposeContinuationLabel currentDisposeContinuationLabel
302-
(mkCallSeqUsing g m inpEnumTy genElemTy(callNonOverloadedMethod g amap m"GetEnumerator"(mkSeqTy g inpElemTy)[inp])
303-
(mkLambdaNoType g m enumv
342+
letreduction=
343+
mkCallSeqUsing g m inpEnumTy genElemTy(callNonOverloadedMethod g amap m"GetEnumerator"(mkSeqTy g inpElemTy)[inp])
344+
(mkLambdaNoType g m enumv
304345
(mkCallSeqGenerated g m genElemTy(mkUnitDelayLambda g m(callNonOverloadedMethod g amap m"MoveNext" inpEnumTy[enume]))
305346
(mkInvisibleLet m v(callNonOverloadedMethod g amap m"get_Current" inpEnumTy[enume])
306-
(mkCoerceIfNeeded g(mkSeqTy g genElemTy)(tyOfExpr g body) body)))))
347+
(mkCoerceIfNeeded g(mkSeqTy g genElemTy)(tyOfExpr g body) body))))
348+
Lowerfalse isTailCall noDisposeContinuationLabel currentDisposeContinuationLabel reduction
307349

308350
| SeqTryFinally(e1,compensation,m)->
309351
// printfn "found Seq.try/finally"
310352
letinnerDisposeContinuationLabel= IL.generateCodeLabel()
311-
match Lowerfalsefalse noDisposeContinuationLabel innerDisposeContinuationLabel e1with
353+
letresBody= Lowerfalsefalse noDisposeContinuationLabel innerDisposeContinuationLabel e1
354+
match resBodywith
312355
| Some res1->
356+
letcapturedVars= unionFreeVars res1.capturedVars(freeInExpr CollectLocals compensation)
313357
Some{ phase2=(fun((pcv,_currv,_,pcMap)asctxt)->
314358
letgenerate1,dispose1,checkDispose1= res1.phase2 ctxt
315359
letgenerate=
@@ -348,7 +392,8 @@ let LowerSeqExpr g amap overallExpr =
348392
generate,dispose,checkDispose)
349393
labels= innerDisposeContinuationLabel:: res1.labels
350394
stateVars= res1.stateVars
351-
significantClose=true}
395+
significantClose=true
396+
capturedVars= capturedVars}
352397
|_->
353398
None
354399

@@ -361,7 +406,8 @@ let LowerSeqExpr g amap overallExpr =
361406
generate,dispose,checkDispose)
362407
labels=[]
363408
stateVars=[]
364-
significantClose=false}
409+
significantClose=false
410+
capturedVars= emptyFreeVars}
365411

366412
| Expr.Sequential(x1,x2,NormalSeq,ty,m)->
367413
match Lowerfalse isTailCall noDisposeContinuationLabel currentDisposeContinuationLabel x2with
@@ -376,13 +422,18 @@ let LowerSeqExpr g amap overallExpr =
376422
generate,dispose,checkDispose)}
377423
| None-> None
378424

379-
| Expr.Let(bind,e2,m,_)
425+
| Expr.Let(bind,bodyExpr,m,_)
380426
// Restriction: compilation of sequence expressions containing non-toplevel constrained generic functions is not supported
381427
when bind.Var.IsCompiledAsTopLevel||not(IsGenericValWithGenericContraints g bind.Var)->
382-
match Lowerfalse isTailCall noDisposeContinuationLabel currentDisposeContinuationLabel e2with
428+
429+
letresBody= Lowerfalse isTailCall noDisposeContinuationLabel currentDisposeContinuationLabel bodyExpr
430+
match resBodywith
383431
| Some res2->
384432
if bind.Var.IsCompiledAsTopLevelthen
385433
Some(RepresentBindingsAsLifted(mkLetBind m bind) res2)
434+
elifnot(res2.capturedVars.FreeLocals.Contains(bind.Var))then
435+
// printfn "found state variable %s" bind.Var.DisplayName
436+
Some(RepresentBindingAsLocal bind res2 m)
386437
else
387438
// printfn "found state variable %s" bind.Var.DisplayName
388439
Some(RepresentBindingAsStateMachineLocal bind res2 m)
@@ -421,12 +472,18 @@ let LowerSeqExpr g amap overallExpr =
421472
*)
422473
| Expr.Match(spBind,exprm,pt,targets,m,ty)when targets|> Array.forall(fun(TTarget(vs,_e,_spTarget))-> isNil vs)->
423474
// lower all the targets. abandon if any fail to lower
424-
lettgl= targets|> Array.map(fun(TTarget(_vs,e,_spTarget))-> Lowerfalse isTailCall noDisposeContinuationLabel currentDisposeContinuationLabele)|> Array.toList
475+
lettglArray= targets|> Array.map(fun(TTarget(_vs,targetExpr,_spTarget))-> Lowerfalse isTailCall noDisposeContinuationLabel currentDisposeContinuationLabeltargetExpr)
425476
// LIMITATION: non-trivial pattern matches involving or-patterns or active patterns where bindings can't be
426477
// transferred to the r.h.s. are not yet compiled.
427-
if tgl|> List.forall Option.isSomethen
428-
lettgl= List.map Option.get tgl
478+
if tglArray|> Array.forall Option.isSomethen
479+
lettglArray= Array.map Option.get tglArray
480+
lettgl= Array.toList tglArray
429481
letlabs= tgl|> List.collect(fun res-> res.labels)
482+
let(capturedVars,_)=
483+
((emptyFreeVars,false), Array.zip targets tglArray)
484+
||> Array.fold(fun(fvs,seenLabel)((TTarget(_vs,e,_spTarget)),res)->
485+
if seenLabelthen unionFreeVars fvs(freeInExpr CollectLocals e),true
486+
else res.capturedVars,not res.labels.IsEmpty)
430487
letstateVars= tgl|> List.collect(fun res-> res.stateVars)
431488
letsignificantClose= tgl|> List.exists(fun res-> res.significantClose)
432489
Some{ phase2=(fun ctxt->
@@ -443,7 +500,8 @@ let LowerSeqExpr g amap overallExpr =
443500
generate,dispose,checkDispose)
444501
labels=labs
445502
stateVars= stateVars
446-
significantClose= significantClose}
503+
significantClose= significantClose
504+
capturedVars= capturedVars}
447505
else
448506
None
449507

@@ -502,7 +560,8 @@ let LowerSeqExpr g amap overallExpr =
502560
generate,dispose,checkDispose)
503561
labels=[label]
504562
stateVars=[]
505-
significantClose=false}
563+
significantClose=false
564+
capturedVars= emptyFreeVars}
506565
else
507566
letv,ve= mkCompGenLocal m"v" inpElemTy
508567
Lowerfalse isTailCall noDisposeContinuationLabel currentDisposeContinuationLabel(mkCallSeqCollect g m inpElemTy inpElemTy(mkLambdaNoType g m v(mkCallSeqSingleton g m inpElemTy ve)) arbitrarySeqExpr)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp