2010-04-21 03:08:52 -04:00
|
|
|
! Copyright (C) 2008, 2010 Slava Pestov.
|
2008-10-22 19:37:47 -04:00
|
|
|
! See http://factorcode.org/license.txt for BSD license.
|
2008-12-06 10:16:29 -05:00
|
|
|
USING: kernel math namespaces assocs hashtables sequences arrays
|
2009-10-02 00:03:17 -04:00
|
|
|
accessors words vectors combinators combinators.short-circuit
|
2010-05-03 18:20:28 -04:00
|
|
|
sets classes layouts fry cpu.architecture
|
2009-10-02 00:03:17 -04:00
|
|
|
compiler.cfg
|
|
|
|
compiler.cfg.rpo
|
|
|
|
compiler.cfg.def-use
|
|
|
|
compiler.cfg.liveness
|
|
|
|
compiler.cfg.registers
|
2010-04-24 02:38:43 -04:00
|
|
|
compiler.cfg.utilities
|
2009-10-02 00:03:17 -04:00
|
|
|
compiler.cfg.comparisons
|
|
|
|
compiler.cfg.instructions
|
|
|
|
compiler.cfg.representations.preferred ;
|
2010-02-26 16:01:01 -05:00
|
|
|
FROM: namespaces => set ;
|
2008-10-22 19:37:47 -04:00
|
|
|
IN: compiler.cfg.alias-analysis
|
|
|
|
|
2009-05-26 20:31:19 -04:00
|
|
|
! We try to eliminate redundant slot operations using some simple heuristics.
|
2008-10-22 19:37:47 -04:00
|
|
|
!
|
|
|
|
! All heap-allocated objects which are loaded from the stack, or
|
|
|
|
! other object slots are pessimistically assumed to belong to
|
|
|
|
! the same alias class.
|
|
|
|
!
|
|
|
|
! Freshly-allocated objects get their own alias class.
|
|
|
|
!
|
|
|
|
! Simple pseudo-C example showing load elimination:
|
|
|
|
!
|
|
|
|
! int *x, *y, z: inputs
|
|
|
|
! int a, b, c, d, e: locals
|
|
|
|
!
|
|
|
|
! Before alias analysis:
|
|
|
|
!
|
|
|
|
! a = x[2]
|
|
|
|
! b = x[2]
|
|
|
|
! c = x[3]
|
|
|
|
! y[2] = z
|
|
|
|
! d = x[2]
|
|
|
|
! e = y[2]
|
|
|
|
! f = x[3]
|
|
|
|
!
|
|
|
|
! After alias analysis:
|
|
|
|
!
|
|
|
|
! a = x[2]
|
|
|
|
! b = a /* ELIMINATED */
|
|
|
|
! c = x[3]
|
|
|
|
! y[2] = z
|
|
|
|
! d = x[2] /* if x=y, d=z, if x!=y, d=b; NOT ELIMINATED */
|
|
|
|
! e = z /* ELIMINATED */
|
|
|
|
! f = c /* ELIMINATED */
|
|
|
|
!
|
|
|
|
! Simple pseudo-C example showing store elimination:
|
|
|
|
!
|
|
|
|
! Before alias analysis:
|
|
|
|
!
|
|
|
|
! x[0] = a
|
|
|
|
! b = x[n]
|
|
|
|
! x[0] = c
|
|
|
|
! x[1] = d
|
|
|
|
! e = x[0]
|
|
|
|
! x[1] = c
|
|
|
|
!
|
|
|
|
! After alias analysis:
|
|
|
|
!
|
|
|
|
! x[0] = a /* dead if n = 0, live otherwise; NOT ELIMINATED */
|
|
|
|
! b = x[n]
|
|
|
|
! x[0] = c
|
|
|
|
! /* x[1] = d */ /* ELIMINATED */
|
|
|
|
! e = c
|
|
|
|
! x[1] = c
|
|
|
|
|
2010-04-30 18:17:52 -04:00
|
|
|
! Local copy propagation
|
|
|
|
SYMBOL: copies
|
|
|
|
|
|
|
|
: resolve ( vreg -- vreg ) copies get ?at drop ;
|
|
|
|
|
|
|
|
: record-copy ( ##copy -- )
|
|
|
|
[ src>> resolve ] [ dst>> ] bi copies get set-at ; inline
|
|
|
|
|
2008-10-22 19:37:47 -04:00
|
|
|
! Map vregs -> alias classes
|
|
|
|
SYMBOL: vregs>acs
|
|
|
|
|
2009-05-28 19:19:01 -04:00
|
|
|
ERROR: vreg-ac-not-set vreg ;
|
|
|
|
|
2008-10-22 19:37:47 -04:00
|
|
|
: vreg>ac ( vreg -- ac )
|
|
|
|
#! Only vregs produced by ##allot, ##peek and ##slot can
|
|
|
|
#! ever be used as valid inputs to ##slot and ##set-slot,
|
|
|
|
#! so we assert this fact by not giving alias classes to
|
|
|
|
#! other vregs.
|
2009-05-28 19:19:01 -04:00
|
|
|
vregs>acs get ?at [ vreg-ac-not-set ] unless ;
|
2008-10-22 19:37:47 -04:00
|
|
|
|
|
|
|
! Map alias classes -> sequence of vregs
|
|
|
|
SYMBOL: acs>vregs
|
|
|
|
|
|
|
|
: ac>vregs ( ac -- vregs ) acs>vregs get at ;
|
|
|
|
|
2010-04-30 18:17:52 -04:00
|
|
|
: aliases ( vreg -- vregs )
|
2008-10-22 19:37:47 -04:00
|
|
|
#! All vregs which may contain the same value as vreg.
|
|
|
|
vreg>ac ac>vregs ;
|
|
|
|
|
|
|
|
: each-alias ( vreg quot -- )
|
|
|
|
[ aliases ] dip each ; inline
|
|
|
|
|
2010-05-03 18:20:28 -04:00
|
|
|
: merge-acs ( vreg into -- )
|
|
|
|
[ vreg>ac ] dip
|
|
|
|
2dup eq? [ 2drop ] [
|
|
|
|
[ ac>vregs ] dip
|
|
|
|
[ vregs>acs get '[ [ _ ] dip _ set-at ] each ]
|
|
|
|
[ acs>vregs get at push-all ]
|
|
|
|
2bi
|
|
|
|
] if ;
|
|
|
|
|
2008-10-22 19:37:47 -04:00
|
|
|
! Map vregs -> slot# -> vreg
|
|
|
|
SYMBOL: live-slots
|
|
|
|
|
|
|
|
! Current instruction number
|
|
|
|
SYMBOL: insn#
|
|
|
|
|
|
|
|
! Load/store history, for dead store elimination
|
|
|
|
TUPLE: load insn# ;
|
|
|
|
TUPLE: store insn# ;
|
|
|
|
|
|
|
|
: new-action ( class -- action )
|
|
|
|
insn# get swap boa ; inline
|
|
|
|
|
|
|
|
! Maps vreg -> slot# -> sequence of loads/stores
|
|
|
|
SYMBOL: histories
|
|
|
|
|
|
|
|
: history ( vreg -- history ) histories get at ;
|
|
|
|
|
|
|
|
: set-ac ( vreg ac -- )
|
|
|
|
#! Set alias class of newly-seen vreg.
|
|
|
|
{
|
|
|
|
[ drop H{ } clone swap histories get set-at ]
|
|
|
|
[ drop H{ } clone swap live-slots get set-at ]
|
|
|
|
[ swap vregs>acs get set-at ]
|
|
|
|
[ acs>vregs get push-at ]
|
|
|
|
} 2cleave ;
|
|
|
|
|
|
|
|
: live-slot ( slot#/f vreg -- vreg' )
|
|
|
|
#! If the slot number is unknown, we never reuse a previous
|
|
|
|
#! value.
|
|
|
|
over [ live-slots get at at ] [ 2drop f ] if ;
|
|
|
|
|
2009-05-28 19:19:01 -04:00
|
|
|
ERROR: vreg-has-no-slots vreg ;
|
|
|
|
|
2008-10-22 19:37:47 -04:00
|
|
|
: load-constant-slot ( value slot# vreg -- )
|
2009-05-28 19:19:01 -04:00
|
|
|
live-slots get ?at [ vreg-has-no-slots ] unless set-at ;
|
2008-10-22 19:37:47 -04:00
|
|
|
|
|
|
|
: load-slot ( value slot#/f vreg -- )
|
|
|
|
over [ load-constant-slot ] [ 3drop ] if ;
|
|
|
|
|
|
|
|
: record-constant-slot ( slot# vreg -- )
|
|
|
|
#! A load can potentially read every store of this slot#
|
|
|
|
#! in that alias class.
|
|
|
|
[
|
|
|
|
history [ load new-action swap ?push ] change-at
|
|
|
|
] with each-alias ;
|
|
|
|
|
|
|
|
: record-computed-slot ( vreg -- )
|
|
|
|
#! Computed load is like a load of every slot touched so far
|
|
|
|
[
|
|
|
|
history values [ load new-action swap push ] each
|
|
|
|
] each-alias ;
|
|
|
|
|
|
|
|
: remember-slot ( value slot#/f vreg -- )
|
|
|
|
over
|
|
|
|
[ [ record-constant-slot ] [ load-constant-slot ] 2bi ]
|
|
|
|
[ 2nip record-computed-slot ] if ;
|
|
|
|
|
|
|
|
SYMBOL: ac-counter
|
|
|
|
|
|
|
|
: next-ac ( -- n )
|
2009-08-13 20:21:44 -04:00
|
|
|
ac-counter [ dup 1 + ] change ;
|
2008-10-22 19:37:47 -04:00
|
|
|
|
|
|
|
! Alias class for objects which are loaded from the data stack
|
|
|
|
! or other object slots. We pessimistically assume that they
|
|
|
|
! can all alias each other.
|
|
|
|
SYMBOL: heap-ac
|
|
|
|
|
|
|
|
: set-heap-ac ( vreg -- ) heap-ac get set-ac ;
|
|
|
|
|
|
|
|
: set-new-ac ( vreg -- ) next-ac set-ac ;
|
|
|
|
|
|
|
|
: kill-constant-set-slot ( slot# vreg -- )
|
|
|
|
[ live-slots get at delete-at ] with each-alias ;
|
|
|
|
|
|
|
|
: record-constant-set-slot ( slot# vreg -- )
|
|
|
|
history [
|
2009-05-25 17:38:33 -04:00
|
|
|
dup empty? [ dup last store? [ dup pop* ] when ] unless
|
2008-10-22 19:37:47 -04:00
|
|
|
store new-action swap ?push
|
|
|
|
] change-at ;
|
|
|
|
|
|
|
|
: kill-computed-set-slot ( ac -- )
|
|
|
|
[ live-slots get at clear-assoc ] each-alias ;
|
|
|
|
|
|
|
|
: remember-set-slot ( slot#/f vreg -- )
|
|
|
|
over [
|
|
|
|
[ record-constant-set-slot ]
|
2010-05-03 18:20:28 -04:00
|
|
|
[ kill-constant-set-slot ]
|
|
|
|
2bi
|
2008-10-22 19:37:47 -04:00
|
|
|
] [ nip kill-computed-set-slot ] if ;
|
|
|
|
|
|
|
|
GENERIC: insn-slot# ( insn -- slot#/f )
|
|
|
|
GENERIC: insn-object ( insn -- vreg )
|
|
|
|
|
2010-04-21 03:08:52 -04:00
|
|
|
M: ##slot insn-slot# drop f ;
|
2008-10-22 19:37:47 -04:00
|
|
|
M: ##slot-imm insn-slot# slot>> ;
|
2010-04-21 03:08:52 -04:00
|
|
|
M: ##set-slot insn-slot# drop f ;
|
2008-10-22 19:37:47 -04:00
|
|
|
M: ##set-slot-imm insn-slot# slot>> ;
|
2008-12-06 10:16:29 -05:00
|
|
|
M: ##alien-global insn-slot# [ library>> ] [ symbol>> ] bi 2array ;
|
2010-04-01 20:06:18 -04:00
|
|
|
M: ##vm-field insn-slot# offset>> ;
|
|
|
|
M: ##set-vm-field insn-slot# offset>> ;
|
2008-10-22 19:37:47 -04:00
|
|
|
|
|
|
|
M: ##slot insn-object obj>> resolve ;
|
|
|
|
M: ##slot-imm insn-object obj>> resolve ;
|
|
|
|
M: ##set-slot insn-object obj>> resolve ;
|
|
|
|
M: ##set-slot-imm insn-object obj>> resolve ;
|
2008-12-06 10:16:29 -05:00
|
|
|
M: ##alien-global insn-object drop \ ##alien-global ;
|
2010-04-01 20:06:18 -04:00
|
|
|
M: ##vm-field insn-object drop \ ##vm-field ;
|
|
|
|
M: ##set-vm-field insn-object drop \ ##vm-field ;
|
2008-10-22 19:37:47 -04:00
|
|
|
|
2009-07-22 04:08:28 -04:00
|
|
|
: init-alias-analysis ( insns -- insns' )
|
2008-10-22 19:37:47 -04:00
|
|
|
H{ } clone histories set
|
|
|
|
H{ } clone vregs>acs set
|
|
|
|
H{ } clone acs>vregs set
|
|
|
|
H{ } clone live-slots set
|
|
|
|
H{ } clone copies set
|
2009-10-02 00:03:17 -04:00
|
|
|
|
2008-10-22 19:37:47 -04:00
|
|
|
0 ac-counter set
|
2009-05-28 03:48:58 -04:00
|
|
|
next-ac heap-ac set
|
|
|
|
|
2010-04-01 20:06:18 -04:00
|
|
|
\ ##vm-field set-new-ac
|
2009-10-02 00:03:17 -04:00
|
|
|
\ ##alien-global set-new-ac
|
|
|
|
|
2009-07-22 07:07:28 -04:00
|
|
|
dup local-live-in [ set-heap-ac ] each ;
|
2008-10-22 19:37:47 -04:00
|
|
|
|
|
|
|
GENERIC: analyze-aliases* ( insn -- insn' )
|
|
|
|
|
2009-09-02 07:22:37 -04:00
|
|
|
M: insn analyze-aliases*
|
2009-10-02 00:03:17 -04:00
|
|
|
! If an instruction defines a value with a non-integer
|
|
|
|
! representation it means that the value will be boxed
|
|
|
|
! anywhere its used as a tagged pointer. Boxing allocates
|
|
|
|
! a new value, except boxing instructions haven't been
|
|
|
|
! inserted yet.
|
|
|
|
dup defs-vreg [
|
2010-04-19 15:05:55 -04:00
|
|
|
over defs-vreg-rep { int-rep tagged-rep } member?
|
2009-10-02 00:03:17 -04:00
|
|
|
[ set-heap-ac ] [ set-new-ac ] if
|
|
|
|
] when* ;
|
|
|
|
|
|
|
|
M: ##phi analyze-aliases*
|
|
|
|
dup defs-vreg set-heap-ac ;
|
2009-09-02 07:22:37 -04:00
|
|
|
|
2009-05-27 19:55:49 -04:00
|
|
|
M: ##allocation analyze-aliases*
|
2008-11-03 02:52:55 -05:00
|
|
|
#! A freshly allocated object is distinct from any other
|
|
|
|
#! object.
|
|
|
|
dup dst>> set-new-ac ;
|
|
|
|
|
2010-05-13 01:46:58 -04:00
|
|
|
M: ##box-displaced-alien analyze-aliases*
|
|
|
|
[ call-next-method ]
|
|
|
|
[ base>> heap-ac get merge-acs ] bi ;
|
|
|
|
|
2008-10-22 19:37:47 -04:00
|
|
|
M: ##read analyze-aliases*
|
2009-05-29 02:39:14 -04:00
|
|
|
call-next-method
|
2008-10-22 19:37:47 -04:00
|
|
|
dup [ dst>> ] [ insn-slot# ] [ insn-object ] tri
|
2010-04-24 02:38:43 -04:00
|
|
|
2dup live-slot dup
|
|
|
|
[ 2nip <copy> analyze-aliases* nip ]
|
|
|
|
[ drop remember-slot ]
|
|
|
|
if ;
|
2008-10-22 19:37:47 -04:00
|
|
|
|
|
|
|
: idempotent? ( value slot#/f vreg -- ? )
|
|
|
|
#! Are we storing a value back to the same slot it was read
|
|
|
|
#! from?
|
|
|
|
live-slot = ;
|
|
|
|
|
|
|
|
M: ##write analyze-aliases*
|
|
|
|
dup
|
|
|
|
[ src>> resolve ] [ insn-slot# ] [ insn-object ] tri
|
2010-04-30 18:17:52 -04:00
|
|
|
3dup idempotent? [ 3drop ] [
|
2010-05-03 18:20:28 -04:00
|
|
|
[ 2drop heap-ac get merge-acs ]
|
|
|
|
[ remember-set-slot drop ]
|
|
|
|
[ load-slot ]
|
|
|
|
3tri
|
2010-04-30 18:17:52 -04:00
|
|
|
] if ;
|
2008-10-22 19:37:47 -04:00
|
|
|
|
|
|
|
M: ##copy analyze-aliases*
|
|
|
|
#! The output vreg gets the same alias class as the input
|
|
|
|
#! vreg, since they both contain the same value.
|
|
|
|
dup record-copy ;
|
|
|
|
|
2009-10-02 00:03:17 -04:00
|
|
|
: useless-compare? ( insn -- ? )
|
|
|
|
{
|
|
|
|
[ cc>> cc= eq? ]
|
2009-10-02 00:54:19 -04:00
|
|
|
[ [ src1>> ] [ src2>> ] bi [ resolve vreg>ac ] bi@ = not ]
|
2009-10-02 00:03:17 -04:00
|
|
|
} 1&& ; inline
|
|
|
|
|
|
|
|
M: ##compare analyze-aliases*
|
2009-10-02 00:20:05 -04:00
|
|
|
call-next-method
|
2009-10-02 00:03:17 -04:00
|
|
|
dup useless-compare? [
|
2010-04-21 03:08:52 -04:00
|
|
|
dst>> f \ ##load-reference new-insn
|
2009-10-02 00:03:17 -04:00
|
|
|
analyze-aliases*
|
|
|
|
] when ;
|
|
|
|
|
2008-10-22 19:37:47 -04:00
|
|
|
: analyze-aliases ( insns -- insns' )
|
|
|
|
[ insn# set analyze-aliases* ] map-index sift ;
|
|
|
|
|
|
|
|
SYMBOL: live-stores
|
|
|
|
|
|
|
|
: compute-live-stores ( -- )
|
|
|
|
histories get
|
|
|
|
values [
|
|
|
|
values [ [ store? ] filter [ insn#>> ] map ] map concat
|
2010-02-28 22:55:22 -05:00
|
|
|
] map concat fast-set
|
2008-10-22 19:37:47 -04:00
|
|
|
live-stores set ;
|
|
|
|
|
|
|
|
GENERIC: eliminate-dead-stores* ( insn -- insn' )
|
|
|
|
|
|
|
|
: (eliminate-dead-stores) ( insn -- insn' )
|
|
|
|
dup insn-slot# [
|
2010-02-28 22:42:10 -05:00
|
|
|
insn# get live-stores get in? [
|
2008-10-22 19:37:47 -04:00
|
|
|
drop f
|
|
|
|
] unless
|
|
|
|
] when ;
|
|
|
|
|
|
|
|
M: ##set-slot eliminate-dead-stores* (eliminate-dead-stores) ;
|
|
|
|
|
|
|
|
M: ##set-slot-imm eliminate-dead-stores* (eliminate-dead-stores) ;
|
|
|
|
|
|
|
|
M: insn eliminate-dead-stores* ;
|
|
|
|
|
|
|
|
: eliminate-dead-stores ( insns -- insns' )
|
|
|
|
[ insn# set eliminate-dead-stores* ] map-index sift ;
|
|
|
|
|
2009-05-26 20:56:56 -04:00
|
|
|
: alias-analysis-step ( insns -- insns' )
|
2009-07-22 04:08:28 -04:00
|
|
|
init-alias-analysis
|
2009-05-26 20:56:56 -04:00
|
|
|
analyze-aliases
|
|
|
|
compute-live-stores
|
|
|
|
eliminate-dead-stores ;
|
2009-05-26 20:31:19 -04:00
|
|
|
|
2010-04-30 18:55:20 -04:00
|
|
|
: alias-analysis ( cfg -- cfg )
|
|
|
|
dup [ alias-analysis-step ] simple-optimization ;
|