]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: generate subfic on ppc64
authorPaul E. Murphy <murp@ibm.com>
Thu, 20 Aug 2020 20:06:23 +0000 (15:06 -0500)
committerLynn Boger <laboger@linux.vnet.ibm.com>
Thu, 27 Aug 2020 20:10:15 +0000 (20:10 +0000)
This merges an lis + subf into subfic, and for 32b constants
lwa + subf into oris + ori + subf.

The carry bit is no longer used in code generation, therefore
I think we can clobber it as needed.  Note, lowered borrow/carry
arithmetic is self-contained and thus is not affected.

A few extra rules are added to ensure early transformations to
SUBFCconst don't trip up earlier rules, fold constant operations,
or otherwise simplify lowering.  Likewise, tests are added to
ensure all rules are hit.  Generic constant folding catches
trivial cases, however some lowering rules insert arithmetic
which can introduce new opportunities (e.g BitLen or Slicemask).

I couldn't find a specific benchmark to demonstrate noteworthy
improvements, but this is generating subfic in many of the default
bent test binaries, so we are at least saving a little code space.

Change-Id: Iad7c6e5767eaa9dc24dc1c989bd1c8cfe1982012
Reviewed-on: https://go-review.googlesource.com/c/go/+/249461
Run-TryBot: Lynn Boger <laboger@linux.vnet.ibm.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Carlos Eduardo Seo <cseo@linux.vnet.ibm.com>
src/cmd/compile/internal/ppc64/ssa.go
src/cmd/compile/internal/ssa/gen/PPC64.rules
src/cmd/compile/internal/ssa/gen/PPC64Ops.go
src/cmd/compile/internal/ssa/opGen.go
src/cmd/compile/internal/ssa/rewritePPC64.go
test/codegen/arithmetic.go
test/codegen/mathbits.go
test/codegen/slices.go

index 9c4c01e93508490d307e8e53bf16ecd17284bac7..f8d9ac23790e804e4314d7c2bb52420a7ac11041 100644 (file)
@@ -649,6 +649,14 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
                p.To.Type = obj.TYPE_REG
                p.To.Reg = v.Reg()
 
+       case ssa.OpPPC64SUBFCconst:
+               p := s.Prog(v.Op.Asm())
+               p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: v.AuxInt})
+               p.From.Type = obj.TYPE_REG
+               p.From.Reg = v.Args[0].Reg()
+               p.To.Type = obj.TYPE_REG
+               p.To.Reg = v.Reg()
+
        case ssa.OpPPC64ANDCCconst:
                p := s.Prog(v.Op.Asm())
                p.Reg = v.Args[0].Reg()
index 509cfe1c4fba1d405eebc24eac5a078266ebfd7a..e5fb1e98c2962a60345af87dc26db50094c299b7 100644 (file)
 // Rotate generation with non-const shift
 // these match patterns from math/bits/RotateLeft[32|64], but there could be others
 (ADD (SLD x (ANDconst <typ.Int64> [63] y)) (SRD x (SUB <typ.UInt> (MOVDconst [64]) (ANDconst <typ.UInt> [63] y)))) => (ROTL x y)
+(ADD (SLD x (ANDconst <typ.Int64> [63] y)) (SRD x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y)))) => (ROTL x y)
 ( OR (SLD x (ANDconst <typ.Int64> [63] y)) (SRD x (SUB <typ.UInt> (MOVDconst [64]) (ANDconst <typ.UInt> [63] y)))) => (ROTL x y)
+( OR (SLD x (ANDconst <typ.Int64> [63] y)) (SRD x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y)))) => (ROTL x y)
 (XOR (SLD x (ANDconst <typ.Int64> [63] y)) (SRD x (SUB <typ.UInt> (MOVDconst [64]) (ANDconst <typ.UInt> [63] y)))) => (ROTL x y)
+(XOR (SLD x (ANDconst <typ.Int64> [63] y)) (SRD x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y)))) => (ROTL x y)
 
+
+(ADD (SLW x (ANDconst <typ.Int32> [31] y)) (SRW x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y)))) => (ROTLW x y)
 (ADD (SLW x (ANDconst <typ.Int32> [31] y)) (SRW x (SUB <typ.UInt> (MOVDconst [32]) (ANDconst <typ.UInt> [31] y)))) => (ROTLW x y)
+( OR (SLW x (ANDconst <typ.Int32> [31] y)) (SRW x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y)))) => (ROTLW x y)
 ( OR (SLW x (ANDconst <typ.Int32> [31] y)) (SRW x (SUB <typ.UInt> (MOVDconst [32]) (ANDconst <typ.UInt> [31] y)))) => (ROTLW x y)
+(XOR (SLW x (ANDconst <typ.Int32> [31] y)) (SRW x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y)))) => (ROTLW x y)
 (XOR (SLW x (ANDconst <typ.Int32> [31] y)) (SRW x (SUB <typ.UInt> (MOVDconst [32]) (ANDconst <typ.UInt> [31] y)))) => (ROTLW x y)
 
+
 // Lowering rotates
 (RotateLeft32 x y) => (ROTLW x y)
 (RotateLeft64 x y) => (ROTL x y)
 (Rsh64Ux64 x (AND y (MOVDconst [63]))) => (SRD x (ANDconst <typ.Int64> [63] y))
 (Rsh64Ux64 x (ANDconst <typ.UInt> [63] y)) => (SRD x (ANDconst <typ.UInt> [63] y))
 (Rsh64Ux64 x (SUB <typ.UInt> (MOVDconst [64]) (ANDconst <typ.UInt> [63] y))) => (SRD x (SUB <typ.UInt> (MOVDconst [64]) (ANDconst <typ.UInt> [63] y)))
+(Rsh64Ux64 x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y))) => (SRD x (SUBFCconst <typ.UInt> [64]  (ANDconst <typ.UInt> [63] y)))
 (Rsh64Ux64 x (SUB <typ.UInt> (MOVDconst [64]) (AND <typ.UInt> y (MOVDconst [63])))) => (SRD x (SUB <typ.UInt> (MOVDconst [64]) (ANDconst <typ.UInt> [63] y)))
