]> de.git.xonotic.org Git - xonotic/gmqcc.git/commitdiff
Merging master and adapting _MEM_* on new mem-vector functions
authorWolfgang Bumiller <wolfgang.linux@bumiller.com>
Fri, 27 Jul 2012 17:13:03 +0000 (19:13 +0200)
committerWolfgang Bumiller <wolfgang.linux@bumiller.com>
Fri, 27 Jul 2012 17:13:03 +0000 (19:13 +0200)
ast.c
ast.h
gmqcc.h
ir.c
ir.h
test/ast-macros.h
test/ast-test.c

diff --git a/ast.c b/ast.c
index 49446a111d7035085c90981018c91b02e48f5e06..61b89e4caee5d78be54d00d201b126d6ac7542df 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -57,12 +57,18 @@ static void ast_expression_init(ast_expression *self,
     self->expression.codegen = codegen;
     self->expression.vtype   = TYPE_VOID;
     self->expression.next    = NULL;
+    MEM_VECTOR_INIT(&self->expression, params);
 }
 
 static void ast_expression_delete(ast_expression *self)
 {
+    size_t i;
     if (self->expression.next)
         ast_delete(self->expression.next);
+    for (i = 0; i < self->expression.params_count; ++i) {
+        ast_delete(self->expression.params[i]);
+    }
+    MEM_VECTOR_CLEAR(&self->expression, params);
 }
 
 static void ast_expression_delete_full(ast_expression *self)
@@ -71,9 +77,26 @@ static void ast_expression_delete_full(ast_expression *self)
     mem_d(self);
 }
 
+MEM_VEC_FUNCTIONS(ast_expression_common, ast_value*, params)
+
+static ast_expression* ast_type_copy(lex_ctx ctx, const ast_expression *ex);
+static ast_value* ast_value_copy(const ast_value *self)
+{
+    ast_value *cp = ast_value_new(self->expression.node.context, self->name, self->expression.vtype);
+    if (self->expression.next) {
+        cp->expression.next = ast_type_copy(self->expression.node.context, self->expression.next);
+        if (!cp->expression.next) {
+            ast_value_delete(cp);
+            return NULL;
+        }
+    }
+    return cp;
+}
+
 static ast_expression* ast_type_copy(lex_ctx ctx, const ast_expression *ex)
 {
-    const ast_expression_common *cpex;
+    size_t i;
+    const ast_expression_common *fromex;
     ast_expression_common *selfex;
 
     if (!ex)
@@ -82,23 +105,32 @@ static ast_expression* ast_type_copy(lex_ctx ctx, const ast_expression *ex)
     {
         ast_instantiate(ast_expression, ctx, ast_expression_delete_full);
 
-        cpex   = &ex->expression;
+        fromex   = &ex->expression;
         selfex = &self->expression;
 
-        selfex->vtype = cpex->vtype;
-        if (cpex->next)
+        /* This may never be codegen()d */
+        selfex->codegen = NULL;
+
+        selfex->vtype = fromex->vtype;
+        if (fromex->next)
         {
-            selfex->next = ast_type_copy(ctx, cpex->next);
+            selfex->next = ast_type_copy(ctx, fromex->next);
             if (!selfex->next) {
-                mem_d(self);
+                ast_expression_delete_full(self);
                 return NULL;
             }
         }
         else
             selfex->next = NULL;
 
-        /* This may never be codegen()d */
-        selfex->codegen = NULL;
+        for (i = 0; i < fromex->params_count; ++i) {
+            ast_value *v = ast_value_copy(fromex->params[i]);
+            if (!v || !ast_expression_common_params_add(selfex, v)) {
+                ast_expression_delete_full(self);
+                return NULL;
+            }
+        }
+
         return self;
     }
 }
@@ -113,7 +145,6 @@ ast_value* ast_value_new(lex_ctx ctx, const char *name, int t)
     self->name = name ? util_strdup(name) : NULL;
     self->expression.vtype = t;
     self->expression.next  = NULL;
-    MEM_VECTOR_INIT(self, params);
     self->isconst = false;
     memset(&self->constval, 0, sizeof(self->constval));
 
@@ -121,16 +152,11 @@ ast_value* ast_value_new(lex_ctx ctx, const char *name, int t)
 
     return self;
 }
