mirror of
https://github.com/DarkPlacesEngine/gmqcc.git
synced 2024-11-27 06:02:22 +00:00
a whole lotta 'm_'s
This commit is contained in:
parent
e7d1e701c4
commit
9d98805dfb
7 changed files with 3004 additions and 3065 deletions
236
ast.h
236
ast.h
|
@ -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
100
fold.cpp
|
@ -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;
|
||||
}
|
||||
|
|
358
intrin.cpp
358
intrin.cpp
File diff suppressed because it is too large
Load diff
176
ir.h
176
ir.h
|
@ -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
1138
parser.cpp
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue