{
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)
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;
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;
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;
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;
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;
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,
* 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),
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
#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
GMQCC_DEFINE_FLAG(EMULATE_STATE)
GMQCC_DEFINE_FLAG(ARITHMETIC_EXCEPTIONS)
GMQCC_DEFINE_FLAG(SPLIT_VECTOR_PARAMETERS)
+ GMQCC_DEFINE_FLAG(DEFAULT_ERASEABLE)
#endif
/* warning flags */
{ "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 }
};
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) {
* 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) {