From: Dale Weiler Date: Wed, 31 Jul 2013 09:04:19 +0000 (+0000) Subject: Work in progress constant-folding rewrite. X-Git-Tag: v0.3.0~54 X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=commitdiff_plain;h=920dbaf1e09f6dce8cc8dd703ed2bfdec62fae38 Work in progress constant-folding rewrite. --- diff --git a/fold.c b/fold.c new file mode 100644 index 0000000..26b5985 --- /dev/null +++ b/fold.c @@ -0,0 +1,359 @@ +/* + * Copyright (C) 2012, 2013 + * Dale Weiler + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include +#include "ast.h" +#include "parser.h" + +#define FOLD_STRING_UNTRANSLATE_HTSIZE 1024 +#define FOLD_STRING_DOTRANSLATE_HTSIZE 1024 + +/* + * There is two stages to constant folding in GMQCC: there is the parse + * stage constant folding, where, witht he help of the AST, operator + * usages can be constant folded. Then there is the constant folding + * in the IR for things like eliding if statements, can occur. + * + * This file is thus, split into two parts. + */ +ast_expression **fold_const_values = NULL; + +static GMQCC_INLINE bool fold_possible(const ast_value *val) { + return ast_istype((ast_expression*)val, ast_value) && + val->hasvalue && (val->cvq == CV_CONST) && + ((ast_expression*)val)->vtype != TYPE_FUNCTION; /* why not for functions? */ +} + +#define isfloat(X) (((ast_expression*)(X))->vtype == TYPE_FLOAT && fold_possible(X)) +#define isvector(X) (((ast_expression*)(X))->vtype == TYPE_VECTOR && fold_possible(X)) +#define isstring(S) (((ast_expression*)(X))->vtype == TYPE_STRING && fold_possible(X)) +#define isfloats(X,Y) (isfloat (X) && isfloat(Y)) +#define isvectors(X,Y) (isvector(X) && isvector(Y)) +#define isstrings(X,Y) (isstring(X) && isstring(Y)) + +/* + * Implementation of basic vector math for vec3_t, for trivial constant + * folding. + * + * TODO: gcc/clang hinting for autovectorization + */ +static GMQCC_INLINE vec3_t vec3_add(vec3_t a, vec3_t b) { + vec3_t out; + out.x = a.x + b.x; + out.y = a.y + b.y; + out.z = a.z + b.z; + return out; +} + +static GMQCC_INLINE vec3_t vec3_sub(vec3_t a, vec3_t b) { + vec3_t out; + out.x = a.x + b.x; + out.y = a.y + b.y; + out.z = a.z + b.z; + return out; +} + +static GMQCC_INLINE vec3_t vec3_not(vec3_t a) { + vec3_t out; + out.x = !a.x; + out.y = !a.y; + out.z = !a.z; + return out; +} + +static GMQCC_INLINE vec3_t vec3_neg(vec3_t a) { + vec3_t out; + out.x = -a.x; + out.y = -a.y; + out.z = -a.z; + return out; +} + +static GMQCC_INLINE vec3_t vec3_xor(vec3_t a, vec3_t b) { + vec3_t out; + out.x = (qcfloat_t)((qcint_t)a.x ^ (qcint_t)b.x); + out.y = (qcfloat_t)((qcint_t)a.y ^ (qcint_t)b.y); + out.z = (qcfloat_t)((qcint_t)a.z ^ (qcint_t)b.z); + return out; +} + +static GMQCC_INLINE vec3_t vec3_xorvf(vec3_t a, qcfloat_t b) { + vec3_t out; + out.x = (qcfloat_t)((qcint_t)a.x ^ (qcint_t)b); + out.y = (qcfloat_t)((qcint_t)a.y ^ (qcint_t)b); + out.z = (qcfloat_t)((qcint_t)a.z ^ (qcint_t)b); + return out; +} + +#if 0 +static GMQCC_INLINE qcfloat_t vec3_mulvv(vec3_t a, vec3_t b) { + return (a.x * b.x + a.y * b.y + a.z * b.z); +} +#endif + +static GMQCC_INLINE vec3_t vec3_mulvf(vec3_t a, qcfloat_t b) { + vec3_t out; + out.x = a.x * b; + out.y = a.y * b; + out.z = a.z * b; + return out; +} + +static GMQCC_INLINE bool vec3_cmp(vec3_t a, vec3_t b) { + return a.x == b.x && + a.y == b.y && + a.z == b.z; +} + +static GMQCC_INLINE vec3_t vec3_create(float x, float y, float z) { + vec3_t out; + out.x = x; + out.y = y; + out.z = z; + return out; +} + + +static GMQCC_INLINE float fold_immvalue_float(ast_value *expr) { + return expr->constval.vfloat; +} +static GMQCC_INLINE vec3_t fold_immvalue_vector(ast_value *expr) { + return expr->constval.vvec; +} +#if 0 +static GMQCC_INLINE const char *fold_immvalue_string(ast_value *expr) { + return expr->constval.vstring; +} +#endif + + +fold_t *fold_init(parser_t *parser) { + fold_t *fold = (fold_t*)mem_a(sizeof(fold_t)); + fold->parser = parser; + fold->imm_float = NULL; + fold->imm_vector = NULL; + fold->imm_string = NULL; + fold->imm_string_untranslate = util_htnew(FOLD_STRING_UNTRANSLATE_HTSIZE); + fold->imm_string_dotranslate = util_htnew(FOLD_STRING_DOTRANSLATE_HTSIZE); + + /* + * prime the tables with common constant values at constant + * locations. + */ + (void)fold_constgen_float (fold, 0.0f); + (void)fold_constgen_float (fold, 1.0f); + (void)fold_constgen_float (fold, -1.0f); + + (void)fold_constgen_vector(fold, vec3_create(0.0f, 0.0f, 0.0f)); + + return fold; +} + +bool fold_generate(fold_t *fold, ir_builder *ir) { + /* generate globals for immediate folded values */ + size_t i; + ast_value *cur; + + for (i = 0; i < vec_size(fold->imm_float); ++i) + if (!ast_global_codegen ((cur = fold->imm_float[i]), ir, false)) goto err; + for (i = 0; i < vec_size(fold->imm_vector); ++i) + if (!ast_global_codegen((cur = fold->imm_vector[i]), ir, false)) goto err; + for (i = 0; i < vec_size(fold->imm_string); ++i) + if (!ast_global_codegen((cur = fold->imm_string[i]), ir, false)) goto err; + + return true; + +err: + con_out("failed to generate global %s\n", cur->name); + ir_builder_delete(ir); + return false; +} + +void fold_cleanup(fold_t *fold) { + size_t i; + + for (i = 0; i < vec_size(fold->imm_float); ++i) ast_delete(fold->imm_float[i]); + for (i = 0; i < vec_size(fold->imm_vector); ++i) ast_delete(fold->imm_vector[i]); + for (i = 0; i < vec_size(fold->imm_string); ++i) ast_delete(fold->imm_string[i]); + + vec_free(fold->imm_float); + vec_free(fold->imm_vector); + vec_free(fold->imm_string); + + util_htdel(fold->imm_string_untranslate); + util_htdel(fold->imm_string_dotranslate); + + mem_d(fold); +} + +static lex_ctx_t fold_ctx(fold_t *fold) { + lex_ctx_t ctx; + if (fold->parser->lex) + return parser_ctx(fold->parser); + + memset(&ctx, 0, sizeof(ctx)); + return ctx; +} + +ast_expression *fold_constgen_float(fold_t *fold, qcfloat_t value) { + ast_value *out = NULL; + size_t i; + + for (i = 0; i < vec_size(fold->imm_float); i++) { + if (fold->imm_float[i]->constval.vfloat == value) + return (ast_expression*)fold->imm_float[i]; + } + + out = ast_value_new(fold_ctx(fold), "#IMMEDIATE", TYPE_FLOAT); + out->cvq = CV_CONST; + out->hasvalue = true; + out->constval.vfloat = value; + + vec_push(fold->imm_float, out); + + return (ast_expression*)out; +} + +ast_expression *fold_constgen_vector(fold_t *fold, vec3_t value) { + ast_value *out; + size_t i; + + for (i = 0; i < vec_size(fold->imm_vector); i++) { + if (vec3_cmp(fold->imm_vector[i]->constval.vvec, value)) + return (ast_expression*)fold->imm_vector[i]; + } + + out = ast_value_new(fold_ctx(fold), "#IMMEDIATE", TYPE_VECTOR); + out->cvq = CV_CONST; + out->hasvalue = true; + out->constval.vvec = value; + + vec_push(fold->imm_vector, out); + + return (ast_expression*)out; +} + +ast_expression *fold_constgen_string(fold_t *fold, const char *str, bool translate) { + hash_table_t *table = (translate) ? fold->imm_string_untranslate : fold->imm_string_dotranslate; + ast_value *out = NULL; + size_t hash = util_hthash(table, str); + + if ((out = (ast_value*)util_htgeth(table, str, hash))) + return (ast_expression*)out; + + if (translate) { + char name[32]; + util_snprintf(name, sizeof(name), "dotranslate_%lu", (unsigned long)(fold->parser->translated++)); + out = ast_value_new(parser_ctx(fold->parser), name, TYPE_STRING); + out->expression.flags |= AST_FLAG_INCLUDE_DEF; /* def needs to be included for translatables */ + } else + out = ast_value_new(fold_ctx(fold), "#IMMEDIATE", TYPE_STRING); + + out->cvq = CV_CONST; + out->hasvalue = true; + out->isimm = true; + out->constval.vstring = parser_strdup(str); + + vec_push(fold->imm_string, out); + util_htseth(table, str, hash, out); + + return (ast_expression*)out; +} + +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]; + ast_value *c = (ast_value*)opexprs[2]; + + /* can a fold operation be applied to this operator usage? */ + if (!info->folds) + return NULL; + + switch(info->operands) { + case 3: if(!c) return NULL; + case 2: if(!b) return NULL; + } + + switch(info->id) { + case opid2('-', 'P'): + return isfloat (a) ? fold_constgen_float (fold, fold_immvalue_float(a)) + : isvector(a) ? fold_constgen_vector(fold, vec3_neg(fold_immvalue_vector(a))) + : NULL; + case opid2('!', 'P'): + return isfloat (a) ? fold_constgen_float (fold, !fold_immvalue_float(a)) + : isvector(a) ? fold_constgen_vector(fold, vec3_not(fold_immvalue_vector(a))) + : NULL; + case opid1('+'): + return isfloats(a,b) ? fold_constgen_float (fold, fold_immvalue_float(a) + fold_immvalue_float(b)) + : isvectors(a,b) ? fold_constgen_vector(fold, vec3_add(fold_immvalue_vector(a), fold_immvalue_vector(b))) + : NULL; + case opid1('-'): + return isfloats(a,b) ? fold_constgen_float (fold, fold_immvalue_float(a) - fold_immvalue_float(b)) + : isvectors(a,b) ? fold_constgen_vector(fold, vec3_sub(fold_immvalue_vector(a), fold_immvalue_vector(b))) + : NULL; + case opid1('*'): + if (isfloat(a)) + return isvector(b) ? fold_constgen_vector(fold, vec3_mulvf(fold_immvalue_vector(b), fold_immvalue_float(a))) + : fold_constgen_float (fold, fold_immvalue_float(a) * fold_immvalue_float(b)); + return NULL; + case opid1('/'): + return isfloats(a,b) ? fold_constgen_float (fold, fold_immvalue_float(a) / fold_immvalue_float(b)) + : isvector(a)&&isfloat(b) ? fold_constgen_vector(fold, vec3_mulvf(fold_immvalue_vector(a), 1.0f / fold_immvalue_float(b))) + : NULL; + case opid1('%'): + return isfloats(a,b) ? fold_constgen_float (fold, (qcfloat_t)(((qcint_t)fold_immvalue_float(a)) % ((qcint_t)fold_immvalue_float(b)))) + : NULL; + case opid1('|'): + return isfloats(a,b) ? fold_constgen_float (fold, (qcfloat_t)(((qcint_t)fold_immvalue_float(a)) | ((qcint_t)fold_immvalue_float(b)))) + : NULL; + case opid1('&'): + return isfloats(a,b) ? fold_constgen_float (fold, (qcfloat_t)(((qcint_t)fold_immvalue_float(a)) & ((qcint_t)fold_immvalue_float(b)))) + : NULL; + case opid1('^'): + return isfloats(a,b) ? fold_constgen_float (fold, (qcfloat_t)(((qcint_t)fold_immvalue_float(a)) ^ ((qcint_t)fold_immvalue_float(b)))) + : isvectors(a,b) ? fold_constgen_vector(fold, vec3_xor (fold_immvalue_vector(a), fold_immvalue_vector(b))) + : isvector(a)&&isfloat(b) ? fold_constgen_vector(fold, vec3_xorvf(fold_immvalue_vector(a), fold_immvalue_float (b))) + : NULL; + case opid2('<','<'): + return isfloats(a,b) ? fold_constgen_float (fold, (qcfloat_t)(((qcuint_t)(fold_immvalue_float(a)) << ((qcuint_t)fold_immvalue_float(b))))) + : NULL; + case opid2('>','>'): + return isfloats(a,b) ? fold_constgen_float (fold, (qcfloat_t)(((qcuint_t)(fold_immvalue_float(a)) >> ((qcuint_t)fold_immvalue_float(b))))) + : NULL; + case opid2('|','|'): return NULL; + case opid2('&','&'): return NULL; + case opid2('?',':'): return NULL; + case opid2('*','*'): return NULL; + case opid3('<','=','>'): return NULL; + case opid2('!','='): + return isfloats(a,b) ? fold_constgen_float (fold, fold_immvalue_float(a) != fold_immvalue_float(b)) + : NULL; + case opid2('=','='): + return isfloats(a,b) ? fold_constgen_float (fold, fold_immvalue_float(a) == fold_immvalue_float(b)) + : NULL; + case opid2('~','P'): + return isfloat(a) ? fold_constgen_float (fold, ~(qcint_t)fold_immvalue_float(a)) + : NULL; + break; + } + return NULL; +} diff --git a/gmqcc.h b/gmqcc.h index 2ab3a00..25eed13 100644 --- a/gmqcc.h +++ b/gmqcc.h @@ -713,9 +713,10 @@ enum { /* TODO: elide */ extern const char *util_instr_str[VINSTR_END]; -/* TOO: _t */ -typedef float qcfloat_t; -typedef int32_t qcint_t; + +typedef float qcfloat_t; +typedef int32_t qcint_t; +typedef uint32_t qcuint_t; typedef struct { prog_section_statement_t *statements; @@ -728,7 +729,7 @@ typedef struct { uint16_t crc; uint32_t entfields; ht string_cache; - qcint_t string_cached_empty; + qcint_t string_cached_empty; } code_t; /* @@ -824,11 +825,6 @@ typedef struct { qcfloat_t x, y, z; } vec3_t; -vec3_t vec3_add (vec3_t, vec3_t); -vec3_t vec3_sub (vec3_t, vec3_t); -qcfloat_t vec3_mulvv(vec3_t, vec3_t); -vec3_t vec3_mulvf(vec3_t, float); - /*===================================================================*/ /*============================= exec.c ==============================*/ /*===================================================================*/ diff --git a/include.mk b/include.mk index 3fa588d..77342d9 100644 --- a/include.mk +++ b/include.mk @@ -14,7 +14,7 @@ LDFLAGS += LIBS += -lm #objects -OBJ_C = main.o lexer.o parser.o fs.o stat.o util.o code.o ast.o ir.o conout.o ftepp.o opts.o utf8.o correct.o +OBJ_C = main.o lexer.o parser.o fs.o stat.o util.o code.o ast.o ir.o conout.o ftepp.o opts.o utf8.o correct.o fold.o OBJ_P = util.o fs.o conout.o opts.o pak.o stat.o OBJ_T = test.o util.o opts.o conout.o fs.o stat.o OBJ_X = exec-standalone.o util.o opts.o conout.o fs.o stat.o diff --git a/intrin.h b/intrin.h index 00464aa..1503d60 100644 --- a/intrin.h +++ b/intrin.h @@ -115,7 +115,7 @@ static ast_expression *intrin_pow (parser_t *parser) { parser_ctx(parser), INSTR_STORE_F, (ast_expression*)local, - (ast_expression*)parser_const_float_1(parser) + (ast_expression*)parser->fold->imm_float[1] /* 1 == 1.0f */ ) ); @@ -126,7 +126,7 @@ static ast_expression *intrin_pow (parser_t *parser) { INSTR_STORE_F, INSTR_MUL_F, (ast_expression*)arg2, - (ast_expression*)parser_const_float(parser, 0.25f) + (ast_expression*)fold_constgen_float(parser->fold, 0.25f) ) ); @@ -149,7 +149,7 @@ static ast_expression *intrin_pow (parser_t *parser) { parser_ctx(parser), INSTR_AND, (ast_expression*)arg2, - (ast_expression*)parser_const_float_1(parser) + (ast_expression*)parser->fold->imm_float[1] /* 1 == 1.0f */ ), true, /* ! not */ NULL, @@ -168,7 +168,7 @@ static ast_expression *intrin_pow (parser_t *parser) { INSTR_STORE_F, INSTR_SUB_F, (ast_expression*)arg2, - (ast_expression*)parser_const_float_1(parser) + (ast_expression*)parser->fold->imm_float[1] /* 1 == 1.0f */ ) ); /* local *= x */ @@ -190,7 +190,7 @@ static ast_expression *intrin_pow (parser_t *parser) { parser_ctx(parser), INSTR_GT, (ast_expression*)arg2, - (ast_expression*)parser_const_float_0(parser) + (ast_expression*)parser->fold->imm_float[0] /* 0 == 0.0f */ ), false, NULL, @@ -291,7 +291,7 @@ static ast_expression *intrin_exp(parser_t *parser) { INTRIN_VAL(value, "exp", func, "", TYPE_FLOAT); /* push arguments for params to call */ - vec_push(call->params, (ast_expression*)parser_const_float(parser, QC_M_E)); + vec_push(call->params, (ast_expression*)fold_constgen_float(parser->fold, QC_M_E)); vec_push(call->params, (ast_expression*)arg1); /* return pow(QC_M_E, x) */ diff --git a/lexer.h b/lexer.h index efbdd64..f490d2a 100644 --- a/lexer.h +++ b/lexer.h @@ -161,6 +161,7 @@ typedef struct { unsigned int assoc; signed int prec; unsigned int flags; + bool folds; } oper_info; /* @@ -173,168 +174,168 @@ typedef struct { #define opid3(a,b,c) (((uint8_t)a<<16)|((uint8_t)b<<8)|(uint8_t)c) static const oper_info c_operators[] = { - { "(", 0, opid1('('), ASSOC_LEFT, 99, OP_PREFIX}, /* paren expression - non function call */ + { "(", 0, opid1('('), ASSOC_LEFT, 99, OP_PREFIX, false}, /* paren expression - non function call */ - { "++", 1, opid3('S','+','+'), ASSOC_LEFT, 17, OP_SUFFIX}, - { "--", 1, opid3('S','-','-'), ASSOC_LEFT, 17, OP_SUFFIX}, - { ".", 2, opid1('.'), ASSOC_LEFT, 17, 0 }, - { "(", 0, opid1('('), ASSOC_LEFT, 17, 0 }, /* function call */ - { "[", 2, opid1('['), ASSOC_LEFT, 17, 0 }, /* array subscript */ + { "++", 1, opid3('S','+','+'), ASSOC_LEFT, 17, OP_SUFFIX, false}, + { "--", 1, opid3('S','-','-'), ASSOC_LEFT, 17, OP_SUFFIX, false}, + { ".", 2, opid1('.'), ASSOC_LEFT, 17, 0, false}, + { "(", 0, opid1('('), ASSOC_LEFT, 17, 0, false}, /* function call */ + { "[", 2, opid1('['), ASSOC_LEFT, 17, 0, false}, /* array subscript */ - { "++", 1, opid3('+','+','P'), ASSOC_RIGHT, 16, OP_PREFIX }, - { "--", 1, opid3('-','-','P'), ASSOC_RIGHT, 16, OP_PREFIX }, + { "++", 1, opid3('+','+','P'), ASSOC_RIGHT, 16, OP_PREFIX, false}, + { "--", 1, opid3('-','-','P'), ASSOC_RIGHT, 16, OP_PREFIX, false}, - { "**", 2, opid2('*', '*'), ASSOC_RIGHT, 15, 0 }, + { "**", 2, opid2('*', '*'), ASSOC_RIGHT, 15, 0, true}, - { "!", 1, opid2('!', 'P'), ASSOC_RIGHT, 14, OP_PREFIX }, - { "~", 1, opid2('~', 'P'), ASSOC_RIGHT, 14, OP_PREFIX }, - { "+", 1, opid2('+','P'), ASSOC_RIGHT, 14, OP_PREFIX }, - { "-", 1, opid2('-','P'), ASSOC_RIGHT, 14, OP_PREFIX }, -/* { "&", 1, opid2('&','P'), ASSOC_RIGHT, 14, OP_PREFIX }, */ + { "!", 1, opid2('!', 'P'), ASSOC_RIGHT, 14, OP_PREFIX, true}, + { "~", 1, opid2('~', 'P'), ASSOC_RIGHT, 14, OP_PREFIX, true}, + { "+", 1, opid2('+','P'), ASSOC_RIGHT, 14, OP_PREFIX, false}, + { "-", 1, opid2('-','P'), ASSOC_RIGHT, 14, OP_PREFIX, true}, +/* { "&", 1, opid2('&','P'), ASSOC_RIGHT, 14, OP_PREFIX, false}, */ - { "*", 2, opid1('*'), ASSOC_LEFT, 13, 0 }, - { "/", 2, opid1('/'), ASSOC_LEFT, 13, 0 }, - { "%", 2, opid1('%'), ASSOC_LEFT, 13, 0 }, + { "*", 2, opid1('*'), ASSOC_LEFT, 13, 0, true}, + { "/", 2, opid1('/'), ASSOC_LEFT, 13, 0, true}, + { "%", 2, opid1('%'), ASSOC_LEFT, 13, 0, true}, - { "+", 2, opid1('+'), ASSOC_LEFT, 12, 0 }, - { "-", 2, opid1('-'), ASSOC_LEFT, 12, 0 }, + { "+", 2, opid1('+'), ASSOC_LEFT, 12, 0, true}, + { "-", 2, opid1('-'), ASSOC_LEFT, 12, 0, true}, - { "<<", 2, opid2('<','<'), ASSOC_LEFT, 11, 0 }, - { ">>", 2, opid2('>','>'), ASSOC_LEFT, 11, 0 }, + { "<<", 2, opid2('<','<'), ASSOC_LEFT, 11, 0, true}, + { ">>", 2, opid2('>','>'), ASSOC_LEFT, 11, 0, true}, - { "<", 2, opid1('<'), ASSOC_LEFT, 10, 0 }, - { ">", 2, opid1('>'), ASSOC_LEFT, 10, 0 }, - { "<=>", 2, opid3('<','=','>'), ASSOC_LEFT, 10, 0 }, - { "<=", 2, opid2('<','='), ASSOC_LEFT, 10, 0 }, - { ">=", 2, opid2('>','='), ASSOC_LEFT, 10, 0 }, + { "<", 2, opid1('<'), ASSOC_LEFT, 10, 0, false}, + { ">", 2, opid1('>'), ASSOC_LEFT, 10, 0, false}, + { "<=>", 2, opid3('<','=','>'), ASSOC_LEFT, 10, 0, true}, + { "<=", 2, opid2('<','='), ASSOC_LEFT, 10, 0, false}, + { ">=", 2, opid2('>','='), ASSOC_LEFT, 10, 0, false}, - { "==", 2, opid2('=','='), ASSOC_LEFT, 9, 0 }, - { "!=", 2, opid2('!','='), ASSOC_LEFT, 9, 0 }, + { "==", 2, opid2('=','='), ASSOC_LEFT, 9, 0, false}, + { "!=", 2, opid2('!','='), ASSOC_LEFT, 9, 0, false}, - { "&", 2, opid1('&'), ASSOC_LEFT, 8, 0 }, + { "&", 2, opid1('&'), ASSOC_LEFT, 8, 0, true}, - { "^", 2, opid1('^'), ASSOC_LEFT, 7, 0 }, + { "^", 2, opid1('^'), ASSOC_LEFT, 7, 0, true}, - { "|", 2, opid1('|'), ASSOC_LEFT, 6, 0 }, + { "|", 2, opid1('|'), ASSOC_LEFT, 6, 0, true}, - { "&&", 2, opid2('&','&'), ASSOC_LEFT, 5, 0 }, + { "&&", 2, opid2('&','&'), ASSOC_LEFT, 5, 0, true}, - { "||", 2, opid2('|','|'), ASSOC_LEFT, 4, 0 }, + { "||", 2, opid2('|','|'), ASSOC_LEFT, 4, 0, true}, - { "?", 3, opid2('?',':'), ASSOC_RIGHT, 3, 0 }, + { "?", 3, opid2('?',':'), ASSOC_RIGHT, 3, 0, true}, - { "=", 2, opid1('='), ASSOC_RIGHT, 2, 0 }, - { "+=", 2, opid2('+','='), ASSOC_RIGHT, 2, 0 }, - { "-=", 2, opid2('-','='), ASSOC_RIGHT, 2, 0 }, - { "*=", 2, opid2('*','='), ASSOC_RIGHT, 2, 0 }, - { "/=", 2, opid2('/','='), ASSOC_RIGHT, 2, 0 }, - { "%=", 2, opid2('%','='), ASSOC_RIGHT, 2, 0 }, - { ">>=", 2, opid3('>','>','='), ASSOC_RIGHT, 2, 0 }, - { "<<=", 2, opid3('<','<','='), ASSOC_RIGHT, 2, 0 }, - { "&=", 2, opid2('&','='), ASSOC_RIGHT, 2, 0 }, - { "^=", 2, opid2('^','='), ASSOC_RIGHT, 2, 0 }, - { "|=", 2, opid2('|','='), ASSOC_RIGHT, 2, 0 }, - { "&~=", 2, opid3('&','~','='), ASSOC_RIGHT, 2, 0 }, + { "=", 2, opid1('='), ASSOC_RIGHT, 2, 0, false}, + { "+=", 2, opid2('+','='), ASSOC_RIGHT, 2, 0, false}, + { "-=", 2, opid2('-','='), ASSOC_RIGHT, 2, 0, false}, + { "*=", 2, opid2('*','='), ASSOC_RIGHT, 2, 0, false}, + { "/=", 2, opid2('/','='), ASSOC_RIGHT, 2, 0, true}, + { "%=", 2, opid2('%','='), ASSOC_RIGHT, 2, 0, false}, + { ">>=", 2, opid3('>','>','='), ASSOC_RIGHT, 2, 0, false}, + { "<<=", 2, opid3('<','<','='), ASSOC_RIGHT, 2, 0, false}, + { "&=", 2, opid2('&','='), ASSOC_RIGHT, 2, 0, false}, + { "^=", 2, opid2('^','='), ASSOC_RIGHT, 2, 0, false}, + { "|=", 2, opid2('|','='), ASSOC_RIGHT, 2, 0, false}, + { "&~=", 2, opid3('&','~','='), ASSOC_RIGHT, 2, 0, false}, - { ":", 0, opid2(':','?'), ASSOC_RIGHT, 1, 0 }, + { ":", 0, opid2(':','?'), ASSOC_RIGHT, 1, 0, false}, - { ",", 2, opid1(','), ASSOC_LEFT, 0, 0 } + { ",", 2, opid1(','), ASSOC_LEFT, 0, 0, false} }; static const size_t c_operator_count = (sizeof(c_operators) / sizeof(c_operators[0])); static const oper_info fte_operators[] = { - { "(", 0, opid1('('), ASSOC_LEFT, 99, OP_PREFIX}, /* paren expression - non function call */ - - { "++", 1, opid3('S','+','+'), ASSOC_LEFT, 15, OP_SUFFIX}, - { "--", 1, opid3('S','-','-'), ASSOC_LEFT, 15, OP_SUFFIX}, - { ".", 2, opid1('.'), ASSOC_LEFT, 15, 0 }, - { "(", 0, opid1('('), ASSOC_LEFT, 15, 0 }, /* function call */ - { "[", 2, opid1('['), ASSOC_LEFT, 15, 0 }, /* array subscript */ - - { "!", 1, opid2('!', 'P'), ASSOC_RIGHT, 14, OP_PREFIX }, - { "+", 1, opid2('+','P'), ASSOC_RIGHT, 14, OP_PREFIX }, - { "-", 1, opid2('-','P'), ASSOC_RIGHT, 14, OP_PREFIX }, - { "++", 1, opid3('+','+','P'), ASSOC_RIGHT, 14, OP_PREFIX }, - { "--", 1, opid3('-','-','P'), ASSOC_RIGHT, 14, OP_PREFIX }, - - { "*", 2, opid1('*'), ASSOC_LEFT, 13, 0 }, - { "/", 2, opid1('/'), ASSOC_LEFT, 13, 0 }, - { "&", 2, opid1('&'), ASSOC_LEFT, 13, 0 }, - { "|", 2, opid1('|'), ASSOC_LEFT, 13, 0 }, - - { "+", 2, opid1('+'), ASSOC_LEFT, 12, 0 }, - { "-", 2, opid1('-'), ASSOC_LEFT, 12, 0 }, - - { "<<", 2, opid2('<','<'), ASSOC_LEFT, 11, 0 }, - { ">>", 2, opid2('>','>'), ASSOC_LEFT, 11, 0 }, - - { "<", 2, opid1('<'), ASSOC_LEFT, 10, 0 }, - { ">", 2, opid1('>'), ASSOC_LEFT, 10, 0 }, - { "<=", 2, opid2('<','='), ASSOC_LEFT, 10, 0 }, - { ">=", 2, opid2('>','='), ASSOC_LEFT, 10, 0 }, - { "==", 2, opid2('=','='), ASSOC_LEFT, 10, 0 }, - { "!=", 2, opid2('!','='), ASSOC_LEFT, 10, 0 }, - - { "?", 3, opid2('?',':'), ASSOC_RIGHT, 9, 0 }, - - { "=", 2, opid1('='), ASSOC_RIGHT, 8, 0 }, - { "+=", 2, opid2('+','='), ASSOC_RIGHT, 8, 0 }, - { "-=", 2, opid2('-','='), ASSOC_RIGHT, 8, 0 }, - { "*=", 2, opid2('*','='), ASSOC_RIGHT, 8, 0 }, - { "/=", 2, opid2('/','='), ASSOC_RIGHT, 8, 0 }, - { "%=", 2, opid2('%','='), ASSOC_RIGHT, 8, 0 }, - { "&=", 2, opid2('&','='), ASSOC_RIGHT, 8, 0 }, - { "|=", 2, opid2('|','='), ASSOC_RIGHT, 8, 0 }, - { "&~=", 2, opid3('&','~','='), ASSOC_RIGHT, 8, 0 }, - - { "&&", 2, opid2('&','&'), ASSOC_LEFT, 5, 0 }, - { "||", 2, opid2('|','|'), ASSOC_LEFT, 5, 0 }, + { "(", 0, opid1('('), ASSOC_LEFT, 99, OP_PREFIX, false}, /* paren expression - non function call */ + + { "++", 1, opid3('S','+','+'), ASSOC_LEFT, 15, OP_SUFFIX, false}, + { "--", 1, opid3('S','-','-'), ASSOC_LEFT, 15, OP_SUFFIX, false}, + { ".", 2, opid1('.'), ASSOC_LEFT, 15, 0, false}, + { "(", 0, opid1('('), ASSOC_LEFT, 15, 0, false}, /* function call */ + { "[", 2, opid1('['), ASSOC_LEFT, 15, 0, false}, /* array subscript */ + + { "!", 1, opid2('!', 'P'), ASSOC_RIGHT, 14, OP_PREFIX, true}, + { "+", 1, opid2('+','P'), ASSOC_RIGHT, 14, OP_PREFIX, false}, + { "-", 1, opid2('-','P'), ASSOC_RIGHT, 14, OP_PREFIX, true}, + { "++", 1, opid3('+','+','P'), ASSOC_RIGHT, 14, OP_PREFIX, false}, + { "--", 1, opid3('-','-','P'), ASSOC_RIGHT, 14, OP_PREFIX, false}, + + { "*", 2, opid1('*'), ASSOC_LEFT, 13, 0, true}, + { "/", 2, opid1('/'), ASSOC_LEFT, 13, 0, true}, + { "&", 2, opid1('&'), ASSOC_LEFT, 13, 0, true}, + { "|", 2, opid1('|'), ASSOC_LEFT, 13, 0, true}, + + { "+", 2, opid1('+'), ASSOC_LEFT, 12, 0, true}, + { "-", 2, opid1('-'), ASSOC_LEFT, 12, 0, true}, + + { "<<", 2, opid2('<','<'), ASSOC_LEFT, 11, 0, true}, + { ">>", 2, opid2('>','>'), ASSOC_LEFT, 11, 0, true}, + + { "<", 2, opid1('<'), ASSOC_LEFT, 10, 0, false}, + { ">", 2, opid1('>'), ASSOC_LEFT, 10, 0, false}, + { "<=", 2, opid2('<','='), ASSOC_LEFT, 10, 0, false}, + { ">=", 2, opid2('>','='), ASSOC_LEFT, 10, 0, false}, + { "==", 2, opid2('=','='), ASSOC_LEFT, 10, 0, false}, + { "!=", 2, opid2('!','='), ASSOC_LEFT, 10, 0, false}, + + { "?", 3, opid2('?',':'), ASSOC_RIGHT, 9, 0, true}, + + { "=", 2, opid1('='), ASSOC_RIGHT, 8, 0, false}, + { "+=", 2, opid2('+','='), ASSOC_RIGHT, 8, 0, false}, + { "-=", 2, opid2('-','='), ASSOC_RIGHT, 8, 0, false}, + { "*=", 2, opid2('*','='), ASSOC_RIGHT, 8, 0, false}, + { "/=", 2, opid2('/','='), ASSOC_RIGHT, 8, 0, true}, + { "%=", 2, opid2('%','='), ASSOC_RIGHT, 8, 0, false}, + { "&=", 2, opid2('&','='), ASSOC_RIGHT, 8, 0, false}, + { "|=", 2, opid2('|','='), ASSOC_RIGHT, 8, 0, false}, + { "&~=", 2, opid3('&','~','='), ASSOC_RIGHT, 8, 0, false}, + + { "&&", 2, opid2('&','&'), ASSOC_LEFT, 5, 0, true}, + { "||", 2, opid2('|','|'), ASSOC_LEFT, 5, 0, true}, /* Leave precedence 3 for : with -fcorrect-ternary */ - { ",", 2, opid1(','), ASSOC_LEFT, 2, 0 }, - { ":", 0, opid2(':','?'), ASSOC_RIGHT, 1, 0 } + { ",", 2, opid1(','), ASSOC_LEFT, 2, 0, false}, + { ":", 0, opid2(':','?'), ASSOC_RIGHT, 1, 0, false} }; static const size_t fte_operator_count = (sizeof(fte_operators) / sizeof(fte_operators[0])); static const oper_info qcc_operators[] = { - { "(", 0, opid1('('), ASSOC_LEFT, 99, OP_PREFIX}, /* paren expression - non function call */ - - { ".", 2, opid1('.'), ASSOC_LEFT, 15, 0 }, - { "(", 0, opid1('('), ASSOC_LEFT, 15, 0 }, /* function call */ - { "[", 2, opid1('['), ASSOC_LEFT, 15, 0 }, /* array subscript */ - - { "!", 1, opid2('!', 'P'), ASSOC_RIGHT, 14, OP_PREFIX }, - { "+", 1, opid2('+','P'), ASSOC_RIGHT, 14, OP_PREFIX }, - { "-", 1, opid2('-','P'), ASSOC_RIGHT, 14, OP_PREFIX }, - - { "*", 2, opid1('*'), ASSOC_LEFT, 13, 0 }, - { "/", 2, opid1('/'), ASSOC_LEFT, 13, 0 }, - { "&", 2, opid1('&'), ASSOC_LEFT, 13, 0 }, - { "|", 2, opid1('|'), ASSOC_LEFT, 13, 0 }, - - { "+", 2, opid1('+'), ASSOC_LEFT, 12, 0 }, - { "-", 2, opid1('-'), ASSOC_LEFT, 12, 0 }, - - { "<", 2, opid1('<'), ASSOC_LEFT, 10, 0 }, - { ">", 2, opid1('>'), ASSOC_LEFT, 10, 0 }, - { "<=", 2, opid2('<','='), ASSOC_LEFT, 10, 0 }, - { ">=", 2, opid2('>','='), ASSOC_LEFT, 10, 0 }, - { "==", 2, opid2('=','='), ASSOC_LEFT, 10, 0 }, - { "!=", 2, opid2('!','='), ASSOC_LEFT, 10, 0 }, - - { "=", 2, opid1('='), ASSOC_RIGHT, 8, 0 }, - { "+=", 2, opid2('+','='), ASSOC_RIGHT, 8, 0 }, - { "-=", 2, opid2('-','='), ASSOC_RIGHT, 8, 0 }, - { "*=", 2, opid2('*','='), ASSOC_RIGHT, 8, 0 }, - { "/=", 2, opid2('/','='), ASSOC_RIGHT, 8, 0 }, - { "%=", 2, opid2('%','='), ASSOC_RIGHT, 8, 0 }, - { "&=", 2, opid2('&','='), ASSOC_RIGHT, 8, 0 }, - { "|=", 2, opid2('|','='), ASSOC_RIGHT, 8, 0 }, - - { "&&", 2, opid2('&','&'), ASSOC_LEFT, 5, 0 }, - { "||", 2, opid2('|','|'), ASSOC_LEFT, 5, 0 }, - - { ",", 2, opid1(','), ASSOC_LEFT, 2, 0 }, + { "(", 0, opid1('('), ASSOC_LEFT, 99, OP_PREFIX, false}, /* paren expression - non function call */ + + { ".", 2, opid1('.'), ASSOC_LEFT, 15, 0, false}, + { "(", 0, opid1('('), ASSOC_LEFT, 15, 0, false}, /* function call */ + { "[", 2, opid1('['), ASSOC_LEFT, 15, 0, false}, /* array subscript */ + + { "!", 1, opid2('!', 'P'), ASSOC_RIGHT, 14, OP_PREFIX, true}, + { "+", 1, opid2('+','P'), ASSOC_RIGHT, 14, OP_PREFIX, false}, + { "-", 1, opid2('-','P'), ASSOC_RIGHT, 14, OP_PREFIX, true}, + + { "*", 2, opid1('*'), ASSOC_LEFT, 13, 0, true}, + { "/", 2, opid1('/'), ASSOC_LEFT, 13, 0, true}, + { "&", 2, opid1('&'), ASSOC_LEFT, 13, 0, true}, + { "|", 2, opid1('|'), ASSOC_LEFT, 13, 0, true}, + + { "+", 2, opid1('+'), ASSOC_LEFT, 12, 0, true}, + { "-", 2, opid1('-'), ASSOC_LEFT, 12, 0, true}, + + { "<", 2, opid1('<'), ASSOC_LEFT, 10, 0, false}, + { ">", 2, opid1('>'), ASSOC_LEFT, 10, 0, false}, + { "<=", 2, opid2('<','='), ASSOC_LEFT, 10, 0, false}, + { ">=", 2, opid2('>','='), ASSOC_LEFT, 10, 0, false}, + { "==", 2, opid2('=','='), ASSOC_LEFT, 10, 0, false}, + { "!=", 2, opid2('!','='), ASSOC_LEFT, 10, 0, false}, + + { "=", 2, opid1('='), ASSOC_RIGHT, 8, 0, false}, + { "+=", 2, opid2('+','='), ASSOC_RIGHT, 8, 0, false}, + { "-=", 2, opid2('-','='), ASSOC_RIGHT, 8, 0, false}, + { "*=", 2, opid2('*','='), ASSOC_RIGHT, 8, 0, false}, + { "/=", 2, opid2('/','='), ASSOC_RIGHT, 8, 0, true}, + { "%=", 2, opid2('%','='), ASSOC_RIGHT, 8, 0, false}, + { "&=", 2, opid2('&','='), ASSOC_RIGHT, 8, 0, false}, + { "|=", 2, opid2('|','='), ASSOC_RIGHT, 8, 0, false}, + + { "&&", 2, opid2('&','&'), ASSOC_LEFT, 5, 0, true}, + { "||", 2, opid2('|','|'), ASSOC_LEFT, 5, 0, true}, + + { ",", 2, opid1(','), ASSOC_LEFT, 2, 0, false}, }; static const size_t qcc_operator_count = (sizeof(qcc_operators) / sizeof(qcc_operators[0])); diff --git a/parser.c b/parser.c index 9f53b42..e7c7816 100644 --- a/parser.c +++ b/parser.c @@ -23,90 +23,12 @@ */ #include #include +#include "parser.h" -#include "gmqcc.h" -#include "lexer.h" -#include "ast.h" - -/* beginning of locals */ #define PARSER_HT_LOCALS 2 - #define PARSER_HT_SIZE 512 #define TYPEDEF_HT_SIZE 512 -typedef struct parser_s { - lex_file *lex; - int tok; - - bool ast_cleaned; - - ast_expression **globals; - ast_expression **fields; - ast_function **functions; - ast_value **imm_float; - ast_value **imm_string; - ast_value **imm_vector; - size_t translated; - - ht ht_imm_string; - ht ht_imm_string_dotranslate; - - /* must be deleted first, they reference immediates and values */ - ast_value **accessors; - - ast_value *imm_float_zero; - ast_value *imm_float_one; - ast_value *imm_float_neg_one; - - ast_value *imm_vector_zero; - - ast_value *nil; - ast_value *reserved_version; - - size_t crc_globals; - size_t crc_fields; - - ast_function *function; - ht aliases; - - /* All the labels the function defined... - * Should they be in ast_function instead? - */ - ast_label **labels; - ast_goto **gotos; - const char **breaks; - const char **continues; - - /* A list of hashtables for each scope */ - ht *variables; - ht htfields; - ht htglobals; - ht *typedefs; - - /* same as above but for the spelling corrector */ - correct_trie_t **correct_variables; - size_t ***correct_variables_score; /* vector of vector of size_t* */ - - /* not to be used directly, we use the hash table */ - ast_expression **_locals; - size_t *_blocklocals; - ast_value **_typedefs; - size_t *_blocktypedefs; - lex_ctx_t *_block_ctx; - - /* we store the '=' operator info */ - const oper_info *assign_op; - - /* magic values */ - ast_value *const_vec[3]; - - /* pragma flags */ - bool noref; - - /* collected information */ - size_t max_param_count; -} parser_t; - static ast_expression * const intrinsic_debug_typestring = (ast_expression*)0x1; static void parser_enterblock(parser_t *parser); @@ -144,42 +66,6 @@ static bool GMQCC_WARN parsewarning(parser_t *parser, int warntype, const char * return r; } -/********************************************************************** - * some maths used for constant folding - */ - -vec3_t vec3_add(vec3_t a, vec3_t b) -{ - vec3_t out; - out.x = a.x + b.x; - out.y = a.y + b.y; - out.z = a.z + b.z; - return out; -} - -vec3_t vec3_sub(vec3_t a, vec3_t b) -{ - vec3_t out; - out.x = a.x - b.x; - out.y = a.y - b.y; - out.z = a.z - b.z; - return out; -} - -qcfloat_t vec3_mulvv(vec3_t a, vec3_t b) -{ - return (a.x * b.x + a.y * b.y + a.z * b.z); -} - -vec3_t vec3_mulvf(vec3_t a, float b) -{ - vec3_t out; - out.x = a.x * b; - out.y = a.y * b; - out.z = a.z * b; - return out; -} - /********************************************************************** * parsing */ @@ -199,53 +85,8 @@ static bool parser_next(parser_t *parser) #define parser_tokval(p) ((p)->lex->tok.value) #define parser_token(p) (&((p)->lex->tok)) -#define parser_ctx(p) ((p)->lex->tok.ctx) - -static ast_value* parser_const_float(parser_t *parser, double d) -{ - size_t i; - ast_value *out; - lex_ctx_t ctx; - for (i = 0; i < vec_size(parser->imm_float); ++i) { - const double compare = parser->imm_float[i]->constval.vfloat; - if (memcmp((const void*)&compare, (const void *)&d, sizeof(double)) == 0) - return parser->imm_float[i]; - } - if (parser->lex) - ctx = parser_ctx(parser); - else { - memset(&ctx, 0, sizeof(ctx)); - } - out = ast_value_new(ctx, "#IMMEDIATE", TYPE_FLOAT); - out->cvq = CV_CONST; - out->hasvalue = true; - out->isimm = true; - out->constval.vfloat = d; - vec_push(parser->imm_float, out); - return out; -} - -static ast_value* parser_const_float_0(parser_t *parser) -{ - if (!parser->imm_float_zero) - parser->imm_float_zero = parser_const_float(parser, 0); - return parser->imm_float_zero; -} - -static ast_value* parser_const_float_neg1(parser_t *parser) { - if (!parser->imm_float_neg_one) - parser->imm_float_neg_one = parser_const_float(parser, -1); - return parser->imm_float_neg_one; -} - -static ast_value* parser_const_float_1(parser_t *parser) -{ - if (!parser->imm_float_one) - parser->imm_float_one = parser_const_float(parser, 1); - return parser->imm_float_one; -} -static char *parser_strdup(const char *str) +char *parser_strdup(const char *str) { if (str && !*str) { /* actually dup empty strings */ @@ -256,74 +97,6 @@ static char *parser_strdup(const char *str) return util_strdup(str); } -static ast_value* parser_const_string(parser_t *parser, const char *str, bool dotranslate) -{ - ht ht_string = (dotranslate) - ? parser->ht_imm_string_dotranslate - : parser->ht_imm_string; - - ast_value *out; - size_t hash = util_hthash(ht_string, str); - - if ((out = (ast_value*)util_htgeth(ht_string, str, hash))) - return out; - /* - for (i = 0; i < vec_size(parser->imm_string); ++i) { - if (!strcmp(parser->imm_string[i]->constval.vstring, str)) - return parser->imm_string[i]; - } - */ - if (dotranslate) { - char name[32]; - util_snprintf(name, sizeof(name), "dotranslate_%lu", (unsigned long)(parser->translated++)); - out = ast_value_new(parser_ctx(parser), name, TYPE_STRING); - out->expression.flags |= AST_FLAG_INCLUDE_DEF; - } else - out = ast_value_new(parser_ctx(parser), "#IMMEDIATE", TYPE_STRING); - - out->cvq = CV_CONST; - out->hasvalue = true; - out->isimm = true; - out->constval.vstring = parser_strdup(str); - vec_push(parser->imm_string, out); - util_htseth(ht_string, str, hash, out); - - return out; -} - -static ast_value* parser_const_vector(parser_t *parser, vec3_t v) -{ - size_t i; - ast_value *out; - for (i = 0; i < vec_size(parser->imm_vector); ++i) { - if (!memcmp(&parser->imm_vector[i]->constval.vvec, &v, sizeof(v))) - return parser->imm_vector[i]; - } - out = ast_value_new(parser_ctx(parser), "#IMMEDIATE", TYPE_VECTOR); - out->cvq = CV_CONST; - out->hasvalue = true; - out->isimm = true; - out->constval.vvec = v; - vec_push(parser->imm_vector, out); - return out; -} - -static ast_value* parser_const_vector_f(parser_t *parser, float x, float y, float z) -{ - vec3_t v; - v.x = x; - v.y = y; - v.z = z; - return parser_const_vector(parser, v); -} - -static ast_value* parser_const_vector_0(parser_t *parser) -{ - if (!parser->imm_vector_zero) - parser->imm_vector_zero = parser_const_vector_f(parser, 0, 0, 0); - return parser->imm_vector_zero; -} - static ast_expression* parser_find_field(parser_t *parser, const char *name) { return ( ast_expression*)util_htget(parser->htfields, name); @@ -514,32 +287,6 @@ static bool rotate_entfield_array_index_nodes(ast_expression **out) return true; } -static bool immediate_is_true(lex_ctx_t ctx, ast_value *v) -{ - switch (v->expression.vtype) { - case TYPE_FLOAT: - return !!v->constval.vfloat; - case TYPE_INTEGER: - return !!v->constval.vint; - case TYPE_VECTOR: - if (OPTS_FLAG(CORRECT_LOGIC)) - return v->constval.vvec.x && - v->constval.vvec.y && - v->constval.vvec.z; - else - return !!(v->constval.vvec.x); - case TYPE_STRING: - if (!v->constval.vstring) - return false; - if (v->constval.vstring && OPTS_FLAG(TRUE_EMPTY_STRINGS)) - return true; - return !!v->constval.vstring[0]; - default: - compile_error(ctx, "internal error: immediate_is_true on invalid type"); - return !!v->constval.vfunc; - } -} - static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) { const oper_info *op; @@ -606,14 +353,11 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) #define NotSameType(T) \ (exprs[0]->vtype != exprs[1]->vtype || \ exprs[0]->vtype != T) -#define CanConstFold1(A) \ - (ast_istype((A), ast_value) && ((ast_value*)(A))->hasvalue && (((ast_value*)(A))->cvq == CV_CONST) &&\ - (A)->vtype != TYPE_FUNCTION) -#define CanConstFold(A, B) \ - (CanConstFold1(A) && CanConstFold1(B)) -#define ConstV(i) (asvalue[(i)]->constval.vvec) -#define ConstF(i) (asvalue[(i)]->constval.vfloat) -#define ConstS(i) (asvalue[(i)]->constval.vstring) + + /* preform any constant folding on operator usage first */ + if ((out = fold_op(parser->fold, op, exprs))) + goto complete; + switch (op->id) { default: @@ -710,20 +454,13 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) case opid2('-','P'): switch (exprs[0]->vtype) { case TYPE_FLOAT: - if (CanConstFold1(exprs[0])) - out = (ast_expression*)parser_const_float(parser, -ConstF(0)); - else - out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_F, - (ast_expression*)parser_const_float_0(parser), + out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_F, + (ast_expression*)parser->fold->imm_float[0], exprs[0]); break; case TYPE_VECTOR: - if (CanConstFold1(exprs[0])) - out = (ast_expression*)parser_const_vector_f(parser, - -ConstV(0).x, -ConstV(0).y, -ConstV(0).z); - else - out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_V, - (ast_expression*)parser_const_vector_0(parser), + out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_V, + (ast_expression*)parser->fold->imm_vector[0], exprs[0]); break; default: @@ -736,30 +473,16 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) case opid2('!','P'): switch (exprs[0]->vtype) { case TYPE_FLOAT: - if (CanConstFold1(exprs[0])) - out = (ast_expression*)parser_const_float(parser, !ConstF(0)); - else - out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_F, exprs[0]); + out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_F, exprs[0]); break; case TYPE_VECTOR: - if (CanConstFold1(exprs[0])) - out = (ast_expression*)parser_const_float(parser, - (!ConstV(0).x && !ConstV(0).y && !ConstV(0).z)); - else - out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_V, exprs[0]); + out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_V, exprs[0]); break; case TYPE_STRING: - if (CanConstFold1(exprs[0])) { - if (OPTS_FLAG(TRUE_EMPTY_STRINGS)) - out = (ast_expression*)parser_const_float(parser, !ConstS(0)); - else - out = (ast_expression*)parser_const_float(parser, !ConstS(0) || !*ConstS(0)); - } else { - if (OPTS_FLAG(TRUE_EMPTY_STRINGS)) - out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_F, exprs[0]); - else - out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_S, exprs[0]); - } + if (OPTS_FLAG(TRUE_EMPTY_STRINGS)) + out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_F, exprs[0]); + else + out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_S, exprs[0]); break; /* we don't constant-fold NOT for these types */ case TYPE_ENTITY: @@ -786,18 +509,10 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) } switch (exprs[0]->vtype) { case TYPE_FLOAT: - if (CanConstFold(exprs[0], exprs[1])) - { - out = (ast_expression*)parser_const_float(parser, ConstF(0) + ConstF(1)); - } - else - out = (ast_expression*)ast_binary_new(ctx, INSTR_ADD_F, exprs[0], exprs[1]); + out = (ast_expression*)ast_binary_new(ctx, INSTR_ADD_F, exprs[0], exprs[1]); break; case TYPE_VECTOR: - if (CanConstFold(exprs[0], exprs[1])) - out = (ast_expression*)parser_const_vector(parser, vec3_add(ConstV(0), ConstV(1))); - else - out = (ast_expression*)ast_binary_new(ctx, INSTR_ADD_V, exprs[0], exprs[1]); + out = (ast_expression*)ast_binary_new(ctx, INSTR_ADD_V, exprs[0], exprs[1]); break; default: compile_error(ctx, "invalid types used in expression: cannot add type %s and %s", @@ -817,16 +532,10 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) } switch (exprs[0]->vtype) { case TYPE_FLOAT: - if (CanConstFold(exprs[0], exprs[1])) - out = (ast_expression*)parser_const_float(parser, ConstF(0) - ConstF(1)); - else - out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_F, exprs[0], exprs[1]); + out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_F, exprs[0], exprs[1]); break; case TYPE_VECTOR: - if (CanConstFold(exprs[0], exprs[1])) - out = (ast_expression*)parser_const_vector(parser, vec3_sub(ConstV(0), ConstV(1))); - else - out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_V, exprs[0], exprs[1]); + out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_V, exprs[0], exprs[1]); break; default: compile_error(ctx, "invalid types used in expression: cannot subtract type %s from %s", @@ -851,93 +560,15 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) switch (exprs[0]->vtype) { case TYPE_FLOAT: if (exprs[1]->vtype == TYPE_VECTOR) - { - if (CanConstFold(exprs[0], exprs[1])) - out = (ast_expression*)parser_const_vector(parser, vec3_mulvf(ConstV(1), ConstF(0))); - else - out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_FV, exprs[0], exprs[1]); - } + out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_FV, exprs[0], exprs[1]); else - { - if (CanConstFold(exprs[0], exprs[1])) - out = (ast_expression*)parser_const_float(parser, ConstF(0) * ConstF(1)); - else - out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, exprs[0], exprs[1]); - } + out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, exprs[0], exprs[1]); break; case TYPE_VECTOR: if (exprs[1]->vtype == TYPE_FLOAT) - { - if (CanConstFold(exprs[0], exprs[1])) - out = (ast_expression*)parser_const_vector(parser, vec3_mulvf(ConstV(0), ConstF(1))); - else - out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_VF, exprs[0], exprs[1]); - } + out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_VF, exprs[0], exprs[1]); else - { - if (CanConstFold(exprs[0], exprs[1])) - out = (ast_expression*)parser_const_float(parser, vec3_mulvv(ConstV(0), ConstV(1))); - else if (OPTS_OPTIMIZATION(OPTIM_VECTOR_COMPONENTS) && CanConstFold1(exprs[0])) { - vec3_t vec = ConstV(0); - if (!vec.y && !vec.z) { /* 'n 0 0' * v */ - ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS]; - out = (ast_expression*)ast_member_new(ctx, exprs[1], 0, NULL); - out->node.keep = false; - ((ast_member*)out)->rvalue = true; - if (vec.x != 1) - out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, (ast_expression*)parser_const_float(parser, vec.x), out); - } - else if (!vec.x && !vec.z) { /* '0 n 0' * v */ - ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS]; - out = (ast_expression*)ast_member_new(ctx, exprs[1], 1, NULL); - out->node.keep = false; - ((ast_member*)out)->rvalue = true; - if (vec.y != 1) - out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, (ast_expression*)parser_const_float(parser, vec.y), out); - } - else if (!vec.x && !vec.y) { /* '0 n 0' * v */ - ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS]; - out = (ast_expression*)ast_member_new(ctx, exprs[1], 2, NULL); - out->node.keep = false; - ((ast_member*)out)->rvalue = true; - if (vec.z != 1) - out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, (ast_expression*)parser_const_float(parser, vec.z), out); - } - else - out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_V, exprs[0], exprs[1]); - } - else if (OPTS_OPTIMIZATION(OPTIM_VECTOR_COMPONENTS) && CanConstFold1(exprs[1])) { - vec3_t vec = ConstV(1); - if (!vec.y && !vec.z) { /* v * 'n 0 0' */ - ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS]; - out = (ast_expression*)ast_member_new(ctx, exprs[0], 0, NULL); - out->node.keep = false; - ((ast_member*)out)->rvalue = true; - if (vec.x != 1) - out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, out, (ast_expression*)parser_const_float(parser, vec.x)); - } - else if (!vec.x && !vec.z) { /* v * '0 n 0' */ - ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS]; - out = (ast_expression*)ast_member_new(ctx, exprs[0], 1, NULL); - out->node.keep = false; - ((ast_member*)out)->rvalue = true; - if (vec.y != 1) - out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, out, (ast_expression*)parser_const_float(parser, vec.y)); - } - else if (!vec.x && !vec.y) { /* v * '0 n 0' */ - ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS]; - out = (ast_expression*)ast_member_new(ctx, exprs[0], 2, NULL); - out->node.keep = false; - ((ast_member*)out)->rvalue = true; - if (vec.z != 1) - out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, out, (ast_expression*)parser_const_float(parser, vec.z)); - } - else - out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_V, exprs[0], exprs[1]); - } - else - out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_V, exprs[0], exprs[1]); - } + out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_V, exprs[0], exprs[1]); break; default: compile_error(ctx, "invalid types used in expression: cannot multiply types %s and %s", @@ -953,30 +584,10 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) compile_error(ctx, "invalid types used in expression: cannot divide types %s and %s", ty1, ty2); return false; } - if (exprs[0]->vtype == TYPE_FLOAT) { - if (CanConstFold(exprs[0], exprs[1])) - out = (ast_expression*)parser_const_float(parser, ConstF(0) / ConstF(1)); - else - out = (ast_expression*)ast_binary_new(ctx, INSTR_DIV_F, exprs[0], exprs[1]); - } - else if (exprs[0]->vtype == TYPE_VECTOR) { - if (CanConstFold(exprs[0], exprs[1])) - out = (ast_expression*)parser_const_vector(parser, vec3_mulvf(ConstV(0), 1.0/ConstF(1))); - else { - if (CanConstFold1(exprs[1])) { - out = (ast_expression*)parser_const_float(parser, 1.0 / ConstF(1)); - } else { - out = (ast_expression*)ast_binary_new(ctx, INSTR_DIV_F, - (ast_expression*)parser_const_float_1(parser), - exprs[1]); - } - if (!out) { - compile_error(ctx, "internal error: failed to generate division"); - return false; - } - out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_VF, exprs[0], out); - } - } + if (exprs[0]->vtype == TYPE_FLOAT) + out = (ast_expression*)ast_binary_new(ctx, INSTR_DIV_F, exprs[0], exprs[1]); + else if (exprs[0]->vtype == TYPE_VECTOR) + out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_VF, exprs[0], out); else { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); @@ -992,10 +603,6 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) type_name[exprs[0]->vtype], type_name[exprs[1]->vtype]); return false; - } - if (CanConstFold(exprs[0], exprs[1])) { - out = (ast_expression*)parser_const_float(parser, - (float)(((qcint_t)ConstF(0)) % ((qcint_t)ConstF(1)))); } else { /* generate a call to __builtin_mod */ ast_expression *mod = intrin_func(parser, "mod"); @@ -1022,14 +629,9 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) type_name[exprs[1]->vtype]); return false; } - if (CanConstFold(exprs[0], exprs[1])) - out = (ast_expression*)parser_const_float(parser, - (op->id == opid1('|') ? (float)( ((qcint_t)ConstF(0)) | ((qcint_t)ConstF(1)) ) : - (float)( ((qcint_t)ConstF(0)) & ((qcint_t)ConstF(1)) ) )); - else - out = (ast_expression*)ast_binary_new(ctx, - (op->id == opid1('|') ? INSTR_BITOR : INSTR_BITAND), - exprs[0], exprs[1]); + out = (ast_expression*)ast_binary_new(ctx, + (op->id == opid1('|') ? INSTR_BITOR : INSTR_BITAND), + exprs[0], exprs[1]); break; case opid1('^'): /* @@ -1084,35 +686,31 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) * since scalar ^ vector is not allowed. */ if (exprs[0]->vtype == TYPE_FLOAT) { - if(CanConstFold(exprs[0], exprs[1])) { - out = (ast_expression*)parser_const_float(parser, (float)((qcint_t)(ConstF(0)) ^ ((qcint_t)(ConstF(1))))); - } else { - ast_binary *expr = ast_binary_new( + ast_binary *expr = ast_binary_new( + ctx, + INSTR_SUB_F, + (ast_expression*)parser->fold->imm_float[2], + (ast_expression*)ast_binary_new( ctx, - INSTR_SUB_F, - (ast_expression*)parser_const_float_neg1(parser), + INSTR_BITAND, + exprs[0], + exprs[1] + ) + ); + expr->refs = AST_REF_NONE; + + out = (ast_expression*) + ast_binary_new( + ctx, + INSTR_BITAND, (ast_expression*)ast_binary_new( ctx, - INSTR_BITAND, + INSTR_BITOR, exprs[0], exprs[1] - ) + ), + (ast_expression*)expr ); - expr->refs = AST_REF_NONE; - - out = (ast_expression*) - ast_binary_new( - ctx, - INSTR_BITAND, - (ast_expression*)ast_binary_new( - ctx, - INSTR_BITOR, - exprs[0], - exprs[1] - ), - (ast_expression*)expr - ); - } } else { /* * The first is a vector: vector is allowed to xor with vector and @@ -1123,33 +721,11 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) * Xor all the values of the vector components against the * vectors components in question. */ - if (CanConstFold(exprs[0], exprs[1])) { - out = (ast_expression*)parser_const_vector_f( - parser, - (float)(((qcint_t)(ConstV(0).x)) ^ ((qcint_t)(ConstV(1).x))), - (float)(((qcint_t)(ConstV(0).y)) ^ ((qcint_t)(ConstV(1).y))), - (float)(((qcint_t)(ConstV(0).z)) ^ ((qcint_t)(ConstV(1).z))) - ); - } else { - compile_error(ast_ctx(exprs[0]), "Not Yet Implemented: bit-xor for vector against vector"); - return false; - } + compile_error(ast_ctx(exprs[0]), "Not Yet Implemented: bit-xor for vector against vector"); + return false; } else { - /* - * Xor all the values of the vector components against the - * scalar in question. - */ - if (CanConstFold(exprs[0], exprs[1])) { - out = (ast_expression*)parser_const_vector_f( - parser, - (float)(((qcint_t)(ConstV(0).x)) ^ ((qcint_t)(ConstF(1)))), - (float)(((qcint_t)(ConstV(0).y)) ^ ((qcint_t)(ConstF(1)))), - (float)(((qcint_t)(ConstV(0).z)) ^ ((qcint_t)(ConstF(1)))) - ); - } else { - compile_error(ast_ctx(exprs[0]), "Not Yet Implemented: bit-xor for vector against float"); - return false; - } + compile_error(ast_ctx(exprs[0]), "Not Yet Implemented: bit-xor for vector against float"); + return false; } } @@ -1157,13 +733,6 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) case opid2('<','<'): case opid2('>','>'): - if (CanConstFold(exprs[0], exprs[1]) && ! NotSameType(TYPE_FLOAT)) { - if (op->id == opid2('<','<')) - out = (ast_expression*)parser_const_float(parser, (double)((unsigned int)(ConstF(0)) << (unsigned int)(ConstF(1)))); - else - out = (ast_expression*)parser_const_float(parser, (double)((unsigned int)(ConstF(0)) >> (unsigned int)(ConstF(1)))); - break; - } case opid3('<','<','='): case opid3('>','>','='): compile_error(ast_ctx(exprs[0]), "Not Yet Implemented: bit-shifts"); @@ -1173,53 +742,37 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) generated_op += 1; /* INSTR_OR */ case opid2('&','&'): generated_op += INSTR_AND; - if (CanConstFold(exprs[0], exprs[1])) - { - if (OPTS_FLAG(PERL_LOGIC)) { - if (immediate_is_true(ctx, asvalue[0])) - out = exprs[1]; - } - else - out = (ast_expression*)parser_const_float(parser, - ( (generated_op == INSTR_OR) - ? (immediate_is_true(ctx, asvalue[0]) || immediate_is_true(ctx, asvalue[1])) - : (immediate_is_true(ctx, asvalue[0]) && immediate_is_true(ctx, asvalue[1])) ) - ? 1 : 0); + if (OPTS_FLAG(PERL_LOGIC) && !ast_compare_type(exprs[0], exprs[1])) { + ast_type_to_string(exprs[0], ty1, sizeof(ty1)); + ast_type_to_string(exprs[1], ty2, sizeof(ty2)); + compile_error(ctx, "invalid types for logical operation with -fperl-logic: %s and %s", ty1, ty2); + return false; } - else - { - if (OPTS_FLAG(PERL_LOGIC) && !ast_compare_type(exprs[0], exprs[1])) { - ast_type_to_string(exprs[0], ty1, sizeof(ty1)); - ast_type_to_string(exprs[1], ty2, sizeof(ty2)); - compile_error(ctx, "invalid types for logical operation with -fperl-logic: %s and %s", ty1, ty2); - return false; - } - for (i = 0; i < 2; ++i) { - if (OPTS_FLAG(CORRECT_LOGIC) && exprs[i]->vtype == TYPE_VECTOR) { - out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_V, exprs[i]); - if (!out) break; - out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_F, out); - if (!out) break; - exprs[i] = out; out = NULL; - if (OPTS_FLAG(PERL_LOGIC)) { - /* here we want to keep the right expressions' type */ - break; - } + for (i = 0; i < 2; ++i) { + if (OPTS_FLAG(CORRECT_LOGIC) && exprs[i]->vtype == TYPE_VECTOR) { + out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_V, exprs[i]); + if (!out) break; + out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_F, out); + if (!out) break; + exprs[i] = out; out = NULL; + if (OPTS_FLAG(PERL_LOGIC)) { + /* here we want to keep the right expressions' type */ + break; } - else if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && exprs[i]->vtype == TYPE_STRING) { - out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_S, exprs[i]); - if (!out) break; - out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_F, out); - if (!out) break; - exprs[i] = out; out = NULL; - if (OPTS_FLAG(PERL_LOGIC)) { - /* here we want to keep the right expressions' type */ - break; - } + } + else if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && exprs[i]->vtype == TYPE_STRING) { + out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_S, exprs[i]); + if (!out) break; + out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_F, out); + if (!out) break; + exprs[i] = out; out = NULL; + if (OPTS_FLAG(PERL_LOGIC)) { + /* here we want to keep the right expressions' type */ + break; } } - out = (ast_expression*)ast_binary_new(ctx, generated_op, exprs[0], exprs[1]); } + out = (ast_expression*)ast_binary_new(ctx, generated_op, exprs[0], exprs[1]); break; case opid2('?',':'): @@ -1234,10 +787,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) compile_error(ctx, "operands of ternary expression must have the same type, got %s and %s", ty1, ty2); return false; } - if (CanConstFold1(exprs[0])) - out = (immediate_is_true(ctx, asvalue[0]) ? exprs[1] : exprs[2]); - else - out = (ast_expression*)ast_ternary_new(ctx, exprs[0], exprs[1], exprs[2]); + out = (ast_expression*)ast_ternary_new(ctx, exprs[0], exprs[1], exprs[2]); break; case opid2('*', '*'): @@ -1248,10 +798,6 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) ty1, ty2); return false; - } - - if (CanConstFold(exprs[0], exprs[1])) { - out = (ast_expression*)parser_const_float(parser, powf(ConstF(0), ConstF(1))); } else { ast_call *gencall = ast_call_new(parser_ctx(parser), intrin_func(parser, "pow")); vec_push(gencall->params, exprs[0]); @@ -1268,15 +814,6 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) ty1, ty2); return false; - } - - if (CanConstFold(exprs[0], exprs[1])) { - if (ConstF(0) < ConstF(1)) - out = (ast_expression*)parser_const_float_neg1(parser); - else if (ConstF(0) == ConstF(1)) - out = (ast_expression*)parser_const_float_0(parser); - else if (ConstF(0) > ConstF(1)) - out = (ast_expression*)parser_const_float_1(parser); } else { ast_binary *eq = ast_binary_new(ctx, INSTR_EQ_F, exprs[0], exprs[1]); @@ -1286,15 +823,15 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) out = (ast_expression*)ast_ternary_new(ctx, (ast_expression*)ast_binary_new(ctx, INSTR_LT, exprs[0], exprs[1]), /* out = -1 */ - (ast_expression*)parser_const_float_neg1(parser), + (ast_expression*)parser->fold->imm_float[2], /* } else { */ /* if (eq) { */ (ast_expression*)ast_ternary_new(ctx, (ast_expression*)eq, /* out = 0 */ - (ast_expression*)parser_const_float_0(parser), + (ast_expression*)parser->fold->imm_float[0], /* } else { */ /* out = 1 */ - (ast_expression*)parser_const_float_1(parser) + (ast_expression*)parser->fold->imm_float[1] /* } */ ) /* } */ @@ -1326,9 +863,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) type_name[exprs[1]->vtype]); return false; } - out = CanConstFold(exprs[0], exprs[1]) - ? (ast_expression*)parser_const_float(parser, ConstF(0) != ConstF(1)) - : (ast_expression*)ast_binary_new(ctx, type_ne_instr[exprs[0]->vtype], exprs[0], exprs[1]); + out = (ast_expression*)ast_binary_new(ctx, type_ne_instr[exprs[0]->vtype], exprs[0], exprs[1]); break; case opid2('=', '='): if (exprs[0]->vtype != exprs[1]->vtype) { @@ -1337,9 +872,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) type_name[exprs[1]->vtype]); return false; } - out = CanConstFold(exprs[0], exprs[1]) - ? (ast_expression*)parser_const_float(parser, ConstF(0) == ConstF(1)) - : (ast_expression*)ast_binary_new(ctx, type_eq_instr[exprs[0]->vtype], exprs[0], exprs[1]); + out = (ast_expression*)ast_binary_new(ctx, type_eq_instr[exprs[0]->vtype], exprs[0], exprs[1]); break; case opid1('='): @@ -1423,11 +956,11 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) if (ast_istype(exprs[0], ast_entfield)) { out = (ast_expression*)ast_binstore_new(ctx, INSTR_STOREP_F, addop, exprs[0], - (ast_expression*)parser_const_float_1(parser)); + (ast_expression*)parser->fold->imm_float[1]); } else { out = (ast_expression*)ast_binstore_new(ctx, INSTR_STORE_F, addop, exprs[0], - (ast_expression*)parser_const_float_1(parser)); + (ast_expression*)parser->fold->imm_float[1]); } break; case opid3('S','+','+'): @@ -1451,17 +984,17 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) if (ast_istype(exprs[0], ast_entfield)) { out = (ast_expression*)ast_binstore_new(ctx, INSTR_STOREP_F, addop, exprs[0], - (ast_expression*)parser_const_float_1(parser)); + (ast_expression*)parser->fold->imm_float[1]); } else { out = (ast_expression*)ast_binstore_new(ctx, INSTR_STORE_F, addop, exprs[0], - (ast_expression*)parser_const_float_1(parser)); + (ast_expression*)parser->fold->imm_float[1]); } if (!out) return false; out = (ast_expression*)ast_binary_new(ctx, subop, out, - (ast_expression*)parser_const_float_1(parser)); + (ast_expression*)parser->fold->imm_float[1]); break; case opid2('+','='): case opid2('-','='): @@ -1529,14 +1062,9 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) out = (ast_expression*)ast_binstore_new(ctx, assignop, INSTR_MUL_VF, exprs[0], exprs[1]); } else { - /* there's no DIV_VF */ - if (CanConstFold1(exprs[1])) { - out = (ast_expression*)parser_const_float(parser, 1.0 / ConstF(1)); - } else { - out = (ast_expression*)ast_binary_new(ctx, INSTR_DIV_F, - (ast_expression*)parser_const_float_1(parser), + out = (ast_expression*)ast_binary_new(ctx, INSTR_DIV_F, + (ast_expression*)parser->fold->imm_float[1], exprs[1]); - } if (!out) { compile_error(ctx, "internal error: failed to generate division"); return false; @@ -1605,16 +1133,11 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) compile_error(ast_ctx(exprs[0]), "invalid type for bit not: %s", ty1); return false; } - - if(CanConstFold1(exprs[0])) - out = (ast_expression*)parser_const_float(parser, ~(qcint_t)ConstF(0)); - else - out = (ast_expression*) - ast_binary_new(ctx, INSTR_SUB_F, (ast_expression*)parser_const_float_neg1(parser), exprs[0]); + out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_F, (ast_expression*)parser->fold->imm_float[2], exprs[0]); break; } #undef NotSameType - +complete: if (!out) { compile_error(ctx, "failed to apply operator %s", op->op); return false; @@ -1669,7 +1192,7 @@ static bool parser_close_call(parser_t *parser, shunt *sy) ast_type_to_string(vec_last(sy->out).out, ty, sizeof(ty)); ast_unref(vec_last(sy->out).out); sy->out[fid] = syexp(ast_ctx(vec_last(sy->out).out), - (ast_expression*)parser_const_string(parser, ty, false)); + (ast_expression*)fold_constgen_string(parser->fold, ty, false)); vec_shrinkby(sy->out, 1); return true; } @@ -1699,7 +1222,7 @@ static bool parser_close_call(parser_t *parser, shunt *sy) if ((fun->flags & AST_FLAG_VARIADIC) && !(/*funval->cvq == CV_CONST && */ funval->hasvalue && funval->constval.vfunc->builtin)) { - call->va_count = (ast_expression*)parser_const_float(parser, (double)paramcount); + call->va_count = (ast_expression*)fold_constgen_float(parser->fold, (qcfloat_t)paramcount); } } @@ -1930,7 +1453,7 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels) parseerror(parser, "expected a constant string in translatable-string extension"); return false; } - val = parser_const_string(parser, parser_tokval(parser), true); + val = (ast_value*)fold_constgen_string(parser->fold, parser_tokval(parser), true); if (!val) return false; vec_push(sy->out, syexp(parser_ctx(parser), (ast_expression*)val)); @@ -1955,35 +1478,31 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels) return true; } else if (parser->tok == TOKEN_FLOATCONST) { - ast_value *val; - val = parser_const_float(parser, (parser_token(parser)->constval.f)); + ast_expression *val = fold_constgen_float(parser->fold, (parser_token(parser)->constval.f)); if (!val) return false; - vec_push(sy->out, syexp(parser_ctx(parser), (ast_expression*)val)); + vec_push(sy->out, syexp(parser_ctx(parser), val)); return true; } else if (parser->tok == TOKEN_INTCONST || parser->tok == TOKEN_CHARCONST) { - ast_value *val; - val = parser_const_float(parser, (double)(parser_token(parser)->constval.i)); + ast_expression *val = fold_constgen_float(parser->fold, (qcfloat_t)(parser_token(parser)->constval.i)); if (!val) return false; - vec_push(sy->out, syexp(parser_ctx(parser), (ast_expression*)val)); + vec_push(sy->out, syexp(parser_ctx(parser), val)); return true; } else if (parser->tok == TOKEN_STRINGCONST) { - ast_value *val; - val = parser_const_string(parser, parser_tokval(parser), false); + ast_expression *val = fold_constgen_string(parser->fold, parser_tokval(parser), false); if (!val) return false; - vec_push(sy->out, syexp(parser_ctx(parser), (ast_expression*)val)); + vec_push(sy->out, syexp(parser_ctx(parser), val)); return true; } else if (parser->tok == TOKEN_VECTORCONST) { - ast_value *val; - val = parser_const_vector(parser, parser_token(parser)->constval.v); + ast_expression *val = fold_constgen_vector(parser->fold, parser_token(parser)->constval.v); if (!val) return false; - vec_push(sy->out, syexp(parser_ctx(parser), (ast_expression*)val)); + vec_push(sy->out, syexp(parser_ctx(parser), val)); return true; } else if (parser->tok == TOKEN_IDENT) @@ -2018,7 +1537,7 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels) } } if (!var && !strcmp(parser_tokval(parser), "__FUNC__")) - var = (ast_expression*)parser_const_string(parser, parser->function->name, false); + var = (ast_expression*)fold_constgen_string(parser->fold, parser->function->name, false); if (!var) { /* intrinsics */ if (!strcmp(parser_tokval(parser), "__builtin_debug_typestring")) { @@ -2318,7 +1837,7 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma { char *newstr = NULL; util_asprintf(&newstr, "%s%s", last->constval.vstring, parser_tokval(parser)); - vec_last(sy.out).out = (ast_expression*)parser_const_string(parser, newstr, false); + vec_last(sy.out).out = (ast_expression*)fold_constgen_string(parser->fold, newstr, false); mem_d(newstr); concatenated = true; } @@ -4337,7 +3856,7 @@ static bool parse_function_body(parser_t *parser, ast_value *var) self_think = (ast_expression*)ast_entfield_new(ctx, gbl_self, fld_think); time_plus_1 = (ast_expression*)ast_binary_new(ctx, INSTR_ADD_F, - gbl_time, (ast_expression*)parser_const_float(parser, 0.1)); + gbl_time, (ast_expression*)fold_constgen_float(parser->fold, 0.1)); if (!self_frame || !self_nextthink || !self_think || !time_plus_1) { if (self_frame) ast_delete(self_frame); @@ -4451,9 +3970,8 @@ static bool parse_function_body(parser_t *parser, ast_value *var) ast_block_delete(block); goto enderrfn; } - func->varargs = varargs; - - func->fixedparams = parser_const_float(parser, vec_size(var->expression.params)); + func->varargs = varargs; + func->fixedparams = (ast_value*)fold_constgen_float(parser->fold, vec_size(var->expression.params)); } parser->function = func; @@ -4512,7 +4030,7 @@ static ast_expression *array_accessor_split( cmp = ast_binary_new(ctx, INSTR_LT, (ast_expression*)index, - (ast_expression*)parser_const_float(parser, middle)); + (ast_expression*)fold_constgen_float(parser->fold, middle)); if (!cmp) { ast_delete(left); ast_delete(right); @@ -4545,7 +4063,7 @@ static ast_expression *array_setter_node(parser_t *parser, ast_value *array, ast if (value->expression.vtype == TYPE_FIELD && value->expression.next->vtype == TYPE_VECTOR) assignop = INSTR_STORE_V; - subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)parser_const_float(parser, from)); + subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)fold_constgen_float(parser->fold, from)); if (!subscript) return NULL; @@ -4611,7 +4129,7 @@ static ast_expression *array_field_setter_node( if (value->expression.vtype == TYPE_FIELD && value->expression.next->vtype == TYPE_VECTOR) assignop = INSTR_STOREP_V; - subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)parser_const_float(parser, from)); + subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)fold_constgen_float(parser->fold, from)); if (!subscript) return NULL; @@ -4674,7 +4192,7 @@ static ast_expression *array_getter_node(parser_t *parser, ast_value *array, ast ast_return *ret; ast_array_index *subscript; - subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)parser_const_float(parser, from)); + subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)fold_constgen_float(parser->fold, from)); if (!subscript) return NULL; @@ -6309,9 +5827,6 @@ parser_t *parser_create() parser->aliases = util_htnew(PARSER_HT_SIZE); - parser->ht_imm_string = util_htnew(512); - parser->ht_imm_string_dotranslate = util_htnew(512); - /* corrector */ vec_push(parser->correct_variables, correct_trie_new()); vec_push(parser->correct_variables_score, NULL); @@ -6340,6 +5855,7 @@ parser_t *parser_create() parser->reserved_version = NULL; } + parser->fold = fold_init(parser); return parser; } @@ -6409,15 +5925,6 @@ static void parser_remove_ast(parser_t *parser) for (i = 0; i < vec_size(parser->functions); ++i) { ast_delete(parser->functions[i]); } - for (i = 0; i < vec_size(parser->imm_vector); ++i) { - ast_delete(parser->imm_vector[i]); - } - for (i = 0; i < vec_size(parser->imm_string); ++i) { - ast_delete(parser->imm_string[i]); - } - for (i = 0; i < vec_size(parser->imm_float); ++i) { - ast_delete(parser->imm_float[i]); - } for (i = 0; i < vec_size(parser->fields); ++i) { ast_delete(parser->fields[i]); } @@ -6426,11 +5933,6 @@ static void parser_remove_ast(parser_t *parser) } vec_free(parser->accessors); vec_free(parser->functions); - vec_free(parser->imm_vector); - vec_free(parser->imm_string); - util_htdel(parser->ht_imm_string_dotranslate); - util_htdel(parser->ht_imm_string); - vec_free(parser->imm_float); vec_free(parser->globals); vec_free(parser->fields); @@ -6473,6 +5975,7 @@ static void parser_remove_ast(parser_t *parser) util_htdel(parser->aliases); intrin_intrinsics_destroy(parser); + fold_cleanup(parser->fold); } void parser_cleanup(parser_t *parser) @@ -6564,27 +6067,9 @@ bool parser_finish(parser_t *parser, const char *output) } } /* Now we can generate immediates */ - for (i = 0; i < vec_size(parser->imm_float); ++i) { - if (!ast_global_codegen(parser->imm_float[i], ir, false)) { - con_out("failed to generate global %s\n", parser->imm_float[i]->name); - ir_builder_delete(ir); - return false; - } - } - for (i = 0; i < vec_size(parser->imm_string); ++i) { - if (!ast_global_codegen(parser->imm_string[i], ir, false)) { - con_out("failed to generate global %s\n", parser->imm_string[i]->name); - ir_builder_delete(ir); - return false; - } - } - for (i = 0; i < vec_size(parser->imm_vector); ++i) { - if (!ast_global_codegen(parser->imm_vector[i], ir, false)) { - con_out("failed to generate global %s\n", parser->imm_vector[i]->name); - ir_builder_delete(ir); - return false; - } - } + if (!fold_generate(parser->fold, ir)) + return false; + for (i = 0; i < vec_size(parser->globals); ++i) { ast_value *asvalue; if (!ast_istype(parser->globals[i], ast_value)) diff --git a/parser.h b/parser.h new file mode 100644 index 0000000..0869210 --- /dev/null +++ b/parser.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2012, 2013 + * Wolfgang Bumiller + * Dale Weiler + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef GMQCC_PARSER_HDR +#define GMQCC_PARSER_HDR +#include "gmqcc.h" +#include "lexer.h" +#include "ast.h" + +typedef struct { + struct parser_s *parser; + ast_value **imm_float; /* vector */ + ast_value **imm_vector; /* vector */ + ast_value **imm_string; /* vector */ + hash_table_t *imm_string_untranslate; /* map */ + hash_table_t *imm_string_dotranslate; /* map */ +} fold_t; + +#define parser_ctx(p) ((p)->lex->tok.ctx) +typedef struct parser_s { + lex_file *lex; + int tok; + + bool ast_cleaned; + + ast_expression **globals; + ast_expression **fields; + ast_function **functions; + size_t translated; + + /* must be deleted first, they reference immediates and values */ + ast_value **accessors; + + ast_value *nil; + ast_value *reserved_version; + + size_t crc_globals; + size_t crc_fields; + + ast_function *function; + ht aliases; + + /* All the labels the function defined... + * Should they be in ast_function instead? + */ + ast_label **labels; + ast_goto **gotos; + const char **breaks; + const char **continues; + + /* A list of hashtables for each scope */ + ht *variables; + ht htfields; + ht htglobals; + ht *typedefs; + + /* same as above but for the spelling corrector */ + correct_trie_t **correct_variables; + size_t ***correct_variables_score; /* vector of vector of size_t* */ + + /* not to be used directly, we use the hash table */ + ast_expression **_locals; + size_t *_blocklocals; + ast_value **_typedefs; + size_t *_blocktypedefs; + lex_ctx_t *_block_ctx; + + /* we store the '=' operator info */ + const oper_info *assign_op; + + /* magic values */ + ast_value *const_vec[3]; + + /* pragma flags */ + bool noref; + + /* collected information */ + size_t max_param_count; + + fold_t *fold; +} parser_t; + + +char *parser_strdup(const char *str); + +/* fold.c */ +fold_t *fold_init (parser_t *); +void fold_cleanup (fold_t *); +ast_expression *fold_constgen_float (fold_t *, qcfloat_t); +ast_expression *fold_constgen_vector(fold_t *, vec3_t); +ast_expression *fold_constgen_string(fold_t *, const char *, bool); +bool fold_generate (fold_t *, ir_builder *); +ast_expression *fold_op (fold_t *, const oper_info *, ast_expression**); +#endif