github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/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/gagliardetto/golang-go/cmd/compile/internal/gc" 9 "github.com/gagliardetto/golang-go/cmd/compile/internal/ssa" 10 "github.com/gagliardetto/golang-go/cmd/compile/internal/types" 11 "github.com/gagliardetto/golang-go/cmd/internal/obj" 12 "github.com/gagliardetto/golang-go/cmd/internal/obj/riscv" 13 ) 14 15 // ssaRegToReg maps ssa register numbers to obj register numbers. 16 var ssaRegToReg = []int16{ 17 riscv.REG_X0, 18 // X1 (LR): unused 19 riscv.REG_X2, 20 riscv.REG_X3, 21 riscv.REG_X4, 22 riscv.REG_X5, 23 riscv.REG_X6, 24 riscv.REG_X7, 25 riscv.REG_X8, 26 riscv.REG_X9, 27 riscv.REG_X10, 28 riscv.REG_X11, 29 riscv.REG_X12, 30 riscv.REG_X13, 31 riscv.REG_X14, 32 riscv.REG_X15, 33 riscv.REG_X16, 34 riscv.REG_X17, 35 riscv.REG_X18, 36 riscv.REG_X19, 37 riscv.REG_X20, 38 riscv.REG_X21, 39 riscv.REG_X22, 40 riscv.REG_X23, 41 riscv.REG_X24, 42 riscv.REG_X25, 43 riscv.REG_X26, 44 riscv.REG_X27, 45 riscv.REG_X28, 46 riscv.REG_X29, 47 riscv.REG_X30, 48 riscv.REG_X31, 49 riscv.REG_F0, 50 riscv.REG_F1, 51 riscv.REG_F2, 52 riscv.REG_F3, 53 riscv.REG_F4, 54 riscv.REG_F5, 55 riscv.REG_F6, 56 riscv.REG_F7, 57 riscv.REG_F8, 58 riscv.REG_F9, 59 riscv.REG_F10, 60 riscv.REG_F11, 61 riscv.REG_F12, 62 riscv.REG_F13, 63 riscv.REG_F14, 64 riscv.REG_F15, 65 riscv.REG_F16, 66 riscv.REG_F17, 67 riscv.REG_F18, 68 riscv.REG_F19, 69 riscv.REG_F20, 70 riscv.REG_F21, 71 riscv.REG_F22, 72 riscv.REG_F23, 73 riscv.REG_F24, 74 riscv.REG_F25, 75 riscv.REG_F26, 76 riscv.REG_F27, 77 riscv.REG_F28, 78 riscv.REG_F29, 79 riscv.REG_F30, 80 riscv.REG_F31, 81 0, // SB isn't a real register. We fill an Addr.Reg field with 0 in this case. 82 } 83 84 func loadByType(t *types.Type) obj.As { 85 width := t.Size() 86 87 if t.IsFloat() { 88 switch width { 89 case 4: 90 return riscv.AMOVF 91 case 8: 92 return riscv.AMOVD 93 default: 94 gc.Fatalf("unknown float width for load %d in type %v", width, t) 95 return 0 96 } 97 } 98 99 switch width { 100 case 1: 101 if t.IsSigned() { 102 return riscv.AMOVB 103 } else { 104 return riscv.AMOVBU 105 } 106 case 2: 107 if t.IsSigned() { 108 return riscv.AMOVH 109 } else { 110 return riscv.AMOVHU 111 } 112 case 4: 113 if t.IsSigned() { 114 return riscv.AMOVW 115 } else { 116 return riscv.AMOVWU 117 } 118 case 8: 119 return riscv.AMOV 120 default: 121 gc.Fatalf("unknown width for load %d in type %v", width, t) 122 return 0 123 } 124 } 125 126 // storeByType returns the store instruction of the given type. 127 func storeByType(t *types.Type) obj.As { 128 width := t.Size() 129 130 if t.IsFloat() { 131 switch width { 132 case 4: 133 return riscv.AMOVF 134 case 8: 135 return riscv.AMOVD 136 default: 137 gc.Fatalf("unknown float width for store %d in type %v", width, t) 138 return 0 139 } 140 } 141 142 switch width { 143 case 1: 144 return riscv.AMOVB 145 case 2: 146 return riscv.AMOVH 147 case 4: 148 return riscv.AMOVW 149 case 8: 150 return riscv.AMOV 151 default: 152 gc.Fatalf("unknown width for store %d in type %v", width, t) 153 return 0 154 } 155 } 156 157 // largestMove returns the largest move instruction possible and its size, 158 // given the alignment of the total size of the move. 159 // 160 // e.g., a 16-byte move may use MOV, but an 11-byte move must use MOVB. 161 // 162 // Note that the moves may not be on naturally aligned addresses depending on 163 // the source and destination. 164 // 165 // This matches the calculation in ssa.moveSize. 166 func largestMove(alignment int64) (obj.As, int64) { 167 switch { 168 case alignment%8 == 0: 169 return riscv.AMOV, 8 170 case alignment%4 == 0: 171 return riscv.AMOVW, 4 172 case alignment%2 == 0: 173 return riscv.AMOVH, 2 174 default: 175 return riscv.AMOVB, 1 176 } 177 } 178 179 // markMoves marks any MOVXconst ops that need to avoid clobbering flags. 180 // RISC-V has no flags, so this is a no-op. 181 func ssaMarkMoves(s *gc.SSAGenState, b *ssa.Block) {} 182 183 func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { 184 s.SetPos(v.Pos) 185 186 switch v.Op { 187 case ssa.OpInitMem: 188 // memory arg needs no code 189 case ssa.OpArg: 190 // input args need no code 191 case ssa.OpPhi: 192 gc.CheckLoweredPhi(v) 193 case ssa.OpCopy, ssa.OpRISCV64MOVconvert: 194 if v.Type.IsMemory() { 195 return 196 } 197 rs := v.Args[0].Reg() 198 rd := v.Reg() 199 if rs == rd { 200 return 201 } 202 as := riscv.AMOV 203 if v.Type.IsFloat() { 204 as = riscv.AMOVD 205 } 206 p := s.Prog(as) 207 p.From.Type = obj.TYPE_REG 208 p.From.Reg = rs 209 p.To.Type = obj.TYPE_REG 210 p.To.Reg = rd 211 case ssa.OpLoadReg: 212 if v.Type.IsFlags() { 213 v.Fatalf("load flags not implemented: %v", v.LongString()) 214 return 215 } 216 p := s.Prog(loadByType(v.Type)) 217 gc.AddrAuto(&p.From, v.Args[0]) 218 p.To.Type = obj.TYPE_REG 219 p.To.Reg = v.Reg() 220 case ssa.OpStoreReg: 221 if v.Type.IsFlags() { 222 v.Fatalf("store flags not implemented: %v", v.LongString()) 223 return 224 } 225 p := s.Prog(storeByType(v.Type)) 226 p.From.Type = obj.TYPE_REG 227 p.From.Reg = v.Args[0].Reg() 228 gc.AddrAuto(&p.To, v) 229 case ssa.OpSP, ssa.OpSB, ssa.OpGetG: 230 // nothing to do 231 case ssa.OpRISCV64ADD, ssa.OpRISCV64SUB, ssa.OpRISCV64XOR, ssa.OpRISCV64OR, ssa.OpRISCV64AND, 232 ssa.OpRISCV64SLL, ssa.OpRISCV64SRA, ssa.OpRISCV64SRL, 233 ssa.OpRISCV64SLT, ssa.OpRISCV64SLTU, ssa.OpRISCV64MUL, ssa.OpRISCV64MULW, ssa.OpRISCV64MULH, 234 ssa.OpRISCV64MULHU, ssa.OpRISCV64DIV, ssa.OpRISCV64DIVU, ssa.OpRISCV64DIVW, 235 ssa.OpRISCV64DIVUW, ssa.OpRISCV64REM, ssa.OpRISCV64REMU, ssa.OpRISCV64REMW, 236 ssa.OpRISCV64REMUW, 237 ssa.OpRISCV64FADDS, ssa.OpRISCV64FSUBS, ssa.OpRISCV64FMULS, ssa.OpRISCV64FDIVS, 238 ssa.OpRISCV64FEQS, ssa.OpRISCV64FNES, ssa.OpRISCV64FLTS, ssa.OpRISCV64FLES, 239 ssa.OpRISCV64FADDD, ssa.OpRISCV64FSUBD, ssa.OpRISCV64FMULD, ssa.OpRISCV64FDIVD, 240 ssa.OpRISCV64FEQD, ssa.OpRISCV64FNED, ssa.OpRISCV64FLTD, ssa.OpRISCV64FLED: 241 r := v.Reg() 242 r1 := v.Args[0].Reg() 243 r2 := v.Args[1].Reg() 244 p := s.Prog(v.Op.Asm()) 245 p.From.Type = obj.TYPE_REG 246 p.From.Reg = r2 247 p.Reg = r1 248 p.To.Type = obj.TYPE_REG 249 p.To.Reg = r 250 case ssa.OpRISCV64FSQRTS, ssa.OpRISCV64FNEGS, ssa.OpRISCV64FSQRTD, ssa.OpRISCV64FNEGD, 251 ssa.OpRISCV64FMVSX, ssa.OpRISCV64FMVDX, 252 ssa.OpRISCV64FCVTSW, ssa.OpRISCV64FCVTSL, ssa.OpRISCV64FCVTWS, ssa.OpRISCV64FCVTLS, 253 ssa.OpRISCV64FCVTDW, ssa.OpRISCV64FCVTDL, ssa.OpRISCV64FCVTWD, ssa.OpRISCV64FCVTLD, ssa.OpRISCV64FCVTDS, ssa.OpRISCV64FCVTSD: 254 p := s.Prog(v.Op.Asm()) 255 p.From.Type = obj.TYPE_REG 256 p.From.Reg = v.Args[0].Reg() 257 p.To.Type = obj.TYPE_REG 258 p.To.Reg = v.Reg() 259 case ssa.OpRISCV64ADDI, ssa.OpRISCV64XORI, ssa.OpRISCV64ORI, ssa.OpRISCV64ANDI, 260 ssa.OpRISCV64SLLI, ssa.OpRISCV64SRAI, ssa.OpRISCV64SRLI, ssa.OpRISCV64SLTI, 261 ssa.OpRISCV64SLTIU: 262 p := s.Prog(v.Op.Asm()) 263 p.From.Type = obj.TYPE_CONST 264 p.From.Offset = v.AuxInt 265 p.Reg = v.Args[0].Reg() 266 p.To.Type = obj.TYPE_REG 267 p.To.Reg = v.Reg() 268 case ssa.OpRISCV64MOVBconst, ssa.OpRISCV64MOVHconst, ssa.OpRISCV64MOVWconst, ssa.OpRISCV64MOVDconst: 269 p := s.Prog(v.Op.Asm()) 270 p.From.Type = obj.TYPE_CONST 271 p.From.Offset = v.AuxInt 272 p.To.Type = obj.TYPE_REG 273 p.To.Reg = v.Reg() 274 case ssa.OpRISCV64MOVaddr: 275 p := s.Prog(v.Op.Asm()) 276 p.From.Type = obj.TYPE_ADDR 277 p.To.Type = obj.TYPE_REG 278 p.To.Reg = v.Reg() 279 280 var wantreg string 281 // MOVW $sym+off(base), R 282 switch v.Aux.(type) { 283 default: 284 v.Fatalf("aux is of unknown type %T", v.Aux) 285 case *obj.LSym: 286 wantreg = "SB" 287 gc.AddAux(&p.From, v) 288 case *gc.Node: 289 wantreg = "SP" 290 gc.AddAux(&p.From, v) 291 case nil: 292 // No sym, just MOVW $off(SP), R 293 wantreg = "SP" 294 p.From.Reg = riscv.REG_SP 295 p.From.Offset = v.AuxInt 296 } 297 if reg := v.Args[0].RegName(); reg != wantreg { 298 v.Fatalf("bad reg %s for symbol type %T, want %s", reg, v.Aux, wantreg) 299 } 300 case ssa.OpRISCV64MOVBload, ssa.OpRISCV64MOVHload, ssa.OpRISCV64MOVWload, ssa.OpRISCV64MOVDload, 301 ssa.OpRISCV64MOVBUload, ssa.OpRISCV64MOVHUload, ssa.OpRISCV64MOVWUload, 302 ssa.OpRISCV64FMOVWload, ssa.OpRISCV64FMOVDload: 303 p := s.Prog(v.Op.Asm()) 304 p.From.Type = obj.TYPE_MEM 305 p.From.Reg = v.Args[0].Reg() 306 gc.AddAux(&p.From, v) 307 p.To.Type = obj.TYPE_REG 308 p.To.Reg = v.Reg() 309 case ssa.OpRISCV64MOVBstore, ssa.OpRISCV64MOVHstore, ssa.OpRISCV64MOVWstore, ssa.OpRISCV64MOVDstore, 310 ssa.OpRISCV64FMOVWstore, ssa.OpRISCV64FMOVDstore: 311 p := s.Prog(v.Op.Asm()) 312 p.From.Type = obj.TYPE_REG 313 p.From.Reg = v.Args[1].Reg() 314 p.To.Type = obj.TYPE_MEM 315 p.To.Reg = v.Args[0].Reg() 316 gc.AddAux(&p.To, v) 317 case ssa.OpRISCV64SEQZ, ssa.OpRISCV64SNEZ: 318 p := s.Prog(v.Op.Asm()) 319 p.From.Type = obj.TYPE_REG 320 p.From.Reg = v.Args[0].Reg() 321 p.To.Type = obj.TYPE_REG 322 p.To.Reg = v.Reg() 323 case ssa.OpRISCV64CALLstatic, ssa.OpRISCV64CALLclosure, ssa.OpRISCV64CALLinter: 324 s.Call(v) 325 case ssa.OpRISCV64LoweredWB: 326 p := s.Prog(obj.ACALL) 327 p.To.Type = obj.TYPE_MEM 328 p.To.Name = obj.NAME_EXTERN 329 p.To.Sym = v.Aux.(*obj.LSym) 330 case ssa.OpRISCV64LoweredPanicBoundsA, ssa.OpRISCV64LoweredPanicBoundsB, ssa.OpRISCV64LoweredPanicBoundsC: 331 p := s.Prog(obj.ACALL) 332 p.To.Type = obj.TYPE_MEM 333 p.To.Name = obj.NAME_EXTERN 334 p.To.Sym = gc.BoundsCheckFunc[v.AuxInt] 335 s.UseArgs(16) // space used in callee args area by assembly stubs 336 case ssa.OpRISCV64LoweredZero: 337 mov, sz := largestMove(v.AuxInt) 338 339 // mov ZERO, (Rarg0) 340 // ADD $sz, Rarg0 341 // BGEU Rarg1, Rarg0, -2(PC) 342 343 p := s.Prog(mov) 344 p.From.Type = obj.TYPE_REG 345 p.From.Reg = riscv.REG_ZERO 346 p.To.Type = obj.TYPE_MEM 347 p.To.Reg = v.Args[0].Reg() 348 349 p2 := s.Prog(riscv.AADD) 350 p2.From.Type = obj.TYPE_CONST 351 p2.From.Offset = sz 352 p2.To.Type = obj.TYPE_REG 353 p2.To.Reg = v.Args[0].Reg() 354 355 p3 := s.Prog(riscv.ABGEU) 356 p3.To.Type = obj.TYPE_BRANCH 357 p3.Reg = v.Args[0].Reg() 358 p3.From.Type = obj.TYPE_REG 359 p3.From.Reg = v.Args[1].Reg() 360 gc.Patch(p3, p) 361 362 case ssa.OpRISCV64LoweredMove: 363 mov, sz := largestMove(v.AuxInt) 364 365 // mov (Rarg1), T2 366 // mov T2, (Rarg0) 367 // ADD $sz, Rarg0 368 // ADD $sz, Rarg1 369 // BGEU Rarg2, Rarg0, -4(PC) 370 371 p := s.Prog(mov) 372 p.From.Type = obj.TYPE_MEM 373 p.From.Reg = v.Args[1].Reg() 374 p.To.Type = obj.TYPE_REG 375 p.To.Reg = riscv.REG_T2 376 377 p2 := s.Prog(mov) 378 p2.From.Type = obj.TYPE_REG 379 p2.From.Reg = riscv.REG_T2 380 p2.To.Type = obj.TYPE_MEM 381 p2.To.Reg = v.Args[0].Reg() 382 383 p3 := s.Prog(riscv.AADD) 384 p3.From.Type = obj.TYPE_CONST 385 p3.From.Offset = sz 386 p3.To.Type = obj.TYPE_REG 387 p3.To.Reg = v.Args[0].Reg() 388 389 p4 := s.Prog(riscv.AADD) 390 p4.From.Type = obj.TYPE_CONST 391 p4.From.Offset = sz 392 p4.To.Type = obj.TYPE_REG 393 p4.To.Reg = v.Args[1].Reg() 394 395 p5 := s.Prog(riscv.ABGEU) 396 p5.To.Type = obj.TYPE_BRANCH 397 p5.Reg = v.Args[1].Reg() 398 p5.From.Type = obj.TYPE_REG 399 p5.From.Reg = v.Args[2].Reg() 400 gc.Patch(p5, p) 401 402 case ssa.OpRISCV64LoweredNilCheck: 403 // Issue a load which will fault if arg is nil. 404 // TODO: optimizations. See arm and amd64 LoweredNilCheck. 405 p := s.Prog(riscv.AMOVB) 406 p.From.Type = obj.TYPE_MEM 407 p.From.Reg = v.Args[0].Reg() 408 gc.AddAux(&p.From, v) 409 p.To.Type = obj.TYPE_REG 410 p.To.Reg = riscv.REG_ZERO 411 if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos == 1 in generated wrappers 412 gc.Warnl(v.Pos, "generated nil check") 413 } 414 415 case ssa.OpRISCV64LoweredGetClosurePtr: 416 // Closure pointer is S4 (riscv.REG_CTXT). 417 gc.CheckLoweredGetClosurePtr(v) 418 419 case ssa.OpRISCV64LoweredGetCallerSP: 420 // caller's SP is FixedFrameSize below the address of the first arg 421 p := s.Prog(riscv.AMOV) 422 p.From.Type = obj.TYPE_ADDR 423 p.From.Offset = -gc.Ctxt.FixedFrameSize() 424 p.From.Name = obj.NAME_PARAM 425 p.To.Type = obj.TYPE_REG 426 p.To.Reg = v.Reg() 427 428 case ssa.OpRISCV64LoweredGetCallerPC: 429 p := s.Prog(obj.AGETCALLERPC) 430 p.To.Type = obj.TYPE_REG 431 p.To.Reg = v.Reg() 432 433 default: 434 v.Fatalf("Unhandled op %v", v.Op) 435 } 436 } 437 438 func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) { 439 s.SetPos(b.Pos) 440 441 switch b.Kind { 442 case ssa.BlockDefer: 443 // defer returns in A0: 444 // 0 if we should continue executing 445 // 1 if we should jump to deferreturn call 446 p := s.Prog(riscv.ABNE) 447 p.To.Type = obj.TYPE_BRANCH 448 p.From.Type = obj.TYPE_REG 449 p.From.Reg = riscv.REG_ZERO 450 p.Reg = riscv.REG_A0 451 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()}) 452 if b.Succs[0].Block() != next { 453 p := s.Prog(obj.AJMP) 454 p.To.Type = obj.TYPE_BRANCH 455 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) 456 } 457 case ssa.BlockPlain: 458 if b.Succs[0].Block() != next { 459 p := s.Prog(obj.AJMP) 460 p.To.Type = obj.TYPE_BRANCH 461 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) 462 } 463 case ssa.BlockExit: 464 case ssa.BlockRet: 465 s.Prog(obj.ARET) 466 case ssa.BlockRetJmp: 467 p := s.Prog(obj.AJMP) 468 p.To.Type = obj.TYPE_MEM 469 p.To.Name = obj.NAME_EXTERN 470 p.To.Sym = b.Aux.(*obj.LSym) 471 case ssa.BlockRISCV64BNE: 472 var p *obj.Prog 473 switch next { 474 case b.Succs[0].Block(): 475 p = s.Br(riscv.ABNE, b.Succs[1].Block()) 476 p.As = riscv.InvertBranch(p.As) 477 case b.Succs[1].Block(): 478 p = s.Br(riscv.ABNE, b.Succs[0].Block()) 479 default: 480 if b.Likely != ssa.BranchUnlikely { 481 p = s.Br(riscv.ABNE, b.Succs[0].Block()) 482 s.Br(obj.AJMP, b.Succs[1].Block()) 483 } else { 484 p = s.Br(riscv.ABNE, b.Succs[1].Block()) 485 p.As = riscv.InvertBranch(p.As) 486 s.Br(obj.AJMP, b.Succs[0].Block()) 487 } 488 } 489 p.Reg = b.Controls[0].Reg() 490 p.From.Type = obj.TYPE_REG 491 p.From.Reg = riscv.REG_ZERO 492 493 default: 494 b.Fatalf("Unhandled block: %s", b.LongString()) 495 } 496 }