- change enum to have an underlying atomic type
authorMatthias Braun <matze@braunis.de>
Sun, 14 Dec 2008 11:05:39 +0000 (11:05 +0000)
committerMatthias Braun <matze@braunis.de>
Sun, 14 Dec 2008 11:05:39 +0000 (11:05 +0000)
- improve handling of mode attribute a bit

[r24658]

ast2firm.c
parser.c
type_t.h

index 7e9d18c..a6eb917 100644 (file)
@@ -265,7 +265,7 @@ static unsigned get_type_size_const(type_t *type)
        case TYPE_IMAGINARY:
                return get_atomic_type_size(type->imaginary.akind);
        case TYPE_ENUM:
-               return get_mode_size_bytes(mode_int);
+               return get_atomic_type_size(type->enumt.akind);
        case TYPE_COMPOUND_UNION:
        case TYPE_COMPOUND_STRUCT:
                return get_compound_type_size(&type->compound);
@@ -350,14 +350,13 @@ static type_t *get_aligned_type(type_t *type, int alignment)
 /**
  * Creates a Firm type for an atomic type
  */
-static ir_type *create_atomic_type(const atomic_type_t *type)
+static ir_type *create_atomic_type(atomic_type_kind_t akind, int alignment)
 {
-       atomic_type_kind_t  kind   = type->akind;
-       ir_mode            *mode   = atomic_modes[kind];
+       ir_mode            *mode   = atomic_modes[akind];
        ident              *id     = get_mode_ident(mode);
        ir_type            *irtype = new_type_primitive(id, mode);
 
-       set_type_alignment_bytes(irtype, type->base.alignment);
+       set_type_alignment_bytes(irtype, alignment);
 
        return irtype;
 }
@@ -826,7 +825,7 @@ static ir_type *create_enum_type(enum_type_t *const type)
 
        constant_folding = constant_folding_old;
 
-       return ir_type_int;
+       return create_atomic_type(type->akind, type->base.alignment);
 }
 
 static ir_type *get_ir_type_incomplete(type_t *type)
