compiler.cfg.two-operand: make it work in more cases

db4
Slava Pestov 2009-07-27 22:28:29 -05:00
parent 423d2996fa
commit e8cf50ac3e
2 changed files with 131 additions and 41 deletions

View File

@ -0,0 +1,45 @@
IN: compiler.cfg.two-operand.tests
USING: compiler.cfg.two-operand compiler.cfg.instructions
compiler.cfg.registers cpu.architecture namespaces tools.test ;
3 vreg-counter set-global
[
V{
T{ ##copy f V int-regs 1 V int-regs 2 }
T{ ##sub f V int-regs 1 V int-regs 1 V int-regs 3 }
}
] [
{
T{ ##sub f V int-regs 1 V int-regs 2 V int-regs 3 }
} (convert-two-operand)
] unit-test
[
V{
T{ ##sub f V int-regs 1 V int-regs 1 V int-regs 2 }
}
] [
{
T{ ##sub f V int-regs 1 V int-regs 1 V int-regs 2 }
} (convert-two-operand)
] unit-test
[
V{
T{ ##copy f V int-regs 4 V int-regs 2 }
T{ ##sub f V int-regs 4 V int-regs 4 V int-regs 1 }
T{ ##copy f V int-regs 1 V int-regs 4 }
}
] [
{
T{ ##sub f V int-regs 1 V int-regs 2 V int-regs 1 }
} (convert-two-operand)
] unit-test
! This should never come up after coalescing
[
V{
T{ ##fixnum-add f V int-regs 2 V int-regs 4 V int-regs 2 }
} (convert-two-operand)
] must-fail

View File

@ -1,59 +1,104 @@
! Copyright (C) 2008, 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors kernel sequences make compiler.cfg.instructions
USING: accessors kernel sequences make combinators
compiler.cfg.registers compiler.cfg.instructions
compiler.cfg.rpo cpu.architecture ;
IN: compiler.cfg.two-operand
! On x86, instructions take the form x = x op y
! Our SSA IR is x = y op z
! This pass runs after SSA coalescing and normalizes instructions
! to fit the x86 two-address scheme. Possibilities are:
! 1) x = x op y
! 2) x = y op x
! 3) x = y op z
! In case 1, there is nothing to do.
! In case 2, we convert to
! z = y
! z = z op x
! x = z
! In case 3, we convert to
! x = y
! x = x op z
! In case 2 and case 3, linear scan coalescing will eliminate a
! copy if the value y is never used again.
! We don't bother with ##add, ##add-imm, ##sub-imm or ##mul-imm
! since x86 has LEA and IMUL instructions which are effectively
! three-operand addition and multiplication, respectively.
: convert-two-operand/integer ( insn -- )
[ [ dst>> ] [ src1>> ] bi ##copy ]
[ dup dst>> >>src1 , ]
bi ; inline
: convert-two-operand/float ( insn -- )
[ [ dst>> ] [ src1>> ] bi ##copy-float ]
[ dup dst>> >>src1 , ]
bi ; inline
UNION: two-operand-insn
##sub
##mul
##and
##and-imm
##or
##or-imm
##xor
##xor-imm
##shl
##shl-imm
##shr
##shr-imm
##sar
##sar-imm
##fixnum-overflow
##add-float
##sub-float
##mul-float
##div-float ;
GENERIC: convert-two-operand* ( insn -- )
: emit-copy ( dst src -- )
dup reg-class>> {
{ int-regs [ ##copy ] }
{ double-float-regs [ ##copy-float ] }
} case ; inline
: case-1? ( insn -- ? ) [ dst>> ] [ src1>> ] bi = ; inline
: case-1 ( insn -- ) , ; inline
: case-2? ( insn -- ? ) [ dst>> ] [ src2>> ] bi = ; inline
ERROR: bad-case-2 insn ;
: case-2 ( insn -- )
! This can't work with a ##fixnum-overflow since it branches
dup ##fixnum-overflow? [ bad-case-2 ] when
dup dst>> reg-class>> next-vreg
[ swap src1>> emit-copy ]
[ [ >>src1 ] [ >>dst ] bi , ]
[ [ src2>> ] dip emit-copy ]
2tri ; inline
: case-3 ( insn -- )
[ [ dst>> ] [ src1>> ] bi emit-copy ]
[ dup dst>> >>src1 , ]
bi ; inline
M: two-operand-insn convert-two-operand*
{
{ [ dup case-1? ] [ case-1 ] }
{ [ dup case-2? ] [ case-2 ] }
[ case-3 ]
} cond ; inline
M: ##not convert-two-operand*
[ [ dst>> ] [ src>> ] bi ##copy ]
[ dup dst>> >>src , ]
bi ;
M: ##sub convert-two-operand* convert-two-operand/integer ;
M: ##mul convert-two-operand* convert-two-operand/integer ;
M: ##and convert-two-operand* convert-two-operand/integer ;
M: ##and-imm convert-two-operand* convert-two-operand/integer ;
M: ##or convert-two-operand* convert-two-operand/integer ;
M: ##or-imm convert-two-operand* convert-two-operand/integer ;
M: ##xor convert-two-operand* convert-two-operand/integer ;
M: ##xor-imm convert-two-operand* convert-two-operand/integer ;
M: ##shl convert-two-operand* convert-two-operand/integer ;
M: ##shl-imm convert-two-operand* convert-two-operand/integer ;
M: ##shr convert-two-operand* convert-two-operand/integer ;
M: ##shr-imm convert-two-operand* convert-two-operand/integer ;
M: ##sar convert-two-operand* convert-two-operand/integer ;
M: ##sar-imm convert-two-operand* convert-two-operand/integer ;
M: ##fixnum-overflow convert-two-operand* convert-two-operand/integer ;
M: ##add-float convert-two-operand* convert-two-operand/float ;
M: ##sub-float convert-two-operand* convert-two-operand/float ;
M: ##mul-float convert-two-operand* convert-two-operand/float ;
M: ##div-float convert-two-operand* convert-two-operand/float ;
dup [ dst>> ] [ src>> ] bi = [
[ [ dst>> ] [ src>> ] bi ##copy ]
[ dup dst>> >>src ]
bi
] unless , ;
M: insn convert-two-operand* , ;
: (convert-two-operand) ( cfg -- cfg' )
[ [ convert-two-operand* ] each ] V{ } make ;
: convert-two-operand ( cfg -- cfg' )
two-operand? [
[ [ [ convert-two-operand* ] each ] V{ } make ]
local-optimization
] when ;
two-operand? [ [ (convert-two-operand) ] local-optimization ] when ;