cmd/compile: add MakeTuple generic SSA op to remove duplicate Select[01] rules

Change-Id: Id94a5e503f02aa29dc1e334b521770107d4261db
Reviewed-on: https://go-review.googlesource.com/c/go/+/656615
Reviewed-by: Keith Randall <khr@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: David Chase <drchase@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Jorropo <jorropo.pgm@gmail.com>
This commit is contained in:
Jorropo 2025-03-11 09:52:10 +01:00
parent 99411d7847
commit 4ff70cf868
4 changed files with 136 additions and 180 deletions

View file

@ -174,8 +174,7 @@
(Div64u (Const64 [c]) (Const64 [d])) && d != 0 => (Const64 [int64(uint64(c)/uint64(d))])
(Div32F (Const32F [c]) (Const32F [d])) && c/d == c/d => (Const32F [c/d])
(Div64F (Const64F [c]) (Const64F [d])) && c/d == c/d => (Const64F [c/d])
(Select0 (Div128u (Const64 [0]) lo y)) => (Div64u lo y)
(Select1 (Div128u (Const64 [0]) lo y)) => (Mod64u lo y)
(Div128u <t> (Const64 [0]) lo y) => (MakeTuple (Div64u <t.FieldType(0)> lo y) (Mod64u <t.FieldType(1)> lo y))
(Not (ConstBool [c])) => (ConstBool [!c])
@ -186,8 +185,7 @@
// Convert x * 1 to x.
(Mul(8|16|32|64) (Const(8|16|32|64) [1]) x) => x
(Select0 (Mul(32|64)uover (Const(32|64) [1]) x)) => x
(Select1 (Mul(32|64)uover (Const(32|64) [1]) x)) => (ConstBool [false])
(Mul(32|64)uover <t> (Const(32|64) [1]) x) => (MakeTuple x (ConstBool <t.FieldType(1)> [false]))
// Convert x * -1 to -x.
(Mul(8|16|32|64) (Const(8|16|32|64) [-1]) x) => (Neg(8|16|32|64) x)
@ -592,8 +590,7 @@
(Add(64|32|16|8) (Const(64|32|16|8) [0]) x) => x
(Sub(64|32|16|8) x x) => (Const(64|32|16|8) [0])
(Mul(64|32|16|8) (Const(64|32|16|8) [0]) _) => (Const(64|32|16|8) [0])
(Select0 (Mul(64|32)uover (Const(64|32) [0]) x)) => (Const(64|32) [0])
(Select1 (Mul(64|32)uover (Const(64|32) [0]) x)) => (ConstBool [false])
(Mul(64|32)uover <t> (Const(64|32) [0]) x) => (MakeTuple (Const(64|32) <t.FieldType(0)> [0]) (ConstBool <t.FieldType(1)> [false]))
(Com(64|32|16|8) (Com(64|32|16|8) x)) => x
(Com(64|32|16|8) (Const(64|32|16|8) [c])) => (Const(64|32|16|8) [^c])
@ -2046,6 +2043,10 @@
(Sqrt (Const64F [c])) && !math.IsNaN(math.Sqrt(c)) => (Const64F [math.Sqrt(c)])
// for rewriting constant folded math/bits ops
(Select0 (MakeTuple x y)) => x
(Select1 (MakeTuple x y)) => y
// for rewriting results of some late-expanded rewrites (below)
(SelectN [0] (MakeResult x ___)) => x
(SelectN [1] (MakeResult x y ___)) => y

View file

