podman

Форк
0
1999 строк · 55.8 Кб
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

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.