+/*
+ * Copyright (C) 1995-2011 University of Karlsruhe. All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file type.c
+ * @brief Representation of types.
+ * @author Goetz Lindenmaier, Michael Beck
+ * @version $Id$
+ * @brief
+ *
+ * Implementation of the datastructure to hold
+ * type information.
+ *
+ * This module supplies a datastructure to represent all types
+ * known in the compiled program. This includes types specified
+ * in the program as well as types defined by the language. In the
+ * view of the intermediate representation there is no difference
+ * between these types.
+ *
+ * There exist several kinds of types, arranged by the structure of
+ * the type. A type is described by a set of attributes. Some of
+ * these attributes are common to all types, others depend on the
+ * kind of the type.
+ *
+ * Types are different from the modes defined in irmode: Types are
+ * on the level of the programming language, modes at the level of
+ * the target processor.
+ */
+#include "config.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+
+#include "type_t.h"
+
+#include "xmalloc.h"
+#include "irprog_t.h"
+#include "ircons.h"
+#include "tpop_t.h"
+#include "tv_t.h"
+#include "irhooks.h"
+#include "irtools.h"
+#include "entity_t.h"
+#include "error.h"
+#include "dbginfo.h"
+
+#include "array.h"
+
+ir_type *firm_none_type;
+ir_type *get_none_type(void)
+{
+ return firm_none_type;
+}
+
+ir_type *firm_code_type;
+ir_type *get_code_type(void)
+{
+ return firm_code_type;
+}
+
+ir_type *firm_unknown_type;
+ir_type *get_unknown_type(void)
+{
+ return firm_unknown_type;
+}
+
+/* Suffixes added to types used for pass-by-value representations. */
+static ident *value_params_suffix = NULL;
+static ident *value_ress_suffix = NULL;
+
+void ir_init_type(void)
+{
+ value_params_suffix = new_id_from_str(VALUE_PARAMS_SUFFIX);
+ value_ress_suffix = new_id_from_str(VALUE_RESS_SUFFIX);
+
+ /* construct none and unknown type. */
+ firm_none_type = new_type(tpop_none, mode_BAD, NULL);
+ set_type_size_bytes(firm_none_type, 0);
+ set_type_state (firm_none_type, layout_fixed);
+ remove_irp_type(firm_none_type);
+
+ firm_code_type = new_type(tpop_code, mode_ANY, NULL);
+ set_type_state(firm_code_type, layout_fixed);
+ remove_irp_type(firm_code_type);
+
+ firm_unknown_type = new_type(tpop_unknown, mode_ANY, NULL);
+ set_type_size_bytes(firm_unknown_type, 0);
+ set_type_state (firm_unknown_type, layout_fixed);
+ remove_irp_type(firm_unknown_type);
+}
+
+void ir_finish_type(void)
+{
+ if (firm_none_type != NULL) {
+ free_type(firm_none_type);
+ firm_none_type = NULL;
+ }
+ if (firm_code_type != NULL) {
+ free_type(firm_code_type);
+ firm_code_type = NULL;
+ }
+ if (firm_unknown_type != NULL) {
+ free_type(firm_unknown_type);
+ firm_unknown_type = NULL;
+ }
+ value_params_suffix = NULL;
+ value_ress_suffix = NULL;
+}
+
+/** the global type visited flag */
+ir_visited_t firm_type_visited;
+
+void (set_master_type_visited)(ir_visited_t val)
+{
+ _set_master_type_visited(val);
+}
+
+ir_visited_t (get_master_type_visited)(void)
+{
+ return _get_master_type_visited();
+}
+
+void (inc_master_type_visited)(void)
+{
+ _inc_master_type_visited();
+}
+
+ir_type *new_type(const tp_op *type_op, ir_mode *mode, type_dbg_info *db)
+{
+ ir_type *res;
+ size_t node_size;
+
+ node_size = offsetof(ir_type, attr) + type_op->attr_size;
+ res = (ir_type*)xmalloc(node_size);
+ memset(res, 0, node_size);
+
+ res->kind = k_type;
+ res->type_op = type_op;
+ res->mode = mode;
+ res->visibility = ir_visibility_external;
+ res->flags = tf_none;
+ res->size = 0;
+ res->align = 0;
+ res->visit = 0;
+ res->link = NULL;
+ res->dbi = db;
+ res->assoc_type = NULL;
+#ifdef DEBUG_libfirm
+ res->nr = get_irp_new_node_nr();
+#endif /* defined DEBUG_libfirm */
+
+ add_irp_type(res); /* Remember the new type global. */
+
+ return res;
+}
+
+void free_type(ir_type *tp)
+{
+ const tp_op *op = get_type_tpop(tp);
+
+ if ((get_type_tpop(tp) == tpop_none) || (get_type_tpop(tp) == tpop_unknown)
+ || (get_type_tpop(tp) == tpop_code))
+ return;
+ /* Remove from list of all types */
+ remove_irp_type(tp);
+ /* Free the attributes of the type. */
+ free_type_attrs(tp);
+ /* Free entities automatically allocated with the ir_type */
+ if (op->ops.free_auto_entities)
+ op->ops.free_auto_entities(tp);
+ /* And now the type itself... */
+ tp->kind = k_BAD;
+ free(tp);
+}
+
+void free_type_entities(ir_type *tp)
+{
+ const tp_op *tpop = get_type_tpop(tp);
+
+ if (tpop->ops.free_entities)
+ tpop->ops.free_entities(tp);
+}
+
+void free_type_attrs(ir_type *tp)
+{
+ const tp_op *tpop = get_type_tpop(tp);
+
+ if (tpop->ops.free_attrs)
+ tpop->ops.free_attrs(tp);
+}
+
+void *(get_type_link)(const ir_type *tp)
+{
+ return _get_type_link(tp);
+}
+
+void (set_type_link)(ir_type *tp, void *l)
+{
+ _set_type_link(tp, l);
+}
+
+const tp_op *(get_type_tpop)(const ir_type *tp)
+{
+ return _get_type_tpop(tp);
+}
+
+ident *(get_type_tpop_nameid)(const ir_type *tp)
+{
+ return _get_type_tpop_nameid(tp);
+}
+
+const char* get_type_tpop_name(const ir_type *tp)
+{
+ assert(tp && tp->kind == k_type);
+ return get_id_str(tp->type_op->name);
+}
+
+tp_opcode (get_type_tpop_code)(const ir_type *tp)
+{
+ return _get_type_tpop_code(tp);
+}
+
+ir_mode *(get_type_mode)(const ir_type *tp)
+{
+ return _get_type_mode(tp);
+}
+
+void set_type_mode(ir_type *tp, ir_mode *mode)
+{
+ const tp_op *tpop = get_type_tpop(tp);
+
+ if (tpop->ops.set_type_mode)
+ tpop->ops.set_type_mode(tp, mode);
+ else
+ assert(0 && "setting a mode is NOT allowed for this type");
+}
+
+/* Outputs a unique number for this node */
+long get_type_nr(const ir_type *tp)
+{
+ assert(tp);
+#ifdef DEBUG_libfirm
+ return tp->nr;
+#else
+ return (long)PTR_TO_INT(tp);
+#endif
+}
+
+unsigned (get_type_size_bytes)(const ir_type *tp)
+{
+ return _get_type_size_bytes(tp);
+}
+
+ir_visibility get_type_visibility(const ir_type *tp)
+{
+ assert(is_type(tp));
+ return tp->visibility;
+}
+
+void set_type_visibility(ir_type *tp, ir_visibility v)
+{
+ assert(is_type(tp));
+ tp->visibility = v;
+}
+
+void set_type_size_bytes(ir_type *tp, unsigned size)
+{
+ const tp_op *tpop = get_type_tpop(tp);
+
+ if (tpop->ops.set_type_size)
+ tpop->ops.set_type_size(tp, size);
+ else
+ assert(0 && "Cannot set size for this type");
+}
+
+unsigned get_type_alignment_bytes(ir_type *tp)
+{
+ unsigned align = 1;
+
+ if (tp->align > 0)
+ return tp->align;
+
+ /* alignment NOT set calculate it "on demand" */
+ if (tp->mode)
+ align = (get_mode_size_bits(tp->mode) + 7) >> 3;
+ else if (is_Array_type(tp))
+ align = get_type_alignment_bytes(get_array_element_type(tp));
+ else if (is_compound_type(tp)) {
+ int i, n = get_compound_n_members(tp);
+
+ align = 0;
+ for (i = 0; i < n; ++i) {
+ ir_type *t = get_entity_type(get_compound_member(tp, i));
+ unsigned a = get_type_alignment_bytes(t);
+
+ if (a > align)
+ align = a;
+ }
+ } else if (is_Method_type(tp)) {
+ align = 0;
+ }
+
+ /* write back */
+ tp->align = align;
+
+ return align;
+}
+
+void set_type_alignment_bytes(ir_type *tp, unsigned align)
+{
+ assert(tp && tp->kind == k_type);
+ /* Methods don't have an alignment. */
+ if (tp->type_op != type_method) {
+ tp->align = align;
+ }
+}
+
+const char *get_type_state_name(ir_type_state s)
+{
+#define X(a) case a: return #a;
+ switch (s) {
+ X(layout_undefined);
+ X(layout_fixed);
+ }
+ return "<unknown>";
+#undef X
+}
+
+ir_type_state (get_type_state)(const ir_type *tp)
+{
+ return _get_type_state(tp);
+}
+
+void set_type_state(ir_type *tp, ir_type_state state)
+{
+ assert(tp && tp->kind == k_type);
+
+ if ((tp->type_op == type_pointer) || (tp->type_op == type_primitive) ||
+ (tp->type_op == type_method))
+ return;
+
+ /* Just a correctness check: */
+ if (state == layout_fixed) {
+ size_t i;
+ switch (get_type_tpop_code(tp)) {
+ case tpo_class:
+ if (tp != get_glob_type()) {
+ size_t n_mem = get_class_n_members(tp);
+ for (i = 0; i < n_mem; i++) {
+ assert(get_entity_offset(get_class_member(tp, i)) > -1);
+ /* TR ??
+ assert(is_Method_type(get_entity_type(get_class_member(tp, i))) ||
+ (get_entity_allocation(get_class_member(tp, i)) == allocation_automatic));
+ */
+ }
+ }
+ break;
+ case tpo_struct:
+ for (i = 0; i < get_struct_n_members(tp); i++) {
+ assert(get_entity_offset(get_struct_member(tp, i)) > -1);
+ }
+ break;
+ case tpo_union:
+ /* ?? */
+ break;
+ case tpo_array:
+ /* ??
+ Check order?
+ Assure that only innermost dimension is dynamic? */
+ break;
+ case tpo_enumeration: {
+#ifndef NDEBUG
+ assert(get_type_mode(tp) != NULL);
+ size_t n_enums = get_enumeration_n_enums(tp);
+ for (i = 0; i < n_enums; ++i) {
+ ir_enum_const *ec = get_enumeration_const(tp, i);
+ ir_tarval *tv = get_enumeration_value(ec);
+ assert(tv != NULL && tv != tarval_bad);
+ }
+#endif
+ break;
+ }
+ default: break;
+ } /* switch (tp) */
+ }
+ if (state == layout_fixed)
+ tp->flags |= tf_layout_fixed;
+ else
+ tp->flags &= ~tf_layout_fixed;
+}
+
+ir_visited_t (get_type_visited)(const ir_type *tp)
+{
+ return _get_type_visited(tp);
+}
+
+void (set_type_visited)(ir_type *tp, ir_visited_t num)
+{
+ _set_type_visited(tp, num);
+}
+
+void (mark_type_visited)(ir_type *tp)
+{
+ _mark_type_visited(tp);
+}
+
+int (type_visited)(const ir_type *tp)
+{
+ return _type_visited(tp);
+}
+
+int (type_not_visited)(const ir_type *tp)
+{
+ return _type_not_visited(tp);
+}
+
+type_dbg_info *(get_type_dbg_info)(const ir_type *tp)
+{
+ return _get_type_dbg_info(tp);
+}
+
+void (set_type_dbg_info)(ir_type *tp, type_dbg_info *db)
+{
+ _set_type_dbg_info(tp, db);
+}
+
+int (is_type)(const void *thing)
+{
+ return _is_type(thing);
+}
+
+/* Checks whether two types are structural equal.*/
+int equal_type(ir_type *typ1, ir_type *typ2)
+{
+ ir_entity **m;
+ ir_type **t;
+ size_t i;
+ size_t j;
+
+ if (typ1 == typ2) return 1;
+
+ if ((get_type_tpop_code(typ1) != get_type_tpop_code(typ2)) ||
+ typ1->name != typ2->name ||
+ (get_type_mode(typ1) != get_type_mode(typ2)) ||
+ (get_type_state(typ1) != get_type_state(typ2)))
+ return 0;
+ if ((get_type_state(typ1) == layout_fixed) &&
+ (get_type_size_bytes(typ1) != get_type_size_bytes(typ2)))
+ return 0;
+
+ switch (get_type_tpop_code(typ1)) {
+ case tpo_class:
+ if (get_class_n_members(typ1) != get_class_n_members(typ2)) return 0;
+ if (get_class_n_subtypes(typ1) != get_class_n_subtypes(typ2)) return 0;
+ if (get_class_n_supertypes(typ1) != get_class_n_supertypes(typ2)) return 0;
+ if (get_class_peculiarity(typ1) != get_class_peculiarity(typ2)) return 0;
+ /** Compare the members **/
+ m = ALLOCANZ(ir_entity*, get_class_n_members(typ1));
+ /* First sort the members of typ2 */
+ for (i = 0; i < get_class_n_members(typ1); i++) {
+ ir_entity *e1 = get_class_member(typ1, i);
+ for (j = 0; j < get_class_n_members(typ2); j++) {
+ ir_entity *e2 = get_class_member(typ2, j);
+ if (get_entity_name(e1) == get_entity_name(e2))
+ m[i] = e2;
+ }
+ }
+ for (i = 0; i < get_class_n_members(typ1); i++) {
+ if (!m[i] || get_class_member(typ1, i) != m[i])
+ return 0;
+ }
+ /** Compare the supertypes **/
+ t = ALLOCANZ(ir_type*, get_class_n_supertypes(typ1));
+ /* First sort the supertypes of typ2 */
+ for (i = 0; i < get_class_n_supertypes(typ1); i++) {
+ ir_type *t1 = get_class_supertype(typ1, i);
+ for (j = 0; j < get_class_n_supertypes(typ2); j++) {
+ ir_type *t2 = get_class_supertype(typ2, j);
+ if (t2->name == t1->name)
+ t[i] = t2;
+ }
+ }
+ for (i = 0; i < get_class_n_supertypes(typ1); i++) {
+ if (!t[i] || /* Found no counterpart */
+ get_class_supertype(typ1, i) != t[i])
+ return 0;
+ }
+ break;
+
+ case tpo_struct:
+ if (get_struct_n_members(typ1) != get_struct_n_members(typ2)) return 0;
+ m = ALLOCANZ(ir_entity*, get_struct_n_members(typ1));
+ /* First sort the members of lt */
+ for (i = 0; i < get_struct_n_members(typ1); i++) {
+ ir_entity *e1 = get_struct_member(typ1, i);
+ for (j = 0; j < get_struct_n_members(typ2); j++) {
+ ir_entity *e2 = get_struct_member(typ2, j);
+ if (get_entity_name(e1) == get_entity_name(e2))
+ m[i] = e2;
+ }
+ }
+ for (i = 0; i < get_struct_n_members(typ1); i++) {
+ if (!m[i] || get_struct_member(typ1, i) != m[i])
+ return 0;
+ }
+ break;
+
+ case tpo_method: {
+ size_t n_param1;
+ size_t n_param2;
+
+ if (get_method_variadicity(typ1) != get_method_variadicity(typ2)) return 0;
+ if (get_method_n_ress(typ1) != get_method_n_ress(typ2)) return 0;
+ if (get_method_calling_convention(typ1) !=
+ get_method_calling_convention(typ2)) return 0;
+
+ if (get_method_variadicity(typ1) == variadicity_non_variadic) {
+ n_param1 = get_method_n_params(typ1);
+ n_param2 = get_method_n_params(typ2);
+ } else {
+ n_param1 = get_method_first_variadic_param_index(typ1);
+ n_param2 = get_method_first_variadic_param_index(typ2);
+ }
+
+ if (n_param1 != n_param2) return 0;
+
+ for (i = 0; i < n_param1; i++) {
+ if (!equal_type(get_method_param_type(typ1, i), get_method_param_type(typ2, i)))
+ return 0;
+ }
+ for (i = 0; i < get_method_n_ress(typ1); i++) {
+ if (!equal_type(get_method_res_type(typ1, i), get_method_res_type(typ2, i)))
+ return 0;
+ }
+ } break;
+
+ case tpo_union:
+ if (get_union_n_members(typ1) != get_union_n_members(typ2)) return 0;
+ m = ALLOCANZ(ir_entity*, get_union_n_members(typ1));
+ /* First sort the members of lt */
+ for (i = 0; i < get_union_n_members(typ1); i++) {
+ ir_entity *e1 = get_union_member(typ1, i);
+ for (j = 0; j < get_union_n_members(typ2); j++) {
+ ir_entity *e2 = get_union_member(typ2, j);
+ if (get_entity_name(e1) == get_entity_name(e2))
+ m[i] = e2;
+ }
+ }
+ for (i = 0; i < get_union_n_members(typ1); i++) {
+ if (!m[i] || get_union_member(typ1, i) != m[i])
+ return 0;
+ }
+ break;
+
+ case tpo_array:
+ if (get_array_n_dimensions(typ1) != get_array_n_dimensions(typ2))
+ return 0;
+ if (!equal_type(get_array_element_type(typ1), get_array_element_type(typ2)))
+ return 0;
+ for (i = 0; i < get_array_n_dimensions(typ1); i++) {
+ if (get_array_lower_bound(typ1, i) != get_array_lower_bound(typ2, i) ||
+ get_array_upper_bound(typ1, i) != get_array_upper_bound(typ2, i))
+ return 0;
+ if (get_array_order(typ1, i) != get_array_order(typ2, i))
+ assert(0 && "type compare with different dimension orders not implemented");
+ }
+ break;
+
+ case tpo_enumeration:
+ assert(0 && "enumerations not implemented");
+ break;
+
+ case tpo_pointer:
+ if (get_pointer_points_to_type(typ1) != get_pointer_points_to_type(typ2))
+ return 0;
+ break;
+
+ case tpo_primitive:
+ break;
+
+ default: break;
+ }
+ return 1;
+}
+
+int smaller_type(ir_type *st, ir_type *lt)
+{
+ ir_entity **m;
+ size_t i;
+ size_t j;
+ size_t n_st_members;
+
+ if (st == lt) return 1;
+
+ if (get_type_tpop_code(st) != get_type_tpop_code(lt))
+ return 0;
+
+ switch (get_type_tpop_code(st)) {
+ case tpo_class:
+ return is_SubClass_of(st, lt);
+
+ case tpo_struct:
+ n_st_members = get_struct_n_members(st);
+ if (n_st_members != get_struct_n_members(lt))
+ return 0;
+
+ m = ALLOCANZ(ir_entity*, n_st_members);
+ /* First sort the members of lt */
+ for (i = 0; i < n_st_members; ++i) {
+ ir_entity *se = get_struct_member(st, i);
+ size_t n = get_struct_n_members(lt);
+ for (j = 0; j < n; ++j) {
+ ir_entity *le = get_struct_member(lt, j);
+ if (get_entity_name(le) == get_entity_name(se))
+ m[i] = le;
+ }
+ }
+ for (i = 0; i < n_st_members; i++) {
+ if (!m[i] || /* Found no counterpart */
+ !smaller_type(get_entity_type(get_struct_member(st, i)), get_entity_type(m[i])))
+ return 0;
+ }
+ break;
+
+ case tpo_method: {
+ size_t n_param1, n_param2;
+
+ /** FIXME: is this still 1? */
+ if (get_method_variadicity(st) != get_method_variadicity(lt)) return 0;
+ if (get_method_n_ress(st) != get_method_n_ress(lt)) return 0;
+ if (get_method_calling_convention(st) !=
+ get_method_calling_convention(lt)) return 0;
+
+ if (get_method_variadicity(st) == variadicity_non_variadic) {
+ n_param1 = get_method_n_params(st);
+ n_param2 = get_method_n_params(lt);
+ } else {
+ n_param1 = get_method_first_variadic_param_index(st);
+ n_param2 = get_method_first_variadic_param_index(lt);
+ }
+
+ if (n_param1 != n_param2) return 0;
+
+ for (i = 0; i < get_method_n_params(st); i++) {
+ if (!smaller_type(get_method_param_type(st, i), get_method_param_type(lt, i)))
+ return 0;
+ }
+ for (i = 0; i < get_method_n_ress(st); i++) {
+ if (!smaller_type(get_method_res_type(st, i), get_method_res_type(lt, i)))
+ return 0;
+ }
+ } break;
+
+ case tpo_union:
+ n_st_members = get_union_n_members(st);
+ if (n_st_members != get_union_n_members(lt)) return 0;
+ m = ALLOCANZ(ir_entity*, n_st_members);
+ /* First sort the members of lt */
+ for (i = 0; i < n_st_members; ++i) {
+ ir_entity *se = get_union_member(st, i);
+ size_t n = get_union_n_members(lt);
+ for (j = 0; j < n; ++j) {
+ ir_entity *le = get_union_member(lt, j);
+ if (get_entity_name(le) == get_entity_name(se))
+ m[i] = le;
+ }
+ }
+ for (i = 0; i < n_st_members; ++i) {
+ if (!m[i] || /* Found no counterpart */
+ !smaller_type(get_entity_type(get_union_member(st, i)), get_entity_type(m[i])))
+ return 0;
+ }
+ break;
+
+ case tpo_array: {
+ ir_type *set, *let; /* small/large elt. ir_type */
+ if (get_array_n_dimensions(st) != get_array_n_dimensions(lt))
+ return 0;
+ set = get_array_element_type(st);
+ let = get_array_element_type(lt);
+ if (set != let) {
+ /* If the element types are different, set must be convertible
+ to let, and they must have the same size so that address
+ computations work out. To have a size the layout must
+ be fixed. */
+ if ((get_type_state(set) != layout_fixed) ||
+ (get_type_state(let) != layout_fixed))
+ return 0;
+ if (!smaller_type(set, let) ||
+ get_type_size_bytes(set) != get_type_size_bytes(let))
+ return 0;
+ }
+ for (i = 0; i < get_array_n_dimensions(st); i++) {
+ if (get_array_lower_bound(lt, i))
+ if (get_array_lower_bound(st, i) != get_array_lower_bound(lt, i))
+ return 0;
+ if (get_array_upper_bound(lt, i))
+ if (get_array_upper_bound(st, i) != get_array_upper_bound(lt, i))
+ return 0;
+ }
+ } break;
+
+ case tpo_enumeration:
+ assert(0 && "enumerations not implemented");
+ break;
+
+ case tpo_pointer:
+ if (!smaller_type(get_pointer_points_to_type(st), get_pointer_points_to_type(lt)))
+ return 0;
+ break;
+
+ case tpo_primitive:
+ if (!smaller_mode(get_type_mode(st), get_type_mode(lt)))
+ return 0;
+ break;
+
+ default: break;
+ }
+ return 1;
+}
+
+
+ir_type *new_d_type_class(ident *name, type_dbg_info *db)
+{
+ ir_type *res;
+
+ res = new_type(type_class, NULL, db);
+ res->name = name;
+
+ res->attr.ca.members = NEW_ARR_F (ir_entity *, 0);
+ res->attr.ca.subtypes = NEW_ARR_F (ir_type *, 0);
+ res->attr.ca.supertypes = NEW_ARR_F (ir_type *, 0);
+ res->attr.ca.peculiarity = peculiarity_existent;
+ res->attr.ca.type_info = NULL;
+ res->attr.ca.vtable_size = 0;
+ res->attr.ca.clss_flags = cf_none;
+ res->attr.ca.dfn = 0;
+ hook_new_type(res);
+ return res;
+}
+
+ir_type *new_type_class(ident *name)
+{
+ return new_d_type_class (name, NULL);
+}
+
+void free_class_entities(ir_type *clss)
+{
+ int i;
+ assert(clss && (clss->type_op == type_class));
+ for (i = get_class_n_members(clss) - 1; i >= 0; --i)
+ free_entity(get_class_member(clss, i));
+ /* do NOT free the type info here. It belongs to another class */
+}
+
+void free_class_attrs(ir_type *clss)
+{
+ assert(clss && (clss->type_op == type_class));
+ DEL_ARR_F(clss->attr.ca.members);
+ DEL_ARR_F(clss->attr.ca.subtypes);
+ DEL_ARR_F(clss->attr.ca.supertypes);
+}
+
+ident *get_class_ident(const ir_type *clss)
+{
+ assert(clss->type_op == type_class);
+ return clss->name;
+}
+
+const char *get_class_name(const ir_type *clss)
+{
+ if (get_class_ident(clss) == NULL)
+ return NULL;
+ return get_id_str(get_class_ident(clss));
+}
+
+static void add_class_member(ir_type *clss, ir_entity *member)
+{
+ assert(clss && (clss->type_op == type_class));
+ assert(clss != get_entity_type(member) && "recursive type");
+ ARR_APP1 (ir_entity *, clss->attr.ca.members, member);
+}
+
+size_t (get_class_n_members)(const ir_type *clss)
+{
+ return _get_class_n_members(clss);
+}
+
+size_t get_class_member_index(const ir_type *clss, ir_entity *mem)
+{
+ size_t i, n;
+ assert(clss && (clss->type_op == type_class));
+ for (i = 0, n = get_class_n_members(clss); i < n; ++i) {
+ if (get_class_member(clss, i) == mem)
+ return i;
+ }
+ return (size_t)-1;
+}
+
+ir_entity *(get_class_member)(const ir_type *clss, size_t pos)
+{
+ return _get_class_member(clss, pos);
+}
+
+ir_entity *get_class_member_by_name(ir_type *clss, ident *name)
+{
+ int i, n_mem;
+ assert(clss && (clss->type_op == type_class));
+ n_mem = get_class_n_members(clss);
+ for (i = 0; i < n_mem; ++i) {
+ ir_entity *mem = get_class_member(clss, i);
+ if (get_entity_ident(mem) == name) return mem;
+ }
+ return NULL;
+}
+
+static void remove_class_member(ir_type *clss, ir_entity *member)
+{
+ size_t i;
+ assert(clss && (clss->type_op == type_class));
+ for (i = 0; i < ARR_LEN(clss->attr.ca.members); ++i) {
+ if (clss->attr.ca.members[i] == member) {
+ for (; i < ARR_LEN(clss->attr.ca.members) - 1; ++i)
+ clss->attr.ca.members[i] = clss->attr.ca.members[i + 1];
+ ARR_SETLEN(ir_entity*, clss->attr.ca.members, ARR_LEN(clss->attr.ca.members) - 1);
+ break;
+ }
+ }
+}
+
+void add_class_subtype(ir_type *clss, ir_type *subtype)
+{
+ size_t i;
+ assert(clss->type_op == type_class);
+ ARR_APP1 (ir_type *, clss->attr.ca.subtypes, subtype);
+ for (i = 0; i < get_class_n_supertypes(subtype); i++) {
+ if (get_class_supertype(subtype, i) == clss)
+ /* Class already registered */
+ return;
+ }
+ ARR_APP1(ir_type *, subtype->attr.ca.supertypes, clss);
+}
+
+size_t get_class_n_subtypes(const ir_type *clss)
+{
+ assert(clss->type_op == type_class);
+ return ARR_LEN (clss->attr.ca.subtypes);
+}
+
+ir_type *get_class_subtype(ir_type *clss, size_t pos)
+{
+ assert(clss->type_op == type_class);
+ assert(pos < get_class_n_subtypes(clss));
+ return clss->attr.ca.subtypes[pos];
+}
+
+size_t get_class_subtype_index(ir_type *clss, const ir_type *subclass)
+{
+ size_t i, n_subtypes = get_class_n_subtypes(clss);
+ assert(is_Class_type(subclass));
+ for (i = 0; i < n_subtypes; ++i) {
+ if (get_class_subtype(clss, i) == subclass)
+ return i;
+ }
+ return (size_t)-1;
+}
+
+void set_class_subtype(ir_type *clss, ir_type *subtype, size_t pos)
+{
+ assert(clss->type_op == type_class);
+ assert(pos < get_class_n_subtypes(clss));
+ clss->attr.ca.subtypes[pos] = subtype;
+}
+
+void remove_class_subtype(ir_type *clss, ir_type *subtype)
+{
+ size_t i;
+ assert(clss && (clss->type_op == type_class));
+ for (i = 0; i < ARR_LEN(clss->attr.ca.subtypes); ++i) {
+ if (clss->attr.ca.subtypes[i] == subtype) {
+ for (; i < ARR_LEN(clss->attr.ca.subtypes) - 1; ++i)
+ clss->attr.ca.subtypes[i] = clss->attr.ca.subtypes[i+1];
+ ARR_SETLEN(ir_type*, clss->attr.ca.subtypes, ARR_LEN(clss->attr.ca.subtypes) - 1);
+ break;
+ }
+ }
+}
+
+void add_class_supertype(ir_type *clss, ir_type *supertype)
+{
+ size_t i;
+ size_t n;
+ assert(clss && (clss->type_op == type_class));
+ assert(supertype && (supertype -> type_op == type_class));
+ ARR_APP1 (ir_type *, clss->attr.ca.supertypes, supertype);
+ for (i = 0, n = get_class_n_subtypes(supertype); i < n; ++i) {
+ if (get_class_subtype(supertype, i) == clss)
+ /* Class already registered */
+ return;
+ }
+ ARR_APP1(ir_type *, supertype->attr.ca.subtypes, clss);
+}
+
+size_t get_class_n_supertypes(const ir_type *clss)
+{
+ assert(clss->type_op == type_class);
+ return ARR_LEN(clss->attr.ca.supertypes);
+}
+
+size_t get_class_supertype_index(ir_type *clss, ir_type *super_clss)
+{
+ size_t i, n_supertypes = get_class_n_supertypes(clss);
+ assert(super_clss && (super_clss->type_op == type_class));
+ for (i = 0; i < n_supertypes; i++) {
+ if (get_class_supertype(clss, i) == super_clss)
+ return i;
+ }
+ return (size_t)-1;
+}
+
+ir_type *get_class_supertype(ir_type *clss, size_t pos)
+{
+ assert(clss->type_op == type_class);
+ assert(pos < get_class_n_supertypes(clss));
+ return clss->attr.ca.supertypes[pos];
+}
+
+void set_class_supertype(ir_type *clss, ir_type *supertype, size_t pos)
+{
+ assert(clss->type_op == type_class);
+ assert(pos < get_class_n_supertypes(clss));
+ clss->attr.ca.supertypes[pos] = supertype;
+}
+
+void remove_class_supertype(ir_type *clss, ir_type *supertype)
+{
+ size_t i;
+ assert(clss && (clss->type_op == type_class));
+ for (i = 0; i < ARR_LEN(clss->attr.ca.supertypes); ++i) {
+ if (clss->attr.ca.supertypes[i] == supertype) {
+ for (; i < ARR_LEN(clss->attr.ca.supertypes) - 1; ++i)
+ clss->attr.ca.supertypes[i] = clss->attr.ca.supertypes[i+1];
+ ARR_SETLEN(ir_type*, clss->attr.ca.supertypes, ARR_LEN(clss->attr.ca.supertypes) - 1);
+ break;
+ }
+ }
+}
+
+ir_entity *get_class_type_info(const ir_type *clss)
+{
+ return clss->attr.ca.type_info;
+}
+
+void set_class_type_info(ir_type *clss, ir_entity *ent)
+{
+ clss->attr.ca.type_info = ent;
+ if (ent)
+ ent->repr_class = clss;
+}
+
+ir_peculiarity get_class_peculiarity(const ir_type *clss)
+{
+ assert(clss && (clss->type_op == type_class));
+ return clss->attr.ca.peculiarity;
+}
+
+void set_class_peculiarity(ir_type *clss, ir_peculiarity pec)
+{
+ assert(clss && (clss->type_op == type_class));
+ assert(pec != peculiarity_inherited); /* There is no inheritance of types in libFirm. */
+ clss->attr.ca.peculiarity = pec;
+}
+
+unsigned (get_class_vtable_size)(const ir_type *clss)
+{
+ return _get_class_vtable_size(clss);
+}
+
+void (set_class_vtable_size)(ir_type *clss, unsigned size)
+{
+ _set_class_vtable_size(clss, size);
+}
+
+int (is_class_final)(const ir_type *clss)
+{
+ return _is_class_final(clss);
+}
+
+void (set_class_final)(ir_type *clss, int flag)
+{
+ _set_class_final(clss, flag);
+}
+
+int (is_class_interface)(const ir_type *clss)
+{
+ return _is_class_interface(clss);
+}
+
+void (set_class_interface)(ir_type *clss, int flag)
+{
+ _set_class_interface(clss, flag);
+}
+
+int (is_class_abstract)(const ir_type *clss)
+{
+ return _is_class_abstract(clss);
+}
+
+void (set_class_abstract)(ir_type *clss, int final)
+{
+ _set_class_abstract(clss, final);
+}
+
+void set_class_dfn(ir_type *clss, int dfn)
+{
+ clss->attr.ca.dfn = dfn;
+}
+
+int get_class_dfn(const ir_type *clss)
+{
+ return (clss->attr.ca.dfn);
+}
+
+int (is_Class_type)(const ir_type *clss)
+{
+ return _is_class_type(clss);
+}
+
+void set_class_mode(ir_type *tp, ir_mode *mode)
+{
+ /* for classes and structs we allow to set a mode if the layout is fixed AND the size matches */
+ assert(get_type_state(tp) == layout_fixed &&
+ tp->size == get_mode_size_bytes(mode) && "mode don't match class layout");
+ tp->mode = mode;
+}
+
+void set_class_size(ir_type *tp, unsigned size)
+{
+ tp->size = size;
+}
+
+
+ir_type *new_d_type_struct(ident *name, type_dbg_info *db)
+{
+ ir_type *res = new_type(type_struct, NULL, db);
+ res->name = name;
+
+ res->attr.sa.members = NEW_ARR_F(ir_entity *, 0);
+ hook_new_type(res);
+ return res;
+}
+
+ir_type *new_type_struct(ident *name)
+{
+ return new_d_type_struct (name, NULL);
+}
+
+void free_struct_entities(ir_type *strct)
+{
+ int i;
+ assert(strct && (strct->type_op == type_struct));
+ for (i = get_struct_n_members(strct)-1; i >= 0; --i)
+ free_entity(get_struct_member(strct, i));
+}