From 39f037e698ced8645048043c73e9797bdecd3360 Mon Sep 17 00:00:00 2001 From: Szabolcs Nagy Date: Thu, 27 Dec 2012 16:38:52 +0100 Subject: [PATCH] simple support for __attribute__((alias("symbol"))) --- ast2firm.c | 35 ++++++++++++++++++++++-- attribute.c | 36 +++++++++++++++++++++++++ entity_t.h | 2 ++ libfirm | 2 +- parser.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 150 insertions(+), 3 deletions(-) diff --git a/ast2firm.c b/ast2firm.c index c93c67c..8d24dd7 100644 --- a/ast2firm.c +++ b/ast2firm.c @@ -894,6 +894,8 @@ static bool declaration_is_definition(const entity_t *entity) switch (entity->kind) { case ENTITY_VARIABLE: return entity->declaration.storage_class != STORAGE_CLASS_EXTERN; +// TODO: alias provides a definition +// || entity->variable.alias != NULL; case ENTITY_FUNCTION: return entity->function.body != NULL; case ENTITY_PARAMETER: @@ -939,8 +941,10 @@ static void handle_decl_modifiers(ir_entity *irentity, entity_t *entity) if ((modifiers & DM_USED) && declaration_is_definition(entity)) { add_entity_linkage(irentity, IR_LINKAGE_HIDDEN_USER); } - if ((modifiers & DM_WEAK) && declaration_is_definition(entity) - && entity->declaration.storage_class != STORAGE_CLASS_EXTERN) { +// TODO: i dont understand this logic +// if ((modifiers & DM_WEAK) && declaration_is_definition(entity) +// && entity->declaration.storage_class != STORAGE_CLASS_EXTERN) { + if (modifiers & DM_WEAK) { add_entity_linkage(irentity, IR_LINKAGE_WEAK); } } @@ -4675,6 +4679,18 @@ static void create_variable_initializer(entity_t *entity) { assert(entity->kind == ENTITY_VARIABLE); initializer_t *initializer = entity->variable.initializer; + if (entity->variable.alias != NULL) { + const namespace_tag_t namespc = (namespace_tag_t)entity->base.namespc; + entity_t *a = entity->variable.alias->entity; + for (; a != NULL; a = a->base.symbol_next) { + if ((namespace_tag_t)a->base.namespc == namespc) + break; + } + assert(a != NULL && a->kind == ENTITY_VARIABLE && a->variable.v.entity != NULL); + set_entity_alias(entity->variable.v.entity, a->variable.v.entity); + /* prevent usage assumption to be made about aliased variables */ + add_entity_linkage(a->variable.v.entity, IR_LINKAGE_HIDDEN_USER); + } if (initializer == NULL) return; @@ -5795,6 +5811,21 @@ static void create_function(entity_t *entity) assert(entity->kind == ENTITY_FUNCTION); ir_entity *function_entity = get_function_entity(entity, current_outer_frame); + if (entity->function.alias != NULL) { + const namespace_tag_t namespc = (namespace_tag_t)entity->base.namespc; + entity_t *a = entity->function.alias->entity; + for (; a != NULL; a = a->base.symbol_next) { + if ((namespace_tag_t)a->base.namespc == namespc) + break; + } +// TODO: or use entitymap +// ir_entity *a = entitymap_get(&entitymap, entity->function.alias); + assert(a != NULL && a->kind == ENTITY_VARIABLE && a->function.irentity != NULL); + set_entity_alias(entity->function.irentity, a->function.irentity); + /* prevent usage assumption to be made about aliased functions */ + add_entity_linkage(a->function.irentity, IR_LINKAGE_HIDDEN_USER); + } + if (entity->function.body == NULL) return; diff --git a/attribute.c b/attribute.c index a29299a..8059435 100644 --- a/attribute.c +++ b/attribute.c @@ -295,6 +295,38 @@ static void handle_attribute_asm(const attribute_t *attribute, return; } +static void handle_attribute_alias(const attribute_t *attribute, + entity_t *entity) +{ + // TODO: return if not at function_scope + attribute_argument_t *arg = attribute->a.arguments; + if (arg == NULL) { + errorf(&attribute->pos, + "__attribute__((alias(X))) misses argument"); + return; + } + const char *string = get_argument_string(arg); + if (string == NULL) { + errorf(&attribute->pos, + "__attribute__((alias(X))) argument is not a string"); + return; + } + symbol_t *symbol = symbol_table_insert(string); + + switch (entity->kind) { + case ENTITY_VARIABLE: + entity->variable.alias = symbol; + break; + case ENTITY_FUNCTION: + entity->function.alias = symbol; + break; + default: + warningf(WARN_OTHER, &attribute->pos, "alias attribute on '%N' ignored", entity); + break; + } + return; +} + void handle_entity_attributes(const attribute_t *attributes, entity_t *entity) { if (entity->kind == ENTITY_TYPEDEF) { @@ -338,6 +370,10 @@ void handle_entity_attributes(const attribute_t *attributes, entity_t *entity) case ATTRIBUTE_MS_RESTRICT: modifiers |= DM_RESTRICT; break; case ATTRIBUTE_MS_NOALIAS: modifiers |= DM_NOALIAS; break; + case ATTRIBUTE_GNU_ALIAS: + handle_attribute_alias(attribute, entity); + break; + case ATTRIBUTE_GNU_PACKED: handle_attribute_packed_e(attribute, entity); break; diff --git a/entity_t.h b/entity_t.h index f2ee603..e9108bc 100644 --- a/entity_t.h +++ b/entity_t.h @@ -212,6 +212,7 @@ struct variable_t { unsigned elf_visibility : 2; initializer_t *initializer; + symbol_t *alias; /**< gnu extension attribute alias */ /* ast2firm info */ union { @@ -233,6 +234,7 @@ struct function_t { scope_t parameters; statement_t *body; symbol_t *actual_name; /**< gnu extension __REDIRECT */ + symbol_t *alias; /**< gnu extension attribute alias */ /* ast2firm info */ union { diff --git a/libfirm b/libfirm index 6911c8a..828bda9 160000 --- a/libfirm +++ b/libfirm @@ -1 +1 @@ -Subproject commit 6911c8a5253d79be26f5fcb668b7fb69f1998819 +Subproject commit 828bda9d31a92928f8e7b211a1f3cf9d9de724bb diff --git a/parser.c b/parser.c index b637dd2..38f8794 100644 --- a/parser.c +++ b/parser.c @@ -3755,6 +3755,7 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, if (attributes != NULL) { handle_entity_attributes(attributes, entity); + // TODO: maybe drop alias symbol here if not file_scope } if (entity->kind == ENTITY_FUNCTION && !freestanding) { @@ -3907,6 +3908,50 @@ static void merge_in_attributes(declaration_t *decl, attribute_t *attributes) static bool is_main(entity_t*); +/* +__attribute__(alias("sym")) provides a definition +in function scope function and variable declarations + +the sym must be declared in the same translation unit +but the sym declaration can come later than the alias one +(weakref is not supported) + +sym must be marked used +*/ +static struct alias { + struct alias *next; + entity_t *entity; + symbol_t *symbol; +} *aliases; +static void add_alias(entity_t *entity, symbol_t *symbol) +{ + struct alias *a; + + assert(entity->kind == ENTITY_FUNCTION || entity->kind == ENTITY_VARIABLE); + a = malloc(sizeof *a); + a->entity = entity; + a->symbol = symbol; + a->next = aliases; + aliases = a; +} +static void mark_aliases_used(void) +{ + struct alias *alias; + for (alias = aliases; alias; alias = alias->next) { + const namespace_tag_t namespc = (namespace_tag_t)alias->entity->base.namespc; + entity_t *entity = get_entity(alias->symbol, namespc); + if (entity == NULL) { + errorf(&alias->entity->base.pos, "'%N' is aliased to undefined symbol \"%s\"", alias->entity, alias->symbol->string); + } else if (entity->base.parent_scope != file_scope) { + errorf(&alias->entity->base.pos, "'%N' is aliased to undefined symbol \"%s\" (TODO: scope)", alias->entity, alias->symbol->string); + } else { + // printf("handle alias %s -> %s\n", alias->entity->base.symbol->string, alias->symbol->string); + assert(entity->kind == ENTITY_FUNCTION || entity->kind == ENTITY_VARIABLE); + entity->declaration.used = true; + } + } +} + /** * record entities for the NAMESPACE_NORMAL, and produce error messages/warnings * for various problems that occur for multiple definitions @@ -3952,6 +3997,27 @@ entity_t *record_entity(entity_t *entity, const bool is_definition) warningf(WARN_NESTED_EXTERNS, pos, "nested extern declaration of '%#N'", entity); } + if (current_scope == file_scope) { + if (entity->kind == ENTITY_FUNCTION) { + if (entity->function.alias) { + if (is_definition) + errorf(pos, "definition of '%N' with alias attribute", entity); + /* TODO alias provides a definition */ + *(bool*)&is_definition = true; + add_alias(entity, entity->function.alias); + } + } + if (entity->kind == ENTITY_VARIABLE) { + if (entity->variable.alias) { + if (is_definition) + errorf(pos, "definition of '%N' with alias attribute", entity); + /* TODO alias provides a definition */ + *(bool*)&is_definition = true; + add_alias(entity, entity->variable.alias); + } + } + } + if (previous_entity != NULL) { position_t const *const ppos = &previous_entity->base.pos; @@ -4094,6 +4160,16 @@ error_redeclaration: } } + /* merge alias attribute into earlier declaration */ + if (entity->kind == ENTITY_FUNCTION) { + if (entity->function.alias) + previous_entity->function.alias = entity->function.alias; + } + if (entity->kind == ENTITY_VARIABLE) { + if (entity->variable.alias) + previous_entity->variable.alias = entity->variable.alias; + } + prev_decl->modifiers |= decl->modifiers; if (entity->kind == ENTITY_FUNCTION) { previous_entity->function.is_inline |= entity->function.is_inline; @@ -10068,6 +10144,8 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) */ static void check_unused_globals(void) { + mark_aliases_used(); + if (!is_warn_on(WARN_UNUSED_FUNCTION) && !is_warn_on(WARN_UNUSED_VARIABLE)) return; -- 2.20.1