From a7c1f6f021f3c924c11b338e289b8ed636b8f7f6 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Thu, 29 Aug 2013 00:05:37 -0400 Subject: [PATCH] Implement [[eraseable]] attribute. When used with a function it instructs the AST (which than transfers logic to the IR) that the function (or variable) is potentially unused (verified by checking the read count). This than propogates through the IR and prevents the IR from generating both the definition and global/function. The intrinsics system uses this as well to prevent intrinsic functions from being generated unless they're used. --- ast.c | 14 ++++++++++++++ ast.h | 3 ++- intrin.c | 1 + ir.c | 16 ++++++++++++++++ ir.h | 1 + parser.c | 10 +++++++++- 6 files changed, 43 insertions(+), 2 deletions(-) diff --git a/ast.c b/ast.c index a228f3f..2f1566b 100644 --- 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 11644ff..c759a48 100644 --- 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 diff --git a/intrin.c b/intrin.c index 0075ece..7e7e69e 100644 --- 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 7a04e3b..3efad3d 100644 --- 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 46ac464..73dd447 100644 --- 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) diff --git a/parser.c b/parser.c index ef20655..2277abf 100644 --- 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; } -- 2.39.2