+(Rsh64Ux64 x (SUBFCconst <typ.UInt> [64] (AND <typ.UInt> y (MOVDconst [63])))) => (SRD x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y)))
 (Rsh64x64 x (AND y (MOVDconst [63]))) => (SRAD x (ANDconst <typ.Int64> [63] y))
 (Rsh64x64 x (ANDconst <typ.UInt> [63] y)) => (SRAD x (ANDconst <typ.UInt> [63] y))
 (Rsh64x64 x (SUB <typ.UInt> (MOVDconst [64]) (ANDconst <typ.UInt> [63] y))) => (SRAD x (SUB <typ.UInt> (MOVDconst [64]) (ANDconst <typ.UInt> [63] y)))
+(Rsh64x64 x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y))) => (SRAD x (SUBFCconst <typ.UInt> [64]  (ANDconst <typ.UInt> [63] y)))
 (Rsh64x64 x (SUB <typ.UInt> (MOVDconst [64]) (AND <typ.UInt> y (MOVDconst [63])))) => (SRAD x (SUB <typ.UInt> (MOVDconst [64]) (ANDconst <typ.UInt> [63] y)))
+(Rsh64x64 x (SUBFCconst <typ.UInt> [64] (AND <typ.UInt> y (MOVDconst [63])))) => (SRAD x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y)))
 
 (Lsh64x64 x y)  => (SLD  x (ISEL [0] y (MOVDconst [-1]) (CMPU y (MOVDconst [64]))))
 (Rsh64x64 x y) => (SRAD x (ISEL [0] y (MOVDconst [-1]) (CMPU y (MOVDconst [64]))))
 (Rsh32Ux64 x (AND y (MOVDconst [31]))) => (SRW x (ANDconst <typ.Int32> [31] y))
 (Rsh32Ux64 x (ANDconst <typ.UInt> [31] y)) => (SRW x (ANDconst <typ.UInt> [31] y))
 (Rsh32Ux64 x (SUB <typ.UInt> (MOVDconst [32]) (ANDconst <typ.UInt> [31] y))) => (SRW x (SUB <typ.UInt> (MOVDconst [32]) (ANDconst <typ.UInt> [31] y)))
+(Rsh32Ux64 x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y))) => (SRW x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y)))
 (Rsh32Ux64 x (SUB <typ.UInt> (MOVDconst [32]) (AND <typ.UInt> y (MOVDconst [31])))) => (SRW x (SUB <typ.UInt> (MOVDconst [32]) (ANDconst <typ.UInt> [31] y)))
+(Rsh32Ux64 x (SUBFCconst <typ.UInt> [32] (AND <typ.UInt> y (MOVDconst [31])))) => (SRW x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y)))
 
 (Rsh32x64 x (AND y (MOVDconst [31]))) => (SRAW x (ANDconst <typ.Int32> [31] y))
 (Rsh32x64 x (ANDconst <typ.UInt> [31] y)) => (SRAW x (ANDconst <typ.UInt> [31] y))
 (Rsh32x64 x (SUB <typ.UInt> (MOVDconst [32]) (ANDconst <typ.UInt> [31] y))) => (SRAW x (SUB <typ.UInt> (MOVDconst [32]) (ANDconst <typ.UInt> [31] y)))
+(Rsh32x64 x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y))) => (SRAW x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y)))
 (Rsh32x64 x (SUB <typ.UInt> (MOVDconst [32]) (AND <typ.UInt> y (MOVDconst [31])))) => (SRAW x (SUB <typ.UInt> (MOVDconst [32]) (ANDconst <typ.UInt> [31] y)))
+(Rsh32x64 x (SUBFCconst <typ.UInt> [32] (AND <typ.UInt> y (MOVDconst [31])))) => (SRAW x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y)))
 
 (Rsh32x64 x y)  => (SRAW x (ISEL [0] y (MOVDconst [-1]) (CMPU y (MOVDconst [32]))))
 (Rsh32Ux64 x y) => (SRW  x (ISEL [0] y (MOVDconst [-1]) (CMPU y (MOVDconst [32]))))
 (Ctz16 x) => (POPCNTW (MOVHZreg (ANDN <typ.Int16> (ADDconst <typ.Int16> [-1] x) x)))
 (Ctz8 x)  => (POPCNTB (MOVBZreg (ANDN <typ.UInt8> (ADDconst <typ.UInt8> [-1] x) x)))
 
-(BitLen64 x) => (SUB (MOVDconst [64]) (CNTLZD <typ.Int> x))
-(BitLen32 x) => (SUB (MOVDconst [32]) (CNTLZW <typ.Int> x))
+(BitLen64 x) => (SUBFCconst [64] (CNTLZD <typ.Int> x))
+(BitLen32 x) => (SUBFCconst [32] (CNTLZW <typ.Int> x))
 
 (PopCount64 ...) => (POPCNTD ...)
 (PopCount32 x) => (POPCNTW (MOVWZreg x))
 (ADDconst [c] (ADDconst [d] x)) && is32Bit(c+d) => (ADDconst [c+d] x)
 (ADDconst [0] x) => x
 (SUB x (MOVDconst [c])) && is32Bit(-c) => (ADDconst [-c] x)
-// TODO deal with subtract-from-const
 
 (ADDconst [c] (MOVDaddr [d] {sym} x)) && is32Bit(c+int64(d)) => (MOVDaddr [int32(c+int64(d))] {sym} x)
 
+// Subtract from (with carry, but ignored) constant.
+// Note, these clobber the carry bit.
+(SUB (MOVDconst [c]) x) && is32Bit(c) => (SUBFCconst [c] x)
+(SUBFCconst [c] (NEG x)) => (ADDconst [c] x)
+(SUBFCconst [c] (SUBFCconst [d] x)) && is32Bit(c-d) => (ADDconst [c-d] x)
+(SUBFCconst [0] x) => (NEG x)
+(ADDconst [c] (SUBFCconst [d] x)) && is32Bit(c+d) => (SUBFCconst [c+d] x)
+(NEG (ADDconst [c] x)) && is32Bit(-c) => (SUBFCconst [-c] x)
+(NEG (SUBFCconst [c] x)) && is32Bit(-c) => (ADDconst [-c] x)
+
 // Use register moves instead of stores and loads to move int<=>float values
 // Common with math Float64bits, Float64frombits
 (MOVDload [off] {sym} ptr (FMOVDstore [off] {sym} ptr x _)) => (MFVSRD x)
