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 5package main 6 7import ( 8 "fmt" 9) 10 11// Notes: 12// - Boolean types occupy the entire register. 0=false, 1=true. 13 14// Suffixes encode the bit width of various instructions: 15// 16// D (double word) = 64 bit int 17// W (word) = 32 bit int 18// H (half word) = 16 bit int 19// B (byte) = 8 bit int 20// S (single) = 32 bit float 21// D (double) = 64 bit float 22// L = 64 bit int, used when the opcode starts with F 23 24const ( 25 riscv64REG_G = 27 26 riscv64REG_CTXT = 26 27 riscv64REG_LR = 1 28 riscv64REG_SP = 2 29 riscv64REG_GP = 3 30 riscv64REG_TP = 4 31 riscv64REG_TMP = 31 32 riscv64REG_ZERO = 0 33) 34 35func riscv64RegName(r int) string { 36 switch { 37 case r == riscv64REG_G: 38 return "g" 39 case r == riscv64REG_SP: 40 return "SP" 41 case 0 <= r && r <= 31: 42 return fmt.Sprintf("X%d", r) 43 case 32 <= r && r <= 63: 44 return fmt.Sprintf("F%d", r-32) 45 default: 46 panic(fmt.Sprintf("unknown register %d", r)) 47 } 48} 49 50func init() { 51 var regNamesRISCV64 []string 52 var gpMask, fpMask, gpgMask, gpspMask, gpspsbMask, gpspsbgMask regMask 53 regNamed := make(map[string]regMask) 54 55 // Build the list of register names, creating an appropriately indexed 56 // regMask for the gp and fp registers as we go. 57 // 58 // If name is specified, use it rather than the riscv reg number. 59 addreg := func(r int, name string) regMask { 60 mask := regMask(1) << uint(len(regNamesRISCV64)) 61 if name == "" { 62 name = riscv64RegName(r) 63 } 64 regNamesRISCV64 = append(regNamesRISCV64, name) 65 regNamed[name] = mask 66 return mask 67 } 68 69 // General purpose registers. 70 for r := 0; r <= 31; r++ { 71 if r == riscv64REG_LR { 72 // LR is not used by regalloc, so we skip it to leave 73 // room for pseudo-register SB. 74 continue 75 } 76 77 mask := addreg(r, "") 78 79 // Add general purpose registers to gpMask. 80 switch r { 81 // ZERO, GP, TP and TMP are not in any gp mask. 82 case riscv64REG_ZERO, riscv64REG_GP, riscv64REG_TP, riscv64REG_TMP: 83 case riscv64REG_G: 84 gpgMask |= mask 85 gpspsbgMask |= mask 86 case riscv64REG_SP: 87 gpspMask |= mask 88 gpspsbMask |= mask 89 gpspsbgMask |= mask 90 default: 91 gpMask |= mask 92 gpgMask |= mask 93 gpspMask |= mask 94 gpspsbMask |= mask 95 gpspsbgMask |= mask 96 } 97 } 98 99 // Floating pointer registers. 100 for r := 32; r <= 63; r++ { 101 mask := addreg(r, "") 102 fpMask |= mask 103 } 104 105 // Pseudo-register: SB 106 mask := addreg(-1, "SB") 107 gpspsbMask |= mask 108 gpspsbgMask |= mask 109 110 if len(regNamesRISCV64) > 64 { 111 // regMask is only 64 bits. 112 panic("Too many RISCV64 registers") 113 } 114 115 regCtxt := regNamed["X26"] 116 callerSave := gpMask | fpMask | regNamed["g"] 117 118 var ( 119 gpstore = regInfo{inputs: []regMask{gpspsbMask, gpspMask, 0}} // SB in first input so we can load from a global, but not in second to avoid using SB as a temporary register 120 gpstore0 = regInfo{inputs: []regMask{gpspsbMask}} 121 gp01 = regInfo{outputs: []regMask{gpMask}} 122 gp11 = regInfo{inputs: []regMask{gpMask}, outputs: []regMask{gpMask}} 123 gp21 = regInfo{inputs: []regMask{gpMask, gpMask}, outputs: []regMask{gpMask}} 124 gp22 = regInfo{inputs: []regMask{gpMask, gpMask}, outputs: []regMask{gpMask, gpMask}} 125 gpload = regInfo{inputs: []regMask{gpspsbMask, 0}, outputs: []regMask{gpMask}} 126 gp11sb = regInfo{inputs: []regMask{gpspsbMask}, outputs: []regMask{gpMask}} 127 gpxchg = regInfo{inputs: []regMask{gpspsbgMask, gpgMask}, outputs: []regMask{gpMask}} 128 gpcas = regInfo{inputs: []regMask{gpspsbgMask, gpgMask, gpgMask}, outputs: []regMask{gpMask}} 129 gpatomic = regInfo{inputs: []regMask{gpspsbgMask, gpgMask}} 130 131 fp11 = regInfo{inputs: []regMask{fpMask}, outputs: []regMask{fpMask}} 132 fp21 = regInfo{inputs: []regMask{fpMask, fpMask}, outputs: []regMask{fpMask}} 133 fp31 = regInfo{inputs: []regMask{fpMask, fpMask, fpMask}, outputs: []regMask{fpMask}} 134 gpfp = regInfo{inputs: []regMask{gpMask}, outputs: []regMask{fpMask}} 135 fpgp = regInfo{inputs: []regMask{fpMask}, outputs: []regMask{gpMask}} 136 fpstore = regInfo{inputs: []regMask{gpspsbMask, fpMask, 0}} 137 fpload = regInfo{inputs: []regMask{gpspsbMask, 0}, outputs: []regMask{fpMask}} 138 fp2gp = regInfo{inputs: []regMask{fpMask, fpMask}, outputs: []regMask{gpMask}} 139 140 call = regInfo{clobbers: callerSave} 141 callClosure = regInfo{inputs: []regMask{gpspMask, regCtxt, 0}, clobbers: callerSave} 142 callInter = regInfo{inputs: []regMask{gpMask}, clobbers: callerSave} 143 ) 144 145 RISCV64ops := []opData{ 146 {name: "ADD", argLength: 2, reg: gp21, asm: "ADD", commutative: true}, // arg0 + arg1 147 {name: "ADDI", argLength: 1, reg: gp11sb, asm: "ADDI", aux: "Int64"}, // arg0 + auxint 148 {name: "ADDIW", argLength: 1, reg: gp11, asm: "ADDIW", aux: "Int64"}, // 32 low bits of arg0 + auxint, sign extended to 64 bits 149 {name: "NEG", argLength: 1, reg: gp11, asm: "NEG"}, // -arg0 150 {name: "NEGW", argLength: 1, reg: gp11, asm: "NEGW"}, // -arg0 of 32 bits, sign extended to 64 bits 151 {name: "SUB", argLength: 2, reg: gp21, asm: "SUB"}, // arg0 - arg1 152 {name: "SUBW", argLength: 2, reg: gp21, asm: "SUBW"}, // 32 low bits of arg 0 - 32 low bits of arg 1, sign extended to 64 bits 153 154 // M extension. H means high (i.e., it returns the top bits of 155 // the result). U means unsigned. W means word (i.e., 32-bit). 156 {name: "MUL", argLength: 2, reg: gp21, asm: "MUL", commutative: true, typ: "Int64"}, // arg0 * arg1 157 {name: "MULW", argLength: 2, reg: gp21, asm: "MULW", commutative: true, typ: "Int32"}, 158 {name: "MULH", argLength: 2, reg: gp21, asm: "MULH", commutative: true, typ: "Int64"}, 159 {name: "MULHU", argLength: 2, reg: gp21, asm: "MULHU", commutative: true, typ: "UInt64"}, 160 {name: "LoweredMuluhilo", argLength: 2, reg: gp22, resultNotInArgs: true}, // arg0 * arg1, return (hi, lo) 161 {name: "LoweredMuluover", argLength: 2, reg: gp22, resultNotInArgs: true}, // arg0 * arg1, return (64 bits of arg0*arg1, overflow) 162 163 {name: "DIV", argLength: 2, reg: gp21, asm: "DIV", typ: "Int64"}, // arg0 / arg1 164 {name: "DIVU", argLength: 2, reg: gp21, asm: "DIVU", typ: "UInt64"}, 165 {name: "DIVW", argLength: 2, reg: gp21, asm: "DIVW", typ: "Int32"}, 166 {name: "DIVUW", argLength: 2, reg: gp21, asm: "DIVUW", typ: "UInt32"}, 167 {name: "REM", argLength: 2, reg: gp21, asm: "REM", typ: "Int64"}, // arg0 % arg1 168 {name: "REMU", argLength: 2, reg: gp21, asm: "REMU", typ: "UInt64"}, 169 {name: "REMW", argLength: 2, reg: gp21, asm: "REMW", typ: "Int32"}, 170 {name: "REMUW", argLength: 2, reg: gp21, asm: "REMUW", typ: "UInt32"}, 171 172 {name: "MOVaddr", argLength: 1, reg: gp11sb, asm: "MOV", aux: "SymOff", rematerializeable: true, symEffect: "Addr"}, // arg0 + auxint + offset encoded in aux 173 // auxint+aux == add auxint and the offset of the symbol in aux (if any) to the effective address 174 175 {name: "MOVDconst", reg: gp01, asm: "MOV", typ: "UInt64", aux: "Int64", rematerializeable: true}, // auxint 176 177 // Loads: load <size> bits from arg0+auxint+aux and extend to 64 bits; arg1=mem 178 {name: "MOVBload", argLength: 2, reg: gpload, asm: "MOVB", aux: "SymOff", typ: "Int8", faultOnNilArg0: true, symEffect: "Read"}, // 8 bits, sign extend 179 {name: "MOVHload", argLength: 2, reg: gpload, asm: "MOVH", aux: "SymOff", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"}, // 16 bits, sign extend 180 {name: "MOVWload", argLength: 2, reg: gpload, asm: "MOVW", aux: "SymOff", typ: "Int32", faultOnNilArg0: true, symEffect: "Read"}, // 32 bits, sign extend 181 {name: "MOVDload", argLength: 2, reg: gpload, asm: "MOV", aux: "SymOff", typ: "Int64", faultOnNilArg0: true, symEffect: "Read"}, // 64 bits 182 {name: "MOVBUload", argLength: 2, reg: gpload, asm: "MOVBU", aux: "SymOff", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"}, // 8 bits, zero extend 183 {name: "MOVHUload", argLength: 2, reg: gpload, asm: "MOVHU", aux: "SymOff", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // 16 bits, zero extend 184 {name: "MOVWUload", argLength: 2, reg: gpload, asm: "MOVWU", aux: "SymOff", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"}, // 32 bits, zero extend 185 186 // Stores: store <size> lowest bits in arg1 to arg0+auxint+aux; arg2=mem 187 {name: "MOVBstore", argLength: 3, reg: gpstore, asm: "MOVB", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 8 bits 188 {name: "MOVHstore", argLength: 3, reg: gpstore, asm: "MOVH", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 16 bits 189 {name: "MOVWstore", argLength: 3, reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 32 bits 190 {name: "MOVDstore", argLength: 3, reg: gpstore, asm: "MOV", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 64 bits 191 192 // Stores: store <size> of zero in arg0+auxint+aux; arg1=mem 193 {name: "MOVBstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 8 bits 194 {name: "MOVHstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 16 bits 195 {name: "MOVWstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 32 bits 196 {name: "MOVDstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOV", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 64 bits 197 198 // Conversions 199 {name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB"}, // move from arg0, sign-extended from byte 200 {name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH"}, // move from arg0, sign-extended from half 201 {name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW"}, // move from arg0, sign-extended from word 202 {name: "MOVDreg", argLength: 1, reg: gp11, asm: "MOV"}, // move from arg0 203 {name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU"}, // move from arg0, unsign-extended from byte 204 {name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU"}, // move from arg0, unsign-extended from half 205 {name: "MOVWUreg", argLength: 1, reg: gp11, asm: "MOVWU"}, // move from arg0, unsign-extended from word 206 207 {name: "MOVDnop", argLength: 1, reg: regInfo{inputs: []regMask{gpMask}, outputs: []regMask{gpMask}}, resultInArg0: true}, // nop, return arg0 in same register 208 209 // Shift ops 210 {name: "SLL", argLength: 2, reg: gp21, asm: "SLL"}, // arg0 << (aux1 & 63), logical left shift 211 {name: "SLLW", argLength: 2, reg: gp21, asm: "SLLW"}, // arg0 << (aux1 & 31), logical left shift of 32 bit value, sign extended to 64 bits 212 {name: "SRA", argLength: 2, reg: gp21, asm: "SRA"}, // arg0 >> (aux1 & 63), arithmetic right shift 213 {name: "SRAW", argLength: 2, reg: gp21, asm: "SRAW"}, // arg0 >> (aux1 & 31), arithmetic right shift of 32 bit value, sign extended to 64 bits 214 {name: "SRL", argLength: 2, reg: gp21, asm: "SRL"}, // arg0 >> (aux1 & 63), logical right shift 215 {name: "SRLW", argLength: 2, reg: gp21, asm: "SRLW"}, // arg0 >> (aux1 & 31), logical right shift of 32 bit value, sign extended to 64 bits 216 {name: "SLLI", argLength: 1, reg: gp11, asm: "SLLI", aux: "Int64"}, // arg0 << auxint, shift amount 0-63, logical left shift 217 {name: "SLLIW", argLength: 1, reg: gp11, asm: "SLLIW", aux: "Int64"}, // arg0 << auxint, shift amount 0-31, logical left shift of 32 bit value, sign extended to 64 bits 218 {name: "SRAI", argLength: 1, reg: gp11, asm: "SRAI", aux: "Int64"}, // arg0 >> auxint, shift amount 0-63, arithmetic right shift 219 {name: "SRAIW", argLength: 1, reg: gp11, asm: "SRAIW", aux: "Int64"}, // arg0 >> auxint, shift amount 0-31, arithmetic right shift of 32 bit value, sign extended to 64 bits 220 {name: "SRLI", argLength: 1, reg: gp11, asm: "SRLI", aux: "Int64"}, // arg0 >> auxint, shift amount 0-63, logical right shift 221 {name: "SRLIW", argLength: 1, reg: gp11, asm: "SRLIW", aux: "Int64"}, // arg0 >> auxint, shift amount 0-31, logical right shift of 32 bit value, sign extended to 64 bits 222 223 // Bitwise ops 224 {name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true}, // arg0 & arg1 225 {name: "ANDI", argLength: 1, reg: gp11, asm: "ANDI", aux: "Int64"}, // arg0 & auxint 226 {name: "NOT", argLength: 1, reg: gp11, asm: "NOT"}, // ^arg0 227 {name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true}, // arg0 | arg1 228 {name: "ORI", argLength: 1, reg: gp11, asm: "ORI", aux: "Int64"}, // arg0 | auxint 229 {name: "ROL", argLength: 2, reg: gp21, asm: "ROL"}, // rotate left arg0 by (arg1 & 63) 230 {name: "ROLW", argLength: 2, reg: gp21, asm: "ROLW"}, // rotate left least significant word of arg0 by (arg1 & 31), sign extended 231 {name: "ROR", argLength: 2, reg: gp21, asm: "ROR"}, // rotate right arg0 by (arg1 & 63) 232 {name: "RORI", argLength: 1, reg: gp11, asm: "RORI", aux: "Int64"}, // rotate right arg0 by auxint, shift amount 0-63 233 {name: "RORIW", argLength: 1, reg: gp11, asm: "RORIW", aux: "Int64"}, // rotate right least significant word of arg0 by auxint, shift amount 0-31, sign extended 234 {name: "RORW", argLength: 2, reg: gp21, asm: "RORW"}, // rotate right least significant word of arg0 by (arg1 & 31), sign extended 235 {name: "XOR", argLength: 2, reg: gp21, asm: "XOR", commutative: true}, // arg0 ^ arg1 236 {name: "XORI", argLength: 1, reg: gp11, asm: "XORI", aux: "Int64"}, // arg0 ^ auxint 237 238 // Generate boolean values 239 {name: "SEQZ", argLength: 1, reg: gp11, asm: "SEQZ"}, // arg0 == 0, result is 0 or 1 240 {name: "SNEZ", argLength: 1, reg: gp11, asm: "SNEZ"}, // arg0 != 0, result is 0 or 1 241 {name: "SLT", argLength: 2, reg: gp21, asm: "SLT"}, // arg0 < arg1, result is 0 or 1 242 {name: "SLTI", argLength: 1, reg: gp11, asm: "SLTI", aux: "Int64"}, // arg0 < auxint, result is 0 or 1 243 {name: "SLTU", argLength: 2, reg: gp21, asm: "SLTU"}, // arg0 < arg1, unsigned, result is 0 or 1 244 {name: "SLTIU", argLength: 1, reg: gp11, asm: "SLTIU", aux: "Int64"}, // arg0 < auxint, unsigned, result is 0 or 1 245 246 // Round ops to block fused-multiply-add extraction. 247 {name: "LoweredRound32F", argLength: 1, reg: fp11, resultInArg0: true}, 248 {name: "LoweredRound64F", argLength: 1, reg: fp11, resultInArg0: true}, 249 250 // Calls 251 {name: "CALLstatic", argLength: -1, reg: call, aux: "CallOff", call: true}, // call static function aux.(*gc.Sym). last arg=mem, auxint=argsize, returns mem 252 {name: "CALLtail", argLength: -1, reg: call, aux: "CallOff", call: true, tailCall: true}, // tail call static function aux.(*gc.Sym). last arg=mem, auxint=argsize, returns mem 253 {name: "CALLclosure", argLength: -1, reg: callClosure, aux: "CallOff", call: true}, // call function via closure. arg0=codeptr, arg1=closure, last arg=mem, auxint=argsize, returns mem 254 {name: "CALLinter", argLength: -1, reg: callInter, aux: "CallOff", call: true}, // call fn by pointer. arg0=codeptr, last arg=mem, auxint=argsize, returns mem 255 256 // duffzero 257 // arg0 = address of memory to zero (in X25, changed as side effect) 258 // arg1 = mem 259 // auxint = offset into duffzero code to start executing 260 // X1 (link register) changed because of function call 261 // returns mem 262 { 263 name: "DUFFZERO", 264 aux: "Int64", 265 argLength: 2, 266 reg: regInfo{ 267 inputs: []regMask{regNamed["X25"]}, 268 clobbers: regNamed["X1"] | regNamed["X25"], 269 }, 270 typ: "Mem", 271 faultOnNilArg0: true, 272 }, 273 274 // duffcopy 275 // arg0 = address of dst memory (in X25, changed as side effect) 276 // arg1 = address of src memory (in X24, changed as side effect) 277 // arg2 = mem 278 // auxint = offset into duffcopy code to start executing 279 // X1 (link register) changed because of function call 280 // returns mem 281 { 282 name: "DUFFCOPY", 283 aux: "Int64", 284 argLength: 3, 285 reg: regInfo{ 286 inputs: []regMask{regNamed["X25"], regNamed["X24"]}, 287 clobbers: regNamed["X1"] | regNamed["X24"] | regNamed["X25"], 288 }, 289 typ: "Mem", 290 faultOnNilArg0: true, 291 faultOnNilArg1: true, 292 }, 293 294 // Generic moves and zeros 295 296 // general unaligned zeroing 297 // arg0 = address of memory to zero (in X5, changed as side effect) 298 // arg1 = address of the last element to zero (inclusive) 299 // arg2 = mem 300 // auxint = element size 301 // returns mem 302 // mov ZERO, (X5) 303 // ADD $sz, X5 304 // BGEU Rarg1, X5, -2(PC) 305 { 306 name: "LoweredZero", 307 aux: "Int64", 308 argLength: 3, 309 reg: regInfo{ 310 inputs: []regMask{regNamed["X5"], gpMask}, 311 clobbers: regNamed["X5"], 312 }, 313 typ: "Mem", 314 faultOnNilArg0: true, 315 }, 316 317 // general unaligned move 318 // arg0 = address of dst memory (in X5, changed as side effect) 319 // arg1 = address of src memory (in X6, changed as side effect) 320 // arg2 = address of the last element of src (can't be X7 as we clobber it before using arg2) 321 // arg3 = mem 322 // auxint = alignment 323 // clobbers X7 as a tmp register. 324 // returns mem 325 // mov (X6), X7 326 // mov X7, (X5) 327 // ADD $sz, X5 328 // ADD $sz, X6 329 // BGEU Rarg2, X5, -4(PC) 330 { 331 name: "LoweredMove", 332 aux: "Int64", 333 argLength: 4, 334 reg: regInfo{ 335 inputs: []regMask{regNamed["X5"], regNamed["X6"], gpMask &^ regNamed["X7"]}, 336 clobbers: regNamed["X5"] | regNamed["X6"] | regNamed["X7"], 337 }, 338 typ: "Mem", 339 faultOnNilArg0: true, 340 faultOnNilArg1: true, 341 }, 342 343 // Atomic loads. 344 // load from arg0. arg1=mem. 345 // returns <value,memory> so they can be properly ordered with other loads. 346 {name: "LoweredAtomicLoad8", argLength: 2, reg: gpload, faultOnNilArg0: true}, 347 {name: "LoweredAtomicLoad32", argLength: 2, reg: gpload, faultOnNilArg0: true}, 348 {name: "LoweredAtomicLoad64", argLength: 2, reg: gpload, faultOnNilArg0: true}, 349 350 // Atomic stores. 351 // store arg1 to *arg0. arg2=mem. returns memory. 352 {name: "LoweredAtomicStore8", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true}, 353 {name: "LoweredAtomicStore32", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true}, 354 {name: "LoweredAtomicStore64", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true}, 355 356 // Atomic exchange. 357 // store arg1 to *arg0. arg2=mem. returns <old content of *arg0, memory>. 358 {name: "LoweredAtomicExchange32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, 359 {name: "LoweredAtomicExchange64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, 360 361 // Atomic add. 362 // *arg0 += arg1. arg2=mem. returns <new content of *arg0, memory>. 363 {name: "LoweredAtomicAdd32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, 364 {name: "LoweredAtomicAdd64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, 365 366 // Atomic compare and swap. 367 // arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory. 368 // if *arg0 == arg1 { 369 // *arg0 = arg2 370 // return (true, memory) 371 // } else { 372 // return (false, memory) 373 // } 374 // MOV $0, Rout 375 // LR (Rarg0), Rtmp 376 // BNE Rtmp, Rarg1, 3(PC) 377 // SC Rarg2, (Rarg0), Rtmp 378 // BNE Rtmp, ZERO, -3(PC) 379 // MOV $1, Rout 380 {name: "LoweredAtomicCas32", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, 381 {name: "LoweredAtomicCas64", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, 382 383 // Atomic 32 bit AND/OR. 384 // *arg0 &= (|=) arg1. arg2=mem. returns nil. 385 {name: "LoweredAtomicAnd32", argLength: 3, reg: gpatomic, asm: "AMOANDW", faultOnNilArg0: true, hasSideEffects: true}, 386 {name: "LoweredAtomicOr32", argLength: 3, reg: gpatomic, asm: "AMOORW", faultOnNilArg0: true, hasSideEffects: true}, 387 388 // Lowering pass-throughs 389 {name: "LoweredNilCheck", argLength: 2, faultOnNilArg0: true, nilCheck: true, reg: regInfo{inputs: []regMask{gpspMask}}}, // arg0=ptr,arg1=mem, returns void. Faults if ptr is nil. 390 {name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{regCtxt}}}, // scheduler ensures only at beginning of entry block 391 392 // LoweredGetCallerSP returns the SP of the caller of the current function. arg0=mem. 393 {name: "LoweredGetCallerSP", argLength: 1, reg: gp01, rematerializeable: true}, 394 395 // LoweredGetCallerPC evaluates to the PC to which its "caller" will return. 396 // I.e., if f calls g "calls" getcallerpc, 397 // the result should be the PC within f that g will return to. 398 // See runtime/stubs.go for a more detailed discussion. 399 {name: "LoweredGetCallerPC", reg: gp01, rematerializeable: true}, 400 401 // LoweredWB invokes runtime.gcWriteBarrier. arg0=mem, auxint=# of buffer entries needed 402 // It saves all GP registers if necessary, 403 // but clobbers RA (LR) because it's a call 404 // and T6 (REG_TMP). 405 // Returns a pointer to a write barrier buffer in X24. 406 {name: "LoweredWB", argLength: 1, reg: regInfo{clobbers: (callerSave &^ (gpMask | regNamed["g"])) | regNamed["X1"], outputs: []regMask{regNamed["X24"]}}, clobberFlags: true, aux: "Int64"}, 407 408 // Do data barrier. arg0=memorys 409 {name: "LoweredPubBarrier", argLength: 1, asm: "FENCE", hasSideEffects: true}, 410 411 // There are three of these functions so that they can have three different register inputs. 412 // When we check 0 <= c <= cap (A), then 0 <= b <= c (B), then 0 <= a <= b (C), we want the 413 // default registers to match so we don't need to copy registers around unnecessarily. 414 {name: "LoweredPanicBoundsA", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{regNamed["X7"], regNamed["X28"]}}, typ: "Mem", call: true}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go). 415 {name: "LoweredPanicBoundsB", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{regNamed["X6"], regNamed["X7"]}}, typ: "Mem", call: true}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go). 416 {name: "LoweredPanicBoundsC", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{regNamed["X5"], regNamed["X6"]}}, typ: "Mem", call: true}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go). 417 418 // F extension. 419 {name: "FADDS", argLength: 2, reg: fp21, asm: "FADDS", commutative: true, typ: "Float32"}, // arg0 + arg1 420 {name: "FSUBS", argLength: 2, reg: fp21, asm: "FSUBS", commutative: false, typ: "Float32"}, // arg0 - arg1 421 {name: "FMULS", argLength: 2, reg: fp21, asm: "FMULS", commutative: true, typ: "Float32"}, // arg0 * arg1 422 {name: "FDIVS", argLength: 2, reg: fp21, asm: "FDIVS", commutative: false, typ: "Float32"}, // arg0 / arg1 423 {name: "FMADDS", argLength: 3, reg: fp31, asm: "FMADDS", commutative: true, typ: "Float32"}, // (arg0 * arg1) + arg2 424 {name: "FMSUBS", argLength: 3, reg: fp31, asm: "FMSUBS", commutative: true, typ: "Float32"}, // (arg0 * arg1) - arg2 425 {name: "FNMADDS", argLength: 3, reg: fp31, asm: "FNMADDS", commutative: true, typ: "Float32"}, // -(arg0 * arg1) + arg2 426 {name: "FNMSUBS", argLength: 3, reg: fp31, asm: "FNMSUBS", commutative: true, typ: "Float32"}, // -(arg0 * arg1) - arg2 427 {name: "FSQRTS", argLength: 1, reg: fp11, asm: "FSQRTS", typ: "Float32"}, // sqrt(arg0) 428 {name: "FNEGS", argLength: 1, reg: fp11, asm: "FNEGS", typ: "Float32"}, // -arg0 429 {name: "FMVSX", argLength: 1, reg: gpfp, asm: "FMVSX", typ: "Float32"}, // reinterpret arg0 as float 430 {name: "FCVTSW", argLength: 1, reg: gpfp, asm: "FCVTSW", typ: "Float32"}, // float32(low 32 bits of arg0) 431 {name: "FCVTSL", argLength: 1, reg: gpfp, asm: "FCVTSL", typ: "Float32"}, // float32(arg0) 432 {name: "FCVTWS", argLength: 1, reg: fpgp, asm: "FCVTWS", typ: "Int32"}, // int32(arg0) 433 {name: "FCVTLS", argLength: 1, reg: fpgp, asm: "FCVTLS", typ: "Int64"}, // int64(arg0) 434 {name: "FMOVWload", argLength: 2, reg: fpload, asm: "MOVF", aux: "SymOff", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"}, // load float32 from arg0+auxint+aux 435 {name: "FMOVWstore", argLength: 3, reg: fpstore, asm: "MOVF", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store float32 to arg0+auxint+aux 436 {name: "FEQS", argLength: 2, reg: fp2gp, asm: "FEQS", commutative: true}, // arg0 == arg1 437 {name: "FNES", argLength: 2, reg: fp2gp, asm: "FNES", commutative: true}, // arg0 != arg1 438 {name: "FLTS", argLength: 2, reg: fp2gp, asm: "FLTS"}, // arg0 < arg1 439 {name: "FLES", argLength: 2, reg: fp2gp, asm: "FLES"}, // arg0 <= arg1 440 {name: "LoweredFMAXS", argLength: 2, reg: fp21, resultNotInArgs: true, asm: "FMAXS", commutative: true, typ: "Float32"}, // max(arg0, arg1) 441 {name: "LoweredFMINS", argLength: 2, reg: fp21, resultNotInArgs: true, asm: "FMINS", commutative: true, typ: "Float32"}, // min(arg0, arg1) 442 443 // D extension. 444 {name: "FADDD", argLength: 2, reg: fp21, asm: "FADDD", commutative: true, typ: "Float64"}, // arg0 + arg1 445 {name: "FSUBD", argLength: 2, reg: fp21, asm: "FSUBD", commutative: false, typ: "Float64"}, // arg0 - arg1 446 {name: "FMULD", argLength: 2, reg: fp21, asm: "FMULD", commutative: true, typ: "Float64"}, // arg0 * arg1 447 {name: "FDIVD", argLength: 2, reg: fp21, asm: "FDIVD", commutative: false, typ: "Float64"}, // arg0 / arg1 448 {name: "FMADDD", argLength: 3, reg: fp31, asm: "FMADDD", commutative: true, typ: "Float64"}, // (arg0 * arg1) + arg2 449 {name: "FMSUBD", argLength: 3, reg: fp31, asm: "FMSUBD", commutative: true, typ: "Float64"}, // (arg0 * arg1) - arg2 450 {name: "FNMADDD", argLength: 3, reg: fp31, asm: "FNMADDD", commutative: true, typ: "Float64"}, // -(arg0 * arg1) + arg2 451 {name: "FNMSUBD", argLength: 3, reg: fp31, asm: "FNMSUBD", commutative: true, typ: "Float64"}, // -(arg0 * arg1) - arg2 452 {name: "FSQRTD", argLength: 1, reg: fp11, asm: "FSQRTD", typ: "Float64"}, // sqrt(arg0) 453 {name: "FNEGD", argLength: 1, reg: fp11, asm: "FNEGD", typ: "Float64"}, // -arg0 454 {name: "FABSD", argLength: 1, reg: fp11, asm: "FABSD", typ: "Float64"}, // abs(arg0) 455 {name: "FSGNJD", argLength: 2, reg: fp21, asm: "FSGNJD", typ: "Float64"}, // copy sign of arg1 to arg0 456 {name: "FMVDX", argLength: 1, reg: gpfp, asm: "FMVDX", typ: "Float64"}, // reinterpret arg0 as float 457 {name: "FCVTDW", argLength: 1, reg: gpfp, asm: "FCVTDW", typ: "Float64"}, // float64(low 32 bits of arg0) 458 {name: "FCVTDL", argLength: 1, reg: gpfp, asm: "FCVTDL", typ: "Float64"}, // float64(arg0) 459 {name: "FCVTWD", argLength: 1, reg: fpgp, asm: "FCVTWD", typ: "Int32"}, // int32(arg0) 460 {name: "FCVTLD", argLength: 1, reg: fpgp, asm: "FCVTLD", typ: "Int64"}, // int64(arg0) 461 {name: "FCVTDS", argLength: 1, reg: fp11, asm: "FCVTDS", typ: "Float64"}, // float64(arg0) 462 {name: "FCVTSD", argLength: 1, reg: fp11, asm: "FCVTSD", typ: "Float32"}, // float32(arg0) 463 {name: "FMOVDload", argLength: 2, reg: fpload, asm: "MOVD", aux: "SymOff", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"}, // load float64 from arg0+auxint+aux 464 {name: "FMOVDstore", argLength: 3, reg: fpstore, asm: "MOVD", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store float6 to arg0+auxint+aux 465 {name: "FEQD", argLength: 2, reg: fp2gp, asm: "FEQD", commutative: true}, // arg0 == arg1 466 {name: "FNED", argLength: 2, reg: fp2gp, asm: "FNED", commutative: true}, // arg0 != arg1 467 {name: "FLTD", argLength: 2, reg: fp2gp, asm: "FLTD"}, // arg0 < arg1 468 {name: "FLED", argLength: 2, reg: fp2gp, asm: "FLED"}, // arg0 <= arg1 469 {name: "LoweredFMIND", argLength: 2, reg: fp21, resultNotInArgs: true, asm: "FMIND", commutative: true, typ: "Float64"}, // min(arg0, arg1) 470 {name: "LoweredFMAXD", argLength: 2, reg: fp21, resultNotInArgs: true, asm: "FMAXD", commutative: true, typ: "Float64"}, // max(arg0, arg1) 471 } 472 473 RISCV64blocks := []blockData{ 474 {name: "BEQ", controls: 2}, 475 {name: "BNE", controls: 2}, 476 {name: "BLT", controls: 2}, 477 {name: "BGE", controls: 2}, 478 {name: "BLTU", controls: 2}, 479 {name: "BGEU", controls: 2}, 480 481 {name: "BEQZ", controls: 1}, 482 {name: "BNEZ", controls: 1}, 483 {name: "BLEZ", controls: 1}, 484 {name: "BGEZ", controls: 1}, 485 {name: "BLTZ", controls: 1}, 486 {name: "BGTZ", controls: 1}, 487 } 488 489 archs = append(archs, arch{ 490 name: "RISCV64", 491 pkg: "cmd/internal/obj/riscv", 492 genfile: "../../riscv64/ssa.go", 493 ops: RISCV64ops, 494 blocks: RISCV64blocks, 495 regnames: regNamesRISCV64, 496 gpregmask: gpMask, 497 fpregmask: fpMask, 498 framepointerreg: -1, // not used 499 // Integer parameters passed in register X10-X17, X8-X9, X18-X23 500 ParamIntRegNames: "X10 X11 X12 X13 X14 X15 X16 X17 X8 X9 X18 X19 X20 X21 X22 X23", 501 // Float parameters passed in register F10-F17, F8-F9, F18-F23 502 ParamFloatRegNames: "F10 F11 F12 F13 F14 F15 F16 F17 F8 F9 F18 F19 F20 F21 F22 F23", 503 }) 504} 505