Added be arch reflection/backend support infrastructure.
authorSebastian Hack <hack@ipd.info.uni-karlsruhe.de>
Mon, 14 Mar 2005 11:26:22 +0000 (11:26 +0000)
committerSebastian Hack <hack@ipd.info.uni-karlsruhe.de>
Mon, 14 Mar 2005 11:26:22 +0000 (11:26 +0000)
ir/be/Makefile.in
ir/be/bearch.c [new file with mode: 0644]
ir/be/bearch.h [new file with mode: 0644]
ir/be/bearch_obj.def [new file with mode: 0644]
ir/be/bearch_t.h [new file with mode: 0644]
ir/be/bechordal.c
ir/be/belistsched.c
ir/be/belistsched.h
ir/be/bemain.c
ir/be/besched.c

index 6ffc755..f3aa6c3 100644 (file)
@@ -23,7 +23,7 @@ SOURCES +=    Makefile.in besched.h belistsched.h belistsched.c \
        beutil.h bemain.c besched.c bemain.c belive.c belive.h benumb.h \
        benumb_t.h benumb.c bechordal.c bera.c beutil.c phistat.c \
        bephiopt.c bephicoal.c bera.h bechordalspill.c \
-       beasm_dump_globals.c beasm_asm_gnu.c
+       beasm_dump_globals.c beasm_asm_gnu.c bearch.h bearch.c
 
 include $(topdir)/MakeRules
 
