From 809b40d4971cc888284a3558c56d737c7e46ad1c Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Tue, 7 Jul 2009 16:26:50 -0500 Subject: [PATCH 01/96] preserve sequence type in math.matrices:cross --- basis/math/matrices/matrices.factor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basis/math/matrices/matrices.factor b/basis/math/matrices/matrices.factor index b939162577..3203355bb9 100644 --- a/basis/math/matrices/matrices.factor +++ b/basis/math/matrices/matrices.factor @@ -120,7 +120,7 @@ IN: math.matrices PRIVATE> -: cross ( vec1 vec2 -- vec3 ) [ i ] [ j ] [ k ] 2tri 3array ; +: cross ( vec1 vec2 -- vec3 ) [ [ i ] [ j ] [ k ] 2tri ] keep 3sequence ; : proj ( v u -- w ) [ [ v. ] [ norm-sq ] bi / ] keep n*v ; From 771d4fd4d9071a276d034833e17db39c5b477436 Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Tue, 7 Jul 2009 16:27:14 -0500 Subject: [PATCH 02/96] byte-length for specialized-vectors --- basis/specialized-vectors/functor/functor.factor | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/basis/specialized-vectors/functor/functor.factor b/basis/specialized-vectors/functor/functor.factor index 6635fbeaf2..08c44cd197 100644 --- a/basis/specialized-vectors/functor/functor.factor +++ b/basis/specialized-vectors/functor/functor.factor @@ -1,6 +1,6 @@ ! Copyright (C) 2008, 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: functors sequences sequences.private growable +USING: accessors alien.c-types functors sequences sequences.private growable prettyprint.custom kernel words classes math parser ; QUALIFIED: vectors.functor IN: specialized-vectors.functor @@ -21,6 +21,8 @@ V A vectors.functor:define-vector M: V contract 2drop ; +M: V byte-length underlying>> byte-length ; + M: V pprint-delims drop \ V{ \ } ; M: V >pprint-sequence ; From cf3038b7d6f7e440005eeef9dba4d4e35f6122a0 Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Thu, 9 Jul 2009 23:07:38 -0500 Subject: [PATCH 03/96] Improving modular arithmetic optimization to be aware of words like set-alien-unsigned-2 --- .../modular-arithmetic-tests.factor | 37 ++++++++++++++++++- .../modular-arithmetic.factor | 14 ++++++- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/basis/compiler/tree/modular-arithmetic/modular-arithmetic-tests.factor b/basis/compiler/tree/modular-arithmetic/modular-arithmetic-tests.factor index 6e1c32d89d..55a8cb9ea2 100644 --- a/basis/compiler/tree/modular-arithmetic/modular-arithmetic-tests.factor +++ b/basis/compiler/tree/modular-arithmetic/modular-arithmetic-tests.factor @@ -3,7 +3,8 @@ USING: kernel kernel.private tools.test math math.partial-dispatch math.private accessors slots.private sequences strings sbufs compiler.tree.builder compiler.tree.optimizer -compiler.tree.debugger ; +compiler.tree.debugger +alien.accessors layouts combinators byte-arrays ; : test-modular-arithmetic ( quot -- quot' ) build-tree optimize-tree nodes>quot ; @@ -135,4 +136,36 @@ TUPLE: declared-fixnum { x fixnum } ; ] unit-test [ [ >fixnum 255 fixnum-bitand ] ] -[ [ >integer 256 rem ] test-modular-arithmetic ] unit-test \ No newline at end of file +[ [ >integer 256 rem ] test-modular-arithmetic ] unit-test + +[ [ "COMPLEX SHUFFLE" fixnum+fast "COMPLEX SHUFFLE" set-alien-unsigned-1 ] ] +[ [ [ { fixnum fixnum } declare + ] 2dip set-alien-unsigned-1 ] test-modular-arithmetic ] unit-test + +[ [ "COMPLEX SHUFFLE" fixnum+fast "COMPLEX SHUFFLE" set-alien-unsigned-2 ] ] +[ [ [ { fixnum fixnum } declare + ] 2dip set-alien-unsigned-2 ] test-modular-arithmetic ] unit-test + +cell { + { 4 [ [ [ "COMPLEX SHUFFLE" fixnum+ "COMPLEX SHUFFLE" set-alien-unsigned-4 ] ] ] } + { 8 [ [ [ "COMPLEX SHUFFLE" fixnum+fast "COMPLEX SHUFFLE" set-alien-unsigned-4 ] ] ] } +} case +[ [ [ { fixnum fixnum } declare + ] 2dip set-alien-unsigned-4 ] test-modular-arithmetic ] unit-test + +[ [ "COMPLEX SHUFFLE" fixnum+ "COMPLEX SHUFFLE" set-alien-unsigned-8 ] ] +[ [ [ { fixnum fixnum } declare + ] 2dip set-alien-unsigned-8 ] test-modular-arithmetic ] unit-test + +[ [ "COMPLEX SHUFFLE" fixnum+fast "COMPLEX SHUFFLE" set-alien-signed-1 ] ] +[ [ [ { fixnum fixnum } declare + ] 2dip set-alien-signed-1 ] test-modular-arithmetic ] unit-test + +[ [ "COMPLEX SHUFFLE" fixnum+fast "COMPLEX SHUFFLE" set-alien-signed-2 ] ] +[ [ [ { fixnum fixnum } declare + ] 2dip set-alien-signed-2 ] test-modular-arithmetic ] unit-test + +cell { + { 4 [ [ [ "COMPLEX SHUFFLE" fixnum+ "COMPLEX SHUFFLE" set-alien-signed-4 ] ] ] } + { 8 [ [ [ "COMPLEX SHUFFLE" fixnum+fast "COMPLEX SHUFFLE" set-alien-signed-4 ] ] ] } +} case +[ [ [ { fixnum fixnum } declare + ] 2dip set-alien-signed-4 ] test-modular-arithmetic ] unit-test + +[ [ "COMPLEX SHUFFLE" fixnum+ "COMPLEX SHUFFLE" set-alien-signed-8 ] ] +[ [ [ { fixnum fixnum } declare + ] 2dip set-alien-signed-8 ] test-modular-arithmetic ] unit-test + +[ t ] [ [ { fixnum byte-array } declare [ + ] with map ] { + fixnum+ >fixnum } inlined? ] unit-test diff --git a/basis/compiler/tree/modular-arithmetic/modular-arithmetic.factor b/basis/compiler/tree/modular-arithmetic/modular-arithmetic.factor index 31939a0d22..6ddefa9307 100644 --- a/basis/compiler/tree/modular-arithmetic/modular-arithmetic.factor +++ b/basis/compiler/tree/modular-arithmetic/modular-arithmetic.factor @@ -2,7 +2,7 @@ ! See http://factorcode.org/license.txt for BSD license. USING: math math.partial-dispatch namespaces sequences sets accessors assocs words kernel memoize fry combinators -combinators.short-circuit +combinators.short-circuit layouts alien.accessors compiler.tree compiler.tree.combinators compiler.tree.def-use @@ -28,6 +28,16 @@ IN: compiler.tree.modular-arithmetic { bitand bitor bitxor bitnot } [ t "modular-arithmetic" set-word-prop ] each +{ + >fixnum + set-alien-unsigned-1 set-alien-signed-1 + set-alien-unsigned-2 set-alien-signed-2 +} +cell 8 = [ + { set-alien-unsigned-4 set-alien-signed-4 } append +] when +[ t "low-order" set-word-prop ] each + SYMBOL: modularize-values : modular-value? ( value -- ? ) @@ -54,7 +64,7 @@ M: node maybe-modularize* 2drop ; GENERIC: compute-modularized-values* ( node -- ) M: #call compute-modularized-values* - dup word>> \ >fixnum eq? + dup word>> "low-order" word-prop [ in-d>> first maybe-modularize ] [ drop ] if ; M: node compute-modularized-values* drop ; From 4b29d13fdaca1bb8a91e973539e3751c72a994bf Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Thu, 9 Jul 2009 23:09:49 -0500 Subject: [PATCH 04/96] Adding authors to compiler.tree.modular-arithmetic --- basis/compiler/tree/modular-arithmetic/authors.txt | 2 ++ .../tree/modular-arithmetic/modular-arithmetic-tests.factor | 2 ++ .../compiler/tree/modular-arithmetic/modular-arithmetic.factor | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 basis/compiler/tree/modular-arithmetic/authors.txt diff --git a/basis/compiler/tree/modular-arithmetic/authors.txt b/basis/compiler/tree/modular-arithmetic/authors.txt new file mode 100644 index 0000000000..a44f8d7f8d --- /dev/null +++ b/basis/compiler/tree/modular-arithmetic/authors.txt @@ -0,0 +1,2 @@ +Slava Pestov +Daniel Ehrenberg diff --git a/basis/compiler/tree/modular-arithmetic/modular-arithmetic-tests.factor b/basis/compiler/tree/modular-arithmetic/modular-arithmetic-tests.factor index 55a8cb9ea2..7fb1b3d5ac 100644 --- a/basis/compiler/tree/modular-arithmetic/modular-arithmetic-tests.factor +++ b/basis/compiler/tree/modular-arithmetic/modular-arithmetic-tests.factor @@ -1,3 +1,5 @@ +! Copyright (C) 2008, 2009 Slava Pestov, Daniel Ehrenberg. +! See http://factorcode.org/license.txt for BSD license. IN: compiler.tree.modular-arithmetic.tests USING: kernel kernel.private tools.test math math.partial-dispatch math.private accessors slots.private sequences strings sbufs diff --git a/basis/compiler/tree/modular-arithmetic/modular-arithmetic.factor b/basis/compiler/tree/modular-arithmetic/modular-arithmetic.factor index 6ddefa9307..148286faba 100644 --- a/basis/compiler/tree/modular-arithmetic/modular-arithmetic.factor +++ b/basis/compiler/tree/modular-arithmetic/modular-arithmetic.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2008 Slava Pestov. +! Copyright (C) 2008, 2009 Slava Pestov, Daniel Ehrenberg. ! See http://factorcode.org/license.txt for BSD license. USING: math math.partial-dispatch namespaces sequences sets accessors assocs words kernel memoize fry combinators From d02854b04ebc74a06f3b7381cd2b4676d36e36d8 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 9 Jul 2009 23:12:49 -0500 Subject: [PATCH 05/96] compiler.cfg.linear-scan: two live intervals which are coalesced will use the same spill slot --- .../allocation/spilling/spilling.factor | 4 ++-- .../cfg/linear-scan/allocation/state/state.factor | 14 ++++++++++++-- .../cfg/linear-scan/assignment/assignment.factor | 2 +- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/basis/compiler/cfg/linear-scan/allocation/spilling/spilling.factor b/basis/compiler/cfg/linear-scan/allocation/spilling/spilling.factor index b89c1f4de2..8c91ca7f60 100644 --- a/basis/compiler/cfg/linear-scan/allocation/spilling/spilling.factor +++ b/basis/compiler/cfg/linear-scan/allocation/spilling/spilling.factor @@ -38,10 +38,10 @@ ERROR: bad-live-ranges interval ; } 2cleave ; : assign-spill ( live-interval -- ) - dup vreg>> assign-spill-slot >>spill-to f >>split-next drop ; + dup assign-spill-slot >>spill-to f >>split-next drop ; : assign-reload ( live-interval -- ) - dup vreg>> assign-spill-slot >>reload-from drop ; + dup assign-spill-slot >>reload-from drop ; : split-and-spill ( live-interval n -- before after ) split-for-spill 2dup [ assign-spill ] [ assign-reload ] bi* ; diff --git a/basis/compiler/cfg/linear-scan/allocation/state/state.factor b/basis/compiler/cfg/linear-scan/allocation/state/state.factor index 3e646b40f0..1e670ad6a6 100644 --- a/basis/compiler/cfg/linear-scan/allocation/state/state.factor +++ b/basis/compiler/cfg/linear-scan/allocation/state/state.factor @@ -126,8 +126,18 @@ SYMBOL: spill-counts ! Mapping from vregs to spill slots SYMBOL: spill-slots -: assign-spill-slot ( vreg -- n ) - spill-slots get [ reg-class>> next-spill-slot ] cache ; +DEFER: assign-spill-slot + +: compute-spill-slot ( live-interval -- n ) + dup copy-from>> + [ assign-spill-slot ] + [ vreg>> reg-class>> next-spill-slot ] ?if ; + +: assign-spill-slot ( live-interval -- n ) + dup vreg>> spill-slots get at [ ] [ + [ compute-spill-slot dup ] keep + vreg>> spill-slots get set-at + ] ?if ; : init-allocator ( registers -- ) registers set diff --git a/basis/compiler/cfg/linear-scan/assignment/assignment.factor b/basis/compiler/cfg/linear-scan/assignment/assignment.factor index 143e84aaf4..9275c6d687 100644 --- a/basis/compiler/cfg/linear-scan/assignment/assignment.factor +++ b/basis/compiler/cfg/linear-scan/assignment/assignment.factor @@ -107,7 +107,7 @@ SYMBOL: check-assignment? ERROR: overlapping-registers intervals ; : check-assignment ( intervals -- ) - dup [ copy-from>> ] map sift '[ vreg>> _ member? not ] filter + dup [ copy-from>> ] map sift [ vreg>> ] map '[ vreg>> _ member? not ] filter dup [ reg>> ] map all-unique? [ drop ] [ overlapping-registers ] if ; : active-intervals ( n -- intervals ) From 6810b922eeea59f05893925e7cccc5c7433037a9 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 9 Jul 2009 23:13:30 -0500 Subject: [PATCH 06/96] compiler.cfg: move back-edge? word from stack-analysis to top-level vocab --- basis/compiler/cfg/cfg.factor | 3 +++ basis/compiler/cfg/stack-analysis/stack-analysis.factor | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/basis/compiler/cfg/cfg.factor b/basis/compiler/cfg/cfg.factor index 68d7e15a5d..12a1180d40 100644 --- a/basis/compiler/cfg/cfg.factor +++ b/basis/compiler/cfg/cfg.factor @@ -48,6 +48,9 @@ SYMBOL: visited building get push ] with-variable ; inline +: back-edge? ( from to -- ? ) + [ number>> ] bi@ > ; + TUPLE: cfg { entry basic-block } word label spill-counts post-order ; : ( entry word label -- cfg ) f f cfg boa ; diff --git a/basis/compiler/cfg/stack-analysis/stack-analysis.factor b/basis/compiler/cfg/stack-analysis/stack-analysis.factor index fb71fe332d..ab16bbea44 100644 --- a/basis/compiler/cfg/stack-analysis/stack-analysis.factor +++ b/basis/compiler/cfg/stack-analysis/stack-analysis.factor @@ -60,9 +60,6 @@ UNION: sync-if-back-edge ##dispatch ##loop-entry ; -: back-edge? ( from to -- ? ) - [ number>> ] bi@ > ; - : sync-state? ( -- ? ) basic-block get successors>> [ [ predecessors>> ] keep '[ _ back-edge? ] any? ] any? ; From 789d82745c2dccb065aa6123843a7f507133ce3c Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 9 Jul 2009 23:14:26 -0500 Subject: [PATCH 07/96] compiler.cfg.value-numbering: factor out value renaming into a separate compiler.cfg.renaming vocabulary --- basis/compiler/cfg/renaming/renaming.factor | 151 ++++++++++++++++++ .../propagate/propagate.factor | 69 -------- .../cfg/value-numbering/propagate/summary.txt | 1 - .../value-numbering/value-numbering.factor | 18 ++- 4 files changed, 165 insertions(+), 74 deletions(-) create mode 100644 basis/compiler/cfg/renaming/renaming.factor delete mode 100644 basis/compiler/cfg/value-numbering/propagate/propagate.factor delete mode 100644 basis/compiler/cfg/value-numbering/propagate/summary.txt diff --git a/basis/compiler/cfg/renaming/renaming.factor b/basis/compiler/cfg/renaming/renaming.factor new file mode 100644 index 0000000000..4a8c6e6a4d --- /dev/null +++ b/basis/compiler/cfg/renaming/renaming.factor @@ -0,0 +1,151 @@ +! Copyright (C) 2009 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: accessors assocs kernel namespaces sequences +compiler.cfg.instructions compiler.cfg.registers ; +IN: compiler.cfg.renaming + +SYMBOL: renamings + +: rename-value ( vreg -- vreg' ) renamings get at ; + +GENERIC: rename-insn-defs ( insn -- ) + +M: ##flushable rename-insn-defs + [ rename-value ] change-dst + drop ; + +M: insn rename-insn-defs drop ; + +GENERIC: rename-insn-uses ( insn -- ) + +M: ##effect rename-insn-uses + [ rename-value ] change-src + drop ; + +M: ##unary rename-insn-uses + [ rename-value ] change-src + drop ; + +M: ##binary rename-insn-uses + [ rename-value ] change-src1 + [ rename-value ] change-src2 + drop ; + +M: ##binary-imm rename-insn-uses + [ rename-value ] change-src1 + drop ; + +M: ##slot rename-insn-uses + [ rename-value ] change-obj + [ rename-value ] change-slot + drop ; + +M: ##slot-imm rename-insn-uses + [ rename-value ] change-obj + drop ; + +M: ##set-slot rename-insn-uses + dup call-next-method + [ rename-value ] change-obj + [ rename-value ] change-slot + drop ; + +M: ##string-nth rename-insn-uses + [ rename-value ] change-obj + [ rename-value ] change-index + drop ; + +M: ##set-slot-imm rename-insn-uses + dup call-next-method + [ rename-value ] change-obj + drop ; + +M: ##alien-getter rename-insn-uses + dup call-next-method + [ rename-value ] change-src + drop ; + +M: ##alien-setter rename-insn-uses + dup call-next-method + [ rename-value ] change-value + drop ; + +M: ##conditional-branch rename-insn-uses + [ rename-value ] change-src1 + [ rename-value ] change-src2 + drop ; + +M: ##compare-imm-branch rename-insn-uses + [ rename-value ] change-src1 + drop ; + +M: ##dispatch rename-insn-uses + [ rename-value ] change-src + drop ; + +M: ##fixnum-overflow rename-insn-uses + [ rename-value ] change-src1 + [ rename-value ] change-src2 + drop ; + +M: insn rename-insn-uses drop ; + +: fresh-vreg ( vreg -- vreg' ) + reg-class>> next-vreg ; + +GENERIC: fresh-insn-temps ( insn -- ) + +M: ##write-barrier fresh-insn-temps + [ fresh-vreg ] change-card# + [ fresh-vreg ] change-table + drop ; + +M: ##unary/temp fresh-insn-temps + [ fresh-vreg ] change-temp drop ; + +M: ##allot fresh-insn-temps + [ fresh-vreg ] change-temp drop ; + +M: ##dispatch fresh-insn-temps + [ fresh-vreg ] change-temp drop ; + +M: ##slot fresh-insn-temps + [ fresh-vreg ] change-temp drop ; + +M: ##set-slot fresh-insn-temps + [ fresh-vreg ] change-temp drop ; + +M: ##string-nth fresh-insn-temps + [ fresh-vreg ] change-temp drop ; + +M: ##set-string-nth-fast fresh-insn-temps + [ fresh-vreg ] change-temp drop ; + +M: ##compare fresh-insn-temps + [ fresh-vreg ] change-temp drop ; + +M: ##compare-imm fresh-insn-temps + [ fresh-vreg ] change-temp drop ; + +M: ##compare-float fresh-insn-temps + [ fresh-vreg ] change-temp drop ; + +M: ##fixnum-mul fresh-insn-temps + [ fresh-vreg ] change-temp1 + [ fresh-vreg ] change-temp2 + drop ; + +M: ##fixnum-mul-tail fresh-insn-temps + [ fresh-vreg ] change-temp1 + [ fresh-vreg ] change-temp2 + drop ; + +M: ##gc fresh-insn-temps + [ fresh-vreg ] change-temp1 + [ fresh-vreg ] change-temp2 + drop ; + +M: _dispatch fresh-insn-temps + [ fresh-vreg ] change-temp drop ; + +M: insn fresh-insn-temps drop ; \ No newline at end of file diff --git a/basis/compiler/cfg/value-numbering/propagate/propagate.factor b/basis/compiler/cfg/value-numbering/propagate/propagate.factor deleted file mode 100644 index d5c9830c0b..0000000000 --- a/basis/compiler/cfg/value-numbering/propagate/propagate.factor +++ /dev/null @@ -1,69 +0,0 @@ -! Copyright (C) 2008 Slava Pestov. -! See http://factorcode.org/license.txt for BSD license. -USING: namespaces assocs sequences kernel accessors -compiler.cfg.instructions compiler.cfg.value-numbering.graph ; -IN: compiler.cfg.value-numbering.propagate - -! If two vregs compute the same value, replace references to -! the latter with the former. - -: resolve ( vreg -- vreg' ) vreg>vn vn>vreg ; inline - -GENERIC: propagate ( insn -- insn ) - -M: ##effect propagate - [ resolve ] change-src ; - -M: ##unary propagate - [ resolve ] change-src ; - -M: ##binary propagate - [ resolve ] change-src1 - [ resolve ] change-src2 ; - -M: ##binary-imm propagate - [ resolve ] change-src1 ; - -M: ##slot propagate - [ resolve ] change-obj - [ resolve ] change-slot ; - -M: ##slot-imm propagate - [ resolve ] change-obj ; - -M: ##set-slot propagate - call-next-method - [ resolve ] change-obj - [ resolve ] change-slot ; - -M: ##string-nth propagate - [ resolve ] change-obj - [ resolve ] change-index ; - -M: ##set-slot-imm propagate - call-next-method - [ resolve ] change-obj ; - -M: ##alien-getter propagate - call-next-method - [ resolve ] change-src ; - -M: ##alien-setter propagate - call-next-method - [ resolve ] change-value ; - -M: ##conditional-branch propagate - [ resolve ] change-src1 - [ resolve ] change-src2 ; - -M: ##compare-imm-branch propagate - [ resolve ] change-src1 ; - -M: ##dispatch propagate - [ resolve ] change-src ; - -M: ##fixnum-overflow propagate - [ resolve ] change-src1 - [ resolve ] change-src2 ; - -M: insn propagate ; diff --git a/basis/compiler/cfg/value-numbering/propagate/summary.txt b/basis/compiler/cfg/value-numbering/propagate/summary.txt deleted file mode 100644 index fd56a8e099..0000000000 --- a/basis/compiler/cfg/value-numbering/propagate/summary.txt +++ /dev/null @@ -1 +0,0 @@ -Propagation pass to update code after value numbering diff --git a/basis/compiler/cfg/value-numbering/value-numbering.factor b/basis/compiler/cfg/value-numbering/value-numbering.factor index 9f5473c62f..f0efa5dcca 100644 --- a/basis/compiler/cfg/value-numbering/value-numbering.factor +++ b/basis/compiler/cfg/value-numbering/value-numbering.factor @@ -1,12 +1,12 @@ -! Copyright (C) 2008 Slava Pestov. +! Copyright (C) 2008, 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: namespaces assocs biassocs classes kernel math accessors -sorting sets sequences +sorting sets sequences fry compiler.cfg.local compiler.cfg.liveness +compiler.cfg.renaming compiler.cfg.value-numbering.graph compiler.cfg.value-numbering.expressions -compiler.cfg.value-numbering.propagate compiler.cfg.value-numbering.simplify compiler.cfg.value-numbering.rewrite ; IN: compiler.cfg.value-numbering @@ -19,8 +19,18 @@ IN: compiler.cfg.value-numbering init-expressions number-input-values ; +: vreg>vreg-mapping ( -- assoc ) + vregs>vns get [ keys ] keep + '[ dup _ [ at ] [ value-at ] bi ] H{ } map>assoc ; + +: rename-uses ( insns -- ) + vreg>vreg-mapping renamings [ + [ rename-insn-uses ] each + ] with-variable ; + : value-numbering-step ( insns -- insns' ) - [ [ number-values ] [ rewrite propagate ] bi ] map ; + [ [ number-values ] [ rewrite ] bi ] map + dup rename-uses ; : value-numbering ( cfg -- cfg' ) [ init-value-numbering ] [ value-numbering-step ] local-optimization ; From dea872c7e3526b9df0bf9995d6084cdc9461de14 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 10 Jul 2009 00:25:46 -0500 Subject: [PATCH 08/96] compiler.cfg.linear-scan.allocation: fix broken spill slot reuse logic --- .../allocation/coalescing/coalescing.factor | 15 +++++++++++---- .../allocation/spilling/spilling.factor | 4 ++-- .../cfg/linear-scan/allocation/state/state.factor | 14 ++------------ 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/basis/compiler/cfg/linear-scan/allocation/coalescing/coalescing.factor b/basis/compiler/cfg/linear-scan/allocation/coalescing/coalescing.factor index e99c2ba710..ef8a9c56f8 100644 --- a/basis/compiler/cfg/linear-scan/allocation/coalescing/coalescing.factor +++ b/basis/compiler/cfg/linear-scan/allocation/coalescing/coalescing.factor @@ -1,6 +1,6 @@ ! Copyright (C) 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: accessors kernel sequences +USING: accessors kernel sequences namespaces assocs fry combinators.short-circuit compiler.cfg.linear-scan.live-intervals compiler.cfg.linear-scan.allocation.state ; @@ -20,9 +20,16 @@ IN: compiler.cfg.linear-scan.allocation.coalescing [ avoids-inactive-intervals? ] } 1&& ; +: reuse-spill-slot ( old new -- ) + [ vreg>> spill-slots get at ] dip '[ _ vreg>> spill-slots get set-at ] when* ; + +: reuse-register ( old new -- ) + reg>> >>reg drop ; + +: (coalesce) ( old new -- ) + [ add-active ] [ [ delete-active ] [ add-handled ] bi ] bi* ; + : coalesce ( live-interval -- ) dup copy-from>> active-interval - [ [ add-active ] [ [ delete-active ] [ add-handled ] bi ] bi* ] - [ reg>> >>reg drop ] - 2bi ; + [ reuse-spill-slot ] [ reuse-register ] [ (coalesce) ] 2tri ; \ No newline at end of file diff --git a/basis/compiler/cfg/linear-scan/allocation/spilling/spilling.factor b/basis/compiler/cfg/linear-scan/allocation/spilling/spilling.factor index 8c91ca7f60..b89c1f4de2 100644 --- a/basis/compiler/cfg/linear-scan/allocation/spilling/spilling.factor +++ b/basis/compiler/cfg/linear-scan/allocation/spilling/spilling.factor @@ -38,10 +38,10 @@ ERROR: bad-live-ranges interval ; } 2cleave ; : assign-spill ( live-interval -- ) - dup assign-spill-slot >>spill-to f >>split-next drop ; + dup vreg>> assign-spill-slot >>spill-to f >>split-next drop ; : assign-reload ( live-interval -- ) - dup assign-spill-slot >>reload-from drop ; + dup vreg>> assign-spill-slot >>reload-from drop ; : split-and-spill ( live-interval n -- before after ) split-for-spill 2dup [ assign-spill ] [ assign-reload ] bi* ; diff --git a/basis/compiler/cfg/linear-scan/allocation/state/state.factor b/basis/compiler/cfg/linear-scan/allocation/state/state.factor index 1e670ad6a6..3e646b40f0 100644 --- a/basis/compiler/cfg/linear-scan/allocation/state/state.factor +++ b/basis/compiler/cfg/linear-scan/allocation/state/state.factor @@ -126,18 +126,8 @@ SYMBOL: spill-counts ! Mapping from vregs to spill slots SYMBOL: spill-slots -DEFER: assign-spill-slot - -: compute-spill-slot ( live-interval -- n ) - dup copy-from>> - [ assign-spill-slot ] - [ vreg>> reg-class>> next-spill-slot ] ?if ; - -: assign-spill-slot ( live-interval -- n ) - dup vreg>> spill-slots get at [ ] [ - [ compute-spill-slot dup ] keep - vreg>> spill-slots get set-at - ] ?if ; +: assign-spill-slot ( vreg -- n ) + spill-slots get [ reg-class>> next-spill-slot ] cache ; : init-allocator ( registers -- ) registers set From 23b8f4826764027d406232d24e2b0ee05ccc0bac Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Fri, 10 Jul 2009 00:52:08 -0500 Subject: [PATCH 09/96] stack-checker.known-words:infer-special uses a word property --- basis/stack-checker/known-words/authors.txt | 1 + .../known-words/known-words.factor | 84 ++++++++++++------- 2 files changed, 53 insertions(+), 32 deletions(-) diff --git a/basis/stack-checker/known-words/authors.txt b/basis/stack-checker/known-words/authors.txt index 1901f27a24..a44f8d7f8d 100644 --- a/basis/stack-checker/known-words/authors.txt +++ b/basis/stack-checker/known-words/authors.txt @@ -1 +1,2 @@ Slava Pestov +Daniel Ehrenberg diff --git a/basis/stack-checker/known-words/known-words.factor b/basis/stack-checker/known-words/known-words.factor index cf2d08b84f..5bf50dfac1 100644 --- a/basis/stack-checker/known-words/known-words.factor +++ b/basis/stack-checker/known-words/known-words.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2004, 2009 Slava Pestov. +! Copyright (C) 2004, 2009 Slava Pestov, Daniel Ehrenberg. ! See http://factorcode.org/license.txt for BSD license. USING: fry accessors alien alien.accessors arrays byte-arrays classes continuations.private effects generic hashtables @@ -67,12 +67,18 @@ IN: stack-checker.known-words [ length ensure-d ] keep zip #declare, ; +\ declare [ infer-declare ] "special" set-word-prop + GENERIC: infer-call* ( value known -- ) : (infer-call) ( value -- ) dup known infer-call* ; : infer-call ( -- ) pop-d (infer-call) ; +\ call [ infer-call ] "special" set-word-prop + +\ (call) [ infer-call ] "special" set-word-prop + M: literal infer-call* [ 1array #drop, ] [ infer-literal-quot ] bi* ; @@ -103,10 +109,16 @@ M: object infer-call* : infer-dip ( -- ) \ dip 1 infer-ndip ; +\ dip [ infer-dip ] "special" set-word-prop + : infer-2dip ( -- ) \ 2dip 2 infer-ndip ; +\ 2dip [ infer-2dip ] "special" set-word-prop + : infer-3dip ( -- ) \ 3dip 3 infer-ndip ; +\ 3dip [ infer-3dip ] "special" set-word-prop + : infer-builder ( quot word -- ) [ [ 2 consume-d ] dip @@ -116,8 +128,12 @@ M: object infer-call* : infer-curry ( -- ) [ ] \ curry infer-builder ; +\ curry [ infer-curry ] "special" set-word-prop + : infer-compose ( -- ) [ ] \ compose infer-builder ; +\ compose [ infer-compose ] "special" set-word-prop + : infer-execute ( -- ) pop-literal nip dup word? [ @@ -127,11 +143,17 @@ M: object infer-call* "execute must be given a word" time-bomb ] if ; +\ execute [ infer-execute ] "special" set-word-prop + +\ (execute) [ infer-execute ] "special" set-word-prop + : infer- ( -- ) \ peek-d literal value>> second 1+ { tuple } apply-word/effect ; +\ [ infer- ] "special" set-word-prop + : infer-effect-unsafe ( word -- ) pop-literal nip add-effect-input @@ -140,17 +162,30 @@ M: object infer-call* : infer-execute-effect-unsafe ( -- ) \ (execute) infer-effect-unsafe ; +\ execute-effect-unsafe [ infer-execute-effect-unsafe ] "special" set-word-prop + : infer-call-effect-unsafe ( -- ) \ call infer-effect-unsafe ; +\ call-effect-unsafe [ infer-call-effect-unsafe ] "special" set-word-prop + : infer-exit ( -- ) \ exit (( n -- * )) apply-word/effect ; +\ exit [ infer-exit ] "special" set-word-prop + : infer-load-locals ( -- ) pop-literal nip consume-d dup copy-values dup output-r [ [ f f ] dip ] [ swap zip ] 2bi #shuffle, ; +\ load-locals [ infer-load-locals ] "special" set-word-prop + +: infer-load-local ( -- ) + 1 infer->r ; + +\ load-local [ infer-load-local ] "special" set-word-prop + : infer-get-local ( -- ) [let* | n [ pop-literal nip 1 swap - ] in-r [ n consume-r ] @@ -163,36 +198,24 @@ M: object infer-call* #shuffle, ] ; +\ get-local [ infer-get-local ] "special" set-word-prop + : infer-drop-locals ( -- ) f f pop-literal nip consume-r f f #shuffle, ; +\ drop-locals [ infer-drop-locals ] "special" set-word-prop + +\ do-primitive [ unknown-primitive-error ] "special" set-word-prop + +\ if [ infer-if ] "special" set-word-prop +\ dispatch [ infer-dispatch ] "special" set-word-prop + +\ alien-invoke [ infer-alien-invoke ] "special" set-word-prop +\ alien-indirect [ infer-alien-indirect ] "special" set-word-prop +\ alien-callback [ infer-alien-callback ] "special" set-word-prop + : infer-special ( word -- ) - { - { \ declare [ infer-declare ] } - { \ call [ infer-call ] } - { \ (call) [ infer-call ] } - { \ dip [ infer-dip ] } - { \ 2dip [ infer-2dip ] } - { \ 3dip [ infer-3dip ] } - { \ curry [ infer-curry ] } - { \ compose [ infer-compose ] } - { \ execute [ infer-execute ] } - { \ (execute) [ infer-execute ] } - { \ execute-effect-unsafe [ infer-execute-effect-unsafe ] } - { \ call-effect-unsafe [ infer-call-effect-unsafe ] } - { \ if [ infer-if ] } - { \ dispatch [ infer-dispatch ] } - { \ [ infer- ] } - { \ exit [ infer-exit ] } - { \ load-local [ 1 infer->r ] } - { \ load-locals [ infer-load-locals ] } - { \ get-local [ infer-get-local ] } - { \ drop-locals [ infer-drop-locals ] } - { \ do-primitive [ unknown-primitive-error ] } - { \ alien-invoke [ infer-alien-invoke ] } - { \ alien-indirect [ infer-alien-indirect ] } - { \ alien-callback [ infer-alien-callback ] } - } case ; + "special" word-prop call( -- ) ; : infer-local-reader ( word -- ) (( -- value )) apply-word/effect ; @@ -209,10 +232,7 @@ M: object infer-call* dispatch exit load-local load-locals get-local drop-locals do-primitive alien-invoke alien-indirect alien-callback -} [ - [ t "special" set-word-prop ] - [ t "no-compile" set-word-prop ] bi -] each +} [ t "no-compile" set-word-prop ] each ! Exceptions to the above \ curry f "no-compile" set-word-prop @@ -662,4 +682,4 @@ M: object infer-call* \ reset-inline-cache-stats { } { } define-primitive \ inline-cache-stats { } { array } define-primitive -\ optimized? { word } { object } define-primitive \ No newline at end of file +\ optimized? { word } { object } define-primitive From 500c784bd7bf4cb9b5a85b10fa37ffcff804bd38 Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Fri, 10 Jul 2009 01:05:03 -0500 Subject: [PATCH 10/96] Minor reorganization of stack-checker.call-effect --- .../call-effect/call-effect.factor | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/basis/stack-checker/call-effect/call-effect.factor b/basis/stack-checker/call-effect/call-effect.factor index b3b678d93d..12477fdb1d 100644 --- a/basis/stack-checker/call-effect/call-effect.factor +++ b/basis/stack-checker/call-effect/call-effect.factor @@ -84,16 +84,16 @@ M: quotation cached-effect [ drop call-effect-slow ] if ; inline -\ call-effect [ - inline-cache new '[ - _ - 3dup nip cache-hit? [ - drop call-effect-unsafe - ] [ - call-effect-fast - ] if - ] -] 0 define-transform +: call-effect-ic ( quot effect inline-cache -- ) + 3dup nip cache-hit? + [ drop call-effect-unsafe ] + [ call-effect-fast ] + if ; inline + +: call-effect>quot ( -- quot ) + inline-cache new '[ _ call-effect-ic ] ; + +\ call-effect [ call-effect>quot ] 0 define-transform \ call-effect t "no-compile" set-word-prop @@ -120,4 +120,4 @@ M: quotation cached-effect \ execute-effect [ execute-effect>quot ] 1 define-transform -\ execute-effect t "no-compile" set-word-prop \ No newline at end of file +\ execute-effect t "no-compile" set-word-prop From 11347e784c1d2dc4c6c4a34de593ef3520683bad Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 10 Jul 2009 03:05:45 -0500 Subject: [PATCH 11/96] insn. doesn't print numbers --- basis/compiler/cfg/debugger/debugger.factor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basis/compiler/cfg/debugger/debugger.factor b/basis/compiler/cfg/debugger/debugger.factor index 60805124cd..e355ee2ac1 100644 --- a/basis/compiler/cfg/debugger/debugger.factor +++ b/basis/compiler/cfg/debugger/debugger.factor @@ -26,7 +26,7 @@ M: word test-cfg ] map ; : insn. ( insn -- ) - tuple>array [ pprint bl ] each nl ; + tuple>array but-last [ pprint bl ] each nl ; : mr. ( mrs -- ) [ From ae67de6f905ab393af3542b9821047683fe12063 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 10 Jul 2009 03:58:51 -0500 Subject: [PATCH 12/96] compiler.cfg.linear-scan: fix fencepost error in spill insertion --- .../allocation/spilling/spilling.factor | 2 +- .../linear-scan/assignment/assignment.factor | 4 +- .../cfg/linear-scan/linear-scan-tests.factor | 203 ++++++++++++++---- 3 files changed, 167 insertions(+), 42 deletions(-) diff --git a/basis/compiler/cfg/linear-scan/allocation/spilling/spilling.factor b/basis/compiler/cfg/linear-scan/allocation/spilling/spilling.factor index b89c1f4de2..14046a91f1 100644 --- a/basis/compiler/cfg/linear-scan/allocation/spilling/spilling.factor +++ b/basis/compiler/cfg/linear-scan/allocation/spilling/spilling.factor @@ -17,7 +17,7 @@ ERROR: bad-live-ranges interval ; ] [ drop ] if ; : trim-before-ranges ( live-interval -- ) - [ ranges>> ] [ uses>> last ] bi + [ ranges>> ] [ uses>> last 1 + ] bi [ '[ from>> _ <= ] filter-here ] [ swap last (>>to) ] 2bi ; diff --git a/basis/compiler/cfg/linear-scan/assignment/assignment.factor b/basis/compiler/cfg/linear-scan/assignment/assignment.factor index 9275c6d687..c0f90e5932 100644 --- a/basis/compiler/cfg/linear-scan/assignment/assignment.factor +++ b/basis/compiler/cfg/linear-scan/assignment/assignment.factor @@ -107,7 +107,7 @@ SYMBOL: check-assignment? ERROR: overlapping-registers intervals ; : check-assignment ( intervals -- ) - dup [ copy-from>> ] map sift [ vreg>> ] map '[ vreg>> _ member? not ] filter + dup [ copy-from>> ] map sift '[ vreg>> _ member? not ] filter dup [ reg>> ] map all-unique? [ drop ] [ overlapping-registers ] if ; : active-intervals ( n -- intervals ) @@ -150,7 +150,7 @@ ERROR: bad-live-values live-values ; : begin-block ( bb -- ) dup basic-block set - dup block-from prepare-insn + dup block-from activate-new-intervals [ [ live-in ] [ block-from ] bi compute-live-values ] keep register-live-ins get set-at ; diff --git a/basis/compiler/cfg/linear-scan/linear-scan-tests.factor b/basis/compiler/cfg/linear-scan/linear-scan-tests.factor index 06817071d4..bc3061128c 100644 --- a/basis/compiler/cfg/linear-scan/linear-scan-tests.factor +++ b/basis/compiler/cfg/linear-scan/linear-scan-tests.factor @@ -82,9 +82,9 @@ check-numbering? on T{ live-interval { vreg T{ vreg { reg-class int-regs } { n 1 } } } { start 0 } - { end 1 } + { end 2 } { uses V{ 0 1 } } - { ranges V{ T{ live-range f 0 1 } } } + { ranges V{ T{ live-range f 0 2 } } } } T{ live-interval { vreg T{ vreg { reg-class int-regs } { n 1 } } } @@ -107,9 +107,9 @@ check-numbering? on T{ live-interval { vreg T{ vreg { reg-class int-regs } { n 1 } } } { start 0 } - { end 0 } + { end 1 } { uses V{ 0 } } - { ranges V{ T{ live-range f 0 0 } } } + { ranges V{ T{ live-range f 0 1 } } } } T{ live-interval { vreg T{ vreg { reg-class int-regs } { n 1 } } } @@ -132,9 +132,9 @@ check-numbering? on T{ live-interval { vreg T{ vreg { reg-class int-regs } { n 1 } } } { start 0 } - { end 0 } + { end 1 } { uses V{ 0 } } - { ranges V{ T{ live-range f 0 0 } } } + { ranges V{ T{ live-range f 0 1 } } } } T{ live-interval { vreg T{ vreg { reg-class int-regs } { n 1 } } } @@ -1317,38 +1317,6 @@ USING: math.private ; allocate-registers drop ] unit-test -! Spill slot liveness was computed incorrectly, leading to a FEP -! early in bootstrap on x86-32 -[ t ] [ - [ - H{ } clone live-ins set - H{ } clone live-outs set - H{ } clone phi-live-ins set - T{ basic-block - { id 12345 } - { instructions - V{ - T{ ##gc f V int-regs 6 V int-regs 7 } - T{ ##peek f V int-regs 0 D 0 } - T{ ##peek f V int-regs 1 D 1 } - T{ ##peek f V int-regs 2 D 2 } - T{ ##peek f V int-regs 3 D 3 } - T{ ##peek f V int-regs 4 D 4 } - T{ ##peek f V int-regs 5 D 5 } - T{ ##replace f V int-regs 0 D 1 } - T{ ##replace f V int-regs 1 D 2 } - T{ ##replace f V int-regs 2 D 3 } - T{ ##replace f V int-regs 3 D 4 } - T{ ##replace f V int-regs 4 D 5 } - T{ ##replace f V int-regs 5 D 0 } - } - } - } dup 1array { { int-regs V{ 0 1 2 3 } } } (linear-scan) - instructions>> first - live-values>> assoc-empty? - ] with-scope -] unit-test - [ f ] [ T{ live-range f 0 10 } T{ live-range f 20 30 } @@ -2482,4 +2450,161 @@ V{ 7 get 9 get 1vector >>successors drop 8 get 9 get 1vector >>successors drop -[ ] [ { 1 2 3 4 5 } test-linear-scan-on-cfg ] unit-test \ No newline at end of file +[ ] [ { 1 2 3 4 5 } test-linear-scan-on-cfg ] unit-test + +! Fencepost error in assignment pass +V{ T{ ##branch } } 0 test-bb + +V{ + T{ ##peek f V int-regs 0 D 0 } + T{ ##compare-imm-branch f V int-regs 0 5 cc= } +} 1 test-bb + +V{ T{ ##branch } } 2 test-bb + +V{ + T{ ##peek f V int-regs 1 D 0 } + T{ ##peek f V int-regs 2 D 0 } + T{ ##replace f V int-regs 1 D 0 } + T{ ##replace f V int-regs 2 D 0 } + T{ ##branch } +} 3 test-bb + +V{ + T{ ##replace f V int-regs 0 D 0 } + T{ ##return } +} 4 test-bb + +test-diamond + +[ ] [ { 1 2 } test-linear-scan-on-cfg ] unit-test + +[ 0 ] [ 1 get instructions>> [ _spill? ] count ] unit-test + +[ 1 ] [ 2 get instructions>> [ _spill? ] count ] unit-test + +[ 1 ] [ 3 get instructions>> [ _spill? ] count ] unit-test + +[ 1 ] [ 4 get instructions>> [ _reload? ] count ] unit-test + +! Another test case for fencepost error in assignment pass +V{ T{ ##branch } } 0 test-bb + +V{ + T{ ##peek f V int-regs 0 D 0 } + T{ ##compare-imm-branch f V int-regs 0 5 cc= } +} 1 test-bb + +V{ + T{ ##peek f V int-regs 1 D 0 } + T{ ##peek f V int-regs 2 D 0 } + T{ ##replace f V int-regs 1 D 0 } + T{ ##replace f V int-regs 2 D 0 } + T{ ##replace f V int-regs 0 D 0 } + T{ ##branch } +} 2 test-bb + +V{ + T{ ##branch } +} 3 test-bb + +V{ + T{ ##replace f V int-regs 0 D 0 } + T{ ##return } +} 4 test-bb + +test-diamond + +[ ] [ { 1 2 } test-linear-scan-on-cfg ] unit-test + +[ 0 ] [ 1 get instructions>> [ _spill? ] count ] unit-test + +[ 1 ] [ 2 get instructions>> [ _spill? ] count ] unit-test + +[ 1 ] [ 2 get instructions>> [ _reload? ] count ] unit-test + +[ 0 ] [ 3 get instructions>> [ _spill? ] count ] unit-test + +[ 0 ] [ 4 get instructions>> [ _reload? ] count ] unit-test + +! GC check tests + +! Spill slot liveness was computed incorrectly, leading to a FEP +! early in bootstrap on x86-32 +[ t ] [ + [ + H{ } clone live-ins set + H{ } clone live-outs set + H{ } clone phi-live-ins set + T{ basic-block + { id 12345 } + { instructions + V{ + T{ ##gc f V int-regs 6 V int-regs 7 } + T{ ##peek f V int-regs 0 D 0 } + T{ ##peek f V int-regs 1 D 1 } + T{ ##peek f V int-regs 2 D 2 } + T{ ##peek f V int-regs 3 D 3 } + T{ ##peek f V int-regs 4 D 4 } + T{ ##peek f V int-regs 5 D 5 } + T{ ##replace f V int-regs 0 D 1 } + T{ ##replace f V int-regs 1 D 2 } + T{ ##replace f V int-regs 2 D 3 } + T{ ##replace f V int-regs 3 D 4 } + T{ ##replace f V int-regs 4 D 5 } + T{ ##replace f V int-regs 5 D 0 } + } + } + } dup 1array { { int-regs V{ 0 1 2 3 } } } (linear-scan) + instructions>> first + live-values>> assoc-empty? + ] with-scope +] unit-test + +V{ + T{ ##peek f V int-regs 0 D 0 } + T{ ##peek f V int-regs 1 D 1 } + T{ ##replace f V int-regs 1 D 1 } + T{ ##branch } +} 0 test-bb + +V{ + T{ ##gc f V int-regs 2 V int-regs 3 } + T{ ##branch } +} 1 test-bb + +V{ + T{ ##replace f V int-regs 0 D 0 } + T{ ##return } +} 2 test-bb + +0 get 1 get 1vector >>successors drop +1 get 2 get 1vector >>successors drop + +[ ] [ { 1 2 3 } test-linear-scan-on-cfg ] unit-test + +[ H{ { V int-regs 0 3 } } ] [ 1 get instructions>> first live-values>> ] unit-test + + + +V{ + T{ ##peek f V int-regs 0 D 0 } + T{ ##peek f V int-regs 1 D 1 } + T{ ##compare-imm-branch f V int-regs 1 5 cc= } +} 0 test-bb + +V{ + T{ ##gc f V int-regs 2 V int-regs 3 } + T{ ##replace f V int-regs 0 D 0 } + T{ ##return } +} 1 test-bb + +V{ + T{ ##return } +} 2 test-bb + +0 get 1 get 2 get V{ } 2sequence >>successors drop + +[ ] [ { 1 2 3 } test-linear-scan-on-cfg ] unit-test + +[ H{ { V int-regs 0 3 } } ] [ 1 get instructions>> first live-values>> ] unit-test From e0fa51512f6e1ac8342155f788a02a9ee4947a6c Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 10 Jul 2009 07:07:54 -0500 Subject: [PATCH 13/96] llvm: new add-llvm-library word to make things a bit more portable --- extra/llvm/core/core.factor | 19 +++++++++++------- extra/llvm/engine/engine.factor | 35 +++++++++++---------------------- 2 files changed, 24 insertions(+), 30 deletions(-) diff --git a/extra/llvm/core/core.factor b/extra/llvm/core/core.factor index 00a395d3b2..cb62821390 100644 --- a/extra/llvm/core/core.factor +++ b/extra/llvm/core/core.factor @@ -1,18 +1,23 @@ ! Copyright (C) 2009 Matthew Willis. ! See http://factorcode.org/license.txt for BSD license. -USING: alien.libraries alien.syntax ; +USING: alien.libraries alien.syntax system sequences combinators ; IN: llvm.core << -"LLVMSystem" "/usr/local/lib/libLLVMSystem.dylib" "cdecl" add-library +: add-llvm-library ( name -- ) + dup + { + { [ os macosx? ] [ "/usr/local/lib/lib" ".dylib" surround ] } + { [ os windows? ] [ ".dll" append ] } + { [ os unix? ] [ ".so" append ] } + } cond add-library ; -"LLVMSupport" "/usr/local/lib/libLLVMSupport.dylib" "cdecl" add-library - -"LLVMCore" "/usr/local/lib/libLLVMCore.dylib" "cdecl" add-library - -"LLVMBitReader" "/usr/local/lib/libLLVMBitReader.dylib" "cdecl" add-library +"LLVMSystem" add-llvm-library +"LLVMSupport" add-llvm-library +"LLVMCore" add-llvm-library +"LLVMBitReader" add-llvm-library >> diff --git a/extra/llvm/engine/engine.factor b/extra/llvm/engine/engine.factor index 1fa7ef01d6..d259c740e6 100644 --- a/extra/llvm/engine/engine.factor +++ b/extra/llvm/engine/engine.factor @@ -5,29 +5,18 @@ IN: llvm.engine << -"LLVMExecutionEngine" "/usr/local/lib/libLLVMExecutionEngine.dylib" "cdecl" add-library - -"LLVMTarget" "/usr/local/lib/libLLVMTarget.dylib" "cdecl" add-library - -"LLVMAnalysis" "/usr/local/lib/libLLVMAnalysis.dylib" "cdecl" add-library - -"LLVMipa" "/usr/local/lib/libLLVMipa.dylib" "cdecl" add-library - -"LLVMTransformUtils" "/usr/local/lib/libLLVMTransformUtils.dylib" "cdecl" add-library - -"LLVMScalarOpts" "/usr/local/lib/libLLVMScalarOpts.dylib" "cdecl" add-library - -"LLVMCodeGen" "/usr/local/lib/libLLVMCodeGen.dylib" "cdecl" add-library - -"LLVMAsmPrinter" "/usr/local/lib/libLLVMAsmPrinter.dylib" "cdecl" add-library - -"LLVMSelectionDAG" "/usr/local/lib/libLLVMSelectionDAG.dylib" "cdecl" add-library - -"LLVMX86CodeGen" "/usr/local/lib/libLLVMX86CodeGen.dylib" "cdecl" add-library - -"LLVMJIT" "/usr/local/lib/libLLVMJIT.dylib" "cdecl" add-library - -"LLVMInterpreter.dylib" "/usr/local/lib/libLLVMInterpreter.dylib" "cdecl" add-library +"LLVMExecutionEngine" add-llvm-library +"LLVMTarget" add-llvm-library +"LLVMAnalysis" add-llvm-library +"LLVMipa" add-llvm-library +"LLVMTransformUtils" add-llvm-library +"LLVMScalarOpts" add-llvm-library +"LLVMCodeGen" add-llvm-library +"LLVMAsmPrinter" add-llvm-library +"LLVMSelectionDAG" add-llvm-library +"LLVMX86CodeGen" add-llvm-library +"LLVMJIT" add-llvm-library +"LLVMInterpreter" add-llvm-library >> From b7aac8c13a68418e7ef2d544126ddfb28f4a0150 Mon Sep 17 00:00:00 2001 From: sheeple Date: Fri, 10 Jul 2009 07:38:19 -0500 Subject: [PATCH 14/96] llvm.core: fix add-llvm-library --- extra/llvm/core/core.factor | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extra/llvm/core/core.factor b/extra/llvm/core/core.factor index cb62821390..0d1b22e288 100644 --- a/extra/llvm/core/core.factor +++ b/extra/llvm/core/core.factor @@ -1,6 +1,6 @@ ! Copyright (C) 2009 Matthew Willis. ! See http://factorcode.org/license.txt for BSD license. -USING: alien.libraries alien.syntax system sequences combinators ; +USING: alien.libraries alien.syntax system sequences combinators kernel ; IN: llvm.core @@ -11,8 +11,8 @@ IN: llvm.core { { [ os macosx? ] [ "/usr/local/lib/lib" ".dylib" surround ] } { [ os windows? ] [ ".dll" append ] } - { [ os unix? ] [ ".so" append ] } - } cond add-library ; + { [ os unix? ] [ "lib" ".so" surround ] } + } cond "cdecl" add-library ; "LLVMSystem" add-llvm-library "LLVMSupport" add-llvm-library From c25ac2a066fa682a63c63378e6bcc5781610202a Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 10 Jul 2009 07:46:47 -0500 Subject: [PATCH 15/96] llvm: add unportable tag --- extra/llvm/core/tags.txt | 1 + extra/llvm/engine/tags.txt | 1 + extra/llvm/invoker/tags.txt | 1 + extra/llvm/jit/tags.txt | 1 + extra/llvm/reader/tags.txt | 1 + extra/llvm/tags.txt | 1 + extra/llvm/types/tags.txt | 1 + extra/llvm/wrappers/tags.txt | 1 + 8 files changed, 8 insertions(+) create mode 100644 extra/llvm/core/tags.txt create mode 100644 extra/llvm/engine/tags.txt create mode 100644 extra/llvm/invoker/tags.txt create mode 100644 extra/llvm/jit/tags.txt create mode 100644 extra/llvm/reader/tags.txt create mode 100644 extra/llvm/types/tags.txt create mode 100644 extra/llvm/wrappers/tags.txt diff --git a/extra/llvm/core/tags.txt b/extra/llvm/core/tags.txt new file mode 100644 index 0000000000..6bf68304bb --- /dev/null +++ b/extra/llvm/core/tags.txt @@ -0,0 +1 @@ +unportable diff --git a/extra/llvm/engine/tags.txt b/extra/llvm/engine/tags.txt new file mode 100644 index 0000000000..6bf68304bb --- /dev/null +++ b/extra/llvm/engine/tags.txt @@ -0,0 +1 @@ +unportable diff --git a/extra/llvm/invoker/tags.txt b/extra/llvm/invoker/tags.txt new file mode 100644 index 0000000000..6bf68304bb --- /dev/null +++ b/extra/llvm/invoker/tags.txt @@ -0,0 +1 @@ +unportable diff --git a/extra/llvm/jit/tags.txt b/extra/llvm/jit/tags.txt new file mode 100644 index 0000000000..6bf68304bb --- /dev/null +++ b/extra/llvm/jit/tags.txt @@ -0,0 +1 @@ +unportable diff --git a/extra/llvm/reader/tags.txt b/extra/llvm/reader/tags.txt new file mode 100644 index 0000000000..6bf68304bb --- /dev/null +++ b/extra/llvm/reader/tags.txt @@ -0,0 +1 @@ +unportable diff --git a/extra/llvm/tags.txt b/extra/llvm/tags.txt index bb863cf9a0..bf2a35f15b 100644 --- a/extra/llvm/tags.txt +++ b/extra/llvm/tags.txt @@ -1 +1,2 @@ bindings +unportable diff --git a/extra/llvm/types/tags.txt b/extra/llvm/types/tags.txt new file mode 100644 index 0000000000..6bf68304bb --- /dev/null +++ b/extra/llvm/types/tags.txt @@ -0,0 +1 @@ +unportable diff --git a/extra/llvm/wrappers/tags.txt b/extra/llvm/wrappers/tags.txt new file mode 100644 index 0000000000..6bf68304bb --- /dev/null +++ b/extra/llvm/wrappers/tags.txt @@ -0,0 +1 @@ +unportable From 1cf6bb7f99b0369a413670d8306eea0b2d4935ff Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 10 Jul 2009 07:48:49 -0500 Subject: [PATCH 16/96] compiler.cfg.linear-scan: disable unit test for unimplemented feature --- basis/compiler/cfg/linear-scan/linear-scan-tests.factor | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/basis/compiler/cfg/linear-scan/linear-scan-tests.factor b/basis/compiler/cfg/linear-scan/linear-scan-tests.factor index bc3061128c..e8b4b67cf0 100644 --- a/basis/compiler/cfg/linear-scan/linear-scan-tests.factor +++ b/basis/compiler/cfg/linear-scan/linear-scan-tests.factor @@ -1770,7 +1770,8 @@ test-diamond 2 get instructions>> first regs>> V int-regs 1 swap at assert= ] unit-test -[ _copy ] [ 3 get instructions>> second class ] unit-test +! Not until splitting is finished +! [ _copy ] [ 3 get instructions>> second class ] unit-test ! Resolve pass; make sure the spilling is done correctly V{ T{ ##peek f V int-regs 3 R 1 } T{ ##branch } } 0 test-bb From 949b527ed58167bf6d667108ecb00cd678603f44 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 10 Jul 2009 07:52:20 -0500 Subject: [PATCH 17/96] Help lint fixes for urls.encoding and mongodb.driver --- basis/urls/encoding/encoding-docs.factor | 2 +- extra/mongodb/driver/driver-docs.factor | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/basis/urls/encoding/encoding-docs.factor b/basis/urls/encoding/encoding-docs.factor index 82ab3d1f69..a021bd6d23 100644 --- a/basis/urls/encoding/encoding-docs.factor +++ b/basis/urls/encoding/encoding-docs.factor @@ -26,7 +26,7 @@ HELP: assoc>query "USING: io urls.encoding ;" "{ { \"from\" \"Lead\" } { \"to\" \"Gold, please\" } }" "assoc>query print" - "from=Lead&to=Gold%2c%20please" + "from=Lead&to=Gold%2C%20please" } } ; diff --git a/extra/mongodb/driver/driver-docs.factor b/extra/mongodb/driver/driver-docs.factor index e8f726374c..532dfe1dce 100644 --- a/extra/mongodb/driver/driver-docs.factor +++ b/extra/mongodb/driver/driver-docs.factor @@ -76,7 +76,7 @@ HELP: count HELP: create-collection { $values - { "name" "collection name" } + { "name/collection" "collection name" } } { $description "Creates a new collection with the given name." } ; From fe4aaad4171af47b18180d4f4e57896b7a4869a7 Mon Sep 17 00:00:00 2001 From: Jeremy Hughes Date: Sat, 11 Jul 2009 20:53:50 +1200 Subject: [PATCH 18/96] alien.inline.compiler: added -mno-cygwin to linker on windows --- basis/alien/inline/compiler/compiler.factor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basis/alien/inline/compiler/compiler.factor b/basis/alien/inline/compiler/compiler.factor index bc098ee26b..7ec70a356e 100644 --- a/basis/alien/inline/compiler/compiler.factor +++ b/basis/alien/inline/compiler/compiler.factor @@ -60,7 +60,7 @@ M: word link-descr { "-shared" "-o" } ; M: macosx link-descr { "-g" "-prebind" "-dynamiclib" "-o" } cpu x86.64? [ { "-arch" "x86_64" } prepend ] when ; -M: windows link-descr { "-lstdc++" "-o" } ; +M: windows link-descr { "-lstdc++" "-mno-cygwin" "-o" } ; Date: Sat, 11 Jul 2009 11:14:17 +0200 Subject: [PATCH 19/96] added unit-tests to bson vocab --- extra/bson/bson-tests.factor | 48 ++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 extra/bson/bson-tests.factor diff --git a/extra/bson/bson-tests.factor b/extra/bson/bson-tests.factor new file mode 100644 index 0000000000..e66b9c6ec2 --- /dev/null +++ b/extra/bson/bson-tests.factor @@ -0,0 +1,48 @@ +USING: bson.reader bson.writer byte-arrays io.encodings.binary +io.streams.byte-array tools.test literals calendar kernel math ; + +IN: bson.tests + +: turnaround ( value -- value ) + assoc>bv >byte-array binary [ H{ } stream>assoc ] with-byte-reader ; + +M: timestamp equal? ( obj1 obj2 -- ? ) + [ timestamp>millis ] bi@ = ; + +[ H{ { "a" "a string" } } ] [ H{ { "a" "a string" } } turnaround ] unit-test + +[ H{ { "a" "a string" } { "b" H{ { "a" "a string" } } } } ] +[ H{ { "a" "a string" } { "b" H{ { "a" "a string" } } } } turnaround ] unit-test + +[ H{ { "a list" { 1 2.234 "hello world" } } } ] +[ H{ { "a list" { 1 2.234 "hello world" } } } turnaround ] unit-test + +[ H{ { "a quotation" [ 1 2 + ] } } ] +[ H{ { "a quotation" [ 1 2 + ] } } turnaround ] unit-test + +[ H{ { "a date" T{ timestamp { year 2009 } + { month 7 } + { day 11 } + { hour 11 } + { minute 8 } + { second 40+15437/200000 } + { gmt-offset T{ duration { hour 2 } } } } } } +] +[ H{ { "a date" T{ timestamp { year 2009 } + { month 7 } + { day 11 } + { hour 11 } + { minute 8 } + { second 40+15437/200000 } + { gmt-offset T{ duration { hour 2 } } } } } } turnaround +] unit-test + +[ H{ { "nested" H{ { "a" "a string" } { "b" H{ { "a" "a string" } } } } } + { "array" H{ { "a list" { 1 2.234 "hello world" } } } } + { "quot" [ 1 2 + ] } } +] +[ H{ { "nested" H{ { "a" "a string" } { "b" H{ { "a" "a string" } } } } } + { "array" H{ { "a list" { 1 2.234 "hello world" } } } } + { "quot" [ 1 2 + ] } } turnaround ] unit-test + + From 608fb054f26bc006037d8cb4dd2762136b8ab26b Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Sun, 12 Jul 2009 22:22:46 -0500 Subject: [PATCH 20/96] compiler.cfg: Some code cleanups, update stack-analysis and phi-insertion to work on CFGs with critical edges --- .../branch-folding-tests.factor | 5 +- .../cfg/branch-folding/branch-folding.factor | 4 +- basis/compiler/cfg/cfg.factor | 36 +--------- .../cfg/optimizer/optimizer-tests.factor | 11 +++- .../phi-elimination-tests.factor | 10 ++- .../phi-elimination/phi-elimination.factor | 13 ++-- .../stack-analysis/merge/merge-tests.factor | 47 ++++++++----- .../cfg/stack-analysis/merge/merge.factor | 66 +++++++++++-------- .../stack-analysis-tests.factor | 12 ++-- .../cfg/stack-analysis/stack-analysis.factor | 22 ++++++- basis/compiler/cfg/tco/tco.factor | 5 +- .../useless-conditionals.factor | 5 +- basis/compiler/cfg/utilities/utilities.factor | 58 ++++++++++++++-- 13 files changed, 185 insertions(+), 109 deletions(-) diff --git a/basis/compiler/cfg/branch-folding/branch-folding-tests.factor b/basis/compiler/cfg/branch-folding/branch-folding-tests.factor index 964620d2d3..8ae1f6b75b 100644 --- a/basis/compiler/cfg/branch-folding/branch-folding-tests.factor +++ b/basis/compiler/cfg/branch-folding/branch-folding-tests.factor @@ -40,7 +40,10 @@ test-diamond [ 1 ] [ 1 get successors>> length ] unit-test [ t ] [ 1 get successors>> first 3 get eq? ] unit-test -[ T{ ##copy f V int-regs 3 V int-regs 2 } ] [ 3 get instructions>> second ] unit-test +[ T{ ##copy f V int-regs 3 V int-regs 2 } ] +[ 3 get successors>> first instructions>> first ] +unit-test + [ 2 ] [ 4 get instructions>> length ] unit-test V{ diff --git a/basis/compiler/cfg/branch-folding/branch-folding.factor b/basis/compiler/cfg/branch-folding/branch-folding.factor index 627db63c9f..2432849a9a 100644 --- a/basis/compiler/cfg/branch-folding/branch-folding.factor +++ b/basis/compiler/cfg/branch-folding/branch-folding.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: accessors combinators.short-circuit kernel sequences vectors -compiler.cfg.instructions compiler.cfg.rpo ; +compiler.cfg.instructions compiler.cfg.rpo compiler.cfg ; IN: compiler.cfg.branch-folding ! Fold comparisons where both inputs are the same. Predecessors must be @@ -27,4 +27,4 @@ IN: compiler.cfg.branch-folding dup fold-branch? [ fold-branch ] [ drop ] if ] each-basic-block - f >>post-order ; \ No newline at end of file + cfg-changed ; \ No newline at end of file diff --git a/basis/compiler/cfg/cfg.factor b/basis/compiler/cfg/cfg.factor index 12a1180d40..f856efac78 100644 --- a/basis/compiler/cfg/cfg.factor +++ b/basis/compiler/cfg/cfg.factor @@ -1,9 +1,6 @@ ! Copyright (C) 2008, 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: kernel arrays vectors accessors assocs sets -namespaces math make fry sequences -combinators.short-circuit -compiler.cfg.instructions ; +USING: kernel math vectors arrays accessors namespaces ; IN: compiler.cfg TUPLE: basic-block < identity-tuple @@ -22,39 +19,12 @@ M: basic-block hashcode* nip id>> ; V{ } clone >>predecessors \ basic-block counter >>id ; -: empty-block? ( bb -- ? ) - instructions>> { - [ length 1 = ] - [ first ##branch? ] - } 1&& ; - -SYMBOL: visited - -: (skip-empty-blocks) ( bb -- bb' ) - dup visited get key? [ - dup empty-block? [ - dup visited get conjoin - successors>> first (skip-empty-blocks) - ] when - ] unless ; - -: skip-empty-blocks ( bb -- bb' ) - H{ } clone visited [ (skip-empty-blocks) ] with-variable ; - -: add-instructions ( bb quot -- ) - [ instructions>> building ] dip '[ - building get pop - _ dip - building get push - ] with-variable ; inline - -: back-edge? ( from to -- ? ) - [ number>> ] bi@ > ; - TUPLE: cfg { entry basic-block } word label spill-counts post-order ; : ( entry word label -- cfg ) f f cfg boa ; +: cfg-changed ( cfg -- cfg ) f >>post-order ; inline + TUPLE: mr { instructions array } word label ; : ( instructions word label -- mr ) diff --git a/basis/compiler/cfg/optimizer/optimizer-tests.factor b/basis/compiler/cfg/optimizer/optimizer-tests.factor index 93adc4c0f9..f585d80d72 100755 --- a/basis/compiler/cfg/optimizer/optimizer-tests.factor +++ b/basis/compiler/cfg/optimizer/optimizer-tests.factor @@ -1,7 +1,7 @@ USING: accessors arrays compiler.cfg.checker compiler.cfg.debugger compiler.cfg.def-use compiler.cfg.instructions fry kernel kernel.private math -math.private sbufs sequences sequences.private sets +math.partial-dispatch math.private sbufs sequences sequences.private sets slots.private strings tools.test vectors layouts ; IN: compiler.cfg.optimizer.tests @@ -31,6 +31,15 @@ IN: compiler.cfg.optimizer.tests [ [ 2 fixnum+ ] when 3 ] [ [ 2 fixnum- ] when 3 ] [ 10000 [ ] times ] + [ + over integer? [ + over dup 16 <-integer-fixnum + [ 0 >=-integer-fixnum ] [ drop f ] if [ + nip dup + [ ] [ ] if + ] [ 2drop f ] if + ] [ 2drop f ] if + ] } [ [ [ ] ] dip '[ _ test-mr first check-mr ] unit-test ] each diff --git a/basis/compiler/cfg/phi-elimination/phi-elimination-tests.factor b/basis/compiler/cfg/phi-elimination/phi-elimination-tests.factor index 4577e70997..2dd75df693 100644 --- a/basis/compiler/cfg/phi-elimination/phi-elimination-tests.factor +++ b/basis/compiler/cfg/phi-elimination/phi-elimination-tests.factor @@ -35,6 +35,12 @@ test-diamond [ ] [ cfg new 0 get >>entry eliminate-phis drop ] unit-test -[ T{ ##copy f V int-regs 3 V int-regs 1 } ] [ 2 get instructions>> second ] unit-test -[ T{ ##copy f V int-regs 3 V int-regs 2 } ] [ 3 get instructions>> second ] unit-test +[ T{ ##copy f V int-regs 3 V int-regs 1 } ] +[ 2 get successors>> first instructions>> first ] +unit-test + +[ T{ ##copy f V int-regs 3 V int-regs 2 } ] +[ 3 get successors>> first instructions>> first ] +unit-test + [ 2 ] [ 4 get instructions>> length ] unit-test \ No newline at end of file diff --git a/basis/compiler/cfg/phi-elimination/phi-elimination.factor b/basis/compiler/cfg/phi-elimination/phi-elimination.factor index 9c2f0adafd..7e184a9b53 100644 --- a/basis/compiler/cfg/phi-elimination/phi-elimination.factor +++ b/basis/compiler/cfg/phi-elimination/phi-elimination.factor @@ -1,7 +1,8 @@ ! Copyright (C) 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: accessors assocs fry kernel sequences -compiler.cfg compiler.cfg.instructions compiler.cfg.rpo ; +USING: accessors assocs fry kernel sequences namespaces +compiler.cfg compiler.cfg.instructions compiler.cfg.rpo +compiler.cfg.utilities ; IN: compiler.cfg.phi-elimination : insert-copy ( predecessor input output -- ) @@ -11,7 +12,11 @@ IN: compiler.cfg.phi-elimination [ inputs>> ] [ dst>> ] bi '[ _ insert-copy ] assoc-each ; : eliminate-phi-step ( bb -- ) - instructions>> [ dup ##phi? [ eliminate-phi f ] [ drop t ] if ] filter-here ; + H{ } clone added-instructions set + [ instructions>> [ dup ##phi? [ eliminate-phi f ] [ drop t ] if ] filter-here ] + [ insert-basic-blocks ] + bi ; : eliminate-phis ( cfg -- cfg' ) - dup [ eliminate-phi-step ] each-basic-block ; \ No newline at end of file + dup [ eliminate-phi-step ] each-basic-block + cfg-changed ; \ No newline at end of file diff --git a/basis/compiler/cfg/stack-analysis/merge/merge-tests.factor b/basis/compiler/cfg/stack-analysis/merge/merge-tests.factor index 14a81958a9..e67f6b5143 100644 --- a/basis/compiler/cfg/stack-analysis/merge/merge-tests.factor +++ b/basis/compiler/cfg/stack-analysis/merge/merge-tests.factor @@ -2,7 +2,7 @@ IN: compiler.cfg.stack-analysis.merge.tests USING: compiler.cfg.stack-analysis.merge tools.test arrays accessors compiler.cfg.instructions compiler.cfg.stack-analysis.state compiler.cfg compiler.cfg.registers compiler.cfg.debugger -cpu.architecture make assocs +cpu.architecture make assocs namespaces sequences kernel classes ; [ @@ -11,13 +11,15 @@ sequences kernel classes ; ] [ - V{ T{ ##branch } } >>instructions - V{ T{ ##branch } } >>instructions 2array + V{ T{ ##branch } } >>instructions dup 1 set + V{ T{ ##branch } } >>instructions dup 2 set 2array H{ { D 0 V int-regs 0 } } >>locs>vregs H{ { D 0 V int-regs 1 } } >>locs>vregs 2array - [ merge-locs locs>vregs>> keys ] { } make first inputs>> values + H{ } clone added-instructions set + V{ } clone added-phis set + merge-locs locs>vregs>> keys added-phis get values first ] unit-test [ @@ -26,15 +28,16 @@ sequences kernel classes ; ] [ - V{ T{ ##branch } } >>instructions - V{ T{ ##branch } } >>instructions 2array + V{ T{ ##branch } } >>instructions dup 1 set + V{ T{ ##branch } } >>instructions dup 2 set 2array - [ - - H{ { D 0 V int-regs 1 } } >>locs>vregs 2array + + H{ { D 0 V int-regs 1 } } >>locs>vregs 2array - [ merge-locs locs>vregs>> keys ] { } make drop - ] keep first instructions>> first class + H{ } clone added-instructions set + V{ } clone added-phis set + [ merge-locs locs>vregs>> keys ] { } make drop + 1 get added-instructions get at first class ] unit-test [ @@ -42,15 +45,17 @@ sequences kernel classes ; ] [ - V{ T{ ##branch } } >>instructions - V{ T{ ##branch } } >>instructions 2array + V{ T{ ##branch } } >>instructions dup 1 set + V{ T{ ##branch } } >>instructions dup 2 set 2array - [ - -1 >>ds-height - 2array + H{ } clone added-instructions set + V{ } clone added-phis set - [ merge-ds-heights ds-height>> ] { } make drop - ] keep first instructions>> first class + -1 >>ds-height + 2array + + [ merge-ds-heights ds-height>> ] { } make drop + 1 get added-instructions get at first class ] unit-test [ @@ -63,6 +68,9 @@ sequences kernel classes ; V{ T{ ##branch } } >>instructions V{ T{ ##branch } } >>instructions 2array + H{ } clone added-instructions set + V{ } clone added-phis set + [ -1 >>ds-height H{ { D 1 V int-regs 0 } } >>locs>vregs H{ { D 0 V int-regs 1 } } >>locs>vregs 2array @@ -82,6 +90,9 @@ sequences kernel classes ; V{ T{ ##branch } } >>instructions V{ T{ ##branch } } >>instructions 2array + H{ } clone added-instructions set + V{ } clone added-phis set + [ -1 >>ds-height H{ { D -1 V int-regs 0 } } >>locs>vregs -1 >>ds-height H{ { D -1 V int-regs 1 } } >>locs>vregs 2array diff --git a/basis/compiler/cfg/stack-analysis/merge/merge.factor b/basis/compiler/cfg/stack-analysis/merge/merge.factor index b6c443a2d3..cb0ad7d615 100644 --- a/basis/compiler/cfg/stack-analysis/merge/merge.factor +++ b/basis/compiler/cfg/stack-analysis/merge/merge.factor @@ -1,12 +1,11 @@ ! Copyright (C) 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: kernel assocs sequences accessors fry combinators grouping -sets locals compiler.cfg compiler.cfg.hats compiler.cfg.instructions -compiler.cfg.stack-analysis.state ; +USING: kernel assocs sequences accessors fry combinators grouping sets +arrays vectors locals namespaces make compiler.cfg compiler.cfg.hats +compiler.cfg.instructions compiler.cfg.stack-analysis.state +compiler.cfg.registers compiler.cfg.utilities cpu.architecture ; IN: compiler.cfg.stack-analysis.merge -! XXX critical edges - : initial-state ( bb states -- state ) 2drop ; : single-predecessor ( bb states -- state ) nip first clone ; @@ -27,14 +26,14 @@ IN: compiler.cfg.stack-analysis.merge [ nip first >>rs-height ] [ [ '[ _ save-rs-height ] add-instructions ] 2each ] if ; -: assoc-map-values ( assoc quot -- assoc' ) +: assoc-map-keys ( assoc quot -- assoc' ) '[ _ dip ] assoc-map ; inline : translate-locs ( assoc state -- assoc' ) - '[ _ translate-loc ] assoc-map-values ; + '[ _ translate-loc ] assoc-map-keys ; : untranslate-locs ( assoc state -- assoc' ) - '[ _ untranslate-loc ] assoc-map-values ; + '[ _ untranslate-loc ] assoc-map-keys ; : collect-locs ( loc-maps states -- assoc ) ! assoc maps locs to sequences @@ -45,12 +44,16 @@ IN: compiler.cfg.stack-analysis.merge : insert-peek ( predecessor loc state -- vreg ) '[ _ _ translate-loc ^^peek ] add-instructions ; +SYMBOL: added-phis + +: add-phi-later ( inputs -- vreg ) + [ int-regs next-vreg dup ] dip 2array added-phis get push ; + : merge-loc ( predecessors vregs loc state -- vreg ) ! Insert a ##phi in the current block where the input ! is the vreg storing loc from each predecessor block - [ dup ] 3dip '[ [ ] [ _ _ insert-peek ] ?if ] 2map - dup all-equal? [ nip first ] [ zip ^^phi ] if ; + dup all-equal? [ first ] [ add-phi-later ] if ; :: merge-locs ( state predecessors states -- state ) states [ locs>vregs>> ] map states collect-locs @@ -77,30 +80,35 @@ IN: compiler.cfg.stack-analysis.merge over translate-locs >>changed-locs ; -ERROR: cannot-merge-poisoned states ; +:: insert-phis ( bb -- ) + bb predecessors>> :> predecessors + [ + added-phis get [| dst inputs | + dst predecessors inputs zip ##phi + ] assoc-each + ] V{ } make bb instructions>> over push-all + bb (>>instructions) ; -: multiple-predecessors ( bb states -- state ) - dup [ not ] any? [ - 2drop +:: multiple-predecessors ( bb states -- state ) + states [ not ] any? [ + ] [ - dup [ poisoned?>> ] any? [ - cannot-merge-poisoned - ] [ - [ state new ] 2dip - [ predecessors>> ] dip - { - [ merge-ds-heights ] - [ merge-rs-heights ] - [ merge-locs ] - [ nip merge-actual-locs ] - [ nip merge-changed-locs ] - } 2cleave - ] if + [ + H{ } clone added-instructions set + V{ } clone added-phis set + bb predecessors>> :> predecessors + state new + predecessors states merge-ds-heights + predecessors states merge-rs-heights + predecessors states merge-locs + states merge-actual-locs + states merge-changed-locs + bb insert-basic-blocks + bb insert-phis + ] with-scope ] if ; : merge-states ( bb states -- state ) - ! If any states are poisoned, save all registers - ! to the stack in each branch dup length { { 0 [ initial-state ] } { 1 [ single-predecessor ] } diff --git a/basis/compiler/cfg/stack-analysis/stack-analysis-tests.factor b/basis/compiler/cfg/stack-analysis/stack-analysis-tests.factor index cbc939b1f2..23b1098cd6 100644 --- a/basis/compiler/cfg/stack-analysis/stack-analysis-tests.factor +++ b/basis/compiler/cfg/stack-analysis/stack-analysis-tests.factor @@ -99,7 +99,7 @@ IN: compiler.cfg.stack-analysis.tests ! Correct height tracking [ t ] [ [ pick [ ] [ drop ] if swap ] test-stack-analysis eliminate-dead-code - reverse-post-order 3 swap nth + reverse-post-order 4 swap nth instructions>> [ ##peek? ] filter first2 [ loc>> ] [ loc>> ] bi* 2array { D 1 D 0 } set= ] unit-test @@ -126,7 +126,7 @@ IN: compiler.cfg.stack-analysis.tests stack-analysis drop - 3 get instructions>> second loc>> + 3 get successors>> first instructions>> first loc>> ] unit-test ! Do inserted ##peeks reference the correct stack location if @@ -156,7 +156,7 @@ IN: compiler.cfg.stack-analysis.tests stack-analysis drop - 3 get instructions>> [ ##peek? ] find nip loc>> + 3 get successors>> first instructions>> [ ##peek? ] find nip loc>> ] unit-test ! Missing ##replace @@ -170,9 +170,9 @@ IN: compiler.cfg.stack-analysis.tests ! Inserted ##peeks reference the wrong stack location [ t ] [ [ [ "B" ] 2dip dup [ [ /mod ] dip ] when ] test-stack-analysis - eliminate-dead-code reverse-post-order 3 swap nth + eliminate-dead-code reverse-post-order 4 swap nth instructions>> [ ##peek? ] filter [ loc>> ] map - { R 0 D 0 D 1 } set= + { D 0 D 1 } set= ] unit-test [ D 0 ] [ @@ -200,5 +200,5 @@ IN: compiler.cfg.stack-analysis.tests stack-analysis drop - 3 get instructions>> [ ##peek? ] find nip loc>> + 3 get successors>> first instructions>> [ ##peek? ] find nip loc>> ] unit-test \ No newline at end of file diff --git a/basis/compiler/cfg/stack-analysis/stack-analysis.factor b/basis/compiler/cfg/stack-analysis/stack-analysis.factor index ab16bbea44..48a4b79783 100644 --- a/basis/compiler/cfg/stack-analysis/stack-analysis.factor +++ b/basis/compiler/cfg/stack-analysis/stack-analysis.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: accessors assocs kernel namespaces math sequences fry grouping -sets make combinators +sets make combinators dlists deques compiler.cfg compiler.cfg.copy-prop compiler.cfg.def-use @@ -10,9 +10,14 @@ compiler.cfg.registers compiler.cfg.rpo compiler.cfg.hats compiler.cfg.stack-analysis.state -compiler.cfg.stack-analysis.merge ; +compiler.cfg.stack-analysis.merge +compiler.cfg.utilities ; IN: compiler.cfg.stack-analysis +SYMBOL: work-list + +: add-to-work-list ( bb -- ) work-list get push-front ; + : redundant-replace? ( vreg loc -- ? ) dup state get untranslate-loc n>> 0 < [ 2drop t ] [ state get actual-locs>vregs>> at = ] if ; @@ -137,10 +142,21 @@ SYMBOLS: state-in state-out ; ] 2bi ] V{ } make >>instructions drop ; +: visit-successors ( bb -- ) + dup successors>> [ + 2dup back-edge? [ 2drop ] [ nip add-to-work-list ] if + ] with each ; + +: process-work-list ( -- ) + work-list get [ visit-block ] slurp-deque ; + : stack-analysis ( cfg -- cfg' ) [ + work-list set H{ } clone copies set H{ } clone state-in set H{ } clone state-out set - dup [ visit-block ] each-basic-block + dup [ add-to-work-list ] each-basic-block + process-work-list + cfg-changed ] with-scope ; diff --git a/basis/compiler/cfg/tco/tco.factor b/basis/compiler/cfg/tco/tco.factor index df5d962999..5fa2e1b042 100644 --- a/basis/compiler/cfg/tco/tco.factor +++ b/basis/compiler/cfg/tco/tco.factor @@ -5,7 +5,8 @@ namespaces sequences fry combinators compiler.cfg compiler.cfg.rpo compiler.cfg.hats -compiler.cfg.instructions ; +compiler.cfg.instructions +compiler.cfg.utilities ; IN: compiler.cfg.tco ! Tail call optimization. You must run compute-predecessors after this @@ -82,4 +83,4 @@ M: ##fixnum-mul convert-fixnum-tail-call* drop i i \ ##fixnum-mul-tail new-insn : optimize-tail-calls ( cfg -- cfg' ) dup cfg set dup [ optimize-tail-call ] each-basic-block - f >>post-order ; \ No newline at end of file + cfg-changed ; \ No newline at end of file diff --git a/basis/compiler/cfg/useless-conditionals/useless-conditionals.factor b/basis/compiler/cfg/useless-conditionals/useless-conditionals.factor index 6f4a6eea55..cc98d08042 100644 --- a/basis/compiler/cfg/useless-conditionals/useless-conditionals.factor +++ b/basis/compiler/cfg/useless-conditionals/useless-conditionals.factor @@ -1,7 +1,8 @@ ! Copyright (C) 2008, 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: kernel accessors sequences math combinators combinators.short-circuit -classes vectors compiler.cfg compiler.cfg.instructions compiler.cfg.rpo ; +classes vectors compiler.cfg compiler.cfg.instructions compiler.cfg.rpo +compiler.cfg.utilities ; IN: compiler.cfg.useless-conditionals : delete-conditional? ( bb -- ? ) @@ -18,4 +19,4 @@ IN: compiler.cfg.useless-conditionals dup [ dup delete-conditional? [ delete-conditional ] [ drop ] if ] each-basic-block - f >>post-order ; + cfg-changed ; diff --git a/basis/compiler/cfg/utilities/utilities.factor b/basis/compiler/cfg/utilities/utilities.factor index 99a138a763..0e08607331 100644 --- a/basis/compiler/cfg/utilities/utilities.factor +++ b/basis/compiler/cfg/utilities/utilities.factor @@ -1,8 +1,8 @@ -! Copyright (C) 2008 Slava Pestov. +! Copyright (C) 2008, 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: accessors kernel math layouts make sequences combinators -cpu.architecture namespaces compiler.cfg -compiler.cfg.instructions ; +USING: accessors assocs combinators combinators.short-circuit +compiler.cfg compiler.cfg.instructions cpu.architecture kernel +layouts locals make math namespaces sequences sets vectors ; IN: compiler.cfg.utilities : value-info-small-fixnum? ( value-info -- ? ) @@ -33,7 +33,53 @@ IN: compiler.cfg.utilities building off basic-block off ; -: stop-iterating ( -- next ) end-basic-block f ; - : emit-primitive ( node -- ) word>> ##call ##branch begin-basic-block ; + +: back-edge? ( from to -- ? ) + [ number>> ] bi@ >= ; + +: empty-block? ( bb -- ? ) + instructions>> { + [ length 1 = ] + [ first ##branch? ] + } 1&& ; + +SYMBOL: visited + +: (skip-empty-blocks) ( bb -- bb' ) + dup visited get key? [ + dup empty-block? [ + dup visited get conjoin + successors>> first (skip-empty-blocks) + ] when + ] unless ; + +: skip-empty-blocks ( bb -- bb' ) + H{ } clone visited [ (skip-empty-blocks) ] with-variable ; + +! assoc mapping predecessors to sequences +SYMBOL: added-instructions + +: add-instructions ( predecessor quot -- ) + [ + added-instructions get + [ drop V{ } clone ] cache + building + ] dip with-variable ; inline + +:: insert-basic-block ( from to bb -- ) + bb from 1vector >>predecessors drop + bb to 1vector >>successors drop + to predecessors>> [ dup from eq? [ drop bb ] when ] change-each + from successors>> [ dup to eq? [ drop bb ] when ] change-each ; + +:: insert-basic-blocks ( bb -- ) + added-instructions get + [| predecessor instructions | + \ ##branch new-insn instructions push + predecessor bb + instructions >>instructions + insert-basic-block + ] assoc-each ; + From 8ff473e42cdc6b1965703938e21be27ecd51abce Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Sun, 12 Jul 2009 23:00:33 -0500 Subject: [PATCH 21/96] compiler.cfg.linear-scan.resolve: get it to work on CFGs with critical edges --- .../cfg/linear-scan/linear-scan-tests.factor | 9 +++-- .../cfg/linear-scan/linear-scan.factor | 1 + .../linear-scan/resolve/resolve-tests.factor | 7 ---- .../cfg/linear-scan/resolve/resolve.factor | 39 +++---------------- basis/compiler/cfg/utilities/utilities.factor | 18 ++++----- 5 files changed, 21 insertions(+), 53 deletions(-) delete mode 100644 basis/compiler/cfg/linear-scan/resolve/resolve-tests.factor diff --git a/basis/compiler/cfg/linear-scan/linear-scan-tests.factor b/basis/compiler/cfg/linear-scan/linear-scan-tests.factor index e8b4b67cf0..20f8570f84 100644 --- a/basis/compiler/cfg/linear-scan/linear-scan-tests.factor +++ b/basis/compiler/cfg/linear-scan/linear-scan-tests.factor @@ -1509,6 +1509,7 @@ SYMBOL: linear-scan-result compute-liveness dup reverse-post-order { { int-regs regs } } (linear-scan) + cfg-changed flatten-cfg 1array mr. ] with-scope ; @@ -1803,7 +1804,7 @@ test-diamond [ ] [ { 1 2 } test-linear-scan-on-cfg ] unit-test -[ _spill ] [ 2 get instructions>> first class ] unit-test +[ _spill ] [ 2 get successors>> first instructions>> first class ] unit-test [ _spill ] [ 3 get instructions>> second class ] unit-test @@ -1859,7 +1860,7 @@ V{ [ t ] [ 2 get instructions>> [ _spill? ] any? ] unit-test -[ t ] [ 3 get instructions>> [ _spill? ] any? ] unit-test +[ t ] [ 3 get predecessors>> first instructions>> [ _spill? ] any? ] unit-test [ t ] [ 5 get instructions>> [ _reload? ] any? ] unit-test @@ -1926,7 +1927,7 @@ V{ [ V{ 3 2 1 } ] [ 9 get instructions>> [ _reload? ] filter [ n>> ] map ] unit-test ! Resolve pass should insert this -[ _reload ] [ 5 get instructions>> first class ] unit-test +[ _reload ] [ 5 get predecessors>> first instructions>> first class ] unit-test ! Some random bug V{ @@ -2484,7 +2485,7 @@ test-diamond [ 1 ] [ 2 get instructions>> [ _spill? ] count ] unit-test -[ 1 ] [ 3 get instructions>> [ _spill? ] count ] unit-test +[ 1 ] [ 3 get predecessors>> first instructions>> [ _spill? ] count ] unit-test [ 1 ] [ 4 get instructions>> [ _reload? ] count ] unit-test diff --git a/basis/compiler/cfg/linear-scan/linear-scan.factor b/basis/compiler/cfg/linear-scan/linear-scan.factor index 77d66c274d..c17aa23e83 100644 --- a/basis/compiler/cfg/linear-scan/linear-scan.factor +++ b/basis/compiler/cfg/linear-scan/linear-scan.factor @@ -40,4 +40,5 @@ IN: compiler.cfg.linear-scan init-mapping dup reverse-post-order machine-registers (linear-scan) spill-counts get >>spill-counts + cfg-changed ] with-scope ; diff --git a/basis/compiler/cfg/linear-scan/resolve/resolve-tests.factor b/basis/compiler/cfg/linear-scan/resolve/resolve-tests.factor deleted file mode 100644 index b5e95258bf..0000000000 --- a/basis/compiler/cfg/linear-scan/resolve/resolve-tests.factor +++ /dev/null @@ -1,7 +0,0 @@ -USING: arrays compiler.cfg.linear-scan.resolve kernel -tools.test ; -IN: compiler.cfg.linear-scan.resolve.tests - -[ { 1 2 3 4 5 6 } ] [ - { 3 4 } V{ 1 2 } clone [ { 5 6 } 3append-here ] keep >array -] unit-test diff --git a/basis/compiler/cfg/linear-scan/resolve/resolve.factor b/basis/compiler/cfg/linear-scan/resolve/resolve.factor index 7b7f242e4e..f7ed994f18 100644 --- a/basis/compiler/cfg/linear-scan/resolve/resolve.factor +++ b/basis/compiler/cfg/linear-scan/resolve/resolve.factor @@ -3,6 +3,7 @@ USING: accessors arrays assocs combinators combinators.short-circuit fry kernel locals make math sequences +compiler.cfg.utilities compiler.cfg.instructions compiler.cfg.linear-scan.assignment compiler.cfg.linear-scan.mapping compiler.cfg.liveness ; @@ -30,42 +31,14 @@ IN: compiler.cfg.linear-scan.resolve [ resolve-value-data-flow ] with with each ] { } make ; -: fork? ( from to -- ? ) - { - [ drop successors>> length 1 >= ] - [ nip predecessors>> length 1 = ] - } 2&& ; inline - -: insert-position/fork ( from to -- before after ) - nip instructions>> [ >array ] [ dup delete-all ] bi swap ; - -: join? ( from to -- ? ) - { - [ drop successors>> length 1 = ] - [ nip predecessors>> length 1 >= ] - } 2&& ; inline - -: insert-position/join ( from to -- before after ) - drop instructions>> dup pop 1array ; - -: insert-position ( bb to -- before after ) - { - { [ 2dup fork? ] [ insert-position/fork ] } - { [ 2dup join? ] [ insert-position/join ] } - } cond ; - -: 3append-here ( seq2 seq1 seq3 -- ) - #! Mutate seq1 - swap '[ _ push-all ] bi@ ; - -: perform-mappings ( mappings bb to -- ) - pick empty? [ 3drop ] [ - [ mapping-instructions ] 2dip - insert-position 3append-here +: perform-mappings ( bb to mappings -- ) + dup empty? [ 3drop ] [ + mapping-instructions + insert-basic-block ] if ; : resolve-edge-data-flow ( bb to -- ) - [ compute-mappings ] [ perform-mappings ] 2bi ; + 2dup compute-mappings perform-mappings ; : resolve-block-data-flow ( bb -- ) dup successors>> [ resolve-edge-data-flow ] with each ; diff --git a/basis/compiler/cfg/utilities/utilities.factor b/basis/compiler/cfg/utilities/utilities.factor index 0e08607331..288fa403dd 100644 --- a/basis/compiler/cfg/utilities/utilities.factor +++ b/basis/compiler/cfg/utilities/utilities.factor @@ -2,7 +2,7 @@ ! See http://factorcode.org/license.txt for BSD license. USING: accessors assocs combinators combinators.short-circuit compiler.cfg compiler.cfg.instructions cpu.architecture kernel -layouts locals make math namespaces sequences sets vectors ; +layouts locals make math namespaces sequences sets vectors fry ; IN: compiler.cfg.utilities : value-info-small-fixnum? ( value-info -- ? ) @@ -74,12 +74,12 @@ SYMBOL: added-instructions to predecessors>> [ dup from eq? [ drop bb ] when ] change-each from successors>> [ dup to eq? [ drop bb ] when ] change-each ; -:: insert-basic-blocks ( bb -- ) - added-instructions get - [| predecessor instructions | - \ ##branch new-insn instructions push - predecessor bb - instructions >>instructions - insert-basic-block - ] assoc-each ; +: ( insns -- bb ) + + swap >vector + \ ##branch new-insn over push + >>instructions ; +: insert-basic-blocks ( bb -- ) + [ added-instructions get ] dip + '[ [ _ ] dip insert-basic-block ] assoc-each ; From d7aeae45be8984bd2dc0c198758d3c9713c98dda Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 13 Jul 2009 10:44:08 -0500 Subject: [PATCH 22/96] compiler.cfg.branch-splitting: split blocks with successors --- .../branch-splitting-tests.factor | 85 +++++++++++++++++++ .../branch-splitting/branch-splitting.factor | 82 +++++++++++++----- .../cfg/optimizer/optimizer-tests.factor | 6 +- basis/compiler/cfg/optimizer/optimizer.factor | 3 +- basis/compiler/cfg/renaming/renaming.factor | 6 ++ .../stack-analysis/merge/merge-tests.factor | 6 +- 6 files changed, 162 insertions(+), 26 deletions(-) create mode 100644 basis/compiler/cfg/branch-splitting/branch-splitting-tests.factor diff --git a/basis/compiler/cfg/branch-splitting/branch-splitting-tests.factor b/basis/compiler/cfg/branch-splitting/branch-splitting-tests.factor new file mode 100644 index 0000000000..fbaaf92203 --- /dev/null +++ b/basis/compiler/cfg/branch-splitting/branch-splitting-tests.factor @@ -0,0 +1,85 @@ +USING: accessors assocs compiler.cfg +compiler.cfg.branch-splitting compiler.cfg.debugger +compiler.cfg.predecessors compiler.cfg.rpo fry kernel +tools.test namespaces sequences vectors ; +IN: compiler.cfg.branch-splitting.tests + +: get-predecessors ( cfg -- assoc ) + H{ } clone [ '[ [ predecessors>> ] keep _ set-at ] each-basic-block ] keep ; + +: check-predecessors ( cfg -- ) + [ get-predecessors ] + [ compute-predecessors drop ] + [ get-predecessors ] tri assert= ; + +: check-branch-splitting ( cfg -- ) + compute-predecessors + split-branches + check-predecessors ; + +: test-branch-splitting ( -- ) + cfg new 0 get >>entry check-branch-splitting ; + +V{ } 0 test-bb + +V{ } 1 test-bb + +V{ } 2 test-bb + +V{ } 3 test-bb + +V{ } 4 test-bb + +test-diamond + +[ ] [ test-branch-splitting ] unit-test + +V{ } 0 test-bb + +V{ } 1 test-bb + +V{ } 2 test-bb + +V{ } 3 test-bb + +V{ } 4 test-bb + +V{ } 5 test-bb + +0 get 1 get 2 get V{ } 2sequence >>successors drop + +1 get 3 get 4 get V{ } 2sequence >>successors drop + +2 get 3 get 4 get V{ } 2sequence >>successors drop + +[ ] [ test-branch-splitting ] unit-test + +V{ } 0 test-bb + +V{ } 1 test-bb + +V{ } 2 test-bb + +V{ } 3 test-bb + +V{ } 4 test-bb + +0 get 1 get 2 get V{ } 2sequence >>successors drop + +1 get 3 get 4 get V{ } 2sequence >>successors drop + +2 get 4 get 1vector >>successors drop + +[ ] [ test-branch-splitting ] unit-test + +V{ } 0 test-bb + +V{ } 1 test-bb + +V{ } 2 test-bb + +0 get 1 get 2 get V{ } 2sequence >>successors drop + +1 get 2 get 1vector >>successors drop + +[ ] [ test-branch-splitting ] unit-test \ No newline at end of file diff --git a/basis/compiler/cfg/branch-splitting/branch-splitting.factor b/basis/compiler/cfg/branch-splitting/branch-splitting.factor index f7e9ea9cbf..0dd963125f 100644 --- a/basis/compiler/cfg/branch-splitting/branch-splitting.factor +++ b/basis/compiler/cfg/branch-splitting/branch-splitting.factor @@ -1,37 +1,79 @@ ! Copyright (C) 2009 Doug Coleman, Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: accessors combinators.short-circuit kernel math sequences -compiler.cfg.def-use compiler.cfg compiler.cfg.rpo ; +USING: accessors combinators.short-circuit kernel math math.order +sequences assocs namespaces vectors fry arrays splitting +compiler.cfg.def-use compiler.cfg compiler.cfg.rpo +compiler.cfg.renaming compiler.cfg.instructions compiler.cfg.utilities ; IN: compiler.cfg.branch-splitting -! Predecessors must be recomputed after this +: clone-renamings ( insns -- assoc ) + [ defs-vregs ] map concat [ dup fresh-vreg ] H{ } map>assoc ; -: split-branch-for ( bb predecessor -- ) - [ +: clone-instructions ( insns -- insns' ) + dup clone-renamings renamings [ [ - - swap - [ instructions>> [ clone ] map >>instructions ] - [ successors>> clone >>successors ] - bi - ] keep - ] dip - [ [ 2dup eq? [ 2drop ] [ 2nip ] if ] with with map ] change-successors - drop ; + clone + dup rename-insn-defs + dup rename-insn-uses + dup fresh-insn-temps + ] map + ] with-variable ; + +: clone-basic-block ( bb -- bb' ) + ! The new block gets the same RPO number as the old one. + ! This is just to make 'back-edge?' work. + + swap + [ instructions>> clone-instructions >>instructions ] + [ successors>> clone >>successors ] + [ number>> >>number ] + tri ; + +: new-blocks ( bb -- copies ) + dup predecessors>> [ + [ clone-basic-block ] dip + 1vector >>predecessors + ] with map ; + +: update-predecessor-successor ( pred copy old-bb -- ) + '[ + [ _ _ 3dup nip eq? [ drop nip ] [ 2drop ] if ] map + ] change-successors drop ; + +: update-predecessor-successors ( copies old-bb -- ) + [ predecessors>> swap ] keep + '[ _ update-predecessor-successor ] 2each ; + +: update-successor-predecessor ( copies old-bb succ -- ) + [ + swap 1array split swap join V{ } like + ] change-predecessors drop ; + +: update-successor-predecessors ( copies old-bb -- ) + dup successors>> [ + update-successor-predecessor + ] with with each ; : split-branch ( bb -- ) - dup predecessors>> [ split-branch-for ] with each ; + [ new-blocks ] keep + [ update-predecessor-successors ] + [ update-successor-predecessors ] + 2bi ; + +UNION: irrelevant ##peek ##replace ##inc-d ##inc-r ; + +: split-instructions? ( insns -- ? ) + [ irrelevant? not ] count 5 <= ; : split-branches? ( bb -- ? ) { - [ successors>> empty? ] - [ predecessors>> length 1 > ] - [ instructions>> [ defs-vregs ] any? not ] - [ instructions>> [ temp-vregs ] any? not ] + [ dup successors>> [ back-edge? ] with any? not ] + [ predecessors>> length 1 4 between? ] + [ instructions>> split-instructions? ] } 1&& ; : split-branches ( cfg -- cfg' ) dup [ dup split-branches? [ split-branch ] [ drop ] if ] each-basic-block - f >>post-order ; + cfg-changed ; diff --git a/basis/compiler/cfg/optimizer/optimizer-tests.factor b/basis/compiler/cfg/optimizer/optimizer-tests.factor index f585d80d72..1eb1996da4 100755 --- a/basis/compiler/cfg/optimizer/optimizer-tests.factor +++ b/basis/compiler/cfg/optimizer/optimizer-tests.factor @@ -2,7 +2,7 @@ USING: accessors arrays compiler.cfg.checker compiler.cfg.debugger compiler.cfg.def-use compiler.cfg.instructions fry kernel kernel.private math math.partial-dispatch math.private sbufs sequences sequences.private sets -slots.private strings tools.test vectors layouts ; +slots.private strings strings.private tools.test vectors layouts ; IN: compiler.cfg.optimizer.tests ! Miscellaneous tests @@ -40,6 +40,10 @@ IN: compiler.cfg.optimizer.tests ] [ 2drop f ] if ] [ 2drop f ] if ] + [ + pick 10 fixnum>= [ [ 123 fixnum-bitand ] 2dip ] [ ] if + set-string-nth-fast + ] } [ [ [ ] ] dip '[ _ test-mr first check-mr ] unit-test ] each diff --git a/basis/compiler/cfg/optimizer/optimizer.factor b/basis/compiler/cfg/optimizer/optimizer.factor index 84eb8a84d1..5b0892a0ee 100644 --- a/basis/compiler/cfg/optimizer/optimizer.factor +++ b/basis/compiler/cfg/optimizer/optimizer.factor @@ -29,10 +29,9 @@ SYMBOL: check-optimizer? ! The passes that need this document it. [ optimize-tail-calls - compute-predecessors delete-useless-conditionals - split-branches compute-predecessors + split-branches stack-analysis compute-liveness alias-analysis diff --git a/basis/compiler/cfg/renaming/renaming.factor b/basis/compiler/cfg/renaming/renaming.factor index 4a8c6e6a4d..228d72483c 100644 --- a/basis/compiler/cfg/renaming/renaming.factor +++ b/basis/compiler/cfg/renaming/renaming.factor @@ -55,6 +55,12 @@ M: ##string-nth rename-insn-uses [ rename-value ] change-index drop ; +M: ##set-string-nth-fast rename-insn-uses + dup call-next-method + [ rename-value ] change-obj + [ rename-value ] change-index + drop ; + M: ##set-slot-imm rename-insn-uses dup call-next-method [ rename-value ] change-obj diff --git a/basis/compiler/cfg/stack-analysis/merge/merge-tests.factor b/basis/compiler/cfg/stack-analysis/merge/merge-tests.factor index e67f6b5143..5883777861 100644 --- a/basis/compiler/cfg/stack-analysis/merge/merge-tests.factor +++ b/basis/compiler/cfg/stack-analysis/merge/merge-tests.factor @@ -1,8 +1,8 @@ IN: compiler.cfg.stack-analysis.merge.tests USING: compiler.cfg.stack-analysis.merge tools.test arrays accessors -compiler.cfg.instructions compiler.cfg.stack-analysis.state -compiler.cfg compiler.cfg.registers compiler.cfg.debugger -cpu.architecture make assocs namespaces + compiler.cfg.instructions compiler.cfg.stack-analysis.state +compiler.cfg.utilities compiler.cfg compiler.cfg.registers +compiler.cfg.debugger cpu.architecture make assocs namespaces sequences kernel classes ; [ From 3b244d5d4149a88516482aa2f6a784468259e655 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 13 Jul 2009 12:33:58 -0500 Subject: [PATCH 23/96] compiler.cfg.value-numbering: fix ##compare and ##compare-branch rewrites --- .../value-numbering/rewrite/rewrite.factor | 39 ++++++++++--------- core/sequences/sequences-tests.factor | 5 ++- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/basis/compiler/cfg/value-numbering/rewrite/rewrite.factor b/basis/compiler/cfg/value-numbering/rewrite/rewrite.factor index ca7a959a82..92965e40c5 100755 --- a/basis/compiler/cfg/value-numbering/rewrite/rewrite.factor +++ b/basis/compiler/cfg/value-numbering/rewrite/rewrite.factor @@ -77,13 +77,19 @@ M: ##compare-imm-branch rewrite insn cc>> swap? [ swap-cc ] when i \ ##compare-imm new-insn ; inline -! M: ##compare rewrite -! dup [ src1>> ] [ src2>> ] bi -! [ vreg>expr constant-expr? ] bi@ 2array { -! { { f t } [ f >compare-imm ] } -! { { t f } [ t >compare-imm ] } -! [ drop ] -! } case ; +: vreg-small-constant? ( vreg -- ? ) + vreg>expr { + [ constant-expr? ] + [ value>> small-enough? ] + } 1&& ; + +M: ##compare rewrite + dup [ src1>> ] [ src2>> ] bi + [ vreg-small-constant? ] bi@ 2array { + { { f t } [ f >compare-imm ] } + { { t f } [ t >compare-imm ] } + [ drop ] + } case ; :: >compare-imm-branch ( insn swap? -- insn' ) insn src1>> @@ -91,13 +97,13 @@ M: ##compare-imm-branch rewrite insn cc>> swap? [ swap-cc ] when \ ##compare-imm-branch new-insn ; inline -! M: ##compare-branch rewrite -! dup [ src1>> ] [ src2>> ] bi -! [ vreg>expr constant-expr? ] bi@ 2array { -! { { f t } [ f >compare-imm-branch ] } -! { { t f } [ t >compare-imm-branch ] } -! [ drop ] -! } case ; +M: ##compare-branch rewrite + dup [ src1>> ] [ src2>> ] bi + [ vreg-small-constant? ] bi@ 2array { + { { f t } [ f >compare-imm-branch ] } + { { t f } [ t >compare-imm-branch ] } + [ drop ] + } case ; : rewrite-redundant-comparison? ( insn -- ? ) { @@ -198,10 +204,7 @@ M: ##or-imm rewrite [ bitor ] \ ##or-imm combine-imm ; M: ##xor-imm rewrite [ bitxor ] \ ##xor-imm combine-imm ; : rewrite-add? ( insn -- ? ) - src2>> { - [ vreg>expr constant-expr? ] - [ vreg>constant small-enough? ] - } 1&& ; + src2>> vreg-small-constant? ; M: ##add rewrite dup rewrite-add? [ diff --git a/core/sequences/sequences-tests.factor b/core/sequences/sequences-tests.factor index 5e0d5597ca..2aa95b23ab 100644 --- a/core/sequences/sequences-tests.factor +++ b/core/sequences/sequences-tests.factor @@ -290,4 +290,7 @@ M: bogus-hashcode hashcode* 2drop 0 >bignum ; USE: make [ { "a" 1 "b" 1 "c" } ] -[ 1 { "a" "b" "c" } [ [ dup , ] [ , ] interleave drop ] { } make ] unit-test \ No newline at end of file +[ 1 { "a" "b" "c" } [ [ dup , ] [ , ] interleave drop ] { } make ] unit-test + +[ t ] [ 0 array-capacity? ] unit-test +[ f ] [ -1 array-capacity? ] unit-test \ No newline at end of file From 768e2a51486d32c5d866b174adfeae088721f1e6 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 13 Jul 2009 14:42:52 -0500 Subject: [PATCH 24/96] compiler.cfg: split off condition codes into a comparisons sub-vocabulary --- .../cfg/branch-folding/branch-folding.factor | 5 ++- basis/compiler/cfg/builder/builder.factor | 1 + .../cfg/comparisons/comparisons.factor | 36 ++++++++++++++++++ .../cfg/instructions/instructions.factor | 38 ------------------- .../cfg/intrinsics/fixnum/fixnum.factor | 3 +- .../compiler/cfg/intrinsics/intrinsics.factor | 3 +- .../cfg/linearization/linearization.factor | 1 + .../value-numbering/rewrite/rewrite.factor | 5 ++- basis/cpu/x86/x86.factor | 11 ++++-- 9 files changed, 58 insertions(+), 45 deletions(-) create mode 100644 basis/compiler/cfg/comparisons/comparisons.factor diff --git a/basis/compiler/cfg/branch-folding/branch-folding.factor b/basis/compiler/cfg/branch-folding/branch-folding.factor index 2432849a9a..04842552b7 100644 --- a/basis/compiler/cfg/branch-folding/branch-folding.factor +++ b/basis/compiler/cfg/branch-folding/branch-folding.factor @@ -1,7 +1,10 @@ ! Copyright (C) 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: accessors combinators.short-circuit kernel sequences vectors -compiler.cfg.instructions compiler.cfg.rpo compiler.cfg ; +compiler.cfg.instructions +compiler.cfg.comparisons +compiler.cfg.rpo +compiler.cfg ; IN: compiler.cfg.branch-folding ! Fold comparisons where both inputs are the same. Predecessors must be diff --git a/basis/compiler/cfg/builder/builder.factor b/basis/compiler/cfg/builder/builder.factor index 8cf141f3f4..991fd2e20d 100755 --- a/basis/compiler/cfg/builder/builder.factor +++ b/basis/compiler/cfg/builder/builder.factor @@ -14,6 +14,7 @@ compiler.cfg.stacks compiler.cfg.utilities compiler.cfg.registers compiler.cfg.intrinsics +compiler.cfg.comparisons compiler.cfg.stack-frame compiler.cfg.instructions compiler.alien ; diff --git a/basis/compiler/cfg/comparisons/comparisons.factor b/basis/compiler/cfg/comparisons/comparisons.factor new file mode 100644 index 0000000000..576d541230 --- /dev/null +++ b/basis/compiler/cfg/comparisons/comparisons.factor @@ -0,0 +1,36 @@ +! Copyright (C) 2009 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: assocs math.order sequences ; +IN: compiler.cfg.comparisons + +SYMBOLS: cc< cc<= cc= cc> cc>= cc/= ; + +: negate-cc ( cc -- cc' ) + H{ + { cc< cc>= } + { cc<= cc> } + { cc> cc<= } + { cc>= cc< } + { cc= cc/= } + { cc/= cc= } + } at ; + +: swap-cc ( cc -- cc' ) + H{ + { cc< cc> } + { cc<= cc>= } + { cc> cc< } + { cc>= cc<= } + { cc= cc= } + { cc/= cc/= } + } at ; + +: evaluate-cc ( result cc -- ? ) + H{ + { cc< { +lt+ } } + { cc<= { +lt+ +eq+ } } + { cc= { +eq+ } } + { cc>= { +eq+ +gt+ } } + { cc> { +gt+ } } + { cc/= { +lt+ +gt+ } } + } at memq? ; \ No newline at end of file diff --git a/basis/compiler/cfg/instructions/instructions.factor b/basis/compiler/cfg/instructions/instructions.factor index abbb86cb16..910cb1992b 100644 --- a/basis/compiler/cfg/instructions/instructions.factor +++ b/basis/compiler/cfg/instructions/instructions.factor @@ -181,44 +181,6 @@ INSN: ##loop-entry ; INSN: ##phi < ##pure inputs ; -! Condition codes -SYMBOL: cc< -SYMBOL: cc<= -SYMBOL: cc= -SYMBOL: cc> -SYMBOL: cc>= -SYMBOL: cc/= - -: negate-cc ( cc -- cc' ) - H{ - { cc< cc>= } - { cc<= cc> } - { cc> cc<= } - { cc>= cc< } - { cc= cc/= } - { cc/= cc= } - } at ; - -: swap-cc ( cc -- cc' ) - H{ - { cc< cc> } - { cc<= cc>= } - { cc> cc< } - { cc>= cc<= } - { cc= cc= } - { cc/= cc/= } - } at ; - -: evaluate-cc ( result cc -- ? ) - H{ - { cc< { +lt+ } } - { cc<= { +lt+ +eq+ } } - { cc= { +eq+ } } - { cc>= { +eq+ +gt+ } } - { cc> { +gt+ } } - { cc/= { +lt+ +gt+ } } - } at memq? ; - TUPLE: ##conditional-branch < insn { src1 vreg } { src2 vreg } cc ; INSN: ##compare-branch < ##conditional-branch ; diff --git a/basis/compiler/cfg/intrinsics/fixnum/fixnum.factor b/basis/compiler/cfg/intrinsics/fixnum/fixnum.factor index 9efac9e81a..b360eed80b 100644 --- a/basis/compiler/cfg/intrinsics/fixnum/fixnum.factor +++ b/basis/compiler/cfg/intrinsics/fixnum/fixnum.factor @@ -7,7 +7,8 @@ compiler.cfg.hats compiler.cfg.stacks compiler.cfg.instructions compiler.cfg.utilities -compiler.cfg.registers ; +compiler.cfg.registers +compiler.cfg.comparisons ; IN: compiler.cfg.intrinsics.fixnum : emit-both-fixnums? ( -- ) diff --git a/basis/compiler/cfg/intrinsics/intrinsics.factor b/basis/compiler/cfg/intrinsics/intrinsics.factor index df01bba89b..5283581bdd 100644 --- a/basis/compiler/cfg/intrinsics/intrinsics.factor +++ b/basis/compiler/cfg/intrinsics/intrinsics.factor @@ -8,7 +8,8 @@ compiler.cfg.intrinsics.allot compiler.cfg.intrinsics.fixnum compiler.cfg.intrinsics.float compiler.cfg.intrinsics.slots -compiler.cfg.intrinsics.misc ; +compiler.cfg.intrinsics.misc +compiler.cfg.comparisons ; QUALIFIED: kernel QUALIFIED: arrays QUALIFIED: byte-arrays diff --git a/basis/compiler/cfg/linearization/linearization.factor b/basis/compiler/cfg/linearization/linearization.factor index 15e7cef553..a75ac064d9 100755 --- a/basis/compiler/cfg/linearization/linearization.factor +++ b/basis/compiler/cfg/linearization/linearization.factor @@ -5,6 +5,7 @@ combinators assocs arrays locals cpu.architecture compiler.cfg compiler.cfg.rpo compiler.cfg.liveness +compiler.cfg.comparisons compiler.cfg.stack-frame compiler.cfg.instructions ; IN: compiler.cfg.linearization diff --git a/basis/compiler/cfg/value-numbering/rewrite/rewrite.factor b/basis/compiler/cfg/value-numbering/rewrite/rewrite.factor index 92965e40c5..0dea35409d 100755 --- a/basis/compiler/cfg/value-numbering/rewrite/rewrite.factor +++ b/basis/compiler/cfg/value-numbering/rewrite/rewrite.factor @@ -2,7 +2,10 @@ ! See http://factorcode.org/license.txt for BSD license. USING: accessors locals combinators combinators.short-circuit arrays fry kernel layouts math namespaces sequences cpu.architecture -math.bitwise compiler.cfg.hats compiler.cfg.instructions +math.bitwise +compiler.cfg.hats +compiler.cfg.comparisons +compiler.cfg.instructions compiler.cfg.value-numbering.expressions compiler.cfg.value-numbering.graph compiler.cfg.value-numbering.simplify ; diff --git a/basis/cpu/x86/x86.factor b/basis/cpu/x86/x86.factor index 15c54aa7d8..bb2ee620e3 100644 --- a/basis/cpu/x86/x86.factor +++ b/basis/cpu/x86/x86.factor @@ -4,9 +4,14 @@ USING: accessors assocs alien alien.c-types arrays strings cpu.x86.assembler cpu.x86.assembler.private cpu.architecture kernel kernel.private math memory namespaces make sequences words system layouts combinators math.order fry locals -compiler.constants compiler.cfg.registers -compiler.cfg.instructions compiler.cfg.intrinsics -compiler.cfg.stack-frame compiler.codegen compiler.codegen.fixup ; +compiler.constants +compiler.cfg.registers +compiler.cfg.instructions +compiler.cfg.intrinsics +compiler.cfg.comparisons +compiler.cfg.stack-frame +compiler.codegen +compiler.codegen.fixup ; IN: cpu.x86 << enable-fixnum-log2 >> From ccae9b59a4e69b17b2a011313a5050d524920d8e Mon Sep 17 00:00:00 2001 From: Doug Coleman Date: Mon, 13 Jul 2009 19:02:05 -0500 Subject: [PATCH 25/96] clean up value numbering conversion of ##add/sub to ##add/sub-imm --- .../value-numbering/rewrite/rewrite.factor | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/basis/compiler/cfg/value-numbering/rewrite/rewrite.factor b/basis/compiler/cfg/value-numbering/rewrite/rewrite.factor index 92965e40c5..988df366eb 100755 --- a/basis/compiler/cfg/value-numbering/rewrite/rewrite.factor +++ b/basis/compiler/cfg/value-numbering/rewrite/rewrite.factor @@ -49,9 +49,12 @@ M: insn rewrite ; [ src2>> tag-mask get bitand 0 = ] } 1&& ; inline +: tagged>constant ( n -- n' ) + tag-bits get neg shift ; inline + : (rewrite-tagged-comparison) ( insn -- src1 src2 cc ) [ src1>> vreg>expr in1>> vn>vreg ] - [ src2>> tag-bits get neg shift ] + [ src2>> tagged>constant ] [ cc>> ] tri ; inline @@ -203,15 +206,20 @@ M: ##or-imm rewrite [ bitor ] \ ##or-imm combine-imm ; M: ##xor-imm rewrite [ bitxor ] \ ##xor-imm combine-imm ; -: rewrite-add? ( insn -- ? ) - src2>> vreg-small-constant? ; - -M: ##add rewrite - dup rewrite-add? [ +: new-arithmetic ( obj op -- ) + [ [ dst>> ] [ src1>> ] - [ src2>> vreg>constant ] tri \ ##add-imm new-insn - dup number-values - ] when ; + [ src2>> vreg>constant ] tri + ] dip new-insn dup number-values ; inline -M: ##sub rewrite constant-fold ; +: rewrite-arithmetic ( insn op -- ? ) + over src2>> vreg-small-constant? [ + new-arithmetic constant-fold + ] [ + drop + ] if ; inline + +M: ##add rewrite \ ##add-imm rewrite-arithmetic ; + +M: ##sub rewrite \ ##sub-imm rewrite-arithmetic ; From a06948298bf705649c04bc77d141a14687683522 Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Mon, 13 Jul 2009 22:35:36 -0500 Subject: [PATCH 26/96] ensure resize-world never happens before begin-world --- basis/ui/gadgets/worlds/worlds.factor | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/basis/ui/gadgets/worlds/worlds.factor b/basis/ui/gadgets/worlds/worlds.factor index ed21c85b19..0c59af95d6 100755 --- a/basis/ui/gadgets/worlds/worlds.factor +++ b/basis/ui/gadgets/worlds/worlds.factor @@ -163,9 +163,11 @@ M: world resize-world M: world (>>dim) [ call-next-method ] [ - dup handle>> - [ [ set-gl-context ] [ resize-world ] bi ] - [ drop ] if + dup active?>> [ + dup handle>> + [ [ set-gl-context ] [ resize-world ] bi ] + [ drop ] if + ] [ drop ] if ] bi ; GENERIC: draw-world* ( world -- ) From 05343e88ba9af38b7a86815a6f59cc173323c4f6 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 13 Jul 2009 22:59:51 -0500 Subject: [PATCH 27/96] bson: fix broken unit test --- extra/bson/bson-tests.factor | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/extra/bson/bson-tests.factor b/extra/bson/bson-tests.factor index e66b9c6ec2..9db3451f26 100644 --- a/extra/bson/bson-tests.factor +++ b/extra/bson/bson-tests.factor @@ -6,9 +6,6 @@ IN: bson.tests : turnaround ( value -- value ) assoc>bv >byte-array binary [ H{ } stream>assoc ] with-byte-reader ; -M: timestamp equal? ( obj1 obj2 -- ? ) - [ timestamp>millis ] bi@ = ; - [ H{ { "a" "a string" } } ] [ H{ { "a" "a string" } } turnaround ] unit-test [ H{ { "a" "a string" } { "b" H{ { "a" "a string" } } } } ] @@ -23,10 +20,9 @@ M: timestamp equal? ( obj1 obj2 -- ? ) [ H{ { "a date" T{ timestamp { year 2009 } { month 7 } { day 11 } - { hour 11 } + { hour 9 } { minute 8 } - { second 40+15437/200000 } - { gmt-offset T{ duration { hour 2 } } } } } } + { second 40+77/1000 } } } } ] [ H{ { "a date" T{ timestamp { year 2009 } { month 7 } From afdd53768194272b267591e5a3a2d97075d1bd34 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 13 Jul 2009 23:35:21 -0500 Subject: [PATCH 28/96] tools.annotations: add (annotate) word which doesn't create a compilation unit for use in loops --- basis/tools/annotations/annotations.factor | 23 +++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/basis/tools/annotations/annotations.factor b/basis/tools/annotations/annotations.factor index e7e5837ee8..f02476d4da 100644 --- a/basis/tools/annotations/annotations.factor +++ b/basis/tools/annotations/annotations.factor @@ -31,19 +31,20 @@ M: cannot-annotate-twice summary drop "Cannot annotate a word twice" ; cannot-annotate-twice ] when ; +GENERIC# (annotate) 1 ( word quot -- ) + +M: generic (annotate) + [ "methods" word-prop values ] dip '[ _ (annotate) ] each ; + +M: word (annotate) + [ check-annotate-twice ] dip + [ dup def>> 2dup "unannotated-def" set-word-prop ] dip + call( old -- new ) define ; + PRIVATE> -GENERIC# annotate 1 ( word quot -- ) - -M: generic annotate - [ "methods" word-prop values ] dip '[ _ annotate ] each ; - -M: word annotate - [ check-annotate-twice ] dip - [ - [ dup def>> 2dup "unannotated-def" set-word-prop ] dip - call( old -- new ) define - ] with-compilation-unit ; +: annotate ( word quot -- ) + [ (annotate) ] with-compilation-unit ; Date: Tue, 14 Jul 2009 01:12:45 -0500 Subject: [PATCH 29/96] call( and execute( inline known quotations/words in the propagation pass --- .../tree/propagation/call-effect/authors.txt | 2 + .../call-effect/call-effect-tests.factor | 51 +++++++++++ .../call-effect/call-effect.factor | 85 ++++++++++++++++--- .../known-words/known-words.factor | 3 +- basis/stack-checker/call-effect/authors.txt | 1 - .../call-effect/call-effect-tests.factor | 16 ---- .../known-words/known-words.factor | 10 +++ basis/stack-checker/stack-checker.factor | 2 - 8 files changed, 138 insertions(+), 32 deletions(-) create mode 100644 basis/compiler/tree/propagation/call-effect/authors.txt create mode 100644 basis/compiler/tree/propagation/call-effect/call-effect-tests.factor rename basis/{stack-checker => compiler/tree/propagation}/call-effect/call-effect.factor (59%) delete mode 100644 basis/stack-checker/call-effect/authors.txt delete mode 100644 basis/stack-checker/call-effect/call-effect-tests.factor diff --git a/basis/compiler/tree/propagation/call-effect/authors.txt b/basis/compiler/tree/propagation/call-effect/authors.txt new file mode 100644 index 0000000000..a44f8d7f8d --- /dev/null +++ b/basis/compiler/tree/propagation/call-effect/authors.txt @@ -0,0 +1,2 @@ +Slava Pestov +Daniel Ehrenberg diff --git a/basis/compiler/tree/propagation/call-effect/call-effect-tests.factor b/basis/compiler/tree/propagation/call-effect/call-effect-tests.factor new file mode 100644 index 0000000000..5964bcee35 --- /dev/null +++ b/basis/compiler/tree/propagation/call-effect/call-effect-tests.factor @@ -0,0 +1,51 @@ +! Copyright (C) 2009 Slava Pestov, Daniel Ehrenberg. +! See http://factorcode.org/license.txt for BSD license. +USING: compiler.tree.propagation.call-effect tools.test fry math effects kernel +compiler.tree.builder compiler.tree.optimizer compiler.tree.debugger sequences ; +IN: compiler.tree.propagation.call-effect.tests + +[ t ] [ \ + (( a b -- c )) execute-effect-unsafe? ] unit-test +[ t ] [ \ + (( a b c -- d e )) execute-effect-unsafe? ] unit-test +[ f ] [ \ + (( a b c -- d )) execute-effect-unsafe? ] unit-test +[ f ] [ \ call (( x -- )) execute-effect-unsafe? ] unit-test + +[ t ] [ [ + ] cached-effect (( a b -- c )) effect= ] unit-test +[ t ] [ 5 [ + ] curry cached-effect (( a -- c )) effect= ] unit-test +[ t ] [ 5 [ ] curry cached-effect (( -- c )) effect= ] unit-test +[ t ] [ [ dup ] [ drop ] compose cached-effect (( a -- b )) effect= ] unit-test +[ t ] [ [ drop ] [ dup ] compose cached-effect (( a b -- c d )) effect= ] unit-test +[ t ] [ [ 2drop ] [ dup ] compose cached-effect (( a b c -- d e )) effect= ] unit-test +[ t ] [ [ 1 2 3 ] [ 2drop ] compose cached-effect (( -- a )) effect= ] unit-test +[ t ] [ [ 1 2 ] [ 3drop ] compose cached-effect (( a -- )) effect= ] unit-test + +: optimized-quot ( quot -- quot' ) + build-tree optimize-tree nodes>quot ; + +: compiled-call2 ( a quot: ( a -- b ) -- b ) + call( a -- b ) ; + +: compiled-execute2 ( a b word: ( a b -- c ) -- c ) + execute( a b -- c ) ; + +[ [ 3 ] ] [ [ 1 2 \ + execute( a b -- c ) ] optimized-quot ] unit-test +[ [ 3 ] ] [ [ 1 2 [ + ] call( a b -- c ) ] optimized-quot ] unit-test +[ [ 3 ] ] [ [ 1 2 '[ _ + ] call( a -- b ) ] optimized-quot ] unit-test +[ [ 3 ] ] [ [ 1 2 '[ _ ] [ + ] compose call( a -- b ) ] optimized-quot ] unit-test + +[ 1 2 { [ + ] } first compiled-call2 ] must-fail +[ 3 ] [ 1 2 { + } first compiled-execute2 ] unit-test +[ 3 ] [ 1 2 '[ _ + ] compiled-call2 ] unit-test +[ 3 ] [ 1 2 '[ _ ] [ + ] compose compiled-call2 ] unit-test +[ 3 ] [ 1 2 \ + compiled-execute2 ] unit-test + +[ 3 ] [ 1 2 { [ + ] } first call( a b -- c ) ] unit-test +[ 3 ] [ 1 2 { + } first execute( a b -- c ) ] unit-test +[ 3 ] [ 1 2 '[ _ + ] call( a -- b ) ] unit-test +[ 3 ] [ 1 2 '[ _ ] [ + ] compose call( a -- b ) ] unit-test + +[ t ] [ [ 2 '[ _ ] [ + ] compose ] final-info first infer-value (( object -- object )) effect= ] unit-test +[ t ] [ [ 2 '[ _ ] 1 '[ _ + ] compose ] final-info first infer-value (( -- object )) effect= ] unit-test +[ t ] [ [ 2 '[ _ + ] ] final-info first infer-value (( object -- object )) effect= ] unit-test +[ f ] [ [ [ [ ] [ 1 ] if ] ] final-info first infer-value ] unit-test +[ f ] [ [ [ 1 ] '[ @ ] ] final-info first infer-value ] unit-test +[ f ] [ [ dup drop ] final-info first infer-value ] unit-test diff --git a/basis/stack-checker/call-effect/call-effect.factor b/basis/compiler/tree/propagation/call-effect/call-effect.factor similarity index 59% rename from basis/stack-checker/call-effect/call-effect.factor rename to basis/compiler/tree/propagation/call-effect/call-effect.factor index 12477fdb1d..bc18aa6ec1 100644 --- a/basis/stack-checker/call-effect/call-effect.factor +++ b/basis/compiler/tree/propagation/call-effect/call-effect.factor @@ -1,9 +1,10 @@ -! Copyright (C) 2009 Slava Pestov. +! Copyright (C) 2009 Slava Pestov, Daniel Ehrenberg. ! See http://factorcode.org/license.txt for BSD license. USING: accessors combinators combinators.private effects fry kernel kernel.private make sequences continuations quotations -stack-checker stack-checker.transforms words math ; -IN: stack-checker.call-effect +words math stack-checker stack-checker.transforms +compiler.tree.propagation.info slots.private ; +IN: compiler.tree.propagation.call-effect ! call( and execute( have complex expansions. @@ -90,12 +91,8 @@ M: quotation cached-effect [ call-effect-fast ] if ; inline -: call-effect>quot ( -- quot ) - inline-cache new '[ _ call-effect-ic ] ; - -\ call-effect [ call-effect>quot ] 0 define-transform - -\ call-effect t "no-compile" set-word-prop +: call-effect>quot ( effect -- quot ) + inline-cache new '[ drop _ _ call-effect-ic ] ; : execute-effect-slow ( word effect -- ) [ '[ _ execute ] ] dip call-effect-slow ; inline @@ -116,8 +113,72 @@ M: quotation cached-effect if ; inline : execute-effect>quot ( effect -- quot ) - inline-cache new '[ _ _ execute-effect-ic ] ; + inline-cache new '[ drop _ _ execute-effect-ic ] ; -\ execute-effect [ execute-effect>quot ] 1 define-transform +: last2 ( seq -- penultimate ultimate ) + 2 tail* first2 ; -\ execute-effect t "no-compile" set-word-prop +: top-two ( #call -- effect value ) + in-d>> last2 [ value-info ] bi@ + literal>> swap ; + +ERROR: uninferable ; + +: remove-effect-input ( effect -- effect' ) + (( -- object )) swap compose-effects ; + +: (infer-value) ( value-info -- effect ) + dup class>> { + { \ quotation [ + literal>> [ uninferable ] unless* cached-effect + dup +unknown+ = [ uninferable ] when + ] } + { \ curry [ + slots>> third (infer-value) + remove-effect-input + ] } + { \ compose [ + slots>> last2 [ (infer-value) ] bi@ + compose-effects + ] } + [ uninferable ] + } case ; + +: infer-value ( value-info -- effect/f ) + [ (infer-value) ] + [ dup uninferable? [ 2drop f ] [ rethrow ] if ] + recover ; + +: (value>quot) ( value-info -- quot ) + dup class>> { + { \ quotation [ literal>> '[ drop @ ] ] } + { \ curry [ + slots>> third (value>quot) + '[ [ obj>> ] [ quot>> @ ] bi ] + ] } + { \ compose [ + slots>> last2 [ (value>quot) ] bi@ + '[ [ first>> @ ] [ second>> @ ] bi ] + ] } + } case ; + +: value>quot ( value-info -- quot: ( code effect -- ) ) + (value>quot) '[ drop @ ] ; + +: call-inlining ( #call -- quot/f ) + top-two dup infer-value [ + pick effect<= + [ nip value>quot ] + [ drop call-effect>quot ] if + ] [ drop call-effect>quot ] if* ; + +\ call-effect [ call-inlining ] "custom-inlining" set-word-prop + +: execute-inlining ( #call -- quot/f ) + top-two >literal< [ + 2dup swap execute-effect-unsafe? + [ nip '[ 2drop _ execute ] ] + [ drop execute-effect>quot ] if + ] [ drop execute-effect>quot ] if ; + +\ execute-effect [ execute-inlining ] "custom-inlining" set-word-prop diff --git a/basis/compiler/tree/propagation/known-words/known-words.factor b/basis/compiler/tree/propagation/known-words/known-words.factor index 2f5c166ac5..b3c8026bc4 100644 --- a/basis/compiler/tree/propagation/known-words/known-words.factor +++ b/basis/compiler/tree/propagation/known-words/known-words.factor @@ -13,7 +13,8 @@ compiler.tree.propagation.info compiler.tree.propagation.nodes compiler.tree.propagation.slots compiler.tree.propagation.simple -compiler.tree.propagation.constraints ; +compiler.tree.propagation.constraints +compiler.tree.propagation.call-effect ; IN: compiler.tree.propagation.known-words \ fixnum diff --git a/basis/stack-checker/call-effect/authors.txt b/basis/stack-checker/call-effect/authors.txt deleted file mode 100644 index d4f5d6b3ae..0000000000 --- a/basis/stack-checker/call-effect/authors.txt +++ /dev/null @@ -1 +0,0 @@ -Slava Pestov \ No newline at end of file diff --git a/basis/stack-checker/call-effect/call-effect-tests.factor b/basis/stack-checker/call-effect/call-effect-tests.factor deleted file mode 100644 index 0ad64cace3..0000000000 --- a/basis/stack-checker/call-effect/call-effect-tests.factor +++ /dev/null @@ -1,16 +0,0 @@ -USING: stack-checker.call-effect tools.test kernel math effects ; -IN: stack-checker.call-effect.tests - -[ t ] [ \ + (( a b -- c )) execute-effect-unsafe? ] unit-test -[ t ] [ \ + (( a b c -- d e )) execute-effect-unsafe? ] unit-test -[ f ] [ \ + (( a b c -- d )) execute-effect-unsafe? ] unit-test -[ f ] [ \ call (( x -- )) execute-effect-unsafe? ] unit-test - -[ t ] [ [ + ] cached-effect (( a b -- c )) effect= ] unit-test -[ t ] [ 5 [ + ] curry cached-effect (( a -- c )) effect= ] unit-test -[ t ] [ 5 [ ] curry cached-effect (( -- c )) effect= ] unit-test -[ t ] [ [ dup ] [ drop ] compose cached-effect (( a -- b )) effect= ] unit-test -[ t ] [ [ drop ] [ dup ] compose cached-effect (( a b -- c d )) effect= ] unit-test -[ t ] [ [ 2drop ] [ dup ] compose cached-effect (( a b c -- d e )) effect= ] unit-test -[ t ] [ [ 1 2 3 ] [ 2drop ] compose cached-effect (( -- a )) effect= ] unit-test -[ t ] [ [ 1 2 ] [ 3drop ] compose cached-effect (( a -- )) effect= ] unit-test \ No newline at end of file diff --git a/basis/stack-checker/known-words/known-words.factor b/basis/stack-checker/known-words/known-words.factor index 5bf50dfac1..6959e32452 100644 --- a/basis/stack-checker/known-words/known-words.factor +++ b/basis/stack-checker/known-words/known-words.factor @@ -205,6 +205,16 @@ M: object infer-call* \ drop-locals [ infer-drop-locals ] "special" set-word-prop +: infer-call-effect ( word -- ) + 1 ensure-d first literal value>> + add-effect-input add-effect-input + apply-word/effect ; + +{ call-effect execute-effect } [ + dup t "no-compile" set-word-prop + dup '[ _ infer-call-effect ] "special" set-word-prop +] each + \ do-primitive [ unknown-primitive-error ] "special" set-word-prop \ if [ infer-if ] "special" set-word-prop diff --git a/basis/stack-checker/stack-checker.factor b/basis/stack-checker/stack-checker.factor index 759988a61f..fe52357f9e 100644 --- a/basis/stack-checker/stack-checker.factor +++ b/basis/stack-checker/stack-checker.factor @@ -15,5 +15,3 @@ M: callable infer ( quot -- effect ) : infer. ( quot -- ) #! Safe to call from inference transforms. infer effect>string print ; - -"stack-checker.call-effect" require \ No newline at end of file From 4aa3e2135aeee3b0aa0e67bec4edacbee8091d4c Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Tue, 14 Jul 2009 01:23:21 -0500 Subject: [PATCH 30/96] Unit tests for inference behavior of call( and execute( --- basis/stack-checker/stack-checker-tests.factor | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/basis/stack-checker/stack-checker-tests.factor b/basis/stack-checker/stack-checker-tests.factor index b84f561861..8fee8df538 100644 --- a/basis/stack-checker/stack-checker-tests.factor +++ b/basis/stack-checker/stack-checker-tests.factor @@ -375,4 +375,10 @@ DEFER: eee' ! Found during code review [ [ [ drop [ ] ] when call ] infer ] must-fail -[ swap [ [ drop [ ] ] when call ] infer ] must-fail \ No newline at end of file +[ swap [ [ drop [ ] ] when call ] infer ] must-fail + +{ 3 1 } [ call( a b -- c ) ] must-infer-as +{ 3 1 } [ execute( a b -- c ) ] must-infer-as + +[ [ call-effect ] infer ] must-fail +[ [ execute-effect ] infer ] must-fail From c0e99e738e141cfdddf37a72d6eedef7dcbdf72c Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Tue, 14 Jul 2009 11:43:11 -0500 Subject: [PATCH 31/96] fix inaccuracy in tools.annotations docs --- basis/tools/annotations/annotations-docs.factor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basis/tools/annotations/annotations-docs.factor b/basis/tools/annotations/annotations-docs.factor index 8d73d85fb5..07ad79f867 100644 --- a/basis/tools/annotations/annotations-docs.factor +++ b/basis/tools/annotations/annotations-docs.factor @@ -21,7 +21,7 @@ $nl ABOUT: "tools.annotations" HELP: annotate -{ $values { "word" "a word" } { "quot" { $quotation "( word def -- def )" } } } +{ $values { "word" "a word" } { "quot" { $quotation "( old-def -- new-def )" } } } { $description "Changes a word definition to the result of applying a quotation to the old definition." } { $notes "This word is used to implement " { $link watch } "." } ; From 4b8132d7770e5db675640ef9255d27eb2c11e2ca Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Tue, 14 Jul 2009 11:43:32 -0500 Subject: [PATCH 32/96] factor compilation unit from tools.annotations:reset --- basis/tools/annotations/annotations.factor | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/basis/tools/annotations/annotations.factor b/basis/tools/annotations/annotations.factor index f02476d4da..2fb246786c 100644 --- a/basis/tools/annotations/annotations.factor +++ b/basis/tools/annotations/annotations.factor @@ -7,19 +7,24 @@ tools.time generic inspector fry tools.continuations locals generalizations macros ; IN: tools.annotations -GENERIC: reset ( word -- ) + + +: reset ( word -- ) + [ (reset) ] with-compilation-unit ; + ERROR: cannot-annotate-twice word ; M: cannot-annotate-twice summary drop "Cannot annotate a word twice" ; From 8bf1fd5f2ac65d3f742bb8a068a28501e1993ccd Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Tue, 14 Jul 2009 12:00:37 -0500 Subject: [PATCH 33/96] throw-gl-errors, log-gl-errors annotations for all OpenGL functions --- basis/opengl/opengl-docs.factor | 38 ++++++++++++++++++++-- basis/opengl/opengl.factor | 56 ++++++++++++++++++++++++++++----- 2 files changed, 85 insertions(+), 9 deletions(-) diff --git a/basis/opengl/opengl-docs.factor b/basis/opengl/opengl-docs.factor index 1e4112d5d4..79038a0fd9 100644 --- a/basis/opengl/opengl-docs.factor +++ b/basis/opengl/opengl-docs.factor @@ -1,5 +1,5 @@ USING: alien help.markup help.syntax io kernel math quotations -opengl.gl assocs vocabs.loader sequences accessors colors ; +opengl.gl assocs vocabs.loader sequences accessors colors words ; IN: opengl HELP: gl-color @@ -8,7 +8,35 @@ HELP: gl-color { $notes "See " { $link "colors" } "." } ; HELP: gl-error -{ $description "If the most recent OpenGL call resulted in an error, print the error to " { $link output-stream } "." } ; +{ $description "If the most recent OpenGL call resulted in an error, throw a " { $snippet "gl-error" } " instance reporting the error." } ; + +HELP: log-gl-error +{ $values { "function" word } } +{ $description "If the most recent OpenGL call resulted in an error, append it to the " { $link gl-error-log } "." } +{ $notes "Don't call this function directly. Call " { $link log-gl-errors } " to annotate every OpenGL function to automatically log errors." } ; + +HELP: gl-error-log +{ $var-description "A vector of OpenGL errors logged by " { $link log-gl-errors } ". Each log entry has the following tuple slots:" } +{ $list + { { $snippet "function" } " is the OpenGL function that raised the error." } + { { $snippet "error" } " is the OpenGL error code." } + { { $snippet "timestamp" } " is the time the error was logged." } +} +{ "The error log is emptied using the " { $link clear-gl-error-log } " word." } ; + +HELP: clear-gl-error-log +{ $description "Empties the OpenGL error log populated by " { $link log-gl-errors } "." } ; + +HELP: throw-gl-errors +{ $description "Annotate every OpenGL function to throw a " { $link gl-error } " if the function results in an error. Use " { $link reset-gl-functions } " to reverse this operation." } ; + +HELP: log-gl-errors +{ $description "Annotate every OpenGL function to log using " { $link log-gl-error } " if the function results in an error. Use " { $link reset-gl-functions } " to reverse this operation." } ; + +HELP: reset-gl-functions +{ $description "Removes any annotations from all OpenGL functions, such as those applied by " { $link throw-gl-errors } " or " { $link log-gl-errors } "." } ; + +{ throw-gl-errors gl-error log-gl-errors log-gl-error clear-gl-error-log reset-gl-functions } related-words HELP: do-enabled { $values { "what" integer } { "quot" quotation } } @@ -73,6 +101,12 @@ ARTICLE: "gl-utilities" "OpenGL utility words" $nl "The " { $vocab-link "opengl.gl" } " and " { $vocab-link "opengl.glu" } " vocabularies have the actual OpenGL bindings." { $subsection "opengl-low-level" } +"Error reporting:" +{ $subsection gl-error } +{ $subsection throw-gl-errors } +{ $subsection log-gl-errors } +{ $subsection clear-gl-error-log } +{ $subsection reset-gl-functions } "Wrappers:" { $subsection gl-color } { $subsection gl-translate } diff --git a/basis/opengl/opengl.factor b/basis/opengl/opengl.factor index bb5847e734..7884890ebf 100644 --- a/basis/opengl/opengl.factor +++ b/basis/opengl/opengl.factor @@ -2,11 +2,13 @@ ! Portions copyright (C) 2007 Eduardo Cavazos. ! Portions copyright (C) 2008 Joe Groff. ! See http://factorcode.org/license.txt for BSD license. -USING: alien alien.c-types continuations kernel libc math macros -namespaces math.vectors math.parser opengl.gl combinators -combinators.smart arrays sequences splitting words byte-arrays assocs +USING: alien alien.c-types ascii calendar combinators.short-circuit +continuations kernel libc math macros namespaces math.vectors +math.parser opengl.gl combinators combinators.smart arrays +sequences splitting words byte-arrays assocs vocabs colors colors.constants accessors generalizations locals fry -specialized-arrays.float specialized-arrays.uint ; +specialized-arrays.float specialized-arrays.uint +tools.annotations tools.annotations.private compiler.units ; IN: opengl : gl-color ( color -- ) >rgba-components glColor4d ; inline @@ -30,10 +32,50 @@ IN: opengl TUPLE: gl-error code string ; +TUPLE: gl-error-log + { function word initial: t } + { error gl-error } + { timestamp timestamp } ; + +gl-error-log [ V{ } clone ] initialize + +: ( code -- gl-error ) + dup error>string \ gl-error boa ; inline + +: ( function code -- gl-error-log ) + now gl-error-log boa ; + +: gl-error-code ( -- code/f ) + glGetError dup 0 = [ drop f ] when ; inline + : gl-error ( -- ) - glGetError dup 0 = [ drop ] [ - dup error>string \ gl-error boa throw - ] if ; + gl-error-code [ throw ] [ ] if* ; + +: log-gl-error ( function -- ) + gl-error-code [ gl-error-log get push ] [ drop ] if* ; + +: gl-function? ( word -- ? ) + name>> { [ "glGetError" = not ] [ "gl" head? ] [ third LETTER? ] } 1&& ; + +: gl-functions ( -- words ) + "opengl.gl" vocab words [ gl-function? ] filter ; + +: annotate-gl-functions ( quot -- ) + [ + [ gl-functions ] dip [ [ dup ] dip curry (annotate) ] curry each + ] with-compilation-unit ; + +: reset-gl-functions ( -- ) + [ gl-functions [ (reset) ] each ] with-compilation-unit ; + +: clear-gl-error-log ( -- ) + V{ } clone gl-error-log set ; + +: throw-gl-errors ( -- ) + [ drop '[ @ gl-error ] ] annotate-gl-functions ; + +: log-gl-errors ( -- ) + [ '[ @ _ log-gl-error ] ] annotate-gl-functions ; : do-enabled ( what quot -- ) over glEnable dip glDisable ; inline From c860a3b1e6b2ad02a8f01fe29aa89fe9c93d1551 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 14 Jul 2009 12:06:55 -0500 Subject: [PATCH 34/96] compiler.cfg: update unit tests for compiler.cfg.comparisons --- .../compiler/cfg/branch-folding/branch-folding-tests.factor | 5 +++-- basis/compiler/cfg/linear-scan/linear-scan-tests.factor | 1 + .../cfg/phi-elimination/phi-elimination-tests.factor | 5 +++-- .../cfg/value-numbering/value-numbering-tests.factor | 6 +++--- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/basis/compiler/cfg/branch-folding/branch-folding-tests.factor b/basis/compiler/cfg/branch-folding/branch-folding-tests.factor index 8ae1f6b75b..1d43ea0af3 100644 --- a/basis/compiler/cfg/branch-folding/branch-folding-tests.factor +++ b/basis/compiler/cfg/branch-folding/branch-folding-tests.factor @@ -2,8 +2,9 @@ IN: compiler.cfg.branch-folding.tests USING: compiler.cfg.branch-folding compiler.cfg.instructions compiler.cfg compiler.cfg.registers compiler.cfg.debugger arrays compiler.cfg.phi-elimination compiler.cfg.dce -compiler.cfg.predecessors kernel accessors assocs -sequences classes namespaces tools.test cpu.architecture ; +compiler.cfg.predecessors compiler.cfg.comparisons +kernel accessors assocs sequences classes namespaces +tools.test cpu.architecture ; V{ T{ ##branch } } 0 test-bb diff --git a/basis/compiler/cfg/linear-scan/linear-scan-tests.factor b/basis/compiler/cfg/linear-scan/linear-scan-tests.factor index 20f8570f84..fd95a3e09c 100644 --- a/basis/compiler/cfg/linear-scan/linear-scan-tests.factor +++ b/basis/compiler/cfg/linear-scan/linear-scan-tests.factor @@ -12,6 +12,7 @@ compiler.cfg.predecessors compiler.cfg.rpo compiler.cfg.linearization compiler.cfg.debugger +compiler.cfg.comparisons compiler.cfg.linear-scan compiler.cfg.linear-scan.numbering compiler.cfg.linear-scan.live-intervals diff --git a/basis/compiler/cfg/phi-elimination/phi-elimination-tests.factor b/basis/compiler/cfg/phi-elimination/phi-elimination-tests.factor index 2dd75df693..27458185a5 100644 --- a/basis/compiler/cfg/phi-elimination/phi-elimination-tests.factor +++ b/basis/compiler/cfg/phi-elimination/phi-elimination-tests.factor @@ -1,7 +1,8 @@ IN: compiler.cfg.phi-elimination.tests USING: compiler.cfg.instructions compiler.cfg compiler.cfg.registers -compiler.cfg.debugger compiler.cfg.phi-elimination kernel accessors -sequences classes namespaces tools.test cpu.architecture arrays ; +compiler.cfg.comparisons compiler.cfg.debugger +compiler.cfg.phi-elimination kernel accessors sequences classes +namespaces tools.test cpu.architecture arrays ; V{ T{ ##branch } } 0 test-bb diff --git a/basis/compiler/cfg/value-numbering/value-numbering-tests.factor b/basis/compiler/cfg/value-numbering/value-numbering-tests.factor index 5063273bf4..b4f8fa1c58 100644 --- a/basis/compiler/cfg/value-numbering/value-numbering-tests.factor +++ b/basis/compiler/cfg/value-numbering/value-numbering-tests.factor @@ -1,8 +1,8 @@ IN: compiler.cfg.value-numbering.tests USING: compiler.cfg.value-numbering compiler.cfg.instructions -compiler.cfg.registers compiler.cfg.debugger cpu.architecture -tools.test kernel math combinators.short-circuit accessors -sequences compiler.cfg vectors arrays ; +compiler.cfg.registers compiler.cfg.debugger compiler.cfg.comparisons +cpu.architecture tools.test kernel math combinators.short-circuit +accessors sequences compiler.cfg vectors arrays ; : trim-temps ( insns -- insns ) [ From bf54aebcc10f34fea063eedd15a8a515f9073284 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 14 Jul 2009 12:07:08 -0500 Subject: [PATCH 35/96] Fix QUALIFIED: docs. Reported by ex_rzr in #concatenative --- core/syntax/syntax-docs.factor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/syntax/syntax-docs.factor b/core/syntax/syntax-docs.factor index d408da4bc7..70905ceda9 100644 --- a/core/syntax/syntax-docs.factor +++ b/core/syntax/syntax-docs.factor @@ -447,7 +447,7 @@ HELP: USING: HELP: QUALIFIED: { $syntax "QUALIFIED: vocab" } { $description "Adds the vocabulary's words, prefixed with the vocabulary name, to the search path." } -{ $notes "If adding the vocabulary introduces ambiguity, the vocabulary will take precedence when resolving any ambiguous names. This is a rare case; for example, suppose a vocabulary " { $snippet "fish" } " defines a word named " { $snippet "go:fishing" } ", and a vocabulary named " { $snippet "go" } " defines a word named " { $snippet "finishing" } ". Then, the following will call the latter word:" +{ $notes "If adding the vocabulary introduces ambiguity, the vocabulary will take precedence when resolving any ambiguous names. This is a rare case; for example, suppose a vocabulary " { $snippet "fish" } " defines a word named " { $snippet "go:fishing" } ", and a vocabulary named " { $snippet "go" } " defines a word named " { $snippet "fishing" } ". Then, the following will call the latter word:" { $code "USE: fish" "QUALIFIED: go" From d1eea090b6d0b665b443636298bc3ae9b1e4215a Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 14 Jul 2009 13:25:07 -0500 Subject: [PATCH 36/96] compiler.cfg.value-numbering: add some unit tests --- .../value-numbering-tests.factor | 582 ++++++++++++++++-- 1 file changed, 524 insertions(+), 58 deletions(-) diff --git a/basis/compiler/cfg/value-numbering/value-numbering-tests.factor b/basis/compiler/cfg/value-numbering/value-numbering-tests.factor index b4f8fa1c58..0166f8f834 100644 --- a/basis/compiler/cfg/value-numbering/value-numbering-tests.factor +++ b/basis/compiler/cfg/value-numbering/value-numbering-tests.factor @@ -17,6 +17,7 @@ accessors sequences compiler.cfg vectors arrays ; { } init-value-numbering value-numbering-step ; +! Copy propagation [ { T{ ##peek f V int-regs 45 D 1 } @@ -31,58 +32,7 @@ accessors sequences compiler.cfg vectors arrays ; } test-value-numbering ] unit-test -[ - { - T{ ##load-immediate f V int-regs 2 8 } - T{ ##peek f V int-regs 3 D 0 } - T{ ##slot-imm f V int-regs 4 V int-regs 3 1 3 } - T{ ##replace f V int-regs 4 D 0 } - } -] [ - { - T{ ##load-immediate f V int-regs 2 8 } - T{ ##peek f V int-regs 3 D 0 } - T{ ##slot-imm f V int-regs 4 V int-regs 3 1 3 } - T{ ##replace f V int-regs 4 D 0 } - } test-value-numbering -] unit-test - -[ t ] [ - { - T{ ##peek f V int-regs 1 D 0 } - T{ ##dispatch f V int-regs 1 V int-regs 2 } - } dup test-value-numbering = -] unit-test - -[ t ] [ - { - T{ ##peek f V int-regs 16 D 0 } - T{ ##peek f V int-regs 17 D -1 } - T{ ##sar-imm f V int-regs 18 V int-regs 17 3 } - T{ ##add-imm f V int-regs 19 V int-regs 16 13 } - T{ ##add f V int-regs 21 V int-regs 18 V int-regs 19 } - T{ ##alien-unsigned-1 f V int-regs 22 V int-regs 21 } - T{ ##shl-imm f V int-regs 23 V int-regs 22 3 } - T{ ##replace f V int-regs 23 D 0 } - } dup test-value-numbering = -] unit-test - -[ - { - T{ ##peek f V int-regs 1 D 0 } - T{ ##shl-imm f V int-regs 2 V int-regs 1 3 } - T{ ##shr-imm f V int-regs 3 V int-regs 2 3 } - T{ ##replace f V int-regs 1 D 0 } - } -] [ - { - T{ ##peek f V int-regs 1 D 0 } - T{ ##mul-imm f V int-regs 2 V int-regs 1 8 } - T{ ##shr-imm f V int-regs 3 V int-regs 2 3 } - T{ ##replace f V int-regs 3 D 0 } - } test-value-numbering -] unit-test - +! Compare propagation [ { T{ ##load-reference f V int-regs 1 + } @@ -157,15 +107,531 @@ accessors sequences compiler.cfg vectors arrays ; } test-value-numbering trim-temps ] unit-test +! Immediate operand conversion [ { - T{ ##copy f V int-regs 48 V int-regs 45 } - T{ ##compare-imm-branch f V int-regs 45 7 cc/= } + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##add-imm f V int-regs 2 V int-regs 0 100 } } ] [ - { V int-regs 45 } init-value-numbering { - T{ ##copy f V int-regs 48 V int-regs 45 } - T{ ##compare-imm-branch f V int-regs 48 7 cc/= } - } value-numbering-step + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##add f V int-regs 2 V int-regs 0 V int-regs 1 } + } test-value-numbering ] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##add-imm f V int-regs 2 V int-regs 0 100 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##add f V int-regs 2 V int-regs 1 V int-regs 0 } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##sub-imm f V int-regs 2 V int-regs 0 100 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##sub f V int-regs 2 V int-regs 0 V int-regs 1 } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##mul-imm f V int-regs 2 V int-regs 0 100 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##mul f V int-regs 2 V int-regs 0 V int-regs 1 } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##mul-imm f V int-regs 2 V int-regs 0 100 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##mul f V int-regs 2 V int-regs 1 V int-regs 0 } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 1 D 0 } + T{ ##shl-imm f V int-regs 2 V int-regs 1 3 } + } +] [ + { + T{ ##peek f V int-regs 1 D 0 } + T{ ##mul-imm f V int-regs 2 V int-regs 1 8 } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##and-imm f V int-regs 2 V int-regs 0 100 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##and f V int-regs 2 V int-regs 0 V int-regs 1 } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##and-imm f V int-regs 2 V int-regs 0 100 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##and f V int-regs 2 V int-regs 1 V int-regs 0 } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##or-imm f V int-regs 2 V int-regs 0 100 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##or f V int-regs 2 V int-regs 0 V int-regs 1 } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##or-imm f V int-regs 2 V int-regs 0 100 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##or f V int-regs 2 V int-regs 1 V int-regs 0 } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##xor-imm f V int-regs 2 V int-regs 0 100 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##xor f V int-regs 2 V int-regs 0 V int-regs 1 } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##xor-imm f V int-regs 2 V int-regs 0 100 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##xor f V int-regs 2 V int-regs 1 V int-regs 0 } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##compare-imm f V int-regs 2 V int-regs 0 100 cc<= } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##compare f V int-regs 2 V int-regs 0 V int-regs 1 cc<= } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##compare-imm f V int-regs 2 V int-regs 0 100 cc>= } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##compare f V int-regs 2 V int-regs 1 V int-regs 0 cc<= } + } test-value-numbering trim-temps +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##compare-imm-branch f V int-regs 0 100 cc<= } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##compare-branch f V int-regs 0 V int-regs 1 cc<= } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##compare-imm-branch f V int-regs 0 100 cc>= } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##compare-branch f V int-regs 1 V int-regs 0 cc<= } + } test-value-numbering trim-temps +] unit-test + +! Reassociation +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##add-imm f V int-regs 2 V int-regs 0 100 } + T{ ##load-immediate f V int-regs 3 50 } + T{ ##add-imm f V int-regs 4 V int-regs 0 150 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##add f V int-regs 2 V int-regs 0 V int-regs 1 } + T{ ##load-immediate f V int-regs 3 50 } + T{ ##add f V int-regs 4 V int-regs 2 V int-regs 3 } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##add-imm f V int-regs 2 V int-regs 0 100 } + T{ ##load-immediate f V int-regs 3 50 } + T{ ##add-imm f V int-regs 4 V int-regs 0 150 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##add f V int-regs 2 V int-regs 1 V int-regs 0 } + T{ ##load-immediate f V int-regs 3 50 } + T{ ##add f V int-regs 4 V int-regs 3 V int-regs 2 } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##add-imm f V int-regs 2 V int-regs 0 100 } + T{ ##load-immediate f V int-regs 3 50 } + T{ ##add-imm f V int-regs 4 V int-regs 0 50 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##add f V int-regs 2 V int-regs 0 V int-regs 1 } + T{ ##load-immediate f V int-regs 3 50 } + T{ ##sub f V int-regs 4 V int-regs 2 V int-regs 3 } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##sub-imm f V int-regs 2 V int-regs 0 100 } + T{ ##load-immediate f V int-regs 3 50 } + T{ ##sub-imm f V int-regs 4 V int-regs 0 150 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##sub f V int-regs 2 V int-regs 0 V int-regs 1 } + T{ ##load-immediate f V int-regs 3 50 } + T{ ##sub f V int-regs 4 V int-regs 2 V int-regs 3 } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##mul-imm f V int-regs 2 V int-regs 0 100 } + T{ ##load-immediate f V int-regs 3 50 } + T{ ##mul-imm f V int-regs 4 V int-regs 0 5000 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##mul f V int-regs 2 V int-regs 0 V int-regs 1 } + T{ ##load-immediate f V int-regs 3 50 } + T{ ##mul f V int-regs 4 V int-regs 2 V int-regs 3 } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##mul-imm f V int-regs 2 V int-regs 0 100 } + T{ ##load-immediate f V int-regs 3 50 } + T{ ##mul-imm f V int-regs 4 V int-regs 0 5000 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##mul f V int-regs 2 V int-regs 1 V int-regs 0 } + T{ ##load-immediate f V int-regs 3 50 } + T{ ##mul f V int-regs 4 V int-regs 3 V int-regs 2 } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##and-imm f V int-regs 2 V int-regs 0 100 } + T{ ##load-immediate f V int-regs 3 50 } + T{ ##and-imm f V int-regs 4 V int-regs 0 32 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##and f V int-regs 2 V int-regs 0 V int-regs 1 } + T{ ##load-immediate f V int-regs 3 50 } + T{ ##and f V int-regs 4 V int-regs 2 V int-regs 3 } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##and-imm f V int-regs 2 V int-regs 0 100 } + T{ ##load-immediate f V int-regs 3 50 } + T{ ##and-imm f V int-regs 4 V int-regs 0 32 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##and f V int-regs 2 V int-regs 1 V int-regs 0 } + T{ ##load-immediate f V int-regs 3 50 } + T{ ##and f V int-regs 4 V int-regs 3 V int-regs 2 } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##or-imm f V int-regs 2 V int-regs 0 100 } + T{ ##load-immediate f V int-regs 3 50 } + T{ ##or-imm f V int-regs 4 V int-regs 0 118 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##or f V int-regs 2 V int-regs 0 V int-regs 1 } + T{ ##load-immediate f V int-regs 3 50 } + T{ ##or f V int-regs 4 V int-regs 2 V int-regs 3 } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##or-imm f V int-regs 2 V int-regs 0 100 } + T{ ##load-immediate f V int-regs 3 50 } + T{ ##or-imm f V int-regs 4 V int-regs 0 118 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##or f V int-regs 2 V int-regs 1 V int-regs 0 } + T{ ##load-immediate f V int-regs 3 50 } + T{ ##or f V int-regs 4 V int-regs 3 V int-regs 2 } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##xor-imm f V int-regs 2 V int-regs 0 100 } + T{ ##load-immediate f V int-regs 3 50 } + T{ ##xor-imm f V int-regs 4 V int-regs 0 86 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##xor f V int-regs 2 V int-regs 0 V int-regs 1 } + T{ ##load-immediate f V int-regs 3 50 } + T{ ##xor f V int-regs 4 V int-regs 2 V int-regs 3 } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##xor-imm f V int-regs 2 V int-regs 0 100 } + T{ ##load-immediate f V int-regs 3 50 } + T{ ##xor-imm f V int-regs 4 V int-regs 0 86 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 100 } + T{ ##xor f V int-regs 2 V int-regs 1 V int-regs 0 } + T{ ##load-immediate f V int-regs 3 50 } + T{ ##xor f V int-regs 4 V int-regs 3 V int-regs 2 } + } test-value-numbering +] unit-test + +! Simplification +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##peek f V int-regs 1 D 1 } + T{ ##sub f V int-regs 2 V int-regs 1 V int-regs 1 } + T{ ##add f V int-regs 3 V int-regs 0 V int-regs 2 } + T{ ##replace f V int-regs 0 D 0 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##peek f V int-regs 1 D 1 } + T{ ##sub f V int-regs 2 V int-regs 1 V int-regs 1 } + T{ ##add f V int-regs 3 V int-regs 0 V int-regs 2 } + T{ ##replace f V int-regs 3 D 0 } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##peek f V int-regs 1 D 1 } + T{ ##sub f V int-regs 2 V int-regs 1 V int-regs 1 } + T{ ##sub f V int-regs 3 V int-regs 0 V int-regs 2 } + T{ ##replace f V int-regs 0 D 0 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##peek f V int-regs 1 D 1 } + T{ ##sub f V int-regs 2 V int-regs 1 V int-regs 1 } + T{ ##sub f V int-regs 3 V int-regs 0 V int-regs 2 } + T{ ##replace f V int-regs 3 D 0 } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##peek f V int-regs 1 D 1 } + T{ ##sub f V int-regs 2 V int-regs 1 V int-regs 1 } + T{ ##or f V int-regs 3 V int-regs 0 V int-regs 2 } + T{ ##replace f V int-regs 0 D 0 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##peek f V int-regs 1 D 1 } + T{ ##sub f V int-regs 2 V int-regs 1 V int-regs 1 } + T{ ##or f V int-regs 3 V int-regs 0 V int-regs 2 } + T{ ##replace f V int-regs 3 D 0 } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##peek f V int-regs 1 D 1 } + T{ ##sub f V int-regs 2 V int-regs 1 V int-regs 1 } + T{ ##xor f V int-regs 3 V int-regs 0 V int-regs 2 } + T{ ##replace f V int-regs 0 D 0 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##peek f V int-regs 1 D 1 } + T{ ##sub f V int-regs 2 V int-regs 1 V int-regs 1 } + T{ ##xor f V int-regs 3 V int-regs 0 V int-regs 2 } + T{ ##replace f V int-regs 3 D 0 } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 1 } + T{ ##mul f V int-regs 2 V int-regs 0 V int-regs 1 } + T{ ##replace f V int-regs 0 D 0 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 1 } + T{ ##mul f V int-regs 2 V int-regs 0 V int-regs 1 } + T{ ##replace f V int-regs 2 D 0 } + } test-value-numbering +] unit-test \ No newline at end of file From bb06facb0188b9f335b852a705d2ea6424561b0e Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Tue, 14 Jul 2009 14:16:39 -0500 Subject: [PATCH 37/96] new is inlined in the propagation pass when the class is known --- .../propagation/known-words/known-words.factor | 14 +++++++++++++- .../tree/propagation/propagation-tests.factor | 13 +++++++++++++ basis/stack-checker/transforms/transforms.factor | 9 --------- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/basis/compiler/tree/propagation/known-words/known-words.factor b/basis/compiler/tree/propagation/known-words/known-words.factor index b3c8026bc4..aec61608f1 100644 --- a/basis/compiler/tree/propagation/known-words/known-words.factor +++ b/basis/compiler/tree/propagation/known-words/known-words.factor @@ -6,7 +6,7 @@ math.parser math.order layouts words sequences sequences.private arrays assocs classes classes.algebra combinators generic.math splitting fry locals classes.tuple alien.accessors classes.tuple.private slots.private definitions strings.private -vectors hashtables generic +vectors hashtables generic quotations stack-checker.state compiler.tree.comparisons compiler.tree.propagation.info @@ -360,3 +360,15 @@ generic-comparison-ops [ [ swap equal? ] f ? ] [ drop f ] if ] "custom-inlining" set-word-prop + +: inline-new ( class -- quot/f ) + dup tuple-class? [ + dup inlined-dependency depends-on + [ all-slots [ initial>> literalize ] map ] + [ tuple-layout '[ _ ] ] + bi append [ drop ] prepend >quotation + ] [ drop f ] if ; + +\ new [ + in-d>> first value-info literal>> inline-new +] "custom-inlining" set-word-prop diff --git a/basis/compiler/tree/propagation/propagation-tests.factor b/basis/compiler/tree/propagation/propagation-tests.factor index 32c9f4ed0b..108afad296 100644 --- a/basis/compiler/tree/propagation/propagation-tests.factor +++ b/basis/compiler/tree/propagation/propagation-tests.factor @@ -704,3 +704,16 @@ TUPLE: circle me ; ! Joe found an oversight [ V{ integer } ] [ [ >integer ] final-classes ] unit-test + +TUPLE: foo bar ; + +[ t ] [ [ foo new ] { new } inlined? ] unit-test + +GENERIC: whatever ( x -- y ) +M: number whatever drop foo ; + +[ t ] [ [ 1 whatever new ] { new } inlined? ] unit-test + +: that-thing ( -- class ) foo ; + +[ f ] [ [ that-thing new ] { new } inlined? ] unit-test diff --git a/basis/stack-checker/transforms/transforms.factor b/basis/stack-checker/transforms/transforms.factor index 017594a4eb..9d1ab1332a 100755 --- a/basis/stack-checker/transforms/transforms.factor +++ b/basis/stack-checker/transforms/transforms.factor @@ -108,15 +108,6 @@ IN: stack-checker.transforms \ boa t "no-compile" set-word-prop -\ new [ - dup tuple-class? [ - dup inlined-dependency depends-on - [ all-slots [ initial>> literalize ] map ] - [ tuple-layout '[ _ ] ] - bi append - ] [ drop f ] if -] 1 define-transform - ! Fast at for integer maps CONSTANT: lookup-table-at-max 256 From 2ace87370e9e37948526be7476b6a2499fc1de33 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 14 Jul 2009 16:05:25 -0500 Subject: [PATCH 38/96] compiler.cfg.value-numbering: more optimizations --- .../value-numbering/rewrite/rewrite.factor | 236 +++++++++++------- .../value-numbering/simplify/simplify.factor | 61 ++++- .../value-numbering-tests.factor | 201 +++++++++++++-- .../value-numbering/value-numbering.factor | 3 +- basis/compiler/tests/codegen.factor | 4 +- 5 files changed, 393 insertions(+), 112 deletions(-) diff --git a/basis/compiler/cfg/value-numbering/rewrite/rewrite.factor b/basis/compiler/cfg/value-numbering/rewrite/rewrite.factor index bc8fc50547..a0e8dd6146 100755 --- a/basis/compiler/cfg/value-numbering/rewrite/rewrite.factor +++ b/basis/compiler/cfg/value-numbering/rewrite/rewrite.factor @@ -2,7 +2,7 @@ ! See http://factorcode.org/license.txt for BSD license. USING: accessors locals combinators combinators.short-circuit arrays fry kernel layouts math namespaces sequences cpu.architecture -math.bitwise +math.bitwise classes compiler.cfg.hats compiler.cfg.comparisons compiler.cfg.instructions @@ -11,9 +11,15 @@ compiler.cfg.value-numbering.graph compiler.cfg.value-numbering.simplify ; IN: compiler.cfg.value-numbering.rewrite -GENERIC: rewrite ( insn -- insn' ) +! Outputs f to mean no change -M: insn rewrite ; +GENERIC: rewrite* ( insn -- insn/f ) + +: rewrite ( insn -- insn' ) + dup [ number-values ] [ rewrite* ] bi + [ rewrite ] [ ] ?if ; + +M: insn rewrite* drop f ; : ##branch-t? ( insn -- ? ) dup ##compare-imm-branch? [ @@ -61,7 +67,7 @@ M: insn rewrite ; [ cc>> ] tri ; inline -GENERIC: rewrite-tagged-comparison ( insn -- insn' ) +GENERIC: rewrite-tagged-comparison ( insn -- insn/f ) M: ##compare-imm-branch rewrite-tagged-comparison (rewrite-tagged-comparison) \ ##compare-imm-branch new-insn ; @@ -70,11 +76,12 @@ M: ##compare-imm rewrite-tagged-comparison [ dst>> ] [ (rewrite-tagged-comparison) ] bi i \ ##compare-imm new-insn ; -M: ##compare-imm-branch rewrite - dup rewrite-boolean-comparison? [ rewrite-boolean-comparison ] when - dup ##compare-imm-branch? [ - dup rewrite-tagged-comparison? [ rewrite-tagged-comparison ] when - ] when ; +M: ##compare-imm-branch rewrite* + { + { [ dup rewrite-boolean-comparison? ] [ rewrite-boolean-comparison ] } + { [ dup rewrite-tagged-comparison? ] [ rewrite-tagged-comparison ] } + [ drop f ] + } cond ; :: >compare-imm ( insn swap? -- insn' ) insn dst>> @@ -89,12 +96,12 @@ M: ##compare-imm-branch rewrite [ value>> small-enough? ] } 1&& ; -M: ##compare rewrite +M: ##compare rewrite* dup [ src1>> ] [ src2>> ] bi [ vreg-small-constant? ] bi@ 2array { { { f t } [ f >compare-imm ] } { { t f } [ t >compare-imm ] } - [ drop ] + [ 2drop f ] } case ; :: >compare-imm-branch ( insn swap? -- insn' ) @@ -103,12 +110,12 @@ M: ##compare rewrite insn cc>> swap? [ swap-cc ] when \ ##compare-imm-branch new-insn ; inline -M: ##compare-branch rewrite +M: ##compare-branch rewrite* dup [ src1>> ] [ src2>> ] bi [ vreg-small-constant? ] bi@ 2array { { { f t } [ f >compare-imm-branch ] } { { t f } [ t >compare-imm-branch ] } - [ drop ] + [ 2drop f ] } case ; : rewrite-redundant-comparison? ( insn -- ? ) @@ -126,103 +133,158 @@ M: ##compare-branch rewrite } case swap cc= eq? [ [ negate-cc ] change-cc ] when ; -M: ##compare-imm rewrite - dup rewrite-redundant-comparison? [ - rewrite-redundant-comparison - dup number-values rewrite - ] when - dup ##compare-imm? [ - dup rewrite-tagged-comparison? [ - rewrite-tagged-comparison - dup number-values rewrite - ] when - ] when ; +M: ##compare-imm rewrite* + { + { [ dup rewrite-redundant-comparison? ] [ rewrite-redundant-comparison ] } + { [ dup rewrite-tagged-comparison? ] [ rewrite-tagged-comparison ] } + [ drop f ] + } cond ; + +: constant-fold? ( insn -- ? ) + src1>> vreg>expr constant-expr? ; inline + +GENERIC: constant-fold* ( x y insn -- z ) + +M: ##add-imm constant-fold* drop + ; +M: ##sub-imm constant-fold* drop - ; +M: ##mul-imm constant-fold* drop * ; +M: ##and-imm constant-fold* drop bitand ; +M: ##or-imm constant-fold* drop bitor ; +M: ##xor-imm constant-fold* drop bitxor ; +M: ##shr-imm constant-fold* drop [ cell-bits 2^ wrap ] dip neg shift ; +M: ##sar-imm constant-fold* drop neg shift ; +M: ##shl-imm constant-fold* drop shift ; : constant-fold ( insn -- insn' ) - dup dst>> vreg>expr dup constant-expr? [ - [ dst>> ] [ value>> ] bi* \ ##load-immediate new-insn - dup number-values - ] [ - drop - ] if ; + [ dst>> ] + [ [ src1>> vreg>constant ] [ src2>> ] [ ] tri constant-fold* ] bi + \ ##load-immediate new-insn ; inline -: (new-imm-insn) ( insn dst src1 n op -- new-insn/insn ) - [ cell-bits bits ] dip over small-enough? [ - new-insn dup number-values nip - ] [ - 2drop 2drop - ] if constant-fold ; inline +:: new-imm-insn ( insn dst src1 src2 op -- new-insn/insn ) + src2 small-enough? [ dst src1 src2 op new-insn ] [ insn ] if ; inline -: new-imm-insn ( insn dst src n op -- n' op' ) - 2dup [ sgn ] dip 2array - { - { { -1 ##add-imm } [ drop neg \ ##sub-imm (new-imm-insn) ] } - { { -1 ##sub-imm } [ drop neg \ ##add-imm (new-imm-insn) ] } - [ drop (new-imm-insn) ] - } case ; inline +: reassociate? ( insn -- ? ) + [ src1>> vreg>expr op>> ] [ class ] bi = ; inline -: combine-imm? ( insn op -- ? ) - [ src1>> vreg>expr op>> ] dip = ; - -: (combine-imm) ( insn quot op -- insn ) +: reassociate ( insn op -- insn ) [ { [ ] [ dst>> ] [ src1>> vreg>expr [ in1>> vn>vreg ] [ in2>> vn>constant ] bi ] [ src2>> ] - } cleave - ] [ call ] [ ] tri* new-imm-insn ; inline + [ ] + } cleave constant-fold* + ] dip new-imm-insn ; inline -:: combine-imm ( insn quot op -- insn ) - insn op combine-imm? [ - insn quot op (combine-imm) - ] [ - insn - ] if ; inline - -M: ##add-imm rewrite +M: ##add-imm rewrite* { - { [ dup \ ##add-imm combine-imm? ] [ [ + ] \ ##add-imm (combine-imm) ] } - { [ dup \ ##sub-imm combine-imm? ] [ [ - ] \ ##sub-imm (combine-imm) ] } - [ ] + { [ dup constant-fold? ] [ constant-fold ] } + { [ dup reassociate? ] [ \ ##add-imm reassociate ] } + [ drop f ] } cond ; -M: ##sub-imm rewrite +: sub-imm>add-imm ( insn -- insn' ) + dup [ dst>> ] [ src1>> ] [ src2>> neg ] tri dup small-enough? + [ \ ##add-imm new-insn nip ] [ 2drop 2drop f ] if ; + +M: ##sub-imm rewrite* { - { [ dup \ ##add-imm combine-imm? ] [ [ - ] \ ##add-imm (combine-imm) ] } - { [ dup \ ##sub-imm combine-imm? ] [ [ + ] \ ##sub-imm (combine-imm) ] } - [ ] + { [ dup constant-fold? ] [ constant-fold ] } + [ sub-imm>add-imm ] } cond ; -M: ##mul-imm rewrite - dup src2>> dup power-of-2? [ - [ [ dst>> ] [ src1>> ] bi ] [ log2 ] bi* \ ##shl-imm new-insn - dup number-values - ] [ - drop [ * ] \ ##mul-imm combine-imm - ] if ; +: strength-reduce-mul ( insn -- insn' ) + [ [ dst>> ] [ src1>> ] bi ] [ src2>> log2 ] bi \ ##shl-imm new-insn ; -M: ##and-imm rewrite [ bitand ] \ ##and-imm combine-imm ; +: strength-reduce-mul? ( insn -- ? ) + src2>> power-of-2? ; -M: ##or-imm rewrite [ bitor ] \ ##or-imm combine-imm ; +M: ##mul-imm rewrite* + { + { [ dup constant-fold? ] [ constant-fold ] } + { [ dup strength-reduce-mul? ] [ strength-reduce-mul ] } + { [ dup reassociate? ] [ \ ##mul-imm reassociate ] } + [ drop f ] + } cond ; -M: ##xor-imm rewrite [ bitxor ] \ ##xor-imm combine-imm ; +M: ##and-imm rewrite* + { + { [ dup constant-fold? ] [ constant-fold ] } + { [ dup reassociate? ] [ \ ##and-imm reassociate ] } + [ drop f ] + } cond ; -: new-arithmetic ( obj op -- ) - [ - [ dst>> ] - [ src1>> ] - [ src2>> vreg>constant ] tri - ] dip new-insn dup number-values ; inline +M: ##or-imm rewrite* + { + { [ dup constant-fold? ] [ constant-fold ] } + { [ dup reassociate? ] [ \ ##or-imm reassociate ] } + [ drop f ] + } cond ; + +M: ##xor-imm rewrite* + { + { [ dup constant-fold? ] [ constant-fold ] } + { [ dup reassociate? ] [ \ ##xor-imm reassociate ] } + [ drop f ] + } cond ; + +M: ##shl-imm rewrite* + { + { [ dup constant-fold? ] [ constant-fold ] } + [ drop f ] + } cond ; + +M: ##shr-imm rewrite* + { + { [ dup constant-fold? ] [ constant-fold ] } + [ drop f ] + } cond ; + +M: ##sar-imm rewrite* + { + { [ dup constant-fold? ] [ constant-fold ] } + [ drop f ] + } cond ; + +:: insn>imm-insn ( insn op swap? -- ) + insn + insn dst>> + insn src1>> + insn src2>> swap? [ swap ] when vreg>constant + op new-imm-insn ; inline : rewrite-arithmetic ( insn op -- ? ) - over src2>> vreg-small-constant? [ - new-arithmetic constant-fold - ] [ - drop - ] if ; inline + { + { [ over src2>> vreg-small-constant? ] [ f insn>imm-insn ] } + [ 2drop f ] + } cond ; inline -M: ##add rewrite \ ##add-imm rewrite-arithmetic ; +: rewrite-arithmetic-commutative ( insn op -- ? ) + { + { [ over src2>> vreg-small-constant? ] [ f insn>imm-insn ] } + { [ over src1>> vreg-small-constant? ] [ t insn>imm-insn ] } + [ 2drop f ] + } cond ; inline -M: ##sub rewrite \ ##sub-imm rewrite-arithmetic ; +M: ##add rewrite* \ ##add-imm rewrite-arithmetic-commutative ; + +: subtraction-identity? ( insn -- ? ) + [ src1>> ] [ src2>> ] bi [ vreg>vn ] bi@ eq? ; + +: rewrite-subtraction-identity ( insn -- insn' ) + dst>> 0 \ ##load-immediate new-insn ; + +M: ##sub rewrite* + { + { [ dup subtraction-identity? ] [ rewrite-subtraction-identity ] } + [ \ ##sub-imm rewrite-arithmetic ] + } cond ; + +M: ##mul rewrite* \ ##mul-imm rewrite-arithmetic-commutative ; + +M: ##and rewrite* \ ##and-imm rewrite-arithmetic-commutative ; + +M: ##or rewrite* \ ##or-imm rewrite-arithmetic-commutative ; + +M: ##xor rewrite* \ ##xor-imm rewrite-arithmetic-commutative ; diff --git a/basis/compiler/cfg/value-numbering/simplify/simplify.factor b/basis/compiler/cfg/value-numbering/simplify/simplify.factor index b7526528e4..a956498af4 100644 --- a/basis/compiler/cfg/value-numbering/simplify/simplify.factor +++ b/basis/compiler/cfg/value-numbering/simplify/simplify.factor @@ -32,6 +32,8 @@ M: unary-expr simplify* : expr-zero? ( expr -- ? ) T{ constant-expr f f 0 } = ; inline +: expr-one? ( expr -- ? ) T{ constant-expr f f 1 } = ; inline + : >binary-expr< ( expr -- in1 in2 ) [ in1>> vn>expr ] [ in2>> vn>expr ] bi ; inline @@ -44,18 +46,54 @@ M: unary-expr simplify* : simplify-sub ( expr -- vn/expr/f ) >binary-expr< { - { [ 2dup eq? ] [ 2drop T{ constant-expr f f 0 } ] } { [ dup expr-zero? ] [ drop ] } [ 2drop f ] } cond ; inline -: useless-shift? ( in1 in2 -- ? ) +: simplify-mul ( expr -- vn/expr/f ) + >binary-expr< { + { [ over expr-one? ] [ drop ] } + { [ dup expr-one? ] [ drop ] } + [ 2drop f ] + } cond ; inline + +: simplify-and ( expr -- vn/expr/f ) + >binary-expr< { + { [ 2dup eq? ] [ drop ] } + [ 2drop f ] + } cond ; inline + +: simplify-or ( expr -- vn/expr/f ) + >binary-expr< { + { [ 2dup eq? ] [ drop ] } + { [ over expr-zero? ] [ nip ] } + { [ dup expr-zero? ] [ drop ] } + [ 2drop f ] + } cond ; inline + +: simplify-xor ( expr -- vn/expr/f ) + >binary-expr< { + { [ over expr-zero? ] [ nip ] } + { [ dup expr-zero? ] [ drop ] } + [ 2drop f ] + } cond ; inline + +: useless-shr? ( in1 in2 -- ? ) over op>> \ ##shl-imm eq? [ [ in2>> ] [ expr>vn ] bi* = ] [ 2drop f ] if ; inline -: simplify-shift ( expr -- vn/expr/f ) - >binary-expr< - 2dup useless-shift? [ drop in1>> ] [ 2drop f ] if ; inline +: simplify-shr ( expr -- vn/expr/f ) + >binary-expr< { + { [ 2dup useless-shr? ] [ drop in1>> ] } + { [ dup expr-zero? ] [ drop ] } + [ 2drop f ] + } cond ; inline + +: simplify-shl ( expr -- vn/expr/f ) + >binary-expr< { + { [ dup expr-zero? ] [ drop ] } + [ 2drop f ] + } cond ; inline M: binary-expr simplify* dup op>> { @@ -63,8 +101,17 @@ M: binary-expr simplify* { \ ##add-imm [ simplify-add ] } { \ ##sub [ simplify-sub ] } { \ ##sub-imm [ simplify-sub ] } - { \ ##shr-imm [ simplify-shift ] } - { \ ##sar-imm [ simplify-shift ] } + { \ ##mul [ simplify-mul ] } + { \ ##mul-imm [ simplify-mul ] } + { \ ##and [ simplify-and ] } + { \ ##and-imm [ simplify-and ] } + { \ ##or [ simplify-or ] } + { \ ##or-imm [ simplify-or ] } + { \ ##xor [ simplify-xor ] } + { \ ##xor-imm [ simplify-xor ] } + { \ ##shr-imm [ simplify-shr ] } + { \ ##sar-imm [ simplify-shr ] } + { \ ##shl-imm [ simplify-shl ] } [ 2drop f ] } case ; diff --git a/basis/compiler/cfg/value-numbering/value-numbering-tests.factor b/basis/compiler/cfg/value-numbering/value-numbering-tests.factor index 0166f8f834..6ed0a74da5 100644 --- a/basis/compiler/cfg/value-numbering/value-numbering-tests.factor +++ b/basis/compiler/cfg/value-numbering/value-numbering-tests.factor @@ -2,7 +2,7 @@ IN: compiler.cfg.value-numbering.tests USING: compiler.cfg.value-numbering compiler.cfg.instructions compiler.cfg.registers compiler.cfg.debugger compiler.cfg.comparisons cpu.architecture tools.test kernel math combinators.short-circuit -accessors sequences compiler.cfg vectors arrays ; +accessors sequences compiler.cfg vectors arrays layouts ; : trim-temps ( insns -- insns ) [ @@ -140,7 +140,7 @@ accessors sequences compiler.cfg vectors arrays ; { T{ ##peek f V int-regs 0 D 0 } T{ ##load-immediate f V int-regs 1 100 } - T{ ##sub-imm f V int-regs 2 V int-regs 0 100 } + T{ ##add-imm f V int-regs 2 V int-regs 0 -100 } } ] [ { @@ -150,6 +150,18 @@ accessors sequences compiler.cfg vectors arrays ; } test-value-numbering ] unit-test +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 0 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##sub f V int-regs 1 V int-regs 0 V int-regs 0 } + } test-value-numbering +] unit-test + [ { T{ ##peek f V int-regs 0 D 0 } @@ -285,7 +297,7 @@ accessors sequences compiler.cfg vectors arrays ; T{ ##peek f V int-regs 0 D 0 } T{ ##load-immediate f V int-regs 1 100 } T{ ##compare f V int-regs 2 V int-regs 0 V int-regs 1 cc<= } - } test-value-numbering + } test-value-numbering trim-temps ] unit-test [ @@ -389,9 +401,9 @@ accessors sequences compiler.cfg vectors arrays ; { T{ ##peek f V int-regs 0 D 0 } T{ ##load-immediate f V int-regs 1 100 } - T{ ##sub-imm f V int-regs 2 V int-regs 0 100 } + T{ ##add-imm f V int-regs 2 V int-regs 0 -100 } T{ ##load-immediate f V int-regs 3 50 } - T{ ##sub-imm f V int-regs 4 V int-regs 0 150 } + T{ ##add-imm f V int-regs 4 V int-regs 0 -150 } } ] [ { @@ -552,8 +564,8 @@ accessors sequences compiler.cfg vectors arrays ; { T{ ##peek f V int-regs 0 D 0 } T{ ##peek f V int-regs 1 D 1 } - T{ ##sub f V int-regs 2 V int-regs 1 V int-regs 1 } - T{ ##add f V int-regs 3 V int-regs 0 V int-regs 2 } + T{ ##load-immediate f V int-regs 2 0 } + T{ ##add-imm f V int-regs 3 V int-regs 0 0 } T{ ##replace f V int-regs 0 D 0 } } ] [ @@ -570,8 +582,8 @@ accessors sequences compiler.cfg vectors arrays ; { T{ ##peek f V int-regs 0 D 0 } T{ ##peek f V int-regs 1 D 1 } - T{ ##sub f V int-regs 2 V int-regs 1 V int-regs 1 } - T{ ##sub f V int-regs 3 V int-regs 0 V int-regs 2 } + T{ ##load-immediate f V int-regs 2 0 } + T{ ##add-imm f V int-regs 3 V int-regs 0 0 } T{ ##replace f V int-regs 0 D 0 } } ] [ @@ -588,8 +600,8 @@ accessors sequences compiler.cfg vectors arrays ; { T{ ##peek f V int-regs 0 D 0 } T{ ##peek f V int-regs 1 D 1 } - T{ ##sub f V int-regs 2 V int-regs 1 V int-regs 1 } - T{ ##or f V int-regs 3 V int-regs 0 V int-regs 2 } + T{ ##load-immediate f V int-regs 2 0 } + T{ ##or-imm f V int-regs 3 V int-regs 0 0 } T{ ##replace f V int-regs 0 D 0 } } ] [ @@ -606,8 +618,8 @@ accessors sequences compiler.cfg vectors arrays ; { T{ ##peek f V int-regs 0 D 0 } T{ ##peek f V int-regs 1 D 1 } - T{ ##sub f V int-regs 2 V int-regs 1 V int-regs 1 } - T{ ##xor f V int-regs 3 V int-regs 0 V int-regs 2 } + T{ ##load-immediate f V int-regs 2 0 } + T{ ##xor-imm f V int-regs 3 V int-regs 0 0 } T{ ##replace f V int-regs 0 D 0 } } ] [ @@ -624,7 +636,7 @@ accessors sequences compiler.cfg vectors arrays ; { T{ ##peek f V int-regs 0 D 0 } T{ ##load-immediate f V int-regs 1 1 } - T{ ##mul f V int-regs 2 V int-regs 0 V int-regs 1 } + T{ ##shl-imm f V int-regs 2 V int-regs 0 0 } T{ ##replace f V int-regs 0 D 0 } } ] [ @@ -634,4 +646,163 @@ accessors sequences compiler.cfg vectors arrays ; T{ ##mul f V int-regs 2 V int-regs 0 V int-regs 1 } T{ ##replace f V int-regs 2 D 0 } } test-value-numbering -] unit-test \ No newline at end of file +] unit-test + +! Constant folding +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 1 } + T{ ##load-immediate f V int-regs 2 3 } + T{ ##load-immediate f V int-regs 3 4 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 1 } + T{ ##load-immediate f V int-regs 2 3 } + T{ ##add f V int-regs 3 V int-regs 1 V int-regs 2 } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 1 } + T{ ##load-immediate f V int-regs 2 3 } + T{ ##load-immediate f V int-regs 3 -2 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 1 } + T{ ##load-immediate f V int-regs 2 3 } + T{ ##sub f V int-regs 3 V int-regs 1 V int-regs 2 } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 2 } + T{ ##load-immediate f V int-regs 2 3 } + T{ ##load-immediate f V int-regs 3 6 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 2 } + T{ ##load-immediate f V int-regs 2 3 } + T{ ##mul f V int-regs 3 V int-regs 1 V int-regs 2 } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 2 } + T{ ##load-immediate f V int-regs 2 1 } + T{ ##load-immediate f V int-regs 3 0 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 2 } + T{ ##load-immediate f V int-regs 2 1 } + T{ ##and f V int-regs 3 V int-regs 1 V int-regs 2 } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 2 } + T{ ##load-immediate f V int-regs 2 1 } + T{ ##load-immediate f V int-regs 3 3 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 2 } + T{ ##load-immediate f V int-regs 2 1 } + T{ ##or f V int-regs 3 V int-regs 1 V int-regs 2 } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 2 } + T{ ##load-immediate f V int-regs 2 3 } + T{ ##load-immediate f V int-regs 3 1 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 2 } + T{ ##load-immediate f V int-regs 2 3 } + T{ ##xor f V int-regs 3 V int-regs 1 V int-regs 2 } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 1 } + T{ ##load-immediate f V int-regs 3 8 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 1 } + T{ ##shl-imm f V int-regs 3 V int-regs 1 3 } + } test-value-numbering +] unit-test + +cell 8 = [ + [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 -1 } + T{ ##load-immediate f V int-regs 3 HEX: ffffffffffff } + } + ] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 -1 } + T{ ##shr-imm f V int-regs 3 V int-regs 1 16 } + } test-value-numbering + ] unit-test +] when + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 -8 } + T{ ##load-immediate f V int-regs 3 -4 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 -8 } + T{ ##sar-imm f V int-regs 3 V int-regs 1 1 } + } test-value-numbering +] unit-test + +cell 8 = [ + [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 65536 } + T{ ##load-immediate f V int-regs 2 140737488355328 } + T{ ##add f V int-regs 3 V int-regs 0 V int-regs 2 } + } + ] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 65536 } + T{ ##shl-imm f V int-regs 2 V int-regs 1 31 } + T{ ##add f V int-regs 3 V int-regs 0 V int-regs 2 } + } test-value-numbering + ] unit-test +] when \ No newline at end of file diff --git a/basis/compiler/cfg/value-numbering/value-numbering.factor b/basis/compiler/cfg/value-numbering/value-numbering.factor index f0efa5dcca..9e6e058b52 100644 --- a/basis/compiler/cfg/value-numbering/value-numbering.factor +++ b/basis/compiler/cfg/value-numbering/value-numbering.factor @@ -29,8 +29,7 @@ IN: compiler.cfg.value-numbering ] with-variable ; : value-numbering-step ( insns -- insns' ) - [ [ number-values ] [ rewrite ] bi ] map - dup rename-uses ; + [ rewrite ] map dup rename-uses ; : value-numbering ( cfg -- cfg' ) [ init-value-numbering ] [ value-numbering-step ] local-optimization ; diff --git a/basis/compiler/tests/codegen.factor b/basis/compiler/tests/codegen.factor index 82da31b5fe..1463dbadb5 100644 --- a/basis/compiler/tests/codegen.factor +++ b/basis/compiler/tests/codegen.factor @@ -314,4 +314,6 @@ M: cucumber equal? "The cucumber has no equal" throw ; ! Regression from Doug's value numbering changes [ t ] [ 2 [ 1 swap fixnum< ] compile-call ] unit-test -[ 3 ] [ 2 [ 1 swap fixnum< [ 3 ] [ 4 ] if ] compile-call ] unit-test \ No newline at end of file +[ 3 ] [ 2 [ 1 swap fixnum< [ 3 ] [ 4 ] if ] compile-call ] unit-test + +[ 0 ] [ 101 [ dup fixnum-fast 1 fixnum+fast 20 fixnum-shift-fast 20 fixnum-shift-fast ] compile-call ] unit-test \ No newline at end of file From 03cd550b93fa0dea53fbdfb542ea07a68670d517 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 14 Jul 2009 16:11:14 -0500 Subject: [PATCH 39/96] Fix codegen test --- basis/compiler/tests/codegen.factor | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/basis/compiler/tests/codegen.factor b/basis/compiler/tests/codegen.factor index 1463dbadb5..8f7bc077b4 100644 --- a/basis/compiler/tests/codegen.factor +++ b/basis/compiler/tests/codegen.factor @@ -316,4 +316,6 @@ M: cucumber equal? "The cucumber has no equal" throw ; [ t ] [ 2 [ 1 swap fixnum< ] compile-call ] unit-test [ 3 ] [ 2 [ 1 swap fixnum< [ 3 ] [ 4 ] if ] compile-call ] unit-test -[ 0 ] [ 101 [ dup fixnum-fast 1 fixnum+fast 20 fixnum-shift-fast 20 fixnum-shift-fast ] compile-call ] unit-test \ No newline at end of file +cell 4 = [ + [ 0 ] [ 101 [ dup fixnum-fast 1 fixnum+fast 20 fixnum-shift-fast 20 fixnum-shift-fast ] compile-call ] unit-test +] when \ No newline at end of file From 73a22225417d6ae7f8bef438f92ffb57e335e66e Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 14 Jul 2009 19:17:12 -0500 Subject: [PATCH 40/96] compiler.cfg.value-numbering: branch folding --- basis/compiler/cfg/local/local.factor | 14 +- .../expressions/expressions.factor | 27 ++- .../value-numbering/rewrite/rewrite.factor | 145 +++++++----- .../value-numbering-tests.factor | 206 +++++++++++++++++- 4 files changed, 323 insertions(+), 69 deletions(-) diff --git a/basis/compiler/cfg/local/local.factor b/basis/compiler/cfg/local/local.factor index 5d78397998..2f5f5b18e3 100644 --- a/basis/compiler/cfg/local/local.factor +++ b/basis/compiler/cfg/local/local.factor @@ -1,10 +1,14 @@ ! Copyright (C) 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: fry accessors kernel assocs compiler.cfg.liveness compiler.cfg.rpo ; +USING: locals accessors kernel assocs namespaces +compiler.cfg compiler.cfg.liveness compiler.cfg.rpo ; IN: compiler.cfg.local -: optimize-basic-block ( bb init-quot insn-quot -- ) - [ '[ live-in keys @ ] ] [ '[ _ change-instructions drop ] ] bi* bi ; inline +:: optimize-basic-block ( bb init-quot insn-quot -- ) + bb basic-block set + bb live-in keys init-quot call + bb insn-quot change-instructions drop ; inline -: local-optimization ( cfg init-quot: ( live-in -- ) insn-quot: ( insns -- insns' ) -- cfg' ) - [ dup ] 2dip '[ _ _ optimize-basic-block ] each-basic-block ; inline \ No newline at end of file +:: local-optimization ( cfg init-quot: ( live-in -- ) insn-quot: ( insns -- insns' ) -- cfg' ) + cfg [ init-quot insn-quot optimize-basic-block ] each-basic-block + cfg ; inline \ No newline at end of file diff --git a/basis/compiler/cfg/value-numbering/expressions/expressions.factor b/basis/compiler/cfg/value-numbering/expressions/expressions.factor index bf750231c7..76ad3d892f 100644 --- a/basis/compiler/cfg/value-numbering/expressions/expressions.factor +++ b/basis/compiler/cfg/value-numbering/expressions/expressions.factor @@ -1,7 +1,8 @@ -! Copyright (C) 2008 Slava Pestov. +! Copyright (C) 2008, 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: accessors classes kernel math namespaces combinators -compiler.cfg.instructions compiler.cfg.value-numbering.graph ; +combinators.short-circuit compiler.cfg.instructions +compiler.cfg.value-numbering.graph ; IN: compiler.cfg.value-numbering.expressions ! Referentially-transparent expressions @@ -11,15 +12,29 @@ TUPLE: binary-expr < expr in1 in2 ; TUPLE: commutative-expr < binary-expr ; TUPLE: compare-expr < binary-expr cc ; TUPLE: constant-expr < expr value ; +TUPLE: reference-expr < expr value ; : ( constant -- expr ) f swap constant-expr boa ; inline M: constant-expr equal? over constant-expr? [ - [ [ value>> ] bi@ = ] - [ [ value>> class ] bi@ = ] 2bi - and + { + [ [ value>> class ] bi@ = ] + [ [ value>> ] bi@ = ] + } 2&& + ] [ 2drop f ] if ; + +: ( constant -- expr ) + f swap reference-expr boa ; inline + +M: reference-expr equal? + over reference-expr? [ + [ value>> ] bi@ { + { [ 2dup eq? ] [ 2drop t ] } + { [ 2dup [ float? ] both? ] [ fp-bitwise= ] } + [ 2drop f ] + } cond ] [ 2drop f ] if ; ! Expressions whose values are inputs to the basic block. We @@ -39,6 +54,8 @@ GENERIC: >expr ( insn -- expr ) M: ##load-immediate >expr val>> ; +M: ##load-reference >expr obj>> ; + M: ##unary >expr [ class ] [ src>> vreg>vn ] bi unary-expr boa ; diff --git a/basis/compiler/cfg/value-numbering/rewrite/rewrite.factor b/basis/compiler/cfg/value-numbering/rewrite/rewrite.factor index a0e8dd6146..5dd8884a89 100755 --- a/basis/compiler/cfg/value-numbering/rewrite/rewrite.factor +++ b/basis/compiler/cfg/value-numbering/rewrite/rewrite.factor @@ -1,8 +1,9 @@ ! Copyright (C) 2008, 2009 Slava Pestov, Doug Coleman. ! See http://factorcode.org/license.txt for BSD license. -USING: accessors locals combinators combinators.short-circuit arrays +USING: accessors combinators combinators.short-circuit arrays fry kernel layouts math namespaces sequences cpu.architecture -math.bitwise classes +math.bitwise math.order classes vectors +compiler.cfg compiler.cfg.hats compiler.cfg.comparisons compiler.cfg.instructions @@ -11,6 +12,12 @@ compiler.cfg.value-numbering.graph compiler.cfg.value-numbering.simplify ; IN: compiler.cfg.value-numbering.rewrite +: vreg-small-constant? ( vreg -- ? ) + vreg>expr { + [ constant-expr? ] + [ value>> small-enough? ] + } 1&& ; + ! Outputs f to mean no change GENERIC: rewrite* ( insn -- insn/f ) @@ -76,48 +83,6 @@ M: ##compare-imm rewrite-tagged-comparison [ dst>> ] [ (rewrite-tagged-comparison) ] bi i \ ##compare-imm new-insn ; -M: ##compare-imm-branch rewrite* - { - { [ dup rewrite-boolean-comparison? ] [ rewrite-boolean-comparison ] } - { [ dup rewrite-tagged-comparison? ] [ rewrite-tagged-comparison ] } - [ drop f ] - } cond ; - -:: >compare-imm ( insn swap? -- insn' ) - insn dst>> - insn src1>> - insn src2>> swap? [ swap ] when vreg>constant - insn cc>> swap? [ swap-cc ] when - i \ ##compare-imm new-insn ; inline - -: vreg-small-constant? ( vreg -- ? ) - vreg>expr { - [ constant-expr? ] - [ value>> small-enough? ] - } 1&& ; - -M: ##compare rewrite* - dup [ src1>> ] [ src2>> ] bi - [ vreg-small-constant? ] bi@ 2array { - { { f t } [ f >compare-imm ] } - { { t f } [ t >compare-imm ] } - [ 2drop f ] - } case ; - -:: >compare-imm-branch ( insn swap? -- insn' ) - insn src1>> - insn src2>> swap? [ swap ] when vreg>constant - insn cc>> swap? [ swap-cc ] when - \ ##compare-imm-branch new-insn ; inline - -M: ##compare-branch rewrite* - dup [ src1>> ] [ src2>> ] bi - [ vreg-small-constant? ] bi@ 2array { - { { f t } [ f >compare-imm-branch ] } - { { t f } [ t >compare-imm-branch ] } - [ 2drop f ] - } case ; - : rewrite-redundant-comparison? ( insn -- ? ) { [ src1>> vreg>expr compare-expr? ] @@ -133,10 +98,80 @@ M: ##compare-branch rewrite* } case swap cc= eq? [ [ negate-cc ] change-cc ] when ; +: (fold-compare-imm) ( insn -- ? ) + [ [ src1>> vreg>constant ] [ src2>> ] bi ] [ cc>> ] bi + pick integer? [ [ <=> ] dip evaluate-cc ] [ 3drop f ] if ; + +: fold-compare-imm? ( insn -- ? ) + src1>> vreg>expr [ constant-expr? ] [ reference-expr? ] bi or ; + +: fold-compare-imm-branch ( insn -- insn/f ) + (fold-compare-imm) 0 1 ? + basic-block get [ nth 1vector ] change-successors drop + \ ##branch new-insn ; + +M: ##compare-imm-branch rewrite* + { + { [ dup rewrite-boolean-comparison? ] [ rewrite-boolean-comparison ] } + { [ dup rewrite-tagged-comparison? ] [ rewrite-tagged-comparison ] } + { [ dup fold-compare-imm? ] [ fold-compare-imm-branch ] } + [ drop f ] + } cond ; + +: swap-compare ( src1 src2 cc swap? -- src1 src2 cc ) + [ [ swap ] dip swap-cc ] when ; inline + +: >compare-imm-branch ( insn swap? -- insn' ) + [ + [ src1>> ] + [ src2>> ] + [ cc>> ] + tri + ] dip + swap-compare + [ vreg>constant ] dip + \ ##compare-imm-branch new-insn ; inline + +M: ##compare-branch rewrite* + { + { [ dup src1>> vreg-small-constant? ] [ t >compare-imm-branch ] } + { [ dup src2>> vreg-small-constant? ] [ f >compare-imm-branch ] } + [ drop f ] + } cond ; + +: >compare-imm ( insn swap? -- insn' ) + [ + { + [ dst>> ] + [ src1>> ] + [ src2>> ] + [ cc>> ] + } cleave + ] dip + swap-compare + [ vreg>constant ] dip + i \ ##compare-imm new-insn ; inline + +M: ##compare rewrite* + { + { [ dup src1>> vreg-small-constant? ] [ t >compare-imm ] } + { [ dup src2>> vreg-small-constant? ] [ f >compare-imm ] } + [ drop f ] + } cond ; + +: fold-compare-imm ( insn -- ) + [ dst>> ] + [ (fold-compare-imm) ] bi + { + { t [ t \ ##load-reference new-insn ] } + { f [ \ f tag-number \ ##load-immediate new-insn ] } + } case ; + M: ##compare-imm rewrite* { { [ dup rewrite-redundant-comparison? ] [ rewrite-redundant-comparison ] } { [ dup rewrite-tagged-comparison? ] [ rewrite-tagged-comparison ] } + { [ dup fold-compare-imm? ] [ fold-compare-imm ] } [ drop f ] } cond ; @@ -160,22 +195,19 @@ M: ##shl-imm constant-fold* drop shift ; [ [ src1>> vreg>constant ] [ src2>> ] [ ] tri constant-fold* ] bi \ ##load-immediate new-insn ; inline -:: new-imm-insn ( insn dst src1 src2 op -- new-insn/insn ) - src2 small-enough? [ dst src1 src2 op new-insn ] [ insn ] if ; inline - : reassociate? ( insn -- ? ) [ src1>> vreg>expr op>> ] [ class ] bi = ; inline : reassociate ( insn op -- insn ) [ { - [ ] [ dst>> ] [ src1>> vreg>expr [ in1>> vn>vreg ] [ in2>> vn>constant ] bi ] [ src2>> ] [ ] } cleave constant-fold* - ] dip new-imm-insn ; inline + ] dip + over small-enough? [ new-insn ] [ 2drop 2drop f ] if ; inline M: ##add-imm rewrite* { @@ -185,8 +217,8 @@ M: ##add-imm rewrite* } cond ; : sub-imm>add-imm ( insn -- insn' ) - dup [ dst>> ] [ src1>> ] [ src2>> neg ] tri dup small-enough? - [ \ ##add-imm new-insn nip ] [ 2drop 2drop f ] if ; + [ dst>> ] [ src1>> ] [ src2>> neg ] tri dup small-enough? + [ \ ##add-imm new-insn ] [ 3drop f ] if ; M: ##sub-imm rewrite* { @@ -247,12 +279,11 @@ M: ##sar-imm rewrite* [ drop f ] } cond ; -:: insn>imm-insn ( insn op swap? -- ) - insn - insn dst>> - insn src1>> - insn src2>> swap? [ swap ] when vreg>constant - op new-imm-insn ; inline +: insn>imm-insn ( insn op swap? -- ) + swap [ + [ [ dst>> ] [ src1>> ] [ src2>> ] tri ] dip + [ swap ] when vreg>constant + ] dip new-insn ; inline : rewrite-arithmetic ( insn op -- ? ) { diff --git a/basis/compiler/cfg/value-numbering/value-numbering-tests.factor b/basis/compiler/cfg/value-numbering/value-numbering-tests.factor index 6ed0a74da5..e808220716 100644 --- a/basis/compiler/cfg/value-numbering/value-numbering-tests.factor +++ b/basis/compiler/cfg/value-numbering/value-numbering-tests.factor @@ -2,7 +2,7 @@ IN: compiler.cfg.value-numbering.tests USING: compiler.cfg.value-numbering compiler.cfg.instructions compiler.cfg.registers compiler.cfg.debugger compiler.cfg.comparisons cpu.architecture tools.test kernel math combinators.short-circuit -accessors sequences compiler.cfg vectors arrays layouts ; +accessors sequences compiler.cfg vectors arrays layouts namespaces ; : trim-temps ( insns -- insns ) [ @@ -17,6 +17,55 @@ accessors sequences compiler.cfg vectors arrays layouts ; { } init-value-numbering value-numbering-step ; +! Folding constants together +[ + { + T{ ##load-reference f V int-regs 0 0.0 } + T{ ##load-reference f V int-regs 1 -0.0 } + T{ ##replace f V int-regs 0 D 0 } + T{ ##replace f V int-regs 1 D 1 } + } +] [ + { + T{ ##load-reference f V int-regs 0 0.0 } + T{ ##load-reference f V int-regs 1 -0.0 } + T{ ##replace f V int-regs 0 D 0 } + T{ ##replace f V int-regs 1 D 1 } + } test-value-numbering +] unit-test + +[ + { + T{ ##load-reference f V int-regs 0 0.0 } + T{ ##load-reference f V int-regs 1 0.0 } + T{ ##replace f V int-regs 0 D 0 } + T{ ##replace f V int-regs 0 D 1 } + } +] [ + { + T{ ##load-reference f V int-regs 0 0.0 } + T{ ##load-reference f V int-regs 1 0.0 } + T{ ##replace f V int-regs 0 D 0 } + T{ ##replace f V int-regs 1 D 1 } + } test-value-numbering +] unit-test + +[ + { + T{ ##load-reference f V int-regs 0 t } + T{ ##load-reference f V int-regs 1 t } + T{ ##replace f V int-regs 0 D 0 } + T{ ##replace f V int-regs 0 D 1 } + } +] [ + { + T{ ##load-reference f V int-regs 0 t } + T{ ##load-reference f V int-regs 1 t } + T{ ##replace f V int-regs 0 D 0 } + T{ ##replace f V int-regs 1 D 1 } + } test-value-numbering +] unit-test + ! Copy propagation [ { @@ -805,4 +854,157 @@ cell 8 = [ T{ ##add f V int-regs 3 V int-regs 0 V int-regs 2 } } test-value-numbering ] unit-test -] when \ No newline at end of file + + [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 2 140737488355328 } + T{ ##add f V int-regs 3 V int-regs 0 V int-regs 2 } + } + ] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 2 140737488355328 } + T{ ##add f V int-regs 3 V int-regs 0 V int-regs 2 } + } test-value-numbering + ] unit-test + + [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 2 2147483647 } + T{ ##add-imm f V int-regs 3 V int-regs 0 2147483647 } + T{ ##add-imm f V int-regs 4 V int-regs 3 2147483647 } + } + ] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 2 2147483647 } + T{ ##add f V int-regs 3 V int-regs 0 V int-regs 2 } + T{ ##add f V int-regs 4 V int-regs 3 V int-regs 2 } + } test-value-numbering + ] unit-test +] when + +! Branch folding +[ + { + T{ ##load-immediate f V int-regs 1 1 } + T{ ##load-immediate f V int-regs 2 2 } + T{ ##load-immediate f V int-regs 3 5 } + } +] [ + { + T{ ##load-immediate f V int-regs 1 1 } + T{ ##load-immediate f V int-regs 2 2 } + T{ ##compare f V int-regs 3 V int-regs 1 V int-regs 2 cc= } + } test-value-numbering +] unit-test + +[ + { + T{ ##load-immediate f V int-regs 1 1 } + T{ ##load-immediate f V int-regs 2 2 } + T{ ##load-reference f V int-regs 3 t } + } +] [ + { + T{ ##load-immediate f V int-regs 1 1 } + T{ ##load-immediate f V int-regs 2 2 } + T{ ##compare f V int-regs 3 V int-regs 1 V int-regs 2 cc/= } + } test-value-numbering +] unit-test + +[ + { + T{ ##load-immediate f V int-regs 1 1 } + T{ ##load-immediate f V int-regs 2 2 } + T{ ##load-reference f V int-regs 3 t } + } +] [ + { + T{ ##load-immediate f V int-regs 1 1 } + T{ ##load-immediate f V int-regs 2 2 } + T{ ##compare f V int-regs 3 V int-regs 1 V int-regs 2 cc< } + } test-value-numbering +] unit-test + +[ + { + T{ ##load-immediate f V int-regs 1 1 } + T{ ##load-immediate f V int-regs 2 2 } + T{ ##load-immediate f V int-regs 3 5 } + } +] [ + { + T{ ##load-immediate f V int-regs 1 1 } + T{ ##load-immediate f V int-regs 2 2 } + T{ ##compare f V int-regs 3 V int-regs 2 V int-regs 1 cc< } + } test-value-numbering +] unit-test + +: test-branch-folding ( insns -- insns' ) + + [ V{ 0 1 } clone >>successors basic-block set test-value-numbering ] keep + successors>> first ; + +[ + { + T{ ##load-immediate f V int-regs 1 1 } + T{ ##load-immediate f V int-regs 2 2 } + T{ ##branch } + } + 1 +] [ + { + T{ ##load-immediate f V int-regs 1 1 } + T{ ##load-immediate f V int-regs 2 2 } + T{ ##compare-branch f V int-regs 1 V int-regs 2 cc= } + } test-branch-folding +] unit-test + +[ + { + T{ ##load-immediate f V int-regs 1 1 } + T{ ##load-immediate f V int-regs 2 2 } + T{ ##branch } + } + 0 +] [ + { + T{ ##load-immediate f V int-regs 1 1 } + T{ ##load-immediate f V int-regs 2 2 } + T{ ##compare-branch f V int-regs 1 V int-regs 2 cc/= } + } test-branch-folding +] unit-test + +[ + { + T{ ##load-immediate f V int-regs 1 1 } + T{ ##load-immediate f V int-regs 2 2 } + T{ ##branch } + } + 0 +] [ + { + T{ ##load-immediate f V int-regs 1 1 } + T{ ##load-immediate f V int-regs 2 2 } + T{ ##compare-branch f V int-regs 1 V int-regs 2 cc< } + } test-branch-folding +] unit-test + +[ + { + T{ ##load-immediate f V int-regs 1 1 } + T{ ##load-immediate f V int-regs 2 2 } + T{ ##branch } + } + 1 +] [ + { + T{ ##load-immediate f V int-regs 1 1 } + T{ ##load-immediate f V int-regs 2 2 } + T{ ##compare-branch f V int-regs 2 V int-regs 1 cc< } + } test-branch-folding +] unit-test + From a75d558b300391e391dd40c94446e870b8c803fd Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 14 Jul 2009 19:18:57 -0500 Subject: [PATCH 41/96] compiler.cfg.intrinsics.fixnum: don't generate -imm forms anymore since value numbering does it --- .../cfg/intrinsics/fixnum/fixnum.factor | 61 +++---------------- .../compiler/cfg/intrinsics/intrinsics.factor | 22 +++---- 2 files changed, 18 insertions(+), 65 deletions(-) diff --git a/basis/compiler/cfg/intrinsics/fixnum/fixnum.factor b/basis/compiler/cfg/intrinsics/fixnum/fixnum.factor index b360eed80b..2a82139e13 100644 --- a/basis/compiler/cfg/intrinsics/fixnum/fixnum.factor +++ b/basis/compiler/cfg/intrinsics/fixnum/fixnum.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2008, 2009 Slava Pestov, Doug Coleman. ! See http://factorcode.org/license.txt for BSD license. USING: sequences accessors layouts kernel math namespaces -combinators fry locals +combinators fry compiler.tree.propagation.info compiler.cfg.hats compiler.cfg.stacks @@ -21,32 +21,8 @@ IN: compiler.cfg.intrinsics.fixnum : tag-literal ( n -- tagged ) literal>> [ tag-fixnum ] [ \ f tag-number ] if* ; -: emit-fixnum-imm-op1 ( infos insn -- dst ) - [ ds-pop ds-drop ] [ first tag-literal ] [ ] tri* call ; inline - -: emit-fixnum-imm-op2 ( infos insn -- dst ) - [ ds-drop ds-pop ] [ second tag-literal ] [ ] tri* call ; inline - -: (emit-fixnum-op) ( insn -- dst ) - [ 2inputs ] dip call ; inline - -:: emit-fixnum-op ( node insn imm-insn -- ) - [let | infos [ node node-input-infos ] | - infos second value-info-small-tagged? - [ infos imm-insn emit-fixnum-imm-op2 ] - [ insn (emit-fixnum-op) ] if - ds-push - ] ; inline - -:: emit-commutative-fixnum-op ( node insn imm-insn -- ) - [let | infos [ node node-input-infos ] | - { - { [ infos first value-info-small-tagged? ] [ infos imm-insn emit-fixnum-imm-op1 ] } - { [ infos second value-info-small-tagged? ] [ infos imm-insn emit-fixnum-imm-op2 ] } - [ insn (emit-fixnum-op) ] - } cond - ds-push - ] ; inline +: emit-fixnum-op ( insn -- dst ) + [ 2inputs ] dip call ds-push ; inline : emit-fixnum-shift-fast ( node -- ) dup node-input-infos dup second value-info-small-fixnum? [ @@ -66,34 +42,11 @@ IN: compiler.cfg.intrinsics.fixnum : emit-fixnum-log2 ( -- ) ds-pop ^^log2 tag-bits get ^^sub-imm ^^tag-fixnum ds-push ; -: (emit-fixnum*fast) ( -- dst ) - 2inputs ^^untag-fixnum ^^mul ; +: emit-fixnum*fast ( -- ) + 2inputs ^^untag-fixnum ^^mul ds-push ; -: (emit-fixnum*fast-imm1) ( infos -- dst ) - [ ds-pop ds-drop ] [ first literal>> ] bi* ^^mul-imm ; - -: (emit-fixnum*fast-imm2) ( infos -- dst ) - [ ds-drop ds-pop ] [ second literal>> ] bi* ^^mul-imm ; - -: emit-fixnum*fast ( node -- ) - node-input-infos - dup first value-info-small-fixnum? drop f - [ - (emit-fixnum*fast-imm1) - ] [ - dup second value-info-small-fixnum? - [ (emit-fixnum*fast-imm2) ] [ drop (emit-fixnum*fast) ] if - ] if - ds-push ; - -: (emit-fixnum-comparison) ( cc -- quot1 quot2 ) - [ ^^compare ] [ ^^compare-imm ] bi-curry ; inline - -: emit-eq ( node -- ) - cc= (emit-fixnum-comparison) emit-commutative-fixnum-op ; - -: emit-fixnum-comparison ( node cc -- ) - (emit-fixnum-comparison) emit-fixnum-op ; +: emit-fixnum-comparison ( cc -- ) + '[ _ ^^compare ] emit-fixnum-op ; : emit-bignum>fixnum ( -- ) ds-pop ^^bignum>integer ^^tag-fixnum ds-push ; diff --git a/basis/compiler/cfg/intrinsics/intrinsics.factor b/basis/compiler/cfg/intrinsics/intrinsics.factor index 5283581bdd..ed94ec36d9 100644 --- a/basis/compiler/cfg/intrinsics/intrinsics.factor +++ b/basis/compiler/cfg/intrinsics/intrinsics.factor @@ -103,20 +103,20 @@ IN: compiler.cfg.intrinsics { \ math.private:fixnum+ [ drop [ ##fixnum-add ] emit-fixnum-overflow-op ] } { \ math.private:fixnum- [ drop [ ##fixnum-sub ] emit-fixnum-overflow-op ] } { \ math.private:fixnum* [ drop [ i i ##fixnum-mul ] emit-fixnum-overflow-op ] } - { \ math.private:fixnum+fast [ [ ^^add ] [ ^^add-imm ] emit-commutative-fixnum-op ] } - { \ math.private:fixnum-fast [ [ ^^sub ] [ ^^sub-imm ] emit-fixnum-op ] } - { \ math.private:fixnum-bitand [ [ ^^and ] [ ^^and-imm ] emit-commutative-fixnum-op ] } - { \ math.private:fixnum-bitor [ [ ^^or ] [ ^^or-imm ] emit-commutative-fixnum-op ] } - { \ math.private:fixnum-bitxor [ [ ^^xor ] [ ^^xor-imm ] emit-commutative-fixnum-op ] } + { \ math.private:fixnum+fast [ drop [ ^^add ] emit-fixnum-op ] } + { \ math.private:fixnum-fast [ drop [ ^^sub ] emit-fixnum-op ] } + { \ math.private:fixnum-bitand [ drop [ ^^and ] emit-fixnum-op ] } + { \ math.private:fixnum-bitor [ drop [ ^^or ] emit-fixnum-op ] } + { \ math.private:fixnum-bitxor [ drop [ ^^xor ] emit-fixnum-op ] } { \ math.private:fixnum-shift-fast [ emit-fixnum-shift-fast ] } { \ math.private:fixnum-bitnot [ drop emit-fixnum-bitnot ] } { \ math.integers.private:fixnum-log2 [ drop emit-fixnum-log2 ] } - { \ math.private:fixnum*fast [ emit-fixnum*fast ] } - { \ math.private:fixnum< [ cc< emit-fixnum-comparison ] } - { \ math.private:fixnum<= [ cc<= emit-fixnum-comparison ] } - { \ math.private:fixnum>= [ cc>= emit-fixnum-comparison ] } - { \ math.private:fixnum> [ cc> emit-fixnum-comparison ] } - { \ kernel:eq? [ emit-eq ] } + { \ math.private:fixnum*fast [ drop emit-fixnum*fast ] } + { \ math.private:fixnum< [ drop cc< emit-fixnum-comparison ] } + { \ math.private:fixnum<= [ drop cc<= emit-fixnum-comparison ] } + { \ math.private:fixnum>= [ drop cc>= emit-fixnum-comparison ] } + { \ math.private:fixnum> [ drop cc> emit-fixnum-comparison ] } + { \ kernel:eq? [ drop cc= emit-fixnum-comparison ] } { \ math.private:bignum>fixnum [ drop emit-bignum>fixnum ] } { \ math.private:fixnum>bignum [ drop emit-fixnum>bignum ] } { \ math.private:float+ [ drop [ ^^add-float ] emit-float-op ] } From 11731f8d485675b6eff6cf18c060256f9cb06a78 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 14 Jul 2009 20:05:01 -0500 Subject: [PATCH 42/96] compiler.cfg.value-numbering: merge in compiler.cfg.branch-folding --- .../branch-folding-tests.factor | 89 ------ .../cfg/branch-folding/branch-folding.factor | 33 --- basis/compiler/cfg/optimizer/optimizer.factor | 2 - .../value-numbering/rewrite/rewrite.factor | 55 +++- .../value-numbering-tests.factor | 263 +++++++++++++++++- .../value-numbering/value-numbering.factor | 2 + basis/compiler/tests/codegen.factor | 5 +- 7 files changed, 309 insertions(+), 140 deletions(-) delete mode 100644 basis/compiler/cfg/branch-folding/branch-folding-tests.factor delete mode 100644 basis/compiler/cfg/branch-folding/branch-folding.factor diff --git a/basis/compiler/cfg/branch-folding/branch-folding-tests.factor b/basis/compiler/cfg/branch-folding/branch-folding-tests.factor deleted file mode 100644 index 1d43ea0af3..0000000000 --- a/basis/compiler/cfg/branch-folding/branch-folding-tests.factor +++ /dev/null @@ -1,89 +0,0 @@ -IN: compiler.cfg.branch-folding.tests -USING: compiler.cfg.branch-folding compiler.cfg.instructions -compiler.cfg compiler.cfg.registers compiler.cfg.debugger -arrays compiler.cfg.phi-elimination compiler.cfg.dce -compiler.cfg.predecessors compiler.cfg.comparisons -kernel accessors assocs sequences classes namespaces -tools.test cpu.architecture ; - -V{ T{ ##branch } } 0 test-bb - -V{ - T{ ##peek f V int-regs 0 D 0 } - T{ ##compare-branch f V int-regs 0 V int-regs 0 cc< } -} 1 test-bb - -V{ - T{ ##load-immediate f V int-regs 1 1 } - T{ ##branch } -} 2 test-bb - -V{ - T{ ##load-immediate f V int-regs 2 2 } - T{ ##branch } -} 3 test-bb - -V{ - T{ ##phi f V int-regs 3 { } } - T{ ##replace f V int-regs 3 D 0 } - T{ ##return } -} 4 test-bb - -4 get instructions>> first -2 get V int-regs 1 2array -3 get V int-regs 2 2array 2array ->>inputs drop - -test-diamond - -[ ] [ cfg new 0 get >>entry fold-branches compute-predecessors eliminate-phis drop ] unit-test - -[ 1 ] [ 1 get successors>> length ] unit-test -[ t ] [ 1 get successors>> first 3 get eq? ] unit-test - -[ T{ ##copy f V int-regs 3 V int-regs 2 } ] -[ 3 get successors>> first instructions>> first ] -unit-test - -[ 2 ] [ 4 get instructions>> length ] unit-test - -V{ - T{ ##peek f V int-regs 0 D 0 } - T{ ##branch } -} 0 test-bb - -V{ - T{ ##peek f V int-regs 1 D 1 } - T{ ##compare-branch f V int-regs 1 V int-regs 1 cc< } -} 1 test-bb - -V{ - T{ ##copy f V int-regs 2 V int-regs 0 } - T{ ##branch } -} 2 test-bb - -V{ - T{ ##phi f V int-regs 3 V{ } } - T{ ##branch } -} 3 test-bb - -V{ - T{ ##replace f V int-regs 3 D 0 } - T{ ##return } -} 4 test-bb - -1 get V int-regs 1 2array -2 get V int-regs 0 2array 2array 3 get instructions>> first (>>inputs) - -test-diamond - -[ ] [ - cfg new 0 get >>entry - compute-predecessors - fold-branches - compute-predecessors - eliminate-dead-code - drop -] unit-test - -[ 1 ] [ 3 get instructions>> first inputs>> assoc-size ] unit-test \ No newline at end of file diff --git a/basis/compiler/cfg/branch-folding/branch-folding.factor b/basis/compiler/cfg/branch-folding/branch-folding.factor deleted file mode 100644 index 04842552b7..0000000000 --- a/basis/compiler/cfg/branch-folding/branch-folding.factor +++ /dev/null @@ -1,33 +0,0 @@ -! Copyright (C) 2009 Slava Pestov. -! See http://factorcode.org/license.txt for BSD license. -USING: accessors combinators.short-circuit kernel sequences vectors -compiler.cfg.instructions -compiler.cfg.comparisons -compiler.cfg.rpo -compiler.cfg ; -IN: compiler.cfg.branch-folding - -! Fold comparisons where both inputs are the same. Predecessors must be -! recomputed after this - -: fold-branch? ( bb -- ? ) - instructions>> last { - [ ##compare-branch? ] - [ [ src1>> ] [ src2>> ] bi = ] - } 1&& ; - -: chosen-successor ( bb -- succ ) - [ instructions>> last cc>> { cc= cc<= cc>= } memq? 0 1 ? ] - [ successors>> ] - bi nth ; - -: fold-branch ( bb -- ) - dup chosen-successor 1vector >>successors - instructions>> [ pop* ] [ [ \ ##branch new-insn ] dip push ] bi ; - -: fold-branches ( cfg -- cfg' ) - dup [ - dup fold-branch? - [ fold-branch ] [ drop ] if - ] each-basic-block - cfg-changed ; \ No newline at end of file diff --git a/basis/compiler/cfg/optimizer/optimizer.factor b/basis/compiler/cfg/optimizer/optimizer.factor index 5b0892a0ee..e16fb734e1 100644 --- a/basis/compiler/cfg/optimizer/optimizer.factor +++ b/basis/compiler/cfg/optimizer/optimizer.factor @@ -9,7 +9,6 @@ compiler.cfg.branch-splitting compiler.cfg.alias-analysis compiler.cfg.value-numbering compiler.cfg.dce -compiler.cfg.branch-folding compiler.cfg.write-barrier compiler.cfg.liveness compiler.cfg.rpo @@ -36,7 +35,6 @@ SYMBOL: check-optimizer? compute-liveness alias-analysis value-numbering - fold-branches compute-predecessors eliminate-dead-code eliminate-write-barriers diff --git a/basis/compiler/cfg/value-numbering/rewrite/rewrite.factor b/basis/compiler/cfg/value-numbering/rewrite/rewrite.factor index 5dd8884a89..3f7173c355 100755 --- a/basis/compiler/cfg/value-numbering/rewrite/rewrite.factor +++ b/basis/compiler/cfg/value-numbering/rewrite/rewrite.factor @@ -98,18 +98,31 @@ M: ##compare-imm rewrite-tagged-comparison } case swap cc= eq? [ [ negate-cc ] change-cc ] when ; +ERROR: bad-comparison ; + : (fold-compare-imm) ( insn -- ? ) [ [ src1>> vreg>constant ] [ src2>> ] bi ] [ cc>> ] bi - pick integer? [ [ <=> ] dip evaluate-cc ] [ 3drop f ] if ; + pick integer? + [ [ <=> ] dip evaluate-cc ] + [ + 2nip { + { cc= [ f ] } + { cc/= [ t ] } + [ bad-comparison ] + } case + ] if ; : fold-compare-imm? ( insn -- ? ) src1>> vreg>expr [ constant-expr? ] [ reference-expr? ] bi or ; -: fold-compare-imm-branch ( insn -- insn/f ) - (fold-compare-imm) 0 1 ? +: fold-branch ( ? -- insn ) + 0 1 ? basic-block get [ nth 1vector ] change-successors drop \ ##branch new-insn ; +: fold-compare-imm-branch ( insn -- insn/f ) + (fold-compare-imm) fold-branch ; + M: ##compare-imm-branch rewrite* { { [ dup rewrite-boolean-comparison? ] [ rewrite-boolean-comparison ] } @@ -132,10 +145,20 @@ M: ##compare-imm-branch rewrite* [ vreg>constant ] dip \ ##compare-imm-branch new-insn ; inline +: self-compare? ( insn -- ? ) + [ src1>> ] [ src2>> ] bi [ vreg>vn ] bi@ = ; inline + +: (rewrite-self-compare) ( insn -- ? ) + cc>> { cc= cc<= cc>= } memq? ; + +: rewrite-self-compare-branch ( insn -- insn' ) + (rewrite-self-compare) fold-branch ; + M: ##compare-branch rewrite* { { [ dup src1>> vreg-small-constant? ] [ t >compare-imm-branch ] } { [ dup src2>> vreg-small-constant? ] [ f >compare-imm-branch ] } + { [ dup self-compare? ] [ rewrite-self-compare-branch ] } [ drop f ] } cond ; @@ -152,21 +175,27 @@ M: ##compare-branch rewrite* [ vreg>constant ] dip i \ ##compare-imm new-insn ; inline -M: ##compare rewrite* - { - { [ dup src1>> vreg-small-constant? ] [ t >compare-imm ] } - { [ dup src2>> vreg-small-constant? ] [ f >compare-imm ] } - [ drop f ] - } cond ; - -: fold-compare-imm ( insn -- ) - [ dst>> ] - [ (fold-compare-imm) ] bi +: >boolean-insn ( insn ? -- insn' ) + [ dst>> ] dip { { t [ t \ ##load-reference new-insn ] } { f [ \ f tag-number \ ##load-immediate new-insn ] } } case ; +: rewrite-self-compare ( insn -- insn' ) + dup (rewrite-self-compare) >boolean-insn ; + +M: ##compare rewrite* + { + { [ dup src1>> vreg-small-constant? ] [ t >compare-imm ] } + { [ dup src2>> vreg-small-constant? ] [ f >compare-imm ] } + { [ dup self-compare? ] [ rewrite-self-compare ] } + [ drop f ] + } cond ; + +: fold-compare-imm ( insn -- insn' ) + dup (fold-compare-imm) >boolean-insn ; + M: ##compare-imm rewrite* { { [ dup rewrite-redundant-comparison? ] [ rewrite-redundant-comparison ] } diff --git a/basis/compiler/cfg/value-numbering/value-numbering-tests.factor b/basis/compiler/cfg/value-numbering/value-numbering-tests.factor index e808220716..60d23cefb7 100644 --- a/basis/compiler/cfg/value-numbering/value-numbering-tests.factor +++ b/basis/compiler/cfg/value-numbering/value-numbering-tests.factor @@ -2,7 +2,9 @@ IN: compiler.cfg.value-numbering.tests USING: compiler.cfg.value-numbering compiler.cfg.instructions compiler.cfg.registers compiler.cfg.debugger compiler.cfg.comparisons cpu.architecture tools.test kernel math combinators.short-circuit -accessors sequences compiler.cfg vectors arrays layouts namespaces ; +accessors sequences compiler.cfg.predecessors +compiler.cfg.phi-elimination compiler.cfg.dce compiler.cfg.liveness +compiler.cfg assocs vectors arrays layouts namespaces ; : trim-temps ( insns -- insns ) [ @@ -943,7 +945,79 @@ cell 8 = [ } test-value-numbering ] unit-test -: test-branch-folding ( insns -- insns' ) +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 5 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##compare f V int-regs 1 V int-regs 0 V int-regs 0 cc< } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-reference f V int-regs 1 t } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##compare f V int-regs 1 V int-regs 0 V int-regs 0 cc<= } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 5 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##compare f V int-regs 1 V int-regs 0 V int-regs 0 cc> } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-reference f V int-regs 1 t } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##compare f V int-regs 1 V int-regs 0 V int-regs 0 cc>= } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-immediate f V int-regs 1 5 } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##compare f V int-regs 1 V int-regs 0 V int-regs 0 cc/= } + } test-value-numbering +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-reference f V int-regs 1 t } + } +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##compare f V int-regs 1 V int-regs 0 V int-regs 0 cc= } + } test-value-numbering +] unit-test + +: test-branch-folding ( insns -- insns' n ) [ V{ 0 1 } clone >>successors basic-block set test-value-numbering ] keep successors>> first ; @@ -1008,3 +1082,188 @@ cell 8 = [ } test-branch-folding ] unit-test +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##branch } + } + 1 +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##compare-branch f V int-regs 0 V int-regs 0 cc< } + } test-branch-folding +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##branch } + } + 0 +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##compare-branch f V int-regs 0 V int-regs 0 cc<= } + } test-branch-folding +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##branch } + } + 1 +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##compare-branch f V int-regs 0 V int-regs 0 cc> } + } test-branch-folding +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##branch } + } + 0 +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##compare-branch f V int-regs 0 V int-regs 0 cc>= } + } test-branch-folding +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##branch } + } + 0 +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##compare-branch f V int-regs 0 V int-regs 0 cc= } + } test-branch-folding +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##branch } + } + 1 +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##compare-branch f V int-regs 0 V int-regs 0 cc/= } + } test-branch-folding +] unit-test + +[ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##load-reference f V int-regs 1 t } + T{ ##branch } + } + 0 +] [ + { + T{ ##peek f V int-regs 0 D 0 } + T{ ##compare f V int-regs 1 V int-regs 0 V int-regs 0 cc<= } + T{ ##compare-imm-branch f V int-regs 1 5 cc/= } + } test-branch-folding +] unit-test + +! More branch folding tests +V{ T{ ##branch } } 0 test-bb + +V{ + T{ ##peek f V int-regs 0 D 0 } + T{ ##compare-branch f V int-regs 0 V int-regs 0 cc< } +} 1 test-bb + +V{ + T{ ##load-immediate f V int-regs 1 1 } + T{ ##branch } +} 2 test-bb + +V{ + T{ ##load-immediate f V int-regs 2 2 } + T{ ##branch } +} 3 test-bb + +V{ + T{ ##phi f V int-regs 3 { } } + T{ ##replace f V int-regs 3 D 0 } + T{ ##return } +} 4 test-bb + +4 get instructions>> first +2 get V int-regs 1 2array +3 get V int-regs 2 2array 2array +>>inputs drop + +test-diamond + +[ ] [ + cfg new 0 get >>entry + compute-liveness + value-numbering + compute-predecessors + eliminate-phis drop +] unit-test + +[ 1 ] [ 1 get successors>> length ] unit-test + +[ t ] [ 1 get successors>> first 3 get eq? ] unit-test + +[ T{ ##copy f V int-regs 3 V int-regs 2 } ] +[ 3 get successors>> first instructions>> first ] +unit-test + +[ 2 ] [ 4 get instructions>> length ] unit-test + +V{ + T{ ##peek f V int-regs 0 D 0 } + T{ ##branch } +} 0 test-bb + +V{ + T{ ##peek f V int-regs 1 D 1 } + T{ ##compare-branch f V int-regs 1 V int-regs 1 cc< } +} 1 test-bb + +V{ + T{ ##copy f V int-regs 2 V int-regs 0 } + T{ ##branch } +} 2 test-bb + +V{ + T{ ##phi f V int-regs 3 V{ } } + T{ ##branch } +} 3 test-bb + +V{ + T{ ##replace f V int-regs 3 D 0 } + T{ ##return } +} 4 test-bb + +1 get V int-regs 1 2array +2 get V int-regs 0 2array 2array 3 get instructions>> first (>>inputs) + +test-diamond + +[ ] [ + cfg new 0 get >>entry + compute-predecessors + compute-liveness + value-numbering + compute-predecessors + eliminate-dead-code + drop +] unit-test + +[ t ] [ 1 get successors>> first 3 get eq? ] unit-test + +[ 1 ] [ 3 get instructions>> first inputs>> assoc-size ] unit-test \ No newline at end of file diff --git a/basis/compiler/cfg/value-numbering/value-numbering.factor b/basis/compiler/cfg/value-numbering/value-numbering.factor index 9e6e058b52..202b3d1e9b 100644 --- a/basis/compiler/cfg/value-numbering/value-numbering.factor +++ b/basis/compiler/cfg/value-numbering/value-numbering.factor @@ -11,6 +11,8 @@ compiler.cfg.value-numbering.simplify compiler.cfg.value-numbering.rewrite ; IN: compiler.cfg.value-numbering +! Local value numbering. Predecessors must be recomputed after this + : number-input-values ( live-in -- ) [ [ f next-input-expr simplify ] dip set-vn ] each ; diff --git a/basis/compiler/tests/codegen.factor b/basis/compiler/tests/codegen.factor index 8f7bc077b4..9f573019c2 100644 --- a/basis/compiler/tests/codegen.factor +++ b/basis/compiler/tests/codegen.factor @@ -318,4 +318,7 @@ M: cucumber equal? "The cucumber has no equal" throw ; cell 4 = [ [ 0 ] [ 101 [ dup fixnum-fast 1 fixnum+fast 20 fixnum-shift-fast 20 fixnum-shift-fast ] compile-call ] unit-test -] when \ No newline at end of file +] when + +! Regression from Slava's value numbering changes +[ 1 ] [ 31337 [ dup fixnum<= [ 1 ] [ 2 ] if ] compile-call ] unit-test \ No newline at end of file From 4ac74e93041d8f4d5340da3e178472267131a0aa Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 14 Jul 2009 20:42:50 -0500 Subject: [PATCH 43/96] compiler.cfg.branch-splitting: don't split if there's one predecessor --- basis/compiler/cfg/branch-splitting/branch-splitting.factor | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/basis/compiler/cfg/branch-splitting/branch-splitting.factor b/basis/compiler/cfg/branch-splitting/branch-splitting.factor index 0dd963125f..9d6e59e4da 100644 --- a/basis/compiler/cfg/branch-splitting/branch-splitting.factor +++ b/basis/compiler/cfg/branch-splitting/branch-splitting.factor @@ -65,15 +65,15 @@ UNION: irrelevant ##peek ##replace ##inc-d ##inc-r ; : split-instructions? ( insns -- ? ) [ irrelevant? not ] count 5 <= ; -: split-branches? ( bb -- ? ) +: split-branch? ( bb -- ? ) { [ dup successors>> [ back-edge? ] with any? not ] - [ predecessors>> length 1 4 between? ] + [ predecessors>> length 2 4 between? ] [ instructions>> split-instructions? ] } 1&& ; : split-branches ( cfg -- cfg' ) dup [ - dup split-branches? [ split-branch ] [ drop ] if + dup split-branch? [ split-branch ] [ drop ] if ] each-basic-block cfg-changed ; From ebcd0dc2520f99409573ecd36bd9ca3ee6b9684e Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 14 Jul 2009 20:43:06 -0500 Subject: [PATCH 44/96] compiler.cfg: Fix regressions from recent changes --- .../stack-analysis-tests.factor | 4 +- .../value-numbering-tests.factor | 67 ++++++++++++++++++- .../value-numbering/value-numbering.factor | 4 +- 3 files changed, 71 insertions(+), 4 deletions(-) diff --git a/basis/compiler/cfg/stack-analysis/stack-analysis-tests.factor b/basis/compiler/cfg/stack-analysis/stack-analysis-tests.factor index 23b1098cd6..9fbf7acf78 100644 --- a/basis/compiler/cfg/stack-analysis/stack-analysis-tests.factor +++ b/basis/compiler/cfg/stack-analysis/stack-analysis-tests.factor @@ -91,9 +91,9 @@ IN: compiler.cfg.stack-analysis.tests ! Sync before a back-edge, not after ! ##peeks should be inserted before a ##loop-entry ! Don't optimize out the constants -[ 1 t ] [ +[ t ] [ [ 1000 [ ] times ] test-stack-analysis eliminate-dead-code linearize - [ [ ##add-imm? ] count ] [ [ ##load-immediate? ] any? ] bi + [ ##load-immediate? ] any? ] unit-test ! Correct height tracking diff --git a/basis/compiler/cfg/value-numbering/value-numbering-tests.factor b/basis/compiler/cfg/value-numbering/value-numbering-tests.factor index 60d23cefb7..4c431b8a5c 100644 --- a/basis/compiler/cfg/value-numbering/value-numbering-tests.factor +++ b/basis/compiler/cfg/value-numbering/value-numbering-tests.factor @@ -1266,4 +1266,69 @@ test-diamond [ t ] [ 1 get successors>> first 3 get eq? ] unit-test -[ 1 ] [ 3 get instructions>> first inputs>> assoc-size ] unit-test \ No newline at end of file +[ 1 ] [ 3 get instructions>> first inputs>> assoc-size ] unit-test + +V{ T{ ##prologue } T{ ##branch } } 0 test-bb + +V{ + T{ ##peek { dst V int-regs 15 } { loc D 0 } } + T{ ##copy { dst V int-regs 16 } { src V int-regs 15 } } + T{ ##copy { dst V int-regs 17 } { src V int-regs 15 } } + T{ ##copy { dst V int-regs 18 } { src V int-regs 15 } } + T{ ##copy { dst V int-regs 19 } { src V int-regs 15 } } + T{ ##compare + { dst V int-regs 20 } + { src1 V int-regs 18 } + { src2 V int-regs 19 } + { cc cc= } + { temp V int-regs 22 } + } + T{ ##copy { dst V int-regs 21 } { src V int-regs 20 } } + T{ ##compare-imm-branch + { src1 V int-regs 21 } + { src2 5 } + { cc cc/= } + } +} 1 test-bb + +V{ + T{ ##copy { dst V int-regs 23 } { src V int-regs 15 } } + T{ ##copy { dst V int-regs 24 } { src V int-regs 15 } } + T{ ##load-reference { dst V int-regs 25 } { obj t } } + T{ ##branch } +} 2 test-bb + +V{ + T{ ##replace { src V int-regs 25 } { loc D 0 } } + T{ ##epilogue } + T{ ##return } +} 3 test-bb + +V{ + T{ ##copy { dst V int-regs 26 } { src V int-regs 15 } } + T{ ##copy { dst V int-regs 27 } { src V int-regs 15 } } + T{ ##add + { dst V int-regs 28 } + { src1 V int-regs 26 } + { src2 V int-regs 27 } + } + T{ ##branch } +} 4 test-bb + +V{ + T{ ##replace { src V int-regs 28 } { loc D 0 } } + T{ ##epilogue } + T{ ##return } +} 5 test-bb + +0 get 1 get 1vector >>successors drop +1 get 2 get 4 get V{ } 2sequence >>successors drop +2 get 3 get 1vector >>successors drop +4 get 5 get 1vector >>successors drop + +[ ] [ + cfg new 0 get >>entry + compute-liveness value-numbering eliminate-dead-code drop +] unit-test + +[ f ] [ 1 get instructions>> [ ##peek? ] any? ] unit-test \ No newline at end of file diff --git a/basis/compiler/cfg/value-numbering/value-numbering.factor b/basis/compiler/cfg/value-numbering/value-numbering.factor index 202b3d1e9b..e49555e06e 100644 --- a/basis/compiler/cfg/value-numbering/value-numbering.factor +++ b/basis/compiler/cfg/value-numbering/value-numbering.factor @@ -2,6 +2,7 @@ ! See http://factorcode.org/license.txt for BSD license. USING: namespaces assocs biassocs classes kernel math accessors sorting sets sequences fry +compiler.cfg compiler.cfg.local compiler.cfg.liveness compiler.cfg.renaming @@ -34,4 +35,5 @@ IN: compiler.cfg.value-numbering [ rewrite ] map dup rename-uses ; : value-numbering ( cfg -- cfg' ) - [ init-value-numbering ] [ value-numbering-step ] local-optimization ; + [ init-value-numbering ] [ value-numbering-step ] local-optimization + cfg-changed ; From b7dd3d5d35573513ab28cd00c4d6b3557b57fd14 Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Wed, 15 Jul 2009 13:53:57 -0500 Subject: [PATCH 45/96] report opengl function name in gl-errors --- basis/opengl/opengl.factor | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) mode change 100644 => 100755 basis/opengl/opengl.factor diff --git a/basis/opengl/opengl.factor b/basis/opengl/opengl.factor old mode 100644 new mode 100755 index 7884890ebf..196293adc9 --- a/basis/opengl/opengl.factor +++ b/basis/opengl/opengl.factor @@ -30,7 +30,7 @@ IN: opengl { HEX: 0506 "Invalid framebuffer operation" } } at "Unknown error" or ; -TUPLE: gl-error code string ; +TUPLE: gl-error function code string ; TUPLE: gl-error-log { function word initial: t } @@ -39,17 +39,20 @@ TUPLE: gl-error-log gl-error-log [ V{ } clone ] initialize -: ( code -- gl-error ) +: ( function code -- gl-error ) dup error>string \ gl-error boa ; inline : ( function code -- gl-error-log ) - now gl-error-log boa ; + [ dup ] dip now gl-error-log boa ; : gl-error-code ( -- code/f ) glGetError dup 0 = [ drop f ] when ; inline +: (gl-error) ( function -- ) + gl-error-code [ throw ] [ drop ] if* ; + : gl-error ( -- ) - gl-error-code [ throw ] [ ] if* ; + f (gl-error) ; inline : log-gl-error ( function -- ) gl-error-code [ gl-error-log get push ] [ drop ] if* ; @@ -72,7 +75,7 @@ gl-error-log [ V{ } clone ] initialize V{ } clone gl-error-log set ; : throw-gl-errors ( -- ) - [ drop '[ @ gl-error ] ] annotate-gl-functions ; + [ '[ @ _ (gl-error) ] ] annotate-gl-functions ; : log-gl-errors ( -- ) [ '[ @ _ log-gl-error ] ] annotate-gl-functions ; From 8e58f5e5aa974eda52e263b60d6e4304461b50d4 Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Wed, 15 Jul 2009 22:39:23 -0500 Subject: [PATCH 46/96] in kazakhstan, they say that a world is like a context-world --- basis/ui/gadgets/worlds/worlds-docs.factor | 3 --- basis/ui/gadgets/worlds/worlds.factor | 6 ++---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/basis/ui/gadgets/worlds/worlds-docs.factor b/basis/ui/gadgets/worlds/worlds-docs.factor index ddaad93b1b..fe662b898c 100755 --- a/basis/ui/gadgets/worlds/worlds-docs.factor +++ b/basis/ui/gadgets/worlds/worlds-docs.factor @@ -29,9 +29,6 @@ HELP: set-title { $description "Sets the title bar of the native window containing the world." } { $notes "This word should not be called directly by user code. Instead, change the " { $snippet "title" } " slot model; see " { $link "models" } "." } ; -HELP: context-world -{ $var-description "Holds the " { $link world } " whose OpenGL context was most recently made active by " { $link set-gl-context } "." } ; - HELP: set-gl-context { $values { "world" world } } { $description "Selects an OpenGL context to be the implicit destination for subsequent GL rendering calls. This word is called automatically by the UI before drawing a " { $link world } "." } ; diff --git a/basis/ui/gadgets/worlds/worlds.factor b/basis/ui/gadgets/worlds/worlds.factor index 0c59af95d6..91666c4e7a 100755 --- a/basis/ui/gadgets/worlds/worlds.factor +++ b/basis/ui/gadgets/worlds/worlds.factor @@ -78,13 +78,11 @@ TUPLE: world-attributes '[ f _ [ (>>status-owner) ] [ status>> set-model ] 2bi ] when ] [ 2drop ] if ; -SYMBOL: context-world - : window-resource ( resource -- resource ) - dup context-world get-global window-resources>> push ; + dup world get-global window-resources>> push ; : set-gl-context ( world -- ) - [ context-world set-global ] + [ world set-global ] [ handle>> select-gl-context ] bi ; : with-gl-context ( world quot -- ) From e90c947062fb0d91e07ce5fb7dd48fb99f43049a Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Wed, 15 Jul 2009 22:44:03 -0500 Subject: [PATCH 47/96] gl-break word and interactive debugging aids --- basis/opengl/debug/authors.txt | 1 + basis/opengl/debug/debug-docs.factor | 36 ++++++++++++++++++++++++++++ basis/opengl/debug/debug.factor | 23 ++++++++++++++++++ basis/opengl/debug/summary.txt | 1 + 4 files changed, 61 insertions(+) create mode 100644 basis/opengl/debug/authors.txt create mode 100644 basis/opengl/debug/debug-docs.factor create mode 100644 basis/opengl/debug/debug.factor create mode 100644 basis/opengl/debug/summary.txt diff --git a/basis/opengl/debug/authors.txt b/basis/opengl/debug/authors.txt new file mode 100644 index 0000000000..f13c9c1e77 --- /dev/null +++ b/basis/opengl/debug/authors.txt @@ -0,0 +1 @@ +Joe Groff diff --git a/basis/opengl/debug/debug-docs.factor b/basis/opengl/debug/debug-docs.factor new file mode 100644 index 0000000000..7cb8f9b246 --- /dev/null +++ b/basis/opengl/debug/debug-docs.factor @@ -0,0 +1,36 @@ +! (c)2009 Joe Groff bsd license +USING: help.markup help.syntax multiline tools.continuations ; +IN: opengl.debug + +HELP: G +{ $description "Makes the OpenGL context associated with " { $link G-world } " active for subsequent OpenGL calls. This is intended to be used from the listener, where interactively entered OpenGL calls can be directed to any window. Note that the Factor UI resets the OpenGL context every time a window is updated, so every code snippet entered in the listener must be prefixed with " { $snippet "G" } " in this use case." } +{ $examples { $code <" USING: opengl.debug ui ; + +[ drop t ] find-window G-world set +G 0.0 0.0 1.0 1.0 glClearColor +G GL_COLOR_BUFFER_BIT glClear +"> } } ; + +HELP: F +{ $description "Flushes the OpenGL context associated with " { $link G-world } ", thereby committing any outstanding drawing operations." } ; + +HELP: G-world +{ $var-description "The world whose OpenGL context is made active by " { $link G } "." } ; + +HELP: GB +{ $description "A shorthand for " { $link gl-break } "." } ; + +HELP: gl-break +{ $description "Suspends the current thread and activates the walker like " { $link break } ", but also preserves the current OpenGL context, saves it to " { $link G-world } " for interactive use through " { $link G } ", and restores the current context when the suspended thread is continued. The shorthand word " { $link POSTPONE: GB } " can also be used." } ; + +{ G F G-world POSTPONE: GB gl-break } related-words + +ARTICLE: "opengl.debug" "Interactive debugging of OpenGL applications" +"The " { $vocab-link "opengl.debug" } " vocabulary provides words to assist with interactive debugging of OpenGL applications in the Factor UI." +{ $subsection G-world } +{ $subsection G } +{ $subsection F } +{ $subsection GB } +{ $subsection gl-break } ; + +ABOUT: "opengl.debug" diff --git a/basis/opengl/debug/debug.factor b/basis/opengl/debug/debug.factor new file mode 100644 index 0000000000..7cbdf62346 --- /dev/null +++ b/basis/opengl/debug/debug.factor @@ -0,0 +1,23 @@ +! (c)2009 Joe Groff bsd license +USING: accessors kernel namespaces parser tools.continuations +ui.backend ui.gadgets.worlds words ; +IN: opengl.debug + +SYMBOL: G-world + +: G ( -- ) + G-world get set-gl-context ; + +: F ( -- ) + G-world get handle>> flush-gl-context ; + +: gl-break ( -- ) + world get dup G-world set-global + [ break ] dip + set-gl-context ; + +<< \ gl-break t "break?" set-word-prop >> + +SYNTAX: GB + \ gl-break parsed ; + diff --git a/basis/opengl/debug/summary.txt b/basis/opengl/debug/summary.txt new file mode 100644 index 0000000000..3a85f2f3c8 --- /dev/null +++ b/basis/opengl/debug/summary.txt @@ -0,0 +1 @@ +Helper words for breaking and interactively manipulating OpenGL applications From ee3e84a1f867850ceb7ad907e951d65a55263e29 Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Thu, 16 Jul 2009 00:34:50 -0500 Subject: [PATCH 48/96] define-partial-eval framework in propagation pass makes it easy to add transforms; moving some transforms from stack checker to propagation, making them stronger --- .../known-words/known-words.factor | 71 +------ .../tree/propagation/propagation-tests.factor | 25 ++- .../tree/propagation/transforms/authors.txt | 2 + .../propagation/transforms/transforms.factor | 195 ++++++++++++++++++ .../transforms/transforms.factor | 94 --------- 5 files changed, 223 insertions(+), 164 deletions(-) create mode 100644 basis/compiler/tree/propagation/transforms/authors.txt create mode 100644 basis/compiler/tree/propagation/transforms/transforms.factor diff --git a/basis/compiler/tree/propagation/known-words/known-words.factor b/basis/compiler/tree/propagation/known-words/known-words.factor index aec61608f1..f5ea64bc0a 100644 --- a/basis/compiler/tree/propagation/known-words/known-words.factor +++ b/basis/compiler/tree/propagation/known-words/known-words.factor @@ -14,7 +14,8 @@ compiler.tree.propagation.nodes compiler.tree.propagation.slots compiler.tree.propagation.simple compiler.tree.propagation.constraints -compiler.tree.propagation.call-effect ; +compiler.tree.propagation.call-effect +compiler.tree.propagation.transforms ; IN: compiler.tree.propagation.known-words \ fixnum @@ -227,39 +228,6 @@ generic-comparison-ops [ ] "outputs" set-word-prop ] assoc-each -: rem-custom-inlining ( #call -- quot/f ) - second value-info literal>> dup integer? - [ power-of-2? [ 1- bitand ] f ? ] [ drop f ] if ; - -{ - mod-integer-integer - mod-integer-fixnum - mod-fixnum-integer - fixnum-mod -} [ - [ - in-d>> dup first value-info interval>> [0,inf] interval-subset? - [ rem-custom-inlining ] [ drop f ] if - ] "custom-inlining" set-word-prop -] each - -\ rem [ - in-d>> rem-custom-inlining -] "custom-inlining" set-word-prop - -{ - bitand-integer-integer - bitand-integer-fixnum - bitand-fixnum-integer -} [ - [ - in-d>> second value-info >literal< [ - 0 most-positive-fixnum between? - [ [ >fixnum ] bi@ fixnum-bitand ] f ? - ] when - ] "custom-inlining" set-word-prop -] each - { numerator denominator } [ [ drop integer ] "outputs" set-word-prop ] each @@ -314,15 +282,6 @@ generic-comparison-ops [ "outputs" set-word-prop ] each -! Generate more efficient code for common idiom -\ clone [ - in-d>> first value-info literal>> { - { V{ } [ [ drop { } 0 vector boa ] ] } - { H{ } [ [ drop 0 ] ] } - [ drop f ] - } case -] "custom-inlining" set-word-prop - \ slot [ dup literal?>> [ literal>> swap value-info-slot ] [ 2drop object-info ] if @@ -346,29 +305,3 @@ generic-comparison-ops [ bi ] [ 2drop object-info ] if ] "outputs" set-word-prop - -\ instance? [ - in-d>> second value-info literal>> dup class? - [ "predicate" word-prop '[ drop @ ] ] [ drop f ] if -] "custom-inlining" set-word-prop - -\ equal? [ - ! If first input has a known type and second input is an - ! object, we convert this to [ swap equal? ]. - in-d>> first2 value-info class>> object class= [ - value-info class>> \ equal? specific-method - [ swap equal? ] f ? - ] [ drop f ] if -] "custom-inlining" set-word-prop - -: inline-new ( class -- quot/f ) - dup tuple-class? [ - dup inlined-dependency depends-on - [ all-slots [ initial>> literalize ] map ] - [ tuple-layout '[ _ ] ] - bi append [ drop ] prepend >quotation - ] [ drop f ] if ; - -\ new [ - in-d>> first value-info literal>> inline-new -] "custom-inlining" set-word-prop diff --git a/basis/compiler/tree/propagation/propagation-tests.factor b/basis/compiler/tree/propagation/propagation-tests.factor index 108afad296..0a5dbab883 100644 --- a/basis/compiler/tree/propagation/propagation-tests.factor +++ b/basis/compiler/tree/propagation/propagation-tests.factor @@ -9,7 +9,7 @@ compiler.tree.propagation.info compiler.tree.def-use compiler.tree.debugger compiler.tree.checker slots.private words hashtables classes assocs locals specialized-arrays.double system sorting math.libm -math.intervals quotations ; +math.intervals quotations effects ; IN: compiler.tree.propagation.tests [ V{ } ] [ [ ] final-classes ] unit-test @@ -717,3 +717,26 @@ M: number whatever drop foo ; : that-thing ( -- class ) foo ; [ f ] [ [ that-thing new ] { new } inlined? ] unit-test + +GENERIC: whatever2 ( x -- y ) +M: number whatever2 drop H{ { 1 1 } { 2 2 } { 3 3 } { 4 4 } { 5 6 } } ; +M: f whatever2 ; + +[ t ] [ [ 1 whatever2 at ] { at* hashcode* } inlined? ] unit-test +[ f ] [ [ whatever2 at ] { at* hashcode* } inlined? ] unit-test + +[ t ] [ [ { 1 2 3 } member? ] { member? } inlined? ] unit-test +[ f ] [ [ { 1 2 3 } swap member? ] { member? } inlined? ] unit-test + +[ t ] [ [ { 1 2 3 } memq? ] { memq? } inlined? ] unit-test +[ f ] [ [ { 1 2 3 } swap memq? ] { memq? } inlined? ] unit-test + +[ t ] [ [ V{ } clone ] { clone (clone) } inlined? ] unit-test +[ f ] [ [ { } clone ] { clone (clone) } inlined? ] unit-test + +[ f ] [ [ instance? ] { instance? } inlined? ] unit-test +[ f ] [ [ 5 instance? ] { instance? } inlined? ] unit-test +[ t ] [ [ array instance? ] { instance? } inlined? ] unit-test + +[ t ] [ [ (( a b c -- c b a )) shuffle ] { shuffle } inlined? ] unit-test +[ f ] [ [ { 1 2 3 } swap shuffle ] { shuffle } inlined? ] unit-test diff --git a/basis/compiler/tree/propagation/transforms/authors.txt b/basis/compiler/tree/propagation/transforms/authors.txt new file mode 100644 index 0000000000..a44f8d7f8d --- /dev/null +++ b/basis/compiler/tree/propagation/transforms/authors.txt @@ -0,0 +1,2 @@ +Slava Pestov +Daniel Ehrenberg diff --git a/basis/compiler/tree/propagation/transforms/transforms.factor b/basis/compiler/tree/propagation/transforms/transforms.factor new file mode 100644 index 0000000000..1441897b07 --- /dev/null +++ b/basis/compiler/tree/propagation/transforms/transforms.factor @@ -0,0 +1,195 @@ +! Copyright (C) 2008, 2009 Slava Pestov, Daniel Ehrenberg. +! See http://factorcode.org/license.txt for BSD license. +USING: kernel sequences words fry generic accessors classes.tuple +classes classes.algebra definitions stack-checker.state quotations +classes.tuple.private math math.partial-dispatch math.private +math.intervals layouts math.order vectors hashtables +combinators effects generalizations assocs sets +combinators.short-circuit sequences.private locals +stack-checker +compiler.tree.propagation.info ; +IN: compiler.tree.propagation.transforms + +\ equal? [ + ! If first input has a known type and second input is an + ! object, we convert this to [ swap equal? ]. + in-d>> first2 value-info class>> object class= [ + value-info class>> \ equal? specific-method + [ swap equal? ] f ? + ] [ drop f ] if +] "custom-inlining" set-word-prop + +: rem-custom-inlining ( #call -- quot/f ) + second value-info literal>> dup integer? + [ power-of-2? [ 1- bitand ] f ? ] [ drop f ] if ; + +{ + mod-integer-integer + mod-integer-fixnum + mod-fixnum-integer + fixnum-mod +} [ + [ + in-d>> dup first value-info interval>> [0,inf] interval-subset? + [ rem-custom-inlining ] [ drop f ] if + ] "custom-inlining" set-word-prop +] each + +\ rem [ + in-d>> rem-custom-inlining +] "custom-inlining" set-word-prop + +{ + bitand-integer-integer + bitand-integer-fixnum + bitand-fixnum-integer +} [ + [ + in-d>> second value-info >literal< [ + 0 most-positive-fixnum between? + [ [ >fixnum ] bi@ fixnum-bitand ] f ? + ] when + ] "custom-inlining" set-word-prop +] each + +! Generate more efficient code for common idiom +\ clone [ + in-d>> first value-info literal>> { + { V{ } [ [ drop { } 0 vector boa ] ] } + { H{ } [ [ drop 0 ] ] } + [ drop f ] + } case +] "custom-inlining" set-word-prop + +: prepare-partial-eval ( #call n -- value-infos ? ) + +ERROR: bad-partial-eval quot word ; + +: check-effect ( quot word -- ) + 2dup [ infer ] [ stack-effect ] bi* effect<= + [ 2drop ] [ bad-partial-eval ] if ; + +: values ( #call n -- infos ) + [ in-d>> ] dip tail* [ value-info ] map ; + +:: define-partial-eval ( word quot n -- ) + word [ + n values + dup [ literal?>> ] all? [ + [ literal>> ] map + n firstn + quot call dup [ + [ n ndrop ] prepose + dup word check-effect + ] when + ] [ drop f ] if + ] "custom-inlining" set-word-prop ; + +: inline-new ( class -- quot/f ) + dup tuple-class? [ + dup inlined-dependency depends-on + [ all-slots [ initial>> literalize ] map ] + [ tuple-layout '[ _ ] ] + bi append >quotation + ] [ drop f ] if ; + +\ new [ inline-new ] 1 define-partial-eval + +\ instance? [ + dup class? + [ "predicate" word-prop ] [ drop f ] if +] 1 define-partial-eval + +! Shuffling +: nths-quot ( indices -- quot ) + [ [ '[ _ swap nth ] ] map ] [ length ] bi + '[ _ cleave _ narray ] ; + +\ shuffle [ + shuffle-mapping nths-quot +] 1 define-partial-eval + +! Index search +\ index [ + dup sequence? [ + dup length 4 >= [ + dup length zip >hashtable '[ _ at ] + ] [ drop f ] if + ] [ drop f ] if +] 1 define-partial-eval + +: memq-quot ( seq -- newquot ) + [ [ dupd eq? ] curry [ drop t ] ] { } map>assoc + [ drop f ] suffix [ cond ] curry ; + +\ memq? [ + dup sequence? [ memq-quot ] [ drop f ] if +] 1 define-partial-eval + +! Membership testing +: member-quot ( seq -- newquot ) + dup length 4 <= [ + [ drop f ] swap + [ literalize [ t ] ] { } map>assoc linear-case-quot + ] [ + unique [ key? ] curry + ] if ; + +\ member? [ + dup sequence? [ member-quot ] [ drop f ] if +] 1 define-partial-eval + +! Fast at for integer maps +CONSTANT: lookup-table-at-max 256 + +: lookup-table-at? ( assoc -- ? ) + #! Can we use a fast byte array test here? + { + [ assoc-size 4 > ] + [ values [ ] all? ] + [ keys [ integer? ] all? ] + [ keys [ 0 lookup-table-at-max between? ] all? ] + } 1&& ; + +: lookup-table-seq ( assoc -- table ) + [ keys supremum 1+ ] keep '[ _ at ] { } map-as ; + +: lookup-table-quot ( seq -- newquot ) + lookup-table-seq + '[ + _ over integer? [ + 2dup bounds-check? [ + nth-unsafe dup >boolean + ] [ 2drop f f ] if + ] [ 2drop f f ] if + ] ; + +: fast-lookup-table-at? ( assoc -- ? ) + values { + [ [ integer? ] all? ] + [ [ 0 254 between? ] all? ] + } 1&& ; + +: fast-lookup-table-seq ( assoc -- table ) + lookup-table-seq [ 255 or ] B{ } map-as ; + +: fast-lookup-table-quot ( seq -- newquot ) + fast-lookup-table-seq + '[ + _ over integer? [ + 2dup bounds-check? [ + nth-unsafe dup 255 eq? [ drop f f ] [ t ] if + ] [ 2drop f f ] if + ] [ 2drop f f ] if + ] ; + +: at-quot ( assoc -- quot ) + dup lookup-table-at? [ + dup fast-lookup-table-at? [ + fast-lookup-table-quot + ] [ + lookup-table-quot + ] if + ] [ drop f ] if ; + +\ at* [ at-quot ] 1 define-partial-eval diff --git a/basis/stack-checker/transforms/transforms.factor b/basis/stack-checker/transforms/transforms.factor index 9d1ab1332a..056eda8b61 100755 --- a/basis/stack-checker/transforms/transforms.factor +++ b/basis/stack-checker/transforms/transforms.factor @@ -107,97 +107,3 @@ IN: stack-checker.transforms ] 1 define-transform \ boa t "no-compile" set-word-prop - -! Fast at for integer maps -CONSTANT: lookup-table-at-max 256 - -: lookup-table-at? ( assoc -- ? ) - #! Can we use a fast byte array test here? - { - [ assoc-size 4 > ] - [ values [ ] all? ] - [ keys [ integer? ] all? ] - [ keys [ 0 lookup-table-at-max between? ] all? ] - } 1&& ; - -: lookup-table-seq ( assoc -- table ) - [ keys supremum 1+ ] keep '[ _ at ] { } map-as ; - -: lookup-table-quot ( seq -- newquot ) - lookup-table-seq - '[ - _ over integer? [ - 2dup bounds-check? [ - nth-unsafe dup >boolean - ] [ 2drop f f ] if - ] [ 2drop f f ] if - ] ; - -: fast-lookup-table-at? ( assoc -- ? ) - values { - [ [ integer? ] all? ] - [ [ 0 254 between? ] all? ] - } 1&& ; - -: fast-lookup-table-seq ( assoc -- table ) - lookup-table-seq [ 255 or ] B{ } map-as ; - -: fast-lookup-table-quot ( seq -- newquot ) - fast-lookup-table-seq - '[ - _ over integer? [ - 2dup bounds-check? [ - nth-unsafe dup 255 eq? [ drop f f ] [ t ] if - ] [ 2drop f f ] if - ] [ 2drop f f ] if - ] ; - -: at-quot ( assoc -- quot ) - dup lookup-table-at? [ - dup fast-lookup-table-at? [ - fast-lookup-table-quot - ] [ - lookup-table-quot - ] if - ] [ drop f ] if ; - -\ at* [ at-quot ] 1 define-transform - -! Membership testing -: member-quot ( seq -- newquot ) - dup length 4 <= [ - [ drop f ] swap - [ literalize [ t ] ] { } map>assoc linear-case-quot - ] [ - unique [ key? ] curry - ] if ; - -\ member? [ - dup sequence? [ member-quot ] [ drop f ] if -] 1 define-transform - -: memq-quot ( seq -- newquot ) - [ [ dupd eq? ] curry [ drop t ] ] { } map>assoc - [ drop f ] suffix [ cond ] curry ; - -\ memq? [ - dup sequence? [ memq-quot ] [ drop f ] if -] 1 define-transform - -! Index search -\ index [ - dup sequence? [ - dup length 4 >= [ - dup length zip >hashtable '[ _ at ] - ] [ drop f ] if - ] [ drop f ] if -] 1 define-transform - -! Shuffling -: nths-quot ( indices -- quot ) - [ [ '[ _ swap nth ] ] map ] [ length ] bi - '[ _ cleave _ narray ] ; - -\ shuffle [ - shuffle-mapping nths-quot -] 1 define-transform From 062e33f8fbbf45aa49413ff9b1d5a5ca1b9db933 Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Thu, 16 Jul 2009 00:43:54 -0500 Subject: [PATCH 49/96] fixing stupid bug in propagation --- .../tree/propagation/transforms/transforms.factor | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/basis/compiler/tree/propagation/transforms/transforms.factor b/basis/compiler/tree/propagation/transforms/transforms.factor index 1441897b07..60f1db5093 100644 --- a/basis/compiler/tree/propagation/transforms/transforms.factor +++ b/basis/compiler/tree/propagation/transforms/transforms.factor @@ -61,20 +61,16 @@ IN: compiler.tree.propagation.transforms } case ] "custom-inlining" set-word-prop -: prepare-partial-eval ( #call n -- value-infos ? ) - ERROR: bad-partial-eval quot word ; : check-effect ( quot word -- ) 2dup [ infer ] [ stack-effect ] bi* effect<= [ 2drop ] [ bad-partial-eval ] if ; -: values ( #call n -- infos ) - [ in-d>> ] dip tail* [ value-info ] map ; - :: define-partial-eval ( word quot n -- ) word [ - n values + in-d>> n tail* + [ value-info ] map dup [ literal?>> ] all? [ [ literal>> ] map n firstn From 9f926ab88cd2388d7e7a3b9c55bac9cd4e628a39 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 16 Jul 2009 02:17:58 -0500 Subject: [PATCH 50/96] compiler.cfg.block-joining: join basic blocks connected by a single edge to improve effectiveness of local optimizations --- .../cfg/block-joining/block-joining.factor | 44 +++++++++++++++++++ .../cfg/instructions/instructions.factor | 22 ++++++++++ basis/compiler/cfg/optimizer/optimizer.factor | 3 ++ basis/compiler/cfg/tco/tco.factor | 3 +- basis/compiler/utilities/utilities.factor | 4 +- 5 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 basis/compiler/cfg/block-joining/block-joining.factor diff --git a/basis/compiler/cfg/block-joining/block-joining.factor b/basis/compiler/cfg/block-joining/block-joining.factor new file mode 100644 index 0000000000..39d9a64c41 --- /dev/null +++ b/basis/compiler/cfg/block-joining/block-joining.factor @@ -0,0 +1,44 @@ +! Copyright (C) 2009 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: accessors combinators.short-circuit kernel sequences math +compiler.utilities compiler.cfg compiler.cfg.instructions compiler.cfg.rpo +compiler.cfg.utilities ; +IN: compiler.cfg.block-joining + +! Joining blocks that are not calls and are connected by a single CFG edge. +! Predecessors must be recomputed after this. Also this pass does not +! update ##phi nodes and should therefore only run before stack analysis. + +: kill-vreg-block? ( bb -- ? ) + instructions>> { + [ length 2 >= ] + [ penultimate kill-vreg-insn? ] + } 1&& ; + +: predecessor ( bb -- pred ) + predecessors>> first ; inline + +: join-block? ( bb -- ? ) + { + [ kill-vreg-block? not ] + [ predecessors>> length 1 = ] + [ predecessor kill-vreg-block? not ] + [ predecessor successors>> length 1 = ] + [ [ predecessor ] keep back-edge? not ] + } 1&& ; + +: join-instructions ( bb pred -- ) + [ instructions>> ] bi@ dup pop* push-all ; + +: update-successors ( bb pred -- ) + [ successors>> ] dip (>>successors) ; + +: join-block ( bb pred -- ) + [ join-instructions ] [ update-successors ] 2bi ; + +: join-blocks ( cfg -- cfg' ) + dup post-order [ + dup join-block? + [ dup predecessor join-block ] [ drop ] if + ] each + cfg-changed ; diff --git a/basis/compiler/cfg/instructions/instructions.factor b/basis/compiler/cfg/instructions/instructions.factor index 910cb1992b..2f2668df8b 100644 --- a/basis/compiler/cfg/instructions/instructions.factor +++ b/basis/compiler/cfg/instructions/instructions.factor @@ -223,3 +223,25 @@ INSN: _reload dst class n ; INSN: _copy dst src class ; INSN: _spill-counts counts ; +! Instructions that poison the stack state +UNION: poison-insn + ##jump + ##return + ##callback-return + ##fixnum-mul-tail + ##fixnum-add-tail + ##fixnum-sub-tail ; + +! Instructions that kill all live vregs +UNION: kill-vreg-insn + poison-insn + ##stack-frame + ##call + ##prologue + ##epilogue + ##fixnum-mul + ##fixnum-add + ##fixnum-sub + ##alien-invoke + ##alien-indirect + ##alien-callback ; diff --git a/basis/compiler/cfg/optimizer/optimizer.factor b/basis/compiler/cfg/optimizer/optimizer.factor index e16fb734e1..1af0fcbc53 100644 --- a/basis/compiler/cfg/optimizer/optimizer.factor +++ b/basis/compiler/cfg/optimizer/optimizer.factor @@ -6,6 +6,7 @@ compiler.cfg.predecessors compiler.cfg.useless-conditionals compiler.cfg.stack-analysis compiler.cfg.branch-splitting +compiler.cfg.block-joining compiler.cfg.alias-analysis compiler.cfg.value-numbering compiler.cfg.dce @@ -31,6 +32,8 @@ SYMBOL: check-optimizer? delete-useless-conditionals compute-predecessors split-branches + join-blocks + compute-predecessors stack-analysis compute-liveness alias-analysis diff --git a/basis/compiler/cfg/tco/tco.factor b/basis/compiler/cfg/tco/tco.factor index 5fa2e1b042..8be9c15b04 100644 --- a/basis/compiler/cfg/tco/tco.factor +++ b/basis/compiler/cfg/tco/tco.factor @@ -2,6 +2,7 @@ ! See http://factorcode.org/license.txt for BSD license. USING: accessors combinators.short-circuit kernel math namespaces sequences fry combinators +compiler.utilities compiler.cfg compiler.cfg.rpo compiler.cfg.hats @@ -19,8 +20,6 @@ IN: compiler.cfg.tco [ second ##return? ] } 1&& ; -: penultimate ( seq -- elt ) [ length 2 - ] keep nth ; - : tail-call? ( bb -- ? ) { [ instructions>> { [ length 2 >= ] [ last ##branch? ] } 1&& ] diff --git a/basis/compiler/utilities/utilities.factor b/basis/compiler/utilities/utilities.factor index ac276b6e41..c21be39adb 100644 --- a/basis/compiler/utilities/utilities.factor +++ b/basis/compiler/utilities/utilities.factor @@ -27,4 +27,6 @@ SYMBOL: yield-hook yield-hook [ [ ] ] initialize : alist-max ( alist -- pair ) - [ ] [ [ [ second ] bi@ > ] most ] map-reduce ; \ No newline at end of file + [ ] [ [ [ second ] bi@ > ] most ] map-reduce ; + +: penultimate ( seq -- elt ) [ length 2 - ] keep nth ; From 884e41dd9c0d18c794a3e61a2a4da36ca59a734e Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 16 Jul 2009 02:42:01 -0500 Subject: [PATCH 51/96] compiler.cfg.linear-scan.live-intervals: remove bogus assertion --- .../linear-scan/live-intervals/live-intervals.factor | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/basis/compiler/cfg/linear-scan/live-intervals/live-intervals.factor b/basis/compiler/cfg/linear-scan/live-intervals/live-intervals.factor index bf7e8bc042..d2fa661136 100644 --- a/basis/compiler/cfg/linear-scan/live-intervals/live-intervals.factor +++ b/basis/compiler/cfg/linear-scan/live-intervals/live-intervals.factor @@ -122,10 +122,10 @@ M: ##copy-float compute-live-intervals* dup ranges>> [ first from>> ] [ last to>> ] bi [ >>start ] [ >>end ] bi* drop ; -: check-start/end ( live-interval -- ) - [ [ start>> ] [ uses>> first ] bi assert= ] - [ [ end>> ] [ uses>> last ] bi assert= ] - bi ; +ERROR: bad-live-interval live-interval ; + +: check-start ( live-interval -- ) + dup start>> -1 = [ bad-live-interval ] [ drop ] if ; : finish-live-intervals ( live-intervals -- ) ! Since live intervals are computed in a backward order, we have @@ -135,7 +135,7 @@ M: ##copy-float compute-live-intervals* [ ranges>> reverse-here ] [ uses>> reverse-here ] [ compute-start/end ] - [ check-start/end ] + [ check-start ] } cleave ] each ; From 4931ab0d5fa05c0a35f5be016d73a6d93c0f5683 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 16 Jul 2009 03:30:11 -0500 Subject: [PATCH 52/96] benchmark: run each benchmark 5 times and take the best time --- extra/benchmark/benchmark.factor | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/extra/benchmark/benchmark.factor b/extra/benchmark/benchmark.factor index ca71e22e9f..23809f2744 100755 --- a/extra/benchmark/benchmark.factor +++ b/extra/benchmark/benchmark.factor @@ -2,7 +2,7 @@ ! See http://factorcode.org/license.txt for BSD license. USING: kernel vocabs vocabs.loader tools.time vocabs.hierarchy arrays assocs io.styles io help.markup prettyprint sequences -continuations debugger math namespaces memory ; +continuations debugger math namespaces memory fry ; IN: benchmark +: (run-benchmark) ( vocab -- time ) + [ 5 ] dip '[ gc [ _ run ] benchmark ] replicate infimum ; + : run-benchmark ( vocab -- ) [ "=== " write print flush ] [ - [ [ require ] [ gc [ run ] benchmark ] [ ] tri timings ] + [ [ require ] [ (run-benchmark) ] [ ] tri timings ] [ swap errors ] recover get set-at ] bi ; @@ -24,6 +27,7 @@ PRIVATE> V{ } clone timings set V{ } clone errors set "benchmark" child-vocab-names + [ find-vocab-root ] filter [ run-benchmark ] each timings get errors get From fc0e0f19245f522e7064dcf7e12bc0540bb97432 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 16 Jul 2009 05:50:44 -0500 Subject: [PATCH 53/96] compiler.cfg.block-joining: relax join heuristic --- basis/compiler/cfg/block-joining/block-joining.factor | 1 - 1 file changed, 1 deletion(-) diff --git a/basis/compiler/cfg/block-joining/block-joining.factor b/basis/compiler/cfg/block-joining/block-joining.factor index 39d9a64c41..982f0866e6 100644 --- a/basis/compiler/cfg/block-joining/block-joining.factor +++ b/basis/compiler/cfg/block-joining/block-joining.factor @@ -20,7 +20,6 @@ IN: compiler.cfg.block-joining : join-block? ( bb -- ? ) { - [ kill-vreg-block? not ] [ predecessors>> length 1 = ] [ predecessor kill-vreg-block? not ] [ predecessor successors>> length 1 = ] From 685e32b091f754ac53fcaac0c5f6800a34f33e81 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 16 Jul 2009 16:43:14 -0500 Subject: [PATCH 54/96] compiler.cfg.stack-analysis: global optimization work in progress --- .../cfg/stack-analysis/merge/merge.factor | 1 + .../cfg/stack-analysis/stack-analysis.factor | 42 +++---------------- .../cfg/stack-analysis/state/state.factor | 6 ++- 3 files changed, 11 insertions(+), 38 deletions(-) diff --git a/basis/compiler/cfg/stack-analysis/merge/merge.factor b/basis/compiler/cfg/stack-analysis/merge/merge.factor index cb0ad7d615..a53fd7494e 100644 --- a/basis/compiler/cfg/stack-analysis/merge/merge.factor +++ b/basis/compiler/cfg/stack-analysis/merge/merge.factor @@ -92,6 +92,7 @@ SYMBOL: added-phis :: multiple-predecessors ( bb states -- state ) states [ not ] any? [ + bb add-to-work-list ] [ [ H{ } clone added-instructions set diff --git a/basis/compiler/cfg/stack-analysis/stack-analysis.factor b/basis/compiler/cfg/stack-analysis/stack-analysis.factor index 48a4b79783..51baea71a9 100644 --- a/basis/compiler/cfg/stack-analysis/stack-analysis.factor +++ b/basis/compiler/cfg/stack-analysis/stack-analysis.factor @@ -14,9 +14,7 @@ compiler.cfg.stack-analysis.merge compiler.cfg.utilities ; IN: compiler.cfg.stack-analysis -SYMBOL: work-list - -: add-to-work-list ( bb -- ) work-list get push-front ; +SYMBOL: global-optimization? : redundant-replace? ( vreg loc -- ? ) dup state get untranslate-loc n>> 0 < @@ -70,7 +68,8 @@ UNION: sync-if-back-edge [ [ predecessors>> ] keep '[ _ back-edge? ] any? ] any? ; M: sync-if-back-edge visit - sync-state? [ sync-state ] when , ; + global-optimization? get [ sync-state? [ sync-state ] when ] unless + , ; : eliminate-peek ( dst src -- ) ! the requested stack location is already in 'src' @@ -87,31 +86,8 @@ M: ##replace visit M: ##copy visit [ call-next-method ] [ record-copy ] bi ; -! Instructions that poison the stack state -UNION: poison-insn - ##jump - ##return - ##callback-return - ##fixnum-mul-tail - ##fixnum-add-tail - ##fixnum-sub-tail ; - M: poison-insn visit call-next-method poison-state ; -! Instructions that kill all live vregs -UNION: kill-vreg-insn - poison-insn - ##stack-frame - ##call - ##prologue - ##epilogue - ##fixnum-mul - ##fixnum-add - ##fixnum-sub - ##alien-invoke - ##alien-indirect - ##alien-callback ; - M: kill-vreg-insn visit sync-state , ; ! Maps basic-blocks to states @@ -142,21 +118,13 @@ SYMBOLS: state-in state-out ; ] 2bi ] V{ } make >>instructions drop ; -: visit-successors ( bb -- ) - dup successors>> [ - 2dup back-edge? [ 2drop ] [ nip add-to-work-list ] if - ] with each ; - -: process-work-list ( -- ) - work-list get [ visit-block ] slurp-deque ; - : stack-analysis ( cfg -- cfg' ) [ work-list set H{ } clone copies set H{ } clone state-in set H{ } clone state-out set - dup [ add-to-work-list ] each-basic-block - process-work-list + dup [ visit-block ] each-basic-block + global-optimization? get [ work-list get [ visit-block ] slurp-deque ] when cfg-changed ] with-scope ; diff --git a/basis/compiler/cfg/stack-analysis/state/state.factor b/basis/compiler/cfg/stack-analysis/state/state.factor index f701b84763..25fa249853 100644 --- a/basis/compiler/cfg/stack-analysis/state/state.factor +++ b/basis/compiler/cfg/stack-analysis/state/state.factor @@ -1,6 +1,6 @@ ! Copyright (C) 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: kernel accessors namespaces assocs sets math +USING: kernel accessors namespaces assocs sets math deques compiler.cfg.registers ; IN: compiler.cfg.stack-analysis.state @@ -47,3 +47,7 @@ M: rs-loc translate-loc [ n>> ] [ rs-height>> ] bi* - ; GENERIC# untranslate-loc 1 ( loc state -- loc' ) M: ds-loc untranslate-loc [ n>> ] [ ds-height>> ] bi* + ; M: rs-loc untranslate-loc [ n>> ] [ rs-height>> ] bi* + ; + +SYMBOL: work-list + +: add-to-work-list ( bb -- ) work-list get push-front ; From e76dce8aff2a2b4950343f58a3fc22b26410a7a9 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 16 Jul 2009 18:29:40 -0500 Subject: [PATCH 55/96] Overflowing fixnum intrinsics now expand into several CFG nodes. This speeds up the common case since only the uncommon case is now a stack syncpoint --- .../branch-splitting-tests.factor | 40 ++-- .../branch-splitting/branch-splitting.factor | 4 +- .../build-stack-frame.factor | 8 +- basis/compiler/cfg/builder/builder.factor | 11 +- basis/compiler/cfg/checker/checker.factor | 6 +- basis/compiler/cfg/def-use/def-use.factor | 3 +- basis/compiler/cfg/hats/hats.factor | 4 +- .../cfg/instructions/instructions.factor | 30 ++- .../cfg/intrinsics/fixnum/fixnum.factor | 30 ++- .../compiler/cfg/intrinsics/intrinsics.factor | 6 +- .../cfg/linear-scan/linear-scan-tests.factor | 207 +----------------- .../cfg/linearization/linearization.factor | 17 +- basis/compiler/cfg/renaming/renaming.factor | 10 - .../cfg/stack-analysis/stack-analysis.factor | 3 +- basis/compiler/cfg/tco/tco.factor | 17 -- .../cfg/two-operand/two-operand.factor | 2 + basis/compiler/cfg/utilities/utilities.factor | 12 + basis/compiler/codegen/codegen.factor | 16 +- basis/compiler/tree/debugger/debugger.factor | 17 +- .../tree/finalization/finalization.factor | 3 + .../modular-arithmetic-tests.factor | 4 +- basis/cpu/architecture/architecture.factor | 9 +- basis/cpu/x86/32/32.factor | 2 - basis/cpu/x86/64/64.factor | 5 - basis/cpu/x86/x86.factor | 81 +------ 25 files changed, 143 insertions(+), 404 deletions(-) diff --git a/basis/compiler/cfg/branch-splitting/branch-splitting-tests.factor b/basis/compiler/cfg/branch-splitting/branch-splitting-tests.factor index fbaaf92203..89f26f7928 100644 --- a/basis/compiler/cfg/branch-splitting/branch-splitting-tests.factor +++ b/basis/compiler/cfg/branch-splitting/branch-splitting-tests.factor @@ -1,6 +1,6 @@ USING: accessors assocs compiler.cfg compiler.cfg.branch-splitting compiler.cfg.debugger -compiler.cfg.predecessors compiler.cfg.rpo fry kernel +compiler.cfg.predecessors compiler.cfg.rpo compiler.cfg.instructions fry kernel tools.test namespaces sequences vectors ; IN: compiler.cfg.branch-splitting.tests @@ -20,31 +20,31 @@ IN: compiler.cfg.branch-splitting.tests : test-branch-splitting ( -- ) cfg new 0 get >>entry check-branch-splitting ; -V{ } 0 test-bb +V{ T{ ##branch } } 0 test-bb -V{ } 1 test-bb +V{ T{ ##branch } } 1 test-bb -V{ } 2 test-bb +V{ T{ ##branch } } 2 test-bb -V{ } 3 test-bb +V{ T{ ##branch } } 3 test-bb -V{ } 4 test-bb +V{ T{ ##branch } } 4 test-bb test-diamond [ ] [ test-branch-splitting ] unit-test -V{ } 0 test-bb +V{ T{ ##branch } } 0 test-bb -V{ } 1 test-bb +V{ T{ ##branch } } 1 test-bb -V{ } 2 test-bb +V{ T{ ##branch } } 2 test-bb -V{ } 3 test-bb +V{ T{ ##branch } } 3 test-bb -V{ } 4 test-bb +V{ T{ ##branch } } 4 test-bb -V{ } 5 test-bb +V{ T{ ##branch } } 5 test-bb 0 get 1 get 2 get V{ } 2sequence >>successors drop @@ -54,15 +54,15 @@ V{ } 5 test-bb [ ] [ test-branch-splitting ] unit-test -V{ } 0 test-bb +V{ T{ ##branch } } 0 test-bb -V{ } 1 test-bb +V{ T{ ##branch } } 1 test-bb -V{ } 2 test-bb +V{ T{ ##branch } } 2 test-bb -V{ } 3 test-bb +V{ T{ ##branch } } 3 test-bb -V{ } 4 test-bb +V{ T{ ##branch } } 4 test-bb 0 get 1 get 2 get V{ } 2sequence >>successors drop @@ -72,11 +72,11 @@ V{ } 4 test-bb [ ] [ test-branch-splitting ] unit-test -V{ } 0 test-bb +V{ T{ ##branch } } 0 test-bb -V{ } 1 test-bb +V{ T{ ##branch } } 1 test-bb -V{ } 2 test-bb +V{ T{ ##branch } } 2 test-bb 0 get 1 get 2 get V{ } 2sequence >>successors drop diff --git a/basis/compiler/cfg/branch-splitting/branch-splitting.factor b/basis/compiler/cfg/branch-splitting/branch-splitting.factor index 9d6e59e4da..2ab476e20c 100644 --- a/basis/compiler/cfg/branch-splitting/branch-splitting.factor +++ b/basis/compiler/cfg/branch-splitting/branch-splitting.factor @@ -63,7 +63,9 @@ IN: compiler.cfg.branch-splitting UNION: irrelevant ##peek ##replace ##inc-d ##inc-r ; : split-instructions? ( insns -- ? ) - [ irrelevant? not ] count 5 <= ; + [ [ irrelevant? not ] count 5 <= ] + [ last ##fixnum-overflow? not ] + bi and ; : split-branch? ( bb -- ? ) { diff --git a/basis/compiler/cfg/build-stack-frame/build-stack-frame.factor b/basis/compiler/cfg/build-stack-frame/build-stack-frame.factor index e5be2d9eb9..71798da6fc 100644 --- a/basis/compiler/cfg/build-stack-frame/build-stack-frame.factor +++ b/basis/compiler/cfg/build-stack-frame/build-stack-frame.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2008 Slava Pestov. +! Copyright (C) 2008, 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: namespaces accessors math.order assocs kernel sequences combinators make classes words cpu.architecture @@ -36,12 +36,6 @@ M: insn compute-stack-frame* ] when ; \ _spill t frame-required? set-word-prop -\ ##fixnum-add t frame-required? set-word-prop -\ ##fixnum-sub t frame-required? set-word-prop -\ ##fixnum-mul t frame-required? set-word-prop -\ ##fixnum-add-tail f frame-required? set-word-prop -\ ##fixnum-sub-tail f frame-required? set-word-prop -\ ##fixnum-mul-tail f frame-required? set-word-prop : compute-stack-frame ( insns -- ) frame-required? off diff --git a/basis/compiler/cfg/builder/builder.factor b/basis/compiler/cfg/builder/builder.factor index 991fd2e20d..c866835ac5 100755 --- a/basis/compiler/cfg/builder/builder.factor +++ b/basis/compiler/cfg/builder/builder.factor @@ -98,17 +98,10 @@ M: #recursive emit-node ! #if : emit-branch ( obj -- final-bb ) - [ - begin-basic-block - emit-nodes - basic-block get dup [ ##branch ] when - ] with-scope ; + [ emit-nodes ] with-branch ; : emit-if ( node -- ) - children>> [ emit-branch ] map - end-basic-block - begin-basic-block - basic-block get '[ [ _ swap successors>> push ] when* ] each ; + children>> [ emit-branch ] map emit-conditional ; : ##branch-t ( vreg -- ) \ f tag-number cc/= ##compare-imm-branch ; diff --git a/basis/compiler/cfg/checker/checker.factor b/basis/compiler/cfg/checker/checker.factor index e7d9dbdd9c..49ea775600 100644 --- a/basis/compiler/cfg/checker/checker.factor +++ b/basis/compiler/cfg/checker/checker.factor @@ -16,9 +16,9 @@ ERROR: last-insn-not-a-jump insn ; [ ##return? ] [ ##callback-return? ] [ ##jump? ] - [ ##fixnum-add-tail? ] - [ ##fixnum-sub-tail? ] - [ ##fixnum-mul-tail? ] + [ ##fixnum-add? ] + [ ##fixnum-sub? ] + [ ##fixnum-mul? ] [ ##no-tco? ] } 1|| [ drop ] [ last-insn-not-a-jump ] if ; diff --git a/basis/compiler/cfg/def-use/def-use.factor b/basis/compiler/cfg/def-use/def-use.factor index 43ea89f284..c8a9d1861b 100644 --- a/basis/compiler/cfg/def-use/def-use.factor +++ b/basis/compiler/cfg/def-use/def-use.factor @@ -8,6 +8,7 @@ GENERIC: temp-vregs ( insn -- seq ) GENERIC: uses-vregs ( insn -- seq ) M: ##flushable defs-vregs dst>> 1array ; +M: ##fixnum-overflow defs-vregs dst>> 1array ; M: insn defs-vregs drop f ; M: ##write-barrier temp-vregs [ card#>> ] [ table>> ] bi 2array ; @@ -21,8 +22,6 @@ M: ##set-string-nth-fast temp-vregs temp>> 1array ; M: ##compare temp-vregs temp>> 1array ; M: ##compare-imm temp-vregs temp>> 1array ; M: ##compare-float temp-vregs temp>> 1array ; -M: ##fixnum-mul temp-vregs [ temp1>> ] [ temp2>> ] bi 2array ; -M: ##fixnum-mul-tail temp-vregs [ temp1>> ] [ temp2>> ] bi 2array ; M: ##gc temp-vregs [ temp1>> ] [ temp2>> ] bi 2array ; M: _dispatch temp-vregs temp>> 1array ; M: insn temp-vregs drop f ; diff --git a/basis/compiler/cfg/hats/hats.factor b/basis/compiler/cfg/hats/hats.factor index b61f091fad..986438d055 100644 --- a/basis/compiler/cfg/hats/hats.factor +++ b/basis/compiler/cfg/hats/hats.factor @@ -73,5 +73,7 @@ IN: compiler.cfg.hats : ^^offset>slot ( vreg -- vreg' ) cell 4 = [ 1 ^^shr-imm ] when ; inline : ^^tag-fixnum ( src -- dst ) ^^i1 ##tag-fixnum ; inline : ^^untag-fixnum ( src -- dst ) ^^i1 ##untag-fixnum ; inline - +: ^^fixnum-add ( src1 src2 -- dst ) ^^i2 ##fixnum-add ; inline +: ^^fixnum-sub ( src1 src2 -- dst ) ^^i2 ##fixnum-sub ; inline +: ^^fixnum-mul ( src1 src2 -- dst ) ^^i2 ##fixnum-mul ; inline : ^^phi ( inputs -- dst ) ^^i1 ##phi ; inline \ No newline at end of file diff --git a/basis/compiler/cfg/instructions/instructions.factor b/basis/compiler/cfg/instructions/instructions.factor index 2f2668df8b..8d4b0f40ad 100644 --- a/basis/compiler/cfg/instructions/instructions.factor +++ b/basis/compiler/cfg/instructions/instructions.factor @@ -92,15 +92,6 @@ INSN: ##sar-imm < ##binary-imm ; INSN: ##not < ##unary ; INSN: ##log2 < ##unary ; -! Overflowing arithmetic -TUPLE: ##fixnum-overflow < insn src1 src2 ; -INSN: ##fixnum-add < ##fixnum-overflow ; -INSN: ##fixnum-add-tail < ##fixnum-overflow ; -INSN: ##fixnum-sub < ##fixnum-overflow ; -INSN: ##fixnum-sub-tail < ##fixnum-overflow ; -INSN: ##fixnum-mul < ##fixnum-overflow temp1 temp2 ; -INSN: ##fixnum-mul-tail < ##fixnum-overflow temp1 temp2 ; - : ##tag-fixnum ( dst src -- ) tag-bits get ##shl-imm ; inline : ##untag-fixnum ( dst src -- ) tag-bits get ##sar-imm ; inline @@ -181,6 +172,7 @@ INSN: ##loop-entry ; INSN: ##phi < ##pure inputs ; +! Conditionals TUPLE: ##conditional-branch < insn { src1 vreg } { src2 vreg } cc ; INSN: ##compare-branch < ##conditional-branch ; @@ -192,6 +184,12 @@ INSN: ##compare-imm < ##binary-imm cc temp ; INSN: ##compare-float-branch < ##conditional-branch ; INSN: ##compare-float < ##binary cc temp ; +! Overflowing arithmetic +TUPLE: ##fixnum-overflow < insn { dst vreg } { src1 vreg } { src2 vreg } ; +INSN: ##fixnum-add < ##fixnum-overflow ; +INSN: ##fixnum-sub < ##fixnum-overflow ; +INSN: ##fixnum-mul < ##fixnum-overflow ; + INSN: ##gc { temp1 vreg } { temp2 vreg } live-values ; ! Instructions used by machine IR only. @@ -212,6 +210,12 @@ INSN: _compare-imm-branch label { src1 vreg } { src2 integer } cc ; INSN: _compare-float-branch < _conditional-branch ; +! Overflowing arithmetic +TUPLE: _fixnum-overflow < insn label { dst vreg } { src1 vreg } { src2 vreg } ; +INSN: _fixnum-add < _fixnum-overflow ; +INSN: _fixnum-sub < _fixnum-overflow ; +INSN: _fixnum-mul < _fixnum-overflow ; + TUPLE: spill-slot n ; C: spill-slot INSN: _gc { temp1 vreg } { temp2 vreg } gc-roots gc-root-count gc-root-size ; @@ -227,10 +231,7 @@ INSN: _spill-counts counts ; UNION: poison-insn ##jump ##return - ##callback-return - ##fixnum-mul-tail - ##fixnum-add-tail - ##fixnum-sub-tail ; + ##callback-return ; ! Instructions that kill all live vregs UNION: kill-vreg-insn @@ -239,9 +240,6 @@ UNION: kill-vreg-insn ##call ##prologue ##epilogue - ##fixnum-mul - ##fixnum-add - ##fixnum-sub ##alien-invoke ##alien-indirect ##alien-callback ; diff --git a/basis/compiler/cfg/intrinsics/fixnum/fixnum.factor b/basis/compiler/cfg/intrinsics/fixnum/fixnum.factor index 2a82139e13..57eb7fb63c 100644 --- a/basis/compiler/cfg/intrinsics/fixnum/fixnum.factor +++ b/basis/compiler/cfg/intrinsics/fixnum/fixnum.factor @@ -1,7 +1,7 @@ ! Copyright (C) 2008, 2009 Slava Pestov, Doug Coleman. ! See http://factorcode.org/license.txt for BSD license. USING: sequences accessors layouts kernel math namespaces -combinators fry +combinators fry arrays compiler.tree.propagation.info compiler.cfg.hats compiler.cfg.stacks @@ -54,6 +54,28 @@ IN: compiler.cfg.intrinsics.fixnum : emit-fixnum>bignum ( -- ) ds-pop ^^untag-fixnum ^^integer>bignum ds-push ; -: emit-fixnum-overflow-op ( quot -- next ) - [ 2inputs 1 ##inc-d ] dip call ##branch - begin-basic-block ; inline +: emit-no-overflow-case ( dst -- final-bb ) + [ -2 ##inc-d ds-push ] with-branch ; + +: emit-overflow-case ( word -- final-bb ) + [ ##call ] with-branch ; + +: emit-fixnum-overflow-op ( quot word -- ) + [ [ D 1 ^^peek D 0 ^^peek ] dip call ] dip + [ emit-no-overflow-case ] [ emit-overflow-case ] bi* 2array + emit-conditional ; inline + +: fixnum+overflow ( x y -- z ) [ >bignum ] bi@ + ; + +: fixnum-overflow ( x y -- z ) [ >bignum ] bi@ - ; + +: fixnum*overflow ( x y -- z ) [ >bignum ] bi@ * ; + +: emit-fixnum+ ( -- ) + [ ^^fixnum-add ] \ fixnum+overflow emit-fixnum-overflow-op ; + +: emit-fixnum- ( -- ) + [ ^^fixnum-sub ] \ fixnum-overflow emit-fixnum-overflow-op ; + +: emit-fixnum* ( -- ) + [ ^^untag-fixnum ^^fixnum-mul ] \ fixnum*overflow emit-fixnum-overflow-op ; \ No newline at end of file diff --git a/basis/compiler/cfg/intrinsics/intrinsics.factor b/basis/compiler/cfg/intrinsics/intrinsics.factor index ed94ec36d9..e4a7b8972a 100644 --- a/basis/compiler/cfg/intrinsics/intrinsics.factor +++ b/basis/compiler/cfg/intrinsics/intrinsics.factor @@ -100,9 +100,9 @@ IN: compiler.cfg.intrinsics { \ kernel.private:tag [ drop emit-tag ] } { \ kernel.private:getenv [ emit-getenv ] } { \ math.private:both-fixnums? [ drop emit-both-fixnums? ] } - { \ math.private:fixnum+ [ drop [ ##fixnum-add ] emit-fixnum-overflow-op ] } - { \ math.private:fixnum- [ drop [ ##fixnum-sub ] emit-fixnum-overflow-op ] } - { \ math.private:fixnum* [ drop [ i i ##fixnum-mul ] emit-fixnum-overflow-op ] } + { \ math.private:fixnum+ [ drop emit-fixnum+ ] } + { \ math.private:fixnum- [ drop emit-fixnum- ] } + { \ math.private:fixnum* [ drop emit-fixnum* ] } { \ math.private:fixnum+fast [ drop [ ^^add ] emit-fixnum-op ] } { \ math.private:fixnum-fast [ drop [ ^^sub ] emit-fixnum-op ] } { \ math.private:fixnum-bitand [ drop [ ^^and ] emit-fixnum-op ] } diff --git a/basis/compiler/cfg/linear-scan/linear-scan-tests.factor b/basis/compiler/cfg/linear-scan/linear-scan-tests.factor index fd95a3e09c..63da100b02 100644 --- a/basis/compiler/cfg/linear-scan/linear-scan-tests.factor +++ b/basis/compiler/cfg/linear-scan/linear-scan-tests.factor @@ -2159,12 +2159,7 @@ V{ T{ ##replace { src V int-regs 85 } { loc D 1 } } T{ ##replace { src V int-regs 89 } { loc D 4 } } T{ ##replace { src V int-regs 96 } { loc R 0 } } - T{ ##fixnum-mul - { src1 V int-regs 128 } - { src2 V int-regs 129 } - { temp1 V int-regs 132 } - { temp2 V int-regs 133 } - } + T{ ##replace { src V int-regs 129 } { loc R 0 } } T{ ##branch } } 2 test-bb @@ -2255,206 +2250,6 @@ V{ [ ] [ { 1 2 3 4 5 } test-linear-scan-on-cfg ] unit-test -! Another push-all reduction to demonstrate numbering anamoly -V{ T{ ##prologue } T{ ##branch } } -0 test-bb - -V{ - T{ ##peek { dst V int-regs 1 } { loc D 0 } } - T{ ##slot-imm - { dst V int-regs 5 } - { obj V int-regs 1 } - { slot 3 } - { tag 7 } - } - T{ ##peek { dst V int-regs 7 } { loc D 1 } } - T{ ##slot-imm - { dst V int-regs 12 } - { obj V int-regs 7 } - { slot 1 } - { tag 6 } - } - T{ ##add - { dst V int-regs 25 } - { src1 V int-regs 5 } - { src2 V int-regs 12 } - } - T{ ##compare-branch - { src1 V int-regs 25 } - { src2 V int-regs 5 } - { cc cc> } - } -} -1 test-bb - -V{ - T{ ##slot-imm - { dst V int-regs 41 } - { obj V int-regs 1 } - { slot 2 } - { tag 7 } - } - T{ ##slot-imm - { dst V int-regs 44 } - { obj V int-regs 41 } - { slot 1 } - { tag 6 } - } - T{ ##compare-branch - { src1 V int-regs 25 } - { src2 V int-regs 44 } - { cc cc> } - } -} -2 test-bb - -V{ - T{ ##add-imm - { dst V int-regs 54 } - { src1 V int-regs 25 } - { src2 8 } - } - T{ ##load-immediate { dst V int-regs 55 } { val 24 } } - T{ ##inc-d { n 4 } } - T{ ##inc-r { n 1 } } - T{ ##replace { src V int-regs 25 } { loc D 2 } } - T{ ##replace { src V int-regs 1 } { loc D 3 } } - T{ ##replace { src V int-regs 5 } { loc D 4 } } - T{ ##replace { src V int-regs 1 } { loc D 1 } } - T{ ##replace { src V int-regs 54 } { loc D 0 } } - T{ ##replace { src V int-regs 12 } { loc R 0 } } - T{ ##fixnum-mul - { src1 V int-regs 54 } - { src2 V int-regs 55 } - { temp1 V int-regs 58 } - { temp2 V int-regs 59 } - } - T{ ##branch } -} -3 test-bb - -V{ - T{ ##peek { dst V int-regs 60 } { loc D 1 } } - T{ ##slot-imm - { dst V int-regs 66 } - { obj V int-regs 60 } - { slot 2 } - { tag 7 } - } - T{ ##inc-d { n 1 } } - T{ ##inc-r { n 1 } } - T{ ##replace { src V int-regs 66 } { loc D 0 } } - T{ ##replace { src V int-regs 60 } { loc R 0 } } - T{ ##call { word resize-string } } - T{ ##branch } -} -4 test-bb - -V{ - T{ ##peek { dst V int-regs 67 } { loc R 0 } } - T{ ##peek { dst V int-regs 68 } { loc D 0 } } - T{ ##set-slot-imm - { src V int-regs 68 } - { obj V int-regs 67 } - { slot 2 } - { tag 7 } - } - T{ ##write-barrier - { src V int-regs 67 } - { card# V int-regs 75 } - { table V int-regs 76 } - } - T{ ##inc-d { n -1 } } - T{ ##inc-r { n -1 } } - T{ ##peek { dst V int-regs 94 } { loc D 0 } } - T{ ##peek { dst V int-regs 96 } { loc D 1 } } - T{ ##peek { dst V int-regs 98 } { loc D 2 } } - T{ ##peek { dst V int-regs 100 } { loc D 3 } } - T{ ##peek { dst V int-regs 102 } { loc D 4 } } - T{ ##peek { dst V int-regs 106 } { loc R 0 } } - T{ ##copy { dst V int-regs 95 } { src V int-regs 94 } } - T{ ##copy { dst V int-regs 97 } { src V int-regs 96 } } - T{ ##copy { dst V int-regs 99 } { src V int-regs 98 } } - T{ ##copy { dst V int-regs 101 } { src V int-regs 100 } } - T{ ##copy { dst V int-regs 103 } { src V int-regs 102 } } - T{ ##copy { dst V int-regs 107 } { src V int-regs 106 } } - T{ ##branch } -} -5 test-bb - -V{ - T{ ##inc-d { n 3 } } - T{ ##inc-r { n 1 } } - T{ ##copy { dst V int-regs 95 } { src V int-regs 1 } } - T{ ##copy { dst V int-regs 97 } { src V int-regs 25 } } - T{ ##copy { dst V int-regs 99 } { src V int-regs 1 } } - T{ ##copy { dst V int-regs 101 } { src V int-regs 5 } } - T{ ##copy { dst V int-regs 103 } { src V int-regs 7 } } - T{ ##copy { dst V int-regs 107 } { src V int-regs 12 } } - T{ ##branch } -} -6 test-bb - -V{ - T{ ##load-immediate - { dst V int-regs 78 } - { val 4611686018427387896 } - } - T{ ##and - { dst V int-regs 81 } - { src1 V int-regs 97 } - { src2 V int-regs 78 } - } - T{ ##set-slot-imm - { src V int-regs 81 } - { obj V int-regs 95 } - { slot 3 } - { tag 7 } - } - T{ ##inc-d { n -2 } } - T{ ##copy { dst V int-regs 110 } { src V int-regs 99 } } - T{ ##copy { dst V int-regs 111 } { src V int-regs 101 } } - T{ ##copy { dst V int-regs 112 } { src V int-regs 103 } } - T{ ##copy { dst V int-regs 117 } { src V int-regs 107 } } - T{ ##branch } -} -7 test-bb - -V{ - T{ ##inc-d { n 1 } } - T{ ##inc-r { n 1 } } - T{ ##copy { dst V int-regs 110 } { src V int-regs 1 } } - T{ ##copy { dst V int-regs 111 } { src V int-regs 5 } } - T{ ##copy { dst V int-regs 112 } { src V int-regs 7 } } - T{ ##copy { dst V int-regs 117 } { src V int-regs 12 } } - T{ ##branch } -} -8 test-bb - -V{ - T{ ##inc-d { n 1 } } - T{ ##inc-r { n -1 } } - T{ ##replace { src V int-regs 117 } { loc D 0 } } - T{ ##replace { src V int-regs 110 } { loc D 1 } } - T{ ##replace { src V int-regs 111 } { loc D 2 } } - T{ ##replace { src V int-regs 112 } { loc D 3 } } - T{ ##epilogue } - T{ ##return } -} -9 test-bb - -0 get 1 get 1vector >>successors drop -1 get 2 get 8 get V{ } 2sequence >>successors drop -2 get 3 get 6 get V{ } 2sequence >>successors drop -3 get 4 get 1vector >>successors drop -4 get 5 get 1vector >>successors drop -5 get 7 get 1vector >>successors drop -6 get 7 get 1vector >>successors drop -7 get 9 get 1vector >>successors drop -8 get 9 get 1vector >>successors drop - -[ ] [ { 1 2 3 4 5 } test-linear-scan-on-cfg ] unit-test - ! Fencepost error in assignment pass V{ T{ ##branch } } 0 test-bb diff --git a/basis/compiler/cfg/linearization/linearization.factor b/basis/compiler/cfg/linearization/linearization.factor index a75ac064d9..9faa1e9e38 100755 --- a/basis/compiler/cfg/linearization/linearization.factor +++ b/basis/compiler/cfg/linearization/linearization.factor @@ -31,8 +31,10 @@ M: insn linearize-insn , drop ; M: ##branch linearize-insn drop dup successors>> first emit-branch ; +: successors ( bb -- first second ) successors>> first2 ; inline + : (binary-conditional) ( basic-block insn -- basic-block successor1 successor2 src1 src2 cc ) - [ dup successors>> first2 ] + [ dup successors ] [ [ src1>> ] [ src2>> ] [ cc>> ] tri ] bi* ; inline : binary-conditional ( basic-block insn -- basic-block successor label2 src1 src2 cc ) @@ -52,6 +54,19 @@ M: ##compare-imm-branch linearize-insn M: ##compare-float-branch linearize-insn [ binary-conditional _compare-float-branch ] with-regs emit-branch ; +: overflow-conditional ( basic-block insn -- basic-block successor label2 dst src1 src2 ) + [ dup successors number>> ] + [ [ dst>> ] [ src1>> ] [ src2>> ] tri ] bi* ; inline + +M: ##fixnum-add linearize-insn + [ overflow-conditional _fixnum-add ] with-regs emit-branch ; + +M: ##fixnum-sub linearize-insn + [ overflow-conditional _fixnum-sub ] with-regs emit-branch ; + +M: ##fixnum-mul linearize-insn + [ overflow-conditional _fixnum-mul ] with-regs emit-branch ; + M: ##dispatch linearize-insn swap [ [ [ src>> ] [ temp>> ] bi _dispatch ] with-regs ] diff --git a/basis/compiler/cfg/renaming/renaming.factor b/basis/compiler/cfg/renaming/renaming.factor index 228d72483c..efc841e21f 100644 --- a/basis/compiler/cfg/renaming/renaming.factor +++ b/basis/compiler/cfg/renaming/renaming.factor @@ -136,16 +136,6 @@ M: ##compare-imm fresh-insn-temps M: ##compare-float fresh-insn-temps [ fresh-vreg ] change-temp drop ; -M: ##fixnum-mul fresh-insn-temps - [ fresh-vreg ] change-temp1 - [ fresh-vreg ] change-temp2 - drop ; - -M: ##fixnum-mul-tail fresh-insn-temps - [ fresh-vreg ] change-temp1 - [ fresh-vreg ] change-temp2 - drop ; - M: ##gc fresh-insn-temps [ fresh-vreg ] change-temp1 [ fresh-vreg ] change-temp2 diff --git a/basis/compiler/cfg/stack-analysis/stack-analysis.factor b/basis/compiler/cfg/stack-analysis/stack-analysis.factor index 51baea71a9..e46460a741 100644 --- a/basis/compiler/cfg/stack-analysis/stack-analysis.factor +++ b/basis/compiler/cfg/stack-analysis/stack-analysis.factor @@ -61,7 +61,8 @@ UNION: sync-if-back-edge ##conditional-branch ##compare-imm-branch ##dispatch - ##loop-entry ; + ##loop-entry + ##fixnum-overflow ; : sync-state? ( -- ? ) basic-block get successors>> diff --git a/basis/compiler/cfg/tco/tco.factor b/basis/compiler/cfg/tco/tco.factor index 8be9c15b04..3dbdf148e9 100644 --- a/basis/compiler/cfg/tco/tco.factor +++ b/basis/compiler/cfg/tco/tco.factor @@ -53,28 +53,11 @@ IN: compiler.cfg.tco [ [ cfg get entry>> successors>> first ] dip successors>> push ] tri ; -: fixnum-tail-call? ( bb -- ? ) - instructions>> penultimate - { [ ##fixnum-add? ] [ ##fixnum-sub? ] [ ##fixnum-mul? ] } 1|| ; - -GENERIC: convert-fixnum-tail-call* ( src1 src2 insn -- insn' ) - -M: ##fixnum-add convert-fixnum-tail-call* drop \ ##fixnum-add-tail new-insn ; -M: ##fixnum-sub convert-fixnum-tail-call* drop \ ##fixnum-sub-tail new-insn ; -M: ##fixnum-mul convert-fixnum-tail-call* drop i i \ ##fixnum-mul-tail new-insn ; - -: convert-fixnum-tail-call ( bb -- ) - [ - [ src1>> ] [ src2>> ] [ ] tri - convert-fixnum-tail-call* - ] convert-tail-call ; - : optimize-tail-call ( bb -- ) dup tail-call? [ { { [ dup loop-tail-call? ] [ convert-loop-tail-call ] } { [ dup word-tail-call? ] [ convert-word-tail-call ] } - { [ dup fixnum-tail-call? ] [ convert-fixnum-tail-call ] } [ drop ] } cond ] [ drop ] if ; diff --git a/basis/compiler/cfg/two-operand/two-operand.factor b/basis/compiler/cfg/two-operand/two-operand.factor index d30a02b0d3..98bbfb9cd0 100644 --- a/basis/compiler/cfg/two-operand/two-operand.factor +++ b/basis/compiler/cfg/two-operand/two-operand.factor @@ -44,6 +44,8 @@ M: ##shl-imm convert-two-operand* convert-two-operand/integer ; M: ##shr-imm convert-two-operand* convert-two-operand/integer ; M: ##sar-imm convert-two-operand* convert-two-operand/integer ; +M: ##fixnum-overflow convert-two-operand* convert-two-operand/integer ; + M: ##add-float convert-two-operand* convert-two-operand/float ; M: ##sub-float convert-two-operand* convert-two-operand/float ; M: ##mul-float convert-two-operand* convert-two-operand/float ; diff --git a/basis/compiler/cfg/utilities/utilities.factor b/basis/compiler/cfg/utilities/utilities.factor index 288fa403dd..9cb8bf26f9 100644 --- a/basis/compiler/cfg/utilities/utilities.factor +++ b/basis/compiler/cfg/utilities/utilities.factor @@ -36,6 +36,18 @@ IN: compiler.cfg.utilities : emit-primitive ( node -- ) word>> ##call ##branch begin-basic-block ; +: with-branch ( quot -- final-bb ) + [ + begin-basic-block + call + basic-block get dup [ ##branch ] when + ] with-scope ; inline + +: emit-conditional ( branches -- ) + end-basic-block + begin-basic-block + basic-block get '[ [ _ swap successors>> push ] when* ] each ; + : back-edge? ( from to -- ? ) [ number>> ] bi@ >= ; diff --git a/basis/compiler/codegen/codegen.factor b/basis/compiler/codegen/codegen.factor index df6e91aec9..42c6bf45cb 100755 --- a/basis/compiler/codegen/codegen.factor +++ b/basis/compiler/codegen/codegen.factor @@ -171,18 +171,12 @@ M: ##sar-imm generate-insn dst/src1/src2 %sar-imm ; M: ##not generate-insn dst/src %not ; M: ##log2 generate-insn dst/src %log2 ; -: src1/src2 ( insn -- src1 src2 ) - [ src1>> register ] [ src2>> register ] bi ; inline +: label/dst/src1/src2 ( insn -- label dst src1 src2 ) + [ label>> lookup-label ] [ dst/src1/src2 ] bi ; inline -: src1/src2/temp1/temp2 ( insn -- src1 src2 temp1 temp2 ) - [ src1/src2 ] [ temp1>> register ] [ temp2>> register ] tri ; inline - -M: ##fixnum-add generate-insn src1/src2 %fixnum-add ; -M: ##fixnum-add-tail generate-insn src1/src2 %fixnum-add-tail ; -M: ##fixnum-sub generate-insn src1/src2 %fixnum-sub ; -M: ##fixnum-sub-tail generate-insn src1/src2 %fixnum-sub-tail ; -M: ##fixnum-mul generate-insn src1/src2/temp1/temp2 %fixnum-mul ; -M: ##fixnum-mul-tail generate-insn src1/src2/temp1/temp2 %fixnum-mul-tail ; +M: _fixnum-add generate-insn label/dst/src1/src2 %fixnum-add ; +M: _fixnum-sub generate-insn label/dst/src1/src2 %fixnum-sub ; +M: _fixnum-mul generate-insn label/dst/src1/src2 %fixnum-mul ; : dst/src/temp ( insn -- dst src temp ) [ dst/src ] [ temp>> register ] bi ; inline diff --git a/basis/compiler/tree/debugger/debugger.factor b/basis/compiler/tree/debugger/debugger.factor index 4fc4f4814b..d6906d6348 100644 --- a/basis/compiler/tree/debugger/debugger.factor +++ b/basis/compiler/tree/debugger/debugger.factor @@ -1,4 +1,4 @@ -! Copyright (C) 2006, 2008 Slava Pestov. +! Copyright (C) 2006, 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: kernel assocs match fry accessors namespaces make effects sequences sequences.private quotations generic macros arrays @@ -15,7 +15,9 @@ compiler.tree.def-use compiler.tree.builder compiler.tree.optimizer compiler.tree.combinators -compiler.tree.checker ; +compiler.tree.checker +compiler.tree.dead-code +compiler.tree.modular-arithmetic ; FROM: fry => _ ; RENAME: _ match => __ IN: compiler.tree.debugger @@ -201,8 +203,15 @@ SYMBOL: node-count : cleaned-up-tree ( quot -- nodes ) [ - check-optimizer? on - build-tree optimize-tree + build-tree + analyze-recursive + normalize + propagate + cleanup + compute-def-use + remove-dead-code + compute-def-use + optimize-modular-arithmetic ] with-scope ; : inlined? ( quot seq/word -- ? ) diff --git a/basis/compiler/tree/finalization/finalization.factor b/basis/compiler/tree/finalization/finalization.factor index 0e72deb6fa..4c17399c95 100644 --- a/basis/compiler/tree/finalization/finalization.factor +++ b/basis/compiler/tree/finalization/finalization.factor @@ -46,6 +46,9 @@ M: predicate finalize-word [ drop ] } cond ; +M: math-partial finalize-word + dup primitive? [ drop ] [ nip cached-expansion ] if ; + M: word finalize-word drop ; M: #call finalize* diff --git a/basis/compiler/tree/modular-arithmetic/modular-arithmetic-tests.factor b/basis/compiler/tree/modular-arithmetic/modular-arithmetic-tests.factor index 7fb1b3d5ac..13555d45f7 100644 --- a/basis/compiler/tree/modular-arithmetic/modular-arithmetic-tests.factor +++ b/basis/compiler/tree/modular-arithmetic/modular-arithmetic-tests.factor @@ -4,12 +4,12 @@ IN: compiler.tree.modular-arithmetic.tests USING: kernel kernel.private tools.test math math.partial-dispatch math.private accessors slots.private sequences strings sbufs compiler.tree.builder -compiler.tree.optimizer +compiler.tree.normalization compiler.tree.debugger alien.accessors layouts combinators byte-arrays ; : test-modular-arithmetic ( quot -- quot' ) - build-tree optimize-tree nodes>quot ; + cleaned-up-tree nodes>quot ; [ [ >R >fixnum R> >fixnum fixnum+fast ] ] [ [ { integer integer } declare + >fixnum ] test-modular-arithmetic ] unit-test diff --git a/basis/cpu/architecture/architecture.factor b/basis/cpu/architecture/architecture.factor index 556424f50c..41dd53fa8a 100644 --- a/basis/cpu/architecture/architecture.factor +++ b/basis/cpu/architecture/architecture.factor @@ -82,12 +82,9 @@ HOOK: %sar-imm cpu ( dst src1 src2 -- ) HOOK: %not cpu ( dst src -- ) HOOK: %log2 cpu ( dst src -- ) -HOOK: %fixnum-add cpu ( src1 src2 -- ) -HOOK: %fixnum-add-tail cpu ( src1 src2 -- ) -HOOK: %fixnum-sub cpu ( src1 src2 -- ) -HOOK: %fixnum-sub-tail cpu ( src1 src2 -- ) -HOOK: %fixnum-mul cpu ( src1 src2 temp1 temp2 -- ) -HOOK: %fixnum-mul-tail cpu ( src1 src2 temp1 temp2 -- ) +HOOK: %fixnum-add cpu ( label dst src1 src2 -- ) +HOOK: %fixnum-sub cpu ( label dst src1 src2 -- ) +HOOK: %fixnum-mul cpu ( label dst src1 src2 -- ) HOOK: %integer>bignum cpu ( dst src temp -- ) HOOK: %bignum>integer cpu ( dst src temp -- ) diff --git a/basis/cpu/x86/32/32.factor b/basis/cpu/x86/32/32.factor index 96a99f4d5e..727131aa25 100755 --- a/basis/cpu/x86/32/32.factor +++ b/basis/cpu/x86/32/32.factor @@ -51,8 +51,6 @@ M: x86.32 reserved-area-size 0 ; M: x86.32 %alien-invoke 0 CALL rc-relative rel-dlsym ; -M: x86.32 %alien-invoke-tail 0 JMP rc-relative rel-dlsym ; - M: x86.32 return-struct-in-registers? ( c-type -- ? ) c-type [ return-in-registers?>> ] diff --git a/basis/cpu/x86/64/64.factor b/basis/cpu/x86/64/64.factor index 5390d7e0c8..8eb04eb2b5 100644 --- a/basis/cpu/x86/64/64.factor +++ b/basis/cpu/x86/64/64.factor @@ -167,11 +167,6 @@ M: x86.64 %alien-invoke rc-absolute-cell rel-dlsym R11 CALL ; -M: x86.64 %alien-invoke-tail - R11 0 MOV - rc-absolute-cell rel-dlsym - R11 JMP ; - M: x86.64 %prepare-alien-indirect ( -- ) "unbox_alien" f %alien-invoke RBP RAX MOV ; diff --git a/basis/cpu/x86/x86.factor b/basis/cpu/x86/x86.factor index bb2ee620e3..bd39549973 100644 --- a/basis/cpu/x86/x86.factor +++ b/basis/cpu/x86/x86.factor @@ -129,83 +129,18 @@ M: x86 %log2 BSR ; : ?MOV ( dst src -- ) 2dup = [ 2drop ] [ MOV ] if ; inline -:: move>args ( src1 src2 -- ) - { - { [ src1 param-reg-2 = ] [ param-reg-1 src2 ?MOV param-reg-1 param-reg-2 XCHG ] } - { [ src1 param-reg-1 = ] [ param-reg-2 src2 ?MOV ] } - { [ src2 param-reg-1 = ] [ param-reg-2 src1 ?MOV param-reg-1 param-reg-2 XCHG ] } - { [ src2 param-reg-2 = ] [ param-reg-1 src1 ?MOV ] } - [ - param-reg-1 src1 MOV - param-reg-2 src2 MOV - ] - } cond ; - -HOOK: %alien-invoke-tail cpu ( func dll -- ) - -:: overflow-template ( src1 src2 insn inverse func -- ) - PFsR6G6;@iCx61JIbe;}eW{9w*v}pb6 z3wpR1{%ivNl|Z{=V`k+Xq{?-;jdb;wuS3CyyhRE}wSGb@Z`Rg!6iY*_=JvdBcySLf zw5x2azz_xo@N_~|8rvgTU;sBFt*0@$dhZp%mcm#AE&1uUYzu-K)YLQe-gK!8bbTFa z=gnPN@+ji%%L>nz@VC=0gxme{p%RKNdts89JoL&}ZoFB?HwsaSx3HWp*wU+Zo8(h37DY$D=j)qQ2*OX&`b+s=laM8)V~R#`kgmX$F>56 z)9Y8RD!o zr<-`C5{PgsOAylUmFZF~YNwr{*<~&li{kZe_%6Oe(DajW552^~5l$=z<7kXZ&i?&glI5^I!^QD)*E+lg*B!aI{1@F((Qx`o zU9d+nb(Qp-6}e*DJar{-)0C?Xp$uxUJ+`;E0MoQj-%FjA+#MXAEHC*`9ru-h-bH<(hifK66oV1)hIX3OH85Fi?bUpUVg+ zAN$^V4H)Z$RexBza%CkB`D$=>ImqfKt6&RhzdMluSOwl4&2>%xB zXsxk63rRVcoGt6(Q$M=pJ`;ewlM$m(?_^vM*m-kfK~L_TTJKpS+5#aPHm0WNAQiaQ zo_FJ(Cmgx_C5OhtTW7g4O@*$#kX%rRZz-Jd?dWfvs(Mt|>f3RFNv%skmQq#Mwa*DSUs# z@il7=E{>m~*5P|yt}?Xo@#p5_HRD?EM7ZpwdKaQ$W#yA zKEfA`CkW*Lp98Jpk1ztXqk27uekjC%>KKQZP^d_DKX!zpZ=P%@bPaY-v-LiV6z%x9 znHAw!0i!@Tw!tVh&9xyagyR&98sWI*hzjS2tE0ltz;&1rPU0|nw38}~p)nGE0u}K> z-5hnD1n!Kwt_?qpx*iGlL|y+1_d(s@hhIe9h=gB3-DrV_&>@`ZV29DpM_@Q)Q9kP2}Q3kjp0Kf;coJ=`%vV34pfIi&@1D5Z*VNqC!(6}FaJ6&ta zEO%r=5o}kzQ~J`d(%WUtP5lApnToM4g6%lNx6h;2q~5J@bYB=oKD+xBzd);T3 zN<6Smjx_ruRdeKB*X3Ky=@T32yFzYDeRxMuXYi0Su6 z!XGPlLa3XcFLhy|d#9%d@0HNOR6|8!cx{E z=#?`58;B$vBFuVHYC_j(eU=*)&KUiii4JSka?egM!t)kmG72JVfCPG=TUh9rg)*L5 zC}f#45ek_r;~7DO_7KBsa3ujxFO*0CqK$+u#lC z50s&dtcpM*WjqDG@aglR_`Zhpl*gYug5B>Ichz#l6Vq>~i38gPJwF41PV>yTM9()m z-wvJQzE`pAM))C3!<~<(JXOrB;bls3qJFLpJtE~RbOMd%ra4&6tc*Vkk-vsSNurfM zGALY+en4MxR|Z0qK^|@j&~fS2kx+sw5MI$fEBXJsV}QpvoWlptzDOBsDTu(oa~g#b z78MmPPVk2C#sd)0k(dAoA02>(j=?A}y$Hu?b_z}c66HEcAxDUh0NBo!lECd@aMX1_ zQPF`77(42QqZ6QyUM8TyHW-VsQ|QQ{Zlawp!5_hnrYSf2h`HeW0hF6)#G)x&30SaA zN!sxDFd0yH z>J-2Z;0(MB6_o>=`=UwU4XEfdznuX1_xwy)2_ecB`1o%>lj-08{zmM7{_ofE|M}m) zwr^WviE#C0N8R3YEQxf6*`RSUf3)jIhMx-mGkfCxKmL8d^Ff1u|JuL)`{3#cKI}YV z|KFF?E)Y-&whb5}-gdPfN-6NN8D{LfU^kpH6YTJsiPACP=Blvusi(EuDUQRIa89>3 zOt;V?Z*RL^b$G{QR+`PWI#Xaxzea*Q|5ms90rA^w+ZEpL*1Sdo-ZRHcUVeY4U?y;k zxpO6W?9R-#&AoM!G1Q2cRJ-Ni@b-+Ci)oen0xOs&U9r!kqmWrnFdce6h;SgG;#zAcOwYTA9aU5 z9#1Be{u18tP@?dD3AC$ivlv7qS%peIlU#&K>dSlr(TfMA^0e}^a2-Lr_+N`gxabG4 zH+^LxW3{B#yV)tUAp(_DhzJgm$Ur8_kV{Ds)U6D_6aqRCNrtVSNnpuP zd{ar+TIc8_`_tsUTyx!WJ3&{JQA%Q$RlAOpa8|>MJErgL+Kxv;JX^KN5@e3L3_B37 zLTl0z0#$lcQR1_IZ&Crihfe>Y-AMMdBtO>-ns_|vC(HNKbSWPgT8qeL)?J6_b1%}! z3i9yz$w6dCE_Wa0Q+(4ApCPWP)ji~m#1hD$#ig_$GIB0%Yl4Sl%8+pz%aNQgiASa! z_h_^o{^i+?v>ol2!o&H&*;270F46s`50>`)@nC$y{g#qX{dT>n9k zE%qT9!mCsMwyor{@Wyn&7<&5nG0#(z)pB=$z5MF&i@9d-mz+u3x*4;Es+h1Crw9}O z!sExV^}%_9LI(cNXpye@o#n4AXW!er3-+ERsx8xd)#?iCNr>+!9E|M7yE*X%v@&9*r!o3PI8XQ z?9AGsZv|pzWwA){M(La1Y>vgla}z(lRng8_B!Wn&Voq689!`FgoB*E{)lLgkyH`Nk zVt(Y>#7R8mV%4ZtQ@P-YH$2RXK`U)$eOC;(3KZOIZ>O7{I%asYmDhLcej3G(P0YO) z_db6@-oO0pjQ+@I>gm(x?^(CGcIeNDPEwTLxi_ci_9if6QlYqqWmD;lBISe0t>$~3 z_+ExA!t!4-x6lm7Za&pj)Xt<7dD8nCJrMbY-N(W{KZXNsmAiH5?=x4!$DMQz&KW0A zxBtLy$hBGDf;qz|9Y=e@&HdefiN;+X^CliSD-9IK(@+k2PM(0n+m4{Gz zIegSwui`nmI#%;eWIgTCE@#4@JmPV>J4@Rv&mEE1cEuZ2pRo=xIFI=1kI3Lsz*4r1 zxwxoh0hxc3+;I^OB(PiZP{4VJ_uagMc75M$RXIF&$z3H9?tuBSa7E!zMR!U6+*(jz z-oA7)2yE(yS1;z(7%lyPu#xxAK=?)MjCd;X{1Din3@{U`#;4u~bAN*{?9n;1bDt0{ zTk0RcU5w*ajkJX3d16kR3LhKK6P$i7p5W`{sK+udx)(j|AN6$Po1y8DPQwzDwmj(gKc+T z_0I-a3#snx7UqTu_}>raKoK}BTuQ5mlSt`If;+nId5C|#knMDr)9?9P94F>(mP0GJ zqM;D%x(}vShajzn`<0f0cQOiJ&GG~I?eP}4qA@`Mf#pXz0k()8{vE(?0mQXkbTF(` zr?%3wdov@7)Fqu!SBD#J((N>-PUoFNHatJez}cA3ZbkEx6N9_ifSdbEXl+jc<*Ps; za|zAI8RnPbglTQ{@%;`IGCpTpoDk;}1O-(SKiw8XpG$sq4Cu5BDdkIqs=;?smn005 z!rw+zqY2*Q0tfxg4F{N!FCUDYE$YsJKd_8-5kyXXcwTf5d4q^nUj0?%ddAAE>{h=Y zshP3Hp{M2Woo)Z;BW!COd+4b)YQ6F{!OzPyzwz*2ky99LXSQgVIx81MyK9&G+QVv7 zA*BWRs_xtB*=^pnVE=N<#!U_l!z80rF@)zaEzWckpiHJa#ZA%J2NZU8N*&YE1e9Q( zh2ivTCC~d&ZSUZg@z4+w#W^5XzWcs;)!jY=v$nj8Bt=6M$~55g2?o#{M3lQ5IAB%Y zs9+L>iB0DOk=jkxvHJL_HmwFqc|#GLlX&yZ1$`05+=eaNR`qLJI6QnryjHFESLF65 z{pd?$TulXGw#fYRVh{RTMXSWy8jl2t@U#@SdpxTba}g%w|11ET)TbBXlu!Uu^He9j zXSa0av2{FILwf(Ca@pP!Gm72x6%6Z2+BhP^-;Lt9)6IiXv`5`J@c(^f!v|4R?q9@t zm~n{=Ijrn^nEkQU@Qm4X+!?jXBj0m#opG&{uU)H*0RG}-_O)xN78hTSVR83`Tz5v0 z4mge6pQ8A4E9p}fbnX@XwYn4MQWP%^eeh+T_HEhz{I)P|)T7K+UgLB`%~P`5xDFB#te2s-Tm@g(~-~5MwO!d;LgMa5K+yHd?b#4_Ah&?6Kt!`w_g?j$9QG@ z%`7LSxhl(6+~#pR#A+POBQ{re0sqY7cJIb6N7&xQsGkwF_3gEv;>#dcD?9%+3Qdoy&^8>eZ;@z2PSg%cLXj|YkH(fc!xmN4JA+MFKQ zw-9JoHTtg5^wGLAMHw4!26!0-4q?podkG{qgONzL{z+phY<)(^mv`ViD=AqvgqfQr zCBS5TypI!hkQ3L^gi|~ch>sQ~tut=ZzfWM?AVR6uO9F`@PH}5cH`2;)WP`cDJf~td zsT};5dOpO>RFw|wcptZdx|NdM;$ew*B_KB5OTpb=;TS97ipJ>3KQ!5{+&glGwFNioNPCtY3#im zwpJPw1`dWFz&UkHy>ZzN@gS^)ZAqukyz|Iy)zVQhBQtGV21p|^6#T@0w-#SVJCz^& zi%+5M{ZWf4POu${(@kQ=#oQdC&KLY{wDGSoKj~$$x?LLLowt99qlmiVy|3!L}J_ z@~k(jlpe!4$4}aA$=7V;6~8;X{#Fk|IadDF{|aMP2(yN1X78Jx<6g+>H}mH5J4a=K zQ^CSUkWwMv%OFnFjp_`f17IWFwoux|WG~I{q9=dSOCV&CJ}ptU_W;ALDoqe~1ddw( zQ}u}!qkKeg1SX*-Mj=akRM!V`X^8w()bniS&4X{6v{Ah6<>&J~KgmU(!EiKvZ>MT+ zGR2{;(SAY=FP^`ydEdOpK%tA$uWvOt>-@5%xZ{OzdvvA6QHTms8ZIZ^BoJv`G;?Rx zC-2+fYfp-P#VprJ{+#j%>>6yQ!Ebtjp$1qMEEx?D?y5com&bpYFeq}U@%CI`(>C?b zCxnzE|3Rg`KJL_dFvhN^dw*1Fio0xpJskNv#u9%KW6QAMz5jaO=jcK{!RT5gFeVDA z9QSyW6)RzB^^JC<*~>!{}sZn{Dw?zCkuUgiLu641|jvBvKV>%AJW_ho){ zbpTn`HTNp@7~qvU6-dmpy(Qm86Frl3LllJZl~xCX7B3}0ikF^0K}qTPxP*D0}<3+o+YZcZ={=4@0(A0g2; z<-T#Gl};gbXx!EyRt2=s6j7Iu?Xk8QBAMq?nVCqJ@V^M;i%Fan(~~%R zYofj5Q!4)bNVbO*Y9$@>nUpPTKNM9MhzKLX`PtePdn7er=~#aY4)s3LrCA8c|4$f& zHxN#54#xKk>VEd`%?U*dn_QfH0Ja(T66ZtAL)L#e(L^|S=Z*aKu~KGQ34VbIskYTx zm)c=^x9=nZF8#R$O!(w2?O4H(#Gid+t3F>`B*MqTN6}o5MzD|*5gieO724#pM-zp8 z$fuxiZb61yVKL+K;XM?Y{P_U;~;xp<^Az{)y@%)Rt2#2Z*WHV;W4 zwrb3GlUgblb}(+QM(5VA80;dchi8r~Ih*WaFgI4U@~10uw`ypFC<*d%-#o~Vm|lDW z2?*%&0zcqK8RVdDr%=|DUK&Tm^h|3|s{2gnP=J+%3SDD@f&p`5PFo&aqc_@%wfPs( zj9oL4!uzlmZQ2cRb6!0%47~A*;F^wp7SBU9U6@pxcxJXx1K6#d(V>ZE?W&E_rYT%M+zloy;z4fymSF#$zQc8dg zMyvmjCSA!2Prydmt}nbk`y#Xi^Zl`i?eNPO!j_(;Bg7;PO%*VY_QcU@VLi25#MJLr zXKMX;Yw3s?MqYV!2dMi>eYiZjmK)3g(SH0VdpUspemj_5XHltqzq5;ygiSM!HvrrC zE4%FeBD*dImvVY@j(A=4cvthDIuE=M`>b?_)^+*RZOn}t=7kd%cbI>5>y}l89c)V$ z_a6`gy^uC)yvNb_2n|DI1O5k@_#i1b9dZ4&d+cE^-p#yXs~%eO!@T#A9ytW=UI6v| zWreF&()YRn>uB`Y4PqCW;b^IA2HIizG`(SxN=Tk1+56I;8Gm^1WtYqFu6*Qf``Xr( zB8)>b@PomU=eE4OH@!Ifvc zo?D)-UWF9~EJr*|=$mML#dDj)f?U~}dRu>T*tEp*BiOaiceo$Xp`%DTg8ue+m#2-+ zJd5|RE)5<+H!U47#Niuq~AF*6&XqRWvYXm{EOa zikHR8Bwwn{Ki@Oxp}x_h9z==+$g^j8wK0UWGAP_xkPmrq3CYUpYg$ z#mn^RcfCScO?XYt?^tf$>9A2n(S*h;v9m-G5sJ0+JkdgYTak;gd}UoYIDO%r@bzvl za8Fa(CiwlA%a}2rfGQw>gFO{c3G3tTof>J=!+`?f)! zIq(!ow}n%)+}x?FDQp;)!W%yW|5kAZY~Z7B z-3XUCNep#Fy6v5LT;DCKdA41RhLVCv^042YSD|W6 zQ-b+l(3@LtL?WD74rGm-H!98T zk2(bIZ^jY-Pgzs&Qq#Nar03LTR>g0>tgnUTzptiBFKBPM+ByWcxG1BQ5iUXupz08O z$iaeS`LZlW$#h32yLZa}ZGmQ?UBTZYX&)#KjlHnV)hQT3m^ z{lX|(!h{%FQR0g7@8#ifjnWGoHD3a%$4W2i?I>m6Ru5TrRNKKwza;)nJ!H4a8!|i^ zzs$MCiTScx^+T*%;89W<2}@OWEtx)DmP-6d8DMl>%0Z+GEO|)lT0(VE^*&XK6!o+e zO1A~h6Kc^n^y;feGXK=5n=m#dqgbrYq(tx~AlgT>?+o zHMlRU>@oGNPd)TA1jrt9VN$goe*;Qj_iV?ZSxVpIE*~Bn_*k|gwgf)iIWVJWlo$8( z0p~z+UAAPA;I@9tfFAwCy2aT>ZO#rxA}=87b)X2 z2zw^)xSnLv_j!8KGC1!{R>B!PW*p7y?@l<8|E7!dMWy{Q)fVKi`9?Y<40u?GLN)nw zf1YZKnP)8YTwkh(l${hByaBj+=Wu8fc)xyJB+i?+652zXoX=bG?nrUQ<&n?5k^c(v zhMBY>e80&2ukr@xI>PJYevi)e+C9UpFI;h2pKR9m@@D>o)sEQiojeolMbU{}w~SG) zl@r_HyCFmBoLiSd959m?zqV9OUE}vfxX~qN^5Z5P?36J$I7s8kNU9Q_CQSASPYy<} z8b2*UtwxKln$sY~$Cnw0Z8x>-6KYz=ge% zzoje5^OMOyQebHr^^(AR%OF)h1Jb9n6L9_d^Xs&2OF+~0xLFd}mRZshkBFs<@L@WpM&6zR>^gvK^?!@K5 z*NEz9%y|faK7)z@?W8VDSywcDl=?|qvI@0Y0=oen*og1jB+zNnDx6}_q-Aht(W0&L zj{se?9!IlSS_C4qjRukjFVzhm)$4!=^EiBSXs3E^pg{1scObMOT6jijvwB*gY(sQ0 zw_@!X_vXfr;u6W{;HA2Zk&Ri(Zxky+^ON8cjQ5DLU&lL@ty00jm8IItpvb6Zl5D`H z(K`@xSf_WnfJcu+60%kbqwgVA5Y1PZlI}Xa^~r3IQE%2^Foi(OlKDINn21GpT2B6; zMdt;HJbIe}ZL|-=9jBH=7a1ht)Fdu<1QLLW{9f+lbFrPg?e)U*;dx^`rhkw-HxbU( z2XiL?_27@bnF`Jp%bT&EJ4*T8f37kzsF@YW9r;@|xZKfMtCZW>a=_Y5VK)o9 zf8Jl0$ADYJ)QeVWS>p^Ogro!?YUc+W&A8(IS%sc zibewz=51Pi(|O~}`9cuJv~PA>&1#53ZzoTwI6Q*KicU9P8F6aG&t}+?P?fQ6Wjn_4 z^;ZRV7wg-MiMKT%Li2yn+uU??zI-rOE~6fN`Q6)4onX5U>qdp)P&j=~E4M#)#3wxu zZ@OCIJb10v?v9Ng->B)`MVe6#t(;-!&i zS|aI~4hr#y(ed<$hhKftS})z<0~7qEAj_!xyU)LrC2iX~m>_%ST9|k2k=esDAM;D* zl%fVz6CXb{1`aEjZ?fRn5DhmGeyxuuBXKC6GmKG{#-9b~z$y%L!ChksYBdvls$XeB zfdt*Jr!Y8h!ElPDvBg*)6+xTn%G#XpRv+B{n7DAbxtNokh0A zh3BuTTw(r^(YV7Fp6|1%N-KV1XRDiU}KtzBQ)!Qag zA(1(Wiir2*fvLvZ3Z)9rR0)#S8&Aui_9vsS4AS)Vz3NE%dNErw=EmMzxJFms6|P~@ z;gbX=qir^DHSby$(h;&;su9Ug;dy5G4nnq3%XduIr58y)?owe%%A^v){oD-> z9SjA+yz-I}QU(>pdUfjs11lmXH7^J{m@%dt7Kbe&TPaZS7iIg#3f3i!xg>b%iFgvcI(7#`q(*!>_z$GDwZ^~!`Y~c=O$63!!gi;6R zp8vCJ1jaiDhu^0>A9Jp0(FDcVTEN-T|i;n}6;*{jxk1jUb^81NMKM#8juyUkuIizsYy`b%05Seq>vz zhklX>+2cdWny&%M0g%v#B(XC9iXI#Fn0Q(rUVkF_p1y*V?t z--ARQ2|@ywVs|tcnokQc&}*yJ0e~*O`%5XSBGVnU>^=|4x9O(~!KVG}MY-+U!|t!% z%wBv~&@=}w9C*vv>~Mk$2cLW|Rn=$#j>K2L4cpmlEx-GRTpL-GHT9~X<{JxT7+mdW zJQWC#;g^#a-L`_McdaVYKmFJVaj3}Bu30;JOZR6FLd(xW4LA}E93VTKdEp4BARgkn zd9dAis_QRBU60%D{F;=t7#nC^G??mpgIt+46FlqzwBq8%rgeVW13)Wy#GG0QTQQXM zb3P$Fm_*OC#+t(72fN3}axw(ljI23@Tc;j6h_oMNt8?f`obHsU>Ns03nvVqw1LE2o z$M1%*X;V{wRXg^OmU6#HCuw|oXY@RVUPD;#`QczG9e}h5O6HeNX&Lo13Z?VhnDbBK zYDodIN7^$iv{u?L3fu{S#eew|3}}!y_;hGzt0(9iFg85B2CBz%T=h7g zEAtQ{lmyiy;iJ79+A*-9v4}c4hO6lNC{8%&i?3kvR(9b3X~-EypNoi_&ct9ERu!1I?NSRe6D?!8X`x&?1_c z2*QhTG9PBF2nGU%Nk3~VOME9Ph-UF0sLrGQjSUcidiV=BG2xgO3yMuQ$|ji7|BKw{ z-Or7E*S`efSxddF3l0G<+2#y4Cx`ZY!Yn0sm?k*OoK-+CnyHE4jlU5gE=zp$cH88V zb=v1simBj8z~87H?GsveKfr`&ZL{1Cg;zEvB8*j@&pz>4(=va({xX9~zIuMT_es+1F zI&V;;RM-9m@2j8p)T7g+5zhe4N3=Uz&P}u(n^r=8FgsVKI80rum@wu@w#ZV~R?VVk zS}jH-9H`EtOhN=(r+PAkp9v;Eb7+^KXsB(U(@zn|G%PyJL_`&qAzj`dJqlPlX)_=< zGFRlg{W^Xiy9X#XReBhB2tOJ)sTD{b?U%%e0iO!<_^JpoF6LS#mvv`fWuWb4Id4 zks9jdIL=nu1q7;=QNzw`h-QEnvb+%EU_R8t4wh+BjlnigXl3vi{t2QMg?9dNuxi{u zJ^Iy=>a{O|>xF5M(SXAWj`?$-=djXPl?(o*e%0O?bt6V)@E@ICQmaqZFjz0OubgQl6!P#?RNL4=_|qZmDF*adYQdnF`U_5`U$AV zI}Vt_rRiN|2s(qh?nAz_Q%j=&h|v7(Y=qdJ=)Vx`*V8_pK$QzJ{-i9*rE6{Zw``4jsb!xyy} z9s8vGnN8v+J-VvWPq;(d!tMPOwK(t3MhX2Sg+a;AB=u3L&gsD0pW8fK9*MMm-bz*M zzEvKA3|pr7ex$ij|AtCSvHqq;@2$2e>8jolKej%fd*GrsLzWb~nfF}}6xM%ILw6va zf|GdQ1&6#v=6o3*1ug;pCMp&+ev0K_{BNNi|9Ukvt@h(D^5^)U@W5{JDE)G<$$jMT ze4jG{{3zt-v^FQ>IlW$7LqVwh4)Z)b-%x}jrsb6QiLD1(NAI+s_ARe!@{U{-0N3s!fqe-}N7|`~y0aPs7)D3-h^W_}TY}6aT{6dUzRWAbO zSN`X%^drC_Kl7PF_&QRs^(GA&J`}5V>w`YsR>LQK3GQa`PI`qwK)Td_Ck0-O53-$0 z`IGX7F(nDYp^0t8f?ZDxMBC&B)v?i` zvs%3q7g(A_RrpaDDGoi0L0x5U{J|6+8*2?3A3VCDl$Zd3BiG|=3*A#h@ zbtX;SU7pwo-qC`IiX}HWN#E%@-T$;2B)Z-&DC3Dp{l>J1W{P2#%E)MOwoU((VzFLv7e&MQvT+9H* zbyGVxbf>#=Yqz?aeDw!7V0$;~D48TJQLQ?-C#oVE%>qtd=JVgYK?3(8uk)D}rdEqL zCPX!yCo}-uF$(k8Uqh=AW20D_7i;ECc6W}Zg$a*4PtcGXr*^`04Cf;kUzoObv3lH* zn{%nFJ6O8>{E`CR^$g(}!i^Q-Hjzx6`(V`SYTFXvjwx^jjfxjIA(W_OXKfPXyZYNx z|1^gT7?5l9GPp8ocFzV)P#KaXk4SgY+esPp$BtC$4v?ScG|4w=8$MdNJYykPDatk} z+Bz7WN=o;YMbNr+rPGy-m>=$KYju$lMXLT>IKuA4Mb#v5g7eCM+*3e~zWmF+DhIPf z(?>S#K$fs*Vf!T7xObuyGfl?b)^XEnj+xnt^!C5J949>W!L-_GO#RlweUoly)a3Wo zl(LLDOTo!~EaP~ksM5kk>g!>IsQGaKVSHMYrMPW%^iJz%-#7V9e|K6fZK4u89IZG^ zezx{vAm}#(s%>7Z1lh}Hm511hY@A!S;X-0Szv-~UiNL?7xn&w6`Sg}EObU|JQ}SS`w{=%cPATfT$9RgRpZ>>ywYOV?hpdSh|=$&+iL zkqA!M!?3$wI+pa(r3~n8M~`>WyG%-V`9*_iwZG##VE#_5fN6Ep3P^ZK4vV0Dzg}H! zH}~Su%A3og)p_QvHn30~#dFx8rM-W4QJZ!}Ata zqoZTtwPPqk8tk88_eWEPmI?OTW_&3fu1nUQpWWnB z{}%QMW>h(wv`dfSB#n0GiMJ#$q&V!;UV&(-D^l6k;ak!FvniP?^tXBUhzqyNZW)WDujSTcD7l<;nWB zUeQQkx1-VcdQv-4Q!L+!t?_BaX$aQa;KdGba>s|EgqZ**7f^YRikOpe;Hxa`$U0g? zw3YuuiTrMea9iVMrI4Nk@GV9Az77#Epw}ZlR_%8L#t`lV-9Jnm8~Ehwe>tP>u>pEx z^*P6?JSwDkWFvrcKcvVAnK%VMiz;WEBRWVb)MpBmC6sl4J6f4 z+?FdZE|U{Svhz5cNSTQtR|_RnbRJ%HO?#k@B{cqzaq_>)l_IgKgSn!s+*h)nE6sZI zpz};OA|9~*Q?8u-_OtVFuitd6!STZPm~N@(m@9wP4~Ig-rK?OcK4gTd|EKk%`?JSF zShThpwMSj*{G~&CXqOfBjuPfhr{6+G`wm92?-BLWk}V`Md#Ge#ZRMN)ed)#coy>_v zm?3graGL;2BT1J`90?Bq-o@%%M0GdUVW_(KWGOOmZ%!fk7nC7SU!S0lWIXJSAYyEy zRX@eVi&qR|*F4_==GDlL*CD!vfxtsY2?M*VTB%D@c!~rME3LNC-I}ga^d8CL7oi%t zC)^%29dCsZj|99mycS0$ISEidKC;ZL(wITiL{q`v2U~$S97lxGTi^X zRwEfKrKLBg5Oc(wj@5`SlyEu%c;~5Y976kenOO~3m{U^JOT{=@TTbb#Lh5J!b95YX zbmaf{zGGgj;lPW+p{LwWzn>9xZ}v0d3Fn^>E~}(fxrkr0$f>I%b7kgny{_@_ntokw?c9$!7mdH32im=VT@d<72^&p?(!oWo9!uiWFwLX4f4Awh-u z_;Zn~(S(bK{d!TPXzLcZr71E)3C;GokJxWH5PM^@Qbf)Kw3+ zqJOl~>D6ep#+j${RdWSp=8K$-M+&x)`A2hBCYo1^6gCDmtm=#dT#Ll1<;>U4SpT=* z4C#X=r45s!{~8@HmC$yVz^4m*BgVKy#G_L<2geBYGjvK$E5@DA&^2eIc)8dTN*KX5 zNQcjFg7983f1B5o2L9)Wg6FslG@#?_ed$E(fXYfm{C>^8-TvsoT&J6&pBM zE%dSdKVOzm(*4|^97Ic#QEx^P{bzVer{NCU1eJGz(+yX z04wqTtlI#&A^WDvF^P__{;kiG&D-R-t=d`2T^=mwn`JPkVBB&-<`#lLPdd{!_YDjz zW4T(hRKSvsd=un`;5NSUH|49S8$G}gTV-CKJEIaJ1dJh?4l&BQqwYT^RyE^kJy0!F z84|e@^zG<17EBZGh2o7ku{D`Q`^VC2v&gb*oo_p-Ree1udP9d!j}X}!x96^?I%QP2 zm^wyOkT;S7s>P2Gk($Lz{3O@#m4nzpwaAvLF!LOgHb@Ero0FvQ8QHF-`~}5sv+1Ru z8`zkM4t9OVaCBw+I9M+Xu>JclNQ%U`e+76! z^tApwyYfw|9L$My7wXr7dYkB-8AFlx=l0pG1)TGi-?hOC9?+k0VAem!E^ypKH@?*N zFU}fw9eL?`uOY|fK?iyvV~lwH%KN>oe93#g?J>Y+4b6GHwfuB$C}uVDsH2CR))){B z0{7JiB>eCY2s6(P<`m;IWT=WFPkPeY_)PAMpQVBZ@<5z+hB>2M7hyIC*DEkHv@015 zsIBkAG|(;rFu;zefXSdwnZm>o&WkW1gfqBPiFOtTPUr66xINklSTiG>1Yk4>$G0$Y zgkvHMhIZ725pa8}cR&Cx>6bLnW>tp_mab?+hCb0;#G&*JEs&9;9E{LtiINb)(}n{h znq>7F6siS&2z8AF&ZVQ51Ls9ui-ZdbqyHam@4?m7+I4~M5C|<8sw4sur3*;6P^0uF zy$ML~y@>^cC@3IE$A%IqN(T`eQbLs~ND~wk6%`c(X(C1Lvq8_{sONh<Jf(9;{i3A7Cs0iZHiI-?_*~A72QAoT@g98Ua zqHvW&AP{UIf(zRnRVEmGMq|~o57)!|vrLNjbe2m*ri&w&1|}~~#&7GKrF&oVIC4d7 z2fXx#d%j?+vBR6foSw{w#=AY6AMW%R{=)Sx==lQIYUGO}S21T_EK4v#RFQ28}EKr%Mfv5_Hg+p+}jql{McZ`sa+@1IL zy*Um)g*a>>F9PJS%ek4*M8W6L;a4P+0QEyiQ;4E5w|pA4qZym0>cy1>QCfAyuqe7j zpmn59qWEaANzRVwuMo->Vj@9IBH6?!XB|QV%XUXRq?jN+PpEI(0-+rtYBj-g14N{9 zyEL35u?4#qi7sR$p5BhavM)gN1>?lXoGFN+V)l?GTQKA9E{NS6qCJ~Vj7V*|7Y?c7 zJwhN#zB>@(9>@}cE`?L&L(Kl&7Nckmk=sc(o3Rq+;SjrsI7H7j1(}f$*5OqC5JK`U zL^l8lZ4cZ34m&qEdm_AjpV}*a=bXg0`MK578d8&LcqC1mutb z2_ded$_lZ{M&R99A%3AtBm%_=z35otjfkl$$vXmdd%X7W_YUsvu^bW2tCAOlpiBZq za$0MgiLl8L!l)}`L4Y`mQfoONib;rm2of7Xu!Tczc)O}ti3M*6=Lf_ zAZEt)K{^_zLOfL>E*^s3hNS5t*~xRFg^+Yzc)KH5dlZg%`bL-dC|VAQA=FPvpwX&G zCUQe^F7^@%oZbu)m#{)xAUBg6yCfpe4oDoKDL@1J6a}u9tf$K$xd{)aK)OsMayy~9 zYz(&@rI|)(NstUgXCMVzNlqHLgD5j%nyphV&L3r+OlW76VogE;3)G17MOO3xkwk!= zC*U0}p=9w6W$-uMic-Wod_aL!F&%0j-f=rh8Sl6srOHEt+d@nPzke3*n2FNHJFZ8_ z$P-g&z`sk0!f8dp-?RzI$$c$7#+jIwi}NO)7sMSVo?rW>1#zb%@XoR*N78y|)LL-N zC6qhKxdP=$a()W(qSiBGwxa^@F3S0N`L@f;!Cllq3elA!3e1SCx@@YCQ^2JDcyxtN zNh;tCcsp4;WOV3fC${PJvH>Y>Z%Poa9&t{0S1tsW)j&08dz~jr=8DHb)4mQr>;Ack zARDt(5a2zKMipl_FfW?uG-&FT>@t`ZdByc<+La>4;fUc6H#$^!3n5@m*Way&*%rNQZPsy)s`=`}GOfk0w= z1xl+CqC5aG)8IIXi3!WH#DuYK)V{jXbRa@==-nKTcPONT6N7*?sB;=6Q{&T$l2Rl? zO~hEit)Q+z$RUW{M@xUY(uWa5v}{^{K7~_wltHvc0}xNefm7*k`8O%YzQWr*J4rml z@bL(=`vi~gQ~r)qR{a7D<`AoN5gvLR&OifohNH(2THS@sP+K@U7s?1nCqT^*+81hq z=xCsZaP%Ii4x+Jdh5e!jvBN8M>Av$>)ywklqX=Po81ccK`zF0`C zyV|UE9Jiy(vv6M%e?!bTGckd7S&6#+%hhZ75US%fgaqnb4M=t;nHWi}@h(0qk#K;G z451bvCZxA&QCtb{=1fB4D^u-khRfm5K)Cuf(n8Ta_ChQ%e*6T)-W$@oS2WWOGpf1Cy^e8lHhQ%C`o#$ji-@mrZbj$y zx}dh#T3${mo20HUwCx)-Kyu9Pkd!=$+T$AH;Ml9-mms^Ng@+M}m3EVR+yxCn2o^`$ zw@DDq1I;Mxha3s_G>GPwb`*Bvy2L@CE_zOQe-DZ&A0x(ZInJ67L0cU+T??nlGKj*? zG1ts# z`en}i!f}owQ}6P=n0gBc$v`#k$^F!FpIe_L+pVTr4|X=aRkaE zQRG;*o;Tb{r5a;P@p4Eu1lp+}cSHKEa5(+t0Jj9FLb_TsoW4LSoNC|!Mb1`3xhi%t z)rh0#xwyx7v|3!N-e>Auje_W(wp!@YgS;6jn}ZDd2uRTyX}a*vuPX!|N6)x{O~;?`%^Uk`slE@p%<=Jx3`Y77EdPc%C_P z5A&bxxu6kSjh|#_sHICri_nhI)SbExhQ}F!gCh=o_EFF~r&H-7;L}*jC35yz&j{W)Twon-E zAyY~adyWA3m-3wfy$dRg$d`r&DXd&T=GCjqwEqC$ zvegY)z4+9-1LK6WyL;P&B~B+pxEc6Ol_(qIw*yW%<`vto2Qq3x>pc`-;5y zTDBh_Aos4%m=MR>jG4}zEB8Cx$j)g#4=YDb7=QeJFHv6_R@JOIP9#pO1l$J_ z8dzEtS^x4Tw$gMrOMH`~#Nhwlg=z4g{A{}%w8!faUFw!oM@Tk1(2&Ds`_ET?O`~X=F>dQ-tc=b&dz)L06%WQt#78J&<2|?^Co?( zHR@lMR~7V5R)5944q-s-W7L|ywF6rEmYqi@d7L(j&mCn_Cl2loQCT>KKA-Q)3t~|Sg$+hdumC~;)1*kl-A5XN~ zlp9T~Yj5sI!P*<(kSr3OBrLtD8)Bu2_`XD~w-;YXcNXJ{X?F16v;05yWc?ZEZct8J z3*Iu@@icDp@tm%AmA)RA-ziRHG>!V~X$6?N_~`A-qV-nqdYdOt4j&sXeh9K~r-J3J zSGmu$fNT|TBSy^yB~PXl>wh+)I9u}aM3~Lpm6ofEkyErU5Czwk(O+vBwcnQ0Prka1 zxH4rwuvpU-C`w=G9<@p(q_HLGY6G40{>aTVIIFA%KOI%JMkYr?FvLq+;u;OItvQ;S zv73nDkJ~-CA2L&hT>U|cNAfjGdY%!u=7y&i)a-W56KyX|XK6gVLWnjlVdULK zexcK^^zsXmT<%g?Ue`D56L!()V~sRX>kHDgFzf4!v$W`E%W*mwCC#{xAXM5XXLC<) z7GJ7(`%UcKeaXoyP~_y5i*^H>V?OWFHPR{aXi$wonYH&%-1Jec+fR+P{36mB@a*vb zV(ZWos^P;8%z_A>|5BH1&3}5&Xv8HsH@;`agub=+Oh}LX-nha^np@B3S5%o^0T%+( z+T+U)diHxT+^IG2IseJ{8H}n*!^kfWII4%?D{>~6-zza3tt1k{_pSR+{Ba`Z^hCjX zCS?)w++}Y@r)xlk0xDS*I8x>gdO6>)EO_DxTm~neINf>bcECA#`_Y{#pe}tnube@B z=+$0;vtu1r1;)9()UWgEbA6x92P;%P48HyRQ}FU3Zh=!BuV=o7Zmlu9+XI3j6kc%c zl(vgWwBNa4ANu7S@ZHi=+*8sQVW249zf4)oGUa}in*70vg{m&0;M~1^Q!%LQ8>JuO zFfjFEF8FzEM=xT;LMw=kXM^2LVEcLrg>3p<4r_%+1OEb4D9^((oiIKCD1?Bfp~^+U z)sJxiPz4V?^ za`tl0qt4m6eI2Jm8RYcFurPz_8nIO|{tE9`!<0B-&F)^16L9OmgG~Ls&LRDy0Ay$M z5-FjD;nsO2aBf=quFJ80<9l+F>yX;FM4tOp&<=o z+ke2o{$0*F_K(ttAiM zz0&c$m^yny6mJ9L>~7ehs})V8!D2w^iZH=8CFFhYrqphxgl=tSx`a=H9xq4oXfo5C zxD-wylFZX$7<-K_)fHzg&_=tDn?{7NI2&A>jBcpj$+!G~Mwh8eqDL6*zROq}Lp}mbTLLb+!CzOeoD5yQ^m|zWv%Ga7D!K zE)_EA&Er&2F10>386%@U6E9G;g5s=Ue0hG>-{!bXp_lxaTi$##noH6AtX7{~wODA( z1MOS4Pr20kFLxrf{Zq;ZB&9c2EmLye+FMBH^W!bF`K4+VagQ4>!Kf-fs5*Zq^iHi$Nw3-KrJUf1A`B}3w^letNrF8%E4G`kj zt)NDir2NJzWk&9of~yo#eZ5L4=>`9Sr-Jj}s}#_@gQgtd>7I#b-r|uH4L0lQRi~OT z_7Shcej2d^;E(xZ^`cG`ft$T8=fUH*GgWsl$KBS7BLqlalsP!zf{6p^6ML;r*a%z% zV(6n)if4>+KvKn$wf8%h2hS#tglv_6&bsf^EnC$u^DAFKT8`DH|9X$jA5yPm1-@pQf;~a9&($r8JpKF z-zppckY-{80RV{Q4WCkXz=Wt)4^Xda_XKu;?!1oy++1VhVc#3c5>6}D9^lw#R)a~e zyQMhY{KB$7sI^P|Nor)MS?imn)g9r?>8af3U2y?|7HJAs1W8j}5dYwv$O4Z>19?3U zi}}X;n?VA#{U2*kfF$S0&-G|ZQfFg5vLN)suiObGVz--dgo9jPv z56ezX99VKXyry&ndL;{+;M>TF&9J~xnKKT4+%WVJ_4a<)O2yr5=b9Y;UH!a;zA+M@ z<$d7ZPZ;&f9U&E#nT*sOJF|}0^i2Ie4@a*E;788-1h|v_h|C~H(jJza2{s!BTV*HX zn#t+G&^N1IY6Fwp;Cg4xo49IlXBka}$anXB{wCw5R zD!E6ufLHTD=2$jAv!flO`xgG=&QI@5v;`~b1$xe@KTe6{(&$dPA_@+%75$j*Jj-8g z)g?PN$|TR|8qX{GFTFzuzge7-Fg;7KvFr=#2->MtGJb%rU27Lroc$opg=-92 zo4w*)G$il{7K{0!WDixQK-)h@&4_K(PpF|4mo(mpnuCP?9)KFd7sONRoIp*k63D#S zsF^oa8gT2ETYts8j2Gihd`C@c#HvTx>HW3)-Dr-0V&jVy*@R(;Y_O9s4>=_8?_84L zTQ^Cu^V-2#9q)V{Z<@PCAZAo^o_z|u{C_*K;NIxy?#FM&gpQP17XvqV+8vwOgDX_4 zGKLc)3n5;vt2gcfm7CcI`qflHC|jVEE*4S>M;y!C$H>Y8yD69jN%kQ>(o0&zS^rKi z`LTv({qDrd5@LjsR38`Gu|H&-c86&F+I={HP{8{j$*CcdJCiZ_)$W$~_A3Gf??SSv zTjNte1{=LNP`NRKY{h&%t1{rut1ppyV5EFgro+gy`$ZB!h!4l4drO4e$N?TPfsUs0kr;Fk6SC8noW?$iJuIIM5;1?}vhntkm)pqZ|* z6m$zwp_f6HeEx}^LAQ_3zr&e?7sLjV!TctI|kzzHc;l&s3Z=oQw zI-eArM_w8QP}y=#TG4H-Nke^pBxl zn@No+#EB&{8qb1lN^JMzs-rlF;s;qJF8JoC_h5-`DB>Cn>{+Ap?33d;LdEfcO{i(7^J_6@GkZ3Oq?E8HOP~pxOeCBblC-^zLa5Wu~tkW|;&lM#>(sN@) zu_8YS09fJoS$~I4{PGT2zxe(RMcKHNTX>m10IaP~@z9zUa>AhG!Njho=0L!*?VK7c zV4*!-_wuuOx-$>gS>VpZ$)}m|oNslO9Q>zu?;-EwsMA@h8P><-pL@vo7j_*IaVtL# za@h=i;y#KF+=rvBPbin8um4N~q42g=s*K8y zbqv_*e<*0#R6fJ+P}GKZNCosUf#2UDL0d{|J{8ra58sHBI<%mo6e5HaJM+7iIX+y= zkSOsVZ$GImr2{^5?Z=tv4O}$QM%&rtvLTc7f{B=W|bf)5esE-%nB&X#8smbj^TI=92YC(D@!p zTvgJ00^T6P$9Icyg(p^Pb{O?9kijICm)CfF8q^v00}dqT?a{QgU72xk$^>2*Z=Wp+ z+`yDFOe*2X$1Ey0IhEm*3Br%i2}dK4gsp5~XmX|AE0bWPmhrSA=OccJBtMIbD zV4UKF7(05^{e6h_=GTNu5j~dj_aF($noAYzGkDayjf=oOBd|kM*NAmk;lNE6-y<_* zG0SJtCM@C^ChaC(R!hasAVJJDmVIY+vN8*O23WZfT@?#josCEvat3jrpUQ37hm@;{qUbw#M(i z66`!PAjm-Vs;NK^B=!Y`Y~rT>)kppdvvZtIz7{FIS$nE_VX_LI!CS&6J}v`3`W`lH zxx6O+>07hv1i&2T^Dkb_u3@x4ceRd&m_)qrfmf8K?t_RFLp=nQ5@SG?&87xF5mlBf zk~?ZnB~b;;;7lQoe}z*xu&XByh2k=!K}Vzhc^uT5F0j#{lhipY(87H3gbm3VeTC_| z&(j_-gO68+0mgEAiT-0bwS+G7P>oDSOxyE$vY7TGph%!x^McO4h1=a{cRI5C`=gVG zX5@bAUb<5vMK!x;izIY=4ir3^C5w5y*wvdL|5Dn7O&8Rf){{Ag{mi3vE83DVI^b%V zN{Mx=$%JR5@(5IN$ZT#ddTS$rDjB>>3ULBWBuei;?sO@Bov*bRB~vz58C$}D(bv)1 zFl4r&oAJ$1nN{HD_{V&tvucww0B)M|GGw?EV3o$fT1+%sEym)=fR8mZ2IqzRG6 z!pl<5t@N~K>g|2+RjNs`{R>~i$*hZw0-LS5^I08l0aoa9wmZk~137(xm*bv){5jom zO<@@ba^b_wa{51j`TFWRhs!6>HbN=SK+pkDWV?63J8Siiz-(N9V4R zY4%G7wvzP6%bz4AmM0y zIXfKOw{QGhXw6P1h`q5z?el0T2Tu$ZvR8i}uDHtnX6Xyqn!0DIw_*z3enE^b7v@!F zF5ec?4yR1!)9e9!O=Zc)w^MS(&#GjAJ8)R$)@#tia5TNV(=XF;%JHf0jOWY0e8W_~ zWM)kw$ExISaY--lqzZWeD~A+!_ofW%@@vn?#}F^(;?A2iv&9~_;LGgYW^NkP;m24{ zpxk@VoUQMaxk@;t&Y!a{K>c;^r%FPnFPXlvlGu?4ZhalSu)2nhvXx)aVG*{D4!#r{ zm$Ii`rWM*JhOOZaSGKKs!iD{rklj?5El^;;nA(Hh%uaiz_Lc8Iq1x}gqmH^%uj&ml zI}59}`pAIk*;GAvE zZ`=THkkR{`)zGcSRxdW=E@Tqo7td0Vr=%I9!CA9gK!h910_514-qd*C20ps_gdqj` z{f)0sB*2eSVd`&E8nHFffHp<-v#}*kEz!|E61W2kfU7+HI7iOg?I;KJv6nF2Lc`5h z3C}^TbXm<`wUP=8OHWO=XNk7OZ=YI_`}C~rQ@fE!i&VR(wk<#0*B0yMJWvzS>CyQp z*TM2@($RW~BN|z~An#FrU$cgJxwx#wUsp`GC$J?$uR9f;K5ZmvNX_%G+2ShkVwtEB z-lXrO5GtIa&%v^9u0d2+*(5d8+MF>~1ycDBS@aYmw#`3d!&kC=BR1^G12bPo9c$LG zQU06C;cN398!*#rady69;trURO|E>AU8wHS23|la$-StrC#qjenRD_Z8BW!|1kB3s z_U3d~wR7M%#VPl(%O(28*m)n2@agjJ37>zZQ3Qak=MCi|a^>lrvjs&RFZ_TL%w*SU z3irE-!R3)za1I8>2LI}f_%&?gu10P>cKH$z^=`yQ6!z{0Y>;dNg+XH4s3_*fo9`yD zP2e(*5k@uIPzB;mv;vOKL{Im~nCNUTt|q@x@ADU$af#g9ot8!_Y9xWLxS-_O8*qOh zropT=$+2+xL0iGA@rvThB|F=hmm9@sc)pj4!VdnS_C3I6{CaPDz%OYO`#NVusg(84 z370KAC`d0+uk^oWBLtMStv*%RD?++GG3Kj!-9U3FsxU2m4BDcBySCl<^NNMp_LJjW zX8oyN9`wo(Re-r!YE>vr1A$WGk6#qzuT!yBm*hWOUyg)9@S+gbUzFRwsTqf_PL?9a zjURmHPE0GzPYfSgs~J(>COq%_F)myy4EX_Na;y#Tvzl2c+b&M(?z{V{KPb5xd%h1&O7Rvuco9tz&|Ewa%mP3o@*sLlMYlo`? z3vLm$#1s>*hX$HS#EX8dta??Q=2w?nm~~R_$)8$!3F88#*P3KixI{nQ_I$j=yR!15 z&Zfdfv5M@^JGG=AUMho`eMNqq0CdZG-}<|Bw5~vH>zxYI%{9W^7?z6iYSmDYyh7@b z9Dobu2Rhv{3@UR9@t)CKm!fbv+tgDXkDK9rZK0k0Y+hbw{bQp$A!V74P%Cq`!vE&~ zLgH-)ey$l)lIaZdI0BYJfA*fVa(3{mf#KJx`_`VHT$0-dR6Ns@5i&MBJ*z&$FP z8u!BKx)s$NYQ;%u5^RNRrsR@UkqvssV=-Hran}K_w&f^Qt+*p=3h*dA zK-DFLh*B#v<{zRV*+$3!_b80lHZ4^Ci_S#Gn zc=@6$?#ed2!_wFiW^xF;Cm1Fhq3WcklTW7@vIkjJg^5tjNHzK_KzJbBHbgY zd^ke!RDJJlZ_sqf2J(no?$#P(OTyCK)aG}MLPSzq~tw;UgkzsgTk_l zHaaG3T5rUv{f#xi#oX*fe18&`=Vdevw#uS^uIMNp_KdE%M{UBH#1X99|5#0fw6z`k z2_y83lD!)-;!GHv`Fi{W3bT%p-?3`o(!1`wtkVyVpyUaVR|0wt4*wH_PVl(9?g;#Y zo}(7V$c*1zE3hVf)14@_FJr*v&c7x{|NO4>e4IPZb#`QW8vUSW=Uv$IW9qZ$F-IMC z2J{?;jjKx9VVxkwHOxfGX^-L;A&4UO>NV#&l!st~4$akl3C0{$IXrYIvD&V}ZS){- zT;%*okYs~a_CxOju5;Y?J&#Hvt2UgVCz}Y-@>+5Nqn%tL=PNLP&h3LGfR ztbz;jJ}^d@kJJcNOBNPBXtiI?60K|usoL@2)5kj#I_KIuB-$q)1En6_%kDrnpJ+4||hbYZ1gTS}2gMeA&b^v$^Gml=BTa}1&eHPZDj`D)*`qCA=n zMWRjnX-ME2EL)tlWq)53AI3~3G}Ov$jPn4bD){G|)TY$1&~%M)Ei%(7=^$s2{Pe*!sWg2QA(<_W!6Kh|dw$ z*oPqDHySjh_c=6}+D~y^e|r+;riNICAogjGC4i0C?0lx_!t=sybbD4sTm3&g_i4wl zJfDQEqZ6_-I*(-@uy{!Ju+r75c-?x#`Tt z>Dde@&&!&uRS?&C@s&tGF<5z<1c&y5ou5UsL*lhR;^p~W#Wn-^N~oQ4vB^6biwS^| zKgnnPn>l;&yy^U9nIW5?;GyM1N<1q{?>+%1X(=LX_)Q7so9W@zCojSFCNE;uaZ~K& z%elDnOhWWH`YMP>W4;_4g?$Ko=kmaJo^WXoI1ir!G$jdzat!s&#P7vJ`Lm8PqiUj| zAzVDHagBc2mRm9@Ub%5ROe_!O6nLA2a#yxnT7(p@FU|0^#Iq*NBv1NQf2AG?Da_F# zhvW%qVUP_1ljWTm!l&)#XRWGozrRbK$-vlhvf@dEWG{OIIg5!m-gX;W6j zgsdJIrT>v34q`Ai+`wRHf6l7opZ&zBGJdGVq{y)Sn(+<~|2`vAwt|Pe&C`*vO07SibCDx-Y5fd322LsUjAcP~9XIN~;%0~4w^Y!p0QQXG@ZBH%Y-Y(l3z2OJrTUL>&5JCNJPkahYHb6q~D8JYBRtKO{&2-QAI^90_A5y~sdzSWTjP<_xPP(Pw z;3`kqcYU!dcS z{2XXmK&7dsugfCc^HU<@_Zj#v)$zzV1_|8))fHVm zlI@C#p~+b<*%^gtI$1xG3p&X1p-lVXWCj{+2iOx+MY5mFW++vTh)#0#Es z&D(`0C4e(t--Y4-b5raHR(x>Zk_BdBu(`o?IJ;P0`IFq=e{TQS#*ZGMu+IIWom$`V z?rzD-Au&gE#^m&(q6uR4$um2pZzsZP-c+ZlSC4IpiQ$aGHDugKfbaH|da|M71hJhc zkeUNjOkH({=t#ENYss#nOe!>c|LSQy)!7?v#&{<|OxbqqY6g`-oFoSdx2@{T=-_QC zs8*EM^@qn$)K#SA^lxA$E-&WyMHdNImE?vAX(x?Wi7HM)us3D2eWGJiZ}0otJg0Py z=AXWn>2fwR;i6PWfX+X%4gNXzJPwTG9BQ}AA}>|F3aQd9>TF&W5yGtOxu>AILMTDZ zX}>n;i0N@a|KyFi6Zq9{qHHjjn-7`J9O)YpNt=NtN-@S5XC(uwQOC&XLC_91wrK$axx@xTmB@|Rq7T@3dn1W z*%v0zoD`cqo;qEa1~Qb88KU>QKVI9p3zj3nOlv;eq`(S-+TCqE5j7wOBOTaFn5ULy z&(T|endmLRPnR(t_5NFt7Of7%$2{nt``B#uHL{J*iX*`n{=JK8sK? zTjiUz2D$eJ_cN=6lt#}L*#`GL>b+{yQhcq(=E*Ml7Q9?v`VokW2G_P_Ffr!}2cJG8 zBx7+WvdDd~)D=NJIN$id=joW0IHdd^Hh{mwkgpW)MhtnApG_zK8-`TpDt=%{4*xfX zu6Eu-elpeC11{u%WzO!)!ymqe)!2fiFN%c<=$Ag5dpZknoc&AN-FRM0r3sAA#*gki za!%&A(M{=jEA!h61>?ZnWO>izy!N$6;1PpG-e9N#&l<B*vsai8yMgNcRX&&8uoB^}n=d5+6;#9R`h zo0$H7@hC`xZ9UFV&o}_GAoP3X;GFTjEPNvsD7r=_Pd)aA#0aauQh0!OKw{j5`}%u4 zMBB_XdvtpX(^F>%U8WN!06a~`K6n?3Jpg7QG?=yoE1+MBf6q+~UtcOyQeCbE8^HT7 zb{E)%(7`4-5ZeIUbAV_0*gstEunk@yUrVyT;MsK%4yES;{fyI^7fx`zBH2s&hQ78`JYVx9^?Jc z!tBw?4`)GXlDX0LLF(ALru!F0_aR_ylt1^rY<&IsKJ1wT{-!eX!d+RaSAmJ(6IVr; z-JNP{(VmvT8#FEC7v3v}GF-BTKYm#{!L4-u$?GqRClp_#SB<(pfX-&3?$du7Wk8ZY z48EY;cWyw5nyepF?NgWFDN0ZNV4*|{A@fmzH{Oq`GB!ky>oPSoGeWymZmL*=eX_j$ z`IBQ<(RF9#L%-JV5%-M-qjB7tOyeo%;Tp!*A}N1Os8yr6^^%rkd!DFP-c2$w-Sy&g zKp3-b#ngifa0T%*o_oPvotXDjx&ejb`N~E|!1;^#-sNvff#`3~VVPV(SGFp(Y8R^$ z)rRi)&L-uwxA#946pufeow+({I43G<)WfC=7Rqea)~5ZK!uid*Q@xXxPuN;Zs6q;&KpT;e+q9$a`mScVxWIX74na=Xk)~HO0(}525J>&H zQ5wrd6F0VnigrI^x(vELpVk`|eb?k6Wnsn-0nk3rY zxYTKy+lg^Zn%mQF-zy-k@Tr)H_5;bs| zy#kB&6Bz|558Do@n2VL(9Nw&havcHf!yD5^y%#_ueXexm11#k3-0D-cP3?l?MXU+~ z#ner3c?Ud!e|Z89=#WpXNJP%iz7XqYi*vj|m~LAZd%|`l$U?L8h}^d3eyYgrnGPpW zyUhBDxJjvST`ia8BKFL6L?6$1Y5!K(JhGXE`Zw>_-`*tl?+;n`omrI*)Lpsa z&X51+B`=44M@o~`w!_WJCMpXQH$v*B2n zUZAWpDB;R@2RylCx_e598u1-T<-~U(Y*1~2CueS+y9gTEuQ@7`QTKivASPPl6}XYx zpvutTJFdynKyF2$Rc?A3u&X?dwf&)B`IBfUYD_rtH_=db-KY)GP$b(|D0-3`BScNI zJ&2+t*-E08Ayzycv1^2iN)-=hK^e>}qNof5KA?bn&r1?yL2)iX6g1fF#FIv?YQ&Sd zSW&q~S59LHse#=sOS1id!r*O}-x4DHWmh%~)UJ8A0q};+ZJyG2)pSS=2VX{T9^r_FQZNF=o+1StQfAOXrPy$mEkaR%;g9mBo_7cTR^hd*h#!r@OEI2vL?Gj0k=h!+KMX+$6&AQ3NVa2|oSjN!_NmtAoc-y@%LagT^sWD4mKr>4T# z8uN)^T(r}4h8OZ`)sMVro0jirzWF(QlAUIH+mt(2Q9<}+Pj#rWZQt!3S=TLZhwe5S zoVPA9c{YFLq1VutD=$Kak6^Sfy{k|-3YrSTW7%gK~RR z#3d}G8IH&ZM~FO%0%=g~k1tA5ptj>2b~sU@31#{aw+8k&-tJ921bt|_&F#-D>A}A zoT>?8r-3X-5Hb+e9SBkJ1foBvTEqc6^K1meS zjqZE`B#&m&D1;Ek?jsNmi6YnbYU3duMXSp;K$KGwDrh4l8@Vw-!V_(c#1fjsCDPGu(!{tChv*b^FmfyTAqYx9pF(aU zG$%-kpyQFegccxxM_)z?kXxB^aR*SQ#MBX|3pj6-RWhLsFdpcKNJ(;gmy}8j%9D7R zWuXa=e+#A_q2Q4I{>V;qA&Mh*C5Y{rSl;2l4p^fEPY zYQ&V>lPD9s6Uc^wbA>>-P$rgmo(9fpih}dkKvokGs45bO7d0eNE?_T@0?YX_lqcS~ z8wCbLaLth9vKG^%LPG>wj~t=o>AY2-1Z}@93iNzca6&<&xK?Sz4d8*&=@U$x@q8!} zKNI_8@1vv(VR9Wa?Q;s9$+#LNB1rHTj0E>VgrZ(CFsT|ygIlUUx_LO+qC;4>hjqin za1CH$umi8K|7Rc|os)4g=noQg0~@gp59=pvZ-NdDu&qSen5QwEwHxTyO>`QV_eyoK zNDEcl8^^N^44iD%mWnWi{@ty&IkLm;;BMW{AZvE(;lt0_o!$gL4~~1U+EvJg%G8(o zTBA6E-9$wkNg7_pykvjQCe(#L`r^#Uy>oogol-m51;VLy&hwI7SYwEn%g|w4Nv?tj zaBZ9nIg^~NoUnN3?I=4{4cu`Syi+U6lH^pVw5i?|XF*SLQW2uvkEiUQhA5w+*7KV( zn{hl4-qB+bViIecf*5_WMi=l7uLp?nG+1y`I9|AE>cJScp9rX*N8`NbGEw3nNP-0I zB_l6De0XF6M0XAk3EpFvIWmm5*Y-TWO9OlQiAmc$Ghjk4$U*IHy}E2R7AKsBkg|h$3^O=5c&w5{WPi60Wn;Fyvc}q z--ilS5b6VjJo?@I(P)6wo4>N!6Ojqb2wXTV{WkkRUA#ZvmT+1Q9(%_`wa5IL4bdWmroaoyI@ft1 znzI6#+xMpET-_EFp$w|8b6x277oN9q}Q#EQ^LV7H?*8nK>` zI|EaONyPqK+Em#xlPzt=1qyD3eZ}RbjZd_npQX!5$*(XoT)l9#UB=g3?PKE=TYRfz#S152dS0D(BC3JIG{zdx zHr3q7UBv;9TrKvz<9wMeb<9UM@AfYKhCXQX2VA{$0wlWp=wi=Kr+Qz6-*xFGjc|%L zSHmF>FDUk9m#l#x#t7%$47HM zM;mJKWob|FWLtktG~6Q4e3U9|6dfAxr}mJpp!OaeV2hUzOAoWtC z1uNd*5X+RmTh+CQ`&CG6Qkl12S+rrxwdFe%$*4C&ZdZIJdY`6CoeMgcV#Mh=Oo35Z zPb8#X-b7D%YQG)hJ^5X1n@%ggGQei<7iBry=)iQZ_plWAIVxK_*PmuS27M{VjWb^$ zp>Il-Z*!cwUboFGoZR{s<87?e?>YzHK~!TOFq@aHB5=EuJoPf(A9|+^_C}e+^c6?_ zIpZDO-t7q7EkV4OB$(2BorCrQ&fx#P8t>5tB*&?YE%v3KWZ5r$4ZPcl+cR9P7ZCqq z^2qUOCF~ zO2`_~2~Nk4NAol{H}_xCDDzAd&=k7aO+2GFvk=_I7mbp?3<_ zFvG!9sT6#>3;0~%8zld0OY#FVlz)sFzb`0Yz5`4C3hPbBPei`!G?}62^nNGspmh?k zmOn6KML*y_gM4u2(_Q$k>X+*!tI9A>uu8@(&Dzv3iZCDx^${no?u%aDag0{K4q;j+*JfEHU!ykcL&nh%0ukN=zDDDvGm|?~>N#(Um@s zZ1r*1&$k8Q-ZK&~r$Gcou`1ZQ#e;k=f?*1m@cy;LlkVA%+a!tcvkkl3*+g}&U!K!m z;BHIxvfimEqu?Y~T;}jxtc6)L$m$`8>6A4~k^%Sc+;j+#3c!rLMH(H3Eu6{y&p9P3 z(l1!S6Oe%$>IVaIC-Lim2{s4Fn$`mh&t zd|C-5+lZSjZ>9d#w?GN3{;=qn0N87%atnp6X8-$=CVvW8zwIz~M?XId?`vlkw{jza zuiI|}!!2^V*Ug{83V--b=q;cUGqGNkTz%5FrV^W7{qhQ=H@ ztAmZ)G=_ao4OC*_Hc3Lmj!k&mAt_AVW8jWz(D<$ryV#J3hB?U{V50^#IAI$Twdpr+CyOhqW z>o)AFm2DF3JrUqG$v>0i52yg@2=+3Ra|!J0+{eU9#ii8E@@Cx~MbNJ0nG_{Xx0mQu zGdHgq^dw!;HR^+?_Uak4d7kGbOjd?%H%;R5Vh7v#kCy#qR7Y*D`GO;wX8oea9R_IR z|C?TnYQ!$;=ZexL6|n&&^lO1!;1yC4`}q|z2=3oESE2BImj?7=jh58?)^o?fCWhnh%9>EjCsmRWLDg^9i8Pv`y4uFJ! zZr28N?&$v4>+Y7SXOmw-wkmDjG|pH7?NnJh1N34y1il^0fGf&k#;Oel@JQG5wl9ud z3#X$yj=Yhe6-Kp>@gU53l!H+_!BLd9Zi*yJJmuSaif1i>bjglHV434X%|8MREy59RJ|bf>{PAIcrR@tOfL9iv&r>!d15Ewzc#&a9b6F zZkX2b5iV`N<@q6d^c(}iJ5RSqNr+tw_}=YhotVka&8QzyJ^w)+l1 zn?N`&aQ{P;|4lE3!rNW=86{IvDH~COS*s;9VL#Ur)0CP*gNL&R|GwGGR^w6ttCB6N z!Q}x9TZhE((*M12B~k*d5A51L39L`GC4i_t9qp6a>v(&w?*HmlK+3$Q9jVg1$K+Dn z=A(e0e(Qf+z8d!C{@9kaR?zPx(1$AyP2Pe1a=Lb5Yks+!mayeT0wbC-r$9StLoFf3 z3t~TSs3j!Z(VuGxQANU2lU?Oz1S2dOb7FtU6dS;CP5Go7mj=^lBv;Pp(zIC%BPZCn zMl7deS}~*Gc47?ng>Xw!JC*Qtj|542ig@0JnRXwM_O@tP|JcsQBGbpDy_3NO`f@gSzUG3rWoJ{xPR3i^7d48%kfGOl8>A=aUJunh(8ufu zpFxp6gKtiaASmoNNwu-;m#Guj1mD%P>F=isgj7Z-4gXvl_8W9;5|>K<8yz7K_c}V1 zenCg!WFhxQ!s46F-?bZjX^~dc{akY%poVzc40-m##}ak7VL)&Q!>6T?8e3m1IMYsb zx(@78|LNRr{!T&b!!`yTf6$ZWx}`1ZI$K&^_&bN~=Nj_xmH(cht1ev2qxdgduGV$Q4EX@XAR$u{QY`d!Vwz zAsG&}#POrtO=EjTFKIB%p4#3*bFKPY;g^O3a%Dp}EZ`?LAo{;Wjv6@uSliH9ENvm8|4+2NGoQ}Sl2d85J zdL)Nwe-CSwjIvQmhn()+WW4!Gt*~*8QPKZH+IKioz5o9o>sZGoJ2FBxNA})(H|-J0 z3=L6EC@Whk(y6S9Qb^e|dlMB+Es@=j>i2vfRJVI?*XQ^B8{Uui^Yt8$aXHLZ+&10E zuDHfl*IlS1aWaE{m{Bg6lP;+=)qYs+Yh+XtFR8xMgAHWq&iGj;BGz?te9%tL1;14h zS_|2npE&V$#PxdGC{d`zPv@w={k40Aw6v>|@3fa*GOpnSqwZ0NR1w2(W9}Crx0@Ik zgTa+!H&`o&KFlAhagrSQn;S$E%iLQ(%bnNK539WVBAQX)F@IO=#JZB-y^bnnadzDs zvp)T3oJ+yZSLiPsLi_8Q)KTcsW4D2IdQQ70o^Ed0m+X7~g&sR_zH+P-&r(~ggDP^Y z`o@vxc%fpW!({orHXPY>;HpgCkQ5}2)|x4liimi_rc47ILbzE-^9ip(gbU%V$D0uD zpzL}KS%KUwC=@K{Z;l6VY~8=b`yk#gqJ4>ah6{M>^z7;)wLRlSqJ>_4$3WX)ctNs8 z1I*GWiDvv~luLk{T<*PesZT{rXSDa$fZLG5@7-$}8I9&G0q9K#OjOzD!1=IbE}}NJ zSg4jW8Axkt=Q7dYe<^u(Zp!3#(Ol!p&76zgs1F@hgL&pP9sU<~*KT?DdFSBbwSZw+j+X^{JxzxHHcW&uXjM>o$vgP8-LltpSZC~ zB;bbsX#96Xf&0tUv#rQd9qCa7S9%m1hOeh@0Ef`)faTYO6B0}@NLlHA7gXus$68ta zVex2<2CPhRiLbEI{qh|6w6lq#EC*J0VjMl|A3S2d9pw2 ziw#rQ>6?I)y$N5O)W%#d(YNqx{bzmg7m_thelve~04l`;`1CDqw>Y?{06F<@;T_so zuDc#xU4^+||Jl$kkE;PPmEE z6UT3_ncxUtnRqm%TujvQu9Mu9^~Hs()LKauv=CskEKAqOfRUru`H}6bV<|wGcpPBj z8FysYo9%Svrfp@L<<^H@mN%zinF>WRXF`JDBrB(Gzlkb;dmPEbk8N}9mu{V!!&@;# z(s6drby|z2^iU>TIx`^?A<+50%+%N%CLVz)=^m!SdF3AKNl17O!hF@VVCD?QA_w#< z2u{GSv6)7zKTU8&)vsziGoA<#p*rU{n0V*Abq5QJt?f{XcP`laap88}H?&0I5{GhP z?6;?1<)v>dn>y&Y!!~Da*jXPwo;tVwUPoqRn||VB^E3e;o4)-MJ_@ZoTV}!z#2_pk z;V*)FK#yz1{-Kg39N0Nb2HJ>g^`GA#KQb@{sT%beK&W2If=NA|ejP9SA79AX{ib9I zHg1~#gpaZGEplYCC-6^!Lw4Om=zIrw4ReyNkbK^LJ$Vkg;WwW`!X$;_e%#Di_HW!> zzv1E6q6>SMk9ui;e@S2SJ#z-K)u2zIA*rXby1gVuMSO%jKPfhhLd&y_7?;>vC`YB8 zl!mAt6tr*=D}J#Ua~8xAji9n)ZVo^kW@18+sRxo7TjnsKD42TYHyJQ;r3zk-3}w4f zw|SXKq#d-{Ioxv{-z3}SCL-xN8LOHK)N#vIxRc=62`3@92lD0OTG`VoOhJ=F-9~|y z3Z^B1kM0H1ufU_=eE8x{w;-8rZ>c+tzG*!EjN6$!4lrB~O5db6kQSzF3Ql>NTTM5) zb)!s5xNUOUWksiKfo0(?Z6v2e4vw|D!FHF6@1WF&_q!i<-Vsx(ha%lTlkWWB0J9xR zk06j)7gET1okxB{3LU-dFDlHG}QmhWc zoafu$9;|fmEw5~zTZG-o%=XF6o_JfAfLJPm5KF-v51d~!`;h|j`t;|jdl`oL z-FwTFPW?9TNO`4m96wuS;d|iAbspBJm5$b#j6Pfq8J7?%YnYR{uD_PA>_8mP2_5as z?&BLe$gZe+u6RBmyV9c!~-8E`s~qfg=C?T%dIJ5r}(eV zF*wk*r4XOEesWGHC-3}R;hFDkt!&6ZtW!1LNhj+)nLu?ISbzJMo9<&xsnzAom@qHo zz*z>ohypvTp2|;6E~=OfAih}F3<8(J}Ex{IG=Y>yCa&kxOC zO^b=uNjDX?Tt3J(l)g(?6YoZ|d*jehu6L$ZI7)lxaC*^^UD~U0YyaQ4kdht!SwWar zJJ^5fL?9{NOK9n-TD8t4`AOSrf~VW;)JMc^7*-55eOX0Mbx#FX*-LIeGWP0s)~I_Y zEX9!T>3aCiBhb>F$?}y%9H$LLS1X8Y1ym5->-YEl#=0p6e`)4!s)%D%FQ)Hu)ohnf zg# zVqwZj(rk^G1#%KTQVz7HCcQTud0lZNHwFF~BbvU!zf+K=A!$%4cFo01kxrLE#g;A? z$f0z)(r&Jxo4T|IMVFl8&e4+mkQSjIf4ih6IeLm8(itZYwjE#2x^#XLoB8?IpQo-5n`xus%F4ga>QTLv^BQ`Pza)6bk@Kw!x zd-Cwa0j06**M8Mk%VNdVq{zAAr7U%9nZijPqScxMOm?#C zMO!#56~xYDe`-md4C85K#6%WcI}z%Ci5L=}-&b0BpA{-G!_nshe`mX}VfPpGYuU-5 zo01*Ym=ftuCV^&|4w@GSMj=jqOxBFa`-S{L;i|Xd_gDDgS6I^kd zR#T>Qg0%{yt325H)6Q+s*1#6-Gqw(z@Ij;KgB49}(z$k0hts#Of7?#(3OjwmVwB&% zYZPdU=girx`0C;5rtJNpnS#bNt}5Ln`>U!2K~dQ#iTJ<>l$&<=$#w>McOluFsGb~8=BMhN7jtt7m~B7DMD499pak$ka!hCzSwJ}T0E?A8oEG70o=*s0kE zna6ZZ1$zBa41;ol*0zJ5kX5Mdx$fH>IsWemD3)FRfq;jG2m&l*{)_-g1Oa>+pZwvv z@@E9_A&mh~LOzC;i8HZ&97#!Gr88?3pW9h=Jy7WHX#`=&OHdsfvHkj}&&OR~U%ft3 z3I9Ip(7C(Y&EWWpn5CYqedAxD@-1WgmEpG^LPnH@pSL_g?I2s6230=zL?J%9TVr8D z&Y$nenVwQz4%47G#KHOgs|MXN>2jSv)doghXD(2>C3%C=ExK*>x7X~AM{aYG9LXrU zEO|N|@VcbMyUw9CbY{gYSsR$Hx#^_gc zv4Q&p4QU4oI!iDr7e(8x5GNqU@iK|qQ`bBnm@qDPNt!Z=4ak->!Rlg*Yyg9tS*qKV z9AWynp2DWcTVVNFed9{P9G#t)M=uqZJDYClDc-1Lx+y_cYvyWfENKB3gW-T2nY=}V zMUGf_`1%|O$)CDV{QlSXVo85|^PH8x9`(m>o~)Z}F{y$2x#zt8$h+LmmlfQaULL5h zpWdGN^7+>zU;sx@+aJZU#vxk9({LM`ITM<_on|E=Kna0^$LY_fHv1W84NL?*tkx^B zEm~8pogsYu_6U#LPyIgaJ}N{W*Z5-pVfKi#Ic@PR)f6)Tyuqp;)jT9WZ6TP@ z>~!Nty${`cn@%p_7@^+RzJ5lJOPYT7VY$u%oLuTWTa9p$NmwRwB)^;da_;KP0GrPo zRmvuMrG^ykn;3N@Q3-}pH;gH3vveeyyyhAM4`+=f^39VcLqDa?VZ3gV0Z;6G6{AVA zU~wldJGTO3aC5Vv*>XWS(hiEY_fKAv>_{c8mg`|Gp)_VwxMvCKcdet;vP=5PJe*AG&6yg1_I^n+;4X?trJ zYX19e?{e?G3;b;_MZAQ(+pX}YlAmZ9_lNBz;%;l7(UDuNytTaDbN`Z9_wV~mhY2 zQp_3Dx#naYcb0~RBkwOp&33$8srjvplDHCf^mq#K#V8+pvYBwfh#oc9$iw17X5xRs-$(GqxN9_WJQdbUZ<~u0eI-5=pQ|m?Q@91#)Fimq?7FC;wMieP_ z{dW%vUYEape<>{2kMD2#bF3Fts(#_Vxq6vQeL5(Wu|2fvq4EGX~c` z#AAgh0>1ywRd-_`(f{lBuNX2qrD^=IVCxZ@#~r^o1K#m?JF@MuEO+aRg+pU&&ii)z zc=?*0Z=8HrL&#o6Dt<*Si~5sKD53c$IrCG>%SOrmSo7EKA-o7fL{$5x)dUw=%uG$D znIynT_T$F~ubxOb^2Q_%9TX|S-PlshAeP=R2c#RxySzWvh%!83uTC!XAyj-W)xOvh z>`^%FqD_@D{I~1nxA=pWkP&;Hubnn7Ew5xQG!cG$sQAW=qg8j>wpa&Bn4~OsNI;`E zIMD9pdgirhph?$?k5i=#%92OeJm{c$FEb69=Dj{ha1xe|+|AS%jI3!>RxB zz4hFdU5ZaQJ6TM&CN#xQ6`NV!&TX?2OBQPD?ojHMwTe#^HDatP6YEH6yfrRjT2(FH zxqlM8{sv6iK}xEf^78KW&^{SNcPeK#f31u+iec&G#+D%X-o0sJJ{x;FFwPtLlCeAV zY6F4=_40%=7kuznyn)gyMA?Sf(S770QvRP_n*d~oR;s_q5*_SJs!JPM!!|7f!#B@^ z@$DaLy6nzinCZ>Bi{=k!)%^aZtAwo0ae2Si^zmI-?4-oTb0FZHJ@a0D`>EmawK;BR zC(#B`noxE7pA)=|=auh5gGB1t-#jkdeeywAAMdsg8eG&Q5p`+7D zn=aA;_dStD@XRvYZ*o?&y@%vylg%*Y(a9QTY%o!KgauX~OI1Q`5|fZksafLTYC_dG`E>elnuGlJbS2zKA@ zd)fcwFRwbJ${m&VGwaziuh{kbB;O7z-;7cV@7o+xzjSrM*}blQnX!TJ`@aYXfor4w ziZ^t%ToQvz@o>xHlb>@Ogk#R^ILfp#$LTQAV~;(VSYCV8t#DEF|N7Un=_NN7kIEud zUKpypjxmF7@~+JXYb0Z!%HLdl)j2X|CtZpW*~gU9oLCJ1by}^orj6dhX9Wzp$1jRh z?6*48OPJ%@Q(%tk#8jTim1n|KBUK)}p=n7Ao9~)bJ8|?T@#g5bKPjH1e zwgeH9!i^uWr!G)6vg!2s@YAM9j@ug!FsEa`)IB9-GU;C!)3m%Sl|)3fZf*j_)4zZ9 z8LZCQe_v5Ut`5_?*%JRZ#DC-;_cu4yshKzyu#qajdfS?5fAxW1xt&kBa#a6I z*z8Vk-}my>mm>rY%V$!cL|R*UHtA7QC$u`t{7k64hR~_=VB_Dl+0XRMN-CELke^)o zD90--U=6%4Sh;%7ybUr6*pZ>%9f8hZe~YYPYBVG*DcYU-h)nOZrMtMkT`M=~I}q|% zqGi<&;FyC$r^-#7*jB1pwY!APE`h^xE6Gii zvZ3{j4K7NmN)-dQLv;p0-PP$1qLjRMf*$}MJOVetcTt}qa(_gg6A=@4E5l%9H1*7u z$fY_)@M?wI;dz0~x%l{t$aMFigU+pVp%|ewUC{%thz=Q~)-yihn!e(P8ItdukL-VO zTOSOKuH>Gzv+WL?94}Ky;EYf=!;0FCnCOLMN^<%fI;&;H^cC~YG}dNx0crf3rPEFc zAt_3NmNuButMo=*m`i?bi$3;nV~+c_G$gVNhDOp=4u)DR1W(R>N1AZ@sR+lBZMw&p zPz+k@*7;NNy6pI^HZag*ZPrk7M-4%V$J;-mC0l3a^ zd>))%D%v`1eY+JHv{c*PYL-5lfsWuXoTL5ZIfK=V{bCwM5ijtglIq#r!QRWh`diKc zZj|lKGS*Pyn9u6EamP^&s@bD|MTy$yLdrS+^Y!#9%-MXT=gJK0^75brk*7o%#M$shb#EQOki~ z(D@IhYm10RFkU4W!Og`y5xSpVuZMQz&g!8AM}%6}}~ zZRdfgoJ<`&soDBx#D7AJ6xMDHF_wh7;_>{Ci1|i949T&kQ(B;P`P z(v^c8i(P>WdB!X!+g?mVhUEQ^`4<~L%Dje>LqGrM`OR!ekAo%CAC^_0@Z|SQ9ln_$ zrd~{T=-YK*PC`1{%FWp;nzc5LP+=f*J3m?x)QVDRqBO7}LT=7)w&9{ImQCp)UCW&1 zM}=Y5CET2oU7*7Bl?L({Ff<)UDh&IkHb&;Oh=>`lNd0zt6JSmvey;5r%Vk1BPeISG zb|Vc~*!++^A#!~ugN)j|TMP6PMbw$?|=eq z`6f6+bOqbjGvau5=Fb5=yJZ$5fnwYy2sh``TO2m%oVGu|ch_mR|LOWn>Ez=1dzG=k zx~*cS;N4NeTV(Pl%$y@s8U02}+<#(594ORj&@xW{t;z&$ScD$b6nao4h`uq+LEa(` zE6A*^&H+x;UZB(t`UdZ=HmwH}2&?i5STM!4^v}FC*U#*P_sRjR_EbgS4833BQ8%z{ zardpUs_(}d-AiXZsaabeEso1jLvn;gcKukk`Pgw=IqZDs9 z;F1yPrXfWe4_a7b`8+9bvI&^M^K>w}9EB^R_Ny<(^VAQ)b@6zn3@sCL-4bjSAIRU3 zq&hv@%@j1OT$PY{HKz-+o8IS&bqW#)AKspXSj`QIEByFg(CSsR2e6iL%$=&AM3q_n71qM(yKoqCX;}e)iA9; zzf0n;UihZL`uQIa!!Gw5VglUzlVviKfP%n0pn2$K!KhdHt`sU{eDO=;JpY>MR4UMQ zne%}mSGd{bvr2^-KTG9{S)|HjYU6tjgznf_h6P)QLtkoccmzIr_c0XwXTtLC2^W9U zV0ra55OhJSh{5CvM;uuw7HVra2-NJ@L&m&rIlS50^i{yX^>4S?!0T+M%+Qz&3GGcW zhgZiLojyotzn84z$s`bvR2ibSsIWa34P{hfoG<58pp8aSKuh)@#$q@9gWL8|dmkE( zZ$s%8tb5L(#JfcQj+rEE=o)4&5nd)w^Cd)o_)i_LmjuFPfR4BE8UDXtCW#E~>?DwP z{1av>yEpk6_v{JU*|l+>X>KP{T(luHX>j5#96FFv;)TtuRzs|2tmKg@bEC~mmeYw{0 zHYFn+ZvcS!<&cu}d~%yO2sW@Z)t z3UP}Ohup``PbTwXy}Tve9W0PTYd6?@$CoL*zc^kdQKCCAE>5Z7J=YgSGf9T*#!A!i zxg0u>k!kib%`0xbVoD>Zh3%in(6m}OC2elQJf&-X%Y|(}2h#DHuXViN`C}H1j`0~- zeho@UrH?wuy8|@yG}@=RBkUe*P&)j-b-Yjij*?<*S1L0IY#wFF~4U5VZ6v2$23peG@`NwmJ`yy zbUp5Ijvsq}FiYhbyiR$uaU95k#RwrlN#v6kHI2P{d(Pp8YjxI?)sm`O?Lk1v!LKVQ zDIaM-P;v}7+s9T>LS+@LUlT{QIv3@RH=vC*4aWuHt_^chuBI1ygVxL>WNa~DR5DhV zq5tVAgLiE}EAqPTLd)P?me68&mrH0NUKb-YAFuNgnw!`8Dw<7uF9(_d@2{YMi=bfJ zf;;XBHZiz2oUc%(Pf-H6?x&;=QKn8PG2HQaEi?x2)Q_gY2P&Xw@lFfvxJY3(U1_{C zADR*Iqe(##8KGG^c}cM-vbiP1Fy3Y1CkMeR z=AI`z#2b2Y8KGF;uph@k4qiO&ECu2fQ?TL{vt!jOCYrqpmnF=850}---j}UWEK+-| zPN}=B=-s*ZRo}c`eY;wWhP~4#)gFhT(pyt=DUBPw+0K^wW;(pP?fa#pf98tWtEt*) zE)tGccPEVR4JjJ=(bWee`i|yoJu*zvHXSQZ@eG+Ob0Lw6p)H7OpHTZ1&W}R9Wk-_1 znZoCq-`!yDMBN7qU-R7`-ufc0c(Z_$w)V-VjdW4ZYIoBeDrRqGA1L4j`-}kIBlJW$ z;pl$yOX29N=)JF7c~VdwPDGHl_4yLonfGus%Hd@+dth2P*(LN&w{W6exO7i;YaltX z>u59+kuWvU#G;5~G@9;`FcvIEg_BaC*fda1bwtNeXi^j@-&aRBjJo80^u`Q4ina-( zBryZt4k%xHLjl~0^wyMN;>U*9JaJLYg=G|M+j*T~ke54mtN&cfjw`lKNmB7Q!ilR< zL}Yg1WC2X+=XTpplu2AoH`Az(A+f=uSn1{T3Q(vmyk3V;B6ySB!K*1&q!@bP#SNEi zl%g!WC{V)8%je=4z0E1_Dhg37WnXRzPT(cdN0Dtt@hhO>8GN>($efw^j2d@}s&OIi zGhjqxFO`LBkV4gjlc0|4z;$t(eh`cJ=?Wy~yzqDGg$tQe-2 zL|mgiNhS!BO2VhnG9x{R*+;^Ln6cMqM?zoMWc`NiGv)^00yscecF;Saas(Id+f^8QE%WI;Q>DAyC% z2~6)n%oojGX1E0RF)JKLG_Zbp8y4gQb^3#BMUBp#h`GRlyl2Mk*vP#GHq2!r)_v9& zH5I$d#O-ZtpJN`$cS~Q~tjEA2ZoAEFC@Rc)2g@lMOT8h%W6nDkHNf#Y`7SU-59mS! z*ny(leGgAJ7kNKQ812uy zXA+Ccq+lymQ}%CKN^i#aZk`LRKkRhjPM2 zb&R0Shf^1$Do~VfPjgYa5xPfB`5!Wvp+7$w}L!9 zoLvKDUPD*%0r3JlNzS_`_28xKX!dbjHU;}A?tC=+Fq6YmvN^;eUJKw429XlhN3rNJ7VFDQoW;0&fB?3 zlin^eoWhvWsg#A+KbI_=VmEaw7t?WzrfgO$TZ3~G?U5uI?j(OAI=lrcTAGX^oFb0F zNdpxlY=Y8hJyRb}YH_5FSfm-d1;uxlEZm=rTDKQf_k4*h-h45fUb=++!gEd(!wkt{~9%0l*0b0v&@)nV3ws~H^NR(0igvQH51lyGkEwma1+vg04 z&xZx@wUWa@^=GVUT}*bySE54OG71V9iDndT=N%tACu(bd8T(XaC~F|o+Q?V@ZuQnz zO9eZkhg`u)T46))W6lU4Gm)1@`P#?jGi47137@?hpKi05_0Dp4bfl+}zQ*fqvSVyL zXWweR9(|nUbxN=2D%T~QnGDA0$47gYm~;!8DK29jP6^Vhp|d(Wf~_~Z_U|$^e5)&B zZ?&A-FJLuYM_Q35^Y|Q!a-Uch);pcJj{KXR%?QB|aw(osrdnIzlfkE?{J$X?iSH%6>%$mmfv`*d{w-`2y&?}Uo zE|Yw_!EpP|{g!t-_c2W;%WX5Xd0j&OQddJ^oOE5+dMaL*Gr!F@aOQ|#>s)uN%)}Fa z>Rh839AQ^$uo7hPr4XI$SHzpO!zMI{;sv&^C@Bpuf3uteI(KDpgh zH6ofZ&F>HG?q(+gBIb;AmhsUq>CJBf=;u5eE5bf+rk99z$2QX#_mRD&Mkt*(>z;)F87XV(c0BP4QvSH3ji^C(w7Lxe zoBm_p=3tL(#bA_moIV3NeSg{N2eMb)KhO_D^4kis8V}Q~f!Aeh9KLxUfUG5w|Kduc z{k0)qzeB-jP6qG>S6~$v6iI1zo|*ch9VLSBxbCQ`o%V<`=?^|+Uy~mIi#Ka)aPQq$ z35ua3**ElWj7^P>G@a(b6IV_D1u2)vrmxnmPQuY`VC5+Fa}u_pLXq|U`y_0DBC}l0 z+)7{+W*0(qW0Bx&NB@Ms&T3^6&ib}8316Z=^ud@e^wwL%i#Hb$n2u1Uj6x1DT_oK3 zC0(!QR?2$6+^RC={aU`@y>hBzmv_XWC(^PnN#Ay+QohPne(|F7m11|~7tM~qhE#>_ zw6HDR=GLT5h>T1e$?1~>Cmz1pEhkgXMF^+Pg(0_}Q*K{dUxe9QXiZ@TeDoednHp@M z33lEdbH@qSc$+&N(qQ>~*2dxWasH^BTnc`#DpJ^-wW`APAx!1>)x3Vgy-+yti!a-s<^X2=m2Z8Ff5Cxo&uxgh8w#sjR zOM}&dJ7F%|3Bxw;1IFj>y&<8RU~Z6$=-BtHrj9p1xgh`bUv_HyY!<=}L^$Gb;IIRFLidsfMH?z@Zx8t0wi6%ztNx=3#5+qy z0D)Qu#0i1q7gzZeS6-LC6T1hn?30gEm2i(G_vl|L$@=UDl zCY#EOUIeRK#8o}NT!rT9lUAJMrdF>mRi>KkE)5fV*kiuwwc$Wo-{$d2_xB)(0Dr3mEh*$Hu45oIeQYfY+z7j#Lwz5V+HwH}@G3v8>y@nF{}R zocLo4SE@+=Oeg^-8Gpjby{~{1Jl%=Q#Q%Ylazqkh42{FT;l!2cc!Sl#3Qp>*u@6p> z3F#LMOa>othuUL^Fh|8toLQ|9Mw?KfW6#Z7tfK^x7w2HL>dP0qFV(N$!~{_;W|f>g zSpIkc{J#A>@*llx+i_w89iF)2Nzu2ptr|Vm3CEhNO9(`OZE%Tn32jzyILMBuMZ_r) zhKsBK_}Ej6L&pVZeC?fs?6Hx`JBk9 zPiJLKx;p$HnKPxLkd7oJ=sdYfmxhIrHm1pZ;K+bnS$7wwTHoN+h1X{%3}FKll&fku z$Xo_E(Zb}B8VPe{>$jB=a1u{qQy?P{#oJ=x&0~io!`kK5r^zFxr7^CTl7)$w5Qwbv zrNO(j{$5Lxu%)XQaa+Mi)Soc2#8v~fB!=W!!+&AqDv$+?L0R~(7*XAWY+k#lo~WPi zdb_aDwJom`T$kPgL&17?!RQ{T9Y%W7ezn6MQe72hUm_~%XZ=HIdU&!l``=>iy7Seq zbxqotL79==d;8s?BWe=08Evm;mqH&X)9h-S$Nfb+2)L#R7ZN&&kht3E@l zw@_{SrzbqM`&V`x@t-s2OhRr%Lss8nJDtv@QKSvYfrf-Zq$4G*YSDOZvR=B~H}-UY zr?s)*mi7tl+cG9*ODQ8<^ER!O<-V4h$|lw!X8=%5%_`;B?HaYqnPk$jmP{`>^>69| zU*(Fd6X;UYf~Jv_lTGHTGM;+{3uFvy`9W(4YWCRCqw<3>%ZItQC7%-^38y#R$8~>b z>M*&M6Ux)vB`*cnR2z>B67nyI05prxI|z!2c36SPt1HabBF8O z)_LjNe$R^YHRT7dJ$XK5c*f(rP|CIUhm;>*Sbc94E9vHB>g1^Sa-)u(rC|OWEpfQ@2;Kv0=(h9NshO}`Nk$a>tV8P%_-K=nUybC5csZD zH0ZW8Ww}s9WMIl{gutj-+Pr^=OwwX7Rp&ab(UpZf)^@p-Izl9He$l9wADl5lq8d=7 zg7yaKV^K~G&$5(Vc5E;`>CT_5K*YTM_vWd~$nUkJcMT_f=_|D);!ikP_j|*e)wS6O zvD^B0oMirjlW9`~C!jf%+m$H;uS*W(*2@53N(TJ{AQIqsYLkV(;%<{|^$d5%<~}KP z1@i)LE~wJ3LodVd($q|4HlkaOL0aYP{0nXG=OHbCC%}(IJWq)${I2=0F$(JG zjZVJ zG9jV?Pb%qXa9=#eHFuT*#lBPqsT z@X|o2D<>N@|EsR>g66aZ&i{rWU(R^`rPB_pb3zYWq8j%aMsVr#L_BhIEIuK)Ebv8HZ$xX&X)tcFDRt23AT$ z=bV|ScJ|u}CcEp;MQE{KHE%EzCp<1+;9IDtjCGqAH*L3hrfZd&&SNa`0$g}RQt{7> z2bqhsO>ELR*|+GWq#P6Go&#@MWFr37dN0i8Myp(Bc$DT-B5nKDZ7>mQ(~l6*j+}wFS8w2_Cv<^HsQ9)c z_IZEh&2B@kxccy59L&7UN_n#S`9I|iBg_*c;41Bmf4l=2BbJX7<+Bs*_trdlGs3ko z!?3&oVMMCE)x0t4Q=9;7gakzB&LImCNcupH46R|ciMZJ7QIWL~6z}(^r@k=z@?U6t zJri=IhOj&NFkGWS^{}SoCvUdK?;O&^icw^yMYC&@2wA9blGi82bCW$TnGK^1ITj{Ht=$^b_M@J~r04#ga= zyZrQnQDW%Tn_vW4oNLV2lrIW`*JjbqR1A2Fc2}xQmRhTfmKmoE_TE+`)wa2Bw*MN! zgY4`_LfYORhC9t!b+N#Q@x6VtCHHbHQ^Pp1{ecS=xn`wBf~Ngxi1R*UxQGz%ey3VN zTSAwTI3CF}7_)GU`+o8yBZ}GbW$>=yfJqw;UjL%Q&cj1f@#&!J(m{se^&!N`<;`zz z50eyjbQK}QE4Ad*pK3`RGV9=0Q(^x!6Z8IeADh|p7$MKf>Xr9S1hF0fTp0oZiKB38 z49K(nmJ}qf2EsDyokh5~zYU)X8R!pMwx=z3GyqqotS*PZRO6S6Az4QW-jT1A77jw} z(X;6gm5r-CiqD2ky2oqn>F$63$uqflYWfzTqh%q@d&!5k)Z9DB4$SI!amsquI;smfP&dSEnwYU{WY_1!(5 z(5}Whf#8mrB0{tG>JG%X%bG_;_1eKlcd5q z-wX1MPi8|@9gZP$@ke@Z-uAB{cM^+!?Ck00BK>NLw;=p#C0{GNI~U`5O^ZlDaC(bp z1ky$pQ1N>w73muNudKGR+I<*nmL>)_n+RxS9a--s2l;Ghp}dJbr+2f{H!WjECY-!A z3A4IgtJ}1Eev{BeUNu@Z#%oVR??fTf3eugl_r$|ojQD3Dipq|vSZh;REY0Cp1lEy) zcpgI3r&SbDQAnT;e_}zCwx}ljo`&jH?*eBO_O`WGs(e3l;jpn~P{sR4aa4Bilm}R7 z$h+gdv$mg?$2K3RnD))NSk8?jEH5K?bT1alIzQOJlI|iX z%|^ty?tYfq$>r1UHN^ruxq_44pp}01k9)Rucy-h`;t~J9gbufoT|OHsRc{aZ-roIw zJ7;dgRAA*8I06nW97m)%!jVLCpASQNTQIbmmreLoy)? zJATRr`a(f6bOD6b9S@HNe%H5t=M^0rrqkg!t*xGhJDOM+{Q)MQ_es~6D4kB&HPo@VlaLXk2h=% zJ!?CZ4s%cKe%|la`TdwJ z7gkXcu=4Vx{^{jOC3LYTwCc6~V>%`nub5H#9j$&Iz*dF++pZp|Cf#oSgPmI=OvAyy zDXkI6u=%}@*~PYPWF;>ibz%YGuFwJe=wuLL?tlzL3W{N7*H0swp2J@bBxK}H_*bf` zt-L(oV|?@x-LEf??+4yoczNW1zC6_5E~fr?d2)4?&{p-oygXOY9AG*sP1o3mQKnv7 z#KHwIz+0D9H(E&tg=UENVbf;_4a#JS$?@ZE5i!9Ov(JfiI_EYPXbDAzql)FG%ImMV$-Wv-JO9)pU9`a zD^U?)8X_(4nb1U7u}Uwtstg7V$@izFZ>dadEO>ffZm>+%aA2WYSG(O=;L-)dXQ7#^ zC`l2yV0~?l%!jkSj&u|6aC-F-o`z?o@=gSls?mZJ&GIqkVsM@VEq{?Pc)qQXYFj6V>D> z^{LQI68Md-GCP(L-=2;=`|noW3zSPhCgbz4Wy`NXy49^2mggItvV+_pW8ucAS8$Mz zRYYKMhs=&bRo}Q{rvXQq;(3n}vv0l)%JMx)a;@jx0bowo9vA^S|C{;$5XZf(!gWcP?7KSRXg!CDXaGu{Pi4Y$AXW_+pBr4Uj zY1{MC{;H~v9dk{f&qyWhlJ0zeEhk5AK$HU+a)|4@sH;jZgEiy@rCUDl4h{9hSEg(h z;fI07LUt||cCxC(x4OJk9%1{_LdT5zOB=m(%skGM8(YiKXj%@i@J5KBQjU`gvCO%z z-TrW2ZL(XXr-G?8ok%(DTkg}~oO5UDP#hzcUx7KDG^&TvSwCNz`sv@1QoM$g76MYT zGyc?@px1f%Th>I@8IfA3&wuJox;>`ff!Zen+#}_-4Z{F!03FS_YMN2#O{_k=JeBw1 zA)@5rB13=KmjLZ+T0HfIQyF9Za0}E|mn#@}8!{Tk8d&{k=3uDm7m0F5{kMyu4z)t% zEz=)DLCKR_(ZGCT_}Yo3;T66#qU2$Wl&sydbSP_c+aOyyi!i$>IOT_OBQ2~r1`n)K zj>e=>T^gNaj4{KH#XS?Uk7c?S4U2oUbo@Sc;MgC^%yS~%$J4TZivrwsW`4Qt5D{)W zWc3OLpN$g>D=KgE^JPeOrYx-O+N`}tZdFoQTgtDj*=P+#lqAs5pxp7re5zDPqmGmB zqV=A8X_gur|EjM@^wwY>GuNAyiIh_BB;LS-VDHn@OsW`GFYVQ0BQogtO z+uPvU7zM(Z8hDA!?MGOKqWJYRtJIxfCQf$GoBdyIJAf0m-z!S59O+6$sb9g#pDx6n z*AbkkZ%WYnj~;ds`M#LbqO@N^2)&7!EGtx$xgC>v`l6{Fdw@+qcy&BxsaJ6lga`_g zK)A8E3*!RDp*cW63CoV73$M5Q#Q9io1g2&yP>y-9%D~=M$N>RO?#A$MaF zc_V$PEOny+n=kG}@uVW$0L65fblg`LD2zI@@y_hc3|E*1);^nAXx1x_YjC9#3B`fv?k%=02Ei{W&_F*&2 zOl_FEbWI1-sn3gsr(7i`HL@k_WMfOe*&31J_?ziLSZq)><>$Dafmscuvz6?W>kmvt*iF}(kd5_i!Rltlcgnvk!vnoN31ZV)*{-27qjWTT7UNW6pSKXtG@dyuJE z5~gBzM7FhQbG(jM;HPR;e)C(sj}cQ5e&|j7eS4rcNrIL{Vdtq3zSDpb#X~+tqJAZ# zAC$tbzxF_KHv&c@Uh+rJ!`qZi=Mgvd47n74KkY!MCMW+|O~`*#lZ12wcFVt1lL|Da z_MfYX6bbHNJJ`7sK zdA~O73+fV8woV&Tx?SeumGEj{NL=39dePKUERqpQN_#M2BYW-pmZ7#;N51Vzp?oN< zfaO!p+i!Cn;L`p;Nb-^KVGd{5wSI3wz>4ti6=g;aL#Qb3LMvFw{1aAC1g!AT=#l-I zb25os`l(>+{vQ=(VLKTt+l*lws}Kk#HOBC<&sC$PVcO|u1V#IRe%X^5KLrd6H>4>{ zmv9+r!`WzL@)O%vv&*LKZ$BKezurQacEqcK?Ki<8`O}eal8)s=$jdX*fr+ivxK8r! z#|DKAC9Hkq{S88+qG|9J@-n6D1kv?Lg+hq0H6mpwm4j_;lP+CT0MXi&N1EVkE#?-b z)+XS}dM^Nye2`*dsn3Wx5EC<_RHeR>zJXMf+Pu(Qe$k$^!cQHv^I3QnH9DN{Iu(f@!Dr@tYD83^Pn2;p1Dn{$PLkpJGBOoAL;1es9&3n4oY z=_rB_`E;0mBN|}K-{o-pJB~n4x}NA$^K>U<%ja$a%uEM-;q&0`G4R6fTrLFWQr?9B z!LNw#=tJmD6z;)t-{4uUibKu!k`{>d39D7Ej%0Vdv7Kr0#;TT!jHtGq;pnpH+von7 zLKeG}Z1L_U?3DGr-r`g+O-+)^&9{AGx+!VPG-zLutdThpYE>)?gw20E!BB)Dh zi4peyFBF-FfWc-fE^j5Baz}AX{;e}lgb90-`>}&5enYVfVSJ5(E@<2Br!gm;hXdl3 zP}&~^qkzG-%ZC}oVD*2+3Ksz@uBQlC`P0NhjZ8e4Jz~uNG4Wi6HO6J3l()uzo_Nmp zdJMzMBcxZ}^QhR+bZe@0c7@lQ?hNe<;Gp6wuPxt_apAYc~p4B~YcNgn@wKZPB(QngFi3yD>DwZXh z-4<0(&qYR7FXhGpnE~x+PLLRjgKJr#EcIIBDhYio7w`%Y#tAw=47{x&Ih@eAvNzAR zGdtE^C3*VQfRVr}5dF9@|2c^8RLxb+Z@$&_B|=!0vG9VZQ3}Dus;OGMT*4)3paR*p zT|v?{jIX)get(5_`H^A?vW6=dkUqJ&>os^@6m-mH&zl&jv`KcSlCkLYrD?aR3J=`e zuGbe7ENa}J);=tVPSHBXZ^HsvK7)yupP38Y91mdE(DkO-wvEN!om;0DT9a+Tr}o+p z8*3W^(IJqkP_Qo(v$*rOydZmIS{^5=Byhi9+5!(|^?$|bul3m`nD|K%T{ng75 zxwaUiM^_A9tMP0?jY4ZU_oGfV? zXP&KXUT>0ue{C|xE(&ePwVk#3W|j{}9-&ud$O(<2gE?5eHF0^3*C>E&Uh!Z|pgMPL zO!QW>p`L}jc-l=-H73$#$(1|KfJtv3HsSJ~p|YaTG1=>G2x*blZCFX!x^(8{9m&Hg z#woG(Xd~r>b7^DdsiQ-X@DwJfFP3`zG`J)RiWm$8omVs;=oHJLFrwhfGH**q*e2;- zWqby5TgZ2`%ue`_h12`^*xxUk^rLS?p#mI7(qG0oYOXC^*LM}h;Qx*h3ps(6$`P@G zk;{L=NFL#pVI*(-ugL~x6y)3T{nsnAiz@^n!9u=I3&C*x(=f*@q18qu5{TaGmpK zA42-AK<8&4a?uWe@|QjY@7(l$|8gzn8T zH$wk&?@4HXM?YVq6^>U(uLQxUP*8U(eBxSq(VFLq|F3XPzm`5~<@#+zglXIt5 zCg37N!LK$KG^HnF(3($4`8Vxg8H%uPd^QMdlLMwv?si8>Iw+g?9H|Jo`pjBdv^+}#o!@+>1-H)@sK=NcT)RM;tLDs7BWkOFNq8SczIOdo) z?7*>I&BCZ>)g{07^~2+Sa1##7+T6>*3!&?7D^AF0&6yxx+(`qr0Fak=@&nssTxM-C zKd8*q)CW7Yi{{ZNj%EfoTW}*d=WB^~7u(0KAI<&*RbxI$Q0JZEubEyBzfj%3?~%~0 zCTKT>k@lml#|`mGjI0y~bsqGq@2_R&C`mlp@5QnCh}&SNF@N;`s$9Eh-%V^< zV$-dp2m;dG-7SrDY>*U1P|`q<1|@WZq@;;-NOyx^pdtu@l8Oj&pBM0)?|9C4^c(k% z`=7DLU_9$xG1pvk`W3Dw96iy;n`ARl2qzxNGVI9Q{t@hPp~5xoPU%5^^op86@_7@P z!gVSR^hUd30GN=_**@UIsd*Nhi8i1B&R!k`kurN!x z?@0zB*;RkjyY`TsL*dUAW}QY5|CT-WDh&2-^r-L!#qUfp7EBzw*jkNz z>yMXo?_d|#79`GVDuGfn;VNb!`YXU^{1_DcvRvh5Gckb8u5FF~5fv{ZN$U?#GyJGjZaQ16rg&+fkGtRHm4GaLx9{E-!`fD>CD-T}67b8=T>t=`<}^J^KE-m5T%u~RWK`pF{4G=_v<$mos``C|w* zIu~!qb($Phn8Qj`Jm(Q@kM5$)G2Yss!i>(Gx4BYCdl^)ijaZw;0lHWUR#s47LZM$e zVv}Kfxz~LaIFdEq8M-;4~|8Uo6c;xp6 zo^HLeB%Hs9$YMd!BFDuu_xml8Rj zwGyA#9qoo0ub{p>6)GunPn@em877Fz948>l6)TV)6yhsW@5rmbaxk7uakrY86)yEK zI-$F+L$1i_6xnP@n{+CnBy7>nig40^Vu1o2js-(ssqF|$An4Rbpi~FYS`80sZ z_`43VQ176_7?oJ-D~BI36Tl8G9}H*d~RmD0^u$m|4awt#x)4-qSd}Du<`w z?{Nj?AC|sdxX98_PhC%ctb!1~RDMrKi%gpexA88y9OBs3y;(P%+6v=Tdz7SkphO1j zX%^+fqSa}$$y*Gxm4GCtqv0uxvmvJ(#=zK;p>43onkic`SO?G;N5T$wXjHpH)Q0R4 z92oCp*4s3zF?9PnTHS<$4Sbyo*jqbVpWe2>{!4p@Hcv%*Q0P{%-Xx%}4r}j9$Xx$` zH7;}d>aE3UUdGQ$_tDYW7Q)loe(#?}v zD_JozLDd-4lP{d%UBNxv7MkMi7f2m*zv#BZ0H!B2J|2V zojOfpv)x*o?<09EOido4r><5-hu!o^#|mYHejPiM(@yF?#SXQ;NbY{@*zL#8gMWz~ zvyE!pGe}Zo#4p$aqc8wQ3XUUI*I=ym$$!IIUH$2$zw-rGTLMGyki)RCEf8m}wg8u) z14qd4x?r>nRF!~R9A=JFQydafFTRJu=Q+26+i%t0#EdRHqJKG?rtmxjBmds8rLR9YcjAnZ@d zK>`kPL=Iu>hmgF0(x?Mmd%&p4RXfnT}QW zNv47u3nfM{xUj!PzEW2p zBjQ(L#wk=<1|xmz-*W~UvQG_+j}^P zAsg8*a1wKHvv&t9Vtyy%EFH#$qsIS32;GmU(FA*(`yV>5fFE4jPoke1LK^CbY^uvfkzsOJBhp*iW`kIWpz4% z1cdzsq&BN#I#P|*Q4j{KNQN4XSEMO$+6nUY=%Yq4Iz0j_79g~xtjYxCI_mNWcN!%3K;vK-$2AyXnVq9 z-qQ|(A2mdZVEpWWT!TXpG7Q2_gf$#;kW#D;wOwIx>a<_L|FMdc>*1!u35)mLLMmY# zm8-)NTAER-^XXohck#BaN8gHS64$_z zm+Y%(tBlNvS)>hmj(hKeC1>mXB?j5i2c8+aQ;*8ZkHiC5VYo1Nk+A6fxm#Xzrr^`# zobDFWd;GDu@>5sh`(#oE{nbYq7da|@Gg-L0eQRsBX08$H3HGm9fz5}%2lHJDcUR^d zmie92*5jX9p9+w+j$157OY}G(zEAS0SBf zjbZh?)x48W8C4^M{wTUMpajU>3|X*3^1P!rAnZ3CC#Mk(5bhO-nhZKgxFKAe zh%7^yW0OR;0&;>4MCA&Z*dfFroRbi_H$=>n3~>oSG$|0Idp8(5`XoB95eR1x>O))= zP_BJYY_vQ=MMZ@yJDDc}B6m}2wS(^DxThE?A3CCp@1HU1&tv9+YacHzgp1Ee4iULR z9F0&FgtY*X?(C3>Ekd|P$Ww6%%Mc=Z;|lEntAqKC;``vri%}jzu9Muuc58fAAu3H0 zg>550P9~B`VvTLwI08r}BqFfli-0higdAH@et=A9258$z%J-28p^1mFg&KRjg>Z=L zu=yIh$xb{ZF2X)4-z9J&iYF7w4JGt^jx`XS`wu+nLd8}uI!W82D4kiBQ1K(=0zefz_1^s)vXMp!86pCs1`Lw&5(q#ftS3;=^E#L0ooN0}xkrPRBin2p>9r z3|!PeL_8BvNhl#VR16VH=H_~a!WuL+mnMrAzfm`o@>Ykxxbt4)2Gls~%4`Rnpp#XH zgf?ddud+I>`GiBXB-0>nI5 zH@{^Q*LpgLg+F60l-c)m4(5VOlIPBDT*BAQhVrZ58X&y2?J1TItGkVet+N6o(^7N6 z;#U~)Au=9ZmT3fb)>JjCw+aN|AH%hNT6v}eA5v&{U&3c(Ipft6KqjsU9hL+haYYl7 zU#!9*908k9XfYIriX_We0y8C2F!)%@JP| z8mT^~=QgXNepT?OlX5|dVY(?7B2iG4o(9!yrKx$-lIPvSsxp&n}jY-4(cBT}Mej+**xp--LGb$7dMe*i*IE*te{szv#fN|dZsk5V5 z7Tw>cpHkbO2X6n%JYWsa0~h}NX62(UEO-fvcZ;DpNlAj5-w14GI`cC{cR2i~CNt19 z1RF5nldT8aQg)bAt_!+#^4LKVmpNA<}e|1MprAB;=^wAFXDWc zk9$snXk6x@lw@_tB*$yg2Oba2WEjW=aiLC-r=jsVSYF&V`-4#avhcKmqtTK<0Pm!ZZ~} zm;_p<`HG}8uQDU{0f4!4hd%}~)EohgJ;1yD9|AV$*$Kl(HN9gQH~Z)O&(-bwH@Rqm zO(_3^G1%qzBG={a(F&Ynqmz^0fle=ogFQFbivvmDtJhb-np|%aa>6(p1J6c%Vk#U3 zZ*AJJxGS_@fOIZUKy8k1;Q8V-hsU~6u`D}u__zk$GS8Dux0ZX*w}Ne@LzgUb}s zwawdgDWr>73lst39{({atz}X28zNk4Rvq z=(xoMOuDguR%7qjE74Qz;C@2mCjT@2VO!Ydd3{olMNyM52r+;_+#B&CRG{1I!ya z(~)SU_xQgT6D-rNKl6cUmqnHT5)=Q%-qYK|3XYOr`9)0JgD;_}-QQXNUQ7h+$HWW3 z%QBqWx0fGsgFSy>LkRTLo(*Wp=;^>9FEg>5{qNS#0T!2D>F9l*v+E&2Y~>?xOvI5U zwcn_~2Ql&NuQ8GKXH2-TI-~zHCgQKq;r$sC?ySyToO0LWdsK*&y+?E?n(^s~D3ue? zdNeBW1YqDZi18$Bh+b)6Y9K#waQ$+1mDl$+%;;R}j1$gme{@&zyS_#_FRUyW{NPx( z;UehA{D^BGX!2x4PKluyM+LNoVM6%AHA_LAB;fqq>({a*{ctD)r&-UK_^Zr7GAe*Q zGEwsUk*ljru>VUedvUw-4rN*EdY2*i`h!pFs8W$A=#z8Pk?R4yb|Zs4&ihEuz4vGO z4Xo%0tLu%Qasr*VsN??o>+kKZE)KZ<7e2Tm%b3f?6WUF8fnV&d;Cn_Dph`>g>)n-K zwG2`Np8CN(<4v&R9CSNl$&{Zs2}+B|X-U|Y!6&KT`C9PZ0d3jm&YUWuwA!zZEXv_eBPCd+d`^h z93621I|7FayUAOj3`j}d_$~>!RwyEciXK6%M(^kRq)!cSq_^k_>9WXM$&}ud)(xVq zX@Ih%<2v?AiRmrrLp}Z<)zC-58!lqwGIu1*#C%fU>&FezNnD+Y5p*maJW}2#G=^dx zE>^IG#{-Cw@qu8M5pN~D;~bgkS~wO6RFRe6iS&7OH!)y*3gzhflNNX61_*1HZ?_2Z z7=kd&G*VJF_M}s#;HEpQGL#%}Of8SI3+dIYjvvY-|7%2$oz;!@=T}}9-A9w{JohvI zzp*b}VKg~kjdgrcl!z*|)8*bIdaPLGFK)e7Zh_ZIKYzVg`>H~mm>O&vn%;O%l&Jol z^{)ezx(opqD&Iq@VA$R7#tVAGwA-@okLc_2`#tYJ_Y9N@fjxezZN5y^bCJe2f>);Z zb;Cbr{a)diwQPY|>GqJ^JypVq%4GLBrC@cCei7 z#R&uu2kp4=Jxq>&2Dm(tE>eDFb$mz)h%mt%`1!NZNH<0Ah%MWi1?VDajnDqnrM>X< zE_Mo4m7oV9ETj_o4(y_==>g$CfI%&x=R8yU5aGb_XvI_TH>&`2+g2$ra&>l7rn(g2 z0Y*zlxZ@pGt%D6^QCpWpI0r16OvY-{|l-?c9FeHPU;F?jyc-2fN09W3!m= zWpP|A#4ob=US+2TH|4*V#gk#xrOS7EX91&0I6VZsZ~n7IBKq;H!+}5N?BMsU10vFiG(Hk?gs26sm(!>5y{#w$`Cmf+`>! zJE*OLlI_pA@Ku(4-^0oO3-EAqybZf=FLhjBkA7OdNO*l-eH9(cRZ9_>#od*dS$b59 zqU3(9n9iH{k!0Z6C)lIa1XEQk15R}Np*vwW=6B)`Q8@LZx=E2668(PN4XokhTj!b6 zR$h=O0UvJ4je28>;BP7`zT%!3=TQ#SFlDR|B>>Wtw1!Q2!;5DaWJHHaOZ|pKj)gq_;?eNT zTkJXW{;Qv**(PBLY<~y4^XM7njdq>HqFPw;ylB3BHrQt0k5lfw^7nT^=fpGm^7%R# zPQU%KdEtU>L;Ko#6lEbJ)^20mI`Q`=GF}RARu_6ur08$H=is3}7j(C$zgHKr&cM zek}^S@$$FZ<@(-gn+f)SU!6+j?h4vOq2OV#g2tUot4Oa_%3Kxg;RFKXuoU4X5x|1v zvG>Nf@G=8t0n=~v@jL*J`YD?;=!-tztJ!u3d*gqb=Uk1taQ&g*=-J>h3?J(K-q#+` zRCx3dAeCqoz%I<5w@v}3^AP`skg_js4HL_Myt{upkajdHeY;w1&0N3*9NV0Du?RQL zRQ~6?e+Ze}@C^{p(3)Bn{nEa)ynTMx_TsBqO29Jl_=;#4IQ9*@F!ML2@l#3(N z=D=3;Hs&M5I0Xw4E5WPQhbLfwAK z4`3JO$3SGxaTxYttypU7BE0;gW7r$ zJHj%Tg8){_{2RR)@3hCydpw2#(e3~D?+icG@9y!^RM0@VBpJ@?UhC~Ec5MQ)#06ucCwU{f~sLG};7-O8QQO*Un^1t_=k*O70w zE?l_SkoIMLSMG`dI;_!~m;_QF-3Gmx%L$}^j>F~}%wgSAJK_ZT)h&P|u-v0SUatnk zu3H4PdAaHq=H+PW682TU(JPl%dMx(10E;z=#G$ofo(tFEHQc48PG3s!eGkQC9POgW z&Ex4NatpSmUQm8)*)>f3Kv0+i?B|ZchgLmFz-_y0E#`%UE^+OMXN5NVoJ`+?#d*0( z!T07&1@}5GGVFcdgVD7%dIMM2%_&sWJ3GSaNAg6-jgm`@tyu$b#q^8=_#`ucH2Ek# z1|T-fztOMpv;K`4Vx=#}xS!b%w*UV&m8tF3^IzY4-%ks!o%W`c`bb0+`4p&b*2;=e z{ip95tk4=Lbi2>m%>{h4GT9?;8x|xs7?>Nj@h;YD+`Mw+qv+Iu^R6!}ft8Ru>>ap$ z+=V}@>%E`vXGBy`jU~(2dF%SQz`9o;v+He9?3UVq#%-E zK$zg?M5H1n{?^v}1K9J`6kWa*%M&vArTz@}3%6EBJJ* z9o0$>^xj*q58tEU>brAmUNs?oxuII{p&wJ*y_o>8!QGBxQBNd}t|iBTHglP{6#5T$ z48>sH!DqUApZU>_)x|u1t;FqCfqQ$LWgLKhYbW8n5bRy^xUry0@ZlbHKdNU#ra!u- zTe6^ETZxPf%TNvN-c^^lXBx=#xKXamE3O z%w|viOl^7W{p$Vy^NlTO056>l@X}oaEV7&E4G7670w(q@9ko5O7Gi*Crv*Jhhc3k$}7_QzuyV?BTOy*}^21sN`+IhuY9De~< z?^oq5M`OYoKK+5p%~>D=kAR29Q6%GK!*15UOXZfW=fV23aWjVT5g0+hI_CpWy!RLG=9+ofkT~JSCjAhcG;613`Pwpf7a>0{-<<=Oo zdc<2cI1>!)HHj+)wUU5NNat~f)R~?&-a#?orf##STD0g)3cPv28z(K4t@jnJO;NO5 znW2Q3jCmDQ29h1c0eECW1@xM;`0$wu>0TlCzU1Gi)k1cE`;x5%#EgIYOLnEI`U)hL z%TFHr%)oKI*Z!for|9{=c&0zNeZ7EC32eG+UI?6IK5AKb1t{e9{=D4-?t0d2x*CnmIZmSiIx0*=-0_gsi3|=`kvSDd#F6nCRg8gFHw#;q0!11XsTNh*p z9tV?dZ8wrW$JvpOCngMJbqR-|HDM-1(=zX2f^5}jJR;DUA0<)LU$76T7g!e~sXMJ1 zyjFV;{*n{WR;$Wg*u``;>Q69V>KjIoEs_f&4-1l@68`OeWN zZSbYRAq@o{O+)E}eOHBG^YsP+6lK#19r#kE?dZ0x#NOmpODg^5R-F%{@^u9WF(vmj znRiD?sVyDprk^asq&h_APYE##SilwfH(po7&eQd$ZM|ff>)*kJt5{)DeMc;EO-MZk;Xnmqk2=tL<|DJp+g;ht;COF_|BE+C~y}@qy+3 zfZdFQb;Ew->Gb9Q%+t}xbD%DNMKlVqGa;MF>^VJIy>r1y{W4(wa`1;DNR@nuk!!`L z8NoIa&eJU`M?&W%@5R_vRUKQ{rK=tUx?w;>8#vdI&qT3w_(a^u1q~NDcxUuY=C->M z@C9S=wPT$_Ev10@JB7_%*ymWsr=7UiE!ZaLdy!fv3H?H>kCb=>qpbhtC^m#@`5^NY zHM4}waAm@l>wm~cpwvJn4+SZ3o$`KCtNKqG z8dmUSyb?Gf$?RVUps)S>z$5||(+D{;Zdp10@yt|d+ozDa>C^mMMo|l28(#ZLSTWmj z-Ryrl7NoCPd4QDE&si1>XX+Ff;boG%d%J$N&V~h6nb%Rxv>*v+jW0Wy0(=P!1*^=^nERwuzn7_X!CV=R=RdrBauCW1N2;&C$JoTjxd*W z0T)mqt>JrOz;ltjCyBRLsF$#$<+h@cyZHA|ROAcdrnSr^ye16Jnp9uX;#awx)0@zF zdBA33k^l8ON?^Rs{`6%s$BUKx`HsQ=ckc+`Y=h$qM0ssHA&u6jH+c_{0-cLff+vIj zK{3Y;mS+RL<{$Tc%}r(j8mbJ?Q2G#?0ym(8ex|0bZ7rZ~+FaQ3JLk99CK%VO&2!1Z zDfSOKK)n2`w!eEcb0GzP%%s5dZ{J&$C7VvOO@flNV?F}mD+%GC8JRy;TQE6_in#r`% zynJ*Ktqs%&t^gTmktx1Qdtais<#!gmtL+aBzB1Z?9=PqjUyuaPwBjT4;_`*MKXR+M zoNc*yhHgIT4VDMPpVosxZoNGGj_9oXuAJ@Mt8MUti&!D7-bcWZqdq0&Zj(1L9bUFt zIv#;SMaf|zg@G;yZ25s&8K|~vxbuK1a%k!SS;6&U(EgGKy>BS*o^hOSCyxQP!v>4z zfb;}$$YBYeoJ%mK{MS7Fa z&x?8%dgO?YTz*bOqU+bQBGY$8;(b{E+TvFkePfKWy zf6(#T{d;cxzkJanZ!dP(p5P(AWybNJy^z1e4t1JF!Qg`bWT|Sob?JnMsKw5$R(Swd z3W|N(SOXgK-rz;K@ZfpY%d(4UH}3I!&mhY`oaXBr0w2Bn=(8exk>*%;#~&)-U+jy+ z2uGdE8t#7oQw99cR((;IR~EGz9#BU_5Gm?|UI=u&B8QsPZ+vIL zIBaWyduU-JN)-d(z}V^&V+{-UdIA(WH-Mqtrw6>~VCYs@htFaxtNJQ&5=SQmI)zIk zF*rF4qR7oY)@2y;2X6J(uIcCP@U={A{;sz zBO81MCKdddeOdMEJA10EcxDBOEsw0t3?DwQG5bssc%_cw@#(hCW^m{1MJ|sl#!d?+kA` z=2#yCnn5UuXJzG(t%)CNX=r)#a_Ab;C<@97kI z+gVuK6CkESvUJ7 zq+#0VjFn7&e{2iL-!$5B$Fe%#`+oggz5n%Z?sryqHn#O$**|mwkCNc}2DJyHOPlAv z+k7f$|FE{le{X=XkGO5127Z;tKT)1c8xL2$!V2!J969hB3h5~@5Lt`xMZjSe11gF@ zk#$df2HaE`fX)hSvY)@7&ULOrs)L!Q;5rNxSy$Ep|J{(+{sK!VP67bBh_g7K#!)<6 z)`Wee?|+Sd_7y&;fyv5G#q?InqKWUS6!K$9JR~2rJxQdwXI2TwJ zKL83?l9GTgKkjvgq3*(;lla~al+MZ)jx`%z1b|T=H%4sfA5LDhBKZC~$`Z6l~r%tp3h)fNgBq{k9G|&ZYWgy8eaI&u?}$b!DRPRC2svX4kAUt7C%iT%3dyT;t4Lb>Rh5j z42)9vy3YZ{Rb1!m-9WdMpZHE2>A7lY5D$95v|13 z_T$#OLv@P(z5%DHsr$Tfq26}+BqJv_$;G_sA2x6KS|g~Od9tSR5K zdAkqv8K;L|eBKVZ2+;Jo&E19pqHlBp93>oZ8u+eE`0ip2i)m<)?#`kdQr(ABz56T(@hbx zAvHj8BI<~KG9TET9a_T4Q4~gVA@dt?*$52b4fxPHa8qg}*f!Ay@-)CV%Y;w-t75tK z34p)-*1I!a|A((WqvtojdIMLJYJz`9W@@eZ&Cb7={R$?%(@&({0?*z%KrCJxiNgIS z-72S|lO@iVb%6HjhDC@?0NA|@ZhQ#&31dAg^__<1YE7QcW^ld8Y*l~6*pCU}Opx`V zV0r@CPiKRfWp{sESh0--uYU$tG7WoIG8Zm1z}vI$jilc?d<#0+cCZ@-lyPwt;^H%uH=Kg~#+z%DL&a!BL`TNNgv#>eZJGY$<8TC!hW`4?XYj1}`xkq#{C}S?Y`iLKT30th8f}-&7CAN!7A=?Xh$7k@0XBERj3ag5y~sf( zqkqnK9%ul>1EZ03`a0@LCD3D>h)F$0s#i1t5ZKaGz={B}WY3QS;1wuHNLW5MZ%(-E zvU+yAK4qw8JYuZo2g-il`g$!rf!taUxOkC+SrM>HfJ4^>K$DQO1?bJem)}Unj*Hbq zCN<&3wd@EkbOj=*_LZ8Om$PSY--_$_4zX$s1>aIO0QZ+IKAOfJ>C-soC=~xk*|9oY=4$662cGNVT>WmlKw=FWE|#uOiYQWinkra82DkH2e; zxDM!LGRVUe3c!$bS5jBj9_D>_LN^jl1b!7?!L{AYjzs_35(4ny_^@Rq%FdH34I~ra z%GP)o%b_upe7F2a#(L1j!-^HHGP?QmTYmaVB5>YM0WR`&`OO#2Oj1;wOkgg$WhiMQ zf}}wocA#PIxBGQG(Ce^b>l84>x4)yPGJb5tpQ_C3yjseX5+4teLK>o4>kc7hshy~VZ`jN&I>mg|+jsGX?Q586#T;6gc_iEmgLEELeBidX`u9$?Ar z#{)hT$gR%?_NrvcxHwJmR!q2x@O%Os;*a8`M^g$BJdJ+{_US9cGJC2*XSvmqapXer zDg1A99bg9Nl$&jEJowal>~CGz@C-&E^&#S`9Bk3pZ*uBBq4V}{E{j)#VwR;=Kh(i0 zyS49Oc5HqM2c3dIZxZ7RL0uI3tyrH&EOcHqI&lGCZs(_ozQcFwI zlsf%YCQ8z0`baAI-l2!|~6fBWU8<-mRHu&hBLl ze|j0}G^K(ecj3tld(a>j!l$>+<(_u|k4j=_Ui}78MqR)IySsq)sa3JydNZ-4{#k#C z7tH$?+n$!}Dk1UjGY2$@R#J#Zq01y{FlM zirw%v|E~Kn$x~8&sFrtoouZ6{YIcsxW4m>x|nkFf*)*<2BPsXDLA)Yi!%f6>A+o+b#*^X0fMA*r-DMmW% z`$U*}rno?O_K|_A7%VuS{7$sc@{(Z_ME#sk5;`E?D(57LnXX_6j3<;pYc~e69kP4) z&-ug_=3ky?g@Q$B;nPZ!`{RGr82U?R8S(VB4{fcf7%Hv-_Al}S+q*VkFLJQ^`3v4r zwg~bGLvPy)HTEmx9)T9UvvcSDz*&EsT1LNT(ktJ<;L_dyDf zUnW;t;gvzPkZXempB!|S4F!gm&NQ)YLegAM##MC*4NNFN?VO9>I>GE3r~(S zM8B=1#KluFxOT_ujd)kYX_WzEPgp;u_n6KwCGd*4M~Z6x1P-2r*LxP&rv8YQ6%Z{> zo-|KgPF%J&qgp&=Ili$Gc4|UX@zVChW0Dkm^D{a(T|)6RFP%Av7CqKq=N1~GP^@=; zKSv92L;6vD^tcYH&+Y$OeQI}E_HxUN9WOkP{B~{uXf)**P@V%T!yh|;SD{HJ&N!W% z5w`%z5K~5gVFNv9$#8IgJN7}$qHcCh?y<75sGcnHTWrnSPcRerFS*6-8Lugm*tOBc zjcuA5f%}~f6>%TF|G3gH*;2gN?|^CI);~S|1w@NC(GEhMjFAMZv4AJiS3Vw1il;!f z?*#zc0Q3lwG%tVHv@SHjkvXJfz_{mGWP)n-QHT6MB4U&a#co`NN0q(JgC9$tQ?@Ha zomX;>Rc&aG)uSkII%68q=&j-FfA>1+%AJon-E80H_R+DP=!_h7g0Na0evX=eYUs3B{(g>;ySMU04%i1EAMCOZ6=-F@sD2hnt;KYy zVeSX>)3)NP^h1zZz^(tEQ_MDwccC{s&aMI(F$#O%HP1VS3AUo)BW&PEzf7V;mMa4| zLW>93MWM@)OaAgaWFMsp+_uhxJx8V|of?6;sYxjADRcUEL4b_|oGd(s!FdAmVn}3< z<6?^@nz>WkA6$B@o1*6tUvYm-evY&rc7tHeFmJ1n_H{Qv1OC`uDb$D3ekZKEkCSzc zfacaAX#BCz$R~ySI>Tqj`oo=YVGR+2KYAA4_dtGTHXoSW+|wNLuW98kOf0D~I?&48 zP{$}IDCY3=Vf?dBtP_Msf5}e;6r)h4zUg1b z3FU$}R<^;Kw=V*4XbK9vu++Gxu4k>F(S?AqR* zd%L{@*d_=>quzXNc18s+Hg01)P(l0?;{w@5;CqTYoe4?v3b6<{|Ju(k#@{kE>AG>b z)hW*0E`as!0QT;mlI%o_U~XG^?zhiFU_(}wK@7;2YwQ~D-?VITHwTw&YQb^Row!hM z+e48P4NFASF2YVD%Q}8qH(nLx0cx4fgOX=by~90AGJ2@z+jUPa0s6w@(%M~F10u)i zf-JyLQW`=naVQV@#~#$8{^M*_x<odE%o_Zkv{UEUkQWoG=?C?0&d7h<V)ESo`5K3o zjUFP8bOOSeBPmBU2G?U5R1I3LvMCSx>q8oe0oImE1O9yY5Jk%)gn~XRLO@&Z!S*(U zQXbimMMX{{q#>LY8OLXCg7W$h^;t+iStwW7AlWZwP6EO`stHlH3cnDi!c`s@?F~hk zn)ITKhajpvSICTNn78jFHH5G~*<*Cr*}Qv=z}+Gg_nv3?^t&c+h=!w&?lO(j1Y|>V z;}(xCP3Kkw4}>HDhtaBJ(5V}~k-7FaFo+ljjr-@~9U-Jf5{Jem^E9?jPM=JOZZ`NT z8$IV0$c^5R_)>cQe9r~&wKYQM3|7P=Y=%qIkXHr<#~)%?F=+IL@CceAMi*MhmoXt1 z?Z?=N81PpWyg3p8;hB#?OqcDTK&D2-%fL`PfL}AK#Y5+A*&*HsL9|9QcVtNeIXYJ} z%lW#CzkUp9FSG+D4pJY#D1ThfBGnqKDjhzXFLnHt!T9=4oX)e)Oa)GpUx@vjOE#=4 zgWth`W+8K?BIZ?~%C1HpeWX{*5EH+}a31N{&s4rpt+2YxFE7$4ojQ#Ug}N zn9Vr=RVDc-T50)b^R2(pPwnzoaw2dqrHIs^)=)I}V9e%qT-Q%})5xu{Bb&@|7DGt! z*ffejvCuv;hss>hz@0st#~Z>J0esiHy2aXe3xB0Y)1RD-*dUO&Y>f?JbNw!QGZ zhQldEU61hNtv3o#IaVs%8lG35-f$s`MhU4eUphp2#CIebWsVjg*-d6$fbija2we;w zn6qbmA;#lm*r2^ZKb9vkEkxuDLP9qikw)B5ha*HABae+64%w8;6Xgvcyec6+YM{N+ z0+pFTRPGg6+4_)SkvyRYEkYgxaV0h4OroKi+MyKl-dG0QkVbAJ0Zu4_ISyhoz~ET$ zLeVM^Id?qPVRFyPsWR$fr?P&xhvvK;Ep}L6Pu;td&`3-b)MN#*8;WOIXmFe?HM#r9 z|E@8Vs%3mPMF8uRpk85qk~|63iOfu02vszx!zX+Djv@CnE@32;W1#>3t_lZMWWEtZ zxo~cA$FKrrkP&@V_iO5qBlI{{jo6ik7&^98jJKUKkNOZh&WhK=q6zP^8bI1AI zEs%)9d1L6EZ$R$!SJHVr=o=AmhH9#S7*q!!&kQ@n6R*RC=ju;~;vpKN4qv8gi^%3W z+66JrN#aK^aj8QAO!A0{GZ3EJBm}@e=qxjYcyl%sFJT5^zI(p&Isi@6}^!F5)Gq~Q5`Ll zQ7R`B(=n=WWvJHiBQJweEzx`tlJGHhuCq zwkeE5Nn47`5?r<$HDS2gJ7UUr?JaGeNbK7i9|a}wHuD%nb>tCqqCJV*lYzbWpO=be z`Jr>eb?$p3I52DI>rp!QX%VbI2xW>{bq$TaqH`}4L7n4=HiVQL5qY95@;I_Fy%iIX zvrgeMf{<+ueHgd5!caxDah`VylJoOePu3}~fWGGWdA!`vDT?S9t!>0^ZO|!Odmvil zRy&zlZRCD7OQ*~uNwnZ2<>YiB$|ESdx3t?$^l_K)%~8WPGabN&ZGy<5EQz zC;Qn9VnbV$ed+4-t*($bi5e1Y^umf%W-)4h;ul_aTWP>=_}Ld1f3JAxQ&H$ z9CpfhVJDoi8r4a->?jeTzEQgk?-57U2DTuIe3P#1&$5j;<*6qcFOaqbbtK!7rfCP+ zXgv$zpT%i%pm?n&@HM8zS&8hX5wlZIhr z^oVlLT?(zG<{X(YFZT2*IM)IGRYxN~AL-utQJFdIujvmy2J3Zh$hqR|VzibbD;|DQ zaAiW=?vm$>WIZQH>DZiOtQ&1$!JCseK$=7Fv1r&aeC(s(3r|8AC%xg)ic z+arFCt|F76ZoXpe`ZA8_Cp``k0wqAPJkO%j{8^Tpv&O>+AriQG{yU!w>9Pd8QIo} zYch6dBJr}(XBnoGlRY0qoJ*+ArI}b18@qcPEqsKVIGlQYpvaR4LM%gMWP4TMm)m^u z!T~G^rk^JriA>1l!7MxxhY&)03{FBKwSRDEg;9L@3w0_L`f5)N!oY&>fd%j945zXe z?oTYeM8Bns%?DP!^cpX2{Ro(UwgP6`%y(ijw$ z0m|N^BvJ+=R2(XXRcl?z;NC9Ez-UA-axz=z)b_CDI8|?eb#Y4iHTntiTx~aQ&e$jh zb83<#hi9gqH*wgfu{4|}Qv-@!CO`L<;-)VUR51ZC1#}RHLVrE?kQM4<(UJTdJ4cft zr~7}29fAh6@S%T3Qv$y0RT!X+$-Ohxfn+5#$7mz=OLRVnEuSk4~YF z00%h0XYn8K{TwhH7ko(F%FGGB1xHGH-RxN~Hv=ubAQyuE22OWyD1YIT2|!Z<>wb=% z(+}5x0pAM{Rbn;ViS70ks1Lw&ZC|t3WI^iU%Uw*zk%$8(2pR7Ini7hP4tG@~^QR#K zQ}Qub$ywwF>j*)KNf6{!BWwMWp+-nhg30g>g_njfY&!&4qwT9art)ME0!zNbQ1~im z7e#O$7aKeQ(Q#_u;n8wCd4Z*2;pj!d20xhni_#t`CtX7~XGZ}Kn~lCWhjEel|ASACV-nK9m@qa_6vp_j1*L#KpR;S{r6inM#h!RkJjCOM=f8Mu?fGJT;<_xC*ku&h+rX0XVyVUaDYYfX zm0i2-3kPh+5<-m&TfET}_}Q2NX)3TyREGHl=)*t|{O%>^LT5)d;Iucx_al~oe;UkS zqa@>@L!jEojUA}kd`g@c+7epOZiUV*;_#XgpfL9tV~+sOvgDNOZ=ZnOzzOLz_I=eI z*QP7>5Wz!mATVzcfyF(u-3#fU_W7$=xjoU`-1y<75#3TUYqc9-SJXUN_(W*^i-O)m zI1f>BP>x6vMz~1J5MBj6jx^^@Iis|~C_0{&^qIzZ`cRL8(%WYLFHm7Fku zOLO#*iF=E#UF4e_d7}db*Rr0LoijP|gS{yX=HAA_5S^)09uus>={EVfggGgcfaB5W zDKQcdOEiabv(r~LA;3}q6qH}b(IFQB#K8Q|aRla^Qxyksbb#>2K$zRp|8JsdVm9cbaIPlT9e?Z7_mjfN~0~Z2m>zzYy19aBT$=I-%Bm400KjYQv>clZfa&K~ZZq#WWI1CVt;zviBtM zGzRukEOdPCjdOgy(z}L!E%9h6I&-~GsApbA*9crB^!pQO&+(AtZr2Y)2d^kd>Z;%9 zyni=zRyZbEa!I*pLRI`Y zb9SRaX%yW_Z(&}D_A>{Fqf|b4ssWcIg>Eu=9+RTI*`8C>uWx0iCrtcy^pL1x5EajU zik>%LgCX1UgXmGabFhQt`tLi)e1k<}d-+Z8|EZz@V*Jq_z+d?<6>VGvh=3W4m2OB$ z4epy+1WU zx9uO@kdi$D^`Oymr{-N;02do- zZ!i}O2|MYij8c*O!K1x~DIBJXvQ*Jkh@8&u3EO@K>qtkPDxq3BlU-o&D24u6G~Jc# z8$Kx+P6s^N9_pk}Y-^ZIyVL6ZJPmOpJKbPEj&xanorQ>1SrIYqKgZEKU&y-bAdYOy z58{aCU*d>#FAG_5QT%UN$elBM#eprY-T4IF&%5l?a94ehCv+aC}fq%J)JyzXcA zs80VopeY~!a8}Zj`DxOVB$M;2s`{gtJ$@j_YnWJ)&HnwUY4Qz z)y({5VB_hGUAQv>*BEgfyJ9_exedu9NzZpm$qXMF8Dw>oM*_(!xS!StdS{V&{ zkEV)-QD&3w-}OG{P`TZG^!@!^)Z=)%Ue|aIX|lR~{?ctb;dN-|6-eZMz5DCRL_iK) z4!*0t(Q?1--ubBo4Rg9O;Js^Q`A+l1V$_fDa;*8KU$C_GlV8z=;HDQ-&V?>?49Cl2 zFVFeV%>>L=-jZQG4$Mo?W`QgVoKT5a3i);fjTAk+_Y?88v)=G>v2+0?F(9U)YW!$C-uBAQ$fjjNq8S8|C4y>BZy%* z0*0mnR*Dv!>uex5BT1I?wkfS6PSb*|OA8W1d7&%9Ntmm*i|IpW1c_Wagdo?>3<@F8NXnkYxZ>8w)^Zx%a$Y5Po3QR*h7+cJWfd~OplD9HTHaLHF|s3up8$bxwv6n^e?HiQ+B*U!8~X)q!dz-s(ZQp`R473LRY~ezgO;q zKe$}RKN|jGze=#hwxDxF(P5Jl$FE+7P>;OK0dSYR8`GLw5^o;A_D!8#X!dt*P41M4 zAS3<1FqHE+)KPsb3b#T7yl;S8lZ|F)G(tUU9lM+n(KzVn>q#t)ml2~zt!Cu3bxfSVQdJ3={@+6iRn~ipbjG=HH%@1pV$RBL=jYt z%%?_)tZgmx8;lfLW|laqw=y(|QqfXY$?!<^&{5qo?l$25%F)Z>7EA?ej9o6aEFsA* zeJO-gx2nvup^1;#i!ONeb%Q>HGlDC5C2`7M5_Xmk_+t3u7h4zVsEV`nKH^+nQK zwr3;z-@RopT2U*)_%*OtNA2~)ahGY2m#nhHmKLAVr#|v_Y5Qs-&3O2N##WZ)l!J=ED4qlhhOQsY;?O^9eP1@m^K?I-`0|=bdXj>C%WphSx=#)wZr2y( zdD5;J;!ORW=c(-?vfYR|gP~>*dIl$HL%oy3wsQW)^Q1PlfPw=&PoW69{;bG}$S34% z4JMV$4UdMGR=wFql(Rw1#6z?Gek|RwaCzqYut>g z321C(6QqWG1V>)H8Jo{qT`BMUvrvQ_g$ZrfzG$q^O?Y~pl)F;M`b<4@lc|Iwi{-}| zdW1bW#0QJ|VA}WiH+&Kl*-AL*($g(*7+8Gjh;#0CZ7X7hiLUzJ6=qpYKQeQ4Axhwg zWGQx$RAI;+Pqbj-f3krM)&4JxiOAdKFp_&fU-EGK?%Rb&NUpg=W(|1e`4vFNlTm2@ zexF_R`2v!HxJ;=K9EwZQD;MC3{lwJ(`B1N#s+&R0Q)>eEUc6R;-ezQ#| z@e8rAFaR6)AE#Y!-+r5|Y^BFwDswVJZ7Ro%sHxR~4NOv?Rr^MX!Y-&dDkCheP?cV5 ztWgWtz-X>@C`IVDdr(*8qVr(+1MF}Q?)$szt$3HIBl~#ow{`9&GbX4djQ}d*@xlO= zfvjLOA&|(dX^7Q4{>{LXa}~|8n8~}+cN2}8Koww{u=TX32RNEz9Y*C^u&&d}Eqm*S zUWksK_^Q#;DgIsSt{+93hDoO&3n?McEGc@Osu(3aT4qzDYbB2*(uQwnD23Zn7tWwk zEO;8H%c?yc?Ly6Nz~y3Fhih^J_TIC=EtQ$Hq5L+u!DuI7OvJn8x=n;`BQk5a3F-eE zCp1|mNUzUAoW$!P=AvYr?7vH5VB!C3XSgrvMKL;Io#6>~yWUsCe%JCw$F3U=5SL8#z^jMk!ZyBN z*$>_wh6PH+{OVAviZQxrj2fuNew)vI4`rP6^_Ez!ITj@iJHruKCasX6(5>oouMSB^ zqO-!rl?%a~c4xmY89;Ijh+@MtBdK6(AIYw2h%KAaC#9`Kb_nEFL)@tH`nzYq1L7&z zKcGKh(Mjg3>l?A!T^rD}m6taS_S(udCk8xIZoXdqOd;?3xlxr?>?{o4Nem#FZhDUz z^|=6^{0J=iMH9syVj}IyBvtDb<<2^3My+WHeGIOi%htRW=R+WM#uXXup*&W}A^x^K z{!Is+a@}5qy40qleeTkbp~a6hx-UdVxHe)YDnzUxJWJ_OF2c3qut1WH$ltJNB5#A2 z@|`^Zk;N*=PPBr+%=BvoDZkI>a;5vDy#4dvTp0(ab{B%m{Tys}VAH&R=ZrKg1yk1j z^3EhwjvsjEyF+-vJM--ue3;gVy012{Xh@rzC~olG&K9Jt#K6a@**YRgSIay_+T1KV z6~T29LA8eH)q$ul*~XpYvC<&%ep~i#lAd6V$2H$HJt=`iE|CopF}jfNMb;CPy$&c9 z7Rlh>#HidnQu~3ZVQp-_r+!H(l&49)2^-a-*o@7Jc#+R=Vpz4=d|*_qrD@WxUru@y zb=_nDB_rf}=_)<|8Co71aBVu(#I=Dk;Z?WbyQAk;yIr$M{KOcPhu=wx4oTIISqfZ^8| z{ZIWN?{bI;6rWut1`(24aYPqK^1W({$aWq^(k`!#s6HLfw~EisQ}N)^X(M{byb?-9 zsJV1k>rQBU>&AaP6vJ1~Gs$MGI4GTc zD1&n4u-VfJEqe=RH(kGe=YmR0lK4MbCTw_|R$CHba7@&Z zT)B%4Ftak5`d8Tqtd_=8%MtZ1A6wfl{~|X~o!r9E2QfeMcj(2{g*f&4H<}=L6Ktf$ zf#gzNz}*39UQvLLSm_?2++(M0*p$tNuWz`6MOA8aHn7Nz2!pW~R7q0JSOLI?S4Z}x z(vCTN-0HZKwg4X;D6jVtYOJ7Zj*Ti|GoHD7*ppg-&02FKBf)@B<=g>@H3j@CPx;aW7FW)bOhg>p!F8tT)1jXA9=jn*h3EdA;aS;c_z+9SMbn6WEEyvl++wcW{m< zPD1wVU2}ojQ7{P=xrnAWNNZnKF8h^VueEx8Y&M3BWXB0}m=*8v-jq(f5s!|qo4?{_6r za0?Psq`0pv5!vv&vV;LWKti$``%S~kZKzN1ksh}jk9|HVL0H?~%BQ~j9T@rO!ok7r zKv{*ZG!+E8y?+FuZ>c?l`_{{C>8Ge|`B^~@ychm4x@ZMaqqYmRs9L;&_%2>Su52Z? zAmF>w7G=*xYC%j-c#w7_Yh1r>Lf8c9kF9z*{w?8CZcV_sDN+SVC}>>Pz`8XIqMCwB zH{6w`OOtHG3e?^{8yZ=45fqNrP(f4%r8g%=raTv8a2Qo>-a9b72{7_NMRc-@Qq7c2 z6{le;12wC}APl`Ah4A4U!UakYLnNRG&3(X|mhJInA9!J&`MdPW3GT-tELvYap}NMUy)la-BybaAlDnPQsjf>!NXpm$=6jcK z&SrWCy2ig$kwjL2W--DGZq@(pRBxkIBs6bVPOqn&lF!8!e$;vLZV1g2x5~%hD9pS0 zihTj_y&Woq*QGYTMV+LNTIY0^LaJorWv44Ih7PRX=R%$Ez~#y}81mdvUE|@xOfb{pX}8#?o?g**hK8G zBlwNZc_4Jq#iOz4KEfao82T!CJdyU~hS-TwQquW!eR`lpM!l(uHCvC#F^dcw?per| zo)ihFA}LBCOb82gB5Y)%lXuwd)3!tKV?0}z+?N1mY8NVxUL90HOhic2jSTtadGViI znSDu>=*z<_!o2*iUY--EB>MhheF<0mqmI&*gzc$@SGq@Jd+@M$HF}&Yr(Ayivs>l! zEz@kXTfPUQRfT6xBjE7E9I$s0Fw-1sUjFPspL&Wi?%2^S^NNyb(`P@7vsbRrSm4kT zM@4TbBB+h7@?CkUtLN0xbk)9%;y-AHmivJG=qaALHlB*WQadiLy+uTbhnCD`m{*j9 zygX!(2+E`Vr2PnK#JQ%ODiqxR{at2R%L%gbs6tHT;??CY4|j|y?Oj_b1&Wd`=?%my z;%k_NA=7PG7W@;&T5kE63&P9OMbUCoqQ*y~jSa_kza`%*QngJcgag#lX%hP83ieQVzjt_C| zOL4G4@U1e=OGOIxtFixql%>2smmUrzfe!X>Z-*|az+g~>!_U7a9Ab5W4)$WNr_6WN zm=3qFhFqz>=*ypXRX*|E-#feSrghDLucFHOUovKRZ(jm4o=unb7j-@8t4*;NjJP+i zQ5(s=Fq2}y#(I+G-$+4lVqC_QRmD6ggJEtCu0a`jG(((T^wmU0-fr^kkT~XiB~ljV zH)-gYvzuGjbOz1*qYy$BA)AaJw)3Q}$q+Mq154L}7jxCc`2|!L5!Bg!@}4w-ai&AM z$=vfDoCr0~ftCHa9?%}u_Ng{Di>3EK#>}L~?GM#wpSGG0uFx*&n7E*B>KBdEZ%ayE zXJFRZa2^N^-u>EU(+q-WVF}+5Juyns9!=F}&Kkky)rer<-5SM;X!ti;I#?5Ru$GNV zh}I{GV7J~Bx8&`Q(Ns!&D|TSX6ETXHDwl;lt-lgte2Fyi$XFMU`xUYr5*`@>y0h#gD?@x^1L?@3tXn#c71wIH%+er ztG2|Fad?e}>7;2A*ThQlPEwOzqtBKGDp%O+ESq-ICNul{bD%zP&NlmS;mkoe0?{Wf z+PyD@%^A@#(cZCiyj1ruf|uP2h_NuKzf}$m zuoY|5q4fp3T+=rR-P99Vo4wu{G;y8EsDGCtBp0h#vQ>w?I^lAU5~d*$mi)uq!s94j z!ddkaby?~6uhvDGb{PYGasU;TaN$Syz8v|UTRT(um9(i(819z`ZDSby@v5xq;l@eB z2e7Gkcv_(_l$gKjTB1Q^k6Q~{vft-raZe!j=6R%iBW#a#Ob4bVx5^>ZW??jmTjI@w zz!LD|<|J5MGOix*J?OB>So#zx3-Mw+@HEYzG~IupThQ@w`^fW+)X`2Z^IglQ_Shc= zc*Ygl|LSxpDJ$_xVP+c4GAkB#y45f9!&YjUltI@LH$Y}(azv~?NwsMQ>oKlNS2K@- z4z|oMhC0I&?OICUEsB2{xjOw(F|s-Fns(aShXV&!eG_>(Gp~akekmr30q&E^2CBx7 zO;~Ywi;VgJCPRlU<(d);dz71_QzLSl_m)h;-I(^%GkJ+}jEaecDwAqHc9cc8&4M7P zXNKxvi+1+ixO8VAN5Z(hz^Infh*qVXq?azgR(#YfH{qNmwmbQpJT=1X=7Z}l9o)aA z7dPv}gkaKwoov}vlU;1(wuZ9@u>{b3O<(F%M4j2X2v$5~kj=uR4p%vNLk}4%lz+g= z0~9M^0!$}q!5#YY6YrZ2J2@cbYH;5j$B)*jgRf=}SHAG&RAJ|!JXyVUWA8a~ZYKD) zRA<8gEoEDFWbazY&786w6*_5%X5&pu7`!mP(&6oQSR%B==MpNJovjb{s(kFbZwCCK z@I~F8x5_Gn<)a%>x7tmoth0J*!F$Xg9*A~B`;?yZB®zt;QU6W{zhlq16T?pkYq zlAip6x?)5}U0EjufQhqUK{vBtsm)v{O$Tl-z%g*i596w7eTq6VP?=*E8N|k5=C-;7j$hQP9daiv;Bn6@aSU+!*ErN=Pz*^ha%>dCz>8=m1c*U9-F*S5qgY|r z5Nuk0L(JVfAT2mz%F;RFU&ggg{Z-Rj#HQ~T#6*iay~{RP95GdcVqvDhY+3{{ng1um zRDl5c;Y3ujD1Y^riW!mD0VUrI(axn2OZSecF#))EA;+}tj}v0)pUDDOx4%bu^Q&{+ zoA)NcE6@qH?Zb}-7M4yI1kxUz13{}S%Bp}t^U^+@9`sz=g|9Y*y%;JVQKK`~LgM{#qadHQJn`VrLf zcI3-P`KIChK=g)`2!)R73{{gU)Ww4>dbNJr@GUqEM8pA`g{?@?c;h5({D$O-QIu;y zu=s3Ypq&TJOSB74!;2IF35quSu3x$pz=#!ST zr=vbzg_PJYtS=}|gvgz4)Dk+~{b;8v@|PY#kq;in1LH^?$O5j?Hcy}H5|f;5XVyUX zk_+7nuMl{mw~fd?;k{T2)3*7(A%>LCUKM>~2Y6Ix3oP?G#uXg4ILRl^`H!gpCq?u! zPzHDI|Ro1y`;{ zk}6BhRY>q9cDi+O8V52seHDN-X+Y(D{{H(Jlxr}gogmQG7_v%l_Y~~u9v)n87z99A zQ_rfMdGh4T?;}|(6Ago;$*7Sj?t*0f5dS6yN+!0>v8I@k9(ls`!~7`gEmetYGU>Hy zGj`bZb>652SR*I#GRWQZ>DUd9gW!AJbv2XZ6$8vV5FVdojaa@lWUEEIG>?%hAXO7hGa{QsPv=J){IU;iDJ&Zh>USU>$j@ZKp zlhh;BSJB;n3GDt)f#znV>|3g|oDV%h@n4kdPQM z&2w$((H@2xHNgGv9wwo-7%{@Ks=yqx45y1vb`ssDU^hQMP1$-070|)$a}?By1NOvrF*9-)ml3V%s0?y32!n5mF3pd$_&jm zzhr3xbJVe}y-4#s2uFA|jLp3R+BuDewCi^@`bVR#QUxz1f~P$r#qrZ4wodpuHa-}r zCBk7#M~HR>rMbSFExTh5aBV{pIfGcvF|1sA=exCdkvd~5ju;7%JKrezCnVHlDgOaA zb^o`{S6&N#$Y%OkEWf@-ykyj@I%x<_{iHr7mW&#o%DyqV88o#h7DdfYVZKzTGo<&Z z1yo4M0-DIzPC$*qVf8(Ln#f;KV_w;S-TX}@Y}HK?hyyC1K7X_ zWDMkq!C37OFIunHyNRh{NWPO(xZ?`D0*A!!u71irVdZub8rPi|E8-#GT-hJS6XtO#=*Zpyd zTfq){_VVO8=q&Mt0^}6iE_|UZ#Sp`sH>7$Km-vWWZ@B+}oF~K%Sc@n6?>ZTIP0)Z$ z9V~l4EW785;Drb8qz(}sGKu%-6xj8)d&-g7a69GdAuQ=anF(YT?p!sDdg{tO9^H8* z5i&`Y9Db1WM*BXT(mH=0luSxLHuWSj?O17Bu1?2&q~>SFd=B@lUjz?pSg;zAH900u z4Y@0Gs>iB23V;ttALn*4a|&9GmkD8TQ z7Jw|LK#nyp>L5`lew89wLN9XN-z5 zLQN%L%BGHfY$%HrC#Z*5COc#7tb(YIIV0@&I52Ta&`xqV#gEzN7)1U45W+F|1##gt zV+-4Mx*wC^`e0(kId_C6JQE>0u$)aN{w&%`5ble^ycBaO=?=$tPZ2$);8^*m6F(Rq41WG`H1hlyYeXDei!WT7nN7!JDTZkG zsC^#B^vkRW5(?|*o;*yEu1$B`M2D8ghQ@+l9DAI3Cxb@sx@GAvkFZc6n{aEzu&e1s zPf%Z-E_l$6@F@?5nl!J}vhfalp|U|FJOE+L3{#?A+m291WinEPO#~rNM1oy28McPS zrajW;8f4)IPb*Uz4Q;(34E$h&Oj#8W&>OY}VRo8Q=V|ZVY>`R(Dr~^PMcaUpGm};- z>_qCgHa3K%9D6*B(0*H+RghUXNvAUK_kC2~wVldl_q;-YQr zj0hy@u-!9QbHr(o<*4vPSOv!!ZIj57Ov>Y789kEP4*C3<>p7iG*JOH%%*6(%OWBt9V((n1UUSv~jo~DI*96yFeBZx|p9$_9(K=3T;7)~98YBvwjIZdBcooJ+XRUE-m zRS|#Bl{N=aeccq5<;JB0o@W~o3mk&6utcam?7}m1!nY#qZfE(!IjE};RPlLW3qt+% z2+_-ID`ybcn1O>?0>ZW3265-A!lds&XyUVxl^1gna8AdR_#iYdZz15PkL>1ACsskp zMub<`=(}1Fj`${D{fDHQA}Tpa3OqCsr7y)N&HXXED4$1efOVsUkIHlU<_v{q@ng6rTJ}(bGhkWJ3&rj8jg1gbP*+6HG50r;do|4nq(C`b# zTu%MqKK6?9h~P=boN+(p3;_mbBxPF9O*m0IIGUMqN{R>X7?c~z3JvnEKsqDIoF6us3YA!7r zKKr5k$_O{Z!Tga>YA;)4nX2cW?oxujU218OI>L?1E3!N5pOz~JBcfTLA!YFtTf8AZXu<3$pLspqM&v%Oc1xdRt^ES&5 zb-rMm_T0&Ewp1(#=}ETq^lXwUrS|MB;+pnc(Us>YP20&*V7}hfGA~YCtn)snzo$#& zn$nGKX?CZoJBtkO`B>#VytU5k1zi=@`VilwNB3@tds-GU$on$oY}t3 z`tRixJG0M#1Dc_zh>c_ z%kUd6irwFYU^XKT;3wFj&xCFC0Vyd>R= zsMB0WN>ii?wA@E=xusTVF}69!+$9|IN>l0|+jIMP_xSE*SRL;|12#|+b@y%*9IC2% z{G(`i^zd!#^=}-WoGbB4dtlX7U0Pt*Wrr(rD;Vl74x%l$!WG#eEZ4>h?DDuR3wI$n zrRf5jK~u{j-5AeqrH*N@Rco)6#_k@p>xl5~>nf7W8R{y=tP26|iz{M^v zb9s@TOv*0K57Mu@KPx?HFExwMw|n$n;f0iDtkv~BI|oWVHSIr{%9%*o)!SZ5w*O&k zs_1Fa7~*xx0ej5qc8Io!o7b7W>rONobZO?Q^ra4-+t$o=Q|^{g!|6T4LG^8^BChwp z$BlnGb^l8n;nj#`*f%iF4K1BZt_JwnrF5ROuTP`a3GY~CdD39ceY_0NADc7E#Qbn zz3D$q|GEFT=lU&d^WyuDh%k=DCfSOItjD-7U9CQfavuX?s8<`HT!Kz;VPTm`T$}y~ z)EN4EU?YDq!u&(_vWbSba~reWe6TUwNK1jl5;tbG=tkb_a`TF)M{kH183p6Sq{pLT z3>M!NT47_RW)eMl=ouO&1}d(@PU@mlI6+-=wrJF`pR;uX9W8OkI;v=X1FNt?D)%}U z-^Okny8noEy~fuSv2K*3C*JKahkEuDpR-N!Y&6{aBoeo1!~O#-p`zi2v#-z*9b)Of zFa1iqCT?j>AA~a)_-dMEOzyJuq!G2^`7-5>yBEy1|-GK?^*3YvtF*H zbF=mBZ}w7BZI9Umg$RsEKRTVt{=-nhaw^phag_N_2Kj z*9jl-ya0U2-MrcQ{1!N!33~t4x{%rojDqkrWJbZG)Hhdi@!#k7@y@W1Coz_08b1;k z3sF9#VFkKkJqwJb(C?wspr+3N$Bzr;bB+w!ny)oh)DJ!@-|(agnGwrB}m zv#AhCLaX$xGfJyGy@a&QEhVJN8=bRjm>TB!kOrl8v21w%rrnNJ10x(b>*OwQ?uW~t zgH{!l25Kjn3JjF!-RP;9nlqh$iCYiAORnX@DuZ7GuA=0v$AzVAJuDN6TMxo&roXH* z+cXXoqg#&=uv?j{GJ@oN*?Lq12&@9K2CxelOKSVlpX@x~uuAAPk%iAOx~0JM!MiO-?_!eF_ox_|7z!3v#LZjDh?&4>kos)_<$fQH_S$ zz)%=Llev(O?%pqs2H?>XO3UvEMm=a+;cik|A+RDtdBDJbIqNarOIKeVMU`GB;swIN z8}y-+_DOIwuv?W1k_|LN?Cf@s^t8ut{Gvt|4rr1P#rSS!Rf*{&d-OD$$D>lecsS)H z7QR-yvC}iNtED3c171(6Y!8(q_8!%4?L_Z4yBMf)O_GXa_09cq6pe4af|H*#eLK;f zN7b^UP^OcWK&#TYzmcd$$2GiIPdyzGE`Fb#-i@<2?zZBJ-W$9q7t%4!4L|)3gGKE} zz3kbGO1bV|y@dn?E%l;95rkx$FGP+8KcX*ik+d(naJ}z;Z(1$GiSH8=P4HhL=lfpp z-M<8KW2yIgXA)Z7WNcN1P8=s+j8h%6dfv|=XQvb`d0%$R{=Co=l78dv#p~92Z}!}p zC2|ag_Q{peH}5KaG4kc0T#y^QPr|>wPv(_P|G8~L z;EBi)CA9mE${H^he|JX3w3$K8ydx&Nb)`{z<4s8`();A_$SU_*nZ0A(xPKsHqHoAi zU|#b^Z|!3juw_A51X0VvkR12N@h99?!W!WJ3o)vz5WQ@2M{}WCe_)In%_~Icrfx|r zmQv+ZY~!W=T~MeA&$_GzjjQV0dE?0kYwn!t(Y<${?c%uG^;=q{%Wj2$`MkoAa`0xd z=y>FJ(O5MZ5MzUb9>=`BX!4sX<9v!PbToI+jwTdt#gEY&;7yK@`>%FS*`?{ECbkUt z9du;8V3^laxhtPZH?r27TxFS!*&3H+=K%)DvW1yw+$?wMQ5& zR%=4)MeP4oYcBp$Yl8W}qwvs)Y!5Nx)el*j8hnQ`8kCZpZB%aQbm7!)(Xk%l*Y2Du3e*T4N zQZ!cI)GtlE*2FWK&agcRz37zERR}4cOg;1roG#7k2!#z}qtM$#i&j=GK zP4x+W1;QEpUpCE(QU#QKC%f*f8{z}kohUR5;{GIIGO__&cg~F}6~6|lv66)MMePMFQE7_HZZq{6HQycw;TyIwVq2B1D^+pe9aMXWUZ(c&5Ytg== zR)<(`)}tisOWF2sr|gQhpR_ON@rD-))MHl~-gtaZ1LFiB)9o+Yvl#`K=NUG%Ui@2`)R{Z7Mx~^@s!z)I0Ny8nP)gi z?Ka}34x*}#Fw__;8SHXY?*3z)0^VpqGQfc7k`3zi^xTumGiyL zqV-0HB^;=51_|B;!m9-jZkZ{Z&pfMe4`^J5;)W?$y{2qj1sgC3*@!1b6|d63899F& zILH~Z(LNp&BjBl(n@d!2;Fh8}@-&}ekQ)yyI0^j@2Hf)8*3PC422f?x`-!icbkeM) zsie8Hq^!twbv|j{NkQ}$*yQ)6n^yZKhmIV$s@H9dLkxONlaryh5lnTfWf6hirn@M^ zs}KBi*>!@be5iDn{8pjZIcL1EyOHEXbl1*xH??UW$Tg?y57^NmzEu>*kQ439V_?_x z8W26lZEPDY-b>u|Fi9@sdu4nYT_k&A(pOHLf9Oe%dZ4ahWj&E6W(*9<6NzA3d9Dy2?@{e9YM4-X zcikGz0~Zj{4Uu2xT;tj*?JrL2olVao~cZk8ib$*mLMDIC}c*Rd(J>(oh)l^E4Lcj?#*IG&v!MI zg40(oJKflq9x<5*D<7~!&3PbjEyBRovDCg95raHXr z!Mmk)JXCPh_&16q*b$wqxsK<4+dFavqWlAjvWO@G63bs!pioh?lKG@?X>aentZyBmz^oBi$>wO&_Dl_t;>9>D_k0b%8H!|QbFa7;hgP6prmJ+D z%n)A`N^Nsl@alE1B3$lmBU0q*5A%vhjvVBBu)_eZANORA@##rvC$D{!pogR)R4!aX zkM{T#iDkU`TJgQ?en8pRxtHseF;t*NRMT1~UnU)Sh4gY=+qpHnAs$;}uPP=XGppR3 z1eD-bKSS^5H>107+9sXET+X0ibul*FI{o&}K~+V#wSLJ%1HO$rN}j~a(O}IIWw4X7 zD2JuU`*XwnK!@yx-L6icG^2Mm$jweW#!2FA?=wY)$4J*g)5>HC*!^3 z=?X>8X~M$#Bg%&8texw5>VsdBk;C!_>w_7?-TI3%|A|JPhDe4ACH?7Q79R3FScC|bb$xN`qMY`FdZ&zRIX=@hS zPeob4V=2AP2*`J%)CpU1)j6(?BpEKm&T3`^pE=j})SntAzg|Q5ft=0hkmK5rvu3+BVL!^rRR#8c3UHuo ziJV;W+qDPeMPfYEG?V@n^S&Ez_KqETw!I*yZNyL6@yH8zF_05TpBXxez5Vv%p~E*L zZMJsoxK23|^POYPclqt7^qka>0aTg%5n`yXlM1=-`IVC!4j=NyTJ-H|#G@?_89OyE z?IPF!K$hfWJ(j|~%TGm!o}^W0m}Ti$;3SmI%|8;Y#EyaE%P6;@g;lb0kJ7Tl zghU0pNwR!*20I zi0)X_@ujL?sTRc%FC!em=X#*VhCy--`cwa0MC_m0!fOAv25o*0Tw5`4ZDNu*NrVsW z3$-Nh@3wW^e(7ibj509)Rf7)P;$5GJZ1X zUhsrM-$an*2y31oA);|71ojRC>o8+%CeAj z{^cly9w?TX7hF-^oCwajHyAy$+gpmT=Q@np#6N2pC!zj6(aNZvgusn&C#DklM9t*3 zveii#bxhOF0F6#59X0;Jo0vBj_OBwO3v_2zOyWuX^Eabqf!nhUuLiht!Y(Hd~h(~_sm~)46zj4XX_)7pAEP4Lr zLP+A%DIj{e*#U5gFfkGYZ6nczkjVH(%ra}ne$zJQ=0Mw1RWqjy5RrsS#Qk>$s1MKx z`4aI6=pb;3K$QU#n%jlLKPJSBt@!9i*1|Sq%+#$DsWM@vQeHm*TG*JUpoQ&->gR`U z`F!3@db+sW+vZ6xP@mJc>Lz|zw)c6HO$_+f5>N)TB?ZScme7x`HEipw6Bvrb)_Cb# zuyq`k#$eY(N-mqE25loGPD?c4q$0)YaD~<&Ypfa5()UysNT`rl53RGR#YU76hg?u(d5@$ zC^_rtU{cS^wjZ2$Tz2`U<>hWKblR#xb<_JfsA0on3LBoomxbO&*SsDlCkS_XOqDes zH7{x&p58SI)|Hvi_Dl*ix175AcGPiHGg9})N$smMpqnOny?Z7-IC}T-b^eEIq8Fx@ z+#_efQs{})`mKY+i4h4#t+6R`7Hn;tiCLCvybMh0ZBeFNIxLX!nOpZN%7vIyF2YJ1 zvN~5vJY=n2m>Kj9E3=D3O$2(#+J9NE-wE z9IeKw=Dh`Nq)Jo1fm@+PZ0GB;yi#l(19)@~qJDE;NIxucxWM=)O#*bVS?%vyW75!W zhcXvs?dGDPH+bW&n1FsNLcL5cQWw=QU3?*94BL^1Pac?S05p3RC5nAmeo!3E8X6*Pk2~C7n=*ZSOU?_!&m+( z$?bHDAKjr#8zLXQp8V#>`^gpM{|<@6Yj>%2Z2ye4mq}(Dyi(?$)P8Pxww!sFW9po= zV-c<6J!Z&YFjzpKXQg zywwDm=9i(lcbBCWZMH~y5-58NYY;6RJSjocI=XE%ycB4Woj9K4!htG~DC6rTxty%` zfli?3lWZc5_EptW?rc<4m@8wyEE`v zjmWj$c{S1z%flNkG~th%rjwlMz?6>SpWl+UXmv$u9bmd@^_HO394nM$0DY`9Q%&63 zdW5Qtp1`C%PDS1f22n$mLA`Q8x>g^;n=3iu&!-Dj2AUfBXnuW`8JNqpiR5H~Q*e_g z%)Jo)>hMT*!0O zw<&~I?=s`zb8pO&(q#3e%-cZd=oyY$qBbd-D@fb0$mDh?s7aBy6^T4|twh>8Z8`B> z;E-FV?Y$Pf$7Um)Z9WmA5bfO(r(A76S!Q@VHW@%ia&Z{Rmv$+qS`;%Ys1S|x`8R5- z#}eKstCj!fH!5ikGyhR%xQ{PhXFO%-0)Ct%)fw*Va5v3`yQ#_}>EG&%_mR1jdncuG z$rtY?`_fwt{;SU1%ibD=CvTHWr0KPYnrf&s6jVbS4Hv01YzylQ6$U}#A4(aW6ntpr zoh-~OKntXtgn%Nkh84$8&qy$tzn`l!{D7H=f7KbK%gw{+^W^XgX37>|rg*dc*)}sj z*a%(`7+-H7b^@j^v!pJAF@m#pdzMlEOamy`;0n>`C1I6aG4AKaiPjl*O?3=*Ug-#! zfx{ITHW0o4LGaR~>{lKD7P6bN!cYhk6Kra(0K=U=C7C+1!!ia%5u`EN&>3`)#& zw%*hD+gZHP9!BtOkdu`U7CEn63>AdVP`nE^fCtLTQHzKCy(u%z)@$>6 z9zjT;F6^UC+ctjZbrOz!;KgPas7@z!EaR>B?;wM6f zFV~DV7|xvnCqgLuzZoPxobZkoet0b^O(c$r!Z*!ePh*CJf&SMm)|HX^m6DZMaxUBV zM^YBm^Mh35urZVPq;d-}1Iatl043_=ws8AMVAM=x+<4(i?!%5QbJps%TcEn?sZp61 zcQ!{}Fg8z`HR5lhjl6TP%~Dn0`ZhNGph8gMp=h}#f5`OfNgf`ROr5@#xKYPS+-sXo zx3)H3q!ypJ?J;{`j+>oawmc4DaVzq9d}H*|F8jErzKE`g!+|C50*MTCjRhEbIr9Ti zPoICS+?>bA9nSLqjUoIRNz7kk$e9D)9aC5ef*pfVvppfF({0)=aLXmzD?Q%+cU42m z(OVa)o$U!M@Apxd&ou8V8#O*tKd}1_ukxKHhk|?vcw@YzTmJ0BOewsDNp~glC~AxjA4@MM$2cy7&&5 zfVrmiunS}v@FO-ieBkB~z3LIGc$^v&>gHg;s*)w};P{t{Z+ZHho4$~l7W8)|3~AMY z33zngA0}7hL}Zb=!Sp zCf-T|N5?>Fb8COTQk|nbsM`cOR~hvS)MquA<47IOdZT2!=yi4ejgF4^=>Ze%YT42K zD5ooMtIb%p4x)X7kmhQ~E}P|E9goWL!|yDyCte&eUuF<>exbSk#?5P*JWtX8Z^URH z8+-ZJh}miebU-J$u*Sg>$QW_@r6+C^1A;}&BaO@5-tye#-JkbXJ}33WtmwpkE~Jtp zq~+~SI+CANE*OGW#Bygm|M0HJrNKA}v)#B)_2=DzcAHw$VCFrM*2V7*ki1rvtr?}I zQCzqh?9{;(v3d;U=ETitXHn&E)MtjC*pdb1=D<9qe;|v~*M@kr^2^YTpbzAIFh0b_ zL|H|l%db!FiO+6|O-KIWCf*$ySiNJu=TXee-yOuOIpFS)B(UsWO^tjRHnNh~6DzgQ zqpYr&>&1Cs?qRLc+zEGw<|zV$qFhsfyEgci0jtXb^tgAMx1|iUcaCl>TL~k3Zc7c^ zO3gdVEykLT)plk#VFH>+Op8X=u}bUQM*{Xv_t~koxmb_IVQ6hq7$9S0AK{Gqy>ZaS zJ!bbQg3KfTQl|UPR9=)iOTJlA-s?vK)D~8osc(oH-~5ZUJ#>;>ZIC};N9oWH^u^Lz z?VRz~*l~^7o`~ks=F6@Wp8$f_nFhF7l~w#QiytGuSa1UU_{CwBFeP~wx4I4V!7jz& zBksaQUG*P5!)3Ovz1lSVMfqE*jadiGQ>Q)||D2~bpJtje%PlsL`H!nPY>)Z1a%;u; z=&DU>SCf0=cq&!q+K7#MSs=%;WWmRa+v8AIZyZ{3$XmY%wgA}rjRf;$=)=zVVFJ0& z5sD3d1%1v$;TgCuxm4_`T&J(Lq2f9{Y3m1j7Na{k%RqcR-ps@{Fb2N7sF_29Lwk5A zh_CZcf}hOwZ35HEsDf6-G|6x$aFItjbfGPl&}pA4lGM4gGcm)clLTAe%1Czf?OA%z-ity2nwc2$Z8U&b9EgRLZd`vMxju zj0g9Xqk9}HWkHP#?m3S=G}Ob?|MF@M*+v{8KW zc(o_6Nk_hK_{s3fBM5)<@Y^A{>OUA>Xx3WgfK-eIY>b5&G~)(T8EVN_a~W2Vmu&hd zo0PzTkB6&yUC65#mwUwRpXVHQ9;#CiH^#}UA0>#N64qPW`w3P!0YyUf6DLYgnpfwp zMy8Uvjq%o*t_`9tURC-3kT6X&Q!mQfM)Ta^5vOHjTUrcY?7p`_f&4Q2nS3Z zJiJt>N7ePHiTpQEcLYYcJrfHLqMR@zvr+<+JT-P}vMk*so_O!{ku;*2b;vQi8WPCW zGoBOd5?5Rv;!M1E_Q|=*u++&prg}hTUz%5~X)%UJL$ZCTOr6DX^KJ^+#5ez5?Ld|t zE<>1>1&LbRag#xg=4vdCo0KN^yqlvI5d@{D2pr6*NVJP*ALS$el|=IU#i|j~i@o2t zE2l#8H7Dhn?1!+88D@C%dY6G~n>)Jyi*>*8c=WS<+MCyb5oqz*LK}Se?u+rS4(Hw1 zrZv2sJcRmHQNRl}%o|c^p7rAO=XKy~w6^^1@F5khb?FnYmfw6*lyY%4Yd-mUrXZj4 z`>U^_22#s&_!lP5{^Fa+swt|?CJXK$0;*U%i#Ul(%29i4WfH{Z720#(XQ}l;wGQ4} zM0I#1G5iKAL)PX>8AS`~v)VvxUl4_^u>LiuIrRy(XH{ZFtNqs*N`n`8gWiFP4OO1L zYOV-_O(B1B5`KIV=!1+xo;8$a57tMauxEx$VR3fJ*@ht- zh%ILPUZ=P@mL7e*P~Oh)J9vsLswl#e=y&IrMW|vZQ9MG+gs-OazegEw{ep!k+(zNv@v|TK8ERj zd`L1E+WD|Bo0O+{^xY`B;A!`%gbsA^mUG#~%zoa8F0+x}Qnx*nF2#%B=;;SU<^0c= zj78><3JFIkvwwKWjET)=KW4Ic8tD`{5wojKbu1YOYcdFBop3u$p< zh~Z*`S4ID>1NJ{i%pI89zoB#cBynyxf)o6ZF>sXuQ2r_ov3%C%-t2bZ2BGky;pg05 z&|&|h(sJeUtn~k$+s_GUhzw8(GE^52NHA$LkC5l~nq#yv%-Rd)_BW)tJv2j)mOg~< z;U4-hL;!VQ(3_A+1HU5gthGW_$e4pu>gFQn+`_n$Y>QrltttF?=Ht9h6tf(^_ zvsPp>ADC!i5}2AamLB*F&hxWWoe8ck%pX>H7BNFY=pdz<8C#&B2Js~W2fcNK4mQA1 z%g)5iw;jz{dikx{ctaEOY0u9}ClljX6hzH;Uy!rLp>unp(W6yX5k@s!Ht|J~+%}(# z*wk}BQG=5!dE3K5oZCI@Q;P2TJZT;H+qoSunx#D>4r?v+2Ptx9e47>vvBG2tF(P`g0 z<>tWnwWr_mVXOFVLdmhBXH_qM=>c{2y@B%=(3_x8J~?A?M}{?aQ7sl}_v0C(F7kQ` z3+%6KUPyWb_h_xSMrDR74ceHmT5aMQ;0A1j(gz(jZV`FI!-#HtLNjz}>HWDM>~1`O z2<)NI=hKTHiROEFO?w|nF8|0ZDpB;|M5cn%sgGwnts7zkP)|Lylh!5jPuo*anZ$MZ zyNSVf!5b}#nAXP*j~6<;dlvpU*m5F!TB}9IXdJFuZn&R0Y(ON;%zfM56b=D9jC;>) z?!ZZ`FKarM-I+r`0#I2Ek+)n}vmQ5Xmn>e_<`c+ngBuN|t45ITE`98{WGARar)N}X z-R5f17||D)ZRx(ilp5)XxBNonw7x@>(|*2Uti@l*$ie&xIksy5_dc4d%$AItXgc&g z+J5aD+_V&byNCWi+Ri(k>i7Tu*TJ#(-jNZ$M3&xw{EGUr{{HD&*$TDfBf=(kEp3cq+)l4-I~UR zV&L=N1P+WA<<_`gxmCK59;m=l$e(F>^?l-#XQcT>-kP0E^AD_7e3Tj$QFW9R=hw?q zaw}-nC>Ifu^;Cn+_d6>#r3&sRXw_*~H||4_eYGouNLA?9%0bj$-z(<^AS{@L6Cd3) zzGf#2Zq2GNgGXXj^qcB0soQgL_tS!_<+Nt?B4?h?ecMlr_mw%QAVq^*XAr>RzD3d5 zJ?({hFxrCAnhRErBXW-p6MeNS-&&|f`X&FeQnq+$v5J0Nk)C!RC4V=)?v&BQ_6=`M z%*;c#zHH-r%mdN>*0uu=iBy$^UQPrb8r-QD0I^q=?^g)>UDFO9xZ;y>4C{f6ecVI; z`X0?2^@qA?odohXf1FzM#XsMpZU5ySo%>+cc-m1Kg2wiSBK4o{bKR0 zjyo*;pC8$UFw@k#qov?;y#M)S+3PUUt@FqUc#jVIp<1qb?)LNB-Ap#tuV>16jr+_+ zSZ&VFeQXA-9{0WSQs7qXYw~a-u!PfQBc-k%r&fM1#g{T4evrZwYDo2;_UK5qtk&l= zny6GoirV?sZ+rA;H9g|5 zfxR1h^wbzwMoDilEirNBBD!SBNneDsvE0cw=j!@o+G3G=G|9)WyIMot;XR0kuU4_c zXu5v$9vzEBh!Vr6e9jSg8R~o)4DUq7c@#Q^aR_BEu3k~E2g#OwC>~lcWh_zvrGwNx zCH=emm>i9J!xrC??#p(WRBqqA{q#xe_BF??H8ShEIX3PzxxrCu2bLlI$|vvefe(52 zQ1wYfwk|`=!$lrLviu}mIJy~*ElGb%5GI6`bX4Z|4%9Rb!ZyUBgO|CB6k z-lKh!HmV4&g`wJ`54KYx{1`xhF977K zQ2>ETh4TT}3;>D!AmAXz13OlLGB*W8FW}UM2n%*I!#frdt9@}RK;hj1!gr!20zi_= zxX(_G#>fO{(F0Q~U_=}Hh-m>7&JGZtD?+Q0oErr^q(+5n3V;9`1;_&JAW6%}cvO@E zfD&8Rrtjf;@g9c_^GO$nq0gxt(u3^atuz>&4 zj-k(jWH^wx4G`dx0QuI7KseM6CWYe&O76(C$|%ay3Wt7j09%x ze;>Juxu`LBO5eFOAp#thltGnNLE%Usy{eq9pS_wuu;eW!)j@L~Rl5gFHMw~=X**d0 z>qJBJ^SM=DpQe7XsB)2xdP|*oFkLdg<|R$ZS6qaN9`@%3cdP5~y;x00f3Qv~OoN`5 zut^@p^F;f+q|J5>^ES4ZY7B}7K`EI>sSO%cG;wYpQzGdjWkcnLgkBy^c|;3jwB>q) z<}v~0SY$N!Cr#D~F22fxk&@){+JJNvP$Wmbx8c=fcH}gV^Gni2CU#RcFw zgOuiR9I6CIa2ybx)1<2BD#U?)gJ(j(1q-&vou~kWbehM=no^2*Ko1^R2+fKD^ufq3 zqiW3~Gp|#Ex+8C6fws^L94dH5wp`n*Nvh7Jf&*s^o{)k=&9o`^k^nWi{3QT-Q|=Kn z8w?tug+@zK3b5d0!V67XJHW{3^R^;X{v80}DOviU?DAesb#3#Md`VD3CalSi1C)$D z4*_${b)jkX!;C(O8QStqfPzV%(I@aOxqOweBbSwkYGiJol%~lj!M*IVn!M~H1EFcd zWTWoO`-D$@N!3+L!8fQG)bMI1=`N;p98NNLr3I)2xE>a7jl2Me8UcY&N=t^S!LS{O z!voVekD~_T$@2c{Tpw`6-B|3p6Zh|lTw8D?UL|161F%P6k&bU80VvQolvXMbh`|#< z0VfU%s2lB21%p766@DWNz*Sv9M~XwitLSz%fFMdBT8oMphq5aGJhXrimCwQ>$NkK$ z7@&BffDlu_qo;U)cf8e2O#-9<@KXS^q!yyp@b?56;B@W^2P?wi3dW;w^{4RcRDf{( z$z+)yQaef&1)*QLra_2|R145w!V-AM!GtD2t}cT~DliAkVOW9}K1#{(-$8sx5+Q>j zAHt&qxXS_R5G-nR9w>6-NNQmg_8Gtvg!7859;WFt)$WJR$#r& z1dpz_nLs-nG24Y;-U}*GfK9`YI_TP@A2@oQ2bJ!GBfgirep0w{U{Phqam1gh0H-D` z@Z`jyTD{hBhOp(K+=f`F>fMurPk!|pX3^{O8BTB=_I=J0F>&&FLf-7@5tg>4fRTjR zG1*ZTZnOs>Pl1r|#W8BSV0$?mt_x$VhXq2${33daE)3g zdi=>ggZS}J$4wF(ubpwcI(hBF0XW&I&OCZ;`HsIe^C$ehYm-j}Bd)*xEFPWq=D_jT zj5pUW+{~Q1ek(8Q7<>MMoaqB^OYctmrJu1Je#RYxWR1aK7hfd)l!Lmm)P>{L>?OP0 z=OmS*gaK=h<~eE5)$@rGRJG3s#Fy(+c~CuWi61_-xIM+9s@Eyo}ow(@*wp@%?N3fXVc;Bw&2FMjQTY ze64EVv)79YZZZ9<)5k3r{QKP6b_i6dSuOyeYWcnsV4uCw2TIT02PL?r-50Cc^$fN* z*=Mggz1-40ZdS2f`Lq+DBHS)8Rk8Gc-lnGGFDCZh4-k}%kmvXd=Pil`nSR`7`C2+j zY>^resE!C_d~yqtsX7z7eMBjw((TsE?&9j^5rs4aO`s#|!%c0h2=Ez9gg7W3!3fI11t z^8gOI7li+T|8;y|9u( zz&w+M522V(%StzWSdtgUyV)J>72kjcpSaLd`<qeaS#gF@$>B2R(-2bD&elhKr&qW)Kf`MJCLl=5sXuYo*?aOz{w3RX?OYWtUgAV7 zL0+zKwOK>S0K6X@6m@zei$x!`px|=oFBs(n1bYCX`*Ab*sr!>n;QG>(i|EAl2a`Eh zJYNR6<0#0aXRt3h?Fj0{WOAg_ap1m)^)azai9odMsilaEcgc!8Akm+?wnN-e*C|>G z4`#U@ruVh(4Uy9Hn*+=ZcDlS{3RrY;!u>C{05z$ACn_)5K7Z=6KFR|NK5!2RPF(hQ z3rO%E%UHDhFGrz#^imByjs>j{F4OtWp$g*(#+%Y(1xGx=H4+bd|(x_M(O!!9h@gtdjeyCBtI-u}*d$h2f@)Mv}(1Fywa zQi1pxtmU%!%e<8cchl91;+8X`I(?6hi#3m2HA1;P6FFQwDOzj!A^(urr|9jbt1X2T zXS(Djs$TXtk650tcgqXT9e)tmV>xZwAhyC>$eBD+@Q}@|)K|2)|5Tgh!oflq^1Kt<;MeDA3GLLgxwu7TJb2SYRbOyId_=ju8;l!sxsdTudeJXcbRof zo_eTTIPi4Z(s|7cO094Ai2G_By-9InU5&3V(}9Iy9c5E_<}J9*-yV!qpnS$9rL z?3G761f6#ueAf*5AM2ewoA6jO(2(apDO|Z=T95;QLKb0#07=b!_&0?svc<=NsVHhS z1KquJ_0h)bTYOF%VPej8wc^DjgdTQBi*70izW?!3Tbc}YqXn9_AGDLD!h=z{z1_Jt zL>?Q~UGcpMpED#?&E}7!s*E;tXMHl+f&RmiS-7OFq`PBtig%ay)Xge%#15?~>Qj@! zql;>{VP4quivw})>R0YhMdEZKtN z#wJ##_28OSsxBZZXEmn_2xfx|{EMkHw0V~gSwQ!N1|eVV-fcd!iPM zoI1`T645^EQ(-M(c6xa7)7eLMZY2uD4CvrG`*-FphqrNrH9B~*DV#AAxY7)_v5Aw1 z6eHmlpBkd93*i=H5u$0&?*7hD|L%SNX^J#9u%V8AwNRQEnZc6tc*a&NS;y8Jb(G}E z%@6y(=ej$3ULBe9Jt7H(A8(dd&YXGlsBvKt=DM#EeZ@vmBGH(-bZGp%(0mGYrwbFA zN>m~;MM{;SsC93Z1B9WHveb1^tBMSD_mC93sCD6x&=(-sOzD!ONzUoT(Wp%eU(aNm zr@6JFhaz~J-i^5=!{IgbebMWt0^!S{{fSg_E}PDsR`O_Dspe*VL~jP8?Bo}Y<;j-s zfaLx5*hGk3p~fR)BV_%m3D;*3af*dEsJc1%4(T7$N4UjD(u1CtVP4+WHS$5LRqLsw zwiD=P>o%BeW;KLYi<)3`UN8;NnfNdd__XS2Rx>Z)yFr#C{rldPQSJ$RCm{W%04OES{mbO>?u}XF7DrKT zDq`a%t?nZ(0d)@VrMeQ`Je~U!2Hq@x`f_IEZsR`_r?Lp|N6D)| zE5g)L)L4w&mGJ|et zXmLjHKK2y7w(W6~ft|VH^wF;(mD@KGrz$0~JIs}(nzQX7SUWPcce?F(?gkA?w%sfI zH4g&Ku!yg>K*rYZpm}uRg_%MaLlKjFS8OGVra|Gl(>+*hZ}(y*vf4*RlGG6*y2kMw z96M?kF!567=d7wX)X^>PD-M|mtFM|dn#B(XFb*=!0QoG!n`iA2<%iu9_aRk4Xu3YJ z*2{6K@;HiO!PEWq#G2p^L@|r~UN;b)drt4CUQ?`-3I~s1L-|3IxqC|gz#kMtQ29}K zz(r)mQGVEM3zY_9HhpuVYeq7GzHd4l zvvyB`uS{}hwf~dP9qOZD!m4}NM|t5riCko=a7PC7gX$C!i@OR5p|idWU7Z2+m?Ac1 z<_6l6$edc}OCpamrFW8MDCcRe#%6j%EJPHsHO-=yS(6n&-i9Eh38cM_>#hYuhvh9OK?S{@H|u?%BPjWGCIZv z4HvGlPFVdorf-Rv$etAjxT!ra(>sO0SFwgVq|9BTd}0pc8V@@^9Qr{ZkAeq2q@1w2f1%M2#qCHS9gJjxV_V^-mg6{0Zr zK%>Qj`{ucd2Y5PdM4fyOh&{jY>zo=%h>u575zW1z-Uu27r;kl^k7RVc^7H3b6l>yj zUj$;wE4JSiX9Lf4(?2^aUzMg${O4H(`GqQo;;berNQ{u$+5IJXje7-5y6d8Z37T{; zp|>WfJCU-UPQjW%gU;m;3ry%0wGrO5fL%m9%0YLuV#tHY37}qxx2YSlp_=Xo+DS)1 zy^v4~z4rsiX?e=;#feA3N`k2IHE{+hr4_yPjR!;ccs|EM=9b-U}9~#Fw5@v5VFrH=D-{nK4Xkg65rDxd3Bw(U$ zbOau8Io>CQjrx4_jy~_OCwiaRKI%W^)_#I2*dDUQgJsN|!#mh5qHo^hu=wD5hn8Bu zFT=@_Iil#;vlDg3K>bQvsmG9+Sh*M81CQcTxi|K=+cN~>ZY=V9FG}hJGVDK}Vb9{5 zfww%b%4RKL8S$&k|4=V()>66lnPI~cE6rMib5H_XZX>?@U${^cS`K@bRy26Yd{0eG zfh2`68P7a;d49?b*Jx1K0lO1%;JZV5kGkfi*Rx|9$2{eRZb8R#^J}kD3SSb;vcjO> zokRAfm*>Ul#Z_y!Eg>OZtX2Ug6rN|E{Meo?_bK{dT<8=3m;mx^=fOu&b0{WJZVzpt zF!XAyLd;h*B}~}t#Ba|aq|-HEse?b)>n>EXgiw!-7?5P4?Ud(uGYv(9?hx2rhw|5M ze&|B&4!?ef@}(S*j@TY|N4Ujvrbr?&1dc8^n+%_?<D8l9e~_ouge>ym9O#&(jn_k{y?-v-YeJ`C)JLUa(6c0_ zZe$#x&O3wXd#Z%1V5YQpGOc$;64H8)D-A>+KnVy(G{V{=Jf}wgPE(!JoTQ zL<8_FJ!t<|m84TOBvE3VZ$g`-#sja?ZY()%Z`T6wwvuM6+$3ZnwFlixDt@6yK^-hx zMU}72t@a-|&|Z^)@9ZHG2>O6zp^@j<(~1weGTIT?GxCX0ZGSi=B75BVq}3VQZ9lTB z`euAqtdHMXQn4C>&X0W^UM;U?KkqWr5AGNOB^0ymD@VQ)IF_ff6{n))GkBW#kz8Mx zzq#&7t$}H0B&t#2Kd~_hBFWu{X^^Z|8nqwXpQPqQN)5VPTaNnZ4Lu_*(x0{>YLJTv zfg|qD-Wcs5BvAZ@z~k=RERkksdKWEKcld zkIkLk-9dr6t$1!>W+)5I%ZgpnzpO{OfS5JZyNq2K5Pu;jPYL1q3TOv9{T_)Ok~~sg z2fbnn`vnAyx@GjXnZOOKiD^GmfTNjI8cZIjpeoWiU@9|lc(#+5=u2itlK-;a{+%0% z2iN2nKCmatH+J>qaX*E7Sl5QyQ;FxE$x@YiSel7F=4ikH2`?*O*C)P1%iaudZ`df!`d^qg3 zf5^Fbchcs1_QvqkU%kw3biDFrU(YD&c9wp669uEBp(>UNTHi>4IR}_)TVuUzlVTa<>qpo`=y5UPl>W)K} z{9DiSHFawT3p^%YzdSj_3qmScp0Lm!o+dz9D}5K!!hqD(h4ra9y_|BB+xyAoM@HeB zb(K@Ix+IH9f@n=r`=+A{6?fICAgxyb5;3E%ycftd zYDxEroQ#gmXm^UhHZ7CIczcU}le|Ng{qePmrbwdW-QL3-wbthGZ4qkvys4`M`$JO~ zC3-$Yq&Ypkk~_KlBs*y;^QP29CD#z$Y`xo%hrilRs|3ATAFE>5CzK6#=$F3MzIks> z4=)$;Zo$!0^6@79uPQ9632eW1_~*`bvI4l59E$ww3QONzzbv2Ep9wj?WU0J}m*|n5 z#79m+8mhp$Ul^^wD@fpdDpoxW`V|kjZuk{_j=+~4Y+<5(%@0%5Z$Xjv?5dJri!FQw zp5Xj;pR#%jQ?NSJcxV!-nNGrI;Ns`!$}9O4S~|Iw+j0+zICpNGx;=? zQ`t#?BlJ>dW>ORXuYSc}lY^nll_<#$4E*A9g=e4&PgydBMs({Dt_HesAA|?ZYJ(Bv z#B8=N$Y{NzP45h6N%W~H+nNnq?};@}(KbkBkoA^}>3WVo-qG4*u(6?uzx-Z}pe%MF zXJvN>L+g@aN9>#1%31TAlUe8C=4C6MxjAo5EYo@o`Dl?rLErmjcp}c5%?OfE zoUc6y=aEXX|IlUo?zr84bjMRJ!OMEdy-q&z0f;lCmqlBx7A8Ix$?dNn1JjJCLVwARVBEC9O{%p?XgIa?QQ;03hNjM$(wYYZl|j34BXU?_!bzyk%*5tU%0N~9T$pt4{xgg7Cni-r?bZIw z2m=?WO!RPY;(%QGV~B@QkOIS#8^GImU(|5lCG{D>Hnc&r+;8BA@K}I7U5BVEsgFiuME2&&;SEK!v|RJs+a*_p(k9 z8}@q6;+(P#&%cLxOaB6*P=Md-f5U%k|SIPIFpzcE2Sm z`-o-P8c_RVe&Ci9vTAYwM{t8Evou>=JDg+w>!VJJ6%?M9AN?oR83C2{#V#a-_-B7L ze)N7adEGr10~R&tR%5GwmrIQ_sCCfmPwzjNY4`K{Pm&UVIw`2rP7!d9ld?V6R}oFlt(G4{_{IvBLG=Pp6T_N@FO6-uStn~6eIzgLe=9p)V{X&S`+ zm^GkZpdi6E)G#z{x#`Wpx_Aw59=H9)~ouzM2JML?`)y6K!d(Pp`}taRRztI&L1GzwJwKORvWFdtdUe z0+LsMIq$6Vf$Pr9C_5;*MI38b5MVO$Z#Syk2X9UE1NO}tlAKrBB)^W#%TY43kcCu_ zx&KNY`oo*A2O)GS{p5B;$V0!)pGM$yTmurRk>&%>#M-c?=?{Ku`3(dg6)Mh)e}SI5 z@s5%odlJ`p-+-RSMj0x?^KPA}ri?_1A)+sjqC`muf22PC^yZ7g18L!x(mQBsx`>d` zljt6Xx@a|B@~qKRJ;nyed1cZ-6qD8Hv0EFgPGQe)`5$dFIWYbVRoot zJcM5ndDu665OsyKZndL3YN5CK5F~-59j%E!y3P3jGn_wJG7ouiH6{`K<(>qQm|%H- zuO06)Ad&D(?=i^+$BJG@&3~&MGFHWZt(| z|E%rhkyju8(0kYcWwT!keC1h*K=RNxeScu6-!`h+E||5lq3@@8 zR~4v1r|dzC6Jj@x;JaX)HD2oa-%giM_)(y+<@aiFF98xP=|A7B_0oZJ(b4F0A6M5q zjS2IbDaG&J*dK4Va=i@Ww`ROo3-tfTGXdCXzHzF4-N+8W2U`90QZqY;d*=RI53l&b z2cI98Xj-p<*NpLT=C`kWzg5eL?2(xd;*v)Nl%LFH6lcwL_zpZ<{&+^|j~iK~TFkBO zDzsL}q|!l*tY)1#r0pk|5eUIUbhXiNQVEBY#w!V-CpR`EX$_%_E=i4axt`Zj;f92x z(GX6T8a*)=#KP=AnRt_-^d;D7{BI$Or%Y#U7;Lzhf6%|;{U!@owDtbY1ua{dmPq^s z&I^&L<8Rs{gT6V_7H0lYEnUXP2zEvA@xtkn^BXw$c7W&@gI-65{XMNS&)M~I68l-& zw)uCg^YG02$?Gb%^=8Kv)7{8ESuBTpj{(7QvtEMkNV26~2z4`&Kth|5`U?BPDxNmv*PA{r|e*2&zDD znmI>X!;{u-hZpnmkRi>IlUzw9KB{x~gpOc|?Cf*p@7q`ble5p?_9Vr9lzoc;mvgopye@h4!-$y&kJN8>@0+KYU5}@Z9_Oqx}$OO7GM_)PY)KS37kp~ znREE&L<>_ZJd$rjpFVpDf`O+ys0$b0bbQ~CbTSH{k%S(mJ+Q4H0Q(4@X~>Hnow#v~ zFjC*pJ3w)-(JcQI=Wef<)Ka|#*A0%MS&o;0ZWhP8lMgd)Ncmf`4nXdZ?SO|?Lq@pF z()mLc%;?xdb)kNIj!&6Q5HCphVW3gKfBbK^u_!pSmgD-p*Erk(cJY6c!pVibmI*94H7!LX$t1xK#Ezt8P<1CfAKPDLs2xVfM+@O_fq`Jpv``r%Aj zJ|wqxL>8_ncJ#tqamS(<8v5|plMmFn)Vmg4dH0s7!GR+e9Q_n9!3a~WUdFUNd!?yc ziskd&TqeHtnxSsr*3mWnj8+^`ElX8;&8=e^%v2{Kxm6(KAbvg*d>rg|jfT`ApAbTpA0^T(VGuA* zT?I8Fh(F}(NqAEERw@Myp7bKNI&C8FSp4mzN@$xX{_s|MP(Yq)_T%X+^JH;9bOZ#KWs52^=RkQdTwH`y7g%8?Ig-jV~)b6S6XRMqUOSH#pI}@d8 zgd+M6{-|U7S>S@IehVdoD`-)c9M~I4W53>HIVjM!`ATVq0dZ{+I_azn0o;b(d znlf+e#!A}8R-YO5G3mjM6FSr6)`|_#$j})jDrHhmzn|!=?lbGbY}SuHYll}|~q0UcBP;ioWf<%mU>JBn2~+xf3=I5_xb;P}1kSmnb!E2FVBE&0-V^C{S2jP^W#HR=c&N^{mppNpMMW?< z>1cgXu7zbkQ@yKI_1OC)akCRtKK27wn8GLmp=8K$@CxKb*Gu70Y*?w}zpfT21(Ia@ zy;@)xxJdjjXB1Z?aJYXoj`h^qnT=|Rs`}Sz@f~um`JC22vzd7Me|SdqA@^Z88gv-T zlv8Ub{(7?t*|x5>jY^%EF>xMX3HYU2hE^0q{ps%zFZ-X_qI`B>tUFU$X=H!GKNUl8 zN5=RyEE`u!TodIlMzV)CcZ1tXK|qe%LbJzX{q-bm#HhaioL?rZ+sE&(CkHn!P2mH` z>uDxheL6W^yqA{7OAFGz~>->MJmJ)I8Li~(;d))ZczDTGt zYhTEH2fd0j3!7d=glcBMD8{g-ObuRuk=IiJ^3+BqeN1{?akDIH@;#?!O3P!d;p++M zGC5v!TMRIst7bIUG3RbGn=vI?S`GO0`F*Xi1I6D|W@^fGIN%d|WUxOt-l?7rc|y@$ z|J(QWA1g*T9bn=Q|9lgsy9f^5gZ-s8pb80%XF}*g`kCd^`Uif{g?{QUZY5U7P0M;J zY<+W{yQ$1~+Chi?|KY5LlO7shVSvvE8=adl8r4HCK#9dHt$*s++_|uU6FI&t!^h8j zztucC^kv#0%Qt(3-Jd?=yPrPmI{CH4ugaHKkz50QCcn(w!K?SXFDN(ek9jZAM&t6$-Ads(HLu$~{Se-S zTNh{c$F}~bTg@>c2!lQcjULm&o6jgiCMp4gZW$4x+4h_s{JVWJuIn5;hk`bOHNza; zdx=L-IARA!+Xf`t)O;r=vsm`QHW)j2MF47A-zk`a11BQ#U?zs^1GWY{kq4os*58t; zP}n3O%JO@+QA-BGaldpMvLJ9!N+^yE=f8P2#eDg{ei|jBU>^$X5X&{oK@cG zs&ZuwPt!}Zf_JCda~<#**yud~mrS z>;Z|tS<$_xxdqmzd-S4b`5L=*!>_~TLaOjyL$w59n2C`LSOrOeeM3xYOpap9gOa81 zXVb&-_VJqKyW*+iuiKC3&dPT%z}M#=UQvoA;vAv(A&T!f(r8#<;wj{CJ`k@MkrF?? zIABmw#IzT78=Y!dqp4hb798=xBuA5XKCTA_n1bD`v63Y~)J$eL*lsX>B7(RMUV#t6 zu+wW$XBK*gO~)hi@Ap+3_O;*Z1s0J|+|Rw{DLjm;e19 zbR#?N;ZxV;bs|;y$mIS;qw`R5b{~p6kkA7BYqwJhNODtUC!1+d-ru5yB+v)c3rcPrhE3^HVh@o!^=_u{W-oBgw;tk zPNaTt0O-ytN=-ur)$~&4|Cw#Z4h3TB>D_RnzL|poE9uI>q2i}MC@?;cr4RB#!PyhY zpE?P39WT6n*TiY|=k?7Txtr3`x&7Tp*0B1rY(OL2P??8)Da(2^{N|%S%r;01%~ziH zouY*ssvoyvqOaG;FGauWDJB!K2lcGa>X+2yr&NBtumh<_6q+%B#XlvP1N?$A-FTLfTH`E`V&zKS!)NW+p{K z%W?daElc-!Rk(OZ^INmF%ee^KEOcm@YSJGrG8w{}-s$aIDMKKgSt@0Vd=Gw|-#`}U zcPGZhtq}JCALQ7Vr6RnDgv0BOUJsM2g;`HTFyP$%U~2xILTsD&=k~~zIcumY3o6nJ z4sgjvzpL}5W}Uhe=6HavFU9fciM&*x20#vs36#Kjz>0YC@ zR5u6y?JbBW>YuN3Cuy*6+t07_qNg*U!bbl!V~OGSd$SVEXjJ)=2B>(={<(6Au`~Wd zK>rip3L7_55%;P!W4s+U3Cm0ADGlFUa)~w~KczeU%*y+Vdiq8cdhaU;^=D9z0rBIz zWfk38MLkNbA_sg+M`l0zncJsRlAT*LzFV{6GY82G7Cm2;_4dD9UOjWxww$YM@^b;^ z6lo?;=a1L9E-PSdK6eSZH^WT1f;us%m>yE3Qrl!KQi@;*67`_7$I6=io8pz37z3=F zxEefWT(@XOuLiSZ@t{J;5gmTo-cZWK^u6z0lA_K5RqYttHM3b_QViAQ#nCj<81tQm{j&u}?Q7H#60*7>kkIp{r~0}vQXj;Qf-B>sHE zzH)1hW#|}-e45r4w};Q&%*rRypDW|7CC#KZwiX_&x%+;~VfmkKL$6cRL)``zil}F~ zNaSIf3uNUd+Gu)JHqI^kb1O6JkPB6Rb}m7!jjcchtm~z(8978}SN$K^K7uNZ`#I_> zGr1T$f}}vqMd_c_Kh=lXGwo{hTZQ4=uy)HF=0Fe^$-yL;xINGttfO;kD_ zTou&y(yfcLKV-RhM;nF{oZ)Aoy z6?6cQ%PJ0gKW9;&@U4CK5uj}n+Fl0O_zsr~0D6aQ+y44Y1f%YNhwk?}6N-b_fuC>V zPoKB|D{&!MXSuibZ=Q*N-kcs2U9nRdHYu@kPF_i=nstUf%&dIxnKe(m3E@U~UF|{1 zkBNsRxI&u_dHzpT8-k0FN(4hReW7&LakAo*ju*UU)sCJx%~d7gRWv;BDrp~16Nfq@ zF#`G2j#Gmj#e}PaTP_!`^FB>Jmp+=z#*l7JK9AKGg|~5cT`0Vvwc;XR#auc|tQzGn zLi}TMip;0!YUf8&GeZ&Se!Yi_36jhUsrXSxnKREB#QCr{dL#xwmD#x5ca>R!K&GMd zjct2lPN^c7tve#khT%n`I!>f9{7_|9D%G-szkEkCI?EX_PgHbm&zOX=MzOiiskR+7 zL+dKDFUwUsiipb4)AvS{4H&gcl)K{SM=1mGNl=F!xgXjDaa?!;%Z>n^ohB!!Ozis}3Iw%w+fVS28#L#!DtDPiFktsRbe`D7 z@gcs*^;zinJF>2hDAcYdgS8eijKIu!s0Ok|)IcueLiH>G6Q`dKz&g_yCGrXwWoaM` zurp`82(&uAqyDz9!Fv1WnW@49v;}@SGq1OTq63|;8B4E2TkQH|GV08q&rFx~dNYQT z1GB9G{e8%pX;#*KX3Yz4{A0%be{p8!!O=F^cp1Xoe`*8O|B#>${Q!x_x4<*=<#L4* z4NC&0LiKq`Iga;dKEb}`X4()?vSoVJMDdZty84W~`gsoFTytthQfS~hPmK$$x_Ji^ zvc;gsw^7w}jtl?f5`nu{69%<|fl1ryArzersytwt@4H+Nt{R+S5>exJ%9FgBhN74F znmjnA0jv8cGLAA%O==Ex$PsRSOiD?}pT&PyqGfwsy`-)axicW!s@o#d8tYOktF4ZZ za)MKz$hPu+JWGh-^IwCk3o0~L@owR#J^2UMm{hvroLkMh8D(ezVo5>(evkDkyr*0C z87(fU82nUk@z&NRrc6fz$4ieNyY)JM5_UMGxmlPq1)Mh@G!-e=C63D^+l!+q;xX&$ zk4Vk$Ha#?;PVwO;Qg4f^vRw>Av3yqUFHU8$c&b1488&lm@g0tGumfZRJ};4adl8_C zCp!1N-Vy|B?w|V08ydjd0Zy9VyBlXD;HUrP#$SIBSmeS})RC%c(D9djcv&1^<__4Fe%)LFQF zL$r=SM1AE$c7bysX*N%%)w=f@+O9W}@0|RyS@d%iDfi5`?t#nN%~KR^Y}KrZFHI%g zV6OM@|DkpC&PHt~I?dboUNnHODMl@Vxz-L9LbHBXYYt`1O>cgmTM(6MM^rA_NadvCO6?32`D>m_ZG#rA49m;MEyAG_(NRf&t#UpTBl|}vByvXS1p!s(P~9t zIL27iIy<;7_T+GJ+VE*xdZEN@vV^v|Q==?j&}Y?RNKxnQ{HV!-?XT*_3qGE&NdD_S zhqwD@pM#;nntZK4ZSIOZOTayI*yqZOh0ZAd%eh*>H)~>v_ygd%x_2clc^2t&Cd&aI zZtIs?)v8ZXm_jyVs%n^jwUi=MyrUA5W5O9J~` zu;k8_wWX2M$Xjza`J>tCRm(HYUo#MuElps)>?2GVIL{Lr{`38hD3wGe( z)g+X^EkNIM0ZJ49TauefCqPtAHY_-lzA+%WBLom)8^T*F5CsI-C`f2a0t{RD@vI~S z`B*5o>r1yG{t z^$}8~#i3}`0FgZ_peKq)t1$$Pu77@6MaG)4=P!bfNdBQ zKx&Wz*7I~CY0**JA$x~yuYm~Vi$p+->jZ>aP6CYSG8YN}2caFHx>E>WVe zMh*)g6b5)k>VsX43jEf`vIwdT&fpFP8HB1w*O%0LFpX8aiwB+&t{<#8ur=2L!=pfq z!(X6Qx${ziE?-8Yr-dWM!7b9DL0*$|mh)wW&t1vQ(B4FTK^^cYMthe{cu5E2WM~I`Ny)=Y!SSHl6BuL7nw&1>s zOc>w0Vwk*5>zhI0Z!(#&vzWn0#NsuXpu3EK*Wefq@FX2frU?x*brw+90l?GvfEFOGS5Gb^NbbM` zDGbIPa*&eSa6lA;3Ahr^Y!2A8lQ5V|QB2HAfORYdBWiyso|zx8o=V4vik)X-CI_ta zSs0N|0ZdHqbI3!NY&^m<>zc0SVu{kMba0t@OAeR&OAQX-37*8LY8#sdwqr!Z4l^+w zzfT@oWA3PKozrs3W5UU$#B{>t>5V;yXRa9>%ni@H|9Q&z0Mp@|35{GFh%>gl;fE1t zYhq%N1GEAHz5?oFI25C?+9d;j0QPryrhsjG4HEZC0?PX-6xIN2zTW2Z+62Hn^a zEI2fT#l>ku{u@AWa-z(DC=d(PM}Uk7!d2`5B{A5z-}H~608RqB8)t|JfbF~-h0nw1 z@K=x?C&a=QS@bjy2LW%iq%DWVm``g7F#>cT9^emO)^UVDK>P+_4*sWcUFog^WI^y} zHVI&u?wYSNP2fkpfJG(s9WUdg284HDR*3?j37KZPLmC9O(!qa_cAk~4ARwz7MgEvD zBMyDA0DMEuK_&_-KwUft_o2%4Nzmn%hOKxOr{a6Lb zbF@Gz+zvEv#}P`l0xCk)gV!PsnZwhF(0wRDaJ|W$PXfEC@sOqt2%FvmnnQy?>2j8; zF*b?^MWh0Vcu4_mog`4B12C_ge=je)29D??H=ySaRf>v9%>+6zqp;KQU3@3E5Ak(F zIw$}Jj93&x^pw&COlT}HVZx%2ChuVdn9(?3!HoR@qU-VoEWu;!Aya>y1}zg+*fH*WL!)e$7t)!jj=rdqm0`_I>dw#wOfBWw>0dCo4Me zY9!Cp(}ugb)7PI@=DD!Ht-U*ADgOAu%;|k?MXnq+!w=tb9G)nCdphz>`P*mh)0J}^ zlS@_e9AD9o+!JY_WMc@XrOvOqF*P3N!&ZpWL*6`s(}0@LQ#KZDH~gzj;chczOV7KT zn!J5W)^0`vOE*JIvVyONF=XUlcT*f*zBw0=Ha^_wK^wC6HR9zb?tPczxW3SM?8T92 zk9y^kU|xhB6ggK>!Vz|^u*B{o{R`YkSn%>`ah6QrkWVZ>dI1o#kJ{y?(0ukleuyY2=X#C3Ut)nJ1C*2kCV3Emi z^dta$;v_+U>t%rzb!oRaiCSI);dM`nbB%z6_AUz{?s&_&GEo8iy&GFcUG(hTWgMeQ zm=9@KQPF}O3#28?G3{2Ac(6S!vxK>p)r!(1RGfOK_)7Pv9VO*}IC{KNue4(R+T!5# z9sJ!bhXRDth!Vs}>eia%R=8dUIf;{@1rmtvGC&xsI2{onF?>N~K_qy-zS>+xAkYeZ z?CY6{>Q55eN2SAp)b|l~o&uY_6DfH zH5MU|vvqC71dlSyL0jjVoVnM}{@7w#=5UToo|kDYw?lUKWcHH9XEXU(YuhxFyE^HW zk60#*rM0T9T?Z8BpG1-kNFNH)4$O(F^F;XzFbdt+=2w^FRjEPI)H|h%O~P zSQ6}(Fr+h>Ro5ue89hQdiaO>RkZ)^3|CC5>G7O7WwGI1prsp%SzS#S(cG913(;AYh zT;)4K3Ykma5owQp6uW<+lDVNP;{W0YV? zig}w(2*PHk*?PYw_D-FR@=t=*zg{s`r4;zE^A2it68DNn&xBH+)oHC&%c zC3#09dlT!&l0!o$tfU%ti8Gq9B~aR{hXu3NP1G`W#k|mX zhjOp;b}uoQ*=Z%&36a8hiv;q$T4A`UA%W^Qiu9w6gVR03x<^Z-TEUXedA5TqbtSf8 z@0XVA7sOc}&&)j=IL$qPN}H&@DEX?ideFk%zSwony`R>K)nunQhg1$Ze-)&?Rf=Bz`SDp=My&d{Uag9 zZ>%|z7TUeqPM#I{2L?I>pOLrGY(*Ngs z7)FDuZT)5LXP60cOxEAS9zRcFME<$YI2O5L_vPCprhnEui}1;ExygsMvv@nV;)i~Z zsC-KiaLmRw){{*%@;4s-Kitg!*y7LmaVoK}oNw%gVl!w+9lfQK#_T*{3HSQd=ELG4 z@;~q&mzrLlT(h}-BxQIS63n>$k1jCM)>#$QtZqB9?m8vX#9wZu%vCO6WI|U*IXCAq z&C4ev1L(~2sz2u-s?*j*6J#F11joT$nTIHngBWhf)Ex+|1_cIn4mnKgwQ)7Ovqp+J#z>7H7Q*N&emxDOVW>JS{EEz zWZNEVI|I^#oG*5EFjOqbWd*C~1EB{)3rc)JpOncYFee|87{s}Nhg@?*0(-mTvgfl@ zq2gwYm3I1lC@cQ{Y!IG>AhM9cAtH zG7f`|C?s%E|C+Vw2k5yNI8pS#MX^uFjsQkfDQ)X!oM`i^p6WX5(<8EnO#dD&?-p;H zgj^1F3CVaGOtWW2785{6tehLUDz`IE#%;gHJyCytqAG+rrjJlgE2(nOFDUZ4N-q8xjLUq9ZxE`4= zmKh2nxvd7(a8LuYJE>#N#njsuv5PM2-029ZJ#lRs0&1WqALaw^+eR`x`_UudtHfpK z>)JaefO-%2$KA02pe>zK+vwu}I2SeabLsc6!qfk)Y zSpqVXLSv{950D9idbI9Fwjy+^W&-nU^&nSv4TGWey~ld05Uj^;-B5mvszNkO74nD9 zK+kZ<1?euJ&H~-Jm7+TDTWh6S8AR=DFdCdLh|V_g&OUONm$L0f*=jNTJ*i8(I%1(N zKXog>0l{80m2wxu5@QBqy(BPZVpL>NOFQ=eh23t1 z8x%wZq(!B+gh~mUv_S=xP6f$LN=kzP(gxD4)OXz*J&MQY`JMMY?-<|z49Au|S!-Q$ z%{8Y6RHmX&DzDoUMOCd=gQin8$aGFUP|i5@soJ6%f|f#~JR6g`c|lN($0MLD4Y|H{WZ=Ofs}RhqPaaTPI9@m2>22hw%Cs+OPlP z%863=Tji_)0kVp0dzi#SvCtDkxN;g31y=7eiAD%L+nT*9gQkvR+!-(SZxQD6CjoI_LM-q%}lB}!}>WvAU8P1d|&(M|9BJprVprd!zMgkfN)O! zX2;l5nr80@K)wQYD9i^wQdHK?`})i7&?h&4T=?eyK08U$J}T~H=Ibi~1BtN8z&LGZ zZ31xE#E;!DF@t2dH56|P5ZqJXRA2E|{nM^qj)-n5+!8it)1<*NiMzgR;4YS)aO!#_ zLqk`a2T&R8`alHYatm{Wuxe7vBp%chc1WhB2XYp&-Fhk9a*I!!dawenmtaG;1U7VS z%^Lo!fTg=4s#6p-daRw>em8kQ>bPNMs6_NUB(Io9;7_C6MLae2q9(z4` z-4=~@55*9%Ku^N$ht#+u;{yhjbnI^od;4^?|Eio0Z_7kmsy+^oJ3sscr)Yg4--mQE z>+6T_sxRn*Xrp~%3gm_uq@+OSvu8QZ+1?fdXWqryv%0;bC#%PF7H1)Gdk_iK}1f`&U2qS@`}XUT#`8Aub4ps4R2Z$hgf6w?1jTspc6;IUf7ZU?wl_QIW~`k-Q0|uS4#Q*$`6GVzNWWU^8=n2!3tln zInlAz_kHU|uRU2~8&v$gK3>%ub4}ftX#!4@-w*v0TPKS^df)$SbK(gMl<2s{2n6o5 zee}K*K2c^E>;7f+lC0-vjav=#?iDg_z~5$U`BH#fkZH-Axs^>H#)FS#7^6$a7LIPp z!~8X=aKBT5TRlJ>$(J>#Cf0?8AZzM%3h1;r4}-a%ivH?aTMsTzs8p#Anq?*$=;%?y z*|YF9|E~T3nypnOSFrG4#r*sJnfz1UTu@IuSBNq>L;)POZpDO<@G0gb~r=0=w+9K z>fOX&)^KV>b9ghm(){oxdJ@Ve1bS(sRSkM0PxO}?Vz_na@kZH4*5r%>9L@R@!(7e# zS8_b8!L6H@?LZPT0Mtho;7hWPFaFePF*{9Tj^(l$MDO#Q90Xs2wXEyA$Vo|ww`*ke z#XW+`3=rdDWgqVln$aXPQNpU=(tFdKcYfN`gwVlZ`kA?)_cxInvi$B~@c zU@Jte{plZ9J3GO@SG!Nk2(epjPYf9+KKMze=$|@=gb*qZALxBHy6vEOAm)3ugF1fe z%Rcf>Sr)D)<)GRb6+M}D+DNaOF(G*GQUW%1@SNy!WAk7TneTHXm=hJ&-TzHrhUdiJ zoZqzfOE%yM?W+(9BAly%-AfN6t3OtRYy?(2m6QxEZUT)SoqfveQ$=pUKjmd(R8KrK zQUvmHIPC^Fzs3I0R4JZ3^za}MR%ug!YG*)Kzu;m_3bkA(fqj)+!JL@p!&HX^i;|jC zu+Syb;tJfCBRL-&71rg@j5B%w)WMlX2MEH;T)DM`r(X!PbO(1n)b1f|=L{e7>!)bH zvGG}=B6p*E?Rb1aMekx#z60MJ&7 zX&WZA!yd_doZtGQ`u6WLP~eza&K2czwX8b7Zfo7KGULBmMb{8!pEbMrZKd5{GLiX> zd(DZb2@6BF;N03f&ToSEKV*B`pI!hoRa*^=D07cxOvr9mzm4D^en_VgwaU4)f9GMyx z>QBLWwgDvc5e3%>D8S3&Nk%4ZB1dza%H2@-2%NKd(FLCKT1@V65%m^uw^464@M(o& z6Ev3VgmvQ)_nj(3{U^S?ig_59F5AojO4nAj_|_ zSaJ6m=FW)16QXf`s)4dYtlabGrr|-@?bpy zwmR`_vIUV{d=9^2|F5gl)&)_I2*Q(mH|@5mf`YNP3xw6}Z?S2BdN*z6)-TD~%Ck78 ze0f^Kt^cR$RO5bBBZJo6g%hZybbfIYq)-mVNn@>x-NfG2?WO@zpfY2L=+)3JuJnxs z^=`~Hj$>)xt5eHK*!Asi)rt8U8;`&prRqI|CsU(}i@-B7~9adD<+66zPCe9pd%nLY&3 z0{eiomL@YV-0BwCAXdwM;K?;akF2!lFOlu@9U6%4VSzO(xEdP&xbOW5S(p*%81o)v z)!IR~b$5{!4CXD|(eLxt%ird$e5M)WJD~5G>kYd25Jy+RdI4wT#^l3FZ~BpQ{f`1R z$gb6&^f0S%ptFr3m~b<72VR!S%+bUSp5$)QcR}v<|3piCaWGe1;2v<#m9pASQO^Kr zrk5+LUV5Q#?srsTlzy(l8es9)!Y?v@3lb4$ib~qb0wS=FY z<;La4rz&@qD*bfnjzCLX>0@b{*zRXN&`);7eqfc)!-yd9h@wH}a+rkP+kMgL$M3A> zaNBmeu+J}gZwA*|EAg4Z6}zZuP&zs#H9-RzF(HkGR<(0_ldYRgVGGot9t;&&iq@ z*<_gjk|}aEoLb=Pb+6-N@h>ixf4nc>lP&m{XEWAgum^Z{u~b$2J{xK$5gv)k8RtU3 z{I-j_x%|^z0N?R>L}?w!yfOis?N;~z)YS*Dyqqs3%!EAgq7O7Jl483fvkmuE zW=WXmxc@kly8anYYg`iqi$N=eTD>^R!IYnQp6Tk6%#g@&8lABRaiOr#p~rtxwnNjR ze@ECkJO!sS#iW%#lSm3l?%rE1MwcUme{eQ!Q7-JXaq6B50&!G**)Y^YdP z0`e`RS>y97-}O;{MBVJOeMB%w!v@va82zc*%Hv+OOlz;D_U@a}q^eYcsd|L-f)WWhE;vw)nhO=;ScOIit3{V|L=9{^gNOOL_93@`y zd}c~8Xuc+Go%znF1gmR5D<4!g_-1X8(_)OG`pIl5jJTL42N&(l)F8gFHVAo02(c@f zl43a!`Hx)U>c$r?F;{_H)Q%6{$A;i*uI_0cKiRDvurJ^*Gsa$VzbA&i53rmxM@ZUd@*Zw{dj-y zz#i89D>FVo*ZzZdEA7)aFuX#?{eCm6k1YLcPn#|mPULF)!E?e!uJ>Fl#V6~FyKwx8 z2{PN5Q;xPsSP#)RKnRfwHpu~BE)3IGC<3`s--@3d{VUv{p+bFRusy>8x-0f*aG}q#xhXu&flIUJNou9GjQxZ#iHi1%lL*u(7Bt)gH1x4XwK#n zF7aHo@L6+Rz7pOO0JNfx%-{b2o8OS!V71YI4;sQ|2Ruu z1JdiHa%u7L24Y_7ZGG;^06HLi4BPP zYhc{F;%aPaocMP}qpXj?oirGeE|X=DFeKvmCZ=aY(`@=t*Xc@Lv4>e0ll0sz_y50vgmN-YJv3{u5^ zzVG@I+JJel2;-i4&QlUZDt>&87n zos*YHeD%TW8}R*6&guEG0y^t}Z=vEV3Xy|t)ky^j&C-hp;CU{p#N^7h+mqzU&uiN* zzK3=O2+OMVN%7XR^yZD+(b8pUUC zzWw-fTf0!Z7w;R1jI^`+A$}U~8L;nS;((B&{-hg)`gE|%D)%eBE=n=l9eoO8GWBj+ z?!mGy7Y2~}b45dqQigxLTF;1lMOhE%+%*k*eRP4T0-d!rsB?~vru{zAXDy!zkcm>B z7~$lu;m_7(w|^buL#a2gs*SU4mUrqaurKmkIQ{lIPxn`ao_WZ(S=c4{{2;XfZzgpz z8Q?JnbgO+DYU-VRtmz#`FTDr5yhAn;?Vkf|N+x`{P}EU8M^pc)YbHc3NQnQNLr@LY z%y&;!J1Gd=Q2&9mYejEHpo?Ee?{DyCZHF~W)4ErK= zH!0o*II9?QX47Y*Jk3iBOc9xr47otg_>#HH2Pf$}|I2rSlh9a{9Sz+8WM8*#v`qm! zy|_*8aGh%ZSZ;c6Tfp(oi-BB{Et}ydA$<$W#wa>TjvIgGH{jF_Jn9TaE<$C>yCT?h z=pQ$T+-gi|_QjfX^&T#|FjeNr(14=W+^> zGw&TvE#O1W)l!49gANx~Wbx_%e&aBegBkR&wMVB;Ovm|7C%Phd1K8NbXMf6IoXT2} z=!h~Jmj?F~c*T{#!UI3NspZwttSPV;q6f2jjIIsb9!E zH|9^$9zVHo5o`o*9zP8@*eNUrdnQ2xu`d$K!8+pHJE;C>A`$FH9|!%$!D44L=T{pJ z-OeUh?*Crd?u`y$If{od^z)`VoEY#1AZ-W^27NL5<#^%W5~Ti#XW7r%#W1b^h@7x? z`P{`r+lcDG=?i|=<;wCE6!YE{HgeH+JA=#SG}|w@P^|sSn|?NK9C7J*=$dNQ>VdVz zo$6TJt-aax3|rKijO@tTSZ^MXSO?sL;8y`i-*|cseHFY#DO9OQcV7iGsH4oMKz6;i zGkxO%@U~BLgyF=#%fY4q7Z{m@^vpu5cy=wY8|6B9(B0||7qB1a)AAgwcnl|ot5Thq zZs*sf{w7{im5ST1R|R|9=h<(9+C|De_?%@aZA-qBq^H8^Rn6w&i(|9S3FBP}*36S# z#bK=9oyYgG9Af94Q) zL{MJ;fg;&E&G3d@GvyE0_C?@rX^Gui;?5dh2-v-V09@HhP|%%M{0vf0K_=q=)$Pp~ zd{?7JbMFLZcwp`Q6Vsf5skf1v+rVYhP<`F+0PGQSrp$NZ;t^45b*y*U+>@7ImNo)| zSgWhomSKAsBvc(5tfsCIiwArge)Wi<-p^rw7sMpMx%Io((F(-sz#c|Nm98EQE(=v- z9$ZA|qolAQ1(qQ@$YsR^>E3E3Cu;Sy4))@#{;|+UIg{E^oKV6^j63B z-sd8`S$>7fpO)Hbbb1S9IQ;q~%5NkLz?JEPUI(0;VF-tBk?^hR-S$?+9+%FEC!Ju^10h)2A~^d?3-iu5Js zxGeF<^HkL62n7T%yrv2ZBWlMWn0~lyI`5D{h{RhCSno2`E)@e1gtfohgCP|*1nJcu7}9ns0{UD3IKbXRxGN%e!u)!pPvOW(-QxyEo4{&oMm_3iR(`5n~7^T7w`p% zBBnLw*R5D#r&ha6-f!uqMHlK~w#s86>-GAME6J9;b;JC}TzNE?q`G*E}IOvxP@D&Yu z`Wm|i2n(>`IL*upQxmt-GZyc{UiB6Qye*4qmHchgW7M|~H`jxxjV019v5Zhge26lQ zx9?cHNcQVgIRQ^K`i_`ZP>Ec^1oBl^kkMu4nt z&+^P4t_7Waw6D>o3Tes`zk8u>nm7a1b|%(7&g4g4Zc%@;k1iq00B3W{)?!~o(`Lt& z0AkzbeQk*x?~;0bDN%UFl^*YWImUcENX#Edn4B0IDN3`HfLGQ-+G>h-E>Pe zZTDa=Qn47TFp6L8-0C3nB*s(19es)c?pEWA$4LK{d-qR$>+8lpd4!N^C{uJ~jS8BP z!*yz!X~UX)JgCx%Yu)d@JVz|+N2hOoU{ZhH<+Io{<*v#6-!eASEYwsm^HINLY(fla z_My_i4VV{XY@$KNW}O{z7M&WEgDGR95KyKihcjNo!73;+sR1LAv3STVOQTRHj8miA z-S!ImrXdw^qW!?E8B_WZ4_4%0wpfBn?QF!$CFK$pUyRo(9!P1wyX2 zSGrj3%c)~jZAowNdbg(f(x-Z%3BiJ)n);_3$3Nf+tpOQv|B5H4rF8_(mA~*5Pv5$W zCyBq~$z;k{suH_#M68K#^#eSaIUimPSY7(A*BO<+Mlp6?vK$4bD2l5gcvt2}0I(*P zjz#U}{d&FS!;jGgxh-NA0X9#}^9Ede%4M(iID-7mHA~kIAN|UQ-7hi&F-}C@0kD)9k%L-z#v?r3bDcj`Z~r#o*>tsNM-? z^8Mi=weMl7*0~2@N2Ha)$%!sTbHd89!&=w1&VcDDD(fg<@=McW>VW$@CG}vtfX?D( z9P72Y*8Yv-G!fkokL0yYH_8;nsQpB z(7>nDlQ1N!YeYMPefep;F?gU#OK3pqNG8$g6YZ!_9(j}1q?&WfJHI@!!M{{*VV^e?Zd}1)#avgQlKO&}QIYXi6?08bO%lYJ&IOxzB&+5xBj3XP!Bv7NW450Q_sJ z;!nPmB(|B62tbNM_E()E2C_nj75KX{G*YzzZ$`i)kYx!?0G*=8bo8NSsuy6!axaA` zgmYLuL<$dQ9BBq%=m#r#bqF<%)1Zjb>I7PgWcozYK#~k}B;KkEIC*C0x-uz1QsmXD z{+m0Uw8Twts2%AG*;4^{4cC^P-^zE>S_9o|6#Ik#V6Di@5F=+8fba&+&btwrVQ5T# z&(N^X7p==dg*kLIKWaXCa^ zVbu4?IoFNuj%!8Hg3T80JV&@k(;7#-=MdE~VsxzU_YQcmF`U8tvJHLv#{gTZiIBh% z`VYu}k#OcDNHag-{y%0(|A03SNl5?59=sL3hSvT6!dvRG!4c%tGDJbp%wt?OX_McP zulNf;4<@eexl$7zv3D?^P#!;L@?~;$GX`TLfV0VYB_;3&OX^xG-SJg$+Z37H1{4&E zO&Bwv$noCKNB%#oUacROF0;rb(@62QBSl!stBmC1I=W~E?=4V6aM!UPbl^*BN7JPo)k~}b85hH=9d)DBe`lG;O(b|22*=b_Gt%|6lgIFA-j6mcw+ z&(qOem0#71HQ!&qpPL1Xt#7G|Q2_tX=%C0dIv`7bS(& z*;7(tKz~#Aj86N+?=0yJS1ATVg$90{6WI-18u7~kAjLEO?Z}+zbC5b!xNIHiRM1hI zzs2D;5y0|pU*$74OAi-uh*JEo6wgryQ!lGz)i=IFUEUrStxG_z*?VD1#34mbVekQ% zbW{J|=~I82whWGd?cyGMg z?ek7MAB#43a^}27zVaOTf7LUJItOAkd0-!U?ALnM1(~4345F~SD9Fvj)-&|adR73} zvkDC$_X-8N!U+G&Bn{!aIq;r4PvF5pa7ukR9;PwQmacb@O*{m-DoBoc@G-b*yh9MF&$+6n;s zA3Suk9o`)xm4B|C{zElWgw1C5pzTyXH0%2d+L$2%nh41hy*=Mw(kFd0mM5H)G1!sEo(me zbB_N9_x+zt*6%F*lIX*B%2RT9uh!4M$*!s9OTg-NKs9q%T(7c~?pqwa{dIF|r+V`7 zNM6`nGY9$}(SFk4|Jpq%>S84~(J=+2z(0KfZ#Sip9=IEk)24Z(onmU}s&`}o9E2BZ z?YRlSLBuhG?n%vY9v;mOW8aTY0Xv%gq~)_i7#Q$@ny^)bn3^io4(F^8kXCewwQCA~ zl7fgi-iW@6zdOUr)CkrBoN1R1Y+^`4HWVw}A{Q4ZmURhNt}VM#sONU@AyvB*a(LGg zms=*lZOA8K5}Yew$4CUy9;S`Sb52b6C1TxXTu+&Tl*Y4`{XXrkX1xy@RA>!H(xo*F zy_;>du^D=Wv_sdN(oSxrRp*%m&zvP$bu2E)7Q|hWM^PSuyflSn61}YH`T7pjr$TE! zLlUxpg*VN1p|welUhyAJ&Ne=1TQanT8i_Lk7bcx)ssE;X!m(%^d+;W56Z+)+6K@hs zDEy_%p0)!232%ctdb`!F#7yAboN4)(+|~tHt53O27j&%(R`FoB+veH)8xet30yQ7J zPAGtA2o8#C1iNX+J?BKf-TNQuDIT|~33d{Qq_z$FB9mJt7Ui(rbNRCC8<}dqpqwCxiYoUjb*R*E||ilT`*m>c49BDN*|9&;@TW ztu6TP>M00$(1Sq-cCVZ~uE5nT|36J@fDyy9XZ~wi16C8iPHQ-6saX_${0s8lBu!48 zr~uLp!Gl|L3i{eTAbSfFK&4q;7r>`xP~0x2+bQZdw%VOY2!qc3I5nIj`l&4U-XHW7 ztrd~dGix&2>OEmvs z_?o_*Qo9Xuk&mY0IDv=meMi>hmLDpfb+f)5dDa19icKr?RcDfF@eTeKOw~FjCgj^r zg;on8IX7VuDEya#&LVq&%R?Wh~*CbG8D_v~W8OZEt8O0s^u; zFP#p_SMj%XB%()f!lhmrPJfkeI}8r&xleq{|CZ}EO`=*U@CAnzL&`KyP;GRwbLoU= zyJ)T+ZUCLO5gnPTLE)Szm2Qs!ZUt?qJ%nws86b-`tH8o!<=IcIzW;FFXqXwLbO+Kv zw<5c>%K)q5c^j#)@9`?CFzVx)db*ZtUw$fZlLBKs zkG-O^#v<>-U;WjjE70xHlFH@>R@s!YkebvQHh)QxeZ+*P&<{Ye?SPBe#@-~Yp?Tjy zegcYUz|S7D`ZZlUK5PFuIfle_m$E-gKRgY5k+==d70y@9ZGisj+$^`59}+;PSY@Qj zqTVHHj8r<2ki(~)Gxyb2H&;hPUc-oZ{s>_(`FQcP)HCgLW2wG9uhY`=b;Ywrc45l4 zX$gyyx{1s8gmyD(D=9W{?JOt=ch0^^%4~PyrKG)v58)3cyET`P-trivn%0NNlll5Q ztbIA(_+rpa5Y% zWk~Tvg|nh4GPQJJC3)8W)LVxfYzGzBq_9;EyiDl>s@~_p`W+e0bNTXjUI~_#R~`Nu z*yI4ua;ALAZKqvaHpk>;uQi_Wwx9$}mXQPrv}6zn?EYTv&OU!T^TP-H#|80TC4aJM zM#t-DvD$XC5PjP25Ya$+&UX~|)ju+R&BMM-fuojudUc-{!B^n6TQUxrR^^k7Rq>4a zHGwX>AFHTfM&CKh_zbBO>jJitzh4mJ!S2mRASsSh35FnZAj}mUi4=#gjH-(nP`5#c80B?H&V!8x8M} zsP2-^SSlHCJ$ZQCFcc&y#os0cax$Dpa;dF^P+mnW4=chT=2UNebz~)NfpF{if=0Do z?Rpj2@{C}GfKmVxoN1!-Ret%?Fiy{kv&wuhxYL{s143<9{0CSOW6={3P(hMsXLf-O z+`;v0M_XT`!`NGd-k3Q_C?n>RU5j~UxMTP(X{OR`ke--$=j|Hz0#2nVU2hO3LHQ*v zMBsmi2!&st?$;vG_8?%GD*prehQus5aq|5@^8>bw!EIv%$sI|Zfj#Y=9;x>7sPU{ZWys@g^$IdmwCkpU)hwx zG2;(gobL`k={@HOr7Exii5dLL0B6ShG~rOFSnHgBafy41tZp(7rw{rl*hzGk**6W`OP5|V_K$iWv4ztIq;rp zH~F38bgi1Ra%`J288-W(-a|+C7adunN0i_(j#Ht|pymPB=a+GK0c=fi%$KP+?18O<+rr>Re zrhW$8V}fq`=#)YyNCm*#k_9PnwBffvBv^)i)9pftV080Pu0W$dlWw)rmMm_bXe)1* z5gi`&i|o8~g)YNHZ1zP&Z(%{$CZT-ygAL9T1BqVPai#b>3w7`M8=Pyu^r8H>;#0Ca9)! zV#nX`YsR-4LI@$1qC@`%o8X8*ie(Qry(FRTvp=yZ{KgL7S^SQE2)u*F}3C~MbRZbH3 zPB#j4Y{?yF${EO^|K_wEBVUjNl2nC9a0}s0UX_nhDEYskUVG#RRNwc6Jn&Vr(vMzH>i z*MvQ=36o^rgCWBsP}}KWFvJMqYahO&ANAibmA@ukmHq+cxJrOq+d|%Pn|PM4T*xHAddE{cX&K7^F9P?a0R%>1nGUZeR)qywGw;H-74n%G+&JmCv42;9!hjY2>Q&|%gvgjEzP6 zM0CM<9l{I+9U-ykU#{fS0j81&8x*8KrP*Da3Lz0DvT?{OcHmz)0YZo%1jZf82O14F z;F%Wv!p#5!9VS9SsYf7SP}${UU{;H^M}=aOlG9AhUfC;*6!79;~XvKX@H$QFfXU1^;jG zYk>XYRoJTXcn{_mt4dY^3@#}|cnI7X6DmMg52A36L`oi4lDq+YjWr-nB14z=hr?5$ zyIc@S6Lcg(#OU?W2sar4LkKe-2+E~vCNxDMPVy>1 zh5HmB3lf#USXE3Zg!9Q7LR{eA^|Ne*5GdekRm-3Nog`I&gsuug+^YInqy%(9#~+9W0^WQX(tdr15p8StjLKT0Z++ekdo!96QX~+N3A#4h z#RYwWUrpl;vt{(bsF>69eYZ;&I4A0F#cN%VxLtJVK>I>Cdhx~yEpr{9Uu(6bb{Tj% zKYa8Rsb6B~4O49*7x}iR3*tieg&T3yj%hNCb9gvFWQ*#wV;<~GDp4-fk~gB78G1OJ zilGDR?i!<|5Ti;|M(v_H$pcMx297A(I7u~#%7KZ){R~9nsm7X*L#fe62H#4MhxD9=!7LwDb|I8lXb`xEt4{?SwjcJBPPoofQ8t-pHmx*N1*W=U{ zZ4RZtUgY(ZKRng7$Vz*ka6mawFT_Nq0!>vi)yq)OfC>v8iZG?_Qn#yPJ|bI zOe{`~iipYh9A30kaiLoG?W62x!e669;?z3KYuNQ%n$SgRHX3g%{5kAO(S;XOGLCTjmi7yhk-HX`!i>DvX^Ej$i=3o_F;fU_%QN7=z;6mjV3xg)UArA8b?q@<6n;kOT?aNO?# zhhoqQB92Z4auWlSR~`tbG#4T{)C2-`6`<#QD4f46FWCu!<>lFjF2Yf%&?^xXu0rR{ z$EVEtAvT5GIynN7E5|~|ZrEY#fBrPqr5G-jtFkEEk@W;lWe}1`$w3Gy#@Zp^#sCD1 zloOJW3i>Fuh8h(L!K{vLU%L*Np?kf49bQAn<5LlGdMIq~P^E+n66_FKCmuG{oG?Nm z4U8bTm6*~s-R3q+VnaBXL&yhbt{+mZafj$tJ0a_2JH%xh6bK;)eeG|Cm|$K*Bsrq+ z&)$X@8{HxBh()BGWxFnv?F{|qiiy8a0WotCLLSTt2-sj0n7*+PsFVxjwLW{Um-6k^ zvz#xtXDjojnaCRortk2V`OeUIzb}=50y}-D-+oGYF;$*BQ=a=^d)aO7&W)|=Y5XAM z^W3>3@>%oDdVmYM>&EhOkvWF5dD<_Kr8Rj)LR5bCWZ*LE{JWPRkNBQ|PSyP2j&ytP zU?WS(;=LHhH>>yZT;DA^1o_l@Z%xfVMQ&a582#dB>i@#ELOpzP@p83x<~fUVBc8bg z`$r!^_}@lTot%NQB@@ZjGr|1$w@1$8;$I$(pU}RNPC-HDjMrIdl2X~q~VziQRlnO|K z>r5MJY~l`$m3x?(h?zNlZo_dDI$w!+^6!<%rS< z6Uh}3@QW|y!a$6XSHzDy)*OTI`;RL?*8D^dgp%>G2_C|(%z6SS?-JwtLOg-;dp{J4mq z73qsOetebZ$vE#%YG1j2AD^(4f$_8Kdzr5(hO?KB$E%8cuy5ukIBk)_sAWZYk`~=i zL*ImV-HJNSf}aTV=R>1(5ah;>=q=?IGqJ)ma5rm}B1=Z-SRv24+m0Z%t51wHGkWXk zhmu~VP=I8v#X<+*k3BjF5!g*bxY<4^M7NXz^pSZ4@~l)#>Uyg&!c2yIP_%lX!@LP% zq6oW%LS%|5Kt29#m5GG|c+KX=2px3Lu|kb9LXFalr(CSRRi8cr;ghVN)y6WKO!xtbjjL;xSXE(3j3W%{e7} zvHe{M8?zUoG6_|5e|e5YZViz`-@{qqB>k4$mG{|e(JR6&t(O`jKUK2ftn_OSw(-!} z`w!Fy7wxY!_sn1b4Xp6rbW#I>HM#IuY?_XXKx}QGvvxGNorM_npG6zlb7zkz6<< z`FMHaQj8$tmI6|&UG(+k7=6SYufX#M>Rv-mf{^UXD&G$F5r2sEYf90ludG6so|Q=? zEQu=L@H$TDRQm9Us?&S)`Sxd3WLwlDR*a?RbD5Ms2gp8I!GF+ud_YZVG;lW5FWc*U zkjc3L<+NuZ8GU6P#>a9DGKx<>8nBqNaUSyTzg?Br&qOvN!xuPq#}DH@%VaejaAD~l zyK|=@R8?yN4jKYo)|dfMfc)zQ|OGSxc%$+1zrqh0Q;j7Ft~ z-~1}IuO4rntbJgFGiq?|zz#nn$-!h|v_WJ@*Qjc3dT-oF&-+B3%l^9Q^!T?T4&*VO znXE}GR?mA0d^9uN97<(#H9ECJl$|=?L+{TCIh6{{d6_+-vn4o|rCM{R$mZgD z83g(J1n1F{Usp`wwD+&%zq#CR@5d@{;OJPBv?2(7D=YuZPnwb7Q&rJyYirLoi3wem zYuAxho}IDGiAly+e&-jmFsp|tHD$UsOs9v%0;78AIAyyBAj!lc<1_mehGuP#-~eyGGH3zCcJx@@}gd5i1m^7|+Km#eK$ zRk~%a+Pr*wdCqC3GB0x}(6(_s27gO>d|_s;x=8NTi#}U*t`}m0mvPVA8$9*uPyT#+3o=0XG{krG(;szV`5Rk_ z-}DL~H9~q;VIw{8`_wZLSL;@4=WZe%xbG81)%%e3qHXbsxtfW;IBx9Qn={7tledNJ z;bhgAj_>>pcze4vZ$0Lf4<9`5Yg!Yy=9up`@4k@_?LvP@TPGy7>WJlo`0zdjBr#|8!td;QEDcDNv2dt>MwL*9lcv4^zQ-2|rX~pmyE!}s9J6TE)x2XzUd3=mUD`u11`N1(uq6IoVVt<+J)c_k10pXWY*rIH<# z|Jd)EK<>2ke)%>-W;mg6H|uf++%~t(c1hN3c7e;AvK?7rR~j$H&iJS&eDU*b{3{g@ zB3k`KY#*O`4{g?~4HPb)m|ph^QbfNtRuUrXHP+QM=u0$ACo=AfHZ?cSH7~FZ&@*(3Oulkeb>lKvpL@`a8LQgi+(Zk`t@Gw{`=mMU3m&?n0VV|wM zc?0k;gZAgj$u1yR{c@hH-IZCjbb66Hz!oPd@v9@qhk`U0n>^ow_g^mhACTKgZuqdc z>zLZ&h`uEYTpN03mf)P+pn|`L+YDXy zV1dl&xm)Ry%9eaP^%+~4q86!GbU_g(k%VwBP3%hu>CZzf|CmEav(_8rGz;B{(+n}=HzLlx1 z4=t>|W9LgN98-t_zy{1Tn{#k`xb2k4?&hHrY`{Qu_yrNKT|6#b{Tk#N52}M@g z^&6K0{;h(bYc&&Rrq=^z_r3V7I(&3Xt3~Jg*~rbsSAGDVd^SP0Pu_r#z<_Ew^bNI> zU;X7$Qa;XYZYfYqS#2ouPL<)id4GaMy2o*4RR3NYo zY+HMC6Sz!G#L`{Ol;)@9W>t>-i(a7sM=b0?1MnOvw)lw#z9bB?b_}55xb^HjRAGxn zgXmV$-aVA5#MkYaQ}7G9FktohT$!Trx^%$~?zPgQ1%*w=IoL_V^Mum2DHYg<{>9Vo zK||(F6v4zQmZv@0AhJ?k`C(1MQEz6#XCCQE#2)hf&fvRJ*F>!vop)Kb>WNnlSkG@- z&v9Mb?G+(-QPm#-Pb*iQGBCOJEl{rJ7Q?Asu73+~{lpu*`l9fCoeapfqBshd2JGEj zh3J#Ib8W{c(qnaGsp<-N6=}FKfd7EXf{P}-DpiCIpiXhZ8C4g6FKAsDh~VQknD8Oz zv4a9xOBHa5hc%;?Jo6;uv=6-&bo9SnSHc&X&es}ADKF5nMA{(K7SG!*0`BWT20O_H z`G|HAKtr>3@f+z55@!;QW^!Ie`I_1BVo1rGjEt~z8A+x3V(ua&U|02I58ihYxYzQ@>oN#GHq99LylfgL zHsF-=ej3h};tFXWU-}BB1k;j-Ht6I4d3mRvA>duSW9#;DL=YW3_hoexvzytd{V88j zUxjSfD@rQ&HDq622gKGqTK-bmbzP(iNs4G@d763y6`kZ@g;?meszH~N{LUSZvWphTLHRrm#G|d-h6ZHbI-a z=bsL$`KgHb4F_?xOeVLw)>ZQo= z{lm{*fB6ju-B#$N%KIr#I%Z}!fU3KC;1fSOxT6hkTLDO_a51skPxBQzji|ok02bYs z!=n2?;s7MT{KUcTdZ5vu`0Rlu$^|P^h&TZ_0}~nq+M-C9F4ysdZiF2zYGbqIDQ$m5 zYT6o26V9bALRvpAq2izMy#mDVP6)5wwH21y3gx%mEj4ZPY_+KoSJ?d4_{xZn>_}-& z7CEFDo5rrLNInl))OrWN7q(%dlaXf`igdb{hro5D9tRGD^Ndp&WW>5^;~V!mYMYxR zwDCg9V_cD!H+$QLcAZIvU|qqkLkyI-|g4xHXkPHip^o3EFVEQs?{ds9M$exu1org!l@L~ z>k%X4GmxJL#~Xd1CY<0+1kQvebXF`RD9YB%iholRK&3fEwFd`){(Wfh69?SJY)Fe- z7zdxjzV`;zKh*^D-I{PhEMWDsOJPyXy7YT+FIHeSv|g|+K^0Ru{2zP6D}ohsveQia z=32(pzYRU6t1c-uS$PJ*Cdf zH_DSm!qlgp5%B0eMdWP%VrH6kzpU6-k_K_7%G0ifu=U(xD>x`Wi+5a{zO8X@2oT@N;i~@O-pU*mt zxcOr52+@%XrUL;fjMtm&Uw)O|HW`R2w_B9d9%8s3(lHn7tNyYWq<6IW zBDhYqmH+q=E)ApzMD;w+B6r%!yGUGx*uRoc-OLW7gZ0zI2j|Bfn>GQ1ofVsAJJwMB?ptzg=NRo&p5I{~6)IgG6t#4oZx!m+yvBE-CJ9c>m) zOG*KcOz3G#_jDGMAR8|242tw-V52mRcJ82LRLI5d64Ku0W8i_?S^UCr^HY<~tE@}M z^jws$e>}cqOs3pLi&ciWvZzSRy31?k@!uR)%JmY%8I>SgQq_II&nc!aX&At2*g5T} z_9^T$W6C~NpD1JEsu6^#nTbz>kGZLPHZ4SKJQHSPme?MNP-cUGGf_WCLhTpgeBflZ znv+4Niovs6$^G=de`DB4y_(dUBiGBut48vgPI{V)1e)w52R&Ibm-*mJY1=8VY##jw z)Z~e#RDDcKvfIX=DH(Eie_C^TGv~5{3{uS&Ig*% z6Va?18D|nWA!24AycCXlz@C7Fpr_4?ZRxyu$4{!Mw~;3_2<7OI?4!@O^V{E=FQQW^ zksZA_QPEHoLL(*4OFAQ)U$eQ{MZd%eyIApIQA67!$S*S_2hr3{G4Rm--6w^ zXE;@RX=pL(uV}Kh4eJ-gjJ`rhSwkaZ<1k0l+Rh`;5n$QpWjTm+`vyAz09 z+uYx=;`ILfyk)CgwOt|B@r)kFwq9bvWKc1PET+knZmqnunlBc-N6ijyU)V_a13Pgh zdgK3N?akw%ZrlI=a~S)+?@>l7YnCMYPRPC#qL9iqwkTqP zG6`)6$-ex~_h`ND`}h6akNdj+@6iKu%yFLQalBs7m+G6|`b#{+*XJ31UY|bPcr3VV zO`IoOc;tZ4@+J=@*QPvNr5B9b-0;ln>gLpp53o%9vu;Xk{@ehXi!W%Zx0Q4; z5<6uwmlNfST08?^#D3M; zP^~hz?2(d4led`7JWp!B*g|~X{9@Zd{MBhe9Tw{}f$n)6m6)DQcY(X9orW}gQ1o(n zd)xJX%bcLi?CCk}*vD1t$80yp74O<7qq-O9e&MwICo?P;0;VC>0hcOxIq4k=JMz@grE%-ic(X;(L@)CC(E_%5lKX3 z!p#~XS=r+Hw>Jwi)wJ`^=_H~yMokz2?FGQ)x`WB?&(ZxN@f-KlB==?KR!Qk^;W%#*iv`eJ}kJ*{DaD6EZ> zLI%$;30bMS?Z7nEU-0IZ#*c^FNxQT|1K%05Hx2VNUqDyLv@i}?g_Ds@caM~lt#Z2p8-(LQM_zZ%O>euGT!Uc~HR)*e z3F1GPX1V0p|E(@E%u&3Fzv==B2))?4Q5T)Pp{hWbWuq<#!p^T;3V)kzLJw2v!!Nd> zQX3pQ=p^A@_9%BsTPWX!I7z_HGegy&nBmk&OrPU`ocs)Y^pX>xtQTwwZhn)PGz;k;=n zQvdcsczDFqhhJA#3CL`dU@kE$mT}mcJlkYK5dC7bRXBfrxc-P%q}x!gw(V$S)yb8F zDK|S6ERhTC0Qo|jCE=F^?h+{YODLB!b40F%tJ zoH6B=_DU7`F4G_PllTCa{#{XFv-NHHCjDw%oJ~t_1SaIugU@_pQnbhjJ!a1t?5UJN2ba#2S!%7OReJnw zCf++__-2_C1H}P&#w6 zkz6@}EuM@4n+#?cgEwz?F=W5K^%*8@b7KnnS{$Obywlj3by>pbQ`J@@9DPDAG6j7G z6mgWyqs1;KofXThyaph``m>rsQGBTNi#-8N)t`#?ey&v8DShfghb$^oLLuKcQ&H0* zQAN6Eciw3vR}OI?Wxoq+eqrsZD&EbRiSQ41EWA*%sx=vF&&%Fv*GnteYu766sv@Vi z(>=)XCEl}c4WP;Jbg{%k)vQ<`+RrTo70tGlB*5gPetxkaMJD!a zP{xo=n{ChPY(zv}U)2KKy3VcJ4g0=ZVMcn7VaKAX+H3l@2I$%~sTk{(X+PqdxuU#o zdL5ognvA>}JP$O6Z6;P9*uhO3vR6S=^CjboVd`R+4G3jCi;f4OYW_^Wuhl9{G;&Ba zm{D(BFH;lgmkHafQi=c%{f_sii^S%~OWg6}vT zvT0+Ws$zBHTsZfUH<1Q9i==4aUPYdv#@vM$e+E0Q%vR$ksmGy<-_ypahqs2#qTFa* zqzjEBU8qDT)9+KRutCzEMiE2&N}@<3-6@~z4bM!HAd~u(EMc2}VD`4AnG~!cJ2VSP zwy+axrM8${x2Gw=t#rRD%kvtTQ1Cin*qfI}B}_-SCDwT(hzXCiC&*sT@RQ*x^LNGkZmHa%m;s-F>lI^Rw_|HQ)GRuxS4y*V&z!Vx zJ=i&2Jvw{JN%huix2NMl3ZrZ99d05FRuxZ+%6u7oAF|DT3bO=5)eo-!i(-CVBl?;C zUP3Y>2dc{43zDU=2|{q@as_P3I4roGsk$A$tr5dF8vz{9r_#kUA}&Zy=z?rkfK2n; z3}^m&R)k-%!8{y~eqwmOC4O^7reqRyU3lTe?|)23Z8u7Zz6k*XrLvo1(<$O4OxRm$ zq{J~0?z_WEuxF=f>J}5IiiFABW&1d=(`E=k?1^-jsk-dfuNTLjv_3O@tJ1>1;@fWR zwW`vVI>no{j3tZ5jp2HwaWqD+r@U3fcM^BAO6$2ZWeHt}e*1*tjv*L@@cl$*ygt zCe#6xsMId19<-B+ml^Xdq72ngODfHr-G3T+gBN^IJW%#rPxxtL{5Jtr!wB!IG7snX z3rzNDz(BWSLWbXoYVkW#94V2%)>zaed z#?SJb<(ofT-9V(oNNa*y;w4gF&rgx7>*>C-3}V^l<>w7W@p)VN+9uQ}waX>0{{;z9 zrkL(MsUuS_p~FqwXy4(`KnO2qQnDyu-qLJo!{GJBSa?>?%C408b%li@CzGA69anSd zaM26HWc*DS9CxVCR?@?jkdE5yYJW-Xx<`MqwIrbBhMt}S@PwlzYNCz2Vg6s0Uw>{; zt=AxrTKAkj3GKgBfAl|2n)z4Hwu_4_V5a$_o^ty@i0W_k#0JooJAT$v^;@v}h6Qmc z?EkDM0jX<)kSOLBwQ_`c8LRZx*G@d7QtEum5x@P1!mWfN>R7&#RRp399^Vd>-_dY- z*yk1a*XsQ)ooDdI#D8yXKB$spB!8`(8z!uccqytHm#*Ku*8cVK$_s>dSmiD!$Y6*P z6%A-0wVVCOlYDCMuiYw91dneUN3Ux7j{H3BT|TyfE2ME8Y!;`mwn=an-RNLP{xwTuOmY49>TN3YB|0Mr^L{lsqGf^e8dI6x~Gf zX@|rY!Ceu1Lf&?9j50GEA`d{cT*|PCuK)pBYs4NbJ_kE501f5ReMIC1)-?B~Zqk@V zeNXG1gSEMt@3y^eYZcwyroy08rkgW~zipJ06~j94%&P0j3ro(=Y|2re%N)hKdL)eZ z#DNb% zzwS@kcQk1OH)hMndLFy_6$785qqMW+5fGwOa!Vfa4IXgWU^@NQp?pSH#EKxJ?ts}s zIahyWQr;^mFF!cVZeAOXsOU#hu~gSpjx{&# zcS+eTi)s}0gXdr6!=j0=8+*vV^PK&VoqJE+Sv27Rc8r(M162^B-x2lvWBX)YenngN|6;QAJE$M?MfZ^6FAOj#=koL+NN} zBQhmqj3|(d|EsY0Lh}XToK{!#M+@(~6XWd)nY-J}pNLvEw|`;KF||(2(|(g1BxOBd zk;PEV(i0Rf_sUv)Rerx6^G&S-FViMYo3|@ir5OSyPR0cs4LVe4|0SoJ!uy|QK*!Ur z)Au}I!Rt3g4GEm|cHkbY#SSEm9H1QFF|7}B%;oewagfJp^aQ~Ypf+nf+w$MDG+oTM z{aIOcH7;Pl_g7_UiQs4zgudU*AG;pP0bYfkIP@viU%g7BSn1!KeP;9Foa?c0^VwJK zo*j`?H7NUj#XD0xN@mQzqIa|K#A-06FLOPeBLD=_;M>LocFzGj8qMz5dBy zhZ3PQ;ixyqbXL^GY5dzpJY~uc?z+s8O8k1t-Y!A{vRO}r+6}C|yna4U3xoCLx!f>> zFDehORLW~4E1ooBf6Ww;tp!7$ZibsKin4MFPK&fyH?|g-O_)OiPzYyERAi`0Zc$-+ z?y|>#O$T}rIclb%*II|c&4Q~AX5Vt_;}JoOZ|b%)lE(+avJ9rjaj~_Xg7EBAv7KUMc@=$H1%h0;^rGIgwqdSB!hhTZ>!c&k%H&@q;vw|dNzymcj`=Pq>q9~!$satXAJc+$2q!*lvM#D!HQQet$U%{(mUg#y zIK4nIuy$8V5bLbnxYeU_MFscsg>qbCH$7f4e6=&Nv_1zuHLx^3!(W@8jUqGdg_Gm> zX#5;`gt~$TSsir&4Uc!vNhDR7yLSHmx6q;BEJY#bVy4A2L+zYrf#K6n5MT0NE4y8w zaGMtWN4;%M21n$7t2Y)L<;S_7^_Jca6b>l9qOUmktKRaXI{sa~4U_B5V4<9;RoM3j zy#!xopbTvaDHKTL4u(`QY2&2PYVBZ$8q-?9rCIjkXPWWy69`j%8tn9%LJwJ{|D zb}~9SgbJK-e@Ao5s|Mb)@De6tY$aJHFB#Q73m=M@Hl^0C^B5040;Q`mMhXj*5+_Ub zdD@wj!>3_#B$G}_i+tF-!mr({2AvF{Vbx}-6Qai1EkSIiPiDDfn-nid7*0G<00*nB zz8Py6i?Q9%NO;(@#;k8WF7U6M+4%?ac(HRx<@38hmf zp&km=_re)N|MXi5d@{7>d%d1#s(?l%;O#fSqgNX^nB;ZAZ|5aqA8`G3UaG?Gb+6~=c`0=X9Le*%qzK=NGCUh^#XhrtdtTZV zh4X-?M9OK~aWa3-&ENL!njN)9i`&=z<)crUDyu#O+B2>Nn3-2MBjT%Xb zFuO(F$Wm)&rl z7{9rpA^8fT0V z-FXqsq|tH)_unQEa5uA*1gpx9aigld7t+JIZeMOhl*aCY&S%??Vhb}52ADp?kFqQk zg%|0C2#*H|s6D7eWd~2lpEQ2)*159h_N3NoZ(D5PbL>J%%Y%1#r~)|Uq#o0u(KOnq zP0cviB^B4?!uA5Hn4YX)>$ zIa!+-v^K~~#kBaEDI^pInU4~ast4hGOTmFtuOopIsiikaEj49jB23_V&oD^5@rN(Q zZQJ3C(Fm!khLlKlX!WIt+t$n;n73UlD*eOH7vt{3SJEjeced0*53BUPCd0niuYTd5 zHYN}ggdvR=)(qyPoGdM2EepnwO1-v=$ETXF&cX>q?mmVa?Pl-7KJKwNyc|g??aEU# z%FR@+RDIF2Ww=D)Lap^H^9yP6cDYXqgpjJbr?T%N$2nj+9TUC87sq#*Pj3#XDr`3` zVA+LK)uo$R%hhMn?t8x~9DRC7cPCS&-|LrBW%RYdij4t-!Jb3>fGw{}@E_@sL|Fgq zRJD-=knixTQz;ALXykv)+#kC#odt(;JumI)Us?Nk9(s!pIQ*OQP*rSfY)EFK ztc{)7xAK64-MQgNfUWD&x@uCpd+m~HQ-o;@oVhEv^un1b{*~6JRTxjFG2o?STRyYy z9o8j29|kESho04Znao=A5OBUcCco&Uj!Yp4ZznNpK~KIPgMUmRX5=!wZhO2Onp+5m zHTAn5sX;Zvl}LxuZ2zf8!k*XX!yHOLW~Sp3WJ*2-h~uSUt%c+`Ha)z_fiPBzN^IW2i;^PWzgp-> z!@J=Ir&7|CL$w=<tr(+-|fyn zbegpR@>r}6`o^>?qTu2(@0+$BDN~!C_<+LC9r@q*No_$w z-VQGrG4uPnS_r_mZjO=O4Rb^-MsPp3TAF}njyX{2KVf?H*nvy&JuoLGCi~dy6WJw4 zbV*b-zK)kBT79eViES`W*{Mhfu)TYg_m31Pth9ftDJX}|+5fAil&%wKI1+!Heur1X zfs3rfr9A^a=zK zEm-C@+#%bQU0qj#+5+!$t4A)Z-|zAA4oM3yopT=Wf_JR3x$?@_o@~oG>paFceJ4uD z^rKUyWwRw}6VJNA(|=Vfg}C6hY%9;%f7n3T?`U|jEgLsjO8u2O2TN+NyA&;=jU zZo&tlHCY14ot_<)fgOR#3p*L5*mT(hrV5F86F4r#TOU~Afr6Cz{08=hEXiDAkicU< z-C$^qLB|L`j4Sos+#rWZ70WziXbHy+ZfO`u`#qt=L?G{wv&tkk>wP>0SvRwl@)^WM zb+G%%U%idR`@%+{w&1UY53Rb(+~TFF{sRLHlkvJkZ7r|GRV+C7&W=b)S1=glKGC_= zXUQ0~_kBlxwxVeP^EUO@dnCKWHI-&9|otGkmX zG&duAoEVqBq_8c3s*oz}Q2z<37#3jb4U-ox1PXAIp zTau}mqtr7jK3XlgZw-fZbP?;)Alt`w4|>Jo3;IwY<=OV0^7Bxl5}|=Zkru^}Eucfq zyu#|gtDacrVQ-q5aD|AZ;@3WhRzg;VFZ+&R=T}NKL}B%~T~$3O7U3Q|_6@SL3RfRA zeJFHLyHBhvdg;uyT=8UHBYxn`#EI5EY<*?m|7)dwBVS^ zN*kW}#OH13m)f$6D^=PPQpU#evK3K!IVKKrzBz%XskA%eM9+@rcV`|Usc`nFnRPx9 zc+jiR9iXUh!)0pSqvCl}OAAN65+G2QvlEBE{Ox8CoMPQS4TTlpt<%eI6Ob=RK=0z- z&nrkS3vb_%+Cy}ndXcD&y2^PBwtY4;%xV?nybukNGBkE70W`q_O3 zeIPajcAvpZvO~T&ns*!ZX&ryj9_#bBpL# zvRaeI-}NUZ1Y)I3D+YZEM@! zFK>MpElsK-f;MhR_m{?Rclb}w5vU&gTZQe(mz|35YX+xR$gZ593fnI@5@U#xMnJwx1jI}?yCVCst{9JK(6{I1KA>{y8rxj!9t zMzq0SH%?3}Zi}xNqLtjAbyIX+?f{hfKpAA&Vw=}*zegH?6>n-knUZ(Yg!aWVA zETFPwN;|y&gw$nrVqwr#gbVnVr@yfEvG;*CqMwkO-|&Awjq*2=tn)@xabF*|OrGXo zkJF?$q%fDLnql@);gt0XN`HSed)A1V2K?gPoos_ zW5*j8{$(14)J_cSJsY>71_z-^%oh(5&9d+%5AebHU*jWUkeZ`1qU>nv~wS`}mL@T~M|Eq~5mzs-IMy z)`g=%DgH^=^GfleRz#gWBn+KAGb^DYE|eZGXO_RKvn8o0RjMrYIib#$jz)_$VKZIT zz~2ss0&?>qv0XI%iiC8NTe0adOS*sY1$ zXN9Ap(*_(+6=#&R=D4@65$a2?iG82uPs=pTp z0X5t=1q{v*uqZDa2-yVha5z94sU*~_*J17Qi@wI98%Zigo%)@=2LC`fh;xI~t`CsD z)2!W{->$%`&5A>@>OwF&FJMRGsKDJ{2)3%Lnq+Q{J-2&5?f^Fqg>_PkA%VlZI8?Ix zt@m#cg58;nX*KF9h(4kLz+do1Uhz*3+hlIGV(P^YBIiUv^kzW8dlvqbB4Eq8bZ|iw zN1>Vg1IFeyfc((kaYJ;&AqbJpq!+PVJ=y^%ao6_o7)gTov7|nz&5N3=ujd6eGU&O0DHAPp!1UkXu=gEx^1R$IY1muf(q-958Qs5@N>M&sR=C3%YyAxB7pO5+GdQF z`3?a7;?e{*=W~Drl?&jyn-A#UIsz(O4xk{~<4|sr=ciq`@AhoEH;t7BphQjk!z@GY z2|zV0Vc-I48BsVu%~}m8nYa_Q&Lws<)bo;n8zTWS&q4`ruIIN;p&zpp3@iP{iFh z@J`SL_%mw)Wdlhn+&G_k&hW_o3no=pte6j*SkC#3jyEc}*SQL&l^3+k$BpwC|E=2W%G3Zup@8v&&gi=aLO65) zpyb8hyV7g;&K!`jZVDlQ>Z7Qh3x!N=iUBtOMHoNxr|i4$ur~_sHAG(!t(h@kxzi}h zg-L|eLKDNc36dCW_Lda+d+?ij6N5d8Vc#idNa|+CV09q_%Yf2FOB6Rnizl#x^%Or* zHr>SK$}RdUmT^C5aK7w!M8jCT@D&gLGJJE_4&$plk|H~1_(uBx=1@7loE3x*4m)9d zNRLwF(t%Kl3&y9UJ4MOdn~vWdpaSuwN~(qfokuV}`x{bZ|1umnehlLSW2Y(f-(H^< z^?jU!FS_)>@bz^c%(2>nlwB|S;sg%u(@hXgkqt9^)n$Y6w%C)hE4{OkR|(_2{Vw~i zvp_~g!$UWLmwlHH;JZJC@v2HoQQ&NB6xiy9Nw}LktY2?mC3={II`5*bpWdt`dMHZ- zpL2rVuv=~&W_`%PjGZg^nXHOpupYv8gpDtKSl9TUL1e> zez!!U?Tkkadu2hr1f5Ze;*RV_{*nfINQ2XpH0-W3uyISYaVs!6D|goH2A|mucgO6s zW*^fA`}aJK`GulP(q8GjaT6Mo?sZ-xGhbU3Nn`KV17zP}qaP;3oQ2QQ&ZPp^_&Z8jJ2*-9b zhk}b9Xb9tI0*b+~AK*{aq=cjLgED}D3WqYx0AeWw^kG>5MOVzRnkcxJk>SBn!I$2} zy-+6uP!L}#$qmqvn&7Ac1g^pE=>p+w;7@(k4+V^>SUV)TK^9zsIV~F0yX~C&>|MDH zO#$Qq*v6xL>%}WF6prP7S0su%)byS`{CsgB=V04$M(X{Nz2;!IP{mMG6$$xi*l4F0 zcZmQK@z(b-@E<+0t#Dz8AqXYIM^{hPKL_HX{9*OC4$&q(+K9LE&p0?q(R z>;Pbh2f4OnqDJd?Ff6G2(q0IL1Afb0IzKiP6uj{pS8ci>Vw%Etjm z1-TJC@Wp~q=0Xm_E_LecolyieN1m%_qRt+=V|XaR6;LZ*Ak$6V`7|MKF8zbiwIeuc zzZ-y`8V8PE6WM^y{dF8iotp*t$BM~xzkF{%-Cszip!!@-N0s|-e3;@J47xf$9L@IT z-fwedxay}eS2WIZypITsn7{eu^w7d4mYBB-w`3CEEp9SP8(qBRdy~YsmV{MWIv;uO zRp=%{<;3FJmx?#@jKbch*p@mX28GrYx)eh-j#bVtuL*n4eraZ9;$<3EEe2edG&9w69@H&IfqoikrjDY^s1!#5d*F@UR?MhP>O1fj%S%<2 zU0_M-;XjGx(W||4=NS3?vz%6pv6Nuv)X^H8e;Dn6{J zmwoY0b08ic#R4e2ie(EK9eE`n;B_VGG796!^J-2Sf?#PoNo6mMuucHz!mkS8VIPpD zU@Vp@-jUC6X2<^fRc<&i>&Pt&?2peD(^!(80*XSh+N%9KI!T&6T3G85Vlj0J=@Dl? z)=Ia%c)JVWjgL$QsIX#=G)_lOxiixA;3f}x;bwE>iG5;(+Yg3G*R8f=O&|&KA_eKP zWfgWW2~z4P&Zovlni^46iC#QRTGN`w8hrRrESi$y$o7}4G#Dt}GHdC`rU~wBO9qte zq;ux|SRGA@xH~R@zWI!`R&5n^dL-#g(_=EbPPhxQ>pCE?u6_P8<-jT9GoK~g2{X4S zNWm{YVpa4)iiKQ2;KxO*@@RCiVCn@&W?8U1Xj`$CcFTT-GbOv+39qhGki6oRu~H(S zr>B~9tl0u9l@|Sihf?)O{F$p#_X$P4c_NOCr+s&d5r}qsCY)T-PCm7nd~Ww@WkMp+ zBeP)dJ*!X0!_4Wh+MN0^<`i$$Jt7^hk5;KZ@_#D_(9Z$tx$R}DD*!WscNVLP-YG|F zbQRoxT(9bx(iYNNv8Jp|QSE?b^9Z29O##Z{V1VjV0pK(8V_$$M$$FKXD0A=bJv{pF z2VURwCjhVNha$s{4zYl8AK&g>3q!Zg0iTJU5+$uvme-!gyuEJ#M#F@@SIdVy(}9a_ z*(bo?v)~y#w&q;68lFS7N>Exyxj52AG(Vswgve0246sDWhBH_5n$aC{6pfjBz*}AW zlId;Pm)I|bo1b5aXH~4L2%FXyueHCnFx*=ef1O#TcD{yxm&x(I>td4?xdKA2eF@sH zrL`LPDCXR3JMd3!jlB0`)`Uk;r~IRQ%1M;lNA1H01Va6q`3{x5ajdv(s5jE0e0F-w zb~@yB*Gb=#4;9`B4l;dVI9;~bN>G}oycv-Frfnblq*Jl`?SPL|*iz<+qjqd3ZrJp7 z>{G1UJ;BTSKs(KEQvdUy!(;mVyj1^vR;I@?9|jIIUkNx6^TJ8U^s&#`$AK)*S*xY& zKRh{+8~6m@<*9N#d(b#DXkVU_=bc9CZ>!BE`$|WdkILlYs2fUnHjRwuw(kMdZLd_c zhX;%k3r;-xB&12{El=&%D$P_=Y`a8qScNd)qZ5MynSrm%LVcC6AlRWH_>1X;k9Te9 z5W=}*TC6OZC@d@-I)mLjrb?ipd8@jmAIB_EWANx35HyIJmfofon*(o~o(V~QlVJC} z$h&u>Fu-ioSRy@mKykvZtaL~JTv4#-VmV&A{zIMo2T=@*k)7!I_ za}y<*3mpW2(=eTNm6fVu%$R8H_IWThr<{j^%sj z^svxR?k%w_m|2>;s|1_!wpyj=WZ_(Qad5?QWqfQzku9k>MD25Vd~EF0+}z-07QWIV zE$j>rMUQ-Qq@%R(L^50AAn673oADMI?$CCJ+zPWwB2^N)VpU@ zTh&m!UNS%6Cb42(G_$+1kzrj6E7D#wrz26s7!eg&u-;l(qcO31=;@;G(3k*@Woi9U z0N93=rk*M{r-SM_)D{lZwv(twC#0!|V{^nPwuLvH3zJ4e%de()U7s|oGUd4_^tLnT zqtVi|vFIriX$szR$@{6Ww&$8(oy&2j-byS;_NLCk#<2#Tn+oxqI_24rN-KMY_V8O; z+Dp&RrP0aa>99$3ITzz{(&Lgdo=iQYmzbu{$)%qvpl>f>kS$}tRxrv|F=8tjb7~pe z8yTm17)&^rupLZOgUqsBbXZ&*g9A0I?K!M6MUE&6OCKvUcQ$EY)wd<)ob{5~t;KDc z^IyE8WcJPa?wL84Uhrh@3*9~uk^i20^S2oZ`P#(!YerIi2=FFY|Co^+FR(}1XCX6^ z9o>U(z5poZ0U_$g5S6`^@ln;GVBa?`ML)9Of6dp*kL+5gY!IE%T}h9S3V{AnOOwcT zq1$!+6MPkj4!Y~|w*!nK>rRjQ9G^<9x{13Mr5r6pct_j^ADEj!(M?^^L1O20NK^Ec_|PM-=>uN2SgAuD#iJgomLD&NpDq)`MF zJI|-ciXC1Pd~}W^7ll@`Ai|~hd<3$m5~OH#ST8~?m~k{rCf$ivVkKU9496orpL)+o z;*Zz!Waaw%vgq%OhS>%kO~Oz{k#%}g1Kn^WF!bw=5{9|T;XQy7REajRTi?To)EZd= zEcJJ(D{XwHI&87h55`qf}4ryu3{FwI;gp9F3iIsR1V%*}f82HS)7> z^z1QbQrXkKD^S8z4JMO9mj=VY3y+q3%i&Qe7s~7GMC%C{bWX?TWJU~ z8{@AUDL)8!nt#sGjtA{VSw1G$NY5qCFTpsL_fu5Vw1go{EV!wzdhyp=TDYl(9%R{kdAb@|BHRFVFz)$;c#ywHonvq0%JMtj%CoKg zhBIF+KI4$Uo#~67LiKDTUbnNG14B30PtPV?MmT!X@y}G_w-|MvXSckVPEoSmXr?9S z2FJ+KtC8XfQLI5rLO|?y3QBxqrP4FT)NPL$zIvWiy8e~%n_BVsN~>Z)>N`*A)ba5K zgEnu%ZM|ovH`Y}wITOWcXHYf z%I16DidSGq#_?P0!BxL;^gTp zZ8+7%kw@V68OFHHjh4sR%`b{jl!zPoXFcZFg$xgi{Xc-#*wHZJ;16$T|ZLJk%-iZOQfl~V;C4!t(5N5^`RPV%ysQ61QuR`^*PQ~;%Y=X-550RIwA`dSx==)6Yua&-gYa^Wwg%Ol(y zZkwN59HchLTO8HlhSVc^*ua!&3&|;vrNjkpQjfY%9@O$mBe|fgQSS47bxhk-*W1K~9Q) z*0mT8;uL6UN-58lt`}z`!a>Cr&gW9ixJ@)A0msM0Ur>dO4FB+_&(?eJeibve*pA2a*u3PkdiMfKNRyJG`E%Sg%$i}MY zo9Utb&nbrWrFs=xk2%?zEAW@Syu<{F7ddFH!!Sk%@BSQ$6FmBNC3o8UfaaJzF`_ti!FEFh8gF=&sC?N#f{&QwVK4^pwuvB^@rE|vgDSRg3P`wqHE z4ek+O2kP9=MycFcTNxr~{kHY{RWH9ME+Lu(1v^Bqc>hbezfPs=|0Xi}FaHp8M& z5~%2%52$>DRT|hN&XQRDd-mq*G|ohwuJJ$>HR&IO6sblZ{R1=b#Hpkq-%94Mwa+&X z&M&MXgp|J~*DB2st`1gW5)x7{R4^^akpiiR^GHRsFpvI0*WJfjj@kwm@` z6dtHrXGUpup1q^zr|ZsJcaDJU0v=`Z)$WAasJpt2a)85a;Eb^TGga-4xyQB)s4Ad& zyL?EZ8GzeTO}fjbGA$f`QW#S`MWve$hvg|h_0K_VFRtg;_tVO;UR7^r4JbCp1Q6G? z%oWtQbjv^T=IL8-Ch{0*J$(e2J2`JEnsi-IVB2fWIjFO*Byd#^;y6u&XaQ?#BK`mF z(zMO6-PVV=PI2YxSivLZw z_;;VaX*6MIvdD9+$SI`Pk-$R>FBJs?yWM=43g`WbNYMAU#={d=|90m0H1jJcHPLQ&@(5n=^2>YaH;Z9S*Mvg*w{=)V}SMrRmuP1sR75$zjp!6bQn~3 z>_-;E{wgFfMw0%sE}$y5I&|7B{+r!R zn7bAL9HE7GSDSaifVYw+^+;k-*}%ktpgIrq)cu)Fx#hV2)sH7m-F$vKxPZ*Q+0=hP z-+FpM?ci;X)R&WU%X4=cd41o_LwbdC($MGp(#jl$MaXKFM9*llVpyo41DJ6Rxn2$< z7?Z-ROio3{nm8hgxduywr$*vmAK8h1XdBK)>BZ7Oufxp(5;^Z;#pwvpU0G*=yiL$} z3}AP=aYn$1Z6yWppM?&LYtQz`R{p31C#mMRj1%GoO!7v55IK=LVDvQUHl7(De`##_ zmws^73%Y##b@>S@n)YOO`Uws?J{hg{ZW#AVc&Z7ucX9@?zzwZD3{9}kR)f^F=3sO; zmz18BwX~R#RZp6!g=Mt}dh2lYqyL_j^|xCkvaG0Jj6z5CY@q+?*Lfd}`kc=EvLP=gr~Y_JW7ChlCa|Yv6V`^eWlK z-?%Ue;SxnZPXYow8?viMAc;cVL;QO4Z|~D3qhtJb1^rVekR5((UagRrK}MNzxc%aljYhy*ie=oy^_>UKs4UZ9I~0T1ih1_DGHqT%;mA_WsG z)?m?}4r9UM?ukh-iU8=e4msFwobqXnkmDs`@%I{Nm9nybY21}nA=Lx{ByrP`bHdj^@ zf{I2iH6sSVT9XEWtpBsyBa$Fwp7pB+;D(C5@#lGPl<0yIyzsLIJmj;vGldGnp%{p1 zYzl;FC~RneW^YHBk$jjIr2nHD;D{nT{4%mU3018rPLq}@2~bJ@+9z0`;`w~g^EbW= z4rgy9-X}ncjq0Yqk$KrI6_Q-D`@bxNzR{pbtsR}k?qyf=c-RVu7Gdkquh!0sUsHE> zhIFH4O_t9Y;qZ&rkphNmuqxhtaQE&B5@ucb_f0KJlby^gZPJ{$;3UG^)y^Dy1w~&pRr)`x1lnj=jTe9Qg!6iU z?cC3E;V7gRF~|Pw35RzAMq8;{^}cy3gCsO`;G2oJ${^>$YD7isl-|mgN+$o{DnI-G zM1Peib(lFj0K>uc*C=EP{yu_ie+wM56mcmgQ}@lCLHu@JS|aSEzYe>xog`Siyq?%JG-6&cReaw#Ta)7E$l!x%RfnY`P(f4iVje$3BRf#S{tx7{5l~p ztSIWJpVffq2)LP$YA_R;oT7lvK$*)>4Hee;eZIiD&KNc?}VJQC$!cQ9C|xp!b{e)qXn;C#|^Jk85~6v95TT7;<+uf@TxGK z1&Nv;-U3a4rlZ`_$exg%bNT)U;LOu`BULJ^#T=UaV0I%*VX91;>T3T3?fKuT0tN^E{(b;B zAd>v^v`DHap;p#^o)%?JIG*@scv`p@H9Jg9Q9ysPc4ZVv|5+8c zYvreT53jLmL?S+ShMr!7K*;ZZeRJ%~=~9w!$e-^>qKn~6$mGz-Y#oQY4WIWOWv{=4 zxE(d(XQ_JsWhv|+naMHB=H_M=n>X=ggP?%M;3H)|e??U$L*HH%!z>4-RClR2@Ovn%G-z#ol}$0_@UA;EfWFQPcy{ z?{1tGZgCAG*gZM2Z1$6ih)|oy-zl}`Id(zq@Mq_pm;hRojCQ`)P6KVR8U2Gb3NbME zhcyn3Pgcm5H}2|Tq+S9PLVB<&)U4lYicmRNcXK5kveyoB@^G-@^!D6ur&w{4S_k|2 z{L}RR-F=ceN)wO*e|3vfYEb?A^X%}*>jMj6Kf8rPHi03g7U>p_QtflgVIau>M>m3` z!YClLOk}7la zyou;_0+x{$AGw`(GrUxKF~DOZnx6n2Eusun?L^5c9qc&bXkqA^1k?f#7DSA1SeNL< zCpgAv#W}1E>?Y;3tq-EB(S z4=mgFrqu?qR;LX@2yeT4sEd8tYN81dFMngsN)GP=O$fi$7kS9#By? z74ow}_DkXz6yd8AsgSN<=m>o0M|}Bt3I#28!b!-%(zW3_fLqaH(KIB3v6cG^>!Hp? zU(Fq%ul&dS@sCWP6Z;>mxk_DB8hOS$fo#008X9NhFDBZ-iKMdNb33Kfwy{9v!A%d% zvOC9vLe;{*&mRZU$`ifc&4#F{%Y65h4@n!%>4z;rZf0dHIjwv7iU`JwW0jI1s|yJk z$tLX8#j;-T*@4XxW2i__-Oi}pjwr{Oy%brYK@-}YSn$X#^sluu(thVh`JU|ji;GFW zBg0*={(Od?Py<_c%%%(iOs3u@#~3HpXn7Q7Z_|fe-`wQy_Gr(Abczz_E6=D9;1)ZF zl5KvL-zxX0r5&bJ)9<|HK^{)fP4cR<6eH}hTvXUfqg)q$Q_HTzv>)8ei=K|Js=O($77NybZr_gFNSgbzZXDFOPv5@jJl3_Cy5?A!))+gZstz3o_-f~= z!W^m@x|pbdC8tgCQ4B9W1*$ly4|$XfeF+JDzVTB1&OCgx|E=x8^@n8>pMNrYl1#SE zAUiN5JH!Nnk(rlMgtd}kPC!)-tQ!qdCC_lTU|BpJvJH4$8DjoOHC4$#fjr{o-rWLGSA>kn3YcE58RI3F6H- zIO%xTfo#(|6s&fLcP73I8B}7bp7SjvI}W%QJWRVJKL;7hE2Q6Qf-AbscD-EjOm+<8 zQjCCSIG*5V6J_Ow=QzAKcsU9NC!$)*E z>1h>yuZtutL=ES~9tREDQguMPxZ>-Rx>TR(57%o_{DRauB&_L1$c%2F2w zH1C#vRu*KB1*`P_tgJKwgH6hyN6{6^I|oQ1*+LzpyR6=6}-^`UD?=Y2_*6 zW%2j7_YzxY36DHP`mH0iqe^1G%!l4mANrMBH~4veIb2x%S~GL*!dm$4rTsSMH}FCkJiZ2EfLc=laQRz=cyU*%d;GX`?g?jP?fc#${$MI*ZoS~|?F@>4vnl28Zj zaExE+k;!`6#s;m6bHmG`O6=U5$|7Q6qQ)UuH~F@(=Bc8dlaP&Kg84FFsf9WXm_YIW zRd(h7Q15U1GZ|Y3!;BgGa*!j-%veH3_GK~-V<$@@lBI+YN+&HswiJar52X&Wc9gv_ zL$YrPWiOQ>LK5nEk4_!u`+8oF*Y^+j{B*tV`*Yp*ecjg$OG+SeyAEKu&w5;9XeN3% z>;c>2)whRvxSg)qUG#NMAZE%s?`h8uFu>Fn9~}2*2c>^qH*-SRW3jRI6Cb+BE+S6F z1OB1aIv08mgO2*jfq*esdHm>HSasdMna_!9jt`Smi#lhPBE{+k!pcWy-}8>}tOPT= zsZn)xj}AGZa%2&Evk(`d&gyFZ}sQByCKQaw-UNwM-I49jN&d#M2 zCveai_Y@ak+URWdR>#3V2@BVsx0T|oMf!_?$~i%Or(wYO<>t&l{sv7Ru4k(#aQ!g# z4~Xy3ihwa+l-FJ36p&Y%_}aYVF2G`7;>{FVnAB6V@H}~FM@GJ6ORCI`yGS?$>D8u& z6#dfjzURfmqOzKD9GNrX-cbl8TCYe}Ikf(y9dzUyH#sx=*-135G(hxkF8mP9Wv3s5 zigYsk3)!Y++-;S1)z7dZQHVq-4)SiU4#`&E-y4z}Yd~0L)u!~OD-ofcZQ%t#;3Mlq zVpELvbg)kk@c(u%D8Su$AhdefWk7xTyxWT;*p=qYQY3gFF`_)s_V0sDdRs;VM)9ym zBmcY)@CLY8FaP-O^a&%NSc9L8rf~C6+7CuUxd#}HvPO0G$7QyNng&6ko6&XPp)3d% zn!&`AfS7PqG{^i`P-i!=EPOqtoz;0H1n_E>pNz%@>Upy?`0Cn#Z$-OT$e_;i6{$Su&%yPp1s(U6MnF0Mwq;oQ@{cU(d5om{@Q zURMt~D`5VT4CXJ$Sv4-0J`w@6U&&--|7^o?$gBr2VN$BFoJ@;K z$Q{{dCyt5(173Kkf_Z9TO%b@c%T$Ij?yI)7{(&%r;6yH5yK3yz^`hG_FQ?yBji!lr zOfv7*C@;QZ)v>zlI~4(;iL3f$vy1>?-3}`liLz99%)Ezp_0L|Lkai_Y8}wR@a|Qhl z(0&P681?d55Ky*up>`f*u32?ZJ_{sCu= z*pQEy#xOl?M1Paq{Ry-o-bPdmt7dvL`(imKdT|a(FX=lDwmK+d*F*NJJN-PZ7*hMo(<)72+fQ%_d7QFNYg7DiE zT8JyiCR7A-dGzR{sS3hV?AO+NFi=zjuZUa(7aO%DRhpk(S^_TwhcH=;q56-E$GFO( z>SGFR{7WsW6^E;_>g00&ZVg>{JjRUNTR5)Wz+!_@>*$Tz*w;$+!|bv`(YbW1N)luZ zyRWK?4s_ev@sYYKau50t{94uM%<5S5ir)4pgXYF|D5EdyZAEz~0J3>kQDqD~9q#w? z%OiJ?WSt5e6)+;QSHyt|Pzj@O_}Z{{WwUSqo`rHhsM0METR;<gJR_2PugC>{vqy zKjLa~Nt+>h{TVN6Uxe<7__f`wJlaQw_V+N#ar+Se9l=&_)0p-=L+HMnB zwYQWdZ(O^>CjO&RDQaqwXlct*#HL??{$|*v-OF=p|FN##hO&aR@FR0@K!gI5uMQ z<;7JUH(j6WuUb<{(O*a1fiKm-`e|Lu>CrFix-(!erh;ttb}znl3RD_#W*w?A$S4uk z;*!E&vkico9cN?m&=<8tNw_`_bwP%lLx5nAp3#D$4%R4dfe4vU`~$E}ZwaTyn}gb- zMa?)O3Wv;s);**R6IkF>a5%)8Uf&a6*cro(fXV9uweP$z!?qfPZ(pNQ4C@-&ot%d5 zS8Gos7|_uu{{ccr(jRa-QuXTc-p*r!&*_$nuUWOauGmU(bXHif8>{!}@B-(cM9DVu zH!pWWKwSmg!M4X2C@r^(UXTU0MDGIP0wmS7^dm=KmPNu$a)0J%Af!OBvHr-><&MyR z-^(948koak6aU{Fy-2Sq|G#o{(|_b>vZy;Mx_RuQrpp5#x$JA!6Mb2AXEZjupH*Ha zxN7E2%YC}+*U7=aa%#j93!JJ)m^nJXerA5{BgoOs!|Pugc<-0dZx)H5&*EnooA`nS z_f34ew&1(2!>jiLU*W?>#e$r-? zgft#}f(X|yB!6>EQv+@-qzeMh=SuY|6*U752jPv%KtTg?w72x%Ia-_524maC%+b&C zg0VW5sESeDy4+!`zGa0H%z%na*f8$u^IS9PR@0F+wZ7u<7yafup2^z8t~6|qG4j`K zS({|n!L1nYN`qwiul~fCeh}td^b_MlrFsZ&^&c3wdVOd03Lu6T!ej7QhU}%UXCR1x zB$GvilA67O9uqIv$fmb}|FC~3K1A2PBrFh>rm<(5#!hItoc5-;#!Y`*C5~)5U%cjjlrwsud<3Xwbk(^G`ZvXsd0=W?f`j;&@A%9Xj=n)Xx zH7aCt`JLL!V_)s!q;}O6YeuQKBi@yT zAT{q`PCdms#_EV_2gpMCK&a25OAdnfRI+rA$^67ctjpMe05qj2H0ydhT z;PBu&?Hw7AcR?YKs5L;I3S|THE#S7>+9zz8Hcyk~HR2oxd&hj>09zx$XrCK426oDg zwg4_xOEyL1fMwxWU$Lg3_u`;Rho2QUww6(j$TGN zA4#}eaE0mAX=e$5@50K)H}@>nTZmAV!rkx&y#zF(A>SC>64$p<L|G z9$l>Y?f(YdCKLzM=+Sf3w#v>v-#$-uaBOG4TdggKUV9`<(Bs49FO=-HT~mjN!CEmq zVLDZVVbyK{^F9TA(5FbZVr&U>*hHO>>>}H12qgj4!Jy&=OC^w_Rg$7if>p1#A5nAK z*mco7xA$nMaP7WIyQHd@%QrRvx(~ib@4M}K$xngcTO!ui0!** zBTva+u6A{sHm@Fjro14o{Ox+}^!%v^fNnwe8*m><@S9Kh=*sHpeP@bP%aLI!49!nE zB~}WYEG53(mkvQl7jCdGlYl%ASTrb;kTjWd1|?pbzIrulk>Ocosk zSahBoaA7d%zG^INYBt^%3h}K+ikqbj;Tv!aM7%g)(L5XVN*?na&s1UyzwR%JIxE?# z!YIa>Loh0hd;+lOb`%TJ&m!2iQ^P`eJcDLb9yP1k$!jab)`0>YU6r(#E5yzvC61{s zTUG%>i{?mVIFmrfNbtsNkE>AI*nfp6EDPU@iZPn64s9bP6FheJT9T&i_`o5eNXY#AT2oJXivgGF|NKy~_q!Yu^wY;NY64(am>unkc zJ^H{w^(vF^!~oCQm^|4Zt~yPVuq_z7??^Lfn(#Fk#T2eRO#7A#zUNW>N*|YmIiMp zv@I%j1GixRUXAv&*jFH6vu3p{QH6`zoi>bBWwRwjygmsHWHDVK7Tm@Zv@4fn58sBg zlr`9cBH5sU;Gp>`Bh=CqtSwmerL$U4`W9XW*){ch9Rp_=qYs0QT0)RuQz&pOYqA55 z(k}!y&SPJsgeGFZ*|apzL3>*pAKIr_$`Rn}3XV2n3T^m|uFXC^Mhj!DJ^m8hE#i&A z8uuez!z>2FUJWD;M~q;NG=u8FlIjlNn6}us?J`KV`~E*)VM?)5PNH>r6M-v?q@fu$lUqSy&c*p^l*J zhE*CnOfU26`P*-Auq8t8IKD-#F@gH~-HW;kt(f5X=0=gPAX%o|G~U zC^wcf{6*l@fCGVpl`*i-r>S%Pdl=L}hB6QgewpE_n-}@UT7Nu?=N|Qal&%16A^94B3ieTP3q zcLspl0;AC*pT+v*I7;dy5+_#0<$ zpI^Tv(Y_EZf$LpdFJ^UoM9{o!?Y-8(Uu^cUef{rB4aW(nak_Tvmr*>SF zG7Wr5ldz#?0OAjt`bGSRm|@<@D`Z98OBA+Wj5rdJ6GY=UJ}HSj7B1AGSj)?ly}OMC z3(yl4PM3WJqy-%xV<(n8;!CgKP0Z**o<=^2Bs?|m(V)m=NKj&Fho-67YcWq+SQ2Gu zpJ~RL_~g>rWPTpqr%tR=c`_GMtaq81#fkkg6_uFE{~L+qBrQ9Ymyz1z{Tt~qO88KX fZ5;9wmins#Y_#=#Brjp4s?zM8=y0m;6#Rby9^6PF literal 0 HcmV?d00001 diff --git a/extra/gpu/demos/bunny/sobel.f.glsl b/extra/gpu/demos/bunny/sobel.f.glsl new file mode 100644 index 0000000000..16d2e408f2 --- /dev/null +++ b/extra/gpu/demos/bunny/sobel.f.glsl @@ -0,0 +1,45 @@ +#version 110 + +uniform sampler2D color_texture, normal_texture, depth_texture; +uniform vec4 line_color; + +varying vec2 texcoord; + +const float sample_step = 1.0/512.0; +const float depth_weight = 8.0; + +float +border_factor(vec2 texcoord) +{ + float depth_samples[8]; + + depth_samples[0] = texture2D(depth_texture, texcoord + vec2(-sample_step, -sample_step)).x; + depth_samples[1] = texture2D(depth_texture, texcoord + vec2( 0, -sample_step)).x; + depth_samples[2] = texture2D(depth_texture, texcoord + vec2( sample_step, -sample_step)).x; + + depth_samples[3] = texture2D(depth_texture, texcoord + vec2(-sample_step, 0 )).x; + + depth_samples[4] = texture2D(depth_texture, texcoord + vec2( sample_step, 0 )).x; + + depth_samples[5] = texture2D(depth_texture, texcoord + vec2(-sample_step, sample_step)).x; + depth_samples[6] = texture2D(depth_texture, texcoord + vec2( 0, sample_step)).x; + depth_samples[7] = texture2D(depth_texture, texcoord + vec2( sample_step, sample_step)).x; + + float horizontal = 1.0 * depth_samples[0] + 2.0 * depth_samples[3] + 1.0 * depth_samples[5] + - 1.0 * depth_samples[2] - 2.0 * depth_samples[4] - 1.0 * depth_samples[7]; + + float vertical = 1.0 * depth_samples[0] + 2.0 * depth_samples[1] + 1.0 * depth_samples[2] + - 1.0 * depth_samples[5] - 2.0 * depth_samples[6] - 1.0 * depth_samples[7]; + + return depth_weight * sqrt(horizontal*horizontal + vertical*vertical); +} + +void +main() +{ + gl_FragColor = /*vec4(border_factor(texcoord));*/ mix( + texture2D(color_texture, texcoord), + line_color, + border_factor(texcoord) + ); +} diff --git a/extra/gpu/demos/bunny/summary.txt b/extra/gpu/demos/bunny/summary.txt new file mode 100644 index 0000000000..5a423b70f6 --- /dev/null +++ b/extra/gpu/demos/bunny/summary.txt @@ -0,0 +1 @@ +Stanford Bunny with shader effects diff --git a/extra/gpu/demos/bunny/window.v.glsl b/extra/gpu/demos/bunny/window.v.glsl new file mode 100644 index 0000000000..7e678136ac --- /dev/null +++ b/extra/gpu/demos/bunny/window.v.glsl @@ -0,0 +1,14 @@ +#version 110 + +uniform vec2 texcoord_scale; + +attribute vec2 vertex; + +varying vec2 texcoord; + +void +main() +{ + texcoord = (vertex * texcoord_scale) * vec2(0.5) + vec2(0.5); + gl_Position = vec4(vertex, 0.0, 1.0); +} diff --git a/extra/gpu/demos/raytrace/authors.txt b/extra/gpu/demos/raytrace/authors.txt new file mode 100644 index 0000000000..f13c9c1e77 --- /dev/null +++ b/extra/gpu/demos/raytrace/authors.txt @@ -0,0 +1 @@ +Joe Groff diff --git a/extra/gpu/demos/raytrace/raytrace.f.glsl b/extra/gpu/demos/raytrace/raytrace.f.glsl new file mode 100644 index 0000000000..02c460790e --- /dev/null +++ b/extra/gpu/demos/raytrace/raytrace.f.glsl @@ -0,0 +1,153 @@ +#version 110 + +struct sphere +{ + vec3 center; + float radius; + vec4 color; +}; + +uniform sphere spheres[4]; +uniform float floor_height; +uniform vec4 floor_color[2]; +uniform vec4 background_color; +uniform vec3 light_direction; + +varying vec3 ray_origin, ray_direction; + +const float FAR_AWAY = 1.0e20; +const vec4 reflection_color = vec4(1.0, 0.0, 1.0, 0.0); + +float sphere_intersect(sphere s, vec3 ro, vec3 rd) +{ + vec3 dist = (ro - s.center); + + float b = dot(dist, normalize(rd)); + float c = dot(dist, dist) - s.radius*s.radius; + float d = b * b - c; + + return d > 0.0 ? -b - sqrt(d) : FAR_AWAY; +} + +float floor_intersect(float height, vec3 ro, vec3 rd) +{ + return (height - ro.y) / rd.y; +} + +void +cast_ray(vec3 ro, vec3 rd, out sphere intersect_sphere, out bool intersect_floor, out float intersect_distance) +{ + intersect_floor = false; + intersect_distance = FAR_AWAY; + + for (int i = 0; i < 4; ++i) { + float d = sphere_intersect(spheres[i], ro, rd); + + if (d > 0.0 && d < intersect_distance) { + intersect_distance = d; + intersect_sphere = spheres[i]; + } + } + + if (intersect_distance >= FAR_AWAY) { + intersect_distance = floor_intersect(floor_height, ro, rd); + if (intersect_distance < 0.0) + intersect_distance = FAR_AWAY; + intersect_floor = intersect_distance < FAR_AWAY; + } +} + +vec4 render_floor(vec3 at, float distance, bool shadowed) +{ + vec3 at2 = 0.125 * at; + + float dropoff = exp(-0.005 * abs(distance)) * 0.8 + 0.2; + float fade = 0.5 * dropoff + 0.5; + + vec4 color = fract((floor(at2.x) + floor(at2.z)) * 0.5) == 0.0 + ? mix(floor_color[1], floor_color[0], fade) + : mix(floor_color[0], floor_color[1], fade); + + float light = shadowed ? 0.2 : dropoff; + + return color * light * dot(vec3(0.0, 1.0, 0.0), -light_direction); +} + +vec4 sphere_color(vec4 color, vec3 normal, vec3 eye_ray, bool shadowed) +{ + float light = shadowed + ? 0.2 + : max(dot(normal, -light_direction), 0.0) * 0.8 + 0.2; + + float spec = shadowed + ? 0.0 + : 0.3 * pow(max(dot(reflect(-light_direction, normal), eye_ray), 0.0), 100.0); + + return color * light + vec4(spec); +} + +bool reflection_p(vec4 color) +{ + vec4 difference = color - reflection_color; + return dot(difference, difference) == 0.0; +} + +vec4 render_sphere(sphere s, vec3 at, vec3 eye_ray, bool shadowed) +{ + vec3 normal = normalize(at - s.center); + + vec4 color; + + if (reflection_p(s.color)) { + sphere reflect_sphere; + bool reflect_floor; + float reflect_distance; + vec3 reflect_direction = reflect(eye_ray, normal); + + cast_ray(at, reflect_direction, reflect_sphere, reflect_floor, reflect_distance); + + vec3 reflect_at = at + reflect_direction * reflect_distance; + if (reflect_floor) + color = render_floor(reflect_at, reflect_distance, false); + else if (reflect_distance < FAR_AWAY) { + vec3 reflect_normal = normalize(reflect_at - reflect_sphere.center); + + color = sphere_color(reflect_sphere.color, reflect_normal, reflect_direction, false); + } else { + color = background_color; + } + } else + color = s.color; + + return sphere_color(color, normal, eye_ray, shadowed); +} + +void +main() +{ + vec3 ray_direction_normalized = normalize(ray_direction); + + sphere intersect_sphere; + bool intersect_floor; + float intersect_distance; + + cast_ray(ray_origin, ray_direction_normalized, intersect_sphere, intersect_floor, intersect_distance); + + vec3 at = ray_origin + ray_direction_normalized * intersect_distance; + + sphere shadow_sphere; + bool shadow_floor; + float shadow_distance; + + cast_ray(at - 0.0001 * light_direction, -light_direction, shadow_sphere, shadow_floor, shadow_distance); + + bool shadowed = shadow_distance < FAR_AWAY; + + if (intersect_floor) + gl_FragColor = render_floor(at, intersect_distance, shadowed); + else if (intersect_distance < FAR_AWAY) + gl_FragColor = render_sphere(intersect_sphere, at, ray_direction_normalized, shadowed); + else + gl_FragColor = background_color; +} + diff --git a/extra/gpu/demos/raytrace/raytrace.factor b/extra/gpu/demos/raytrace/raytrace.factor new file mode 100644 index 0000000000..df323d3c82 --- /dev/null +++ b/extra/gpu/demos/raytrace/raytrace.factor @@ -0,0 +1,125 @@ +! (c)2009 Joe Groff bsd license +USING: accessors arrays game-loop game-worlds generalizations +gpu gpu.render gpu.shaders gpu.util gpu.util.wasd kernel +literals math math.matrices math.order math.vectors +method-chains sequences ui ui.gadgets ui.gadgets.worlds +ui.pixel-formats ; +IN: gpu.demos.raytrace + +GLSL-SHADER-FILE: raytrace-vertex-shader vertex-shader "raytrace.v.glsl" +GLSL-SHADER-FILE: raytrace-fragment-shader fragment-shader "raytrace.f.glsl" +GLSL-PROGRAM: raytrace-program + raytrace-vertex-shader raytrace-fragment-shader ; + +UNIFORM-TUPLE: raytrace-uniforms + { "mv_inv_matrix" float-uniform { 4 4 } } + { "fov" float-uniform 2 } + + { "spheres[0].center" float-uniform 3 } + { "spheres[0].radius" float-uniform 1 } + { "spheres[0].color" float-uniform 4 } + + { "spheres[1].center" float-uniform 3 } + { "spheres[1].radius" float-uniform 1 } + { "spheres[1].color" float-uniform 4 } + + { "spheres[2].center" float-uniform 3 } + { "spheres[2].radius" float-uniform 1 } + { "spheres[2].color" float-uniform 4 } + + { "spheres[3].center" float-uniform 3 } + { "spheres[3].radius" float-uniform 1 } + { "spheres[3].color" float-uniform 4 } + + { "floor_height" float-uniform 1 } + { "floor_color[0]" float-uniform 4 } + { "floor_color[1]" float-uniform 4 } + { "background_color" float-uniform 4 } + { "light_direction" float-uniform 3 } ; + +CONSTANT: reflection-color { 1.0 0.0 1.0 0.0 } + +TUPLE: sphere + { axis array } + { home array } + { dtheta float } + { radius float } + { color array } + { theta float initial: 0.0 } ; + +TUPLE: raytrace-world < wasd-world + fov + spheres + vertex-array ; + +: tick-sphere ( sphere -- ) + dup dtheta>> [ + ] curry change-theta drop ; + +: sphere-center ( sphere -- center ) + [ [ axis>> ] [ theta>> ] bi rotation-matrix4 ] + [ home>> ] bi m.v ; + +: ( world -- uniforms ) + [ wasd-mv-inv-matrix ] + [ fov>> ] + [ + spheres>> + [ [ sphere-center ] [ radius>> ] [ color>> ] tri 3array ] map + first4 [ first3 ] 4 napply + ] tri + -30.0 ! floor_height + { 1.0 0.0 0.0 1.0 } ! floor_color[0] + { 1.0 1.0 1.0 1.0 } ! floor_color[1] + { 0.15 0.15 1.0 1.0 } ! background_color + { 0.0 -1.0 -0.1 } ! light_direction + raytrace-uniforms boa ; + +CONSTANT: initial-spheres { + T{ sphere f { 0.0 1.0 0.0 } { 0.0 0.0 0.0 } 0.0 4.0 $ reflection-color } + T{ sphere f { 0.0 1.0 0.0 } { 7.0 0.0 0.0 } 0.02 1.0 { 1.0 0.0 0.0 1.0 } } + T{ sphere f { 0.0 0.0 -1.0 } { -9.0 0.0 0.0 } 0.03 1.0 { 0.0 1.0 0.0 1.0 } } + T{ sphere f { 1.0 0.0 0.0 } { 0.0 5.0 0.0 } 0.025 1.0 { 1.0 1.0 0.0 1.0 } } +} + +BEFORE: raytrace-world begin-world + init-gpu + { -2.0 6.25 10.0 } 0.19 0.55 set-wasd-view + initial-spheres [ clone ] map >>spheres + raytrace-program >>vertex-array + drop ; + +CONSTANT: fov 0.7 + +AFTER: raytrace-world resize-world + dup dim>> dup first2 min >float v/n fov v*n >>fov drop ; + +AFTER: raytrace-world tick* + spheres>> [ tick-sphere ] each ; + +M: raytrace-world draw-world* + render-set new + triangle-strip-mode >>primitive-mode + T{ index-range f 0 4 } >>indexes + swap + [ >>uniforms ] + [ vertex-array>> >>vertex-array ] bi + render ; + +M: raytrace-world pref-dim* drop { 1024 768 } ; +M: raytrace-world tick-length drop 1000 30 /i ; +M: raytrace-world wasd-movement-speed drop 1/4. ; + +: raytrace-window ( -- ) + [ + f T{ world-attributes + { world-class raytrace-world } + { title "Raytracing" } + { pixel-format-attributes { + windowed + double-buffered + } } + { grab-input? t } + } open-window + ] with-ui ; + +MAIN: raytrace-window diff --git a/extra/gpu/demos/raytrace/raytrace.v.glsl b/extra/gpu/demos/raytrace/raytrace.v.glsl new file mode 100644 index 0000000000..88187c8777 --- /dev/null +++ b/extra/gpu/demos/raytrace/raytrace.v.glsl @@ -0,0 +1,17 @@ +#version 110 + +uniform mat4 mv_inv_matrix; +uniform vec2 fov; + +attribute vec2 vertex; + +varying vec3 ray_origin, ray_direction; + +void +main() +{ + gl_Position = vec4(vertex, 0.0, 1.0); + ray_direction = (mv_inv_matrix * vec4(fov * vertex, -1.0, 0.0)).xyz; + ray_origin = (mv_inv_matrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz; +} + diff --git a/extra/gpu/demos/raytrace/summary.txt b/extra/gpu/demos/raytrace/summary.txt new file mode 100644 index 0000000000..91f95341e6 --- /dev/null +++ b/extra/gpu/demos/raytrace/summary.txt @@ -0,0 +1 @@ +Real-time GPU-accelerated raytracing of reflective spheres diff --git a/extra/gpu/demos/summary.txt b/extra/gpu/demos/summary.txt new file mode 100644 index 0000000000..0800fbe3ec --- /dev/null +++ b/extra/gpu/demos/summary.txt @@ -0,0 +1 @@ +Runnable demonstrations of the gpu library diff --git a/extra/gpu/framebuffers/authors.txt b/extra/gpu/framebuffers/authors.txt new file mode 100644 index 0000000000..f13c9c1e77 --- /dev/null +++ b/extra/gpu/framebuffers/authors.txt @@ -0,0 +1 @@ +Joe Groff diff --git a/extra/gpu/framebuffers/framebuffers-docs.factor b/extra/gpu/framebuffers/framebuffers-docs.factor new file mode 100755 index 0000000000..4f35fcc91f --- /dev/null +++ b/extra/gpu/framebuffers/framebuffers-docs.factor @@ -0,0 +1,316 @@ +! (c)2009 Joe Groff bsd license +USING: alien byte-arrays gpu.buffers gpu.textures help.markup +help.syntax images kernel math math.rectangles sequences ; +IN: gpu.framebuffers + +HELP: +{ $values + { "index" integer } + { "color-attachment" color-attachment } +} +{ $description "Constructs an " { $link attachment-ref } " referencing the " { $snippet "index" } "th " { $snippet "color-attachment" } " of a framebuffer." } +{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ; + +HELP: +{ $values + { "framebuffer" any-framebuffer } { "attachment" attachment-ref } { "rect" rect } + { "framebuffer-rect" framebuffer-rect } +} +{ $description "Constructs a " { $link framebuffer-rect } " tuple that references a rectangular region of " { $snippet "attachment" } " in " { $snippet "framebuffer" } "." } +{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ; + +{ framebuffer-rect } related-words + +HELP: +{ $values + { "color-attachments" sequence } { "depth-attachment" framebuffer-attachment } { "stencil-attachment" framebuffer-attachment } { "dim" { $maybe sequence } } + { "framebuffer" framebuffer } +} +{ $description "Creates a new " { $link framebuffer } " object comprising the given set of " { $snippet "color-attachments" } ", " { $snippet "depth-attachment" } ", and " { $snippet "stencil-attachment" } ". If " { $snippet "dim" } " is not null, all of the attachments will be resized using " { $link resize-framebuffer } "; otherwise, each texture or renderbuffer being attached must have image memory allocated for the framebuffer creation to succeed." } +{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions. If only the " { $snippet "GL_EXT_framebuffer_object" } " is available, all framebuffer attachments must have the same size, and all color attachments must have the same " { $link component-order } " and " { $link component-type } "." } ; + +HELP: +{ $values + { "framebuffer" any-framebuffer } { "attachment" attachment-ref } + { "framebuffer-rect" framebuffer-rect } +} +{ $description "Constructs a " { $link framebuffer-rect } " tuple that spans the entire size of " { $snippet "attachment" } " in " { $snippet "framebuffer" } "." } +{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ; + +HELP: +{ $values + { "component-order" component-order } { "component-type" component-type } { "samples" { $maybe integer } } { "dim" { $maybe sequence } } + { "renderbuffer" renderbuffer } +} +{ $description "Creates a new " { $link renderbuffer } " object. If " { $snippet "samples" } " is not " { $link f } ", it specifies the multisampling level to use. If " { $snippet "dim" } " is not " { $link f } ", image memory of the given dimensions will be allocated for the renderbuffer; otherwise, memory will have to be allocated separately with " { $link allocate-renderbuffer } "." } +{ $notes "Renderbuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions. Multisampled renderbuffers require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_multisample" } " extensions." } ; + +HELP: +{ $values + { "side" { $maybe framebuffer-attachment-side } } { "face" { $maybe framebuffer-attachment-face } } + { "system-attachment" system-attachment } +} +{ $description "Constructs an " { $link attachment-ref } " referencing a " { $link system-framebuffer } " color attachment." } ; + +HELP: +{ $values + { "texture" texture-data-target } { "level" integer } + { "texture-1d-attachment" texture-1d-attachment } +} +{ $description "Constructs a " { $link framebuffer-attachment } " to the " { $snippet "level" } "th level of detail of one-dimensional texture " { $snippet "texture" } "." } +{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ; + +HELP: +{ $values + { "texture" texture-data-target } { "level" integer } + { "texture-2d-attachment" texture-2d-attachment } +} +{ $description "Constructs a " { $link framebuffer-attachment } " to the " { $snippet "level" } "th level of detail of two-dimensional texture " { $snippet "texture" } "." } +{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ; + +HELP: +{ $values + { "texture" texture-data-target } { "z-offset" integer } { "level" integer } + { "texture-3d-attachment" texture-3d-attachment } +} +{ $description "Constructs a " { $link framebuffer-attachment } " to the " { $snippet "z-offset" } "th plane of the " { $snippet "level" } "th level of detail of three-dimensional texture " { $snippet "texture" } "." } +{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ; + +HELP: +{ $values + { "texture" texture-data-target } { "layer" integer } { "level" integer } + { "texture-layer-attachment" texture-layer-attachment } +} +{ $description "Constructs a " { $link framebuffer-attachment } " to the " { $snippet "layer" } "th layer of the " { $snippet "level" } "th level of detail of three-dimensional texture or array texture " { $snippet "texture" } "." } +{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions. Array textures require OpenGL 3.0 or the " { $snippet "GL_EXT_texture_array" } " extension." } ; + +HELP: allocate-renderbuffer +{ $values + { "renderbuffer" renderbuffer } { "dim" sequence } +} +{ $description "Allocates image memory for " { $snippet "renderbuffer" } " with dimension " { $snippet "dim" } "." } +{ $notes "Renderbuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ; + +HELP: any-framebuffer +{ $class-description "This class is a union of the " { $link framebuffer } " class, which represents user-created framebuffer objects, and the " { $link system-framebuffer } ". Words which accept " { $snippet "any-framebuffer" } " can operate on either the system framebuffer or user framebuffers." } +{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ; + +HELP: attachment-ref +{ $class-description "An " { $snippet "attachment-ref" } " value references a particular color, depth, or stencil attachment to a " { $link framebuffer } " object." +{ $list +{ { $link system-attachment } " references one or more of the color attachments to the " { $link system-framebuffer } "." } +{ { $link color-attachment } " references one of the indexed color attachments to a user-created " { $link framebuffer } "." } +{ { $link default-attachment } " references the back buffer of the " { $snippet "system-framebuffer" } " or the first color attachment of a user " { $snippet "framebuffer" } "." } +{ { $link depth-attachment } " references the depth buffer attachment to any framebuffer." } +{ { $link stencil-attachment } " references the stencil buffer attachment to any framebuffer." } +} } +{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ; + +HELP: back-face +{ $class-description "Use this value in the " { $snippet "face" } " slot of a " { $link system-attachment } " reference to select the back face of a double-buffered " { $link system-framebuffer } "." } ; + +HELP: clear-framebuffer +{ $values + { "framebuffer" any-framebuffer } { "alist" "a list of " { $link attachment-ref } "/value pairs" } +} +{ $description "Clears the active viewport area of the specified attachments to " { $snippet "framebuffer" } " to the associated values." } +{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ; + +HELP: clear-framebuffer-attachment +{ $values + { "framebuffer" any-framebuffer } { "attachment-ref" attachment-ref } { "value" object } +} +{ $description "Clears the active viewport area of the given attachment to " { $snippet "framebuffer" } " to " { $snippet "value" } "." } +{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ; + +{ clear-framebuffer clear-framebuffer-attachment } related-words + +HELP: color-attachment +{ $class-description "This " { $link attachment-ref } " type references a color attachment to a user-created " { $link framebuffer } " object. The " { $snippet "index" } " slot of the tuple indicates the color attachment referenced. Color attachments to the " { $link system-framebuffer } " are referenced by the " { $link system-attachment } " type." } +{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ; + +{ + color-attachment system-attachment default-attachment depth-attachment stencil-attachment + attachment-ref color-attachment-ref +} related-words + +HELP: color-attachment-ref +{ $class-description "A " { $snippet "color-attachment-ref" } " value references a particular color attachment to a " { $link framebuffer } " object." +{ $list +{ { $link system-attachment } " references one or more of the color attachments to the " { $link system-framebuffer } "." } +{ { $link color-attachment } " references one of the indexed color attachments to a user-created " { $link framebuffer } "." } +{ { $link default-attachment } " references the back buffer of the " { $snippet "system-framebuffer" } " or the first color attachment of a user " { $snippet "framebuffer" } "." } +} } +{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ; + +HELP: copy-framebuffer +{ $values + { "to-fb-rect" framebuffer-rect } { "from-fb-rect" framebuffer-rect } { "depth?" boolean } { "stencil?" boolean } { "filter" texture-filter } +} +{ $description "Copies the rectangular region " { $snippet "from-fb-rect" } " to " { $snippet "to-fb-rect" } ". If " { $snippet "depth?" } " is true, depth values are also copied, and if " { $snippet "stencil?" } " is true, so are stencil values. If the rectangle sizes do not match, the region is scaled using nearest-neighbor or linear filtering based on " { $snippet "filter" } "." } +{ $notes "This word requires OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_blit" } " extensions." } ; + +HELP: default-attachment +{ $class-description "This " { $link attachment-ref } " references the back buffer of the " { $link system-framebuffer } " or the first color attachment of a user-created " { $link framebuffer } "." } +{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ; + +HELP: depth-attachment +{ $class-description "This " { $link attachment-ref } " references the depth buffer attachment of a user-created " { $link framebuffer } " or the " { $link system-framebuffer } "." } +{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ; + +HELP: framebuffer +{ $class-description "Objects of this class represent user-created framebuffer objects. These framebuffer objects provide an offscreen target for rendering operations and can send rendering output either to textures or to dedicated " { $link renderbuffer } "s. A framebuffer consists of a set of one or more color " { $link framebuffer-attachment } "s, an optional depth buffer " { $snippet "framebuffer-attachment" } ", and an optional stencil buffer " { $snippet "framebuffer-attachment" } "." } +{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ; + +HELP: framebuffer-attachment +{ $class-description "This class is a union of the " { $link renderbuffer } " and " { $link texture-attachment } " classes, either of which can function as an attachment to a user-created " { $link framebuffer } " object." } +{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ; + +HELP: framebuffer-attachment-at +{ $values + { "framebuffer" framebuffer } { "attachment-ref" attachment-ref } + { "attachment" framebuffer-attachment } +} +{ $description "Returns the " { $link texture-attachment } " or " { $link renderbuffer } " referenced by " { $snippet "attachment-ref" } " in " { $snippet "framebuffer" } "." } +{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ; + +HELP: framebuffer-attachment-face +{ $class-description "The values " { $link front-face } " and " { $link back-face } " select a face of a double-buffered " { $link system-framebuffer } " when stored in the " { $snippet "face" } " slot of a " { $link system-attachment } " reference." } ; + +HELP: framebuffer-attachment-side +{ $class-description "The values " { $link left-side } " and " { $link right-side } " select a face of a stereoscopic " { $link system-framebuffer } " when stored in the " { $snippet "side" } " slot of a " { $link system-attachment } " reference." } ; + +HELP: framebuffer-rect +{ $class-description "This tuple class references a rectangular subregion of a color attachment of a " { $link framebuffer } " object." +{ $list +{ { $snippet "framebuffer" } " references either a user-created " { $link framebuffer } " or the " { $link system-framebuffer } "." } +{ { $snippet "attachment" } " is a " { $link color-attachment-ref } " referencing the color attachment of interest in the framebuffer." } +{ { $snippet "rect" } " is a " { $link rect } " referencing the rectangular region of interest of the attachment." } +} } +{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ; + +HELP: front-face +{ $class-description "Use this value in the " { $snippet "face" } " slot of a " { $link system-attachment } " reference to select the front face of a double-buffered " { $link system-framebuffer } "." } ; + +{ front-face back-face } related-words + +HELP: left-side +{ $class-description "Use this value in the " { $snippet "side" } " slot of a " { $link system-attachment } " reference to select the left side of a stereoscopic " { $link system-framebuffer } "." } ; + +{ left-side right-side } related-words + +HELP: read-framebuffer +{ $values + { "framebuffer-rect" framebuffer-rect } + { "byte-array" byte-array } +} +{ $description "Reads the rectangular region " { $snippet "framebuffer-rect" } " into a new " { $snippet "byte-array" } ". The format of the byte array is determined by the " { $link component-order } " and " { $link component-type } " of the associated " { $link framebuffer-attachment } "." } +{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ; + +HELP: read-framebuffer-image +{ $values + { "framebuffer-rect" framebuffer-rect } + { "image" image } +} +{ $description "Reads the rectangular region " { $snippet "framebuffer-rect" } " into a new " { $snippet "image" } ". The format of the image is determined by the " { $link component-order } " and " { $link component-type } " of the associated " { $link framebuffer-attachment } "." } +{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ; + +HELP: read-framebuffer-to +{ $values + { "framebuffer-rect" framebuffer-rect } { "gpu-data-ptr" gpu-data-ptr } +} +{ $description "Reads the rectangular region " { $snippet "framebuffer-rect" } " into " { $snippet "gpu-data-ptr" } ", which can reference either CPU memory (a " { $link byte-array } " or " { $link alien } ") or a GPU " { $link buffer-ptr } ". The format of the written data is determined by the " { $link component-order } " and " { $link component-type } " of the associated " { $link framebuffer-attachment } "." } +{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions. Reading into a " { $snippet "buffer-ptr" } " requires OpenGL 2.1 or the " { $snippet "GL_ARB_pixel_buffer_object" } " extension." } ; + +{ read-framebuffer read-framebuffer-image read-framebuffer-to } related-words + +HELP: renderbuffer +{ $class-description "Objects of this type represent renderbuffer objects, two-dimensional image buffers that can serve as " { $link framebuffer-attachment } "s to user-created " { $link framebuffer } " objects." } +{ $notes "Renderbuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ; + +{ renderbuffer renderbuffer-dim allocate-renderbuffer } related-words +{ framebuffer resize-framebuffer } related-words + +HELP: renderbuffer-dim +{ $values + { "renderbuffer" renderbuffer } + { "dim" sequence } +} +{ $description "Returns the dimensions of the allocated image memory for " { $snippet "renderbuffer" } "." } +{ $notes "Renderbuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ; + +HELP: resize-framebuffer +{ $values + { "framebuffer" framebuffer } { "dim" sequence } +} +{ $description "Reallocates the image memory for all of the textures and renderbuffers bound to " { $snippet "framebuffer" } " to be of the given dimensions." } +{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ; + +HELP: right-side +{ $class-description "Use this value in the " { $snippet "side" } " slot of a " { $link system-attachment } " reference to select the right side of a stereoscopic " { $link system-framebuffer } "." } ; + +HELP: stencil-attachment +{ $class-description "This " { $link attachment-ref } " references the stencil buffer attachment of a user-created " { $link framebuffer } " or the " { $link system-framebuffer } "." } +{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ; + +HELP: system-attachment +{ $class-description "This " { $link attachment-ref } " references one or more of the color attachments to the " { $link system-framebuffer } ". Depending on the window system pixel format for the window, up to four attachments may be available:" +{ $list +{ "If double buffering is available, there is a " { $link back-face } ", which holds the screen image as it is drawn, and a " { $link front-face } ", which holds the current contents of the screen. The two buffers get swapped when a scene is completely drawn." } +{ "If stereoscopic rendering is available, there is a " { $link left-side } " and " { $link right-side } ", representing the left and right eye viewpoints of a 3D viewing apparatus." } +} +"To select a subset of these attachments, the " { $snippet "system-attachment" } " tuple type has two slots:" +{ $list +{ { $snippet "side" } " selects either the " { $snippet "left-side" } " or " { $snippet "right-side" } ", or both if set to " { $link f } "." } +{ { $snippet "face" } " selects either the " { $snippet "back-face" } " or " { $snippet "front-face" } ", or both if set to " { $link f } "." } +} +"If stereo or double buffering are not available, then both sides or faces respectively will be equivalent. All attachments can be selected by setting both slots to " { $link f } ", both attachments of a side or face can be selected by setting a single slot, and a single attachment can be targeted by setting both slots." } ; + +HELP: system-framebuffer +{ $class-description "This symbol represents the framebuffer supplied by the window system to store the contents of the window on screen. Since this framebuffer is managed by the window system, it cannot have its attachments modified or resized; however, it is still a valid target for rendering, copying via " { $link copy-framebuffer } ", clearing via " { $link clear-framebuffer } ", and reading via " { $link read-framebuffer } "." } ; + +HELP: texture-1d-attachment +{ $class-description "This class references a single level of detail of a one-dimensional texture for use as a " { $link framebuffer-attachment } "." } +{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ; + +HELP: texture-2d-attachment +{ $class-description "This class references a single level of detail of a two-dimensional texture for use as a " { $link framebuffer-attachment } "." } +{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ; + +HELP: texture-3d-attachment +{ $class-description "This class references a single plane and level of detail of a three-dimensional texture for use as a " { $link framebuffer-attachment } "." } +{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ; + +HELP: texture-attachment +{ $class-description "This class is a union of the " { $link texture-1d-attachment } ", " { $link texture-2d-attachment } ", " { $link texture-3d-attachment } ", and " { $link texture-layer-attachment } " classes, which select layers and levels of detail of " { $link texture } " objects to serve as " { $link framebuffer } " attachments." } +{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions." } ; + +HELP: texture-layer-attachment +{ $class-description "This class references a single layer and level of detail of a three-dimensional texture or array texture for use as a " { $link framebuffer-attachment } "." } +{ $notes "User-created framebuffer objects require OpenGL 3.0 or one of the " { $snippet "GL_ARB_framebuffer_object" } " or " { $snippet "GL_EXT_framebuffer_object" } " extensions. Array textures require OpenGL 3.0 or the " { $snippet "GL_EXT_texture_array" } " extension." } ; + +{ texture-1d-attachment } related-words +{ texture-2d-attachment } related-words +{ texture-3d-attachment } related-words +{ texture-layer-attachment } related-words + +ARTICLE: "gpu.framebuffers" "Framebuffer objects" +"The " { $vocab-link "gpu.framebuffers" } " vocabulary provides words for creating, allocating, and reading from framebuffer objects. Framebuffer objects are used as rendering targets; the " { $link system-framebuffer } " is supplied by the window system and contains the contents of the window on screen. User-created " { $link framebuffer } " objects can also be created to direct rendering output to offscreen " { $link texture } "s or " { $link renderbuffer } "s." +{ $subsection system-framebuffer } +{ $subsection framebuffer } +{ $subsection renderbuffer } +"The contents of a framebuffer can be cleared to known values before rendering a scene:" +{ $subsection clear-framebuffer } +{ $subsection clear-framebuffer-attachment } +"The image memory for a renderbuffer can be resized, or the full set of textures and renderbuffers attached to a framebuffer can be resized to the same dimensions together:" +{ $subsection allocate-renderbuffer } +{ $subsection resize-framebuffer } +"Rectangular regions of framebuffers can be read into memory, read into GPU " { $link buffer } "s, and copied between framebuffers:" +{ $subsection framebuffer-rect } +{ $subsection attachment-ref } +{ $subsection read-framebuffer } +{ $subsection read-framebuffer-to } +{ $subsection read-framebuffer-image } +{ $subsection copy-framebuffer } ; + +ABOUT: "gpu.framebuffers" diff --git a/extra/gpu/framebuffers/framebuffers.factor b/extra/gpu/framebuffers/framebuffers.factor new file mode 100755 index 0000000000..12bc3430c3 --- /dev/null +++ b/extra/gpu/framebuffers/framebuffers.factor @@ -0,0 +1,368 @@ +! (c)2009 Joe Groff bsd license +USING: accessors alien.c-types arrays byte-arrays combinators +destructors gpu gpu.buffers gpu.private gpu.textures +gpu.textures.private images kernel locals math math.rectangles opengl +opengl.framebuffers opengl.gl opengl.textures sequences +specialized-arrays.int specialized-arrays.uint +ui.gadgets.worlds variants ; +IN: gpu.framebuffers + +SINGLETON: system-framebuffer + +TUPLE: renderbuffer < gpu-object + { component-order component-order initial: RGBA } + { component-type component-type initial: ubyte-components } + { samples integer initial: 0 } ; + + [ glGetRenderbufferParameteriv ] keep *int ; + +PRIVATE> + +:: allocate-renderbuffer ( renderbuffer dim -- ) + GL_RENDERBUFFER renderbuffer handle>> glBindRenderbuffer + GL_RENDERBUFFER + renderbuffer samples>> dup zero? + [ drop renderbuffer texture-gl-internal-format dim first2 glRenderbufferStorage ] + [ renderbuffer texture-gl-internal-format dim first2 glRenderbufferStorageMultisample ] + if ; + +:: renderbuffer-dim ( renderbuffer -- dim ) + GL_RENDERBUFFER renderbuffer handle>> glBindRenderbuffer + GL_RENDERBUFFER_WIDTH get-framebuffer-int + GL_RENDERBUFFER_HEIGHT get-framebuffer-int 2array ; + +: ( component-order component-type samples dim -- renderbuffer ) + [ [ gen-renderbuffer ] 3dip renderbuffer boa dup ] dip + [ allocate-renderbuffer ] [ drop ] if* + window-resource ; + +M: renderbuffer dispose + [ [ delete-renderbuffer ] when* f ] change-handle drop ; + +TUPLE: texture-1d-attachment + { texture texture-1d-data-target read-only initial: T{ texture-1d } } + { level integer read-only } ; + +C: texture-1d-attachment + +TUPLE: texture-2d-attachment + { texture texture-2d-data-target read-only initial: T{ texture-2d } } + { level integer read-only } ; + +C: texture-2d-attachment + +TUPLE: texture-3d-attachment + { texture texture-3d read-only initial: T{ texture-3d } } + { z-offset integer read-only } + { level integer read-only } ; + +C: texture-3d-attachment + +TUPLE: texture-layer-attachment + { texture texture-3d-data-target read-only initial: T{ texture-3d } } + { layer integer read-only } + { level integer read-only } ; + +C: texture-layer-attachment + +UNION: texture-attachment + texture-1d-attachment texture-2d-attachment texture-3d-attachment texture-layer-attachment ; + +M: texture-attachment dispose texture>> dispose ; + +UNION: framebuffer-attachment renderbuffer texture-attachment ; +UNION: ?framebuffer-attachment framebuffer-attachment POSTPONE: f ; + +GENERIC: attachment-object ( attachment -- object ) +M: renderbuffer attachment-object ; +M: texture-attachment attachment-object texture>> texture-object ; + +TUPLE: framebuffer < gpu-object + { color-attachments array read-only } + { depth-attachment ?framebuffer-attachment read-only initial: f } + { stencil-attachment ?framebuffer-attachment read-only initial: f } ; + +UNION: any-framebuffer system-framebuffer framebuffer ; + +VARIANT: framebuffer-attachment-side + left-side right-side ; + +VARIANT: framebuffer-attachment-face + back-face front-face ; + +UNION: ?framebuffer-attachment-side framebuffer-attachment-side POSTPONE: f ; +UNION: ?framebuffer-attachment-face framebuffer-attachment-face POSTPONE: f ; + +VARIANT: color-attachment-ref + default-attachment + system-attachment: { + { side ?framebuffer-attachment-side initial: f } + { face ?framebuffer-attachment-face initial: back-face } + } + color-attachment: { { index integer } } ; + +VARIANT: non-color-attachment-ref + depth-attachment + stencil-attachment ; + +UNION: attachment-ref + color-attachment-ref + non-color-attachment-ref + POSTPONE: f ; + +TUPLE: framebuffer-rect + { framebuffer any-framebuffer read-only initial: system-framebuffer } + { attachment color-attachment-ref read-only initial: default-attachment } + { rect rect read-only } ; + +C: framebuffer-rect + +: framebuffer-attachment-at ( framebuffer attachment-ref -- attachment ) + { + { default-attachment [ color-attachments>> first ] } + { color-attachment [ swap color-attachments>> nth ] } + { depth-attachment [ depth-attachment>> ] } + { stencil-attachment [ stencil-attachment>> ] } + } match ; + +> ; + +GENERIC# allocate-framebuffer-attachment 1 ( framebuffer-attachment dim -- ) + +M: texture-attachment allocate-framebuffer-attachment + [ [ texture>> ] [ level>> ] bi ] dip f allocate-texture ; +M: renderbuffer allocate-framebuffer-attachment + allocate-renderbuffer ; + +GENERIC: framebuffer-attachment-dim ( framebuffer-attachment -- dim ) + +M: texture-attachment framebuffer-attachment-dim + [ texture>> ] [ level>> ] bi texture-dim + dup number? [ 1 2array ] [ 2 head ] if ; + +M: renderbuffer framebuffer-attachment-dim + renderbuffer-dim ; + +: each-attachment ( framebuffer quot: ( attachment -- ) -- ) + [ [ color-attachments>> ] dip each ] + [ swap depth-attachment>> [ swap call ] [ drop ] if* ] + [ swap stencil-attachment>> [ swap call ] [ drop ] if* ] 2tri ; inline + +: each-attachment-target ( framebuffer quot: ( attachment-target attachment -- ) -- ) + [ [ color-attachments>> ] dip [ GL_COLOR_ATTACHMENT0 + swap ] prepose each-index ] + [ swap depth-attachment>> [ GL_DEPTH_ATTACHMENT spin call ] [ drop ] if* ] + [ swap stencil-attachment>> [ GL_STENCIL_ATTACHMENT spin call ] [ drop ] if* ] 2tri ; inline + +GENERIC: bind-framebuffer-attachment ( attachment-target attachment -- ) + +M:: renderbuffer bind-framebuffer-attachment ( attachment-target renderbuffer -- ) + GL_DRAW_FRAMEBUFFER attachment-target + GL_RENDERBUFFER renderbuffer handle>> + glFramebufferRenderbuffer ; + +M:: texture-1d-attachment bind-framebuffer-attachment ( attachment-target texture-attachment -- ) + GL_DRAW_FRAMEBUFFER attachment-target + texture-attachment [ texture>> [ texture-data-gl-target ] [ texture-object handle>> ] bi ] [ level>> ] bi + glFramebufferTexture1D ; + +M:: texture-2d-attachment bind-framebuffer-attachment ( attachment-target texture-attachment -- ) + GL_DRAW_FRAMEBUFFER attachment-target + texture-attachment [ texture>> [ texture-data-gl-target ] [ texture-object handle>> ] bi ] [ level>> ] bi + glFramebufferTexture2D ; + +M:: texture-3d-attachment bind-framebuffer-attachment ( attachment-target texture-attachment -- ) + GL_DRAW_FRAMEBUFFER attachment-target + texture-attachment + [ texture>> [ texture-data-gl-target ] [ texture-object handle>> ] bi ] + [ level>> ] [ z-offset>> ] tri + glFramebufferTexture3D ; + +M:: texture-layer-attachment bind-framebuffer-attachment ( attachment-target texture-attachment -- ) + GL_DRAW_FRAMEBUFFER attachment-target + texture-attachment + [ texture>> texture-object handle>> ] + [ level>> ] [ layer>> ] tri + glFramebufferTextureLayer ; + +GENERIC: (default-gl-attachment) ( framebuffer -- gl-attachment ) +GENERIC: (default-attachment-type) ( framebuffer -- type ) +GENERIC: (default-attachment-image-type) ( framebuffer -- order type ) + +M: system-framebuffer (default-gl-attachment) + drop GL_BACK ; +M: framebuffer (default-gl-attachment) + drop GL_COLOR_ATTACHMENT0 ; + +SYMBOLS: float-type int-type uint-type ; + +: (color-attachment-type) ( framebuffer index -- type ) + swap color-attachments>> nth attachment-object component-type>> { + { [ dup signed-unnormalized-integer-components? ] [ drop int-type ] } + { [ dup unsigned-unnormalized-integer-components? ] [ drop uint-type ] } + [ drop float-type ] + } cond ; + +M: system-framebuffer (default-attachment-type) + drop float-type ; +M: framebuffer (default-attachment-type) + 0 (color-attachment-type) ; + +M: system-framebuffer (default-attachment-image-type) ( framebuffer -- order type ) + drop RGBA ubyte-components ; +M: framebuffer (default-attachment-image-type) ( framebuffer -- order type ) + color-attachments>> first attachment-object + [ component-order>> ] [ component-type>> ] bi ; + +: gl-system-attachment ( side face -- attachment ) + 2array { + { { f f } [ GL_FRONT_AND_BACK ] } + { { f front-face } [ GL_FRONT ] } + { { f back-face } [ GL_BACK ] } + { { left-side f } [ GL_LEFT ] } + { { left-side front-face } [ GL_FRONT_LEFT ] } + { { left-side back-face } [ GL_BACK_LEFT ] } + { { right-side f } [ GL_RIGHT ] } + { { right-side front-face } [ GL_FRONT_RIGHT ] } + { { right-side back-face } [ GL_BACK_RIGHT ] } + } case ; + +: gl-attachment ( framebuffer attachment-ref -- gl-attachment ) + [ { + { depth-attachment [ GL_DEPTH_ATTACHMENT ] } + { stencil-attachment [ GL_STENCIL_ATTACHMENT ] } + { color-attachment [ GL_COLOR_ATTACHMENT0 + ] } + { system-attachment [ gl-system-attachment ] } + { default-attachment [ dup (default-gl-attachment) ] } + } match ] [ GL_NONE ] if* nip ; + +: color-attachment-image-type ( framebuffer attachment-ref -- order type ) + { + { color-attachment [ + swap color-attachments>> nth + attachment-object [ component-order>> ] [ component-type>> ] bi + ] } + { system-attachment [ 3drop RGBA ubyte-components ] } + { default-attachment [ (default-attachment-image-type) ] } + } match ; + +: framebuffer-rect-image-type ( framebuffer-rect -- order type ) + [ framebuffer>> ] [ attachment>> ] bi color-attachment-image-type ; + +HOOK: (clear-integer-color-attachment) gpu-api ( type value -- ) + +M: opengl-2 (clear-integer-color-attachment) + 4 0 pad-tail first4 + swap { + { int-type [ glClearColorIiEXT ] } + { uint-type [ glClearColorIuiEXT ] } + } case GL_COLOR_BUFFER_BIT glClear ; + +M: opengl-3 (clear-integer-color-attachment) + [ GL_COLOR 0 ] dip 4 0 pad-tail + swap { + { int-type [ >int-array glClearBufferiv ] } + { uint-type [ >uint-array glClearBufferuiv ] } + } case ; + +:: (clear-color-attachment) ( type attachment value -- ) + attachment glDrawBuffer + type float-type = + [ value 4 value last pad-tail first4 glClearColor GL_COLOR_BUFFER_BIT glClear ] + [ type value (clear-integer-color-attachment) ] if ; + +: framebuffer-rect-size ( framebuffer-rect -- size ) + [ rect>> dim>> product ] + [ framebuffer-rect-image-type (bytes-per-pixel) ] bi * ; + +PRIVATE> + +: ( framebuffer attachment -- framebuffer-rect ) + 2dup framebuffer-attachment-at + { 0 0 } swap framebuffer-attachment-dim + ; + +: resize-framebuffer ( framebuffer dim -- ) + [ allocate-framebuffer-attachment ] curry each-attachment ; + +:: attach-framebuffer-attachments ( framebuffer -- ) + GL_DRAW_FRAMEBUFFER framebuffer handle>> glBindFramebuffer + framebuffer [ bind-framebuffer-attachment ] each-attachment-target ; + +M: framebuffer dispose + [ [ delete-framebuffer ] when* f ] change-handle drop ; + +: dispose-framebuffer-attachments ( framebuffer -- ) + [ [ dispose ] when* ] each-attachment ; + +: ( color-attachments depth-attachment stencil-attachment dim -- framebuffer ) + [ [ 0 ] 3dip framebuffer boa dup ] dip + [ resize-framebuffer ] [ drop ] if* + gen-framebuffer >>handle + dup attach-framebuffer-attachments + window-resource ; + +:: clear-framebuffer-attachment ( framebuffer attachment-ref value -- ) + GL_DRAW_FRAMEBUFFER framebuffer framebuffer-handle glBindFramebuffer + attachment-ref { + { system-attachment [| side face | + float-type + side face gl-system-attachment + value (clear-color-attachment) + ] } + { color-attachment [| i | + framebuffer i (color-attachment-type) + GL_COLOR_ATTACHMENT0 i + + value (clear-color-attachment) + ] } + { default-attachment [ + framebuffer [ (default-attachment-type) ] [ (default-gl-attachment) ] bi + value (clear-color-attachment) + ] } + { depth-attachment [ value glClearDepth GL_DEPTH_BUFFER_BIT glClear ] } + { stencil-attachment [ value glClearStencil GL_STENCIL_BUFFER_BIT glClear ] } + } match ; + +: clear-framebuffer ( framebuffer alist -- ) + [ first2 clear-framebuffer-attachment ] with each ; + +:: read-framebuffer-to ( framebuffer-rect gpu-data-ptr -- ) + GL_READ_FRAMEBUFFER framebuffer-rect framebuffer>> framebuffer-handle glBindFramebuffer + framebuffer-rect [ framebuffer>> ] [ attachment>> ] bi gl-attachment glReadBuffer + framebuffer-rect rect>> [ loc>> first2 ] [ dim>> first2 ] bi + framebuffer-rect framebuffer-rect-image-type image-data-format + gpu-data-ptr pixel-pack-buffer [ glReadPixels ] with-gpu-data-ptr ; + +: read-framebuffer ( framebuffer-rect -- byte-array ) + dup framebuffer-rect-size [ read-framebuffer-to ] keep ; + +: read-framebuffer-image ( framebuffer-rect -- image ) + [ ] dip { + [ rect>> dim>> >>dim ] + [ + framebuffer-rect-image-type + [ >>component-order ] [ >>component-type ] bi* + ] + [ read-framebuffer >>bitmap ] + } cleave ; + +:: copy-framebuffer ( to-fb-rect from-fb-rect depth? stencil? filter -- ) + GL_DRAW_FRAMEBUFFER to-fb-rect framebuffer>> framebuffer-handle glBindFramebuffer + to-fb-rect [ framebuffer>> ] [ attachment>> ] bi gl-attachment glDrawBuffer + GL_READ_FRAMEBUFFER from-fb-rect framebuffer>> framebuffer-handle glBindFramebuffer + from-fb-rect [ framebuffer>> ] [ attachment>> ] bi gl-attachment glReadBuffer + to-fb-rect attachment>> [ GL_COLOR_BUFFER_BIT ] [ 0 ] if + depth? [ GL_DEPTH_BUFFER_BIT ] [ 0 ] if bitor + stencil? [ GL_STENCIL_BUFFER_BIT ] [ 0 ] if bitor :> mask + + from-fb-rect rect>> rect-extent [ first2 ] bi@ + to-fb-rect rect>> rect-extent [ first2 ] bi@ + mask filter gl-mag-filter glBlitFramebuffer ; + diff --git a/extra/gpu/framebuffers/summary.txt b/extra/gpu/framebuffers/summary.txt new file mode 100644 index 0000000000..26b9835578 --- /dev/null +++ b/extra/gpu/framebuffers/summary.txt @@ -0,0 +1 @@ +Render targets for GPU operations diff --git a/extra/gpu/gpu-docs.factor b/extra/gpu/gpu-docs.factor new file mode 100755 index 0000000000..c927eed10a --- /dev/null +++ b/extra/gpu/gpu-docs.factor @@ -0,0 +1,43 @@ +! (c)2009 Joe Groff bsd license +USING: help.markup help.syntax ui.gadgets.worlds ; +IN: gpu + +HELP: finish-gpu +{ $description "Waits for all outstanding GPU commands in the current graphics context to complete." } ; + +HELP: flush-gpu +{ $description "Forces the execution of all outstanding GPU commands in the current graphics context." } +{ $notes { $snippet "flush-gpu" } " does not wait for execution to finish. For that, use " { $link finish-gpu } "." } ; + +{ finish-gpu flush-gpu } related-words + +HELP: gpu-object +{ $class-description "Parent class of all GPU resources." } ; + +HELP: init-gpu +{ $description "Initializes the current graphics context for use with the " { $snippet "gpu" } " library. This should be the first thing called in a world's " { $link begin-world } " method." } ; + +HELP: reset-gpu +{ $description "Clears all framebuffer, GPU buffer, shader, and vertex array bindings. Call this before directly calling OpenGL functions after using " { $snippet "gpu" } " functions." } ; + +ARTICLE: "gpu" "Graphics context management" +"Preparing the GPU library:" +{ $subsection init-gpu } +"Forcing execution of queued commands:" +{ $subsection flush-gpu } +{ $subsection finish-gpu } +"Resetting OpenGL state:" +{ $subsection reset-gpu } ; + +ARTICLE: "gpu-summary" "GPU-accelerated rendering" +"The " { $vocab-link "gpu" } " library is a set of vocabularies that work together to provide a convenient interface to creating, managing, and using GPU resources." +{ $subsection "gpu" } +{ $subsection "gpu.state" } +{ $subsection "gpu.buffers" } +{ $subsection "gpu.textures" } +{ $subsection "gpu.framebuffers" } +{ $subsection "gpu.shaders" } +{ $subsection "gpu.render" } +"The library is built on top of the OpenGL API, but it aims to be complete enough that raw OpenGL calls are never needed. OpenGL 2.0 with the vertex array object extension (" { $snippet "GL_APPLE_vertex_array_object" } " or " { $snippet "GL_ARB_vertex_array_object" } ") is required. Some features require later OpenGL versions or additional extensions; these requirements are documented alongside individual words. To make full use of the library, an OpenGL 3.1 or later implementation is recommended." ; + +ABOUT: "gpu-summary" diff --git a/extra/gpu/gpu.factor b/extra/gpu/gpu.factor new file mode 100644 index 0000000000..12c6801439 --- /dev/null +++ b/extra/gpu/gpu.factor @@ -0,0 +1,61 @@ +! (c)2009 Joe Groff bsd license +USING: kernel namespaces opengl.capabilities opengl.gl variants ; +IN: gpu + +TUPLE: gpu-object < identity-tuple handle ; + + + +: init-gpu ( -- ) + set-gpu-api + init-gpu-api ; + +: reset-gpu ( -- ) + "3.0" { { "GL_APPLE_vertex_array_object" "GL_ARB_vertex_array_object" } } + has-gl-version-or-extensions? + [ 0 glBindVertexArray ] when + + "3.0" { { "GL_EXT_framebuffer_object" "GL_ARB_framebuffer_object" } } + has-gl-version-or-extensions? [ + GL_DRAW_FRAMEBUFFER 0 glBindFramebuffer + GL_READ_FRAMEBUFFER 0 glBindFramebuffer + GL_RENDERBUFFER 0 glBindRenderbuffer + ] when + + "1.5" { "GL_ARB_vertex_buffer_object" } + has-gl-version-or-extensions? [ + GL_ARRAY_BUFFER 0 glBindBuffer + GL_ELEMENT_ARRAY_BUFFER 0 glBindBuffer + ] when + + "2.1" { "GL_ARB_pixel_buffer_object" } + has-gl-version-or-extensions? [ + GL_PIXEL_PACK_BUFFER 0 glBindBuffer + GL_PIXEL_UNPACK_BUFFER 0 glBindBuffer + ] when + + "2.0" { "GL_ARB_shader_objects" } + has-gl-version-or-extensions? + [ 0 glUseProgram ] when ; + +: flush-gpu ( -- ) + glFlush ; + +: finish-gpu ( -- ) + glFinish ; diff --git a/extra/gpu/render/authors.txt b/extra/gpu/render/authors.txt new file mode 100644 index 0000000000..f13c9c1e77 --- /dev/null +++ b/extra/gpu/render/authors.txt @@ -0,0 +1 @@ +Joe Groff diff --git a/extra/gpu/render/render-docs.factor b/extra/gpu/render/render-docs.factor new file mode 100755 index 0000000000..68afc68f9b --- /dev/null +++ b/extra/gpu/render/render-docs.factor @@ -0,0 +1,284 @@ +! (c)2009 Joe Groff bsd license +USING: alien alien.syntax byte-arrays classes gpu.buffers +gpu.framebuffers gpu.shaders gpu.textures help.markup +help.syntax images kernel math multiline sequences +specialized-arrays.alien specialized-arrays.uint +specialized-arrays.ulong strings ; +IN: gpu.render + +HELP: +{ $values + { "ptr" gpu-data-ptr } { "count" integer } { "index-type" index-type } + { "index-elements" index-elements } +} +{ $description "Constructs an " { $link index-elements } " tuple." } ; + +HELP: +{ $values + { "start" integer } { "count" integer } + { "index-range" index-range } +} +{ $description "Constructs an " { $link index-range } " tuple." } ; + +HELP: +{ $values + { "buffer" { $maybe buffer } } { "ptrs" "an " { $link uint-array } " or " { $link void*-array } } { "counts" uint-array } { "index-type" index-type } + { "multi-index-elements" multi-index-elements } +} +{ $description "Constructs a " { $link multi-index-elements } " tuple." } ; + +HELP: +{ $values + { "starts" uint-array } { "counts" uint-array } + { "multi-index-range" multi-index-range } +} +{ $description "Constructs a " { $link multi-index-range } " tuple." } ; + +HELP: +{ $values + { "program-instance" program-instance } { "vertex-formats" "a list of " { $link buffer-ptr } "/" { $link vertex-format } " pairs" } + { "vertex-array" vertex-array } +} +{ $description "Creates a new " { $link vertex-array } " to feed data to " { $snippet "program-instance" } " from the set of " { $link buffer } "s specified in " { $snippet "vertex-formats" } "." } ; + +HELP: UNIFORM-TUPLE: +{ $syntax <" UNIFORM-TUPLE: class-name + { "slot" uniform-type dimension } + { "slot" uniform-type dimension } + ... + { "slot" uniform-type dimension } ; "> } +{ $description "Defines a new " { $link uniform-tuple } " class. Tuples of the new class can be used as the " { $snippet "uniforms" } " slot of a " { $link render-set } " in order to set the uniform parameters of the active shader program. The " { $link uniform-type } " of each slot defines the component type, and the " { $snippet "dimension" } " defines the vector or matrix dimensions; for example, a slot " { $snippet "{ \"foo\" float-uniform { 2 2 } }" } " will define a slot " { $snippet "foo" } " as a 2x2 matrix of floats." +$nl +"Uniform parameters are passed from Factor to the shader program through the uniform tuple as follows:" +{ $list +{ { $link int-uniform } "s and " { $link uint-uniform } "s take their values from Factor " { $link integer } "s." } +{ { $link float-uniform } "s take their values from Factor " { $link float } "s." } +{ { $link bool-uniform } "s take their values from Factor " { $link boolean } "s." } +{ { $link texture-uniform } "s take their values from " { $link texture } " objects." } +{ "Vector uniforms are passed as Factor " { $link sequence } "s of the corresponding component type." } +{ "Matrix uniforms are passed as row-major Factor " { $link sequence } "s of sequences of the corresponding component type." } } +"A value of a uniform tuple type is a standard Factor tuple. Uniform tuples are constructed with " { $link new } " or " { $link boa } ", and values are placed inside them using standard slot accessors." +} ; + +HELP: VERTEX-FORMAT: +{ $syntax <" VERTEX-FORMAT: format-name + { "attribute"/f component-type dimension normalize? } + { "attribute"/f component-type dimension normalize? } + ... + { "attribute"/f component-type dimension normalize? } ; "> } +{ $description "Defines a new binary " { $link vertex-format } " for structuring vertex data stored in " { $link buffer } "s. Each " { $snippet "attribute" } " name either corresponds to an input parameter of a vertex shader, or is " { $link f } " to include padding in the vertex format. The " { $link component-type } " determines the format of the components, and the " { $snippet "dimension" } " determines the number of components. If the " { $snippet "component-type" } " is an integer type and " { $snippet "normalize?" } " is true, the component values will be scaled to the range 0.0 to 1.0 when fed to the vertex shader; otherwise, they will be cast to floats retaining their integral values." } ; + +HELP: VERTEX-STRUCT: +{ $syntax <" VERTEX-STRUCT: struct-name format-name "> } +{ $description "Defines a struct C type (like " { $link POSTPONE: C-STRUCT: } ") with the same binary format and component types as the given " { $link vertex-format } "." } ; + +HELP: bool-uniform +{ $class-description "This " { $link uniform-type } " value indicates a uniform parameter whose components are " { $snippet "bool" } "s." } ; + +HELP: buffer>vertex-array +{ $values + { "vertex-buffer" buffer } { "program-instance" program-instance } { "format" vertex-format } + { "vertex-array" vertex-array } +} +{ $description "Creates a new " { $link vertex-array } " from the entire contents of a single " { $link buffer } " in a single " { $link vertex-format } " for use with " { $snippet "program-instance" } "." } ; + +{ vertex-array buffer>vertex-array } related-words + +HELP: define-uniform-tuple +{ $values + { "class" class } { "superclass" class } { "uniforms" sequence } +} +{ $description "Defines a new " { $link uniform-tuple } " as a subclass of " { $snippet "superclass" } " with the slots specified by the " { $link uniform } " tuple values in " { $snippet "uniforms" } ". The runtime equivalent of " { $link POSTPONE: UNIFORM-TUPLE: } ". This word must be called inside a compilation unit." } ; + +HELP: define-vertex-format +{ $values + { "class" class } { "vertex-attributes" sequence } +} +{ $description "Defines a new " { $link vertex-format } " with the binary format specified by the " { $link vertex-attribute } " tuple values in " { $snippet "vertex-attributes" } ". The runtime equivalent of " { $link POSTPONE: VERTEX-FORMAT: } ". This word must be called inside a compilation unit." } ; + +HELP: define-vertex-struct +{ $values + { "struct-name" string } { "vertex-format" vertex-format } +} +{ $description "Defines a new struct C type from a " { $link vertex-format } ". The runtime equivalent of " { $link POSTPONE: VERTEX-STRUCT: } ". This word must be called inside a compilation unit." } ; + +HELP: float-uniform +{ $class-description "This " { $link uniform-type } " value indicates a uniform parameter whose components are " { $snippet "float" } "s." } ; + +{ bool-uniform int-uniform float-uniform texture-uniform } related-words + +{ index-elements index-range multi-index-elements multi-index-range } related-words + +HELP: index-elements +{ $class-description "Objects of this tuple class can be passed as the " { $snippet "indexes" } " slot of a " { $link render-set } " to instruct " { $link render } " to assemble primitives from the active " { $link vertex-array } " by using an array of indexes in CPU or GPU memory." +{ $list +{ "The " { $snippet "ptr" } " slot contains a " { $link byte-array } ", " { $link alien } ", or " { $link buffer-ptr } " value referencing the beginning of the index array." } +{ "The " { $snippet "count" } " slot contains an " { $link integer } " value specifying the number of indexes to supply from the array." } +{ "The " { $snippet "index-type" } " slot contains an " { $link index-type } " value specifying whether the array consists of " { $link ubyte-indexes } ", " { $link ushort-indexes } ", or " { $link uint-indexes } "." } +} } ; + +HELP: index-range +{ $class-description "Objects of this tuple class can be passed as the " { $snippet "indexes" } " slot of a " { $link render-set } " to instruct " { $link render } " to assemble primitives sequentially from a slice of the active " { $link vertex-array } "." +{ $list +{ "The " { $snippet "start" } " slot contains an " { $link integer } " value indicating the first element of the array to draw." } +{ "The " { $snippet "count" } " slot contains an " { $link integer } " value indicating the number of elements to draw." } +} } ; + +HELP: index-type +{ $class-description "The " { $snippet "index-type" } " slot of an " { $link index-elements } " or " { $link multi-index-elements } " tuple indicates the type of the index array's elements: one-byte " { $link ubyte-indexes } ", two-byte " { $link ushort-indexes } ", or four-byte " { $link uint-indexes } "." } ; + +{ index-type ubyte-indexes ushort-indexes uint-indexes } related-words + +HELP: int-uniform +{ $class-description "This " { $link uniform-type } " value indicates a uniform parameter whose components are " { $snippet "int" } "s." } ; + +HELP: invalid-uniform-type +{ $values + { "uniform" uniform } +} +{ $description "Throws an error indicating that a slot of a " { $link uniform-tuple } " has been declared to have an invalid type." } ; + +HELP: lines-mode +{ $class-description "This " { $link primitive-mode } " value instructs " { $link render } " to assemble a line from each pair of indexed vertex array elements." } ; + +HELP: line-loop-mode +{ $class-description "This " { $link primitive-mode } " value instructs " { $link render } " to assemble a connected loop of lines from each consecutive pair of indexed vertex array elements, adding another line to close the last and first elements." } ; + +HELP: line-strip-mode +{ $class-description "This " { $link primitive-mode } " value instructs " { $link render } " to assemble a connected strip of lines from each consecutive pair of indexed vertex array elements." } ; + +HELP: multi-index-elements +{ $class-description "Objects of this tuple class can be passed as the " { $snippet "indexes" } " slot of a non-instanced " { $link render-set } " to instruct " { $link render } " to assemble primitives from the active " { $link vertex-array } " by using multiple arrays of indexes in CPU or GPU memory." +{ $list +{ "The " { $snippet "buffer" } " slot contains either a " { $link buffer } " object to read indexes from, or " { $link f } " to read from CPU memory." } +{ "The " { $snippet "ptrs" } " slot contains either a " { $link void*-array } " of pointers to the starts of index data, or a pointer-sized " { $link ulong-array } " of offsets into " { $snippet "buffer" } "." } +{ "The " { $snippet "counts" } " slot contains a " { $link uint-array } " containing the number of indexes to read from each pointer or offset in " { $snippet "ptrs" } "." } +{ "The " { $snippet "index-type" } " slot contains an " { $link index-type } " value specifying whether the arrays consist of " { $link ubyte-indexes } ", " { $link ushort-indexes } ", or " { $link uint-indexes } "." } +} } ; + +HELP: multi-index-range +{ $class-description "Objects of this tuple class can be passed as the " { $snippet "indexes" } " slot of a non-instanced " { $link render-set } " to instruct " { $link render } " to assemble primitives from the active " { $link vertex-array } " by using multiple consecutive slices of its elements." +{ $list +{ "The " { $snippet "starts" } " slot contains a " { $link uint-array } " of indexes into the array from which to start generating primitives." } +{ "The " { $snippet "counts" } " slot contains a " { $link uint-array } " of corresponding counts of indexes to read from each specified " { $snippet "start" } " index." } +} } ; + +HELP: points-mode +{ $class-description "This " { $link primitive-mode } " value instructs " { $link render } " to generate a point for each indexed vertex array element." } ; + +HELP: primitive-mode +{ $class-description "The " { $snippet "primitive-mode" } " slot of a " { $link render-set } " tells " { $link render } " what kind of primitives to generate and how to assemble them from the selected elements of the active " { $link vertex-array } "." } +{ $list +{ { $link points-mode } " causes each element to generate a point." } +{ { $link lines-mode } " causes each pair of elements to generate a disconnected line." } +{ { $link line-strip-mode } " causes each consecutive pair of elements to generate a connected strip of lines." } +{ { $link line-loop-mode } " causes each consecutive pair of elements to generate a connected loop of lines, with an extra line connecting the last and first elements." } +{ { $link triangles-mode } " causes every 3 elements to generate an independent triangle." } +{ { $link triangle-strip-mode } " causes every consecutive group of 3 elements to generate a connected strip of triangles." } +{ { $link triangle-fan-mode } " causes a triangle to be generated from the first element and every subsequent consecutive pair of elements in a fan pattern." } } ; + +{ primitive-mode points-mode lines-mode line-strip-mode line-loop-mode triangles-mode triangle-strip-mode triangle-fan-mode } related-words + +HELP: render +{ $values + { "render-set" render-set } +} +{ $description "Submits a rendering job to the GPU. The values in the " { $link render-set } " tuple describe the job." } ; + +HELP: render-set +{ $class-description "A " { $snippet "render-set" } " tuple describes a GPU rendering job." +{ $list +{ "The " { $link primitive-mode } " slot determines what kind of primitives should be rendered, and how they should be assembled." } +{ "The " { $link vertex-array } " slot supplies the shader program and vertex data to be rendered." } +{ "The " { $snippet "uniforms" } " slot contains a " { $link uniform-tuple } " with values for the shader program's uniform parameters." } +{ "The " { $snippet "indexes" } " slot contains one of the " { $link vertex-indexes } " types and selects elements from the vertex array to be rendered." } +{ "The " { $snippet "instances" } " slot, if not " { $link f } ", instructs the GPU to render several instances of the same set of vertexes. Instancing requires OpenGL 3.1 or one of the " { $snippet "GL_EXT_draw_instanced" } " or " { $snippet "GL_ARB_draw_instanced" } " extensions." } +{ "The " { $snippet "framebuffer" } " slot determines the target for the rendering output. Either the " { $link system-framebuffer } " or a user-created " { $link framebuffer } " object can be specified. User-created framebuffers require OpenGL 3.0 or one of the " { $snippet "GL_EXT_framebuffer_object" } " or " { $snippet "GL_ARB_framebuffer_object" } " extensions." } +{ "The " { $snippet "output-attachments" } " slot specifies which of the framebuffer's " { $link color-attachment-ref } "s to write the fragment shader's color output to. If the shader uses " { $snippet "gl_FragColor" } " or " { $snippet "gl_FragData[n]" } " to write its output, then " { $snippet "output-attachments" } " should be an array of " { $link color-attachment-ref } "s, and the output to color attachment binding is determined positionally. If the shader uses named output values, then " { $snippet "output-attachments" } " should be a list of string/" { $link color-attachment-ref } " pairs, mapping output names to color attachments. Named output values are available in GLSL 1.30 or later, and GLSL 1.20 and earlier using the " { $snippet "GL_EXT_gpu_shader4" } " extension." } +} } ; + +{ render render-set } related-words + +HELP: texture-uniform +{ $class-description "This " { $link uniform-type } " indicates that a slot of a " { $link uniform-tuple } " is a texture. The dimension of the corresponding " { $link uniform } " slot must be " { $snippet "1" } "." } ; + +HELP: triangle-fan-mode +{ $class-description "This " { $link primitive-mode } " value instructs " { $link render } " to generate a fan of triangles using the first indexed vertex array element and every subsequent consecutive pair of elements." } ; + +HELP: triangle-strip-mode +{ $class-description "This " { $link primitive-mode } " value instructs " { $link render } " to generate a strip of triangles using every consecutive group of 3 indexed vertex array elements." } ; + +HELP: triangles-mode +{ $class-description "This " { $link primitive-mode } " value instructs " { $link render } " to generate a triangle for each group of 3 indexed vertex array elements." } ; + +HELP: ubyte-indexes +{ $class-description "This " { $link index-type } " indicates that an " { $link index-elements } " or " { $link multi-index-elements } " buffer consists of unsigned byte indexes." } ; + +HELP: uint-indexes +{ $class-description "This " { $link index-type } " indicates that an " { $link index-elements } " or " { $link multi-index-elements } " buffer consists of four-byte unsigned int indexes." } ; + +HELP: uint-uniform +{ $class-description "This " { $link uniform-type } " indicates that a slot of a " { $link uniform-tuple } " is a scalar or vector of unsigned integers." } ; + +HELP: uniform +{ $class-description "Values of this tuple type are passed to " { $link define-uniform-tuple } " to define a new " { $link uniform-tuple } " type." } ; + +HELP: uniform-tuple +{ $class-description "The base class for tuple types defined with " { $link POSTPONE: UNIFORM-TUPLE: } ". A uniform tuple is used as part of a " { $link render-set } " to supply values for a shader program's uniform parameters. See the " { $link POSTPONE: UNIFORM-TUPLE: } " documentation for details on how uniform tuples are defined and used." } ; + +HELP: uniform-type +{ $class-description { $snippet "uniform-type" } " values are used as part of a " { $link POSTPONE: UNIFORM-TUPLE: } " definition to define the types of uniform slots." } ; + +{ uniform-type bool-uniform int-uniform float-uniform texture-uniform uint-uniform } related-words + +HELP: ushort-indexes +{ $class-description "This " { $link index-type } " indicates that an " { $link index-elements } " or " { $link multi-index-elements } " buffer consists of two-byte unsigned short indexes." } ; + +{ index-type ubyte-indexes ushort-indexes uint-indexes } related-words + +HELP: vertex-array +{ $class-description "A " { $snippet "vertex-array" } " object associates a shader " { $link program-instance } " with vertex attribute data from one or more " { $link buffer } "s. The format of the binary data inside these buffers is described using " { $link vertex-format } "s. " { $snippet "vertex-array" } "s are constructed using the " { $link } " or " { $link buffer>vertex-array } " words." } ; + +HELP: vertex-array-buffer +{ $values + { "vertex-array" vertex-array } + { "vertex-buffer" buffer } +} +{ $description "Returns the first " { $link buffer } " object comprised in " { $snippet "vertex-array" } "." } ; + +HELP: vertex-attribute +{ $class-description "This tuple type is passed to " { $link define-vertex-format } " to define a new " { $link vertex-format } " type." } ; + +HELP: vertex-format +{ $class-description "This class encompasses all vertex formats defined by " { $link POSTPONE: VERTEX-FORMAT: } ". A vertex format defines the binary layout of vertex attribute data in a " { $link buffer } " for use as part of a " { $link vertex-array } ". See the " { $link POSTPONE: VERTEX-FORMAT: } " documentation for details on how vertex formats are defined." } ; + +HELP: vertex-format-size +{ $values + { "format" vertex-format } + { "size" integer } +} +{ $description "Returns the size in bytes of a set of vertex attributes in " { $snippet "format" } "." } ; + +HELP: vertex-indexes +{ $class-description "This class is a union of the following tuple types, any of which can be used as the " { $snippet "indexes" } " slot of a " { $link render-set } " to select elements from a " { $link vertex-array } " for rendering." +{ $list +{ "An " { $link index-range } " value submits a sequential slice of a vertex array for rendering." } +{ "An " { $link index-elements } " value submits vertex array elements in an order specified by an array of indexes." } +{ "A " { $link multi-index-range } " value submits multiple sequential slices of a vertex array." } +{ "A " { $link multi-index-elements } " value submits multiple separate lists of indexed vertex array elements." } +} } ; + +ARTICLE: "gpu.render" "Rendering" +"The " { $vocab-link "gpu.render" } " vocabulary contains words for organizing and submitting data to the GPU for rendering." +{ $subsection render } +{ $subsection render-set } +"Render data inside GPU " { $link buffer } "s is organized into " { $link vertex-array } "s for consumption by shader code:" +{ $subsection vertex-array } +{ $subsection } +{ $subsection buffer>vertex-array } +{ $subsection POSTPONE: VERTEX-FORMAT: } +{ $link uniform-tuple } "s provide Factor types for containing and submitting shader uniform parameters:" +{ $subsection POSTPONE: UNIFORM-TUPLE: } +; + +ABOUT: "gpu.render" diff --git a/extra/gpu/render/render.factor b/extra/gpu/render/render.factor new file mode 100644 index 0000000000..65a99f94d7 --- /dev/null +++ b/extra/gpu/render/render.factor @@ -0,0 +1,506 @@ +! (c)2009 Joe Groff bsd license +USING: accessors alien alien.c-types alien.structs arrays +assocs classes.mixin classes.parser classes.singleton +classes.tuple classes.tuple.private combinators destructors fry +generic generic.parser gpu gpu.buffers gpu.framebuffers +gpu.framebuffers.private gpu.shaders gpu.state gpu.textures +gpu.textures.private half-floats images kernel lexer locals +math math.order math.parser namespaces opengl opengl.gl parser +quotations sequences slots sorting specialized-arrays.alien +specialized-arrays.float specialized-arrays.int +specialized-arrays.uint strings ui.gadgets.worlds variants +vocabs.parser words ; +IN: gpu.render + +UNION: ?string string POSTPONE: f ; +UNION: uniform-dim integer sequence ; + +TUPLE: vertex-attribute + { name ?string read-only initial: f } + { component-type component-type read-only initial: float-components } + { dim integer read-only initial: 4 } + { normalize? boolean read-only initial: f } ; + +VARIANT: uniform-type + bool-uniform + uint-uniform + int-uniform + float-uniform + texture-uniform ; + +TUPLE: uniform + { name string read-only initial: "" } + { uniform-type uniform-type read-only initial: float-uniform } + { dim uniform-dim read-only initial: 4 } ; + +VARIANT: index-type + ubyte-indexes + ushort-indexes + uint-indexes ; + +TUPLE: index-range + { start integer read-only } + { count integer read-only } ; + +C: index-range + +TUPLE: multi-index-range + { starts uint-array read-only } + { counts uint-array read-only } ; + +C: multi-index-range + +UNION: ?integer integer POSTPONE: f ; + +TUPLE: index-elements + { ptr gpu-data-ptr read-only } + { count integer read-only } + { index-type index-type read-only } ; + +C: index-elements + +UNION: ?buffer buffer POSTPONE: f ; + +TUPLE: multi-index-elements + { buffer ?buffer read-only } + { ptrs read-only } + { counts uint-array read-only } + { index-type index-type read-only } ; + +C: multi-index-elements + +UNION: vertex-indexes + index-range + multi-index-range + index-elements + multi-index-elements ; + +VARIANT: primitive-mode + points-mode + lines-mode + line-strip-mode + line-loop-mode + triangles-mode + triangle-strip-mode + triangle-fan-mode ; + +MIXIN: vertex-format + +TUPLE: uniform-tuple ; + +GENERIC: vertex-format-size ( format -- size ) + +ERROR: invalid-uniform-type uniform ; + +> vertex-type-size ] [ dim>> ] bi * ; + +: vertex-attributes-size ( vertex-attributes -- size ) + [ vertex-attribute-size ] [ + ] map-reduce ; + +: gl-index-type ( index-type -- gl-index-type ) + { + { ubyte-indexes [ GL_UNSIGNED_BYTE ] } + { ushort-indexes [ GL_UNSIGNED_SHORT ] } + { uint-indexes [ GL_UNSIGNED_INT ] } + } case ; + +: gl-primitive-mode ( primitive-mode -- gl-primitive-mode ) + { + { points-mode [ GL_POINTS ] } + { lines-mode [ GL_LINES ] } + { line-strip-mode [ GL_LINE_STRIP ] } + { line-loop-mode [ GL_LINE_LOOP ] } + { triangles-mode [ GL_TRIANGLES ] } + { triangle-strip-mode [ GL_TRIANGLE_STRIP ] } + { triangle-fan-mode [ GL_TRIANGLE_FAN ] } + } case ; + +GENERIC: render-vertex-indexes ( primitive-mode vertex-indexes -- ) + +GENERIC# render-vertex-indexes-instanced 1 ( primitive-mode vertex-indexes instances -- ) + +M: index-range render-vertex-indexes + [ gl-primitive-mode ] [ [ start>> ] [ count>> ] bi ] bi* glDrawArrays ; + +M: index-range render-vertex-indexes-instanced + [ gl-primitive-mode ] [ [ start>> ] [ count>> ] bi ] [ ] tri* + glDrawArraysInstanced ; + +M: multi-index-range render-vertex-indexes + [ gl-primitive-mode ] [ [ starts>> ] [ counts>> dup length ] bi ] bi* + glMultiDrawArrays ; + +M: index-elements render-vertex-indexes + [ gl-primitive-mode ] + [ [ count>> ] [ index-type>> gl-index-type ] [ ptr>> ] tri ] bi* + index-buffer [ glDrawElements ] with-gpu-data-ptr ; + +M: index-elements render-vertex-indexes-instanced + [ gl-primitive-mode ] + [ [ count>> ] [ index-type>> gl-index-type ] [ ptr>> ] tri ] + [ ] tri* + swap index-buffer [ swap glDrawElementsInstanced ] with-gpu-data-ptr ; + +M: multi-index-elements render-vertex-indexes + [ gl-primitive-mode ] + [ { [ counts>> ] [ index-type>> gl-index-type ] [ ptrs>> dup length ] [ buffer>> ] } cleave ] + bi* + GL_ELEMENT_ARRAY_BUFFER swap [ handle>> ] [ 0 ] if* glBindBuffer glMultiDrawElements ; + +: (bind-texture-unit) ( texture-unit texture -- ) + [ GL_TEXTURE0 + glActiveTexture ] [ bind-texture drop ] bi* ; inline + +:: [bind-vertex-attribute] ( stride offset vertex-attribute -- stride offset' quot ) + vertex-attribute name>> :> name + vertex-attribute component-type>> :> type + type gl-vertex-type :> gl-type + vertex-attribute dim>> :> dim + vertex-attribute normalize?>> >c-bool :> normalize? + vertex-attribute vertex-attribute-size :> size + + stride offset size + + { + { [ name not ] [ [ 2drop ] ] } + { + [ type unnormalized-integer-components? ] + [ + { + name attribute-index [ glEnableVertexAttribArray ] keep + dim gl-type stride offset + } >quotation :> dip-block + + { dip-block dip glVertexAttribIPointer } >quotation + ] + } + [ + { + name attribute-index [ glEnableVertexAttribArray ] keep + dim gl-type normalize? stride offset + } >quotation :> dip-block + + { dip-block dip glVertexAttribPointer } >quotation + ] + } cond ; + +:: [bind-vertex-format] ( vertex-attributes -- quot ) + vertex-attributes vertex-attributes-size :> stride + stride 0 vertex-attributes [ [bind-vertex-attribute] ] { } map-as 2nip :> attributes-cleave + { attributes-cleave 2cleave } >quotation :> with-block + + { drop vertex-buffer with-block with-buffer-ptr } >quotation ; + +GENERIC: bind-vertex-format ( program-instance buffer-ptr format -- ) + +: define-vertex-format-methods ( class vertex-attributes -- ) + [ + [ \ bind-vertex-format create-method-in ] dip + [bind-vertex-format] define + ] [ + [ \ vertex-format-size create-method-in ] dip + [ \ drop ] dip vertex-attributes-size [ ] 2sequence define + ] 2bi ; + +GENERIC: bind-uniform-textures ( program-instance uniform-tuple -- ) +GENERIC: bind-uniforms ( program-instance uniform-tuple -- ) + +M: uniform-tuple bind-uniform-textures + 2drop ; +M: uniform-tuple bind-uniforms + 2drop ; + +: uniform-slot-type ( uniform -- type ) + dup dim>> 1 = [ + uniform-type>> { + { bool-uniform [ boolean ] } + { uint-uniform [ integer ] } + { int-uniform [ integer ] } + { float-uniform [ float ] } + { texture-uniform [ texture ] } + } case + ] [ drop sequence ] if ; + +: uniform>slot ( uniform -- slot ) + [ name>> ] [ uniform-slot-type ] bi 2array ; + +:: [bind-uniform-texture] ( uniform index -- quot ) + uniform name>> reader-word :> value>>-word + { index swap value>>-word (bind-texture-unit) } >quotation ; + +:: [bind-uniform-textures] ( superclass uniforms -- quot ) + superclass "uniform-tuple-texture-units" word-prop 0 or :> first-texture-unit + superclass \ bind-uniform-textures method :> next-method + uniforms + [ uniform-type>> texture-uniform = ] filter + [ first-texture-unit + [bind-uniform-texture] ] map-index + :> texture-uniforms-cleave + + { + 2dup next-method + nip texture-uniforms-cleave cleave + } >quotation ; + +:: [bind-uniform] ( texture-unit uniform -- texture-unit' quot ) + uniform name>> :> name + { name uniform-index } >quotation :> index-quot + uniform name>> reader-word 1quotation :> value>>-quot + { index-quot value>>-quot bi* } >quotation :> pre-quot + + uniform [ uniform-type>> ] [ dim>> ] bi 2array H{ + { { bool-uniform 1 } [ >c-bool glUniform1i ] } + { { int-uniform 1 } [ glUniform1i ] } + { { uint-uniform 1 } [ glUniform1ui ] } + { { float-uniform 1 } [ glUniform1f ] } + + { { bool-uniform 2 } [ [ >c-bool ] map first2 glUniform2i ] } + { { int-uniform 2 } [ first2 glUniform2i ] } + { { uint-uniform 2 } [ first2 glUniform2ui ] } + { { float-uniform 2 } [ first2 glUniform2f ] } + + { { bool-uniform 3 } [ [ >c-bool ] map first3 glUniform3i ] } + { { int-uniform 3 } [ first3 glUniform3i ] } + { { uint-uniform 3 } [ first3 glUniform3ui ] } + { { float-uniform 3 } [ first3 glUniform3f ] } + + { { bool-uniform 4 } [ [ >c-bool ] map first4 glUniform4i ] } + { { int-uniform 4 } [ first4 glUniform4i ] } + { { uint-uniform 4 } [ first4 glUniform4ui ] } + { { float-uniform 4 } [ first4 glUniform4f ] } + + { { float-uniform { 2 2 } } [ [ 1 1 ] dip concat >float-array glUniformMatrix2fv ] } + { { float-uniform { 3 2 } } [ [ 1 1 ] dip concat >float-array glUniformMatrix2x3fv ] } + { { float-uniform { 4 2 } } [ [ 1 1 ] dip concat >float-array glUniformMatrix2x4fv ] } + + { { float-uniform { 2 3 } } [ [ 1 1 ] dip concat >float-array glUniformMatrix3x2fv ] } + { { float-uniform { 3 3 } } [ [ 1 1 ] dip concat >float-array glUniformMatrix3fv ] } + { { float-uniform { 4 3 } } [ [ 1 1 ] dip concat >float-array glUniformMatrix3x4fv ] } + + { { float-uniform { 2 4 } } [ [ 1 1 ] dip concat >float-array glUniformMatrix4x2fv ] } + { { float-uniform { 3 4 } } [ [ 1 1 ] dip concat >float-array glUniformMatrix4x3fv ] } + { { float-uniform { 4 4 } } [ [ 1 1 ] dip concat >float-array glUniformMatrix4fv ] } + + { { texture-uniform 1 } { drop texture-unit glUniform1i } } + } at [ uniform invalid-uniform-type ] unless* >quotation :> value-quot + + uniform uniform-type>> texture-uniform = + [ texture-unit 1 + ] [ texture-unit ] if + pre-quot value-quot append ; + +:: [bind-uniforms] ( superclass uniforms -- quot ) + superclass "uniform-tuple-texture-units" word-prop 0 or :> first-texture-unit + superclass \ bind-uniforms method :> next-method + first-texture-unit uniforms [ [bind-uniform] ] map nip :> uniforms-cleave + + { + 2dup next-method + uniforms-cleave 2cleave + } >quotation ; + +: define-uniform-tuple-methods ( class superclass uniforms -- ) + [ + [ \ bind-uniform-textures create-method-in ] 2dip + [bind-uniform-textures] define + ] [ + [ \ bind-uniforms create-method-in ] 2dip + [bind-uniforms] define + ] 3bi ; + +: parse-uniform-tuple-definition ( -- class superclass uniforms ) + CREATE-CLASS scan { + { ";" [ uniform-tuple f ] } + { "<" [ scan-word parse-definition [ first3 uniform boa ] map ] } + { "{" [ + uniform-tuple + \ } parse-until parse-definition swap prefix + [ first3 uniform boa ] map + ] } + } case ; + +: component-type>c-type ( component-type -- c-type ) + { + { ubyte-components [ "uchar" ] } + { ushort-components [ "ushort" ] } + { uint-components [ "uint" ] } + { half-components [ "half" ] } + { float-components [ "float" ] } + { byte-integer-components [ "char" ] } + { ubyte-integer-components [ "uchar" ] } + { short-integer-components [ "short" ] } + { ushort-integer-components [ "ushort" ] } + { int-integer-components [ "int" ] } + { uint-integer-components [ "uint" ] } + } case ; + +: c-array-dim ( dim -- string ) + dup 1 = [ drop "" ] [ number>string "[" "]" surround ] if ; + +SYMBOL: padding-no +padding-no [ 0 ] initialize + +: padding-name ( -- name ) + "padding-" + padding-no get number>string append + "(" ")" surround + padding-no inc ; + +: vertex-attribute>c-type ( vertex-attribute -- {type,name} ) + [ + [ component-type>> component-type>c-type ] + [ dim>> c-array-dim ] bi append + ] [ name>> [ padding-name ] unless* ] bi 2array ; + +: (define-uniform-tuple) ( class superclass uniforms -- ) + { + [ [ uniform>slot ] map define-tuple-class ] + [ define-uniform-tuple-methods ] + [ + [ "uniform-tuple-texture-units" word-prop 0 or ] + [ [ uniform-type>> texture-uniform = ] filter length ] bi* + + "uniform-tuple-texture-units" set-word-prop + ] + [ nip "uniform-tuple-slots" set-word-prop ] + } 3cleave ; + +: true-subclasses ( class -- seq ) + [ subclasses ] keep [ = not ] curry filter ; + +: redefine-uniform-tuple-subclass-methods ( class -- ) + [ true-subclasses ] keep + [ over "uniform-tuple-slots" word-prop (define-uniform-tuple) ] curry each ; + +PRIVATE> + +: define-vertex-format ( class vertex-attributes -- ) + [ + [ + [ define-singleton-class ] + [ vertex-format add-mixin-instance ] + [ ] tri + ] [ define-vertex-format-methods ] bi* + ] + [ "vertex-format-attributes" set-word-prop ] 2bi ; + +SYNTAX: VERTEX-FORMAT: + CREATE-CLASS parse-definition + [ first4 vertex-attribute boa ] map + define-vertex-format ; + +: define-vertex-struct ( struct-name vertex-format -- ) + [ current-vocab ] dip + "vertex-format-attributes" word-prop [ vertex-attribute>c-type ] map + define-struct ; + +SYNTAX: VERTEX-STRUCT: + scan scan-word define-vertex-struct ; + +: define-uniform-tuple ( class superclass uniforms -- ) + [ (define-uniform-tuple) ] + [ 2drop redefine-uniform-tuple-subclass-methods ] 3bi ; + +SYNTAX: UNIFORM-TUPLE: + parse-uniform-tuple-definition define-uniform-tuple ; + +TUPLE: vertex-array < gpu-object + { program-instance program-instance read-only } + { vertex-buffers sequence read-only } ; + +M: vertex-array dispose + [ [ delete-vertex-array ] when* f ] change-handle drop ; + +: ( program-instance vertex-formats -- vertex-array ) + gen-vertex-array + [ glBindVertexArray [ first2 bind-vertex-format ] with each ] + [ -rot [ first buffer>> ] map vertex-array boa ] 3bi + window-resource ; + +: buffer>vertex-array ( vertex-buffer program-instance format -- vertex-array ) + [ swap ] dip + [ 0 ] dip 2array 1array ; inline + +: vertex-array-buffer ( vertex-array -- vertex-buffer ) + vertex-buffers>> first ; + +> glBindVertexArray ; + +: bind-unnamed-output-attachments ( framebuffer attachments -- ) + [ gl-attachment ] with map + dup length 1 = + [ first glDrawBuffer ] + [ [ length ] [ >int-array ] bi glDrawBuffers ] if ; + +: bind-named-output-attachments ( program-instance framebuffer attachments -- ) + rot '[ [ first _ swap output-index ] bi@ <=> ] sort [ second ] map + bind-unnamed-output-attachments ; + +: bind-output-attachments ( program-instance framebuffer attachments -- ) + dup first sequence? + [ bind-named-output-attachments ] [ [ drop ] 2dip bind-unnamed-output-attachments ] if ; + +PRIVATE> + +TUPLE: render-set + { primitive-mode primitive-mode } + { vertex-array vertex-array } + { uniforms uniform-tuple } + { indexes vertex-indexes initial: T{ index-range } } + { instances ?integer initial: f } + { framebuffer any-framebuffer initial: system-framebuffer } + { output-attachments sequence initial: { default-attachment } } ; + +: render ( render-set -- ) + { + [ vertex-array>> program-instance>> handle>> glUseProgram ] + [ + [ vertex-array>> program-instance>> ] [ uniforms>> ] bi + [ bind-uniform-textures ] [ bind-uniforms ] 2bi + ] + [ GL_DRAW_FRAMEBUFFER swap framebuffer>> framebuffer-handle glBindFramebuffer ] + [ + [ vertex-array>> program-instance>> ] + [ framebuffer>> ] + [ output-attachments>> ] tri + bind-output-attachments + ] + [ vertex-array>> bind-vertex-array ] + [ + [ primitive-mode>> ] [ indexes>> ] [ instances>> ] tri + [ render-vertex-indexes-instanced ] + [ render-vertex-indexes ] if* + ] + } cleave ; inline + diff --git a/extra/gpu/render/summary.txt b/extra/gpu/render/summary.txt new file mode 100644 index 0000000000..d4b9e71f32 --- /dev/null +++ b/extra/gpu/render/summary.txt @@ -0,0 +1 @@ +Execution of GPU jobs diff --git a/extra/gpu/shaders/authors.txt b/extra/gpu/shaders/authors.txt new file mode 100644 index 0000000000..f13c9c1e77 --- /dev/null +++ b/extra/gpu/shaders/authors.txt @@ -0,0 +1 @@ +Joe Groff diff --git a/extra/gpu/shaders/prettyprint/authors.txt b/extra/gpu/shaders/prettyprint/authors.txt new file mode 100644 index 0000000000..f13c9c1e77 --- /dev/null +++ b/extra/gpu/shaders/prettyprint/authors.txt @@ -0,0 +1 @@ +Joe Groff diff --git a/extra/gpu/shaders/prettyprint/prettyprint.factor b/extra/gpu/shaders/prettyprint/prettyprint.factor new file mode 100644 index 0000000000..128333ce3c --- /dev/null +++ b/extra/gpu/shaders/prettyprint/prettyprint.factor @@ -0,0 +1,12 @@ +USING: accessors debugger gpu.shaders io kernel prettyprint ; +IN: gpu.shaders.prettyprint + +M: compile-shader-error error. + "The GLSL shader " write + [ shader>> name>> pprint-short " failed to compile." write nl ] + [ log>> write nl ] bi ; + +M: link-program-error error. + "The GLSL program " write + [ shader>> name>> pprint-short " failed to link." write nl ] + [ log>> write nl ] bi ; diff --git a/extra/gpu/shaders/shaders-docs.factor b/extra/gpu/shaders/shaders-docs.factor new file mode 100755 index 0000000000..cac61114d6 --- /dev/null +++ b/extra/gpu/shaders/shaders-docs.factor @@ -0,0 +1,116 @@ +! (c)2009 Joe Groff bsd license +USING: help.markup help.syntax kernel math multiline quotations strings ; +IN: gpu.shaders + +HELP: +{ $values + { "program" program } + { "instance" program-instance } +} +{ $description "Compiles and links an instance of " { $snippet "program" } " for the current graphics context. If an instance already exists for " { $snippet "program" } " in the current context, it is reused." } ; + +HELP: +{ $values + { "shader" shader } + { "instance" shader-instance } +} +{ $description "Compiles an instance of " { $snippet "shader" } " for the current graphics context. If an instance already exists for " { $snippet "shader" } " in the current context, it is reused." } ; + +HELP: GLSL-PROGRAM: +{ $syntax "GLSL-PROGRAM: program-name shader shader ... shader ;" } +{ $description "Defines a new " { $link program } " named " { $snippet "program-name" } ". When the program is instantiated with " { $link } ", it will link together instances of all of the specified " { $link shader } "s to create the program instance." } ; + +HELP: GLSL-SHADER-FILE: +{ $syntax "GLSL-SHADER-FILE: shader-name shader-kind \"filename\"" } +{ $description "Defines a new " { $link shader } " of kind " { $link shader-kind } " named " { $snippet "shader-name" } ". The shader will read its source code from " { $snippet "filename" } " in the current Factor source file's directory." } ; + +HELP: GLSL-SHADER: +{ $syntax <" GLSL-SHADER-FILE: shader-name shader-kind + +shader source + +; "> } +{ $description "Defines a new " { $link shader } " of kind " { $link shader-kind } " named " { $snippet "shader-name" } ". The shader will read its source code from the current Factor source file between the " { $snippet "GLSL-SHADER:" } " line and the first subsequent line with a single semicolon on it." } ; + +{ POSTPONE: GLSL-PROGRAM: POSTPONE: GLSL-SHADER-FILE: POSTPONE: GLSL-SHADER: } related-words + +HELP: attribute-index +{ $values + { "program-instance" program-instance } { "attribute-name" string } + { "index" integer } +} +{ $description "Returns the numeric index of the vertex attribute named " { $snippet "attribute-name" } " in " { $snippet "program-instance" } "." } ; + +HELP: compile-shader-error +{ $class-description "An error compiling the source for a " { $link shader } "." +{ $list +{ "The " { $snippet "shader" } " slot indicates the shader that failed to compile." } +{ "The " { $snippet "log" } " slot contains the error string from the GLSL compiler." } +} } ; + +HELP: fragment-shader +{ $class-description "This " { $link shader-kind } " indicates that a " { $link shader } " is a fragment shader." } ; + +HELP: link-program-error +{ $class-description "An error linking the constituent shaders of a " { $link program } "." +{ $list +{ "The " { $snippet "program" } " slot indicates the program that failed to link." } +{ "The " { $snippet "log" } " slot contains the error string from the GLSL linker." } +} } ; + +{ compile-shader-error link-program-error } related-words + +HELP: output-index +{ $values + { "program-instance" program-instance } { "output-name" string } + { "index" integer } +} +{ $description "Returns the numeric index of the fragment shader output named " { $snippet "output-name" } " in " { $snippet "program-instance" } "." } +{ $notes "Named fragment shader outputs require OpenGL 3.0 or later and GLSL 1.30 or later, or OpenGL 2.0 or later and GLSL 1.20 or earlier with the " { $snippet "GL_EXT_gpu_shader4" } " extension." } ; + +HELP: program +{ $class-description "A " { $snippet "program" } " provides a specification for linking a " { $link program-instance } " in a graphics context. Programs are defined with " { $link POSTPONE: GLSL-PROGRAM: } " and instantiated in a context with " { $link } "." } ; + +HELP: program-instance +{ $class-description "A " { $snippet "program-instance" } " is a shader " { $link program } " that has been compiled and linked for a graphics context using " { $link } "." } ; + +HELP: refresh-program +{ $values + { "program" program } +} +{ $description "Rereads the source code for every " { $link shader } " in " { $link program } " and attempts to refresh all the existing " { $link shader-instance } "s and " { $link program-instance } "s for those programs. If the new source code fails to compile or link, the existing instances are untouched; otherwise, they are updated on the fly to reference the newly compiled code." } ; + +HELP: shader +{ $class-description "A " { $snippet "shader" } " provides a block of GLSL source code that can be compiled into a " { $link shader-instance } " in a graphics context. Shaders are defined with " { $link POSTPONE: GLSL-SHADER: } " or " { $link POSTPONE: GLSL-SHADER-FILE: } " and instantiated in a context with " { $link } "." } ; + +HELP: shader-instance +{ $class-description "A " { $snippet "shader-instance" } " is a " { $link shader } " that has been compiled for a graphics context using " { $link } "." } ; + +HELP: shader-kind +{ $class-description "A " { $snippet "shader-kind" } " value is passed as part of a " { $link POSTPONE: GLSL-SHADER: } " or " { $link POSTPONE: GLSL-SHADER-FILE: } " definition to indicate the kind of " { $link shader } " being defined." +{ $list +{ { $link vertex-shader } "s run during primitive assembly and map input vertex data to positions in screen space for rasterization." } +{ { $link fragment-shader } "s run as part of rasterization and decide the final rendered output of a primitive as the outputs of the vertex shader are interpolated across its surface." } +} } ; + +HELP: uniform-index +{ $values + { "program-instance" program-instance } { "uniform-name" string } + { "index" integer } +} +{ $description "Returns the numeric index of the uniform parameter named " { $snippet "output-name" } " in " { $snippet "program-instance" } "." } ; + +HELP: vertex-shader +{ $class-description "This " { $link shader-kind } " indicates that a " { $link shader } " is a vertex shader." } ; + +ARTICLE: "gpu.shaders" "Shader objects" +"The " { $vocab-link "gpu.shaders" } " vocabulary supports defining, compiling, and linking " { $link shader } "s into " { $link program } "s that run on the GPU and control rendering." +{ $subsection POSTPONE: GLSL-PROGRAM: } +{ $subsection POSTPONE: GLSL-SHADER: } +{ $subsection POSTPONE: GLSL-SHADER-FILE: } +"A program must be instantiated for each graphics context it is used in:" +{ $subsection } +"Program instances can be updated on the fly, allowing for interactive development of shaders:" +{ $subsection refresh-program } ; + +ABOUT: "gpu.shaders" diff --git a/extra/gpu/shaders/shaders-tests.factor b/extra/gpu/shaders/shaders-tests.factor new file mode 100644 index 0000000000..38c70e57b2 --- /dev/null +++ b/extra/gpu/shaders/shaders-tests.factor @@ -0,0 +1,12 @@ +! (c)2009 Joe Groff bsd license +USING: multiline gpu.shaders gpu.shaders.private tools.test ; +IN: gpu.shaders.tests + +[ <" ERROR: foo.factor:20: Bad command or filename +INFO: foo.factor:30: The operation completed successfully +NOT:A:LOG:LINE "> ] +[ T{ shader { filename "foo.factor" } { line 19 } } +<" ERROR: 0:1: Bad command or filename +INFO: 0:11: The operation completed successfully +NOT:A:LOG:LINE "> replace-log-line-numbers ] unit-test + diff --git a/extra/gpu/shaders/shaders.factor b/extra/gpu/shaders/shaders.factor new file mode 100755 index 0000000000..e11fa639b4 --- /dev/null +++ b/extra/gpu/shaders/shaders.factor @@ -0,0 +1,208 @@ +! (c)2009 Joe Groff bsd license +USING: accessors arrays assocs combinators +combinators.short-circuit definitions destructors gpu +io.encodings.ascii io.files io.pathnames kernel lexer +locals math math.parser memoize multiline namespaces +opengl.gl opengl.shaders parser sequences +specialized-arrays.int splitting strings ui.gadgets.worlds +variants hashtables vectors vocabs vocabs.loader words +words.constant ; +IN: gpu.shaders + +VARIANT: shader-kind + vertex-shader fragment-shader ; + +TUPLE: shader + { name word read-only initial: t } + { kind shader-kind read-only } + { filename read-only } + { line integer read-only } + { source string } + { instances hashtable read-only } ; + +TUPLE: program + { name word read-only initial: t } + { filename read-only } + { line integer read-only } + { shaders array read-only } + { instances hashtable read-only } ; + +TUPLE: shader-instance < gpu-object + { shader shader } + { world world } ; + +TUPLE: program-instance < gpu-object + { program program } + { world world } ; + +> [ nip ] [ name>> where first ] if* file-name ; + +: numbered-log-line? ( log-line-components -- ? ) + { + [ length 4 >= ] + [ third string>number ] + } 1&& ; + +: replace-log-line-number ( object log-line -- log-line' ) + ":" split dup numbered-log-line? [ + { + [ nip first ] + [ drop shader-filename " " prepend ] + [ [ line>> ] [ third string>number ] bi* + number>string ] + [ nip 3 tail ] + } 2cleave [ 3array ] dip append + ] [ nip ] if ":" join ; + +: replace-log-line-numbers ( object log -- log' ) + "\n" split [ empty? not ] filter + [ replace-log-line-number ] with map + "\n" join ; + +: gl-shader-kind ( shader-kind -- shader-kind ) + { + { vertex-shader [ GL_VERTEX_SHADER ] } + { fragment-shader [ GL_FRAGMENT_SHADER ] } + } case ; + +PRIVATE> + +TUPLE: compile-shader-error shader log ; +TUPLE: link-program-error program log ; + +: compile-shader-error ( shader instance -- * ) + [ dup ] dip [ gl-shader-info-log ] [ delete-gl-shader ] bi replace-log-line-numbers + \ compile-shader-error boa throw ; + +: link-program-error ( program instance -- * ) + [ dup ] dip [ gl-program-info-log ] [ delete-gl-program ] bi replace-log-line-numbers + \ link-program-error boa throw ; + +DEFER: + +MEMO: uniform-index ( program-instance uniform-name -- index ) + [ handle>> ] dip glGetUniformLocation ; +MEMO: attribute-index ( program-instance attribute-name -- index ) + [ handle>> ] dip glGetAttribLocation ; +MEMO: output-index ( program-instance output-name -- index ) + [ handle>> ] dip glGetFragDataLocation ; + +> ] [ kind>> gl-shader-kind ] tri + dup gl-shader-ok? + [ swap world get \ shader-instance boa window-resource ] + [ compile-shader-error ] if ; + +: (link-program) ( program shader-instances -- program-instance ) + [ handle>> ] map + dup gl-program-ok? + [ swap world get \ program-instance boa window-resource ] + [ link-program-error ] if ; + +: link-program ( program -- program-instance ) + dup shaders>> [ ] map (link-program) ; + +: in-word's-path ( word kind filename -- word kind filename' ) + [ over ] dip [ where first parent-directory ] dip append-path ; + +: become-shader-instance ( shader-instance new-shader-instance -- ) + handle>> [ swap delete-gl-shader ] curry change-handle drop ; + +: refresh-shader-source ( shader -- ) + dup filename>> + [ ascii file-contents >>source drop ] + [ drop ] if* ; + +: become-program-instance ( program-instance new-program-instance -- ) + handle>> [ swap delete-gl-program-only ] curry change-handle drop ; + +: reset-memos ( -- ) + \ uniform-index reset-memoized + \ attribute-index reset-memoized + \ output-index reset-memoized ; + +: ?delete-at ( key assoc value -- ) + 2over at = [ delete-at ] [ 2drop ] if ; + +: find-shader-instance ( shader -- instance ) + world get over instances>> at* + [ nip ] [ drop compile-shader ] if ; + +: find-program-instance ( program -- instance ) + world get over instances>> at* + [ nip ] [ drop link-program ] if ; + +PRIVATE> + +:: refresh-program ( program -- ) + program shaders>> [ refresh-shader-source ] each + program instances>> [| world old-instance | + old-instance valid-handle? [ + world [ + [ + program shaders>> [ compile-shader |dispose ] map :> new-shader-instances + program new-shader-instances (link-program) |dispose :> new-program-instance + + old-instance new-program-instance become-program-instance + new-shader-instances [| new-shader-instance | + world new-shader-instance shader>> instances>> at + new-shader-instance become-shader-instance + ] each + ] with-destructors + ] with-gl-context + ] when + ] assoc-each + reset-memos ; + +: ( shader -- instance ) + [ find-shader-instance dup world get ] keep instances>> set-at ; + +: ( program -- instance ) + [ find-program-instance dup world get ] keep instances>> set-at ; + +SYNTAX: GLSL-SHADER: + CREATE-WORD dup + scan-word + f + lexer get line>> + parse-here + H{ } clone + shader boa + define-constant ; + +SYNTAX: GLSL-SHADER-FILE: + CREATE-WORD dup + scan-word execute( -- kind ) + scan-object in-word's-path + 0 + over ascii file-contents + H{ } clone + shader boa + define-constant ; + +SYNTAX: GLSL-PROGRAM: + CREATE-WORD dup + f + lexer get line>> + \ ; parse-until >array [ def>> first ] map + H{ } clone + program boa + define-constant ; + +M: shader-instance dispose + [ dup valid-handle? [ delete-gl-shader ] [ drop ] if f ] change-handle + [ world>> ] [ shader>> instances>> ] [ ] tri ?delete-at ; + +M: program-instance dispose + [ dup valid-handle? [ delete-gl-program-only ] [ drop ] if f ] change-handle + [ world>> ] [ program>> instances>> ] [ ] tri ?delete-at + reset-memos ; + +"prettyprint" vocab [ "gpu.shaders.prettyprint" require ] when diff --git a/extra/gpu/shaders/summary.txt b/extra/gpu/shaders/summary.txt new file mode 100644 index 0000000000..67a467ab4c --- /dev/null +++ b/extra/gpu/shaders/summary.txt @@ -0,0 +1 @@ +GPU programs that control vertex transformation and shading diff --git a/extra/gpu/state/authors.txt b/extra/gpu/state/authors.txt new file mode 100644 index 0000000000..f13c9c1e77 --- /dev/null +++ b/extra/gpu/state/authors.txt @@ -0,0 +1 @@ +Joe Groff diff --git a/extra/gpu/state/state-docs.factor b/extra/gpu/state/state-docs.factor new file mode 100755 index 0000000000..a989e14b0b --- /dev/null +++ b/extra/gpu/state/state-docs.factor @@ -0,0 +1,622 @@ +! (c)2009 Joe Groff bsd license +USING: help.markup help.syntax kernel math math.rectangles multiline sequences ; +IN: gpu.state + +HELP: +{ $values + { "equation" blend-equation } { "source-function" blend-function } { "dest-function" blend-function } + { "blend-mode" blend-mode } +} +{ $description "Constructs a " { $link blend-mode } " tuple." } ; + +{ blend-mode } related-words + +HELP: +{ $values + { "constant-color" sequence } { "rgb-mode" { $maybe blend-mode } } { "alpha-mode" { $maybe blend-mode } } + { "blend-state" blend-state } +} +{ $description "Constructs a " { $link blend-state } " tuple." } ; + +{ blend-state get-blend-state } related-words + +HELP: +{ $values + { "near" float } { "far" float } + { "depth-range-state" depth-range-state } +} +{ $description "Constructs a " { $link depth-range-state } " tuple." } ; + +{ depth-range-state get-depth-range-state } related-words + +HELP: +{ $values + { "comparison" comparison } + { "depth-state" depth-state } +} +{ $description "Constructs a " { $link depth-state } " tuple." } ; + +{ depth-state get-depth-state } related-words + +HELP: +{ $values + { "width" float } { "antialias?" boolean } + { "line-state" line-state } +} +{ $description "Constructs a " { $link line-state } " tuple." } ; + +{ line-state get-line-state } related-words + +HELP: +{ $values + { "color" sequence } { "depth" boolean } { "stencil-front" boolean } { "stencil-back" boolean } + { "mask-state" mask-state } +} +{ $description "Constructs a " { $link mask-state } " tuple." } ; + +{ mask-state get-mask-state } related-words + +HELP: +{ $values + { "multisample?" boolean } { "sample-alpha-to-coverage?" boolean } { "sample-alpha-to-one?" boolean } { "sample-coverage" { $maybe float } } { "invert-sample-coverage?" boolean } + { "multisample-state" multisample-state } +} +{ $description "Constructs a " { $link multisample-state } " tuple." } ; + +{ multisample-state get-multisample-state } related-words + +HELP: +{ $values + { "size" { $maybe float } } { "sprite-origin" point-sprite-origin } { "fade-threshold" float } + { "point-state" point-state } +} +{ $description "Constructs a " { $link point-state } " tuple." } ; + +{ point-state get-point-state } related-words + +HELP: +{ $values + { "rect" { $maybe rect } } + { "scissor-state" scissor-state } +} +{ $description "Constructs a " { $link scissor-state } " tuple." } ; + +{ scissor-state get-scissor-state } related-words + +HELP: +{ $values + { "value" integer } { "mask" integer } { "comparison" comparison } { "stencil-fail-op" stencil-op } { "depth-fail-op" stencil-op } { "depth-pass-op" stencil-op } + { "stencil-mode" stencil-mode } +} +{ $description "Constructs a " { $link stencil-mode } " tuple." } ; + +{ stencil-mode } related-words + +HELP: +{ $values + { "front-mode" { $maybe stencil-mode } } { "back-mode" { $maybe stencil-mode } } + { "stencil-state" stencil-state } +} +{ $description "Constructs a " { $link stencil-state } " tuple." } ; + +{ stencil-state get-stencil-state } related-words + +HELP: +{ $values + { "front-face" triangle-face } { "cull" { $maybe triangle-cull } } + { "triangle-cull-state" triangle-cull-state } +} +{ $description "Constructs a " { $link triangle-cull-state } " tuple." } ; + +{ triangle-cull-state get-triangle-cull-state } related-words + +HELP: +{ $values + { "front-mode" triangle-mode } { "back-mode" triangle-mode } { "antialias?" boolean } + { "triangle-state" triangle-state } +} +{ $description "Constructs a " { $link triangle-state } " tuple." } ; + +{ triangle-state get-triangle-state } related-words + +HELP: +{ $values + { "rect" rect } + { "viewport-state" viewport-state } +} +{ $description "Constructs a " { $link viewport-state } " tuple." } ; + +{ viewport-state get-viewport-state } related-words + +HELP: blend-equation +{ $class-description "The " { $snippet "blend-equation" } " of a " { $link blend-mode } " determines how the source and destination color values are combined after they have been multiplied by the result of their respective " { $link blend-function } "s." +{ $list +{ { $link eq-add } " indicates that the source and destination results are added." } +{ { $link eq-subtract } " indicates that the destination result is subtracted from the source." } +{ { $link eq-reverse-subtract } " indicates that the source result is subtracted from the destination." } +{ { $link eq-min } " indicates that the componentwise minimum of the source and destination results is taken." } +{ { $link eq-max } " indicates that the componentwise maximum of the source and destination results is taken." } +} } ; + +HELP: blend-function +{ $class-description "The " { $snippet "blend-function" } "s of a " { $link blend-mode } " multiply the source and destination colors being blended by a function of their values before they are combined by the " { $link blend-equation } "." +{ $list + { { $link func-zero } " returns a constant factor of zero." } + { { $link func-one } " returns a constant factor of one." } + { { $link func-source } " returns the corresponding source color component for every result component." } + { { $link func-one-minus-source } " returns one minus the corresponding source color component for every result component." } + { { $link func-dest } " returns the corresponding destination color component for every result component." } + { { $link func-one-minus-dest } " returns one minus the corresponding destination color component for every result component." } + { { $link func-constant } " returns the corresponding component of the current " { $link blend-state } "'s " { $snippet "constant-color" } " for every result component." } + { { $link func-one-minus-constant } " returns one minus the corresponding component of the current " { $link blend-state } "'s " { $snippet "constant-color" } " for every result component." } + { { $link func-source-alpha } " returns the source alpha component for every result component." } + { { $link func-one-minus-source-alpha } " returns one minus the source alpha component for every result component." } + { { $link func-dest-alpha } " returns the destination alpha component for every result component." } + { { $link func-one-minus-dest-alpha } " returns one minus the destination alpha component for every result component." } + { { $link func-constant-alpha } " returns the alpha component of the current " { $link blend-state } "'s " { $snippet "constant-color" } " for every result component." } + { { $link func-one-minus-constant-alpha } " returns one minus the alpha component of the current " { $link blend-state } "'s " { $snippet "constant-color" } " for every result component." } +} } ; + +HELP: blend-mode +{ $class-description "A " { $link blend-mode } " is specified as part of the " { $link blend-state } " to determine the blending equation used between the source (incoming fragment) and destination (existing framebuffer value) colors of blended pixels." +{ $list +{ "The " { $snippet "equation" } " slot determines how the source and destination colors are combined after the " { $snippet "source-function" } " and " { $snippet "dest-function" } " have been applied." + { $list + { { $link eq-add } " indicates that the source and destination results are added." } + { { $link eq-subtract } " indicates that the destination result is subtracted from the source." } + { { $link eq-reverse-subtract } " indicates that the source result is subtracted from the destination." } + { { $link eq-min } " indicates that the componentwise minimum of the source and destination results is taken." } + { { $link eq-max } " indicates that the componentwise maximum of the source and destination results is taken." } + } +} +{ "The " { $snippet "source-function" } " and " { $snippet "dest-function" } " slots each specify a function to apply to the source, destination, or constant color values to generate a blending factor that is multiplied respectively against the source or destination value before feeding the results to the " { $snippet "equation" } "." +} + { $list + { { $link func-zero } " returns a constant factor of zero." } + { { $link func-one } " returns a constant factor of one." } + { { $link func-source } " returns the corresponding source color component for every result component." } + { { $link func-one-minus-source } " returns one minus the corresponding source color component for every result component." } + { { $link func-dest } " returns the corresponding destination color component for every result component." } + { { $link func-one-minus-dest } " returns one minus the corresponding destination color component for every result component." } + { { $link func-constant } " returns the corresponding component of the current " { $link blend-state } "'s " { $snippet "constant-color" } " for every result component." } + { { $link func-one-minus-constant } " returns one minus the corresponding component of the current " { $link blend-state } "'s " { $snippet "constant-color" } " for every result component." } + { { $link func-source-alpha } " returns the source alpha component for every result component." } + { { $link func-one-minus-source-alpha } " returns one minus the source alpha component for every result component." } + { { $link func-dest-alpha } " returns the destination alpha component for every result component." } + { { $link func-one-minus-dest-alpha } " returns one minus the destination alpha component for every result component." } + { { $link func-constant-alpha } " returns the alpha component of the current " { $link blend-state } "'s " { $snippet "constant-color" } " for every result component." } + { { $link func-one-minus-constant-alpha } " returns one minus the alpha component of the current " { $link blend-state } "'s " { $snippet "constant-color" } " for every result component." } +} +"A typical transparency effect will use the values:" +{ $code <" T{ blend-mode + { equation eq-add } + { source-function func-source-alpha } + { dest-function func-one-minus-source-alpha } +} "> } +} } ; + +HELP: blend-state +{ $class-description "The " { $snippet "blend-state" } " controls how alpha blending between the current framebuffer contents and newly drawn pixels." +{ $list +{ "The " { $snippet "constant-color" } " slot contains an optional four-" { $link float } " sequence that specifies a constant parameter to the " { $snippet "func-*constant*" } " " { $link blend-function } "s. If constant blend functions are not used, the slot can be " { $link f } "." } +{ "The " { $snippet "rgb-mode" } " and " { $snippet "alpha-mode" } " slots both contain " { $link blend-mode } " values that determine the blending equation used between RGB and alpha channel values, respectively. If both slots are " { $link f } ", blending is disabled." } +} } ; + +HELP: cmp-always +{ $class-description "This " { $link comparison } " test always succeeds." } ; + +HELP: cmp-equal +{ $class-description "This " { $link comparison } " test succeeds if the compared values are equal." } ; + +HELP: cmp-greater +{ $class-description "This " { $link comparison } " test succeeds if the incoming value is greater than the buffer value." } ; + +HELP: cmp-greater-equal +{ $class-description "This " { $link comparison } " test succeeds if the incoming value is greater than or equal to the buffer value." } ; + +HELP: cmp-less +{ $class-description "This " { $link comparison } " test succeeds if the incoming value is less than the buffer value." } ; + +HELP: cmp-less-equal +{ $class-description "This " { $link comparison } " test succeeds if the incoming value is less than or equal to the buffer value." } ; + +HELP: cmp-never +{ $class-description "This " { $link comparison } " test always fails." } ; + +HELP: cmp-not-equal +{ $class-description "This " { $link comparison } " test succeeds if the compared values are not equal." } ; + +HELP: comparison +{ $class-description { $snippet "comparison" } " values are used in the " { $link stencil-state } " and " { $link depth-state } " and control how the fragment stencil and depth tests are performed. For the stencil test, a reference value (the " { $snippet "value" } " slot of the active " { $link stencil-mode } ") is compared to the stencil buffer value using the comparison operator. For the depth test, the incoming fragment depth is compared to the depth buffer value." +{ $list +{ { $link cmp-always } " always succeeds." } +{ { $link cmp-never } " always fails." } +{ { $link cmp-equal } " succeeds if the compared values are equal." } +{ { $link cmp-not-equal } " succeeds if the compared values are not equal." } +{ { $link cmp-less } " succeeds if the incoming value is less than the buffer value." } +{ { $link cmp-less-equal } " succeeds if the incoming value is less than or equal to the buffer value." } +{ { $link cmp-greater } " succeeds if the incoming value is greater than the buffer value." } +{ { $link cmp-greater-equal } " succeeds if the incoming value is greater than or equal to the buffer value." } +} } ; + +HELP: cull-all +{ $class-description "This " { $link triangle-cull } " value culls all triangles." } ; + +HELP: cull-back +{ $class-description "This " { $link triangle-cull } " value culls back-facing triangles." } ; + +HELP: cull-front +{ $class-description "This " { $link triangle-cull } " value culls front-facing triangles." } ; + +HELP: depth-range-state +{ $class-description "The " { $snippet "depth-range-state" } " controls the range of depth values that are generated for fragments and used for depth testing and writing to the depth buffer." +{ $list +{ "The " { $snippet "near" } " slot contains a " { $link float } " value that will be assigned to fragments on the near plane. The default value is " { $snippet "0.0" } "." } +{ "The " { $snippet "far" } " slot contains a " { $link float } " value that will be assigned to fragments on the far plane. The default value is " { $snippet "1.0" } "." } +} } ; + +HELP: depth-state +{ $class-description "The " { $snippet "depth-state" } " controls how incoming fragments' depth values are tested against the depth buffer. The " { $link comparison } " slot, if not " { $link f } ", determines the condition that must be true between the incoming fragment depth and depth buffer depth to pass a fragment. If the " { $snippet "comparison" } " is " { $link f } ", depth testing is disabled and all fragments pass. " { $link cmp-less } " is typically used for depth culling." } ; + +HELP: eq-add +{ $var-description "This " { $link blend-equation } " adds the source and destination colors together." } ; + +HELP: eq-max +{ $var-description "This " { $link blend-equation } " takes the componentwise maximum of the source and destination colors." } ; + +HELP: eq-min +{ $var-description "This " { $link blend-equation } " takes the componentwise minimum of the source and destination colors." } ; + +HELP: eq-reverse-subtract +{ $var-description "This " { $link blend-equation } " subtracts the source color from the destination color." } ; + +HELP: eq-subtract +{ $var-description "This " { $link blend-equation } " subtracts the destination color from the source color." } ; + +HELP: face-ccw +{ $class-description "This " { $link triangle-face } " value refers to the face with counterclockwise-wound vertices." } ; + +HELP: face-cw +{ $class-description "This " { $link triangle-face } " value refers to the face with clockwise-wound vertices." } ; + +HELP: func-constant +{ $class-description "This " { $link blend-function } " componentwise multiplies the input color by the current " { $link blend-state } "'s " { "constant-color" } " slot value." } ; + +HELP: func-constant-alpha +{ $class-description "This " { $link blend-function } " multiplies the input color by the alpha component of the current " { $link blend-state } "'s " { "constant-color" } " slot value." } ; + +HELP: func-dest +{ $class-description "This " { $link blend-function } " componentwise multiplies the input color by the destination color value." } ; + +HELP: func-dest-alpha +{ $class-description "This " { $link blend-function } " componentwise multiplies the input color by the alpha component of the destination color value." } ; + +HELP: func-one +{ $class-description "This " { $link blend-function } " multiplies the input color by one; that is, the input color is unchanged." } ; + +HELP: func-one-minus-constant +{ $class-description "This " { $link blend-function } " componentwise multiplies the input color by one minus the current " { $link blend-state } "'s " { "constant-color" } " slot value." } ; + +HELP: func-one-minus-constant-alpha +{ $class-description "This " { $link blend-function } " multiplies the input color by one minus the alpha component of the current " { $link blend-state } "'s " { "constant-color" } " slot value." } ; + +HELP: func-one-minus-dest +{ $class-description "This " { $link blend-function } " componentwise multiplies the input color by one minus the destination color value." } ; + +HELP: func-one-minus-dest-alpha +{ $class-description "This " { $link blend-function } " multiplies the input color by one minus the alpha component of the destination color value." } ; + +HELP: func-one-minus-source +{ $class-description "This " { $link blend-function } " componentwise multiplies the input color by one minus the source color value." } ; + +HELP: func-one-minus-source-alpha +{ $class-description "This " { $link blend-function } " multiplies the input color by one minus the alpha component source color value." } ; + +HELP: func-source +{ $class-description "This " { $link blend-function } " componentwise multiplies the input color by the source color value." } ; + +HELP: func-source-alpha +{ $class-description "This " { $link blend-function } " multiplies the input color by the alpha component of the source color value." } ; + +HELP: func-source-alpha-saturate +{ $class-description "This " { $link blend-function } " multiplies the input color by the minimum of the alpha component of the source color value and one minus the alpha component of the destination color value. It is only valid as the " { $snippet "source-function" } " of a " { $link blend-mode } "." } ; + +HELP: func-zero +{ $class-description "This " { $link blend-function } " multiplies the input color by zero." } ; + +HELP: get-blend-state +{ $values + + { "blend-state" blend-state } +} +{ $description "Retrieves the current GPU " { $link blend-state } "." } ; + +HELP: get-depth-range-state +{ $values + + { "depth-range-state" depth-range-state } +} +{ $description "Retrieves the current GPU " { $link depth-range-state } "." } ; + +HELP: get-depth-state +{ $values + + { "depth-state" depth-state } +} +{ $description "Retrieves the current GPU " { $link depth-state } "." } ; + +HELP: get-line-state +{ $values + + { "line-state" line-state } +} +{ $description "Retrieves the current GPU " { $link line-state } "." } ; + +HELP: get-mask-state +{ $values + + { "mask-state" mask-state } +} +{ $description "Retrieves the current GPU " { $link mask-state } "." } ; + +HELP: get-multisample-state +{ $values + + { "multisample-state" multisample-state } +} +{ $description "Retrieves the current GPU " { $link multisample-state } "." } ; + +HELP: get-point-state +{ $values + + { "point-state" point-state } +} +{ $description "Retrieves the current GPU " { $link point-state } "." } ; + +HELP: get-scissor-state +{ $values + + { "scissor-state" scissor-state } +} +{ $description "Retrieves the current GPU " { $link scissor-state } "." } ; + +HELP: get-stencil-state +{ $values + + { "stencil-state" stencil-state } +} +{ $description "Retrieves the current GPU " { $link stencil-state } "." } ; + +HELP: get-triangle-cull-state +{ $values + + { "triangle-cull-state" triangle-cull-state } +} +{ $description "Retrieves the current GPU " { $link triangle-cull-state } "." } ; + +HELP: get-triangle-state +{ $values + + { "triangle-state" triangle-state } +} +{ $description "Retrieves the current GPU " { $link triangle-state } "." } ; + +HELP: get-viewport-state +{ $values + + { "viewport-state" viewport-state } +} +{ $description "Retrieves the current GPU " { $link viewport-state } "." } ; + +HELP: gpu-state +{ $class-description "This class is a union of all the GPU state tuple classes that can be passed to " { $link set-gpu-state } ":" +{ $list +{ { $link viewport-state } } +{ { $link scissor-state } } +{ { $link multisample-state } } +{ { $link stencil-state } } +{ { $link depth-range-state } } +{ { $link depth-state } } +{ { $link blend-state } } +{ { $link mask-state } } +{ { $link triangle-cull-state } } +{ { $link triangle-state } } +{ { $link point-state } } +{ { $link line-state } } +} } ; + +HELP: line-state +{ $class-description "The " { $snippet "line-state" } " controls how lines are rendered." +{ $list +{ "The " { $snippet "width" } " slot is a " { $link float } " value specifying the line width in pixels." } +{ "The " { $snippet "antialias?" } " slot is a " { $link boolean } " value specifying whether line edges should be smoothed." } +} +} ; + +HELP: mask-state +{ $class-description "The " { $snippet "mask-state" } " controls what parts of the framebuffer are written to." +{ $list +{ "The " { $snippet "color" } " slot is a sequence of four " { $link boolean } " values specifying whether the red, green, blue, and alpha channels of the color buffer will be written to." } +{ "The " { $snippet "depth" } " slot is a " { $link boolean } " value specifying whether the depth buffer will be written to." } +{ "The " { $snippet "stencil-front" } " and " { $snippet "stencil-back" } " slots are " { $link integer } " values that indicate which bits of the stencil buffer will be written to for front- and back-facing triangles, respectively." } +} } ; + +HELP: multisample-state +{ $class-description "The " { $snippet "multisample-state" } " controls whether and how multisampling occurs." +{ $list +{ "The " { $snippet "multisample?" } " slot is a " { $link boolean } " value that determines whether multisampling is enabled." } +{ "The " { $snippet "sample-alpha-to-coverage?" } " slot is a " { $link boolean } " value that determines whether sample coverage values are determined from their alpha components." } +{ "The " { $snippet "sample-alpha-to-one?" } " slot is a " { $link boolean } " value that determines whether a sample's alpha value is replaced with one after its alpha-based coverage is calculated." } +{ "The " { $snippet "sample-coverage" } " slot is an optional " { $link float } " value that is used to calculate another coverage value that is then combined with the alpha-based coverage. If " { $link f } ", the alpha-based coverage is untouched." } +{ "The " { $snippet "invert-sample-coverage?" } " slot is a " { $link boolean } " value that, if true, indicates that the coverage value derived from " { $snippet "sample-coverage" } " should be inverted before being combined." } +} } ; + +HELP: op-dec-sat +{ $class-description "This " { $link stencil-op } " subtracts one from the stencil buffer value, leaving it unchanged if it is already zero." } ; + +HELP: op-dec-wrap +{ $class-description "This " { $link stencil-op } " subtracts one from the stencil buffer value, wrapping the value to the maximum storable value if it was zero." } ; + +HELP: op-inc-sat +{ $class-description "This " { $link stencil-op } " adds one to the stencil buffer value, leaving it unchanged if it is already the maximum storable value." } ; + +HELP: op-inc-wrap +{ $class-description "This " { $link stencil-op } " adds one to the stencil buffer value, wrapping the value to zero if it was the maximum storable value." } ; + +HELP: op-invert +{ $class-description "This " { $link stencil-op } " bitwise NOTs the stencil buffer value." } ; + +HELP: op-keep +{ $class-description "This " { $link stencil-op } " leaves the stencil buffer value unchanged." } ; + +HELP: op-replace +{ $class-description "This " { $link stencil-op } " sets the stencil buffer value to the reference " { $snippet "value" } "." } ; + +HELP: op-zero +{ $class-description "This " { $link stencil-op } " sets the stencil buffer value to zero." } ; + +HELP: origin-lower-left +{ "This " { $link point-sprite-origin } " value sets the point sprite coordinate origin to the lower left corner of the point and increases the Y coordinate upward." } ; + +HELP: origin-upper-left +{ "This " { $link point-sprite-origin } " value sets the point sprite coordinate origin to the upper left corner of the point and increases the Y coordinate downward." } ; + +HELP: point-sprite-origin +{ $class-description "The " { $snippet "point-sprite-origin" } " is set as part of the " { $link point-state } " and determines how point sprite coordinates are generated over the rendered area of a point." +{ $list +{ { $link origin-lower-left } " sets the coordinate origin to the lower left corner of the point and increases the Y coordinate upward." } +{ { $link origin-upper-left } " sets the coordinate origin to the upper left corner of the point and increases the Y coordinate downward." } +} } ; + +HELP: point-state +{ $class-description "The " { $snippet "point-state" } " controls how points are drawn." +{ $list +{ "The " { $snippet "size" } " slot contains either a " { $link float } " value specifying a constant pixel radius for all points drawn, or " { $link f } ", in which case the vertex shader determines the size of each point independently." } +{ "The " { $snippet "sprite-origin" } " slot contains either " { $link origin-lower-left } " or " { $link origin-upper-left } ", and determines whether the vertical point sprite coordinates fed to the fragment shader start at zero in the bottom corner and increase upward or start at zero in the upper corner and increase downward." } +{ "If multisampling is enabled in the " { $link multisample-state } ", the " { $snippet "fade-threshold" } " slot specifies a pixel width at which the multisampling implementation may fade the alpha component of point fragments." } +} } ; + +HELP: scissor-state +{ $class-description "The " { $snippet "scissor-state" } " allows rendering output to be clipped to a rectangular region of the framebuffer. If the " { $snippet "rect" } " slot is set to a " { $link rect } " value, fragments outside that rectangle will be discarded. If it is " { $link f } ", fragments are allowed anywhere on the framebuffer." } ; + +HELP: set-gpu-state +{ $values + { "states" "a " { $link sequence } " or " { $link gpu-state } } +} +{ $description "Changes the GPU state using the values passed in " { $snippet "states" } "." } ; + +HELP: set-gpu-state* +{ $values + { "state" gpu-state } +} +{ $description "Changes the GPU state using a single " { $link gpu-state } " value." } ; + +HELP: stencil-mode +{ $class-description "A " { $snippet "stencil-mode" } " is specified as part of the " { $link stencil-state } " to define the interaction between an incoming fragment and the stencil buffer." +{ $list +{ "The " { $snippet "value" } " slot contains an " { $link integer } " value that is used as the reference value for the " { $snippet "comparison" } " of the stencil test." } +{ "The " { $snippet "mask" } " slot contains an " { $link integer } " mask value that indicates which bits are relevant to the stencil test." } +{ "The " { $snippet "comparison" } " slot contains a " { $link comparison } " value that indicates the comparison taken between the masked reference value and stored stencil buffer value to determine whether the fragment is allowed to pass." } +{ "The " { $snippet "stencil-fail-op" } ", " { $snippet "depth-fail-op" } ", and " { $snippet "depth-pass-op" } " slots all contain " { $link stencil-op } " values that determine how the value in the stencil buffer is affected when the stencil test fails, the stencil test succeeds but depth test fails, and both stencil and depth tests succeed, respectively." + { $list + { { $link op-keep } " leaves the stencil buffer value unchanged." } + { { $link op-zero } " sets the stencil buffer value to zero." } + { { $link op-replace } " sets the stencil buffer value to the reference " { $snippet "value" } "." } + { { $link op-invert } " bitwise NOTs the stencil buffer value." } + { { $link op-inc-sat } " adds one to the stencil buffer value, leaving it unchanged if it is already the maximum storable value." } + { { $link op-dec-sat } " subtracts one from the stencil buffer value, leaving it unchanged if it is already zero." } + { { $link op-inc-wrap } " adds one to the stencil buffer value, wrapping the value to zero if it was the maximum storable value." } + { { $link op-dec-wrap } " subtracts one from the stencil buffer value, wrapping the value to the maximum storable value if it was zero." } + } +} +} } ; + +HELP: stencil-op +{ $class-description { $snippet "stencil-op" } "s are set as part of a " { $link stencil-mode } " and determine how the stencil buffer is modified by incoming fragments." +{ $list +{ { $link op-keep } " leaves the stencil buffer value unchanged." } +{ { $link op-zero } " sets the stencil buffer value to zero." } +{ { $link op-replace } " sets the stencil buffer value to the reference " { $snippet "value" } "." } +{ { $link op-invert } " bitwise NOTs the stencil buffer value." } +{ { $link op-inc-sat } " adds one to the stencil buffer value, leaving it unchanged if it is already the maximum storable value." } +{ { $link op-dec-sat } " subtracts one from the stencil buffer value, leaving it unchanged if it is already zero." } +{ { $link op-inc-wrap } " adds one to the stencil buffer value, wrapping the value to zero if it was the maximum storable value." } +{ { $link op-dec-wrap } " subtracts one from the stencil buffer value, wrapping the value to the maximum storable value if it was zero." } +} } ; + +HELP: stencil-state +{ $class-description "The " { $snippet "stencil-state" } " controls how incoming fragments interact with the stencil buffer. The " { $snippet "front-mode" } " and " { $snippet "back-mode" } " slots are both " { $link stencil-mode } " tuples that define the stencil buffer interaction for front- and back-facing triangle fragments, respectively. If both slots are " { $link f } ", stencil testing is disabled." } ; + +HELP: triangle-cull +{ $class-description "The " { $snippet "cull" } " slot of the " { $link triangle-cull-state } " determines which triangle faces are culled, if any." +{ $list +{ { $link cull-all } " culls all triangles." } +{ { $link cull-front } " culls front-facing triangles." } +{ { $link cull-back } " culls back-facing triangles." } +} } ; + +HELP: triangle-cull-state +{ $class-description "The " { $snippet "triangle-cull-state" } " controls what faces of triangles are rasterized." +{ $list +{ "The " { $snippet "front-face" } " slot determines which vertex winding order is considered the front face of a triangle: " { $link face-ccw } " or " { $link face-cw } "." } +{ "The " { $snippet "cull" } " slot determines which triangle faces are discarded: " { $link cull-front } ", " { $link cull-back } ", " { $link cull-all } ", or " { $link f } " to disable triangle culling." } +} } ; + +HELP: triangle-face +{ $class-description "A " { $snippet "triangle-face" } " value names a vertex winding order for triangles." +{ $list +{ { $link face-ccw } " indicates counterclockwise winding." } +{ { $link face-cw } " indicates clockwise winding." } +} } ; + +HELP: triangle-fill +{ $class-description "This " { $link triangle-mode } " fills the entire surface of triangles." } ; + +HELP: triangle-lines +{ $class-description "This " { $link triangle-mode } " renders lines across the edges of triangles." } ; + +HELP: triangle-mode +{ $class-description "The " { $snippet "triangle-mode" } " is set as part of the " { $link triangle-state } " to determine how triangles are rendered." +{ $list +{ { $link triangle-points } " renders the vertices of triangles as if they were points." } +{ { $link triangle-lines } " renders lines across the edges of triangles." } +{ { $link triangle-fill } ", the default, fills the entire surface of triangles." } +} } ; + +HELP: triangle-points +{ $class-description "This " { $link triangle-mode } " renders the vertices of triangles as if they were points." } ; + +HELP: triangle-state +{ $class-description "The " { $snippet "triangle-state" } " controls how triangles are rasterized." +{ $list +{ "The " { $snippet "front-mode" } " and " { $snippet "back-mode" } " slots determine how a front- or back-facing triangle is rendered." + { $list + { { $link triangle-points } " renders the vertices of triangles as if they were points." } + { { $link triangle-lines } " renders lines across the edges of triangles." } + { { $link triangle-fill } ", the default, fills the entire surface of triangles." } + } +} +{ "The " { $snippet "antialias?" } " slot contains a " { $link boolean } " value that decides whether the edges of triangles should be smoothed." } +} } ; + +HELP: viewport-state +{ $class-description "The " { $snippet "viewport-state" } " controls the rectangular region of the framebuffer to which window-space coordinates are mapped. Window-space vertices are mapped from the rectangle <-1.0, -1.0>­<1.0, 1.0> to the rectangular region specified by the " { $snippet "rect" } " slot." } ; + +ARTICLE: "gpu.state" "GPU state" +"The " { $vocab-link "gpu.state" } " vocabulary provides words for querying and setting GPU state." +{ $subsection set-gpu-state } +"The following state tuples are available:" +{ $subsection viewport-state } +{ $subsection scissor-state } +{ $subsection multisample-state } +{ $subsection stencil-state } +{ $subsection depth-range-state } +{ $subsection depth-state } +{ $subsection blend-state } +{ $subsection mask-state } +{ $subsection triangle-cull-state } +{ $subsection triangle-state } +{ $subsection point-state } +{ $subsection line-state } ; + +ABOUT: "gpu.state" diff --git a/extra/gpu/state/state.factor b/extra/gpu/state/state.factor new file mode 100755 index 0000000000..6027be74b5 --- /dev/null +++ b/extra/gpu/state/state.factor @@ -0,0 +1,530 @@ +! (c)2009 Joe Groff bsd license +USING: accessors alien.c-types arrays byte-arrays combinators gpu +kernel literals math math.rectangles opengl opengl.gl sequences +variants specialized-arrays.int specialized-arrays.float ; +IN: gpu.state + +UNION: ?rect rect POSTPONE: f ; +UNION: ?float float POSTPONE: f ; + +TUPLE: viewport-state + { rect rect read-only } ; +C: viewport-state + +TUPLE: scissor-state + { rect ?rect read-only } ; +C: scissor-state + +TUPLE: multisample-state + { multisample? boolean read-only } + { sample-alpha-to-coverage? boolean read-only } + { sample-alpha-to-one? boolean read-only } + { sample-coverage ?float read-only } + { invert-sample-coverage? boolean read-only } ; +C: multisample-state + +VARIANT: comparison + cmp-never cmp-always + cmp-less cmp-less-equal cmp-equal + cmp-greater-equal cmp-greater cmp-not-equal ; +VARIANT: stencil-op + op-keep op-zero + op-replace op-invert + op-inc-sat op-dec-sat + op-inc-wrap op-dec-wrap ; + +UNION: ?comparison comparison POSTPONE: f ; + +TUPLE: stencil-mode + { value integer initial: 0 read-only } + { mask integer initial: HEX: FFFFFFFF read-only } + { comparison comparison initial: cmp-always read-only } + { stencil-fail-op stencil-op initial: op-keep read-only } + { depth-fail-op stencil-op initial: op-keep read-only } + { depth-pass-op stencil-op initial: op-keep read-only } ; +C: stencil-mode + +UNION: ?stencil-mode stencil-mode POSTPONE: f ; + +TUPLE: stencil-state + { front-mode ?stencil-mode initial: f read-only } + { back-mode ?stencil-mode initial: f read-only } ; +C: stencil-state + +TUPLE: depth-range-state + { near float initial: 0.0 read-only } + { far float initial: 1.0 read-only } ; +C: depth-range-state + +TUPLE: depth-state + { comparison ?comparison initial: f read-only } ; +C: depth-state + +VARIANT: blend-equation + eq-add eq-subtract eq-reverse-subtract eq-min eq-max ; +VARIANT: blend-function + func-zero func-one + func-source func-one-minus-source + func-dest func-one-minus-dest + func-constant func-one-minus-constant + func-source-alpha func-one-minus-source-alpha + func-dest-alpha func-one-minus-dest-alpha + func-constant-alpha func-one-minus-constant-alpha ; + +VARIANT: source-only-blend-function + func-source-alpha-saturate ; + +UNION: source-blend-function blend-function source-only-blend-function ; + +TUPLE: blend-mode + { equation blend-equation initial: eq-add read-only } + { source-function source-blend-function initial: func-source-alpha read-only } + { dest-function blend-function initial: func-one-minus-source-alpha read-only } ; +C: blend-mode + +UNION: ?blend-mode blend-mode POSTPONE: f ; + +TUPLE: blend-state + { constant-color sequence initial: f read-only } + { rgb-mode ?blend-mode read-only } + { alpha-mode ?blend-mode read-only } ; +C: blend-state + +TUPLE: mask-state + { color sequence initial: { t t t t } read-only } + { depth boolean initial: t read-only } + { stencil-front integer initial: HEX: FFFFFFFF read-only } + { stencil-back integer initial: HEX: FFFFFFFF read-only } ; +C: mask-state + +VARIANT: triangle-face + face-ccw face-cw ; +VARIANT: triangle-cull + cull-front cull-back cull-all ; +VARIANT: triangle-mode + triangle-points triangle-lines triangle-fill ; + +UNION: ?triangle-cull triangle-cull POSTPONE: f ; + +TUPLE: triangle-cull-state + { front-face triangle-face initial: face-ccw read-only } + { cull ?triangle-cull initial: f read-only } ; +C: triangle-cull-state + +TUPLE: triangle-state + { front-mode triangle-mode initial: triangle-fill read-only } + { back-mode triangle-mode initial: triangle-fill read-only } + { antialias? boolean initial: f read-only } ; +C: triangle-state + +VARIANT: point-sprite-origin + origin-upper-left origin-lower-left ; + +TUPLE: point-state + { size ?float initial: 1.0 read-only } + { sprite-origin point-sprite-origin initial: origin-upper-left read-only } + { fade-threshold float initial: 1.0 read-only } ; +C: point-state + +TUPLE: line-state + { width float initial: 1.0 read-only } + { antialias? boolean initial: f read-only } ; +C: line-state + +UNION: gpu-state + viewport-state + triangle-cull-state + triangle-state + point-state + line-state + scissor-state + multisample-state + stencil-state + depth-range-state + depth-state + blend-state + mask-state ; + + ( triangle-face -- face ) + { + { $ GL_CCW [ face-ccw ] } + { $ GL_CW [ face-cw ] } + } case ; + +: gl-triangle-cull ( triangle-cull -- cull ) + { + { cull-front [ GL_FRONT ] } + { cull-back [ GL_BACK ] } + { cull-all [ GL_FRONT_AND_BACK ] } + } case ; + +: gl-triangle-cull> ( triangle-cull -- cull ) + { + { $ GL_FRONT [ cull-front ] } + { $ GL_BACK [ cull-back ] } + { $ GL_FRONT_AND_BACK [ cull-all ] } + } case ; + +: gl-triangle-mode ( triangle-mode -- mode ) + { + { triangle-points [ GL_POINT ] } + { triangle-lines [ GL_LINE ] } + { triangle-fill [ GL_FILL ] } + } case ; + +: gl-triangle-mode> ( triangle-mode -- mode ) + { + { $ GL_POINT [ triangle-points ] } + { $ GL_LINE [ triangle-lines ] } + { $ GL_FILL [ triangle-fill ] } + } case ; + +: gl-point-sprite-origin ( point-sprite-origin -- sprite-origin ) + { + { origin-upper-left [ GL_UPPER_LEFT ] } + { origin-lower-left [ GL_LOWER_LEFT ] } + } case ; + +: gl-point-sprite-origin> ( point-sprite-origin -- sprite-origin ) + { + { $ GL_UPPER_LEFT [ origin-upper-left ] } + { $ GL_LOWER_LEFT [ origin-lower-left ] } + } case ; + +: gl-comparison ( comparison -- comparison ) + { + { cmp-never [ GL_NEVER ] } + { cmp-always [ GL_ALWAYS ] } + { cmp-less [ GL_LESS ] } + { cmp-less-equal [ GL_LEQUAL ] } + { cmp-equal [ GL_EQUAL ] } + { cmp-greater-equal [ GL_GEQUAL ] } + { cmp-greater [ GL_GREATER ] } + { cmp-not-equal [ GL_NOTEQUAL ] } + } case ; + +: gl-comparison> ( comparison -- comparison ) + { + { $ GL_NEVER [ cmp-never ] } + { $ GL_ALWAYS [ cmp-always ] } + { $ GL_LESS [ cmp-less ] } + { $ GL_LEQUAL [ cmp-less-equal ] } + { $ GL_EQUAL [ cmp-equal ] } + { $ GL_GEQUAL [ cmp-greater-equal ] } + { $ GL_GREATER [ cmp-greater ] } + { $ GL_NOTEQUAL [ cmp-not-equal ] } + } case ; + +: gl-stencil-op ( stencil-op -- op ) + { + { op-keep [ GL_KEEP ] } + { op-zero [ GL_ZERO ] } + { op-replace [ GL_REPLACE ] } + { op-invert [ GL_INVERT ] } + { op-inc-sat [ GL_INCR ] } + { op-dec-sat [ GL_DECR ] } + { op-inc-wrap [ GL_INCR_WRAP ] } + { op-dec-wrap [ GL_DECR_WRAP ] } + } case ; + +: gl-stencil-op> ( op -- op ) + { + { $ GL_KEEP [ op-keep ] } + { $ GL_ZERO [ op-zero ] } + { $ GL_REPLACE [ op-replace ] } + { $ GL_INVERT [ op-invert ] } + { $ GL_INCR [ op-inc-sat ] } + { $ GL_DECR [ op-dec-sat ] } + { $ GL_INCR_WRAP [ op-inc-wrap ] } + { $ GL_DECR_WRAP [ op-dec-wrap ] } + } case ; + +: (set-stencil-mode) ( gl-face stencil-mode -- ) + { + [ [ comparison>> gl-comparison ] [ value>> ] [ mask>> ] tri glStencilFuncSeparate ] + [ + [ stencil-fail-op>> ] [ depth-fail-op>> ] [ depth-pass-op>> ] tri + [ gl-stencil-op ] tri@ glStencilOpSeparate + ] + } 2cleave ; + +: gl-blend-equation ( blend-equation -- blend-equation ) + { + { eq-add [ GL_FUNC_ADD ] } + { eq-subtract [ GL_FUNC_SUBTRACT ] } + { eq-reverse-subtract [ GL_FUNC_REVERSE_SUBTRACT ] } + { eq-min [ GL_MIN ] } + { eq-max [ GL_MAX ] } + } case ; + +: gl-blend-equation> ( blend-equation -- blend-equation ) + { + { $ GL_FUNC_ADD [ eq-add ] } + { $ GL_FUNC_SUBTRACT [ eq-subtract ] } + { $ GL_FUNC_REVERSE_SUBTRACT [ eq-reverse-subtract ] } + { $ GL_MIN [ eq-min ] } + { $ GL_MAX [ eq-max ] } + } case ; + +: gl-blend-function ( blend-function -- blend-function ) + { + { func-zero [ GL_ZERO ] } + { func-one [ GL_ONE ] } + { func-source [ GL_SRC_COLOR ] } + { func-one-minus-source [ GL_ONE_MINUS_SRC_COLOR ] } + { func-dest [ GL_DST_COLOR ] } + { func-one-minus-dest [ GL_ONE_MINUS_DST_COLOR ] } + { func-constant [ GL_CONSTANT_COLOR ] } + { func-one-minus-constant [ GL_ONE_MINUS_CONSTANT_COLOR ] } + { func-source-alpha [ GL_SRC_ALPHA ] } + { func-one-minus-source-alpha [ GL_ONE_MINUS_SRC_ALPHA ] } + { func-dest-alpha [ GL_DST_ALPHA ] } + { func-one-minus-dest-alpha [ GL_ONE_MINUS_DST_ALPHA ] } + { func-constant-alpha [ GL_CONSTANT_ALPHA ] } + { func-one-minus-constant-alpha [ GL_ONE_MINUS_CONSTANT_ALPHA ] } + { func-source-alpha-saturate [ GL_SRC_ALPHA_SATURATE ] } + } case ; + +: gl-blend-function> ( blend-function -- blend-function ) + { + { $ GL_ZERO [ func-zero ] } + { $ GL_ONE [ func-one ] } + { $ GL_SRC_COLOR [ func-source ] } + { $ GL_ONE_MINUS_SRC_COLOR [ func-one-minus-source ] } + { $ GL_DST_COLOR [ func-dest ] } + { $ GL_ONE_MINUS_DST_COLOR [ func-one-minus-dest ] } + { $ GL_CONSTANT_COLOR [ func-constant ] } + { $ GL_ONE_MINUS_CONSTANT_COLOR [ func-one-minus-constant ] } + { $ GL_SRC_ALPHA [ func-source-alpha ] } + { $ GL_ONE_MINUS_SRC_ALPHA [ func-one-minus-source-alpha ] } + { $ GL_DST_ALPHA [ func-dest-alpha ] } + { $ GL_ONE_MINUS_DST_ALPHA [ func-one-minus-dest-alpha ] } + { $ GL_CONSTANT_ALPHA [ func-constant-alpha ] } + { $ GL_ONE_MINUS_CONSTANT_ALPHA [ func-one-minus-constant-alpha ] } + { $ GL_SRC_ALPHA_SATURATE [ func-source-alpha-saturate ] } + } case ; + +PRIVATE> + +GENERIC: set-gpu-state* ( state -- ) + +M: viewport-state set-gpu-state* + rect>> [ loc>> first2 ] [ dim>> first2 ] bi glViewport ; + +M: triangle-cull-state set-gpu-state* + { + [ front-face>> gl-triangle-face glFrontFace ] + [ GL_CULL_FACE swap cull>> [ gl-triangle-cull glCullFace glEnable ] [ glDisable ] if* ] + } cleave ; + +M: triangle-state set-gpu-state* + { + [ GL_FRONT swap front-mode>> gl-triangle-mode glPolygonMode ] + [ GL_BACK swap back-mode>> gl-triangle-mode glPolygonMode ] + [ GL_POLYGON_SMOOTH swap antialias?>> [ glEnable ] [ glDisable ] if ] + } cleave ; + +M: point-state set-gpu-state* + { + [ GL_VERTEX_PROGRAM_POINT_SIZE swap size>> [ glPointSize glDisable ] [ glEnable ] if* ] + [ GL_POINT_SPRITE_COORD_ORIGIN swap sprite-origin>> gl-point-sprite-origin glPointParameteri ] + [ GL_POINT_FADE_THRESHOLD_SIZE swap fade-threshold>> glPointParameterf ] + } cleave ; + +M: line-state set-gpu-state* + { + [ width>> glLineWidth ] + [ GL_LINE_SMOOTH swap antialias?>> [ glEnable ] [ glDisable ] if ] + } cleave ; + +M: scissor-state set-gpu-state* + GL_SCISSOR_TEST swap rect>> + [ [ loc>> first2 ] [ dim>> first2 ] bi glViewport glEnable ] + [ glDisable ] if* ; + +M: multisample-state set-gpu-state* + dup multisample?>> [ + GL_MULTISAMPLE glEnable + { + [ GL_SAMPLE_ALPHA_TO_COVERAGE swap sample-alpha-to-coverage?>> + [ glEnable ] [ glDisable ] if + ] + [ GL_SAMPLE_ALPHA_TO_ONE swap sample-alpha-to-one?>> + [ glEnable ] [ glDisable ] if + ] + [ GL_SAMPLE_COVERAGE swap [ invert-sample-coverage?>> >c-bool ] [ sample-coverage>> ] bi + [ swap glSampleCoverage glEnable ] [ drop glDisable ] if* + ] + } cleave + ] [ drop GL_MULTISAMPLE glDisable ] if ; + +M: stencil-state set-gpu-state* + [ ] [ front-mode>> ] [ back-mode>> ] tri or + [ + GL_STENCIL_TEST glEnable + [ front-mode>> GL_FRONT swap (set-stencil-mode) ] + [ back-mode>> GL_BACK swap (set-stencil-mode) ] bi + ] [ drop GL_STENCIL_TEST glDisable ] if ; + +M: depth-range-state set-gpu-state* + [ near>> ] [ far>> ] bi glDepthRange ; + +M: depth-state set-gpu-state* + GL_DEPTH_TEST swap comparison>> [ gl-comparison glDepthFunc glEnable ] [ glDisable ] if* ; + +M: blend-state set-gpu-state* + [ ] [ rgb-mode>> ] [ alpha-mode>> ] tri or + [ + GL_BLEND glEnable + [ constant-color>> [ first4 glBlendColor ] when* ] + [ + [ rgb-mode>> ] [ alpha-mode>> ] bi { + [ [ equation>> gl-blend-equation ] bi@ glBlendEquationSeparate ] + [ + [ + [ source-function>> gl-blend-function ] + [ dest-function>> gl-blend-function ] bi + ] bi@ glBlendFuncSeparate + ] + } 2cleave + ] bi + ] [ drop GL_BLEND glDisable ] if ; + +M: mask-state set-gpu-state* + { + [ color>> [ >c-bool ] map first4 glColorMask ] + [ depth>> >c-bool glDepthMask ] + [ GL_FRONT swap stencil-front>> glStencilMaskSeparate ] + [ GL_BACK swap stencil-back>> glStencilMaskSeparate ] + } cleave ; + +: set-gpu-state ( states -- ) + dup sequence? + [ [ set-gpu-state* ] each ] + [ set-gpu-state* ] if ; inline + + [ glGetBooleanv ] keep *uchar c-bool> ; +: get-gl-int ( enum -- value ) + 0 [ glGetIntegerv ] keep *int ; +: get-gl-float ( enum -- value ) + 0 [ glGetFloatv ] keep *float ; + +: get-gl-bools ( enum count -- value ) + [ glGetBooleanv ] keep [ c-bool> ] { } map-as ; +: get-gl-ints ( enum count -- value ) + [ glGetIntegerv ] keep ; +: get-gl-floats ( enum count -- value ) + [ glGetFloatv ] keep ; + +: get-gl-rect ( enum -- value ) + 4 get-gl-ints first4 [ 2array ] 2bi@ ; + +: gl-enabled? ( enum -- ? ) + glIsEnabled c-bool> ; + +PRIVATE> + +: get-viewport-state ( -- viewport-state ) + GL_VIEWPORT get-gl-rect ; + +: get-scissor-state ( -- scissor-state ) + GL_SCISSOR_TEST get-gl-bool + [ GL_SCISSOR_BOX get-gl-rect ] [ f ] if + ; + +: get-multisample-state ( -- multisample-state ) + GL_MULTISAMPLE gl-enabled? + GL_SAMPLE_ALPHA_TO_COVERAGE gl-enabled? + GL_SAMPLE_ALPHA_TO_ONE gl-enabled? + GL_SAMPLE_COVERAGE gl-enabled? [ + GL_SAMPLE_COVERAGE_VALUE get-gl-float + GL_SAMPLE_COVERAGE_INVERT get-gl-bool + ] [ f f ] if + ; + +: get-stencil-state ( -- stencil-state ) + GL_STENCIL_TEST gl-enabled? [ + GL_STENCIL_REF get-gl-int + GL_STENCIL_VALUE_MASK get-gl-int + GL_STENCIL_FUNC get-gl-int gl-comparison> + GL_STENCIL_FAIL get-gl-int gl-stencil-op> + GL_STENCIL_PASS_DEPTH_FAIL get-gl-int gl-stencil-op> + GL_STENCIL_PASS_DEPTH_PASS get-gl-int gl-stencil-op> + + + GL_STENCIL_BACK_REF get-gl-int + GL_STENCIL_BACK_VALUE_MASK get-gl-int + GL_STENCIL_BACK_FUNC get-gl-int gl-comparison> + GL_STENCIL_BACK_FAIL get-gl-int gl-stencil-op> + GL_STENCIL_BACK_PASS_DEPTH_FAIL get-gl-int gl-stencil-op> + GL_STENCIL_BACK_PASS_DEPTH_PASS get-gl-int gl-stencil-op> + + ] [ f f ] if + ; + +: get-depth-range-state ( -- depth-range-state ) + GL_DEPTH_RANGE 2 get-gl-floats first2 ; + +: get-depth-state ( -- depth-state ) + GL_DEPTH_TEST gl-enabled? + [ GL_DEPTH_FUNC get-gl-int gl-comparison> ] [ f ] if + ; + +: get-blend-state ( -- blend-state ) + GL_BLEND gl-enabled? [ + GL_BLEND_COLOR 4 get-gl-floats + + GL_BLEND_EQUATION_RGB get-gl-int gl-blend-equation> + GL_BLEND_SRC_RGB get-gl-int gl-blend-function> + GL_BLEND_DST_RGB get-gl-int gl-blend-function> + + + GL_BLEND_EQUATION_ALPHA get-gl-int gl-blend-equation> + GL_BLEND_SRC_ALPHA get-gl-int gl-blend-function> + GL_BLEND_DST_ALPHA get-gl-int gl-blend-function> + + ] [ f f f ] if + ; + +: get-mask-state ( -- mask-state ) + GL_COLOR_WRITEMASK 4 get-gl-bools + GL_DEPTH_WRITEMASK get-gl-bool + GL_STENCIL_WRITEMASK get-gl-int + GL_STENCIL_BACK_WRITEMASK get-gl-int + ; + +: get-triangle-cull-state ( -- triangle-cull-state ) + GL_FRONT_FACE get-gl-int gl-triangle-face> + GL_CULL_FACE gl-enabled? + [ GL_CULL_FACE_MODE get-gl-int gl-triangle-cull> ] + [ f ] if + ; + +: get-triangle-state ( -- triangle-state ) + GL_POLYGON_MODE 2 get-gl-ints + first2 [ gl-triangle-mode> ] bi@ + GL_POLYGON_SMOOTH gl-enabled? + ; + +: get-point-state ( -- point-state ) + GL_VERTEX_PROGRAM_POINT_SIZE gl-enabled? + [ f ] [ GL_POINT_SIZE get-gl-float ] if + GL_POINT_SPRITE_COORD_ORIGIN get-gl-int gl-point-sprite-origin> + GL_POINT_FADE_THRESHOLD_SIZE get-gl-float + ; + +: get-line-state ( -- line-state ) + GL_LINE_WIDTH get-gl-float + GL_LINE_SMOOTH gl-enabled? + ; diff --git a/extra/gpu/state/summary.txt b/extra/gpu/state/summary.txt new file mode 100644 index 0000000000..aba35444bd --- /dev/null +++ b/extra/gpu/state/summary.txt @@ -0,0 +1 @@ +GPU state manipulation diff --git a/extra/gpu/summary.txt b/extra/gpu/summary.txt new file mode 100644 index 0000000000..c754f65262 --- /dev/null +++ b/extra/gpu/summary.txt @@ -0,0 +1 @@ +High-level OpenGL-based GPU resource management and rendering library diff --git a/extra/gpu/textures/authors.txt b/extra/gpu/textures/authors.txt new file mode 100644 index 0000000000..f13c9c1e77 --- /dev/null +++ b/extra/gpu/textures/authors.txt @@ -0,0 +1 @@ +Joe Groff diff --git a/extra/gpu/textures/summary.txt b/extra/gpu/textures/summary.txt new file mode 100644 index 0000000000..6b3a0ef156 --- /dev/null +++ b/extra/gpu/textures/summary.txt @@ -0,0 +1 @@ +Multidimensional image data in GPU memory diff --git a/extra/gpu/textures/textures-docs.factor b/extra/gpu/textures/textures-docs.factor new file mode 100644 index 0000000000..8f3bb361a5 --- /dev/null +++ b/extra/gpu/textures/textures-docs.factor @@ -0,0 +1,301 @@ +! (c)2009 Joe Groff bsd license +USING: byte-arrays classes gpu.buffers help.markup help.syntax +images kernel math ; +IN: gpu.textures + +HELP: +X +{ $class-description "This " { $link cube-map-axis } " references the positive X face of a " { $link texture-cube-map } "." } ; + +HELP: +Y +{ $class-description "This " { $link cube-map-axis } " references the positive Y face of a " { $link texture-cube-map } "." } ; + +HELP: +Z +{ $class-description "This " { $link cube-map-axis } " references the positive Z face of a " { $link texture-cube-map } "." } ; + +HELP: -X +{ $class-description "This " { $link cube-map-axis } " references the negative X face of a " { $link texture-cube-map } "." } ; + +HELP: -Y +{ $class-description "This " { $link cube-map-axis } " references the negative Y face of a " { $link texture-cube-map } "." } ; + +HELP: -Z +{ $class-description "This " { $link cube-map-axis } " references the negative Z face of a " { $link texture-cube-map } "." } ; + +HELP: +{ $values + { "texture" texture-cube-map } { "axis" cube-map-axis } + { "cube-map-face" cube-map-face } +} +{ $description "Constructs a new " { $link cube-map-face } " reference." } ; + +HELP: +{ $values + { "component-order" component-order } { "component-type" component-type } { "parameters" texture-parameters } + { "texture" texture-1d-array } +} +{ $description "Creates a new one-dimensional array texture. The new texture starts out with no image data; " { $link allocate-texture } " or " { $link allocate-texture-image } " must be used to allocate memory for the required levels of detail of the texture." } +{ $notes "Array textures require OpenGL 3.0 or the " { $snippet "GL_EXT_texture_array" } " extension." } ; + +HELP: +{ $values + { "component-order" component-order } { "component-type" component-type } { "parameters" texture-parameters } + { "texture" texture-1d } +} +{ $description "Creates a new one-dimensional texture. The new texture starts out with no image data; " { $link allocate-texture } " or " { $link allocate-texture-image } " must be used to allocate memory for the required levels of detail of the texture." } ; + +HELP: +{ $values + { "component-order" component-order } { "component-type" component-type } { "parameters" texture-parameters } + { "texture" texture-2d-array } +} +{ $description "Creates a new two-dimensional array texture. The new texture starts out with no image data; " { $link allocate-texture } " or " { $link allocate-texture-image } " must be used to allocate memory for the required levels of detail of the texture." } +{ $notes "Array textures require OpenGL 3.0 or the " { $snippet "GL_EXT_texture_array" } " extension." } ; + +HELP: +{ $values + { "component-order" component-order } { "component-type" component-type } { "parameters" texture-parameters } + { "texture" texture-2d } +} +{ $description "Creates a new two-dimensional texture. The new texture starts out with no image data; " { $link allocate-texture } " or " { $link allocate-texture-image } " must be used to allocate memory for the required levels of detail of the texture." } ; + +HELP: +{ $values + { "component-order" component-order } { "component-type" component-type } { "parameters" texture-parameters } + { "texture" texture-3d } +} +{ $description "Creates a new three-dimensional texture. The new texture starts out with no image data; " { $link allocate-texture } " or " { $link allocate-texture-image } " must be used to allocate memory for the required levels of detail of the texture." } ; + +HELP: +{ $values + { "component-order" component-order } { "component-type" component-type } { "parameters" texture-parameters } + { "texture" texture-cube-map } +} +{ $description "Creates a new cube map texture. The new texture starts out with no image data; " { $link allocate-texture } " or " { $link allocate-texture-image } " must be used to allocate memory for the required levels of detail of each " { $link cube-map-face } " of the new texture." } ; + +HELP: +{ $values + { "ptr" gpu-data-ptr } { "component-order" component-order } { "component-type" component-type } + { "texture-data" texture-data } +} +{ $description "Constructs a new " { $link texture-data } " tuple." } +{ $notes "Using a " { $link buffer-ptr } " as the " { $snippet "ptr" } " of a " { $snippet "texture-data" } " object requires OpenGL 2.1 or later or the " { $snippet "GL_ARB_pixel_buffer_object" } " extension." } ; + +HELP: +{ $values + { "component-order" component-order } { "component-type" component-type } { "parameters" texture-parameters } + { "texture" texture-rectangle } +} +{ $description "Creates a new rectangle texture. The new texture starts out with no image data; " { $link allocate-texture } " or " { $link allocate-texture-image } " must be used to allocate memory for the texture." } +{ $notes "Rectangle textures require OpenGL 3.1 or the " { $snippet "GL_ARB_texture_rectangle" } " extension." } ; + +HELP: allocate-texture +{ $values + { "tdt" texture-data-target } { "level" integer } { "dim" "an " { $link integer } " or sequence of " { $link integer } "s" } { "data" { $maybe texture-data } } +} +{ $description "Allocates a new block of GPU memory for the " { $snippet "level" } "th level of detail of a " { $link texture-data-target } ". If " { $snippet "data" } " is not " { $link f } ", the new data is initialized from the given " { $link texture-data } " object; otherwise, the new image is left uninitialized." } +{ $notes "Using a " { $link buffer-ptr } " as the " { $snippet "ptr" } " of a " { $snippet "texture-data" } " object requires OpenGL 2.1 or later or the " { $snippet "GL_ARB_pixel_buffer_object" } " extension." } ; + +HELP: allocate-texture-image +{ $values + { "tdt" texture-data-target } { "level" integer } { "image" image } +} +{ $description "Allocates a new block of GPU memory for the " { $snippet "level" } "th level of detail of a " { $link texture-data-target } " and initializes it with the contents of an " { $link image } "." } ; + +{ allocate-texture allocate-texture-image } related-words + +HELP: clamp-texcoord-to-border +{ $class-description "This " { $link texture-wrap } " value clamps texture coordinates to a texture's border." } ; + +HELP: clamp-texcoord-to-edge +{ $class-description "This " { $link texture-wrap } " value clamps texture coordinates to a texture image's edge." } ; + +HELP: cube-map-axis +{ $class-description "Objects of this class are stored in the " { $snippet "axis" } " slot of a " { $link cube-map-face } " to choose the referenced face: " { $link +X } ", " { $link +Y } ", " { $link +Z } ", " { $link -X } ", " { $link -Y } ", or " { $link -Z } "." +} ; + +HELP: cube-map-face +{ $class-description "A " { $snippet "cube-map-face" } " tuple references a single face of a " { $link texture-cube-map } " object for use with " { $link allocate-texture } ", " { $link update-texture } ", or " { $link read-texture } "." +{ $list +{ "The " { $snippet "texture" } " slot indicates the cube map texture being referenced." } +{ "The " { $snippet "axis" } " slot indicates which face to reference: " { $link +X } ", " { $link +Y } ", " { $link +Z } ", " { $link -X } ", " { $link -Y } ", or " { $link -Z } "." } +} } ; + +HELP: filter-linear +{ $class-description "This " { $link texture-filter } " value selects linear filtering between pixel samples." } ; + +HELP: filter-nearest +{ $class-description "This " { $link texture-filter } " value selects nearest-neighbor sampling." } ; + +HELP: generate-mipmaps +{ $values + { "texture" texture } +} +{ $description "Replaces the image data for all levels of detail of " { $snippet "texture" } " below the highest level with images automatically generated from the highest level of detail image." } +{ $notes "This word requires OpenGL 3.0 or one of the " { $snippet "GL_EXT_framebuffer_object" } " or " { $snippet "GL_ARB_framebuffer_object" } " extensions." } ; + +HELP: image>texture-data +{ $values + { "image" image } + { "dim" "a sequence of " { $link integer } "s" } { "texture-data" texture-data } +} +{ $description "Constructs a " { $link texture-data } " tuple referencing the pixel data from an " { $link image } "." } ; + +HELP: read-texture +{ $values + { "tdt" texture-data-target } { "level" integer } + { "byte-array" byte-array } +} +{ $description "Reads the entire image for the " { $snippet "level" } "th level of detail of a texture into a new " { $link byte-array } ". The format of the data in the byte array is determined by the " { $link component-order } " and " { $link component-type } " of the texture." } ; + +HELP: read-texture-image +{ $values + { "tdt" texture-data-target } { "level" integer } + { "image" image } +} +{ $description "Reads the entire image for the " { $snippet "level" } "th level of detail of a texture into a new " { $link image } ". The format of the image is determined by the " { $link component-order } " and " { $link component-type } " of the texture." } ; + +HELP: read-texture-to +{ $values + { "tdt" texture-data-target } { "level" integer } { "gpu-data-ptr" gpu-data-ptr } +} +{ $description "Reads the entire image for the " { $snippet "level" } "th level of detail of a texture into the CPU or GPU memory referenced by " { $link gpu-data-ptr } ". The format of the data in the byte array is determined by the " { $link component-order } " and " { $link component-type } " of the texture." } +{ $notes "Reading texture data into a GPU " { $snippet "buffer-ptr" } " requires OpenGL 2.1 or later or the " { $snippet "GL_ARB_pixel_buffer_object" } " extension." } ; + +{ read-texture read-texture-image read-texture-to } related-words + +HELP: repeat-texcoord +{ $class-description "This " { $link texture-wrap } " value causes the texture image to be repeated through texture coordinate space." } ; + +HELP: repeat-texcoord-mirrored +{ $class-description "This " { $link texture-wrap } " value causes the texture image to be repeated through texture coordinate space, mirroring the image on every repetition." } ; + +HELP: set-texture-parameters +{ $values + { "texture" texture } { "parameters" texture-parameters } +} +{ $description "Changes the " { $link texture-parameters } " of a " { $link texture } "." } ; + +HELP: texture +{ $class-description "Textures are typed, multidimensional arrays of GPU memory used for storing image data, lookup tables, and other kinds of multidimensional data for use with shader programs. They come in different types depending on dimensionality and intended usage:" +{ $subsection texture-1d } +{ $subsection texture-2d } +{ $subsection texture-3d } +{ $subsection texture-cube-map } +{ $subsection texture-rectangle } +{ $subsection texture-1d-array } +{ $subsection texture-2d-array } +"Textures are constructed using the corresponding " { $snippet "" } " for their type. The constructor sets the texture's " { $link component-order } ", " { $link component-type } ", and " { $link texture-parameters } ". Once created, memory for a texture can be allocated with " { $link allocate-texture } ", updated with " { $link update-texture } ", or retrieved with " { $link read-texture } "." } ; + +HELP: texture-1d +{ $class-description "A one-dimensional " { $link texture } " object. Textures of this type are dimensioned by single integers in calls to " { $link allocate-texture } " and " { $link update-texture } "." } ; + +{ texture-1d } related-words + +HELP: texture-1d-array +{ $class-description "A one-dimensional array " { $link texture } " object. Textures of this type are dimensioned by pairs of integers in calls to " { $link allocate-texture } " and " { $link update-texture } ". A 1D array texture is distinct from a 2D texture (" { $link texture-2d } ") in that each row of the texture is independent; texture values are not filtered between rows, and lower levels of detail retain the same height, only losing detail in the width direction." } +{ $notes "Array textures require OpenGL 3.0 or the " { $snippet "GL_EXT_texture_array" } " extension." } ; + +{ texture-1d-array } related-words + +HELP: texture-2d +{ $class-description "A two-dimensional " { $link texture } " object. Textures of this type are dimensioned by pairs of integers in calls to " { $link allocate-texture } " and " { $link update-texture } "." } ; + +{ texture-2d } related-words + +HELP: texture-2d-array +{ $class-description "A two-dimensional array " { $link texture } " object. Textures of this type are dimensioned by sequences of three integers in calls to " { $link allocate-texture } " and " { $link update-texture } ". A 2D array texture is distinct from a 3D texture (" { $link texture-3d } ") in that each plane of the texture is independent; texture values are not filtered between planes, and lower levels of detail retain the same depth, only losing detail in the width and height directions." } +{ $notes "Array textures require OpenGL 3.0 or the " { $snippet "GL_EXT_texture_array" } " extension." } ; + +{ texture-2d-array } related-words + +HELP: texture-3d +{ $class-description "A three-dimensional " { $link texture } " object. Textures of this type are dimensioned by sequences of three integers in calls to " { $link allocate-texture } " and " { $link update-texture } "." } ; + +{ texture-3d } related-words + +HELP: texture-wrap +{ $class-description "Values of this class are used in the " { $snippet "wrap" } " slot of a set of " { $link texture-parameters } " to specify how texture coordinates outside the 0.0 to 1.0 range should be mapped onto the texture image." +{ $list +{ { $link clamp-texcoord-to-edge } " clamps coordinates to the edge of the texture image." } +{ { $link clamp-texcoord-to-border } " clamps coordinates to the border of the texture image." } +{ { $link repeat-texcoord } " repeats the texture image." } +{ { $link repeat-texcoord-mirrored } " repeats the texture image, mirroring it with each repetition." } +} } ; + +HELP: texture-cube-map +{ $class-description "A cube map " { $link texture } " object. Textures of this type comprise six two-dimensional image sets, which are independently referenced by " { $link cube-map-face } " objects and dimensioned by pairs of integers in calls to " { $link allocate-texture } " and " { $link update-texture } ". When a cube map is sampled in shader code, the three-dimensional texture coordinates are projected onto the unit cube, and the cube face that is hit by the vector is used to select a face of the cube map texture." } ; + +{ texture-cube-map } related-words + +HELP: texture-data +{ $class-description { $snippet "texture-data" } " tuples are used to feed image data to " { $link allocate-texture } " and " { $link update-texture } ". In addition to providing a " { $snippet "ptr" } " to CPU memory or a GPU " { $link buffer-ptr } ", the " { $link texture-data } " object also specifies the " { $link component-order } " and " { $link component-type } " of the referenced data." } +{ $notes "Using a " { $link buffer-ptr } " as the " { $snippet "ptr" } " of a " { $snippet "texture-data" } " object requires OpenGL 2.1 or later or the " { $snippet "GL_ARB_pixel_buffer_object" } " extension." } ; + +{ texture-data } related-words + +HELP: texture-data-size +{ $values + { "tdt" texture-data-target } { "level" integer } + { "size" integer } +} +{ $description "Returns the size in bytes of the image data allocated for the " { $snippet "level" } "th level of detail of a " { $link texture-data-target } "." } ; + +HELP: texture-data-target +{ $class-description "Most " { $link texture } " types can have image data assigned to themselves directly by " { $link allocate-texture } " and " { $link update-texture } "; however, " { $link texture-cube-map } " objects comprise six independent image sets, each of which must be referenced separately with a " { $link cube-map-face } " tuple when allocating or updating images. The " { $snippet "texture-data-target" } " class is a union of all " { $link texture } " classes (except " { $snippet "texture-cube-map" } ") and the " { $snippet "cube-map-face" } " class." } ; + +HELP: texture-dim +{ $values + { "tdt" texture-data-target } { "level" integer } + { "dim" "an " { $link integer } " or sequence of integers" } +} +{ $description "Returns the dimensions of the memory allocated for the " { $snippet "level" } "th level of detail of the given " { $link texture-data-target } "." } ; + +HELP: texture-filter +{ $class-description { $snippet "texture-filter" } " values are used in a " { $link texture-parameters } " tuple to determine how a texture should be sampled between pixels or between levels of detail. " { $link filter-linear } " selects linear filtering, while " { $link filter-nearest } " selects nearest-neighbor sampling." } ; + +HELP: texture-parameters +{ $class-description "When a " { $link texture } " is created, the following " { $snippet "texture-parameter" } "s are set to control how the texture is sampled:" +{ $list +{ "The " { $snippet "wrap" } " slot determines how texture coordinates outside the 0.0 to 1.0 range are mapped to the texture image. The slot either contains a single " { $link texture-wrap } " value, which will apply to all three axes, or a sequence of up to three values, which will apply to the S, T, and R axes, respectively." } +{ "The " { $snippet "min-filter" } " and " { $snippet "min-mipmap-filter" } " determine how the texture image is filtered when sampled below its highest level of detail, the former controlling filtering between pixels within a level of detail and the latter filtering between levels of detail. A setting of " { $link filter-linear } " uses linear, bilinear, or trilinear filtering among sampled pixels, while a setting of " { $link filter-nearest } " uses nearest-neighbor sampling. The " { $snippet "min-mipmap-filter" } " slot may additionally be set to " { $link f } " to disable mipmapping and only sample the highest level of detail." } +{ "The " { $snippet "mag-filter" } " analogously determines how the texture image is filtered when sampled above its highest level of detail." } +{ "The " { $snippet "min-lod" } " and " { $snippet "max-lod" } " slots contain integer values that will clamp the range of levels of detail that will be sampled from the texture." } +{ "The " { $snippet "lod-bias" } " slot contains an integer value that will offset the levels of detail that would normally be sampled from the texture." } +{ "The " { $snippet "base-level" } " slot contains an integer value that identifies the highest level of detail for the image, typically zero." } +{ "The " { $snippet "max-level" } " slot contains an integer value that identifies the lowest level of detail for the image. This value will automatically be clamped to the maximum of the base-2 logarithm of the dimensions of the highest level of detail image." } +} } ; + +{ texture-parameters set-texture-parameters } related-words + +HELP: texture-rectangle +{ $class-description "A two-dimensional rectangle " { $link texture } " object. Textures of this type are dimensioned by pairs of integers in calls to " { $link allocate-texture } " and " { $link update-texture } ". Rectangle textures differ from normal 2D textures (" { $link texture-2d } ") in that texture coordinates map directly to pixel coordinates when they are sampled from shader code, rather than being normalized into the 0.0 to 1.0 range as with other texture types. Also, rectangle textures do not support mipmapping or texture wrapping." } +{ $notes "Rectangle textures require OpenGL 3.1 or the " { $snippet "GL_ARB_texture_rectangle" } " extension." } ; + +HELP: update-texture +{ $values + { "tdt" texture-data-target } { "level" integer } { "loc" "an " { $link integer } " or sequence of integers" } { "dim" "an " { $link integer } " or sequence of integers" } { "data" texture-data } +} +{ $description "Updates the linear, rectangular, or cubic subregion of a " { $link texture-data-target } " bounded by " { $snippet "loc" } " and " { $snippet "dim" } " with new image data from a " { $link texture-data } " tuple." } +{ $notes "Using a " { $link buffer-ptr } " as the " { $snippet "ptr" } " of a " { $snippet "texture-data" } " object requires OpenGL 2.1 or later or the " { $snippet "GL_ARB_pixel_buffer_object" } " extension." } ; + +HELP: update-texture-image +{ $values + { "tdt" texture-data-target } { "level" integer } { "loc" "an " { $link integer } " or sequence of integers" } { "image" image } +} +{ $description "Updates the linear, rectangular, or cubic subregion of a " { $link texture-data-target } " bounded by " { $snippet "loc" } " and " { $snippet "dim" } " with new image data from an " { $link image } " object." } ; + +{ update-texture update-texture-image } related-words + +ARTICLE: "gpu.textures" "Texture objects" +"The " { $vocab-link "gpu.textures" } " vocabulary provides words for creating, allocating, updating, and reading GPU texture objects." +{ $subsection texture } +{ $subsection allocate-texture } +{ $subsection update-texture } +{ $subsection read-texture } +"Words are also provided to interface textures with the " { $vocab-link "images" } " library:" +{ $subsection allocate-texture-image } +{ $subsection update-texture-image } +{ $subsection read-texture-image } +; + +ABOUT: "gpu.textures" diff --git a/extra/gpu/textures/textures.factor b/extra/gpu/textures/textures.factor new file mode 100644 index 0000000000..5740799fbe --- /dev/null +++ b/extra/gpu/textures/textures.factor @@ -0,0 +1,300 @@ +! (c)2009 Joe Groff bsd license +USING: accessors alien.c-types arrays byte-arrays combinators +destructors fry gpu gpu.buffers images kernel locals math +opengl opengl.gl opengl.textures sequences +specialized-arrays.float ui.gadgets.worlds variants ; +IN: gpu.textures + +TUPLE: texture < gpu-object + { component-order component-order read-only initial: RGBA } + { component-type component-type read-only initial: ubyte-components } ; + +TUPLE: texture-1d < texture ; +TUPLE: texture-2d < texture ; +TUPLE: texture-rectangle < texture ; +TUPLE: texture-3d < texture ; +TUPLE: texture-cube-map < texture ; + +TUPLE: texture-1d-array < texture ; +TUPLE: texture-2d-array < texture ; + +VARIANT: cube-map-axis + -X -Y -Z +X +Y +Z ; + +TUPLE: cube-map-face + { texture texture-cube-map read-only } + { axis cube-map-axis read-only } ; +C: cube-map-face + +UNION: texture-data-target + texture-1d texture-2d texture-3d cube-map-face ; +UNION: texture-1d-data-target + texture-1d ; +UNION: texture-2d-data-target + texture-2d texture-rectangle texture-1d-array cube-map-face ; +UNION: texture-3d-data-target + texture-3d texture-2d-array ; + +M: texture dispose + [ [ delete-texture ] when* f ] change-handle drop ; + +TUPLE: texture-data + { ptr read-only } + { component-order component-order read-only initial: RGBA } + { component-type component-type read-only initial: ubyte-components } ; + +C: texture-data +UNION: ?texture-data texture-data POSTPONE: f ; +UNION: ?float-array float-array POSTPONE: f ; + +VARIANT: texture-wrap + clamp-texcoord-to-edge clamp-texcoord-to-border repeat-texcoord repeat-texcoord-mirrored ; +VARIANT: texture-filter + filter-nearest filter-linear ; + +UNION: wrap-set texture-wrap sequence ; +UNION: ?texture-filter texture-filter POSTPONE: f ; + +TUPLE: texture-parameters + { wrap wrap-set initial: { repeat-texcoord repeat-texcoord repeat-texcoord } } + { min-filter texture-filter initial: filter-nearest } + { min-mipmap-filter ?texture-filter initial: filter-linear } + { mag-filter texture-filter initial: filter-linear } + { min-lod integer initial: -1000 } + { max-lod integer initial: 1000 } + { lod-bias integer initial: 0 } + { base-level integer initial: 0 } + { max-level integer initial: 1000 } ; + +> ; +M: texture texture-object + ; + +: gl-wrap ( wrap -- gl-wrap ) + { + { clamp-texcoord-to-edge [ GL_CLAMP_TO_EDGE ] } + { clamp-texcoord-to-border [ GL_CLAMP_TO_BORDER ] } + { repeat-texcoord [ GL_REPEAT ] } + { repeat-texcoord-mirrored [ GL_MIRRORED_REPEAT ] } + } case ; + +: set-texture-gl-wrap ( target wraps -- ) + dup sequence? [ 1array ] unless 3 over last pad-tail { + [ [ GL_TEXTURE_WRAP_S ] dip first gl-wrap glTexParameteri ] + [ [ GL_TEXTURE_WRAP_T ] dip second gl-wrap glTexParameteri ] + [ [ GL_TEXTURE_WRAP_R ] dip third gl-wrap glTexParameteri ] + } 2cleave ; + +: gl-mag-filter ( filter -- gl-filter ) + { + { filter-nearest [ GL_NEAREST ] } + { filter-linear [ GL_LINEAR ] } + } case ; + +: gl-min-filter ( filter mipmap-filter -- gl-filter ) + 2array { + { { filter-nearest f } [ GL_NEAREST ] } + { { filter-linear f } [ GL_LINEAR ] } + { { filter-nearest filter-nearest } [ GL_NEAREST_MIPMAP_NEAREST ] } + { { filter-linear filter-nearest } [ GL_LINEAR_MIPMAP_NEAREST ] } + { { filter-linear filter-linear } [ GL_LINEAR_MIPMAP_LINEAR ] } + { { filter-nearest filter-linear } [ GL_NEAREST_MIPMAP_LINEAR ] } + } case ; + +GENERIC: texture-gl-target ( texture -- target ) +GENERIC: texture-data-gl-target ( texture -- target ) + +M: texture-1d texture-gl-target drop GL_TEXTURE_1D ; +M: texture-2d texture-gl-target drop GL_TEXTURE_2D ; +M: texture-rectangle texture-gl-target drop GL_TEXTURE_RECTANGLE ; +M: texture-3d texture-gl-target drop GL_TEXTURE_3D ; +M: texture-cube-map texture-gl-target drop GL_TEXTURE_CUBE_MAP ; +M: texture-1d-array texture-gl-target drop GL_TEXTURE_1D_ARRAY ; +M: texture-2d-array texture-gl-target drop GL_TEXTURE_2D_ARRAY ; + +M: texture-1d texture-data-gl-target drop GL_TEXTURE_1D ; +M: texture-2d texture-data-gl-target drop GL_TEXTURE_2D ; +M: texture-rectangle texture-data-gl-target drop GL_TEXTURE_RECTANGLE ; +M: texture-3d texture-data-gl-target drop GL_TEXTURE_3D ; +M: texture-1d-array texture-data-gl-target drop GL_TEXTURE_1D_ARRAY ; +M: texture-2d-array texture-data-gl-target drop GL_TEXTURE_2D_ARRAY ; +M: cube-map-face texture-data-gl-target + axis>> { + { -X [ GL_TEXTURE_CUBE_MAP_NEGATIVE_X ] } + { -Y [ GL_TEXTURE_CUBE_MAP_NEGATIVE_Y ] } + { -Z [ GL_TEXTURE_CUBE_MAP_NEGATIVE_Z ] } + { +X [ GL_TEXTURE_CUBE_MAP_POSITIVE_X ] } + { +Y [ GL_TEXTURE_CUBE_MAP_POSITIVE_Y ] } + { +Z [ GL_TEXTURE_CUBE_MAP_POSITIVE_Z ] } + } case ; + +: texture-gl-internal-format ( texture -- internal-format ) + [ component-order>> ] [ component-type>> ] bi image-internal-format ; inline + +: texture-data-gl-args ( texture data -- format type ptr ) + [ + nip + [ [ component-order>> ] [ component-type>> ] bi image-data-format ] + [ ptr>> ] bi + ] [ + [ component-order>> ] [ component-type>> ] bi image-data-format f + ] if* ; + +:: bind-tdt ( tdt -- texture ) + tdt texture-object :> texture + texture [ texture-gl-target ] [ handle>> ] bi glBindTexture + texture ; + +: get-texture-float ( target level enum -- value ) + 0 [ glGetTexLevelParameterfv ] keep *float ; +: get-texture-int ( texture level enum -- value ) + 0 [ glGetTexLevelParameteriv ] keep *int ; + +: ?product ( x -- y ) + dup number? [ product ] unless ; + +PRIVATE> + +GENERIC# allocate-texture 3 ( tdt level dim data -- ) + +M:: texture-1d-data-target allocate-texture ( tdt level dim data -- ) + tdt bind-tdt :> texture + tdt texture-data-gl-target level texture texture-gl-internal-format + dim 0 texture data texture-data-gl-args + pixel-unpack-buffer [ glTexImage1D ] with-gpu-data-ptr ; + +M:: texture-2d-data-target allocate-texture ( tdt level dim data -- ) + tdt bind-tdt :> texture + tdt texture-data-gl-target level texture texture-gl-internal-format + dim first2 0 texture data texture-data-gl-args + pixel-unpack-buffer [ glTexImage2D ] with-gpu-data-ptr ; + +M:: texture-3d-data-target allocate-texture ( tdt level dim data -- ) + tdt bind-tdt :> texture + tdt texture-data-gl-target level texture texture-gl-internal-format + dim first3 0 texture data texture-data-gl-args + pixel-unpack-buffer [ glTexImage3D ] with-gpu-data-ptr ; + +GENERIC# update-texture 4 ( tdt level loc dim data -- ) + +M:: texture-1d-data-target update-texture ( tdt level loc dim data -- ) + tdt bind-tdt :> texture + tdt texture-data-gl-target level + loc dim texture data texture-data-gl-args + pixel-unpack-buffer [ glTexSubImage1D ] with-gpu-data-ptr ; + +M:: texture-2d-data-target update-texture ( tdt level loc dim data -- ) + tdt bind-tdt :> texture + tdt texture-data-gl-target level + loc dim [ first2 ] bi@ + texture data texture-data-gl-args + pixel-unpack-buffer [ glTexSubImage2D ] with-gpu-data-ptr ; + +M:: texture-3d-data-target update-texture ( tdt level loc dim data -- ) + tdt bind-tdt :> texture + tdt texture-data-gl-target level + loc dim [ first3 ] bi@ + texture data texture-data-gl-args + pixel-unpack-buffer [ glTexSubImage3D ] with-gpu-data-ptr ; + +: image>texture-data ( image -- dim texture-data ) + { [ dim>> ] [ bitmap>> ] [ component-order>> ] [ component-type>> ] } cleave + ; inline + +GENERIC# texture-dim 1 ( tdt level -- dim ) + +M:: texture-1d-data-target texture-dim ( tdt level -- dim ) + tdt bind-tdt :> texture + tdt texture-data-gl-target level GL_TEXTURE_WIDTH get-texture-int ; + +M:: texture-2d-data-target texture-dim ( tdt level -- dim ) + tdt bind-tdt :> texture + tdt texture-data-gl-target level + [ GL_TEXTURE_WIDTH get-texture-int ] [ GL_TEXTURE_HEIGHT get-texture-int ] 2bi + 2array ; + +M:: texture-3d-data-target texture-dim ( tdt level -- dim ) + tdt bind-tdt :> texture + tdt texture-data-gl-target level + [ GL_TEXTURE_WIDTH get-texture-int ] + [ GL_TEXTURE_HEIGHT get-texture-int ] + [ GL_TEXTURE_DEPTH get-texture-int ] 2tri + 3array ; + +: texture-data-size ( tdt level -- size ) + [ texture-dim ?product ] [ drop texture-object bytes-per-pixel ] 2bi * ; + +:: read-texture-to ( tdt level gpu-data-ptr -- ) + tdt bind-tdt :> texture + tdt texture-data-gl-target level + texture [ component-order>> ] [ component-type>> ] bi image-data-format + gpu-data-ptr pixel-pack-buffer [ glGetTexImage ] with-gpu-data-ptr ; + +: read-texture ( tdt level -- byte-array ) + 2dup texture-data-size + [ read-texture-to ] keep ; + +: allocate-texture-image ( tdt level image -- ) + image>texture-data allocate-texture ; + +: update-texture-image ( tdt level loc image -- ) + image>texture-data update-texture ; + +: read-texture-image ( tdt level -- image ) + [ texture-dim ] + [ drop texture-object [ component-order>> ] [ component-type>> ] bi f ] + [ read-texture ] 2tri + image boa ; + +> ] bi glBindTexture ; +PRIVATE> + +: generate-mipmaps ( texture -- ) + bind-texture glGenerateMipmap ; + +: set-texture-parameters ( texture parameters -- ) + [ bind-texture ] dip { + [ wrap>> set-texture-gl-wrap ] + [ + [ GL_TEXTURE_MIN_FILTER ] dip + [ min-filter>> ] [ min-mipmap-filter>> ] bi gl-min-filter glTexParameteri + ] [ + [ GL_TEXTURE_MAG_FILTER ] dip + mag-filter>> gl-mag-filter glTexParameteri + ] + [ [ GL_TEXTURE_MIN_LOD ] dip min-lod>> glTexParameteri ] + [ [ GL_TEXTURE_MAX_LOD ] dip max-lod>> glTexParameteri ] + [ [ GL_TEXTURE_LOD_BIAS ] dip lod-bias>> glTexParameteri ] + [ [ GL_TEXTURE_BASE_LEVEL ] dip base-level>> glTexParameteri ] + [ [ GL_TEXTURE_MAX_LEVEL ] dip max-level>> glTexParameteri ] + } 2cleave ; + + ( component-order component-type parameters class -- texture ) + '[ [ gen-texture ] 2dip _ boa dup window-resource ] dip + [ T{ texture-parameters } clone ] unless* set-texture-parameters ; inline + +PRIVATE> + +: ( component-order component-type parameters -- texture ) + texture-1d ; +: ( component-order component-type parameters -- texture ) + texture-2d ; +: ( component-order component-type parameters -- texture ) + texture-3d ; +: ( component-order component-type parameters -- texture ) + texture-cube-map ; +: ( component-order component-type parameters -- texture ) + texture-rectangle ; +: ( component-order component-type parameters -- texture ) + texture-1d-array ; +: ( component-order component-type parameters -- texture ) + texture-2d-array ; + diff --git a/extra/gpu/util/authors.txt b/extra/gpu/util/authors.txt new file mode 100644 index 0000000000..f13c9c1e77 --- /dev/null +++ b/extra/gpu/util/authors.txt @@ -0,0 +1 @@ +Joe Groff diff --git a/extra/gpu/util/summary.txt b/extra/gpu/util/summary.txt new file mode 100644 index 0000000000..6670159d8d --- /dev/null +++ b/extra/gpu/util/summary.txt @@ -0,0 +1 @@ +Miscellaneous functions useful for GPU library apps diff --git a/extra/gpu/util/util.factor b/extra/gpu/util/util.factor new file mode 100644 index 0000000000..5b7719d06b --- /dev/null +++ b/extra/gpu/util/util.factor @@ -0,0 +1,63 @@ +! (c)2009 Joe Groff bsd license +USING: gpu.buffers gpu.render gpu.textures images kernel +specialized-arrays.float ; +IN: gpu.util + +CONSTANT: environment-cube-map-mv-matrices + H{ + { +X { + { 0.0 0.0 -1.0 0.0 } + { 0.0 -1.0 0.0 0.0 } + { -1.0 0.0 0.0 0.0 } + { 0.0 0.0 0.0 1.0 } + } } + { +Y { + { 1.0 0.0 0.0 0.0 } + { 0.0 0.0 1.0 0.0 } + { 0.0 -1.0 0.0 0.0 } + { 0.0 0.0 0.0 1.0 } + } } + { +Z { + { 1.0 0.0 0.0 0.0 } + { 0.0 -1.0 0.0 0.0 } + { 0.0 0.0 -1.0 0.0 } + { 0.0 0.0 0.0 1.0 } + } } + { -X { + { 0.0 0.0 1.0 0.0 } + { 0.0 -1.0 0.0 0.0 } + { 1.0 0.0 0.0 0.0 } + { 0.0 0.0 0.0 1.0 } + } } + { -Y { + { 1.0 0.0 0.0 0.0 } + { 0.0 0.0 -1.0 0.0 } + { 0.0 1.0 0.0 0.0 } + { 0.0 0.0 0.0 1.0 } + } } + { -Z { + { -1.0 0.0 0.0 0.0 } + { 0.0 -1.0 0.0 0.0 } + { 0.0 0.0 1.0 0.0 } + { 0.0 0.0 0.0 1.0 } + } } + } + +VERTEX-FORMAT: window-vertex + { "vertex" float-components 2 f } ; + +CONSTANT: window-vertexes + float-array{ + -1.0 -1.0 + -1.0 1.0 + 1.0 -1.0 + 1.0 1.0 + } + +: ( -- buffer ) + window-vertexes + static-upload draw-usage vertex-buffer + byte-array>buffer ; + +: ( program-instance -- vertex-array ) + [ ] dip window-vertex buffer>vertex-array ; diff --git a/extra/gpu/util/wasd/authors.txt b/extra/gpu/util/wasd/authors.txt new file mode 100644 index 0000000000..f13c9c1e77 --- /dev/null +++ b/extra/gpu/util/wasd/authors.txt @@ -0,0 +1 @@ +Joe Groff diff --git a/extra/gpu/util/wasd/summary.txt b/extra/gpu/util/wasd/summary.txt new file mode 100644 index 0000000000..eacc97dd08 --- /dev/null +++ b/extra/gpu/util/wasd/summary.txt @@ -0,0 +1 @@ +Scaffolding for demo scenes that can be explored using FPS-style controls diff --git a/extra/gpu/util/wasd/wasd.factor b/extra/gpu/util/wasd/wasd.factor new file mode 100644 index 0000000000..34051730fb --- /dev/null +++ b/extra/gpu/util/wasd/wasd.factor @@ -0,0 +1,128 @@ +! (c)2009 Joe Groff bsd license +USING: accessors arrays combinators.smart game-input +game-input.scancodes game-loop game-worlds +gpu.render gpu.state kernel literals +locals math math.constants math.functions math.matrices +math.order math.vectors opengl.gl sequences +specialized-arrays.float ui ui.gadgets.worlds ; +IN: gpu.util.wasd + +UNIFORM-TUPLE: mvp-uniforms + { "mv_matrix" float-uniform { 4 4 } } + { "p_matrix" float-uniform { 4 4 } } ; + +CONSTANT: -pi/2 $[ pi -2.0 / ] +CONSTANT: pi/2 $[ pi 2.0 / ] + +TUPLE: wasd-world < game-world location yaw pitch p-matrix ; + +GENERIC: wasd-near-plane ( world -- near-plane ) +M: wasd-world wasd-near-plane drop 0.25 ; + +GENERIC: wasd-far-plane ( world -- far-plane ) +M: wasd-world wasd-far-plane drop 1024.0 ; + +GENERIC: wasd-movement-speed ( world -- speed ) +M: wasd-world wasd-movement-speed drop 1/16. ; + +GENERIC: wasd-mouse-scale ( world -- scale ) +M: wasd-world wasd-mouse-scale drop 1/600. ; + +GENERIC: wasd-pitch-range ( world -- min max ) +M: wasd-world wasd-pitch-range drop -pi/2 pi/2 ; + +GENERIC: wasd-fly-vertically? ( world -- ? ) +M: wasd-world wasd-fly-vertically? drop t ; + +: wasd-mv-matrix ( world -- matrix ) + [ { 1.0 0.0 0.0 } swap pitch>> rotation-matrix4 ] + [ { 0.0 1.0 0.0 } swap yaw>> rotation-matrix4 ] + [ location>> vneg translation-matrix4 ] tri m. m. ; + +: wasd-mv-inv-matrix ( world -- matrix ) + [ location>> translation-matrix4 ] + [ { 0.0 -1.0 0.0 } swap yaw>> rotation-matrix4 ] + [ { -1.0 0.0 0.0 } swap pitch>> rotation-matrix4 ] tri m. m. ; + +: wasd-p-matrix ( world -- matrix ) + p-matrix>> ; + +CONSTANT: fov 0.7 + +:: generate-p-matrix ( world -- matrix ) + world wasd-near-plane :> near-plane + world wasd-far-plane :> far-plane + + world dim>> dup first2 min >float v/n fov v*n near-plane v*n + near-plane far-plane frustum-matrix4 ; + +: set-wasd-view ( world location yaw pitch -- world ) + [ >>location ] [ >>yaw ] [ >>pitch ] tri* ; + +:: eye-rotate ( yaw pitch v -- v' ) + yaw neg :> y + pitch neg :> p + y cos :> cosy + y sin :> siny + p cos :> cosp + p sin :> sinp + + cosy 0.0 siny neg 3array + siny sinp * cosp cosy sinp * 3array + siny cosp * sinp neg cosy cosp * 3array 3array + v swap v.m ; + +: ?pitch ( world -- pitch ) + dup wasd-fly-vertically? [ pitch>> ] [ drop 0.0 ] if ; + +: forward-vector ( world -- v ) + [ yaw>> ] [ ?pitch ] [ wasd-movement-speed ] tri + { 0.0 0.0 -1.0 } n*v eye-rotate ; +: rightward-vector ( world -- v ) + [ yaw>> ] [ ?pitch ] [ wasd-movement-speed ] tri + { 1.0 0.0 0.0 } n*v eye-rotate ; + +: walk-forward ( world -- ) + dup forward-vector [ v+ ] curry change-location drop ; +: walk-backward ( world -- ) + dup forward-vector [ v- ] curry change-location drop ; +: walk-leftward ( world -- ) + dup rightward-vector [ v- ] curry change-location drop ; +: walk-rightward ( world -- ) + dup rightward-vector [ v+ ] curry change-location drop ; +: walk-upward ( world -- ) + dup wasd-movement-speed { 0.0 1.0 0.0 } n*v [ v+ ] curry change-location drop ; +: walk-downward ( world -- ) + dup wasd-movement-speed { 0.0 1.0 0.0 } n*v [ v- ] curry change-location drop ; + +: clamp-pitch ( world -- world ) + dup [ wasd-pitch-range clamp ] curry change-pitch ; + +: rotate-with-mouse ( world mouse -- ) + [ [ dup wasd-mouse-scale ] [ dx>> ] bi* * [ + ] curry change-yaw ] + [ [ dup wasd-mouse-scale ] [ dy>> ] bi* * [ + ] curry change-pitch clamp-pitch ] bi + drop ; + +:: wasd-keyboard-input ( world -- ) + read-keyboard keys>> :> keys + key-w keys nth key-, keys nth or [ world walk-forward ] when + key-s keys nth key-o keys nth or [ world walk-backward ] when + key-a keys nth [ world walk-leftward ] when + key-d keys nth key-e keys nth or [ world walk-rightward ] when + key-space keys nth [ world walk-upward ] when + key-c keys nth key-j keys nth or [ world walk-downward ] when + key-escape keys nth [ world close-window ] when ; + +: wasd-mouse-input ( world -- ) + read-mouse rotate-with-mouse ; + +M: wasd-world tick* + dup focused?>> [ + [ wasd-keyboard-input ] [ wasd-mouse-input ] bi + reset-mouse + ] [ drop ] if ; + +M: wasd-world resize-world + [ set-gpu-state* ] + [ dup generate-p-matrix >>p-matrix drop ] bi ; + From 8e9badd4f54e7d40f9276d340fdb6fd9a7bcee89 Mon Sep 17 00:00:00 2001 From: Maximilian Lupke Date: Mon, 20 Jul 2009 01:31:26 +0200 Subject: [PATCH 84/96] sequences.abbrev: Initial commit --- extra/sequences/abbrev/abbrev-tests.factor | 26 ++++++++++++++++++++++ extra/sequences/abbrev/abbrev.factor | 23 +++++++++++++++++++ extra/sequences/abbrev/authors.txt | 1 + 3 files changed, 50 insertions(+) create mode 100644 extra/sequences/abbrev/abbrev-tests.factor create mode 100644 extra/sequences/abbrev/abbrev.factor create mode 100644 extra/sequences/abbrev/authors.txt diff --git a/extra/sequences/abbrev/abbrev-tests.factor b/extra/sequences/abbrev/abbrev-tests.factor new file mode 100644 index 0000000000..6e6739e09a --- /dev/null +++ b/extra/sequences/abbrev/abbrev-tests.factor @@ -0,0 +1,26 @@ +USING: assocs sequences.abbrev tools.test ; +IN: sequences.abbrev.tests + +[ { "help" "hello" } ] [ + "he" { "apple" "hello" "help" } abbrev at +] unit-test + +[ f ] [ + "he" { "apple" "hello" "help" } unique-abbrev at +] unit-test + +[ { "apple" } ] [ + "a" { "apple" "hello" "help" } abbrev at +] unit-test + +[ { "apple" } ] [ + "a" { "apple" "hello" "help" } unique-abbrev at +] unit-test + +[ f ] [ + "a" { "hello" "help" } abbrev at +] unit-test + +[ f ] [ + "a" { "hello" "help" } unique-abbrev at +] unit-test diff --git a/extra/sequences/abbrev/abbrev.factor b/extra/sequences/abbrev/abbrev.factor new file mode 100644 index 0000000000..526737bd55 --- /dev/null +++ b/extra/sequences/abbrev/abbrev.factor @@ -0,0 +1,23 @@ +! Copyright (C) 2009 Maximilian Lupke. +! See http://factorcode.org/license.txt for BSD license. +USING: arrays assocs fry kernel math.ranges sequences ; +IN: sequences.abbrev + +assoc ; + +: assoc-merge ( assoc1 assoc2 -- assoc3 ) + swap over '[ over _ at dup [ prepend ] [ drop ] if ] assoc-map assoc-union ; + +PRIVATE> + +: abbrev ( seqs -- assoc ) + [ (abbrev) ] map H{ } [ assoc-merge ] reduce ; + +: unique-abbrev ( seqs -- assoc ) + abbrev [ nip length 1 = ] assoc-filter ; diff --git a/extra/sequences/abbrev/authors.txt b/extra/sequences/abbrev/authors.txt new file mode 100644 index 0000000000..758ea89529 --- /dev/null +++ b/extra/sequences/abbrev/authors.txt @@ -0,0 +1 @@ +Maximilian Lupke From 52e09199e12be8c4a4e4f7c56a51099c84a2ceb8 Mon Sep 17 00:00:00 2001 From: Maximilian Lupke Date: Mon, 20 Jul 2009 01:40:20 +0200 Subject: [PATCH 85/96] sequences.abbrev: small refactoring --- extra/sequences/abbrev/abbrev.factor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extra/sequences/abbrev/abbrev.factor b/extra/sequences/abbrev/abbrev.factor index 526737bd55..bab8bb94b2 100644 --- a/extra/sequences/abbrev/abbrev.factor +++ b/extra/sequences/abbrev/abbrev.factor @@ -6,7 +6,7 @@ IN: sequences.abbrev assoc ; From e3ec2b6c8bbb018ebeeb58ffbe231281ebdc6ce1 Mon Sep 17 00:00:00 2001 From: Maximilian Lupke Date: Mon, 20 Jul 2009 17:22:55 +0200 Subject: [PATCH 86/96] sequences.abbrev: more small refactoring --- extra/sequences/abbrev/abbrev.factor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extra/sequences/abbrev/abbrev.factor b/extra/sequences/abbrev/abbrev.factor index bab8bb94b2..d5bba8951e 100644 --- a/extra/sequences/abbrev/abbrev.factor +++ b/extra/sequences/abbrev/abbrev.factor @@ -12,7 +12,7 @@ IN: sequences.abbrev [ prefixes ] keep 1array '[ _ ] H{ } map>assoc ; : assoc-merge ( assoc1 assoc2 -- assoc3 ) - swap over '[ over _ at dup [ prepend ] [ drop ] if ] assoc-map assoc-union ; + tuck '[ over _ at dup [ prepend ] [ drop ] if ] assoc-map assoc-union ; PRIVATE> From ea7cbd2b5afab52059973509c426d595d167a5c3 Mon Sep 17 00:00:00 2001 From: Maximilian Lupke Date: Mon, 20 Jul 2009 20:18:13 +0200 Subject: [PATCH 87/96] sequences.abbrev: keep insertion order --- extra/sequences/abbrev/abbrev-tests.factor | 2 +- extra/sequences/abbrev/abbrev.factor | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/extra/sequences/abbrev/abbrev-tests.factor b/extra/sequences/abbrev/abbrev-tests.factor index 6e6739e09a..39e445b495 100644 --- a/extra/sequences/abbrev/abbrev-tests.factor +++ b/extra/sequences/abbrev/abbrev-tests.factor @@ -1,7 +1,7 @@ USING: assocs sequences.abbrev tools.test ; IN: sequences.abbrev.tests -[ { "help" "hello" } ] [ +[ { "hello" "help" } ] [ "he" { "apple" "hello" "help" } abbrev at ] unit-test diff --git a/extra/sequences/abbrev/abbrev.factor b/extra/sequences/abbrev/abbrev.factor index d5bba8951e..6770a48a3a 100644 --- a/extra/sequences/abbrev/abbrev.factor +++ b/extra/sequences/abbrev/abbrev.factor @@ -12,7 +12,7 @@ IN: sequences.abbrev [ prefixes ] keep 1array '[ _ ] H{ } map>assoc ; : assoc-merge ( assoc1 assoc2 -- assoc3 ) - tuck '[ over _ at dup [ prepend ] [ drop ] if ] assoc-map assoc-union ; + tuck '[ over _ at dup [ append ] [ drop ] if ] assoc-map assoc-union ; PRIVATE> From 08814c33085f4901683c853abcf5913f4cf949a1 Mon Sep 17 00:00:00 2001 From: Maximilian Lupke Date: Tue, 21 Jul 2009 00:37:45 +0200 Subject: [PATCH 88/96] sequences.abbrev: add docs - not much, but a start --- extra/sequences/abbrev/abbrev-docs.factor | 28 +++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 extra/sequences/abbrev/abbrev-docs.factor diff --git a/extra/sequences/abbrev/abbrev-docs.factor b/extra/sequences/abbrev/abbrev-docs.factor new file mode 100644 index 0000000000..ae351914de --- /dev/null +++ b/extra/sequences/abbrev/abbrev-docs.factor @@ -0,0 +1,28 @@ +! Copyright (C) 2009 Maximilian Lupke. +! See http://factorcode.org/license.txt for BSD license. +USING: assocs help.markup help.syntax sequences ; +IN: sequences.abbrev + +HELP: abbrev +{ $values + { "seqs" sequence } + { "assoc" assoc } +} +{ $description "Calculates an assoc of { prefix sequence } pairs with prefix being an prefix of each element of sequence for each element in " { $snippet "seqs" } "." } ; + +HELP: unique-abbrev +{ $values + { "seqs" sequence } + { "assoc" assoc } +} +{ $description "Calculates an assoc of { prefix { sequence } } pairs with prefix being an unambiguous prefix of sequence in seqs." } ; + +ARTICLE: "sequences.abbrev" "Examples of abbrev usage" +"It is probably easiest to just run examples to understand abbrev." +{ $code + "{ \"hello\" \"help\" } abbrev" + "{ \"hello\" \"help\" } unique-abbrev" +} +; + +ABOUT: "sequences.abbrev" From fd9a353fd6cce01933e81db1727cc5772159a6ca Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 21 Jul 2009 03:02:06 -0500 Subject: [PATCH 89/96] Move conjoin-at from compiler.cfg.liveness to sets --- basis/compiler/cfg/liveness/liveness.factor | 3 --- core/sets/sets-docs.factor | 5 +++++ core/sets/sets.factor | 3 +++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/basis/compiler/cfg/liveness/liveness.factor b/basis/compiler/cfg/liveness/liveness.factor index 8a46b32070..9dc320660c 100644 --- a/basis/compiler/cfg/liveness/liveness.factor +++ b/basis/compiler/cfg/liveness/liveness.factor @@ -43,9 +43,6 @@ SYMBOL: work-list [ nip kill-set ] 2bi assoc-diff ; -: conjoin-at ( value key assoc -- ) - [ dupd ?set-at ] change-at ; - : compute-phi-live-in ( basic-block -- phi-live-in ) instructions>> [ ##phi? ] filter [ f ] [ H{ } clone [ diff --git a/core/sets/sets-docs.factor b/core/sets/sets-docs.factor index 0fce78dd68..cec3d65d3c 100755 --- a/core/sets/sets-docs.factor +++ b/core/sets/sets-docs.factor @@ -23,6 +23,7 @@ $nl "Adding elements to sets:" { $subsection adjoin } { $subsection conjoin } +{ $subsection conjoin-at } { $see-also member? memq? any? all? "assocs-sets" } ; ABOUT: "sets" @@ -54,6 +55,10 @@ HELP: conjoin } { $side-effects "assoc" } ; +HELP: conjoin-at +{ $values { "value" object } { "key" object } { "assoc" assoc } } +{ $description "Adds " { $snippet "value" } " to the set stored at " { $snippet "key" } " of " { $snippet "assoc" } "." } ; + HELP: unique { $values { "seq" "a sequence" } { "assoc" assoc } } { $description "Outputs a new assoc where the keys and values are equal." } diff --git a/core/sets/sets.factor b/core/sets/sets.factor index 062b624e8f..c7b834297a 100755 --- a/core/sets/sets.factor +++ b/core/sets/sets.factor @@ -7,6 +7,9 @@ IN: sets : conjoin ( elt assoc -- ) dupd set-at ; +: conjoin-at ( value key assoc -- ) + [ dupd ?set-at ] change-at ; + : (prune) ( elt hash vec -- ) 3dup drop key? [ 3drop ] [ [ drop conjoin ] [ nip push ] 3bi From 3136549f489cc573b53c461700e92a12b9190989 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 21 Jul 2009 03:02:45 -0500 Subject: [PATCH 90/96] compiler.cfg.dominance: fix idom computation, compute dominator tree, compute dominance frontiers, add some tests --- .../cfg/dominance/dominance-tests.factor | 77 +++++++++++++++++++ basis/compiler/cfg/dominance/dominance.factor | 76 +++++++++++++++--- 2 files changed, 141 insertions(+), 12 deletions(-) create mode 100644 basis/compiler/cfg/dominance/dominance-tests.factor diff --git a/basis/compiler/cfg/dominance/dominance-tests.factor b/basis/compiler/cfg/dominance/dominance-tests.factor new file mode 100644 index 0000000000..e3e0d09cfc --- /dev/null +++ b/basis/compiler/cfg/dominance/dominance-tests.factor @@ -0,0 +1,77 @@ +IN: compiler.cfg.dominance.tests +USING: tools.test sequences vectors namespaces kernel accessors assocs sets +math.ranges arrays compiler.cfg compiler.cfg.dominance compiler.cfg.debugger +compiler.cfg.predecessors ; + +: test-dominance ( -- ) + cfg new 0 get >>entry + compute-predecessors + compute-dominance + drop ; + +! Example with no back edges +V{ } 0 test-bb +V{ } 1 test-bb +V{ } 2 test-bb +V{ } 3 test-bb +V{ } 4 test-bb +V{ } 5 test-bb + +0 get 1 get 2 get V{ } 2sequence >>successors drop +1 get 3 get 1vector >>successors drop +2 get 4 get 1vector >>successors drop +3 get 4 get 1vector >>successors drop +4 get 5 get 1vector >>successors drop + +[ ] [ test-dominance ] unit-test + +[ t ] [ 0 get dom-parent 0 get eq? ] unit-test +[ t ] [ 1 get dom-parent 0 get eq? ] unit-test +[ t ] [ 2 get dom-parent 0 get eq? ] unit-test +[ t ] [ 4 get dom-parent 0 get eq? ] unit-test +[ t ] [ 3 get dom-parent 1 get eq? ] unit-test +[ t ] [ 5 get dom-parent 4 get eq? ] unit-test + +[ t ] [ 0 get dom-children 1 get 2 get 4 get 3array set= ] unit-test + +[ t ] [ 4 get 1 get dom-frontier key? ] unit-test +[ f ] [ 3 get 1 get dom-frontier key? ] unit-test +[ t ] [ 4 get 2 get dom-frontier key? ] unit-test +[ t ] [ 0 get dom-frontier assoc-empty? ] unit-test +[ t ] [ 4 get dom-frontier assoc-empty? ] unit-test + +! Example from the paper +V{ } 0 test-bb +V{ } 1 test-bb +V{ } 2 test-bb +V{ } 3 test-bb +V{ } 4 test-bb + +0 get 1 get 2 get V{ } 2sequence >>successors drop +1 get 3 get 1vector >>successors drop +2 get 4 get 1vector >>successors drop +3 get 4 get 1vector >>successors drop +4 get 3 get 1vector >>successors drop + +[ ] [ test-dominance ] unit-test + +[ t ] [ 0 4 [a,b] [ get dom-parent 0 get eq? ] all? ] unit-test + +! The other example from the paper +V{ } 0 test-bb +V{ } 1 test-bb +V{ } 2 test-bb +V{ } 3 test-bb +V{ } 4 test-bb +V{ } 5 test-bb + +0 get 1 get 2 get V{ } 2sequence >>successors drop +1 get 5 get 1vector >>successors drop +2 get 4 get 3 get V{ } 2sequence >>successors drop +5 get 4 get 1vector >>successors drop +4 get 5 get 3 get V{ } 2sequence >>successors drop +3 get 4 get 1vector >>successors drop + +[ ] [ test-dominance ] unit-test + +[ t ] [ 0 5 [a,b] [ get dom-parent 0 get eq? ] all? ] unit-test diff --git a/basis/compiler/cfg/dominance/dominance.factor b/basis/compiler/cfg/dominance/dominance.factor index 750a46ee6c..8b8d006560 100644 --- a/basis/compiler/cfg/dominance/dominance.factor +++ b/basis/compiler/cfg/dominance/dominance.factor @@ -1,6 +1,6 @@ ! Copyright (C) 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: accessors assocs combinators compiler.cfg.rpo +USING: accessors assocs combinators sets math compiler.cfg.rpo compiler.cfg.stack-analysis fry kernel math.order namespaces sequences ; IN: compiler.cfg.dominance @@ -11,31 +11,83 @@ IN: compiler.cfg.dominance ! Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy ! http://www.cs.rice.edu/~keith/EMBED/dom.pdf -SYMBOL: idoms - -: idom ( bb -- bb' ) idoms get at ; +! Also, a nice overview is given in these lecture notes: +! http://llvm.cs.uiuc.edu/~vadve/CS526/public_html/Notes/4ssa.4up.pdf idom(bb) +SYMBOL: dom-parents + +PRIVATE> + +: dom-parent ( bb -- bb' ) dom-parents get at ; + +> ] compare { - { +lt+ [ [ idom ] dip intersect ] } - { +gt+ [ idom intersect ] } + { +gt+ [ [ dom-parent ] dip intersect ] } + { +lt+ [ dom-parent intersect ] } [ 2drop ] } case ; : compute-idom ( bb -- idom ) - predecessors>> [ idom ] map sift + predecessors>> [ dom-parent ] filter [ ] [ intersect ] map-reduce ; : iterate ( rpo -- changed? ) [ [ compute-idom ] keep set-idom ] map [ ] any? ; +: compute-dom-parents ( cfg -- ) + H{ } clone dom-parents set + reverse-post-order + unclip dup set-idom drop '[ _ iterate ] loop ; + +! Maps bb -> {bb' | idom(bb') = bb} +SYMBOL: dom-childrens + PRIVATE> -: compute-dominance ( cfg -- cfg ) - H{ } clone idoms set - dup reverse-post-order - unclip dup set-idom drop '[ _ iterate ] loop ; \ No newline at end of file +: dom-children ( bb -- seq ) dom-childrens get at ; + + DF(bb) +SYMBOL: dom-frontiers + +PRIVATE> + +: dom-frontier ( bb -- set ) dom-frontiers get at ; + +> dup length 2 >= [ + [ compute-dom-frontier ] with each + ] [ 2drop ] if + ] each-basic-block ; + +PRIVATE> + +: compute-dominance ( cfg -- cfg' ) + [ compute-dom-parents compute-dom-children ] + [ compute-dom-frontiers ] + [ ] + tri ; From e7e5bee9a278e554a1f151586c715feaf6921819 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 21 Jul 2009 17:49:30 -0500 Subject: [PATCH 91/96] compiler.cfg.ssa: Cytron's SSA construction algorithm --- .../cfg/dominance/dominance-tests.factor | 9 +- basis/compiler/cfg/dominance/dominance.factor | 7 +- basis/compiler/cfg/renaming/renaming.factor | 8 + basis/compiler/cfg/ssa/ssa-tests.factor | 79 ++++++++++ basis/compiler/cfg/ssa/ssa.factor | 146 ++++++++++++++++++ 5 files changed, 240 insertions(+), 9 deletions(-) create mode 100644 basis/compiler/cfg/ssa/ssa-tests.factor create mode 100644 basis/compiler/cfg/ssa/ssa.factor diff --git a/basis/compiler/cfg/dominance/dominance-tests.factor b/basis/compiler/cfg/dominance/dominance-tests.factor index e3e0d09cfc..b87f668d88 100644 --- a/basis/compiler/cfg/dominance/dominance-tests.factor +++ b/basis/compiler/cfg/dominance/dominance-tests.factor @@ -34,11 +34,10 @@ V{ } 5 test-bb [ t ] [ 0 get dom-children 1 get 2 get 4 get 3array set= ] unit-test -[ t ] [ 4 get 1 get dom-frontier key? ] unit-test -[ f ] [ 3 get 1 get dom-frontier key? ] unit-test -[ t ] [ 4 get 2 get dom-frontier key? ] unit-test -[ t ] [ 0 get dom-frontier assoc-empty? ] unit-test -[ t ] [ 4 get dom-frontier assoc-empty? ] unit-test +[ { 4 } ] [ 1 get dom-frontier [ number>> ] map ] unit-test +[ { 4 } ] [ 2 get dom-frontier [ number>> ] map ] unit-test +[ f ] [ 0 get dom-frontier ] unit-test +[ f ] [ 4 get dom-frontier ] unit-test ! Example from the paper V{ } 0 test-bb diff --git a/basis/compiler/cfg/dominance/dominance.factor b/basis/compiler/cfg/dominance/dominance.factor index 8b8d006560..9c8fc79619 100644 --- a/basis/compiler/cfg/dominance/dominance.factor +++ b/basis/compiler/cfg/dominance/dominance.factor @@ -1,8 +1,7 @@ ! Copyright (C) 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: accessors assocs combinators sets math compiler.cfg.rpo -compiler.cfg.stack-analysis fry kernel math.order namespaces -sequences ; +USING: accessors assocs combinators sets math fry kernel math.order +namespaces sequences sorting compiler.cfg.rpo ; IN: compiler.cfg.dominance ! Reference: @@ -66,7 +65,7 @@ SYMBOL: dom-frontiers PRIVATE> -: dom-frontier ( bb -- set ) dom-frontiers get at ; +: dom-frontier ( bb -- set ) dom-frontiers get at keys ; >successors drop +1 get 3 get 1vector >>successors drop +2 get 3 get 1vector >>successors drop + +: test-ssa ( -- ) + cfg new 0 get >>entry + compute-predecessors + compute-dominance + construct-ssa + drop ; + +[ ] [ test-ssa ] unit-test + +[ + V{ + T{ ##load-immediate f V int-regs 1 100 } + T{ ##add-imm f V int-regs 2 V int-regs 1 50 } + T{ ##add-imm f V int-regs 3 V int-regs 2 10 } + T{ ##branch } + } +] [ 0 get instructions>> ] unit-test + +[ + V{ + T{ ##load-immediate f V int-regs 4 3 } + T{ ##branch } + } +] [ 1 get instructions>> ] unit-test + +[ + V{ + T{ ##load-immediate f V int-regs 5 4 } + T{ ##branch } + } +] [ 2 get instructions>> ] unit-test + +[ + V{ + T{ ##phi f V int-regs 6 H{ { 1 V int-regs 4 } { 2 V int-regs 5 } } } + T{ ##replace f V int-regs 6 D 0 } + T{ ##return } + } +] [ + 3 get instructions>> + [ dup ##phi? [ [ [ [ number>> ] dip ] assoc-map ] change-inputs ] when ] map +] unit-test \ No newline at end of file diff --git a/basis/compiler/cfg/ssa/ssa.factor b/basis/compiler/cfg/ssa/ssa.factor new file mode 100644 index 0000000000..e11701965b --- /dev/null +++ b/basis/compiler/cfg/ssa/ssa.factor @@ -0,0 +1,146 @@ +! Copyright (C) 2009 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: namespaces kernel accessors sequences fry dlists +deques assocs sets math combinators sorting +compiler.cfg +compiler.cfg.rpo +compiler.cfg.def-use +compiler.cfg.renaming +compiler.cfg.registers +compiler.cfg.dominance +compiler.cfg.instructions ; +IN: compiler.cfg.ssa + +! SSA construction. Predecessors and dominance must be computed first. + +! This is the classical algorithm based on dominance frontiers: +! http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.25.8240 + +! Eventually might be worth trying something fancier: +! http://portal.acm.org/citation.cfm?id=1065887.1065890 + +> [ + defs-vregs [ + _ push-at + ] with each + ] with each + ] each-basic-block ; + +SYMBOLS: has-already ever-on-work-list work-list ; + +: init-insert-phi-nodes ( bbs -- ) + H{ } clone has-already set + [ unique ever-on-work-list set ] + [ [ push-all-front ] keep work-list set ] bi ; + +: add-to-work-list ( bb -- ) + dup ever-on-work-list get key? [ drop ] [ + [ ever-on-work-list get conjoin ] + [ work-list get push-front ] + bi + ] if ; + +: insert-phi-node-later ( vreg bb -- ) + [ predecessors>> over '[ _ ] H{ } map>assoc \ ##phi new-insn ] keep + inserting-phi-nodes get push-at ; + +: compute-phi-node-in ( vreg bb -- ) + dup has-already get key? [ 2drop ] [ + [ insert-phi-node-later ] + [ has-already get conjoin ] + [ add-to-work-list ] + tri + ] if ; + +: compute-phi-nodes-for ( vreg bbs -- ) + dup length 2 >= [ + init-insert-phi-nodes + work-list get [ + dom-frontier [ + compute-phi-node-in + ] with each + ] with slurp-deque + ] [ 2drop ] if ; + +: compute-phi-nodes ( -- ) + H{ } clone inserting-phi-nodes set + defs get [ compute-phi-nodes-for ] assoc-each ; + +: insert-phi-nodes-in ( phis bb -- ) + [ append ] change-instructions drop ; + +: insert-phi-nodes ( -- ) + inserting-phi-nodes get [ swap insert-phi-nodes-in ] assoc-each ; + +SYMBOLS: stacks originals ; + +: init-renaming ( -- ) + H{ } clone stacks set + H{ } clone originals set ; + +: gen-name ( vreg -- vreg' ) + [ reg-class>> next-vreg ] keep + [ stacks get push-at ] + [ swap originals get set-at ] + [ drop ] + 2tri ; + +: top-name ( vreg -- vreg' ) + stacks get at last ; + +GENERIC: rename-insn ( insn -- ) + +M: insn rename-insn + [ dup uses-vregs [ dup top-name ] { } map>assoc renamings set rename-insn-uses ] + [ dup defs-vregs [ dup gen-name ] { } map>assoc renamings set rename-insn-defs ] + bi ; + +M: ##phi rename-insn + dup defs-vregs [ dup gen-name ] { } map>assoc renamings set rename-insn-defs ; + +: rename-insns ( bb -- ) + instructions>> [ rename-insn ] each ; + +: rename-successor-phi ( phi bb -- ) + swap inputs>> [ top-name ] change-at ; + +: rename-successor-phis ( succ bb -- ) + [ inserting-phi-nodes get at ] dip + '[ _ rename-successor-phi ] each ; + +: rename-successors-phis ( bb -- ) + [ successors>> ] keep '[ _ rename-successor-phis ] each ; + +: pop-stacks ( bb -- ) + instructions>> [ + defs-vregs originals get stacks get + '[ _ at _ at pop* ] each + ] each ; + +: rename-in-block ( bb -- ) + { + [ rename-insns ] + [ rename-successors-phis ] + [ dom-children [ rename-in-block ] each ] + [ pop-stacks ] + } cleave ; + +: rename ( cfg -- ) + init-renaming + entry>> rename-in-block ; + +PRIVATE> + +: construct-ssa ( cfg -- cfg' ) + dup [ compute-defs compute-phi-nodes insert-phi-nodes ] [ rename ] bi ; \ No newline at end of file From ead57fc5dde4cc15770d74301f197be96e9777a0 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 21 Jul 2009 17:49:44 -0500 Subject: [PATCH 92/96] compiler.cfg.registers: minor optimization --- basis/compiler/cfg/registers/registers.factor | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/basis/compiler/cfg/registers/registers.factor b/basis/compiler/cfg/registers/registers.factor index 71f313be5a..c5b3907153 100644 --- a/basis/compiler/cfg/registers/registers.factor +++ b/basis/compiler/cfg/registers/registers.factor @@ -1,11 +1,17 @@ -! Copyright (C) 2008 Slava Pestov. +! Copyright (C) 2008, 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: accessors namespaces kernel arrays parser ; +USING: accessors namespaces kernel arrays parser math math.order ; IN: compiler.cfg.registers ! Virtual registers, used by CFG and machine IRs -TUPLE: vreg { reg-class read-only } { n read-only } ; +TUPLE: vreg { reg-class read-only } { n fixnum read-only } ; + +M: vreg equal? over vreg? [ [ n>> ] bi@ eq? ] [ 2drop f ] if ; + +M: vreg hashcode* nip n>> ; + SYMBOL: vreg-counter + : next-vreg ( reg-class -- vreg ) \ vreg-counter counter vreg boa ; ! Stack locations -- 'n' is an index starting from the top of the stack From 1aa6c9a0d538812370d499b274f69cdeedbc4c26 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 21 Jul 2009 22:25:19 -0500 Subject: [PATCH 93/96] compiler.cfg: Fix unit tests --- .../cfg/dominance/dominance-tests.factor | 4 ++-- .../phi-elimination-tests.factor | 23 +++++++------------ .../value-numbering-tests.factor | 11 --------- 3 files changed, 10 insertions(+), 28 deletions(-) diff --git a/basis/compiler/cfg/dominance/dominance-tests.factor b/basis/compiler/cfg/dominance/dominance-tests.factor index b87f668d88..210d5614c2 100644 --- a/basis/compiler/cfg/dominance/dominance-tests.factor +++ b/basis/compiler/cfg/dominance/dominance-tests.factor @@ -36,8 +36,8 @@ V{ } 5 test-bb [ { 4 } ] [ 1 get dom-frontier [ number>> ] map ] unit-test [ { 4 } ] [ 2 get dom-frontier [ number>> ] map ] unit-test -[ f ] [ 0 get dom-frontier ] unit-test -[ f ] [ 4 get dom-frontier ] unit-test +[ { } ] [ 0 get dom-frontier ] unit-test +[ { } ] [ 4 get dom-frontier ] unit-test ! Example from the paper V{ } 0 test-bb diff --git a/basis/compiler/cfg/phi-elimination/phi-elimination-tests.factor b/basis/compiler/cfg/phi-elimination/phi-elimination-tests.factor index 79d1797720..22afc0b32b 100644 --- a/basis/compiler/cfg/phi-elimination/phi-elimination-tests.factor +++ b/basis/compiler/cfg/phi-elimination/phi-elimination-tests.factor @@ -36,27 +36,20 @@ V{ test-diamond +3 vreg-counter set-global + [ ] [ cfg new 0 get >>entry eliminate-phis drop ] unit-test -[let | n! [ f ] | - -[ ] [ 2 get successors>> first instructions>> first dst>> n>> n! ] unit-test - -[ t ] [ - T{ ##copy f V int-regs n V int-regs 1 } - 2 get successors>> first instructions>> first = +[ T{ ##copy f V int-regs 4 V int-regs 1 } ] [ + 2 get successors>> first instructions>> first ] unit-test -[ t ] [ - T{ ##copy f V int-regs n V int-regs 2 } - 3 get successors>> first instructions>> first = +[ T{ ##copy f V int-regs 4 V int-regs 2 } ] [ + 3 get successors>> first instructions>> first ] unit-test -[ t ] [ - T{ ##copy f V int-regs 3 V int-regs n } - 4 get instructions>> first = +[ T{ ##copy f V int-regs 3 V int-regs 4 } ] [ + 4 get instructions>> first ] unit-test -] - [ 3 ] [ 4 get instructions>> length ] unit-test diff --git a/basis/compiler/cfg/value-numbering/value-numbering-tests.factor b/basis/compiler/cfg/value-numbering/value-numbering-tests.factor index 62ed4a7eb3..bd2bb692b7 100644 --- a/basis/compiler/cfg/value-numbering/value-numbering-tests.factor +++ b/basis/compiler/cfg/value-numbering/value-numbering-tests.factor @@ -1218,17 +1218,6 @@ test-diamond [ t ] [ 1 get successors>> first 3 get eq? ] unit-test -[let | n! [ f ] | - -[ ] [ 2 get successors>> first instructions>> first src>> n>> n! ] unit-test - -[ t ] [ - T{ ##copy f V int-regs n V int-regs 2 } - 3 get successors>> first instructions>> first = -] unit-test - -] - [ 3 ] [ 4 get instructions>> length ] unit-test V{ From 42230b21a3b76fae48f6fdc0dda61d6f9fd661ec Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 22 Jul 2009 02:06:14 -0500 Subject: [PATCH 94/96] Add assoc-refine, which takes the intersection of a sequence of assocs --- core/assocs/assocs-tests.factor | 16 ++++++++++++++++ core/assocs/assocs.factor | 3 +++ 2 files changed, 19 insertions(+) diff --git a/core/assocs/assocs-tests.factor b/core/assocs/assocs-tests.factor index 75607b0258..3c5ac31d23 100644 --- a/core/assocs/assocs-tests.factor +++ b/core/assocs/assocs-tests.factor @@ -134,3 +134,19 @@ unit-test [ f ] [ 1 2 H{ { 2 1 } } maybe-set-at ] unit-test [ t ] [ 1 3 H{ { 2 1 } } clone maybe-set-at ] unit-test [ t ] [ 3 2 H{ { 2 1 } } clone maybe-set-at ] unit-test + +[ H{ { 1 2 } { 2 3 } } ] [ + { + H{ { 1 3 } } + H{ { 2 3 } } + H{ { 1 2 } } + } assoc-combine +] unit-test + +[ H{ { 1 7 } } ] [ + { + H{ { 1 2 } { 2 4 } { 5 6 } } + H{ { 1 3 } { 2 5 } } + H{ { 1 7 } { 5 6 } } + } assoc-refine +] unit-test \ No newline at end of file diff --git a/core/assocs/assocs.factor b/core/assocs/assocs.factor index 62ab9f86ae..8b6809236c 100755 --- a/core/assocs/assocs.factor +++ b/core/assocs/assocs.factor @@ -129,6 +129,9 @@ M: assoc assoc-clone-like ( assoc exemplar -- newassoc ) : assoc-combine ( seq -- union ) H{ } clone [ dupd update ] reduce ; +: assoc-refine ( seq -- assoc ) + [ f ] [ [ ] [ assoc-intersect ] map-reduce ] if-empty ; + : assoc-diff ( assoc1 assoc2 -- diff ) [ nip key? not ] curry assoc-filter ; From dce020ca711d5157910c61214042cba41d5682b4 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 22 Jul 2009 02:06:24 -0500 Subject: [PATCH 95/96] functors: add MIXIN:, SINGLETON: --- basis/functors/functors.factor | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/basis/functors/functors.factor b/basis/functors/functors.factor index 6ffc4d8112..5129515980 100644 --- a/basis/functors/functors.factor +++ b/basis/functors/functors.factor @@ -1,11 +1,11 @@ ! Copyright (C) 2008, 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: accessors arrays classes.mixin classes.parser -classes.tuple classes.tuple.parser combinators effects -effects.parser fry generic generic.parser generic.standard -interpolate io.streams.string kernel lexer locals.parser -locals.rewrite.closures locals.types make namespaces parser -quotations sequences vocabs.parser words words.symbol ; +USING: accessors arrays classes.mixin classes.parser classes.singleton +classes.tuple classes.tuple.parser combinators effects effects.parser +fry generic generic.parser generic.standard interpolate +io.streams.string kernel lexer locals.parser locals.rewrite.closures +locals.types make namespaces parser quotations sequences vocabs.parser +words words.symbol ; IN: functors ! This is a hack @@ -71,6 +71,14 @@ SYNTAX: `TUPLE: } case \ define-tuple-class parsed ; +SYNTAX: `SINGLETON: + scan-param parsed + \ define-singleton-class parsed ; + +SYNTAX: `MIXIN: + scan-param parsed + \ define-mixin-class parsed ; + SYNTAX: `M: scan-param parsed scan-param parsed @@ -134,6 +142,8 @@ DEFER: ;FUNCTOR delimiter : functor-words ( -- assoc ) H{ { "TUPLE:" POSTPONE: `TUPLE: } + { "SINGLETON:" POSTPONE: `SINGLETON: } + { "MIXIN:" POSTPONE: `MIXIN: } { "M:" POSTPONE: `M: } { "C:" POSTPONE: `C: } { ":" POSTPONE: `: } From e6a323dfaae4b956b06d0afad1e5f9a84c33b3b9 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 22 Jul 2009 02:06:35 -0500 Subject: [PATCH 96/96] compiler.cfg.dataflow-analysis: iterative dataflow analysis framework --- .../dataflow-analysis.factor | 140 ++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 basis/compiler/cfg/dataflow-analysis/dataflow-analysis.factor diff --git a/basis/compiler/cfg/dataflow-analysis/dataflow-analysis.factor b/basis/compiler/cfg/dataflow-analysis/dataflow-analysis.factor new file mode 100644 index 0000000000..975adfa6cb --- /dev/null +++ b/basis/compiler/cfg/dataflow-analysis/dataflow-analysis.factor @@ -0,0 +1,140 @@ +! Copyright (C) 2009 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license. +USING: accessors assocs deques dlists kernel locals sequences lexer +namespaces functors compiler.cfg.rpo compiler.cfg.utilities +compiler.cfg ; +IN: compiler.cfg.dataflow-analysis + +GENERIC: join-sets ( sets dfa -- set ) +GENERIC: transfer-set ( in-set bb dfa -- out-set ) +GENERIC: block-order ( cfg dfa -- bbs ) +GENERIC: successors ( bb dfa -- seq ) +GENERIC: predecessors ( bb dfa -- seq ) + + ( cfg dfa -- queue ) + block-order [ push-all-front ] keep ; + +GENERIC# compute-in-set 2 ( bb out-sets dfa -- set ) + +M: kill-block compute-in-set 3drop f ; + +M:: basic-block compute-in-set ( bb out-sets dfa -- set ) + bb dfa predecessors [ out-sets at ] map dfa join-sets ; + +:: update-in-set ( bb in-sets out-sets dfa -- ? ) + bb out-sets dfa compute-in-set + bb in-sets maybe-set-at ; inline + +GENERIC# compute-out-set 2 ( bb out-sets dfa -- set ) + +M: kill-block compute-out-set 3drop f ; + +M:: basic-block compute-out-set ( bb in-sets dfa -- set ) + bb in-sets at bb dfa transfer-set ; + +:: update-out-set ( bb in-sets out-sets dfa -- ? ) + bb in-sets dfa compute-out-set + bb out-sets maybe-set-at ; inline + +:: dfa-step ( bb in-sets out-sets dfa work-list -- ) + bb in-sets out-sets dfa update-in-set [ + bb in-sets out-sets dfa update-out-set [ + bb dfa successors work-list push-all-front + ] when + ] when ; inline + +:: run-dataflow-analysis ( cfg dfa -- in-sets out-sets ) + H{ } clone :> in-sets + H{ } clone :> out-sets + cfg dfa :> work-list + work-list [ in-sets out-sets dfa work-list dfa-step ] slurp-deque + in-sets + out-sets ; inline + +M: dataflow-analysis join-sets drop assoc-refine ; + +FUNCTOR: define-analysis ( name -- ) + +name-analysis DEFINES-CLASS ${name}-analysis +name-ins DEFINES ${name}-ins +name-outs DEFINES ${name}-outs +name-in DEFINES ${name}-in +name-out DEFINES ${name}-out + +WHERE + +SINGLETON: name-analysis + +SYMBOL: name-ins + +: name-in ( bb -- set ) name-ins get at ; + +SYMBOL: name-outs + +: name-out ( bb -- set ) name-outs get at ; + +;FUNCTOR + +! ! ! Forward dataflow analysis + +MIXIN: forward-analysis +INSTANCE: forward-analysis dataflow-analysis + +M: forward-analysis block-order drop reverse-post-order ; +M: forward-analysis successors drop successors>> ; +M: forward-analysis predecessors drop predecessors>> ; + +FUNCTOR: define-forward-analysis ( name -- ) + +name-analysis IS ${name}-analysis +name-ins IS ${name}-ins +name-outs IS ${name}-outs +compute-name-sets DEFINES compute-${name}-sets + +WHERE + +INSTANCE: name-analysis forward-analysis + +: compute-name-sets ( cfg -- ) + name-analysis run-dataflow-analysis + [ name-ins set ] [ name-outs set ] bi* ; + +;FUNCTOR + +! ! ! Backward dataflow analysis + +MIXIN: backward-analysis +INSTANCE: backward-analysis dataflow-analysis + +M: backward-analysis block-order drop post-order ; +M: backward-analysis successors drop predecessors>> ; +M: backward-analysis predecessors drop successors>> ; + +FUNCTOR: define-backward-analysis ( name -- ) + +name-analysis IS ${name}-analysis +name-ins IS ${name}-ins +name-outs IS ${name}-outs +compute-name-sets DEFINES compute-${name}-sets + +WHERE + +INSTANCE: name-analysis backward-analysis + +: compute-name-sets ( cfg -- ) + \ name-analysis run-dataflow-analysis + [ name-outs set ] [ name-ins set ] bi* ; + +;FUNCTOR + +PRIVATE> + +SYNTAX: FORWARD-ANALYSIS: + scan [ define-analysis ] [ define-forward-analysis ] bi ; + +SYNTAX: BACKWARD-ANALYSIS: + scan [ define-analysis ] [ define-backward-analysis ] bi ;