Skip to content

Commit ca69e01

Browse files
forkiKevinRansom
authored andcommitted
Cleanup Optimizer (#1519)
* Cleanup Optimizer Thank you for taking care of this. * We don't need to check the lenght here * Don't convert list to array multiple times * Only fold the Flatlist * Optimize FlatList away * Revert code duplication * match => if * cleanup * DevirtualizeApplication doesn't need optimized Expression
1 parent 85f3a40 commit ca69e01

File tree

3 files changed

+99
-90
lines changed

3 files changed

+99
-90
lines changed

src/absil/illib.fs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -780,6 +780,7 @@ module NameMap =
780780
let exists f m = Map.foldBack (fun x y sofar -> sofar || f x y) m false
781781
let ofKeyedList f l = List.foldBack (fun x acc -> Map.add (f x) x acc) l Map.empty
782782
let ofList l : NameMap<'T> = Map.ofList l
783+
let ofSeq l : NameMap<'T> = Map.ofSeq l
783784
let ofFlatList (l:FlatList<_>) : NameMap<'T> = FlatList.toMap l
784785
let toList (l: NameMap<'T>) = Map.toList l
785786
let layer (m1 : NameMap<'T>) m2 = Map.foldBack Map.add m1 m2

src/fsharp/FlatList.fs

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -198,38 +198,38 @@ type internal FlatList<'T> ='T list
198198
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
199199
module internal FlatList =
200200
let empty<'T> : 'T list = []
201-
let collect (f: 'T -> FlatList<'T>) (x:FlatList<_>) = List.collect f x
202-
let exists f (x:FlatList<_>) = List.exists f x
203-
let filter f (x:FlatList<_>) = List.filter f x
204-
let fold f acc (x:FlatList<_>) = List.fold f acc x
205-
let fold2 f acc (x:FlatList<_>) (y:FlatList<_>) = List.fold2 f acc x y
206-
let foldBack f (x:FlatList<_>) acc = List.foldBack f x acc
207-
let foldBack2 f (x:FlatList<_>) (y:FlatList<_>) acc = List.foldBack2 f x y acc
208-
let map2 f (x:FlatList<_>) (y:FlatList<_>) = List.map2 f x y
209-
let forall f (x:FlatList<_>) = List.forall f x
210-
let forall2 f (x1:FlatList<_>) (x2:FlatList<_>) = List.forall2 f x1 x2
211-
let iter2 f (x1:FlatList<_>) (x2:FlatList<_>) = List.iter2 f x1 x2
212-
let partition f (x:FlatList<_>) = List.partition f x
213-
let (* inline *) sum (x:FlatList<int>) = List.sum x
214-
let (* inline *) sumBy (f: 'T -> int) (x:FlatList<'T>) = List.sumBy f x
215-
let unzip (x:FlatList<_>) = List.unzip x
216-
let physicalEquality (x:FlatList<_>) (y:FlatList<_>) = (LanguagePrimitives.PhysicalEquality x y)
217-
let tryFind f (x:FlatList<_>) = List.tryFind f x
218-
let concat (x:FlatList<_>) = List.concat x
219-
let isEmpty (x:FlatList<_>) = List.isEmpty x
220-
let one(x) = [x]
221-
let toMap (x:FlatList<_>) = Map.ofList x
222-
let length (x:FlatList<_>) = List.length x
223-
let map f (x:FlatList<_>) = List.map f x
224-
let mapi f (x:FlatList<_>) = List.mapi f x
225-
let iter f (x:FlatList<_>) = List.iter f x
226-
let iteri f (x:FlatList<_>) = List.iteri f x
227-
let toList (x:FlatList<_>) = x
228-
let ofSeq (x:seq<_>) = List.ofSeq x
229-
let append(l1 : FlatList<'T>) (l2 : FlatList<'T>) = List.append l1 l2
230-
let ofList(l) = l
231-
let init n f = List.init n f
232-
let zip (x:FlatList<_>) (y:FlatList<_>) = List.zip x y
201+
let inline collect (f: 'T -> FlatList<'T>) (x:FlatList<_>) = List.collect f x
202+
let inline exists f (x:FlatList<_>) = List.exists f x
203+
let inline filter f (x:FlatList<_>) = List.filter f x
204+
let inline fold f acc (x:FlatList<_>) = List.fold f acc x
205+
let inline fold2 f acc (x:FlatList<_>) (y:FlatList<_>) = List.fold2 f acc x y
206+
let inline foldBack f (x:FlatList<_>) acc = List.foldBack f x acc
207+
let inline foldBack2 f (x:FlatList<_>) (y:FlatList<_>) acc = List.foldBack2 f x y acc
208+
let inline map2 f (x:FlatList<_>) (y:FlatList<_>) = List.map2 f x y
209+
let inline forall f (x:FlatList<_>) = List.forall f x
210+
let inline forall2 f (x1:FlatList<_>) (x2:FlatList<_>) = List.forall2 f x1 x2
211+
let inline iter2 f (x1:FlatList<_>) (x2:FlatList<_>) = List.iter2 f x1 x2
212+
let inline partition f (x:FlatList<_>) = List.partition f x
213+
let inline sum (x:FlatList<int>) = List.sum x
214+
let inline sumBy (f: 'T -> int) (x:FlatList<'T>) = List.sumBy f x
215+
let inline unzip (x:FlatList<_>) = List.unzip x
216+
let inline physicalEquality (x:FlatList<_>) (y:FlatList<_>) = (LanguagePrimitives.PhysicalEquality x y)
217+
let inline tryFind f (x:FlatList<_>) = List.tryFind f x
218+
let inline concat (x:FlatList<_>) = List.concat x
219+
let inline isEmpty (x:FlatList<_>) = List.isEmpty x
220+
let inline one(x) = [x]
221+
let inline toMap (x:FlatList<_>) = Map.ofList x
222+
let inline length (x:FlatList<_>) = List.length x
223+
let inline map f (x:FlatList<_>) = List.map f x
224+
let inline mapi f (x:FlatList<_>) = List.mapi f x
225+
let inline iter f (x:FlatList<_>) = List.iter f x
226+
let inline iteri f (x:FlatList<_>) = List.iteri f x
227+
let inline toList (x:FlatList<_>) = x
228+
let inline ofSeq (x:seq<_>) = List.ofSeq x
229+
let inline append(l1 : FlatList<'T>) (l2 : FlatList<'T>) = List.append l1 l2
230+
let inline ofList(l) = l
231+
let inline init n f = List.init n f
232+
let inline zip (x:FlatList<_>) (y:FlatList<_>) = List.zip x y
233233
#endif
234234

235235
#if FLAT_LIST_AS_ARRAY

src/fsharp/Optimizer.fs

Lines changed: 66 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -467,18 +467,20 @@ let rec BindValsInModuleOrNamespace cenv (mval:LazyModuleInfo) env =
467467
let env = (env, mval.ValInfos.Entries) ||> Seq.fold (fun env (v:ValRef, vval) -> BindExternalLocalVal cenv v.Deref vval env)
468468
env
469469

470-
let BindInternalValToUnknown cenv v env =
470+
let inline BindInternalValToUnknown cenv v env =
471471
#if CHECKED
472472
BindInternalLocalVal cenv v UnknownValue env
473473
#else
474-
ignore (cenv,v)
474+
ignore cenv
475+
ignore v
475476
env
476477
#endif
477-
let BindInternalValsToUnknown cenv vs env =
478+
let inline BindInternalValsToUnknown cenv vs env =
478479
#if CHECKED
479480
List.foldBack (BindInternalValToUnknown cenv) vs env
480481
#else
481-
ignore (cenv,vs)
482+
ignore cenv
483+
ignore vs
482484
env
483485
#endif
484486

@@ -568,9 +570,11 @@ let GetInfoForNonLocalVal cenv env (vref:ValRef) =
568570

569571
let GetInfoForVal cenv env m (vref:ValRef) =
570572
let res =
571-
match vref.IsLocalRef with
572-
| true -> GetInfoForLocalValue cenv env vref.binding m
573-
| false -> GetInfoForNonLocalVal cenv env vref
573+
if vref.IsLocalRef then
574+
GetInfoForLocalValue cenv env vref.binding m
575+
else
576+
GetInfoForNonLocalVal cenv env vref
577+
574578
check (* "its stored value was incomplete" m *) vref res |> ignore
575579
res
576580

@@ -2032,16 +2036,15 @@ and OptimizeFastIntegerForLoop cenv env (spStart,v,e1,dir,e2,e3,m) =
20322036
//-------------------------------------------------------------------------
20332037

20342038
and OptimizeLetRec cenv env (binds,bodyExpr,m) =
2035-
let vs = binds |> FlatList.map (fun v -> v.Var) in
2039+
let vs = binds |> FlatList.map (fun v -> v.Var)
20362040
let env = BindInternalValsToUnknown cenv vs env
20372041
let binds',env = OptimizeBindings cenv true env binds
20382042
let bodyExpr',einfo = OptimizeExpr cenv env bodyExpr
20392043
// REVIEW: graph analysis to determine which items are unused
20402044
// Eliminate any unused bindings, as in let case
20412045
let binds'',bindinfos =
20422046
let fvs0 = freeInExpr CollectLocals bodyExpr'
2043-
let fvsN = FlatList.map (fst >> freeInBindingRhs CollectLocals) binds'
2044-
let fvs = FlatList.fold unionFreeVars fvs0 fvsN
2047+
let fvs = FlatList.fold (fun acc x -> unionFreeVars acc (fst x |> freeInBindingRhs CollectLocals)) fvs0 binds'
20452048
SplitValuesByIsUsedOrHasEffect cenv (fun () -> fvs.FreeLocals) binds'
20462049
// Trim out any optimization info that involves escaping values
20472050
let evalue' = AbstractExprInfoByVars (FlatList.toList vs,[]) einfo.Info
@@ -2206,7 +2209,7 @@ and TryOptimizeVal cenv env (mustInline,valInfoForVal,m) =
22062209
| SizeValue (_,detail) -> TryOptimizeVal cenv env (mustInline,detail,m)
22072210
| ValValue (v',detail) ->
22082211
// Inline values bound to other values immediately
2209-
match TryOptimizeVal cenv env (mustInline,detail,m) with
2212+
match TryOptimizeVal cenv env (mustInline,detail,m) with
22102213
// Prefer to inline using the more specific info if possible
22112214
| Some e -> Some e
22122215
//If the more specific info didn't reveal an inline then use the value
@@ -2300,9 +2303,9 @@ and TakeAddressOfStructArgumentIfNeeded cenv (vref:ValRef) ty args m =
23002303
wrap, (objArgAddress::rest)
23012304
| _ ->
23022305
// no wrapper, args stay the same
2303-
(fun x -> x), args
2306+
id, args
23042307
else
2305-
(fun x -> x), args
2308+
id, args
23062309

23072310
and DevirtualizeApplication cenv env (vref:ValRef) ty tyargs args m =
23082311
let wrap,args = TakeAddressOfStructArgumentIfNeeded cenv vref ty args m
@@ -2579,50 +2582,51 @@ and TryInlineApplication cenv env (_f0',finfo) (tyargs: TType list,args: Expr li
25792582
//-------------------------------------------------------------------------
25802583

25812584
and OptimizeApplication cenv env (f0,f0ty,tyargs,args,m) =
2582-
let f0',finfo = OptimizeExpr cenv env f0
25832585
// trying to devirtualize
25842586
match TryDevirtualizeApplication cenv env (f0,tyargs,args,m) with
25852587
| Some res ->
25862588
// devirtualized
25872589
res
25882590
| None ->
2589-
2590-
match TryInlineApplication cenv env (f0',finfo) (tyargs,args,m) with
2591+
let newf0,finfo = OptimizeExpr cenv env f0
2592+
match TryInlineApplication cenv env (newf0,finfo) (tyargs,args,m) with
25912593
| Some res ->
25922594
// inlined
25932595
res
25942596
| None ->
25952597

25962598
let shapes =
2597-
match f0' with
2598-
| Expr.Val(vref,_,_) when Option.isSome vref.ValReprInfo ->
2599-
let (ValReprInfo(_kinds,detupArgsL,_)) = Option.get vref.ValReprInfo
2600-
let nargs = (args.Length)
2601-
let nDetupArgsL = detupArgsL.Length
2602-
let nShapes = min nargs nDetupArgsL
2603-
let detupArgsShapesL =
2604-
List.take nShapes detupArgsL |> List.map (fun detupArgs ->
2605-
match detupArgs with
2606-
| [] | [_] -> UnknownValue
2607-
| _ -> TupleValue(Array.ofList (List.map (fun _ -> UnknownValue) detupArgs)))
2608-
detupArgsShapesL @ List.replicate (nargs - nShapes) UnknownValue
2609-
2610-
| _ -> args |> List.map (fun _ -> UnknownValue)
2611-
2612-
let args',arginfos = OptimizeExprsThenReshapeAndConsiderSplits cenv env (List.zip shapes args)
2599+
match newf0 with
2600+
| Expr.Val(vref,_,_) ->
2601+
match vref.ValReprInfo with
2602+
| Some(ValReprInfo(_,detupArgsL,_)) ->
2603+
let nargs = args.Length
2604+
let nDetupArgsL = detupArgsL.Length
2605+
let nShapes = min nargs nDetupArgsL
2606+
let detupArgsShapesL =
2607+
List.take nShapes detupArgsL
2608+
|> List.map (fun detupArgs ->
2609+
match detupArgs with
2610+
| [] | [_] -> UnknownValue
2611+
| _ -> TupleValue(Array.ofList (List.map (fun _ -> UnknownValue) detupArgs)))
2612+
List.zip (detupArgsShapesL @ List.replicate (nargs - nShapes) UnknownValue) args
2613+
| _ -> args |> List.map (fun arg -> UnknownValue,arg)
2614+
| _ -> args |> List.map (fun arg -> UnknownValue,arg)
2615+
2616+
let newArgs,arginfos = OptimizeExprsThenReshapeAndConsiderSplits cenv env shapes
26132617
// beta reducing
2614-
let expr' = MakeApplicationAndBetaReduce cenv.g (f0',f0ty, [tyargs],args',m)
2618+
let newExpr = MakeApplicationAndBetaReduce cenv.g (newf0,f0ty, [tyargs],newArgs,m)
26152619

2616-
match f0', expr' with
2620+
match newf0, newExpr with
26172621
| (Expr.Lambda _ | Expr.TyLambda _), Expr.Let _ ->
26182622
// we beta-reduced, hence reoptimize
2619-
OptimizeExpr cenv env expr'
2623+
OptimizeExpr cenv env newExpr
26202624
| _ ->
26212625
// regular
26222626

26232627
// Determine if this application is a critical tailcall
26242628
let mayBeCriticalTailcall =
2625-
match f0' with
2629+
match newf0 with
26262630
| KnownValApp(vref,_typeArgs,otherArgs) ->
26272631

26282632
// Check if this is a call to a function of known arity that has been inferred to not be a critical tailcall when used as a direct call
@@ -2633,25 +2637,25 @@ and OptimizeApplication cenv env (f0,f0ty,tyargs,args,m) =
26332637
(let valInfoForVal = GetInfoForVal cenv env m vref in valInfoForVal.ValMakesNoCriticalTailcalls) ||
26342638
(match env.functionVal with | None -> false | Some (v,_) -> valEq vref.Deref v)
26352639
if doesNotMakeCriticalTailcall then
2636-
let numArgs = otherArgs.Length + args'.Length
2640+
let numArgs = otherArgs.Length + newArgs.Length
26372641
match vref.ValReprInfo with
26382642
| Some i -> numArgs > i.NumCurriedArgs
26392643
| None ->
26402644
match env.functionVal with
26412645
| Some (_v,i) -> numArgs > i.NumCurriedArgs
2642-
| None -> true // over-applicaiton of a known function, which presumably returns a function. This counts as an indirect call
2646+
| None -> true // over-application of a known function, which presumably returns a function. This counts as an indirect call
26432647
else
26442648
true // application of a function that may make a critical tailcall
26452649

26462650
| _ ->
26472651
// All indirect calls (calls to unknown functions) are assumed to be critical tailcalls
26482652
true
26492653

2650-
expr', { TotalSize=finfo.TotalSize + AddTotalSizes arginfos
2651-
FunctionSize=finfo.FunctionSize + AddFunctionSizes arginfos
2652-
HasEffect=true
2653-
MightMakeCriticalTailcall = mayBeCriticalTailcall
2654-
Info=ValueOfExpr expr' }
2654+
newExpr, { TotalSize=finfo.TotalSize + AddTotalSizes arginfos
2655+
FunctionSize=finfo.FunctionSize + AddFunctionSizes arginfos
2656+
HasEffect=true
2657+
MightMakeCriticalTailcall = mayBeCriticalTailcall
2658+
Info=ValueOfExpr newExpr }
26552659

26562660
//-------------------------------------------------------------------------
26572661
// Optimize/analyze a lambda expression
@@ -2661,7 +2665,6 @@ and OptimizeLambdas (vspec: Val option) cenv env topValInfo e ety =
26612665
match e with
26622666
| Expr.Lambda (lambdaId,_,_,_,_,m,_)
26632667
| Expr.TyLambda(lambdaId,_,_,m,_) ->
2664-
let isTopLevel = Option.isSome vspec && vspec.Value.IsCompiledAsTopLevel
26652668
let tps,ctorThisValOpt,baseValOpt,vsl,body,bodyty = IteratedAdjustArityOfLambda cenv.g cenv.amap topValInfo e
26662669
let env = { env with functionVal = (match vspec with None -> None | Some v -> Some (v,topValInfo)) }
26672670
let env = Option.foldBack (BindInternalValToUnknown cenv) ctorThisValOpt env
@@ -2709,13 +2712,18 @@ and OptimizeLambdas (vspec: Val option) cenv env topValInfo e ety =
27092712
| Some baseVal ->
27102713
let fvs = freeInExpr CollectLocals body'
27112714
if fvs.UsesMethodLocalConstructs || fvs.FreeLocals.Contains baseVal then
2712-
UnknownValue
2715+
UnknownValue
27132716
else
27142717
let expr2 = mkMemberLambdas m tps ctorThisValOpt None vsl (body',bodyty)
27152718
CurriedLambdaValue (lambdaId,arities,bsize,expr2,ety)
27162719

27172720

2718-
expr', { TotalSize=bsize + (if isTopLevel then methodDefnTotalSize else closureTotalSize) (* estimate size of new syntactic closure - expensive, in contrast to a method *)
2721+
let estimatedSize =
2722+
match vspec with
2723+
| Some v when v.IsCompiledAsTopLevel -> methodDefnTotalSize
2724+
| _ -> closureTotalSize
2725+
2726+
expr', { TotalSize=bsize + estimatedSize (* estimate size of new syntactic closure - expensive, in contrast to a method *)
27192727
FunctionSize=1
27202728
HasEffect=false
27212729
MightMakeCriticalTailcall = false
@@ -2739,9 +2747,10 @@ and OptimizeExprsThenConsiderSplits cenv env exprs =
27392747
| [] -> NoExprs
27402748
| _ -> OptimizeList (OptimizeExprThenConsiderSplit cenv env) exprs
27412749

2742-
and OptimizeFlatExprsThenConsiderSplits cenv env (exprs:FlatExprs) =
2743-
if FlatList.isEmpty exprs then NoFlatExprs
2744-
else OptimizeFlatList (OptimizeExprThenConsiderSplit cenv env) exprs
2750+
and OptimizeFlatExprsThenConsiderSplits cenv env exprs =
2751+
match exprs with
2752+
| [] -> NoFlatExprs
2753+
| _ -> OptimizeFlatList (OptimizeExprThenConsiderSplit cenv env) exprs
27452754

27462755
and OptimizeExprThenReshapeAndConsiderSplit cenv env (shape,e) =
27472756
OptimizeExprThenConsiderSplit cenv env (ReshapeExpr cenv (shape,e))
@@ -2753,7 +2762,8 @@ and ReshapeExpr cenv (shape,e) =
27532762
match shape,e with
27542763
| TupleValue(subshapes), Expr.Val(_vref,_vFlags,m) ->
27552764
let tinst = destRefTupleTy cenv.g (tyOfExpr cenv.g e)
2756-
mkRefTupled cenv.g m (List.mapi (fun i subshape -> ReshapeExpr cenv (subshape,mkTupleFieldGet cenv.g (tupInfoRef,e,tinst,i,m))) (Array.toList subshapes)) tinst
2765+
let subshapes = Array.toList subshapes
2766+
mkRefTupled cenv.g m (List.mapi (fun i subshape -> ReshapeExpr cenv (subshape,mkTupleFieldGet cenv.g (tupInfoRef,e,tinst,i,m))) subshapes) tinst
27572767
| _ ->
27582768
e
27592769

@@ -2868,8 +2878,7 @@ and OptimizeDecisionTree cenv env m x =
28682878
let info = CombineValueInfosUnknown [rinfo;binfo]
28692879
// try to fold the let-binding into a single result expression
28702880
match rest with
2871-
| TDSuccess(es,n) when es.Length = 1 ->
2872-
let e = es.[0]
2881+
| TDSuccess([e],n) ->
28732882
let e,_adjust = TryEliminateLet cenv env bind e m
28742883
TDSuccess(FlatList.one e,n),info
28752884
| _ ->
@@ -3072,7 +3081,7 @@ and OptimizeModuleExpr cenv env x =
30723081
new ModuleOrNamespaceType(kind=mtyp.ModuleOrNamespaceKind,
30733082
vals= (mtyp.AllValsAndMembers |> QueueList.filter (Zset.memberOf deadSet >> not)),
30743083
entities= mtyp.AllEntities)
3075-
mtyp.ModuleAndNamespaceDefinitions |> List.iter (fun mspec -> elimModSpec mspec)
3084+
mtyp.ModuleAndNamespaceDefinitions |> List.iter elimModSpec
30763085
mty
30773086
and elimModSpec (mspec:ModuleOrNamespace) =
30783087
let mtyp = elimModTy mspec.ModuleOrNamespaceType
@@ -3116,13 +3125,12 @@ and OptimizeModuleDef cenv (env,bindInfosColl) x =
31163125
let binds = minfos |> List.choose (function Choice1Of2 (x,_) -> Some x | _ -> None)
31173126
let binfos = minfos |> List.choose (function Choice1Of2 (_,x) -> Some x | _ -> None)
31183127
let minfos = minfos |> List.choose (function Choice2Of2 x -> Some x | _ -> None)
3119-
31203128

3121-
(* REVIEW: Eliminate let bindings on the way back up *)
3129+
(* REVIEW: Eliminate let bindings on the way back up *)
31223130
(TMDefRec(isRec,tycons,mbinds,m),
3123-
notlazy { ValInfos= ValInfos(FlatList.map2 (fun bind binfo -> mkValBind bind (mkValInfo binfo bind.Var)) binds binfos)
3131+
notlazy { ValInfos = ValInfos(FlatList.map2 (fun bind binfo -> mkValBind bind (mkValInfo binfo bind.Var)) binds binfos)
31243132
ModuleOrNamespaceInfos = NameMap.ofList minfos}),
3125-
(env,bindInfosColl)
3133+
(env,bindInfosColl)
31263134
| TMAbstract(mexpr) ->
31273135
let mexpr,info = OptimizeModuleExpr cenv env mexpr
31283136
let env = BindValsInModuleOrNamespace cenv info env
@@ -3132,7 +3140,7 @@ and OptimizeModuleDef cenv (env,bindInfosColl) x =
31323140
(* REVIEW: Eliminate unused let bindings from modules *)
31333141
(TMDefLet(bind',m),
31343142
notlazy { ValInfos=ValInfos [mkValBind bind (mkValInfo binfo bind.Var)]
3135-
ModuleOrNamespaceInfos = NameMap.ofList []}),
3143+
ModuleOrNamespaceInfos = NameMap.empty }),
31363144
(env ,([bindInfo]::bindInfosColl))
31373145

31383146
| TMDefDo(e,m) ->

0 commit comments

Comments
 (0)