diff --git a/ir/be/bearch.c b/ir/be/bearch.c
new file mode 100644 (file)
index 0000000..7aa7b55
--- /dev/null
@@ -0,0 +1,281 @@
+/**
+ * Processor architecture specification.
+ * @author Sebastian Hack
+ * @date 11.2.2005
+ *
+ * $Id$
+ */
+
+#include "bearch_t.h"
+
+#include "firm_config.h"
+#include "set.h"
+
+#include "entity.h"
+#include "ircons_t.h"
+
+#if 1 /* HAVE_ALLOCA_H */
+#include <alloca.h>
+#endif /* HAVE_ALLOCA_H */
+
+#define INIT_HEADER(tgt, kind_suffix, a_isa, str) \
+       do { \
+               arch_header_t *h = (arch_header_t *) (tgt); \
+               memset(tgt, 0, sizeof(*(tgt))); \
+               h->kind = arch_kind_ ## kind_suffix; \
+               h->name = new_id_from_str(str); \
+               h->isa = a_isa; \
+       } while(0)
+
+static INLINE int hash_header(const arch_header_t *header)
+{
+       int res = HASH_PTR(header->isa);
+       res = 37 * res + HASH_STR(header->name, strlen(header->name));
+       res = 37 * res + header->kind;
+       return res;
+}
+
+static int cmp_header(const void *a, const void *b, size_t size)
+{
+       const arch_header_t *h1 = a;
+       const arch_header_t *h2 = b;
+
+       return !(h1->kind == h2->kind && strcmp(h1->name, h2->name) == 0);
+}
+
+static set *arch_data = NULL;
+
+static set *get_arch_data(void)
+{
+       if(!arch_data)
+               arch_data = new_set(cmp_header, 256);
+
+       return arch_data;
+}
+
+typedef struct _obj_info_t {
+       const char *name;
+       int listed_in_isa;
+       size_t size;
+} obj_info_t;
+
+static const obj_info_t obj_info[] = {
+#define ARCH_OBJ(name,listed_in_isa)           { #name, listed_in_isa, sizeof(arch_ ## name ## _t) },
+#include "bearch_obj.def"
+#undef ARCH_OBJ
+       { 0 }
+};
+
+/**
+ * Insert an arch object to the global arch obj storage.
+ *
+ * If the object has already been created there, nothing is done and
+ * the old object is created.
+ *
+ * @param kind The kind of the arch object.
+ * @param isa The isa the object belongs to or NULL if it is the isa
+ * itself.
+ * @param name The name of the object.
+ * @param was_new A pointer to an int where 1/0 is stored if the
+ * object was created or already present. If NULL, it is simply ignored.
+ * @return A pointer to the object.
+ */
+static INLINE void *_arch_data_insert(arch_kind_t kind, arch_isa_t *isa,
+               const char *name, size_t size, int *was_new)
+{
+       const obj_info_t *info = &obj_info[kind];
+       arch_header_t *data = alloca(size);
+       arch_header_t *res = NULL;
+
+       memset(data, 0, size);
+       data->kind = kind;
+       data->isa = isa;
+       data->name = get_id_str(new_id_from_str(name));
+       data->is_new = 1;
+
+       res = set_insert(get_arch_data(), data, size, hash_header(data));
+
+       /* If the object is newly created and thus not yet present
+        * in the set, add it to the isa */
+       if(res->is_new) {
+
+               /*
+                * The inserted object was no isa, list it in the isa if this is
+                * desired.
+                */
+               if(isa && info->listed_in_isa)
+                       list_add(&res->list, &isa->heads[kind]);
+
+               /* The inserted object is an isa, so initialize all its list heads. */
+               else {
+                       int i;
+                       arch_isa_t *isa = (arch_isa_t *) res;
+
+                       for(i = 0; i < arch_kind_last; ++i)
+                               INIT_LIST_HEAD(&isa->heads[i]);
+               }
+       }
+
+       /*
+        * If the caller wants to know, of the object was newly created,
+        * give it to him.
+        */
+       if(was_new)
+               *was_new = res->is_new;
+
+       /* Mark the object as NOT new. */
+       res->is_new = 0;
+
+       return res;
+}
+
+#define arch_data_insert(type_suffix, isa, name, was_new) \
+       _arch_data_insert(arch_kind_ ## type_suffix, isa, name, sizeof(arch_ ## type_suffix ## _t), was_new)
+
+static INLINE void *_arch_data_find(arch_kind_t kind, const arch_isa_t *isa, const char *name)
+{
+       arch_header_t header;
+
+       memset(&header, 0, sizeof(header));
+       header.kind = kind;
+       header.isa = (arch_isa_t *) isa;
+       header.name = name;
+
+       return set_find(get_arch_data(), &header, sizeof(header), hash_header(&header));
+}
+
+#define arch_data_find(type_suffix, isa, name) \
+       _arch_data_find(arch_kind_ ## type_suffix, isa, name)
+
+arch_isa_t *arch_add_isa(const char *name)
+{
+       return arch_data_insert(isa, NULL, name, NULL);
+}
+
+arch_register_class_t *arch_add_register_class(arch_isa_t *isa, const char *name, int n_regs)
+{
+       arch_register_class_t *cls =
+               _arch_data_insert(arch_kind_register_class, isa, name,
+                               sizeof(arch_register_class_t) + n_regs * sizeof(arch_register_t *), NULL);
+
+       cls->n_regs = n_regs;
+
+       return cls;
+}
+
+arch_register_t *arch_add_register(arch_register_class_t *cls, int index, const char *name)
+{
+       arch_register_t *reg = NULL;
+
+       assert(index >= 0 && index < cls->n_regs);
+       reg = _arch_data_insert(arch_kind_register, arch_obj_get_isa(cls), name,
+                       sizeof(arch_register_t), NULL);
+       cls->regs[index] = reg;
+
+       reg->index = index;
+       reg->reg_class = cls;
+       reg->flags = arch_register_flag_none;
+
+       return reg;
+}
+
+arch_immediate_t *arch_add_immediate(arch_isa_t *isa, const char *name, ir_mode *mode)
+{
+       arch_immediate_t *imm = arch_data_insert(immediate, isa, name, NULL);
+       imm->mode = mode;
+       return imm;
+}
+
+static const size_t operand_sizes[] = {
+       0,
+       0,
+       sizeof(entity *),
+       sizeof(arch_register_t *),
+       sizeof(tarval *)
+};
+
+arch_insn_format_t *arch_add_insn_format(arch_isa_t *isa, const char *name, int n_in, int n_out)
+{
+       int i;
+
+       arch_insn_format_t *fmt =
+               _arch_data_insert(arch_kind_insn_format, isa, name,
+                               sizeof(arch_insn_format_t) + (n_in + n_out) * sizeof(arch_operand_type_t), NULL);
+
+       fmt->n_in = n_in;
+       fmt->n_out = n_out;
+       fmt->irn_data_size = 0;
+
+       /*
+        * Compute the number of bytes which must be extra allocated if this
+        * opcode is instantiated.
+        */
+       for(i = 0; i < fmt->n_in; ++i) {
+               arch_operand_t *op = arch_get_in_operand(fmt, i);
+               op->offset_in_irn_data = fmt->irn_data_size;
+               fmt->irn_data_size += operand_sizes[op->type];
+       }
+
+       if(fmt->n_out == 1) {
+               arch_operand_t *op = arch_get_in_operand(fmt, i);
+               op->offset_in_irn_data = fmt->irn_data_size;
+               fmt->irn_data_size += operand_sizes[op->type];
+       }
+
+       return fmt;
+}
+
+arch_insn_t *arch_add_insn(arch_insn_format_t *fmt, const char *name)
+{
+       /* Insert the insn into the isa. */
+       arch_insn_t *insn = arch_data_insert(insn, arch_obj_get_isa(fmt), name, NULL);
+
+       insn->format = fmt;
+       insn->op = new_ir_op(get_next_ir_opcode(), name, op_pin_state_pinned, 0,
+                       oparity_dynamic, 0, sizeof(arch_irn_data_t) + fmt->irn_data_size);
+
+       return insn;
+}
+
+arch_insn_format_t *arch_find_insn_format(arch_isa_t *isa, const char *name)
+{
+       return arch_data_find(insn_format, isa, name);
+}
+
+arch_isa_t *arch_find_isa(const char *name)
+{
+       return arch_data_find(isa, NULL, name);
+}
+
+arch_register_class_t *arch_find_register_class_t(arch_isa_t *isa, const char *name)
+{
+       return arch_data_find(register_class, isa, name);
+}
+
+arch_register_set_t *arch_get_register_set_for_class(arch_register_class_t *cls)
+{
+       return _arch_get_register_set_for_class(cls);
+}
+
+ir_node *arch_new_node(const arch_insn_t *insn, ir_graph *irg, ir_node *block,
+               ir_mode *mode, int arity, ir_node **in)
+{
+       ir_node *irn = new_ir_node(NULL, irg, block, insn->op, mode, arity, in);
+       arch_irn_data_t *data = (void *) &irn->attr;
+
+       data->magic = ARCH_IRN_FOURCC;
+       data->insn = insn;
+
+       return irn;
+}
+
+ir_node *arch_new_node_bare(const arch_insn_t *insn, ir_graph *irg, int arity)
+{
+       int i;
+       ir_node **in = alloca(sizeof(in[0]) * arity);
+
+       for(i = 0; i < arity; ++i)
+               in[i] = new_Unknown(mode_Is);
+
+       return arch_new_node(insn, irg, new_Unknown(mode_BB), mode_Is, arity, in);
+}
diff --git a/ir/be/bearch.h b/ir/be/bearch.h
new file mode 100644 (file)
index 0000000..743002c
--- /dev/null
@@ -0,0 +1,130 @@
+
+#ifndef _FIRM_BEARCH_H
+#define _FIRM_BEARCH_H
+
+#include "bitset.h"
+
+/*
+ * Define the types of the arch facility.
+ * All arch object names are stored in bearch_obj.def
+ */
+#define ARCH_OBJ(x,list) typedef struct _arch_ ## x ## _t arch_ ## x ## _t;
+#include "bearch_obj.def"
+#undef ARCH_OBJ
+
+/**
+ * A callback to determine the set of valid registers.
+ *
+ * @param irn                          The node which represents an instance of the instruction.
+ * @param pos                          The number of the insn's operand to consider.
+ * @param valid_regs   A bitset where all valid registers are put.
+ */
+typedef void (arch_register_callback_t)(ir_node *irn, int pos, bitset_t *valid_regs);
+
+
+/**
+ * Add a new instruction set architecture.
+ * @param name The name of the isa.
+ * @return The isa object.
+ */
+arch_isa_t *arch_add_isa(const char *name);
+
+/**
+ * Add a register class to the isa.
+ * @param isa The isa to add the reg class to.
+ * @param name The name of the register class.
+ * @param n_regs The number of registers in that class.
+ * @param mode The mode of the registers in that class.
+ */
+arch_register_class_t *arch_add_register_class(arch_isa_t *isa, const char *name, int n_regs);
+
+/**
+ * Add a register to a register class.
+ * @param cls The register class.
+ * @param index The index of the register (its number within the
+ * class).
+ * @param name The name of the register.
+ * @return The register.
+ */
+arch_register_t *arch_add_register(arch_register_class_t *cls, int index, const char *name);
+
+/**
+ * Add an immediate to the instruction set architecture.
+ * @param isa The isa.
+ * @param name The name of the immediate.
+ * @param mode The mode of the immediate.
+ * @return The immediate.
+ */
+arch_immediate_t *arch_add_immediate(arch_isa_t *isa, const char *name, ir_mode *mode);
+
+/**
+ * Add an instruction format to an isa.
+ * @param isa The isa.
+ * @param name The name of the instruction format.
+ * @param n_in The number of in operands.
+ * @param n_out The number of out operands.
+ * @return The format.
+ */
+arch_insn_format_t *arch_add_insn_format(arch_isa_t *isa, const char *name, int n_in, int n_out);
+
+/**
+ * Add a register set as an operand type.
+ * @param fmt The instruction format whose operand is to be set.
+ * @param pos The position of the operand. Note that input operands are
+ * numbered from 0 to n and output operands from -1 to -m.
+ * @param set The register set.
+ * @return The corresponding operand type.
+ */
+arch_operand_t *arch_add_operand_register_set(arch_insn_format_t *fmt,
+               int pos, const arch_register_set_t *set);
+
+arch_operand_t *arch_add_operand_callback(arch_insn_format_t *fmt,
+               int pos, arch_register_callback_t *cb);
+
+arch_operand_t *arch_add_operand_immediate(arch_insn_format_t *fmt,
+               int pos, const arch_immediate_t *imm);
+
+/**
+ * Add an instruction to the isa.
+ * @param fmt The instructon format.
+ * @param name The name of the instruction.
+ */
+arch_insn_t *arch_add_insn(arch_insn_format_t *fmt, const char *name);
+
+
+/**
+ * Find an instruction format.
+ * @param isa The isa.
+ * @param name The name of the instruction format.
+ * @return The instruction format, if it was added before, or NULL if it
+ * is unknown.
+ */
+arch_insn_format_t *arch_find_insn_format(arch_isa_t *isa, const char *name);
+
+/**
+ * Find an isa.
+ * @param name The name of the isa.
+ * @return The isa if it has been added, or NULl if it is unknwon.
+ */
+arch_isa_t *arch_find_isa(const char *name);
+
+/**
+ * Find a register class of an isa.
+ * @param isa The isa.
+ * @param name The name of the register class.
+ * @return The register class, if it has been added, NULL if it is
+ * unknown.
+ */
+arch_register_class_t *arch_find_register_class(arch_isa_t *isa, const char *name);
+
+/**
+ * Get the register set for a register class.
+ * Each register class possesses a set containing all registers known in
+ * the class.
+ * @param cls The class.
+ * @return The register set for the register class.
+ */
+arch_register_set_t *arch_get_register_set_for_class(arch_register_class_t *cls);
+
+
+#endif
diff --git a/ir/be/bearch_obj.def b/ir/be/bearch_obj.def
new file mode 100644 (file)
index 0000000..6b55d9a
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+        The fields have following meaning:
+
+        1) Name of the object. This used to ## it to some pre- or suffix.
+        2) Boolean flag. If 1, the object shall be listed in a list whose
+                       head is in the isa. This is useful, since we can generically
+                       create lists of register classes, formats and so on.
+
+*/
+
+ARCH_OBJ(enum,                                         1)
+ARCH_OBJ(enum_member,                  0)
+ARCH_OBJ(register,                             0)
+ARCH_OBJ(register_class,       1)
+ARCH_OBJ(register_set,         1)
+ARCH_OBJ(immediate,                            0)
+ARCH_OBJ(operand,                                      0)
+ARCH_OBJ(insn_format,                  1)
+ARCH_OBJ(insn,                                         0)
+ARCH_OBJ(isa,                                                  0)
diff --git a/ir/be/bearch_t.h b/ir/be/bearch_t.h
new file mode 100644 (file)
index 0000000..383879a
--- /dev/null
@@ -0,0 +1,274 @@
+
+#ifndef _FIRM_BEARCH_T_H
+#define _FIRM_BEARCH_T_H
+
+#include "firm_config.h"
+
+#include "irop_t.h"
+#include "irnode_t.h"
+#include "irmode_t.h"
+
+#include "hashptr.h"
+#include "fourcc.h"
+#include "set.h"
+#include "list.h"
+#include "ident.h"
+
+#include "bearch.h"
+
+#define ARCH_IRN_FOURCC                FOURCC('A', 'R', 'C', 'H')
+
+/**
+ * Flags for registers.
+ */
+enum {
+
+       /**
+        * The register is invariant concerning writes.
+        * Examples are the 0 registers in RISC architectures.
+        */
+       REG_WRITE_INVARIAT                              = 1
+
+} arch_register_flags_t;
+
+typedef enum {
+#define ARCH_OBJ(x,list)       arch_kind_##x,
+#include "bearch_obj.def"
+#undef ARCH_OBJ
+       arch_kind_last
+} arch_kind_t;
+
+/**
+ * A header which each of the arch structs should posess.
+ */
+typedef struct {
+       arch_kind_t kind;
+       arch_isa_t *isa;
+       const char *name;
+       struct list_head list;
+       unsigned is_new : 1;
+} arch_header_t;
+
+
+/**
+ * Get the architecture an arch object belongs to.
+ * @param obj The object.
+ * @return The architecture it belongs to.
+ */
+static INLINE arch_isa_t *arch_obj_get_isa(const void *obj)
+{
+       return ((const arch_header_t *) obj)->isa;
+}
+
+typedef enum _arch_register_flag_t {
+       arch_register_flag_none,
+       arch_register_flag_caller_saved,                                                /**< The register must be saved by the caller
+                                                                                                                                                                                               upon a function call. It thus can be overwritten
+                                                                                                                                                                                               in the called function. */
+       arch_register_flag_callee_saved,                                                /**< The register must be saved by the called function,
+                                                                                                                                                                                               it thus survives a function call. */
+       arch_register_flag_ignore                                                                               /**< Do not consider this register when allocating. */
+} arch_register_flag_t;
+
+/**
+ * A register.
+ */
+struct _arch_register_t {
+       arch_header_t header;
+       int index;                                                                                                                              /**< The index of the register in the class. */
+       const arch_register_class_t *reg_class;         /**< The class the register belongs to. */
+       arch_register_flag_t flags;                                                             /**< Flags describing several properties of
+                                                                                                                                                                                       the register. */
+};
+
+/**
+ * A (sub-) set of registers.
+ */
+struct _arch_register_set_t {
+       arch_header_t header;
+       const struct _arch_register_class_t *reg_class;         /**< The register class for this set. */
+       unsigned comprises_full_class : 1;                                                              /**< True, if all registers of the class
+                                                                                                                                                                                                                       are contained in this set. */
+       int regs[1];                                                                                                                                                    /**< An array containing 0/1 at place i
+                                                                                                                                                                                                                       whether the register with index i is
+                                                                                                                                                                                                                       in the set or not. */
+};
+
+static INLINE int _arch_register_in_set(const arch_register_set_t *set, const arch_register_t *reg)
+{
+       if(reg->reg_class != set->reg_class)
+               return 0;
+
+       return set->regs[reg->index];
+}
+
+
+/**
+ * A class of registers.
+ * Like general purpose or floating point.
+ */
+struct _arch_register_class_t {
+       arch_header_t header;
+       struct list_head list;          /**< list head to list up in the list of all
+                                                                                                                       register classes in an isa. */
+       arch_register_set_t *set; /**< A register set containing all registers
+                                                                                                                       in this class. */
+       int n_regs;                                                             /**< Number of registers in this class. */
+       arch_register_t *regs[1]; /**< The array of registers. */
+};
+
+static INLINE const arch_register_t *_arch_register_for_index(const arch_register_class_t *cls, int idx)
+{
+       assert(0 <= idx && idx <= cls->n_regs);
+       return cls->regs[idx];
+}
+
+/**
+ * Get the register set for a register class.
+ * @param cls The register class.
+ * @return The set containing all registers in the class.
+ */
+static INLINE arch_register_set_t *_arch_get_register_set_for_class(const arch_register_class_t *cls)
+{
+       return cls->set;
+}
+
+/**
+ * An immediate.
+ */
+struct _arch_immediate_t {
+       arch_header_t header;
+       ir_mode *mode;                                          /**< The mode of the immediate. */
+};
+
+/**
+ * The member of an enum.
+ */
+struct _arch_enum_member_t {
+       arch_header_t header;                   /**< The omnipresent header. */
+       arch_enum_t *enm;                                       /**< The enum, this member belongs to. */
+};
+
+/**
+ * An enumeration operand type.
+ *
+ * Enumeration operand types can be used to describe the variants
+ * of an instruction, like giving the cases for a compare (gt, lt,
+ * eq, ...) some other special attributes of an instruction.
+ */
+struct _arch_enum_t {
+       arch_header_t header;
+       int n_members;                                                                          /**< The number of members in this enum. */
+       arch_enum_member_t *members[1];         /**< The array of members. */
+};
+
+typedef enum _arch_operand_type_t {
+       arch_operand_type_ir = 0,
+       arch_operand_type_variadic,
+       arch_operand_type_symconst,
+       arch_operand_type_register_set,
+       arch_operand_type_immediate
+} arch_operand_type_t;
+
+
+
+/**
+ * The data for the different flavours of operand types.
+ */
+typedef union _arch_operand_data_t {
+       arch_register_callback_t *callback;                             /**< The set of valid registers is determined
+                                                                                                                                                                                       by a callback function. */
+
+       const arch_register_set_t *set;                                         /**< The set of valid registers is directly
+                                                                                                                                                                                       given. Note, that if an insn has no constraints,
+                                                                                                                                                                                       the set comprises all registers in the
+                                                                                                                                                                                       register class. */
+
+       const arch_immediate_t *imm;                                                    /**< If the operand is an immediate
+                                                                                                                                                                                       operand, this describes the kind of
+                                                                                                                                                                                       immediate. */
+
+       const arch_enum_t *enm;                                                                         /**< Some enumeration value. */
+} arch_operand_data_t;
+
+/**
+ * An operand to an instruction.
+ */
+struct _arch_operand_t {
+       int offset_in_irn_data;
+       arch_operand_type_t type;                                                                       /**< The type of the operand. */
+       arch_operand_data_t data;                                                                       /**< The payload. */
+};
+
+/**
+ * An instruction format.
+ */
+struct _arch_insn_format_t {
+       arch_header_t header;
+       int n_in;                                                                                                                                       /**< Number of in operands. */
+       int n_out;                                                                                                                              /**< Number of out operands. */
+       int irn_data_size;
+
+       arch_operand_t operands[1];     /**< Array with operands. */
+};
+
+#define arch_get_in_operand(fmt, index)                (&((fmt)->operands[(fmt)->n_out + (index)]))
+#define arch_get_out_operand(fmt, index)               (&((fmt)->operands[index]))
+
+/**
+ * An instruction.
+ */
+struct _arch_insn_t {
+       arch_header_t header;
+       const arch_insn_format_t *format;                       /**< The format of the instruction. */
+       ir_op *op;                                                                                                              /**< The firm opcode for this insn. */
+};
+
+/**
+ * This truct is placed into each ir_node which is made from an arch
+ * insn (If the node is made via arch_new node).
+ */
+typedef struct _arch_irn_data_t {
+       unsigned magic;                                                                                         /**< A magic number to tell if node is an
+                                                                                                                                                                       arch node. */
+       const arch_insn_t *insn;                                                        /**< The insn this nodes instantiates. */
+} arch_irn_data_t;
+
+#define _arch_get_irn_data(irn) ((const arch_irn_data_t *) &((irn)->attr))
+
+/**
+ * Check, if an ir node is made by the arch module.
+ * @param irn An ir node.
+ * @return 1 if the node was made via arch_new_node() or 0 otherwise.
+ */
+static INLINE int _arch_is_irn(const ir_node *irn)
+{
+       return _arch_get_irn_data(irn)->magic == ARCH_IRN_FOURCC;
+}
+
+static INLINE const arch_insn_t *_arch_irn_get_insn(const ir_node *irn)
+{
+       if(!_arch_is_irn(irn))
+               return NULL;
+
+       return _arch_get_irn_data(irn)->insn;
+}
+
+
+/**
+ * An instruction set architecture.
+ */
+struct _arch_isa_t {
+       arch_header_t header;
+       struct list_head heads[arch_kind_last];         /**< List heads to list objects created in the
+                                                                                                                                                                                       context of this isa. Note: some of the list heads
+                                                                                                                                                                                       remain unused. */
+};
+
+struct _arch_implementation_t {
+       const arch_isa_t *isa;
+       const char *name;
+};
+
+
+#endif /* _FIRM_BEARCH_T_H */
index c14d635..817a3b9 100644 (file)
 #include "belive_t.h"
 #include "bechordal_t.h"
 