index f91222446c35c3cba54d8bd960d8101da10d54f9..44f6a74c63ed3fbafda5d6bea8a86e82ea046575 100644 (file)
@@ -175,6 +175,7 @@ func init() {
                {name: "FADD", argLength: 2, reg: fp21, asm: "FADD", commutative: true},   // arg0+arg1
                {name: "FADDS", argLength: 2, reg: fp21, asm: "FADDS", commutative: true}, // arg0+arg1
                {name: "SUB", argLength: 2, reg: gp21, asm: "SUB"},                        // arg0-arg1
+               {name: "SUBFCconst", argLength: 1, reg: gp11, asm: "SUBC", aux: "Int64"},  // auxInt - arg0 (with carry)
                {name: "FSUB", argLength: 2, reg: fp21, asm: "FSUB"},                      // arg0-arg1
                {name: "FSUBS", argLength: 2, reg: fp21, asm: "FSUBS"},                    // arg0-arg1
 
index e181174d1190e5b7ba986429ab9065c378d0c414..45401898c858919a218e27f9fcadc776a500a725 100644 (file)
@@ -1828,6 +1828,7 @@ const (
        OpPPC64FADD
        OpPPC64FADDS
        OpPPC64SUB
+       OpPPC64SUBFCconst
        OpPPC64FSUB
        OpPPC64FSUBS
        OpPPC64MULLD
@@ -24313,6 +24314,20 @@ var opcodeTable = [...]opInfo{
                        },
                },
        },
+       {
+               name:    "SUBFCconst",
+               auxType: auxInt64,
+               argLen:  1,
+               asm:     ppc64.ASUBC,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+                       },
+                       outputs: []outputInfo{
+                               {0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+                       },
+               },
+       },
        {
                name:   "FSUB",
                argLen: 2,
index 1a0b03e81cf8301425c9af0a5bbda8d3757b7877..152cdfdf4d5a9448e1f79fafdf35e87a0e1faac4 100644 (file)
@@ -568,6 +568,8 @@ func rewriteValuePPC64(v *Value) bool {
                return rewriteValuePPC64_OpPPC64MOVWstorezero(v)
        case OpPPC64MTVSRD:
                return rewriteValuePPC64_OpPPC64MTVSRD(v)
+       case OpPPC64NEG:
+               return rewriteValuePPC64_OpPPC64NEG(v)
        case OpPPC64NOR:
                return rewriteValuePPC64_OpPPC64NOR(v)
        case OpPPC64NotEqual:
@@ -596,6 +598,8 @@ func rewriteValuePPC64(v *Value) bool {
                return rewriteValuePPC64_OpPPC64SRW(v)
        case OpPPC64SUB:
                return rewriteValuePPC64_OpPPC64SUB(v)
+       case OpPPC64SUBFCconst:
+               return rewriteValuePPC64_OpPPC64SUBFCconst(v)
        case OpPPC64XOR:
                return rewriteValuePPC64_OpPPC64XOR(v)
        case OpPPC64XORconst:
@@ -1021,15 +1025,14 @@ func rewriteValuePPC64_OpBitLen32(v *Value) bool {
        b := v.Block
        typ := &b.Func.Config.Types
        // match: (BitLen32 x)
-       // result: (SUB (MOVDconst [32]) (CNTLZW <typ.Int> x))
+       // result: (SUBFCconst [32] (CNTLZW <typ.Int> x))
        for {
                x := v_0
-               v.reset(OpPPC64SUB)
-               v0 := b.NewValue0(v.Pos, OpPPC64MOVDconst, typ.Int64)
-               v0.AuxInt = int64ToAuxInt(32)
-               v1 := b.NewValue0(v.Pos, OpPPC64CNTLZW, typ.Int)
-               v1.AddArg(x)
-               v.AddArg2(v0, v1)
+               v.reset(OpPPC64SUBFCconst)
+               v.AuxInt = int64ToAuxInt(32)
+               v0 := b.NewValue0(v.Pos, OpPPC64CNTLZW, typ.Int)
+               v0.AddArg(x)
+               v.AddArg(v0)
                return true
        }
 }
@@ -1038,15 +1041,14 @@ func rewriteValuePPC64_OpBitLen64(v *Value) bool {
        b := v.Block
        typ := &b.Func.Config.Types
        // match: (BitLen64 x)
-       // result: (SUB (MOVDconst [64]) (CNTLZD <typ.Int> x))
+       // result: (SUBFCconst [64] (CNTLZD <typ.Int> x))
        for {
                x := v_0
-               v.reset(OpPPC64SUB)
-               v0 := b.NewValue0(v.Pos, OpPPC64MOVDconst, typ.Int64)
-               v0.AuxInt = int64ToAuxInt(64)
-               v1 := b.NewValue0(v.Pos, OpPPC64CNTLZD, typ.Int)
-               v1.AddArg(x)
-               v.AddArg2(v0, v1)
+               v.reset(OpPPC64SUBFCconst)
+               v.AuxInt = int64ToAuxInt(64)
+               v0 := b.NewValue0(v.Pos, OpPPC64CNTLZD, typ.Int)
+               v0.AddArg(x)
+               v.AddArg(v0)
                return true
        }
 }
@@ -3957,6 +3959,76 @@ func rewriteValuePPC64_OpPPC64ADD(v *Value) bool {
                }
                break
        }
+       // match: (ADD (SLD x (ANDconst <typ.Int64> [63] y)) (SRD x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y))))
+       // result: (ROTL x y)
+       for {
+               for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+                       if v_0.Op != OpPPC64SLD {
+                               continue
+                       }
+                       _ = v_0.Args[1]
+                       x := v_0.Args[0]
+                       v_0_1 := v_0.Args[1]
+                       if v_0_1.Op != OpPPC64ANDconst || v_0_1.Type != typ.Int64 || auxIntToInt64(v_0_1.AuxInt) != 63 {
+                               continue
+                       }
+                       y := v_0_1.Args[0]
+                       if v_1.Op != OpPPC64SRD {
+                               continue
+                       }
+                       _ = v_1.Args[1]
+                       if x != v_1.Args[0] {
+                               continue
+                       }
+                       v_1_1 := v_1.Args[1]
+                       if v_1_1.Op != OpPPC64SUBFCconst || v_1_1.Type != typ.UInt || auxIntToInt64(v_1_1.AuxInt) != 64 {
+                               continue
+                       }
+                       v_1_1_0 := v_1_1.Args[0]
+                       if v_1_1_0.Op != OpPPC64ANDconst || v_1_1_0.Type != typ.UInt || auxIntToInt64(v_1_1_0.AuxInt) != 63 || y != v_1_1_0.Args[0] {
+                               continue
+                       }
+                       v.reset(OpPPC64ROTL)
+                       v.AddArg2(x, y)
+                       return true
+               }
+               break
+       }
+       // match: (ADD (SLW x (ANDconst <typ.Int32> [31] y)) (SRW x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y))))
+       // result: (ROTLW x y)
+       for {
+               for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+                       if v_0.Op != OpPPC64SLW {
+                               continue
+                       }
+                       _ = v_0.Args[1]
+                       x := v_0.Args[0]
+                       v_0_1 := v_0.Args[1]
+                       if v_0_1.Op != OpPPC64ANDconst || v_0_1.Type != typ.Int32 || auxIntToInt64(v_0_1.AuxInt) != 31 {
+                               continue
+                       }
+                       y := v_0_1.Args[0]
+                       if v_1.Op != OpPPC64SRW {
+                               continue
+                       }
+                       _ = v_1.Args[1]
+                       if x != v_1.Args[0] {
+                               continue
+                       }
+                       v_1_1 := v_1.Args[1]
+                       if v_1_1.Op != OpPPC64SUBFCconst || v_1_1.Type != typ.UInt || auxIntToInt64(v_1_1.AuxInt) != 32 {
+                               continue
+                       }
+                       v_1_1_0 := v_1_1.Args[0]
+                       if v_1_1_0.Op != OpPPC64ANDconst || v_1_1_0.Type != typ.UInt || auxIntToInt64(v_1_1_0.AuxInt) != 31 || y != v_1_1_0.Args[0] {
+                               continue
+                       }
+                       v.reset(OpPPC64ROTLW)
+                       v.AddArg2(x, y)
+                       return true
+               }
+               break
+       }
        // match: (ADD (SLW x (ANDconst <typ.Int32> [31] y)) (SRW x (SUB <typ.UInt> (MOVDconst [32]) (ANDconst <typ.UInt> [31] y))))
        // result: (ROTLW x y)
        for {
@@ -4069,6 +4141,24 @@ func rewriteValuePPC64_OpPPC64ADDconst(v *Value) bool {
                v.AddArg(x)
                return true
        }
+       // match: (ADDconst [c] (SUBFCconst [d] x))
+       // cond: is32Bit(c+d)
+       // result: (SUBFCconst [c+d] x)
+       for {
+               c := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpPPC64SUBFCconst {
+                       break
+               }
+               d := auxIntToInt64(v_0.AuxInt)
+               x := v_0.Args[0]
+               if !(is32Bit(c + d)) {
+                       break
+               }
+               v.reset(OpPPC64SUBFCconst)
+               v.AuxInt = int64ToAuxInt(c + d)
+               v.AddArg(x)
+               return true
+       }
        return false
 }
 func rewriteValuePPC64_OpPPC64AND(v *Value) bool {
@@ -10336,6 +10426,44 @@ func rewriteValuePPC64_OpPPC64MTVSRD(v *Value) bool {
        }
        return false
 }
