Pristine Ack-5.5
[Ack-5.5.git] / mach / sparc / ce / cache.c.x
1 /* cache.c */
2
3 #include <stdio.h>
4 #include <assert.h>
5 #include <alloc.h>
6 #include "mach.h"
7
8 #ifdef __STDC__
9 #include <string.h>
10 #else
11 extern char *strcpy();
12 #endif
13
14 #define free_reg_num(i) if (1) { assert(reg[i].inuse > 0); reg[i].inuse--; if (debug) fprintf(stderr,"free_reg(%s)\n", regnam[i]); } else
15
16 #define POP1 cache_need(1);
17 #define POP2 { --tos; assert(c_count); --c_count; }
18
19 static int indent_count = 0;
20
21 #define enter(x) indent_count++;
22 #define indent() { int i = indent_count; while (i--) putc('\t', stderr); }
23 #define leave(x) indent_count--;
24
25 /* procedures:
26                 const13(int)            boolean proc
27                 init_cache()            mandatory
28                 free_reg(reg_t)
29                 forced_alloc_reg(reg_t)
30                 soft_alloc_reg(reg_t)
31                 change_reg(reg_t)       used when reg on stack has changed
32                 type_of_tos()           bit-field representation of ext/reg/cst
33                 inc_tos(int)            tos->cst += n
34                 push_const(int)
35                 push_reg(reg_t)
36                 push_ext(char *)
37                 flush_cache()           after branches and labels
38                 cache_read(int)         read-ahead. optimization only
39                 dump_cache(File *)      debug info: show current stack
40                 pop_nop()               remove element from cache
41
42                 reg_t alloc_reg()
43                 reg_t pop_reg()
44                 reg_t pop_reg_c13(char*)
45
46                 arith pop_const(char *)
47                 arith top_const()
48
49                 alloc_float, alloc_double, free_double,
50                 pop_float, pop_double, push_float, push_double
51
52 */
53
54 typedef struct regdat_t {
55                 int     inuse;          /* free == 0, otherwise #owners */
56 } regdat_t;
57 /*
58 typedef struct cache_elt {
59         reg_t   reg, reg2;
60         char    *ext;
61         arith   cst;
62 } cache_elt;
63 */
64
65 #define REG_NUM(r) (((char(*)[8])(r))-regnam)
66
67 static char regnam[][8] = {
68 /*x*/   "%g0", "%g1", "%g2", "%g3", "%g4", "%g5", "%g6", "%g7",
69 /*x*/   "%i0", "%i1", "%i2", "%i3", "%i4", "%i5", "%i6", "%i7",
70 /*x*/   "%l0", "%l1", "%l2", "%l3", "%l4", "%l5", "%l6", "%l7",
71 /*x*/   "%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%o6", "%o7",
72 /*x*/   "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7",
73 /*x*/   "%f8", "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15",
74 /*x*/   "%f16", "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23",
75 /*x*/   "%f24", "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31"
76 };
77
78 reg_t reg_g0, reg_g1, reg_g2, reg_g3, reg_g4, reg_g5, reg_g6, reg_g7;
79 reg_t reg_i0, reg_i1, reg_i2, reg_i3, reg_i4, reg_i5, reg_i6, reg_i7;
80 reg_t reg_l0, reg_l1, reg_l2, reg_l3, reg_l4, reg_l5, reg_l6, reg_l7;
81 reg_t reg_o0, reg_o1, reg_o2, reg_o3, reg_o4, reg_o5, reg_o6, reg_o7;
82 reg_t reg_f0;
83 reg_t reg_sp, reg_lb, reg_gap;
84 reg_t reg_tmp, reg_lin, reg_fil;
85
86 static struct regdat_t reg[NR_REGS];
87
88 #define POP_SIZE 1      /* maybe >1  (read-ahead cache) or explicit?! */
89 #define CACHE_SIZE 32   /* ? */
90 #define LO_GLOB         0
91 #define HI_GLOB         7
92 #define LO_IN           8
93 #define HI_IN           15
94 #define LO_LOC          16
95 #define HI_LOC          23
96 #define LO_OUT          24
97 #define HI_OUT          31
98 #define LO_FLOAT        32
99 #define HI_FLOAT        63
100
101 const13(x) 
102 {
103         return (x < 4096 && x >= -4096);
104 }
105
106 static struct cache_elt cache[CACHE_SIZE], *tos = 0;
107 static int c_count = 0;
108 static const_str_t s;
109
110 _PROTOTYPE(static void panic, (char*));
111 _PROTOTYPE(static void dump_cache, (File *stream));
112 _PROTOTYPE(static int cache_read, (int n, int i));
113 _PROTOTYPE(static void flush_part_cache, (int c, int r, int f, int d));
114 _PROTOTYPE(static void subst_reg, (reg_t, reg_t));
115
116 static void panic(s)
117 char *s;
118 {
119         printf("PANIC: %s\n", s);
120         exit(1);
121 }
122
123 void init_cache()
124 {
125         int i;
126
127         for (i = 0; i < NR_REGS; i++)
128                 reg[i].inuse = 0;
129
130         reg_g0 = regnam[000];
131         reg_g1 = regnam[001];
132         reg_g2 = regnam[002];
133         reg_g3 = regnam[003];
134         reg_g4 = regnam[004];
135         reg_g5 = regnam[005];
136         reg_g6 = regnam[006];
137         reg_g7 = regnam[007];
138
139         reg_i0 = regnam[010];
140         reg_i1 = regnam[011];
141         reg_i2 = regnam[012];
142         reg_i3 = regnam[013];
143         reg_i4 = regnam[014];
144         reg_i5 = regnam[015];
145         reg_i6 = regnam[016];
146         reg_i7 = regnam[017];
147
148         reg_l0 = regnam[020];
149         reg_l1 = regnam[021];
150         reg_l2 = regnam[022];
151         reg_l3 = regnam[023];
152         reg_l4 = regnam[024];
153         reg_l5 = regnam[025];
154         reg_l6 = regnam[026];
155         reg_l7 = regnam[027];
156
157         reg_o0 = regnam[030];
158         reg_o1 = regnam[031];
159         reg_o2 = regnam[032];
160         reg_o3 = regnam[033];
161         reg_o4 = regnam[034];
162         reg_o5 = regnam[035];
163         reg_o6 = regnam[036];
164         reg_o7 = regnam[037];
165
166         reg_f0 = regnam[040];
167
168         reg_sp = reg_l0;
169         reg_lb = reg_l1;
170         reg_gap = reg_g4;
171         reg_tmp = reg_o7;
172         forced_alloc_reg(reg_g0);       /* can not be used as a reg */
173         forced_alloc_reg(reg_o6);
174         forced_alloc_reg(reg_o7);
175         forced_alloc_reg(reg_i6);
176         forced_alloc_reg(reg_i7);
177 }
178
179 static void flush_part_cache(n,r,f,d)
180 int n,r,f,d;
181 {
182 /* free at least n entries, r integer registers, f float regs and d double regs
183  */
184         int i, ready;
185         int rn, j;
186         const_str_t i_str, e_str, n_str;
187         char *ext, R1, R2;
188         reg_t rh, rt;
189
190 enter("flush_part_cache");
191         for (i = 0; i < c_count; i++)
192         {
193                 if (i >= n && !r && !f && !d)
194                         break;
195                 if (cache[i].reg != reg_g0)
196                 {
197                         rn= REG_NUM(cache[i].reg);
198                         free_reg_num(rn);
199                         if (!reg[rn].inuse)
200                                 if (rn<LO_FLOAT)
201                                 {
202                                         if (r)
203                                                 r--;
204                                 }
205                                 else
206                                 {
207                                         if (d && (((rn & 1) &&
208                                         !reg[rn-1].inuse) ||
209                                         (!(rn & 1) && !reg[rn+1].inuse)))
210                                                 d--;
211                                         if (f)
212                                                 f--;
213                                 }
214                 }
215                 if (cache[i].reg2 != reg_g0)
216                 {
217                         rn= REG_NUM(cache[i].reg2);
218                         free_reg_num(rn);
219                         if (!reg[rn].inuse)
220                                 if (rn<LO_FLOAT)
221                                 {
222                                         if (r)
223                                                 r--;
224                                 }
225                                 else
226                                 {
227                                         if (d && (((rn & 1) &&
228                                         !reg[rn-1].inuse) ||
229                                         (!(rn & 1) && !reg[rn+1].inuse)))
230                                                 d--;
231                                         if (f)
232                                                 f--;
233                                 }
234                 }
235         }
236         if (r || f || d)
237                 panic ("can't free enough registers");
238         j = i;
239         if (i)
240         {
241                 sprint (i_str, "%d", 4*i);
242                 "dec    $i_str, $reg_sp";
243                 while (i--)
244                 {
245                         sprint(i_str, "%d", 4*(j-1-i));
246                         if (cache[i].ext)
247                         {
248                                 ext= cache[i].ext;
249                                 sprint (e_str, "%d", cache[i].cst);
250                                 "set    $ext+$e_str, $reg_tmp";
251                                 "st     $reg_tmp, [$reg_sp+$i_str]";
252                                 free(ext);
253                         }
254                         else
255                         {
256                                 if (cache[i].reg2 != reg_g0)
257                                 {
258                                         rt = cache[i].reg;
259                                         rh = cache[i].reg2;
260                                         "add    $rt, $rh, $reg_tmp";
261                                         cache[i].reg = reg_tmp;
262                                         cache[i].reg2 = reg_g0;
263                                 }
264                                 if (!const13(cache[i].cst))
265                                 {
266                                         sprint(n_str, "%d",
267                                                 cache[i].cst);
268                                         "sethi  %hi($n_str), $reg_tmp";
269                                         if (cache[i].reg != reg_g0)
270                                         {
271                                                 rt = cache[i].reg;
272                                                 "add    $reg_tmp, $rt, $reg_tmp";
273                                         }
274                                         rh= reg_tmp;
275                                         cache[i].cst &= 0x3ff;
276                                 }
277                                 else {
278                                         rh= cache[i].reg;
279                                 }
280                                 if (cache[i].cst)
281                                 {
282                                         sprint(n_str, "%d", cache[i].cst);
283                                         "add    $rh, $n_str, $reg_tmp";
284                                         rh= reg_tmp;
285                                 }
286                                 "st     $rh, [$reg_sp+$i_str]";
287                         }
288                 }
289                 for (i= j; i < c_count; i++)
290                         cache[i-j]= cache[i];
291                 c_count -= j;
292                 tos= &cache[c_count-1];
293         }
294 leave("flush_part_cache");
295 }
296
297 reg_t alloc_reg()
298 {
299         int i;
300         reg_t res = NULL;
301
302 enter("alloc_reg");
303         for (i = LO_GLOB+1 /* SPEED-HACK */; i <= HI_GLOB; i++) {
304                 if (reg[i].inuse)
305                         continue;
306                 reg[i].inuse = 1;       /* allocate */
307                 res = regnam[i];
308                 break;
309         }
310         if (!res)
311                 for (i = LO_IN; i <= HI_IN; i++) {
312                         if (reg[i].inuse)
313                                 continue;
314                         reg[i].inuse = 1;       /* allocate */
315                         res = regnam[i];
316                         break;
317                 }
318                 if (!res)
319                         for (i = LO_LOC; i <= HI_LOC; i++) {
320                                 if (reg[i].inuse)
321                                         continue;
322                                 reg[i].inuse = 1;       /* allocate */
323                                 res = regnam[i];
324                                 break;
325                         }
326                         if (!res)
327                                 for (i = LO_OUT; i <= HI_OUT; i++) {
328                                         if (reg[i].inuse)
329                                                 continue;
330                                         reg[i].inuse = 1;       /* allocate */
331                                         res = regnam[i];
332                                         break;
333                                 }
334                                 if (!res) {
335                                         flush_part_cache(c_count/2,1,0,0);
336                                         res = alloc_reg();
337                                 }
338 if (debug) { indent(); fprintf(stderr,"alloc_reg() = %s\n", res ? regnam[i] : "NULL"); }
339 leave("alloc_reg");
340         return res;
341 }
342
343 reg_t alloc_float()
344 {
345         int i;
346         reg_t res = NULL;
347
348 enter("alloc_float");
349         for (i = LO_FLOAT+15; i >= LO_FLOAT; i--) {
350                 if (reg[i].inuse)
351                         continue;
352                 reg[i].inuse = 1;       /* allocate */
353                 res = regnam[i];
354                 break;
355         }
356         if (!res) {
357                 flush_part_cache(c_count/2,0,1,0);
358                 res = alloc_float();
359         }
360 if (debug) { indent(); fprintf(stderr,"alloc_float() = %s\n", res ? regnam[i] : "NULL"); }
361 leave("alloc_float");
362         return res;
363 }
364
365 reg_t alloc_double(sub_reg)
366 reg_t *sub_reg;
367 {
368         int i;
369         reg_t res = NULL;
370
371 enter("alloc_double");
372         for (i = LO_FLOAT+14; i >= LO_FLOAT; i -= 2) {
373                 if (reg[i].inuse || reg[i+1].inuse)
374                         continue;
375                 reg[i].inuse = 1;       /* allocate */
376                 reg[i+1].inuse = 1;     /* allocate */
377 if (debug) { indent(); fprintf(stderr,"alloc_double() = %s\n", regnam[i]); }
378                 if (sub_reg)
379                         *sub_reg= regnam[i+1];
380                 res = regnam[i];
381                 break;
382         }
383         if (!res) {
384                 flush_part_cache(c_count/2,0,0,1);
385                 res = alloc_double(sub_reg);
386         }
387 if (debug) { indent(); fprintf(stderr,"alloc_double() = %s\n", res ? regnam[i] : "NULL"); }
388 leave("alloc_double");
389         return res;
390 }
391
392 reg_t alloc_reg_var()           /* ins and locals only */
393 {
394         int i;
395         reg_t res = NULL;
396
397 enter("alloc_reg_var");
398         for (i = LO_LOC +2 /* SPEED-HACK */; i <= HI_LOC; i++) {
399                 if (reg[i].inuse)
400                         continue;
401                 reg[i].inuse = 1;       /* allocate */
402                 res = regnam[i];
403                 break;
404         }
405         if (!res)
406                 for (i = LO_IN; i <= HI_IN; i++) {
407                         if (reg[i].inuse)
408                                 continue;
409                         reg[i].inuse = 1;       /* allocate */
410                         res = regnam[i];
411                         break;
412                 }
413 if (debug) { indent(); fprintf(stderr,"alloc_reg_var() = %s\n", res ? regnam[i] : "NULL"); }
414 leave("alloc_reg_var");
415         return res;
416 }
417
418 reg_t alloc_float_var()
419 {
420         int i;
421         reg_t res = NULL;
422
423 enter("alloc_float_var");
424         for (i= LO_FLOAT+16; i<= HI_FLOAT; i++)
425         {
426                 if (reg[i].inuse)
427                         continue;
428                 reg[i].inuse = 1;       /* allocate */
429                 res = regnam[i];
430                 break;
431         }
432 if (debug) { indent(); fprintf(stderr,"alloc_reg_var() = %s\n", res ? regnam[i] : "NULL"); }
433 leave("alloc_float_var");
434         return res;
435 }
436
437 reg_t alloc_double_var(sub_reg)
438 reg_t *sub_reg;
439 {
440         int i;
441         reg_t res = NULL;
442
443 enter("alloc_double_var");
444         for (i = LO_FLOAT+16; i < HI_FLOAT; i += 2) {
445                 if (reg[i].inuse || reg[i+1].inuse)
446                         continue;
447                 reg[i].inuse = 1;       /* allocate */
448                 reg[i+1].inuse = 1;     /* allocate */
449 if (debug) { indent(); fprintf(stderr,"alloc_double_var() = %s\n", regnam[i]); }
450                 if (sub_reg)
451                         *sub_reg= regnam[i+1];
452                 res = regnam[i];
453                 break;
454         }
455 if (debug) { indent(); fprintf(stderr,"alloc_double_var() = %s\n", res? regnam[i] : "NULL"); }
456 leave("alloc_double_var");
457         return res;
458 }
459
460 void free_reg(i)
461 reg_t i;
462 {
463         int r;
464
465 enter("free_reg");
466         if (i != 0 && i != reg_g0) {
467                 r = REG_NUM(i);
468                 assert(0 <= r && r <= NR_REGS);
469                 assert(reg[r].inuse > 0);       /* "freeing unused register" */
470                 reg[r].inuse--;
471         }
472 if (debug) { indent(); fprintf(stderr,"free_reg(%s)\n", i); }
473 leave("free_reg");
474 }
475
476 void free_double_reg(i)
477 reg_t i;
478 {
479         int rn;
480
481 enter("free_double_reg");
482         rn= REG_NUM(i);
483         assert (!(rn & 1));
484         free_reg(i);
485         free_reg(regnam[rn+1]);
486 leave("free_double_reg");
487 }
488
489
490 void force_alloc_output()       /* TMP HACK */
491 {
492         int i;
493
494 enter("force_alloc_output");
495 if (debug) { indent(); fprintf(stderr,"force_alloc_output\n"); }
496         for (i = REG_NUM(reg_o0); i <= REG_NUM(reg_o5); i++)
497                 forced_alloc_reg(regnam[i]);
498 leave("force_alloc_output");
499 }
500
501 void free_output()
502 {
503         int i;
504
505 enter("free_output");
506 leave("free_output");
507 if (debug) { indent(); fprintf(stderr,"free_output\n"); }
508         for (i = REG_NUM(reg_o0); i <= REG_NUM(reg_o5); i++) {
509                 assert(reg[i].inuse > 0);
510                 reg[i].inuse--;
511         }
512 }
513
514 void soft_alloc_reg(i)
515 reg_t i;
516 {
517 enter("soft_alloc_reg");
518 if (debug) { indent(); fprintf(stderr,"soft_alloc_reg(%s)\n", i); }
519         /* assert(reg[REG_NUM(i)].inuse); */
520         reg[REG_NUM(i)].inuse++;
521 leave("soft_alloc_reg");
522 }
523
524 void forced_alloc_reg(i)
525 reg_t i;
526 {
527         int r;
528
529 enter("forced_alloc_reg");
530 if (debug) { indent(); fprintf(stderr,"forced_alloc_reg(%s)\n", i); }
531
532         r = REG_NUM(i);
533
534         if (reg[r].inuse) {
535                 reg_t S1;
536                 char *V2;
537
538                 S1 = alloc_reg();
539 if (debug) { indent(); fprintf(stderr,"---> inuse: moving to %s\n", S1); }
540                 "mov    $i, $S1";
541                 subst_reg(i, S1);
542                 free_reg(S1);
543                 if (reg[r].inuse)
544                         panic("forced_alloc_reg: external owners left!");
545         }
546         reg[r].inuse = 1;
547 leave("forced_alloc_reg");
548 }
549
550 void change_reg(r)      /* to be called when register r changes */
551 reg_t r;
552 {
553         int i;
554
555 enter("change_reg");
556 if (debug) { indent(); fprintf(stderr, "change_reg(%s)\n", r); }
557         if (r != reg_g0)
558                 for (i = 0; i < c_count; i++)
559                         if (cache[i].reg == r || cache[i].reg2 == r) {
560                                 reg_t S1;
561
562                                 if (r >= reg_f0) {
563                                         S1 = alloc_float();
564                                         "fmovs  $r, $S1";
565                                 } else {
566                                         S1 = alloc_reg();
567                                         "mov    $r, $S1";
568                                 }
569                                 subst_reg(r, S1);
570                                 free_reg(S1);
571                                 break;
572                         }
573 leave("change_reg");
574 }
575
576 static void subst_reg(old, new)
577 reg_t old, new;
578 {
579         int i;
580
581 enter("subst_reg");
582 if (debug) { indent(); fprintf(stderr,"subst_reg(%s, %s)\n", old, new); }
583         for (i = 0; i < c_count; i++) {
584                 if (cache[i].reg == old) {
585                         cache[i].reg = new;
586                         free_reg(old);
587                         soft_alloc_reg(new);
588                 }
589                 if (cache[i].reg2 == old) {
590                         cache[i].reg2 = new;
591                         free_reg(old);
592                         soft_alloc_reg(new);
593                 }
594         }
595 leave("subst_reg");
596 }
597
598 int type_of_tos()
599 {
600         int r = 0;
601
602         cache_need(1);
603
604         if (tos->ext)
605                 r |= T_ext;
606         if (tos->reg != reg_g0)
607                 if (tos->reg >= reg_f0)
608                         r |= T_float;
609                 else
610                         r |= T_reg;
611         if (tos->reg2 != reg_g0)
612                 if (tos->reg2 >= reg_f0)
613                         r |= T_float2;
614                 else
615                         r |= T_reg2;
616         if (tos->cst)
617                 r |= T_cst;
618         return r;
619 }
620
621 arith top_const()
622 {
623 enter("top_const");
624         assert(type_of_tos() == T_cst);
625 if (debug) { indent(); fprintf(stderr,"top_const()=%d\n", tos->cst); }
626 leave("top_const");
627         return tos->cst;
628 }
629
630 reg_t pop_reg_reg(r)
631 reg_t *r;
632 {
633         reg_t s;
634
635 enter("pop_reg_reg");
636         POP1;
637         if (!(type_of_tos() & T_reg2))
638                 push_reg(pop_reg());
639         assert(r);
640         *r = tos->reg2;
641         s = tos->reg;
642         POP2;
643 if (debug) { indent(); fprintf(stderr,"pop_reg_reg()=%s\n", s); fprint(codefile,"\t\t! "); dump_cache(codefile); }
644 leave("pop_reg_reg");
645         return s;
646 }
647
648 reg_t pop_reg_c13(n)            /* returns reg_t + optional n (as string) */
649 char *n;
650 {
651         reg_t S1, S2, S3;
652         register char *V1;
653         const_str_t V2;
654 enter("pop_reg_c13");
655 if (debug) { indent(); fprintf(stderr,"pop_reg_c13()=...\n"); }
656         *n = '0';
657         *(n+1) = 0;
658         cache_need(1);
659
660         if (tos->reg >= reg_f0) {       /* convert float to int */
661                 S1= pop_float();
662                 S2= alloc_reg();
663                 "st     $S1, [%fp+64]";
664                 "ld     [%fp+64], $S2";
665                 free_reg(S1);
666                 S1 = S2;
667         }
668         else if (tos->reg2 != reg_g0) { /* add integers */
669                 S1 = pop_reg();
670         }
671         else if (tos->ext) {
672                 assert(tos->reg == reg_g0);
673                 S1 = alloc_reg();
674                 V1 = tos->ext;
675                 sprint(V2, "%d", tos->cst);
676                 "sethi  %hi($V1+$V2), $S1";
677                 sprint(n, "%%lo(%s+%d)", tos->ext, tos->cst);
678                 free(V1);
679                 POP2;
680         } else {
681                 S1 = tos->reg;
682                 if (!(const13(tos->cst))) {
683                         S3 = alloc_reg();
684                         sprint(V2, "%d", tos->cst);
685                         "sethi  %hi($V2), $S3";
686                         if (tos->reg != reg_g0) {
687                                 S2 = alloc_reg();
688                                 "add    $S3, $S1, $S2";
689                                 free_reg(S1);
690                                 free_reg(S3);
691                                 S1 = S2;
692                         }
693                         else {
694                                 free_reg(S1);
695                                 S1 = S3;
696                         }
697                         tos->cst &= 0x3FF;
698                 }
699                 sprint(n, "%d", tos->cst);
700                 POP2;
701         }
702 if (debug) { indent(); fprint(codefile, "\t\t! %s+%s cache:", S1, n); dump_cache(codefile);}
703 leave("pop_reg_c13");
704         return S1;
705 }
706
707 reg_t pop_float()
708 {
709         reg_t S1, R1, R2;
710         char *V1, *V2;
711
712 enter("pop_float");
713         cache_need(1);
714         S1 = tos->reg;
715         if (!(type_of_tos() & T_float)) {
716                 S1 = pop_reg();
717                 R2 = alloc_float();
718                 "st     $S1, [%fp+64]";
719                 "ld     [%fp+64], $R2";
720                 free_reg(S1);
721                 S1 = R2;
722         }
723         else if (tos->reg2 >= reg_f0) {
724                 R1 = tos->reg2;
725                 R2 = alloc_float();
726                 "fadds  $S1, $R1, $R2";
727                 free_reg(S1);   
728                 free_reg(R1);   
729                 S1 = R2;
730                 POP2;
731         } else
732                 POP2;
733 if (debug) { indent(); fprint(codefile, "\t\t! %s cache:", S1); dump_cache(codefile); }
734 leave("pop_float");
735         return S1;
736 }
737
738 void inc_tos_reg(r)
739 reg_t r;
740 {
741 enter("inc_tos_reg");
742 if (debug) { indent(); fprintf(stderr, "inc_tos_reg(%s)\n", r); }
743         if (type_of_tos() != T_reg)
744                 push_reg(pop_reg());
745         tos->reg2 = r;
746 if (debug) { indent(); fprint(codefile, "\t\t! "); dump_cache(codefile); }
747 leave("inc_tos_reg");
748 }
749
750 void inc_tos(n)
751 arith n;
752 {
753         reg_t S1;
754         char *V1, *V2;
755
756 enter("inc_tos");
757 if (debug) { indent(); fprintf(stderr,"inc_tos(%d)\n", n); }
758         cache_need(1);
759         if (tos->reg >= reg_f0)
760         {
761                 S1= pop_reg();
762                 push_reg(S1);
763         }
764         else if (tos->reg2 != reg_g0) {
765                 S1= pop_reg();
766                 push_reg(S1);
767         }
768         tos->cst += n;
769 if (debug) { indent(); fprint(codefile, "\t\t! "); dump_cache(codefile); }
770 leave("inc_tos");
771 }
772
773 #define INC_TOS if (c_count >= CACHE_SIZE) flush_part_cache(c_count/2,0,0,0); \
774                         tos = &cache[c_count++];
775
776 void push_const(n)
777 arith n;
778 {
779 enter("push_const");
780         INC_TOS;
781         tos->reg = reg_g0;
782         tos->reg2 = reg_g0;
783         tos->ext = 0;
784         tos->cst = n;
785 if (debug) { indent(); fprint(codefile, "\t\t! "); dump_cache(codefile); }
786 leave("push_const");
787 }
788
789 void push_reg(i)
790 reg_t i;
791 {
792 enter("push_reg");
793         assert(0 <= REG_NUM(i) && REG_NUM(i) < NR_REGS);
794         INC_TOS;
795         tos->reg = i;
796         tos->reg2 = reg_g0;
797         tos->ext = 0;
798         tos->cst = 0;
799 if (debug) { indent(); fprint(codefile, "\t\t! "); dump_cache(codefile); }
800 leave("push_reg");
801 }
802
803
804 void push_double_reg(i)
805 reg_t i;
806 {
807         int rn;
808
809 enter("push_double_reg");
810         rn= REG_NUM(i);
811         assert (!(rn & 1));
812         INC_TOS;
813         tos->ext = 0;
814         tos->cst = 0;
815         tos->reg = regnam[rn+1];
816         tos->reg2 = reg_g0;
817         INC_TOS;
818         tos->ext = 0;
819         tos->cst = 0;
820         tos->reg = i;
821         tos->reg2 = reg_g0;
822 if (debug) { indent(); fprint(codefile, "\t\t! "); dump_cache(codefile); }
823 leave("push_double_reg");
824 }
825
826 void push_ext(s)
827 char *s;
828 {
829         char *p;
830
831 enter("push_ext");
832         p = Malloc(strlen(s)+1);
833
834         INC_TOS;
835         tos->reg = reg_g0;
836         tos->reg2 = reg_g0;
837         tos->ext = strcpy(p, s);
838         tos->cst = 0;
839 if (debug) { indent(); fprint(codefile, "\t\t! "); dump_cache(codefile); }
840 leave("push_ext");
841 }
842
843 arith pop_const(n)
844 char *n;
845 {
846         arith x;
847
848 enter("pop_const");
849         POP1;
850         x = top_const();
851         POP2;
852         if (n)
853                 sprint(n, "%d", x);
854 if (debug) { indent(); fprint(codefile, "\t\t! %d cache:", x); dump_cache(codefile); }
855 leave("pop_const");
856         return x;
857 }
858
859 void pop_reg_as(r)
860 reg_t r;
861 {
862         reg_t S1, S2;
863         register char *V1, *V3;
864         const_str_t V2, c_str;
865         char *tos_ext;
866         reg_t tos_reg, tos_reg2;
867         int tos_cst;
868
869 enter("pop_reg_as");
870 if (debug) { indent(); fprintf(stderr,"pop_reg_as(%s)=...\n", r); }
871         if (c_count == 0) {     /* special case */
872                 "ld     [%l0], $r";
873                 "inc    4, %l0";
874         } else if (r >= reg_f0) {
875                 if (tos->reg < reg_f0)
876                 {
877                         S1= pop_reg();
878                         change_reg(r);
879                         "st     $S1, [%fp+64]";
880                         "ld     [%fp+64], $r";
881                         free_reg(S1);
882                 }
883                 else
884                 {
885                         if (tos->reg2 == reg_g0) {
886                                 S1= pop_float();
887                                 change_reg(r);
888                                 if (S1 != r)
889                                         "fmovs  $S1, $r";
890                                 free_reg(S1);
891                         } else {
892                                 V1 = tos->reg;
893                                 V3 = tos->reg2;
894                                 POP2;
895                                 change_reg(r);
896                                 "fadds  $V1, $V3, $r";
897                                 free_reg(V1);
898                                 free_reg(V3);
899                         }
900                 }
901         } else if (tos->reg >= reg_f0) {
902                 S1= pop_float();
903                 change_reg(r);
904                 "st     $S1, [%fp+64]";
905                 "ld     [%fp+64], $r";
906                 free_reg(S1);
907         } else if (tos->ext) {
908                 assert(tos->reg == reg_g0);
909                 V1 = tos->ext;
910                 sprint(V2, "%d", tos->cst);
911                 "set    $V1+$V2, $r";
912                 free(V1);
913                 POP2;
914         } else {
915                 POP1;
916                 tos_reg= tos->reg;
917                 tos_reg2= tos->reg2;
918                 tos_cst= tos->cst;
919                 POP2;
920                 change_reg(r);
921                 if (!const13(tos_cst))
922                 {
923                         assert (tos_reg2 == reg_g0);
924                         if (tos_reg != reg_g0 || (tos_cst & 0x3ff))
925                                 tos_reg2= alloc_reg();
926                         else
927                         {
928                                 soft_alloc_reg(r);
929                                 tos_reg2= r;
930                         }
931                         sprint(c_str, "%d", tos_cst);
932                         "sethi  %hi($c_str), $tos_reg2";
933                         tos_cst &= 0x3ff;
934                         if (tos_reg == reg_g0)
935                         {
936                                 tos_reg= tos_reg2;
937                                 tos_reg2= reg_g0;
938                         }
939                 }
940                 if (tos_reg2 != reg_g0)
941                 {
942                         assert (tos_reg != reg_g0);
943                         if (tos_cst)
944                                 S1= alloc_reg();
945                         else
946                         {
947                                 soft_alloc_reg(r);
948                                 S1= r;
949                         }
950                         "add    $tos_reg, $tos_reg2, $S1";
951                         free_reg(tos_reg);
952                         free_reg(tos_reg2);
953                         tos_reg= S1;
954                         tos_reg2= reg_g0;
955                 }
956                 if (tos_cst)
957                 {
958                         sprint(c_str, "%d", tos_cst);
959                         soft_alloc_reg(r);
960                         "add    $tos_reg, $c_str, $r";
961                         free_reg(tos_reg);
962                         tos_reg= r;
963                 }
964                 if (tos_reg != r)
965                         "mov    $tos_reg, $r";
966                 free_reg(tos_reg);
967         }
968 leave("pop_reg_as");
969 }
970
971 void pop_double_reg_as(rdl)
972 reg_t rdl;
973 {
974         reg_t rl, rh;
975         reg_t rdh;
976         reg_t t;
977         int rn;
978         
979 enter("pop_double_reg_as");
980         rn= REG_NUM(rdl);
981         assert (!(rn & 1));
982         rdh= regnam[rn+1];
983         if (rdl>= reg_f0)
984         {
985                 if (c_count == 0) {
986                         "ld     [%l0], $rdl";
987                         "ld     [%l0+4], $rdh";
988                         "inc    8, %l0";
989                 } else {
990                         if (type_of_tos() & T_float)
991                                 rl= pop_float();
992                         else
993                                 rl= pop_reg();
994                         if (type_of_tos() & T_float)
995                                 rh= pop_float();
996                         else
997                                 rh= pop_reg();
998                         change_reg(rdl);
999                         change_reg(rdh);
1000                         if (rl < reg_f0 && rh < reg_f0)
1001                         {
1002                                 "st     $rl, [%fp+64]";
1003                                 "st     $rh, [%fp+68]";
1004                                 "ldd    [%fp+64], $rdl";
1005                                 free_reg(rl);
1006                                 free_reg(rh);
1007                         }
1008                         else if (rl < reg_f0)
1009                         {
1010                                 if (rh != rdh)
1011                                         "fmovs  $rh, $rdh";
1012                                 "st     $rl, [%fp+64]";
1013                                 "ld     [%fp+64], $rdl";
1014                                 free_reg(rl);
1015                                 free_reg(rh);
1016                         }
1017                         else if (rh < reg_f0)
1018                         {
1019                                 if (rl != rdl)
1020                                         "fmovs  $rl, $rdl";
1021                                 "st     $rh, [%fp+64]";
1022                                 "ld     [%fp+64], $rdh";
1023                                 free_reg(rl);
1024                                 free_reg(rh);
1025                         } else {
1026                                 if (rdl == rl)
1027                                         free_reg(rl);
1028                                 if (rdh == rh)
1029                                         free_reg(rh);
1030                                 if (rdl == rh && rdh == rl)
1031                                 {
1032                                         t= alloc_float();
1033                                         "fmovs  $rl, $t";
1034                                         free_reg(rl);
1035                                         rl= t;
1036                                 }
1037                                 if (rdl != rl && rdl != rh)
1038                                 {
1039                                         "fmovs  $rl, $rdl";
1040                                         free_reg(rl);
1041                                         rl= rdl;
1042                                 }
1043                                 if (rdh != rh && rdh != rl)
1044                                 {
1045                                         "fmovs  $rh, $rdh";
1046                                         free_reg(rh);
1047                                         rh= rdh;
1048                                 }
1049                                 if (rdl != rl && rdl != rh)
1050                                 {
1051                                         "fmovs  $rl, $rdl";
1052                                         free_reg(rl);
1053                                         rl= rdl;
1054                                 }
1055                                 assert (rdl == rl && rdh == rh);
1056                         }
1057                 }
1058         }
1059         else
1060         {
1061                 pop_reg_as (rdl);
1062                 pop_reg_as (rdh);
1063         }
1064 leave("pop_double_reg_as");
1065 }
1066
1067                         
1068                 
1069 reg_t pop_reg()
1070 {
1071         reg_t S1;
1072
1073 enter("pop_reg");
1074         POP1;
1075         if (type_of_tos() == T_reg) {
1076                 S1 = tos->reg;
1077                 POP2;
1078         } else {
1079                 S1 = alloc_reg();
1080                 pop_reg_as(S1);
1081         }
1082 if (debug) { indent(); fprint(codefile, "\t\t! %s cache:", S1); dump_cache(codefile); }
1083 leave("pop_reg");
1084         return S1;
1085 }
1086
1087
1088 reg_t pop_double(sub_reg)       /* pop_double_float actually */
1089 reg_t *sub_reg;
1090 {
1091         reg_t R1, R2, R3, R4;
1092         char *V1, *V2;
1093
1094 enter("pop_double");
1095         if (c_count == 0) {
1096                 R1 = alloc_double(&R2);
1097                 "ld     [%l0], $R1";
1098                 "ld     [%l0+4], $R2";
1099                 "inc    8, %l0";
1100                 if (sub_reg)
1101                         *sub_reg = R2;
1102         } else {
1103                 cache_need(2);
1104                 if (tos->reg >= reg_f0 && tos[-1].reg >= reg_f0 &&
1105                         REG_NUM(tos->reg) == REG_NUM(tos[-1].reg)-1 &&
1106                         tos->reg2 == reg_g0 && tos[-1].reg2 == reg_g0)
1107                 {
1108                         R1= tos->reg;
1109                         if (sub_reg)
1110                                 *sub_reg= tos[-1].reg;
1111                         POP2;
1112                         POP2;
1113                 } else {
1114                         R1= alloc_double(&R2);
1115                         if (sub_reg)
1116                                 *sub_reg= R2;
1117                         if (tos->reg >= reg_f0 || tos[-1].reg >= reg_f0)
1118                         {
1119                                 pop_reg_as(R1);
1120                                 pop_reg_as(R2);
1121                         } else {
1122                                 /* two normal registers */
1123                                 R3= pop_reg();
1124                                 R4= pop_reg();
1125                                 "st     $R3, [%fp+64]";
1126                                 "st     $R4, [%fp+68]";
1127                                 "ldd    [%fp+64], $R1";
1128                                 free_reg(R3);
1129                                 free_reg(R4);
1130                         }
1131                 }
1132         }
1133 leave("pop_double");
1134         return R1;
1135 }
1136
1137 void pop_nop(i)
1138 int i;
1139 {
1140         const_str_t V1;
1141         int j = i;
1142
1143 enter("pop_nop");
1144         while (c_count && i) {
1145                 i--;
1146                 POP1;
1147                 free_reg(tos->reg);
1148                 free_reg(tos->reg2);
1149                 if (tos->ext)
1150                         free(tos->ext);
1151                 POP2;
1152         }
1153         if (i) {
1154                 sprint(V1, "%d", 4*i);
1155                 if (const13(4*i)) {
1156                         "inc    $V1, %l0";
1157                 } else {
1158                         "set    $V1, $reg_tmp";
1159                         "add    %l0, $reg_tmp, %l0";
1160                 }
1161         }
1162 if (debug) { indent(); fprint(codefile, "\t\t! %dw cache:",j); dump_cache(codefile); }
1163 leave("pop_nop");
1164 }
1165
1166 check_cache()
1167 {
1168         int i;
1169 if (debug)
1170         for (i = 0; i < NR_REGS; i++)
1171                 fprintf(stderr, "%c", reg[i].inuse ? (reg[i].inuse)+48 : '.');
1172         fprintf(stderr, "\n");
1173 }
1174
1175 void flush_cache()              /* flush the cache onto the stack */
1176 {
1177 enter("flush_cache");
1178
1179 if (debug) { indent(); fprintf(stderr,"flush_cache\n"); }
1180         if (c_count)
1181                 flush_part_cache(c_count, 0, 0, 0);
1182
1183         /* TEST */
1184 if (debug)
1185         check_cache();
1186 leave("flush_cache");
1187 }
1188
1189 void cache_need(n)
1190 int n;
1191 {
1192 enter("cache_need");
1193         if (c_count < n)
1194                 (void) cache_read(n, 0);
1195         assert(c_count >= n);
1196 leave("cache_need");
1197 }
1198
1199 static int cache_read(n, i)
1200 int n;
1201 int i;
1202 {
1203         const_str_t V1;
1204         reg_t S1;
1205         int j;
1206         int old_c_count;
1207
1208 enter("cache_read");
1209 if (debug) { indent(); fprintf(stderr,"cache_read(%d, %d)\n", n,i); }
1210         if (i+c_count<n)
1211         {
1212                 S1= alloc_reg();
1213                 old_c_count = cache_read(n, i+1);
1214
1215                 sprint(V1, "%d", (old_c_count-1-i) * 4);
1216                 "ld     [%l0+$V1], $S1";
1217                 cache[i].reg= S1;
1218                 cache[i].reg2= reg_g0;
1219                 cache[i].ext= 0;
1220                 cache[i].cst= 0;
1221                 if (!i)
1222                 {
1223                         sprint(V1, "%d", (old_c_count)*4);
1224                         "add    $reg_sp, $V1, $reg_sp";
1225                 }
1226         }
1227         else
1228         {
1229                 assert (i);
1230                 for (j= c_count-1; j>=0; j--)
1231                         cache[j+i]= cache[j];
1232                 c_count += i;
1233                 tos= &cache[c_count-1];
1234                 old_c_count = i;
1235         }
1236 leave("cache_read");
1237         return old_c_count;
1238 }
1239
1240 static void dump_cache(stream)          /* to codefile! */
1241 File *stream;
1242 {
1243         int i;
1244
1245         assert (c_count >= 0);
1246         for (i = c_count -1; i >= 0; i--) {
1247                 if (cache[i].ext)
1248                         fprint(stream, "%s", cache[i].ext);
1249                 if (cache[i].reg != reg_g0) {
1250                         if (cache[i].ext)
1251                                 fprint(stream, "+");
1252                         fprint(stream, "%s", cache[i].reg);
1253                         if (cache[i].reg2 != reg_g0) {
1254                                 fprint(stream, "+");
1255                                 fprint(stream, "%s", cache[i].reg2);
1256                         }
1257                 }
1258                 if (cache[i].cst || (!cache[i].ext && cache[i].reg == reg_g0)) {
1259                         if (cache[i].ext || cache[i].reg != reg_g0)
1260                                 fprint(stream, "+");
1261                         fprint(stream, "%d", cache[i].cst);
1262                 }
1263                 fprint(stream, " ");
1264         }
1265         fprint(stream, "\n");
1266 if (debug) check_cache();
1267 }
1268
1269 void dup_tos(n)
1270 int n;
1271 {
1272         reg_t a;
1273         int i;
1274         const_str_t i_str;
1275
1276 enter("dup_tos");
1277         for (i = 0;i < n; i++) {
1278                 INC_TOS;
1279                 tos->reg = reg_g0;
1280                 tos->reg2 = reg_g0;
1281                 tos->cst = 0;
1282                 tos->ext = 0;
1283                 if (c_count > n) {
1284                         char *ext;
1285
1286                         *tos = tos[-n];
1287                         if (tos->ext)
1288                         {
1289                                 ext= Malloc(strlen(tos->ext)+1);
1290                                 strcpy(ext, tos->ext);
1291                                 tos->ext= ext;
1292                         }
1293                         soft_alloc_reg(tos->reg);
1294                         soft_alloc_reg(tos->reg2);
1295                 } else {
1296                         a= alloc_reg();
1297                         sprint(i_str, "%d", (n-c_count)*4);
1298                         "ld     [$reg_sp+$i_str], $a";
1299                         tos->reg = a;
1300                 }
1301         }
1302 if (debug) { indent(); fprint(codefile, "\t\t! "); dump_cache(codefile); }
1303 leave("dup_tos");
1304 }