github.com/bir3/gocompiler@v0.9.2202/src/cmd/compile/internal/riscv64/ssa.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 package riscv64 6 7 import ( 8 "github.com/bir3/gocompiler/src/cmd/compile/internal/base" 9 "github.com/bir3/gocompiler/src/cmd/compile/internal/ir" 10 "github.com/bir3/gocompiler/src/cmd/compile/internal/objw" 11 "github.com/bir3/gocompiler/src/cmd/compile/internal/ssa" 12 "github.com/bir3/gocompiler/src/cmd/compile/internal/ssagen" 13 "github.com/bir3/gocompiler/src/cmd/compile/internal/types" 14 "github.com/bir3/gocompiler/src/cmd/internal/obj" 15 "github.com/bir3/gocompiler/src/cmd/internal/obj/riscv" 16 ) 17 18 // ssaRegToReg maps ssa register numbers to obj register numbers. 19 var ssaRegToReg = []int16{ 20 riscv.REG_X0, 21 // X1 (LR): unused 22 riscv.REG_X2, 23 riscv.REG_X3, 24 riscv.REG_X4, 25 riscv.REG_X5, 26 riscv.REG_X6, 27 riscv.REG_X7, 28 riscv.REG_X8, 29 riscv.REG_X9, 30 riscv.REG_X10, 31 riscv.REG_X11, 32 riscv.REG_X12, 33 riscv.REG_X13, 34 riscv.REG_X14, 35 riscv.REG_X15, 36 riscv.REG_X16, 37 riscv.REG_X17, 38 riscv.REG_X18, 39 riscv.REG_X19, 40 riscv.REG_X20, 41 riscv.REG_X21, 42 riscv.REG_X22, 43 riscv.REG_X23, 44 riscv.REG_X24, 45 riscv.REG_X25, 46 riscv.REG_X26, 47 riscv.REG_X27, 48 riscv.REG_X28, 49 riscv.REG_X29, 50 riscv.REG_X30, 51 riscv.REG_X31, 52 riscv.REG_F0, 53 riscv.REG_F1, 54 riscv.REG_F2, 55 riscv.REG_F3, 56 riscv.REG_F4, 57 riscv.REG_F5, 58 riscv.REG_F6, 59 riscv.REG_F7, 60 riscv.REG_F8, 61 riscv.REG_F9, 62 riscv.REG_F10, 63 riscv.REG_F11, 64 riscv.REG_F12, 65 riscv.REG_F13, 66 riscv.REG_F14, 67 riscv.REG_F15, 68 riscv.REG_F16, 69 riscv.REG_F17, 70 riscv.REG_F18, 71 riscv.REG_F19, 72 riscv.REG_F20, 73 riscv.REG_F21, 74 riscv.REG_F22, 75 riscv.REG_F23, 76 riscv.REG_F24, 77 riscv.REG_F25, 78 riscv.REG_F26, 79 riscv.REG_F27, 80 riscv.REG_F28, 81 riscv.REG_F29, 82 riscv.REG_F30, 83 riscv.REG_F31, 84 0, // SB isn't a real register. We fill an Addr.Reg field with 0 in this case. 85 } 86 87 func loadByType(t *types.Type) obj.As { 88 width := t.Size() 89 90 if t.IsFloat() { 91 switch width { 92 case 4: 93 return riscv.AMOVF 94 case 8: 95 return riscv.AMOVD 96 default: 97 base.Fatalf("unknown float width for load %d in type %v", width, t) 98 return 0 99 } 100 } 101 102 switch width { 103 case 1: 104 if t.IsSigned() { 105 return riscv.AMOVB 106 } else { 107 return riscv.AMOVBU 108 } 109 case 2: 110 if t.IsSigned() { 111 return riscv.AMOVH 112 } else { 113 return riscv.AMOVHU 114 } 115 case 4: 116 if t.IsSigned() { 117 return riscv.AMOVW 118 } else { 119 return riscv.AMOVWU 120 } 121 case 8: 122 return riscv.AMOV 123 default: 124 base.Fatalf("unknown width for load %d in type %v", width, t) 125 return 0 126 } 127 } 128 129 // storeByType returns the store instruction of the given type. 130 func storeByType(t *types.Type) obj.As { 131 width := t.Size() 132 133 if t.IsFloat() { 134 switch width { 135 case 4: 136 return riscv.AMOVF 137 case 8: 138 return riscv.AMOVD 139 default: 140 base.Fatalf("unknown float width for store %d in type %v", width, t) 141 return 0 142 } 143 } 144 145 switch width { 146 case 1: 147 return riscv.AMOVB 148 case 2: 149 return riscv.AMOVH 150 case 4: 151 return riscv.AMOVW 152 case 8: 153 return riscv.AMOV 154 default: 155 base.Fatalf("unknown width for store %d in type %v", width, t) 156 return 0 157 } 158 } 159 160 // largestMove returns the largest move instruction possible and its size, 161 // given the alignment of the total size of the move. 162 // 163 // e.g., a 16-byte move may use MOV, but an 11-byte move must use MOVB. 164 // 165 // Note that the moves may not be on naturally aligned addresses depending on 166 // the source and destination. 167 // 168 // This matches the calculation in ssa.moveSize. 169 func largestMove(alignment int64) (obj.As, int64) { 170 switch { 171 case alignment%8 == 0: 172 return riscv.AMOV, 8 173 case alignment%4 == 0: 174 return riscv.AMOVW, 4 175 case alignment%2 == 0: 176 return riscv.AMOVH, 2 177 default: 178 return riscv.AMOVB, 1 179 } 180 } 181 182 // ssaMarkMoves marks any MOVXconst ops that need to avoid clobbering flags. 183 // RISC-V has no flags, so this is a no-op. 184 func ssaMarkMoves(s *ssagen.State, b *ssa.Block) {} 185 186 func ssaGenValue(s *ssagen.State, v *ssa.Value) { 187 s.SetPos(v.Pos) 188 189 switch v.Op { 190 case ssa.OpInitMem: 191 // memory arg needs no code 192 case ssa.OpArg: 193 // input args need no code 194 case ssa.OpPhi: 195 ssagen.CheckLoweredPhi(v) 196 case ssa.OpCopy, ssa.OpRISCV64MOVDreg: 197 if v.Type.IsMemory() { 198 return 199 } 200 rs := v.Args[0].Reg() 201 rd := v.Reg() 202 if rs == rd { 203 return 204 } 205 as := riscv.AMOV 206 if v.Type.IsFloat() { 207 as = riscv.AMOVD 208 } 209 p := s.Prog(as) 210 p.From.Type = obj.TYPE_REG 211 p.From.Reg = rs 212 p.To.Type = obj.TYPE_REG 213 p.To.Reg = rd 214 case ssa.OpRISCV64MOVDnop: 215 // nothing to do 216 case ssa.OpLoadReg: 217 if v.Type.IsFlags() { 218 v.Fatalf("load flags not implemented: %v", v.LongString()) 219 return 220 } 221 p := s.Prog(loadByType(v.Type)) 222 ssagen.AddrAuto(&p.From, v.Args[0]) 223 p.To.Type = obj.TYPE_REG 224 p.To.Reg = v.Reg() 225 case ssa.OpStoreReg: 226 if v.Type.IsFlags() { 227 v.Fatalf("store flags not implemented: %v", v.LongString()) 228 return 229 } 230 p := s.Prog(storeByType(v.Type)) 231 p.From.Type = obj.TYPE_REG 232 p.From.Reg = v.Args[0].Reg() 233 ssagen.AddrAuto(&p.To, v) 234 case ssa.OpArgIntReg, ssa.OpArgFloatReg: 235 // The assembler needs to wrap the entry safepoint/stack growth code with spill/unspill 236 // The loop only runs once. 237 for _, a := range v.Block.Func.RegArgs { 238 // Pass the spill/unspill information along to the assembler, offset by size of 239 // the saved LR slot. 240 addr := ssagen.SpillSlotAddr(a, riscv.REG_SP, base.Ctxt.Arch.FixedFrameSize) 241 s.FuncInfo().AddSpill( 242 obj.RegSpill{Reg: a.Reg, Addr: addr, Unspill: loadByType(a.Type), Spill: storeByType(a.Type)}) 243 } 244 v.Block.Func.RegArgs = nil 245 246 ssagen.CheckArgReg(v) 247 case ssa.OpSP, ssa.OpSB, ssa.OpGetG: 248 // nothing to do 249 case ssa.OpRISCV64MOVBreg, ssa.OpRISCV64MOVHreg, ssa.OpRISCV64MOVWreg, 250 ssa.OpRISCV64MOVBUreg, ssa.OpRISCV64MOVHUreg, ssa.OpRISCV64MOVWUreg: 251 a := v.Args[0] 252 for a.Op == ssa.OpCopy || a.Op == ssa.OpRISCV64MOVDreg { 253 a = a.Args[0] 254 } 255 as := v.Op.Asm() 256 rs := v.Args[0].Reg() 257 rd := v.Reg() 258 if a.Op == ssa.OpLoadReg { 259 t := a.Type 260 switch { 261 case v.Op == ssa.OpRISCV64MOVBreg && t.Size() == 1 && t.IsSigned(), 262 v.Op == ssa.OpRISCV64MOVHreg && t.Size() == 2 && t.IsSigned(), 263 v.Op == ssa.OpRISCV64MOVWreg && t.Size() == 4 && t.IsSigned(), 264 v.Op == ssa.OpRISCV64MOVBUreg && t.Size() == 1 && !t.IsSigned(), 265 v.Op == ssa.OpRISCV64MOVHUreg && t.Size() == 2 && !t.IsSigned(), 266 v.Op == ssa.OpRISCV64MOVWUreg && t.Size() == 4 && !t.IsSigned(): 267 // arg is a proper-typed load and already sign/zero-extended 268 if rs == rd { 269 return 270 } 271 as = riscv.AMOV 272 default: 273 } 274 } 275 p := s.Prog(as) 276 p.From.Type = obj.TYPE_REG 277 p.From.Reg = rs 278 p.To.Type = obj.TYPE_REG 279 p.To.Reg = rd 280 case ssa.OpRISCV64ADD, ssa.OpRISCV64SUB, ssa.OpRISCV64SUBW, ssa.OpRISCV64XOR, ssa.OpRISCV64OR, ssa.OpRISCV64AND, 281 ssa.OpRISCV64SLL, ssa.OpRISCV64SRA, ssa.OpRISCV64SRAW, ssa.OpRISCV64SRL, ssa.OpRISCV64SRLW, 282 ssa.OpRISCV64SLT, ssa.OpRISCV64SLTU, ssa.OpRISCV64MUL, ssa.OpRISCV64MULW, ssa.OpRISCV64MULH, 283 ssa.OpRISCV64MULHU, ssa.OpRISCV64DIV, ssa.OpRISCV64DIVU, ssa.OpRISCV64DIVW, 284 ssa.OpRISCV64DIVUW, ssa.OpRISCV64REM, ssa.OpRISCV64REMU, ssa.OpRISCV64REMW, 285 ssa.OpRISCV64REMUW, 286 ssa.OpRISCV64FADDS, ssa.OpRISCV64FSUBS, ssa.OpRISCV64FMULS, ssa.OpRISCV64FDIVS, 287 ssa.OpRISCV64FEQS, ssa.OpRISCV64FNES, ssa.OpRISCV64FLTS, ssa.OpRISCV64FLES, 288 ssa.OpRISCV64FADDD, ssa.OpRISCV64FSUBD, ssa.OpRISCV64FMULD, ssa.OpRISCV64FDIVD, 289 ssa.OpRISCV64FEQD, ssa.OpRISCV64FNED, ssa.OpRISCV64FLTD, ssa.OpRISCV64FLED, 290 ssa.OpRISCV64FSGNJD: 291 r := v.Reg() 292 r1 := v.Args[0].Reg() 293 r2 := v.Args[1].Reg() 294 p := s.Prog(v.Op.Asm()) 295 p.From.Type = obj.TYPE_REG 296 p.From.Reg = r2 297 p.Reg = r1 298 p.To.Type = obj.TYPE_REG 299 p.To.Reg = r 300 case ssa.OpRISCV64LoweredMuluhilo: 301 r0 := v.Args[0].Reg() 302 r1 := v.Args[1].Reg() 303 p := s.Prog(riscv.AMULHU) 304 p.From.Type = obj.TYPE_REG 305 p.From.Reg = r1 306 p.Reg = r0 307 p.To.Type = obj.TYPE_REG 308 p.To.Reg = v.Reg0() 309 p1 := s.Prog(riscv.AMUL) 310 p1.From.Type = obj.TYPE_REG 311 p1.From.Reg = r1 312 p1.Reg = r0 313 p1.To.Type = obj.TYPE_REG 314 p1.To.Reg = v.Reg1() 315 case ssa.OpRISCV64LoweredMuluover: 316 r0 := v.Args[0].Reg() 317 r1 := v.Args[1].Reg() 318 p := s.Prog(riscv.AMULHU) 319 p.From.Type = obj.TYPE_REG 320 p.From.Reg = r1 321 p.Reg = r0 322 p.To.Type = obj.TYPE_REG 323 p.To.Reg = v.Reg1() 324 p1 := s.Prog(riscv.AMUL) 325 p1.From.Type = obj.TYPE_REG 326 p1.From.Reg = r1 327 p1.Reg = r0 328 p1.To.Type = obj.TYPE_REG 329 p1.To.Reg = v.Reg0() 330 p2 := s.Prog(riscv.ASNEZ) 331 p2.From.Type = obj.TYPE_REG 332 p2.From.Reg = v.Reg1() 333 p2.To.Type = obj.TYPE_REG 334 p2.To.Reg = v.Reg1() 335 case ssa.OpRISCV64FMADDD, ssa.OpRISCV64FMSUBD, ssa.OpRISCV64FNMADDD, ssa.OpRISCV64FNMSUBD, 336 ssa.OpRISCV64FMADDS, ssa.OpRISCV64FMSUBS, ssa.OpRISCV64FNMADDS, ssa.OpRISCV64FNMSUBS: 337 r := v.Reg() 338 r1 := v.Args[0].Reg() 339 r2 := v.Args[1].Reg() 340 r3 := v.Args[2].Reg() 341 p := s.Prog(v.Op.Asm()) 342 p.From.Type = obj.TYPE_REG 343 p.From.Reg = r2 344 p.Reg = r1 345 p.AddRestSource(obj.Addr{Type: obj.TYPE_REG, Reg: r3}) 346 p.To.Type = obj.TYPE_REG 347 p.To.Reg = r 348 case ssa.OpRISCV64FSQRTS, ssa.OpRISCV64FNEGS, ssa.OpRISCV64FABSD, ssa.OpRISCV64FSQRTD, ssa.OpRISCV64FNEGD, 349 ssa.OpRISCV64FMVSX, ssa.OpRISCV64FMVDX, 350 ssa.OpRISCV64FCVTSW, ssa.OpRISCV64FCVTSL, ssa.OpRISCV64FCVTWS, ssa.OpRISCV64FCVTLS, 351 ssa.OpRISCV64FCVTDW, ssa.OpRISCV64FCVTDL, ssa.OpRISCV64FCVTWD, ssa.OpRISCV64FCVTLD, ssa.OpRISCV64FCVTDS, ssa.OpRISCV64FCVTSD, 352 ssa.OpRISCV64NOT, ssa.OpRISCV64NEG, ssa.OpRISCV64NEGW: 353 p := s.Prog(v.Op.Asm()) 354 p.From.Type = obj.TYPE_REG 355 p.From.Reg = v.Args[0].Reg() 356 p.To.Type = obj.TYPE_REG 357 p.To.Reg = v.Reg() 358 case ssa.OpRISCV64ADDI, ssa.OpRISCV64ADDIW, ssa.OpRISCV64XORI, ssa.OpRISCV64ORI, ssa.OpRISCV64ANDI, 359 ssa.OpRISCV64SLLI, ssa.OpRISCV64SRAI, ssa.OpRISCV64SRAIW, ssa.OpRISCV64SRLI, ssa.OpRISCV64SRLIW, ssa.OpRISCV64SLTI, 360 ssa.OpRISCV64SLTIU: 361 p := s.Prog(v.Op.Asm()) 362 p.From.Type = obj.TYPE_CONST 363 p.From.Offset = v.AuxInt 364 p.Reg = v.Args[0].Reg() 365 p.To.Type = obj.TYPE_REG 366 p.To.Reg = v.Reg() 367 case ssa.OpRISCV64MOVDconst: 368 p := s.Prog(v.Op.Asm()) 369 p.From.Type = obj.TYPE_CONST 370 p.From.Offset = v.AuxInt 371 p.To.Type = obj.TYPE_REG 372 p.To.Reg = v.Reg() 373 case ssa.OpRISCV64MOVaddr: 374 p := s.Prog(v.Op.Asm()) 375 p.From.Type = obj.TYPE_ADDR 376 p.To.Type = obj.TYPE_REG 377 p.To.Reg = v.Reg() 378 379 var wantreg string 380 // MOVW $sym+off(base), R 381 switch v.Aux.(type) { 382 default: 383 v.Fatalf("aux is of unknown type %T", v.Aux) 384 case *obj.LSym: 385 wantreg = "SB" 386 ssagen.AddAux(&p.From, v) 387 case *ir.Name: 388 wantreg = "SP" 389 ssagen.AddAux(&p.From, v) 390 case nil: 391 // No sym, just MOVW $off(SP), R 392 wantreg = "SP" 393 p.From.Reg = riscv.REG_SP 394 p.From.Offset = v.AuxInt 395 } 396 if reg := v.Args[0].RegName(); reg != wantreg { 397 v.Fatalf("bad reg %s for symbol type %T, want %s", reg, v.Aux, wantreg) 398 } 399 case ssa.OpRISCV64MOVBload, ssa.OpRISCV64MOVHload, ssa.OpRISCV64MOVWload, ssa.OpRISCV64MOVDload, 400 ssa.OpRISCV64MOVBUload, ssa.OpRISCV64MOVHUload, ssa.OpRISCV64MOVWUload, 401 ssa.OpRISCV64FMOVWload, ssa.OpRISCV64FMOVDload: 402 p := s.Prog(v.Op.Asm()) 403 p.From.Type = obj.TYPE_MEM 404 p.From.Reg = v.Args[0].Reg() 405 ssagen.AddAux(&p.From, v) 406 p.To.Type = obj.TYPE_REG 407 p.To.Reg = v.Reg() 408 case ssa.OpRISCV64MOVBstore, ssa.OpRISCV64MOVHstore, ssa.OpRISCV64MOVWstore, ssa.OpRISCV64MOVDstore, 409 ssa.OpRISCV64FMOVWstore, ssa.OpRISCV64FMOVDstore: 410 p := s.Prog(v.Op.Asm()) 411 p.From.Type = obj.TYPE_REG 412 p.From.Reg = v.Args[1].Reg() 413 p.To.Type = obj.TYPE_MEM 414 p.To.Reg = v.Args[0].Reg() 415 ssagen.AddAux(&p.To, v) 416 case ssa.OpRISCV64MOVBstorezero, ssa.OpRISCV64MOVHstorezero, ssa.OpRISCV64MOVWstorezero, ssa.OpRISCV64MOVDstorezero: 417 p := s.Prog(v.Op.Asm()) 418 p.From.Type = obj.TYPE_REG 419 p.From.Reg = riscv.REG_ZERO 420 p.To.Type = obj.TYPE_MEM 421 p.To.Reg = v.Args[0].Reg() 422 ssagen.AddAux(&p.To, v) 423 case ssa.OpRISCV64SEQZ, ssa.OpRISCV64SNEZ: 424 p := s.Prog(v.Op.Asm()) 425 p.From.Type = obj.TYPE_REG 426 p.From.Reg = v.Args[0].Reg() 427 p.To.Type = obj.TYPE_REG 428 p.To.Reg = v.Reg() 429 case ssa.OpRISCV64CALLstatic, ssa.OpRISCV64CALLclosure, ssa.OpRISCV64CALLinter: 430 s.Call(v) 431 case ssa.OpRISCV64CALLtail: 432 s.TailCall(v) 433 case ssa.OpRISCV64LoweredWB: 434 p := s.Prog(obj.ACALL) 435 p.To.Type = obj.TYPE_MEM 436 p.To.Name = obj.NAME_EXTERN 437 // AuxInt encodes how many buffer entries we need. 438 p.To.Sym = ir.Syms.GCWriteBarrier[v.AuxInt-1] 439 case ssa.OpRISCV64LoweredPanicBoundsA, ssa.OpRISCV64LoweredPanicBoundsB, ssa.OpRISCV64LoweredPanicBoundsC: 440 p := s.Prog(obj.ACALL) 441 p.To.Type = obj.TYPE_MEM 442 p.To.Name = obj.NAME_EXTERN 443 p.To.Sym = ssagen.BoundsCheckFunc[v.AuxInt] 444 s.UseArgs(16) // space used in callee args area by assembly stubs 445 446 case ssa.OpRISCV64LoweredAtomicLoad8: 447 s.Prog(riscv.AFENCE) 448 p := s.Prog(riscv.AMOVBU) 449 p.From.Type = obj.TYPE_MEM 450 p.From.Reg = v.Args[0].Reg() 451 p.To.Type = obj.TYPE_REG 452 p.To.Reg = v.Reg0() 453 s.Prog(riscv.AFENCE) 454 455 case ssa.OpRISCV64LoweredAtomicLoad32, ssa.OpRISCV64LoweredAtomicLoad64: 456 as := riscv.ALRW 457 if v.Op == ssa.OpRISCV64LoweredAtomicLoad64 { 458 as = riscv.ALRD 459 } 460 p := s.Prog(as) 461 p.From.Type = obj.TYPE_MEM 462 p.From.Reg = v.Args[0].Reg() 463 p.To.Type = obj.TYPE_REG 464 p.To.Reg = v.Reg0() 465 466 case ssa.OpRISCV64LoweredAtomicStore8: 467 s.Prog(riscv.AFENCE) 468 p := s.Prog(riscv.AMOVB) 469 p.From.Type = obj.TYPE_REG 470 p.From.Reg = v.Args[1].Reg() 471 p.To.Type = obj.TYPE_MEM 472 p.To.Reg = v.Args[0].Reg() 473 s.Prog(riscv.AFENCE) 474 475 case ssa.OpRISCV64LoweredAtomicStore32, ssa.OpRISCV64LoweredAtomicStore64: 476 as := riscv.AAMOSWAPW 477 if v.Op == ssa.OpRISCV64LoweredAtomicStore64 { 478 as = riscv.AAMOSWAPD 479 } 480 p := s.Prog(as) 481 p.From.Type = obj.TYPE_REG 482 p.From.Reg = v.Args[1].Reg() 483 p.To.Type = obj.TYPE_MEM 484 p.To.Reg = v.Args[0].Reg() 485 p.RegTo2 = riscv.REG_ZERO 486 487 case ssa.OpRISCV64LoweredAtomicAdd32, ssa.OpRISCV64LoweredAtomicAdd64: 488 as := riscv.AAMOADDW 489 if v.Op == ssa.OpRISCV64LoweredAtomicAdd64 { 490 as = riscv.AAMOADDD 491 } 492 p := s.Prog(as) 493 p.From.Type = obj.TYPE_REG 494 p.From.Reg = v.Args[1].Reg() 495 p.To.Type = obj.TYPE_MEM 496 p.To.Reg = v.Args[0].Reg() 497 p.RegTo2 = riscv.REG_TMP 498 499 p2 := s.Prog(riscv.AADD) 500 p2.From.Type = obj.TYPE_REG 501 p2.From.Reg = riscv.REG_TMP 502 p2.Reg = v.Args[1].Reg() 503 p2.To.Type = obj.TYPE_REG 504 p2.To.Reg = v.Reg0() 505 506 case ssa.OpRISCV64LoweredAtomicExchange32, ssa.OpRISCV64LoweredAtomicExchange64: 507 as := riscv.AAMOSWAPW 508 if v.Op == ssa.OpRISCV64LoweredAtomicExchange64 { 509 as = riscv.AAMOSWAPD 510 } 511 p := s.Prog(as) 512 p.From.Type = obj.TYPE_REG 513 p.From.Reg = v.Args[1].Reg() 514 p.To.Type = obj.TYPE_MEM 515 p.To.Reg = v.Args[0].Reg() 516 p.RegTo2 = v.Reg0() 517 518 case ssa.OpRISCV64LoweredAtomicCas32, ssa.OpRISCV64LoweredAtomicCas64: 519 // MOV ZERO, Rout 520 // LR (Rarg0), Rtmp 521 // BNE Rtmp, Rarg1, 3(PC) 522 // SC Rarg2, (Rarg0), Rtmp 523 // BNE Rtmp, ZERO, -3(PC) 524 // MOV $1, Rout 525 526 lr := riscv.ALRW 527 sc := riscv.ASCW 528 if v.Op == ssa.OpRISCV64LoweredAtomicCas64 { 529 lr = riscv.ALRD 530 sc = riscv.ASCD 531 } 532 533 r0 := v.Args[0].Reg() 534 r1 := v.Args[1].Reg() 535 r2 := v.Args[2].Reg() 536 out := v.Reg0() 537 538 p := s.Prog(riscv.AMOV) 539 p.From.Type = obj.TYPE_REG 540 p.From.Reg = riscv.REG_ZERO 541 p.To.Type = obj.TYPE_REG 542 p.To.Reg = out 543 544 p1 := s.Prog(lr) 545 p1.From.Type = obj.TYPE_MEM 546 p1.From.Reg = r0 547 p1.To.Type = obj.TYPE_REG 548 p1.To.Reg = riscv.REG_TMP 549 550 p2 := s.Prog(riscv.ABNE) 551 p2.From.Type = obj.TYPE_REG 552 p2.From.Reg = r1 553 p2.Reg = riscv.REG_TMP 554 p2.To.Type = obj.TYPE_BRANCH 555 556 p3 := s.Prog(sc) 557 p3.From.Type = obj.TYPE_REG 558 p3.From.Reg = r2 559 p3.To.Type = obj.TYPE_MEM 560 p3.To.Reg = r0 561 p3.RegTo2 = riscv.REG_TMP 562 563 p4 := s.Prog(riscv.ABNE) 564 p4.From.Type = obj.TYPE_REG 565 p4.From.Reg = riscv.REG_TMP 566 p4.Reg = riscv.REG_ZERO 567 p4.To.Type = obj.TYPE_BRANCH 568 p4.To.SetTarget(p1) 569 570 p5 := s.Prog(riscv.AMOV) 571 p5.From.Type = obj.TYPE_CONST 572 p5.From.Offset = 1 573 p5.To.Type = obj.TYPE_REG 574 p5.To.Reg = out 575 576 p6 := s.Prog(obj.ANOP) 577 p2.To.SetTarget(p6) 578 579 case ssa.OpRISCV64LoweredAtomicAnd32, ssa.OpRISCV64LoweredAtomicOr32: 580 p := s.Prog(v.Op.Asm()) 581 p.From.Type = obj.TYPE_REG 582 p.From.Reg = v.Args[1].Reg() 583 p.To.Type = obj.TYPE_MEM 584 p.To.Reg = v.Args[0].Reg() 585 p.RegTo2 = riscv.REG_ZERO 586 587 case ssa.OpRISCV64LoweredZero: 588 mov, sz := largestMove(v.AuxInt) 589 590 // mov ZERO, (Rarg0) 591 // ADD $sz, Rarg0 592 // BGEU Rarg1, Rarg0, -2(PC) 593 594 p := s.Prog(mov) 595 p.From.Type = obj.TYPE_REG 596 p.From.Reg = riscv.REG_ZERO 597 p.To.Type = obj.TYPE_MEM 598 p.To.Reg = v.Args[0].Reg() 599 600 p2 := s.Prog(riscv.AADD) 601 p2.From.Type = obj.TYPE_CONST 602 p2.From.Offset = sz 603 p2.To.Type = obj.TYPE_REG 604 p2.To.Reg = v.Args[0].Reg() 605 606 p3 := s.Prog(riscv.ABGEU) 607 p3.To.Type = obj.TYPE_BRANCH 608 p3.Reg = v.Args[0].Reg() 609 p3.From.Type = obj.TYPE_REG 610 p3.From.Reg = v.Args[1].Reg() 611 p3.To.SetTarget(p) 612 613 case ssa.OpRISCV64LoweredMove: 614 mov, sz := largestMove(v.AuxInt) 615 616 // mov (Rarg1), T2 617 // mov T2, (Rarg0) 618 // ADD $sz, Rarg0 619 // ADD $sz, Rarg1 620 // BGEU Rarg2, Rarg0, -4(PC) 621 622 p := s.Prog(mov) 623 p.From.Type = obj.TYPE_MEM 624 p.From.Reg = v.Args[1].Reg() 625 p.To.Type = obj.TYPE_REG 626 p.To.Reg = riscv.REG_T2 627 628 p2 := s.Prog(mov) 629 p2.From.Type = obj.TYPE_REG 630 p2.From.Reg = riscv.REG_T2 631 p2.To.Type = obj.TYPE_MEM 632 p2.To.Reg = v.Args[0].Reg() 633 634 p3 := s.Prog(riscv.AADD) 635 p3.From.Type = obj.TYPE_CONST 636 p3.From.Offset = sz 637 p3.To.Type = obj.TYPE_REG 638 p3.To.Reg = v.Args[0].Reg() 639 640 p4 := s.Prog(riscv.AADD) 641 p4.From.Type = obj.TYPE_CONST 642 p4.From.Offset = sz 643 p4.To.Type = obj.TYPE_REG 644 p4.To.Reg = v.Args[1].Reg() 645 646 p5 := s.Prog(riscv.ABGEU) 647 p5.To.Type = obj.TYPE_BRANCH 648 p5.Reg = v.Args[1].Reg() 649 p5.From.Type = obj.TYPE_REG 650 p5.From.Reg = v.Args[2].Reg() 651 p5.To.SetTarget(p) 652 653 case ssa.OpRISCV64LoweredNilCheck: 654 // Issue a load which will fault if arg is nil. 655 // TODO: optimizations. See arm and amd64 LoweredNilCheck. 656 p := s.Prog(riscv.AMOVB) 657 p.From.Type = obj.TYPE_MEM 658 p.From.Reg = v.Args[0].Reg() 659 ssagen.AddAux(&p.From, v) 660 p.To.Type = obj.TYPE_REG 661 p.To.Reg = riscv.REG_ZERO 662 if base.Debug.Nil != 0 && v.Pos.Line() > 1 { // v.Pos == 1 in generated wrappers 663 base.WarnfAt(v.Pos, "generated nil check") 664 } 665 666 case ssa.OpRISCV64LoweredGetClosurePtr: 667 // Closure pointer is S10 (riscv.REG_CTXT). 668 ssagen.CheckLoweredGetClosurePtr(v) 669 670 case ssa.OpRISCV64LoweredGetCallerSP: 671 // caller's SP is FixedFrameSize below the address of the first arg 672 p := s.Prog(riscv.AMOV) 673 p.From.Type = obj.TYPE_ADDR 674 p.From.Offset = -base.Ctxt.Arch.FixedFrameSize 675 p.From.Name = obj.NAME_PARAM 676 p.To.Type = obj.TYPE_REG 677 p.To.Reg = v.Reg() 678 679 case ssa.OpRISCV64LoweredGetCallerPC: 680 p := s.Prog(obj.AGETCALLERPC) 681 p.To.Type = obj.TYPE_REG 682 p.To.Reg = v.Reg() 683 684 case ssa.OpRISCV64DUFFZERO: 685 p := s.Prog(obj.ADUFFZERO) 686 p.To.Type = obj.TYPE_MEM 687 p.To.Name = obj.NAME_EXTERN 688 p.To.Sym = ir.Syms.Duffzero 689 p.To.Offset = v.AuxInt 690 691 case ssa.OpRISCV64DUFFCOPY: 692 p := s.Prog(obj.ADUFFCOPY) 693 p.To.Type = obj.TYPE_MEM 694 p.To.Name = obj.NAME_EXTERN 695 p.To.Sym = ir.Syms.Duffcopy 696 p.To.Offset = v.AuxInt 697 698 case ssa.OpRISCV64LoweredPubBarrier: 699 // FENCE 700 s.Prog(v.Op.Asm()) 701 702 case ssa.OpRISCV64LoweredRound32F, ssa.OpRISCV64LoweredRound64F: 703 // input is already rounded 704 705 case ssa.OpClobber, ssa.OpClobberReg: 706 // TODO: implement for clobberdead experiment. Nop is ok for now. 707 708 default: 709 v.Fatalf("Unhandled op %v", v.Op) 710 } 711 } 712 713 var blockBranch = [...]obj.As{ 714 ssa.BlockRISCV64BEQ: riscv.ABEQ, 715 ssa.BlockRISCV64BEQZ: riscv.ABEQZ, 716 ssa.BlockRISCV64BGE: riscv.ABGE, 717 ssa.BlockRISCV64BGEU: riscv.ABGEU, 718 ssa.BlockRISCV64BGEZ: riscv.ABGEZ, 719 ssa.BlockRISCV64BGTZ: riscv.ABGTZ, 720 ssa.BlockRISCV64BLEZ: riscv.ABLEZ, 721 ssa.BlockRISCV64BLT: riscv.ABLT, 722 ssa.BlockRISCV64BLTU: riscv.ABLTU, 723 ssa.BlockRISCV64BLTZ: riscv.ABLTZ, 724 ssa.BlockRISCV64BNE: riscv.ABNE, 725 ssa.BlockRISCV64BNEZ: riscv.ABNEZ, 726 } 727 728 func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) { 729 s.SetPos(b.Pos) 730 731 switch b.Kind { 732 case ssa.BlockDefer: 733 // defer returns in A0: 734 // 0 if we should continue executing 735 // 1 if we should jump to deferreturn call 736 p := s.Prog(riscv.ABNE) 737 p.To.Type = obj.TYPE_BRANCH 738 p.From.Type = obj.TYPE_REG 739 p.From.Reg = riscv.REG_ZERO 740 p.Reg = riscv.REG_A0 741 s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[1].Block()}) 742 if b.Succs[0].Block() != next { 743 p := s.Prog(obj.AJMP) 744 p.To.Type = obj.TYPE_BRANCH 745 s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()}) 746 } 747 case ssa.BlockPlain: 748 if b.Succs[0].Block() != next { 749 p := s.Prog(obj.AJMP) 750 p.To.Type = obj.TYPE_BRANCH 751 s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()}) 752 } 753 case ssa.BlockExit, ssa.BlockRetJmp: 754 case ssa.BlockRet: 755 s.Prog(obj.ARET) 756 case ssa.BlockRISCV64BEQ, ssa.BlockRISCV64BEQZ, ssa.BlockRISCV64BNE, ssa.BlockRISCV64BNEZ, 757 ssa.BlockRISCV64BLT, ssa.BlockRISCV64BLEZ, ssa.BlockRISCV64BGE, ssa.BlockRISCV64BGEZ, 758 ssa.BlockRISCV64BLTZ, ssa.BlockRISCV64BGTZ, ssa.BlockRISCV64BLTU, ssa.BlockRISCV64BGEU: 759 760 as := blockBranch[b.Kind] 761 invAs := riscv.InvertBranch(as) 762 763 var p *obj.Prog 764 switch next { 765 case b.Succs[0].Block(): 766 p = s.Br(invAs, b.Succs[1].Block()) 767 case b.Succs[1].Block(): 768 p = s.Br(as, b.Succs[0].Block()) 769 default: 770 if b.Likely != ssa.BranchUnlikely { 771 p = s.Br(as, b.Succs[0].Block()) 772 s.Br(obj.AJMP, b.Succs[1].Block()) 773 } else { 774 p = s.Br(invAs, b.Succs[1].Block()) 775 s.Br(obj.AJMP, b.Succs[0].Block()) 776 } 777 } 778 779 p.From.Type = obj.TYPE_REG 780 switch b.Kind { 781 case ssa.BlockRISCV64BEQ, ssa.BlockRISCV64BNE, ssa.BlockRISCV64BLT, ssa.BlockRISCV64BGE, ssa.BlockRISCV64BLTU, ssa.BlockRISCV64BGEU: 782 if b.NumControls() != 2 { 783 b.Fatalf("Unexpected number of controls (%d != 2): %s", b.NumControls(), b.LongString()) 784 } 785 p.From.Reg = b.Controls[0].Reg() 786 p.Reg = b.Controls[1].Reg() 787 788 case ssa.BlockRISCV64BEQZ, ssa.BlockRISCV64BNEZ, ssa.BlockRISCV64BGEZ, ssa.BlockRISCV64BLEZ, ssa.BlockRISCV64BLTZ, ssa.BlockRISCV64BGTZ: 789 if b.NumControls() != 1 { 790 b.Fatalf("Unexpected number of controls (%d != 1): %s", b.NumControls(), b.LongString()) 791 } 792 p.From.Reg = b.Controls[0].Reg() 793 } 794 795 default: 796 b.Fatalf("Unhandled block: %s", b.LongString()) 797 } 798 } 799 800 func loadRegResult(s *ssagen.State, f *ssa.Func, t *types.Type, reg int16, n *ir.Name, off int64) *obj.Prog { 801 p := s.Prog(loadByType(t)) 802 p.From.Type = obj.TYPE_MEM 803 p.From.Name = obj.NAME_AUTO 804 p.From.Sym = n.Linksym() 805 p.From.Offset = n.FrameOffset() + off 806 p.To.Type = obj.TYPE_REG 807 p.To.Reg = reg 808 return p 809 } 810 811 func spillArgReg(pp *objw.Progs, p *obj.Prog, f *ssa.Func, t *types.Type, reg int16, n *ir.Name, off int64) *obj.Prog { 812 p = pp.Append(p, storeByType(t), obj.TYPE_REG, reg, 0, obj.TYPE_MEM, 0, n.FrameOffset()+off) 813 p.To.Name = obj.NAME_PARAM 814 p.To.Sym = n.Linksym() 815 p.Pos = p.Pos.WithNotStmt() 816 return p 817 }