! Copyright (C) 2010 Slava Pestov, 2011 Alex Vondrak. ! See http://factorcode.org/license.txt for BSD license. USING: accessors combinators combinators.short-circuit compiler.cfg.gvn.avail compiler.cfg.gvn.folding compiler.cfg.gvn.graph compiler.cfg.gvn.rewrite compiler.cfg.instructions compiler.cfg.registers compiler.cfg.utilities cpu.architecture kernel layouts make math namespaces ; IN: compiler.cfg.gvn.math : f-insn? ( insn -- ? ) { [ ##load-reference? ] [ obj>> not ] } 1&& ; inline : zero-insn? ( insn -- ? ) { [ ##load-integer? ] [ val>> 0 = ] } 1&& ; inline M: ##tagged>integer rewrite [ dst>> ] [ src>> vreg>insn ] bi { { [ dup ##load-integer? ] [ val>> tag-fixnum ##load-integer new-insn ] } { [ dup f-insn? ] [ drop \ f type-number ##load-integer new-insn ] } [ 2drop f ] } cond ; : self-inverse? ( insn quot -- ? ) [ src>> vreg>insn ] dip with-available-uses? ; inline : self-inverse ( insn -- insn' ) [ dst>> ] [ src>> vreg>insn src>> ] bi ; : identity ( insn -- insn' ) [ dst>> ] [ src1>> ] bi ; M: ##neg rewrite { { [ dup [ ##neg? ] self-inverse? ] [ self-inverse ] } { [ dup unary-constant-fold? ] [ unary-constant-fold ] } [ drop f ] } cond ; M: ##not rewrite { { [ dup [ ##not? ] self-inverse? ] [ self-inverse ] } { [ dup unary-constant-fold? ] [ unary-constant-fold ] } [ drop f ] } cond ; ! Reassociation converts ! ## *-imm 2 1 X ! ## *-imm 3 2 Y ! into ! ## *-imm 3 1 (X $ Y) ! If * is associative, then $ is the same operation as *. ! In the case of shifts, $ is addition. : (reassociate) ( insn -- dst src1 src2' src2'' ) { [ dst>> ] [ src1>> vreg>insn [ src1>> ] [ src2>> ] bi ] [ src2>> ] } cleave ; inline : reassociate ( insn -- dst src1 src2 ) [ (reassociate) ] keep binary-constant-fold* ; : ?new-insn ( dst src1 src2 ? class -- insn/f ) '[ _ new-insn ] [ 3drop f ] if ; inline : reassociate-arithmetic ( insn new-insn -- insn/f ) [ reassociate dup immediate-arithmetic? ] dip ?new-insn ; inline : reassociate-bitwise ( insn new-insn -- insn/f ) [ reassociate dup immediate-bitwise? ] dip ?new-insn ; inline : reassociate-shift ( insn new-insn -- insn/f ) [ (reassociate) + dup immediate-shift-count? ] dip ?new-insn ; inline M: ##add-imm rewrite { { [ dup src2>> 0 = ] [ identity ] } { [ dup binary-constant-fold? ] [ binary-constant-fold ] } { [ dup src1>> vreg>insn [ ##add-imm? ] with-available-uses? ] [ ##add-imm reassociate-arithmetic ] } [ drop f ] } cond ; : sub-imm>add-imm ( insn -- insn' ) [ dst>> ] [ src1>> ] [ src2>> neg ] tri dup immediate-arithmetic? ##add-imm ?new-insn ; M: ##sub-imm rewrite sub-imm>add-imm ; ! Convert ##mul-imm -1 => ##neg : mul-to-neg? ( insn -- ? ) src2>> -1 = ; : mul-to-neg ( insn -- insn' ) [ dst>> ] [ src1>> ] bi ##neg new-insn ; ! Convert ##mul-imm 2^X => ##shl-imm X : mul-to-shl? ( insn -- ? ) src2>> power-of-2? ; : mul-to-shl ( insn -- insn' ) [ [ dst>> ] [ src1>> ] bi ] [ src2>> log2 ] bi ##shl-imm new-insn ; ! Distribution converts ! ##+-imm 2 1 X ! ##*-imm 3 2 Y ! Into ! ##*-imm 4 1 Y ! ##+-imm 3 4 X*Y ! Where * is mul or shl, + is add or sub ! Have to make sure that X*Y fits in an immediate :: (distribute) ( outer inner imm temp add-op mul-op -- new-outers/f ) imm immediate-arithmetic? [ [ temp inner src1>> outer src2>> mul-op execute outer dst>> temp imm add-op execute ] { } make ] [ f ] if ; inline : distribute-over-add? ( insn -- ? ) final-iteration? get [ src1>> vreg>insn [ ##add-imm? ] with-available-uses? ] [ drop f ] if ; : distribute-over-sub? ( insn -- ? ) final-iteration? get [ src1>> vreg>insn [ ##sub-imm? ] with-available-uses? ] [ drop f ] if ; ! XXX next-vreg makes vregs>vns change on every iteration : distribute ( insn add-op mul-op -- new-insns/f ) [ dup src1>> vreg>insn 2dup src2>> swap [ src2>> ] keep binary-constant-fold* next-vreg ] 2dip (distribute) ; inline M: ##mul-imm rewrite { { [ dup binary-constant-fold? ] [ binary-constant-fold ] } { [ dup mul-to-neg? ] [ mul-to-neg ] } { [ dup mul-to-shl? ] [ mul-to-shl ] } { [ dup src1>> vreg>insn [ ##mul-imm? ] with-available-uses? ] [ ##mul-imm reassociate-arithmetic ] } { [ dup distribute-over-add? ] [ \ ##add-imm, \ ##mul-imm, distribute ] } { [ dup distribute-over-sub? ] [ \ ##sub-imm, \ ##mul-imm, distribute ] } [ drop f ] } cond ; M: ##and-imm rewrite { { [ dup binary-constant-fold? ] [ binary-constant-fold ] } { [ dup src1>> vreg>insn [ ##and-imm? ] with-available-uses? ] [ ##and-imm reassociate-bitwise ] } { [ dup src2>> 0 = ] [ dst>> 0 ##load-integer new-insn ] } { [ dup src2>> -1 = ] [ identity ] } [ drop f ] } cond ; M: ##or-imm rewrite { { [ dup src2>> 0 = ] [ identity ] } { [ dup src2>> -1 = ] [ dst>> -1 ##load-integer new-insn ] } { [ dup binary-constant-fold? ] [ binary-constant-fold ] } { [ dup src1>> vreg>insn [ ##or-imm? ] with-available-uses? ] [ ##or-imm reassociate-bitwise ] } [ drop f ] } cond ; M: ##xor-imm rewrite { { [ dup src2>> 0 = ] [ identity ] } { [ dup src2>> -1 = ] [ [ dst>> ] [ src1>> ] bi ##not new-insn ] } { [ dup binary-constant-fold? ] [ binary-constant-fold ] } { [ dup src1>> vreg>insn [ ##xor-imm? ] with-available-uses? ] [ ##xor-imm reassociate-bitwise ] } [ drop f ] } cond ; M: ##shl-imm rewrite { { [ dup src2>> 0 = ] [ identity ] } { [ dup binary-constant-fold? ] [ binary-constant-fold ] } { [ dup src1>> vreg>insn [ ##shl-imm? ] with-available-uses? ] [ ##shl-imm reassociate-shift ] } { [ dup distribute-over-add? ] [ \ ##add-imm, \ ##shl-imm, distribute ] } { [ dup distribute-over-sub? ] [ \ ##sub-imm, \ ##shl-imm, distribute ] } [ drop f ] } cond ; M: ##shr-imm rewrite { { [ dup src2>> 0 = ] [ identity ] } { [ dup binary-constant-fold? ] [ binary-constant-fold ] } { [ dup src1>> vreg>insn [ ##shr-imm? ] with-available-uses? ] [ ##shr-imm reassociate-shift ] } [ drop f ] } cond ; M: ##sar-imm rewrite { { [ dup src2>> 0 = ] [ identity ] } { [ dup binary-constant-fold? ] [ binary-constant-fold ] } { [ dup src1>> vreg>insn [ ##sar-imm? ] with-available-uses? ] [ ##sar-imm reassociate-shift ] } [ drop f ] } cond ; ! Convert ! ##load-integer 2 X ! ##* 3 1 2 ! Where * is an operation with an -imm equivalent into ! ##*-imm 3 1 X : insn>imm-insn ( insn op swap? -- new-insn ) swap [ [ [ dst>> ] [ src1>> ] [ src2>> ] tri ] dip [ swap ] when vreg>integer ] dip new-insn ; inline M: ##add rewrite { { [ dup src2>> vreg-immediate-arithmetic? ] [ ##add-imm f insn>imm-insn ] } { [ dup src1>> vreg-immediate-arithmetic? ] [ ##add-imm t insn>imm-insn ] } [ drop f ] } cond ; : diagonal? ( insn -- ? ) [ src1>> vreg>vn ] [ src2>> vreg>vn ] bi = ; inline ! ##sub 2 1 1 => ##load-integer 2 0 : rewrite-subtraction-identity ( insn -- insn' ) dst>> 0 ##load-integer new-insn ; ! ##load-integer 1 0 ! ##sub 3 1 2 ! => ! ##neg 3 2 : sub-to-neg? ( ##sub -- ? ) src1>> vreg>insn zero-insn? ; : sub-to-neg ( ##sub -- insn ) [ dst>> ] [ src2>> ] bi ##neg new-insn ; M: ##sub rewrite { { [ dup sub-to-neg? ] [ sub-to-neg ] } { [ dup diagonal? ] [ rewrite-subtraction-identity ] } { [ dup src2>> vreg-immediate-arithmetic? ] [ ##sub-imm f insn>imm-insn ] } [ drop f ] } cond ; M: ##mul rewrite { { [ dup src2>> vreg-immediate-arithmetic? ] [ ##mul-imm f insn>imm-insn ] } { [ dup src1>> vreg-immediate-arithmetic? ] [ ##mul-imm t insn>imm-insn ] } [ drop f ] } cond ; M: ##and rewrite { { [ dup diagonal? ] [ identity ] } { [ dup src2>> vreg-immediate-bitwise? ] [ ##and-imm f insn>imm-insn ] } { [ dup src1>> vreg-immediate-bitwise? ] [ ##and-imm t insn>imm-insn ] } [ drop f ] } cond ; M: ##or rewrite { { [ dup diagonal? ] [ identity ] } { [ dup src2>> vreg-immediate-bitwise? ] [ ##or-imm f insn>imm-insn ] } { [ dup src1>> vreg-immediate-bitwise? ] [ ##or-imm t insn>imm-insn ] } [ drop f ] } cond ; M: ##xor rewrite { { [ dup diagonal? ] [ dst>> 0 ##load-integer new-insn ] } { [ dup src2>> vreg-immediate-bitwise? ] [ ##xor-imm f insn>imm-insn ] } { [ dup src1>> vreg-immediate-bitwise? ] [ ##xor-imm t insn>imm-insn ] } [ drop f ] } cond ; M: ##shl rewrite { { [ dup src2>> vreg-immediate-bitwise? ] [ ##shl-imm f insn>imm-insn ] } [ drop f ] } cond ; M: ##shr rewrite { { [ dup src2>> vreg-immediate-bitwise? ] [ ##shr-imm f insn>imm-insn ] } [ drop f ] } cond ; M: ##sar rewrite { { [ dup src2>> vreg-immediate-bitwise? ] [ ##sar-imm f insn>imm-insn ] } [ drop f ] } cond ;