@ -585,6 +585,7 @@ var genericOps = []opData{
// pseudo-ops for breaking Tuple
{name: "Select0", argLength: 1, zeroWidth: true}, // the first component of a tuple
{name: "Select1", argLength: 1, zeroWidth: true}, // the second component of a tuple
{name: "MakeTuple", argLength: 2}, // arg0 arg1 are components of a "Tuple" (like the result from a 128bits op).
{name: "SelectN", argLength: 1, aux: "Int64"}, // arg0=result, auxint=field index. Returns the auxint'th member.
{name: "SelectNAddr", argLength: 1, aux: "Int64"}, // arg0=result, auxint=field index. Returns the address of auxint'th member. Used for un-SSA-able result types.
{name: "MakeResult", argLength: -1}, // arg0 .. are components of a "Result" (like the result from a Call). The last arg should be memory (like the result from a call).

View file

@ -3327,6 +3327,7 @@ const (
OpCvt64Fto64U
OpSelect0
OpSelect1
OpMakeTuple
OpSelectN
OpSelectNAddr
OpMakeResult
@ -42299,6 +42300,11 @@ var opcodeTable = [...]opInfo{
zeroWidth: true,
generic: true,
},
{
name: "MakeTuple",
argLen: 2,
generic: true,
},
{
name: "SelectN",
auxType: auxInt64,

View file

@ -92,6 +92,8 @@ func rewriteValuegeneric(v *Value) bool {
return rewriteValuegeneric_OpCvt64to64F(v)
case OpCvtBoolToUint8:
return rewriteValuegeneric_OpCvtBoolToUint8(v)
case OpDiv128u:
return rewriteValuegeneric_OpDiv128u(v)
case OpDiv16:
return rewriteValuegeneric_OpDiv16(v)
case OpDiv16u:
@ -242,10 +244,14 @@ func rewriteValuegeneric(v *Value) bool {
return rewriteValuegeneric_OpMul32(v)
case OpMul32F:
return rewriteValuegeneric_OpMul32F(v)
case OpMul32uover:
return rewriteValuegeneric_OpMul32uover(v)
case OpMul64:
return rewriteValuegeneric_OpMul64(v)
case OpMul64F:
return rewriteValuegeneric_OpMul64F(v)
case OpMul64uover:
return rewriteValuegeneric_OpMul64uover(v)
case OpMul8:
return rewriteValuegeneric_OpMul8(v)
case OpNeg16:
@ -6246,6 +6252,30 @@ func rewriteValuegeneric_OpCvtBoolToUint8(v *Value) bool {
}
return false
}
func rewriteValuegeneric_OpDiv128u(v *Value) bool {
v_2 := v.Args[2]
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
// match: (Div128u <t> (Const64 [0]) lo y)
// result: (MakeTuple (Div64u <t.FieldType(0)> lo y) (Mod64u <t.FieldType(1)> lo y))
for {
t := v.Type
if v_0.Op != OpConst64 || auxIntToInt64(v_0.AuxInt) != 0 {
break
}
lo := v_1
y := v_2
v.reset(OpMakeTuple)
v0 := b.NewValue0(v.Pos, OpDiv64u, t.FieldType(0))
v0.AddArg2(lo, y)
v1 := b.NewValue0(v.Pos, OpMod64u, t.FieldType(1))
v1.AddArg2(lo, y)
v.AddArg2(v0, v1)
return true
}
return false
}
func rewriteValuegeneric_OpDiv16(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
@ -18696,6 +18726,47 @@ func rewriteValuegeneric_OpMul32F(v *Value) bool {
}
return false
}
func rewriteValuegeneric_OpMul32uover(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
// match: (Mul32uover <t> (Const32 [1]) x)
// result: (MakeTuple x (ConstBool <t.FieldType(1)> [false]))
for {
t := v.Type
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
if v_0.Op != OpConst32 || auxIntToInt32(v_0.AuxInt) != 1 {
continue
}
x := v_1
v.reset(OpMakeTuple)
v0 := b.NewValue0(v.Pos, OpConstBool, t.FieldType(1))
v0.AuxInt = boolToAuxInt(false)
v.AddArg2(x, v0)
return true
}
break
}
// match: (Mul32uover <t> (Const32 [0]) x)
// result: (MakeTuple (Const32 <t.FieldType(0)> [0]) (ConstBool <t.FieldType(1)> [false]))
for {
t := v.Type
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
if v_0.Op != OpConst32 || auxIntToInt32(v_0.AuxInt) != 0 {
continue
}
v.reset(OpMakeTuple)
v0 := b.NewValue0(v.Pos, OpConst32, t.FieldType(0))
v0.AuxInt = int32ToAuxInt(0)
v1 := b.NewValue0(v.Pos, OpConstBool, t.FieldType(1))
v1.AuxInt = boolToAuxInt(false)
v.AddArg2(v0, v1)
return true
}
break
}
return false
}
func rewriteValuegeneric_OpMul64(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
@ -18971,6 +19042,47 @@ func rewriteValuegeneric_OpMul64F(v *Value) bool {
}
return false
}
func rewriteValuegeneric_OpMul64uover(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
// match: (Mul64uover <t> (Const64 [1]) x)
// result: (MakeTuple x (ConstBool <t.FieldType(1)> [false]))
for {
t := v.Type
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
if v_0.Op != OpConst64 || auxIntToInt64(v_0.AuxInt) != 1 {
continue
}
x := v_1
v.reset(OpMakeTuple)
v0 := b.NewValue0(v.Pos, OpConstBool, t.FieldType(1))
v0.AuxInt = boolToAuxInt(false)
v.AddArg2(x, v0)
return true
}
break
}
// match: (Mul64uover <t> (Const64 [0]) x)
// result: (MakeTuple (Const64 <t.FieldType(0)> [0]) (ConstBool <t.FieldType(1)> [false]))
for {
t := v.Type
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
if v_0.Op != OpConst64 || auxIntToInt64(v_0.AuxInt) != 0 {
continue
}
v.reset(OpMakeTuple)
v0 := b.NewValue0(v.Pos, OpConst64, t.FieldType(0))
v0.AuxInt = int64ToAuxInt(0)
v1 := b.NewValue0(v.Pos, OpConstBool, t.FieldType(1))
v1.AuxInt = boolToAuxInt(false)
v.AddArg2(v0, v1)
return true
}
break
}
return false
}
func rewriteValuegeneric_OpMul8(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
@ -29095,194 +29207,30 @@ func rewriteValuegeneric_OpRsh8x8(v *Value) bool {
}
func rewriteValuegeneric_OpSelect0(v *Value) bool {
v_0 := v.Args[0]
// match: (Select0 (Div128u (Const64 [0]) lo y))
// result: (Div64u lo y)
// match: (Select0 (MakeTuple x y))
// result: x
for {
if v_0.Op != OpDiv128u {
if v_0.Op != OpMakeTuple {
break
}
y := v_0.Args[2]
v_0_0 := v_0.Args[0]
if v_0_0.Op != OpConst64 || auxIntToInt64(v_0_0.AuxInt) != 0 {
break
}
lo := v_0.Args[1]
v.reset(OpDiv64u)
v.AddArg2(lo, y)
x := v_0.Args[0]
v.copyOf(x)
return true
}
// match: (Select0 (Mul32uover (Const32 [1]) x))
// result: x
for {
if v_0.Op != OpMul32uover {
break
}
_ = v_0.Args[1]
v_0_0 := v_0.Args[0]
v_0_1 := v_0.Args[1]
for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 {
if v_0_0.Op != OpConst32 || auxIntToInt32(v_0_0.AuxInt) != 1 {
continue
}
x := v_0_1
v.copyOf(x)
return true
}
break
}
// match: (Select0 (Mul64uover (Const64 [1]) x))
// result: x
for {
if v_0.Op != OpMul64uover {
break
}
_ = v_0.Args[1]
v_0_0 := v_0.Args[0]
v_0_1 := v_0.Args[1]
for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 {
if v_0_0.Op != OpConst64 || auxIntToInt64(v_0_0.AuxInt) != 1 {
continue
}
x := v_0_1
v.copyOf(x)
return true
}
break
}
// match: (Select0 (Mul64uover (Const64 [0]) x))
// result: (Const64 [0])
for {
if v_0.Op != OpMul64uover {
break
}
_ = v_0.Args[1]
v_0_0 := v_0.Args[0]
v_0_1 := v_0.Args[1]
for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 {
if v_0_0.Op != OpConst64 || auxIntToInt64(v_0_0.AuxInt) != 0 {
continue
}
v.reset(OpConst64)
v.AuxInt = int64ToAuxInt(0)
return true
}
break
}
// match: (Select0 (Mul32uover (Const32 [0]) x))
// result: (Const32 [0])
for {
if v_0.Op != OpMul32uover {
break
}
_ = v_0.Args[1]
v_0_0 := v_0.Args[0]
v_0_1 := v_0.Args[1]
for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 {
if v_0_0.Op != OpConst32 || auxIntToInt32(v_0_0.AuxInt) != 0 {
continue
}
v.reset(OpConst32)
v.AuxInt = int32ToAuxInt(0)
return true
}
break
}
return false
}
func rewriteValuegeneric_OpSelect1(v *Value) bool {
v_0 := v.Args[0]
// match: (Select1 (Div128u (Const64 [0]) lo y))
// result: (Mod64u lo y)
// match: (Select1 (MakeTuple x y))
// result: y
for {
if v_0.Op != OpDiv128u {
if v_0.Op != OpMakeTuple {
break
}
y := v_0.Args[2]
v_0_0 := v_0.Args[0]
if v_0_0.Op != OpConst64 || auxIntToInt64(v_0_0.AuxInt) != 0 {
break
}
lo := v_0.Args[1]
v.reset(OpMod64u)
v.AddArg2(lo, y)
y := v_0.Args[1]
v.copyOf(y)
return true
}
// match: (Select1 (Mul32uover (Const32 [1]) x))
// result: (ConstBool [false])
for {
if v_0.Op != OpMul32uover {
break
}
_ = v_0.Args[1]
v_0_0 := v_0.Args[0]
v_0_1 := v_0.Args[1]
for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 {
if v_0_0.Op != OpConst32 || auxIntToInt32(v_0_0.AuxInt) != 1 {
continue
}
v.reset(OpConstBool)
v.AuxInt = boolToAuxInt(false)
return true
}
break
}
// match: (Select1 (Mul64uover (Const64 [1]) x))
// result: (ConstBool [false])
for {
if v_0.Op != OpMul64uover {
break
}
_ = v_0.Args[1]
v_0_0 := v_0.Args[0]
v_0_1 := v_0.Args[1]
for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 {
if v_0_0.Op != OpConst64 || auxIntToInt64(v_0_0.AuxInt) != 1 {
continue
}
v.reset(OpConstBool)
v.AuxInt = boolToAuxInt(false)
return true
}
break
}
// match: (Select1 (Mul64uover (Const64 [0]) x))
// result: (ConstBool [false])
for {
if v_0.Op != OpMul64uover {
break
}
_ = v_0.Args[1]
v_0_0 := v_0.Args[0]
v_0_1 := v_0.Args[1]
for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 {
if v_0_0.Op != OpConst64 || auxIntToInt64(v_0_0.AuxInt) != 0 {
continue
}
v.reset(OpConstBool)
v.AuxInt = boolToAuxInt(false)
return true
}
break
}
// match: (Select1 (Mul32uover (Const32 [0]) x))
// result: (ConstBool [false])
for {
if v_0.Op != OpMul32uover {
break
}
_ = v_0.Args[1]
v_0_0 := v_0.Args[0]
v_0_1 := v_0.Args[1]
for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 {
if v_0_0.Op != OpConst32 || auxIntToInt32(v_0_0.AuxInt) != 0 {
continue
}
v.reset(OpConstBool)
v.AuxInt = boolToAuxInt(false)
return true
}
break
}
return false
}
func rewriteValuegeneric_OpSelectN(v *Value) bool {