github.com/sanprasirt/go@v0.0.0-20170607001320-a027466e4b6d/src/cmd/compile/internal/ssa/gen/PPC64Ops.go (about)

     1  // Copyright 2016 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // +build ignore
     6  
     7  package main
     8  
     9  import "strings"
    10  
    11  // Notes:
    12  //  - Less-than-64-bit integer types live in the low portion of registers.
    13  //    For now, the upper portion is junk; sign/zero-extension might be optimized in the future, but not yet.
    14  //  - Boolean types are zero or 1; stored in a byte, but loaded with AMOVBZ so the upper bytes of a register are zero.
    15  //  - *const instructions may use a constant larger than the instruction can encode.
    16  //    In this case the assembler expands to multiple instructions and uses tmp
    17  //    register (R31).
    18  
    19  var regNamesPPC64 = []string{
    20  	"R0", // REGZERO, not used, but simplifies counting in regalloc
    21  	"SP", // REGSP
    22  	"SB", // REGSB
    23  	"R3",
    24  	"R4",
    25  	"R5",
    26  	"R6",
    27  	"R7",
    28  	"R8",
    29  	"R9",
    30  	"R10",
    31  	"R11", // REGCTXT for closures
    32  	"R12",
    33  	"R13", // REGTLS
    34  	"R14",
    35  	"R15",
    36  	"R16",
    37  	"R17",
    38  	"R18",
    39  	"R19",
    40  	"R20",
    41  	"R21",
    42  	"R22",
    43  	"R23",
    44  	"R24",
    45  	"R25",
    46  	"R26",
    47  	"R27",
    48  	"R28",
    49  	"R29",
    50  	"g",   // REGG.  Using name "g" and setting Config.hasGReg makes it "just happen".
    51  	"R31", // REGTMP
    52  
    53  	"F0",
    54  	"F1",
    55  	"F2",
    56  	"F3",
    57  	"F4",
    58  	"F5",
    59  	"F6",
    60  	"F7",
    61  	"F8",
    62  	"F9",
    63  	"F10",
    64  	"F11",
    65  	"F12",
    66  	"F13",
    67  	"F14",
    68  	"F15",
    69  	"F16",
    70  	"F17",
    71  	"F18",
    72  	"F19",
    73  	"F20",
    74  	"F21",
    75  	"F22",
    76  	"F23",
    77  	"F24",
    78  	"F25",
    79  	"F26",
    80  	"F27",
    81  	"F28",
    82  	"F29",
    83  	"F30",
    84  	"F31",
    85  
    86  	// "CR0",
    87  	// "CR1",
    88  	// "CR2",
    89  	// "CR3",
    90  	// "CR4",
    91  	// "CR5",
    92  	// "CR6",
    93  	// "CR7",
    94  
    95  	// "CR",
    96  	// "XER",
    97  	// "LR",
    98  	// "CTR",
    99  }
   100  
   101  func init() {
   102  	// Make map from reg names to reg integers.
   103  	if len(regNamesPPC64) > 64 {
   104  		panic("too many registers")
   105  	}
   106  	num := map[string]int{}
   107  	for i, name := range regNamesPPC64 {
   108  		num[name] = i
   109  	}
   110  	buildReg := func(s string) regMask {
   111  		m := regMask(0)
   112  		for _, r := range strings.Split(s, " ") {
   113  			if n, ok := num[r]; ok {
   114  				m |= regMask(1) << uint(n)
   115  				continue
   116  			}
   117  			panic("register " + r + " not found")
   118  		}
   119  		return m
   120  	}
   121  
   122  	var (
   123  		gp = buildReg("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")
   124  		fp = buildReg("F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26")
   125  		sp = buildReg("SP")
   126  		sb = buildReg("SB")
   127  		gr = buildReg("g")
   128  		// cr  = buildReg("CR")
   129  		// ctr = buildReg("CTR")
   130  		// lr  = buildReg("LR")
   131  		tmp  = buildReg("R31")
   132  		ctxt = buildReg("R11")
   133  		// tls = buildReg("R13")
   134  		gp01        = regInfo{inputs: nil, outputs: []regMask{gp}}
   135  		gp11        = regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{gp}}
   136  		gp21        = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}, outputs: []regMask{gp}}
   137  		gp1cr       = regInfo{inputs: []regMask{gp | sp | sb}}
   138  		gp2cr       = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}}
   139  		crgp        = regInfo{inputs: nil, outputs: []regMask{gp}}
   140  		gpload      = regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{gp}}
   141  		gpstore     = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}}
   142  		gpstorezero = regInfo{inputs: []regMask{gp | sp | sb}} // ppc64.REGZERO is reserved zero value
   143  		gpxchg      = regInfo{inputs: []regMask{gp | sp | sb, gp}, outputs: []regMask{gp}}
   144  		gpcas       = regInfo{inputs: []regMask{gp | sp | sb, gp, gp}, outputs: []regMask{gp}}
   145  		fp01        = regInfo{inputs: nil, outputs: []regMask{fp}}
   146  		fp11        = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}}
   147  		fpgp        = regInfo{inputs: []regMask{fp}, outputs: []regMask{gp}}
   148  		gpfp        = regInfo{inputs: []regMask{gp}, outputs: []regMask{fp}}
   149  		fp21        = regInfo{inputs: []regMask{fp, fp}, outputs: []regMask{fp}}
   150  		fp31        = regInfo{inputs: []regMask{fp, fp, fp}, outputs: []regMask{fp}}
   151  		fp2cr       = regInfo{inputs: []regMask{fp, fp}}
   152  		fpload      = regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{fp}}
   153  		fpstore     = regInfo{inputs: []regMask{gp | sp | sb, fp}}
   154  		callerSave  = regMask(gp | fp | gr)
   155  	)
   156  	ops := []opData{
   157  		{name: "ADD", argLength: 2, reg: gp21, asm: "ADD", commutative: true},                     // arg0 + arg1
   158  		{name: "ADDconst", argLength: 1, reg: gp11, asm: "ADD", aux: "SymOff", symEffect: "Addr"}, // arg0 + auxInt + aux.(*gc.Sym)
   159  		{name: "FADD", argLength: 2, reg: fp21, asm: "FADD", commutative: true},                   // arg0+arg1
   160  		{name: "FADDS", argLength: 2, reg: fp21, asm: "FADDS", commutative: true},                 // arg0+arg1
   161  		{name: "SUB", argLength: 2, reg: gp21, asm: "SUB"},                                        // arg0-arg1
   162  		{name: "FSUB", argLength: 2, reg: fp21, asm: "FSUB"},                                      // arg0-arg1
   163  		{name: "FSUBS", argLength: 2, reg: fp21, asm: "FSUBS"},                                    // arg0-arg1
   164  
   165  		{name: "MULLD", argLength: 2, reg: gp21, asm: "MULLD", typ: "Int64", commutative: true}, // arg0*arg1 (signed 64-bit)
   166  		{name: "MULLW", argLength: 2, reg: gp21, asm: "MULLW", typ: "Int32", commutative: true}, // arg0*arg1 (signed 32-bit)
   167  
   168  		{name: "MULHD", argLength: 2, reg: gp21, asm: "MULHD", commutative: true},   // (arg0 * arg1) >> 64, signed
   169  		{name: "MULHW", argLength: 2, reg: gp21, asm: "MULHW", commutative: true},   // (arg0 * arg1) >> 32, signed
   170  		{name: "MULHDU", argLength: 2, reg: gp21, asm: "MULHDU", commutative: true}, // (arg0 * arg1) >> 64, unsigned
   171  		{name: "MULHWU", argLength: 2, reg: gp21, asm: "MULHWU", commutative: true}, // (arg0 * arg1) >> 32, unsigned
   172  
   173  		{name: "FMUL", argLength: 2, reg: fp21, asm: "FMUL", commutative: true},   // arg0*arg1
   174  		{name: "FMULS", argLength: 2, reg: fp21, asm: "FMULS", commutative: true}, // arg0*arg1
   175  
   176  		{name: "FMADD", argLength: 3, reg: fp31, asm: "FMADD"},   // arg0*arg1 + arg2
   177  		{name: "FMADDS", argLength: 3, reg: fp31, asm: "FMADDS"}, // arg0*arg1 + arg2
   178  		{name: "FMSUB", argLength: 3, reg: fp31, asm: "FMSUB"},   // arg0*arg1 - arg2
   179  		{name: "FMSUBS", argLength: 3, reg: fp31, asm: "FMSUBS"}, // arg0*arg1 - arg2
   180  
   181  		{name: "SRAD", argLength: 2, reg: gp21, asm: "SRAD"}, // arg0 >>a arg1, 64 bits (all sign if arg1 & 64 != 0)
   182  		{name: "SRAW", argLength: 2, reg: gp21, asm: "SRAW"}, // arg0 >>a arg1, 32 bits (all sign if arg1 & 32 != 0)
   183  		{name: "SRD", argLength: 2, reg: gp21, asm: "SRD"},   // arg0 >> arg1, 64 bits  (0 if arg1 & 64 != 0)
   184  		{name: "SRW", argLength: 2, reg: gp21, asm: "SRW"},   // arg0 >> arg1, 32 bits  (0 if arg1 & 32 != 0)
   185  		{name: "SLD", argLength: 2, reg: gp21, asm: "SLD"},   // arg0 << arg1, 64 bits  (0 if arg1 & 64 != 0)
   186  		{name: "SLW", argLength: 2, reg: gp21, asm: "SLW"},   // arg0 << arg1, 32 bits  (0 if arg1 & 32 != 0)
   187  
   188  		{name: "ADDconstForCarry", argLength: 1, reg: regInfo{inputs: []regMask{gp | sp | sb}, clobbers: tmp}, aux: "Int16", asm: "ADDC", typ: "Flags"}, // _, carry := arg0 + aux
   189  		{name: "MaskIfNotCarry", argLength: 1, reg: crgp, asm: "ADDME", typ: "Int64"},                                                                   // carry - 1 (if carry then 0 else -1)
   190  
   191  		{name: "SRADconst", argLength: 1, reg: gp11, asm: "SRAD", aux: "Int64"}, // arg0 >>a aux, 64 bits
   192  		{name: "SRAWconst", argLength: 1, reg: gp11, asm: "SRAW", aux: "Int64"}, // arg0 >>a aux, 32 bits
   193  		{name: "SRDconst", argLength: 1, reg: gp11, asm: "SRD", aux: "Int64"},   // arg0 >> aux, 64 bits
   194  		{name: "SRWconst", argLength: 1, reg: gp11, asm: "SRW", aux: "Int64"},   // arg0 >> aux, 32 bits
   195  		{name: "SLDconst", argLength: 1, reg: gp11, asm: "SLD", aux: "Int64"},   // arg0 << aux, 64 bits
   196  		{name: "SLWconst", argLength: 1, reg: gp11, asm: "SLW", aux: "Int64"},   // arg0 << aux, 32 bits
   197  
   198  		{name: "ROTLconst", argLength: 1, reg: gp11, asm: "ROTL", aux: "Int64"},   // arg0 rotate left by auxInt bits
   199  		{name: "ROTLWconst", argLength: 1, reg: gp11, asm: "ROTLW", aux: "Int64"}, // uint32(arg0) rotate left by auxInt bits
   200  
   201  		{name: "CNTLZD", argLength: 1, reg: gp11, asm: "CNTLZD", clobberFlags: true}, // count leading zeros
   202  		{name: "CNTLZW", argLength: 1, reg: gp11, asm: "CNTLZW", clobberFlags: true}, // count leading zeros (32 bit)
   203  
   204  		{name: "POPCNTD", argLength: 1, reg: gp11, asm: "POPCNTD"}, // number of set bits in arg0
   205  		{name: "POPCNTW", argLength: 1, reg: gp11, asm: "POPCNTW"}, // number of set bits in each word of arg0 placed in corresponding word
   206  		{name: "POPCNTB", argLength: 1, reg: gp11, asm: "POPCNTB"}, // number of set bits in each byte of arg0 placed in corresonding byte
   207  
   208  		{name: "FDIV", argLength: 2, reg: fp21, asm: "FDIV"},   // arg0/arg1
   209  		{name: "FDIVS", argLength: 2, reg: fp21, asm: "FDIVS"}, // arg0/arg1
   210  
   211  		{name: "DIVD", argLength: 2, reg: gp21, asm: "DIVD", typ: "Int64"},   // arg0/arg1 (signed 64-bit)
   212  		{name: "DIVW", argLength: 2, reg: gp21, asm: "DIVW", typ: "Int32"},   // arg0/arg1 (signed 32-bit)
   213  		{name: "DIVDU", argLength: 2, reg: gp21, asm: "DIVDU", typ: "Int64"}, // arg0/arg1 (unsigned 64-bit)
   214  		{name: "DIVWU", argLength: 2, reg: gp21, asm: "DIVWU", typ: "Int32"}, // arg0/arg1 (unsigned 32-bit)
   215  
   216  		// MOD is implemented as rem := arg0 - (arg0/arg1) * arg1
   217  
   218  		// Conversions are all float-to-float register operations.  "Integer" refers to encoding in the FP register.
   219  		{name: "FCTIDZ", argLength: 1, reg: fp11, asm: "FCTIDZ", typ: "Float64"}, // convert float to 64-bit int round towards zero
   220  		{name: "FCTIWZ", argLength: 1, reg: fp11, asm: "FCTIWZ", typ: "Float64"}, // convert float to 32-bit int round towards zero
   221  		{name: "FCFID", argLength: 1, reg: fp11, asm: "FCFID", typ: "Float64"},   // convert 64-bit integer to float
   222  		{name: "FRSP", argLength: 1, reg: fp11, asm: "FRSP", typ: "Float64"},     // round float to 32-bit value
   223  
   224  		// Movement between float and integer registers with no change in bits; accomplished with stores+loads on PPC.
   225  		// Because the 32-bit load-literal-bits instructions have impoverished addressability, always widen the
   226  		// data instead and use FMOVDload and FMOVDstore instead (this will also dodge endianess issues).
   227  		// There are optimizations that should apply -- (Xi2f64 (MOVWload (not-ADD-ptr+offset) ) ) could use
   228  		// the word-load instructions.  (Xi2f64 (MOVDload ptr )) can be (FMOVDload ptr)
   229  
   230  		{name: "Xf2i64", argLength: 1, reg: fpgp, typ: "Int64"},   // move 64 bits of F register into G register
   231  		{name: "Xi2f64", argLength: 1, reg: gpfp, typ: "Float64"}, // move 64 bits of G register into F register
   232  
   233  		{name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true},               // arg0&arg1
   234  		{name: "ANDN", argLength: 2, reg: gp21, asm: "ANDN"},                                // arg0&^arg1
   235  		{name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true},                 // arg0|arg1
   236  		{name: "ORN", argLength: 2, reg: gp21, asm: "ORN"},                                  // arg0|^arg1
   237  		{name: "NOR", argLength: 2, reg: gp21, asm: "NOR", commutative: true},               // ^(arg0|arg1)
   238  		{name: "XOR", argLength: 2, reg: gp21, asm: "XOR", typ: "Int64", commutative: true}, // arg0^arg1
   239  		{name: "EQV", argLength: 2, reg: gp21, asm: "EQV", typ: "Int64", commutative: true}, // arg0^^arg1
   240  		{name: "NEG", argLength: 1, reg: gp11, asm: "NEG"},                                  // -arg0 (integer)
   241  		{name: "FNEG", argLength: 1, reg: fp11, asm: "FNEG"},                                // -arg0 (floating point)
   242  		{name: "FSQRT", argLength: 1, reg: fp11, asm: "FSQRT"},                              // sqrt(arg0) (floating point)
   243  		{name: "FSQRTS", argLength: 1, reg: fp11, asm: "FSQRTS"},                            // sqrt(arg0) (floating point, single precision)
   244  
   245  		{name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int64"},                                                                                     // arg0|aux
   246  		{name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int64"},                                                                                   // arg0^aux
   247  		{name: "ANDconst", argLength: 1, reg: regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{gp}}, asm: "ANDCC", aux: "Int64", clobberFlags: true}, // arg0&aux // and-immediate sets CC on PPC, always.
   248  		{name: "ANDCCconst", argLength: 1, reg: regInfo{inputs: []regMask{gp | sp | sb}}, asm: "ANDCC", aux: "Int64", typ: "Flags"},                             // arg0&aux == 0 // and-immediate sets CC on PPC, always.
   249  
   250  		{name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB", typ: "Int64"},                                                               // sign extend int8 to int64
   251  		{name: "MOVBZreg", argLength: 1, reg: gp11, asm: "MOVBZ", typ: "Int64"},                                                             // zero extend uint8 to uint64
   252  		{name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH", typ: "Int64"},                                                               // sign extend int16 to int64
   253  		{name: "MOVHZreg", argLength: 1, reg: gp11, asm: "MOVHZ", typ: "Int64"},                                                             // zero extend uint16 to uint64
   254  		{name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW", typ: "Int64"},                                                               // sign extend int32 to int64
   255  		{name: "MOVWZreg", argLength: 1, reg: gp11, asm: "MOVWZ", typ: "Int64"},                                                             // zero extend uint32 to uint64
   256  		{name: "MOVBZload", argLength: 2, reg: gpload, asm: "MOVBZ", aux: "SymOff", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"},  // zero extend uint8 to uint64
   257  		{name: "MOVHload", argLength: 2, reg: gpload, asm: "MOVH", aux: "SymOff", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"},    // sign extend int16 to int64
   258  		{name: "MOVHZload", argLength: 2, reg: gpload, asm: "MOVHZ", aux: "SymOff", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // zero extend uint16 to uint64
   259  		{name: "MOVWload", argLength: 2, reg: gpload, asm: "MOVW", aux: "SymOff", typ: "Int32", faultOnNilArg0: true, symEffect: "Read"},    // sign extend int32 to int64
   260  		{name: "MOVWZload", argLength: 2, reg: gpload, asm: "MOVWZ", aux: "SymOff", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"}, // zero extend uint32 to uint64
   261  		{name: "MOVDload", argLength: 2, reg: gpload, asm: "MOVD", aux: "SymOff", typ: "Int64", faultOnNilArg0: true, symEffect: "Read"},
   262  
   263  		{name: "FMOVDload", argLength: 2, reg: fpload, asm: "FMOVD", aux: "SymOff", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"},
   264  		{name: "FMOVSload", argLength: 2, reg: fpload, asm: "FMOVS", aux: "SymOff", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"},
   265  		{name: "MOVBstore", argLength: 3, reg: gpstore, asm: "MOVB", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},
   266  		{name: "MOVHstore", argLength: 3, reg: gpstore, asm: "MOVH", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},
   267  		{name: "MOVWstore", argLength: 3, reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},
   268  		{name: "MOVDstore", argLength: 3, reg: gpstore, asm: "MOVD", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},
   269  		{name: "FMOVDstore", argLength: 3, reg: fpstore, asm: "FMOVD", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},
   270  		{name: "FMOVSstore", argLength: 3, reg: fpstore, asm: "FMOVS", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},
   271  
   272  		{name: "MOVBstorezero", argLength: 2, reg: gpstorezero, asm: "MOVB", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store zero byte to arg0+aux.  arg1=mem
   273  		{name: "MOVHstorezero", argLength: 2, reg: gpstorezero, asm: "MOVH", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store zero 2 bytes to ...
   274  		{name: "MOVWstorezero", argLength: 2, reg: gpstorezero, asm: "MOVW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store zero 4 bytes to ...
   275  		{name: "MOVDstorezero", argLength: 2, reg: gpstorezero, asm: "MOVD", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store zero 8 bytes to ...
   276  
   277  		{name: "MOVDaddr", argLength: 1, reg: regInfo{inputs: []regMask{sp | sb}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVD", rematerializeable: true, symEffect: "Addr"}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB
   278  
   279  		{name: "MOVDconst", argLength: 0, reg: gp01, aux: "Int64", asm: "MOVD", typ: "Int64", rematerializeable: true}, //
   280  		{name: "FMOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "FMOVD", rematerializeable: true},           //
   281  		{name: "FMOVSconst", argLength: 0, reg: fp01, aux: "Float32", asm: "FMOVS", rematerializeable: true},           //
   282  		{name: "FCMPU", argLength: 2, reg: fp2cr, asm: "FCMPU", typ: "Flags"},
   283  
   284  		{name: "CMP", argLength: 2, reg: gp2cr, asm: "CMP", typ: "Flags"},     // arg0 compare to arg1
   285  		{name: "CMPU", argLength: 2, reg: gp2cr, asm: "CMPU", typ: "Flags"},   // arg0 compare to arg1
   286  		{name: "CMPW", argLength: 2, reg: gp2cr, asm: "CMPW", typ: "Flags"},   // arg0 compare to arg1
   287  		{name: "CMPWU", argLength: 2, reg: gp2cr, asm: "CMPWU", typ: "Flags"}, // arg0 compare to arg1
   288  		{name: "CMPconst", argLength: 1, reg: gp1cr, asm: "CMP", aux: "Int64", typ: "Flags"},
   289  		{name: "CMPUconst", argLength: 1, reg: gp1cr, asm: "CMPU", aux: "Int64", typ: "Flags"},
   290  		{name: "CMPWconst", argLength: 1, reg: gp1cr, asm: "CMPW", aux: "Int32", typ: "Flags"},
   291  		{name: "CMPWUconst", argLength: 1, reg: gp1cr, asm: "CMPWU", aux: "Int32", typ: "Flags"},
   292  
   293  		// pseudo-ops
   294  		{name: "Equal", argLength: 1, reg: crgp},         // bool, true flags encode x==y false otherwise.
   295  		{name: "NotEqual", argLength: 1, reg: crgp},      // bool, true flags encode x!=y false otherwise.
   296  		{name: "LessThan", argLength: 1, reg: crgp},      // bool, true flags encode  x<y false otherwise.
   297  		{name: "FLessThan", argLength: 1, reg: crgp},     // bool, true flags encode  x<y false otherwise.
   298  		{name: "LessEqual", argLength: 1, reg: crgp},     // bool, true flags encode  x<=y false otherwise.
   299  		{name: "FLessEqual", argLength: 1, reg: crgp},    // bool, true flags encode  x<=y false otherwise; PPC <= === !> which is wrong for NaN
   300  		{name: "GreaterThan", argLength: 1, reg: crgp},   // bool, true flags encode  x>y false otherwise.
   301  		{name: "FGreaterThan", argLength: 1, reg: crgp},  // bool, true flags encode  x>y false otherwise.
   302  		{name: "GreaterEqual", argLength: 1, reg: crgp},  // bool, true flags encode  x>=y false otherwise.
   303  		{name: "FGreaterEqual", argLength: 1, reg: crgp}, // bool, true flags encode  x>=y false otherwise.; PPC >= === !< which is wrong for NaN
   304  
   305  		// Scheduler ensures LoweredGetClosurePtr occurs only in entry block,
   306  		// and sorts it to the very beginning of the block to prevent other
   307  		// use of the closure pointer.
   308  		{name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{ctxt}}},
   309  
   310  		//arg0=ptr,arg1=mem, returns void.  Faults if ptr is nil.
   311  		{name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gp | sp | sb}, clobbers: tmp}, clobberFlags: true, nilCheck: true, faultOnNilArg0: true},
   312  		// Round ops to block fused-multiply-add extraction.
   313  		{name: "LoweredRound32F", argLength: 1, reg: fp11, resultInArg0: true},
   314  		{name: "LoweredRound64F", argLength: 1, reg: fp11, resultInArg0: true},
   315  
   316  		// Convert pointer to integer, takes a memory operand for ordering.
   317  		{name: "MOVDconvert", argLength: 2, reg: gp11, asm: "MOVD"},
   318  
   319  		{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true, call: true, symEffect: "None"},                   // call static function aux.(*obj.LSym).  arg0=mem, auxint=argsize, returns mem
   320  		{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gp | sp, ctxt, 0}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call function via closure.  arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
   321  		{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true},                 // call fn by pointer.  arg0=codeptr, arg1=mem, auxint=argsize, returns mem
   322  
   323  		// large or unaligned zeroing
   324  		// arg0 = address of memory to zero (in R3, changed as side effect)
   325  		// returns mem
   326  		//
   327  		// a loop is generated when there is more than one iteration
   328  		// needed to clear 4 doublewords
   329  		//
   330  		// 	MOVD	$len/32,R31
   331  		//	MOVD	R31,CTR
   332  		//	loop:
   333  		//	MOVD	R0,(R3)
   334  		//	MOVD	R0,8(R3)
   335  		//	MOVD	R0,16(R3)
   336  		//	MOVD	R0,24(R3)
   337  		//	ADD	R3,32
   338  		//	BC	loop
   339  
   340  		// remaining doubleword clears generated as needed
   341  		//	MOVD	R0,(R3)
   342  		//	MOVD	R0,8(R3)
   343  		//	MOVD	R0,16(R3)
   344  		//	MOVD	R0,24(R3)
   345  
   346  		// one or more of these to clear remainder < 8 bytes
   347  		//	MOVW	R0,n1(R3)
   348  		//	MOVH	R0,n2(R3)
   349  		//	MOVB	R0,n3(R3)
   350  		{
   351  			name:      "LoweredZero",
   352  			aux:       "Int64",
   353  			argLength: 2,
   354  			reg: regInfo{
   355  				inputs:   []regMask{buildReg("R3")},
   356  				clobbers: buildReg("R3"),
   357  			},
   358  			clobberFlags:   true,
   359  			typ:            "Mem",
   360  			faultOnNilArg0: true,
   361  		},
   362  		// Loop code:
   363  		//	MOVD len/32,REG_TMP  only for loop
   364  		//	MOVD REG_TMP,CTR     only for loop
   365  		// loop:
   366  		//	MOVD (R4),R7
   367  		//	MOVD 8(R4),R8
   368  		//	MOVD 16(R4),R9
   369  		//	MOVD 24(R4),R10
   370  		//	ADD  R4,$32          only with loop
   371  		//	MOVD R7,(R3)
   372  		//	MOVD R8,8(R3)
   373  		//	MOVD R9,16(R3)
   374  		//	MOVD R10,24(R3)
   375  		//	ADD  R3,$32          only with loop
   376  		//	BC 16,0,loop         only with loop
   377  		// Bytes not moved by this loop are moved
   378  		// with a combination of the following instructions,
   379  		// starting with the largest sizes and generating as
   380  		// many as needed, using the appropriate offset value.
   381  		//	MOVD  n(R4),R7
   382  		//	MOVD  R7,n(R3)
   383  		//	MOVW  n1(R4),R7
   384  		//	MOVW  R7,n1(R3)
   385  		//	MOVH  n2(R4),R7
   386  		//	MOVH  R7,n2(R3)
   387  		//	MOVB  n3(R4),R7
   388  		//	MOVB  R7,n3(R3)
   389  
   390  		{
   391  			name:      "LoweredMove",
   392  			aux:       "Int64",
   393  			argLength: 3,
   394  			reg: regInfo{
   395  				inputs:   []regMask{buildReg("R3"), buildReg("R4")},
   396  				clobbers: buildReg("R3 R4 R7 R8 R9 R10"),
   397  			},
   398  			clobberFlags:   true,
   399  			typ:            "Mem",
   400  			faultOnNilArg0: true,
   401  			faultOnNilArg1: true,
   402  		},
   403  
   404  		{name: "LoweredAtomicStore32", argLength: 3, reg: gpstore, typ: "Mem", faultOnNilArg0: true, hasSideEffects: true},
   405  		{name: "LoweredAtomicStore64", argLength: 3, reg: gpstore, typ: "Mem", faultOnNilArg0: true, hasSideEffects: true},
   406  
   407  		{name: "LoweredAtomicLoad32", argLength: 2, reg: gpload, typ: "UInt32", clobberFlags: true, faultOnNilArg0: true},
   408  		{name: "LoweredAtomicLoad64", argLength: 2, reg: gpload, typ: "Int64", clobberFlags: true, faultOnNilArg0: true},
   409  		{name: "LoweredAtomicLoadPtr", argLength: 2, reg: gpload, typ: "Int64", clobberFlags: true, faultOnNilArg0: true},
   410  
   411  		// atomic add32, 64
   412  		// SYNC
   413  		// LDAR         (Rarg0), Rout
   414  		// ADD		Rarg1, Rout
   415  		// STDCCC       Rout, (Rarg0)
   416  		// BNE          -3(PC)
   417  		// ISYNC
   418  		// return new sum
   419  
   420  		{name: "LoweredAtomicAdd32", argLength: 3, reg: gpxchg, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
   421  		{name: "LoweredAtomicAdd64", argLength: 3, reg: gpxchg, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
   422  
   423  		// atomic exchange32, 64
   424  		// SYNC
   425  		// LDAR         (Rarg0), Rout
   426  		// STDCCC       Rarg1, (Rarg0)
   427  		// BNE          -2(PC)
   428  		// ISYNC
   429  		// return old val
   430  
   431  		{name: "LoweredAtomicExchange32", argLength: 3, reg: gpxchg, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
   432  		{name: "LoweredAtomicExchange64", argLength: 3, reg: gpxchg, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
   433  
   434  		// atomic compare and swap.
   435  		// arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory. auxint must be zero.
   436  		// if *arg0 == arg1 {
   437  		//   *arg0 = arg2
   438  		//   return (true, memory)
   439  		// } else {
   440  		//   return (false, memory)
   441  		// }
   442  		// SYNC
   443  		// LDAR		(Rarg0), Rtmp
   444  		// CMP		Rarg1, Rtmp
   445  		// BNE		3(PC)
   446  		// STDCCC	Rarg2, (Rarg0)
   447  		// BNE		-4(PC)
   448  		// CBNZ         Rtmp, -4(PC)
   449  		// CSET         EQ, Rout
   450  		{name: "LoweredAtomicCas64", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
   451  		{name: "LoweredAtomicCas32", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
   452  
   453  		// atomic 8 and/or.
   454  		// *arg0 &= (|=) arg1. arg2=mem. returns memory. auxint must be zero.
   455  		// LBAR		(Rarg0), Rtmp
   456  		// AND/OR	Rarg1, Rtmp
   457  		// STBCCC	Rtmp, (Rarg0), Rtmp
   458  		// BNE		Rtmp, -3(PC)
   459  
   460  		{name: "LoweredAtomicAnd8", argLength: 3, reg: gpstore, asm: "AND", faultOnNilArg0: true, hasSideEffects: true},
   461  		{name: "LoweredAtomicOr8", argLength: 3, reg: gpstore, asm: "OR", faultOnNilArg0: true, hasSideEffects: true},
   462  
   463  		// (InvertFlags (CMP a b)) == (CMP b a)
   464  		// So if we want (LessThan (CMP a b)) but we can't do that because a is a constant,
   465  		// then we do (LessThan (InvertFlags (CMP b a))) instead.
   466  		// Rewrites will convert this to (GreaterThan (CMP b a)).
   467  		// InvertFlags is a pseudo-op which can't appear in assembly output.
   468  		{name: "InvertFlags", argLength: 1}, // reverse direction of arg0
   469  
   470  		// Constant flag values. For any comparison, there are 3 possible
   471  		// outcomes: either the three from the signed total order (<,==,>)
   472  		// or the three from the unsigned total order, depending on which
   473  		// comparison operation was used (CMP or CMPU -- PPC is different from
   474  		// the other architectures, which have a single comparison producing
   475  		// both signed and unsigned comparison results.)
   476  
   477  		// These ops are for temporary use by rewrite rules. They
   478  		// cannot appear in the generated assembly.
   479  		{name: "FlagEQ"}, // equal
   480  		{name: "FlagLT"}, // signed < or unsigned <
   481  		{name: "FlagGT"}, // signed > or unsigned >
   482  
   483  	}
   484  
   485  	blocks := []blockData{
   486  		{name: "EQ"},
   487  		{name: "NE"},
   488  		{name: "LT"},
   489  		{name: "LE"},
   490  		{name: "GT"},
   491  		{name: "GE"},
   492  		{name: "FLT"},
   493  		{name: "FLE"},
   494  		{name: "FGT"},
   495  		{name: "FGE"},
   496  	}
   497  
   498  	archs = append(archs, arch{
   499  		name:            "PPC64",
   500  		pkg:             "cmd/internal/obj/ppc64",
   501  		genfile:         "../../ppc64/ssa.go",
   502  		ops:             ops,
   503  		blocks:          blocks,
   504  		regnames:        regNamesPPC64,
   505  		gpregmask:       gp,
   506  		fpregmask:       fp,
   507  		framepointerreg: int8(num["SP"]),
   508  		linkreg:         -1, // not used
   509  	})
   510  }