]> gitweb.factorcode.org Git - factor.git/commitdiff
Merge branch 'master' of git://factorcode.org/git/factor
authorDoug Coleman <doug.coleman@gmail.com>
Tue, 22 Sep 2009 15:25:42 +0000 (10:25 -0500)
committerDoug Coleman <doug.coleman@gmail.com>
Tue, 22 Sep 2009 15:25:42 +0000 (10:25 -0500)
Conflicts:
core/generic/generic-tests.factor

28 files changed:
basis/compiler/cfg/linear-scan/assignment/assignment.factor
basis/compiler/cfg/linear-scan/numbering/numbering.factor
basis/compiler/cfg/linearization/order/order-tests.factor [new file with mode: 0644]
basis/compiler/cfg/linearization/order/order.factor
basis/compiler/tests/codegen.factor
basis/compiler/tests/low-level-ir.factor
basis/cpu/ppc/ppc.factor
basis/math/functions/functions-tests.factor
basis/math/functions/functions.factor
basis/tools/annotations/annotations-docs.factor
basis/tools/annotations/annotations.factor
basis/tools/walker/walker-docs.factor
basis/tools/walker/walker.factor
basis/ui/tools/walker/walker-docs.factor
core/generic/generic-tests.factor
extra/compiler/graphviz/graphviz-tests.factor [new file with mode: 0644]
extra/compiler/graphviz/graphviz.factor
extra/jvm-summit-talk/authors.txt [new file with mode: 0644]
extra/jvm-summit-talk/jvm-summit-talk.factor [new file with mode: 0644]
extra/jvm-summit-talk/summary.txt [new file with mode: 0644]
extra/project-euler/072/072-tests.factor [new file with mode: 0644]
extra/project-euler/072/072.factor [new file with mode: 0644]
extra/project-euler/074/074-tests.factor [new file with mode: 0644]
extra/project-euler/074/074.factor [new file with mode: 0644]
extra/project-euler/085/085.factor
extra/project-euler/124/124-tests.factor [new file with mode: 0644]
extra/project-euler/124/124.factor [new file with mode: 0644]
extra/project-euler/project-euler.factor

index 8754b65475ed0f9fb96645523208fd933c0b1091..572107be6cd05142e58751f809a8390cbcf13193 100644 (file)
@@ -28,10 +28,12 @@ SYMBOL: pending-interval-assoc
 : remove-pending ( live-interval -- )
     vreg>> pending-interval-assoc get delete-at ;
 
+ERROR: bad-vreg vreg ;
+
 : (vreg>reg) ( vreg pending -- reg )
     ! If a live vreg is not in the pending set, then it must
     ! have been spilled.
-    ?at [ spill-slots get at <spill-slot> ] unless ;
+    ?at [ spill-slots get ?at [ <spill-slot> ] [ bad-vreg ] if ] unless ;
 
 : vreg>reg ( vreg -- reg )
     pending-interval-assoc get (vreg>reg) ;
@@ -157,8 +159,6 @@ M: insn assign-registers-in-insn drop ;
 : end-block ( bb -- )
     [ live-out vregs>regs ] keep register-live-outs get set-at ;
 
-ERROR: bad-vreg vreg ;
-
 : vreg-at-start ( vreg bb -- state )
     register-live-ins get at ?at [ bad-vreg ] unless ;
 
index 6fd97c64dad30f66d915b633e757901543cbf577..44b2ff907a19ad9400e7f525d30519935478ab1e 100644 (file)
@@ -4,12 +4,18 @@ USING: kernel accessors math sequences grouping namespaces
 compiler.cfg.linearization.order ;
 IN: compiler.cfg.linear-scan.numbering
 
