diff --git a/src/peep.c b/src/peep.c new file mode 100644 index 0000000000000000000000000000000000000000..8795c4336fd936ff7cddd22066c29fbc29a5d27b --- /dev/null +++ b/src/peep.c @@ -0,0 +1,513 @@ +#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 +} + diff --git a/src/peep.h b/src/peep.h new file mode 100644 index 0000000000000000000000000000000000000000..48268f65d21c0cb9651740491b6103c750eadede --- /dev/null +++ b/src/peep.h @@ -0,0 +1,22 @@ +#ifndef PEEP_H +#define PEEP_H + +#include "dynamic_buffer.h" +extern dynamic_buffer instrbuf; + +/* Prototypes begin here */ +struct p_instr_s; +void init_bytecode(); +void exit_bytecode(); +int insert_opcode(unsigned int f, + INT32 b, + INT32 current_line, + struct lpc_string *current_file); +int insert_opcode2(int f,int current_line, struct lpc_string *current_file); +void update_arg(int instr,INT32 arg); +void ins_f_byte(unsigned int b); +void assemble(); +void asm_opt(); +/* Prototypes end here */ + +#endif diff --git a/src/peep.in b/src/peep.in new file mode 100644 index 0000000000000000000000000000000000000000..53890f8872c0272a3a2ed374fa603f62ba327091 --- /dev/null +++ b/src/peep.in @@ -0,0 +1,86 @@ +POP_N_ELEMS (0) : +POP_N_ELEMS POP_VALUE : POP_N_ELEMS ($1a + 1) +POP_VALUE POP_VALUE : POP_N_ELEMS (2) +POP_VALUE POP_N_ELEMS : POP_N_ELEMS ($2a + 1) +POP_N_ELEMS POP_N_ELEMS : POP_N_ELEMS ($1a + $2a) +POP_N_ELEMS(1) : POP_VALUE + +ASSIGN_GLOBAL POP_VALUE : ASSIGN_GLOBAL_AND_POP($1a) +ASSIGN_LOCAL POP_VALUE : ASSIGN_LOCAL_AND_POP($1a) +NUMBER(0) : CONST0 +NUMBER(1) : CONST1 +NUMBER(-1) : CONST_1 +NUMBER (0x7fffffff) : BIGNUM +CONST0 NEGATE : CONST0 +CONST1 NEGATE : CONST_1 +CONST_1 NEGATE : CONST1 +NUMBER NEGATE : NEG_NUMBER($1a) +NUMBER [$1a < 0] : NEG_NUMBER (-$1a) +NEG_NUMBER NEGATE : NUMBER ($1a) +NEGATE CONST_1 ADD : COMPL +NEGATE CONST1 SUBTRACT : COMPL +CONST0 ASSIGN_LOCAL_AND_POP : CLEAR_LOCAL($2a) + +CONST_1 MULTIPLY : NEGATE +#CONST0 MULTIPLY : POP_VALUE CONST0 +CONST1 MULTIPLY : +#NUMBER MULTIPLY [count_bits($1a)==1]: NUMBER(my_log2($1a)) LSH + +CONST_1 DIVIDE : NEGATE +CONST1 DIVIDE : +#NUMBER DIVIDE [count_bits($1a)==1]: NUMBER(my_log2($1a)) RSH + +CONST0 SUBTRACT: +CONST0 XOR: +CONST_1 XOR: COMPL +EQ CONST0: NOT +CONST0 RETURN: RETURN_0 +INC POP_VALUE: INC_AND_POP +POST_INC POP_VALUE: INC_AND_POP +DEC POP_VALUE: DEC_AND_POP +POST_DEC POP_VALUE: DEC_AND_POP +NOT BRANCH_WHEN_NON_ZERO: BRANCH_WHEN_ZERO($2a) +NOT BRANCH_WHEN_ZERO: BRANCH_WHEN_NON_ZERO($2a) + +BRANCH !LABEL : BRANCH($1a) +RETURN !LABEL : RETURN +RETURN_0 !LABEL : RETURN_0 +BRANCH LABEL ($1a) : + +LOCAL_LVALUE INC : INC_LOCAL ($1a) +LOCAL_LVALUE POST_INC : POST_INC_LOCAL ($1a) +LOCAL_LVALUE INC_AND_POP : INC_LOCAL_AND_POP ($1a) +INC_LOCAL POP_VALUE : INC_LOCAL_AND_POP ($1a) +POST_INC_LOCAL POP_VALUE : INC_LOCAL_AND_POP ($1a) + +LOCAL_LVALUE DEC : DEC_LOCAL ($1a) +LOCAL_LVALUE POST_DEC : POST_DEC_LOCAL ($1a) +LOCAL_LVALUE DEC_AND_POP : DEC_LOCAL_AND_POP ($1a) +DEC_LOCAL POP_VALUE : DEC_LOCAL_AND_POP ($1a) +POST_DEC_LOCAL POP_VALUE : DEC_LOCAL_AND_POP ($1a) + +CONST1 BRANCH_WHEN_ZERO: +CONST0 BRANCH_WHEN_ZERO: BRANCH($2a) +CONST1 BRANCH_WHEN_NON_ZERO: BRANCH($2a) +CONST0 BRANCH_WHEN_NON_ZERO: + +EQ BRANCH_WHEN_NON_ZERO: BRANCH_WHEN_EQ ($2a) +NE BRANCH_WHEN_NON_ZERO: BRANCH_WHEN_NE ($2a) +LT BRANCH_WHEN_NON_ZERO: BRANCH_WHEN_LT ($2a) +GT BRANCH_WHEN_NON_ZERO: BRANCH_WHEN_GT ($2a) +LE BRANCH_WHEN_NON_ZERO: BRANCH_WHEN_LE ($2a) +GE BRANCH_WHEN_NON_ZERO: BRANCH_WHEN_GE ($2a) + +EQ BRANCH_WHEN_ZERO: BRANCH_WHEN_NE ($2a) +NE BRANCH_WHEN_ZERO: BRANCH_WHEN_EQ ($2a) +LT BRANCH_WHEN_ZERO: BRANCH_WHEN_GE ($2a) +GT BRANCH_WHEN_ZERO: BRANCH_WHEN_LE ($2a) +LE BRANCH_WHEN_ZERO: BRANCH_WHEN_GT ($2a) +GE BRANCH_WHEN_ZERO: BRANCH_WHEN_LT ($2a) + +EQ NOT: NE +NE NOT: EQ +LT NOT: GE +GT NOT: LE +LE NOT: GT +GE NOT: LT