]> Cypherpunks.ru repositories - gostls13.git/commitdiff
cmd/compile: clean up codegen for branch-on-carry on s390x
authorMichael Munday <mike.munday@ibm.com>
Mon, 17 Feb 2020 11:43:33 +0000 (03:43 -0800)
committerMichael Munday <mike.munday@ibm.com>
Wed, 22 Apr 2020 20:11:06 +0000 (20:11 +0000)
This CL optimizes code that uses a carry from a function such as
bits.Add64 as the condition in an if statement. For example:

    x, c := bits.Add64(a, b, 0)
    if c != 0 {
        panic("overflow")
    }

Rather than converting the carry into a 0 or a 1 value and using
that as an input to a comparison instruction the carry flag is now
used as the input to a conditional branch directly. This typically
removes an ADD LOGICAL WITH CARRY instruction when user code is
doing overflow detection and is closer to the code that a user
would expect to generate.

Change-Id: I950431270955ab72f1b5c6db873b6abe769be0da
Reviewed-on: https://go-review.googlesource.com/c/go/+/219757
Run-TryBot: Michael Munday <mike.munday@ibm.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
src/cmd/compile/internal/ssa/gen/S390X.rules
src/cmd/compile/internal/ssa/rewriteS390X.go
src/cmd/internal/obj/s390x/condition_code.go
src/math/bits/bits_test.go
test/codegen/mathbits.go

index 7e713303af24168f9f09b964831651258ecf7894..61ba4ac38e31ea0396145d9b9fa1523530f49cf8 100644 (file)
 (SUBE x y (Select1 (SUBC (MOVDconst [0]) (NEG (Select0 (SUBE (MOVDconst [0]) (MOVDconst [0]) c))))))
   -> (SUBE x y c)
 
+// branch on carry
+(C(G|LG)IJ {s390x.Equal}         (Select0 (ADDE (MOVDconst [0]) (MOVDconst [0]) carry)) [0]) => (BRC {s390x.NoCarry} carry)
+(C(G|LG)IJ {s390x.Equal}         (Select0 (ADDE (MOVDconst [0]) (MOVDconst [0]) carry)) [1]) => (BRC {s390x.Carry}   carry)
+(C(G|LG)IJ {s390x.LessOrGreater} (Select0 (ADDE (MOVDconst [0]) (MOVDconst [0]) carry)) [0]) => (BRC {s390x.Carry}   carry)
+(C(G|LG)IJ {s390x.LessOrGreater} (Select0 (ADDE (MOVDconst [0]) (MOVDconst [0]) carry)) [1]) => (BRC {s390x.NoCarry} carry)
+(C(G|LG)IJ {s390x.Greater}       (Select0 (ADDE (MOVDconst [0]) (MOVDconst [0]) carry)) [0]) => (BRC {s390x.Carry}   carry)
+
+// branch on borrow
+(C(G|LG)IJ {s390x.Equal}         (NEG (Select0 (SUBE (MOVDconst [0]) (MOVDconst [0]) borrow))) [0]) => (BRC {s390x.NoBorrow} borrow)
+(C(G|LG)IJ {s390x.Equal}         (NEG (Select0 (SUBE (MOVDconst [0]) (MOVDconst [0]) borrow))) [1]) => (BRC {s390x.Borrow}   borrow)
+(C(G|LG)IJ {s390x.LessOrGreater} (NEG (Select0 (SUBE (MOVDconst [0]) (MOVDconst [0]) borrow))) [0]) => (BRC {s390x.Borrow}   borrow)
+(C(G|LG)IJ {s390x.LessOrGreater} (NEG (Select0 (SUBE (MOVDconst [0]) (MOVDconst [0]) borrow))) [1]) => (BRC {s390x.NoBorrow} borrow)
+(C(G|LG)IJ {s390x.Greater}       (NEG (Select0 (SUBE (MOVDconst [0]) (MOVDconst [0]) borrow))) [0]) => (BRC {s390x.Borrow}   borrow)
+
 // fused multiply-add
 (Select0 (F(ADD|SUB) (FMUL y z) x)) -> (FM(ADD|SUB) x y z)
 (Select0 (F(ADDS|SUBS) (FMULS y z) x)) -> (FM(ADDS|SUBS) x y z)
index 01b654ac955aca525fb16fb157da15c0a6785a4e..a7f6b3cd9ca121f74fe57dadb6d12460af765087 100644 (file)
@@ -19678,6 +19678,236 @@ func rewriteBlockS390X(b *Block) bool {
                        b.swapSuccessors()
                        return true
                }
