Skip to content

Commit

Permalink
Eliminate the native counter hack.
Browse files Browse the repository at this point in the history
For some reason, natives had a weird relationship with the assembler.
The code generator assigned an address based on a global counter, and
then the assembler was responsible for building the table in the same
order. (Similar nonsense exists with the staging counter, but we'll save
that for another day.)

Instead, emit sysreq instructions by name as we do for the call
instruction. This allows us to build the table during code generation,
simplifying another piece of the assembler pipeline.

Bug: issue #358
Test: manual test
  • Loading branch information
dvander committed Sep 10, 2019
1 parent 82ed2b3 commit e2e0343
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 93 deletions.
130 changes: 72 additions & 58 deletions compiler/assembler.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// vim: set sts=2 ts=8 sw=2 tw=99 et:
// vim: set sts=4 ts=8 sw=4 tw=99 et:
/* Pawn compiler - Binary code generation (the "assembler")
*
* Copyright (c) ITB CompuPhase, 1997-2006
Expand Down Expand Up @@ -209,6 +209,10 @@ class AsmReader final
assert(pos_ < end_);
return pos_;
}
Vector<symbol*>& native_list() {
return native_list_;
}
symbol* extract_call_target();

private:
template <bool StopAtLine>
Expand All @@ -218,6 +222,7 @@ class AsmReader final
memfile_t* fp_;
const char* pos_;
const char* end_;
Vector<symbol*> native_list_;
};

const char*
Expand Down Expand Up @@ -270,6 +275,32 @@ AsmReader::end_of_token()
return pos_;
}

symbol*
AsmReader::extract_call_target()
{
char name[METHOD_NAMEMAX];

const char* params = pos();

int i;
for (i = 0; !isspace(*params); i++, params++) {
assert(*params != '\0');
assert(i < METHOD_NAMEMAX);
name[i] = *params;
}
name[i] = '\0';
pos_ += i;

symbol* sym = findglb(name);
if (!sym) {
return nullptr;
}

assert(sym->ident == iFUNCTN);
assert(sym->vclass == sGLOBAL);
return sym;
}

static void
noop(CellWriter* writer, AsmReader* reader, cell opcode)
{
Expand Down Expand Up @@ -369,35 +400,10 @@ do_dumpfill(CellWriter* writer, AsmReader* reader, cell opcode)
}
}

static symbol*
extract_call_target(AsmReader* reader)
{
char name[METHOD_NAMEMAX];

const char* params = reader->pos();

int i;
for (i = 0; !isspace(*params); i++, params++) {
assert(*params != '\0');
assert(i < METHOD_NAMEMAX);
name[i] = *params;
}
name[i] = '\0';

symbol* sym = findglb(name);
if (!sym) {
return nullptr;
}

assert(sym->ident == iFUNCTN);
assert(sym->vclass == sGLOBAL);
return sym;
}

static void
do_ldgfen(CellWriter* writer, AsmReader* reader, cell opcode)
{
symbol* sym = extract_call_target(reader);
symbol* sym = reader->extract_call_target();
assert(sym->ident == iFUNCTN);
assert(!(sym->usage & uNATIVE));
assert((sym->function()->funcid & 1) == 1);
Expand All @@ -411,12 +417,29 @@ do_ldgfen(CellWriter* writer, AsmReader* reader, cell opcode)
static void
do_call(CellWriter* writer, AsmReader* reader, cell opcode)
{
symbol* sym = extract_call_target(reader);
symbol* sym = reader->extract_call_target();

writer->append(opcode);
writer->append(sym->addr());
}

static void
do_sysreq(CellWriter* writer, AsmReader* reader, cell opcode)
{
symbol* sym = reader->extract_call_target();
ucell nargs = reader->getparam();

assert(sym->usage & uNATIVE);
if (sym->addr() < 0) {
sym->setAddr(reader->native_list().length());
reader->native_list().append(sym);
}

writer->append(opcode);
writer->append(sym->addr());
writer->append(nargs);
}

static void
do_jump(CellWriter* writer, AsmReader* reader, cell opcode)
{
Expand Down Expand Up @@ -573,10 +596,10 @@ static OPCODEC opcodelist[] = {
{ 24, "strb.i", sIN_CSEG, parm1 },
{ 79, "sub", sIN_CSEG, parm0 },
{ 80, "sub.alt", sIN_CSEG, parm0 },
{132, "swap.alt", sIN_CSEG, parm0 }, /* version 4 */
{131, "swap.pri", sIN_CSEG, parm0 }, /* version 4 */
{129, "switch", sIN_CSEG, do_switch }, /* version 1 */
{135, "sysreq.n", sIN_CSEG, parm2 }, /* version 9 (replaces SYSREQ.d from earlier version) */
{132, "swap.alt", sIN_CSEG, parm0 },
{131, "swap.pri", sIN_CSEG, parm0 },
{129, "switch", sIN_CSEG, do_switch },
{135, "sysreq.n", sIN_CSEG, do_sysreq },
{161, "tracker.pop.setheap", sIN_CSEG, parm0 },
{160, "tracker.push.c", sIN_CSEG, parm1 },
{ 35, "xchg", sIN_CSEG, parm0 },
Expand Down Expand Up @@ -620,9 +643,8 @@ findopcode(const char* instr, size_t maxlen)

