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