github.com/rsc/go@v0.0.0-20150416155037-e040fd465409/src/cmd/internal/gc/cgen.go (about)

     1  // Copyright 2009 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 gc
     6  
     7  import (
     8  	"cmd/internal/obj"
     9  	"fmt"
    10  )
    11  
    12  /*
    13   * generate:
    14   *	res = n;
    15   * simplifies and calls Thearch.Gmove.
    16   */
    17  func Cgen(n *Node, res *Node) {
    18  	if Debug['g'] != 0 {
    19  		Dump("\ncgen-n", n)
    20  		Dump("cgen-res", res)
    21  	}
    22  
    23  	if n == nil || n.Type == nil {
    24  		return
    25  	}
    26  
    27  	if res == nil || res.Type == nil {
    28  		Fatal("cgen: res nil")
    29  	}
    30  
    31  	for n.Op == OCONVNOP {
    32  		n = n.Left
    33  	}
    34  
    35  	switch n.Op {
    36  	case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
    37  		if res.Op != ONAME || !res.Addable {
    38  			var n1 Node
    39  			Tempname(&n1, n.Type)
    40  			Cgen_slice(n, &n1)
    41  			Cgen(&n1, res)
    42  		} else {
    43  			Cgen_slice(n, res)
    44  		}
    45  		return
    46  
    47  	case OEFACE:
    48  		if res.Op != ONAME || !res.Addable {
    49  			var n1 Node
    50  			Tempname(&n1, n.Type)
    51  			Cgen_eface(n, &n1)
    52  			Cgen(&n1, res)
    53  		} else {
    54  			Cgen_eface(n, res)
    55  		}
    56  		return
    57  
    58  	case ODOTTYPE:
    59  		cgen_dottype(n, res, nil)
    60  		return
    61  	}
    62  
    63  	if n.Ullman >= UINF {
    64  		if n.Op == OINDREG {
    65  			Fatal("cgen: this is going to miscompile")
    66  		}
    67  		if res.Ullman >= UINF {
    68  			var n1 Node
    69  			Tempname(&n1, n.Type)
    70  			Cgen(n, &n1)
    71  			Cgen(&n1, res)
    72  			return
    73  		}
    74  	}
    75  
    76  	if Isfat(n.Type) {
    77  		if n.Type.Width < 0 {
    78  			Fatal("forgot to compute width for %v", Tconv(n.Type, 0))
    79  		}
    80  		sgen(n, res, n.Type.Width)
    81  		return
    82  	}
    83  
    84  	if !res.Addable {
    85  		if n.Ullman > res.Ullman {
    86  			if Ctxt.Arch.Regsize == 4 && Is64(n.Type) {
    87  				var n1 Node
    88  				Tempname(&n1, n.Type)
    89  				Cgen(n, &n1)
    90  				Cgen(&n1, res)
    91  				return
    92  			}
    93  
    94  			var n1 Node
    95  			Regalloc(&n1, n.Type, res)
    96  			Cgen(n, &n1)
    97  			if n1.Ullman > res.Ullman {
    98  				Dump("n1", &n1)
    99  				Dump("res", res)
   100  				Fatal("loop in cgen")
   101  			}
   102  
   103  			Cgen(&n1, res)
   104  			Regfree(&n1)
   105  			return
   106  		}
   107  
   108  		var f int
   109  		if res.Ullman >= UINF {
   110  			goto gen
   111  		}
   112  
   113  		if Complexop(n, res) {
   114  			Complexgen(n, res)
   115  			return
   116  		}
   117  
   118  		f = 1 // gen thru register
   119  		switch n.Op {
   120  		case OLITERAL:
   121  			if Smallintconst(n) {
   122  				f = 0
   123  			}
   124  
   125  		case OREGISTER:
   126  			f = 0
   127  		}
   128  
   129  		if !Iscomplex[n.Type.Etype] && Ctxt.Arch.Regsize == 8 {
   130  			a := Thearch.Optoas(OAS, res.Type)
   131  			var addr obj.Addr
   132  			if Thearch.Sudoaddable(a, res, &addr) {
   133  				var p1 *obj.Prog
   134  				if f != 0 {
   135  					var n2 Node
   136  					Regalloc(&n2, res.Type, nil)
   137  					Cgen(n, &n2)
   138  					p1 = Thearch.Gins(a, &n2, nil)
   139  					Regfree(&n2)
   140  				} else {
   141  					p1 = Thearch.Gins(a, n, nil)
   142  				}
   143  				p1.To = addr
   144  				if Debug['g'] != 0 {
   145  					fmt.Printf("%v [ignore previous line]\n", p1)
   146  				}
   147  				Thearch.Sudoclean()
   148  				return
   149  			}
   150  		}
   151  
   152  	gen:
   153  		if Ctxt.Arch.Thechar == '8' {
   154  			// no registers to speak of
   155  			var n1, n2 Node
   156  			Tempname(&n1, n.Type)
   157  			Cgen(n, &n1)
   158  			Igen(res, &n2, nil)
   159  			Thearch.Gmove(&n1, &n2)
   160  			Regfree(&n2)
   161  			return
   162  		}
   163  
   164  		var n1 Node
   165  		Igen(res, &n1, nil)
   166  		Cgen(n, &n1)
   167  		Regfree(&n1)
   168  		return
   169  	}
   170  
   171  	// update addressability for string, slice
   172  	// can't do in walk because n->left->addable
   173  	// changes if n->left is an escaping local variable.
   174  	switch n.Op {
   175  	case OSPTR, OLEN:
   176  		if Isslice(n.Left.Type) || Istype(n.Left.Type, TSTRING) {
   177  			n.Addable = n.Left.Addable
   178  		}
   179  
   180  	case OCAP:
   181  		if Isslice(n.Left.Type) {
   182  			n.Addable = n.Left.Addable
   183  		}
   184  
   185  	case OITAB:
   186  		n.Addable = n.Left.Addable
   187  	}
   188  
   189  	if Ctxt.Arch.Thechar == '5' { // TODO(rsc): Maybe more often?
   190  		// if both are addressable, move
   191  		if n.Addable && res.Addable {
   192  			if Is64(n.Type) || Is64(res.Type) || n.Op == OREGISTER || res.Op == OREGISTER || Iscomplex[n.Type.Etype] || Iscomplex[res.Type.Etype] {
   193  				Thearch.Gmove(n, res)
   194  			} else {
   195  				var n1 Node
   196  				Regalloc(&n1, n.Type, nil)
   197  				Thearch.Gmove(n, &n1)
   198  				Cgen(&n1, res)
   199  				Regfree(&n1)
   200  			}
   201  
   202  			return
   203  		}
   204  
   205  		// if both are not addressable, use a temporary.
   206  		if !n.Addable && !res.Addable {
   207  			// could use regalloc here sometimes,
   208  			// but have to check for ullman >= UINF.
   209  			var n1 Node
   210  			Tempname(&n1, n.Type)
   211  			Cgen(n, &n1)
   212  			Cgen(&n1, res)
   213  			return
   214  		}
   215  
   216  		// if result is not addressable directly but n is,
   217  		// compute its address and then store via the address.
   218  		if !res.Addable {
   219  			var n1 Node
   220  			Igen(res, &n1, nil)
   221  			Cgen(n, &n1)
   222  			Regfree(&n1)
   223  			return
   224  		}
   225  	}
   226  
   227  	if Complexop(n, res) {
   228  		Complexgen(n, res)
   229  		return
   230  	}
   231  
   232  	if (Ctxt.Arch.Thechar == '6' || Ctxt.Arch.Thechar == '8') && n.Addable {
   233  		Thearch.Gmove(n, res)
   234  		return
   235  	}
   236  
   237  	if Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' {
   238  		// if both are addressable, move
   239  		if n.Addable {
   240  			if n.Op == OREGISTER || res.Op == OREGISTER {
   241  				Thearch.Gmove(n, res)
   242  			} else {
   243  				var n1 Node
   244  				Regalloc(&n1, n.Type, nil)
   245  				Thearch.Gmove(n, &n1)
   246  				Cgen(&n1, res)
   247  				Regfree(&n1)
   248  			}
   249  			return
   250  		}
   251  	}
   252  
   253  	// if n is sudoaddable generate addr and move
   254  	if Ctxt.Arch.Thechar == '5' && !Is64(n.Type) && !Is64(res.Type) && !Iscomplex[n.Type.Etype] && !Iscomplex[res.Type.Etype] {
   255  		a := Thearch.Optoas(OAS, n.Type)
   256  		var addr obj.Addr
   257  		if Thearch.Sudoaddable(a, n, &addr) {
   258  			if res.Op != OREGISTER {
   259  				var n2 Node
   260  				Regalloc(&n2, res.Type, nil)
   261  				p1 := Thearch.Gins(a, nil, &n2)
   262  				p1.From = addr
   263  				if Debug['g'] != 0 {
   264  					fmt.Printf("%v [ignore previous line]\n", p1)
   265  				}
   266  				Thearch.Gmove(&n2, res)
   267  				Regfree(&n2)
   268  			} else {
   269  				p1 := Thearch.Gins(a, nil, res)
   270  				p1.From = addr
   271  				if Debug['g'] != 0 {
   272  					fmt.Printf("%v [ignore previous line]\n", p1)
   273  				}
   274  			}
   275  			Thearch.Sudoclean()
   276  			return
   277  		}
   278  	}
   279  
   280  	nl := n.Left
   281  	nr := n.Right
   282  
   283  	if nl != nil && nl.Ullman >= UINF {
   284  		if nr != nil && nr.Ullman >= UINF {
   285  			var n1 Node
   286  			Tempname(&n1, nl.Type)
   287  			Cgen(nl, &n1)
   288  			n2 := *n
   289  			n2.Left = &n1
   290  			Cgen(&n2, res)
   291  			return
   292  		}
   293  	}
   294  
   295  	// 64-bit ops are hard on 32-bit machine.
   296  	if Ctxt.Arch.Regsize == 4 && (Is64(n.Type) || Is64(res.Type) || n.Left != nil && Is64(n.Left.Type)) {
   297  		switch n.Op {
   298  		// math goes to cgen64.
   299  		case OMINUS,
   300  			OCOM,
   301  			OADD,
   302  			OSUB,
   303  			OMUL,
   304  			OLROT,
   305  			OLSH,
   306  			ORSH,
   307  			OAND,
   308  			OOR,
   309  			OXOR:
   310  			Thearch.Cgen64(n, res)
   311  			return
   312  		}
   313  	}
   314  
   315  	if Thearch.Cgen_float != nil && nl != nil && Isfloat[n.Type.Etype] && Isfloat[nl.Type.Etype] {
   316  		Thearch.Cgen_float(n, res)
   317  		return
   318  	}
   319  
   320  	if !Iscomplex[n.Type.Etype] && Ctxt.Arch.Regsize == 8 {
   321  		a := Thearch.Optoas(OAS, n.Type)
   322  		var addr obj.Addr
   323  		if Thearch.Sudoaddable(a, n, &addr) {
   324  			if res.Op == OREGISTER {
   325  				p1 := Thearch.Gins(a, nil, res)
   326  				p1.From = addr
   327  			} else {
   328  				var n2 Node
   329  				Regalloc(&n2, n.Type, nil)
   330  				p1 := Thearch.Gins(a, nil, &n2)
   331  				p1.From = addr
   332  				Thearch.Gins(a, &n2, res)
   333  				Regfree(&n2)
   334  			}
   335  
   336  			Thearch.Sudoclean()
   337  			return
   338  		}
   339  	}
   340  
   341  	var a int
   342  	switch n.Op {
   343  	default:
   344  		Dump("cgen", n)
   345  		Dump("cgen-res", res)
   346  		Fatal("cgen: unknown op %v", Nconv(n, obj.FmtShort|obj.FmtSign))
   347  
   348  		// these call bgen to get a bool value
   349  	case OOROR,
   350  		OANDAND,
   351  		OEQ,
   352  		ONE,
   353  		OLT,
   354  		OLE,
   355  		OGE,
   356  		OGT,
   357  		ONOT:
   358  		p1 := Gbranch(obj.AJMP, nil, 0)
   359  
   360  		p2 := Pc
   361  		Thearch.Gmove(Nodbool(true), res)
   362  		p3 := Gbranch(obj.AJMP, nil, 0)
   363  		Patch(p1, Pc)
   364  		Bgen(n, true, 0, p2)
   365  		Thearch.Gmove(Nodbool(false), res)
   366  		Patch(p3, Pc)
   367  		return
   368  
   369  	case OPLUS:
   370  		Cgen(nl, res)
   371  		return
   372  
   373  		// unary
   374  	case OCOM:
   375  		a := Thearch.Optoas(OXOR, nl.Type)
   376  
   377  		var n1 Node
   378  		Regalloc(&n1, nl.Type, nil)
   379  		Cgen(nl, &n1)
   380  		var n2 Node
   381  		Nodconst(&n2, nl.Type, -1)
   382  		Thearch.Gins(a, &n2, &n1)
   383  		cgen_norm(n, &n1, res)
   384  		return
   385  
   386  	case OMINUS:
   387  		if Isfloat[nl.Type.Etype] {
   388  			nr = Nodintconst(-1)
   389  			Convlit(&nr, n.Type)
   390  			a = Thearch.Optoas(OMUL, nl.Type)
   391  			goto sbop
   392  		}
   393  
   394  		a := Thearch.Optoas(int(n.Op), nl.Type)
   395  		// unary
   396  		var n1 Node
   397  		Regalloc(&n1, nl.Type, res)
   398  
   399  		Cgen(nl, &n1)
   400  		if Ctxt.Arch.Thechar == '5' {
   401  			var n2 Node
   402  			Nodconst(&n2, nl.Type, 0)
   403  			Thearch.Gins(a, &n2, &n1)
   404  		} else if Ctxt.Arch.Thechar == '7' {
   405  			Thearch.Gins(a, &n1, &n1)
   406  		} else {
   407  			Thearch.Gins(a, nil, &n1)
   408  		}
   409  		cgen_norm(n, &n1, res)
   410  		return
   411  
   412  	case OSQRT:
   413  		var n1 Node
   414  		Regalloc(&n1, nl.Type, res)
   415  		Cgen(n.Left, &n1)
   416  		Thearch.Gins(Thearch.Optoas(OSQRT, nl.Type), &n1, &n1)
   417  		Thearch.Gmove(&n1, res)
   418  		Regfree(&n1)
   419  		return
   420  
   421  	case OGETG:
   422  		Thearch.Getg(res)
   423  		return
   424  
   425  		// symmetric binary
   426  	case OAND,
   427  		OOR,
   428  		OXOR,
   429  		OADD,
   430  		OMUL:
   431  		if n.Op == OMUL && Thearch.Cgen_bmul != nil && Thearch.Cgen_bmul(int(n.Op), nl, nr, res) {
   432  			break
   433  		}
   434  		a = Thearch.Optoas(int(n.Op), nl.Type)
   435  		goto sbop
   436  
   437  		// asymmetric binary
   438  	case OSUB:
   439  		a = Thearch.Optoas(int(n.Op), nl.Type)
   440  		goto abop
   441  
   442  	case OHMUL:
   443  		Thearch.Cgen_hmul(nl, nr, res)
   444  
   445  	case OCONV:
   446  		if Eqtype(n.Type, nl.Type) || Noconv(n.Type, nl.Type) {
   447  			Cgen(nl, res)
   448  			return
   449  		}
   450  
   451  		if Ctxt.Arch.Thechar == '8' {
   452  			var n1 Node
   453  			var n2 Node
   454  			Tempname(&n2, n.Type)
   455  			Mgen(nl, &n1, res)
   456  			Thearch.Gmove(&n1, &n2)
   457  			Thearch.Gmove(&n2, res)
   458  			Mfree(&n1)
   459  			break
   460  		}
   461  
   462  		var n1 Node
   463  		var n2 Node
   464  		if Ctxt.Arch.Thechar == '5' {
   465  			if nl.Addable && !Is64(nl.Type) {
   466  				Regalloc(&n1, nl.Type, res)
   467  				Thearch.Gmove(nl, &n1)
   468  			} else {
   469  				if n.Type.Width > int64(Widthptr) || Is64(nl.Type) || Isfloat[nl.Type.Etype] {
   470  					Tempname(&n1, nl.Type)
   471  				} else {
   472  					Regalloc(&n1, nl.Type, res)
   473  				}
   474  				Cgen(nl, &n1)
   475  			}
   476  			if n.Type.Width > int64(Widthptr) || Is64(n.Type) || Isfloat[n.Type.Etype] {
   477  				Tempname(&n2, n.Type)
   478  			} else {
   479  				Regalloc(&n2, n.Type, nil)
   480  			}
   481  		} else {
   482  			if n.Type.Width > nl.Type.Width {
   483  				// If loading from memory, do conversion during load,
   484  				// so as to avoid use of 8-bit register in, say, int(*byteptr).
   485  				switch nl.Op {
   486  				case ODOT, ODOTPTR, OINDEX, OIND, ONAME:
   487  					Igen(nl, &n1, res)
   488  					Regalloc(&n2, n.Type, res)
   489  					Thearch.Gmove(&n1, &n2)
   490  					Thearch.Gmove(&n2, res)
   491  					Regfree(&n2)
   492  					Regfree(&n1)
   493  					return
   494  				}
   495  			}
   496  			Regalloc(&n1, nl.Type, res)
   497  			Regalloc(&n2, n.Type, &n1)
   498  			Cgen(nl, &n1)
   499  		}
   500  
   501  		// if we do the conversion n1 -> n2 here
   502  		// reusing the register, then gmove won't
   503  		// have to allocate its own register.
   504  		Thearch.Gmove(&n1, &n2)
   505  		Thearch.Gmove(&n2, res)
   506  		if n2.Op == OREGISTER {
   507  			Regfree(&n2)
   508  		}
   509  		if n1.Op == OREGISTER {
   510  			Regfree(&n1)
   511  		}
   512  
   513  	case ODOT,
   514  		ODOTPTR,
   515  		OINDEX,
   516  		OIND,
   517  		ONAME: // PHEAP or PPARAMREF var
   518  		var n1 Node
   519  		Igen(n, &n1, res)
   520  
   521  		Thearch.Gmove(&n1, res)
   522  		Regfree(&n1)
   523  
   524  		// interface table is first word of interface value
   525  	case OITAB:
   526  		var n1 Node
   527  		Igen(nl, &n1, res)
   528  
   529  		n1.Type = n.Type
   530  		Thearch.Gmove(&n1, res)
   531  		Regfree(&n1)
   532  
   533  	case OSPTR:
   534  		// pointer is the first word of string or slice.
   535  		if Isconst(nl, CTSTR) {
   536  			var n1 Node
   537  			Regalloc(&n1, Types[Tptr], res)
   538  			p1 := Thearch.Gins(Thearch.Optoas(OAS, n1.Type), nil, &n1)
   539  			Datastring(nl.Val.U.Sval, &p1.From)
   540  			p1.From.Type = obj.TYPE_ADDR
   541  			Thearch.Gmove(&n1, res)
   542  			Regfree(&n1)
   543  			break
   544  		}
   545  
   546  		var n1 Node
   547  		Igen(nl, &n1, res)
   548  		n1.Type = n.Type
   549  		Thearch.Gmove(&n1, res)
   550  		Regfree(&n1)
   551  
   552  	case OLEN:
   553  		if Istype(nl.Type, TMAP) || Istype(nl.Type, TCHAN) {
   554  			// map and chan have len in the first int-sized word.
   555  			// a zero pointer means zero length
   556  			var n1 Node
   557  			Regalloc(&n1, Types[Tptr], res)
   558  
   559  			Cgen(nl, &n1)
   560  
   561  			var n2 Node
   562  			Nodconst(&n2, Types[Tptr], 0)
   563  			Thearch.Gins(Thearch.Optoas(OCMP, Types[Tptr]), &n1, &n2)
   564  			p1 := Gbranch(Thearch.Optoas(OEQ, Types[Tptr]), nil, 0)
   565  
   566  			n2 = n1
   567  			n2.Op = OINDREG
   568  			n2.Type = Types[Simtype[TINT]]
   569  			Thearch.Gmove(&n2, &n1)
   570  
   571  			Patch(p1, Pc)
   572  
   573  			Thearch.Gmove(&n1, res)
   574  			Regfree(&n1)
   575  			break
   576  		}
   577  
   578  		if Istype(nl.Type, TSTRING) || Isslice(nl.Type) {
   579  			// both slice and string have len one pointer into the struct.
   580  			// a zero pointer means zero length
   581  			var n1 Node
   582  			Igen(nl, &n1, res)
   583  
   584  			n1.Type = Types[Simtype[TUINT]]
   585  			n1.Xoffset += int64(Array_nel)
   586  			Thearch.Gmove(&n1, res)
   587  			Regfree(&n1)
   588  			break
   589  		}
   590  
   591  		Fatal("cgen: OLEN: unknown type %v", Tconv(nl.Type, obj.FmtLong))
   592  
   593  	case OCAP:
   594  		if Istype(nl.Type, TCHAN) {
   595  			// chan has cap in the second int-sized word.
   596  			// a zero pointer means zero length
   597  			var n1 Node
   598  			Regalloc(&n1, Types[Tptr], res)
   599  
   600  			Cgen(nl, &n1)
   601  
   602  			var n2 Node
   603  			Nodconst(&n2, Types[Tptr], 0)
   604  			Thearch.Gins(Thearch.Optoas(OCMP, Types[Tptr]), &n1, &n2)
   605  			p1 := Gbranch(Thearch.Optoas(OEQ, Types[Tptr]), nil, 0)
   606  
   607  			n2 = n1
   608  			n2.Op = OINDREG
   609  			n2.Xoffset = int64(Widthint)
   610  			n2.Type = Types[Simtype[TINT]]
   611  			Thearch.Gmove(&n2, &n1)
   612  
   613  			Patch(p1, Pc)
   614  
   615  			Thearch.Gmove(&n1, res)
   616  			Regfree(&n1)
   617  			break
   618  		}
   619  
   620  		if Isslice(nl.Type) {
   621  			var n1 Node
   622  			Igen(nl, &n1, res)
   623  			n1.Type = Types[Simtype[TUINT]]
   624  			n1.Xoffset += int64(Array_cap)
   625  			Thearch.Gmove(&n1, res)
   626  			Regfree(&n1)
   627  			break
   628  		}
   629  
   630  		Fatal("cgen: OCAP: unknown type %v", Tconv(nl.Type, obj.FmtLong))
   631  
   632  	case OADDR:
   633  		if n.Bounded { // let race detector avoid nil checks
   634  			Disable_checknil++
   635  		}
   636  		Agen(nl, res)
   637  		if n.Bounded {
   638  			Disable_checknil--
   639  		}
   640  
   641  	case OCALLMETH:
   642  		cgen_callmeth(n, 0)
   643  		cgen_callret(n, res)
   644  
   645  	case OCALLINTER:
   646  		cgen_callinter(n, res, 0)
   647  		cgen_callret(n, res)
   648  
   649  	case OCALLFUNC:
   650  		cgen_call(n, 0)
   651  		cgen_callret(n, res)
   652  
   653  	case OMOD, ODIV:
   654  		if Isfloat[n.Type.Etype] || Thearch.Dodiv == nil {
   655  			a = Thearch.Optoas(int(n.Op), nl.Type)
   656  			goto abop
   657  		}
   658  
   659  		if nl.Ullman >= nr.Ullman {
   660  			var n1 Node
   661  			Regalloc(&n1, nl.Type, res)
   662  			Cgen(nl, &n1)
   663  			cgen_div(int(n.Op), &n1, nr, res)
   664  			Regfree(&n1)
   665  		} else {
   666  			var n2 Node
   667  			if !Smallintconst(nr) {
   668  				Regalloc(&n2, nr.Type, res)
   669  				Cgen(nr, &n2)
   670  			} else {
   671  				n2 = *nr
   672  			}
   673  
   674  			cgen_div(int(n.Op), nl, &n2, res)
   675  			if n2.Op != OLITERAL {
   676  				Regfree(&n2)
   677  			}
   678  		}
   679  
   680  	case OLSH, ORSH, OLROT:
   681  		Thearch.Cgen_shift(int(n.Op), n.Bounded, nl, nr, res)
   682  	}
   683  
   684  	return
   685  
   686  	/*
   687  	 * put simplest on right - we'll generate into left
   688  	 * and then adjust it using the computation of right.
   689  	 * constants and variables have the same ullman
   690  	 * count, so look for constants specially.
   691  	 *
   692  	 * an integer constant we can use as an immediate
   693  	 * is simpler than a variable - we can use the immediate
   694  	 * in the adjustment instruction directly - so it goes
   695  	 * on the right.
   696  	 *
   697  	 * other constants, like big integers or floating point
   698  	 * constants, require a mov into a register, so those
   699  	 * might as well go on the left, so we can reuse that
   700  	 * register for the computation.
   701  	 */
   702  sbop: // symmetric binary
   703  	if nl.Ullman < nr.Ullman || (nl.Ullman == nr.Ullman && (Smallintconst(nl) || (nr.Op == OLITERAL && !Smallintconst(nr)))) {
   704  		r := nl
   705  		nl = nr
   706  		nr = r
   707  	}
   708  
   709  abop: // asymmetric binary
   710  	var n1 Node
   711  	var n2 Node
   712  	if Ctxt.Arch.Thechar == '8' {
   713  		// no registers, sigh
   714  		if Smallintconst(nr) {
   715  			var n1 Node
   716  			Mgen(nl, &n1, res)
   717  			var n2 Node
   718  			Regalloc(&n2, nl.Type, &n1)
   719  			Thearch.Gmove(&n1, &n2)
   720  			Thearch.Gins(a, nr, &n2)
   721  			Thearch.Gmove(&n2, res)
   722  			Regfree(&n2)
   723  			Mfree(&n1)
   724  		} else if nl.Ullman >= nr.Ullman {
   725  			var nt Node
   726  			Tempname(&nt, nl.Type)
   727  			Cgen(nl, &nt)
   728  			var n2 Node
   729  			Mgen(nr, &n2, nil)
   730  			var n1 Node
   731  			Regalloc(&n1, nl.Type, res)
   732  			Thearch.Gmove(&nt, &n1)
   733  			Thearch.Gins(a, &n2, &n1)
   734  			Thearch.Gmove(&n1, res)
   735  			Regfree(&n1)
   736  			Mfree(&n2)
   737  		} else {
   738  			var n2 Node
   739  			Regalloc(&n2, nr.Type, res)
   740  			Cgen(nr, &n2)
   741  			var n1 Node
   742  			Regalloc(&n1, nl.Type, nil)
   743  			Cgen(nl, &n1)
   744  			Thearch.Gins(a, &n2, &n1)
   745  			Regfree(&n2)
   746  			Thearch.Gmove(&n1, res)
   747  			Regfree(&n1)
   748  		}
   749  		return
   750  	}
   751  
   752  	if nl.Ullman >= nr.Ullman {
   753  		Regalloc(&n1, nl.Type, res)
   754  		Cgen(nl, &n1)
   755  
   756  		if Smallintconst(nr) && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' { // TODO(rsc): Check opcode for arm
   757  			n2 = *nr
   758  		} else {
   759  			Regalloc(&n2, nr.Type, nil)
   760  			Cgen(nr, &n2)
   761  		}
   762  	} else {
   763  		if Smallintconst(nr) && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' { // TODO(rsc): Check opcode for arm
   764  			n2 = *nr
   765  		} else {
   766  			Regalloc(&n2, nr.Type, res)
   767  			Cgen(nr, &n2)
   768  		}
   769  
   770  		Regalloc(&n1, nl.Type, nil)
   771  		Cgen(nl, &n1)
   772  	}
   773  
   774  	Thearch.Gins(a, &n2, &n1)
   775  	if n2.Op != OLITERAL {
   776  		Regfree(&n2)
   777  	}
   778  	cgen_norm(n, &n1, res)
   779  }
   780  
   781  // cgen_norm moves n1 to res, truncating to expected type if necessary.
   782  // n1 is a register, and cgen_norm frees it.
   783  func cgen_norm(n, n1, res *Node) {
   784  	switch Ctxt.Arch.Thechar {
   785  	case '6', '8':
   786  		// We use sized math, so the result is already truncated.
   787  	default:
   788  		switch n.Op {
   789  		case OADD, OSUB, OMUL, ODIV, OCOM, OMINUS:
   790  			// TODO(rsc): What about left shift?
   791  			Thearch.Gins(Thearch.Optoas(OAS, n.Type), n1, n1)
   792  		}
   793  	}
   794  
   795  	Thearch.Gmove(n1, res)
   796  	Regfree(n1)
   797  }
   798  
   799  func Mgen(n *Node, n1 *Node, rg *Node) {
   800  	n1.Op = OEMPTY
   801  
   802  	if n.Addable {
   803  		*n1 = *n
   804  		if n1.Op == OREGISTER || n1.Op == OINDREG {
   805  			reg[n.Reg-int16(Thearch.REGMIN)]++
   806  		}
   807  		return
   808  	}
   809  
   810  	Tempname(n1, n.Type)
   811  	Cgen(n, n1)
   812  	if n.Type.Width <= int64(Widthptr) || Isfloat[n.Type.Etype] {
   813  		n2 := *n1
   814  		Regalloc(n1, n.Type, rg)
   815  		Thearch.Gmove(&n2, n1)
   816  	}
   817  }
   818  
   819  func Mfree(n *Node) {
   820  	if n.Op == OREGISTER {
   821  		Regfree(n)
   822  	}
   823  }
   824  
   825  /*
   826   * allocate a register (reusing res if possible) and generate
   827   *  a = n
   828   * The caller must call Regfree(a).
   829   */
   830  func Cgenr(n *Node, a *Node, res *Node) {
   831  	if Debug['g'] != 0 {
   832  		Dump("cgenr-n", n)
   833  	}
   834  
   835  	if Isfat(n.Type) {
   836  		Fatal("cgenr on fat node")
   837  	}
   838  
   839  	if n.Addable {
   840  		Regalloc(a, n.Type, res)
   841  		Thearch.Gmove(n, a)
   842  		return
   843  	}
   844  
   845  	switch n.Op {
   846  	case ONAME,
   847  		ODOT,
   848  		ODOTPTR,
   849  		OINDEX,
   850  		OCALLFUNC,
   851  		OCALLMETH,
   852  		OCALLINTER:
   853  		var n1 Node
   854  		Igen(n, &n1, res)
   855  		Regalloc(a, Types[Tptr], &n1)
   856  		Thearch.Gmove(&n1, a)
   857  		Regfree(&n1)
   858  
   859  	default:
   860  		Regalloc(a, n.Type, res)
   861  		Cgen(n, a)
   862  	}
   863  }
   864  
   865  /*
   866   * allocate a register (reusing res if possible) and generate
   867   * a = &n
   868   * The caller must call Regfree(a).
   869   * The generated code checks that the result is not nil.
   870   */
   871  func Agenr(n *Node, a *Node, res *Node) {
   872  	if Debug['g'] != 0 {
   873  		Dump("\nagenr-n", n)
   874  	}
   875  
   876  	nl := n.Left
   877  	nr := n.Right
   878  
   879  	switch n.Op {
   880  	case ODOT, ODOTPTR, OCALLFUNC, OCALLMETH, OCALLINTER:
   881  		var n1 Node
   882  		Igen(n, &n1, res)
   883  		Regalloc(a, Types[Tptr], &n1)
   884  		Agen(&n1, a)
   885  		Regfree(&n1)
   886  
   887  	case OIND:
   888  		Cgenr(n.Left, a, res)
   889  		Cgen_checknil(a)
   890  
   891  	case OINDEX:
   892  		if Ctxt.Arch.Thechar == '5' {
   893  			var p2 *obj.Prog // to be patched to panicindex.
   894  			w := uint32(n.Type.Width)
   895  			bounded := Debug['B'] != 0 || n.Bounded
   896  			var n1 Node
   897  			var n3 Node
   898  			if nr.Addable {
   899  				var tmp Node
   900  				if !Isconst(nr, CTINT) {
   901  					Tempname(&tmp, Types[TINT32])
   902  				}
   903  				if !Isconst(nl, CTSTR) {
   904  					Agenr(nl, &n3, res)
   905  				}
   906  				if !Isconst(nr, CTINT) {
   907  					p2 = Thearch.Cgenindex(nr, &tmp, bounded)
   908  					Regalloc(&n1, tmp.Type, nil)
   909  					Thearch.Gmove(&tmp, &n1)
   910  				}
   911  			} else if nl.Addable {
   912  				if !Isconst(nr, CTINT) {
   913  					var tmp Node
   914  					Tempname(&tmp, Types[TINT32])
   915  					p2 = Thearch.Cgenindex(nr, &tmp, bounded)
   916  					Regalloc(&n1, tmp.Type, nil)
   917  					Thearch.Gmove(&tmp, &n1)
   918  				}
   919  
   920  				if !Isconst(nl, CTSTR) {
   921  					Agenr(nl, &n3, res)
   922  				}
   923  			} else {
   924  				var tmp Node
   925  				Tempname(&tmp, Types[TINT32])
   926  				p2 = Thearch.Cgenindex(nr, &tmp, bounded)
   927  				nr = &tmp
   928  				if !Isconst(nl, CTSTR) {
   929  					Agenr(nl, &n3, res)
   930  				}
   931  				Regalloc(&n1, tmp.Type, nil)
   932  				Thearch.Gins(Thearch.Optoas(OAS, tmp.Type), &tmp, &n1)
   933  			}
   934  
   935  			// &a is in &n3 (allocated in res)
   936  			// i is in &n1 (if not constant)
   937  			// w is width
   938  
   939  			// constant index
   940  			if Isconst(nr, CTINT) {
   941  				if Isconst(nl, CTSTR) {
   942  					Fatal("constant string constant index")
   943  				}
   944  				v := uint64(Mpgetfix(nr.Val.U.Xval))
   945  				var n2 Node
   946  				if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
   947  					if Debug['B'] == 0 && !n.Bounded {
   948  						n1 = n3
   949  						n1.Op = OINDREG
   950  						n1.Type = Types[Tptr]
   951  						n1.Xoffset = int64(Array_nel)
   952  						var n4 Node
   953  						Regalloc(&n4, n1.Type, nil)
   954  						Thearch.Gmove(&n1, &n4)
   955  						Nodconst(&n2, Types[TUINT32], int64(v))
   956  						Thearch.Gins(Thearch.Optoas(OCMP, Types[TUINT32]), &n4, &n2)
   957  						Regfree(&n4)
   958  						p1 := Gbranch(Thearch.Optoas(OGT, Types[TUINT32]), nil, +1)
   959  						Ginscall(Panicindex, 0)
   960  						Patch(p1, Pc)
   961  					}
   962  
   963  					n1 = n3
   964  					n1.Op = OINDREG
   965  					n1.Type = Types[Tptr]
   966  					n1.Xoffset = int64(Array_array)
   967  					Thearch.Gmove(&n1, &n3)
   968  				}
   969  
   970  				Nodconst(&n2, Types[Tptr], int64(v*uint64(w)))
   971  				Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
   972  				*a = n3
   973  				break
   974  			}
   975  
   976  			var n2 Node
   977  			Regalloc(&n2, Types[TINT32], &n1) // i
   978  			Thearch.Gmove(&n1, &n2)
   979  			Regfree(&n1)
   980  
   981  			var n4 Node
   982  			if Debug['B'] == 0 && !n.Bounded {
   983  				// check bounds
   984  				if Isconst(nl, CTSTR) {
   985  					Nodconst(&n4, Types[TUINT32], int64(len(nl.Val.U.Sval)))
   986  				} else if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
   987  					n1 = n3
   988  					n1.Op = OINDREG
   989  					n1.Type = Types[Tptr]
   990  					n1.Xoffset = int64(Array_nel)
   991  					Regalloc(&n4, Types[TUINT32], nil)
   992  					Thearch.Gmove(&n1, &n4)
   993  				} else {
   994  					Nodconst(&n4, Types[TUINT32], nl.Type.Bound)
   995  				}
   996  
   997  				Thearch.Gins(Thearch.Optoas(OCMP, Types[TUINT32]), &n2, &n4)
   998  				if n4.Op == OREGISTER {
   999  					Regfree(&n4)
  1000  				}
  1001  				p1 := Gbranch(Thearch.Optoas(OLT, Types[TUINT32]), nil, +1)
  1002  				if p2 != nil {
  1003  					Patch(p2, Pc)
  1004  				}
  1005  				Ginscall(Panicindex, 0)
  1006  				Patch(p1, Pc)
  1007  			}
  1008  
  1009  			if Isconst(nl, CTSTR) {
  1010  				Regalloc(&n3, Types[Tptr], res)
  1011  				p1 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &n3)
  1012  				Datastring(nl.Val.U.Sval, &p1.From)
  1013  				p1.From.Type = obj.TYPE_ADDR
  1014  			} else if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
  1015  				n1 = n3
  1016  				n1.Op = OINDREG
  1017  				n1.Type = Types[Tptr]
  1018  				n1.Xoffset = int64(Array_array)
  1019  				Thearch.Gmove(&n1, &n3)
  1020  			}
  1021  
  1022  			if w == 0 {
  1023  				// nothing to do
  1024  			} else if Thearch.AddIndex != nil && Thearch.AddIndex(&n2, int64(w), &n3) {
  1025  				// done by back end
  1026  			} else if w == 1 {
  1027  				Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
  1028  			} else {
  1029  				Regalloc(&n4, Types[TUINT32], nil)
  1030  				Nodconst(&n1, Types[TUINT32], int64(w))
  1031  				Thearch.Gmove(&n1, &n4)
  1032  				Thearch.Gins(Thearch.Optoas(OMUL, Types[TUINT32]), &n4, &n2)
  1033  				Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
  1034  				Regfree(&n4)
  1035  			}
  1036  			*a = n3
  1037  			Regfree(&n2)
  1038  			break
  1039  		}
  1040  		if Ctxt.Arch.Thechar == '8' {
  1041  			var p2 *obj.Prog // to be patched to panicindex.
  1042  			w := uint32(n.Type.Width)
  1043  			bounded := Debug['B'] != 0 || n.Bounded
  1044  			var n3 Node
  1045  			var tmp Node
  1046  			var n1 Node
  1047  			if nr.Addable {
  1048  				// Generate &nl first, and move nr into register.
  1049  				if !Isconst(nl, CTSTR) {
  1050  					Igen(nl, &n3, res)
  1051  				}
  1052  				if !Isconst(nr, CTINT) {
  1053  					p2 = Thearch.Igenindex(nr, &tmp, bounded)
  1054  					Regalloc(&n1, tmp.Type, nil)
  1055  					Thearch.Gmove(&tmp, &n1)
  1056  				}
  1057  			} else if nl.Addable {
  1058  				// Generate nr first, and move &nl into register.
  1059  				if !Isconst(nr, CTINT) {
  1060  					p2 = Thearch.Igenindex(nr, &tmp, bounded)
  1061  					Regalloc(&n1, tmp.Type, nil)
  1062  					Thearch.Gmove(&tmp, &n1)
  1063  				}
  1064  
  1065  				if !Isconst(nl, CTSTR) {
  1066  					Igen(nl, &n3, res)
  1067  				}
  1068  			} else {
  1069  				p2 = Thearch.Igenindex(nr, &tmp, bounded)
  1070  				nr = &tmp
  1071  				if !Isconst(nl, CTSTR) {
  1072  					Igen(nl, &n3, res)
  1073  				}
  1074  				Regalloc(&n1, tmp.Type, nil)
  1075  				Thearch.Gins(Thearch.Optoas(OAS, tmp.Type), &tmp, &n1)
  1076  			}
  1077  
  1078  			// For fixed array we really want the pointer in n3.
  1079  			var n2 Node
  1080  			if Isfixedarray(nl.Type) {
  1081  				Regalloc(&n2, Types[Tptr], &n3)
  1082  				Agen(&n3, &n2)
  1083  				Regfree(&n3)
  1084  				n3 = n2
  1085  			}
  1086  
  1087  			// &a[0] is in n3 (allocated in res)
  1088  			// i is in n1 (if not constant)
  1089  			// len(a) is in nlen (if needed)
  1090  			// w is width
  1091  
  1092  			// constant index
  1093  			if Isconst(nr, CTINT) {
  1094  				if Isconst(nl, CTSTR) {
  1095  					Fatal("constant string constant index") // front end should handle
  1096  				}
  1097  				v := uint64(Mpgetfix(nr.Val.U.Xval))
  1098  				if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
  1099  					if Debug['B'] == 0 && !n.Bounded {
  1100  						nlen := n3
  1101  						nlen.Type = Types[TUINT32]
  1102  						nlen.Xoffset += int64(Array_nel)
  1103  						Nodconst(&n2, Types[TUINT32], int64(v))
  1104  						Thearch.Gins(Thearch.Optoas(OCMP, Types[TUINT32]), &nlen, &n2)
  1105  						p1 := Gbranch(Thearch.Optoas(OGT, Types[TUINT32]), nil, +1)
  1106  						Ginscall(Panicindex, -1)
  1107  						Patch(p1, Pc)
  1108  					}
  1109  				}
  1110  
  1111  				// Load base pointer in n2 = n3.
  1112  				Regalloc(&n2, Types[Tptr], &n3)
  1113  
  1114  				n3.Type = Types[Tptr]
  1115  				n3.Xoffset += int64(Array_array)
  1116  				Thearch.Gmove(&n3, &n2)
  1117  				Regfree(&n3)
  1118  				if v*uint64(w) != 0 {
  1119  					Nodconst(&n1, Types[Tptr], int64(v*uint64(w)))
  1120  					Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n1, &n2)
  1121  				}
  1122  				*a = n2
  1123  				break
  1124  			}
  1125  
  1126  			// i is in register n1, extend to 32 bits.
  1127  			t := Types[TUINT32]
  1128  
  1129  			if Issigned[n1.Type.Etype] {
  1130  				t = Types[TINT32]
  1131  			}
  1132  
  1133  			Regalloc(&n2, t, &n1) // i
  1134  			Thearch.Gmove(&n1, &n2)
  1135  			Regfree(&n1)
  1136  
  1137  			if Debug['B'] == 0 && !n.Bounded {
  1138  				// check bounds
  1139  				t := Types[TUINT32]
  1140  
  1141  				var nlen Node
  1142  				if Isconst(nl, CTSTR) {
  1143  					Nodconst(&nlen, t, int64(len(nl.Val.U.Sval)))
  1144  				} else if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
  1145  					nlen = n3
  1146  					nlen.Type = t
  1147  					nlen.Xoffset += int64(Array_nel)
  1148  				} else {
  1149  					Nodconst(&nlen, t, nl.Type.Bound)
  1150  				}
  1151  
  1152  				Thearch.Gins(Thearch.Optoas(OCMP, t), &n2, &nlen)
  1153  				p1 := Gbranch(Thearch.Optoas(OLT, t), nil, +1)
  1154  				if p2 != nil {
  1155  					Patch(p2, Pc)
  1156  				}
  1157  				Ginscall(Panicindex, -1)
  1158  				Patch(p1, Pc)
  1159  			}
  1160  
  1161  			if Isconst(nl, CTSTR) {
  1162  				Regalloc(&n3, Types[Tptr], res)
  1163  				p1 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &n3)
  1164  				Datastring(nl.Val.U.Sval, &p1.From)
  1165  				p1.From.Type = obj.TYPE_ADDR
  1166  				Thearch.Gins(Thearch.Optoas(OADD, n3.Type), &n2, &n3)
  1167  				goto indexdone1
  1168  			}
  1169  
  1170  			// Load base pointer in n3.
  1171  			Regalloc(&tmp, Types[Tptr], &n3)
  1172  
  1173  			if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
  1174  				n3.Type = Types[Tptr]
  1175  				n3.Xoffset += int64(Array_array)
  1176  				Thearch.Gmove(&n3, &tmp)
  1177  			}
  1178  
  1179  			Regfree(&n3)
  1180  			n3 = tmp
  1181  
  1182  			if w == 0 {
  1183  				// nothing to do
  1184  			} else if Thearch.AddIndex != nil && Thearch.AddIndex(&n2, int64(w), &n3) {
  1185  				// done by back end
  1186  			} else if w == 1 {
  1187  				Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
  1188  			} else {
  1189  				Nodconst(&tmp, Types[TUINT32], int64(w))
  1190  				Thearch.Gins(Thearch.Optoas(OMUL, Types[TUINT32]), &tmp, &n2)
  1191  				Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
  1192  			}
  1193  
  1194  		indexdone1:
  1195  			*a = n3
  1196  			Regfree(&n2)
  1197  			break
  1198  		}
  1199  
  1200  		freelen := 0
  1201  		w := uint64(n.Type.Width)
  1202  
  1203  		// Generate the non-addressable child first.
  1204  		var n3 Node
  1205  		var nlen Node
  1206  		var tmp Node
  1207  		var n1 Node
  1208  		if nr.Addable {
  1209  			goto irad
  1210  		}
  1211  		if nl.Addable {
  1212  			Cgenr(nr, &n1, nil)
  1213  			if !Isconst(nl, CTSTR) {
  1214  				if Isfixedarray(nl.Type) {
  1215  					Agenr(nl, &n3, res)
  1216  				} else {
  1217  					Igen(nl, &nlen, res)
  1218  					freelen = 1
  1219  					nlen.Type = Types[Tptr]
  1220  					nlen.Xoffset += int64(Array_array)
  1221  					Regalloc(&n3, Types[Tptr], res)
  1222  					Thearch.Gmove(&nlen, &n3)
  1223  					nlen.Type = Types[Simtype[TUINT]]
  1224  					nlen.Xoffset += int64(Array_nel) - int64(Array_array)
  1225  				}
  1226  			}
  1227  
  1228  			goto index
  1229  		}
  1230  
  1231  		Tempname(&tmp, nr.Type)
  1232  		Cgen(nr, &tmp)
  1233  		nr = &tmp
  1234  
  1235  	irad:
  1236  		if !Isconst(nl, CTSTR) {
  1237  			if Isfixedarray(nl.Type) {
  1238  				Agenr(nl, &n3, res)
  1239  			} else {
  1240  				if !nl.Addable {
  1241  					if res != nil && res.Op == OREGISTER { // give up res, which we don't need yet.
  1242  						Regfree(res)
  1243  					}
  1244  
  1245  					// igen will need an addressable node.
  1246  					var tmp2 Node
  1247  					Tempname(&tmp2, nl.Type)
  1248  					Cgen(nl, &tmp2)
  1249  					nl = &tmp2
  1250  
  1251  					if res != nil && res.Op == OREGISTER { // reacquire res
  1252  						Regrealloc(res)
  1253  					}
  1254  				}
  1255  
  1256  				Igen(nl, &nlen, res)
  1257  				freelen = 1
  1258  				nlen.Type = Types[Tptr]
  1259  				nlen.Xoffset += int64(Array_array)
  1260  				Regalloc(&n3, Types[Tptr], res)
  1261  				Thearch.Gmove(&nlen, &n3)
  1262  				nlen.Type = Types[Simtype[TUINT]]
  1263  				nlen.Xoffset += int64(Array_nel) - int64(Array_array)
  1264  			}
  1265  		}
  1266  
  1267  		if !Isconst(nr, CTINT) {
  1268  			Cgenr(nr, &n1, nil)
  1269  		}
  1270  
  1271  		goto index
  1272  
  1273  		// &a is in &n3 (allocated in res)
  1274  		// i is in &n1 (if not constant)
  1275  		// len(a) is in nlen (if needed)
  1276  		// w is width
  1277  
  1278  		// constant index
  1279  	index:
  1280  		if Isconst(nr, CTINT) {
  1281  			if Isconst(nl, CTSTR) {
  1282  				Fatal("constant string constant index") // front end should handle
  1283  			}
  1284  			v := uint64(Mpgetfix(nr.Val.U.Xval))
  1285  			if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
  1286  				if Debug['B'] == 0 && !n.Bounded {
  1287  					if nlen.Op != OREGISTER && (Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9') {
  1288  						var tmp2 Node
  1289  						Regalloc(&tmp2, Types[Simtype[TUINT]], nil)
  1290  						Thearch.Gmove(&nlen, &tmp2)
  1291  						Regfree(&nlen) // in case it is OINDREG
  1292  						nlen = tmp2
  1293  					}
  1294  					var n2 Node
  1295  					Nodconst(&n2, Types[Simtype[TUINT]], int64(v))
  1296  					if Smallintconst(nr) {
  1297  						Thearch.Gins(Thearch.Optoas(OCMP, Types[Simtype[TUINT]]), &nlen, &n2)
  1298  					} else {
  1299  						Regalloc(&tmp, Types[Simtype[TUINT]], nil)
  1300  						Thearch.Gmove(&n2, &tmp)
  1301  						Thearch.Gins(Thearch.Optoas(OCMP, Types[Simtype[TUINT]]), &nlen, &tmp)
  1302  						Regfree(&tmp)
  1303  					}
  1304  
  1305  					p1 := Gbranch(Thearch.Optoas(OGT, Types[Simtype[TUINT]]), nil, +1)
  1306  					Ginscall(Panicindex, -1)
  1307  					Patch(p1, Pc)
  1308  				}
  1309  
  1310  				Regfree(&nlen)
  1311  			}
  1312  
  1313  			if v*w != 0 {
  1314  				Thearch.Ginscon(Thearch.Optoas(OADD, Types[Tptr]), int64(v*w), &n3)
  1315  			}
  1316  			*a = n3
  1317  			break
  1318  		}
  1319  
  1320  		// type of the index
  1321  		t := Types[TUINT64]
  1322  
  1323  		if Issigned[n1.Type.Etype] {
  1324  			t = Types[TINT64]
  1325  		}
  1326  
  1327  		var n2 Node
  1328  		Regalloc(&n2, t, &n1) // i
  1329  		Thearch.Gmove(&n1, &n2)
  1330  		Regfree(&n1)
  1331  
  1332  		if Debug['B'] == 0 && !n.Bounded {
  1333  			// check bounds
  1334  			t = Types[Simtype[TUINT]]
  1335  
  1336  			if Is64(nr.Type) {
  1337  				t = Types[TUINT64]
  1338  			}
  1339  			if Isconst(nl, CTSTR) {
  1340  				Nodconst(&nlen, t, int64(len(nl.Val.U.Sval)))
  1341  			} else if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
  1342  				if Is64(nr.Type) || Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' {
  1343  					var n5 Node
  1344  					Regalloc(&n5, t, nil)
  1345  					Thearch.Gmove(&nlen, &n5)
  1346  					Regfree(&nlen)
  1347  					nlen = n5
  1348  				}
  1349  			} else {
  1350  				Nodconst(&nlen, t, nl.Type.Bound)
  1351  				if !Smallintconst(&nlen) {
  1352  					var n5 Node
  1353  					Regalloc(&n5, t, nil)
  1354  					Thearch.Gmove(&nlen, &n5)
  1355  					nlen = n5
  1356  					freelen = 1
  1357  				}
  1358  			}
  1359  
  1360  			Thearch.Gins(Thearch.Optoas(OCMP, t), &n2, &nlen)
  1361  			p1 := Gbranch(Thearch.Optoas(OLT, t), nil, +1)
  1362  			Ginscall(Panicindex, -1)
  1363  			Patch(p1, Pc)
  1364  		}
  1365  
  1366  		if Isconst(nl, CTSTR) {
  1367  			Regalloc(&n3, Types[Tptr], res)
  1368  			p1 := Thearch.Gins(Thearch.Optoas(OAS, n3.Type), nil, &n3) // XXX was LEAQ!
  1369  			Datastring(nl.Val.U.Sval, &p1.From)
  1370  			p1.From.Type = obj.TYPE_ADDR
  1371  			Thearch.Gins(Thearch.Optoas(OADD, n3.Type), &n2, &n3)
  1372  			goto indexdone
  1373  		}
  1374  
  1375  		if w == 0 {
  1376  			// nothing to do
  1377  		} else if Thearch.AddIndex != nil && Thearch.AddIndex(&n2, int64(w), &n3) {
  1378  			// done by back end
  1379  		} else if w == 1 {
  1380  			Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
  1381  		} else {
  1382  			Thearch.Ginscon(Thearch.Optoas(OMUL, t), int64(w), &n2)
  1383  			Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
  1384  		}
  1385  
  1386  	indexdone:
  1387  		*a = n3
  1388  		Regfree(&n2)
  1389  		if freelen != 0 {
  1390  			Regfree(&nlen)
  1391  		}
  1392  
  1393  	default:
  1394  		Regalloc(a, Types[Tptr], res)
  1395  		Agen(n, a)
  1396  	}
  1397  }
  1398  
  1399  /*
  1400   * generate:
  1401   *	res = &n;
  1402   * The generated code checks that the result is not nil.
  1403   */
  1404  func Agen(n *Node, res *Node) {
  1405  	if Debug['g'] != 0 {
  1406  		Dump("\nagen-res", res)
  1407  		Dump("agen-r", n)
  1408  	}
  1409  
  1410  	if n == nil || n.Type == nil {
  1411  		return
  1412  	}
  1413  
  1414  	for n.Op == OCONVNOP {
  1415  		n = n.Left
  1416  	}
  1417  
  1418  	if Isconst(n, CTNIL) && n.Type.Width > int64(Widthptr) {
  1419  		// Use of a nil interface or nil slice.
  1420  		// Create a temporary we can take the address of and read.
  1421  		// The generated code is just going to panic, so it need not
  1422  		// be terribly efficient. See issue 3670.
  1423  		var n1 Node
  1424  		Tempname(&n1, n.Type)
  1425  
  1426  		Gvardef(&n1)
  1427  		Thearch.Clearfat(&n1)
  1428  		var n2 Node
  1429  		Regalloc(&n2, Types[Tptr], res)
  1430  		var n3 Node
  1431  		n3.Op = OADDR
  1432  		n3.Left = &n1
  1433  		Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &n3, &n2)
  1434  		Thearch.Gmove(&n2, res)
  1435  		Regfree(&n2)
  1436  		return
  1437  	}
  1438  
  1439  	if n.Addable {
  1440  		if n.Op == OREGISTER {
  1441  			Fatal("agen OREGISTER")
  1442  		}
  1443  		var n1 Node
  1444  		n1.Op = OADDR
  1445  		n1.Left = n
  1446  		var n2 Node
  1447  		Regalloc(&n2, Types[Tptr], res)
  1448  		Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &n1, &n2)
  1449  		Thearch.Gmove(&n2, res)
  1450  		Regfree(&n2)
  1451  		return
  1452  	}
  1453  
  1454  	nl := n.Left
  1455  
  1456  	switch n.Op {
  1457  	default:
  1458  		Fatal("agen: unknown op %v", Nconv(n, obj.FmtShort|obj.FmtSign))
  1459  
  1460  	case OCALLMETH:
  1461  		cgen_callmeth(n, 0)
  1462  		cgen_aret(n, res)
  1463  
  1464  	case OCALLINTER:
  1465  		cgen_callinter(n, res, 0)
  1466  		cgen_aret(n, res)
  1467  
  1468  	case OCALLFUNC:
  1469  		cgen_call(n, 0)
  1470  		cgen_aret(n, res)
  1471  
  1472  	case OEFACE, ODOTTYPE, OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
  1473  		var n1 Node
  1474  		Tempname(&n1, n.Type)
  1475  		Cgen(n, &n1)
  1476  		Agen(&n1, res)
  1477  
  1478  	case OINDEX:
  1479  		var n1 Node
  1480  		Agenr(n, &n1, res)
  1481  		Thearch.Gmove(&n1, res)
  1482  		Regfree(&n1)
  1483  
  1484  	case ONAME:
  1485  		// should only get here with names in this func.
  1486  		if n.Funcdepth > 0 && n.Funcdepth != Funcdepth {
  1487  			Dump("bad agen", n)
  1488  			Fatal("agen: bad ONAME funcdepth %d != %d", n.Funcdepth, Funcdepth)
  1489  		}
  1490  
  1491  		// should only get here for heap vars or paramref
  1492  		if n.Class&PHEAP == 0 && n.Class != PPARAMREF {
  1493  			Dump("bad agen", n)
  1494  			Fatal("agen: bad ONAME class %#x", n.Class)
  1495  		}
  1496  
  1497  		Cgen(n.Heapaddr, res)
  1498  		if n.Xoffset != 0 {
  1499  			addOffset(res, n.Xoffset)
  1500  		}
  1501  
  1502  	case OIND:
  1503  		Cgen(nl, res)
  1504  		Cgen_checknil(res)
  1505  
  1506  	case ODOT:
  1507  		Agen(nl, res)
  1508  		if n.Xoffset != 0 {
  1509  			addOffset(res, n.Xoffset)
  1510  		}
  1511  
  1512  	case ODOTPTR:
  1513  		Cgen(nl, res)
  1514  		Cgen_checknil(res)
  1515  		if n.Xoffset != 0 {
  1516  			addOffset(res, n.Xoffset)
  1517  		}
  1518  	}
  1519  }
  1520  
  1521  func addOffset(res *Node, offset int64) {
  1522  	if Ctxt.Arch.Thechar == '6' || Ctxt.Arch.Thechar == '8' {
  1523  		Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), Nodintconst(offset), res)
  1524  		return
  1525  	}
  1526  
  1527  	var n1, n2 Node
  1528  	Regalloc(&n1, Types[Tptr], nil)
  1529  	Thearch.Gmove(res, &n1)
  1530  	Regalloc(&n2, Types[Tptr], nil)
  1531  	Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), Nodintconst(offset), &n2)
  1532  	Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n1)
  1533  	Thearch.Gmove(&n1, res)
  1534  	Regfree(&n1)
  1535  	Regfree(&n2)
  1536  }
  1537  
  1538  // Igen computes the address &n, stores it in a register r,
  1539  // and rewrites a to refer to *r. The chosen r may be the
  1540  // stack pointer, it may be borrowed from res, or it may
  1541  // be a newly allocated register. The caller must call Regfree(a)
  1542  // to free r when the address is no longer needed.
  1543  // The generated code ensures that &n is not nil.
  1544  func Igen(n *Node, a *Node, res *Node) {
  1545  	if Debug['g'] != 0 {
  1546  		Dump("\nigen-n", n)
  1547  	}
  1548  
  1549  	switch n.Op {
  1550  	case ONAME:
  1551  		if (n.Class&PHEAP != 0) || n.Class == PPARAMREF {
  1552  			break
  1553  		}
  1554  		*a = *n
  1555  		return
  1556  
  1557  	case OINDREG:
  1558  		// Increase the refcount of the register so that igen's caller
  1559  		// has to call Regfree.
  1560  		if n.Reg != int16(Thearch.REGSP) {
  1561  			reg[n.Reg-int16(Thearch.REGMIN)]++
  1562  		}
  1563  		*a = *n
  1564  		return
  1565  
  1566  	case ODOT:
  1567  		Igen(n.Left, a, res)
  1568  		a.Xoffset += n.Xoffset
  1569  		a.Type = n.Type
  1570  		Fixlargeoffset(a)
  1571  		return
  1572  
  1573  	case ODOTPTR:
  1574  		Cgenr(n.Left, a, res)
  1575  		Cgen_checknil(a)
  1576  		a.Op = OINDREG
  1577  		a.Xoffset += n.Xoffset
  1578  		a.Type = n.Type
  1579  		Fixlargeoffset(a)
  1580  		return
  1581  
  1582  	case OCALLFUNC, OCALLMETH, OCALLINTER:
  1583  		switch n.Op {
  1584  		case OCALLFUNC:
  1585  			cgen_call(n, 0)
  1586  
  1587  		case OCALLMETH:
  1588  			cgen_callmeth(n, 0)
  1589  
  1590  		case OCALLINTER:
  1591  			cgen_callinter(n, nil, 0)
  1592  		}
  1593  
  1594  		var flist Iter
  1595  		fp := Structfirst(&flist, Getoutarg(n.Left.Type))
  1596  		*a = Node{}
  1597  		a.Op = OINDREG
  1598  		a.Reg = int16(Thearch.REGSP)
  1599  		a.Addable = true
  1600  		a.Xoffset = fp.Width
  1601  		if HasLinkRegister() {
  1602  			a.Xoffset += int64(Ctxt.Arch.Ptrsize)
  1603  		}
  1604  		a.Type = n.Type
  1605  		return
  1606  
  1607  		// Index of fixed-size array by constant can
  1608  	// put the offset in the addressing.
  1609  	// Could do the same for slice except that we need
  1610  	// to use the real index for the bounds checking.
  1611  	case OINDEX:
  1612  		if Isfixedarray(n.Left.Type) || (Isptr[n.Left.Type.Etype] && Isfixedarray(n.Left.Left.Type)) {
  1613  			if Isconst(n.Right, CTINT) {
  1614  				// Compute &a.
  1615  				if !Isptr[n.Left.Type.Etype] {
  1616  					Igen(n.Left, a, res)
  1617  				} else {
  1618  					var n1 Node
  1619  					Igen(n.Left, &n1, res)
  1620  					Cgen_checknil(&n1)
  1621  					Regalloc(a, Types[Tptr], res)
  1622  					Thearch.Gmove(&n1, a)
  1623  					Regfree(&n1)
  1624  					a.Op = OINDREG
  1625  				}
  1626  
  1627  				// Compute &a[i] as &a + i*width.
  1628  				a.Type = n.Type
  1629  
  1630  				a.Xoffset += Mpgetfix(n.Right.Val.U.Xval) * n.Type.Width
  1631  				Fixlargeoffset(a)
  1632  				return
  1633  			}
  1634  		}
  1635  	}
  1636  
  1637  	Agenr(n, a, res)
  1638  	a.Op = OINDREG
  1639  	a.Type = n.Type
  1640  }
  1641  
  1642  /*
  1643   * generate:
  1644   *	if(n == true) goto to;
  1645   */
  1646  func Bgen(n *Node, true_ bool, likely int, to *obj.Prog) {
  1647  	if Debug['g'] != 0 {
  1648  		Dump("\nbgen", n)
  1649  	}
  1650  
  1651  	if n == nil {
  1652  		n = Nodbool(true)
  1653  	}
  1654  
  1655  	if n.Ninit != nil {
  1656  		Genlist(n.Ninit)
  1657  	}
  1658  
  1659  	if n.Type == nil {
  1660  		Convlit(&n, Types[TBOOL])
  1661  		if n.Type == nil {
  1662  			return
  1663  		}
  1664  	}
  1665  
  1666  	et := int(n.Type.Etype)
  1667  	if et != TBOOL {
  1668  		Yyerror("cgen: bad type %v for %v", Tconv(n.Type, 0), Oconv(int(n.Op), 0))
  1669  		Patch(Thearch.Gins(obj.AEND, nil, nil), to)
  1670  		return
  1671  	}
  1672  
  1673  	for n.Op == OCONVNOP {
  1674  		n = n.Left
  1675  		if n.Ninit != nil {
  1676  			Genlist(n.Ninit)
  1677  		}
  1678  	}
  1679  
  1680  	if Thearch.Bgen_float != nil && n.Left != nil && Isfloat[n.Left.Type.Etype] {
  1681  		Thearch.Bgen_float(n, bool2int(true_), likely, to)
  1682  		return
  1683  	}
  1684  
  1685  	var nl *Node
  1686  	var nr *Node
  1687  	switch n.Op {
  1688  	default:
  1689  		goto def
  1690  
  1691  		// need to ask if it is bool?
  1692  	case OLITERAL:
  1693  		if true_ == n.Val.U.Bval {
  1694  			Patch(Gbranch(obj.AJMP, nil, likely), to)
  1695  		}
  1696  		return
  1697  
  1698  	case ONAME:
  1699  		if !n.Addable || Ctxt.Arch.Thechar == '5' || Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' {
  1700  			goto def
  1701  		}
  1702  		var n1 Node
  1703  		Nodconst(&n1, n.Type, 0)
  1704  		Thearch.Gins(Thearch.Optoas(OCMP, n.Type), n, &n1)
  1705  		a := Thearch.Optoas(ONE, n.Type)
  1706  		if !true_ {
  1707  			a = Thearch.Optoas(OEQ, n.Type)
  1708  		}
  1709  		Patch(Gbranch(a, n.Type, likely), to)
  1710  		return
  1711  
  1712  	case OANDAND, OOROR:
  1713  		if (n.Op == OANDAND) == true_ {
  1714  			p1 := Gbranch(obj.AJMP, nil, 0)
  1715  			p2 := Gbranch(obj.AJMP, nil, 0)
  1716  			Patch(p1, Pc)
  1717  			Bgen(n.Left, !true_, -likely, p2)
  1718  			Bgen(n.Right, !true_, -likely, p2)
  1719  			p1 = Gbranch(obj.AJMP, nil, 0)
  1720  			Patch(p1, to)
  1721  			Patch(p2, Pc)
  1722  		} else {
  1723  			Bgen(n.Left, true_, likely, to)
  1724  			Bgen(n.Right, true_, likely, to)
  1725  		}
  1726  
  1727  		return
  1728  
  1729  	case OEQ, ONE, OLT, OGT, OLE, OGE:
  1730  		nr = n.Right
  1731  		if nr == nil || nr.Type == nil {
  1732  			return
  1733  		}
  1734  		fallthrough
  1735  
  1736  	case ONOT: // unary
  1737  		nl = n.Left
  1738  
  1739  		if nl == nil || nl.Type == nil {
  1740  			return
  1741  		}
  1742  	}
  1743  
  1744  	switch n.Op {
  1745  	case ONOT:
  1746  		Bgen(nl, !true_, likely, to)
  1747  		return
  1748  
  1749  	case OEQ, ONE, OLT, OGT, OLE, OGE:
  1750  		a := int(n.Op)
  1751  		if !true_ {
  1752  			if Isfloat[nr.Type.Etype] {
  1753  				// brcom is not valid on floats when NaN is involved.
  1754  				p1 := Gbranch(obj.AJMP, nil, 0)
  1755  				p2 := Gbranch(obj.AJMP, nil, 0)
  1756  				Patch(p1, Pc)
  1757  				ll := n.Ninit // avoid re-genning ninit
  1758  				n.Ninit = nil
  1759  				Bgen(n, true, -likely, p2)
  1760  				n.Ninit = ll
  1761  				Patch(Gbranch(obj.AJMP, nil, 0), to)
  1762  				Patch(p2, Pc)
  1763  				return
  1764  			}
  1765  
  1766  			a = Brcom(a)
  1767  			true_ = !true_
  1768  		}
  1769  
  1770  		// make simplest on right
  1771  		if nl.Op == OLITERAL || (nl.Ullman < nr.Ullman && nl.Ullman < UINF) {
  1772  			a = Brrev(a)
  1773  			r := nl
  1774  			nl = nr
  1775  			nr = r
  1776  		}
  1777  
  1778  		if Isslice(nl.Type) {
  1779  			// front end should only leave cmp to literal nil
  1780  			if (a != OEQ && a != ONE) || nr.Op != OLITERAL {
  1781  				Yyerror("illegal slice comparison")
  1782  				break
  1783  			}
  1784  
  1785  			a = Thearch.Optoas(a, Types[Tptr])
  1786  			var n1 Node
  1787  			Igen(nl, &n1, nil)
  1788  			n1.Xoffset += int64(Array_array)
  1789  			n1.Type = Types[Tptr]
  1790  			var n2 Node
  1791  			Regalloc(&n2, Types[Tptr], &n1)
  1792  			Cgen(&n1, &n2)
  1793  			Regfree(&n1)
  1794  			var tmp Node
  1795  			Nodconst(&tmp, Types[Tptr], 0)
  1796  			Thearch.Gins(Thearch.Optoas(OCMP, Types[Tptr]), &n2, &tmp)
  1797  			Patch(Gbranch(a, Types[Tptr], likely), to)
  1798  			Regfree(&n2)
  1799  			break
  1800  		}
  1801  
  1802  		if Isinter(nl.Type) {
  1803  			// front end should only leave cmp to literal nil
  1804  			if (a != OEQ && a != ONE) || nr.Op != OLITERAL {
  1805  				Yyerror("illegal interface comparison")
  1806  				break
  1807  			}
  1808  
  1809  			a = Thearch.Optoas(a, Types[Tptr])
  1810  			var n1 Node
  1811  			Igen(nl, &n1, nil)
  1812  			n1.Type = Types[Tptr]
  1813  			var n2 Node
  1814  			Regalloc(&n2, Types[Tptr], &n1)
  1815  			Cgen(&n1, &n2)
  1816  			Regfree(&n1)
  1817  			var tmp Node
  1818  			Nodconst(&tmp, Types[Tptr], 0)
  1819  			Thearch.Gins(Thearch.Optoas(OCMP, Types[Tptr]), &n2, &tmp)
  1820  			Patch(Gbranch(a, Types[Tptr], likely), to)
  1821  			Regfree(&n2)
  1822  			break
  1823  		}
  1824  
  1825  		if Iscomplex[nl.Type.Etype] {
  1826  			Complexbool(a, nl, nr, true_, likely, to)
  1827  			break
  1828  		}
  1829  
  1830  		if Ctxt.Arch.Regsize == 4 && Is64(nr.Type) {
  1831  			if !nl.Addable || Isconst(nl, CTINT) {
  1832  				var n1 Node
  1833  				Tempname(&n1, nl.Type)
  1834  				Cgen(nl, &n1)
  1835  				nl = &n1
  1836  			}
  1837  
  1838  			if !nr.Addable {
  1839  				var n2 Node
  1840  				Tempname(&n2, nr.Type)
  1841  				Cgen(nr, &n2)
  1842  				nr = &n2
  1843  			}
  1844  
  1845  			Thearch.Cmp64(nl, nr, a, likely, to)
  1846  			break
  1847  		}
  1848  
  1849  		var n1 Node
  1850  		var n2 Node
  1851  		if nr.Ullman >= UINF {
  1852  			Regalloc(&n1, nl.Type, nil)
  1853  			Cgen(nl, &n1)
  1854  
  1855  			var tmp Node
  1856  			Tempname(&tmp, nl.Type)
  1857  			Thearch.Gmove(&n1, &tmp)
  1858  			Regfree(&n1)
  1859  
  1860  			Regalloc(&n2, nr.Type, nil)
  1861  			Cgen(nr, &n2)
  1862  
  1863  			Regalloc(&n1, nl.Type, nil)
  1864  			Cgen(&tmp, &n1)
  1865  
  1866  			goto cmp
  1867  		}
  1868  
  1869  		if !nl.Addable && Ctxt.Arch.Thechar == '8' {
  1870  			Tempname(&n1, nl.Type)
  1871  		} else {
  1872  			Regalloc(&n1, nl.Type, nil)
  1873  		}
  1874  		Cgen(nl, &n1)
  1875  		nl = &n1
  1876  
  1877  		if Smallintconst(nr) && Ctxt.Arch.Thechar != '9' {
  1878  			Thearch.Gins(Thearch.Optoas(OCMP, nr.Type), nl, nr)
  1879  			Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
  1880  			if n1.Op == OREGISTER {
  1881  				Regfree(&n1)
  1882  			}
  1883  			break
  1884  		}
  1885  
  1886  		if !nr.Addable && Ctxt.Arch.Thechar == '8' {
  1887  			var tmp Node
  1888  			Tempname(&tmp, nr.Type)
  1889  			Cgen(nr, &tmp)
  1890  			nr = &tmp
  1891  		}
  1892  
  1893  		Regalloc(&n2, nr.Type, nil)
  1894  		Cgen(nr, &n2)
  1895  		nr = &n2
  1896  
  1897  	cmp:
  1898  		l, r := nl, nr
  1899  		// On x86, only < and <= work right with NaN; reverse if needed
  1900  		if Ctxt.Arch.Thechar == '6' && Isfloat[nl.Type.Etype] && (a == OGT || a == OGE) {
  1901  			l, r = r, l
  1902  			a = Brrev(a)
  1903  		}
  1904  
  1905  		Thearch.Gins(Thearch.Optoas(OCMP, nr.Type), l, r)
  1906  
  1907  		if Ctxt.Arch.Thechar == '6' && Isfloat[nr.Type.Etype] && (n.Op == OEQ || n.Op == ONE) {
  1908  			if n.Op == OEQ {
  1909  				// neither NE nor P
  1910  				p1 := Gbranch(Thearch.Optoas(ONE, nr.Type), nil, -likely)
  1911  				p2 := Gbranch(Thearch.Optoas(OPS, nr.Type), nil, -likely)
  1912  				Patch(Gbranch(obj.AJMP, nil, 0), to)
  1913  				Patch(p1, Pc)
  1914  				Patch(p2, Pc)
  1915  			} else {
  1916  				// either NE or P
  1917  				Patch(Gbranch(Thearch.Optoas(ONE, nr.Type), nil, likely), to)
  1918  				Patch(Gbranch(Thearch.Optoas(OPS, nr.Type), nil, likely), to)
  1919  			}
  1920  		} else if Ctxt.Arch.Thechar == '5' && Isfloat[nl.Type.Etype] {
  1921  			if n.Op == ONE {
  1922  				Patch(Gbranch(Thearch.Optoas(OPS, nr.Type), nr.Type, likely), to)
  1923  				Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
  1924  			} else {
  1925  				p := Gbranch(Thearch.Optoas(OPS, nr.Type), nr.Type, -likely)
  1926  				Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
  1927  				Patch(p, Pc)
  1928  			}
  1929  		} else if (Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9') && Isfloat[nl.Type.Etype] && (a == OLE || a == OGE) {
  1930  			// On arm64 and ppc64, <= and >= mishandle NaN. Must decompose into < or > and =.
  1931  			if a == OLE {
  1932  				a = OLT
  1933  			} else {
  1934  				a = OGT
  1935  			}
  1936  			Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
  1937  			Patch(Gbranch(Thearch.Optoas(OEQ, nr.Type), nr.Type, likely), to)
  1938  		} else {
  1939  			Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
  1940  		}
  1941  		if n1.Op == OREGISTER {
  1942  			Regfree(&n1)
  1943  		}
  1944  		if n2.Op == OREGISTER {
  1945  			Regfree(&n2)
  1946  		}
  1947  	}
  1948  
  1949  	return
  1950  
  1951  def:
  1952  	// TODO: Optimize on systems that can compare to zero easily.
  1953  	var n1 Node
  1954  	Regalloc(&n1, n.Type, nil)
  1955  	Cgen(n, &n1)
  1956  	var n2 Node
  1957  	Nodconst(&n2, n.Type, 0)
  1958  	Thearch.Gins(Thearch.Optoas(OCMP, n.Type), &n1, &n2)
  1959  	a := Thearch.Optoas(ONE, n.Type)
  1960  	if !true_ {
  1961  		a = Thearch.Optoas(OEQ, n.Type)
  1962  	}
  1963  	Patch(Gbranch(a, n.Type, likely), to)
  1964  	Regfree(&n1)
  1965  	return
  1966  }
  1967  
  1968  /*
  1969   * n is on stack, either local variable
  1970   * or return value from function call.
  1971   * return n's offset from SP.
  1972   */
  1973  func stkof(n *Node) int64 {
  1974  	switch n.Op {
  1975  	case OINDREG:
  1976  		return n.Xoffset
  1977  
  1978  	case ODOT:
  1979  		t := n.Left.Type
  1980  		if Isptr[t.Etype] {
  1981  			break
  1982  		}
  1983  		off := stkof(n.Left)
  1984  		if off == -1000 || off == 1000 {
  1985  			return off
  1986  		}
  1987  		return off + n.Xoffset
  1988  
  1989  	case OINDEX:
  1990  		t := n.Left.Type
  1991  		if !Isfixedarray(t) {
  1992  			break
  1993  		}
  1994  		off := stkof(n.Left)
  1995  		if off == -1000 || off == 1000 {
  1996  			return off
  1997  		}
  1998  		if Isconst(n.Right, CTINT) {
  1999  			return off + t.Type.Width*Mpgetfix(n.Right.Val.U.Xval)
  2000  		}
  2001  		return 1000
  2002  
  2003  	case OCALLMETH, OCALLINTER, OCALLFUNC:
  2004  		t := n.Left.Type
  2005  		if Isptr[t.Etype] {
  2006  			t = t.Type
  2007  		}
  2008  
  2009  		var flist Iter
  2010  		t = Structfirst(&flist, Getoutarg(t))
  2011  		if t != nil {
  2012  			w := t.Width
  2013  			if HasLinkRegister() {
  2014  				w += int64(Ctxt.Arch.Ptrsize)
  2015  			}
  2016  			return w
  2017  		}
  2018  	}
  2019  
  2020  	// botch - probably failing to recognize address
  2021  	// arithmetic on the above. eg INDEX and DOT
  2022  	return -1000
  2023  }
  2024  
  2025  /*
  2026   * block copy:
  2027   *	memmove(&ns, &n, w);
  2028   */
  2029  func sgen(n *Node, ns *Node, w int64) {
  2030  	if Debug['g'] != 0 {
  2031  		fmt.Printf("\nsgen w=%d\n", w)
  2032  		Dump("r", n)
  2033  		Dump("res", ns)
  2034  	}
  2035  
  2036  	if n.Ullman >= UINF && ns.Ullman >= UINF {
  2037  		Fatal("sgen UINF")
  2038  	}
  2039  
  2040  	if w < 0 {
  2041  		Fatal("sgen copy %d", w)
  2042  	}
  2043  
  2044  	// If copying .args, that's all the results, so record definition sites
  2045  	// for them for the liveness analysis.
  2046  	if ns.Op == ONAME && ns.Sym.Name == ".args" {
  2047  		for l := Curfn.Func.Dcl; l != nil; l = l.Next {
  2048  			if l.N.Class == PPARAMOUT {
  2049  				Gvardef(l.N)
  2050  			}
  2051  		}
  2052  	}
  2053  
  2054  	// Avoid taking the address for simple enough types.
  2055  	if Componentgen(n, ns) {
  2056  		return
  2057  	}
  2058  
  2059  	if w == 0 {
  2060  		// evaluate side effects only
  2061  		var nodr Node
  2062  		Regalloc(&nodr, Types[Tptr], nil)
  2063  		Agen(ns, &nodr)
  2064  		Agen(n, &nodr)
  2065  		Regfree(&nodr)
  2066  		return
  2067  	}
  2068  
  2069  	// offset on the stack
  2070  	osrc := stkof(n)
  2071  	odst := stkof(ns)
  2072  
  2073  	if osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000) {
  2074  		// osrc and odst both on stack, and at least one is in
  2075  		// an unknown position.  Could generate code to test
  2076  		// for forward/backward copy, but instead just copy
  2077  		// to a temporary location first.
  2078  		var tmp Node
  2079  		Tempname(&tmp, n.Type)
  2080  		sgen(n, &tmp, w)
  2081  		sgen(&tmp, ns, w)
  2082  		return
  2083  	}
  2084  
  2085  	Thearch.Stackcopy(n, ns, osrc, odst, w)
  2086  }
  2087  
  2088  /*
  2089   * generate:
  2090   *	call f
  2091   *	proc=-1	normal call but no return
  2092   *	proc=0	normal call
  2093   *	proc=1	goroutine run in new proc
  2094   *	proc=2	defer call save away stack
  2095    *	proc=3	normal call to C pointer (not Go func value)
  2096  */
  2097  func Ginscall(f *Node, proc int) {
  2098  	if f.Type != nil {
  2099  		extra := int32(0)
  2100  		if proc == 1 || proc == 2 {
  2101  			extra = 2 * int32(Widthptr)
  2102  		}
  2103  		Setmaxarg(f.Type, extra)
  2104  	}
  2105  
  2106  	switch proc {
  2107  	default:
  2108  		Fatal("Ginscall: bad proc %d", proc)
  2109  
  2110  	case 0, // normal call
  2111  		-1: // normal call but no return
  2112  		if f.Op == ONAME && f.Class == PFUNC {
  2113  			if f == Deferreturn {
  2114  				// Deferred calls will appear to be returning to
  2115  				// the CALL deferreturn(SB) that we are about to emit.
  2116  				// However, the stack trace code will show the line
  2117  				// of the instruction byte before the return PC.
  2118  				// To avoid that being an unrelated instruction,
  2119  				// insert an actual hardware NOP that will have the right line number.
  2120  				// This is different from obj.ANOP, which is a virtual no-op
  2121  				// that doesn't make it into the instruction stream.
  2122  				Thearch.Ginsnop()
  2123  			}
  2124  
  2125  			p := Thearch.Gins(obj.ACALL, nil, f)
  2126  			Afunclit(&p.To, f)
  2127  			if proc == -1 || Noreturn(p) {
  2128  				Thearch.Gins(obj.AUNDEF, nil, nil)
  2129  			}
  2130  			break
  2131  		}
  2132  
  2133  		var reg Node
  2134  		Nodreg(&reg, Types[Tptr], Thearch.REGCTXT)
  2135  		var r1 Node
  2136  		Nodreg(&r1, Types[Tptr], Thearch.REGCALLX)
  2137  		Thearch.Gmove(f, &reg)
  2138  		reg.Op = OINDREG
  2139  		Thearch.Gmove(&reg, &r1)
  2140  		reg.Op = OREGISTER
  2141  		Thearch.Gins(obj.ACALL, &reg, &r1)
  2142  
  2143  	case 3: // normal call of c function pointer
  2144  		Thearch.Gins(obj.ACALL, nil, f)
  2145  
  2146  	case 1, // call in new proc (go)
  2147  		2: // deferred call (defer)
  2148  		var stk Node
  2149  
  2150  		// size of arguments at 0(SP)
  2151  		stk.Op = OINDREG
  2152  		stk.Reg = int16(Thearch.REGSP)
  2153  		stk.Xoffset = 0
  2154  		if HasLinkRegister() {
  2155  			stk.Xoffset += int64(Ctxt.Arch.Ptrsize)
  2156  		}
  2157  		Thearch.Ginscon(Thearch.Optoas(OAS, Types[Tptr]), int64(Argsize(f.Type)), &stk)
  2158  
  2159  		// FuncVal* at 8(SP)
  2160  		stk.Xoffset = int64(Widthptr)
  2161  		if HasLinkRegister() {
  2162  			stk.Xoffset += int64(Ctxt.Arch.Ptrsize)
  2163  		}
  2164  
  2165  		var reg Node
  2166  		Nodreg(&reg, Types[Tptr], Thearch.REGCALLX2)
  2167  		Thearch.Gmove(f, &reg)
  2168  		Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &reg, &stk)
  2169  
  2170  		if proc == 1 {
  2171  			Ginscall(Newproc, 0)
  2172  		} else {
  2173  			if Hasdefer == 0 {
  2174  				Fatal("hasdefer=0 but has defer")
  2175  			}
  2176  			Ginscall(Deferproc, 0)
  2177  		}
  2178  
  2179  		if proc == 2 {
  2180  			Nodreg(&reg, Types[TINT32], Thearch.REGRETURN)
  2181  			Thearch.Gins(Thearch.Optoas(OCMP, Types[TINT32]), &reg, Nodintconst(0))
  2182  			p := Gbranch(Thearch.Optoas(OEQ, Types[TINT32]), nil, +1)
  2183  			cgen_ret(nil)
  2184  			Patch(p, Pc)
  2185  		}
  2186  	}
  2187  }
  2188  
  2189  /*
  2190   * n is call to interface method.
  2191   * generate res = n.
  2192   */
  2193  func cgen_callinter(n *Node, res *Node, proc int) {
  2194  	i := n.Left
  2195  	if i.Op != ODOTINTER {
  2196  		Fatal("cgen_callinter: not ODOTINTER %v", Oconv(int(i.Op), 0))
  2197  	}
  2198  
  2199  	f := i.Right // field
  2200  	if f.Op != ONAME {
  2201  		Fatal("cgen_callinter: not ONAME %v", Oconv(int(f.Op), 0))
  2202  	}
  2203  
  2204  	i = i.Left // interface
  2205  
  2206  	if !i.Addable {
  2207  		var tmpi Node
  2208  		Tempname(&tmpi, i.Type)
  2209  		Cgen(i, &tmpi)
  2210  		i = &tmpi
  2211  	}
  2212  
  2213  	Genlist(n.List) // assign the args
  2214  
  2215  	// i is now addable, prepare an indirected
  2216  	// register to hold its address.
  2217  	var nodi Node
  2218  	Igen(i, &nodi, res) // REG = &inter
  2219  
  2220  	var nodsp Node
  2221  	Nodindreg(&nodsp, Types[Tptr], Thearch.REGSP)
  2222  	nodsp.Xoffset = 0
  2223  	if HasLinkRegister() {
  2224  		nodsp.Xoffset += int64(Ctxt.Arch.Ptrsize)
  2225  	}
  2226  	if proc != 0 {
  2227  		nodsp.Xoffset += 2 * int64(Widthptr) // leave room for size & fn
  2228  	}
  2229  	nodi.Type = Types[Tptr]
  2230  	nodi.Xoffset += int64(Widthptr)
  2231  	Cgen(&nodi, &nodsp) // {0, 8(nacl), or 16}(SP) = 8(REG) -- i.data
  2232  
  2233  	var nodo Node
  2234  	Regalloc(&nodo, Types[Tptr], res)
  2235  
  2236  	nodi.Type = Types[Tptr]
  2237  	nodi.Xoffset -= int64(Widthptr)
  2238  	Cgen(&nodi, &nodo) // REG = 0(REG) -- i.tab
  2239  	Regfree(&nodi)
  2240  
  2241  	var nodr Node
  2242  	Regalloc(&nodr, Types[Tptr], &nodo)
  2243  	if n.Left.Xoffset == BADWIDTH {
  2244  		Fatal("cgen_callinter: badwidth")
  2245  	}
  2246  	Cgen_checknil(&nodo) // in case offset is huge
  2247  	nodo.Op = OINDREG
  2248  	nodo.Xoffset = n.Left.Xoffset + 3*int64(Widthptr) + 8
  2249  	if proc == 0 {
  2250  		// plain call: use direct c function pointer - more efficient
  2251  		Cgen(&nodo, &nodr) // REG = 32+offset(REG) -- i.tab->fun[f]
  2252  		proc = 3
  2253  	} else {
  2254  		// go/defer. generate go func value.
  2255  		Agen(&nodo, &nodr) // REG = &(32+offset(REG)) -- i.tab->fun[f]
  2256  	}
  2257  
  2258  	nodr.Type = n.Left.Type
  2259  	Ginscall(&nodr, proc)
  2260  
  2261  	Regfree(&nodr)
  2262  	Regfree(&nodo)
  2263  }
  2264  
  2265  /*
  2266   * generate function call;
  2267   *	proc=0	normal call
  2268   *	proc=1	goroutine run in new proc
  2269   *	proc=2	defer call save away stack
  2270   */
  2271  func cgen_call(n *Node, proc int) {
  2272  	if n == nil {
  2273  		return
  2274  	}
  2275  
  2276  	var afun Node
  2277  	if n.Left.Ullman >= UINF {
  2278  		// if name involves a fn call
  2279  		// precompute the address of the fn
  2280  		Tempname(&afun, Types[Tptr])
  2281  
  2282  		Cgen(n.Left, &afun)
  2283  	}
  2284  
  2285  	Genlist(n.List) // assign the args
  2286  	t := n.Left.Type
  2287  
  2288  	// call tempname pointer
  2289  	if n.Left.Ullman >= UINF {
  2290  		var nod Node
  2291  		Regalloc(&nod, Types[Tptr], nil)
  2292  		Cgen_as(&nod, &afun)
  2293  		nod.Type = t
  2294  		Ginscall(&nod, proc)
  2295  		Regfree(&nod)
  2296  		return
  2297  	}
  2298  
  2299  	// call pointer
  2300  	if n.Left.Op != ONAME || n.Left.Class != PFUNC {
  2301  		var nod Node
  2302  		Regalloc(&nod, Types[Tptr], nil)
  2303  		Cgen_as(&nod, n.Left)
  2304  		nod.Type = t
  2305  		Ginscall(&nod, proc)
  2306  		Regfree(&nod)
  2307  		return
  2308  	}
  2309  
  2310  	// call direct
  2311  	n.Left.Method = true
  2312  
  2313  	Ginscall(n.Left, proc)
  2314  }
  2315  
  2316  func HasLinkRegister() bool {
  2317  	c := Ctxt.Arch.Thechar
  2318  	return c != '6' && c != '8'
  2319  }
  2320  
  2321  /*
  2322   * call to n has already been generated.
  2323   * generate:
  2324   *	res = return value from call.
  2325   */
  2326  func cgen_callret(n *Node, res *Node) {
  2327  	t := n.Left.Type
  2328  	if t.Etype == TPTR32 || t.Etype == TPTR64 {
  2329  		t = t.Type
  2330  	}
  2331  
  2332  	var flist Iter
  2333  	fp := Structfirst(&flist, Getoutarg(t))
  2334  	if fp == nil {
  2335  		Fatal("cgen_callret: nil")
  2336  	}
  2337  
  2338  	var nod Node
  2339  	nod.Op = OINDREG
  2340  	nod.Reg = int16(Thearch.REGSP)
  2341  	nod.Addable = true
  2342  
  2343  	nod.Xoffset = fp.Width
  2344  	if HasLinkRegister() {
  2345  		nod.Xoffset += int64(Ctxt.Arch.Ptrsize)
  2346  	}
  2347  	nod.Type = fp.Type
  2348  	Cgen_as(res, &nod)
  2349  }
  2350  
  2351  /*
  2352   * call to n has already been generated.
  2353   * generate:
  2354   *	res = &return value from call.
  2355   */
  2356  func cgen_aret(n *Node, res *Node) {
  2357  	t := n.Left.Type
  2358  	if Isptr[t.Etype] {
  2359  		t = t.Type
  2360  	}
  2361  
  2362  	var flist Iter
  2363  	fp := Structfirst(&flist, Getoutarg(t))
  2364  	if fp == nil {
  2365  		Fatal("cgen_aret: nil")
  2366  	}
  2367  
  2368  	var nod1 Node
  2369  	nod1.Op = OINDREG
  2370  	nod1.Reg = int16(Thearch.REGSP)
  2371  	nod1.Addable = true
  2372  	nod1.Xoffset = fp.Width
  2373  	if HasLinkRegister() {
  2374  		nod1.Xoffset += int64(Ctxt.Arch.Ptrsize)
  2375  	}
  2376  	nod1.Type = fp.Type
  2377  
  2378  	if res.Op != OREGISTER {
  2379  		var nod2 Node
  2380  		Regalloc(&nod2, Types[Tptr], res)
  2381  		Agen(&nod1, &nod2)
  2382  		Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &nod2, res)
  2383  		Regfree(&nod2)
  2384  	} else {
  2385  		Agen(&nod1, res)
  2386  	}
  2387  }
  2388  
  2389  /*
  2390   * generate return.
  2391   * n->left is assignments to return values.
  2392   */
  2393  func cgen_ret(n *Node) {
  2394  	if n != nil {
  2395  		Genlist(n.List) // copy out args
  2396  	}
  2397  	if Hasdefer != 0 {
  2398  		Ginscall(Deferreturn, 0)
  2399  	}
  2400  	Genlist(Curfn.Func.Exit)
  2401  	p := Thearch.Gins(obj.ARET, nil, nil)
  2402  	if n != nil && n.Op == ORETJMP {
  2403  		p.To.Type = obj.TYPE_MEM
  2404  		p.To.Name = obj.NAME_EXTERN
  2405  		p.To.Sym = Linksym(n.Left.Sym)
  2406  	}
  2407  }
  2408  
  2409  /*
  2410   * generate division according to op, one of:
  2411   *	res = nl / nr
  2412   *	res = nl % nr
  2413   */
  2414  func cgen_div(op int, nl *Node, nr *Node, res *Node) {
  2415  	var w int
  2416  
  2417  	// TODO(rsc): arm64 needs to support the relevant instructions
  2418  	// in peep and optoas in order to enable this.
  2419  	// TODO(rsc): ppc64 needs to support the relevant instructions
  2420  	// in peep and optoas in order to enable this.
  2421  	if nr.Op != OLITERAL || Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' {
  2422  		goto longdiv
  2423  	}
  2424  	w = int(nl.Type.Width * 8)
  2425  
  2426  	// Front end handled 32-bit division. We only need to handle 64-bit.
  2427  	// try to do division by multiply by (2^w)/d
  2428  	// see hacker's delight chapter 10
  2429  	switch Simtype[nl.Type.Etype] {
  2430  	default:
  2431  		goto longdiv
  2432  
  2433  	case TUINT64:
  2434  		var m Magic
  2435  		m.W = w
  2436  		m.Ud = uint64(Mpgetfix(nr.Val.U.Xval))
  2437  		Umagic(&m)
  2438  		if m.Bad != 0 {
  2439  			break
  2440  		}
  2441  		if op == OMOD {
  2442  			goto longmod
  2443  		}
  2444  
  2445  		var n1 Node
  2446  		Cgenr(nl, &n1, nil)
  2447  		var n2 Node
  2448  		Nodconst(&n2, nl.Type, int64(m.Um))
  2449  		var n3 Node
  2450  		Regalloc(&n3, nl.Type, res)
  2451  		Thearch.Cgen_hmul(&n1, &n2, &n3)
  2452  
  2453  		if m.Ua != 0 {
  2454  			// need to add numerator accounting for overflow
  2455  			Thearch.Gins(Thearch.Optoas(OADD, nl.Type), &n1, &n3)
  2456  
  2457  			Nodconst(&n2, nl.Type, 1)
  2458  			Thearch.Gins(Thearch.Optoas(ORROTC, nl.Type), &n2, &n3)
  2459  			Nodconst(&n2, nl.Type, int64(m.S)-1)
  2460  			Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n3)
  2461  		} else {
  2462  			Nodconst(&n2, nl.Type, int64(m.S))
  2463  			Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n3) // shift dx
  2464  		}
  2465  
  2466  		Thearch.Gmove(&n3, res)
  2467  		Regfree(&n1)
  2468  		Regfree(&n3)
  2469  		return
  2470  
  2471  	case TINT64:
  2472  		var m Magic
  2473  		m.W = w
  2474  		m.Sd = Mpgetfix(nr.Val.U.Xval)
  2475  		Smagic(&m)
  2476  		if m.Bad != 0 {
  2477  			break
  2478  		}
  2479  		if op == OMOD {
  2480  			goto longmod
  2481  		}
  2482  
  2483  		var n1 Node
  2484  		Cgenr(nl, &n1, res)
  2485  		var n2 Node
  2486  		Nodconst(&n2, nl.Type, m.Sm)
  2487  		var n3 Node
  2488  		Regalloc(&n3, nl.Type, nil)
  2489  		Thearch.Cgen_hmul(&n1, &n2, &n3)
  2490  
  2491  		if m.Sm < 0 {
  2492  			// need to add numerator
  2493  			Thearch.Gins(Thearch.Optoas(OADD, nl.Type), &n1, &n3)
  2494  		}
  2495  
  2496  		Nodconst(&n2, nl.Type, int64(m.S))
  2497  		Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n3) // shift n3
  2498  
  2499  		Nodconst(&n2, nl.Type, int64(w)-1)
  2500  
  2501  		Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n1) // -1 iff num is neg
  2502  		Thearch.Gins(Thearch.Optoas(OSUB, nl.Type), &n1, &n3) // added
  2503  
  2504  		if m.Sd < 0 {
  2505  			// this could probably be removed
  2506  			// by factoring it into the multiplier
  2507  			Thearch.Gins(Thearch.Optoas(OMINUS, nl.Type), nil, &n3)
  2508  		}
  2509  
  2510  		Thearch.Gmove(&n3, res)
  2511  		Regfree(&n1)
  2512  		Regfree(&n3)
  2513  		return
  2514  	}
  2515  
  2516  	goto longdiv
  2517  
  2518  	// division and mod using (slow) hardware instruction
  2519  longdiv:
  2520  	Thearch.Dodiv(op, nl, nr, res)
  2521  
  2522  	return
  2523  
  2524  	// mod using formula A%B = A-(A/B*B) but
  2525  	// we know that there is a fast algorithm for A/B
  2526  longmod:
  2527  	var n1 Node
  2528  	Regalloc(&n1, nl.Type, res)
  2529  
  2530  	Cgen(nl, &n1)
  2531  	var n2 Node
  2532  	Regalloc(&n2, nl.Type, nil)
  2533  	cgen_div(ODIV, &n1, nr, &n2)
  2534  	a := Thearch.Optoas(OMUL, nl.Type)
  2535  	if w == 8 {
  2536  		// use 2-operand 16-bit multiply
  2537  		// because there is no 2-operand 8-bit multiply
  2538  		a = Thearch.Optoas(OMUL, Types[TINT16]) // XXX was IMULW
  2539  	}
  2540  
  2541  	if !Smallintconst(nr) {
  2542  		var n3 Node
  2543  		Regalloc(&n3, nl.Type, nil)
  2544  		Cgen(nr, &n3)
  2545  		Thearch.Gins(a, &n3, &n2)
  2546  		Regfree(&n3)
  2547  	} else {
  2548  		Thearch.Gins(a, nr, &n2)
  2549  	}
  2550  	Thearch.Gins(Thearch.Optoas(OSUB, nl.Type), &n2, &n1)
  2551  	Thearch.Gmove(&n1, res)
  2552  	Regfree(&n1)
  2553  	Regfree(&n2)
  2554  }
  2555  
  2556  func Fixlargeoffset(n *Node) {
  2557  	if n == nil {
  2558  		return
  2559  	}
  2560  	if n.Op != OINDREG {
  2561  		return
  2562  	}
  2563  	if n.Reg == int16(Thearch.REGSP) { // stack offset cannot be large
  2564  		return
  2565  	}
  2566  	if n.Xoffset != int64(int32(n.Xoffset)) {
  2567  		// offset too large, add to register instead.
  2568  		a := *n
  2569  
  2570  		a.Op = OREGISTER
  2571  		a.Type = Types[Tptr]
  2572  		a.Xoffset = 0
  2573  		Cgen_checknil(&a)
  2574  		Thearch.Ginscon(Thearch.Optoas(OADD, Types[Tptr]), n.Xoffset, &a)
  2575  		n.Xoffset = 0
  2576  	}
  2577  }