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