@@ -866,10 +865,11 @@ ir_type *get_ir_type(type_t *type)
        switch (type->kind) {
        case TYPE_ERROR:
                /* Happens while constant folding, when there was an error */
-               return create_atomic_type(&type_void->atomic);
+               return create_atomic_type(ATOMIC_TYPE_VOID, 0);
 
        case TYPE_ATOMIC:
-               firm_type = create_atomic_type(&type->atomic);
+               firm_type = create_atomic_type(type->atomic.akind,
+                                              type->base.alignment);
                break;
        case TYPE_COMPLEX:
                firm_type = create_complex_type(&type->complex);
index fb9f02d..cca652e 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -65,7 +65,7 @@ struct gnu_attribute_t {
        union {
                size_t              value;
                string_t            string;
-               atomic_type_kind_t  akind;
+               symbol_t           *symbol;
                long                argument;  /**< Single argument. */
                argument_list_t    *arguments; /**< List of argument expressions. */
        } u;
@@ -969,13 +969,8 @@ static int get_akind_rank(atomic_type_kind_t akind)
 static int get_rank(const type_t *type)
 {
        assert(!is_typeref(type));
-       /* The C-standard allows promoting enums to int or unsigned int (see ยง 7.2.2
-        * and esp. footnote 108). However we can't fold constants (yet), so we
-        * can't decide whether unsigned int is possible, while int always works.
-        * (unsigned int would be preferable when possible... for stuff like
-        *  struct { enum { ... } bla : 4; } ) */
        if (type->kind == TYPE_ENUM)
-               return get_akind_rank(ATOMIC_TYPE_INT);
+               return get_akind_rank(type->enumt.akind);
 
        assert(type->kind == TYPE_ATOMIC);
        return get_akind_rank(type->atomic.akind);
@@ -1465,35 +1460,13 @@ static void parse_gnu_attribute_model_arg(gnu_attribute_t *attribute)
  */
 static void parse_gnu_attribute_mode_arg(gnu_attribute_t *attribute)
 {
-       /* TODO: find out what is allowed here... */
-
-       /* at least: byte, word, pointer, list of machine modes
-        * __XXX___ is interpreted as XXX */
        add_anchor_token(')');
 
        if (token.type != T_IDENTIFIER) {
                expect(T_IDENTIFIER, end_error);
        }
 
-       /* This isn't really correct, the backend should provide a list of machine
-        * specific modes (according to gcc philosophy that is...) */
-       const char *symbol_str = token.v.symbol->string;
-       if (strcmp_underscore("QI",   symbol_str) == 0 ||
-           strcmp_underscore("byte", symbol_str) == 0) {
-               attribute->u.akind = ATOMIC_TYPE_CHAR;
-       } else if (strcmp_underscore("HI", symbol_str) == 0) {
-               attribute->u.akind = ATOMIC_TYPE_SHORT;
-       } else if (strcmp_underscore("SI",      symbol_str) == 0
-               || strcmp_underscore("word",    symbol_str) == 0
-               || strcmp_underscore("pointer", symbol_str) == 0) {
-               attribute->u.akind = ATOMIC_TYPE_INT;
-       } else if (strcmp_underscore("DI", symbol_str) == 0) {
-               attribute->u.akind = ATOMIC_TYPE_LONGLONG;
-       } else {
-               if (warning.other)
-                       warningf(HERE, "ignoring unknown mode '%s'", symbol_str);
-               attribute->invalid = true;
-       }
+       attribute->u.symbol = token.v.symbol;
        next_token();
 
        rem_anchor_token(')');
@@ -3167,6 +3140,7 @@ static type_t *parse_enum_specifier(void)
 
        type_t *const type = allocate_type_zero(TYPE_ENUM);
        type->enumt.enume  = &entity->enume;
+       type->enumt.akind  = ATOMIC_TYPE_INT;
 
        if (token.type == '{') {
                if (symbol != NULL) {
@@ -3610,54 +3584,63 @@ static void finish_union_type(compound_type_t *type)
        type->base.alignment = alignment;
 }
 
-static type_t *handle_mode_attribute(const gnu_attribute_t *attribute,
+static type_t *handle_attribute_mode(const gnu_attribute_t *attribute,
                                      type_t *orig_type)
 {
        type_t *type = skip_typeref(orig_type);
-       if (type->kind != TYPE_ATOMIC) {
-               errorf(HERE,
-                          "__attribute__(mode)) only allowed for atomic types");
+
+       /* at least: byte, word, pointer, list of machine modes
+        * __XXX___ is interpreted as XXX */
+
+       /* This isn't really correct, the backend should provide a list of machine
+        * specific modes (according to gcc philosophy that is...) */
+       const char         *symbol_str = attribute->u.symbol->string;
+       bool                sign       = is_type_signed(type);
+       atomic_type_kind_t  akind;
+       if (strcmp_underscore("QI",   symbol_str) == 0 ||
+           strcmp_underscore("byte", symbol_str) == 0) {
+               akind = sign ? ATOMIC_TYPE_CHAR : ATOMIC_TYPE_UCHAR;
+       } else if (strcmp_underscore("HI", symbol_str) == 0) {
+               akind = sign ? ATOMIC_TYPE_SHORT : ATOMIC_TYPE_USHORT;
+       } else if (strcmp_underscore("SI",      symbol_str) == 0
+               || strcmp_underscore("word",    symbol_str) == 0
+               || strcmp_underscore("pointer", symbol_str) == 0) {
+               akind = sign ? ATOMIC_TYPE_INT : ATOMIC_TYPE_UINT;
+       } else if (strcmp_underscore("DI", symbol_str) == 0) {
+               akind = sign ? ATOMIC_TYPE_LONGLONG : ATOMIC_TYPE_ULONGLONG;
+       } else {
+               if (warning.other)
+                       warningf(HERE, "ignoring unknown mode '%s'", symbol_str);
                return orig_type;
        }
-       atomic_type_kind_t  akind = attribute->u.akind;
-       if (!is_type_signed(type)) {
-               switch (akind) {
-               case ATOMIC_TYPE_CHAR: akind = ATOMIC_TYPE_UCHAR; break;
-               case ATOMIC_TYPE_SHORT: akind = ATOMIC_TYPE_USHORT; break;
-               case ATOMIC_TYPE_INT: akind = ATOMIC_TYPE_UINT; break;
-               case ATOMIC_TYPE_LONGLONG: akind = ATOMIC_TYPE_ULONGLONG; break;
-               default:
-                       errorf(HERE, "invalid akind in mode attribute");
-                       return orig_type;
-               }
-       } else {
-               switch (akind) {
-               case ATOMIC_TYPE_CHAR: akind = ATOMIC_TYPE_SCHAR; break;
-               case ATOMIC_TYPE_SHORT: akind = ATOMIC_TYPE_SHORT; break;
-               case ATOMIC_TYPE_INT: akind = ATOMIC_TYPE_INT; break;
-               case ATOMIC_TYPE_LONGLONG: akind = ATOMIC_TYPE_LONGLONG; break;
-               default:
-                       errorf(HERE, "invalid akind in mode attribute");
-                       return orig_type;
-               }
+
+       if (type->kind == TYPE_ATOMIC) {
+               type_t *copy       = duplicate_type(type);
+               copy->atomic.akind = akind;
+               return identify_new_type(copy);
+       } else if (type->kind == TYPE_ENUM) {
+               type_t *copy      = duplicate_type(type);
+               copy->enumt.akind = akind;
+               return identify_new_type(copy);
+       } else if (is_type_pointer(type)) {
+               warningf(HERE, "__attribute__((mode)) on pointers not implemented yet (ignored)");
+               return type;
        }
 
-       type_t *copy       = duplicate_type(type);
-       copy->atomic.akind = akind;
-       return identify_new_type(copy);
+       errorf(HERE, "__attribute__((mode)) only allowed on integer, enum or pointer type");
+       return orig_type;
 }
 
 static type_t *handle_type_attributes(const gnu_attribute_t *attributes,
                                       type_t *type)
 {
-       /* handle these strange/stupid mode attributes */
        const gnu_attribute_t *attribute = attributes;
        for ( ; attribute != NULL; attribute = attribute->next) {
                if (attribute->invalid)
                        continue;
 
                if (attribute->kind == GNU_AK_MODE) {
-                       type = handle_mode_attribute(attribute, type);
+                       type = handle_attribute_mode(attribute, type);
                } else if (attribute->kind == GNU_AK_ALIGNED) {
                        int alignment = 32; /* TODO: fill in maximum useful alignment for
                                               target machine */
@@ -4607,14 +4590,13 @@ static void parse_declaration_attributes(entity_t *entity)
        if (type == NULL)
                return;
 
-       /* handle these strange/stupid mode attributes */
        gnu_attribute_t *attribute = attributes;
        for ( ; attribute != NULL; attribute = attribute->next) {
                if (attribute->invalid)
                        continue;
 
                if (attribute->kind == GNU_AK_MODE) {
-                       type = handle_mode_attribute(attribute, type);
+                       type = handle_attribute_mode(attribute, type);
                } else if (attribute->kind == GNU_AK_ALIGNED) {
                        int alignment = 32; /* TODO: fill in maximum usefull alignment for target machine */
                        if (attribute->has_arguments)
index f9b5ae6..9015589 100644 (file)
--- a/type_t.h
+++ b/type_t.h
@@ -162,11 +162,12 @@ struct compound_type_t {
 };
 
 struct enum_type_t {
-       type_base_t     base;
+       type_base_t         base;
+       atomic_type_kind_t  akind; /**< underlying atomic type */
        /** the enum entity. You can find the enum entries by walking the
         *  enum->base.next list until you don't find ENTITY_ENUM_VALUE entities
         *  anymore */
-       enum_t         *enume;
+       enum_t             *enume;
 };
 
 struct typedef_type_t {