The Go Programming Language

Text file src/cmd/8g/cgen64.c

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

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.