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

1939
ast.cpp

File diff suppressed because it is too large Load diff

228
ast.h
View file

@ -93,9 +93,7 @@ enum {
TYPE_ast_state /* 22 */ TYPE_ast_state /* 22 */
}; };
#define ast_istype(x, t) ( ((ast_node*)x)->node_type == (TYPE_##t) ) #define ast_istype(x, t) ( (x)->m_node_type == (TYPE_##t) )
#define ast_ctx(node) (((ast_node*)(node))->context)
#define ast_side_effects(node) (((ast_node*)(node))->side_effects)
/* Node interface with common components /* Node interface with common components
*/ */
@ -103,21 +101,25 @@ typedef void ast_node_delete(ast_node*);
struct 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... */ /* I don't feel comfortable using keywords like 'delete' as names... */
ast_node_delete *destroy; ast_node_delete *m_destroy;
int node_type; int m_node_type;
/* keep_node: if a node contains this node, 'keep_node' /* keep_node: if a node contains this node, 'keep_node'
* prevents its dtor from destroying this node as well. * prevents its dtor from destroying this node as well.
*/ */
bool keep_node; bool m_keep_node;
bool side_effects; bool m_side_effects;
}; };
#define ast_delete(x) (*( ((ast_node*)(x))->destroy ))((ast_node*)(x)) #define ast_delete(x) ( (x)->m_destroy((x)) )
#define ast_unref(x) do \ #define ast_unref(x) do \
{ \ { \
if (! (((ast_node*)(x))->keep_node) ) { \ if (! (x)->m_keep_node ) { \
ast_delete(x); \ ast_delete(x); \
} \ } \
} while(0) } while(0)
@ -144,25 +146,25 @@ typedef bool ast_expression_codegen(ast_expression*,
struct ast_expression : ast_node { struct ast_expression : ast_node {
ast_expression() {} ast_expression() {}
ast_expression_codegen *codegen; ast_expression_codegen *m_codegen;
qc_type vtype; qc_type m_vtype;
ast_expression *next; ast_expression *m_next;
/* arrays get a member-count */ /* arrays get a member-count */
size_t count; size_t m_count;
std::vector<ast_value*> type_params; 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 /* void foo(string...) gets varparam set as a restriction
* for variadic parameters * for variadic parameters
*/ */
ast_expression *varparam; ast_expression *m_varparam;
/* The codegen functions should store their output values /* The codegen functions should store their output values
* so we can call it multiple times without re-evaluating. * so we can call it multiple times without re-evaluating.
* Store lvalue and rvalue seperately though. So that * Store lvalue and rvalue seperately though. So that
* ast_entfield for example can generate both if required. * ast_entfield for example can generate both if required.
*/ */
ir_value *outl; ir_value *m_outl;
ir_value *outr; ir_value *m_outr;
}; };
/* Value /* Value
@ -184,36 +186,36 @@ union basic_value_t {
struct ast_value : ast_expression struct ast_value : ast_expression
{ {
const char *name; const char *m_name;
const char *desc; const char *m_desc;
const char *argcounter; const char *m_argcounter;
int cvq; /* const/var qualifier */ int m_cvq; /* const/var qualifier */
bool isfield; /* this declares a field */ bool m_isfield; /* this declares a field */
bool isimm; /* an immediate, not just const */ bool m_isimm; /* an immediate, not just const */
bool hasvalue; bool m_hasvalue;
bool inexact; /* inexact coming from folded expression */ bool m_inexact; /* inexact coming from folded expression */
basic_value_t constval; basic_value_t m_constval;
/* for TYPE_ARRAY we have an optional vector /* for TYPE_ARRAY we have an optional vector
* of constants when an initializer list * of constants when an initializer list
* was provided. * was provided.
*/ */
std::vector<basic_value_t> initlist; std::vector<basic_value_t> m_initlist;
/* usecount for the parser */ /* usecount for the parser */
size_t uses; size_t m_uses;
ir_value *ir_v; ir_value *m_ir_v;
ir_value **ir_values; ir_value **m_ir_values;
size_t ir_value_count; size_t m_ir_value_count;
/* ONLY for arrays in progs version up to 6 */ /* ONLY for arrays in progs version up to 6 */
ast_value *setter; ast_value *m_setter;
ast_value *getter; 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); 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 struct ast_binary : ast_expression
{ {
int op; int m_op;
ast_expression *left; ast_expression *m_left;
ast_expression *right; ast_expression *m_right;
ast_binary_ref refs; ast_binary_ref m_refs;
bool right_first; bool m_right_first;
}; };
ast_binary* ast_binary_new(lex_ctx_t ctx, ast_binary* ast_binary_new(lex_ctx_t ctx,
int op, int op,
@ -270,12 +272,12 @@ ast_binary* ast_binary_new(lex_ctx_t ctx,
*/ */
struct ast_binstore : ast_expression struct ast_binstore : ast_expression
{ {
int opstore; int m_opstore;
int opbin; int m_opbin;
ast_expression *dest; ast_expression *m_dest;
ast_expression *source; ast_expression *m_source;
/* for &~= which uses the destination in a binary in source we can use this */ /* 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, ast_binstore* ast_binstore_new(lex_ctx_t ctx,
int storeop, int storeop,
@ -289,8 +291,8 @@ ast_binstore* ast_binstore_new(lex_ctx_t ctx,
*/ */
struct ast_unary : ast_expression struct ast_unary : ast_expression
{ {
int op; int m_op;
ast_expression *operand; ast_expression *m_operand;
}; };
ast_unary* ast_unary_new(lex_ctx_t ctx, ast_unary* ast_unary_new(lex_ctx_t ctx,
int op, int op,
@ -304,7 +306,7 @@ ast_unary* ast_unary_new(lex_ctx_t ctx,
*/ */
struct ast_return : ast_expression struct ast_return : ast_expression
{ {
ast_expression *operand; ast_expression *m_operand;
}; };
ast_return* ast_return_new(lex_ctx_t ctx, ast_return* ast_return_new(lex_ctx_t ctx,
ast_expression *expr); ast_expression *expr);
@ -325,9 +327,9 @@ ast_return* ast_return_new(lex_ctx_t ctx,
struct ast_entfield : ast_expression struct ast_entfield : ast_expression
{ {
/* The entity can come from an expression of course. */ /* 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 */ /* 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(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); 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 struct ast_member : ast_expression
{ {
ast_expression *owner; ast_expression *m_owner;
unsigned int field; unsigned int m_field;
const char *name; const char *m_name;
bool rvalue; bool m_rvalue;
}; };
ast_member* ast_member_new(lex_ctx_t ctx, ast_expression *owner, unsigned int field, const char *name); ast_member* ast_member_new(lex_ctx_t ctx, ast_expression *owner, unsigned int field, const char *name);
void ast_member_delete(ast_member*); 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 struct ast_array_index : ast_expression
{ {
ast_expression *array; ast_expression *m_array;
ast_expression *index; ast_expression *m_index;
}; };
ast_array_index* ast_array_index_new(lex_ctx_t ctx, ast_expression *array, ast_expression *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 struct ast_argpipe : ast_expression
{ {
ast_expression *index; ast_expression *m_index;
}; };
ast_argpipe* ast_argpipe_new(lex_ctx_t ctx, ast_expression *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 struct ast_store : ast_expression
{ {
int op; int m_op;
ast_expression *dest; ast_expression *m_dest;
ast_expression *source; ast_expression *m_source;
}; };
ast_store* ast_store_new(lex_ctx_t ctx, int op, ast_store* ast_store_new(lex_ctx_t ctx, int op,
ast_expression *d, ast_expression *s); 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 struct ast_ifthen : ast_expression
{ {
ast_expression *cond; ast_expression *m_cond;
/* It's all just 'expressions', since an ast_block is one too. */ /* It's all just 'expressions', since an ast_block is one too. */
ast_expression *on_true; ast_expression *m_on_true;
ast_expression *on_false; ast_expression *m_on_false;
}; };
ast_ifthen* ast_ifthen_new(lex_ctx_t ctx, ast_expression *cond, ast_expression *ontrue, ast_expression *onfalse); 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 struct ast_ternary : ast_expression
{ {
ast_expression *cond; ast_expression *m_cond;
/* It's all just 'expressions', since an ast_block is one too. */ /* It's all just 'expressions', since an ast_block is one too. */
ast_expression *on_true; ast_expression *m_on_true;
ast_expression *on_false; ast_expression *m_on_false;
}; };
ast_ternary* ast_ternary_new(lex_ctx_t ctx, ast_expression *cond, ast_expression *ontrue, ast_expression *onfalse); 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 struct ast_loop : ast_expression
{ {
ast_expression *initexpr; ast_expression *m_initexpr;
ast_expression *precond; ast_expression *m_precond;
ast_expression *postcond; ast_expression *m_postcond;
ast_expression *increment; ast_expression *m_increment;
ast_expression *body; ast_expression *m_body;
/* For now we allow a seperate flag on whether or not the condition /* For now we allow a seperate flag on whether or not the condition
* is supposed to be true or false. * is supposed to be true or false.
* That way, the parser can generate a 'while not(!x)' for `while(x)` * 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 * if desired, which is useful for the new -f{true,false}-empty-strings
* flag. * flag.
*/ */
bool pre_not; bool m_pre_not;
bool post_not; bool m_post_not;
}; };
ast_loop* ast_loop_new(lex_ctx_t ctx, ast_loop* ast_loop_new(lex_ctx_t ctx,
ast_expression *initexpr, ast_expression *initexpr,
@ -482,8 +484,8 @@ ast_loop* ast_loop_new(lex_ctx_t ctx,
*/ */
struct ast_breakcont : ast_expression struct ast_breakcont : ast_expression
{ {
bool is_continue; bool m_is_continue;
unsigned int levels; unsigned int m_levels;
}; };
ast_breakcont* ast_breakcont_new(lex_ctx_t ctx, bool iscont, unsigned int 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 * TODO: Ticket #20
*/ */
struct ast_switch_case { struct ast_switch_case {
ast_expression *value; /* #20 will replace this */ ast_expression *m_value; /* #20 will replace this */
ast_expression *code; ast_expression *m_code;
}; };
struct ast_switch : ast_expression struct ast_switch : ast_expression
{ {
ast_expression *operand; ast_expression *m_operand;
std::vector<ast_switch_case> cases; std::vector<ast_switch_case> m_cases;
}; };
ast_switch* ast_switch_new(lex_ctx_t ctx, ast_expression *op); 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 struct ast_label : ast_expression
{ {
const char *name; const char *m_name;
ir_block *irblock; ir_block *m_irblock;
std::vector<ast_goto*> gotos; std::vector<ast_goto*> m_gotos;
/* means it has not yet been defined */ /* 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); 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 struct ast_goto : ast_expression
{ {
const char *name; const char *m_name;
ast_label *target; ast_label *m_target;
ir_block *irblock_from; ir_block *m_irblock_from;
}; };
ast_goto* ast_goto_new(lex_ctx_t ctx, const char *name); 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 struct ast_state : ast_expression
{ {
ast_expression *framenum; ast_expression *m_framenum;
ast_expression *nextthink; ast_expression *m_nextthink;
}; };
ast_state* ast_state_new(lex_ctx_t ctx, ast_expression *frame, ast_expression *think); ast_state* ast_state_new(lex_ctx_t ctx, ast_expression *frame, ast_expression *think);
void ast_state_delete(ast_state*); void ast_state_delete(ast_state*);
@ -564,9 +566,9 @@ void ast_state_delete(ast_state*);
*/ */
struct ast_call : ast_expression struct ast_call : ast_expression
{ {
ast_expression *func; ast_expression *m_func;
std::vector<ast_expression *> params; std::vector<ast_expression *> m_params;
ast_expression *va_count; ast_expression *m_va_count;
}; };
ast_call* ast_call_new(lex_ctx_t ctx, ast_call* ast_call_new(lex_ctx_t ctx,
ast_expression *funcexpr); 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 struct ast_block : ast_expression
{ {
std::vector<ast_value*> locals; std::vector<ast_value*> m_locals;
std::vector<ast_expression*> exprs; std::vector<ast_expression*> m_exprs;
std::vector<ast_expression*> collect; std::vector<ast_expression*> m_collect;
}; };
ast_block* ast_block_new(lex_ctx_t ctx); ast_block* ast_block_new(lex_ctx_t ctx);
void ast_block_delete(ast_block*); 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 * pointers could just work with a name. However, this way could be
* more flexible, and adds no real complexity. * 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; int m_builtin;
const char *name;
int builtin;
/* list of used-up names for statics without the count suffix */ /* 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 /* number of static variables, by convention this includes the
* ones without the count-suffix - remember this when dealing * ones without the count-suffix - remember this when dealing
* with savegames. uint instead of size_t as %zu in printf is * with savegames. uint instead of size_t as %zu in printf is
* C99, so no windows support. */ * C99, so no windows support. */
unsigned int static_count; unsigned int m_static_count;
ir_function *ir_func; ir_function *m_ir_func;
ir_block *curblock; ir_block *m_curblock;
std::vector<ir_block*> breakblocks; std::vector<ir_block*> m_breakblocks;
std::vector<ir_block*> continueblocks; std::vector<ir_block*> m_continueblocks;
size_t labelcount; size_t m_labelcount;
/* in order for thread safety - for the optional /* in order for thread safety - for the optional
* channel abesed multithreading... keeping a buffer * channel abesed multithreading... keeping a buffer
* here to use in ast_function_label. * here to use in ast_function_label.
*/ */
char labelbuf[64]; char m_labelbuf[64];
std::vector<std::unique_ptr<ast_block>> blocks; std::vector<std::unique_ptr<ast_block>> m_blocks;
ast_value *varargs; ast_value *m_varargs;
ast_value *argc; ast_value *m_argc;
ast_value *fixedparams; ast_value *m_fixedparams;
ast_value *return_value; ast_value *m_return_value;
}; };
ast_function* ast_function_new(lex_ctx_t ctx, const char *name, ast_value *vtype); ast_function* ast_function_new(lex_ctx_t ctx, const char *name, ast_value *vtype);
/* This will NOT delete the underlying ast_value */ /* 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. * This file is thus, split into two parts.
*/ */
#define isfloat(X) (((ast_expression*)(X))->vtype == TYPE_FLOAT) #define isfloat(X) (((ast_expression*)(X))->m_vtype == TYPE_FLOAT)
#define isvector(X) (((ast_expression*)(X))->vtype == TYPE_VECTOR) #define isvector(X) (((ast_expression*)(X))->m_vtype == TYPE_VECTOR)
#define isstring(X) (((ast_expression*)(X))->vtype == TYPE_STRING) #define isstring(X) (((ast_expression*)(X))->m_vtype == TYPE_STRING)
#define isarray(X) (((ast_expression*)(X))->vtype == TYPE_ARRAY) #define isarray(X) (((ast_expression*)(X))->m_vtype == TYPE_ARRAY)
#define isfloats(X,Y) (isfloat (X) && isfloat (Y)) #define isfloats(X,Y) (isfloat (X) && isfloat (Y))
/* /*
@ -858,15 +858,15 @@ end:
} }
qcfloat_t fold::immvalue_float(ast_value *value) { 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) { 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) { const char *fold::immvalue_string(ast_value *value) {
return value->constval.vstring; return value->m_constval.vstring;
} }
lex_ctx_t fold::ctx() { lex_ctx_t fold::ctx() {
@ -878,32 +878,32 @@ lex_ctx_t fold::ctx() {
} }
bool fold::immediate_true(ast_value *v) { bool fold::immediate_true(ast_value *v) {
switch (v->vtype) { switch (v->m_vtype) {
case TYPE_FLOAT: case TYPE_FLOAT:
return !!v->constval.vfloat; return !!v->m_constval.vfloat;
case TYPE_INTEGER: case TYPE_INTEGER:
return !!v->constval.vint; return !!v->m_constval.vint;
case TYPE_VECTOR: case TYPE_VECTOR:
if (OPTS_FLAG(CORRECT_LOGIC)) if (OPTS_FLAG(CORRECT_LOGIC))
return vec3_pbool(v->constval.vvec); return vec3_pbool(v->m_constval.vvec);
return !!(v->constval.vvec.x); return !!(v->m_constval.vvec.x);
case TYPE_STRING: case TYPE_STRING:
if (!v->constval.vstring) if (!v->m_constval.vstring)
return false; return false;
if (OPTS_FLAG(TRUE_EMPTY_STRINGS)) if (OPTS_FLAG(TRUE_EMPTY_STRINGS))
return true; return true;
return !!v->constval.vstring[0]; return !!v->m_constval.vstring[0];
default: default:
compile_error(ctx(), "internal error: fold_immediate_true on invalid type"); compile_error(ctx(), "internal error: fold_immediate_true on invalid type");
break; break;
} }
return !!v->constval.vfunc; return !!v->m_constval.vfunc;
} }
/* Handy macros to determine if an ast_value can be constant folded. */ /* Handy macros to determine if an ast_value can be constant folded. */
#define fold_can_1(X) \ #define fold_can_1(X) \
(ast_istype(((ast_expression*)(X)), ast_value) && (X)->hasvalue && ((X)->cvq == CV_CONST) && \ (ast_istype(((ast_expression*)(X)), ast_value) && (X)->m_hasvalue && ((X)->m_cvq == CV_CONST) && \
((ast_expression*)(X))->vtype != TYPE_FUNCTION) ((ast_expression*)(X))->m_vtype != TYPE_FUNCTION)
#define fold_can_2(X, Y) (fold_can_1(X) && fold_can_1(Y)) #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; if (!ast_global_codegen((cur = it), ir, false)) goto err;
return true; return true;
err: err:
con_out("failed to generate global %s\n", cur->name); con_out("failed to generate global %s\n", cur->m_name);
delete ir; delete ir;
return false; return false;
} }
@ -957,14 +957,14 @@ fold::~fold() {
ast_expression *fold::constgen_float(qcfloat_t value, bool inexact) { ast_expression *fold::constgen_float(qcfloat_t value, bool inexact) {
for (auto &it : m_imm_float) 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; return (ast_expression*)it;
ast_value *out = ast_value_new(ctx(), "#IMMEDIATE", TYPE_FLOAT); ast_value *out = ast_value_new(ctx(), "#IMMEDIATE", TYPE_FLOAT);
out->cvq = CV_CONST; out->m_cvq = CV_CONST;
out->hasvalue = true; out->m_hasvalue = true;
out->inexact = inexact; out->m_inexact = inexact;
out->constval.vfloat = value; out->m_constval.vfloat = value;
m_imm_float.push_back(out); 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) { ast_expression *fold::constgen_vector(vec3_t value) {
for (auto &it : m_imm_vector) 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; return (ast_expression*)it;
ast_value *out = ast_value_new(ctx(), "#IMMEDIATE", TYPE_VECTOR); ast_value *out = ast_value_new(ctx(), "#IMMEDIATE", TYPE_VECTOR);
out->cvq = CV_CONST; out->m_cvq = CV_CONST;
out->hasvalue = true; out->m_hasvalue = true;
out->constval.vvec = value; out->m_constval.vvec = value;
m_imm_vector.push_back(out); m_imm_vector.push_back(out);
@ -998,15 +998,15 @@ ast_expression *fold::constgen_string(const char *str, bool translate) {
char name[32]; char name[32];
util_snprintf(name, sizeof(name), "dotranslate_%zu", m_parser->translated++); util_snprintf(name, sizeof(name), "dotranslate_%zu", m_parser->translated++);
out = ast_value_new(ctx(), name, TYPE_STRING); 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 { } else {
out = ast_value_new(ctx(), "#IMMEDIATE", TYPE_STRING); out = ast_value_new(ctx(), "#IMMEDIATE", TYPE_STRING);
} }
out->cvq = CV_CONST; out->m_cvq = CV_CONST;
out->hasvalue = true; out->m_hasvalue = true;
out->isimm = true; out->m_isimm = true;
out->constval.vstring = parser_strdup(str); out->m_constval.vstring = parser_strdup(str);
m_imm_string.push_back(out); m_imm_string.push_back(out);
util_htseth(table, str, hash, out); util_htseth(table, str, hash, out);
@ -1057,7 +1057,7 @@ inexact_possible:
bool fold::check_inexact_float(ast_value *a, ast_value *b) { bool fold::check_inexact_float(ast_value *a, ast_value *b) {
if (!OPTS_WARN(WARN_INEXACT_COMPARES)) if (!OPTS_WARN(WARN_INEXACT_COMPARES))
return false; return false;
if (!a->inexact && !b->inexact) if (!a->m_inexact && !b->m_inexact)
return false; return false;
return compile_warning(ctx(), WARN_INEXACT_COMPARES, "inexact value in comparison"); 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; ast_expression *out;
++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS]; ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS];
out = (ast_expression*)ast_member_new(ctx(), (ast_expression*)sel, set[0]-'x', nullptr); out = (ast_expression*)ast_member_new(ctx(), (ast_expression*)sel, set[0]-'x', nullptr);
out->keep_node = false; out->m_keep_node = false;
((ast_member*)out)->rvalue = true; ((ast_member*)out)->m_rvalue = true;
if (x != -1.0f) if (x != -1.0f)
return (ast_expression*)ast_binary_new(ctx(), INSTR_MUL_F, constgen_float(x, false), out); 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)) if (fold_can_1(a) && isstring(a))
return constgen_float(strlen(immvalue_string(a)), false); return constgen_float(strlen(immvalue_string(a)), false);
if (isarray(a)) if (isarray(a))
return constgen_float(a->initlist.size(), false); return constgen_float(a->m_initlist.size(), false);
return nullptr; return nullptr;
} }
@ -1522,18 +1522,18 @@ ast_expression *fold::intrinsic(const char *intrinsic, ast_expression **arg) {
#undef fold_can_1 #undef fold_can_1
#undef fold_can_2 #undef fold_can_2
#define isfloat(X) ((X)->vtype == TYPE_FLOAT) #define isfloat(X) ((X)->m_vtype == TYPE_FLOAT)
/*#define isstring(X) ((X)->vtype == TYPE_STRING)*/ /*#define isstring(X) ((X)->m_vtype == TYPE_STRING)*/
/*#define isvector(X) ((X)->vtype == TYPE_VECTOR)*/ /*#define isvector(X) ((X)->m_vtype == TYPE_VECTOR)*/
#define fold_can_1(X) ((X)->hasvalue && (X)->cvq == CV_CONST) #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))*/ /*#define fold_can_2(X,Y) (fold_can_1(X) && fold_can_1(Y))*/
qcfloat_t fold::immvalue_float(ir_value *value) { 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) { 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) { 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; ast_expression_codegen *cgen;
ir_block *elide; ir_block *elide;
ir_value *dummy; ir_value *dummy;
bool istrue = (immvalue_float(condval) != 0.0f && branch->on_true); bool istrue = (immvalue_float(condval) != 0.0f && branch->m_on_true);
bool isfalse = (immvalue_float(condval) == 0.0f && branch->on_false); bool isfalse = (immvalue_float(condval) == 0.0f && branch->m_on_false);
ast_expression *path = (istrue) ? branch->on_true : ast_expression *path = (istrue) ? branch->m_on_true :
(isfalse) ? branch->on_false : nullptr; (isfalse) ? branch->m_on_false : nullptr;
if (!path) { if (!path) {
/* /*
* no path to take implies that the evaluation is if(0) and there * 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; 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; 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; 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; return false;
/* /*
* now the branch has been eliminated and the correct block for the constant evaluation * now the branch has been eliminated and the correct block for the constant evaluation
* is expanded into the current block for the function. * is expanded into the current block for the function.
*/ */
func->curblock = elide; func->m_curblock = elide;
++opts_optimizationcount[OPTIM_CONST_FOLD_DCE]; ++opts_optimizationcount[OPTIM_CONST_FOLD_DCE];
return true; 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(std::string&& name, store_type storetype, qc_type vtype);
~ir_value(); ~ir_value();
void* operator new(std::size_t); // to use mem_a std::string m_name;
void operator delete(void*); // to use mem_d
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; std::vector<ir_instr *> m_reads;
store_type store; std::vector<ir_instr *> m_writes;
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;
// constant values // constant values
bool hasvalue; bool m_hasvalue;
union { union {
qcfloat_t vfloat; qcfloat_t vfloat;
int vint; int vint;
@ -65,7 +62,7 @@ struct ir_value {
char *vstring; char *vstring;
ir_value *vpointer; ir_value *vpointer;
ir_function *vfunc; ir_function *vfunc;
} constval; } m_constval;
struct { struct {
int32_t globaladdr; int32_t globaladdr;
@ -73,17 +70,17 @@ struct ir_value {
int32_t local; // filled by the local-allocator int32_t local; // filled by the local-allocator
int32_t addroffset; // added for members int32_t addroffset; // added for members
int32_t fieldaddr; // to generate field-addresses early int32_t fieldaddr; // to generate field-addresses early
} code; } m_code;
// for accessing vectors // for accessing vectors
ir_value *members[3]; ir_value *m_members[3];
ir_value *memberof; ir_value *m_memberof;
bool unique_life; // arrays will never overlap with temps bool m_unique_life; // arrays will never overlap with temps
bool locked; // temps living during a CALL must be locked bool m_locked; // temps living during a CALL must be locked
bool callparam; 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 */ /* instruction */
struct ir_instr { 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(lex_ctx_t, ir_block *owner, int opcode);
~ir_instr(); ~ir_instr();
int opcode; int m_opcode;
lex_ctx_t context; lex_ctx_t m_context;
ir_value *(_ops[3]) = { nullptr, nullptr, nullptr }; ir_value *(_m_ops[3]) = { nullptr, nullptr, nullptr };
ir_block *(bops[2]) = { nullptr, nullptr }; ir_block *(m_bops[2]) = { nullptr, nullptr };
std::vector<ir_phi_entry_t> phi; std::vector<ir_phi_entry_t> m_phi;
std::vector<ir_value *> params; std::vector<ir_value *> m_params;
// For the temp-allocation // For the temp-allocation
size_t eid = 0; size_t m_eid = 0;
// For IFs // For IFs
bool likely = true; bool m_likely = true;
ir_block *owner; ir_block *m_owner;
}; };
/* block */ /* block */
struct ir_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, const std::string& name);
~ir_block(); ~ir_block();
ir_function *owner; ir_function *m_owner;
std::string label; std::string m_label;
lex_ctx_t context; lex_ctx_t m_context;
bool final = false; /* once a jump is added we're done */ bool m_final = false; /* once a jump is added we're done */
ir_instr **instr = nullptr; ir_instr **m_instr = nullptr;
ir_block **entries = nullptr; ir_block **m_entries = nullptr;
ir_block **exits = nullptr; ir_block **m_exits = nullptr;
std::vector<ir_value *> living; std::vector<ir_value *> m_living;
/* For the temp-allocation */ /* For the temp-allocation */
size_t entry_id = 0; size_t m_entry_id = 0;
size_t eid = 0; size_t m_eid = 0;
bool is_return = false; bool m_is_return = false;
bool generated = false; bool m_generated = false;
size_t code_start = 0; 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); 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 */ /* function */
struct ir_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, qc_type returntype);
~ir_function(); ~ir_function();
ir_builder *owner; ir_builder *m_owner;
std::string name; std::string m_name;
qc_type outtype; qc_type m_outtype;
int *params = nullptr; int *m_params = nullptr;
ir_flag_t flags = 0; ir_flag_t m_flags = 0;
int builtin = 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 * values generated from operations
* which might get optimized away, so anything * which might get optimized away, so anything
* in there needs to be deleted in the dtor. * in there needs to be deleted in the dtor.
*/ */
std::vector<std::unique_ptr<ir_value>> values; std::vector<std::unique_ptr<ir_value>> m_values;
std::vector<std::unique_ptr<ir_value>> locals; /* locally defined variables */ std::vector<std::unique_ptr<ir_value>> m_locals; /* locally defined variables */
ir_value *value = nullptr; ir_value *m_value = nullptr;
size_t allocated_locals = 0; size_t m_allocated_locals = 0;
size_t globaltemps = 0; size_t m_globaltemps = 0;
ir_block* first = nullptr; ir_block* m_first = nullptr;
ir_block* last = nullptr; ir_block* m_last = nullptr;
lex_ctx_t context; lex_ctx_t m_context;
/* /*
* for prototypes - first we generate all the * for prototypes - first we generate all the
@ -233,13 +221,13 @@ struct ir_function {
* *
* remember the ID: * remember the ID:
*/ */
qcint_t code_function_def = -1; qcint_t m_code_function_def = -1;
/* for temp allocation */ /* for temp allocation */
size_t run_id = 0; size_t m_run_id = 0;
/* vararg support: */ /* 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 #define IR_MAX_VINSTR_TEMPS 1
struct ir_builder { struct ir_builder {
void* operator new(std::size_t);
void operator delete(void*);
ir_builder(const std::string& modulename); ir_builder(const std::string& modulename);
~ir_builder(); ~ir_builder();
std::string name; std::string m_name;
std::vector<std::unique_ptr<ir_function>> functions; std::vector<std::unique_ptr<ir_function>> m_functions;
std::vector<std::unique_ptr<ir_value>> globals; std::vector<std::unique_ptr<ir_value>> m_globals;
std::vector<std::unique_ptr<ir_value>> fields; std::vector<std::unique_ptr<ir_value>> m_fields;
// for reusing them in vector-splits, TODO: sort this or use a radix-tree // 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 m_htfunctions;
ht htglobals; ht m_htglobals;
ht htfields; ht m_htfields;
// extparams' ir_values reference the ones from extparam_protos // extparams' ir_values reference the ones from extparam_protos
std::vector<std::unique_ptr<ir_value>> extparam_protos; std::vector<std::unique_ptr<ir_value>> m_extparam_protos;
std::vector<ir_value*> extparams; std::vector<ir_value*> m_extparams;
// the highest func->allocated_locals // the highest func->allocated_locals
size_t max_locals = 0; size_t m_max_locals = 0;
size_t max_globaltemps = 0; size_t m_max_globaltemps = 0;
uint32_t first_common_local = 0; uint32_t m_first_common_local = 0;
uint32_t first_common_globaltemp = 0; uint32_t m_first_common_globaltemp = 0;
std::vector<const char*> filenames; std::vector<const char*> m_filenames;
std::vector<qcint_t> filestrings; std::vector<qcint_t> m_filestrings;
// we cache the #IMMEDIATE string here // we cache the #IMMEDIATE string here
qcint_t str_immediate = 0; qcint_t m_str_immediate = 0;
// there should just be this one nil // there should just be this one nil
ir_value *nil; ir_value *m_nil;
ir_value *reserved_va_count = nullptr; ir_value *m_reserved_va_count = nullptr;
ir_value *coverage_func = nullptr; ir_value *m_coverage_func = nullptr;
/* some virtual instructions require temps, and their code is isolated /* some virtual instructions require temps, and their code is isolated
* so that we don't need to keep track of their liveness. * 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 */ /* 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); 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