From 4ae49b592110055d2461c708bc2b85b049deb535 Mon Sep 17 00:00:00 2001 From: Lynn Boger Date: Wed, 10 Oct 2018 13:47:18 -0400 Subject: [PATCH] cmd/compile: use ANDCC, ORCC, XORCC to avoid CMP on ppc64x This change makes use of the cc versions of the AND, OR, XOR instructions, omitting the need for a CMP instruction. In many test programs and in the go binary, this reduces the size of 20-30 functions by at least 1 instruction, many in runtime. Testcase added to test/codegen/comparisons.go Change-Id: I6cc1ca8b80b065d7390749c625bc9784b0039adb Reviewed-on: https://go-review.googlesource.com/c/143059 Reviewed-by: Carlos Eduardo Seo Reviewed-by: Michael Munday Run-TryBot: Lynn Boger TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/ppc64/ssa.go | 2 +- src/cmd/compile/internal/ssa/gen/PPC64.rules | 7 + src/cmd/compile/internal/ssa/gen/PPC64Ops.go | 39 +- src/cmd/compile/internal/ssa/opGen.go | 48 ++ src/cmd/compile/internal/ssa/rewritePPC64.go | 822 +++++++++++++++++++ test/codegen/comparisons.go | 33 + 6 files changed, 932 insertions(+), 19 deletions(-) diff --git a/src/cmd/compile/internal/ppc64/ssa.go b/src/cmd/compile/internal/ppc64/ssa.go index a3f8b67177d..a6dd8cab5f5 100644 --- a/src/cmd/compile/internal/ppc64/ssa.go +++ b/src/cmd/compile/internal/ppc64/ssa.go @@ -569,7 +569,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ssa.OpPPC64ROTL, ssa.OpPPC64ROTLW, ssa.OpPPC64MULHD, ssa.OpPPC64MULHW, ssa.OpPPC64MULHDU, ssa.OpPPC64MULHWU, ssa.OpPPC64FMUL, ssa.OpPPC64FMULS, ssa.OpPPC64FDIV, ssa.OpPPC64FDIVS, ssa.OpPPC64FCPSGN, - ssa.OpPPC64AND, ssa.OpPPC64OR, ssa.OpPPC64ANDN, ssa.OpPPC64ORN, ssa.OpPPC64NOR, ssa.OpPPC64XOR, ssa.OpPPC64EQV: + ssa.OpPPC64AND, ssa.OpPPC64ANDCC, ssa.OpPPC64OR, ssa.OpPPC64ORCC, ssa.OpPPC64ANDN, ssa.OpPPC64ORN, ssa.OpPPC64NOR, ssa.OpPPC64XOR, ssa.OpPPC64XORCC, ssa.OpPPC64EQV: r := v.Reg() r1 := v.Args[0].Reg() r2 := v.Args[1].Reg() diff --git a/src/cmd/compile/internal/ssa/gen/PPC64.rules b/src/cmd/compile/internal/ssa/gen/PPC64.rules index 0eaa88596ba..24cee6f0a3a 100644 --- a/src/cmd/compile/internal/ssa/gen/PPC64.rules +++ b/src/cmd/compile/internal/ssa/gen/PPC64.rules @@ -518,6 +518,13 @@ (LessEqual (InvertFlags x)) -> (GreaterEqual x) (GreaterEqual (InvertFlags x)) -> (LessEqual x) +// Elide compares of bit tests // TODO need to make both CC and result of ANDCC available. +((EQ|NE|LT|LE|GT|GE) (CMPconst [0] (ANDconst [c] x)) yes no) -> ((EQ|NE|LT|LE|GT|GE) (ANDCCconst [c] x) yes no) +((EQ|NE|LT|LE|GT|GE) (CMPWconst [0] (ANDconst [c] x)) yes no) -> ((EQ|NE|LT|LE|GT|GE) (ANDCCconst [c] x) yes no) +((EQ|NE|LT|LE|GT|GE) (CMPconst [0] z:(AND x y)) yes no) && z.Uses == 1 -> ((EQ|NE|LT|LE|GT|GE) (ANDCC x y) yes no) +((EQ|NE|LT|LE|GT|GE) (CMPconst [0] z:(OR x y)) yes no) && z.Uses == 1 -> ((EQ|NE|LT|LE|GT|GE) (ORCC x y) yes no) +((EQ|NE|LT|LE|GT|GE) (CMPconst [0] z:(XOR x y)) yes no) && z.Uses == 1 -> ((EQ|NE|LT|LE|GT|GE) (XORCC x y) yes no) + // Lowering loads (Load ptr mem) && (is64BitInt(t) || isPtr(t)) -> (MOVDload ptr mem) (Load ptr mem) && is32BitInt(t) && isSigned(t) -> (MOVWload ptr mem) diff --git a/src/cmd/compile/internal/ssa/gen/PPC64Ops.go b/src/cmd/compile/internal/ssa/gen/PPC64Ops.go index ef0db69fb71..d6638b1ec72 100644 --- a/src/cmd/compile/internal/ssa/gen/PPC64Ops.go +++ b/src/cmd/compile/internal/ssa/gen/PPC64Ops.go @@ -241,24 +241,27 @@ func init() { {name: "MFVSRD", argLength: 1, reg: fpgp, asm: "MFVSRD", typ: "Int64"}, // move 64 bits of F register into G register {name: "MTVSRD", argLength: 1, reg: gpfp, asm: "MTVSRD", typ: "Float64"}, // move 64 bits of G register into F register - {name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true}, // arg0&arg1 - {name: "ANDN", argLength: 2, reg: gp21, asm: "ANDN"}, // arg0&^arg1 - {name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true}, // arg0|arg1 - {name: "ORN", argLength: 2, reg: gp21, asm: "ORN"}, // arg0|^arg1 - {name: "NOR", argLength: 2, reg: gp21, asm: "NOR", commutative: true}, // ^(arg0|arg1) - {name: "XOR", argLength: 2, reg: gp21, asm: "XOR", typ: "Int64", commutative: true}, // arg0^arg1 - {name: "EQV", argLength: 2, reg: gp21, asm: "EQV", typ: "Int64", commutative: true}, // arg0^^arg1 - {name: "NEG", argLength: 1, reg: gp11, asm: "NEG"}, // -arg0 (integer) - {name: "FNEG", argLength: 1, reg: fp11, asm: "FNEG"}, // -arg0 (floating point) - {name: "FSQRT", argLength: 1, reg: fp11, asm: "FSQRT"}, // sqrt(arg0) (floating point) - {name: "FSQRTS", argLength: 1, reg: fp11, asm: "FSQRTS"}, // sqrt(arg0) (floating point, single precision) - {name: "FFLOOR", argLength: 1, reg: fp11, asm: "FRIM"}, // floor(arg0), float64 - {name: "FCEIL", argLength: 1, reg: fp11, asm: "FRIP"}, // ceil(arg0), float64 - {name: "FTRUNC", argLength: 1, reg: fp11, asm: "FRIZ"}, // trunc(arg0), float64 - {name: "FROUND", argLength: 1, reg: fp11, asm: "FRIN"}, // round(arg0), float64 - {name: "FABS", argLength: 1, reg: fp11, asm: "FABS"}, // abs(arg0), float64 - {name: "FNABS", argLength: 1, reg: fp11, asm: "FNABS"}, // -abs(arg0), float64 - {name: "FCPSGN", argLength: 2, reg: fp21, asm: "FCPSGN"}, // copysign arg0 -> arg1, float64 + {name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true}, // arg0&arg1 + {name: "ANDN", argLength: 2, reg: gp21, asm: "ANDN"}, // arg0&^arg1 + {name: "ANDCC", argLength: 2, reg: gp21, asm: "ANDCC", commutative: true, typ: "Flags"}, // arg0&arg1 sets CC + {name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true}, // arg0|arg1 + {name: "ORN", argLength: 2, reg: gp21, asm: "ORN"}, // arg0|^arg1 + {name: "ORCC", argLength: 2, reg: gp21, asm: "ORCC", commutative: true, typ: "Flags"}, // arg0|arg1 sets CC + {name: "NOR", argLength: 2, reg: gp21, asm: "NOR", commutative: true}, // ^(arg0|arg1) + {name: "XOR", argLength: 2, reg: gp21, asm: "XOR", typ: "Int64", commutative: true}, // arg0^arg1 + {name: "XORCC", argLength: 2, reg: gp21, asm: "XORCC", commutative: true, typ: "Flags"}, // arg0^arg1 sets CC + {name: "EQV", argLength: 2, reg: gp21, asm: "EQV", typ: "Int64", commutative: true}, // arg0^^arg1 + {name: "NEG", argLength: 1, reg: gp11, asm: "NEG"}, // -arg0 (integer) + {name: "FNEG", argLength: 1, reg: fp11, asm: "FNEG"}, // -arg0 (floating point) + {name: "FSQRT", argLength: 1, reg: fp11, asm: "FSQRT"}, // sqrt(arg0) (floating point) + {name: "FSQRTS", argLength: 1, reg: fp11, asm: "FSQRTS"}, // sqrt(arg0) (floating point, single precision) + {name: "FFLOOR", argLength: 1, reg: fp11, asm: "FRIM"}, // floor(arg0), float64 + {name: "FCEIL", argLength: 1, reg: fp11, asm: "FRIP"}, // ceil(arg0), float64 + {name: "FTRUNC", argLength: 1, reg: fp11, asm: "FRIZ"}, // trunc(arg0), float64 + {name: "FROUND", argLength: 1, reg: fp11, asm: "FRIN"}, // round(arg0), float64 + {name: "FABS", argLength: 1, reg: fp11, asm: "FABS"}, // abs(arg0), float64 + {name: "FNABS", argLength: 1, reg: fp11, asm: "FNABS"}, // -abs(arg0), float64 + {name: "FCPSGN", argLength: 2, reg: fp21, asm: "FCPSGN"}, // copysign arg0 -> arg1, float64 {name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int64"}, // arg0|aux {name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int64"}, // arg0^aux diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index 03837b5f63e..f6568be660f 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -1663,10 +1663,13 @@ const ( OpPPC64MTVSRD OpPPC64AND OpPPC64ANDN + OpPPC64ANDCC OpPPC64OR OpPPC64ORN + OpPPC64ORCC OpPPC64NOR OpPPC64XOR + OpPPC64XORCC OpPPC64EQV OpPPC64NEG OpPPC64FNEG @@ -22202,6 +22205,21 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "ANDCC", + argLen: 2, + commutative: true, + asm: ppc64.AANDCC, + 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 + {1, 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: "OR", argLen: 2, @@ -22231,6 +22249,21 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "ORCC", + argLen: 2, + commutative: true, + asm: ppc64.AORCC, + 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 + {1, 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: "NOR", argLen: 2, @@ -22261,6 +22294,21 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "XORCC", + argLen: 2, + commutative: true, + asm: ppc64.AXORCC, + 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 + {1, 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: "EQV", argLen: 2, diff --git a/src/cmd/compile/internal/ssa/rewritePPC64.go b/src/cmd/compile/internal/ssa/rewritePPC64.go index abad10a2d1a..9c89e0e674a 100644 --- a/src/cmd/compile/internal/ssa/rewritePPC64.go +++ b/src/cmd/compile/internal/ssa/rewritePPC64.go @@ -30996,6 +30996,143 @@ func rewriteBlockPPC64(b *Block) bool { b.Aux = nil return true } + // match: (EQ (CMPconst [0] (ANDconst [c] x)) yes no) + // cond: + // result: (EQ (ANDCCconst [c] x) yes no) + for { + v := b.Control + if v.Op != OpPPC64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + v_0 := v.Args[0] + if v_0.Op != OpPPC64ANDconst { + break + } + c := v_0.AuxInt + x := v_0.Args[0] + b.Kind = BlockPPC64EQ + v0 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (EQ (CMPWconst [0] (ANDconst [c] x)) yes no) + // cond: + // result: (EQ (ANDCCconst [c] x) yes no) + for { + v := b.Control + if v.Op != OpPPC64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + v_0 := v.Args[0] + if v_0.Op != OpPPC64ANDconst { + break + } + c := v_0.AuxInt + x := v_0.Args[0] + b.Kind = BlockPPC64EQ + v0 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (EQ (CMPconst [0] z:(AND x y)) yes no) + // cond: z.Uses == 1 + // result: (EQ (ANDCC x y) yes no) + for { + v := b.Control + if v.Op != OpPPC64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpPPC64AND { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockPPC64EQ + v0 := b.NewValue0(v.Pos, OpPPC64ANDCC, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (EQ (CMPconst [0] z:(OR x y)) yes no) + // cond: z.Uses == 1 + // result: (EQ (ORCC x y) yes no) + for { + v := b.Control + if v.Op != OpPPC64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpPPC64OR { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockPPC64EQ + v0 := b.NewValue0(v.Pos, OpPPC64ORCC, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (EQ (CMPconst [0] z:(XOR x y)) yes no) + // cond: z.Uses == 1 + // result: (EQ (XORCC x y) yes no) + for { + v := b.Control + if v.Op != OpPPC64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpPPC64XOR { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockPPC64EQ + v0 := b.NewValue0(v.Pos, OpPPC64XORCC, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } case BlockPPC64GE: // match: (GE (FlagEQ) yes no) // cond: @@ -31051,6 +31188,143 @@ func rewriteBlockPPC64(b *Block) bool { b.Aux = nil return true } + // match: (GE (CMPconst [0] (ANDconst [c] x)) yes no) + // cond: + // result: (GE (ANDCCconst [c] x) yes no) + for { + v := b.Control + if v.Op != OpPPC64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + v_0 := v.Args[0] + if v_0.Op != OpPPC64ANDconst { + break + } + c := v_0.AuxInt + x := v_0.Args[0] + b.Kind = BlockPPC64GE + v0 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPWconst [0] (ANDconst [c] x)) yes no) + // cond: + // result: (GE (ANDCCconst [c] x) yes no) + for { + v := b.Control + if v.Op != OpPPC64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + v_0 := v.Args[0] + if v_0.Op != OpPPC64ANDconst { + break + } + c := v_0.AuxInt + x := v_0.Args[0] + b.Kind = BlockPPC64GE + v0 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] z:(AND x y)) yes no) + // cond: z.Uses == 1 + // result: (GE (ANDCC x y) yes no) + for { + v := b.Control + if v.Op != OpPPC64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpPPC64AND { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockPPC64GE + v0 := b.NewValue0(v.Pos, OpPPC64ANDCC, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] z:(OR x y)) yes no) + // cond: z.Uses == 1 + // result: (GE (ORCC x y) yes no) + for { + v := b.Control + if v.Op != OpPPC64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpPPC64OR { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockPPC64GE + v0 := b.NewValue0(v.Pos, OpPPC64ORCC, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] z:(XOR x y)) yes no) + // cond: z.Uses == 1 + // result: (GE (XORCC x y) yes no) + for { + v := b.Control + if v.Op != OpPPC64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpPPC64XOR { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockPPC64GE + v0 := b.NewValue0(v.Pos, OpPPC64XORCC, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } case BlockPPC64GT: // match: (GT (FlagEQ) yes no) // cond: @@ -31107,6 +31381,143 @@ func rewriteBlockPPC64(b *Block) bool { b.Aux = nil return true } + // match: (GT (CMPconst [0] (ANDconst [c] x)) yes no) + // cond: + // result: (GT (ANDCCconst [c] x) yes no) + for { + v := b.Control + if v.Op != OpPPC64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + v_0 := v.Args[0] + if v_0.Op != OpPPC64ANDconst { + break + } + c := v_0.AuxInt + x := v_0.Args[0] + b.Kind = BlockPPC64GT + v0 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPWconst [0] (ANDconst [c] x)) yes no) + // cond: + // result: (GT (ANDCCconst [c] x) yes no) + for { + v := b.Control + if v.Op != OpPPC64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + v_0 := v.Args[0] + if v_0.Op != OpPPC64ANDconst { + break + } + c := v_0.AuxInt + x := v_0.Args[0] + b.Kind = BlockPPC64GT + v0 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] z:(AND x y)) yes no) + // cond: z.Uses == 1 + // result: (GT (ANDCC x y) yes no) + for { + v := b.Control + if v.Op != OpPPC64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpPPC64AND { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockPPC64GT + v0 := b.NewValue0(v.Pos, OpPPC64ANDCC, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] z:(OR x y)) yes no) + // cond: z.Uses == 1 + // result: (GT (ORCC x y) yes no) + for { + v := b.Control + if v.Op != OpPPC64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpPPC64OR { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockPPC64GT + v0 := b.NewValue0(v.Pos, OpPPC64ORCC, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] z:(XOR x y)) yes no) + // cond: z.Uses == 1 + // result: (GT (XORCC x y) yes no) + for { + v := b.Control + if v.Op != OpPPC64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpPPC64XOR { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockPPC64GT + v0 := b.NewValue0(v.Pos, OpPPC64XORCC, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } case BlockIf: // match: (If (Equal cc) yes no) // cond: @@ -31318,6 +31729,143 @@ func rewriteBlockPPC64(b *Block) bool { b.Aux = nil return true } + // match: (LE (CMPconst [0] (ANDconst [c] x)) yes no) + // cond: + // result: (LE (ANDCCconst [c] x) yes no) + for { + v := b.Control + if v.Op != OpPPC64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + v_0 := v.Args[0] + if v_0.Op != OpPPC64ANDconst { + break + } + c := v_0.AuxInt + x := v_0.Args[0] + b.Kind = BlockPPC64LE + v0 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPWconst [0] (ANDconst [c] x)) yes no) + // cond: + // result: (LE (ANDCCconst [c] x) yes no) + for { + v := b.Control + if v.Op != OpPPC64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + v_0 := v.Args[0] + if v_0.Op != OpPPC64ANDconst { + break + } + c := v_0.AuxInt + x := v_0.Args[0] + b.Kind = BlockPPC64LE + v0 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] z:(AND x y)) yes no) + // cond: z.Uses == 1 + // result: (LE (ANDCC x y) yes no) + for { + v := b.Control + if v.Op != OpPPC64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpPPC64AND { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockPPC64LE + v0 := b.NewValue0(v.Pos, OpPPC64ANDCC, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] z:(OR x y)) yes no) + // cond: z.Uses == 1 + // result: (LE (ORCC x y) yes no) + for { + v := b.Control + if v.Op != OpPPC64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpPPC64OR { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockPPC64LE + v0 := b.NewValue0(v.Pos, OpPPC64ORCC, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] z:(XOR x y)) yes no) + // cond: z.Uses == 1 + // result: (LE (XORCC x y) yes no) + for { + v := b.Control + if v.Op != OpPPC64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpPPC64XOR { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockPPC64LE + v0 := b.NewValue0(v.Pos, OpPPC64XORCC, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } case BlockPPC64LT: // match: (LT (FlagEQ) yes no) // cond: @@ -31374,6 +31922,143 @@ func rewriteBlockPPC64(b *Block) bool { b.Aux = nil return true } + // match: (LT (CMPconst [0] (ANDconst [c] x)) yes no) + // cond: + // result: (LT (ANDCCconst [c] x) yes no) + for { + v := b.Control + if v.Op != OpPPC64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + v_0 := v.Args[0] + if v_0.Op != OpPPC64ANDconst { + break + } + c := v_0.AuxInt + x := v_0.Args[0] + b.Kind = BlockPPC64LT + v0 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPWconst [0] (ANDconst [c] x)) yes no) + // cond: + // result: (LT (ANDCCconst [c] x) yes no) + for { + v := b.Control + if v.Op != OpPPC64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + v_0 := v.Args[0] + if v_0.Op != OpPPC64ANDconst { + break + } + c := v_0.AuxInt + x := v_0.Args[0] + b.Kind = BlockPPC64LT + v0 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] z:(AND x y)) yes no) + // cond: z.Uses == 1 + // result: (LT (ANDCC x y) yes no) + for { + v := b.Control + if v.Op != OpPPC64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpPPC64AND { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockPPC64LT + v0 := b.NewValue0(v.Pos, OpPPC64ANDCC, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] z:(OR x y)) yes no) + // cond: z.Uses == 1 + // result: (LT (ORCC x y) yes no) + for { + v := b.Control + if v.Op != OpPPC64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpPPC64OR { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockPPC64LT + v0 := b.NewValue0(v.Pos, OpPPC64ORCC, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] z:(XOR x y)) yes no) + // cond: z.Uses == 1 + // result: (LT (XORCC x y) yes no) + for { + v := b.Control + if v.Op != OpPPC64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpPPC64XOR { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockPPC64LT + v0 := b.NewValue0(v.Pos, OpPPC64XORCC, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } case BlockPPC64NE: // match: (NE (CMPWconst [0] (Equal cc)) yes no) // cond: @@ -31689,6 +32374,143 @@ func rewriteBlockPPC64(b *Block) bool { b.Aux = nil return true } + // match: (NE (CMPconst [0] (ANDconst [c] x)) yes no) + // cond: + // result: (NE (ANDCCconst [c] x) yes no) + for { + v := b.Control + if v.Op != OpPPC64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + v_0 := v.Args[0] + if v_0.Op != OpPPC64ANDconst { + break + } + c := v_0.AuxInt + x := v_0.Args[0] + b.Kind = BlockPPC64NE + v0 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (NE (CMPWconst [0] (ANDconst [c] x)) yes no) + // cond: + // result: (NE (ANDCCconst [c] x) yes no) + for { + v := b.Control + if v.Op != OpPPC64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + v_0 := v.Args[0] + if v_0.Op != OpPPC64ANDconst { + break + } + c := v_0.AuxInt + x := v_0.Args[0] + b.Kind = BlockPPC64NE + v0 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (NE (CMPconst [0] z:(AND x y)) yes no) + // cond: z.Uses == 1 + // result: (NE (ANDCC x y) yes no) + for { + v := b.Control + if v.Op != OpPPC64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpPPC64AND { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockPPC64NE + v0 := b.NewValue0(v.Pos, OpPPC64ANDCC, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (NE (CMPconst [0] z:(OR x y)) yes no) + // cond: z.Uses == 1 + // result: (NE (ORCC x y) yes no) + for { + v := b.Control + if v.Op != OpPPC64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpPPC64OR { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockPPC64NE + v0 := b.NewValue0(v.Pos, OpPPC64ORCC, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (NE (CMPconst [0] z:(XOR x y)) yes no) + // cond: z.Uses == 1 + // result: (NE (XORCC x y) yes no) + for { + v := b.Control + if v.Op != OpPPC64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpPPC64XOR { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockPPC64NE + v0 := b.NewValue0(v.Pos, OpPPC64XORCC, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } } return false } diff --git a/test/codegen/comparisons.go b/test/codegen/comparisons.go index fb17d3ca5dd..f14918e9dfd 100644 --- a/test/codegen/comparisons.go +++ b/test/codegen/comparisons.go @@ -210,3 +210,36 @@ func CmpToZero(a, b, d int32, e, f int64) int32 { return 0 } } + +func CmpLogicalToZero(a, b, c uint32, d, e uint64) uint64 { + + // ppc64:"ANDCC",-"CMPW" + // ppc64le:"ANDCC",-"CMPW" + if a & 63 == 0 { + return 1 + } + + // ppc64:"ANDCC",-"CMP" + // ppc64le:"ANDCC",-"CMP" + if d & 255 == 0 { + return 1 + } + + // ppc64:"ANDCC",-"CMP" + // ppc64le:"ANDCC",-"CMP" + if d & e == 0 { + return 1 + } + // ppc64:"ORCC",-"CMP" + // ppc64le:"ORCC",-"CMP" + if d | e == 0 { + return 1 + } + + // ppc64:"XORCC",-"CMP" + // ppc64le:"XORCC",-"CMP" + if e ^ d == 0 { + return 1 + } + return 0 +}