From c7aae220f908ae663ee138672a16a14aceab2aa4 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Christian=20W=C3=BCrdig?= Date: Tue, 13 Dec 2005 15:39:47 +0000 Subject: [PATCH] fixed indent changed backend interface improved emitter fixed a lot of bugs --- ir/be/ia32/Makefile.in | 11 +- ir/be/ia32/bearch_ia32.c | 491 ++++++++++--- ir/be/ia32/ia32_emitter.c | 655 +++++++++++++++++- ir/be/ia32/ia32_emitter.h | 19 +- ir/be/ia32/ia32_gen_decls.c | 1 + ir/be/ia32/ia32_new_nodes.c | 135 ++-- ir/be/ia32/ia32_new_nodes.h | 15 +- ir/be/ia32/ia32_nodes_attr.h | 3 + ir/be/ia32/ia32_spec.pl | 413 ++++++++--- ir/be/ia32/ia32_transform.c | 1257 +++++++++++++++++++++++----------- 10 files changed, 2316 insertions(+), 684 deletions(-) diff --git a/ir/be/ia32/Makefile.in b/ir/be/ia32/Makefile.in index 70e97eb26..03f235895 100644 --- a/ir/be/ia32/Makefile.in +++ b/ir/be/ia32/Makefile.in @@ -18,10 +18,11 @@ full_dir = $(top_srcdir)/ir/be full_dirbe = $(full_dir)/$(FIRMBE_ARCH) arch = $(FIRMBE_ARCH) -SOURCES = Makefile.in $(arch)_new_nodes.c $(arch)_new_nodes.h gen_$(arch)_new_nodes.c.inl gen_$(arch)_new_nodes.h.inl \ +SOURCES = Makefile.in $(arch)_new_nodes.c $(arch)_new_nodes.h gen_$(arch)_new_nodes.c.inl gen_$(arch)_new_nodes.h \ gen_$(arch)_emitter.c gen_$(arch)_emitter.h $(arch)_emitter.c $(arch)_emitter.h \ - bearch_$(arch).c gen_$(arch)_regalloc_if.h gen_$(arch)_regalloc_if.c.inl \ - $(arch)_transform.c $(arch)_transform.h $(arch)_gen_decls.c $(arch)_gen_decls.h + bearch_$(arch).c gen_$(arch)_regalloc_if_t.h gen_$(arch)_regalloc_if.h gen_$(arch)_regalloc_if.c \ + $(arch)_transform.c $(arch)_transform.h $(arch)_gen_decls.c $(arch)_gen_decls.h \ + $(arch)_map_regs.c $(arch)_map_regs.h include $(topdir)/MakeRules @@ -33,7 +34,7 @@ CPPFLAGS += -I$(top_srcdir)/ir/adt -I$(top_srcdir)/ir/ir -I$(top_srcdir)/ir/ include $(top_srcdir)/MakeTargets -$(full_dirbe)/$(arch)_new_nodes.c: $(full_dirbe)/gen_$(arch)_new_nodes.c.inl $(full_dirbe)/gen_$(arch)_regalloc_if.c.inl $(full_dirbe)/gen_$(arch)_regalloc_if.h +$(full_dirbe)/$(arch)_new_nodes.c: $(full_dirbe)/gen_$(arch)_regalloc_if.h $(full_dirbe)/gen_$(arch)_new_nodes.c.inl $(full_dirbe)/$(arch)_new_nodes.h: $(full_dirbe)/gen_$(arch)_new_nodes.h.inl @@ -45,7 +46,7 @@ $(full_dirbe)/gen_$(arch)_new_nodes.c.inl $(full_dirbe)/gen_$(arch)_new_nodes.h. $(full_dirbe)/gen_$(arch)_emitter.c $(full_dirbe)/gen_$(arch)_emitter.h: $(full_dir)/scripts/generate_emitter.pl $(full_dirbe)/$(arch)_spec.pl $(full_dir)/scripts/generate_emitter.pl $(full_dirbe)/$(arch)_spec.pl $(full_dirbe) -$(full_dirbe)/gen_$(arch)_regalloc_if.c.inl $(full_dirbe)/gen_$(arch)_regalloc_if.h: $(full_dir)/scripts/generate_regalloc_if.pl $(full_dirbe)/$(arch)_spec.pl +$(full_dirbe)/gen_$(arch)_regalloc_if.c $(full_dirbe)/gen_$(arch)_regalloc_if.h $(full_dirbe)/gen_$(arch)_regalloc_if_t.h: $(full_dir)/scripts/generate_regalloc_if.pl $(full_dirbe)/$(arch)_spec.pl $(full_dir)/scripts/generate_regalloc_if.pl $(full_dirbe)/$(arch)_spec.pl $(full_dirbe) all: subdir.o diff --git a/ir/be/ia32/bearch_ia32.c b/ir/be/ia32/bearch_ia32.c index da45d1b82..51a5dfbbf 100644 --- a/ir/be/ia32/bearch_ia32.c +++ b/ir/be/ia32/bearch_ia32.c @@ -1,31 +1,71 @@ #include "pseudo_irg.h" #include "irgwalk.h" +#include "irprog.h" +#include "irprintf.h" +#include "bearch_ia32.h" #include "bitset.h" #include "debug.h" +#include + +#ifdef obstack_chunk_alloc +# undef obstack_chunk_alloc +# define obstack_chunk_alloc malloc +#else +# define obstack_chunk_alloc malloc +# define obstack_chunk_free free +#endif + #include "../bearch.h" /* the general register allocator interface */ #include "ia32_new_nodes.h" /* ia32 nodes interface */ #include "gen_ia32_regalloc_if.h" /* the generated interface (register type and class defenitions) */ #include "ia32_gen_decls.h" /* interface declaration emitter */ #include "ia32_transform.h" +#include "ia32_emitter.h" +#include "ia32_map_regs.h" -/* define shorter names for classes and indicees */ +#define DEBUG_MODULE "be.isa.ia32" -#define N_GP_REGS N_ia32_general_purpose_REGS -#define N_FP_REGS N_ia32_floating_point_REGS -#define N_FLAG_REGS N_ia32_flag_register_REGS +/* TODO: ugly */ +static set *cur_reg_set = NULL; -#define CLS_GP CLASS_ia32_general_purpose -#define CLS_FP CLASS_ia32_floating_point -#define CLS_FLAG CLASS_ia32_flag_register +/** + * Stuff needed for dummy register requirements to keep register allocator + * happy during development. + */ +static arch_register_t ia32_dummy_regs[500]; +static arch_register_class_t ia32_dummy_reg_class = { + "dummy", + 500, + ia32_dummy_regs +}; + +static arch_register_req_t ia32_dummy_register_req = { + arch_register_req_type_normal, + &ia32_dummy_reg_class, + { NULL } +}; -#define N_CLASSES (sizeof(ia32_reg_classes) / sizeof(ia32_reg_classes[0])) -extern arch_register_class_t ia32_reg_classes[3]; -/* Implementation of the register allocator functions */ +/************************************************** + * _ _ _ __ + * | | | (_)/ _| + * _ __ ___ __ _ __ _| | | ___ ___ _| |_ + * | '__/ _ \/ _` | / _` | | |/ _ \ / __| | | _| + * | | | __/ (_| | | (_| | | | (_) | (__ | | | + * |_| \___|\__, | \__,_|_|_|\___/ \___| |_|_| + * __/ | + * |___/ + **************************************************/ + +static ir_node *my_skip_proj(const ir_node *n) { + while (is_Proj(n)) + n = get_Proj_pred(n); + return (ir_node *)n; +} /** * Return register requirements for an ia32 node. @@ -33,140 +73,377 @@ extern arch_register_class_t ia32_reg_classes[3]; * will be asked for this information. */ static const arch_register_req_t *ia32_get_irn_reg_req(const arch_irn_ops_t *self, arch_register_req_t *req, const ir_node *irn, int pos) { - const arch_register_req_t **irn_req; + const arch_register_req_t **irn_req; + long node_pos = pos == -1 ? 0 : pos; + ir_mode *mode = get_irn_mode(irn); + firm_dbg_module_t *mod = firm_dbg_register(DEBUG_MODULE); + + if (mode == mode_T || mode == mode_M) { + DBG((mod, LEVEL_1, "ignoring mode_T, mode_M node %+F\n", irn)); + return NULL; + } + + DBG((mod, LEVEL_1, "get requirements at pos %d for %+F ... ", pos, irn)); + + if (is_Proj(irn)) { + if (pos == -1) + node_pos = translate_proj_pos(irn); + else + node_pos = pos; + + irn = my_skip_proj(irn); + + DBG((mod, LEVEL_1, "skipping Proj, going to %+F at pos %d ... ", irn, node_pos)); + } + + if (is_ia32_irn(irn)) { + if (pos >= 0) { + irn_req = get_ia32_in_req(irn); + } + else { + irn_req = get_ia32_out_req(irn); + pos = node_pos; + } + + DBG((mod, LEVEL_1, "returning reqs for %+F at pos %d\n", irn, pos)); + + memcpy(req, irn_req[pos], sizeof(*req)); + return req; + } + else { + /* treat Phi like Const with default requirements */ + if (is_Phi(irn)) { + DBG((mod, LEVEL_1, "returning standard reqs for %+F\n", irn)); + if (mode_is_float(mode)) + memcpy(req, &ia32_default_req_ia32_floating_point, sizeof(*req)); + else if (mode_is_int(mode) || mode_is_reference(mode)) + memcpy(req, &ia32_default_req_ia32_general_purpose, sizeof(*req)); + else if (mode == mode_T || mode == mode_M) { + DBG((mod, LEVEL_1, "ignoring Phi node %+F\n", irn)); + return NULL; + } + else + assert(0 && "unsupported Phi-Mode"); + } + else if (get_irn_op(irn) == op_Start) { + DBG((mod, LEVEL_1, "returning reqs none for ProjX -> Start (%+F )\n", irn)); + switch (node_pos) { + case pn_Start_X_initial_exec: + case pn_Start_P_value_arg_base: + case pn_Start_P_globals: + case pn_Start_P_frame_base: + memcpy(req, &ia32_default_req_none, sizeof(*req)); + break; +// memcpy(req, &ia32_default_req_ia32_general_purpose, sizeof(*req)); +// break; + case pn_Start_T_args: + assert(0 && "ProjT(pn_Start_T_args) should not be asked"); + } + } + else if (get_irn_op(irn) == op_Return && pos >= 0) { + DBG((mod, LEVEL_1, "returning reqs EAX for %+F\n", irn)); + memcpy(req, &ia32_default_req_ia32_general_purpose_eax, sizeof(*req)); + } + else { + DBG((mod, LEVEL_1, "returning standard reqs for %+F (not ia32)\n", irn)); + memcpy(req, &ia32_dummy_register_req, sizeof(*req)); + } + } + + return req; +} - if (is_Proj(irn)) { - } - else if (is_ia32_irn(irn)) { - if (get_irn_mode(irn) == mode_T) { - return NULL; - } +static void ia32_set_irn_reg(const arch_irn_ops_t *self, ir_node *irn, const arch_register_t *reg) { + int pos = 0; - if (pos >= 0) { - irn_req = get_ia32_in_req(irn); - } - else { - irn_req = get_ia32_out_req(irn); - pos = -1 - pos; - } + if (is_Proj(irn)) { + pos = translate_proj_pos(irn); + irn = my_skip_proj(irn); + } - memcpy(req, irn_req[pos], sizeof(*req)); - return req; - } - else - req = NULL; + if (is_ia32_irn(irn)) { + const arch_register_t **slots; - return req; + slots = get_ia32_slots(irn); + slots[pos] = reg; + } + else { + ia32_set_firm_reg(self, irn, reg, cur_reg_set); + } } -static int ia32_get_n_operands(const arch_irn_ops_t *self, const ir_node *irn, int in_out) { - if (in_out >= 0) - return get_irn_arity(irn); - else - return get_ia32_n_res(irn); +static const arch_register_t *ia32_get_irn_reg(const arch_irn_ops_t *self, const ir_node *irn) { + int pos = 0; + const arch_register_t *reg = NULL; + + if (is_Proj(irn)) { + pos = translate_proj_pos(irn); + irn = my_skip_proj(irn); + } + + if (is_ia32_irn(irn)) { + const arch_register_t **slots; + slots = get_ia32_slots(irn); + reg = slots[pos]; + } + else { + reg = ia32_get_firm_reg(self, irn, cur_reg_set); + } + + return reg; } -static void ia32_set_irn_reg(const arch_irn_ops_t *self, ir_node *irn, int pos, const arch_register_t *reg) { - if (is_ia32_irn(irn)) { - const arch_register_t **slots; +static arch_irn_class_t ia32_classify(const arch_irn_ops_t *self, const ir_node *irn) { + irn = my_skip_proj(irn); + if (is_cfop(irn)) + return arch_irn_class_branch; + else + return arch_irn_class_normal; +} - slots = get_ia32_slots(irn); - slots[pos] = reg; - } +static arch_irn_flags_t ia32_get_flags(const arch_irn_ops_t *self, const ir_node *irn) { + irn = my_skip_proj(irn); + if (is_ia32_irn(irn)) + return get_ia32_flags(irn); + else { + ir_printf("don't know flags of %+F\n", irn); + return 0; + } } -static const arch_register_t *ia32_get_irn_reg(const arch_irn_ops_t *self, const ir_node *irn, int pos) { - if (is_ia32_irn(irn)) { - const arch_register_t **slots; +/* fill register allocator interface */ + +static const arch_irn_ops_t ia32_irn_ops = { + ia32_get_irn_reg_req, + ia32_set_irn_reg, + ia32_get_irn_reg, + ia32_classify, + ia32_get_flags +}; + + + +/************************************************** + * _ _ __ + * | | (_)/ _| + * ___ ___ __| | ___ __ _ ___ _ __ _| |_ + * / __/ _ \ / _` |/ _ \/ _` |/ _ \ '_ \ | | _| + * | (_| (_) | (_| | __/ (_| | __/ | | | | | | + * \___\___/ \__,_|\___|\__, |\___|_| |_| |_|_| + * __/ | + * |___/ + **************************************************/ + +typedef struct _ia32_code_gen_t { + const arch_code_generator_if_t *impl; /* implementation */ + ir_graph *irg; /* current irg */ + FILE *out; /* output file */ + set *reg_set; /* set to memorize registers for non-ia32 nodes (e.g. phi nodes) */ + firm_dbg_module_t *mod; /* debugging module */ + int emit_decls; +} ia32_code_gen_t; - slots = get_ia32_slots(irn); - return slots[pos]; - } - else - return NULL; + +/** + * Transforms the standard firm graph into + * an ia32 firm graph + */ +static void ia32_prepare_graph(void *self) { + ia32_code_gen_t *cg = self; + + if (! is_pseudo_ir_graph(cg->irg)) + irg_walk_blkwise_graph(cg->irg, NULL, ia32_transform_node, cg->mod); } -static arch_irn_class_t ia32_classify(const arch_irn_ops_t *self, const ir_node *irn) { - if (is_ia32_irn(irn)) { - if (is_ia32_Cmp(irn) || is_ia32_Cmp_i(irn)) // TODO: ia32_Jmp - return arch_irn_class_branch; - else - return arch_irn_class_normal; - } - else - return 0; + + +/** + * Dummy functions for hooks we don't need but which must be filled. + */ +static void ia32_before_sched(void *self) { } -static arch_irn_flags_t ia32_get_flags(const arch_irn_ops_t *self, const ir_node *irn) { - if (is_ia32_irn(irn)) - return get_ia32_flags(irn); - else - return 0; +static void ia32_before_ra(void *self) { } -/* fill register allocator interface */ -static const arch_irn_ops_t ia32_irn_ops = { - ia32_get_irn_reg_req, - ia32_get_n_operands, - ia32_set_irn_reg, - ia32_get_irn_reg, - ia32_classify, - ia32_get_flags + +/** + * Emits the code, closes the output file and frees + * the code generator interface. + */ +static void ia32_codegen(void *self) { + ia32_code_gen_t *cg = self; + ir_graph *irg = cg->irg; + FILE *out = cg->out; + + if (cg->emit_decls) { + ia32_gen_decls(cg->out); + cg->emit_decls = 0; + } + +// ia32_finish_irg(irg); + ia32_gen_routine(out, irg, cur_reg_set); + + cur_reg_set = NULL; + + /* de-allocate code generator */ + del_set(cg->reg_set); + free(self); +} + +static const arch_code_generator_if_t ia32_code_gen_if = { + ia32_prepare_graph, + ia32_before_sched, /* before scheduling hook */ + ia32_before_ra, /* before register allocation hook */ + ia32_codegen /* emit && done */ }; -/* Implementation of the backend isa functions */ -static void ia32_init(void) { - ia32_register_init(); - ia32_create_opcodes(); + +/***************************************************************** + * ____ _ _ _____ _____ + * | _ \ | | | | |_ _|/ ____| /\ + * | |_) | __ _ ___| | _____ _ __ __| | | | | (___ / \ + * | _ < / _` |/ __| |/ / _ \ '_ \ / _` | | | \___ \ / /\ \ + * | |_) | (_| | (__| < __/ | | | (_| | _| |_ ____) / ____ \ + * |____/ \__,_|\___|_|\_\___|_| |_|\__,_| |_____|_____/_/ \_\ + * + *****************************************************************/ + +typedef struct _ia32_isa_t { + const arch_isa_if_t *impl; + int num_codegens; + FILE *output_file; +} ia32_isa_t; + +/** + * Initializes the backend ISA and opens the output file. + */ +static void *ia32_init(FILE *out) { + int i; + static struct obstack obst; + static int inited = 0; + ia32_isa_t *isa = malloc(sizeof(*isa)); + + isa->impl = &ia32_isa_if; + + if(inited) + return NULL; + + inited = 1; + + isa->output_file = out; + isa->num_codegens = 0; + + /* init dummy register requirements */ + obstack_init(&obst); + + for (i = 0; i < 500; i++) { + int n; + char buf[5]; + char *name; + arch_register_t *reg = &ia32_dummy_regs[i]; + + n = snprintf(buf, sizeof(buf), "d%d", i); + name = obstack_copy0(&obst, buf, n); + + reg->name = name; + reg->reg_class = &ia32_dummy_reg_class; + reg->index = i; + reg->type = arch_register_type_none; + } + + obstack_free(&obst, NULL); + + ia32_register_init(); + ia32_create_opcodes(); + + return isa; } -static int ia32_get_n_reg_class(void) { - return N_CLASSES; + + +/** + * Closes the output file and frees the ISA structure. + */ +static void ia32_done(void *self) { + free(self); } -static const arch_register_class_t *ia32_get_reg_class(int i) { - assert(i >= 0 && i < N_CLASSES && "Invalid ia32 register class requested."); - return &ia32_reg_classes[i]; + + +static int ia32_get_n_reg_class(const void *self) { + return N_CLASSES; +} + +static const arch_register_class_t *ia32_get_reg_class(const void *self, int i) { + assert(i >= 0 && i < N_CLASSES && "Invalid ia32 register class requested."); + return &ia32_reg_classes[i]; } static const arch_irn_ops_t *ia32_get_irn_ops(const arch_irn_handler_t *self, const ir_node *irn) { - return &ia32_irn_ops; + return &ia32_irn_ops; } -static void ia32_prepare_graph(ir_graph *irg) { - firm_dbg_module_t *dbg = firm_dbg_register("be.transform.ia32"); - if (! is_pseudo_ir_graph(irg)) - irg_walk_blkwise_graph(irg, NULL, ia32_transform_node, dbg); +const arch_irn_handler_t ia32_irn_handler = { + ia32_get_irn_ops +}; + +const arch_irn_handler_t *ia32_get_irn_handler(const void *self) { + return &ia32_irn_handler; } -static void ia32_codegen(FILE *out) { - ia32_gen_decls(out); -#if 0 - for (i = 0; i < get_irp_n_irgs(); ++i) { - ir_graph *irg = get_irp_irg(i); - if (! is_pseudo_ir_graph(irg)) { - ia32_finish_irg(irg); - ia32_gen_routine(out, irg); - } - } -#endif + +/** + * Initializes the code generator interface. + */ +static arch_code_generator_t *ia32_make_code_generator(void *self, ir_graph *irg) { + ia32_isa_t *isa = self; + ia32_code_gen_t *cg = malloc(sizeof(*cg)); + + cg->impl = &ia32_code_gen_if; + cg->irg = irg; + cg->reg_set = new_set(cmp_irn_reg_assoc, 1024); + cg->mod = firm_dbg_register("be.transform.ia32"); + cg->out = isa->output_file; + + isa->num_codegens++; + + if (isa->num_codegens > 1) + cg->emit_decls = 0; + else + cg->emit_decls = 1; + + cur_reg_set = cg->reg_set; + + return (arch_code_generator_t *)cg; } -const arch_irn_handler_t ia32_irn_handler = { - ia32_get_irn_ops -}; +/** + * Returns the default scheduler + */ +static const list_sched_selector_t *ia32_get_list_sched_selector(const void *self) { + return trivial_selector; +} -/* fill isa interface */ +#ifdef WITH_LIBCORE +static void ia32_register_options(lc_opt_entry_t *ent) +{ +} +#endif /* WITH_LIBCORE */ -const arch_isa_if_t ia32_isa = { - ia32_init, - ia32_get_n_reg_class, - ia32_get_reg_class, - ia32_prepare_graph, - &ia32_irn_handler, - ia32_codegen +const arch_isa_if_t ia32_isa_if = { +#ifdef WITH_LIBCORE + ia32_register_options, +#endif + ia32_init, + ia32_done, + ia32_get_n_reg_class, + ia32_get_reg_class, + ia32_get_irn_handler, + ia32_make_code_generator, + ia32_get_list_sched_selector }; diff --git a/ir/be/ia32/ia32_emitter.c b/ir/be/ia32/ia32_emitter.c index b5d8c0773..3557aa850 100644 --- a/ir/be/ia32/ia32_emitter.c +++ b/ir/be/ia32/ia32_emitter.c @@ -1,42 +1,258 @@ +#include + #include "tv.h" #include "iredges.h" +#include "debug.h" +#include "irgwalk.h" +#include "irprintf.h" +#include "irop_t.h" + +#include "../besched.h" + #include "ia32_emitter.h" +#include "gen_ia32_emitter.h" #include "ia32_nodes_attr.h" #include "ia32_new_nodes.h" +#include "ia32_map_regs.h" + +#define SNPRINTF_BUF_LEN 128 + +static set *cur_reg_set = NULL; -#define TARVAL_SNPRINTF_BUF_LEN 1024 -const char *get_dest_reg_name(ir_node *n, int num) { - return get_ia32_out_reg_name(n, --num); +/************************************************************* + * _ _ __ _ _ + * (_) | | / _| | | | | + * _ __ _ __ _ _ __ | |_| |_ | |__ ___| |_ __ ___ _ __ + * | '_ \| '__| | '_ \| __| _| | '_ \ / _ \ | '_ \ / _ \ '__| + * | |_) | | | | | | | |_| | | | | | __/ | |_) | __/ | + * | .__/|_| |_|_| |_|\__|_| |_| |_|\___|_| .__/ \___|_| + * | | | | + * |_| |_| + *************************************************************/ + +/** + * Return node's tarval as string. + */ +const char *node_const_to_str(ir_node *n) { + char *buf; + tarval *tv = get_ia32_Immop_tarval(n); + + if (tv) { + buf = malloc(SNPRINTF_BUF_LEN); + tarval_snprintf(buf, SNPRINTF_BUF_LEN, tv); + return buf; + } + else if (get_ia32_old_ir(n)) { + return get_sc_name(get_ia32_old_ir(n)); + } + else + return "0"; } -const char *get_source_reg_name(ir_node *n, int num) { - return get_ia32_in_reg_name(n, --num); +/** + * Returns node's offset as string. + */ +char *node_offset_to_str(ir_node *n) { + char *buf; + tarval *tv = get_ia32_offs(n); + + if (tv) { + buf = malloc(SNPRINTF_BUF_LEN); + tarval_snprintf(buf, SNPRINTF_BUF_LEN, tv); + return buf; + } + else + return ""; } -char *node_const_to_str(ir_node *n) { - char *buf = malloc(TARVAL_SNPRINTF_BUF_LEN); - tarval_snprintf(buf, TARVAL_SNPRINTF_BUF_LEN, get_ia32_Immop_tarval(n)); - return buf; +/* We always pass the ir_node which is a pointer. */ +static int ia32_get_arg_type(const lc_arg_occ_t *occ) { + return lc_arg_type_ptr; } -char *node_offset_to_str(ir_node *n) { - char *buf = malloc(TARVAL_SNPRINTF_BUF_LEN); - tarval_snprintf(buf, TARVAL_SNPRINTF_BUF_LEN, get_ia32_offs(n)); - return buf; + +/** + * Returns the register at in position pos. If the IN node is not an + * ia32 node, we check for phi and proj. + */ +static const arch_register_t *get_in_reg(ir_node *irn, int pos) { + ir_node *op; + const arch_register_t *reg = NULL; + const arch_register_t **slots; + + assert(get_irn_arity(irn) > pos && "Invalid IN position"); + + /* The out register of the operator at position pos is the + in register we need. */ + op = get_irn_n(irn, pos); + + if (is_Proj(op)) { + pos = (int)translate_proj_pos(op); + while(is_Proj(op)) + op = get_Proj_pred(op); + } + + if (is_ia32_irn(op)) { + /* The operator is an ia32 node: this node has only one out */ + slots = get_ia32_slots(op); + reg = slots[0]; + } + else { + /* The operator is not an ia32 node: check for Phi or Proj */ + if (is_Phi(op)) { + /* Phi's getting register assigned */ + reg = ia32_get_firm_reg(NULL, op, cur_reg_set); + assert(reg && "No register assigned to Phi node"); + } + else { + assert(0 && "Unsupported node for IN register"); + } + } + + return reg; +} + +/** + * Returns the number of the in register at position pos. + */ +int get_ia32_in_regnr(ir_node *irn, int pos) { + const arch_register_t *reg; + + reg = get_in_reg(irn, pos); + assert(reg && "no in register"); + return reg->index; +} + +/** + * Returns the name of the in register at position pos. + */ +const char *get_ia32_in_reg_name(ir_node *irn, int pos) { + const arch_register_t *reg; + + reg = get_in_reg(irn, pos); + assert(reg && "no in register"); + return reg->name; +} + +/** + * Get the register name for a node. + */ +static int ia32_get_reg_name(lc_appendable_t *app, + const lc_arg_occ_t *occ, const lc_arg_value_t *arg) +{ + const char *buf; + ir_node *X = arg->v_ptr; + int nr = occ->width - 1; + + if (!X) + return lc_arg_append(app, occ, "(null)", 6); + + if (occ->conversion == 's') { + buf = get_ia32_in_reg_name(X, nr); + } + else { /* 'd' */ + buf = get_ia32_out_reg_name(X, nr); + } + + return lc_arg_append(app, occ, buf, strlen(buf)); } +/** + * Returns the tarval or offset of an ia32 as a string. + */ +static int ia32_const_to_str(lc_appendable_t *app, + const lc_arg_occ_t *occ, const lc_arg_value_t *arg) +{ + const char *buf; + ir_node *X = arg->v_ptr; + + if (!X) + return lc_arg_append(app, occ, "(null)", 6); + + if (occ->conversion == 'c') { + buf = node_const_to_str(X); + } + else { /* 'o' */ + buf = node_offset_to_str(X); + } + + return lc_arg_append(app, occ, buf, strlen(buf)); +} + +/** + * Determines the SSE suffix depending on the mode. + */ +static int ia32_get_mode_suffix(lc_appendable_t *app, + const lc_arg_occ_t *occ, const lc_arg_value_t *arg) +{ + ir_node *X = arg->v_ptr; + + if (!X) + return lc_arg_append(app, occ, "(null)", 6); + + if (get_mode_size_bits(get_irn_mode(X)) == 32) + return lc_appendable_chadd(app, 's'); + else + return lc_appendable_chadd(app, 'd'); +} + +/** + * Return the ia32 printf arg environment. + * We use the firm environment with some additional handlers. + */ +const lc_arg_env_t *ia32_get_arg_env(void) { + static lc_arg_env_t *env = NULL; + + static const lc_arg_handler_t ia32_reg_handler = { ia32_get_arg_type, ia32_get_reg_name }; + static const lc_arg_handler_t ia32_const_handler = { ia32_get_arg_type, ia32_const_to_str }; + static const lc_arg_handler_t ia32_mode_handler = { ia32_get_arg_type, ia32_get_mode_suffix }; + + if(env == NULL) { + env = firm_get_arg_env(); + + lc_arg_register(env, "ia32:sreg", 's', &ia32_reg_handler); + lc_arg_register(env, "ia32:dreg", 'd', &ia32_reg_handler); + lc_arg_register(env, "ia32:cnst", 'c', &ia32_const_handler); + lc_arg_register(env, "ia32:offs", 'o', &ia32_const_handler); + lc_arg_register(env, "ia32:mode", 'm', &ia32_mode_handler); + } + + return env; +} + +/** + * For 2-address code we need to make sure the first src reg is equal to dest reg. + */ void equalize_dest_src(FILE *F, ir_node *n) { - if (get_ia32_out_regnr(n, 0) != get_ia32_in_regnr(n, 0)) - fprintf(F, "\tmovl %%%s, %%%s\t\t\t/* src -> dest for 2 address code */\n", get_source_reg_name(n, 1), get_dest_reg_name(n, 1)); + if (get_ia32_in_regnr(n, 0) != get_ia32_out_regnr(n, 0)) { + if (get_irn_arity(n) > 1 && get_ia32_in_regnr(n, 1) == get_ia32_out_regnr(n, 0)) { + if (! is_op_commutative(get_irn_op(n))) { + /* we only need to echange for non-commutative ops */ + lc_efprintf(ia32_get_arg_env(), F, "\txchg %1s, %2s\t\t\t/* xchg src1 <-> src2 for 2 address code */\n", n, n); + } + } + else { + lc_efprintf(ia32_get_arg_env(), F, "\tmovl %1s, %1d\t\t\t/* src -> dest for 2 address code */\n", n, n); + } + } +} + +/* + * Add a number to a prefix. This number will not be used a second time. + */ +char *get_unique_label(char *buf, size_t buflen, const char *prefix) { + static unsigned long id = 0; + snprintf(buf, buflen, "%s%lu", prefix, ++id); + return buf; } /* * coding of conditions */ struct cmp2conditon_t { - const char *name; - pn_Cmp num; + const char *name; + pn_Cmp num; }; /* @@ -86,28 +302,397 @@ static const struct cmp2conditon_t cmp2condition_u[] = { /* * returns the condition code */ -const char *get_cmp_suffix(int cmp_code, int unsigned_cmp) +static const char *get_cmp_suffix(int cmp_code, int unsigned_cmp) { - assert(cmp2condition_s[cmp_code].num == cmp_code); - assert(cmp2condition_u[cmp_code].num == cmp_code); + assert(cmp2condition_s[cmp_code].num == cmp_code); + assert(cmp2condition_u[cmp_code].num == cmp_code); - return unsigned_cmp ? cmp2condition_u[cmp_code & 7].name : cmp2condition_s[cmp_code & 7].name; + return unsigned_cmp ? cmp2condition_u[cmp_code & 7].name : cmp2condition_s[cmp_code & 7].name; } -void emit_ia32_Proj_Cond(FILE *F, ir_node *n, ir_node *cond) { - ir_node *succ_block = get_edge_src_irn(get_irn_out_edge_first(n)); - ir_node *sel = get_Cond_selector(cond); - ir_mode *sel_mode = get_irn_mode(sel); +/** + * Returns the target label for a control flow node. + */ +static char *get_cfop_target(const ir_node *irn, char *buf) { + ir_node *bl = get_irn_link(irn); - assert(succ_block && "Target block of Proj_Cond missing!"); + snprintf(buf, SNPRINTF_BUF_LEN, "BLOCK_%ld", get_irn_node_nr(bl)); + return buf; +} - if (sel_mode == mode_b) { // Boolean condition - int label = get_irn_node_nr(succ_block); - int nr = get_Proj_proj(n); - fprintf(F, "j%s%s Label%d\t\t\t/* if (%sCond) goto Label */\n", - nr == pn_Cond_true ? "" : "n", - get_cmp_suffix(get_Proj_proj(sel), mode_is_signed(sel_mode)), - label, - nr == pn_Cond_true ? "" : "!"); - } +/** + * Emits the jump sequence for a conditional jump (cmp + jmp_true + jmp_false) + */ +static void finish_CondJmp(FILE *F, ir_node *irn) { + const ir_node *proj; + const ir_edge_t *edge; + char buf[SNPRINTF_BUF_LEN]; + + edge = get_irn_out_edge_first(irn); + proj = get_edge_src_irn(edge); + assert(is_Proj(proj) && "CondJmp with a non-Proj"); + + if (get_Proj_proj(proj) == 1) { + fprintf(F, "\tj%s %s\t\t\t/* cmp(a, b) == TRUE */\n", + get_cmp_suffix(get_ia32_pncode(irn), !mode_is_signed(get_irn_mode(get_irn_n(irn, 0)))), + get_cfop_target(proj, buf)); + } + else { + fprintf(F, "\tjn%s %s\t\t\t/* cmp(a, b) == FALSE */\n", + get_cmp_suffix(get_ia32_pncode(irn), !mode_is_signed(get_irn_mode(get_irn_n(irn, 0)))), + get_cfop_target(proj, buf)); + } + + edge = get_irn_out_edge_next(irn, edge); + if (edge) { + proj = get_edge_src_irn(edge); + assert(is_Proj(proj) && "CondJmp with a non-Proj"); + fprintf(F, "\tjmp %s\t\t\t/* otherwise */\n", get_cfop_target(proj, buf)); + } +} + +/** + * Emits code for conditional jump with two variables. + */ +static void emit_ia32_CondJmp(ir_node *irn, emit_env_t *env) { + FILE *F = env->out; + + lc_efprintf(ia32_get_arg_env(), F, "\tcmp %2s, %1s\t\t\t/* CondJmp(%+F, %+F) */\n", irn, irn, + get_irn_n(irn, 0), get_irn_n(irn, 1)); + finish_CondJmp(F, irn); +} + +/** + * Emits code for conditional jump with immediate. + */ +void emit_ia32_CondJmp_i(ir_node *irn, emit_env_t *env) { + FILE *F = env->out; + + lc_efprintf(ia32_get_arg_env(), F, "\tcmp %c, %1s\t\t\t/* CondJmp_i(%+F) */\n", irn, irn, get_irn_n(irn, 0)); + finish_CondJmp(F, irn); +} + +typedef struct _branch_t { + ir_node *target; + int value; +} branch_t; + +typedef struct _jmp_tbl_t { + ir_node *defProj; + int min_value; + int max_value; + int num_branches; + char *label; + branch_t *branches; +} jmp_tbl_t; + +/* Compare two variables of type branch_t */ +static int ia32_cmp_branch_t(const void *a, const void *b) { + branch_t *b1 = (branch_t *)a; + branch_t *b2 = (branch_t *)b; + + if (b1->value <= b2->value) + return -1; + else + return 1; +} + +/** + * Emits code for a SwitchJmp (creates a jump table if + * possible otherwise a cmp-jmp cascade). Port from + * cggg ia32 backend + */ +void emit_ia32_SwitchJmp(const ir_node *irn, emit_env_t *emit_env) { + unsigned long interval; + char buf[SNPRINTF_BUF_LEN]; + int last_value, i, pn, do_jmp_tbl = 1; + jmp_tbl_t tbl; + ir_node *proj; + const ir_edge_t *edge; + const lc_arg_env_t *env = ia32_get_arg_env(); + FILE *F = emit_env->out; + + /* fill the table structure */ + tbl.label = malloc(SNPRINTF_BUF_LEN); + tbl.label = get_unique_label(tbl.label, SNPRINTF_BUF_LEN, "JMPTBL_"); + tbl.defProj = NULL; + tbl.num_branches = get_irn_n_edges(irn); + tbl.branches = calloc(tbl.num_branches, sizeof(*(tbl.branches))); + tbl.min_value = INT_MAX; + tbl.max_value = INT_MIN; + + i = 0; + /* go over all proj's and collect them */ + foreach_out_edge(irn, edge) { + proj = get_edge_src_irn(edge); + assert(is_Proj(proj) && "Only proj allowed at SwitchJmp"); + + pn = get_Proj_proj(proj); + + /* create branch entry */ + tbl.branches[i].target = proj; + tbl.branches[i].value = pn; + + tbl.min_value = pn < tbl.min_value ? pn : tbl.min_value; + tbl.max_value = pn > tbl.max_value ? pn : tbl.max_value; + + /* check for default proj */ + if (pn == get_ia32_pncode(irn)) { + assert(tbl.defProj == NULL && "found two defProjs at SwitchJmp"); + tbl.defProj = proj; + } + + i++; + } + + /* sort the branches by their number */ + qsort(tbl.branches, tbl.num_branches, sizeof(*(tbl.branches)), ia32_cmp_branch_t); + + /* two-complement's magic make this work without overflow */ + interval = tbl.max_value - tbl.min_value; + + /* check value interval */ + if (interval > 16 * 1024) { + do_jmp_tbl = 0; + } + + /* check ratio of value interval to number of branches */ + if ((float)(interval + 1) / (float)tbl.num_branches > 8.0) { + do_jmp_tbl = 0; + } + + if (do_jmp_tbl) { + /* emit the table */ + if (tbl.min_value != 0) { + fprintf(F, "\tcmpl %lu, -%d", interval, tbl.min_value); + lc_efprintf(env, F, "(%1s)\t\t/* first switch value is not 0 */\n", irn); + } + else { + fprintf(F, "\tcmpl %lu, ", interval); + lc_efprintf(env, F, "%1s\t\t\t/* compare for switch */\n", irn); + } + + fprintf(F, "\tja %s\t\t\t/* default jump if out of range */\n", get_cfop_target(tbl.defProj, buf)); + + if (tbl.num_branches > 1) { + /* create table */ + + fprintf(F, "\tjmp *%s", tbl.label); + lc_efprintf(env, F, "(,%1s,4)\t\t/* get jump table entry as target */\n", irn); + + fprintf(F, "\t.section\t.rodata\t\t/* start jump table */\n"); + fprintf(F, "\t.align 4\n"); + + fprintf(F, "%s:\n", tbl.label); + fprintf(F, "\t.long %s\t\t\t/* case %d */\n", get_cfop_target(tbl.branches[0].target, buf), tbl.branches[0].value); + + last_value = tbl.branches[0].value; + for (i = 1; i < tbl.num_branches; ++i) { + while (++last_value < tbl.branches[i].value) { + fprintf(F, "\t.long %s\t\t/* default case */\n", get_cfop_target(tbl.defProj, buf)); + } + fprintf(F, "\t.long %s\t\t\t/* case %d */\n", get_cfop_target(tbl.branches[i].target, buf), last_value); + } + + fprintf(F, "\t.text\t\t\t\t/* end of jump table */\n"); + } + else { + /* one jump is enough */ + fprintf(F, "\tjmp %s\t\t/* only one case given */\n", get_cfop_target(tbl.branches[0].target, buf)); + } + } + else { // no jump table + for (i = 0; i < tbl.num_branches; ++i) { + fprintf(F, "\tcmpl %d, ", tbl.branches[i].value); + lc_efprintf(env, F, "%1s", irn); + fprintf(F, "\t\t\t/* case %d */\n", tbl.branches[i].value); + fprintf(F, "\tje %s\n", get_cfop_target(tbl.branches[i].target, buf)); + } + + fprintf(F, "\tjmp %s\t\t\t/* default case */\n", get_cfop_target(tbl.defProj, buf)); + } + + if (tbl.branches) + free(tbl.branches); +} + +/** + * Emits code for a unconditional jump. + */ +void emit_Jmp(ir_node *irn, emit_env_t *env) { + FILE *F = env->out; + + char buf[SNPRINTF_BUF_LEN]; + ir_fprintf(F, "\tjmp %s\t\t\t/* Jmp(%+F) */\n", get_cfop_target(irn, buf), get_irn_link(irn)); +} + +/** + * Emits code for a proj -> node + */ +void emit_Proj(ir_node *irn, emit_env_t *env) { + ir_node *pred = get_Proj_pred(irn); + + if (get_irn_opcode(pred) == iro_Start) { + switch(get_Proj_proj(irn)) { + case pn_Start_X_initial_exec: + emit_Jmp(irn, env); + break; + default: + break; + } + } +} + +/** + * Main emitting function + */ +void ia32_emit_node(ir_node *irn, void *env) { + emit_env_t *emit_env = env; + firm_dbg_module_t *mod = emit_env->mod; + FILE *F = emit_env->out; + + DBG((mod, LEVEL_1, "emitting code for %+F\n", irn)); + +#define IA32_EMIT(a) if (is_ia32_##a(irn)) { emit_ia32_##a(irn, emit_env); return; } +#define EMIT(a) if (get_irn_opcode(irn) == iro_##a) { emit_##a(irn, emit_env); return; } + + /* generated int emitter functions */ + IA32_EMIT(Const); + + IA32_EMIT(Add); + IA32_EMIT(Add_i); + IA32_EMIT(Sub); + IA32_EMIT(Sub_i); + IA32_EMIT(Minus); + IA32_EMIT(Inc); + IA32_EMIT(Dec); + + IA32_EMIT(Max); + IA32_EMIT(Min); + + IA32_EMIT(And); + IA32_EMIT(And_i); + IA32_EMIT(Or); + IA32_EMIT(Or_i); + IA32_EMIT(Eor); + IA32_EMIT(Eor_i); + IA32_EMIT(Not); + + IA32_EMIT(Shl); + IA32_EMIT(Shl_i); + IA32_EMIT(Shr); + IA32_EMIT(Shr_i); + IA32_EMIT(Shrs); + IA32_EMIT(Shrs_i); + IA32_EMIT(RotL); + IA32_EMIT(RotL_i); + IA32_EMIT(RotR); + + IA32_EMIT(Lea); + IA32_EMIT(Lea_i); + + IA32_EMIT(Mul); + IA32_EMIT(Mul_i); + IA32_EMIT(Mulh); + IA32_EMIT(Mulh_i); + + IA32_EMIT(Cltd); + IA32_EMIT(DivMod); + + IA32_EMIT(Store); + IA32_EMIT(Load); + + /* generated floating point emitter */ + IA32_EMIT(fConst); + + IA32_EMIT(fAdd); + IA32_EMIT(fSub); + IA32_EMIT(fMinus); + + IA32_EMIT(fMul); + IA32_EMIT(fDiv); + + IA32_EMIT(fMin); + IA32_EMIT(fMax); + + IA32_EMIT(fLoad); + IA32_EMIT(fStore); + + /* other emitter functions */ + IA32_EMIT(CondJmp); + IA32_EMIT(CondJmp_i); + IA32_EMIT(SwitchJmp); + + EMIT(Jmp); + EMIT(Proj); + + ir_fprintf(F, "\t\t\t\t\t/* %+F */\n", irn); +} + +/** + * Walks over the nodes in a block connected by scheduling edges + * and emits code for each node. + */ +void ia32_gen_block(ir_node *block, void *env) { + ir_node *irn; + + fprintf(((emit_env_t *)env)->out, "BLOCK_%ld:\n", get_irn_node_nr(block)); + sched_foreach(block, irn) { + ia32_emit_node(irn, env); + } +} + + +/** + * Emits code for function start. + */ +void ia32_emit_start(FILE *F, ir_graph *irg) { + const char *irg_name = get_entity_name(get_irg_entity(irg)); + + fprintf(F, "\t.text\n"); + fprintf(F, ".globl %s\n", irg_name); + fprintf(F, "\t.type\t%s, @function\n", irg_name); + fprintf(F, "%s:\n", irg_name); +} + +/** + * Emits code for function end + */ +void ia32_emit_end(FILE *F, ir_graph *irg) { + const char *irg_name = get_entity_name(get_irg_entity(irg)); + + fprintf(F, "\tret\n"); + fprintf(F, "\t.size\t%s, .-%s\n\n", irg_name, irg_name); +} + +/** + * Sets labels for control flow nodes (jump target) + * TODO: Jump optimization + */ +void ia32_gen_labels(ir_node *block, void *env) { + ir_node *pred; + int n = get_Block_n_cfgpreds(block); + + for (n--; n >= 0; n--) { + pred = get_Block_cfgpred(block, n); + set_irn_link(pred, block); + } +} + +/** + * Main driver + */ +void ia32_gen_routine(FILE *F, ir_graph *irg, set *reg_set) { + emit_env_t emit_env; + + emit_env.mod = firm_dbg_register("be.codegen.ia32"); + emit_env.out = F; + emit_env.reg_set = reg_set; + + cur_reg_set = reg_set; + + ia32_emit_start(F, irg); + irg_block_walk_graph(irg, ia32_gen_labels, NULL, &emit_env); + irg_block_walk_graph(irg, NULL, ia32_gen_block, &emit_env); + ia32_emit_end(F, irg); } diff --git a/ir/be/ia32/ia32_emitter.h b/ir/be/ia32/ia32_emitter.h index a029c3e27..4245b4cbb 100644 --- a/ir/be/ia32/ia32_emitter.h +++ b/ir/be/ia32/ia32_emitter.h @@ -1,16 +1,25 @@ #ifndef _IA32_EMITTER_H_ #define _IA32_EMITTER_H_ +#include "irargs_t.h" // this also inlucdes #include "irnode.h" +#include "set.h" -const char *get_dest_reg_name(ir_node *n, int num); +#include "debug.h" -const char *get_source_reg_name(ir_node *n, int num); +typedef struct _emit_env_t { + firm_dbg_module_t *mod; + FILE *out; + set *reg_set; +} emit_env_t; -char *node_const_to_str(ir_node *n); - -char *node_offset_to_str(ir_node *n); +const lc_arg_env_t *ia32_get_arg_env(void); void equalize_dest_src(FILE *F, ir_node *n); +int get_ia32_in_regnr(ir_node *irn, int pos); +const char *get_ia32_in_reg_name(ir_node *irn, int pos); + +void ia32_gen_routine(FILE *F, ir_graph *irg, set *reg_set); + #endif /* _IA32_EMITTER_H_ */ diff --git a/ir/be/ia32/ia32_gen_decls.c b/ir/be/ia32/ia32_gen_decls.c index 5390a33b1..8ec802453 100644 --- a/ir/be/ia32/ia32_gen_decls.c +++ b/ir/be/ia32/ia32_gen_decls.c @@ -8,6 +8,7 @@ #include #include #include +#include #include diff --git a/ir/be/ia32/ia32_new_nodes.c b/ir/be/ia32/ia32_new_nodes.c index 481d53683..19a6fc062 100644 --- a/ir/be/ia32/ia32_new_nodes.c +++ b/ir/be/ia32/ia32_new_nodes.c @@ -17,6 +17,7 @@ #include "irmode_t.h" #include "ircons_t.h" #include "iropt_t.h" +#include "irop.h" #include "firm_common_t.h" #include "irvrfy_t.h" @@ -24,6 +25,7 @@ #include "ia32_nodes_attr.h" #include "ia32_new_nodes.h" +#include "gen_ia32_regalloc_if.h" @@ -73,6 +75,8 @@ const char *get_sc_name(ir_node *symc) { default: assert(0 && "Unsupported SymConst"); } + + return NULL; } /** @@ -117,7 +121,7 @@ static int dump_node_ia32(ir_node *n, FILE *F, dump_reason_t reason) { case dump_node_nodeattr_txt: name = get_irn_opname(n); p = name + strlen(name) - 2; - if ((p[0] == '_' && p[1] == 'i') || is_ia32_Const(n)) { + if ((p[0] == '_' && p[1] == 'i') || is_ia32_Const(n) || is_ia32_fConst(n)) { tarval *tv = get_ia32_Immop_tarval(n); if (tv) fprintf_tv(F, tv, 1); @@ -126,7 +130,7 @@ static int dump_node_ia32(ir_node *n, FILE *F, dump_reason_t reason) { } } else if (is_ia32_Call(n)) { - ir_node *sc = get_ia32_old_ir(get_ia32_old_ir(n)); + ir_node *sc = get_ia32_old_ir(n); fprintf(F, "&%s ", get_sc_name(sc)); } @@ -248,11 +252,17 @@ void set_ia32_Immop_attr(ir_node *node, ir_node *cnst) { asmop_attr *na = get_ia32_attr(node); asmop_attr *ca = get_ia32_attr(cnst); - assert(is_ia32_Const(cnst) && "Need ia32_Const to set Immop attr"); + assert((is_ia32_Const(cnst) || is_ia32_fConst(cnst)) && "Need ia32_Const to set Immop attr"); na->tp = ca->tp; na->tv = ca->tv; - na->old_ir = ca->old_ir; + + if (ca->old_ir) { + na->old_ir = calloc(1, sizeof(*(ca->old_ir))); + memcpy(na->old_ir, ca->old_ir, sizeof(*(ca->old_ir))); + } + else + na->old_ir = NULL; } /** @@ -261,7 +271,7 @@ void set_ia32_Immop_attr(ir_node *node, ir_node *cnst) { void set_ia32_Const_attr(ir_node *ia32_cnst, ir_node *cnst) { asmop_attr *attr = get_ia32_attr(ia32_cnst); - assert(is_ia32_Const(ia32_cnst) && "Need ia32_Const to set Const attr"); + assert((is_ia32_Const(ia32_cnst) || is_ia32_fConst(ia32_cnst)) && "Need ia32_Const to set Const attr"); switch (get_irn_opcode(cnst)) { case iro_Const: @@ -285,136 +295,153 @@ void set_ia32_Const_attr(ir_node *ia32_cnst, ir_node *cnst) { * Sets the type of an ia32_Const. */ void set_ia32_Const_type(ir_node *node, int type) { - asmop_attr *attr = get_ia32_attr(node); + asmop_attr *attr = get_ia32_attr(node); - assert(is_ia32_Const(node) && "Need ia32_Const to set type"); - assert((type == asmop_Const || type == asmop_SymConst) && "Unsupported ia32_Const type"); + assert((is_ia32_Const(node) || is_ia32_fConst(node)) && "Need ia32_Const to set type"); + assert((type == asmop_Const || type == asmop_SymConst) && "Unsupported ia32_Const type"); - attr->tp = type; + attr->tp = type; } /** * Sets the attributes of an immediate operation to the specified tarval */ void set_ia32_Immop_tarval(ir_node *node, tarval *tv) { - asmop_attr *attr = get_ia32_attr(node); + asmop_attr *attr = get_ia32_attr(node); - attr->tp = asmop_Const; - attr->tv = tv; + attr->tp = asmop_Const; + attr->tv = tv; } /** * Sets the offset for a Lea. */ void set_ia32_offs(ir_node *node, tarval *offs) { - asmop_attr *attr = get_ia32_attr(node); - attr->offset = offs; + asmop_attr *attr = get_ia32_attr(node); + attr->offset = offs; } /** * Gets the offset for a Lea. */ tarval *get_ia32_offs(const ir_node *node) { - asmop_attr *attr = get_ia32_attr(node); - return attr->offset; + asmop_attr *attr = get_ia32_attr(node); + return attr->offset; } /** * Returns the argument register requirements of an ia32 node. */ const arch_register_req_t **get_ia32_in_req(const ir_node *node) { - asmop_attr *attr = get_ia32_attr(node); - return attr->in_req; + asmop_attr *attr = get_ia32_attr(node); + return attr->in_req; } /** * Returns the result register requirements of an ia32 node. */ const arch_register_req_t **get_ia32_out_req(const ir_node *node) { - asmop_attr *attr = get_ia32_attr(node); - return attr->out_req; + asmop_attr *attr = get_ia32_attr(node); + return attr->out_req; } /** - * Returns the register flag of an ia32 node. + * Sets the OUT register requirements at position pos. */ -arch_irn_flags_t get_ia32_flags(const ir_node *node) { - asmop_attr *attr = get_ia32_attr(node); - return attr->flags; +void set_ia32_regreq_out(ir_node *node, const arch_register_req_t *req, int pos) { + asmop_attr *attr = get_ia32_attr(node); + attr->out_req[pos] = req; } /** - * Returns the result register slots of an ia32 node. + * Sets the IN register requirements at position pos. */ -const arch_register_t **get_ia32_slots(const ir_node *node) { - asmop_attr *attr = get_ia32_attr(node); - return attr->slots; +void set_ia32_regreq_in(ir_node *node, const arch_register_req_t *req, int pos) { + asmop_attr *attr = get_ia32_attr(node); + attr->in_req[pos] = req; } /** - * Returns the name of the IN register at position pos. + * Returns the register flag of an ia32 node. */ -const char *get_ia32_in_reg_name(const ir_node *node, int pos) { - assert(0 && "in reg name not yet implemented"); +arch_irn_flags_t get_ia32_flags(const ir_node *node) { + asmop_attr *attr = get_ia32_attr(node); + return attr->flags; } /** - * Returns the name of the OUT register at position pos. + * Returns the result register slots of an ia32 node. */ -const char *get_ia32_out_reg_name(const ir_node *node, int pos) { - asmop_attr *attr = get_ia32_attr(node); - - assert(is_ia32_irn(node) && "Not an ia32 node."); - assert(pos < attr->n_res && "Invalid OUT position."); - - return attr->slots[pos]->name; +const arch_register_t **get_ia32_slots(const ir_node *node) { + asmop_attr *attr = get_ia32_attr(node); + return attr->slots; } /** - * Returns the index of the IN register at position pos within its register class. + * Returns the name of the OUT register at position pos. */ -int get_ia32_in_regnr(const ir_node *node, int pos) { - assert(0 && "in reg nr not yet implemented"); +const char *get_ia32_out_reg_name(const ir_node *node, int pos) { + asmop_attr *attr = get_ia32_attr(node); + + assert(is_ia32_irn(node) && "Not an ia32 node."); + assert(pos < attr->n_res && "Invalid OUT position."); + assert(attr->slots[pos] && "No register assigned"); + + return attr->slots[pos]->name; } /** * Returns the index of the OUT register at position pos within its register class. */ int get_ia32_out_regnr(const ir_node *node, int pos) { - asmop_attr *attr = get_ia32_attr(node); + asmop_attr *attr = get_ia32_attr(node); - assert(is_ia32_irn(node) && "Not an ia32 node."); - assert(pos < attr->n_res && "Invalid OUT position."); + assert(is_ia32_irn(node) && "Not an ia32 node."); + assert(pos < attr->n_res && "Invalid OUT position."); + assert(attr->slots[pos] && "No register assigned"); - return attr->slots[pos]->index; + return attr->slots[pos]->index; } /** * Sets the number of results. */ void set_ia32_n_res(ir_node *node, int n_res) { - asmop_attr *attr = get_ia32_attr(node); - attr->n_res = n_res; + asmop_attr *attr = get_ia32_attr(node); + attr->n_res = n_res; } /** * Returns the number of results. */ int get_ia32_n_res(const ir_node *node) { - asmop_attr *attr = get_ia32_attr(node); - return attr->n_res; + asmop_attr *attr = get_ia32_attr(node); + return attr->n_res; } /** * Sets the flavour of an ia32 DivMod node to flavour_Div/Mod/DivMod. */ void set_ia32_DivMod_flavour(ir_node *node, divmod_flavour_t dm_flav) { - asmop_attr *attr = get_ia32_attr(node); - attr->dm_flav = dm_flav; + asmop_attr *attr = get_ia32_attr(node); + attr->dm_flav = dm_flav; } -/* include generated register allocator interface */ -#include "gen_ia32_regalloc_if.c.inl" +/** + * Returns the projnum code. + */ +long get_ia32_pncode(const ir_node *node) { + asmop_attr *attr = get_ia32_attr(node); + return attr->pn_code; +} + +/** + * Sets the projnum code + */ +void set_ia32_pncode(ir_node *node, long code) { + asmop_attr *attr = get_ia32_attr(node); + attr->pn_code = code; +} /* Include the generated functions */ #include "gen_ia32_new_nodes.c.inl" diff --git a/ir/be/ia32/ia32_new_nodes.h b/ir/be/ia32/ia32_new_nodes.h index 58a73d298..5e44f7d7e 100644 --- a/ir/be/ia32/ia32_new_nodes.h +++ b/ir/be/ia32/ia32_new_nodes.h @@ -13,6 +13,8 @@ asmop_attr *get_ia32_attr(const ir_node *node); ir_node *get_ia32_old_ir(const ir_node *node); +const char *get_sc_name(ir_node *symc); + void set_ia32_Immop_attr(ir_node *node, ir_node *imm); tarval *get_ia32_Immop_tarval(const ir_node *node); void set_ia32_Immop_tarval(ir_node *node, tarval *tv); @@ -20,6 +22,9 @@ void set_ia32_Immop_tarval(ir_node *node, tarval *tv); void set_ia32_Const_attr(ir_node *ia32_cnst, ir_node *cnst); void set_ia32_Const_type(ir_node *node, int type); +void set_ia32_pncode(ir_node *node, long code); +long get_ia32_pncode(const ir_node *node); + void set_ia32_offs(ir_node *node, tarval *offs); tarval *get_ia32_offs(const ir_node *node); void set_ia32_n_res(ir_node *node, int n_res); @@ -32,15 +37,15 @@ const arch_register_req_t **get_ia32_in_req(const ir_node *node); const arch_register_req_t **get_ia32_out_req(const ir_node *node); const arch_register_t **get_ia32_slots(const ir_node *node); -const char *get_ia32_in_reg_name(const ir_node *node, int pos); -const char *get_ia32_out_reg_name(const ir_node *node, int pos); +void set_ia32_regreq_out(ir_node *node, const arch_register_req_t *req, int pos); +void set_ia32_regreq_in(ir_node *node, const arch_register_req_t *req, int pos); -int get_ia32_in_regnr(const ir_node *node, int pos); -int get_ia32_out_regnr(const ir_node *node, int pos); +const char *get_ia32_out_reg_name(const ir_node *node, int pos); +int get_ia32_out_regnr(const ir_node *node, int pos); int is_ia32_irn(const ir_node *node); /* Inlcude the generated headers */ -#include "gen_ia32_new_nodes.h.inl" +#include "gen_ia32_new_nodes.h" #endif /* _IA32_NEW_NODES_H_ */ diff --git a/ir/be/ia32/ia32_nodes_attr.h b/ir/be/ia32/ia32_nodes_attr.h index e89b4a651..70013ced3 100644 --- a/ir/be/ia32/ia32_nodes_attr.h +++ b/ir/be/ia32/ia32_nodes_attr.h @@ -16,6 +16,9 @@ typedef struct { divmod_flavour_t dm_flav; /**<< flavour of a DivMod (flavour_Div/Mod/DivMod) */ + long pn_code; /**<< projnum "types" (e.g. indicates the compare operator of a conditional jump + or an argument number) */ + unsigned n_res; /**<< number of results */ arch_irn_flags_t flags; /**<< indicating if spillable and/or rematerializeable */ diff --git a/ir/be/ia32/ia32_spec.pl b/ir/be/ia32/ia32_spec.pl index ffb1d39dd..1d437394f 100644 --- a/ir/be/ia32/ia32_spec.pl +++ b/ir/be/ia32/ia32_spec.pl @@ -108,7 +108,16 @@ $arch = "ia32"; %nodes = ( -# arithmetic operations +#-----------------------------------------------------------------# +# _ _ _ # +# (_) | | | | # +# _ _ __ | |_ ___ __ _ ___ _ __ _ __ ___ __| | ___ ___ # +# | | '_ \| __/ _ \/ _` |/ _ \ '__| | '_ \ / _ \ / _` |/ _ \/ __| # +# | | | | | || __/ (_| | __/ | | | | | (_) | (_| | __/\__ \ # +# |_|_| |_|\__\___|\__, |\___|_| |_| |_|\___/ \__,_|\___||___/ # +# __/ | # +# |___/ # +#-----------------------------------------------------------------# # commutative operations @@ -119,7 +128,7 @@ $arch = "ia32"; "comment" => "construct Add: Add(a, b) = Add(b, a) = a + b", "check_inout" => 1, "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "in_s1" ] }, - "emit" => '. addl %s2, %d1\t\t\t/* Add(%s1, %s2) -> %d1 */' + "emit" => '. addl %s2, %d1\t\t\t/* Add(%s1, %s2) -> %d1, (%a1, %a2) */' }, "Add_i" => { @@ -128,7 +137,7 @@ $arch = "ia32"; "comment" => "construct Add: Add(a, const) = Add(const, a) = a + const", "check_inout" => 1, "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "in_s1" ] }, - "emit" => '. addl %c, %d1\t\t\t/* Add(%c, %s1) -> %d1 */' + "emit" => '. addl %c, %d1\t\t\t/* Add(%c, %s1) -> %d1, (%a1, const) */' }, "Mul" => { @@ -138,10 +147,10 @@ $arch = "ia32"; "reg_req" => { "in" => [ "eax", "general_purpose" ], "out" => [ "eax" ] }, "emit" => ' if (mode_is_signed(get_irn_mode(n))) { -4. imull %s2\t\t\t/* signed Mul(%s1, %s2) -> %d1 */ +4. imull %s2\t\t\t/* signed Mul(%s1, %s2) -> %d1, (%a1, %a2) */ } else { -4. mull %s2\t\t\t/* unsigned Mul(%s1, %s2) -> %d1 */ +4. mull %s2\t\t\t/* unsigned Mul(%s1, %s2) -> %d1, (%a1, %a2) */ } ' }, @@ -150,14 +159,13 @@ $arch = "ia32"; "state" => "pinned", "arity" => 1, "comment" => "construct Mul: Mul(a, const) = Mul(const, a) = a * const", -# "reg_req" => { "in" => [ "eax" ], "out" => [ "eax" ] }, - "reg_req" => { "in" => [ "!eax" ], "out" => [ "eax" ] }, + "reg_req" => { "in" => [ "eax" ], "out" => [ "eax" ] }, "emit" => ' if (mode_is_signed(get_irn_mode(n))) { -4. imull %c\t\t\t/* signed Mul(%c, %s1) -> %d1 */ +4. imull %c\t\t\t/* signed Mul(%c, %s1) -> %d1, (%a1, const) */ } else { -4. mull %c\t\t\t/* unsigned Mul(%c, %s1) -> %d1 */ +4. mull %c\t\t\t/* unsigned Mul(%c, %s1) -> %d1, (%a1, const) */ } ' }, @@ -169,10 +177,10 @@ $arch = "ia32"; "reg_req" => { "in" => [ "eax", "general_purpose" ], "out" => [ "edx" ] }, "emit" => ' if (mode_is_signed(get_irn_mode(n))) { -4. imull %s2\t\t\t/* signed Mulh(%s1, %s2) -> %d1 */ +4. imull %s2\t\t\t/* signed Mulh(%s1, %s2) -> %d1, (%a1, %a2) */ } else { -4. mull %s2\t\t\t/* unsigned Mulh(%s1, %s2) -> %d1 */ +4. mull %s2\t\t\t/* unsigned Mulh(%s1, %s2) -> %d1, (%a1, %a2) */ } ' }, @@ -184,10 +192,10 @@ $arch = "ia32"; "reg_req" => { "in" => [ "eax" ], "out" => [ "edx" ] }, "emit" => ' if (mode_is_signed(get_irn_mode(n))) { -4. imull %c\t\t\t/* signed Mulh(%c, %s1) -> %d1 */ +4. imull %c\t\t\t/* signed Mulh(%c, %s1) -> %d1, (%a1, const) */ } else { -4. mull %c\t\t\t/* unsigned Mulh(%c, %s1) -> %d1 */ +4. mull %c\t\t\t/* unsigned Mulh(%c, %s1) -> %d1, (%a1, const) */ } ' }, @@ -199,7 +207,7 @@ $arch = "ia32"; "comment" => "construct And: And(a, b) = And(b, a) = a AND b", "check_inout" => 1, "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "in_s1" ] }, - "emit" => '. andl %s2, %d1\t\t\t/* And(%s1, %s2) -> %d1 */' + "emit" => '. andl %s2, %d1\t\t\t/* And(%s1, %s2) -> %d1, (%a1, %a2) */' }, "And_i" => { @@ -208,7 +216,7 @@ $arch = "ia32"; "comment" => "construct And: And(a, const) = And(const, a) = a AND const", "check_inout" => 1, "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "in_s1" ] }, - "emit" => '. andl %c, %d1\t\t\t/* And(%c, %s1) -> %d1 */' + "emit" => '. andl %c, %d1\t\t\t/* And(%c, %s1) -> %d1, (%a1, const) */' }, "Or" => { @@ -218,7 +226,7 @@ $arch = "ia32"; "comment" => "construct Or: Or(a, b) = Or(b, a) = a OR b", "check_inout" => 1, "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "in_s1" ] }, - "emit" => '. orl %s2, %d1\t\t\t/* Or(%s1, %s2) -> %d1 */' + "emit" => '. orl %s2, %d1\t\t\t/* Or(%s1, %s2) -> %d1, (%a1, %a2) */' }, "Or_i" => { @@ -227,7 +235,7 @@ $arch = "ia32"; "comment" => "construct Or: Or(a, const) = Or(const, a) = a OR const", "check_inout" => 1, "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "in_s1" ] }, - "emit" => '. orl %c, %d1\t\t\t/* Or(%c, %s1) -> %d1 */' + "emit" => '. orl %c, %d1\t\t\t/* Or(%c, %s1) -> %d1, (%a1, const) */' }, "Eor" => { @@ -237,7 +245,7 @@ $arch = "ia32"; "comment" => "construct Eor: Eor(a, b) = Eor(b, a) = a EOR b", "check_inout" => 1, "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "in_s1" ] }, - "emit" => '. xorl %s2, %d1\t\t\t/* Xor(%s1, %s2) -> %d1 */' + "emit" => '. xorl %s2, %d1\t\t\t/* Xor(%s1, %s2) -> %d1, (%a1, %a2) */' }, "Eor_i" => { @@ -246,7 +254,7 @@ $arch = "ia32"; "comment" => "construct Eor: Eor(a, const) = Eor(const, a) = a EOR const", "check_inout" => 1, "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "in_s1" ] }, - "emit" => '. xorl %c, %d1\t\t\t/* Xor(%c, %s1) -> %d1 */' + "emit" => '. xorl %c, %d1\t\t\t/* Xor(%c, %s1) -> %d1, (%a1, const) */' }, "Max" => { @@ -257,7 +265,7 @@ $arch = "ia32"; "check_inout" => 1, "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "in_s1" ] }, "emit" => -'2. cmpl %s2, %s1\t\t\t/* prepare Max (%s1 should be %d1) */ +'2. cmpl %s2, %s1\t\t\t/* prepare Max (%s1 should be %d1), (%a1, %a2) */ if (mode_is_signed(get_irn_mode(n))) { 4. cmovl %s2, %d1\t\t\t/* %s1 is less %s2 */ } @@ -275,7 +283,7 @@ $arch = "ia32"; "check_inout" => 1, "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "in_s1" ] }, "emit" => -'2. cmpl %s2, %s1\t\t\t/* prepare Min (%s1 should be %d1) */ +'2. cmpl %s2, %s1\t\t\t/* prepare Min (%s1 should be %d1), (%a1, %a2) */ if (mode_is_signed(get_irn_mode(n))) { 2. cmovg %s2, %d1\t\t\t/* %s1 is greater %s2 */ } @@ -293,7 +301,7 @@ $arch = "ia32"; "comment" => "construct Sub: Sub(a, b) = a - b", "check_inout" => 1, "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "in_s1" ] }, - "emit" => '. subl %s2, %d1\t\t\t/* Sub(%s1, %s2) -> %d1 */' + "emit" => '. subl %s2, %d1\t\t\t/* Sub(%s1, %s2) -> %d1, (%a1, %a2) */' }, "Sub_i" => { @@ -302,47 +310,49 @@ $arch = "ia32"; "comment" => "construct Sub: Sub(a, const) = a - const", "check_inout" => 1, "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "in_s1" ] }, - "emit" => '. subl %c, %d1\t\t\t/* Sub(%s1, %c) -> %d1 */' + "emit" => '. subl %c, %d1\t\t\t/* Sub(%s1, %c) -> %d1, (%a1, const) */' }, "DivMod" => { + "op_flags" => "F|L", + "state" => "exc_pinned", "arity" => 4, "comment" => "construct DivMod: DivMod(a,b) = (a / b, a % b)", - "reg_req" => { "in" => [ "eax", "general_purpose", "edx" ], "out" => [ "eax", "edx" ] }, "emit" => ' if (mode_is_signed(get_irn_mode(n))) { -4. idivl %s2\t\t\t/* signed Mod(%s1, %s2) -> %d1 */ +4. idivl %s2\t\t\t/* signed Mod(%s1, %s2) -> %d1, (%a2, %a3, %4) */ } else { -4. divl %s2\t\t\t/* unsigned Mod(%s1, %s2) -> %d1 */ +4. divl %s2\t\t\t/* unsigned Mod(%s1, %s2) -> %d1, (%a2, %a3, %a4) */ } ', "args" => [ - { "type" => "ir_node *", "name" => "mem" }, - { "type" => "ir_node *", "name" => "divisor" }, { "type" => "ir_node *", "name" => "dividend" }, + { "type" => "ir_node *", "name" => "divisor" }, + { "type" => "ir_node *", "name" => "mem" }, { "type" => "divmod_flavour_t", "name" => "dm_flav" }, # flavours (flavour_Div, flavour_Mod, flavour_DivMod) { "type" => "ir_mode *", "name" => "mode" }, ], "rd_constructor" => " ir_node *res; ir_node *in[4]; + asmop_attr *attr; if (!op_ia32_DivMod) assert(0); - in[0] = mem; - in[2] = dividend; + in[1] = divisor; + in[3] = mem; if (mode_is_signed(mode)) { ir_node *cltd; - /* in signed mode , we need to sign extend the divisor */ + /* in signed mode , we need to sign extend the dividend */ cltd = new_rd_ia32_Cltd(db, current_ir_graph, block, divisor, mode_T); - in[1] = new_rd_Proj(db, current_ir_graph, block, cltd, mode, pn_EAX); - in[3] = new_rd_Proj(db, current_ir_graph, block, cltd, mode, pn_EDX); + in[0] = new_rd_Proj(db, current_ir_graph, block, cltd, mode_Is, pn_EAX); + in[2] = new_rd_Proj(db, current_ir_graph, block, cltd, mode_Is, pn_EDX); } else { - in[1] = divisor; - in[3] = new_rd_ia32_Const(db, current_ir_graph, block, mode); + in[0] = dividend; + in[2] = new_rd_ia32_Const(db, current_ir_graph, block, mode_Iu); set_ia32_Const_type(in[2], asmop_Const); set_ia32_Immop_tarval(in[2], get_tarval_null(mode_Iu)); } @@ -352,6 +362,20 @@ $arch = "ia32"; set_ia32_DivMod_flavour(res, dm_flav); set_ia32_n_res(res, 2); + attr = get_ia32_attr(res); + + attr->in_req = calloc(4, sizeof(arch_register_req_t *)); + attr->in_req[0] = &ia32_default_req_ia32_general_purpose_eax; + attr->in_req[1] = &ia32_default_req_ia32_general_purpose; + attr->in_req[2] = &ia32_default_req_ia32_general_purpose_edx; + attr->in_req[3] = &ia32_default_req_none; + + attr->out_req = calloc(2, sizeof(arch_register_req_t *)); + attr->out_req[0] = &ia32_default_req_ia32_general_purpose_eax; + attr->out_req[1] = &ia32_default_req_ia32_general_purpose_edx; + + attr->slots = calloc(2, sizeof(arch_register_t *)); + return res; " }, @@ -362,7 +386,7 @@ $arch = "ia32"; "comment" => "construct Shl: Shl(a, b) = a << b", "check_inout" => 1, "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "in_s1" ] }, - "emit" => '. shll %s2, %d1\t\t\t/* Shl(%s1, %s2) -> %d1 */' + "emit" => '. shll %s2, %d1\t\t\t/* Shl(%s1, %s2) -> %d1, (%a1, %a2) */' }, "Shl_i" => { @@ -371,7 +395,7 @@ $arch = "ia32"; "comment" => "construct Shl: Shl(a, const) = a << const", "check_inout" => 1, "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "in_s1" ] }, - "emit" => '. shll %c, %d1\t\t\t/* Shl(%s1, %c) -> %d1 */' + "emit" => '. shll %c, %d1\t\t\t/* Shl(%s1, %c) -> %d1, (%a1, const) */' }, "Shr" => { @@ -380,7 +404,7 @@ $arch = "ia32"; "comment" => "construct Shr: Shr(a, b) = a >> b", "check_inout" => 1, "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "in_s1" ] }, - "emit" => '. shrl %s2, %d1\t\t\t/* Shr(%s1, %s2) -> %d1 */' + "emit" => '. shrl %s2, %d1\t\t\t/* Shr(%s1, %s2) -> %d1, (%a1, %a2) */' }, "Shr_i" => { @@ -389,7 +413,7 @@ $arch = "ia32"; "comment" => "construct Shr: Shr(a, const) = a >> const", "check_inout" => 1, "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "in_s1" ] }, - "emit" => '. shrl %c, %d1\t\t\t/* Shr(%s1, %c) -> %d1 */' + "emit" => '. shrl %c, %d1\t\t\t/* Shr(%s1, %c) -> %d1, (%a1, const) */' }, "Shrs" => { @@ -398,7 +422,7 @@ $arch = "ia32"; "comment" => "construct Shrs: Shrs(a, b) = a >> b", "check_inout" => 1, "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "in_s1" ] }, - "emit" => '. sarl %s2, %d1\t\t\t/* Shrs(%s1, %s2) -> %d1 */' + "emit" => '. sarl %s2, %d1\t\t\t/* Shrs(%s1, %s2) -> %d1, (%a1, %a2) */' }, "Shrs_i" => { @@ -407,7 +431,7 @@ $arch = "ia32"; "comment" => "construct Shrs: Shrs(a, const) = a >> const", "check_inout" => 1, "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "in_s1" ] }, - "emit" => '. sarl %c, %d1\t\t\t/* Shrs(%s1, %c) -> %d1 */' + "emit" => '. sarl %c, %d1\t\t\t/* Shrs(%s1, %c) -> %d1, (%a1, const) */' }, "RotR" => { @@ -416,7 +440,7 @@ $arch = "ia32"; "comment" => "construct RotR: RotR(a, b) = a ROTR b", "check_inout" => 1, "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "in_s1" ] }, - "emit" => '. rorl %s2, %d1\t\t\t/* RotR(%s1, %s2) -> %d1 */' + "emit" => '. rorl %s2, %d1\t\t\t/* RotR(%s1, %s2) -> %d1, (%a1, %a2) */' }, "RotL" => { @@ -425,7 +449,7 @@ $arch = "ia32"; "comment" => "construct RotL: RotL(a, b) = a ROTL b", "check_inout" => 1, "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "in_s1" ] }, - "emit" => '. roll %s2, %d1\t\t\t/* RotL(%s1, %s2) -> %d1 */' + "emit" => '. roll %s2, %d1\t\t\t/* RotL(%s1, %s2) -> %d1, (%a1, %a2) */' }, "RotL_i" => { @@ -434,7 +458,7 @@ $arch = "ia32"; "comment" => "construct RotL: RotL(a, const) = a ROTL const", "check_inout" => 1, "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "in_s1" ] }, - "emit" => '. roll %c, %d1\t\t\t/* RotL(%s1, %c) -> %d1 */' + "emit" => '. roll %c, %d1\t\t\t/* RotL(%s1, %c) -> %d1, (%a1, const) */' }, "Minus" => { @@ -443,7 +467,7 @@ $arch = "ia32"; "comment" => "construct Minus: Minus(a) = -a", "check_inout" => 1, "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "in_s1" ] }, - "emit" => '. negl %d1\t\t\t/* Neg(%s1) -> %d1 */' + "emit" => '. negl %d1\t\t\t/* Neg(%s1) -> %d1, (%a1) */' }, "Inc" => { @@ -452,7 +476,7 @@ $arch = "ia32"; "comment" => "construct Increment: Inc(a) = a++", "check_inout" => 1, "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "in_s1" ] }, - "emit" => '. incl %d1\t\t\t/* Inc(%s1) -> %d1 */' + "emit" => '. incl %d1\t\t\t/* Inc(%s1) -> %d1, (%a1) */' }, "Dec" => { @@ -461,7 +485,7 @@ $arch = "ia32"; "comment" => "construct Decrement: Dec(a) = a--", "check_inout" => 1, "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "in_s1" ] }, - "emit" => '. decl %d1\t\t\t/* Dec(%s1) -> %d1 */' + "emit" => '. decl %d1\t\t\t/* Dec(%s1) -> %d1, (%a1) */' }, "Not" => { @@ -470,7 +494,7 @@ $arch = "ia32"; "comment" => "construct Not: Not(a) = !a", "check_inout" => 1, "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "in_s1" ] }, - "emit" => '. notl %d1\t\t\t/* Not(%s1) -> %d1 */' + "emit" => '. notl %d1\t\t\t/* Not(%s1) -> %d1, (%a1) */' }, # other operations @@ -481,32 +505,56 @@ $arch = "ia32"; "comment" => "construct Conv: Conv(a) = (conv)a" }, -"Cmp" => { - "op_flags" => "C", +"CondJmp" => { + "op_flags" => "C|L|X|Y", "arity" => 2, - "comment" => "construct Cmp: Cmp(a, b) = a CMP b", - "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "flag_register" ] }, - "emit" => '. cmpl %s2, %s1\t\t\t/* Cmp(%s1, %s2) -> flags */' + "comment" => "construct conditional jump: CMP A, B && JMPxx LABEL", + "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "none", "flag_register" ] }, }, -"Cmp_i" => { +"CondJmp_i" => { + "op_flags" => "L|X|Y", "arity" => 1, - "comment" => "construct Cmp: Cmp(a, const) = Cmp(const, a) = a CMP const", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "flag_register" ] }, - "emit" => '. cmpl %c, %s1\t\t\t/* Cmp(%s1, %c) -> flags */' + "comment" => "construct conditional jump: CMP A, const && JMPxx LABEL", + "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "none", "flag_register" ] }, }, -"Cond" => { +"SwitchJmp" => { + "op_flags" => "L|X|Y", "arity" => 1, - "comment" => "construct Cond: evaluate Cmp node", - "reg_req" => { "in" => [ "flag_register" ] } + "comment" => "construct switch", + "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "flag_register" ] }, }, "Const" => { + "op_flags" => "c", "arity" => "0", "remat" => 1, "comment" => "represents an integer constant", "reg_req" => { "out" => [ "general_purpose" ] }, + "emit" => '. movl %c, %d1\t\t\t/* Mov Const into register */', + "cmp_attr" => +' + if (attr_a->tp == attr_b->tp) { + if (attr_a->tp == asmop_SymConst) { + if (attr_a->old_ir == NULL || attr_b->old_ir == NULL) + return 1; + else + return strcmp(get_sc_name(attr_a->old_ir), get_sc_name(attr_b->old_ir)); + } + else { + if (attr_a->old_ir == NULL || attr_b->old_ir == NULL) + return 1; + + if (tarval_cmp(attr_a->tv, attr_b->tv) == pn_Cmp_Eq) + return 0; + else + return 1; + } + } + else + return 1; +' }, "Cltd" => { @@ -514,70 +562,257 @@ $arch = "ia32"; "remat" => 1, "comment" => "construct Cltd: sign extend EAX -> EDX:EAX", "reg_req" => { "in" => [ "eax" ], "out" => [ "eax", "edx" ] }, - "emit" => '. cltd\t\t\t/* sign extend EAX -> EDX:EAX */' + "emit" => '. cltd\t\t\t/* sign extend EAX -> EDX:EAX, (%a1) */' }, # Load / Store "Load" => { + "op_flags" => "L|F", + "state" => "exc_pinned", "arity" => 2, "remat" => 1, - "comment" => "construct Load: Load(mem-edge, ptr) = LD ptr", - "reg_req" => { "in" => [ "none", "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. movl (%s1), %d1\t\t\t/* Load((%s1)) -> %d1 */' + "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg", + "reg_req" => { "in" => [ "general_purpose", "none" ], "out" => [ "general_purpose" ] }, + "emit" => '. movl (%s1), %d1\t\t\t/* Load((%s1)) -> %d1, (%a1) */' }, "Store" => { + "op_flags" => "L|F", + "state" => "exc_pinned", "arity" => 3, "remat" => 1, - "comment" => "construct Store: Store(mem-edge, ptr, val) = ST ptr,val", - "reg_req" => { "in" => [ "none", "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. movl %s1, (%d1)\t\t\t/* Store(%s1) -> (%d1) */' + "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", + "reg_req" => { "in" => [ "general_purpose", "general_purpose", "none" ] }, + "emit" => '. movl %s2, (%s1)\t\t\t/* Store(%s1) -> (%s2), (%a1, %a2) */' }, "Lea" => { "arity" => 2, "comment" => "construct Lea: Lea(a,b) = lea offs(a,b,const) | res = a + b * const + offs with const = 0,1,2,4,8", "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. leal %o(%s1, %s2, %c), %d1\t\t\t/* %d1 = %s1 + %s2 << %c + %o */' + "emit" => '. leal %o(%s1, %s2, %c), %d1\t\t/* %d1 = %s1 + %s2 << %c + %o, (%a1, %a2) */' }, "Lea_i" => { "arity" => 1, "comment" => "construct Lea: Lea(a) = lea offs(a) | res = a + offs", "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. leal %c(%s1), %d1\t\t\t/* %d1 = %s1 + %c */' + "emit" => '. leal %c(%s1), %d1\t\t\t/* %d1 = %s1 + %c, (%a1)*/' }, -"Jmp" => { - "arity" => 0, - "comment" => "construct Jump: Jmp(Label)", - "emit" => '. jmp %l /* jump to label %l */' +"RegParam" => { + "arity" => 1, + "comment" => "constructs a Register Parameter to cover parameters passed in register", + "reg_req" => { "in" => [ "none" ], "out" => [ "none" ] }, + "cmp_attr" => +' + return (attr_a->pn_code != attr_b->pn_code); +' }, -# Call +"StackParam" => { + "arity" => 1, + "comment" => "constructs a Stack Parameter to retrieve a parameter from Stack", + "reg_req" => { "in" => [ "none" ], "out" => [ "general_purpose" ] }, + "cmp_attr" => +' + return (attr_a->pn_code != attr_b->pn_code); +' +}, -"Call" => { +"StackArg" => { + "arity" => 2, + "comment" => "constructs a Stack Argument to pass an argument on Stack", + "reg_req" => { "in" => [ "none", "general_purpose" ], "out" => [ "none" ] }, + "cmp_attr" => +' + return (attr_a->pn_code != attr_b->pn_code); +' +}, + +#--------------------------------------------------------# +# __ _ _ _ # +# / _| | | | | | # +# | |_| | ___ __ _| |_ _ __ ___ __| | ___ ___ # +# | _| |/ _ \ / _` | __| | '_ \ / _ \ / _` |/ _ \/ __| # +# | | | | (_) | (_| | |_ | | | | (_) | (_| | __/\__ \ # +# |_| |_|\___/ \__,_|\__| |_| |_|\___/ \__,_|\___||___/ # +#--------------------------------------------------------# + +# commutative operations + +"fAdd" => { + "op_flags" => "C", + "arity" => 2, + "remat" => 1, + "check_inout" => 1, + "comment" => "construct SSE Add: Add(a, b) = Add(b, a) = a + b", + "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "in_s1" ] }, + "emit" => '. add%m %s2, %d1\t\t\t/* SSE Add(%s1, %s2) -> %d1 */' +}, + +"fMul" => { + "op_flags" => "C", + "arity" => 2, + "check_inout" => 1, + "comment" => "construct SSE Mul: Mul(a, b) = Mul(b, a) = a * b", + "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "in_s1" ] }, + "emit" =>'. muls%m %s2, %d1\t\t\t/* SSE Mul(%s1, %s2) -> %d1 */' +}, + +"fMax" => { + "op_flags" => "C", + "arity" => 2, + "remat" => 1, + "check_inout" => 1, + "comment" => "construct SSE Max: Max(a, b) = Max(b, a) = a > b ? a : b", + "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "in_s1" ] }, + "emit" =>'. maxs%m %s2, %d1\t\t\t/* SSE Max(%s1, %s2) -> %d1 */' +}, + +"fMin" => { + "op_flags" => "C", + "arity" => 2, + "remat" => 1, + "check_inout" => 1, + "comment" => "construct SSE Min: Min(a, b) = Min(b, a) = a < b ? a : b", + "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "in_s1" ] }, + "emit" =>'. mins%m %s2, %d1\t\t\t/* SSE Min(%s1, %s2) -> %d1 */' +}, + +# not commutative operations + +"fSub" => { + "arity" => 2, + "remat" => 1, + "check_inout" => 1, + "comment" => "construct SSE Sub: Sub(a, b) = a - b", + "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "in_s1" ] }, + "emit" => '. subs%m %s2, %d1\t\t\t/* SSE Sub(%s1, %s2) -> %d1 */' +}, + +"fDiv" => { + "arity" => 2, + "remat" => 1, + "check_inout" => 1, + "comment" => "construct SSE Div: Div(a, b) = a / b", + "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "in_s1" ] }, + "emit" => '. divs%m %s2, %d1\t\t\t/* SSE Div(%s1, %s2) -> %d1 */' +}, + +"fMinus" => { + "arity" => 1, + "remat" => 1, + "check_inout" => 1, + "comment" => "construct SSE Minus: Minus(a) = -a", + "reg_req" => { "in" => [ "floating_point" ], "out" => [ "in_s1" ] }, + "emit" => '. xorp%m c %d1\t\t\t/* SSE Minus(%s1) -> %d1 */' +}, + +# other operations + +"fConv" => { "arity" => 1, - "spill" => 0, - "comment" => "construct Call: Call(...)", - "args" => [ { "type" => "ir_node *", "name" => "old_call" } ], - "rd_constructor" => -" ir_node *res; - ir_node *in[1]; - asmop_attr *attr; + "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "in_s1" ] }, + "comment" => "construct Conv: Conv(a) = (conv)a" +}, - if (!op_ia32_Call) assert(0); +"fCondJmp" => { + "op_flags" => "C|L|X|Y", + "arity" => 2, + "comment" => "construct conditional jump: CMP A, B && JMPxx LABEL", + "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "none", "flag_register" ] }, +}, - in[0] = get_Call_mem(old_call); +"fConst" => { + "op_flags" => "c", + "arity" => "0", + "remat" => 1, + "comment" => "represents a SSE constant", + "reg_req" => { "out" => [ "floating_point" ] }, + "emit" => '. mov%m %c, %d1\t\t\t/* Mov fConst into register */', + "cmp_attr" => +' + if (attr_a->tp == attr_b->tp) { + if (attr_a->tp == asmop_SymConst) { + if (attr_a->old_ir == NULL || attr_b->old_ir == NULL) + return 1; + else + return strcmp(get_sc_name(attr_a->old_ir), get_sc_name(attr_b->old_ir)); + } + else { + if (attr_a->old_ir == NULL || attr_b->old_ir == NULL) + return 1; + + if (tarval_cmp(attr_a->tv, attr_b->tv) == pn_Cmp_Eq) + return 0; + else + return 1; + } + } + else + return 1; +' +}, - res = new_ir_node(db, irg, block, op_ia32_Call, mode_T, 1, in); +# Load / Store - attr = get_ia32_attr(res); - attr->old_ir = get_Call_ptr(old_call); - attr->n_res = 1; +"fLoad" => { + "op_flags" => "L|F", + "state" => "exc_pinned", + "arity" => 2, + "remat" => 1, + "comment" => "construct SSE Load: Load(ptr, mem) = LD ptr", + "reg_req" => { "in" => [ "general_purpose", "none" ], "out" => [ "floating_point" ] }, + "emit" => '. movl (%s1), %d1\t\t\t/* Load((%s1)) -> %d1 */' +}, - return res; +"fStore" => { + "op_flags" => "L|F", + "state" => "exc_pinned", + "arity" => 3, + "remat" => 1, + "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", + "reg_req" => { "in" => [ "general_purpose", "floating_point", "none" ] }, + "emit" => '. movl %s2, (%s1)\t\t\t/* Store(%s2) -> (%s1), (%a1, %a2) */' +}, + +"fStackParam" => { + "arity" => 1, + "comment" => "constructs a Stack Parameter to retrieve a SSE parameter from Stack", + "reg_req" => { "in" => [ "none" ], "out" => [ "floating_point" ] }, + "cmp_attr" => +' + return (attr_a->pn_code != attr_b->pn_code); +' +}, + +"fStackArg" => { + "arity" => 2, + "comment" => "constructs a Stack Argument to pass an argument on Stack", + "reg_req" => { "in" => [ "none", "floating_point" ], "out" => [ "none" ] }, + "cmp_attr" => +' + return (attr_a->pn_code != attr_b->pn_code); +' +}, + +# Call + +"Call" => { + "op_flags" => "L|F", + "state" => "mem_pinned", + "arity" => "variable", + "spill" => 0, + "comment" => "construct Call: Call(...)", + "args" => [ + { "type" => "int", "name" => "n" }, + { "type" => "ir_node **", "name" => "in" } + ], + "rd_constructor" => +" if (!op_ia32_Call) assert(0); + return new_ir_node(db, irg, block, op_ia32_Call, mode_T, n, in); " } diff --git a/ir/be/ia32/ia32_transform.c b/ir/be/ia32/ia32_transform.c index b6fdb10b2..5647fa9b6 100644 --- a/ir/be/ia32/ia32_transform.c +++ b/ir/be/ia32/ia32_transform.c @@ -6,9 +6,11 @@ #include "irgraph_t.h" #include "irmode_t.h" #include "irgmod.h" +#include "iredges.h" +#include "irvrfy.h" #include "ircons.h" #include "dbginfo.h" -#include "irop_t.h" +#include "iropt_t.h" #include "debug.h" #include "ia32_nodes_attr.h" @@ -16,18 +18,83 @@ #include "ia32_transform.h" #include "ia32_new_nodes.h" +#include "gen_ia32_regalloc_if.h" + extern ir_op *get_op_Mulh(void); +static int maxnum_gpreg_args = 3; /* maximum number of int arguments passed in registers; default 3 */ +static int maxnum_fpreg_args = 5; /* maximum number of float arguments passed in registers; default 5 */ + +static const arch_register_req_t **current_gpreg_param_req; +static const arch_register_req_t **current_fpreg_param_req; + +/* this is the order of the assigned registers usesd for parameter passing */ + +const arch_register_req_t *gpreg_param_req_std[] = { + &ia32_default_req_ia32_general_purpose_eax, + &ia32_default_req_ia32_general_purpose_ecx, + &ia32_default_req_ia32_general_purpose_edx, + &ia32_default_req_ia32_general_purpose_ebx, + &ia32_default_req_ia32_general_purpose_edi, + &ia32_default_req_ia32_general_purpose_esi +}; + +const arch_register_req_t *gpreg_param_req_this[] = { + &ia32_default_req_ia32_general_purpose_ecx, + &ia32_default_req_ia32_general_purpose_eax, + &ia32_default_req_ia32_general_purpose_edx, + &ia32_default_req_ia32_general_purpose_ebx, + &ia32_default_req_ia32_general_purpose_edi, + &ia32_default_req_ia32_general_purpose_esi +}; + +const arch_register_req_t *fpreg_param_req_std[] = { + &ia32_default_req_ia32_floating_point_xmm0, + &ia32_default_req_ia32_floating_point_xmm1, + &ia32_default_req_ia32_floating_point_xmm2, + &ia32_default_req_ia32_floating_point_xmm3, + &ia32_default_req_ia32_floating_point_xmm4, + &ia32_default_req_ia32_floating_point_xmm5, + &ia32_default_req_ia32_floating_point_xmm6, + &ia32_default_req_ia32_floating_point_xmm7 +}; + +const arch_register_req_t *fpreg_param_req_this[] = { + NULL, /* in case of a "this" pointer, the first parameter must not be a float */ + &ia32_default_req_ia32_floating_point_xmm0, + &ia32_default_req_ia32_floating_point_xmm1, + &ia32_default_req_ia32_floating_point_xmm2, + &ia32_default_req_ia32_floating_point_xmm3, + &ia32_default_req_ia32_floating_point_xmm4, + &ia32_default_req_ia32_floating_point_xmm5, + &ia32_default_req_ia32_floating_point_xmm6, + &ia32_default_req_ia32_floating_point_xmm7 +}; + + + +/**************************************************************************************************** + * _ _ __ _ _ + * | | | | / _| | | (_) + * _ __ ___ __| | ___ | |_ _ __ __ _ _ __ ___| |_ ___ _ __ _ __ ___ __ _| |_ _ ___ _ __ + * | '_ \ / _ \ / _` |/ _ \ | __| '__/ _` | '_ \/ __| _/ _ \| '__| '_ ` _ \ / _` | __| |/ _ \| '_ \ + * | | | | (_) | (_| | __/ | |_| | | (_| | | | \__ \ || (_) | | | | | | | | (_| | |_| | (_) | | | | + * |_| |_|\___/ \__,_|\___| \__|_| \__,_|_| |_|___/_| \___/|_| |_| |_| |_|\__,_|\__|_|\___/|_| |_| + * + ****************************************************************************************************/ + + + /* determine if one operator is an Imm */ static ir_node *get_immediate_op(ir_node *op1, ir_node *op2) { - if (op1) - return is_ia32_Const(op1) ? op1 : (is_ia32_Const(op2) ? op2 : NULL); - else return is_ia32_Const(op2) ? op2 : NULL; + if (op1) + return is_ia32_Const(op1) ? op1 : (is_ia32_Const(op2) ? op2 : NULL); + else return is_ia32_Const(op2) ? op2 : NULL; } /* determine if one operator is not an Imm */ static ir_node *get_expr_op(ir_node *op1, ir_node *op2) { - return !is_ia32_Const(op1) ? op1 : (!is_ia32_Const(op2) ? op2 : NULL); + return !is_ia32_Const(op1) ? op1 : (!is_ia32_Const(op2) ? op2 : NULL); } @@ -42,35 +109,35 @@ static ir_node *get_expr_op(ir_node *op1, ir_node *op2) { * @return the created ia23 Add_i node */ static ir_node *gen_imm_Add(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node *expr_op, ir_node *const_op, ir_mode *mode) { - ir_node *new_op; - tarval *tv = get_ia32_Immop_tarval(const_op); - int normal_add = 0; - tarval_classification_t class_tv, class_negtv; - - /* const_op: tarval or SymConst? */ - if (tv) { - /* optimize tarvals */ - class_tv = classify_tarval(tv); - class_negtv = classify_tarval(tarval_neg(tv)); - - if (class_tv == TV_CLASSIFY_ONE) { /* + 1 == INC */ - DBG((mod, LEVEL_2, "optimizing Add(1) to Inc ... ")); - new_op = new_rd_ia32_Inc(dbg, current_ir_graph, block, expr_op, mode); - } - else if (class_tv == TV_CLASSIFY_ALL_ONE || class_negtv == TV_CLASSIFY_ONE) { /* + (-1) == DEC */ - DBG((mod, LEVEL_2, "optimizing Add(-1) to Dec ... ")); - new_op = new_rd_ia32_Dec(dbg, current_ir_graph, block, expr_op, mode); - } - else - normal_add = 1; - } - else - normal_add = 1; - - if (normal_add) - new_op = new_rd_ia32_Lea_i(dbg, current_ir_graph, block, expr_op, mode); - - return new_op; + ir_node *new_op; + tarval *tv = get_ia32_Immop_tarval(const_op); + int normal_add = 0; + tarval_classification_t class_tv, class_negtv; + + /* const_op: tarval or SymConst? */ + if (tv) { + /* optimize tarvals */ + class_tv = classify_tarval(tv); + class_negtv = classify_tarval(tarval_neg(tv)); + + if (class_tv == TV_CLASSIFY_ONE) { /* + 1 == INC */ + DBG((mod, LEVEL_2, "optimizing Add(1) to Inc ... ")); + new_op = new_rd_ia32_Inc(dbg, current_ir_graph, block, expr_op, mode); + } + else if (class_tv == TV_CLASSIFY_ALL_ONE || class_negtv == TV_CLASSIFY_ONE) { /* + (-1) == DEC */ + DBG((mod, LEVEL_2, "optimizing Add(-1) to Dec ... ")); + new_op = new_rd_ia32_Dec(dbg, current_ir_graph, block, expr_op, mode); + } + else + normal_add = 1; + } + else + normal_add = 1; + + if (normal_add) + new_op = new_rd_ia32_Lea_i(dbg, current_ir_graph, block, expr_op, mode); + + return new_op; } /** @@ -84,50 +151,58 @@ static ir_node *gen_imm_Add(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *bloc * @return the created ia32 Add node */ static ir_node *gen_Add(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node *op1, ir_node *op2, ir_mode *mode) { - /* try to optimize with LEA */ - ir_node *shli_op = is_ia32_Shl_i(op1) ? op1 : (is_ia32_Shl_i(op2) ? op2 : NULL); - ir_node *expr_op = shli_op == op1 ? op2 : (shli_op == op2 ? op1 : NULL); - int normal_add = 0; - ir_node *new_op; - - if (shli_op) { - tarval *tv = get_ia32_Immop_tarval(shli_op); - tarval *offs = NULL; - if (tv) { - switch (get_tarval_long(tv)) { - case 1: - case 2: - case 3: - // If the other operand of the LEA is an LEA_i (that means LEA ofs(%regop1)), - // we can skip it and transform the whole sequence into LEA ofs(%regop1, %regop2, shl_val), - if (is_ia32_Lea_i(expr_op)) { - offs = get_ia32_Immop_tarval(expr_op); - expr_op = get_irn_n(expr_op, 0); - } - - new_op = new_rd_ia32_Lea(dbg, current_ir_graph, block, expr_op, get_irn_n(shli_op, 0), mode); - set_ia32_Immop_tarval(new_op, tv); - set_ia32_offs(new_op, offs); - - break; - default: - normal_add = 1; - break; - } - } - else - normal_add = 1; - } - else - normal_add = 1; - - if (normal_add) { - new_op = new_rd_ia32_Lea(dbg, current_ir_graph, block, op1, op2, mode); - set_ia32_Immop_tarval(new_op, get_tarval_one(mode_Iu)); - set_ia32_offs(new_op, NULL); - } - - return new_op; + ir_node *shli_op; + ir_node *expr_op; + ir_node *new_op; + int normal_add = 0; + + if (mode_is_float(mode)) { + return new_rd_ia32_fAdd(dbg, current_ir_graph, block, op1, op2, mode); + } + + /* try to optimize with LEA */ + + shli_op = is_ia32_Shl_i(op1) ? op1 : (is_ia32_Shl_i(op2) ? op2 : NULL); + expr_op = shli_op == op1 ? op2 : (shli_op == op2 ? op1 : NULL); + + if (shli_op) { + tarval *tv = get_ia32_Immop_tarval(shli_op); + tarval *offs = NULL; + if (tv) { + switch (get_tarval_long(tv)) { + case 1: + case 2: + case 3: + // If the other operand of the LEA is an LEA_i (that means LEA ofs(%regop1)), + // we can skip it and transform the whole sequence into LEA ofs(%regop1, %regop2, shl_val), + if (is_ia32_Lea_i(expr_op)) { + offs = get_ia32_Immop_tarval(expr_op); + expr_op = get_irn_n(expr_op, 0); + } + + new_op = new_rd_ia32_Lea(dbg, current_ir_graph, block, expr_op, get_irn_n(shli_op, 0), mode); + set_ia32_Immop_tarval(new_op, tv); + set_ia32_offs(new_op, offs); + + break; + default: + normal_add = 1; + break; + } + } + else + normal_add = 1; + } + else + normal_add = 1; + + if (normal_add) { + new_op = new_rd_ia32_Lea(dbg, current_ir_graph, block, op1, op2, mode); + set_ia32_Immop_tarval(new_op, get_tarval_one(mode_Iu)); + set_ia32_offs(new_op, NULL); + } + + return new_op; } @@ -142,7 +217,7 @@ static ir_node *gen_Add(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, i * @return the created ia23 Mul_i node */ static ir_node *gen_imm_Mul(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node *expr_op, ir_node *const_op, ir_mode *mode) { - return new_rd_ia32_Mul_i(dbg, current_ir_graph, block, expr_op, mode); + return new_rd_ia32_Mul_i(dbg, current_ir_graph, block, expr_op, mode); } /** @@ -156,7 +231,10 @@ static ir_node *gen_imm_Mul(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *bloc * @return the created ia32 Mul node */ ir_node *gen_Mul(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node *op1, ir_node *op2, ir_mode *mode) { - return new_rd_ia32_Mul(dbg, current_ir_graph, block, op1, op2, mode); + if (mode_is_float(mode)) { + return new_rd_ia32_fMul(dbg, current_ir_graph, block, op1, op2, mode); + } + return new_rd_ia32_Mul(dbg, current_ir_graph, block, op1, op2, mode); } @@ -173,7 +251,7 @@ ir_node *gen_Mul(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node * @return the created ia23 Mulh_i node */ static ir_node *gen_imm_Mulh(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node *expr_op, ir_node *const_op, ir_mode *mode) { - return new_rd_ia32_Mulh_i(dbg, current_ir_graph, block, expr_op, mode); + return new_rd_ia32_Mulh_i(dbg, current_ir_graph, block, expr_op, mode); } /** @@ -189,7 +267,7 @@ static ir_node *gen_imm_Mulh(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *blo * @return the created ia32 Mulh node */ static ir_node *gen_Mulh(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node *op1, ir_node *op2, ir_mode *mode) { - return new_rd_ia32_Mulh(dbg, current_ir_graph, block, op1, op2, mode); + return new_rd_ia32_Mulh(dbg, current_ir_graph, block, op1, op2, mode); } @@ -204,7 +282,7 @@ static ir_node *gen_Mulh(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, * @return the created ia23 And_i node */ static ir_node *gen_imm_And(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node *expr_op, ir_node *const_op, ir_mode *mode) { - return new_rd_ia32_And_i(dbg, current_ir_graph, block, expr_op, mode); + return new_rd_ia32_And_i(dbg, current_ir_graph, block, expr_op, mode); } /** @@ -218,7 +296,7 @@ static ir_node *gen_imm_And(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *bloc * @return the created ia32 And node */ static ir_node *gen_And(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node *op1, ir_node *op2, ir_mode *mode) { - return new_rd_ia32_And(dbg, current_ir_graph, block, op1, op2, mode); + return new_rd_ia32_And(dbg, current_ir_graph, block, op1, op2, mode); } @@ -233,7 +311,7 @@ static ir_node *gen_And(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, i * @return the created ia23 Or_i node */ static ir_node *gen_imm_Or(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node *expr_op, ir_node *const_op, ir_mode *mode) { - return new_rd_ia32_Or_i(dbg, current_ir_graph, block, expr_op, mode); + return new_rd_ia32_Or_i(dbg, current_ir_graph, block, expr_op, mode); } /** @@ -247,7 +325,7 @@ static ir_node *gen_imm_Or(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block * @return the created ia32 Or node */ static ir_node *gen_Or(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node *op1, ir_node *op2, ir_mode *mode) { - return new_rd_ia32_Or(dbg, current_ir_graph, block, op1, op2, mode); + return new_rd_ia32_Or(dbg, current_ir_graph, block, op1, op2, mode); } @@ -262,7 +340,7 @@ static ir_node *gen_Or(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir * @return the created ia23 Eor_i node */ static ir_node *gen_imm_Eor(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node *expr_op, ir_node *const_op, ir_mode *mode) { - return new_rd_ia32_Eor_i(dbg, current_ir_graph, block, expr_op, mode); + return new_rd_ia32_Eor_i(dbg, current_ir_graph, block, expr_op, mode); } /** @@ -276,7 +354,7 @@ static ir_node *gen_imm_Eor(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *bloc * @return the created ia32 Eor node */ static ir_node *gen_Eor(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node *op1, ir_node *op2, ir_mode *mode) { - return new_rd_ia32_Eor(dbg, current_ir_graph, block, op1, op2, mode); + return new_rd_ia32_Eor(dbg, current_ir_graph, block, op1, op2, mode); } @@ -291,7 +369,7 @@ static ir_node *gen_Eor(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, i * @return the created ia23 Max node */ static ir_node *gen_Max(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node *op1, ir_node *op2, ir_mode *mode) { - return new_rd_ia32_Max(dbg, current_ir_graph, block, op1, op2, mode); + return new_rd_ia32_Max(dbg, current_ir_graph, block, op1, op2, mode); } @@ -306,36 +384,7 @@ static ir_node *gen_Max(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, i * @return the created ia23 Min node */ static ir_node *gen_Min(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node *op1, ir_node *op2, ir_mode *mode) { - return new_rd_ia32_Min(dbg, current_ir_graph, block, op1, op2, mode); -} - - - -/** - * Creates an ia32 Cmp with immediate. - * - * @param dbg firm dbg - * @param block the block the new node should belong to - * @param expr_op operator - * @param mode node mode - * @return the created ia23 Cmp_i node - */ -static ir_node *gen_imm_Cmp(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node *expr_op, ir_node *const_op, ir_mode *mode) { - return new_rd_ia32_Cmp_i(dbg, current_ir_graph, block, expr_op, mode); -} - -/** - * Creates an ia32 Cmp. - * - * @param dbg firm node dbg - * @param block the block the new node should belong to - * @param op1 first operator - * @param op2 second operator - * @param mode node mode - * @return the created ia32 Cmp node - */ -static ir_node *gen_Cmp(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node *op1, ir_node *op2, ir_mode *mode) { - return new_rd_ia32_Cmp(dbg, current_ir_graph, block, op1, op2, mode); + return new_rd_ia32_Min(dbg, current_ir_graph, block, op1, op2, mode); } @@ -350,35 +399,35 @@ static ir_node *gen_Cmp(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, i * @return the created ia23 Sub_i node */ static ir_node *gen_imm_Sub(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node *expr_op, ir_node *const_op, ir_mode *mode) { - ir_node *new_op; - tarval *tv = get_ia32_Immop_tarval(const_op); - int normal_sub = 0; - tarval_classification_t class_tv, class_negtv; - - /* const_op: tarval or SymConst? */ - if (tv) { - /* optimize tarvals */ - class_tv = classify_tarval(tv); - class_negtv = classify_tarval(tarval_neg(tv)); - - if (class_tv == TV_CLASSIFY_ONE) { /* - 1 == DEC */ - DBG((mod, LEVEL_2, "optimizing Sub(1) to Dec ... ")); - new_op = new_rd_ia32_Dec(dbg, current_ir_graph, block, expr_op, mode); - } - else if (class_negtv == TV_CLASSIFY_ONE) { /* - (-1) == Sub */ - DBG((mod, LEVEL_2, "optimizing Sub(-1) to Inc ... ")); - new_op = new_rd_ia32_Inc(dbg, current_ir_graph, block, expr_op, mode); - } - else - normal_sub = 1; - } - else - normal_sub = 1; - - if (normal_sub) - new_op = new_rd_ia32_Sub_i(dbg, current_ir_graph, block, expr_op, mode); - - return new_op; + ir_node *new_op; + tarval *tv = get_ia32_Immop_tarval(const_op); + int normal_sub = 0; + tarval_classification_t class_tv, class_negtv; + + /* const_op: tarval or SymConst? */ + if (tv) { + /* optimize tarvals */ + class_tv = classify_tarval(tv); + class_negtv = classify_tarval(tarval_neg(tv)); + + if (class_tv == TV_CLASSIFY_ONE) { /* - 1 == DEC */ + DBG((mod, LEVEL_2, "optimizing Sub(1) to Dec ... ")); + new_op = new_rd_ia32_Dec(dbg, current_ir_graph, block, expr_op, mode); + } + else if (class_negtv == TV_CLASSIFY_ONE) { /* - (-1) == Sub */ + DBG((mod, LEVEL_2, "optimizing Sub(-1) to Inc ... ")); + new_op = new_rd_ia32_Inc(dbg, current_ir_graph, block, expr_op, mode); + } + else + normal_sub = 1; + } + else + normal_sub = 1; + + if (normal_sub) + new_op = new_rd_ia32_Sub_i(dbg, current_ir_graph, block, expr_op, mode); + + return new_op; } /** @@ -392,7 +441,10 @@ static ir_node *gen_imm_Sub(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *bloc * @return the created ia32 Sub node */ static ir_node *gen_Sub(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node *op1, ir_node *op2, ir_mode *mode) { - return new_rd_ia32_Sub(dbg, current_ir_graph, block, op1, op2, mode); + if (mode_is_float(mode)) { + return new_rd_ia32_fSub(dbg, current_ir_graph, block, op1, op2, mode); + } + return new_rd_ia32_Sub(dbg, current_ir_graph, block, op1, op2, mode); } @@ -408,7 +460,7 @@ static ir_node *gen_Sub(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, i * @return the created ia32 Mod node */ static ir_node *gen_Mod(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node *mem, ir_node *op1, ir_node *op2, ir_mode *mode) { - return new_rd_ia32_DivMod(dbg, current_ir_graph, block, mem, op1, op2, flavour_Mod, mode); + return new_rd_ia32_DivMod(dbg, current_ir_graph, block, op1, op2, mem, flavour_Mod, mode); } @@ -424,7 +476,7 @@ static ir_node *gen_Mod(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, i * @return the created ia32 Div node */ static ir_node *gen_Div(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node *mem, ir_node *op1, ir_node *op2, ir_mode *mode) { - return new_rd_ia32_DivMod(dbg, current_ir_graph, block, mem, op1, op2, flavour_Div, mode); + return new_rd_ia32_DivMod(dbg, current_ir_graph, block, op1, op2, mem, flavour_Div, mode); } @@ -440,7 +492,23 @@ static ir_node *gen_Div(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, i * @return the created ia32 DivMod node */ static ir_node *gen_DivMod(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node *mem, ir_node *op1, ir_node *op2, ir_mode *mode) { - return new_rd_ia32_DivMod(dbg, current_ir_graph, block, mem, op1, op2, flavour_DivMod, mode); + return new_rd_ia32_DivMod(dbg, current_ir_graph, block, op1, op2, mem, flavour_DivMod, mode); +} + + + +/** + * Creates an ia32 floating Div. + * + * @param dbg firm node dbg + * @param block the block the new node should belong to + * @param op1 first operator + * @param op2 second operator + * @param mode node mode + * @return the created ia32 fDiv node + */ +static ir_node *gen_Quot(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node *op1, ir_node *op2, ir_mode *mode) { + return new_rd_ia32_fDiv(dbg, current_ir_graph, block, op1, op2, mode); } @@ -455,7 +523,7 @@ static ir_node *gen_DivMod(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block * @return the created ia23 Shl_i node */ static ir_node *gen_imm_Shl(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node *expr_op, ir_node *const_op, ir_mode *mode) { - return new_rd_ia32_Shl_i(dbg, current_ir_graph, block, expr_op, mode); + return new_rd_ia32_Shl_i(dbg, current_ir_graph, block, expr_op, mode); } /** @@ -469,7 +537,7 @@ static ir_node *gen_imm_Shl(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *bloc * @return the created ia32 Shl node */ static ir_node *gen_Shl(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node *op1, ir_node *op2, ir_mode *mode) { - return new_rd_ia32_Shl(dbg, current_ir_graph, block, op1, op2, mode); + return new_rd_ia32_Shl(dbg, current_ir_graph, block, op1, op2, mode); } @@ -484,7 +552,7 @@ static ir_node *gen_Shl(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, i * @return the created ia23 Shr_i node */ static ir_node *gen_imm_Shr(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node *expr_op, ir_node *const_op, ir_mode *mode) { - return new_rd_ia32_Shr_i(dbg, current_ir_graph, block, expr_op, mode); + return new_rd_ia32_Shr_i(dbg, current_ir_graph, block, expr_op, mode); } /** @@ -498,7 +566,7 @@ static ir_node *gen_imm_Shr(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *bloc * @return the created ia32 Shr node */ static ir_node *gen_Shr(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node *op1, ir_node *op2, ir_mode *mode) { - return new_rd_ia32_Shr(dbg, current_ir_graph, block, op1, op2, mode); + return new_rd_ia32_Shr(dbg, current_ir_graph, block, op1, op2, mode); } @@ -513,7 +581,7 @@ static ir_node *gen_Shr(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, i * @return the created ia23 Shrs_i node */ static ir_node *gen_imm_Shrs(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node *expr_op, ir_node *const_op, ir_mode *mode) { - return new_rd_ia32_Shrs_i(dbg, current_ir_graph, block, expr_op, mode); + return new_rd_ia32_Shrs_i(dbg, current_ir_graph, block, expr_op, mode); } /** @@ -527,7 +595,7 @@ static ir_node *gen_imm_Shrs(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *blo * @return the created ia32 Shrs node */ static ir_node *gen_Shrs(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node *op1, ir_node *op2, ir_mode *mode) { - return new_rd_ia32_Shrs(dbg, current_ir_graph, block, op1, op2, mode); + return new_rd_ia32_Shrs(dbg, current_ir_graph, block, op1, op2, mode); } @@ -543,7 +611,7 @@ static ir_node *gen_Shrs(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, * @return the created ia32 RotL node */ static ir_node *gen_RotL(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node *op1, ir_node *op2, ir_mode *mode) { - return new_rd_ia32_RotL(dbg, current_ir_graph, block, op1, op2, mode); + return new_rd_ia32_RotL(dbg, current_ir_graph, block, op1, op2, mode); } @@ -561,7 +629,7 @@ static ir_node *gen_RotL(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, * @return the created ia32 RotR node */ static ir_node *gen_RotR(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node *op1, ir_node *op2, ir_mode *mode) { - return new_rd_ia32_RotR(dbg, current_ir_graph, block, op1, op2, mode); + return new_rd_ia32_RotR(dbg, current_ir_graph, block, op1, op2, mode); } @@ -578,7 +646,7 @@ static ir_node *gen_RotR(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, * @return the created ia32 RotL node */ static ir_node *gen_imm_Rot(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node *expr_op, ir_node *const_op, ir_mode *mode) { - return new_rd_ia32_RotL_i(dbg, current_ir_graph, block, expr_op, mode); + return new_rd_ia32_RotL_i(dbg, current_ir_graph, block, expr_op, mode); } /** @@ -592,36 +660,36 @@ static ir_node *gen_imm_Rot(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *bloc * @return the created ia32 RotL or RotR node */ static ir_node *gen_Rot(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, ir_node *op1, ir_node *op2, ir_mode *mode) { - ir_node *rotate = NULL; + ir_node *rotate = NULL; - /* Firm has only Rot (which is a RotL), so we are looking for a right (op2) - operand "-e+mode_size_bits" (it's an already modified "mode_size_bits-e", - that means we can create a RotR instead of an Add and a RotL */ + /* Firm has only Rot (which is a RotL), so we are looking for a right (op2) + operand "-e+mode_size_bits" (it's an already modified "mode_size_bits-e", + that means we can create a RotR instead of an Add and a RotL */ - if (is_ia32_Add_i(op2)) { - ir_node *minus = get_irn_n(op2, 0); // is there an op_Minus? + if (is_ia32_Add_i(op2)) { + ir_node *minus = get_irn_n(op2, 0); // is there an op_Minus? - if (is_ia32_Minus(minus)) { - tarval *tv = get_ia32_Immop_tarval(op2); - long bits = get_mode_size_bits(mode); + if (is_ia32_Minus(minus)) { + tarval *tv = get_ia32_Immop_tarval(op2); + long bits = get_mode_size_bits(mode); - if (tarval_is_long(tv) && get_tarval_long(tv) == bits) { - DBG((mod, LEVEL_1, "optimizing RotL into RotR ... ")); - rotate = gen_RotR(mod, dbg, block, op1, get_irn_n(minus, 0), mode); - } - } - } + if (tarval_is_long(tv) && get_tarval_long(tv) == bits) { + DBG((mod, LEVEL_1, "optimizing RotL into RotR ... ")); + rotate = gen_RotR(mod, dbg, block, op1, get_irn_n(minus, 0), mode); + } + } + } - if (!rotate) - rotate = gen_RotL(mod, dbg, block, op1, op2, mode); + if (!rotate) + rotate = gen_RotL(mod, dbg, block, op1, op2, mode); - return rotate; + return rotate; } /** - * Transforms commutative operations (op_Add, op_Mul, op_And, op_Or, op_Eor, op_Cmp) + * Transforms commutative operations (op_Add, op_Mul, op_And, op_Or, op_Eor) * and non-commutative operations with com == 0 (op_Sub, op_Shl, op_Shr, op_Shrs, op_Rot) * * @param mod the debug module @@ -634,94 +702,94 @@ static ir_node *gen_Rot(firm_dbg_module_t *mod, dbg_info *dbg, ir_node *block, i * @return the created assembler node */ static ir_node *gen_arith_Op(firm_dbg_module_t *mod, ir_node *block, ir_node *node, ir_node *op1, ir_node *op2, ir_mode *mode, int com) { - dbg_info *dbg = get_irn_dbg_info(node); - ir_node *imm_op = NULL; - ir_node *expr_op = NULL; - ir_node *asm_node = NULL; - opcode opc = get_irn_opcode(node); - ir_op *op = get_irn_op(node); + dbg_info *dbg = get_irn_dbg_info(node); + ir_node *imm_op = NULL; + ir_node *expr_op = NULL; + ir_node *asm_node = NULL; + opcode opc = get_irn_opcode(node); + ir_op *op = get_irn_op(node); #define GENOP(a) case iro_##a: asm_node = gen_##a(mod, dbg, block, op1, op2, mode); break #define GENOPI(a) case iro_##a: asm_node = gen_imm_##a(mod, dbg, block, expr_op, imm_op, mode); break - if (com) - imm_op = get_immediate_op(op1, op2); - else - imm_op = get_immediate_op(NULL, op2); - - expr_op = get_expr_op(op1, op2); - - /* TODO: Op(Const, Const) support */ - if (is_ia32_Const(op1) && is_ia32_Const(op2)) { - DBG((mod, LEVEL_2, "found unexpected %s(Const, Const), creating binop ... ", get_irn_opname(node))); - imm_op = NULL; - } - - if (op == get_op_Min() || op == get_op_Max()) { - DBG((mod, LEVEL_2, "MIN/MAX imm not available, creating binop ... ")); - imm_op = NULL; - } - - DBG((mod, LEVEL_1, "(op1: %s -- op2: %s) ... ", get_irn_opname(op1), get_irn_opname(op2))); - - if (imm_op) { - DBG((mod, LEVEL_1, "%s with imm ... ", get_irn_opname(node))); - - switch(opc) { - GENOPI(Add); - GENOPI(Mul); - GENOPI(And); - GENOPI(Or); - GENOPI(Eor); - GENOPI(Cmp); - - GENOPI(Sub); - GENOPI(Shl); - GENOPI(Shr); - GENOPI(Shrs); - GENOPI(Rot); - default: - if (op == get_op_Mulh()) { - asm_node = gen_imm_Mulh(mod, dbg, block, expr_op, imm_op, mode); - } - else - assert("binop_i: THIS SHOULD NOT HAPPEN"); - } - - set_ia32_Immop_attr(asm_node, imm_op); - } - else { - DBG((mod, LEVEL_1, "%s as binop ... ", get_irn_opname(node))); - - switch(opc) { - GENOP(Add); - GENOP(Mul); - GENOP(And); - GENOP(Or); - GENOP(Eor); - GENOP(Cmp); - - GENOP(Sub); - GENOP(Shl); - GENOP(Shr); - GENOP(Shrs); - GENOP(Rot); - default: - if (op == get_op_Mulh()) { - asm_node = gen_Mulh(mod, dbg, block, op1, op2, mode); - } - else if (op == get_op_Max()) { - asm_node = gen_Max(mod, dbg, block, op1, op2, mode); - } - else if (op == get_op_Min()) { - asm_node = gen_Min(mod, dbg, block, op1, op2, mode); - } - else - assert("binop: THIS SHOULD NOT HAPPEN"); - } - } - - return asm_node; + if (com) + imm_op = get_immediate_op(op1, op2); + else + imm_op = get_immediate_op(NULL, op2); + + expr_op = get_expr_op(op1, op2); + + /* TODO: Op(Const, Const) support */ + if (is_ia32_Const(op1) && is_ia32_Const(op2)) { + DBG((mod, LEVEL_2, "found unexpected %s(Const, Const), creating binop ... ", get_irn_opname(node))); + imm_op = NULL; + } + + if (op == get_op_Min() || op == get_op_Max()) { + DBG((mod, LEVEL_2, "MIN/MAX imm not available, creating binop ... ")); + imm_op = NULL; + } + + DBG((mod, LEVEL_1, "(op1: %s -- op2: %s) ... ", get_irn_opname(op1), get_irn_opname(op2))); + + if (!mode_is_float(mode) && imm_op) { + DBG((mod, LEVEL_1, "%s with imm ... ", get_irn_opname(node))); + + switch(opc) { + GENOPI(Add); + GENOPI(Mul); + GENOPI(And); + GENOPI(Or); + GENOPI(Eor); + + GENOPI(Sub); + GENOPI(Shl); + GENOPI(Shr); + GENOPI(Shrs); + GENOPI(Rot); + default: + if (op == get_op_Mulh()) { + asm_node = gen_imm_Mulh(mod, dbg, block, expr_op, imm_op, mode); + } + else + assert("binop_i: THIS SHOULD NOT HAPPEN"); + } + + set_ia32_Immop_attr(asm_node, imm_op); + } + else { + DBG((mod, LEVEL_1, "%s as binop ... ", get_irn_opname(node))); + + switch(opc) { + GENOP(Add); + GENOP(Mul); + GENOP(And); + GENOP(Or); + GENOP(Eor); + + GENOP(Quot); + + GENOP(Sub); + GENOP(Shl); + GENOP(Shr); + GENOP(Shrs); + GENOP(Rot); + default: + if (op == get_op_Mulh()) { + asm_node = gen_Mulh(mod, dbg, block, op1, op2, mode); + } + else if (op == get_op_Max()) { + asm_node = gen_Max(mod, dbg, block, op1, op2, mode); + } + else if (op == get_op_Min()) { + asm_node = gen_Min(mod, dbg, block, op1, op2, mode); + } + else + assert("binop: THIS SHOULD NOT HAPPEN"); + } + } + + return asm_node; } @@ -737,12 +805,16 @@ static ir_node *gen_arith_Op(firm_dbg_module_t *mod, ir_node *block, ir_node *no * @return the created ia32 Minus node */ static ir_node *gen_Minus(firm_dbg_module_t *mod, ir_node *block, ir_node *node, ir_node *op, ir_mode *mode) { - if (is_ia32_Minus(op)) { - DBG((mod, LEVEL_1, "optimizing --(e) to e ...")); - return get_irn_n(op, 0); - } - else - return new_rd_ia32_Minus(get_irn_dbg_info(node), current_ir_graph, block, op, mode); + if (is_ia32_Minus(op) || is_ia32_fMinus(op)) { + DBG((mod, LEVEL_1, "optimizing --(e) to e ...")); + return get_irn_n(op, 0); + } + else { + if (mode_is_float(mode)) { + return new_rd_ia32_fMinus(get_irn_dbg_info(node), current_ir_graph, block, op, mode); + } + return new_rd_ia32_Minus(get_irn_dbg_info(node), current_ir_graph, block, op, mode); + } } @@ -758,7 +830,7 @@ static ir_node *gen_Minus(firm_dbg_module_t *mod, ir_node *block, ir_node *node, * @return the created ia32 Conv node */ static ir_node *gen_Conv(firm_dbg_module_t *mod, ir_node *block, ir_node *node, ir_node *op, ir_mode *mode) { - return new_rd_ia32_Conv(get_irn_dbg_info(node), current_ir_graph, block, op, mode); + return new_rd_ia32_Conv(get_irn_dbg_info(node), current_ir_graph, block, op, mode); } @@ -774,7 +846,7 @@ static ir_node *gen_Conv(firm_dbg_module_t *mod, ir_node *block, ir_node *node, * @return the created ia32 Not node */ static ir_node *gen_Not(firm_dbg_module_t *mod, ir_node *block, ir_node *node, ir_node *op, ir_mode *mode) { - return new_rd_ia32_Not(get_irn_dbg_info(node), current_ir_graph, block, op, mode); + return new_rd_ia32_Not(get_irn_dbg_info(node), current_ir_graph, block, op, mode); } @@ -790,16 +862,16 @@ static ir_node *gen_Not(firm_dbg_module_t *mod, ir_node *block, ir_node *node, i * @return the created ia32 Abs node */ static ir_node *gen_Abs(firm_dbg_module_t *mod, ir_node *block, ir_node *node, ir_node *op, ir_mode *mode) { - ir_node *res, *p_eax, *p_edx; - dbg_info *dbg = get_irn_dbg_info(node); + ir_node *res, *p_eax, *p_edx; + dbg_info *dbg = get_irn_dbg_info(node); - res = new_rd_ia32_Cltd(dbg, current_ir_graph, block, op, mode_T); - p_eax = new_rd_Proj(dbg, current_ir_graph, block, res, mode, pn_EAX); - p_edx = new_rd_Proj(dbg, current_ir_graph, block, res, mode, pn_EDX); - res = new_rd_ia32_Eor(dbg, current_ir_graph, block, p_eax, p_edx, mode); - res = new_rd_ia32_Sub(dbg, current_ir_graph, block, res, p_edx, mode); + res = new_rd_ia32_Cltd(dbg, current_ir_graph, block, op, mode_T); + p_eax = new_rd_Proj(dbg, current_ir_graph, block, res, mode, pn_EAX); + p_edx = new_rd_Proj(dbg, current_ir_graph, block, res, mode, pn_EDX); + res = new_rd_ia32_Eor(dbg, current_ir_graph, block, p_eax, p_edx, mode); + res = new_rd_ia32_Sub(dbg, current_ir_graph, block, res, p_edx, mode); - return res; + return res; } @@ -814,7 +886,10 @@ static ir_node *gen_Abs(firm_dbg_module_t *mod, ir_node *block, ir_node *node, i * @return the created ia32 Load node */ static ir_node *gen_Load(firm_dbg_module_t *mod, ir_node *block, ir_node *node, ir_mode *mode) { - return new_rd_ia32_Load(get_irn_dbg_info(node), current_ir_graph, block, get_Load_mem(node), get_Load_ptr(node), mode); + if (mode_is_float(mode)) { + return new_rd_ia32_fLoad(get_irn_dbg_info(node), current_ir_graph, block, get_Load_ptr(node), get_Load_mem(node), mode); + } + return new_rd_ia32_Load(get_irn_dbg_info(node), current_ir_graph, block, get_Load_ptr(node), get_Load_mem(node), mode); } @@ -829,13 +904,38 @@ static ir_node *gen_Load(firm_dbg_module_t *mod, ir_node *block, ir_node *node, * @return the created ia32 Store node */ ir_node *gen_Store(firm_dbg_module_t *mod, ir_node *block, ir_node *node, ir_mode *mode) { - return new_rd_ia32_Store(get_irn_dbg_info(node), current_ir_graph, block, get_Store_mem(node), get_Store_ptr(node), get_Store_value(node), mode); + if (mode_is_float(mode)) { + return new_rd_ia32_fStore(get_irn_dbg_info(node), current_ir_graph, block, get_Store_ptr(node), get_Store_value(node), get_Store_mem(node), mode); + } + return new_rd_ia32_Store(get_irn_dbg_info(node), current_ir_graph, block, get_Store_ptr(node), get_Store_value(node), get_Store_mem(node), mode); } /** - * Transforms a Call. + * Check all parameters and determine the maximum number of parameters + * to pass in gp regs resp. in fp regs. + */ +static void get_n_regparam_class(int n, ir_node **param, int *n_int, int *n_float) { + int i; + + for (i = 0; i < n; i++) { + if (mode_is_int(get_irn_mode(param[i]))) + *n_int = *n_int + 1; + else if (mode_is_float(get_irn_mode(param[i]))) + *n_float = *n_float + 1; + + /* test for maximum */ + if (*n_int == maxnum_gpreg_args) + break; + + if (*n_float == maxnum_fpreg_args) + break; + } +} + +/** + * Transforms a Call and its arguments corresponding to the calling convention. * * @param mod the debug module * @param block the block the new node should belong to @@ -843,12 +943,167 @@ ir_node *gen_Store(firm_dbg_module_t *mod, ir_node *block, ir_node *node, ir_mod * @param dummy mode doesn't matter * @return the created ia32 Call node */ -static ir_node *gen_Call(firm_dbg_module_t *mod, ir_node *block, ir_node *node, ir_mode *dummy) { - return new_rd_ia32_Call(get_irn_dbg_info(node), current_ir_graph, block, node); +static ir_node *gen_Call(firm_dbg_module_t *mod, ir_node *block, ir_node *call, ir_mode *dummy) { + const arch_register_req_t **in_req; + ir_node **in; + ir_node *new_call, *sync; + ir_mode *mode; + int i, j, n_new_call_in; + asmop_attr *attr; + ir_node **stack_param = NULL; + ir_node **param = get_Call_param_arr(call); + ir_node *call_Mem = get_Call_mem(call); + unsigned cc = get_method_calling_convention(get_Call_type(call)); + int n = get_Call_n_params(call); + int n_gpregparam = 0; + int n_fpregparam = 0; + int cur_gp_idx = 0; + int cur_fp_idx = 0; + int stack_idx = 0; + int done = 0; + + if (cc & cc_reg_param) + get_n_regparam_class(n, param, &n_gpregparam, &n_fpregparam); + + /* do we need to pass arguments on stack? */ + if (n - n_gpregparam - n_fpregparam > 0) + stack_param = calloc(n - n_gpregparam - n_fpregparam, sizeof(ir_node *)); + + /* we need at least one in, either for the stack params or the call_Mem */ + n_new_call_in = 1 + n_gpregparam + n_fpregparam; + + current_gpreg_param_req = gpreg_param_req_std; + current_fpreg_param_req = fpreg_param_req_std; + + if (cc & cc_this_call) { + current_gpreg_param_req = gpreg_param_req_this; + current_fpreg_param_req = fpreg_param_req_this; + } + + /* the call has one IN for all stack parameter and one IN for each reg param */ + in = calloc(n_new_call_in, sizeof(ir_node *)); + in_req = calloc(n_new_call_in, sizeof(arch_register_req_t *)); + + /* loop over all parameters and determine whether its a int or float register parameter */ + for (i = 0; i < n && !done && (cc & cc_reg_param); i++) { + mode = get_irn_mode(param[i]); + + if (mode_is_int(mode) && cur_gp_idx < maxnum_gpreg_args) { + /* param can be passed in general purpose register and we have some registers left */ + in[cur_gp_idx + cur_fp_idx] = param[i]; + in_req[cur_gp_idx] = current_gpreg_param_req[cur_gp_idx]; + cur_gp_idx++; + } + else if (mode_is_float(mode) && cur_fp_idx < maxnum_fpreg_args) { + /* param can be passed in floating point register and we have some registers left */ + assert(current_gpreg_param_req[cur_fp_idx] && "'this' pointer cannot be passed as float"); + in[cur_gp_idx + cur_fp_idx] = param[i]; + in_req[cur_fp_idx] = current_gpreg_param_req[cur_fp_idx]; + cur_fp_idx++; + } + + /* maximum number of register parameters in one class reached? */ + if (cur_gp_idx >= maxnum_gpreg_args || cur_fp_idx >= maxnum_fpreg_args) { + done = 1; + } + } + stack_idx = i; + + /* create remaining stack parameters */ + if (cc & cc_last_on_top) { + for (i = stack_idx; i < n; i++) { + /* pass it on stack */ + if (mode_is_float(get_irn_mode(param[i]))) { + stack_param[i] = new_rd_ia32_fStackArg(get_irn_dbg_info(param[i]), current_ir_graph, + block, call_Mem, param[i], mode_M); + } + else { + stack_param[i] = new_rd_ia32_StackArg(get_irn_dbg_info(param[i]), current_ir_graph, + block, call_Mem, param[i], mode_M); + } + } + } + else { + for (i = n - 1, j = stack_idx; i >= stack_idx; i--, j++) { + /* pass it on stack */ + if (mode_is_float(get_irn_mode(param[i]))) { + stack_param[i] = new_rd_ia32_fStackArg(get_irn_dbg_info(param[i]), current_ir_graph, + block, call_Mem, param[i], mode_M); + } + else { + stack_param[i] = new_rd_ia32_StackArg(get_irn_dbg_info(param[i]), current_ir_graph, + block, call_Mem, param[i], mode_M); + } + } + } + + if (stack_param) { + sync = new_r_Sync(current_ir_graph, block, n - n_gpregparam - n_fpregparam, stack_param); + in[n_new_call_in - 1] = sync; + } + else { + in[n_new_call_in - 1] = call_Mem; + } + + /* create the new node */ + new_call = new_rd_ia32_Call(get_irn_dbg_info(call), current_ir_graph, block, n_new_call_in, in); + set_ia32_Immop_attr(new_call, get_Call_ptr(call)); + set_ia32_n_res(new_call, 1); + + /* set register requirements for in and out */ + attr = get_ia32_attr(new_call); + attr->in_req = in_req; + attr->out_req = calloc(1, sizeof(arch_register_req_t *)); + attr->out_req[0] = &ia32_default_req_ia32_general_purpose_eax; + attr->slots = calloc(1, sizeof(arch_register_t *)); + + /* stack parameter has no OUT register */ + attr->in_req[n_new_call_in - 1] = &ia32_default_req_none; + + return new_call; } +/** + * creates a unique ident by adding a number to a tag + * + * @param tag the tag string, must contain a %d if a number + * should be added + */ +static ident *unique_id(const char *tag) +{ + static unsigned id = 0; + char str[256]; + + snprintf(str, sizeof(str), tag, ++id); + return new_id_from_str(str); +} + +/** + * Transforms a SymConst. + * + * @param mod the debug module + * @param block the block the new node should belong to + * @param node the ir SymConst node + * @param mode mode of the SymConst + * @return the created ia32 Const node + */ +static ir_node *gen_SymConst(firm_dbg_module_t *mod, ir_node *block, ir_node *node, ir_mode *mode) { + ir_node *cnst; + + if (mode_is_float(mode)) { + cnst = new_rd_ia32_fConst(get_irn_dbg_info(node), current_ir_graph, block, mode); + + } + else { + cnst = new_rd_ia32_Const(get_irn_dbg_info(node), current_ir_graph, block, mode); + } + + set_ia32_Const_attr(cnst, node); + return cnst; +} + /** * Transforms a Const. * @@ -859,28 +1114,262 @@ static ir_node *gen_Call(firm_dbg_module_t *mod, ir_node *block, ir_node *node, * @return the created ia32 Const node */ static ir_node *gen_Const(firm_dbg_module_t *mod, ir_node *block, ir_node *node, ir_mode *mode) { - ir_node *cnst = new_rd_ia32_Const(get_irn_dbg_info(node), current_ir_graph, block, mode); - set_ia32_Const_attr(cnst, node); - return cnst; + ir_node *cnst; + entity *ent; + type *tp; + symconst_symbol sym; + + if (mode_is_float(mode)) { + tp = get_Const_type(node); + if (tp == firm_unknown_type) { + tp = new_type_primitive(unique_id("tp_ia32_float_%u"), mode); + } + + ent = new_entity(get_glob_type(), unique_id("ia32FloatCnst_%u"), tp); + + set_entity_ld_ident(ent, get_entity_ident(ent)); + set_entity_visibility(ent, visibility_local); + set_entity_variability(ent, variability_constant); + set_entity_allocation(ent, allocation_static); + + set_atomic_ent_value(ent, node); + + sym.entity_p = ent; + + cnst = new_rd_SymConst(get_irn_dbg_info(node), current_ir_graph, block, sym, symconst_addr_ent); + cnst = gen_SymConst(mod, block, cnst, mode); + } + else { + cnst = new_rd_ia32_Const(get_irn_dbg_info(node), current_ir_graph, block, mode); + set_ia32_Const_attr(cnst, node); + } + + return cnst; } + + /** - * Transforms a SymConst. + * Transforms a Cond -> Proj[b] -> Cmp into a CondJmp or CondJmp_i * * @param mod the debug module * @param block the block the new node should belong to - * @param node the ir SymConst node - * @param mode mode of the SymConst - * @return the created ia32 Const node + * @param node the ir Cond node + * @param mode mode of the Cond + * @return The transformed node. */ -static ir_node *gen_SymConst(firm_dbg_module_t *mod, ir_node *block, ir_node *node, ir_mode *mode) { - ir_node *cnst = new_rd_ia32_Const(get_irn_dbg_info(node), current_ir_graph, block, mode); - set_ia32_Const_attr(cnst, node); - return cnst; +static ir_node *gen_Cond(firm_dbg_module_t *mod, ir_node *block, ir_node *node, ir_mode *mode) { + ir_node *sel = get_Cond_selector(node); + ir_mode *sel_mode = get_irn_mode(sel); + ir_node *res = NULL; + ir_node *pred = NULL; + ir_node *cmp_a, *cmp_b, *cnst, *expr; + + if (is_Proj(sel) && sel_mode == mode_b) { + pred = get_Proj_pred(sel); + + /* get both compare operators */ + cmp_a = get_Cmp_left(pred); + cmp_b = get_Cmp_right(pred); + + /* check if we can use a CondJmp with immediate */ + cnst = get_immediate_op(cmp_a, cmp_b); + expr = get_expr_op(cmp_a, cmp_b); + + if (cnst && expr) { + res = new_rd_ia32_CondJmp_i(get_irn_dbg_info(node), current_ir_graph, block, expr, mode_T); + set_ia32_Immop_attr(res, cnst); + } + else { + res = new_rd_ia32_CondJmp(get_irn_dbg_info(node), current_ir_graph, block, cmp_a, cmp_b, mode_T); + } + + set_ia32_pncode(res, get_Proj_proj(sel)); + } + else { + res = new_rd_ia32_SwitchJmp(get_irn_dbg_info(node), current_ir_graph, block, sel, mode_T); + set_ia32_pncode(res, get_Cond_defaultProj(node)); + } + + return res; +} + + + +/** + * Transform the argument projs from a start node corresponding to the + * calling convention. + * It transforms "Proj Arg x -> ProjT -> Start <- ProjM" into + * "RegParam x -> ProjT -> Start" OR + * "StackParam x -> ProjM -> Start" + * whether parameter is passed in register or on stack. + * + * @param mod the debug module + * @param block the block the nodes should belong to + * @param proj the ProjT node which points to Start + * @param start the Start node + * @return Should be always NULL + */ +static ir_node *gen_Proj_Start(firm_dbg_module_t *mod, ir_node *block, ir_node *proj, ir_node *start) { + const ir_edge_t *edge; + ir_node *succ, *irn; + ir_node **projargs; + ir_mode *mode; + int n, i, j; + unsigned cc; + ir_node *proj_M = get_irg_initial_mem(current_ir_graph); + entity *irg_ent = get_irg_entity(current_ir_graph); + type *tp = get_entity_type(irg_ent); + int cur_gp_idx = 0; + int cur_fp_idx = 0; + int stack_idx = 0; + int done = 0; + + assert(is_Method_type(tp) && "irg type is not a method"); + + switch(get_Proj_proj(proj)) { + case pn_Start_T_args: + /* We cannot use get_method_n_params here as the function might + be variadic or one argument is not used. */ + n = get_irn_n_edges(proj); + + /* we are done here when there are no parameters */ + if (n < 1) + break; + + /* temporary remember all proj arg x */ + projargs = calloc(n, sizeof(ir_node *)); + + foreach_out_edge((const ir_node *)proj, edge) { + succ = get_edge_src_irn(edge); + assert(is_Proj(succ) && "non-Proj from a Proj_T (pn_Start_T_args)."); + projargs[get_Proj_proj(succ)] = succ; + } + + cc = get_method_calling_convention(tp); + + /* get the correct order in case of 'this' call */ + current_gpreg_param_req = gpreg_param_req_std; + current_fpreg_param_req = fpreg_param_req_std; + if (cc & cc_this_call) { + current_gpreg_param_req = gpreg_param_req_this; + current_fpreg_param_req = fpreg_param_req_this; + } + + /* loop over all parameters and check whether its a int or float */ + for (i = 0; i < n && !done && (cc & cc_reg_param); i++) { + mode = get_irn_mode(projargs[i]); + + if (mode_is_int(mode) && cur_gp_idx < maxnum_gpreg_args) { + /* parameter got passed in general purpose register */ + irn = new_rd_ia32_RegParam(get_irn_dbg_info(proj), current_ir_graph, block, proj, mode); + set_ia32_pncode(irn, i); + set_ia32_regreq_out(irn, current_gpreg_param_req[cur_gp_idx], 0); + cur_gp_idx++; + } + else if (mode_is_float(mode) && cur_fp_idx < maxnum_fpreg_args) { + /* parameter got passed in floating point register*/ + irn = new_rd_ia32_RegParam(get_irn_dbg_info(proj), current_ir_graph, block, proj, mode); + set_ia32_pncode(irn, i); + set_ia32_regreq_out(irn, current_fpreg_param_req[cur_fp_idx], 0); + cur_fp_idx++; + } + + /* kill the old "Proj Arg" and replace with the new Arg */ + exchange(projargs[i], irn); + + if (cur_gp_idx >= maxnum_gpreg_args || cur_fp_idx >= maxnum_fpreg_args) { + stack_idx = i; + done = 1; + } + } + + /* create all remaining stack parameters */ + if (cc & cc_last_on_top) { + for (i = stack_idx; i < n; i++) { + mode = get_irn_mode(projargs[i]); + + if (mode_is_float(mode)) + irn = new_rd_ia32_fStackParam(get_irn_dbg_info(projargs[i]), current_ir_graph, block, proj_M, mode); + else + irn = new_rd_ia32_StackParam(get_irn_dbg_info(projargs[i]), current_ir_graph, block, proj_M, mode); + + set_ia32_pncode(irn, i); + + /* kill the old "Proj Arg" and replace with the new stack param */ + exchange(projargs[i], irn); + } + } + else { + for (i = n - 1, j = stack_idx; i >= stack_idx; i--, j++) { + mode = get_irn_mode(projargs[i]); + + if (mode_is_float(mode)) + irn = new_rd_ia32_fStackParam(get_irn_dbg_info(projargs[i]), current_ir_graph, block, proj_M, mode); + else + irn = new_rd_ia32_StackParam(get_irn_dbg_info(projargs[i]), current_ir_graph, block, proj_M, mode); + + set_ia32_pncode(irn, j); + + /* kill the old "Proj Arg" and replace with the new stack param */ + exchange(projargs[i], irn); + } + } + + free(projargs); + + break; + case pn_Start_X_initial_exec: + case pn_Start_M: + case pn_Start_P_frame_base: + case pn_Start_P_globals: + case pn_Start_P_value_arg_base: + break; + default: + assert(0 && "unsupported Proj(Start)"); + } + + return NULL; +} + +/** + * Transform some Proj's (Proj_Proj, Proj_Start, Proj_Cmp, Proj_Cond, Proj_Call). + * All others are ignored. + * + * @param mod the debug module + * @param block the block the new node should belong to + * @param node the ir Proj node + * @param mode mode of the Proj + * @return The transformed node. + */ +static ir_node *gen_Proj(firm_dbg_module_t *mod, ir_node *block, ir_node *node, ir_mode *mode) { + ir_node *new_node = NULL; + ir_node *pred = get_Proj_pred(node); + + if (mode == mode_M) + return NULL; + + if (get_irn_op(pred) == op_Start) { + new_node = gen_Proj_Start(mod, block, node, pred); + } + + return new_node; } +/********************************************************* + * _ _ _ + * (_) | | (_) + * _ __ ___ __ _ _ _ __ __| |_ __ ___ _____ _ __ + * | '_ ` _ \ / _` | | '_ \ / _` | '__| \ \ / / _ \ '__| + * | | | | | | (_| | | | | | | (_| | | | |\ V / __/ | + * |_| |_| |_|\__,_|_|_| |_| \__,_|_| |_| \_/ \___|_| + * + *********************************************************/ + + + /** * Transforms the given firm node (and maybe some other related nodes) * into one or more assembler nodes. @@ -889,17 +1378,17 @@ static ir_node *gen_SymConst(firm_dbg_module_t *mod, ir_node *block, ir_node *no * @param env the debug module */ void ia32_transform_node(ir_node *node, void *env) { - firm_dbg_module_t *mod = (firm_dbg_module_t *)env; - opcode code = get_irn_opcode(node); - ir_node *asm_node = NULL; - ir_node *block; - ir_mode *mode; + firm_dbg_module_t *mod = (firm_dbg_module_t *)env; + opcode code = get_irn_opcode(node); + ir_node *asm_node = NULL; + ir_node *block; + ir_mode *mode; - if (is_Block(node)) - return; + if (is_Block(node)) + return; - block = get_nodes_block(node); - mode = get_irn_mode(node); + block = get_nodes_block(node); + mode = get_irn_mode(node); #define BINOP_COM(a) case iro_##a: asm_node = gen_arith_Op(mod, block, node, get_irn_n(node, 0), get_irn_n(node, 1), mode, 1); break #define BINOP_NCOM(a) case iro_##a: asm_node = gen_arith_Op(mod, block, node, get_irn_n(node, 0), get_irn_n(node, 1), mode, 0); break @@ -909,84 +1398,84 @@ void ia32_transform_node(ir_node *node, void *env) { #define IGN(a) case iro_##a: break #define BAD(a) case iro_##a: goto bad - DBG((mod, LEVEL_1, "transforming node %s (%ld) ... ", get_irn_opname(node), get_irn_node_nr(node))); - - switch (code) { - BINOP_COM(Add); - BINOP_COM(Mul); - BINOP_COM(And); - BINOP_COM(Or); - BINOP_COM(Eor); - BINOP_COM(Cmp); - - BINOP_NCOM(Sub); - TRIOP(Mod); - TRIOP(Div); - TRIOP(DivMod); - BINOP_NCOM(Shl); - BINOP_NCOM(Shr); - BINOP_NCOM(Shrs); - - UNOP(Minus); - UNOP(Conv); - UNOP(Abs); - UNOP(Not); - - GEN(Load); - GEN(Store); - GEN(Call); - GEN(Const); - GEN(SymConst); - - IGN(Block); - IGN(Start); - IGN(End); - IGN(NoMem); - IGN(Phi); - IGN(Cond); - IGN(Jmp); - IGN(IJmp); - IGN(Proj); - IGN(Break); - - BAD(Raise); - BAD(Sel); - BAD(InstOf); - BAD(Quot); - BAD(Cast); - BAD(Alloc); - BAD(Free); - BAD(Sync); - BAD(Tuple); - BAD(Id); - BAD(Bad); - BAD(Confirm); - BAD(Unknown); - BAD(Filter); - BAD(CallBegin); - BAD(EndReg); - BAD(EndExcept); - BAD(Mux); - BAD(CopyB); - - default: - if (get_irn_op(node) == get_op_Mulh() || - get_irn_op(node) == get_op_Max() || - get_irn_op(node) == get_op_Min()) - { - asm_node = gen_arith_Op(mod, block, node, get_irn_n(node, 0), get_irn_n(node, 1), mode, 1); - } - break; + DBG((mod, LEVEL_1, "transforming node %s (%ld) ... ", get_irn_opname(node), get_irn_node_nr(node))); + + switch (code) { + BINOP_COM(Add); + BINOP_COM(Mul); + BINOP_COM(And); + BINOP_COM(Or); + BINOP_COM(Eor); + + BINOP_NCOM(Sub); + TRIOP(Mod); + TRIOP(Div); + TRIOP(DivMod); + BINOP_NCOM(Shl); + BINOP_NCOM(Shr); + BINOP_NCOM(Shrs); + BINOP_NCOM(Quot); + + UNOP(Minus); + UNOP(Conv); + UNOP(Abs); + UNOP(Not); + + GEN(Load); + GEN(Store); + GEN(Call); + GEN(Const); + GEN(SymConst); + GEN(Cond); + + GEN(Proj); + + IGN(Block); + IGN(Start); + IGN(End); + IGN(NoMem); + IGN(Phi); + IGN(IJmp); + IGN(Break); + IGN(Cmp); + + BAD(Raise); + BAD(Sel); + BAD(InstOf); + BAD(Cast); + BAD(Alloc); + BAD(Free); + BAD(Sync); + BAD(Tuple); + BAD(Id); + BAD(Bad); + BAD(Confirm); + BAD(Unknown); + BAD(Filter); + BAD(CallBegin); + BAD(EndReg); + BAD(EndExcept); + BAD(Mux); + BAD(CopyB); + + default: + if (get_irn_op(node) == get_op_Mulh() || + get_irn_op(node) == get_op_Max() || + get_irn_op(node) == get_op_Min()) + { + asm_node = gen_arith_Op(mod, block, node, get_irn_n(node, 0), get_irn_n(node, 1), mode, 1); + } + break; bad: - fprintf(stderr, "Not implemented: %s\n", get_irn_opname(node)); - assert(0); - } - - if (asm_node) { - exchange(node, asm_node); - DBG((mod, LEVEL_1, "created node %u\n", get_irn_node_nr(asm_node))); - } - else { - DBG((mod, LEVEL_1, "ignored\n")); - } + fprintf(stderr, "Not implemented: %s\n", get_irn_opname(node)); + assert(0); + } + + if (asm_node) { + exchange(node, asm_node); + DBG((mod, LEVEL_1, "created node %+F[%p]\n", asm_node, asm_node)); + } + else { + DBG((mod, LEVEL_1, "ignored\n")); + } } -- 2.20.1