-
-
 #undef DUMP_INTERVALS
 #undef DUMP_PRESSURE
 #define DUMP_IFG
 
 #define BUILD_GRAPH
 
-#ifdef USE_OLD_PHI_INTERFERENCE
-#undef BUILD_GRAPH
-#define BUILD_GRAPH
-#endif
-
 #ifdef DEBUG_libfirm
 #include "fourcc.h"
 
@@ -160,6 +153,114 @@ static void draw_interval_graphs(ir_node *block,
        }
 }
 
+#if 0
+typedef struct _tree_layout_info_t {
+       ir_node *block;
+       int is_child;
+       int child_slot;
+       unsigned x;
+       unsigned y;
+       int steps;
+} tree_layout_info_t;
+
+typedef struct _tree_layout_params_t {
+       int interval_dist;
+       int x_block_dist;
+       int y_block_dist;
+       int step_len;
+} tree_layout_params_t;
+
+static const tree_layout_params_t tree_layout_params = {
+       10, 20, 20, 5
+};
+
+static void dump_tree_collect(ir_node *block, void *env)
+{
+       ir_block *curr;
+       struct list_head *border_head;
+
+       int pre_num = get_Block_dom_tree_pre_num(block);
+       tree_layout_info_t *info = env;
+       tree_layout_info_t *i = &info[pre_num];
+
+       i->block = block;
+       i->child_slot = -1;
+       i->steps = list_empty(border_head) ? 0 : list_entry(border_head->prev, border_t, list)->step;
+       i->is_child = 1;
+
+       dominates_for_each(block, curr)
+               i->is_child = 0;
+}
+
+static void dump_tree_assign_x(ir_node *block, void *env)
+{
+       unsigned min_x = -1, max_x = 0;
+       int n_childs = 0;
+       ir_block *curr;
+
+       int pre_num = get_Block_dom_tree_pre_num(block);
+       tree_layout_info_t *info = env;
+       tree_layout_info_t *i = &info[pre_num];
+
+       if(i->is_child)
+               return;
+
+       dominates_for_each(block, curr) {
+               tree_layout_info_t *ci = &info[get_Block_dom_tree_pre_num(curr)];
+               max_x = MAX(max_x, ci->x);
+               min_x = MIN(min_x, ci->x);
+               n_childs++;
+       }
+
+       i->x = (max_x - mix_x) / n_childs;
+}
+
+static void dump_tree_assign_y(ir_node *block, void *env)
+{
+       unsigned min_x = -1, max_x = 0;
+       int n_childs = 0;
+       ir_block *curr;
+
+       int pre_num = get_Block_dom_tree_pre_num(block);
+       tree_layout_info_t *info = env;
+       tree_layout_info_t *i = &info[pre_num];
+       ir_block *idom = get_Block_idom(block);
+
+       i->y = 0;
+       if(idom) {
+               tree_layout_info_t *idom_info = &info[get_Block_dom_tree_pre_num(idom)];
+               i->y = idom_info->y + idom_info->steps * params->step_len + params->y_dist;
+       }
+}
+
+static void draw_block(ir_block *bl, void *env)
+{
+}
+
+static void dump_interval_tree(ir_graph *irg, const tree_layout_params_t *params)
+{
+       int i, slot;
+       int n_blocks = get_Block_dom_max_subtree_pre_num(get_irg_start_block(irg));
+       tree_layout_info_t *info = malloc(sizeof(info[0]) * n_blocks);
+
+       /* Fill the info array. */
+       dom_tree_walk_irg(irg, NULL, dump_tree_collect, info);
+
+       /* Assign the child slots. */
+       for(i = 0, slot = 0; i < n_blocks; ++i) {
+               tree_layout_info_t *i = &info[i];
+               if(i->is_child) {
+                       i->child_slot = slot++;
+                       i->x = i->child_slot * params->max_color * params->interval_dist + params->block_dist;
+               }
+       }
+
+       dom_tree_walk_irg(irg, NULL, dump_tree_assign_xy, info);
+
+       free(info);
+}
+#endif
+
 #ifdef BUILD_GRAPH
 
 typedef struct _if_edge_t {
@@ -204,21 +305,126 @@ static INLINE int are_connected(const env_t *env, int src, int tgt)
        return set_find(env->graph, &edge, sizeof(edge), IF_EDGE_HASH(&edge)) != NULL;
 }
 
