! Copyright (C) 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: accessors combinators kernel math math.order namespaces sequences vectors combinators.short-circuit cpu.architecture compiler.cfg compiler.cfg.comparisons compiler.cfg.instructions compiler.cfg.registers compiler.cfg.value-numbering.math compiler.cfg.value-numbering.graph compiler.cfg.value-numbering.rewrite ; IN: compiler.cfg.value-numbering.comparisons ! Optimizations performed here: ! ! 1) Eliminating intermediate boolean values when the result of ! a comparison is used by a compare-branch ! 2) Folding comparisons where both inputs are literal ! 3) Folding comparisons where both inputs are congruent ! 4) Converting compare instructions into compare-imm instructions : fold-compare-imm? ( insn -- ? ) src1>> vreg>insn literal-insn? ; : evaluate-compare-imm ( insn -- ? ) [ src1>> vreg>literal ] [ src2>> ] [ cc>> ] tri { { cc= [ eq? ] } { cc/= [ eq? not ] } } case ; : fold-compare-integer-imm? ( insn -- ? ) src1>> vreg>insn ##load-integer? ; : evaluate-compare-integer-imm ( insn -- ? ) [ src1>> vreg>integer ] [ src2>> ] [ cc>> ] tri [ <=> ] dip evaluate-cc ; : fold-test-imm? ( insn -- ? ) src1>> vreg>insn ##load-integer? ; : evaluate-test-imm ( insn -- ? ) [ src1>> vreg>integer ] [ src2>> ] [ cc>> ] tri [ bitand ] dip { { cc= [ 0 = ] } { cc/= [ 0 = not ] } } case ; : rewrite-into-test? ( insn -- ? ) { [ drop test-instruction? ] [ cc>> { cc= cc/= } member-eq? ] [ src2>> 0 = ] } 1&& ; : >compare< ( insn -- in1 in2 cc ) [ src1>> ] [ src2>> ] [ cc>> ] tri ; inline : >test-vector< ( insn -- src1 temp rep vcc ) { [ src1>> ] [ drop next-vreg ] [ rep>> ] [ vcc>> ] } cleave ; inline UNION: scalar-compare-insn ##compare ##compare-imm ##compare-integer ##compare-integer-imm ##test ##test-imm ##compare-float-unordered ##compare-float-ordered ; UNION: general-compare-insn scalar-compare-insn ##test-vector ; : rewrite-boolean-comparison? ( insn -- ? ) { [ src1>> vreg>insn general-compare-insn? ] [ src2>> not ] [ cc>> cc/= eq? ] } 1&& ; inline : rewrite-boolean-comparison ( insn -- insn ) src1>> vreg>insn { { [ dup ##compare? ] [ >compare< \ ##compare-branch new-insn ] } { [ dup ##compare-imm? ] [ >compare< \ ##compare-imm-branch new-insn ] } { [ dup ##compare-integer? ] [ >compare< \ ##compare-integer-branch new-insn ] } { [ dup ##compare-integer-imm? ] [ >compare< \ ##compare-integer-imm-branch new-insn ] } { [ dup ##test? ] [ >compare< \ ##test-branch new-insn ] } { [ dup ##test-imm? ] [ >compare< \ ##test-imm-branch new-insn ] } { [ dup ##compare-float-unordered? ] [ >compare< \ ##compare-float-unordered-branch new-insn ] } { [ dup ##compare-float-ordered? ] [ >compare< \ ##compare-float-ordered-branch new-insn ] } { [ dup ##test-vector? ] [ >test-vector< \ ##test-vector-branch new-insn ] } } cond ; : fold-branch ( ? -- insn ) 0 1 ? basic-block get [ nth 1vector ] change-successors drop \ ##branch new-insn ; : fold-compare-imm-branch ( insn -- insn/f ) evaluate-compare-imm fold-branch ; : >test-branch ( insn -- insn ) [ src1>> ] [ src1>> ] [ cc>> ] tri \ ##test-branch new-insn ; M: ##compare-imm-branch rewrite { { [ dup rewrite-boolean-comparison? ] [ rewrite-boolean-comparison ] } { [ dup fold-compare-imm? ] [ fold-compare-imm-branch ] } [ drop f ] } cond ; : fold-compare-integer-imm-branch ( insn -- insn/f ) evaluate-compare-integer-imm fold-branch ; M: ##compare-integer-imm-branch rewrite { { [ dup fold-compare-integer-imm? ] [ fold-compare-integer-imm-branch ] } { [ dup rewrite-into-test? ] [ >test-branch ] } [ drop f ] } cond ; : fold-test-imm-branch ( insn -- insn/f ) evaluate-test-imm fold-branch ; M: ##test-imm-branch rewrite { { [ dup fold-test-imm? ] [ fold-test-imm-branch ] } [ drop f ] } cond ; : swap-compare ( src1 src2 cc swap? -- src1 src2 cc ) [ [ swap ] dip swap-cc ] when ; inline : (>compare-imm-branch) ( insn swap? -- src1 src2 cc ) [ [ src1>> ] [ src2>> ] [ cc>> ] tri ] dip swap-compare ; inline : >compare-imm-branch ( insn swap? -- insn' ) (>compare-imm-branch) [ vreg>literal ] dip \ ##compare-imm-branch new-insn ; inline : >compare-integer-imm-branch ( insn swap? -- insn' ) (>compare-imm-branch) [ vreg>integer ] dip \ ##compare-integer-imm-branch new-insn ; inline : evaluate-self-compare ( insn -- ? ) cc>> { cc= cc<= cc>= } member-eq? ; : rewrite-self-compare-branch ( insn -- insn' ) evaluate-self-compare fold-branch ; M: ##compare-branch rewrite { { [ dup src1>> vreg-immediate-comparand? ] [ t >compare-imm-branch ] } { [ dup src2>> vreg-immediate-comparand? ] [ f >compare-imm-branch ] } { [ dup diagonal? ] [ rewrite-self-compare-branch ] } [ drop f ] } cond ; M: ##compare-integer-branch rewrite { { [ dup src1>> vreg-immediate-arithmetic? ] [ t >compare-integer-imm-branch ] } { [ dup src2>> vreg-immediate-arithmetic? ] [ f >compare-integer-imm-branch ] } { [ dup diagonal? ] [ rewrite-self-compare-branch ] } [ drop f ] } cond ; : (>compare-imm) ( insn swap? -- dst src1 src2 cc ) [ { [ dst>> ] [ src1>> ] [ src2>> ] [ cc>> ] } cleave ] dip swap-compare ; inline : >compare-imm ( insn swap? -- insn' ) (>compare-imm) [ vreg>literal ] dip next-vreg \ ##compare-imm new-insn ; inline : >compare-integer-imm ( insn swap? -- insn' ) (>compare-imm) [ vreg>integer ] dip next-vreg \ ##compare-integer-imm new-insn ; inline : >boolean-insn ( insn ? -- insn' ) [ dst>> ] dip \ ##load-reference new-insn ; : rewrite-self-compare ( insn -- insn' ) dup evaluate-self-compare >boolean-insn ; M: ##compare rewrite { { [ dup src1>> vreg-immediate-comparand? ] [ t >compare-imm ] } { [ dup src2>> vreg-immediate-comparand? ] [ f >compare-imm ] } { [ dup diagonal? ] [ rewrite-self-compare ] } [ drop f ] } cond ; M: ##compare-integer rewrite { { [ dup src1>> vreg-immediate-arithmetic? ] [ t >compare-integer-imm ] } { [ dup src2>> vreg-immediate-arithmetic? ] [ f >compare-integer-imm ] } { [ dup diagonal? ] [ rewrite-self-compare ] } [ drop f ] } cond ; : rewrite-redundant-comparison? ( insn -- ? ) { [ src1>> vreg>insn scalar-compare-insn? ] [ src2>> not ] [ cc>> { cc= cc/= } member? ] } 1&& ; inline : rewrite-redundant-comparison ( insn -- insn' ) [ cc>> ] [ dst>> ] [ src1>> vreg>insn ] tri { { [ dup ##compare? ] [ >compare< next-vreg \ ##compare new-insn ] } { [ dup ##compare-imm? ] [ >compare< next-vreg \ ##compare-imm new-insn ] } { [ dup ##compare-integer? ] [ >compare< next-vreg \ ##compare-integer new-insn ] } { [ dup ##compare-integer-imm? ] [ >compare< next-vreg \ ##compare-integer-imm new-insn ] } { [ dup ##test? ] [ >compare< next-vreg \ ##test new-insn ] } { [ dup ##test-imm? ] [ >compare< next-vreg \ ##test-imm new-insn ] } { [ dup ##compare-float-unordered? ] [ >compare< next-vreg \ ##compare-float-unordered new-insn ] } { [ dup ##compare-float-ordered? ] [ >compare< next-vreg \ ##compare-float-ordered new-insn ] } } cond swap cc= eq? [ [ negate-cc ] change-cc ] when ; : fold-compare-imm ( insn -- insn' ) dup evaluate-compare-imm >boolean-insn ; M: ##compare-imm rewrite { { [ dup rewrite-redundant-comparison? ] [ rewrite-redundant-comparison ] } { [ dup fold-compare-imm? ] [ fold-compare-imm ] } [ drop f ] } cond ; : fold-compare-integer-imm ( insn -- insn' ) dup evaluate-compare-integer-imm >boolean-insn ; : >test ( insn -- insn' ) { [ dst>> ] [ src1>> ] [ src1>> ] [ cc>> ] [ temp>> ] } cleave \ ##test new-insn ; M: ##compare-integer-imm rewrite { { [ dup fold-compare-integer-imm? ] [ fold-compare-integer-imm ] } { [ dup rewrite-into-test? ] [ >test ] } [ drop f ] } cond ; : (simplify-test) ( insn -- src1 src2 cc ) [ src1>> vreg>insn [ src1>> ] [ src2>> ] bi ] [ cc>> ] bi ; inline : simplify-test ( insn -- insn ) dup (simplify-test) drop [ >>src1 ] [ >>src2 ] bi* ; inline : simplify-test-branch ( insn -- insn ) dup (simplify-test) drop [ >>src1 ] [ >>src2 ] bi* ; inline : (simplify-test-imm) ( insn -- src1 src2 cc ) [ src1>> vreg>insn [ src1>> ] [ src2>> ] bi ] [ cc>> ] bi ; inline : simplify-test-imm ( insn -- insn ) [ dst>> ] [ (simplify-test-imm) ] [ temp>> ] tri \ ##test-imm new-insn ; inline : simplify-test-imm-branch ( insn -- insn ) (simplify-test-imm) \ ##test-imm-branch new-insn ; inline : >test-imm ( insn ? -- insn' ) (>compare-imm) [ vreg>integer ] dip next-vreg \ ##test-imm new-insn ; inline : >test-imm-branch ( insn ? -- insn' ) (>compare-imm-branch) [ vreg>integer ] dip \ ##test-imm-branch new-insn ; inline M: ##test rewrite { { [ dup src1>> vreg-immediate-comparand? ] [ t >test-imm ] } { [ dup src2>> vreg-immediate-comparand? ] [ f >test-imm ] } { [ dup diagonal? ] [ { { [ dup src1>> vreg>insn ##and? ] [ simplify-test ] } { [ dup src1>> vreg>insn ##and-imm? ] [ simplify-test-imm ] } [ drop f ] } cond ] } [ drop f ] } cond ; M: ##test-branch rewrite { { [ dup src1>> vreg-immediate-comparand? ] [ t >test-imm-branch ] } { [ dup src2>> vreg-immediate-comparand? ] [ f >test-imm-branch ] } { [ dup diagonal? ] [ { { [ dup src1>> vreg>insn ##and? ] [ simplify-test-branch ] } { [ dup src1>> vreg>insn ##and-imm? ] [ simplify-test-imm-branch ] } [ drop f ] } cond ] } [ drop f ] } cond ; : fold-test-imm ( insn -- insn' ) dup evaluate-test-imm >boolean-insn ; M: ##test-imm rewrite { { [ dup fold-test-imm? ] [ fold-test-imm ] } [ drop f ] } cond ;