Skip to content

Commit

Permalink
Fixed match generation
Browse files Browse the repository at this point in the history
  • Loading branch information
TIHan committed Oct 2, 2019
1 parent eff36da commit 83bc428
Showing 1 changed file with 53 additions and 34 deletions.
87 changes: 53 additions & 34 deletions src/fsharp/IlxGen.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2199,7 +2199,7 @@ and GenExprAux (cenv: cenv) (cgbuf: CodeGenBuffer) eenv sp expr sequel =
| Expr.Const (c, m, ty) ->
GenConstant cenv cgbuf eenv (c, m, ty) sequel
| Expr.Match (spBind, exprm, tree, targets, m, ty) ->
GenMatch cenv cgbuf eenv (spBind, exprm, tree, targets, m, ty) sequel
GenMatch cenv cgbuf eenv (spBind, exprm, tree, targets, m, ty) sequel id |> ignore<FakeUnit>
| Expr.LetRec (binds, body, m, _) ->
GenLetRec cenv cgbuf eenv (binds, body, m) sequel
| Expr.Lambda _ | Expr.TyLambda _ ->
Expand Down Expand Up @@ -4768,8 +4768,29 @@ and GenJoinPoint cenv cgbuf pos eenv ty m sequel =
let afterJoin = CG.GenerateDelayMark cgbuf (pos + "_join")
// go to the join point
Br afterJoin, afterJoin, stackAfterJoin, sequel

and GenSequelAfterMatch cenv cgbuf eenv afterJoin stackAfterJoin sequelAfterJoin =
CG.SetMarkToHere cgbuf afterJoin

//assert(cgbuf.GetCurrentStack() = stackAfterJoin) // REVIEW: Since gen_dtree* now sets stack, stack should be stackAfterJoin at this point...
CG.SetStack cgbuf stackAfterJoin
// If any values are left on the stack after the join then we're certainly going to do something with them
// For example, we may be about to execute a 'stloc' for
//
// let y2 = if System.DateTime.Now.Year < 2000 then 1 else 2
//
// or a 'stelem' for
//
// arr.[0] <- if System.DateTime.Now.Year > 2000 then 1 else 2
//
// In both cases, any instructions that come after this point will be falsely associated with the last branch of the control
// prior to the join point. This is base, e.g. see FSharp 1.0 bug 5155
if not (isNil stackAfterJoin) then
cgbuf.EmitStartOfHiddenCode()

GenSequel cenv eenv.cloc cgbuf sequelAfterJoin

and GenMatch cenv cgbuf eenv (spBind, _exprm, tree, targets, m, ty) sequel =
and GenMatch cenv cgbuf eenv (spBind, _exprm, tree, targets, m, ty) sequel contf =

match spBind with
| SequencePointAtBinding m -> CG.EmitSeqPoint cgbuf m
Expand Down Expand Up @@ -4806,38 +4827,36 @@ and GenMatch cenv cgbuf eenv (spBind, _exprm, tree, targets, m, ty) sequel =
// match-testing (dtrees) should not contribute to the stack.
// Each branch-RHS (targets) may contribute to the stack, leaving it in the "stackAfterJoin" state, for the join point.
// Since code is branching and joining, the cgbuf stack is maintained manually.
let eenvAtTarget, spExpr, successExpr, sequel = GenDecisionTreeAndTargets cenv cgbuf stackAtTargets eenv tree targets repeatSP sequelOnBranches
let successExpr = stripExpr successExpr
match successExpr with
| Expr.Match (spBind, exprm, tree, targets, m, ty) ->
ProcessSequencePointForExpr cenv cgbuf spExpr successExpr
GenMatch cenv cgbuf eenv (spBind, exprm, tree, targets, m, ty) sequel
| Expr.Let (bind, (Expr.Match (spBind, exprm, tree, targets, m, ty) as nextExpr), _, _) ->
ProcessSequencePointForExpr cenv cgbuf spExpr successExpr
let eenv, spBody, endScope = ProcessSequencePointForBinding cenv cgbuf eenv spExpr bind
ProcessSequencePointForExpr cenv cgbuf spBody nextExpr
GenMatch cenv cgbuf eenv (spBind, exprm, tree, targets, m, ty) (EndLocalScope(sequel, endScope))
let lastTargetInfoOpt = GenDecisionTreeAndTargets cenv cgbuf stackAtTargets eenv tree targets repeatSP sequelOnBranches

