! Joining blocks that are not calls and are connected by a single CFG edge.
! Predecessors must be recomputed after this. Also this pass does not
! update ##phi nodes and should therefore only run before stack analysis.
-
-: kill-vreg-block? ( bb -- ? )
- instructions>> {
- [ length 2 >= ]
- [ penultimate kill-vreg-insn? ]
- } 1&& ;
-
: predecessor ( bb -- pred )
predecessors>> first ; inline
: join-block? ( bb -- ? )
{
+ [ kill-block? not ]
[ predecessors>> length 1 = ]
- [ predecessor kill-vreg-block? not ]
+ [ predecessor kill-block? not ]
[ predecessor successors>> length 1 = ]
[ [ predecessor ] keep back-edge? not ]
} 1&& ;
GENERIC: compute-stack-frame* ( insn -- )
: request-stack-frame ( stack-frame -- )
+ frame-required? on
stack-frame [ max-stack-frame ] change ;
-M: ##stack-frame compute-stack-frame*
- frame-required? on
+M: ##alien-invoke compute-stack-frame*
+ stack-frame>> request-stack-frame ;
+
+M: ##alien-indirect compute-stack-frame*
+ stack-frame>> request-stack-frame ;
+
+M: ##alien-callback compute-stack-frame*
stack-frame>> request-stack-frame ;
M: ##call compute-stack-frame*
GENERIC: insert-pro/epilogues* ( insn -- )
-M: ##stack-frame insert-pro/epilogues* drop ;
-
M: ##prologue insert-pro/epilogues*
drop frame-required? get [ stack-frame get _prologue ] when ;
IN: compiler.cfg.builder.tests
-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 arrays locals byte-arrays
-kernel.private math ;
+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.predecessors compiler.cfg.checker arrays locals
+byte-arrays kernel.private math slots.private ;
! Just ensure that various CFGs build correctly.
-: unit-test-cfg ( quot -- ) '[ _ test-cfg drop ] [ ] swap unit-test ;
+: unit-test-cfg ( quot -- )
+ '[ _ test-cfg [ compute-predecessors check-cfg ] each ] [ ] swap unit-test ;
{
[ ]
[ "int" f "malloc" { "int" } alien-invoke ]
[ "int" { "int" } "cdecl" alien-indirect ]
[ "int" { "int" } "cdecl" [ ] alien-callback ]
+ [ swap - + * ]
+ [ swap slot ]
} [
unit-test-cfg
] each
basic-block get successors>> push
basic-block off ;
+: emit-trivial-block ( quot -- )
+ basic-block get instructions>> empty? [ ##branch begin-basic-block ] unless
+ call
+ ##branch begin-basic-block ; inline
+
: emit-call ( word height -- )
over loops get key?
[ drop loops get at emit-loop-call ]
- [ ##call ##branch begin-basic-block ]
+ [ [ ##call ] emit-trivial-block ]
if ;
! #recursive
! #return
M: #return emit-node
- drop ##epilogue ##return ;
+ drop ##branch begin-basic-block ##epilogue ##return ;
M: #return-recursive emit-node
label>> id>> loops get key?
[ return>> return-size >>return ]
[ alien-parameters parameter-sizes drop >>params ] bi ;
-: alien-stack-frame ( params -- )
- <alien-stack-frame> ##stack-frame ;
-
: emit-alien-node ( node quot -- )
- [ params>> ] dip [ drop alien-stack-frame ] [ call ] 2bi
- ##branch begin-basic-block ; inline
+ [
+ [ params>> dup <alien-stack-frame> ] dip call
+ ] emit-trivial-block ; inline
M: #alien-invoke emit-node
[ ##alien-invoke ] emit-alien-node ;
! Copyright (C) 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel compiler.cfg.instructions compiler.cfg.rpo
-compiler.cfg.def-use compiler.cfg.linearization compiler.cfg.liveness
-combinators.short-circuit accessors math sequences sets assocs ;
+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.liveness
+compiler.cfg.utilities ;
IN: compiler.cfg.checker
-ERROR: last-insn-not-a-jump insn ;
+ERROR: bad-kill-block bb ;
+
+: check-kill-block ( bb -- )
+ dup instructions>> first2
+ swap ##epilogue? [ [ ##return? ] [ ##callback-return? ] bi or ] [ ##branch? ] if
+ [ drop ] [ bad-kill-block ] if ;
+
+ERROR: last-insn-not-a-jump bb ;
: check-last-instruction ( bb -- )
- last dup {
+ dup instructions>> last {
[ ##branch? ]
[ ##dispatch? ]
[ ##conditional-branch? ]
[ ##compare-imm-branch? ]
- [ ##return? ]
- [ ##callback-return? ]
- [ ##jump? ]
[ ##fixnum-add? ]
[ ##fixnum-sub? ]
[ ##fixnum-mul? ]
[ ##no-tco? ]
} 1|| [ drop ] [ last-insn-not-a-jump ] if ;
-ERROR: bad-loop-entry ;
+ERROR: bad-loop-entry bb ;
: check-loop-entry ( bb -- )
- dup length 2 >= [
+ dup instructions>> dup length 2 >= [
2 head* [ ##loop-entry? ] any?
- [ bad-loop-entry ] when
- ] [ drop ] if ;
+ [ bad-loop-entry ] [ drop ] if
+ ] [ 2drop ] if ;
+
+ERROR: bad-kill-insn bb ;
+
+: check-kill-instructions ( bb -- )
+ dup instructions>> [ kill-vreg-insn? ] any?
+ [ bad-kill-insn ] [ drop ] if ;
+
+: check-normal-block ( bb -- )
+ [ check-loop-entry ]
+ [ check-last-instruction ]
+ [ check-kill-instructions ]
+ tri ;
ERROR: bad-successors ;
[ bad-successors ] unless ;
: check-basic-block ( bb -- )
- [ instructions>> check-last-instruction ]
- [ instructions>> check-loop-entry ]
+ [ dup kill-block? [ check-kill-block ] [ check-normal-block ] if ]
[ check-successors ]
- tri ;
+ bi ;
ERROR: bad-live-in ;
USING: tools.test kernel accessors namespaces assocs
cpu.architecture vectors sequences
compiler.cfg
+compiler.cfg.utilities
compiler.cfg.debugger
compiler.cfg.registers
compiler.cfg.predecessors
M: ##flushable defs-vregs dst>> 1array ;
M: ##fixnum-overflow defs-vregs dst>> 1array ;
+M: _fixnum-overflow defs-vregs dst>> 1array ;
M: insn defs-vregs drop f ;
M: ##write-barrier temp-vregs [ card#>> ] [ table>> ] bi 2array ;
M: _compare-imm-branch uses-vregs src1>> 1array ;
M: _dispatch uses-vregs src>> 1array ;
M: insn uses-vregs drop f ;
-
-! Instructions that use vregs
-UNION: vreg-insn
-##flushable
-##write-barrier
-##dispatch
-##effect
-##fixnum-overflow
-##conditional-branch
-##compare-imm-branch
-##phi
-##gc
-_conditional-branch
-_compare-imm-branch
-_dispatch ;
INSN: ##inc-r { n integer } ;
! Subroutine calls
-INSN: ##stack-frame stack-frame ;
INSN: ##call word { height integer } ;
INSN: ##jump word ;
INSN: ##return ;
INSN: ##alien-global < ##flushable symbol library ;
! FFI
-INSN: ##alien-invoke params ;
-INSN: ##alien-indirect params ;
-INSN: ##alien-callback params ;
+INSN: ##alien-invoke params stack-frame ;
+INSN: ##alien-indirect params stack-frame ;
+INSN: ##alien-callback params stack-frame ;
INSN: ##callback-return params ;
! Instructions used by CFG IR only.
INSN: _copy dst src class ;
INSN: _spill-counts counts ;
-! Instructions that poison the stack state
-UNION: poison-insn
- ##jump
- ##return
- ##callback-return ;
+! Instructions that use vregs
+UNION: vreg-insn
+ ##flushable
+ ##write-barrier
+ ##dispatch
+ ##effect
+ ##fixnum-overflow
+ ##conditional-branch
+ ##compare-imm-branch
+ ##phi
+ ##gc
+ _conditional-branch
+ _compare-imm-branch
+ _dispatch ;
! Instructions that kill all live vregs
UNION: kill-vreg-insn
- poison-insn
- ##stack-frame
##call
##prologue
##epilogue
[ 2drop ] [ state get untranslate-loc ##replace ] if
] each ;
-ERROR: poisoned-state state ;
-
: sync-state ( -- )
state get {
- [ dup poisoned?>> [ poisoned-state ] [ drop ] if ]
[ ds-height>> save-ds-height ]
[ rs-height>> save-rs-height ]
[ save-changed-locs ]
[ clear-state ]
} cleave ;
-: poison-state ( -- ) state get t >>poisoned? drop ;
-
! Abstract interpretation
GENERIC: visit ( insn -- )
M: ##copy visit
[ call-next-method ] [ record-copy ] bi ;
-M: poison-insn visit call-next-method poison-state ;
+M: ##jump visit sync-state , ;
+
+M: ##return visit sync-state , ;
+
+M: ##callback-return visit sync-state , ;
M: kill-vreg-insn visit sync-state , ;
building off
basic-block off ;
+: emit-trivial-block ( quot -- )
+ basic-block get instructions>> empty? [ ##branch begin-basic-block ] unless
+ call
+ ##branch begin-basic-block ; inline
+
: call-height ( #call -- n )
[ out-d>> length ] [ in-d>> length ] bi - ;
: emit-primitive ( node -- )
- [ word>> ] [ call-height ] bi ##call ##branch begin-basic-block ;
+ [ [ word>> ] [ call-height ] bi ##call ] emit-trivial-block ;
: with-branch ( quot -- final-bb )
[