-static void dump_ifg(set *edges, const char *filename)
+static void dump_ifg(ir_graph *irg, set *edges, const char *filename)
 {
+       static const char *colors[] = {
+               "coral",
+               "azure",
+               "bisque",
+               "aliceblue",
+               "blanchedalmond",
+               "deeppink",
+               "cornsilk",
+               "blueviolet",
+               "floralwhite",
+               "hotpink",
+               "gainsboro",
+               "indianred",
+               "cornflowerblue",
+               "ghostwhite",
+               "lightpink",
+               "palegoldenrod",
+               "darkslateblue",
+               "honeydew",
+               "ivory",
+               "lavender",
+               "mediumvioletred",
+               "indigo",
+               "lavenderblush",
+               "lemonchiffon",
+               "linen",
+               "pink",
+               "mintcream",
+               "red",
+               "mediumblue",
+               "mistyrose",
+               "mediumslateblue",
+               "moccasin",
+               "tomato",
+               "forestgreen",
+               "midnightblue",
+               "navajowhite",
+               "navy",
+               "oldlace",
+               "greenyellow",
+               "navyblue",
+               "papayawhip",
+               "lawngreen",
+               "powderblue",
+               "peachpuff",
+               "seashell",
+               "snow",
+               "thistle",
+               "wheat",
+               "darkkhaki",
+               "mintcream",
+               "khaki",
+               "Magentas",
+               "whitesmoke",
+               "peru",
+               "palegreen",
+               "blueviolet",
+               "rosybrown",
+               "saddlebrown",
+               "springgreen",
+               "darkviolet",
+               "darkslategray",
+               "dimgray",
+               "sienna",
+               "gray",
+               "tan",
+               "gray",
+               "mediumvioletred",
+               "lightgray",
+               "Oranges",
+               "cyan",
+               "lightslategray",
+               "darkorange",
+               "slategray",
+               "orangered",
+               "mediumturquoise",
+               "violet",
+               "paleturquoise"
+       };
+
+       static const int n_colors = sizeof(colors) / sizeof(colors[0]);
+
        FILE *f;
 
        if((f = fopen(filename, "wt")) != NULL) {
+               long pos;
+               int n_edges = 0;
                if_edge_t *edge;
+               bitset_t *bs = bitset_malloc(get_graph_node_count(irg));
+
+               ir_fprintf(f, "graph \"%F\" {\n", irg);
+               fprintf(f, "\tnode [shape=box,style=filled]\n");
+
+               for(edge = set_first(edges); edge; edge = set_next(edges)) {
+                       bitset_set(bs, edge->src);
+                       bitset_set(bs, edge->tgt);
+                       n_edges++;
+               }
+
+               fprintf(f, "\tx [label=\"nodes: %d, edges: %d\"]\n", bitset_popcnt(bs), n_edges);
 
-               fprintf(f, "graph G {\n");
+               bitset_foreach(bs, pos) {
+                       int nr = (int) pos;
+                       ir_node *irn = get_irn_for_graph_nr(irg, nr);
+                       int color = get_irn_color(irn);
+
+                       ir_fprintf(f, "\tn%d [label=\"%n\",color=\"%s\"]\n", nr, irn,
+                                       color >= 0 && color < n_colors ? colors[color] : "black");
+               }
 
                for(edge = set_first(edges); edge; edge = set_next(edges)) {
-                       fprintf(f, "i\tn%d -- n%d\n", edge->src, edge->tgt);
+                       fprintf(f, "\tn%d -- n%d [len=5]\n", edge->src, edge->tgt);
                }
 
                fprintf(f, "}\n");
                fclose(f);
+
+               bitset_free(bs);
        }
 
 }
