(FCMP (FMOVDconst [c]) x) && auxTo64F(c) == 0 -> (InvertFlags (LTDBR <v.Type> x))
(FCMPS (FMOVSconst [c]) x) && auxTo32F(c) == 0 -> (InvertFlags (LTEBR <v.Type> x))
-// FSUB, FSUBS, FADD, FADDS now produce a flag, so when a comparison against zero instruction (e.g: LTDBR) is following
-// one of those instructions, we can use the generated flag and remove the comparison instruction.
-(LTDBR (Select0 x:(F(ADD|SUB) _ _))) -> (Select1 x)
-(LTEBR (Select0 x:(F(ADDS|SUBS) _ _))) -> (Select1 x)
+// FSUB, FSUBS, FADD, FADDS now produce a condition code representing the
+// comparison of the result with 0.0. If a compare with zero instruction
+// (e.g. LTDBR) is following one of those instructions, we can use the
+// generated flag and remove the comparison instruction.
+// Note: when inserting Select1 ops we need to ensure they are in the
+// same block as their argument. We could also use @x.Block for this
+// but moving the flag generating value to a different block seems to
+// increase the likelihood that the flags value will have to be regenerated
+// by flagalloc which is not what we want.
+(LTDBR (Select0 x:(F(ADD|SUB) _ _))) && b == x.Block -> (Select1 x)
+(LTEBR (Select0 x:(F(ADDS|SUBS) _ _))) && b == x.Block -> (Select1 x)
// Fold memory operations into operations.
// Exclude global data (SB) because these instructions cannot handle relative addresses.
}
func rewriteValueS390X_OpS390XLTDBR(v *Value) bool {
v_0 := v.Args[0]
+ b := v.Block
// match: (LTDBR (Select0 x:(FADD _ _)))
+ // cond: b == x.Block
// result: (Select1 x)
for {
if v_0.Op != OpSelect0 {
break
}
x := v_0.Args[0]
- if x.Op != OpS390XFADD {
+ if x.Op != OpS390XFADD || !(b == x.Block) {
break
}
v.reset(OpSelect1)
return true
}
// match: (LTDBR (Select0 x:(FSUB _ _)))
+ // cond: b == x.Block
// result: (Select1 x)
for {
if v_0.Op != OpSelect0 {
break
}
x := v_0.Args[0]
- if x.Op != OpS390XFSUB {
+ if x.Op != OpS390XFSUB || !(b == x.Block) {
break
}
v.reset(OpSelect1)
}
func rewriteValueS390X_OpS390XLTEBR(v *Value) bool {
v_0 := v.Args[0]
+ b := v.Block
// match: (LTEBR (Select0 x:(FADDS _ _)))
+ // cond: b == x.Block
// result: (Select1 x)
for {
if v_0.Op != OpSelect0 {
break
}
x := v_0.Args[0]
- if x.Op != OpS390XFADDS {
+ if x.Op != OpS390XFADDS || !(b == x.Block) {
break
}
v.reset(OpSelect1)
return true
}
// match: (LTEBR (Select0 x:(FSUBS _ _)))
+ // cond: b == x.Block
// result: (Select1 x)
for {
if v_0.Op != OpSelect0 {
break
}
x := v_0.Args[0]
- if x.Op != OpS390XFSUBS {
+ if x.Op != OpS390XFSUBS || !(b == x.Block) {
break
}
v.reset(OpSelect1)
--- /dev/null
+// compile
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Make sure floating point operations that generate flags
+// are scheduled correctly on s390x.
+
+package p
+
+func f1(x, y float64, z int) float64 {
+ a := x + y // generate flags
+ if z == 0 { // create basic block that does not clobber flags
+ return a
+ }
+ if a > 0 { // use flags in different basic block
+ return y
+ }
+ return x
+}
+
+func f2(x, y float64, z int) float64 {
+ a := x - y // generate flags
+ if z == 0 { // create basic block that does not clobber flags
+ return a
+ }
+ if a > 0 { // use flags in different basic block
+ return y
+ }
+ return x
+}
+
+func f3(x, y float32, z int) float32 {
+ a := x + y // generate flags
+ if z == 0 { // create basic block that does not clobber flags
+ return a
+ }
+ if a > 0 { // use flags in different basic block
+ return y
+ }
+ return x
+}
+
+func f4(x, y float32, z int) float32 {
+ a := x - y // generate flags
+ if z == 0 { // create basic block that does not clobber flags
+ return a
+ }
+ if a > 0 { // use flags in different basic block
+ return y
+ }
+ return x
+}