#include "global.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" |
#include "pike_memory.h" |
#include "peep.h" |
#include "dmalloc.h" |
#include "stuff.h" |
#include "bignum.h" |
|
RCSID("$Id: peep.c,v 1.29 2006/09/05 12:14:34 grubba Exp $"); |
|
struct p_instr_s |
{ |
short opcode; |
short line; |
struct pike_string *file; |
INT32 arg; |
}; |
|
typedef struct p_instr_s p_instr; |
static void asm_opt(void); |
|
dynamic_buffer instrbuf; |
|
static int hasarg(int opcode) |
{ |
return instrs[opcode-F_OFFSET].flags & I_HASARG; |
} |
|
void init_bytecode(void) |
{ |
low_reinit_buf(&instrbuf); |
} |
|
void exit_bytecode(void) |
{ |
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[e].file); |
|
toss_buffer(&instrbuf); |
} |
|
int insert_opcode(unsigned int f, |
INT32 b, |
INT32 current_line, |
struct pike_string *current_file) |
{ |
p_instr *p; |
|
#ifdef PIKE_DEBUG |
if(!hasarg(f) && b) |
fatal("hasarg(%d) is wrong!\n",f); |
#endif |
|
p=(p_instr *)low_make_buf_space(sizeof(p_instr), &instrbuf); |
|
|
#ifdef PIKE_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 pike_string *current_file) |
{ |
#ifdef PIKE_DEBUG |
if(hasarg(f)) |
fatal("hasarg(%d) is wrong!\n",f); |
#endif |
return insert_opcode(f,0,current_line, current_file); |
} |
|
|
void update_arg(int instr,INT32 arg) |
{ |
p_instr *p; |
#ifdef PIKE_DEBUG |
if(instr > (long)instrbuf.s.len / (long)sizeof(p_instr) || instr < 0) |
fatal("update_arg outside known space.\n"); |
#endif |
p=(p_instr *)instrbuf.s.str; |
p[instr].arg=arg; |
} |
|
|
|
|
void ins_f_byte(unsigned int b) |
{ |
#ifdef PIKE_DEBUG |
if(store_linenumbers && b<F_MAX_OPCODE) |
ADD_COMPILED(b); |
#endif /* PIKE_DEBUG */ |
|
b-=F_OFFSET; |
#ifdef PIKE_DEBUG |
if(b>255) |
error("Instruction too big %d\n",b); |
#endif |
add_to_program((unsigned char)b); |
} |
|
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); |
add_to_program(b>>8); |
}else if(b < 256*256*256) { |
ins_f_byte(F_PREFIX_WORDX256); |
add_to_program(b>>16); |
add_to_program(b>>8); |
}else{ |
ins_f_byte(F_PREFIX_24BITX256); |
add_to_program(b>>24); |
add_to_program(b>>16); |
add_to_program(b>>8); |
} |
} |
ins_f_byte(a); |
add_to_program(b); |
} |
|
void assemble(void) |
{ |
INT32 e,d,length,max_label,tmp; |
INT32 *labels, *jumps, *uses; |
p_instr *c; |
|
c=(p_instr *)instrbuf.s.str; |
length=instrbuf.s.len / sizeof(p_instr); |
|
max_label=-1; |
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+2)); |
jumps=(INT32 *)xalloc(sizeof(INT32) * (max_label+2)); |
uses=(INT32 *)xalloc(sizeof(INT32) * (max_label+2)); |
|
for(e=0;e<=max_label;e++) |
{ |
labels[e]=jumps[e]=-1; |
uses[e]=0; |
} |
|
c=(p_instr *)instrbuf.s.str; |
for(e=0;e<length;e++) |
if(c[e].opcode == F_LABEL) |
labels[c[e].arg]=e; |
|
for(e=0;e<length;e++) |
{ |
if(instrs[c[e].opcode-F_OFFSET].flags & I_POINTER) |
{ |
while(1) |
{ |
int tmp,tmp2; |
tmp=labels[c[e].arg]; |
|
while(tmp<length && |
(c[tmp].opcode == F_LABEL || |
c[tmp].opcode == F_NOP)) tmp++; |
|
if(tmp>=length) break; |
|
if(c[tmp].opcode==F_BRANCH) |
{ |
c[e].arg=c[tmp].arg; |
continue; |
} |
|
#define TWOO(X,Y) (((X)<<8)+(Y)) |
|
switch(TWOO(c[e].opcode,c[tmp].opcode)) |
{ |
case TWOO(F_LOR,F_BRANCH_WHEN_NON_ZERO): |
c[e].opcode=F_BRANCH_WHEN_NON_ZERO; |
case TWOO(F_LOR,F_LOR): |
c[e].arg=c[tmp].arg; |
continue; |
|
case TWOO(F_LAND,F_BRANCH_WHEN_ZERO): |
c[e].opcode=F_BRANCH_WHEN_ZERO; |
case TWOO(F_LAND,F_LAND): |
c[e].arg=c[tmp].arg; |
continue; |
} |
break; |
} |
uses[c[e].arg]++; |
} |
} |
|
for(e=0;e<=max_label;e++) |
if(!uses[e] && labels[e]>=0) |
c[labels[e]].opcode=F_NOP; |
|
asm_opt(); |
|
c=(p_instr *)instrbuf.s.str; |
length=instrbuf.s.len / sizeof(p_instr); |
|
for(e=0;e<=max_label;e++) labels[e]=jumps[e]=-1; |
|
c=(p_instr *)instrbuf.s.str; |
for(e=0;e<length;e++) |
{ |
#ifdef PIKE_DEBUG |
if((a_flag > 2 && store_linenumbers) || a_flag > 3) |
{ |
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_NOP: break; |
case F_ALIGN: |
while(PC % c->arg) add_to_program(0); |
break; |
|
case F_BYTE: |
add_to_program(c->arg); |
break; |
|
case F_DATA: |
ins_int(c->arg, (void(*)(char))add_to_program); |
break; |
|
case F_LABEL: |
#ifdef PIKE_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; |
break; |
|
default: |
switch(instrs[c->opcode - F_OFFSET].flags) |
{ |
case I_ISJUMP: |
ins_f_byte(c->opcode); |
case I_ISPOINTER: |
#ifdef PIKE_DEBUG |
if(c->arg > max_label || c->arg < 0) fatal("Jump to unknown label?\n"); |
#endif |
tmp=PC; |
ins_int(jumps[c->arg], (void(*)(char))add_to_program); |
jumps[c->arg]=tmp; |
break; |
|
case I_HASARG: |
ins_f_byte_with_arg(c->opcode, c->arg); |
break; |
|
case 0: |
ins_f_byte(c->opcode); |
break; |
|
#ifdef PIKE_DEBUG |
default: |
fatal("Unknown instruction type.\n"); |
#endif |
} |
} |
|
c++; |
} |
|
for(e=0;e<=max_label;e++) |
{ |
int tmp2=labels[e]; |
|
while(jumps[e]!=-1) |
{ |
#ifdef PIKE_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 *)uses); |
|
|
exit_bytecode(); |
} |
|
|
|
int remove_clear_locals=0x7fffffff; |
static int fifo_len, eye,len; |
static p_instr *instructions; |
|
int insopt(int f, INT32 b, int cl, struct pike_string *cf) |
{ |
p_instr *p; |
|
#ifdef PIKE_DEBUG |
if(!hasarg(f) && b) |
fatal("hasarg(%d) is wrong!\n",f); |
#endif |
|
p=(p_instr *)low_make_buf_space(sizeof(p_instr), &instrbuf); |
|
if(fifo_len) |
{ |
MEMMOVE(p-fifo_len+1,p-fifo_len,fifo_len*sizeof(p_instr)); |
p-=fifo_len; |
} |
|
#ifdef PIKE_DEBUG |
if(!instrbuf.s.len) |
fatal("Low make buf space failed!!!!!!\n"); |
#endif |
|
p->opcode=f; |
p->line=cl; |
copy_shared_string(p->file, lex.current_file); |
p->arg=b; |
|
return p - (p_instr *)instrbuf.s.str; |
} |
|
int insopt2(int f, int cl, struct pike_string *cf) |
{ |
#ifdef PIKE_DEBUG |
if(hasarg(f)) |
fatal("hasarg(%d) is wrong!\n",f); |
#endif |
return insopt(f,0,cl, cf); |
} |
|
static void debug(void) |
{ |
if(fifo_len > (long)instrbuf.s.len / (long)sizeof(p_instr)) |
fifo_len=(long)instrbuf.s.len / (long)sizeof(p_instr); |
#ifdef PIKE_DEBUG |
if(eye < 0) |
fatal("Popped beyond start of code.\n"); |
|
if(instrbuf.s.len) |
{ |
p_instr *p; |
p=(p_instr *)low_make_buf_space(0, &instrbuf); |
if(!p[-1].file) |
fatal("No file name on last instruction!\n"); |
} |
#endif |
} |
|
|
static INLINE p_instr *instr(int offset) |
{ |
p_instr *p; |
|
debug(); |
|
if(offset < fifo_len) |
{ |
p=(p_instr *)low_make_buf_space(0, &instrbuf); |
p-=fifo_len; |
p+=offset; |
if(((char *)p)<instrbuf.s.str) return 0; |
return p; |
}else{ |
offset-=fifo_len; |
offset+=eye; |
if(offset >= len) return 0; |
return instructions+offset; |
} |
} |
|
static INLINE int opcode(int offset) |
{ |
p_instr *a; |
a=instr(offset); |
if(a) return a->opcode; |
return -1; |
} |
|
static INLINE int argument(int offset) |
{ |
p_instr *a; |
a=instr(offset); |
if(a) return a->arg; |
return -1; |
} |
|
static void advance(void) |
{ |
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) |
{ |
int e,d; |
if(fifo_len) |
{ |
p_instr *p; |
|
d=n; |
if(d>fifo_len) d=fifo_len; |
#ifdef PIKE_DEBUG |
if((long)d > (long)instrbuf.s.len / (long)sizeof(p_instr)) |
fatal("Popping out of instructions.\n"); |
#endif |
|
p=(p_instr *)low_make_buf_space(0, &instrbuf); |
p-=fifo_len; |
for(e=0;e<d;e++) free_string(p[e].file); |
fifo_len-=d; |
if(fifo_len) MEMMOVE(p,p+d,fifo_len*sizeof(p_instr)); |
n-=d; |
low_make_buf_space(-((INT32)sizeof(p_instr))*d, &instrbuf); |
} |
eye+=n; |
} |
|
static void do_optimization(int topop, ...) |
{ |
va_list arglist; |
struct pike_string *cf; |
int q=-1; |
INT32 cl=instr(0)->line; |
copy_shared_string(cf,instr(0)->file); |
pop_n_opcodes(topop); |
va_start(arglist, topop); |
|
while(1) |
{ |
q++; |
switch(va_arg(arglist, int)) |
{ |
case 0: |
break; |
case 1: |
{ |
int i=va_arg(arglist, int); |
insopt2(i,cl,cf); |
continue; |
} |
case 2: |
{ |
int i=va_arg(arglist, int); |
int j=va_arg(arglist, int); |
insopt(i,j,cl,cf); |
continue; |
} |
} |
break; |
} |
|
va_end(arglist); |
fifo_len+=q; |
free_string(cf); |
debug(); |
fifo_len+=q + 3; |
} |
|
|
static void asm_opt(void) |
{ |
#ifdef PIKE_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 |
|
#ifndef IN_TPIKE |
#include "peep_engine.c" |
#endif /* IN_TPIKE */ |
|
#ifdef PIKE_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 |
} |
|
|
|