From: Josh Bleecher Snyder Date: Tue, 25 Apr 2017 22:55:52 +0000 (-0700) Subject: cmd/compile: add minor bit twiddling optimizations X-Git-Tag: go1.9beta1~367 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=00db0cbf8648ca5b856aa3bd0179d205e6626473;p=gostls13.git cmd/compile: add minor bit twiddling optimizations Noticed while adding to the bitset implementation in cmd/compile/internal/gc. The (Com (Const)) optimizations were already present in the AMD64 lowered optimizations. They trigger 118, 44, 262, and 108 times respectively for int sizes 8, 16, 32, and 64 in a run of make.bash. The (Or (And)) optimization is new. It triggers 3 times for int size 8 and once for int size 64 during make.bash, in packages internal/poll, reflect, encoding/asn1, and go/types, so there is a bit of natural test coverage. Change-Id: I44072864ff88831d5ec7dce37c516d29df056e98 Reviewed-on: https://go-review.googlesource.com/41758 Run-TryBot: Josh Bleecher Snyder TryBot-Result: Gobot Gobot Reviewed-by: Keith Randall --- diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules index c50b91b0cb..321a52d718 100644 --- a/src/cmd/compile/internal/ssa/gen/generic.rules +++ b/src/cmd/compile/internal/ssa/gen/generic.rules @@ -586,6 +586,10 @@ (Com16 (Com16 x)) -> x (Com32 (Com32 x)) -> x (Com64 (Com64 x)) -> x +(Com8 (Const8 [c])) -> (Const8 [^c]) +(Com16 (Const16 [c])) -> (Const16 [^c]) +(Com32 (Const32 [c])) -> (Const32 [^c]) +(Com64 (Const64 [c])) -> (Const64 [^c]) (Neg8 (Sub8 x y)) -> (Sub8 y x) (Neg16 (Sub16 x y)) -> (Sub16 y x) (Neg32 (Sub32 x y)) -> (Sub32 y x) @@ -608,6 +612,18 @@ (Xor16 x (Xor16 x y)) -> y (Xor8 x (Xor8 x y)) -> y +// Ands clear bits. Ors set bits. +// If a subsequent Or will set all the bits +// that an And cleared, we can skip the And. +// This happens in bitmasking code like: +// x &^= 3 << shift // clear two old bits +// x |= v << shift // set two new bits +// when shift is a small constant and v ends up a constant 3. +(Or8 (And8 x (Const8 [c2])) (Const8 [c1])) && ^(c1 | c2) == 0 -> (Or8 (Const8 [c1]) x) +(Or16 (And16 x (Const16 [c2])) (Const16 [c1])) && ^(c1 | c2) == 0 -> (Or16 (Const16 [c1]) x) +(Or32 (And32 x (Const32 [c2])) (Const32 [c1])) && ^(c1 | c2) == 0 -> (Or32 (Const32 [c1]) x) +(Or64 (And64 x (Const64 [c2])) (Const64 [c1])) && ^(c1 | c2) == 0 -> (Or64 (Const64 [c1]) x) + (Trunc64to8 (And64 (Const64 [y]) x)) && y&0xFF == 0xFF -> (Trunc64to8 x) (Trunc64to16 (And64 (Const64 [y]) x)) && y&0xFFFF == 0xFFFF -> (Trunc64to16 x) (Trunc64to32 (And64 (Const64 [y]) x)) && y&0xFFFFFFFF == 0xFFFFFFFF -> (Trunc64to32 x) diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go index 70ce0d2621..72d9c818b2 100644 --- a/src/cmd/compile/internal/ssa/rewritegeneric.go +++ b/src/cmd/compile/internal/ssa/rewritegeneric.go @@ -266,13 +266,13 @@ func rewriteValuegeneric(v *Value) bool { case OpOffPtr: return rewriteValuegeneric_OpOffPtr_0(v) case OpOr16: - return rewriteValuegeneric_OpOr16_0(v) || rewriteValuegeneric_OpOr16_10(v) + return rewriteValuegeneric_OpOr16_0(v) || rewriteValuegeneric_OpOr16_10(v) || rewriteValuegeneric_OpOr16_20(v) case OpOr32: - return rewriteValuegeneric_OpOr32_0(v) || rewriteValuegeneric_OpOr32_10(v) + return rewriteValuegeneric_OpOr32_0(v) || rewriteValuegeneric_OpOr32_10(v) || rewriteValuegeneric_OpOr32_20(v) case OpOr64: - return rewriteValuegeneric_OpOr64_0(v) || rewriteValuegeneric_OpOr64_10(v) + return rewriteValuegeneric_OpOr64_0(v) || rewriteValuegeneric_OpOr64_10(v) || rewriteValuegeneric_OpOr64_20(v) case OpOr8: - return rewriteValuegeneric_OpOr8_0(v) || rewriteValuegeneric_OpOr8_10(v) + return rewriteValuegeneric_OpOr8_0(v) || rewriteValuegeneric_OpOr8_10(v) || rewriteValuegeneric_OpOr8_20(v) case OpPhi: return rewriteValuegeneric_OpPhi_0(v) case OpPtrIndex: @@ -5411,6 +5411,19 @@ func rewriteValuegeneric_OpCom16_0(v *Value) bool { v.AddArg(x) return true } + // match: (Com16 (Const16 [c])) + // cond: + // result: (Const16 [^c]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst16 { + break + } + c := v_0.AuxInt + v.reset(OpConst16) + v.AuxInt = ^c + return true + } return false } func rewriteValuegeneric_OpCom32_0(v *Value) bool { @@ -5428,6 +5441,19 @@ func rewriteValuegeneric_OpCom32_0(v *Value) bool { v.AddArg(x) return true } + // match: (Com32 (Const32 [c])) + // cond: + // result: (Const32 [^c]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst32 { + break + } + c := v_0.AuxInt + v.reset(OpConst32) + v.AuxInt = ^c + return true + } return false } func rewriteValuegeneric_OpCom64_0(v *Value) bool { @@ -5445,6 +5471,19 @@ func rewriteValuegeneric_OpCom64_0(v *Value) bool { v.AddArg(x) return true } + // match: (Com64 (Const64 [c])) + // cond: + // result: (Const64 [^c]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst64 { + break + } + c := v_0.AuxInt + v.reset(OpConst64) + v.AuxInt = ^c + return true + } return false } func rewriteValuegeneric_OpCom8_0(v *Value) bool { @@ -5462,6 +5501,19 @@ func rewriteValuegeneric_OpCom8_0(v *Value) bool { v.AddArg(x) return true } + // match: (Com8 (Const8 [c])) + // cond: + // result: (Const8 [^c]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst8 { + break + } + c := v_0.AuxInt + v.reset(OpConst8) + v.AuxInt = ^c + return true + } return false } func rewriteValuegeneric_OpConstInterface_0(v *Value) bool { @@ -15447,6 +15499,126 @@ func rewriteValuegeneric_OpOr16_10(v *Value) bool { v.AddArg(y) return true } + // match: (Or16 (And16 x (Const16 [c2])) (Const16 [c1])) + // cond: ^(c1 | c2) == 0 + // result: (Or16 (Const16 [c1]) x) + for { + v_0 := v.Args[0] + if v_0.Op != OpAnd16 { + break + } + x := v_0.Args[0] + v_0_1 := v_0.Args[1] + if v_0_1.Op != OpConst16 { + break + } + c2 := v_0_1.AuxInt + v_1 := v.Args[1] + if v_1.Op != OpConst16 { + break + } + t := v_1.Type + c1 := v_1.AuxInt + if !(^(c1 | c2) == 0) { + break + } + v.reset(OpOr16) + v0 := b.NewValue0(v.Pos, OpConst16, t) + v0.AuxInt = c1 + v.AddArg(v0) + v.AddArg(x) + return true + } + // match: (Or16 (And16 (Const16 [c2]) x) (Const16 [c1])) + // cond: ^(c1 | c2) == 0 + // result: (Or16 (Const16 [c1]) x) + for { + v_0 := v.Args[0] + if v_0.Op != OpAnd16 { + break + } + v_0_0 := v_0.Args[0] + if v_0_0.Op != OpConst16 { + break + } + c2 := v_0_0.AuxInt + x := v_0.Args[1] + v_1 := v.Args[1] + if v_1.Op != OpConst16 { + break + } + t := v_1.Type + c1 := v_1.AuxInt + if !(^(c1 | c2) == 0) { + break + } + v.reset(OpOr16) + v0 := b.NewValue0(v.Pos, OpConst16, t) + v0.AuxInt = c1 + v.AddArg(v0) + v.AddArg(x) + return true + } + // match: (Or16 (Const16 [c1]) (And16 x (Const16 [c2]))) + // cond: ^(c1 | c2) == 0 + // result: (Or16 (Const16 [c1]) x) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst16 { + break + } + t := v_0.Type + c1 := v_0.AuxInt + v_1 := v.Args[1] + if v_1.Op != OpAnd16 { + break + } + x := v_1.Args[0] + v_1_1 := v_1.Args[1] + if v_1_1.Op != OpConst16 { + break + } + c2 := v_1_1.AuxInt + if !(^(c1 | c2) == 0) { + break + } + v.reset(OpOr16) + v0 := b.NewValue0(v.Pos, OpConst16, t) + v0.AuxInt = c1 + v.AddArg(v0) + v.AddArg(x) + return true + } + // match: (Or16 (Const16 [c1]) (And16 (Const16 [c2]) x)) + // cond: ^(c1 | c2) == 0 + // result: (Or16 (Const16 [c1]) x) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst16 { + break + } + t := v_0.Type + c1 := v_0.AuxInt + v_1 := v.Args[1] + if v_1.Op != OpAnd16 { + break + } + v_1_0 := v_1.Args[0] + if v_1_0.Op != OpConst16 { + break + } + c2 := v_1_0.AuxInt + x := v_1.Args[1] + if !(^(c1 | c2) == 0) { + break + } + v.reset(OpOr16) + v0 := b.NewValue0(v.Pos, OpConst16, t) + v0.AuxInt = c1 + v.AddArg(v0) + v.AddArg(x) + return true + } // match: (Or16 (Or16 i:(Const16 ) z) x) // cond: (z.Op != OpConst16 && x.Op != OpConst16) // result: (Or16 i (Or16 z x)) @@ -15581,6 +15753,11 @@ func rewriteValuegeneric_OpOr16_10(v *Value) bool { v.AddArg(x) return true } + return false +} +func rewriteValuegeneric_OpOr16_20(v *Value) bool { + b := v.Block + _ = b // match: (Or16 (Const16 [c]) (Or16 x (Const16 [d]))) // cond: // result: (Or16 (Const16 [int64(int16(c|d))]) x) @@ -15864,6 +16041,126 @@ func rewriteValuegeneric_OpOr32_10(v *Value) bool { v.AddArg(y) return true } + // match: (Or32 (And32 x (Const32 [c2])) (Const32 [c1])) + // cond: ^(c1 | c2) == 0 + // result: (Or32 (Const32 [c1]) x) + for { + v_0 := v.Args[0] + if v_0.Op != OpAnd32 { + break + } + x := v_0.Args[0] + v_0_1 := v_0.Args[1] + if v_0_1.Op != OpConst32 { + break + } + c2 := v_0_1.AuxInt + v_1 := v.Args[1] + if v_1.Op != OpConst32 { + break + } + t := v_1.Type + c1 := v_1.AuxInt + if !(^(c1 | c2) == 0) { + break + } + v.reset(OpOr32) + v0 := b.NewValue0(v.Pos, OpConst32, t) + v0.AuxInt = c1 + v.AddArg(v0) + v.AddArg(x) + return true + } + // match: (Or32 (And32 (Const32 [c2]) x) (Const32 [c1])) + // cond: ^(c1 | c2) == 0 + // result: (Or32 (Const32 [c1]) x) + for { + v_0 := v.Args[0] + if v_0.Op != OpAnd32 { + break + } + v_0_0 := v_0.Args[0] + if v_0_0.Op != OpConst32 { + break + } + c2 := v_0_0.AuxInt + x := v_0.Args[1] + v_1 := v.Args[1] + if v_1.Op != OpConst32 { + break + } + t := v_1.Type + c1 := v_1.AuxInt + if !(^(c1 | c2) == 0) { + break + } + v.reset(OpOr32) + v0 := b.NewValue0(v.Pos, OpConst32, t) + v0.AuxInt = c1 + v.AddArg(v0) + v.AddArg(x) + return true + } + // match: (Or32 (Const32 [c1]) (And32 x (Const32 [c2]))) + // cond: ^(c1 | c2) == 0 + // result: (Or32 (Const32 [c1]) x) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst32 { + break + } + t := v_0.Type + c1 := v_0.AuxInt + v_1 := v.Args[1] + if v_1.Op != OpAnd32 { + break + } + x := v_1.Args[0] + v_1_1 := v_1.Args[1] + if v_1_1.Op != OpConst32 { + break + } + c2 := v_1_1.AuxInt + if !(^(c1 | c2) == 0) { + break + } + v.reset(OpOr32) + v0 := b.NewValue0(v.Pos, OpConst32, t) + v0.AuxInt = c1 + v.AddArg(v0) + v.AddArg(x) + return true + } + // match: (Or32 (Const32 [c1]) (And32 (Const32 [c2]) x)) + // cond: ^(c1 | c2) == 0 + // result: (Or32 (Const32 [c1]) x) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst32 { + break + } + t := v_0.Type + c1 := v_0.AuxInt + v_1 := v.Args[1] + if v_1.Op != OpAnd32 { + break + } + v_1_0 := v_1.Args[0] + if v_1_0.Op != OpConst32 { + break + } + c2 := v_1_0.AuxInt + x := v_1.Args[1] + if !(^(c1 | c2) == 0) { + break + } + v.reset(OpOr32) + v0 := b.NewValue0(v.Pos, OpConst32, t) + v0.AuxInt = c1 + v.AddArg(v0) + v.AddArg(x) + return true + } // match: (Or32 (Or32 i:(Const32 ) z) x) // cond: (z.Op != OpConst32 && x.Op != OpConst32) // result: (Or32 i (Or32 z x)) @@ -15998,6 +16295,11 @@ func rewriteValuegeneric_OpOr32_10(v *Value) bool { v.AddArg(x) return true } + return false +} +func rewriteValuegeneric_OpOr32_20(v *Value) bool { + b := v.Block + _ = b // match: (Or32 (Const32 [c]) (Or32 x (Const32 [d]))) // cond: // result: (Or32 (Const32 [int64(int32(c|d))]) x) @@ -16281,6 +16583,126 @@ func rewriteValuegeneric_OpOr64_10(v *Value) bool { v.AddArg(y) return true } + // match: (Or64 (And64 x (Const64 [c2])) (Const64 [c1])) + // cond: ^(c1 | c2) == 0 + // result: (Or64 (Const64 [c1]) x) + for { + v_0 := v.Args[0] + if v_0.Op != OpAnd64 { + break + } + x := v_0.Args[0] + v_0_1 := v_0.Args[1] + if v_0_1.Op != OpConst64 { + break + } + c2 := v_0_1.AuxInt + v_1 := v.Args[1] + if v_1.Op != OpConst64 { + break + } + t := v_1.Type + c1 := v_1.AuxInt + if !(^(c1 | c2) == 0) { + break + } + v.reset(OpOr64) + v0 := b.NewValue0(v.Pos, OpConst64, t) + v0.AuxInt = c1 + v.AddArg(v0) + v.AddArg(x) + return true + } + // match: (Or64 (And64 (Const64 [c2]) x) (Const64 [c1])) + // cond: ^(c1 | c2) == 0 + // result: (Or64 (Const64 [c1]) x) + for { + v_0 := v.Args[0] + if v_0.Op != OpAnd64 { + break + } + v_0_0 := v_0.Args[0] + if v_0_0.Op != OpConst64 { + break + } + c2 := v_0_0.AuxInt + x := v_0.Args[1] + v_1 := v.Args[1] + if v_1.Op != OpConst64 { + break + } + t := v_1.Type + c1 := v_1.AuxInt + if !(^(c1 | c2) == 0) { + break + } + v.reset(OpOr64) + v0 := b.NewValue0(v.Pos, OpConst64, t) + v0.AuxInt = c1 + v.AddArg(v0) + v.AddArg(x) + return true + } + // match: (Or64 (Const64 [c1]) (And64 x (Const64 [c2]))) + // cond: ^(c1 | c2) == 0 + // result: (Or64 (Const64 [c1]) x) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst64 { + break + } + t := v_0.Type + c1 := v_0.AuxInt + v_1 := v.Args[1] + if v_1.Op != OpAnd64 { + break + } + x := v_1.Args[0] + v_1_1 := v_1.Args[1] + if v_1_1.Op != OpConst64 { + break + } + c2 := v_1_1.AuxInt + if !(^(c1 | c2) == 0) { + break + } + v.reset(OpOr64) + v0 := b.NewValue0(v.Pos, OpConst64, t) + v0.AuxInt = c1 + v.AddArg(v0) + v.AddArg(x) + return true + } + // match: (Or64 (Const64 [c1]) (And64 (Const64 [c2]) x)) + // cond: ^(c1 | c2) == 0 + // result: (Or64 (Const64 [c1]) x) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst64 { + break + } + t := v_0.Type + c1 := v_0.AuxInt + v_1 := v.Args[1] + if v_1.Op != OpAnd64 { + break + } + v_1_0 := v_1.Args[0] + if v_1_0.Op != OpConst64 { + break + } + c2 := v_1_0.AuxInt + x := v_1.Args[1] + if !(^(c1 | c2) == 0) { + break + } + v.reset(OpOr64) + v0 := b.NewValue0(v.Pos, OpConst64, t) + v0.AuxInt = c1 + v.AddArg(v0) + v.AddArg(x) + return true + } // match: (Or64 (Or64 i:(Const64 ) z) x) // cond: (z.Op != OpConst64 && x.Op != OpConst64) // result: (Or64 i (Or64 z x)) @@ -16415,6 +16837,11 @@ func rewriteValuegeneric_OpOr64_10(v *Value) bool { v.AddArg(x) return true } + return false +} +func rewriteValuegeneric_OpOr64_20(v *Value) bool { + b := v.Block + _ = b // match: (Or64 (Const64 [c]) (Or64 x (Const64 [d]))) // cond: // result: (Or64 (Const64 [c|d]) x) @@ -16698,6 +17125,126 @@ func rewriteValuegeneric_OpOr8_10(v *Value) bool { v.AddArg(y) return true } + // match: (Or8 (And8 x (Const8 [c2])) (Const8 [c1])) + // cond: ^(c1 | c2) == 0 + // result: (Or8 (Const8 [c1]) x) + for { + v_0 := v.Args[0] + if v_0.Op != OpAnd8 { + break + } + x := v_0.Args[0] + v_0_1 := v_0.Args[1] + if v_0_1.Op != OpConst8 { + break + } + c2 := v_0_1.AuxInt + v_1 := v.Args[1] + if v_1.Op != OpConst8 { + break + } + t := v_1.Type + c1 := v_1.AuxInt + if !(^(c1 | c2) == 0) { + break + } + v.reset(OpOr8) + v0 := b.NewValue0(v.Pos, OpConst8, t) + v0.AuxInt = c1 + v.AddArg(v0) + v.AddArg(x) + return true + } + // match: (Or8 (And8 (Const8 [c2]) x) (Const8 [c1])) + // cond: ^(c1 | c2) == 0 + // result: (Or8 (Const8 [c1]) x) + for { + v_0 := v.Args[0] + if v_0.Op != OpAnd8 { + break + } + v_0_0 := v_0.Args[0] + if v_0_0.Op != OpConst8 { + break + } + c2 := v_0_0.AuxInt + x := v_0.Args[1] + v_1 := v.Args[1] + if v_1.Op != OpConst8 { + break + } + t := v_1.Type + c1 := v_1.AuxInt + if !(^(c1 | c2) == 0) { + break + } + v.reset(OpOr8) + v0 := b.NewValue0(v.Pos, OpConst8, t) + v0.AuxInt = c1 + v.AddArg(v0) + v.AddArg(x) + return true + } + // match: (Or8 (Const8 [c1]) (And8 x (Const8 [c2]))) + // cond: ^(c1 | c2) == 0 + // result: (Or8 (Const8 [c1]) x) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst8 { + break + } + t := v_0.Type + c1 := v_0.AuxInt + v_1 := v.Args[1] + if v_1.Op != OpAnd8 { + break + } + x := v_1.Args[0] + v_1_1 := v_1.Args[1] + if v_1_1.Op != OpConst8 { + break + } + c2 := v_1_1.AuxInt + if !(^(c1 | c2) == 0) { + break + } + v.reset(OpOr8) + v0 := b.NewValue0(v.Pos, OpConst8, t) + v0.AuxInt = c1 + v.AddArg(v0) + v.AddArg(x) + return true + } + // match: (Or8 (Const8 [c1]) (And8 (Const8 [c2]) x)) + // cond: ^(c1 | c2) == 0 + // result: (Or8 (Const8 [c1]) x) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst8 { + break + } + t := v_0.Type + c1 := v_0.AuxInt + v_1 := v.Args[1] + if v_1.Op != OpAnd8 { + break + } + v_1_0 := v_1.Args[0] + if v_1_0.Op != OpConst8 { + break + } + c2 := v_1_0.AuxInt + x := v_1.Args[1] + if !(^(c1 | c2) == 0) { + break + } + v.reset(OpOr8) + v0 := b.NewValue0(v.Pos, OpConst8, t) + v0.AuxInt = c1 + v.AddArg(v0) + v.AddArg(x) + return true + } // match: (Or8 (Or8 i:(Const8 ) z) x) // cond: (z.Op != OpConst8 && x.Op != OpConst8) // result: (Or8 i (Or8 z x)) @@ -16832,6 +17379,11 @@ func rewriteValuegeneric_OpOr8_10(v *Value) bool { v.AddArg(x) return true } + return false +} +func rewriteValuegeneric_OpOr8_20(v *Value) bool { + b := v.Block + _ = b // match: (Or8 (Const8 [c]) (Or8 x (Const8 [d]))) // cond: // result: (Or8 (Const8 [int64(int8(c|d))]) x)