github.com/rsc/tmp@v0.0.0-20240517235954-6deaab19748b/bootstrap/internal/gc/zz (about)

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