-MEM_VEC_FUNCTIONS(ast_value, ast_value*, params)
 
 void ast_value_delete(ast_value* self)
 {
-    size_t i;
     if (self->name)
         mem_d((void*)self->name);
-    for (i = 0; i < self->params_count; ++i)
-        ast_value_delete(self->params[i]); /* delete, the ast_function is expected to die first */
-    MEM_VECTOR_CLEAR(self, params);
     if (self->isconst) {
         switch (self->expression.vtype)
         {
@@ -152,6 +178,11 @@ void ast_value_delete(ast_value* self)
     mem_d(self);
 }
 
+bool GMQCC_WARN ast_value_params_add(ast_value *self, ast_value *p)
+{
+    return ast_expression_common_params_add(&self->expression, p);
+}
+
 bool ast_value_set_name(ast_value *self, const char *name)
 {
     if (self->name)
@@ -181,6 +212,42 @@ 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_return* ast_return_new(lex_ctx ctx, ast_expression *expr)
+{
+    ast_instantiate(ast_return, ctx, ast_return_delete);
+    ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_return_codegen);
+
+    self->operand = expr;
+
+    return self;
+}
+
+void ast_return_delete(ast_return *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;
@@ -308,6 +375,34 @@ void ast_loop_delete(ast_loop *self)
     mem_d(self);
 }
 
+ast_call* ast_call_new(lex_ctx ctx,
+                       ast_expression *funcexpr)
+{
+    ast_instantiate(ast_call, ctx, ast_call_delete);
+    ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_call_codegen);
+
+    MEM_VECTOR_INIT(self, params);
+
+    self->func = funcexpr;
+
+    return self;
+}
+MEM_VEC_FUNCTIONS(ast_call, ast_expression*, params)
+
+void ast_call_delete(ast_call *self)
+{
+    size_t i;
+    for (i = 0; i < self->params_count; ++i)
+        ast_unref(self->params[i]);
+    MEM_VECTOR_CLEAR(self, params);
+
+    if (self->func)
+        ast_unref(self->func);
+
+    ast_expression_delete((ast_expression*)self);
+    mem_d(self);
+}
+
 ast_store* ast_store_new(lex_ctx ctx, int op,
                          ast_value *dest, ast_expression *source)
 {
@@ -356,6 +451,19 @@ void ast_block_delete(ast_block *self)
     mem_d(self);
 }
 
+bool ast_block_set_type(ast_block *self, ast_expression *from)
+{
+    if (self->expression.next)
+        ast_delete(self->expression.next);
+    self->expression.vtype = from->expression.vtype;
+    if (from->expression.next) {
+        self->expression.next = ast_type_copy(self->expression.node.context, from->expression.next);
+        if (!self->expression.next)
+            return false;
+    }
+    return true;
+}
+
 ast_function* ast_function_new(lex_ctx ctx, const char *name, ast_value *vtype)
 {
     ast_instantiate(ast_function, ctx, ast_function_delete);
@@ -373,6 +481,7 @@ ast_function* ast_function_new(lex_ctx ctx, const char *name, ast_value *vtype)
     MEM_VECTOR_INIT(self, blocks);
 
     self->labelcount = 0;
+    self->builtin = 0;
 
     self->ir_func = NULL;
     self->curblock = NULL;
@@ -457,8 +566,10 @@ bool ast_value_codegen(ast_value *self, ast_function *func, bool lvalue, ir_valu
      * and the ast-user should take care of ast_global_codegen to be used
      * on all the globals.
      */
-    if (!self->ir_v)
+    if (!self->ir_v) {
+        printf("ast_value used before generated (%s)\n", self->name);
         return false;
+    }
     *out = self->ir_v;
     return true;
 }
@@ -468,11 +579,12 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir)
     ir_value *v = NULL;
     if (self->isconst && self->expression.vtype == TYPE_FUNCTION)
     {
-        ir_function *func = ir_builder_create_function(ir, self->name);
+        ir_function *func = ir_builder_create_function(ir, self->name, self->expression.next->expression.vtype);
         if (!func)
             return false;
 
         self->constval.vfunc->ir_func = func;
+        self->ir_v = func->value;
         /* The function is filled later on ast_function_codegen... */
         return true;
     }
@@ -497,10 +609,11 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir)
                     goto error;
                 break;
             case TYPE_FUNCTION:
+                printf("global of type function not properly generated\n");
+                goto error;
                 /* Cannot generate an IR value for a function,
                  * need a pointer pointing to a function rather.
                  */
-                goto error;
             default:
                 printf("TODO: global constant type %i\n", self->expression.vtype);
                 break;
@@ -516,7 +629,7 @@ error: /* clean up */
     return false;
 }
 
-bool ast_local_codegen(ast_value *self, ir_function *func)
+bool ast_local_codegen(ast_value *self, ir_function *func, bool param)
 {
     ir_value *v = NULL;
     if (self->isconst && self->expression.vtype == TYPE_FUNCTION)
@@ -527,7 +640,7 @@ bool ast_local_codegen(ast_value *self, ir_function *func)
         return false;
     }
 
-    v = ir_function_create_local(func, self->name, self->expression.vtype);
+    v = ir_function_create_local(func, self->name, self->expression.vtype, param);
     if (!v)
         return false;
 
@@ -568,6 +681,7 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir)
 {
     ir_function *irf;
     ir_value    *dummy;
+    ast_expression_common *ec;
     size_t    i;
 
     irf = self->ir_func;
@@ -576,6 +690,23 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir)
         return false;
     }
 
+    /* fill the parameter list */
+    ec = &self->vtype->expression;
+    for (i = 0; i < ec->params_count; ++i)
+    {
+        if (!ir_function_params_add(irf, ec->params[i]->expression.vtype))
+            return false;
+        if (!self->builtin) {
+            if (!ast_local_codegen(ec->params[i], self->ir_func, true))
+                return false;
+        }
+    }
+
+    if (self->builtin) {
+        irf->builtin = self->builtin;
+        return true;
+    }
+
     self->curblock = ir_function_create_block(irf, "entry");
     if (!self->curblock)
         return false;
@@ -591,7 +722,9 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir)
     {
         if (!self->vtype->expression.next ||
             self->vtype->expression.next->expression.vtype == TYPE_VOID)
+        {
             return ir_block_create_return(self->curblock, NULL);
+        }
         else
         {
             /* error("missing return"); */
@@ -628,7 +761,7 @@ bool ast_block_codegen(ast_block *self, ast_function *func, bool lvalue, ir_valu
     /* generate locals */
     for (i = 0; i < self->locals_count; ++i)
     {
-        if (!ast_local_codegen(self->locals[i], func->ir_func))
+        if (!ast_local_codegen(self->locals[i], func->ir_func, false))
             return false;
     }
 
@@ -700,6 +833,50 @@ 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, "unary"),
+                                 self->op, operand);
+    if (!*out)
+        return false;
+
+    return true;
+}
+
+bool ast_return_codegen(ast_return *self, ast_function *func, bool lvalue, ir_value **out)
+{
+    ast_expression_codegen *cgen;
+    ir_value *operand;
+
+    /* In the context of a return 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;
+
+    if (!ir_block_create_return(func->curblock, operand))
+        return false;
+
+    return true;
+}
+
 bool ast_entfield_codegen(ast_entfield *self, ast_function *func, bool lvalue, ir_value **out)
 {
     ast_expression_codegen *cgen;
@@ -1148,3 +1325,56 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value
 
     return true;
 }
+
+bool ast_call_codegen(ast_call *self, ast_function *func, bool lvalue, ir_value **out)
+{
+    ast_expression_codegen *cgen;
+    ir_value_vector         params;
+    ir_instr               *callinstr;
+    size_t i;
+
+    ir_value *funval = NULL;
+
+    /* return values are never rvalues */
+    (void)lvalue;
+
+    cgen = self->func->expression.codegen;
+    if (!(*cgen)((ast_expression*)(self->func), func, false, &funval))
+        return false;
+    if (!funval)
+        return false;
+
+    MEM_VECTOR_INIT(&params, v);
+
+    /* parameters */
+    for (i = 0; i < self->params_count; ++i)
+    {
+        ir_value *param;
+        ast_expression *expr = self->params[i];
+
+        cgen = expr->expression.codegen;
+        if (!(*cgen)(expr, func, false, &param))
+            goto error;
+        if (!param)
+            goto error;
+        if (!ir_value_vector_v_add(&params, param))
+            goto error;
+    }
+
+    callinstr = ir_block_create_call(func->curblock, ast_function_label(func, "call"), funval);
+    if (!callinstr)
+        goto error;
+
+    for (i = 0; i < params.v_count; ++i) {
+        if (!ir_call_param(callinstr, params.v[i]))
+            goto error;
+    }
+
+    *out = ir_call_value(callinstr);
+
+    MEM_VECTOR_CLEAR(&params, v);
+    return true;
+error:
+    MEM_VECTOR_CLEAR(&params, v);
+    return false;
+}
diff --git a/ast.h b/ast.h
index d0ce67a02aba7846dd0ce31fb6049cdae7e2edc7..187ec882cb8093dc6f09d24374be9fa0944012e5 100644 (file)
--- a/ast.h
+++ b/ast.h
@@ -40,6 +40,9 @@ typedef struct ast_entfield_s   ast_entfield;
 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
  */
