Skip to content

Commit aefc4ce

Browse files
committed
Nested inline with different type args
1 parent 3b27d90 commit aefc4ce

1 file changed

Lines changed: 25 additions & 8 deletions

File tree

src/Compiler/Optimize/Optimizer.fs

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -454,8 +454,12 @@ type IncrementalOptimizationEnv =
454454
{ /// An identifier to help with name generation
455455
latestBoundId: Ident option
456456

457-
/// The set of lambda IDs we've inlined to reach this point. Helps to prevent recursive inlining
458-
dontInline: Zset<Unique>
457+
/// Prevents recursive inlining/specialization. Maps lambda ID to a list of specialized types
458+
/// currently being processed. An empty list means "block unconditionally" (used by normal
459+
/// inlining and non-concrete debug specialization). A non-empty list means "block only these
460+
/// specific type specializations" (used by concrete debug specialization, allowing different
461+
/// type instantiations of the same function to proceed).
462+
dontInline: Map<Stamp, TType list>
459463

460464
/// Recursively bound vars. If an sub-expression that is a candidate for method splitting
461465
/// contains any of these variables then don't split it, for fear of mucking up tailcalls.
@@ -479,7 +483,7 @@ type IncrementalOptimizationEnv =
479483

480484
static member Empty =
481485
{ latestBoundId = None
482-
dontInline = Zset.empty Int64.order
486+
dontInline = Map.empty
483487
typarInfos = []
484488
functionVal = None
485489
dontSplitVars = ValMap.Empty
@@ -3481,22 +3485,35 @@ and TryInlineApplication cenv env finfo (valExpr: Expr) (tyargs: TType list, arg
34813485

34823486
let origFinfo = GetInfoForValWithCheck cenv env m vref
34833487
match stripValue origFinfo.ValExprInfo with
3484-
| CurriedLambdaValue(origLambdaId, _, _, origLambda, origLambdaTy) when not (Zset.contains origLambdaId env.dontInline) ->
3488+
| CurriedLambdaValue(origLambdaId, _, _, origLambda, origLambdaTy) ->
34853489
let f2R = CopyExprForInlining cenv true origLambda m
34863490
let specLambda = MakeApplicationAndBetaReduce g (f2R, origLambdaTy, [tyargs], [], m)
34873491
let specLambdaTy = tyOfExpr g specLambda
34883492

3493+
// For concrete type args, only block the exact same (stamp, type) pair, allowing different
3494+
// type instantiations to proceed (e.g. sum<int, int->int> calling sum<int, int> in its body).
3495+
// For non-concrete type args, block unconditionally.
3496+
let shouldInline =
3497+
match Map.tryFind origLambdaId env.dontInline with
3498+
| Some tys -> not allTyargsAreConcrete || tys.IsEmpty || tys |> List.exists (typeEquiv g specLambdaTy)
3499+
| None -> false
3500+
3501+
if shouldInline then
3502+
None else
3503+
34893504
let specLambdaR =
34903505
if allTyargsAreConcrete then
34913506
match cenv.specializedInlineVals.FindAll(origLambdaId) |> List.tryFind (fun (ty, _) -> typeEquiv g ty specLambdaTy) with
34923507
| Some (_, body) -> copyExpr g CloneAll body
34933508
| None ->
34943509

3495-
let specLambdaR, _ = OptimizeExpr cenv { env with dontInline = Zset.add origLambdaId env.dontInline } specLambda
3510+
let existingTypes = defaultArg (Map.tryFind origLambdaId env.dontInline) []
3511+
let env = { env with dontInline = Map.add origLambdaId (specLambdaTy :: existingTypes) env.dontInline }
3512+
let specLambdaR, _ = OptimizeExpr cenv env specLambda
34963513
cenv.specializedInlineVals.Add(origLambdaId, (specLambdaTy, specLambdaR))
34973514
specLambdaR
34983515
else
3499-
let specLambdaR, _ = OptimizeExpr cenv { env with dontInline = Zset.add origLambdaId env.dontInline } specLambda
3516+
let specLambdaR, _ = OptimizeExpr cenv { env with dontInline = Map.add origLambdaId [] env.dontInline } specLambda
35003517
specLambdaR
35013518

35023519
let specLambdaR =
@@ -3537,7 +3554,7 @@ and TryInlineApplication cenv env finfo (valExpr: Expr) (tyargs: TType list, arg
35373554
cenv.settings.InlineLambdas &&
35383555
not finfo.HasEffect &&
35393556
// Don't inline recursively!
3540-
not (Zset.contains lambdaId env.dontInline) &&
3557+
not (Map.containsKey lambdaId env.dontInline) &&
35413558
(// Check the number of argument groups is enough to saturate the lambdas of the target.
35423559
(if tyargs |> List.exists (fun t -> match t with TType_measure _ -> false | _ -> true) then 1 else 0) + args.Length = arities &&
35433560
if size <= cenv.settings.lambdaInlineThreshold + args.Length then true
@@ -3609,7 +3626,7 @@ and TryInlineApplication cenv env finfo (valExpr: Expr) (tyargs: TType list, arg
36093626
// Inlining: beta reducing
36103627
let exprR = MakeApplicationAndBetaReduce g (f2R, f2ty, [tyargs], argsR, m)
36113628
// Inlining: reoptimizing
3612-
Some(OptimizeExpr cenv {env with dontInline= Zset.add lambdaId env.dontInline} exprR)
3629+
Some(OptimizeExpr cenv {env with dontInline = Map.add lambdaId [] env.dontInline} exprR)
36133630

36143631
| _ -> None
36153632

0 commit comments

Comments
 (0)