]> de.git.xonotic.org Git - xonotic/gmqcc.git/commitdiff
Merge branch 'master' into cooking
authorDale Weiler <killfieldengine@gmail.com>
Sun, 8 Sep 2013 17:05:20 +0000 (13:05 -0400)
committerDale Weiler <killfieldengine@gmail.com>
Sun, 8 Sep 2013 17:05:20 +0000 (13:05 -0400)
15 files changed:
ast.c
code.c
fold.c
gmqcc.h
intrin.c
ir.c
lexer.c
lexer.h
main.c
parser.c
parser.h
test.c
tests/vec_ops.qc
tests/vec_ops.tmpl
util.c

diff --git a/ast.c b/ast.c
index 2f1566bfc5700a26f7fb51f923b46c0a7ecdc700..3531adadf15ee1c03fda93efd719fc960d229915 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -1877,6 +1877,17 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir)
     return true;
 }
 
+static bool starts_a_label(ast_expression *ex)
+{
+    while (ex && ast_istype(ex, ast_block)) {
+        ast_block *b = (ast_block*)ex;
+        ex = b->exprs[0];
+    }
+    if (!ex)
+        return false;
+    return ast_istype(ex, ast_label);
+}
+
 /* Note, you will not see ast_block_codegen generate ir_blocks.
  * To the AST and the IR, blocks are 2 different things.
  * In the AST it represents a block of code, usually enclosed in
@@ -1922,7 +1933,7 @@ bool ast_block_codegen(ast_block *self, ast_function *func, bool lvalue, ir_valu
     for (i = 0; i < vec_size(self->exprs); ++i)
     {
         ast_expression_codegen *gen;
-        if (func->curblock->final && !ast_istype(self->exprs[i], ast_label)) {
+        if (func->curblock->final && !starts_a_label(self->exprs[i])) {
             if (compile_warning(ast_ctx(self->exprs[i]), WARN_UNREACHABLE_CODE, "unreachable statement"))
                 return false;
             continue;
diff --git a/code.c b/code.c
index f3d60fffc40555de1c7f2f1abcd2306a53b8f7d9..5703e5098b60131251ba96ec7d34df62efaa2e11 100644 (file)
--- a/code.c
+++ b/code.c
@@ -253,8 +253,6 @@ static void code_create_header(code_t *code, prog_header_t *code_header, const c
     code_header->entfield          = code->entfields;
 
     if (OPTS_FLAG(DARKPLACES_STRING_TABLE_BUG)) {
-        util_debug("GEN", "Patching stringtable for -fdarkplaces-stringtablebug\n");
-
         /* >= + P */
         vec_push(code->chars, '\0'); /* > */
         vec_push(code->chars, '\0'); /* = */
