@@ -23,6 +23,7 @@ open FSharp.Compiler.Text.LayoutRender
2323open FSharp.Compiler .Text .TaggedText
2424open FSharp.Compiler .TypedTree
2525open FSharp.Compiler .TypedTreeBasics
26+ open FSharp.Compiler .Xml
2627open FSharp.Compiler .TypedTreeOps
2728open FSharp.Compiler .TypedTreeOps .DebugPrint
2829open FSharp.Compiler .TypedTreePickle
@@ -327,6 +328,8 @@ type OptimizationSettings =
327328 reportTotalSizes : bool
328329
329330 processingMode : OptimizationProcessingMode
331+
332+ inlineNamedFunctions: bool
330333 }
331334
332335 static member Defaults =
@@ -344,6 +347,7 @@ type OptimizationSettings =
344347 reportHasEffect = false
345348 reportTotalSizes = false
346349 processingMode = OptimizationProcessingMode.Parallel
350+ inlineNamedFunctions = false
347351 }
348352
349353 /// Determines if JIT optimizations are enabled
@@ -432,6 +436,8 @@ type cenv =
432436 stackGuard: StackGuard
433437
434438 realsig: bool
439+
440+ specializedInlineVals: HashMultiMap < Stamp , TType * Val * Expr >
435441 }
436442
437443 override x.ToString () = " <cenv>"
@@ -1692,6 +1698,7 @@ let TryEliminateBinding cenv _env bind e2 _m =
16921698 not vspec1.IsCompilerGenerated then
16931699 None
16941700 elif vspec1.IsFixed then None
1701+ elif vspec1.InlineInfo = ValInline.InlinedDefinition then None
16951702 elif vspec1.LogicalName.StartsWithOrdinal stackVarPrefix ||
16961703 vspec1.LogicalName.Contains suffixForVariablesThatMayNotBeEliminated then None
16971704 else
@@ -3421,8 +3428,60 @@ and TryDevirtualizeApplication cenv env (f, tyargs, args, m) =
34213428 | _ -> None
34223429
34233430/// Attempt to inline an application of a known value at callsites
3424- and TryInlineApplication cenv env finfo ( tyargs : TType list , args : Expr list , m ) =
3431+ and TryInlineApplication cenv env finfo ( valExpr : Expr ) ( tyargs : TType list , args : Expr list , m ) =
34253432 let g = cenv.g
3433+
3434+ match cenv.settings.inlineNamedFunctions, stripExpr valExpr with
3435+ | false , Expr.Val( vref, _, _) when vref.ShouldInline ->
3436+ let origFinfo = GetInfoForValWithCheck cenv env m vref
3437+ match stripValue origFinfo.ValExprInfo with
3438+ | CurriedLambdaValue( origLambdaId, _, _, origLambda, origLambdaTy) when not ( Zset.contains origLambdaId env.dontInline) ->
3439+ let argsR = args |> List.map ( OptimizeExpr cenv env >> fst)
3440+ let info = { TotalSize = 1 ; FunctionSize = 1 ; HasEffect = true ; MightMakeCriticalTailcall = false ; Info = UnknownValue }
3441+
3442+ let canCallDirectly =
3443+ let hasNoTraits =
3444+ match vref.ValReprInfo with
3445+ | Some reprInfo ->
3446+ let tps , _ , _ , _ = GetValReprTypeInFSharpForm g reprInfo vref.Type m
3447+ GetTraitWitnessInfosOfTypars g 0 tps |> List.isEmpty
3448+ | None -> false
3449+
3450+ let hasNoFreeTyargs =
3451+ tyargs |> List.forall ( fun t -> ( freeInType CollectTyparsNoCaching t) .FreeTypars.IsEmpty) |> not
3452+
3453+ hasNoTraits || hasNoFreeTyargs
3454+
3455+ if canCallDirectly then
3456+ Some( mkApps g (( exprForValRef m vref, vref.Type), [ tyargs], argsR, m), info)
3457+ else
3458+ let f2R = CopyExprForInlining cenv true origLambda m
3459+ let specLambda = MakeApplicationAndBetaReduce g ( f2R, origLambdaTy, [ tyargs], [], m)
3460+ let specLambdaTy = tyOfExpr g specLambda
3461+
3462+ let debugVal , specLambdaR =
3463+ match cenv.specializedInlineVals.FindAll( origLambdaId) |> List.tryFind ( fun ( ty , _ , _ ) -> typeEquiv g ty specLambdaTy) with
3464+ | Some (_, v, body) -> v, body
3465+ | None ->
3466+
3467+ let specLambdaR , _ = OptimizeExpr cenv { env with dontInline = Zset.add origLambdaId env.dontInline } specLambda
3468+ let debugVal =
3469+ let name = $" <{vref.LogicalName}>__debug"
3470+ let valReprInfo = Some( InferValReprInfoOfExpr g AllowTypeDirectedDetupling.No specLambdaTy [] [] specLambdaR)
3471+
3472+ Construct.NewVal( name, m, None, specLambdaTy, Immutable, true , valReprInfo, taccessPublic, ValNotInRecScope, None,
3473+ NormalVal, [], ValInline.InlinedDefinition, XmlDoc.Empty, false , false , false , false , false , false , None,
3474+ ParentNone)
3475+
3476+ cenv.specializedInlineVals.Add( origLambdaId, ( specLambdaTy, debugVal, specLambdaR))
3477+ debugVal, specLambdaR
3478+
3479+ let callExpr = mkApps g (( exprForVal m debugVal, specLambdaTy), [], argsR, m)
3480+ Some( mkCompGenLet m debugVal specLambdaR callExpr, info)
3481+
3482+ | _ -> None
3483+ | _ ->
3484+
34263485 // Considering inlining app
34273486 match finfo.Info with
34283487 | StripLambdaValue ( lambdaId, arities, size, f2, f2ty) when
@@ -3621,7 +3680,7 @@ and OptimizeApplication cenv env (f0, f0ty, tyargs, args, m) =
36213680 OptimizeExpr cenv env remade
36223681 | Choice2Of2 ( newf0, remake) ->
36233682
3624- match TryInlineApplication cenv env finfo ( tyargs, args, m) with
3683+ match TryInlineApplication cenv env finfo f0 ( tyargs, args, m) with
36253684 | Some ( res, info) ->
36263685 // inlined
36273686 ( res |> remake), info
@@ -3869,6 +3928,10 @@ and OptimizeLambdas (vspec: Val option) cenv env valReprInfo expr exprTy =
38693928
38703929 // can't inline any values with semi-recursive object references to self or base
38713930 let value_ =
3931+ match vspec with
3932+ | Some v when v.InlineInfo = ValInline.InlinedDefinition -> UnknownValue
3933+ | _ ->
3934+
38723935 match baseValOpt with
38733936 | None -> CurriedLambdaValue ( lambdaId, arities, bsize, exprR, exprTy)
38743937 | Some baseVal ->
@@ -4403,6 +4466,7 @@ let OptimizeImplFile (settings, ccu, tcGlobals, tcVal, importMap, optEnv, isIncr
44034466 casApplied= Dictionary< Stamp, bool>()
44044467 stackGuard = StackGuard( " OptimizerStackGuardDepth" )
44054468 realsig = tcGlobals.realsig
4469+ specializedInlineVals = HashMultiMap( HashIdentity.Structural, true )
44064470 }
44074471
44084472 let env , _ , _ , _ as results = OptimizeImplFileInternal cenv optEnv isIncrementalFragment hidden mimpls
0 commit comments