added -fdefault-eraseable which is the same as adding [[eraseable]] to all definitions

instead the opposite behavior can be controlled with [[noerase]] attribute
This commit is contained in:
Dale Weiler 2018-05-09 21:18:37 -04:00
parent 9a21c638fa
commit 092067482f
6 changed files with 32 additions and 14 deletions

12
ast.cpp
View file

@ -37,6 +37,8 @@ ast_expression::ast_expression(lex_ctx_t ctx, int nodetype, qc_type type)
{
if (OPTS_OPTION_BOOL(OPTION_COVERAGE))
m_flags |= AST_FLAG_BLOCK_COVERAGE;
if (OPTS_FLAG(DEFAULT_ERASEABLE))
m_flags |= AST_FLAG_ERASEABLE;
}
ast_expression::ast_expression(lex_ctx_t ctx, int nodetype)
: ast_expression(ctx, nodetype, TYPE_VOID)
@ -1130,7 +1132,7 @@ bool ast_value::generateGlobal(ir_builder *ir, bool isfield)
if (m_flags & AST_FLAG_INCLUDE_DEF)
m_ir_v->m_flags |= IR_FLAG_INCLUDE_DEF;
if (m_flags & AST_FLAG_ERASEABLE)
if (m_flags & AST_FLAG_ERASEABLE && !(m_flags & AST_FLAG_NOERASE))
m_ir_v->m_flags |= IR_FLAG_ERASABLE;
if (m_flags & AST_FLAG_NOREF)
m_ir_v->m_flags |= IR_FLAG_NOREF;
@ -1194,7 +1196,7 @@ bool ast_value::generateGlobalFunction(ir_builder *ir)
m_ir_v = func->m_value;
if (m_flags & AST_FLAG_INCLUDE_DEF)
m_ir_v->m_flags |= IR_FLAG_INCLUDE_DEF;
if (m_flags & AST_FLAG_ERASEABLE)
if (m_flags & AST_FLAG_ERASEABLE && !(m_flags & AST_FLAG_NOERASE))
m_ir_v->m_flags |= IR_FLAG_ERASABLE;
if (m_flags & AST_FLAG_BLOCK_COVERAGE)
func->m_flags |= IR_FLAG_BLOCK_COVERAGE;
@ -1236,7 +1238,7 @@ bool ast_value::generateGlobalField(ir_builder *ir)
if (m_flags & AST_FLAG_INCLUDE_DEF)
m_ir_v->m_flags |= IR_FLAG_INCLUDE_DEF;
if (m_flags & AST_FLAG_ERASEABLE)
if (m_flags & AST_FLAG_ERASEABLE && !(m_flags & AST_FLAG_NOERASE))
m_ir_v->m_flags |= IR_FLAG_ERASABLE;
if (m_flags & AST_FLAG_NOREF)
m_ir_v->m_flags |= IR_FLAG_NOREF;
@ -1272,7 +1274,7 @@ bool ast_value::generateGlobalField(ir_builder *ir)
m_ir_v = v;
if (m_flags & AST_FLAG_INCLUDE_DEF)
m_ir_v->m_flags |= IR_FLAG_INCLUDE_DEF;
if (m_flags & AST_FLAG_ERASEABLE)
if (m_flags & AST_FLAG_ERASEABLE && !(m_flags & AST_FLAG_NOERASE))
m_ir_v->m_flags |= IR_FLAG_ERASABLE;
if (m_flags & AST_FLAG_NOREF)
m_ir_v->m_flags |= IR_FLAG_NOREF;
@ -1305,7 +1307,7 @@ ir_value *ast_value::prepareGlobalArray(ir_builder *ir)
if (m_flags & AST_FLAG_INCLUDE_DEF)
v->m_flags |= IR_FLAG_INCLUDE_DEF;
if (m_flags & AST_FLAG_ERASEABLE)
if (m_flags & AST_FLAG_ERASEABLE && !(m_flags & AST_FLAG_NOERASE))
v->m_flags |= IR_FLAG_ERASABLE;
if (m_flags & AST_FLAG_NOREF)
v->m_flags |= IR_FLAG_NOREF;

13
ast.h
View file

