summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan <Stefan.Mada@utah.edu>2023-05-10 01:34:47 +0000
committerCherry Mui <cherryyz@google.com>2023-05-10 16:32:25 +0000
commit95c4f320d55fabf04ba45685109691f182678c01 (patch)
treed3585e6118bacb6bef294ec37941d13209e7e8f1
parentf30cd520516037b2fdb367ddd8e0851019bf3440 (diff)
downloadgo-git-95c4f320d55fabf04ba45685109691f182678c01.tar.gz
cmd/compile: add De Morgan's rewrite rule
Adds rules that rewrites statements such as ~P&~Q as ~(P|Q) and ~P|~Q as ~(P&Q), removing an extraneous instruction. Change-Id: Icedb97df741680ddf9799df79df78657173aa500 GitHub-Last-Rev: f22e2350c95e9052e990b2351c3c2b0af810e381 GitHub-Pull-Request: golang/go#60018 Reviewed-on: https://go-review.googlesource.com/c/go/+/493175 Reviewed-by: Keith Randall <khr@golang.org> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Stefan M <st3f4nm4d4@gmail.com> Reviewed-by: Keith Randall <khr@google.com> Run-TryBot: Cherry Mui <cherryyz@google.com> Reviewed-by: Cherry Mui <cherryyz@google.com>
-rw-r--r--src/cmd/compile/internal/ssa/_gen/generic.rules4
-rw-r--r--src/cmd/compile/internal/ssa/rewritegeneric.go178
-rw-r--r--test/codegen/logic.go14
3 files changed, 196 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/ssa/_gen/generic.rules b/src/cmd/compile/internal/ssa/_gen/generic.rules
index c7a525abb7..2ee8010857 100644
--- a/src/cmd/compile/internal/ssa/_gen/generic.rules
+++ b/src/cmd/compile/internal/ssa/_gen/generic.rules
@@ -176,6 +176,10 @@
// Convert x * -1 to -x.
(Mul(8|16|32|64) (Const(8|16|32|64) [-1]) x) => (Neg(8|16|32|64) x)
+// DeMorgan's Laws
+(And(8|16|32|64) <t> (Com(8|16|32|64) x) (Com(8|16|32|64) y)) => (Com(8|16|32|64) (Or(8|16|32|64) <t> x y))
+(Or(8|16|32|64) <t> (Com(8|16|32|64) x) (Com(8|16|32|64) y)) => (Com(8|16|32|64) (And(8|16|32|64) <t> x y))
+
// Convert multiplication by a power of two to a shift.
(Mul8 <t> n (Const8 [c])) && isPowerOfTwo8(c) => (Lsh8x64 <t> n (Const64 <typ.UInt64> [log8(c)]))
(Mul16 <t> n (Const16 [c])) && isPowerOfTwo16(c) => (Lsh16x64 <t> n (Const64 <typ.UInt64> [log16(c)]))
diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go
index 6026eac279..78f13e679d 100644
--- a/src/cmd/compile/internal/ssa/rewritegeneric.go
+++ b/src/cmd/compile/internal/ssa/rewritegeneric.go
@@ -3020,6 +3020,27 @@ func rewriteValuegeneric_OpAnd16(v *Value) bool {
}
break
}
+ // match: (And16 <t> (Com16 x) (Com16 y))
+ // result: (Com16 (Or16 <t> x y))
+ for {
+ t := v.Type
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ if v_0.Op != OpCom16 {
+ continue
+ }
+ x := v_0.Args[0]
+ if v_1.Op != OpCom16 {
+ continue
+ }
+ y := v_1.Args[0]
+ v.reset(OpCom16)
+ v0 := b.NewValue0(v.Pos, OpOr16, t)
+ v0.AddArg2(x, y)
+ v.AddArg(v0)
+ return true
+ }
+ break
+ }
// match: (And16 (Const16 [m]) (Rsh16Ux64 _ (Const64 [c])))
// cond: c >= int64(16-ntz16(m))
// result: (Const16 [0])
@@ -3235,6 +3256,27 @@ func rewriteValuegeneric_OpAnd32(v *Value) bool {
}
break
}
+ // match: (And32 <t> (Com32 x) (Com32 y))
+ // result: (Com32 (Or32 <t> x y))
+ for {
+ t := v.Type
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ if v_0.Op != OpCom32 {
+ continue
+ }
+ x := v_0.Args[0]
+ if v_1.Op != OpCom32 {
+ continue
+ }
+ y := v_1.Args[0]
+ v.reset(OpCom32)
+ v0 := b.NewValue0(v.Pos, OpOr32, t)
+ v0.AddArg2(x, y)
+ v.AddArg(v0)
+ return true
+ }
+ break
+ }
// match: (And32 (Const32 [m]) (Rsh32Ux64 _ (Const64 [c])))
// cond: c >= int64(32-ntz32(m))
// result: (Const32 [0])
@@ -3450,6 +3492,27 @@ func rewriteValuegeneric_OpAnd64(v *Value) bool {
}
break
}
+ // match: (And64 <t> (Com64 x) (Com64 y))
+ // result: (Com64 (Or64 <t> x y))
+ for {
+ t := v.Type
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ if v_0.Op != OpCom64 {
+ continue
+ }
+ x := v_0.Args[0]
+ if v_1.Op != OpCom64 {
+ continue
+ }
+ y := v_1.Args[0]
+ v.reset(OpCom64)
+ v0 := b.NewValue0(v.Pos, OpOr64, t)
+ v0.AddArg2(x, y)
+ v.AddArg(v0)
+ return true
+ }
+ break
+ }
// match: (And64 (Const64 [m]) (Rsh64Ux64 _ (Const64 [c])))
// cond: c >= int64(64-ntz64(m))
// result: (Const64 [0])
@@ -3665,6 +3728,27 @@ func rewriteValuegeneric_OpAnd8(v *Value) bool {
}
break
}
+ // match: (And8 <t> (Com8 x) (Com8 y))
+ // result: (Com8 (Or8 <t> x y))
+ for {
+ t := v.Type
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ if v_0.Op != OpCom8 {
+ continue
+ }
+ x := v_0.Args[0]
+ if v_1.Op != OpCom8 {
+ continue
+ }
+ y := v_1.Args[0]
+ v.reset(OpCom8)
+ v0 := b.NewValue0(v.Pos, OpOr8, t)
+ v0.AddArg2(x, y)
+ v.AddArg(v0)
+ return true
+ }
+ break
+ }
// match: (And8 (Const8 [m]) (Rsh8Ux64 _ (Const64 [c])))
// cond: c >= int64(8-ntz8(m))
// result: (Const8 [0])
@@ -11096,6 +11180,16 @@ func rewriteValuegeneric_OpIsNonNil(v *Value) bool {
v.AuxInt = boolToAuxInt(true)
return true
}
+ // match: (IsNonNil (LocalAddr _ _))
+ // result: (ConstBool [true])
+ for {
+ if v_0.Op != OpLocalAddr {
+ break
+ }
+ v.reset(OpConstBool)
+ v.AuxInt = boolToAuxInt(true)
+ return true
+ }
return false
}
func rewriteValuegeneric_OpIsSliceInBounds(v *Value) bool {
@@ -19109,6 +19203,27 @@ func rewriteValuegeneric_OpOr16(v *Value) bool {
}
break
}
+ // match: (Or16 <t> (Com16 x) (Com16 y))
+ // result: (Com16 (And16 <t> x y))
+ for {
+ t := v.Type
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ if v_0.Op != OpCom16 {
+ continue
+ }
+ x := v_0.Args[0]
+ if v_1.Op != OpCom16 {
+ continue
+ }
+ y := v_1.Args[0]
+ v.reset(OpCom16)
+ v0 := b.NewValue0(v.Pos, OpAnd16, t)
+ v0.AddArg2(x, y)
+ v.AddArg(v0)
+ return true
+ }
+ break
+ }
// match: (Or16 x x)
// result: x
for {
@@ -19613,6 +19728,27 @@ func rewriteValuegeneric_OpOr32(v *Value) bool {
}
break
}
+ // match: (Or32 <t> (Com32 x) (Com32 y))
+ // result: (Com32 (And32 <t> x y))
+ for {
+ t := v.Type
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ if v_0.Op != OpCom32 {
+ continue
+ }
+ x := v_0.Args[0]
+ if v_1.Op != OpCom32 {
+ continue
+ }
+ y := v_1.Args[0]
+ v.reset(OpCom32)
+ v0 := b.NewValue0(v.Pos, OpAnd32, t)
+ v0.AddArg2(x, y)
+ v.AddArg(v0)
+ return true
+ }
+ break
+ }
// match: (Or32 x x)
// result: x
for {
@@ -20117,6 +20253,27 @@ func rewriteValuegeneric_OpOr64(v *Value) bool {
}
break
}
+ // match: (Or64 <t> (Com64 x) (Com64 y))
+ // result: (Com64 (And64 <t> x y))
+ for {
+ t := v.Type
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ if v_0.Op != OpCom64 {
+ continue
+ }
+ x := v_0.Args[0]
+ if v_1.Op != OpCom64 {
+ continue
+ }
+ y := v_1.Args[0]
+ v.reset(OpCom64)
+ v0 := b.NewValue0(v.Pos, OpAnd64, t)
+ v0.AddArg2(x, y)
+ v.AddArg(v0)
+ return true
+ }
+ break
+ }
// match: (Or64 x x)
// result: x
for {
@@ -20621,6 +20778,27 @@ func rewriteValuegeneric_OpOr8(v *Value) bool {
}
break
}
+ // match: (Or8 <t> (Com8 x) (Com8 y))
+ // result: (Com8 (And8 <t> x y))
+ for {
+ t := v.Type
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ if v_0.Op != OpCom8 {
+ continue
+ }
+ x := v_0.Args[0]
+ if v_1.Op != OpCom8 {
+ continue
+ }
+ y := v_1.Args[0]
+ v.reset(OpCom8)
+ v0 := b.NewValue0(v.Pos, OpAnd8, t)
+ v0.AddArg2(x, y)
+ v.AddArg(v0)
+ return true
+ }
+ break
+ }
// match: (Or8 x x)
// result: x
for {
diff --git a/test/codegen/logic.go b/test/codegen/logic.go
index 748c639d6b..ac33f91dad 100644
--- a/test/codegen/logic.go
+++ b/test/codegen/logic.go
@@ -25,3 +25,17 @@ func ornot(x, y int) int {
z := x | ^y
return z
}
+
+// Verify that (OR (NOT x) (NOT y)) rewrites to (NOT (AND x y))
+func orDemorgans(x, y int) int {
+ // amd64:"AND",-"OR"
+ z := ^x | ^y
+ return z
+}
+
+// Verify that (AND (NOT x) (NOT y)) rewrites to (NOT (OR x y))
+func andDemorgans(x, y int) int {
+ // amd64:"OR",-"AND"
+ z := ^x & ^y
+ return z
+}