github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/src/cmd/compile/internal/ssa/gen/ARM64Ops.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 // - Integer types live in the low portion of registers. Upper portions are junk. 13 // - Boolean types use the low-order byte of a register. 0=false, 1=true. 14 // Upper bytes are junk. 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 (R27). 18 19 // Suffixes encode the bit width of various instructions. 20 // D (double word) = 64 bit 21 // W (word) = 32 bit 22 // H (half word) = 16 bit 23 // HU = 16 bit unsigned 24 // B (byte) = 8 bit 25 // BU = 8 bit unsigned 26 // S (single) = 32 bit float 27 // D (double) = 64 bit float 28 29 // Note: registers not used in regalloc are not included in this list, 30 // so that regmask stays within int64 31 // Be careful when hand coding regmasks. 32 var regNamesARM64 = []string{ 33 "R0", 34 "R1", 35 "R2", 36 "R3", 37 "R4", 38 "R5", 39 "R6", 40 "R7", 41 "R8", 42 "R9", 43 "R10", 44 "R11", 45 "R12", 46 "R13", 47 "R14", 48 "R15", 49 "R16", 50 "R17", 51 "R18", // platform register, not used 52 "R19", 53 "R20", 54 "R21", 55 "R22", 56 "R23", 57 "R24", 58 "R25", 59 "R26", 60 // R27 = REGTMP not used in regalloc 61 "g", // aka R28 62 "R29", // frame pointer, not used 63 "R30", // aka REGLINK 64 "SP", // aka R31 65 66 "F0", 67 "F1", 68 "F2", 69 "F3", 70 "F4", 71 "F5", 72 "F6", 73 "F7", 74 "F8", 75 "F9", 76 "F10", 77 "F11", 78 "F12", 79 "F13", 80 "F14", 81 "F15", 82 "F16", 83 "F17", 84 "F18", 85 "F19", 86 "F20", 87 "F21", 88 "F22", 89 "F23", 90 "F24", 91 "F25", 92 "F26", 93 "F27", 94 "F28", 95 "F29", 96 "F30", 97 "F31", 98 99 // pseudo-registers 100 "SB", 101 } 102 103 func init() { 104 // Make map from reg names to reg integers. 105 if len(regNamesARM64) > 64 { 106 panic("too many registers") 107 } 108 num := map[string]int{} 109 for i, name := range regNamesARM64 { 110 num[name] = i 111 } 112 buildReg := func(s string) regMask { 113 m := regMask(0) 114 for _, r := range strings.Split(s, " ") { 115 if n, ok := num[r]; ok { 116 m |= regMask(1) << uint(n) 117 continue 118 } 119 panic("register " + r + " not found") 120 } 121 return m 122 } 123 124 // Common individual register masks 125 var ( 126 gp = buildReg("R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30") 127 gpg = gp | buildReg("g") 128 gpsp = gp | buildReg("SP") 129 gpspg = gpg | buildReg("SP") 130 gpspsbg = gpspg | buildReg("SB") 131 fp = buildReg("F0 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 F27 F28 F29 F30 F31") 132 callerSave = gp | fp | buildReg("g") // runtime.setg (and anything calling it) may clobber g 133 ) 134 // Common regInfo 135 var ( 136 gp01 = regInfo{inputs: nil, outputs: []regMask{gp}} 137 gp11 = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}} 138 gp11sp = regInfo{inputs: []regMask{gpspg}, outputs: []regMask{gp}} 139 gp1flags = regInfo{inputs: []regMask{gpg}} 140 gp1flags1 = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}} 141 gp21 = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}} 142 gp2flags = regInfo{inputs: []regMask{gpg, gpg}} 143 gp2flags1 = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp}} 144 gpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}} 145 gpstore = regInfo{inputs: []regMask{gpspsbg, gpg}} 146 gpstore0 = regInfo{inputs: []regMask{gpspsbg}} 147 gpxchg = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{gp}} 148 gpcas = regInfo{inputs: []regMask{gpspsbg, gpg, gpg}, outputs: []regMask{gp}} 149 fp01 = regInfo{inputs: nil, outputs: []regMask{fp}} 150 fp11 = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}} 151 fpgp = regInfo{inputs: []regMask{fp}, outputs: []regMask{gp}} 152 gpfp = regInfo{inputs: []regMask{gp}, outputs: []regMask{fp}} 153 fp21 = regInfo{inputs: []regMask{fp, fp}, outputs: []regMask{fp}} 154 fp2flags = regInfo{inputs: []regMask{fp, fp}} 155 fpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{fp}} 156 fpstore = regInfo{inputs: []regMask{gpspsbg, fp}} 157 readflags = regInfo{inputs: nil, outputs: []regMask{gp}} 158 ) 159 ops := []opData{ 160 // binary ops 161 {name: "ADD", argLength: 2, reg: gp21, asm: "ADD", commutative: true}, // arg0 + arg1 162 {name: "ADDconst", argLength: 1, reg: gp11sp, asm: "ADD", aux: "Int64"}, // arg0 + auxInt 163 {name: "SUB", argLength: 2, reg: gp21, asm: "SUB"}, // arg0 - arg1 164 {name: "SUBconst", argLength: 1, reg: gp11, asm: "SUB", aux: "Int64"}, // arg0 - auxInt 165 {name: "MUL", argLength: 2, reg: gp21, asm: "MUL", commutative: true}, // arg0 * arg1 166 {name: "MULW", argLength: 2, reg: gp21, asm: "MULW", commutative: true}, // arg0 * arg1, 32-bit 167 {name: "MULH", argLength: 2, reg: gp21, asm: "SMULH", commutative: true}, // (arg0 * arg1) >> 64, signed 168 {name: "UMULH", argLength: 2, reg: gp21, asm: "UMULH", commutative: true}, // (arg0 * arg1) >> 64, unsigned 169 {name: "MULL", argLength: 2, reg: gp21, asm: "SMULL", commutative: true}, // arg0 * arg1, signed, 32-bit mult results in 64-bit 170 {name: "UMULL", argLength: 2, reg: gp21, asm: "UMULL", commutative: true}, // arg0 * arg1, unsigned, 32-bit mult results in 64-bit 171 {name: "DIV", argLength: 2, reg: gp21, asm: "SDIV"}, // arg0 / arg1, signed 172 {name: "UDIV", argLength: 2, reg: gp21, asm: "UDIV"}, // arg0 / arg1, unsighed 173 {name: "DIVW", argLength: 2, reg: gp21, asm: "SDIVW"}, // arg0 / arg1, signed, 32 bit 174 {name: "UDIVW", argLength: 2, reg: gp21, asm: "UDIVW"}, // arg0 / arg1, unsighed, 32 bit 175 {name: "MOD", argLength: 2, reg: gp21, asm: "REM"}, // arg0 % arg1, signed 176 {name: "UMOD", argLength: 2, reg: gp21, asm: "UREM"}, // arg0 % arg1, unsigned 177 {name: "MODW", argLength: 2, reg: gp21, asm: "REMW"}, // arg0 % arg1, signed, 32 bit 178 {name: "UMODW", argLength: 2, reg: gp21, asm: "UREMW"}, // arg0 % arg1, unsigned, 32 bit 179 180 {name: "FADDS", argLength: 2, reg: fp21, asm: "FADDS", commutative: true}, // arg0 + arg1 181 {name: "FADDD", argLength: 2, reg: fp21, asm: "FADDD", commutative: true}, // arg0 + arg1 182 {name: "FSUBS", argLength: 2, reg: fp21, asm: "FSUBS"}, // arg0 - arg1 183 {name: "FSUBD", argLength: 2, reg: fp21, asm: "FSUBD"}, // arg0 - arg1 184 {name: "FMULS", argLength: 2, reg: fp21, asm: "FMULS", commutative: true}, // arg0 * arg1 185 {name: "FMULD", argLength: 2, reg: fp21, asm: "FMULD", commutative: true}, // arg0 * arg1 186 {name: "FDIVS", argLength: 2, reg: fp21, asm: "FDIVS"}, // arg0 / arg1 187 {name: "FDIVD", argLength: 2, reg: fp21, asm: "FDIVD"}, // arg0 / arg1 188 189 {name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true}, // arg0 & arg1 190 {name: "ANDconst", argLength: 1, reg: gp11, asm: "AND", aux: "Int64"}, // arg0 & auxInt 191 {name: "OR", argLength: 2, reg: gp21, asm: "ORR", commutative: true}, // arg0 | arg1 192 {name: "ORconst", argLength: 1, reg: gp11, asm: "ORR", aux: "Int64"}, // arg0 | auxInt 193 {name: "XOR", argLength: 2, reg: gp21, asm: "EOR", commutative: true}, // arg0 ^ arg1 194 {name: "XORconst", argLength: 1, reg: gp11, asm: "EOR", aux: "Int64"}, // arg0 ^ auxInt 195 {name: "BIC", argLength: 2, reg: gp21, asm: "BIC"}, // arg0 &^ arg1 196 {name: "BICconst", argLength: 1, reg: gp11, asm: "BIC", aux: "Int64"}, // arg0 &^ auxInt 197 198 // unary ops 199 {name: "MVN", argLength: 1, reg: gp11, asm: "MVN"}, // ^arg0 200 {name: "NEG", argLength: 1, reg: gp11, asm: "NEG"}, // -arg0 201 {name: "FNEGS", argLength: 1, reg: fp11, asm: "FNEGS"}, // -arg0, float32 202 {name: "FNEGD", argLength: 1, reg: fp11, asm: "FNEGD"}, // -arg0, float64 203 {name: "FSQRTD", argLength: 1, reg: fp11, asm: "FSQRTD"}, // sqrt(arg0), float64 204 {name: "REV", argLength: 1, reg: gp11, asm: "REV"}, // byte reverse, 64-bit 205 {name: "REVW", argLength: 1, reg: gp11, asm: "REVW"}, // byte reverse, 32-bit 206 {name: "REV16W", argLength: 1, reg: gp11, asm: "REV16W"}, // byte reverse in each 16-bit halfword, 32-bit 207 {name: "RBIT", argLength: 1, reg: gp11, asm: "RBIT"}, // bit reverse, 64-bit 208 {name: "RBITW", argLength: 1, reg: gp11, asm: "RBITW"}, // bit reverse, 32-bit 209 {name: "CLZ", argLength: 1, reg: gp11, asm: "CLZ"}, // count leading zero, 64-bit 210 {name: "CLZW", argLength: 1, reg: gp11, asm: "CLZW"}, // count leading zero, 32-bit 211 212 // shifts 213 {name: "SLL", argLength: 2, reg: gp21, asm: "LSL"}, // arg0 << arg1, shift amount is mod 64 214 {name: "SLLconst", argLength: 1, reg: gp11, asm: "LSL", aux: "Int64"}, // arg0 << auxInt 215 {name: "SRL", argLength: 2, reg: gp21, asm: "LSR"}, // arg0 >> arg1, unsigned, shift amount is mod 64 216 {name: "SRLconst", argLength: 1, reg: gp11, asm: "LSR", aux: "Int64"}, // arg0 >> auxInt, unsigned 217 {name: "SRA", argLength: 2, reg: gp21, asm: "ASR"}, // arg0 >> arg1, signed, shift amount is mod 64 218 {name: "SRAconst", argLength: 1, reg: gp11, asm: "ASR", aux: "Int64"}, // arg0 >> auxInt, signed 219 {name: "RORconst", argLength: 1, reg: gp11, asm: "ROR", aux: "Int64"}, // arg0 right rotate by auxInt bits 220 {name: "RORWconst", argLength: 1, reg: gp11, asm: "RORW", aux: "Int64"}, // uint32(arg0) right rotate by auxInt bits 221 222 // comparisons 223 {name: "CMP", argLength: 2, reg: gp2flags, asm: "CMP", typ: "Flags"}, // arg0 compare to arg1 224 {name: "CMPconst", argLength: 1, reg: gp1flags, asm: "CMP", aux: "Int64", typ: "Flags"}, // arg0 compare to auxInt 225 {name: "CMPW", argLength: 2, reg: gp2flags, asm: "CMPW", typ: "Flags"}, // arg0 compare to arg1, 32 bit 226 {name: "CMPWconst", argLength: 1, reg: gp1flags, asm: "CMPW", aux: "Int32", typ: "Flags"}, // arg0 compare to auxInt, 32 bit 227 {name: "CMN", argLength: 2, reg: gp2flags, asm: "CMN", typ: "Flags"}, // arg0 compare to -arg1 228 {name: "CMNconst", argLength: 1, reg: gp1flags, asm: "CMN", aux: "Int64", typ: "Flags"}, // arg0 compare to -auxInt 229 {name: "CMNW", argLength: 2, reg: gp2flags, asm: "CMNW", typ: "Flags"}, // arg0 compare to -arg1, 32 bit 230 {name: "CMNWconst", argLength: 1, reg: gp1flags, asm: "CMNW", aux: "Int32", typ: "Flags"}, // arg0 compare to -auxInt, 32 bit 231 {name: "FCMPS", argLength: 2, reg: fp2flags, asm: "FCMPS", typ: "Flags"}, // arg0 compare to arg1, float32 232 {name: "FCMPD", argLength: 2, reg: fp2flags, asm: "FCMPD", typ: "Flags"}, // arg0 compare to arg1, float64 233 234 // shifted ops 235 {name: "ADDshiftLL", argLength: 2, reg: gp21, asm: "ADD", aux: "Int64"}, // arg0 + arg1<<auxInt 236 {name: "ADDshiftRL", argLength: 2, reg: gp21, asm: "ADD", aux: "Int64"}, // arg0 + arg1>>auxInt, unsigned shift 237 {name: "ADDshiftRA", argLength: 2, reg: gp21, asm: "ADD", aux: "Int64"}, // arg0 + arg1>>auxInt, signed shift 238 {name: "SUBshiftLL", argLength: 2, reg: gp21, asm: "SUB", aux: "Int64"}, // arg0 - arg1<<auxInt 239 {name: "SUBshiftRL", argLength: 2, reg: gp21, asm: "SUB", aux: "Int64"}, // arg0 - arg1>>auxInt, unsigned shift 240 {name: "SUBshiftRA", argLength: 2, reg: gp21, asm: "SUB", aux: "Int64"}, // arg0 - arg1>>auxInt, signed shift 241 {name: "ANDshiftLL", argLength: 2, reg: gp21, asm: "AND", aux: "Int64"}, // arg0 & (arg1<<auxInt) 242 {name: "ANDshiftRL", argLength: 2, reg: gp21, asm: "AND", aux: "Int64"}, // arg0 & (arg1>>auxInt), unsigned shift 243 {name: "ANDshiftRA", argLength: 2, reg: gp21, asm: "AND", aux: "Int64"}, // arg0 & (arg1>>auxInt), signed shift 244 {name: "ORshiftLL", argLength: 2, reg: gp21, asm: "ORR", aux: "Int64"}, // arg0 | arg1<<auxInt 245 {name: "ORshiftRL", argLength: 2, reg: gp21, asm: "ORR", aux: "Int64"}, // arg0 | arg1>>auxInt, unsigned shift 246 {name: "ORshiftRA", argLength: 2, reg: gp21, asm: "ORR", aux: "Int64"}, // arg0 | arg1>>auxInt, signed shift 247 {name: "XORshiftLL", argLength: 2, reg: gp21, asm: "EOR", aux: "Int64"}, // arg0 ^ arg1<<auxInt 248 {name: "XORshiftRL", argLength: 2, reg: gp21, asm: "EOR", aux: "Int64"}, // arg0 ^ arg1>>auxInt, unsigned shift 249 {name: "XORshiftRA", argLength: 2, reg: gp21, asm: "EOR", aux: "Int64"}, // arg0 ^ arg1>>auxInt, signed shift 250 {name: "BICshiftLL", argLength: 2, reg: gp21, asm: "BIC", aux: "Int64"}, // arg0 &^ (arg1<<auxInt) 251 {name: "BICshiftRL", argLength: 2, reg: gp21, asm: "BIC", aux: "Int64"}, // arg0 &^ (arg1>>auxInt), unsigned shift 252 {name: "BICshiftRA", argLength: 2, reg: gp21, asm: "BIC", aux: "Int64"}, // arg0 &^ (arg1>>auxInt), signed shift 253 {name: "CMPshiftLL", argLength: 2, reg: gp2flags, asm: "CMP", aux: "Int64", typ: "Flags"}, // arg0 compare to arg1<<auxInt 254 {name: "CMPshiftRL", argLength: 2, reg: gp2flags, asm: "CMP", aux: "Int64", typ: "Flags"}, // arg0 compare to arg1>>auxInt, unsigned shift 255 {name: "CMPshiftRA", argLength: 2, reg: gp2flags, asm: "CMP", aux: "Int64", typ: "Flags"}, // arg0 compare to arg1>>auxInt, signed shift 256 257 // moves 258 {name: "MOVDconst", argLength: 0, reg: gp01, aux: "Int64", asm: "MOVD", typ: "UInt64", rematerializeable: true}, // 32 low bits of auxint 259 {name: "FMOVSconst", argLength: 0, reg: fp01, aux: "Float64", asm: "FMOVS", typ: "Float32", rematerializeable: true}, // auxint as 64-bit float, convert to 32-bit float 260 {name: "FMOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "FMOVD", typ: "Float64", rematerializeable: true}, // auxint as 64-bit float 261 262 {name: "MOVDaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP") | buildReg("SB")}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVD", rematerializeable: true, symEffect: "Addr"}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB 263 264 {name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 265 {name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 266 {name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 267 {name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 268 {name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "Int32", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 269 {name: "MOVWUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVWU", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 270 {name: "MOVDload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVD", typ: "UInt64", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 271 {name: "FMOVSload", argLength: 2, reg: fpload, aux: "SymOff", asm: "FMOVS", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 272 {name: "FMOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "FMOVD", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 273 274 {name: "MOVBstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 1 byte of arg1 to arg0 + auxInt + aux. arg2=mem. 275 {name: "MOVHstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes of arg1 to arg0 + auxInt + aux. arg2=mem. 276 {name: "MOVWstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of arg1 to arg0 + auxInt + aux. arg2=mem. 277 {name: "MOVDstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVD", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of arg1 to arg0 + auxInt + aux. arg2=mem. 278 {name: "FMOVSstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "FMOVS", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of arg1 to arg0 + auxInt + aux. arg2=mem. 279 {name: "FMOVDstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "FMOVD", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of arg1 to arg0 + auxInt + aux. arg2=mem. 280 281 {name: "MOVBstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 1 byte of zero to arg0 + auxInt + aux. arg1=mem. 282 {name: "MOVHstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes of zero to arg0 + auxInt + aux. arg1=mem. 283 {name: "MOVWstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of zero to arg0 + auxInt + aux. arg1=mem. 284 {name: "MOVDstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVD", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of zero to arg0 + auxInt + aux. ar12=mem. 285 286 // conversions 287 {name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB"}, // move from arg0, sign-extended from byte 288 {name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU"}, // move from arg0, unsign-extended from byte 289 {name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH"}, // move from arg0, sign-extended from half 290 {name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU"}, // move from arg0, unsign-extended from half 291 {name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW"}, // move from arg0, sign-extended from word 292 {name: "MOVWUreg", argLength: 1, reg: gp11, asm: "MOVWU"}, // move from arg0, unsign-extended from word 293 {name: "MOVDreg", argLength: 1, reg: gp11, asm: "MOVD"}, // move from arg0 294 295 {name: "MOVDnop", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}, resultInArg0: true}, // nop, return arg0 in same register 296 297 {name: "SCVTFWS", argLength: 1, reg: gpfp, asm: "SCVTFWS"}, // int32 -> float32 298 {name: "SCVTFWD", argLength: 1, reg: gpfp, asm: "SCVTFWD"}, // int32 -> float64 299 {name: "UCVTFWS", argLength: 1, reg: gpfp, asm: "UCVTFWS"}, // uint32 -> float32 300 {name: "UCVTFWD", argLength: 1, reg: gpfp, asm: "UCVTFWD"}, // uint32 -> float64 301 {name: "SCVTFS", argLength: 1, reg: gpfp, asm: "SCVTFS"}, // int64 -> float32 302 {name: "SCVTFD", argLength: 1, reg: gpfp, asm: "SCVTFD"}, // int64 -> float64 303 {name: "UCVTFS", argLength: 1, reg: gpfp, asm: "UCVTFS"}, // uint64 -> float32 304 {name: "UCVTFD", argLength: 1, reg: gpfp, asm: "UCVTFD"}, // uint64 -> float64 305 {name: "FCVTZSSW", argLength: 1, reg: fpgp, asm: "FCVTZSSW"}, // float32 -> int32 306 {name: "FCVTZSDW", argLength: 1, reg: fpgp, asm: "FCVTZSDW"}, // float64 -> int32 307 {name: "FCVTZUSW", argLength: 1, reg: fpgp, asm: "FCVTZUSW"}, // float32 -> uint32 308 {name: "FCVTZUDW", argLength: 1, reg: fpgp, asm: "FCVTZUDW"}, // float64 -> uint32 309 {name: "FCVTZSS", argLength: 1, reg: fpgp, asm: "FCVTZSS"}, // float32 -> int64 310 {name: "FCVTZSD", argLength: 1, reg: fpgp, asm: "FCVTZSD"}, // float64 -> int64 311 {name: "FCVTZUS", argLength: 1, reg: fpgp, asm: "FCVTZUS"}, // float32 -> uint64 312 {name: "FCVTZUD", argLength: 1, reg: fpgp, asm: "FCVTZUD"}, // float64 -> uint64 313 {name: "FCVTSD", argLength: 1, reg: fp11, asm: "FCVTSD"}, // float32 -> float64 314 {name: "FCVTDS", argLength: 1, reg: fp11, asm: "FCVTDS"}, // float64 -> float32 315 316 // conditional instructions 317 {name: "CSELULT", argLength: 3, reg: gp2flags1, asm: "CSEL"}, // returns arg0 if flags indicates unsigned LT, arg1 otherwise, arg2=flags 318 {name: "CSELULT0", argLength: 2, reg: gp1flags1, asm: "CSEL"}, // returns arg0 if flags indicates unsigned LT, 0 otherwise, arg1=flags 319 320 // function calls 321 {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 322 {name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("R26"), 0}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem 323 {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 324 325 // pseudo-ops 326 {name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}, nilCheck: true, faultOnNilArg0: true}, // panic if arg0 is nil. arg1=mem. 327 328 {name: "Equal", argLength: 1, reg: readflags}, // bool, true flags encode x==y false otherwise. 329 {name: "NotEqual", argLength: 1, reg: readflags}, // bool, true flags encode x!=y false otherwise. 330 {name: "LessThan", argLength: 1, reg: readflags}, // bool, true flags encode signed x<y false otherwise. 331 {name: "LessEqual", argLength: 1, reg: readflags}, // bool, true flags encode signed x<=y false otherwise. 332 {name: "GreaterThan", argLength: 1, reg: readflags}, // bool, true flags encode signed x>y false otherwise. 333 {name: "GreaterEqual", argLength: 1, reg: readflags}, // bool, true flags encode signed x>=y false otherwise. 334 {name: "LessThanU", argLength: 1, reg: readflags}, // bool, true flags encode unsigned x<y false otherwise. 335 {name: "LessEqualU", argLength: 1, reg: readflags}, // bool, true flags encode unsigned x<=y false otherwise. 336 {name: "GreaterThanU", argLength: 1, reg: readflags}, // bool, true flags encode unsigned x>y false otherwise. 337 {name: "GreaterEqualU", argLength: 1, reg: readflags}, // bool, true flags encode unsigned x>=y false otherwise. 338 339 // duffzero 340 // arg0 = address of memory to zero 341 // arg1 = mem 342 // auxint = offset into duffzero code to start executing 343 // returns mem 344 // R16 aka arm64.REGRT1 changed as side effect 345 { 346 name: "DUFFZERO", 347 aux: "Int64", 348 argLength: 2, 349 reg: regInfo{ 350 inputs: []regMask{gp}, 351 clobbers: buildReg("R16 R30"), 352 }, 353 faultOnNilArg0: true, 354 }, 355 356 // large zeroing 357 // arg0 = address of memory to zero (in R16 aka arm64.REGRT1, changed as side effect) 358 // arg1 = address of the last element to zero 359 // arg2 = mem 360 // returns mem 361 // MOVD.P ZR, 8(R16) 362 // CMP Rarg1, R16 363 // BLE -2(PC) 364 // Note: the-end-of-the-memory may be not a valid pointer. it's a problem if it is spilled. 365 // the-end-of-the-memory - 8 is with the area to zero, ok to spill. 366 { 367 name: "LoweredZero", 368 argLength: 3, 369 reg: regInfo{ 370 inputs: []regMask{buildReg("R16"), gp}, 371 clobbers: buildReg("R16"), 372 }, 373 clobberFlags: true, 374 faultOnNilArg0: true, 375 }, 376 377 // duffcopy 378 // arg0 = address of dst memory (in R17 aka arm64.REGRT2, changed as side effect) 379 // arg1 = address of src memory (in R16 aka arm64.REGRT1, changed as side effect) 380 // arg2 = mem 381 // auxint = offset into duffcopy code to start executing 382 // returns mem 383 // R16, R17 changed as side effect 384 { 385 name: "DUFFCOPY", 386 aux: "Int64", 387 argLength: 3, 388 reg: regInfo{ 389 inputs: []regMask{buildReg("R17"), buildReg("R16")}, 390 clobbers: buildReg("R16 R17 R30"), 391 }, 392 faultOnNilArg0: true, 393 faultOnNilArg1: true, 394 }, 395 396 // large move 397 // arg0 = address of dst memory (in R17 aka arm64.REGRT2, changed as side effect) 398 // arg1 = address of src memory (in R16 aka arm64.REGRT1, changed as side effect) 399 // arg2 = address of the last element of src 400 // arg3 = mem 401 // returns mem 402 // MOVD.P 8(R16), Rtmp 403 // MOVD.P Rtmp, 8(R17) 404 // CMP Rarg2, R16 405 // BLE -3(PC) 406 // Note: the-end-of-src may be not a valid pointer. it's a problem if it is spilled. 407 // the-end-of-src - 8 is within the area to copy, ok to spill. 408 { 409 name: "LoweredMove", 410 argLength: 4, 411 reg: regInfo{ 412 inputs: []regMask{buildReg("R17"), buildReg("R16"), gp}, 413 clobbers: buildReg("R16 R17"), 414 }, 415 clobberFlags: true, 416 faultOnNilArg0: true, 417 faultOnNilArg1: true, 418 }, 419 420 // Scheduler ensures LoweredGetClosurePtr occurs only in entry block, 421 // and sorts it to the very beginning of the block to prevent other 422 // use of R26 (arm64.REGCTXT, the closure pointer) 423 {name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{buildReg("R26")}}}, 424 425 // MOVDconvert converts between pointers and integers. 426 // We have a special op for this so as to not confuse GC 427 // (particularly stack maps). It takes a memory arg so it 428 // gets correctly ordered with respect to GC safepoints. 429 // arg0=ptr/int arg1=mem, output=int/ptr 430 {name: "MOVDconvert", argLength: 2, reg: gp11, asm: "MOVD"}, 431 432 // Constant flag values. For any comparison, there are 5 possible 433 // outcomes: the three from the signed total order (<,==,>) and the 434 // three from the unsigned total order. The == cases overlap. 435 // Note: there's a sixth "unordered" outcome for floating-point 436 // comparisons, but we don't use such a beast yet. 437 // These ops are for temporary use by rewrite rules. They 438 // cannot appear in the generated assembly. 439 {name: "FlagEQ"}, // equal 440 {name: "FlagLT_ULT"}, // signed < and unsigned < 441 {name: "FlagLT_UGT"}, // signed < and unsigned > 442 {name: "FlagGT_UGT"}, // signed > and unsigned < 443 {name: "FlagGT_ULT"}, // signed > and unsigned > 444 445 // (InvertFlags (CMP a b)) == (CMP b a) 446 // InvertFlags is a pseudo-op which can't appear in assembly output. 447 {name: "InvertFlags", argLength: 1}, // reverse direction of arg0 448 449 // atomic loads. 450 // load from arg0. arg1=mem. auxint must be zero. 451 // returns <value,memory> so they can be properly ordered with other loads. 452 {name: "LDAR", argLength: 2, reg: gpload, asm: "LDAR", faultOnNilArg0: true}, 453 {name: "LDARW", argLength: 2, reg: gpload, asm: "LDARW", faultOnNilArg0: true}, 454 455 // atomic stores. 456 // store arg1 to arg0. arg2=mem. returns memory. auxint must be zero. 457 {name: "STLR", argLength: 3, reg: gpstore, asm: "STLR", faultOnNilArg0: true, hasSideEffects: true}, 458 {name: "STLRW", argLength: 3, reg: gpstore, asm: "STLRW", faultOnNilArg0: true, hasSideEffects: true}, 459 460 // atomic exchange. 461 // store arg1 to arg0. arg2=mem. returns <old content of *arg0, memory>. auxint must be zero. 462 // LDAXR (Rarg0), Rout 463 // STLXR Rarg1, (Rarg0), Rtmp 464 // CBNZ Rtmp, -2(PC) 465 {name: "LoweredAtomicExchange64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, 466 {name: "LoweredAtomicExchange32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, 467 468 // atomic add. 469 // *arg0 += arg1. arg2=mem. returns <new content of *arg0, memory>. auxint must be zero. 470 // LDAXR (Rarg0), Rout 471 // ADD Rarg1, Rout 472 // STLXR Rout, (Rarg0), Rtmp 473 // CBNZ Rtmp, -3(PC) 474 {name: "LoweredAtomicAdd64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, 475 {name: "LoweredAtomicAdd32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, 476 477 // atomic compare and swap. 478 // arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory. auxint must be zero. 479 // if *arg0 == arg1 { 480 // *arg0 = arg2 481 // return (true, memory) 482 // } else { 483 // return (false, memory) 484 // } 485 // LDAXR (Rarg0), Rtmp 486 // CMP Rarg1, Rtmp 487 // BNE 3(PC) 488 // STLXR Rarg2, (Rarg0), Rtmp 489 // CBNZ Rtmp, -4(PC) 490 // CSET EQ, Rout 491 {name: "LoweredAtomicCas64", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true}, 492 {name: "LoweredAtomicCas32", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true}, 493 494 // atomic and/or. 495 // *arg0 &= (|=) arg1. arg2=mem. returns memory. auxint must be zero. 496 // LDAXRB (Rarg0), Rtmp 497 // AND/OR Rarg1, Rtmp 498 // STLXRB Rtmp, (Rarg0), Rtmp 499 // CBNZ Rtmp, -3(PC) 500 {name: "LoweredAtomicAnd8", argLength: 3, reg: gpstore, asm: "AND", faultOnNilArg0: true, hasSideEffects: true}, 501 {name: "LoweredAtomicOr8", argLength: 3, reg: gpstore, asm: "ORR", faultOnNilArg0: true, hasSideEffects: true}, 502 } 503 504 blocks := []blockData{ 505 {name: "EQ"}, 506 {name: "NE"}, 507 {name: "LT"}, 508 {name: "LE"}, 509 {name: "GT"}, 510 {name: "GE"}, 511 {name: "ULT"}, 512 {name: "ULE"}, 513 {name: "UGT"}, 514 {name: "UGE"}, 515 {name: "Z"}, // Control == 0 (take a register instead of flags) 516 {name: "NZ"}, // Control != 0 517 {name: "ZW"}, // Control == 0, 32-bit 518 {name: "NZW"}, // Control != 0, 32-bit 519 } 520 521 archs = append(archs, arch{ 522 name: "ARM64", 523 pkg: "cmd/internal/obj/arm64", 524 genfile: "../../arm64/ssa.go", 525 ops: ops, 526 blocks: blocks, 527 regnames: regNamesARM64, 528 gpregmask: gp, 529 fpregmask: fp, 530 framepointerreg: -1, // not used 531 linkreg: int8(num["R30"]), 532 }) 533 }