Skip to content

Commit

Permalink
Merge pull request #3 from fable-compiler/resizelist
Browse files Browse the repository at this point in the history
[WIP] More optimization attempts
  • Loading branch information
ncave authored Nov 18, 2020
2 parents 2877fcd + 0e12796 commit bb07495
Show file tree
Hide file tree
Showing 5 changed files with 313 additions and 170 deletions.
10 changes: 10 additions & 0 deletions build.fsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,21 @@ let buildLibrary() =

let watchLibrary() =
let libDir = "src/fable-library"
let buildDir = fullPath "build/fable-library"
printfn "Watching %s..." libDir
chokidar
.watch(libDir)
.on("change", fun _ -> buildLibrary())
|> ignore

// runFableWithArgs ("watch " + libDir) [
// "--outDir " + buildDir
// "--fableLib " + buildDir
// "--exclude Fable.Core"
// "--define FX_NO_BIGINT"
// "--define FABLE_LIBRARY"
// ]

let buildLibraryTs() =
let projectDir = "src/fable-library"
let buildDirTs = "build/fable-library-ts"
Expand Down Expand Up @@ -160,6 +169,7 @@ let testJsFast() =
]

runFableWithArgs "src/fable-compiler-js/src" [
"--forcePkgs"
"--exclude Fable.Core"
"--define LOCAL_TEST"
]
Expand Down
52 changes: 19 additions & 33 deletions src/Fable.Transforms/Fable2Babel.fs
Original file line number Diff line number Diff line change
Expand Up @@ -835,9 +835,7 @@ module Util =
let rec checkCrossRefs tempVars allArgs = function
| [] -> tempVars
| (argId, _arg)::rest ->
let found = allArgs |> List.exists (FableTransforms.deepExists (function
| Fable.IdentExpr i -> argId = i.Name
| _ -> false))
let found = allArgs |> List.exists (FableTransforms.isIdentUsed argId)
let tempVars =
if found then
let tempVarName = getUniqueNameInDeclarationScope ctx (argId + "_tmp")
Expand Down Expand Up @@ -907,36 +905,24 @@ module Util =
// | Fable.NewList (headAndTail, _) when List.contains "FABLE_LIBRARY" com.Options.Define ->
// makeList com ctx r headAndTail
// Optimization for bundle size: compile list literals as List.ofArray
| Replacements.ListLiteral(exprs, t) ->
[|List.rev exprs |> makeArray com ctx|]
|> libCall com ctx r "List" "newList"
// match exprs with
// | [] -> libCall com ctx r "List" "empty" [||]
// | [TransformExpr com ctx expr] -> libCall com ctx r "List" "singleton" [|expr|]
// | exprs -> [|makeArray com ctx exprs|] |> libCall com ctx r "List" "ofArray"
| Fable.NewList (headAndTail, _) ->
match headAndTail with
| None -> libCall com ctx r "List" "empty" [||]
| Some(TransformExpr com ctx head, TransformExpr com ctx tail) ->
let rec getItems acc = function
| None -> List.rev acc, None
| Some(head, Fable.Value(Fable.NewList(tail, _),_)) -> getItems (head::acc) tail
| Some(head, tail) -> List.rev (head::acc), Some tail
match getItems [] headAndTail with
| [], None ->
libCall com ctx r "List" "empty" [||]
| [TransformExpr com ctx expr], None ->
libCall com ctx r "List" "singleton" [|expr|]
| exprs, None ->
[|List.rev exprs |> makeArray com ctx|]
|> libCall com ctx r "List" "newList"
| [TransformExpr com ctx head], Some(TransformExpr com ctx tail) ->
libCall com ctx r "List" "cons" [|head; tail|]

// let rec getItems acc = function
// | None -> List.rev acc, None
// | Some(head, Fable.Value(Fable.NewList(tail, _),_)) -> getItems (head::acc) tail
// | Some(head, tail) -> List.rev (head::acc), Some tail
// match getItems [] headAndTail with
// | [], None ->
// libCall com ctx r "List" "empty" [||]
// | [TransformExpr com ctx expr], None ->
// libCall com ctx r "List" "singleton" [|expr|]
// | exprs, None ->
// [|makeArray com ctx exprs|]
// |> libCall com ctx r "List" "ofArray"
// | [TransformExpr com ctx head], Some(TransformExpr com ctx tail) ->
// libCall com ctx r "List" "cons" [|head; tail|]
// | exprs, Some(TransformExpr com ctx tail) ->
// [|makeArray com ctx exprs; tail|]
// |> libCall com ctx r "List" "ofArrayWithTail"
| exprs, Some(TransformExpr com ctx tail) ->
[|List.rev exprs |> makeArray com ctx; tail|]
|> libCall com ctx r "List" "newListWithTail"
| Fable.NewOption (value, t) ->
match value with
| Some (TransformExpr com ctx e) ->
Expand Down Expand Up @@ -1191,11 +1177,11 @@ module Util =