// Generate code or data into a buffer.
static void
generate_segment(Vector<cell>* code_buffer, Vector<cell>* data_buffer, memfile_t* fin)
generate_segment(AsmReader& reader, Vector<cell>* code_buffer, Vector<cell>* data_buffer)
{
AsmReader reader(fin);
CellWriter code_writer(*code_buffer);
CellWriter data_writer(*data_buffer);

Expand Down Expand Up @@ -677,14 +699,6 @@ class VerifyOpcodeSorting
} sVerifyOpcodeSorting;
#endif

static int
sort_by_addr(const void* a1, const void* a2)
{
symbol* s1 = *(symbol**)a1;
symbol* s2 = *(symbol**)a2;
return s1->addr() - s2->addr();
}

static int
sort_by_name(const void* a1, const void* a2)
{
Expand Down Expand Up @@ -1403,7 +1417,6 @@ assemble_to_buffer(SmxByteBuffer* buffer, memfile_t* fin)

RttiBuilder rtti(names);

Vector<symbol*> nativeList;
Vector<function_entry> functions;

// Sort globals.
Expand All @@ -1415,9 +1428,10 @@ assemble_to_buffer(SmxByteBuffer* buffer, memfile_t* fin)
// Build the easy symbol tables.
for (const auto& sym : global_symbols) {
if (sym->ident == iFUNCTN) {
if ((sym->usage & uNATIVE) != 0 && (sym->usage & uREAD) != 0 && sym->addr() >= 0) {
// Natives require special handling, so we save them for later.
nativeList.append(sym);
if (sym->usage & uNATIVE) {
// Set native addresses to -1 to indicate whether we've seen
// them in the assembly yet.
sym->setAddr(-1);
continue;
}

Expand Down Expand Up @@ -1473,10 +1487,18 @@ assemble_to_buffer(SmxByteBuffer* buffer, memfile_t* fin)
rtti.add_method(sym);
}

// Shuffle natives to be in address order.
qsort(nativeList.buffer(), nativeList.length(), sizeof(symbol*), sort_by_addr);
for (size_t i = 0; i < nativeList.length(); i++) {
symbol* sym = nativeList[i];
for (int i = 1; i <= sc_labnum; i++)
sLabelTable.append(-1);
assert(sLabelTable.length() == size_t(sc_labnum));

// Generate buffers.
AsmReader reader(fin);
Vector<cell> code_buffer, data_buffer;
generate_segment(reader, &code_buffer, &data_buffer);

// Populate the native table.
for (size_t i = 0; i < reader.native_list().length(); i++) {
symbol* sym = reader.native_list()[i];
assert(size_t(sym->addr()) == i);

sp_file_natives_t& entry = natives->add();
Expand All @@ -1490,14 +1512,6 @@ assemble_to_buffer(SmxByteBuffer* buffer, memfile_t* fin)
rtti.add_native(sym);
}

for (int i = 1; i <= sc_labnum; i++)
sLabelTable.append(-1);
assert(sLabelTable.length() == size_t(sc_labnum));

// Generate buffers.
Vector<cell> code_buffer, data_buffer;
generate_segment(&code_buffer, &data_buffer, fin);

// Set up the code section.
code->header().codesize = code_buffer.length() * sizeof(cell);
code->header().cellsize = sizeof(cell);
Expand Down
39 changes: 12 additions & 27 deletions compiler/codegen.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// vim: set ts=8 sts=2 sw=2 tw=99 et:
// vim: set ts=8 sts=4 sw=4 tw=99 et:
/* Pawn compiler - code generation (unoptimized "assembler" code)
*
* Copyright (c) ITB CompuPhase, 1997-2006
Expand Down Expand Up @@ -718,7 +718,7 @@ ffcase(cell value, char* labelname, int newtable)
* Call specified function
*/
void
ffcall(symbol* sym, const char* label, int numargs)
ffcall(symbol* sym, int numargs)
{
char symname[2 * sNAMEMAX + 16];
char aliasname[sNAMEMAX + 1];
Expand All @@ -729,44 +729,29 @@ ffcall(symbol* sym, const char* label, int numargs)
funcdisplayname(symname, sym->name());
if ((sym->usage & uNATIVE) != 0) {
/* reserve a SYSREQ id if called for the first time */
assert(label == NULL);
stgwrite("\tsysreq.n ");
if (sc_status == statWRITE && (sym->usage & uREAD) == 0 && sym->addr() >= 0)
sym->setAddr(ntv_funcid++);

/* Look for an alias */
symbol* target = sym;
if (lookup_alias(aliasname, sym->name())) {
symbol* asym = findglb(aliasname);
if (asym && asym->ident == iFUNCTN && ((sym->usage & uNATIVE) != 0)) {
sym = asym;
if (sc_status == statWRITE && (sym->usage & uREAD) == 0 && sym->addr() >= 0) {
sym->setAddr(ntv_funcid++);
markusage(sym, uREAD);
}
target = asym;
}
}
outval(sym->addr(), FALSE);
stgwrite(target->name());
stgwrite(" ");
outval(numargs, FALSE);
if (sc_asmfile) {
stgwrite("\t; ");
stgwrite(symname);
}
stgwrite(
"\n"); /* write on a separate line, to mark a sequence point for the peephole optimizer */
stgwrite("\n");
code_idx += opcodes(1) + opargs(2);
} else {
const char* symname = sym->name();
pushval(numargs);
/* normal function */
stgwrite("\tcall ");
if (label != NULL) {
stgwrite("l.");
stgwrite(label);
} else {
stgwrite(symname);
}
if (sc_asmfile && (label != NULL || (!isalpha(symname[0]) && symname[0] != '_' &&
symname[0] != sc_ctrlchar)))
stgwrite(symname);
if (sc_asmfile &&
((!isalpha(symname[0]) && symname[0] != '_' && symname[0] != sc_ctrlchar)))
{
stgwrite("\t; ");
stgwrite(symname);
Expand Down Expand Up @@ -1375,7 +1360,7 @@ invoke_getter(methodmap_method_t* method)
// sysreq.n N 1
// stack 8
pushreg(sPRI);
ffcall(method->getter, NULL, 1);
ffcall(method->getter, 1);

if (sc_status != statSKIP)
markusage(method->getter, uREAD);
Expand All @@ -1393,7 +1378,7 @@ invoke_setter(methodmap_method_t* method, int save)
pushreg(sPRI);
pushreg(sPRI);
pushreg(sALT);
ffcall(method->setter, NULL, 2);
ffcall(method->setter, 2);
if (save)
popreg(sPRI);

Expand Down
2 changes: 1 addition & 1 deletion compiler/codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ void genarray(int dims, int _autozero);
void swap1(void);
void ffswitch(int label);
void ffcase(cell value, char* labelname, int newtable);
void ffcall(symbol* sym, const char* label, int numargs);
void ffcall(symbol* sym, int numargs);
void ffret();
void ffabort(int reason);
void ffbounds(cell size);
Expand Down
4 changes: 2 additions & 2 deletions compiler/expressions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ check_userop(void (*oper)(void), int tag1, int tag2, int numparam, value* lval,
}
markexpr(sPARM, NULL, 0); /* mark the end of a sub-expression */
assert(sym->ident == iFUNCTN);
ffcall(sym, NULL, paramspassed);
ffcall(sym, paramspassed);
if (sc_status != statSKIP)
markusage(sym, uREAD); /* do not mark as "used" when this call itself is skipped */
sideeffect = TRUE; /* assume functions carry out a side-effect */
Expand Down Expand Up @@ -3024,7 +3024,7 @@ SC3ExpressionParser::callfunction(symbol* sym, const svalue* aImplicitThis, valu
stgmark(sENDREORDER); /* mark end of reversed evaluation */

sCallStackUsage++;
ffcall(sym, NULL, nargs);
ffcall(sym, nargs);
if (sc_status != statSKIP)
markusage(sym, uREAD); /* do not mark as "used" when this call itself is skipped */
if (symret != NULL)
Expand Down
5 changes: 2 additions & 3 deletions compiler/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,6 @@ resetglobals(void) {
declared = 0; /* number of local cells declared */
glb_declared = 0; /* number of global cells declared */
code_idx = 0; /* number of bytes with generated code */
ntv_funcid = 0; /* incremental number of native function */
curseg = 0; /* 1 if currently parsing CODE, 2 if parsing DATA */
freading = FALSE; /* no input file ready yet */
fline = 0; /* the line number in the current file */
Expand Down Expand Up @@ -3792,7 +3791,7 @@ dodelete() {
// stack 8
pushreg(sPRI);
{
ffcall(map->dtor->target, NULL, 1);
ffcall(map->dtor->target, 1);

// Only mark usage if we're not skipping codegen.
if (sc_status != statSKIP)
Expand Down Expand Up @@ -5326,7 +5325,7 @@ destructsymbols(symbol* root, int level) {
addconst(offset); /* add offset to array data to the address */
pushreg(sPRI);
assert(opsym->ident == iFUNCTN);
ffcall(opsym, NULL, 2);
ffcall(opsym, 2);
if (sc_status != statSKIP)
markusage(opsym,
uREAD); /* do not mark as "used" when this call itself is skipped */
Expand Down
1 change: 0 additions & 1 deletion compiler/scvars.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ int staging = 0; /* true if staging output */
cell declared = 0; /* number of local cells declared */
cell glb_declared = 0; /* number of global cells declared */
cell code_idx = 0; /* number of bytes with generated code */
int ntv_funcid = 0; /* incremental number of native function */
int errnum = 0; /* number of errors */
int warnnum = 0; /* number of warnings */
int sc_debug = sCHKBOUNDS; /* by default: bounds checking+assertions */
Expand Down
1 change: 0 additions & 1 deletion compiler/scvars.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ extern int staging; /* true if staging output */
extern cell declared; /* number of local cells declared */
extern cell glb_declared; /* number of global cells declared */
extern cell code_idx; /* number of bytes with generated code */
extern int ntv_funcid; /* incremental number of native function */
extern int errnum; /* number of errors */
extern int warnnum; /* number of warnings */
extern int sc_debug; /* debug/optimization options (bit field) */
Expand Down

0 comments on commit e2e0343

Please sign in to comment.