+               // match: (CGIJ {s390x.Equal} (Select0 (ADDE (MOVDconst [0]) (MOVDconst [0]) carry)) [0])
+               // result: (BRC {s390x.NoCarry} carry)
+               for b.Controls[0].Op == OpSelect0 {
+                       v_0 := b.Controls[0]
+                       v_0_0 := v_0.Args[0]
+                       if v_0_0.Op != OpS390XADDE {
+                               break
+                       }
+                       carry := v_0_0.Args[2]
+                       v_0_0_0 := v_0_0.Args[0]
+                       if v_0_0_0.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_0.AuxInt) != 0 {
+                               break
+                       }
+                       v_0_0_1 := v_0_0.Args[1]
+                       if v_0_0_1.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_1.AuxInt) != 0 || auxIntToInt8(b.AuxInt) != 0 || auxToS390xCCMask(b.Aux) != s390x.Equal {
+                               break
+                       }
+                       b.resetWithControl(BlockS390XBRC, carry)
+                       b.Aux = s390xCCMaskToAux(s390x.NoCarry)
+                       return true
+               }
+               // match: (CGIJ {s390x.Equal} (Select0 (ADDE (MOVDconst [0]) (MOVDconst [0]) carry)) [1])
+               // result: (BRC {s390x.Carry} carry)
+               for b.Controls[0].Op == OpSelect0 {
+                       v_0 := b.Controls[0]
+                       v_0_0 := v_0.Args[0]
+                       if v_0_0.Op != OpS390XADDE {
+                               break
+                       }
+                       carry := v_0_0.Args[2]
+                       v_0_0_0 := v_0_0.Args[0]
+                       if v_0_0_0.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_0.AuxInt) != 0 {
+                               break
+                       }
+                       v_0_0_1 := v_0_0.Args[1]
+                       if v_0_0_1.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_1.AuxInt) != 0 || auxIntToInt8(b.AuxInt) != 1 || auxToS390xCCMask(b.Aux) != s390x.Equal {
+                               break
+                       }
+                       b.resetWithControl(BlockS390XBRC, carry)
+                       b.Aux = s390xCCMaskToAux(s390x.Carry)
+                       return true
+               }
+               // match: (CGIJ {s390x.LessOrGreater} (Select0 (ADDE (MOVDconst [0]) (MOVDconst [0]) carry)) [0])
+               // result: (BRC {s390x.Carry} carry)
+               for b.Controls[0].Op == OpSelect0 {
+                       v_0 := b.Controls[0]
+                       v_0_0 := v_0.Args[0]
+                       if v_0_0.Op != OpS390XADDE {
+                               break
+                       }
+                       carry := v_0_0.Args[2]
+                       v_0_0_0 := v_0_0.Args[0]
+                       if v_0_0_0.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_0.AuxInt) != 0 {
+                               break
+                       }
+                       v_0_0_1 := v_0_0.Args[1]
+                       if v_0_0_1.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_1.AuxInt) != 0 || auxIntToInt8(b.AuxInt) != 0 || auxToS390xCCMask(b.Aux) != s390x.LessOrGreater {
+                               break
+                       }
+                       b.resetWithControl(BlockS390XBRC, carry)
+                       b.Aux = s390xCCMaskToAux(s390x.Carry)
+                       return true
+               }
+               // match: (CGIJ {s390x.LessOrGreater} (Select0 (ADDE (MOVDconst [0]) (MOVDconst [0]) carry)) [1])
+               // result: (BRC {s390x.NoCarry} carry)
+               for b.Controls[0].Op == OpSelect0 {
+                       v_0 := b.Controls[0]
+                       v_0_0 := v_0.Args[0]
+                       if v_0_0.Op != OpS390XADDE {
+                               break
+                       }
+                       carry := v_0_0.Args[2]
+                       v_0_0_0 := v_0_0.Args[0]
+                       if v_0_0_0.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_0.AuxInt) != 0 {
+                               break
+                       }
+                       v_0_0_1 := v_0_0.Args[1]
+                       if v_0_0_1.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_1.AuxInt) != 0 || auxIntToInt8(b.AuxInt) != 1 || auxToS390xCCMask(b.Aux) != s390x.LessOrGreater {
+                               break
+                       }
+                       b.resetWithControl(BlockS390XBRC, carry)
+                       b.Aux = s390xCCMaskToAux(s390x.NoCarry)
+                       return true
+               }
+               // match: (CGIJ {s390x.Greater} (Select0 (ADDE (MOVDconst [0]) (MOVDconst [0]) carry)) [0])
+               // result: (BRC {s390x.Carry} carry)
+               for b.Controls[0].Op == OpSelect0 {
+                       v_0 := b.Controls[0]
+                       v_0_0 := v_0.Args[0]
+                       if v_0_0.Op != OpS390XADDE {
+                               break
+                       }
+                       carry := v_0_0.Args[2]
+                       v_0_0_0 := v_0_0.Args[0]
+                       if v_0_0_0.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_0.AuxInt) != 0 {
+                               break
+                       }
+                       v_0_0_1 := v_0_0.Args[1]
+                       if v_0_0_1.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_1.AuxInt) != 0 || auxIntToInt8(b.AuxInt) != 0 || auxToS390xCCMask(b.Aux) != s390x.Greater {
+                               break
+                       }
+                       b.resetWithControl(BlockS390XBRC, carry)
+                       b.Aux = s390xCCMaskToAux(s390x.Carry)
+                       return true
+               }
+               // match: (CGIJ {s390x.Equal} (NEG (Select0 (SUBE (MOVDconst [0]) (MOVDconst [0]) borrow))) [0])
+               // result: (BRC {s390x.NoBorrow} borrow)
+               for b.Controls[0].Op == OpS390XNEG {
+                       v_0 := b.Controls[0]
+                       v_0_0 := v_0.Args[0]
+                       if v_0_0.Op != OpSelect0 {
+                               break
+                       }
+                       v_0_0_0 := v_0_0.Args[0]
+                       if v_0_0_0.Op != OpS390XSUBE {
+                               break
+                       }
+                       borrow := v_0_0_0.Args[2]
+                       v_0_0_0_0 := v_0_0_0.Args[0]
+                       if v_0_0_0_0.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_0_0.AuxInt) != 0 {
+                               break
+                       }
+                       v_0_0_0_1 := v_0_0_0.Args[1]
+                       if v_0_0_0_1.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_0_1.AuxInt) != 0 || auxIntToInt8(b.AuxInt) != 0 || auxToS390xCCMask(b.Aux) != s390x.Equal {
+                               break
+                       }
+                       b.resetWithControl(BlockS390XBRC, borrow)
+                       b.Aux = s390xCCMaskToAux(s390x.NoBorrow)
+                       return true
+               }
+               // match: (CGIJ {s390x.Equal} (NEG (Select0 (SUBE (MOVDconst [0]) (MOVDconst [0]) borrow))) [1])
+               // result: (BRC {s390x.Borrow} borrow)
+               for b.Controls[0].Op == OpS390XNEG {
+                       v_0 := b.Controls[0]
+                       v_0_0 := v_0.Args[0]
+                       if v_0_0.Op != OpSelect0 {
+                               break
+                       }
+                       v_0_0_0 := v_0_0.Args[0]
+                       if v_0_0_0.Op != OpS390XSUBE {
+                               break
+                       }
+                       borrow := v_0_0_0.Args[2]
+                       v_0_0_0_0 := v_0_0_0.Args[0]
+                       if v_0_0_0_0.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_0_0.AuxInt) != 0 {
+                               break
+                       }
+                       v_0_0_0_1 := v_0_0_0.Args[1]
+                       if v_0_0_0_1.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_0_1.AuxInt) != 0 || auxIntToInt8(b.AuxInt) != 1 || auxToS390xCCMask(b.Aux) != s390x.Equal {
+                               break
+                       }
+                       b.resetWithControl(BlockS390XBRC, borrow)
+                       b.Aux = s390xCCMaskToAux(s390x.Borrow)
+                       return true
+               }
+               // match: (CGIJ {s390x.LessOrGreater} (NEG (Select0 (SUBE (MOVDconst [0]) (MOVDconst [0]) borrow))) [0])
+               // result: (BRC {s390x.Borrow} borrow)
+               for b.Controls[0].Op == OpS390XNEG {
+                       v_0 := b.Controls[0]
+                       v_0_0 := v_0.Args[0]
+                       if v_0_0.Op != OpSelect0 {
+                               break
+                       }
+                       v_0_0_0 := v_0_0.Args[0]
+                       if v_0_0_0.Op != OpS390XSUBE {
+                               break
+                       }
+                       borrow := v_0_0_0.Args[2]
+                       v_0_0_0_0 := v_0_0_0.Args[0]
+                       if v_0_0_0_0.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_0_0.AuxInt) != 0 {
+                               break
+                       }
+                       v_0_0_0_1 := v_0_0_0.Args[1]
+                       if v_0_0_0_1.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_0_1.AuxInt) != 0 || auxIntToInt8(b.AuxInt) != 0 || auxToS390xCCMask(b.Aux) != s390x.LessOrGreater {
+                               break
+                       }
+                       b.resetWithControl(BlockS390XBRC, borrow)
+                       b.Aux = s390xCCMaskToAux(s390x.Borrow)
+                       return true
+               }
+               // match: (CGIJ {s390x.LessOrGreater} (NEG (Select0 (SUBE (MOVDconst [0]) (MOVDconst [0]) borrow))) [1])
+               // result: (BRC {s390x.NoBorrow} borrow)
+               for b.Controls[0].Op == OpS390XNEG {
+                       v_0 := b.Controls[0]
+                       v_0_0 := v_0.Args[0]
+                       if v_0_0.Op != OpSelect0 {
+                               break
+                       }
+                       v_0_0_0 := v_0_0.Args[0]
+                       if v_0_0_0.Op != OpS390XSUBE {
+                               break
+                       }
+                       borrow := v_0_0_0.Args[2]
+                       v_0_0_0_0 := v_0_0_0.Args[0]
+                       if v_0_0_0_0.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_0_0.AuxInt) != 0 {
+                               break
+                       }
+                       v_0_0_0_1 := v_0_0_0.Args[1]
+                       if v_0_0_0_1.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_0_1.AuxInt) != 0 || auxIntToInt8(b.AuxInt) != 1 || auxToS390xCCMask(b.Aux) != s390x.LessOrGreater {
+                               break
+                       }
+                       b.resetWithControl(BlockS390XBRC, borrow)
+                       b.Aux = s390xCCMaskToAux(s390x.NoBorrow)
+                       return true
+               }
+               // match: (CGIJ {s390x.Greater} (NEG (Select0 (SUBE (MOVDconst [0]) (MOVDconst [0]) borrow))) [0])
+               // result: (BRC {s390x.Borrow} borrow)
+               for b.Controls[0].Op == OpS390XNEG {
+                       v_0 := b.Controls[0]
+                       v_0_0 := v_0.Args[0]
+                       if v_0_0.Op != OpSelect0 {
+                               break
+                       }
+                       v_0_0_0 := v_0_0.Args[0]
+                       if v_0_0_0.Op != OpS390XSUBE {
+                               break
+                       }
+                       borrow := v_0_0_0.Args[2]
+                       v_0_0_0_0 := v_0_0_0.Args[0]
+                       if v_0_0_0_0.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_0_0.AuxInt) != 0 {
+                               break
+                       }
+                       v_0_0_0_1 := v_0_0_0.Args[1]
+                       if v_0_0_0_1.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_0_1.AuxInt) != 0 || auxIntToInt8(b.AuxInt) != 0 || auxToS390xCCMask(b.Aux) != s390x.Greater {
+                               break
+                       }
+                       b.resetWithControl(BlockS390XBRC, borrow)
+                       b.Aux = s390xCCMaskToAux(s390x.Borrow)
+                       return true
+               }
        case BlockS390XCGRJ:
                // match: (CGRJ {c} x (MOVDconst [y]) yes no)
                // cond: is8Bit(y)
