cmd/compile: sign or zero extend for 32 bit equality on riscv64

For 32 bit equality (Eq32), rather than always zero extending to 64 bits,
sign extend for signed types and zero extend for unsigned types. This makes
no difference to the equality test (via SUB), however it increases the
likelihood of avoiding unnecessary sign or zero extension simply for the
purpose of equality testing.

While here, replace the Neq* rules with (Not (Eq*)) - this makes no
difference to the generated code (as the intermediates get expanded and
eliminated), however it means that changes to the equality rules also
reflect in the inequality rules.

As an example, the following:

   lw      t0,956(t0)
   slli    t0,t0,0x20
   srli    t0,t0,0x20
   li      t1,1
   bne     t1,t0,278fc

Becomes:

   lw      t0,1024(t0)
   li      t1,1
   bne     t1,t0,278b0

Removes almost 1000 instructions from the Go binary on riscv64.

Change-Id: Iac60635f494f6db87faa47752bd1cc16e6b5967f
Reviewed-on: https://go-review.googlesource.com/c/go/+/516595
Run-TryBot: Joel Sing <joel@sing.id.au>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: M Zhuo <mzh@golangcn.org>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
This commit is contained in:
Joel Sing 2022-10-19 16:43:22 +11:00
parent aa5d483f25
commit 33da4ce457
2 changed files with 67 additions and 47 deletions

View file

@ -229,16 +229,17 @@
(EqPtr x y) => (SEQZ (SUB <typ.Uintptr> x y))
(Eq64 x y) => (SEQZ (SUB <x.Type> x y))
(Eq32 x y) => (SEQZ (SUB <x.Type> (ZeroExt32to64 x) (ZeroExt32to64 y)))
(Eq32 x y) && x.Type.IsSigned() => (SEQZ (SUB <x.Type> (SignExt32to64 x) (SignExt32to64 y)))
(Eq32 x y) && !x.Type.IsSigned() => (SEQZ (SUB <x.Type> (ZeroExt32to64 x) (ZeroExt32to64 y)))
(Eq16 x y) => (SEQZ (SUB <x.Type> (ZeroExt16to64 x) (ZeroExt16to64 y)))
(Eq8 x y) => (SEQZ (SUB <x.Type> (ZeroExt8to64 x) (ZeroExt8to64 y)))
(Eq(64|32)F ...) => (FEQ(D|S) ...)
(NeqPtr x y) => (SNEZ (SUB <typ.Uintptr> x y))
(Neq64 x y) => (SNEZ (SUB <x.Type> x y))
(Neq32 x y) => (SNEZ (SUB <x.Type> (ZeroExt32to64 x) (ZeroExt32to64 y)))
(Neq16 x y) => (SNEZ (SUB <x.Type> (ZeroExt16to64 x) (ZeroExt16to64 y)))
(Neq8 x y) => (SNEZ (SUB <x.Type> (ZeroExt8to64 x) (ZeroExt8to64 y)))
(NeqPtr x y) => (Not (EqPtr x y))
(Neq64 x y) => (Not (Eq64 x y))
(Neq32 x y) => (Not (Eq32 x y))
(Neq16 x y) => (Not (Eq16 x y))
(Neq8 x y) => (Not (Eq8 x y))
(Neq(64|32)F ...) => (FNE(D|S) ...)
// Loads

View file