// Sometimes we will get the last target information.
// When we do, that target's expression has not been generated yet.
// So, we do the generation here and check to see if the last target's expression
// is part of a linear expression tree to another match expression. This way we can take advantage of tailcalls
// to prevent stack overflows when generating large linear match expression trees.
match lastTargetInfoOpt with
| Some (eenvAtTarget, spExpr, successExpr, sequel) ->
let successExpr = stripExpr successExpr
match successExpr with
| Expr.Match (spBind, exprm, tree, targets, m, ty) ->
ProcessSequencePointForExpr cenv cgbuf spExpr successExpr
GenMatch cenv cgbuf eenv (spBind, exprm, tree, targets, m, ty) sequel (contf >> fun _ ->
GenSequelAfterMatch cenv cgbuf eenv afterJoin stackAfterJoin sequelAfterJoin
Fake)
| Expr.Let (bind, (Expr.Match (spBind, exprm, tree, targets, m, ty) as nextExpr), _, _) ->
ProcessSequencePointForExpr cenv cgbuf spExpr successExpr
let eenv, spBody, endScope = ProcessSequencePointForBinding cenv cgbuf eenv spExpr bind
ProcessSequencePointForExpr cenv cgbuf spBody nextExpr
GenMatch cenv cgbuf eenv (spBind, exprm, tree, targets, m, ty) (EndLocalScope(sequel, endScope)) (contf >> fun _ ->
GenSequelAfterMatch cenv cgbuf eenv afterJoin stackAfterJoin sequelAfterJoin
Fake)
| _ ->
GenExpr cenv cgbuf eenvAtTarget spExpr successExpr sequel
GenSequelAfterMatch cenv cgbuf eenv afterJoin stackAfterJoin sequelAfterJoin
contf Fake
| _ ->
GenExpr cenv cgbuf eenvAtTarget spExpr successExpr sequel
CG.SetMarkToHere cgbuf afterJoin

//assert(cgbuf.GetCurrentStack() = stackAfterJoin) // REVIEW: Since gen_dtree* now sets stack, stack should be stackAfterJoin at this point...
CG.SetStack cgbuf stackAfterJoin
// If any values are left on the stack after the join then we're certainly going to do something with them
// For example, we may be about to execute a 'stloc' for
//
// let y2 = if System.DateTime.Now.Year < 2000 then 1 else 2
//
// or a 'stelem' for
//
// arr.[0] <- if System.DateTime.Now.Year > 2000 then 1 else 2
//
// In both cases, any instructions that come after this point will be falsely associated with the last branch of the control
// prior to the join point. This is base, e.g. see FSharp 1.0 bug 5155
if not (isNil stackAfterJoin) then
cgbuf.EmitStartOfHiddenCode()

GenSequel cenv eenv.cloc cgbuf sequelAfterJoin
GenSequelAfterMatch cenv cgbuf eenv afterJoin stackAfterJoin sequelAfterJoin
contf Fake

// Accumulate the decision graph as we go
and GenDecisionTreeAndTargets cenv cgbuf stackAtTargets eenv tree targets repeatSP sequel =
Expand Down Expand Up @@ -4950,7 +4969,7 @@ and GenPostponedDecisionTreeTargets cenv cgbuf stackAtTargets targetInfos sequel
let eenvAtTarget, spExpr, successExpr, sequel = GenDecisionTreeTarget cenv cgbuf stackAtTargets targetIdx targetInfo sequel
GenExpr cenv cgbuf eenvAtTarget spExpr successExpr sequel
}
|> Seq.exactlyOne
|> Seq.tryExactlyOne

and GenDecisionTreeTarget cenv cgbuf stackAtTargets _targetIdx (targetMarkBeforeBinds, targetMarkAfterBinds, eenvAtTarget, successExpr, spTarget, repeatSP, vs, binds, startScope, endScope) sequel =
CG.SetMarkToHere cgbuf targetMarkBeforeBinds
Expand Down

0 comments on commit 83bc428

Please sign in to comment.