2199ed1996-04-13Fredrik Hübinette (Hubbe) #include "global.h" #include "types.h" #include "language.h" #include "stralloc.h" #include "dynamic_buffer.h" #include "program.h" #include "las.h" #include "docode.h" #include "main.h" #include "error.h" #include "lex.h" struct p_instr_s { short opcode; short line; struct lpc_string *file; INT32 arg; }; typedef struct p_instr_s p_instr; dynamic_buffer instrbuf; static int hasarg(int opcode) { switch(opcode) { case F_NUMBER: case F_NEG_NUMBER: case F_CALL_LFUN: case F_SSCANF: case F_POP_N_ELEMS: case F_ASSIGN_GLOBAL: case F_ASSIGN_GLOBAL_AND_POP: case F_ASSIGN_LOCAL: case F_ASSIGN_LOCAL_AND_POP: case F_GLOBAL_LVALUE: case F_LOCAL_LVALUE: case F_CLEAR_LOCAL: case F_LOCAL: case F_GLOBAL: case F_INC_LOCAL: case F_DEC_LOCAL: case F_POST_INC_LOCAL: case F_POST_DEC_LOCAL: case F_INC_LOCAL_AND_POP: case F_DEC_LOCAL_AND_POP: case F_LFUN: case F_STRING: case F_CONSTANT: case F_SWITCH: case F_APPLY: case F_CATCH: case F_BRANCH: case F_BRANCH_WHEN_ZERO: case F_BRANCH_WHEN_NON_ZERO: case F_BRANCH_WHEN_EQ: case F_BRANCH_WHEN_NE: case F_BRANCH_WHEN_LT: case F_BRANCH_WHEN_LE: case F_BRANCH_WHEN_GT: case F_BRANCH_WHEN_GE: case F_FOREACH: case F_INC_LOOP: case F_DEC_LOOP: case F_INC_NEQ_LOOP: case F_DEC_NEQ_LOOP: case F_LAND: case F_LOR: case F_ALIGN: case F_POINTER: case F_LABEL: return 1; default: return 0; } } void init_bytecode() { low_init_buf(&instrbuf); } void exit_bytecode() { INT32 e,length; p_instr *c; c=(p_instr *)instrbuf.s.str; length=instrbuf.s.len / sizeof(p_instr); for(e=0;e<length;e++) free_string(c->file); toss_buffer(&instrbuf); } int insert_opcode(unsigned int f, INT32 b, INT32 current_line, struct lpc_string *current_file) { p_instr *p; #ifdef DEBUG if(!hasarg(f) && b) fatal("hasarg() is wrong!\n"); #endif p=(p_instr *)low_make_buf_space(sizeof(p_instr), &instrbuf); #ifdef DEBUG if(!instrbuf.s.len) fatal("Low make buf space failed!!!!!!\n"); #endif p->opcode=f; p->line=current_line; copy_shared_string(p->file, current_file); p->arg=b; return p - (p_instr *)instrbuf.s.str; } int insert_opcode2(int f,int current_line, struct lpc_string *current_file) { #ifdef DEBUG if(hasarg(f)) fatal("hasarg() is wrong!\n"); #endif return insert_opcode(f,0,current_line, current_file); } void update_arg(int instr,INT32 arg) { p_instr *p; #ifdef DEBUG if(instr > instrbuf.s.len / sizeof(p_instr) || instr < 0) fatal("update_arg outside known space.\n"); #endif p=(p_instr *)instrbuf.s.str; p[instr].arg=arg; } /**** Bytecode Generator *****/ void ins_f_byte(unsigned int b) { b-=F_OFFSET; #ifdef OPCPROF if(store_linenumbers) add_compiled(b); #endif if(b>255) { switch(b >> 8) { case 1: ins_f_byte(F_ADD_256); break; case 2: ins_f_byte(F_ADD_512); break; case 3: ins_f_byte(F_ADD_768); break; case 4: ins_f_byte(F_ADD_1024); break; default: ins_f_byte(F_ADD_256X); ins_byte(b/256,A_PROGRAM); } b&=255; } ins_byte((unsigned char)b,A_PROGRAM); } static void ins_f_byte_with_arg(unsigned int a,unsigned INT32 b) { switch(b >> 8) { case 0 : break; case 1 : ins_f_byte(F_PREFIX_256); break; case 2 : ins_f_byte(F_PREFIX_512); break; case 3 : ins_f_byte(F_PREFIX_768); break; case 4 : ins_f_byte(F_PREFIX_1024); break; default: if( b < 256*256) { ins_f_byte(F_PREFIX_CHARX256); ins_byte(b>>8, A_PROGRAM); }else if(b < 256*256*256) { ins_f_byte(F_PREFIX_WORDX256); ins_byte(b >> 16, A_PROGRAM); ins_byte(b >> 8, A_PROGRAM); }else{ ins_f_byte(F_PREFIX_24BITX256); ins_byte(b >> 24, A_PROGRAM); ins_byte(b >> 16, A_PROGRAM); ins_byte(b >> 8, A_PROGRAM); } } ins_f_byte(a); ins_byte(b, A_PROGRAM); } void assemble() { INT32 e,d,length,max_label,tmp; INT32 *labels, *jumps, *point; p_instr *c; c=(p_instr *)instrbuf.s.str; length=instrbuf.s.len / sizeof(p_instr); max_label=0; for(e=0;e<length;e++,c++) if(c->opcode == F_LABEL) if(c->arg > max_label) max_label = c->arg; labels=(INT32 *)xalloc(sizeof(INT32) * (max_label+1)); jumps=(INT32 *)xalloc(sizeof(INT32) * (max_label+1)); point=(INT32 *)xalloc(sizeof(INT32) * (max_label+1)); for(e=0;e<=max_label;e++) point[e]=labels[e]=jumps[e]=-1; c=(p_instr *)instrbuf.s.str; for(e=0;e<length;e++) { #ifdef DEBUG if(a_flag > 2 && store_linenumbers) { if(hasarg(c->opcode)) fprintf(stderr,"===%3d %4x %s(%d)\n",c->line,PC,get_token_name(c->opcode),c->arg); else fprintf(stderr,"===%3d %4x %s\n",c->line,PC,get_token_name(c->opcode)); } #endif if(store_linenumbers) store_linenumber(c->line, c->file); switch(c->opcode) { case F_ALIGN: while(PC % c->arg) ins_byte(0, A_PROGRAM); break; case F_LABEL: #ifdef DEBUG if(c->arg > max_label || c->arg < 0) fatal("max_label calculation failed!\n"); if(labels[c->arg] != -1) fatal("Duplicate label!\n"); #endif labels[c->arg]=PC; for(d=1;e+d<length;d++) { switch(c[d].opcode) { case F_LABEL: continue; case F_BRANCH: point[c->arg]=c[d].arg; } break; } break; case F_BRANCH_WHEN_EQ: case F_BRANCH_WHEN_NE: case F_BRANCH_WHEN_LT: case F_BRANCH_WHEN_LE: case F_BRANCH_WHEN_GT: case F_BRANCH_WHEN_GE: case F_BRANCH_WHEN_ZERO: case F_BRANCH_WHEN_NON_ZERO: case F_BRANCH: case F_INC_LOOP: case F_DEC_LOOP: case F_INC_NEQ_LOOP: case F_DEC_NEQ_LOOP: case F_LAND: case F_LOR: case F_CATCH: case F_FOREACH: ins_f_byte(c->opcode); case F_POINTER: #ifdef DEBUG if(c->arg > max_label || c->arg < 0) fatal("Jump to unknown label?\n"); #endif tmp=PC; ins_int(jumps[c->arg],A_PROGRAM); jumps[c->arg]=tmp; break; case F_APPLY: ins_f_byte(c->arg + F_MAX_OPCODE); break; default: if(hasarg(c->opcode)) ins_f_byte_with_arg(c->opcode, c->arg); else ins_f_byte(c->opcode); break; } c++; } for(e=0;e<=max_label;e++) { int tmp2; tmp2=e; while(point[tmp2]!=-1) tmp2=point[tmp2]; tmp2=labels[tmp2]; while(jumps[e]!=-1) { #ifdef DEBUG if(labels[e]==-1) fatal("Hyperspace error: unknown jump point.\n"); #endif tmp=read_int(jumps[e]); upd_int(jumps[e], tmp2 - jumps[e]); jumps[e]=tmp; } } free((char *)labels); free((char *)jumps); free((char *)point); exit_bytecode(); } /**** Peephole optimizer ****/ static int fifo_len, eye,len; static p_instr *instrs; #ifdef DEBUG static void debug() { p_instr *p; if(fifo_len > instrbuf.s.len / sizeof(p_instr)) fatal("Fifo too long.\n"); if(eye < 0) fatal("Popped beyond start of code.\n"); if(instrbuf.s.len) { p=(p_instr *)low_make_buf_space(0, &instrbuf); if(!p[-1].file) fatal("No file name on last instruction!\n"); } } #else #define debug() #endif static p_instr *instr(int offset) { p_instr *p; debug(); if(offset >= 0) { if(offset < fifo_len) { p=(p_instr *)low_make_buf_space(0, &instrbuf); p-=fifo_len; p+=offset; return p; }else{ offset-=fifo_len; offset+=eye; if(offset >= len) return 0; return instrs+offset; } }else{ fatal("Can't handle negative offsets in peephole optimizer!\n"); } } static int opcode(int offset) { p_instr *a; a=instr(offset); if(a) return a->opcode; return -1; } static int argument(int offset) { p_instr *a; a=instr(offset); if(a) return a->arg; return -1; } static void advance() { if(fifo_len) { fifo_len--; }else{ p_instr *p; if(p=instr(0)) insert_opcode(p->opcode, p->arg, p->line, p->file); eye++; } debug(); } static void pop_n_opcodes(int n) { while(n>0) { if(fifo_len) { p_instr *p; #ifdef DEBUG if(instrbuf.s.len <= 0) fatal("Popping out of opcodes.\n"); #endif low_make_buf_space(-sizeof(p_instr), &instrbuf); p=(p_instr *)low_make_buf_space(0, &instrbuf); free_string(p->file); fifo_len--; }else{ eye++; } n--; } } #define insert(X,Y) insert_opcode((X),(Y),current_line, current_file),dofix() #define insert2(X) insert_opcode2((X),current_line, current_file),dofix() static void dofix() { p_instr *p,tmp; int e; if(fifo_len) { p=(p_instr *)low_make_buf_space(0, &instrbuf); tmp=p[-1]; for(e=0;e<fifo_len;e++) p[-1-e]=p[-2-e]; p[-1-e]=tmp; } } void asm_opt() { #ifdef DEBUG if(a_flag > 3) { p_instr *c; INT32 e,length; c=(p_instr *)instrbuf.s.str; length=instrbuf.s.len / sizeof(p_instr); fprintf(stderr,"Optimization begins: \n"); for(e=0;e<length;e++,c++) { if(hasarg(c->opcode)) fprintf(stderr,"---%3d: %s(%d)\n",c->line,get_token_name(c->opcode),c->arg); else fprintf(stderr,"---%3d: %s\n",c->line,get_token_name(c->opcode)); } } #endif #include "peep_engine.c" #ifdef DEBUG if(a_flag > 4) { p_instr *c; INT32 e,length; c=(p_instr *)instrbuf.s.str; length=instrbuf.s.len / sizeof(p_instr); fprintf(stderr,"Optimization begins: \n"); for(e=0;e<length;e++,c++) { if(hasarg(c->opcode)) fprintf(stderr,">>>%3d: %s(%d)\n",c->line,get_token_name(c->opcode),c->arg); else fprintf(stderr,">>>%3d: %s\n",c->line,get_token_name(c->opcode)); } } #endif }