self->left = left;
self->right = right;
+ if (op >= INSTR_EQ_F && op <= INSTR_GT)
+ self->expression.vtype = TYPE_FLOAT;
+ else if (op == INSTR_AND || op == INSTR_OR ||
+ op == INSTR_BITAND || op == INSTR_BITOR)
+ self->expression.vtype = TYPE_FLOAT;
+ else if (op == INSTR_MUL_VF || op == INSTR_MUL_FV)
+ self->expression.vtype = TYPE_VECTOR;
+ else if (op == INSTR_MUL_V)
+ self->expression.vtype = TYPE_FLOAT;
+ else
+ self->expression.vtype = left->expression.vtype;
+
return self;
}
mem_d(self);
}
+ ast_member* ast_member_new(lex_ctx ctx, ast_expression *owner, unsigned int field)
+ {
+ ast_instantiate(ast_member, ctx, ast_member_delete);
+ if (field >= 3) {
+ mem_d(self);
+ return NULL;
+ }
+
+ ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_member_codegen);
+
+ self->expression.vtype = TYPE_FLOAT;
+ self->expression.next = NULL;
+
+ self->owner = owner;
+ self->field = field;
+
+ return self;
+ }
+
+ void ast_member_delete(ast_member *self)
+ {
+ ast_unref(self->owner);
+ ast_expression_delete((ast_expression*)self);
+ mem_d(self);
+ }
+
ast_ifthen* ast_ifthen_new(lex_ctx ctx, ast_expression *cond, ast_expression *ontrue, ast_expression *onfalse)
{
ast_instantiate(ast_ifthen, ctx, ast_ifthen_delete);
}
v = ir_builder_create_global(ir, self->name, self->expression.vtype);
- if (!v)
+ if (!v) {
+ printf("ir_builder_create_global failed\n");
return false;
+ }
if (self->isconst) {
switch (self->expression.vtype)
return true;
}
+ bool ast_member_codegen(ast_member *self, ast_function *func, bool lvalue, ir_value **out)
+ {
+ ast_expression_codegen *cgen;
+ ir_value *vec, *field;
+
+ cgen = self->owner->expression.codegen;
+ if (!(*cgen)((ast_expression*)(self->owner), func, true, &vec))
+ return false;
+
+ if (vec->vtype != TYPE_VECTOR)
+ return false;
+
+ *out = ir_value_vector_member(vec, self->field);
+
+ return (*out != NULL);
+ }
+
bool ast_ifthen_codegen(ast_ifthen *self, ast_function *func, bool lvalue, ir_value **out)
{
ast_expression_codegen *cgen;
* Type sizes used at multiple points in the IR codegen
*/
+const char *type_name[TYPE_COUNT] = {
+ "void",
+ "string",
+ "float",
+ "vector",
+ "entity",
+ "field",
+ "function",
+ "pointer",
+#if 0
+ "integer",
+#endif
+ "quaternion",
+ "matrix",
+ "variant"
+};
+
size_t type_sizeof[TYPE_COUNT] = {
1, /* TYPE_VOID */
1, /* TYPE_STRING */
#if 0
1, /* TYPE_INTEGER */
#endif
- 3, /* TYPE_VARIANT */
+ 4, /* TYPE_QUATERNION */
+ 16, /* TYPE_MATRIX */
+ 16, /* TYPE_VARIANT */
};
uint16_t type_store_instr[TYPE_COUNT] = {
INSTR_STORE_FNC,
INSTR_STORE_ENT, /* should use I */
#if 0
- INSTR_STORE_ENT, /* integer type */
+ INSTR_STORE_I, /* integer type */
#endif
- INSTR_STORE_V, /* variant, should never be accessed */
+ INSTR_STORE_Q,
+ INSTR_STORE_M,
+
+ INSTR_STORE_M, /* variant, should never be accessed */
};
uint16_t type_storep_instr[TYPE_COUNT] = {
#if 0
INSTR_STOREP_ENT, /* integer type */
#endif
- INSTR_STOREP_V, /* variant, should never be accessed */
+ INSTR_STOREP_Q,
+ INSTR_STOREP_M,
+
+ INSTR_STOREP_M, /* variant, should never be accessed */
};
MEM_VEC_FUNCTIONS(ir_value_vector, ir_value*, v)
ir_value* ir_builder_create_global(ir_builder *self, const char *name, int vtype)
{
- ir_value *ve = ir_builder_get_global(self, name);
- if (ve) {
- return NULL;
+ ir_value *ve;
+
+ if (name && name[0] != '#')
+ {
+ ve = ir_builder_get_global(self, name);
+ if (ve) {
+ return NULL;
+ }
}
ve = ir_value_var(name, store_global, vtype);
*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);
return true;
}
+bool ir_value_set_quaternion(ir_value *self, quaternion v)
+{
+ if (self->vtype != TYPE_QUATERNION)
+ return false;
+ memcpy(&self->constval.vquat, v, sizeof(self->constval.vquat));
+ self->isconst = true;
+ return true;
+}
+
+bool ir_value_set_matrix(ir_value *self, matrix v)
+{
+ if (self->vtype != TYPE_MATRIX)
+ return false;
+ memcpy(&self->constval.vmat, v, sizeof(self->constval.vmat));
+ self->isconst = true;
+ return true;
+}
+
bool ir_value_set_string(ir_value *self, const char *str)
{
if (self->vtype != TYPE_STRING)
vtype = what->vtype;
op = type_storep_instr[vtype];
-
return ir_block_create_store_op(self, op, target, what);
}
case TYPE_POINTER: op = INSTR_LOAD_I; break;
case TYPE_INTEGER: op = INSTR_LOAD_I; break;
#endif
+ case TYPE_QUATERNION: op = INSTR_LOAD_Q; break;
+ case TYPE_MATRIX: op = INSTR_LOAD_M; break;
default:
return NULL;
}
case TYPE_VECTOR:
op = INSTR_MUL_V;
break;
+ case TYPE_QUATERNION:
+ op = INSTR_MUL_Q;
+ break;
+ case TYPE_MATRIX:
+ op = INSTR_MUL_M;
+ break;
}
} else {
if ( (l == TYPE_VECTOR && r == TYPE_FLOAT) )
op = INSTR_MUL_VF;
else if ( (l == TYPE_FLOAT && r == TYPE_VECTOR) )
op = INSTR_MUL_FV;
+ else if ( (l == TYPE_QUATERNION && r == TYPE_FLOAT) )
+ op = INSTR_MUL_QF;
+ else if ( (l == TYPE_MATRIX && r == TYPE_FLOAT) )
+ op = INSTR_MUL_MF;
#if 0
else if ( (l == TYPE_VECTOR && r == TYPE_INTEGER) )
op = INSTR_MUL_VI;
* 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;
/* 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)
{
return global->code.globaladdr >= 0;
}
case TYPE_VECTOR:
+ case TYPE_QUATERNION:
+ case TYPE_MATRIX:
{
size_t d;
if (code_defs_add(def) < 0)
{
if (v->isconst) {
switch (v->vtype) {
+ default:
case TYPE_VOID:
oprintf("(void)");
break;
char *vstring;
struct ir_value_s *vpointer;
struct ir_function_s *vfunc;
+ quaternion vquat;
+ matrix vmat;
} constval;
struct {
int32_t name;
/* filled by the local-allocator */
int32_t local;
+ /* added for members */
+ int32_t addroffset;
} code;
+ /* for acessing vectors */
+ struct ir_value_s *members[3];
+
/* For the temp allocator */
MEM_VECTOR_MAKE(ir_life_entry_t, life);
} ir_value;
+ int32_t ir_value_code_addr(const ir_value*);
+
/* ir_value can be a variable, or created by an operation */
ir_value* ir_value_var(const char *name, int st, int vtype);
/* if a result of an operation: the function should store
ir_value* ir_value_out(struct ir_function_s *owner, const char *name, int st, int vtype);
void ir_value_delete(ir_value*);
void ir_value_set_name(ir_value*, const char *name);
+ ir_value* ir_value_vector_member(ir_value*, unsigned int member);
MEM_VECTOR_PROTO_ALL(ir_value, struct ir_instr_s*, reads);
MEM_VECTOR_PROTO_ALL(ir_value, struct ir_instr_s*, writes);
bool GMQCC_WARN ir_value_set_vector(ir_value*, vector v);
/*bool ir_value_set_pointer_v(ir_value*, ir_value* p); */
/*bool ir_value_set_pointer_i(ir_value*, int i); */
+bool GMQCC_WARN ir_value_set_quaternion(ir_value*, quaternion v);
+bool GMQCC_WARN ir_value_set_matrix(ir_value*, matrix v);
MEM_VECTOR_PROTO(ir_value, ir_life_entry_t, life);
/* merge an instruction into the life-range */