- case opid2('-', 'P'):
- return isfloat (a) ? fold_constgen_float (fold, fold_immvalue_float(a))
- : isvector(a) ? fold_constgen_vector(fold, vec3_neg(fold_immvalue_vector(a)))
- : NULL;
- case opid2('!', 'P'):
- return isfloat (a) ? fold_constgen_float (fold, !fold_immvalue_float(a))
- : isvector(a) ? fold_constgen_vector(fold, vec3_not(fold_immvalue_vector(a)))
- : isstring(a) ? fold_constgen_float (fold, !fold_immvalue_string(a) || OPTS_FLAG(TRUE_EMPTY_STRINGS) ? 0 : !*fold_immvalue_string(a))
- : NULL;
- case opid1('+'):
- return isfloats(a,b) ? fold_constgen_float (fold, fold_immvalue_float(a) + fold_immvalue_float(b))
- : isvectors(a,b) ? fold_constgen_vector(fold, vec3_add(fold_immvalue_vector(a), fold_immvalue_vector(b)))
- : NULL;
- case opid1('-'):
- return isfloats(a,b) ? fold_constgen_float (fold, fold_immvalue_float(a) - fold_immvalue_float(b))
- : isvectors(a,b) ? fold_constgen_vector(fold, vec3_sub(fold_immvalue_vector(a), fold_immvalue_vector(b)))
- : NULL;
- case opid1('%'):
- return isfloats(a,b) ? fold_constgen_float (fold, (qcfloat_t)(((qcint_t)fold_immvalue_float(a)) % ((qcint_t)fold_immvalue_float(b))))
- : NULL;
- case opid1('|'):
- return isfloats(a,b) ? fold_constgen_float (fold, (qcfloat_t)(((qcint_t)fold_immvalue_float(a)) | ((qcint_t)fold_immvalue_float(b))))
- : NULL;
- case opid1('&'):
- return isfloats(a,b) ? fold_constgen_float (fold, (qcfloat_t)(((qcint_t)fold_immvalue_float(a)) & ((qcint_t)fold_immvalue_float(b))))
- : NULL;
- case opid1('^'):
- return isfloats(a,b) ? fold_constgen_float (fold, (qcfloat_t)(((qcint_t)fold_immvalue_float(a)) ^ ((qcint_t)fold_immvalue_float(b))))
- : isvectors(a,b) ? fold_constgen_vector(fold, vec3_xor (fold_immvalue_vector(a), fold_immvalue_vector(b)))
- : isvector(a)&&isfloat(b) ? fold_constgen_vector(fold, vec3_xorvf(fold_immvalue_vector(a), fold_immvalue_float (b)))
- : NULL;
- case opid2('<','<'):
- return isfloats(a,b) ? fold_constgen_float (fold, (qcfloat_t)(((qcuint_t)(fold_immvalue_float(a)) << ((qcuint_t)fold_immvalue_float(b)))))
- : NULL;
- case opid2('>','>'):
- return isfloats(a,b) ? fold_constgen_float (fold, (qcfloat_t)(((qcuint_t)(fold_immvalue_float(a)) >> ((qcuint_t)fold_immvalue_float(b)))))
- : NULL;
- case opid2('*','*'):
- return isfloats(a,b) ? fold_constgen_float (fold, (qcfloat_t)powf(fold_immvalue_float(a), fold_immvalue_float(b)))
- : NULL;
- case opid2('!','='):
- return isfloats(a,b) ? fold_constgen_float (fold, fold_immvalue_float(a) != fold_immvalue_float(b))
- : NULL;
- case opid2('=','='):
- return isfloats(a,b) ? fold_constgen_float (fold, fold_immvalue_float(a) == fold_immvalue_float(b))
- : NULL;
- case opid2('~','P'):
- return isfloat(a) ? fold_constgen_float (fold, ~(qcint_t)fold_immvalue_float(a))
- : NULL;
-
- case opid1('*'): return fold_op_mul(fold, a, b);
- case opid1('/'):
- /* TODO: seperate function for this case */
- return NULL;
- case opid2('|','|'):
- /* TODO: seperate function for this case */
- return NULL;
- case opid2('&','&'):
- /* TODO: seperate function for this case */
- return NULL;
- case opid2('?',':'):
- /* TODO: seperate function for this case */
- return NULL;
- case opid3('<','=','>'):
- /* TODO: seperate function for this case */
- return NULL;
+ fold_op_case(2, ('-', 'P'), neg, (fold, a));
+ fold_op_case(2, ('!', 'P'), not, (fold, a));
+ fold_op_case(1, ('+'), add, (fold, a, b));
+ fold_op_case(1, ('-'), sub, (fold, a, b));
+ fold_op_case(1, ('*'), mul, (fold, a, b));
+ fold_op_case(1, ('/'), div, (fold, a, b));
+ fold_op_case(1, ('%'), mod, (fold, a, b));
+ fold_op_case(1, ('|'), bor, (fold, a, b));
+ fold_op_case(1, ('&'), band, (fold, a, b));
+ fold_op_case(1, ('^'), xor, (fold, a, b));
+ fold_op_case(2, ('<', '<'), lshift, (fold, a, b));
+ fold_op_case(2, ('>', '>'), rshift, (fold, a, b));
+ fold_op_case(2, ('|', '|'), andor, (fold, a, b, true));
+ fold_op_case(2, ('&', '&'), andor, (fold, a, b, false));
+ fold_op_case(2, ('?', ':'), tern, (fold, a, b, c));
+ fold_op_case(2, ('*', '*'), exp, (fold, a, b));
+ fold_op_case(3, ('<','=','>'), lteqgt, (fold, a, b));
+ 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));
+ }
+ #undef fold_op_case
+ compile_error(fold_ctx(fold), "internal error: attempted to constant-fold for unsupported operator");
+ return NULL;
+}
+
+#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])));