-: number-instructions ( rpo -- )
-    linearization-order 0 [
-        instructions>> [
-            [ (>>insn#) ] [ drop 2 + ] 2bi
-        ] each
-    ] reduce drop ;
+ERROR: already-numbered insn ;
+
+: number-instruction ( n insn -- n' )
+    [ nip dup insn#>> [ already-numbered ] [ drop ] if ]
+    [ (>>insn#) ]
+    [ drop 2 + ]
+    2tri ;
+
+: number-instructions ( cfg -- )
+    linearization-order
+    0 [ instructions>> [ number-instruction ] each ] reduce
+    drop ;
 
 SYMBOL: check-numbering?
 
diff --git a/basis/compiler/cfg/linearization/order/order-tests.factor b/basis/compiler/cfg/linearization/order/order-tests.factor
new file mode 100644 (file)
index 0000000..67fb55f
--- /dev/null
@@ -0,0 +1,14 @@
+USING: compiler.cfg.debugger compiler.cfg compiler.cfg.linearization.order
+kernel accessors sequences sets tools.test namespaces ;
+IN: compiler.cfg.linearization.order.tests
+
+V{ } 0 test-bb
+
+V{ } 1 test-bb
+
+V{ } 2 test-bb
+
+0 { 1 1 } edges
+1 2 edge
+
+[ t ] [ cfg new 0 get >>entry linearization-order [ id>> ] map all-unique? ] unit-test
index 703db8e5167c5d7f96dcd10987ba16d7e34068b9..1fcc137c6041c44ccd5278fba7c53b0b021c87a3 100644 (file)
@@ -3,7 +3,7 @@
 USING: accessors assocs deques dlists kernel make sorting
 namespaces sequences combinators combinators.short-circuit
 fry math sets compiler.cfg.rpo compiler.cfg.utilities
-compiler.cfg.loop-detection ;
+compiler.cfg.loop-detection compiler.cfg.predecessors ;
 IN: compiler.cfg.linearization.order
 
 ! This is RPO except loops are rotated. Based on SBCL's src/compiler/control.lisp
@@ -56,10 +56,12 @@ SYMBOLS: work-list loop-heads visited ;
     successors>> <reversed> [ loop-nesting-at ] sort-with ;
 
 : process-block ( bb -- )
-    [ , ]
-    [ visited get conjoin ]
-    [ sorted-successors [ process-successor ] each ]
-    tri ;
+    dup visited? [ drop ] [
+        [ , ]
+        [ visited get conjoin ]
+        [ sorted-successors [ process-successor ] each ]
+        tri
+    ] if ;
 
 : (linearization-order) ( cfg -- bbs )
     init-linearization-order
@@ -69,7 +71,7 @@ SYMBOLS: work-list loop-heads visited ;
 PRIVATE>
 
 : linearization-order ( cfg -- bbs )
-    needs-post-order needs-loops
+    needs-post-order needs-loops needs-predecessors
 
     dup linear-order>> [ ] [
         dup (linearization-order)
index 56e368e3209d46e738bac6accd80eb7fc1476fd0..14ed2294c7b6a7ad8a9638bb5052108b1b9f7ec6 100644 (file)
@@ -416,3 +416,18 @@ cell 4 = [
 [ 1 "0.169967142900241" "0.9854497299884601" ] [ 1.4 1 [ swap >float [ fcos ] [ fsin ] bi ] compile-call [ number>string ] bi@ ] unit-test
 
 [ 6.0 ] [ 1.0 [ >float 3.0 + [ B{ 0 0 0 0 } 0 set-alien-float ] [ 2.0 + ] bi ] compile-call ] unit-test
+
+! Bug in linearization
+[ 283686952174081 ] [
+    B{ 1 1 1 1 } [
+        { byte-array } declare
+        [ 0 2 ] dip
+        [
+            [ drop ] 2dip
+            [
+                swap 1 < [ [ ] dip ] [ [ ] dip ] if
+                0 alien-signed-4
+            ] curry dup bi *
+        ] curry each-integer
+    ] compile-call
+] unit-test
index e2fc26e94bea23d842c5b2f27b174d63a64a31ac..76d7e6de420df90d570bf3bd5051817add7ffd1d 100644 (file)
@@ -18,7 +18,7 @@ IN: compiler.tests.low-level-ir
     compile-cfg ;
 
 : compile-test-bb ( insns -- result )
-    V{ T{ ##prologue } T{ ##branch } } 0 test-bb
+    V{ T{ ##prologue } T{ ##branch } } [ clone ] map 0 test-bb
     V{
         T{ ##inc-d f 1 }
         T{ ##replace f 0 D 0 }
@@ -73,7 +73,7 @@ IN: compiler.tests.low-level-ir
 [ t ] [
     V{
         T{ ##load-reference f 0 { t f t } }
-        T{ ##slot-imm f 0 0 2 $[ array tag-number ] }
+        T{ ##slot-imm f 0 0 2 $[ array tag-number ] }
     } compile-test-bb
 ] unit-test
 
index 2a16a8b6df8511549bb39cf683881a50f2d3f93e..eb9709a350d421d424a70f77843584fefb74c2dc 100644 (file)
@@ -9,6 +9,7 @@ compiler.codegen.fixup compiler.cfg.intrinsics
 compiler.cfg.stack-frame compiler.cfg.build-stack-frame
 compiler.units compiler.constants compiler.codegen vm ;
 FROM: cpu.ppc.assembler => B ;
+FROM: layouts => cell ;
 FROM: math => float ;
 IN: cpu.ppc
 
index fa880f77af5593c16471b3c597272dbaa6ec2d4f..4502e993a3575faa8d61e3e6eac6a5cddf4945c3 100644 (file)
@@ -6,6 +6,10 @@ IN: math.functions.tests
 [ t ] [ 4.0000001 4.0000001 .000001 ~ ] unit-test
 [ f ] [ -4.0000001 4.0000001 .00001 ~ ] unit-test
 [ t ] [ -.0000000000001 0 .0000000001 ~ ] unit-test
+[ t ] [ 100 101 -.9 ~ ] unit-test
+[ f ] [ 100 120 -.09 ~ ] unit-test
+[ t ] [ 0 0 -.9 ~ ] unit-test
+[ f ] [ 0 10 -.9 ~ ] unit-test
 
 ! Lets get the argument order correct, eh?
 [ 0.0 ] [ 0.0 1.0 fatan2 ] unit-test
index f124c202b833025d78ca9c5b4e7d8ff45241c6fd..a31b6ee7cc9457911c1ddb89c9825dec70a762a7 100644 (file)
@@ -137,13 +137,13 @@ M: real absq sq ; inline
     [ - abs ] dip < ;
 
 : ~rel ( x y epsilon -- ? )
-    [ [ - abs ] 2keep [ abs ] bi@ + ] dip * < ;
+    [ [ - abs ] 2keep [ abs ] bi@ + ] dip * <= ;
 
 : ~ ( x y epsilon -- ? )
     {
         { [ 2over [ fp-nan? ] either? ] [ 3drop f ] }
         { [ dup zero? ] [ drop number= ] }
-        { [ dup 0 < ] [ ~rel ] }
+        { [ dup 0 < ] [ neg ~rel ] }
         [ ~abs ]
     } cond ;
 
index 89ef6192c64813374fa7ab748e058b256c332ddc..17743610bc63176776b4f29ad1bcd97cf2e64e17 100644 (file)
@@ -8,9 +8,6 @@ $nl
 "Printing messages when a word is called or returns:"
 { $subsection watch }
 { $subsection watch-vars }
-"Starting the walker when a word is called:"
-{ $subsection breakpoint }
-{ $subsection breakpoint-if }
 "Timing words:"
 { $subsection reset-word-timing }
 { $subsection add-timing }
@@ -34,14 +31,6 @@ HELP: watch
 
 { watch watch-vars reset } related-words
 
-HELP: breakpoint
-{ $values { "word" word } }
-{ $description "Annotates a word definition to enter the single stepper when executed." } ;
-
-HELP: breakpoint-if
-{ $values { "quot" { $quotation "( -- ? )" } } { "word" word } }
-{ $description "Annotates a word definition to enter the single stepper if the quotation yields true." } ;
-
 HELP: reset
 { $values
      { "word" word } }
index 2fb246786ca7a50e9e970deb7bf8d509483ba5a4..5d4a9226ceb5b348eb4a6865c948cd853de4c6a5 100644 (file)
@@ -2,9 +2,8 @@
 ! See http://factorcode.org/license.txt for BSD license.
 USING: accessors kernel math sorting words parser io summary
 quotations sequences prettyprint continuations effects
-definitions compiler.units namespaces assocs tools.walker
-tools.time generic inspector fry tools.continuations
-locals generalizations macros ;
+definitions compiler.units namespaces assocs tools.time generic
+inspector fry locals generalizations macros ;
 IN: tools.annotations
 
 <PRIVATE
@@ -90,12 +89,6 @@ PRIVATE>
 : watch-vars ( word vars -- )
     dupd '[ [ _ _ ] dip (watch-vars) ] annotate ;
 
-: breakpoint ( word -- )
-    [ add-breakpoint ] annotate ;
-
-: breakpoint-if ( word quot -- )
-    '[ [ _ [ [ break ] when ] ] dip 3append ] annotate ;
-
 SYMBOL: word-timing
 
 word-timing [ H{ } clone ] initialize
index b6367606342e3203bc6d687fa49078e906338cf4..5a78e0cfc27f04a55f56c6241e71cd6da007ab58 100644 (file)
@@ -1,5 +1,26 @@
 IN: tools.walker
-USING: help.syntax help.markup tools.continuations ;
+USING: help.syntax help.markup tools.continuations sequences math words ;
+
+HELP: breakpoint
+{ $values { "word" word } }
+{ $description "Annotates a word definition to enter the single stepper when executed." } ;
+
+HELP: breakpoint-if
+{ $values { "quot" { $quotation "( -- ? )" } } { "word" word } }
+{ $description "Annotates a word definition to enter the single stepper if the quotation yields true." } ;
 
 HELP: B
-{ $description "An alias for " { $link break } ", defined in the " { $vocab-link "syntax" } " vocabulary so that it is always available." } ;
\ No newline at end of file
+{ $description "An alias for " { $link break } ", defined in the " { $vocab-link "syntax" } " vocabulary so that it is always available." } ;
+
+ARTICLE: "breakpoints" "Setting breakpoints"
+"In addition to invoking the walker explicitly through the UI, it is possible to set breakpoints on words using words in the " { $vocab-link "tools.walker" } " vocabulary."
+$nl
+"Annotating a word with a breakpoint (see " { $link "tools.annotations" } "):"
+{ $subsection breakpoint }
+{ $subsection breakpoint-if }
+"Breakpoints can be inserted directly into code:"
+{ $subsection break }
+{ $subsection POSTPONE: B }
+"Note that because the walker calls various core library and UI words while rendering its own user interface, setting a breakpoint on a word such as " { $link append } " or " { $link + } " will hang the UI." ;
+
+ABOUT: "breakpoints"
index 4208c4420f5257741b024db8285adff5b1318e5c..19924d67e43e650a3555329da3990e4412d51d3e 100644 (file)
@@ -5,7 +5,7 @@ sequences math namespaces.private continuations.private
 concurrency.messaging quotations kernel.private words
 sequences.private assocs models models.arrow arrays accessors
 generic generic.standard definitions make sbufs
-tools.continuations parser ;
+tools.continuations parser tools.annotations fry ;
 IN: tools.walker
 
 SYMBOL: show-walker-hook ! ( status continuation thread -- )
@@ -158,6 +158,12 @@ SYMBOL: +stopped+
     "Walker on " self name>> append spawn
     [ associate-thread ] keep ;
 
+: breakpoint ( word -- )
+    [ add-breakpoint ] annotate ;
+
+: breakpoint-if ( word quot -- )
+    '[ [ _ [ [ break ] when ] ] dip 3append ] annotate ;
+
 ! For convenience
 IN: syntax
 
index ce354da2689034206066fdc506420d56d35d11d9..da4f345de2378073413883932f199a83dbe79ca1 100644 (file)
@@ -23,14 +23,6 @@ ARTICLE: "ui-walker-step" "Stepping through code"
 $nl\r
 "The " { $link com-back } " command travels backwards through time, and restore stacks. This does not undo side effects (modifying array entries, writing to files, formatting the hard drive, etc) and therefore can only be used reliably on referentially transparent code." ;\r
 \r
-ARTICLE: "breakpoints" "Setting breakpoints"\r
-"In addition to invoking the walker explicitly through the UI, it is possible to set breakpoints on words. See " { $link "tools.annotations" } "."\r
-$nl\r
-"Breakpoints can be inserted directly into code:"\r
-{ $subsection break }\r
-{ $subsection POSTPONE: B }\r
-"Note that because the walker calls various core library and UI words while rendering its own user interface, setting a breakpoint on a word such as " { $link append } " or " { $link draw-gadget } " will hang the UI." ;\r
-\r
 ARTICLE: "ui-walker" "UI walker"\r
 "The walker single-steps through quotations. To use the walker, enter a piece of code in the listener's input area and press " { $operation walk } "."\r
 $nl\r
index 9d6721c44bbcb4acaf53155c004db281d676c47e..1691ca8932c7118559da0b9751b6c9676101b220 100755 (executable)
@@ -1,8 +1,9 @@
-USING: accessors alien arrays definitions generic generic.standard
-generic.math assocs hashtables io kernel math namespaces parser
-prettyprint sequences strings tools.test vectors words
-quotations classes classes.algebra classes.tuple continuations
-layouts classes.union sorting compiler.units eval io.streams.string ;
+USING: accessors alien arrays assocs classes classes.algebra
+classes.tuple classes.union compiler.units continuations
+definitions eval generic generic.math generic.standard
+hashtables io io.streams.string kernel layouts math math.order
+namespaces parser prettyprint quotations sequences sorting
+strings tools.test vectors words ;
 IN: generic.tests
 
 GENERIC: foobar ( x -- y )
@@ -195,4 +196,4 @@ M: slice foozul ;
     fixnum \ <=> method-for-class
     real \ <=> method
     eq?
-] unit-test
\ No newline at end of file
+] unit-test
diff --git a/extra/compiler/graphviz/graphviz-tests.factor b/extra/compiler/graphviz/graphviz-tests.factor
new file mode 100644 (file)
index 0000000..8f6c017
--- /dev/null
@@ -0,0 +1,6 @@
+IN: compiler.graphviz.tests
+USING: compiler.graphviz io.files kernel tools.test ;
+
+[ t ] [ [ [ 1 ] [ 2 ] if ] render-cfg exists? ] unit-test
+[ t ] [ [ [ 1 ] [ 2 ] if ] render-dom exists? ] unit-test
+[ t ] [ [ [ 1 ] [ 2 ] if ] render-call-graph exists? ] unit-test
index 9823f93d4e644350b658ac60902ad1da810b988e..7378d3284c36eb0a7243ec2965ed5d1a38a681fe 100644 (file)
@@ -18,15 +18,18 @@ IN: compiler.graphviz
         "}" ,
     ] { } make , ; inline
 
-: render-graph ( quot -- )
+: render-graph ( quot -- name )
     { } make
     "cfg" ".dot" make-unique-file
     dup "Wrote " prepend print
     [ [ concat ] dip ascii set-file-lines ]
     [ { "dot" "-Tpng" "-O" } swap suffix try-process ]
-    [ ".png" append "open" swap 2array try-process ]
+    [ ".png" append ]
     tri ; inline
 
+: display-graph ( name -- )
+    "open" swap 2array try-process ;
+
 : attrs>string ( seq -- str )
     [ "" ] [ "," join "[" "]" surround ] if-empty ;
 
@@ -75,12 +78,12 @@ IN: compiler.graphviz
 : optimized-cfg ( quot -- cfgs )
     {
         { [ dup cfg? ] [ 1array ] }
-        { [ dup quotation? ] [ test-cfg [ optimize-cfg ] map ] }
-        { [ dup word? ] [ test-cfg [ optimize-cfg ] map ] }
+        { [ dup quotation? ] [ test-cfg [ dup cfg set optimize-cfg ] map ] }
+        { [ dup word? ] [ test-cfg [ dup cfg set optimize-cfg ] map ] }
         [ ]
     } cond ;
 
-: render-cfg ( cfg -- )
+: render-cfg ( cfg -- name )
     optimized-cfg [ cfgs ] render-graph ;
 
 : dom-trees ( cfgs -- )
@@ -95,7 +98,7 @@ IN: compiler.graphviz
         ] over cfg-title graph,
     ] each ;
 
-: render-dom ( cfg -- )
+: render-dom ( cfg -- name )
     optimized-cfg [ dom-trees ] render-graph ;
 
 SYMBOL: word-counts
@@ -131,7 +134,7 @@ SYMBOL: vertex-names
     H{ } clone vertex-names set
     [ "ROOT" ] dip (call-graph-edges) ;
 
-: render-call-graph ( tree -- )
+: render-call-graph ( tree -- name )
     dup quotation? [ build-tree ] when
     analyze-recursive drop
     [ [ call-graph get call-graph-edges ] "Call graph" graph, ]
diff --git a/extra/jvm-summit-talk/authors.txt b/extra/jvm-summit-talk/authors.txt
new file mode 100644 (file)
index 0000000..d4f5d6b
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
\ No newline at end of file
diff --git a/extra/jvm-summit-talk/jvm-summit-talk.factor b/extra/jvm-summit-talk/jvm-summit-talk.factor
new file mode 100644 (file)
index 0000000..c6a2885
--- /dev/null
@@ -0,0 +1,358 @@
+! Copyright (C) 2009 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: slides help.markup math math.private kernel sequences
+slots.private ;
+IN: jvm-summit-talk
+
+CONSTANT: jvm-summit-slides
+{
+    { $slide "Factor language implementation"
+        "Goals: expressiveness, metaprogramming, performance"
+        "We want a language for anything from scripting DSLs to high-performance numerics"
+        "I assume you know a bit about compiler implementation: parser -> frontend -> optimizer -> codegen"
+        { "This is " { $strong "not" } " a talk about the Factor language" }
+        { "Go to " { $url "http://factorcode.org" } " to learn the language" }
+    }
+    { $slide "Why are dynamic languages slow?"
+        "Branching and indirection!"
+        "Runtime type checks and dispatch"
+        "Integer overflow checks"
+        "Boxed integers and floats"
+        "Lots of allocation of temporary objects"
+    }
+    { $slide "Interactive development"
+        "Code can be reloaded at any time"
+        "Class hierarchy might change"
+        "Slots may be added and removed"
+        "Functions might be redefined"
+    }
+    { $slide "Factor's solution"
+        "Factor implements most of the library in Factor"
+        "Library contains very generic, high-level code"
+        "Always compiles to native code"
+        "Compiler removes unused generality from high-level code"
+        "Inlining, specialization, partial evaluation"
+        "And deoptimize when assumptions change"
+    }
+    { $slide "Introduction: SSA form"
+        "Every identifier only has one global definition"
+        {
+            "Not SSA:"
+            { $code
+                "x = 1"
+                "y = 2"
+                "x = x + y"
+                "if(z < 0)"
+                "    t = x + y"
+                "else"
+                "    t = x - y"
+                "print(t)"
+            }
+        }
+    }
+    { $slide "Introduction: SSA form"
+        "Rename re-definitions and subsequent usages"
+        {
+            "Still not SSA:"
+            { $code
+                "x = 1"
+                "y = 2"
+                "x1 = x + y"
+                "if(z < 0)"
+                "    t = x1 + y"
+                "else"
+                "    t = x1 - y"
+                "print(t)"
+            }
+        }
+    }
+    { $slide "Introduction: SSA form"
+        "Introduce “φ functions” at control-flow merge points"
+        {
+            "This is SSA:"
+            { $code
+                "x = 1"
+                "y = 2"
+                "x1 = x + y"
+                "if(z < 0)"
+                "    t1 = x1 + y"
+                "else"
+                "    t2 = x1 - y"
+                "t3 = φ(t1,t2)"
+                "print(t3)"
+            }
+        }
+    }
+    { $slide "Why SSA form?"
+        {
+            "Def-use chains:"
+            { $list
+                "Defs-of: instructions that define a value"
+                "Uses-of: instructions that use a value"
+            }
+            "With SSA, defs-of has exactly one element"
+        }
+    }
+    { $slide "Def-use chains"
+        "Simpler def-use makes analysis more accurate."
+        {
+            "Non-SSA example:"
+            { $code
+                "if(x < 0)"
+                "    s = new Circle"
+                "    a = area(s1)"
+                "else"
+                "    s = new Rectangle"
+                "    a = area(s2)"
+            }
+        }
+    }
+    { $slide "Def-use chains"
+        {
+            "SSA example:"
+            { $code
+                "if(x < 0)"
+                "    s1 = new Circle"
+                "    a1 = area(s1)"
+                "else"
+                "    s2 = new Rectangle"
+                "    a2 = area(s2)"
+                "a = φ(a1,a2)"
+            }
+            
+        }
+    }
+    { $slide "Factor compiler overview"
+        "High-level SSA IR constructed from stack code"
+        "High level optimizer transforms high-level IR"
+        "Low-level SSA IR is constructed from high-level IR"
+        "Low level optimizer transforms low-level IR"
+        "Register allocator runs on low-level IR"
+        "Machine IR is constructed from low-level IR"
+        "Code generation"
+    }
+    { $slide "High-level optimizer"
+        "Frontend: expands macros, inline higher order functions"
+        "Propagation: inline methods, constant folding"
+        "Escape analysis: unbox tuples"
+        "Dead code elimination: clean up"
+    }
+    { $slide "Higher-order functions"
+        "Almost all control flow is done with higher-order functions"
+        { { $link if } ", " { $link times } ", " { $link each } }
+        "Calling a block is an indirect jump"
+        "Solution: inline higher order functions at the call site"
+        "Inline the block body at the higher order call site in the function"
+        "Record inlining in deoptimization database"
+    }
+    { $slide "Generic functions"
+        "A generic function contains multiple method bodies"
+        "Dispatches on the class of argument(s)"
+        "In Factor, generic functions are single dispatch"
+        "Almost equivalent to message passing"
+    }
+    { $slide "Tuple slot access"
+        "Slot readers and writers are generic functions"
+        "Generated automatically when you define a tuple class"
+        { "The generated methods call " { $link slot } ", " { $link set-slot } " primitives" }
+        "These primitives are not type safe; the generic dispatch performs the type checking for us"
+        "If class of dispatch value known statically, inline method"
+        "This may result in more methods inlining from additional specialization"
+    }
+    { $slide "Generic arithmetic"
+        { { $link + } ", " { $link * } ", etc perform a double dispatch on arguments" }
+        { "Fixed-precision integers (" { $link fixnum } "s) upgrade to " { $link bignum } "s automatically" }
+        "Floats and complex numbers are boxed, heap-allocated"
+        "Propagation of classes helps for floats"
+        "But not for fixnums, because of overflow checks"
+        "So we also propagate integer intervals"
+        "Interval arithmetic: etc, [a,b] + [c,d] = [a+c,b+d]"
+    }
+    { $slide "Slot value propagation"
+        "Complex numbers are even trickier"
+        "We can have a complex number with integer components, float components"
+        "Even if we inline complex arithmetic methods, still dispatching on components"
+        "Solution: propagate slot info"
+    }
+    { $slide "Constrant propagation"
+        "Contrieved example:"
+        { $code
+            "x = •"
+            "b = isa(x,array)"
+            "if(b)"
+            "    a = length(x)"
+            "else"
+            "    b = length(x)"
+            "c = φ(a,b)"
+        }
+        { "We should be able to inline the call to " { $snippet "length" } " in the true branch" }
+    }
+    { $slide "Constrant propagation"
+        "We build a table:"
+        { $code
+            "b true => x is array"
+            "b false => x is ~array"
+        }
+        { "In true branch, apply all " { $snippet "b true" } " constraints" }
+        { "In false branch, apply all " { $snippet "b false" } " constraints" }
+    }
+    { $slide "Going further"
+        "High-level optimizer eliminates some dispatch overhead and allocation"
+        {
+            { "Let's take a look at the " { $link float+ } " primitive" }
+            { $list
+                "No type checking anymore... but"
+                "Loads two tagged pointers from operand stack"
+                "Unboxes floats"
+                "Adds two floats"
+                "Boxes float result and perform a GC check"
+            }
+        }
+    }
+    { $slide "Low-level optimizer"
+        "Frontend: construct LL SSA IR from HL SSA IR"
+        "Alias analysis: remove redundant slot loads/stores"
+        "Value numbering: simplify arithmetic"
+        "Representation selection: eliminate boxing"
+        "Dead code elimination: clean up"
+        "Register allocation"
+    }
+    { $slide "Constructing low-level IR"
+        { "Low-level IR is a " { $emphasis "control flow graph" } " of " { $emphasis "basic blocks" } }
+        "A basic block is a list of instructions"
+        "Register-based IR; infinite, uniform register file"
+        { "Instructions:"
+            { $list
+                "Subroutine calls"
+                "Machine arithmetic"
+                "Load/store values on operand stack"
+                "Box/unbox values"
+            }
+        }
+    }
+    { $slide "Inline allocation and GC checks"
+        {
+            "Allocation of small objects can be done in a few instructions:"
+            { $list
+                "Bump allocation pointer"
+                "Write object header"
+                "Fill in payload"
+            }
+        }
+        "Multiple allocations in the same basic block only need a single GC check; saves on a conditional branch"
+    }
+    { $slide "Alias analysis"
+        "Factor constructors are just ordinary functions"
+        { "They call a primitive constructor: " { $link new } }
+        "When a new object is constructed, it has to be initialized"
+        "... but the user's constructor probably fills in all the slots again with actual values"
+        "Local alias analysis eliminates redundant slot loads and stores"
+    }
+    { $slide "Value numbering"
+        { "A form of " { $emphasis "redundancy elimination" } }
+        "Requires use of SSA form in order to work"
+        "Define an equivalence relation over SSA values"
+        "Assign a “value number” to each SSA value"
+        "If two values have the same number, they will always be equal at runtime"
+    }
+    { $slide "Types of value numbering"
+        "Many variations: algebraic simplifications, various rewrite rules can be tacked on"
+        "Local value numbering: in basic blocks"
+        "Global value numbering: entire procedure"
+        "Factor only does local value numbering"
+    }
+    { $slide "Value graph and expressions"
+        { $table
+            {
+                {
+                    "Basic block:"
+                    { $code
+                        "x = •"
+                        "y = •"
+                        "a = x + 1"
+                        "b = a + 1"
+                        "c = x + 2"
+                        "d = b - c"
+                        "e = y + d"
+                    }
+                }
+                {
+                    "Value numbers:"
+                    { $code
+                        "V1: •"
+                        "V2: •"
+                        "V3: 1"
+                        "V4: 2"
+                        "V5: (V1 + V3)"
+                        "V6: (V5 + V3)"
+                        "V7: (V3 + V4)"
+                        "V8: (V6 - V7)"
+                        "V9: (V2 + V8)"
+                    }
+                }
+            }
+        }
+    }
+    { $slide "Expression simplification"
+        {
+            "Constant folding: if V1 and V2 are constants "
+            { $snippet "(V1 op V2)" }
+            " can be evaluated at compile-time"
+        }
+        {
+            "Reassociation: if V2 and V3 are constants "
+            { $code "((V1 op V2) op V3) => (V1 op (V2 op V3))" }
+        }
+        {
+            "Algebraic identities: if V2 is constant 0, "
+            { $code "(V1 + V2) => V1" }
+        }
+        {
+            "Strength reduction: if V2 is a constant power of two, "
+            { $code "(V1 * V2) => (V1 << log2(V2))" }
+        }
+        "etc, etc, etc"
+    }
+    { $slide "Representation selection overview"
+        "Floats and SIMD vectors need to be boxed"
+        "Representation: tagged pointer, unboxed float, unboxed SIMD value..."
+        "When IR is built, no boxing or unboxing instructions inserted"
+        "Representation selection pass makes IR consistent"
+    }
+    { $slide "Representation selection algorithm"
+        {
+            "For each SSA value:"
+            { $list
+                "Compute possible representations"
+                "Compute cost of each representation"
+                "Pick representation with minimum cost"
+            }
+        }
+        {
+            "For each instruction:"
+            { $list
+                "If it expects a value to be in a different representation, insert box or unbox code"
+            }
+        }
+    }
+    { $slide "Register allocation"
+        "Linear scan algorithm used in Java HotSpot Client"
+        "Described in Christian Wimmer's masters thesis"
+        "Works fine on x86-64, not too great on x86-32"
+        "Good enough since basic blocks tend to be short, with lots of procedure calls"
+        "Might switch to graph coloring eventually"
+    }
+    { $slide "Compiler tools"
+        "Printing high level IR"
+        "Printing low level IR"
+        "Disassembly"
+        "Display call tree"
+        "Display control flow graph"
+        "Display dominator tree"
+    }
+}
+
+: jvm-summit-talk ( -- )
+    jvm-summit-slides slides-window ;
+
+MAIN: jvm-summit-talk
diff --git a/extra/jvm-summit-talk/summary.txt b/extra/jvm-summit-talk/summary.txt
new file mode 100644 (file)
index 0000000..769abbc
--- /dev/null
@@ -0,0 +1 @@
+Slides from Slava's talk at JVM Language Summit 2009
diff --git a/extra/project-euler/072/072-tests.factor b/extra/project-euler/072/072-tests.factor
new file mode 100644 (file)
index 0000000..80a8949
--- /dev/null
@@ -0,0 +1,4 @@
+USING: project-euler.072 tools.test ;
+IN: project-euler.072.tests
+
+[ 303963552391 ] [ euler072 ] unit-test
diff --git a/extra/project-euler/072/072.factor b/extra/project-euler/072/072.factor
new file mode 100644 (file)
index 0000000..de6312f
--- /dev/null
@@ -0,0 +1,38 @@
+! Copyright (c) 2009 Guillaume Nargeot.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel math math.primes.factors math.ranges
+project-euler.common sequences ;
+IN: project-euler.072
+
+! http://projecteuler.net/index.php?section=problems&id=072
+
+! DESCRIPTION
+! -----------
+
+! Consider the fraction, n/d, where n and d are positive integers.
+! If n<d and HCF(n,d)=1, it is called a reduced proper fraction.
+
+! If we list the set of reduced proper fractions for d ≤ 8 in ascending order
+! of size, we get:
+
+! 1/8, 1/7, 1/6, 1/5, 1/4, 2/7, 1/3, 3/8, 2/5, 3/7, 1/2, 4/7, 3/5, 5/8, 2/3,
+! 5/7, 3/4, 4/5, 5/6, 6/7, 7/8
+
+! It can be seen that there are 21 elements in this set.
+
+! How many elements would be contained in the set of reduced proper fractions
+! for d ≤ 1,000,000?
+
+
+! SOLUTION
+! --------
+
+! The answer can be found by adding totient(n) for 2 ≤ n ≤ 1e6
+
+: euler072 ( -- answer )
+    2 1000000 [a,b] [ totient ] [ + ] map-reduce ;
+
+! [ euler072 ] 100 ave-time
+! 5274 ms ave run time - 102.7 SD (100 trials)
+
+SOLUTION: euler072
diff --git a/extra/project-euler/074/074-tests.factor b/extra/project-euler/074/074-tests.factor
new file mode 100644 (file)
index 0000000..9287480
--- /dev/null
@@ -0,0 +1,4 @@
+USING: project-euler.074 tools.test ;
+IN: project-euler.074.tests
+
+[ 402 ] [ euler074 ] unit-test
diff --git a/extra/project-euler/074/074.factor b/extra/project-euler/074/074.factor
new file mode 100644 (file)
index 0000000..7f0a54a
--- /dev/null
@@ -0,0 +1,68 @@
+! Copyright (c) 2009 Guillaume Nargeot.
+! See http://factorcode.org/license.txt for BSD license.
+USING: assocs hashtables kernel math math.ranges
+project-euler.common sequences sets ;
+IN: project-euler.074
+
+! http://projecteuler.net/index.php?section=problems&id=074
+
+! DESCRIPTION
+! -----------
+
+! The number 145 is well known for the property that the sum of the factorial
+! of its digits is equal to 145:
+
+! 1! + 4! + 5! = 1 + 24 + 120 = 145
+
+! Perhaps less well known is 169, in that it produces the longest chain of
+! numbers that link back to 169; it turns out that there are only three such
+! loops that exist:
+
+! 169 → 363601 → 1454 → 169
+! 871 → 45361 → 871
+! 872 → 45362 → 872
+
+! It is not difficult to prove that EVERY starting number will eventually get
+! stuck in a loop. For example,
+
+! 69 → 363600 → 1454 → 169 → 363601 (→ 1454)
+! 78 → 45360 → 871 → 45361 (→ 871)
+! 540 → 145 (→ 145)
+
+! Starting with 69 produces a chain of five non-repeating terms, but the
+! longest non-repeating chain with a starting number below one million is sixty
+! terms.
+
+! How many chains, with a starting number below one million, contain exactly
+! sixty non-repeating terms?
+
+
+! SOLUTION
+! --------
+
+! Brute force
+
+<PRIVATE
+
+: digit-factorial ( n -- n! )
+    { 1 1 2 6 24 120 720 5040 40320 362880 } nth ;
+
+: digits-factorial-sum ( n -- n )
+    number>digits [ digit-factorial ] sigma ;
+
+: chain-length ( n -- n )
+    61 <hashtable>
+    [ 2dup key? not ]
+    [ [ conjoin ] [ [ digits-factorial-sum ] dip ] 2bi ]
+    while nip assoc-size ;
+
+PRIVATE>
+
+: euler074 ( -- answer )
+    1000000 [1,b] [ chain-length 60 = ] count ;
+
+! [ euler074 ] 10 ave-time
+! 25134 ms ave run time - 31.96 SD (10 trials)
+
+SOLUTION: euler074
+
index 6c70f65bf7ad7ecf810dfbb1de1e613f9afb73f1..9c12367cdfd727b1f24fc8edea5a060d11e3182c 100644 (file)
@@ -19,7 +19,7 @@ IN: project-euler.085
 ! SOLUTION
 ! --------
 
-! A grid measuring x by y contains x * (x + 1) * y * (x + 1) rectangles.
+! A grid measuring x by y contains x * (x + 1) * y * (x + 1) / 4 rectangles.
 
 <PRIVATE
 
@@ -56,6 +56,6 @@ PRIVATE>
     area-of-nearest ;
 
 ! [ euler085 ] 100 ave-time
-! 2285 ms ave run time - 4.8 SD (100 trials)
+! 791 ms ave run time - 17.15 SD (100 trials)
 
 SOLUTION: euler085
diff --git a/extra/project-euler/124/124-tests.factor b/extra/project-euler/124/124-tests.factor
new file mode 100644 (file)
index 0000000..cdbb5af
--- /dev/null
@@ -0,0 +1,4 @@
+USING: project-euler.124 tools.test ;
+IN: project-euler.124.tests
+
+[ 21417 ] [ euler124 ] unit-test
diff --git a/extra/project-euler/124/124.factor b/extra/project-euler/124/124.factor
new file mode 100644 (file)
index 0000000..0f4d1ee
--- /dev/null
@@ -0,0 +1,63 @@
+! Copyright (c) 2009 Guillaume Nargeot.
+! See http://factorcode.org/license.txt for BSD license.
+USING: arrays kernel math.primes.factors
+math.ranges project-euler.common sequences sorting ;
+IN: project-euler.124
+
+! http://projecteuler.net/index.php?section=problems&id=124
+
+! DESCRIPTION
+! -----------
+
+! The radical of n, rad(n), is the product of distinct prime factors of n.
+! For example, 504 = 2^3 × 3^2 × 7, so rad(504) = 2 × 3 × 7 = 42.
+
+! If we calculate rad(n) for 1 ≤ n ≤ 10, then sort them on rad(n),
+! and sorting on n if the radical values are equal, we get:
+
+!   Unsorted          Sorted
+!   n  rad(n)       n  rad(n) k
+!   1    1          1    1    1
+!   2    2          2    2    2
+!   3    3          4    2    3
+!   4    2          8    2    4
+!   5    5          3    3    5
+!   6    6          9    3    6
+!   7    7          5    5    7
+!   8    2          6    6    8
+!   9    3          7    7    9
+!  10   10         10   10   10
+
+! Let E(k) be the kth element in the sorted n column; for example,
+! E(4) = 8 and E(6) = 9.
+
+! If rad(n) is sorted for 1 ≤ n ≤ 100000, find E(10000).
+
+
+! SOLUTION
+! --------
+
+<PRIVATE
+
+: rad ( n -- n )
+    unique-factors product ; inline
+
+: rads-upto ( n -- seq )
+    [0,b] [ dup rad 2array ] map ;
+
+: (euler124) ( -- seq )
+    100000 rads-upto sort-values ;
+
+PRIVATE>
+
+: euler124 ( -- answer )
+    10000 (euler124) nth first ;
+
+! [ euler124 ] 100 ave-time
+! 373 ms ave run time - 17.61 SD (100 trials)
+
+! TODO: instead of the brute-force method, making the rad
+! array in the way of the sieve of eratosthene would scale
+! better on bigger values.
+
+SOLUTION: euler124
index f0e40674da0f7b887bcb2676aa01f502066dd9e4..1bba3182d1138a9ffaa010a2ef1ed9539644d05c 100644 (file)
@@ -17,13 +17,14 @@ USING: definitions io io.files io.pathnames kernel math math.parser
     project-euler.049 project-euler.052 project-euler.053 project-euler.054
     project-euler.055 project-euler.056 project-euler.057 project-euler.058
     project-euler.059 project-euler.063 project-euler.067 project-euler.069
-    project-euler.071 project-euler.073 project-euler.075 project-euler.076
-    project-euler.079 project-euler.085 project-euler.092 project-euler.097
-    project-euler.099 project-euler.100 project-euler.102 project-euler.112
-    project-euler.116 project-euler.117 project-euler.134 project-euler.148
-    project-euler.150 project-euler.151 project-euler.164 project-euler.169
-    project-euler.173 project-euler.175 project-euler.186 project-euler.190
-    project-euler.203 project-euler.215 ;
+    project-euler.071 project-euler.072 project-euler.073 project-euler.074
+    project-euler.075 project-euler.076 project-euler.079 project-euler.085
+    project-euler.092 project-euler.097 project-euler.099 project-euler.100
+    project-euler.102 project-euler.112 project-euler.116 project-euler.117
+    project-euler.124 project-euler.134 project-euler.148 project-euler.150
+    project-euler.151 project-euler.164 project-euler.169 project-euler.173
+    project-euler.175 project-euler.186 project-euler.190 project-euler.203
+    project-euler.215 ;
 IN: project-euler
 
 <PRIVATE