@@ -403,8 +401,7 @@ static bool code_write_memory(code_t *code, uint8_t **datmem, size_t *sizedat, u
 
 bool code_write(code_t *code, const char *filename, const char *lnofile) {
     prog_header_t  code_header;
-    FILE          *fp           = NULL;
-    size_t         it           = 2;
+    FILE          *fp = NULL;
 
     code_create_header(code, &code_header, filename, lnofile);
 
@@ -451,60 +448,6 @@ bool code_write(code_t *code, const char *filename, const char *lnofile) {
         return false;
     }
 
-    util_debug("GEN","HEADER:\n");
-    util_debug("GEN","    version:    = %d\n", code_header.version );
-    util_debug("GEN","    crc16:      = %d\n", code_header.crc16   );
-    util_debug("GEN","    entfield:   = %d\n", code_header.entfield);
-    util_debug("GEN","    statements  = {.offset = % 8d, .length = % 8d}\n", code_header.statements.offset, code_header.statements.length);
-    util_debug("GEN","    defs        = {.offset = % 8d, .length = % 8d}\n", code_header.defs      .offset, code_header.defs      .length);
-    util_debug("GEN","    fields      = {.offset = % 8d, .length = % 8d}\n", code_header.fields    .offset, code_header.fields    .length);
-    util_debug("GEN","    functions   = {.offset = % 8d, .length = % 8d}\n", code_header.functions .offset, code_header.functions .length);
-    util_debug("GEN","    globals     = {.offset = % 8d, .length = % 8d}\n", code_header.globals   .offset, code_header.globals   .length);
-    util_debug("GEN","    strings     = {.offset = % 8d, .length = % 8d}\n", code_header.strings   .offset, code_header.strings   .length);
-
-    /* FUNCTIONS */
-    util_debug("GEN", "FUNCTIONS:\n");
-    for (; it < vec_size(code->functions); it++) {
-        size_t j = code->functions[it].entry;
-        util_debug("GEN", "    {.entry =% 5d, .firstlocal =% 5d, .locals =% 5d, .profile =% 5d, .name =% 5d, .file =% 5d, .nargs =% 5d, .argsize ={%d,%d,%d,%d,%d,%d,%d,%d} }\n",
-            code->functions[it].entry,
-            code->functions[it].firstlocal,
-            code->functions[it].locals,
-            code->functions[it].profile,
-            code->functions[it].name,
-            code->functions[it].file,
-            code->functions[it].nargs,
-            code->functions[it].argsize[0],
-            code->functions[it].argsize[1],
-            code->functions[it].argsize[2],
-            code->functions[it].argsize[3],
-            code->functions[it].argsize[4],
-            code->functions[it].argsize[5],
-            code->functions[it].argsize[6],
-            code->functions[it].argsize[7]
-
-        );
-        util_debug("GEN", "    NAME: %s\n", &code->chars[code->functions[it].name]);
-        /* Internal functions have no code */
-        if (code->functions[it].entry >= 0) {
-            util_debug("GEN", "    CODE:\n");
-            for (;;) {
-                if (code->statements[j].opcode != INSTR_DONE)
-                    util_debug("GEN", "        %-12s {% 5i,% 5i,% 5i}\n",
-                        util_instr_str[code->statements[j].opcode],
-                        code->statements[j].o1.s1,
-                        code->statements[j].o2.s1,
-                        code->statements[j].o3.s1
-                    );
-                else {
-                    util_debug("GEN", "        DONE  {0x00000,0x00000,0x00000}\n");
-                    break;
-                }
-                j++;
-            }
-        }
-    }
-
     fs_file_close(fp);
     code_stats(filename, lnofile, code, &code_header);
     return true;
diff --git a/fold.c b/fold.c
index f8a143ceb7f7f4ab772c99323d7a96336965bf84..98e637ae0e62177fe580fbcb180495898d3e3540 100644 (file)
--- a/fold.c
+++ b/fold.c
@@ -163,6 +163,14 @@ static GMQCC_INLINE bool vec3_pbool(vec3_t a) {
     return (a.x && a.y && a.z);
 }
 
+static GMQCC_INLINE vec3_t vec3_cross(vec3_t a, vec3_t b) {
+    vec3_t out;
+    out.x = a.y * b.z - a.z * b.y;
+    out.y = a.z * b.x - a.x * b.z;
+    out.z = a.x * b.y - a.y * b.x;
+    return out;
+}
+
 static lex_ctx_t fold_ctx(fold_t *fold) {
     lex_ctx_t ctx;
     if (fold->parser->lex)
@@ -201,11 +209,25 @@ static GMQCC_INLINE bool fold_immediate_true(fold_t *fold, ast_value *v) {
                 ((ast_expression*)(X))->vtype != TYPE_FUNCTION)
 
 #define fold_can_2(X, Y) (fold_can_1(X) && fold_can_1(Y))
+#define fold_can_div(X) (fold_immvalue_float(X) != 0.0f)
 
 #define fold_immvalue_float(E)  ((E)->constval.vfloat)
 #define fold_immvalue_vector(E) ((E)->constval.vvec)
 #define fold_immvalue_string(E) ((E)->constval.vstring)
 
+#ifdef INFINITY
+#   define fold_infinity_float  INFINITY
+#else
+#   define fold_infinity_float  (1.0 / 0.0)
+#endif /*! INFINITY */
+
+#define fold_infinity_vector \
+    vec3_create(             \
+        fold_infinity_float, \
+        fold_infinity_float, \
+        fold_infinity_float  \
+    )
+
 fold_t *fold_init(parser_t *parser) {
     fold_t *fold                 = (fold_t*)mem_a(sizeof(fold_t));
     fold->parser                 = parser;
@@ -222,9 +244,11 @@ fold_t *fold_init(parser_t *parser) {
     (void)fold_constgen_float (fold,  0.0f);
     (void)fold_constgen_float (fold,  1.0f);
     (void)fold_constgen_float (fold, -1.0f);
+    (void)fold_constgen_float (fold,  fold_infinity_float); /* +inf */
 
     (void)fold_constgen_vector(fold, vec3_create(0.0f, 0.0f, 0.0f));
     (void)fold_constgen_vector(fold, vec3_create(-1.0f, -1.0f, -1.0f));
+    (void)fold_constgen_vector(fold, fold_infinity_vector); /* +inf */
 
     return fold;
 }
@@ -454,12 +478,23 @@ static GMQCC_INLINE ast_expression *fold_op_mul(fold_t *fold, ast_value *a, ast_
 
 static GMQCC_INLINE ast_expression *fold_op_div(fold_t *fold, ast_value *a, ast_value *b) {
     if (isfloat(a)) {
-        if (fold_can_2(a, b))
-            return fold_constgen_float(fold, fold_immvalue_float(a) / fold_immvalue_float(b));
+        if (fold_can_2(a, b)) {
+            if (fold_can_div(b))
+                return fold_constgen_float(fold, fold_immvalue_float(a) / fold_immvalue_float(b));
+            else
+                return (ast_expression*)fold->imm_float[3]; /* inf */
+        }
     } else if (isvector(a)) {
-        if (fold_can_2(a, b))
-            return fold_constgen_vector(fold, vec3_mulvf(fold_immvalue_vector(a), 1.0f / fold_immvalue_float(b)));
-        else {
+        if (fold_can_2(a, b)) {
+            if (fold_can_div(b)) {
+                printf("hit wrong logic\n");
+                return fold_constgen_vector(fold, vec3_mulvf(fold_immvalue_vector(a), 1.0f / fold_immvalue_float(b)));
+            }
+            else {
+                printf("hit logic\n");
+                return (ast_expression*)fold->imm_vector[2]; /* inf */
+            }
+        } else {
             return (ast_expression*)ast_binary_new(
                 fold_ctx(fold),
                 INSTR_MUL_VF,
@@ -479,8 +514,12 @@ static GMQCC_INLINE ast_expression *fold_op_div(fold_t *fold, ast_value *a, ast_
 }
 
 static GMQCC_INLINE ast_expression *fold_op_mod(fold_t *fold, ast_value *a, ast_value *b) {
-    if (fold_can_2(a, b))
-        return fold_constgen_float(fold, (qcfloat_t)(((qcint_t)fold_immvalue_float(a)) % ((qcint_t)fold_immvalue_float(b))));
+    if (fold_can_2(a, b)) {
+        if (fold_can_div(b))
+            return fold_constgen_float(fold, (qcfloat_t)(((qcint_t)fold_immvalue_float(a)) % ((qcint_t)fold_immvalue_float(b))));
+        else
+            return (ast_expression*)fold->imm_float[3]; /* inf */
+    }
     return NULL;
 }
 
@@ -610,6 +649,12 @@ static GMQCC_INLINE ast_expression *fold_op_bnot(fold_t *fold, ast_value *a) {
     return NULL;
 }
 
+static GMQCC_INLINE ast_expression *fold_op_cross(fold_t *fold, ast_value *a, ast_value *b) {
+    if (fold_can_2(a, b))
+        return fold_constgen_vector(fold, vec3_cross(fold_immvalue_vector(a), fold_immvalue_vector(b)));
+    return NULL;
+}
+
 ast_expression *fold_op(fold_t *fold, const oper_info *info, ast_expression **opexprs) {
     ast_value      *a = (ast_value*)opexprs[0];
     ast_value      *b = (ast_value*)opexprs[1];
@@ -667,69 +712,56 @@ ast_expression *fold_op(fold_t *fold, const oper_info *info, ast_expression **op
         fold_op_case(2, ('!', '='),    cmp,    (fold, a, b, true));
         fold_op_case(2, ('=', '='),    cmp,    (fold, a, b, false));
         fold_op_case(2, ('~', 'P'),    bnot,   (fold, a));
+        fold_op_case(2, ('>', '<'),    cross,  (fold, a, b));
     }
     #undef fold_op_case
     compile_error(fold_ctx(fold), "internal error: attempted to constant-fold for unsupported operator");
     return NULL;
 }
 
-#define expect(X)                                                                                        \
-    do {                                                                                                 \
-        if (vec_size(params) != (X)) {                                                                   \
-            compile_error(                                                                               \
-                fold_ctx(fold),                                                                          \
-                "internal error: attempted to constant-fold with invalid paramaters for intrinsic `%s`", \
-                intrin                                                                                   \
-            );                                                                                           \
-            return NULL;                                                                                 \
-        }                                                                                                \
-    } while (0)
-
-ast_expression *fold_intrin(fold_t *fold, const char *intrin, ast_expression **params) {
-    if (!fold)   return NULL;
-    if (!intrin) return NULL;
-
-    if (!strcmp(intrin, "__builtin_exp")) {
-        expect(1);
-        ++opts_optimizationcount[OPTIM_CONST_FOLD];
-        return fold_constgen_float(fold, exp(fold_immvalue_float((ast_value*)params[0])));
-    }
+/*
+ * Constant folding for compiler intrinsics, simaler approach to operator
+ * folding, primarly: individual functions for each intrinsics to fold,
+ * and a generic selection function.
+ */
+static GMQCC_INLINE ast_expression *fold_intrin_mod(fold_t *fold, ast_value *lhs, ast_value *rhs) {
+    return fold_constgen_float(
+                fold,
+                fmodf(
+                    fold_immvalue_float(lhs),
+                    fold_immvalue_float(rhs)
+                )
+            );
+}
 
-    if (!strcmp(intrin, "__builtin_mod")) {
-        expect(2);
-        ++opts_optimizationcount[OPTIM_CONST_FOLD];
-        return fold_constgen_float(
-                    fold,
-                    fmodf(
-                        fold_immvalue_float((ast_value*)params[0]),
-                        fold_immvalue_float((ast_value*)params[1])
-                    )
-                );
-    }
+static GMQCC_INLINE ast_expression *fold_intrin_pow(fold_t *fold, ast_value *lhs, ast_value *rhs) {
+    return fold_constgen_float(
+                fold,
+                powf(
+                    fold_immvalue_float(lhs),
+                    fold_immvalue_float(rhs)
+                )
+            );
+}
 
-    if (!strcmp(intrin, "__builtin_pow")) {
-        expect(2);
-        ++opts_optimizationcount[OPTIM_CONST_FOLD];
-        return fold_constgen_float(
-                    fold,
-                    powf(
-                        fold_immvalue_float((ast_value*)params[0]),
-                        fold_immvalue_float((ast_value*)params[1])
-                    )
-                );
-    }
+static GMQCC_INLINE ast_expression *fold_intrin_exp(fold_t *fold, ast_value *value) {
+    return fold_constgen_float(fold, exp(fold_immvalue_float(value)));
+}
 
-    if (!strcmp(intrin, "__builtin_isnan")) {
-        expect(1);
-        ++opts_optimizationcount[OPTIM_CONST_FOLD];
-        return fold_constgen_float(fold, isnan(fold_immvalue_float((ast_value*)params[0])) != 0.0f);
-    }
+static GMQCC_INLINE ast_expression *fold_intrin_isnan(fold_t *fold, ast_value *value) {
+    return fold_constgen_float(fold, isnan(fold_immvalue_float(value)) != 0.0f);
+}
 
-    if (!strcmp(intrin, "__builtin_fabs")) {
-        expect(1);
-        ++opts_optimizationcount[OPTIM_CONST_FOLD];
-        return fold_constgen_float(fold, fabs(fold_immvalue_float((ast_value*)params[0])));
-    }
+static GMQCC_INLINE ast_expression *fold_intrin_fabs(fold_t *fold, ast_value *value) {
+    return fold_constgen_float(fold, fabs(fold_immvalue_float(value)));
+}
+
+ast_expression *fold_intrin(fold_t *fold, const char *intrin, ast_expression **arg) {
+    if (!strcmp(intrin, "mod"))   return fold_intrin_mod  (fold, (ast_value*)arg[0], (ast_value*)arg[1]);
+    if (!strcmp(intrin, "pow"))   return fold_intrin_pow  (fold, (ast_value*)arg[0], (ast_value*)arg[1]);
+    if (!strcmp(intrin, "exp"))   return fold_intrin_exp  (fold, (ast_value*)arg[0]);
+    if (!strcmp(intrin, "isnan")) return fold_intrin_isnan(fold, (ast_value*)arg[0]);
+    if (!strcmp(intrin, "fabs"))  return fold_intrin_fabs (fold, (ast_value*)arg[0]);
 
     return NULL;
 }
diff --git a/gmqcc.h b/gmqcc.h
index 86b0bffd6e861280294df032f14853d035aeda3c..d8ad37465ef0525ea2298a9eb484f7a6e9220f04 100644 (file)
--- a/gmqcc.h
+++ b/gmqcc.h
@@ -332,7 +332,6 @@ void *stat_mem_allocate  (size_t, size_t, const char *);
 bool  util_filexists     (const char *);
 bool  util_strupper      (const char *);
 bool  util_strdigit      (const char *);
-void  util_debug         (const char *, const char *, ...);
 void  util_endianswap    (void *,  size_t, unsigned int);
 
 size_t util_strtocmd         (const char *, char *, size_t);
@@ -726,7 +725,8 @@ enum {
     VINSTR_BITOR_VF,
     VINSTR_BITXOR,
     VINSTR_BITXOR_V,
-    VINSTR_BITXOR_VF /* BITXOR_VF must be the last emulated bitop */
+    VINSTR_BITXOR_VF,
+    VINSTR_CROSS
 };
 
 /* TODO: elide */
index 7e7e69e4a204022cfd3bb966f5983515ee5237c4..d713df0f4000f0786353ea4d5de3239073986916 100644 (file)
--- a/intrin.c
+++ b/intrin.c
@@ -409,12 +409,12 @@ ast_expression *intrin_debug_typestring(intrin_t *intrin) {
 }
 
 static const intrin_func_t intrinsics[] = {
-    {&intrin_exp,              "__builtin_exp",              "exp"},
-    {&intrin_mod,              "__builtin_mod",              "mod"},
-    {&intrin_pow,              "__builtin_pow",              "pow"},
-    {&intrin_isnan,            "__builtin_isnan",            "isnan"},
-    {&intrin_fabs,             "__builtin_fabs",             "fabs"},
-    {&intrin_debug_typestring, "__builtin_debug_typestring", ""}
+    {&intrin_exp,              "__builtin_exp",              "exp",   1},
+    {&intrin_mod,              "__builtin_mod",              "mod",   2},
+    {&intrin_pow,              "__builtin_pow",              "pow",   2},
+    {&intrin_isnan,            "__builtin_isnan",            "isnan", 1},
+    {&intrin_fabs,             "__builtin_fabs",             "fabs",  1},
+    {&intrin_debug_typestring, "__builtin_debug_typestring", "",      0}
 };
 
 static void intrin_error(intrin_t *intrin, const char *fmt, ...) {
@@ -447,9 +447,14 @@ ast_expression *intrin_fold(intrin_t *intrin, ast_value *value, ast_expression *
     if (!value || !value->name)
         return NULL;
 
-    for (i = 0; i < vec_size(intrin->intrinsics); i++)
-        if (!strcmp(value->name, intrin->intrinsics[i].name))
-            return fold_intrin(intrin->fold, value->name, exprs);
+    for (i = 0; i < vec_size(intrin->intrinsics); i++) {
+        if (!strcmp(value->name, intrin->intrinsics[i].name)) {
+            if (intrin->intrinsics[i].args != vec_size(exprs))
+                return NULL;
+            /* +10 to skip the "__builtin_" substring in the string */
+            return fold_intrin(intrin->fold, value->name + 10, exprs);
+        }
+    }
 
     return NULL;
 }
diff --git a/ir.c b/ir.c
index 3efad3da81164b9064c882e5c11179ace81e9463..4b7442e9ccf1a73fb714ee7be4554039b0f293b2 100644 (file)
--- a/ir.c
+++ b/ir.c
@@ -613,7 +613,7 @@ static bool instr_is_operation(uint16_t op)
              (op >= INSTR_NOT_F  && op <= INSTR_NOT_FNC) ||
              (op >= INSTR_AND    && op <= INSTR_BITOR) ||
              (op >= INSTR_CALL0  && op <= INSTR_CALL8) ||
-             (op >= VINSTR_BITAND_V && op <= VINSTR_BITXOR_VF) );
+             (op >= VINSTR_BITAND_V && op <= VINSTR_CROSS) );
 }
 
 static bool ir_function_pass_peephole(ir_function *self)
@@ -1815,6 +1815,7 @@ ir_value* ir_block_create_binop(ir_block *self, lex_ctx_t ctx,
         case VINSTR_BITAND_VF:
         case VINSTR_BITOR_VF:
         case VINSTR_BITXOR_VF:
+        case VINSTR_CROSS:
 #if 0
         case INSTR_DIV_VF:
         case INSTR_MUL_IV:
@@ -2518,7 +2519,8 @@ static bool ir_block_life_propagate(ir_block *self, bool *changed)
             instr->opcode == VINSTR_BITOR_VF ||
             instr->opcode == VINSTR_BITXOR ||
             instr->opcode == VINSTR_BITXOR_VF ||
-            instr->opcode == VINSTR_BITXOR_V)
+            instr->opcode == VINSTR_BITXOR_V ||
+            instr->opcode == VINSTR_CROSS)
         {
             value = instr->_ops[2];
             /* the float source will get an additional lifetime */
@@ -2532,7 +2534,8 @@ static bool ir_block_life_propagate(ir_block *self, bool *changed)
             instr->opcode == INSTR_LOAD_V ||
             instr->opcode == VINSTR_BITXOR ||
             instr->opcode == VINSTR_BITXOR_VF ||
-            instr->opcode == VINSTR_BITXOR_V)
+            instr->opcode == VINSTR_BITXOR_V ||
+            instr->opcode == VINSTR_CROSS)
         {
             value = instr->_ops[1];
             /* the float source will get an additional lifetime */
@@ -2960,6 +2963,28 @@ static bool gen_blocks_recursive(code_t *code, ir_function *func, ir_block *bloc
             continue;
         }
 
+        if (instr->opcode == VINSTR_CROSS) {
+            stmt.opcode = INSTR_MUL_F;
+            for (j = 0; j < 3; ++j) {
+                stmt.o1.s1 = ir_value_code_addr(instr->_ops[1]) + (j + 1) % 3;
+                stmt.o2.s1 = ir_value_code_addr(instr->_ops[2]) + (j + 2) % 3;
+                stmt.o3.s1 = ir_value_code_addr(instr->_ops[0]) + j;
+                code_push_statement(code, &stmt, instr->context);
+                stmt.o1.s1 = ir_value_code_addr(instr->_ops[1]) + (j + 2) % 3;
+                stmt.o2.s1 = ir_value_code_addr(instr->_ops[2]) + (j + 1) % 3;
+                stmt.o3.s1 = ir_value_code_addr(func->owner->vinstr_temp[0]) + j;
+                code_push_statement(code, &stmt, instr->context);
+            }
+            stmt.opcode = INSTR_SUB_V;
+            stmt.o1.s1 = ir_value_code_addr(instr->_ops[0]);
+            stmt.o2.s1 = ir_value_code_addr(func->owner->vinstr_temp[0]);
+            stmt.o3.s1 = ir_value_code_addr(instr->_ops[0]);
+            code_push_statement(code, &stmt, instr->context);
+
+            /* instruction generated */
+            continue;
+        }
+
         if (instr->opcode == VINSTR_COND) {
             ontrue  = instr->bops[0];
             onfalse = instr->bops[1];
@@ -3959,6 +3984,7 @@ static const char *qc_opname(int op)
         case VINSTR_BITAND_VF: return "BITAND_VF";
         case VINSTR_BITOR_VF:  return "BITOR_VF";
         case VINSTR_BITXOR_VF: return "BITXOR_VF";
+        case VINSTR_CROSS:     return "CROSS";
         default:               return "<UNK>";
     }
 }
diff --git a/lexer.c b/lexer.c
index af7819dd802016e0870843c5b6b85ded5d5efc59..7642d261b89b4b3b9eae3e8fa6c4c1ec0751b96e 100644 (file)
--- a/lexer.c
+++ b/lexer.c
@@ -1306,7 +1306,7 @@ int lex_do(lex_file *lex)
     }
 
     if (ch == '+' || ch == '-' || /* ++, --, +=, -=  and -> as well! */
-        ch == '>' || ch == '<' || /* <<, >>, <=, >=                  */
+        ch == '>' || ch == '<' || /* <<, >>, <=, >=  and >< as well! */
         ch == '=' || ch == '!' || /* <=>, ==, !=                     */
         ch == '&' || ch == '|' || /* &&, ||, &=, |=                  */
         ch == '~' || ch == '^'    /* ~=, ~, ^                        */
@@ -1314,7 +1314,9 @@ int lex_do(lex_file *lex)
         lex_tokench(lex, ch);
 
         nextch = lex_getch(lex);
-        if ((nextch == '=' && ch != '<') || (nextch == ch && ch != '!')) {
+        if ((nextch == '=' && ch != '<') ||
+            (nextch == ch  && ch != '!') ||
+            (nextch == '<' && ch == '>')) {
             lex_tokench(lex, nextch);
         } else if (ch == '<' && nextch == '=') {
             lex_tokench(lex, nextch);
@@ -1517,6 +1519,6 @@ int lex_do(lex_file *lex)
         return (lex->tok.ttype = ch);
     }
 
-    lexerror(lex, "unknown token: `%s`", lex->tok.value);
+    lexerror(lex, "unknown token: `%c`", ch);
     return (lex->tok.ttype = TOKEN_ERROR);
 }
diff --git a/lexer.h b/lexer.h
index 48ab4b6e17b0a3b7af2aea2d6cbbb66af28ffee7..24e29ddee4080659be406da5f073ef041ecdb115 100644 (file)
--- a/lexer.h
+++ b/lexer.h
@@ -196,6 +196,7 @@ static const oper_info c_operators[] = {
     { "*",   2, opid1('*'),         ASSOC_LEFT,  13, 0,         true},
     { "/",   2, opid1('/'),         ASSOC_LEFT,  13, 0,         true},
     { "%",   2, opid1('%'),         ASSOC_LEFT,  13, 0,         true},
+    { "><",  2, opid2('>','<'),     ASSOC_LEFT,  13, 0,         true},
 
     { "+",   2, opid1('+'),         ASSOC_LEFT,  12, 0,         true},
     { "-",   2, opid1('-'),         ASSOC_LEFT,  12, 0,         true},
diff --git a/main.c b/main.c
index eab582dc5cae10d3b19db19c697c7130a870f7ee..33bde557176bf0d3a5c6ab9a4077551334f37606 100644 (file)
--- a/main.c
+++ b/main.c
@@ -650,8 +650,6 @@ int main(int argc, char **argv) {
         }
     }
 
-    util_debug("COM", "starting ...\n");
-
     /* add macros */
     if (OPTS_OPTION_BOOL(OPTION_PP_ONLY) || OPTS_FLAG(FTEPP)) {
         for (itr = 0; itr < vec_size(ppems); itr++) {
@@ -772,7 +770,6 @@ int main(int argc, char **argv) {
     }
 
 cleanup:
-    util_debug("COM", "cleaning ...\n");
     if (ftepp)
         ftepp_finish(ftepp);
     con_close();
index 1cd74dd8ef49c9141e005abccc4280b376869d0c..d65eafe714eb6c8a78a752e896642cb95eb7b2cb 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -282,6 +282,21 @@ static bool rotate_entfield_array_index_nodes(ast_expression **out)
     return true;
 }
 
+static bool check_write_to(lex_ctx_t ctx, ast_expression *expr)
+{
+    if (ast_istype(expr, ast_value)) {
+        ast_value *val = (ast_value*)expr;
+        if (val->cvq == CV_CONST) {
+            if (val->name[0] == '#')
+                compile_error(ctx, "invalid assignment to a literal constant");
+            else
+                compile_error(ctx, "assignment to constant `%s`", val->name);
+            return false;
+        }
+    }
+    return true;
+}
+
 static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
 {
     const oper_info *op;
@@ -289,7 +304,6 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
     ast_expression *out = NULL;
     ast_expression *exprs[3];
     ast_block      *blocks[3];
-    ast_value      *asvalue[3];
     ast_binstore   *asbinstore;
     size_t i, assignop, addop, subop;
     qcint_t  generated_op = 0;
@@ -311,8 +325,10 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
     ctx = vec_last(sy->ops).ctx;
 
     if (vec_size(sy->out) < op->operands) {
-        compile_error(ctx, "internal error: not enough operands: %i (operator %s (%i))", vec_size(sy->out),
-                      op->op, (int)op->id);
+        if (op->flags & OP_PREFIX)
+            compile_error(ctx, "expected expression after unary operator `%s`", op->op, (int)op->id);
+        else /* this should have errored previously already */
+            compile_error(ctx, "expected expression after operator `%s`", op->op, (int)op->id);
         return false;
     }
 
@@ -326,7 +342,6 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
     for (i = 0; i < op->operands; ++i) {
         exprs[i]  = sy->out[vec_size(sy->out)+i].out;
         blocks[i] = sy->out[vec_size(sy->out)+i].block;
-        asvalue[i] = (ast_value*)exprs[i];
 
         if (exprs[i]->vtype == TYPE_NOEXPR &&
             !(i != 0 && op->id == opid2('?',':')) &&
@@ -747,6 +762,26 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
             }
             break;
 
+        case opid2('>', '<'):
+            if (NotSameType(TYPE_VECTOR)) {
+                ast_type_to_string(exprs[0], ty1, sizeof(ty1));
+                ast_type_to_string(exprs[1], ty2, sizeof(ty2));
+                compile_error(ctx, "invalid types used in cross product: %s and %s",
+                    ty1, ty2);
+                return false;
+            }
+
+            if (!(out = fold_op(parser->fold, op, exprs))) {
+                out = (ast_expression*)ast_binary_new(
+                        parser_ctx(parser),
+                        VINSTR_CROSS,
+                        exprs[0],
+                        exprs[1]
+                );
+            }
+
+            break;
+
         case opid3('<','=','>'): /* -1, 0, or 1 */
             if (NotSameType(TYPE_FLOAT)) {
                 ast_type_to_string(exprs[0], ty1, sizeof(ty1));
@@ -879,9 +914,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
                         compile_error(ctx, "invalid types in assignment: cannot assign %s to %s", ty2, ty1);
                 }
             }
-            if (ast_istype(exprs[0], ast_value) && asvalue[0]->cvq == CV_CONST) {
-                compile_error(ctx, "assignment to constant `%s`", asvalue[0]->name);
-            }
+            (void)check_write_to(ctx, exprs[0]);
             out = (ast_expression*)ast_store_new(ctx, assignop, exprs[0], exprs[1]);
             break;
         case opid3('+','+','P'):
@@ -896,9 +929,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
                 addop = INSTR_ADD_F;
             else
                 addop = INSTR_SUB_F;
-            if (ast_istype(exprs[0], ast_value) && asvalue[0]->cvq == CV_CONST) {
-                compile_error(ast_ctx(exprs[0]), "assignment to constant `%s`", asvalue[0]->name);
-            }
+            (void)check_write_to(ast_ctx(exprs[0]), exprs[0]);
             if (ast_istype(exprs[0], ast_entfield)) {
                 out = (ast_expression*)ast_binstore_new(ctx, INSTR_STOREP_F, addop,
                                                         exprs[0],
@@ -924,9 +955,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
                 addop = INSTR_SUB_F;
                 subop = INSTR_ADD_F;
             }
-            if (ast_istype(exprs[0], ast_value) && asvalue[0]->cvq == CV_CONST) {
-                compile_error(ast_ctx(exprs[0]), "assignment to constant `%s`", asvalue[0]->name);
-            }
+            (void)check_write_to(ast_ctx(exprs[0]), exprs[0]);
             if (ast_istype(exprs[0], ast_entfield)) {
                 out = (ast_expression*)ast_binstore_new(ctx, INSTR_STOREP_F, addop,
                                                         exprs[0],
@@ -953,9 +982,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
                               ty1, ty2);
                 return false;
             }
-            if (ast_istype(exprs[0], ast_value) && asvalue[0]->cvq == CV_CONST) {
-                compile_error(ctx, "assignment to constant `%s`", asvalue[0]->name);
-            }
+            (void)check_write_to(ctx, exprs[0]);
             if (ast_istype(exprs[0], ast_entfield))
                 assignop = type_storep_instr[exprs[0]->vtype];
             else
@@ -990,9 +1017,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
                               ty1, ty2);
                 return false;
             }
-            if (ast_istype(exprs[0], ast_value) && asvalue[0]->cvq == CV_CONST) {
-                compile_error(ctx, "assignment to constant `%s`", asvalue[0]->name);
-            }
+            (void)check_write_to(ctx, exprs[0]);
             if (ast_istype(exprs[0], ast_entfield))
                 assignop = type_storep_instr[exprs[0]->vtype];
             else
@@ -1036,9 +1061,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
                               ty1, ty2);
                 return false;
             }
-            if (ast_istype(exprs[0], ast_value) && asvalue[0]->cvq == CV_CONST) {
-                compile_error(ctx, "assignment to constant `%s`", asvalue[0]->name);
-            }
+            (void)check_write_to(ctx, exprs[0]);
             if (ast_istype(exprs[0], ast_entfield))
                 assignop = type_storep_instr[exprs[0]->vtype];
             else
@@ -1074,9 +1097,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
                 out = (ast_expression*)ast_binary_new(ctx, VINSTR_BITAND_V, exprs[0], exprs[1]);
             if (!out)
                 return false;
-            if (ast_istype(exprs[0], ast_value) && asvalue[0]->cvq == CV_CONST) {
-                compile_error(ctx, "assignment to constant `%s`", asvalue[0]->name);
-            }
+            (void)check_write_to(ctx, exprs[0]);
             if (exprs[0]->vtype == TYPE_FLOAT)
                 asbinstore = ast_binstore_new(ctx, assignop, INSTR_SUB_F, exprs[0], out);
             else
@@ -1664,7 +1685,7 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma
                 }
             }
             if (o == operator_count) {
-                compile_error(parser_ctx(parser), "unknown operator: %s", parser_tokval(parser));
+                compile_error(parser_ctx(parser), "unexpected operator: %s", parser_tokval(parser));
                 goto onerr;
             }
             /* found an operator */
@@ -1898,7 +1919,7 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma
 
     parser->lex->flags.noops = true;
     if (vec_size(sy.out) != 1) {
-        parseerror(parser, "expression with not 1 but %lu output values...", (unsigned long) vec_size(sy.out));
+        parseerror(parser, "expression expected");
         expr = NULL;
     } else
         expr = sy.out[0].out;
@@ -4657,6 +4678,11 @@ static ast_value *parse_arraysize(parser_t *parser, ast_value *var)
  * The base type makes up every bit of type information which comes *before* the
  * variable name.
  *
+ * NOTE: The value must either be named, have a NULL name, or a name starting
+ *       with '<'. In the first case, this will be the actual variable or type
+ *       name, in the other cases it is assumed that the name will appear
+ *       later, and an error is generated otherwise.
+ *
  * The following will be parsed in its entirety:
  *     void() foo()
  * The 'basetype' in this case is 'void()'
@@ -4817,6 +4843,13 @@ static bool parse_typedef(parser_t *parser)
     if (!typevar)
         return false;
 
+    /* while parsing types, the ast_value's get named '<something>' */
+    if (!typevar->name || typevar->name[0] == '<') {
+        parseerror(parser, "missing name in typedef");
+        ast_delete(typevar);
+        return false;
+    }
+
     if ( (old = parser_find_var(parser, typevar->name)) ) {
         parseerror(parser, "cannot define a type with the same name as a variable: %s\n"
                    " -> `%s` has been declared here: %s:%i",
@@ -4982,6 +5015,14 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield
         return false;
     }
 
+    /* while parsing types, the ast_value's get named '<something>' */
+    if (!var->name || var->name[0] == '<') {
+        parseerror(parser, "declaration does not declare anything");
+        if (basetype)
+            ast_delete(basetype);
+        return false;
+    }
+
     while (true) {
         proto = NULL;
         wasarray = false;
index d4c8dddd5e65c80c2fa70de221ddd6d9123c1c39..c34d39baba108d68808873630651d5230a3cbaaf 100644 (file)
--- a/parser.h
+++ b/parser.h
@@ -43,6 +43,7 @@ typedef struct {
     ast_expression *(*intrin)(intrin_t *);
     const char       *name;
     const char       *alias;
+    size_t            args;
 } intrin_func_t;
 
 struct intrin_s {
diff --git a/test.c b/test.c
index 4c149316acb90689010e4918d9911a8d13f74e6c..fdf3777f4f0af16363a5f6170ab2749742240f16 100644 (file)
--- a/test.c
+++ b/test.c
@@ -736,7 +736,6 @@ static bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
                 char            *qcflags = NULL;
                 task_t           task;
 
-                util_debug("TEST", "compiling task template: %s/%s\n", directories[i], files->d_name);
                 found ++;
                 if (!tmpl) {
                     con_err("error compiling task template: %s\n", files->d_name);
@@ -847,8 +846,6 @@ static bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
                     continue;
                 }
 
-                util_debug("TEST", "executing test: `%s` [%s]\n", tmpl->description, buf);
-
                 /*
                  * Open up some file desciptors for logging the stdout/stderr
                  * to our own.
@@ -876,11 +873,6 @@ static bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
     }
     vec_free(directories);
 
-    util_debug("TEST", "compiled %d task template files out of %d\n",
-        vec_size(task_tasks),
-        found
-    );
-
     return success;
 }
 
@@ -903,8 +895,6 @@ static void task_precleanup(const char *curdir) {
             util_snprintf(buffer, sizeof(buffer), "%s/%s", curdir, files->d_name);
             if (remove(buffer))
                 con_err("error removing temporary file: %s\n", buffer);
-            else
-                util_debug("TEST", "removed temporary file: %s\n", buffer);
         }
     }
 
@@ -934,12 +924,8 @@ static void task_destroy(void) {
         if (task_tasks[i].compiled || !strcmp(task_tasks[i].tmpl->proceduretype, "-fail")) {
             if (remove(task_tasks[i].stdoutlogfile))
                 con_err("error removing stdout log file: %s\n", task_tasks[i].stdoutlogfile);
-            else
-                util_debug("TEST", "removed stdout log file: %s\n", task_tasks[i].stdoutlogfile);
             if (remove(task_tasks[i].stderrlogfile))
                 con_err("error removing stderr log file: %s\n", task_tasks[i].stderrlogfile);
-            else
-                util_debug("TEST", "removed stderr log file: %s\n", task_tasks[i].stderrlogfile);
 
             (void)!remove(task_tasks[i].tmpl->tempfilename);
         }
@@ -987,11 +973,6 @@ static bool task_trymatch(size_t i, char ***line) {
             );
         }
 
-        util_debug("TEST", "executing qcvm: `%s` [%s]\n",
-            tmpl->description,
-            buffer
-        );
-
         execute = popen(buffer, "r");
         if (!execute)
             return false;
@@ -1138,7 +1119,6 @@ static size_t task_schedualize(size_t *pad) {
 
         con_out("test #%u %*s", i + 1, strlen(space[0]) - strlen(space[1]), "");
 
-        util_debug("TEST", "executing task: %d: %s\n", i, task_tasks[i].tmpl->description);
         /*
          * Generate a task from thin air if it requires execution in
          * the QCVM.
index 509dc3a6a1c36a42fbf532ad1b63b2a44c4ce641..d06d5799dd0e39819756ffe048010e1d997ce34d 100644 (file)
@@ -8,4 +8,5 @@ void main(vector v) {
     print(vtos(v & 16), "\n");
     print(vtos(v | '25 42 51'), "\n");
     print(vtos(v & '25 42 51'), "\n");
+    print(vtos(v >< '3 2 1'));
 }
index 79432325d3b52ae2032fca3d7a300074245c76c1..738ec46ba97a44116005c235d19a379b25958b88 100644 (file)
@@ -1,7 +1,7 @@
 I: vec_ops.qc
 D: some additional vector operations
 T: -execute
-C: -std=fteqcc
+C: -std=gmqcc
 E: -vector "8 16 32"
 M: '8 16 32'
 M: '4 8 16'
@@ -11,3 +11,4 @@ M: '20 24 16'
 M: '0 0 16'
 M: '29 42 51'
 M: '0 8 16'
+M: '-24 44 -16'
diff --git a/util.c b/util.c
index 6a701e4557a1f4a8943453802445128bfcc350d9..9b32e48394806022e2ab2f0e9c7446aeb211cae1 100644 (file)
--- a/util.c
+++ b/util.c
@@ -54,20 +54,6 @@ const char *util_instr_str[VINSTR_END] = {
     "BITAND",     "BITOR"
 };
 
-void util_debug(const char *area, const char *ms, ...) {
-    va_list  va;
-    if (!OPTS_OPTION_BOOL(OPTION_DEBUG))
-        return;
-
-    if (!strcmp(area, "MEM") && !OPTS_OPTION_BOOL(OPTION_MEMCHK))
-        return;
-
-    va_start(va, ms);
-    con_out ("[%s] ", area);
-    con_vout(ms, va);
-    va_end  (va);
-}
-
 /*
  * only required if big endian .. otherwise no need to swap
  * data.