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, ®, &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