| Fable.ListHead ->
// get range (com.TransformAsExpr(ctx, fableExpr)) "head"
libCall com ctx range "List" "head" [|com.TransformAsExpr(ctx, fableExpr)|]
libCall com ctx range "List" "head_" [|com.TransformAsExpr(ctx, fableExpr)|]

| Fable.ListTail ->
// get range (com.TransformAsExpr(ctx, fableExpr)) "tail"
libCall com ctx range "List" "tail" [|com.TransformAsExpr(ctx, fableExpr)|]
libCall com ctx range "List" "tail_" [|com.TransformAsExpr(ctx, fableExpr)|]

| Fable.TupleIndex index ->
match fableExpr with
Expand Down
56 changes: 35 additions & 21 deletions src/Fable.Transforms/FableTransforms.fs
Original file line number Diff line number Diff line change
Expand Up @@ -149,23 +149,31 @@ let getSubExpressions = function
| DecisionTree(expr, targets) -> expr::(List.map snd targets)
| DecisionTreeSuccess(_, boundValues, _) -> boundValues

let deepExists (f: Expr -> bool) expr =
let rec deepExistsInner (exprs: ResizeArray<Expr>) =
let mutable found = false
let subExprs = ResizeArray()
for e in exprs do
if not found then
subExprs.AddRange(getSubExpressions e)
found <- f e
if found then true
elif subExprs.Count > 0 then deepExistsInner subExprs
else false
ResizeArray [|expr|] |> deepExistsInner
let deepExists arg (f: 'arg -> Expr -> bool * 'arg) expr =
let rec deepExistsInner arg = function
| [] -> false
| e::rest ->
let found, subarg = f arg e
if found then true
else
let subexprs = getSubExpressions e
let found = deepExistsInner subarg subexprs
if found then true
else deepExistsInner arg rest
deepExistsInner arg [expr]

let isIdentUsed identName expr =
expr |> deepExists (function
| IdentExpr i -> i.Name = identName
| _ -> false)
expr |> deepExists () (fun _ e ->
match e with
| IdentExpr i -> i.Name = identName, ()
| _ -> false, ())

let isIdentCaptured identName expr =
expr |> deepExists false (fun isClosure e ->
match e with
| Lambda _ | Delegate _ | ObjectExpr _ -> false, true
| IdentExpr i -> isClosure && i.Name = identName, isClosure
| _ -> false, isClosure)

let replaceValues replacements expr =
if Map.isEmpty replacements
Expand All @@ -189,16 +197,20 @@ let replaceNames replacements expr =

let countReferences limit identName body =
let mutable count = 0
body |> deepExists (function
body |> deepExists () (fun _ e ->
match e with
| IdentExpr id2 when id2.Name = identName ->
count <- count + 1
count > limit
| _ -> false) |> ignore
count > limit, ()
| _ -> false, ()) |> ignore
count

let canInlineArg identName value body =
not(canHaveSideEffects value)
&& countReferences 1 identName body <= 1
match value with
| IdentExpr i -> not i.IsMutable
| _ ->
not(canHaveSideEffects value)
&& countReferences 1 identName body <= 1

module private Transforms =
let (|LambdaOrDelegate|_|) = function
Expand Down Expand Up @@ -237,7 +249,9 @@ module private Transforms =
| [] -> replaceValues replacements body
| bindings -> Let(List.rev bindings, replaceValues replacements body)
match e with
// TODO: Other binary operations and numeric types, also recursive?
| IfThenElse(IfThenElse(condition1, condition2, Value(BoolConstant false, _), _), thenExpr, elseExpr, r) ->
IfThenElse(Operation(Logical(AST.LogicalAnd, condition1, condition2), Boolean, None), thenExpr, elseExpr, r)
// TODO: Other binary operations and numeric types
| Operation(Binary(AST.BinaryPlus, Value(StringConstant str1, r1), Value(StringConstant str2, r2)),_,_) ->
Value(StringConstant(str1 + str2), addRanges [r1; r2])
| Call(Delegate(args, body, _), info, _, _) when List.sameLength args info.Args ->
Expand Down
Loading

0 comments on commit bb07495

Please sign in to comment.