static GMQCC_INLINE ast_expression *fold_op_mul(fold_t *fold, ast_value *a, ast_value *b) { if (isfloat(a)) { if (isvector(b)) { if (fold_can_2(a, b)) return fold_constgen_vector(fold, vec3_mulvf(fold_immvalue_vector(b), fold_immvalue_float(a))); } else { if (fold_can_2(a, b)) return fold_constgen_float(fold, fold_immvalue_float(a) * fold_immvalue_float(b)); } } else if (isvector(a)) { if (isfloat(b)) { if (fold_can_2(a, b)) return fold_constgen_vector(fold, vec3_mulvf(fold_immvalue_vector(a), fold_immvalue_float(b))); } else { if (fold_can_2(a, b)) { return fold_constgen_float(fold, vec3_mulvv(fold_immvalue_vector(a), fold_immvalue_vector(b))); } else if (OPTS_OPTIMIZATION(OPTIM_VECTOR_COMPONENTS) && fold_can_1(a)) { ast_expression *out; if ((out = fold_op_mul_vec(fold, fold_immvalue_vector(a), b, "xyz"))) return out; if ((out = fold_op_mul_vec(fold, fold_immvalue_vector(a), b, "yxz"))) return out; if ((out = fold_op_mul_vec(fold, fold_immvalue_vector(a), b, "zxy"))) return out; } else if (OPTS_OPTIMIZATION(OPTIM_VECTOR_COMPONENTS) && fold_can_1(b)) { ast_expression *out; if ((out = fold_op_mul_vec(fold, fold_immvalue_vector(b), a, "xyz"))) return out; if ((out = fold_op_mul_vec(fold, fold_immvalue_vector(b), a, "yxz"))) return out; if ((out = fold_op_mul_vec(fold, fold_immvalue_vector(b), a, "zxy"))) return out; } } } return NULL; }
uint32_t code_genstring(code_t *code, const char *str) { size_t hash; code_hash_entry_t existing; if (!str) return 0; if (!*str) { if (!code->string_cached_empty) { code->string_cached_empty = vec_size(code->chars); vec_push(code->chars, 0); } return code->string_cached_empty; } if (OPTS_OPTIMIZATION(OPTIM_OVERLAP_STRINGS)) { hash = ((unsigned char*)str)[strlen(str)-1]; CODE_HASH_ENTER(existing) = code_util_str_htgeth(code->string_cache, str, hash); } else { hash = util_hthash(code->string_cache, str); CODE_HASH_ENTER(existing) = util_htgeth(code->string_cache, str, hash); } if (CODE_HASH_ENTER(existing)) return CODE_HASH_LEAVE(existing); CODE_HASH_LEAVE(existing) = vec_size(code->chars); vec_append(code->chars, strlen(str)+1, str); util_htseth(code->string_cache, str, hash, CODE_HASH_ENTER(existing)); return CODE_HASH_LEAVE(existing); }
code_t *code_init() { static lex_ctx_t empty_ctx = {0, 0, 0}; static prog_section_function_t empty_function = {0,0,0,0,0,0,0,{0,0,0,0,0,0,0,0}}; static prog_section_statement_t empty_statement = {0,{0},{0},{0}}; static prog_section_def_t empty_def = {0, 0, 0}; code_t *code = (code_t*)mem_a(sizeof(code_t)); int i = 0; memset(code, 0, sizeof(code_t)); code->entfields = 0; code->string_cache = util_htnew(OPTS_OPTIMIZATION(OPTIM_OVERLAP_STRINGS) ? 0x100 : 1024); /* * The way progs.dat is suppose to work is odd, there needs to be * some null (empty) statements, functions, and 28 globals */ for(; i < 28; i++) vec_push(code->globals, 0); vec_push(code->chars, '\0'); vec_push(code->functions, empty_function); code_push_statement(code, &empty_statement, empty_ctx); vec_push(code->defs, empty_def); vec_push(code->fields, empty_def); return code; }
static GMQCC_INLINE 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 */ }
code_t::code_t() { static lex_ctx_t empty_ctx = {0, 0, 0}; static prog_section_function_t empty_function = {0,0,0,0,0,0,0,{0,0,0,0,0,0,0,0}}; static prog_section_statement_t empty_statement = {0,{0},{0},{0}}; static prog_section_def_t empty_def = {0, 0, 0}; string_cache = util_htnew(OPTS_OPTIMIZATION(OPTIM_OVERLAP_STRINGS) ? 0x100 : 1024); // The way progs.dat is suppose to work is odd, there needs to be // some null (empty) statements, functions, and 28 globals globals.insert(globals.begin(), 28, 0); chars.push_back('\0'); functions.push_back(empty_function); code_push_statement(this, &empty_statement, empty_ctx); defs.push_back(empty_def); fields.push_back(empty_def); }