diff --git a/src/Compiler/CodeGen/IlxGen.fs b/src/Compiler/CodeGen/IlxGen.fs index 9f4a8b0b9d73..1047dfa4433e 100644 --- a/src/Compiler/CodeGen/IlxGen.fs +++ b/src/Compiler/CodeGen/IlxGen.fs @@ -2867,13 +2867,9 @@ and GenExprPreSteps (cenv: cenv) (cgbuf: CodeGenBuffer) eenv expr sequel = None match lowering with - | Some(LowerComputedCollectionExpressions.ComputedCollectionExprLowering.Expr initExpr) -> + | Some initExpr -> GenExpr cenv cgbuf eenv initExpr sequel true - | Some(LowerComputedCollectionExpressions.ComputedCollectionExprLowering.Either(branch1, branch2)) -> - GenExpr cenv cgbuf eenv branch1 (sequelIgnoreEndScopes sequel) - GenExpr cenv cgbuf eenv branch2 sequel - true | None -> let lowering = diff --git a/src/Compiler/Optimize/LowerComputedCollections.fs b/src/Compiler/Optimize/LowerComputedCollections.fs index ed28282b768d..908a54a7551a 100644 --- a/src/Compiler/Optimize/LowerComputedCollections.fs +++ b/src/Compiler/Optimize/LowerComputedCollections.fs @@ -269,86 +269,79 @@ let (|Int32Range|_|) g expr = | ValApp g g.range_int32_op_vref ([], [start; Expr.Const (value = Const.Int32 1); finish], _), _ -> ValueSome (start, finish) | _ -> ValueNone -[] -type ComputedCollectionExprLowering = - | Expr of initExpr: Expr - | Either of branch1: Expr * branch2: Expr - let LowerComputedListOrArrayExpr tcVal (g: TcGlobals) amap overallExpr = // If ListCollector is in FSharp.Core then this optimization kicks in if g.ListCollector_tcr.CanDeref then - let constListSizeThreshold = 100 - let constArrayBytesThreshold = 1024 + //let constListSizeThreshold = 100 + //let constArrayBytesThreshold = 1024 match overallExpr with // [5..1] → [] | SeqToList g (OptionalCoerce (OptionalSeq g amap (ConstInt32Range g (start, finish))), m) when start > finish -> - Some (ComputedCollectionExprLowering.Expr (mkUnionCaseExpr (g.nil_ucref, [g.int32_ty], [], m))) + Some (mkUnionCaseExpr (g.nil_ucref, [g.int32_ty], [], m)) - // [1..5] → [1; 2; 3; 4; 5] ≡ 1 :: 2 :: 3 :: 4 :: 5 :: [] - | SeqToList g (OptionalCoerce (OptionalSeq g amap (ConstInt32Range g (start, finish))), _) when - finish - start < constListSizeThreshold - -> - // … :: … :: … - let rec conses acc n = - if n < start then acc - else conses (mkCons g g.int32_ty (Expr.Const (Const.Int32 n, Text.Range.range0, g.int32_ty)) acc) (n - 1) + //// [1..5] → [1; 2; 3; 4; 5] ≡ 1 :: 2 :: 3 :: 4 :: 5 :: [] + //| SeqToList g (OptionalCoerce (OptionalSeq g amap (ConstInt32Range g (start, finish))), _) when + // finish - start < constListSizeThreshold + // -> + // // … :: … :: … + // let rec conses acc n = + // if n < start then acc + // else conses (mkCons g g.int32_ty (Expr.Const (Const.Int32 n, Text.Range.range0, g.int32_ty)) acc) (n - 1) - Some (ComputedCollectionExprLowering.Expr (conses (mkNil g Text.Range.range0 g.int32_ty) finish)) + // Some (conses (mkNil g Text.Range.range0 g.int32_ty) finish) // [start..finish] → if start <= finish then List.init (finish - start + 1) ((+) start) else [] | SeqToList g (OptionalCoerce (OptionalSeq g amap (Int32Range g (start, finish))), m) -> let diff = mkAsmExpr ([AI_sub], [], [finish; start], [g.int32_ty], Text.Range.range0) let range = mkAsmExpr ([AI_add], [], [diff; mkOne g Text.Range.range0], [g.int32_ty], Text.Range.range0) + let zero = mkZero g Text.Range.range0 + let rangeXorZero = mkAsmExpr ([AI_xor], [], [range; zero], [g.int32_ty], Text.Range.range0) + let negRangeLtZero = mkAsmExpr ([AI_neg], [], [mkAsmExpr ([AI_clt], [], [range; zero], [g.int32_ty], Text.Range.range0)], [g.int32_ty], Text.Range.range0) + let anded = mkAsmExpr ([AI_and], [], [rangeXorZero; negRangeLtZero], [g.int32_ty], Text.Range.range0) + let range = mkAsmExpr ([AI_xor], [], [range; anded], [g.int32_ty], Text.Range.range0) let v, e = mkCompGenLocal Text.Range.range0 "i" g.int32_ty let body = mkAsmExpr ([AI_add], [], [start; e], [g.int32_ty], Text.Range.range0) let initializer = mkLambda Text.Range.range0 v (body, g.int32_ty) - let init = mkCallListInit g Text.Range.range0 g.int32_ty range initializer - - let emptyLabel = generateCodeLabel () - let empty = mkLabelled Text.Range.range0 emptyLabel (mkNil g Text.Range.range0 g.int32_ty) - let breakToEmptyIfStartGtFinish = mkAsmExpr ([I_brcmp (BI_bgt, emptyLabel)], [], [start; finish], [mkListTy g g.int32_ty], Text.Range.range0) - - Some (ComputedCollectionExprLowering.Either (mkAsmExpr ([], [], [breakToEmptyIfStartGtFinish; init], [mkListTy g g.int32_ty], m), empty)) + Some (mkCallListInit g m g.int32_ty range initializer) | SeqToList g (OptionalCoerce (OptionalSeq g amap (overallSeqExpr, overallElemTy)), m) -> let collectorTy = g.mk_ListCollector_ty overallElemTy LowerComputedListOrArraySeqExpr tcVal g amap m collectorTy overallSeqExpr - |> Option.map ComputedCollectionExprLowering.Expr // [|5..1|] → [||] | SeqToArray g (OptionalCoerce (OptionalSeq g amap (ConstInt32Range g (start, finish))), m) when start > finish -> - Some (ComputedCollectionExprLowering.Expr (mkArray (g.int32_ty, [], m))) + Some (mkArray (g.int32_ty, [], m)) - // [|1..5|] → [|1; 2; 3; 4; 5|] - | SeqToArray g (OptionalCoerce (OptionalSeq g amap (ConstInt32Range g (start, finish))), m) when - (finish - start) * sizeof < constArrayBytesThreshold - -> - Some (ComputedCollectionExprLowering.Expr (mkArray (g.int32_ty, [for n in start..finish -> Expr.Const (Const.Int32 n, Text.Range.range0, g.int32_ty)], m))) + //// [|1..5|] → [|1; 2; 3; 4; 5|] + //| SeqToArray g (OptionalCoerce (OptionalSeq g amap (ConstInt32Range g (start, finish))), m) when + // (finish - start) * sizeof < constArrayBytesThreshold + // -> + // Some (mkArray (g.int32_ty, [for n in start..finish -> Expr.Const (Const.Int32 n, Text.Range.range0, g.int32_ty)], m)) // [|start..finish|] → if start <= finish then Array.init (finish - start + 1) ((+) start) else [||] | SeqToArray g (OptionalCoerce (OptionalSeq g amap (Int32Range g (start, finish))), m) -> let diff = mkAsmExpr ([AI_sub], [], [finish; start], [g.int32_ty], Text.Range.range0) let range = mkAsmExpr ([AI_add], [], [diff; mkOne g Text.Range.range0], [g.int32_ty], Text.Range.range0) + let zero = mkZero g Text.Range.range0 + let rangeXorZero = mkAsmExpr ([AI_xor], [], [range; zero], [g.int32_ty], Text.Range.range0) + let negRangeLtZero = mkAsmExpr ([AI_neg], [], [mkAsmExpr ([AI_clt], [], [range; zero], [g.int32_ty], Text.Range.range0)], [g.int32_ty], Text.Range.range0) + let anded = mkAsmExpr ([AI_and], [], [rangeXorZero; negRangeLtZero], [g.int32_ty], Text.Range.range0) + // range ^ ((range ^ 0) & -(range < 0)) + // https://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax + let range = mkAsmExpr ([AI_xor], [], [range; anded], [g.int32_ty], Text.Range.range0) let v, e = mkCompGenLocal Text.Range.range0 "i" g.int32_ty let body = mkAsmExpr ([AI_add], [], [start; e], [g.int32_ty], Text.Range.range0) let initializer = mkLambda Text.Range.range0 v (body, g.int32_ty) - let init = mkCallArrayInit g Text.Range.range0 g.int32_ty range initializer - - let emptyLabel = generateCodeLabel () - let empty = mkLabelled Text.Range.range0 emptyLabel (mkArray (g.int32_ty, [], Text.Range.range0)) - let breakToEmptyIfStartGtFinish = mkAsmExpr ([I_brcmp (BI_bgt, emptyLabel)], [], [start; finish], [mkArrayType g g.int32_ty], Text.Range.range0) - - Some (ComputedCollectionExprLowering.Either (mkAsmExpr ([], [], [breakToEmptyIfStartGtFinish; init], [mkArrayType g g.int32_ty], m), empty)) + Some (mkCallArrayInit g m g.int32_ty range initializer) | SeqToArray g (OptionalCoerce (OptionalSeq g amap (overallSeqExpr, overallElemTy)), m) -> let collectorTy = g.mk_ArrayCollector_ty overallElemTy LowerComputedListOrArraySeqExpr tcVal g amap m collectorTy overallSeqExpr - |> Option.map ComputedCollectionExprLowering.Expr | _ -> None else diff --git a/src/Compiler/Optimize/LowerComputedCollections.fsi b/src/Compiler/Optimize/LowerComputedCollections.fsi index 393e007a7df3..a16563617761 100644 --- a/src/Compiler/Optimize/LowerComputedCollections.fsi +++ b/src/Compiler/Optimize/LowerComputedCollections.fsi @@ -6,10 +6,5 @@ open FSharp.Compiler.Import open FSharp.Compiler.TcGlobals open FSharp.Compiler.TypedTree -[] -type ComputedCollectionExprLowering = - | Expr of initExpr: Expr - | Either of branch1: Expr * branch2: Expr - val LowerComputedListOrArrayExpr: - tcVal: ConstraintSolver.TcValF -> g: TcGlobals -> amap: ImportMap -> Expr -> ComputedCollectionExprLowering option + tcVal: ConstraintSolver.TcValF -> g: TcGlobals -> amap: ImportMap -> Expr -> Expr option