xref: /netbsd/external/bsd/pcc/dist/pcc/arch/sparc64/code.c (revision 6935091c)
1 /*	Id: code.c,v 1.23 2015/07/24 07:57:01 ragge Exp 	*/
2 /*	$NetBSD: code.c,v 1.1.1.6 2016/02/09 20:28:32 plunky Exp $	*/
3 
4 /*
5  * Copyright (c) 2008 David Crawshaw <david@zentus.com>
6  *
7  * Permission to use, copy, modify, and/or distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "pass1.h"
21 
22 /*
23  * Print out assembler segment name.
24  */
25 void
setseg(int seg,char * name)26 setseg(int seg, char *name)
27 {
28 	switch (seg) {
29 	case PROG: name = ".text"; break;
30 	case DATA:
31 	case LDATA: name = ".data"; break;
32 	case STRNG:
33 	case RDATA: name = ".section .rodata"; break;
34 	case UDATA: break;
35 	case PICLDATA:
36 	case PICDATA:
37 	case PICRDATA:
38 	case TLSDATA:
39 	case TLSUDATA:
40 	case CTORS:
41 	case DTORS:
42 		uerror("FIXME: unknown section");
43 	case NMSEG:
44 		printf("\t.section %s,\"a%c\",@progbits\n", name,
45 		    cftnsp ? 'x' : 'w');
46 		return;
47 	}
48 	printf("\t%s\n", name);
49 }
50 
51 
52 void
defloc(struct symtab * sp)53 defloc(struct symtab *sp)
54 {
55 	TWORD t;
56 	char *name;
57 
58 	t = sp->stype;
59 
60 	if ((name = sp->soname) == NULL)
61 		name = exname(sp->sname);
62 
63 	if (!ISFTN(t)) {
64 		printf("\t.type %s,#object\n", name);
65 		printf("\t.size %s," CONFMT "\n", name,
66 			tsize(sp->stype, sp->sdf, sp->sap) / SZCHAR);
67 	}
68 	if (sp->sclass == EXTDEF)
69 		printf("\t.global %s\n", name);
70 	if (sp->slevel == 0) {
71 		printf("%s:\n", name);
72 	} else
73 		printf(LABFMT ":\n", sp->soffset);
74 }
75 
76 void
efcode(void)77 efcode(void)
78 {
79 	/* XXX */
80 }
81 
82 void
bfcode(struct symtab ** sp,int cnt)83 bfcode(struct symtab **sp, int cnt)
84 {
85 	int i, off;
86 	NODE *p, *q;
87 	struct symtab *sym;
88 
89 	/* Process the first six arguments. */
90 	for (i=0; i < cnt && i < 6; i++) {
91 		sym = sp[i];
92 		q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap);
93 		q->n_rval = RETREG_PRE(sym->stype) + i;
94 		p = tempnode(0, sym->stype, sym->sdf, sym->sap);
95 		sym->soffset = regno(p);
96 		sym->sflags |= STNODE;
97 		p = buildtree(ASSIGN, p, q);
98 		ecomp(p);
99 	}
100 
101 	/* Process the remaining arguments. */
102 	for (off = V9RESERVE; i < cnt; i++) {
103 		sym = sp[i];
104 		p = tempnode(0, sym->stype, sym->sdf, sym->sap);
105 		off = ALIGN(off, (tlen(p) - 1));
106 		sym->soffset = off * SZCHAR;
107 		off += tlen(p);
108 		p = buildtree(ASSIGN, p, nametree(sym));
109 		sym->soffset = regno(p->n_left);
110 		sym->sflags |= STNODE;
111 		ecomp(p);
112 	}
113 }
114 
115 void
ejobcode(int flag)116 ejobcode(int flag)
117 {
118 }
119 
120 void
bjobcode(void)121 bjobcode(void)
122 {
123 	astypnames[USHORT] = astypnames[SHORT] = "\t.half";
124 	astypnames[INT] = astypnames[UNSIGNED] = "\t.long";
125 	astypnames[LONG] = astypnames[ULONG] =
126 	    astypnames[LONGLONG] = astypnames[ULONGLONG] = "\t.xword";
127 }
128 
129 /*
130  * The first six 64-bit arguments are saved in the registers O0 to O5,
131  * which become I0 to I5 after the "save" instruction moves the register
132  * window. Arguments 7 and up must be saved on the stack to %sp+BIAS+176.
133  *
134  * For a pretty picture, see Figure 3-16 in the SPARC Compliance Def 2.4.
135  */
136 static NODE *
moveargs(NODE * p,int * regp,int * stacksize)137 moveargs(NODE *p, int *regp, int *stacksize)
138 {
139 	NODE *r, *q;
140 
141 	if (p->n_op == CM) {
142 		p->n_left = moveargs(p->n_left, regp, stacksize);
143 		r = p->n_right;
144 	} else {
145 		r = p;
146 	}
147 
148 	/* XXX more than six FP args can and should be passed in registers. */
149 	if (*regp > 5 && r->n_op != STARG) {
150 		/* We are storing the stack offset in n_rval. */
151 		r = block(FUNARG, r, NIL, r->n_type, r->n_df, r->n_ap);
152 		/* Make sure we are appropriately aligned. */
153 		*stacksize = ALIGN(*stacksize, (tlen(r) - 1));
154 		r->n_rval = *stacksize;
155 		*stacksize += tlen(r);
156 	} else if (r->n_op == STARG)
157 		cerror("op STARG in moveargs");
158 	else {
159 		q = block(REG, NIL, NIL, r->n_type, r->n_df, r->n_ap);
160 
161 		/*
162 		 * The first six non-FP arguments go in the registers O0 - O5.
163 		 * Float arguments are stored in %fp1, %fp3, ..., %fp29, %fp31.
164 		 * Double arguments are stored in %fp0, %fp2, ..., %fp28, %fp30.
165 		 * A non-fp argument still increments register, eg.
166 		 *     test(int a, int b, float b)
167 		 * takes %o0, %o1, %fp5.
168 		 */
169 		if (q->n_type == FLOAT)
170 			q->n_rval = F0 + (*regp++ * 2) + 1;
171 		else if (q->n_type == DOUBLE)
172 			q->n_rval = D0 + *regp++;
173 		else if (q->n_type == LDOUBLE)
174 			cerror("long double support incomplete");
175 		else
176 			q->n_rval = O0 + (*regp)++;
177 
178 		r = buildtree(ASSIGN, q, r);
179 	}
180 
181 	if (p->n_op == CM) {
182 		p->n_right = r;
183 		return p;
184 	}
185 
186 	return r;
187 }
188 
189 NODE *
funcode(NODE * p)190 funcode(NODE *p)
191 {
192 	NODE *r, *l;
193 	int reg = 0, stacksize = 0;
194 
195 	r = l = 0;
196 
197 	p->n_right = moveargs(p->n_right, &reg, &stacksize);
198 
199 	/*
200 	 * This is a particularly gross and inefficient way to handle
201 	 * argument overflows. First, we calculate how much stack space
202 	 * we need in moveargs(). Then we assign it by moving %sp, make
203 	 * the function call, and then move %sp back.
204 	 *
205 	 * What we should be doing is getting the maximum of all the needed
206 	 * stacksize values to the prologue and doing it all in the "save"
207 	 * instruction.
208 	 */
209 	if (stacksize != 0) {
210 		stacksize = V9STEP(stacksize); /* 16-bit alignment. */
211 
212 		r = block(REG, NIL, NIL, INT, 0, 0);
213 		r->n_lval = 0;
214 		r->n_rval = SP;
215 		r = block(MINUS, r, bcon(stacksize), INT, 0, 0);
216 
217 		l = block(REG, NIL, NIL, INT, 0, 0);
218 		l->n_lval = 0;
219 		l->n_rval = SP;
220 		r = buildtree(ASSIGN, l, r);
221 
222 		p = buildtree(COMOP, r, p);
223 
224 		r = block(REG, NIL, NIL, INT, 0, 0);
225 		r->n_lval = 0;
226 		r->n_rval = SP;
227 		r = block(PLUS, r, bcon(stacksize), INT, 0, 0);
228 
229 		l = block(REG, NIL, NIL, INT, 0, 0);
230 		l->n_lval = 0;
231 		l->n_rval = SP;
232 		r = buildtree(ASSIGN, l, r);
233 
234 		p = buildtree(COMOP, p, r);
235 
236 	}
237 	return p;
238 }
239 
240 void
fldty(struct symtab * p)241 fldty(struct symtab *p)
242 {
243 }
244 
245 int
mygenswitch(int num,TWORD type,struct swents ** p,int n)246 mygenswitch(int num, TWORD type, struct swents **p, int n)
247 {
248 	return 0;
249 }
250 
251 /*
252  * Return "canonical frame address".
253  */
254 NODE *
builtin_cfa(const struct bitable * bt,NODE * a)255 builtin_cfa(const struct bitable *bt, NODE *a)
256 {
257 	uerror("missing %s", __func__);
258 	return bcon(0);
259 }
260 
261 NODE *
builtin_frame_address(const struct bitable * bt,NODE * a)262 builtin_frame_address(const struct bitable *bt, NODE *a)
263 {
264 	uerror("missing %s", __func__);
265 	return bcon(0);
266 }
267 
268 NODE *
builtin_return_address(const struct bitable * bt,NODE * a)269 builtin_return_address(const struct bitable *bt, NODE *a)
270 {
271 	uerror("missing %s", __func__);
272 	return bcon(0);
273 }
274