github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/internal/obj/riscv/obj.go (about)

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