+func rewriteValuePPC64_OpPPC64NEG(v *Value) bool {
+       v_0 := v.Args[0]
+       // match: (NEG (ADDconst [c] x))
+       // cond: is32Bit(-c)
+       // result: (SUBFCconst [-c] x)
+       for {
+               if v_0.Op != OpPPC64ADDconst {
+                       break
+               }
+               c := auxIntToInt64(v_0.AuxInt)
+               x := v_0.Args[0]
+               if !(is32Bit(-c)) {
+                       break
+               }
+               v.reset(OpPPC64SUBFCconst)
+               v.AuxInt = int64ToAuxInt(-c)
+               v.AddArg(x)
+               return true
+       }
+       // match: (NEG (SUBFCconst [c] x))
+       // cond: is32Bit(-c)
+       // result: (ADDconst [-c] x)
+       for {
+               if v_0.Op != OpPPC64SUBFCconst {
+                       break
+               }
+               c := auxIntToInt64(v_0.AuxInt)
+               x := v_0.Args[0]
+               if !(is32Bit(-c)) {
+                       break
+               }
+               v.reset(OpPPC64ADDconst)
+               v.AuxInt = int64ToAuxInt(-c)
+               v.AddArg(x)
+               return true
+       }
+       return false
+}
 func rewriteValuePPC64_OpPPC64NOR(v *Value) bool {
        v_1 := v.Args[1]
        v_0 := v.Args[0]
@@ -10510,6 +10638,76 @@ func rewriteValuePPC64_OpPPC64OR(v *Value) bool {
                }
                break
        }