@@ -597,7 +803,7 @@ void be_ra_chordal(ir_graph *irg)
                char buf[128];
 
                ir_snprintf(buf, sizeof(buf), "ifg_%s.dot", get_entity_name(get_irg_entity(irg)));
-               dump_ifg(env->graph, buf);
+               dump_ifg(irg, env->graph, buf);
        }
 #endif
 
index e36645b..7111443 100644 (file)
  */
 typedef struct _sched_env_t {
     const ir_graph *irg;                        /**< The graph to schedule. */
-    list_sched_selector_t *select;  /**< The node selector. */
-    void *select_env;                               /**< A pointer to give to the selector. */
+    const list_sched_selector_t *selector;               /**< The node selector. */
+    void *selector_env;                         /**< A pointer to give to the selector. */
 } sched_env_t;
 
-ir_node *trivial_selector(void *env, ir_node *block, int curr_time,
-        pset *already_scheduled, pset *ready_list)
+static ir_node *trivial_select(void *env, void *block_env, const struct list_head *sched_head,
+               int curr_time, pset *ready_set)
 {
-    ir_node *res = pset_first(ready_list);
-    pset_break(ready_list);
+    ir_node *res = pset_first(ready_set);
+    pset_break(ready_set);
     return res;
 }
 
+static const list_sched_selector_t trivial_selector_struct = {
+       NULL,
+       NULL,
+       trivial_select,
+       NULL,
+       NULL
+};
+
+const list_sched_selector_t *trivial_selector = &trivial_selector_struct;
+
 static void list_sched_block(ir_node *block, void *env_ptr);
 
