github.com/bir3/gocompiler@v0.3.205/src/cmd/internal/obj/riscv/obj.go (about)

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