]> git.xonotic.org Git - xonotic/gmqcc.git/commitdiff
ast/ir support for unary instructions
authorWolfgang Bumiller <wolfgang.linux@bumiller.com>
Thu, 26 Jul 2012 18:45:18 +0000 (20:45 +0200)
committerWolfgang Bumiller <wolfgang.linux@bumiller.com>
Thu, 26 Jul 2012 18:45:18 +0000 (20:45 +0200)
ast.c
ast.h
ir.c
ir.h

diff --git a/ast.c b/ast.c
index 404df573c17ed046b8f919f3f0a6687979541638..70bc0374fa8c883df19d6ae6d6aea29491376e6a 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -181,6 +181,25 @@ void ast_binary_delete(ast_binary *self)
     mem_d(self);
 }
 
+ast_unary* ast_unary_new(lex_ctx ctx, int op,
+                         ast_expression *expr)
+{
+    ast_instantiate(ast_unary, ctx, ast_unary_delete);
+    ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_unary_codegen);
+
+    self->op = op;
+    self->operand = expr;
+
+    return self;
+}
+
+void ast_unary_delete(ast_unary *self)
+{
+    ast_unref(self->operand);
+    ast_expression_delete((ast_expression*)self);
+    mem_d(self);
+}
+
 ast_entfield* ast_entfield_new(lex_ctx ctx, ast_expression *entity, ast_expression *field)
 {
     const ast_expression *outtype;
@@ -751,6 +770,29 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va
     return true;
 }
 
+bool ast_unary_codegen(ast_unary *self, ast_function *func, bool lvalue, ir_value **out)
+{
+    ast_expression_codegen *cgen;
+    ir_value *operand;
+
+    /* In the context of a unary operation, we can disregard
+     * the lvalue flag.
+     */
+    (void)lvalue;
+
+    cgen = self->operand->expression.codegen;
+    /* lvalue! */
+    if (!(*cgen)((ast_expression*)(self->operand), func, false, &operand))
+        return false;
+
+    *out = ir_block_create_unary(func->curblock, ast_function_label(func, "bin"),
+                                 self->op, operand);
+    if (!*out)
+        return false;
+
+    return true;
+}
+
 bool ast_entfield_codegen(ast_entfield *self, ast_function *func, bool lvalue, ir_value **out)
 {
     ast_expression_codegen *cgen;
diff --git a/ast.h b/ast.h
index 8ae190d2ff1fb70b700a758760c08a885ed876ae..663099d4efa46dbe73b81f2c85cd11b6af47a5ff 100644 (file)
--- a/ast.h
+++ b/ast.h
@@ -41,6 +41,8 @@ typedef struct ast_ifthen_s     ast_ifthen;
 typedef struct ast_ternary_s    ast_ternary;
 typedef struct ast_loop_s       ast_loop;
 typedef struct ast_call_s       ast_call;
+typedef struct ast_unary_s      ast_unary;
+typedef struct ast_return_s     ast_return;
 
 /* Node interface with common components
  */
@@ -148,6 +150,24 @@ void ast_binary_delete(ast_binary*);
 
 bool ast_binary_codegen(ast_binary*, ast_function*, bool lvalue, ir_value**);
 
+/* Unary
+ *
+ * Regular unary expressions: not,neg
+ */
+struct ast_unary_s
+{
+    ast_expression_common expression;
+
+    int             op;
+    ast_expression *operand;
+};
+ast_unary* ast_unary_new(lex_ctx    ctx,
+                         int        op,
+                         ast_expression *expr);
+void ast_unary_delete(ast_unary*);
+
+bool ast_unary_codegen(ast_unary*, ast_function*, bool lvalue, ir_value**);
+
 /* Entity-field
  *
  * This must do 2 things:
diff --git a/ir.c b/ir.c
index 2a5018b0cb94c6441047bac8d256f2f06e8d3756..7508f908ea23d4ba1de8ef6fe91dc31654195182 100644 (file)
--- a/ir.c
+++ b/ir.c
@@ -1169,6 +1169,39 @@ ir_value* ir_block_create_binop(ir_block *self,
     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)
 {
diff --git a/ir.h b/ir.h
index fb0f699283dc9036aa16111359c184af6835875b..9eab51f73f5d9282e4597986badb38ff85fb6268 100644 (file)
--- a/ir.h
+++ b/ir.h
@@ -177,6 +177,8 @@ MEM_VECTOR_PROTO_ALL(ir_block, ir_block*, entries);
 
 ir_value* ir_block_create_binop(ir_block*, const char *label, int op,
                                 ir_value *left, ir_value *right);
+ir_value* ir_block_create_unary(ir_block*, const char *label, int op,
+                                ir_value *operand);
 bool GMQCC_WARN ir_block_create_store_op(ir_block*, int op, ir_value *target, ir_value *what);
 bool GMQCC_WARN ir_block_create_store(ir_block*, ir_value *target, ir_value *what);
 bool GMQCC_WARN ir_block_create_storep(ir_block*, ir_value *target, ir_value *what);