Black Lives Matter. Support the Equal Justice Initiative.

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

Documentation: cmd/internal/obj/riscv

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

View as plain text