mirror of
https://github.com/golang/go.git
synced 2026-07-30 21:34:12 +08:00
cmd/compile: ssa rewrite x-(x&y) => x&^y
This allows to rewrite: AND BX, AX SUB AX, BX Into (with GOAMD64=v3): ANDN AX, BX, AX Which is twice as fast, and smaller. Into (without GOAMD64=v3): NOT BX AND AX, BX Which if AX's dependency isn't resolved yet but BX is in most cases twice as fast because now the NOT BX and AX's depency can execute in parallel. In other cases, it has negligible positive impact. Other instructions set will also benefit from the pipelining advantage And also benefit from the smaller ANDN instruction if they have something similar. Help reduce ChaCha20 and Poly1305 to #52563 Change-Id: I0a0a3fe553b857e13c61fbf52f9765377615a898 Reviewed-on: https://go-review.googlesource.com/c/go/+/786700 Reviewed-by: Keith Randall <khr@golang.org> Reviewed-by: Keith Randall <khr@google.com> Auto-Submit: Jorropo <jorropo.pgm@gmail.com> LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Carlos Amedee <carlos@golang.org>
This commit is contained in:
parent
e798729d8c
commit
1008f900f6
@ -1602,6 +1602,7 @@
|
||||
|
||||
// CPUID feature: BMI1.
|
||||
(AND(Q|L) x (NOT(Q|L) y)) && buildcfg.GOAMD64 >= 3 => (ANDN(Q|L) x y)
|
||||
(SUB(Q|L) x (AND(Q|L) x y)) && buildcfg.GOAMD64 >= 3 => (ANDN(Q|L) x y)
|
||||
(AND(Q|L) x (NEG(Q|L) x)) && buildcfg.GOAMD64 >= 3 => (BLSI(Q|L) x)
|
||||
(XOR(Q|L) x (ADD(Q|L)const [-1] x)) && buildcfg.GOAMD64 >= 3 => (BLSMSK(Q|L) x)
|
||||
(AND(Q|L) <t> x (ADD(Q|L)const [-1] x)) && buildcfg.GOAMD64 >= 3 => (Select0 <t> (BLSR(Q|L) x))
|
||||
|
||||
@ -708,6 +708,9 @@
|
||||
(Or(64|32|16|8) x (Or(64|32|16|8) x y)) => (Or(64|32|16|8) x y)
|
||||
(Xor(64|32|16|8) x (Xor(64|32|16|8) x y)) => y
|
||||
|
||||
// x-(x&y) == x&^y
|
||||
(Sub(64|32|16|8) x (And(64|32|16|8) <t> x y)) => (And(64|32|16|8) x (Com(64|32|16|8) <t> y))
|
||||
|
||||
// Fold comparisons with numeric bounds
|
||||
(Less(64|32|16|8)U _ (Const(64|32|16|8) [0])) => (ConstBool [false])
|
||||
(Leq(64|32|16|8)U (Const(64|32|16|8) [0]) _) => (ConstBool [true])
|
||||
|
||||
@ -40193,6 +40193,31 @@ func rewriteValueAMD64_OpAMD64SUBL(v *Value) bool {
|
||||
v.AddArg3(x, ptr, mem)
|
||||
return true
|
||||
}
|
||||
// match: (SUBL x (ANDL x y))
|
||||
// cond: buildcfg.GOAMD64 >= 3
|
||||
// result: (ANDNL x y)
|
||||
for {
|
||||
x := v_0
|
||||
if v_1.Op != OpAMD64ANDL {
|
||||
break
|
||||
}
|
||||
_ = v_1.Args[1]
|
||||
v_1_0 := v_1.Args[0]
|
||||
v_1_1 := v_1.Args[1]
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_1_0, v_1_1 = _i0+1, v_1_1, v_1_0 {
|
||||
if x != v_1_0 {
|
||||
continue
|
||||
}
|
||||
y := v_1_1
|
||||
if !(buildcfg.GOAMD64 >= 3) {
|
||||
continue
|
||||
}
|
||||
v.reset(OpAMD64ANDNL)
|
||||
v.AddArg2(x, y)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64_OpAMD64SUBLconst(v *Value) bool {
|
||||
@ -40435,6 +40460,31 @@ func rewriteValueAMD64_OpAMD64SUBQ(v *Value) bool {
|
||||
v.AddArg3(x, ptr, mem)
|
||||
return true
|
||||
}
|
||||
// match: (SUBQ x (ANDQ x y))
|
||||
// cond: buildcfg.GOAMD64 >= 3
|
||||
// result: (ANDNQ x y)
|
||||
for {
|
||||
x := v_0
|
||||
if v_1.Op != OpAMD64ANDQ {
|
||||
break
|
||||
}
|
||||
_ = v_1.Args[1]
|
||||
v_1_0 := v_1.Args[0]
|
||||
v_1_1 := v_1.Args[1]
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_1_0, v_1_1 = _i0+1, v_1_1, v_1_0 {
|
||||
if x != v_1_0 {
|
||||
continue
|
||||
}
|
||||
y := v_1_1
|
||||
if !(buildcfg.GOAMD64 >= 3) {
|
||||
continue
|
||||
}
|
||||
v.reset(OpAMD64ANDNQ)
|
||||
v.AddArg2(x, y)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64_OpAMD64SUBQborrow(v *Value) bool {
|
||||
|
||||
@ -35967,6 +35967,30 @@ func rewriteValuegeneric_OpSub16(v *Value) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Sub16 x (And16 <t> x y))
|
||||
// result: (And16 x (Com16 <t> y))
|
||||
for {
|
||||
x := v_0
|
||||
if v_1.Op != OpAnd16 {
|
||||
break
|
||||
}
|
||||
t := v_1.Type
|
||||
_ = v_1.Args[1]
|
||||
v_1_0 := v_1.Args[0]
|
||||
v_1_1 := v_1.Args[1]
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_1_0, v_1_1 = _i0+1, v_1_1, v_1_0 {
|
||||
if x != v_1_0 {
|
||||
continue
|
||||
}
|
||||
y := v_1_1
|
||||
v.reset(OpAnd16)
|
||||
v0 := b.NewValue0(v.Pos, OpCom16, t)
|
||||
v0.AddArg(y)
|
||||
v.AddArg2(x, v0)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Sub16 (Add16 x y) x)
|
||||
// result: y
|
||||
for {
|
||||
@ -36340,6 +36364,30 @@ func rewriteValuegeneric_OpSub32(v *Value) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Sub32 x (And32 <t> x y))
|
||||
// result: (And32 x (Com32 <t> y))
|
||||
for {
|
||||
x := v_0
|
||||
if v_1.Op != OpAnd32 {
|
||||
break
|
||||
}
|
||||
t := v_1.Type
|
||||
_ = v_1.Args[1]
|
||||
v_1_0 := v_1.Args[0]
|
||||
v_1_1 := v_1.Args[1]
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_1_0, v_1_1 = _i0+1, v_1_1, v_1_0 {
|
||||
if x != v_1_0 {
|
||||
continue
|
||||
}
|
||||
y := v_1_1
|
||||
v.reset(OpAnd32)
|
||||
v0 := b.NewValue0(v.Pos, OpCom32, t)
|
||||
v0.AddArg(y)
|
||||
v.AddArg2(x, v0)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Sub32 (Add32 x y) x)
|
||||
// result: y
|
||||
for {
|
||||
@ -36737,6 +36785,30 @@ func rewriteValuegeneric_OpSub64(v *Value) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Sub64 x (And64 <t> x y))
|
||||
// result: (And64 x (Com64 <t> y))
|
||||
for {
|
||||
x := v_0
|
||||
if v_1.Op != OpAnd64 {
|
||||
break
|
||||
}
|
||||
t := v_1.Type
|
||||
_ = v_1.Args[1]
|
||||
v_1_0 := v_1.Args[0]
|
||||
v_1_1 := v_1.Args[1]
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_1_0, v_1_1 = _i0+1, v_1_1, v_1_0 {
|
||||
if x != v_1_0 {
|
||||
continue
|
||||
}
|
||||
y := v_1_1
|
||||
v.reset(OpAnd64)
|
||||
v0 := b.NewValue0(v.Pos, OpCom64, t)
|
||||
v0.AddArg(y)
|
||||
v.AddArg2(x, v0)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Sub64 (Add64 x y) x)
|
||||
// result: y
|
||||
for {
|
||||
@ -37134,6 +37206,30 @@ func rewriteValuegeneric_OpSub8(v *Value) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Sub8 x (And8 <t> x y))
|
||||
// result: (And8 x (Com8 <t> y))
|
||||
for {
|
||||
x := v_0
|
||||
if v_1.Op != OpAnd8 {
|
||||
break
|
||||
}
|
||||
t := v_1.Type
|
||||
_ = v_1.Args[1]
|
||||
v_1_0 := v_1.Args[0]
|
||||
v_1_1 := v_1.Args[1]
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_1_0, v_1_1 = _i0+1, v_1_1, v_1_0 {
|
||||
if x != v_1_0 {
|
||||
continue
|
||||
}
|
||||
y := v_1_1
|
||||
v.reset(OpAnd8)
|
||||
v0 := b.NewValue0(v.Pos, OpCom8, t)
|
||||
v0.AddArg(y)
|
||||
v.AddArg2(x, v0)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Sub8 (Add8 x y) x)
|
||||
// result: y
|
||||
for {
|
||||
|
||||
@ -207,3 +207,15 @@ func shlrx32_load(x []uint32, i int, s uint32) uint32 {
|
||||
s = x[i+1] << s
|
||||
return s
|
||||
}
|
||||
|
||||
func XSubXandYAndn64(x, y uint64) uint64 {
|
||||
// amd64/v1:"ANDQ" "NOTQ" -"SUBQ"
|
||||
// amd64/v3:"ANDNQ" -"SUBQ" -"ANDQ"
|
||||
return x - (x & y)
|
||||
}
|
||||
|
||||
func XSubXandYAndn32(x, y uint32) uint32 {
|
||||
// amd64/v1:"ANDL" "NOTL" -"SUBL"
|
||||
// amd64/v3:"ANDNL" -"SUBL" -"ANDL"
|
||||
return x - (x & y)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user