1
0
mirror of https://github.com/golang/go synced 2024-11-13 18:30:26 -07:00

[dev.ssa] cmd/compile/internal/ssa: handle rewrite of Phis.

* Phis can have variable number of arguments, but rulegen assumed that
each operation has fixed number of arguments.
* Rewriting Phis is necessary to handle the following case:

func f1_ssa(a bool, x int) int {
        v := 0
        if a {
                v = -1
        } else {
                v = -1
        }
        return x|v
}

Change-Id: Iff6bd411b854f3d1d6d3ce21934bf566757094f2
Reviewed-on: https://go-review.googlesource.com/19412
Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
Alexandru Moșoi 2016-02-09 19:46:26 +01:00 committed by Alexandru Moșoi
parent 7f7f7cddec
commit d0d04d2d6c
6 changed files with 140 additions and 2 deletions

View File

@ -358,6 +358,26 @@ func testSubConst() {
} }
} }
//go:noinline
func orPhi_ssa(a bool, x int) int {
v := 0
if a {
v = -1
} else {
v = -1
}
return x | v
}
func testOrPhi() {
if want, got := -1, orPhi_ssa(true, 4); got != want {
println("orPhi_ssa(true, 4)=", got, " want ", want)
}
if want, got := -1, orPhi_ssa(false, 0); got != want {
println("orPhi_ssa(false, 0)=", got, " want ", want)
}
}
var failed = false var failed = false
func main() { func main() {

View File

@ -263,6 +263,12 @@
(Sub8 (Add8 x y) x) -> y (Sub8 (Add8 x y) x) -> y
(Sub8 (Add8 x y) y) -> x (Sub8 (Add8 x y) y) -> x
// basic phi simplifications
(Phi (Const8 [c]) (Const8 [d])) && int8(c) == int8(d) -> (Const8 [c])
(Phi (Const16 [c]) (Const16 [d])) && int16(c) == int16(d) -> (Const16 [c])
(Phi (Const32 [c]) (Const32 [d])) && int32(c) == int32(d) -> (Const32 [c])
(Phi (Const64 [c]) (Const64 [c])) -> (Const64 [c])
// user nil checks // user nil checks
(NeqPtr p (ConstNil)) -> (IsNonNil p) (NeqPtr p (ConstNil)) -> (IsNonNil p)
(NeqPtr (ConstNil) p) -> (IsNonNil p) (NeqPtr (ConstNil) p) -> (IsNonNil p)

View File

@ -240,8 +240,8 @@ var genericOps = []opData{
{name: "Sqrt"}, // sqrt(arg0), float64 only {name: "Sqrt"}, // sqrt(arg0), float64 only
// Data movement // Data movement
{name: "Phi"}, // select an argument based on which predecessor block we came from {name: "Phi", variableLength: true}, // select an argument based on which predecessor block we came from
{name: "Copy"}, // output = arg0 {name: "Copy"}, // output = arg0
// Convert converts between pointers and integers. // Convert converts between pointers and integers.
// We have a special op for this so as to not confuse GC // We have a special op for this so as to not confuse GC
// (particularly stack maps). It takes a memory arg so it // (particularly stack maps). It takes a memory arg so it

View File

@ -32,6 +32,7 @@ type opData struct {
typ string // default result type typ string // default result type
aux string aux string
rematerializeable bool rematerializeable bool
variableLength bool // if true the operation has a variable number of arguments
} }
type blockData struct { type blockData struct {

View File

@ -395,6 +395,23 @@ func genMatch0(w io.Writer, arch arch, match, v string, m map[string]string, top
argnum++ argnum++
} }
} }
variableLength := false
for _, op := range genericOps {
if op.name == s[0] {
variableLength = op.variableLength
break
}
}
for _, op := range arch.ops {
if op.name == s[0] {
variableLength = op.variableLength
break
}
}
if variableLength {
fmt.Fprintf(w, "if len(%s.Args) != %d {\nbreak\n}\n", v, argnum)
}
} }
func genResult(w io.Writer, arch arch, result string) { func genResult(w io.Writer, arch arch, result string) {

View File

@ -213,6 +213,8 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
return rewriteValuegeneric_OpOr64(v, config) return rewriteValuegeneric_OpOr64(v, config)
case OpOr8: case OpOr8:
return rewriteValuegeneric_OpOr8(v, config) return rewriteValuegeneric_OpOr8(v, config)
case OpPhi:
return rewriteValuegeneric_OpPhi(v, config)
case OpPtrIndex: case OpPtrIndex:
return rewriteValuegeneric_OpPtrIndex(v, config) return rewriteValuegeneric_OpPtrIndex(v, config)
case OpRsh16Ux16: case OpRsh16Ux16:
@ -3965,6 +3967,98 @@ func rewriteValuegeneric_OpOr8(v *Value, config *Config) bool {
} }
return false return false
} }
func rewriteValuegeneric_OpPhi(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (Phi (Const8 [c]) (Const8 [d]))
// cond: int8(c) == int8(d)
// result: (Const8 [c])
for {
if v.Args[0].Op != OpConst8 {
break
}
c := v.Args[0].AuxInt
if v.Args[1].Op != OpConst8 {
break
}
d := v.Args[1].AuxInt
if len(v.Args) != 2 {
break
}
if !(int8(c) == int8(d)) {
break
}
v.reset(OpConst8)
v.AuxInt = c
return true
}
// match: (Phi (Const16 [c]) (Const16 [d]))
// cond: int16(c) == int16(d)
// result: (Const16 [c])
for {
if v.Args[0].Op != OpConst16 {
break
}
c := v.Args[0].AuxInt
if v.Args[1].Op != OpConst16 {
break
}
d := v.Args[1].AuxInt
if len(v.Args) != 2 {
break
}
if !(int16(c) == int16(d)) {
break
}
v.reset(OpConst16)
v.AuxInt = c
return true
}
// match: (Phi (Const32 [c]) (Const32 [d]))
// cond: int32(c) == int32(d)
// result: (Const32 [c])
for {
if v.Args[0].Op != OpConst32 {
break
}
c := v.Args[0].AuxInt
if v.Args[1].Op != OpConst32 {
break
}
d := v.Args[1].AuxInt
if len(v.Args) != 2 {
break
}
if !(int32(c) == int32(d)) {
break
}
v.reset(OpConst32)
v.AuxInt = c
return true
}
// match: (Phi (Const64 [c]) (Const64 [c]))
// cond:
// result: (Const64 [c])
for {
if v.Args[0].Op != OpConst64 {
break
}
c := v.Args[0].AuxInt
if v.Args[1].Op != OpConst64 {
break
}
if v.Args[1].AuxInt != v.Args[0].AuxInt {
break
}
if len(v.Args) != 2 {
break
}
v.reset(OpConst64)
v.AuxInt = c
return true
}
return false
}
func rewriteValuegeneric_OpPtrIndex(v *Value, config *Config) bool { func rewriteValuegeneric_OpPtrIndex(v *Value, config *Config) bool {
b := v.Block b := v.Block
_ = b _ = b