From 092067482fddeccf1b3e42ff09a046f6555cd11e Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Wed, 9 May 2018 21:18:37 -0400 Subject: [PATCH] added -fdefault-eraseable which is the same as adding [[eraseable]] to all definitions instead the opposite behavior can be controlled with [[noerase]] attribute --- ast.cpp | 12 +++++++----- ast.h | 13 +++++++------ doc/gmqcc.1 | 7 +++++++ gmqcc.ini.example | 8 ++++++++ opts.def | 1 + parser.cpp | 5 ++--- 6 files changed, 32 insertions(+), 14 deletions(-) diff --git a/ast.cpp b/ast.cpp index 1ac0a44..7b444f8 100644 --- a/ast.cpp +++ b/ast.cpp @@ -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; diff --git a/ast.h b/ast.h index 04fa4d8..2459729 100644 --- a/ast.h +++ b/ast.h @@ -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), diff --git a/doc/gmqcc.1 b/doc/gmqcc.1 index 510e754..f392cc3 100644 --- a/doc/gmqcc.1 +++ b/doc/gmqcc.1 @@ -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 diff --git a/gmqcc.ini.example b/gmqcc.ini.example index 5c1ad37..2b4920c 100644 --- a/gmqcc.ini.example +++ b/gmqcc.ini.example @@ -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 diff --git a/opts.def b/opts.def index 2dc4fb7..5addc3c 100644 --- a/opts.def +++ b/opts.def @@ -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 */ diff --git a/parser.cpp b/parser.cpp index cc2b358..9345760 100644 --- a/parser.cpp +++ b/parser.cpp @@ -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) { -- 2.39.2