implement array intiailizers
[cparser] / ast2firm.c
index 3f90847..721c92d 100644 (file)
@@ -35,6 +35,9 @@ static ir_node  *current_switch_cond;
 static bool      saw_default_label;
 static ir_node **imature_blocks;
 
+static const declaration_t *current_function_decl;
+static ir_node             *current_function_name;
+
 typedef enum declaration_type_t {
        DECLARATION_TYPE_UNKNOWN,
        DECLARATION_TYPE_FUNCTION,
@@ -106,7 +109,7 @@ static ident *unique_ident(const char *tag)
 {
        char buf[256];
 
-       snprintf(buf, sizeof(buf), "%s.%d", tag, unique_id);
+       snprintf(buf, sizeof(buf), "%s.%u", tag, unique_id);
        unique_id++;
        return new_id_from_str(buf);
 }
@@ -368,8 +371,9 @@ static ir_type *create_struct_type(compound_type_t *type)
 
                int entry_size      = get_type_size_bytes(entry_ir_type);
                int entry_alignment = get_type_alignment_bytes(entry_ir_type);
-               int misalign = offset % entry_alignment;
-               offset += misalign;
+               int misalign        = offset % entry_alignment;
+               if (misalign != 0)
+                       offset += entry_alignment - misalign;
 
                ir_entity *entity = new_entity(ir_type, ident, entry_ir_type);
                set_entity_offset(entity, offset);
@@ -569,29 +573,30 @@ static ir_node *create_symconst(dbg_info *dbgi, ir_entity *entity)
        return new_d_SymConst(dbgi, sym, symconst_addr_ent);
 }
 
-static ir_node *string_literal_to_firm(const string_literal_t* literal)
+static ir_node *string_to_firm(const source_position_t *const src_pos,
+                               const char *const id_prefix,
+                               const char *const string)
 {
-       ir_type   *global_type = get_glob_type();
-       ir_type   *type        = new_type_array(unique_ident("strtype"), 1,
-                                               ir_type_const_char);
+       ir_type *const global_type = get_glob_type();
+       ir_type *const type        = new_type_array(unique_ident("strtype"), 1,
+                                                   ir_type_const_char);
 
-       ident     *id     = unique_ident("Lstr");
-       ir_entity *entity = new_entity(global_type, id, type);
+       ident     *const id     = unique_ident(id_prefix);
+       ir_entity *const entity = new_entity(global_type, id, type);
        set_entity_ld_ident(entity, id);
        set_entity_variability(entity, variability_constant);
 
-       ir_type    *elem_type = ir_type_const_char;
-       ir_mode    *mode      = get_type_mode(elem_type);
+       ir_type *const elem_type = ir_type_const_char;
+       ir_mode *const mode      = get_type_mode(elem_type);
 
-       const char *string = literal->value;
-       size_t      slen   = strlen(string) + 1;
+       const size_t slen = strlen(string) + 1;
 
        set_array_lower_bound_int(type, 0, 0);
        set_array_upper_bound_int(type, 0, slen);
        set_type_size_bytes(type, slen);
        set_type_state(type, layout_fixed);
 
-       tarval **tvs = xmalloc(slen * sizeof(tvs[0]));
+       tarval **const tvs = xmalloc(slen * sizeof(tvs[0]));
        for(size_t i = 0; i < slen; ++i) {
                tvs[i] = new_tarval_from_long(string[i], mode);
        }
@@ -599,11 +604,17 @@ static ir_node *string_literal_to_firm(const string_literal_t* literal)
        set_array_entity_values(entity, tvs, slen);
        free(tvs);
 
-       dbg_info *dbgi = get_dbg_info(&literal->expression.source_position);
+       dbg_info *const dbgi = get_dbg_info(src_pos);
 
        return create_symconst(dbgi, entity);
 }
 
