Source file src/cmd/internal/obj/riscv/obj.go

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

View as plain text