1/*	Id: local2.c,v 1.17 2016/01/30 17:26:19 ragge Exp 	*/
2/*	$NetBSD: local2.c,v 1.1.1.2 2016/02/09 20:28:34 plunky Exp $	*/
3/*
4 * Copyright (c) 2014 Anders Magnusson (ragge@ludd.luth.se).
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28# include "pass2.h"
29# include <ctype.h>
30# include <string.h>
31
32static int stkpos;
33
34void
35deflab(int label)
36{
37	printf(LABFMT ":\n", label);
38}
39
40static int regm, regf, fpsub, nfp;
41
42void
43prologue(struct interpass_prolog *ipp)
44{
45	int i;
46
47	/*
48	 * Subtract both space for automatics and permanent regs.
49	 * XXX - no struct return yet.
50	 */
51
52	fpsub = p2maxautooff;
53	if (fpsub >= AUTOINIT/SZCHAR)
54		fpsub -= AUTOINIT/SZCHAR;
55	regm = regf = nfp = 0;
56	for (i = 0; i < MAXREGS; i++)
57		if (TESTBIT(ipp->ipp_regs, i)) {
58			if (i <= A7) {
59				regm |= (1 << i);
60				fpsub += 4;
61			} else if (i >= FP0) {
62				regf |= (1 << (i - FP0));
63				fpsub += 12;
64				nfp += 12;
65			} else
66				comperr("bad reg range");
67		}
68	printf("	link.%c %%fp,#%d\n", fpsub > 32768 ? 'l' : 'w', -fpsub);
69	if (regm)
70		printf("	movem.l #%d,%d(%%fp)\n", regm, -fpsub + nfp);
71	if (regf)
72		printf("	fmovem #%d,%d(%%fp)\n", regf, -fpsub);
73}
74
75void
76eoftn(struct interpass_prolog *ipp)
77{
78	if (ipp->ipp_ip.ip_lbl == 0)
79		return; /* no code needs to be generated */
80
81	if (regm)
82		printf("	movem.l %d(%%fp),#%d\n", -fpsub + nfp, regm);
83	if (regf)
84		printf("	fmovem %d(%%fp),#%d\n", -fpsub, regf);
85	printf("	unlk %%fp\n	rts\n");
86}
87
88/*
89 * add/sub/...
90 *
91 * Param given:
92 */
93void
94hopcode(int f, int o)
95{
96	char *str;
97
98	switch (o) {
99	case PLUS:
100		str = "add";
101		break;
102	case MINUS:
103		str = "sub";
104		break;
105	case AND:
106		str = "and";
107		break;
108	case OR:
109		str = "or";
110		break;
111	case ER:
112		str = "eor";
113		break;
114	default:
115		comperr("hopcode2: %d", o);
116		str = 0; /* XXX gcc */
117	}
118	printf("%s", str);
119}
120
121/*
122 * Return type size in bytes.  Used by R2REGS, arg 2 to offset().
123 */
124int
125tlen(NODE *p)
126{
127	switch(p->n_type) {
128		case CHAR:
129		case UCHAR:
130			return(1);
131
132		case SHORT:
133		case USHORT:
134			return(SZSHORT/SZCHAR);
135
136		case DOUBLE:
137			return(SZDOUBLE/SZCHAR);
138
139		case INT:
140		case UNSIGNED:
141			return(SZINT/SZCHAR);
142
143		case LONG:
144		case ULONG:
145		case LONGLONG:
146		case ULONGLONG:
147			return SZLONGLONG/SZCHAR;
148
149		default:
150			if (!ISPTR(p->n_type))
151				comperr("tlen type %d not pointer");
152			return SZPOINT(p->n_type)/SZCHAR;
153		}
154}
155
156int
157fldexpand(NODE *p, int cookie, char **cp)
158{
159	comperr("fldexpand");
160	return 0;
161}
162
163static void
164starg(NODE *p)
165{
166	int sz = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0);
167	int subsz = (sz + 3) & ~3;
168	int fr, tr, cr;
169
170	fr = regno(getlr(p, 'L')); /* from reg (struct pointer) */
171	cr = regno(getlr(p, '1')); /* count reg (number of words) */
172	tr = regno(getlr(p, '2')); /* to reg (stack) */
173
174	/* Sub from stack and put in toreg */
175	printf("	sub.l #%d,%%sp\n", subsz);
176	printf("	move.l %%sp,%s\n", rnames[tr]);
177
178	/* Gen an even copy start */
179	if (sz & 1)
180		expand(p, INBREG, "	move.b (AL)+,(A2)+\n");
181	if (sz & 2)
182		expand(p, INBREG, "	move.w (AL)+,(A2)+\n");
183	sz -= (sz & 3);
184
185	/* if more than 4 words, use loop, otherwise output instructions */
186	if (sz > 16) {
187		printf("	move.l #%d,%s\n", (sz/4)-1, rnames[cr]);
188		expand(p, INBREG, "1:	move.l (AL)+,(A2)+\n");
189		expand(p, INBREG, "	dbra A1,1b\n");
190	} else {
191		if (sz > 12)
192			expand(p, INBREG, "	move.l (AL)+,(A2)+\n"), sz -= 4;
193		if (sz > 8)
194			expand(p, INBREG, "	move.l (AL)+,(A2)+\n"), sz -= 4;
195		if (sz > 4)
196			expand(p, INBREG, "	move.l (AL)+,(A2)+\n"), sz -= 4;
197		if (sz == 4)
198			expand(p, INBREG, "	move.l (AL)+,(A2)+\n");
199	}
200}
201
202void
203zzzcode(NODE *p, int c)
204{
205	TWORD t = p->n_type;
206	char *s;
207
208	switch (c) {
209	case 'L':
210		t = p->n_left->n_type;
211		/* FALLTHROUGH */
212	case 'A':
213		s = (t == CHAR || t == UCHAR ? "b" :
214		    t == SHORT || t == USHORT ? "w" :
215		    t == FLOAT ? "s" :
216		    t == DOUBLE ? "d" :
217		    t == LDOUBLE ? "x" : "l");
218		printf("%s", s);
219		break;
220
221	case 'B':
222		if (p->n_qual)
223			printf("	add.l #%d,%%sp\n", (int)p->n_qual);
224		break;
225
226	case 'C': /* jsr or bsr.l XXX - type of CPU? */
227		printf("%s", kflag ? "bsr.l" : "jsr");
228		break;
229
230	case 'F': /* Emit float branches */
231		switch (p->n_op) {
232		case GT: s = "fjnle"; break;
233		case GE: s = "fjnlt"; break;
234		case LE: s = "fjngt"; break;
235		case LT: s = "fjnge"; break;
236		case NE: s = "fjne"; break;
237		case EQ: s = "fjeq"; break;
238		default: comperr("ZF"); s = 0;
239		}
240		printf("%s " LABFMT "\n", s, p->n_label);
241		break;
242
243	case 'P':
244		printf("	lea -%d(%%fp),%%a0\n", stkpos);
245		break;
246
247	case 'Q': /* struct assign */
248		printf("	move.l %d,-(%%sp)\n",
249		    attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0));
250		expand(p, INAREG, "	move.l AR,-(%sp)\n");
251		expand(p, INAREG, "	move.l AL,-(%sp)\n");
252		printf("	jsr memcpy\n");
253		printf("	add.l #12,%%sp\n");
254		break;
255
256	case 'S': /* struct arg */
257		starg(p);
258		break;
259
260	case '2':
261		if (regno(getlr(p, '2')) != regno(getlr(p, 'L')))
262			expand(p, INAREG, "	fmove.x AL,A2\n");
263		break;
264
265	default:
266		comperr("zzzcode %c", c);
267	}
268}
269
270#if 0
271int canaddr(NODE *);
272int
273canaddr(NODE *p)
274{
275	int o = p->n_op;
276
277	if (o==NAME || o==REG || o==ICON || o==OREG ||
278	    (o==UMUL && shumul(p->n_left, SOREG)))
279		return(1);
280	return(0);
281}
282#endif
283
284/*
285 * Does the bitfield shape match?
286 */
287int
288flshape(NODE *p)
289{
290	comperr("flshape");
291	return(0);
292}
293
294/* INTEMP shapes must not contain any temporary registers */
295/* XXX should this go away now? */
296int
297shtemp(NODE *p)
298{
299	return 0;
300#if 0
301	int r;
302
303	if (p->n_op == STARG )
304		p = p->n_left;
305
306	switch (p->n_op) {
307	case REG:
308		return (!istreg(p->n_rval));
309
310	case OREG:
311		r = p->n_rval;
312		if (R2TEST(r)) {
313			if (istreg(R2UPK1(r)))
314				return(0);
315			r = R2UPK2(r);
316		}
317		return (!istreg(r));
318
319	case UMUL:
320		p = p->n_left;
321		return (p->n_op != UMUL && shtemp(p));
322	}
323
324	if (optype(p->n_op) != LTYPE)
325		return(0);
326	return(1);
327#endif
328}
329
330void
331adrcon(CONSZ val)
332{
333	printf("#" CONFMT, val);
334}
335
336void
337conput(FILE *fp, NODE *p)
338{
339	long val = getlval(p);
340
341	if (p->n_type <= UCHAR)
342		val &= 255;
343	else if (p->n_type <= USHORT)
344		val &= 65535;
345
346	switch (p->n_op) {
347	case ICON:
348		fprintf(fp, "%ld", val);
349		if (p->n_name[0])
350			printf("+%s", p->n_name);
351		break;
352
353	default:
354		comperr("illegal conput, p %p", p);
355	}
356}
357
358/*ARGSUSED*/
359void
360insput(NODE *p)
361{
362	comperr("insput");
363}
364
365/*
366 * Write out the upper address, like the upper register of a 2-register
367 * reference, or the next memory location.
368 */
369void
370upput(NODE *p, int size)
371{
372	switch (p->n_op) {
373	case REG:
374		printf("%%%s", &rnames[p->n_rval][2]);
375		break;
376	case NAME:
377	case OREG:
378		setlval(p, getlval(p) + 4);
379		adrput(stdout, p);
380		setlval(p, getlval(p) - 4);
381		break;
382
383	case ICON:
384		printf("#%d", (int)getlval(p));
385		break;
386
387	default:
388		comperr("upput bad op %d size %d", p->n_op, size);
389	}
390}
391
392void
393adrput(FILE *io, NODE *p)
394{
395	int r;
396
397	/* output an address, with offsets, from p */
398	switch (p->n_op) {
399	case NAME:
400		if (getlval(p))
401			fprintf(io, CONFMT "%s", getlval(p),
402			    *p->n_name ? "+" : "");
403		if (p->n_name[0])
404			printf("%s", p->n_name);
405		else
406			comperr("adrput");
407		return;
408
409	case OREG:
410		r = p->n_rval;
411
412		if (getlval(p))
413			fprintf(io, CONFMT "%s", getlval(p),
414			    *p->n_name ? "+" : "");
415		if (p->n_name[0])
416			printf("%s", p->n_name);
417		if (R2TEST(r)) {
418			int r1 = R2UPK1(r);
419			int r2 = R2UPK2(r);
420			int sh = R2UPK3(r);
421
422			fprintf(io, "(%s,%s,%d)",
423			    r1 == MAXREGS ? "" : rnames[r1],
424			    r2 == MAXREGS ? "" : rnames[r2], sh);
425		} else
426			fprintf(io, "(%s)", rnames[p->n_rval]);
427		return;
428	case ICON:
429		/* addressable value of the constant */
430		if (p->n_type == LONGLONG || p->n_type == ULONGLONG) {
431			fprintf(io, "#" CONFMT, getlval(p) >> 32);
432		} else {
433			fputc('#', io);
434			conput(io, p);
435		}
436		return;
437
438	case REG:
439		if ((p->n_type == LONGLONG || p->n_type == ULONGLONG) &&
440			/* XXX allocated reg may get wrong type here */
441		    (p->n_rval > A7 && p->n_rval < FP0)) {
442			fprintf(io, "%%%c%c", rnames[p->n_rval][0],
443			    rnames[p->n_rval][1]);
444		} else
445			fprintf(io, "%s", rnames[p->n_rval]);
446		return;
447
448	default:
449		comperr("illegal address, op %d, node %p", p->n_op, p);
450		return;
451
452	}
453}
454
455static char *
456ccbranches[] = {
457	"jeq",		/* jumpe */
458	"jne",		/* jumpn */
459	"jle",		/* jumple */
460	"jlt",		/* jumpl */
461	"jge",		/* jumpge */
462	"jgt",		/* jumpg */
463	"jls",		/* jumple (jlequ) */
464	"jcs",		/* jumpl (jlssu) */
465	"jcc",		/* jumpge (jgequ) */
466	"jhi",		/* jumpg (jgtru) */
467};
468
469
470/*   printf conditional and unconditional branches */
471void
472cbgen(int o, int lab)
473{
474	if (o < EQ || o > UGT)
475		comperr("bad conditional branch: %s", opst[o]);
476	printf("	%s " LABFMT "\n", ccbranches[o-EQ], lab);
477}
478
479static void
480mkcall(NODE *p, char *name)
481{
482	p->n_op = CALL;
483	p->n_right = mkunode(FUNARG, p->n_left, 0, p->n_left->n_type);
484	p->n_left = mklnode(ICON, 0, 0, FTN|p->n_type);
485	p->n_left->n_name = name;
486}
487
488static void
489mkcall2(NODE *p, char *name)
490{
491	p->n_op = CALL;
492	p->n_right = mkunode(FUNARG, p->n_right, 0, p->n_right->n_type);
493	p->n_left = mkunode(FUNARG, p->n_left, 0, p->n_left->n_type);
494	p->n_right = mkbinode(CM, p->n_left, p->n_right, INT);
495	p->n_left = mklnode(ICON, 0, 0, FTN|p->n_type);
496	p->n_left->n_name = name;
497}
498
499
500static void
501fixcalls(NODE *p, void *arg)
502{
503	struct attr *ap;
504	TWORD lt;
505
506	switch (p->n_op) {
507	case STCALL:
508	case USTCALL:
509		ap = attr_find(p->n_ap, ATTR_P2STRUCT);
510		if (ap->iarg(0)+p2autooff > stkpos)
511			stkpos = ap->iarg(0)+p2autooff;
512		break;
513
514	case DIV:
515		if (p->n_type == LONGLONG)
516			mkcall2(p, "__divdi3");
517		else if (p->n_type == ULONGLONG)
518			mkcall2(p, "__udivdi3");
519		break;
520
521	case MOD:
522		if (p->n_type == LONGLONG)
523			mkcall2(p, "__moddi3");
524		else if (p->n_type == ULONGLONG)
525			mkcall2(p, "__umoddi3");
526		break;
527
528	case MUL:
529		if (p->n_type == LONGLONG || p->n_type == ULONGLONG)
530			mkcall2(p, "__muldi3");
531		break;
532
533	case LS:
534		if (p->n_type == LONGLONG || p->n_type == ULONGLONG)
535			mkcall2(p, "__ashldi3");
536		break;
537
538	case RS:
539		if (p->n_type == LONGLONG)
540			mkcall2(p, "__ashrdi3");
541		else if (p->n_type == ULONGLONG)
542			mkcall2(p, "__lshrdi3");
543		break;
544
545	case SCONV:
546		lt = p->n_left->n_type;
547		switch (p->n_type) {
548		case LONGLONG:
549			if (lt == FLOAT)
550				mkcall(p, "__fixsfdi");
551			else if (lt == DOUBLE)
552				mkcall(p, "__fixdfdi");
553			else if (lt == LDOUBLE)
554				mkcall(p, "__fixxfdi");
555			break;
556		case ULONGLONG:
557			if (lt == FLOAT)
558				mkcall(p, "__fixunssfdi");
559			else if (lt == DOUBLE)
560				mkcall(p, "__fixunsdfdi");
561			else if (lt == LDOUBLE)
562				mkcall(p, "__fixunsxfdi");
563			break;
564		case FLOAT:
565			if (lt == LONGLONG)
566				mkcall(p, "__floatdisf");
567			else if (lt == ULONGLONG)
568				mkcall(p, "__floatundisf");
569			break;
570		case DOUBLE:
571			if (lt == LONGLONG)
572				mkcall(p, "__floatdidf");
573			else if (lt == ULONGLONG)
574				mkcall(p, "__floatundidf");
575			break;
576		case LDOUBLE:
577			if (lt == LONGLONG)
578				mkcall(p, "__floatdixf");
579			else if (lt == ULONGLONG)
580				mkcall(p, "__floatundixf");
581			break;
582		}
583		break;
584#if 0
585	case XASM:
586		p->n_name = adjustname(p->n_name);
587		break;
588#endif
589	}
590}
591
592void
593myreader(struct interpass *ipole)
594{
595	struct interpass *ip;
596
597	stkpos = p2autooff;
598	DLIST_FOREACH(ip, ipole, qelem) {
599		if (ip->type != IP_NODE)
600			continue;
601		walkf(ip->ip_node, fixcalls, 0);
602	}
603	if (stkpos > p2autooff)
604		p2autooff = stkpos;
605	if (stkpos > p2maxautooff)
606		p2maxautooff = stkpos;
607	if (x2debug)
608		printip(ipole);
609}
610
611/*
612 * Remove some PCONVs after OREGs are created.
613 */
614static void
615pconv2(NODE *p, void *arg)
616{
617	NODE *q;
618
619	if (p->n_op == PLUS) {
620		if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) {
621			if (p->n_right->n_op != ICON)
622				return;
623			if (p->n_left->n_op != PCONV)
624				return;
625			if (p->n_left->n_left->n_op != OREG)
626				return;
627			q = p->n_left->n_left;
628			nfree(p->n_left);
629			p->n_left = q;
630			/*
631			 * This will be converted to another OREG later.
632			 */
633		}
634	}
635}
636
637void
638mycanon(NODE *p)
639{
640	walkf(p, pconv2, 0);
641}
642
643void
644myoptim(struct interpass *ip)
645{
646}
647
648void
649rmove(int s, int d, TWORD t)
650{
651
652	if (s >= D0D1 && s <= D6D7) {
653		printf("	move.l %s,%s\n",
654		    rnames[s-D0D1], rnames[d-D0D1]);
655		printf("	move.l %s,%s\n",
656		    rnames[s+1-D0D1], rnames[d+1-D0D1]);
657	} else if (t >= FLOAT && t <= TDOUBLE)
658		printf("	fmove.x %s,%s\n", rnames[s], rnames[d]);
659	else
660		printf("	move.l %s,%s\n", rnames[s], rnames[d]);
661}
662
663/*
664 * For class cc, find worst-case displacement of the number of
665 * registers in the array r[] indexed by class.
666 */
667int
668COLORMAP(int cc, int *r)
669{
670	int a,c;
671
672	a = r[CLASSA];
673	c = r[CLASSC];
674
675	switch (cc) {
676	case CLASSA:
677		if (c * 2 + a < 8)
678			return 1;
679		break;
680	case CLASSB:
681		return r[CLASSB] < 6;
682	case CLASSC:
683		if (c > 2)
684			return 0;
685		if (c == 2 && a > 0)
686			return 0;
687		if (c == 1 && a > 1)
688			return 0;
689		if (c == 0 && a > 3)
690			return 0;
691		return 1;
692	}
693	return 0;
694}
695
696char *rnames[] = {
697	"%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7",
698	"%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%a7",
699	"d0d1", "d1d2", "d2d3", "d3d4", "d4d5", "d5d6", "d6d7",
700	"%fp0", "%fp1", "%fp2", "%fp3", "%fp4", "%fp5", "%fp6", "%fp7",
701};
702
703/*
704 * Return a class suitable for a specific type.
705 */
706int
707gclass(TWORD t)
708{
709	if (t > BTMASK)
710		return CLASSB;
711	if (t == LONGLONG || t == ULONGLONG)
712		return CLASSC;
713	if (t == FLOAT || t == DOUBLE || t == LDOUBLE)
714		return CLASSD;
715	return CLASSA;
716}
717
718static int
719argsiz(NODE *p)
720{
721	TWORD t = p->n_type;
722
723	if (t < LONGLONG || t == FLOAT || t > BTMASK)
724		return 4;
725	if (t == LONGLONG || t == ULONGLONG || t == DOUBLE)
726		return 8;
727	if (t == LDOUBLE)
728		return 12;
729	if (t == STRTY || t == UNIONTY)
730		return (attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)+3) & ~3;
731	comperr("argsiz");
732	return 0;
733}
734
735/*
736 * Calculate argument sizes.
737 */
738void
739lastcall(NODE *p)
740{
741	NODE *op = p;
742	int size = 0;
743
744	p->n_qual = 0;
745	if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
746		return;
747	for (p = p->n_right; p->n_op == CM; p = p->n_left)
748		size += argsiz(p->n_right);
749	size += argsiz(p);
750	op->n_qual = size; /* XXX */
751}
752
753/*
754 * Special shapes.
755 */
756int
757special(NODE *p, int shape)
758{
759	return SRNOPE;
760}
761
762/*
763 * Target-dependent command-line options.
764 */
765void
766mflags(char *str)
767{
768}
769
770/*
771 * Do something target-dependent for xasm arguments.
772 */
773int
774myxasm(struct interpass *ip, NODE *p)
775{
776	int cw = xasmcode(p->n_name);
777	int ww;
778	char *w;
779
780	ww = XASMVAL(cw);
781again:	switch (ww) {
782	case 'd': /* Just convert to reg */
783	case 'a':
784		p->n_name = tmpstrdup(p->n_name);
785		w = strchr(p->n_name, XASMVAL(cw));
786		*w = 'r'; /* now reg */
787		break;
788	case 'o': /* offsetable reg */
789		if (p->n_left->n_op == UMUL || p->n_left->n_op == OREG ||
790		    p->n_left->n_op == NAME) {
791			return 1;
792		}
793		if (ww == XASMVAL(cw))
794			ww = XASMVAL1(cw);
795		else
796			ww = XASMVAL2(cw);
797		goto again;
798	}
799	return 0;
800}
801
802/*
803 * Handle special characters following % in gcc extended assembler.
804 */
805int
806targarg(char *w, void *arg)
807{
808	switch (w[1]) {
809	case '.': /* Remove dot if not needed */
810		printf(".");
811		break;
812	default:
813		return 0;
814	}
815	return 1;
816}
817