@@ -19993,6 +20223,236 @@ func rewriteBlockS390X(b *Block) bool {
                        b.swapSuccessors()
                        return true
                }
+               // match: (CLGIJ {s390x.Equal} (Select0 (ADDE (MOVDconst [0]) (MOVDconst [0]) carry)) [0])
+               // result: (BRC {s390x.NoCarry} carry)
+               for b.Controls[0].Op == OpSelect0 {
+                       v_0 := b.Controls[0]
+                       v_0_0 := v_0.Args[0]
+                       if v_0_0.Op != OpS390XADDE {
+                               break
+                       }
+                       carry := v_0_0.Args[2]
+                       v_0_0_0 := v_0_0.Args[0]
+                       if v_0_0_0.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_0.AuxInt) != 0 {
+                               break
+                       }
+                       v_0_0_1 := v_0_0.Args[1]
+                       if v_0_0_1.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_1.AuxInt) != 0 || auxIntToUint8(b.AuxInt) != 0 || auxToS390xCCMask(b.Aux) != s390x.Equal {
+                               break
+                       }
+                       b.resetWithControl(BlockS390XBRC, carry)
+                       b.Aux = s390xCCMaskToAux(s390x.NoCarry)
+                       return true
+               }
+               // match: (CLGIJ {s390x.Equal} (Select0 (ADDE (MOVDconst [0]) (MOVDconst [0]) carry)) [1])
+               // result: (BRC {s390x.Carry} carry)
+               for b.Controls[0].Op == OpSelect0 {
+                       v_0 := b.Controls[0]
+                       v_0_0 := v_0.Args[0]
+                       if v_0_0.Op != OpS390XADDE {
+                               break
+                       }
+                       carry := v_0_0.Args[2]
+                       v_0_0_0 := v_0_0.Args[0]
+                       if v_0_0_0.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_0.AuxInt) != 0 {
+                               break
+                       }
+                       v_0_0_1 := v_0_0.Args[1]
+                       if v_0_0_1.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_1.AuxInt) != 0 || auxIntToUint8(b.AuxInt) != 1 || auxToS390xCCMask(b.Aux) != s390x.Equal {
+                               break
+                       }
+                       b.resetWithControl(BlockS390XBRC, carry)
+                       b.Aux = s390xCCMaskToAux(s390x.Carry)
+                       return true
+               }
+               // match: (CLGIJ {s390x.LessOrGreater} (Select0 (ADDE (MOVDconst [0]) (MOVDconst [0]) carry)) [0])
+               // result: (BRC {s390x.Carry} carry)
+               for b.Controls[0].Op == OpSelect0 {
+                       v_0 := b.Controls[0]
+                       v_0_0 := v_0.Args[0]
+                       if v_0_0.Op != OpS390XADDE {
+                               break
+                       }
+                       carry := v_0_0.Args[2]
+                       v_0_0_0 := v_0_0.Args[0]
+                       if v_0_0_0.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_0.AuxInt) != 0 {
+                               break
+                       }
+                       v_0_0_1 := v_0_0.Args[1]
+                       if v_0_0_1.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_1.AuxInt) != 0 || auxIntToUint8(b.AuxInt) != 0 || auxToS390xCCMask(b.Aux) != s390x.LessOrGreater {
+                               break
+                       }
+                       b.resetWithControl(BlockS390XBRC, carry)
+                       b.Aux = s390xCCMaskToAux(s390x.Carry)
+                       return true
+               }
+               // match: (CLGIJ {s390x.LessOrGreater} (Select0 (ADDE (MOVDconst [0]) (MOVDconst [0]) carry)) [1])
+               // result: (BRC {s390x.NoCarry} carry)
+               for b.Controls[0].Op == OpSelect0 {
+                       v_0 := b.Controls[0]
+                       v_0_0 := v_0.Args[0]
+                       if v_0_0.Op != OpS390XADDE {
+                               break
+                       }
+                       carry := v_0_0.Args[2]
+                       v_0_0_0 := v_0_0.Args[0]
+                       if v_0_0_0.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_0.AuxInt) != 0 {
+                               break
+                       }
+                       v_0_0_1 := v_0_0.Args[1]
+                       if v_0_0_1.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_1.AuxInt) != 0 || auxIntToUint8(b.AuxInt) != 1 || auxToS390xCCMask(b.Aux) != s390x.LessOrGreater {
+                               break
+                       }
+                       b.resetWithControl(BlockS390XBRC, carry)
+                       b.Aux = s390xCCMaskToAux(s390x.NoCarry)
+                       return true
+               }
+               // match: (CLGIJ {s390x.Greater} (Select0 (ADDE (MOVDconst [0]) (MOVDconst [0]) carry)) [0])
+               // result: (BRC {s390x.Carry} carry)
+               for b.Controls[0].Op == OpSelect0 {
+                       v_0 := b.Controls[0]
+                       v_0_0 := v_0.Args[0]
+                       if v_0_0.Op != OpS390XADDE {
+                               break
+                       }
+                       carry := v_0_0.Args[2]
+                       v_0_0_0 := v_0_0.Args[0]
+                       if v_0_0_0.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_0.AuxInt) != 0 {
+                               break
+                       }
+                       v_0_0_1 := v_0_0.Args[1]
+                       if v_0_0_1.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_1.AuxInt) != 0 || auxIntToUint8(b.AuxInt) != 0 || auxToS390xCCMask(b.Aux) != s390x.Greater {
+                               break
+                       }
+                       b.resetWithControl(BlockS390XBRC, carry)
+                       b.Aux = s390xCCMaskToAux(s390x.Carry)
+                       return true
+               }
+               // match: (CLGIJ {s390x.Equal} (NEG (Select0 (SUBE (MOVDconst [0]) (MOVDconst [0]) borrow))) [0])
+               // result: (BRC {s390x.NoBorrow} borrow)
+               for b.Controls[0].Op == OpS390XNEG {
+                       v_0 := b.Controls[0]
+                       v_0_0 := v_0.Args[0]
+                       if v_0_0.Op != OpSelect0 {
+                               break
+                       }
+                       v_0_0_0 := v_0_0.Args[0]
+                       if v_0_0_0.Op != OpS390XSUBE {
+                               break
+                       }
+                       borrow := v_0_0_0.Args[2]
+                       v_0_0_0_0 := v_0_0_0.Args[0]
+                       if v_0_0_0_0.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_0_0.AuxInt) != 0 {
+                               break
+                       }
+                       v_0_0_0_1 := v_0_0_0.Args[1]
+                       if v_0_0_0_1.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_0_1.AuxInt) != 0 || auxIntToUint8(b.AuxInt) != 0 || auxToS390xCCMask(b.Aux) != s390x.Equal {
+                               break
+                       }
+                       b.resetWithControl(BlockS390XBRC, borrow)
+                       b.Aux = s390xCCMaskToAux(s390x.NoBorrow)
+                       return true
+               }
+               // match: (CLGIJ {s390x.Equal} (NEG (Select0 (SUBE (MOVDconst [0]) (MOVDconst [0]) borrow))) [1])
+               // result: (BRC {s390x.Borrow} borrow)
+               for b.Controls[0].Op == OpS390XNEG {
+                       v_0 := b.Controls[0]
+                       v_0_0 := v_0.Args[0]
+                       if v_0_0.Op != OpSelect0 {
+                               break
+                       }
+                       v_0_0_0 := v_0_0.Args[0]
+                       if v_0_0_0.Op != OpS390XSUBE {
+                               break
+                       }
+                       borrow := v_0_0_0.Args[2]
+                       v_0_0_0_0 := v_0_0_0.Args[0]
+                       if v_0_0_0_0.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_0_0.AuxInt) != 0 {
+                               break
+                       }
+                       v_0_0_0_1 := v_0_0_0.Args[1]
+                       if v_0_0_0_1.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_0_1.AuxInt) != 0 || auxIntToUint8(b.AuxInt) != 1 || auxToS390xCCMask(b.Aux) != s390x.Equal {
+                               break
+                       }
+                       b.resetWithControl(BlockS390XBRC, borrow)
+                       b.Aux = s390xCCMaskToAux(s390x.Borrow)
+                       return true
+               }
+               // match: (CLGIJ {s390x.LessOrGreater} (NEG (Select0 (SUBE (MOVDconst [0]) (MOVDconst [0]) borrow))) [0])
+               // result: (BRC {s390x.Borrow} borrow)
+               for b.Controls[0].Op == OpS390XNEG {
+                       v_0 := b.Controls[0]
+                       v_0_0 := v_0.Args[0]
+                       if v_0_0.Op != OpSelect0 {
+                               break
+                       }
+                       v_0_0_0 := v_0_0.Args[0]
+                       if v_0_0_0.Op != OpS390XSUBE {
+                               break
+                       }
+                       borrow := v_0_0_0.Args[2]
+                       v_0_0_0_0 := v_0_0_0.Args[0]
+                       if v_0_0_0_0.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_0_0.AuxInt) != 0 {
+                               break
+                       }
+                       v_0_0_0_1 := v_0_0_0.Args[1]
+                       if v_0_0_0_1.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_0_1.AuxInt) != 0 || auxIntToUint8(b.AuxInt) != 0 || auxToS390xCCMask(b.Aux) != s390x.LessOrGreater {
+                               break
+                       }
+                       b.resetWithControl(BlockS390XBRC, borrow)
+                       b.Aux = s390xCCMaskToAux(s390x.Borrow)
+                       return true
+               }
+               // match: (CLGIJ {s390x.LessOrGreater} (NEG (Select0 (SUBE (MOVDconst [0]) (MOVDconst [0]) borrow))) [1])
+               // result: (BRC {s390x.NoBorrow} borrow)
+               for b.Controls[0].Op == OpS390XNEG {
+                       v_0 := b.Controls[0]
+                       v_0_0 := v_0.Args[0]
+                       if v_0_0.Op != OpSelect0 {
+                               break
+                       }
+                       v_0_0_0 := v_0_0.Args[0]
+                       if v_0_0_0.Op != OpS390XSUBE {
+                               break
+                       }
+                       borrow := v_0_0_0.Args[2]
+                       v_0_0_0_0 := v_0_0_0.Args[0]
+                       if v_0_0_0_0.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_0_0.AuxInt) != 0 {
+                               break
+                       }
+                       v_0_0_0_1 := v_0_0_0.Args[1]
+                       if v_0_0_0_1.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_0_1.AuxInt) != 0 || auxIntToUint8(b.AuxInt) != 1 || auxToS390xCCMask(b.Aux) != s390x.LessOrGreater {
+                               break
+                       }
+                       b.resetWithControl(BlockS390XBRC, borrow)
+                       b.Aux = s390xCCMaskToAux(s390x.NoBorrow)
+                       return true
+               }
+               // match: (CLGIJ {s390x.Greater} (NEG (Select0 (SUBE (MOVDconst [0]) (MOVDconst [0]) borrow))) [0])
+               // result: (BRC {s390x.Borrow} borrow)
+               for b.Controls[0].Op == OpS390XNEG {
+                       v_0 := b.Controls[0]
+                       v_0_0 := v_0.Args[0]
+                       if v_0_0.Op != OpSelect0 {
+                               break
+                       }
+                       v_0_0_0 := v_0_0.Args[0]
+                       if v_0_0_0.Op != OpS390XSUBE {
+                               break
+                       }
+                       borrow := v_0_0_0.Args[2]
+                       v_0_0_0_0 := v_0_0_0.Args[0]
+                       if v_0_0_0_0.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_0_0.AuxInt) != 0 {
+                               break
+                       }
+                       v_0_0_0_1 := v_0_0_0.Args[1]
+                       if v_0_0_0_1.Op != OpS390XMOVDconst || auxIntToInt64(v_0_0_0_1.AuxInt) != 0 || auxIntToUint8(b.AuxInt) != 0 || auxToS390xCCMask(b.Aux) != s390x.Greater {
+                               break
+                       }
+                       b.resetWithControl(BlockS390XBRC, borrow)
+                       b.Aux = s390xCCMaskToAux(s390x.Borrow)
+                       return true
+               }
        case BlockS390XCLGRJ:
                // match: (CLGRJ {c} x (MOVDconst [y]) yes no)
                // cond: isU8Bit(y)
