github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/src/cmd/compile/internal/gc/cgen.go (about)

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