From 17e47394fa72025d14172a2acef2d258a067aa42 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Christian=20W=C3=BCrdig?= Date: Fri, 3 Mar 2006 15:57:34 +0000 Subject: [PATCH] finished TEMPLATE backend --- ir/be/TEMPLATE/TEMPLATE_emitter.c | 107 +----- ir/be/TEMPLATE/TEMPLATE_gen_decls.c | 1 - ir/be/TEMPLATE/TEMPLATE_map_regs.c | 76 ++++ ir/be/TEMPLATE/TEMPLATE_map_regs.h | 16 + ir/be/TEMPLATE/TEMPLATE_new_nodes.c | 166 ++++++--- ir/be/TEMPLATE/TEMPLATE_new_nodes.h | 2 +- ir/be/TEMPLATE/TEMPLATE_nodes_attr.h | 3 +- ir/be/TEMPLATE/TEMPLATE_spec.pl | 538 +++++++++++---------------- ir/be/TEMPLATE/TEMPLATE_transform.c | 415 +++++++++++++++++++++ ir/be/TEMPLATE/TEMPLATE_transform.h | 6 + ir/be/TEMPLATE/bearch_TEMPLATE.c | 201 +++++++--- ir/be/TEMPLATE/bearch_TEMPLATE_t.h | 24 +- 12 files changed, 1045 insertions(+), 510 deletions(-) create mode 100644 ir/be/TEMPLATE/TEMPLATE_map_regs.c create mode 100644 ir/be/TEMPLATE/TEMPLATE_map_regs.h create mode 100644 ir/be/TEMPLATE/TEMPLATE_transform.c create mode 100644 ir/be/TEMPLATE/TEMPLATE_transform.h diff --git a/ir/be/TEMPLATE/TEMPLATE_emitter.c b/ir/be/TEMPLATE/TEMPLATE_emitter.c index 05f50e1d2..4a38e5fe5 100644 --- a/ir/be/TEMPLATE/TEMPLATE_emitter.c +++ b/ir/be/TEMPLATE/TEMPLATE_emitter.c @@ -1,3 +1,6 @@ +/* TEMPLATE emitter */ +/* $Id$ */ + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -170,7 +173,7 @@ static int TEMPLATE_get_reg_name(lc_appendable_t *app, } /** - * Returns the tarval or offset of an ia32 as a string. + * Returns the tarval or offset of an TEMPLATE node as a string. */ static int TEMPLATE_const_to_str(lc_appendable_t *app, const lc_arg_occ_t *occ, const lc_arg_value_t *arg) @@ -209,52 +212,35 @@ static int TEMPLATE_get_mode_suffix(lc_appendable_t *app, } /** - * Return the ia32 printf arg environment. + * Return the TEMPLATE printf arg environment. * We use the firm environment with some additional handlers. */ const lc_arg_env_t *TEMPLATE_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 }; + static const lc_arg_handler_t TEMPLATE_reg_handler = { TEMPLATE_get_arg_type, TEMPLATE_get_reg_name }; + static const lc_arg_handler_t TEMPLATE_const_handler = { TEMPLATE_get_arg_type, TEMPLATE_const_to_str }; + static const lc_arg_handler_t TEMPLATE_mode_handler = { TEMPLATE_get_arg_type, TEMPLATE_get_mode_suffix }; if(env == NULL) { /* extend the firm printer */ env = firm_get_arg_env(); //lc_arg_new_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); + lc_arg_register(env, "TEMPLATE:sreg", 'S', &TEMPLATE_reg_handler); + lc_arg_register(env, "TEMPLATE:dreg", 'D', &TEMPLATE_reg_handler); + lc_arg_register(env, "TEMPLATE:cnst", 'C', &TEMPLATE_const_handler); + lc_arg_register(env, "TEMPLATE:offs", 'O', &TEMPLATE_const_handler); + lc_arg_register(env, "TEMPLATE:mode", 'M', &TEMPLATE_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_reg_nr(n, 0, 1) != get_ia32_reg_nr(n, 0, 0)) { - if (get_irn_arity(n) > 1 && get_ia32_reg_nr(n, 1, 1) == get_ia32_reg_nr(n, 0, 0)) { - if (! is_op_commutative(get_irn_op(n))) { - /* we only need to exchange 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 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; @@ -271,62 +257,6 @@ static char *get_cfop_target(const ir_node *irn, char *buf) { return buf; } -/********************************************************* - * _ _ _ - * (_) | (_) - * ___ _ __ ___ _| |_ _ _ _ _ __ ___ _ __ ___ - * / _ \ '_ ` _ \| | __| | | | | | '_ ` _ \| '_ \/ __| - * | __/ | | | | | | |_ | | |_| | | | | | | |_) \__ \ - * \___|_| |_| |_|_|\__| | |\__,_|_| |_| |_| .__/|___/ - * _/ | | | - * |__/ |_| - *********************************************************/ - -/** - * Emits code for a Switch (creates a jump table if - * possible otherwise a cmp-jmp cascade). - */ -void emit_TEMPLATE_Switch(const ir_node *irn, emit_env_t *emit_env) { - unsigned long interval; - jmp_tbl_t *tbl; - ir_node **cases; - int def_projnum; - int do_jmp_tbl = 1; - const lc_arg_env_t *env = ia32_get_arg_env(); - FILE *F = emit_env->out; - - /* TODO: */ - /* - create list of projs, each corresponding to one switch case */ - /* - determine the projnumber of the default case */ - - tbl = create_jump_table(cases, def_projnum, "JMPTBL_"); - - /* two-complement's magic make this work without overflow */ - interval = tbl.max_value - tbl.min_value; - - /* check value interval: do not create jump table if interval is too large */ - 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) { - /* TODO: emit table code */ - } - else { - /* TODO: emit cmp - jmp cascade */ - } - - if (tbl.label) - free(tbl.label); - if (tbl.branches) - free(tbl.branches); -} - /*********************************************************************************** @@ -351,10 +281,6 @@ void TEMPLATE_emit_node(ir_node *irn, void *env) { #define BE_EMIT(a) if (is_TEMPLATE_##a(irn)) { emit_TEMPLATE_##a(irn, emit_env); return; } - /* generated int emitter functions */ - BE_EMIT(Copy); - BE_EMIT(Perm); - BE_EMIT(Const); BE_EMIT(Add); @@ -403,9 +329,6 @@ void TEMPLATE_emit_node(ir_node *irn, void *env) { BE_EMIT(fLoad); BE_EMIT(fStore); - /* other emitter functions */ -// BE_EMIT(Switch); - ir_fprintf(F, "\t\t\t\t\t/* %+F */\n", irn); } @@ -461,7 +384,7 @@ void TEMPLATE_gen_labels(ir_node *block, void *env) { /** * Main driver */ -void TEMPLATE_gen_routine(FILE *F, ir_graph *irg, const ia32_code_gen_t *cg) { +void TEMPLATE_gen_routine(FILE *F, ir_graph *irg, const TEMPLATE_code_gen_t *cg) { emit_env_t emit_env; emit_env.mod = firm_dbg_register("firm.be.TEMPLATE.emit"); diff --git a/ir/be/TEMPLATE/TEMPLATE_gen_decls.c b/ir/be/TEMPLATE/TEMPLATE_gen_decls.c index 4851517de..d2a636ebd 100644 --- a/ir/be/TEMPLATE/TEMPLATE_gen_decls.c +++ b/ir/be/TEMPLATE/TEMPLATE_gen_decls.c @@ -1,6 +1,5 @@ /** * Dumps global variables and constants as TEMPLATE assembler. - * @author Christian Wuerdig * @date 14.02.2006 * @version $Id$ */ diff --git a/ir/be/TEMPLATE/TEMPLATE_map_regs.c b/ir/be/TEMPLATE/TEMPLATE_map_regs.c new file mode 100644 index 000000000..cd2d0f592 --- /dev/null +++ b/ir/be/TEMPLATE/TEMPLATE_map_regs.c @@ -0,0 +1,76 @@ +/** + * Register mapping for firm nodes. Stolen from bearch_firm :) + * $Id$ + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "TEMPLATE_map_regs.h" +#include "TEMPLATE_new_nodes.h" + +/* Mapping to store registers in firm nodes */ + +struct TEMPLATE_irn_reg_assoc { + const ir_node *irn; + const arch_register_t *reg; +}; + +int TEMPLATE_cmp_irn_reg_assoc(const void *a, const void *b, size_t len) { + const struct TEMPLATE_irn_reg_assoc *x = a; + const struct TEMPLATE_irn_reg_assoc *y = b; + + return x->irn != y->irn; +} + +static struct TEMPLATE_irn_reg_assoc *get_irn_reg_assoc(const ir_node *irn, set *reg_set) { + struct TEMPLATE_irn_reg_assoc templ; + unsigned int hash; + + templ.irn = irn; + templ.reg = NULL; + hash = HASH_PTR(irn); + + return set_insert(reg_set, &templ, sizeof(templ), hash); +} + +void TEMPLATE_set_firm_reg(ir_node *irn, const arch_register_t *reg, set *reg_set) { + struct TEMPLATE_irn_reg_assoc *assoc = get_irn_reg_assoc(irn, reg_set); + assoc->reg = reg; +} + +const arch_register_t *TEMPLATE_get_firm_reg(const ir_node *irn, set *reg_set) { + struct TEMPLATE_irn_reg_assoc *assoc = get_irn_reg_assoc(irn, reg_set); + return assoc->reg; +} + + + +/** + * Translates the projnum into a "real" argument position for register + * requirements dependend on the predecessor. + */ +long TEMPLATE_translate_proj_pos(const ir_node *proj) { + ir_node *pred = get_Proj_pred(proj); + long nr = get_Proj_proj(proj); + + if (is_TEMPLATE_Load(pred)) { + if (nr == pn_Load_res) + return 0; + assert(0 && "unsupported Proj(Load) number"); + } + else if (is_TEMPLATE_Store(pred)) { + return 0; + } + else if (is_TEMPLATE_fDiv(pred)) { + if (nr == pn_Quot_res) + return 0; + else + assert(0 && "there should be no more Projs for a fDiv"); + } + +// assert(0 && "unsupported Proj(X)"); + return nr; +} diff --git a/ir/be/TEMPLATE/TEMPLATE_map_regs.h b/ir/be/TEMPLATE/TEMPLATE_map_regs.h new file mode 100644 index 000000000..035ad41ba --- /dev/null +++ b/ir/be/TEMPLATE/TEMPLATE_map_regs.h @@ -0,0 +1,16 @@ +#ifndef _TEMPLATE_MAP_REGS_H_ +#define _TEMPLATE_MAP_REGS_H_ + +#include "irnode.h" +#include "set.h" + +#include "../bearch.h" +#include "TEMPLATE_nodes_attr.h" + +int TEMPLATE_cmp_irn_reg_assoc(const void *a, const void *b, size_t len); +void TEMPLATE_set_firm_reg(ir_node *irn, const arch_register_t *reg, set *reg_set); +const arch_register_t *TEMPLATE_get_firm_reg(const ir_node *irn, set *reg_set); + +long TEMPLATE_translate_proj_pos(const ir_node *proj); + +#endif /* _TEMPLATE_MAP_REGS_H_ */ diff --git a/ir/be/TEMPLATE/TEMPLATE_new_nodes.c b/ir/be/TEMPLATE/TEMPLATE_new_nodes.c index 670824f56..b09d95f4b 100644 --- a/ir/be/TEMPLATE/TEMPLATE_new_nodes.c +++ b/ir/be/TEMPLATE/TEMPLATE_new_nodes.c @@ -7,6 +7,12 @@ #include "config.h" #endif +#ifdef _WIN32 +#include +#else +#include +#endif + #include #include "irprog_t.h" @@ -18,6 +24,7 @@ #include "irop.h" #include "firm_common_t.h" #include "irvrfy_t.h" +#include "irprintf.h" #include "../bearch.h" @@ -38,6 +45,82 @@ * |_| ***********************************************************************************/ +/** + * Returns a string containing the names of all registers within the limited bitset + */ +static char *get_limited_regs(const arch_register_req_t *req, char *buf, int max) { + bitset_t *bs = bitset_alloca(req->cls->n_regs); + char *p = buf; + int size = 0; + int i, cnt; + + req->limited(NULL, bs); + + for (i = 0; i < req->cls->n_regs; i++) { + if (bitset_is_set(bs, i)) { + cnt = snprintf(p, max - size, " %s", req->cls->regs[i].name); + if (cnt < 0) { + fprintf(stderr, "dumper problem, exiting\n"); + exit(1); + } + + p += cnt; + size += cnt; + + if (size >= max) + break; + } + } + + return buf; +} + +/** + * Dumps the register requirements for either in or out. + */ +static void dump_reg_req(FILE *F, ir_node *n, const TEMPLATE_register_req_t **reqs, int inout) { + char *dir = inout ? "out" : "in"; + int max = inout ? get_TEMPLATE_n_res(n) : get_irn_arity(n); + char *buf = alloca(1024); + int i; + + memset(buf, 0, 1024); + + if (reqs) { + for (i = 0; i < max; i++) { + fprintf(F, "%sreq #%d =", dir, i); + + if (reqs[i]->req.type == arch_register_req_type_none) { + fprintf(F, " n/a"); + } + + if (reqs[i]->req.type & arch_register_req_type_normal) { + fprintf(F, " %s", reqs[i]->req.cls->name); + } + + if (reqs[i]->req.type & arch_register_req_type_limited) { + fprintf(F, " %s", get_limited_regs(&reqs[i]->req, buf, 1024)); + } + + if (reqs[i]->req.type & arch_register_req_type_should_be_same) { + ir_fprintf(F, " same as %+F", get_irn_n(n, reqs[i]->same_pos)); + } + + if (reqs[i]->req.type & arch_register_req_type_should_be_different) { + ir_fprintf(F, " different from %+F", get_irn_n(n, reqs[i]->different_pos)); + } + + fprintf(F, "\n"); + } + + fprintf(F, "\n"); + } + else { + fprintf(F, "%sreq = N/A\n", dir); + } +} + + /** * Dumper interface for dumping TEMPLATE nodes in vcg. * @param n the node to dump @@ -46,80 +129,50 @@ * @return 0 on success or != 0 on failure */ static int dump_node_TEMPLATE(ir_node *n, FILE *F, dump_reason_t reason) { - const char *name, *p; - ir_mode *mode = NULL; - int bad = 0; - int i; + ir_mode *mode = NULL; + int bad = 0; + int i; TEMPLATE_attr_t *attr; const TEMPLATE_register_req_t **reqs; - const arch_register_t **slots; + const arch_register_t **slots; switch (reason) { case dump_node_opcode_txt: - name = get_irn_opname(n); - fprintf(F, "%s", name); + fprintf(F, "%s", get_irn_opname(n)); break; case dump_node_mode_txt: mode = get_irn_mode(n); - if (mode == mode_BB || mode == mode_ANY || mode == mode_BAD || mode == mode_T) { - mode = NULL; - } - if (mode) { fprintf(F, "[%s]", get_mode_name(mode)); } + else { + fprintf(F, "[?NOMODE?]"); + } break; case dump_node_nodeattr_txt: - /* TODO: Dump node specific attributes which should */ - /* visible in node name (e.g. const or the like). */ + /* TODO: dump some attributes which should show up */ + /* in node name in dump (e.g. consts or the like) */ break; case dump_node_info_txt: attr = get_TEMPLATE_attr(n); + fprintf(F, "=== TEMPLATE attr begin ===\n"); /* dump IN requirements */ if (get_irn_arity(n) > 0) { reqs = get_TEMPLATE_in_req_all(n); - - if (reqs) { - for (i = 0; i < get_irn_arity(n); i++) { - if (reqs[i]->req.type != arch_register_req_type_none) { - fprintf(F, "in req #%d = [%s]\n", i, reqs[i]->req.cls->name); - } - else { - fprintf(F, "in req #%d = n/a\n", i); - } - } - - fprintf(F, "\n"); - } - else { - fprintf(F, "in req = N/A\n"); - } + dump_reg_req(F, n, reqs, 0); } /* dump OUT requirements */ if (attr->n_res > 0) { reqs = get_TEMPLATE_out_req_all(n); - - if (reqs) { - for (i = 0; i < attr->n_res; i++) { - if (reqs[i]->req.type != arch_register_req_type_none) { - fprintf(F, "out req #%d = [%s]\n", i, reqs[i]->req.cls->name); - } - else { - fprintf(F, "out req #%d = n/a\n", i); - } - } - } - else { - fprintf(F, "out req = N/A\n"); - } + dump_reg_req(F, n, reqs, 1); } /* dump assigned registers */ @@ -134,10 +187,37 @@ static int dump_node_TEMPLATE(ir_node *n, FILE *F, dump_reason_t reason) { } } } + fprintf(F, "\n"); + /* dump n_res */ + fprintf(F, "n_res = %d\n", get_TEMPLATE_n_res(n)); + + /* dump flags */ + fprintf(F, "flags ="); + if (attr->flags == arch_irn_flags_none) { + fprintf(F, " none"); + } + else { + if (attr->flags & arch_irn_flags_dont_spill) { + fprintf(F, " unspillable"); + } + if (attr->flags & arch_irn_flags_rematerializable) { + fprintf(F, " remat"); + } + if (attr->flags & arch_irn_flags_ignore) { + fprintf(F, " ignore"); + } + } + fprintf(F, " (%d)\n", attr->flags); + + /* TODO: dump all additional attributes */ + + fprintf(F, "=== TEMPLATE attr end ===\n"); + /* end of: case dump_node_info_txt */ break; } + return bad; } diff --git a/ir/be/TEMPLATE/TEMPLATE_new_nodes.h b/ir/be/TEMPLATE/TEMPLATE_new_nodes.h index 48d0b6d38..b67c06c48 100644 --- a/ir/be/TEMPLATE/TEMPLATE_new_nodes.h +++ b/ir/be/TEMPLATE/TEMPLATE_new_nodes.h @@ -22,7 +22,7 @@ /** * Returns the attributes of an TEMPLATE node. */ -TEMPLATE_attr *get_TEMPLATE_attr(const ir_node *node); +TEMPLATE_attr_t *get_TEMPLATE_attr(const ir_node *node); /** * Returns the argument register requirements of an TEMPLATE node. diff --git a/ir/be/TEMPLATE/TEMPLATE_nodes_attr.h b/ir/be/TEMPLATE/TEMPLATE_nodes_attr.h index 156ef65e0..e33c73475 100644 --- a/ir/be/TEMPLATE/TEMPLATE_nodes_attr.h +++ b/ir/be/TEMPLATE/TEMPLATE_nodes_attr.h @@ -5,7 +5,8 @@ typedef struct _TEMPLATE_register_req_t { const arch_register_req_t req; - int pos; /**<< in case of "should be same/different" we need to remember the pos to get the irn */ + int same_pos; /**<< in case of "should be same" we need to remember the pos to get the irn */ + int different_pos; /**<< in case of "should be different" we need to remember the pos to get the irn */ } TEMPLATE_register_req_t; diff --git a/ir/be/TEMPLATE/TEMPLATE_spec.pl b/ir/be/TEMPLATE/TEMPLATE_spec.pl index 85ced05a3..a7ff0bc80 100644 --- a/ir/be/TEMPLATE/TEMPLATE_spec.pl +++ b/ir/be/TEMPLATE/TEMPLATE_spec.pl @@ -12,15 +12,19 @@ $arch = "TEMPLATE"; # %nodes = ( # # => { -# "op_flags" => "N|L|C|X|I|F|Y|H|c|K", -# "arity" => "0|1|2|3|variable|dynamic|all", -# "state" => "floats|pinned", -# "args" => [ -# { "type" => "type 1", "name" => "name 1" }, -# { "type" => "type 2", "name" => "name 2" }, -# ... -# ], -# "comment" => "any comment for constructor", +# "op_flags" => "N|L|C|X|I|F|Y|H|c|K", +# "irn_flags" => "R|N|I" +# "arity" => "0|1|2|3 ... |variable|dynamic|any", +# "state" => "floats|pinned|mem_pinned|exc_pinned", +# "args" => [ +# { "type" => "type 1", "name" => "name 1" }, +# { "type" => "type 2", "name" => "name 2" }, +# ... +# ], +# "comment" => "any comment for constructor", +# "reg_req" => { "in" => [ "reg_class|register" ], "out" => [ "reg_class|register|in_rX" ] }, +# "cmp_attr" => "c source code for comparing node attributes", +# "emit" => "emit code with templates", # "rd_constructor" => "c source code which constructs an ir_node" # }, # @@ -28,6 +32,7 @@ $arch = "TEMPLATE"; # # ); # close the %nodes initializer +# op_flags: flags for the operation, OPTIONAL (default is "N") # the op_flags correspond to the firm irop_flags: # N irop_flag_none # L irop_flag_labeled @@ -40,9 +45,13 @@ $arch = "TEMPLATE"; # c irop_flag_constlike # K irop_flag_keep # -# op_flags: flags for the operation, OPTIONAL (default is "N") +# irn_flags: special node flags, OPTIONAL (default is 0) +# following irn_flags are supported: +# R rematerializeable +# N not spillable +# I ignore for register allocation # -# state: state of the operation, OPTIONAL (default is "pinned") +# state: state of the operation, OPTIONAL (default is "floats") # # arity: arity of the operation, MUST NOT BE OMITTED # @@ -73,50 +82,48 @@ $arch = "TEMPLATE"; # register types: # 0 - no special type -# 1 - write invariant (writes to this register doesn't change it's content) -# 2 - caller save (register must be saved by the caller of a function) -# 3 - callee save (register must be saved by the called function) +# 1 - caller save (register must be saved by the caller of a function) +# 2 - callee save (register must be saved by the called function) # 4 - ignore (do not assign this register) -# NOTE: Make sure to list the registers returning the call-result before all other -# caller save registers and in the correct order, otherwise it will break -# the magic! - +# NOTE: Last entry of each class is the largest Firm-Mode a register can hold %reg_classes = ( "general_purpose" => [ - { "name" => "r0", "type" => 2 }, - { "name" => "r1", "type" => 2 }, - { "name" => "r2", "type" => 3 }, - { "name" => "r3", "type" => 2 }, - { "name" => "r4", "type" => 3 }, - { "name" => "r5", "type" => 3 }, - { "name" => "r6", "type" => 4 }, # this is our stackpointer - { "name" => "r7", "type" => 3 }, - { "name" => "r8", "type" => 3 }, - { "name" => "r9", "type" => 3 }, - { "name" => "r10", "type" => 3 }, - { "name" => "r11", "type" => 3 }, - { "name" => "r12", "type" => 3 }, - { "name" => "r13", "type" => 3 }, - { "name" => "r14", "type" => 3 }, - { "name" => "r15", "type" => 3 } + { "name" => "r0", "type" => 1 }, + { "name" => "r1", "type" => 1 }, + { "name" => "r2", "type" => 1 }, + { "name" => "r3", "type" => 1 }, + { "name" => "r4", "type" => 1 }, + { "name" => "r5", "type" => 1 }, + { "name" => "r6", "type" => 6 }, # this is our stackpointer + { "name" => "r7", "type" => 6 }, # this is out basepointer + { "name" => "r8", "type" => 2 }, + { "name" => "r9", "type" => 2 }, + { "name" => "r10", "type" => 2 }, + { "name" => "r11", "type" => 2 }, + { "name" => "r12", "type" => 2 }, + { "name" => "r13", "type" => 2 }, + { "name" => "r14", "type" => 2 }, + { "name" => "r15", "type" => 2 }, + { "mode" => "mode_P" } ], "floating_point" => [ - { "name" => "f0", "type" => 2 }, - { "name" => "f1", "type" => 2 }, - { "name" => "f2", "type" => 2 }, - { "name" => "f3", "type" => 2 }, - { "name" => "f4", "type" => 2 }, - { "name" => "f5", "type" => 2 }, - { "name" => "f6", "type" => 2 }, - { "name" => "f7", "type" => 2 }, - { "name" => "f8", "type" => 2 }, - { "name" => "f9", "type" => 2 }, - { "name" => "f10", "type" => 2 }, - { "name" => "f11", "type" => 2 }, - { "name" => "f12", "type" => 2 }, - { "name" => "f13", "type" => 2 }, - { "name" => "f14", "type" => 2 }, - { "name" => "f15", "type" => 2 } + { "name" => "f0", "type" => 1 }, + { "name" => "f1", "type" => 1 }, + { "name" => "f2", "type" => 1 }, + { "name" => "f3", "type" => 1 }, + { "name" => "f4", "type" => 1 }, + { "name" => "f5", "type" => 1 }, + { "name" => "f6", "type" => 1 }, + { "name" => "f7", "type" => 1 }, + { "name" => "f8", "type" => 1 }, + { "name" => "f9", "type" => 1 }, + { "name" => "f10", "type" => 1 }, + { "name" => "f11", "type" => 1 }, + { "name" => "f12", "type" => 1 }, + { "name" => "f13", "type" => 1 }, + { "name" => "f14", "type" => 1 }, + { "name" => "f15", "type" => 1 }, + { "mode" => "mode_D" } ] ); # %reg_classes @@ -147,185 +154,165 @@ $arch = "TEMPLATE"; # commutative operations "Add" => { - "op_flags" => "C", - "arity" => 2, - "remat" => 1, - "comment" => "construct Add: Add(a, b) = Add(b, a) = a + b", - "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. add %S1, %S2, %D1\t\t\t/* Add(%S1, %S2) -> %D1, (%A1, %A2) */' + "op_flags" => "C", + "irn_flags" => "R", + "comment" => "construct Add: Add(a, b) = Add(b, a) = a + b", + "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, + "emit" => '. add %S1, %S2, %D1\t\t\t/* Add(%S1, %S2) -> %D1, (%A1, %A2) */' }, "Add_i" => { - "arity" => 1, - "remat" => 1, - "comment" => "construct Add: Add(a, const) = Add(const, a) = a + const", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. add %S1, %C, %D1\t\t\t/* Add(%C, %S1) -> %D1, (%A1, const) */' + "irn_flags" => "R", + "comment" => "construct Add: Add(a, const) = Add(const, a) = a + const", + "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, + "emit" => '. add %S1, %C, %D1\t\t\t/* Add(%C, %S1) -> %D1, (%A1, const) */' }, "Mul" => { - "op_flags" => "C", - "arity" => 2, - "comment" => "construct Mul: Mul(a, b) = Mul(b, a) = a * b", - "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" =>'. mul %S1, %S2, %D1\t\t\t/* Mul(%S1, %S2) -> %D1, (%A1, %A2) */' + "op_flags" => "C", + "irn_flags" => "R", + "comment" => "construct Mul: Mul(a, b) = Mul(b, a) = a * b", + "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, + "emit" =>'. mul %S1, %S2, %D1\t\t\t/* Mul(%S1, %S2) -> %D1, (%A1, %A2) */' }, "Mul_i" => { - "state" => "pinned", - "arity" => 1, - "comment" => "construct Mul: Mul(a, const) = Mul(const, a) = a * const", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. mul %S1, %C, %D1\t\t\t/* signed Mul(%C, %S1) -> %D1, (%A1, const) */' + "irn_flags" => "R", + "comment" => "construct Mul: Mul(a, const) = Mul(const, a) = a * const", + "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, + "emit" => '. mul %S1, %C, %D1\t\t\t/* signed Mul(%C, %S1) -> %D1, (%A1, const) */' }, "And" => { - "op_flags" => "C", - "arity" => 2, - "remat" => 1, - "comment" => "construct And: And(a, b) = And(b, a) = a AND b", - "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. and %S1, %S2, %D1\t\t\t/* And(%S1, %S2) -> %D1, (%A1, %A2) */' + "op_flags" => "C", + "irn_flags" => "R", + "comment" => "construct And: And(a, b) = And(b, a) = a AND b", + "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, + "emit" => '. and %S1, %S2, %D1\t\t\t/* And(%S1, %S2) -> %D1, (%A1, %A2) */' }, "And_i" => { - "arity" => 1, - "remat" => 1, - "comment" => "construct And: And(a, const) = And(const, a) = a AND const", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. and %S1, %C, %D1\t\t\t/* And(%C, %S1) -> %D1, (%A1, const) */' + "irn_flags" => "R", + "comment" => "construct And: And(a, const) = And(const, a) = a AND const", + "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, + "emit" => '. and %S1, %C, %D1\t\t\t/* And(%C, %S1) -> %D1, (%A1, const) */' }, "Or" => { - "op_flags" => "C", - "arity" => 2, - "remat" => 1, - "comment" => "construct Or: Or(a, b) = Or(b, a) = a OR b", - "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. or %S1, %S2, %D1\t\t\t/* Or(%S1, %S2) -> %D1, (%A1, %A2) */' + "op_flags" => "C", + "irn_flags" => "R", + "comment" => "construct Or: Or(a, b) = Or(b, a) = a OR b", + "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, + "emit" => '. or %S1, %S2, %D1\t\t\t/* Or(%S1, %S2) -> %D1, (%A1, %A2) */' }, "Or_i" => { - "arity" => 1, - "remat" => 1, - "comment" => "construct Or: Or(a, const) = Or(const, a) = a OR const", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. or %S1, %C, %D1\t\t\t/* Or(%C, %S1) -> %D1, (%A1, const) */' + "op_flags" => "C", + "irn_flags" => "R", + "comment" => "construct Or: Or(a, const) = Or(const, a) = a OR const", + "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, + "emit" => '. or %S1, %C, %D1\t\t\t/* Or(%C, %S1) -> %D1, (%A1, const) */' }, "Eor" => { - "op_flags" => "C", - "arity" => 2, - "remat" => 1, - "comment" => "construct Eor: Eor(a, b) = Eor(b, a) = a EOR b", - "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. xor %S1, %S2, %D1\t\t\t/* Xor(%S1, %S2) -> %D1, (%A1, %A2) */' + "op_flags" => "C", + "irn_flags" => "R", + "comment" => "construct Eor: Eor(a, b) = Eor(b, a) = a EOR b", + "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, + "emit" => '. xor %S1, %S2, %D1\t\t\t/* Xor(%S1, %S2) -> %D1, (%A1, %A2) */' }, "Eor_i" => { - "arity" => 1, - "remat" => 1, - "comment" => "construct Eor: Eor(a, const) = Eor(const, a) = a EOR const", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. xor %S1, %C, %D1\t\t\t/* Xor(%C, %S1) -> %D1, (%A1, const) */' + "irn_flags" => "R", + "comment" => "construct Eor: Eor(a, const) = Eor(const, a) = a EOR const", + "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, + "emit" => '. xor %S1, %C, %D1\t\t\t/* Xor(%C, %S1) -> %D1, (%A1, const) */' }, # not commutative operations "Sub" => { - "arity" => 2, - "remat" => 1, - "comment" => "construct Sub: Sub(a, b) = a - b", - "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. sub %S1, %S2, %D1\t\t\t/* Sub(%S1, %S2) -> %D1, (%A1, %A2) */' + "irn_flags" => "R", + "comment" => "construct Sub: Sub(a, b) = a - b", + "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, + "emit" => '. sub %S1, %S2, %D1\t\t\t/* Sub(%S1, %S2) -> %D1, (%A1, %A2) */' }, "Sub_i" => { - "arity" => 1, - "remat" => 1, - "comment" => "construct Sub: Sub(a, const) = a - const", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. subl %S1, %C, %D1\t\t\t/* Sub(%S1, %C) -> %D1, (%A1, const) */' + "irn_flags" => "R", + "comment" => "construct Sub: Sub(a, const) = a - const", + "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, + "emit" => '. subl %S1, %C, %D1\t\t\t/* Sub(%S1, %C) -> %D1, (%A1, const) */' }, "Shl" => { - "arity" => 2, - "remat" => 1, - "comment" => "construct Shl: Shl(a, b) = a << b", - "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. shl %S1, %S2, %D1\t\t\t/* Shl(%S1, %S2) -> %D1, (%A1, %A2) */' + "irn_flags" => "R", + "comment" => "construct Shl: Shl(a, b) = a << b", + "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, + "emit" => '. shl %S1, %S2, %D1\t\t\t/* Shl(%S1, %S2) -> %D1, (%A1, %A2) */' }, "Shl_i" => { - "arity" => 1, - "remat" => 1, - "comment" => "construct Shl: Shl(a, const) = a << const", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. shl %S1, %C, %D1\t\t\t/* Shl(%S1, %C) -> %D1, (%A1, const) */' + "irn_flags" => "R", + "comment" => "construct Shl: Shl(a, const) = a << const", + "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, + "emit" => '. shl %S1, %C, %D1\t\t\t/* Shl(%S1, %C) -> %D1, (%A1, const) */' }, "Shr" => { - "arity" => 2, - "remat" => 1, - "comment" => "construct Shr: Shr(a, b) = a >> b", - "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "in_r1" ] }, - "emit" => '. shr %S2, %D1\t\t\t/* Shr(%S1, %S2) -> %D1, (%A1, %A2) */' + "irn_flags" => "R", + "comment" => "construct Shr: Shr(a, b) = a >> b", + "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "in_r1" ] }, + "emit" => '. shr %S2, %D1\t\t\t/* Shr(%S1, %S2) -> %D1, (%A1, %A2) */' }, "Shr_i" => { - "arity" => 1, - "remat" => 1, - "comment" => "construct Shr: Shr(a, const) = a >> const", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. shr %S1, %C, %D1\t\t\t/* Shr(%S1, %C) -> %D1, (%A1, const) */' + "irn_flags" => "R", + "comment" => "construct Shr: Shr(a, const) = a >> const", + "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, + "emit" => '. shr %S1, %C, %D1\t\t\t/* Shr(%S1, %C) -> %D1, (%A1, const) */' }, "RotR" => { - "arity" => 2, - "remat" => 1, - "comment" => "construct RotR: RotR(a, b) = a ROTR b", - "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. ror %S1, %S2, %D1\t\t\t/* RotR(%S1, %S2) -> %D1, (%A1, %A2) */' + "irn_flags" => "R", + "comment" => "construct RotR: RotR(a, b) = a ROTR b", + "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, + "emit" => '. ror %S1, %S2, %D1\t\t\t/* RotR(%S1, %S2) -> %D1, (%A1, %A2) */' }, "RotL" => { - "arity" => 2, - "remat" => 1, - "comment" => "construct RotL: RotL(a, b) = a ROTL b", - "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. rol %S1, %S2, %D1\t\t\t/* RotL(%S1, %S2) -> %D1, (%A1, %A2) */' + "irn_flags" => "R", + "comment" => "construct RotL: RotL(a, b) = a ROTL b", + "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, + "emit" => '. rol %S1, %S2, %D1\t\t\t/* RotL(%S1, %S2) -> %D1, (%A1, %A2) */' }, "RotL_i" => { - "arity" => 1, - "remat" => 1, - "comment" => "construct RotL: RotL(a, const) = a ROTL const", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. rol %S1, %C, %D1\t\t\t/* RotL(%S1, %C) -> %D1, (%A1, const) */' + "irn_flags" => "R", + "comment" => "construct RotL: RotL(a, const) = a ROTL const", + "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, + "emit" => '. rol %S1, %C, %D1\t\t\t/* RotL(%S1, %C) -> %D1, (%A1, const) */' }, "Minus" => { - "arity" => 1, - "remat" => 1, - "comment" => "construct Minus: Minus(a) = -a", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. neg %S1, %D1\t\t\t/* Neg(%S1) -> %D1, (%A1) */' + "irn_flags" => "R", + "comment" => "construct Minus: Minus(a) = -a", + "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, + "emit" => '. neg %S1, %D1\t\t\t/* Neg(%S1) -> %D1, (%A1) */' }, "Inc" => { - "arity" => 1, - "remat" => 1, - "comment" => "construct Increment: Inc(a) = a++", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. inc %S1, %D1\t\t\t/* Inc(%S1) -> %D1, (%A1) */' + "irn_flags" => "R", + "comment" => "construct Increment: Inc(a) = a++", + "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, + "emit" => '. inc %S1, %D1\t\t\t/* Inc(%S1) -> %D1, (%A1) */' }, "Dec" => { - "arity" => 1, - "remat" => 1, - "comment" => "construct Decrement: Dec(a) = a--", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. dec %S1, %D1\t\t\t/* Dec(%S1) -> %D1, (%A1) */' + "irn_flags" => "R", + "comment" => "construct Decrement: Dec(a) = a--", + "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, + "emit" => '. dec %S1, %D1\t\t\t/* Dec(%S1) -> %D1, (%A1) */' }, "Not" => { @@ -339,32 +326,14 @@ $arch = "TEMPLATE"; # other operations "Const" => { - "op_flags" => "c", - "arity" => "0", - "remat" => 1, - "comment" => "represents an integer constant", - "reg_req" => { "out" => [ "general_purpose" ] }, - "emit" => '. mov %C, %D1\t\t\t/* Mov Const into register */', - "cmp_attr" => + "op_flags" => "c", + "irn_flags" => "R", + "comment" => "represents an integer constant", + "reg_req" => { "out" => [ "general_purpose" ] }, + "emit" => '. mov %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 + /* TODO: compare Const attributes */ return 1; ' }, @@ -372,23 +341,21 @@ $arch = "TEMPLATE"; # Load / Store "Load" => { - "op_flags" => "L|F", - "state" => "exc_pinned", - "arity" => 2, - "remat" => 1, - "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg", - "reg_req" => { "in" => [ "general_purpose", "none" ], "out" => [ "general_purpose" ] }, - "emit" => '. mov %O(%S1), %D1\t\t\t/* Load((%S1)) -> %D1, (%A1) */' + "op_flags" => "L|F", + "irn_flags" => "R", + "state" => "exc_pinned", + "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg", + "reg_req" => { "in" => [ "general_purpose", "none" ], "out" => [ "general_purpose" ] }, + "emit" => '. mov %O(%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(ptr, val, mem) = ST ptr,val", - "reg_req" => { "in" => [ "general_purpose", "general_purpose", "none" ] }, - "emit" => '. movl %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */' + "op_flags" => "L|F", + "irn_flags" => "R", + "state" => "exc_pinned", + "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", + "reg_req" => { "in" => [ "general_purpose", "general_purpose", "none" ] }, + "emit" => '. movl %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */' }, #--------------------------------------------------------# @@ -403,154 +370,91 @@ $arch = "TEMPLATE"; # commutative operations "fAdd" => { - "op_flags" => "C", - "arity" => 2, - "remat" => 1, - "comment" => "construct FP Add: Add(a, b) = Add(b, a) = a + b", - "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] }, - "emit" => '. fadd %S1, %S2, %D1\t\t\t/* FP Add(%S1, %S2) -> %D1 */' + "op_flags" => "C", + "irn_flags" => "R", + "comment" => "construct FP Add: Add(a, b) = Add(b, a) = a + b", + "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] }, + "emit" => '. fadd %S1, %S2, %D1\t\t\t/* FP Add(%S1, %S2) -> %D1 */' }, "fMul" => { - "op_flags" => "C", - "arity" => 2, - "comment" => "construct FP Mul: Mul(a, b) = Mul(b, a) = a * b", - "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] }, - "emit" =>'. fmul %S1, %S2, %D1\t\t\t/* FP Mul(%S1, %S2) -> %D1 */' + "op_flags" => "C", + "comment" => "construct FP Mul: Mul(a, b) = Mul(b, a) = a * b", + "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] }, + "emit" =>'. fmul %S1, %S2, %D1\t\t\t/* FP Mul(%S1, %S2) -> %D1 */' }, "fMax" => { - "op_flags" => "C", - "arity" => 2, - "remat" => 1, - "comment" => "construct FP Max: Max(a, b) = Max(b, a) = a > b ? a : b", - "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] }, - "emit" =>'. fmax %S1, %S2, %D1\t\t\t/* FP Max(%S1, %S2) -> %D1 */' + "op_flags" => "C", + "irn_flags" => "R", + "comment" => "construct FP Max: Max(a, b) = Max(b, a) = a > b ? a : b", + "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] }, + "emit" =>'. fmax %S1, %S2, %D1\t\t\t/* FP Max(%S1, %S2) -> %D1 */' }, "fMin" => { - "op_flags" => "C", - "arity" => 2, - "remat" => 1, - "comment" => "construct FP Min: Min(a, b) = Min(b, a) = a < b ? a : b", - "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] }, - "emit" =>'. fmin %S1, %S2, %D1\t\t\t/* FP Min(%S1, %S2) -> %D1 */' + "op_flags" => "C", + "irn_flags" => "R", + "comment" => "construct FP Min: Min(a, b) = Min(b, a) = a < b ? a : b", + "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] }, + "emit" =>'. fmin %S1, %S2, %D1\t\t\t/* FP Min(%S1, %S2) -> %D1 */' }, # not commutative operations "fSub" => { - "arity" => 2, - "remat" => 1, - "comment" => "construct FP Sub: Sub(a, b) = a - b", - "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] }, - "emit" => '. fsub %S1, %S2, %D1\t\t\t/* FP Sub(%S1, %S2) -> %D1 */' + "irn_flags" => "R", + "comment" => "construct FP Sub: Sub(a, b) = a - b", + "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] }, + "emit" => '. fsub %S1, %S2, %D1\t\t\t/* FP Sub(%S1, %S2) -> %D1 */' }, "fDiv" => { - "arity" => 2, - "remat" => 1, - "comment" => "construct FP Div: Div(a, b) = a / b", - "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] }, - "emit" => '. fdiv %S1, %S2, %D1\t\t\t/* FP Div(%S1, %S2) -> %D1 */' + "comment" => "construct FP Div: Div(a, b) = a / b", + "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] }, + "emit" => '. fdiv %S1, %S2, %D1\t\t\t/* FP Div(%S1, %S2) -> %D1 */' }, "fMinus" => { - "arity" => 1, - "remat" => 1, - "comment" => "construct FP Minus: Minus(a) = -a", - "reg_req" => { "in" => [ "floating_point" ], "out" => [ "floating_point" ] }, - "emit" => '. fneg %S1, %D1\t\t\t/* FP Minus(%S1) -> %D1 */' + "irn_flags" => "R", + "comment" => "construct FP Minus: Minus(a) = -a", + "reg_req" => { "in" => [ "floating_point" ], "out" => [ "floating_point" ] }, + "emit" => '. fneg %S1, %D1\t\t\t/* FP Minus(%S1) -> %D1 */' }, # other operations "fConst" => { - "op_flags" => "c", - "arity" => "0", - "remat" => 1, - "comment" => "represents a FP constant", - "reg_req" => { "out" => [ "floating_point" ] }, - "emit" => '. fmov %C, %D1\t\t\t/* Mov fConst into register */', - "cmp_attr" => + "op_flags" => "c", + "irn_flags" => "R", + "comment" => "represents a FP constant", + "reg_req" => { "out" => [ "floating_point" ] }, + "emit" => '. fmov %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; + /* TODO: compare fConst attributes */ + return 1; ' }, # Load / Store "fLoad" => { - "op_flags" => "L|F", - "state" => "exc_pinned", - "arity" => 2, - "remat" => 1, - "comment" => "construct FP Load: Load(ptr, mem) = LD ptr", - "reg_req" => { "in" => [ "general_purpose", "none" ], "out" => [ "floating_point" ] }, - "emit" => '. fmov %O(%S1), %D1\t\t\t/* Load((%S1)) -> %D1 */' + "op_flags" => "L|F", + "irn_flags" => "R", + "state" => "exc_pinned", + "comment" => "construct FP Load: Load(ptr, mem) = LD ptr", + "reg_req" => { "in" => [ "general_purpose", "none" ], "out" => [ "floating_point" ] }, + "emit" => '. fmov %O(%S1), %D1\t\t\t/* Load((%S1)) -> %D1 */' }, "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" => '. fmov %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */' -}, - -# Call - -"Call" => { - "op_flags" => "L|F", - "state" => "mem_pinned", - "arity" => "variable", - "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); -" -}, - -# M/Alloc - -"Alloca" => { - "op_flags" => "L|F", - "state" => "pinned", - "arity" => "2", - "comment" => "construct Alloca: allocate memory on Stack", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] } -}, - -"Alloca_i" => { - "op_flags" => "L|F", - "state" => "pinned", - "arity" => "1", - "comment" => "construct Alloca: allocate memory on Stack", - "reg_req" => { "out" => [ "general_purpose" ] } -} + "op_flags" => "L|F", + "irn_flags" => "R", + "state" => "exc_pinned", + "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", + "reg_req" => { "in" => [ "general_purpose", "floating_point", "none" ] }, + "emit" => '. fmov %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */' +}, ); # end of %nodes diff --git a/ir/be/TEMPLATE/TEMPLATE_transform.c b/ir/be/TEMPLATE/TEMPLATE_transform.c new file mode 100644 index 000000000..93bcdccf6 --- /dev/null +++ b/ir/be/TEMPLATE/TEMPLATE_transform.c @@ -0,0 +1,415 @@ +/* The codegenrator (transform FIRM into TEMPLATE FIRM */ +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "irnode_t.h" +#include "irgraph_t.h" +#include "irmode_t.h" +#include "irgmod.h" +#include "iredges.h" +#include "irvrfy.h" +#include "ircons.h" +#include "dbginfo.h" +#include "iropt_t.h" +#include "debug.h" + +#include "../benode_t.h" +#include "bearch_TEMPLATE_t.h" + +#include "TEMPLATE_nodes_attr.h" +#include "../arch/archop.h" /* we need this for Min and Max nodes */ +#include "TEMPLATE_transform.h" +#include "TEMPLATE_new_nodes.h" +#include "TEMPLATE_map_regs.h" + +#include "gen_TEMPLATE_regalloc_if.h" + +extern ir_op *get_op_Mulh(void); + + + +/**************************************************************************************************** + * _ _ __ _ _ + * | | | | / _| | | (_) + * _ __ ___ __| | ___ | |_ _ __ __ _ _ __ ___| |_ ___ _ __ _ __ ___ __ _| |_ _ ___ _ __ + * | '_ \ / _ \ / _` |/ _ \ | __| '__/ _` | '_ \/ __| _/ _ \| '__| '_ ` _ \ / _` | __| |/ _ \| '_ \ + * | | | | (_) | (_| | __/ | |_| | | (_| | | | \__ \ || (_) | | | | | | | | (_| | |_| | (_) | | | | + * |_| |_|\___/ \__,_|\___| \__|_| \__,_|_| |_|___/_| \___/|_| |_| |_| |_|\__,_|\__|_|\___/|_| |_| + * + ****************************************************************************************************/ + +/** + * Creates an TEMPLATE Add. + * + * @param env The transformation environment + * @param op1 first operator + * @param op2 second operator + * @return the created TEMPLATE Add node + */ +static ir_node *gen_Add(TEMPLATE_transform_env_t *env, ir_node *op1, ir_node *op2) { + return new_rd_TEMPLATE_Add(env->dbg, env->irg, env->block, op1, op2, env->mode); +} + + + +/** + * Creates an TEMPLATE Mul. + * + * @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 TEMPLATE Mul node + */ +static ir_node *gen_Mul(TEMPLATE_transform_env_t *env, ir_node *op1, ir_node *op2) { + if (mode_is_float(env->mode)) { + return new_rd_TEMPLATE_fMul(env->dbg, env->irg, env->block, op1, op2, env->mode); + } + else { + return new_rd_TEMPLATE_Mul(env->dbg, env->irg, env->block, op1, op2, env->mode); + } +} + + + +/** + * Creates an TEMPLATE And. + * + * @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 TEMPLATE And node + */ +static ir_node *gen_And(TEMPLATE_transform_env_t *env, ir_node *op1, ir_node *op2) { + return new_rd_TEMPLATE_And(env->dbg, env->irg, env->block, op1, op2, env->mode); +} + + + +/** + * Creates an TEMPLATE Or. + * + * @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 TEMPLATE Or node + */ +static ir_node *gen_Or(TEMPLATE_transform_env_t *env, ir_node *op1, ir_node *op2) { + return new_rd_TEMPLATE_Or(env->dbg, env->irg, env->block, op1, op2, env->mode); +} + + + +/** + * Creates an TEMPLATE Eor. + * + * @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 TEMPLATE Eor node + */ +static ir_node *gen_Eor(TEMPLATE_transform_env_t *env, ir_node *op1, ir_node *op2) { + return new_rd_TEMPLATE_Eor(env->dbg, env->irg, env->block, op1, op2, env->mode); +} + + + +/** + * Creates an TEMPLATE Sub. + * + * @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 TEMPLATE Sub node + */ +static ir_node *gen_Sub(TEMPLATE_transform_env_t *env, ir_node *op1, ir_node *op2) { + if (mode_is_float(env->mode)) { + return new_rd_TEMPLATE_fSub(env->dbg, env->irg, env->block, op1, op2, env->mode); + } + else { + return new_rd_TEMPLATE_Sub(env->dbg, env->irg, env->block, op1, op2, env->mode); + } +} + + + +/** + * Creates an TEMPLATE 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 TEMPLATE fDiv node + */ +static ir_node *gen_Quot(TEMPLATE_transform_env_t *env, ir_node *op1, ir_node *op2) { + return new_rd_TEMPLATE_fDiv(env->dbg, env->irg, env->block, op1, op2, env->mode); +} + + + +/** + * Creates an TEMPLATE Shl. + * + * @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 TEMPLATE Shl node + */ +static ir_node *gen_Shl(TEMPLATE_transform_env_t *env, ir_node *op1, ir_node *op2) { + return new_rd_TEMPLATE_Shl(env->dbg, env->irg, env->block, op1, op2, env->mode); +} + + + +/** + * Creates an TEMPLATE Shr. + * + * @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 TEMPLATE Shr node + */ +static ir_node *gen_Shr(TEMPLATE_transform_env_t *env, ir_node *op1, ir_node *op2) { + return new_rd_TEMPLATE_Shr(env->dbg, env->irg, env->block, op1, op2, env->mode); +} + + + +/** + * Creates an TEMPLATE RotL. + * + * @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 TEMPLATE RotL node + */ +static ir_node *gen_RotL(TEMPLATE_transform_env_t *env, ir_node *op1, ir_node *op2) { + return new_rd_TEMPLATE_RotL(env->dbg, env->irg, env->block, op1, op2, env->mode); +} + + + +/** + * Transforms a Minus node. + * + * @param mod the debug module + * @param block the block the new node should belong to + * @param node the ir Minus node + * @param op operator + * @param mode node mode + * @return the created TEMPLATE Minus node + */ +static ir_node *gen_Minus(TEMPLATE_transform_env_t *env, ir_node *op) { + if (mode_is_float(env->mode)) { + return new_rd_TEMPLATE_fMinus(env->dbg, env->irg, env->block, op, env->mode); + } + return new_rd_TEMPLATE_Minus(env->dbg, env->irg, env->block, op, env->mode); +} + + + +/** + * Transforms a Not node. + * + * @param mod the debug module + * @param block the block the new node should belong to + * @param node the ir Not node + * @param op operator + * @param mode node mode + * @return the created TEMPLATE Not node + */ +static ir_node *gen_Not(TEMPLATE_transform_env_t *env, ir_node *op) { + return new_rd_TEMPLATE_Not(env->dbg, env->irg, env->block, op, env->mode); +} + + + +/** + * Transforms a Load. + * + * @param mod the debug module + * @param block the block the new node should belong to + * @param node the ir Load node + * @param mode node mode + * @return the created TEMPLATE Load node + */ +static ir_node *gen_Load(TEMPLATE_transform_env_t *env) { + ir_node *node = env->irn; + + if (mode_is_float(env->mode)) { + return new_rd_TEMPLATE_fLoad(env->dbg, env->irg, env->block, get_Load_ptr(node), get_Load_mem(node), env->mode); + } + return new_rd_TEMPLATE_Load(env->dbg, env->irg, env->block, get_Load_ptr(node), get_Load_mem(node), env->mode); +} + + + +/** + * Transforms a Store. + * + * @param mod the debug module + * @param block the block the new node should belong to + * @param node the ir Store node + * @param mode node mode + * @return the created TEMPLATE Store node + */ +static ir_node *gen_Store(TEMPLATE_transform_env_t *env) { + ir_node *node = env->irn; + + if (mode_is_float(env->mode)) { + return new_rd_TEMPLATE_fStore(env->dbg, env->irg, env->block, get_Store_ptr(node), get_Store_value(node), get_Store_mem(node), env->mode); + } + return new_rd_TEMPLATE_Store(env->dbg, env->irg, env->block, get_Store_ptr(node), get_Store_value(node), get_Store_mem(node), env->mode); +} + + + +/********************************************************* + * _ _ _ + * (_) | | (_) + * _ __ ___ __ _ _ _ __ __| |_ __ ___ _____ _ __ + * | '_ ` _ \ / _` | | '_ \ / _` | '__| \ \ / / _ \ '__| + * | | | | | | (_| | | | | | | (_| | | | |\ V / __/ | + * |_| |_| |_|\__,_|_|_| |_| \__,_|_| |_| \_/ \___|_| + * + *********************************************************/ + + + +/** + * Transforms the given firm node (and maybe some other related nodes) + * into one or more assembler nodes. + * + * @param node the firm node + * @param env the debug module + */ +void TEMPLATE_transform_node(ir_node *node, void *env) { + TEMPLATE_code_gen_t *cgenv = (TEMPLATE_code_gen_t *)env; + opcode code = get_irn_opcode(node); + ir_node *asm_node = NULL; + TEMPLATE_transform_env_t tenv; + + if (is_Block(node)) + return; + + tenv.block = get_nodes_block(node); + tenv.dbg = get_irn_dbg_info(node); + tenv.irg = current_ir_graph; + tenv.irn = node; + tenv.mod = cgenv->mod; + tenv.mode = get_irn_mode(node); + +#define UNOP(a) case iro_##a: asm_node = gen_##a(&tenv, get_##a##_op(node)); break +#define BINOP(a) case iro_##a: asm_node = gen_##a(&tenv, get_##a##_left(node), get_##a##_right(node)); break +#define GEN(a) case iro_##a: asm_node = gen_##a(&tenv); break +#define IGN(a) case iro_##a: break +#define BAD(a) case iro_##a: goto bad + + DBG((tenv.mod, LEVEL_1, "check %+F ... ", node)); + + switch (code) { + BINOP(Add); + BINOP(Mul); + BINOP(And); + BINOP(Or); + BINOP(Eor); + + BINOP(Sub); + BINOP(Shl); + BINOP(Shr); + BINOP(Quot); + + + UNOP(Minus); + UNOP(Not); + + GEN(Load); + GEN(Store); + + /* TODO: implement these nodes */ + IGN(Shrs); + IGN(Div); + IGN(Mod); + IGN(DivMod); + IGN(Const); + IGN(SymConst); + IGN(Conv); + IGN(Abs); + IGN(Cond); + IGN(Mux); + IGN(CopyB); + IGN(Unknown); + IGN(Cmp); + + /* You probably don't need to handle the following nodes */ + + IGN(Call); + IGN(Proj); + IGN(Alloc); + + IGN(Block); + IGN(Start); + IGN(End); + IGN(NoMem); + IGN(Phi); + IGN(IJmp); + IGN(Jmp); + IGN(Break); + IGN(Sync); + + BAD(Raise); + BAD(Sel); + BAD(InstOf); + BAD(Cast); + BAD(Free); + BAD(Tuple); + BAD(Id); + BAD(Bad); + BAD(Confirm); + BAD(Filter); + BAD(CallBegin); + BAD(EndReg); + BAD(EndExcept); + + default: + if (get_irn_op(node) == get_op_Max() || + get_irn_op(node) == get_op_Min() || + get_irn_op(node) == get_op_Mulh()) + { + /* TODO: implement */ + /* ignore for now */ + } + break; +bad: + fprintf(stderr, "Not implemented: %s\n", get_irn_opname(node)); + assert(0); + } + + if (asm_node) { + exchange(node, asm_node); + DB((tenv.mod, LEVEL_1, "created node %+F[%p]\n", asm_node, asm_node)); + } + else { + DB((tenv.mod, LEVEL_1, "ignored\n")); + } +} diff --git a/ir/be/TEMPLATE/TEMPLATE_transform.h b/ir/be/TEMPLATE/TEMPLATE_transform.h new file mode 100644 index 000000000..6e380aebb --- /dev/null +++ b/ir/be/TEMPLATE/TEMPLATE_transform.h @@ -0,0 +1,6 @@ +#ifndef _TEMPLATE_TRANSFORM_H_ +#define _TEMPLATE_TRANSFORM_H_ + +void TEMPLATE_transform_node(ir_node *node, void *env); + +#endif /* _TEMPLATE_TRANSFORM_H_ */ diff --git a/ir/be/TEMPLATE/bearch_TEMPLATE.c b/ir/be/TEMPLATE/bearch_TEMPLATE.c index 1552d1b7e..658e11489 100644 --- a/ir/be/TEMPLATE/bearch_TEMPLATE.c +++ b/ir/be/TEMPLATE/bearch_TEMPLATE.c @@ -1,3 +1,6 @@ +/* The main TEMPLATE backend driver file. */ +/* $Id$ */ + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -16,6 +19,9 @@ #include "../benode_t.h" #include "../belower.h" #include "../besched_t.h" +#include "../be.h" +#include "../beabi.h" + #include "bearch_TEMPLATE_t.h" #include "TEMPLATE_new_nodes.h" /* TEMPLATE nodes interface */ @@ -93,10 +99,14 @@ static const arch_register_req_t *TEMPLATE_get_irn_reg_req(const void *self, arc memcpy(req, &(irn_req->req), sizeof(*req)); - if (arch_register_req_is(&(irn_req->req), should_be_same) || - arch_register_req_is(&(irn_req->req), should_be_different)) { - assert(irn_req->pos >= 0 && "should be same/different constraint for in -> out NYI"); - req->other = get_irn_n(irn, irn_req->pos); + if (arch_register_req_is(&(irn_req->req), should_be_same)) { + assert(irn_req->same_pos >= 0 && "should be same constraint for in -> out NYI"); + req->other_same = get_irn_n(irn, irn_req->same_pos); + } + + if (arch_register_req_is(&(irn_req->req), should_be_different)) { + assert(irn_req->different_pos >= 0 && "should be different constraint for in -> out NYI"); + req->other_different = get_irn_n(irn, irn_req->different_pos); } } /* get requirements for FIRM nodes */ @@ -119,30 +129,6 @@ static const arch_register_req_t *TEMPLATE_get_irn_reg_req(const void *self, arc assert(0 && "unsupported Phi-Mode"); } } - else if ((get_irn_op(irn) == op_Return) && pos > 0) { - /* pos == 0 is Memory -> no requirements */ - DB((mod, LEVEL_1, "giving return (%+F) requirements\n", irn)); - - if (pos == 1) { - /* pos == 1 is Stackpointer */ - memcpy(req, &(TEMPLATE_default_req_TEMPLATE_general_purpose_r6.req), sizeof(*req)); - } - else { - if (mode_is_float(get_irn_mode(get_Return_res(irn, pos)))) { - /* fp result */ - memcpy(req, &(TEMPLATE_default_req_TEMPLATE_floating_point_f0.req), sizeof(*req)); - } - else { - /* integer result, 64bit results are returned as two 32bit values */ - if (pos == 2) { - memcpy(req, &(TEMPLATE_default_req_TEMPLATE_general_purpose_r0.req), sizeof(*req)); - } - else { - memcpy(req, &(TEMPLATE_default_req_TEMPLATE_general_purpose_r1.req), sizeof(*req)); - } - } - } - } else { DB((mod, LEVEL_1, "returning NULL for %+F (node not supported)\n", irn)); req = NULL; @@ -155,7 +141,7 @@ static const arch_register_req_t *TEMPLATE_get_irn_reg_req(const void *self, arc static void TEMPLATE_set_irn_reg(const void *self, ir_node *irn, const arch_register_t *reg) { int pos = 0; - else if (is_Proj(irn)) { + if (is_Proj(irn)) { pos = TEMPLATE_translate_proj_pos(irn); irn = my_skip_proj(irn); } @@ -176,7 +162,7 @@ static const arch_register_t *TEMPLATE_get_irn_reg(const void *self, const ir_no int pos = 0; const arch_register_t *reg = NULL; - else if (is_Proj(irn)) { + if (is_Proj(irn)) { pos = TEMPLATE_translate_proj_pos(irn); irn = my_skip_proj(irn); } @@ -219,6 +205,19 @@ static arch_irn_flags_t TEMPLATE_get_flags(const void *self, const ir_node *irn) return 0; } +static entity *TEMPLATE_get_frame_entity(const void *self, const ir_node *irn) { + /* TODO: return the entity assigned to the frame */ + return NULL; +} + +/** + * This function is called by the generic backend to correct offsets for + * nodes accessing the stack. + */ +static void TEMPLATE_set_stack_bias(const void *self, ir_node *irn, int bias) { + /* TODO: correct offset if irn accesses the stack */ +} + /* fill register allocator interface */ static const arch_irn_ops_if_t TEMPLATE_irn_ops_if = { @@ -226,7 +225,9 @@ static const arch_irn_ops_if_t TEMPLATE_irn_ops_if = { TEMPLATE_set_irn_reg, TEMPLATE_get_irn_reg, TEMPLATE_classify, - TEMPLATE_get_flags + TEMPLATE_get_flags, + TEMPLATE_get_frame_entity, + TEMPLATE_set_stack_bias }; TEMPLATE_irn_ops_t TEMPLATE_irn_ops = { @@ -254,23 +255,30 @@ TEMPLATE_irn_ops_t TEMPLATE_irn_ops = { static void TEMPLATE_prepare_graph(void *self) { TEMPLATE_code_gen_t *cg = self; - irg_walk_blkwise_graph(cg->irg, TEMPLATE_place_consts, TEMPLATE_transform_node, cg); + irg_walk_blkwise_graph(cg->irg, NULL, TEMPLATE_transform_node, cg); } /** - * Fix offsets and stacksize + * Called immediatly before emit phase. */ static void TEMPLATE_finish_irg(ir_graph *irg, TEMPLATE_code_gen_t *cg) { - /* TODO */ + /* TODO: - fix offsets for nodes accessing stack + - ... + */ } +/** + * These are some hooks which must be filled but are probably not needed. + */ static void TEMPLATE_before_sched(void *self) { + /* Some stuff you need to do after scheduling but before register allocation */ } static void TEMPLATE_before_ra(void *self) { + /* Some stuff you need to do immediatly after register allocation */ } @@ -318,7 +326,7 @@ static ir_node *TEMPLATE_lower_reload(void *self, ir_node *reload) { * Emits the code, closes the output file and frees * the code generator interface. */ -static void TEMPLATE_codegen(void *self) { +static void TEMPLATE_emit_and_done(void *self) { TEMPLATE_code_gen_t *cg = self; ir_graph *irg = cg->irg; FILE *out = cg->out; @@ -339,7 +347,7 @@ static void TEMPLATE_codegen(void *self) { free(self); } -static void *TEMPLATE_cg_init(FILE *F, ir_graph *irg, const arch_env_t *arch_env); +static void *TEMPLATE_cg_init(FILE *F, const be_irg_t *birg); static const arch_code_generator_if_t TEMPLATE_code_gen_if = { TEMPLATE_cg_init, @@ -348,22 +356,23 @@ static const arch_code_generator_if_t TEMPLATE_code_gen_if = { TEMPLATE_before_ra, /* before register allocation hook */ TEMPLATE_lower_spill, TEMPLATE_lower_reload, - TEMPLATE_codegen /* emit && done */ + TEMPLATE_emit_and_done }; /** * Initializes the code generator. */ -static void *TEMPLATE_cg_init(FILE *F, ir_graph *irg, const arch_env_t *arch_env) { - TEMPLATE_isa_t *isa = (TEMPLATE_isa_t *)arch_env->isa; +static void *TEMPLATE_cg_init(FILE *F, const be_irg_t *birg) { + TEMPLATE_isa_t *isa = (TEMPLATE_isa_t *)birg->main_env->arch_env->isa; TEMPLATE_code_gen_t *cg = xmalloc(sizeof(*cg)); - cg->impl = &TEMPLATE_code_gen_if; - cg->irg = irg; - cg->reg_set = new_set(TEMPLATE_cmp_irn_reg_assoc, 1024); - cg->mod = firm_dbg_register("firm.be.TEMPLATE.cg"); - cg->out = F; - cg->arch_env = arch_env; + cg->impl = &TEMPLATE_code_gen_if; + cg->irg = birg->irg; + cg->reg_set = new_set(TEMPLATE_cmp_irn_reg_assoc, 1024); + cg->mod = firm_dbg_register("firm.be.TEMPLATE.cg"); + cg->out = F; + cg->arch_env = birg->main_env->arch_env; + cg->birg = birg; isa->num_codegens++; @@ -391,24 +400,32 @@ static void *TEMPLATE_cg_init(FILE *F, ir_graph *irg, const arch_env_t *arch_env * *****************************************************************/ +static TEMPLATE_isa_t TEMPLATE_isa_template = { + &TEMPLATE_isa_if, + &TEMPLATE_general_purpose_regs[REG_R6], + &TEMPLATE_general_purpose_regs[REG_R7], + -1, + 0 +}; + /** * Initializes the backend ISA and opens the output file. */ static void *TEMPLATE_init(void) { static int inited = 0; - TEMPLATE_isa_t *isa = xmalloc(sizeof(*isa)); - - isa->impl = &TEMPLATE_isa_if; + TEMPLATE_isa_t *isa; if(inited) return NULL; - inited = 1; - isa->num_codegens = 0; + isa = xcalloc(1, sizeof(*isa)); + memcpy(isa, &TEMPLATE_isa_template, sizeof(*isa)); TEMPLATE_register_init(isa); TEMPLATE_create_opcodes(); + inited = 1; + return isa; } @@ -432,6 +449,88 @@ static const arch_register_class_t *TEMPLATE_get_reg_class(const void *self, int return &TEMPLATE_reg_classes[i]; } + + +/** + * Get the register class which shall be used to store a value of a given mode. + * @param self The this pointer. + * @param mode The mode in question. + * @return A register class which can hold values of the given mode. + */ +const arch_register_class_t *TEMPLATE_get_reg_class_for_mode(const void *self, const ir_mode *mode) { + if (mode_is_float(mode)) + return &TEMPLATE_reg_classes[CLASS_TEMPLATE_floating_point]; + else + return &TEMPLATE_reg_classes[CLASS_TEMPLATE_general_purpose]; +} + + + +/** + * Produces the type which sits between the stack args and the locals on the stack. + * it will contain the return address and space to store the old base pointer. + * @return The Firm type modelling the ABI between type. + */ +static ir_type *get_between_type(void) { + static ir_type *between_type = NULL; + static entity *old_bp_ent = NULL; + + if(!between_type) { + entity *ret_addr_ent; + ir_type *ret_addr_type = new_type_primitive(new_id_from_str("return_addr"), mode_P); + ir_type *old_bp_type = new_type_primitive(new_id_from_str("bp"), mode_P); + + between_type = new_type_class(new_id_from_str("TEMPLATE_between_type")); + old_bp_ent = new_entity(between_type, new_id_from_str("old_bp"), old_bp_type); + ret_addr_ent = new_entity(between_type, new_id_from_str("old_bp"), ret_addr_type); + + set_entity_offset_bytes(old_bp_ent, 0); + set_entity_offset_bytes(ret_addr_ent, get_type_size_bytes(old_bp_type)); + set_type_size_bytes(between_type, get_type_size_bytes(old_bp_type) + get_type_size_bytes(ret_addr_type)); + } + + return between_type; +} + +/** + * Get the ABI restrictions for procedure calls. + * @param self The this pointer. + * @param method_type The type of the method (procedure) in question. + * @param abi The abi object to be modified + */ +void TEMPLATE_get_call_abi(const void *self, ir_type *method_type, be_abi_call_t *abi) { + ir_type *between_type; + ir_type *tp; + ir_mode *mode; + int i, n = get_method_n_params(method_type); + const arch_register_t *reg; + + /* get the between type and the frame pointer save entity */ + between_type = get_between_type(); + + /* set stack parameter passing style */ + be_abi_call_set_flags(abi, BE_ABI_NONE, between_type); + + for (i = 0; i < n; i++) { + /* TODO: implement register parameter: */ + /* reg = get reg for param i; */ + /* be_abi_call_param_reg(abi, i, reg); */ + + /* default: all parameters on stack */ + be_abi_call_param_stack(abi, i); + } + + /* TODO: set correct return register */ + /* default: return value is in R0 resp. F0 */ + if (get_method_n_ress(method_type) > 0) { + tp = get_method_res_type(method_type, 0); + mode = get_type_mode(tp); + + be_abi_call_res_reg(abi, 0, + mode_is_float(mode) ? &TEMPLATE_floating_point_regs[REG_F0] : &TEMPLATE_general_purpose_regs[REG_R0]); + } +} + static const void *TEMPLATE_get_irn_ops(const arch_irn_handler_t *self, const ir_node *irn) { return &TEMPLATE_irn_ops; } @@ -480,6 +579,8 @@ const arch_isa_if_t TEMPLATE_isa_if = { TEMPLATE_done, TEMPLATE_get_n_reg_class, TEMPLATE_get_reg_class, + TEMPLATE_get_reg_class_for_mode, + TEMPLATE_get_call_abi, TEMPLATE_get_irn_handler, TEMPLATE_get_code_generator_if, TEMPLATE_get_list_sched_selector, diff --git a/ir/be/TEMPLATE/bearch_TEMPLATE_t.h b/ir/be/TEMPLATE/bearch_TEMPLATE_t.h index cde5333b8..a707afdd7 100644 --- a/ir/be/TEMPLATE/bearch_TEMPLATE_t.h +++ b/ir/be/TEMPLATE/bearch_TEMPLATE_t.h @@ -4,7 +4,7 @@ #include "debug.h" #include "bearch_TEMPLATE.h" #include "TEMPLATE_nodes_attr.h" - +#include "../be.h" typedef struct _TEMPLATE_code_gen_t { const arch_code_generator_if_t *impl; /* implementation */ @@ -14,21 +14,35 @@ typedef struct _TEMPLATE_code_gen_t { set *reg_set; /* set to memorize registers for FIRM nodes (e.g. phi) */ firm_dbg_module_t *mod; /* debugging module */ int emit_decls; /* flag indicating if decls were already emitted */ - int has_alloca; /* indicates whether the irg contains an alloca or not */ - const TEMPLATE_register_req_t **reg_param_req; /* hold the requirements for the reg param nodes */ + const be_irg_t *birg; /* The be-irg (contains additional information about the irg) */ } TEMPLATE_code_gen_t; typedef struct _TEMPLATE_isa_t { - const arch_isa_if_t *impl; + const arch_isa_if_t *impl; + const arch_register_t *sp; /** The stack pointer register. */ + const arch_register_t *bp; /** The base pointer register. */ + const int stack_dir; /** -1 for decreasing, 1 for increasing. */ int num_codegens; } TEMPLATE_isa_t; typedef struct _TEMPLATE_irn_ops_t { const arch_irn_ops_if_t *impl; - TEMPLATE_code_gen_t *cg; + TEMPLATE_code_gen_t *cg; } TEMPLATE_irn_ops_t; +/* this is a struct to minimize the number of parameters + for transformation walker */ +typedef struct _TEMPLATE_transform_env_t { + firm_dbg_module_t *mod; /**< The firm debugger */ + dbg_info *dbg; /**< The node debug info */ + ir_graph *irg; /**< The irg, the node should be created in */ + ir_node *block; /**< The block, the node should belong to */ + ir_node *irn; /**< The irn, to be transformed */ + ir_mode *mode; /**< The mode of the irn */ +} TEMPLATE_transform_env_t; + + #endif /* _BEARCH_TEMPLATE_T_H_ */ -- 2.20.1