xref: /netbsd/external/bsd/pcc/dist/pcc/arch/amd64/code.c (revision 6550d01e)
1 /*	Id: code.c,v 1.22 2010/05/30 19:00:04 ragge Exp 	*/
2 /*	$NetBSD: code.c,v 1.1.1.2 2010/06/03 18:57:07 plunky Exp $	*/
3 /*
4  * Copyright (c) 2008 Michael Shalayeff
5  * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 
32 # include "pass1.h"
33 
34 static int nsse, ngpr, nrsp, rsaoff;
35 static int thissse, thisgpr, thisrsp;
36 enum { INTEGER = 1, INTMEM, SSE, SSEMEM, X87, STRREG, STRMEM };
37 static const int argregsi[] = { RDI, RSI, RDX, RCX, R08, R09 };
38 /*
39  * The Register Save Area looks something like this.
40  * It is put first on stack with fixed offsets.
41  * struct {
42  *	long regs[6];
43  *	double xmm[8][2]; // 16 byte in width
44  * };
45  */
46 #define	RSASZ		(6*SZLONG+8*2*SZDOUBLE)
47 #define	RSALONGOFF(x)	(RSASZ-(x)*SZLONG)
48 #define	RSADBLOFF(x)	((8*2*SZDOUBLE)-(x)*SZDOUBLE*2)
49 /* va_list */
50 #define	VAARGSZ		(SZINT*2+SZPOINT(CHAR)*2)
51 #define	VAGPOFF(x)	(x)
52 #define	VAFPOFF(x)	(x-SZINT)
53 #define	VAOFA(x)	(x-SZINT-SZINT)
54 #define	VARSA(x)	(x-SZINT-SZINT-SZPOINT(0))
55 
56 int lastloc = -1;
57 static int stroffset;
58 
59 static int argtyp(TWORD t, union dimfun *df, struct suedef *sue);
60 static NODE *movtomem(NODE *p, int off, int reg);
61 static NODE *movtoreg(NODE *p, int rno);
62 
63 /*
64  * Define everything needed to print out some data (or text).
65  * This means segment, alignment, visibility, etc.
66  */
67 void
68 defloc(struct symtab *sp)
69 {
70 	extern char *nextsect;
71 	static char *loctbl[] = { "text", "data", "section .rodata" };
72 	int weak = 0;
73 	char *name;
74 	TWORD t;
75 	int s;
76 
77 	if (sp == NULL) {
78 		lastloc = -1;
79 		return;
80 	}
81 	t = sp->stype;
82 	s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? RDATA : DATA;
83 	if ((name = sp->soname) == NULL)
84 		name = exname(sp->sname);
85 #ifdef TLS
86 	if (sp->sflags & STLS) {
87 		if (s != DATA)
88 			cerror("non-data symbol in tls section");
89 		nextsect = ".tdata";
90 	}
91 #endif
92 #ifdef GCC_COMPAT
93 	{
94 		struct gcc_attrib *ga;
95 
96 		if ((ga = gcc_get_attr(sp->ssue, GCC_ATYP_SECTION)) != NULL)
97 			nextsect = ga->a1.sarg;
98 		if ((ga = gcc_get_attr(sp->ssue, GCC_ATYP_WEAK)) != NULL)
99 			weak = 1;
100 		if (gcc_get_attr(sp->ssue, GCC_ATYP_DESTRUCTOR)) {
101 			printf("\t.section\t.dtors,\"aw\",@progbits\n");
102 			printf("\t.align 8\n\t.quad\t%s\n", name);
103 			lastloc = -1;
104 		}
105 		if (gcc_get_attr(sp->ssue, GCC_ATYP_CONSTRUCTOR)) {
106 			printf("\t.section\t.ctors,\"aw\",@progbits\n");
107 			printf("\t.align 8\n\t.quad\t%s\n", name);
108 			lastloc = -1;
109 		}
110 		if ((ga = gcc_get_attr(sp->ssue, GCC_ATYP_VISIBILITY)) &&
111 		    strcmp(ga->a1.sarg, "default"))
112 			printf("\t.%s %s\n", ga->a1.sarg, name);
113 	}
114 #endif
115 
116 	if (nextsect) {
117 		printf("	.section %s\n", nextsect);
118 		nextsect = NULL;
119 		s = -1;
120 	} else if (s != lastloc)
121 		printf("	.%s\n", loctbl[s]);
122 	lastloc = s;
123 	while (ISARY(t))
124 		t = DECREF(t);
125 	s = ISFTN(t) ? ALINT : talign(t, sp->ssue);
126 	if (s > ALCHAR)
127 		printf("	.align %d\n", s/ALCHAR);
128 	if (weak)
129 		printf("        .weak %s\n", name);
130 	else if (sp->sclass == EXTDEF) {
131 		printf("\t.globl %s\n", name);
132 		printf("\t.type %s,@%s\n", name,
133 		    ISFTN(t)? "function" : "object");
134 	}
135 	if (sp->slevel == 0)
136 		printf("%s:\n", name);
137 	else
138 		printf(LABFMT ":\n", sp->soffset);
139 }
140 
141 /*
142  * code for the end of a function
143  * deals with struct return here
144  */
145 void
146 efcode()
147 {
148 	struct symtab *sp;
149 	extern int gotnr;
150 	TWORD t;
151 	NODE *p, *r, *l;
152 	int o;
153 
154 	gotnr = 0;	/* new number for next fun */
155 	sp = cftnsp;
156 	t = DECREF(sp->stype);
157 	if (t != STRTY && t != UNIONTY)
158 		return;
159 	if (argtyp(t, sp->sdf, sp->ssue) != STRMEM)
160 		return;
161 
162 	/* call memcpy() to put return struct at destination */
163 #define  cmop(x,y) block(CM, x, y, INT, 0, MKSUE(INT))
164 	r = tempnode(stroffset, INCREF(t), sp->sdf, sp->ssue);
165 	l = block(REG, NIL, NIL, INCREF(t), sp->sdf, sp->ssue);
166 	regno(l) = RAX;
167 	o = tsize(t, sp->sdf, sp->ssue)/SZCHAR;
168 	r = cmop(cmop(r, l), bcon(o));
169 
170 	blevel++; /* Remove prototype at exit of function */
171 	sp = lookup(addname("memcpy"), 0);
172 	if (sp->stype == UNDEF) {
173 		sp->ssue = MKSUE(VOID);
174 		p = talloc();
175 		p->n_op = NAME;
176 		p->n_sp = sp;
177 		p->n_sue = sp->ssue;
178 		p->n_type = VOID|FTN|(PTR<<TSHIFT);
179 		defid(p, EXTERN);
180 		nfree(p);
181 	}
182 	blevel--;
183 
184 	p = doacall(sp, nametree(sp), r);
185 	ecomp(p);
186 
187 
188 	/* RAX contains destination after memcpy() */
189 }
190 
191 /*
192  * code for the beginning of a function; a is an array of
193  * indices in symtab for the arguments; n is the number
194  */
195 void
196 bfcode(struct symtab **s, int cnt)
197 {
198 	union arglist *al;
199 	struct symtab *sp;
200 	NODE *p, *r;
201 	int i, rno, typ;
202 
203 	/* recalculate the arg offset and create TEMP moves */
204 	/* Always do this for reg, even if not optimizing, to free arg regs */
205 	nsse = ngpr = 0;
206 	nrsp = ARGINIT;
207 	if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
208 		sp = cftnsp;
209 		if (argtyp(DECREF(sp->stype), sp->sdf, sp->ssue) == STRMEM) {
210 			r = block(REG, NIL, NIL, LONG, 0, MKSUE(LONG));
211 			regno(r) = argregsi[ngpr++];
212 			p = tempnode(0, r->n_type, r->n_df, r->n_sue);
213 			stroffset = regno(p);
214 			ecomp(buildtree(ASSIGN, p, r));
215 		}
216 	}
217 
218 	for (i = 0; i < cnt; i++) {
219 		sp = s[i];
220 
221 		if (sp == NULL)
222 			continue; /* XXX when happens this? */
223 
224 		switch (typ = argtyp(sp->stype, sp->sdf, sp->ssue)) {
225 		case INTEGER:
226 		case SSE:
227 			if (typ == SSE)
228 				rno = XMM0 + nsse++;
229 			else
230 				rno = argregsi[ngpr++];
231 			r = block(REG, NIL, NIL, sp->stype, sp->sdf, sp->ssue);
232 			regno(r) = rno;
233 			p = tempnode(0, sp->stype, sp->sdf, sp->ssue);
234 			sp->soffset = regno(p);
235 			sp->sflags |= STNODE;
236 			ecomp(buildtree(ASSIGN, p, r));
237 			break;
238 
239 		case INTMEM:
240 			sp->soffset = nrsp;
241 			nrsp += SZLONG;
242 			if (xtemps) {
243 				p = tempnode(0, sp->stype, sp->sdf, sp->ssue);
244 				p = buildtree(ASSIGN, p, nametree(sp));
245 				sp->soffset = regno(p->n_left);
246 				sp->sflags |= STNODE;
247 				ecomp(p);
248 			}
249 			break;
250 
251 		case STRMEM: /* Struct in memory */
252 			sp->soffset = nrsp;
253 			nrsp += tsize(sp->stype, sp->sdf, sp->ssue);
254 			break;
255 
256 		case STRREG: /* Struct in register */
257 			/* Allocate space on stack for the struct */
258 			/* For simplicity always fetch two longwords */
259 			autooff += (2*SZLONG);
260 
261 			r = block(REG, NIL, NIL, LONG, 0, MKSUE(LONG));
262 			regno(r) = argregsi[ngpr++];
263 			ecomp(movtomem(r, -autooff, FPREG));
264 
265 			if (tsize(sp->stype, sp->sdf, sp->ssue) > SZLONG) {
266 				r = block(REG, NIL, NIL, LONG, 0, MKSUE(LONG));
267 				regno(r) = argregsi[ngpr++];
268 				ecomp(movtomem(r, -autooff+SZLONG, FPREG));
269 			}
270 
271 			sp->soffset = -autooff;
272 			break;
273 
274 		default:
275 			cerror("bfcode: %d", typ);
276 		}
277 	}
278 
279 	/* Check if there are varargs */
280 	if (cftnsp->sdf == NULL || cftnsp->sdf->dfun == NULL)
281 		return; /* no prototype */
282 	al = cftnsp->sdf->dfun;
283 
284 	for (; al->type != TELLIPSIS; al++) {
285 		if (al->type == TNULL)
286 			return;
287 		if (BTYPE(al->type) == STRTY || BTYPE(al->type) == UNIONTY ||
288 		    ISARY(al->type))
289 			al++;
290 	}
291 
292 	/* fix stack offset */
293 	SETOFF(autooff, ALMAX);
294 
295 	/* Save reg arguments in the reg save area */
296 	p = NIL;
297 	for (i = ngpr; i < 6; i++) {
298 		r = block(REG, NIL, NIL, LONG, 0, MKSUE(LONG));
299 		regno(r) = argregsi[i];
300 		r = movtomem(r, -RSALONGOFF(i)-autooff, FPREG);
301 		p = (p == NIL ? r : block(COMOP, p, r, INT, 0, MKSUE(INT)));
302 	}
303 	for (i = nsse; i < 8; i++) {
304 		r = block(REG, NIL, NIL, DOUBLE, 0, MKSUE(DOUBLE));
305 		regno(r) = i + XMM0;
306 		r = movtomem(r, -RSADBLOFF(i)-autooff, FPREG);
307 		p = (p == NIL ? r : block(COMOP, p, r, INT, 0, MKSUE(INT)));
308 	}
309 	autooff += RSASZ;
310 	rsaoff = autooff;
311 	thissse = nsse;
312 	thisgpr = ngpr;
313 	thisrsp = nrsp;
314 
315 	ecomp(p);
316 }
317 
318 
319 /*
320  * by now, the automatics and register variables are allocated
321  */
322 void
323 bccode()
324 {
325 	SETOFF(autooff, SZINT);
326 }
327 
328 /* called just before final exit */
329 /* flag is 1 if errors, 0 if none */
330 void
331 ejobcode(int flag )
332 {
333 #define _MKSTR(x) #x
334 #define MKSTR(x) _MKSTR(x)
335 #define OS MKSTR(TARGOS)
336         printf("\t.ident \"PCC: %s (%s)\"\n\t.end\n", PACKAGE_STRING, OS);
337 }
338 
339 /*
340  * Varargs stuff:
341  * The ABI says that va_list should be declared as this typedef.
342  * We handcraft it here and then just reference it.
343  *
344  * typedef struct {
345  *	unsigned int gp_offset;
346  *	unsigned int fp_offset;
347  *	void *overflow_arg_area;
348  *	void *reg_save_area;
349  * } __builtin_va_list[1];
350  */
351 
352 static char *gp_offset, *fp_offset, *overflow_arg_area, *reg_save_area;
353 
354 void
355 bjobcode()
356 {
357 	struct rstack *rp;
358 	NODE *p, *q;
359 	char *c;
360 
361 	gp_offset = addname("gp_offset");
362 	fp_offset = addname("fp_offset");
363 	overflow_arg_area = addname("overflow_arg_area");
364 	reg_save_area = addname("reg_save_area");
365 
366 	rp = bstruct(NULL, STNAME, NULL);
367 	p = block(NAME, NIL, NIL, UNSIGNED, 0, MKSUE(UNSIGNED));
368 	soumemb(p, gp_offset, 0);
369 	soumemb(p, fp_offset, 0);
370 	p->n_type = VOID+PTR;
371 	p->n_sue = MKSUE(VOID);
372 	soumemb(p, overflow_arg_area, 0);
373 	soumemb(p, reg_save_area, 0);
374 	nfree(p);
375 	q = dclstruct(rp);
376 	c = addname("__builtin_va_list");
377 	p = block(LB, bdty(NAME, c), bcon(1), INT, 0, MKSUE(INT));
378 	p = tymerge(q, p);
379 	p->n_sp = lookup(c, 0);
380 	defid(p, TYPEDEF);
381 	nfree(q);
382 	nfree(p);
383 }
384 
385 static NODE *
386 mkstkref(int off, TWORD typ)
387 {
388 	NODE *p;
389 
390 	p = block(REG, NIL, NIL, PTR|typ, 0, MKSUE(LONG));
391 	regno(p) = FPREG;
392 	return buildtree(PLUS, p, bcon(off/SZCHAR));
393 }
394 
395 NODE *
396 amd64_builtin_stdarg_start(NODE *f, NODE *a)
397 {
398 	NODE *p, *r;
399 
400 	/* use the values from the function header */
401 	p = a->n_left;
402 	r = buildtree(ASSIGN, structref(ccopy(p), STREF, reg_save_area),
403 	    mkstkref(-rsaoff, VOID));
404 	r = buildtree(COMOP, r,
405 	    buildtree(ASSIGN, structref(ccopy(p), STREF, overflow_arg_area),
406 	    mkstkref(thisrsp, VOID)));
407 	r = buildtree(COMOP, r,
408 	    buildtree(ASSIGN, structref(ccopy(p), STREF, gp_offset),
409 	    bcon(thisgpr*(SZLONG/SZCHAR))));
410 	r = buildtree(COMOP, r,
411 	    buildtree(ASSIGN, structref(ccopy(p), STREF, fp_offset),
412 	    bcon(thissse*(SZDOUBLE*2/SZCHAR)+48)));
413 
414 	tfree(f);
415 	tfree(a);
416 	return r;
417 }
418 
419 /*
420  * Create a tree that should be like the expression
421  *	((long *)(l->gp_offset >= 48 ?
422  *	    l->overflow_arg_area += 8, l->overflow_arg_area :
423  *	    l->gp_offset += 8, l->reg_save_area + l->gp_offset))[-1]
424  * ...or similar for floats.
425  */
426 static NODE *
427 bva(NODE *ap, TWORD dt, char *ot, int addto, int max)
428 {
429 	NODE *cm1, *cm2, *gpo, *ofa, *l1, *qc;
430 	TWORD nt;
431 
432 	ofa = structref(ccopy(ap), STREF, overflow_arg_area);
433 	l1 = buildtree(PLUSEQ, ccopy(ofa), bcon(addto));
434 	cm1 = buildtree(COMOP, l1, ofa);
435 
436 	gpo = structref(ccopy(ap), STREF, ot);
437 	l1 = buildtree(PLUSEQ, ccopy(gpo), bcon(addto));
438 	cm2 = buildtree(COMOP, l1, buildtree(PLUS, ccopy(gpo),
439 	    structref(ccopy(ap), STREF, reg_save_area)));
440 	qc = buildtree(QUEST,
441 	    buildtree(GE, gpo, bcon(max)),
442 	    buildtree(COLON, cm1, cm2));
443 
444 	nt = (dt == DOUBLE ? DOUBLE : LONG);
445 	l1 = block(NAME, NIL, NIL, nt|PTR, 0, MKSUE(nt));
446 	l1 = buildtree(CAST, l1, qc);
447 	qc = l1->n_right;
448 	nfree(l1->n_left);
449 	nfree(l1);
450 
451 	/* qc has now a real type, for indexing */
452 	addto = dt == DOUBLE ? 2 : 1;
453 	qc = buildtree(UMUL, buildtree(PLUS, qc, bcon(-addto)), NIL);
454 
455 	l1 = block(NAME, NIL, NIL, dt, 0, MKSUE(BTYPE(dt)));
456 	l1 = buildtree(CAST, l1, qc);
457 	qc = l1->n_right;
458 	nfree(l1->n_left);
459 	nfree(l1);
460 
461 	return qc;
462 }
463 
464 NODE *
465 amd64_builtin_va_arg(NODE *f, NODE *a)
466 {
467 	NODE *ap, *r;
468 	TWORD dt;
469 
470 	ap = a->n_left;
471 	dt = a->n_right->n_type;
472 	if (dt <= ULONGLONG || ISPTR(dt)) {
473 		/* type might be in general register */
474 		r = bva(ap, dt, gp_offset, 8, 48);
475 	} else if (dt == FLOAT || dt == DOUBLE) {
476 		/* Float are promoted to double here */
477 		if (dt == FLOAT)
478 			dt = DOUBLE;
479 		r = bva(ap, dt, fp_offset, 16, RSASZ/SZCHAR);
480 	} else {
481 		uerror("amd64_builtin_va_arg not supported type");
482 		goto bad;
483 	}
484 	tfree(a);
485 	tfree(f);
486 	return r;
487 bad:
488 	uerror("bad argument to __builtin_va_arg");
489 	return bcon(0);
490 }
491 
492 NODE *
493 amd64_builtin_va_end(NODE *f, NODE *a)
494 {
495 	tfree(f);
496 	tfree(a);
497 	return bcon(0); /* nothing */
498 }
499 
500 NODE *
501 amd64_builtin_va_copy(NODE *f, NODE *a) { cerror("amd64_builtin_va_copy"); return NULL; }
502 
503 static NODE *
504 movtoreg(NODE *p, int rno)
505 {
506 	NODE *r;
507 
508 	r = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_sue);
509 	regno(r) = rno;
510 	return clocal(buildtree(ASSIGN, r, p));
511 }
512 
513 static NODE *
514 movtomem(NODE *p, int off, int reg)
515 {
516 	struct symtab s;
517 	NODE *r, *l;
518 
519 	s.stype = p->n_type;
520 	s.sdf = p->n_df;
521 	s.ssue = p->n_sue;
522 	s.soffset = off;
523 	s.sclass = AUTO;
524 
525 	l = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
526 	l->n_lval = 0;
527 	regno(l) = reg;
528 
529 	r = block(NAME, NIL, NIL, p->n_type, p->n_df, p->n_sue);
530 	r->n_sp = &s;
531 	r = stref(block(STREF, l, r, 0, 0, 0));
532 
533 	return clocal(buildtree(ASSIGN, r, p));
534 }
535 
536 
537 /*
538  * AMD64 parameter classification.
539  */
540 static int
541 argtyp(TWORD t, union dimfun *df, struct suedef *sue)
542 {
543 	int cl = 0;
544 
545 	if (t <= ULONG || ISPTR(t)) {
546 		cl = ngpr < 6 ? INTEGER : INTMEM;
547 	} else if (t == FLOAT || t == DOUBLE) {
548 		cl = nsse < 8 ? SSE : SSEMEM;
549 	} else if (t == LDOUBLE) {
550 		cl = X87; /* XXX */
551 	} else if (t == STRTY) {
552 		/* XXX no SSEOP handling */
553 		if ((tsize(t, df, sue) > 2*SZLONG) ||
554 		    (gcc_get_attr(sue, GCC_ATYP_PACKED) != NULL))
555 			cl = STRMEM;
556 		else
557 			cl = STRREG;
558 	} else
559 		cerror("FIXME: classify");
560 	return cl;
561 }
562 
563 static void
564 argput(NODE *p)
565 {
566 	NODE *q;
567 	int typ, r, ssz;
568 
569 	/* first arg may be struct return pointer */
570 	/* XXX - check if varargs; setup al */
571 	switch (typ = argtyp(p->n_type, p->n_df, p->n_sue)) {
572 	case INTEGER:
573 	case SSE:
574 		q = talloc();
575 		*q = *p;
576 		if (typ == SSE)
577 			r = XMM0 + nsse++;
578 		else
579 			r = argregsi[ngpr++];
580 		q = movtoreg(q, r);
581 		*p = *q;
582 		nfree(q);
583 		break;
584 	case X87:
585 		cerror("no long double yet");
586 		break;
587 
588 	case INTMEM:
589 		q = talloc();
590 		*q = *p;
591 		r = nrsp;
592 		nrsp += SZLONG;
593 		q = movtomem(q, r, STKREG);
594 		*p = *q;
595 		nfree(q);
596 		break;
597 
598 	case STRREG: /* Struct in registers */
599 		/* Cast to long pointer and move to the registers */
600 		ssz = tsize(p->n_type, p->n_df, p->n_sue);
601 
602 		if (ssz <= SZLONG) {
603 			q = cast(p->n_left, LONG+PTR, 0);
604 			q = buildtree(UMUL, q, NIL);
605 			q = movtoreg(q, argregsi[ngpr++]);
606 			*p = *q;
607 			nfree(q);
608 		} else if (ssz <= SZLONG*2) {
609 			NODE *qt, *q1, *q2, *ql, *qr;
610 
611 			qt = tempnode(0, LONG+PTR, 0, MKSUE(LONG));
612 			q1 = ccopy(qt);
613 			q2 = ccopy(qt);
614 			ql = buildtree(ASSIGN, qt, cast(p->n_left,LONG+PTR, 0));
615 			qr = movtoreg(buildtree(UMUL, q1, NIL),
616 			    argregsi[ngpr++]);
617 			ql = buildtree(COMOP, ql, qr);
618 			qr = buildtree(UMUL, buildtree(PLUS, q2, bcon(1)), NIL);
619 			qr = movtoreg(qr, argregsi[ngpr++]);
620 			q = buildtree(COMOP, ql, qr);
621 			*p = *q;
622 			nfree(q);
623 		} else
624 			cerror("STRREG");
625 		break;
626 
627 	case STRMEM:
628 		/* Struct moved to memory */
629 	default:
630 		cerror("argument %d", typ);
631 	}
632 }
633 
634 
635 /*
636  * Called with a function call with arguments as argument.
637  * This is done early in buildtree() and only done once.
638  * Returns p.
639  */
640 NODE *
641 funcode(NODE *p)
642 {
643 	NODE *l, *r;
644 
645 	nsse = ngpr = nrsp = 0;
646 	/* Check if hidden arg needed */
647 	/* If so, add it in pass2 */
648 	if ((l = p->n_left)->n_type == INCREF(FTN)+STRTY ||
649 	    l->n_type == INCREF(FTN)+UNIONTY) {
650 		int ssz = tsize(BTYPE(l->n_type), l->n_df, l->n_sue);
651 		if (ssz > 2*SZLONG)
652 			ngpr++;
653 	}
654 	listf(p->n_right, argput);
655 
656 	/* Check if there are varargs */
657 	if (nsse || l->n_df == NULL || l->n_df->dfun == NULL) {
658 		; /* Need RAX */
659 	} else {
660 		union arglist *al = l->n_df->dfun;
661 
662 		for (; al->type != TELLIPSIS; al++) {
663 			if (al->type == TNULL)
664 				return p; /* No need */
665 			if (BTYPE(al->type) == STRTY ||
666 			    BTYPE(al->type) == UNIONTY ||
667 			    ISARY(al->type))
668 				al++;
669 		}
670 	}
671 
672 	/* Always emit number of SSE regs used */
673 	l = movtoreg(bcon(nsse), RAX);
674 	if (p->n_right->n_op != CM) {
675 		p->n_right = block(CM, l, p->n_right, INT, 0, MKSUE(INT));
676 	} else {
677 		for (r = p->n_right; r->n_left->n_op == CM; r = r->n_left)
678 			;
679 		r->n_left = block(CM, l, r->n_left, INT, 0, MKSUE(INT));
680 	}
681 	return p;
682 }
683 
684 /*
685  * return the alignment of field of type t
686  */
687 int
688 fldal(unsigned int t)
689 {
690 	uerror("illegal field type");
691 	return(ALINT);
692 }
693 
694 /* fix up type of field p */
695 void
696 fldty(struct symtab *p)
697 {
698 }
699 
700 /*
701  * XXX - fix genswitch.
702  */
703 int
704 mygenswitch(int num, TWORD type, struct swents **p, int n)
705 {
706 	return 0;
707 }
708