An optimizer for ARC (#14962)

* WIP: an optimizer for ARC
* do not optimize away destructors in 'finally' if unstructured control flow is involved
* optimized the optimizer
* minor code cleanup
* first steps to .cursor inference
* cursor inference: big steps to a working solution
* baby steps
* better .cursor inference
* new feature: expandArc for easy inspection of the AST after ARC transformations
* added topt_cursor test
* adapt tests
* cleanups, make tests green
* optimize common traversal patterns
* moved test case
* fixes .cursor inference so that npeg compiles once again
* cursor inference: more bugfixes

Co-authored-by: Clyybber <darkmine956@gmail.com>
This commit is contained in:
Andreas Rumpf 2020-07-15 23:00:06 +02:00 • committed by GitHub
commit c5358b0d4b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 895 additions and 62 deletions

View file

@ -354,7 +354,8 @@ Destructor removal
``wasMoved(x);`` followed by a `=destroy(x)` operation cancel each other
out. An implementation is encouraged to exploit this in order to improve
efficiency and code sizes.
efficiency and code sizes. The current implementation does perform this
optimization.
Self assignments
@ -509,6 +510,31 @@ to be safe, but for ``ptr`` the compiler has to remain silent about possible
problems.
Cursor inference / copy elision
===============================
The current implementation also performs `.cursor` inference. Cursor inference is
a form of copy elision.
To see how and when we can do that, think about this question: In `dest = src` when
do we really have to *materialize* the full copy? - Only if `dest` or `src` are mutated
afterwards. If `dest` is a local variable that is simple to analyse. And if `src` is a
location derived from a formal parameter, we also know it is not mutated! In other
words, we do a compile-time copy-on-write analysis.
This means that "borrowed" views can be written naturally and without explicit pointer
indirections:
.. code-block:: nim
proc main(tab: Table[string, string]) =
let v = tab["key"] # inferred as .cursor because 'tab' is not mutated.
# no copy into 'v', no destruction of 'v'.
use(v)
useItAgain(v)
Owned refs
==========