Skip to content

FlatExpression: optimize representation #533

@dadhi

Description

@dadhi

Optimize, genetalize and simplify FE:

  • Reduce Constant node inplace struct value from 8 to 4 bytes (up to uint instead of ulong), bigger values (e.g. long) are stored as boxed Obj now - that is fine for now, wemay figure out unboxed storage later. The freed 4 bytes should be used to add back NextIdx to simplify chaining, and to store NodeType to simplify constant conditional logic. From impl cchange make _data to 4 bytes to store either const value in const node or ChildCount, ChildIdx. The freed 4 bytes can stor NodeType in 1b, Flags in 1b, NextIdx in 2b.
  • We have primary expression nodes and reference nodes - example parameter declaration and param usage. If expression is created in a single place or couple of places it is a waste of time to aways use ref nodes in multi arguments expressions. Instead if expression node is created,then it does not have NextIdx set yet. When first used in parent we will set its NextIdx, if it was not set before. Otherwise, if NextIdx is set (expr node is slready used by some parent) only then we create a genetal ref node wich ChildIdx refers to decl. node. General ref node has Type and NodeType defined, has NextId pointing to the next child or to its parent if it is the last one. So we can use the type of ref nodes to point to any type of expr decl.
    • General change - the NextIdx for every type of node in the last node in the chain should point to the parent/owner expression to allow to reach the parent from its children. To enable stop for loops and check we need to use one bit in those meta bits after NodeType.
  • Genersl perf - Avoid exceptions with Try... methods returning bool result or when impossible use Throw static helpers introduced by modern .net and create such wrappers for older plats - avoidance of bare throw will allow inlining of the method.
  • Genetal perf - Move the bounds check to api surface and avoid checking them every time with SmallList indexer - use GetSurePresentRef instead, etc. Add Debug.Assert where needed to be on the safe side.
  • General perf / representation remarks:
    Avoid non-inlinable bare throws in hot paths; prefer Try... patterns or throw-helper wrappers.
    Move bounds checks to the API edge where possible and use GetSurePresentRef/direct refs internally.
    Keep Debug.Assert where useful for safety without paying runtime costs in release.

--
Next big step after this:

Try to absorb as much of TryCollectInfo as practical while building FE incrementally instead of requiring a separate analysis step.
FE is already accumulating closure constants during construction; lambdas and blocks are the next natural area to do the same.
Shape that metadata so it directly helps nested-lambda emit and closure construction.
Use FE construction to accumulate structural data and some capture facts by construction.
Then shrink TryCollectInfo into a lighter finalization/analysis pass over FE rather than trying to eliminate it in one jump.

Metadata

Metadata

Assignees

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions