github.com/euank/go@v0.0.0-20160829210321-495514729181/src/cmd/compile/internal/mips64/gsubr.go (about)

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