1// Copyright 2014 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package asm
6
7import (
8	"fmt"
9	"internal/abi"
10	"strconv"
11	"strings"
12	"text/scanner"
13
14	"cmd/asm/internal/arch"
15	"cmd/asm/internal/flags"
16	"cmd/asm/internal/lex"
17	"cmd/internal/obj"
18	"cmd/internal/obj/ppc64"
19	"cmd/internal/obj/riscv"
20	"cmd/internal/obj/x86"
21	"cmd/internal/sys"
22)
23
24// TODO: configure the architecture
25
26var testOut *strings.Builder // Gathers output when testing.
27
28// append adds the Prog to the end of the program-thus-far.
29// If doLabel is set, it also defines the labels collect for this Prog.
30func (p *Parser) append(prog *obj.Prog, cond string, doLabel bool) {
31	if cond != "" {
32		switch p.arch.Family {
33		case sys.ARM:
34			if !arch.ARMConditionCodes(prog, cond) {
35				p.errorf("unrecognized condition code .%q", cond)
36				return
37			}
38
39		case sys.ARM64:
40			if !arch.ARM64Suffix(prog, cond) {
41				p.errorf("unrecognized suffix .%q", cond)
42				return
43			}
44
45		case sys.AMD64, sys.I386:
46			if err := x86.ParseSuffix(prog, cond); err != nil {
47				p.errorf("%v", err)
48				return
49			}
50		case sys.RISCV64:
51			if err := riscv.ParseSuffix(prog, cond); err != nil {
52				p.errorf("unrecognized suffix .%q", cond)
53				return
54			}
55		default:
56			p.errorf("unrecognized suffix .%q", cond)
57			return
58		}
59	}
60	if p.firstProg == nil {
61		p.firstProg = prog
62	} else {
63		p.lastProg.Link = prog
64	}
65	p.lastProg = prog
66	if doLabel {
67		p.pc++
68		for _, label := range p.pendingLabels {
69			if p.labels[label] != nil {
70				p.errorf("label %q multiply defined", label)
71				return
72			}
73			p.labels[label] = prog
74		}
75		p.pendingLabels = p.pendingLabels[0:0]
76	}
77	prog.Pc = p.pc
78	if *flags.Debug {
79		fmt.Println(p.lineNum, prog)
80	}
81	if testOut != nil {
82		fmt.Fprintln(testOut, prog)
83	}
84}
85
86// validSymbol checks that addr represents a valid name for a pseudo-op.
87func (p *Parser) validSymbol(pseudo string, addr *obj.Addr, offsetOk bool) bool {
88	if addr.Sym == nil || addr.Name != obj.NAME_EXTERN && addr.Name != obj.NAME_STATIC || addr.Scale != 0 || addr.Reg != 0 {
89		p.errorf("%s symbol %q must be a symbol(SB)", pseudo, symbolName(addr))
90		return false
91	}
92	if !offsetOk && addr.Offset != 0 {
93		p.errorf("%s symbol %q must not be offset from SB", pseudo, symbolName(addr))
94		return false
95	}
96	return true
97}
98
99// evalInteger evaluates an integer constant for a pseudo-op.
100func (p *Parser) evalInteger(pseudo string, operands []lex.Token) int64 {
101	addr := p.address(operands)
102	return p.getConstantPseudo(pseudo, &addr)
103}
104
105// validImmediate checks that addr represents an immediate constant.
106func (p *Parser) validImmediate(pseudo string, addr *obj.Addr) bool {
107	if addr.Type != obj.TYPE_CONST || addr.Name != 0 || addr.Reg != 0 || addr.Index != 0 {
108		p.errorf("%s: expected immediate constant; found %s", pseudo, obj.Dconv(&emptyProg, addr))
109		return false
110	}
111	return true
112}
113
114// asmText assembles a TEXT pseudo-op.
115// TEXT runtime·sigtramp(SB),4,$0-0
116func (p *Parser) asmText(operands [][]lex.Token) {
117	if len(operands) != 2 && len(operands) != 3 {
118		p.errorf("expect two or three operands for TEXT")
119		return
120	}
121
122	// Labels are function scoped. Patch existing labels and
123	// create a new label space for this TEXT.
124	p.patch()
125	p.labels = make(map[string]*obj.Prog)
126
127	// Operand 0 is the symbol name in the form foo(SB).
128	// That means symbol plus indirect on SB and no offset.
129	nameAddr := p.address(operands[0])
130	if !p.validSymbol("TEXT", &nameAddr, false) {
131		return
132	}
133	name := symbolName(&nameAddr)
134	next := 1
135
136	// Next operand is the optional text flag, a literal integer.
137	var flag = int64(0)
138	if len(operands) == 3 {
139		flag = p.evalInteger("TEXT", operands[1])
140		next++
141	}
142
143	// Issue an error if we see a function defined as ABIInternal
144	// without NOSPLIT. In ABIInternal, obj needs to know the function
145	// signature in order to construct the morestack path, so this
146	// currently isn't supported for asm functions.
147	if nameAddr.Sym.ABI() == obj.ABIInternal && flag&obj.NOSPLIT == 0 {
148		p.errorf("TEXT %q: ABIInternal requires NOSPLIT", name)
149	}
150
151	// Next operand is the frame and arg size.
152	// Bizarre syntax: $frameSize-argSize is two words, not subtraction.
153	// Both frameSize and argSize must be simple integers; only frameSize
154	// can be negative.
155	// The "-argSize" may be missing; if so, set it to objabi.ArgsSizeUnknown.
156	// Parse left to right.
157	op := operands[next]
158	if len(op) < 2 || op[0].ScanToken != '$' {
159		p.errorf("TEXT %s: frame size must be an immediate constant", name)
160		return
161	}
162	op = op[1:]
163	negative := false
164	if op[0].ScanToken == '-' {
165		negative = true
166		op = op[1:]
167	}
168	if len(op) == 0 || op[0].ScanToken != scanner.Int {
169		p.errorf("TEXT %s: frame size must be an immediate constant", name)
170		return
171	}
172	frameSize := p.positiveAtoi(op[0].String())
173	if negative {
174		frameSize = -frameSize
175	}
176	op = op[1:]
177	argSize := int64(abi.ArgsSizeUnknown)
178	if len(op) > 0 {
179		// There is an argument size. It must be a minus sign followed by a non-negative integer literal.
180		if len(op) != 2 || op[0].ScanToken != '-' || op[1].ScanToken != scanner.Int {
181			p.errorf("TEXT %s: argument size must be of form -integer", name)
182			return
183		}
184		argSize = p.positiveAtoi(op[1].String())
185	}
186	p.ctxt.InitTextSym(nameAddr.Sym, int(flag), p.pos())
187	prog := &obj.Prog{
188		Ctxt: p.ctxt,
189		As:   obj.ATEXT,
190		Pos:  p.pos(),
191		From: nameAddr,
192		To: obj.Addr{
193			Type:   obj.TYPE_TEXTSIZE,
194			Offset: frameSize,
195			// Argsize set below.
196		},
197	}
198	nameAddr.Sym.Func().Text = prog
199	prog.To.Val = int32(argSize)
200	p.append(prog, "", true)
201}
202
203// asmData assembles a DATA pseudo-op.
204// DATA masks<>+0x00(SB)/4, $0x00000000
205func (p *Parser) asmData(operands [][]lex.Token) {
206	if len(operands) != 2 {
207		p.errorf("expect two operands for DATA")
208		return
209	}
210
211	// Operand 0 has the general form foo<>+0x04(SB)/4.
212	op := operands[0]
213	n := len(op)
214	if n < 3 || op[n-2].ScanToken != '/' || op[n-1].ScanToken != scanner.Int {
215		p.errorf("expect /size for DATA argument")
216		return
217	}
218	szop := op[n-1].String()
219	sz, err := strconv.Atoi(szop)
220	if err != nil {
221		p.errorf("bad size for DATA argument: %q", szop)
222	}
223	op = op[:n-2]
224	nameAddr := p.address(op)
225	if !p.validSymbol("DATA", &nameAddr, true) {
226		return
227	}
228	name := symbolName(&nameAddr)
229
230	// Operand 1 is an immediate constant or address.
231	valueAddr := p.address(operands[1])
232	switch valueAddr.Type {
233	case obj.TYPE_CONST, obj.TYPE_FCONST, obj.TYPE_SCONST, obj.TYPE_ADDR:
234		// OK
235	default:
236		p.errorf("DATA value must be an immediate constant or address")
237		return
238	}
239
240	// The addresses must not overlap. Easiest test: require monotonicity.
241	if lastAddr, ok := p.dataAddr[name]; ok && nameAddr.Offset < lastAddr {
242		p.errorf("overlapping DATA entry for %s", name)
243		return
244	}
245	p.dataAddr[name] = nameAddr.Offset + int64(sz)
246
247	switch valueAddr.Type {
248	case obj.TYPE_CONST:
249		switch sz {
250		case 1, 2, 4, 8:
251			nameAddr.Sym.WriteInt(p.ctxt, nameAddr.Offset, int(sz), valueAddr.Offset)
252		default:
253			p.errorf("bad int size for DATA argument: %d", sz)
254		}
255	case obj.TYPE_FCONST:
256		switch sz {
257		case 4:
258			nameAddr.Sym.WriteFloat32(p.ctxt, nameAddr.Offset, float32(valueAddr.Val.(float64)))
259		case 8:
260			nameAddr.Sym.WriteFloat64(p.ctxt, nameAddr.Offset, valueAddr.Val.(float64))
261		default:
262			p.errorf("bad float size for DATA argument: %d", sz)
263		}
264	case obj.TYPE_SCONST:
265		nameAddr.Sym.WriteString(p.ctxt, nameAddr.Offset, int(sz), valueAddr.Val.(string))
266	case obj.TYPE_ADDR:
267		if sz == p.arch.PtrSize {
268			nameAddr.Sym.WriteAddr(p.ctxt, nameAddr.Offset, int(sz), valueAddr.Sym, valueAddr.Offset)
269		} else {
270			p.errorf("bad addr size for DATA argument: %d", sz)
271		}
272	}
273}
274
275// asmGlobl assembles a GLOBL pseudo-op.
276// GLOBL shifts<>(SB),8,$256
277// GLOBL shifts<>(SB),$256
278func (p *Parser) asmGlobl(operands [][]lex.Token) {
279	if len(operands) != 2 && len(operands) != 3 {
280		p.errorf("expect two or three operands for GLOBL")
281		return
282	}
283
284	// Operand 0 has the general form foo<>+0x04(SB).
285	nameAddr := p.address(operands[0])
286	if !p.validSymbol("GLOBL", &nameAddr, false) {
287		return
288	}
289	next := 1
290
291	// Next operand is the optional flag, a literal integer.
292	var flag = int64(0)
293	if len(operands) == 3 {
294		flag = p.evalInteger("GLOBL", operands[1])
295		next++
296	}
297
298	// Final operand is an immediate constant.
299	addr := p.address(operands[next])
300	if !p.validImmediate("GLOBL", &addr) {
301		return
302	}
303
304	// log.Printf("GLOBL %s %d, $%d", name, flag, size)
305	p.ctxt.GloblPos(nameAddr.Sym, addr.Offset, int(flag), p.pos())
306}
307
308// asmPCData assembles a PCDATA pseudo-op.
309// PCDATA $2, $705
310func (p *Parser) asmPCData(operands [][]lex.Token) {
311	if len(operands) != 2 {
312		p.errorf("expect two operands for PCDATA")
313		return
314	}
315
316	// Operand 0 must be an immediate constant.
317	key := p.address(operands[0])
318	if !p.validImmediate("PCDATA", &key) {
319		return
320	}
321
322	// Operand 1 must be an immediate constant.
323	value := p.address(operands[1])
324	if !p.validImmediate("PCDATA", &value) {
325		return
326	}
327
328	// log.Printf("PCDATA $%d, $%d", key.Offset, value.Offset)
329	prog := &obj.Prog{
330		Ctxt: p.ctxt,
331		As:   obj.APCDATA,
332		Pos:  p.pos(),
333		From: key,
334		To:   value,
335	}
336	p.append(prog, "", true)
337}
338
339// asmPCAlign assembles a PCALIGN pseudo-op.
340// PCALIGN $16
341func (p *Parser) asmPCAlign(operands [][]lex.Token) {
342	if len(operands) != 1 {
343		p.errorf("expect one operand for PCALIGN")
344		return
345	}
346
347	// Operand 0 must be an immediate constant.
348	key := p.address(operands[0])
349	if !p.validImmediate("PCALIGN", &key) {
350		return
351	}
352
353	prog := &obj.Prog{
354		Ctxt: p.ctxt,
355		As:   obj.APCALIGN,
356		From: key,
357	}
358	p.append(prog, "", true)
359}
360
361// asmFuncData assembles a FUNCDATA pseudo-op.
362// FUNCDATA $1, funcdata<>+4(SB)
363func (p *Parser) asmFuncData(operands [][]lex.Token) {
364	if len(operands) != 2 {
365		p.errorf("expect two operands for FUNCDATA")
366		return
367	}
368
369	// Operand 0 must be an immediate constant.
370	valueAddr := p.address(operands[0])
371	if !p.validImmediate("FUNCDATA", &valueAddr) {
372		return
373	}
374
375	// Operand 1 is a symbol name in the form foo(SB).
376	nameAddr := p.address(operands[1])
377	if !p.validSymbol("FUNCDATA", &nameAddr, true) {
378		return
379	}
380
381	prog := &obj.Prog{
382		Ctxt: p.ctxt,
383		As:   obj.AFUNCDATA,
384		Pos:  p.pos(),
385		From: valueAddr,
386		To:   nameAddr,
387	}
388	p.append(prog, "", true)
389}
390
391// asmJump assembles a jump instruction.
392// JMP	R1
393// JMP	exit
394// JMP	3(PC)
395func (p *Parser) asmJump(op obj.As, cond string, a []obj.Addr) {
396	var target *obj.Addr
397	prog := &obj.Prog{
398		Ctxt: p.ctxt,
399		Pos:  p.pos(),
400		As:   op,
401	}
402	targetAddr := &prog.To
403	switch len(a) {
404	case 0:
405		if p.arch.Family == sys.Wasm {
406			target = &obj.Addr{Type: obj.TYPE_NONE}
407			break
408		}
409		p.errorf("wrong number of arguments to %s instruction", op)
410		return
411	case 1:
412		target = &a[0]
413	case 2:
414		// Special 2-operand jumps.
415		if p.arch.Family == sys.ARM64 && arch.IsARM64ADR(op) {
416			// ADR label, R. Label is in From.
417			target = &a[0]
418			prog.To = a[1]
419			targetAddr = &prog.From
420		} else {
421			target = &a[1]
422			prog.From = a[0]
423		}
424	case 3:
425		if p.arch.Family == sys.PPC64 {
426			// Special 3-operand jumps.
427			// a[1] is a register number expressed as a constant or register value
428			target = &a[2]
429			prog.From = a[0]
430			if a[0].Type != obj.TYPE_CONST {
431				// Legacy code may use a plain constant, accept it, and coerce
432				// into a constant. E.g:
433				//   BC 4,...
434				// into
435				//   BC $4,...
436				prog.From = obj.Addr{
437					Type:   obj.TYPE_CONST,
438					Offset: p.getConstant(prog, op, &a[0]),
439				}
440
441			}
442
443			// Likewise, fixup usage like:
444			//   BC x,LT,...
445			//   BC x,foo+2,...
446			//   BC x,4
447			//   BC x,$5
448			// into
449			//   BC x,CR0LT,...
450			//   BC x,CR0EQ,...
451			//   BC x,CR1LT,...
452			//   BC x,CR1GT,...
453			// The first and second cases demonstrate a symbol name which is
454			// effectively discarded. In these cases, the offset determines
455			// the CR bit.
456			prog.Reg = a[1].Reg
457			if a[1].Type != obj.TYPE_REG {
458				// The CR bit is represented as a constant 0-31. Convert it to a Reg.
459				c := p.getConstant(prog, op, &a[1])
460				reg, success := ppc64.ConstantToCRbit(c)
461				if !success {
462					p.errorf("invalid CR bit register number %d", c)
463				}
464				prog.Reg = reg
465			}
466			break
467		}
468		if p.arch.Family == sys.MIPS || p.arch.Family == sys.MIPS64 || p.arch.Family == sys.RISCV64 {
469			// 3-operand jumps.
470			// First two must be registers
471			target = &a[2]
472			prog.From = a[0]
473			prog.Reg = p.getRegister(prog, op, &a[1])
474			break
475		}
476		if p.arch.Family == sys.Loong64 {
477			// 3-operand jumps.
478			// First two must be registers
479			target = &a[2]
480			prog.From = a[0]
481			prog.Reg = p.getRegister(prog, op, &a[1])
482			break
483		}
484		if p.arch.Family == sys.S390X {
485			// 3-operand jumps.
486			target = &a[2]
487			prog.From = a[0]
488			if a[1].Reg != 0 {
489				// Compare two registers and jump.
490				prog.Reg = p.getRegister(prog, op, &a[1])
491			} else {
492				// Compare register with immediate and jump.
493				prog.AddRestSource(a[1])
494			}
495			break
496		}
497		if p.arch.Family == sys.ARM64 {
498			// Special 3-operand jumps.
499			// a[0] must be immediate constant; a[1] is a register.
500			if a[0].Type != obj.TYPE_CONST {
501				p.errorf("%s: expected immediate constant; found %s", op, obj.Dconv(prog, &a[0]))
502				return
503			}
504			prog.From = a[0]
505			prog.Reg = p.getRegister(prog, op, &a[1])
506			target = &a[2]
507			break
508		}
509		p.errorf("wrong number of arguments to %s instruction", op)
510		return
511	case 4:
512		if p.arch.Family == sys.S390X || p.arch.Family == sys.PPC64 {
513			// 4-operand compare-and-branch.
514			prog.From = a[0]
515			prog.Reg = p.getRegister(prog, op, &a[1])
516			prog.AddRestSource(a[2])
517			target = &a[3]
518			break
519		}
520		p.errorf("wrong number of arguments to %s instruction", op)
521		return
522	default:
523		p.errorf("wrong number of arguments to %s instruction", op)
524		return
525	}
526	switch {
527	case target.Type == obj.TYPE_BRANCH:
528		// JMP 4(PC)
529		*targetAddr = obj.Addr{
530			Type:   obj.TYPE_BRANCH,
531			Offset: p.pc + 1 + target.Offset, // +1 because p.pc is incremented in append, below.
532		}
533	case target.Type == obj.TYPE_REG:
534		// JMP R1
535		*targetAddr = *target
536	case target.Type == obj.TYPE_MEM && (target.Name == obj.NAME_EXTERN || target.Name == obj.NAME_STATIC):
537		// JMP main·morestack(SB)
538		*targetAddr = *target
539	case target.Type == obj.TYPE_INDIR && (target.Name == obj.NAME_EXTERN || target.Name == obj.NAME_STATIC):
540		// JMP *main·morestack(SB)
541		*targetAddr = *target
542		targetAddr.Type = obj.TYPE_INDIR
543	case target.Type == obj.TYPE_MEM && target.Reg == 0 && target.Offset == 0:
544		// JMP exit
545		if target.Sym == nil {
546			// Parse error left name unset.
547			return
548		}
549		targetProg := p.labels[target.Sym.Name]
550		if targetProg == nil {
551			p.toPatch = append(p.toPatch, Patch{targetAddr, target.Sym.Name})
552		} else {
553			p.branch(targetAddr, targetProg)
554		}
555	case target.Type == obj.TYPE_MEM && target.Name == obj.NAME_NONE:
556		// JMP 4(R0)
557		*targetAddr = *target
558		// On the ppc64, 9a encodes BR (CTR) as BR CTR. We do the same.
559		if p.arch.Family == sys.PPC64 && target.Offset == 0 {
560			targetAddr.Type = obj.TYPE_REG
561		}
562	case target.Type == obj.TYPE_CONST:
563		// JMP $4
564		*targetAddr = a[0]
565	case target.Type == obj.TYPE_NONE:
566		// JMP
567	default:
568		p.errorf("cannot assemble jump %+v", target)
569		return
570	}
571
572	p.append(prog, cond, true)
573}
574
575func (p *Parser) patch() {
576	for _, patch := range p.toPatch {
577		targetProg := p.labels[patch.label]
578		if targetProg == nil {
579			p.errorf("undefined label %s", patch.label)
580			return
581		}
582		p.branch(patch.addr, targetProg)
583	}
584	p.toPatch = p.toPatch[:0]
585}
586
587func (p *Parser) branch(addr *obj.Addr, target *obj.Prog) {
588	*addr = obj.Addr{
589		Type:  obj.TYPE_BRANCH,
590		Index: 0,
591	}
592	addr.Val = target
593}
594
595// asmInstruction assembles an instruction.
596// MOVW R9, (R10)
597func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
598	// fmt.Printf("%s %+v\n", op, a)
599	prog := &obj.Prog{
600		Ctxt: p.ctxt,
601		Pos:  p.pos(),
602		As:   op,
603	}
604	switch len(a) {
605	case 0:
606		// Nothing to do.
607	case 1:
608		if p.arch.UnaryDst[op] || op == obj.ARET || op == obj.AGETCALLERPC {
609			// prog.From is no address.
610			prog.To = a[0]
611		} else {
612			prog.From = a[0]
613			// prog.To is no address.
614		}
615		if p.arch.Family == sys.PPC64 && arch.IsPPC64NEG(op) {
616			// NEG: From and To are both a[0].
617			prog.To = a[0]
618			prog.From = a[0]
619			break
620		}
621	case 2:
622		if p.arch.Family == sys.ARM {
623			if arch.IsARMCMP(op) {
624				prog.From = a[0]
625				prog.Reg = p.getRegister(prog, op, &a[1])
626				break
627			}
628			// Strange special cases.
629			if arch.IsARMFloatCmp(op) {
630				prog.From = a[0]
631				prog.Reg = p.getRegister(prog, op, &a[1])
632				break
633			}
634		} else if p.arch.Family == sys.ARM64 && arch.IsARM64CMP(op) {
635			prog.From = a[0]
636			prog.Reg = p.getRegister(prog, op, &a[1])
637			break
638		} else if p.arch.Family == sys.MIPS || p.arch.Family == sys.MIPS64 {
639			if arch.IsMIPSCMP(op) || arch.IsMIPSMUL(op) {
640				prog.From = a[0]
641				prog.Reg = p.getRegister(prog, op, &a[1])
642				break
643			}
644		} else if p.arch.Family == sys.Loong64 {
645			if arch.IsLoong64CMP(op) {
646				prog.From = a[0]
647				prog.Reg = p.getRegister(prog, op, &a[1])
648				break
649			}
650
651			if arch.IsLoong64RDTIME(op) {
652				// The Loong64 RDTIME family of instructions is a bit special,
653				// in that both its register operands are outputs
654				prog.To = a[0]
655				if a[1].Type != obj.TYPE_REG {
656					p.errorf("invalid addressing modes for 2nd operand to %s instruction, must be register", op)
657					return
658				}
659				prog.RegTo2 = a[1].Reg
660				break
661			}
662		}
663		prog.From = a[0]
664		prog.To = a[1]
665	case 3:
666		switch p.arch.Family {
667		case sys.MIPS, sys.MIPS64:
668			prog.From = a[0]
669			prog.Reg = p.getRegister(prog, op, &a[1])
670			prog.To = a[2]
671		case sys.Loong64:
672			switch {
673			// Loong64 atomic instructions with one input and two outputs.
674			case arch.IsLoong64AMO(op):
675				prog.From = a[0]
676				prog.To = a[1]
677				prog.RegTo2 = a[2].Reg
678			default:
679				prog.From = a[0]
680				prog.Reg = p.getRegister(prog, op, &a[1])
681				prog.To = a[2]
682			}
683		case sys.ARM:
684			// Special cases.
685			if arch.IsARMSTREX(op) {
686				/*
687					STREX x, (y), z
688						from=(y) reg=x to=z
689				*/
690				prog.From = a[1]
691				prog.Reg = p.getRegister(prog, op, &a[0])
692				prog.To = a[2]
693				break
694			}
695			if arch.IsARMBFX(op) {
696				// a[0] and a[1] must be constants, a[2] must be a register
697				prog.From = a[0]
698				prog.AddRestSource(a[1])
699				prog.To = a[2]
700				break
701			}
702			// Otherwise the 2nd operand (a[1]) must be a register.
703			prog.From = a[0]
704			prog.Reg = p.getRegister(prog, op, &a[1])
705			prog.To = a[2]
706		case sys.AMD64:
707			prog.From = a[0]
708			prog.AddRestSource(a[1])
709			prog.To = a[2]
710		case sys.ARM64:
711			switch {
712			case arch.IsARM64STLXR(op):
713				// ARM64 instructions with one input and two outputs.
714				prog.From = a[0]
715				prog.To = a[1]
716				if a[2].Type != obj.TYPE_REG {
717					p.errorf("invalid addressing modes for third operand to %s instruction, must be register", op)
718					return
719				}
720				prog.RegTo2 = a[2].Reg
721			case arch.IsARM64TBL(op):
722				// one of its inputs does not fit into prog.Reg.
723				prog.From = a[0]
724				prog.AddRestSource(a[1])
725				prog.To = a[2]
726			case arch.IsARM64CASP(op):
727				prog.From = a[0]
728				prog.To = a[1]
729				// both 1st operand and 3rd operand are (Rs, Rs+1) register pair.
730				// And the register pair must be contiguous.
731				if (a[0].Type != obj.TYPE_REGREG) || (a[2].Type != obj.TYPE_REGREG) {
732					p.errorf("invalid addressing modes for 1st or 3rd operand to %s instruction, must be register pair", op)
733					return
734				}
735				// For ARM64 CASP-like instructions, its 2nd destination operand is register pair(Rt, Rt+1) that can
736				// not fit into prog.RegTo2, so save it to the prog.RestArgs.
737				prog.AddRestDest(a[2])
738			default:
739				prog.From = a[0]
740				prog.Reg = p.getRegister(prog, op, &a[1])
741				prog.To = a[2]
742			}
743		case sys.I386:
744			prog.From = a[0]
745			prog.AddRestSource(a[1])
746			prog.To = a[2]
747		case sys.PPC64:
748			if arch.IsPPC64CMP(op) {
749				// CMPW etc.; third argument is a CR register that goes into prog.Reg.
750				prog.From = a[0]
751				prog.Reg = p.getRegister(prog, op, &a[2])
752				prog.To = a[1]
753				break
754			}
755
756			prog.From = a[0]
757			prog.To = a[2]
758
759			// If the second argument is not a register argument, it must be
760			// passed RestArgs/AddRestSource
761			switch a[1].Type {
762			case obj.TYPE_REG:
763				prog.Reg = p.getRegister(prog, op, &a[1])
764			default:
765				prog.AddRestSource(a[1])
766			}
767		case sys.RISCV64:
768			// RISCV64 instructions with one input and two outputs.
769			if arch.IsRISCV64AMO(op) {
770				prog.From = a[0]
771				prog.To = a[1]
772				if a[2].Type != obj.TYPE_REG {
773					p.errorf("invalid addressing modes for third operand to %s instruction, must be register", op)
774					return
775				}
776				prog.RegTo2 = a[2].Reg
777				break
778			}
779			prog.From = a[0]
780			prog.Reg = p.getRegister(prog, op, &a[1])
781			prog.To = a[2]
782		case sys.S390X:
783			prog.From = a[0]
784			if a[1].Type == obj.TYPE_REG {
785				prog.Reg = p.getRegister(prog, op, &a[1])
786			} else {
787				prog.AddRestSource(a[1])
788			}
789			prog.To = a[2]
790		default:
791			p.errorf("TODO: implement three-operand instructions for this architecture")
792			return
793		}
794	case 4:
795		if p.arch.Family == sys.ARM {
796			if arch.IsARMBFX(op) {
797				// a[0] and a[1] must be constants, a[2] and a[3] must be registers
798				prog.From = a[0]
799				prog.AddRestSource(a[1])
800				prog.Reg = p.getRegister(prog, op, &a[2])
801				prog.To = a[3]
802				break
803			}
804			if arch.IsARMMULA(op) {
805				// All must be registers.
806				p.getRegister(prog, op, &a[0])
807				r1 := p.getRegister(prog, op, &a[1])
808				r2 := p.getRegister(prog, op, &a[2])
809				p.getRegister(prog, op, &a[3])
810				prog.From = a[0]
811				prog.To = a[3]
812				prog.To.Type = obj.TYPE_REGREG2
813				prog.To.Offset = int64(r2)
814				prog.Reg = r1
815				break
816			}
817		}
818		if p.arch.Family == sys.AMD64 {
819			prog.From = a[0]
820			prog.AddRestSourceArgs([]obj.Addr{a[1], a[2]})
821			prog.To = a[3]
822			break
823		}
824		if p.arch.Family == sys.ARM64 {
825			prog.From = a[0]
826			prog.Reg = p.getRegister(prog, op, &a[1])
827			prog.AddRestSource(a[2])
828			prog.To = a[3]
829			break
830		}
831		if p.arch.Family == sys.PPC64 {
832			prog.From = a[0]
833			prog.To = a[3]
834			// If the second argument is not a register argument, it must be
835			// passed RestArgs/AddRestSource
836			if a[1].Type == obj.TYPE_REG {
837				prog.Reg = p.getRegister(prog, op, &a[1])
838				prog.AddRestSource(a[2])
839			} else {
840				// Don't set prog.Reg if a1 isn't a reg arg.
841				prog.AddRestSourceArgs([]obj.Addr{a[1], a[2]})
842			}
843			break
844		}
845		if p.arch.Family == sys.RISCV64 {
846			prog.From = a[0]
847			prog.Reg = p.getRegister(prog, op, &a[1])
848			prog.AddRestSource(a[2])
849			prog.To = a[3]
850			break
851		}
852		if p.arch.Family == sys.S390X {
853			if a[1].Type != obj.TYPE_REG {
854				p.errorf("second operand must be a register in %s instruction", op)
855				return
856			}
857			prog.From = a[0]
858			prog.Reg = p.getRegister(prog, op, &a[1])
859			prog.AddRestSource(a[2])
860			prog.To = a[3]
861			break
862		}
863		p.errorf("can't handle %s instruction with 4 operands", op)
864		return
865	case 5:
866		if p.arch.Family == sys.PPC64 {
867			prog.From = a[0]
868			// Second arg is always a register type on ppc64.
869			prog.Reg = p.getRegister(prog, op, &a[1])
870			prog.AddRestSourceArgs([]obj.Addr{a[2], a[3]})
871			prog.To = a[4]
872			break
873		}
874		if p.arch.Family == sys.AMD64 {
875			prog.From = a[0]
876			prog.AddRestSourceArgs([]obj.Addr{a[1], a[2], a[3]})
877			prog.To = a[4]
878			break
879		}
880		if p.arch.Family == sys.S390X {
881			prog.From = a[0]
882			prog.AddRestSourceArgs([]obj.Addr{a[1], a[2], a[3]})
883			prog.To = a[4]
884			break
885		}
886		p.errorf("can't handle %s instruction with 5 operands", op)
887		return
888	case 6:
889		if p.arch.Family == sys.ARM && arch.IsARMMRC(op) {
890			// Strange special case: MCR, MRC.
891			prog.To.Type = obj.TYPE_CONST
892			x0 := p.getConstant(prog, op, &a[0])
893			x1 := p.getConstant(prog, op, &a[1])
894			x2 := int64(p.getRegister(prog, op, &a[2]))
895			x3 := int64(p.getRegister(prog, op, &a[3]))
896			x4 := int64(p.getRegister(prog, op, &a[4]))
897			x5 := p.getConstant(prog, op, &a[5])
898			// Cond is handled specially for this instruction.
899			offset, MRC, ok := arch.ARMMRCOffset(op, cond, x0, x1, x2, x3, x4, x5)
900			if !ok {
901				p.errorf("unrecognized condition code .%q", cond)
902			}
903			prog.To.Offset = offset
904			cond = ""
905			prog.As = MRC // Both instructions are coded as MRC.
906			break
907		}
908		if p.arch.Family == sys.PPC64 {
909			prog.From = a[0]
910			// Second arg is always a register type on ppc64.
911			prog.Reg = p.getRegister(prog, op, &a[1])
912			prog.AddRestSourceArgs([]obj.Addr{a[2], a[3], a[4]})
913			prog.To = a[5]
914			break
915		}
916		fallthrough
917	default:
918		p.errorf("can't handle %s instruction with %d operands", op, len(a))
919		return
920	}
921
922	p.append(prog, cond, true)
923}
924
925// symbolName returns the symbol name, or an error string if none is available.
926func symbolName(addr *obj.Addr) string {
927	if addr.Sym != nil {
928		return addr.Sym.Name
929	}
930	return "<erroneous symbol>"
931}
932
933var emptyProg obj.Prog
934
935// getConstantPseudo checks that addr represents a plain constant and returns its value.
936func (p *Parser) getConstantPseudo(pseudo string, addr *obj.Addr) int64 {
937	if addr.Type != obj.TYPE_MEM || addr.Name != 0 || addr.Reg != 0 || addr.Index != 0 {
938		p.errorf("%s: expected integer constant; found %s", pseudo, obj.Dconv(&emptyProg, addr))
939	}
940	return addr.Offset
941}
942
943// getConstant checks that addr represents a plain constant and returns its value.
944func (p *Parser) getConstant(prog *obj.Prog, op obj.As, addr *obj.Addr) int64 {
945	if addr.Type != obj.TYPE_MEM || addr.Name != 0 || addr.Reg != 0 || addr.Index != 0 {
946		p.errorf("%s: expected integer constant; found %s", op, obj.Dconv(prog, addr))
947	}
948	return addr.Offset
949}
950
951// getImmediate checks that addr represents an immediate constant and returns its value.
952func (p *Parser) getImmediate(prog *obj.Prog, op obj.As, addr *obj.Addr) int64 {
953	if addr.Type != obj.TYPE_CONST || addr.Name != 0 || addr.Reg != 0 || addr.Index != 0 {
954		p.errorf("%s: expected immediate constant; found %s", op, obj.Dconv(prog, addr))
955	}
956	return addr.Offset
957}
958
959// getRegister checks that addr represents a register and returns its value.
960func (p *Parser) getRegister(prog *obj.Prog, op obj.As, addr *obj.Addr) int16 {
961	if addr.Type != obj.TYPE_REG || addr.Offset != 0 || addr.Name != 0 || addr.Index != 0 {
962		p.errorf("%s: expected register; found %s", op, obj.Dconv(prog, addr))
963	}
964	return addr.Reg
965}
966