all expression generator done

This commit is contained in:
ridethepig 2023-03-31 16:34:05 +00:00
parent 7140f01bb0
commit c29b455305
3 changed files with 166 additions and 74 deletions

View File

@ -25,9 +25,11 @@
#include "cgen.h" #include "cgen.h"
#include "cgen_gc.h" #include "cgen_gc.h"
#include "cool-tree.h" #include "cool-tree.h"
#include <algorithm>
#include <cassert> #include <cassert>
#include <cstddef> #include <cstddef>
#include <iostream> #include <iostream>
#include <map>
#include <utility> #include <utility>
extern void emit_string_constant(ostream &str, char *s); extern void emit_string_constant(ostream &str, char *s);
@ -95,6 +97,7 @@ BoolConst falsebool(FALSE);
BoolConst truebool(TRUE); BoolConst truebool(TRUE);
static int rel_stack_depth; static int rel_stack_depth;
static int class_tag_count;
//********************************************************* //*********************************************************
// //
// Define method for code generation // Define method for code generation
@ -433,10 +436,9 @@ void IntEntry::code_def(ostream &s, int intclasstag) {
s << WORD << "-1" << endl; s << WORD << "-1" << endl;
code_ref(s); code_ref(s);
s << LABEL // label s << LABEL // label
<< WORD << intclasstag << endl // class tag << WORD << intclasstag << endl // class tag
<< WORD << (DEFAULT_OBJFIELDS + INT_SLOTS) << endl // object size << WORD << (DEFAULT_OBJFIELDS + INT_SLOTS) << endl; // object size
<< WORD;
s << WORD << INTNAME << DISPTAB_SUFFIX << endl; // dispatch ptr s << WORD << INTNAME << DISPTAB_SUFFIX << endl; // dispatch ptr
s << WORD << str << endl; // integer value s << WORD << str << endl; // integer value
@ -469,10 +471,9 @@ void BoolConst::code_def(ostream &s, int boolclasstag) {
s << WORD << "-1" << endl; s << WORD << "-1" << endl;
code_ref(s); code_ref(s);
s << LABEL // label s << LABEL // label
<< WORD << boolclasstag << endl // class tag << WORD << boolclasstag << endl // class tag
<< WORD << (DEFAULT_OBJFIELDS + BOOL_SLOTS) << endl // object size << WORD << (DEFAULT_OBJFIELDS + BOOL_SLOTS) << endl; // object size
<< WORD;
s << WORD << BOOLNAME << DISPTAB_SUFFIX << endl; // dispatch ptr s << WORD << BOOLNAME << DISPTAB_SUFFIX << endl; // dispatch ptr
s << WORD << val << endl; // value (0 or 1) s << WORD << val << endl; // value (0 or 1)
@ -674,6 +675,18 @@ CgenClassTable::CgenClassTable(Classes classes, ostream &s) : str(s) {
build_inheritance_tree(); build_inheritance_tree();
if (cgen_debug) if (cgen_debug)
dump_inheritance_tree(); dump_inheritance_tree();
root()->traverse_allocate_tag();
std::sort(nodes.begin(), nodes.end(), [](CgenNode *a, CgenNode *b) {
return a->get_class_tag() < b->get_class_tag();
});
if (cgen_debug) {
std::cerr << "Dump class tags:\n";
for (auto node : nodes) {
std::cerr << node->name << ": " << node->get_class_tag() << ","
<< node->get_children_tag() << "\n";
}
}
// sort the vector is in tag order to generate correct class_objTab
root()->traverse_generate_object(); root()->traverse_generate_object();
// nodes[0] is the Object class // nodes[0] is the Object class
stringclasstag = get_node(Str)->get_class_tag(); stringclasstag = get_node(Str)->get_class_tag();
@ -818,7 +831,6 @@ void CgenClassTable::install_class(CgenNodeP nd) {
// The class name is legal, so add it to the list of classes // The class name is legal, so add it to the list of classes
// and the symbol table. // and the symbol table.
nodes.push_back(nd); nodes.push_back(nd);
nd->set_class_tag(nodes.size());
addid(name, nd); addid(name, nd);
} }
@ -1057,6 +1069,14 @@ void CgenNode::traverse_generate_object() {
} }
} }
void CgenNode::traverse_allocate_tag() {
this->_class_tag = class_tag_count++;
for (auto child : children) {
child->traverse_allocate_tag();
}
this->_children_tag_range = class_tag_count - 1;
}
#pragma endregion #pragma endregion
//****************************************************************** //******************************************************************
@ -1105,9 +1125,9 @@ void static_dispatch_class::code(ostream &s, CgenClassTable *classtab) {
emit_push(ACC, s); // push param to stack emit_push(ACC, s); // push param to stack
} }
this->expr->code(s, classtab); this->expr->code(s, classtab);
auto label_index_dispatch = classtab->alloc_label_index(); auto label_dispatch = classtab->alloc_label_index();
// use bne to save a label, because we'll never come back if abort // use bne to save a label, because we'll never come back if abort
emit_bne(ACC, ZERO, label_index_dispatch, s); emit_bne(ACC, ZERO, label_dispatch, s);
// Prints the line number, from $t1, and filename, from $a0, at which the // Prints the line number, from $t1, and filename, from $a0, at which the
// dispatch occurred, and aborts. // dispatch occurred, and aborts.
emit_load_imm(T1, this->line_number, s); emit_load_imm(T1, this->line_number, s);
@ -1117,7 +1137,7 @@ void static_dispatch_class::code(ostream &s, CgenClassTable *classtab) {
s << endl; s << endl;
emit_jal("_dispatch_abort", s); emit_jal("_dispatch_abort", s);
// ready to call the method // ready to call the method
emit_label_def(label_index_dispatch, s); emit_label_def(label_dispatch, s);
// load dispatch table // load dispatch table
emit_partial_load_address(T1, s); emit_partial_load_address(T1, s);
emit_disptable_ref(this->type_name, s); emit_disptable_ref(this->type_name, s);
@ -1141,9 +1161,9 @@ void dispatch_class::code(ostream &s, CgenClassTable *classtab) {
emit_push(ACC, s); // push param to stack emit_push(ACC, s); // push param to stack
} }
this->expr->code(s, classtab); this->expr->code(s, classtab);
auto label_index_dispatch = classtab->alloc_label_index(); auto label_dispatch = classtab->alloc_label_index();
// use bne to save a label, because we'll never come back if abort // use bne to save a label, because we'll never come back if abort
emit_bne(ACC, ZERO, label_index_dispatch, s); emit_bne(ACC, ZERO, label_dispatch, s);
// Prints the line number, from $t1, and filename, from $a0, at which the // Prints the line number, from $t1, and filename, from $a0, at which the
// dispatch occurred, and aborts. // dispatch occurred, and aborts.
emit_load_imm(T1, this->line_number, s); emit_load_imm(T1, this->line_number, s);
@ -1153,7 +1173,7 @@ void dispatch_class::code(ostream &s, CgenClassTable *classtab) {
s << endl; s << endl;
emit_jal("_dispatch_abort", s); emit_jal("_dispatch_abort", s);
// ready to call the method // ready to call the method
emit_label_def(label_index_dispatch, s); emit_label_def(label_dispatch, s);
// load dispatch table // load dispatch table
emit_load(T1, DISPTABLE_OFFSET, ACC, s); emit_load(T1, DISPTABLE_OFFSET, ACC, s);
// load method address // load method address
@ -1178,15 +1198,15 @@ void dispatch_class::code(ostream &s, CgenClassTable *classtab) {
void cond_class::code(ostream &s, CgenClassTable *classtab) { void cond_class::code(ostream &s, CgenClassTable *classtab) {
this->pred->code(s, classtab); this->pred->code(s, classtab);
emit_fetch_bool(ACC, ACC, s); // fetch the boolean value into $a0 emit_fetch_bool(ACC, ACC, s); // fetch the boolean value into $a0
auto label_index_false = classtab->alloc_label_index(); auto label_false = classtab->alloc_label_index();
auto label_index_exit = classtab->alloc_label_index(); auto label_exit = classtab->alloc_label_index();
emit_beqz(ACC, label_index_false, s); // $a0==0, pred is false, goto else emit_beqz(ACC, label_false, s); // $a0==0, pred is false, goto else
this->then_exp->code(s, classtab); // pred is true, eval then branch this->then_exp->code(s, classtab); // pred is true, eval then branch
emit_branch(label_index_exit, s); // $a0 <- then, and we goto exit emit_branch(label_exit, s); // $a0 <- then, and we goto exit
emit_label_def(label_index_false, s); emit_label_def(label_false, s);
// the label is preserved in advance so that we can define it here safely // the label is preserved in advance so that we can define it here safely
this->else_exp->code(s, classtab); // $a0 <- else this->else_exp->code(s, classtab); // $a0 <- else
emit_label_def(label_index_exit, s); emit_label_def(label_exit, s);
} }
/* /*
@ -1194,20 +1214,92 @@ void cond_class::code(ostream &s, CgenClassTable *classtab) {
loop always evaluate to void, so remember to set $a0<-0 loop always evaluate to void, so remember to set $a0<-0
*/ */
void loop_class::code(ostream &s, CgenClassTable *classtab) { void loop_class::code(ostream &s, CgenClassTable *classtab) {
auto label_index_predicate = classtab->alloc_label_index(); auto label_predicate = classtab->alloc_label_index();
emit_label_def(label_index_predicate, s); emit_label_def(label_predicate, s);
// predefine a label and our loop could restart and check predicate from here // predefine a label and our loop could restart and check predicate from here
this->pred->code(s, classtab); // check predicate, which sets $a0<-Bool object this->pred->code(s, classtab); // check predicate, which sets $a0<-Bool object
emit_fetch_bool(ACC, ACC, s); // extrace 0 or 1 from Bool object in $a0 emit_fetch_bool(ACC, ACC, s); // extrace 0 or 1 from Bool object in $a0
auto label_index_exit = classtab->alloc_label_index(); auto label_exit = classtab->alloc_label_index();
emit_beqz(ACC, label_index_exit, s); // if predicate is false, goto exit emit_beqz(ACC, label_exit, s); // if predicate is false, goto exit
this->body->code(s, classtab); // if predicate is true, move on with our loop this->body->code(s, classtab); // if predicate is true, move on with our loop
emit_branch(label_index_predicate, s); // anyways, go back and check predicate emit_branch(label_predicate, s); // anyways, go back and check predicate
emit_label_def(label_index_exit, s); emit_label_def(label_exit, s);
emit_load_imm(ACC, 0, s); // whatever the case, loop expr evaluates to void! emit_load_imm(ACC, 0, s); // whatever the case, loop expr evaluates to void!
} }
void typcase_class::code(ostream &s, CgenClassTable *classtab) {} /*
I think type case is the most difficult part in this PA. It selects the
closest ancestor of the expr's type, thus requiring hierarchy infomation
available at runtime.
Again, through reverse engineering (^_^) the reference compiler, I managed to
find out a relatively simple way to embed hierarchy into the program.
We may use the class tag to do this. In advance, allocate the class tags in
pre-order traversal of the inheritance tree, and record for each node when
all its children is allocated. In this way, every node has a range of tags
covering itself and its children. When generating `case`, start from the
leaves, because we need to match the closest ancestor. If the tag is in some
range, then we can say it matches the branch.
Besides the hierarchy problem, there are two runtime error here: a case
statement has no match -> `_case_abort`; a case on a void object ->
`_case_abort2`. Remember to set these two guys.
*/
void typcase_class::code(ostream &s, CgenClassTable *classtab) {
this->expr->code(s, classtab);
auto label_case = classtab->alloc_label_index();
// use bne to save a label, because we'll never come back if abort
emit_bne(ACC, ZERO, label_case, s);
// Prints the line number, from $t1, and filename, from $a0, at which the
// type case occurred, and aborts.
emit_load_imm(T1, this->line_number, s);
emit_partial_load_address(ACC, s);
stringtable.lookup_string(classtab->cur_class->get_filename()->get_string())
->code_ref(s);
s << endl;
emit_jal("_case_abort2", s);
// start type case here
emit_label_def(label_case, s);
// load class tag, if no error, object ref is in $a0
emit_load(T1, TAG_OFFSET, ACC, s);
// generate a map<Type, BranchNode> to simplify branch search
std::map<Symbol, branch_class *> sym_branch;
for (auto branch_i = this->cases->first(); this->cases->more(branch_i);
branch_i = this->cases->next(branch_i)) {
auto branch = static_cast<branch_class *>(this->cases->nth(branch_i));
sym_branch[branch->type_decl] = branch;
}
auto label_exit = classtab->alloc_label_index();
// generate the branches in reverse pre-order
for (auto node_ritr = classtab->nodes.rbegin();
node_ritr != classtab->nodes.rend(); ++node_ritr) {
auto node = *node_ritr;
auto branch_itr = sym_branch.find(node->name);
if (branch_itr == sym_branch.end())
continue;
auto branch = branch_itr->second;
auto label_branch = classtab->alloc_label_index();
// if expr's tag is not in the branch's children range, test next branch
emit_blti(T1, node->get_class_tag(), label_branch, s);
emit_bgti(T1, node->get_children_tag(), label_branch, s);
// though maybe quite trivial(just bind another name), still push to stack
// because we dont know whether $a0 is going to be overwritten
emit_push(ACC, s);
// allocate a new location
classtab->enterscope();
classtab->loctab.add(LocationTableItem(branch->name, Stack, -rel_stack_depth));
// if expr's tag is in range, evaluate this branch
branch->expr->code(s, classtab);
classtab->loctab.exitscope();
emit_pop(s); // balance stack
// already matched, the matching process ends here and go to exit
emit_branch(label_exit, s);
// the label for the next branch
emit_label_def(label_branch, s);
}
// no match, the procedure's is in $a0, which remains unmodified if no branch
// is taken, thus unnecessary to set it
emit_jal("_case_abort", s);
emit_label_def(label_exit, s);
}
/* /*
For block expression, generate code expression by expression, nothing else For block expression, generate code expression by expression, nothing else
@ -1361,17 +1453,17 @@ void lt_class::code(ostream &s, CgenClassTable *classtab) {
this->e2->code(s, classtab); this->e2->code(s, classtab);
emit_fetch_int(ACC, ACC, s); // $a0 <- val(e2) emit_fetch_int(ACC, ACC, s); // $a0 <- val(e2)
emit_load(T1, 1, SP, s); // $t1 <- val(e1) emit_load(T1, 1, SP, s); // $t1 <- val(e1)
auto label_index_true = classtab->alloc_label_index(); auto label_true = classtab->alloc_label_index();
auto label_index_exit = classtab->alloc_label_index(); auto label_exit = classtab->alloc_label_index();
emit_blt(T1, ACC, label_index_true, s); emit_blt(T1, ACC, label_true, s);
// after the branch, val(e2) in $a0 is no more needed, making space for result // after the branch, val(e2) in $a0 is no more needed, making space for result
emit_load_bool(ACC, falsebool, s); emit_load_bool(ACC, falsebool, s);
// didn't jump in last instruction, so it is false // didn't jump in last instruction, so it is false
emit_branch(label_index_exit, s); // dont want it to be overridden emit_branch(label_exit, s); // dont want it to be overridden
emit_label_def(label_index_true, s); // first branch goes to here emit_label_def(label_true, s); // first branch goes to here
emit_load_bool(ACC, truebool, s); // branch means true emit_load_bool(ACC, truebool, s); // branch means true
emit_label_def(label_index_exit, s); // second jump goes to here emit_label_def(label_exit, s); // second jump goes to here
emit_pop(1, s); // cleanup anyway, only one push is made emit_pop(1, s); // cleanup anyway, only one push is made
} }
/* /*
@ -1384,14 +1476,14 @@ void leq_class::code(ostream &s, CgenClassTable *classtab) {
this->e2->code(s, classtab); this->e2->code(s, classtab);
emit_fetch_int(ACC, ACC, s); emit_fetch_int(ACC, ACC, s);
emit_load(T1, 1, SP, s); emit_load(T1, 1, SP, s);
auto label_index_true = classtab->alloc_label_index(); auto label_true = classtab->alloc_label_index();
auto label_index_exit = classtab->alloc_label_index(); auto label_exit = classtab->alloc_label_index();
emit_bleq(T1, ACC, label_index_true, s); emit_bleq(T1, ACC, label_true, s);
emit_load_bool(ACC, falsebool, s); emit_load_bool(ACC, falsebool, s);
emit_branch(label_index_exit, s); emit_branch(label_exit, s);
emit_label_def(label_index_true, s); emit_label_def(label_true, s);
emit_load_bool(ACC, truebool, s); emit_load_bool(ACC, truebool, s);
emit_label_def(label_index_exit, s); emit_label_def(label_exit, s);
emit_pop(1, s); emit_pop(1, s);
} }
@ -1435,13 +1527,13 @@ void eq_class::code(ostream &s, CgenClassTable *classtab) {
emit_move(T2, ACC, s); // $t2<-&e2 emit_move(T2, ACC, s); // $t2<-&e2
// there's no choice but to break our 2 register rule ~_~ // there's no choice but to break our 2 register rule ~_~
emit_load_bool(ACC, truebool, s); // load true in advance in case &e1==&e2 emit_load_bool(ACC, truebool, s); // load true in advance in case &e1==&e2
auto label_index_exit = classtab->alloc_label_index(); auto label_exit = classtab->alloc_label_index();
emit_beq(T1, T2, label_index_exit, s); // if &e1==&e2, then we are done here emit_beq(T1, T2, label_exit, s); // if &e1==&e2, then we are done here
emit_load_bool(A1, falsebool, s); // prepare a false choice for equality_test emit_load_bool(A1, falsebool, s); // prepare a false choice for equality_test
emit_jal("equality_test", s); emit_jal("equality_test", s);
// at this point, $t1=&e1, $t2=&e2, $a0=true, $a1=false. ready to call // at this point, $t1=&e1, $t2=&e2, $a0=true, $a1=false. ready to call
// $a0 will be either true or false, so just keep it as the result // $a0 will be either true or false, so just keep it as the result
emit_label_def(label_index_exit, s); emit_label_def(label_exit, s);
emit_pop(1, s); // balance stack, 1 push in this expression emit_pop(1, s); // balance stack, 1 push in this expression
} }
@ -1522,11 +1614,11 @@ void isvoid_class::code(ostream &s, CgenClassTable *classtab) {
this->e1->code(s, classtab); this->e1->code(s, classtab);
emit_move(T1, ACC, s); // $t1 <- &e1 emit_move(T1, ACC, s); // $t1 <- &e1
emit_load_bool(ACC, truebool, s); emit_load_bool(ACC, truebool, s);
auto label_index_exit = classtab->alloc_label_index(); auto label_exit = classtab->alloc_label_index();
emit_beqz(T1, label_index_exit, s); emit_beqz(T1, label_exit, s);
// &e1 == nullptr ?, if so skip the next load false // &e1 == nullptr ?, if so skip the next load false
emit_load_bool(ACC, falsebool, s); emit_load_bool(ACC, falsebool, s);
emit_label_def(label_index_exit, s); emit_label_def(label_exit, s);
} }
/* /*

View File

@ -38,10 +38,11 @@ class LocationTable {
private: private:
std::vector<LocationTableItem> table; std::vector<LocationTableItem> table;
std::vector<size_t> scope; std::vector<size_t> scope;
public: public:
// lookup the inner-most item with the same id as name // lookup the inner-most item with the same id as name
LocationTableItem* lookup(Symbol name) { LocationTableItem *lookup(Symbol name) {
for (auto itr = table.rbegin(); itr != table.rend(); ++ itr) { for (auto itr = table.rbegin(); itr != table.rend(); ++itr) {
if (itr->id == name) { if (itr->id == name) {
return &*itr; return &*itr;
} }
@ -49,12 +50,8 @@ public:
assert(0); assert(0);
return nullptr; return nullptr;
} }
void add(LocationTableItem item) { void add(LocationTableItem item) { table.push_back(item); };
table.push_back(item); void enterscope() { scope.push_back(table.size()); }
};
void enterscope() {
scope.push_back(table.size());
}
void exitscope() { void exitscope() {
auto end = scope.back(); auto end = scope.back();
scope.pop_back(); scope.pop_back();
@ -62,10 +59,11 @@ public:
} }
void dump() { void dump() {
scope.push_back(table.size()); scope.push_back(table.size());
for (size_t i = 0; i < scope.size() - 1; ++ i) { for (size_t i = 0; i < scope.size() - 1; ++i) {
std::cerr << "scope" << i << "\n"; std::cerr << "scope" << i << "\n";
for (size_t j = scope[i]; j < scope[i+1]; j ++) { for (size_t j = scope[i]; j < scope[i + 1]; j++) {
std::cerr << table[j].id << ", " << table[j].location << ", " << table[j].offset << "\n"; std::cerr << table[j].id << ", " << table[j].location << ", "
<< table[j].offset << "\n";
} }
} }
scope.pop_back(); scope.pop_back();
@ -74,14 +72,13 @@ public:
class CgenClassTable : public SymbolTable<Symbol, CgenNode> { class CgenClassTable : public SymbolTable<Symbol, CgenNode> {
private: private:
std::vector<CgenNode *> nodes;
ostream &str; ostream &str;
int stringclasstag; int stringclasstag;
int intclasstag; int intclasstag;
int boolclasstag; int boolclasstag;
IntEntry* _int_default = nullptr; IntEntry *_int_default = nullptr;
StringEntry* _str_default = nullptr; StringEntry *_str_default = nullptr;
BoolConst* _bool_default = nullptr; BoolConst *_bool_default = nullptr;
int label_count = 0; // an incremental counter to avoid label conflicts int label_count = 0; // an incremental counter to avoid label conflicts
// The following methods emit code for // The following methods emit code for
@ -115,15 +112,16 @@ private:
public: public:
LocationTable loctab; LocationTable loctab;
Symbol expr_type_decl; Symbol expr_type_decl;
CgenNode* cur_class; std::vector<CgenNode *> nodes;
CgenNode *cur_class;
CgenClassTable(Classes, ostream &str); CgenClassTable(Classes, ostream &str);
void code(); void code();
CgenNode* root() { return nodes[0]; } CgenNode *root() { return nodes[0]; }
/* aquire an unused label index */ /* aquire an unused label index */
int alloc_label_index() { return label_count++; } int alloc_label_index() { return label_count++; }
IntEntry* int_default() const { return _int_default; }; IntEntry *int_default() const { return _int_default; };
StringEntry* str_default() const { return _str_default; }; StringEntry *str_default() const { return _str_default; };
BoolConst* bool_default() const { return _bool_default; }; BoolConst *bool_default() const { return _bool_default; };
int get_method_index(Symbol class_name, Symbol method_name); int get_method_index(Symbol class_name, Symbol method_name);
}; };
@ -133,10 +131,11 @@ private:
std::vector<CgenNode *> children; // Children of class std::vector<CgenNode *> children; // Children of class
Basicness basic_status; // `Basic' if class is basic Basicness basic_status; // `Basic' if class is basic
// `NotBasic' otherwise // `NotBasic' otherwise
/* class_tag is allocated in pre-order */
uint32_t _class_tag = 0; uint32_t _class_tag = 0;
/* Allocate a class_tag on first scan increase in scanning order, /* record children's class tag range for type case code gen */
starting from 1, so 0 is actually invalid by design uint32_t _children_tag_range;
*/
AttrListT attributes; AttrListT attributes;
// attr list including inherited // attr list including inherited
MethodListT methods; MethodListT methods;
@ -151,10 +150,11 @@ public:
CgenNodeP get_parentnd() { return parentnd; } CgenNodeP get_parentnd() { return parentnd; }
int basic() { return (basic_status == Basic); } int basic() { return (basic_status == Basic); }
uint32_t get_class_tag() { return _class_tag; } uint32_t get_class_tag() { return _class_tag; }
void set_class_tag(uint32_t val) { _class_tag = val; } uint32_t get_children_tag() { return _children_tag_range; }
void traverse_dump(int pad); void traverse_dump(int pad);
uint32_t get_object_size() { return (3 + attributes.size()); } uint32_t get_object_size() { return (3 + attributes.size()); }
void traverse_generate_object(); void traverse_generate_object();
void traverse_allocate_tag();
AttrListT *get_attributes() { return &attributes; }; AttrListT *get_attributes() { return &attributes; };
MethodListT *get_methods() { return &methods; }; MethodListT *get_methods() { return &methods; };
}; };

View File

@ -68,7 +68,7 @@ class D inherits C {
method_case(x1 : Object) : Int { method_case(x1 : Object) : Int {
case (x1) of case (x1) of
t1: Bool => 1; t1: Bool => 1;
t2: Int => 2; t2: Int => t2 + 100;
t3: String => 3; t3: String => 3;
t4: Object => 4; t4: Object => 4;
t5: A => 5; t5: A => 5;