1 #include "l.h"
2
3 static Sym* sym_div;
4 static Sym* sym_divu;
5 static Sym* sym_mod;
6 static Sym* sym_modu;
7
8 void
noops(void)9 noops(void)
10 {
11 Prog *p, *q, *q1;
12 int o, curframe, curbecome, maxbecome;
13
14 /*
15 * find leaf subroutines
16 * become sizes
17 * frame sizes
18 * strip NOPs
19 * expand RET
20 * expand BECOME pseudo
21 */
22
23 if(debug['v'])
24 Bprint(&bso, "%5.2f noops\n", cputime());
25 Bflush(&bso);
26
27 curframe = 0;
28 curbecome = 0;
29 maxbecome = 0;
30 curtext = 0;
31
32 q = P;
33 for(p = firstp; p != P; p = p->link) {
34
35 /* find out how much arg space is used in this TEXT */
36 if(p->to.type == D_OREG && p->to.reg == REGSP)
37 if(p->to.offset > curframe)
38 curframe = p->to.offset;
39
40 switch(p->as) {
41 case ATEXT:
42 if(curtext && curtext->from.sym) {
43 curtext->from.sym->frame = curframe;
44 curtext->from.sym->become = curbecome;
45 if(curbecome > maxbecome)
46 maxbecome = curbecome;
47 }
48 curframe = 0;
49 curbecome = 0;
50
51 p->mark |= LEAF;
52 curtext = p;
53 break;
54
55 case ARET:
56 /* special form of RET is BECOME */
57 if(p->from.type == D_CONST)
58 if(p->from.offset > curbecome)
59 curbecome = p->from.offset;
60 break;
61
62 case ADIV:
63 case ADIVU:
64 case AMOD:
65 case AMODU:
66 q = p;
67 if(prog_div == P)
68 initdiv();
69 if(curtext != P)
70 curtext->mark &= ~LEAF;
71 continue;
72
73 case ANOP:
74 q1 = p->link;
75 q->link = q1; /* q is non-nop */
76 q1->mark |= p->mark;
77 continue;
78
79 case ABL:
80 if(curtext != P)
81 curtext->mark &= ~LEAF;
82
83 case ABCASE:
84 case AB:
85
86 case ABEQ:
87 case ABNE:
88 case ABCS:
89 case ABHS:
90 case ABCC:
91 case ABLO:
92 case ABMI:
93 case ABPL:
94 case ABVS:
95 case ABVC:
96 case ABHI:
97 case ABLS:
98 case ABGE:
99 case ABLT:
100 case ABGT:
101 case ABLE:
102
103 q1 = p->cond;
104 if(q1 != P) {
105 while(q1->as == ANOP) {
106 q1 = q1->link;
107 p->cond = q1;
108 }
109 }
110 break;
111 }
112 q = p;
113 }
114
115 if(curtext && curtext->from.sym) {
116 curtext->from.sym->frame = curframe;
117 curtext->from.sym->become = curbecome;
118 if(curbecome > maxbecome)
119 maxbecome = curbecome;
120 }
121
122 if(debug['b'])
123 print("max become = %d\n", maxbecome);
124 xdefine("ALEFbecome", STEXT, maxbecome);
125
126 curtext = 0;
127 for(p = firstp; p != P; p = p->link) {
128 switch(p->as) {
129 case ATEXT:
130 curtext = p;
131 break;
132 case ABL:
133 if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) {
134 o = maxbecome - curtext->from.sym->frame;
135 if(o <= 0)
136 break;
137 /* calling a become or calling a variable */
138 if(p->to.sym == S || p->to.sym->become) {
139 curtext->to.offset += o;
140 if(debug['b']) {
141 curp = p;
142 print("%D calling %D increase %d\n",
143 &curtext->from, &p->to, o);
144 }
145 }
146 }
147 break;
148 }
149 }
150
151 for(p = firstp; p != P; p = p->link) {
152 o = p->as;
153 switch(o) {
154 case ATEXT:
155 curtext = p;
156 autosize = p->to.offset + 4;
157 if(autosize <= 4)
158 if(curtext->mark & LEAF) {
159 p->to.offset = -4;
160 autosize = 0;
161 }
162
163 if(!autosize && !(curtext->mark & LEAF)) {
164 if(debug['v'])
165 Bprint(&bso, "save suppressed in: %s\n",
166 curtext->from.sym->name);
167 Bflush(&bso);
168 curtext->mark |= LEAF;
169 }
170
171 if(curtext->mark & LEAF) {
172 if(curtext->from.sym)
173 curtext->from.sym->type = SLEAF;
174 #ifdef optimise_time
175 if(autosize) {
176 q = prg();
177 q->as = ASUB;
178 q->line = p->line;
179 q->from.type = D_CONST;
180 q->from.offset = autosize;
181 q->to.type = D_REG;
182 q->to.reg = REGSP;
183
184 q->link = p->link;
185 p->link = q;
186 }
187 break;
188 #else
189 if(!autosize)
190 break;
191 #endif
192 }
193
194 q1 = prg();
195 q1->as = AMOVW;
196 q1->scond |= C_WBIT;
197 q1->line = p->line;
198 q1->from.type = D_REG;
199 q1->from.reg = REGLINK;
200 q1->to.type = D_OREG;
201 q1->to.offset = -autosize;
202 q1->to.reg = REGSP;
203
204 q1->link = p->link;
205 p->link = q1;
206 break;
207
208 case ARET:
209 nocache(p);
210 if(p->from.type == D_CONST)
211 goto become;
212 if(curtext->mark & LEAF) {
213 if(!autosize) {
214 p->as = AB;
215 p->from = zprg.from;
216 p->to.type = D_OREG;
217 p->to.offset = 0;
218 p->to.reg = REGLINK;
219 break;
220 }
221
222 #ifdef optimise_time
223 p->as = AADD;
224 p->from.type = D_CONST;
225 p->from.offset = autosize;
226 p->to.type = D_REG;
227 p->to.reg = REGSP;
228
229 q = prg();
230 q->as = AB;
231 q->scond = p->scond;
232 q->line = p->line;
233 q->to.type = D_OREG;
234 q->to.offset = 0;
235 q->to.reg = REGLINK;
236
237 q->link = p->link;
238 p->link = q;
239
240 break;
241 #endif
242 }
243 p->as = AMOVW;
244 p->scond |= C_PBIT;
245 p->from.type = D_OREG;
246 p->from.offset = autosize;
247 p->from.reg = REGSP;
248 p->to.type = D_REG;
249 p->to.reg = REGPC;
250 break;
251
252 become:
253 if(curtext->mark & LEAF) {
254
255 if(!autosize) {
256 p->as = AB;
257 p->from = zprg.from;
258 break;
259 }
260
261 #ifdef optimise_time
262 q = prg();
263 q->scond = p->scond;
264 q->line = p->line;
265 q->as = AB;
266 q->from = zprg.from;
267 q->to = p->to;
268 q->cond = p->cond;
269 q->link = p->link;
270 p->link = q;
271
272 p->as = AADD;
273 p->from = zprg.from;
274 p->from.type = D_CONST;
275 p->from.offset = autosize;
276 p->to = zprg.to;
277 p->to.type = D_REG;
278 p->to.reg = REGSP;
279
280 break;
281 #endif
282 }
283 q = prg();
284 q->scond = p->scond;
285 q->line = p->line;
286 q->as = AB;
287 q->from = zprg.from;
288 q->to = p->to;
289 q->cond = p->cond;
290 q->link = p->link;
291 p->link = q;
292
293 p->as = AMOVW;
294 p->scond |= C_PBIT;
295 p->from = zprg.from;
296 p->from.type = D_OREG;
297 p->from.offset = autosize;
298 p->from.reg = REGSP;
299 p->to = zprg.to;
300 p->to.type = D_REG;
301 p->to.reg = REGLINK;
302
303 break;
304
305 /*
306 * 5c code generation for unsigned -> double made the
307 * unfortunate assumption that single and double floating
308 * point registers are aliased - true for emulated 7500
309 * but not for vfp. Now corrected, but this test is
310 * insurance against old 5c compiled code in libraries.
311 */
312 case AMOVWD:
313 if((q = p->link) != P && q->as == ACMP)
314 if((q = q->link) != P && q->as == AMOVF)
315 if((q1 = q->link) != P && q1->as == AADDF)
316 if(q1->to.type == D_FREG && q1->to.reg == p->to.reg) {
317 q1->as = AADDD;
318 q1 = prg();
319 q1->scond = q->scond;
320 q1->line = q->line;
321 q1->as = AMOVFD;
322 q1->from = q->to;
323 q1->to = q1->from;
324 q1->link = q->link;
325 q->link = q1;
326 }
327 break;
328
329 case ADIV:
330 case ADIVU:
331 case AMOD:
332 case AMODU:
333 if(debug['M'])
334 break;
335 if(p->from.type != D_REG)
336 break;
337 if(p->to.type != D_REG)
338 break;
339 q1 = p;
340
341 /* MOV a,4(SP) */
342 q = prg();
343 q->link = p->link;
344 p->link = q;
345 p = q;
346
347 p->as = AMOVW;
348 p->line = q1->line;
349 p->from.type = D_REG;
350 p->from.reg = q1->from.reg;
351 p->to.type = D_OREG;
352 p->to.reg = REGSP;
353 p->to.offset = 4;
354
355 /* MOV b,REGTMP */
356 q = prg();
357 q->link = p->link;
358 p->link = q;
359 p = q;
360
361 p->as = AMOVW;
362 p->line = q1->line;
363 p->from.type = D_REG;
364 p->from.reg = q1->reg;
365 if(q1->reg == NREG)
366 p->from.reg = q1->to.reg;
367 p->to.type = D_REG;
368 p->to.reg = REGTMP;
369 p->to.offset = 0;
370
371 /* CALL appropriate */
372 q = prg();
373 q->link = p->link;
374 p->link = q;
375 p = q;
376
377 p->as = ABL;
378 p->line = q1->line;
379 p->to.type = D_BRANCH;
380 p->cond = p;
381 switch(o) {
382 case ADIV:
383 p->cond = prog_div;
384 p->to.sym = sym_div;
385 break;
386 case ADIVU:
387 p->cond = prog_divu;
388 p->to.sym = sym_divu;
389 break;
390 case AMOD:
391 p->cond = prog_mod;
392 p->to.sym = sym_mod;
393 break;
394 case AMODU:
395 p->cond = prog_modu;
396 p->to.sym = sym_modu;
397 break;
398 }
399
400 /* MOV REGTMP, b */
401 q = prg();
402 q->link = p->link;
403 p->link = q;
404 p = q;
405
406 p->as = AMOVW;
407 p->line = q1->line;
408 p->from.type = D_REG;
409 p->from.reg = REGTMP;
410 p->from.offset = 0;
411 p->to.type = D_REG;
412 p->to.reg = q1->to.reg;
413
414 /* ADD $8,SP */
415 q = prg();
416 q->link = p->link;
417 p->link = q;
418 p = q;
419
420 p->as = AADD;
421 p->from.type = D_CONST;
422 p->from.reg = NREG;
423 p->from.offset = 8;
424 p->reg = NREG;
425 p->to.type = D_REG;
426 p->to.reg = REGSP;
427
428 /* SUB $8,SP */
429 q1->as = ASUB;
430 q1->from.type = D_CONST;
431 q1->from.offset = 8;
432 q1->from.reg = NREG;
433 q1->reg = NREG;
434 q1->to.type = D_REG;
435 q1->to.reg = REGSP;
436 break;
437 }
438 }
439 }
440
441 static void
sigdiv(char * n)442 sigdiv(char *n)
443 {
444 Sym *s;
445
446 s = lookup(n, 0);
447 if(s->type == STEXT){
448 if(s->sig == 0)
449 s->sig = SIGNINTERN;
450 }
451 else if(s->type == 0 || s->type == SXREF)
452 s->type = SUNDEF;
453 }
454
455 void
divsig(void)456 divsig(void)
457 {
458 sigdiv("_div");
459 sigdiv("_divu");
460 sigdiv("_mod");
461 sigdiv("_modu");
462 }
463
464 static void
sdiv(Sym * s)465 sdiv(Sym *s)
466 {
467 if(s->type == 0 || s->type == SXREF){
468 /* undefsym(s); */
469 s->type = SXREF;
470 if(s->sig == 0)
471 s->sig = SIGNINTERN;
472 s->subtype = SIMPORT;
473 }
474 else if(s->type != STEXT)
475 diag("undefined: %s", s->name);
476 }
477
478 void
initdiv(void)479 initdiv(void)
480 {
481 Sym *s2, *s3, *s4, *s5;
482 Prog *p;
483
484 if(prog_div != P)
485 return;
486 sym_div = s2 = lookup("_div", 0);
487 sym_divu = s3 = lookup("_divu", 0);
488 sym_mod = s4 = lookup("_mod", 0);
489 sym_modu = s5 = lookup("_modu", 0);
490 if(dlm) {
491 sdiv(s2); if(s2->type == SXREF) prog_div = UP;
492 sdiv(s3); if(s3->type == SXREF) prog_divu = UP;
493 sdiv(s4); if(s4->type == SXREF) prog_mod = UP;
494 sdiv(s5); if(s5->type == SXREF) prog_modu = UP;
495 }
496 for(p = firstp; p != P; p = p->link)
497 if(p->as == ATEXT) {
498 if(p->from.sym == s2)
499 prog_div = p;
500 if(p->from.sym == s3)
501 prog_divu = p;
502 if(p->from.sym == s4)
503 prog_mod = p;
504 if(p->from.sym == s5)
505 prog_modu = p;
506 }
507 if(prog_div == P) {
508 diag("undefined: %s", s2->name);
509 prog_div = curtext;
510 }
511 if(prog_divu == P) {
512 diag("undefined: %s", s3->name);
513 prog_divu = curtext;
514 }
515 if(prog_mod == P) {
516 diag("undefined: %s", s4->name);
517 prog_mod = curtext;
518 }
519 if(prog_modu == P) {
520 diag("undefined: %s", s5->name);
521 prog_modu = curtext;
522 }
523 }
524
525 void
nocache(Prog * p)526 nocache(Prog *p)
527 {
528 p->optab = 0;
529 p->from.class = 0;
530 p->to.class = 0;
531 }
532