diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2021-03-02 22:47:19 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2021-03-02 22:47:19 -0800 |
commit | 8bfcf3d9d7514309a481d5ee34bf491b6d01705a (patch) | |
tree | 5bf8c2ed2cc8d4cea3333ce73079ac6e46587fa7 | |
parent | df56f19421d05175a40cb09420596629773a113d (diff) | |
download | txr-8bfcf3d9d7514309a481d5ee34bf491b6d01705a.tar.gz txr-8bfcf3d9d7514309a481d5ee34bf491b6d01705a.tar.bz2 txr-8bfcf3d9d7514309a481d5ee34bf491b6d01705a.zip |
compiler: merge duplicate jump blocks.
I've noticed that some duplicate short blocks are generated,
which look like this. Often they are consecutive, which
is why they are noticeable. These can become one block:
mov t17 d3
jmp label17
mov t17 d3
jmp label17
mov t17 d3
jmp label17
We identify identical blocks by looking for short instruction
sequences that end in an unconditional jmp, and then we group
duplicates in a hash table keyed on the instruction sequence.
We must ignore the label: the first instruction in each block
is a unique label.
We have to be careful about which ones to delete. Any block
that is entered from the top must be preserved. When these
blocks are identified, at least one block must remain that
is removable for the optimization to be able to do anything.
If all blocks are removable, we pick a leader which is
preserved. Otherwise we pick a leader from the preserved
blocks. The non-preserved blocks are deleted, and all jumps
to them from other blocks are redirected to jumps to the
leader.
* share/txr/stdlib/compiler.tl (optimize): Call
merge-jump-thunks as the last pass.
* share/txr/stdlib/optimize.tl (basic-blocks
merge-jump-thunks): New method.
-rw-r--r-- | share/txr/stdlib/compiler.tl | 1 | ||||
-rw-r--r-- | share/txr/stdlib/optimize.tl | 25 |
2 files changed, 26 insertions, 0 deletions
diff --git a/share/txr/stdlib/compiler.tl b/share/txr/stdlib/compiler.tl index 0c90d5ce..d6ca1f45 100644 --- a/share/txr/stdlib/compiler.tl +++ b/share/txr/stdlib/compiler.tl @@ -1508,6 +1508,7 @@ bb.(elim-dead-code) bb.(calc-liveness) bb.(peephole) + bb.(merge-jump-thunks) bb.(get-insns))) (defun true-const-p (arg) diff --git a/share/txr/stdlib/optimize.tl b/share/txr/stdlib/optimize.tl index e94c98a1..af684aea 100644 --- a/share/txr/stdlib/optimize.tl +++ b/share/txr/stdlib/optimize.tl @@ -467,6 +467,31 @@ bb.(elim-next-jump bl))) bb.(join-blocks)) +(defmeth basic-blocks merge-jump-thunks (bb) + (let* ((candidates (mappend (load-time + [andf [chain .links len (op eql 1)] + [chain .insns len (lop < 4)] + [chain .insns last car + [iff consp + [chain car (op eq 'jmp)]]] + list]) + bb.list)) + (hash (group-by (load-time [chain .insns cdr]) candidates))) + (dohash (insns bls hash) + (when (cdr bls) + (whenlet ((keep (or (keep-if (op some @1.rlinks (op eq @@1) .next) bls) + (list (car bls)))) + (leader (car keep))) + (whenlet ((dupes (diff bls keep))) + (each ((bl dupes)) + (each ((pbl bl.rlinks)) + (let* ((code pbl.insns) + (tail (last code)) + (lins (car tail)) + (sins (subst bl.label leader.label lins))) + (set pbl.insns (append (ldiff code tail) (list sins)))))) + (set bb.list (remove-if (lop memq dupes) bb.list)))))))) + (defun rewrite (fun list) (build (while* list |