...

Source file src/github.com/twitchyliquid64/golang-asm/obj/riscv/obj.go

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

View as plain text