From: Dale Weiler Date: Sun, 8 Sep 2013 17:05:20 +0000 (-0400) Subject: Merge branch 'master' into cooking X-Git-Tag: 0.3.5~102 X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=commitdiff_plain;h=c2cf41baf95c7a45789e4c73202928baf9e9b650;hp=9908209f5825821eb8c73ff4926bc2b504848792 Merge branch 'master' into cooking --- diff --git a/ast.c b/ast.c index 2f1566b..3531ada 100644 --- 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 f3d60ff..5703e50 100644 --- 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 f8a143c..98e637a 100644 --- 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 86b0bff..d8ad374 100644 --- 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 */ diff --git a/intrin.c b/intrin.c index 7e7e69e..d713df0 100644 --- 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 3efad3d..4b7442e 100644 --- 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 ""; } } diff --git a/lexer.c b/lexer.c index af7819d..7642d26 100644 --- 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 48ab4b6..24e29dd 100644 --- 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 eab582d..33bde55 100644 --- 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(); diff --git a/parser.c b/parser.c index 1cd74dd..d65eafe 100644 --- 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 '' */ + 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 '' */ + 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; diff --git a/parser.h b/parser.h index d4c8ddd..c34d39b 100644 --- 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 4c14931..fdf3777 100644 --- 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. diff --git a/tests/vec_ops.qc b/tests/vec_ops.qc index 509dc3a..d06d579 100644 --- a/tests/vec_ops.qc +++ b/tests/vec_ops.qc @@ -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')); } diff --git a/tests/vec_ops.tmpl b/tests/vec_ops.tmpl index 7943232..738ec46 100644 --- a/tests/vec_ops.tmpl +++ b/tests/vec_ops.tmpl @@ -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 6a701e4..9b32e48 100644 --- 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.