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