Source file src/cmd/asm/internal/asm/asm.go

     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  	"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  
    26  var 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.
    30  func (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.
    87  func (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.
   100  func (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.
   106  func (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
   116  func (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
   205  func (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
   278  func (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
   310  func (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
   341  func (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  		Pos:  p.pos(),
   357  		From: key,
   358  	}
   359  	p.append(prog, "", true)
   360  }
   361  
   362  // asmFuncData assembles a FUNCDATA pseudo-op.
   363  // FUNCDATA $1, funcdata<>+4(SB)
   364  func (p *Parser) asmFuncData(operands [][]lex.Token) {
   365  	if len(operands) != 2 {
   366  		p.errorf("expect two operands for FUNCDATA")
   367  		return
   368  	}
   369  
   370  	// Operand 0 must be an immediate constant.
   371  	valueAddr := p.address(operands[0])
   372  	if !p.validImmediate("FUNCDATA", &valueAddr) {
   373  		return
   374  	}
   375  
   376  	// Operand 1 is a symbol name in the form foo(SB).
   377  	nameAddr := p.address(operands[1])
   378  	if !p.validSymbol("FUNCDATA", &nameAddr, true) {
   379  		return
   380  	}
   381  
   382  	prog := &obj.Prog{
   383  		Ctxt: p.ctxt,
   384  		As:   obj.AFUNCDATA,
   385  		Pos:  p.pos(),
   386  		From: valueAddr,
   387  		To:   nameAddr,
   388  	}
   389  	p.append(prog, "", true)
   390  }
   391  
   392  // asmJump assembles a jump instruction.
   393  // JMP	R1
   394  // JMP	exit
   395  // JMP	3(PC)
   396  func (p *Parser) asmJump(op obj.As, cond string, a []obj.Addr) {
   397  	var target *obj.Addr
   398  	prog := &obj.Prog{
   399  		Ctxt: p.ctxt,
   400  		Pos:  p.pos(),
   401  		As:   op,
   402  	}
   403  	targetAddr := &prog.To
   404  	switch len(a) {
   405  	case 0:
   406  		if p.arch.Family == sys.Wasm {
   407  			target = &obj.Addr{Type: obj.TYPE_NONE}
   408  			break
   409  		}
   410  		p.errorf("wrong number of arguments to %s instruction", op)
   411  		return
   412  	case 1:
   413  		target = &a[0]
   414  	case 2:
   415  		// Special 2-operand jumps.
   416  		if p.arch.Family == sys.ARM64 && arch.IsARM64ADR(op) {
   417  			// ADR label, R. Label is in From.
   418  			target = &a[0]
   419  			prog.To = a[1]
   420  			targetAddr = &prog.From
   421  		} else {
   422  			target = &a[1]
   423  			prog.From = a[0]
   424  		}
   425  	case 3:
   426  		if p.arch.Family == sys.PPC64 {
   427  			// Special 3-operand jumps.
   428  			// a[1] is a register number expressed as a constant or register value
   429  			target = &a[2]
   430  			prog.From = a[0]
   431  			if a[0].Type != obj.TYPE_CONST {
   432  				// Legacy code may use a plain constant, accept it, and coerce
   433  				// into a constant. E.g:
   434  				//   BC 4,...
   435  				// into
   436  				//   BC $4,...
   437  				prog.From = obj.Addr{
   438  					Type:   obj.TYPE_CONST,
   439  					Offset: p.getConstant(prog, op, &a[0]),
   440  				}
   441  
   442  			}
   443  
   444  			// Likewise, fixup usage like:
   445  			//   BC x,LT,...
   446  			//   BC x,foo+2,...
   447  			//   BC x,4
   448  			//   BC x,$5
   449  			// into
   450  			//   BC x,CR0LT,...
   451  			//   BC x,CR0EQ,...
   452  			//   BC x,CR1LT,...
   453  			//   BC x,CR1GT,...
   454  			// The first and second cases demonstrate a symbol name which is
   455  			// effectively discarded. In these cases, the offset determines
   456  			// the CR bit.
   457  			prog.Reg = a[1].Reg
   458  			if a[1].Type != obj.TYPE_REG {
   459  				// The CR bit is represented as a constant 0-31. Convert it to a Reg.
   460  				c := p.getConstant(prog, op, &a[1])
   461  				reg, success := ppc64.ConstantToCRbit(c)
   462  				if !success {
   463  					p.errorf("invalid CR bit register number %d", c)
   464  				}
   465  				prog.Reg = reg
   466  			}
   467  			break
   468  		}
   469  		if p.arch.Family == sys.MIPS || p.arch.Family == sys.MIPS64 || p.arch.Family == sys.RISCV64 {
   470  			// 3-operand jumps.
   471  			// First two must be registers
   472  			target = &a[2]
   473  			prog.From = a[0]
   474  			prog.Reg = p.getRegister(prog, op, &a[1])
   475  			break
   476  		}
   477  		if p.arch.Family == sys.Loong64 {
   478  			// 3-operand jumps.
   479  			// First two must be registers
   480  			target = &a[2]
   481  			prog.From = a[0]
   482  			prog.Reg = p.getRegister(prog, op, &a[1])
   483  			break
   484  		}
   485  		if p.arch.Family == sys.S390X {
   486  			// 3-operand jumps.
   487  			target = &a[2]
   488  			prog.From = a[0]
   489  			if a[1].Reg != 0 {
   490  				// Compare two registers and jump.
   491  				prog.Reg = p.getRegister(prog, op, &a[1])
   492  			} else {
   493  				// Compare register with immediate and jump.
   494  				prog.AddRestSource(a[1])
   495  			}
   496  			break
   497  		}
   498  		if p.arch.Family == sys.ARM64 {
   499  			// Special 3-operand jumps.
   500  			// a[0] must be immediate constant; a[1] is a register.
   501  			if a[0].Type != obj.TYPE_CONST {
   502  				p.errorf("%s: expected immediate constant; found %s", op, obj.Dconv(prog, &a[0]))
   503  				return
   504  			}
   505  			prog.From = a[0]
   506  			prog.Reg = p.getRegister(prog, op, &a[1])
   507  			target = &a[2]
   508  			break
   509  		}
   510  		p.errorf("wrong number of arguments to %s instruction", op)
   511  		return
   512  	case 4:
   513  		if p.arch.Family == sys.S390X || p.arch.Family == sys.PPC64 {
   514  			// 4-operand compare-and-branch.
   515  			prog.From = a[0]
   516  			prog.Reg = p.getRegister(prog, op, &a[1])
   517  			prog.AddRestSource(a[2])
   518  			target = &a[3]
   519  			break
   520  		}
   521  		p.errorf("wrong number of arguments to %s instruction", op)
   522  		return
   523  	default:
   524  		p.errorf("wrong number of arguments to %s instruction", op)
   525  		return
   526  	}
   527  	switch {
   528  	case target.Type == obj.TYPE_BRANCH:
   529  		// JMP 4(PC)
   530  		*targetAddr = obj.Addr{
   531  			Type:   obj.TYPE_BRANCH,
   532  			Offset: p.pc + 1 + target.Offset, // +1 because p.pc is incremented in append, below.
   533  		}
   534  	case target.Type == obj.TYPE_REG:
   535  		// JMP R1
   536  		*targetAddr = *target
   537  	case target.Type == obj.TYPE_MEM && (target.Name == obj.NAME_EXTERN || target.Name == obj.NAME_STATIC):
   538  		// JMP main·morestack(SB)
   539  		*targetAddr = *target
   540  	case target.Type == obj.TYPE_INDIR && (target.Name == obj.NAME_EXTERN || target.Name == obj.NAME_STATIC):
   541  		// JMP *main·morestack(SB)
   542  		*targetAddr = *target
   543  		targetAddr.Type = obj.TYPE_INDIR
   544  	case target.Type == obj.TYPE_MEM && target.Reg == 0 && target.Offset == 0:
   545  		// JMP exit
   546  		if target.Sym == nil {
   547  			// Parse error left name unset.
   548  			return
   549  		}
   550  		targetProg := p.labels[target.Sym.Name]
   551  		if targetProg == nil {
   552  			p.toPatch = append(p.toPatch, Patch{targetAddr, target.Sym.Name})
   553  		} else {
   554  			p.branch(targetAddr, targetProg)
   555  		}
   556  	case target.Type == obj.TYPE_MEM && target.Name == obj.NAME_NONE:
   557  		// JMP 4(R0)
   558  		*targetAddr = *target
   559  		// On the ppc64, 9a encodes BR (CTR) as BR CTR. We do the same.
   560  		if p.arch.Family == sys.PPC64 && target.Offset == 0 {
   561  			targetAddr.Type = obj.TYPE_REG
   562  		}
   563  	case target.Type == obj.TYPE_CONST:
   564  		// JMP $4
   565  		*targetAddr = a[0]
   566  	case target.Type == obj.TYPE_NONE:
   567  		// JMP
   568  	default:
   569  		p.errorf("cannot assemble jump %+v", target)
   570  		return
   571  	}
   572  
   573  	p.append(prog, cond, true)
   574  }
   575  
   576  func (p *Parser) patch() {
   577  	for _, patch := range p.toPatch {
   578  		targetProg := p.labels[patch.label]
   579  		if targetProg == nil {
   580  			p.errorf("undefined label %s", patch.label)
   581  			return
   582  		}
   583  		p.branch(patch.addr, targetProg)
   584  	}
   585  	p.toPatch = p.toPatch[:0]
   586  }
   587  
   588  func (p *Parser) branch(addr *obj.Addr, target *obj.Prog) {
   589  	*addr = obj.Addr{
   590  		Type:  obj.TYPE_BRANCH,
   591  		Index: 0,
   592  	}
   593  	addr.Val = target
   594  }
   595  
   596  // asmInstruction assembles an instruction.
   597  // MOVW R9, (R10)
   598  func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
   599  	// fmt.Printf("%s %+v\n", op, a)
   600  	prog := &obj.Prog{
   601  		Ctxt: p.ctxt,
   602  		Pos:  p.pos(),
   603  		As:   op,
   604  	}
   605  	switch len(a) {
   606  	case 0:
   607  		// Nothing to do.
   608  	case 1:
   609  		if p.arch.UnaryDst[op] || op == obj.ARET || op == obj.AGETCALLERPC {
   610  			// prog.From is no address.
   611  			prog.To = a[0]
   612  		} else {
   613  			prog.From = a[0]
   614  			// prog.To is no address.
   615  		}
   616  		if p.arch.Family == sys.PPC64 && arch.IsPPC64NEG(op) {
   617  			// NEG: From and To are both a[0].
   618  			prog.To = a[0]
   619  			prog.From = a[0]
   620  			break
   621  		}
   622  	case 2:
   623  		if p.arch.Family == sys.ARM {
   624  			if arch.IsARMCMP(op) {
   625  				prog.From = a[0]
   626  				prog.Reg = p.getRegister(prog, op, &a[1])
   627  				break
   628  			}
   629  			// Strange special cases.
   630  			if arch.IsARMFloatCmp(op) {
   631  				prog.From = a[0]
   632  				prog.Reg = p.getRegister(prog, op, &a[1])
   633  				break
   634  			}
   635  		} else if p.arch.Family == sys.ARM64 && arch.IsARM64CMP(op) {
   636  			prog.From = a[0]
   637  			prog.Reg = p.getRegister(prog, op, &a[1])
   638  			break
   639  		} else if p.arch.Family == sys.MIPS || p.arch.Family == sys.MIPS64 {
   640  			if arch.IsMIPSCMP(op) || arch.IsMIPSMUL(op) {
   641  				prog.From = a[0]
   642  				prog.Reg = p.getRegister(prog, op, &a[1])
   643  				break
   644  			}
   645  		} else if p.arch.Family == sys.Loong64 {
   646  			if arch.IsLoong64RDTIME(op) {
   647  				// The Loong64 RDTIME family of instructions is a bit special,
   648  				// in that both its register operands are outputs
   649  				prog.To = a[0]
   650  				if a[1].Type != obj.TYPE_REG {
   651  					p.errorf("invalid addressing modes for 2nd operand to %s instruction, must be register", op)
   652  					return
   653  				}
   654  				prog.RegTo2 = a[1].Reg
   655  				break
   656  			}
   657  
   658  			if arch.IsLoong64PRELD(op) {
   659  				prog.From = a[0]
   660  				prog.AddRestSource(a[1])
   661  				break
   662  			}
   663  		}
   664  		prog.From = a[0]
   665  		prog.To = a[1]
   666  	case 3:
   667  		switch p.arch.Family {
   668  		case sys.MIPS, sys.MIPS64:
   669  			prog.From = a[0]
   670  			prog.Reg = p.getRegister(prog, op, &a[1])
   671  			prog.To = a[2]
   672  		case sys.Loong64:
   673  			switch {
   674  			// Loong64 atomic instructions with one input and two outputs.
   675  			case arch.IsLoong64AMO(op):
   676  				prog.From = a[0]
   677  				prog.To = a[1]
   678  				prog.RegTo2 = a[2].Reg
   679  
   680  			case arch.IsLoong64PRELD(op):
   681  				prog.From = a[0]
   682  				prog.AddRestSourceArgs([]obj.Addr{a[1], a[2]})
   683  
   684  			default:
   685  				prog.From = a[0]
   686  				prog.Reg = p.getRegister(prog, op, &a[1])
   687  				prog.To = a[2]
   688  			}
   689  		case sys.ARM:
   690  			// Special cases.
   691  			if arch.IsARMSTREX(op) {
   692  				/*
   693  					STREX x, (y), z
   694  						from=(y) reg=x to=z
   695  				*/
   696  				prog.From = a[1]
   697  				prog.Reg = p.getRegister(prog, op, &a[0])
   698  				prog.To = a[2]
   699  				break
   700  			}
   701  			if arch.IsARMBFX(op) {
   702  				// a[0] and a[1] must be constants, a[2] must be a register
   703  				prog.From = a[0]
   704  				prog.AddRestSource(a[1])
   705  				prog.To = a[2]
   706  				break
   707  			}
   708  			// Otherwise the 2nd operand (a[1]) must be a register.
   709  			prog.From = a[0]
   710  			prog.Reg = p.getRegister(prog, op, &a[1])
   711  			prog.To = a[2]
   712  		case sys.AMD64:
   713  			prog.From = a[0]
   714  			prog.AddRestSource(a[1])
   715  			prog.To = a[2]
   716  		case sys.ARM64:
   717  			switch {
   718  			case arch.IsARM64STLXR(op):
   719  				// ARM64 instructions with one input and two outputs.
   720  				prog.From = a[0]
   721  				prog.To = a[1]
   722  				if a[2].Type != obj.TYPE_REG {
   723  					p.errorf("invalid addressing modes for third operand to %s instruction, must be register", op)
   724  					return
   725  				}
   726  				prog.RegTo2 = a[2].Reg
   727  			case arch.IsARM64TBL(op):
   728  				// one of its inputs does not fit into prog.Reg.
   729  				prog.From = a[0]
   730  				prog.AddRestSource(a[1])
   731  				prog.To = a[2]
   732  			case arch.IsARM64CASP(op):
   733  				prog.From = a[0]
   734  				prog.To = a[1]
   735  				// both 1st operand and 3rd operand are (Rs, Rs+1) register pair.
   736  				// And the register pair must be contiguous.
   737  				if (a[0].Type != obj.TYPE_REGREG) || (a[2].Type != obj.TYPE_REGREG) {
   738  					p.errorf("invalid addressing modes for 1st or 3rd operand to %s instruction, must be register pair", op)
   739  					return
   740  				}
   741  				// For ARM64 CASP-like instructions, its 2nd destination operand is register pair(Rt, Rt+1) that can
   742  				// not fit into prog.RegTo2, so save it to the prog.RestArgs.
   743  				prog.AddRestDest(a[2])
   744  			default:
   745  				prog.From = a[0]
   746  				prog.Reg = p.getRegister(prog, op, &a[1])
   747  				prog.To = a[2]
   748  			}
   749  		case sys.I386:
   750  			prog.From = a[0]
   751  			prog.AddRestSource(a[1])
   752  			prog.To = a[2]
   753  		case sys.PPC64:
   754  			if arch.IsPPC64CMP(op) {
   755  				// CMPW etc.; third argument is a CR register that goes into prog.Reg.
   756  				prog.From = a[0]
   757  				prog.Reg = p.getRegister(prog, op, &a[2])
   758  				prog.To = a[1]
   759  				break
   760  			}
   761  
   762  			prog.From = a[0]
   763  			prog.To = a[2]
   764  
   765  			// If the second argument is not a register argument, it must be
   766  			// passed RestArgs/AddRestSource
   767  			switch a[1].Type {
   768  			case obj.TYPE_REG:
   769  				prog.Reg = p.getRegister(prog, op, &a[1])
   770  			default:
   771  				prog.AddRestSource(a[1])
   772  			}
   773  		case sys.RISCV64:
   774  			// RISCV64 instructions with one input and two outputs.
   775  			if arch.IsRISCV64AMO(op) {
   776  				prog.From = a[0]
   777  				prog.To = a[1]
   778  				if a[2].Type != obj.TYPE_REG {
   779  					p.errorf("invalid addressing modes for third operand to %s instruction, must be register", op)
   780  					return
   781  				}
   782  				prog.RegTo2 = a[2].Reg
   783  				break
   784  			}
   785  			prog.From = a[0]
   786  			prog.Reg = p.getRegister(prog, op, &a[1])
   787  			prog.To = a[2]
   788  		case sys.S390X:
   789  			prog.From = a[0]
   790  			if a[1].Type == obj.TYPE_REG {
   791  				prog.Reg = p.getRegister(prog, op, &a[1])
   792  			} else {
   793  				prog.AddRestSource(a[1])
   794  			}
   795  			prog.To = a[2]
   796  		default:
   797  			p.errorf("TODO: implement three-operand instructions for this architecture")
   798  			return
   799  		}
   800  	case 4:
   801  		if p.arch.Family == sys.ARM {
   802  			if arch.IsARMBFX(op) {
   803  				// a[0] and a[1] must be constants, a[2] and a[3] must be registers
   804  				prog.From = a[0]
   805  				prog.AddRestSource(a[1])
   806  				prog.Reg = p.getRegister(prog, op, &a[2])
   807  				prog.To = a[3]
   808  				break
   809  			}
   810  			if arch.IsARMMULA(op) {
   811  				// All must be registers.
   812  				p.getRegister(prog, op, &a[0])
   813  				r1 := p.getRegister(prog, op, &a[1])
   814  				r2 := p.getRegister(prog, op, &a[2])
   815  				p.getRegister(prog, op, &a[3])
   816  				prog.From = a[0]
   817  				prog.To = a[3]
   818  				prog.To.Type = obj.TYPE_REGREG2
   819  				prog.To.Offset = int64(r2)
   820  				prog.Reg = r1
   821  				break
   822  			}
   823  		}
   824  		if p.arch.Family == sys.AMD64 {
   825  			prog.From = a[0]
   826  			prog.AddRestSourceArgs([]obj.Addr{a[1], a[2]})
   827  			prog.To = a[3]
   828  			break
   829  		}
   830  		if p.arch.Family == sys.ARM64 {
   831  			prog.From = a[0]
   832  			prog.Reg = p.getRegister(prog, op, &a[1])
   833  			prog.AddRestSource(a[2])
   834  			prog.To = a[3]
   835  			break
   836  		}
   837  		if p.arch.Family == sys.Loong64 {
   838  			prog.From = a[0]
   839  			prog.Reg = p.getRegister(prog, op, &a[1])
   840  			prog.AddRestSource(a[2])
   841  			prog.To = a[3]
   842  			break
   843  		}
   844  		if p.arch.Family == sys.PPC64 {
   845  			prog.From = a[0]
   846  			prog.To = a[3]
   847  			// If the second argument is not a register argument, it must be
   848  			// passed RestArgs/AddRestSource
   849  			if a[1].Type == obj.TYPE_REG {
   850  				prog.Reg = p.getRegister(prog, op, &a[1])
   851  				prog.AddRestSource(a[2])
   852  			} else {
   853  				// Don't set prog.Reg if a1 isn't a reg arg.
   854  				prog.AddRestSourceArgs([]obj.Addr{a[1], a[2]})
   855  			}
   856  			break
   857  		}
   858  		if p.arch.Family == sys.RISCV64 {
   859  			prog.From = a[0]
   860  			prog.Reg = p.getRegister(prog, op, &a[1])
   861  			prog.AddRestSource(a[2])
   862  			prog.To = a[3]
   863  			break
   864  		}
   865  		if p.arch.Family == sys.S390X {
   866  			if a[1].Type != obj.TYPE_REG {
   867  				p.errorf("second operand must be a register in %s instruction", op)
   868  				return
   869  			}
   870  			prog.From = a[0]
   871  			prog.Reg = p.getRegister(prog, op, &a[1])
   872  			prog.AddRestSource(a[2])
   873  			prog.To = a[3]
   874  			break
   875  		}
   876  		p.errorf("can't handle %s instruction with 4 operands", op)
   877  		return
   878  	case 5:
   879  		if p.arch.Family == sys.PPC64 {
   880  			prog.From = a[0]
   881  			// Second arg is always a register type on ppc64.
   882  			prog.Reg = p.getRegister(prog, op, &a[1])
   883  			prog.AddRestSourceArgs([]obj.Addr{a[2], a[3]})
   884  			prog.To = a[4]
   885  			break
   886  		}
   887  		if p.arch.Family == sys.AMD64 {
   888  			prog.From = a[0]
   889  			prog.AddRestSourceArgs([]obj.Addr{a[1], a[2], a[3]})
   890  			prog.To = a[4]
   891  			break
   892  		}
   893  		if p.arch.Family == sys.S390X {
   894  			prog.From = a[0]
   895  			prog.AddRestSourceArgs([]obj.Addr{a[1], a[2], a[3]})
   896  			prog.To = a[4]
   897  			break
   898  		}
   899  		p.errorf("can't handle %s instruction with 5 operands", op)
   900  		return
   901  	case 6:
   902  		if p.arch.Family == sys.ARM && arch.IsARMMRC(op) {
   903  			// Strange special case: MCR, MRC.
   904  			prog.To.Type = obj.TYPE_CONST
   905  			x0 := p.getConstant(prog, op, &a[0])
   906  			x1 := p.getConstant(prog, op, &a[1])
   907  			x2 := int64(p.getRegister(prog, op, &a[2]))
   908  			x3 := int64(p.getRegister(prog, op, &a[3]))
   909  			x4 := int64(p.getRegister(prog, op, &a[4]))
   910  			x5 := p.getConstant(prog, op, &a[5])
   911  			// Cond is handled specially for this instruction.
   912  			offset, MRC, ok := arch.ARMMRCOffset(op, cond, x0, x1, x2, x3, x4, x5)
   913  			if !ok {
   914  				p.errorf("unrecognized condition code .%q", cond)
   915  			}
   916  			prog.To.Offset = offset
   917  			cond = ""
   918  			prog.As = MRC // Both instructions are coded as MRC.
   919  			break
   920  		}
   921  		if p.arch.Family == sys.PPC64 {
   922  			prog.From = a[0]
   923  			// Second arg is always a register type on ppc64.
   924  			prog.Reg = p.getRegister(prog, op, &a[1])
   925  			prog.AddRestSourceArgs([]obj.Addr{a[2], a[3], a[4]})
   926  			prog.To = a[5]
   927  			break
   928  		}
   929  		if p.arch.Family == sys.RISCV64 && arch.IsRISCV64VTypeI(op) {
   930  			prog.From = a[0]
   931  			vsew := p.getSpecial(prog, op, &a[1])
   932  			vlmul := p.getSpecial(prog, op, &a[2])
   933  			vtail := p.getSpecial(prog, op, &a[3])
   934  			vmask := p.getSpecial(prog, op, &a[4])
   935  			if err := arch.RISCV64ValidateVectorType(vsew, vlmul, vtail, vmask); err != nil {
   936  				p.errorf("invalid vtype: %v", err)
   937  			}
   938  			prog.AddRestSourceArgs([]obj.Addr{a[1], a[2], a[3], a[4]})
   939  			prog.To = a[5]
   940  			break
   941  		}
   942  		fallthrough
   943  	default:
   944  		p.errorf("can't handle %s instruction with %d operands", op, len(a))
   945  		return
   946  	}
   947  
   948  	p.append(prog, cond, true)
   949  }
   950  
   951  // symbolName returns the symbol name, or an error string if none is available.
   952  func symbolName(addr *obj.Addr) string {
   953  	if addr.Sym != nil {
   954  		return addr.Sym.Name
   955  	}
   956  	return "<erroneous symbol>"
   957  }
   958  
   959  var emptyProg obj.Prog
   960  
   961  // getConstantPseudo checks that addr represents a plain constant and returns its value.
   962  func (p *Parser) getConstantPseudo(pseudo string, addr *obj.Addr) int64 {
   963  	if addr.Type != obj.TYPE_MEM || addr.Name != 0 || addr.Reg != 0 || addr.Index != 0 {
   964  		p.errorf("%s: expected integer constant; found %s", pseudo, obj.Dconv(&emptyProg, addr))
   965  	}
   966  	return addr.Offset
   967  }
   968  
   969  // getConstant checks that addr represents a plain constant and returns its value.
   970  func (p *Parser) getConstant(prog *obj.Prog, op obj.As, addr *obj.Addr) int64 {
   971  	if addr.Type != obj.TYPE_MEM || addr.Name != 0 || addr.Reg != 0 || addr.Index != 0 {
   972  		p.errorf("%s: expected integer constant; found %s", op, obj.Dconv(prog, addr))
   973  	}
   974  	return addr.Offset
   975  }
   976  
   977  // getImmediate checks that addr represents an immediate constant and returns its value.
   978  func (p *Parser) getImmediate(prog *obj.Prog, op obj.As, addr *obj.Addr) int64 {
   979  	if addr.Type != obj.TYPE_CONST || addr.Name != 0 || addr.Reg != 0 || addr.Index != 0 {
   980  		p.errorf("%s: expected immediate constant; found %s", op, obj.Dconv(prog, addr))
   981  	}
   982  	return addr.Offset
   983  }
   984  
   985  // getRegister checks that addr represents a register and returns its value.
   986  func (p *Parser) getRegister(prog *obj.Prog, op obj.As, addr *obj.Addr) int16 {
   987  	if addr.Type != obj.TYPE_REG || addr.Offset != 0 || addr.Name != 0 || addr.Index != 0 {
   988  		p.errorf("%s: expected register; found %s", op, obj.Dconv(prog, addr))
   989  	}
   990  	return addr.Reg
   991  }
   992  
   993  // getSpecial checks that addr represents a special operand and returns its value.
   994  func (p *Parser) getSpecial(prog *obj.Prog, op obj.As, addr *obj.Addr) int64 {
   995  	if addr.Type != obj.TYPE_SPECIAL || addr.Name != 0 || addr.Reg != 0 || addr.Index != 0 {
   996  		p.errorf("%s: expected special operand; found %s", op, obj.Dconv(prog, addr))
   997  	}
   998  	return addr.Offset
   999  }
  1000  

View as plain text