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 1ac0a4418fe73032a086427dee3f225a51790275..7b444f8a402dfdf18efaab0ae3d171c1174972ae 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_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)
 }
 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_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->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;
     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;
         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_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->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;
         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;
             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_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;
         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 04fa4d80b5e5b248c3a2b3d73c8a7f77c04f3b28..2459729725641c4bb46828b0c8471edc2bf5f6a7 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_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
      */
 
     /* 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,
 
     /* 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.
      */
      * 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.
      */
 
     /*
      * 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),
 
     AST_FLAG_LAST,
     AST_FLAG_TYPE_MASK      = (AST_FLAG_VARIADIC | AST_FLAG_NORETURN),
index 510e754d31dbe276eb4eab87e365ebe4291a4bba..f392cc3e1357060e6f7491fd8158b5e99f19a4a9 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.
 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
 .El
 .Sh OPTIMIZATIONS
 .Bl -tag -width Ds
index 5c1ad3777a8c999ad7815492da0fec9f0ba3d927..2b4920c6d19ad55585b67e6911d716c576546eac 100644 (file)
     #expense of additional instructions.
     SPLIT_VECTOR_PARAMETERS = false
 
     #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
 [warnings]
     #Generate a warning about variables which are declared but never
     #used. This can be avoided by adding the ‘noref’ keyword in front
index 2dc4fb77cd9d8a38d3fa15422ce74b38bde3e7e2..5addc3c5d5fa2cc95807910506882ff7ea9b7ffc 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(EMULATE_STATE)
     GMQCC_DEFINE_FLAG(ARITHMETIC_EXCEPTIONS)
     GMQCC_DEFINE_FLAG(SPLIT_VECTOR_PARAMETERS)
+    GMQCC_DEFINE_FLAG(DEFAULT_ERASEABLE)
 #endif
 
 /* warning flags */
 #endif
 
 /* warning flags */
index cc2b3589b4ab85b9ec1c08c59655947e43e8773b..9345760ad2d83b3e4825dbe7fb3d729e40f0cbcc 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  },
         { "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 }
     };
         { "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 (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) {
             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.
          */
          * 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) {
             var->m_desc = vstring;
 
         if (parser_find_global(parser, var->m_name) && var->m_flags & AST_FLAG_ALIAS) {