]> Cypherpunks.ru repositories - gostls13.git/commitdiff
cmd/compile: merge zero constant ISEL in PPC64 lateLower pass
authorPaul E. Murphy <murp@ibm.com>
Wed, 12 Oct 2022 19:02:38 +0000 (14:02 -0500)
committerPaul Murphy <murp@ibm.com>
Mon, 14 Nov 2022 19:44:47 +0000 (19:44 +0000)
Add a new SSA opcode ISELZ, similar to ISELB to represent a select
of value or 0. Then, merge candidate ISEL opcodes inside the late
lower pass.

This avoids complicating rules within the the lower pass.

Change-Id: I3b14c94b763863aadc834b0e910a85870c131313
Reviewed-on: https://go-review.googlesource.com/c/go/+/442596
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Lynn Boger <laboger@linux.vnet.ibm.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Run-TryBot: Paul Murphy <murp@ibm.com>
Reviewed-by: Joedian Reid <joedian@golang.org>
src/cmd/compile/internal/ppc64/ssa.go
src/cmd/compile/internal/ssa/_gen/PPC64Ops.go
src/cmd/compile/internal/ssa/_gen/PPC64latelower.rules
src/cmd/compile/internal/ssa/opGen.go
src/cmd/compile/internal/ssa/rewritePPC64latelower.go
test/codegen/condmove.go

index aa3620f56b5dcf135030f7d768fedbd784f1c676..c25681a71c907b328317214c196d0eec5607be7c 100644 (file)
@@ -963,18 +963,21 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                p.To.Type = obj.TYPE_MEM
                p.To.Reg = v.Args[0].Reg()
 
-       case ssa.OpPPC64ISEL, ssa.OpPPC64ISELB:
-               // ISEL, ISELB
-               // AuxInt value indicates condition: 0=LT 1=GT 2=EQ 4=GE 5=LE 6=NE
-               // ISEL only accepts 0, 1, 2 condition values but the others can be
-               // achieved by swapping operand order.
-               // arg0 ? arg1 : arg2 with conditions LT, GT, EQ
-               // arg0 ? arg2 : arg1 for conditions GE, LE, NE
-               // ISELB is used when a boolean result is needed, returning 0 or 1
+       case ssa.OpPPC64ISEL, ssa.OpPPC64ISELB, ssa.OpPPC64ISELZ:
+               // ISEL  AuxInt ? arg0 : arg1
+               // ISELB is a special case of ISEL where AuxInt ? $1 (arg0) : $0.
+               // ISELZ is a special case of ISEL where arg1 is implicitly $0.
+               //
+               // AuxInt value indicates conditions 0=LT 1=GT 2=EQ 3=SO 4=GE 5=LE 6=NE 7=NSO.
+               // ISEL accepts a CR bit argument, not a condition as expressed by AuxInt.
+               // Convert the condition to a CR bit argument by the following conversion:
+               //
+               // AuxInt&3 ? arg0 : arg1 for conditions LT, GT, EQ, SO
+               // AuxInt&3 ? arg1 : arg0 for conditions GE, LE, NE, NSO
                p := s.Prog(ppc64.AISEL)
                p.To.Type = obj.TYPE_REG
                p.To.Reg = v.Reg()