@ -43,14 +43,15 @@ enum {
AST_FLAG_IS_VARARG = 1 << 6,
AST_FLAG_ALIAS = 1 << 7,
AST_FLAG_ERASEABLE = 1 << 8,
AST_FLAG_ACCUMULATE = 1 << 9,
AST_FLAG_NOERASE = 1 << 9, /* Never allow it to be erased, even if ERASEABLE is present */
AST_FLAG_ACCUMULATE = 1 << 10,
/* An array declared as []
* so that the size is taken from the initializer
*/
AST_FLAG_ARRAY_INIT = 1 << 10,
AST_FLAG_ARRAY_INIT = 1 << 11,
AST_FLAG_FINAL_DECL = 1 << 11,
AST_FLAG_FINAL_DECL = 1 << 12,
/* Several coverage options
* AST_FLAG_COVERAGE means there was an explicit [[coverage]] attribute,
@ -59,14 +60,14 @@ enum {
* In the future there might be more options like tracking variable access
* by creating get/set wrapper functions.
*/
AST_FLAG_COVERAGE = 1 << 12,
AST_FLAG_BLOCK_COVERAGE = 1 << 13,
AST_FLAG_COVERAGE = 1 << 13,
AST_FLAG_BLOCK_COVERAGE = 1 << 14,
/*
* Propagates norefness to the IR so the unused (read/write) check can be
* more intelligently done.
*/
AST_FLAG_NOREF = 1 << 14,
AST_FLAG_NOREF = 1 << 15,
AST_FLAG_LAST,
AST_FLAG_TYPE_MASK = (AST_FLAG_VARIADIC | AST_FLAG_NORETURN),

View file

@ -628,6 +628,13 @@ after all limited to 64k. There's at least one known codebase where this
lowers the number of globals from over 80k down to around 3k. In other code
bases it doesn't reduce the globals at all but only increases code size.
Just try it and see whether it helps you.
.It Fl f Ns Cm default-eraseable
Force all expressions to be "eraseable" which permits the compiler to
remove unused functions, variables and statements. This is equivlant to
putting [[eraseable]] on all definitions. This is dangerous as it breaks
auto cvars, definitions for functions the engine may be looking for and
translatable strings. Instead, you can mark a definition with [[noerase]]
to prevent this from happening.
.El
.Sh OPTIMIZATIONS
.Bl -tag -width Ds

View file

@ -346,6 +346,14 @@
#expense of additional instructions.
SPLIT_VECTOR_PARAMETERS = false
#Force all expressions to be "eraseable" which permits the compiler
#to remove unused functions, variables and statements. This is
#equivlant to putting [[eraseable]] on all definitions. This is
#dangerous as it breaks auto cvars, definitions for functions the
#engine may be looking for and translatable strings. Instead, you
#can mark a definition with [[noerase]] to prevent this from happening.
DEFAULT_ERASEABLE = false
[warnings]
#Generate a warning about variables which are declared but never
#used. This can be avoided by adding the noref keyword in front

View file

@ -37,6 +37,7 @@
GMQCC_DEFINE_FLAG(EMULATE_STATE)
GMQCC_DEFINE_FLAG(ARITHMETIC_EXCEPTIONS)
GMQCC_DEFINE_FLAG(SPLIT_VECTOR_PARAMETERS)
GMQCC_DEFINE_FLAG(DEFAULT_ERASEABLE)
#endif
/* warning flags */

View file

@ -2763,6 +2763,7 @@ static bool parse_qualifiers(parser_t *parser, bool with_local, int *cvq, bool *
{ "noreturn", AST_FLAG_NORETURN },
{ "inline", AST_FLAG_INLINE },
{ "eraseable", AST_FLAG_ERASEABLE },
{ "noerase", AST_FLAG_NOERASE },
{ "accumulate", AST_FLAG_ACCUMULATE },
{ "last", AST_FLAG_FINAL_DECL }
};
@ -2796,7 +2797,6 @@ static bool parse_qualifiers(parser_t *parser, bool with_local, int *cvq, bool *
if (i != GMQCC_ARRAY_COUNT(attributes))
goto leave;
if (!strcmp(parser_tokval(parser), "noref")) {
had_noref = true;
if (!parser_next(parser) || parser->tok != TOKEN_ATTRIBUTE_CLOSE) {
@ -5197,8 +5197,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield
* store the vstring back to var for alias and
* deprecation messages.
*/
if (var->m_flags & AST_FLAG_DEPRECATED ||
var->m_flags & AST_FLAG_ALIAS)
if (var->m_flags & AST_FLAG_DEPRECATED || var->m_flags & AST_FLAG_ALIAS)
var->m_desc = vstring;
if (parser_find_global(parser, var->m_name) && var->m_flags & AST_FLAG_ALIAS) {