From: Dale Weiler Date: Wed, 31 Jul 2013 19:34:38 +0000 (+0000) Subject: Move const-branch-elision into fold.c X-Git-Tag: v0.3.0~40 X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=commitdiff_plain;h=10b75fd8b9ebc7ea6dbfd802dde13af4ec4c2414 Move const-branch-elision into fold.c --- diff --git a/ast.c b/ast.c index 202adb6..dd98a83 100644 --- a/ast.c +++ b/ast.c @@ -26,6 +26,7 @@ #include "gmqcc.h" #include "ast.h" +#include "parser.h" #define ast_instantiate(T, ctx, destroyfn) \ T* self = (T*)mem_a(sizeof(T)); \ @@ -1221,7 +1222,7 @@ void ast_function_delete(ast_function *self) mem_d(self); } -static const char* ast_function_label(ast_function *self, const char *prefix) +const char* ast_function_label(ast_function *self, const char *prefix) { size_t id; size_t len; @@ -2513,6 +2514,7 @@ bool ast_ifthen_codegen(ast_ifthen *self, ast_function *func, bool lvalue, ir_va ir_block *ontrue_endblock = NULL; ir_block *onfalse_endblock = NULL; ir_block *merge = NULL; + int fold = 0; /* We don't output any value, thus also don't care about r/lvalue */ (void)out; @@ -2531,33 +2533,10 @@ bool ast_ifthen_codegen(ast_ifthen *self, ast_function *func, bool lvalue, ir_va /* update the block which will get the jump - because short-logic or ternaries may have changed this */ cond = func->curblock; - /* eliminate branches if value is constant */ - if (condval->vtype == TYPE_FLOAT && condval->hasvalue && condval->cvq == CV_CONST) { - /* don't generate if statements */ - if (condval->constval.vfloat == 1.0f && self->on_true) { - if (!(ontrue = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "ontrue")))) - return false; - /* generate */ - if (!(*(cgen = self->on_true->codegen))((ast_expression*)(self->on_true), func, false, &dummy)) - return false; - if (!ir_block_create_jump(func->curblock, ast_ctx(self), ontrue)) - return false; - func->curblock = ontrue; - return true; - } else if (condval->constval.vfloat == 0.0f && self->on_false) { - if (!(onfalse = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "onfalse")))) - return false; - /* generate */ - if (!(*(cgen = self->on_false->codegen))((ast_expression*)(self->on_false), func, false, &dummy)) - return false; - if (!ir_block_create_jump(func->curblock, ast_ctx(self), onfalse)) - return false; - func->curblock = onfalse; - return true; - } - } - /* on-true path */ - + /* try constant folding away the if */ + if ((fold = fold_cond((ast_value*)condval, func, self)) != -1) + return fold; + if (self->on_true) { /* create on-true block */ ontrue = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "ontrue")); diff --git a/ast.h b/ast.h index 1f3029f..ca323a2 100644 --- a/ast.h +++ b/ast.h @@ -642,7 +642,7 @@ void ast_function_delete(ast_function*); /* For "optimized" builds this can just keep returning "foo"... * or whatever... */ -/*const char* ast_function_label(ast_function*, const char *prefix);*/ +const char* ast_function_label(ast_function*, const char *prefix); bool ast_function_codegen(ast_function *self, ir_builder *builder); bool ast_generate_accessors(ast_value *asvalue, ir_builder *ir); diff --git a/fold.c b/fold.c index 884e039..c8996cf 100644 --- a/fold.c +++ b/fold.c @@ -588,3 +588,35 @@ ast_expression *fold_op(fold_t *fold, const oper_info *info, ast_expression **op compile_error(fold_ctx(fold), "internal error: attempted to constant for unsupported operator"); return NULL; } + +/* + * These are all the actual constant folding methods that happen in the AST + * stage of the compiler, i.e eliminating branches for const expressions, + * which is the only supported thing so far. + */ +int fold_cond(ir_value *condval, ast_function *func, ast_ifthen *branch) { + if (condval->vtype == TYPE_FLOAT && condval->hasvalue && condval->cvq == CV_CONST) { + ast_expression_codegen *cgen; + ir_block *elide; + ir_value *dummy; + bool istrue = (fold_immvalue_float(condval) == 1.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 (!(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)) + return false; + if (!ir_block_create_jump(func->curblock, ast_ctx(branch), elide)) + return false; + /* + * now the branch has been eliminates, and the correct block for the constant evaluation + * is expanded into the current block for the function. + */ + func->curblock = elide; + return true; + } + return -1; /* nothing done */ +} diff --git a/parser.h b/parser.h index 147d292..15c0ce4 100644 --- a/parser.h +++ b/parser.h @@ -112,4 +112,7 @@ 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**); + +int fold_cond (ir_value *, ast_function *, ast_ifthen *); + #endif