Implement [[eraseable]] attribute. When used with a function it instructs the AST...
authorDale Weiler <killfieldengine@gmail.com>
Thu, 29 Aug 2013 04:05:37 +0000 (00:05 -0400)
committerDale Weiler <killfieldengine@gmail.com>
Thu, 29 Aug 2013 04:05:37 +0000 (00:05 -0400)
ast.c
ast.h
intrin.c
ir.c
ir.h
parser.c

diff --git a/ast.c b/ast.c
index a228f3f7edcb5d7b671db45c9142d26a0d9fb69c..2f1566bfc5700a26f7fb51f923b46c0a7ecdc700 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -1385,6 +1385,8 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield)
         self->ir_v = func->value;
         if (self->expression.flags & AST_FLAG_INCLUDE_DEF)
             self->ir_v->flags |= IR_FLAG_INCLUDE_DEF;
+        if (self->expression.flags & AST_FLAG_ERASEABLE)
+            self->ir_v->flags |= IR_FLAG_ERASEABLE;
         /* The function is filled later on ast_function_codegen... */
         return true;
     }
@@ -1426,8 +1428,11 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield)
             v->unique_life = true;
             v->locked      = true;
             array->ir_v = self->ir_v = v;
+
             if (self->expression.flags & AST_FLAG_INCLUDE_DEF)
                 self->ir_v->flags |= IR_FLAG_INCLUDE_DEF;
+            if (self->expression.flags & AST_FLAG_ERASEABLE)
+                self->ir_v->flags |= IR_FLAG_ERASEABLE;
 
             namelen = strlen(self->name);
             name    = (char*)mem_a(namelen + 16);
@@ -1460,6 +1465,9 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield)
             self->ir_v = v;
             if (self->expression.flags & AST_FLAG_INCLUDE_DEF)
                 self->ir_v->flags |= IR_FLAG_INCLUDE_DEF;
+
+            if (self->expression.flags & AST_FLAG_ERASEABLE)
+                self->ir_v->flags |= IR_FLAG_ERASEABLE;
         }
         return true;
     }
@@ -1489,8 +1497,11 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield)
         v->context = ast_ctx(self);
         v->unique_life = true;
         v->locked      = true;
+
         if (self->expression.flags & AST_FLAG_INCLUDE_DEF)
             v->flags |= IR_FLAG_INCLUDE_DEF;
+        if (self->expression.flags & AST_FLAG_ERASEABLE)
+            self->ir_v->flags |= IR_FLAG_ERASEABLE;
 
         namelen = strlen(self->name);
         name    = (char*)mem_a(namelen + 16);
@@ -1531,8 +1542,11 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield)
     /* link us to the ir_value */
     v->cvq = self->cvq;
     self->ir_v = v;
+
     if (self->expression.flags & AST_FLAG_INCLUDE_DEF)
         self->ir_v->flags |= IR_FLAG_INCLUDE_DEF;