@@ -78,7 +81,9 @@ typedef struct
     ast_expression_codegen *codegen;
     int                     vtype;
     ast_expression         *next;
+    MEM_VECTOR_MAKE(ast_value*, params);
 } ast_expression_common;
+MEM_VECTOR_PROTO(ast_expression_common, ast_value*, params);
 
 /* Value
  *
@@ -109,12 +114,8 @@ struct ast_value_s
     } constval;
 
     ir_value *ir_v;
-
-    /* if vtype is qc_function, params contain parameters, and
-     * 'next' the return type.
-     */
-    MEM_VECTOR_MAKE(ast_value*, params);
 };
+
 ast_value* ast_value_new(lex_ctx ctx, const char *name, int qctype);
 /* This will NOT delete an underlying ast_function */
 void ast_value_delete(ast_value*);
@@ -122,9 +123,11 @@ void ast_value_delete(ast_value*);
 bool ast_value_set_name(ast_value*, const char *name);
 
 bool ast_value_codegen(ast_value*, ast_function*, bool lvalue, ir_value**);
-bool ast_local_codegen(ast_value *self, ir_function *func);
+bool ast_local_codegen(ast_value *self, ir_function *func, bool isparam);
 bool ast_global_codegen(ast_value *self, ir_builder *ir);
 
+bool GMQCC_WARN ast_value_params_add(ast_value*, ast_value*);
+
 /* Binary
  *
  * A value-returning binary expression.
@@ -145,6 +148,41 @@ 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**);
+
+/* Return
+ *
+ * Make sure 'return' only happens at the end of a block, otherwise the IR
+ * will refuse to create further instructions.
+ * This should be honored by the parser.
+ */
+struct ast_return_s
+{
+    ast_expression_common expression;
+    ast_expression *operand;
+};
+ast_return* ast_return_new(lex_ctx    ctx,
+                           ast_expression *expr);
+void ast_return_delete(ast_return*);
+
+bool ast_return_codegen(ast_return*, ast_function*, bool lvalue, ir_value**);
+
 /* Entity-field
  *
  * This must do 2 things:
@@ -284,6 +322,29 @@ void ast_loop_delete(ast_loop*);
 
 bool ast_loop_codegen(ast_loop*, ast_function*, bool lvalue, ir_value**);
 
+/* CALL node
+ *
+ * Contains an ast_expression as target, rather than an ast_function/value.
+ * Since it's how QC works, every ast_function has an ast_value
+ * associated anyway - in other words, the VM contains function
+ * pointers for every function anyway. Thus, this node will call
+ * expression.
+ * Additionally it contains a list of ast_expressions as parameters.
+ * Since calls can return values, an ast_call is also an ast_expression.
+ */
+struct ast_call_s
+{
+    ast_expression_common expression;
+    ast_expression *func;
+    MEM_VECTOR_MAKE(ast_expression*, params);
+};
+ast_call* ast_call_new(lex_ctx ctx,
+                       ast_expression *funcexpr);
+void ast_call_delete(ast_call*);
+bool ast_call_codegen(ast_call*, ast_function*, bool lvalue, ir_value**);
+
+MEM_VECTOR_PROTO(ast_call, ast_expression*, params);
+
 /* Blocks
  *
  */
@@ -296,6 +357,7 @@ struct ast_block_s
 };
 ast_block* ast_block_new(lex_ctx ctx);
 void ast_block_delete(ast_block*);
+bool ast_block_set_type(ast_block*, ast_expression *from);
 
 MEM_VECTOR_PROTO(ast_block, ast_value*, locals);
 MEM_VECTOR_PROTO(ast_block, ast_expression*, exprs);
@@ -319,6 +381,8 @@ struct ast_function_s
     ast_value  *vtype;
     const char *name;
 
+    int builtin;
+
     ir_function *ir_func;
     ir_block    *curblock;
     ir_block    *breakblock;
diff --git a/gmqcc.h b/gmqcc.h
index e9e153ee8ce54ff56d601f0df35b9462df4be674..90d1e05b98e0830763d74d9ed116d4d39efd947a 100644 (file)
--- a/gmqcc.h
+++ b/gmqcc.h
@@ -77,7 +77,7 @@
  * This is a hack to silent clang regarding empty
  * body if statements.
  */
