diff --git a/include/kxoptimizer.h b/include/kxoptimizer.h index 858f46206..afa74a150 100644 --- a/include/kxoptimizer.h +++ b/include/kxoptimizer.h @@ -4,7 +4,7 @@ #include typedef void (*opt_ast_func_t)(kx_context_t *ctx, kx_object_t *node); -extern void opt_ast_constant_folding(kx_context_t *ctx, kx_object_t *node); +extern int opt_ast_constant_folding(kx_context_t *ctx, kx_object_t *node); typedef void (*opt_code_func_t)(kvec_pt(kx_code_t) *fixcode, int start); extern void opt_code_remove_jmp(kvec_pt(kx_code_t) *fixcode, int start); diff --git a/src/ast_analyzer.c b/src/ast_analyzer.c index 86725cec8..00f6bbb6b 100644 --- a/src/ast_analyzer.c +++ b/src/ast_analyzer.c @@ -706,36 +706,45 @@ LOOP_HEAD:; kx_object_t *n = NULL; int vtype = KX_UNKNOWN_T; if (!actx->lvalue && sym->optional == KXDC_CONST && sym->base->init) { - switch (sym->base->init->type) { - case KXVL_INT: - n = kx_gen_int_object(sym->base->init->value.i); - vtype = KX_INT_T; - break; - case KXVL_DBL: - n = kx_gen_dbl_object(sym->base->init->value.d); - vtype = KX_DBL_T; - break; - case KXVL_STR: - n = kx_gen_str_object(sym->base->init->value.s); - vtype = KX_CSTR_T; - break; - case KXVL_BIG: - n = kx_gen_big_object(sym->base->init->value.s); - vtype = KX_BIG_T; - break; - case KXVL_NULL: - n = kx_gen_special_object(KXVL_NULL); - vtype = KX_UND_T; - break; - case KXVL_TRUE: - n = kx_gen_special_object(KXVL_TRUE); - vtype = KX_INT_T; - break; - case KXVL_FALSE: - n = kx_gen_special_object(KXVL_FALSE); - vtype = KX_INT_T; - break; - } + int retry; + do { + retry = 0; + switch (sym->base->init->type) { + case KXVL_INT: + n = kx_gen_int_object(sym->base->init->value.i); + vtype = KX_INT_T; + break; + case KXVL_DBL: + n = kx_gen_dbl_object(sym->base->init->value.d); + vtype = KX_DBL_T; + break; + case KXVL_STR: + n = kx_gen_str_object(sym->base->init->value.s); + vtype = KX_CSTR_T; + break; + case KXVL_BIG: + n = kx_gen_big_object(sym->base->init->value.s); + vtype = KX_BIG_T; + break; + case KXVL_NULL: + n = kx_gen_special_object(KXVL_NULL); + vtype = KX_UND_T; + break; + case KXVL_TRUE: + n = kx_gen_special_object(KXVL_TRUE); + vtype = KX_INT_T; + break; + case KXVL_FALSE: + n = kx_gen_special_object(KXVL_FALSE); + vtype = KX_INT_T; + break; + default: + if (sym->base->init->type < KXST_EXPR) { + retry = opt_ast_constant_folding(ctx, sym->base->init); + } + break; + } + } while (!n && retry); if (n) { node->lhs = n; analyze_ast(ctx, node->lhs, actx); // expanding const value. diff --git a/src/optimizer/opt_cfold.c b/src/optimizer/opt_cfold.c index 6fd5d062e..4438a3628 100644 --- a/src/optimizer/opt_cfold.c +++ b/src/optimizer/opt_cfold.c @@ -1,6 +1,7 @@ #include #define KX_OPT_REPLACE_NODE(node, expr) \ + cctx->changed++; \ node->value.i = expr; \ node->type = KXVL_INT; \ node->lhs = NULL; \ @@ -9,8 +10,9 @@ /**/ #define KX_CONST_VAR_CHECK(p, br) { \ kx_object_t *n = p->br; \ - if (n->type == KXOP_VAR && n->lhs) { \ + if (p->br != n->lhs && n->type == KXOP_VAR && n->lhs) { \ if (n->lhs->type == KXVL_INT || n->lhs->type == KXVL_DBL) { \ + cctx->changed++; \ p->br = n->lhs; \ } \ } \ @@ -23,6 +25,7 @@ typedef struct folding_context_ { int exprlist_r2l; int in_function; int in_case_when; + int changed; } folding_context_t; static void opt_ast_constant_folding_impl(kx_context_t *ctx, kx_object_t *node, folding_context_t *cctx) @@ -223,6 +226,7 @@ static void opt_ast_constant_folding_impl(kx_context_t *ctx, kx_object_t *node, if (v1val % (v2val > 0 ? v2val : -v2val) == 0) { KX_OPT_REPLACE_NODE(node, v1val / v2val); } else { + cctx->changed++; node->value.d = (double)v1val / v2val; node->type = KXVL_DBL; node->lhs = NULL; @@ -468,10 +472,18 @@ static void opt_ast_constant_folding_impl(kx_context_t *ctx, kx_object_t *node, } } -void opt_ast_constant_folding(kx_context_t *ctx, kx_object_t *node) +int opt_ast_constant_folding(kx_context_t *ctx, kx_object_t *node) { folding_context_t cctx = {0}; cctx.anon_check = (node->type == KXST_STMTLIST && node->optional == 0); ++node->optional; - opt_ast_constant_folding_impl(ctx, node, &cctx); + int changed = 0; + do { + cctx.changed = 0; + opt_ast_constant_folding_impl(ctx, node, &cctx); + if (changed < cctx.changed) { + changed = cctx.changed; + } + } while (cctx.changed > 0); + return changed; }