github.com/euank/go@v0.0.0-20160829210321-495514729181/src/cmd/compile/internal/x86/cgen64.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 x86
     6  
     7  import (
     8  	"cmd/compile/internal/gc"
     9  	"cmd/internal/obj"
    10  	"cmd/internal/obj/x86"
    11  )
    12  
    13  /*
    14   * attempt to generate 64-bit
    15   *	res = n
    16   * return 1 on success, 0 if op not handled.
    17   */
    18  func cgen64(n *gc.Node, res *gc.Node) {
    19  	if res.Op != gc.OINDREG && res.Op != gc.ONAME {
    20  		gc.Dump("n", n)
    21  		gc.Dump("res", res)
    22  		gc.Fatalf("cgen64 %v of %v", n.Op, res.Op)
    23  	}
    24  
    25  	switch n.Op {
    26  	default:
    27  		gc.Fatalf("cgen64 %v", n.Op)
    28  
    29  	case gc.OMINUS:
    30  		gc.Cgen(n.Left, res)
    31  		var hi1 gc.Node
    32  		var lo1 gc.Node
    33  		split64(res, &lo1, &hi1)
    34  		gins(x86.ANEGL, nil, &lo1)
    35  		gins(x86.AADCL, ncon(0), &hi1)
    36  		gins(x86.ANEGL, nil, &hi1)
    37  		splitclean()
    38  		return
    39  
    40  	case gc.OCOM:
    41  		gc.Cgen(n.Left, res)
    42  		var lo1 gc.Node
    43  		var hi1 gc.Node
    44  		split64(res, &lo1, &hi1)
    45  		gins(x86.ANOTL, nil, &lo1)
    46  		gins(x86.ANOTL, nil, &hi1)
    47  		splitclean()
    48  		return
    49  
    50  		// binary operators.
    51  	// common setup below.
    52  	case gc.OADD,
    53  		gc.OSUB,
    54  		gc.OMUL,
    55  		gc.OLROT,
    56  		gc.OLSH,
    57  		gc.ORSH,
    58  		gc.OAND,
    59  		gc.OOR,
    60  		gc.OXOR:
    61  		break
    62  	}
    63  
    64  	l := n.Left
    65  	r := n.Right
    66  	if !l.Addable {
    67  		var t1 gc.Node
    68  		gc.Tempname(&t1, l.Type)
    69  		gc.Cgen(l, &t1)
    70  		l = &t1
    71  	}
    72  
    73  	if r != nil && !r.Addable {
    74  		var t2 gc.Node
    75  		gc.Tempname(&t2, r.Type)
    76  		gc.Cgen(r, &t2)
    77  		r = &t2
    78  	}
    79  
    80  	var ax gc.Node
    81  	gc.Nodreg(&ax, gc.Types[gc.TINT32], x86.REG_AX)
    82  	var cx gc.Node
    83  	gc.Nodreg(&cx, gc.Types[gc.TINT32], x86.REG_CX)
    84  	var dx gc.Node
    85  	gc.Nodreg(&dx, gc.Types[gc.TINT32], x86.REG_DX)
    86  
    87  	// Setup for binary operation.
    88  	var hi1 gc.Node
    89  	var lo1 gc.Node
    90  	split64(l, &lo1, &hi1)
    91  
    92  	var lo2 gc.Node
    93  	var hi2 gc.Node
    94  	if gc.Is64(r.Type) {
    95  		split64(r, &lo2, &hi2)
    96  	}
    97  
    98  	// Do op. Leave result in DX:AX.
    99  	switch n.Op {
   100  	// TODO: Constants
   101  	case gc.OADD:
   102  		gins(x86.AMOVL, &lo1, &ax)
   103  
   104  		gins(x86.AMOVL, &hi1, &dx)
   105  		gins(x86.AADDL, &lo2, &ax)
   106  		gins(x86.AADCL, &hi2, &dx)
   107  
   108  		// TODO: Constants.
   109  	case gc.OSUB:
   110  		gins(x86.AMOVL, &lo1, &ax)
   111  
   112  		gins(x86.AMOVL, &hi1, &dx)
   113  		gins(x86.ASUBL, &lo2, &ax)
   114  		gins(x86.ASBBL, &hi2, &dx)
   115  
   116  	case gc.OMUL:
   117  		// let's call the next three EX, FX and GX
   118  		var ex, fx, gx gc.Node
   119  		gc.Regalloc(&ex, gc.Types[gc.TPTR32], nil)
   120  		gc.Regalloc(&fx, gc.Types[gc.TPTR32], nil)
   121  		gc.Regalloc(&gx, gc.Types[gc.TPTR32], nil)
   122  
   123  		// load args into DX:AX and EX:GX.
   124  		gins(x86.AMOVL, &lo1, &ax)
   125  
   126  		gins(x86.AMOVL, &hi1, &dx)
   127  		gins(x86.AMOVL, &lo2, &gx)
   128  		gins(x86.AMOVL, &hi2, &ex)
   129  
   130  		// if DX and EX are zero, use 32 x 32 -> 64 unsigned multiply.
   131  		gins(x86.AMOVL, &dx, &fx)
   132  
   133  		gins(x86.AORL, &ex, &fx)
   134  		p1 := gc.Gbranch(x86.AJNE, nil, 0)
   135  		gins(x86.AMULL, &gx, nil) // implicit &ax
   136  		p2 := gc.Gbranch(obj.AJMP, nil, 0)
   137  		gc.Patch(p1, gc.Pc)
   138  
   139  		// full 64x64 -> 64, from 32x32 -> 64.
   140  		gins(x86.AIMULL, &gx, &dx)
   141  
   142  		gins(x86.AMOVL, &ax, &fx)
   143  		gins(x86.AIMULL, &ex, &fx)
   144  		gins(x86.AADDL, &dx, &fx)
   145  		gins(x86.AMOVL, &gx, &dx)
   146  		gins(x86.AMULL, &dx, nil) // implicit &ax
   147  		gins(x86.AADDL, &fx, &dx)
   148  		gc.Patch(p2, gc.Pc)
   149  
   150  		gc.Regfree(&ex)
   151  		gc.Regfree(&fx)
   152  		gc.Regfree(&gx)
   153  
   154  	// We only rotate by a constant c in [0,64).
   155  	// if c >= 32:
   156  	//	lo, hi = hi, lo
   157  	//	c -= 32
   158  	// if c == 0:
   159  	//	no-op
   160  	// else:
   161  	//	t = hi
   162  	//	shld hi:lo, c
   163  	//	shld lo:t, c
   164  	case gc.OLROT:
   165  		v := uint64(r.Int64())
   166  
   167  		if v >= 32 {
   168  			// reverse during load to do the first 32 bits of rotate
   169  			v -= 32
   170  
   171  			gins(x86.AMOVL, &lo1, &dx)
   172  			gins(x86.AMOVL, &hi1, &ax)
   173  		} else {
   174  			gins(x86.AMOVL, &lo1, &ax)
   175  			gins(x86.AMOVL, &hi1, &dx)
   176  		}
   177  
   178  		if v == 0 {
   179  		} else // done
   180  		{
   181  			gins(x86.AMOVL, &dx, &cx)
   182  			p1 := gins(x86.ASHLL, ncon(uint32(v)), &dx)
   183  			p1.From.Index = x86.REG_AX // double-width shift
   184  			p1.From.Scale = 0
   185  			p1 = gins(x86.ASHLL, ncon(uint32(v)), &ax)
   186  			p1.From.Index = x86.REG_CX // double-width shift
   187  			p1.From.Scale = 0
   188  		}
   189  
   190  	case gc.OLSH:
   191  		if r.Op == gc.OLITERAL {
   192  			v := uint64(r.Int64())
   193  			if v >= 64 {
   194  				if gc.Is64(r.Type) {
   195  					splitclean()
   196  				}
   197  				splitclean()
   198  				split64(res, &lo2, &hi2)
   199  				gins(x86.AMOVL, ncon(0), &lo2)
   200  				gins(x86.AMOVL, ncon(0), &hi2)
   201  				splitclean()
   202  				return
   203  			}
   204  
   205  			if v >= 32 {
   206  				if gc.Is64(r.Type) {
   207  					splitclean()
   208  				}
   209  				split64(res, &lo2, &hi2)
   210  				gmove(&lo1, &hi2)
   211  				if v > 32 {
   212  					gins(x86.ASHLL, ncon(uint32(v-32)), &hi2)
   213  				}
   214  
   215  				gins(x86.AMOVL, ncon(0), &lo2)
   216  				splitclean()
   217  				splitclean()
   218  				return
   219  			}
   220  
   221  			// general shift
   222  			gins(x86.AMOVL, &lo1, &ax)
   223  
   224  			gins(x86.AMOVL, &hi1, &dx)
   225  			p1 := gins(x86.ASHLL, ncon(uint32(v)), &dx)
   226  			p1.From.Index = x86.REG_AX // double-width shift
   227  			p1.From.Scale = 0
   228  			gins(x86.ASHLL, ncon(uint32(v)), &ax)
   229  			break
   230  		}
   231  
   232  		// load value into DX:AX.
   233  		gins(x86.AMOVL, &lo1, &ax)
   234  
   235  		gins(x86.AMOVL, &hi1, &dx)
   236  
   237  		// load shift value into register.
   238  		// if high bits are set, zero value.
   239  		var p1 *obj.Prog
   240  
   241  		if gc.Is64(r.Type) {
   242  			gins(x86.ACMPL, &hi2, ncon(0))
   243  			p1 = gc.Gbranch(x86.AJNE, nil, +1)
   244  			gins(x86.AMOVL, &lo2, &cx)
   245  		} else {
   246  			cx.Type = gc.Types[gc.TUINT32]
   247  			gmove(r, &cx)
   248  		}
   249  
   250  		// if shift count is >=64, zero value
   251  		gins(x86.ACMPL, &cx, ncon(64))
   252  
   253  		p2 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1)
   254  		if p1 != nil {
   255  			gc.Patch(p1, gc.Pc)
   256  		}
   257  		gins(x86.AXORL, &dx, &dx)
   258  		gins(x86.AXORL, &ax, &ax)
   259  		gc.Patch(p2, gc.Pc)
   260  
   261  		// if shift count is >= 32, zero low.
   262  		gins(x86.ACMPL, &cx, ncon(32))
   263  
   264  		p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1)
   265  		gins(x86.AMOVL, &ax, &dx)
   266  		gins(x86.ASHLL, &cx, &dx) // SHLL only uses bottom 5 bits of count
   267  		gins(x86.AXORL, &ax, &ax)
   268  		p2 = gc.Gbranch(obj.AJMP, nil, 0)
   269  		gc.Patch(p1, gc.Pc)
   270  
   271  		// general shift
   272  		p1 = gins(x86.ASHLL, &cx, &dx)
   273  
   274  		p1.From.Index = x86.REG_AX // double-width shift
   275  		p1.From.Scale = 0
   276  		gins(x86.ASHLL, &cx, &ax)
   277  		gc.Patch(p2, gc.Pc)
   278  
   279  	case gc.ORSH:
   280  		if r.Op == gc.OLITERAL {
   281  			v := uint64(r.Int64())
   282  			if v >= 64 {
   283  				if gc.Is64(r.Type) {
   284  					splitclean()
   285  				}
   286  				splitclean()
   287  				split64(res, &lo2, &hi2)
   288  				if hi1.Type.Etype == gc.TINT32 {
   289  					gmove(&hi1, &lo2)
   290  					gins(x86.ASARL, ncon(31), &lo2)
   291  					gmove(&hi1, &hi2)
   292  					gins(x86.ASARL, ncon(31), &hi2)
   293  				} else {
   294  					gins(x86.AMOVL, ncon(0), &lo2)
   295  					gins(x86.AMOVL, ncon(0), &hi2)
   296  				}
   297  
   298  				splitclean()
   299  				return
   300  			}
   301  
   302  			if v >= 32 {
   303  				if gc.Is64(r.Type) {
   304  					splitclean()
   305  				}
   306  				split64(res, &lo2, &hi2)
   307  				gmove(&hi1, &lo2)
   308  				if v > 32 {
   309  					gins(optoas(gc.ORSH, hi1.Type), ncon(uint32(v-32)), &lo2)
   310  				}
   311  				if hi1.Type.Etype == gc.TINT32 {
   312  					gmove(&hi1, &hi2)
   313  					gins(x86.ASARL, ncon(31), &hi2)
   314  				} else {
   315  					gins(x86.AMOVL, ncon(0), &hi2)
   316  				}
   317  				splitclean()
   318  				splitclean()
   319  				return
   320  			}
   321  
   322  			// general shift
   323  			gins(x86.AMOVL, &lo1, &ax)
   324  
   325  			gins(x86.AMOVL, &hi1, &dx)
   326  			p1 := gins(x86.ASHRL, ncon(uint32(v)), &ax)
   327  			p1.From.Index = x86.REG_DX // double-width shift
   328  			p1.From.Scale = 0
   329  			gins(optoas(gc.ORSH, hi1.Type), ncon(uint32(v)), &dx)
   330  			break
   331  		}
   332  
   333  		// load value into DX:AX.
   334  		gins(x86.AMOVL, &lo1, &ax)
   335  
   336  		gins(x86.AMOVL, &hi1, &dx)
   337  
   338  		// load shift value into register.
   339  		// if high bits are set, zero value.
   340  		var p1 *obj.Prog
   341  
   342  		if gc.Is64(r.Type) {
   343  			gins(x86.ACMPL, &hi2, ncon(0))
   344  			p1 = gc.Gbranch(x86.AJNE, nil, +1)
   345  			gins(x86.AMOVL, &lo2, &cx)
   346  		} else {
   347  			cx.Type = gc.Types[gc.TUINT32]
   348  			gmove(r, &cx)
   349  		}
   350  
   351  		// if shift count is >=64, zero or sign-extend value
   352  		gins(x86.ACMPL, &cx, ncon(64))
   353  
   354  		p2 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1)
   355  		if p1 != nil {
   356  			gc.Patch(p1, gc.Pc)
   357  		}
   358  		if hi1.Type.Etype == gc.TINT32 {
   359  			gins(x86.ASARL, ncon(31), &dx)
   360  			gins(x86.AMOVL, &dx, &ax)
   361  		} else {
   362  			gins(x86.AXORL, &dx, &dx)
   363  			gins(x86.AXORL, &ax, &ax)
   364  		}
   365  
   366  		gc.Patch(p2, gc.Pc)
   367  
   368  		// if shift count is >= 32, sign-extend hi.
   369  		gins(x86.ACMPL, &cx, ncon(32))
   370  
   371  		p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1)
   372  		gins(x86.AMOVL, &dx, &ax)
   373  		if hi1.Type.Etype == gc.TINT32 {
   374  			gins(x86.ASARL, &cx, &ax) // SARL only uses bottom 5 bits of count
   375  			gins(x86.ASARL, ncon(31), &dx)
   376  		} else {
   377  			gins(x86.ASHRL, &cx, &ax)
   378  			gins(x86.AXORL, &dx, &dx)
   379  		}
   380  
   381  		p2 = gc.Gbranch(obj.AJMP, nil, 0)
   382  		gc.Patch(p1, gc.Pc)
   383  
   384  		// general shift
   385  		p1 = gins(x86.ASHRL, &cx, &ax)
   386  
   387  		p1.From.Index = x86.REG_DX // double-width shift
   388  		p1.From.Scale = 0
   389  		gins(optoas(gc.ORSH, hi1.Type), &cx, &dx)
   390  		gc.Patch(p2, gc.Pc)
   391  
   392  		// make constant the right side (it usually is anyway).
   393  	case gc.OXOR,
   394  		gc.OAND,
   395  		gc.OOR:
   396  		if lo1.Op == gc.OLITERAL {
   397  			nswap(&lo1, &lo2)
   398  			nswap(&hi1, &hi2)
   399  		}
   400  
   401  		if lo2.Op == gc.OLITERAL {
   402  			// special cases for constants.
   403  			lv := uint32(lo2.Int64())
   404  			hv := uint32(hi2.Int64())
   405  			splitclean() // right side
   406  			split64(res, &lo2, &hi2)
   407  			switch n.Op {
   408  			case gc.OXOR:
   409  				gmove(&lo1, &lo2)
   410  				gmove(&hi1, &hi2)
   411  				switch lv {
   412  				case 0:
   413  					break
   414  
   415  				case 0xffffffff:
   416  					gins(x86.ANOTL, nil, &lo2)
   417  
   418  				default:
   419  					gins(x86.AXORL, ncon(lv), &lo2)
   420  				}
   421  
   422  				switch hv {
   423  				case 0:
   424  					break
   425  
   426  				case 0xffffffff:
   427  					gins(x86.ANOTL, nil, &hi2)
   428  
   429  				default:
   430  					gins(x86.AXORL, ncon(hv), &hi2)
   431  				}
   432  
   433  			case gc.OAND:
   434  				switch lv {
   435  				case 0:
   436  					gins(x86.AMOVL, ncon(0), &lo2)
   437  
   438  				default:
   439  					gmove(&lo1, &lo2)
   440  					if lv != 0xffffffff {
   441  						gins(x86.AANDL, ncon(lv), &lo2)
   442  					}
   443  				}
   444  
   445  				switch hv {
   446  				case 0:
   447  					gins(x86.AMOVL, ncon(0), &hi2)
   448  
   449  				default:
   450  					gmove(&hi1, &hi2)
   451  					if hv != 0xffffffff {
   452  						gins(x86.AANDL, ncon(hv), &hi2)
   453  					}
   454  				}
   455  
   456  			case gc.OOR:
   457  				switch lv {
   458  				case 0:
   459  					gmove(&lo1, &lo2)
   460  
   461  				case 0xffffffff:
   462  					gins(x86.AMOVL, ncon(0xffffffff), &lo2)
   463  
   464  				default:
   465  					gmove(&lo1, &lo2)
   466  					gins(x86.AORL, ncon(lv), &lo2)
   467  				}
   468  
   469  				switch hv {
   470  				case 0:
   471  					gmove(&hi1, &hi2)
   472  
   473  				case 0xffffffff:
   474  					gins(x86.AMOVL, ncon(0xffffffff), &hi2)
   475  
   476  				default:
   477  					gmove(&hi1, &hi2)
   478  					gins(x86.AORL, ncon(hv), &hi2)
   479  				}
   480  			}
   481  
   482  			splitclean()
   483  			splitclean()
   484  			return
   485  		}
   486  
   487  		gins(x86.AMOVL, &lo1, &ax)
   488  		gins(x86.AMOVL, &hi1, &dx)
   489  		gins(optoas(n.Op, lo1.Type), &lo2, &ax)
   490  		gins(optoas(n.Op, lo1.Type), &hi2, &dx)
   491  	}
   492  
   493  	if gc.Is64(r.Type) {
   494  		splitclean()
   495  	}
   496  	splitclean()
   497  
   498  	split64(res, &lo1, &hi1)
   499  	gins(x86.AMOVL, &ax, &lo1)
   500  	gins(x86.AMOVL, &dx, &hi1)
   501  	splitclean()
   502  }
   503  
   504  /*
   505   * generate comparison of nl, nr, both 64-bit.
   506   * nl is memory; nr is constant or memory.
   507   */
   508  func cmp64(nl *gc.Node, nr *gc.Node, op gc.Op, likely int, to *obj.Prog) {
   509  	var lo1 gc.Node
   510  	var hi1 gc.Node
   511  	var lo2 gc.Node
   512  	var hi2 gc.Node
   513  	var rr gc.Node
   514  
   515  	split64(nl, &lo1, &hi1)
   516  	split64(nr, &lo2, &hi2)
   517  
   518  	// compare most significant word;
   519  	// if they differ, we're done.
   520  	t := hi1.Type
   521  
   522  	if nl.Op == gc.OLITERAL || nr.Op == gc.OLITERAL {
   523  		gins(x86.ACMPL, &hi1, &hi2)
   524  	} else {
   525  		gc.Regalloc(&rr, gc.Types[gc.TINT32], nil)
   526  		gins(x86.AMOVL, &hi1, &rr)
   527  		gins(x86.ACMPL, &rr, &hi2)
   528  		gc.Regfree(&rr)
   529  	}
   530  
   531  	var br *obj.Prog
   532  	switch op {
   533  	default:
   534  		gc.Fatalf("cmp64 %v %v", op, t)
   535  
   536  		// cmp hi
   537  	// jne L
   538  	// cmp lo
   539  	// jeq to
   540  	// L:
   541  	case gc.OEQ:
   542  		br = gc.Gbranch(x86.AJNE, nil, -likely)
   543  
   544  		// cmp hi
   545  	// jne to
   546  	// cmp lo
   547  	// jne to
   548  	case gc.ONE:
   549  		gc.Patch(gc.Gbranch(x86.AJNE, nil, likely), to)
   550  
   551  		// cmp hi
   552  	// jgt to
   553  	// jlt L
   554  	// cmp lo
   555  	// jge to (or jgt to)
   556  	// L:
   557  	case gc.OGE,
   558  		gc.OGT:
   559  		gc.Patch(gc.Gbranch(optoas(gc.OGT, t), nil, likely), to)
   560  
   561  		br = gc.Gbranch(optoas(gc.OLT, t), nil, -likely)
   562  
   563  		// cmp hi
   564  	// jlt to
   565  	// jgt L
   566  	// cmp lo
   567  	// jle to (or jlt to)
   568  	// L:
   569  	case gc.OLE,
   570  		gc.OLT:
   571  		gc.Patch(gc.Gbranch(optoas(gc.OLT, t), nil, likely), to)
   572  
   573  		br = gc.Gbranch(optoas(gc.OGT, t), nil, -likely)
   574  	}
   575  
   576  	// compare least significant word
   577  	t = lo1.Type
   578  
   579  	if nl.Op == gc.OLITERAL || nr.Op == gc.OLITERAL {
   580  		gins(x86.ACMPL, &lo1, &lo2)
   581  	} else {
   582  		gc.Regalloc(&rr, gc.Types[gc.TINT32], nil)
   583  		gins(x86.AMOVL, &lo1, &rr)
   584  		gins(x86.ACMPL, &rr, &lo2)
   585  		gc.Regfree(&rr)
   586  	}
   587  
   588  	// jump again
   589  	gc.Patch(gc.Gbranch(optoas(op, t), nil, likely), to)
   590  
   591  	// point first branch down here if appropriate
   592  	if br != nil {
   593  		gc.Patch(br, gc.Pc)
   594  	}
   595  
   596  	splitclean()
   597  	splitclean()
   598  }