self->expression.codegen = codegen;
self->expression.vtype = TYPE_VOID;
self->expression.next = NULL;
+ self->expression.outl = NULL;
+ self->expression.outr = NULL;
MEM_VECTOR_INIT(&self->expression, params);
}
return cp;
}
+static ast_expression* ast_shallow_type(lex_ctx ctx, int vtype)
+{
+ ast_instantiate(ast_expression, ctx, ast_expression_delete_full);
+ self->expression.codegen = NULL;
+ self->expression.next = NULL;
+ self->expression.vtype = vtype;
+ return self;
+}
+
static ast_expression* ast_type_copy(lex_ctx ctx, const ast_expression *ex)
{
size_t i;
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_binstore* ast_binstore_new(lex_ctx ctx, int storop, int op,
+ ast_expression* left, ast_expression* right)
+{
+ ast_instantiate(ast_binstore, ctx, ast_binstore_delete);
+ ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_binstore_codegen);
+
+ self->opstore = storop;
+ self->opbin = op;
+ self->dest = left;
+ self->source = right;
+
+ self->expression.vtype = left->expression.vtype;
+ if (left->expression.next) {
+ self->expression.next = ast_type_copy(ctx, left);
+ if (!self->expression.next) {
+ ast_delete(self);
+ return NULL;
+ }
+ }
+ else
+ self->expression.next = NULL;
+
+ return self;
+}
+
+void ast_binstore_delete(ast_binstore *self)
+{
+ ast_unref(self->dest);
+ ast_unref(self->source);
+ ast_expression_delete((ast_expression*)self);
+ mem_d(self);
+}
+
ast_unary* ast_unary_new(lex_ctx ctx, int op,
ast_expression *expr)
{
return NULL;
}
+ if (owner->expression.vtype != TYPE_VECTOR &&
+ owner->expression.vtype != TYPE_FIELD) {
+ printf("ast_member on an invalid owner of type %i\n", (int)owner->expression.vtype);
+ 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;
+ if (owner->expression.vtype == TYPE_VECTOR) {
+ self->expression.vtype = TYPE_FLOAT;
+ self->expression.next = NULL;
+ } else {
+ self->expression.vtype = TYPE_FIELD;
+ self->expression.next = ast_shallow_type(ctx, TYPE_FLOAT);
+ }
self->owner = owner;
self->field = field;
return true;
}
+ if (self->expression.vtype == TYPE_FIELD) {
+ v = ir_builder_create_field(ir, self->name, self->expression.next->expression.vtype);
+ if (!v)
+ return false;
+ if (self->isconst) {
+ printf("TODO: constant field pointers with value\n");
+ goto error;
+ }
+ self->ir_v = v;
+ return true;
+ }
+
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)
* of the form: (a, b, c) = x should not assign to c...
*/
(void)lvalue;
+ if (self->expression.outr) {
+ *out = self->expression.outr;
+ return true;
+ }
/* output is NULL at first, we'll have each expression
* assign to out output, thus, a comma-operator represention
return false;
}
+ self->expression.outr = *out;
+
return true;
}
ast_expression_codegen *cgen;
ir_value *left, *right;
+ if (lvalue && self->expression.outl) {
+ *out = self->expression.outl;
+ return true;
+ }
+
+ if (!lvalue && self->expression.outr) {
+ *out = self->expression.outr;
+ return true;
+ }
+
cgen = self->dest->expression.codegen;
/* lvalue! */
if (!(*cgen)((ast_expression*)(self->dest), func, true, &left))
return false;
+ self->expression.outl = left;
cgen = self->source->expression.codegen;
/* rvalue! */
if (!ir_block_create_store_op(func->curblock, self->op, left, right))
return false;
+ self->expression.outr = right;
/* Theoretically, an assinment returns its left side as an
* lvalue, if we don't need an lvalue though, we return
/* In the context of a binary operation, we can disregard
* the lvalue flag.
*/
- (void)lvalue;
+ (void)lvalue;
+ if (self->expression.outr) {
+ *out = self->expression.outr;
+ return true;
+ }
cgen = self->left->expression.codegen;
/* lvalue! */
self->op, left, right);
if (!*out)
return false;
+ self->expression.outr = *out;
+
+ return true;
+}
+
+bool ast_binstore_codegen(ast_binstore *self, ast_function *func, bool lvalue, ir_value **out)
+{
+ ast_expression_codegen *cgen;
+ ir_value *leftl, *leftr, *right, *bin;
+
+ if (lvalue && self->expression.outl) {
+ *out = self->expression.outl;
+ return true;
+ }
+
+ if (!lvalue && self->expression.outr) {
+ *out = self->expression.outr;
+ return true;
+ }
+
+ /* for a binstore we need both an lvalue and an rvalue for the left side */
+ /* rvalue of destination! */
+ cgen = self->dest->expression.codegen;
+ if (!(*cgen)((ast_expression*)(self->dest), func, true, &leftr))
+ return false;
+
+ /* source as rvalue only */
+ cgen = self->source->expression.codegen;
+ if (!(*cgen)((ast_expression*)(self->source), func, false, &right))
+ return false;
+
+ /* now the binary */
+ bin = ir_block_create_binop(func->curblock, ast_function_label(func, "binst"),
+ self->opbin, leftr, right);
+ self->expression.outr = bin;
+
+ /* now store them */
+ cgen = self->dest->expression.codegen;
+ /* lvalue of destination */
+ if (!(*cgen)((ast_expression*)(self->dest), func, true, &leftl))
+ return false;
+ self->expression.outl = leftl;
+
+ if (!ir_block_create_store_op(func->curblock, self->opstore, leftl, bin))
+ return false;
+ self->expression.outr = bin;
+
+ /* Theoretically, an assinment returns its left side as an
+ * lvalue, if we don't need an lvalue though, we return
+ * the right side as an rvalue, otherwise we have to
+ * somehow know whether or not we need to dereference the pointer
+ * on the left side - that is: OP_LOAD if it was an address.
+ * Also: in original QC we cannot OP_LOADP *anyway*.
+ */
+ *out = (lvalue ? leftl : bin);
return true;
}
* the lvalue flag.
*/
(void)lvalue;
+ if (self->expression.outr) {
+ *out = self->expression.outr;
+ return true;
+ }
cgen = self->operand->expression.codegen;
/* lvalue! */
self->op, operand);
if (!*out)
return false;
+ self->expression.outr = *out;
return true;
}
* the lvalue flag.
*/
(void)lvalue;
+ if (self->expression.outr) {
+ printf("internal error: ast_return cannot be reused, it bears no result!\n");
+ return false;
+ }
+ self->expression.outr = (ir_value*)1;
cgen = self->operand->expression.codegen;
/* lvalue! */
* value in a temp.
*/
+ if (lvalue && self->expression.outl) {
+ *out = self->expression.outl;
+ return true;
+ }
+
+ if (!lvalue && self->expression.outr) {
+ *out = self->expression.outr;
+ return true;
+ }
+
cgen = self->entity->expression.codegen;
if (!(*cgen)((ast_expression*)(self->entity), func, false, &ent))
return false;
if (!*out)
return false;
+ if (lvalue)
+ self->expression.outl = *out;
+ else
+ self->expression.outr = *out;
+
/* Hm that should be it... */
return true;
}
ast_expression_codegen *cgen;
ir_value *vec;
+ /* in QC this is always an lvalue */
+ (void)lvalue;
+ if (self->expression.outl) {
+ *out = self->expression.outl;
+ return true;
+ }
+
cgen = self->owner->expression.codegen;
if (!(*cgen)((ast_expression*)(self->owner), func, true, &vec))
return false;
- if (vec->vtype != TYPE_VECTOR)
+ if (vec->vtype != TYPE_VECTOR &&
+ !(vec->vtype == TYPE_FIELD && self->owner->expression.next->expression.vtype == TYPE_VECTOR))
+ {
return false;
+ }
*out = ir_value_vector_member(vec, self->field);
+ self->expression.outl = *out;
return (*out != NULL);
}
(void)out;
(void)lvalue;
+ if (self->expression.outr) {
+ printf("internal error: ast_ifthen cannot be reused, it bears no result!\n");
+ return false;
+ }
+ self->expression.outr = (ir_value*)1;
+
/* generate the condition */
func->curblock = cond;
cgen = self->cond->expression.codegen;
ir_block *onfalse;
ir_block *merge;
+ /* Ternary can never create an lvalue... */
+ if (lvalue)
+ return false;
+
/* In theory it shouldn't be possible to pass through a node twice, but
* in case we add any kind of optimization pass for the AST itself, it
* may still happen, thus we remember a created ir_value and simply return one
return true;
}
- /* Ternary can never create an lvalue... */
- if (lvalue)
- return false;
-
/* In the following, contraty to ast_ifthen, we assume both paths exist. */
/* generate the condition */
(void)lvalue;
(void)out;
+ if (self->expression.outr) {
+ printf("internal error: ast_loop cannot be reused, it bears no result!\n");
+ return false;
+ }
+ self->expression.outr = (ir_value*)1;
+
/* NOTE:
* Should we ever need some kind of block ordering, better make this function
* move blocks around than write a block ordering algorithm later... after all
ir_value *funval = NULL;
- /* return values are never rvalues */
+ /* return values are never lvalues */
(void)lvalue;
+ if (self->expression.outr) {
+ *out = self->expression.outr;
+ return true;
+ }
+
cgen = self->func->expression.codegen;
if (!(*cgen)((ast_expression*)(self->func), func, false, &funval))
return false;
}
*out = ir_call_value(callinstr);
+ self->expression.outr = *out;
MEM_VECTOR_CLEAR(¶ms, v);
return true;