diff --git a/src/cmd/compile/internal/ssa/_gen/AMD64.rules b/src/cmd/compile/internal/ssa/_gen/AMD64.rules
index eb08ce8..bdf0230 100644
--- a/src/cmd/compile/internal/ssa/_gen/AMD64.rules
+++ b/src/cmd/compile/internal/ssa/_gen/AMD64.rules
@@ -42,6 +42,12 @@
(SUBQborrow x (MOVQconst [c])) && is32Bit(c) => (SUBQconstborrow x [int32(c)])
(Select1 (NEGLflags (MOVQconst [0]))) => (FlagEQ)
(Select1 (NEGLflags (MOVBQZX (SETB x)))) => x
+// Absorb InvertFlags into ADCQ/SBBQ: CF(InvertFlags(f)) = SETA(f), so
+// re-materialize the carry/borrow through the SETA+NEGLflags path.
+(ADCQ x y (InvertFlags f)) => (ADCQ x y (Select1 <types.TypeFlags> (NEGLflags (MOVBQZX <types.Types[types.TUINT32]> (SETA <types.Types[types.TUINT8]> f)))))
+(ADCQconst x [c] (InvertFlags f)) => (ADCQconst x [c] (Select1 <types.TypeFlags> (NEGLflags (MOVBQZX <types.Types[types.TUINT32]> (SETA <types.Types[types.TUINT8]> f)))))
+(SBBQ x y (InvertFlags f)) => (SBBQ x y (Select1 <types.TypeFlags> (NEGLflags (MOVBQZX <types.Types[types.TUINT32]> (SETA <types.Types[types.TUINT8]> f)))))
+(SBBQconst x [c] (InvertFlags f)) => (SBBQconst x [c] (Select1 <types.TypeFlags> (NEGLflags (MOVBQZX <types.Types[types.TUINT32]> (SETA <types.Types[types.TUINT8]> f)))))
(Mul64uhilo ...) => (MULQU2 ...)
diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go
index e628e5b..c083fd8 100644
--- a/src/cmd/compile/internal/ssa/rewriteAMD64.go
+++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go
@@ -7494,6 +7494,8 @@
v_2 := v.Args[2]
v_1 := v.Args[1]
v_0 := v.Args[0]
+ b := v.Block
+ typ := &b.Func.Config.Types
// match: (ADCQ x (MOVQconst [c]) carry)
// cond: is32Bit(c)
// result: (ADCQconst x [int32(c)] carry)
@@ -7527,11 +7529,34 @@
v.AddArg2(x, y)
return true
}
+ // match: (ADCQ x y (InvertFlags f))
+ // result: (ADCQ x y (Select1 <types.TypeFlags> (NEGLflags (MOVBQZX <types.Types[types.TUINT32]> (SETA <types.Types[types.TUINT8]> f)))))
+ for {
+ x := v_0
+ y := v_1
+ if v_2.Op != OpAMD64InvertFlags {
+ break
+ }
+ f := v_2.Args[0]
+ v.reset(OpAMD64ADCQ)
+ v0 := b.NewValue0(v.Pos, OpSelect1, types.TypeFlags)
+ v1 := b.NewValue0(v.Pos, OpAMD64NEGLflags, types.NewTuple(typ.UInt32, types.TypeFlags))
+ v2 := b.NewValue0(v.Pos, OpAMD64MOVBQZX, types.Types[types.TUINT32])
+ v3 := b.NewValue0(v.Pos, OpAMD64SETA, types.Types[types.TUINT8])
+ v3.AddArg(f)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg3(x, y, v0)
+ return true
+ }
return false
}
func rewriteValueAMD64_OpAMD64ADCQconst(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
+ b := v.Block
+ typ := &b.Func.Config.Types
// match: (ADCQconst x [c] (FlagEQ))
// result: (ADDQconstcarry x [c])
for {
@@ -7545,6 +7570,28 @@
v.AddArg(x)
return true
}
+ // match: (ADCQconst x [c] (InvertFlags f))
+ // result: (ADCQconst x [c] (Select1 <types.TypeFlags> (NEGLflags (MOVBQZX <types.Types[types.TUINT32]> (SETA <types.Types[types.TUINT8]> f)))))
+ for {
+ c := auxIntToInt32(v.AuxInt)
+ x := v_0
+ if v_1.Op != OpAMD64InvertFlags {
+ break
+ }
+ f := v_1.Args[0]
+ v.reset(OpAMD64ADCQconst)
+ v.AuxInt = int32ToAuxInt(c)
+ v0 := b.NewValue0(v.Pos, OpSelect1, types.TypeFlags)
+ v1 := b.NewValue0(v.Pos, OpAMD64NEGLflags, types.NewTuple(typ.UInt32, types.TypeFlags))
+ v2 := b.NewValue0(v.Pos, OpAMD64MOVBQZX, types.Types[types.TUINT32])
+ v3 := b.NewValue0(v.Pos, OpAMD64SETA, types.Types[types.TUINT8])
+ v3.AddArg(f)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg2(x, v0)
+ return true
+ }
return false
}
func rewriteValueAMD64_OpAMD64ADDL(v *Value) bool {
@@ -31447,6 +31494,8 @@
v_2 := v.Args[2]
v_1 := v.Args[1]
v_0 := v.Args[0]
+ b := v.Block
+ typ := &b.Func.Config.Types
// match: (SBBQ x (MOVQconst [c]) borrow)
// cond: is32Bit(c)
// result: (SBBQconst x [int32(c)] borrow)
@@ -31477,6 +31526,27 @@
v.AddArg2(x, y)
return true
}
+ // match: (SBBQ x y (InvertFlags f))
+ // result: (SBBQ x y (Select1 <types.TypeFlags> (NEGLflags (MOVBQZX <types.Types[types.TUINT32]> (SETA <types.Types[types.TUINT8]> f)))))
+ for {
+ x := v_0
+ y := v_1
+ if v_2.Op != OpAMD64InvertFlags {
+ break
+ }
+ f := v_2.Args[0]
+ v.reset(OpAMD64SBBQ)
+ v0 := b.NewValue0(v.Pos, OpSelect1, types.TypeFlags)
+ v1 := b.NewValue0(v.Pos, OpAMD64NEGLflags, types.NewTuple(typ.UInt32, types.TypeFlags))
+ v2 := b.NewValue0(v.Pos, OpAMD64MOVBQZX, types.Types[types.TUINT32])
+ v3 := b.NewValue0(v.Pos, OpAMD64SETA, types.Types[types.TUINT8])
+ v3.AddArg(f)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg3(x, y, v0)
+ return true
+ }
return false
}
func rewriteValueAMD64_OpAMD64SBBQcarrymask(v *Value) bool {
@@ -31536,6 +31606,8 @@
func rewriteValueAMD64_OpAMD64SBBQconst(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
+ b := v.Block
+ typ := &b.Func.Config.Types
// match: (SBBQconst x [c] (FlagEQ))
// result: (SUBQconstborrow x [c])
for {
@@ -31549,6 +31621,28 @@
v.AddArg(x)
return true
}
+ // match: (SBBQconst x [c] (InvertFlags f))
+ // result: (SBBQconst x [c] (Select1 <types.TypeFlags> (NEGLflags (MOVBQZX <types.Types[types.TUINT32]> (SETA <types.Types[types.TUINT8]> f)))))
+ for {
+ c := auxIntToInt32(v.AuxInt)
+ x := v_0
+ if v_1.Op != OpAMD64InvertFlags {
+ break
+ }
+ f := v_1.Args[0]
+ v.reset(OpAMD64SBBQconst)
+ v.AuxInt = int32ToAuxInt(c)
+ v0 := b.NewValue0(v.Pos, OpSelect1, types.TypeFlags)
+ v1 := b.NewValue0(v.Pos, OpAMD64NEGLflags, types.NewTuple(typ.UInt32, types.TypeFlags))
+ v2 := b.NewValue0(v.Pos, OpAMD64MOVBQZX, types.Types[types.TUINT32])
+ v3 := b.NewValue0(v.Pos, OpAMD64SETA, types.Types[types.TUINT8])
+ v3.AddArg(f)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg2(x, v0)
+ return true
+ }
return false
}
func rewriteValueAMD64_OpAMD64SETA(v *Value) bool {
diff --git a/test/fixedbugs/issue79887_1.go b/test/fixedbugs/issue79887_1.go
new file mode 100644
index 0000000..3325d8f
--- /dev/null
+++ b/test/fixedbugs/issue79887_1.go
@@ -0,0 +1,23 @@
+// build
+
+package main
+
+import "math/bits"
+
+//go:noinline
+func f(p, q, x, y uint64) uint64 {
+ c := uint64(0)
+ if p < q {
+ c = 1
+ }
+ s, _ := bits.Sub64(x, y, c)
+ return s
+}
+
+func main() {
+ got := f(1, 2, 10, 3)
+ println(got)
+ if got != 6 {
+ panic("wrong result")
+ }
+}
diff --git a/test/fixedbugs/issue79887_2.go b/test/fixedbugs/issue79887_2.go
new file mode 100644
index 0000000..c424291
--- /dev/null
+++ b/test/fixedbugs/issue79887_2.go
@@ -0,0 +1,23 @@
+// build
+
+package main
+
+import "math/bits"
+
+//go:noinline
+func f(p, q, x, y uint64) uint64 {
+ c := uint64(0)
+ if p < q {
+ c = 1
+ }
+ s, _ := bits.Add64(x, y, c)
+ return s
+}
+
+func main() {
+ got := f(1, 2, 10, 20)
+ println(got)
+ if got != 31 {
+ panic("wrong result")
+ }
+}