gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

obj.go (57153B)


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