[go] cmd/compile: add the ability to eat InvertFlags to ADCQ and SBBQ

2 views
Skip to first unread message

Jorropo (Gerrit)

unread,
Jun 6, 2026, 10:56:23 PM (3 hours ago) Jun 6
to goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com

Jorropo has uploaded the change for review

Commit message

cmd/compile: add the ability to eat InvertFlags to ADCQ and SBBQ

Fixes #79887
Change-Id: Ib44eba1a6cb8689ce32294c76f6fc94843201ca3

Change diff

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")
+ }
+}

Change information

Files:
  • M src/cmd/compile/internal/ssa/_gen/AMD64.rules
  • M src/cmd/compile/internal/ssa/rewriteAMD64.go
  • A test/fixedbugs/issue79887_1.go
  • A test/fixedbugs/issue79887_2.go
Change size: M
Delta: 4 files changed, 146 insertions(+), 0 deletions(-)
Open in Gerrit

Related details

Attention set is empty
Submit Requirements:
  • requirement is not satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: newchange
Gerrit-Project: go
Gerrit-Branch: master
Gerrit-Change-Id: Ib44eba1a6cb8689ce32294c76f6fc94843201ca3
Gerrit-Change-Number: 787741
Gerrit-PatchSet: 1
Gerrit-Owner: Jorropo <jorro...@gmail.com>
Gerrit-Reviewer: Jorropo <jorro...@gmail.com>
unsatisfied_requirement
satisfied_requirement
open
diffy
Reply all
Reply to author
Forward
0 new messages