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; }