@ -1081,20 +1081,50 @@ func rewriteValueRISCV64_OpEq32(v *Value) bool {
b := v.Block
typ := &b.Func.Config.Types
// match: (Eq32 x y)
// cond: x.Type.IsSigned()
// result: (SEQZ (SUB <x.Type> (SignExt32to64 x) (SignExt32to64 y)))
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
x := v_0
y := v_1
if !(x.Type.IsSigned()) {
continue
}
v.reset(OpRISCV64SEQZ)
v0 := b.NewValue0(v.Pos, OpRISCV64SUB, x.Type)
v1 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
v1.AddArg(x)
v2 := b.NewValue0(v.Pos, OpSignExt32to64, typ.Int64)
v2.AddArg(y)
v0.AddArg2(v1, v2)
v.AddArg(v0)
return true
}
break
}
// match: (Eq32 x y)
// cond: !x.Type.IsSigned()
// result: (SEQZ (SUB <x.Type> (ZeroExt32to64 x) (ZeroExt32to64 y)))
for {
x := v_0
y := v_1
v.reset(OpRISCV64SEQZ)
v0 := b.NewValue0(v.Pos, OpRISCV64SUB, x.Type)
v1 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
v1.AddArg(x)
v2 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
v2.AddArg(y)
v0.AddArg2(v1, v2)
v.AddArg(v0)
return true
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
x := v_0
y := v_1
if !(!x.Type.IsSigned()) {
continue
}
v.reset(OpRISCV64SEQZ)
v0 := b.NewValue0(v.Pos, OpRISCV64SUB, x.Type)
v1 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
v1.AddArg(x)
v2 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
v2.AddArg(y)
v0.AddArg2(v1, v2)
v.AddArg(v0)
return true
}
break
}
return false
}
func rewriteValueRISCV64_OpEq64(v *Value) bool {
v_1 := v.Args[1]
@ -2942,17 +2972,13 @@ func rewriteValueRISCV64_OpNeq16(v *Value) bool {
b := v.Block
typ := &b.Func.Config.Types
// match: (Neq16 x y)
// result: (SNEZ (SUB <x.Type> (ZeroExt16to64 x) (ZeroExt16to64 y)))
// result: (Not (Eq16 x y))
for {
x := v_0
y := v_1
v.reset(OpRISCV64SNEZ)
v0 := b.NewValue0(v.Pos, OpRISCV64SUB, x.Type)
v1 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
v1.AddArg(x)
v2 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
v2.AddArg(y)
v0.AddArg2(v1, v2)
v.reset(OpNot)
v0 := b.NewValue0(v.Pos, OpEq16, typ.Bool)
v0.AddArg2(x, y)
v.AddArg(v0)
return true
}
@ -2963,17 +2989,13 @@ func rewriteValueRISCV64_OpNeq32(v *Value) bool {
b := v.Block
typ := &b.Func.Config.Types
// match: (Neq32 x y)
// result: (SNEZ (SUB <x.Type> (ZeroExt32to64 x) (ZeroExt32to64 y)))
// result: (Not (Eq32 x y))
for {
x := v_0
y := v_1
v.reset(OpRISCV64SNEZ)
v0 := b.NewValue0(v.Pos, OpRISCV64SUB, x.Type)
v1 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
v1.AddArg(x)
v2 := b.NewValue0(v.Pos, OpZeroExt32to64, typ.UInt64)
v2.AddArg(y)
v0.AddArg2(v1, v2)
v.reset(OpNot)
v0 := b.NewValue0(v.Pos, OpEq32, typ.Bool)
v0.AddArg2(x, y)
v.AddArg(v0)
return true
}
@ -2982,13 +3004,14 @@ func rewriteValueRISCV64_OpNeq64(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
typ := &b.Func.Config.Types
// match: (Neq64 x y)
// result: (SNEZ (SUB <x.Type> x y))
// result: (Not (Eq64 x y))
for {
x := v_0
y := v_1
v.reset(OpRISCV64SNEZ)
v0 := b.NewValue0(v.Pos, OpRISCV64SUB, x.Type)
v.reset(OpNot)
v0 := b.NewValue0(v.Pos, OpEq64, typ.Bool)
v0.AddArg2(x, y)
v.AddArg(v0)
return true
@ -3000,17 +3023,13 @@ func rewriteValueRISCV64_OpNeq8(v *Value) bool {
b := v.Block
typ := &b.Func.Config.Types
// match: (Neq8 x y)
// result: (SNEZ (SUB <x.Type> (ZeroExt8to64 x) (ZeroExt8to64 y)))
// result: (Not (Eq8 x y))
for {
x := v_0
y := v_1
v.reset(OpRISCV64SNEZ)
v0 := b.NewValue0(v.Pos, OpRISCV64SUB, x.Type)
v1 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
v1.AddArg(x)
v2 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
v2.AddArg(y)
v0.AddArg2(v1, v2)
v.reset(OpNot)
v0 := b.NewValue0(v.Pos, OpEq8, typ.Bool)
v0.AddArg2(x, y)
v.AddArg(v0)
return true
}
@ -3038,12 +3057,12 @@ func rewriteValueRISCV64_OpNeqPtr(v *Value) bool {
b := v.Block
typ := &b.Func.Config.Types
// match: (NeqPtr x y)
// result: (SNEZ (SUB <typ.Uintptr> x y))
// result: (Not (EqPtr x y))
for {
x := v_0
y := v_1
v.reset(OpRISCV64SNEZ)
v0 := b.NewValue0(v.Pos, OpRISCV64SUB, typ.Uintptr)
v.reset(OpNot)
v0 := b.NewValue0(v.Pos, OpEqPtr, typ.Bool)
v0.AddArg2(x, y)
v.AddArg(v0)
return true