obj.go (57153B)
1 // Copyright © 2015 The Go Authors. All rights reserved. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package riscv 22 23 import ( 24 "github.com/twitchyliquid64/golang-asm/obj" 25 "github.com/twitchyliquid64/golang-asm/objabi" 26 "github.com/twitchyliquid64/golang-asm/sys" 27 "fmt" 28 ) 29 30 func buildop(ctxt *obj.Link) {} 31 32 // jalrToSym replaces p with a set of Progs needed to jump to the Sym in p. 33 // lr is the link register to use for the JALR. 34 // p must be a CALL, JMP or RET. 35 func jalrToSym(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc, lr int16) *obj.Prog { 36 if p.As != obj.ACALL && p.As != obj.AJMP && p.As != obj.ARET { 37 ctxt.Diag("unexpected Prog in jalrToSym: %v", p) 38 return p 39 } 40 41 // TODO(jsing): Consider using a single JAL instruction and teaching 42 // the linker to provide trampolines for the case where the destination 43 // offset is too large. This would potentially reduce instructions for 44 // the common case, but would require three instructions to go via the 45 // trampoline. 46 47 to := p.To 48 49 p.As = AAUIPC 50 p.Mark |= NEED_PCREL_ITYPE_RELOC 51 p.RestArgs = []obj.Addr{obj.Addr{Type: obj.TYPE_CONST, Offset: to.Offset, Sym: to.Sym}} 52 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: 0} 53 p.Reg = 0 54 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP} 55 p = obj.Appendp(p, newprog) 56 57 // Leave Sym only for the CALL reloc in assemble. 58 p.As = AJALR 59 p.From.Type = obj.TYPE_REG 60 p.From.Reg = lr 61 p.Reg = 0 62 p.To.Type = obj.TYPE_REG 63 p.To.Reg = REG_TMP 64 p.To.Sym = to.Sym 65 66 return p 67 } 68 69 // progedit is called individually for each *obj.Prog. It normalizes instruction 70 // formats and eliminates as many pseudo-instructions as possible. 71 func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) { 72 73 // Expand binary instructions to ternary ones. 74 if p.Reg == 0 { 75 switch p.As { 76 case AADDI, ASLTI, ASLTIU, AANDI, AORI, AXORI, ASLLI, ASRLI, ASRAI, 77 AADD, AAND, AOR, AXOR, ASLL, ASRL, ASUB, ASRA, 78 AMUL, AMULH, AMULHU, AMULHSU, AMULW, ADIV, ADIVU, ADIVW, ADIVUW, 79 AREM, AREMU, AREMW, AREMUW: 80 p.Reg = p.To.Reg 81 } 82 } 83 84 // Rewrite instructions with constant operands to refer to the immediate 85 // form of the instruction. 86 if p.From.Type == obj.TYPE_CONST { 87 switch p.As { 88 case AADD: 89 p.As = AADDI 90 case ASLT: 91 p.As = ASLTI 92 case ASLTU: 93 p.As = ASLTIU 94 case AAND: 95 p.As = AANDI 96 case AOR: 97 p.As = AORI 98 case AXOR: 99 p.As = AXORI 100 case ASLL: 101 p.As = ASLLI 102 case ASRL: 103 p.As = ASRLI 104 case ASRA: 105 p.As = ASRAI 106 } 107 } 108 109 switch p.As { 110 case obj.AJMP: 111 // Turn JMP into JAL ZERO or JALR ZERO. 112 p.From.Type = obj.TYPE_REG 113 p.From.Reg = REG_ZERO 114 115 switch p.To.Type { 116 case obj.TYPE_BRANCH: 117 p.As = AJAL 118 case obj.TYPE_MEM: 119 switch p.To.Name { 120 case obj.NAME_NONE: 121 p.As = AJALR 122 case obj.NAME_EXTERN: 123 // Handled in preprocess. 124 default: 125 ctxt.Diag("unsupported name %d for %v", p.To.Name, p) 126 } 127 default: 128 panic(fmt.Sprintf("unhandled type %+v", p.To.Type)) 129 } 130 131 case obj.ACALL: 132 switch p.To.Type { 133 case obj.TYPE_MEM: 134 // Handled in preprocess. 135 case obj.TYPE_REG: 136 p.As = AJALR 137 p.From.Type = obj.TYPE_REG 138 p.From.Reg = REG_LR 139 default: 140 ctxt.Diag("unknown destination type %+v in CALL: %v", p.To.Type, p) 141 } 142 143 case obj.AUNDEF: 144 p.As = AEBREAK 145 146 case ASCALL: 147 // SCALL is the old name for ECALL. 148 p.As = AECALL 149 150 case ASBREAK: 151 // SBREAK is the old name for EBREAK. 152 p.As = AEBREAK 153 } 154 } 155 156 // addrToReg extracts the register from an Addr, handling special Addr.Names. 157 func addrToReg(a obj.Addr) int16 { 158 switch a.Name { 159 case obj.NAME_PARAM, obj.NAME_AUTO: 160 return REG_SP 161 } 162 return a.Reg 163 } 164 165 // movToLoad converts a MOV mnemonic into the corresponding load instruction. 166 func movToLoad(mnemonic obj.As) obj.As { 167 switch mnemonic { 168 case AMOV: 169 return ALD 170 case AMOVB: 171 return ALB 172 case AMOVH: 173 return ALH 174 case AMOVW: 175 return ALW 176 case AMOVBU: 177 return ALBU 178 case AMOVHU: 179 return ALHU 180 case AMOVWU: 181 return ALWU 182 case AMOVF: 183 return AFLW 184 case AMOVD: 185 return AFLD 186 default: 187 panic(fmt.Sprintf("%+v is not a MOV", mnemonic)) 188 } 189 } 190 191 // movToStore converts a MOV mnemonic into the corresponding store instruction. 192 func movToStore(mnemonic obj.As) obj.As { 193 switch mnemonic { 194 case AMOV: 195 return ASD 196 case AMOVB: 197 return ASB 198 case AMOVH: 199 return ASH 200 case AMOVW: 201 return ASW 202 case AMOVF: 203 return AFSW 204 case AMOVD: 205 return AFSD 206 default: 207 panic(fmt.Sprintf("%+v is not a MOV", mnemonic)) 208 } 209 } 210 211 // rewriteMOV rewrites MOV pseudo-instructions. 212 func rewriteMOV(ctxt *obj.Link, newprog obj.ProgAlloc, p *obj.Prog) { 213 switch p.As { 214 case AMOV, AMOVB, AMOVH, AMOVW, AMOVBU, AMOVHU, AMOVWU, AMOVF, AMOVD: 215 default: 216 panic(fmt.Sprintf("%+v is not a MOV pseudo-instruction", p.As)) 217 } 218 219 switch p.From.Type { 220 case obj.TYPE_MEM: // MOV c(Rs), Rd -> L $c, Rs, Rd 221 switch p.From.Name { 222 case obj.NAME_AUTO, obj.NAME_PARAM, obj.NAME_NONE: 223 if p.To.Type != obj.TYPE_REG { 224 ctxt.Diag("unsupported load at %v", p) 225 } 226 p.As = movToLoad(p.As) 227 p.From.Reg = addrToReg(p.From) 228 229 case obj.NAME_EXTERN, obj.NAME_STATIC: 230 // AUIPC $off_hi, R 231 // L $off_lo, R 232 as := p.As 233 to := p.To 234 235 p.As = AAUIPC 236 p.Mark |= NEED_PCREL_ITYPE_RELOC 237 p.RestArgs = []obj.Addr{obj.Addr{Type: obj.TYPE_CONST, Offset: p.From.Offset, Sym: p.From.Sym}} 238 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: 0} 239 p.Reg = 0 240 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: to.Reg} 241 p = obj.Appendp(p, newprog) 242 243 p.As = movToLoad(as) 244 p.From = obj.Addr{Type: obj.TYPE_MEM, Reg: to.Reg, Offset: 0} 245 p.To = to 246 247 default: 248 ctxt.Diag("unsupported name %d for %v", p.From.Name, p) 249 } 250 251 case obj.TYPE_REG: 252 switch p.To.Type { 253 case obj.TYPE_REG: 254 switch p.As { 255 case AMOV: // MOV Ra, Rb -> ADDI $0, Ra, Rb 256 p.As = AADDI 257 p.Reg = p.From.Reg 258 p.From = obj.Addr{Type: obj.TYPE_CONST} 259 260 case AMOVF: // MOVF Ra, Rb -> FSGNJS Ra, Ra, Rb 261 p.As = AFSGNJS 262 p.Reg = p.From.Reg 263 264 case AMOVD: // MOVD Ra, Rb -> FSGNJD Ra, Ra, Rb 265 p.As = AFSGNJD 266 p.Reg = p.From.Reg 267 268 default: 269 ctxt.Diag("unsupported register-register move at %v", p) 270 } 271 272 case obj.TYPE_MEM: // MOV Rs, c(Rd) -> S $c, Rs, Rd 273 switch p.As { 274 case AMOVBU, AMOVHU, AMOVWU: 275 ctxt.Diag("unsupported unsigned store at %v", p) 276 } 277 switch p.To.Name { 278 case obj.NAME_AUTO, obj.NAME_PARAM, obj.NAME_NONE: 279 p.As = movToStore(p.As) 280 p.To.Reg = addrToReg(p.To) 281 282 case obj.NAME_EXTERN: 283 // AUIPC $off_hi, TMP 284 // S $off_lo, TMP, R 285 as := p.As 286 from := p.From 287 288 p.As = AAUIPC 289 p.Mark |= NEED_PCREL_STYPE_RELOC 290 p.RestArgs = []obj.Addr{obj.Addr{Type: obj.TYPE_CONST, Offset: p.To.Offset, Sym: p.To.Sym}} 291 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: 0} 292 p.Reg = 0 293 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP} 294 p = obj.Appendp(p, newprog) 295 296 p.As = movToStore(as) 297 p.From = from 298 p.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_TMP, Offset: 0} 299 300 default: 301 ctxt.Diag("unsupported name %d for %v", p.From.Name, p) 302 } 303 304 default: 305 ctxt.Diag("unsupported MOV at %v", p) 306 } 307 308 case obj.TYPE_CONST: 309 // MOV $c, R 310 // If c is small enough, convert to: 311 // ADD $c, ZERO, R 312 // If not, convert to: 313 // LUI top20bits(c), R 314 // ADD bottom12bits(c), R, R 315 if p.As != AMOV { 316 ctxt.Diag("unsupported constant load at %v", p) 317 } 318 off := p.From.Offset 319 to := p.To 320 321 low, high, err := Split32BitImmediate(off) 322 if err != nil { 323 ctxt.Diag("%v: constant %d too large: %v", p, off, err) 324 } 325 326 // LUI is only necessary if the offset doesn't fit in 12-bits. 327 needLUI := high != 0 328 if needLUI { 329 p.As = ALUI 330 p.To = to 331 // Pass top 20 bits to LUI. 332 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: high} 333 p = obj.Appendp(p, newprog) 334 } 335 p.As = AADDIW 336 p.To = to 337 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: low} 338 p.Reg = REG_ZERO 339 if needLUI { 340 p.Reg = to.Reg 341 } 342 343 case obj.TYPE_ADDR: // MOV $sym+off(SP/SB), R 344 if p.To.Type != obj.TYPE_REG || p.As != AMOV { 345 ctxt.Diag("unsupported addr MOV at %v", p) 346 } 347 switch p.From.Name { 348 case obj.NAME_EXTERN, obj.NAME_STATIC: 349 // AUIPC $off_hi, R 350 // ADDI $off_lo, R 351 to := p.To 352 353 p.As = AAUIPC 354 p.Mark |= NEED_PCREL_ITYPE_RELOC 355 p.RestArgs = []obj.Addr{obj.Addr{Type: obj.TYPE_CONST, Offset: p.From.Offset, Sym: p.From.Sym}} 356 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: 0} 357 p.Reg = 0 358 p.To = to 359 p = obj.Appendp(p, newprog) 360 361 p.As = AADDI 362 p.From = obj.Addr{Type: obj.TYPE_CONST} 363 p.Reg = to.Reg 364 p.To = to 365 366 case obj.NAME_PARAM, obj.NAME_AUTO: 367 p.As = AADDI 368 p.Reg = REG_SP 369 p.From.Type = obj.TYPE_CONST 370 371 case obj.NAME_NONE: 372 p.As = AADDI 373 p.Reg = p.From.Reg 374 p.From.Type = obj.TYPE_CONST 375 p.From.Reg = 0 376 377 default: 378 ctxt.Diag("bad addr MOV from name %v at %v", p.From.Name, p) 379 } 380 381 default: 382 ctxt.Diag("unsupported MOV at %v", p) 383 } 384 } 385 386 // InvertBranch inverts the condition of a conditional branch. 387 func InvertBranch(as obj.As) obj.As { 388 switch as { 389 case ABEQ: 390 return ABNE 391 case ABEQZ: 392 return ABNEZ 393 case ABGE: 394 return ABLT 395 case ABGEU: 396 return ABLTU 397 case ABGEZ: 398 return ABLTZ 399 case ABGT: 400 return ABLE 401 case ABGTU: 402 return ABLEU 403 case ABGTZ: 404 return ABLEZ 405 case ABLE: 406 return ABGT 407 case ABLEU: 408 return ABGTU 409 case ABLEZ: 410 return ABGTZ 411 case ABLT: 412 return ABGE 413 case ABLTU: 414 return ABGEU 415 case ABLTZ: 416 return ABGEZ 417 case ABNE: 418 return ABEQ 419 case ABNEZ: 420 return ABEQZ 421 default: 422 panic("InvertBranch: not a branch") 423 } 424 } 425 426 // containsCall reports whether the symbol contains a CALL (or equivalent) 427 // instruction. Must be called after progedit. 428 func containsCall(sym *obj.LSym) bool { 429 // CALLs are CALL or JAL(R) with link register LR. 430 for p := sym.Func.Text; p != nil; p = p.Link { 431 switch p.As { 432 case obj.ACALL: 433 return true 434 case AJAL, AJALR: 435 if p.From.Type == obj.TYPE_REG && p.From.Reg == REG_LR { 436 return true 437 } 438 } 439 } 440 441 return false 442 } 443 444 // setPCs sets the Pc field in all instructions reachable from p. 445 // It uses pc as the initial value. 446 func setPCs(p *obj.Prog, pc int64) { 447 for ; p != nil; p = p.Link { 448 p.Pc = pc 449 for _, ins := range instructionsForProg(p) { 450 pc += int64(ins.length()) 451 } 452 } 453 } 454 455 // stackOffset updates Addr offsets based on the current stack size. 456 // 457 // The stack looks like: 458 // ------------------- 459 // | | 460 // | PARAMs | 461 // | | 462 // | | 463 // ------------------- 464 // | Parent RA | SP on function entry 465 // ------------------- 466 // | | 467 // | | 468 // | AUTOs | 469 // | | 470 // | | 471 // ------------------- 472 // | RA | SP during function execution 473 // ------------------- 474 // 475 // FixedFrameSize makes other packages aware of the space allocated for RA. 476 // 477 // A nicer version of this diagram can be found on slide 21 of the presentation 478 // attached to: 479 // 480 // https://golang.org/issue/16922#issuecomment-243748180 481 // 482 func stackOffset(a *obj.Addr, stacksize int64) { 483 switch a.Name { 484 case obj.NAME_AUTO: 485 // Adjust to the top of AUTOs. 486 a.Offset += stacksize 487 case obj.NAME_PARAM: 488 // Adjust to the bottom of PARAMs. 489 a.Offset += stacksize + 8 490 } 491 } 492 493 // preprocess generates prologue and epilogue code, computes PC-relative branch 494 // and jump offsets, and resolves pseudo-registers. 495 // 496 // preprocess is called once per linker symbol. 497 // 498 // When preprocess finishes, all instructions in the symbol are either 499 // concrete, real RISC-V instructions or directive pseudo-ops like TEXT, 500 // PCDATA, and FUNCDATA. 501 func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { 502 if cursym.Func.Text == nil || cursym.Func.Text.Link == nil { 503 return 504 } 505 506 // Generate the prologue. 507 text := cursym.Func.Text 508 if text.As != obj.ATEXT { 509 ctxt.Diag("preprocess: found symbol that does not start with TEXT directive") 510 return 511 } 512 513 stacksize := text.To.Offset 514 if stacksize == -8 { 515 // Historical way to mark NOFRAME. 516 text.From.Sym.Set(obj.AttrNoFrame, true) 517 stacksize = 0 518 } 519 if stacksize < 0 { 520 ctxt.Diag("negative frame size %d - did you mean NOFRAME?", stacksize) 521 } 522 if text.From.Sym.NoFrame() { 523 if stacksize != 0 { 524 ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", stacksize) 525 } 526 } 527 528 if !containsCall(cursym) { 529 text.From.Sym.Set(obj.AttrLeaf, true) 530 if stacksize == 0 { 531 // A leaf function with no locals has no frame. 532 text.From.Sym.Set(obj.AttrNoFrame, true) 533 } 534 } 535 536 // Save LR unless there is no frame. 537 if !text.From.Sym.NoFrame() { 538 stacksize += ctxt.FixedFrameSize() 539 } 540 541 cursym.Func.Args = text.To.Val.(int32) 542 cursym.Func.Locals = int32(stacksize) 543 544 prologue := text 545 546 if !cursym.Func.Text.From.Sym.NoSplit() { 547 prologue = stacksplit(ctxt, prologue, cursym, newprog, stacksize) // emit split check 548 } 549 550 if stacksize != 0 { 551 prologue = ctxt.StartUnsafePoint(prologue, newprog) 552 553 // Actually save LR. 554 prologue = obj.Appendp(prologue, newprog) 555 prologue.As = AMOV 556 prologue.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR} 557 prologue.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_SP, Offset: -stacksize} 558 559 // Insert stack adjustment. 560 prologue = obj.Appendp(prologue, newprog) 561 prologue.As = AADDI 562 prologue.From = obj.Addr{Type: obj.TYPE_CONST, Offset: -stacksize} 563 prologue.Reg = REG_SP 564 prologue.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_SP} 565 prologue.Spadj = int32(stacksize) 566 567 prologue = ctxt.EndUnsafePoint(prologue, newprog, -1) 568 } 569 570 if cursym.Func.Text.From.Sym.Wrapper() { 571 // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame 572 // 573 // MOV g_panic(g), X11 574 // BNE X11, ZERO, adjust 575 // end: 576 // NOP 577 // ...rest of function.. 578 // adjust: 579 // MOV panic_argp(X11), X12 580 // ADD $(autosize+FIXED_FRAME), SP, X13 581 // BNE X12, X13, end 582 // ADD $FIXED_FRAME, SP, X12 583 // MOV X12, panic_argp(X11) 584 // JMP end 585 // 586 // The NOP is needed to give the jumps somewhere to land. 587 588 ldpanic := obj.Appendp(prologue, newprog) 589 590 ldpanic.As = AMOV 591 ldpanic.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REGG, Offset: 4 * int64(ctxt.Arch.PtrSize)} // G.panic 592 ldpanic.Reg = 0 593 ldpanic.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X11} 594 595 bneadj := obj.Appendp(ldpanic, newprog) 596 bneadj.As = ABNE 597 bneadj.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X11} 598 bneadj.Reg = REG_ZERO 599 bneadj.To.Type = obj.TYPE_BRANCH 600 601 endadj := obj.Appendp(bneadj, newprog) 602 endadj.As = obj.ANOP 603 604 last := endadj 605 for last.Link != nil { 606 last = last.Link 607 } 608 609 getargp := obj.Appendp(last, newprog) 610 getargp.As = AMOV 611 getargp.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_X11, Offset: 0} // Panic.argp 612 getargp.Reg = 0 613 getargp.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X12} 614 615 bneadj.To.SetTarget(getargp) 616 617 calcargp := obj.Appendp(getargp, newprog) 618 calcargp.As = AADDI 619 calcargp.From = obj.Addr{Type: obj.TYPE_CONST, Offset: stacksize + ctxt.FixedFrameSize()} 620 calcargp.Reg = REG_SP 621 calcargp.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X13} 622 623 testargp := obj.Appendp(calcargp, newprog) 624 testargp.As = ABNE 625 testargp.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X12} 626 testargp.Reg = REG_X13 627 testargp.To.Type = obj.TYPE_BRANCH 628 testargp.To.SetTarget(endadj) 629 630 adjargp := obj.Appendp(testargp, newprog) 631 adjargp.As = AADDI 632 adjargp.From = obj.Addr{Type: obj.TYPE_CONST, Offset: int64(ctxt.Arch.PtrSize)} 633 adjargp.Reg = REG_SP 634 adjargp.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X12} 635 636 setargp := obj.Appendp(adjargp, newprog) 637 setargp.As = AMOV 638 setargp.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X12} 639 setargp.Reg = 0 640 setargp.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_X11, Offset: 0} // Panic.argp 641 642 godone := obj.Appendp(setargp, newprog) 643 godone.As = AJAL 644 godone.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_ZERO} 645 godone.To.Type = obj.TYPE_BRANCH 646 godone.To.SetTarget(endadj) 647 } 648 649 // Update stack-based offsets. 650 for p := cursym.Func.Text; p != nil; p = p.Link { 651 stackOffset(&p.From, stacksize) 652 stackOffset(&p.To, stacksize) 653 } 654 655 // Additional instruction rewriting. 656 for p := cursym.Func.Text; p != nil; p = p.Link { 657 switch p.As { 658 case obj.AGETCALLERPC: 659 if cursym.Leaf() { 660 // MOV LR, Rd 661 p.As = AMOV 662 p.From.Type = obj.TYPE_REG 663 p.From.Reg = REG_LR 664 } else { 665 // MOV (RSP), Rd 666 p.As = AMOV 667 p.From.Type = obj.TYPE_MEM 668 p.From.Reg = REG_SP 669 } 670 671 case obj.ACALL: 672 switch p.To.Type { 673 case obj.TYPE_MEM: 674 jalrToSym(ctxt, p, newprog, REG_LR) 675 } 676 677 case obj.AJMP: 678 switch p.To.Type { 679 case obj.TYPE_MEM: 680 switch p.To.Name { 681 case obj.NAME_EXTERN: 682 // JMP to symbol. 683 jalrToSym(ctxt, p, newprog, REG_ZERO) 684 } 685 } 686 687 case obj.ARET: 688 // Replace RET with epilogue. 689 retJMP := p.To.Sym 690 691 if stacksize != 0 { 692 // Restore LR. 693 p.As = AMOV 694 p.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_SP, Offset: 0} 695 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR} 696 p = obj.Appendp(p, newprog) 697 698 p.As = AADDI 699 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: stacksize} 700 p.Reg = REG_SP 701 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_SP} 702 p.Spadj = int32(-stacksize) 703 p = obj.Appendp(p, newprog) 704 } 705 706 if retJMP != nil { 707 p.As = obj.ARET 708 p.To.Sym = retJMP 709 p = jalrToSym(ctxt, p, newprog, REG_ZERO) 710 } else { 711 p.As = AJALR 712 p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_ZERO} 713 p.Reg = 0 714 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR} 715 } 716 717 // "Add back" the stack removed in the previous instruction. 718 // 719 // This is to avoid confusing pctospadj, which sums 720 // Spadj from function entry to each PC, and shouldn't 721 // count adjustments from earlier epilogues, since they 722 // won't affect later PCs. 723 p.Spadj = int32(stacksize) 724 725 case AADDI: 726 // Refine Spadjs account for adjustment via ADDI instruction. 727 if p.To.Type == obj.TYPE_REG && p.To.Reg == REG_SP && p.From.Type == obj.TYPE_CONST { 728 p.Spadj = int32(-p.From.Offset) 729 } 730 } 731 } 732 733 // Rewrite MOV pseudo-instructions. This cannot be done in 734 // progedit, as SP offsets need to be applied before we split 735 // up some of the Addrs. 736 for p := cursym.Func.Text; p != nil; p = p.Link { 737 switch p.As { 738 case AMOV, AMOVB, AMOVH, AMOVW, AMOVBU, AMOVHU, AMOVWU, AMOVF, AMOVD: 739 rewriteMOV(ctxt, newprog, p) 740 } 741 } 742 743 // Split immediates larger than 12-bits. 744 for p := cursym.Func.Text; p != nil; p = p.Link { 745 switch p.As { 746 // <opi> $imm, REG, TO 747 case AADDI, AANDI, AORI, AXORI: 748 // LUI $high, TMP 749 // ADDI $low, TMP, TMP 750 // <op> TMP, REG, TO 751 q := *p 752 low, high, err := Split32BitImmediate(p.From.Offset) 753 if err != nil { 754 ctxt.Diag("%v: constant %d too large", p, p.From.Offset, err) 755 } 756 if high == 0 { 757 break // no need to split 758 } 759 760 p.As = ALUI 761 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: high} 762 p.Reg = 0 763 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP} 764 p.Spadj = 0 // needed if TO is SP 765 p = obj.Appendp(p, newprog) 766 767 p.As = AADDIW 768 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: low} 769 p.Reg = REG_TMP 770 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP} 771 p = obj.Appendp(p, newprog) 772 773 switch q.As { 774 case AADDI: 775 p.As = AADD 776 case AANDI: 777 p.As = AAND 778 case AORI: 779 p.As = AOR 780 case AXORI: 781 p.As = AXOR 782 default: 783 ctxt.Diag("unsupported instruction %v for splitting", q) 784 } 785 p.Spadj = q.Spadj 786 p.To = q.To 787 p.Reg = q.Reg 788 p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP} 789 790 // <load> $imm, REG, TO (load $imm+(REG), TO) 791 case ALD, ALB, ALH, ALW, ALBU, ALHU, ALWU, AFLW, AFLD: 792 low, high, err := Split32BitImmediate(p.From.Offset) 793 if err != nil { 794 ctxt.Diag("%v: constant %d too large", p, p.From.Offset) 795 } 796 if high == 0 { 797 break // no need to split 798 } 799 q := *p 800 801 // LUI $high, TMP 802 // ADD TMP, REG, TMP 803 // <load> $low, TMP, TO 804 p.As = ALUI 805 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: high} 806 p.Reg = 0 807 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP} 808 p.Spadj = 0 // needed if TO is SP 809 p = obj.Appendp(p, newprog) 810 811 p.As = AADD 812 p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP} 813 p.Reg = q.From.Reg 814 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP} 815 p = obj.Appendp(p, newprog) 816 817 p.As = q.As 818 p.To = q.To 819 p.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_TMP, Offset: low} 820 p.Reg = obj.REG_NONE 821 822 // <store> $imm, REG, TO (store $imm+(TO), REG) 823 case ASD, ASB, ASH, ASW, AFSW, AFSD: 824 low, high, err := Split32BitImmediate(p.To.Offset) 825 if err != nil { 826 ctxt.Diag("%v: constant %d too large", p, p.To.Offset) 827 } 828 if high == 0 { 829 break // no need to split 830 } 831 q := *p 832 833 // LUI $high, TMP 834 // ADD TMP, TO, TMP 835 // <store> $low, REG, TMP 836 p.As = ALUI 837 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: high} 838 p.Reg = 0 839 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP} 840 p.Spadj = 0 // needed if TO is SP 841 p = obj.Appendp(p, newprog) 842 843 p.As = AADD 844 p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP} 845 p.Reg = q.To.Reg 846 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP} 847 p = obj.Appendp(p, newprog) 848 849 p.As = q.As 850 p.From = obj.Addr{Type: obj.TYPE_REG, Reg: q.From.Reg, Offset: 0} 851 p.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_TMP, Offset: low} 852 } 853 } 854 855 // Compute instruction addresses. Once we do that, we need to check for 856 // overextended jumps and branches. Within each iteration, Pc differences 857 // are always lower bounds (since the program gets monotonically longer, 858 // a fixed point will be reached). No attempt to handle functions > 2GiB. 859 for { 860 rescan := false 861 setPCs(cursym.Func.Text, 0) 862 863 for p := cursym.Func.Text; p != nil; p = p.Link { 864 switch p.As { 865 case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ: 866 if p.To.Type != obj.TYPE_BRANCH { 867 panic("assemble: instruction with branch-like opcode lacks destination") 868 } 869 offset := p.To.Target().Pc - p.Pc 870 if offset < -4096 || 4096 <= offset { 871 // Branch is long. Replace it with a jump. 872 jmp := obj.Appendp(p, newprog) 873 jmp.As = AJAL 874 jmp.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_ZERO} 875 jmp.To = obj.Addr{Type: obj.TYPE_BRANCH} 876 jmp.To.SetTarget(p.To.Target()) 877 878 p.As = InvertBranch(p.As) 879 p.To.SetTarget(jmp.Link) 880 881 // We may have made previous branches too long, 882 // so recheck them. 883 rescan = true 884 } 885 case AJAL: 886 if p.To.Target() == nil { 887 panic("intersymbol jumps should be expressed as AUIPC+JALR") 888 } 889 offset := p.To.Target().Pc - p.Pc 890 if offset < -(1<<20) || (1<<20) <= offset { 891 // Replace with 2-instruction sequence. This assumes 892 // that TMP is not live across J instructions, since 893 // it is reserved by SSA. 894 jmp := obj.Appendp(p, newprog) 895 jmp.As = AJALR 896 jmp.From = p.From 897 jmp.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP} 898 899 // p.From is not generally valid, however will be 900 // fixed up in the next loop. 901 p.As = AAUIPC 902 p.From = obj.Addr{Type: obj.TYPE_BRANCH, Sym: p.From.Sym} 903 p.From.SetTarget(p.To.Target()) 904 p.Reg = 0 905 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP} 906 907 rescan = true 908 } 909 } 910 } 911 912 if !rescan { 913 break 914 } 915 } 916 917 // Now that there are no long branches, resolve branch and jump targets. 918 // At this point, instruction rewriting which changes the number of 919 // instructions will break everything--don't do it! 920 for p := cursym.Func.Text; p != nil; p = p.Link { 921 switch p.As { 922 case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ, AJAL: 923 switch p.To.Type { 924 case obj.TYPE_BRANCH: 925 p.To.Type, p.To.Offset = obj.TYPE_CONST, p.To.Target().Pc-p.Pc 926 case obj.TYPE_MEM: 927 panic("unhandled type") 928 } 929 930 case AAUIPC: 931 if p.From.Type == obj.TYPE_BRANCH { 932 low, high, err := Split32BitImmediate(p.From.Target().Pc - p.Pc) 933 if err != nil { 934 ctxt.Diag("%v: jump displacement %d too large", p, p.To.Target().Pc-p.Pc) 935 } 936 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: high, Sym: cursym} 937 p.Link.From.Offset = low 938 } 939 } 940 } 941 942 // Validate all instructions - this provides nice error messages. 943 for p := cursym.Func.Text; p != nil; p = p.Link { 944 for _, ins := range instructionsForProg(p) { 945 ins.validate(ctxt) 946 } 947 } 948 } 949 950 func stacksplit(ctxt *obj.Link, p *obj.Prog, cursym *obj.LSym, newprog obj.ProgAlloc, framesize int64) *obj.Prog { 951 // Leaf function with no frame is effectively NOSPLIT. 952 if framesize == 0 { 953 return p 954 } 955 956 // MOV g_stackguard(g), X10 957 p = obj.Appendp(p, newprog) 958 p.As = AMOV 959 p.From.Type = obj.TYPE_MEM 960 p.From.Reg = REGG 961 p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0 962 if cursym.CFunc() { 963 p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1 964 } 965 p.To.Type = obj.TYPE_REG 966 p.To.Reg = REG_X10 967 968 var to_done, to_more *obj.Prog 969 970 if framesize <= objabi.StackSmall { 971 // small stack: SP < stackguard 972 // BLTU SP, stackguard, done 973 p = obj.Appendp(p, newprog) 974 p.As = ABLTU 975 p.From.Type = obj.TYPE_REG 976 p.From.Reg = REG_X10 977 p.Reg = REG_SP 978 p.To.Type = obj.TYPE_BRANCH 979 to_done = p 980 } else if framesize <= objabi.StackBig { 981 // large stack: SP-framesize < stackguard-StackSmall 982 // ADD $-(framesize-StackSmall), SP, X11 983 // BLTU X11, stackguard, done 984 p = obj.Appendp(p, newprog) 985 // TODO(sorear): logic inconsistent with comment, but both match all non-x86 arches 986 p.As = AADDI 987 p.From.Type = obj.TYPE_CONST 988 p.From.Offset = -(int64(framesize) - objabi.StackSmall) 989 p.Reg = REG_SP 990 p.To.Type = obj.TYPE_REG 991 p.To.Reg = REG_X11 992 993 p = obj.Appendp(p, newprog) 994 p.As = ABLTU 995 p.From.Type = obj.TYPE_REG 996 p.From.Reg = REG_X10 997 p.Reg = REG_X11 998 p.To.Type = obj.TYPE_BRANCH 999 to_done = p 1000 } else { 1001 // Such a large stack we need to protect against wraparound. 1002 // If SP is close to zero: 1003 // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall) 1004 // The +StackGuard on both sides is required to keep the left side positive: 1005 // SP is allowed to be slightly below stackguard. See stack.h. 1006 // 1007 // Preemption sets stackguard to StackPreempt, a very large value. 1008 // That breaks the math above, so we have to check for that explicitly. 1009 // // stackguard is X10 1010 // MOV $StackPreempt, X11 1011 // BEQ X10, X11, more 1012 // ADD $StackGuard, SP, X11 1013 // SUB X10, X11 1014 // MOV $(framesize+(StackGuard-StackSmall)), X10 1015 // BGTU X11, X10, done 1016 p = obj.Appendp(p, newprog) 1017 p.As = AMOV 1018 p.From.Type = obj.TYPE_CONST 1019 p.From.Offset = objabi.StackPreempt 1020 p.To.Type = obj.TYPE_REG 1021 p.To.Reg = REG_X11 1022 1023 p = obj.Appendp(p, newprog) 1024 to_more = p 1025 p.As = ABEQ 1026 p.From.Type = obj.TYPE_REG 1027 p.From.Reg = REG_X10 1028 p.Reg = REG_X11 1029 p.To.Type = obj.TYPE_BRANCH 1030 1031 p = obj.Appendp(p, newprog) 1032 p.As = AADDI 1033 p.From.Type = obj.TYPE_CONST 1034 p.From.Offset = int64(objabi.StackGuard) 1035 p.Reg = REG_SP 1036 p.To.Type = obj.TYPE_REG 1037 p.To.Reg = REG_X11 1038 1039 p = obj.Appendp(p, newprog) 1040 p.As = ASUB 1041 p.From.Type = obj.TYPE_REG 1042 p.From.Reg = REG_X10 1043 p.Reg = REG_X11 1044 p.To.Type = obj.TYPE_REG 1045 p.To.Reg = REG_X11 1046 1047 p = obj.Appendp(p, newprog) 1048 p.As = AMOV 1049 p.From.Type = obj.TYPE_CONST 1050 p.From.Offset = int64(framesize) + int64(objabi.StackGuard) - objabi.StackSmall 1051 p.To.Type = obj.TYPE_REG 1052 p.To.Reg = REG_X10 1053 1054 p = obj.Appendp(p, newprog) 1055 p.As = ABLTU 1056 p.From.Type = obj.TYPE_REG 1057 p.From.Reg = REG_X10 1058 p.Reg = REG_X11 1059 p.To.Type = obj.TYPE_BRANCH 1060 to_done = p 1061 } 1062 1063 p = ctxt.EmitEntryLiveness(cursym, p, newprog) 1064 1065 // CALL runtime.morestack(SB) 1066 p = obj.Appendp(p, newprog) 1067 p.As = obj.ACALL 1068 p.To.Type = obj.TYPE_BRANCH 1069 if cursym.CFunc() { 1070 p.To.Sym = ctxt.Lookup("runtime.morestackc") 1071 } else if !cursym.Func.Text.From.Sym.NeedCtxt() { 1072 p.To.Sym = ctxt.Lookup("runtime.morestack_noctxt") 1073 } else { 1074 p.To.Sym = ctxt.Lookup("runtime.morestack") 1075 } 1076 if to_more != nil { 1077 to_more.To.SetTarget(p) 1078 } 1079 p = jalrToSym(ctxt, p, newprog, REG_X5) 1080 1081 // JMP start 1082 p = obj.Appendp(p, newprog) 1083 p.As = AJAL 1084 p.To = obj.Addr{Type: obj.TYPE_BRANCH} 1085 p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_ZERO} 1086 p.To.SetTarget(cursym.Func.Text.Link) 1087 1088 // placeholder for to_done's jump target 1089 p = obj.Appendp(p, newprog) 1090 p.As = obj.ANOP // zero-width place holder 1091 to_done.To.SetTarget(p) 1092 1093 return p 1094 } 1095 1096 // signExtend sign extends val starting at bit bit. 1097 func signExtend(val int64, bit uint) int64 { 1098 return val << (64 - bit) >> (64 - bit) 1099 } 1100 1101 // Split32BitImmediate splits a signed 32-bit immediate into a signed 20-bit 1102 // upper immediate and a signed 12-bit lower immediate to be added to the upper 1103 // result. For example, high may be used in LUI and low in a following ADDI to 1104 // generate a full 32-bit constant. 1105 func Split32BitImmediate(imm int64) (low, high int64, err error) { 1106 if !immIFits(imm, 32) { 1107 return 0, 0, fmt.Errorf("immediate does not fit in 32-bits: %d", imm) 1108 } 1109 1110 // Nothing special needs to be done if the immediate fits in 12-bits. 1111 if immIFits(imm, 12) { 1112 return imm, 0, nil 1113 } 1114 1115 high = imm >> 12 1116 1117 // The bottom 12 bits will be treated as signed. 1118 // 1119 // If that will result in a negative 12 bit number, add 1 to 1120 // our upper bits to adjust for the borrow. 1121 // 1122 // It is not possible for this increment to overflow. To 1123 // overflow, the 20 top bits would be 1, and the sign bit for 1124 // the low 12 bits would be set, in which case the entire 32 1125 // bit pattern fits in a 12 bit signed value. 1126 if imm&(1<<11) != 0 { 1127 high++ 1128 } 1129 1130 low = signExtend(imm, 12) 1131 high = signExtend(high, 20) 1132 1133 return low, high, nil 1134 } 1135 1136 func regVal(r, min, max uint32) uint32 { 1137 if r < min || r > max { 1138 panic(fmt.Sprintf("register out of range, want %d < %d < %d", min, r, max)) 1139 } 1140 return r - min 1141 } 1142 1143 // regI returns an integer register. 1144 func regI(r uint32) uint32 { 1145 return regVal(r, REG_X0, REG_X31) 1146 } 1147 1148 // regF returns a float register. 1149 func regF(r uint32) uint32 { 1150 return regVal(r, REG_F0, REG_F31) 1151 } 1152 1153 // regAddr extracts a register from an Addr. 1154 func regAddr(a obj.Addr, min, max uint32) uint32 { 1155 if a.Type != obj.TYPE_REG { 1156 panic(fmt.Sprintf("ill typed: %+v", a)) 1157 } 1158 return regVal(uint32(a.Reg), min, max) 1159 } 1160 1161 // regIAddr extracts the integer register from an Addr. 1162 func regIAddr(a obj.Addr) uint32 { 1163 return regAddr(a, REG_X0, REG_X31) 1164 } 1165 1166 // regFAddr extracts the float register from an Addr. 1167 func regFAddr(a obj.Addr) uint32 { 1168 return regAddr(a, REG_F0, REG_F31) 1169 } 1170 1171 // immIFits reports whether immediate value x fits in nbits bits 1172 // as a signed integer. 1173 func immIFits(x int64, nbits uint) bool { 1174 nbits-- 1175 var min int64 = -1 << nbits 1176 var max int64 = 1<<nbits - 1 1177 return min <= x && x <= max 1178 } 1179 1180 // immI extracts the signed integer of the specified size from an immediate. 1181 func immI(as obj.As, imm int64, nbits uint) uint32 { 1182 if !immIFits(imm, nbits) { 1183 panic(fmt.Sprintf("%v\tsigned immediate %d cannot fit in %d bits", as, imm, nbits)) 1184 } 1185 return uint32(imm) 1186 } 1187 1188 func wantImmI(ctxt *obj.Link, as obj.As, imm int64, nbits uint) { 1189 if !immIFits(imm, nbits) { 1190 ctxt.Diag("%v\tsigned immediate cannot be larger than %d bits but got %d", as, nbits, imm) 1191 } 1192 } 1193 1194 func wantReg(ctxt *obj.Link, as obj.As, pos string, descr string, r, min, max uint32) { 1195 if r < min || r > max { 1196 var suffix string 1197 if r != obj.REG_NONE { 1198 suffix = fmt.Sprintf(" but got non-%s register %s", descr, RegName(int(r))) 1199 } 1200 ctxt.Diag("%v\texpected %s register in %s position%s", as, descr, pos, suffix) 1201 } 1202 } 1203 1204 func wantNoneReg(ctxt *obj.Link, as obj.As, pos string, r uint32) { 1205 if r != obj.REG_NONE { 1206 ctxt.Diag("%v\texpected no register in %s but got register %s", as, pos, RegName(int(r))) 1207 } 1208 } 1209 1210 // wantIntReg checks that r is an integer register. 1211 func wantIntReg(ctxt *obj.Link, as obj.As, pos string, r uint32) { 1212 wantReg(ctxt, as, pos, "integer", r, REG_X0, REG_X31) 1213 } 1214 1215 // wantFloatReg checks that r is a floating-point register. 1216 func wantFloatReg(ctxt *obj.Link, as obj.As, pos string, r uint32) { 1217 wantReg(ctxt, as, pos, "float", r, REG_F0, REG_F31) 1218 } 1219 1220 // wantEvenOffset checks that the offset is a multiple of two. 1221 func wantEvenOffset(ctxt *obj.Link, as obj.As, offset int64) { 1222 if offset%1 != 0 { 1223 ctxt.Diag("%v\tjump offset %v must be even", as, offset) 1224 } 1225 } 1226 1227 func validateRIII(ctxt *obj.Link, ins *instruction) { 1228 wantIntReg(ctxt, ins.as, "rd", ins.rd) 1229 wantIntReg(ctxt, ins.as, "rs1", ins.rs1) 1230 wantIntReg(ctxt, ins.as, "rs2", ins.rs2) 1231 } 1232 1233 func validateRFFF(ctxt *obj.Link, ins *instruction) { 1234 wantFloatReg(ctxt, ins.as, "rd", ins.rd) 1235 wantFloatReg(ctxt, ins.as, "rs1", ins.rs1) 1236 wantFloatReg(ctxt, ins.as, "rs2", ins.rs2) 1237 } 1238 1239 func validateRFFI(ctxt *obj.Link, ins *instruction) { 1240 wantIntReg(ctxt, ins.as, "rd", ins.rd) 1241 wantFloatReg(ctxt, ins.as, "rs1", ins.rs1) 1242 wantFloatReg(ctxt, ins.as, "rs2", ins.rs2) 1243 } 1244 1245 func validateRFI(ctxt *obj.Link, ins *instruction) { 1246 wantIntReg(ctxt, ins.as, "rd", ins.rd) 1247 wantNoneReg(ctxt, ins.as, "rs1", ins.rs1) 1248 wantFloatReg(ctxt, ins.as, "rs2", ins.rs2) 1249 } 1250 1251 func validateRIF(ctxt *obj.Link, ins *instruction) { 1252 wantFloatReg(ctxt, ins.as, "rd", ins.rd) 1253 wantNoneReg(ctxt, ins.as, "rs1", ins.rs1) 1254 wantIntReg(ctxt, ins.as, "rs2", ins.rs2) 1255 } 1256 1257 func validateRFF(ctxt *obj.Link, ins *instruction) { 1258 wantFloatReg(ctxt, ins.as, "rd", ins.rd) 1259 wantNoneReg(ctxt, ins.as, "rs1", ins.rs1) 1260 wantFloatReg(ctxt, ins.as, "rs2", ins.rs2) 1261 } 1262 1263 func validateII(ctxt *obj.Link, ins *instruction) { 1264 wantImmI(ctxt, ins.as, ins.imm, 12) 1265 wantIntReg(ctxt, ins.as, "rd", ins.rd) 1266 wantIntReg(ctxt, ins.as, "rs1", ins.rs1) 1267 } 1268 1269 func validateIF(ctxt *obj.Link, ins *instruction) { 1270 wantImmI(ctxt, ins.as, ins.imm, 12) 1271 wantFloatReg(ctxt, ins.as, "rd", ins.rd) 1272 wantIntReg(ctxt, ins.as, "rs1", ins.rs1) 1273 } 1274 1275 func validateSI(ctxt *obj.Link, ins *instruction) { 1276 wantImmI(ctxt, ins.as, ins.imm, 12) 1277 wantIntReg(ctxt, ins.as, "rd", ins.rd) 1278 wantIntReg(ctxt, ins.as, "rs1", ins.rs1) 1279 } 1280 1281 func validateSF(ctxt *obj.Link, ins *instruction) { 1282 wantImmI(ctxt, ins.as, ins.imm, 12) 1283 wantIntReg(ctxt, ins.as, "rd", ins.rd) 1284 wantFloatReg(ctxt, ins.as, "rs1", ins.rs1) 1285 } 1286 1287 func validateB(ctxt *obj.Link, ins *instruction) { 1288 // Offsets are multiples of two, so accept 13 bit immediates for the 1289 // 12 bit slot. We implicitly drop the least significant bit in encodeB. 1290 wantEvenOffset(ctxt, ins.as, ins.imm) 1291 wantImmI(ctxt, ins.as, ins.imm, 13) 1292 wantNoneReg(ctxt, ins.as, "rd", ins.rd) 1293 wantIntReg(ctxt, ins.as, "rs1", ins.rs1) 1294 wantIntReg(ctxt, ins.as, "rs2", ins.rs2) 1295 } 1296 1297 func validateU(ctxt *obj.Link, ins *instruction) { 1298 wantImmI(ctxt, ins.as, ins.imm, 20) 1299 wantIntReg(ctxt, ins.as, "rd", ins.rd) 1300 wantNoneReg(ctxt, ins.as, "rs1", ins.rs1) 1301 wantNoneReg(ctxt, ins.as, "rs2", ins.rs2) 1302 } 1303 1304 func validateJ(ctxt *obj.Link, ins *instruction) { 1305 // Offsets are multiples of two, so accept 21 bit immediates for the 1306 // 20 bit slot. We implicitly drop the least significant bit in encodeJ. 1307 wantEvenOffset(ctxt, ins.as, ins.imm) 1308 wantImmI(ctxt, ins.as, ins.imm, 21) 1309 wantIntReg(ctxt, ins.as, "rd", ins.rd) 1310 wantNoneReg(ctxt, ins.as, "rs1", ins.rs1) 1311 wantNoneReg(ctxt, ins.as, "rs2", ins.rs2) 1312 } 1313 1314 func validateRaw(ctxt *obj.Link, ins *instruction) { 1315 // Treat the raw value specially as a 32-bit unsigned integer. 1316 // Nobody wants to enter negative machine code. 1317 if ins.imm < 0 || 1<<32 <= ins.imm { 1318 ctxt.Diag("%v\timmediate in raw position cannot be larger than 32 bits but got %d", ins.as, ins.imm) 1319 } 1320 } 1321 1322 // encodeR encodes an R-type RISC-V instruction. 1323 func encodeR(as obj.As, rs1, rs2, rd, funct3, funct7 uint32) uint32 { 1324 enc := encode(as) 1325 if enc == nil { 1326 panic("encodeR: could not encode instruction") 1327 } 1328 if enc.rs2 != 0 && rs2 != 0 { 1329 panic("encodeR: instruction uses rs2, but rs2 was nonzero") 1330 } 1331 return funct7<<25 | enc.funct7<<25 | enc.rs2<<20 | rs2<<20 | rs1<<15 | enc.funct3<<12 | funct3<<12 | rd<<7 | enc.opcode 1332 } 1333 1334 func encodeRIII(ins *instruction) uint32 { 1335 return encodeR(ins.as, regI(ins.rs1), regI(ins.rs2), regI(ins.rd), ins.funct3, ins.funct7) 1336 } 1337 1338 func encodeRFFF(ins *instruction) uint32 { 1339 return encodeR(ins.as, regF(ins.rs1), regF(ins.rs2), regF(ins.rd), ins.funct3, ins.funct7) 1340 } 1341 1342 func encodeRFFI(ins *instruction) uint32 { 1343 return encodeR(ins.as, regF(ins.rs1), regF(ins.rs2), regI(ins.rd), ins.funct3, ins.funct7) 1344 } 1345 1346 func encodeRFI(ins *instruction) uint32 { 1347 return encodeR(ins.as, regF(ins.rs2), 0, regI(ins.rd), ins.funct3, ins.funct7) 1348 } 1349 1350 func encodeRIF(ins *instruction) uint32 { 1351 return encodeR(ins.as, regI(ins.rs2), 0, regF(ins.rd), ins.funct3, ins.funct7) 1352 } 1353 1354 func encodeRFF(ins *instruction) uint32 { 1355 return encodeR(ins.as, regF(ins.rs2), 0, regF(ins.rd), ins.funct3, ins.funct7) 1356 } 1357 1358 // encodeI encodes an I-type RISC-V instruction. 1359 func encodeI(as obj.As, rs1, rd, imm uint32) uint32 { 1360 enc := encode(as) 1361 if enc == nil { 1362 panic("encodeI: could not encode instruction") 1363 } 1364 imm |= uint32(enc.csr) 1365 return imm<<20 | rs1<<15 | enc.funct3<<12 | rd<<7 | enc.opcode 1366 } 1367 1368 func encodeII(ins *instruction) uint32 { 1369 return encodeI(ins.as, regI(ins.rs1), regI(ins.rd), uint32(ins.imm)) 1370 } 1371 1372 func encodeIF(ins *instruction) uint32 { 1373 return encodeI(ins.as, regI(ins.rs1), regF(ins.rd), uint32(ins.imm)) 1374 } 1375 1376 // encodeS encodes an S-type RISC-V instruction. 1377 func encodeS(as obj.As, rs1, rs2, imm uint32) uint32 { 1378 enc := encode(as) 1379 if enc == nil { 1380 panic("encodeS: could not encode instruction") 1381 } 1382 return (imm>>5)<<25 | rs2<<20 | rs1<<15 | enc.funct3<<12 | (imm&0x1f)<<7 | enc.opcode 1383 } 1384 1385 func encodeSI(ins *instruction) uint32 { 1386 return encodeS(ins.as, regI(ins.rd), regI(ins.rs1), uint32(ins.imm)) 1387 } 1388 1389 func encodeSF(ins *instruction) uint32 { 1390 return encodeS(ins.as, regI(ins.rd), regF(ins.rs1), uint32(ins.imm)) 1391 } 1392 1393 // encodeB encodes a B-type RISC-V instruction. 1394 func encodeB(ins *instruction) uint32 { 1395 imm := immI(ins.as, ins.imm, 13) 1396 rs2 := regI(ins.rs1) 1397 rs1 := regI(ins.rs2) 1398 enc := encode(ins.as) 1399 if enc == nil { 1400 panic("encodeB: could not encode instruction") 1401 } 1402 return (imm>>12)<<31 | ((imm>>5)&0x3f)<<25 | rs2<<20 | rs1<<15 | enc.funct3<<12 | ((imm>>1)&0xf)<<8 | ((imm>>11)&0x1)<<7 | enc.opcode 1403 } 1404 1405 // encodeU encodes a U-type RISC-V instruction. 1406 func encodeU(ins *instruction) uint32 { 1407 // The immediates for encodeU are the upper 20 bits of a 32 bit value. 1408 // Rather than have the user/compiler generate a 32 bit constant, the 1409 // bottommost bits of which must all be zero, instead accept just the 1410 // top bits. 1411 imm := immI(ins.as, ins.imm, 20) 1412 rd := regI(ins.rd) 1413 enc := encode(ins.as) 1414 if enc == nil { 1415 panic("encodeU: could not encode instruction") 1416 } 1417 return imm<<12 | rd<<7 | enc.opcode 1418 } 1419 1420 // encodeJ encodes a J-type RISC-V instruction. 1421 func encodeJ(ins *instruction) uint32 { 1422 imm := immI(ins.as, ins.imm, 21) 1423 rd := regI(ins.rd) 1424 enc := encode(ins.as) 1425 if enc == nil { 1426 panic("encodeJ: could not encode instruction") 1427 } 1428 return (imm>>20)<<31 | ((imm>>1)&0x3ff)<<21 | ((imm>>11)&0x1)<<20 | ((imm>>12)&0xff)<<12 | rd<<7 | enc.opcode 1429 } 1430 1431 func encodeRawIns(ins *instruction) uint32 { 1432 // Treat the raw value specially as a 32-bit unsigned integer. 1433 // Nobody wants to enter negative machine code. 1434 if ins.imm < 0 || 1<<32 <= ins.imm { 1435 panic(fmt.Sprintf("immediate %d cannot fit in 32 bits", ins.imm)) 1436 } 1437 return uint32(ins.imm) 1438 } 1439 1440 func EncodeIImmediate(imm int64) (int64, error) { 1441 if !immIFits(imm, 12) { 1442 return 0, fmt.Errorf("immediate %#x does not fit in 12 bits", imm) 1443 } 1444 return imm << 20, nil 1445 } 1446 1447 func EncodeSImmediate(imm int64) (int64, error) { 1448 if !immIFits(imm, 12) { 1449 return 0, fmt.Errorf("immediate %#x does not fit in 12 bits", imm) 1450 } 1451 return ((imm >> 5) << 25) | ((imm & 0x1f) << 7), nil 1452 } 1453 1454 func EncodeUImmediate(imm int64) (int64, error) { 1455 if !immIFits(imm, 20) { 1456 return 0, fmt.Errorf("immediate %#x does not fit in 20 bits", imm) 1457 } 1458 return imm << 12, nil 1459 } 1460 1461 type encoding struct { 1462 encode func(*instruction) uint32 // encode returns the machine code for an instruction 1463 validate func(*obj.Link, *instruction) // validate validates an instruction 1464 length int // length of encoded instruction; 0 for pseudo-ops, 4 otherwise 1465 } 1466 1467 var ( 1468 // Encodings have the following naming convention: 1469 // 1470 // 1. the instruction encoding (R/I/S/B/U/J), in lowercase 1471 // 2. zero or more register operand identifiers (I = integer 1472 // register, F = float register), in uppercase 1473 // 3. the word "Encoding" 1474 // 1475 // For example, rIIIEncoding indicates an R-type instruction with two 1476 // integer register inputs and an integer register output; sFEncoding 1477 // indicates an S-type instruction with rs2 being a float register. 1478 1479 rIIIEncoding = encoding{encode: encodeRIII, validate: validateRIII, length: 4} 1480 rFFFEncoding = encoding{encode: encodeRFFF, validate: validateRFFF, length: 4} 1481 rFFIEncoding = encoding{encode: encodeRFFI, validate: validateRFFI, length: 4} 1482 rFIEncoding = encoding{encode: encodeRFI, validate: validateRFI, length: 4} 1483 rIFEncoding = encoding{encode: encodeRIF, validate: validateRIF, length: 4} 1484 rFFEncoding = encoding{encode: encodeRFF, validate: validateRFF, length: 4} 1485 1486 iIEncoding = encoding{encode: encodeII, validate: validateII, length: 4} 1487 iFEncoding = encoding{encode: encodeIF, validate: validateIF, length: 4} 1488 1489 sIEncoding = encoding{encode: encodeSI, validate: validateSI, length: 4} 1490 sFEncoding = encoding{encode: encodeSF, validate: validateSF, length: 4} 1491 1492 bEncoding = encoding{encode: encodeB, validate: validateB, length: 4} 1493 uEncoding = encoding{encode: encodeU, validate: validateU, length: 4} 1494 jEncoding = encoding{encode: encodeJ, validate: validateJ, length: 4} 1495 1496 // rawEncoding encodes a raw instruction byte sequence. 1497 rawEncoding = encoding{encode: encodeRawIns, validate: validateRaw, length: 4} 1498 1499 // pseudoOpEncoding panics if encoding is attempted, but does no validation. 1500 pseudoOpEncoding = encoding{encode: nil, validate: func(*obj.Link, *instruction) {}, length: 0} 1501 1502 // badEncoding is used when an invalid op is encountered. 1503 // An error has already been generated, so let anything else through. 1504 badEncoding = encoding{encode: func(*instruction) uint32 { return 0 }, validate: func(*obj.Link, *instruction) {}, length: 0} 1505 ) 1506 1507 // encodings contains the encodings for RISC-V instructions. 1508 // Instructions are masked with obj.AMask to keep indices small. 1509 var encodings = [ALAST & obj.AMask]encoding{ 1510 1511 // Unprivileged ISA 1512 1513 // 2.4: Integer Computational Instructions 1514 AADDI & obj.AMask: iIEncoding, 1515 ASLTI & obj.AMask: iIEncoding, 1516 ASLTIU & obj.AMask: iIEncoding, 1517 AANDI & obj.AMask: iIEncoding, 1518 AORI & obj.AMask: iIEncoding, 1519 AXORI & obj.AMask: iIEncoding, 1520 ASLLI & obj.AMask: iIEncoding, 1521 ASRLI & obj.AMask: iIEncoding, 1522 ASRAI & obj.AMask: iIEncoding, 1523 ALUI & obj.AMask: uEncoding, 1524 AAUIPC & obj.AMask: uEncoding, 1525 AADD & obj.AMask: rIIIEncoding, 1526 ASLT & obj.AMask: rIIIEncoding, 1527 ASLTU & obj.AMask: rIIIEncoding, 1528 AAND & obj.AMask: rIIIEncoding, 1529 AOR & obj.AMask: rIIIEncoding, 1530 AXOR & obj.AMask: rIIIEncoding, 1531 ASLL & obj.AMask: rIIIEncoding, 1532 ASRL & obj.AMask: rIIIEncoding, 1533 ASUB & obj.AMask: rIIIEncoding, 1534 ASRA & obj.AMask: rIIIEncoding, 1535 1536 // 2.5: Control Transfer Instructions 1537 AJAL & obj.AMask: jEncoding, 1538 AJALR & obj.AMask: iIEncoding, 1539 ABEQ & obj.AMask: bEncoding, 1540 ABNE & obj.AMask: bEncoding, 1541 ABLT & obj.AMask: bEncoding, 1542 ABLTU & obj.AMask: bEncoding, 1543 ABGE & obj.AMask: bEncoding, 1544 ABGEU & obj.AMask: bEncoding, 1545 1546 // 2.6: Load and Store Instructions 1547 ALW & obj.AMask: iIEncoding, 1548 ALWU & obj.AMask: iIEncoding, 1549 ALH & obj.AMask: iIEncoding, 1550 ALHU & obj.AMask: iIEncoding, 1551 ALB & obj.AMask: iIEncoding, 1552 ALBU & obj.AMask: iIEncoding, 1553 ASW & obj.AMask: sIEncoding, 1554 ASH & obj.AMask: sIEncoding, 1555 ASB & obj.AMask: sIEncoding, 1556 1557 // 2.7: Memory Ordering 1558 AFENCE & obj.AMask: iIEncoding, 1559 1560 // 5.2: Integer Computational Instructions (RV64I) 1561 AADDIW & obj.AMask: iIEncoding, 1562 ASLLIW & obj.AMask: iIEncoding, 1563 ASRLIW & obj.AMask: iIEncoding, 1564 ASRAIW & obj.AMask: iIEncoding, 1565 AADDW & obj.AMask: rIIIEncoding, 1566 ASLLW & obj.AMask: rIIIEncoding, 1567 ASRLW & obj.AMask: rIIIEncoding, 1568 ASUBW & obj.AMask: rIIIEncoding, 1569 ASRAW & obj.AMask: rIIIEncoding, 1570 1571 // 5.3: Load and Store Instructions (RV64I) 1572 ALD & obj.AMask: iIEncoding, 1573 ASD & obj.AMask: sIEncoding, 1574 1575 // 7.1: Multiplication Operations 1576 AMUL & obj.AMask: rIIIEncoding, 1577 AMULH & obj.AMask: rIIIEncoding, 1578 AMULHU & obj.AMask: rIIIEncoding, 1579 AMULHSU & obj.AMask: rIIIEncoding, 1580 AMULW & obj.AMask: rIIIEncoding, 1581 ADIV & obj.AMask: rIIIEncoding, 1582 ADIVU & obj.AMask: rIIIEncoding, 1583 AREM & obj.AMask: rIIIEncoding, 1584 AREMU & obj.AMask: rIIIEncoding, 1585 ADIVW & obj.AMask: rIIIEncoding, 1586 ADIVUW & obj.AMask: rIIIEncoding, 1587 AREMW & obj.AMask: rIIIEncoding, 1588 AREMUW & obj.AMask: rIIIEncoding, 1589 1590 // 8.2: Load-Reserved/Store-Conditional 1591 ALRW & obj.AMask: rIIIEncoding, 1592 ALRD & obj.AMask: rIIIEncoding, 1593 ASCW & obj.AMask: rIIIEncoding, 1594 ASCD & obj.AMask: rIIIEncoding, 1595 1596 // 8.3: Atomic Memory Operations 1597 AAMOSWAPW & obj.AMask: rIIIEncoding, 1598 AAMOSWAPD & obj.AMask: rIIIEncoding, 1599 AAMOADDW & obj.AMask: rIIIEncoding, 1600 AAMOADDD & obj.AMask: rIIIEncoding, 1601 AAMOANDW & obj.AMask: rIIIEncoding, 1602 AAMOANDD & obj.AMask: rIIIEncoding, 1603 AAMOORW & obj.AMask: rIIIEncoding, 1604 AAMOORD & obj.AMask: rIIIEncoding, 1605 AAMOXORW & obj.AMask: rIIIEncoding, 1606 AAMOXORD & obj.AMask: rIIIEncoding, 1607 AAMOMAXW & obj.AMask: rIIIEncoding, 1608 AAMOMAXD & obj.AMask: rIIIEncoding, 1609 AAMOMAXUW & obj.AMask: rIIIEncoding, 1610 AAMOMAXUD & obj.AMask: rIIIEncoding, 1611 AAMOMINW & obj.AMask: rIIIEncoding, 1612 AAMOMIND & obj.AMask: rIIIEncoding, 1613 AAMOMINUW & obj.AMask: rIIIEncoding, 1614 AAMOMINUD & obj.AMask: rIIIEncoding, 1615 1616 // 10.1: Base Counters and Timers 1617 ARDCYCLE & obj.AMask: iIEncoding, 1618 ARDTIME & obj.AMask: iIEncoding, 1619 ARDINSTRET & obj.AMask: iIEncoding, 1620 1621 // 11.5: Single-Precision Load and Store Instructions 1622 AFLW & obj.AMask: iFEncoding, 1623 AFSW & obj.AMask: sFEncoding, 1624 1625 // 11.6: Single-Precision Floating-Point Computational Instructions 1626 AFADDS & obj.AMask: rFFFEncoding, 1627 AFSUBS & obj.AMask: rFFFEncoding, 1628 AFMULS & obj.AMask: rFFFEncoding, 1629 AFDIVS & obj.AMask: rFFFEncoding, 1630 AFMINS & obj.AMask: rFFFEncoding, 1631 AFMAXS & obj.AMask: rFFFEncoding, 1632 AFSQRTS & obj.AMask: rFFFEncoding, 1633 1634 // 11.7: Single-Precision Floating-Point Conversion and Move Instructions 1635 AFCVTWS & obj.AMask: rFIEncoding, 1636 AFCVTLS & obj.AMask: rFIEncoding, 1637 AFCVTSW & obj.AMask: rIFEncoding, 1638 AFCVTSL & obj.AMask: rIFEncoding, 1639 AFCVTWUS & obj.AMask: rFIEncoding, 1640 AFCVTLUS & obj.AMask: rFIEncoding, 1641 AFCVTSWU & obj.AMask: rIFEncoding, 1642 AFCVTSLU & obj.AMask: rIFEncoding, 1643 AFSGNJS & obj.AMask: rFFFEncoding, 1644 AFSGNJNS & obj.AMask: rFFFEncoding, 1645 AFSGNJXS & obj.AMask: rFFFEncoding, 1646 AFMVXS & obj.AMask: rFIEncoding, 1647 AFMVSX & obj.AMask: rIFEncoding, 1648 AFMVXW & obj.AMask: rFIEncoding, 1649 AFMVWX & obj.AMask: rIFEncoding, 1650 1651 // 11.8: Single-Precision Floating-Point Compare Instructions 1652 AFEQS & obj.AMask: rFFIEncoding, 1653 AFLTS & obj.AMask: rFFIEncoding, 1654 AFLES & obj.AMask: rFFIEncoding, 1655 1656 // 11.9: Single-Precision Floating-Point Classify Instruction 1657 AFCLASSS & obj.AMask: rFIEncoding, 1658 1659 // 12.3: Double-Precision Load and Store Instructions 1660 AFLD & obj.AMask: iFEncoding, 1661 AFSD & obj.AMask: sFEncoding, 1662 1663 // 12.4: Double-Precision Floating-Point Computational Instructions 1664 AFADDD & obj.AMask: rFFFEncoding, 1665 AFSUBD & obj.AMask: rFFFEncoding, 1666 AFMULD & obj.AMask: rFFFEncoding, 1667 AFDIVD & obj.AMask: rFFFEncoding, 1668 AFMIND & obj.AMask: rFFFEncoding, 1669 AFMAXD & obj.AMask: rFFFEncoding, 1670 AFSQRTD & obj.AMask: rFFFEncoding, 1671 1672 // 12.5: Double-Precision Floating-Point Conversion and Move Instructions 1673 AFCVTWD & obj.AMask: rFIEncoding, 1674 AFCVTLD & obj.AMask: rFIEncoding, 1675 AFCVTDW & obj.AMask: rIFEncoding, 1676 AFCVTDL & obj.AMask: rIFEncoding, 1677 AFCVTWUD & obj.AMask: rFIEncoding, 1678 AFCVTLUD & obj.AMask: rFIEncoding, 1679 AFCVTDWU & obj.AMask: rIFEncoding, 1680 AFCVTDLU & obj.AMask: rIFEncoding, 1681 AFCVTSD & obj.AMask: rFFEncoding, 1682 AFCVTDS & obj.AMask: rFFEncoding, 1683 AFSGNJD & obj.AMask: rFFFEncoding, 1684 AFSGNJND & obj.AMask: rFFFEncoding, 1685 AFSGNJXD & obj.AMask: rFFFEncoding, 1686 AFMVXD & obj.AMask: rFIEncoding, 1687 AFMVDX & obj.AMask: rIFEncoding, 1688 1689 // 12.6: Double-Precision Floating-Point Compare Instructions 1690 AFEQD & obj.AMask: rFFIEncoding, 1691 AFLTD & obj.AMask: rFFIEncoding, 1692 AFLED & obj.AMask: rFFIEncoding, 1693 1694 // 12.7: Double-Precision Floating-Point Classify Instruction 1695 AFCLASSD & obj.AMask: rFIEncoding, 1696 1697 // Privileged ISA 1698 1699 // 3.2.1: Environment Call and Breakpoint 1700 AECALL & obj.AMask: iIEncoding, 1701 AEBREAK & obj.AMask: iIEncoding, 1702 1703 // Escape hatch 1704 AWORD & obj.AMask: rawEncoding, 1705 1706 // Pseudo-operations 1707 obj.AFUNCDATA: pseudoOpEncoding, 1708 obj.APCDATA: pseudoOpEncoding, 1709 obj.ATEXT: pseudoOpEncoding, 1710 obj.ANOP: pseudoOpEncoding, 1711 } 1712 1713 // encodingForAs returns the encoding for an obj.As. 1714 func encodingForAs(as obj.As) (encoding, error) { 1715 if base := as &^ obj.AMask; base != obj.ABaseRISCV && base != 0 { 1716 return badEncoding, fmt.Errorf("encodingForAs: not a RISC-V instruction %s", as) 1717 } 1718 asi := as & obj.AMask 1719 if int(asi) >= len(encodings) { 1720 return badEncoding, fmt.Errorf("encodingForAs: bad RISC-V instruction %s", as) 1721 } 1722 enc := encodings[asi] 1723 if enc.validate == nil { 1724 return badEncoding, fmt.Errorf("encodingForAs: no encoding for instruction %s", as) 1725 } 1726 return enc, nil 1727 } 1728 1729 type instruction struct { 1730 as obj.As // Assembler opcode 1731 rd uint32 // Destination register 1732 rs1 uint32 // Source register 1 1733 rs2 uint32 // Source register 2 1734 imm int64 // Immediate 1735 funct3 uint32 // Function 3 1736 funct7 uint32 // Function 7 1737 } 1738 1739 func (ins *instruction) encode() (uint32, error) { 1740 enc, err := encodingForAs(ins.as) 1741 if err != nil { 1742 return 0, err 1743 } 1744 if enc.length > 0 { 1745 return enc.encode(ins), nil 1746 } 1747 return 0, fmt.Errorf("fixme") 1748 } 1749 1750 func (ins *instruction) length() int { 1751 enc, err := encodingForAs(ins.as) 1752 if err != nil { 1753 return 0 1754 } 1755 return enc.length 1756 } 1757 1758 func (ins *instruction) validate(ctxt *obj.Link) { 1759 enc, err := encodingForAs(ins.as) 1760 if err != nil { 1761 ctxt.Diag(err.Error()) 1762 return 1763 } 1764 enc.validate(ctxt, ins) 1765 } 1766 1767 // instructionsForProg returns the machine instructions for an *obj.Prog. 1768 func instructionsForProg(p *obj.Prog) []*instruction { 1769 ins := &instruction{ 1770 as: p.As, 1771 rd: uint32(p.To.Reg), 1772 rs1: uint32(p.Reg), 1773 rs2: uint32(p.From.Reg), 1774 imm: p.From.Offset, 1775 } 1776 1777 inss := []*instruction{ins} 1778 switch ins.as { 1779 case AJAL, AJALR: 1780 ins.rd, ins.rs1, ins.rs2 = uint32(p.From.Reg), uint32(p.To.Reg), obj.REG_NONE 1781 ins.imm = p.To.Offset 1782 1783 case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ: 1784 switch ins.as { 1785 case ABEQZ: 1786 ins.as, ins.rs1, ins.rs2 = ABEQ, REG_ZERO, uint32(p.From.Reg) 1787 case ABGEZ: 1788 ins.as, ins.rs1, ins.rs2 = ABGE, REG_ZERO, uint32(p.From.Reg) 1789 case ABGT: 1790 ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.Reg), uint32(p.From.Reg) 1791 case ABGTU: 1792 ins.as, ins.rs1, ins.rs2 = ABLTU, uint32(p.Reg), uint32(p.From.Reg) 1793 case ABGTZ: 1794 ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.From.Reg), REG_ZERO 1795 case ABLE: 1796 ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.Reg), uint32(p.From.Reg) 1797 case ABLEU: 1798 ins.as, ins.rs1, ins.rs2 = ABGEU, uint32(p.Reg), uint32(p.From.Reg) 1799 case ABLEZ: 1800 ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.From.Reg), REG_ZERO 1801 case ABLTZ: 1802 ins.as, ins.rs1, ins.rs2 = ABLT, REG_ZERO, uint32(p.From.Reg) 1803 case ABNEZ: 1804 ins.as, ins.rs1, ins.rs2 = ABNE, REG_ZERO, uint32(p.From.Reg) 1805 } 1806 ins.imm = p.To.Offset 1807 1808 case ALW, ALWU, ALH, ALHU, ALB, ALBU, ALD, AFLW, AFLD: 1809 if p.From.Type != obj.TYPE_MEM { 1810 p.Ctxt.Diag("%v requires memory for source", p) 1811 return nil 1812 } 1813 ins.rs1, ins.rs2 = uint32(p.From.Reg), obj.REG_NONE 1814 ins.imm = p.From.Offset 1815 1816 case ASW, ASH, ASB, ASD, AFSW, AFSD: 1817 if p.To.Type != obj.TYPE_MEM { 1818 p.Ctxt.Diag("%v requires memory for destination", p) 1819 return nil 1820 } 1821 ins.rs1, ins.rs2 = uint32(p.From.Reg), obj.REG_NONE 1822 ins.imm = p.To.Offset 1823 1824 case ALRW, ALRD: 1825 // Set aq to use acquire access ordering, which matches Go's memory requirements. 1826 ins.funct7 = 2 1827 ins.rs1, ins.rs2 = uint32(p.From.Reg), REG_ZERO 1828 1829 case ASCW, ASCD, AAMOSWAPW, AAMOSWAPD, AAMOADDW, AAMOADDD, AAMOANDW, AAMOANDD, AAMOORW, AAMOORD, 1830 AAMOXORW, AAMOXORD, AAMOMINW, AAMOMIND, AAMOMINUW, AAMOMINUD, AAMOMAXW, AAMOMAXD, AAMOMAXUW, AAMOMAXUD: 1831 // Set aq to use acquire access ordering, which matches Go's memory requirements. 1832 ins.funct7 = 2 1833 ins.rd, ins.rs1, ins.rs2 = uint32(p.RegTo2), uint32(p.To.Reg), uint32(p.From.Reg) 1834 1835 case AECALL, AEBREAK, ARDCYCLE, ARDTIME, ARDINSTRET: 1836 insEnc := encode(p.As) 1837 if p.To.Type == obj.TYPE_NONE { 1838 ins.rd = REG_ZERO 1839 } 1840 ins.rs1 = REG_ZERO 1841 ins.imm = insEnc.csr 1842 1843 case AFENCE: 1844 ins.rd, ins.rs1, ins.rs2 = REG_ZERO, REG_ZERO, obj.REG_NONE 1845 ins.imm = 0x0ff 1846 1847 case AFCVTWS, AFCVTLS, AFCVTWUS, AFCVTLUS, AFCVTWD, AFCVTLD, AFCVTWUD, AFCVTLUD: 1848 // Set the rounding mode in funct3 to round to zero. 1849 ins.funct3 = 1 1850 1851 case AFNES, AFNED: 1852 // Replace FNE[SD] with FEQ[SD] and NOT. 1853 if p.To.Type != obj.TYPE_REG { 1854 p.Ctxt.Diag("%v needs an integer register output", ins.as) 1855 return nil 1856 } 1857 if ins.as == AFNES { 1858 ins.as = AFEQS 1859 } else { 1860 ins.as = AFEQD 1861 } 1862 ins = &instruction{ 1863 as: AXORI, // [bit] xor 1 = not [bit] 1864 rd: ins.rd, 1865 rs1: ins.rd, 1866 imm: 1, 1867 } 1868 inss = append(inss, ins) 1869 1870 case AFSQRTS, AFSQRTD: 1871 // These instructions expect a zero (i.e. float register 0) 1872 // to be the second input operand. 1873 ins.rs1 = uint32(p.From.Reg) 1874 ins.rs2 = REG_F0 1875 1876 case ANEG, ANEGW: 1877 // NEG rs, rd -> SUB rs, X0, rd 1878 ins.as = ASUB 1879 if p.As == ANEGW { 1880 ins.as = ASUBW 1881 } 1882 ins.rs1 = REG_ZERO 1883 if ins.rd == obj.REG_NONE { 1884 ins.rd = ins.rs2 1885 } 1886 1887 case ANOT: 1888 // NOT rs, rd -> XORI $-1, rs, rd 1889 ins.as = AXORI 1890 ins.rs1, ins.rs2 = uint32(p.From.Reg), obj.REG_NONE 1891 if ins.rd == obj.REG_NONE { 1892 ins.rd = ins.rs1 1893 } 1894 ins.imm = -1 1895 1896 case ASEQZ: 1897 // SEQZ rs, rd -> SLTIU $1, rs, rd 1898 ins.as = ASLTIU 1899 ins.rs1 = uint32(p.From.Reg) 1900 ins.imm = 1 1901 1902 case ASNEZ: 1903 // SNEZ rs, rd -> SLTU rs, x0, rd 1904 ins.as = ASLTU 1905 ins.rs1 = REG_ZERO 1906 1907 case AFNEGS: 1908 // FNEGS rs, rd -> FSGNJNS rs, rs, rd 1909 ins.as = AFSGNJNS 1910 ins.rs1 = uint32(p.From.Reg) 1911 1912 case AFNEGD: 1913 // FNEGD rs, rd -> FSGNJND rs, rs, rd 1914 ins.as = AFSGNJND 1915 ins.rs1 = uint32(p.From.Reg) 1916 } 1917 return inss 1918 } 1919 1920 // assemble emits machine code. 1921 // It is called at the very end of the assembly process. 1922 func assemble(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { 1923 if ctxt.Retpoline { 1924 ctxt.Diag("-spectre=ret not supported on riscv") 1925 ctxt.Retpoline = false // don't keep printing 1926 } 1927 1928 var symcode []uint32 1929 for p := cursym.Func.Text; p != nil; p = p.Link { 1930 switch p.As { 1931 case AJALR: 1932 if p.To.Sym != nil { 1933 // This is a CALL/JMP. We add a relocation only 1934 // for linker stack checking. No actual 1935 // relocation is needed. 1936 rel := obj.Addrel(cursym) 1937 rel.Off = int32(p.Pc) 1938 rel.Siz = 4 1939 rel.Sym = p.To.Sym 1940 rel.Add = p.To.Offset 1941 rel.Type = objabi.R_CALLRISCV 1942 } 1943 case AAUIPC: 1944 var rt objabi.RelocType 1945 if p.Mark&NEED_PCREL_ITYPE_RELOC == NEED_PCREL_ITYPE_RELOC { 1946 rt = objabi.R_RISCV_PCREL_ITYPE 1947 } else if p.Mark&NEED_PCREL_STYPE_RELOC == NEED_PCREL_STYPE_RELOC { 1948 rt = objabi.R_RISCV_PCREL_STYPE 1949 } else { 1950 break 1951 } 1952 if p.Link == nil { 1953 ctxt.Diag("AUIPC needing PC-relative reloc missing following instruction") 1954 break 1955 } 1956 addr := p.RestArgs[0] 1957 if addr.Sym == nil { 1958 ctxt.Diag("AUIPC needing PC-relative reloc missing symbol") 1959 break 1960 } 1961 1962 rel := obj.Addrel(cursym) 1963 rel.Off = int32(p.Pc) 1964 rel.Siz = 8 1965 rel.Sym = addr.Sym 1966 rel.Add = addr.Offset 1967 rel.Type = rt 1968 } 1969 1970 for _, ins := range instructionsForProg(p) { 1971 ic, err := ins.encode() 1972 if err == nil { 1973 symcode = append(symcode, ic) 1974 } 1975 } 1976 } 1977 cursym.Size = int64(4 * len(symcode)) 1978 1979 cursym.Grow(cursym.Size) 1980 for p, i := cursym.P, 0; i < len(symcode); p, i = p[4:], i+1 { 1981 ctxt.Arch.ByteOrder.PutUint32(p, symcode[i]) 1982 } 1983 1984 obj.MarkUnsafePoints(ctxt, cursym.Func.Text, newprog, isUnsafePoint, nil) 1985 } 1986 1987 func isUnsafePoint(p *obj.Prog) bool { 1988 return p.From.Reg == REG_TMP || p.To.Reg == REG_TMP || p.Reg == REG_TMP 1989 } 1990 1991 var LinkRISCV64 = obj.LinkArch{ 1992 Arch: sys.ArchRISCV64, 1993 Init: buildop, 1994 Preprocess: preprocess, 1995 Assemble: assemble, 1996 Progedit: progedit, 1997 UnaryDst: unaryDst, 1998 DWARFRegisters: RISCV64DWARFRegisters, 1999 }