Move const-branch-elision into fold.c

This commit is contained in:
Dale Weiler 2013-07-31 19:34:38 +00:00
parent 3e24b5a74b
commit 10b75fd8b9
4 changed files with 43 additions and 29 deletions

35
ast.c
View file

@ -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"));

2
ast.h
View file

@ -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);

32
fold.c
View file

@ -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 */
}

View file

@ -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