github.com/euank/go@v0.0.0-20160829210321-495514729181/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 instuction 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 = REGLINK not used in regalloc 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", // 0.0 95 "F29", // 0.5 96 "F30", // 1.0 97 "F31", // 2.0 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") 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") 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 //gp22 = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp, gp}} 145 //gp31 = regInfo{inputs: []regMask{gp, gp, gp}, outputs: []regMask{gp}} 146 //gp3flags = regInfo{inputs: []regMask{gp, gp, gp}} 147 //gp3flags1 = regInfo{inputs: []regMask{gp, gp, gp}, outputs: []regMask{gp}} 148 gpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}} 149 gpstore = regInfo{inputs: []regMask{gpspsbg, gpg}} 150 gpstore0 = regInfo{inputs: []regMask{gpspsbg}} 151 //gp2load = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{gp}} 152 //gp2store = regInfo{inputs: []regMask{gpspsbg, gpg, gpg}} 153 fp01 = regInfo{inputs: nil, outputs: []regMask{fp}} 154 fp11 = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}} 155 //fp1flags = regInfo{inputs: []regMask{fp}} 156 fpgp = regInfo{inputs: []regMask{fp}, outputs: []regMask{gp}} 157 gpfp = regInfo{inputs: []regMask{gp}, outputs: []regMask{fp}} 158 fp21 = regInfo{inputs: []regMask{fp, fp}, outputs: []regMask{fp}} 159 fp2flags = regInfo{inputs: []regMask{fp, fp}} 160 fpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{fp}} 161 fpstore = regInfo{inputs: []regMask{gpspsbg, fp}} 162 readflags = regInfo{inputs: nil, outputs: []regMask{gp}} 163 ) 164 ops := []opData{ 165 // binary ops 166 {name: "ADD", argLength: 2, reg: gp21, asm: "ADD", commutative: true}, // arg0 + arg1 167 {name: "ADDconst", argLength: 1, reg: gp11sp, asm: "ADD", aux: "Int64"}, // arg0 + auxInt 168 {name: "SUB", argLength: 2, reg: gp21, asm: "SUB"}, // arg0 - arg1 169 {name: "SUBconst", argLength: 1, reg: gp11, asm: "SUB", aux: "Int64"}, // arg0 - auxInt 170 {name: "MUL", argLength: 2, reg: gp21, asm: "MUL", commutative: true}, // arg0 * arg1 171 {name: "MULW", argLength: 2, reg: gp21, asm: "MULW", commutative: true}, // arg0 * arg1, 32-bit 172 {name: "MULH", argLength: 2, reg: gp21, asm: "SMULH", commutative: true}, // (arg0 * arg1) >> 64, signed 173 {name: "UMULH", argLength: 2, reg: gp21, asm: "UMULH", commutative: true}, // (arg0 * arg1) >> 64, unsigned 174 {name: "MULL", argLength: 2, reg: gp21, asm: "SMULL", commutative: true}, // arg0 * arg1, signed, 32-bit mult results in 64-bit 175 {name: "UMULL", argLength: 2, reg: gp21, asm: "UMULL", commutative: true}, // arg0 * arg1, unsigned, 32-bit mult results in 64-bit 176 {name: "DIV", argLength: 2, reg: gp21, asm: "SDIV"}, // arg0 / arg1, signed 177 {name: "UDIV", argLength: 2, reg: gp21, asm: "UDIV"}, // arg0 / arg1, unsighed 178 {name: "DIVW", argLength: 2, reg: gp21, asm: "SDIVW"}, // arg0 / arg1, signed, 32 bit 179 {name: "UDIVW", argLength: 2, reg: gp21, asm: "UDIVW"}, // arg0 / arg1, unsighed, 32 bit 180 {name: "MOD", argLength: 2, reg: gp21, asm: "REM"}, // arg0 % arg1, signed 181 {name: "UMOD", argLength: 2, reg: gp21, asm: "UREM"}, // arg0 % arg1, unsigned 182 {name: "MODW", argLength: 2, reg: gp21, asm: "REMW"}, // arg0 % arg1, signed, 32 bit 183 {name: "UMODW", argLength: 2, reg: gp21, asm: "UREMW"}, // arg0 % arg1, unsigned, 32 bit 184 185 {name: "FADDS", argLength: 2, reg: fp21, asm: "FADDS", commutative: true}, // arg0 + arg1 186 {name: "FADDD", argLength: 2, reg: fp21, asm: "FADDD", commutative: true}, // arg0 + arg1 187 {name: "FSUBS", argLength: 2, reg: fp21, asm: "FSUBS"}, // arg0 - arg1 188 {name: "FSUBD", argLength: 2, reg: fp21, asm: "FSUBD"}, // arg0 - arg1 189 {name: "FMULS", argLength: 2, reg: fp21, asm: "FMULS", commutative: true}, // arg0 * arg1 190 {name: "FMULD", argLength: 2, reg: fp21, asm: "FMULD", commutative: true}, // arg0 * arg1 191 {name: "FDIVS", argLength: 2, reg: fp21, asm: "FDIVS"}, // arg0 / arg1 192 {name: "FDIVD", argLength: 2, reg: fp21, asm: "FDIVD"}, // arg0 / arg1 193 194 {name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true}, // arg0 & arg1 195 {name: "ANDconst", argLength: 1, reg: gp11, asm: "AND", aux: "Int64"}, // arg0 & auxInt 196 {name: "OR", argLength: 2, reg: gp21, asm: "ORR", commutative: true}, // arg0 | arg1 197 {name: "ORconst", argLength: 1, reg: gp11, asm: "ORR", aux: "Int64"}, // arg0 | auxInt 198 {name: "XOR", argLength: 2, reg: gp21, asm: "EOR", commutative: true}, // arg0 ^ arg1 199 {name: "XORconst", argLength: 1, reg: gp11, asm: "EOR", aux: "Int64"}, // arg0 ^ auxInt 200 {name: "BIC", argLength: 2, reg: gp21, asm: "BIC"}, // arg0 &^ arg1 201 {name: "BICconst", argLength: 1, reg: gp11, asm: "BIC", aux: "Int64"}, // arg0 &^ auxInt 202 203 // unary ops 204 {name: "MVN", argLength: 1, reg: gp11, asm: "MVN"}, // ^arg0 205 {name: "NEG", argLength: 1, reg: gp11, asm: "NEG"}, // -arg0 206 {name: "FNEGS", argLength: 1, reg: fp11, asm: "FNEGS"}, // -arg0, float32 207 {name: "FNEGD", argLength: 1, reg: fp11, asm: "FNEGD"}, // -arg0, float64 208 {name: "FSQRTD", argLength: 1, reg: fp11, asm: "FSQRTD"}, // sqrt(arg0), float64 209 {name: "REV", argLength: 1, reg: gp11, asm: "REV"}, // byte reverse, 64-bit 210 {name: "REVW", argLength: 1, reg: gp11, asm: "REVW"}, // byte reverse, 32-bit 211 {name: "REV16W", argLength: 1, reg: gp11, asm: "REV16W"}, // byte reverse in each 16-bit halfword, 32-bit 212 213 // shifts 214 {name: "SLL", argLength: 2, reg: gp21, asm: "LSL"}, // arg0 << arg1, shift amount is mod 64 215 {name: "SLLconst", argLength: 1, reg: gp11, asm: "LSL", aux: "Int64"}, // arg0 << auxInt 216 {name: "SRL", argLength: 2, reg: gp21, asm: "LSR"}, // arg0 >> arg1, unsigned, shift amount is mod 64 217 {name: "SRLconst", argLength: 1, reg: gp11, asm: "LSR", aux: "Int64"}, // arg0 >> auxInt, unsigned 218 {name: "SRA", argLength: 2, reg: gp21, asm: "ASR"}, // arg0 >> arg1, signed, shift amount is mod 64 219 {name: "SRAconst", argLength: 1, reg: gp11, asm: "ASR", aux: "Int64"}, // arg0 >> auxInt, signed 220 {name: "RORconst", argLength: 1, reg: gp11, asm: "ROR", aux: "Int64"}, // arg0 right rotate by auxInt bits 221 {name: "RORWconst", argLength: 1, reg: gp11, asm: "RORW", aux: "Int64"}, // uint32(arg0) right rotate by auxInt bits 222 223 // comparisons 224 {name: "CMP", argLength: 2, reg: gp2flags, asm: "CMP", typ: "Flags"}, // arg0 compare to arg1 225 {name: "CMPconst", argLength: 1, reg: gp1flags, asm: "CMP", aux: "Int64", typ: "Flags"}, // arg0 compare to auxInt 226 {name: "CMPW", argLength: 2, reg: gp2flags, asm: "CMPW", typ: "Flags"}, // arg0 compare to arg1, 32 bit 227 {name: "CMPWconst", argLength: 1, reg: gp1flags, asm: "CMPW", aux: "Int32", typ: "Flags"}, // arg0 compare to auxInt, 32 bit 228 {name: "CMN", argLength: 2, reg: gp2flags, asm: "CMN", typ: "Flags"}, // arg0 compare to -arg1 229 {name: "CMNconst", argLength: 1, reg: gp1flags, asm: "CMN", aux: "Int64", typ: "Flags"}, // arg0 compare to -auxInt 230 {name: "CMNW", argLength: 2, reg: gp2flags, asm: "CMNW", typ: "Flags"}, // arg0 compare to -arg1, 32 bit 231 {name: "CMNWconst", argLength: 1, reg: gp1flags, asm: "CMNW", aux: "Int32", typ: "Flags"}, // arg0 compare to -auxInt, 32 bit 232 {name: "FCMPS", argLength: 2, reg: fp2flags, asm: "FCMPS", typ: "Flags"}, // arg0 compare to arg1, float32 233 {name: "FCMPD", argLength: 2, reg: fp2flags, asm: "FCMPD", typ: "Flags"}, // arg0 compare to arg1, float64 234 235 // shifted ops 236 {name: "ADDshiftLL", argLength: 2, reg: gp21, asm: "ADD", aux: "Int64"}, // arg0 + arg1<<auxInt 237 {name: "ADDshiftRL", argLength: 2, reg: gp21, asm: "ADD", aux: "Int64"}, // arg0 + arg1>>auxInt, unsigned shift 238 {name: "ADDshiftRA", argLength: 2, reg: gp21, asm: "ADD", aux: "Int64"}, // arg0 + arg1>>auxInt, signed shift 239 {name: "SUBshiftLL", argLength: 2, reg: gp21, asm: "SUB", aux: "Int64"}, // arg0 - arg1<<auxInt 240 {name: "SUBshiftRL", argLength: 2, reg: gp21, asm: "SUB", aux: "Int64"}, // arg0 - arg1>>auxInt, unsigned shift 241 {name: "SUBshiftRA", argLength: 2, reg: gp21, asm: "SUB", aux: "Int64"}, // arg0 - arg1>>auxInt, signed shift 242 {name: "ANDshiftLL", argLength: 2, reg: gp21, asm: "AND", aux: "Int64"}, // arg0 & (arg1<<auxInt) 243 {name: "ANDshiftRL", argLength: 2, reg: gp21, asm: "AND", aux: "Int64"}, // arg0 & (arg1>>auxInt), unsigned shift 244 {name: "ANDshiftRA", argLength: 2, reg: gp21, asm: "AND", aux: "Int64"}, // arg0 & (arg1>>auxInt), signed shift 245 {name: "ORshiftLL", argLength: 2, reg: gp21, asm: "ORR", aux: "Int64"}, // arg0 | arg1<<auxInt 246 {name: "ORshiftRL", argLength: 2, reg: gp21, asm: "ORR", aux: "Int64"}, // arg0 | arg1>>auxInt, unsigned shift 247 {name: "ORshiftRA", argLength: 2, reg: gp21, asm: "ORR", aux: "Int64"}, // arg0 | arg1>>auxInt, signed shift 248 {name: "XORshiftLL", argLength: 2, reg: gp21, asm: "EOR", aux: "Int64"}, // arg0 ^ arg1<<auxInt 249 {name: "XORshiftRL", argLength: 2, reg: gp21, asm: "EOR", aux: "Int64"}, // arg0 ^ arg1>>auxInt, unsigned shift 250 {name: "XORshiftRA", argLength: 2, reg: gp21, asm: "EOR", aux: "Int64"}, // arg0 ^ arg1>>auxInt, signed shift 251 {name: "BICshiftLL", argLength: 2, reg: gp21, asm: "BIC", aux: "Int64"}, // arg0 &^ (arg1<<auxInt) 252 {name: "BICshiftRL", argLength: 2, reg: gp21, asm: "BIC", aux: "Int64"}, // arg0 &^ (arg1>>auxInt), unsigned shift 253 {name: "BICshiftRA", argLength: 2, reg: gp21, asm: "BIC", aux: "Int64"}, // arg0 &^ (arg1>>auxInt), signed shift 254 {name: "CMPshiftLL", argLength: 2, reg: gp2flags, asm: "CMP", aux: "Int64", typ: "Flags"}, // arg0 compare to arg1<<auxInt 255 {name: "CMPshiftRL", argLength: 2, reg: gp2flags, asm: "CMP", aux: "Int64", typ: "Flags"}, // arg0 compare to arg1>>auxInt, unsigned shift 256 {name: "CMPshiftRA", argLength: 2, reg: gp2flags, asm: "CMP", aux: "Int64", typ: "Flags"}, // arg0 compare to arg1>>auxInt, signed shift 257 258 // moves 259 {name: "MOVDconst", argLength: 0, reg: gp01, aux: "Int64", asm: "MOVD", typ: "UInt64", rematerializeable: true}, // 32 low bits of auxint 260 {name: "FMOVSconst", argLength: 0, reg: fp01, aux: "Float64", asm: "FMOVS", typ: "Float32", rematerializeable: true}, // auxint as 64-bit float, convert to 32-bit float 261 {name: "FMOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "FMOVD", typ: "Float64", rematerializeable: true}, // auxint as 64-bit float 262 263 {name: "MOVDaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP") | buildReg("SB")}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVD", rematerializeable: true}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB 264 265 {name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8"}, // load from arg0 + auxInt + aux. arg1=mem. 266 {name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8"}, // load from arg0 + auxInt + aux. arg1=mem. 267 {name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16"}, // load from arg0 + auxInt + aux. arg1=mem. 268 {name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16"}, // load from arg0 + auxInt + aux. arg1=mem. 269 {name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "Int32"}, // load from arg0 + auxInt + aux. arg1=mem. 270 {name: "MOVWUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVWU", typ: "UInt32"}, // load from arg0 + auxInt + aux. arg1=mem. 271 {name: "MOVDload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVD", typ: "UInt64"}, // load from arg0 + auxInt + aux. arg1=mem. 272 {name: "FMOVSload", argLength: 2, reg: fpload, aux: "SymOff", asm: "FMOVS", typ: "Float32"}, // load from arg0 + auxInt + aux. arg1=mem. 273 {name: "FMOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "FMOVD", typ: "Float64"}, // load from arg0 + auxInt + aux. arg1=mem. 274 275 {name: "MOVBstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVB", typ: "Mem"}, // store 1 byte of arg1 to arg0 + auxInt + aux. arg2=mem. 276 {name: "MOVHstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVH", typ: "Mem"}, // store 2 bytes of arg1 to arg0 + auxInt + aux. arg2=mem. 277 {name: "MOVWstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVW", typ: "Mem"}, // store 4 bytes of arg1 to arg0 + auxInt + aux. arg2=mem. 278 {name: "MOVDstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVD", typ: "Mem"}, // store 8 bytes of arg1 to arg0 + auxInt + aux. arg2=mem. 279 {name: "FMOVSstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "FMOVS", typ: "Mem"}, // store 4 bytes of arg1 to arg0 + auxInt + aux. arg2=mem. 280 {name: "FMOVDstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "FMOVD", typ: "Mem"}, // store 8 bytes of arg1 to arg0 + auxInt + aux. arg2=mem. 281 282 {name: "MOVBstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVB", typ: "Mem"}, // store 1 byte of zero to arg0 + auxInt + aux. arg1=mem. 283 {name: "MOVHstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVH", typ: "Mem"}, // store 2 bytes of zero to arg0 + auxInt + aux. arg1=mem. 284 {name: "MOVWstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVW", typ: "Mem"}, // store 4 bytes of zero to arg0 + auxInt + aux. arg1=mem. 285 {name: "MOVDstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVD", typ: "Mem"}, // store 8 bytes of zero to arg0 + auxInt + aux. ar12=mem. 286 287 // conversions 288 {name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB"}, // move from arg0, sign-extended from byte 289 {name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU"}, // move from arg0, unsign-extended from byte 290 {name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH"}, // move from arg0, sign-extended from half 291 {name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU"}, // move from arg0, unsign-extended from half 292 {name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW"}, // move from arg0, sign-extended from word 293 {name: "MOVWUreg", argLength: 1, reg: gp11, asm: "MOVWU"}, // move from arg0, unsign-extended from word 294 {name: "MOVDreg", argLength: 1, reg: gp11, asm: "MOVD"}, // move from arg0 295 296 {name: "MOVDnop", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}, resultInArg0: true}, // nop, return arg0 in same register 297 298 {name: "SCVTFWS", argLength: 1, reg: gpfp, asm: "SCVTFWS"}, // int32 -> float32 299 {name: "SCVTFWD", argLength: 1, reg: gpfp, asm: "SCVTFWD"}, // int32 -> float64 300 {name: "UCVTFWS", argLength: 1, reg: gpfp, asm: "UCVTFWS"}, // uint32 -> float32 301 {name: "UCVTFWD", argLength: 1, reg: gpfp, asm: "UCVTFWD"}, // uint32 -> float64 302 {name: "SCVTFS", argLength: 1, reg: gpfp, asm: "SCVTFS"}, // int64 -> float32 303 {name: "SCVTFD", argLength: 1, reg: gpfp, asm: "SCVTFD"}, // int64 -> float64 304 {name: "UCVTFS", argLength: 1, reg: gpfp, asm: "UCVTFS"}, // uint64 -> float32 305 {name: "UCVTFD", argLength: 1, reg: gpfp, asm: "UCVTFD"}, // uint64 -> float64 306 {name: "FCVTZSSW", argLength: 1, reg: fpgp, asm: "FCVTZSSW"}, // float32 -> int32 307 {name: "FCVTZSDW", argLength: 1, reg: fpgp, asm: "FCVTZSDW"}, // float64 -> int32 308 {name: "FCVTZUSW", argLength: 1, reg: fpgp, asm: "FCVTZUSW"}, // float32 -> uint32 309 {name: "FCVTZUDW", argLength: 1, reg: fpgp, asm: "FCVTZUDW"}, // float64 -> uint32 310 {name: "FCVTZSS", argLength: 1, reg: fpgp, asm: "FCVTZSS"}, // float32 -> int64 311 {name: "FCVTZSD", argLength: 1, reg: fpgp, asm: "FCVTZSD"}, // float64 -> int64 312 {name: "FCVTZUS", argLength: 1, reg: fpgp, asm: "FCVTZUS"}, // float32 -> uint64 313 {name: "FCVTZUD", argLength: 1, reg: fpgp, asm: "FCVTZUD"}, // float64 -> uint64 314 {name: "FCVTSD", argLength: 1, reg: fp11, asm: "FCVTSD"}, // float32 -> float64 315 {name: "FCVTDS", argLength: 1, reg: fp11, asm: "FCVTDS"}, // float64 -> float32 316 317 // conditional instructions 318 {name: "CSELULT", argLength: 3, reg: gp2flags1, asm: "CSEL"}, // returns arg0 if flags indicates unsigned LT, arg1 otherwise, arg2=flags 319 {name: "CSELULT0", argLength: 2, reg: gp1flags1, asm: "CSEL"}, // returns arg0 if flags indicates unsigned LT, 0 otherwise, arg1=flags 320 321 // function calls 322 {name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true}, // call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem 323 {name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("R26"), 0}, clobbers: callerSave}, aux: "Int64", clobberFlags: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem 324 {name: "CALLdefer", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true}, // call deferproc. arg0=mem, auxint=argsize, returns mem 325 {name: "CALLgo", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true}, // call newproc. arg0=mem, auxint=argsize, returns mem 326 {name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int64", clobberFlags: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem 327 328 // pseudo-ops 329 {name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}}, // panic if arg0 is nil. arg1=mem. 330 331 {name: "Equal", argLength: 1, reg: readflags}, // bool, true flags encode x==y false otherwise. 332 {name: "NotEqual", argLength: 1, reg: readflags}, // bool, true flags encode x!=y false otherwise. 333 {name: "LessThan", argLength: 1, reg: readflags}, // bool, true flags encode signed x<y false otherwise. 334 {name: "LessEqual", argLength: 1, reg: readflags}, // bool, true flags encode signed x<=y false otherwise. 335 {name: "GreaterThan", argLength: 1, reg: readflags}, // bool, true flags encode signed x>y false otherwise. 336 {name: "GreaterEqual", argLength: 1, reg: readflags}, // bool, true flags encode signed x>=y false otherwise. 337 {name: "LessThanU", argLength: 1, reg: readflags}, // bool, true flags encode unsigned x<y false otherwise. 338 {name: "LessEqualU", argLength: 1, reg: readflags}, // bool, true flags encode unsigned x<=y false otherwise. 339 {name: "GreaterThanU", argLength: 1, reg: readflags}, // bool, true flags encode unsigned x>y false otherwise. 340 {name: "GreaterEqualU", argLength: 1, reg: readflags}, // bool, true flags encode unsigned x>=y false otherwise. 341 342 // duffzero 343 // arg0 = address of memory to zero 344 // arg1 = mem 345 // auxint = offset into duffzero code to start executing 346 // returns mem 347 // R16 aka arm64.REGRT1 changed as side effect 348 { 349 name: "DUFFZERO", 350 aux: "Int64", 351 argLength: 2, 352 reg: regInfo{ 353 inputs: []regMask{gp}, 354 clobbers: buildReg("R16"), 355 }, 356 }, 357 358 // large zeroing 359 // arg0 = address of memory to zero (in R16 aka arm64.REGRT1, changed as side effect) 360 // arg1 = address of the last element to zero 361 // arg2 = mem 362 // returns mem 363 // MOVD.P ZR, 8(R16) 364 // CMP Rarg1, R16 365 // BLE -2(PC) 366 // Note: the-end-of-the-memory may be not a valid pointer. it's a problem if it is spilled. 367 // the-end-of-the-memory - 8 is with the area to zero, ok to spill. 368 { 369 name: "LoweredZero", 370 argLength: 3, 371 reg: regInfo{ 372 inputs: []regMask{buildReg("R16"), gp}, 373 clobbers: buildReg("R16"), 374 }, 375 clobberFlags: true, 376 }, 377 378 // large move 379 // arg0 = address of dst memory (in R17 aka arm64.REGRT2, changed as side effect) 380 // arg1 = address of src memory (in R16 aka arm64.REGRT1, changed as side effect) 381 // arg2 = address of the last element of src 382 // arg3 = mem 383 // returns mem 384 // MOVD.P 8(R16), Rtmp 385 // MOVD.P Rtmp, 8(R17) 386 // CMP Rarg2, R16 387 // BLE -3(PC) 388 // Note: the-end-of-src may be not a valid pointer. it's a problem if it is spilled. 389 // the-end-of-src - 8 is within the area to copy, ok to spill. 390 { 391 name: "LoweredMove", 392 argLength: 4, 393 reg: regInfo{ 394 inputs: []regMask{buildReg("R17"), buildReg("R16"), gp}, 395 clobbers: buildReg("R16 R17"), 396 }, 397 clobberFlags: true, 398 }, 399 400 // Scheduler ensures LoweredGetClosurePtr occurs only in entry block, 401 // and sorts it to the very beginning of the block to prevent other 402 // use of R26 (arm64.REGCTXT, the closure pointer) 403 {name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{buildReg("R26")}}}, 404 405 // MOVDconvert converts between pointers and integers. 406 // We have a special op for this so as to not confuse GC 407 // (particularly stack maps). It takes a memory arg so it 408 // gets correctly ordered with respect to GC safepoints. 409 // arg0=ptr/int arg1=mem, output=int/ptr 410 {name: "MOVDconvert", argLength: 2, reg: gp11, asm: "MOVD"}, 411 412 // Constant flag values. For any comparison, there are 5 possible 413 // outcomes: the three from the signed total order (<,==,>) and the 414 // three from the unsigned total order. The == cases overlap. 415 // Note: there's a sixth "unordered" outcome for floating-point 416 // comparisons, but we don't use such a beast yet. 417 // These ops are for temporary use by rewrite rules. They 418 // cannot appear in the generated assembly. 419 {name: "FlagEQ"}, // equal 420 {name: "FlagLT_ULT"}, // signed < and unsigned < 421 {name: "FlagLT_UGT"}, // signed < and unsigned > 422 {name: "FlagGT_UGT"}, // signed > and unsigned < 423 {name: "FlagGT_ULT"}, // signed > and unsigned > 424 425 // (InvertFlags (CMP a b)) == (CMP b a) 426 // InvertFlags is a pseudo-op which can't appear in assembly output. 427 {name: "InvertFlags", argLength: 1}, // reverse direction of arg0 428 } 429 430 blocks := []blockData{ 431 {name: "EQ"}, 432 {name: "NE"}, 433 {name: "LT"}, 434 {name: "LE"}, 435 {name: "GT"}, 436 {name: "GE"}, 437 {name: "ULT"}, 438 {name: "ULE"}, 439 {name: "UGT"}, 440 {name: "UGE"}, 441 } 442 443 archs = append(archs, arch{ 444 name: "ARM64", 445 pkg: "cmd/internal/obj/arm64", 446 genfile: "../../arm64/ssa.go", 447 ops: ops, 448 blocks: blocks, 449 regnames: regNamesARM64, 450 gpregmask: gp, 451 fpregmask: fp, 452 framepointerreg: -1, // not used 453 }) 454 }