X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=fold.c;h=d51b7652dcc9b48efdd2bf42c0befe73d6c13503;hb=48211572e529c37fb2be9ac05c7e810e690757f3;hp=4019794c3669db8204eb9aff76b54bcce27ca4c9;hpb=454234ef5f1a9d3aed01985f99fa6f26cc280d4c;p=xonotic%2Fgmqcc.git diff --git a/fold.c b/fold.c index 4019794..d51b765 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; } @@ -362,7 +386,7 @@ static GMQCC_INLINE ast_expression *fold_op_mul_vec(fold_t *fold, vec3_t vec, as out = (ast_expression*)ast_member_new(fold_ctx(fold), (ast_expression*)sel, set[0]-'x', NULL); out->node.keep = false; ((ast_member*)out)->rvalue = true; - if (x != -1) + if (x != -1.0f) return (ast_expression*)ast_binary_new(fold_ctx(fold), INSTR_MUL_F, fold_constgen_float(fold, x), out); } return NULL; @@ -454,12 +478,28 @@ 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 (fold_can_1(b)) { + return (ast_expression*)ast_binary_new( + fold_ctx(fold), + INSTR_MUL_F, + (ast_expression*)a, + fold_constgen_float(fold, 1.0f / fold_immvalue_float(b)) + ); + } } 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)) { + return fold_constgen_vector(fold, vec3_mulvf(fold_immvalue_vector(a), 1.0f / fold_immvalue_float(b))); + } + else { + return (ast_expression*)fold->imm_vector[2]; /* inf */ + } + } else { return (ast_expression*)ast_binary_new( fold_ctx(fold), INSTR_MUL_VF, @@ -479,8 +519,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 +654,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,18 +717,67 @@ 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; } +/* + * 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) + ) + ); +} + +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) + ) + ); +} + +static GMQCC_INLINE ast_expression *fold_intrin_exp(fold_t *fold, ast_value *value) { + return fold_constgen_float(fold, exp(fold_immvalue_float(value))); +} + +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); +} + +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; +} + /* * These are all the actual constant folding methods that happen in between * the AST/IR stage of the compiler , i.e eliminating branches for const * expressions, which is the only supported thing so far. We undefine the * testing macros here because an ir_value is differant than an ast_value. */ +#undef expect #undef isfloat #undef isstring #undef isvector @@ -698,17 +797,24 @@ ast_expression *fold_op(fold_t *fold, const oper_info *info, ast_expression **op /*#define fold_can_2(X,Y) (fold_can_1(X) && fold_can_1(Y))*/ -int fold_cond(ir_value *condval, ast_function *func, ast_ifthen *branch) { +static GMQCC_INLINE int fold_cond(ir_value *condval, ast_function *func, ast_ifthen *branch) { if (isfloat(condval) && fold_can_1(condval) && OPTS_OPTIMIZATION(OPTIM_CONST_FOLD_DCE)) { ast_expression_codegen *cgen; ir_block *elide; ir_value *dummy; - bool istrue = (fold_immvalue_float(condval) == 1.0f && branch->on_true); + bool istrue = (fold_immvalue_float(condval) != 0.0f && branch->on_true); bool isfalse = (fold_immvalue_float(condval) == 0.0f && branch->on_false); ast_expression *path = (istrue) ? branch->on_true : (isfalse) ? branch->on_false : NULL; - if (!path) - return false; + if (!path) { + /* + * no path to take implies that the evaluation is if(0) and there + * is no else block. so eliminate all the code. + */ + ++opts_optimizationcount[OPTIM_CONST_FOLD_DCE]; + return true; + } + if (!(elide = ir_function_create_block(ast_ctx(branch), func->ir_func, ast_function_label(func, ((istrue) ? "ontrue" : "onfalse"))))) return false; if (!(*(cgen = path->codegen))((ast_expression*)path, func, false, &dummy)) @@ -725,3 +831,11 @@ int fold_cond(ir_value *condval, ast_function *func, ast_ifthen *branch) { } return -1; /* nothing done */ } + +int fold_cond_ternary(ir_value *condval, ast_function *func, ast_ternary *branch) { + return fold_cond(condval, func, (ast_ifthen*)branch); +} + +int fold_cond_ifthen(ir_value *condval, ast_function *func, ast_ifthen *branch) { + return fold_cond(condval, func, branch); +}