Skip to content

Commit

Permalink
Just curious
Browse files Browse the repository at this point in the history
  • Loading branch information
brianrourkeboll committed Jan 26, 2024
1 parent 0136a96 commit f176fd0
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 50 deletions.
6 changes: 1 addition & 5 deletions src/Compiler/CodeGen/IlxGen.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
71 changes: 32 additions & 39 deletions src/Compiler/Optimize/LowerComputedCollections.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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

[<RequireQualifiedAccess>]
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<int32> < 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<int32> < 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
Expand Down
7 changes: 1 addition & 6 deletions src/Compiler/Optimize/LowerComputedCollections.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,5 @@ open FSharp.Compiler.Import
open FSharp.Compiler.TcGlobals
open FSharp.Compiler.TypedTree

[<RequireQualifiedAccess>]
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

0 comments on commit f176fd0

Please sign in to comment.