/* ** Things to do: ** ** Put in assembly data directives (dc i0, good stuff) ** Optimize using side-swapping constant search */ /* C compiler: symbolic code generator */ #include "c.h" #define SWAP_OK 1 #define SWAP_NOT_OK 0 /* func prototypes */ char *memset(void *, void *, int); char *memcpy(void *, void *, int); static int frame_offset, local_stack_frame; /* current frame offset */ static int argument_space; static Node *tail; /* Hack start */ #define MAX_TEMPS 256 int temps[MAX_TEMPS]; static int pass1_flag; static int deep_stack_flag; static int temps_used; static int current_segment = CODE; static int inside_segment = 0; static char filename[32]; static int data_segment_num = 0; /* Hack end */ dclproto(extern char *asmname,(Symbol)); dclproto(extern unsigned regloc,(Symbol)); dclproto(extern int regoffset,(int, int)); dclproto(static int gen1,(Node, int, int)); dclproto(static void symname,(Symbol)); /* address - initialize q for addressing expression p+n */ void address(q, p, n) Symbol q, p; int n; { q->x.name = stringf("%s%s%d", p->x.name, n > 0 ? "+" : "", n); } /* asmcode - emit assembly language specified by asm */ void asmcode(char *str, Symbol argv[]) { for ( ; *str; str++) if ((*str == '%') && (str[1] >= 0) && (str[1] <= 9)) print("%s", asmname(argv[*++str])); else *bp++ = *str; outs("\n"); } /* asmname - print assembler code for symbol p */ char *asmname(p) Symbol p; { return p->x.name; } /* defconst - define a constant */ void defconst(int ty, Value v) { switch (ty) { case C: print("\tdc.b\t%d\n", v.uc); break; case S: print("\tdc.w\t%d\n", v.ss); break; case I: print("\tdc.w\t%d\n", v.i); break; case U: print("\tdc.w\t%d\n", v.u); break; case P: print("\tdc.l\t$%x\n", v.p); break; case F: print("\tdc.l\t$%x\n", v.u); break; case D: print("\tdc.l\t$%x,$%x\n", v.i, *(&v.i + 1)); break; default: print("unknown constant type: %c\n", ty); assert(0); } } void defstring(int len, char *s) { int i, count = 0; for (i=0; iname); if (p->scope == CONSTANTS) p->x.name = stringf("$%x", atol(p->name)); else if (p->generated) p->x.name = stringf("L%s", p->name); else p->x.name = stringf("_%s", p->name); } extern char *infile; /* progbeg - beginning of program */ void progbeg(argc, argv) char *argv[]; { char *source; print("* progbeg(), infile = %s\n", infile); strcpy(filename, infile); if (strrchr(filename, (int)'\\')) strcpy(filename, strrchr(filename, (int)'\\') + 1); else strcpy(filename, infile); if (strchr(filename, (int) '.')) *(char *)strchr(filename, '.') = 0; print("* filename: %s\n", filename); } /* regloc - return "id" for p's register */ unsigned regloc(p) Symbol p; { assert(p && p->sclass == REGISTER); return 0; } /* regoffset - return stack offset of cell that saves reg */ int regoffset(regset, regnum) { return -1; } /* sym - print symbol table entry for p, followed by str */ void sym(kind, p, str) char *kind, *str; Symbol p; { print("* sym() entry\n"); assert(kind); print("* %s (%s) type=%t class=%k scope=", p->name, p->x.name, p->type, p->sclass, p->scope); switch (p->scope) { case CONSTANTS: print("CONSTANTS"); break; case LABELS: print("LABELS"); break; case GLOBAL: print("GLOBAL"); break; case PARAM: print("PARAM"); break; case LOCAL: print("LOCAL"); break; default: if (p->scope > LOCAL) print("LOCAL+%d", p->scope - LOCAL); else print("%d", p->scope); } if (p->scope >= PARAM && p->sclass != STATIC) print(" offset=%d ref=%d", p->x.offset, p->ref); if (glevel > 2) { print(" up="); symname(p->up); } if (str) print(str); if (pass1_flag) return; if (current_segment == CODE) { if (p->scope == PARAM) print("%s\tequ\t%d\n", p->x.name, p->x.offset); else print("%s\tlabel\n", p->x.name); } else { if (inside_segment) print("%s\tentry\n", p->x.name); else print("sym(): Error!\n"); } } /* symname - print prefix, p's name, declaration source coordinate, suffix */ static void symname(p) Symbol p; { if (p) print("%s@%w.%d", p->name, &p->src, p->src.x); else print("0"); } /* stabend - finalize stab output */ void stabend(cp, p, cpp, sp, stab) Coordinate *cp, **cpp; Symbol p, *sp, *stab; { int i; symname(p); print("\n"); for (i = 0; cpp[i] && sp[i]; i++) { print("%w.%d: ", cpp[i], cpp[i]->x); symname(sp[i]); print("\n"); } } /* stabline - emit line number information for source coordinate *cp */ void stabline(cp) Coordinate *cp; { if (cp->file) print("%s:", cp->file); print("%d.%d:\n", cp->y, cp->x); } /************************************* * Start temporary allocation functions *************************************/ /* ** Very simplistic temporary allocation routines, ** but should be reasonably fast. */ /* ** Clear temporaries */ static void Clear_Temps(void) { memset(temps, 0, sizeof(temps)); } /* ** Allocate single temporary */ static int Alloc_Single_Temp(void) { int i; for (i=0; i temps_used) temps_used = i + 1; return i; } assert(0); } /* ** Allocate double temporary */ static int Alloc_Double_Temp(void) { int i; for (i=0; i temps_used) temps_used = i + 2; return i; } assert(0); } /* ** Allocate quad temporary */ static int Alloc_Quad_Temp(void) { int i; for (i=0; i temps_used) temps_used = i + 4; return i; } assert(0); } /* ** Allocate automagic size temporary */ static int Alloc_Auto_Temp(Node p) { switch(optype(p->op)) { case C: case S: return Alloc_Single_Temp(); case I: case U: case P: case F: return Alloc_Double_Temp(); case D: return Alloc_Quad_Temp(); default: error("Attempted to allocate unknown temporary size\n"); } } /* ** Deallocate temporary */ static void Free_Temp(int temp_num) { if (temps[temp_num] == 1) temps[temp_num] = 0; else if (temps[temp_num] == 2) { temps[temp_num] = 0; temps[temp_num+1] = 0; } else if (temps[temp_num] == 4) { temps[temp_num] = 0; temps[temp_num+1] = 0; temps[temp_num+2] = 0; temps[temp_num+3] = 0; } else { print("Free_Temp(): temp%d already deallocated"); assert(0); } } /************************************* * End temporary allocation functions *************************************/ /************************************* * Start code generation functions *************************************/ static void Emit_Nodes(Node p); /* ** Calculate node cost */ static int Calc_Cost(Node p) { int cost, return_flag; Node kid0, kid00; if (!p) return 0; if (kid0 = p->kids[0]) kid00 = kid0->kids[0]; else kid00 = kid0; return_flag = cost = 0; switch(generic(p->op)) { case ADDRFP: case ADDRLP: /* tsc, clc, adc #x, ldx #0 */ cost = 10; break; case ADDRGP: /* lda #op) == INDIR)) { if (kid00 && !kid00->kids[0]) if ((kid00->op == ADDRFP) || (kid00->op == ADDRLP)) return_flag = cost = 4; else if (kid00->op == ADDRGP) return_flag = cost = 5; } else cost = 3; break; case CALL: cost = 99; break; case CNST: /* lda #foo */ cost = 3; break; case CVC: /* bit #$80, bne, ora #$8000, bra, and #$00ff */ /* always I or U, so half the number */ cost = 5; break; case CVS: /* could be 3-x cycles */ cost = 5; break; case DIV: case MUL: cost = 99; break; case EQ: case GE: case GT: case LE: case LT: case NE: /* varies lots */ cost = 10; break; case INDIR: cost = 5; break; case JUMP: cost = 4; break; case LSH: case RSH: /* average should be around 2 shifts */ cost = 20; break; case RET: cost = 20; break; } switch(optype(p->op)) { case I: case U: case P: cost *= 2; } if (return_flag) return cost; else return Calc_Cost(p->kids[0]) + Calc_Cost(p->kids[1]); } /* ** Emit size of instruction */ static char Instruct_Size(Node p) { switch(optype(p->op)) { case C: return 'b'; case S: return 'w'; case U: case I: case P: return 'l'; case D: return 'd'; case F: return 'f'; default: error("Unknown instruction size: %c\n", optype(p->op)); } } /* ** Emit addressing mode of a node */ static char Addr_Mode(Node p) { switch(p->op) { case ADDRFP: case ADDRLP: return '<'; case ADDRGP: return '>'; default: error("Unknown addressing mode!\n"); } } /* ** Special Generic Op Sub() */ static int Special_Generic_Op2(Node p, Node kid0, Node kid1, char *operator) { Node kid00; if (!kid0) return 0; kid00 = kid0->kids[0]; print("* opname: %s\n", opname(generic(kid0->op))); switch(generic(kid0->op)) { case CNST: print("* kid0->op == CNST\n"); Emit_Nodes(kid1); if (!pass1_flag) print("\t%s.%c\t#%s\n", operator, Instruct_Size(p), kid0->syms[0]->x.name); return 1; #if 0 case ADDRG: print("* kid0->op == ADDRG\n"); Emit_Nodes(kid1); if (!pass1_flag) print("\t%s.%c\t&%s\n", operator, Instruct_Size(p), kid0->syms[0]->x.name); return 1; #endif case INDIR: print("* kid1->op == INDIR\n"); if (!kid00 || kid00->kids[0]) return 0; switch(kid00->op) { case ADDRFP: case ADDRLP: case ADDRGP: Emit_Nodes(kid1); if (!pass1_flag) print("\t%s.%c\t%c%s\n", operator, Instruct_Size(p), Addr_Mode(kid00), kid00->syms[0]->x.name); return 1; default: return 0; } } return 0; } /* ** Special_Generic_Op() */ static int Special_Generic_Op(Node p, char *operator, int swap_flag) { if (Calc_Cost(p->kids[0]) > Calc_Cost(p->kids[1])) { if (swap_flag && Special_Generic_Op2(p, p->kids[0], p->kids[1], operator)) return 1; if (Special_Generic_Op2(p, p->kids[1], p->kids[0], operator)) return 1; } else { if (Special_Generic_Op2(p, p->kids[1], p->kids[0], operator)) return 1; if (swap_flag && Special_Generic_Op2(p, p->kids[0], p->kids[1], operator)) return 1; } print("* Special_Generic_Op() for %s failed\n", operator); return 0; } /* ** Generic Operation */ static void Generic_Op(Node p, char *operator, int swap_flag) { if (Special_Generic_Op(p, operator, swap_flag)) return; Emit_Nodes(p->kids[1]); if (pass1_flag) p->x.temp_num = Alloc_Auto_Temp(p); else print("\tst.%c\tx.temp_num); Emit_Nodes(p->kids[0]); if (pass1_flag) Free_Temp(p->x.temp_num); else print("\t%s.%c\tx.temp_num); } /* ** Generic branch */ static void Generic_Branch(Node p, char *operator, char *inv_operator) { if (p->kids[1] && (p->kids[1]->op == CNSTI)) { print("* constant compare optimization\n"); Emit_Nodes(p->kids[0]); if (pass1_flag) return; print("\tcmp.l\t#%s\n", p->kids[1]->syms[0]->x.name); print("\t%s\t%s\n", operator, p->syms[0]->x.name); return; } else if (p->kids[0] && (p->kids[0]->op == CNSTI)) { print("* constant compare optimization inverse\n"); Emit_Nodes(p->kids[1]); if (pass1_flag) return; print("\tcmp.l\t#%s\n", p->kids[0]->syms[0]->x.name); print("\t%s\t%s\n", inv_operator, p->syms[0]->x.name); return; } else { Emit_Nodes(p->kids[1]); if (pass1_flag) p->x.temp_num = Alloc_Double_Temp(); else print("\tst.l\tx.temp_num); Emit_Nodes(p->kids[0]); if (pass1_flag) return; print("\tcmp.l\tx.temp_num); print("\t%s\t%s\n", operator, p->syms[0]->x.name); } } /* ** Emit_ADD() */ static void Emit_ADD(Node p) { Generic_Op(p, "add", SWAP_OK); } /* ** Emit_ADDRFL() ** ** optypes: P */ static void Emit_ADDRFL(Node p) { if (!pass1_flag) if (*p->syms[0]->x.name == '+') print("\tlea\tsyms[0]->x.name); else print("\tlea\t<%s\n", p->syms[0]->x.name); } /* ** Emit_ADDRG() */ static void Emit_ADDRG(Node p) { if (!pass1_flag) print("\tlea\t>%s\n", p->syms[0]->x.name); } /* ** Special_Emit_ARG() */ static int Special_Emit_ARG(Node p) { Node kid0, kid00; kid0 = p->kids[0]; kid00 = kid0->kids[0]; print("****** testing ****** %s\n", opname(kid0->op)); if (kid00) return 0; switch(generic(kid0->op)) { case CNST: if (!pass1_flag) print("\tpush.%c\t#%s\n", Instruct_Size(p), kid0->syms[0]->x.name); return 1; case ADDRF: case ADDRL: case ADDRG: if (!pass1_flag) print("\tpusha\t%c%s\n", Addr_Mode(kid0), kid0->syms[0]->x.name); return 1; } return 0; } /* ** Emit_ARG() ** ** Pushes call arguments on stack. */ static void Emit_ARG(Node p) { argument_space += 4; if (Special_Emit_ARG(p)) return; Emit_Nodes(p->kids[0]); if (!pass1_flag) print("\tpush.l\n"); } /* ** Special Emit_ASGN() */ static int Special_Emit_ASGN(Node p) { Node kid0 = p->kids[0]; if (kid0->kids[0]) return 0; switch(kid0->op) { case ADDRFP: case ADDRLP: case ADDRGP: if (!pass1_flag) print("\tst.%c\t%c%s\n", Instruct_Size(p), Addr_Mode(kid0), kid0->syms[0]->x.name); return 1; } print("* not optimized\n"); return 0; } /* ** Emit_ASGN() ** ** optypes: CSI PFDB */ static void Emit_ASGN(Node p) { Emit_Nodes(p->kids[1]); /* Right-hand side */ if (Special_Emit_ASGN(p)) return; if (pass1_flag) p->x.temp_num = Alloc_Auto_Temp(p); else print("\tst.%c\tx.temp_num); Emit_Nodes(p->kids[0]); /* Left-hand side */ if (pass1_flag) { p->x.temp2_num = Alloc_Double_Temp(); Free_Temp(p->x.temp_num); Free_Temp(p->x.temp2_num); } else { print("\tst.l\tx.temp2_num); print("\tld.%c\tx.temp_num); print("\tsti.%c\tx.temp2_num); } } /* ** Emit_BAND() */ static void Emit_BAND(Node p) { Generic_Op(p, "and", SWAP_OK); } /* ** Emit_BCOM() ** ** Valid optypes: U */ static void Emit_BCOM(Node p) { Emit_Nodes(p->kids[0]); if (!pass1_flag) print("\tneg.l\n"); } /* ** Emit_BOR() */ static void Emit_BOR(Node p) { Generic_Op(p, "or", SWAP_OK); } /* ** Emit_BXOR() */ static void Emit_BXOR(Node p) { Generic_Op(p, "eor", SWAP_OK); } /* ** Special Emit_CALL() */ static int Special_Emit_CALL(Node p) { Node kid0; kid0 = p->kids[0]; if (kid0->kids[0]) return 0; switch(kid0->op) { case ADDRGP: if (!pass1_flag) print("\tjsr\t%s\n", kid0->syms[0]->x.name); return 1; } return 0; } /* ** Emit_CALL() */ static void Emit_CALL(Node p) { if (!Special_Emit_CALL(p)) { Emit_Nodes(p->kids[0]); if (!pass1_flag) print("\tjsri\n"); } if (!pass1_flag && argument_space) { print("\tpop\t#%d\n", argument_space); argument_space = 0; } } /* ** Emit_CNST() ** ** Valid optypes: CSIUPFD */ static void Emit_CNST(Node p) { if (pass1_flag) return; switch(optype(p->op)) { case C: case S: print("\tld.w\t#%s\n", p->syms[0]->x.name); break; case I: case U: case P: print("\tld.l\t#%s\n", p->syms[0]->x.name); break; } } /* ** Emit_CVC() ** ** Valid optypes: IU */ static void Emit_CVC(Node p) { Emit_Nodes(p->kids[0]); if (pass1_flag) return; switch(optype(p->op)) { case I: print("\text.bl\n"); break; case U: print("\tand.l\t#255\n"); break; } } /* ** Emit_CVD() ** ** Valid optypes: ? */ static void Emit_CVD(Node p) { Emit_Nodes(p->kids[0]); if (pass1_flag) return; switch(optype(p->op)) { case F: print("\tcvdf\n"); break; } } /* ** Emit_CVI() ** ** Valid optypes: CSUD */ static void Emit_CVI(Node p) { Emit_Nodes(p->kids[0]); } /* ** Emit_CVP() */ static void Emit_CVP(Node p) { Emit_Nodes(p->kids[0]); } /* ** Emit_CVS() ** ** Valid optypes: IU */ static void Emit_CVS(Node p) { Emit_Nodes(p->kids[0]); if (pass1_flag) return; switch(optype(p->op)) { case I: print("\text.wl\n"); break; case U: print("\tand.l\t#65535\n"); break; } } /* ** Emit_CVU */ static void Emit_CVU(Node p) { Emit_Nodes(p->kids[0]); } /* ** Emit_DIV ** ** This evaluates rhs before lhs for convenience - this is legal. ** (See "The C Programming Language", 2nd ed, pp 51-52) */ static void Emit_DIV(Node p) { Emit_Nodes(p->kids[1]); #if 0 if (Special_Emit_ADD(p)) return; #endif if (pass1_flag) p->x.temp_num = Alloc_Auto_Temp(p); else print("\tst.%c\tx.temp_num); Emit_Nodes(p->kids[0]); if (pass1_flag) Free_Temp(p->x.temp_num); else switch(optype(p->op)) { case I: print("\tdivi.%c\tx.temp_num); break; case U: print("\tdivu.%c\tx.temp_num); break; } } /* ** Emit_EQ() */ static void Emit_EQ(Node p) { Generic_Branch(p, "beq", "beq"); } /* ** Emit_GE() */ static void Emit_GE(Node p) { Generic_Branch(p, "bge", "blt"); } /* ** Emit_GT() */ static void Emit_GT(Node p) { Generic_Branch(p, "bgt", "ble"); } /* ** Special_Emit_INDIR() */ static int Special_Emit_INDIR(Node p) { Node kid0, kid00; /* p is guaranteed to have a valid kid[0] */ kid0 = p->kids[0]; kid00 = kid0->kids[0]; if (kid00) return 0; switch(kid0->op) { case ADDRFP: case ADDRLP: case ADDRGP: if (!pass1_flag) print("\tld.%c\t%c%s\n", Instruct_Size(p), Addr_Mode(kid0), kid0->syms[0]->x.name); return 1; } return 0; } /* ** Emit_INDIR() ** ** Valid optypes: CSIPFDB */ static void Emit_INDIR(Node p) { if (Special_Emit_INDIR(p)) return; Emit_Nodes(p->kids[0]); if (pass1_flag) return; switch(optype(p->op)) { case C: case S: case I: case U: case P: print("\tldi.%c\n", Instruct_Size(p)); } } /* ** Special_Emit_Jump() */ static int Special_Emit_Jump(Node p) { Node kid0; kid0 = p->kids[0]; if (kid0->op == ADDRGP) { if (!pass1_flag) print("\tjmp\t%s\n", kid0->syms[0]->x.name); return 1; } return 0; } /* ** Emit_JUMP() */ static void Emit_JUMP(Node p) { if (Special_Emit_Jump(p)) return; Emit_Nodes(p->kids[0]); if (!pass1_flag) print("\tjmpi\n", p->syms[0]->x.name); } /* ** Emit_LABEL() */ static void Emit_LABEL(Node p) { if (!pass1_flag) print("%s\tlabel\n", p->syms[0]->x.name); } /* ** Emit_LE() */ static void Emit_LE(Node p) { Generic_Branch(p, "ble", "bgt"); } /* ** Emit_LSH() */ static void Emit_LSH(Node p) { Generic_Op(p, "lsh", SWAP_NOT_OK); #if 0 Emit_Nodes(p->kids[1]); if (pass1_flag) p->x.temp_num = Alloc_Double_Temp(); else print("\tst.l\tx.temp_num); Emit_Nodes(p->kids[0]); if (pass1_flag) return; switch (optype(p->op)) { case U: print("\tlshu.l\tx.temp_num); case I: print("\tlshi.l\tx.temp_num); } #endif } /* ** Emit_LT() */ static void Emit_LT(Node p) { Generic_Branch(p, "blt", "bge"); } /* ** Emit_MUL() */ static void Emit_MUL(Node p) { Emit_Nodes(p->kids[0]); #if 0 if (Special_Emit_ADD(p)) return; #endif if (pass1_flag) p->x.temp_num = Alloc_Auto_Temp(p); else print("\tst.%c\tx.temp_num); Emit_Nodes(p->kids[1]); if (pass1_flag) Free_Temp(p->x.temp_num); else switch(optype(p->op)) { case I: print("\tmuli.%c\tx.temp_num); break; case U: print("\tmulu.%c\tx.temp_num); break; } } /* ** Emit_NE() */ static void Emit_NE(Node p) { Generic_Branch(p, "bne", "bne"); } /* ** Emit_RET() */ static void Emit_RET(Node p) { Emit_Nodes(p->kids[0]); if (!pass1_flag) func_epilogue(local_stack_frame); } /* ** Emit_RSH() */ static void Emit_RSH(Node p) { Emit_Nodes(p->kids[1]); if (pass1_flag) p->x.temp_num = Alloc_Double_Temp(); else print("\tst.l\tx.temp_num); Emit_Nodes(p->kids[0]); if (pass1_flag) return; switch (optype(p->op)) { case U: print("\trshu.l\tx.temp_num); case I: print("\trshi.l\tx.temp_num); } } /* ** Emit_SUB() */ static void Emit_SUB(Node p) { Generic_Op(p, "sub", SWAP_NOT_OK); #if 0 Emit_Nodes(p->kids[1]); if (pass1_flag) p->x.temp_num = Alloc_Auto_Temp(p); else print("\tst.%c\tx.temp_num); Emit_Nodes(p->kids[0]); if (pass1_flag) Free_Temp(p->x.temp_num); else print("\tsub.%c\tx.temp_num); #endif } /* ** Emit_Nodes() ** ** This is the main recursive function for emitting code. */ static void Emit_Nodes(Node p) { if (!p) return; if (pass1_flag) { if (p->x.cache_flag && p->x.loaded1_flag) { print("* loaded from cache (temp%d) (refs: %d)\n", p->x.cache_num, p->x.count2); if ((--p->x.count2) < 0) { Free_Temp(p->x.cache_num); print("* freed cache (temp%d)\n", p->x.cache_num); } return; } } else { if (p->x.cache_flag && p->x.loaded2_flag) { switch(optype(p->op)) { case C: case S: print("\tld.w\tx.cache_num); return; case I: case U: case P: print("\tld.l\tx.cache_num); return; } } } print("* Emit_Nodes(%s)\n", opname(p->op)); switch(generic(p->op)) { case ADD: Emit_ADD(p); break; case ADDRF: case ADDRL: Emit_ADDRFL(p); break; case ADDRG: Emit_ADDRG(p); break; case ARG: Emit_ARG(p); break; case ASGN: Emit_ASGN(p); break; case BCOM: Emit_BCOM(p); break; case BAND: Emit_BAND(p); break; case BOR: Emit_BOR(p); break; case BXOR: Emit_BXOR(p); break; case CALL: Emit_CALL(p); break; case CNST: Emit_CNST(p); break; case CVC: Emit_CVC(p); break; case CVD: Emit_CVD(p); break; case CVI: Emit_CVI(p); break; case CVP: Emit_CVP(p); break; case CVS: Emit_CVS(p); break; case CVU: Emit_CVU(p); break; case DIV: Emit_DIV(p); break; case EQ: Emit_EQ(p); break; case GE: Emit_GE(p); break; case GT: Emit_GT(p); break; case INDIR: Emit_INDIR(p); break; case JUMP: Emit_JUMP(p); break; case LABEL: Emit_LABEL(p); break; case LSH: Emit_LSH(p); break; case LE: Emit_LE(p); break; case LT: Emit_LT(p); break; case MUL: Emit_MUL(p); break; case NE: Emit_NE(p); break; case RET: Emit_RET(p); break; case RSH: Emit_RSH(p); break; case SUB: Emit_SUB(p); break; } if (pass1_flag) { if (p->x.cache_flag) { if (!p->x.loaded1_flag) { p->x.loaded1_flag = 1; switch(optype(p->op)) { case C: case S: p->x.cache_num = Alloc_Single_Temp(); break; case I: case U: case P: case F: p->x.cache_num = Alloc_Double_Temp(); break; case D: p->x.cache_num = Alloc_Quad_Temp(); break; default: error("unsupported cache type\n"); } print("* allocated temp for %d (temp%d) (refs: %d)\n", p, p->x.cache_num, p->x.count2); --p->x.count2; } } } else { if (p->x.cache_flag && !p->x.loaded2_flag) { p->x.loaded2_flag = 1; switch(optype(p->op)) { case C: case S: print("\tst.w\tx.cache_num); break; case I: case U: case P: print("\tst.l\tx.cache_num); break; case F: print("\tst.f\tx.cache_num); break; case D: print("\tst.d\tx.cache_num); break; default: print("* Unsupported register cache size\n"); } } } } /************************************* * End code generation functions *************************************/ /************************************* * Start pass 1 (gen) functions *************************************/ int global_temp_num; /* ** gen1 - Initialize nodes recusively */ static int gen1(Node p, int lev, int n) { if (p && p->x.id == 0) { p->x.lev = lev; /* Hacks here */ p->x.count2 = p->count; p->x.cache_flag = 0; p->x.loaded1_flag = 0; p->x.loaded2_flag = 0; p->x.temp_num = -1; p->x.temp2_num = -1; p->x.visit_flag = 0; /* End hack */ p->x.id = ++n; n = gen1(p->kids[0], lev + 1, n); n = gen1(p->kids[1], lev + 1, n); *tail = p; tail = &p->x.next; } return n; } /* ** gen2 ** ** Allocate temporaries for nodes */ static void gen2(Node p, int spaces) { int i; if (!p) return; print("* "); for (i=0; iop), p->x.count2); if (p->syms[0] && p->syms[0]->x.name) print(" (%s)", p->syms[0]->x.name); print("\n"); if (!p->x.visit_flag) { p->x.visit_flag = 1; if ((p->count > 1) || (!p->x.lev && p->count)) { p->x.cache_flag = 1; print("* set cache bit for %d\n", p); } } spaces += 4; gen2(p->kids[0], spaces); gen2(p->kids[1], spaces); } /* ** gen - generate code for the dags on list p */ Node gen(Node p) { int n; Node nodelist; print("* gen() called\n"); global_temp_num = 0; tail = &nodelist; for (n = 0; p; p = p->link) { switch (generic(p->op)) { /* check for valid nodelist */ case CALL: break; case ARG: case ASGN: case JUMP: case LABEL: case RET: case EQ: case GE: case GT: case LE: case LT: case NE: assert(p->count == 0); break; case INDIR: assert(p->count > 0); break; default: assert(0); } n = gen1(p, 0, n); gen2(p, 0); Emit_Nodes(p); Debug_Emit_Nodes(p, 0); } *tail = 0; return nodelist; } /************************************* * End pass 1 (gen) functions *************************************/ /************************************* * Start pass 2 (emit) functions *************************************/ /* ** Debug_Emit_Nodes() subroutine */ static void Priv_Debug_Emit_Nodes_Sub(Node p, int spaces) { if (!p) return; print("%s(", opname(p->op)); if ((generic(p->op) != ASGN) && p->syms[0] && p->syms[0]->x.name) print("%s)", p->syms[0]->x.name); else { Priv_Debug_Emit_Nodes_Sub(p->kids[0], 1); if (p->kids[1]) { print(","); Priv_Debug_Emit_Nodes_Sub(p->kids[1], 1); } print(")"); } } /* ** Debug_Emit_Nodes() */ static void Debug_Emit_Nodes(Node p, int spaces) { #if 1 print("* "); Priv_Debug_Emit_Nodes_Sub(p, spaces); print("\n"); #else bbb int i; print("* "); for (i=0; icount && p->x.loaded2_flag) print("temp%d", p->x.cache_num); else print("%s", opname(p->op)); if (p->syms[0] && p->syms[0]->x.name) print(" (sym: %s)", p->syms[0]->x.name); print(" (refs: %d)", p->count); print(" (addr: %d)", p); if (p->x.cache_flag) { p->count--; if (!p->count && (p->x.temp_num != -1)) print(" (temp%d freed)", p->x.cache_num); } print("\n"); spaces += 4; for (i=0; (ikids[i]; i++) Debug_Emit_Nodes(p->kids[i], spaces); #endif } /* ** emit - emit the dags on list p */ void emit(p) Node p; { Node current; print("* Emit() here\n"); for (current=p; current; current=current->x.next) if (!current->x.lev) { Debug_Emit_Nodes(current, 0); Emit_Nodes(current); } } /************************************* * End pass 2 (emit) functions *************************************/ /************************************* * Start miscellaneous functions *************************************/ /* ** function prologue */ void func_prologue(int size) { print("\tlink\t#%d\n", size); } /* ** function epilogue */ void func_epilogue(int size) { print("\tunlk\t#%d\n", size); print("\tret\n"); } /* ** blockbeg - begin a compound statement */ void blockbeg(Env *e) { print("* blockbeg()\n"); memcpy(e, temps, sizeof(temps)); } /* ** blockend - end a compound statement */ void blockend(Env *e) { print("* blockend()\n"); memcpy(temps, e, sizeof(temps)); } /* ** local ** ** locals are initialized here */ void local(p) Symbol p; { print("* local(%s)\n", p->name); /* frame_offset = roundup(frame_offset, p->type->align); */ p->x.name = stringf("_%s", p->name); p->x.offset = frame_offset; print("%s\tequ\t%d\n", p->x.name, p->x.offset); frame_offset += p->type->size; } /* ** Switch to specified segment */ void segment(int num) { print("* segment()\n"); switch(num) { case CODE: if (inside_segment) print("\tend\n"); current_segment = CODE; inside_segment = 1; break; case BSS: case DATA: case LIT: case SYM: if (current_segment == DATA) return; if (inside_segment) print("\tend\n"); print("%s%d\tdata\n", filename, data_segment_num++); current_segment = DATA; inside_segment = 1; break; } } /* ** End of program */ void progend(void) { segment(CODE); } /************************************* * End miscellaneous functions *************************************/ /************************************* * Start main function *************************************/ /* ** Debug code nodes */ void Debug_Code(void) { Code cp; for (cp = &codehead; cp != 0; cp=cp->next) { switch(cp->kind) { case Address: print("* Address\n"); break; case Asm: print("* Asm\n"); break; case Blockbeg: print("* Blockbeg\n"); break; case Blockend: print("* Blockend\n"); break; case Label: print("* Label\n"); break; case Local: print("* Local\n"); break; case Defpoint: print("* Defpoint\n"); break; case Jump: print("* Jump\n"); break; case Gen: print("* Gen\n"); Debug_Emit_Nodes(cp->u.node, 0); break; case Start: print("* Start\n"); break; case Switch: print("* Switch\n"); break; default: print("* (Unknown - default)\n"); break; } } } /* ** function - generate code for a function */ void function(Symbol f, Symbol caller[], Symbol callee[], int ncalls) { int i; pass1_flag = 1; print("%s\tstart\n", f->x.name); sym("function", f, ncalls ? 0 : "\n"); if (ncalls) print(" ncalls=%d\n", ncalls); /* Pass 1 */ Clear_Temps(); print("************************** PASS 1 **************************\n"); deep_stack_flag = 0; temps_used = 0; frame_offset = 1; print("scratch\tequ\t%d\n", frame_offset); frame_offset += 4; print("fp_reg\tequ\t%d\n", frame_offset); frame_offset += 8; gencode(caller, callee); print("* temps_used: %d\n", temps_used); for (i=0; itype->align); */ caller[i]->x.name = stringf("_%s", caller[i]->name); callee[i]->x.name = stringf("_%s", callee[i]->name); caller[i]->x.offset = callee[i]->x.offset = frame_offset; /* sym("callee's parameter", callee[i], "\n"); */ frame_offset += caller[i]->type->size; print("%s\tequ\t%d\n", callee[i]->x.name, callee[i]->x.offset); } func_prologue(local_stack_frame); /* Pass 2 */ print("************************** PASS 2 **************************\n"); pass1_flag = 0; argument_space = 0; Debug_Code(); emitcode(); func_epilogue(local_stack_frame); print("%s\tend\n", f->x.name); } /************************************* * End main function *************************************/