|
|
1.1 root 1: #ifndef lint
2: static char sccsid[] = "@(#)sky.c 1.1 86/02/03 Copyr 1984 Sun Micro";
3: #endif
4:
5: /*
6: * Copyright (c) 1984 by Sun Microsystems, Inc.
7: */
8:
9: #include "as.h"
10: #include "c2.h"
11:
12: #define SP_REG 15 /* Stack pointer: a7 */
13: #define STATUS_WORD -2 /* Offset to sky status word */
14: #define IDLE 6 /* Idle bit in hibyte of status word */
15:
16: #define SP_ADD 0x1001 /* Single add: B1 = A2 + A1 */
17: #define SP_ADDREG 0x104c /* Single add: R0 = R0 + A1 */
18: #define SP_ADDB1 0x1003 /* Single add: B1 = R0 + A1 */
19:
20: #define SP_SUB 0x1007 /* Single sub: B1 = A1 - A2 */
21: #define SP_SUBREG1 0x104f /* Single sub: R0 = R0 - A1 */
22: #define SP_SUBREG2 0x1050 /* Single sub: R0 = A1 - R0 */
23:
24: #define SP_MUL 0x100b /* Single mul: B1 = A2 * A1 */
25: #define SP_MULREG 0x1052 /* Single mul: R0 = R0 * A1 */
26: #define SP_MULB1 0x100d /* Single mul: B1 = R0 * A1 */
27:
28: #define SP_DIV 0x1013 /* Single div: B1 = A2 / A1 */
29: #define SP_DIVREG1 0x1055 /* Single div: R0 = R0 / A1 */
30: #define SP_DIVREG2 0x1056 /* Single div: R0 = A1 / R0 */
31:
32: #define SP_LOAD 0x1031 /* Single load: R0 = A1 */
33: #define SP_STORE 0x1037 /* Single store: B1 = R0 */
34:
35: #define isskyop(op) (findop(op) != NULL)
36:
37: /*
38: * Struct for each sky operator that can be changed.
39: * The code generator produces operations that push two operands
40: * to the board and fetch one result. The goal here is to use
41: * the on board register as an accumulator. Therefore, one
42: * operand will come from register R0 and the result will be
43: * left in R0.
44: * For some operations (add and mul), one operand can come
45: * from register R0 and the result can be fetched from the
46: * board. Otherwise (sub and div), a SKY operation to fetch
47: * the result must be inserted.
48: */
49: struct skyop {
50: int op; /* Sky board opcode */
51: int arg_op[2]; /* Opcode if arg "n" in R0 */
52: int fetch; /* Opcode to fetch result from board */
53: };
54:
55: /*
56: * Info about single precision SKY board operators.
57: */
58: struct skyop regops[] = {
59: { SP_ADD, SP_ADDREG, SP_ADDREG, SP_ADDB1 },
60: { SP_SUB, SP_SUBREG1, SP_SUBREG2, 0 },
61: { SP_MUL, SP_MULREG, SP_MULREG, SP_MULB1 },
62: { SP_DIV, SP_DIVREG1, SP_DIVREG2, 0 },
63: { 0 },
64: };
65:
66: /*
67: * Struct for a sky board operation
68: */
69: struct skylist {
70: NODE *skyload; /* Instruction to load opcode */
71: NODE *arg[2]; /* Args passed to the board */
72: NODE *result; /* Result fetched from the board */
73: NODE *oldresult; /* Result fetched from the board */
74: int oldop; /* Original sky operator */
75: int tstloop; /* Is result preceeded by tst loop */
76: struct skylist *next; /* Linked list */
77: };
78:
79: struct oper *newoperand();
80: struct skylist *get_sky();
81: struct skylist *bld_skylist();
82: struct skyop *findop();
83: NODE *newinst();
84: NODE *remove();
85: NODE *delete_tst_loop();
86: static struct sym_bkt *skyname;
87: static struct oper skybase;
88:
89: sky()
90: {
91: NODE *n;
92: register v, regno;
93: struct oper *op1;
94: struct oper *op2;
95: int didchange=0;
96: int i, inexact;
97: struct oper saveop;
98: struct skylist *skylist;
99: static struct oper reg = { T_REG, 0, 0, NULL, 0, 0, 0 };
100: static struct oper conz = { T_IMMED, 0, 0, NULL, 0, 0, 0 };
101:
102: /* initialize constant table to empty. Find __skybase */
103: forgetall();
104: if (skyname==NULL) skyname = lookup("__skybase");
105: skybase.type_o = T_NORMAL;
106: skybase.sym_o = skyname;
107: skybase.value_o = 0;
108:
109: for (n = first.forw; n != &first; n = n->forw){
110: if (n->op == OP_LABEL) {
111: /*
112: * we really should be doing flow analysis here.
113: * lacking that, recognize special case SKY code:
114: * 1: tstw a1@(-4)
115: * bge 1b
116: */
117: if (n->nref == 1 && n->luse == n->forw->forw &&
118: emptymask( n->forw->rset) && n->forw->forw->op == OP_JUMP) {
119: n = n->forw;
120: continue;
121: }
122: /* forget everything */
123: forgetall();
124: continue;
125: }
126: if (n->nref == 0) {
127: continue;
128: }
129: if (n->op != OP_MOVE) {
130: continue;
131: }
132: op1 = n->ref[0];
133: op2 = n->ref[1];
134: skylist = bld_skylist(&n);
135: if (skylist != NULL) {
136: rewrite_list(skylist);
137: free_list(skylist);
138: n = n->back;
139: } else if (op1->type_o == T_NORMAL &&
140: op1->value_o == 0 &&
141: op1->sym_o == skyname &&
142: op2->type_o==T_REG) {
143: /* move to a register */
144: con_to_reg( op2->value_o, op1, n->subop );
145: }
146: }
147: }
148:
149: /*
150: * Build a list of sky board operations that
151: * can use an accumulator between them. Two operations
152: * can use an accumulator if the result of the first operation
153: * is the first argument to the second operation.
154: */
155: struct skylist *
156: bld_skylist(np)
157: NODE **np;
158: {
159: struct skylist *hdr;
160: struct skylist *sky;
161: struct skylist **bpatch;
162: NODE *n;
163:
164: hdr = NULL;
165: n = *np;
166: if (is_sky_operation(n)) {
167: hdr = get_sky(&n);
168: if (hdr == NULL) {
169: return(NULL);
170: }
171: sky = hdr;
172: if (result_is_reg(sky)) {
173: bpatch = &sky->next;
174: while (n->op != OP_LABEL &&
175: n->op != OP_JUMP &&
176: n->op != OP_CALL) {
177: if (result_killed(n, sky)) {
178: break;
179: }
180: if (n == &first) {
181: n = first.back;
182: break;
183: }
184: if (is_sky_operation(n)) {
185: sky = get_sky(&n);
186: if (sky == NULL) {
187: return(NULL);
188: }
189: *bpatch = sky;
190: bpatch = &sky->next;
191: if (!result_is_reg(sky)) {
192: break;
193: }
194: } else {
195: n = n->forw;
196: }
197: }
198: }
199: }
200: *np = n;
201: return(hdr);
202: }
203:
204: /*
205: * Disect a sky board operation.
206: * Find the opcode, the two arguments and the result that is fetched
207: * off of the board.
208: * If it is not a sky board operation return NULL.
209: */
210: struct skylist *
211: get_sky(np)
212: NODE **np;
213: {
214: NODE *n;
215: struct skylist *sky;
216: int i;
217:
218: /*
219: * Get the instruction to load an opcode into the sky board
220: */
221: n = *np;
222: sky = (struct skylist *) calloc(sizeof(*sky), 1);
223: sky->skyload = n;
224: n = n->forw;
225:
226: /*
227: * Get pointers to the instructions that push arguments
228: */
229: for (i = 0; i < 2; i++) {
230: if (!move_to_sky(n)) {
231: return(NULL);
232: }
233: sky->arg[i] = n;
234: n = n->forw;
235: }
236:
237: /*
238: * Get the instruction to fetch the result from the board.
239: * It may be preceeded by a test loop.
240: */
241: if (n->op == OP_LABEL) {
242: for (i = 0; i < 3; i++) {
243: n = n->forw;
244: }
245: sky->tstloop = 1;
246: }
247: if (!move_from_sky(n)) {
248: return(NULL);
249: }
250: sky->result = n;
251:
252: n = n->forw;
253: sky->next = NULL;
254: *np = n;
255: return(sky);
256: }
257:
258: /*
259: * Is this instruction a movl to the sky board?
260: */
261: move_to_sky(n)
262: NODE *n;
263: {
264: struct oper *op2;
265: int regno;
266: int inexact;
267:
268: if (n->op == OP_MOVE && n->subop == SUBOP_L) {
269: regno = reglookup(&skybase, SUBOP_L, &inexact);
270: op2 = n->ref[1];
271: if (op2->type_o == T_DEFER && regno == op2->value_o) {
272: return(1);
273: }
274: }
275: return(0);
276: }
277:
278: /*
279: * Is this instruction a movl from the sky board?
280: */
281: move_from_sky(n)
282: NODE *n;
283: {
284: struct oper *op1;
285: int regno;
286: int inexact;
287:
288: if (n->op == OP_MOVE && n->subop == SUBOP_L) {
289: regno = reglookup(&skybase, SUBOP_L, &inexact);
290: op1 = n->ref[0];
291: if (op1->type_o == T_DEFER && regno == op1->value_o) {
292: return(1);
293: }
294: }
295: return(0);
296: }
297:
298: /*
299: * See if this instruction stores the result of the sky operation
300: * into memory or otherwise kills the result.
301: */
302: result_killed(n, sky)
303: NODE *n;
304: struct skylist *sky;
305: {
306: struct oper *result;
307: struct oper *op1;
308: struct oper *op2;
309: int i;
310:
311: /*
312: * Is this a movl from the register holding the sky result?
313: */
314: result = sky->result->ref[1];
315: if (n->op == OP_MOVE && n->subop == SUBOP_L) {
316: op1 = n->ref[0];
317: if (op1->type_o == T_REG && op1->value_o == result->value_o) {
318: return(1);
319: }
320: }
321:
322: /*
323: * Is the destination of this instruction the register holding
324: * the sky result?
325: */
326: op2 = n->ref[1];
327: if (result->type_o == T_REG &&
328: op2->type_o == T_REG &&
329: op2->value_o == result->value_o) {
330: return(1);
331: }
332: return(0);
333: }
334:
335: /*
336: * Is the result of this sky operation assigned to a register.
337: */
338: result_is_reg(sky)
339: struct skylist *sky;
340: {
341: struct oper *result;
342: int i;
343:
344: result = sky->result->ref[1];
345: if (result->type_o == T_REG) {
346: return(1);
347: }
348: return(0);
349: }
350:
351: /*
352: * Is this instuction a movw of an opcode to the sky board?
353: */
354: is_sky_operation(n)
355: NODE *n;
356: {
357: struct oper *op1;
358: struct oper *op2;
359: int regno;
360: int inexact;
361:
362: op1 = n->ref[0];
363: op2 = n->ref[1];
364: if (n->op != OP_MOVE ||
365: op1->type_o != T_IMMED ||
366: !isskyop(op1->value_o) ||
367: op2->type_o != T_DISPL) {
368: return(0);
369: }
370: regno = reglookup(&skybase, SUBOP_L, &inexact);
371: if (regno != op2->reg_o ||
372: op2->value_o != -4) {
373: return(0);
374: }
375: return(1);
376: }
377:
378: /*
379: * Rewrite a list of sky operations doing optimizations along the way.
380: * Look the for the results of one operation being used as an operand
381: * of the next operations. Accumulator operations can be used in
382: * this case.
383: */
384: rewrite_list(sky)
385: struct skylist *sky;
386: {
387: struct skylist *skyp;
388: struct skylist *last_changed;
389: NODE *result;
390: NODE *arg;
391: int first;
392: int i;
393:
394: first = 1;
395: last_changed = NULL;
396: for (skyp = sky; skyp->next != NULL; skyp = skyp->next) {
397: result = skyp->result;
398: if (result == NULL) {
399: continue;
400: }
401: for (i = 0; i < 2; i++) {
402: arg = skyp->next->arg[i];
403: if (sameops(result->ref[0], arg->ref[1]) &&
404: sameops(result->ref[1], arg->ref[0])) {
405: meter.nskyreg++;
406: if (first) {
407: insert_reg_load(skyp);
408: change_to_reg(skyp, 0);
409: }
410: change_to_reg(skyp->next, i);
411: last_changed = skyp->next;
412: first = 0;
413: break;
414: }
415: }
416: if (i == 2 && last_changed != NULL) {
417: fetch_result(last_changed);
418: first = 1;
419: last_changed = NULL;
420: }
421: }
422: if (!first && last_changed != NULL) {
423: fetch_result(last_changed);
424: }
425: }
426:
427: /*
428: * Change an operation to use the accumulator and also
429: * to leave its result in the accumulator.
430: * Remove the instructions that fetch the result from the board.
431: * Add a tst loop after the operation to wait for the result
432: * to solidify.
433: */
434: change_to_reg(sky, argn)
435: struct skylist *sky;
436: int argn;
437: {
438: NODE *arg;
439: NODE *n;
440: struct skyop *skyop;
441: struct oper *opcode;
442: int op;
443: int i;
444:
445: opcode = sky->skyload->ref[0];
446: op = opcode->value_o;
447: sky->oldop = op;
448: skyop = findop(op);
449: if (skyop == NULL) {
450: return;
451: }
452: opcode->value_o = skyop->arg_op[argn];
453: arg = sky->arg[argn];
454: arg = deletenode(arg);
455: if (sky->tstloop) {
456: n = sky->result;
457: for (i = 0; i < 3; i++) {
458: n = n->back;
459: }
460: delete_tst_loop(n);
461: sky->tstloop = 0;
462: }
463: sky->oldresult = remove(sky->result);
464: insert_tst_loop(sky->skyload->forw, sky->skyload->ref[1]);
465: }
466:
467: /*
468: * Insert a test loop waiting for the SKY idle bit to turn on.
469: * Insert the code:
470: * 1: btst #6,skybase(-2)
471: * beqs 1b
472: */
473: insert_tst_loop(node, skybase)
474: NODE *node;
475: struct oper *skybase;
476: {
477: NODE *label;
478: NODE *btst;
479: NODE *beqs;
480: struct sym_bkt *sbp;
481: char ltoken[20];
482: extern char *ll_format;
483: extern int ll_val[];
484: static struct oper btstbit = { T_IMMED, 0, 0, 0, NULL, NULL, 0, IDLE, 0 };
485: static struct oper labelop = { T_NORMAL, 0, 0, 0, NULL, NULL, 0, 0, 0 };
486:
487: sprintf(ltoken, ll_format, '1', ++ll_val[1]);
488: sbp = lookup(ltoken);
489: sbp->attr_s |= S_LABEL | S_DEC | S_DEF;
490: sbp->csect_s = C_TEXT;
491:
492: label = new();
493: label->op = OP_LABEL;
494: label->subop = SUBOP_Z;
495: label->nref = 1;
496: label->name = sbp;
497:
498: btst = new();
499: btst->op = OP_OTHER;
500: btst->subop = SUBOP_B;
501: btst->instr = sopcode("btst");
502: btst->nref = 2;
503: btst->ref[0] = newoperand(&btstbit);
504: btst->ref[1] = newoperand(skybase);
505: btst->ref[1]->value_o = STATUS_WORD;
506:
507: labelop.sym_o = sbp;
508: beqs = new();
509: beqs->op = OP_JUMP;
510: beqs->subop = JGE;
511: beqs->instr = sopcode("beqs");
512: beqs->nref = 0;
513: beqs->ref[0] = newoperand(&labelop);
514: beqs->luse = label;
515:
516: label->forw = btst;
517: btst->forw = beqs;
518: beqs->back = btst;
519: btst->back = label;
520: insert(label, node);
521: }
522:
523: /*
524: * Remove a node from the list
525: */
526: NODE *
527: remove(p)
528: NODE *p;
529: {
530: p->back->forw = p->forw;
531: p->forw->back = p->back;
532: p->back = NULL;
533: p->forw = NULL;
534: return(p);
535: }
536:
537: /*
538: * Find an opcode in the opcode table
539: */
540: struct skyop *
541: findop(op)
542: int op;
543: {
544: struct skyop *sp;
545:
546: for (sp = regops; sp->op != 0; sp++) {
547: if (sp->op == op) {
548: return(sp);
549: }
550: }
551: return(NULL);
552: }
553:
554: /*
555: * Insert code to load the sky register with a value.
556: * Load it with the first operand of the sky operation
557: * passed in here.
558: */
559: insert_reg_load(sky)
560: struct skylist *sky;
561: {
562: NODE *p;
563: NODE *load;
564: NODE *arg;
565:
566: load = sky->skyload;
567: p = newinst(load, load->ref[0], load->ref[1]);
568: p->ref[0]->value_o = SP_LOAD;
569: insert(p, load->back);
570:
571: arg = sky->arg[0];
572: p = newinst(arg, arg->ref[0], arg->ref[1]);
573: insert(p, load->back);
574: }
575:
576: /*
577: * Create a new instruction.
578: * Copy the old one passed in and then give it the new arguments.
579: */
580: NODE *
581: newinst(oldinst, arg1, arg2)
582: NODE *oldinst;
583: struct oper *arg1;
584: struct oper *arg2;
585: {
586: NODE *p;
587:
588: p = new();
589: *p = *oldinst;
590: p->forw = NULL;
591: p->back = NULL;
592: p->ref[0] = newoperand(arg1);
593: p->ref[1] = newoperand(arg2);
594: return(p);
595: }
596:
597: /*
598: * Change the code to fetch the result from the sky board.
599: * If possible change last operation to use R0 as an operand
600: * and generate a fetch'able result.
601: * Otherwise, insert additional code to fetch the result.
602: */
603: fetch_result(sky)
604: struct skylist *sky;
605: {
606: NODE *n;
607: NODE *p;
608: NODE *load;
609: NODE *result;
610: struct skyop *skyop;
611: int i;
612:
613: skyop = findop(sky->oldop);
614: if (skyop->fetch != 0) {
615: n = sky->skyload->forw;
616: n = n->forw;
617: if (n->op == OP_LABEL) {
618: n = delete_tst_loop(n);
619: sky->tstloop = 0;
620: }
621: sky->skyload->ref[0]->value_o = skyop->fetch;
622: insert(sky->oldresult, n);
623: } else {
624: load = sky->skyload;
625: n = load->forw;
626: for (i = 0; i < 3; i++) {
627: n = n->forw;
628: }
629: p = newinst(load, load->ref[0], load->ref[1]);
630: p->ref[0]->value_o = SP_STORE;
631: insert(p, n);
632: n = n->forw;
633:
634: result = sky->oldresult;
635: p = newinst(result, result->ref[0], result->ref[1]);
636: insert(p, n);
637: }
638: }
639:
640: /*
641: * Delete a test loop.
642: * The actual test and branch may differ here.
643: */
644: NODE *
645: delete_tst_loop(n)
646: NODE *n;
647: {
648: if (n->op != OP_LABEL) {
649: fprintf(stderr, "c2: internal error deleting test loop\n");
650: exit(1);
651: }
652: n = deletenode(n); /* Label */
653: n = n->forw;
654: n = deletenode(n); /* test */
655: n = n->forw;
656: n = deletenode(n); /* branch */
657: return(n);
658: }
659:
660: /*
661: * Free a list of sky structures
662: */
663: free_list(sky)
664: struct skylist *sky;
665: {
666: struct skylist *next;
667: struct skylist *skyp;
668:
669: for (skyp = sky; skyp != NULL; skyp = next) {
670: next = skyp->next;
671: free(skyp);
672: }
673: }
674:
675: /*
676: * Look for the sequence:
677: *
678: * movl skybaseR@,X
679: * movl skybaseR@,Y
680: * movl X,mem1
681: * movl Y,mem2
682: *
683: * Change it to
684: *
685: * movl skybaseR@,mem1
686: * movl skybaseR@,mem2
687: *
688: * This sequence occurs when a double precision value is fetched from
689: * the SKY board and is stored into memory.
690: */
691: skymove(n)
692: NODE *n;
693: {
694: NODE *n1;
695: NODE *n2;
696: NODE *n3;
697: int reg;
698: int reg1;
699:
700: n1 = n->forw;
701: n2 = n1->forw;
702: n3 = n2->forw;
703: if (skytoreg(n) && skytoreg(n1)) {
704: reg = n->ref[1]->value_o;
705: reg1 = n1->ref[1]->value_o;
706: if (regtomem(n2, reg) && regtomem(n3, reg1)) {
707: if (!inmask(reg, n3->forw->rlive ) &&
708: !inmask(reg1, n3->forw->rlive ) ) {
709: n->ref[1] = newoperand(n2->ref[1]);
710: n1->ref[1] = newoperand(n3->ref[1]);
711: deletenode(n2);
712: deletenode(n3);
713: meter.ndpsky++;
714: return(1);
715: }
716: }
717: }
718: return(0);
719: }
720:
721: /*
722: * Look for the instruction
723: *
724: * movl skybaseR@,X
725: *
726: * which fetches a value from the sky board and puts it in a register.
727: * skybaseR is a register containing __skybase and X is a register.
728: */
729: static
730: skytoreg(n)
731: NODE *n;
732: {
733: struct oper *op1;
734: struct oper *op2;
735: struct oper *con;
736: struct sym_bkt *sym;
737: int reg;
738: extern struct oper *get_regcon();
739:
740: if (n->op != OP_MOVE || n->subop != SUBOP_L) {
741: return(0);
742: }
743: op1 = n->ref[0];
744: op2 = n->ref[1];
745: if (op1->type_o != T_DEFER) {
746: return(0);
747: }
748: reg = op1->value_o;
749: sym = get_regcon( reg )->sym_o;
750: if (skyname == NULL || sym != skyname) {
751: return(0);
752: }
753: if (op2->type_o != T_REG) {
754: return(0);
755: }
756: return(1);
757: }
758:
759: /*
760: * Look for the instruction
761: *
762: * movl X,mem
763: *
764: * where X is a register.
765: */
766: static
767: regtomem(n, reg)
768: NODE *n;
769: int reg;
770: {
771: struct oper *op1;
772: struct oper *op2;
773:
774: if (n->op != OP_MOVE || n->subop != SUBOP_L) {
775: return(0);
776: }
777: op1 = n->ref[0];
778: op2 = n->ref[1];
779: if (op1->value_o == reg && op2->type_o != T_REG) {
780: return(1);
781: }
782: return(0);
783: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.