-#define GMQCC_SUPRESS_EMPTY_BODY do { } while (0)
+#define GMQCC_SUPPRESS_EMPTY_BODY do { } while (0)
 
 /*
  * Inline is not supported in < C90, however some compilers
@@ -371,6 +371,13 @@ enum {
 };
 
 extern size_t type_sizeof[TYPE_COUNT];
+extern uint16_t type_store_instr[TYPE_COUNT];
+/* could use type_store_instr + INSTR_STOREP_F - INSTR_STORE_F
+ * but this breaks when TYPE_INTEGER is added, since with the enhanced
+ * instruction set, the old ones are left untouched, thus the _I instructions
+ * are at a seperate place.
+ */
+extern uint16_t type_storep_instr[TYPE_COUNT];
 
 typedef struct {
     uint32_t offset;      /* Offset in file of where data begins  */
@@ -605,7 +612,7 @@ static const struct {
     { "EQ_V"      , 0, 4 },
     { "EQ_S"      , 0, 4 },
     { "EQ_E"      , 0, 4 },
-    { "ES_FNC"    , 0, 6 },
+    { "EQ_FNC"    , 0, 6 },
     { "NE_F"      , 0, 4 },
     { "NE_V"      , 0, 4 },
     { "NE_S"      , 0, 4 },
@@ -694,7 +701,7 @@ extern int  opts_compiler;
     size_t name##_count;             \
     size_t name##_alloc
 
-#define _MEM_VEC_FUN_ADD(Tself, Twhat, mem)                          \
+#define MEM_VEC_FUN_ADD(Tself, Twhat, mem)                           \
 bool GMQCC_WARN Tself##_##mem##_add(Tself *self, Twhat f)            \
 {                                                                    \
     Twhat *reall;                                                    \
@@ -716,7 +723,7 @@ bool GMQCC_WARN Tself##_##mem##_add(Tself *self, Twhat f)            \
     return true;                                                     \
 }
 
-#define _MEM_VEC_FUN_REMOVE(Tself, Twhat, mem)                       \
+#define MEM_VEC_FUN_REMOVE(Tself, Twhat, mem)                        \
 bool GMQCC_WARN Tself##_##mem##_remove(Tself *self, size_t idx)      \
 {                                                                    \
     size_t i;                                                        \
@@ -741,7 +748,7 @@ bool GMQCC_WARN Tself##_##mem##_remove(Tself *self, size_t idx)      \
     return true;                                                     \
 }
 
-#define _MEM_VEC_FUN_FIND(Tself, Twhat, mem)                    \
+#define MEM_VEC_FUN_FIND(Tself, Twhat, mem)                     \
 bool GMQCC_WARN Tself##_##mem##_find(Tself *self, Twhat obj, size_t *idx) \
 {                                                               \
     size_t i;                                                   \
@@ -756,7 +763,7 @@ bool GMQCC_WARN Tself##_##mem##_find(Tself *self, Twhat obj, size_t *idx) \
     return false;                                               \
 }
 
-#define _MEM_VEC_FUN_APPEND(Tself, Twhat, mem)                       \
+#define MEM_VEC_FUN_APPEND(Tself, Twhat, mem)                        \
 bool GMQCC_WARN Tself##_##mem##_append(Tself *s, Twhat *p, size_t c) \
 {                                                                    \
     Twhat *reall;                                                    \
@@ -782,7 +789,7 @@ bool GMQCC_WARN Tself##_##mem##_append(Tself *s, Twhat *p, size_t c) \
     return true;                                                     \
 }
 
-#define _MEM_VEC_FUN_RESIZE(Tself, Twhat, mem)                   \
+#define MEM_VEC_FUN_RESIZE(Tself, Twhat, mem)                    \
 bool GMQCC_WARN Tself##_##mem##_resize(Tself *s, size_t c)       \
 {                                                                \
     Twhat *reall;                                                \
@@ -806,7 +813,7 @@ bool GMQCC_WARN Tself##_##mem##_resize(Tself *s, size_t c)       \
     return true;                                                 \
 }
 
-#define _MEM_VEC_FUN_CLEAR(Tself, mem)  \
+#define MEM_VEC_FUN_CLEAR(Tself, mem)   \
 void Tself##_##mem##_clear(Tself *self) \
 {                                       \
     if (!self->mem)                     \
@@ -832,18 +839,20 @@ void Tself##_##mem##_clear(Tself *self) \
 }
 
 #define MEM_VEC_FUNCTIONS(Tself, Twhat, mem) \
-_MEM_VEC_FUN_REMOVE(Tself, Twhat, mem)       \
-_MEM_VEC_FUN_ADD(Tself, Twhat, mem)
+MEM_VEC_FUN_REMOVE(Tself, Twhat, mem)        \
+MEM_VEC_FUN_ADD(Tself, Twhat, mem)
 
 #define MEM_VEC_FUNCTIONS_ALL(Tself, Twhat, mem) \
 MEM_VEC_FUNCTIONS(Tself, Twhat, mem)             \
-_MEM_VEC_FUN_CLEAR(Tself, mem)                   \
-_MEM_VEC_FUN_FIND(Tself, Twhat, mem)
+MEM_VEC_FUN_CLEAR(Tself, mem)                    \
+MEM_VEC_FUN_FIND(Tself, Twhat, mem)
 
 enum store_types {
     store_global,
     store_local,  /* local, assignable for now, should get promoted later */
-    store_value   /* unassignable */
+    store_param,  /* parameters, they are locals with a fixed position */
+    store_value,  /* unassignable */
+    store_return  /* unassignable, at OFS_RETURN */
 };
 
 typedef struct {
diff --git a/ir.c b/ir.c
index d81cdcecf1a838c963189c5990692da9767b213a..f32f9d49492c2ae3efa4b58ec3d3df44e78a42f0 100644 (file)
--- a/ir.c
+++ b/ir.c
@@ -44,6 +44,38 @@ size_t type_sizeof[TYPE_COUNT] = {
     3, /* TYPE_VARIANT  */
 };
 
+uint16_t type_store_instr[TYPE_COUNT] = {
+    INSTR_STORE_F, /* should use I when having integer support */
+    INSTR_STORE_S,
+    INSTR_STORE_F,
+    INSTR_STORE_V,
+    INSTR_STORE_ENT,
+    INSTR_STORE_FLD,
+    INSTR_STORE_FNC,
+    INSTR_STORE_ENT, /* should use I */
+#if 0
+    INSTR_STORE_ENT, /* integer type */
+#endif
+    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)
+
 /***********************************************************************
  *IR Builder
  */
@@ -108,20 +140,32 @@ ir_function* ir_builder_get_function(ir_builder *self, const char *name)
     return NULL;
 }
 
-ir_function* ir_builder_create_function(ir_builder *self, const char *name)
+ir_function* ir_builder_create_function(ir_builder *self, const char *name, int outtype)
 {
     ir_function *fn = ir_builder_get_function(self, name);
     if (fn) {
         return NULL;
     }
 
-    fn = ir_function_new(self);
+    fn = ir_function_new(self, outtype);
     if (!ir_function_set_name(fn, name) ||
         !ir_builder_functions_add(self, fn) )
     {
         ir_function_delete(fn);
         return NULL;
     }
+
+    fn->value = ir_builder_create_global(self, fn->name, TYPE_FUNCTION);
+    if (!fn->value) {
+        ir_function_delete(fn);
+        return NULL;
+    }
+
+    fn->value->isconst = true;
+    fn->value->outtype = outtype;
+    fn->value->constval.vfunc = fn;
+    fn->value->context = fn->context;
+
     return fn;
 }
 
@@ -159,7 +203,7 @@ void ir_function_enumerate(ir_function*);
 bool ir_function_calculate_liferanges(ir_function*);
 bool ir_function_allocate_locals(ir_function*);
 
-ir_function* ir_function_new(ir_builder* owner)
+ir_function* ir_function_new(ir_builder* owner, int outtype)
 {
     ir_function *self;
     self = (ir_function*)mem_a(sizeof(*self));
@@ -175,7 +219,9 @@ ir_function* ir_function_new(ir_builder* owner)
     self->owner = owner;
     self->context.file = "<@no context>";
     self->context.line = 0;
-    self->retype = TYPE_VOID;
+    self->outtype = outtype;
+    self->value = NULL;
+    self->builtin = 0;
     MEM_VECTOR_INIT(self, params);
     MEM_VECTOR_INIT(self, blocks);
     MEM_VECTOR_INIT(self, values);
@@ -187,6 +233,7 @@ ir_function* ir_function_new(ir_builder* owner)
 MEM_VEC_FUNCTIONS(ir_function, ir_value*, values)
 MEM_VEC_FUNCTIONS(ir_function, ir_block*, blocks)
 MEM_VEC_FUNCTIONS(ir_function, ir_value*, locals)
+MEM_VEC_FUNCTIONS(ir_function, int,       params)
 
 bool ir_function_set_name(ir_function *self, const char *name)
 {
@@ -215,6 +262,8 @@ void ir_function_delete(ir_function *self)
         ir_value_delete(self->locals[i]);
     MEM_VECTOR_CLEAR(self, locals);
 
+    /* self->value is deleted by the builder */
+
     mem_d(self);
 }
 
@@ -236,6 +285,9 @@ ir_block* ir_function_create_block(ir_function *self, const char *label)
 
 bool ir_function_finalize(ir_function *self)
 {
+    if (self->builtin)
+        return true;
+
     if (!ir_function_naive_phi(self))
         return false;
 
@@ -259,14 +311,21 @@ ir_value* ir_function_get_local(ir_function *self, const char *name)
     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;
@@ -356,11 +415,13 @@ ir_instr* ir_instr_new(ir_block* owner, int op)
     self->bops[0] = NULL;
     self->bops[1] = NULL;
     MEM_VECTOR_INIT(self, phi);
+    MEM_VECTOR_INIT(self, params);
 
     self->eid = 0;
     return self;
 }
 MEM_VEC_FUNCTIONS(ir_instr, ir_phi_entry_t, phi)
+MEM_VEC_FUNCTIONS(ir_instr, ir_value*, params)
 
 void ir_instr_delete(ir_instr *self)
 {
@@ -374,14 +435,22 @@ void ir_instr_delete(ir_instr *self)
     for (i = 0; i < self->phi_count; ++i) {
         size_t idx;
         if (ir_value_writes_find(self->phi[i].value, self, &idx))
-            if (ir_value_writes_remove(self->phi[i].value, idx)) GMQCC_SUPRESS_EMPTY_BODY;
+            if (ir_value_writes_remove(self->phi[i].value, idx)) GMQCC_SUPPRESS_EMPTY_BODY;
         if (ir_value_reads_find(self->phi[i].value, self, &idx))
-            if (ir_value_reads_remove (self->phi[i].value, idx)) GMQCC_SUPRESS_EMPTY_BODY;
+            if (ir_value_reads_remove (self->phi[i].value, idx)) GMQCC_SUPPRESS_EMPTY_BODY;
     }
     MEM_VECTOR_CLEAR(self, phi);
-    if (ir_instr_op(self, 0, NULL, false)) GMQCC_SUPRESS_EMPTY_BODY;
-    if (ir_instr_op(self, 1, NULL, false)) GMQCC_SUPRESS_EMPTY_BODY;
-    if (ir_instr_op(self, 2, NULL, false)) GMQCC_SUPRESS_EMPTY_BODY;
+    for (i = 0; i < self->params_count; ++i) {
+        size_t idx;
+        if (ir_value_writes_find(self->params[i], self, &idx))
+            if (ir_value_writes_remove(self->params[i], idx)) GMQCC_SUPPRESS_EMPTY_BODY;
+        if (ir_value_reads_find(self->params[i], self, &idx))
+            if (ir_value_reads_remove (self->params[i], idx)) GMQCC_SUPPRESS_EMPTY_BODY;
+    }
+    MEM_VECTOR_CLEAR(self, params);
+    if (ir_instr_op(self, 0, NULL, false)) GMQCC_SUPPRESS_EMPTY_BODY;
+    if (ir_instr_op(self, 1, NULL, false)) GMQCC_SUPPRESS_EMPTY_BODY;
+    if (ir_instr_op(self, 2, NULL, false)) GMQCC_SUPPRESS_EMPTY_BODY;
     mem_d(self);
 }
 
@@ -423,6 +492,7 @@ ir_value* ir_value_var(const char *name, int storetype, int vtype)
     self = (ir_value*)mem_a(sizeof(*self));
     self->vtype = vtype;
     self->fieldtype = TYPE_VOID;
+    self->outtype = TYPE_VOID;
     self->store = storetype;
     MEM_VECTOR_INIT(self, reads);
     MEM_VECTOR_INIT(self, writes);
@@ -486,6 +556,15 @@ bool ir_value_set_float(ir_value *self, float f)
     return true;
 }
 
+bool ir_value_set_func(ir_value *self, int f)
+{
+    if (self->vtype != TYPE_FUNCTION)
+        return false;
+    self->constval.vint = f;
+    self->isconst = true;
+    return true;
+}
+
 bool ir_value_set_vector(ir_value *self, vector v)
 {
     if (self->vtype != TYPE_VECTOR)
@@ -773,46 +852,14 @@ bool ir_block_create_store(ir_block *self, ir_value *target, ir_value *what)
     else
         vtype = target->vtype;
 
-    switch (vtype) {
-        case TYPE_FLOAT:
-#if 0
-            if (what->vtype == TYPE_INTEGER)
-                op = INSTR_CONV_ITOF;
-            else
-#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;
+    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
-        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);
 }
 
@@ -829,38 +876,8 @@ bool ir_block_create_storep(ir_block *self, ir_value *target, ir_value *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);
 }
 
@@ -1017,6 +1034,47 @@ bool ir_phi_add(ir_instr* self, ir_block *b, ir_value *v)
     return ir_instr_phi_add(self, pe);
 }
 