+       // match: ( OR (SLD x (ANDconst <typ.Int64> [63] y)) (SRD x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y))))
+       // result: (ROTL x y)
+       for {
+               for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+                       if v_0.Op != OpPPC64SLD {
+                               continue
+                       }
+                       _ = v_0.Args[1]
+                       x := v_0.Args[0]
+                       v_0_1 := v_0.Args[1]
+                       if v_0_1.Op != OpPPC64ANDconst || v_0_1.Type != typ.Int64 || auxIntToInt64(v_0_1.AuxInt) != 63 {
+                               continue
+                       }
+                       y := v_0_1.Args[0]
+                       if v_1.Op != OpPPC64SRD {
+                               continue
+                       }
+                       _ = v_1.Args[1]
+                       if x != v_1.Args[0] {
+                               continue
+                       }
+                       v_1_1 := v_1.Args[1]
+                       if v_1_1.Op != OpPPC64SUBFCconst || v_1_1.Type != typ.UInt || auxIntToInt64(v_1_1.AuxInt) != 64 {
+                               continue
+                       }
+                       v_1_1_0 := v_1_1.Args[0]
+                       if v_1_1_0.Op != OpPPC64ANDconst || v_1_1_0.Type != typ.UInt || auxIntToInt64(v_1_1_0.AuxInt) != 63 || y != v_1_1_0.Args[0] {
+                               continue
+                       }
+                       v.reset(OpPPC64ROTL)
+                       v.AddArg2(x, y)
+                       return true
+               }
+               break
+       }
+       // match: ( OR (SLW x (ANDconst <typ.Int32> [31] y)) (SRW x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y))))
+       // result: (ROTLW x y)
+       for {
+               for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+                       if v_0.Op != OpPPC64SLW {
+                               continue
+                       }
+                       _ = v_0.Args[1]
+                       x := v_0.Args[0]
+                       v_0_1 := v_0.Args[1]
+                       if v_0_1.Op != OpPPC64ANDconst || v_0_1.Type != typ.Int32 || auxIntToInt64(v_0_1.AuxInt) != 31 {
+                               continue
+                       }
+                       y := v_0_1.Args[0]
+                       if v_1.Op != OpPPC64SRW {
+                               continue
+                       }
+                       _ = v_1.Args[1]
+                       if x != v_1.Args[0] {
+                               continue
+                       }
+                       v_1_1 := v_1.Args[1]
+                       if v_1_1.Op != OpPPC64SUBFCconst || v_1_1.Type != typ.UInt || auxIntToInt64(v_1_1.AuxInt) != 32 {
+                               continue
+                       }
+                       v_1_1_0 := v_1_1.Args[0]
+                       if v_1_1_0.Op != OpPPC64ANDconst || v_1_1_0.Type != typ.UInt || auxIntToInt64(v_1_1_0.AuxInt) != 31 || y != v_1_1_0.Args[0] {
+                               continue
+                       }
+                       v.reset(OpPPC64ROTLW)
+                       v.AddArg2(x, y)
+                       return true
+               }
+               break
+       }
        // match: ( OR (SLW x (ANDconst <typ.Int32> [31] y)) (SRW x (SUB <typ.UInt> (MOVDconst [32]) (ANDconst <typ.UInt> [31] y))))
        // result: (ROTLW x y)
        for {
@@ -12109,6 +12307,69 @@ func rewriteValuePPC64_OpPPC64SUB(v *Value) bool {
                v.AddArg(x)
                return true
        }
+       // match: (SUB (MOVDconst [c]) x)
+       // cond: is32Bit(c)
+       // result: (SUBFCconst [c] x)
+       for {
+               if v_0.Op != OpPPC64MOVDconst {
+                       break
+               }
+               c := auxIntToInt64(v_0.AuxInt)
+               x := v_1
+               if !(is32Bit(c)) {
+                       break
+               }
+               v.reset(OpPPC64SUBFCconst)
+               v.AuxInt = int64ToAuxInt(c)
+               v.AddArg(x)
+               return true
+       }
+       return false
+}
+func rewriteValuePPC64_OpPPC64SUBFCconst(v *Value) bool {
+       v_0 := v.Args[0]
+       // match: (SUBFCconst [c] (NEG x))
+       // result: (ADDconst [c] x)
+       for {
+               c := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpPPC64NEG {
+                       break
+               }
+               x := v_0.Args[0]
+               v.reset(OpPPC64ADDconst)
+               v.AuxInt = int64ToAuxInt(c)
+               v.AddArg(x)
+               return true
+       }
+       // match: (SUBFCconst [c] (SUBFCconst [d] x))
+       // cond: is32Bit(c-d)
+       // result: (ADDconst [c-d] x)
+       for {
+               c := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpPPC64SUBFCconst {
+                       break
+               }
+               d := auxIntToInt64(v_0.AuxInt)
+               x := v_0.Args[0]
+               if !(is32Bit(c - d)) {
+                       break
+               }
+               v.reset(OpPPC64ADDconst)
+               v.AuxInt = int64ToAuxInt(c - d)
+               v.AddArg(x)
+               return true
+       }
+       // match: (SUBFCconst [0] x)
+       // result: (NEG x)
+       for {
+               if auxIntToInt64(v.AuxInt) != 0 {
+                       break
+               }
+               x := v_0
+               v.reset(OpPPC64NEG)
+               v.AddArg(x)
+               return true
+       }
        return false
 }
 func rewriteValuePPC64_OpPPC64XOR(v *Value) bool {
@@ -12204,6 +12465,76 @@ func rewriteValuePPC64_OpPPC64XOR(v *Value) bool {
                }
                break
        }