-               // For ISELB, boolean result 0 or 1. Use R0 for 0 operand to avoid load.
+               // For ISELB/ISELZ Use R0 for 0 operand to avoid load.
                r := obj.Addr{Type: obj.TYPE_REG, Reg: ppc64.REG_R0}
                if v.Op == ssa.OpPPC64ISEL {
                        r.Reg = v.Args[1].Reg()
index fe129c6467360e140d0a7782db8044e5983223a6..baa783e30b7515aba4e5eb4edfdfd782ccfec3bd 100644 (file)
@@ -404,11 +404,14 @@ func init() {
                {name: "CMPWconst", argLength: 1, reg: gp1cr, asm: "CMPW", aux: "Int32", typ: "Flags"},
                {name: "CMPWUconst", argLength: 1, reg: gp1cr, asm: "CMPWU", aux: "Int32", typ: "Flags"},
 
-               // ISEL auxInt values 0=LT 1=GT 2=EQ   arg2 ? arg0 : arg1
-               // ISEL auxInt values 4=GE 5=LE 6=NE   !arg2 ? arg1 : arg0
-               // ISELB special case where arg0, arg1 values are 0, 1 for boolean result
-               {name: "ISEL", argLength: 3, reg: crgp21, asm: "ISEL", aux: "Int32", typ: "Int32"},  // see above
-               {name: "ISELB", argLength: 2, reg: crgp11, asm: "ISEL", aux: "Int32", typ: "Int32"}, // see above
+               // ISEL  arg2 ? arg0 : arg1
+               // ISELB arg1 ? arg0 : $0. arg0 is some register holding $1.
+               // ISELZ arg1 ? arg0 : $0
+               // auxInt values 0=LT 1=GT 2=EQ 3=SO (summary overflow/unordered) 4=GE 5=LE 6=NE 7=NSO (not summary overflow/not unordered)
+               // Note, auxInt^4 inverts the comparison condition. For example, LT^4 becomes GE, and "ISEL [a] x y z" is equivalent to ISEL [a^4] y x z".
+               {name: "ISEL", argLength: 3, reg: crgp21, asm: "ISEL", aux: "Int32", typ: "Int32"},
+               {name: "ISELB", argLength: 2, reg: crgp11, asm: "ISEL", aux: "Int32", typ: "Int32"},
+               {name: "ISELZ", argLength: 2, reg: crgp11, asm: "ISEL", aux: "Int32"},
 
                // pseudo-ops
                {name: "Equal", argLength: 1, reg: crgp},         // bool, true flags encode x==y false otherwise.
index c43e10a8095fcf66be11aa8f550b7cf749037b82..ada97b23f664dca6db32ccb9659f0c3bd752690c 100644 (file)
@@ -3,3 +3,8 @@
 // license that can be found in the LICENSE file.
 
 // This file contains rules used by the laterLower pass.
+
+// Simplify ISEL x $0 z into ISELZ
+(ISEL [a] x (MOVDconst [0]) z) => (ISELZ [a] x z)
+// Simplify ISEL $0 y z into ISELZ by inverting comparison and reversing arguments.
+(ISEL [a] (MOVDconst [0]) y z) => (ISELZ [a^0x4] y z)
index d84bc279a4abeb4a13b4585c77e7bc6abfeca21e..9fb751535d7e3eb7007bc90ddae94277894d417b 100644 (file)
@@ -2240,6 +2240,7 @@ const (
        OpPPC64CMPWUconst
        OpPPC64ISEL
        OpPPC64ISELB
+       OpPPC64ISELZ
        OpPPC64Equal
        OpPPC64NotEqual
        OpPPC64LessThan
@@ -30071,6 +30072,20 @@ var opcodeTable = [...]opInfo{
                        },
                },
        },
+       {
+               name:    "ISELZ",
+               auxType: auxInt32,
+               argLen:  2,
+               asm:     ppc64.AISEL,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {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
+                       },
+                       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:   "Equal",
                argLen: 1,
index 2c66630045b52662d64612694aad69f4744d9155..d687f59c3e43f8ce436faf4403d1818d5e698e31 100644 (file)
@@ -4,6 +4,44 @@
 package ssa
 
 func rewriteValuePPC64latelower(v *Value) bool {
+       switch v.Op {
+       case OpPPC64ISEL:
+               return rewriteValuePPC64latelower_OpPPC64ISEL(v)
+       }
+       return false
+}
+func rewriteValuePPC64latelower_OpPPC64ISEL(v *Value) bool {
+       v_2 := v.Args[2]
+       v_1 := v.Args[1]
+       v_0 := v.Args[0]
+       // match: (ISEL [a] x (MOVDconst [0]) z)
+       // result: (ISELZ [a] x z)
+       for {
+               a := auxIntToInt32(v.AuxInt)
+               x := v_0
+               if v_1.Op != OpPPC64MOVDconst || auxIntToInt64(v_1.AuxInt) != 0 {
+                       break
+               }
+               z := v_2
+               v.reset(OpPPC64ISELZ)
+               v.AuxInt = int32ToAuxInt(a)
+               v.AddArg2(x, z)
+               return true
+       }
+       // match: (ISEL [a] (MOVDconst [0]) y z)
+       // result: (ISELZ [a^0x4] y z)
+       for {
+               a := auxIntToInt32(v.AuxInt)
+               if v_0.Op != OpPPC64MOVDconst || auxIntToInt64(v_0.AuxInt) != 0 {
+                       break
+               }
+               y := v_1
+               z := v_2
+               v.reset(OpPPC64ISELZ)
+               v.AuxInt = int32ToAuxInt(a ^ 0x4)
+               v.AddArg2(y, z)
+               return true
+       }
        return false
 }
 func rewriteBlockPPC64latelower(b *Block) bool {
index bfab62213be7983d7307631719795430a35230f3..7b0f32e70840a621c9f5573b94cd71c1f203e6b6 100644 (file)
@@ -440,3 +440,27 @@ func cmovzero2(c bool) int {
        // loong64:"MASKNEZ", -"MASKEQZ"
        return x
 }
+
+// Conditionally selecting between a value or 0 can be done without
+// an extra load of 0 to a register on PPC64 by using R0 (which always
+// holds the value $0) instead. Verify both cases where either arg1
+// or arg2 is zero.
+func cmovzeroreg0(a, b int) int {
+       x := 0
+       if a == b {
+               x = a
+       }
+       // ppc64:"ISEL\t[$]2, R[0-9]+, R0, R[0-9]+"
+       // ppc64le:"ISEL\t[$]2, R[0-9]+, R0, R[0-9]+"
+       return x
+}
+
+func cmovzeroreg1(a, b int) int {
+       x := a
+       if a == b {
+               x = 0
+       }
+       // ppc64:"ISEL\t[$]2, R0, R[0-9]+, R[0-9]+"
+       // ppc64le:"ISEL\t[$]2, R0, R[0-9]+, R[0-9]+"
+       return x
+}