compiler.cfg.linear-scan.ranges: remove the live-range definition and

use integer pairs instead

so instead of ranges being a sequence of live-ranges it is now a
sequence of integer pairs instead. That makes the
compiler.cfg.linear-scan.ranges simpler and easier to generalize
db4
Björn Lindqvist 2015-09-16 02:14:06 +02:00
parent 2943e7f246
commit 89e261f673
10 changed files with 254 additions and 285 deletions

View File

@ -9,7 +9,7 @@ IN: compiler.cfg.linear-scan.allocation.tests
T{ live-interval-state T{ live-interval-state
{ vreg 49 } { vreg 49 }
{ start 30 } { end 46 } { start 30 } { end 46 }
{ ranges { T{ live-range { from 30 } { to 46 } } } } { ranges { { 30 46 } } }
{ uses { uses
{ {
T{ vreg-use { n 30 } { def-rep double-rep } } T{ vreg-use { n 30 } { def-rep double-rep } }
@ -79,9 +79,7 @@ cpu x86.64? [
{ vreg 1 } { vreg 1 }
{ start 30 } { start 30 }
{ end 40 } { end 40 }
{ ranges { ranges { { 30 40 } } }
{ T{ live-range { from 30 } { to 40 } } }
}
{ uses { uses
{ T{ vreg-use { n 32 } { def-rep double-rep } } } { T{ vreg-use { n 32 } { def-rep double-rep } } }
} }
@ -90,9 +88,7 @@ cpu x86.64? [
{ vreg 50 } { vreg 50 }
{ start 5 } { start 5 }
{ end 10 } { end 10 }
{ ranges { ranges { { 5 10 } } }
{ T{ live-range { from 5 } { to 10 } } }
}
{ uses { uses
{ T{ vreg-use { n 8 } { def-rep double-rep } } } { T{ vreg-use { n 8 } { def-rep double-rep } } }
} }

View File

@ -13,19 +13,7 @@ IN: compiler.cfg.linear-scan.allocation.spilling.tests
{ spill-rep double-rep } { spill-rep double-rep }
{ start 22 } { start 22 }
{ end 47 } { end 47 }
{ ranges { ranges { { 22 47 } { 67 68 } { 69 72 } } }
T{ slice
{ from 0 }
{ to 1 }
{ seq
{
T{ live-range { from 22 } { to 47 } }
T{ live-range { from 67 } { to 68 } }
T{ live-range { from 69 } { to 72 } }
}
}
}
}
{ uses { uses
{ {
T{ vreg-use T{ vreg-use
@ -53,35 +41,24 @@ IN: compiler.cfg.linear-scan.allocation.spilling.tests
! trim-after-ranges ! trim-after-ranges
{ {
T{ live-interval-state T{ live-interval-state
{ ranges { ranges { { 25 30 } { 40 50 } } }
{
T{ live-range { from 25 } { to 30 } }
T{ live-range { from 40 } { to 50 } }
}
}
{ uses { T{ vreg-use { n 25 } } } } { uses { T{ vreg-use { n 25 } } } }
} }
} [ } [
T{ live-interval-state T{ live-interval-state
{ ranges { ranges { { 0 10 } { 20 30 } { 40 50 } } }
{
T{ live-range { from 0 } { to 10 } }
T{ live-range { from 20 } { to 30 } }
T{ live-range { from 40 } { to 50 } }
}
}
{ uses { T{ vreg-use { n 25 } } } } { uses { T{ vreg-use { n 25 } } } }
} dup trim-after-ranges } dup trim-after-ranges
] unit-test ] unit-test
{ {
T{ live-interval-state T{ live-interval-state
{ ranges { T{ live-range { from 10 } { to 23 } } } } { ranges { { 10 23 } } }
{ uses { T{ vreg-use { n 10 } } } } { uses { T{ vreg-use { n 10 } } } }
} }
} [ } [
T{ live-interval-state T{ live-interval-state
{ ranges { T{ live-range { from 20 } { to 23 } } } } { ranges { { 20 23 } } }
{ uses { T{ vreg-use { n 10 } } } } { uses { T{ vreg-use { n 10 } } } }
} }
dup trim-after-ranges dup trim-after-ranges
@ -90,23 +67,12 @@ IN: compiler.cfg.linear-scan.allocation.spilling.tests
! trim-before-ranges ! trim-before-ranges
{ {
T{ live-interval-state T{ live-interval-state
{ ranges { ranges { { 0 10 } { 20 21 } } }
{
T{ live-range { from 0 } { to 10 } }
T{ live-range { from 20 } { to 21 } }
}
}
{ uses { T{ vreg-use { n 20 } } } } { uses { T{ vreg-use { n 20 } } } }
} }
} [ } [
T{ live-interval-state T{ live-interval-state
{ ranges { ranges { { 0 10 } { 20 30 } { 40 50 } } }
{
T{ live-range { from 0 } { to 10 } }
T{ live-range { from 20 } { to 30 } }
T{ live-range { from 40 } { to 50 } }
}
}
{ uses { T{ vreg-use { n 20 } } } } { uses { T{ vreg-use { n 20 } } } }
} dup trim-before-ranges } dup trim-before-ranges
] unit-test ] unit-test

View File

@ -5,20 +5,19 @@ IN: compiler.cfg.linear-scan.allocation.splitting.tests
: test-interval-easy ( -- interval ) : test-interval-easy ( -- interval )
T{ live-interval-state T{ live-interval-state
{ ranges { { ranges { { 5 8 } { 12 20 } } }
T{ live-range { from 5 } { to 8 } } { uses
T{ live-range { from 12 } { to 20 } } {
} }
{ uses {
T{ vreg-use { n 3 } { def-rep int-rep } } T{ vreg-use { n 3 } { def-rep int-rep } }
T{ vreg-use { n 15 } { def-rep int-rep } } T{ vreg-use { n 15 } { def-rep int-rep } }
} } }
}
} ; } ;
! split-interval ! split-interval
{ {
T{ live-interval-state T{ live-interval-state
{ ranges { T{ live-range { from 5 } { to 8 } } } } { ranges { { 5 8 } } }
{ uses { uses
T{ slice T{ slice
{ from 0 } { from 0 }
@ -31,7 +30,7 @@ IN: compiler.cfg.linear-scan.allocation.splitting.tests
} }
} }
T{ live-interval-state T{ live-interval-state
{ ranges { T{ live-range { from 12 } { to 20 } } } } { ranges { { 12 20 } } }
{ uses { uses
T{ slice T{ slice
{ from 1 } { from 1 }

View File

@ -1,9 +1,9 @@
! Copyright (C) 2009, 2010 Slava Pestov. ! Copyright (C) 2009, 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays assocs combinators compiler.cfg USING: accessors arrays assocs combinators compiler.cfg
compiler.cfg.instructions compiler.cfg.instructions compiler.cfg.linear-scan.live-intervals
compiler.cfg.linear-scan.live-intervals compiler.cfg.registers compiler.cfg.linear-scan.ranges compiler.cfg.registers cpu.architecture fry
cpu.architecture fry heaps kernel math math.order namespaces sequences ; heaps kernel math math.order namespaces sequences ;
IN: compiler.cfg.linear-scan.allocation.state IN: compiler.cfg.linear-scan.allocation.state
SYMBOL: progress SYMBOL: progress
@ -88,6 +88,9 @@ ERROR: register-already-used live-interval ;
! symbol stores an alist mapping register classes to vectors ! symbol stores an alist mapping register classes to vectors
[ get values ] dip '[ [ _ cond ] with filter! drop ] with each ; inline [ get values ] dip '[ [ _ cond ] with filter! drop ] with each ; inline
: covers? ( n live-interval -- ? )
ranges>> ranges-cover? ;
: deactivate-intervals ( n -- ) : deactivate-intervals ( n -- )
dup progress set dup progress set
active-intervals { active-intervals {

View File

@ -76,7 +76,7 @@ H{
{ start 0 } { start 0 }
{ end 2 } { end 2 }
{ uses V{ T{ vreg-use f 0 float-rep f } T{ vreg-use f 1 f float-rep } } } { uses V{ T{ vreg-use f 0 float-rep f } T{ vreg-use f 1 f float-rep } } }
{ ranges V{ T{ live-range f 0 2 } } } { ranges V{ { 0 2 } } }
{ spill-to T{ spill-slot f 0 } } { spill-to T{ spill-slot f 0 } }
{ spill-rep float-rep } { spill-rep float-rep }
} }
@ -85,7 +85,7 @@ H{
{ start 5 } { start 5 }
{ end 5 } { end 5 }
{ uses V{ T{ vreg-use f 5 f float-rep } } } { uses V{ T{ vreg-use f 5 f float-rep } } }
{ ranges V{ T{ live-range f 5 5 } } } { ranges V{ { 5 5 } } }
{ reload-from T{ spill-slot f 0 } } { reload-from T{ spill-slot f 0 } }
{ reload-rep float-rep } { reload-rep float-rep }
} }
@ -94,8 +94,14 @@ H{
{ vreg 1 } { vreg 1 }
{ start 0 } { start 0 }
{ end 5 } { end 5 }
{ uses V{ T{ vreg-use f 0 float-rep f } T{ vreg-use f 1 f float-rep } T{ vreg-use f 5 f float-rep } } } { uses
{ ranges V{ T{ live-range f 0 5 } } } V{
T{ vreg-use f 0 float-rep f }
T{ vreg-use f 1 f float-rep }
T{ vreg-use f 5 f float-rep }
}
}
{ ranges V{ { 0 5 } } }
} 2 split-for-spill } 2 split-for-spill
clean-up-split clean-up-split
] unit-test ] unit-test
@ -107,7 +113,7 @@ H{
{ start 1 } { start 1 }
{ end 5 } { end 5 }
{ uses V{ T{ vreg-use f 1 f float-rep } T{ vreg-use f 5 f float-rep } } } { uses V{ T{ vreg-use f 1 f float-rep } T{ vreg-use f 5 f float-rep } } }
{ ranges V{ T{ live-range f 1 5 } } } { ranges V{ { 1 5 } } }
{ reload-from T{ spill-slot f 4 } } { reload-from T{ spill-slot f 4 } }
{ reload-rep float-rep } { reload-rep float-rep }
} }
@ -116,8 +122,14 @@ H{
{ vreg 2 } { vreg 2 }
{ start 0 } { start 0 }
{ end 5 } { end 5 }
{ uses V{ T{ vreg-use f 0 float-rep f } T{ vreg-use f 1 f float-rep } T{ vreg-use f 5 f float-rep } } } { uses
{ ranges V{ T{ live-range f 0 5 } } } V{
T{ vreg-use f 0 float-rep f }
T{ vreg-use f 1 f float-rep }
T{ vreg-use f 5 f float-rep }
}
}
{ ranges V{ { 0 5 } } }
} 0 split-for-spill } 0 split-for-spill
clean-up-split clean-up-split
] unit-test ] unit-test
@ -128,7 +140,7 @@ H{
{ start 0 } { start 0 }
{ end 2 } { end 2 }
{ uses V{ T{ vreg-use f 0 float-rep f } T{ vreg-use f 1 f float-rep } } } { uses V{ T{ vreg-use f 0 float-rep f } T{ vreg-use f 1 f float-rep } } }
{ ranges V{ T{ live-range f 0 2 } } } { ranges V{ { 0 2 } } }
{ spill-to T{ spill-slot f 8 } } { spill-to T{ spill-slot f 8 } }
{ spill-rep float-rep } { spill-rep float-rep }
} }
@ -138,8 +150,14 @@ H{
{ vreg 3 } { vreg 3 }
{ start 0 } { start 0 }
{ end 5 } { end 5 }
{ uses V{ T{ vreg-use f 0 float-rep f } T{ vreg-use f 1 f float-rep } T{ vreg-use f 5 f float-rep } } } { uses
{ ranges V{ T{ live-range f 0 5 } } } V{
T{ vreg-use f 0 float-rep f }
T{ vreg-use f 1 f float-rep }
T{ vreg-use f 5 f float-rep }
}
}
{ ranges V{ { 0 5 } } }
} 5 split-for-spill } 5 split-for-spill
clean-up-split clean-up-split
] unit-test ] unit-test
@ -150,7 +168,7 @@ H{
{ start 0 } { start 0 }
{ end 1 } { end 1 }
{ uses V{ T{ vreg-use f 0 float-rep f } } } { uses V{ T{ vreg-use f 0 float-rep f } } }
{ ranges V{ T{ live-range f 0 1 } } } { ranges V{ { 0 1 } } }
{ spill-to T{ spill-slot f 12 } } { spill-to T{ spill-slot f 12 } }
{ spill-rep float-rep } { spill-rep float-rep }
} }
@ -159,7 +177,7 @@ H{
{ start 20 } { start 20 }
{ end 30 } { end 30 }
{ uses V{ T{ vreg-use f 20 f float-rep } T{ vreg-use f 30 f float-rep } } } { uses V{ T{ vreg-use f 20 f float-rep } T{ vreg-use f 30 f float-rep } } }
{ ranges V{ T{ live-range f 20 30 } } } { ranges V{ { 20 30 } } }
{ reload-from T{ spill-slot f 12 } } { reload-from T{ spill-slot f 12 } }
{ reload-rep float-rep } { reload-rep float-rep }
} }
@ -168,8 +186,14 @@ H{
{ vreg 4 } { vreg 4 }
{ start 0 } { start 0 }
{ end 30 } { end 30 }
{ uses V{ T{ vreg-use f 0 float-rep f } T{ vreg-use f 20 f float-rep } T{ vreg-use f 30 f float-rep } } } { uses
{ ranges V{ T{ live-range f 0 8 } T{ live-range f 10 18 } T{ live-range f 20 30 } } } V{
T{ vreg-use f 0 float-rep f }
T{ vreg-use f 20 f float-rep }
T{ vreg-use f 30 f float-rep }
}
}
{ ranges V{ { 0 8 } { 10 18 } { 20 30 } } }
} 10 split-for-spill } 10 split-for-spill
clean-up-split clean-up-split
] unit-test ] unit-test
@ -181,7 +205,7 @@ H{
{ start 0 } { start 0 }
{ end 1 } { end 1 }
{ uses V{ T{ vreg-use f 0 float-rep f } } } { uses V{ T{ vreg-use f 0 float-rep f } } }
{ ranges V{ T{ live-range f 0 1 } } } { ranges V{ { 0 1 } } }
{ spill-to T{ spill-slot f 16 } } { spill-to T{ spill-slot f 16 } }
{ spill-rep float-rep } { spill-rep float-rep }
} }
@ -190,15 +214,21 @@ H{
{ start 20 } { start 20 }
{ end 30 } { end 30 }
{ uses V{ T{ vreg-use f 20 float-rep f } T{ vreg-use f 30 f float-rep } } } { uses V{ T{ vreg-use f 20 float-rep f } T{ vreg-use f 30 f float-rep } } }
{ ranges V{ T{ live-range f 20 30 } } } { ranges V{ { 20 30 } } }
} }
} [ } [
T{ live-interval-state T{ live-interval-state
{ vreg 5 } { vreg 5 }
{ start 0 } { start 0 }
{ end 30 } { end 30 }
{ uses V{ T{ vreg-use f 0 float-rep f } T{ vreg-use f 20 float-rep f } T{ vreg-use f 30 f float-rep } } } { uses
{ ranges V{ T{ live-range f 0 8 } T{ live-range f 10 18 } T{ live-range f 20 30 } } } V{
T{ vreg-use f 0 float-rep f }
T{ vreg-use f 20 float-rep f }
T{ vreg-use f 30 f float-rep }
}
}
{ ranges V{ { 0 8 } { 10 18 } { 20 30 } } }
} 10 split-for-spill } 10 split-for-spill
clean-up-split clean-up-split
] unit-test ] unit-test
@ -210,7 +240,7 @@ H{
{ start 0 } { start 0 }
{ end 11 } { end 11 }
{ uses V{ T{ vreg-use f 0 float-rep f } T{ vreg-use f 10 double-rep float-rep } } } { uses V{ T{ vreg-use f 0 float-rep f } T{ vreg-use f 10 double-rep float-rep } } }
{ ranges V{ T{ live-range f 0 11 } } } { ranges V{ { 0 11 } } }
{ spill-to T{ spill-slot f 24 } } { spill-to T{ spill-slot f 24 } }
{ spill-rep double-rep } { spill-rep double-rep }
} }
@ -219,7 +249,7 @@ H{
{ start 20 } { start 20 }
{ end 20 } { end 20 }
{ uses V{ T{ vreg-use f 20 f double-rep } } } { uses V{ T{ vreg-use f 20 f double-rep } } }
{ ranges V{ T{ live-range f 20 20 } } } { ranges V{ { 20 20 } } }
{ reload-from T{ spill-slot f 24 } } { reload-from T{ spill-slot f 24 } }
{ reload-rep double-rep } { reload-rep double-rep }
} }
@ -228,8 +258,14 @@ H{
{ vreg 6 } { vreg 6 }
{ start 0 } { start 0 }
{ end 20 } { end 20 }
{ uses V{ T{ vreg-use f 0 float-rep f } T{ vreg-use f 10 double-rep float-rep } T{ vreg-use f 20 f double-rep } } } { uses
{ ranges V{ T{ live-range f 0 20 } } } V{
T{ vreg-use f 0 float-rep f }
T{ vreg-use f 10 double-rep float-rep }
T{ vreg-use f 20 f double-rep }
}
}
{ ranges V{ { 0 20 } } }
} 15 split-for-spill } 15 split-for-spill
clean-up-split clean-up-split
] unit-test ] unit-test
@ -240,7 +276,7 @@ H{
{ vreg 7 } { vreg 7 }
{ start 8 } { start 8 }
{ end 8 } { end 8 }
{ ranges V{ T{ live-range f 8 8 } } } { ranges V{ { 8 8 } } }
{ uses V{ T{ vreg-use f 8 int-rep } } } { uses V{ T{ vreg-use f 8 int-rep } } }
} }
} [ } [
@ -248,7 +284,7 @@ H{
{ vreg 7 } { vreg 7 }
{ start 4 } { start 4 }
{ end 8 } { end 8 }
{ ranges V{ T{ live-range f 4 8 } } } { ranges V{ { 4 8 } } }
{ uses V{ T{ vreg-use f 8 int-rep } } } { uses V{ T{ vreg-use f 8 int-rep } } }
} 4 split-for-spill } 4 split-for-spill
clean-up-split clean-up-split
@ -260,7 +296,7 @@ H{
{ vreg 8 } { vreg 8 }
{ start 0 } { start 0 }
{ end 3 } { end 3 }
{ ranges V{ T{ live-range f 0 3 } } } { ranges V{ { 0 3 } } }
{ uses V{ T{ vreg-use f 0 f int-rep } T{ vreg-use f 2 f int-rep } } } { uses V{ T{ vreg-use f 0 f int-rep } T{ vreg-use f 2 f int-rep } } }
{ spill-to T{ spill-slot f 32 } } { spill-to T{ spill-slot f 32 } }
{ spill-rep int-rep } { spill-rep int-rep }
@ -269,7 +305,7 @@ H{
{ vreg 8 } { vreg 8 }
{ start 14 } { start 14 }
{ end 16 } { end 16 }
{ ranges V{ T{ live-range f 14 16 } } } { ranges V{ { 14 16 } } }
{ uses V{ T{ vreg-use f 14 f int-rep } } } { uses V{ T{ vreg-use f 14 f int-rep } } }
{ reload-from T{ spill-slot f 32 } } { reload-from T{ spill-slot f 32 } }
{ reload-rep int-rep } { reload-rep int-rep }
@ -279,7 +315,7 @@ H{
{ vreg 8 } { vreg 8 }
{ start 0 } { start 0 }
{ end 16 } { end 16 }
{ ranges V{ T{ live-range f 0 4 } T{ live-range f 6 10 } T{ live-range f 12 16 } } } { ranges V{ { 0 4 } { 6 10 } { 12 16 } } }
{ uses { uses
V{ V{
T{ vreg-use f 0 f int-rep } T{ vreg-use f 0 f int-rep }
@ -310,14 +346,28 @@ H{
{ reg 1 } { reg 1 }
{ start 1 } { start 1 }
{ end 15 } { end 15 }
{ uses V{ T{ vreg-use f 1 int-rep f } T{ vreg-use f 3 f int-rep } T{ vreg-use f 7 f int-rep } T{ vreg-use f 10 f int-rep } T{ vreg-use f 15 f int-rep } } } { uses
V{
T{ vreg-use f 1 int-rep f }
T{ vreg-use f 3 f int-rep }
T{ vreg-use f 7 f int-rep }
T{ vreg-use f 10 f int-rep }
T{ vreg-use f 15 f int-rep }
}
}
} }
T{ live-interval-state T{ live-interval-state
{ vreg 2 } { vreg 2 }
{ reg 2 } { reg 2 }
{ start 3 } { start 3 }
{ end 8 } { end 8 }
{ uses V{ T{ vreg-use f 3 int-rep f } T{ vreg-use f 4 f int-rep } T{ vreg-use f 8 f int-rep } } } { uses
V{
T{ vreg-use f 3 int-rep f }
T{ vreg-use f 4 f int-rep }
T{ vreg-use f 8 f int-rep }
}
}
} }
T{ live-interval-state T{ live-interval-state
{ vreg 3 } { vreg 3 }
@ -384,7 +434,7 @@ H{ { 1 int-rep } { 2 int-rep } } representations set
{ start 0 } { start 0 }
{ end 100 } { end 100 }
{ uses V{ T{ vreg-use f 0 int-rep f } T{ vreg-use f 100 f int-rep } } } { uses V{ T{ vreg-use f 0 int-rep f } T{ vreg-use f 100 f int-rep } } }
{ ranges V{ T{ live-range f 0 100 } } } { ranges V{ { 0 100 } } }
} }
} }
H{ { int-regs { "A" } } } H{ { int-regs { "A" } } }
@ -398,14 +448,14 @@ H{ { 1 int-rep } { 2 int-rep } } representations set
{ start 0 } { start 0 }
{ end 10 } { end 10 }
{ uses V{ T{ vreg-use f 0 int-rep f } T{ vreg-use f 10 f int-rep } } } { uses V{ T{ vreg-use f 0 int-rep f } T{ vreg-use f 10 f int-rep } } }
{ ranges V{ T{ live-range f 0 10 } } } { ranges V{ { 0 10 } } }
} }
T{ live-interval-state T{ live-interval-state
{ vreg 2 } { vreg 2 }
{ start 11 } { start 11 }
{ end 20 } { end 20 }
{ uses V{ T{ vreg-use f 11 int-rep f } T{ vreg-use f 20 f int-rep } } } { uses V{ T{ vreg-use f 11 int-rep f } T{ vreg-use f 20 f int-rep } } }
{ ranges V{ T{ live-range f 11 20 } } } { ranges V{ { 11 20 } } }
} }
} }
H{ { int-regs { "A" } } } H{ { int-regs { "A" } } }
@ -419,14 +469,14 @@ H{ { 1 int-rep } { 2 int-rep } } representations set
{ start 0 } { start 0 }
{ end 100 } { end 100 }
{ uses V{ T{ vreg-use f 0 int-rep f } T{ vreg-use f 100 f int-rep } } } { uses V{ T{ vreg-use f 0 int-rep f } T{ vreg-use f 100 f int-rep } } }
{ ranges V{ T{ live-range f 0 100 } } } { ranges V{ { 0 100 } } }
} }
T{ live-interval-state T{ live-interval-state
{ vreg 2 } { vreg 2 }
{ start 30 } { start 30 }
{ end 60 } { end 60 }
{ uses V{ T{ vreg-use f 30 int-rep f } T{ vreg-use f 60 f int-rep } } } { uses V{ T{ vreg-use f 30 int-rep f } T{ vreg-use f 60 f int-rep } } }
{ ranges V{ T{ live-range f 30 60 } } } { ranges V{ { 30 60 } } }
} }
} }
H{ { int-regs { "A" } } } H{ { int-regs { "A" } } }
@ -440,14 +490,14 @@ H{ { 1 int-rep } { 2 int-rep } } representations set
{ start 0 } { start 0 }
{ end 100 } { end 100 }
{ uses V{ T{ vreg-use f 0 int-rep f } T{ vreg-use f 100 f int-rep } } } { uses V{ T{ vreg-use f 0 int-rep f } T{ vreg-use f 100 f int-rep } } }
{ ranges V{ T{ live-range f 0 100 } } } { ranges V{ { 0 100 } } }
} }
T{ live-interval-state T{ live-interval-state
{ vreg 2 } { vreg 2 }
{ start 30 } { start 30 }
{ end 200 } { end 200 }
{ uses V{ T{ vreg-use f 30 int-rep f } T{ vreg-use f 200 f int-rep } } } { uses V{ T{ vreg-use f 30 int-rep f } T{ vreg-use f 200 f int-rep } } }
{ ranges V{ T{ live-range f 30 200 } } } { ranges V{ { 30 200 } } }
} }
} }
H{ { int-regs { "A" } } } H{ { int-regs { "A" } } }
@ -461,14 +511,14 @@ H{ { 1 int-rep } { 2 int-rep } } representations set
{ start 0 } { start 0 }
{ end 100 } { end 100 }
{ uses V{ T{ vreg-use f 0 int-rep f } T{ vreg-use f 100 f int-rep } } } { uses V{ T{ vreg-use f 0 int-rep f } T{ vreg-use f 100 f int-rep } } }
{ ranges V{ T{ live-range f 0 100 } } } { ranges V{ { 0 100 } } }
} }
T{ live-interval-state T{ live-interval-state
{ vreg 2 } { vreg 2 }
{ start 30 } { start 30 }
{ end 100 } { end 100 }
{ uses V{ T{ vreg-use f 30 int-rep f } T{ vreg-use f 100 f int-rep } } } { uses V{ T{ vreg-use f 30 int-rep f } T{ vreg-use f 100 f int-rep } } }
{ ranges V{ T{ live-range f 30 100 } } } { ranges V{ { 30 100 } } }
} }
} }
H{ { int-regs { "A" } } } H{ { int-regs { "A" } } }
@ -490,29 +540,41 @@ H{
{ vreg 1 } { vreg 1 }
{ start 0 } { start 0 }
{ end 20 } { end 20 }
{ uses V{ T{ vreg-use f 0 int-rep f } T{ vreg-use f 10 f int-rep } T{ vreg-use f 20 f int-rep } } } { uses
{ ranges V{ T{ live-range f 0 2 } T{ live-range f 10 20 } } } V{
T{ vreg-use f 0 int-rep f }
T{ vreg-use f 10 f int-rep }
T{ vreg-use f 20 f int-rep }
}
}
{ ranges V{ { 0 2 } { 10 20 } } }
} }
T{ live-interval-state T{ live-interval-state
{ vreg 2 } { vreg 2 }
{ start 0 } { start 0 }
{ end 20 } { end 20 }
{ uses V{ T{ vreg-use f 0 int-rep f } T{ vreg-use f 10 f int-rep } T{ vreg-use f 20 f int-rep } } } { uses
{ ranges V{ T{ live-range f 0 2 } T{ live-range f 10 20 } } } V{
T{ vreg-use f 0 int-rep f }
T{ vreg-use f 10 f int-rep }
T{ vreg-use f 20 f int-rep }
}
}
{ ranges V{ { 0 2 } { 10 20 } } }
} }
T{ live-interval-state T{ live-interval-state
{ vreg 3 } { vreg 3 }
{ start 4 } { start 4 }
{ end 8 } { end 8 }
{ uses V{ T{ vreg-use f 6 int-rep f } } } { uses V{ T{ vreg-use f 6 int-rep f } } }
{ ranges V{ T{ live-range f 4 8 } } } { ranges V{ { 4 8 } } }
} }
T{ live-interval-state T{ live-interval-state
{ vreg 4 } { vreg 4 }
{ start 4 } { start 4 }
{ end 8 } { end 8 }
{ uses V{ T{ vreg-use f 8 int-rep f } } } { uses V{ T{ vreg-use f 8 int-rep f } } }
{ ranges V{ T{ live-range f 4 8 } } } { ranges V{ { 4 8 } } }
} }
! This guy will invoke the 'spill partially available' code path ! This guy will invoke the 'spill partially available' code path
@ -521,7 +583,7 @@ H{
{ start 4 } { start 4 }
{ end 8 } { end 8 }
{ uses V{ T{ vreg-use f 8 int-rep f } } } { uses V{ T{ vreg-use f 8 int-rep f } } }
{ ranges V{ T{ live-range f 4 8 } } } { ranges V{ { 4 8 } } }
} }
} }
H{ { int-regs { "A" "B" } } } H{ { int-regs { "A" "B" } } }
@ -537,7 +599,7 @@ H{
{ start 0 } { start 0 }
{ end 10 } { end 10 }
{ uses V{ T{ vreg-use f 0 int-rep f } T{ vreg-use f 6 f int-rep } T{ vreg-use f 10 f int-rep } } } { uses V{ T{ vreg-use f 0 int-rep f } T{ vreg-use f 6 f int-rep } T{ vreg-use f 10 f int-rep } } }
{ ranges V{ T{ live-range f 0 10 } } } { ranges V{ { 0 10 } } }
} }
! This guy will invoke the 'spill new' code path ! This guy will invoke the 'spill new' code path
@ -546,7 +608,7 @@ H{
{ start 2 } { start 2 }
{ end 8 } { end 8 }
{ uses V{ T{ vreg-use f 8 int-rep f } } } { uses V{ T{ vreg-use f 8 int-rep f } } }
{ ranges V{ T{ live-range f 2 8 } } } { ranges V{ { 2 8 } } }
} }
} }
H{ { int-regs { "A" } } } H{ { int-regs { "A" } } }
@ -571,7 +633,7 @@ H{
{ start 0 } { start 0 }
{ end 20 } { end 20 }
{ reg 0 } { reg 0 }
{ ranges V{ T{ live-range f 0 2 } T{ live-range f 10 20 } } } { ranges V{ { 0 2 } { 10 20 } } }
{ uses V{ 0 2 10 20 } } { uses V{ 0 2 10 20 } }
} }
@ -580,7 +642,7 @@ H{
{ start 4 } { start 4 }
{ end 40 } { end 40 }
{ reg 0 } { reg 0 }
{ ranges V{ T{ live-range f 4 6 } T{ live-range f 30 40 } } } { ranges V{ { 4 6 } { 30 40 } } }
{ uses V{ 4 6 30 40 } } { uses V{ 4 6 30 40 } }
} }
} }
@ -594,7 +656,7 @@ H{
{ start 0 } { start 0 }
{ end 40 } { end 40 }
{ reg 1 } { reg 1 }
{ ranges V{ T{ live-range f 0 40 } } } { ranges V{ { 0 40 } } }
{ uses V{ 0 40 } } { uses V{ 0 40 } }
} }
} }
@ -605,7 +667,7 @@ H{
{ vreg 4 } { vreg 4 }
{ start 8 } { start 8 }
{ end 10 } { end 10 }
{ ranges V{ T{ live-range f 8 10 } } } { ranges V{ { 8 10 } } }
{ uses V{ T{ vreg-use f 8 int-rep f } T{ vreg-use f 10 f int-rep } } } { uses V{ T{ vreg-use f 8 int-rep f } T{ vreg-use f 10 f int-rep } } }
} }
H{ { int-regs { 0 1 } } } register-status H{ { int-regs { 0 1 } } } register-status