+       // match: (XOR (SLD x (ANDconst <typ.Int64> [63] y)) (SRD x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y))))
+       // result: (ROTL x y)
+       for {
+               for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+                       if v_0.Op != OpPPC64SLD {
+                               continue
+                       }
+                       _ = v_0.Args[1]
+                       x := v_0.Args[0]
+                       v_0_1 := v_0.Args[1]
+                       if v_0_1.Op != OpPPC64ANDconst || v_0_1.Type != typ.Int64 || auxIntToInt64(v_0_1.AuxInt) != 63 {
+                               continue
+                       }
+                       y := v_0_1.Args[0]
+                       if v_1.Op != OpPPC64SRD {
+                               continue
+                       }
+                       _ = v_1.Args[1]
+                       if x != v_1.Args[0] {
+                               continue
+                       }
+                       v_1_1 := v_1.Args[1]
+                       if v_1_1.Op != OpPPC64SUBFCconst || v_1_1.Type != typ.UInt || auxIntToInt64(v_1_1.AuxInt) != 64 {
+                               continue
+                       }
+                       v_1_1_0 := v_1_1.Args[0]
+                       if v_1_1_0.Op != OpPPC64ANDconst || v_1_1_0.Type != typ.UInt || auxIntToInt64(v_1_1_0.AuxInt) != 63 || y != v_1_1_0.Args[0] {
+                               continue
+                       }
+                       v.reset(OpPPC64ROTL)
+                       v.AddArg2(x, y)
+                       return true
+               }
+               break
+       }
+       // match: (XOR (SLW x (ANDconst <typ.Int32> [31] y)) (SRW x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y))))
+       // result: (ROTLW x y)
+       for {
+               for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+                       if v_0.Op != OpPPC64SLW {
+                               continue
+                       }
+                       _ = v_0.Args[1]
+                       x := v_0.Args[0]
+                       v_0_1 := v_0.Args[1]
+                       if v_0_1.Op != OpPPC64ANDconst || v_0_1.Type != typ.Int32 || auxIntToInt64(v_0_1.AuxInt) != 31 {
+                               continue
+                       }
+                       y := v_0_1.Args[0]
+                       if v_1.Op != OpPPC64SRW {
+                               continue
+                       }
+                       _ = v_1.Args[1]
+                       if x != v_1.Args[0] {
+                               continue
+                       }
+                       v_1_1 := v_1.Args[1]
+                       if v_1_1.Op != OpPPC64SUBFCconst || v_1_1.Type != typ.UInt || auxIntToInt64(v_1_1.AuxInt) != 32 {
+                               continue
+                       }
+                       v_1_1_0 := v_1_1.Args[0]
+                       if v_1_1_0.Op != OpPPC64ANDconst || v_1_1_0.Type != typ.UInt || auxIntToInt64(v_1_1_0.AuxInt) != 31 || y != v_1_1_0.Args[0] {
+                               continue
+                       }
+                       v.reset(OpPPC64ROTLW)
+                       v.AddArg2(x, y)
+                       return true
+               }
+               break
+       }
        // match: (XOR (SLW x (ANDconst <typ.Int32> [31] y)) (SRW x (SUB <typ.UInt> (MOVDconst [32]) (ANDconst <typ.UInt> [31] y))))
        // result: (ROTLW x y)
        for {
@@ -13175,6 +13506,28 @@ func rewriteValuePPC64_OpRsh32Ux64(v *Value) bool {
                v.AddArg2(x, v0)
                return true
        }
+       // match: (Rsh32Ux64 x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y)))
+       // result: (SRW x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y)))
+       for {
+               x := v_0
+               if v_1.Op != OpPPC64SUBFCconst || v_1.Type != typ.UInt || auxIntToInt64(v_1.AuxInt) != 32 {
+                       break
+               }
+               v_1_0 := v_1.Args[0]
+               if v_1_0.Op != OpPPC64ANDconst || v_1_0.Type != typ.UInt || auxIntToInt64(v_1_0.AuxInt) != 31 {
+                       break
+               }
+               y := v_1_0.Args[0]
+               v.reset(OpPPC64SRW)
+               v0 := b.NewValue0(v.Pos, OpPPC64SUBFCconst, typ.UInt)
+               v0.AuxInt = int64ToAuxInt(32)
+               v1 := b.NewValue0(v.Pos, OpPPC64ANDconst, typ.UInt)
+               v1.AuxInt = int64ToAuxInt(31)
+               v1.AddArg(y)
+               v0.AddArg(v1)
+               v.AddArg2(x, v0)
+               return true
+       }
        // match: (Rsh32Ux64 x (SUB <typ.UInt> (MOVDconst [32]) (AND <typ.UInt> y (MOVDconst [31]))))
        // result: (SRW x (SUB <typ.UInt> (MOVDconst [32]) (ANDconst <typ.UInt> [31] y)))
        for {
@@ -13212,6 +13565,37 @@ func rewriteValuePPC64_OpRsh32Ux64(v *Value) bool {
                }
                break
        }
+       // match: (Rsh32Ux64 x (SUBFCconst <typ.UInt> [32] (AND <typ.UInt> y (MOVDconst [31]))))
+       // result: (SRW x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y)))
+       for {
+               x := v_0
+               if v_1.Op != OpPPC64SUBFCconst || v_1.Type != typ.UInt || auxIntToInt64(v_1.AuxInt) != 32 {
+                       break
+               }
+               v_1_0 := v_1.Args[0]
+               if v_1_0.Op != OpPPC64AND || v_1_0.Type != typ.UInt {
+                       break
+               }
+               _ = v_1_0.Args[1]
+               v_1_0_0 := v_1_0.Args[0]
+               v_1_0_1 := v_1_0.Args[1]
+               for _i0 := 0; _i0 <= 1; _i0, v_1_0_0, v_1_0_1 = _i0+1, v_1_0_1, v_1_0_0 {
+                       y := v_1_0_0
+                       if v_1_0_1.Op != OpPPC64MOVDconst || auxIntToInt64(v_1_0_1.AuxInt) != 31 {
+                               continue
+                       }
+                       v.reset(OpPPC64SRW)
+                       v0 := b.NewValue0(v.Pos, OpPPC64SUBFCconst, typ.UInt)
+                       v0.AuxInt = int64ToAuxInt(32)
+                       v1 := b.NewValue0(v.Pos, OpPPC64ANDconst, typ.UInt)
+                       v1.AuxInt = int64ToAuxInt(31)
+                       v1.AddArg(y)
+                       v0.AddArg(v1)
+                       v.AddArg2(x, v0)
+                       return true
+               }
+               break
+       }
        // match: (Rsh32Ux64 x y)
        // result: (SRW x (ISEL [0] y (MOVDconst [-1]) (CMPU y (MOVDconst [32]))))
        for {
@@ -13482,6 +13866,28 @@ func rewriteValuePPC64_OpRsh32x64(v *Value) bool {
                v.AddArg2(x, v0)
                return true
        }
+       // match: (Rsh32x64 x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y)))
+       // result: (SRAW x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y)))
+       for {
+               x := v_0
+               if v_1.Op != OpPPC64SUBFCconst || v_1.Type != typ.UInt || auxIntToInt64(v_1.AuxInt) != 32 {
+                       break
+               }
+               v_1_0 := v_1.Args[0]
+               if v_1_0.Op != OpPPC64ANDconst || v_1_0.Type != typ.UInt || auxIntToInt64(v_1_0.AuxInt) != 31 {
+                       break
+               }
+               y := v_1_0.Args[0]
+               v.reset(OpPPC64SRAW)
+               v0 := b.NewValue0(v.Pos, OpPPC64SUBFCconst, typ.UInt)
+               v0.AuxInt = int64ToAuxInt(32)
+               v1 := b.NewValue0(v.Pos, OpPPC64ANDconst, typ.UInt)
+               v1.AuxInt = int64ToAuxInt(31)
+               v1.AddArg(y)
+               v0.AddArg(v1)
+               v.AddArg2(x, v0)
+               return true
+       }
        // match: (Rsh32x64 x (SUB <typ.UInt> (MOVDconst [32]) (AND <typ.UInt> y (MOVDconst [31]))))
        // result: (SRAW x (SUB <typ.UInt> (MOVDconst [32]) (ANDconst <typ.UInt> [31] y)))
        for {
@@ -13519,6 +13925,37 @@ func rewriteValuePPC64_OpRsh32x64(v *Value) bool {
                }
                break
        }
+       // match: (Rsh32x64 x (SUBFCconst <typ.UInt> [32] (AND <typ.UInt> y (MOVDconst [31]))))
+       // result: (SRAW x (SUBFCconst <typ.UInt> [32] (ANDconst <typ.UInt> [31] y)))
+       for {
+               x := v_0
+               if v_1.Op != OpPPC64SUBFCconst || v_1.Type != typ.UInt || auxIntToInt64(v_1.AuxInt) != 32 {
+                       break
+               }
+               v_1_0 := v_1.Args[0]
+               if v_1_0.Op != OpPPC64AND || v_1_0.Type != typ.UInt {
+                       break
+               }
+               _ = v_1_0.Args[1]
+               v_1_0_0 := v_1_0.Args[0]
+               v_1_0_1 := v_1_0.Args[1]
+               for _i0 := 0; _i0 <= 1; _i0, v_1_0_0, v_1_0_1 = _i0+1, v_1_0_1, v_1_0_0 {
+                       y := v_1_0_0
+                       if v_1_0_1.Op != OpPPC64MOVDconst || auxIntToInt64(v_1_0_1.AuxInt) != 31 {
+                               continue
+                       }
+                       v.reset(OpPPC64SRAW)
+                       v0 := b.NewValue0(v.Pos, OpPPC64SUBFCconst, typ.UInt)
+                       v0.AuxInt = int64ToAuxInt(32)
+                       v1 := b.NewValue0(v.Pos, OpPPC64ANDconst, typ.UInt)
+                       v1.AuxInt = int64ToAuxInt(31)
+                       v1.AddArg(y)
+                       v0.AddArg(v1)
+                       v.AddArg2(x, v0)
+                       return true
+               }
+               break
+       }
        // match: (Rsh32x64 x y)
        // result: (SRAW x (ISEL [0] y (MOVDconst [-1]) (CMPU y (MOVDconst [32]))))
        for {
@@ -13787,6 +14224,28 @@ func rewriteValuePPC64_OpRsh64Ux64(v *Value) bool {
                v.AddArg2(x, v0)
                return true
        }
+       // match: (Rsh64Ux64 x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y)))
+       // result: (SRD x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y)))
+       for {
+               x := v_0
+               if v_1.Op != OpPPC64SUBFCconst || v_1.Type != typ.UInt || auxIntToInt64(v_1.AuxInt) != 64 {
+                       break
+               }
+               v_1_0 := v_1.Args[0]
+               if v_1_0.Op != OpPPC64ANDconst || v_1_0.Type != typ.UInt || auxIntToInt64(v_1_0.AuxInt) != 63 {
+                       break
+               }
+               y := v_1_0.Args[0]
+               v.reset(OpPPC64SRD)
+               v0 := b.NewValue0(v.Pos, OpPPC64SUBFCconst, typ.UInt)
+               v0.AuxInt = int64ToAuxInt(64)
+               v1 := b.NewValue0(v.Pos, OpPPC64ANDconst, typ.UInt)
+               v1.AuxInt = int64ToAuxInt(63)
+               v1.AddArg(y)
+               v0.AddArg(v1)
+               v.AddArg2(x, v0)
+               return true
+       }
        // match: (Rsh64Ux64 x (SUB <typ.UInt> (MOVDconst [64]) (AND <typ.UInt> y (MOVDconst [63]))))
        // result: (SRD x (SUB <typ.UInt> (MOVDconst [64]) (ANDconst <typ.UInt> [63] y)))
        for {
@@ -13824,6 +14283,37 @@ func rewriteValuePPC64_OpRsh64Ux64(v *Value) bool {
                }
                break
        }
+       // match: (Rsh64Ux64 x (SUBFCconst <typ.UInt> [64] (AND <typ.UInt> y (MOVDconst [63]))))
+       // result: (SRD x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y)))
+       for {
+               x := v_0
+               if v_1.Op != OpPPC64SUBFCconst || v_1.Type != typ.UInt || auxIntToInt64(v_1.AuxInt) != 64 {
+                       break
+               }
+               v_1_0 := v_1.Args[0]
+               if v_1_0.Op != OpPPC64AND || v_1_0.Type != typ.UInt {
+                       break
+               }
+               _ = v_1_0.Args[1]
+               v_1_0_0 := v_1_0.Args[0]
+               v_1_0_1 := v_1_0.Args[1]
+               for _i0 := 0; _i0 <= 1; _i0, v_1_0_0, v_1_0_1 = _i0+1, v_1_0_1, v_1_0_0 {
+                       y := v_1_0_0
+                       if v_1_0_1.Op != OpPPC64MOVDconst || auxIntToInt64(v_1_0_1.AuxInt) != 63 {
+                               continue
+                       }
+                       v.reset(OpPPC64SRD)
+                       v0 := b.NewValue0(v.Pos, OpPPC64SUBFCconst, typ.UInt)
+                       v0.AuxInt = int64ToAuxInt(64)
+                       v1 := b.NewValue0(v.Pos, OpPPC64ANDconst, typ.UInt)
+                       v1.AuxInt = int64ToAuxInt(63)
+                       v1.AddArg(y)
+                       v0.AddArg(v1)
+                       v.AddArg2(x, v0)
+                       return true
+               }
+               break
+       }
        // match: (Rsh64Ux64 x y)
        // result: (SRD x (ISEL [0] y (MOVDconst [-1]) (CMPU y (MOVDconst [64]))))
        for {
@@ -14094,6 +14584,28 @@ func rewriteValuePPC64_OpRsh64x64(v *Value) bool {
                v.AddArg2(x, v0)
                return true
        }
+       // match: (Rsh64x64 x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y)))
+       // result: (SRAD x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y)))
+       for {
+               x := v_0
+               if v_1.Op != OpPPC64SUBFCconst || v_1.Type != typ.UInt || auxIntToInt64(v_1.AuxInt) != 64 {
+                       break
+               }
+               v_1_0 := v_1.Args[0]
+               if v_1_0.Op != OpPPC64ANDconst || v_1_0.Type != typ.UInt || auxIntToInt64(v_1_0.AuxInt) != 63 {
+                       break
+               }
+               y := v_1_0.Args[0]
+               v.reset(OpPPC64SRAD)
+               v0 := b.NewValue0(v.Pos, OpPPC64SUBFCconst, typ.UInt)
+               v0.AuxInt = int64ToAuxInt(64)
+               v1 := b.NewValue0(v.Pos, OpPPC64ANDconst, typ.UInt)
+               v1.AuxInt = int64ToAuxInt(63)
+               v1.AddArg(y)
+               v0.AddArg(v1)
+               v.AddArg2(x, v0)
+               return true
+       }
        // match: (Rsh64x64 x (SUB <typ.UInt> (MOVDconst [64]) (AND <typ.UInt> y (MOVDconst [63]))))
        // result: (SRAD x (SUB <typ.UInt> (MOVDconst [64]) (ANDconst <typ.UInt> [63] y)))
        for {
@@ -14131,6 +14643,37 @@ func rewriteValuePPC64_OpRsh64x64(v *Value) bool {
                }
                break
        }
+       // match: (Rsh64x64 x (SUBFCconst <typ.UInt> [64] (AND <typ.UInt> y (MOVDconst [63]))))
+       // result: (SRAD x (SUBFCconst <typ.UInt> [64] (ANDconst <typ.UInt> [63] y)))
+       for {
+               x := v_0
+               if v_1.Op != OpPPC64SUBFCconst || v_1.Type != typ.UInt || auxIntToInt64(v_1.AuxInt) != 64 {
+                       break
+               }
+               v_1_0 := v_1.Args[0]
+               if v_1_0.Op != OpPPC64AND || v_1_0.Type != typ.UInt {
+                       break
+               }
+               _ = v_1_0.Args[1]
+               v_1_0_0 := v_1_0.Args[0]
+               v_1_0_1 := v_1_0.Args[1]
+               for _i0 := 0; _i0 <= 1; _i0, v_1_0_0, v_1_0_1 = _i0+1, v_1_0_1, v_1_0_0 {
+                       y := v_1_0_0
+                       if v_1_0_1.Op != OpPPC64MOVDconst || auxIntToInt64(v_1_0_1.AuxInt) != 63 {
+                               continue
+                       }
+                       v.reset(OpPPC64SRAD)
+                       v0 := b.NewValue0(v.Pos, OpPPC64SUBFCconst, typ.UInt)
+                       v0.AuxInt = int64ToAuxInt(64)
+                       v1 := b.NewValue0(v.Pos, OpPPC64ANDconst, typ.UInt)
+                       v1.AuxInt = int64ToAuxInt(63)
+                       v1.AddArg(y)
+                       v0.AddArg(v1)
+                       v.AddArg2(x, v0)
+                       return true
+               }
+               break
+       }
        // match: (Rsh64x64 x y)
        // result: (SRAD x (ISEL [0] y (MOVDconst [-1]) (CMPU y (MOVDconst [64]))))
        for {
index afd4d66bd9c43b467e7d612a6266421026251d59..0bdb66a376db2acd133d05a357dcd69c6e740c11 100644 (file)
@@ -42,6 +42,48 @@ func SubMem(arr []int, b, c, d int) int {
        return arr[0] - arr[1]
 }
 
+func SubFromConst(a int) int {
+       // ppc64le: `SUBC\tR[0-9]+,\s[$]40,\sR`
+       // ppc64: `SUBC\tR[0-9]+,\s[$]40,\sR`
+       b := 40 - a
+       return b
+}
+
+func SubFromConstNeg(a int) int {
+       // ppc64le: `ADD\t[$]40,\sR[0-9]+,\sR`
+       // ppc64: `ADD\t[$]40,\sR[0-9]+,\sR`
+       c := 40 - (-a)
+       return c
+}
+
+func SubSubFromConst(a int) int {
+       // ppc64le: `ADD\t[$]20,\sR[0-9]+,\sR`
+       // ppc64: `ADD\t[$]20,\sR[0-9]+,\sR`
+       c := 40 - (20 - a)
+       return c
+}
+
+func AddSubFromConst(a int) int {
+       // ppc64le: `SUBC\tR[0-9]+,\s[$]60,\sR`
+       // ppc64: `SUBC\tR[0-9]+,\s[$]60,\sR`
+       c := 40 + (20 - a)
+       return c
+}
+
+func NegSubFromConst(a int) int {
+       // ppc64le: `ADD\t[$]-20,\sR[0-9]+,\sR`
+       // ppc64: `ADD\t[$]-20,\sR[0-9]+,\sR`
+       c := -(20 - a)
+       return c
+}
+
+func NegAddFromConstNeg(a int) int {
+       // ppc64le: `SUBC\tR[0-9]+,\s[$]40,\sR`
+       // ppc64: `SUBC\tR[0-9]+,\s[$]40,\sR`
+       c := -(-40 + a)
+       return c
+}
+
 // -------------------- //
 //    Multiplication    //
 // -------------------- //
index 942605de55c396e55fac6cc0b13ce829da69debf..4c35f26997c3a692cc6ecbba058a828f95640f63 100644 (file)
@@ -76,9 +76,17 @@ func Len64(n uint64) int {
        // arm:"CLZ" arm64:"CLZ"
        // mips:"CLZ"
        // wasm:"I64Clz"
+       // ppc64le:"SUBC","CNTLZD"
+       // ppc64:"SUBC","CNTLZD"
        return bits.Len64(n)
 }
 
+func SubFromLen64(n uint64) int {
+       // ppc64le:"CNTLZD",-"SUBC"
+       // ppc64:"CNTLZD",-"SUBC"
+       return 64 - bits.Len64(n)
+}
+
 func Len32(n uint32) int {
        // amd64:"BSRQ","LEAQ",-"CMOVQEQ"
        // s390x:"FLOGR"
@@ -291,6 +299,12 @@ func TrailingZeros64(n uint64) int {
        return bits.TrailingZeros64(n)
 }
 
+func TrailingZeros64Subtract(n uint64) int {
+       // ppc64le/power8:"NEG","SUBC","ANDN","POPCNTD"
+       // ppc64le/power9:"SUBC","CNTTZD"
+       return bits.TrailingZeros64(1 - n)
+}
+
 func TrailingZeros32(n uint32) int {
        // amd64:"BTSQ\\t\\$32","BSFQ"
        // arm:"CLZ"
index 40e857f9f69d7f83cb263fffe717d7d6be5dfff4..38e8a62f4b4f0dd7e1f922b0698a186e2315c4b3 100644 (file)
@@ -347,3 +347,24 @@ func InitNotSmallSliceLiteral() []int {
                42,
        }
 }
+
+// --------------------------------------- //
+//   Test PPC64 SUBFCconst folding rules   //
+//   triggered by slice operations.        //
+// --------------------------------------- //
+
+func SliceWithConstCompare(a []int, b int) []int {
+       var c []int = []int{1, 2, 3, 4, 5}
+       if b+len(a) < len(c) {
+               // ppc64le:-"NEG"
+               // ppc64:-"NEG"
+               return c[b:]
+       }
+       return a
+}
+
+func SliceWithSubtractBound(a []int, b int) []int {
+       // ppc64le:"SUBC",-"NEG"
+       // ppc64:"SUBC",-"NEG"
+       return a[(3 - b):]
+}