+
+#define expect(X) \
+ do { \
+ if (vec_size(params) != (X)) { \
+ compile_error( \
+ fold_ctx(fold), \
+ "internal error: attempted to constant-fold with invalid paramaters for intrinsic `%s`", \
+ intrin \
+ ); \
+ return NULL; \
+ } \
+ } while (0)
+
+ast_expression *fold_intrin(fold_t *fold, const char *intrin, ast_expression **params) {
+ if (!fold) return NULL;
+ if (!intrin) return NULL;
+
+ if (!strcmp(intrin, "__builtin_exp")) {
+ expect(1);
+ ++opts_optimizationcount[OPTIM_CONST_FOLD];
+ return fold_constgen_float(fold, exp(fold_immvalue_float((ast_value*)params[0])));
+ }
+
+ if (!strcmp(intrin, "__builtin_mod")) {
+ expect(2);
+ ++opts_optimizationcount[OPTIM_CONST_FOLD];
+ return fold_constgen_float(
+ fold,
+ fmodf(
+ fold_immvalue_float((ast_value*)params[0]),
+ fold_immvalue_float((ast_value*)params[1])
+ )
+ );
+ }
+
+ if (!strcmp(intrin, "__builtin_pow")) {
+ expect(2);
+ ++opts_optimizationcount[OPTIM_CONST_FOLD];
+ return fold_constgen_float(
+ fold,
+ powf(
+ fold_immvalue_float((ast_value*)params[0]),
+ fold_immvalue_float((ast_value*)params[1])
+ )
+ );
+ }
+
+ if (!strcmp(intrin, "__builtin_isnan")) {
+ expect(1);
+ ++opts_optimizationcount[OPTIM_CONST_FOLD];
+ return fold_constgen_float(fold, isnan(fold_immvalue_float((ast_value*)params[0])) != 0.0f);
+ }
+
+ if (!strcmp(intrin, "__builtin_fabs")) {
+ expect(1);
+ ++opts_optimizationcount[OPTIM_CONST_FOLD];
+ return fold_constgen_float(fold, fabs(fold_immvalue_float((ast_value*)params[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
+#undef fold_immvalue_float
+#undef fold_immvalue_string
+#undef fold_immvalue_vector
+#undef fold_can_1
+#undef fold_can_2
+
+#define isfloat(X) ((X)->vtype == TYPE_FLOAT)
+/*#define isstring(X) ((X)->vtype == TYPE_STRING)*/
+/*#define isvector(X) ((X)->vtype == TYPE_VECTOR)*/
+#define fold_immvalue_float(X) ((X)->constval.vfloat)
+/*#define fold_immvalue_vector(X) ((X)->constval.vvec)*/
+/*#define fold_immvalue_string(X) ((X)->constval.vstring)*/
+#define fold_can_1(X) ((X)->hasvalue && (X)->cvq == CV_CONST)
+/*#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) {
+ 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) != 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) {
+ /*
+ * 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))
+ return false;
+ if (!ir_block_create_jump(func->curblock, ast_ctx(branch), elide))
+ return false;
+ /*
+ * now the branch has been eliminated and the correct block for the constant evaluation
+ * is expanded into the current block for the function.
+ */
+ func->curblock = elide;
+ ++opts_optimizationcount[OPTIM_CONST_FOLD_DCE];
+ return true;
+ }
+ return -1; /* nothing done */
+}