diff --git a/README.md b/README.md index 65b2036..1ab78a9 100644 --- a/README.md +++ b/README.md @@ -78,16 +78,6 @@ are trashed inside the block. Not because it saves 3 bytes, but because it's a neat trick. Doing it optimally is probably NP-complete. But doing it adequately is probably not that hard. -> Every routine is falled through to by zero or more routines. -> Don't consider the main routine. -> For each routine α that is finally-falled through to by a set of routines R(α), -> pick a movable routine β from R, move β in front of α, remove the `jmp` at the end of β and -> mark β as unmovable. -> Note this only works if β finally-falls through. If there are multiple tail -> positions, we can't eliminate all the `jmp`s. -> Note that if β finally-falls through to α it can't finally-fall through to anything -> else, so the sets R(α) should be disjoint for every α. (Right?) - ### And at some point... * `low` and `high` address operators - to turn `word` type into `byte`. diff --git a/tests/SixtyPical Fallthru.md b/tests/SixtyPical Fallthru.md index 11d701e..a27e998 100644 --- a/tests/SixtyPical Fallthru.md +++ b/tests/SixtyPical Fallthru.md @@ -5,6 +5,50 @@ This is a test suite, written in [Falderal][] format, for SixtyPical's ability to detect which routines make tail calls to other routines, and thus can be re-arranged to simply "fall through" to them. +The theory is as follows. + +SixtyPical supports a `goto`, but it can only appear in tail position. +If a routine r1 ends with a unique `goto` to a fixed routine r2 it is said +to *potentially fall through* to r2. + +A *unique* `goto` means that there are not multiple different `goto`s in +tail position (which can happen if, for example, an `if` is the last thing +in a routine, and each branch of that `if` ends with a different `goto`.) + +A *fixed* routine means, a routine which is known at compile time, not a +`goto` through a vector. + +Consider the set R of all routines in the program. + +Every routine r1 ∈ R either potentially falls through to a single routine +r2 ∈ R (r2 ≠ r1) or it does not potentially fall through to any routine. +We can say out(r1) = {r2} or out(r1) = ∅. + +Every routine r ∈ R in this set also has a set of zero or more +routines from which it is potentially falled through to by. Call this +in(r). It is the case that out(r1) = {r2} → r1 ∈ in(r2). + +We can trace out the connections by following the in- or our- sets of +a given routine. Because each routine potentially falls through to only +a single routine, the structures we find will be tree-like, not DAG-like. + +But they do permit cycles. + +So, we first break those cycles. We will be left with out() sets which +are disjoint trees, i.e. if r1 ∈ in(r2), then r1 ∉ in(r3) for all r3 ≠ r2. + +We then follow an algorithm something like this. Treat R as a mutable +set and start with an empty list L. Then, + +- Pick a routine r from R where out(r) = ∅. +- Find the longest chain of routines r1,r2,...rn in R where out(r1) = {r2}, + out(r2} = {r3}, ... out(rn-1) = {rn}, and rn = r. +- Remove (r1,r2,...,rn) from R and append them to L in that order. + Mark (r1,r2,...rn-1) as "will have their final `goto` removed." +- Repeat until R is empty. + +When times comes to generate code, generate it in the order given by L. + [Falderal]: http://catseye.tc/node/Falderal -> Functionality "Dump fallthru map of SixtyPical program" is implemented by