11 extern char *strcpy();
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
16 #define POP1 cache_need(1);
17 #define POP2 { --tos; assert(c_count); --c_count; }
19 static int indent_count = 0;
21 #define enter(x) indent_count++;
22 #define indent() { int i = indent_count; while (i--) putc('\t', stderr); }
23 #define leave(x) indent_count--;
26 const13(int) boolean proc
27 init_cache() mandatory
29 forced_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
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
44 reg_t pop_reg_c13(char*)
46 arith pop_const(char *)
49 alloc_float, alloc_double, free_double,
50 pop_float, pop_double, push_float, push_double
54 typedef struct regdat_t {
55 int inuse; /* free == 0, otherwise #owners */
58 typedef struct cache_elt {
65 #define REG_NUM(r) (((char(*)[8])(r))-regnam)
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"
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;
83 reg_t reg_sp, reg_lb, reg_gap;
84 reg_t reg_tmp, reg_lin, reg_fil;
86 static struct regdat_t reg[NR_REGS];
88 #define POP_SIZE 1 /* maybe >1 (read-ahead cache) or explicit?! */
89 #define CACHE_SIZE 32 /* ? */
103 return (x < 4096 && x >= -4096);
106 static struct cache_elt cache[CACHE_SIZE], *tos = 0;
107 static int c_count = 0;
108 static const_str_t s;
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));
119 printf("PANIC: %s\n", s);
127 for (i = 0; i < NR_REGS; i++)
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];
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];
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];
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];
166 reg_f0 = regnam[040];
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);
179 static void flush_part_cache(n,r,f,d)
182 /* free at least n entries, r integer registers, f float regs and d double regs
186 const_str_t i_str, e_str, n_str;
190 enter("flush_part_cache");
191 for (i = 0; i < c_count; i++)
193 if (i >= n && !r && !f && !d)
195 if (cache[i].reg != reg_g0)
197 rn= REG_NUM(cache[i].reg);
207 if (d && (((rn & 1) &&
209 (!(rn & 1) && !reg[rn+1].inuse)))
215 if (cache[i].reg2 != reg_g0)
217 rn= REG_NUM(cache[i].reg2);
227 if (d && (((rn & 1) &&
229 (!(rn & 1) && !reg[rn+1].inuse)))
237 panic ("can't free enough registers");
241 sprint (i_str, "%d", 4*i);
243 "dec %s, %s\n",i_str,reg_sp
247 sprint(i_str, "%d", 4*(j-1-i));
251 sprint (e_str, "%d", cache[i].cst);
253 "set %s+%s, %s\n",ext,e_str,reg_tmp
256 "st %s, [%s+%s]\n",reg_tmp,reg_sp,i_str
262 if (cache[i].reg2 != reg_g0)
267 "add %s, %s, %s\n",rt,rh,reg_tmp
269 cache[i].reg = reg_tmp;
270 cache[i].reg2 = reg_g0;
272 if (!const13(cache[i].cst))
277 "sethi %%hi(%s), %s\n",n_str,reg_tmp
279 if (cache[i].reg != reg_g0)
283 "add %s, %s, %s\n",reg_tmp,rt,reg_tmp
287 cache[i].cst &= 0x3ff;
294 sprint(n_str, "%d", cache[i].cst);
296 "add %s, %s, %s\n",rh,n_str,reg_tmp
301 "st %s, [%s+%s]\n",rh,reg_sp,i_str
305 for (i= j; i < c_count; i++)
306 cache[i-j]= cache[i];
308 tos= &cache[c_count-1];
310 leave("flush_part_cache");
319 for (i = LO_GLOB+1 /* SPEED-HACK */; i <= HI_GLOB; i++) {
322 reg[i].inuse = 1; /* allocate */
327 for (i = LO_IN; i <= HI_IN; i++) {
330 reg[i].inuse = 1; /* allocate */
335 for (i = LO_LOC; i <= HI_LOC; i++) {
338 reg[i].inuse = 1; /* allocate */
343 for (i = LO_OUT; i <= HI_OUT; i++) {
346 reg[i].inuse = 1; /* allocate */
351 flush_part_cache(c_count/2,1,0,0);
354 if (debug) { indent(); fprintf(stderr,"alloc_reg() = %s\n", res ? regnam[i] : "NULL"); }
364 enter("alloc_float");
365 for (i = LO_FLOAT+15; i >= LO_FLOAT; i--) {
368 reg[i].inuse = 1; /* allocate */
373 flush_part_cache(c_count/2,0,1,0);
376 if (debug) { indent(); fprintf(stderr,"alloc_float() = %s\n", res ? regnam[i] : "NULL"); }
377 leave("alloc_float");
381 reg_t alloc_double(sub_reg)
387 enter("alloc_double");
388 for (i = LO_FLOAT+14; i >= LO_FLOAT; i -= 2) {
389 if (reg[i].inuse || reg[i+1].inuse)
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]); }
395 *sub_reg= regnam[i+1];
400 flush_part_cache(c_count/2,0,0,1);
401 res = alloc_double(sub_reg);
403 if (debug) { indent(); fprintf(stderr,"alloc_double() = %s\n", res ? regnam[i] : "NULL"); }
404 leave("alloc_double");
408 reg_t alloc_reg_var() /* ins and locals only */
413 enter("alloc_reg_var");
414 for (i = LO_LOC +2 /* SPEED-HACK */; i <= HI_LOC; i++) {
417 reg[i].inuse = 1; /* allocate */
422 for (i = LO_IN; i <= HI_IN; i++) {
425 reg[i].inuse = 1; /* allocate */
429 if (debug) { indent(); fprintf(stderr,"alloc_reg_var() = %s\n", res ? regnam[i] : "NULL"); }
430 leave("alloc_reg_var");
434 reg_t alloc_float_var()
439 enter("alloc_float_var");
440 for (i= LO_FLOAT+16; i<= HI_FLOAT; i++)
444 reg[i].inuse = 1; /* allocate */
448 if (debug) { indent(); fprintf(stderr,"alloc_reg_var() = %s\n", res ? regnam[i] : "NULL"); }
449 leave("alloc_float_var");
453 reg_t alloc_double_var(sub_reg)
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)
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]); }
467 *sub_reg= regnam[i+1];
471 if (debug) { indent(); fprintf(stderr,"alloc_double_var() = %s\n", res? regnam[i] : "NULL"); }
472 leave("alloc_double_var");
482 if (i != 0 && i != reg_g0) {
484 assert(0 <= r && r <= NR_REGS);
485 assert(reg[r].inuse > 0); /* "freeing unused register" */
488 if (debug) { indent(); fprintf(stderr,"free_reg(%s)\n", i); }
492 void free_double_reg(i)
497 enter("free_double_reg");
501 free_reg(regnam[rn+1]);
502 leave("free_double_reg");
506 void force_alloc_output() /* TMP HACK */
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");
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);
530 void soft_alloc_reg(i)
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");
540 void forced_alloc_reg(i)
545 enter("forced_alloc_reg");
546 if (debug) { indent(); fprintf(stderr,"forced_alloc_reg(%s)\n", i); }
555 if (debug) { indent(); fprintf(stderr,"---> inuse: moving to %s\n", S1); }
562 panic("forced_alloc_reg: external owners left!");
565 leave("forced_alloc_reg");
568 void change_reg(r) /* to be called when register r changes */
574 if (debug) { indent(); fprintf(stderr, "change_reg(%s)\n", r); }
576 for (i = 0; i < c_count; i++)
577 if (cache[i].reg == r || cache[i].reg2 == r) {
583 "fmovs %s, %s\n",r,S1
598 static void subst_reg(old, new)
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) {
611 if (cache[i].reg2 == old) {
628 if (tos->reg != reg_g0)
629 if (tos->reg >= reg_f0)
633 if (tos->reg2 != reg_g0)
634 if (tos->reg2 >= reg_f0)
646 assert(type_of_tos() == T_cst);
647 if (debug) { indent(); fprintf(stderr,"top_const()=%d\n", tos->cst); }
657 enter("pop_reg_reg");
659 if (!(type_of_tos() & T_reg2))
665 if (debug) { indent(); fprintf(stderr,"pop_reg_reg()=%s\n", s); fprint(codefile,"\t\t! "); dump_cache(codefile); }
666 leave("pop_reg_reg");
670 reg_t pop_reg_c13(n) /* returns reg_t + optional n (as string) */
676 enter("pop_reg_c13");
677 if (debug) { indent(); fprintf(stderr,"pop_reg_c13()=...\n"); }
682 if (tos->reg >= reg_f0) { /* convert float to int */
686 "st %s, [%%fp+64]\n",S1
689 "ld [%%fp+64], %s\n",S2
694 else if (tos->reg2 != reg_g0) { /* add integers */
698 assert(tos->reg == reg_g0);
701 sprint(V2, "%d", tos->cst);
703 "sethi %%hi(%s+%s), %s\n",V1,V2,S1
705 sprint(n, "%%lo(%s+%d)", tos->ext, tos->cst);
710 if (!(const13(tos->cst))) {
712 sprint(V2, "%d", tos->cst);
714 "sethi %%hi(%s), %s\n",V2,S3
716 if (tos->reg != reg_g0) {
719 "add %s, %s, %s\n",S3,S1,S2
731 sprint(n, "%d", tos->cst);
734 if (debug) { indent(); fprint(codefile, "\t\t! %s+%s cache:", S1, n); dump_cache(codefile);}
735 leave("pop_reg_c13");
747 if (!(type_of_tos() & T_float)) {
751 "st %s, [%%fp+64]\n",S1
754 "ld [%%fp+64], %s\n",R2
759 else if (tos->reg2 >= reg_f0) {
763 "fadds %s, %s, %s\n",S1,R1,R2
771 if (debug) { indent(); fprint(codefile, "\t\t! %s cache:", S1); dump_cache(codefile); }
779 enter("inc_tos_reg");
780 if (debug) { indent(); fprintf(stderr, "inc_tos_reg(%s)\n", r); }
781 if (type_of_tos() != T_reg)
784 if (debug) { indent(); fprint(codefile, "\t\t! "); dump_cache(codefile); }
785 leave("inc_tos_reg");
795 if (debug) { indent(); fprintf(stderr,"inc_tos(%d)\n", n); }
797 if (tos->reg >= reg_f0)
802 else if (tos->reg2 != reg_g0) {
807 if (debug) { indent(); fprint(codefile, "\t\t! "); dump_cache(codefile); }
811 #define INC_TOS if (c_count >= CACHE_SIZE) flush_part_cache(c_count/2,0,0,0); \
812 tos = &cache[c_count++];
823 if (debug) { indent(); fprint(codefile, "\t\t! "); dump_cache(codefile); }
831 assert(0 <= REG_NUM(i) && REG_NUM(i) < NR_REGS);
837 if (debug) { indent(); fprint(codefile, "\t\t! "); dump_cache(codefile); }
842 void push_double_reg(i)
847 enter("push_double_reg");
853 tos->reg = regnam[rn+1];
860 if (debug) { indent(); fprint(codefile, "\t\t! "); dump_cache(codefile); }
861 leave("push_double_reg");
870 p = Malloc(strlen(s)+1);
875 tos->ext = strcpy(p, s);
877 if (debug) { indent(); fprint(codefile, "\t\t! "); dump_cache(codefile); }
892 if (debug) { indent(); fprint(codefile, "\t\t! %d cache:", x); dump_cache(codefile); }
901 register char *V1, *V3;
902 const_str_t V2, c_str;
904 reg_t tos_reg, tos_reg2;
908 if (debug) { indent(); fprintf(stderr,"pop_reg_as(%s)=...\n", r); }
909 if (c_count == 0) { /* special case */
916 } else if (r >= reg_f0) {
917 if (tos->reg < reg_f0)
922 "st %s, [%%fp+64]\n",S1
925 "ld [%%fp+64], %s\n",r
931 if (tos->reg2 == reg_g0) {
936 "fmovs %s, %s\n",S1,r
945 "fadds %s, %s, %s\n",V1,V3,r
951 } else if (tos->reg >= reg_f0) {
955 "st %s, [%%fp+64]\n",S1
958 "ld [%%fp+64], %s\n",r
961 } else if (tos->ext) {
962 assert(tos->reg == reg_g0);
964 sprint(V2, "%d", tos->cst);
966 "set %s+%s, %s\n",V1,V2,r
977 if (!const13(tos_cst))
979 assert (tos_reg2 == reg_g0);
980 if (tos_reg != reg_g0 || (tos_cst & 0x3ff))
981 tos_reg2= alloc_reg();
987 sprint(c_str, "%d", tos_cst);
989 "sethi %%hi(%s), %s\n",c_str,tos_reg2
992 if (tos_reg == reg_g0)
998 if (tos_reg2 != reg_g0)
1000 assert (tos_reg != reg_g0);
1009 "add %s, %s, %s\n",tos_reg,tos_reg2,S1
1018 sprint(c_str, "%d", tos_cst);
1021 "add %s, %s, %s\n",tos_reg,c_str,r
1028 "mov %s, %s\n",tos_reg,r
1032 leave("pop_reg_as");
1035 void pop_double_reg_as(rdl)
1043 enter("pop_double_reg_as");
1051 "ld [%%l0], %s\n",rdl
1054 "ld [%%l0+4], %s\n",rdh
1060 if (type_of_tos() & T_float)
1064 if (type_of_tos() & T_float)
1070 if (rl < reg_f0 && rh < reg_f0)
1073 "st %s, [%%fp+64]\n",rl
1076 "st %s, [%%fp+68]\n",rh
1079 "ldd [%%fp+64], %s\n",rdl
1084 else if (rl < reg_f0)
1088 "fmovs %s, %s\n",rh,rdh
1091 "st %s, [%%fp+64]\n",rl
1094 "ld [%%fp+64], %s\n",rdl
1099 else if (rh < reg_f0)
1103 "fmovs %s, %s\n",rl,rdl
1106 "st %s, [%%fp+64]\n",rh
1109 "ld [%%fp+64], %s\n",rdh
1118 if (rdl == rh && rdh == rl)
1122 "fmovs %s, %s\n",rl,t
1127 if (rdl != rl && rdl != rh)
1130 "fmovs %s, %s\n",rl,rdl
1135 if (rdh != rh && rdh != rl)
1138 "fmovs %s, %s\n",rh,rdh
1143 if (rdl != rl && rdl != rh)
1146 "fmovs %s, %s\n",rl,rdl
1151 assert (rdl == rl && rdh == rh);
1160 leave("pop_double_reg_as");
1171 if (type_of_tos() == T_reg) {
1178 if (debug) { indent(); fprint(codefile, "\t\t! %s cache:", S1); dump_cache(codefile); }
1184 reg_t pop_double(sub_reg) /* pop_double_float actually */
1187 reg_t R1, R2, R3, R4;
1190 enter("pop_double");
1192 R1 = alloc_double(&R2);
1194 "ld [%%l0], %s\n",R1
1197 "ld [%%l0+4], %s\n",R2
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)
1212 *sub_reg= tos[-1].reg;
1216 R1= alloc_double(&R2);
1219 if (tos->reg >= reg_f0 || tos[-1].reg >= reg_f0)
1224 /* two normal registers */
1228 "st %s, [%%fp+64]\n",R3
1231 "st %s, [%%fp+68]\n",R4
1234 "ldd [%%fp+64], %s\n",R1
1241 leave("pop_double");
1252 while (c_count && i) {
1256 free_reg(tos->reg2);
1262 sprint(V1, "%d", 4*i);
1269 "set %s, %s\n",V1,reg_tmp
1272 "add %%l0, %s, %%l0\n",reg_tmp
1276 if (debug) { indent(); fprint(codefile, "\t\t! %dw cache:",j); dump_cache(codefile); }
1284 for (i = 0; i < NR_REGS; i++)
1285 fprintf(stderr, "%c", reg[i].inuse ? (reg[i].inuse)+48 : '.');
1286 fprintf(stderr, "\n");
1289 void flush_cache() /* flush the cache onto the stack */
1291 enter("flush_cache");
1293 if (debug) { indent(); fprintf(stderr,"flush_cache\n"); }
1295 flush_part_cache(c_count, 0, 0, 0);
1300 leave("flush_cache");
1306 enter("cache_need");
1308 (void) cache_read(n, 0);
1309 assert(c_count >= n);
1310 leave("cache_need");
1313 static int cache_read(n, i)
1322 enter("cache_read");
1323 if (debug) { indent(); fprintf(stderr,"cache_read(%d, %d)\n", n,i); }
1327 old_c_count = cache_read(n, i+1);
1329 sprint(V1, "%d", (old_c_count-1-i) * 4);
1331 "ld [%%l0+%s], %s\n",V1,S1
1334 cache[i].reg2= reg_g0;
1339 sprint(V1, "%d", (old_c_count)*4);
1341 "add %s, %s, %s\n",reg_sp,V1,reg_sp
1348 for (j= c_count-1; j>=0; j--)
1349 cache[j+i]= cache[j];
1351 tos= &cache[c_count-1];
1354 leave("cache_read");
1358 static void dump_cache(stream) /* to codefile! */
1363 assert (c_count >= 0);
1364 for (i = c_count -1; i >= 0; i--) {
1366 fprint(stream, "%s", cache[i].ext);
1367 if (cache[i].reg != reg_g0) {
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);
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);
1381 fprint(stream, " ");
1383 fprint(stream, "\n");
1384 if (debug) check_cache();
1395 for (i = 0;i < n; i++) {
1407 ext= Malloc(strlen(tos->ext)+1);
1408 strcpy(ext, tos->ext);
1411 soft_alloc_reg(tos->reg);
1412 soft_alloc_reg(tos->reg2);
1415 sprint(i_str, "%d", (n-c_count)*4);
1417 "ld [%s+%s], %s\n",reg_sp,i_str,a
1422 if (debug) { indent(); fprint(codefile, "\t\t! "); dump_cache(codefile); }