github.com/sean-/go@v0.0.0-20151219100004-97f854cd7bb6/src/cmd/compile/internal/mips64/gsubr.go (about)

     1  // Derived from Inferno utils/6c/txt.c
     2  // http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.c
     3  //
     4  //	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
     5  //	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
     6  //	Portions Copyright © 1997-1999 Vita Nuova Limited
     7  //	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
     8  //	Portions Copyright © 2004,2006 Bruce Ellis
     9  //	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
    10  //	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
    11  //	Portions Copyright © 2009 The Go Authors.  All rights reserved.
    12  //
    13  // Permission is hereby granted, free of charge, to any person obtaining a copy
    14  // of this software and associated documentation files (the "Software"), to deal
    15  // in the Software without restriction, including without limitation the rights
    16  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    17  // copies of the Software, and to permit persons to whom the Software is
    18  // furnished to do so, subject to the following conditions:
    19  //
    20  // The above copyright notice and this permission notice shall be included in
    21  // all copies or substantial portions of the Software.
    22  //
    23  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    24  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    25  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    26  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    27  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    28  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    29  // THE SOFTWARE.
    30  
    31  package mips64
    32  
    33  import (
    34  	"cmd/compile/internal/big"
    35  	"cmd/compile/internal/gc"
    36  	"cmd/internal/obj"
    37  	"cmd/internal/obj/mips"
    38  	"fmt"
    39  )
    40  
    41  var resvd = []int{
    42  	mips.REGZERO,
    43  	mips.REGSP,   // reserved for SP
    44  	mips.REGLINK, // reserved for link
    45  	mips.REGG,
    46  	mips.REGTMP,
    47  	mips.REG_R26, // kernel
    48  	mips.REG_R27, // kernel
    49  	mips.FREGZERO,
    50  	mips.FREGHALF,
    51  	mips.FREGONE,
    52  	mips.FREGTWO,
    53  }
    54  
    55  /*
    56   * generate
    57   *	as $c, n
    58   */
    59  func ginscon(as int, c int64, n2 *gc.Node) {
    60  	var n1 gc.Node
    61  
    62  	gc.Nodconst(&n1, gc.Types[gc.TINT64], c)
    63  
    64  	if as != mips.AMOVV && (c < -mips.BIG || c > mips.BIG) || n2.Op != gc.OREGISTER || as == mips.AMUL || as == mips.AMULU || as == mips.AMULV || as == mips.AMULVU {
    65  		// cannot have more than 16-bit of immediate in ADD, etc.
    66  		// instead, MOV into register first.
    67  		var ntmp gc.Node
    68  		gc.Regalloc(&ntmp, gc.Types[gc.TINT64], nil)
    69  
    70  		rawgins(mips.AMOVV, &n1, &ntmp)
    71  		rawgins(as, &ntmp, n2)
    72  		gc.Regfree(&ntmp)
    73  		return
    74  	}
    75  
    76  	rawgins(as, &n1, n2)
    77  }
    78  
    79  // generate branch
    80  // n1, n2 are registers
    81  func ginsbranch(as int, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
    82  	p := gc.Gbranch(as, t, likely)
    83  	gc.Naddr(&p.From, n1)
    84  	if n2 != nil {
    85  		p.Reg = n2.Reg
    86  	}
    87  	return p
    88  }
    89  
    90  func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
    91  	if !gc.Isfloat[t.Etype] && (op == gc.OLT || op == gc.OGE) {
    92  		// swap nodes to fit SGT instruction
    93  		n1, n2 = n2, n1
    94  	}
    95  	if gc.Isfloat[t.Etype] && (op == gc.OLT || op == gc.OLE) {
    96  		// swap nodes to fit CMPGT, CMPGE instructions and reverse relation
    97  		n1, n2 = n2, n1
    98  		if op == gc.OLT {
    99  			op = gc.OGT
   100  		} else {
   101  			op = gc.OGE
   102  		}
   103  	}
   104  
   105  	var r1, r2, g1, g2 gc.Node
   106  	gc.Regalloc(&r1, t, n1)
   107  	gc.Regalloc(&g1, n1.Type, &r1)
   108  	gc.Cgen(n1, &g1)
   109  	gmove(&g1, &r1)
   110  
   111  	gc.Regalloc(&r2, t, n2)
   112  	gc.Regalloc(&g2, n1.Type, &r2)
   113  	gc.Cgen(n2, &g2)
   114  	gmove(&g2, &r2)
   115  
   116  	var p *obj.Prog
   117  	var ntmp gc.Node
   118  	gc.Nodreg(&ntmp, gc.Types[gc.TINT], mips.REGTMP)
   119  
   120  	switch gc.Simtype[t.Etype] {
   121  	case gc.TINT8,
   122  		gc.TINT16,
   123  		gc.TINT32,
   124  		gc.TINT64:
   125  		if op == gc.OEQ || op == gc.ONE {
   126  			p = ginsbranch(optoas(op, t), nil, &r1, &r2, likely)
   127  		} else {
   128  			gins3(mips.ASGT, &r1, &r2, &ntmp)
   129  
   130  			p = ginsbranch(optoas(op, t), nil, &ntmp, nil, likely)
   131  		}
   132  
   133  	case gc.TBOOL,
   134  		gc.TUINT8,
   135  		gc.TUINT16,
   136  		gc.TUINT32,
   137  		gc.TUINT64,
   138  		gc.TPTR32,
   139  		gc.TPTR64:
   140  		if op == gc.OEQ || op == gc.ONE {
   141  			p = ginsbranch(optoas(op, t), nil, &r1, &r2, likely)
   142  		} else {
   143  			gins3(mips.ASGTU, &r1, &r2, &ntmp)
   144  
   145  			p = ginsbranch(optoas(op, t), nil, &ntmp, nil, likely)
   146  		}
   147  
   148  	case gc.TFLOAT32:
   149  		switch op {
   150  		default:
   151  			gc.Fatalf("ginscmp: no entry for op=%v type=%v", gc.Oconv(int(op), 0), t)
   152  
   153  		case gc.OEQ,
   154  			gc.ONE:
   155  			gins3(mips.ACMPEQF, &r1, &r2, nil)
   156  
   157  		case gc.OGE:
   158  			gins3(mips.ACMPGEF, &r1, &r2, nil)
   159  
   160  		case gc.OGT:
   161  			gins3(mips.ACMPGTF, &r1, &r2, nil)
   162  		}
   163  		p = gc.Gbranch(optoas(op, t), nil, likely)
   164  
   165  	case gc.TFLOAT64:
   166  		switch op {
   167  		default:
   168  			gc.Fatalf("ginscmp: no entry for op=%v type=%v", gc.Oconv(int(op), 0), t)
   169  
   170  		case gc.OEQ,
   171  			gc.ONE:
   172  			gins3(mips.ACMPEQD, &r1, &r2, nil)
   173  
   174  		case gc.OGE:
   175  			gins3(mips.ACMPGED, &r1, &r2, nil)
   176  
   177  		case gc.OGT:
   178  			gins3(mips.ACMPGTD, &r1, &r2, nil)
   179  		}
   180  		p = gc.Gbranch(optoas(op, t), nil, likely)
   181  	}
   182  
   183  	gc.Regfree(&g2)
   184  	gc.Regfree(&r2)
   185  	gc.Regfree(&g1)
   186  	gc.Regfree(&r1)
   187  
   188  	return p
   189  }
   190  
   191  // set up nodes representing 2^63
   192  var (
   193  	bigi         gc.Node
   194  	bigf         gc.Node
   195  	bignodes_did bool
   196  )
   197  
   198  func bignodes() {
   199  	if bignodes_did {
   200  		return
   201  	}
   202  	bignodes_did = true
   203  
   204  	var i big.Int
   205  	i.SetInt64(1)
   206  	i.Lsh(&i, 63)
   207  
   208  	gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0)
   209  	bigi.SetBigInt(&i)
   210  
   211  	bigi.Convconst(&bigf, gc.Types[gc.TFLOAT64])
   212  }
   213  
   214  /*
   215   * generate move:
   216   *	t = f
   217   * hard part is conversions.
   218   */
   219  func gmove(f *gc.Node, t *gc.Node) {
   220  	if gc.Debug['M'] != 0 {
   221  		fmt.Printf("gmove %v -> %v\n", gc.Nconv(f, obj.FmtLong), gc.Nconv(t, obj.FmtLong))
   222  	}
   223  
   224  	ft := int(gc.Simsimtype(f.Type))
   225  	tt := int(gc.Simsimtype(t.Type))
   226  	cvt := (*gc.Type)(t.Type)
   227  
   228  	if gc.Iscomplex[ft] || gc.Iscomplex[tt] {
   229  		gc.Complexmove(f, t)
   230  		return
   231  	}
   232  
   233  	// cannot have two memory operands
   234  	var r2 gc.Node
   235  	var r1 gc.Node
   236  	var a int
   237  	if gc.Ismem(f) && gc.Ismem(t) {
   238  		goto hard
   239  	}
   240  
   241  	// convert constant to desired type
   242  	if f.Op == gc.OLITERAL {
   243  		var con gc.Node
   244  		switch tt {
   245  		default:
   246  			f.Convconst(&con, t.Type)
   247  
   248  		case gc.TINT32,
   249  			gc.TINT16,
   250  			gc.TINT8:
   251  			var con gc.Node
   252  			f.Convconst(&con, gc.Types[gc.TINT64])
   253  			var r1 gc.Node
   254  			gc.Regalloc(&r1, con.Type, t)
   255  			gins(mips.AMOVV, &con, &r1)
   256  			gmove(&r1, t)
   257  			gc.Regfree(&r1)
   258  			return
   259  
   260  		case gc.TUINT32,
   261  			gc.TUINT16,
   262  			gc.TUINT8:
   263  			var con gc.Node
   264  			f.Convconst(&con, gc.Types[gc.TUINT64])
   265  			var r1 gc.Node
   266  			gc.Regalloc(&r1, con.Type, t)
   267  			gins(mips.AMOVV, &con, &r1)
   268  			gmove(&r1, t)
   269  			gc.Regfree(&r1)
   270  			return
   271  		}
   272  
   273  		f = &con
   274  		ft = tt // so big switch will choose a simple mov
   275  
   276  		// constants can't move directly to memory.
   277  		if gc.Ismem(t) {
   278  			goto hard
   279  		}
   280  	}
   281  
   282  	// value -> value copy, first operand in memory.
   283  	// any floating point operand requires register
   284  	// src, so goto hard to copy to register first.
   285  	if gc.Ismem(f) && ft != tt && (gc.Isfloat[ft] || gc.Isfloat[tt]) {
   286  		cvt = gc.Types[ft]
   287  		goto hard
   288  	}
   289  
   290  	// value -> value copy, only one memory operand.
   291  	// figure out the instruction to use.
   292  	// break out of switch for one-instruction gins.
   293  	// goto rdst for "destination must be register".
   294  	// goto hard for "convert to cvt type first".
   295  	// otherwise handle and return.
   296  
   297  	switch uint32(ft)<<16 | uint32(tt) {
   298  	default:
   299  		gc.Fatalf("gmove %v -> %v", gc.Tconv(f.Type, obj.FmtLong), gc.Tconv(t.Type, obj.FmtLong))
   300  
   301  		/*
   302  		 * integer copy and truncate
   303  		 */
   304  	case gc.TINT8<<16 | gc.TINT8, // same size
   305  		gc.TUINT8<<16 | gc.TINT8,
   306  		gc.TINT16<<16 | gc.TINT8, // truncate
   307  		gc.TUINT16<<16 | gc.TINT8,
   308  		gc.TINT32<<16 | gc.TINT8,
   309  		gc.TUINT32<<16 | gc.TINT8,
   310  		gc.TINT64<<16 | gc.TINT8,
   311  		gc.TUINT64<<16 | gc.TINT8:
   312  		a = mips.AMOVB
   313  
   314  	case gc.TINT8<<16 | gc.TUINT8, // same size
   315  		gc.TUINT8<<16 | gc.TUINT8,
   316  		gc.TINT16<<16 | gc.TUINT8, // truncate
   317  		gc.TUINT16<<16 | gc.TUINT8,
   318  		gc.TINT32<<16 | gc.TUINT8,
   319  		gc.TUINT32<<16 | gc.TUINT8,
   320  		gc.TINT64<<16 | gc.TUINT8,
   321  		gc.TUINT64<<16 | gc.TUINT8:
   322  		a = mips.AMOVBU
   323  
   324  	case gc.TINT16<<16 | gc.TINT16, // same size
   325  		gc.TUINT16<<16 | gc.TINT16,
   326  		gc.TINT32<<16 | gc.TINT16, // truncate
   327  		gc.TUINT32<<16 | gc.TINT16,
   328  		gc.TINT64<<16 | gc.TINT16,
   329  		gc.TUINT64<<16 | gc.TINT16:
   330  		a = mips.AMOVH
   331  
   332  	case gc.TINT16<<16 | gc.TUINT16, // same size
   333  		gc.TUINT16<<16 | gc.TUINT16,
   334  		gc.TINT32<<16 | gc.TUINT16, // truncate
   335  		gc.TUINT32<<16 | gc.TUINT16,
   336  		gc.TINT64<<16 | gc.TUINT16,
   337  		gc.TUINT64<<16 | gc.TUINT16:
   338  		a = mips.AMOVHU
   339  
   340  	case gc.TINT32<<16 | gc.TINT32, // same size
   341  		gc.TUINT32<<16 | gc.TINT32,
   342  		gc.TINT64<<16 | gc.TINT32, // truncate
   343  		gc.TUINT64<<16 | gc.TINT32:
   344  		a = mips.AMOVW
   345  
   346  	case gc.TINT32<<16 | gc.TUINT32, // same size
   347  		gc.TUINT32<<16 | gc.TUINT32,
   348  		gc.TINT64<<16 | gc.TUINT32, // truncate
   349  		gc.TUINT64<<16 | gc.TUINT32:
   350  		a = mips.AMOVWU
   351  
   352  	case gc.TINT64<<16 | gc.TINT64, // same size
   353  		gc.TINT64<<16 | gc.TUINT64,
   354  		gc.TUINT64<<16 | gc.TINT64,
   355  		gc.TUINT64<<16 | gc.TUINT64:
   356  		a = mips.AMOVV
   357  
   358  		/*
   359  		 * integer up-conversions
   360  		 */
   361  	case gc.TINT8<<16 | gc.TINT16, // sign extend int8
   362  		gc.TINT8<<16 | gc.TUINT16,
   363  		gc.TINT8<<16 | gc.TINT32,
   364  		gc.TINT8<<16 | gc.TUINT32,
   365  		gc.TINT8<<16 | gc.TINT64,
   366  		gc.TINT8<<16 | gc.TUINT64:
   367  		a = mips.AMOVB
   368  
   369  		goto rdst
   370  
   371  	case gc.TUINT8<<16 | gc.TINT16, // zero extend uint8
   372  		gc.TUINT8<<16 | gc.TUINT16,
   373  		gc.TUINT8<<16 | gc.TINT32,
   374  		gc.TUINT8<<16 | gc.TUINT32,
   375  		gc.TUINT8<<16 | gc.TINT64,
   376  		gc.TUINT8<<16 | gc.TUINT64:
   377  		a = mips.AMOVBU
   378  
   379  		goto rdst
   380  
   381  	case gc.TINT16<<16 | gc.TINT32, // sign extend int16
   382  		gc.TINT16<<16 | gc.TUINT32,
   383  		gc.TINT16<<16 | gc.TINT64,
   384  		gc.TINT16<<16 | gc.TUINT64:
   385  		a = mips.AMOVH
   386  
   387  		goto rdst
   388  
   389  	case gc.TUINT16<<16 | gc.TINT32, // zero extend uint16
   390  		gc.TUINT16<<16 | gc.TUINT32,
   391  		gc.TUINT16<<16 | gc.TINT64,
   392  		gc.TUINT16<<16 | gc.TUINT64:
   393  		a = mips.AMOVHU
   394  
   395  		goto rdst
   396  
   397  	case gc.TINT32<<16 | gc.TINT64, // sign extend int32
   398  		gc.TINT32<<16 | gc.TUINT64:
   399  		a = mips.AMOVW
   400  
   401  		goto rdst
   402  
   403  	case gc.TUINT32<<16 | gc.TINT64, // zero extend uint32
   404  		gc.TUINT32<<16 | gc.TUINT64:
   405  		a = mips.AMOVWU
   406  
   407  		goto rdst
   408  
   409  		//warn("gmove: convert float to int not implemented: %N -> %N\n", f, t);
   410  	//return;
   411  	// algorithm is:
   412  	//	if small enough, use native float64 -> int64 conversion.
   413  	//	otherwise, subtract 2^63, convert, and add it back.
   414  	/*
   415  	* float to integer
   416  	 */
   417  	case gc.TFLOAT32<<16 | gc.TINT32,
   418  		gc.TFLOAT64<<16 | gc.TINT32,
   419  		gc.TFLOAT32<<16 | gc.TINT64,
   420  		gc.TFLOAT64<<16 | gc.TINT64,
   421  		gc.TFLOAT32<<16 | gc.TINT16,
   422  		gc.TFLOAT32<<16 | gc.TINT8,
   423  		gc.TFLOAT32<<16 | gc.TUINT16,
   424  		gc.TFLOAT32<<16 | gc.TUINT8,
   425  		gc.TFLOAT64<<16 | gc.TINT16,
   426  		gc.TFLOAT64<<16 | gc.TINT8,
   427  		gc.TFLOAT64<<16 | gc.TUINT16,
   428  		gc.TFLOAT64<<16 | gc.TUINT8,
   429  		gc.TFLOAT32<<16 | gc.TUINT32,
   430  		gc.TFLOAT64<<16 | gc.TUINT32,
   431  		gc.TFLOAT32<<16 | gc.TUINT64,
   432  		gc.TFLOAT64<<16 | gc.TUINT64:
   433  		bignodes()
   434  
   435  		gc.Regalloc(&r1, gc.Types[gc.TFLOAT64], nil)
   436  		gmove(f, &r1)
   437  		if tt == gc.TUINT64 {
   438  			gc.Regalloc(&r2, gc.Types[gc.TFLOAT64], nil)
   439  			gmove(&bigf, &r2)
   440  			gins3(mips.ACMPGED, &r1, &r2, nil)
   441  			p1 := gc.Gbranch(mips.ABFPF, nil, 0)
   442  			gins(mips.ASUBD, &r2, &r1)
   443  			gc.Patch(p1, gc.Pc)
   444  			gc.Regfree(&r2)
   445  		}
   446  
   447  		gc.Regalloc(&r2, gc.Types[gc.TINT64], t)
   448  		gins(mips.ATRUNCDV, &r1, &r1)
   449  		gins(mips.AMOVV, &r1, &r2)
   450  		gc.Regfree(&r1)
   451  
   452  		if tt == gc.TUINT64 {
   453  			p1 := gc.Gbranch(mips.ABFPF, nil, 0) // use FCR0 here again
   454  			gc.Nodreg(&r1, gc.Types[gc.TINT64], mips.REGTMP)
   455  			gmove(&bigi, &r1)
   456  			gins(mips.AADDVU, &r1, &r2)
   457  			gc.Patch(p1, gc.Pc)
   458  		}
   459  
   460  		gmove(&r2, t)
   461  		gc.Regfree(&r2)
   462  		return
   463  
   464  		//warn("gmove: convert int to float not implemented: %N -> %N\n", f, t);
   465  	//return;
   466  	// algorithm is:
   467  	//	if small enough, use native int64 -> float64 conversion.
   468  	//	otherwise, halve (rounding to odd?), convert, and double.
   469  	/*
   470  	 * integer to float
   471  	 */
   472  	case gc.TINT32<<16 | gc.TFLOAT32,
   473  		gc.TINT32<<16 | gc.TFLOAT64,
   474  		gc.TINT64<<16 | gc.TFLOAT32,
   475  		gc.TINT64<<16 | gc.TFLOAT64,
   476  		gc.TINT16<<16 | gc.TFLOAT32,
   477  		gc.TINT16<<16 | gc.TFLOAT64,
   478  		gc.TINT8<<16 | gc.TFLOAT32,
   479  		gc.TINT8<<16 | gc.TFLOAT64,
   480  		gc.TUINT16<<16 | gc.TFLOAT32,
   481  		gc.TUINT16<<16 | gc.TFLOAT64,
   482  		gc.TUINT8<<16 | gc.TFLOAT32,
   483  		gc.TUINT8<<16 | gc.TFLOAT64,
   484  		gc.TUINT32<<16 | gc.TFLOAT32,
   485  		gc.TUINT32<<16 | gc.TFLOAT64,
   486  		gc.TUINT64<<16 | gc.TFLOAT32,
   487  		gc.TUINT64<<16 | gc.TFLOAT64:
   488  		bignodes()
   489  
   490  		var rtmp gc.Node
   491  		gc.Regalloc(&r1, gc.Types[gc.TINT64], nil)
   492  		gmove(f, &r1)
   493  		if ft == gc.TUINT64 {
   494  			gc.Nodreg(&rtmp, gc.Types[gc.TUINT64], mips.REGTMP)
   495  			gmove(&bigi, &rtmp)
   496  			gins(mips.AAND, &r1, &rtmp)
   497  			p1 := ginsbranch(mips.ABEQ, nil, &rtmp, nil, 0)
   498  			p2 := gins(mips.ASRLV, nil, &r1)
   499  			p2.From.Type = obj.TYPE_CONST
   500  			p2.From.Offset = 1
   501  			gc.Patch(p1, gc.Pc)
   502  		}
   503  
   504  		gc.Regalloc(&r2, gc.Types[gc.TFLOAT64], t)
   505  		gins(mips.AMOVV, &r1, &r2)
   506  		gins(mips.AMOVVD, &r2, &r2)
   507  		gc.Regfree(&r1)
   508  
   509  		if ft == gc.TUINT64 {
   510  			p1 := ginsbranch(mips.ABEQ, nil, &rtmp, nil, 0)
   511  			gc.Nodreg(&r1, gc.Types[gc.TFLOAT64], mips.FREGTWO)
   512  			gins(mips.AMULD, &r1, &r2)
   513  			gc.Patch(p1, gc.Pc)
   514  		}
   515  
   516  		gmove(&r2, t)
   517  		gc.Regfree(&r2)
   518  		return
   519  
   520  		/*
   521  		 * float to float
   522  		 */
   523  	case gc.TFLOAT32<<16 | gc.TFLOAT32:
   524  		a = mips.AMOVF
   525  
   526  	case gc.TFLOAT64<<16 | gc.TFLOAT64:
   527  		a = mips.AMOVD
   528  
   529  	case gc.TFLOAT32<<16 | gc.TFLOAT64:
   530  		a = mips.AMOVFD
   531  		goto rdst
   532  
   533  	case gc.TFLOAT64<<16 | gc.TFLOAT32:
   534  		a = mips.AMOVDF
   535  		goto rdst
   536  	}
   537  
   538  	gins(a, f, t)
   539  	return
   540  
   541  	// requires register destination
   542  rdst:
   543  	{
   544  		gc.Regalloc(&r1, t.Type, t)
   545  
   546  		gins(a, f, &r1)
   547  		gmove(&r1, t)
   548  		gc.Regfree(&r1)
   549  		return
   550  	}
   551  
   552  	// requires register intermediate
   553  hard:
   554  	gc.Regalloc(&r1, cvt, t)
   555  
   556  	gmove(f, &r1)
   557  	gmove(&r1, t)
   558  	gc.Regfree(&r1)
   559  	return
   560  }
   561  
   562  // gins is called by the front end.
   563  // It synthesizes some multiple-instruction sequences
   564  // so the front end can stay simpler.
   565  func gins(as int, f, t *gc.Node) *obj.Prog {
   566  	if as >= obj.A_ARCHSPECIFIC {
   567  		if x, ok := f.IntLiteral(); ok {
   568  			ginscon(as, x, t)
   569  			return nil // caller must not use
   570  		}
   571  	}
   572  	return rawgins(as, f, t)
   573  }
   574  
   575  /*
   576   * generate one instruction:
   577   *	as f, r, t
   578   * r must be register, if not nil
   579   */
   580  func gins3(as int, f, r, t *gc.Node) *obj.Prog {
   581  	p := rawgins(as, f, t)
   582  	if r != nil {
   583  		p.Reg = r.Reg
   584  	}
   585  	return p
   586  }
   587  
   588  /*
   589   * generate one instruction:
   590   *	as f, t
   591   */
   592  func rawgins(as int, f *gc.Node, t *gc.Node) *obj.Prog {
   593  	// TODO(austin): Add self-move test like in 6g (but be careful
   594  	// of truncation moves)
   595  
   596  	p := gc.Prog(as)
   597  	gc.Naddr(&p.From, f)
   598  	gc.Naddr(&p.To, t)
   599  
   600  	switch as {
   601  	case obj.ACALL:
   602  		if p.To.Type == obj.TYPE_REG {
   603  			// Allow front end to emit CALL REG, and rewrite into CALL (REG).
   604  			p.From = obj.Addr{}
   605  			p.To.Type = obj.TYPE_MEM
   606  			p.To.Offset = 0
   607  
   608  			if gc.Debug['g'] != 0 {
   609  				fmt.Printf("%v\n", p)
   610  			}
   611  
   612  			return p
   613  		}
   614  
   615  	// Bad things the front end has done to us. Crash to find call stack.
   616  	case mips.AAND:
   617  		if p.From.Type == obj.TYPE_CONST {
   618  			gc.Debug['h'] = 1
   619  			gc.Fatalf("bad inst: %v", p)
   620  		}
   621  	case mips.ASGT, mips.ASGTU:
   622  		if p.From.Type == obj.TYPE_MEM || p.To.Type == obj.TYPE_MEM {
   623  			gc.Debug['h'] = 1
   624  			gc.Fatalf("bad inst: %v", p)
   625  		}
   626  
   627  	// Special cases
   628  	case mips.AMUL, mips.AMULU, mips.AMULV, mips.AMULVU:
   629  		if p.From.Type == obj.TYPE_CONST {
   630  			gc.Debug['h'] = 1
   631  			gc.Fatalf("bad inst: %v", p)
   632  		}
   633  
   634  		pp := gc.Prog(mips.AMOVV)
   635  		pp.From.Type = obj.TYPE_REG
   636  		pp.From.Reg = mips.REG_LO
   637  		pp.To = p.To
   638  
   639  		p.Reg = p.To.Reg
   640  		p.To = obj.Addr{}
   641  
   642  	case mips.ASUBVU:
   643  		// unary
   644  		if f == nil {
   645  			p.From = p.To
   646  			p.Reg = mips.REGZERO
   647  		}
   648  	}
   649  
   650  	if gc.Debug['g'] != 0 {
   651  		fmt.Printf("%v\n", p)
   652  	}
   653  
   654  	w := int32(0)
   655  	switch as {
   656  	case mips.AMOVB,
   657  		mips.AMOVBU:
   658  		w = 1
   659  
   660  	case mips.AMOVH,
   661  		mips.AMOVHU:
   662  		w = 2
   663  
   664  	case mips.AMOVW,
   665  		mips.AMOVWU:
   666  		w = 4
   667  
   668  	case mips.AMOVV:
   669  		if p.From.Type == obj.TYPE_CONST || p.From.Type == obj.TYPE_ADDR {
   670  			break
   671  		}
   672  		w = 8
   673  	}
   674  
   675  	if w != 0 && ((f != nil && p.From.Width < int64(w)) || (t != nil && p.To.Type != obj.TYPE_REG && p.To.Width > int64(w))) {
   676  		gc.Dump("f", f)
   677  		gc.Dump("t", t)
   678  		gc.Fatalf("bad width: %v (%d, %d)\n", p, p.From.Width, p.To.Width)
   679  	}
   680  
   681  	return p
   682  }
   683  
   684  /*
   685   * return Axxx for Oxxx on type t.
   686   */
   687  func optoas(op gc.Op, t *gc.Type) int {
   688  	if t == nil {
   689  		gc.Fatalf("optoas: t is nil")
   690  	}
   691  
   692  	// avoid constant conversions in switches below
   693  	const (
   694  		OMINUS_ = uint32(gc.OMINUS) << 16
   695  		OLSH_   = uint32(gc.OLSH) << 16
   696  		ORSH_   = uint32(gc.ORSH) << 16
   697  		OADD_   = uint32(gc.OADD) << 16
   698  		OSUB_   = uint32(gc.OSUB) << 16
   699  		OMUL_   = uint32(gc.OMUL) << 16
   700  		ODIV_   = uint32(gc.ODIV) << 16
   701  		OOR_    = uint32(gc.OOR) << 16
   702  		OAND_   = uint32(gc.OAND) << 16
   703  		OXOR_   = uint32(gc.OXOR) << 16
   704  		OEQ_    = uint32(gc.OEQ) << 16
   705  		ONE_    = uint32(gc.ONE) << 16
   706  		OLT_    = uint32(gc.OLT) << 16
   707  		OLE_    = uint32(gc.OLE) << 16
   708  		OGE_    = uint32(gc.OGE) << 16
   709  		OGT_    = uint32(gc.OGT) << 16
   710  		OCMP_   = uint32(gc.OCMP) << 16
   711  		OAS_    = uint32(gc.OAS) << 16
   712  		OHMUL_  = uint32(gc.OHMUL) << 16
   713  	)
   714  
   715  	a := int(obj.AXXX)
   716  	switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
   717  	default:
   718  		gc.Fatalf("optoas: no entry for op=%v type=%v", gc.Oconv(int(op), 0), t)
   719  
   720  	case OEQ_ | gc.TBOOL,
   721  		OEQ_ | gc.TINT8,
   722  		OEQ_ | gc.TUINT8,
   723  		OEQ_ | gc.TINT16,
   724  		OEQ_ | gc.TUINT16,
   725  		OEQ_ | gc.TINT32,
   726  		OEQ_ | gc.TUINT32,
   727  		OEQ_ | gc.TINT64,
   728  		OEQ_ | gc.TUINT64,
   729  		OEQ_ | gc.TPTR32,
   730  		OEQ_ | gc.TPTR64:
   731  		a = mips.ABEQ
   732  
   733  	case OEQ_ | gc.TFLOAT32, // ACMPEQF
   734  		OEQ_ | gc.TFLOAT64: // ACMPEQD
   735  		a = mips.ABFPT
   736  
   737  	case ONE_ | gc.TBOOL,
   738  		ONE_ | gc.TINT8,
   739  		ONE_ | gc.TUINT8,
   740  		ONE_ | gc.TINT16,
   741  		ONE_ | gc.TUINT16,
   742  		ONE_ | gc.TINT32,
   743  		ONE_ | gc.TUINT32,
   744  		ONE_ | gc.TINT64,
   745  		ONE_ | gc.TUINT64,
   746  		ONE_ | gc.TPTR32,
   747  		ONE_ | gc.TPTR64:
   748  		a = mips.ABNE
   749  
   750  	case ONE_ | gc.TFLOAT32, // ACMPEQF
   751  		ONE_ | gc.TFLOAT64: // ACMPEQD
   752  		a = mips.ABFPF
   753  
   754  	case OLT_ | gc.TINT8, // ASGT
   755  		OLT_ | gc.TINT16,
   756  		OLT_ | gc.TINT32,
   757  		OLT_ | gc.TINT64,
   758  		OLT_ | gc.TUINT8, // ASGTU
   759  		OLT_ | gc.TUINT16,
   760  		OLT_ | gc.TUINT32,
   761  		OLT_ | gc.TUINT64:
   762  		a = mips.ABNE
   763  
   764  	case OLT_ | gc.TFLOAT32, // ACMPGEF
   765  		OLT_ | gc.TFLOAT64: // ACMPGED
   766  		a = mips.ABFPT
   767  
   768  	case OLE_ | gc.TINT8, // ASGT
   769  		OLE_ | gc.TINT16,
   770  		OLE_ | gc.TINT32,
   771  		OLE_ | gc.TINT64,
   772  		OLE_ | gc.TUINT8, // ASGTU
   773  		OLE_ | gc.TUINT16,
   774  		OLE_ | gc.TUINT32,
   775  		OLE_ | gc.TUINT64:
   776  		a = mips.ABEQ
   777  
   778  	case OLE_ | gc.TFLOAT32, // ACMPGTF
   779  		OLE_ | gc.TFLOAT64: // ACMPGTD
   780  		a = mips.ABFPT
   781  
   782  	case OGT_ | gc.TINT8, // ASGT
   783  		OGT_ | gc.TINT16,
   784  		OGT_ | gc.TINT32,
   785  		OGT_ | gc.TINT64,
   786  		OGT_ | gc.TUINT8, // ASGTU
   787  		OGT_ | gc.TUINT16,
   788  		OGT_ | gc.TUINT32,
   789  		OGT_ | gc.TUINT64:
   790  		a = mips.ABNE
   791  
   792  	case OGT_ | gc.TFLOAT32, // ACMPGTF
   793  		OGT_ | gc.TFLOAT64: // ACMPGTD
   794  		a = mips.ABFPT
   795  
   796  	case OGE_ | gc.TINT8, // ASGT
   797  		OGE_ | gc.TINT16,
   798  		OGE_ | gc.TINT32,
   799  		OGE_ | gc.TINT64,
   800  		OGE_ | gc.TUINT8, // ASGTU
   801  		OGE_ | gc.TUINT16,
   802  		OGE_ | gc.TUINT32,
   803  		OGE_ | gc.TUINT64:
   804  		a = mips.ABEQ
   805  
   806  	case OGE_ | gc.TFLOAT32, // ACMPGEF
   807  		OGE_ | gc.TFLOAT64: // ACMPGED
   808  		a = mips.ABFPT
   809  
   810  	case OAS_ | gc.TBOOL,
   811  		OAS_ | gc.TINT8:
   812  		a = mips.AMOVB
   813  
   814  	case OAS_ | gc.TUINT8:
   815  		a = mips.AMOVBU
   816  
   817  	case OAS_ | gc.TINT16:
   818  		a = mips.AMOVH
   819  
   820  	case OAS_ | gc.TUINT16:
   821  		a = mips.AMOVHU
   822  
   823  	case OAS_ | gc.TINT32:
   824  		a = mips.AMOVW
   825  
   826  	case OAS_ | gc.TUINT32,
   827  		OAS_ | gc.TPTR32:
   828  		a = mips.AMOVWU
   829  
   830  	case OAS_ | gc.TINT64,
   831  		OAS_ | gc.TUINT64,
   832  		OAS_ | gc.TPTR64:
   833  		a = mips.AMOVV
   834  
   835  	case OAS_ | gc.TFLOAT32:
   836  		a = mips.AMOVF
   837  
   838  	case OAS_ | gc.TFLOAT64:
   839  		a = mips.AMOVD
   840  
   841  	case OADD_ | gc.TINT8,
   842  		OADD_ | gc.TUINT8,
   843  		OADD_ | gc.TINT16,
   844  		OADD_ | gc.TUINT16,
   845  		OADD_ | gc.TINT32,
   846  		OADD_ | gc.TUINT32,
   847  		OADD_ | gc.TPTR32:
   848  		a = mips.AADDU
   849  
   850  	case OADD_ | gc.TINT64,
   851  		OADD_ | gc.TUINT64,
   852  		OADD_ | gc.TPTR64:
   853  		a = mips.AADDVU
   854  
   855  	case OADD_ | gc.TFLOAT32:
   856  		a = mips.AADDF
   857  
   858  	case OADD_ | gc.TFLOAT64:
   859  		a = mips.AADDD
   860  
   861  	case OSUB_ | gc.TINT8,
   862  		OSUB_ | gc.TUINT8,
   863  		OSUB_ | gc.TINT16,
   864  		OSUB_ | gc.TUINT16,
   865  		OSUB_ | gc.TINT32,
   866  		OSUB_ | gc.TUINT32,
   867  		OSUB_ | gc.TPTR32:
   868  		a = mips.ASUBU
   869  
   870  	case OSUB_ | gc.TINT64,
   871  		OSUB_ | gc.TUINT64,
   872  		OSUB_ | gc.TPTR64:
   873  		a = mips.ASUBVU
   874  
   875  	case OSUB_ | gc.TFLOAT32:
   876  		a = mips.ASUBF
   877  
   878  	case OSUB_ | gc.TFLOAT64:
   879  		a = mips.ASUBD
   880  
   881  	case OMINUS_ | gc.TINT8,
   882  		OMINUS_ | gc.TUINT8,
   883  		OMINUS_ | gc.TINT16,
   884  		OMINUS_ | gc.TUINT16,
   885  		OMINUS_ | gc.TINT32,
   886  		OMINUS_ | gc.TUINT32,
   887  		OMINUS_ | gc.TPTR32,
   888  		OMINUS_ | gc.TINT64,
   889  		OMINUS_ | gc.TUINT64,
   890  		OMINUS_ | gc.TPTR64:
   891  		a = mips.ASUBVU
   892  
   893  	case OAND_ | gc.TINT8,
   894  		OAND_ | gc.TUINT8,
   895  		OAND_ | gc.TINT16,
   896  		OAND_ | gc.TUINT16,
   897  		OAND_ | gc.TINT32,
   898  		OAND_ | gc.TUINT32,
   899  		OAND_ | gc.TPTR32,
   900  		OAND_ | gc.TINT64,
   901  		OAND_ | gc.TUINT64,
   902  		OAND_ | gc.TPTR64:
   903  		a = mips.AAND
   904  
   905  	case OOR_ | gc.TINT8,
   906  		OOR_ | gc.TUINT8,
   907  		OOR_ | gc.TINT16,
   908  		OOR_ | gc.TUINT16,
   909  		OOR_ | gc.TINT32,
   910  		OOR_ | gc.TUINT32,
   911  		OOR_ | gc.TPTR32,
   912  		OOR_ | gc.TINT64,
   913  		OOR_ | gc.TUINT64,
   914  		OOR_ | gc.TPTR64:
   915  		a = mips.AOR
   916  
   917  	case OXOR_ | gc.TINT8,
   918  		OXOR_ | gc.TUINT8,
   919  		OXOR_ | gc.TINT16,
   920  		OXOR_ | gc.TUINT16,
   921  		OXOR_ | gc.TINT32,
   922  		OXOR_ | gc.TUINT32,
   923  		OXOR_ | gc.TPTR32,
   924  		OXOR_ | gc.TINT64,
   925  		OXOR_ | gc.TUINT64,
   926  		OXOR_ | gc.TPTR64:
   927  		a = mips.AXOR
   928  
   929  		// TODO(minux): handle rotates
   930  	//case CASE(OLROT, TINT8):
   931  	//case CASE(OLROT, TUINT8):
   932  	//case CASE(OLROT, TINT16):
   933  	//case CASE(OLROT, TUINT16):
   934  	//case CASE(OLROT, TINT32):
   935  	//case CASE(OLROT, TUINT32):
   936  	//case CASE(OLROT, TPTR32):
   937  	//case CASE(OLROT, TINT64):
   938  	//case CASE(OLROT, TUINT64):
   939  	//case CASE(OLROT, TPTR64):
   940  	//	a = 0//???; RLDC?
   941  	//	break;
   942  
   943  	case OLSH_ | gc.TINT8,
   944  		OLSH_ | gc.TUINT8,
   945  		OLSH_ | gc.TINT16,
   946  		OLSH_ | gc.TUINT16,
   947  		OLSH_ | gc.TINT32,
   948  		OLSH_ | gc.TUINT32,
   949  		OLSH_ | gc.TPTR32,
   950  		OLSH_ | gc.TINT64,
   951  		OLSH_ | gc.TUINT64,
   952  		OLSH_ | gc.TPTR64:
   953  		a = mips.ASLLV
   954  
   955  	case ORSH_ | gc.TUINT8,
   956  		ORSH_ | gc.TUINT16,
   957  		ORSH_ | gc.TUINT32,
   958  		ORSH_ | gc.TPTR32,
   959  		ORSH_ | gc.TUINT64,
   960  		ORSH_ | gc.TPTR64:
   961  		a = mips.ASRLV
   962  
   963  	case ORSH_ | gc.TINT8,
   964  		ORSH_ | gc.TINT16,
   965  		ORSH_ | gc.TINT32,
   966  		ORSH_ | gc.TINT64:
   967  		a = mips.ASRAV
   968  
   969  		// TODO(minux): handle rotates
   970  	//case CASE(ORROTC, TINT8):
   971  	//case CASE(ORROTC, TUINT8):
   972  	//case CASE(ORROTC, TINT16):
   973  	//case CASE(ORROTC, TUINT16):
   974  	//case CASE(ORROTC, TINT32):
   975  	//case CASE(ORROTC, TUINT32):
   976  	//case CASE(ORROTC, TINT64):
   977  	//case CASE(ORROTC, TUINT64):
   978  	//	a = 0//??? RLDC??
   979  	//	break;
   980  
   981  	case OHMUL_ | gc.TINT64:
   982  		a = mips.AMULV
   983  
   984  	case OHMUL_ | gc.TUINT64,
   985  		OHMUL_ | gc.TPTR64:
   986  		a = mips.AMULVU
   987  
   988  	case OMUL_ | gc.TINT8,
   989  		OMUL_ | gc.TINT16,
   990  		OMUL_ | gc.TINT32,
   991  		OMUL_ | gc.TINT64:
   992  		a = mips.AMULV
   993  
   994  	case OMUL_ | gc.TUINT8,
   995  		OMUL_ | gc.TUINT16,
   996  		OMUL_ | gc.TUINT32,
   997  		OMUL_ | gc.TPTR32,
   998  		OMUL_ | gc.TUINT64,
   999  		OMUL_ | gc.TPTR64:
  1000  		a = mips.AMULVU
  1001  
  1002  	case OMUL_ | gc.TFLOAT32:
  1003  		a = mips.AMULF
  1004  
  1005  	case OMUL_ | gc.TFLOAT64:
  1006  		a = mips.AMULD
  1007  
  1008  	case ODIV_ | gc.TINT8,
  1009  		ODIV_ | gc.TINT16,
  1010  		ODIV_ | gc.TINT32,
  1011  		ODIV_ | gc.TINT64:
  1012  		a = mips.ADIVV
  1013  
  1014  	case ODIV_ | gc.TUINT8,
  1015  		ODIV_ | gc.TUINT16,
  1016  		ODIV_ | gc.TUINT32,
  1017  		ODIV_ | gc.TPTR32,
  1018  		ODIV_ | gc.TUINT64,
  1019  		ODIV_ | gc.TPTR64:
  1020  		a = mips.ADIVVU
  1021  
  1022  	case ODIV_ | gc.TFLOAT32:
  1023  		a = mips.ADIVF
  1024  
  1025  	case ODIV_ | gc.TFLOAT64:
  1026  		a = mips.ADIVD
  1027  	}
  1028  
  1029  	return a
  1030  }
  1031  
  1032  const (
  1033  	ODynam   = 1 << 0
  1034  	OAddable = 1 << 1
  1035  )
  1036  
  1037  func xgen(n *gc.Node, a *gc.Node, o int) bool {
  1038  	// TODO(minux)
  1039  
  1040  	return -1 != 0 /*TypeKind(100016)*/
  1041  }
  1042  
  1043  func sudoclean() {
  1044  	return
  1045  }
  1046  
  1047  /*
  1048   * generate code to compute address of n,
  1049   * a reference to a (perhaps nested) field inside
  1050   * an array or struct.
  1051   * return 0 on failure, 1 on success.
  1052   * on success, leaves usable address in a.
  1053   *
  1054   * caller is responsible for calling sudoclean
  1055   * after successful sudoaddable,
  1056   * to release the register used for a.
  1057   */
  1058  func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool {
  1059  	// TODO(minux)
  1060  
  1061  	*a = obj.Addr{}
  1062  	return false
  1063  }