-void list_sched(ir_graph *irg, list_sched_selector_t *selector, void *select_env)
+void list_sched(ir_graph *irg, const list_sched_selector_t *selector)
 {
     sched_env_t env;
 
     memset(&env, 0, sizeof(env));
-    env.select = selector;
-    env.select_env = select_env;
+    env.selector = selector;
+    env.selector_env = selector->init_graph ? selector->init_graph(irg) : NULL;
     env.irg = irg;
 
     /* Normalize proj nodes. */
@@ -68,6 +78,9 @@ void list_sched(ir_graph *irg, list_sched_selector_t *selector, void *select_env
 
     /* Schedule each single block. */
     irg_block_walk_graph(irg, list_sched_block, NULL, &env);
+
+               if(selector->finish_graph)
+                       selector->finish_graph(env.selector_env, irg);
 }
 
 
@@ -267,94 +280,100 @@ static void add_tuple_projs(block_sched_env_t *env, ir_node *irn)
  */
 static void list_sched_block(ir_node *block, void *env_ptr)
 {
-    sched_env_t *env = env_ptr;
-    block_sched_env_t be;
-
-    ir_node *irn;
-    int i, n, j, m;
-    int phi_seen = 0;
-    sched_info_t *info = get_irn_sched_info(block);
-
-    /* Initialize the block's list head that will hold the schedule. */
-    INIT_LIST_HEAD(&info->list);
-
-    /* Initialize the block scheduling environment */
-               be.dbg = firm_dbg_register("firm.be.sched");
-    be.block = block;
-    be.curr_time = 0;
-    be.ready_set = new_pset(node_cmp_func, get_irn_n_outs(block));
-    be.already_scheduled = new_pset(node_cmp_func, get_irn_n_outs(block));
-
-    DBG((be.dbg, LEVEL_1, "scheduling %n\n", block));
-
-    /* Then one can add all nodes are ready to the set. */
-    for(i = 0, n = get_irn_n_outs(block); i < n; ++i) {
-        ir_node *irn = get_irn_out(block, i);
-
-                               /* Skip the end node because of keepalive edges. */
-                               if(get_irn_opcode(irn) == iro_End)
-                                       continue;
-
-        /* Phi functions are scheduled immediately, since they only transfer
-         * data flow from the predecessors to this block. */
-        if(is_Phi(irn)) {
-            add_to_sched(&be, irn);
-            make_users_ready(&be, irn);
-            phi_seen = 1;
-        }
-
-        /* Other nodes must have all operands in other blocks to be made
-         * ready */
-        else {
-            bool ready = true;
-
-            /* Check, if the operands of a node are not local to this block */
-            for(j = 0, m = get_irn_arity(irn); j < m; ++j) {
-                ir_node *operand = get_irn_n(irn, j);
-
-                if(get_nodes_block(operand) == block) {
-                    ready = false;
-                    break;
-                }
-            }
-
-            /* Make the node ready, if all operands live in a foreign block */
-            if(ready) {
-                DBG((be.dbg, LEVEL_2, "\timmediately ready: %n\n", irn));
-                make_ready(&be, irn);
-            }
-        }
-    }
-
-    /* Increase the time, if some phi functions have been scheduled */
-    be.curr_time += phi_seen;
-
-    while(pset_count(be.ready_set) > 0) {
-        DBG((be.dbg, LEVEL_2, "\tready set: %*n\n", pset_iterator, be.ready_set));
-        // pset_print(stdout, be.ready_set, irn_printer);
-
-        /* select a node to be scheduled and check if it was ready */
-        irn = env->select(env->select_env, block, be.curr_time,
-                be.already_scheduled, be.ready_set);
-
-        DBG((be.dbg, LEVEL_3, "\tpicked node %n\n", irn));
-
-        /* Add the node to the schedule. */
-        add_to_sched(&be, irn);
-
-        if(get_irn_mode(irn) == mode_T)
-            add_tuple_projs(&be, irn);
-        else
-            make_users_ready(&be, irn);
-
-        /* Increase the time step. */
-        be.curr_time += 1;
-
-        /* remove the scheduled node from the ready list. */
-        if(pset_find_ptr(be.ready_set, irn))
-            pset_remove_ptr(be.ready_set, irn);
-    }
-
-    del_pset(be.ready_set);
-    del_pset(be.already_scheduled);
+       void *block_env = NULL;
+       sched_env_t *env = env_ptr;
+       block_sched_env_t be;
+       const list_sched_selector_t *selector = env->selector;
+
+       ir_node *irn;
+       int i, n, j, m;
+       int phi_seen = 0;
+       sched_info_t *info = get_irn_sched_info(block);
+
+       /* Initialize the block's list head that will hold the schedule. */
+       INIT_LIST_HEAD(&info->list);
+
+       /* Initialize the block scheduling environment */
+       be.dbg = firm_dbg_register("firm.be.sched");
+       be.block = block;
+       be.curr_time = 0;
+       be.ready_set = new_pset(node_cmp_func, get_irn_n_outs(block));
+       be.already_scheduled = new_pset(node_cmp_func, get_irn_n_outs(block));
+
+       if(selector->init_block)
+               block_env = selector->init_block(env->selector_env, block);
+
+       DBG((be.dbg, LEVEL_1, "scheduling %n\n", block));
+
+       /* Then one can add all nodes are ready to the set. */
+       for(i = 0, n = get_irn_n_outs(block); i < n; ++i) {
+               ir_node *irn = get_irn_out(block, i);
+
+               /* Skip the end node because of keepalive edges. */
+               if(get_irn_opcode(irn) == iro_End)
+                       continue;
+
+               /* Phi functions are scheduled immediately, since they only transfer
+                * data flow from the predecessors to this block. */
+               if(is_Phi(irn)) {
+                       add_to_sched(&be, irn);
+                       make_users_ready(&be, irn);
+                       phi_seen = 1;
+               }
+
+               /* Other nodes must have all operands in other blocks to be made
+                * ready */
+               else {
+                       bool ready = true;
+
+                       /* Check, if the operands of a node are not local to this block */
+                       for(j = 0, m = get_irn_arity(irn); j < m; ++j) {
+                               ir_node *operand = get_irn_n(irn, j);
+
+                               if(get_nodes_block(operand) == block) {
+                                       ready = false;
+                                       break;
+                               }
+                       }
+
+                       /* Make the node ready, if all operands live in a foreign block */
+                       if(ready) {
+                               DBG((be.dbg, LEVEL_2, "\timmediately ready: %n\n", irn));
+                               make_ready(&be, irn);
+                       }
+               }
+       }
+
+       /* Increase the time, if some phi functions have been scheduled */
+       be.curr_time += phi_seen;
+
+       while(pset_count(be.ready_set) > 0) {
+               DBG((be.dbg, LEVEL_2, "\tready set: %*n\n", pset_iterator, be.ready_set));
+
+               /* select a node to be scheduled and check if it was ready */
+               irn = selector->select(env->selector_env, block_env, &info->list, be.curr_time, be.ready_set);
+
+               DBG((be.dbg, LEVEL_3, "\tpicked node %n\n", irn));
+
+               /* Add the node to the schedule. */
+               add_to_sched(&be, irn);
+
+               if(get_irn_mode(irn) == mode_T)
+                       add_tuple_projs(&be, irn);
+               else
+                       make_users_ready(&be, irn);
+
+               /* Increase the time step. */
+               be.curr_time += 1;
+
+               /* remove the scheduled node from the ready list. */
+               if(pset_find_ptr(be.ready_set, irn))
+                       pset_remove_ptr(be.ready_set, irn);
+       }
+
+       if(selector->finish_block)
+               selector->finish_block(env->selector_env, block_env, block);
+
+       del_pset(be.ready_set);
+       del_pset(be.already_scheduled);
 }
index 5a24ab4..8e15ba0 100644 (file)
@@ -7,30 +7,74 @@
 #ifndef _FIRM_LIST_SCHED
 #define _FIRM_LIST_SCHED
 
+#include "irgraph.h"
+#include "irnode.h"
+
 #include "pset.h"
 #include "pmap.h"
 #include "list.h"
 
 /**
- * The selection function.
- * It picks one node out of the ready list to be scheduled next.
- * The function does not have to delete the node from the ready set.
- *
- * @param env Some private information as passed to list_schedule().
- * @param block The block which is currentliy scheduled.
- * @param curr_time The current time step which the picked node
- * will be assigned to.
- * @param already_scheduled A set containing all nodes already
- * scheduled.
- * @param ready_list A set containing all ready nodes. Pick one of these
- * nodes.
- * @return The chosen node.
+ * A selector interface which is used by the list schedule framework.
+ * You can implement your own list scheduler by implementing these
+ * functions.
  */
-typedef ir_node *(list_sched_selector_t)(void *env, ir_node *block,
-               int curr_time, pset *already_scheduled, pset *ready_list);
+typedef struct _list_sched_selector_t {
+       /**
+        * Called before a graph is being scheduled.
+        * @param irg The graph.
+        * @return The environment pointer that is passed to all other
+        * functions in this struct.
+        */
+       void *(*init_graph)(ir_graph *irg);
+
+       /**
+        * Called before scheduling starts on a block.
+        * @param env The environment.
+        * @param block The block which is to be scheduled.
+        * @return A per-block pointer that is additionally passed to select.
+        */
+       void *(*init_block)(void *env, ir_node *block);
+
+       /**
+        * The selection function.
+        * It picks one node out of the ready list to be scheduled next.
+        * The function does not have to delete the node from the ready set.
+        *
+        * @param env Some private information as returned by init_graph().
+        * @return block_env Some provate information as returned by init_block().
+        * @param sched_head The schedule so far.
+        * @param curr_time The current time step which the picked node
+        * will be assigned to.
+        * @param ready_list A set containing all ready nodes. Pick one of these
+        * nodes.
+        * @return The chosen node.
+        */
+       ir_node *(*select)(void *env, void *block_env,
+                       const struct list_head *sched_head,
+                       int curr_time, pset *ready_set);
+
+       /**
+        * Called after a block has been scheduled.
+        * @param env The environment.
+        * @param block_env The per block environemtn as returned by init_block().
+        * @param block The block that has been finished.
+        */
+       void (*finish_block)(void *env, void *block_env, ir_node *block);
 
-ir_node *trivial_selector(void *env, ir_node *block, int curr_time,
-               pset *already_scheduled, pset *ready_list);
+       /**
+        * Called after a whole graph has been scheduled.
+        * @param env The environment.
+        * @param irg The graph.
+        */
+       void (*finish_graph)(void *env, ir_graph *irg);
+} list_sched_selector_t;
+
+
+/**
+ * A trivial selector, that just selects the first ready node.
+ */
+extern const list_sched_selector_t *trivial_selector;
 
 /**
  * List schedule a graph.
@@ -41,9 +85,8 @@ ir_node *trivial_selector(void *env, ir_node *block, int curr_time,
  * @param sched_obst An obstack to allocate the lists on.
  * @param map Maps each block to a list head giving the schedule.
  * @param select_func A selection function.
- * @param env Some private data to give to the select function.
  */
-void list_sched(ir_graph *irg, list_sched_selector_t *select_func, void *env);
+void list_sched(ir_graph *irg, const list_sched_selector_t *select_func);
 
 
 
index 83de369..079785d 100644 (file)
@@ -121,7 +121,7 @@ static void be_main_loop(void)
                dump_ir_block_graph(irg, "-local-const");
 #endif
                be_numbering(irg);
-               list_sched(irg, trivial_selector, NULL);
+               list_sched(irg, trivial_selector);
                be_liveness(irg);
                be_ra_chordal(irg);
 
index ae2f9f4..c0bc380 100644 (file)
@@ -49,7 +49,7 @@ void be_sched_test(void)
        for(i = 0, n = get_irp_n_irgs(); i < n; ++i) {
                ir_graph *irg = get_irp_irg(i);
 
-               list_sched(irg, trivial_selector, NULL);
+               list_sched(irg, trivial_selector);
                be_sched_dump(stdout, irg);
        }