Skip to content

Commit

Permalink
Remove the three-pass codegen step.
Browse files Browse the repository at this point in the history
Code generation happens in three full passes over the assembly stream.
The first pass collects label addresses. The second pass generates code.
The final pass generates data. This is unnecessary; the first pass can
be eliminated via a lazy back-patch list. The last two passes can be
combined into one.
  • Loading branch information
dvander committed Nov 26, 2018
1 parent 0475a24 commit 6f01c5f
Showing 1 changed file with 62 additions and 73 deletions.
135 changes: 62 additions & 73 deletions compiler/assembler.cpp
Expand Up @@ -61,25 +61,26 @@ using namespace ke;
class CellWriter
{
public:
explicit CellWriter(Vector<cell>* buffer)
explicit CellWriter(Vector<cell>& buffer)
: buffer_(buffer),
current_index_(0)
current_address_(0)
{}

void append(cell value) {
if (buffer_) {
buffer_->append(value);
}
current_index_ += sizeof(value);
buffer_.append(value);
current_address_ += sizeof(value);
}

cell current_index() const {
return current_index_;
cell current_address() const {
return current_address_;
}
size_t current_index() const {
return buffer_.length();
}

private:
Vector<cell>* buffer_;
cell current_index_;
Vector<cell>& buffer_;
cell current_address_;
};

class AsmReader;
Expand All @@ -93,7 +94,13 @@ typedef struct {
OPCODE_PROC func;
} OPCODEC;

static cell *LabelTable; /* label table */
struct BackpatchEntry {
size_t index;
cell target;
};

static ke::Vector<cell> sLabelTable;
static ke::Vector<BackpatchEntry> sBackpatchList;

/* apparently, strtol() does not work correctly on very large (unsigned)
* hexadecimal values */
Expand Down Expand Up @@ -384,32 +391,41 @@ static void do_call(CellWriter* writer, AsmReader* reader, cell opcode)
writer->append(sym->addr());
}

static void write_label(CellWriter* writer, int index)
{
assert(index >= 0 && index < sc_labnum);
if (sLabelTable[index] < 0) {
BackpatchEntry entry = { writer->current_index(), index };
sBackpatchList.append(entry);
writer->append(-1);
} else {
writer->append(sLabelTable[index]);
}
}

static void do_jump(CellWriter* writer, AsmReader* reader, cell opcode)
{
int i = reader->hex2long();
assert(i >= 0 && i < sc_labnum);

writer->append(opcode);
writer->append(LabelTable[i]);
write_label(writer, i);
}

static void do_switch(CellWriter* writer, AsmReader* reader, cell opcode)
{
int i = reader->hex2long();
assert(i >= 0 && i < sc_labnum);

writer->append(opcode);
writer->append(LabelTable[i]);
write_label(writer, i);
}

static void do_case(CellWriter* writer, AsmReader* reader, cell opcode)
{
cell v = reader->hex2long();
int i = reader->hex2long();
assert(i >= 0 && i < sc_labnum);

writer->append(v);
writer->append(LabelTable[i]);
write_label(writer, i);
}

static OPCODEC opcodelist[] = {
Expand Down Expand Up @@ -582,71 +598,47 @@ static int findopcode(const char *instr, size_t maxlen)
return p->value;
}

// This pass is necessary because the code addresses of labels is only known
// after the peephole optimization flag. Labels can occur inside expressions
// (e.g. the conditional operator), which are optimized.
static void relocate_labels(memfile_t* fin)
{
if (sc_labnum <= 0)
return;

assert(!LabelTable);
LabelTable = (cell *)calloc(sc_labnum, sizeof(cell));

AsmReader reader(fin);
CellWriter writer(nullptr);

do {
const char* ptr = reader.next_token_on_line();
if (!ptr)
continue;

if (tolower(*ptr) == 'l' && *(ptr + 1) == '.') {
int lindex = (int)hex2long(ptr + 2, nullptr);
assert(lindex >= 0 && lindex < sc_labnum);
LabelTable[lindex] = writer.current_index();
} else {
const char* pos = reader.end_of_token();
int op_index = findopcode(ptr, (pos - ptr));
OPCODEC &op = opcodelist[op_index];
if (!op.name) {
error(104, ke::AString(ptr, pos - ptr).chars());
}

if (op.segment == sIN_CSEG) {
reader.next_token_on_line();
op.func(&writer, &reader, op.opcode);
}
}
} while (reader.next_line());
}

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

do {
const char* instr = reader.next_token_on_line();

// Ignore empty lines and labels.
if (!instr || (tolower(*instr) == 'l' && *(instr + 1)=='.'))
// Ignore empty lines.
if (!instr)
continue;

const char* pos = reader.end_of_token();
if (tolower(instr[0]) == 'l' && instr[1] == '.') {
int lindex = (int)hex2long(instr + 2, nullptr);
assert(lindex >= 0 && lindex < sc_labnum);
assert(sLabelTable[lindex] == -1);
sLabelTable[lindex] = code_writer.current_address();
continue;
}

const char* pos = reader.end_of_token();
int op_index = findopcode(instr, (pos - instr));
OPCODEC &op = opcodelist[op_index];
assert(op.name != nullptr);

if (op.segment != pass)
continue;

CellWriter writer(buffer);

reader.next_token_on_line();
op.func(&writer, &reader, op.opcode);
if (op.segment == sIN_CSEG)
op.func(&code_writer, &reader, op.opcode);
else if (op.segment == sIN_DSEG)
op.func(&data_writer, &reader, op.opcode);
} while (reader.next_line());

// Fix up backpatches.
for (const auto& patch : sBackpatchList) {
assert(patch.index < code_buffer->length());
assert(patch.target >= 0 && patch.target < sc_labnum);
assert(sLabelTable[patch.target] >= 0);
code_buffer->at(patch.index) = sLabelTable[patch.target];
}
}

#if !defined NDEBUG
Expand Down Expand Up @@ -1409,13 +1401,13 @@ static void assemble_to_buffer(SmxByteBuffer *buffer, memfile_t* fin)
rtti.add_native(sym);
}

// Relocate all labels in the assembly buffer.
relocate_labels(fin);
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, fin, sIN_CSEG);
generate_segment(&data_buffer, fin, sIN_DSEG);
generate_segment(&code_buffer, &data_buffer, fin);

// Set up the code section.
code->header().codesize = code_buffer.length() * sizeof(cell);
Expand All @@ -1439,9 +1431,6 @@ static void assemble_to_buffer(SmxByteBuffer *buffer, memfile_t* fin)
data->header().data = sizeof(sp_file_data_t);
data->setBlob((uint8_t *)data_buffer.buffer(), data_buffer.length() * sizeof(cell));

free(LabelTable);
LabelTable = nullptr;

// Add tables in the same order SourceMod 1.6 added them.
builder.add(code);
builder.add(data);
Expand Down

0 comments on commit 6f01c5f

Please sign in to comment.