From: Sebastian Hack Date: Mon, 14 Mar 2005 11:26:22 +0000 (+0000) Subject: Added be arch reflection/backend support infrastructure. X-Git-Url: http://nsz.repo.hu/git/?a=commitdiff_plain;h=8e0086dfdf3c7706b8bc4ee0e54097b4ed63d1e7;p=libfirm Added be arch reflection/backend support infrastructure. --- diff --git a/ir/be/Makefile.in b/ir/be/Makefile.in index 6ffc755d6..f3aa6c364 100644 --- a/ir/be/Makefile.in +++ b/ir/be/Makefile.in @@ -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 index 000000000..7aa7b555f --- /dev/null +++ b/ir/be/bearch.c @@ -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 +#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 index 000000000..743002cb7 --- /dev/null +++ b/ir/be/bearch.h @@ -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 index 000000000..6b55d9ab8 --- /dev/null +++ b/ir/be/bearch_obj.def @@ -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 index 000000000..383879ab2 --- /dev/null +++ b/ir/be/bearch_t.h @@ -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 */ diff --git a/ir/be/bechordal.c b/ir/be/bechordal.c index c14d635aa..817a3b952 100644 --- a/ir/be/bechordal.c +++ b/ir/be/bechordal.c @@ -31,19 +31,12 @@ #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 diff --git a/ir/be/belistsched.c b/ir/be/belistsched.c index e36645b6b..7111443c7 100644 --- a/ir/be/belistsched.c +++ b/ir/be/belistsched.c @@ -33,27 +33,37 @@ */ 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); } diff --git a/ir/be/belistsched.h b/ir/be/belistsched.h index 5a24ab43c..8e15ba098 100644 --- a/ir/be/belistsched.h +++ b/ir/be/belistsched.h @@ -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); diff --git a/ir/be/bemain.c b/ir/be/bemain.c index 83de369fa..079785d5f 100644 --- a/ir/be/bemain.c +++ b/ir/be/bemain.c @@ -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); diff --git a/ir/be/besched.c b/ir/be/besched.c index ae2f9f43d..c0bc38091 100644 --- a/ir/be/besched.c +++ b/ir/be/besched.c @@ -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); }