+static ir_node *string_literal_to_firm(const string_literal_t* literal)
+{
+       return string_to_firm(&literal->expression.source_position, "Lstr",
+                             literal->value);
+}
+
 static ir_node *deref_address(type_t *const type, ir_node *const addr,
                               dbg_info *const dbgi)
 {
@@ -806,7 +817,7 @@ static ir_node *create_conv(dbg_info *dbgi, ir_node *value, ir_mode *dest_mode)
 {
        ir_mode *value_mode = get_irn_mode(value);
 
-       if(value_mode == dest_mode)
+       if (value_mode == dest_mode || is_Bad(value))
                return value;
 
        if(dest_mode == mode_b) {
@@ -1300,6 +1311,9 @@ static ir_node *conditional_to_firm(const conditional_expression_t *expression)
        add_immBlock_pred(common_block, false_jmp);
        mature_immBlock(common_block);
 
+       /* TODO improve static semantics, so either both or no values are NULL */
+       if (true_val == NULL || false_val == NULL) return NULL;
+
        ir_node *in[2] = { true_val, false_val };
        ir_mode *mode  = get_irn_mode(true_val);
        assert(get_irn_mode(false_val) == mode);
@@ -1333,6 +1347,122 @@ static ir_node *select_to_firm(const select_expression_t *expression)
        return deref_address(type, addr, dbgi);
 }
 
+/* Values returned by __builtin_classify_type. */
+typedef enum gcc_type_class
+{
+       no_type_class = -1,
+       void_type_class,
+       integer_type_class,
+       char_type_class,
+       enumeral_type_class,
+       boolean_type_class,
+       pointer_type_class,
+       reference_type_class,
+       offset_type_class,
+       real_type_class,
+       complex_type_class,
+       function_type_class,
+       method_type_class,
+       record_type_class,
+       union_type_class,
+       array_type_class,
+       string_type_class,
+       set_type_class,
+       file_type_class,
+       lang_type_class
+} gcc_type_class;
+
+static ir_node *classify_type_to_firm(const classify_type_expression_t *const expr)
+{
+       const type_t *const type = expr->type_expression->datatype;
+
+       gcc_type_class tc;
+       switch (type->type)
+       {
+               case TYPE_ATOMIC: {
+                       const atomic_type_t *const atomic_type = (const atomic_type_t*)type;
+                       switch (atomic_type->atype) {
+                               // should not be reached
+                               case ATOMIC_TYPE_INVALID:
+                                       tc = no_type_class;
+                                       break;
+
+                               // gcc cannot do that
+                               case ATOMIC_TYPE_VOID:
+                                       tc = void_type_class;
+                                       break;
+
+                               case ATOMIC_TYPE_CHAR:      // gcc handles this as integer
+                               case ATOMIC_TYPE_SCHAR:     // gcc handles this as integer
+                               case ATOMIC_TYPE_UCHAR:     // gcc handles this as integer
+                               case ATOMIC_TYPE_SHORT:
+                               case ATOMIC_TYPE_USHORT:
+                               case ATOMIC_TYPE_INT:
+                               case ATOMIC_TYPE_UINT:
+                               case ATOMIC_TYPE_LONG:
+                               case ATOMIC_TYPE_ULONG:
+                               case ATOMIC_TYPE_LONGLONG:
+                               case ATOMIC_TYPE_ULONGLONG:
+                               case ATOMIC_TYPE_BOOL:      // gcc handles this as integer
+                                       tc = integer_type_class;
+                                       break;
+
+                               case ATOMIC_TYPE_FLOAT:
+                               case ATOMIC_TYPE_DOUBLE:
+                               case ATOMIC_TYPE_LONG_DOUBLE:
+                                       tc = real_type_class;
+                                       break;
+
+#ifdef PROVIDE_COMPLEX
+                               case ATOMIC_TYPE_FLOAT_COMPLEX:
+                               case ATOMIC_TYPE_DOUBLE_COMPLEX:
+                               case ATOMIC_TYPE_LONG_DOUBLE_COMPLEX:
+                                       tc = complex_type_class;
+                                       break;
+                               case ATOMIC_TYPE_FLOAT_IMAGINARY:
+                               case ATOMIC_TYPE_DOUBLE_IMAGINARY:
+                               case ATOMIC_TYPE_LONG_DOUBLE_IMAGINARY:
+                                       tc = complex_type_class;
+                                       break;
+#endif
+
+                               default:
+                                       panic("Unimplemented case in classify_type_to_firm().");
+                       }
+                       break;
+               }
+
+               case TYPE_ARRAY:           // gcc handles this as pointer
+               case TYPE_FUNCTION:        // gcc handles this as pointer
+               case TYPE_POINTER:         tc = pointer_type_class; break;
+               case TYPE_COMPOUND_STRUCT: tc = record_type_class;  break;
+               case TYPE_COMPOUND_UNION:  tc = union_type_class;   break;
+
+               // gcc handles this as integer
+               case TYPE_ENUM:            tc = integer_type_class; break;
+
+               default:
+                       panic("Unimplemented case in classify_type_to_firm().");
+       }
+
+       dbg_info *const dbgi = get_dbg_info(&expr->expression.source_position);
+       ir_mode  *const mode = mode_Is;
+       tarval   *const tv   = new_tarval_from_long(tc, mode);
+       return new_d_Const(dbgi, mode, tv);
+}
+
+static ir_node *function_name_to_firm(const string_literal_t *const expr)
+{
+       if (current_function_name == NULL) {
+               const source_position_t *const src_pos =
+                       &expr->expression.source_position;
+               const char *const name = current_function_decl->symbol->string;
+               current_function_name = string_to_firm(src_pos, "__func__", name);
+       }
+
+       return current_function_name;
+}
+
 static ir_node *dereference_addr(const unary_expression_t *const expression)
 {
        assert(expression->type == UNEXPR_DEREFERENCE);
@@ -1388,9 +1518,12 @@ static ir_node *_expression_to_firm(const expression_t *expression)
                return conditional_to_firm((const conditional_expression_t*)expression);
        case EXPR_SELECT:
                return select_to_firm((const select_expression_t*) expression);
+       case EXPR_CLASSIFY_TYPE:
+               return classify_type_to_firm((const classify_type_expression_t*)expression);
        case EXPR_FUNCTION:
-       case EXPR_OFFSETOF:
        case EXPR_PRETTY_FUNCTION:
+               return function_name_to_firm((const string_literal_t*)expression);
+       case EXPR_OFFSETOF:
        case EXPR_VA_ARG:
        case EXPR_STATEMENT:
        case EXPR_BUILTIN_SYMBOL:
@@ -1769,6 +1902,141 @@ static void create_declaration_entity(declaration_t *declaration,
        /* TODO: visibility? */
 }
 
+typedef struct compound_graph_path_entry_t compound_graph_path_entry_t;
+
+enum compound_graph_entry_type_t {
+       COMPOUND_GRAPH_ENTRY_ARRAY,
+       COMPOUND_GRAPH_ENTRY_COMPOUND
+};
+
+struct compound_graph_path_entry_t {
+       int type;
+       union {
+               ir_entity *entity;
+               int        array_index;
+       } v;
+       compound_graph_path_entry_t *prev;
+};
+
+static void create_initializer_list(initializer_list_t *initializer,
+                                    type_t *type, ir_entity *entity,
+                                    compound_graph_path_entry_t *entry,
+                                    int len);
+
+static void create_initializer_value(initializer_value_t *initializer,
+                                     ir_entity *entity,
+                                     compound_graph_path_entry_t *entry,
+                                     int len)
+{
+       ir_node *node = expression_to_firm(initializer->value);
+
+       ir_type *type = get_entity_type(entity);
+       compound_graph_path *path = new_compound_graph_path(type, len);
+
+       int i = len - 1;
+       for( ; entry != NULL; entry = entry->prev, --i) {
+               assert(i >= 0);
+               if(entry->type == COMPOUND_GRAPH_ENTRY_COMPOUND) {
+                       set_compound_graph_path_node(path, i, entry->v.entity);
+               } else {
+                       assert(entry->type == COMPOUND_GRAPH_ENTRY_ARRAY);
+                       set_compound_graph_path_array_index(path, i, entry->v.array_index);
+               }
+       }
+       assert(i == -1);
+
+       add_compound_ent_value_w_path(entity, node, path);
+}
+
+static void create_initializer_compound(initializer_list_t *initializer,
+                                        compound_type_t *type,
+                                        ir_entity *entity,
+                                        compound_graph_path_entry_t *last_entry,
+                                        int len)
+{
+       declaration_t *compound_declaration = type->declaration;
+
+       declaration_t *compound_entry = compound_declaration->context.declarations;
+
+       compound_graph_path_entry_t entry;
+       entry.type = COMPOUND_GRAPH_ENTRY_COMPOUND;
+       entry.prev = last_entry;
+       ++len;
+
+       size_t i = 0;
+       for( ; compound_entry != NULL; compound_entry = compound_entry->next) {
+               if(compound_entry->symbol == NULL)
+                       continue;
+               if(compound_entry->namespc != NAMESPACE_NORMAL)
+                       continue;
+
+               if(i >= initializer->len)
+                       break;
+
+               entry.v.entity = compound_entry->v.entity;
+
+               initializer_t *sub_initializer = initializer->initializers[i];
+
+               assert(compound_entry != NULL);
+               assert(compound_entry->declaration_type
+                               == DECLARATION_TYPE_COMPOUND_MEMBER);
+
+               if(sub_initializer->type == INITIALIZER_VALUE) {
+                       create_initializer_value((initializer_value_t*) sub_initializer,
+                                                entity, &entry, len);
+               } else {
+                       assert(sub_initializer->type == INITIALIZER_LIST);
+                       create_initializer_list((initializer_list_t*) sub_initializer,
+                                               compound_entry->type, entity, &entry, len);
+               }
+
+               ++i;
+       }
+}
+
+static void create_initializer_array(initializer_list_t *initializer,
+                                     array_type_t *type, ir_entity *entity,
+                                     compound_graph_path_entry_t *last_entry,
+                                     int len)
+{
+       type_t *element_type = type->element_type;
+
+       compound_graph_path_entry_t entry;
+       entry.type = COMPOUND_GRAPH_ENTRY_ARRAY;
+       entry.prev = last_entry;
+       ++len;
+
+       for(size_t i = 0; i < initializer->len; ++i) {
+               entry.v.array_index = i;
+
+               initializer_t *sub_initializer = initializer->initializers[i];
+
+               if(sub_initializer->type == INITIALIZER_VALUE) {
+                       create_initializer_value((initializer_value_t*) sub_initializer,
+                                                entity, &entry, len);
+               } else {
+                       assert(sub_initializer->type == INITIALIZER_LIST);
+                       create_initializer_list((initializer_list_t*) sub_initializer,
+                                               element_type, entity, &entry, len);
+               }
+       }
+}
+
+static void create_initializer_list(initializer_list_t *initializer,
+                                    type_t *type, ir_entity *entity,
+                                    compound_graph_path_entry_t *entry, int len)
+{
+       if(type->type == TYPE_ARRAY) {
+               create_initializer_array(initializer, (array_type_t*) type,
+                                        entity, entry, len);
+       } else {
+               assert(type->type == TYPE_COMPOUND_STRUCT
+                               || type->type == TYPE_COMPOUND_UNION);
+               create_initializer_compound(initializer, (compound_type_t*) type,
+                                           entity, entry, len);
+       }
+}
+
 static void create_initializer(declaration_t *declaration)
 {
        initializer_t *initializer = declaration->init.initializer;
@@ -1776,21 +2044,30 @@ static void create_initializer(declaration_t *declaration)
                return;
 
        if(initializer->type == INITIALIZER_VALUE) {
-               assert(initializer->designator == NULL);
-               assert(initializer->next == NULL);
-               ir_node *init_node = expression_to_firm(initializer->v.value);
+               initializer_value_t *initializer_value
+                       = (initializer_value_t*) initializer;
+               ir_node *value = expression_to_firm(initializer_value->value);
 
                if(declaration->declaration_type == DECLARATION_TYPE_LOCAL_VARIABLE) {
-                       set_value(declaration->v.value_number, init_node);
+                       set_value(declaration->v.value_number, value);
                } else {
                        ir_entity *entity = declaration->v.entity;
 
                        set_entity_variability(entity, variability_initialized);
-                       set_atomic_ent_value(entity, init_node);
+                       set_atomic_ent_value(entity, value);
                }
        } else {
                assert(initializer->type == INITIALIZER_LIST);
-               panic("list initializer not supported yet");
+               initializer_list_t *list = (initializer_list_t*) initializer;
+
+               declaration_type_t declaration_type = declaration->declaration_type;
+               assert(declaration_type == DECLARATION_TYPE_LOCAL_VARIABLE_ENTITY
+                               || declaration_type == DECLARATION_TYPE_GLOBAL_VARIABLE);
+
+               ir_entity *entity = declaration->v.entity;
+               set_entity_variability(entity, variability_initialized);
+
+               create_initializer_list(list, declaration->type, entity, NULL, 0);
        }
 }
 
@@ -2204,6 +2481,9 @@ static void create_function(declaration_t *declaration)
        if(declaration->init.statement == NULL)
                return;
 
+       current_function_decl = declaration;
+       current_function_name = NULL;
+
        assert(imature_blocks == NULL);
        imature_blocks = NEW_ARR_F(ir_node*, 0);
 
@@ -2266,7 +2546,9 @@ static void create_function(declaration_t *declaration)
                int misalign = 0;
                if(align > 0) {
                        misalign  = offset % align;
-                       offset   += misalign;
+                       if(misalign > 0) {
+                               offset += align - misalign;
+                       }
                }
 
                set_entity_offset(entity, offset);
@@ -2320,9 +2602,6 @@ static void context_to_firm(context_t *context)
 
 void translation_unit_to_firm(translation_unit_t *unit)
 {
-       /* remove me later TODO FIXME */
-       (void) get_type_size;
-
        /* just to be sure */
        continue_label      = NULL;
        break_label         = NULL;