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

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