a whole lotta 'm_'s

This commit is contained in:
Wolfgang Bumiller 2015-01-24 12:25:46 +01:00
parent e7d1e701c4
commit 9d98805dfb
7 changed files with 3004 additions and 3065 deletions

1941
ast.cpp

File diff suppressed because it is too large Load diff

236
ast.h
View file

@ -93,9 +93,7 @@ enum {
TYPE_ast_state /* 22 */
};
#define ast_istype(x, t) ( ((ast_node*)x)->node_type == (TYPE_##t) )
#define ast_ctx(node) (((ast_node*)(node))->context)
#define ast_side_effects(node) (((ast_node*)(node))->side_effects)
#define ast_istype(x, t) ( (x)->m_node_type == (TYPE_##t) )
/* Node interface with common components
*/
@ -103,23 +101,27 @@ typedef void ast_node_delete(ast_node*);
struct ast_node
{
lex_ctx_t context;
//ast_node() = delete;
//ast_node(lex_ctx_t, int nodetype);
//virtual ~ast_node();
lex_ctx_t m_context;
/* I don't feel comfortable using keywords like 'delete' as names... */
ast_node_delete *destroy;
int node_type;
ast_node_delete *m_destroy;
int m_node_type;
/* keep_node: if a node contains this node, 'keep_node'
* prevents its dtor from destroying this node as well.
*/
bool keep_node;
bool side_effects;
bool m_keep_node;
bool m_side_effects;
};
#define ast_delete(x) (*( ((ast_node*)(x))->destroy ))((ast_node*)(x))
#define ast_unref(x) do \
{ \
if (! (((ast_node*)(x))->keep_node) ) { \
ast_delete(x); \
} \
#define ast_delete(x) ( (x)->m_destroy((x)) )
#define ast_unref(x) do \
{ \
if (! (x)->m_keep_node ) { \
ast_delete(x); \
} \
} while(0)
/* Expression interface
@ -144,25 +146,25 @@ typedef bool ast_expression_codegen(ast_expression*,
struct ast_expression : ast_node {
ast_expression() {}
ast_expression_codegen *codegen;
qc_type vtype;
ast_expression *next;
ast_expression_codegen *m_codegen;
qc_type m_vtype;
ast_expression *m_next;
/* arrays get a member-count */
size_t count;
std::vector<ast_value*> type_params;
size_t m_count;
std::vector<ast_value*> m_type_params;
ast_flag_t flags;
ast_flag_t m_flags;
/* void foo(string...) gets varparam set as a restriction
* for variadic parameters
*/
ast_expression *varparam;
ast_expression *m_varparam;
/* The codegen functions should store their output values
* so we can call it multiple times without re-evaluating.
* Store lvalue and rvalue seperately though. So that
* ast_entfield for example can generate both if required.
*/
ir_value *outl;
ir_value *outr;
ir_value *m_outl;
ir_value *m_outr;
};
/* Value
@ -184,36 +186,36 @@ union basic_value_t {
struct ast_value : ast_expression
{
const char *name;
const char *desc;
const char *m_name;
const char *m_desc;
const char *argcounter;
const char *m_argcounter;
int cvq; /* const/var qualifier */
bool isfield; /* this declares a field */
bool isimm; /* an immediate, not just const */
bool hasvalue;
bool inexact; /* inexact coming from folded expression */
basic_value_t constval;
int m_cvq; /* const/var qualifier */
bool m_isfield; /* this declares a field */
bool m_isimm; /* an immediate, not just const */
bool m_hasvalue;
bool m_inexact; /* inexact coming from folded expression */
basic_value_t m_constval;
/* for TYPE_ARRAY we have an optional vector
* of constants when an initializer list
* was provided.
*/
std::vector<basic_value_t> initlist;
std::vector<basic_value_t> m_initlist;
/* usecount for the parser */
size_t uses;
size_t m_uses;
ir_value *ir_v;
ir_value **ir_values;
size_t ir_value_count;
ir_value *m_ir_v;
ir_value **m_ir_values;
size_t m_ir_value_count;
/* ONLY for arrays in progs version up to 6 */
ast_value *setter;
ast_value *getter;
ast_value *m_setter;
ast_value *m_getter;
bool intrinsic; /* true if associated with intrinsic */
bool m_intrinsic; /* true if associated with intrinsic */
};
ast_value* ast_value_new(lex_ctx_t ctx, const char *name, qc_type qctype);
@ -252,11 +254,11 @@ enum ast_binary_ref {
*/
struct ast_binary : ast_expression
{
int op;
ast_expression *left;
ast_expression *right;
ast_binary_ref refs;
bool right_first;
int m_op;
ast_expression *m_left;
ast_expression *m_right;
ast_binary_ref m_refs;
bool m_right_first;
};
ast_binary* ast_binary_new(lex_ctx_t ctx,
int op,
@ -270,12 +272,12 @@ ast_binary* ast_binary_new(lex_ctx_t ctx,
*/
struct ast_binstore : ast_expression
{
int opstore;
int opbin;
ast_expression *dest;
ast_expression *source;
int m_opstore;
int m_opbin;
ast_expression *m_dest;
ast_expression *m_source;
/* for &~= which uses the destination in a binary in source we can use this */
bool keep_dest;
bool m_keep_dest;
};
ast_binstore* ast_binstore_new(lex_ctx_t ctx,
int storeop,
@ -289,8 +291,8 @@ ast_binstore* ast_binstore_new(lex_ctx_t ctx,
*/
struct ast_unary : ast_expression
{
int op;
ast_expression *operand;
int m_op;
ast_expression *m_operand;
};
ast_unary* ast_unary_new(lex_ctx_t ctx,
int op,
@ -304,7 +306,7 @@ ast_unary* ast_unary_new(lex_ctx_t ctx,
*/
struct ast_return : ast_expression
{
ast_expression *operand;
ast_expression *m_operand;
};
ast_return* ast_return_new(lex_ctx_t ctx,
ast_expression *expr);
@ -325,9 +327,9 @@ ast_return* ast_return_new(lex_ctx_t ctx,
struct ast_entfield : ast_expression
{
/* The entity can come from an expression of course. */
ast_expression *entity;
ast_expression *m_entity;
/* As can the field, it just must result in a value of TYPE_FIELD */
ast_expression *field;
ast_expression *m_field;
};
ast_entfield* ast_entfield_new(lex_ctx_t ctx, ast_expression *entity, ast_expression *field);
ast_entfield* ast_entfield_new_force(lex_ctx_t ctx, ast_expression *entity, ast_expression *field, const ast_expression *outtype);
@ -339,10 +341,10 @@ ast_entfield* ast_entfield_new_force(lex_ctx_t ctx, ast_expression *entity, ast_
*/
struct ast_member : ast_expression
{
ast_expression *owner;
unsigned int field;
const char *name;
bool rvalue;
ast_expression *m_owner;
unsigned int m_field;
const char *m_name;
bool m_rvalue;
};
ast_member* ast_member_new(lex_ctx_t ctx, ast_expression *owner, unsigned int field, const char *name);
void ast_member_delete(ast_member*);
@ -361,8 +363,8 @@ bool ast_member_set_name(ast_member*, const char *name);
*/
struct ast_array_index : ast_expression
{
ast_expression *array;
ast_expression *index;
ast_expression *m_array;
ast_expression *m_index;
};
ast_array_index* ast_array_index_new(lex_ctx_t ctx, ast_expression *array, ast_expression *index);
@ -372,7 +374,7 @@ ast_array_index* ast_array_index_new(lex_ctx_t ctx, ast_expression *array, ast_e
*/
struct ast_argpipe : ast_expression
{
ast_expression *index;
ast_expression *m_index;
};
ast_argpipe* ast_argpipe_new(lex_ctx_t ctx, ast_expression *index);
@ -383,9 +385,9 @@ ast_argpipe* ast_argpipe_new(lex_ctx_t ctx, ast_expression *index);
*/
struct ast_store : ast_expression
{
int op;
ast_expression *dest;
ast_expression *source;
int m_op;
ast_expression *m_dest;
ast_expression *m_source;
};
ast_store* ast_store_new(lex_ctx_t ctx, int op,
ast_expression *d, ast_expression *s);
@ -403,10 +405,10 @@ ast_store* ast_store_new(lex_ctx_t ctx, int op,
*/
struct ast_ifthen : ast_expression
{
ast_expression *cond;
ast_expression *m_cond;
/* It's all just 'expressions', since an ast_block is one too. */
ast_expression *on_true;
ast_expression *on_false;
ast_expression *m_on_true;
ast_expression *m_on_false;
};
ast_ifthen* ast_ifthen_new(lex_ctx_t ctx, ast_expression *cond, ast_expression *ontrue, ast_expression *onfalse);
@ -425,10 +427,10 @@ ast_ifthen* ast_ifthen_new(lex_ctx_t ctx, ast_expression *cond, ast_expression *
*/
struct ast_ternary : ast_expression
{
ast_expression *cond;
ast_expression *m_cond;
/* It's all just 'expressions', since an ast_block is one too. */
ast_expression *on_true;
ast_expression *on_false;
ast_expression *m_on_true;
ast_expression *m_on_false;
};
ast_ternary* ast_ternary_new(lex_ctx_t ctx, ast_expression *cond, ast_expression *ontrue, ast_expression *onfalse);
@ -457,19 +459,19 @@ continue: // a 'continue' will jump here
*/
struct ast_loop : ast_expression
{
ast_expression *initexpr;
ast_expression *precond;
ast_expression *postcond;
ast_expression *increment;
ast_expression *body;
ast_expression *m_initexpr;
ast_expression *m_precond;
ast_expression *m_postcond;
ast_expression *m_increment;
ast_expression *m_body;
/* For now we allow a seperate flag on whether or not the condition
* is supposed to be true or false.
* That way, the parser can generate a 'while not(!x)' for `while(x)`
* if desired, which is useful for the new -f{true,false}-empty-strings
* flag.
*/
bool pre_not;
bool post_not;
bool m_pre_not;
bool m_post_not;
};
ast_loop* ast_loop_new(lex_ctx_t ctx,
ast_expression *initexpr,
@ -482,8 +484,8 @@ ast_loop* ast_loop_new(lex_ctx_t ctx,
*/
struct ast_breakcont : ast_expression
{
bool is_continue;
unsigned int levels;
bool m_is_continue;
unsigned int m_levels;
};
ast_breakcont* ast_breakcont_new(lex_ctx_t ctx, bool iscont, unsigned int levels);
@ -498,14 +500,14 @@ ast_breakcont* ast_breakcont_new(lex_ctx_t ctx, bool iscont, unsigned int levels
* TODO: Ticket #20
*/
struct ast_switch_case {
ast_expression *value; /* #20 will replace this */
ast_expression *code;
ast_expression *m_value; /* #20 will replace this */
ast_expression *m_code;
};
struct ast_switch : ast_expression
{
ast_expression *operand;
std::vector<ast_switch_case> cases;
ast_expression *m_operand;
std::vector<ast_switch_case> m_cases;
};
ast_switch* ast_switch_new(lex_ctx_t ctx, ast_expression *op);
@ -516,12 +518,12 @@ ast_switch* ast_switch_new(lex_ctx_t ctx, ast_expression *op);
*/
struct ast_label : ast_expression
{
const char *name;
ir_block *irblock;
std::vector<ast_goto*> gotos;
const char *m_name;
ir_block *m_irblock;
std::vector<ast_goto*> m_gotos;
/* means it has not yet been defined */
bool undefined;
bool m_undefined;
};
ast_label* ast_label_new(lex_ctx_t ctx, const char *name, bool undefined);
@ -532,9 +534,9 @@ ast_label* ast_label_new(lex_ctx_t ctx, const char *name, bool undefined);
*/
struct ast_goto : ast_expression
{
const char *name;
ast_label *target;
ir_block *irblock_from;
const char *m_name;
ast_label *m_target;
ir_block *m_irblock_from;
};
ast_goto* ast_goto_new(lex_ctx_t ctx, const char *name);
@ -546,8 +548,8 @@ void ast_goto_set_label(ast_goto*, ast_label*);
*/
struct ast_state : ast_expression
{
ast_expression *framenum;
ast_expression *nextthink;
ast_expression *m_framenum;
ast_expression *m_nextthink;
};
ast_state* ast_state_new(lex_ctx_t ctx, ast_expression *frame, ast_expression *think);
void ast_state_delete(ast_state*);
@ -564,9 +566,9 @@ void ast_state_delete(ast_state*);
*/
struct ast_call : ast_expression
{
ast_expression *func;
std::vector<ast_expression *> params;
ast_expression *va_count;
ast_expression *m_func;
std::vector<ast_expression *> m_params;
ast_expression *m_va_count;
};
ast_call* ast_call_new(lex_ctx_t ctx,
ast_expression *funcexpr);
@ -577,9 +579,9 @@ bool ast_call_check_types(ast_call*, ast_expression *this_func_va_type);
*/
struct ast_block : ast_expression
{
std::vector<ast_value*> locals;
std::vector<ast_expression*> exprs;
std::vector<ast_expression*> collect;
std::vector<ast_value*> m_locals;
std::vector<ast_expression*> m_exprs;
std::vector<ast_expression*> m_collect;
};
ast_block* ast_block_new(lex_ctx_t ctx);
void ast_block_delete(ast_block*);
@ -598,39 +600,37 @@ bool GMQCC_WARN ast_block_add_expr(ast_block*, ast_expression*);
* pointers could just work with a name. However, this way could be
* more flexible, and adds no real complexity.
*/
struct ast_function
struct ast_function : ast_node
{
ast_node node;
ast_value *m_function_type;
const char *m_name;
ast_value *function_type;
const char *name;
int builtin;
int m_builtin;
/* list of used-up names for statics without the count suffix */
std::vector<char*> static_names;
std::vector<char*> m_static_names;
/* number of static variables, by convention this includes the
* ones without the count-suffix - remember this when dealing
* with savegames. uint instead of size_t as %zu in printf is
* C99, so no windows support. */
unsigned int static_count;
unsigned int m_static_count;
ir_function *ir_func;
ir_block *curblock;
std::vector<ir_block*> breakblocks;
std::vector<ir_block*> continueblocks;
ir_function *m_ir_func;
ir_block *m_curblock;
std::vector<ir_block*> m_breakblocks;
std::vector<ir_block*> m_continueblocks;
size_t labelcount;
size_t m_labelcount;
/* in order for thread safety - for the optional
* channel abesed multithreading... keeping a buffer
* here to use in ast_function_label.
*/
char labelbuf[64];
std::vector<std::unique_ptr<ast_block>> blocks;
ast_value *varargs;
ast_value *argc;
ast_value *fixedparams;
ast_value *return_value;
char m_labelbuf[64];
std::vector<std::unique_ptr<ast_block>> m_blocks;
ast_value *m_varargs;
ast_value *m_argc;
ast_value *m_fixedparams;
ast_value *m_return_value;
};
ast_function* ast_function_new(lex_ctx_t ctx, const char *name, ast_value *vtype);
/* This will NOT delete the underlying ast_value */

100
fold.cpp
View file

@ -535,10 +535,10 @@ static GMQCC_INLINE void sfloat_init(sfloat_state_t *state) {
* This file is thus, split into two parts.
*/
#define isfloat(X) (((ast_expression*)(X))->vtype == TYPE_FLOAT)
#define isvector(X) (((ast_expression*)(X))->vtype == TYPE_VECTOR)
#define isstring(X) (((ast_expression*)(X))->vtype == TYPE_STRING)
#define isarray(X) (((ast_expression*)(X))->vtype == TYPE_ARRAY)
#define isfloat(X) (((ast_expression*)(X))->m_vtype == TYPE_FLOAT)
#define isvector(X) (((ast_expression*)(X))->m_vtype == TYPE_VECTOR)
#define isstring(X) (((ast_expression*)(X))->m_vtype == TYPE_STRING)
#define isarray(X) (((ast_expression*)(X))->m_vtype == TYPE_ARRAY)
#define isfloats(X,Y) (isfloat (X) && isfloat (Y))
/*
@ -858,15 +858,15 @@ end:
}
qcfloat_t fold::immvalue_float(ast_value *value) {
return value->constval.vfloat;
return value->m_constval.vfloat;
}
vec3_t fold::immvalue_vector(ast_value *value) {
return value->constval.vvec;
return value->m_constval.vvec;
}
const char *fold::immvalue_string(ast_value *value) {
return value->constval.vstring;
return value->m_constval.vstring;
}
lex_ctx_t fold::ctx() {
@ -878,32 +878,32 @@ lex_ctx_t fold::ctx() {
}
bool fold::immediate_true(ast_value *v) {
switch (v->vtype) {
switch (v->m_vtype) {
case TYPE_FLOAT:
return !!v->constval.vfloat;
return !!v->m_constval.vfloat;
case TYPE_INTEGER:
return !!v->constval.vint;
return !!v->m_constval.vint;
case TYPE_VECTOR:
if (OPTS_FLAG(CORRECT_LOGIC))
return vec3_pbool(v->constval.vvec);
return !!(v->constval.vvec.x);
return vec3_pbool(v->m_constval.vvec);
return !!(v->m_constval.vvec.x);
case TYPE_STRING:
if (!v->constval.vstring)
if (!v->m_constval.vstring)
return false;
if (OPTS_FLAG(TRUE_EMPTY_STRINGS))
return true;
return !!v->constval.vstring[0];
return !!v->m_constval.vstring[0];
default:
compile_error(ctx(), "internal error: fold_immediate_true on invalid type");
break;
}
return !!v->constval.vfunc;
return !!v->m_constval.vfunc;
}
/* Handy macros to determine if an ast_value can be constant folded. */
#define fold_can_1(X) \
(ast_istype(((ast_expression*)(X)), ast_value) && (X)->hasvalue && ((X)->cvq == CV_CONST) && \
((ast_expression*)(X))->vtype != TYPE_FUNCTION)
(ast_istype(((ast_expression*)(X)), ast_value) && (X)->m_hasvalue && ((X)->m_cvq == CV_CONST) && \
((ast_expression*)(X))->m_vtype != TYPE_FUNCTION)
#define fold_can_2(X, Y) (fold_can_1(X) && fold_can_1(Y))
@ -938,7 +938,7 @@ bool fold::generate(ir_builder *ir) {
if (!ast_global_codegen((cur = it), ir, false)) goto err;
return true;
err:
con_out("failed to generate global %s\n", cur->name);
con_out("failed to generate global %s\n", cur->m_name);
delete ir;
return false;
}
@ -957,14 +957,14 @@ fold::~fold() {
ast_expression *fold::constgen_float(qcfloat_t value, bool inexact) {
for (auto &it : m_imm_float)
if (!memcmp(&it->constval.vfloat, &value, sizeof(qcfloat_t)))
if (!memcmp(&it->m_constval.vfloat, &value, sizeof(qcfloat_t)))
return (ast_expression*)it;
ast_value *out = ast_value_new(ctx(), "#IMMEDIATE", TYPE_FLOAT);
out->cvq = CV_CONST;
out->hasvalue = true;
out->inexact = inexact;
out->constval.vfloat = value;
out->m_cvq = CV_CONST;
out->m_hasvalue = true;
out->m_inexact = inexact;
out->m_constval.vfloat = value;
m_imm_float.push_back(out);
@ -973,13 +973,13 @@ ast_expression *fold::constgen_float(qcfloat_t value, bool inexact) {
ast_expression *fold::constgen_vector(vec3_t value) {
for (auto &it : m_imm_vector)
if (vec3_cmp(it->constval.vvec, value))
if (vec3_cmp(it->m_constval.vvec, value))
return (ast_expression*)it;
ast_value *out = ast_value_new(ctx(), "#IMMEDIATE", TYPE_VECTOR);
out->cvq = CV_CONST;
out->hasvalue = true;
out->constval.vvec = value;
out->m_cvq = CV_CONST;
out->m_hasvalue = true;
out->m_constval.vvec = value;
m_imm_vector.push_back(out);
@ -998,15 +998,15 @@ ast_expression *fold::constgen_string(const char *str, bool translate) {
char name[32];
util_snprintf(name, sizeof(name), "dotranslate_%zu", m_parser->translated++);
out = ast_value_new(ctx(), name, TYPE_STRING);
out->flags |= AST_FLAG_INCLUDE_DEF; /* def needs to be included for translatables */
out->m_flags |= AST_FLAG_INCLUDE_DEF; /* def needs to be included for translatables */
} else {
out = ast_value_new(ctx(), "#IMMEDIATE", TYPE_STRING);
}
out->cvq = CV_CONST;
out->hasvalue = true;
out->isimm = true;
out->constval.vstring = parser_strdup(str);
out->m_cvq = CV_CONST;
out->m_hasvalue = true;
out->m_isimm = true;
out->m_constval.vstring = parser_strdup(str);
m_imm_string.push_back(out);
util_htseth(table, str, hash, out);
@ -1057,7 +1057,7 @@ inexact_possible:
bool fold::check_inexact_float(ast_value *a, ast_value *b) {
if (!OPTS_WARN(WARN_INEXACT_COMPARES))
return false;
if (!a->inexact && !b->inexact)
if (!a->m_inexact && !b->m_inexact)
return false;
return compile_warning(ctx(), WARN_INEXACT_COMPARES, "inexact value in comparison");
}
@ -1070,8 +1070,8 @@ ast_expression *fold::op_mul_vec(vec3_t vec, ast_value *sel, const char *set) {
ast_expression *out;
++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS];
out = (ast_expression*)ast_member_new(ctx(), (ast_expression*)sel, set[0]-'x', nullptr);
out->keep_node = false;
((ast_member*)out)->rvalue = true;
out->m_keep_node = false;
((ast_member*)out)->m_rvalue = true;
if (x != -1.0f)
return (ast_expression*)ast_binary_new(ctx(), INSTR_MUL_F, constgen_float(x, false), out);
}
@ -1370,7 +1370,7 @@ ast_expression *fold::op_length(ast_value *a) {
if (fold_can_1(a) && isstring(a))
return constgen_float(strlen(immvalue_string(a)), false);
if (isarray(a))
return constgen_float(a->initlist.size(), false);
return constgen_float(a->m_initlist.size(), false);
return nullptr;
}
@ -1522,18 +1522,18 @@ ast_expression *fold::intrinsic(const char *intrinsic, ast_expression **arg) {
#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_can_1(X) ((X)->hasvalue && (X)->cvq == CV_CONST)
#define isfloat(X) ((X)->m_vtype == TYPE_FLOAT)
/*#define isstring(X) ((X)->m_vtype == TYPE_STRING)*/
/*#define isvector(X) ((X)->m_vtype == TYPE_VECTOR)*/
#define fold_can_1(X) ((X)->m_hasvalue && (X)->m_cvq == CV_CONST)
/*#define fold_can_2(X,Y) (fold_can_1(X) && fold_can_1(Y))*/
qcfloat_t fold::immvalue_float(ir_value *value) {
return value->constval.vfloat;
return value->m_constval.vfloat;
}
vec3_t fold::immvalue_vector(ir_value *value) {
return value->constval.vvec;
return value->m_constval.vvec;
}
ast_expression *fold::superfluous(ast_expression *left, ast_expression *right, int op) {
@ -1608,10 +1608,10 @@ int fold::cond(ir_value *condval, ast_function *func, ast_ifthen *branch) {
ast_expression_codegen *cgen;
ir_block *elide;
ir_value *dummy;
bool istrue = (immvalue_float(condval) != 0.0f && branch->on_true);
bool isfalse = (immvalue_float(condval) == 0.0f && branch->on_false);
ast_expression *path = (istrue) ? branch->on_true :
(isfalse) ? branch->on_false : nullptr;
bool istrue = (immvalue_float(condval) != 0.0f && branch->m_on_true);
bool isfalse = (immvalue_float(condval) == 0.0f && branch->m_on_false);
ast_expression *path = (istrue) ? branch->m_on_true :
(isfalse) ? branch->m_on_false : nullptr;
if (!path) {
/*
* no path to take implies that the evaluation is if(0) and there
@ -1621,17 +1621,17 @@ int fold::cond(ir_value *condval, ast_function *func, ast_ifthen *branch) {
return true;
}
if (!(elide = ir_function_create_block(ast_ctx(branch), func->ir_func, ast_function_label(func, ((istrue) ? "ontrue" : "onfalse")))))
if (!(elide = ir_function_create_block(branch->m_context, func->m_ir_func, ast_function_label(func, ((istrue) ? "ontrue" : "onfalse")))))
return false;
if (!(*(cgen = path->codegen))((ast_expression*)path, func, false, &dummy))
if (!(*(cgen = path->m_codegen))((ast_expression*)path, func, false, &dummy))
return false;
if (!ir_block_create_jump(func->curblock, ast_ctx(branch), elide))
if (!ir_block_create_jump(func->m_curblock, branch->m_context, 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;
func->m_curblock = elide;
++opts_optimizationcount[OPTIM_CONST_FOLD_DCE];
return true;
}

File diff suppressed because it is too large Load diff

2120
ir.cpp

File diff suppressed because it is too large Load diff

176
ir.h
View file

@ -39,24 +39,21 @@ struct ir_value {
ir_value(std::string&& name, store_type storetype, qc_type vtype);
~ir_value();
void* operator new(std::size_t); // to use mem_a
void operator delete(void*); // to use mem_d
std::string m_name;
std::string name;
qc_type m_vtype;
store_type m_store;
lex_ctx_t m_context;
qc_type m_fieldtype; // even the IR knows the subtype of a field
qc_type m_outtype; // and the output type of a function
int m_cvq; // 'const' vs 'var' qualifier
ir_flag_t m_flags;
qc_type vtype;
store_type store;
lex_ctx_t context;
qc_type fieldtype; // even the IR knows the subtype of a field
qc_type outtype; // and the output type of a function
int cvq; // 'const' vs 'var' qualifier
ir_flag_t flags;
std::vector<ir_instr *> reads;
std::vector<ir_instr *> writes;
std::vector<ir_instr *> m_reads;
std::vector<ir_instr *> m_writes;
// constant values
bool hasvalue;
bool m_hasvalue;
union {
qcfloat_t vfloat;
int vint;
@ -65,7 +62,7 @@ struct ir_value {
char *vstring;
ir_value *vpointer;
ir_function *vfunc;
} constval;
} m_constval;
struct {
int32_t globaladdr;
@ -73,17 +70,17 @@ struct ir_value {
int32_t local; // filled by the local-allocator
int32_t addroffset; // added for members
int32_t fieldaddr; // to generate field-addresses early
} code;
} m_code;
// for accessing vectors
ir_value *members[3];
ir_value *memberof;
ir_value *m_members[3];
ir_value *m_memberof;
bool unique_life; // arrays will never overlap with temps
bool locked; // temps living during a CALL must be locked
bool callparam;
bool m_unique_life; // arrays will never overlap with temps
bool m_locked; // temps living during a CALL must be locked
bool m_callparam;
std::vector<ir_life_entry_t> life; // For the temp allocator
std::vector<ir_life_entry_t> m_life; // For the temp allocator
};
/*
@ -108,55 +105,49 @@ struct ir_phi_entry_t {
/* instruction */
struct ir_instr {
void* operator new(std::size_t);
void operator delete(void*);
ir_instr(lex_ctx_t, ir_block *owner, int opcode);
~ir_instr();
int opcode;
lex_ctx_t context;
ir_value *(_ops[3]) = { nullptr, nullptr, nullptr };
ir_block *(bops[2]) = { nullptr, nullptr };
int m_opcode;
lex_ctx_t m_context;
ir_value *(_m_ops[3]) = { nullptr, nullptr, nullptr };
ir_block *(m_bops[2]) = { nullptr, nullptr };
std::vector<ir_phi_entry_t> phi;
std::vector<ir_value *> params;
std::vector<ir_phi_entry_t> m_phi;
std::vector<ir_value *> m_params;
// For the temp-allocation
size_t eid = 0;
size_t m_eid = 0;
// For IFs
bool likely = true;
bool m_likely = true;
ir_block *owner;
ir_block *m_owner;
};
/* block */
struct ir_block {
void* operator new(std::size_t);
void operator delete(void*);
ir_block(ir_function *owner, const std::string& name);
~ir_block();
ir_function *owner;
std::string label;
ir_function *m_owner;
std::string m_label;
lex_ctx_t context;
bool final = false; /* once a jump is added we're done */
lex_ctx_t m_context;
bool m_final = false; /* once a jump is added we're done */
ir_instr **instr = nullptr;
ir_block **entries = nullptr;
ir_block **exits = nullptr;
std::vector<ir_value *> living;
ir_instr **m_instr = nullptr;
ir_block **m_entries = nullptr;
ir_block **m_exits = nullptr;
std::vector<ir_value *> m_living;
/* For the temp-allocation */
size_t entry_id = 0;
size_t eid = 0;
bool is_return = false;
size_t m_entry_id = 0;
size_t m_eid = 0;
bool m_is_return = false;
bool generated = false;
size_t code_start = 0;
bool m_generated = false;
size_t m_code_start = 0;
};
ir_value* ir_block_create_binop(ir_block*, lex_ctx_t, const char *label, int op, ir_value *left, ir_value *right);
@ -193,38 +184,35 @@ bool GMQCC_WARN ir_block_create_goto(ir_block*, lex_ctx_t, ir_block *to);
/* function */
struct ir_function {
void* operator new(std::size_t);
void operator delete(void*);
ir_function(ir_builder *owner, qc_type returntype);
~ir_function();
ir_builder *owner;
ir_builder *m_owner;
std::string name;
qc_type outtype;
int *params = nullptr;
ir_flag_t flags = 0;
int builtin = 0;
std::string m_name;
qc_type m_outtype;
int *m_params = nullptr;
ir_flag_t m_flags = 0;
int m_builtin = 0;
std::vector<std::unique_ptr<ir_block>> blocks;
std::vector<std::unique_ptr<ir_block>> m_blocks;
/*
* values generated from operations
* which might get optimized away, so anything
* in there needs to be deleted in the dtor.
*/
std::vector<std::unique_ptr<ir_value>> values;
std::vector<std::unique_ptr<ir_value>> locals; /* locally defined variables */
ir_value *value = nullptr;
std::vector<std::unique_ptr<ir_value>> m_values;
std::vector<std::unique_ptr<ir_value>> m_locals; /* locally defined variables */
ir_value *m_value = nullptr;
size_t allocated_locals = 0;
size_t globaltemps = 0;
size_t m_allocated_locals = 0;
size_t m_globaltemps = 0;
ir_block* first = nullptr;
ir_block* last = nullptr;
ir_block* m_first = nullptr;
ir_block* m_last = nullptr;
lex_ctx_t context;
lex_ctx_t m_context;
/*
* for prototypes - first we generate all the
@ -233,13 +221,13 @@ struct ir_function {
*
* remember the ID:
*/
qcint_t code_function_def = -1;
qcint_t m_code_function_def = -1;
/* for temp allocation */
size_t run_id = 0;
size_t m_run_id = 0;
/* vararg support: */
size_t max_varargs = 0;
size_t m_max_varargs = 0;
};
@ -252,50 +240,48 @@ ir_block* ir_function_create_block(lex_ctx_t ctx, ir_function*, const char
#define IR_MAX_VINSTR_TEMPS 1
struct ir_builder {
void* operator new(std::size_t);
void operator delete(void*);
ir_builder(const std::string& modulename);
~ir_builder();
std::string name;
std::vector<std::unique_ptr<ir_function>> functions;
std::vector<std::unique_ptr<ir_value>> globals;
std::vector<std::unique_ptr<ir_value>> fields;
std::string m_name;
std::vector<std::unique_ptr<ir_function>> m_functions;
std::vector<std::unique_ptr<ir_value>> m_globals;
std::vector<std::unique_ptr<ir_value>> m_fields;
// for reusing them in vector-splits, TODO: sort this or use a radix-tree
std::vector<ir_value*> const_floats;
std::vector<ir_value*> m_const_floats;
ht htfunctions;
ht htglobals;
ht htfields;
ht m_htfunctions;
ht m_htglobals;
ht m_htfields;
// extparams' ir_values reference the ones from extparam_protos
std::vector<std::unique_ptr<ir_value>> extparam_protos;
std::vector<ir_value*> extparams;
std::vector<std::unique_ptr<ir_value>> m_extparam_protos;
std::vector<ir_value*> m_extparams;
// the highest func->allocated_locals
size_t max_locals = 0;
size_t max_globaltemps = 0;
uint32_t first_common_local = 0;
uint32_t first_common_globaltemp = 0;
size_t m_max_locals = 0;
size_t m_max_globaltemps = 0;
uint32_t m_first_common_local = 0;
uint32_t m_first_common_globaltemp = 0;
std::vector<const char*> filenames;
std::vector<qcint_t> filestrings;
std::vector<const char*> m_filenames;
std::vector<qcint_t> m_filestrings;
// we cache the #IMMEDIATE string here
qcint_t str_immediate = 0;
qcint_t m_str_immediate = 0;
// there should just be this one nil
ir_value *nil;
ir_value *reserved_va_count = nullptr;
ir_value *coverage_func = nullptr;
ir_value *m_nil;
ir_value *m_reserved_va_count = nullptr;
ir_value *m_coverage_func = nullptr;
/* some virtual instructions require temps, and their code is isolated
* so that we don't need to keep track of their liveness.
*/
ir_value *vinstr_temp[IR_MAX_VINSTR_TEMPS];
ir_value *m_vinstr_temp[IR_MAX_VINSTR_TEMPS];
/* code generator */
std::unique_ptr<code_t> code;
std::unique_ptr<code_t> m_code;
};
ir_function* ir_builder_create_function(ir_builder*, const std::string& name, qc_type outtype);

1138
parser.cpp

File diff suppressed because it is too large Load diff