added -fdefault-eraseable which is the same as adding [[eraseable]] to all definitions
authorDale Weiler <weilercdale@gmail.com>
Thu, 10 May 2018 01:18:37 +0000 (21:18 -0400)
committerDale Weiler <weilercdale@gmail.com>
Thu, 10 May 2018 01:18:37 +0000 (21:18 -0400)
instead the opposite behavior can be controlled with [[noerase]] attribute

ast.cpp
ast.h
doc/gmqcc.1
gmqcc.ini.example
opts.def
parser.cpp

diff --git a/ast.cpp b/ast.cpp
index 1ac0a44..7b444f8 100644 (file)
--- 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 (file)
--- 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),
index 510e754..f392cc3 100644 (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
index 5c1ad37..2b4920c 100644 (file)
     #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
index 2dc4fb7..5addc3c 100644 (file)
--- 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 */
index cc2b358..9345760 100644 (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) {