github.com/zxy12/golang_with_comment@v0.0.0-20190701084843-0e6b2aff5ef3/cmd/asm/internal/asm/asm.go (about)

     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  
     5  package asm
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"text/scanner"
    11  
    12  	"cmd/asm/internal/arch"
    13  	"cmd/asm/internal/flags"
    14  	"cmd/asm/internal/lex"
    15  	"cmd/internal/obj"
    16  	"cmd/internal/objabi"
    17  	"cmd/internal/sys"
    18  )
    19  
    20  // TODO: configure the architecture
    21  
    22  var testOut *bytes.Buffer // Gathers output when testing.
    23  
    24  // append adds the Prog to the end of the program-thus-far.
    25  // If doLabel is set, it also defines the labels collect for this Prog.
    26  func (p *Parser) append(prog *obj.Prog, cond string, doLabel bool) {
    27  	if cond != "" {
    28  		switch p.arch.Family {
    29  		case sys.ARM:
    30  			if !arch.ARMConditionCodes(prog, cond) {
    31  				p.errorf("unrecognized condition code .%q", cond)
    32  				return
    33  			}
    34  
    35  		case sys.ARM64:
    36  			if !arch.ARM64Suffix(prog, cond) {
    37  				p.errorf("unrecognized suffix .%q", cond)
    38  				return
    39  			}
    40  
    41  		default:
    42  			p.errorf("unrecognized suffix .%q", cond)
    43  			return
    44  		}
    45  	}
    46  	if p.firstProg == nil {
    47  		p.firstProg = prog
    48  	} else {
    49  		p.lastProg.Link = prog
    50  	}
    51  	p.lastProg = prog
    52  	if doLabel {
    53  		p.pc++
    54  		for _, label := range p.pendingLabels {
    55  			if p.labels[label] != nil {
    56  				p.errorf("label %q multiply defined", label)
    57  				return
    58  			}
    59  			p.labels[label] = prog
    60  		}
    61  		p.pendingLabels = p.pendingLabels[0:0]
    62  	}
    63  	prog.Pc = p.pc
    64  	if *flags.Debug {
    65  		fmt.Println(p.lineNum, prog)
    66  	}
    67  	if testOut != nil {
    68  		fmt.Fprintln(testOut, prog)
    69  	}
    70  }
    71  
    72  // validSymbol checks that addr represents a valid name for a pseudo-op.
    73  func (p *Parser) validSymbol(pseudo string, addr *obj.Addr, offsetOk bool) bool {
    74  	if addr.Name != obj.NAME_EXTERN && addr.Name != obj.NAME_STATIC || addr.Scale != 0 || addr.Reg != 0 {
    75  		p.errorf("%s symbol %q must be a symbol(SB)", pseudo, symbolName(addr))
    76  		return false
    77  	}
    78  	if !offsetOk && addr.Offset != 0 {
    79  		p.errorf("%s symbol %q must not be offset from SB", pseudo, symbolName(addr))
    80  		return false
    81  	}
    82  	return true
    83  }
    84  
    85  // evalInteger evaluates an integer constant for a pseudo-op.
    86  func (p *Parser) evalInteger(pseudo string, operands []lex.Token) int64 {
    87  	addr := p.address(operands)
    88  	return p.getConstantPseudo(pseudo, &addr)
    89  }
    90  
    91  // validImmediate checks that addr represents an immediate constant.
    92  func (p *Parser) validImmediate(pseudo string, addr *obj.Addr) bool {
    93  	if addr.Type != obj.TYPE_CONST || addr.Name != 0 || addr.Reg != 0 || addr.Index != 0 {
    94  		p.errorf("%s: expected immediate constant; found %s", pseudo, obj.Dconv(&emptyProg, addr))
    95  		return false
    96  	}
    97  	return true
    98  }
    99  
   100  // asmText assembles a TEXT pseudo-op.
   101  // TEXT runtime·sigtramp(SB),4,$0-0
   102  func (p *Parser) asmText(word string, operands [][]lex.Token) {
   103  	if len(operands) != 2 && len(operands) != 3 {
   104  		p.errorf("expect two or three operands for TEXT")
   105  		return
   106  	}
   107  
   108  	// Labels are function scoped. Patch existing labels and
   109  	// create a new label space for this TEXT.
   110  	p.patch()
   111  	p.labels = make(map[string]*obj.Prog)
   112  
   113  	// Operand 0 is the symbol name in the form foo(SB).
   114  	// That means symbol plus indirect on SB and no offset.
   115  	nameAddr := p.address(operands[0])
   116  	if !p.validSymbol("TEXT", &nameAddr, false) {
   117  		return
   118  	}
   119  	name := symbolName(&nameAddr)
   120  	next := 1
   121  
   122  	// Next operand is the optional text flag, a literal integer.
   123  	var flag = int64(0)
   124  	if len(operands) == 3 {
   125  		flag = p.evalInteger("TEXT", operands[1])
   126  		next++
   127  	}
   128  
   129  	// Next operand is the frame and arg size.
   130  	// Bizarre syntax: $frameSize-argSize is two words, not subtraction.
   131  	// Both frameSize and argSize must be simple integers; only frameSize
   132  	// can be negative.
   133  	// The "-argSize" may be missing; if so, set it to obj.ArgsSizeUnknown.
   134  	// Parse left to right.
   135  	op := operands[next]
   136  	if len(op) < 2 || op[0].ScanToken != '$' {
   137  		p.errorf("TEXT %s: frame size must be an immediate constant", name)
   138  		return
   139  	}
   140  	op = op[1:]
   141  	negative := false
   142  	if op[0].ScanToken == '-' {
   143  		negative = true
   144  		op = op[1:]
   145  	}
   146  	if len(op) == 0 || op[0].ScanToken != scanner.Int {
   147  		p.errorf("TEXT %s: frame size must be an immediate constant", name)
   148  		return
   149  	}
   150  	frameSize := p.positiveAtoi(op[0].String())
   151  	if negative {
   152  		frameSize = -frameSize
   153  	}
   154  	op = op[1:]
   155  	argSize := int64(objabi.ArgsSizeUnknown)
   156  	if len(op) > 0 {
   157  		// There is an argument size. It must be a minus sign followed by a non-negative integer literal.
   158  		if len(op) != 2 || op[0].ScanToken != '-' || op[1].ScanToken != scanner.Int {
   159  			p.errorf("TEXT %s: argument size must be of form -integer", name)
   160  			return
   161  		}
   162  		argSize = p.positiveAtoi(op[1].String())
   163  	}
   164  	p.ctxt.InitTextSym(nameAddr.Sym, int(flag))
   165  	prog := &obj.Prog{
   166  		Ctxt: p.ctxt,
   167  		As:   obj.ATEXT,
   168  		Pos:  p.pos(),
   169  		From: nameAddr,
   170  		To: obj.Addr{
   171  			Type:   obj.TYPE_TEXTSIZE,
   172  			Offset: frameSize,
   173  			// Argsize set below.
   174  		},
   175  	}
   176  	nameAddr.Sym.Func.Text = prog
   177  	prog.To.Val = int32(argSize)
   178  	p.append(prog, "", true)
   179  }
   180  
   181  // asmData assembles a DATA pseudo-op.
   182  // DATA masks<>+0x00(SB)/4, $0x00000000
   183  func (p *Parser) asmData(word string, operands [][]lex.Token) {
   184  	if len(operands) != 2 {
   185  		p.errorf("expect two operands for DATA")
   186  		return
   187  	}
   188  
   189  	// Operand 0 has the general form foo<>+0x04(SB)/4.
   190  	op := operands[0]
   191  	n := len(op)
   192  	if n < 3 || op[n-2].ScanToken != '/' || op[n-1].ScanToken != scanner.Int {
   193  		p.errorf("expect /size for DATA argument")
   194  		return
   195  	}
   196  	scale := p.parseScale(op[n-1].String())
   197  	op = op[:n-2]
   198  	nameAddr := p.address(op)
   199  	if !p.validSymbol("DATA", &nameAddr, true) {
   200  		return
   201  	}
   202  	name := symbolName(&nameAddr)
   203  
   204  	// Operand 1 is an immediate constant or address.
   205  	valueAddr := p.address(operands[1])
   206  	switch valueAddr.Type {
   207  	case obj.TYPE_CONST, obj.TYPE_FCONST, obj.TYPE_SCONST, obj.TYPE_ADDR:
   208  		// OK
   209  	default:
   210  		p.errorf("DATA value must be an immediate constant or address")
   211  		return
   212  	}
   213  
   214  	// The addresses must not overlap. Easiest test: require monotonicity.
   215  	if lastAddr, ok := p.dataAddr[name]; ok && nameAddr.Offset < lastAddr {
   216  		p.errorf("overlapping DATA entry for %s", name)
   217  		return
   218  	}
   219  	p.dataAddr[name] = nameAddr.Offset + int64(scale)
   220  
   221  	switch valueAddr.Type {
   222  	case obj.TYPE_CONST:
   223  		nameAddr.Sym.WriteInt(p.ctxt, nameAddr.Offset, int(scale), valueAddr.Offset)
   224  	case obj.TYPE_FCONST:
   225  		switch scale {
   226  		case 4:
   227  			nameAddr.Sym.WriteFloat32(p.ctxt, nameAddr.Offset, float32(valueAddr.Val.(float64)))
   228  		case 8:
   229  			nameAddr.Sym.WriteFloat64(p.ctxt, nameAddr.Offset, valueAddr.Val.(float64))
   230  		default:
   231  			panic("bad float scale")
   232  		}
   233  	case obj.TYPE_SCONST:
   234  		nameAddr.Sym.WriteString(p.ctxt, nameAddr.Offset, int(scale), valueAddr.Val.(string))
   235  	case obj.TYPE_ADDR:
   236  		nameAddr.Sym.WriteAddr(p.ctxt, nameAddr.Offset, int(scale), valueAddr.Sym, valueAddr.Offset)
   237  	}
   238  }
   239  
   240  // asmGlobl assembles a GLOBL pseudo-op.
   241  // GLOBL shifts<>(SB),8,$256
   242  // GLOBL shifts<>(SB),$256
   243  func (p *Parser) asmGlobl(word string, operands [][]lex.Token) {
   244  	if len(operands) != 2 && len(operands) != 3 {
   245  		p.errorf("expect two or three operands for GLOBL")
   246  		return
   247  	}
   248  
   249  	// Operand 0 has the general form foo<>+0x04(SB).
   250  	nameAddr := p.address(operands[0])
   251  	if !p.validSymbol("GLOBL", &nameAddr, false) {
   252  		return
   253  	}
   254  	next := 1
   255  
   256  	// Next operand is the optional flag, a literal integer.
   257  	var flag = int64(0)
   258  	if len(operands) == 3 {
   259  		flag = p.evalInteger("GLOBL", operands[1])
   260  		next++
   261  	}
   262  
   263  	// Final operand is an immediate constant.
   264  	addr := p.address(operands[next])
   265  	if !p.validImmediate("GLOBL", &addr) {
   266  		return
   267  	}
   268  
   269  	// log.Printf("GLOBL %s %d, $%d", name, flag, size)
   270  	p.ctxt.Globl(nameAddr.Sym, addr.Offset, int(flag))
   271  }
   272  
   273  // asmPCData assembles a PCDATA pseudo-op.
   274  // PCDATA $2, $705
   275  func (p *Parser) asmPCData(word string, operands [][]lex.Token) {
   276  	if len(operands) != 2 {
   277  		p.errorf("expect two operands for PCDATA")
   278  		return
   279  	}
   280  
   281  	// Operand 0 must be an immediate constant.
   282  	key := p.address(operands[0])
   283  	if !p.validImmediate("PCDATA", &key) {
   284  		return
   285  	}
   286  
   287  	// Operand 1 must be an immediate constant.
   288  	value := p.address(operands[1])
   289  	if !p.validImmediate("PCDATA", &value) {
   290  		return
   291  	}
   292  
   293  	// log.Printf("PCDATA $%d, $%d", key.Offset, value.Offset)
   294  	prog := &obj.Prog{
   295  		Ctxt: p.ctxt,
   296  		As:   obj.APCDATA,
   297  		Pos:  p.pos(),
   298  		From: key,
   299  		To:   value,
   300  	}
   301  	p.append(prog, "", true)
   302  }
   303  
   304  // asmFuncData assembles a FUNCDATA pseudo-op.
   305  // FUNCDATA $1, funcdata<>+4(SB)
   306  func (p *Parser) asmFuncData(word string, operands [][]lex.Token) {
   307  	if len(operands) != 2 {
   308  		p.errorf("expect two operands for FUNCDATA")
   309  		return
   310  	}
   311  
   312  	// Operand 0 must be an immediate constant.
   313  	valueAddr := p.address(operands[0])
   314  	if !p.validImmediate("FUNCDATA", &valueAddr) {
   315  		return
   316  	}
   317  
   318  	// Operand 1 is a symbol name in the form foo(SB).
   319  	nameAddr := p.address(operands[1])
   320  	if !p.validSymbol("FUNCDATA", &nameAddr, true) {
   321  		return
   322  	}
   323  
   324  	prog := &obj.Prog{
   325  		Ctxt: p.ctxt,
   326  		As:   obj.AFUNCDATA,
   327  		Pos:  p.pos(),
   328  		From: valueAddr,
   329  		To:   nameAddr,
   330  	}
   331  	p.append(prog, "", true)
   332  }
   333  
   334  // asmJump assembles a jump instruction.
   335  // JMP	R1
   336  // JMP	exit
   337  // JMP	3(PC)
   338  func (p *Parser) asmJump(op obj.As, cond string, a []obj.Addr) {
   339  	var target *obj.Addr
   340  	prog := &obj.Prog{
   341  		Ctxt: p.ctxt,
   342  		Pos:  p.pos(),
   343  		As:   op,
   344  	}
   345  	switch len(a) {
   346  	case 1:
   347  		target = &a[0]
   348  	case 2:
   349  		// Special 2-operand jumps.
   350  		target = &a[1]
   351  		prog.From = a[0]
   352  	case 3:
   353  		if p.arch.Family == sys.PPC64 {
   354  			// Special 3-operand jumps.
   355  			// First two must be constants; a[1] is a register number.
   356  			target = &a[2]
   357  			prog.From = obj.Addr{
   358  				Type:   obj.TYPE_CONST,
   359  				Offset: p.getConstant(prog, op, &a[0]),
   360  			}
   361  			reg := int16(p.getConstant(prog, op, &a[1]))
   362  			reg, ok := p.arch.RegisterNumber("R", reg)
   363  			if !ok {
   364  				p.errorf("bad register number %d", reg)
   365  				return
   366  			}
   367  			prog.Reg = reg
   368  			break
   369  		}
   370  		if p.arch.Family == sys.MIPS || p.arch.Family == sys.MIPS64 {
   371  			// 3-operand jumps.
   372  			// First two must be registers
   373  			target = &a[2]
   374  			prog.From = a[0]
   375  			prog.Reg = p.getRegister(prog, op, &a[1])
   376  			break
   377  		}
   378  		if p.arch.Family == sys.S390X {
   379  			// 3-operand jumps.
   380  			target = &a[2]
   381  			prog.From = a[0]
   382  			if a[1].Reg != 0 {
   383  				// Compare two registers and jump.
   384  				prog.Reg = p.getRegister(prog, op, &a[1])
   385  			} else {
   386  				// Compare register with immediate and jump.
   387  				prog.From3 = newAddr(a[1])
   388  			}
   389  			break
   390  		}
   391  		if p.arch.Family == sys.ARM64 {
   392  			// Special 3-operand jumps.
   393  			// a[0] must be immediate constant; a[1] is a register.
   394  			if a[0].Type != obj.TYPE_CONST {
   395  				p.errorf("%s: expected immediate constant; found %s", op, obj.Dconv(prog, &a[0]))
   396  				return
   397  			}
   398  			prog.From = a[0]
   399  			prog.Reg = p.getRegister(prog, op, &a[1])
   400  			target = &a[2]
   401  			break
   402  		}
   403  
   404  		fallthrough
   405  	default:
   406  		p.errorf("wrong number of arguments to %s instruction", op)
   407  		return
   408  	}
   409  	switch {
   410  	case target.Type == obj.TYPE_BRANCH:
   411  		// JMP 4(PC)
   412  		prog.To = obj.Addr{
   413  			Type:   obj.TYPE_BRANCH,
   414  			Offset: p.pc + 1 + target.Offset, // +1 because p.pc is incremented in append, below.
   415  		}
   416  	case target.Type == obj.TYPE_REG:
   417  		// JMP R1
   418  		prog.To = *target
   419  	case target.Type == obj.TYPE_MEM && (target.Name == obj.NAME_EXTERN || target.Name == obj.NAME_STATIC):
   420  		// JMP main·morestack(SB)
   421  		prog.To = *target
   422  	case target.Type == obj.TYPE_INDIR && (target.Name == obj.NAME_EXTERN || target.Name == obj.NAME_STATIC):
   423  		// JMP *main·morestack(SB)
   424  		prog.To = *target
   425  		prog.To.Type = obj.TYPE_INDIR
   426  	case target.Type == obj.TYPE_MEM && target.Reg == 0 && target.Offset == 0:
   427  		// JMP exit
   428  		if target.Sym == nil {
   429  			// Parse error left name unset.
   430  			return
   431  		}
   432  		targetProg := p.labels[target.Sym.Name]
   433  		if targetProg == nil {
   434  			p.toPatch = append(p.toPatch, Patch{prog, target.Sym.Name})
   435  		} else {
   436  			p.branch(prog, targetProg)
   437  		}
   438  	case target.Type == obj.TYPE_MEM && target.Name == obj.NAME_NONE:
   439  		// JMP 4(R0)
   440  		prog.To = *target
   441  		// On the ppc64, 9a encodes BR (CTR) as BR CTR. We do the same.
   442  		if p.arch.Family == sys.PPC64 && target.Offset == 0 {
   443  			prog.To.Type = obj.TYPE_REG
   444  		}
   445  	case target.Type == obj.TYPE_CONST:
   446  		// JMP $4
   447  		prog.To = a[0]
   448  	default:
   449  		p.errorf("cannot assemble jump %+v", target)
   450  		return
   451  	}
   452  
   453  	p.append(prog, cond, true)
   454  }
   455  
   456  func (p *Parser) patch() {
   457  	for _, patch := range p.toPatch {
   458  		targetProg := p.labels[patch.label]
   459  		if targetProg == nil {
   460  			p.errorf("undefined label %s", patch.label)
   461  			return
   462  		}
   463  		p.branch(patch.prog, targetProg)
   464  	}
   465  	p.toPatch = p.toPatch[:0]
   466  }
   467  
   468  func (p *Parser) branch(jmp, target *obj.Prog) {
   469  	jmp.To = obj.Addr{
   470  		Type:  obj.TYPE_BRANCH,
   471  		Index: 0,
   472  	}
   473  	jmp.To.Val = target
   474  }
   475  
   476  // asmInstruction assembles an instruction.
   477  // MOVW R9, (R10)
   478  func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
   479  	// fmt.Printf("%s %+v\n", op, a)
   480  	prog := &obj.Prog{
   481  		Ctxt: p.ctxt,
   482  		Pos:  p.pos(),
   483  		As:   op,
   484  	}
   485  	switch len(a) {
   486  	case 0:
   487  		// Nothing to do.
   488  	case 1:
   489  		if p.arch.UnaryDst[op] {
   490  			// prog.From is no address.
   491  			prog.To = a[0]
   492  		} else {
   493  			prog.From = a[0]
   494  			// prog.To is no address.
   495  		}
   496  		if p.arch.Family == sys.PPC64 && arch.IsPPC64NEG(op) {
   497  			// NEG: From and To are both a[0].
   498  			prog.To = a[0]
   499  			prog.From = a[0]
   500  			break
   501  		}
   502  	case 2:
   503  		if p.arch.Family == sys.ARM {
   504  			if arch.IsARMCMP(op) {
   505  				prog.From = a[0]
   506  				prog.Reg = p.getRegister(prog, op, &a[1])
   507  				break
   508  			}
   509  			// Strange special cases.
   510  			if arch.IsARMSTREX(op) {
   511  				/*
   512  					STREX x, (y)
   513  						from=(y) reg=x to=x
   514  					STREX (x), y
   515  						from=(x) reg=y to=y
   516  				*/
   517  				if a[0].Type == obj.TYPE_REG && a[1].Type != obj.TYPE_REG {
   518  					prog.From = a[1]
   519  					prog.Reg = a[0].Reg
   520  					prog.To = a[0]
   521  					break
   522  				} else if a[0].Type != obj.TYPE_REG && a[1].Type == obj.TYPE_REG {
   523  					prog.From = a[0]
   524  					prog.Reg = a[1].Reg
   525  					prog.To = a[1]
   526  					break
   527  				}
   528  				p.errorf("unrecognized addressing for %s", op)
   529  				return
   530  			}
   531  			if arch.IsARMFloatCmp(op) {
   532  				prog.From = a[0]
   533  				prog.Reg = p.getRegister(prog, op, &a[1])
   534  				break
   535  			}
   536  		} else if p.arch.Family == sys.ARM64 && arch.IsARM64CMP(op) {
   537  			prog.From = a[0]
   538  			prog.Reg = p.getRegister(prog, op, &a[1])
   539  			break
   540  		} else if p.arch.Family == sys.MIPS || p.arch.Family == sys.MIPS64 {
   541  			if arch.IsMIPSCMP(op) || arch.IsMIPSMUL(op) {
   542  				prog.From = a[0]
   543  				prog.Reg = p.getRegister(prog, op, &a[1])
   544  				break
   545  			}
   546  		}
   547  		prog.From = a[0]
   548  		prog.To = a[1]
   549  	case 3:
   550  		switch p.arch.Family {
   551  		case sys.MIPS, sys.MIPS64:
   552  			prog.From = a[0]
   553  			prog.Reg = p.getRegister(prog, op, &a[1])
   554  			prog.To = a[2]
   555  		case sys.ARM:
   556  			// Special cases.
   557  			if arch.IsARMSTREX(op) {
   558  				/*
   559  					STREX x, (y), z
   560  						from=(y) reg=x to=z
   561  				*/
   562  				prog.From = a[1]
   563  				prog.Reg = p.getRegister(prog, op, &a[0])
   564  				prog.To = a[2]
   565  				break
   566  			}
   567  			// Otherwise the 2nd operand (a[1]) must be a register.
   568  			prog.From = a[0]
   569  			prog.Reg = p.getRegister(prog, op, &a[1])
   570  			prog.To = a[2]
   571  		case sys.AMD64:
   572  			// Catch missing operand here, because we store immediate as part of From3, and can't distinguish
   573  			// missing operand from legal value 0 in obj/x86/asm6.
   574  			if arch.IsAMD4OP(op) {
   575  				p.errorf("4 operands required, but only 3 are provided for %s instruction", op)
   576  			}
   577  			prog.From = a[0]
   578  			prog.From3 = newAddr(a[1])
   579  			prog.To = a[2]
   580  		case sys.ARM64:
   581  			// ARM64 instructions with one input and two outputs.
   582  			if arch.IsARM64STLXR(op) {
   583  				prog.From = a[0]
   584  				prog.To = a[1]
   585  				if a[2].Type != obj.TYPE_REG {
   586  					p.errorf("invalid addressing modes for third operand to %s instruction, must be register", op)
   587  					return
   588  				}
   589  				prog.RegTo2 = a[2].Reg
   590  				break
   591  			}
   592  			prog.From = a[0]
   593  			prog.Reg = p.getRegister(prog, op, &a[1])
   594  			prog.To = a[2]
   595  		case sys.I386:
   596  			prog.From = a[0]
   597  			prog.From3 = newAddr(a[1])
   598  			prog.To = a[2]
   599  		case sys.PPC64:
   600  			if arch.IsPPC64CMP(op) {
   601  				// CMPW etc.; third argument is a CR register that goes into prog.Reg.
   602  				prog.From = a[0]
   603  				prog.Reg = p.getRegister(prog, op, &a[2])
   604  				prog.To = a[1]
   605  				break
   606  			}
   607  			// Arithmetic. Choices are:
   608  			// reg reg reg
   609  			// imm reg reg
   610  			// reg imm reg
   611  			// If the immediate is the middle argument, use From3.
   612  			switch a[1].Type {
   613  			case obj.TYPE_REG:
   614  				prog.From = a[0]
   615  				prog.Reg = p.getRegister(prog, op, &a[1])
   616  				prog.To = a[2]
   617  			case obj.TYPE_CONST:
   618  				prog.From = a[0]
   619  				prog.From3 = newAddr(a[1])
   620  				prog.To = a[2]
   621  			default:
   622  				p.errorf("invalid addressing modes for %s instruction", op)
   623  				return
   624  			}
   625  		case sys.S390X:
   626  			prog.From = a[0]
   627  			if a[1].Type == obj.TYPE_REG {
   628  				prog.Reg = p.getRegister(prog, op, &a[1])
   629  			} else {
   630  				prog.From3 = newAddr(a[1])
   631  			}
   632  			prog.To = a[2]
   633  		default:
   634  			p.errorf("TODO: implement three-operand instructions for this architecture")
   635  			return
   636  		}
   637  	case 4:
   638  		if p.arch.Family == sys.ARM && arch.IsARMMULA(op) {
   639  			// All must be registers.
   640  			p.getRegister(prog, op, &a[0])
   641  			r1 := p.getRegister(prog, op, &a[1])
   642  			r2 := p.getRegister(prog, op, &a[2])
   643  			p.getRegister(prog, op, &a[3])
   644  			prog.From = a[0]
   645  			prog.To = a[3]
   646  			prog.To.Type = obj.TYPE_REGREG2
   647  			prog.To.Offset = int64(r2)
   648  			prog.Reg = r1
   649  			break
   650  		}
   651  		if p.arch.Family == sys.AMD64 {
   652  			// 4 operand instruction have form  ymm1, ymm2, ymm3/m256, imm8
   653  			// So From3 is always just a register, so we store imm8 in Offset field,
   654  			// to avoid increasing size of Prog.
   655  			prog.From = a[1]
   656  			prog.From3 = newAddr(a[2])
   657  			if a[0].Type != obj.TYPE_CONST {
   658  				p.errorf("first operand must be an immediate in %s instruction", op)
   659  			}
   660  			if prog.From3.Type != obj.TYPE_REG {
   661  				p.errorf("third operand must be a register in %s instruction", op)
   662  			}
   663  			prog.From3.Offset = int64(p.getImmediate(prog, op, &a[0]))
   664  			prog.To = a[3]
   665  			prog.RegTo2 = -1
   666  			break
   667  		}
   668  		if p.arch.Family == sys.ARM64 {
   669  			prog.From = a[0]
   670  			prog.Reg = p.getRegister(prog, op, &a[1])
   671  			prog.From3 = newAddr(a[2])
   672  			prog.To = a[3]
   673  			break
   674  		}
   675  		if p.arch.Family == sys.PPC64 {
   676  			if arch.IsPPC64RLD(op) {
   677  				prog.From = a[0]
   678  				prog.Reg = p.getRegister(prog, op, &a[1])
   679  				prog.From3 = newAddr(a[2])
   680  				prog.To = a[3]
   681  				break
   682  			} else if arch.IsPPC64ISEL(op) {
   683  				// ISEL BC,RB,RA,RT becomes isel rt,ra,rb,bc
   684  				prog.From3 = newAddr(a[2])                // ra
   685  				prog.From = a[0]                          // bc
   686  				prog.Reg = p.getRegister(prog, op, &a[1]) // rb
   687  				prog.To = a[3]                            // rt
   688  				break
   689  			}
   690  			// Else, it is a VA-form instruction
   691  			// reg reg reg reg
   692  			// imm reg reg reg
   693  			// Or a VX-form instruction
   694  			// imm imm reg reg
   695  			if a[1].Type == obj.TYPE_REG {
   696  				prog.From = a[0]
   697  				prog.Reg = p.getRegister(prog, op, &a[1])
   698  				prog.From3 = newAddr(a[2])
   699  				prog.To = a[3]
   700  				break
   701  			} else if a[1].Type == obj.TYPE_CONST {
   702  				prog.From = a[0]
   703  				prog.Reg = p.getRegister(prog, op, &a[2])
   704  				prog.From3 = newAddr(a[1])
   705  				prog.To = a[3]
   706  				break
   707  			} else {
   708  				p.errorf("invalid addressing modes for %s instruction", op)
   709  				return
   710  			}
   711  		}
   712  		if p.arch.Family == sys.S390X {
   713  			if a[1].Type != obj.TYPE_REG {
   714  				p.errorf("second operand must be a register in %s instruction", op)
   715  				return
   716  			}
   717  			prog.From = a[0]
   718  			prog.Reg = p.getRegister(prog, op, &a[1])
   719  			prog.From3 = newAddr(a[2])
   720  			prog.To = a[3]
   721  			break
   722  		}
   723  		p.errorf("can't handle %s instruction with 4 operands", op)
   724  		return
   725  	case 5:
   726  		if p.arch.Family == sys.PPC64 && arch.IsPPC64RLD(op) {
   727  			// Always reg, reg, con, con, reg.  (con, con is a 'mask').
   728  			prog.From = a[0]
   729  			prog.Reg = p.getRegister(prog, op, &a[1])
   730  			mask1 := p.getConstant(prog, op, &a[2])
   731  			mask2 := p.getConstant(prog, op, &a[3])
   732  			var mask uint32
   733  			if mask1 < mask2 {
   734  				mask = (^uint32(0) >> uint(mask1)) & (^uint32(0) << uint(31-mask2))
   735  			} else {
   736  				mask = (^uint32(0) >> uint(mask2+1)) & (^uint32(0) << uint(31-(mask1-1)))
   737  			}
   738  			prog.From3 = &obj.Addr{
   739  				Type:   obj.TYPE_CONST,
   740  				Offset: int64(mask),
   741  			}
   742  			prog.To = a[4]
   743  			break
   744  		}
   745  		p.errorf("can't handle %s instruction with 5 operands", op)
   746  		return
   747  	case 6:
   748  		if p.arch.Family == sys.ARM && arch.IsARMMRC(op) {
   749  			// Strange special case: MCR, MRC.
   750  			prog.To.Type = obj.TYPE_CONST
   751  			x0 := p.getConstant(prog, op, &a[0])
   752  			x1 := p.getConstant(prog, op, &a[1])
   753  			x2 := int64(p.getRegister(prog, op, &a[2]))
   754  			x3 := int64(p.getRegister(prog, op, &a[3]))
   755  			x4 := int64(p.getRegister(prog, op, &a[4]))
   756  			x5 := p.getConstant(prog, op, &a[5])
   757  			// Cond is handled specially for this instruction.
   758  			offset, MRC, ok := arch.ARMMRCOffset(op, cond, x0, x1, x2, x3, x4, x5)
   759  			if !ok {
   760  				p.errorf("unrecognized condition code .%q", cond)
   761  			}
   762  			prog.To.Offset = offset
   763  			cond = ""
   764  			prog.As = MRC // Both instructions are coded as MRC.
   765  			break
   766  		}
   767  		fallthrough
   768  	default:
   769  		p.errorf("can't handle %s instruction with %d operands", op, len(a))
   770  		return
   771  	}
   772  
   773  	p.append(prog, cond, true)
   774  }
   775  
   776  // newAddr returns a new(Addr) initialized to x.
   777  func newAddr(x obj.Addr) *obj.Addr {
   778  	p := new(obj.Addr)
   779  	*p = x
   780  	return p
   781  }
   782  
   783  // symbolName returns the symbol name, or an error string if none if available.
   784  func symbolName(addr *obj.Addr) string {
   785  	if addr.Sym != nil {
   786  		return addr.Sym.Name
   787  	}
   788  	return "<erroneous symbol>"
   789  }
   790  
   791  var emptyProg obj.Prog
   792  
   793  // getConstantPseudo checks that addr represents a plain constant and returns its value.
   794  func (p *Parser) getConstantPseudo(pseudo string, addr *obj.Addr) int64 {
   795  	if addr.Type != obj.TYPE_MEM || addr.Name != 0 || addr.Reg != 0 || addr.Index != 0 {
   796  		p.errorf("%s: expected integer constant; found %s", pseudo, obj.Dconv(&emptyProg, addr))
   797  	}
   798  	return addr.Offset
   799  }
   800  
   801  // getConstant checks that addr represents a plain constant and returns its value.
   802  func (p *Parser) getConstant(prog *obj.Prog, op obj.As, addr *obj.Addr) int64 {
   803  	if addr.Type != obj.TYPE_MEM || addr.Name != 0 || addr.Reg != 0 || addr.Index != 0 {
   804  		p.errorf("%s: expected integer constant; found %s", op, obj.Dconv(prog, addr))
   805  	}
   806  	return addr.Offset
   807  }
   808  
   809  // getImmediate checks that addr represents an immediate constant and returns its value.
   810  func (p *Parser) getImmediate(prog *obj.Prog, op obj.As, addr *obj.Addr) int64 {
   811  	if addr.Type != obj.TYPE_CONST || addr.Name != 0 || addr.Reg != 0 || addr.Index != 0 {
   812  		p.errorf("%s: expected immediate constant; found %s", op, obj.Dconv(prog, addr))
   813  	}
   814  	return addr.Offset
   815  }
   816  
   817  // getRegister checks that addr represents a register and returns its value.
   818  func (p *Parser) getRegister(prog *obj.Prog, op obj.As, addr *obj.Addr) int16 {
   819  	if addr.Type != obj.TYPE_REG || addr.Offset != 0 || addr.Name != 0 || addr.Index != 0 {
   820  		p.errorf("%s: expected register; found %s", op, obj.Dconv(prog, addr))
   821  	}
   822  	return addr.Reg
   823  }