+static void map_to_void(stabs_handle *h, ir_type *tp) {
+ pmap_insert(h->type_map, tp, INT_TO_PTR(0));
+}
+
+/**
+ * generate the void type.
+ */
+static void gen_void_type(stabs_handle *h) {
+ (void) h;
+ be_emit_irprintf("\t.stabs\t\"void:t%u=%u\",%d,0,0,0\n", 0, 0, N_LSYM);
+ be_emit_write_line();
+} /* gen_void_type */
+
+typedef struct walker_env {
+ stabs_handle *h;
+ waitq *wq;
+} wenv_t;
+
+/* a type is not ready: put it on the wait queue */
+#define SET_TYPE_NOT_READY(wq, tp) \
+ do { \
+ set_type_link(tp, (void *)1); \
+ waitq_put(wq, tp); \
+ } while(0)
+
+/* a the is ready */
+#define SET_TYPE_READY(tp) set_type_link(tp, NULL)
+
+/* check whether a type is ready */
+#define IS_TYPE_READY(tp) (get_type_link(tp) == NULL)
+
+#ifdef EXPLICITE_PTR_TYPES
+#define SKIP_PTR(tp) tp
+#else
+#define SKIP_PTR(tp) (is_Pointer_type(tp) ? get_pointer_points_to_type(tp) : tp)
+#endif
+
+/**
+ * mode_info for output as decimal
+ */
+static const tarval_mode_info dec_output = {
+ TVO_DECIMAL,
+ NULL,
+ NULL,
+};
+
+/**
+ * emit a tarval as decimal
+ */
+static void be_emit_tv_as_decimal(tarval *tv) {
+ ir_mode *mode = get_tarval_mode(tv);
+ const tarval_mode_info *old = get_tarval_mode_output_option(mode);
+
+ set_tarval_mode_output_option(mode, &dec_output);
+ be_emit_tarval(tv);
+ set_tarval_mode_output_option(mode, old);
+}
+
+/**
+ * Generates a primitive type.
+ *
+ * @param h the stabs handle
+ * @param tp the type
+ */
+static void gen_primitive_type(stabs_handle *h, ir_type *tp) {
+ ir_mode *mode = get_type_mode(tp);
+ unsigned type_num;
+
+ SET_TYPE_READY(tp);
+ if (mode == mode_T) {
+ /* firmcc, jack and the FirmJC compiler use mode_T for the void type.
+ Ignore it here as it's name is remapped to "void". */
+ map_to_void(h, tp);
+ return;
+ } /* if */
+
+ if (0 && get_mode_size_bits(mode) & 7) {
+ /* this is a bitfield type, ignore it */
+ return;
+ } /* if */
+
+ type_num = get_type_number(h, tp);
+
+ if (mode_is_int(mode)) {
+ be_emit_irprintf("\t.stabs\t\"%s:t%u=r%u;", get_type_name(tp), type_num, type_num);
+ be_emit_tv_as_decimal(get_mode_min(mode));
+ be_emit_char(';');
+ be_emit_tv_as_decimal(get_mode_max(mode));
+ be_emit_irprintf(";\",%d,0,0,0\n", N_LSYM);
+ be_emit_write_line();
+ } else if (mode_is_float(mode)) {
+ int size = get_type_size_bytes(tp);
+ be_emit_irprintf("\t.stabs\t\"%s:t%u=r1;%d;0;\",%d,0,0,0\n", get_type_name(tp), type_num, size, N_LSYM);
+ be_emit_write_line();
+ }
+} /* gen_primitive_type */
+
+/**
+ * Generates an enum type
+ *
+ * @param h the stabs handle
+ * @param tp the type
+ */
+static void gen_enum_type(stabs_handle *h, ir_type *tp) {
+ unsigned type_num = get_type_number(h, tp);
+ int i, n;
+
+ SET_TYPE_READY(tp);
+ be_emit_irprintf("\t.stabs\t\"%s:T%u=e", get_type_name(tp), type_num);
+ for (i = 0, n = get_enumeration_n_enums(tp); i < n; ++i) {
+ ir_enum_const *ec = get_enumeration_const(tp, i);
+ char buf[64];
+
+ tarval_snprintf(buf, sizeof(buf), get_enumeration_value(ec));
+ be_emit_irprintf("%s:%s,", get_enumeration_name(ec), buf);
+ }
+ be_emit_irprintf(";\",%d,0,0,0\n", N_LSYM);
+ be_emit_write_line();
+} /* gen_enum_type */
+
+/**
+ * print a pointer type
+ */
+void print_pointer_type(stabs_handle *h, ir_type *tp, int local) {
+ unsigned type_num = local ? h->next_type_nr++ : get_type_number(h, tp);
+ ir_type *el_tp = get_pointer_points_to_type(tp);
+ unsigned el_num = get_type_number(h, el_tp);
+
+ be_emit_irprintf("%u=*%u", type_num, el_num);
+}
+
+/**
+ * Generates a pointer type
+ *
+ * @param env the walker environment
+ * @param tp the type
+ */
+static void gen_pointer_type(wenv_t *env, ir_type *tp) {
+ stabs_handle *h = env->h;
+ ir_type *el_tp = get_pointer_points_to_type(tp);
+
+ SET_TYPE_READY(tp);
+ if (! IS_TYPE_READY(el_tp))
+ waitq_put(env->wq, el_tp);
+
+ be_emit_irprintf("\t.stabs\t\"%s:t", get_type_name(tp));
+ print_pointer_type(h, tp, 0);
+ be_emit_irprintf("\",%d,0,0,0\n", N_LSYM);
+ be_emit_write_line();
+} /* gen_pointer_type */
+
+/**
+ * print an array type
+ */
+static void print_array_type(stabs_handle *h, ir_type *tp, int local) {
+ ir_type *etp = get_array_element_type(tp);
+ int i, n = get_array_n_dimensions(tp);
+ unsigned type_num = local ? h->next_type_nr++ : get_type_number(h, tp);
+ int *perm;
+
+ be_emit_irprintf("%u=a", type_num);
+ NEW_ARR_A(int, perm, n);
+ for (i = 0; i < n; ++i) {
+ perm[i] = get_array_order(tp, i);
+ }
+
+ for (i = 0; i < n; ++i) {
+ int dim = perm[i];
+
+ if (is_Const(get_array_lower_bound(tp, dim)) && is_Const(get_array_upper_bound(tp, dim))) {
+ long min = get_array_lower_bound_int(tp, dim);
+ long max = get_array_upper_bound_int(tp, dim);
+
+ /* FIXME r1 must be integer type, but seems to work for now */
+ be_emit_irprintf("r1;%ld;%ld;", min, max-1);
+ }
+ }
+
+ type_num = get_type_number(h, etp);
+ be_emit_irprintf("%d", type_num);
+}
+
+/**
+ * Generates an array type
+ *
+ * @param env the walker environment
+ * @param tp the type
+ */
+static void gen_array_type(wenv_t *env, ir_type *tp) {
+ stabs_handle *h = env->h;
+ ir_type *etp = get_array_element_type(tp);
+
+ SET_TYPE_READY(tp);
+ if (! IS_TYPE_READY(etp))
+ waitq_put(env->wq, etp);
+
+ be_emit_irprintf("\t.stabs\t\"%s:t", get_type_name(tp));
+
+ print_array_type(h, tp, 0);
+
+ be_emit_irprintf("\",%d,0,0,0\n", N_LSYM);
+ be_emit_write_line();
+} /* gen_array_type */
+
+/**
+ * Generates a struct/union type
+ *
+ * @param env the walker environment
+ * @param tp the type
+ */
+static void gen_struct_union_type(wenv_t *env, ir_type *tp) {
+ stabs_handle *h = env->h;
+ unsigned type_num = get_type_number(h, tp);
+ int i, n;
+ char desc = 's';
+
+ SET_TYPE_READY(tp);
+ if (is_Struct_type(tp)) {
+ desc = 's';
+ if (get_type_mode(tp) != NULL) {
+ /* this is a bitfield type, ignore it safely */
+ return;
+ }
+ }
+ else if (is_Union_type(tp))
+ desc = 'u';
+
+ be_emit_irprintf("\t.stabs\t\"%s:Tt%u=%c%d",
+ get_type_name(tp), type_num, desc, get_type_size_bytes(tp));
+
+ for (i = 0, n = get_compound_n_members(tp); i < n; ++i) {
+ ir_entity *ent = get_compound_member(tp, i);
+ ir_type *mtp = get_entity_type(ent);
+ int ofs;
+ unsigned size;
+
+ if (! IS_TYPE_READY(mtp))
+ waitq_put(env->wq, mtp);
+ ofs = get_entity_offset(ent);
+ if (is_Struct_type(mtp) && get_type_mode(mtp) != NULL) {
+ /* this structure is a bitfield, skip */
+ int i, n;
+
+ for (i = 0, n = get_struct_n_members(mtp); i < n; ++i) {
+ ir_entity *ent = get_struct_member(mtp, i);
+ ir_type *tp = get_entity_type(ent);
+ int bofs;
+
+ type_num = get_type_number(h, tp);
+ size = get_type_size_bytes(tp) * 8;
+ bofs = (ofs + get_entity_offset(ent)) * 8 + get_entity_offset_bits_remainder(ent);
+
+ /* name:type, bit offset from the start of the struct', number of bits in the element. */
+ be_emit_irprintf("%s:%u,%d,%u;", get_entity_name(ent), type_num, bofs, size);
+ }
+ } else {
+ /* no bitfield */
+ be_emit_irprintf("%s:", get_entity_name(ent));
+
+ if (is_Array_type(mtp)) {
+ /* use a local array definition */
+ print_array_type(h, mtp, 1);
+ } else if (is_Pointer_type(mtp)) {
+ /* use local pointer definition */
+ print_pointer_type(h, mtp, 1);
+ } else {
+ type_num = get_type_number(h, mtp);
+
+ /* name:type, bit offset from the start of the struct', number of bits in the element. */
+ be_emit_irprintf("%u", type_num);
+ }
+ size = get_type_size_bytes(mtp) * 8;
+ be_emit_irprintf(",%d,%u;", ofs * 8, size);
+ }
+ }
+ be_emit_irprintf(";\",%d,0,0,0\n", N_LSYM);
+ be_emit_write_line();
+} /* gen_struct_type */
+
+/**
+ * Generates a method type
+ *
+ * @param env the walker environment
+ * @param tp the type
+ */
+static void gen_method_type(wenv_t *env, ir_type *tp) {
+ stabs_handle *h = env->h;
+ unsigned type_num = get_type_number(h, tp);
+ ir_type *rtp = NULL;
+ unsigned res_type_num;
+ int i, n = get_method_n_ress(tp);
+
+ SET_TYPE_READY(tp);
+ if (n > 0) {
+ rtp = get_method_res_type(tp, 0);
+ if (! IS_TYPE_READY(rtp))
+ waitq_put(env->wq, rtp);
+ }
+ res_type_num = get_type_number(h, rtp);
+
+ be_emit_irprintf("\t.stabs\t\"%s:t%u=f%u", get_type_name(tp), type_num, res_type_num);
+
+ /* handle more than one return type */
+ for (i = 1; i < n; ++i) {
+ rtp = get_method_res_type(tp, i);
+ if (! IS_TYPE_READY(rtp))
+ waitq_put(env->wq, rtp);
+ res_type_num = get_type_number(h, rtp);
+ be_emit_irprintf(",%u", res_type_num);
+ }
+ be_emit_irprintf("\",%d,0,0,0\n", N_LSYM);
+ be_emit_write_line();
+} /* gen_method_type */