+    if (self->expression.flags & AST_FLAG_ERASEABLE)
+        self->ir_v->flags |= IR_FLAG_ERASEABLE;
 
     /* initialize */
     if (self->hasvalue) {
diff --git a/ast.h b/ast.h
index 11644ff5674cde51edc2339e05982091c840c7ad..c759a48e95cd2d8098759dec9c5c03835fe9d5e9 100644 (file)
--- a/ast.h
+++ b/ast.h
@@ -155,9 +155,10 @@ struct ast_expression_common
 #define AST_FLAG_INCLUDE_DEF  (1<<5)
 #define AST_FLAG_IS_VARARG    (1<<6)
 #define AST_FLAG_ALIAS        (1<<7)
+#define AST_FLAG_ERASEABLE    (1<<8)
 /* An array declared as []
  * so that the size is taken from the initializer */
-#define AST_FLAG_ARRAY_INIT   (1<<8)
+#define AST_FLAG_ARRAY_INIT   (1<<9)
 #define AST_FLAG_TYPE_MASK (AST_FLAG_VARIADIC | AST_FLAG_NORETURN)
 
 /* Value
index 0075ece0ee16a6465587a6c78b8ca8b6cfb8d712..7e7e69e4a204022cfd3bb966f5983515ee5237c4 100644 (file)
--- a/intrin.c
+++ b/intrin.c
@@ -50,6 +50,7 @@
             "__builtin_" NAME,                                         \
             (VALUE)                                                    \
         );                                                             \
+        (VALUE)->expression.flags |= AST_FLAG_ERASEABLE;               \
     } while (0)
 
 #define INTRIN_REG(FUNC, VALUE)                                        \
diff --git a/ir.c b/ir.c
index 7a04e3b9ef89127fa067ac1c8122f5450d736b3b..3efad3da81164b9064c882e5c11179ace81e9463 100644 (file)
--- a/ir.c
+++ b/ir.c
@@ -3464,6 +3464,14 @@ static bool gen_global_function_code(ir_builder *ir, ir_value *global)
     if (irfun->builtin)
         return true;
 
+    /*
+     * If there is no definition and the thing is eraseable, we can ignore
+     * outputting the function to begin with.
+     */
+    if (global->flags & IR_FLAG_ERASEABLE && irfun->code_function_def < 0) {
+        return true;
+    }
+
     if (irfun->code_function_def < 0) {
         irerror(irfun->context, "`%s`: IR global wasn't generated, failed to access function-def", irfun->name);
         return false;
@@ -3564,6 +3572,14 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool isloc
     {
         pushdef = true;
 
+        /*
+         * if we're eraseable and the function isn't referenced ignore outputting
+         * the function.
+         */
+        if (global->flags & IR_FLAG_ERASEABLE && vec_size(global->reads) == 0) {
+            return true;
+        }
+
         if (OPTS_OPTIMIZATION(OPTIM_STRIP_CONSTANT_NAMES) &&
             !(global->flags & IR_FLAG_INCLUDE_DEF) &&
             (global->name[0] == '#' || global->cvq == CV_CONST))
diff --git a/ir.h b/ir.h
index 46ac464b808f3db6b47e46cb03dae49ea1aefc6e..73dd447c0df8c946189809557f6dc60caf4ff676 100644 (file)
--- a/ir.h
+++ b/ir.h
@@ -231,6 +231,7 @@ typedef struct ir_function_s
 #define IR_FLAG_HAS_UNINITIALIZED (1<<2)
 #define IR_FLAG_HAS_GOTO          (1<<3)
 #define IR_FLAG_INCLUDE_DEF       (1<<4)
+#define IR_FLAG_ERASEABLE         (1<<5)
 #define IR_FLAG_MASK_NO_OVERLAP     (IR_FLAG_HAS_ARRAYS | IR_FLAG_HAS_UNINITIALIZED)
 #define IR_FLAG_MASK_NO_LOCAL_TEMPS (IR_FLAG_HAS_ARRAYS | IR_FLAG_HAS_UNINITIALIZED)
 
index ef206557b0a384a1dd5b69d47e91e78adf68f3c6..2277abf2b44f847b284dab87757d5ba0e5c0a7c4 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -2738,7 +2738,15 @@ static bool parse_qualifiers(parser_t *parser, bool with_local, int *cvq, bool *
             else if (!strcmp(parser_tokval(parser), "inline")) {
                 flags |= AST_FLAG_INLINE;
                 if (!parser_next(parser) || parser->tok != TOKEN_ATTRIBUTE_CLOSE) {
-                    parseerror(parser, "`noref` attribute has no parameters, expected `]]`");
+                    parseerror(parser, "`inline` attribute has no parameters, expected `]]`");
+                    *cvq = CV_WRONG;
+                    return false;
+                }
+            }
+            else if (!strcmp(parser_tokval(parser), "eraseable")) {
+                flags |= AST_FLAG_ERASEABLE;
+                if (!parser_next(parser) || parser->tok != TOKEN_ATTRIBUTE_CLOSE) {
+                    parseerror(parser, "`eraseable` attribute has no parameters, expected `]]`");
                     *cvq = CV_WRONG;
                     return false;
                 }