INSTR_STORE_V, /* variant, should never be accessed */
};
+uint16_t type_storep_instr[TYPE_COUNT] = {
+ INSTR_STOREP_F, /* should use I when having integer support */
+ INSTR_STOREP_S,
+ INSTR_STOREP_F,
+ INSTR_STOREP_V,
+ INSTR_STOREP_ENT,
+ INSTR_STOREP_FLD,
+ INSTR_STOREP_FNC,
+ INSTR_STOREP_ENT, /* should use I */
+#if 0
+ INSTR_STOREP_ENT, /* integer type */
+#endif
+ INSTR_STOREP_V, /* variant, should never be accessed */
+};
+
MEM_VEC_FUNCTIONS(ir_value_vector, ir_value*, v)
/***********************************************************************
MEM_VECTOR_INIT(self, functions);
MEM_VECTOR_INIT(self, globals);
+ MEM_VECTOR_INIT(self, fields);
self->name = NULL;
if (!ir_builder_set_name(self, modulename)) {
mem_d(self);
}
MEM_VEC_FUNCTIONS(ir_builder, ir_value*, globals)
+MEM_VEC_FUNCTIONS(ir_builder, ir_value*, fields)
MEM_VEC_FUNCTIONS(ir_builder, ir_function*, functions)
void ir_builder_delete(ir_builder* self)
for (i = 0; i != self->globals_count; ++i) {
ir_value_delete(self->globals[i]);
}
- MEM_VECTOR_CLEAR(self, globals);
+ MEM_VECTOR_CLEAR(self, fields);
+ for (i = 0; i != self->fields_count; ++i) {
+ ir_value_delete(self->fields[i]);
+ }
+ MEM_VECTOR_CLEAR(self, fields);
mem_d(self);
}
return ve;
}
+ir_value* ir_builder_get_field(ir_builder *self, const char *name)
+{
+ size_t i;
+ for (i = 0; i < self->fields_count; ++i) {
+ if (!strcmp(self->fields[i]->name, name))
+ return self->fields[i];
+ }
+ return NULL;
+}
+
+
+ir_value* ir_builder_create_field(ir_builder *self, const char *name, int vtype)
+{
+ ir_value *ve = ir_builder_get_field(self, name);
+ if (ve) {
+ return NULL;
+ }
+
+ ve = ir_value_var(name, store_global, TYPE_FIELD);
+ ve->fieldtype = vtype;
+ if (!ir_builder_fields_add(self, ve)) {
+ ir_value_delete(ve);
+ return NULL;
+ }
+ return ve;
+}
+
/***********************************************************************
*IR Function
*/
return NULL;
}
-ir_value* ir_function_create_local(ir_function *self, const char *name, int vtype)
+ir_value* ir_function_create_local(ir_function *self, const char *name, int vtype, bool param)
{
ir_value *ve = ir_function_get_local(self, name);
if (ve) {
return NULL;
}
- ve = ir_value_var(name, store_local, vtype);
+ if (param &&
+ self->locals_count &&
+ self->locals[self->locals_count-1]->store != store_param) {
+ printf("cannot add parameters after adding locals\n");
+ return NULL;
+ }
+
+ ve = ir_value_var(name, (param ? store_param : store_local), vtype);
if (!ir_function_locals_add(self, ve)) {
ir_value_delete(ve);
return NULL;
*IR Value
*/
+int32_t ir_value_code_addr(const ir_value *self)
+{
+ return self->code.globaladdr + self->code.addroffset;
+}
+
ir_value* ir_value_var(const char *name, int storetype, int vtype)
{
ir_value *self;
MEM_VECTOR_INIT(self, life);
return self;
}
+
+ir_value* ir_value_vector_member(ir_value *self, unsigned int member)
+{
+ ir_value *m;
+ if (member >= 3)
+ return NULL;
+
+ if (self->members[member])
+ return self->members[member];
+
+ m = ir_value_var(self->name, self->store, TYPE_FLOAT);
+ if (!m)
+ return NULL;
+ m->context = self->context;
+
+ self->members[member] = m;
+ m->code.addroffset = member;
+
+ return m;
+}
+
MEM_VEC_FUNCTIONS(ir_value, ir_life_entry_t, life)
MEM_VEC_FUNCTIONS_ALL(ir_value, ir_instr*, reads)
MEM_VEC_FUNCTIONS_ALL(ir_value, ir_instr*, writes)
void ir_value_delete(ir_value* self)
{
+ size_t i;
if (self->name)
mem_d((void*)self->name);
if (self->isconst)
if (self->vtype == TYPE_STRING)
mem_d((void*)self->constval.vstring);
}
+ for (i = 0; i < 3; ++i) {
+ if (self->members[i])
+ ir_value_delete(self->members[i]);
+ }
MEM_VECTOR_CLEAR(self, reads);
MEM_VECTOR_CLEAR(self, writes);
MEM_VECTOR_CLEAR(self, life);
else
vtype = target->vtype;
- switch (vtype) {
- case TYPE_FLOAT:
#if 0
- if (what->vtype == TYPE_INTEGER)
- op = INSTR_CONV_ITOF;
- else
+ if (vtype == TYPE_FLOAT && what->vtype == TYPE_INTEGER)
+ op = INSTR_CONV_ITOF;
+ else if (vtype == TYPE_INTEGER && what->vtype == TYPE_FLOAT)
+ op = INSTR_CONV_FTOI;
#endif
- op = INSTR_STORE_F;
- break;
- case TYPE_VECTOR:
- op = INSTR_STORE_V;
- break;
- case TYPE_ENTITY:
- op = INSTR_STORE_ENT;
- break;
- case TYPE_STRING:
- op = INSTR_STORE_S;
- break;
- case TYPE_FIELD:
- op = INSTR_STORE_FLD;
- break;
-#if 0
- case TYPE_INTEGER:
- if (what->vtype == TYPE_INTEGER)
- op = INSTR_CONV_FTOI;
- else
- op = INSTR_STORE_I;
- break;
-#endif
- case TYPE_POINTER:
-#if 0
- op = INSTR_STORE_I;
-#else
- op = INSTR_STORE_ENT;
-#endif
- break;
- default:
- /* Unknown type */
- return false;
- }
+ op = type_store_instr[vtype];
+
return ir_block_create_store_op(self, op, target, what);
}
*/
vtype = what->vtype;
- switch (vtype) {
- case TYPE_FLOAT:
- op = INSTR_STOREP_F;
- break;
- case TYPE_VECTOR:
- op = INSTR_STOREP_V;
- break;
- case TYPE_ENTITY:
- op = INSTR_STOREP_ENT;
- break;
- case TYPE_STRING:
- op = INSTR_STOREP_S;
- break;
- case TYPE_FIELD:
- op = INSTR_STOREP_FLD;
- break;
-#if 0
- case TYPE_INTEGER:
- op = INSTR_STOREP_I;
- break;
-#endif
- case TYPE_POINTER:
-#if 0
- op = INSTR_STOREP_I;
-#else
- op = INSTR_STOREP_ENT;
-#endif
- break;
- default:
- /* Unknown type */
- return false;
- }
+ op = type_storep_instr[vtype];
+
return ir_block_create_store_op(self, op, target, what);
}
return ir_block_create_general_instr(self, label, opcode, left, right, ot);
}
+ir_value* ir_block_create_unary(ir_block *self,
+ const char *label, int opcode,
+ ir_value *operand)
+{
+ int ot = TYPE_FLOAT;
+ switch (opcode) {
+ case INSTR_NOT_F:
+ case INSTR_NOT_V:
+ case INSTR_NOT_S:
+ case INSTR_NOT_ENT:
+ case INSTR_NOT_FNC:
+#if 0
+ case INSTR_NOT_I:
+#endif
+ ot = TYPE_FLOAT;
+ break;
+ /* QC doesn't have other unary operations. We expect extensions to fill
+ * the above list, otherwise we assume out-type = in-type, eg for an
+ * unary minus
+ */
+ default:
+ ot = operand->vtype;
+ break;
+ };
+ if (ot == TYPE_VOID) {
+ /* The AST or parser were supposed to check this! */
+ return NULL;
+ }
+
+ /* let's use the general instruction creator and pass NULL for OPB */
+ return ir_block_create_general_instr(self, label, opcode, operand, NULL, ot);
+}
+
ir_value* ir_block_create_general_instr(ir_block *self, const char *label,
int op, ir_value *a, ir_value *b, int outype)
{
ir_value* ir_block_create_fieldaddress(ir_block *self, const char *label, ir_value *ent, ir_value *field)
{
+ ir_value *v;
+
/* Support for various pointer types todo if so desired */
if (ent->vtype != TYPE_ENTITY)
return NULL;
if (field->vtype != TYPE_FIELD)
return NULL;
- return ir_block_create_general_instr(self, label, INSTR_ADDRESS, ent, field, TYPE_POINTER);
+ v = ir_block_create_general_instr(self, label, INSTR_ADDRESS, ent, field, TYPE_POINTER);
+ v->fieldtype = field->fieldtype;
+ return v;
}
ir_value* ir_block_create_load_from_ent(ir_block *self, const char *label, ir_value *ent, ir_value *field, int outype)
if (v->writes[w]->_ops[0] == v)
v->writes[w]->_ops[0] = instr->_ops[0];
- if (old->store != store_value && old->store != store_local)
+ if (old->store != store_value && old->store != store_local && old->store != store_param)
{
/* If it originally wrote to a global we need to store the value
* there as welli
value = instr->_ops[o];
/* We only care about locals */
+ /* we also calculate parameter liferanges so that locals
+ * can take up parameter slots */
if (value->store != store_value &&
- value->store != store_local)
+ value->store != store_local &&
+ value->store != store_param)
continue;
/* read operands */
}
else
{
- prog_section_field fld;
-
- fld.name = global->code.name;
- fld.offset = code_fields_elements;
- fld.type = global->fieldtype;
-
- if (fld.type == TYPE_VOID) {
- printf("Field is missing a type: %s\n", global->name);
- return false;
- }
-
- if (code_fields_add(fld) < 0)
- return false;
-
- global->code.globaladdr = code_globals_add(fld.offset);
+ global->code.globaladdr = code_globals_add(0);
}
if (global->code.globaladdr < 0)
return false;
* come first: eg. optimize IFs without ELSE...
*/
- stmt.o1.u1 = instr->_ops[0]->code.globaladdr;
+ stmt.o1.u1 = ir_value_code_addr(instr->_ops[0]);
stmt.o2.u1 = 0;
stmt.o3.s1 = 0;
stmt.o3.u1 = 0;
stmt.opcode = type_store_instr[param->vtype];
- stmt.o1.u1 = param->code.globaladdr;
+ stmt.o1.u1 = ir_value_code_addr(param);
stmt.o2.u1 = OFS_PARM0 + 3 * p;
if (code_statements_add(stmt) < 0)
return false;
stmt.opcode = INSTR_CALL0 + instr->params_count;
if (stmt.opcode > INSTR_CALL8)
stmt.opcode = INSTR_CALL8;
- stmt.o1.u1 = instr->_ops[1]->code.globaladdr;
+ stmt.o1.u1 = ir_value_code_addr(instr->_ops[1]);
stmt.o2.u1 = 0;
stmt.o3.u1 = 0;
if (code_statements_add(stmt) < 0)
/* not to be kept in OFS_RETURN */
stmt.opcode = type_store_instr[retvalue->vtype];
stmt.o1.u1 = OFS_RETURN;
- stmt.o2.u1 = retvalue->code.globaladdr;
+ stmt.o2.u1 = ir_value_code_addr(retvalue);
stmt.o3.u1 = 0;
if (code_statements_add(stmt) < 0)
return false;
}
- return true;
+ continue;
}
if (instr->opcode == INSTR_STATE) {
/* This is the general order of operands */
if (instr->_ops[0])
- stmt.o3.u1 = instr->_ops[0]->code.globaladdr;
+ stmt.o3.u1 = ir_value_code_addr(instr->_ops[0]);
if (instr->_ops[1])
- stmt.o1.u1 = instr->_ops[1]->code.globaladdr;
+ stmt.o1.u1 = ir_value_code_addr(instr->_ops[1]);
if (instr->_ops[2])
- stmt.o2.u1 = instr->_ops[2]->code.globaladdr;
+ stmt.o2.u1 = ir_value_code_addr(instr->_ops[2]);
if (stmt.opcode == INSTR_RETURN || stmt.opcode == INSTR_DONE)
{
stmt.o1.u1 = stmt.o3.u1;
stmt.o3.u1 = 0;
}
- else if ((stmt.opcode >= INSTR_STORE_F &&
- stmt.opcode <= INSTR_STORE_FNC) ||
- (stmt.opcode >= INSTR_NOT_F &&
- stmt.opcode <= INSTR_NOT_FNC))
+ else if (stmt.opcode >= INSTR_STORE_F &&
+ stmt.opcode <= INSTR_STORE_FNC)
{
/* 2-operand instructions with A -> B */
stmt.o2.u1 = stmt.o3.u1;
for (i = 0;i < 8; ++i) {
if (i >= fun.nargs)
fun.argsize[i] = 0;
- else if (irfun->params[i] == TYPE_VECTOR)
- fun.argsize[i] = 3;
else
- fun.argsize[i] = 1;
+ fun.argsize[i] = type_sizeof[irfun->params[i]];
}
fun.firstlocal = code_globals_elements;
static bool ir_builder_gen_global(ir_builder *self, ir_value *global)
{
+ size_t i;
int32_t *iptr;
prog_section_def def;
}
case TYPE_VECTOR:
{
+ size_t d;
if (code_defs_add(def) < 0)
return false;
if (global->isconst) {
iptr = (int32_t*)&global->constval.vvec;
global->code.globaladdr = code_globals_add(iptr[0]);
- if (code_globals_add(iptr[1]) < 0 || code_globals_add(iptr[2]) < 0)
+ if (global->code.globaladdr < 0)
return false;
+ for (d = 1; d < type_sizeof[global->vtype]; ++d)
+ {
+ if (code_globals_add(iptr[d]) < 0)
+ return false;
+ }
} else {
global->code.globaladdr = code_globals_add(0);
- if (code_globals_add(0) < 0 || code_globals_add(0) < 0)
+ if (global->code.globaladdr < 0)
return false;
+ for (d = 1; d < type_sizeof[global->vtype]; ++d)
+ {
+ if (code_globals_add(0) < 0)
+ return false;
+ }
}
return global->code.globaladdr >= 0;
}
case TYPE_VARIANT:
/* assume biggest type */
global->code.globaladdr = code_globals_add(0);
- code_globals_add(0);
- code_globals_add(0);
+ for (i = 1; i < type_sizeof[TYPE_VARIANT]; ++i)
+ code_globals_add(0);
return true;
default:
/* refuse to create 'void' type or any other fancy business. */
}
}
+static bool ir_builder_gen_field(ir_builder *self, ir_value *field)
+{
+ prog_section_def def;
+ prog_section_field fld;
+
+ def.type = field->vtype;
+ def.offset = code_globals_elements;
+ def.name = field->code.name = code_genstring(field->name);
+
+ if (code_defs_add(def) < 0)
+ return false;
+
+ fld.name = def.name;
+ fld.offset = code_fields_elements;
+ fld.type = field->fieldtype;
+
+ if (fld.type == TYPE_VOID) {
+ printf("field is missing a type: %s - don't know its size\n", field->name);
+ return false;
+ }
+
+ if (code_fields_add(fld) < 0)
+ return false;
+
+ if (!code_globals_add(code_alloc_field(type_sizeof[field->fieldtype])))
+ return false;
+
+ field->code.globaladdr = code_globals_add(fld.offset);
+ return field->code.globaladdr >= 0;
+}
+
bool ir_builder_generate(ir_builder *self, const char *filename)
{
size_t i;
code_init();
+ for (i = 0; i < self->fields_count; ++i)
+ {
+ if (!ir_builder_gen_field(self, self->fields[i])) {
+ return false;
+ }
+ }
+
for (i = 0; i < self->globals_count; ++i)
{
if (!ir_builder_gen_global(self, self->globals[i])) {
int (*oprintf)(const char*, ...))
{
size_t i;
+ if (f->builtin != 0) {
+ oprintf("%sfunction %s = builtin %i\n", ind, f->name, -f->builtin);
+ return;
+ }
oprintf("%sfunction %s\n", ind, f->name);
strncat(ind, "\t", IND_BUFSZ);
if (f->locals_count)