void setline(int line, int fileno) { if ((sc_debug & (sSYMBOLIC | sCHKBOUNDS)) != 0) { stgwrite("line "); outval(line, FALSE); stgwrite(" "); outval(fileno, FALSE); stgwrite("\t; "); outval(code_idx, TRUE); code_idx += opcodes(1) + opargs(2); } /* if */ }
/* Convert "distance of addresses" to "number of cells" in between. * Or convert a number of packed characters to the number of cells (with * truncation). * The ALT register is be used as scratch. */ SC_FUNC void addr2cell(void) { stgwrite("\tconst.alt "); if (pc_cellsize==2) { outval(1,TRUE,TRUE); } else if (pc_cellsize==4) { outval(2,TRUE,TRUE); } else { assert(pc_cellsize==8); outval(3,TRUE,TRUE); } /* if */ stgwrite("\tshr\n"); code_idx+=opcodes(2)+opargs(1); }
SC_FUNC void setheap_pri(void) { if (!staging && pc_optimize>=sOPTIMIZE_FULL) { stgwrite("\theap.p "); outval(pc_cellsize,FALSE,TRUE); code_idx+=opcodes(3); /* the other 2 opcodes follow below */ } else { stgwrite("\theap "); /* ALT = HEA++ */ outval(pc_cellsize,TRUE,TRUE); code_idx+=opcodes(3)+opargs(1); /* the other 2 opcodes follow below */ } /* if */ stgwrite("\tstor.i\n"); /* store PRI (default value) at address ALT */ stgwrite("\txchg\n"); /* move ALT to PRI: PRI contains the address */ }
/* * Inclrement/decrement stack pointer. Note that this routine does * nothing if the delta is zero. */ SC_FUNC void modstk(int delta) { if (delta) { cell crit=((cell)1<<pc_cellsize*4); if (!staging && pc_optimize>=sOPTIMIZE_FULL && delta>=-crit && delta<crit) { stgwrite("\tstack.p "); outval(delta,FALSE,TRUE); code_idx+=opcodes(1); } else { stgwrite("\tstack "); outval(delta,TRUE,TRUE); code_idx+=opcodes(1)+opargs(1); } /* if */ } /* if */ }
SC_FUNC void setheap(cell value) { stgwrite("\tconst.pri "); /* load default value in PRI */ outval(value,TRUE,TRUE); code_idx+=opcodes(1)+opargs(1); setheap_pri(); }
SC_FUNC void setheap_save(cell value) { assert(value); stgwrite("\ttracker.push.c "); outval(value, TRUE); code_idx+=opcodes(1)+opargs(1); }
/* set the stack to a hard offset from the frame */ SC_FUNC void setstk(cell value) { stgwrite("\tstackadjust "); assert(value<=0); /* STK should always become <= FRM */ outval(value, TRUE); /* add (negative) offset */ code_idx+=opcodes(1)+opargs(1); }
SC_FUNC void oa_eq(cell size) { stgwrite("\tcmps "); outval(size,TRUE,TRUE); stgwrite("\tnot\n"); /* CMPS results in zero if both arrays match, change it to 1 */ code_idx+=opcodes(2)+opargs(1); }
/* writetrailer * Not much left of this once important function. * * Global references: pc_stksize (referred to only) * sc_dataalign (referred to only) * code_idx (altered) * glb_declared (altered) */ SC_FUNC void writetrailer(void) { assert(sc_dataalign % opcodes(1) == 0); /* alignment must be a multiple of * the opcode size */ assert(sc_dataalign!=0); /* pad code to align data segment */ if ((code_idx % sc_dataalign)!=0) { begcseg(); while ((code_idx % sc_dataalign)!=0) nooperation(); } /* if */ /* pad data segment to align the stack and the heap */ assert(litidx==0); /* literal queue should have been emptied */ assert(sc_dataalign % sizeof(cell) == 0); if (((glb_declared*sizeof(cell)) % sc_dataalign)!=0) { begdseg(); defstorage(); while (((glb_declared*sizeof(cell)) % sc_dataalign)!=0) { stgwrite("0 "); glb_declared++; } /* while */ } /* if */ stgwrite("\nSTKSIZE "); /* write stack size (align stack top) */ outval(pc_stksize - (pc_stksize % sc_dataalign),TRUE,TRUE); }
SC_FUNC void setline(int chkbounds) { if (sc_asmfile) { stgwrite("\t; line "); outval(fline,TRUE,TRUE); } /* if */ if ((sc_debug & sSYMBOLIC)!=0 || chkbounds && (sc_debug & sCHKBOUNDS)!=0) { /* generate a "break" (start statement) opcode rather than a "line" opcode * because earlier versions of Small/Pawn have an incompatible version of the * line opcode */ stgwrite("\tbreak\t; "); outval(code_idx,TRUE,TRUE); code_idx+=opcodes(1); } /* if */ }
/* Store a cell into a fixed address in memory */ SC_FUNC void storereg(cell address,regid reg) { assert(reg==sPRI); stgwrite("\tstor "); outval(address,TRUE,TRUE); code_idx+=opcodes(1)+opargs(1); }
/* Source must be in PRI, destination address in ALT. The "size" * parameter is in bytes, not cells. */ SC_FUNC void memcopy(cell size) { stgwrite("\tmovs "); outval(size,TRUE,TRUE); code_idx+=opcodes(1)+opargs(1); }
/* Align PRI (which should hold a character index) to an address. * The first character in a "pack" occupies the highest bits of * the cell. This is at the lower memory address on Big Endian * computers and on the higher address on Little Endian computers. * The ALIGN.pri/alt instructions must solve this machine dependence; * that is, on Big Endian computers, ALIGN.pri/alt shuold do nothing * and on Little Endian computers they should toggle the address. * * NOTE: For Source Pawn, this is fliped. It will do nothing on Little-Endian. */ SC_FUNC void charalign(void) { #if 0 /* TEMPORARILY DISABLED BECAUSE WE DON'T USE BIG ENDIAN */ stgwrite("\talign.pri "); outval(sCHARBITS/8,TRUE); code_idx+=opcodes(1)+opargs(1); #endif }
/* * Add a constant to the primary register. */ SC_FUNC void addconst(cell value) { if (value!=0) { stgwrite("\tadd.c "); outval(value,TRUE); code_idx+=opcodes(1)+opargs(1); } /* if */ }
SC_FUNC void oa_ne(cell size) { stgwrite("\tcmps "); outval(size,TRUE,TRUE); /* this leaves PRI == 0 when the arrays are equal */ stgwrite("\tnot\n"); /* PRI == 1 if equal, 0 if different */ stgwrite("\tnot\n"); /* PRI == 0 if equal, 1 = different */ code_idx+=opcodes(3)+opargs(1); }
SC_FUNC void setheap_pri(void) { stgwrite("\theap "); /* ALT = HEA++ */ outval(sizeof(cell), TRUE); stgwrite("\tstor.i\n"); /* store PRI (default value) at address ALT */ stgwrite("\tmove.pri\n"); /* move ALT to PRI: PRI contains the address */ code_idx+=opcodes(3)+opargs(1); }
/* * Inclrement/decrement stack pointer. Note that this routine does * nothing if the delta is zero. */ void modstk(int delta) { if (delta) { stgwrite("\tstack "); outval(delta, TRUE); code_idx+=opcodes(1)+opargs(1); } /* if */ }
SC_FUNC void modheap(int delta) { if (delta) { stgwrite("\theap "); outval(delta, TRUE); code_idx+=opcodes(1)+opargs(1); } /* if */ }
SC_FUNC void oa_ne(cell size) { stgwrite("\tcmps "); outval(size,TRUE,TRUE); stgwrite("\teq.c.pri 0\n"); stgwrite("\tnot\n"); code_idx+=opcodes(3)+opargs(2); }
SC_FUNC void ffbounds(cell size) { if ((sc_debug & sCHKBOUNDS)!=0) { stgwrite("\tbounds "); outval(size,TRUE,TRUE); code_idx+=opcodes(1)+opargs(1); } /* if */ }
/* increment symbol */ SC_FUNC void inc(value *lval) { symbol *sym; sym=lval->sym; if (lval->ident==iARRAYCELL) { /* indirect increment, address already in PRI */ stgwrite("\tinc.i\n"); code_idx+=opcodes(1); } else if (lval->ident==iARRAYCHAR) { /* indirect increment of single character, address already in PRI */ stgwrite("\tpush.alt\n"); stgwrite("\txchg\n"); /* ALT = address */ stgwrite("\tlodb.i "); /* read from ALT into PRI */ outval(sCHARBITS/8,TRUE,TRUE);/* read one or two bytes */ stgwrite("\tinc.pri\n"); stgwrite("\tstrb.i "); /* write PRI to ALT */ outval(sCHARBITS/8,TRUE,TRUE);/* write one or two bytes */ stgwrite("\txchg\n"); /* PRI = address (restored PRI) */ stgwrite("\tpop.alt\n"); code_idx+=opcodes(7)+opargs(2); } else if (lval->ident==iREFERENCE) { /* indirect increment, but address not yet in PRI */ assert(sym!=NULL); stgwrite("\tpush.pri\n"); assert(sym->vclass==sLOCAL); /* global references don't exist in Pawn */ stgwrite("\tload.s.pri "); outval(sym->addr,TRUE,TRUE); stgwrite("\tinc.i\n"); stgwrite("\tpop.pri\n"); code_idx+=opcodes(4)+opargs(1); } else { /* local or global variable */ assert(sym!=NULL); stgwrite("\tpush.pri\n"); if (sym->vclass==sLOCAL) stgwrite("\taddr.pri "); else stgwrite("\tconst.pri "); outval(sym->addr,TRUE,TRUE); stgwrite("\tinc.i\n"); stgwrite("\tpop.pri\n"); code_idx+=opcodes(4)+opargs(1); } /* if */ }
/* * Inclrement/decrement stack pointer. Note that this routine does * nothing if the delta is zero. */ SC_FUNC void modstk(int delta) { if (delta) { #if !defined AMX_NO_PACKED_OPC if (!staging && pc_optimize>sOPTIMIZE_NOMACRO && delta>=-(1<<sizeof(cell)*4) && delta<(1<<sizeof(cell)*4)) { stgwrite("\tstack.p "); outval(delta,FALSE,TRUE); code_idx+=opcodes(1); } else { #endif stgwrite("\tstack "); outval(delta,TRUE,TRUE); code_idx+=opcodes(1)+opargs(1); #if !defined AMX_NO_PACKED_OPC } /* if */ #endif } /* if */ }
SC_FUNC void ffcase(cell value,int label,int newtable,int icase) { if (newtable) { if (icase) stgwrite("\ticasetbl\n"); else stgwrite("\tcasetbl\n"); code_idx+=opcodes(1); } /* if */ if (icase) stgwrite("\ticase "); else stgwrite("\tcase "); outval(value,TRUE,FALSE); stgwrite(" "); outval(label,TRUE,TRUE); code_idx+=opcodes(0)+opargs(2); }
/* Switch statements * The "switch" statement generates a "case" table using the "CASE" opcode. * The case table contains a list of records, each record holds a comparison * value and a label to branch to on a match. The very first record is an * exception: it holds the size of the table (excluding the first record) and * the label to branch to when none of the values in the case table match. * The case table is sorted on the comparison value. This allows more advanced * abstract machines to sift the case table with a binary search. * The iswitch statement uses an icase table. The parameter of an iswitch is * still a (relative) code address. */ SC_FUNC void ffswitch(int label,int iswitch) { if (iswitch) stgwrite("\tiswitch "); else stgwrite("\tswitch "); outval(label,TRUE,TRUE); /* the label is the address of the case table */ code_idx+=opcodes(1)+opargs(1); }
static void addr_reg(int val, regid reg) { if (reg == sPRI) stgwrite("\taddr.pri "); else stgwrite("\taddr.alt "); outval(val, TRUE); code_idx += opcodes(1) + opargs(1); }
// Load the number of arguments into PRI. Frame layout: // base + 0*sizeof(cell) == previous "base" // base + 1*sizeof(cell) == function return address // base + 2*sizeof(cell) == number of arguments // base + 3*sizeof(cell) == first argument of the function static void load_argcount(regid reg) { if (reg == sPRI) stgwrite("\tload.s.pri "); else stgwrite("\tload.s.alt "); outval(2 * sizeof(cell), TRUE); code_idx += opcodes(1) + opargs(1); }
SC_FUNC void setheap_pri(void) { #if !defined AMX_NO_PACKED_OPC if (!staging && pc_optimize>sOPTIMIZE_NOMACRO) { stgwrite("\theap.p "); outval(sizeof(cell),FALSE,TRUE); code_idx+=opcodes(3); /* the other 2 opcodes follow below */ } else { #endif stgwrite("\theap "); /* ALT = HEA++ */ outval(sizeof(cell),TRUE,TRUE); code_idx+=opcodes(3)+opargs(1); /* the other 2 opcodes follow below */ #if !defined AMX_NO_PACKED_OPC } /* if */ #endif stgwrite("\tstor.i\n"); /* store PRI (default value) at address ALT */ stgwrite("\tmove.pri\n"); /* move ALT to PRI: PRI contains the address */ }
/* Store a cell into a fixed address in memory */ SC_FUNC void storereg(cell address,regid reg) { assert(reg==sPRI || reg==sALT); if (reg==sPRI) stgwrite("\tstor.pri "); else stgwrite("\tstor.alt "); outval(address,TRUE,TRUE); code_idx+=opcodes(1)+opargs(1); }
/* * Generate an array */ SC_FUNC void genarray(int dims, int _autozero) { if (_autozero) { stgwrite("\tgenarray.z "); } else { stgwrite("\tgenarray "); } outval(dims, TRUE); code_idx+=opcodes(1)+opargs(1); }
/* * Call specified function */ SC_FUNC void ffcall(symbol *sym,const char *label,int numargs) { char symname[2*sNAMEMAX+16]; assert(sym!=NULL); assert(sym->ident==iFUNCTN); if (sc_asmfile) funcdisplayname(symname,sym->name); if ((sym->usage & uNATIVE)!=0) { /* reserve a SYSREQ id if called for the first time */ assert(label==NULL); if (sc_status==statWRITE && (sym->usage & uREAD)==0 && sym->addr>=0) sym->addr=ntv_funcid++; stgwrite("\tsysreq.c "); outval(sym->addr,FALSE); if (sc_asmfile) { stgwrite("\t; "); stgwrite(symname); } /* if */ stgwrite("\n"); /* write on a separate line, to mark a sequence point for the peephole optimizer */ stgwrite("\tstack "); outval((numargs+1)*sizeof(cell), TRUE); code_idx+=opcodes(2)+opargs(2); } else { /* normal function */ stgwrite("\tcall "); if (label!=NULL) { stgwrite("l."); stgwrite(label); } else { stgwrite("."); stgwrite(sym->name); } /* if */ if (sc_asmfile && (label!=NULL || !isalpha(sym->name[0]) && sym->name[0]!='_' && sym->name[0]!=sc_ctrlchar)) { stgwrite("\t; "); stgwrite(symname); } /* if */ stgwrite("\n"); code_idx+=opcodes(1)+opargs(1); } /* if */ }