index a112911a3236183f97c8adb6c58495c8ef16bbe4..764fc5bc6a855c9f2b2149bfb22d4eef2233ffa9 100644 (file)
@@ -50,6 +50,12 @@ const (
 
        // 4-bit mask
        Always CCMask = Equal | Less | Greater | Unordered
+
+       // useful aliases
+       Carry    CCMask = GreaterOrUnordered
+       NoCarry  CCMask = LessOrEqual
+       Borrow   CCMask = NoCarry
+       NoBorrow CCMask = Carry
 )
 
 // Inverse returns the complement of the condition code mask.
index c0f43093d9b5f975bc0e600fb59aa8c3b087bbbc..23b4539fcd6ca4d374b96f4d372b777cb09e8219 100644 (file)
@@ -806,6 +806,130 @@ func TestAddSubUint64(t *testing.T) {
        }
 }
 
+func TestAdd64OverflowPanic(t *testing.T) {
+       // Test that 64-bit overflow panics fire correctly.
+       // These are designed to improve coverage of compiler intrinsics.
+       tests := []func(uint64, uint64) uint64{
+               func(a, b uint64) uint64 {
+                       x, c := Add64(a, b, 0)
+                       if c > 0 {
+                               panic("overflow")
+                       }
+                       return x
+               },
+               func(a, b uint64) uint64 {
+                       x, c := Add64(a, b, 0)
+                       if c != 0 {
+                               panic("overflow")
+                       }
+                       return x
+               },
+               func(a, b uint64) uint64 {
+                       x, c := Add64(a, b, 0)
+                       if c == 1 {
+                               panic("overflow")
+                       }
+                       return x
+               },
+               func(a, b uint64) uint64 {
+                       x, c := Add64(a, b, 0)
+                       if c != 1 {
+                               return x
+                       }
+                       panic("overflow")
+               },
+               func(a, b uint64) uint64 {
+                       x, c := Add64(a, b, 0)
+                       if c == 0 {
+                               return x
+                       }
+                       panic("overflow")
+               },
+       }
+       for _, test := range tests {
+               shouldPanic := func(f func()) {
+                       defer func() {
+                               if err := recover(); err == nil {
+                                       t.Fatalf("expected panic")
+                               }
+                       }()
+                       f()
+               }
+
+               // overflow
+               shouldPanic(func() { test(_M64, 1) })
+               shouldPanic(func() { test(1, _M64) })
+               shouldPanic(func() { test(_M64, _M64) })
+
+               // no overflow
+               test(_M64, 0)
+               test(0, 0)
+               test(1, 1)
+       }
+}
+
+func TestSub64OverflowPanic(t *testing.T) {
+       // Test that 64-bit overflow panics fire correctly.
+       // These are designed to improve coverage of compiler intrinsics.
+       tests := []func(uint64, uint64) uint64{
+               func(a, b uint64) uint64 {
+                       x, c := Sub64(a, b, 0)
+                       if c > 0 {
+                               panic("overflow")
+                       }
+                       return x
+               },
+               func(a, b uint64) uint64 {
+                       x, c := Sub64(a, b, 0)
+                       if c != 0 {
+                               panic("overflow")
+                       }
+                       return x
+               },
+               func(a, b uint64) uint64 {
+                       x, c := Sub64(a, b, 0)
+                       if c == 1 {
+                               panic("overflow")
+                       }
+                       return x
+               },
+               func(a, b uint64) uint64 {
+                       x, c := Sub64(a, b, 0)
+                       if c != 1 {
+                               return x
+                       }
+                       panic("overflow")
+               },
+               func(a, b uint64) uint64 {
+                       x, c := Sub64(a, b, 0)
+                       if c == 0 {
+                               return x
+                       }
+                       panic("overflow")
+               },
+       }
+       for _, test := range tests {
+               shouldPanic := func(f func()) {
+                       defer func() {
+                               if err := recover(); err == nil {
+                                       t.Fatalf("expected panic")
+                               }
+                       }()
+                       f()
+               }
+
+               // overflow
+               shouldPanic(func() { test(0, 1) })
+               shouldPanic(func() { test(1, _M64) })
+               shouldPanic(func() { test(_M64-1, _M64) })
+
+               // no overflow
+               test(_M64, 0)
+               test(0, 0)
+               test(1, 1)
+       }
+}
+
 func TestMulDiv(t *testing.T) {
        testMul := func(msg string, f func(x, y uint) (hi, lo uint), x, y, hi, lo uint) {
                hi1, lo1 := f(x, y)
index 8bd6242b1eedb571930cd3086c92ab48da0a1f98..942605de55c396e55fac6cc0b13ce829da69debf 100644 (file)
@@ -472,6 +472,69 @@ func Add64M(p, q, r *[3]uint64) {
        r[2], c = bits.Add64(p[2], q[2], c)
 }
 
+func Add64PanicOnOverflowEQ(a, b uint64) uint64 {
+       r, c := bits.Add64(a, b, 0)
+       // s390x:"BRC\t[$]3,",-"ADDE"
+       if c == 1 {
+               panic("overflow")
+       }
+       return r
+}
+
+func Add64PanicOnOverflowNE(a, b uint64) uint64 {
+       r, c := bits.Add64(a, b, 0)
+       // s390x:"BRC\t[$]3,",-"ADDE"
+       if c != 0 {
+               panic("overflow")
+       }
+       return r
+}
+
+func Add64PanicOnOverflowGT(a, b uint64) uint64 {
+       r, c := bits.Add64(a, b, 0)
+       // s390x:"BRC\t[$]3,",-"ADDE"
+       if c > 0 {
+               panic("overflow")
+       }
+       return r
+}
+
+func Add64MPanicOnOverflowEQ(a, b [2]uint64) [2]uint64 {
+       var r [2]uint64
+       var c uint64
+       r[0], c = bits.Add64(a[0], b[0], c)
+       r[1], c = bits.Add64(a[1], b[1], c)
+       // s390x:"BRC\t[$]3,"
+       if c == 1 {
+               panic("overflow")
+       }
+       return r
+}
+
+func Add64MPanicOnOverflowNE(a, b [2]uint64) [2]uint64 {
+       var r [2]uint64
+       var c uint64
+       r[0], c = bits.Add64(a[0], b[0], c)
+       r[1], c = bits.Add64(a[1], b[1], c)
+       // s390x:"BRC\t[$]3,"
+       if c != 0 {
+               panic("overflow")
+       }
+       return r
+}
+
+func Add64MPanicOnOverflowGT(a, b [2]uint64) [2]uint64 {
+       var r [2]uint64
+       var c uint64
+       r[0], c = bits.Add64(a[0], b[0], c)
+       r[1], c = bits.Add64(a[1], b[1], c)
+       // s390x:"BRC\t[$]3,"
+       if c > 0 {
+               panic("overflow")
+       }
+       return r
+}
+
 // --------------- //
 //    bits.Sub*    //
 // --------------- //
@@ -552,6 +615,69 @@ func Sub64M(p, q, r *[3]uint64) {
        r[2], c = bits.Sub64(p[2], q[2], c)
 }
 
+func Sub64PanicOnOverflowEQ(a, b uint64) uint64 {
+       r, b := bits.Sub64(a, b, 0)
+       // s390x:"BRC\t[$]12,",-"ADDE",-"SUBE"
+       if b == 1 {
+               panic("overflow")
+       }
+       return r
+}
+
+func Sub64PanicOnOverflowNE(a, b uint64) uint64 {
+       r, b := bits.Sub64(a, b, 0)
+       // s390x:"BRC\t[$]12,",-"ADDE",-"SUBE"
+       if b != 0 {
+               panic("overflow")
+       }
+       return r
+}
+
+func Sub64PanicOnOverflowGT(a, b uint64) uint64 {
+       r, b := bits.Sub64(a, b, 0)
+       // s390x:"BRC\t[$]12,",-"ADDE",-"SUBE"
+       if b > 0 {
+               panic("overflow")
+       }
+       return r
+}
+
+func Sub64MPanicOnOverflowEQ(a, b [2]uint64) [2]uint64 {
+       var r [2]uint64
+       var c uint64
+       r[0], c = bits.Sub64(a[0], b[0], c)
+       r[1], c = bits.Sub64(a[1], b[1], c)
+       // s390x:"BRC\t[$]12,"
+       if c == 1 {
+               panic("overflow")
+       }
+       return r
+}
+
+func Sub64MPanicOnOverflowNE(a, b [2]uint64) [2]uint64 {
+       var r [2]uint64
+       var c uint64
+       r[0], c = bits.Sub64(a[0], b[0], c)
+       r[1], c = bits.Sub64(a[1], b[1], c)
+       // s390x:"BRC\t[$]12,"
+       if c != 0 {
+               panic("overflow")
+       }
+       return r
+}
+
+func Sub64MPanicOnOverflowGT(a, b [2]uint64) [2]uint64 {
+       var r [2]uint64
+       var c uint64
+       r[0], c = bits.Sub64(a[0], b[0], c)
+       r[1], c = bits.Sub64(a[1], b[1], c)
+       // s390x:"BRC\t[$]12,"
+       if c > 0 {
+               panic("overflow")
+       }
+       return r
+}
+
 // --------------- //
 //    bits.Mul*    //
 // --------------- //