Pristine Ack-5.5
[Ack-5.5.git] / mach / sparc / ce / cache.c
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 fprint ( codefile,
243                 "dec    %s, %s\n",i_str,reg_sp
244 );
245                 while (i--)
246                 {
247                         sprint(i_str, "%d", 4*(j-1-i));
248                         if (cache[i].ext)
249                         {
250                                 ext= cache[i].ext;
251                                 sprint (e_str, "%d", cache[i].cst);
252 fprint ( codefile,
253                                 "set    %s+%s, %s\n",ext,e_str,reg_tmp
254 );
255 fprint ( codefile,
256                                 "st     %s, [%s+%s]\n",reg_tmp,reg_sp,i_str
257 );
258                                 free(ext);
259                         }
260                         else
261                         {
262                                 if (cache[i].reg2 != reg_g0)
263                                 {
264                                         rt = cache[i].reg;
265                                         rh = cache[i].reg2;
266 fprint ( codefile,
267                                         "add    %s, %s, %s\n",rt,rh,reg_tmp
268 );
269                                         cache[i].reg = reg_tmp;
270                                         cache[i].reg2 = reg_g0;
271                                 }
272                                 if (!const13(cache[i].cst))
273                                 {
274                                         sprint(n_str, "%d",
275                                                 cache[i].cst);
276 fprint ( codefile,
277                                         "sethi  %%hi(%s), %s\n",n_str,reg_tmp
278 );
279                                         if (cache[i].reg != reg_g0)
280                                         {
281                                                 rt = cache[i].reg;
282 fprint ( codefile,
283                                                 "add    %s, %s, %s\n",reg_tmp,rt,reg_tmp
284 );
285                                         }
286                                         rh= reg_tmp;
287                                         cache[i].cst &= 0x3ff;
288                                 }
289                                 else {
290                                         rh= cache[i].reg;
291                                 }
292                                 if (cache[i].cst)
293                                 {
294                                         sprint(n_str, "%d", cache[i].cst);
295 fprint ( codefile,
296                                         "add    %s, %s, %s\n",rh,n_str,reg_tmp
297 );
298                                         rh= reg_tmp;
299                                 }
300 fprint ( codefile,
301                                 "st     %s, [%s+%s]\n",rh,reg_sp,i_str
302 );
303                         }
304                 }
305                 for (i= j; i < c_count; i++)
306                         cache[i-j]= cache[i];
307                 c_count -= j;
308                 tos= &cache[c_count-1];
309         }
310 leave("flush_part_cache");
311 }
312
313 reg_t alloc_reg()
314 {
315         int i;
316         reg_t res = NULL;
317
318 enter("alloc_reg");
319         for (i = LO_GLOB+1 /* SPEED-HACK */; i <= HI_GLOB; 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_IN; i <= HI_IN; 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                         for (i = LO_LOC; i <= HI_LOC; i++) {
336                                 if (reg[i].inuse)
337                                         continue;
338                                 reg[i].inuse = 1;       /* allocate */
339                                 res = regnam[i];
340                                 break;
341                         }
342                         if (!res)
343                                 for (i = LO_OUT; i <= HI_OUT; i++) {
344                                         if (reg[i].inuse)
345                                                 continue;
346                                         reg[i].inuse = 1;       /* allocate */
347                                         res = regnam[i];
348                                         break;
349                                 }
350                                 if (!res) {
351                                         flush_part_cache(c_count/2,1,0,0);
352                                         res = alloc_reg();
353                                 }
354 if (debug) { indent(); fprintf(stderr,"alloc_reg() = %s\n", res ? regnam[i] : "NULL"); }
355 leave("alloc_reg");
356         return res;
357 }
358
359 reg_t alloc_float()
360 {
361         int i;
362         reg_t res = NULL;
363
364 enter("alloc_float");
365         for (i = LO_FLOAT+15; i >= LO_FLOAT; i--) {
366                 if (reg[i].inuse)
367                         continue;
368                 reg[i].inuse = 1;       /* allocate */
369                 res = regnam[i];
370                 break;
371         }
372         if (!res) {
373                 flush_part_cache(c_count/2,0,1,0);
374                 res = alloc_float();
375         }
376 if (debug) { indent(); fprintf(stderr,"alloc_float() = %s\n", res ? regnam[i] : "NULL"); }
377 leave("alloc_float");
378         return res;
379 }
380
381 reg_t alloc_double(sub_reg)
382 reg_t *sub_reg;
383 {
384         int i;
385         reg_t res = NULL;
386
387 enter("alloc_double");
388         for (i = LO_FLOAT+14; i >= LO_FLOAT; i -= 2) {
389                 if (reg[i].inuse || reg[i+1].inuse)
390                         continue;
391                 reg[i].inuse = 1;       /* allocate */
392                 reg[i+1].inuse = 1;     /* allocate */
393 if (debug) { indent(); fprintf(stderr,"alloc_double() = %s\n", regnam[i]); }
394                 if (sub_reg)
395                         *sub_reg= regnam[i+1];
396                 res = regnam[i];
397                 break;
398         }
399         if (!res) {
400                 flush_part_cache(c_count/2,0,0,1);
401                 res = alloc_double(sub_reg);
402         }
403 if (debug) { indent(); fprintf(stderr,"alloc_double() = %s\n", res ? regnam[i] : "NULL"); }
404 leave("alloc_double");
405         return res;
406 }
407
408 reg_t alloc_reg_var()           /* ins and locals only */
409 {
410         int i;
411         reg_t res = NULL;
412
413 enter("alloc_reg_var");
414         for (i = LO_LOC +2 /* SPEED-HACK */; i <= HI_LOC; i++) {
415                 if (reg[i].inuse)
416                         continue;
417                 reg[i].inuse = 1;       /* allocate */
418                 res = regnam[i];
419                 break;
420         }
421         if (!res)
422                 for (i = LO_IN; i <= HI_IN; i++) {
423                         if (reg[i].inuse)
424                                 continue;
425                         reg[i].inuse = 1;       /* allocate */
426                         res = regnam[i];
427                         break;
428                 }
429 if (debug) { indent(); fprintf(stderr,"alloc_reg_var() = %s\n", res ? regnam[i] : "NULL"); }
430 leave("alloc_reg_var");
431         return res;
432 }
433
434 reg_t alloc_float_var()
435 {
436         int i;
437         reg_t res = NULL;
438
439 enter("alloc_float_var");
440         for (i= LO_FLOAT+16; i<= HI_FLOAT; i++)
441         {
442                 if (reg[i].inuse)
443                         continue;
444                 reg[i].inuse = 1;       /* allocate */
445                 res = regnam[i];
446                 break;
447         }
448 if (debug) { indent(); fprintf(stderr,"alloc_reg_var() = %s\n", res ? regnam[i] : "NULL"); }
449 leave("alloc_float_var");
450         return res;
451 }
452
453 reg_t alloc_double_var(sub_reg)
454 reg_t *sub_reg;
455 {
456         int i;
457         reg_t res = NULL;
458
459 enter("alloc_double_var");
460         for (i = LO_FLOAT+16; i < HI_FLOAT; i += 2) {
461                 if (reg[i].inuse || reg[i+1].inuse)
462                         continue;
463                 reg[i].inuse = 1;       /* allocate */
464                 reg[i+1].inuse = 1;     /* allocate */
465 if (debug) { indent(); fprintf(stderr,"alloc_double_var() = %s\n", regnam[i]); }
466                 if (sub_reg)
467                         *sub_reg= regnam[i+1];
468                 res = regnam[i];
469                 break;
470         }
471 if (debug) { indent(); fprintf(stderr,"alloc_double_var() = %s\n", res? regnam[i] : "NULL"); }
472 leave("alloc_double_var");
473         return res;
474 }
475
476 void free_reg(i)
477 reg_t i;
478 {
479         int r;
480
481 enter("free_reg");
482         if (i != 0 && i != reg_g0) {
483                 r = REG_NUM(i);
484                 assert(0 <= r && r <= NR_REGS);
485                 assert(reg[r].inuse > 0);       /* "freeing unused register" */
486                 reg[r].inuse--;
487         }
488 if (debug) { indent(); fprintf(stderr,"free_reg(%s)\n", i); }
489 leave("free_reg");
490 }
491
492 void free_double_reg(i)
493 reg_t i;
494 {
495         int rn;
496
497 enter("free_double_reg");
498         rn= REG_NUM(i);
499         assert (!(rn & 1));
500         free_reg(i);
501         free_reg(regnam[rn+1]);
502 leave("free_double_reg");
503 }
504
505
506 void force_alloc_output()       /* TMP HACK */
507 {
508         int i;
509
510 enter("force_alloc_output");
511 if (debug) { indent(); fprintf(stderr,"force_alloc_output\n"); }
512         for (i = REG_NUM(reg_o0); i <= REG_NUM(reg_o5); i++)
513                 forced_alloc_reg(regnam[i]);
514 leave("force_alloc_output");
515 }
516
517 void free_output()
518 {
519         int i;
520
521 enter("free_output");
522 leave("free_output");
523 if (debug) { indent(); fprintf(stderr,"free_output\n"); }
524         for (i = REG_NUM(reg_o0); i <= REG_NUM(reg_o5); i++) {
525                 assert(reg[i].inuse > 0);
526                 reg[i].inuse--;
527         }
528 }
529
530 void soft_alloc_reg(i)
531 reg_t i;
532 {
533 enter("soft_alloc_reg");
534 if (debug) { indent(); fprintf(stderr,"soft_alloc_reg(%s)\n", i); }
535         /* assert(reg[REG_NUM(i)].inuse); */
536         reg[REG_NUM(i)].inuse++;
537 leave("soft_alloc_reg");
538 }
539
540 void forced_alloc_reg(i)
541 reg_t i;
542 {
543         int r;
544
545 enter("forced_alloc_reg");
546 if (debug) { indent(); fprintf(stderr,"forced_alloc_reg(%s)\n", i); }
547
548         r = REG_NUM(i);
549
550         if (reg[r].inuse) {
551                 reg_t S1;
552                 char *V2;
553
554                 S1 = alloc_reg();
555 if (debug) { indent(); fprintf(stderr,"---> inuse: moving to %s\n", S1); }
556 fprint ( codefile,
557                 "mov    %s, %s\n",i,S1
558 );
559                 subst_reg(i, S1);
560                 free_reg(S1);
561                 if (reg[r].inuse)
562                         panic("forced_alloc_reg: external owners left!");
563         }
564         reg[r].inuse = 1;
565 leave("forced_alloc_reg");
566 }
567
568 void change_reg(r)      /* to be called when register r changes */
569 reg_t r;
570 {
571         int i;
572
573 enter("change_reg");
574 if (debug) { indent(); fprintf(stderr, "change_reg(%s)\n", r); }
575         if (r != reg_g0)
576                 for (i = 0; i < c_count; i++)
577                         if (cache[i].reg == r || cache[i].reg2 == r) {
578                                 reg_t S1;
579
580                                 if (r >= reg_f0) {
581                                         S1 = alloc_float();
582 fprint ( codefile,
583                                         "fmovs  %s, %s\n",r,S1
584 );
585                                 } else {
586                                         S1 = alloc_reg();
587 fprint ( codefile,
588                                         "mov    %s, %s\n",r,S1
589 );
590                                 }
591                                 subst_reg(r, S1);
592                                 free_reg(S1);
593                                 break;
594                         }
595 leave("change_reg");
596 }
597
598 static void subst_reg(old, new)
599 reg_t old, new;
600 {
601         int i;
602
603 enter("subst_reg");
604 if (debug) { indent(); fprintf(stderr,"subst_reg(%s, %s)\n", old, new); }
605         for (i = 0; i < c_count; i++) {
606                 if (cache[i].reg == old) {
607                         cache[i].reg = new;
608                         free_reg(old);
609                         soft_alloc_reg(new);
610                 }
611                 if (cache[i].reg2 == old) {
612                         cache[i].reg2 = new;
613                         free_reg(old);
614                         soft_alloc_reg(new);
615                 }
616         }
617 leave("subst_reg");
618 }
619
620 int type_of_tos()
621 {
622         int r = 0;
623
624         cache_need(1);
625
626         if (tos->ext)
627                 r |= T_ext;
628         if (tos->reg != reg_g0)
629                 if (tos->reg >= reg_f0)
630                         r |= T_float;
631                 else
632                         r |= T_reg;
633         if (tos->reg2 != reg_g0)
634                 if (tos->reg2 >= reg_f0)
635                         r |= T_float2;
636                 else
637                         r |= T_reg2;
638         if (tos->cst)
639                 r |= T_cst;
640         return r;
641 }
642
643 arith top_const()
644 {
645 enter("top_const");
646         assert(type_of_tos() == T_cst);
647 if (debug) { indent(); fprintf(stderr,"top_const()=%d\n", tos->cst); }
648 leave("top_const");
649         return tos->cst;
650 }
651
652 reg_t pop_reg_reg(r)
653 reg_t *r;
654 {
655         reg_t s;
656
657 enter("pop_reg_reg");
658         POP1;
659         if (!(type_of_tos() & T_reg2))
660                 push_reg(pop_reg());
661         assert(r);
662         *r = tos->reg2;
663         s = tos->reg;
664         POP2;
665 if (debug) { indent(); fprintf(stderr,"pop_reg_reg()=%s\n", s); fprint(codefile,"\t\t! "); dump_cache(codefile); }
666 leave("pop_reg_reg");
667         return s;
668 }
669
670 reg_t pop_reg_c13(n)            /* returns reg_t + optional n (as string) */
671 char *n;
672 {
673         reg_t S1, S2, S3;
674         register char *V1;
675         const_str_t V2;
676 enter("pop_reg_c13");
677 if (debug) { indent(); fprintf(stderr,"pop_reg_c13()=...\n"); }
678         *n = '0';
679         *(n+1) = 0;
680         cache_need(1);
681
682         if (tos->reg >= reg_f0) {       /* convert float to int */
683                 S1= pop_float();
684                 S2= alloc_reg();
685 fprint ( codefile,
686                 "st     %s, [%%fp+64]\n",S1
687 );
688 fprint ( codefile,
689                 "ld     [%%fp+64], %s\n",S2
690 );
691                 free_reg(S1);
692                 S1 = S2;
693         }
694         else if (tos->reg2 != reg_g0) { /* add integers */
695                 S1 = pop_reg();
696         }
697         else if (tos->ext) {
698                 assert(tos->reg == reg_g0);
699                 S1 = alloc_reg();
700                 V1 = tos->ext;
701                 sprint(V2, "%d", tos->cst);
702 fprint ( codefile,
703                 "sethi  %%hi(%s+%s), %s\n",V1,V2,S1
704 );
705                 sprint(n, "%%lo(%s+%d)", tos->ext, tos->cst);
706                 free(V1);
707                 POP2;
708         } else {
709                 S1 = tos->reg;
710                 if (!(const13(tos->cst))) {
711                         S3 = alloc_reg();
712                         sprint(V2, "%d", tos->cst);
713 fprint ( codefile,
714                         "sethi  %%hi(%s), %s\n",V2,S3
715 );
716                         if (tos->reg != reg_g0) {
717                                 S2 = alloc_reg();
718 fprint ( codefile,
719                                 "add    %s, %s, %s\n",S3,S1,S2
720 );
721                                 free_reg(S1);
722                                 free_reg(S3);
723                                 S1 = S2;
724                         }
725                         else {
726                                 free_reg(S1);
727                                 S1 = S3;
728                         }
729                         tos->cst &= 0x3FF;
730                 }
731                 sprint(n, "%d", tos->cst);
732                 POP2;
733         }
734 if (debug) { indent(); fprint(codefile, "\t\t! %s+%s cache:", S1, n); dump_cache(codefile);}
735 leave("pop_reg_c13");
736         return S1;
737 }
738
739 reg_t pop_float()
740 {
741         reg_t S1, R1, R2;
742         char *V1, *V2;
743
744 enter("pop_float");
745         cache_need(1);
746         S1 = tos->reg;
747         if (!(type_of_tos() & T_float)) {
748                 S1 = pop_reg();
749                 R2 = alloc_float();
750 fprint ( codefile,
751                 "st     %s, [%%fp+64]\n",S1
752 );
753 fprint ( codefile,
754                 "ld     [%%fp+64], %s\n",R2
755 );
756                 free_reg(S1);
757                 S1 = R2;
758         }
759         else if (tos->reg2 >= reg_f0) {
760                 R1 = tos->reg2;
761                 R2 = alloc_float();
762 fprint ( codefile,
763                 "fadds  %s, %s, %s\n",S1,R1,R2
764 );
765                 free_reg(S1);   
766                 free_reg(R1);   
767                 S1 = R2;
768                 POP2;
769         } else
770                 POP2;
771 if (debug) { indent(); fprint(codefile, "\t\t! %s cache:", S1); dump_cache(codefile); }
772 leave("pop_float");
773         return S1;
774 }
775
776 void inc_tos_reg(r)
777 reg_t r;
778 {
779 enter("inc_tos_reg");
780 if (debug) { indent(); fprintf(stderr, "inc_tos_reg(%s)\n", r); }
781         if (type_of_tos() != T_reg)
782                 push_reg(pop_reg());
783         tos->reg2 = r;
784 if (debug) { indent(); fprint(codefile, "\t\t! "); dump_cache(codefile); }
785 leave("inc_tos_reg");
786 }
787
788 void inc_tos(n)
789 arith n;
790 {
791         reg_t S1;
792         char *V1, *V2;
793
794 enter("inc_tos");
795 if (debug) { indent(); fprintf(stderr,"inc_tos(%d)\n", n); }
796         cache_need(1);
797         if (tos->reg >= reg_f0)
798         {
799                 S1= pop_reg();
800                 push_reg(S1);
801         }
802         else if (tos->reg2 != reg_g0) {
803                 S1= pop_reg();
804                 push_reg(S1);
805         }
806         tos->cst += n;
807 if (debug) { indent(); fprint(codefile, "\t\t! "); dump_cache(codefile); }
808 leave("inc_tos");
809 }
810
811 #define INC_TOS if (c_count >= CACHE_SIZE) flush_part_cache(c_count/2,0,0,0); \
812                         tos = &cache[c_count++];
813
814 void push_const(n)
815 arith n;
816 {
817 enter("push_const");
818         INC_TOS;
819         tos->reg = reg_g0;
820         tos->reg2 = reg_g0;
821         tos->ext = 0;
822         tos->cst = n;
823 if (debug) { indent(); fprint(codefile, "\t\t! "); dump_cache(codefile); }
824 leave("push_const");
825 }
826
827 void push_reg(i)
828 reg_t i;
829 {
830 enter("push_reg");
831         assert(0 <= REG_NUM(i) && REG_NUM(i) < NR_REGS);
832         INC_TOS;
833         tos->reg = i;
834         tos->reg2 = reg_g0;
835         tos->ext = 0;
836         tos->cst = 0;
837 if (debug) { indent(); fprint(codefile, "\t\t! "); dump_cache(codefile); }
838 leave("push_reg");
839 }
840
841
842 void push_double_reg(i)
843 reg_t i;
844 {
845         int rn;
846
847 enter("push_double_reg");
848         rn= REG_NUM(i);
849         assert (!(rn & 1));
850         INC_TOS;
851         tos->ext = 0;
852         tos->cst = 0;
853         tos->reg = regnam[rn+1];
854         tos->reg2 = reg_g0;
855         INC_TOS;
856         tos->ext = 0;
857         tos->cst = 0;
858         tos->reg = i;
859         tos->reg2 = reg_g0;
860 if (debug) { indent(); fprint(codefile, "\t\t! "); dump_cache(codefile); }
861 leave("push_double_reg");
862 }
863
864 void push_ext(s)
865 char *s;
866 {
867         char *p;
868
869 enter("push_ext");
870         p = Malloc(strlen(s)+1);
871
872         INC_TOS;
873         tos->reg = reg_g0;
874         tos->reg2 = reg_g0;
875         tos->ext = strcpy(p, s);
876         tos->cst = 0;
877 if (debug) { indent(); fprint(codefile, "\t\t! "); dump_cache(codefile); }
878 leave("push_ext");
879 }
880
881 arith pop_const(n)
882 char *n;
883 {
884         arith x;
885
886 enter("pop_const");
887         POP1;
888         x = top_const();
889         POP2;
890         if (n)
891                 sprint(n, "%d", x);
892 if (debug) { indent(); fprint(codefile, "\t\t! %d cache:", x); dump_cache(codefile); }
893 leave("pop_const");
894         return x;
895 }
896
897 void pop_reg_as(r)
898 reg_t r;
899 {
900         reg_t S1, S2;
901         register char *V1, *V3;
902         const_str_t V2, c_str;
903         char *tos_ext;
904         reg_t tos_reg, tos_reg2;
905         int tos_cst;
906
907 enter("pop_reg_as");
908 if (debug) { indent(); fprintf(stderr,"pop_reg_as(%s)=...\n", r); }
909         if (c_count == 0) {     /* special case */
910 fprint ( codefile,
911                 "ld     [%%l0], %s\n",r
912 );
913 fprint ( codefile,
914                 "inc    4, %%l0\n"
915 );
916         } else if (r >= reg_f0) {
917                 if (tos->reg < reg_f0)
918                 {
919                         S1= pop_reg();
920                         change_reg(r);
921 fprint ( codefile,
922                         "st     %s, [%%fp+64]\n",S1
923 );
924 fprint ( codefile,
925                         "ld     [%%fp+64], %s\n",r
926 );
927                         free_reg(S1);
928                 }
929                 else
930                 {
931                         if (tos->reg2 == reg_g0) {
932                                 S1= pop_float();
933                                 change_reg(r);
934                                 if (S1 != r)
935 fprint ( codefile,
936                                         "fmovs  %s, %s\n",S1,r
937 );
938                                 free_reg(S1);
939                         } else {
940                                 V1 = tos->reg;
941                                 V3 = tos->reg2;
942                                 POP2;
943                                 change_reg(r);
944 fprint ( codefile,
945                                 "fadds  %s, %s, %s\n",V1,V3,r
946 );
947                                 free_reg(V1);
948                                 free_reg(V3);
949                         }
950                 }
951         } else if (tos->reg >= reg_f0) {
952                 S1= pop_float();
953                 change_reg(r);
954 fprint ( codefile,
955                 "st     %s, [%%fp+64]\n",S1
956 );
957 fprint ( codefile,
958                 "ld     [%%fp+64], %s\n",r
959 );
960                 free_reg(S1);
961         } else if (tos->ext) {
962                 assert(tos->reg == reg_g0);
963                 V1 = tos->ext;
964                 sprint(V2, "%d", tos->cst);
965 fprint ( codefile,
966                 "set    %s+%s, %s\n",V1,V2,r
967 );
968                 free(V1);
969                 POP2;
970         } else {
971                 POP1;
972                 tos_reg= tos->reg;
973                 tos_reg2= tos->reg2;
974                 tos_cst= tos->cst;
975                 POP2;
976                 change_reg(r);
977                 if (!const13(tos_cst))
978                 {
979                         assert (tos_reg2 == reg_g0);
980                         if (tos_reg != reg_g0 || (tos_cst & 0x3ff))
981                                 tos_reg2= alloc_reg();
982                         else
983                         {
984                                 soft_alloc_reg(r);
985                                 tos_reg2= r;
986                         }
987                         sprint(c_str, "%d", tos_cst);
988 fprint ( codefile,
989                         "sethi  %%hi(%s), %s\n",c_str,tos_reg2
990 );
991                         tos_cst &= 0x3ff;
992                         if (tos_reg == reg_g0)
993                         {
994                                 tos_reg= tos_reg2;
995                                 tos_reg2= reg_g0;
996                         }
997                 }
998                 if (tos_reg2 != reg_g0)
999                 {
1000                         assert (tos_reg != reg_g0);
1001                         if (tos_cst)
1002                                 S1= alloc_reg();
1003                         else
1004                         {
1005                                 soft_alloc_reg(r);
1006                                 S1= r;
1007                         }
1008 fprint ( codefile,
1009                         "add    %s, %s, %s\n",tos_reg,tos_reg2,S1
1010 );
1011                         free_reg(tos_reg);
1012                         free_reg(tos_reg2);
1013                         tos_reg= S1;
1014                         tos_reg2= reg_g0;
1015                 }
1016                 if (tos_cst)
1017                 {
1018                         sprint(c_str, "%d", tos_cst);
1019                         soft_alloc_reg(r);
1020 fprint ( codefile,
1021                         "add    %s, %s, %s\n",tos_reg,c_str,r
1022 );
1023                         free_reg(tos_reg);
1024                         tos_reg= r;
1025                 }
1026                 if (tos_reg != r)
1027 fprint ( codefile,
1028                         "mov    %s, %s\n",tos_reg,r
1029 );
1030                 free_reg(tos_reg);
1031         }
1032 leave("pop_reg_as");
1033 }
1034
1035 void pop_double_reg_as(rdl)
1036 reg_t rdl;
1037 {
1038         reg_t rl, rh;
1039         reg_t rdh;
1040         reg_t t;
1041         int rn;
1042         
1043 enter("pop_double_reg_as");
1044         rn= REG_NUM(rdl);
1045         assert (!(rn & 1));
1046         rdh= regnam[rn+1];
1047         if (rdl>= reg_f0)
1048         {
1049                 if (c_count == 0) {
1050 fprint ( codefile,
1051                         "ld     [%%l0], %s\n",rdl
1052 );
1053 fprint ( codefile,
1054                         "ld     [%%l0+4], %s\n",rdh
1055 );
1056 fprint ( codefile,
1057                         "inc    8, %%l0\n"
1058 );
1059                 } else {
1060                         if (type_of_tos() & T_float)
1061                                 rl= pop_float();
1062                         else
1063                                 rl= pop_reg();
1064                         if (type_of_tos() & T_float)
1065                                 rh= pop_float();
1066                         else
1067                                 rh= pop_reg();
1068                         change_reg(rdl);
1069                         change_reg(rdh);
1070                         if (rl < reg_f0 && rh < reg_f0)
1071                         {
1072 fprint ( codefile,
1073                                 "st     %s, [%%fp+64]\n",rl
1074 );
1075 fprint ( codefile,
1076                                 "st     %s, [%%fp+68]\n",rh
1077 );
1078 fprint ( codefile,
1079                                 "ldd    [%%fp+64], %s\n",rdl
1080 );
1081                                 free_reg(rl);
1082                                 free_reg(rh);
1083                         }
1084                         else if (rl < reg_f0)
1085                         {
1086                                 if (rh != rdh)
1087 fprint ( codefile,
1088                                         "fmovs  %s, %s\n",rh,rdh
1089 );
1090 fprint ( codefile,
1091                                 "st     %s, [%%fp+64]\n",rl
1092 );
1093 fprint ( codefile,
1094                                 "ld     [%%fp+64], %s\n",rdl
1095 );
1096                                 free_reg(rl);
1097                                 free_reg(rh);
1098                         }
1099                         else if (rh < reg_f0)
1100                         {
1101                                 if (rl != rdl)
1102 fprint ( codefile,
1103                                         "fmovs  %s, %s\n",rl,rdl
1104 );
1105 fprint ( codefile,
1106                                 "st     %s, [%%fp+64]\n",rh
1107 );
1108 fprint ( codefile,
1109                                 "ld     [%%fp+64], %s\n",rdh
1110 );
1111                                 free_reg(rl);
1112                                 free_reg(rh);
1113                         } else {
1114                                 if (rdl == rl)
1115                                         free_reg(rl);
1116                                 if (rdh == rh)
1117                                         free_reg(rh);
1118                                 if (rdl == rh && rdh == rl)
1119                                 {
1120                                         t= alloc_float();
1121 fprint ( codefile,
1122                                         "fmovs  %s, %s\n",rl,t
1123 );
1124                                         free_reg(rl);
1125                                         rl= t;
1126                                 }
1127                                 if (rdl != rl && rdl != rh)
1128                                 {
1129 fprint ( codefile,
1130                                         "fmovs  %s, %s\n",rl,rdl
1131 );
1132                                         free_reg(rl);
1133                                         rl= rdl;
1134                                 }
1135                                 if (rdh != rh && rdh != rl)
1136                                 {
1137 fprint ( codefile,
1138                                         "fmovs  %s, %s\n",rh,rdh
1139 );
1140                                         free_reg(rh);
1141                                         rh= rdh;
1142                                 }
1143                                 if (rdl != rl && rdl != rh)
1144                                 {
1145 fprint ( codefile,
1146                                         "fmovs  %s, %s\n",rl,rdl
1147 );
1148                                         free_reg(rl);
1149                                         rl= rdl;
1150                                 }
1151                                 assert (rdl == rl && rdh == rh);
1152                         }
1153                 }
1154         }
1155         else
1156         {
1157                 pop_reg_as (rdl);
1158                 pop_reg_as (rdh);
1159         }
1160 leave("pop_double_reg_as");
1161 }
1162
1163                         
1164                 
1165 reg_t pop_reg()
1166 {
1167         reg_t S1;
1168
1169 enter("pop_reg");
1170         POP1;
1171         if (type_of_tos() == T_reg) {
1172                 S1 = tos->reg;
1173                 POP2;
1174         } else {
1175                 S1 = alloc_reg();
1176                 pop_reg_as(S1);
1177         }
1178 if (debug) { indent(); fprint(codefile, "\t\t! %s cache:", S1); dump_cache(codefile); }
1179 leave("pop_reg");
1180         return S1;
1181 }
1182
1183
1184 reg_t pop_double(sub_reg)       /* pop_double_float actually */
1185 reg_t *sub_reg;
1186 {
1187         reg_t R1, R2, R3, R4;
1188         char *V1, *V2;
1189
1190 enter("pop_double");
1191         if (c_count == 0) {
1192                 R1 = alloc_double(&R2);
1193 fprint ( codefile,
1194                 "ld     [%%l0], %s\n",R1
1195 );
1196 fprint ( codefile,
1197                 "ld     [%%l0+4], %s\n",R2
1198 );
1199 fprint ( codefile,
1200                 "inc    8, %%l0\n"
1201 );
1202                 if (sub_reg)
1203                         *sub_reg = R2;
1204         } else {
1205                 cache_need(2);
1206                 if (tos->reg >= reg_f0 && tos[-1].reg >= reg_f0 &&
1207                         REG_NUM(tos->reg) == REG_NUM(tos[-1].reg)-1 &&
1208                         tos->reg2 == reg_g0 && tos[-1].reg2 == reg_g0)
1209                 {
1210                         R1= tos->reg;
1211                         if (sub_reg)
1212                                 *sub_reg= tos[-1].reg;
1213                         POP2;
1214                         POP2;
1215                 } else {
1216                         R1= alloc_double(&R2);
1217                         if (sub_reg)
1218                                 *sub_reg= R2;
1219                         if (tos->reg >= reg_f0 || tos[-1].reg >= reg_f0)
1220                         {
1221                                 pop_reg_as(R1);
1222                                 pop_reg_as(R2);
1223                         } else {
1224                                 /* two normal registers */
1225                                 R3= pop_reg();
1226                                 R4= pop_reg();
1227 fprint ( codefile,
1228                                 "st     %s, [%%fp+64]\n",R3
1229 );
1230 fprint ( codefile,
1231                                 "st     %s, [%%fp+68]\n",R4
1232 );
1233 fprint ( codefile,
1234                                 "ldd    [%%fp+64], %s\n",R1
1235 );
1236                                 free_reg(R3);
1237                                 free_reg(R4);
1238                         }
1239                 }
1240         }
1241 leave("pop_double");
1242         return R1;
1243 }
1244
1245 void pop_nop(i)
1246 int i;
1247 {
1248         const_str_t V1;
1249         int j = i;
1250
1251 enter("pop_nop");
1252         while (c_count && i) {
1253                 i--;
1254                 POP1;
1255                 free_reg(tos->reg);
1256                 free_reg(tos->reg2);
1257                 if (tos->ext)
1258                         free(tos->ext);
1259                 POP2;
1260         }
1261         if (i) {
1262                 sprint(V1, "%d", 4*i);
1263                 if (const13(4*i)) {
1264 fprint ( codefile,
1265                         "inc    %s, %%l0\n",V1
1266 );
1267                 } else {
1268 fprint ( codefile,
1269                         "set    %s, %s\n",V1,reg_tmp
1270 );
1271 fprint ( codefile,
1272                         "add    %%l0, %s, %%l0\n",reg_tmp
1273 );
1274                 }
1275         }
1276 if (debug) { indent(); fprint(codefile, "\t\t! %dw cache:",j); dump_cache(codefile); }
1277 leave("pop_nop");
1278 }
1279
1280 check_cache()
1281 {
1282         int i;
1283 if (debug)
1284         for (i = 0; i < NR_REGS; i++)
1285                 fprintf(stderr, "%c", reg[i].inuse ? (reg[i].inuse)+48 : '.');
1286         fprintf(stderr, "\n");
1287 }
1288
1289 void flush_cache()              /* flush the cache onto the stack */
1290 {
1291 enter("flush_cache");
1292
1293 if (debug) { indent(); fprintf(stderr,"flush_cache\n"); }
1294         if (c_count)
1295                 flush_part_cache(c_count, 0, 0, 0);
1296
1297         /* TEST */
1298 if (debug)
1299         check_cache();
1300 leave("flush_cache");
1301 }
1302
1303 void cache_need(n)
1304 int n;
1305 {
1306 enter("cache_need");
1307         if (c_count < n)
1308                 (void) cache_read(n, 0);
1309         assert(c_count >= n);
1310 leave("cache_need");
1311 }
1312
1313 static int cache_read(n, i)
1314 int n;
1315 int i;
1316 {
1317         const_str_t V1;
1318         reg_t S1;
1319         int j;
1320         int old_c_count;
1321
1322 enter("cache_read");
1323 if (debug) { indent(); fprintf(stderr,"cache_read(%d, %d)\n", n,i); }
1324         if (i+c_count<n)
1325         {
1326                 S1= alloc_reg();
1327                 old_c_count = cache_read(n, i+1);
1328
1329                 sprint(V1, "%d", (old_c_count-1-i) * 4);
1330 fprint ( codefile,
1331                 "ld     [%%l0+%s], %s\n",V1,S1
1332 );
1333                 cache[i].reg= S1;
1334                 cache[i].reg2= reg_g0;
1335                 cache[i].ext= 0;
1336                 cache[i].cst= 0;
1337                 if (!i)
1338                 {
1339                         sprint(V1, "%d", (old_c_count)*4);
1340 fprint ( codefile,
1341                         "add    %s, %s, %s\n",reg_sp,V1,reg_sp
1342 );
1343                 }
1344         }
1345         else
1346         {
1347                 assert (i);
1348                 for (j= c_count-1; j>=0; j--)
1349                         cache[j+i]= cache[j];
1350                 c_count += i;
1351                 tos= &cache[c_count-1];
1352                 old_c_count = i;
1353         }
1354 leave("cache_read");
1355         return old_c_count;
1356 }
1357
1358 static void dump_cache(stream)          /* to codefile! */
1359 File *stream;
1360 {
1361         int i;
1362
1363         assert (c_count >= 0);
1364         for (i = c_count -1; i >= 0; i--) {
1365                 if (cache[i].ext)
1366                         fprint(stream, "%s", cache[i].ext);
1367                 if (cache[i].reg != reg_g0) {
1368                         if (cache[i].ext)
1369                                 fprint(stream, "+");
1370                         fprint(stream, "%s", cache[i].reg);
1371                         if (cache[i].reg2 != reg_g0) {
1372                                 fprint(stream, "+");
1373                                 fprint(stream, "%s", cache[i].reg2);
1374                         }
1375                 }
1376                 if (cache[i].cst || (!cache[i].ext && cache[i].reg == reg_g0)) {
1377                         if (cache[i].ext || cache[i].reg != reg_g0)
1378                                 fprint(stream, "+");
1379                         fprint(stream, "%d", cache[i].cst);
1380                 }
1381                 fprint(stream, " ");
1382         }
1383         fprint(stream, "\n");
1384 if (debug) check_cache();
1385 }
1386
1387 void dup_tos(n)
1388 int n;
1389 {
1390         reg_t a;
1391         int i;
1392         const_str_t i_str;
1393
1394 enter("dup_tos");
1395         for (i = 0;i < n; i++) {
1396                 INC_TOS;
1397                 tos->reg = reg_g0;
1398                 tos->reg2 = reg_g0;
1399                 tos->cst = 0;
1400                 tos->ext = 0;
1401                 if (c_count > n) {
1402                         char *ext;
1403
1404                         *tos = tos[-n];
1405                         if (tos->ext)
1406                         {
1407                                 ext= Malloc(strlen(tos->ext)+1);
1408                                 strcpy(ext, tos->ext);
1409                                 tos->ext= ext;
1410                         }
1411                         soft_alloc_reg(tos->reg);
1412                         soft_alloc_reg(tos->reg2);
1413                 } else {
1414                         a= alloc_reg();
1415                         sprint(i_str, "%d", (n-c_count)*4);
1416 fprint ( codefile,
1417                         "ld     [%s+%s], %s\n",reg_sp,i_str,a
1418 );
1419                         tos->reg = a;
1420                 }
1421         }
1422 if (debug) { indent(); fprint(codefile, "\t\t! "); dump_cache(codefile); }
1423 leave("dup_tos");
1424 }