View File

@ -40,7 +40,7 @@ IN: compiler.cfg.linear-scan.live-intervals.tests
8 8
T{ live-interval-state T{ live-interval-state
{ vreg 8 } { vreg 8 }
{ ranges V{ T{ live-range { from -10 } { to 23 } } } } { ranges V{ { -10 23 } } }
{ uses V{ } } { uses V{ } }
} }
} }
@ -48,7 +48,7 @@ IN: compiler.cfg.linear-scan.live-intervals.tests
9 9
T{ live-interval-state T{ live-interval-state
{ vreg 9 } { vreg 9 }
{ ranges V{ T{ live-range { from -10 } { to 23 } } } } { ranges V{ { -10 23 } } }
{ uses V{ } } { uses V{ } }
} }
} }
@ -56,7 +56,7 @@ IN: compiler.cfg.linear-scan.live-intervals.tests
4 4
T{ live-interval-state T{ live-interval-state
{ vreg 4 } { vreg 4 }
{ ranges V{ T{ live-range { from -10 } { to 23 } } } } { ranges V{ { -10 23 } } }
{ uses V{ } } { uses V{ } }
} }
} }

View File

@ -32,9 +32,6 @@ TUPLE: live-interval-state
insn# uses last-use? [ insn# uses new-use ] unless* insn# uses last-use? [ insn# uses new-use ] unless*
spill-slot? [ t >>spill-slot? ] when ; spill-slot? [ t >>spill-slot? ] when ;
: covers? ( n live-interval -- ? )
ranges>> ranges-cover? ;
: (find-use) ( insn# live-interval -- vreg-use ) : (find-use) ( insn# live-interval -- vreg-use )
uses>> [ n>> <=> ] with search nip ; uses>> [ n>> <=> ] with search nip ;

View File

@ -1,20 +1,20 @@
USING: compiler.cfg help.syntax help.markup math ; USING: arrays help.markup help.syntax math ;
IN: compiler.cfg.linear-scan.ranges IN: compiler.cfg.linear-scan.ranges
HELP: intersect-range HELP: intersect-range
{ $values { $values
{ "range1" live-range } { "range1" pair }
{ "range2" live-range } { "range2" pair }
{ "n/f" { $link number } " or " { $link f } } { "n/f" { $link number } " or " { $link f } }
} }
{ $description "First index for the ranges intersection, or f if they don't intersect." } ; { $description "First index for the ranges intersection, or f if they don't intersect." } ;
HELP: live-range
{ $class-description "Represents a range in the " { $link cfg } " in which a vreg is live." } ;
ARTICLE: "compiler.cfg.linear-scan.ranges" "Live ranges utilities" ARTICLE: "compiler.cfg.linear-scan.ranges" "Live ranges utilities"
"Utilities for dealing with the live range part of live intervals. A sequence of " { $link live-range } " tuples encodes where in the cfg a virtual register is live." "Utilities for dealing with the live range part of live intervals. A sequence of integer 2-tuples encodes the closed intervals in the cfg where a virtual register is live."
$nl $nl
"Constructors:" { $subsections <live-range> live-range } ; "Range splitting:"
{ $subsections
split-range split-ranges
} ;
ABOUT: "compiler.cfg.linear-scan.ranges" ABOUT: "compiler.cfg.linear-scan.ranges"

View File

@ -2,8 +2,19 @@ USING: arrays compiler.cfg.linear-scan.ranges fry kernel sequences
tools.test ; tools.test ;
IN: compiler.cfg.linear-scan.ranges.tests IN: compiler.cfg.linear-scan.ranges.tests
: combine-ranges ( seq -- ranges ) ! add-new-range
V{ } clone [ '[ first2 _ add-range ] each ] keep ; {
V{ { 10 20 } }
} [
10 20 V{ } [ add-new-range ] keep
] unit-test
! extend-ranges
{
V{ { 7 25 } }
} [
7 25 V{ { 10 20 } } [ extend-ranges ] keep
] unit-test
! extend-ranges? ! extend-ranges?
{ f } [ { f } [
@ -12,197 +23,138 @@ IN: compiler.cfg.linear-scan.ranges.tests
! add-range ! add-range
{ {
V{ T{ live-range { from 5 } { to 12 } } } V{ { 5 12 } }
V{ T{ live-range { from 5 } { to 12 } } } V{ { 5 12 } }
V{ { 10 12 } { 5 9 } }
} [ } [
{ { 5 10 } { 8 12 } } combine-ranges 8 12 V{ { 5 10 } } [ add-range ] keep
{ { 10 12 } { 5 10 } } combine-ranges 5 10 V{ { 10 12 } } [ add-range ] keep
5 9 V{ { 10 12 } } [ add-range ] keep
] unit-test ] unit-test
! intersect-range ! intersect-range
{ f 15 f 10 5 } [ { f 15 10 5 } [
10 20 <live-range> 30 40 <live-range> intersect-range { 10 20 } { 30 40 } intersect-range
10 20 <live-range> 15 16 <live-range> intersect-range { 10 20 } { 15 16 } intersect-range
T{ live-range f 0 10 } T{ live-range f 20 30 } intersect-range { 0 10 } { 10 30 } intersect-range
T{ live-range f 0 10 } T{ live-range f 10 30 } intersect-range { 0 10 } { 5 30 } intersect-range
T{ live-range f 0 10 } T{ live-range f 5 30 } intersect-range
] unit-test ] unit-test
! intersect-ranges ! intersect-ranges
{ 50 f f f 11 8 f f } [ { 50 f f f 11 8 f f } [
{ { { 0 10 } { 20 30 } { 40 50 } }
T{ live-range f 0 10 } { { 11 15 } { 31 35 } { 50 55 } } intersect-ranges
T{ live-range f 20 30 } { { 0 10 } { 20 30 } { 40 50 } }
T{ live-range f 40 50 } { { 11 15 } { 31 36 } { 51 55 } } intersect-ranges
} { } { { 11 15 } } intersect-ranges
{ { { 11 15 } } { } intersect-ranges
T{ live-range f 11 15 } { { 11 15 } } { { 10 15 } { 16 18 } } intersect-ranges
T{ live-range f 31 35 }
T{ live-range f 50 55 } { { 4 20 } } { { 8 12 } } intersect-ranges
} { { 9 20 } { 3 5 } } { { 0 1 } { 7 8 } } intersect-ranges
intersect-ranges { { 3 5 } } { { 7 8 } } intersect-ranges
{
T{ live-range f 0 10 }
T{ live-range f 20 30 }
T{ live-range f 40 50 }
}
{
T{ live-range f 11 15 }
T{ live-range f 31 36 }
T{ live-range f 51 55 }
}
intersect-ranges
{ } { T{ live-range f 11 15 } } intersect-ranges
{ T{ live-range f 11 15 } } { } intersect-ranges
{ T{ live-range f 11 15 } }
{ T{ live-range f 10 15 } T{ live-range f 16 18 } }
intersect-ranges
{ T{ live-range f 4 20 } } { T{ live-range f 8 12 } }
intersect-ranges
{ T{ live-range f 9 20 } T{ live-range f 3 5 } }
{ T{ live-range f 0 1 } T{ live-range f 7 8 } }
intersect-ranges
{ T{ live-range f 3 5 } } { T{ live-range f 7 8 } } intersect-ranges
] unit-test ] unit-test
! ranges-cover? ! ranges-cover?
{ {
t f f t t t f f t t
} [ } [
115 { { 90 120 } { 40 50 } } combine-ranges ranges-cover? 115 { { 90 120 } { 40 50 } } ranges-cover?
50 { { 60 70 } { 20 30 } } combine-ranges ranges-cover? 50 { { 60 70 } { 20 30 } } ranges-cover?
120 { { 130 140 } { 70 80 } { 50 60 } { 44 48 } { 40 42 } } 120 { { 130 140 } { 70 80 } { 50 60 } { 44 48 } { 40 42 } }
combine-ranges ranges-cover? ranges-cover?
135 { { 130 140 } { 70 80 } { 50 60 } { 44 48 } } 135 { { 130 140 } { 70 80 } { 50 60 } { 44 48 } }
combine-ranges ranges-cover? ranges-cover?
135 { { 130 140 } { 70 80 } { 50 60 } { 44 48 } { 40 42 } } reverse 135 { { 130 140 } { 70 80 } { 50 60 } { 44 48 } { 40 42 } } reverse
combine-ranges ranges-cover? ranges-cover?
] unit-test ] unit-test
! shorten-ranges ! shorten-ranges
{ {
V{ T{ live-range { from 8 } { to 12 } } } V{ { 8 12 } }
V{ T{ live-range { from 9 } { to 9 } } } V{ { 9 9 } }
} [ } [
8 { { 4 12 } } combine-ranges [ shorten-ranges ] keep 8 V{ { 4 12 } } [ shorten-ranges ] keep
9 { } combine-ranges [ shorten-ranges ] keep 9 V{ } [ shorten-ranges ] keep
] unit-test ] unit-test
! split range ! split range
{ {
T{ live-range f 10 15 } { 10 15 } { 16 20 }
T{ live-range f 16 20 }
} [ } [
10 20 <live-range> 15 split-range { 10 20 } 15 split-range
] unit-test ] unit-test
! split-ranges ! split-ranges
{ { { 10 20 } } { { 30 40 } } }
[ { { 10 20 } { 30 40 } } 25 split-ranges ] unit-test
{ { { 0 0 } } { { 1 5 } } }
[ { { 0 5 } } 0 split-ranges ] unit-test
{ {
{ T{ live-range { from 10 } { to 20 } } } { { 1 10 } { 15 17 } }
{ T{ live-range { from 30 } { to 40 } } } { { 18 20 } }
} [ } [
10 20 <live-range> 30 40 <live-range> 2array 25 split-ranges { { 1 10 } { 15 20 } } 17 split-ranges
] unit-test ] unit-test
{ {
{ T{ live-range f 0 0 } } { { 1 10 } } { { 15 20 } }
{ T{ live-range f 1 5 } }
} [ } [
{ T{ live-range f 0 5 } } 0 split-ranges { { 1 10 } { 15 20 } } 12 split-ranges
] unit-test ] unit-test
{ {
{ T{ live-range f 1 10 } T{ live-range f 15 17 } } { { 1 10 } { 15 16 } }
{ T{ live-range f 18 20 } } { { 17 20 } }
} [ } [
{ { { 1 10 } { 15 20 } } 16 split-ranges
T{ live-range f 1 10 }
T{ live-range f 15 20 }
} 17 split-ranges
] unit-test ] unit-test
{ {
{ T{ live-range f 1 10 } } { { 1 10 } { 15 15 } }
{ T{ live-range f 15 20 } } { { 16 20 } }
} [ } [
{ { { 1 10 } { 15 20 } } 15 split-ranges
T{ live-range f 1 10 }
T{ live-range f 15 20 }
} 12 split-ranges
] unit-test
{
{ T{ live-range f 1 10 } T{ live-range f 15 16 } }
{ T{ live-range f 17 20 } }
} [
{
T{ live-range f 1 10 }
T{ live-range f 15 20 }
} 16 split-ranges
] unit-test
{
{ T{ live-range f 1 10 } T{ live-range f 15 15 } }
{ T{ live-range f 16 20 } }
} [
{
T{ live-range f 1 10 }
T{ live-range f 15 20 }
} 15 split-ranges
] unit-test ] unit-test
[ [
{ T{ live-range f 1 10 } } 0 split-ranges { { 1 10 } } 0 split-ranges
] must-fail ] must-fail
! valid-ranges? ! valid-ranges?
{ t f f f } [ { t f f f } [
{ T{ live-range f 1 10 } T{ live-range f 15 20 } } valid-ranges? { { 1 10 } { 15 20 } } valid-ranges?
{ T{ live-range f 10 1 } T{ live-range f 15 20 } } valid-ranges? { { 10 1 } { 15 20 } } valid-ranges?
{ T{ live-range f 1 5 } T{ live-range f 3 10 } } valid-ranges? { { 1 5 } { 3 10 } } valid-ranges?
{ T{ live-range f 5 1 } } valid-ranges? { { 5 1 } } valid-ranges?
] unit-test ] unit-test
! fix-lower-bound ! fix-lower-bound
{ {
{ { { 25 30 } { 40 50 } }
T{ live-range { from 25 } { to 30 } } { { 10 23 } }
T{ live-range { from 40 } { to 50 } } { { 366 366 } }
}
{ T{ live-range { from 10 } { to 23 } } }
} [ } [
25 { 25 { { 0 10 } { 20 30 } { 40 50 } } fix-lower-bound
T{ live-range { from 0 } { to 10 } } 10 { { 20 23 } } fix-lower-bound
T{ live-range { from 20 } { to 30 } } 366 { { 355 356 } { 357 366 } } fix-lower-bound
T{ live-range { from 40 } { to 50 } }
} fix-lower-bound
10 { T{ live-range { from 20 } { to 23 } } } fix-lower-bound
] unit-test ] unit-test
! fix-upper-bound ! fix-upper-bound
{ {
{ { { 0 10 } { 20 20 } }
T{ live-range { from 0 } { to 10 } } { { 0 20 } }
T{ live-range { from 20 } { to 20 } } { { 0 10 } { 20 23 } }
}
} [ } [
20 { 20 { { 0 10 } { 20 30 } { 40 50 } } fix-upper-bound
T{ live-range { from 0 } { to 10 } } 20 { { 0 40 } } fix-upper-bound
T{ live-range { from 20 } { to 30 } } 23 { { 0 10 } { 20 30 } { 40 50 } } fix-upper-bound
T{ live-range { from 40 } { to 50 } }
} fix-upper-bound
] unit-test
{
{ T{ live-range { from 0 } { to 20 } } }
} [
20 { T{ live-range { from 0 } { to 40 } } } fix-upper-bound
] unit-test ] unit-test
! ranges-endpoints ! ranges-endpoints
{ 0 40 } [ { 0 40 } [
V{ { { 0 10 } { 30 40 } } ranges-endpoints
T{ live-range { from 0 } { to 10 } }
T{ live-range { from 30 } { to 40 } }
} ranges-endpoints
] unit-test ] unit-test

View File

@ -1,67 +1,61 @@
USING: accessors arrays fry grouping kernel math math.order sequences ; USING: accessors arrays fry grouping kernel math math.order sequences ;
IN: compiler.cfg.linear-scan.ranges IN: compiler.cfg.linear-scan.ranges
! Data definitions
TUPLE: live-range from to ;
C: <live-range> live-range
! Range utilities ! Range utilities
: intersect-range ( range1 range2 -- n/f ) : intersect-range ( r1 r2 -- n/f )
2dup [ from>> ] bi@ > [ swap ] when 2dup [ first ] bi@ > [ swap ] when
2dup [ to>> ] [ from>> ] bi* >= 2dup [ second ] [ first ] bi* >=
[ nip from>> ] [ 2drop f ] if ; [ nip first ] [ 2drop f ] if ;
: range-covers? ( n range -- ? ) : split-range ( range n -- before after )
[ from>> ] [ to>> ] bi between? ; swap first2 pick 1 + [ swap 2array ] 2bi@ ;
: split-range ( live-range n -- before after )
[ [ from>> ] dip <live-range> ] [ 1 + swap to>> <live-range> ] 2bi ;
! Range sequence utilities ! Range sequence utilities
: extend-ranges? ( n ranges -- ? ) : extend-ranges? ( n ranges -- ? )
[ drop f ] [ last from>> >= ] if-empty ; [ drop f ] [ last first >= ] if-empty ;
: extend-ranges ( from to ranges -- ) : extend-ranges ( from to ranges -- )
last [ max ] change-to [ min ] change-from drop ; [ last first2 rot [ min ] [ max ] 2bi* 2array ] keep set-last ;
: add-new-range ( from to ranges -- ) : add-new-range ( from to ranges -- )
[ <live-range> ] dip push ; [ 2array ] dip push ;
: add-range ( from to ranges -- ) : add-range ( from to ranges -- )
2dup extend-ranges? [ extend-ranges ] [ add-new-range ] if ; 2dup extend-ranges? [ extend-ranges ] [ add-new-range ] if ;
: ranges-cover? ( n ranges -- ? ) : ranges-cover? ( n ranges -- ? )
[ range-covers? ] with any? ; [ first2 between? ] with any? ;
: intersect-ranges ( ranges1 ranges2 -- n/f ) : intersect-ranges ( ranges1 ranges2 -- n/f )
'[ _ [ intersect-range ] with map-find drop ] map-find drop ; '[ _ [ intersect-range ] with map-find drop ] map-find drop ;
: shorten-ranges ( n ranges -- ) : shorten-ranges ( n ranges -- )
dup empty? [ dupd add-new-range ] [ last from<< ] if ; dup empty? [ dupd add-new-range ] [
[ last second 2array ] keep set-last
: split-last-range? ( last n -- ? ) ] if ;
swap to>> <= ;
: split-last-range ( before after last n -- before' after' ) : split-last-range ( before after last n -- before' after' )
split-range [ [ but-last ] dip suffix ] [ prefix ] bi-curry* bi* ; split-range [ [ but-last ] dip suffix ] [ prefix ] bi-curry* bi* ;
: split-ranges ( live-ranges n -- before after ) : split-last-range? ( last n -- ? )
[ '[ from>> _ <= ] partition ] swap second <= ;
: split-ranges ( ranges n -- before after )
[ '[ first _ <= ] partition ]
[ [
[ over last ] dip 2dup split-last-range? [ over last ] dip 2dup split-last-range?
[ split-last-range ] [ 2drop ] if [ split-last-range ] [ 2drop ] if
] bi ; ] bi ;
: valid-ranges? ( ranges -- ? ) : valid-ranges? ( ranges -- ? )
[ [ [ from>> ] [ to>> ] bi <= ] all? ] [ [ first2 <= ] all? ]
[ [ [ to>> ] [ from>> ] bi* <= ] monotonic? ] bi and ; [ [ [ second ] [ first ] bi* <= ] monotonic? ] bi and ;
: fix-lower-bound ( n ranges -- ranges' ) : fix-lower-bound ( n ranges -- ranges' )
over '[ to>> _ >= ] filter [ first from<< ] keep ; over '[ second _ >= ] filter unclip second swapd 2array prefix ;
: fix-upper-bound ( n ranges -- ranges' ) : fix-upper-bound ( n ranges -- ranges' )
over '[ from>> _ <= ] filter [ last to<< ] keep ; over '[ first _ <= ] filter unclip-last first rot 2array suffix ;
: ranges-endpoints ( ranges -- start end ) : ranges-endpoints ( ranges -- start end )
[ first from>> ] [ last to>> ] bi ; [ first first ] [ last last ] bi ;