Merge branch 'master' into s3

Conflicts:

	basis/compiler/cfg/optimizer/optimizer.factor
db4
Daniel Ehrenberg 2010-05-03 17:19:28 -05:00
commit 5509604ffe
320 changed files with 11351 additions and 6499 deletions

1
.gitignore vendored
View File

@ -12,6 +12,7 @@ Factor/factor
*.res
*.RES
*.image
factor.image.fresh
*.dylib
factor
factor.com

View File

@ -106,61 +106,63 @@ help:
@echo "NO_UI=1 don't link with X11 libraries (ignored on Mac OS X)"
@echo "X11=1 force link with X11 libraries instead of Cocoa (only on Mac OS X)"
ALL = factor factor-ffi-test factor-lib
openbsd-x86-32:
$(MAKE) factor factor-ffi-test CONFIG=vm/Config.openbsd.x86.32
$(MAKE) $(ALL) CONFIG=vm/Config.openbsd.x86.32
openbsd-x86-64:
$(MAKE) factor factor-ffi-test CONFIG=vm/Config.openbsd.x86.64
$(MAKE) $(ALL) CONFIG=vm/Config.openbsd.x86.64
freebsd-x86-32:
$(MAKE) factor factor-ffi-test CONFIG=vm/Config.freebsd.x86.32
$(MAKE) $(ALL) CONFIG=vm/Config.freebsd.x86.32
freebsd-x86-64:
$(MAKE) factor factor-ffi-test CONFIG=vm/Config.freebsd.x86.64
$(MAKE) $(ALL) CONFIG=vm/Config.freebsd.x86.64
netbsd-x86-32:
$(MAKE) factor factor-ffi-test CONFIG=vm/Config.netbsd.x86.32
$(MAKE) $(ALL) CONFIG=vm/Config.netbsd.x86.32
netbsd-x86-64:
$(MAKE) factor factor-ffi-test CONFIG=vm/Config.netbsd.x86.64
$(MAKE) $(ALL) CONFIG=vm/Config.netbsd.x86.64
macosx-ppc:
$(MAKE) factor factor-ffi-test macosx.app CONFIG=vm/Config.macosx.ppc
$(MAKE) $(ALL) macosx.app CONFIG=vm/Config.macosx.ppc
macosx-x86-32:
$(MAKE) factor factor-ffi-test macosx.app CONFIG=vm/Config.macosx.x86.32
$(MAKE) $(ALL) macosx.app CONFIG=vm/Config.macosx.x86.32
macosx-x86-64:
$(MAKE) factor factor-ffi-test macosx.app CONFIG=vm/Config.macosx.x86.64
$(MAKE) $(ALL) macosx.app CONFIG=vm/Config.macosx.x86.64
linux-x86-32:
$(MAKE) factor factor-ffi-test CONFIG=vm/Config.linux.x86.32
$(MAKE) $(ALL) CONFIG=vm/Config.linux.x86.32
linux-x86-64:
$(MAKE) factor factor-ffi-test CONFIG=vm/Config.linux.x86.64
$(MAKE) $(ALL) CONFIG=vm/Config.linux.x86.64
linux-ppc:
$(MAKE) factor factor-ffi-test CONFIG=vm/Config.linux.ppc
$(MAKE) $(ALL) CONFIG=vm/Config.linux.ppc
linux-arm:
$(MAKE) factor factor-ffi-test CONFIG=vm/Config.linux.arm
$(MAKE) $(ALL) CONFIG=vm/Config.linux.arm
solaris-x86-32:
$(MAKE) factor factor-ffi-test CONFIG=vm/Config.solaris.x86.32
$(MAKE) $(ALL) CONFIG=vm/Config.solaris.x86.32
solaris-x86-64:
$(MAKE) factor factor-ffi-test CONFIG=vm/Config.solaris.x86.64
$(MAKE) $(ALL) CONFIG=vm/Config.solaris.x86.64
winnt-x86-32:
$(MAKE) factor factor-ffi-test CONFIG=vm/Config.windows.nt.x86.32
$(MAKE) $(ALL) CONFIG=vm/Config.windows.nt.x86.32
$(MAKE) factor-console CONFIG=vm/Config.windows.nt.x86.32
winnt-x86-64:
$(MAKE) factor factor-ffi-test CONFIG=vm/Config.windows.nt.x86.64
$(MAKE) $(ALL) CONFIG=vm/Config.windows.nt.x86.64
$(MAKE) factor-console CONFIG=vm/Config.windows.nt.x86.64
wince-arm:
$(MAKE) factor factor-ffi-test CONFIG=vm/Config.windows.ce.arm
$(MAKE) $(ALL) CONFIG=vm/Config.windows.ce.arm
ifdef CONFIG
@ -173,6 +175,8 @@ macosx.app: factor
$(ENGINE): $(DLL_OBJS)
$(TOOLCHAIN_PREFIX)$(LINKER) $(ENGINE) $(DLL_OBJS)
factor-lib: $(ENGINE)
factor: $(EXE_OBJS) $(DLL_OBJS)
$(TOOLCHAIN_PREFIX)$(CPP) $(LIBS) $(LIBPATH) -L. $(DLL_OBJS) \
$(CFLAGS) -o $(EXECUTABLE) $(EXE_OBJS)
@ -217,4 +221,4 @@ clean:
tags:
etags vm/*.{cpp,hpp,mm,S,c}
.PHONY: factor factor-console factor-ffi-test tags clean macosx.app
.PHONY: factor factor-lib factor-console factor-ffi-test tags clean macosx.app

View File

@ -1,6 +1,6 @@
! Copyright (C) 2004, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: byte-arrays arrays assocs kernel kernel.private math
USING: byte-arrays arrays assocs delegate kernel kernel.private math
math.order math.parser namespaces make parser sequences strings
words splitting cpu.architecture alien alien.accessors
alien.strings quotations layouts system compiler.units io
@ -79,74 +79,50 @@ GENERIC: c-type-class ( name -- class )
M: abstract-c-type c-type-class class>> ;
M: c-type-name c-type-class c-type c-type-class ;
GENERIC: c-type-boxed-class ( name -- class )
M: abstract-c-type c-type-boxed-class boxed-class>> ;
M: c-type-name c-type-boxed-class c-type c-type-boxed-class ;
GENERIC: c-type-boxer ( name -- boxer )
M: c-type c-type-boxer boxer>> ;
M: c-type-name c-type-boxer c-type c-type-boxer ;
GENERIC: c-type-boxer-quot ( name -- quot )
M: abstract-c-type c-type-boxer-quot boxer-quot>> ;
M: c-type-name c-type-boxer-quot c-type c-type-boxer-quot ;
GENERIC: c-type-unboxer ( name -- boxer )
M: c-type c-type-unboxer unboxer>> ;
M: c-type-name c-type-unboxer c-type c-type-unboxer ;
GENERIC: c-type-unboxer-quot ( name -- quot )
M: abstract-c-type c-type-unboxer-quot unboxer-quot>> ;
M: c-type-name c-type-unboxer-quot c-type c-type-unboxer-quot ;
GENERIC: c-type-rep ( name -- rep )
M: c-type c-type-rep rep>> ;
M: c-type-name c-type-rep c-type c-type-rep ;
GENERIC: c-type-getter ( name -- quot )
M: c-type c-type-getter getter>> ;
M: c-type-name c-type-getter c-type c-type-getter ;
GENERIC: c-type-setter ( name -- quot )
M: c-type c-type-setter setter>> ;
M: c-type-name c-type-setter c-type c-type-setter ;
GENERIC: c-type-align ( name -- n )
M: abstract-c-type c-type-align align>> ;
M: c-type-name c-type-align c-type c-type-align ;
GENERIC: c-type-align-first ( name -- n )
M: c-type-name c-type-align-first c-type c-type-align-first ;
M: abstract-c-type c-type-align-first align-first>> ;
GENERIC: c-type-stack-align? ( name -- ? )
M: c-type c-type-stack-align? stack-align?>> ;
M: c-type-name c-type-stack-align? c-type c-type-stack-align? ;
: c-type-box ( n c-type -- )
[ c-type-rep ] [ c-type-boxer [ "No boxer" throw ] unless* ] bi
%box ;
@ -159,38 +135,26 @@ GENERIC: box-parameter ( n c-type -- )
M: c-type box-parameter c-type-box ;
M: c-type-name box-parameter c-type box-parameter ;
GENERIC: box-return ( c-type -- )
M: c-type box-return f swap c-type-box ;
M: c-type-name box-return c-type box-return ;
GENERIC: unbox-parameter ( n c-type -- )
M: c-type unbox-parameter c-type-unbox ;
M: c-type-name unbox-parameter c-type unbox-parameter ;
GENERIC: unbox-return ( c-type -- )
M: c-type unbox-return f swap c-type-unbox ;
M: c-type-name unbox-return c-type unbox-return ;
: little-endian? ( -- ? ) 1 <int> *char 1 = ; foldable
GENERIC: heap-size ( name -- size )
M: c-type-name heap-size c-type heap-size ;
M: abstract-c-type heap-size size>> ;
GENERIC: stack-size ( name -- size )
M: c-type-name stack-size c-type stack-size ;
M: c-type stack-size size>> cell align ;
: >c-bool ( ? -- int ) 1 0 ? ; inline
@ -217,6 +181,29 @@ MIXIN: value-type
\ swap , [ heap-size , [ * >fixnum ] % ] [ % ] bi*
] [ ] make ;
PROTOCOL: c-type-protocol
c-type-class
c-type-boxed-class
c-type-boxer
c-type-boxer-quot
c-type-unboxer
c-type-unboxer-quot
c-type-rep
c-type-getter
c-type-setter
c-type-align
c-type-align-first
c-type-stack-align?
box-parameter
box-return
unbox-parameter
unbox-return
heap-size
stack-size ;
CONSULT: c-type-protocol c-type-name
c-type ;
PREDICATE: typedef-word < c-type-word
"c-type" word-prop c-type-name? ;

View File

@ -105,7 +105,7 @@ $nl
"Important guidelines for passing data in byte arrays:"
{ $subsections "byte-arrays-gc" }
"C-style enumerated types are supported:"
{ $subsections POSTPONE: C-ENUM: }
{ $subsections "alien.enums" POSTPONE: ENUM: }
"C types can be aliased for convenience and consistency with native library documentation:"
{ $subsections POSTPONE: TYPEDEF: }
"A utility for defining " { $link "destructors" } " for deallocating memory:"

View File

@ -1,8 +1,7 @@
! (c)2009, 2010 Slava Pestov, Joe Groff bsd license
USING: accessors alien alien.c-types alien.arrays alien.strings arrays
byte-arrays cpu.architecture fry io io.encodings.binary
io.files io.streams.memory kernel libc math sequences words
byte-vectors ;
USING: accessors alien alien.c-types alien.arrays alien.strings
arrays byte-arrays cpu.architecture fry io io.encodings.binary
io.files io.streams.memory kernel libc math sequences words ;
IN: alien.data
GENERIC: require-c-array ( c-type -- )
@ -63,13 +62,6 @@ M: memory-stream stream-read
swap memory>byte-array
] [ [ + ] change-index drop ] 2bi ;
M: byte-vector stream-write
[ dup byte-length tail-slice ]
[ [ [ byte-length ] bi@ + ] keep lengthen ]
[ drop byte-length ]
2tri
[ >c-ptr swap >c-ptr ] dip memcpy ;
M: value-type c-type-rep drop int-rep ;
M: value-type c-type-getter
@ -83,4 +75,3 @@ M: array c-type-boxer-quot
unclip [ array-length ] dip [ <c-direct-array> ] 2curry ;
M: array c-type-unboxer-quot drop [ >c-ptr ] ;

View File

@ -0,0 +1,36 @@
! Copyright (C) 2010 Erik Charlebois.
! See http://factorcode.org/license.txt for BSD license.
USING: alien.c-types alien.syntax help.markup help.syntax words ;
IN: alien.enums
HELP: define-enum
{ $values
{ "word" word } { "base-type" c-type } { "members" "sequence of word and value pairs" }
}
{ $description "Defines an enum. This is the run-time equivalent of " { $link POSTPONE: ENUM: } "." } ;
HELP: enum>number
{ $values
{ "enum" "an enum word" }
{ "number" "the corresponding number value" }
}
{ $description "Converts an enum to a number." } ;
HELP: number>enum
{ $values
{ "number" "an enum number" } { "enum-c-type" "an enum type" }
{ "enum" "the corresponding enum word" }
}
{ $description "Convert a number to an enum." } ;
ARTICLE: "alien.enums" "Enumeration types"
"The " { $vocab-link "alien.enums" } " vocab contains the implementation for " { $link POSTPONE: ENUM: } " C types, and provides words for converting between enum symbols and integers."
$nl
"Defining enums at run-time:"
{ $subsection define-enum }
"Conversions between enums and integers:"
{ $subsections enum>number number>enum } ;
{ POSTPONE: ENUM: define-enum enum>number number>enum } related-words
ABOUT: "alien.enums"

View File

@ -0,0 +1,35 @@
! Copyright (C) 2010 Erik Charlebois.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors alien.c-types alien.enums alien.enums.private
alien.syntax sequences tools.test words ;
IN: alien.enums.tests
ENUM: color_t red { green 3 } blue ;
ENUM: instrument_t < ushort trombone trumpet ;
{ { red green blue 5 } }
[ { 0 3 4 5 } [ <color_t> ] map ] unit-test
{ { 0 3 4 5 } }
[ { red green blue 5 } [ enum>number ] map ] unit-test
{ { -1 trombone trumpet } }
[ { -1 0 1 } [ <instrument_t> ] map ] unit-test
{ { -1 0 1 } }
[ { -1 trombone trumpet } [ enum>number ] map ] unit-test
{ t }
[ color_t "c-type" word-prop enum-c-type? ] unit-test
{ f }
[ ushort "c-type" word-prop enum-c-type? ] unit-test
{ int }
[ color_t "c-type" word-prop base-type>> ] unit-test
{ ushort }
[ instrument_t "c-type" word-prop base-type>> ] unit-test
{ V{ { red 0 } { green 3 } { blue 4 } } }
[ color_t "c-type" word-prop members>> ] unit-test

View File

@ -0,0 +1,55 @@
! (c)2010 Joe Groff, Erik Charlebois bsd license
USING: accessors alien.c-types arrays combinators delegate fry
generic.parser kernel macros math parser sequences words words.symbol ;
IN: alien.enums
<PRIVATE
TUPLE: enum-c-type base-type members ;
C: <enum-c-type> enum-c-type
CONSULT: c-type-protocol enum-c-type
base-type>> ;
PRIVATE>
GENERIC: enum>number ( enum -- number ) foldable
M: integer enum>number ;
M: symbol enum>number "enum-value" word-prop ;
<PRIVATE
: enum-boxer ( members -- quot )
[ first2 swap '[ _ ] 2array ]
{ } map-as [ ] suffix '[ _ case ] ;
PRIVATE>
MACRO: number>enum ( enum-c-type -- )
c-type members>> enum-boxer ;
M: enum-c-type c-type-boxed-class drop object ;
M: enum-c-type c-type-boxer-quot members>> enum-boxer ;
M: enum-c-type c-type-unboxer-quot drop [ enum>number ] ;
M: enum-c-type c-type-setter
[ enum>number ] swap base-type>> c-type-setter '[ _ 2dip @ ] ;
<PRIVATE
: define-enum-value ( class value -- )
"enum-value" set-word-prop ;
: define-enum-members ( member-names -- )
[
[ first define-symbol ]
[ first2 define-enum-value ] bi
] each ;
: define-enum-constructor ( word -- )
[ name>> "<" ">" surround create-in ] keep
[ number>enum ] curry (( number -- enum )) define-inline ;
PRIVATE>
: define-enum ( word base-type members -- )
[ dup define-enum-constructor ] 2dip
dup define-enum-members
<enum-c-type> swap typedef ;
PREDICATE: enum-c-type-word < c-type-word
"c-type" word-prop enum-c-type? ;

View File

@ -75,19 +75,32 @@ M: pointer return-type-name to>> return-type-name CHAR: * suffix ;
"*" ?head
[ [ <pointer> ] dip parse-pointers ] when ;
: next-enum-member ( members name value -- members value' )
[ 2array suffix! ] [ 1 + ] bi ;
: parse-enum-name ( -- name )
scan (CREATE-C-TYPE) dup save-location ;
: parse-enum-base-type ( -- base-type token )
scan dup "<" =
[ drop scan-object scan ]
[ [ int ] dip ] if ;
: parse-enum-member ( members name value -- members value' )
over "{" =
[ 2drop scan create-in scan-object next-enum-member "}" expect ]
[ [ create-in ] dip next-enum-member ] if ;
: parse-enum-members ( members counter token -- members )
dup ";" = not
[ swap parse-enum-member scan parse-enum-members ] [ 2drop ] if ;
PRIVATE>
: define-enum-member ( word-string value -- next-value )
[ create-in ] dip [ define-constant ] keep 1 + ;
: parse-enum-member ( word-string value -- next-value )
over "{" =
[ 2drop scan scan-object define-enum-member "}" expect ]
[ define-enum-member ] if ;
: parse-enum-members ( counter -- )
scan dup ";" = not
[ swap parse-enum-member parse-enum-members ] [ 2drop ] if ;
: parse-enum ( -- name base-type members )
parse-enum-name
parse-enum-base-type
[ V{ } clone 0 ] dip parse-enum-members ;
: scan-function-name ( -- return function )
scan-c-type scan parse-pointers ;

View File

@ -1,9 +1,10 @@
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors kernel combinators alien alien.strings alien.c-types
alien.parser alien.syntax arrays assocs effects math.parser
prettyprint.backend prettyprint.custom prettyprint.sections
definitions see see.private sequences strings words ;
USING: accessors kernel combinators alien alien.enums
alien.strings alien.c-types alien.parser alien.syntax arrays
assocs effects math.parser prettyprint.backend prettyprint.custom
prettyprint.sections definitions see see.private sequences
strings words ;
IN: alien.prettyprint
M: alien pprint*
@ -110,3 +111,15 @@ M: alien-callback-type-word synopsis*
")" text block>
]
} cleave ;
M: enum-c-type-word definer
drop \ ENUM: \ ; ;
M: enum-c-type-word synopsis*
{
[ seeing-word ]
[ definer. ]
[ pprint-word ]
[ c-type base-type>> dup int eq? [ drop ] [ "<" text pprint-word ] if ]
} cleave ;
M: enum-c-type-word definition
c-type members>> ;

View File

@ -1,6 +1,6 @@
IN: alien.syntax
USING: alien alien.c-types alien.parser alien.libraries
classes.struct help.markup help.syntax see ;
USING: alien alien.c-types alien.enums alien.libraries classes.struct
help.markup help.syntax see ;
HELP: DLL"
{ $syntax "DLL\" path\"" }
@ -69,16 +69,15 @@ HELP: TYPEDEF:
{ $description "Aliases the C type " { $snippet "old" } " under the name " { $snippet "new" } "." }
{ $notes "This word differs from " { $link typedef } " in that it runs at parse time, to ensure correct ordering of operations when loading source files. Words defined in source files are compiled before top-level forms are run, so if a source file defines C binding words and uses " { $link typedef } ", the type alias won't be available at compile time." } ;
HELP: C-ENUM:
{ $syntax "C-ENUM: type/f words... ;" }
HELP: ENUM:
{ $syntax "ENUM: type words... ;" "ENUM: type < base-type words..." }
{ $values { "type" "a name to typedef to int or f" } { "words" "a sequence of word names" } }
{ $description "Creates a sequence of word definitions in the current vocabulary. Each word pushes an integer according to the rules of C enums." }
{ $notes "This word emulates a C-style " { $snippet "enum" } " in Factor. While this feature can be used for any purpose, using integer constants is discouraged unless it is for interfacing with C libraries. Factor code should use " { $link "words.symbol" } " or " { $link "singletons" } " instead." }
{ $description "Creates a c-type that boxes and unboxes integer values to symbols. A symbol is defined for each member word. The base c-type can optionally be specified and defaults to " { $link int } ". A constructor word " { $snippet "<type>" } " is defined for converting from integers to singletons. The generic word " { $link enum>number } " converts from singletons to integers. Enum-typed values are automatically prettyprinted as their singleton words. Unrecognizing enum numbers are kept as numbers." }
{ $examples
"Here is an example enumeration definition:"
{ $code "C-ENUM: color_t red { green 3 } blue ;" }
"It is equivalent to the following series of definitions:"
{ $code "CONSTANT: red 0" "CONSTANT: green 3" "CONSTANT: blue 4" }
{ $code "ENUM: color_t red { green 3 } blue ;" }
"The following expression returns true:"
{ $code "3 <color_t> [ green = ] [ enum>number 3 = ] bi and" }
} ;
HELP: C-TYPE:

View File

@ -1,6 +1,6 @@
! Copyright (C) 2005, 2010 Slava Pestov, Alex Chapman.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays alien alien.c-types alien.arrays
USING: accessors arrays alien alien.c-types alien.enums alien.arrays
alien.strings kernel math namespaces parser sequences words
quotations math.parser splitting grouping effects assocs
combinators lexer strings.parser alien.parser fry vocabs.parser
@ -28,11 +28,8 @@ SYNTAX: CALLBACK:
SYNTAX: TYPEDEF:
scan-c-type CREATE-C-TYPE dup save-location typedef ;
SYNTAX: C-ENUM:
scan dup "f" =
[ drop ]
[ (CREATE-C-TYPE) dup save-location int swap typedef ] if
0 parse-enum-members ;
SYNTAX: ENUM:
parse-enum define-enum ;
SYNTAX: C-TYPE:
void CREATE-C-TYPE typedef ;

View File

@ -13,9 +13,9 @@ TUPLE: biassoc from to ;
M: biassoc assoc-size from>> assoc-size ;
M: biassoc at* from>> at* ;
M: biassoc at* from>> at* ; inline
M: biassoc value-at* to>> at* ;
M: biassoc value-at* to>> at* ; inline
: once-at ( value key assoc -- )
2dup key? [ 3drop ] [ set-at ] if ;

View File

@ -1,14 +1,14 @@
! Copyright (C) 2008, 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays combinators hints kernel locals math
math.order sequences ;
math.order sequences sequences.private ;
IN: binary-search
<PRIVATE
:: (search) ( seq from to quot: ( elt -- <=> ) -- i elt )
from to + 2/ :> midpoint@
midpoint@ seq nth :> midpoint
midpoint@ seq nth-unsafe :> midpoint
to from - 1 <= [
midpoint@ midpoint

View File

@ -11,6 +11,9 @@ IN: bit-sets.tests
T{ bit-set f ?{ f f t f t f } } intersect
] unit-test
[ f ] [ T{ bit-set f ?{ t f f f t f } } null? ] unit-test
[ t ] [ T{ bit-set f ?{ f f f f f f } } null? ] unit-test
[ T{ bit-set f ?{ t f t f f f } } ] [
T{ bit-set f ?{ t t t f f f } }
T{ bit-set f ?{ f t f f t t } } diff

View File

@ -20,8 +20,8 @@ IN: bootstrap.compiler
"alien.remote-control" require
] unless
"prettyprint" "alien.prettyprint" require-when
"debugger" "alien.debugger" require-when
{ "boostrap.compiler" "prettyprint" } "alien.prettyprint" require-when
{ "boostrap.compiler" "debugger" } "alien.debugger" require-when
"cpu." cpu name>> append require
@ -35,7 +35,7 @@ gc
[ optimized? not ] filter compile ;
"debug-compiler" get [
nl
"Compiling..." write flush
@ -57,7 +57,7 @@ gc
curry compose uncurry
array-nth set-array-nth length>>
array-nth set-array-nth
wrap probe
@ -117,4 +117,6 @@ gc
" done" print flush
"io.streams.byte-array.fast" require
] unless

View File

@ -1,4 +1,4 @@
USING: vocabs.loader vocabs kernel ;
IN: bootstrap.handbook
"bootstrap.help" "help.handbook" require-when
{ "bootstrap.handbook" "bootstrap.help" } "help.handbook" require-when

View File

@ -51,9 +51,11 @@ SYMBOL: bootstrap-time
: save/restore-error ( quot -- )
error get-global
original-error get-global
error-continuation get-global
[ call ] 2dip
[ call ] 3dip
error-continuation set-global
original-error set-global
error set-global ; inline
@ -89,6 +91,7 @@ SYMBOL: bootstrap-time
run-bootstrap-init
f error set-global
f original-error set-global
f error-continuation set-global
nano-count swap - bootstrap-time set-global

View File

@ -4,6 +4,6 @@ USING: vocabs.loader kernel io.thread threads
compiler.utilities namespaces ;
IN: bootstrap.threads
"debugger" "debugger.threads" require-when
{ "bootstrap.threads" "debugger" } "debugger.threads" require-when
[ yield ] yield-hook set-global

View File

@ -4,7 +4,7 @@ USING: kernel vocabs vocabs.loader sequences system ;
[ "bootstrap." prepend vocab ] all? [
"ui.tools" require
"ui.backend.cocoa" "ui.backend.cocoa.tools" require-when
{ "ui.backend.cocoa" } "ui.backend.cocoa.tools" require-when
"ui.tools.walker" require
] when

View File

@ -46,7 +46,7 @@ TYPEDEF: void* cairo_destroy_func_t
STRUCT: cairo_user_data_key_t
{ unused int } ;
C-ENUM: cairo_status_t
ENUM: cairo_status_t
CAIRO_STATUS_SUCCESS
CAIRO_STATUS_NO_MEMORY
CAIRO_STATUS_INVALID_RESTORE
@ -126,7 +126,7 @@ FUNCTION: void
cairo_pop_group_to_source ( cairo_t* cr ) ;
! Modify state
C-ENUM: cairo_operator_t
ENUM: cairo_operator_t
CAIRO_OPERATOR_CLEAR
CAIRO_OPERATOR_SOURCE
@ -163,7 +163,7 @@ cairo_set_source_surface ( cairo_t* cr, cairo_surface_t* surface, double x, doub
FUNCTION: void
cairo_set_tolerance ( cairo_t* cr, double tolerance ) ;
C-ENUM: cairo_antialias_t
ENUM: cairo_antialias_t
CAIRO_ANTIALIAS_DEFAULT
CAIRO_ANTIALIAS_NONE
CAIRO_ANTIALIAS_GRAY
@ -172,7 +172,7 @@ C-ENUM: cairo_antialias_t
FUNCTION: void
cairo_set_antialias ( cairo_t* cr, cairo_antialias_t antialias ) ;
C-ENUM: cairo_fill_rule_t
ENUM: cairo_fill_rule_t
CAIRO_FILL_RULE_WINDING
CAIRO_FILL_RULE_EVEN_ODD ;
@ -182,7 +182,7 @@ cairo_set_fill_rule ( cairo_t* cr, cairo_fill_rule_t fill_rule ) ;
FUNCTION: void
cairo_set_line_width ( cairo_t* cr, double width ) ;
C-ENUM: cairo_line_cap_t
ENUM: cairo_line_cap_t
CAIRO_LINE_CAP_BUTT
CAIRO_LINE_CAP_ROUND
CAIRO_LINE_CAP_SQUARE ;
@ -190,7 +190,7 @@ C-ENUM: cairo_line_cap_t
FUNCTION: void
cairo_set_line_cap ( cairo_t* cr, cairo_line_cap_t line_cap ) ;
C-ENUM: cairo_line_join_t
ENUM: cairo_line_join_t
CAIRO_LINE_JOIN_MITER
CAIRO_LINE_JOIN_ROUND
CAIRO_LINE_JOIN_BEVEL ;
@ -375,30 +375,30 @@ STRUCT: cairo_font_extents_t
{ max_x_advance double }
{ max_y_advance double } ;
C-ENUM: cairo_font_slant_t
ENUM: cairo_font_slant_t
CAIRO_FONT_SLANT_NORMAL
CAIRO_FONT_SLANT_ITALIC
CAIRO_FONT_SLANT_OBLIQUE ;
C-ENUM: cairo_font_weight_t
ENUM: cairo_font_weight_t
CAIRO_FONT_WEIGHT_NORMAL
CAIRO_FONT_WEIGHT_BOLD ;
C-ENUM: cairo_subpixel_order_t
ENUM: cairo_subpixel_order_t
CAIRO_SUBPIXEL_ORDER_DEFAULT
CAIRO_SUBPIXEL_ORDER_RGB
CAIRO_SUBPIXEL_ORDER_BGR
CAIRO_SUBPIXEL_ORDER_VRGB
CAIRO_SUBPIXEL_ORDER_VBGR ;
C-ENUM: cairo_hint_style_t
ENUM: cairo_hint_style_t
CAIRO_HINT_STYLE_DEFAULT
CAIRO_HINT_STYLE_NONE
CAIRO_HINT_STYLE_SLIGHT
CAIRO_HINT_STYLE_MEDIUM
CAIRO_HINT_STYLE_FULL ;
C-ENUM: cairo_hint_metrics_t
ENUM: cairo_hint_metrics_t
CAIRO_HINT_METRICS_DEFAULT
CAIRO_HINT_METRICS_OFF
CAIRO_HINT_METRICS_ON ;
@ -518,7 +518,7 @@ cairo_font_face_get_reference_count ( cairo_font_face_t* font_face ) ;
FUNCTION: cairo_status_t
cairo_font_face_status ( cairo_font_face_t* font_face ) ;
C-ENUM: cairo_font_type_t
ENUM: cairo_font_type_t
CAIRO_FONT_TYPE_TOY
CAIRO_FONT_TYPE_FT
CAIRO_FONT_TYPE_WIN32
@ -630,7 +630,7 @@ cairo_get_target ( cairo_t* cr ) ;
FUNCTION: cairo_surface_t*
cairo_get_group_target ( cairo_t* cr ) ;
C-ENUM: cairo_path_data_type_t
ENUM: cairo_path_data_type_t
CAIRO_PATH_MOVE_TO
CAIRO_PATH_LINE_TO
CAIRO_PATH_CURVE_TO
@ -696,7 +696,7 @@ cairo_surface_get_reference_count ( cairo_surface_t* surface ) ;
FUNCTION: cairo_status_t
cairo_surface_status ( cairo_surface_t* surface ) ;
C-ENUM: cairo_surface_type_t
ENUM: cairo_surface_type_t
CAIRO_SURFACE_TYPE_IMAGE
CAIRO_SURFACE_TYPE_PDF
CAIRO_SURFACE_TYPE_PS
@ -759,7 +759,7 @@ cairo_surface_show_page ( cairo_surface_t* surface ) ;
! Image-surface functions
C-ENUM: cairo_format_t
ENUM: cairo_format_t
CAIRO_FORMAT_ARGB32
CAIRO_FORMAT_RGB24
CAIRO_FORMAT_A8
@ -831,7 +831,7 @@ cairo_pattern_get_user_data ( cairo_pattern_t* pattern, cairo_user_data_key_t* k
FUNCTION: cairo_status_t
cairo_pattern_set_user_data ( cairo_pattern_t* pattern, cairo_user_data_key_t* key, void* user_data, cairo_destroy_func_t destroy ) ;
C-ENUM: cairo_pattern_type_t
ENUM: cairo_pattern_type_t
CAIRO_PATTERN_TYPE_SOLID
CAIRO_PATTERN_TYPE_SURFACE
CAIRO_PATTERN_TYPE_LINEAR
@ -852,7 +852,7 @@ cairo_pattern_set_matrix ( cairo_pattern_t* pattern, cairo_matrix_t* matrix ) ;
FUNCTION: void
cairo_pattern_get_matrix ( cairo_pattern_t* pattern, cairo_matrix_t* matrix ) ;
C-ENUM: cairo_extend_t
ENUM: cairo_extend_t
CAIRO_EXTEND_NONE
CAIRO_EXTEND_REPEAT
CAIRO_EXTEND_REFLECT
@ -864,7 +864,7 @@ cairo_pattern_set_extend ( cairo_pattern_t* pattern, cairo_extend_t extend ) ;
FUNCTION: cairo_extend_t
cairo_pattern_get_extend ( cairo_pattern_t* pattern ) ;
C-ENUM: cairo_filter_t
ENUM: cairo_filter_t
CAIRO_FILTER_FAST
CAIRO_FILTER_GOOD
CAIRO_FILTER_BEST

View File

@ -35,7 +35,8 @@ HELP: STRUCT:
{ "Struct classes cannot have a superclass defined." }
{ "The slots of a struct must all have a type declared. The type must be a C type." }
{ { $link read-only } " slots on structs are not enforced, though they may be declared." }
} } ;
}
"Additionally, structs may use bit fields. A slot specifier may use the syntax " { $snippet "bits: n" } " to specify that the bit width of the slot is " { $snippet "n" } ". Bit width may be specified on signed or unsigned integer slots. The layout of bit fields is not guaranteed to match that of any particular C compiler." } ;
HELP: S{
{ $syntax "S{ class slots... }" }

View File

@ -404,4 +404,4 @@ FUNCTOR-SYNTAX: STRUCT:
USING: vocabs vocabs.loader ;
"prettyprint" "classes.struct.prettyprint" require-when
{ "classes.struct" "prettyprint" } "classes.struct.prettyprint" require-when

View File

@ -8,10 +8,9 @@ IN: cocoa.application
: <NSString> ( str -- alien ) <CFString> -> autorelease ;
C-ENUM: f
NSApplicationDelegateReplySuccess
NSApplicationDelegateReplyCancel
NSApplicationDelegateReplyFailure ;
CONSTANT: NSApplicationDelegateReplySuccess 0
CONSTANT: NSApplicationDelegateReplyCancel 1
CONSTANT: NSApplicationDelegateReplyFailure 2
: with-autorelease-pool ( quot -- )
NSAutoreleasePool -> new [ call ] [ -> release ] bi* ; inline

View File

@ -63,3 +63,16 @@ IN: combinators.smart.tests
[ { 1 2 } { 3 4 } { 5 6 } ] [ 1 2 3 4 5 6 [ 2array ] 3 smart-apply ] unit-test
[ { 1 2 3 } { 4 5 6 } ] [ 1 2 3 4 5 6 [ 3array ] 2 smart-apply ] unit-test
[ 4 ] [ 2 [ even? ] [ 2 + ] smart-when ] unit-test
[ 3 ] [ 3 [ even? ] [ 2 + ] smart-when ] unit-test
[ 4 ] [ 2 [ odd? ] [ 2 + ] smart-unless ] unit-test
[ 3 ] [ 3 [ odd? ] [ 2 + ] smart-unless ] unit-test
[ 4 ] [ 2 [ even? ] [ 2 + ] smart-when* ] unit-test
[ ] [ 3 [ even? ] [ 2 + ] smart-when* ] unit-test
[ 3 ] [ 2 [ odd? ] [ 3 ] smart-unless* ] unit-test
[ 3 ] [ 3 [ odd? ] [ 5 ] smart-unless* ] unit-test
[ -1 ] [ 1 2 [ + odd? ] [ - ] smart-when* ] unit-test
[ ] [ 2 2 [ + odd? ] [ ] smart-unless* ] unit-test

View File

@ -49,8 +49,29 @@ MACRO: preserving ( quot -- )
MACRO: nullary ( quot -- quot' )
dup outputs '[ @ _ ndrop ] ;
MACRO: smart-if ( pred true false -- )
MACRO: dropping ( quot -- quot' )
inputs '[ [ _ ndrop ] ] ;
MACRO: balancing ( quot -- quot' )
'[ _ [ preserving ] [ dropping ] bi ] ;
MACRO: smart-if ( pred true false -- quot )
'[ _ preserving _ _ if ] ;
MACRO: smart-apply ( quot n -- )
MACRO: smart-when ( pred true -- quot )
'[ _ _ [ ] smart-if ] ;
MACRO: smart-unless ( pred false -- quot )
'[ _ [ ] _ smart-if ] ;
MACRO: smart-if* ( pred true false -- quot )
'[ _ balancing _ swap _ compose if ] ;
MACRO: smart-when* ( pred true -- quot )
'[ _ _ [ ] smart-if* ] ;
MACRO: smart-unless* ( pred false -- quot )
'[ _ [ ] _ smart-if* ] ;
MACRO: smart-apply ( quot n -- quot )
[ dup inputs ] dip '[ _ _ _ mnapply ] ;

View File

@ -0,0 +1,244 @@
USING: arrays compiler.cfg.alias-analysis compiler.cfg.instructions
compiler.cfg.registers compiler.cfg.debugger compiler.cfg.comparisons
cpu.architecture tools.test ;
IN: compiler.cfg.alias-analysis.tests
! Redundant load elimination
[
V{
T{ ##peek f 0 D 0 }
T{ ##slot-imm f 1 0 1 0 }
T{ ##copy f 2 1 any-rep }
}
] [
V{
T{ ##peek f 0 D 0 }
T{ ##slot-imm f 1 0 1 0 }
T{ ##slot-imm f 2 0 1 0 }
} alias-analysis-step
] unit-test
! Store-load forwarding
[
V{
T{ ##peek f 0 D 0 }
T{ ##peek f 1 D 1 }
T{ ##set-slot-imm f 1 0 1 0 }
T{ ##copy f 2 1 any-rep }
}
] [
V{
T{ ##peek f 0 D 0 }
T{ ##peek f 1 D 1 }
T{ ##set-slot-imm f 1 0 1 0 }
T{ ##slot-imm f 2 0 1 0 }
} alias-analysis-step
] unit-test
! Dead store elimination
[
V{
T{ ##peek f 0 D 0 }
T{ ##peek f 1 D 1 }
T{ ##peek f 2 D 2 }
T{ ##set-slot-imm f 2 0 1 0 }
}
] [
V{
T{ ##peek f 0 D 0 }
T{ ##peek f 1 D 1 }
T{ ##peek f 2 D 2 }
T{ ##set-slot-imm f 1 0 1 0 }
T{ ##set-slot-imm f 2 0 1 0 }
} alias-analysis-step
] unit-test
! Redundant store elimination
[
V{
T{ ##peek f 0 D 0 }
T{ ##slot-imm f 1 0 1 0 }
}
] [
V{
T{ ##peek f 0 D 0 }
T{ ##slot-imm f 1 0 1 0 }
T{ ##set-slot-imm f 1 0 1 0 }
} alias-analysis-step
] unit-test
[
V{
T{ ##peek f 0 D 0 }
T{ ##slot-imm f 1 0 1 0 }
T{ ##copy f 2 1 any-rep }
}
] [
V{
T{ ##peek f 0 D 0 }
T{ ##slot-imm f 1 0 1 0 }
T{ ##copy f 2 1 any-rep }
T{ ##set-slot-imm f 2 0 1 0 }
} alias-analysis-step
] unit-test
! Not a redundant load
[
V{
T{ ##peek f 0 D 0 }
T{ ##peek f 1 D 1 }
T{ ##slot-imm f 1 0 1 0 }
T{ ##set-slot-imm f 0 1 1 0 }
T{ ##slot-imm f 2 0 1 0 }
}
] [
V{
T{ ##peek f 0 D 0 }
T{ ##peek f 1 D 1 }
T{ ##slot-imm f 1 0 1 0 }
T{ ##set-slot-imm f 0 1 1 0 }
T{ ##slot-imm f 2 0 1 0 }
} alias-analysis-step
] unit-test
! Not a redundant store
[
V{
T{ ##peek f 0 D 0 }
T{ ##peek f 1 D 1 }
T{ ##peek f 2 D 2 }
T{ ##peek f 3 D 3 }
T{ ##set-slot-imm f 2 1 1 0 }
T{ ##slot-imm f 4 0 1 0 }
T{ ##set-slot-imm f 3 1 1 0 }
}
] [
V{
T{ ##peek f 0 D 0 }
T{ ##peek f 1 D 1 }
T{ ##peek f 2 D 2 }
T{ ##peek f 3 D 3 }
T{ ##set-slot-imm f 2 1 1 0 }
T{ ##slot-imm f 4 0 1 0 }
T{ ##set-slot-imm f 3 1 1 0 }
} alias-analysis-step
] unit-test
! There's a redundant load, but not a redundant store
[
V{
T{ ##peek f 0 D 0 }
T{ ##peek f 1 D 1 }
T{ ##peek f 2 D 2 }
T{ ##peek f 3 D 3 }
T{ ##slot-imm f 4 0 1 0 }
T{ ##set-slot-imm f 2 0 1 0 }
T{ ##slot f 5 0 3 0 0 }
T{ ##set-slot-imm f 3 0 1 0 }
T{ ##copy f 6 3 any-rep }
}
] [
V{
T{ ##peek f 0 D 0 }
T{ ##peek f 1 D 1 }
T{ ##peek f 2 D 2 }
T{ ##peek f 3 D 3 }
T{ ##slot-imm f 4 0 1 0 }
T{ ##set-slot-imm f 2 0 1 0 }
T{ ##slot f 5 0 3 0 0 }
T{ ##set-slot-imm f 3 0 1 0 }
T{ ##slot-imm f 6 0 1 0 }
} alias-analysis-step
] unit-test
! Fresh allocations don't alias existing values
! Redundant load elimination
[
V{
T{ ##peek f 1 D 1 }
T{ ##peek f 2 D 2 }
T{ ##peek f 3 D 3 }
T{ ##allot f 4 16 array }
T{ ##set-slot-imm f 3 4 1 0 }
T{ ##set-slot-imm f 2 1 1 0 }
T{ ##copy f 5 3 any-rep }
}
] [
V{
T{ ##peek f 1 D 1 }
T{ ##peek f 2 D 2 }
T{ ##peek f 3 D 3 }
T{ ##allot f 4 16 array }
T{ ##set-slot-imm f 3 4 1 0 }
T{ ##set-slot-imm f 2 1 1 0 }
T{ ##slot-imm f 5 4 1 0 }
} alias-analysis-step
] unit-test
! Redundant store elimination
[
V{
T{ ##peek f 1 D 1 }
T{ ##peek f 2 D 2 }
T{ ##peek f 3 D 3 }
T{ ##allot f 4 16 array }
T{ ##slot-imm f 5 1 1 0 }
T{ ##set-slot-imm f 3 4 1 0 }
}
] [
V{
T{ ##peek f 1 D 1 }
T{ ##peek f 2 D 2 }
T{ ##peek f 3 D 3 }
T{ ##allot f 4 16 array }
T{ ##set-slot-imm f 1 4 1 0 }
T{ ##slot-imm f 5 1 1 0 }
T{ ##set-slot-imm f 3 4 1 0 }
} alias-analysis-step
] unit-test
! Storing a new alias class into another object means that heap-ac
! can now alias the new ac
[
V{
T{ ##peek f 0 D 0 }
T{ ##peek f 1 D 1 }
T{ ##peek f 2 D 2 }
T{ ##peek f 3 D 3 }
T{ ##allot f 4 16 array }
T{ ##set-slot-imm f 0 4 1 0 }
T{ ##set-slot-imm f 4 2 1 0 }
T{ ##slot-imm f 5 3 1 0 }
T{ ##set-slot-imm f 1 5 1 0 }
T{ ##slot-imm f 6 4 1 0 }
}
] [
V{
T{ ##peek f 0 D 0 }
T{ ##peek f 1 D 1 }
T{ ##peek f 2 D 2 }
T{ ##peek f 3 D 3 }
T{ ##allot f 4 16 array }
T{ ##set-slot-imm f 0 4 1 0 }
T{ ##set-slot-imm f 4 2 1 0 }
T{ ##slot-imm f 5 3 1 0 }
T{ ##set-slot-imm f 1 5 1 0 }
T{ ##slot-imm f 6 4 1 0 }
} alias-analysis-step
] unit-test
! Compares between objects which cannot alias are eliminated
[
V{
T{ ##peek f 0 D 0 }
T{ ##allot f 1 16 array }
T{ ##load-reference f 2 f }
}
] [
V{
T{ ##peek f 0 D 0 }
T{ ##allot f 1 16 array }
T{ ##compare f 2 0 1 cc= }
} alias-analysis-step
] unit-test

View File

@ -1,4 +1,4 @@
! Copyright (C) 2008, 2009 Slava Pestov.
! Copyright (C) 2008, 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel math namespaces assocs hashtables sequences arrays
accessors words vectors combinators combinators.short-circuit
@ -7,8 +7,8 @@ compiler.cfg
compiler.cfg.rpo
compiler.cfg.def-use
compiler.cfg.liveness
compiler.cfg.copy-prop
compiler.cfg.registers
compiler.cfg.utilities
compiler.cfg.comparisons
compiler.cfg.instructions
compiler.cfg.representations.preferred ;
@ -68,6 +68,14 @@ IN: compiler.cfg.alias-analysis
! e = c
! x[1] = c
! Local copy propagation
SYMBOL: copies
: resolve ( vreg -- vreg ) copies get ?at drop ;
: record-copy ( ##copy -- )
[ src>> resolve ] [ dst>> ] bi copies get set-at ; inline
! Map vregs -> alias classes
SYMBOL: vregs>acs
@ -85,15 +93,10 @@ SYMBOL: acs>vregs
: ac>vregs ( ac -- vregs ) acs>vregs get at ;
GENERIC: aliases ( vreg -- vregs )
M: integer aliases
: aliases ( vreg -- vregs )
#! All vregs which may contain the same value as vreg.
vreg>ac ac>vregs ;
M: word aliases
1array ;
: each-alias ( vreg quot -- )
[ aliases ] dip each ; inline
@ -187,19 +190,12 @@ SYMBOL: heap-ac
[ kill-constant-set-slot ] 2bi
] [ nip kill-computed-set-slot ] if ;
SYMBOL: constants
: constant ( vreg -- n/f )
#! Return a ##load-immediate value, or f if the vreg was not
#! assigned by an ##load-immediate.
resolve constants get at ;
GENERIC: insn-slot# ( insn -- slot#/f )
GENERIC: insn-object ( insn -- vreg )
M: ##slot insn-slot# slot>> constant ;
M: ##slot insn-slot# drop f ;
M: ##slot-imm insn-slot# slot>> ;
M: ##set-slot insn-slot# slot>> constant ;
M: ##set-slot insn-slot# drop f ;
M: ##set-slot-imm insn-slot# slot>> ;
M: ##alien-global insn-slot# [ library>> ] [ symbol>> ] bi 2array ;
M: ##vm-field insn-slot# offset>> ;
@ -218,7 +214,6 @@ M: ##set-vm-field insn-object drop \ ##vm-field ;
H{ } clone vregs>acs set
H{ } clone acs>vregs set
H{ } clone live-slots set
H{ } clone constants set
H{ } clone copies set
0 ac-counter set
@ -238,17 +233,13 @@ M: insn analyze-aliases*
! a new value, except boxing instructions haven't been
! inserted yet.
dup defs-vreg [
over defs-vreg-rep int-rep eq?
over defs-vreg-rep { int-rep tagged-rep } member?
[ set-heap-ac ] [ set-new-ac ] if
] when* ;
M: ##phi analyze-aliases*
dup defs-vreg set-heap-ac ;
M: ##load-immediate analyze-aliases*
call-next-method
dup [ val>> ] [ dst>> ] bi constants get set-at ;
M: ##allocation analyze-aliases*
#! A freshly allocated object is distinct from any other
#! object.
@ -257,11 +248,10 @@ M: ##allocation analyze-aliases*
M: ##read analyze-aliases*
call-next-method
dup [ dst>> ] [ insn-slot# ] [ insn-object ] tri
2dup live-slot dup [
2nip any-rep \ ##copy new-insn analyze-aliases* nip
] [
drop remember-slot
] if ;
2dup live-slot dup
[ 2nip <copy> analyze-aliases* nip ]
[ drop remember-slot ]
if ;
: idempotent? ( value slot#/f vreg -- ? )
#! Are we storing a value back to the same slot it was read
@ -271,7 +261,9 @@ M: ##read analyze-aliases*
M: ##write analyze-aliases*
dup
[ src>> resolve ] [ insn-slot# ] [ insn-object ] tri
[ remember-set-slot drop ] [ load-slot ] 3bi ;
3dup idempotent? [ 3drop ] [
[ remember-set-slot drop ] [ load-slot ] 3bi
] if ;
M: ##copy analyze-aliases*
#! The output vreg gets the same alias class as the input
@ -287,7 +279,7 @@ M: ##copy analyze-aliases*
M: ##compare analyze-aliases*
call-next-method
dup useless-compare? [
dst>> \ f type-number \ ##load-immediate new-insn
dst>> f \ ##load-reference new-insn
analyze-aliases*
] when ;
@ -327,5 +319,5 @@ M: insn eliminate-dead-stores* ;
compute-live-stores
eliminate-dead-stores ;
: alias-analysis ( cfg -- cfg' )
[ alias-analysis-step ] local-optimization ;
: alias-analysis ( cfg -- cfg )
dup [ alias-analysis-step ] simple-optimization ;

View File

@ -1,9 +1,9 @@
! Copyright (C) 2008, 2010 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 layouts
compiler.cfg.instructions compiler.cfg.registers
compiler.cfg.stack-frame ;
combinators classes words cpu.architecture layouts compiler.cfg
compiler.cfg.rpo compiler.cfg.instructions
compiler.cfg.registers compiler.cfg.stack-frame ;
IN: compiler.cfg.build-stack-frame
SYMBOL: frame-required?
@ -25,49 +25,29 @@ M: stack-frame-insn compute-stack-frame*
M: ##call compute-stack-frame* drop frame-required? on ;
M: ##gc compute-stack-frame*
M: ##call-gc compute-stack-frame*
drop
frame-required? on
stack-frame new
swap tagged-values>> length cells >>gc-root-size
t >>calls-vm?
request-stack-frame ;
M: _spill-area-size compute-stack-frame*
n>> stack-frame get (>>spill-area-size) ;
stack-frame new t >>calls-vm? request-stack-frame ;
M: insn compute-stack-frame*
class frame-required? word-prop [
frame-required? on
] when ;
class "frame-required?" word-prop
[ frame-required? on ] when ;
\ _spill t frame-required? set-word-prop
\ ##unary-float-function t frame-required? set-word-prop
\ ##binary-float-function t frame-required? set-word-prop
: initial-stack-frame ( -- stack-frame )
stack-frame new cfg get spill-area-size>> >>spill-area-size ;
: compute-stack-frame ( insns -- )
frame-required? off
stack-frame new stack-frame set
[ compute-stack-frame* ] each
initial-stack-frame stack-frame set
[ instructions>> [ compute-stack-frame* ] each ] each-basic-block
stack-frame get dup stack-frame-size >>total-size drop ;
GENERIC: insert-pro/epilogues* ( insn -- )
M: ##prologue insert-pro/epilogues*
drop frame-required? get [ stack-frame get _prologue ] when ;
M: ##epilogue insert-pro/epilogues*
drop frame-required? get [ stack-frame get _epilogue ] when ;
M: insn insert-pro/epilogues* , ;
: insert-pro/epilogues ( insns -- insns )
[ [ insert-pro/epilogues* ] each ] { } make ;
: build-stack-frame ( mr -- mr )
: build-stack-frame ( cfg -- cfg )
[
[ compute-stack-frame ]
[
[ compute-stack-frame ]
[ insert-pro/epilogues ]
bi
] change-instructions
frame-required? get stack-frame get f ?
>>stack-frame
] bi
] with-scope ;

View File

@ -1,17 +1,19 @@
USING: tools.test kernel sequences words sequences.private fry
prettyprint alien alien.accessors math.private compiler.tree.builder
compiler.tree.optimizer compiler.cfg.builder compiler.cfg.debugger
compiler.cfg.optimizer compiler.cfg.predecessors compiler.cfg.checker
compiler.cfg arrays locals byte-arrays kernel.private math
slots.private vectors sbufs strings math.partial-dispatch
hashtables assocs combinators.short-circuit
strings.private accessors compiler.cfg.instructions ;
prettyprint alien alien.accessors math.private
compiler.tree.builder compiler.tree.optimizer
compiler.cfg.builder compiler.cfg.debugger
compiler.cfg.optimizer compiler.cfg.rpo
compiler.cfg.predecessors compiler.cfg.checker compiler.cfg
arrays locals byte-arrays kernel.private math slots.private
vectors sbufs strings math.partial-dispatch hashtables assocs
combinators.short-circuit strings.private accessors
compiler.cfg.instructions compiler.cfg.representations ;
FROM: alien.c-types => int ;
IN: compiler.cfg.builder.tests
! Just ensure that various CFGs build correctly.
: unit-test-cfg ( quot -- )
'[ _ test-cfg [ [ optimize-cfg check-cfg ] with-cfg ] each ] [ ] swap unit-test ;
: unit-test-builder ( quot -- )
'[ _ test-builder [ [ optimize-cfg check-cfg ] with-cfg ] each ] [ ] swap unit-test ;
: blahblah ( nodes -- ? )
{ fixnum } declare [
@ -104,7 +106,7 @@ IN: compiler.cfg.builder.tests
set-string-nth-fast
]
} [
unit-test-cfg
unit-test-builder
] each
: test-1 ( -- ) test-1 ;
@ -115,7 +117,7 @@ IN: compiler.cfg.builder.tests
test-1
test-2
test-3
} [ unit-test-cfg ] each
} [ unit-test-builder ] each
{
byte-array
@ -133,8 +135,8 @@ IN: compiler.cfg.builder.tests
alien-float
alien-double
} [| word |
{ class } word '[ _ declare 10 _ execute ] unit-test-cfg
{ class fixnum } word '[ _ declare _ execute ] unit-test-cfg
{ class } word '[ _ declare 10 _ execute ] unit-test-builder
{ class fixnum } word '[ _ declare _ execute ] unit-test-builder
] each
{
@ -145,23 +147,23 @@ IN: compiler.cfg.builder.tests
set-alien-unsigned-2
set-alien-unsigned-4
} [| word |
{ fixnum class } word '[ _ declare 10 _ execute ] unit-test-cfg
{ fixnum class fixnum } word '[ _ declare _ execute ] unit-test-cfg
{ fixnum class } word '[ _ declare 10 _ execute ] unit-test-builder
{ fixnum class fixnum } word '[ _ declare _ execute ] unit-test-builder
] each
{ float class } \ set-alien-float '[ _ declare 10 _ execute ] unit-test-cfg
{ float class fixnum } \ set-alien-float '[ _ declare _ execute ] unit-test-cfg
{ float class } \ set-alien-float '[ _ declare 10 _ execute ] unit-test-builder
{ float class fixnum } \ set-alien-float '[ _ declare _ execute ] unit-test-builder
{ float class } \ set-alien-double '[ _ declare 10 _ execute ] unit-test-cfg
{ float class fixnum } \ set-alien-double '[ _ declare _ execute ] unit-test-cfg
{ float class } \ set-alien-double '[ _ declare 10 _ execute ] unit-test-builder
{ float class fixnum } \ set-alien-double '[ _ declare _ execute ] unit-test-builder
{ pinned-c-ptr class } \ set-alien-cell '[ _ declare 10 _ execute ] unit-test-cfg
{ pinned-c-ptr class fixnum } \ set-alien-cell '[ _ declare _ execute ] unit-test-cfg
{ pinned-c-ptr class } \ set-alien-cell '[ _ declare 10 _ execute ] unit-test-builder
{ pinned-c-ptr class fixnum } \ set-alien-cell '[ _ declare _ execute ] unit-test-builder
] each
: count-insns ( quot insn-check -- ? )
[ test-mr [ instructions>> ] map ] dip
'[ _ count ] map-sum ; inline
[ test-regs [ post-order [ instructions>> ] map concat ] map concat ] dip
count ; inline
: contains-insn? ( quot insn-check -- ? )
count-insns 0 > ; inline
@ -172,17 +174,29 @@ IN: compiler.cfg.builder.tests
[ t ] [
[ { fixnum byte-array fixnum } declare set-alien-unsigned-1 ]
[ ##set-alien-integer-1? ] contains-insn?
[ [ ##store-memory? ] [ ##store-memory-imm? ] bi or ] contains-insn?
] unit-test
[ t ] [
[ { fixnum byte-array fixnum } declare [ dup * dup * ] 2dip set-alien-unsigned-1 ]
[ ##set-alien-integer-1? ] contains-insn?
[ [ ##store-memory? ] [ ##store-memory-imm? ] bi or ] contains-insn?
] unit-test
[ f ] [
[ { byte-array fixnum } declare set-alien-unsigned-1 ]
[ ##set-alien-integer-1? ] contains-insn?
[ [ ##store-memory? ] [ ##store-memory-imm? ] bi or ] contains-insn?
] unit-test
[ t t ] [
[ { byte-array fixnum } declare alien-cell ]
[ [ [ ##load-memory? ] [ ##load-memory-imm? ] bi or ] contains-insn? ]
[ [ ##box-alien? ] contains-insn? ]
bi
] unit-test
[ f ] [
[ { byte-array integer } declare alien-cell ]
[ [ ##load-memory? ] [ ##load-memory-imm? ] bi or ] contains-insn?
] unit-test
[ f ] [
@ -209,7 +223,7 @@ IN: compiler.cfg.builder.tests
[ [ ##allot? ] contains-insn? ] bi
] unit-test
[ 1 ] [ [ dup float+ ] [ ##alien-double? ] count-insns ] unit-test
[ 1 ] [ [ dup float+ ] [ ##load-memory-imm? ] count-insns ] unit-test
] when
! Regression. Make sure everything is inlined correctly

View File

@ -123,7 +123,7 @@ M: #recursive emit-node
and ;
: emit-trivial-if ( -- )
ds-pop \ f type-number cc/= ^^compare-imm ds-push ;
[ f cc/= ^^compare-imm ] unary-op ;
: trivial-not-if? ( #if -- ? )
children>> first2
@ -132,12 +132,12 @@ M: #recursive emit-node
and ;
: emit-trivial-not-if ( -- )
ds-pop \ f type-number cc= ^^compare-imm ds-push ;
[ f cc= ^^compare-imm ] unary-op ;
: emit-actual-if ( #if -- )
! Inputs to the final instruction need to be copied because of
! loc>vreg sync
ds-pop any-rep ^^copy \ f type-number cc/= ##compare-imm-branch emit-if ;
ds-pop any-rep ^^copy f cc/= ##compare-imm-branch emit-if ;
M: #if emit-node
{

View File

@ -1,4 +1,4 @@
! Copyright (C) 2008, 2009 Slava Pestov.
! Copyright (C) 2008, 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel math vectors arrays accessors namespaces ;
IN: compiler.cfg
@ -8,7 +8,8 @@ TUPLE: basic-block < identity-tuple
number
{ instructions vector }
{ successors vector }
{ predecessors vector } ;
{ predecessors vector }
{ unlikely? boolean } ;
: <basic-block> ( -- bb )
basic-block new
@ -20,7 +21,8 @@ number
M: basic-block hashcode* nip id>> ;
TUPLE: cfg { entry basic-block } word label
spill-area-size reps
spill-area-size
stack-frame
post-order linear-order
predecessors-valid? dominance-valid? loops-valid? ;
@ -41,11 +43,3 @@ predecessors-valid? dominance-valid? loops-valid? ;
: with-cfg ( ..a cfg quot: ( ..a cfg -- ..b ) -- ..b )
[ dup cfg ] dip with-variable ; inline
TUPLE: mr { instructions array } word label ;
: <mr> ( instructions word label -- mr )
mr new
swap >>label
swap >>word
swap >>instructions ;

View File

@ -3,7 +3,8 @@
USING: kernel combinators.short-circuit accessors math sequences
sets assocs compiler.cfg.instructions compiler.cfg.rpo
compiler.cfg.def-use compiler.cfg.linearization
compiler.cfg.utilities compiler.cfg.mr compiler.utilities ;
compiler.cfg.utilities compiler.cfg.finalization
compiler.utilities ;
IN: compiler.cfg.checker
! Check invariants
@ -25,13 +26,7 @@ ERROR: last-insn-not-a-jump bb ;
dup instructions>> last {
[ ##branch? ]
[ ##dispatch? ]
[ ##compare-branch? ]
[ ##compare-imm-branch? ]
[ ##compare-float-ordered-branch? ]
[ ##compare-float-unordered-branch? ]
[ ##fixnum-add? ]
[ ##fixnum-sub? ]
[ ##fixnum-mul? ]
[ conditional-branch-insn? ]
[ ##no-tco? ]
} 1|| [ drop ] [ last-insn-not-a-jump ] if ;
@ -57,18 +52,5 @@ ERROR: bad-successors ;
[ check-successors ]
bi ;
ERROR: bad-live-in ;
ERROR: undefined-values uses defs ;
: check-mr ( mr -- )
! Check that every used register has a definition
instructions>>
[ [ uses-vregs ] map concat ]
[ [ [ temp-vregs ] [ defs-vreg ] bi [ suffix ] when* ] map concat ] bi
2dup subset? [ 2drop ] [ undefined-values ] if ;
: check-cfg ( cfg -- )
[ [ check-basic-block ] each-basic-block ]
[ build-mr check-mr ]
bi ;
[ check-basic-block ] each-basic-block ;

View File

@ -1,4 +1,4 @@
! Copyright (C) 2009 Slava Pestov.
! Copyright (C) 2009, 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: assocs math.order sequences ;
IN: compiler.cfg.comparisons
@ -12,6 +12,8 @@ SYMBOLS:
SYMBOLS:
vcc-all vcc-notall vcc-any vcc-none ;
SYMBOLS: cc-o cc/o ;
: negate-cc ( cc -- cc' )
H{
{ cc< cc/< }
@ -28,6 +30,8 @@ SYMBOLS:
{ cc/= cc= }
{ cc/<> cc<> }
{ cc/<>= cc<>= }
{ cc-o cc/o }
{ cc/o cc-o }
} at ;
: negate-vcc ( cc -- cc' )

View File

@ -0,0 +1,107 @@
USING: compiler.cfg.copy-prop tools.test namespaces kernel
compiler.cfg.debugger compiler.cfg accessors
compiler.cfg.registers compiler.cfg.instructions
cpu.architecture ;
IN: compiler.cfg.copy-prop.tests
: test-copy-propagation ( -- )
cfg new 0 get >>entry copy-propagation drop ;
! Simple example
V{
T{ ##prologue }
T{ ##branch }
} 0 test-bb
V{
T{ ##peek f 0 D 0 }
T{ ##branch }
} 1 test-bb
V{
T{ ##peek f 1 D 1 }
T{ ##branch }
} 2 test-bb
V{
T{ ##copy f 2 0 any-rep }
T{ ##branch }
} 3 test-bb
V{
T{ ##phi f 3 H{ { 2 0 } { 3 2 } } }
T{ ##phi f 4 H{ { 2 1 } { 3 2 } } }
T{ ##phi f 5 H{ { 2 1 } { 3 0 } } }
T{ ##branch }
} 4 test-bb
V{
T{ ##copy f 6 4 any-rep }
T{ ##replace f 3 D 0 }
T{ ##replace f 5 D 1 }
T{ ##replace f 6 D 2 }
T{ ##branch }
} 5 test-bb
V{
T{ ##epilogue }
T{ ##return }
} 6 test-bb
0 1 edge
1 { 2 3 } edges
2 4 edge
3 4 edge
4 5 edge
[ ] [ test-copy-propagation ] unit-test
[
V{
T{ ##replace f 0 D 0 }
T{ ##replace f 4 D 1 }
T{ ##replace f 4 D 2 }
T{ ##branch }
}
] [ 5 get instructions>> ] unit-test
! Test optimistic assumption
V{
T{ ##prologue }
T{ ##branch }
} 0 test-bb
V{
T{ ##peek f 0 D 0 }
T{ ##branch }
} 1 test-bb
V{
T{ ##phi f 1 H{ { 1 0 } { 2 2 } } }
T{ ##copy f 2 1 any-rep }
T{ ##branch }
} 2 test-bb
V{
T{ ##replace f 2 D 1 }
T{ ##branch }
} 3 test-bb
V{
T{ ##epilogue }
T{ ##return }
} 4 test-bb
0 1 edge
1 2 edge
2 { 2 3 } edges
3 4 edge
[ ] [ test-copy-propagation ] unit-test
[
V{
T{ ##replace f 0 D 1 }
T{ ##branch }
}
] [ 3 get instructions>> ] unit-test

View File

@ -1,78 +1,90 @@
! Copyright (C) 2008, 2009 Slava Pestov.
! Copyright (C) 2008, 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel namespaces assocs accessors sequences grouping
combinators compiler.cfg.rpo compiler.cfg.renaming
compiler.cfg.instructions compiler.cfg.predecessors ;
USING: sets kernel namespaces assocs accessors sequences grouping
combinators fry compiler.cfg.def-use compiler.cfg.rpo
compiler.cfg.renaming compiler.cfg.instructions
compiler.cfg.predecessors ;
FROM: namespaces => set ;
IN: compiler.cfg.copy-prop
! The first three definitions are also used in compiler.cfg.alias-analysis.
SYMBOL: copies
! Initialized per-basic-block; a mapping from inputs to dst for eliminating
! redundant phi instructions
SYMBOL: phis
: resolve ( vreg -- vreg )
copies get ?at drop ;
: (record-copy) ( dst src -- )
swap copies get set-at ; inline
: record-copy ( ##copy -- )
[ dst>> ] [ src>> resolve ] bi (record-copy) ; inline
<PRIVATE
SYMBOL: changed?
SYMBOL: copies
! Initialized per-basic-block; a mapping from inputs to dst for
! eliminating redundant ##phi instructions
SYMBOL: phis
: resolve ( vreg -- vreg )
copies get at ;
: record-copy ( dst src -- )
swap copies get maybe-set-at [ changed? on ] when ; inline
GENERIC: visit-insn ( insn -- )
M: ##copy visit-insn record-copy ;
M: ##copy visit-insn
[ dst>> ] [ src>> resolve ] bi
dup [ record-copy ] [ 2drop ] if ;
: useless-phi ( dst inputs -- ) first (record-copy) ;
: useless-phi ( dst inputs -- ) first record-copy ;
: redundant-phi ( dst inputs -- ) phis get at (record-copy) ;
: redundant-phi ( dst inputs -- ) phis get at record-copy ;
: record-phi ( dst inputs -- ) phis get set-at ;
: record-phi ( dst inputs -- )
[ phis get set-at ] [ drop dup record-copy ] 2bi ;
M: ##phi visit-insn
[ dst>> ] [ inputs>> values [ resolve ] map ] bi
{
{ [ dup all-equal? ] [ useless-phi ] }
{ [ dup phis get key? ] [ redundant-phi ] }
[ record-phi ]
} cond ;
dup phis get key? [ redundant-phi ] [
dup sift
dup all-equal?
[ nip useless-phi ]
[ drop record-phi ] if
] if ;
M: vreg-insn visit-insn
defs-vreg [ dup record-copy ] when* ;
M: insn visit-insn drop ;
: collect-copies ( cfg -- )
H{ } clone copies set
: (collect-copies) ( cfg -- )
[
H{ } clone phis set
phis get clear-assoc
instructions>> [ visit-insn ] each
] each-basic-block ;
: collect-copies ( cfg -- )
H{ } clone copies set
H{ } clone phis set
'[
changed? off
_ (collect-copies)
changed? get
] loop ;
GENERIC: update-insn ( insn -- keep? )
M: ##copy update-insn drop f ;
M: ##phi update-insn
dup dst>> copies get key? [ drop f ] [ call-next-method ] if ;
dup call-next-method drop
[ dst>> ] [ inputs>> values ] bi [ = not ] with any? ;
M: insn update-insn rename-insn-uses t ;
M: vreg-insn update-insn rename-insn-uses t ;
M: insn update-insn drop t ;
: rename-copies ( cfg -- )
copies get dup assoc-empty? [ 2drop ] [
renamings set
[
instructions>> [ update-insn ] filter! drop
] each-basic-block
] if ;
copies get renamings set
[ [ update-insn ] filter! ] simple-optimization ;
PRIVATE>
: copy-propagation ( cfg -- cfg' )
needs-predecessors
[ collect-copies ]
[ rename-copies ]
[ ]
tri ;
dup collect-copies
dup rename-copies ;

View File

@ -11,41 +11,41 @@ IN: compiler.cfg.dce.tests
entry>> instructions>> ;
[ V{
T{ ##load-immediate { dst 1 } { val 8 } }
T{ ##load-immediate { dst 2 } { val 16 } }
T{ ##load-integer { dst 1 } { val 8 } }
T{ ##load-integer { dst 2 } { val 16 } }
T{ ##add { dst 3 } { src1 1 } { src2 2 } }
T{ ##replace { src 3 } { loc D 0 } }
} ] [ V{
T{ ##load-immediate { dst 1 } { val 8 } }
T{ ##load-immediate { dst 2 } { val 16 } }
T{ ##load-integer { dst 1 } { val 8 } }
T{ ##load-integer { dst 2 } { val 16 } }
T{ ##add { dst 3 } { src1 1 } { src2 2 } }
T{ ##replace { src 3 } { loc D 0 } }
} test-dce ] unit-test
[ V{ } ] [ V{
T{ ##load-immediate { dst 1 } { val 8 } }
T{ ##load-immediate { dst 2 } { val 16 } }
T{ ##load-integer { dst 1 } { val 8 } }
T{ ##load-integer { dst 2 } { val 16 } }
T{ ##add { dst 3 } { src1 1 } { src2 2 } }
} test-dce ] unit-test
[ V{ } ] [ V{
T{ ##load-immediate { dst 3 } { val 8 } }
T{ ##load-integer { dst 3 } { val 8 } }
T{ ##allot { dst 1 } { temp 2 } }
} test-dce ] unit-test
[ V{ } ] [ V{
T{ ##load-immediate { dst 3 } { val 8 } }
T{ ##load-integer { dst 3 } { val 8 } }
T{ ##allot { dst 1 } { temp 2 } }
T{ ##set-slot-imm { obj 1 } { src 3 } }
} test-dce ] unit-test
[ V{
T{ ##load-immediate { dst 3 } { val 8 } }
T{ ##load-integer { dst 3 } { val 8 } }
T{ ##allot { dst 1 } { temp 2 } }
T{ ##set-slot-imm { obj 1 } { src 3 } }
T{ ##replace { src 1 } { loc D 0 } }
} ] [ V{
T{ ##load-immediate { dst 3 } { val 8 } }
T{ ##load-integer { dst 3 } { val 8 } }
T{ ##allot { dst 1 } { temp 2 } }
T{ ##set-slot-imm { obj 1 } { src 3 } }
T{ ##replace { src 1 } { loc D 0 } }
@ -62,11 +62,11 @@ IN: compiler.cfg.dce.tests
[ V{
T{ ##allot { dst 1 } { temp 2 } }
T{ ##replace { src 1 } { loc D 0 } }
T{ ##load-immediate { dst 3 } { val 8 } }
T{ ##load-integer { dst 3 } { val 8 } }
T{ ##set-slot-imm { obj 1 } { src 3 } }
} ] [ V{
T{ ##allot { dst 1 } { temp 2 } }
T{ ##replace { src 1 } { loc D 0 } }
T{ ##load-immediate { dst 3 } { val 8 } }
T{ ##load-integer { dst 3 } { val 8 } }
T{ ##set-slot-imm { obj 1 } { src 3 } }
} test-dce ] unit-test

View File

@ -1,4 +1,4 @@
! Copyright (C) 2008, 2009 Slava Pestov.
! Copyright (C) 2008, 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel words sequences quotations namespaces io vectors
arrays hashtables classes.tuple accessors prettyprint
@ -7,45 +7,87 @@ prettyprint.sections parser compiler.tree.builder
compiler.tree.optimizer cpu.architecture compiler.cfg.builder
compiler.cfg.linearization compiler.cfg.registers
compiler.cfg.stack-frame compiler.cfg.linear-scan
compiler.cfg.optimizer compiler.cfg.instructions
compiler.cfg.utilities compiler.cfg.def-use compiler.cfg.rpo
compiler.cfg.mr compiler.cfg.representations.preferred
compiler.cfg ;
compiler.cfg.optimizer compiler.cfg.finalization
compiler.cfg.instructions compiler.cfg.utilities
compiler.cfg.def-use compiler.cfg.rpo
compiler.cfg.representations compiler.cfg.gc-checks
compiler.cfg.save-contexts compiler.cfg
compiler.cfg.representations.preferred ;
FROM: compiler.cfg.linearization => number-blocks ;
IN: compiler.cfg.debugger
GENERIC: test-cfg ( quot -- cfgs )
GENERIC: test-builder ( quot -- cfgs )
M: callable test-cfg
M: callable test-builder
0 vreg-counter set-global
build-tree optimize-tree gensym build-cfg ;
M: word test-cfg
M: word test-builder
0 vreg-counter set-global
[ build-tree optimize-tree ] keep build-cfg ;
: test-mr ( quot -- mrs )
test-cfg [
: test-optimizer ( quot -- cfgs )
test-builder [ [ optimize-cfg ] with-cfg ] map ;
: test-ssa ( quot -- cfgs )
test-builder [
[
optimize-cfg
build-mr
] with-cfg
] map ;
: insn. ( insn -- )
tuple>array but-last [ pprint bl ] each nl ;
: test-flat ( quot -- cfgs )
test-builder [
[
optimize-cfg
select-representations
insert-gc-checks
insert-save-contexts
] with-cfg
] map ;
: mr. ( mrs -- )
: test-regs ( quot -- cfgs )
test-builder [
[
optimize-cfg
finalize-cfg
] with-cfg
] map ;
GENERIC: insn. ( insn -- )
M: ##phi insn.
clone [ [ [ number>> ] dip ] assoc-map ] change-inputs
call-next-method ;
M: insn insn. tuple>array but-last [ bl ] [ pprint ] interleave nl ;
: block. ( bb -- )
"=== Basic block #" write dup block-number . nl
dup instructions>> [ insn. ] each nl
successors>> [
"Successors: " write
[ block-number unparse ] map ", " join print nl
] unless-empty ;
: cfg. ( cfg -- )
[
dup linearization-order number-blocks
"=== word: " write
dup word>> pprint
", label: " write
dup label>> pprint nl nl
instructions>> [ insn. ] each
nl
] each ;
dup linearization-order [ block. ] each
"=== stack frame: " write
stack-frame>> .
] with-scope ;
: test-mr. ( quot -- )
test-mr mr. ; inline
: cfgs. ( cfgs -- )
[ nl ] [ cfg. ] interleave ;
: ssa. ( quot -- ) test-ssa cfgs. ;
: flat. ( quot -- ) test-flat cfgs. ;
: regs. ( quot -- ) test-regs cfgs. ;
! Prettyprinting
: pprint-loc ( loc word -- ) <block pprint-word n>> pprint* block> ;

View File

@ -1,4 +1,4 @@
! Copyright (C) 2008, 2009 Slava Pestov, Daniel Ehrenberg.
! Copyright (C) 2008, 2010 Slava Pestov, Daniel Ehrenberg.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors assocs arrays classes combinators
compiler.units fry generalizations generic kernel locals

View File

@ -0,0 +1 @@
Slava Pestov

View File

@ -0,0 +1,16 @@
! Copyright (C) 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: compiler.cfg.empty-blocks compiler.cfg.gc-checks
compiler.cfg.representations compiler.cfg.save-contexts
compiler.cfg.ssa.destruction compiler.cfg.build-stack-frame
compiler.cfg.linear-scan compiler.cfg.scheduling ;
IN: compiler.cfg.finalization
: finalize-cfg ( cfg -- cfg' )
select-representations
schedule-instructions
insert-gc-checks
insert-save-contexts
destruct-ssa
linear-scan
build-stack-frame ;

View File

@ -1,14 +1,14 @@
USING: compiler.cfg.gc-checks compiler.cfg.debugger
USING: arrays compiler.cfg.gc-checks
compiler.cfg.gc-checks.private compiler.cfg.debugger
compiler.cfg.registers compiler.cfg.instructions compiler.cfg
compiler.cfg.predecessors cpu.architecture tools.test kernel vectors
namespaces accessors sequences ;
compiler.cfg.predecessors compiler.cfg.rpo cpu.architecture
tools.test kernel vectors namespaces accessors sequences alien
memory classes make combinators.short-circuit byte-arrays ;
IN: compiler.cfg.gc-checks.tests
: test-gc-checks ( -- )
H{ } clone representations set
cfg new 0 get >>entry
insert-gc-checks
drop ;
cfg new 0 get >>entry cfg set ;
V{
T{ ##inc-d f 3 }
@ -23,4 +23,184 @@ V{
[ ] [ test-gc-checks ] unit-test
[ V{ D 0 D 2 } ] [ 1 get instructions>> first uninitialized-locs>> ] unit-test
[ t ] [ cfg get blocks-with-gc 1 get 1array sequence= ] unit-test
[ ] [ 1 get allocation-size 123 <alien> size assert= ] unit-test
2 \ vreg-counter set-global
[
V{
T{ ##load-tagged f 3 0 }
T{ ##replace f 3 D 0 }
T{ ##replace f 3 R 3 }
}
] [ [ { D 0 R 3 } wipe-locs ] V{ } make ] unit-test
: gc-check? ( bb -- ? )
instructions>>
{
[ length 1 = ]
[ first ##check-nursery-branch? ]
} 1&& ;
[ t ] [ V{ } 100 <gc-check> gc-check? ] unit-test
4 \ vreg-counter set-global
[
V{
T{ ##load-tagged f 5 0 }
T{ ##replace f 5 D 0 }
T{ ##replace f 5 R 3 }
T{ ##call-gc f { 0 1 2 } }
T{ ##branch }
}
]
[
{ D 0 R 3 } { 0 1 2 } <gc-call> instructions>>
] unit-test
30 \ vreg-counter set-global
V{
T{ ##branch }
} 0 test-bb
V{
T{ ##branch }
} 1 test-bb
V{
T{ ##branch }
} 2 test-bb
V{
T{ ##branch }
} 3 test-bb
V{
T{ ##branch }
} 4 test-bb
0 { 1 2 } edges
1 3 edge
2 3 edge
3 4 edge
[ ] [ test-gc-checks ] unit-test
[ ] [ cfg get needs-predecessors drop ] unit-test
[ ] [ { D 1 R 2 } { 10 20 } V{ } 31337 3 get (insert-gc-check) ] unit-test
[ t ] [ 1 get successors>> first gc-check? ] unit-test
[ t ] [ 2 get successors>> first gc-check? ] unit-test
[ t ] [ 3 get predecessors>> first gc-check? ] unit-test
30 \ vreg-counter set-global
V{
T{ ##prologue }
T{ ##branch }
} 0 test-bb
V{
T{ ##peek f 2 D 0 }
T{ ##inc-d f 3 }
T{ ##branch }
} 1 test-bb
V{
T{ ##allot f 1 64 byte-array }
T{ ##branch }
} 2 test-bb
V{
T{ ##branch }
} 3 test-bb
V{
T{ ##replace f 2 D 1 }
T{ ##branch }
} 4 test-bb
V{
T{ ##epilogue }
T{ ##return }
} 5 test-bb
0 1 edge
1 { 2 3 } edges
2 4 edge
3 4 edge
4 5 edge
[ ] [ test-gc-checks ] unit-test
H{
{ 2 tagged-rep }
} representations set
[ ] [ cfg get insert-gc-checks drop ] unit-test
[ 2 ] [ 2 get predecessors>> length ] unit-test
[ t ] [ 1 get successors>> first gc-check? ] unit-test
[ 64 ] [ 1 get successors>> first instructions>> first size>> ] unit-test
[ t ] [ 2 get predecessors>> first gc-check? ] unit-test
[
V{
T{ ##load-tagged f 31 0 }
T{ ##replace f 31 D 0 }
T{ ##replace f 31 D 1 }
T{ ##replace f 31 D 2 }
T{ ##call-gc f { 2 } }
T{ ##branch }
}
] [ 2 get predecessors>> second instructions>> ] unit-test
! Don't forget to invalidate RPO after inserting basic blocks!
[ 8 ] [ cfg get reverse-post-order length ] unit-test
! Do the right thing with ##phi instructions
V{
T{ ##branch }
} 0 test-bb
V{
T{ ##load-reference f 1 "hi" }
T{ ##branch }
} 1 test-bb
V{
T{ ##load-reference f 2 "bye" }
T{ ##branch }
} 2 test-bb
V{
T{ ##phi f 3 H{ { 1 1 } { 2 2 } } }
T{ ##allot f 1 64 byte-array }
T{ ##branch }
} 3 test-bb
0 { 1 2 } edges
1 3 edge
2 3 edge
[ ] [ test-gc-checks ] unit-test
H{
{ 1 tagged-rep }
{ 2 tagged-rep }
{ 3 tagged-rep }
} representations set
[ ] [ cfg get insert-gc-checks drop ] unit-test
[ t ] [ 2 get successors>> first instructions>> first ##phi? ] unit-test
[ 2 ] [ 3 get instructions>> length ] unit-test

View File

@ -1,15 +1,25 @@
! Copyright (C) 2009 Slava Pestov.
! Copyright (C) 2009, 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors kernel sequences assocs fry math
cpu.architecture layouts namespaces
USING: accessors assocs combinators fry kernel layouts locals
math make namespaces sequences cpu.architecture
compiler.cfg
compiler.cfg.rpo
compiler.cfg.hats
compiler.cfg.registers
compiler.cfg.utilities
compiler.cfg.comparisons
compiler.cfg.instructions
compiler.cfg.predecessors
compiler.cfg.liveness
compiler.cfg.liveness.ssa
compiler.cfg.stacks.uninitialized ;
IN: compiler.cfg.gc-checks
! Garbage collection check insertion. This pass runs after representation
! selection, so it must keep track of representations.
<PRIVATE
! Garbage collection check insertion. This pass runs after
! representation selection, since it needs to know which vregs
! can contain tagged pointers.
: insert-gc-check? ( bb -- ? )
instructions>> [ ##allocation? ] any? ;
@ -17,6 +27,54 @@ IN: compiler.cfg.gc-checks
: blocks-with-gc ( cfg -- bbs )
post-order [ insert-gc-check? ] filter ;
! A GC check for bb consists of two new basic blocks, gc-check
! and gc-call:
!
! gc-check
! / \
! | gc-call
! \ /
! bb
! Any ##phi instructions at the start of bb are transplanted
! into the gc-check block.
: <gc-check> ( phis size -- bb )
[ <basic-block> ] 2dip
[
[ % ]
[
cc<= int-rep next-vreg-rep int-rep next-vreg-rep
##check-nursery-branch
] bi*
] V{ } make >>instructions ;
: wipe-locs ( uninitialized-locs -- )
'[
int-rep next-vreg-rep
[ 0 ##load-tagged ]
[ '[ [ _ ] dip ##replace ] each ] bi
] unless-empty ;
: <gc-call> ( uninitialized-locs gc-roots -- bb )
[ <basic-block> ] 2dip
[ [ wipe-locs ] [ ##call-gc ] bi* ##branch ] V{ } make
>>instructions t >>unlikely? ;
:: insert-guard ( body check bb -- )
bb predecessors>> check (>>predecessors)
V{ bb body } check (>>successors)
V{ check } body (>>predecessors)
V{ bb } body (>>successors)
V{ check body } bb (>>predecessors)
check predecessors>> [ bb check update-successors ] each ;
: (insert-gc-check) ( uninitialized-locs gc-roots phis size bb -- )
[ [ <gc-call> ] 2dip <gc-check> ] dip insert-guard ;
GENERIC: allocation-size* ( insn -- n )
M: ##allot allocation-size* size>> ;
@ -30,20 +88,35 @@ M: ##box-displaced-alien allocation-size* drop 5 cells ;
[ ##allocation? ] filter
[ allocation-size* data-alignment get align ] map-sum ;
: gc-live-in ( bb -- vregs )
[ live-in keys ] [ instructions>> [ ##phi? ] filter [ dst>> ] map ] bi
append ;
: live-tagged ( bb -- vregs )
gc-live-in [ rep-of tagged-rep? ] filter ;
: remove-phis ( bb -- phis )
[ [ ##phi? ] partition ] change-instructions drop ;
: insert-gc-check ( bb -- )
dup dup '[
int-rep next-vreg-rep
int-rep next-vreg-rep
_ allocation-size
f
f
_ uninitialized-locs
\ ##gc new-insn
prefix
] change-instructions drop ;
{
[ uninitialized-locs ]
[ live-tagged ]
[ remove-phis ]
[ allocation-size ]
[ ]
} cleave
(insert-gc-check) ;
PRIVATE>
: insert-gc-checks ( cfg -- cfg' )
dup blocks-with-gc [
over compute-uninitialized-sets
[
needs-predecessors
dup compute-ssa-live-sets
dup compute-uninitialized-sets
] dip
[ insert-gc-check ] each
cfg-changed
] unless-empty ;

View File

@ -1,8 +1,9 @@
! Copyright (C) 2008, 2009 Slava Pestov.
! Copyright (C) 2008, 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays byte-arrays kernel layouts math
namespaces sequences combinators splitting parser effects
words cpu.architecture compiler.cfg.registers
USING: accessors alien arrays byte-arrays classes.algebra
combinators.short-circuit kernel layouts math namespaces
sequences combinators splitting parser effects words
cpu.architecture compiler.constants compiler.cfg.registers
compiler.cfg.instructions compiler.cfg.instructions.syntax ;
IN: compiler.cfg.hats
@ -42,18 +43,21 @@ insn-classes get [
>>
: ^^load-literal ( obj -- dst )
[ next-vreg dup ] dip {
{ [ dup not ] [ drop \ f type-number ##load-immediate ] }
{ [ dup fixnum? ] [ tag-fixnum ##load-immediate ] }
{ [ dup float? ] [ ##load-constant ] }
[ ##load-reference ]
} cond ;
dup fixnum? [ ^^load-integer ] [ ^^load-reference ] if ;
: ^^offset>slot ( slot -- vreg' )
cell 4 = 2 1 ? ^^shr-imm ;
cell 4 = 2 3 ? ^^shl-imm ;
: ^^tag-fixnum ( src -- dst )
tag-bits get ^^shl-imm ;
: ^^unbox-f ( src -- dst )
drop 0 ^^load-literal ;
: ^^untag-fixnum ( src -- dst )
tag-bits get ^^sar-imm ;
: ^^unbox-byte-array ( src -- dst )
^^tagged>integer byte-array-offset ^^add-imm ;
: ^^unbox-c-ptr ( src class -- dst )
{
{ [ dup \ f class<= ] [ drop ^^unbox-f ] }
{ [ dup alien class<= ] [ drop ^^unbox-alien ] }
{ [ dup byte-array class<= ] [ drop ^^unbox-byte-array ] }
[ drop ^^unbox-any-c-ptr ]
} cond ;

View File

@ -1,9 +1,9 @@
! Copyright (C) 2008, 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: assocs accessors arrays kernel sequences namespaces words
math math.order layouts classes.algebra classes.union
compiler.units alien byte-arrays compiler.constants combinators
compiler.cfg.registers compiler.cfg.instructions.syntax ;
math math.order layouts classes.union compiler.units alien
byte-arrays combinators compiler.cfg.registers
compiler.cfg.instructions.syntax ;
IN: compiler.cfg.instructions
<<
@ -20,27 +20,40 @@ TUPLE: insn ;
! value numbering
TUPLE: pure-insn < insn ;
! Stack operations
INSN: ##load-immediate
! Constants
INSN: ##load-integer
def: dst/int-rep
constant: val ;
literal: val ;
INSN: ##load-reference
def: dst/int-rep
constant: obj ;
def: dst/tagged-rep
literal: obj ;
INSN: ##load-constant
def: dst/int-rep
constant: obj ;
! These three are inserted by representation selection
INSN: ##load-tagged
def: dst/tagged-rep
literal: val ;
INSN: ##load-double
def: dst/double-rep
literal: val ;
INSN: ##load-vector
def: dst
literal: val rep ;
! Stack operations
INSN: ##peek
def: dst/int-rep
def: dst/tagged-rep
literal: loc ;
INSN: ##replace
use: src/int-rep
use: src/tagged-rep
literal: loc ;
INSN: ##replace-imm
literal: src loc ;
INSN: ##inc-d
literal: n ;
@ -54,6 +67,10 @@ literal: word ;
INSN: ##jump
literal: word ;
INSN: ##prologue ;
INSN: ##epilogue ;
INSN: ##return ;
! Dummy instruction that simply inhibits TCO
@ -66,36 +83,33 @@ temp: temp/int-rep ;
! Slot access
INSN: ##slot
def: dst/int-rep
use: obj/int-rep slot/int-rep ;
def: dst/tagged-rep
use: obj/tagged-rep slot/int-rep
literal: scale tag ;
INSN: ##slot-imm
def: dst/int-rep
use: obj/int-rep
def: dst/tagged-rep
use: obj/tagged-rep
literal: slot tag ;
INSN: ##set-slot
use: src/int-rep obj/int-rep slot/int-rep ;
use: src/tagged-rep obj/tagged-rep slot/int-rep
literal: scale tag ;
INSN: ##set-slot-imm
use: src/int-rep obj/int-rep
use: src/tagged-rep obj/tagged-rep
literal: slot tag ;
! String element access
INSN: ##string-nth
def: dst/int-rep
use: obj/int-rep index/int-rep
temp: temp/int-rep ;
INSN: ##set-string-nth-fast
use: src/int-rep obj/int-rep index/int-rep
temp: temp/int-rep ;
PURE-INSN: ##copy
! Register transfers
INSN: ##copy
def: dst
use: src
literal: rep ;
PURE-INSN: ##tagged>integer
def: dst/int-rep
use: src/tagged-rep ;
! Integer arithmetic
PURE-INSN: ##add
def: dst/int-rep
@ -104,7 +118,7 @@ use: src1/int-rep src2/int-rep ;
PURE-INSN: ##add-imm
def: dst/int-rep
use: src1/int-rep
constant: src2 ;
literal: src2 ;
PURE-INSN: ##sub
def: dst/int-rep
@ -113,7 +127,7 @@ use: src1/int-rep src2/int-rep ;
PURE-INSN: ##sub-imm
def: dst/int-rep
use: src1/int-rep
constant: src2 ;
literal: src2 ;
PURE-INSN: ##mul
def: dst/int-rep
@ -122,7 +136,7 @@ use: src1/int-rep src2/int-rep ;
PURE-INSN: ##mul-imm
def: dst/int-rep
use: src1/int-rep
constant: src2 ;
literal: src2 ;
PURE-INSN: ##and
def: dst/int-rep
@ -131,7 +145,7 @@ use: src1/int-rep src2/int-rep ;
PURE-INSN: ##and-imm
def: dst/int-rep
use: src1/int-rep
constant: src2 ;
literal: src2 ;
PURE-INSN: ##or
def: dst/int-rep
@ -140,7 +154,7 @@ use: src1/int-rep src2/int-rep ;
PURE-INSN: ##or-imm
def: dst/int-rep
use: src1/int-rep
constant: src2 ;
literal: src2 ;
PURE-INSN: ##xor
def: dst/int-rep
@ -149,7 +163,7 @@ use: src1/int-rep src2/int-rep ;
PURE-INSN: ##xor-imm
def: dst/int-rep
use: src1/int-rep
constant: src2 ;
literal: src2 ;
PURE-INSN: ##shl
def: dst/int-rep
@ -158,7 +172,7 @@ use: src1/int-rep src2/int-rep ;
PURE-INSN: ##shl-imm
def: dst/int-rep
use: src1/int-rep
constant: src2 ;
literal: src2 ;
PURE-INSN: ##shr
def: dst/int-rep
@ -167,7 +181,7 @@ use: src1/int-rep src2/int-rep ;
PURE-INSN: ##shr-imm
def: dst/int-rep
use: src1/int-rep
constant: src2 ;
literal: src2 ;
PURE-INSN: ##sar
def: dst/int-rep
@ -176,7 +190,7 @@ use: src1/int-rep src2/int-rep ;
PURE-INSN: ##sar-imm
def: dst/int-rep
use: src1/int-rep
constant: src2 ;
literal: src2 ;
PURE-INSN: ##min
def: dst/int-rep
@ -336,7 +350,7 @@ use: src1 src2
literal: rep cc ;
PURE-INSN: ##test-vector
def: dst/int-rep
def: dst/tagged-rep
use: src1
temp: temp/int-rep
literal: rep vcc ;
@ -525,135 +539,57 @@ literal: rep ;
! Boxing and unboxing aliens
PURE-INSN: ##box-alien
def: dst/int-rep
def: dst/tagged-rep
use: src/int-rep
temp: temp/int-rep ;
PURE-INSN: ##box-displaced-alien
def: dst/int-rep
use: displacement/int-rep base/int-rep
def: dst/tagged-rep
use: displacement/int-rep base/tagged-rep
temp: temp/int-rep
literal: base-class ;
PURE-INSN: ##unbox-any-c-ptr
def: dst/int-rep
use: src/int-rep ;
: ##unbox-f ( dst src -- ) drop 0 ##load-immediate ;
: ##unbox-byte-array ( dst src -- ) byte-array-offset ##add-imm ;
use: src/tagged-rep ;
PURE-INSN: ##unbox-alien
def: dst/int-rep
use: src/int-rep ;
use: src/tagged-rep ;
: ##unbox-c-ptr ( dst src class -- )
{
{ [ dup \ f class<= ] [ drop ##unbox-f ] }
{ [ dup alien class<= ] [ drop ##unbox-alien ] }
{ [ dup byte-array class<= ] [ drop ##unbox-byte-array ] }
[ drop ##unbox-any-c-ptr ]
} cond ;
! Alien accessors
INSN: ##alien-unsigned-1
def: dst/int-rep
use: src/int-rep
literal: offset ;
INSN: ##alien-unsigned-2
def: dst/int-rep
use: src/int-rep
literal: offset ;
INSN: ##alien-unsigned-4
def: dst/int-rep
use: src/int-rep
literal: offset ;
INSN: ##alien-signed-1
def: dst/int-rep
use: src/int-rep
literal: offset ;
INSN: ##alien-signed-2
def: dst/int-rep
use: src/int-rep
literal: offset ;
INSN: ##alien-signed-4
def: dst/int-rep
use: src/int-rep
literal: offset ;
INSN: ##alien-cell
def: dst/int-rep
use: src/int-rep
literal: offset ;
INSN: ##alien-float
def: dst/float-rep
use: src/int-rep
literal: offset ;
INSN: ##alien-double
def: dst/double-rep
use: src/int-rep
literal: offset ;
INSN: ##alien-vector
! Raw memory accessors
INSN: ##load-memory
def: dst
use: src/int-rep
literal: offset rep ;
use: base/int-rep displacement/int-rep
literal: scale offset rep c-type ;
INSN: ##set-alien-integer-1
use: src/int-rep
literal: offset
use: value/int-rep ;
INSN: ##load-memory-imm
def: dst
use: base/int-rep
literal: offset rep c-type ;
INSN: ##set-alien-integer-2
use: src/int-rep
literal: offset
use: value/int-rep ;
INSN: ##store-memory
use: src base/int-rep displacement/int-rep
literal: scale offset rep c-type ;
INSN: ##set-alien-integer-4
use: src/int-rep
literal: offset
use: value/int-rep ;
INSN: ##set-alien-cell
use: src/int-rep
literal: offset
use: value/int-rep ;
INSN: ##set-alien-float
use: src/int-rep
literal: offset
use: value/float-rep ;
INSN: ##set-alien-double
use: src/int-rep
literal: offset
use: value/double-rep ;
INSN: ##set-alien-vector
use: src/int-rep
literal: offset
use: value
literal: rep ;
INSN: ##store-memory-imm
use: src base/int-rep
literal: offset rep c-type ;
! Memory allocation
INSN: ##allot
def: dst/int-rep
def: dst/tagged-rep
literal: size class
temp: temp/int-rep ;
INSN: ##write-barrier
use: src/int-rep slot/int-rep
use: src/tagged-rep slot/int-rep
literal: scale tag
temp: temp1/int-rep temp2/int-rep ;
INSN: ##write-barrier-imm
use: src/int-rep
literal: slot
use: src/tagged-rep
literal: slot tag
temp: temp1/int-rep temp2/int-rep ;
INSN: ##alien-global
@ -661,11 +597,11 @@ def: dst/int-rep
literal: symbol library ;
INSN: ##vm-field
def: dst/int-rep
def: dst/tagged-rep
literal: offset ;
INSN: ##set-vm-field
use: src/int-rep
use: src/tagged-rep
literal: offset ;
! FFI
@ -681,39 +617,56 @@ literal: params stack-frame ;
INSN: ##alien-callback
literal: params stack-frame ;
! Instructions used by CFG IR only.
INSN: ##prologue ;
INSN: ##epilogue ;
INSN: ##branch ;
! Control flow
INSN: ##phi
def: dst
literal: inputs ;
! Conditionals
INSN: ##branch ;
! Tagged conditionals
INSN: ##compare-branch
use: src1/int-rep src2/int-rep
use: src1/tagged-rep src2/tagged-rep
literal: cc ;
INSN: ##compare-imm-branch
use: src1/int-rep
constant: src2
literal: cc ;
use: src1/tagged-rep
literal: src2 cc ;
PURE-INSN: ##compare
def: dst/int-rep
use: src1/int-rep src2/int-rep
def: dst/tagged-rep
use: src1/tagged-rep src2/tagged-rep
literal: cc
temp: temp/int-rep ;
PURE-INSN: ##compare-imm
def: dst/int-rep
def: dst/tagged-rep
use: src1/tagged-rep
literal: src2 cc
temp: temp/int-rep ;
! Integer conditionals
INSN: ##compare-integer-branch
use: src1/int-rep src2/int-rep
literal: cc ;
INSN: ##compare-integer-imm-branch
use: src1/int-rep
constant: src2
literal: src2 cc ;
PURE-INSN: ##compare-integer
def: dst/tagged-rep
use: src1/int-rep src2/int-rep
literal: cc
temp: temp/int-rep ;
PURE-INSN: ##compare-integer-imm
def: dst/tagged-rep
use: src1/int-rep
literal: src2 cc
temp: temp/int-rep ;
! Float conditionals
INSN: ##compare-float-ordered-branch
use: src1/double-rep src2/double-rep
literal: cc ;
@ -723,123 +676,81 @@ use: src1/double-rep src2/double-rep
literal: cc ;
PURE-INSN: ##compare-float-ordered
def: dst/int-rep
def: dst/tagged-rep
use: src1/double-rep src2/double-rep
literal: cc
temp: temp/int-rep ;
PURE-INSN: ##compare-float-unordered
def: dst/int-rep
def: dst/tagged-rep
use: src1/double-rep src2/double-rep
literal: cc
temp: temp/int-rep ;
! Overflowing arithmetic
INSN: ##fixnum-add
def: dst/int-rep
use: src1/int-rep src2/int-rep ;
def: dst/tagged-rep
use: src1/tagged-rep src2/tagged-rep
literal: cc ;
INSN: ##fixnum-sub
def: dst/int-rep
use: src1/int-rep src2/int-rep ;
def: dst/tagged-rep
use: src1/tagged-rep src2/tagged-rep
literal: cc ;
INSN: ##fixnum-mul
def: dst/int-rep
use: src1/int-rep src2/int-rep ;
INSN: ##gc
temp: temp1/int-rep temp2/int-rep
literal: size data-values tagged-values uninitialized-locs ;
def: dst/tagged-rep
use: src1/tagged-rep src2/int-rep
literal: cc ;
INSN: ##save-context
temp: temp1/int-rep temp2/int-rep ;
! Instructions used by machine IR only.
INSN: _prologue
literal: stack-frame ;
! GC checks
INSN: ##check-nursery-branch
literal: size cc
temp: temp1/int-rep temp2/int-rep ;
INSN: _epilogue
literal: stack-frame ;
INSN: _label
literal: label ;
INSN: _branch
literal: label ;
INSN: _loop-entry ;
INSN: _dispatch
use: src/int-rep
temp: temp ;
INSN: _dispatch-label
literal: label ;
INSN: _compare-branch
literal: label
use: src1/int-rep src2/int-rep
literal: cc ;
INSN: _compare-imm-branch
literal: label
use: src1/int-rep
constant: src2
literal: cc ;
INSN: _compare-float-unordered-branch
literal: label
use: src1/int-rep src2/int-rep
literal: cc ;
INSN: _compare-float-ordered-branch
literal: label
use: src1/int-rep src2/int-rep
literal: cc ;
! Overflowing arithmetic
INSN: _fixnum-add
literal: label
def: dst/int-rep
use: src1/int-rep src2/int-rep ;
INSN: _fixnum-sub
literal: label
def: dst/int-rep
use: src1/int-rep src2/int-rep ;
INSN: _fixnum-mul
literal: label
def: dst/int-rep
use: src1/int-rep src2/int-rep ;
INSN: ##call-gc
literal: gc-roots ;
! Spills and reloads, inserted by register allocator
TUPLE: spill-slot { n integer } ;
C: <spill-slot> spill-slot
! These instructions operate on machine registers and not
! virtual registers
INSN: _spill
INSN: ##spill
use: src
literal: rep dst ;
INSN: _reload
INSN: ##reload
def: dst
literal: rep src ;
INSN: _spill-area-size
literal: n ;
UNION: ##allocation
##allot
##box-alien
##box-displaced-alien ;
UNION: conditional-branch-insn
##compare-branch
##compare-imm-branch
##compare-integer-branch
##compare-integer-imm-branch
##compare-float-ordered-branch
##compare-float-unordered-branch
##test-vector-branch
##check-nursery-branch
##fixnum-add
##fixnum-sub
##fixnum-mul ;
! For alias analysis
UNION: ##read ##slot ##slot-imm ##vm-field ##alien-global ;
UNION: ##write ##set-slot ##set-slot-imm ##set-vm-field ;
! Instructions that kill all live vregs but cannot trigger GC
UNION: partial-sync-insn
! Instructions that clobber registers
UNION: clobber-insn
##call-gc
##unary-float-function
##binary-float-function ;
@ -857,7 +768,6 @@ UNION: kill-vreg-insn
UNION: def-is-use-insn
##box-alien
##box-displaced-alien
##string-nth
##unbox-any-c-ptr ;
SYMBOL: vreg-insn

View File

@ -5,7 +5,7 @@ make fry sequences parser accessors effects namespaces
combinators splitting classes.parser lexer quotations ;
IN: compiler.cfg.instructions.syntax
SYMBOLS: def use temp literal constant ;
SYMBOLS: def use temp literal ;
SYMBOL: scalar-rep
@ -31,23 +31,22 @@ TUPLE: insn-slot-spec type name rep ;
{ "use:" [ drop use ] }
{ "temp:" [ drop temp ] }
{ "literal:" [ drop literal ] }
{ "constant:" [ drop constant ] }
[ dupd parse-insn-slot-spec , ]
} case
] reduce drop
] { } make ;
: insn-def-slot ( class -- slot/f )
"insn-slots" word-prop
: find-def-slot ( slots -- slot/f )
[ type>> def eq? ] find nip ;
: insn-def-slot ( class -- slot/f )
"insn-slots" word-prop find-def-slot ;
: insn-use-slots ( class -- slots )
"insn-slots" word-prop
[ type>> use eq? ] filter ;
"insn-slots" word-prop [ type>> use eq? ] filter ;
: insn-temp-slots ( class -- slots )
"insn-slots" word-prop
[ type>> temp eq? ] filter ;
"insn-slots" word-prop [ type>> temp eq? ] filter ;
! We cannot reference words in compiler.cfg.instructions directly
! since that would create circularity.

View File

@ -1,4 +1,4 @@
! Copyright (C) 2008, 2009 Slava Pestov.
! Copyright (C) 2008, 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors kernel sequences alien math classes.algebra fry
locals combinators combinators.short-circuit cpu.architecture
@ -16,104 +16,72 @@ IN: compiler.cfg.intrinsics.alien
: emit-<displaced-alien> ( node -- )
dup emit-<displaced-alien>? [
[ 2inputs [ ^^untag-fixnum ] dip ] dip
node-input-infos second class>>
^^box-displaced-alien ds-push
'[
_ node-input-infos second class>>
^^box-displaced-alien
] binary-op
] [ emit-primitive ] if ;
:: inline-alien ( node quot test -- )
:: inline-accessor ( node quot test -- )
node node-input-infos :> infos
infos test call
[ infos quot call ]
[ node emit-primitive ] if ; inline
: inline-alien-getter? ( infos -- ? )
: inline-load-memory? ( infos -- ? )
[ first class>> c-ptr class<= ]
[ second class>> fixnum class<= ]
bi and ;
: ^^unbox-c-ptr ( src class -- dst )
[ next-vreg dup ] 2dip ##unbox-c-ptr ;
: prepare-accessor ( base offset info -- base offset )
class>> swap [ ^^unbox-c-ptr ] dip ^^add 0 ;
: prepare-alien-accessor ( info -- ptr-vreg offset )
class>> [ 2inputs ^^untag-fixnum swap ] dip ^^unbox-c-ptr ^^add 0 ;
: prepare-load-memory ( infos -- base offset )
[ 2inputs ] dip first prepare-accessor ;
: prepare-alien-getter ( infos -- ptr-vreg offset )
first prepare-alien-accessor ;
: (emit-load-memory) ( node rep c-type quot -- )
'[ prepare-load-memory _ _ ^^load-memory-imm @ ds-push ]
[ inline-load-memory? ]
inline-accessor ; inline
: inline-alien-getter ( node quot -- )
'[ prepare-alien-getter @ ds-push ]
[ inline-alien-getter? ] inline-alien ; inline
: emit-load-memory ( node rep c-type -- )
[ ] (emit-load-memory) ;
: inline-alien-setter? ( infos class -- ? )
: emit-alien-cell ( node -- )
int-rep f [ ^^box-alien ] (emit-load-memory) ;
: inline-store-memory? ( infos class -- ? )
'[ first class>> _ class<= ]
[ second class>> c-ptr class<= ]
[ third class>> fixnum class<= ]
tri and and ;
: prepare-alien-setter ( infos -- ptr-vreg offset )
second prepare-alien-accessor ;
: prepare-store-memory ( infos -- value base offset )
[ 3inputs ] dip second prepare-accessor ;
: inline-alien-integer-setter ( node quot -- )
'[ prepare-alien-setter ds-pop ^^untag-fixnum @ ]
[ fixnum inline-alien-setter? ]
inline-alien ; inline
:: (emit-store-memory) ( node rep c-type prepare-quot test-quot -- )
node
[ prepare-quot call rep c-type ##store-memory-imm ]
[ test-quot call inline-store-memory? ]
inline-accessor ; inline
: inline-alien-cell-setter ( node quot -- )
'[ [ prepare-alien-setter ds-pop ] [ first class>> ] bi ^^unbox-c-ptr @ ]
[ pinned-c-ptr inline-alien-setter? ]
inline-alien ; inline
: inline-alien-float-setter ( node quot -- )
'[ prepare-alien-setter ds-pop @ ]
[ float inline-alien-setter? ]
inline-alien ; inline
: emit-alien-unsigned-getter ( node n -- )
'[
_ {
{ 1 [ ^^alien-unsigned-1 ] }
{ 2 [ ^^alien-unsigned-2 ] }
{ 4 [ ^^alien-unsigned-4 ] }
} case ^^tag-fixnum
] inline-alien-getter ;
: emit-alien-signed-getter ( node n -- )
'[
_ {
{ 1 [ ^^alien-signed-1 ] }
{ 2 [ ^^alien-signed-2 ] }
{ 4 [ ^^alien-signed-4 ] }
} case ^^tag-fixnum
] inline-alien-getter ;
: emit-alien-integer-setter ( node n -- )
'[
_ {
{ 1 [ ##set-alien-integer-1 ] }
{ 2 [ ##set-alien-integer-2 ] }
{ 4 [ ##set-alien-integer-4 ] }
:: emit-store-memory ( node rep c-type -- )
node rep c-type
[ prepare-store-memory ]
[
rep {
{ int-rep [ fixnum ] }
{ float-rep [ float ] }
{ double-rep [ float ] }
} case
] inline-alien-integer-setter ;
]
(emit-store-memory) ;
: emit-alien-cell-getter ( node -- )
[ ^^alien-cell ^^box-alien ] inline-alien-getter ;
: emit-alien-cell-setter ( node -- )
[ ##set-alien-cell ] inline-alien-cell-setter ;
: emit-alien-float-getter ( node rep -- )
'[
_ {
{ float-rep [ ^^alien-float ] }
{ double-rep [ ^^alien-double ] }
} case
] inline-alien-getter ;
: emit-alien-float-setter ( node rep -- )
'[
_ {
{ float-rep [ ##set-alien-float ] }
{ double-rep [ ##set-alien-double ] }
} case
] inline-alien-float-setter ;
: emit-set-alien-cell ( node -- )
int-rep f
[
[ first class>> ] [ prepare-store-memory ] bi
[ swap ^^unbox-c-ptr ] 2dip
]
[ pinned-c-ptr ]
(emit-store-memory) ;

View File

@ -1,9 +1,10 @@
! Copyright (C) 2008, 2009 Slava Pestov, Doug Coleman.
! Copyright (C) 2008, 2010 Slava Pestov, Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: sequences accessors layouts kernel math math.intervals
namespaces combinators fry arrays
cpu.architecture
compiler.tree.propagation.info
compiler.cfg
compiler.cfg.hats
compiler.cfg.stacks
compiler.cfg.instructions
@ -14,26 +15,24 @@ compiler.cfg.comparisons ;
IN: compiler.cfg.intrinsics.fixnum
: emit-both-fixnums? ( -- )
2inputs
^^or
tag-mask get ^^and-imm
0 cc= ^^compare-imm
ds-push ;
: tag-literal ( n -- tagged )
literal>> [ tag-fixnum ] [ \ f type-number ] if* ;
: emit-fixnum-op ( insn -- )
[ 2inputs ] dip call ds-push ; inline
[
[ ^^tagged>integer ] bi@
^^or tag-mask get ^^and-imm
0 cc= ^^compare-integer-imm
] binary-op ;
: emit-fixnum-left-shift ( -- )
[ ^^untag-fixnum ^^shl ] emit-fixnum-op ;
[ ^^shl ] binary-op ;
: emit-fixnum-right-shift ( -- )
[ ^^untag-fixnum ^^neg ^^sar dup tag-mask get ^^and-imm ^^xor ] emit-fixnum-op ;
[
[ tag-bits get ^^shl-imm ] dip
^^neg ^^sar
tag-bits get ^^sar-imm
] binary-op ;
: emit-fixnum-shift-general ( -- )
ds-peek 0 cc> ##compare-imm-branch
ds-peek 0 cc> ##compare-integer-imm-branch
[ emit-fixnum-left-shift ] with-branch
[ emit-fixnum-right-shift ] with-branch
2array emit-conditional ;
@ -44,18 +43,9 @@ IN: compiler.cfg.intrinsics.fixnum
{ [ dup 0 [-inf,a] interval-subset? ] [ drop emit-fixnum-right-shift ] }
[ drop emit-fixnum-shift-general ]
} cond ;
: emit-fixnum-bitnot ( -- )
ds-pop ^^not tag-mask get ^^xor-imm ds-push ;
: emit-fixnum-log2 ( -- )
ds-pop ^^log2 tag-bits get ^^sub-imm ^^tag-fixnum ds-push ;
: emit-fixnum*fast ( -- )
2inputs ^^untag-fixnum ^^mul ds-push ;
: emit-fixnum-comparison ( cc -- )
'[ _ ^^compare ] emit-fixnum-op ;
'[ _ ^^compare-integer ] binary-op ;
: emit-no-overflow-case ( dst -- final-bb )
[ ds-drop ds-drop ds-push ] with-branch ;
@ -66,7 +56,7 @@ IN: compiler.cfg.intrinsics.fixnum
: emit-fixnum-overflow-op ( quot word -- )
! Inputs to the final instruction need to be copied because
! of loc>vreg sync
[ [ (2inputs) [ any-rep ^^copy ] bi@ ] dip call ] dip
[ [ (2inputs) [ any-rep ^^copy ] bi@ cc/o ] dip call ] dip
[ emit-no-overflow-case ] [ emit-overflow-case ] bi* 2array
emit-conditional ; inline
@ -83,4 +73,4 @@ IN: compiler.cfg.intrinsics.fixnum
[ ^^fixnum-sub ] \ fixnum-overflow emit-fixnum-overflow-op ;
: emit-fixnum* ( -- )
[ ^^untag-fixnum ^^fixnum-mul ] \ fixnum*overflow emit-fixnum-overflow-op ;
[ ^^fixnum-mul ] \ fixnum*overflow emit-fixnum-overflow-op ;

View File

@ -1,29 +1,17 @@
! Copyright (C) 2008, 2009 Slava Pestov.
! Copyright (C) 2008, 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel compiler.cfg.stacks compiler.cfg.hats
USING: fry kernel compiler.cfg.stacks compiler.cfg.hats
compiler.cfg.instructions compiler.cfg.utilities ;
IN: compiler.cfg.intrinsics.float
: emit-float-op ( insn -- )
[ 2inputs ] dip call ds-push ; inline
: emit-float-ordered-comparison ( cc -- )
[ 2inputs ] dip ^^compare-float-ordered ds-push ; inline
'[ _ ^^compare-float-ordered ] binary-op ; inline
: emit-float-unordered-comparison ( cc -- )
[ 2inputs ] dip ^^compare-float-unordered ds-push ; inline
: emit-float>fixnum ( -- )
ds-pop ^^float>integer ^^tag-fixnum ds-push ;
: emit-fixnum>float ( -- )
ds-pop ^^untag-fixnum ^^integer>float ds-push ;
: emit-fsqrt ( -- )
ds-pop ^^sqrt ds-push ;
'[ _ ^^compare-float-unordered ] binary-op ; inline
: emit-unary-float-function ( func -- )
[ ds-pop ] dip ^^unary-float-function ds-push ;
'[ _ ^^unary-float-function ] unary-op ;
: emit-binary-float-function ( func -- )
[ 2inputs ] dip ^^binary-float-function ds-push ;
'[ _ ^^binary-float-function ] binary-op ;

View File

@ -1,17 +1,20 @@
! Copyright (C) 2008, 2009 Slava Pestov, Doug Coleman.
! Copyright (C) 2008, 2010 Slava Pestov, Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: words sequences kernel combinators cpu.architecture assocs
compiler.cfg.hats
compiler.cfg.stacks
compiler.cfg.instructions
compiler.cfg.intrinsics.alien
compiler.cfg.intrinsics.allot
compiler.cfg.intrinsics.fixnum
compiler.cfg.intrinsics.float
compiler.cfg.intrinsics.slots
compiler.cfg.intrinsics.strings
compiler.cfg.intrinsics.misc
compiler.cfg.comparisons ;
QUALIFIED: alien
QUALIFIED: alien.accessors
QUALIFIED: alien.c-types
QUALIFIED: kernel
QUALIFIED: arrays
QUALIFIED: byte-arrays
@ -38,22 +41,22 @@ IN: compiler.cfg.intrinsics
{ 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*fast [ drop emit-fixnum*fast ] }
{ 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+fast [ drop [ ^^add ] binary-op ] }
{ math.private:fixnum-fast [ drop [ ^^sub ] binary-op ] }
{ math.private:fixnum*fast [ drop [ ^^mul ] binary-op ] }
{ math.private:fixnum-bitand [ drop [ ^^and ] binary-op ] }
{ math.private:fixnum-bitor [ drop [ ^^or ] binary-op ] }
{ math.private:fixnum-bitxor [ drop [ ^^xor ] binary-op ] }
{ math.private:fixnum-shift-fast [ emit-fixnum-shift-fast ] }
{ math.private:fixnum-bitnot [ drop emit-fixnum-bitnot ] }
{ math.private:fixnum-bitnot [ drop [ ^^not ] unary-op ] }
{ 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 ] }
{ kernel:eq? [ emit-eq ] }
{ slots.private:slot [ emit-slot ] }
{ slots.private:set-slot [ emit-set-slot ] }
{ strings.private:string-nth [ drop emit-string-nth ] }
{ strings.private:string-nth-fast [ drop emit-string-nth-fast ] }
{ strings.private:set-string-nth-fast [ drop emit-set-string-nth-fast ] }
{ classes.tuple.private:<tuple-boa> [ emit-<tuple-boa> ] }
{ arrays:<array> [ emit-<array> ] }
@ -61,32 +64,32 @@ IN: compiler.cfg.intrinsics
{ byte-arrays:(byte-array) [ emit-(byte-array) ] }
{ kernel:<wrapper> [ emit-simple-allot ] }
{ alien:<displaced-alien> [ emit-<displaced-alien> ] }
{ alien.accessors:alien-unsigned-1 [ 1 emit-alien-unsigned-getter ] }
{ alien.accessors:set-alien-unsigned-1 [ 1 emit-alien-integer-setter ] }
{ alien.accessors:alien-signed-1 [ 1 emit-alien-signed-getter ] }
{ alien.accessors:set-alien-signed-1 [ 1 emit-alien-integer-setter ] }
{ alien.accessors:alien-unsigned-2 [ 2 emit-alien-unsigned-getter ] }
{ alien.accessors:set-alien-unsigned-2 [ 2 emit-alien-integer-setter ] }
{ alien.accessors:alien-signed-2 [ 2 emit-alien-signed-getter ] }
{ alien.accessors:set-alien-signed-2 [ 2 emit-alien-integer-setter ] }
{ alien.accessors:alien-cell [ emit-alien-cell-getter ] }
{ alien.accessors:set-alien-cell [ emit-alien-cell-setter ] }
{ alien.accessors:alien-unsigned-1 [ int-rep alien.c-types:uchar emit-load-memory ] }
{ alien.accessors:set-alien-unsigned-1 [ int-rep alien.c-types:uchar emit-store-memory ] }
{ alien.accessors:alien-signed-1 [ int-rep alien.c-types:char emit-load-memory ] }
{ alien.accessors:set-alien-signed-1 [ int-rep alien.c-types:char emit-store-memory ] }
{ alien.accessors:alien-unsigned-2 [ int-rep alien.c-types:ushort emit-load-memory ] }
{ alien.accessors:set-alien-unsigned-2 [ int-rep alien.c-types:ushort emit-store-memory ] }
{ alien.accessors:alien-signed-2 [ int-rep alien.c-types:short emit-load-memory ] }
{ alien.accessors:set-alien-signed-2 [ int-rep alien.c-types:short emit-store-memory ] }
{ alien.accessors:alien-cell [ emit-alien-cell ] }
{ alien.accessors:set-alien-cell [ emit-set-alien-cell ] }
} enable-intrinsics
: enable-alien-4-intrinsics ( -- )
{
{ alien.accessors:alien-unsigned-4 [ 4 emit-alien-unsigned-getter ] }
{ alien.accessors:set-alien-unsigned-4 [ 4 emit-alien-integer-setter ] }
{ alien.accessors:alien-signed-4 [ 4 emit-alien-signed-getter ] }
{ alien.accessors:set-alien-signed-4 [ 4 emit-alien-integer-setter ] }
{ alien.accessors:alien-signed-4 [ int-rep alien.c-types:int emit-load-memory ] }
{ alien.accessors:set-alien-signed-4 [ int-rep alien.c-types:int emit-store-memory ] }
{ alien.accessors:alien-unsigned-4 [ int-rep alien.c-types:uint emit-load-memory ] }
{ alien.accessors:set-alien-unsigned-4 [ int-rep alien.c-types:uint emit-store-memory ] }
} enable-intrinsics ;
: enable-float-intrinsics ( -- )
{
{ math.private:float+ [ drop [ ^^add-float ] emit-float-op ] }
{ math.private:float- [ drop [ ^^sub-float ] emit-float-op ] }
{ math.private:float* [ drop [ ^^mul-float ] emit-float-op ] }
{ math.private:float/f [ drop [ ^^div-float ] emit-float-op ] }
{ math.private:float+ [ drop [ ^^add-float ] binary-op ] }
{ math.private:float- [ drop [ ^^sub-float ] binary-op ] }
{ math.private:float* [ drop [ ^^mul-float ] binary-op ] }
{ math.private:float/f [ drop [ ^^div-float ] binary-op ] }
{ math.private:float< [ drop cc< emit-float-ordered-comparison ] }
{ math.private:float<= [ drop cc<= emit-float-ordered-comparison ] }
{ math.private:float>= [ drop cc>= emit-float-ordered-comparison ] }
@ -96,24 +99,24 @@ IN: compiler.cfg.intrinsics
{ math.private:float-u>= [ drop cc>= emit-float-unordered-comparison ] }
{ math.private:float-u> [ drop cc> emit-float-unordered-comparison ] }
{ math.private:float= [ drop cc= emit-float-unordered-comparison ] }
{ math.private:float>fixnum [ drop emit-float>fixnum ] }
{ math.private:fixnum>float [ drop emit-fixnum>float ] }
{ math.private:float>fixnum [ drop [ ^^float>integer ] unary-op ] }
{ math.private:fixnum>float [ drop [ ^^integer>float ] unary-op ] }
{ math.floats.private:float-unordered? [ drop cc/<>= emit-float-unordered-comparison ] }
{ alien.accessors:alien-float [ float-rep emit-alien-float-getter ] }
{ alien.accessors:set-alien-float [ float-rep emit-alien-float-setter ] }
{ alien.accessors:alien-double [ double-rep emit-alien-float-getter ] }
{ alien.accessors:set-alien-double [ double-rep emit-alien-float-setter ] }
{ alien.accessors:alien-float [ float-rep f emit-load-memory ] }
{ alien.accessors:set-alien-float [ float-rep f emit-store-memory ] }
{ alien.accessors:alien-double [ double-rep f emit-load-memory ] }
{ alien.accessors:set-alien-double [ double-rep f emit-store-memory ] }
} enable-intrinsics ;
: enable-fsqrt ( -- )
{
{ math.libm:fsqrt [ drop emit-fsqrt ] }
{ math.libm:fsqrt [ drop [ ^^sqrt ] unary-op ] }
} enable-intrinsics ;
: enable-float-min/max ( -- )
{
{ math.floats.private:float-min [ drop [ ^^min-float ] emit-float-op ] }
{ math.floats.private:float-max [ drop [ ^^max-float ] emit-float-op ] }
{ math.floats.private:float-min [ drop [ ^^min-float ] binary-op ] }
{ math.floats.private:float-max [ drop [ ^^max-float ] binary-op ] }
} enable-intrinsics ;
: enable-float-functions ( -- )
@ -143,13 +146,13 @@ IN: compiler.cfg.intrinsics
: enable-min/max ( -- )
{
{ math.integers.private:fixnum-min [ drop [ ^^min ] emit-fixnum-op ] }
{ math.integers.private:fixnum-max [ drop [ ^^max ] emit-fixnum-op ] }
{ math.integers.private:fixnum-min [ drop [ ^^min ] binary-op ] }
{ math.integers.private:fixnum-max [ drop [ ^^max ] binary-op ] }
} enable-intrinsics ;
: enable-fixnum-log2 ( -- )
: enable-log2 ( -- )
{
{ math.integers.private:fixnum-log2 [ drop emit-fixnum-log2 ] }
{ math.integers.private:fixnum-log2 [ drop [ ^^log2 ] unary-op ] }
} enable-intrinsics ;
: emit-intrinsic ( node word -- )

View File

@ -1,15 +1,24 @@
! Copyright (C) 2008, 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: namespaces layouts sequences kernel math accessors
compiler.tree.propagation.info compiler.cfg.stacks
compiler.cfg.hats compiler.cfg.instructions
USING: accessors classes.algebra layouts kernel math namespaces
sequences cpu.architecture
compiler.tree.propagation.info
compiler.cfg.stacks
compiler.cfg.hats
compiler.cfg.comparisons
compiler.cfg.instructions
compiler.cfg.builder.blocks
compiler.cfg.utilities ;
FROM: vm => context-field-offset vm-field-offset ;
QUALIFIED-WITH: alien.c-types c
IN: compiler.cfg.intrinsics.misc
: emit-tag ( -- )
ds-pop tag-mask get ^^and-imm ^^tag-fixnum ds-push ;
[ ^^tagged>integer tag-mask get ^^and-imm ] unary-op ;
: emit-eq ( node -- )
node-input-infos first2 [ class>> fixnum class<= ] both?
[ [ cc= ^^compare-integer ] binary-op ] [ [ cc= ^^compare ] binary-op ] if ;
: special-object-offset ( n -- offset )
cells "special-objects" vm-field-offset + ;
@ -37,7 +46,9 @@ IN: compiler.cfg.intrinsics.misc
] [ emit-primitive ] ?if ;
: emit-identity-hashcode ( -- )
ds-pop tag-mask get bitnot ^^load-immediate ^^and 0 0 ^^slot-imm
hashcode-shift ^^shr-imm
^^tag-fixnum
ds-push ;
[
^^tagged>integer
tag-mask get bitnot ^^load-integer ^^and
0 int-rep f ^^load-memory-imm
hashcode-shift ^^shr-imm
] unary-op ;

View File

@ -19,7 +19,7 @@ M: ##zero-vector insn-available? rep>> %zero-vector-reps member? ;
M: ##fill-vector insn-available? rep>> %fill-vector-reps member? ;
M: ##gather-vector-2 insn-available? rep>> %gather-vector-2-reps member? ;
M: ##gather-vector-4 insn-available? rep>> %gather-vector-4-reps member? ;
M: ##alien-vector insn-available? rep>> %alien-vector-reps member? ;
M: ##store-memory-imm insn-available? rep>> %alien-vector-reps member? ;
M: ##shuffle-vector insn-available? rep>> %shuffle-vector-reps member? ;
M: ##shuffle-vector-imm insn-available? rep>> %shuffle-vector-imm-reps member? ;
M: ##merge-vector-head insn-available? rep>> %merge-vector-reps member? ;

View File

@ -127,7 +127,7 @@ unit-test
unit-test
! vneg
[ { ##load-constant ##sub-vector } ]
[ { ##load-reference ##sub-vector } ]
[ simple-ops-cpu float-4-rep [ emit-simd-vneg ] test-emit ]
unit-test
@ -153,11 +153,11 @@ M: addsub-cpu %add-sub-vector-reps { int-4-rep float-4-rep } ;
[ addsub-cpu float-4-rep [ emit-simd-v+- ] test-emit ]
unit-test
[ { ##load-constant ##xor-vector ##add-vector } ]
[ { ##load-reference ##xor-vector ##add-vector } ]
[ simple-ops-cpu float-4-rep [ emit-simd-v+- ] test-emit ]
unit-test
[ { ##load-constant ##xor-vector ##sub-vector ##add-vector } ]
[ { ##load-reference ##xor-vector ##sub-vector ##add-vector } ]
[ simple-ops-cpu int-4-rep [ emit-simd-v+- ] test-emit ]
unit-test
@ -301,7 +301,7 @@ unit-test
[ abs-cpu float-4-rep [ emit-simd-vabs ] test-emit ]
unit-test
[ { ##load-constant ##andn-vector } ]
[ { ##load-reference ##andn-vector } ]
[ simple-ops-cpu float-4-rep [ emit-simd-vabs ] test-emit ]
unit-test
@ -388,7 +388,7 @@ TUPLE: shuffle-cpu < simple-ops-cpu ;
M: shuffle-cpu %shuffle-vector-reps signed-reps ;
! vshuffle-elements
[ { ##load-constant ##shuffle-vector } ]
[ { ##load-reference ##shuffle-vector } ]
[ shuffle-cpu { 0 1 2 3 } int-4-rep [ emit-simd-vshuffle-elements ] test-emit-literal ]
unit-test
@ -420,7 +420,7 @@ unit-test
[ minmax-cpu int-4-rep [ emit-simd-v<= ] test-emit ]
unit-test
[ { ##load-constant ##xor-vector ##xor-vector ##compare-vector } ]
[ { ##load-reference ##xor-vector ##xor-vector ##compare-vector } ]
[ compare-cpu uint-4-rep [ emit-simd-v<= ] test-emit ]
unit-test

View File

@ -43,24 +43,24 @@ IN: compiler.cfg.intrinsics.simd
: ^load-neg-zero-vector ( rep -- dst )
{
{ float-4-rep [ float-array{ -0.0 -0.0 -0.0 -0.0 } underlying>> ^^load-constant ] }
{ double-2-rep [ double-array{ -0.0 -0.0 } underlying>> ^^load-constant ] }
{ float-4-rep [ float-array{ -0.0 -0.0 -0.0 -0.0 } underlying>> ^^load-literal ] }
{ double-2-rep [ double-array{ -0.0 -0.0 } underlying>> ^^load-literal ] }
} case ;
: ^load-add-sub-vector ( rep -- dst )
signed-rep {
{ float-4-rep [ float-array{ -0.0 0.0 -0.0 0.0 } underlying>> ^^load-constant ] }
{ double-2-rep [ double-array{ -0.0 0.0 } underlying>> ^^load-constant ] }
{ char-16-rep [ char-array{ -1 0 -1 0 -1 0 -1 0 -1 0 -1 0 -1 0 -1 0 } underlying>> ^^load-constant ] }
{ short-8-rep [ short-array{ -1 0 -1 0 -1 0 -1 0 } underlying>> ^^load-constant ] }
{ int-4-rep [ int-array{ -1 0 -1 0 } underlying>> ^^load-constant ] }
{ longlong-2-rep [ longlong-array{ -1 0 } underlying>> ^^load-constant ] }
{ float-4-rep [ float-array{ -0.0 0.0 -0.0 0.0 } underlying>> ^^load-literal ] }
{ double-2-rep [ double-array{ -0.0 0.0 } underlying>> ^^load-literal ] }
{ char-16-rep [ char-array{ -1 0 -1 0 -1 0 -1 0 -1 0 -1 0 -1 0 -1 0 } underlying>> ^^load-literal ] }
{ short-8-rep [ short-array{ -1 0 -1 0 -1 0 -1 0 } underlying>> ^^load-literal ] }
{ int-4-rep [ int-array{ -1 0 -1 0 } underlying>> ^^load-literal ] }
{ longlong-2-rep [ longlong-array{ -1 0 } underlying>> ^^load-literal ] }
} case ;
: ^load-half-vector ( rep -- dst )
{
{ float-4-rep [ float-array{ 0.5 0.5 0.5 0.5 } underlying>> ^^load-constant ] }
{ double-2-rep [ double-array{ 0.5 0.5 } underlying>> ^^load-constant ] }
{ float-4-rep [ float-array{ 0.5 0.5 0.5 0.5 } underlying>> ^^load-literal ] }
{ double-2-rep [ double-array{ 0.5 0.5 } underlying>> ^^load-literal ] }
} case ;
: >variable-shuffle ( shuffle rep -- shuffle' )
@ -70,7 +70,7 @@ IN: compiler.cfg.intrinsics.simd
'[ _ n*v _ v+ ] map concat ;
: ^load-immediate-shuffle ( shuffle rep -- dst )
>variable-shuffle ^^load-constant ;
>variable-shuffle ^^load-literal ;
:: ^blend-vector ( mask true false rep -- dst )
true mask rep ^^and-vector
@ -118,7 +118,7 @@ IN: compiler.cfg.intrinsics.simd
[ ^(compare-vector) ]
[ ^minmax-compare-vector ]
{ unsigned-int-vector-rep [| src1 src2 rep cc |
rep sign-bit-mask ^^load-constant :> sign-bits
rep sign-bit-mask ^^load-literal :> sign-bits
src1 sign-bits rep ^^xor-vector
src2 sign-bits rep ^^xor-vector
rep signed-rep cc ^(compare-vector)
@ -587,20 +587,20 @@ PREDICATE: fixnum-vector-rep < int-vector-rep
: emit-alien-vector ( node -- )
dup [
'[
ds-drop prepare-alien-getter
_ ^^alien-vector ds-push
ds-drop prepare-load-memory
_ f ^^load-memory-imm ds-push
]
[ inline-alien-getter? ] inline-alien
[ inline-load-memory? ] inline-accessor
] with { [ %alien-vector-reps member? ] } if-literals-match ;
: emit-set-alien-vector ( node -- )
dup [
'[
ds-drop prepare-alien-setter ds-pop
_ ##set-alien-vector
ds-drop prepare-store-memory
_ f ##store-memory-imm
]
[ byte-array inline-alien-setter? ]
inline-alien
[ byte-array inline-store-memory? ]
inline-accessor
] with { [ %alien-vector-reps member? ] } if-literals-match ;
: enable-simd ( -- )

View File

@ -1,9 +1,10 @@
! Copyright (C) 2008, 2009 Slava Pestov.
! Copyright (C) 2008, 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: layouts namespaces kernel accessors sequences math
classes.algebra classes.builtin locals combinators
cpu.architecture compiler.tree.propagation.info
compiler.cfg.stacks compiler.cfg.hats compiler.cfg.registers
combinators.short-circuit cpu.architecture
compiler.tree.propagation.info compiler.cfg.stacks
compiler.cfg.hats compiler.cfg.registers
compiler.cfg.instructions compiler.cfg.utilities
compiler.cfg.builder.blocks compiler.constants ;
IN: compiler.cfg.intrinsics.slots
@ -13,12 +14,13 @@ IN: compiler.cfg.intrinsics.slots
: value-tag ( info -- n ) class>> class-tag ;
: ^^tag-offset>slot ( slot tag -- vreg' )
[ ^^offset>slot ] dip ^^sub-imm ;
: slot-indexing ( slot tag -- slot scale tag )
complex-addressing?
[ [ cell log2 ] dip ] [ [ ^^offset>slot ] dip ^^sub-imm 0 0 ] if ;
: (emit-slot) ( infos -- dst )
[ 2inputs ] [ first value-tag ] bi*
^^tag-offset>slot ^^slot ;
slot-indexing ^^slot ;
: (emit-slot-imm) ( infos -- dst )
ds-drop
@ -28,9 +30,9 @@ IN: compiler.cfg.intrinsics.slots
: immediate-slot-offset? ( value-info -- ? )
literal>> {
{ [ dup fixnum? ] [ tag-fixnum immediate-arithmetic? ] }
[ drop f ]
} cond ;
[ fixnum? ]
[ cell * immediate-arithmetic? ]
} 1&& ;
: emit-slot ( node -- )
dup node-input-infos
@ -47,12 +49,13 @@ IN: compiler.cfg.intrinsics.slots
:: (emit-set-slot) ( infos -- )
3inputs :> ( src obj slot )
slot infos second value-tag ^^tag-offset>slot :> slot
infos second value-tag :> tag
src obj slot ##set-slot
slot tag slot-indexing :> ( slot scale tag )
src obj slot scale tag ##set-slot
infos emit-write-barrier?
[ obj slot next-vreg next-vreg ##write-barrier ] when ;
[ obj slot scale tag next-vreg next-vreg ##write-barrier ] when ;
:: (emit-set-slot-imm) ( infos -- )
ds-drop
@ -65,7 +68,7 @@ IN: compiler.cfg.intrinsics.slots
src obj slot tag ##set-slot-imm
infos emit-write-barrier?
[ obj slot tag slot-offset next-vreg next-vreg ##write-barrier-imm ] when ;
[ obj slot tag next-vreg next-vreg ##write-barrier-imm ] when ;
: emit-set-slot ( node -- )
dup node-input-infos
@ -74,10 +77,3 @@ IN: compiler.cfg.intrinsics.slots
dup third immediate-slot-offset?
[ (emit-set-slot-imm) ] [ (emit-set-slot) ] if
] [ drop emit-primitive ] if ;
: emit-string-nth ( -- )
2inputs swap ^^untag-fixnum ^^string-nth ^^tag-fixnum ds-push ;
: emit-set-string-nth-fast ( -- )
3inputs [ ^^untag-fixnum ] [ ^^untag-fixnum ] [ ] tri*
swap next-vreg ##set-string-nth-fast ;

View File

@ -0,0 +1 @@
Slava Pestov

View File

@ -0,0 +1,15 @@
! Copyright (C) 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: alien.c-types kernel compiler.constants compiler.cfg.hats
compiler.cfg.instructions compiler.cfg.registers
compiler.cfg.stacks cpu.architecture ;
IN: compiler.cfg.intrinsics.strings
: (string-nth) ( n string -- base offset rep c-type )
^^tagged>integer swap ^^add string-offset int-rep uchar ; inline
: emit-string-nth-fast ( -- )
2inputs (string-nth) ^^load-memory-imm ds-push ;
: emit-set-string-nth-fast ( -- )
3inputs (string-nth) ##store-memory-imm ;

View File

@ -1,4 +1,4 @@
! Copyright (C) 2008, 2009 Slava Pestov.
! Copyright (C) 2008, 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors assocs heaps kernel namespaces sequences fry math
math.order combinators arrays sorting compiler.utilities locals
@ -9,11 +9,11 @@ compiler.cfg.linear-scan.allocation.state ;
IN: compiler.cfg.linear-scan.allocation
: active-positions ( new assoc -- )
[ vreg>> active-intervals-for ] dip
[ active-intervals-for ] dip
'[ [ 0 ] dip reg>> _ add-use-position ] each ;
: inactive-positions ( new assoc -- )
[ [ vreg>> inactive-intervals-for ] keep ] dip
[ [ inactive-intervals-for ] keep ] dip
'[
[ _ relevant-ranges intersect-live-ranges 1/0. or ] [ reg>> ] bi
_ add-use-position
@ -38,7 +38,8 @@ IN: compiler.cfg.linear-scan.allocation
! If the live interval has a usage at 'n', don't spill it,
! since this means its being defined by the sync point
! instruction. Output t if this is the case.
2dup [ uses>> ] dip swap member? [ 2drop t ] [ spill f ] if ;
2dup [ uses>> ] dip '[ n>> _ = ] any?
[ 2drop t ] [ spill f ] if ;
: handle-sync-point ( n -- )
[ active-intervals get values ] dip
@ -62,18 +63,19 @@ M: sync-point handle ( sync-point -- )
: smallest-heap ( heap1 heap2 -- heap )
! If heap1 and heap2 have the same key, favors heap1.
[ [ heap-peek nip ] bi@ <= ] most ;
{
{ [ dup heap-empty? ] [ drop ] }
{ [ over heap-empty? ] [ nip ] }
[ [ [ heap-peek nip ] bi@ <= ] most ]
} cond ;
: (allocate-registers) ( -- )
{
{ [ unhandled-intervals get heap-empty? ] [ unhandled-sync-points get ] }
{ [ unhandled-sync-points get heap-empty? ] [ unhandled-intervals get ] }
! If a live interval begins at the same location as a sync point,
! process the sync point before the live interval. This ensures that the
! return value of C function calls doesn't get spilled and reloaded
! unnecessarily.
[ unhandled-sync-points get unhandled-intervals get smallest-heap ]
} cond dup heap-empty? [ drop ] [ heap-pop drop handle (allocate-registers) ] if ;
! If a live interval begins at the same location as a sync point,
! process the sync point before the live interval. This ensures that the
! return value of C function calls doesn't get spilled and reloaded
! unnecessarily.
unhandled-sync-points get unhandled-intervals get smallest-heap
dup heap-empty? [ drop ] [ heap-pop drop handle (allocate-registers) ] if ;
: finish-allocation ( -- )
active-intervals inactive-intervals

View File

@ -1,4 +1,4 @@
! Copyright (C) 2009 Slava Pestov.
! Copyright (C) 2009, 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays assocs combinators fry hints kernel locals
math sequences sets sorting splitting namespaces linked-assocs
@ -17,19 +17,20 @@ ERROR: bad-live-ranges interval ;
] [ drop ] if ;
: trim-before-ranges ( live-interval -- )
[ ranges>> ] [ uses>> last 1 + ] bi
[ ranges>> ] [ last-use n>> 1 + ] bi
[ '[ from>> _ <= ] filter! drop ]
[ swap last (>>to) ]
2bi ;
: trim-after-ranges ( live-interval -- )
[ ranges>> ] [ uses>> first ] bi
[ ranges>> ] [ first-use n>> ] bi
[ '[ to>> _ >= ] filter! drop ]
[ swap first (>>from) ]
2bi ;
: assign-spill ( live-interval -- )
dup vreg>> vreg-spill-slot >>spill-to drop ;
dup [ vreg>> ] [ last-use rep>> ] bi
assign-spill-slot >>spill-to drop ;
: spill-before ( before -- before/f )
! If the interval does not have any usages before the spill location,
@ -46,7 +47,8 @@ ERROR: bad-live-ranges interval ;
] if ;
: assign-reload ( live-interval -- )
dup vreg>> vreg-spill-slot >>reload-from drop ;
dup [ vreg>> ] [ first-use rep>> ] bi
assign-spill-slot >>reload-from drop ;
: spill-after ( after -- after/f )
! If the interval has no more usages after the spill location,
@ -66,18 +68,19 @@ ERROR: bad-live-ranges interval ;
split-interval [ spill-before ] [ spill-after ] bi* ;
: find-use-position ( live-interval new -- n )
[ uses>> ] [ start>> '[ _ >= ] ] bi* find nip 1/0. or ;
[ uses>> ] [ start>> '[ n>> _ >= ] ] bi* find nip
[ n>> ] [ 1/0. ] if* ;
: find-use-positions ( live-intervals new assoc -- )
'[ [ _ find-use-position ] [ reg>> ] bi _ add-use-position ] each ;
: active-positions ( new assoc -- )
[ [ vreg>> active-intervals-for ] keep ] dip
[ [ active-intervals-for ] keep ] dip
find-use-positions ;
: inactive-positions ( new assoc -- )
[
[ vreg>> inactive-intervals-for ] keep
[ inactive-intervals-for ] keep
[ '[ _ intervals-intersect? ] filter ] keep
] dip
find-use-positions ;
@ -88,7 +91,7 @@ ERROR: bad-live-ranges interval ;
>alist alist-max ;
: spill-new? ( new pair -- ? )
[ uses>> first ] [ second ] bi* > ;
[ first-use n>> ] [ second ] bi* > ;
: spill-new ( new pair -- )
drop spill-after add-unhandled ;
@ -102,13 +105,13 @@ ERROR: bad-live-ranges interval ;
! If there is an active interval using 'reg' (there should be at
! most one) are split and spilled and removed from the inactive
! set.
new vreg>> active-intervals-for [ [ reg>> reg = ] find swap dup ] keep
new active-intervals-for [ [ reg>> reg = ] find swap dup ] keep
'[ _ remove-nth! drop new start>> spill ] [ 2drop ] if ;
:: spill-intersecting-inactive ( new reg -- )
! Any inactive intervals using 'reg' are split and spilled
! and removed from the inactive set.
new vreg>> inactive-intervals-for [
new inactive-intervals-for [
dup reg>> reg = [
dup new intervals-intersect? [
new start>> spill f

View File

@ -1,4 +1,4 @@
! Copyright (C) 2009 Slava Pestov.
! Copyright (C) 2009, 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays assocs combinators fry hints kernel locals
math sequences sets sorting splitting namespaces
@ -25,7 +25,7 @@ IN: compiler.cfg.linear-scan.allocation.splitting
] bi ;
: split-uses ( uses n -- before after )
'[ _ <= ] partition ;
'[ n>> _ <= ] partition ;
ERROR: splitting-too-early ;

View File

@ -1,9 +1,10 @@
! Copyright (C) 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors assocs combinators cpu.architecture fry heaps
kernel math math.order namespaces sequences vectors
USING: arrays accessors assocs combinators cpu.architecture fry
heaps kernel math math.order namespaces sequences vectors
linked-assocs compiler.cfg compiler.cfg.registers
compiler.cfg.instructions compiler.cfg.linear-scan.live-intervals ;
compiler.cfg.instructions
compiler.cfg.linear-scan.live-intervals ;
IN: compiler.cfg.linear-scan.allocation.state
! Start index of current live interval. We ensure that all
@ -26,14 +27,14 @@ SYMBOL: registers
! Vector of active live intervals
SYMBOL: active-intervals
: active-intervals-for ( vreg -- seq )
rep-of reg-class-of active-intervals get at ;
: active-intervals-for ( live-interval -- seq )
reg-class>> active-intervals get at ;
: add-active ( live-interval -- )
dup vreg>> active-intervals-for push ;
dup active-intervals-for push ;
: delete-active ( live-interval -- )
dup vreg>> active-intervals-for remove-eq! drop ;
dup active-intervals-for remove-eq! drop ;
: assign-free-register ( new registers -- )
pop >>reg add-active ;
@ -41,14 +42,14 @@ SYMBOL: active-intervals
! Vector of inactive live intervals
SYMBOL: inactive-intervals
: inactive-intervals-for ( vreg -- seq )
rep-of reg-class-of inactive-intervals get at ;
: inactive-intervals-for ( live-interval -- seq )
reg-class>> inactive-intervals get at ;
: add-inactive ( live-interval -- )
dup vreg>> inactive-intervals-for push ;
dup inactive-intervals-for push ;
: delete-inactive ( live-interval -- )
dup vreg>> inactive-intervals-for remove-eq! drop ;
dup inactive-intervals-for remove-eq! drop ;
! Vector of handled live intervals
SYMBOL: handled-intervals
@ -67,7 +68,7 @@ ERROR: register-already-used live-interval ;
: check-activate ( live-interval -- )
check-allocation? get [
dup [ reg>> ] [ vreg>> active-intervals-for [ reg>> ] map ] bi member?
dup [ reg>> ] [ active-intervals-for [ reg>> ] map ] bi member?
[ register-already-used ] [ drop ] if
] [ drop ] if ;
@ -116,8 +117,8 @@ SYMBOL: unhandled-intervals
: reg-class-assoc ( quot -- assoc )
[ reg-classes ] dip { } map>assoc ; inline
: next-spill-slot ( rep -- n )
rep-size cfg get
: next-spill-slot ( size -- n )
cfg get
[ swap [ align dup ] [ + ] bi ] change-spill-area-size drop
<spill-slot> ;
@ -127,8 +128,11 @@ SYMBOL: unhandled-sync-points
! Mapping from vregs to spill slots
SYMBOL: spill-slots
: vreg-spill-slot ( vreg -- spill-slot )
spill-slots get [ rep-of next-spill-slot ] cache ;
: assign-spill-slot ( coalesced-vreg rep -- spill-slot )
rep-size spill-slots get [ nip next-spill-slot ] 2cache ;
: lookup-spill-slot ( coalesced-vreg rep -- spill-slot )
rep-size 2array spill-slots get ?at [ ] [ bad-vreg ] if ;
: init-allocator ( registers -- )
registers set
@ -148,7 +152,7 @@ SYMBOL: spill-slots
! A utility used by register-status and spill-status words
: free-positions ( new -- assoc )
vreg>> rep-of reg-class-of registers get at
reg-class>> registers get at
[ 1/0. ] H{ } <linked-assoc> map>assoc ;
: add-use-position ( n reg assoc -- ) [ [ min ] when* ] change-at ;

View File

@ -1,15 +1,17 @@
! Copyright (C) 2008, 2009 Slava Pestov.
! Copyright (C) 2008, 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors kernel math assocs namespaces sequences heaps
fry make combinators sets locals arrays
fry make combinators combinators.short-circuit sets locals arrays
cpu.architecture layouts
compiler.cfg
compiler.cfg.def-use
compiler.cfg.liveness
compiler.cfg.liveness.ssa
compiler.cfg.registers
compiler.cfg.instructions
compiler.cfg.linearization
compiler.cfg.ssa.destruction
compiler.cfg.renaming.functor
compiler.cfg.linearization.order
compiler.cfg.linear-scan.allocation
compiler.cfg.linear-scan.allocation.state
compiler.cfg.linear-scan.live-intervals ;
@ -29,21 +31,16 @@ SYMBOL: pending-interval-assoc
: remove-pending ( live-interval -- )
vreg>> pending-interval-assoc get delete-at ;
ERROR: bad-vreg vreg ;
: (vreg>reg) ( vreg pending -- reg )
:: vreg>reg ( vreg -- reg )
! If a live vreg is not in the pending set, then it must
! have been spilled.
?at [ spill-slots get ?at [ ] [ bad-vreg ] if ] unless ;
: vreg>reg ( vreg -- reg )
pending-interval-assoc get (vreg>reg) ;
vreg leader :> leader
leader pending-interval-assoc get at* [
drop leader vreg rep-of lookup-spill-slot
] unless ;
: vregs>regs ( vregs -- assoc )
dup assoc-empty? [
pending-interval-assoc get
'[ _ (vreg>reg) ] assoc-map
] unless ;
[ f ] [ [ dup vreg>reg ] H{ } map>assoc ] if-empty ;
! Minheap of live intervals which still need a register allocation
SYMBOL: unhandled-intervals
@ -54,22 +51,49 @@ SYMBOL: unhandled-intervals
: init-unhandled ( live-intervals -- )
[ add-unhandled ] each ;
! Liveness info is used by resolve pass
! Mapping from basic blocks to values which are live at the start
SYMBOL: register-live-ins
! on all incoming CFG edges
SYMBOL: machine-live-ins
: machine-live-in ( bb -- assoc )
machine-live-ins get at ;
: compute-live-in ( bb -- )
[ live-in keys vregs>regs ] keep machine-live-ins get set-at ;
! Mapping from basic blocks to predecessors to values which are
! live on a particular incoming edge
SYMBOL: machine-edge-live-ins
: machine-edge-live-in ( predecessor bb -- assoc )
machine-edge-live-ins get at at ;
: compute-edge-live-in ( bb -- )
[ edge-live-ins get at [ keys vregs>regs ] assoc-map ] keep
machine-edge-live-ins get set-at ;
! Mapping from basic blocks to values which are live at the end
SYMBOL: register-live-outs
SYMBOL: machine-live-outs
: machine-live-out ( bb -- assoc )
machine-live-outs get at ;
: compute-live-out ( bb -- )
[ live-out keys vregs>regs ] keep machine-live-outs get set-at ;
: init-assignment ( live-intervals -- )
<min-heap> pending-interval-heap set
H{ } clone pending-interval-assoc set
<min-heap> unhandled-intervals set
H{ } clone register-live-ins set
H{ } clone register-live-outs set
H{ } clone machine-live-ins set
H{ } clone machine-edge-live-ins set
H{ } clone machine-live-outs set
init-unhandled ;
: insert-spill ( live-interval -- )
[ reg>> ] [ vreg>> rep-of ] [ spill-to>> ] tri _spill ;
[ reg>> ] [ last-use rep>> ] [ spill-to>> ] tri ##spill ;
: handle-spill ( live-interval -- )
dup spill-to>> [ insert-spill ] [ drop ] if ;
@ -89,10 +113,18 @@ SYMBOL: register-live-outs
pending-interval-heap get (expire-old-intervals) ;
: insert-reload ( live-interval -- )
[ reg>> ] [ vreg>> rep-of ] [ reload-from>> ] tri _reload ;
[ reg>> ] [ first-use rep>> ] [ reload-from>> ] tri ##reload ;
: insert-reload? ( live-interval -- ? )
! Don't insert a reload if the register will be written to
! before being read again.
{
[ reload-from>> ]
[ first-use type>> +use+ eq? ]
} 1&& ;
: handle-reload ( live-interval -- )
dup reload-from>> [ insert-reload ] [ drop ] if ;
dup insert-reload? [ insert-reload ] [ drop ] if ;
: activate-interval ( live-interval -- )
[ add-pending ] [ handle-reload ] bi ;
@ -118,55 +150,19 @@ RENAMING: assign [ vreg>reg ] [ vreg>reg ] [ vreg>reg ]
M: vreg-insn assign-registers-in-insn
[ assign-insn-defs ] [ assign-insn-uses ] [ assign-insn-temps ] tri ;
: trace-on-gc ( assoc -- assoc' )
! When a GC occurs, virtual registers which contain tagged data
! are traced by the GC. Outputs a sequence physical registers.
[ drop rep-of int-rep eq? ] { } assoc-filter-as values ;
: spill-on-gc? ( vreg reg -- ? )
[ rep-of int-rep? not ] [ spill-slot? not ] bi* and ;
: spill-on-gc ( assoc -- assoc' )
! When a GC occurs, virtual registers which contain untagged data,
! and are stored in physical registers, are saved to their spill
! slots. Outputs sequence of triples:
! - physical register
! - spill slot
! - representation
[
[
2dup spill-on-gc?
[ swap [ rep-of ] [ vreg-spill-slot ] bi 3array , ] [ 2drop ] if
] assoc-each
] { } make ;
: gc-root-offsets ( registers -- alist )
! Outputs a sequence of { offset register/spill-slot } pairs
[ length iota [ cell * ] map ] keep zip ;
M: ##gc assign-registers-in-insn
! Since ##gc is always the first instruction in a block, the set of
! values live at the ##gc is just live-in.
M: ##call-gc assign-registers-in-insn
dup call-next-method
basic-block get register-live-ins get at
[ trace-on-gc gc-root-offsets >>tagged-values ] [ spill-on-gc >>data-values ] bi
drop ;
[ [ vreg>reg ] map ] change-gc-roots drop ;
M: insn assign-registers-in-insn drop ;
: begin-block ( bb -- )
dup basic-block set
dup block-from activate-new-intervals
[ live-in vregs>regs ] keep register-live-ins get set-at ;
: end-block ( bb -- )
[ live-out vregs>regs ] keep register-live-outs get set-at ;
: vreg-at-start ( vreg bb -- state )
register-live-ins get at ?at [ bad-vreg ] unless ;
: vreg-at-end ( vreg bb -- state )
register-live-outs get at ?at [ bad-vreg ] unless ;
{
[ basic-block set ]
[ block-from activate-new-intervals ]
[ compute-edge-live-in ]
[ compute-live-in ]
} cleave ;
:: assign-registers-in-block ( bb -- )
bb [
@ -180,7 +176,7 @@ M: insn assign-registers-in-insn drop ;
[ , ]
} cleave
] each
bb end-block
bb compute-live-out
] V{ } make
] change-instructions drop ;

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,9 @@
! Copyright (C) 2008, 2009 Slava Pestov.
! Copyright (C) 2008, 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel accessors namespaces make locals
cpu.architecture
compiler.cfg
compiler.cfg.rpo
compiler.cfg.liveness
compiler.cfg.registers
compiler.cfg.instructions
compiler.cfg.linear-scan.numbering
@ -29,8 +28,9 @@ IN: compiler.cfg.linear-scan
! by Omri Traub, Glenn Holloway, Michael D. Smith
! http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.34.8435
! SSA liveness must have been computed already
:: (linear-scan) ( cfg machine-registers -- )
cfg compute-live-sets
cfg number-instructions
cfg compute-live-intervals machine-registers allocate-registers
cfg assign-registers

View File

@ -1,19 +1,36 @@
! Copyright (C) 2008, 2009 Slava Pestov.
! Copyright (C) 2008, 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: namespaces kernel assocs accessors sequences math math.order fry
combinators binary-search compiler.cfg.instructions compiler.cfg.registers
compiler.cfg.def-use compiler.cfg.liveness compiler.cfg.linearization.order
compiler.cfg ;
USING: namespaces kernel assocs accessors locals sequences math
math.order fry combinators binary-search
compiler.cfg.instructions
compiler.cfg.registers
compiler.cfg.def-use
compiler.cfg.liveness
compiler.cfg.linearization
compiler.cfg.ssa.destruction
compiler.cfg
cpu.architecture ;
IN: compiler.cfg.linear-scan.live-intervals
TUPLE: live-range from to ;
C: <live-range> live-range
SYMBOLS: +def+ +use+ +memory+ ;
TUPLE: vreg-use rep n type ;
C: <vreg-use> vreg-use
TUPLE: live-interval
vreg
reg spill-to reload-from
start end ranges uses ;
start end ranges uses
reg-class ;
: first-use ( live-interval -- use ) uses>> first ; inline
: last-use ( live-interval -- use ) uses>> last ; inline
GENERIC: covers? ( insn# obj -- ? )
@ -29,7 +46,7 @@ M: live-interval covers? ( insn# live-interval -- ? )
[ drop ] [ [ from>> <=> ] with search nip ] 2bi
covers?
] if ;
: add-new-range ( from to live-interval -- )
[ <live-range> ] dip ranges>> push ;
@ -50,63 +67,76 @@ M: live-interval covers? ( insn# live-interval -- ? )
2dup extend-range?
[ extend-range ] [ add-new-range ] if ;
GENERIC: operands-in-registers? ( insn -- ? )
:: add-use ( rep n type live-interval -- )
type +memory+ eq? [
rep n type <vreg-use>
live-interval uses>> push
] unless ;
M: vreg-insn operands-in-registers? drop t ;
M: partial-sync-insn operands-in-registers? drop f ;
: add-def ( insn live-interval -- )
[ insn#>> ] [ uses>> ] bi* push ;
: add-use ( insn live-interval -- )
! Every use is a potential def, no SSA here baby!
over operands-in-registers? [ add-def ] [ 2drop ] if ;
: <live-interval> ( vreg -- live-interval )
: <live-interval> ( vreg reg-class -- live-interval )
\ live-interval new
V{ } clone >>uses
V{ } clone >>ranges
swap >>reg-class
swap >>vreg ;
: block-from ( bb -- n ) instructions>> first insn#>> 1 - ;
: block-to ( bb -- n ) instructions>> last insn#>> ;
M: live-interval hashcode*
nip [ start>> ] [ end>> 1000 * ] bi + ;
SYMBOLS: from to ;
! Mapping from vreg to live-interval
SYMBOL: live-intervals
: live-interval ( vreg -- live-interval )
live-intervals get [ <live-interval> ] cache ;
leader live-intervals get
[ dup rep-of reg-class-of <live-interval> ] cache ;
GENERIC: compute-live-intervals* ( insn -- )
M: insn compute-live-intervals* drop ;
: handle-output ( insn vreg -- )
live-interval
[ [ insn#>> ] dip shorten-range ] [ add-def ] 2bi ;
:: record-def ( vreg n type -- )
vreg rep-of :> rep
vreg live-interval :> live-interval
: handle-input ( insn vreg -- )
live-interval
[ [ [ basic-block get block-from ] dip insn#>> ] dip add-range ] [ add-use ] 2bi ;
n live-interval shorten-range
rep n type live-interval add-use ;
: handle-temp ( insn vreg -- )
live-interval
[ [ insn#>> dup ] dip add-range ] [ add-use ] 2bi ;
:: record-use ( vreg n type -- )
vreg rep-of :> rep
vreg live-interval :> live-interval
M: vreg-insn compute-live-intervals*
[ dup defs-vreg [ handle-output ] with when* ]
[ dup uses-vregs [ handle-input ] with each ]
[ dup temp-vregs [ handle-temp ] with each ]
tri ;
from get n live-interval add-range
rep n type live-interval add-use ;
:: record-temp ( vreg n -- )
vreg rep-of :> rep
vreg live-interval :> live-interval
n n live-interval add-range
rep n +def+ live-interval add-use ;
M:: vreg-insn compute-live-intervals* ( insn -- )
insn insn#>> :> n
insn defs-vreg [ n +def+ record-def ] when*
insn uses-vregs [ n +use+ record-use ] each
insn temp-vregs [ n record-temp ] each ;
M:: clobber-insn compute-live-intervals* ( insn -- )
insn insn#>> :> n
insn defs-vreg [ n +use+ record-def ] when*
insn uses-vregs [ n +memory+ record-use ] each
insn temp-vregs [ n record-temp ] each ;
: handle-live-out ( bb -- )
[ block-from ] [ block-to ] [ live-out keys ] tri
[ live-interval add-range ] with with each ;
live-out dup assoc-empty? [ drop ] [
[ from get to get ] dip keys
[ live-interval add-range ] with with each
] if ;
! A location where all registers have to be spilled
TUPLE: sync-point n ;
@ -118,21 +148,24 @@ SYMBOL: sync-points
GENERIC: compute-sync-points* ( insn -- )
M: partial-sync-insn compute-sync-points*
M: clobber-insn compute-sync-points*
insn#>> <sync-point> sync-points get push ;
M: insn compute-sync-points* drop ;
: compute-live-intervals-step ( bb -- )
[ basic-block set ]
[ handle-live-out ]
[
instructions>> <reversed> [
[ compute-live-intervals* ]
[ compute-sync-points* ]
bi
] each
] tri ;
{
[ block-from from set ]
[ block-to to set ]
[ handle-live-out ]
[
instructions>> <reversed> [
[ compute-live-intervals* ]
[ compute-sync-points* ]
bi
] each
]
} cleave ;
: init-live-intervals ( -- )
H{ } clone live-intervals set

View File

@ -1,7 +1,7 @@
! Copyright (C) 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel accessors math sequences grouping namespaces
compiler.cfg.linearization.order ;
compiler.cfg.linearization ;
IN: compiler.cfg.linear-scan.numbering
ERROR: already-numbered insn ;

View File

@ -7,7 +7,10 @@ IN: compiler.cfg.linear-scan.resolve.tests
[
{
{ { T{ spill-slot f 0 } int-rep } { 1 int-rep } }
{
T{ location f T{ spill-slot f 0 } int-rep int-regs }
T{ location f 1 int-rep int-regs }
}
}
] [
[
@ -17,21 +20,25 @@ IN: compiler.cfg.linear-scan.resolve.tests
[
{
T{ _reload { dst 1 } { rep int-rep } { src T{ spill-slot f 0 } } }
T{ ##reload { dst 1 } { rep int-rep } { src T{ spill-slot f 0 } } }
}
] [
[
{ T{ spill-slot f 0 } int-rep } { 1 int-rep } >insn
T{ location f T{ spill-slot f 0 } int-rep int-regs }
T{ location f 1 int-rep int-regs }
>insn
] { } make
] unit-test
[
{
T{ _spill { src 1 } { rep int-rep } { dst T{ spill-slot f 0 } } }
T{ ##spill { src 1 } { rep int-rep } { dst T{ spill-slot f 0 } } }
}
] [
[
{ 1 int-rep } { T{ spill-slot f 0 } int-rep } >insn
T{ location f 1 int-rep int-regs }
T{ location f T{ spill-slot f 0 } int-rep int-regs }
>insn
] { } make
] unit-test
@ -41,27 +48,84 @@ IN: compiler.cfg.linear-scan.resolve.tests
}
] [
[
{ 1 int-rep } { 2 int-rep } >insn
T{ location f 1 int-rep int-regs }
T{ location f 2 int-rep int-regs }
>insn
] { } make
] unit-test
[
{
T{ ##copy { src 1 } { dst 2 } { rep int-rep } }
T{ ##branch }
}
] [
{ { T{ location f 1 int-rep int-regs } T{ location f 2 int-rep int-regs } } }
mapping-instructions
] unit-test
[
{
T{ ##spill { src 0 } { rep int-rep } { dst T{ spill-slot f 0 } } }
T{ ##reload { dst 0 } { rep tagged-rep } { src T{ spill-slot f 1 } } }
T{ ##branch }
}
] [
{
{ T{ location f T{ spill-slot f 1 } tagged-rep int-regs } T{ location f 0 tagged-rep int-regs } }
{ T{ location f 0 int-rep int-regs } T{ location f T{ spill-slot f 0 } int-rep int-regs } }
}
mapping-instructions
] unit-test
[
{
T{ ##spill { src 0 } { rep int-rep } { dst T{ spill-slot f 1 } } }
T{ ##reload { dst 0 } { rep tagged-rep } { src T{ spill-slot f 0 } } }
T{ ##branch }
}
] [
{
{ T{ location f T{ spill-slot f 0 } tagged-rep int-regs } T{ location f 0 tagged-rep int-regs } }
{ T{ location f 0 int-rep int-regs } T{ location f T{ spill-slot f 1 } int-rep int-regs } }
}
mapping-instructions
] unit-test
[
{
T{ ##spill { src 0 } { rep int-rep } { dst T{ spill-slot f 1 } } }
T{ ##reload { dst 0 } { rep tagged-rep } { src T{ spill-slot f 0 } } }
T{ ##branch }
}
] [
{
{ T{ location f 0 int-rep int-regs } T{ location f T{ spill-slot f 1 } int-rep int-regs } }
{ T{ location f T{ spill-slot f 0 } tagged-rep int-regs } T{ location f 0 tagged-rep int-regs } }
}
mapping-instructions
] unit-test
cfg new 8 >>spill-area-size cfg set
H{ } clone spill-temps set
[
t
] [
{ { { 0 int-rep } { 1 int-rep } } { { 1 int-rep } { 0 int-rep } } }
[ t ] [
{
{ T{ location f 0 int-rep int-regs } T{ location f 1 int-rep int-regs } }
{ T{ location f 1 int-rep int-regs } T{ location f 0 int-rep int-regs } }
}
mapping-instructions {
{
T{ _spill { src 0 } { rep int-rep } { dst T{ spill-slot f 8 } } }
T{ ##spill { src 0 } { rep int-rep } { dst T{ spill-slot f 8 } } }
T{ ##copy { dst 0 } { src 1 } { rep int-rep } }
T{ _reload { dst 1 } { rep int-rep } { src T{ spill-slot f 8 } } }
T{ ##reload { dst 1 } { rep int-rep } { src T{ spill-slot f 8 } } }
T{ ##branch }
}
{
T{ _spill { src 1 } { rep int-rep } { dst T{ spill-slot f 8 } } }
T{ ##spill { src 1 } { rep int-rep } { dst T{ spill-slot f 8 } } }
T{ ##copy { dst 1 } { src 0 } { rep int-rep } }
T{ _reload { dst 0 } { rep int-rep } { src T{ spill-slot f 8 } } }
T{ ##reload { dst 0 } { rep int-rep } { src T{ spill-slot f 8 } } }
T{ ##branch }
}
} member?
] unit-test

View File

@ -1,8 +1,9 @@
! Copyright (C) 2009 Slava Pestov.
! Copyright (C) 2009, 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays assocs combinators
combinators.short-circuit fry kernel locals namespaces
make math sequences hashtables
cpu.architecture
compiler.cfg
compiler.cfg.rpo
compiler.cfg.liveness
@ -11,42 +12,67 @@ compiler.cfg.utilities
compiler.cfg.instructions
compiler.cfg.predecessors
compiler.cfg.parallel-copy
compiler.cfg.ssa.destruction
compiler.cfg.linear-scan.assignment
compiler.cfg.linear-scan.allocation.state ;
IN: compiler.cfg.linear-scan.resolve
TUPLE: location
{ reg read-only }
{ rep read-only }
{ reg-class read-only } ;
: <location> ( reg rep -- location )
dup reg-class-of location boa ;
M: location equal?
over location? [
{ [ [ reg>> ] bi@ = ] [ [ reg-class>> ] bi@ = ] } 2&&
] [ 2drop f ] if ;
M: location hashcode*
reg>> hashcode* ;
SYMBOL: spill-temps
: spill-temp ( rep -- n )
spill-temps get [ next-spill-slot ] cache ;
rep-size spill-temps get [ next-spill-slot ] cache ;
: add-mapping ( from to rep -- )
'[ _ 2array ] bi@ 2array , ;
'[ _ <location> ] bi@ 2array , ;
:: resolve-value-data-flow ( bb to vreg -- )
vreg bb vreg-at-end
vreg to vreg-at-start
:: resolve-value-data-flow ( vreg live-out live-in edge-live-in -- )
vreg live-out ?at [ bad-vreg ] unless
vreg live-in ?at [ edge-live-in ?at [ bad-vreg ] unless ] unless
2dup = [ 2drop ] [ vreg rep-of add-mapping ] if ;
: compute-mappings ( bb to -- mappings )
dup live-in dup assoc-empty? [ 3drop f ] [
[ keys [ resolve-value-data-flow ] with with each ] { } make
:: compute-mappings ( bb to -- mappings )
bb machine-live-out :> live-out
to machine-live-in :> live-in
bb to machine-edge-live-in :> edge-live-in
live-out assoc-empty? [ f ] [
[
live-in keys edge-live-in keys append [
live-out live-in edge-live-in
resolve-value-data-flow
] each
] { } make
] if ;
: memory->register ( from to -- )
swap [ first2 ] [ first ] bi* _reload ;
swap [ reg>> ] [ [ rep>> ] [ reg>> ] bi ] bi* ##reload ;
: register->memory ( from to -- )
[ first2 ] [ first ] bi* _spill ;
[ [ reg>> ] [ rep>> ] bi ] [ reg>> ] bi* ##spill ;
: temp->register ( from to -- )
nip [ first ] [ second ] [ second spill-temp ] tri _reload ;
nip [ reg>> ] [ rep>> ] [ rep>> spill-temp ] tri ##reload ;
: register->temp ( from to -- )
drop [ first2 ] [ second spill-temp ] bi _spill ;
drop [ [ reg>> ] [ rep>> ] bi ] [ rep>> spill-temp ] bi ##spill ;
: register->register ( from to -- )
swap [ first ] [ first2 ] bi* ##copy ;
swap [ reg>> ] [ [ reg>> ] [ rep>> ] bi ] bi* ##copy ;
SYMBOL: temp
@ -54,18 +80,18 @@ SYMBOL: temp
{
{ [ over temp eq? ] [ temp->register ] }
{ [ dup temp eq? ] [ register->temp ] }
{ [ over first spill-slot? ] [ memory->register ] }
{ [ dup first spill-slot? ] [ register->memory ] }
{ [ over reg>> spill-slot? ] [ memory->register ] }
{ [ dup reg>> spill-slot? ] [ register->memory ] }
[ register->register ]
} cond ;
: mapping-instructions ( alist -- insns )
[ swap ] H{ } assoc-map-as
[ temp [ swap >insn ] parallel-mapping ] { } make ;
[ temp [ swap >insn ] parallel-mapping ##branch ] { } make ;
: perform-mappings ( bb to mappings -- )
dup empty? [ 3drop ] [
mapping-instructions insert-simple-basic-block
mapping-instructions insert-basic-block
cfg get cfg-changed drop
] if ;

View File

@ -1,6 +1,6 @@
USING: compiler.cfg.debugger compiler.cfg compiler.cfg.linearization.order
USING: compiler.cfg.debugger compiler.cfg compiler.cfg.linearization
kernel accessors sequences sets tools.test namespaces ;
IN: compiler.cfg.linearization.order.tests
IN: compiler.cfg.linearization.tests
V{ } 0 test-bb

View File

@ -1,113 +1,91 @@
! Copyright (C) 2008, 2009 Slava Pestov.
! Copyright (C) 2009, 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel math accessors sequences namespaces make
combinators assocs arrays locals layouts hashtables
cpu.architecture generalizations
compiler.cfg
compiler.cfg.comparisons
compiler.cfg.stack-frame
compiler.cfg.instructions
compiler.cfg.utilities
compiler.cfg.linearization.order ;
USING: accessors arrays assocs deques dlists hashtables kernel
make sorting namespaces sequences combinators
combinators.short-circuit fry math compiler.cfg.rpo
compiler.cfg.utilities compiler.cfg.loop-detection
compiler.cfg.predecessors sets hash-sets ;
FROM: namespaces => set ;
IN: compiler.cfg.linearization
! This is RPO except loops are rotated and unlikely blocks go
! at the end. Based on SBCL's src/compiler/control.lisp
<PRIVATE
SYMBOLS: work-list loop-heads visited ;
: visited? ( bb -- ? ) visited get in? ;
: add-to-work-list ( bb -- )
dup visited? [ drop ] [
work-list get push-back
] if ;
: init-linearization-order ( cfg -- )
<dlist> work-list set
HS{ } clone visited set
entry>> add-to-work-list ;
: (find-alternate-loop-head) ( bb -- bb' )
dup {
[ predecessor visited? not ]
[ predecessors>> length 1 = ]
[ predecessor successors>> length 1 = ]
[ [ number>> ] [ predecessor number>> ] bi > ]
} 1&& [ predecessor (find-alternate-loop-head) ] when ;
: find-back-edge ( bb -- pred )
[ predecessors>> ] keep '[ _ back-edge? ] find nip ;
: find-alternate-loop-head ( bb -- bb' )
dup find-back-edge dup visited? [ drop ] [
nip (find-alternate-loop-head)
] if ;
: predecessors-ready? ( bb -- ? )
[ predecessors>> ] keep '[
_ 2dup back-edge?
[ 2drop t ] [ drop visited? ] if
] all? ;
: process-successor ( bb -- )
dup predecessors-ready? [
dup loop-entry? [ find-alternate-loop-head ] when
add-to-work-list
] [ drop ] if ;
: sorted-successors ( bb -- seq )
successors>> <reversed> [ loop-nesting-at ] sort-with ;
: process-block ( bb -- )
dup visited? [ drop ] [
[ , ]
[ visited get adjoin ]
[ sorted-successors [ process-successor ] each ]
tri
] if ;
: (linearization-order) ( cfg -- bbs )
init-linearization-order
[ work-list get [ process-block ] slurp-deque ] { } make
! [ unlikely?>> not ] partition append
;
PRIVATE>
: linearization-order ( cfg -- bbs )
needs-post-order needs-loops needs-predecessors
dup linear-order>> [ ] [
dup (linearization-order)
>>linear-order linear-order>>
] ?if ;
SYMBOL: numbers
: block-number ( bb -- n ) numbers get at ;
: number-blocks ( bbs -- ) [ 2array ] map-index >hashtable numbers set ;
! Convert CFG IR to machine IR.
GENERIC: linearize-insn ( basic-block insn -- )
: linearize-basic-block ( bb -- )
[ block-number _label ]
[ dup instructions>> [ linearize-insn ] with each ]
bi ;
M: insn linearize-insn , drop ;
: useless-branch? ( basic-block successor -- ? )
! If our successor immediately follows us in linearization
! order then we don't need to branch.
[ block-number ] bi@ 1 - = ; inline
: emit-branch ( bb successor -- )
2dup useless-branch? [ 2drop ] [ nip block-number _branch ] if ;
M: ##branch linearize-insn
drop dup successors>> first emit-branch ;
: successors ( bb -- first second ) successors>> first2 ; inline
:: conditional ( bb insn n conditional-quot negate-cc-quot -- bb successor label etc... )
bb insn
conditional-quot
[ drop dup successors>> second useless-branch? ] 2bi
[ [ swap block-number ] n ndip ]
[ [ block-number ] n ndip negate-cc-quot call ] if ; inline
: (binary-conditional) ( bb insn -- bb successor1 successor2 src1 src2 cc )
[ dup successors ]
[ [ src1>> ] [ src2>> ] [ cc>> ] tri ] bi* ; inline
: binary-conditional ( bb insn -- bb successor label2 src1 src2 cc )
3 [ (binary-conditional) ] [ negate-cc ] conditional ;
: (test-vector-conditional) ( bb insn -- bb successor1 successor2 src1 temp rep vcc )
[ dup successors ]
[ { [ src1>> ] [ temp>> ] [ rep>> ] [ vcc>> ] } cleave ] bi* ; inline
: test-vector-conditional ( bb insn -- bb successor label src1 temp rep vcc )
4 [ (test-vector-conditional) ] [ negate-vcc ] conditional ;
M: ##compare-branch linearize-insn
binary-conditional _compare-branch emit-branch ;
M: ##compare-imm-branch linearize-insn
binary-conditional _compare-imm-branch emit-branch ;
M: ##compare-float-ordered-branch linearize-insn
binary-conditional _compare-float-ordered-branch emit-branch ;
M: ##compare-float-unordered-branch linearize-insn
binary-conditional _compare-float-unordered-branch emit-branch ;
M: ##test-vector-branch linearize-insn
test-vector-conditional _test-vector-branch emit-branch ;
: overflow-conditional ( bb insn -- bb successor label2 dst src1 src2 )
[ dup successors block-number ]
[ [ dst>> ] [ src1>> ] [ src2>> ] tri ] bi* ; inline
M: ##fixnum-add linearize-insn
overflow-conditional _fixnum-add emit-branch ;
M: ##fixnum-sub linearize-insn
overflow-conditional _fixnum-sub emit-branch ;
M: ##fixnum-mul linearize-insn
overflow-conditional _fixnum-mul emit-branch ;
M: ##dispatch linearize-insn
swap
[ [ src>> ] [ temp>> ] bi _dispatch ]
[ successors>> [ block-number _dispatch-label ] each ]
bi* ;
: linearize-basic-blocks ( cfg -- insns )
[
[
linearization-order
[ number-blocks ]
[ [ linearize-basic-block ] each ] bi
] [ spill-area-size>> _spill-area-size ] bi
] { } make ;
PRIVATE>
: flatten-cfg ( cfg -- mr )
[ linearize-basic-blocks ] [ word>> ] [ label>> ] tri
<mr> ;
: number-blocks ( bbs -- )
[ 2array ] map-index >hashtable numbers set ;

View File

@ -1,81 +0,0 @@
! Copyright (C) 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors assocs deques dlists kernel make sorting
namespaces sequences combinators combinators.short-circuit
fry math compiler.cfg.rpo compiler.cfg.utilities
compiler.cfg.loop-detection compiler.cfg.predecessors
sets hash-sets ;
FROM: namespaces => set ;
IN: compiler.cfg.linearization.order
! This is RPO except loops are rotated. Based on SBCL's src/compiler/control.lisp
<PRIVATE
SYMBOLS: work-list loop-heads visited ;
: visited? ( bb -- ? ) visited get in? ;
: add-to-work-list ( bb -- )
dup visited? [ drop ] [
work-list get push-back
] if ;
: init-linearization-order ( cfg -- )
<dlist> work-list set
HS{ } clone visited set
entry>> add-to-work-list ;
: (find-alternate-loop-head) ( bb -- bb' )
dup {
[ predecessor visited? not ]
[ predecessors>> length 1 = ]
[ predecessor successors>> length 1 = ]
[ [ number>> ] [ predecessor number>> ] bi > ]
} 1&& [ predecessor (find-alternate-loop-head) ] when ;
: find-back-edge ( bb -- pred )
[ predecessors>> ] keep '[ _ back-edge? ] find nip ;
: find-alternate-loop-head ( bb -- bb' )
dup find-back-edge dup visited? [ drop ] [
nip (find-alternate-loop-head)
] if ;
: predecessors-ready? ( bb -- ? )
[ predecessors>> ] keep '[
_ 2dup back-edge?
[ 2drop t ] [ drop visited? ] if
] all? ;
: process-successor ( bb -- )
dup predecessors-ready? [
dup loop-entry? [ find-alternate-loop-head ] when
add-to-work-list
] [ drop ] if ;
: sorted-successors ( bb -- seq )
successors>> <reversed> [ loop-nesting-at ] sort-with ;
: process-block ( bb -- )
dup visited? [ drop ] [
[ , ]
[ visited get adjoin ]
[ sorted-successors [ process-successor ] each ]
tri
] if ;
: (linearization-order) ( cfg -- bbs )
init-linearization-order
[ work-list get [ process-block ] slurp-deque ] { } make ;
PRIVATE>
: linearization-order ( cfg -- bbs )
needs-post-order needs-loops needs-predecessors
dup linear-order>> [ ] [
dup (linearization-order)
>>linear-order linear-order>>
] ?if ;

View File

@ -1 +0,0 @@
Flattening CFG into MR (machine representation)

View File

@ -0,0 +1,61 @@
USING: accessors compiler.cfg compiler.cfg.debugger
compiler.cfg.instructions compiler.cfg.liveness.ssa
compiler.cfg.liveness arrays sequences assocs
compiler.cfg.registers kernel namespaces tools.test ;
IN: compiler.cfg.liveness.ssa.tests
V{
T{ ##prologue }
T{ ##branch }
} 0 test-bb
V{
T{ ##branch }
} 1 test-bb
V{
T{ ##load-integer f 0 0 }
T{ ##branch }
} 2 test-bb
V{
T{ ##load-integer f 1 1 }
T{ ##branch }
} 3 test-bb
V{
T{ ##phi f 2 H{ { 2 0 } { 3 1 } } }
T{ ##branch }
} 4 test-bb
V{
T{ ##branch }
} 5 test-bb
V{
T{ ##replace f 2 D 0 }
T{ ##branch }
} 6 test-bb
V{
T{ ##epilogue }
T{ ##return }
} 7 test-bb
0 1 edge
1 { 2 3 } edges
2 4 edge
3 4 edge
4 { 5 6 } edges
5 6 edge
6 7 edge
[ ] [ cfg new 0 get >>entry dup cfg set compute-ssa-live-sets ] unit-test
[ t ] [ 0 get live-in assoc-empty? ] unit-test
[ H{ { 2 2 } } ] [ 4 get live-out ] unit-test
[ H{ { 0 0 } } ] [ 2 get 4 get edge-live-in ] unit-test
[ H{ { 1 1 } } ] [ 3 get 4 get edge-live-in ] unit-test

View File

@ -1,4 +1,4 @@
! Copyright (C) 2009 Slava Pestov.
! Copyright (C) 2009, 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel namespaces deques accessors sets sequences assocs fry
hashtables dlists compiler.cfg.def-use compiler.cfg.instructions
@ -11,9 +11,9 @@ IN: compiler.cfg.liveness.ssa
! Assoc mapping basic blocks to sequences of sets of vregs; each sequence
! is in correspondence with a predecessor
SYMBOL: phi-live-ins
SYMBOL: edge-live-ins
: phi-live-in ( predecessor basic-block -- set ) phi-live-ins get at at ;
: edge-live-in ( predecessor basic-block -- set ) edge-live-ins get at at ;
SYMBOL: work-list
@ -23,19 +23,19 @@ SYMBOL: work-list
: compute-live-in ( basic-block -- live-in )
[ live-out ] keep instructions>> transfer-liveness ;
: compute-phi-live-in ( basic-block -- phi-live-in )
: compute-edge-live-in ( basic-block -- edge-live-in )
H{ } clone [
'[ inputs>> [ swap _ conjoin-at ] assoc-each ] each-phi
] keep ;
: update-live-in ( basic-block -- changed? )
[ [ compute-live-in ] keep live-ins get maybe-set-at ]
[ [ compute-phi-live-in ] keep phi-live-ins get maybe-set-at ]
[ [ compute-edge-live-in ] keep edge-live-ins get maybe-set-at ]
bi or ;
: compute-live-out ( basic-block -- live-out )
[ successors>> [ live-in ] map ]
[ dup successors>> [ phi-live-in ] with map ] bi
[ dup successors>> [ edge-live-in ] with map ] bi
append assoc-combine ;
: update-live-out ( basic-block -- changed? )
@ -48,14 +48,14 @@ SYMBOL: work-list
[ predecessors>> add-to-work-list ] [ drop ] if
] [ drop ] if ;
: compute-ssa-live-sets ( cfg -- cfg' )
: compute-ssa-live-sets ( cfg -- )
needs-predecessors
<hashed-dlist> work-list set
H{ } clone live-ins set
H{ } clone phi-live-ins set
H{ } clone edge-live-ins set
H{ } clone live-outs set
dup post-order add-to-work-list
post-order add-to-work-list
work-list get [ liveness-step ] slurp-deque ;
: live-in? ( vreg bb -- ? ) live-in key? ;

View File

@ -79,6 +79,8 @@ PRIVATE>
: loop-nesting-at ( bb -- n ) loop-nesting get at 0 or ;
: current-loop-nesting ( -- n ) basic-block get loop-nesting-at ;
: needs-loops ( cfg -- cfg' )
needs-predecessors
dup loops-valid?>> [ detect-loops t >>loops-valid? ] unless ;

View File

@ -1 +0,0 @@
Slava Pestov

View File

@ -1,14 +0,0 @@
! Copyright (C) 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel namespaces accessors compiler.cfg
compiler.cfg.linearization compiler.cfg.gc-checks
compiler.cfg.save-contexts compiler.cfg.linear-scan
compiler.cfg.build-stack-frame ;
IN: compiler.cfg.mr
: build-mr ( cfg -- mr )
insert-gc-checks
insert-save-contexts
linear-scan
flatten-cfg
build-stack-frame ;

View File

@ -1,7 +1,6 @@
! Copyright (C) 2008, 2009 Slava Pestov.
! Copyright (C) 2008, 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel sequences accessors combinators namespaces
compiler.cfg.tco
USING: compiler.cfg.tco
compiler.cfg.useless-conditionals
compiler.cfg.branch-splitting
compiler.cfg.block-joining
@ -12,20 +11,14 @@ compiler.cfg.value-numbering
compiler.cfg.copy-prop
compiler.cfg.dce
compiler.cfg.write-barrier
compiler.cfg.scheduling
compiler.cfg.representations
compiler.cfg.gc-checks
compiler.cfg.save-contexts
compiler.cfg.ssa.destruction
compiler.cfg.empty-blocks
compiler.cfg.checker ;
IN: compiler.cfg.optimizer
SYMBOL: check-optimizer?
: ?check ( cfg -- cfg' )
check-optimizer? get [
dup check-cfg
] when ;
: optimize-cfg ( cfg -- cfg' )
optimize-tail-calls
delete-useless-conditionals
@ -37,9 +30,4 @@ SYMBOL: check-optimizer?
value-numbering
copy-propagation
eliminate-dead-code
eliminate-write-barriers
select-representations
schedule-instructions
destruct-ssa
delete-empty-blocks
?check ;
eliminate-write-barriers ;

View File

@ -0,0 +1 @@
Slava Pestov

View File

@ -0,0 +1,40 @@
USING: arrays sequences kernel namespaces accessors compiler.cfg
compiler.cfg.instructions
compiler.cfg.registers
compiler.cfg.debugger
compiler.cfg.representations.coalescing
tools.test ;
IN: compiler.cfg.representations.coalescing.tests
: test-scc ( -- )
cfg new 0 get >>entry compute-components ;
V{
T{ ##prologue }
T{ ##branch }
} 0 test-bb
V{
T{ ##peek f 2 D 0 }
T{ ##load-integer f 0 0 }
T{ ##branch }
} 1 test-bb
V{
T{ ##load-integer f 1 0 }
T{ ##branch }
} 2 test-bb
V{
T{ ##phi f 3 H{ { 1 0 } { 2 1 } } }
} 3 test-bb
0 { 1 2 } edges
1 3 edge
2 3 edge
[ ] [ test-scc ] unit-test
[ t ] [ 0 vreg>scc 1 vreg>scc = ] unit-test
[ t ] [ 0 vreg>scc 3 vreg>scc = ] unit-test
[ f ] [ 2 vreg>scc 3 vreg>scc = ] unit-test

View File

@ -0,0 +1,43 @@
! Copyright (C) 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors assocs compiler.cfg.def-use
compiler.cfg.instructions compiler.cfg.rpo disjoint-sets fry
kernel namespaces sequences ;
IN: compiler.cfg.representations.coalescing
! Find all strongly connected components in the graph where the
! edges are ##phi or ##copy vreg uses
SYMBOL: components
: init-components ( cfg components -- )
'[
instructions>> [
defs-vreg [ _ add-atom ] when*
] each
] each-basic-block ;
GENERIC# visit-insn 1 ( insn disjoint-set -- )
M: ##copy visit-insn
[ [ dst>> ] [ src>> ] bi ] dip equate ;
M: ##phi visit-insn
[ [ inputs>> values ] [ dst>> ] bi ] dip equate-all-with ;
M: insn visit-insn 2drop ;
: merge-components ( cfg components -- )
'[
instructions>> [
_ visit-insn
] each
] each-basic-block ;
: compute-components ( cfg -- )
<disjoint-set>
[ init-components ]
[ merge-components ]
[ components set drop ] 2tri ;
: vreg>scc ( vreg -- scc )
components get representative ;

View File

@ -0,0 +1 @@
Slava Pestov

View File

@ -0,0 +1,84 @@
! Copyright (C) 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: arrays byte-arrays combinators compiler.cfg.instructions
compiler.cfg.registers compiler.constants cpu.architecture
kernel layouts locals math namespaces ;
IN: compiler.cfg.representations.conversion
ERROR: bad-conversion dst src dst-rep src-rep ;
GENERIC: rep>tagged ( dst src rep -- )
GENERIC: tagged>rep ( dst src rep -- )
M: int-rep rep>tagged ( dst src rep -- )
drop tag-bits get ##shl-imm ;
M: int-rep tagged>rep ( dst src rep -- )
drop tag-bits get ##sar-imm ;
M:: float-rep rep>tagged ( dst src rep -- )
double-rep next-vreg-rep :> temp
temp src ##single>double-float
dst temp double-rep rep>tagged ;
M:: float-rep tagged>rep ( dst src rep -- )
double-rep next-vreg-rep :> temp
temp src double-rep tagged>rep
dst temp ##double>single-float ;
M:: double-rep rep>tagged ( dst src rep -- )
dst 16 float int-rep next-vreg-rep ##allot
src dst float-offset double-rep f ##store-memory-imm ;
M: double-rep tagged>rep
drop float-offset double-rep f ##load-memory-imm ;
M:: vector-rep rep>tagged ( dst src rep -- )
tagged-rep next-vreg-rep :> temp
dst 16 2 cells + byte-array int-rep next-vreg-rep ##allot
temp 16 tag-fixnum ##load-tagged
temp dst 1 byte-array type-number ##set-slot-imm
src dst byte-array-offset rep f ##store-memory-imm ;
M: vector-rep tagged>rep
[ byte-array-offset ] dip f ##load-memory-imm ;
M:: scalar-rep rep>tagged ( dst src rep -- )
tagged-rep next-vreg-rep :> temp
temp src rep ##scalar>integer
dst temp int-rep rep>tagged ;
M:: scalar-rep tagged>rep ( dst src rep -- )
tagged-rep next-vreg-rep :> temp
temp src int-rep tagged>rep
dst temp rep ##integer>scalar ;
GENERIC: rep>int ( dst src rep -- )
GENERIC: int>rep ( dst src rep -- )
M: scalar-rep rep>int ( dst src rep -- )
##scalar>integer ;
M: scalar-rep int>rep ( dst src rep -- )
##integer>scalar ;
: emit-conversion ( dst src dst-rep src-rep -- )
{
{ [ 2dup eq? ] [ drop ##copy ] }
{ [ dup tagged-rep? ] [ drop tagged>rep ] }
{ [ over tagged-rep? ] [ nip rep>tagged ] }
{ [ dup int-rep? ] [ drop int>rep ] }
{ [ over int-rep? ] [ nip rep>int ] }
[
2dup 2array {
{ { double-rep float-rep } [ 2drop ##single>double-float ] }
{ { float-rep double-rep } [ 2drop ##double>single-float ] }
! Punning SIMD vector types? Naughty naughty! But
! it is allowed... otherwise bail out.
[
drop 2dup [ reg-class-of ] bi@ eq?
[ drop ##copy ] [ bad-conversion ] if
]
} case
]
} cond ;

View File

@ -0,0 +1 @@
Slava Pestov

View File

@ -0,0 +1,253 @@
! Copyright (C) 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors byte-arrays combinators
combinators.short-circuit kernel layouts locals make math
namespaces sequences cpu.architecture compiler.cfg.registers
compiler.cfg.instructions
compiler.cfg.representations.rewrite
compiler.cfg.representations.selection ;
IN: compiler.cfg.representations.peephole
! Representation selection performs some peephole optimizations
! when inserting conversions to optimize for a few common cases
GENERIC: optimize-insn ( insn -- )
SYMBOL: insn-index
: here ( -- )
building get length 1 - insn-index set ;
: finish ( insn -- ) , here ;
: unchanged ( insn -- )
[ no-use-conversion ] [ finish ] [ no-def-conversion ] tri ;
: last-insn ( -- insn ) insn-index get building get nth ;
M: vreg-insn conversions-for-insn
init-renaming-set
optimize-insn
last-insn perform-renaming ;
M: vreg-insn optimize-insn
[ emit-use-conversion ] [ finish ] [ emit-def-conversion ] tri ;
M: ##load-integer optimize-insn
{
{
[ dup dst>> rep-of tagged-rep? ]
[ [ dst>> ] [ val>> tag-fixnum ] bi ##load-tagged here ]
}
[ call-next-method ]
} cond ;
! When a float is unboxed, we replace the ##load-reference with a ##load-double
! if the architecture supports it
: convert-to-load-double? ( insn -- ? )
{
[ drop fused-unboxing? ]
[ dst>> rep-of double-rep? ]
[ obj>> float? ]
} 1&& ;
: convert-to-load-vector? ( insn -- ? )
{
[ drop fused-unboxing? ]
[ dst>> rep-of vector-rep? ]
[ obj>> byte-array? ]
} 1&& ;
! When a literal zeroes/ones vector is unboxed, we replace the ##load-reference
! with a ##zero-vector or ##fill-vector instruction since this is more efficient.
: convert-to-zero-vector? ( insn -- ? )
{
[ dst>> rep-of vector-rep? ]
[ obj>> B{ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 } = ]
} 1&& ;
: convert-to-fill-vector? ( insn -- ? )
{
[ dst>> rep-of vector-rep? ]
[ obj>> B{ 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 } = ]
} 1&& ;
M: ##load-reference optimize-insn
{
{
[ dup convert-to-load-double? ]
[ [ dst>> ] [ obj>> ] bi ##load-double here ]
}
{
[ dup convert-to-zero-vector? ]
[ dst>> dup rep-of ##zero-vector here ]
}
{
[ dup convert-to-fill-vector? ]
[ dst>> dup rep-of ##fill-vector here ]
}
{
[ dup convert-to-load-vector? ]
[ [ dst>> ] [ obj>> ] [ dst>> rep-of ] tri ##load-vector here ]
}
[ call-next-method ]
} cond ;
! Optimize this:
! ##sar-imm temp src tag-bits
! ##shl-imm dst temp X
! Into either
! ##shl-imm by X - tag-bits, or
! ##sar-imm by tag-bits - X.
: combine-shl-imm-input ( insn -- )
[ dst>> ] [ src1>> ] [ src2>> ] tri tag-bits get {
{ [ 2dup < ] [ swap - ##sar-imm here ] }
{ [ 2dup > ] [ - ##shl-imm here ] }
[ 2drop int-rep ##copy here ]
} cond ;
: dst-tagged? ( insn -- ? ) dst>> rep-of tagged-rep? ;
: src1-tagged? ( insn -- ? ) src1>> rep-of tagged-rep? ;
: src2-tagged? ( insn -- ? ) src2>> rep-of tagged-rep? ;
: src2-tagged-arithmetic? ( insn -- ? ) src2>> tag-fixnum immediate-arithmetic? ;
: src2-tagged-bitwise? ( insn -- ? ) src2>> tag-fixnum immediate-bitwise? ;
: src2-tagged-shift-count? ( insn -- ? ) src2>> tag-bits get + immediate-shift-count? ;
: >tagged-shift ( insn -- ) [ tag-bits get + ] change-src2 finish ; inline
M: ##shl-imm optimize-insn
{
{
[ dup { [ dst-tagged? ] [ src1-tagged? ] } 1&& ]
[ unchanged ]
}
{
[ dup { [ dst-tagged? ] [ src2-tagged-shift-count? ] } 1&& ]
[ [ emit-use-conversion ] [ >tagged-shift ] [ no-def-conversion ] tri ]
}
{
[ dup src1-tagged? ]
[ [ no-use-conversion ] [ combine-shl-imm-input ] [ emit-def-conversion ] tri ]
}
[ call-next-method ]
} cond ;
! Optimize this:
! ##sar-imm temp src tag-bits
! ##sar-imm dst temp X
! Into
! ##sar-imm by X + tag-bits
! assuming X + tag-bits is a valid shift count.
M: ##sar-imm optimize-insn
{
{
[ dup { [ src1-tagged? ] [ src2-tagged-shift-count? ] } 1&& ]
[ [ no-use-conversion ] [ >tagged-shift ] [ emit-def-conversion ] tri ]
}
[ call-next-method ]
} cond ;
! Peephole optimization: for X = add, sub, and, or, xor, min, max
! we have
! tag(untag(a) X untag(b)) = a X b
!
! so if all inputs and outputs of ##X or ##X-imm are tagged,
! don't have to insert any conversions
M: inert-tag-untag-insn optimize-insn
{
{
[ dup { [ dst-tagged? ] [ src1-tagged? ] [ src2-tagged? ] } 1&& ]
[ unchanged ]
}
[ call-next-method ]
} cond ;
! -imm variant of above
: >tagged-imm ( insn -- )
[ tag-fixnum ] change-src2 unchanged ; inline
M: inert-arithmetic-tag-untag-insn optimize-insn
{
{
[ dup { [ dst-tagged? ] [ src1-tagged? ] [ src2-tagged-arithmetic? ] } 1&& ]
[ >tagged-imm ]
}
[ call-next-method ]
} cond ;
M: inert-bitwise-tag-untag-insn optimize-insn
{
{
[ dup { [ dst-tagged? ] [ src1-tagged? ] [ src2-tagged-bitwise? ] } 1&& ]
[ >tagged-imm ]
}
[ call-next-method ]
} cond ;
M: ##mul-imm optimize-insn
{
{ [ dup { [ dst-tagged? ] [ src1-tagged? ] } 1&& ] [ unchanged ] }
{ [ dup { [ dst-tagged? ] [ src2-tagged-arithmetic? ] } 1&& ] [ >tagged-imm ] }
[ call-next-method ]
} cond ;
! Similar optimization for comparison operators
M: ##compare-integer-imm optimize-insn
{
{ [ dup { [ src1-tagged? ] [ src2-tagged-arithmetic? ] } 1&& ] [ >tagged-imm ] }
[ call-next-method ]
} cond ;
M: ##compare-integer-imm-branch optimize-insn
{
{ [ dup { [ src1-tagged? ] [ src2-tagged-arithmetic? ] } 1&& ] [ >tagged-imm ] }
[ call-next-method ]
} cond ;
M: ##compare-integer optimize-insn
{
{ [ dup { [ src1-tagged? ] [ src2-tagged? ] } 1&& ] [ unchanged ] }
[ call-next-method ]
} cond ;
M: ##compare-integer-branch optimize-insn
{
{ [ dup { [ src1-tagged? ] [ src2-tagged? ] } 1&& ] [ unchanged ] }
[ call-next-method ]
} cond ;
! Identities:
! tag(neg(untag(x))) = x
! tag(neg(x)) = x * -2^tag-bits
: inert-tag/untag-unary? ( insn -- ? )
[ dst>> ] [ src>> ] bi [ rep-of tagged-rep? ] both? ;
: combine-neg-tag ( insn -- )
[ dst>> ] [ src>> ] bi tag-bits get 2^ neg ##mul-imm here ;
M: ##neg optimize-insn
{
{ [ dup inert-tag/untag-unary? ] [ unchanged ] }
{
[ dup dst>> rep-of tagged-rep? ]
[ [ emit-use-conversion ] [ combine-neg-tag ] [ no-def-conversion ] tri ]
}
[ call-next-method ]
} cond ;
! Identity:
! tag(not(untag(x))) = not(x) xor tag-mask
:: emit-tagged-not ( insn -- )
tagged-rep next-vreg-rep :> temp
temp insn src>> ##not
insn dst>> temp tag-mask get ##xor-imm here ;
M: ##not optimize-insn
{
{
[ dup inert-tag/untag-unary? ]
[ [ no-use-conversion ] [ emit-tagged-not ] [ no-def-conversion ] tri ]
}
[ call-next-method ]
} cond ;

View File

@ -68,23 +68,23 @@ PRIVATE>
tri
] with-compilation-unit
: each-def-rep ( ... insn vreg-quot: ( ... vreg rep -- ... ) -- ... )
: each-def-rep ( insn vreg-quot: ( vreg rep -- ) -- )
[ [ defs-vreg ] [ defs-vreg-rep ] bi ] dip with when* ; inline
: each-use-rep ( ... insn vreg-quot: ( ... vreg rep -- ... ) -- ... )
: each-use-rep ( insn vreg-quot: ( vreg rep -- ) -- )
[ [ uses-vregs ] [ uses-vreg-reps ] bi ] dip 2each ; inline
: each-temp-rep ( ... insn vreg-quot: ( ... vreg rep -- ... ) -- ... )
: each-temp-rep ( insn vreg-quot: ( vreg rep -- ) -- )
[ [ temp-vregs ] [ temp-vreg-reps ] bi ] dip 2each ; inline
: with-vreg-reps ( ..a cfg vreg-quot: ( ..a vreg rep -- ..b ) -- ..b )
: each-rep ( insn vreg-quot: ( vreg rep -- ) -- )
[ each-def-rep ] [ each-use-rep ] [ each-temp-rep ] 2tri ; inline
: with-vreg-reps ( cfg vreg-quot: ( vreg rep -- ) -- )
'[
[ basic-block set ] [
[
_
[ each-def-rep ]
[ each-use-rep ]
[ each-temp-rep ] 2tri
_ each-rep
] each-non-phi
] bi
] each-basic-block ; inline

View File

@ -1,6 +1,11 @@
USING: tools.test cpu.architecture
compiler.cfg.registers compiler.cfg.instructions
compiler.cfg.representations.preferred ;
USING: accessors compiler.cfg compiler.cfg.debugger
compiler.cfg.instructions compiler.cfg.registers
compiler.cfg.representations.preferred cpu.architecture kernel
namespaces tools.test sequences arrays system literals layouts
math compiler.constants compiler.cfg.representations.conversion
compiler.cfg.representations.rewrite
compiler.cfg.comparisons
make ;
IN: compiler.cfg.representations
[ { double-rep double-rep } ] [
@ -12,8 +17,717 @@ IN: compiler.cfg.representations
] unit-test
[ double-rep ] [
T{ ##alien-double
T{ ##load-memory-imm
{ dst 5 }
{ src 3 }
{ base 3 }
{ offset 0 }
{ rep double-rep }
} defs-vreg-rep
] unit-test
H{ } clone representations set
3 \ vreg-counter set-global
[
{
T{ ##allot f 2 16 float 4 }
T{ ##store-memory-imm f 1 2 $[ float-offset ] double-rep f }
}
] [
[
2 1 tagged-rep double-rep emit-conversion
] { } make
] unit-test
[
{
T{ ##load-memory-imm f 2 1 $[ float-offset ] double-rep f }
}
] [
[
2 1 double-rep tagged-rep emit-conversion
] { } make
] unit-test
: test-representations ( -- )
cfg new 0 get >>entry dup cfg set select-representations drop ;
! Make sure cost calculation isn't completely wrong
V{
T{ ##prologue }
T{ ##branch }
} 0 test-bb
V{
T{ ##peek f 1 D 0 }
T{ ##peek f 2 D 1 }
T{ ##add-float f 3 1 2 }
T{ ##replace f 3 D 0 }
T{ ##replace f 3 D 1 }
T{ ##replace f 3 D 2 }
T{ ##branch }
} 1 test-bb
V{
T{ ##epilogue }
T{ ##return }
} 2 test-bb
0 1 edge
1 2 edge
[ ] [ test-representations ] unit-test
[ 1 ] [ 1 get instructions>> [ ##allot? ] count ] unit-test
! Don't dereference the result of a peek
V{
T{ ##prologue }
T{ ##branch }
} 0 test-bb
V{
T{ ##peek f 1 D 0 }
T{ ##branch }
} 1 test-bb
V{
T{ ##add-float f 2 1 1 }
T{ ##replace f 2 D 0 }
T{ ##epilogue }
T{ ##return }
} 2 test-bb
V{
T{ ##add-float f 3 1 1 }
T{ ##replace f 3 D 0 }
T{ ##epilogue }
T{ ##return }
} 3 test-bb
0 1 edge
1 { 2 3 } edges
[ ] [ test-representations ] unit-test
[
V{
T{ ##peek f 1 D 0 }
T{ ##branch }
}
] [ 1 get instructions>> ] unit-test
! We cannot untag-fixnum the result of a peek if there are usages
! of it as a tagged-rep
V{
T{ ##prologue }
T{ ##branch }
} 0 test-bb
V{
T{ ##peek f 1 D 0 }
T{ ##branch }
} 1 test-bb
V{
T{ ##replace f 1 R 0 }
T{ ##epilogue }
T{ ##return }
} 2 test-bb
V{
T{ ##mul f 2 1 1 }
T{ ##replace f 2 D 0 }
T{ ##branch }
} 3 test-bb
V{
T{ ##epilogue }
T{ ##return }
} 4 test-bb
0 1 edge
1 { 2 3 } edges
3 { 3 4 } edges
2 4 edge
[ ] [ test-representations ] unit-test
[
V{
T{ ##peek f 1 D 0 }
T{ ##branch }
}
] [ 1 get instructions>> ] unit-test
! But its ok to untag-fixnum the result of a peek if all usages use
! it as int-rep
V{
T{ ##prologue }
T{ ##branch }
} 0 test-bb
V{
T{ ##peek f 1 D 0 }
T{ ##branch }
} 1 test-bb
V{
T{ ##epilogue }
T{ ##return }
} 2 test-bb
V{
T{ ##add f 2 1 1 }
T{ ##mul f 3 1 1 }
T{ ##replace f 2 D 0 }
T{ ##replace f 3 D 1 }
T{ ##branch }
} 3 test-bb
V{
T{ ##epilogue }
T{ ##return }
} 4 test-bb
0 1 edge
1 { 2 3 } edges
3 { 3 4 } edges
2 4 edge
3 \ vreg-counter set-global
[ ] [ test-representations ] unit-test
[
V{
T{ ##peek f 4 D 0 }
T{ ##sar-imm f 1 4 $[ tag-bits get ] }
T{ ##branch }
}
] [ 1 get instructions>> ] unit-test
! scalar-rep => int-rep conversion
V{
T{ ##prologue }
T{ ##branch }
} 0 test-bb
V{
T{ ##peek f 1 D 0 }
T{ ##peek f 2 D 0 }
T{ ##vector>scalar f 3 2 int-4-rep }
T{ ##replace f 3 D 0 }
T{ ##branch }
} 1 test-bb
V{
T{ ##epilogue }
T{ ##return }
} 2 test-bb
0 1 edge
1 2 edge
[ ] [ test-representations ] unit-test
[ t ] [ 1 get instructions>> 4 swap nth ##scalar>integer? ] unit-test
! Test phi node behavior
V{
T{ ##prologue }
T{ ##branch }
} 0 test-bb
V{
T{ ##load-integer f 1 1 }
T{ ##branch }
} 1 test-bb
V{
T{ ##load-integer f 2 2 }
T{ ##branch }
} 2 test-bb
V{
T{ ##phi f 3 H{ { 1 1 } { 2 2 } } }
T{ ##replace f 3 D 0 }
T{ ##branch }
} 3 test-bb
V{
T{ ##epilogue }
T{ ##return }
} 4 test-bb
0 { 1 2 } edges
1 3 edge
2 3 edge
3 4 edge
[ ] [ test-representations ] unit-test
[ T{ ##load-tagged f 1 $[ 1 tag-fixnum ] } ]
[ 1 get instructions>> first ]
unit-test
[ T{ ##load-tagged f 2 $[ 2 tag-fixnum ] } ]
[ 2 get instructions>> first ]
unit-test
! ##load-reference corner case
V{
T{ ##prologue }
T{ ##branch }
} 0 test-bb
V{
T{ ##peek f 0 D 0 }
T{ ##peek f 1 D 1 }
T{ ##add f 2 0 1 }
T{ ##branch }
} 1 test-bb
V{
T{ ##load-reference f 3 f }
T{ ##branch }
} 2 test-bb
V{
T{ ##phi f 4 H{ { 1 2 } { 2 3 } } }
T{ ##replace f 4 D 0 }
T{ ##branch }
} 3 test-bb
V{
T{ ##epilogue }
T{ ##return }
} 4 test-bb
0 { 1 2 } edges
1 3 edge
2 3 edge
3 4 edge
[ ] [ test-representations ] unit-test
! Don't untag the f!
[ 2 ] [ 2 get instructions>> length ] unit-test
cpu x86.32? [
! Make sure load-constant is converted into load-double
V{
T{ ##prologue }
T{ ##branch }
} 0 test-bb
V{
T{ ##peek f 1 D 0 }
T{ ##load-reference f 2 0.5 }
T{ ##add-float f 3 1 2 }
T{ ##replace f 3 D 0 }
T{ ##branch }
} 1 test-bb
V{
T{ ##epilogue }
T{ ##return }
} 2 test-bb
0 1 edge
1 2 edge
[ ] [ test-representations ] unit-test
[ t ] [ 1 get instructions>> second ##load-double? ] unit-test
! Make sure phi nodes are handled in a sane way
V{
T{ ##prologue }
T{ ##branch }
} 0 test-bb
V{
T{ ##peek f 1 D 0 }
T{ ##compare-imm-branch f 1 2 cc= }
} 1 test-bb
V{
T{ ##load-reference f 2 1.5 }
T{ ##branch }
} 2 test-bb
V{
T{ ##load-reference f 3 2.5 }
T{ ##branch }
} 3 test-bb
V{
T{ ##phi f 4 H{ { 2 2 } { 3 3 } } }
T{ ##peek f 5 D 0 }
T{ ##add-float f 6 4 5 }
T{ ##replace f 6 D 0 }
} 4 test-bb
V{
T{ ##epilogue }
T{ ##return }
} 5 test-bb
test-diamond
4 5 edge
[ ] [ test-representations ] unit-test
[ t ] [ 2 get instructions>> first ##load-double? ] unit-test
[ t ] [ 3 get instructions>> first ##load-double? ] unit-test
[ t ] [ 4 get instructions>> first ##phi? ] unit-test
] when
: test-peephole ( insns -- insns )
0 test-bb
test-representations
0 get instructions>> ;
! Don't convert the def site into anything but tagged-rep since
! we might lose precision
5 \ vreg-counter set-global
[ f ] [
V{
T{ ##peek f 0 D 0 }
T{ ##peek f 1 D 1 }
T{ ##tagged>integer f 2 1 }
T{ ##add-float f 3 0 0 }
T{ ##store-memory-imm f 3 2 0 float-rep f }
T{ ##store-memory-imm f 3 2 4 float-rep f }
T{ ##mul-float f 4 0 0 }
T{ ##replace f 4 D 0 }
} test-peephole
[ ##single>double-float? ] any?
] unit-test
! Converting a ##load-integer into a ##load-tagged
[
V{
T{ ##load-tagged f 1 $[ 100 tag-fixnum ] }
T{ ##replace f 1 D 0 }
}
] [
V{
T{ ##load-integer f 1 100 }
T{ ##replace f 1 D 0 }
} test-peephole
] unit-test
! Peephole optimization if input to ##shl-imm is tagged
3 \ vreg-counter set-global
[
V{
T{ ##peek f 1 D 0 }
T{ ##sar-imm f 2 1 1 }
T{ ##add f 4 2 2 }
T{ ##shl-imm f 3 4 $[ tag-bits get ] }
T{ ##replace f 3 D 0 }
}
] [
V{
T{ ##peek f 1 D 0 }
T{ ##shl-imm f 2 1 3 }
T{ ##add f 3 2 2 }
T{ ##replace f 3 D 0 }
} test-peephole
] unit-test
3 \ vreg-counter set-global
[
V{
T{ ##peek f 1 D 0 }
T{ ##shl-imm f 2 1 $[ 10 tag-bits get - ] }
T{ ##add f 4 2 2 }
T{ ##shl-imm f 3 4 $[ tag-bits get ] }
T{ ##replace f 3 D 0 }
}
] [
V{
T{ ##peek f 1 D 0 }
T{ ##shl-imm f 2 1 10 }
T{ ##add f 3 2 2 }
T{ ##replace f 3 D 0 }
} test-peephole
] unit-test
[
V{
T{ ##peek f 1 D 0 }
T{ ##copy f 2 1 int-rep }
T{ ##add f 5 2 2 }
T{ ##shl-imm f 3 5 $[ tag-bits get ] }
T{ ##replace f 3 D 0 }
}
] [
V{
T{ ##peek f 1 D 0 }
T{ ##shl-imm f 2 1 $[ tag-bits get ] }
T{ ##add f 3 2 2 }
T{ ##replace f 3 D 0 }
} test-peephole
] unit-test
! Peephole optimization if output of ##shl-imm needs to be tagged
[
V{
T{ ##load-integer f 1 100 }
T{ ##shl-imm f 2 1 $[ 3 tag-bits get + ] }
T{ ##replace f 2 D 0 }
}
] [
V{
T{ ##load-integer f 1 100 }
T{ ##shl-imm f 2 1 3 }
T{ ##replace f 2 D 0 }
} test-peephole
] unit-test
! Peephole optimization if both input and output of ##shl-imm
! needs to be tagged
[
V{
T{ ##peek f 0 D 0 }
T{ ##shl-imm f 1 0 3 }
T{ ##replace f 1 D 0 }
}
] [
V{
T{ ##peek f 0 D 0 }
T{ ##shl-imm f 1 0 3 }
T{ ##replace f 1 D 0 }
} test-peephole
] unit-test
6 \ vreg-counter set-global
! Peephole optimization if input to ##sar-imm is tagged
[
V{
T{ ##peek f 1 D 0 }
T{ ##sar-imm f 7 1 $[ 3 tag-bits get + ] }
T{ ##shl-imm f 2 7 $[ tag-bits get ] }
T{ ##replace f 2 D 0 }
}
] [
V{
T{ ##peek f 1 D 0 }
T{ ##sar-imm f 2 1 3 }
T{ ##replace f 2 D 0 }
} test-peephole
] unit-test
! Tag/untag elimination
[
V{
T{ ##peek f 1 D 0 }
T{ ##add-imm f 2 1 $[ 100 tag-fixnum ] }
T{ ##replace f 2 D 0 }
}
] [
V{
T{ ##peek f 1 D 0 }
T{ ##add-imm f 2 1 100 }
T{ ##replace f 2 D 0 }
} test-peephole
] unit-test
[
V{
T{ ##peek f 0 D 0 }
T{ ##peek f 1 D 1 }
T{ ##add f 2 0 1 }
T{ ##replace f 2 D 0 }
}
] [
V{
T{ ##peek f 0 D 0 }
T{ ##peek f 1 D 1 }
T{ ##add f 2 0 1 }
T{ ##replace f 2 D 0 }
} test-peephole
] unit-test
! Make sure we don't exceed immediate bounds
cpu x86.64? [
4 \ vreg-counter set-global
[
V{
T{ ##peek f 0 D 0 }
T{ ##sar-imm f 5 0 $[ tag-bits get ] }
T{ ##add-imm f 6 5 $[ 30 2^ ] }
T{ ##shl-imm f 2 6 $[ tag-bits get ] }
T{ ##replace f 2 D 0 }
}
] [
V{
T{ ##peek f 0 D 0 }
T{ ##add-imm f 2 0 $[ 30 2^ ] }
T{ ##replace f 2 D 0 }
} test-peephole
] unit-test
[
V{
T{ ##load-integer f 0 100 }
T{ ##mul-imm f 7 0 $[ 30 2^ ] }
T{ ##shl-imm f 1 7 $[ tag-bits get ] }
T{ ##replace f 1 D 0 }
}
] [
V{
T{ ##load-integer f 0 100 }
T{ ##mul-imm f 1 0 $[ 30 2^ ] }
T{ ##replace f 1 D 0 }
} test-peephole
] unit-test
] when
! Tag/untag elimination for ##mul-imm
[
V{
T{ ##peek f 0 D 0 }
T{ ##mul-imm f 1 0 100 }
T{ ##replace f 1 D 0 }
}
] [
V{
T{ ##peek f 0 D 0 }
T{ ##mul-imm f 1 0 100 }
T{ ##replace f 1 D 0 }
} test-peephole
] unit-test
4 \ vreg-counter set-global
[
V{
T{ ##peek f 0 D 0 }
T{ ##peek f 1 D 1 }
T{ ##sar-imm f 5 1 $[ tag-bits get ] }
T{ ##add-imm f 2 5 30 }
T{ ##mul-imm f 3 2 $[ 100 tag-fixnum ] }
T{ ##replace f 3 D 0 }
}
] [
V{
T{ ##peek f 0 D 0 }
T{ ##peek f 1 D 1 }
T{ ##add-imm f 2 1 30 }
T{ ##mul-imm f 3 2 100 }
T{ ##replace f 3 D 0 }
} test-peephole
] unit-test
! Tag/untag elimination for ##compare-integer
[
V{
T{ ##peek f 0 D 0 }
T{ ##peek f 1 D 1 }
T{ ##compare-integer f 2 0 1 cc= }
T{ ##replace f 2 D 0 }
}
] [
V{
T{ ##peek f 0 D 0 }
T{ ##peek f 1 D 1 }
T{ ##compare-integer f 2 0 1 cc= }
T{ ##replace f 2 D 0 }
} test-peephole
] unit-test
[
V{
T{ ##peek f 0 D 0 }
T{ ##peek f 1 D 1 }
T{ ##compare-integer-branch f 0 1 cc= }
}
] [
V{
T{ ##peek f 0 D 0 }
T{ ##peek f 1 D 1 }
T{ ##compare-integer-branch f 0 1 cc= }
} test-peephole
] unit-test
[
V{
T{ ##peek f 0 D 0 }
T{ ##peek f 1 D 1 }
T{ ##compare-integer-imm-branch f 0 $[ 10 tag-fixnum ] cc= }
}
] [
V{
T{ ##peek f 0 D 0 }
T{ ##peek f 1 D 1 }
T{ ##compare-integer-imm-branch f 0 10 cc= }
} test-peephole
] unit-test
! Tag/untag elimination for ##neg
[
V{
T{ ##peek f 0 D 0 }
T{ ##neg f 1 0 }
T{ ##replace f 1 D 0 }
}
] [
V{
T{ ##peek f 0 D 0 }
T{ ##neg f 1 0 }
T{ ##replace f 1 D 0 }
} test-peephole
] unit-test
4 \ vreg-counter set-global
[
V{
T{ ##peek f 5 D 0 }
T{ ##sar-imm f 0 5 $[ tag-bits get ] }
T{ ##peek f 6 D 1 }
T{ ##sar-imm f 1 6 $[ tag-bits get ] }
T{ ##mul f 2 0 1 }
T{ ##mul-imm f 3 2 -16 }
T{ ##replace f 3 D 0 }
}
] [
V{
T{ ##peek f 0 D 0 }
T{ ##peek f 1 D 1 }
T{ ##mul f 2 0 1 }
T{ ##neg f 3 2 }
T{ ##replace f 3 D 0 }
} test-peephole
] unit-test
! Tag/untag elimination for ##not
2 \ vreg-counter set-global
[
V{
T{ ##peek f 0 D 0 }
T{ ##not f 3 0 }
T{ ##xor-imm f 1 3 $[ tag-mask get ] }
T{ ##replace f 1 D 0 }
}
] [
V{
T{ ##peek f 0 D 0 }
T{ ##not f 1 0 }
T{ ##replace f 1 D 0 }
} test-peephole
] unit-test

View File

@ -1,332 +1,29 @@
! Copyright (C) 2009 Slava Pestov
! Copyright (C) 2009, 2010 Slava Pestov
! See http://factorcode.org/license.txt for BSD license.
USING: kernel fry accessors sequences assocs sets namespaces
arrays combinators combinators.short-circuit math make locals
deques dlists layouts byte-arrays cpu.architecture
compiler.utilities
compiler.constants
USING: combinators
compiler.cfg
compiler.cfg.rpo
compiler.cfg.hats
compiler.cfg.registers
compiler.cfg.instructions
compiler.cfg.def-use
compiler.cfg.utilities
compiler.cfg.predecessors
compiler.cfg.loop-detection
compiler.cfg.renaming.functor
compiler.cfg.representations.preferred ;
FROM: namespaces => set ;
compiler.cfg.representations.rewrite
compiler.cfg.representations.peephole
compiler.cfg.representations.selection
compiler.cfg.representations.coalescing ;
IN: compiler.cfg.representations
! Virtual register representation selection.
ERROR: bad-conversion dst src dst-rep src-rep ;
GENERIC: emit-box ( dst src rep -- )
GENERIC: emit-unbox ( dst src rep -- )
M:: float-rep emit-box ( dst src rep -- )
double-rep next-vreg-rep :> temp
temp src ##single>double-float
dst temp double-rep emit-box ;
M:: float-rep emit-unbox ( dst src rep -- )
double-rep next-vreg-rep :> temp
temp src double-rep emit-unbox
dst temp ##double>single-float ;
M: double-rep emit-box
drop
[ drop 16 float int-rep next-vreg-rep ##allot ]
[ float-offset swap ##set-alien-double ]
2bi ;
M: double-rep emit-unbox
drop float-offset ##alien-double ;
M:: vector-rep emit-box ( dst src rep -- )
int-rep next-vreg-rep :> temp
dst 16 2 cells + byte-array int-rep next-vreg-rep ##allot
temp 16 tag-fixnum ##load-immediate
temp dst 1 byte-array type-number ##set-slot-imm
dst byte-array-offset src rep ##set-alien-vector ;
M: vector-rep emit-unbox
[ byte-array-offset ] dip ##alien-vector ;
M:: scalar-rep emit-box ( dst src rep -- )
int-rep next-vreg-rep :> temp
temp src rep ##scalar>integer
dst temp tag-bits get ##shl-imm ;
M:: scalar-rep emit-unbox ( dst src rep -- )
int-rep next-vreg-rep :> temp
temp src tag-bits get ##sar-imm
dst temp rep ##integer>scalar ;
: emit-conversion ( dst src dst-rep src-rep -- )
{
{ [ 2dup eq? ] [ drop ##copy ] }
{ [ dup int-rep eq? ] [ drop emit-unbox ] }
{ [ over int-rep eq? ] [ nip emit-box ] }
[
2dup 2array {
{ { double-rep float-rep } [ 2drop ##single>double-float ] }
{ { float-rep double-rep } [ 2drop ##double>single-float ] }
! Punning SIMD vector types? Naughty naughty! But
! it is allowed... otherwise bail out.
[
drop 2dup [ reg-class-of ] bi@ eq?
[ drop ##copy ] [ bad-conversion ] if
]
} case
]
} cond ;
<PRIVATE
! For every vreg, compute possible representations.
SYMBOL: possibilities
: possible ( vreg -- reps ) possibilities get at ;
: compute-possibilities ( cfg -- )
H{ } clone [ '[ swap _ conjoin-at ] with-vreg-reps ] keep
[ keys ] assoc-map possibilities set ;
! Compute vregs which must remain tagged for their lifetime.
SYMBOL: always-boxed
:: (compute-always-boxed) ( vreg rep assoc -- )
rep int-rep eq? [
int-rep vreg assoc set-at
] when ;
: compute-always-boxed ( cfg -- assoc )
H{ } clone [
'[
[
dup [ ##load-reference? ] [ ##load-constant? ] bi or
[ drop ] [ [ _ (compute-always-boxed) ] each-def-rep ] if
] each-non-phi
] each-basic-block
] keep ;
! For every vreg, compute the cost of keeping it in every possible
! representation.
! Cost map maps vreg to representation to cost.
SYMBOL: costs
: init-costs ( -- )
possibilities get [ [ 0 ] H{ } map>assoc ] assoc-map costs set ;
: increase-cost ( rep vreg -- )
! Increase cost of keeping vreg in rep, making a choice of rep less
! likely.
[ basic-block get loop-nesting-at ] 2dip costs get at at+ ;
: maybe-increase-cost ( possible vreg preferred -- )
pick eq? [ 2drop ] [ increase-cost ] if ;
: representation-cost ( vreg preferred -- )
! 'preferred' is a representation that the instruction can accept with no cost.
! So, for each representation that's not preferred, increase the cost of keeping
! the vreg in that representation.
[ drop possible ]
[ '[ _ _ maybe-increase-cost ] ]
2bi each ;
: compute-costs ( cfg -- costs )
init-costs [ representation-cost ] with-vreg-reps costs get ;
! For every vreg, compute preferred representation, that minimizes costs.
: minimize-costs ( costs -- representations )
[ >alist alist-min first ] assoc-map ;
: compute-representations ( cfg -- )
[ compute-costs minimize-costs ]
[ compute-always-boxed ]
bi assoc-union
representations set ;
! Insert conversions. This introduces new temporaries, so we need
! to rename opearands too.
! Mapping from vreg,rep pairs to vregs
SYMBOL: alternatives
:: emit-def-conversion ( dst preferred required -- new-dst' )
! If an instruction defines a register with representation 'required',
! but the register has preferred representation 'preferred', then
! we rename the instruction's definition to a new register, which
! becomes the input of a conversion instruction.
dst required next-vreg-rep [ preferred required emit-conversion ] keep ;
:: emit-use-conversion ( src preferred required -- new-src' )
! If an instruction uses a register with representation 'required',
! but the register has preferred representation 'preferred', then
! we rename the instruction's input to a new register, which
! becomes the output of a conversion instruction.
preferred required eq? [ src ] [
src required alternatives get [
required next-vreg-rep :> new-src
[ new-src ] 2dip preferred emit-conversion
new-src
] 2cache
] if ;
SYMBOLS: renaming-set needs-renaming? ;
: init-renaming-set ( -- )
needs-renaming? off
V{ } clone renaming-set set ;
: no-renaming ( vreg -- )
dup 2array renaming-set get push ;
: record-renaming ( from to -- )
2array renaming-set get push needs-renaming? on ;
:: (compute-renaming-set) ( ..a vreg required quot: ( ..a vreg preferred required -- ..b ) -- ..b )
vreg rep-of :> preferred
preferred required eq?
[ vreg no-renaming ]
[ vreg vreg preferred required quot call record-renaming ] if ; inline
: compute-renaming-set ( insn -- )
! temp vregs don't need conversions since they're always in their
! preferred representation
init-renaming-set
[ [ [ emit-use-conversion ] (compute-renaming-set) ] each-use-rep ]
[ , ]
[ [ [ emit-def-conversion ] (compute-renaming-set) ] each-def-rep ]
tri ;
: converted-value ( vreg -- vreg' )
renaming-set get pop first2 [ assert= ] dip ;
RENAMING: convert [ converted-value ] [ converted-value ] [ ]
: perform-renaming ( insn -- )
needs-renaming? get [
renaming-set get reverse! drop
[ convert-insn-uses ] [ convert-insn-defs ] bi
renaming-set get length 0 assert=
] [ drop ] if ;
GENERIC: conversions-for-insn ( insn -- )
SYMBOL: phi-mappings
! compiler.cfg.cssa inserts conversions which convert phi inputs into
! the representation of the output. However, we still have to do some
! processing here, because if the only node that uses the output of
! the phi instruction is another phi instruction then this phi node's
! output won't have a representation assigned.
M: ##phi conversions-for-insn
[ , ] [ [ inputs>> values ] [ dst>> ] bi phi-mappings get set-at ] bi ;
! When a literal zeroes/ones vector is unboxed, we replace the ##load-reference
! with a ##zero-vector or ##fill-vector instruction since this is more efficient.
: convert-to-zero-vector? ( insn -- ? )
{
[ dst>> rep-of vector-rep? ]
[ obj>> B{ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 } = ]
} 1&& ;
: convert-to-fill-vector? ( insn -- ? )
{
[ dst>> rep-of vector-rep? ]
[ obj>> B{ 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 } = ]
} 1&& ;
: (convert-to-zero/fill-vector) ( insn -- dst rep )
dst>> dup rep-of ; inline
: conversions-for-load-insn ( insn -- ?insn )
{
{
[ dup convert-to-zero-vector? ]
[ (convert-to-zero/fill-vector) ##zero-vector f ]
}
{
[ dup convert-to-fill-vector? ]
[ (convert-to-zero/fill-vector) ##fill-vector f ]
}
[ ]
} cond ;
M: ##load-reference conversions-for-insn
conversions-for-load-insn [ call-next-method ] when* ;
M: ##load-constant conversions-for-insn
conversions-for-load-insn [ call-next-method ] when* ;
M: vreg-insn conversions-for-insn
[ compute-renaming-set ] [ perform-renaming ] bi ;
M: insn conversions-for-insn , ;
: conversions-for-block ( bb -- )
dup kill-block? [ drop ] [
[
[
H{ } clone alternatives set
[ conversions-for-insn ] each
] V{ } make
] change-instructions drop
] if ;
! If the output of a phi instruction is only used as the input to another
! phi instruction, then we want to use the same representation for both
! if possible.
SYMBOL: work-list
: add-to-work-list ( vregs -- )
work-list get push-all-front ;
: rep-assigned ( vregs -- vregs' )
representations get '[ _ key? ] filter ;
: rep-not-assigned ( vregs -- vregs' )
representations get '[ _ key? not ] filter ;
: add-ready-phis ( -- )
phi-mappings get keys rep-assigned add-to-work-list ;
: process-phi-mapping ( dst -- )
! If dst = phi(src1,src2,...) and dst's representation has been
! determined, assign that representation to each one of src1,...
! that does not have a representation yet, and process those, too.
dup phi-mappings get at* [
[ rep-of ] [ rep-not-assigned ] bi*
[ [ set-rep-of ] with each ] [ add-to-work-list ] bi
] [ 2drop ] if ;
: remaining-phi-mappings ( -- )
phi-mappings get keys rep-not-assigned
[ [ int-rep ] dip set-rep-of ] each ;
: process-phi-mappings ( -- )
<hashed-dlist> work-list set
add-ready-phis
work-list get [ process-phi-mapping ] slurp-deque
remaining-phi-mappings ;
: insert-conversions ( cfg -- )
H{ } clone phi-mappings set
[ conversions-for-block ] each-basic-block
process-phi-mappings ;
PRIVATE>
! Virtual register representation selection. This is where
! decisions about integer tagging and float and vector boxing
! are made. The appropriate conversion operations inserted
! after a cost analysis.
: select-representations ( cfg -- cfg' )
needs-loops
needs-predecessors
{
[ compute-components ]
[ compute-possibilities ]
[ compute-representations ]
[ insert-conversions ]
[ ]
} cleave
representations get cfg get (>>reps) ;
} cleave ;

View File

@ -0,0 +1 @@
Slava Pestov

View File

@ -0,0 +1,104 @@
! Copyright (C) 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays assocs combinators
combinators.short-circuit layouts kernel locals make math
namespaces sequences
compiler.cfg.instructions
compiler.cfg.registers
compiler.cfg.renaming.functor
compiler.cfg.representations.conversion
compiler.cfg.representations.preferred
compiler.cfg.rpo
compiler.cfg.utilities
cpu.architecture ;
IN: compiler.cfg.representations.rewrite
! Insert conversions. This introduces new temporaries, so we need
! to rename opearands too.
! Mapping from vreg,rep pairs to vregs
SYMBOL: alternatives
:: (emit-def-conversion) ( dst preferred required -- new-dst' )
! If an instruction defines a register with representation 'required',
! but the register has preferred representation 'preferred', then
! we rename the instruction's definition to a new register, which
! becomes the input of a conversion instruction.
dst required next-vreg-rep [ preferred required emit-conversion ] keep ;
:: (emit-use-conversion) ( src preferred required -- new-src' )
! If an instruction uses a register with representation 'required',
! but the register has preferred representation 'preferred', then
! we rename the instruction's input to a new register, which
! becomes the output of a conversion instruction.
preferred required eq? [ src ] [
src required alternatives get [
required next-vreg-rep :> new-src
[ new-src ] 2dip preferred emit-conversion
new-src
] 2cache
] if ;
SYMBOLS: renaming-set needs-renaming? ;
: init-renaming-set ( -- )
needs-renaming? off
renaming-set get delete-all ;
: no-renaming ( vreg -- )
dup 2array renaming-set get push ;
: record-renaming ( from to -- )
2array renaming-set get push needs-renaming? on ;
:: (compute-renaming-set) ( vreg required quot: ( vreg preferred required -- new-vreg ) -- )
vreg rep-of :> preferred
preferred required eq?
[ vreg no-renaming ]
[ vreg vreg preferred required quot call record-renaming ] if ; inline
: emit-use-conversion ( insn -- )
[ [ (emit-use-conversion) ] (compute-renaming-set) ] each-use-rep ;
: no-use-conversion ( insn -- )
[ drop no-renaming ] each-use-rep ;
: emit-def-conversion ( insn -- )
[ [ (emit-def-conversion) ] (compute-renaming-set) ] each-def-rep ;
: no-def-conversion ( insn -- )
[ drop no-renaming ] each-def-rep ;
: converted-value ( vreg -- vreg' )
renaming-set get pop first2 [ assert= ] dip ;
RENAMING: convert [ converted-value ] [ converted-value ] [ ]
: perform-renaming ( insn -- )
needs-renaming? get [
renaming-set get reverse! drop
[ convert-insn-uses ] [ convert-insn-defs ] bi
renaming-set get length 0 assert=
] [ drop ] if ;
GENERIC: conversions-for-insn ( insn -- )
M: ##phi conversions-for-insn , ;
M: ##copy conversions-for-insn , ;
M: insn conversions-for-insn , ;
: conversions-for-block ( bb -- )
dup kill-block? [ drop ] [
[
[
H{ } clone alternatives set
[ conversions-for-insn ] each
] V{ } make
] change-instructions drop
] if ;
: insert-conversions ( cfg -- )
V{ } clone renaming-set set
[ conversions-for-block ] each-basic-block ;

View File

@ -0,0 +1 @@
Slava Pestov

View File

@ -0,0 +1,150 @@
! Copyright (C) 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays assocs byte-arrays combinators
disjoint-sets fry kernel locals math namespaces sequences sets
compiler.cfg
compiler.cfg.instructions
compiler.cfg.loop-detection
compiler.cfg.registers
compiler.cfg.representations.preferred
compiler.cfg.representations.coalescing
compiler.cfg.rpo
compiler.cfg.utilities
compiler.utilities
cpu.architecture ;
FROM: namespaces => set ;
IN: compiler.cfg.representations.selection
! vregs which must be tagged at the definition site because
! there is at least one usage that is not int-rep. If all usages
! are int-rep it is safe to untag at the definition site.
SYMBOL: tagged-vregs
SYMBOL: vreg-reps
: handle-def ( vreg rep -- )
swap vreg>scc vreg-reps get
[ [ intersect ] when* ] change-at ;
: handle-use ( vreg rep -- )
int-rep eq? [ drop ] [ vreg>scc tagged-vregs get adjoin ] if ;
GENERIC: (collect-vreg-reps) ( insn -- )
M: ##load-reference (collect-vreg-reps)
[ dst>> ] [ obj>> ] bi {
{ [ dup float? ] [ drop { float-rep double-rep } ] }
{ [ dup byte-array? ] [ drop vector-reps ] }
[ drop { } ]
} cond handle-def ;
M: vreg-insn (collect-vreg-reps)
[ [ handle-use ] each-use-rep ]
[ [ 1array handle-def ] each-def-rep ]
[ [ 1array handle-def ] each-temp-rep ]
tri ;
M: insn (collect-vreg-reps) drop ;
: collect-vreg-reps ( cfg -- )
H{ } clone vreg-reps set
HS{ } clone tagged-vregs set
[ [ (collect-vreg-reps) ] each-non-phi ] each-basic-block ;
SYMBOL: possibilities
: possible-reps ( vreg reps -- vreg reps )
{ tagged-rep } union
2dup [ tagged-vregs get in? not ] [ { tagged-rep } = ] bi* and
[ drop { tagged-rep int-rep } ] [ ] if ;
: compute-possibilities ( cfg -- )
collect-vreg-reps
vreg-reps get [ possible-reps ] assoc-map possibilities set ;
! For every vreg, compute the cost of keeping it in every possible
! representation.
! Cost map maps vreg to representation to cost.
SYMBOL: costs
: init-costs ( -- )
! Initialize cost as 0 for each possibility.
possibilities get [ [ 0 ] H{ } map>assoc ] assoc-map costs set ;
: 10^ ( n -- x ) 10 <repetition> product ;
: increase-cost ( rep scc factor -- )
! Increase cost of keeping vreg in rep, making a choice of rep less
! likely. If the rep is not in the cost alist, it means this
! representation is prohibited.
[ costs get at 2dup key? ] dip
'[ [ current-loop-nesting 10^ _ * + ] change-at ] [ 2drop ] if ;
:: increase-costs ( vreg preferred factor -- )
vreg vreg>scc :> scc
scc possibilities get at [
dup preferred eq? [ drop ] [ scc factor increase-cost ] if
] each ; inline
UNION: inert-tag-untag-insn
##add
##sub
##and
##or
##xor
##min
##max ;
UNION: inert-arithmetic-tag-untag-insn
##add-imm
##sub-imm ;
UNION: inert-bitwise-tag-untag-insn
##and-imm
##or-imm
##xor-imm ;
GENERIC: has-peephole-opts? ( insn -- ? )
M: insn has-peephole-opts? drop f ;
M: ##load-integer has-peephole-opts? drop t ;
M: ##load-reference has-peephole-opts? drop t ;
M: ##neg has-peephole-opts? drop t ;
M: ##not has-peephole-opts? drop t ;
M: inert-tag-untag-insn has-peephole-opts? drop t ;
M: inert-arithmetic-tag-untag-insn has-peephole-opts? drop t ;
M: inert-bitwise-tag-untag-insn has-peephole-opts? drop t ;
M: ##mul-imm has-peephole-opts? drop t ;
M: ##shl-imm has-peephole-opts? drop t ;
M: ##shr-imm has-peephole-opts? drop t ;
M: ##sar-imm has-peephole-opts? drop t ;
M: ##compare-integer-imm has-peephole-opts? drop t ;
M: ##compare-integer has-peephole-opts? drop t ;
M: ##compare-integer-imm-branch has-peephole-opts? drop t ;
M: ##compare-integer-branch has-peephole-opts? drop t ;
GENERIC: compute-insn-costs ( insn -- )
M: insn compute-insn-costs drop ;
M: vreg-insn compute-insn-costs
dup has-peephole-opts? 2 5 ? '[ _ increase-costs ] each-rep ;
: compute-costs ( cfg -- )
init-costs
[
[ basic-block set ]
[ [ compute-insn-costs ] each-non-phi ] bi
] each-basic-block ;
! For every vreg, compute preferred representation, that minimizes costs.
: minimize-costs ( costs -- representations )
[ nip assoc-empty? not ] assoc-filter
[ >alist alist-min first ] assoc-map ;
: compute-representations ( cfg -- )
compute-costs costs get minimize-costs
[ components get [ disjoint-set-members ] keep ] dip
'[ dup _ representative _ at ] H{ } map>assoc
representations set ;

View File

@ -39,8 +39,8 @@ SYMBOL: visited
[ drop basic-block set ]
[ change-instructions drop ] 2bi ; inline
: local-optimization ( ... cfg quot: ( ... insns -- ... insns' ) -- ... cfg' )
dupd '[ _ optimize-basic-block ] each-basic-block ; inline
: simple-optimization ( ... cfg quot: ( ... insns -- ... insns' ) -- ... )
'[ _ optimize-basic-block ] each-basic-block ; inline
: needs-post-order ( cfg -- cfg' )
dup post-order drop ;

View File

@ -10,6 +10,7 @@ IN: compiler.cfg.save-contexts
: needs-save-context? ( insns -- ? )
[
{
[ ##call-gc? ]
[ ##unary-float-function? ]
[ ##binary-float-function? ]
[ ##alien-invoke? ]
@ -20,8 +21,8 @@ IN: compiler.cfg.save-contexts
: insert-save-context ( bb -- )
dup instructions>> dup needs-save-context? [
int-rep next-vreg-rep
int-rep next-vreg-rep
tagged-rep next-vreg-rep
tagged-rep next-vreg-rep
\ ##save-context new-insn prefix
>>instructions drop
] [ 2drop ] if ;

View File

@ -13,19 +13,19 @@ IN: compiler.cfg.ssa.construction.tests
reset-counters
V{
T{ ##load-immediate f 1 100 }
T{ ##load-integer f 1 100 }
T{ ##add-imm f 2 1 50 }
T{ ##add-imm f 2 2 10 }
T{ ##branch }
} 0 test-bb
V{
T{ ##load-immediate f 3 3 }
T{ ##load-integer f 3 3 }
T{ ##branch }
} 1 test-bb
V{
T{ ##load-immediate f 3 4 }
T{ ##load-integer f 3 4 }
T{ ##branch }
} 2 test-bb
@ -48,7 +48,7 @@ V{
[
V{
T{ ##load-immediate f 1 100 }
T{ ##load-integer f 1 100 }
T{ ##add-imm f 2 1 50 }
T{ ##add-imm f 3 2 10 }
T{ ##branch }
@ -57,14 +57,14 @@ V{
[
V{
T{ ##load-immediate f 4 3 }
T{ ##load-integer f 4 3 }
T{ ##branch }
}
] [ 1 get instructions>> ] unit-test
[
V{
T{ ##load-immediate f 5 4 }
T{ ##load-integer f 5 4 }
T{ ##branch }
}
] [ 2 get instructions>> ] unit-test

View File

@ -1,4 +1,4 @@
! Copyright (C) 2009 Slava Pestov.
! Copyright (C) 2009, 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors assocs kernel locals fry sequences
cpu.architecture
@ -6,8 +6,7 @@ compiler.cfg.rpo
compiler.cfg.def-use
compiler.cfg.utilities
compiler.cfg.registers
compiler.cfg.instructions
compiler.cfg.representations ;
compiler.cfg.instructions ;
IN: compiler.cfg.ssa.cssa
! Convert SSA to conventional SSA. This pass runs after representation
@ -24,7 +23,7 @@ IN: compiler.cfg.ssa.cssa
:: insert-copy ( bb src rep -- bb dst )
bb src insert-copy? [
rep next-vreg-rep :> dst
bb [ dst src rep src rep-of emit-conversion ] add-instructions
bb [ dst src rep ##copy ] add-instructions
bb dst
] [ bb src ] if ;

View File

@ -1,11 +1,11 @@
! Copyright (C) 2009 Slava Pestov.
! Copyright (C) 2009, 2010 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays assocs fry kernel namespaces
sequences sequences.deep
sets vectors
cpu.architecture
compiler.cfg.rpo
compiler.cfg.def-use
compiler.cfg.renaming
compiler.cfg.registers
compiler.cfg.dominance
compiler.cfg.instructions
@ -18,7 +18,20 @@ compiler.utilities ;
FROM: namespaces => set ;
IN: compiler.cfg.ssa.destruction
! Maps vregs to leaders.
! Because of the design of the register allocator, this pass
! has three peculiar properties.
!
! 1) Instead of renaming vreg usages in the CFG, a map from
! vregs to canonical representatives is computed. This allows
! the register allocator to use the original SSA names to get
! reaching definitions.
! 2) Useless ##copy instructions, and all ##phi instructions,
! are eliminated, so the register allocator does not have to
! remove any redundant operations.
! 3) A side effect of running this pass is that SSA liveness
! information is computed, so the register allocator does not
! need to compute it again.
SYMBOL: leader-map
: leader ( vreg -- vreg' ) leader-map get compress-path ;
@ -28,12 +41,15 @@ SYMBOL: class-element-map
: class-elements ( vreg -- elts ) class-element-map get at ;
<PRIVATE
! Sequence of vreg pairs
SYMBOL: copies
: init-coalescing ( -- )
H{ } clone leader-map set
H{ } clone class-element-map set
defs get keys
[ [ dup ] H{ } map>assoc leader-map set ]
[ [ dup 1vector ] H{ } map>assoc class-element-map set ] bi
V{ } clone copies set ;
: classes-interfere? ( vreg1 vreg2 -- ? )
@ -56,25 +72,27 @@ SYMBOL: copies
2bi
] if ;
: introduce-vreg ( vreg -- )
[ leader-map get conjoin ]
[ [ 1vector ] keep class-element-map get set-at ] bi ;
GENERIC: prepare-insn ( insn -- )
: try-to-coalesce ( dst src -- ) 2array copies get push ;
M: insn prepare-insn
[ defs-vreg ] [ uses-vregs ] bi
2dup empty? not and [
first
2dup [ rep-of ] bi@ eq?
[ try-to-coalesce ] [ 2drop ] if
] [ 2drop ] if ;
[ temp-vregs [ leader-map get conjoin ] each ]
[
[ defs-vreg ] [ uses-vregs ] bi
2dup empty? not and [
first
2dup [ rep-of reg-class-of ] bi@ eq?
[ try-to-coalesce ] [ 2drop ] if
] [ 2drop ] if
] bi ;
M: ##copy prepare-insn
[ dst>> ] [ src>> ] bi try-to-coalesce ;
M: ##tagged>integer prepare-insn
[ dst>> ] [ src>> ] bi eliminate-copy ;
M: ##phi prepare-insn
[ dst>> ] [ inputs>> values ] bi
[ eliminate-copy ] with each ;
@ -84,7 +102,6 @@ M: ##phi prepare-insn
: prepare-coalescing ( cfg -- )
init-coalescing
defs get keys [ introduce-vreg ] each
[ prepare-block ] each-basic-block ;
: process-copies ( -- )
@ -93,26 +110,31 @@ M: ##phi prepare-insn
[ 2drop ] [ eliminate-copy ] if
] assoc-each ;
: useless-copy? ( ##copy -- ? )
dup ##copy? [ [ dst>> ] [ src>> ] bi eq? ] [ drop f ] if ;
GENERIC: useful-insn? ( insn -- ? )
: perform-renaming ( cfg -- )
leader-map get keys [ dup leader ] H{ } map>assoc renamings set
[
instructions>> [
[ rename-insn-defs ]
[ rename-insn-uses ]
[ [ useless-copy? ] [ ##phi? ] bi or not ] tri
] filter! drop
] each-basic-block ;
: useful-copy? ( insn -- ? )
[ dst>> leader ] [ src>> leader ] bi eq? not ; inline
M: ##copy useful-insn? useful-copy? ;
M: ##tagged>integer useful-insn? useful-copy? ;
M: ##phi useful-insn? drop f ;
M: insn useful-insn? drop t ;
: cleanup-cfg ( cfg -- )
[ [ useful-insn? ] filter! ] simple-optimization ;
PRIVATE>
: destruct-ssa ( cfg -- cfg' )
needs-dominance
dup construct-cssa
dup compute-defs
compute-ssa-live-sets
dup compute-ssa-live-sets
dup compute-live-ranges
dup prepare-coalescing
process-copies
dup perform-renaming ;
dup cleanup-cfg ;

View File

@ -9,7 +9,7 @@ IN: compiler.cfg.ssa.interference.tests
: test-interference ( -- )
cfg new 0 get >>entry
compute-ssa-live-sets
dup compute-ssa-live-sets
dup compute-defs
compute-live-ranges ;

View File

@ -1,291 +0,0 @@
! Copyright (C) 2009 Daniel Ehrenberg
! See http://factorcode.org/license.txt for BSD license.
USING: kernel tools.test namespaces sequences vectors accessors sets
arrays math.ranges assocs
cpu.architecture
compiler.cfg
compiler.cfg.ssa.liveness.private
compiler.cfg.ssa.liveness
compiler.cfg.debugger
compiler.cfg.instructions
compiler.cfg.predecessors
compiler.cfg.registers
compiler.cfg.dominance
compiler.cfg.def-use ;
IN: compiler.cfg.ssa.liveness
[ t ] [ { 1 } 1 only? ] unit-test
[ t ] [ { } 1 only? ] unit-test
[ f ] [ { 2 1 } 1 only? ] unit-test
[ f ] [ { 2 } 1 only? ] unit-test
: test-liveness ( -- )
cfg new 0 get >>entry
dup compute-defs
dup compute-uses
needs-dominance
precompute-liveness ;
V{
T{ ##peek f 0 D 0 }
T{ ##replace f 0 D 0 }
T{ ##replace f 1 D 1 }
} 0 test-bb
V{
T{ ##replace f 2 D 0 }
} 1 test-bb
V{
T{ ##replace f 3 D 0 }
} 2 test-bb
0 { 1 2 } edges
[ ] [ test-liveness ] unit-test
[ H{ } ] [ back-edge-targets get ] unit-test
[ t ] [ 0 get R_q { 0 1 2 } [ get ] map unique = ] unit-test
[ t ] [ 1 get R_q { 1 } [ get ] map unique = ] unit-test
[ t ] [ 2 get R_q { 2 } [ get ] map unique = ] unit-test
: self-T_q ( n -- ? )
get [ T_q ] [ 1array unique ] bi = ;
[ t ] [ 0 self-T_q ] unit-test
[ t ] [ 1 self-T_q ] unit-test
[ t ] [ 2 self-T_q ] unit-test
[ f ] [ 0 0 get live-in? ] unit-test
[ t ] [ 1 0 get live-in? ] unit-test
[ t ] [ 2 0 get live-in? ] unit-test
[ t ] [ 3 0 get live-in? ] unit-test
[ f ] [ 0 0 get live-out? ] unit-test
[ f ] [ 1 0 get live-out? ] unit-test
[ t ] [ 2 0 get live-out? ] unit-test
[ t ] [ 3 0 get live-out? ] unit-test
[ f ] [ 0 1 get live-in? ] unit-test
[ f ] [ 1 1 get live-in? ] unit-test
[ t ] [ 2 1 get live-in? ] unit-test
[ f ] [ 3 1 get live-in? ] unit-test
[ f ] [ 0 1 get live-out? ] unit-test
[ f ] [ 1 1 get live-out? ] unit-test
[ f ] [ 2 1 get live-out? ] unit-test
[ f ] [ 3 1 get live-out? ] unit-test
[ f ] [ 0 2 get live-in? ] unit-test
[ f ] [ 1 2 get live-in? ] unit-test
[ f ] [ 2 2 get live-in? ] unit-test
[ t ] [ 3 2 get live-in? ] unit-test
[ f ] [ 0 2 get live-out? ] unit-test
[ f ] [ 1 2 get live-out? ] unit-test
[ f ] [ 2 2 get live-out? ] unit-test
[ f ] [ 3 2 get live-out? ] unit-test
V{ } 0 test-bb
V{ } 1 test-bb
V{ } 2 test-bb
V{ } 3 test-bb
V{
T{ ##phi f 2 H{ { 2 0 } { 3 1 } } }
} 4 test-bb
test-diamond
[ ] [ test-liveness ] unit-test
[ t ] [ 0 1 get live-in? ] unit-test
[ t ] [ 1 1 get live-in? ] unit-test
[ f ] [ 2 1 get live-in? ] unit-test
[ t ] [ 0 1 get live-out? ] unit-test
[ t ] [ 1 1 get live-out? ] unit-test
[ f ] [ 2 1 get live-out? ] unit-test
[ t ] [ 0 2 get live-in? ] unit-test
[ f ] [ 1 2 get live-in? ] unit-test
[ f ] [ 2 2 get live-in? ] unit-test
[ f ] [ 0 2 get live-out? ] unit-test
[ f ] [ 1 2 get live-out? ] unit-test
[ f ] [ 2 2 get live-out? ] unit-test
[ f ] [ 0 3 get live-in? ] unit-test
[ t ] [ 1 3 get live-in? ] unit-test
[ f ] [ 2 3 get live-in? ] unit-test
[ f ] [ 0 3 get live-out? ] unit-test
[ f ] [ 1 3 get live-out? ] unit-test
[ f ] [ 2 3 get live-out? ] unit-test
[ f ] [ 0 4 get live-in? ] unit-test
[ f ] [ 1 4 get live-in? ] unit-test
[ f ] [ 2 4 get live-in? ] unit-test
[ f ] [ 0 4 get live-out? ] unit-test
[ f ] [ 1 4 get live-out? ] unit-test
[ f ] [ 2 4 get live-out? ] unit-test
! This is the CFG in Figure 3 from the paper
V{ } 0 test-bb
V{ } 1 test-bb
0 1 edge
V{ } 2 test-bb
1 2 edge
V{
T{ ##peek f 0 D 0 }
T{ ##peek f 1 D 0 }
T{ ##peek f 2 D 0 }
} 3 test-bb
V{ } 11 test-bb
2 { 3 11 } edges
V{
T{ ##replace f 0 D 0 }
} 4 test-bb
V{ } 8 test-bb
3 { 8 4 } edges
V{
T{ ##replace f 1 D 0 }
} 9 test-bb
8 9 edge
V{
T{ ##replace f 2 D 0 }
} 5 test-bb
4 5 edge
V{ } 10 test-bb
V{ } 6 test-bb
5 6 edge
9 { 6 10 } edges
V{ } 7 test-bb
6 { 5 7 } edges
10 8 edge
7 2 edge
[ ] [ test-liveness ] unit-test
[ t ] [ 1 get R_q 1 11 [a,b] [ get ] map unique = ] unit-test
[ t ] [ 2 get R_q 2 11 [a,b] [ get ] map unique = ] unit-test
[ t ] [ 3 get R_q 3 10 [a,b] [ get ] map unique = ] unit-test
[ t ] [ 4 get R_q 4 7 [a,b] [ get ] map unique = ] unit-test
[ t ] [ 5 get R_q 5 7 [a,b] [ get ] map unique = ] unit-test
[ t ] [ 6 get R_q 6 7 [a,b] [ get ] map unique = ] unit-test
[ t ] [ 7 get R_q 7 7 [a,b] [ get ] map unique = ] unit-test
[ t ] [ 8 get R_q 6 10 [a,b] [ get ] map unique = ] unit-test
[ t ] [ 9 get R_q 8 6 10 [a,b] remove [ get ] map unique = ] unit-test
[ t ] [ 10 get R_q 10 10 [a,b] [ get ] map unique = ] unit-test
[ t ] [ 11 get R_q 11 11 [a,b] [ get ] map unique = ] unit-test
[ t ] [ 1 get T_q 1 get 1array unique = ] unit-test
[ t ] [ 2 get T_q 2 get 1array unique = ] unit-test
[ t ] [ 3 get T_q 3 get 2 get 2array unique = ] unit-test
[ t ] [ 4 get T_q 4 get 2 get 2array unique = ] unit-test
[ t ] [ 5 get T_q 5 get 2 get 2array unique = ] unit-test
[ t ] [ 6 get T_q { 6 2 5 } [ get ] map unique = ] unit-test
[ t ] [ 7 get T_q { 7 2 } [ get ] map unique = ] unit-test
[ t ] [ 8 get T_q { 8 2 5 } [ get ] map unique = ] unit-test
[ t ] [ 9 get T_q { 2 5 8 9 } [ get ] map unique = ] unit-test
[ t ] [ 10 get T_q { 2 5 8 10 } [ get ] map unique = ] unit-test
[ t ] [ 11 get T_q 11 get 1array unique = ] unit-test
[ f ] [ 1 get back-edge-target? ] unit-test
[ t ] [ 2 get back-edge-target? ] unit-test
[ f ] [ 3 get back-edge-target? ] unit-test
[ f ] [ 4 get back-edge-target? ] unit-test
[ t ] [ 5 get back-edge-target? ] unit-test
[ f ] [ 6 get back-edge-target? ] unit-test
[ f ] [ 7 get back-edge-target? ] unit-test
[ t ] [ 8 get back-edge-target? ] unit-test
[ f ] [ 9 get back-edge-target? ] unit-test
[ f ] [ 10 get back-edge-target? ] unit-test
[ f ] [ 11 get back-edge-target? ] unit-test
[ f ] [ 0 1 get live-in? ] unit-test
[ f ] [ 1 1 get live-in? ] unit-test
[ f ] [ 2 1 get live-in? ] unit-test
[ f ] [ 0 1 get live-out? ] unit-test
[ f ] [ 1 1 get live-out? ] unit-test
[ f ] [ 2 1 get live-out? ] unit-test
[ f ] [ 0 2 get live-in? ] unit-test
[ f ] [ 1 2 get live-in? ] unit-test
[ f ] [ 2 2 get live-in? ] unit-test
[ f ] [ 0 2 get live-out? ] unit-test
[ f ] [ 1 2 get live-out? ] unit-test
[ f ] [ 2 2 get live-out? ] unit-test
[ f ] [ 0 3 get live-in? ] unit-test
[ f ] [ 1 3 get live-in? ] unit-test
[ f ] [ 2 3 get live-in? ] unit-test
[ t ] [ 0 3 get live-out? ] unit-test
[ t ] [ 1 3 get live-out? ] unit-test
[ t ] [ 2 3 get live-out? ] unit-test
[ t ] [ 0 4 get live-in? ] unit-test
[ f ] [ 1 4 get live-in? ] unit-test
[ t ] [ 2 4 get live-in? ] unit-test
[ f ] [ 0 4 get live-out? ] unit-test
[ f ] [ 1 4 get live-out? ] unit-test
[ t ] [ 2 4 get live-out? ] unit-test
[ f ] [ 0 5 get live-in? ] unit-test
[ f ] [ 1 5 get live-in? ] unit-test
[ t ] [ 2 5 get live-in? ] unit-test
[ f ] [ 0 5 get live-out? ] unit-test
[ f ] [ 1 5 get live-out? ] unit-test
[ t ] [ 2 5 get live-out? ] unit-test
[ f ] [ 0 6 get live-in? ] unit-test
[ f ] [ 1 6 get live-in? ] unit-test
[ t ] [ 2 6 get live-in? ] unit-test
[ f ] [ 0 6 get live-out? ] unit-test
[ f ] [ 1 6 get live-out? ] unit-test
[ t ] [ 2 6 get live-out? ] unit-test
[ f ] [ 0 7 get live-in? ] unit-test
[ f ] [ 1 7 get live-in? ] unit-test
[ f ] [ 2 7 get live-in? ] unit-test
[ f ] [ 0 7 get live-out? ] unit-test
[ f ] [ 1 7 get live-out? ] unit-test
[ f ] [ 2 7 get live-out? ] unit-test
[ f ] [ 0 8 get live-in? ] unit-test
[ t ] [ 1 8 get live-in? ] unit-test
[ t ] [ 2 8 get live-in? ] unit-test
[ f ] [ 0 8 get live-out? ] unit-test
[ t ] [ 1 8 get live-out? ] unit-test
[ t ] [ 2 8 get live-out? ] unit-test
[ f ] [ 0 9 get live-in? ] unit-test
[ t ] [ 1 9 get live-in? ] unit-test
[ t ] [ 2 9 get live-in? ] unit-test
[ f ] [ 0 9 get live-out? ] unit-test
[ t ] [ 1 9 get live-out? ] unit-test
[ t ] [ 2 9 get live-out? ] unit-test
[ f ] [ 0 10 get live-in? ] unit-test
[ t ] [ 1 10 get live-in? ] unit-test
[ t ] [ 2 10 get live-in? ] unit-test
[ f ] [ 0 10 get live-out? ] unit-test
[ t ] [ 1 10 get live-out? ] unit-test
[ t ] [ 2 10 get live-out? ] unit-test
[ f ] [ 0 11 get live-in? ] unit-test
[ f ] [ 1 11 get live-in? ] unit-test
[ f ] [ 2 11 get live-in? ] unit-test
[ f ] [ 0 11 get live-out? ] unit-test
[ f ] [ 1 11 get live-out? ] unit-test
[ f ] [ 2 11 get live-out? ] unit-test

View File

@ -1,130 +0,0 @@
! Copyright (C) 2009 Daniel Ehrenberg
! See http://factorcode.org/license.txt for BSD license.
USING: kernel sequences assocs accessors
namespaces fry math sets combinators locals
compiler.cfg.rpo
compiler.cfg.dominance
compiler.cfg.def-use
compiler.cfg.instructions ;
FROM: namespaces => set ;
IN: compiler.cfg.ssa.liveness
! Liveness checking on SSA IR, as described in
! "Fast Liveness Checking for SSA-Form Programs", Sebastian Hack et al.
! http://hal.archives-ouvertes.fr/docs/00/19/22/19/PDF/fast_liveness.pdf
<PRIVATE
! The sets T_q and R_q are described there
SYMBOL: T_q-sets
SYMBOL: R_q-sets
! Targets of back edges
SYMBOL: back-edge-targets
: T_q ( q -- T_q )
T_q-sets get at ;
: R_q ( q -- R_q )
R_q-sets get at ;
: back-edge-target? ( block -- ? )
back-edge-targets get key? ;
: next-R_q ( q -- R_q )
[ ] [ successors>> ] [ number>> ] tri
'[ number>> _ >= ] filter
[ R_q ] map assoc-combine
[ conjoin ] keep ;
: set-R_q ( q -- )
[ next-R_q ] keep R_q-sets get set-at ;
: set-back-edges ( q -- )
[ successors>> ] [ number>> ] bi '[
dup number>> _ <
[ back-edge-targets get conjoin ] [ drop ] if
] each ;
: init-R_q ( -- )
H{ } clone R_q-sets set
H{ } clone back-edge-targets set ;
: compute-R_q ( cfg -- )
init-R_q
post-order [
[ set-R_q ] [ set-back-edges ] bi
] each ;
! This algorithm for computing T_q uses equation (1)
! but not the faster algorithm described in the paper
: back-edges-from ( q -- edges )
R_q keys [
[ successors>> ] [ number>> ] bi
'[ number>> _ < ] filter
] gather ;
: T^_q ( q -- T^_q )
[ back-edges-from ] [ R_q ] bi
'[ _ key? not ] filter ;
: next-T_q ( q -- T_q )
dup dup T^_q [ next-T_q keys ] map
concat unique [ conjoin ] keep
[ swap T_q-sets get set-at ] keep ;
: compute-T_q ( cfg -- )
H{ } T_q-sets set
[ next-T_q drop ] each-basic-block ;
PRIVATE>
: precompute-liveness ( cfg -- )
[ compute-R_q ] [ compute-T_q ] bi ;
<PRIVATE
! This doesn't take advantage of ordering T_q,a so you
! only have to check one if the CFG is reducible.
! It should be changed to be more efficient.
: only? ( seq obj -- ? )
'[ _ eq? ] all? ;
: strictly-dominates? ( bb1 bb2 -- ? )
[ dominates? ] [ eq? not ] 2bi and ;
: T_q,a ( a q -- T_q,a )
! This could take advantage of the structure of dominance,
! but probably I'll replace it with the algorithm that works
! on reducible CFGs anyway
T_q keys swap def-of
[ '[ _ swap strictly-dominates? ] filter ] when* ;
: live? ( vreg node quot -- ? )
[ [ T_q,a ] [ drop uses-of ] 2bi ] dip
'[ [ R_q keys _ ] keep @ intersects? ] any? ; inline
PRIVATE>
: live-in? ( vreg node -- ? )
[ drop ] live? ;
<PRIVATE
: (live-out?) ( vreg node -- ? )
dup dup dup '[
_ = _ back-edge-target? not and
[ _ swap remove ] when
] live? ;
PRIVATE>
:: live-out? ( vreg node -- ? )
vreg def-of :> def
{
{ [ node def eq? ] [ vreg uses-of def only? not ] }
{ [ def node strictly-dominates? ] [ vreg node (live-out?) ] }
[ f ]
} cond ;

Some files were not shown because too many files have changed in this diff Show More