+/* call related code */
+ir_instr* ir_block_create_call(ir_block *self, const char *label, ir_value *func)
+{
+    ir_value *out;
+    ir_instr *in;
+    in = ir_instr_new(self, INSTR_CALL0);
+    if (!in)
+        return NULL;
+    out = ir_value_out(self->owner, label, store_return, func->outtype);
+    if (!out) {
+        ir_instr_delete(in);
+        return NULL;
+    }
+    if (!ir_instr_op(in, 0, out, true) ||
+        !ir_instr_op(in, 1, func, false) ||
+        !ir_block_instr_add(self, in))
+    {
+        ir_instr_delete(in);
+        ir_value_delete(out);
+        return NULL;
+    }
+    return in;
+}
+
+ir_value* ir_call_value(ir_instr *self)
+{
+    return self->_ops[0];
+}
+
+bool ir_call_param(ir_instr* self, ir_value *v)
+{
+    if (!ir_instr_params_add(self, v))
+        return false;
+    if (!ir_value_reads_add(v, self)) {
+        if (!ir_instr_params_remove(self, self->params_count-1))
+            GMQCC_SUPPRESS_EMPTY_BODY;
+        return false;
+    }
+    return true;
+}
+
 /* binary op related code */
 
 ir_value* ir_block_create_binop(ir_block *self,
@@ -1111,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)
 {
@@ -1406,7 +1497,7 @@ static bool ir_block_naive_phi(ir_block *self)
                 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
@@ -1565,6 +1656,9 @@ bool ir_function_allocate_locals(ir_function *self)
 
     function_allocator alloc;
 
+    if (!self->locals_count)
+        return true;
+
     MEM_VECTOR_INIT(&alloc, locals);
     MEM_VECTOR_INIT(&alloc, sizes);
     MEM_VECTOR_INIT(&alloc, positions);
@@ -1611,6 +1705,10 @@ bool ir_function_allocate_locals(ir_function *self)
     if (!function_allocator_positions_add(&alloc, 0))
         goto error;
 
+    if (alloc.sizes_count)
+        pos = alloc.positions[0] + alloc.sizes[0];
+    else
+        pos = 0;
     for (i = 1; i < alloc.sizes_count; ++i)
     {
         pos = alloc.positions[i-1] + alloc.sizes[i-1];
@@ -1779,8 +1877,11 @@ static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *change
             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 */
@@ -2109,8 +2210,56 @@ tailcall:
         }
 
         if (instr->opcode >= INSTR_CALL0 && instr->opcode <= INSTR_CALL8) {
-            printf("TODO: call instruction\n");
-            return false;
+            /* Trivial call translation:
+             * copy all params to OFS_PARM*
+             * if the output's storetype is not store_return,
+             * add append a STORE instruction!
+             *
+             * NOTES on how to do it better without much trouble:
+             * -) The liferanges!
+             *      Simply check the liferange of all parameters for
+             *      other CALLs. For each param with no CALL in its
+             *      liferange, we can store it in an OFS_PARM at
+             *      generation already. This would even include later
+             *      reuse.... probably... :)
+             */
+            size_t p;
+            ir_value *retvalue;
+
+            for (p = 0; p < instr->params_count; ++p)
+            {
+                ir_value *param = instr->params[p];
+
+                stmt.opcode = INSTR_STORE_F;
+                stmt.o3.u1 = 0;
+
+                stmt.opcode = type_store_instr[param->vtype];
+                stmt.o1.u1 = param->code.globaladdr;
+                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.o2.u1 = 0;
+            stmt.o3.u1 = 0;
+            if (code_statements_add(stmt) < 0)
+                return false;
+
+            retvalue = instr->_ops[0];
+            if (retvalue && retvalue->store != store_return && retvalue->life_count)
+            {
+                /* 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.o3.u1 = 0;
+                if (code_statements_add(stmt) < 0)
+                    return false;
+            }
+            continue;
         }
 
         if (instr->opcode == INSTR_STATE) {
@@ -2138,10 +2287,8 @@ tailcall:
             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;
@@ -2157,6 +2304,7 @@ tailcall:
 static bool gen_function_code(ir_function *self)
 {
     ir_block *block;
+    prog_section_statement stmt;
 
     /* Starting from entry point, we generate blocks "as they come"
      * for now. Dead blocks will not be translated obviously.
@@ -2174,6 +2322,14 @@ static bool gen_function_code(ir_function *self)
         printf("failed to generate blocks for '%s'\n", self->name);
         return false;
     }
+
+    /* otherwise code_write crashes since it debug-prints functions until AINSTR_END */
+    stmt.opcode = AINSTR_END;
+    stmt.o1.u1 = 0;
+    stmt.o2.u1 = 0;
+    stmt.o3.u1 = 0;
+    if (code_statements_add(stmt) < 0)
+        return false;
     return true;
 }
 
@@ -2185,8 +2341,7 @@ static bool gen_global_function(ir_builder *ir, ir_value *global)
     size_t i;
     size_t local_var_end;
 
-    if (!global->isconst ||
-        !global->constval.vfunc)
+    if (!global->isconst || (!global->constval.vfunc))
     {
         printf("Invalid state of function-global: not constant: %s\n", global->name);
         return false;
@@ -2202,10 +2357,8 @@ static bool gen_global_function(ir_builder *ir, ir_value *global)
     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;
@@ -2234,10 +2387,14 @@ static bool gen_global_function(ir_builder *ir, ir_value *global)
         code_globals_add(0);
     }
 
-    fun.entry      = code_statements_elements;
-    if (!gen_function_code(irfun)) {
-        printf("Failed to generate code for function %s\n", irfun->name);
-        return false;
+    if (irfun->builtin)
+        fun.entry = irfun->builtin;
+    else {
+        fun.entry = code_statements_elements;
+        if (!gen_function_code(irfun)) {
+            printf("Failed to generate code for function %s\n", irfun->name);
+            return false;
+        }
     }
 
     return (code_functions_add(fun) >= 0);
@@ -2245,6 +2402,7 @@ static bool gen_global_function(ir_builder *ir, ir_value *global)
 
 static bool ir_builder_gen_global(ir_builder *self, ir_value *global)
 {
+    size_t           i;
     int32_t         *iptr;
     prog_section_def def;
 
@@ -2289,31 +2447,43 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global)
     }
     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_FUNCTION:
         if (code_defs_add(def) < 0)
             return false;
+        global->code.globaladdr = code_globals_elements;
         code_globals_add(code_functions_elements);
         return gen_global_function(self, global);
     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. */
@@ -2328,21 +2498,6 @@ bool ir_builder_generate(ir_builder *self, const char *filename)
 
     code_init();
 
-    /* FIXME: generate TYPE_FUNCTION globals and link them
-     * to their ir_function.
-     */
-
-    for (i = 0; i < self->functions_count; ++i)
-    {
-        ir_value    *funval;
-        ir_function *fun = self->functions[i];
-
-        funval = ir_builder_create_global(self, fun->name, TYPE_FUNCTION);
-        funval->isconst = true;
-        funval->constval.vfunc = fun;
-        funval->context = fun->context;
-    }
-
     for (i = 0; i < self->globals_count; ++i)
     {
         if (!ir_builder_gen_global(self, self->globals[i])) {
@@ -2398,6 +2553,10 @@ void ir_function_dump(ir_function *f, char *ind,
                       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)
diff --git a/ir.h b/ir.h
index a611dba13cba29e8f655f8e26ad9da27ecd7f272..9eab51f73f5d9282e4597986badb38ff85fb6268 100644 (file)
--- a/ir.h
+++ b/ir.h
@@ -40,6 +40,8 @@ typedef struct ir_value_s {
     lex_ctx   context;
     /* even the IR knows the subtype of a field */
     int       fieldtype;
+    /* and the output type of a function */
+    int       outtype;
 
     MEM_VECTOR_MAKE(struct ir_instr_s*, reads);
     MEM_VECTOR_MAKE(struct ir_instr_s*, writes);
@@ -79,6 +81,7 @@ 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_float(ir_value*, float f);
+bool GMQCC_WARN ir_value_set_func(ir_value*, int f);
 #if 0
 bool GMQCC_WARN ir_value_set_int(ir_value*, int i);
 #endif
@@ -100,6 +103,13 @@ bool ir_values_overlap(const ir_value*, const ir_value*);
 void ir_value_dump(ir_value*, int (*oprintf)(const char*,...));
 void ir_value_dump_life(ir_value *self, int (*oprintf)(const char*,...));
 
+/* A vector of IR values */
+typedef struct {
+    MEM_VECTOR_MAKE(ir_value*, v);
+} ir_value_vector;
+MEM_VECTOR_PROTO(ir_value_vector, ir_value*, v);
+
+/* PHI data */
 typedef struct ir_phi_entry_s
 {
     ir_value          *value;
@@ -115,6 +125,7 @@ typedef struct ir_instr_s
     struct ir_block_s* (bops[2]);
 
     MEM_VECTOR_MAKE(ir_phi_entry_t, phi);
+    MEM_VECTOR_MAKE(ir_value*, params);
 
     /* For the temp-allocation */
     size_t eid;
@@ -128,6 +139,8 @@ void      ir_instr_delete(ir_instr*);
 MEM_VECTOR_PROTO(ir_value, ir_phi_entry_t, phi);
 bool GMQCC_WARN ir_instr_op(ir_instr*, int op, ir_value *value, bool writing);
 
+MEM_VECTOR_PROTO(ir_value, ir_value*, params);
+
 void ir_instr_dump(ir_instr* in, char *ind, int (*oprintf)(const char*,...));
 
 /* block */
@@ -164,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);
@@ -186,6 +201,9 @@ ir_value* ir_block_create_div(ir_block*, const char *label, ir_value *l, ir_valu
 ir_instr* ir_block_create_phi(ir_block*, const char *label, int vtype);
 ir_value* ir_phi_value(ir_instr*);
 bool GMQCC_WARN ir_phi_add(ir_instr*, ir_block *b, ir_value *v);
+ir_instr* ir_block_create_call(ir_block*, const char *label, ir_value *func);
+ir_value* ir_call_value(ir_instr*);
+bool GMQCC_WARN ir_call_param(ir_instr*, ir_value*);
 
 bool GMQCC_WARN ir_block_create_return(ir_block*, ir_value *opt_value);
 
@@ -209,10 +227,14 @@ void ir_block_dump(ir_block*, char *ind, int (*oprintf)(const char*,...));
 typedef struct ir_function_s
 {
     char *name;
-    int   retype;
+    int   outtype;
     MEM_VECTOR_MAKE(int, params);
     MEM_VECTOR_MAKE(ir_block*, blocks);
 
+    int builtin;
+
+    ir_value *value;
+
     /* values generated from operations
      * which might get optimized away, so anything
      * in there needs to be deleted in the dtor.
@@ -235,7 +257,7 @@ typedef struct ir_function_s
     struct ir_builder_s *owner;
 } ir_function;
 
-ir_function* ir_function_new(struct ir_builder_s *owner);
+ir_function* ir_function_new(struct ir_builder_s *owner, int returntype);
 void         ir_function_delete(ir_function*);
 
 bool GMQCC_WARN ir_function_collect_value(ir_function*, ir_value *value);
@@ -245,7 +267,7 @@ MEM_VECTOR_PROTO(ir_function, int, params);
 MEM_VECTOR_PROTO(ir_function, ir_block*, blocks);
 
 ir_value* ir_function_get_local(ir_function *self, const char *name);
-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);
 
 bool GMQCC_WARN ir_function_finalize(ir_function*);
 /*
@@ -275,7 +297,7 @@ MEM_VECTOR_PROTO(ir_builder, ir_function*, functions);
 MEM_VECTOR_PROTO(ir_builder, ir_value*, globals);
 
 ir_function* ir_builder_get_function(ir_builder*, const char *fun);
-ir_function* ir_builder_create_function(ir_builder*, const char *name);
+ir_function* ir_builder_create_function(ir_builder*, const char *name, int outtype);
 
 ir_value* ir_builder_get_global(ir_builder*, const char *fun);
 ir_value* ir_builder_create_global(ir_builder*, const char *name, int vtype);
index d4ed60721400ee5919ddc3d95e49abf4acb904b1..c17b753696173db090398d7d78f713a15ecc0e07 100644 (file)
@@ -28,6 +28,13 @@ do {                               \
     MKGLOBAL(name);                \
 } while(0)
 
+#define MKCONSTSTRING(name, value)               \
+do {                                             \
+    name->isconst = true;                        \
+    name->constval.vstring = util_strdup(value); \
+    MKGLOBAL(name);                              \
+} while(0)
+
 #define STATE(a)                                 \
 do {                                             \
     ast_expression *exp = (ast_expression*)(a);  \
@@ -40,6 +47,17 @@ do {                                             \
 #define BIN(op, a, b) \
 (ast_expression*)ast_binary_new(ctx, INSTR_##op, (ast_expression*)(a), (ast_expression*)(b))
 
+#define CALL(what)                                             \
+do {                                                           \
+    ast_call *call = ast_call_new(ctx, (ast_expression*)what); \
+
+#define CALLPARAM(x)                                       \
+    assert(ast_call_params_add(call, (ast_expression*)x));
+
+#define ENDCALL()                                \
+    STATE(call);                                 \
+} while(0)
+
 #define WHILE(cond)                                    \
 do {                                                   \
     ast_expression *wh_cond = (ast_expression*)(cond); \
@@ -56,18 +74,51 @@ do {                                                   \
     STATE(loop);                                               \
 } while(0)
 
-#define FUNCTION(name)                                          \
-do {                                                            \
-    ast_function *func_##name;                                  \
-    ast_block    *my_funcblock;                                 \
-    DEFVAR(var_##name);                                         \
-    VARnamed(TYPE_FUNCTION, var_##name, name);                  \
-    MKGLOBAL(var_##name);                                       \
-    func_##name = ast_function_new(ctx, #name, var_##name);     \
-    assert(functions_add(func_##name) >= 0);                    \
-    my_funcblock = ast_block_new(ctx);                          \
-    assert(my_funcblock);                                       \
-    assert(ast_function_blocks_add(func_##name, my_funcblock)); \
+#define BUILTIN(name, outtype, number)                              \
+do {                                                                \
+    ast_function *func_##name;                                      \
+    ast_value    *thisfuncval;                                      \
+    ast_function *thisfunc;                                         \
+    DEFVAR(return_##name);                                          \
+    VARnamed(TYPE_FUNCTION, name, name);                            \
+    VARnamed(outtype, return_##name, "#returntype");                \
+    name->expression.next = (ast_expression*)return_##name;         \
+    MKGLOBAL(name);                                                 \
+    func_##name = ast_function_new(ctx, #name, name);               \
+    thisfunc = func_##name;                                         \
+    (void)thisfunc;                                                 \
+    thisfuncval = name;                                             \
+    (void)thisfuncval;                                              \
+    assert(functions_add(func_##name) >= 0);                        \
+    func_##name->builtin = number;
+
+#define ENDBUILTIN() } while(0)
+
+#define PARAM(ptype, name)                           \
+do {                                                 \
+    DEFVAR(parm);                                    \
+    VARnamed(ptype, parm, name);                     \
+    assert(ast_value_params_add(thisfuncval, parm)); \
+} while(0)
+
+#define FUNCTION(name, outtype)                                   \
+do {                                                              \
+    ast_function *thisfunc;                                       \
+    ast_function *func_##name;                                    \
+    ast_block    *my_funcblock;                                   \
+    DEFVAR(var_##name);                                           \
+    DEFVAR(return_##name);                                        \
+    VARnamed(TYPE_FUNCTION, var_##name, name);                    \
+    VARnamed(outtype, return_##name, "#returntype");              \
+    var_##name->expression.next = (ast_expression*)return_##name; \
+    MKGLOBAL(var_##name);                                         \
+    func_##name = ast_function_new(ctx, #name, var_##name);       \
+    thisfunc = func_##name;                                       \
+    (void)thisfunc;                                               \
+    assert(functions_add(func_##name) >= 0);                      \
+    my_funcblock = ast_block_new(ctx);                            \
+    assert(my_funcblock);                                         \
+    assert(ast_function_blocks_add(func_##name, my_funcblock));   \
     curblock = my_funcblock;
 
 #define MKLOCAL(var) \
index 792ad774c58d3b8eb8452425dfd5226fbacbf880..c57e43644f66685b5c7343b9c52a94b447044ff5 100644 (file)
@@ -27,28 +27,45 @@ int main()
     DEFVAR(f0);
     DEFVAR(f1);
     DEFVAR(f5);
+    DEFVAR(sHello);
+    DEFVAR(print);
+
+    /* opts_debug = true; */
+
+BUILTIN(print, TYPE_VOID, -1);
+PARAM(TYPE_STRING, text);
+ENDBUILTIN();
 
     TESTINIT();
 VAR(TYPE_FLOAT, f0);
 VAR(TYPE_FLOAT, f1);
 VAR(TYPE_FLOAT, f5);
+VAR(TYPE_STRING, sHello);
 MKCONSTFLOAT(f0, 0.0);
 MKCONSTFLOAT(f1, 1.0);
 MKCONSTFLOAT(f5, 5.0);
+MKCONSTSTRING(sHello, "Hello, World\n");
+
+FUNCTION(foo, TYPE_VOID);
+ENDFUNCTION(foo);
+
+FUNCTION(main, TYPE_VOID);
 
-FUNCTION(main);
+    VAR(TYPE_FLOAT, vi);
+    VAR(TYPE_FLOAT, vx);
 
-VAR(TYPE_FLOAT, vi);
-VAR(TYPE_FLOAT, vx);
+    MKLOCAL(vi);
+    MKLOCAL(vx);
 
-MKLOCAL(vi);
-MKLOCAL(vx);
+    STATE(ASSIGN(STORE_F, vi, f0));
+    WHILE(BIN(LT, vi, f5));
+        STATE(ASSIGN(STORE_F, vx, BIN(MUL_F, vi, f5)));
+        STATE(ASSIGN(STORE_F, vi, BIN(ADD_F, vi, f1)));
+    ENDWHILE();
 
-STATE(ASSIGN(STORE_F, vi, f0));
-WHILE(BIN(LT, vi, f5));
-STATE(ASSIGN(STORE_F, vx, BIN(MUL_F, vi, f5)));
-STATE(ASSIGN(STORE_F, vi, BIN(ADD_F, vi, f1)));
-ENDWHILE();
+    CALL(print)
+    CALLPARAM(sHello)
+    ENDCALL();
 
 ENDFUNCTION(main);