From 47955b0c606252ddfcab364d3a3cf71e736e79c1 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Christian=20W=C3=BCrdig?= Date: Wed, 15 Feb 2006 09:20:14 +0000 Subject: [PATCH] initial checkin for TEMPLATE backend --- ir/be/TEMPLATE/TEMPLATE_emitter.c | 479 +++++++++++++++++++++ ir/be/TEMPLATE/TEMPLATE_emitter.h | 28 ++ ir/be/TEMPLATE/TEMPLATE_gen_decls.c | 597 +++++++++++++++++++++++++++ ir/be/TEMPLATE/TEMPLATE_gen_decls.h | 9 + ir/be/TEMPLATE/TEMPLATE_new_nodes.c | 306 ++++++++++++++ ir/be/TEMPLATE/TEMPLATE_new_nodes.h | 101 +++++ ir/be/TEMPLATE/TEMPLATE_nodes_attr.h | 22 + ir/be/TEMPLATE/bearch_TEMPLATE.c | 496 ++++++++++++++++++++++ ir/be/TEMPLATE/bearch_TEMPLATE.h | 8 + ir/be/TEMPLATE/bearch_TEMPLATE_t.h | 34 ++ 10 files changed, 2080 insertions(+) create mode 100644 ir/be/TEMPLATE/TEMPLATE_emitter.c create mode 100644 ir/be/TEMPLATE/TEMPLATE_emitter.h create mode 100644 ir/be/TEMPLATE/TEMPLATE_gen_decls.c create mode 100644 ir/be/TEMPLATE/TEMPLATE_gen_decls.h create mode 100644 ir/be/TEMPLATE/TEMPLATE_new_nodes.c create mode 100644 ir/be/TEMPLATE/TEMPLATE_new_nodes.h create mode 100644 ir/be/TEMPLATE/TEMPLATE_nodes_attr.h create mode 100644 ir/be/TEMPLATE/bearch_TEMPLATE.c create mode 100644 ir/be/TEMPLATE/bearch_TEMPLATE.h create mode 100644 ir/be/TEMPLATE/bearch_TEMPLATE_t.h diff --git a/ir/be/TEMPLATE/TEMPLATE_emitter.c b/ir/be/TEMPLATE/TEMPLATE_emitter.c new file mode 100644 index 000000000..05f50e1d2 --- /dev/null +++ b/ir/be/TEMPLATE/TEMPLATE_emitter.c @@ -0,0 +1,479 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "xmalloc.h" +#include "tv.h" +#include "iredges.h" +#include "debug.h" +#include "irgwalk.h" +#include "irprintf.h" +#include "irop_t.h" +#include "irargs_t.h" + +#include "../besched.h" + +#include "TEMPLATE_emitter.h" +#include "gen_TEMPLATE_emitter.h" +#include "TEMPLATE_nodes_attr.h" +#include "TEMPLATE_new_nodes.h" +#include "TEMPLATE_map_regs.h" + +#define SNPRINTF_BUF_LEN 128 + +static const arch_env_t *arch_env = NULL; + + +/************************************************************* + * _ _ __ _ _ + * (_) | | / _| | | | | + * _ __ _ __ _ _ __ | |_| |_ | |__ ___| |_ __ ___ _ __ + * | '_ \| '__| | '_ \| __| _| | '_ \ / _ \ | '_ \ / _ \ '__| + * | |_) | | | | | | | |_| | | | | | __/ | |_) | __/ | + * | .__/|_| |_|_| |_|\__|_| |_| |_|\___|_| .__/ \___|_| + * | | | | + * |_| |_| + *************************************************************/ + +/** + * Return a const or symconst as string. + */ +static const char *node_const_to_str(ir_node *n) { + /* TODO */ +} + +/** + * Returns node's offset as string. + */ +static char *node_offset_to_str(ir_node *n) { + /* TODO */ +} + +/* We always pass the ir_node which is a pointer. */ +static int TEMPLATE_get_arg_type(const lc_arg_occ_t *occ) { + return lc_arg_type_ptr; +} + + +/** + * Returns the register at in position pos. + */ +static const arch_register_t *get_in_reg(ir_node *irn, int pos) { + ir_node *op; + const arch_register_t *reg = NULL; + + 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); + + reg = arch_get_irn_register(arch_env, op); + + assert(reg && "no in register found"); + return reg; +} + +/** + * Returns the register at out position pos. + */ +static const arch_register_t *get_out_reg(ir_node *irn, int pos) { + ir_node *proj; + const arch_register_t *reg = NULL; + + assert(get_irn_n_edges(irn) > pos && "Invalid OUT position"); + + /* 1st case: irn is not of mode_T, so it has only */ + /* one OUT register -> good */ + /* 2nd case: irn is of mode_T -> collect all Projs and ask the */ + /* Proj with the corresponding projnum for the register */ + + if (get_irn_mode(irn) != mode_T) { + reg = arch_get_irn_register(arch_env, irn); + } + else if (is_TEMPLATE_irn(irn)) { + reg = get_TEMPLATE_out_reg(irn, pos); + } + else { + const ir_edge_t *edge; + + foreach_out_edge(irn, edge) { + proj = get_edge_src_irn(edge); + assert(is_Proj(proj) && "non-Proj from mode_T node"); + if (get_Proj_proj(proj) == pos) { + reg = arch_get_irn_register(arch_env, proj); + break; + } + } + } + + assert(reg && "no out register found"); + return reg; +} + +/** + * Returns the number of the in register at position pos. + */ +int get_TEMPLATE_reg_nr(ir_node *irn, int pos, int in_out) { + const arch_register_t *reg; + + if (in_out == 1) { + reg = get_in_reg(irn, pos); + } + else { + reg = get_out_reg(irn, pos); + } + + return arch_register_get_index(reg); +} + +/** + * Returns the name of the in register at position pos. + */ +const char *get_TEMPLATE_reg_name(ir_node *irn, int pos, int in_out) { + const arch_register_t *reg; + + if (in_out == 1) { + reg = get_in_reg(irn, pos); + } + else { + reg = get_out_reg(irn, pos); + } + + return arch_register_get_name(reg); +} + +/** + * Get the register name for a node. + */ +static int TEMPLATE_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_TEMPLATE_reg_name(X, nr, 1); + } + else { /* 'D' */ + buf = get_TEMPLATE_reg_name(X, nr, 0); + } + + lc_appendable_chadd(app, '%'); + return lc_arg_append(app, occ, buf, strlen(buf)); +} + +/** + * Returns the tarval or offset of an ia32 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) +{ + 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 TEMPLATE_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 *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 }; + + 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); + } + + 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 unsigned long id = 0; + snprintf(buf, buflen, "%s%lu", prefix, ++id); + return buf; +} + + +/** + * 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); + + snprintf(buf, SNPRINTF_BUF_LEN, "BLOCK_%ld", get_irn_node_nr(bl)); + 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); +} + + + +/*********************************************************************************** + * _ __ _ + * (_) / _| | | + * _ __ ___ __ _ _ _ __ | |_ _ __ __ _ _ __ ___ _____ _____ _ __| | __ + * | '_ ` _ \ / _` | | '_ \ | _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ / + * | | | | | | (_| | | | | | | | | | | (_| | | | | | | __/\ V V / (_) | | | < + * |_| |_| |_|\__,_|_|_| |_| |_| |_| \__,_|_| |_| |_|\___| \_/\_/ \___/|_| |_|\_\ + * + ***********************************************************************************/ + +/** + * Emits code for a node. + */ +void TEMPLATE_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 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); + BE_EMIT(Add_i); + BE_EMIT(Sub); + BE_EMIT(Sub_i); + BE_EMIT(Minus); + BE_EMIT(Inc); + BE_EMIT(Dec); + + BE_EMIT(And); + BE_EMIT(And_i); + BE_EMIT(Or); + BE_EMIT(Or_i); + BE_EMIT(Eor); + BE_EMIT(Eor_i); + BE_EMIT(Not); + + BE_EMIT(Shl); + BE_EMIT(Shl_i); + BE_EMIT(Shr); + BE_EMIT(Shr_i); + BE_EMIT(RotL); + BE_EMIT(RotL_i); + BE_EMIT(RotR); + + BE_EMIT(Mul); + BE_EMIT(Mul_i); + + BE_EMIT(Store); + BE_EMIT(Load); + + /* generated floating point emitter */ + BE_EMIT(fConst); + + BE_EMIT(fAdd); + BE_EMIT(fSub); + BE_EMIT(fMinus); + + BE_EMIT(fMul); + BE_EMIT(fDiv); + + BE_EMIT(fMin); + BE_EMIT(fMax); + + BE_EMIT(fLoad); + BE_EMIT(fStore); + + /* other emitter functions */ +// BE_EMIT(Switch); + + 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 TEMPLATE_gen_block(ir_node *block, void *env) { + ir_node *irn; + + if (! is_Block(block)) + return; + + fprintf(((emit_env_t *)env)->out, "BLOCK_%ld:\n", get_irn_node_nr(block)); + sched_foreach(block, irn) { + TEMPLATE_emit_node(irn, env); + } +} + + +/** + * Emits code for function start. + */ +void TEMPLATE_emit_start(FILE *F, ir_graph *irg) { + const char *irg_name = get_entity_name(get_irg_entity(irg)); + + /* TODO: emit function header */ +} + +/** + * Emits code for function end + */ +void TEMPLATE_emit_end(FILE *F, ir_graph *irg) { + const char *irg_name = get_entity_name(get_irg_entity(irg)); + + /* TODO: emit function end */ +} + +/** + * Sets labels for control flow nodes (jump target) + * TODO: Jump optimization + */ +void TEMPLATE_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 TEMPLATE_gen_routine(FILE *F, ir_graph *irg, const ia32_code_gen_t *cg) { + emit_env_t emit_env; + + emit_env.mod = firm_dbg_register("firm.be.TEMPLATE.emit"); + emit_env.out = F; + emit_env.arch_env = cg->arch_env; + emit_env.cg = cg; + + /* set the global arch_env (needed by print hooks) */ + arch_env = cg->arch_env; + + TEMPLATE_emit_start(F, irg); + irg_block_walk_graph(irg, TEMPLATE_gen_labels, NULL, &emit_env); + irg_walk_blkwise_graph(irg, NULL, TEMPLATE_gen_block, &emit_env); + TEMPLATE_emit_end(F, irg); +} diff --git a/ir/be/TEMPLATE/TEMPLATE_emitter.h b/ir/be/TEMPLATE/TEMPLATE_emitter.h new file mode 100644 index 000000000..d211d1fa2 --- /dev/null +++ b/ir/be/TEMPLATE/TEMPLATE_emitter.h @@ -0,0 +1,28 @@ +#ifndef _TEMPLATE_EMITTER_H_ +#define _TEMPLATE_EMITTER_H_ + +#include "irargs_t.h" // this also inlucdes +#include "irnode.h" +#include "debug.h" + +#include "../bearch.h" + +#include "bearch_TEMPLATE_t.h" + +typedef struct _emit_env_t { + firm_dbg_module_t *mod; + FILE *out; + const arch_env_t *arch_env; + const TEMPLATE_code_gen_t *cg; +} emit_env_t; + +const lc_arg_env_t *TEMPLATE_get_arg_env(void); + +void equalize_dest_src(FILE *F, ir_node *n); + +int get_TEMPLATE_reg_nr(ir_node *irn, int posi, int in_out); +const char *get_TEMPLATE_in_reg_name(ir_node *irn, int pos); + +void TEMPLATE_gen_routine(FILE *F, ir_graph *irg, const TEMPLATE_code_gen_t *cg); + +#endif /* _TEMPLATE_EMITTER_H_ */ diff --git a/ir/be/TEMPLATE/TEMPLATE_gen_decls.c b/ir/be/TEMPLATE/TEMPLATE_gen_decls.c new file mode 100644 index 000000000..4851517de --- /dev/null +++ b/ir/be/TEMPLATE/TEMPLATE_gen_decls.c @@ -0,0 +1,597 @@ +/** + * Dumps global variables and constants as TEMPLATE assembler. + * @author Christian Wuerdig + * @date 14.02.2006 + * @version $Id$ + */ + +#include +#include +#include +#include + +#include "xmalloc.h" +#include + +#ifdef obstack_chunk_alloc +# undef obstack_chunk_alloc +# define obstack_chunk_alloc xmalloc +#else +# define obstack_chunk_alloc xmalloc +# define obstack_chunk_free free +#endif + +#include "tv.h" +#include "irnode.h" +#include "entity.h" +#include "irprog.h" + +#include "TEMPLATE_gen_decls.h" + +/************************************************************************/ + +/* + * returns the highest bit value + */ +static unsigned highest_bit(unsigned v) +{ + int res = -1; + + if (v >= (1U << 16U)) { + res += 16; + v >>= 16; + } + if (v >= (1U << 8U)) { + res += 8; + v >>= 8; + } + if (v >= (1U << 4U)) { + res += 4; + v >>= 4; + } + if (v >= (1U << 2U)) { + res += 2; + v >>= 2; + } + if (v >= (1U << 1U)) { + res += 1; + v >>= 1; + } + if (v >= 1) + res += 1; + + return res; +} + +/* + * output the alignment + */ +static void TEMPLATE_dump_align(struct obstack *obst, int align) +{ + int h = highest_bit(align); + + if ((1 << h) < align) + ++h; + align = (1 << h); + + if (align > 1) + obstack_printf(obst, "\t.align %d\n", align); +} + +static void dump_arith_tarval(struct obstack *obst, tarval *tv, int bytes) +{ + switch (bytes) { + + case 1: + obstack_printf(obst, "0x%02x", get_tarval_sub_bits(tv, 0)); + break; + + case 2: + obstack_printf(obst, "0x%02x%02x", get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0)); + break; + + case 4: + obstack_printf(obst, "0x%02x%02x%02x%02x", + get_tarval_sub_bits(tv, 3), get_tarval_sub_bits(tv, 2), get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0)); + break; + + case 8: + obstack_printf(obst, "0x%02x%02x%02x%02x%02x%02x%02x%02x", + get_tarval_sub_bits(tv, 7), get_tarval_sub_bits(tv, 6), get_tarval_sub_bits(tv, 5), get_tarval_sub_bits(tv, 4), + get_tarval_sub_bits(tv, 3), get_tarval_sub_bits(tv, 2), get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0)); + break; + + case 10: + case 12: + break; + + default: + fprintf(stderr, "Try to dump an tarval with %d bytes\n", bytes); + assert(0); + } +} + +/* + * dump an arithmetic tarval + */ +static void TEMPLATE_dump_arith_tarval(struct obstack *obst, tarval *tv, int bytes) +{ + switch (bytes) { + + case 1: + obstack_printf(obst, "\t.byte\t"); + break; + + case 2: + obstack_printf(obst, "\t.value\t"); + break; + + case 4: + obstack_printf(obst, "\t.long\t"); + break; + + case 8: + obstack_printf(obst, "\t.quad\t"); + break; + + case 10: + case 12: + break; + + default: + fprintf(stderr, "Try to dump an tarval with %d bytes\n", bytes); + assert(0); + } + dump_arith_tarval(obst, tv, bytes); +} + + +/* + * dump an atomic value + */ +static void do_dump_atomic_init(struct obstack *obst, ir_node *init) +{ + ir_mode *mode = get_irn_mode(init); + int bytes = get_mode_size_bytes(mode); + tarval *tv; + + switch (get_irn_opcode(init)) { + + case iro_Cast: + do_dump_atomic_init(obst, get_Cast_op(init)); + return; + + case iro_Conv: + do_dump_atomic_init(obst, get_Conv_op(init)); + return; + + case iro_Const: + tv = get_Const_tarval(init); + + /* beware of old stuff */ + assert(! mode_is_reference(mode)); + + /* it's a arithmetic value */ + dump_arith_tarval(obst, tv, bytes); + return; + + case iro_SymConst: + switch (get_SymConst_kind(init)) { + case symconst_addr_name: + obstack_printf(obst, "%s", get_id_str(get_SymConst_name(init))); + break; + + case symconst_addr_ent: + obstack_printf(obst, "%s", get_entity_ld_name(get_SymConst_entity(init))); + break; + + case symconst_size: + obstack_printf(obst, "%d", get_type_size_bytes(get_SymConst_type(init))); + break; + + default: + assert(0 && "dump_atomic_init(): don't know how to init from this SymConst"); + } + return; + + case iro_Add: + do_dump_atomic_init(obst, get_Add_left(init)); + obstack_printf(obst, " + "); + do_dump_atomic_init(obst, get_Add_right(init)); + return; + + case iro_Sub: + do_dump_atomic_init(obst, get_Sub_left(init)); + obstack_printf(obst, " - "); + do_dump_atomic_init(obst, get_Sub_right(init)); + return; + + case iro_Mul: + do_dump_atomic_init(obst, get_Mul_left(init)); + obstack_printf(obst, " * "); + do_dump_atomic_init(obst, get_Mul_right(init)); + return; + + default: + assert(0 && "dump_atomic_init(): unknown IR-node"); + } +} + +/* + * dump an atomic value + */ +static void dump_atomic_init(struct obstack *obst, ir_node *init) +{ + ir_mode *mode = get_irn_mode(init); + int bytes = get_mode_size_bytes(mode); + + switch (bytes) { + + case 1: + obstack_printf(obst, "\t.byte\t"); + break; + + case 2: + obstack_printf(obst, "\t.value\t"); + break; + + case 4: + obstack_printf(obst, "\t.long\t"); + break; + + case 8: + obstack_printf(obst, "\t.quad\t"); + break; + + case 10: + case 12: + /* handled in arith */ + break; + + default: + fprintf(stderr, "Try to dump an tarval with %d bytes\n", bytes); + assert(0); + } + + do_dump_atomic_init(obst, init); + obstack_printf(obst, "\n"); +} + +/************************************************************************/ +/* Routines to dump global variables */ +/************************************************************************/ + +/** + * Determine if an entity is a string constant + * @param ent The entity + * @return 1 if it is a string constant, 0 otherwise + */ +static int ent_is_string_const(entity *ent) +{ + int res = 0; + ir_type *ty; + + ty = get_entity_type(ent); + + /* if it's an array */ + if (is_Array_type(ty)) { + ir_type *elm_ty = get_array_element_type(ty); + + /* and the array's element type is primitive */ + if (is_Primitive_type(elm_ty)) { + ir_mode *mode = get_type_mode(elm_ty); + + /* + * and the mode of the element type is an int of + * the same size as the byte mode + */ + if (mode_is_int(mode) + && get_mode_size_bits(mode) == get_mode_size_bits(mode_Bs)) + { + int i, c, n; + + n = get_compound_ent_n_values(ent); + for (i = 0; i < n; ++i) { + ir_node *irn = get_compound_ent_value(ent, i); + if(get_irn_opcode(irn) != iro_Const) + return 0; + + c = (int) get_tarval_long(get_Const_tarval(irn)); + + if((i < n - 1 && !(isgraph(c) || isspace(c))) + || (i == n - 1 && c != '\0')) + return 0; + } + + res = 1; + } + } + } + + return res; +} + +/** + * Dump a atring constant. + * No checks are made!! + * @param obst The obst to dump on. + * @param ent The entity to dump. + */ +static void dump_string_cst(struct obstack *obst, entity *ent) +{ + int i, n; + + obstack_printf(obst, "\t.string \""); + n = get_compound_ent_n_values(ent); + + for (i = 0; i < n-1; ++i) { + ir_node *irn; + int c; + + irn = get_compound_ent_value(ent, i); + c = (int) get_tarval_long(get_Const_tarval(irn)); + + switch (c) { + case '"' : obstack_printf(obst, "\\\""); break; + case '\n': obstack_printf(obst, "\\n"); break; + case '\r': obstack_printf(obst, "\\r"); break; + case '\t': obstack_printf(obst, "\\t"); break; + default : + if (isprint(c)) + obstack_printf(obst, "%c", c); + else + obstack_printf(obst, "%O", c); + break; + } + } + obstack_printf(obst, "\"\n"); +} + +struct arr_info { + int n_elems; + int visit_cnt; + int size; +}; + +/* + * Dumps the initialization of global variables that are not + * "uninitialized". + */ +static void dump_global(struct obstack *rdata_obstack, struct obstack *data_obstack, struct obstack *comm_obstack, entity *ent) +{ + ir_type *ty = get_entity_type(ent); + const char *ld_name = get_entity_ld_name(ent); + int align, h; + struct obstack *obst = data_obstack; + + /* + * FIXME: did NOT work for partly constant values + */ + if (! is_Method_type(ty)) { + ent_variability variability = get_entity_variability(ent); + visibility visibility = get_entity_visibility(ent); + + if (variability == variability_constant) { + /* a constant entity, put it on the rdata */ + obst = rdata_obstack; + } + + /* check, wether it is initialized, if yes create data */ + if (variability != variability_uninitialized) { + if (visibility == visibility_external_visible) { + obstack_printf(obst, ".globl\t%s\n", ld_name); + } + obstack_printf(obst, "\t.type\t%s,@object\n", ld_name); + obstack_printf(obst, "\t.size\t%s,%d\n", ld_name, (get_type_size_bits(ty) + 7) >> 3); + + align = get_type_alignment_bytes(ty); + TEMPLATE_dump_align(obst, align); + + obstack_printf(obst, "%s:\n", ld_name); + + if (is_atomic_type(ty)) { + if (get_entity_visibility(ent) != visibility_external_allocated) + dump_atomic_init(obst, get_atomic_ent_value(ent)); + } + else { + int i, size = 0; + + if (ent_is_string_const(ent)) { + dump_string_cst(obst, ent); + } + else if (is_Array_type(ty)) { + int filler; + + /* potential spare values should be already included! */ + for (i = 0; i < get_compound_ent_n_values(ent); ++i) { + entity *step = get_compound_ent_value_member(ent, i); + ir_type *stype = get_entity_type(step); + + if (get_type_mode(stype)) { + int align = (get_type_alignment_bits(stype) + 7) >> 3; + int n = size % align; + + if (n > 0) { + obstack_printf(obst, "\t.zero\t%d\n", align - n); + size += align - n; + } + } + dump_atomic_init(obst, get_compound_ent_value(ent, i)); + size += get_type_size_bytes(stype); + } + filler = get_type_size_bytes(ty) - size; + + if (filler > 0) + obstack_printf(obst, "\t.zero\t%d\n", filler); + } + else if (is_compound_type(ty)) { + ir_node **vals; + int type_size, j; + + /* Compound entities are NOT sorted. + * The sorting strategy used doesn't work for `value' compound fields nor + * for partially_constant entities. + */ + + /* + * in the worst case, every entity allocates one byte, so the type + * size should be equal or bigger the number of fields + */ + type_size = get_type_size_bytes(ty); + vals = xcalloc(type_size, sizeof(*vals)); + + /* collect the values and store them at the offsets */ + for(i = 0; i < get_compound_ent_n_values(ent); ++i) { + int graph_length, aipos, offset; + struct arr_info *ai; + int all_n = 1; + compound_graph_path *path = get_compound_ent_value_path(ent, i); + + /* get the access path to the costant value */ + graph_length = get_compound_graph_path_length(path); + ai = xcalloc(graph_length, sizeof(struct arr_info)); + + /* We wanna know how many arrays are on the path to the entity. We also have to know how + * many elements each array holds to calculate the offset for the entity. */ + for (j = 0; j < graph_length; j++) { + entity *step = get_compound_graph_path_node(path, j); + ir_type *step_type = get_entity_type(step); + int ty_size = (get_type_size_bits(step_type) + 7) >> 3; + int k, n = 0; + + if (is_Array_type(step_type)) + for (k = 0; k < get_array_n_dimensions(step_type); k++) + n += get_tarval_long(get_Const_tarval(get_array_upper_bound(step_type, k))); + if (n) all_n *= n; + ai[j].n_elems = n ? all_n + 1 : 0; + ai[j].visit_cnt = 0; + ai[j].size = ty_size; + } + + aipos = graph_length - 1; + if (aipos) aipos--; + + for (offset = j = 0; j < graph_length; j++) { + entity *step = get_compound_graph_path_node(path, j); + ir_type *step_type = get_entity_type(step); + int ent_ofs = get_entity_offset_bytes(step); + int stepsize = 0; + + /* add all positive offsets (= offsets in structs) */ + if (ent_ofs >= 0) offset += ent_ofs; + + if (j == graph_length - 1) { + stepsize = (get_type_size_bits(step_type) + 7) >> 3; + + /* Search the next free position in vals depending on the information from above (ai). */ + while (vals[offset]) { + if (ai[aipos].visit_cnt < ai[aipos].n_elems) { + offset += stepsize; + ai[aipos].visit_cnt++; + } + else + while (aipos >= 0 && ai[aipos].visit_cnt == ai[aipos].n_elems) { + stepsize = ai[aipos--].size; + offset += stepsize; + } + } + + assert(aipos >= 0 && "couldn't store entity"); + vals[offset] = get_compound_ent_value(ent, i); + } + } + + free(ai); + } + + /* now write them sorted */ + for(i = 0; i < type_size; ) { + if (vals[i]) { + dump_atomic_init(obst, vals[i]); + i += (get_mode_size_bytes(get_irn_mode(vals[i]))); + } + else { + /* a gap */ + obstack_printf(obst, "\t.byte\t0\n"); + ++i; + } + } + free(vals); + } + else { + assert(0 && "unsupported type"); + } + } + obstack_printf(obst, "\n"); + } + else if (visibility != visibility_external_allocated) { + if (visibility == visibility_local) { + obstack_printf(comm_obstack, "\t.local\t%s\n", ld_name); + } + + /* calculate the alignment */ + align = get_type_alignment_bytes(ty); + h = highest_bit(align); + + if ((1 << h) < align) + ++h; + align = (1 << h); + + if (align < 1) + align = 1; + + obstack_printf(comm_obstack, "\t.comm\t%s,%d,%d\n", ld_name, (get_type_size_bits(ty) + 7) >> 3, align); + } + } +} + +/* + * Dumps declarations of global variables and the initialization code. + */ +void TEMPLATE_dump_globals(struct obstack *rdata_obstack, struct obstack *data_obstack, struct obstack *comm_obstack) +{ + ir_type *gt = get_glob_type(); + int i, n = get_class_n_members(gt); + + for (i = 0; i < n; i++) + dump_global(rdata_obstack, data_obstack, comm_obstack, get_class_member(gt, i)); +} + +/************************************************************************/ + +void TEMPLATE_gen_decls(FILE *out) { + struct obstack rodata, data, comm; + int size; + char *cp; + + obstack_init(&rodata); + obstack_init(&data); + obstack_init(&comm); + + TEMPLATE_dump_globals(&rodata, &data, &comm); + + size = obstack_object_size(&data); + cp = obstack_finish(&data); + if (size > 0) { + fprintf(out, "\t.data\n"); + fwrite(cp, 1, size, out); + } + + size = obstack_object_size(&rodata); + cp = obstack_finish(&rodata); + if (size > 0) { + fprintf(out, "\t.section\t.rodata\n"); + fwrite(cp, 1, size, out); + } + + size = obstack_object_size(&comm); + cp = obstack_finish(&comm); + if (size > 0) { + fprintf(out, "\t.common\n"); + fwrite(cp, 1, size, out); + } + + obstack_free(&rodata, NULL); + obstack_free(&data, NULL); + obstack_free(&comm, NULL); +} diff --git a/ir/be/TEMPLATE/TEMPLATE_gen_decls.h b/ir/be/TEMPLATE/TEMPLATE_gen_decls.h new file mode 100644 index 000000000..0224dc048 --- /dev/null +++ b/ir/be/TEMPLATE/TEMPLATE_gen_decls.h @@ -0,0 +1,9 @@ +#ifndef _TEMPLATE_GEN_DECLS_H_ +#define _TEMPLATE_GEN_DECLS_H_ + +/** + * Generate all entities. + */ +void TEMPLATE_gen_decls(FILE *out); + +#endif /* _TEMPLATE_GEN_DECLS_H_ */ diff --git a/ir/be/TEMPLATE/TEMPLATE_new_nodes.c b/ir/be/TEMPLATE/TEMPLATE_new_nodes.c new file mode 100644 index 000000000..670824f56 --- /dev/null +++ b/ir/be/TEMPLATE/TEMPLATE_new_nodes.c @@ -0,0 +1,306 @@ +/** + * This file implements the creation of the achitecture specific firm opcodes + * and the coresponding node constructors for the TEMPLATE assembler irg. + * $Id$ + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "irprog_t.h" +#include "irgraph_t.h" +#include "irnode_t.h" +#include "irmode_t.h" +#include "ircons_t.h" +#include "iropt_t.h" +#include "irop.h" +#include "firm_common_t.h" +#include "irvrfy_t.h" + +#include "../bearch.h" + +#include "TEMPLATE_nodes_attr.h" +#include "TEMPLATE_new_nodes.h" +#include "gen_TEMPLATE_regalloc_if.h" + + + +/*********************************************************************************** + * _ _ _ __ + * | | (_) | | / _| + * __| |_ _ _ __ ___ _ __ ___ _ __ _ _ __ | |_ ___ _ __| |_ __ _ ___ ___ + * / _` | | | | '_ ` _ \| '_ \ / _ \ '__| | | '_ \| __/ _ \ '__| _/ _` |/ __/ _ \ + * | (_| | |_| | | | | | | |_) | __/ | | | | | | || __/ | | || (_| | (_| __/ + * \__,_|\__,_|_| |_| |_| .__/ \___|_| |_|_| |_|\__\___|_| |_| \__,_|\___\___| + * | | + * |_| + ***********************************************************************************/ + +/** + * Dumper interface for dumping TEMPLATE nodes in vcg. + * @param n the node to dump + * @param F the output file + * @param reason indicates which kind of information should be dumped + * @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; + TEMPLATE_attr_t *attr; + const TEMPLATE_register_req_t **reqs; + const arch_register_t **slots; + + switch (reason) { + case dump_node_opcode_txt: + name = get_irn_opname(n); + fprintf(F, "%s", name); + 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)); + } + break; + + case dump_node_nodeattr_txt: + + /* TODO: Dump node specific attributes which should */ + /* visible in node name (e.g. const or the like). */ + + break; + + case dump_node_info_txt: + attr = get_TEMPLATE_attr(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 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 assigned registers */ + slots = get_TEMPLATE_slots(n); + if (slots && attr->n_res > 0) { + for (i = 0; i < attr->n_res; i++) { + if (slots[i]) { + fprintf(F, "reg #%d = %s\n", i, slots[i]->name); + } + else { + fprintf(F, "reg #%d = n/a\n", i); + } + } + } + + break; + } + + return bad; +} + + + +/*************************************************************************************************** + * _ _ _ __ _ _ _ _ + * | | | | | | / / | | | | | | | | + * __ _| |_| |_ _ __ ___ ___| |_ / /_ _ ___| |_ _ __ ___ ___| |_| |__ ___ __| |___ + * / _` | __| __| '__| / __|/ _ \ __| / / _` |/ _ \ __| | '_ ` _ \ / _ \ __| '_ \ / _ \ / _` / __| + * | (_| | |_| |_| | \__ \ __/ |_ / / (_| | __/ |_ | | | | | | __/ |_| | | | (_) | (_| \__ \ + * \__,_|\__|\__|_| |___/\___|\__/_/ \__, |\___|\__| |_| |_| |_|\___|\__|_| |_|\___/ \__,_|___/ + * __/ | + * |___/ + ***************************************************************************************************/ + +/** + * Wraps get_irn_generic_attr() as it takes no const ir_node, so we need to do a cast. + * Firm was made by people hating const :-( + */ +TEMPLATE_attr_t *get_TEMPLATE_attr(const ir_node *node) { + assert(is_TEMPLATE_irn(node) && "need TEMPLATE node to get attributes"); + return (TEMPLATE_attr_t *)get_irn_generic_attr((ir_node *)node); +} + +/** + * Returns the argument register requirements of a TEMPLATE node. + */ +const TEMPLATE_register_req_t **get_TEMPLATE_in_req_all(const ir_node *node) { + TEMPLATE_attr_t *attr = get_TEMPLATE_attr(node); + return attr->in_req; +} + +/** + * Returns the result register requirements of an TEMPLATE node. + */ +const TEMPLATE_register_req_t **get_TEMPLATE_out_req_all(const ir_node *node) { + TEMPLATE_attr_t *attr = get_TEMPLATE_attr(node); + return attr->out_req; +} + +/** + * Returns the argument register requirement at position pos of an TEMPLATE node. + */ +const TEMPLATE_register_req_t *get_TEMPLATE_in_req(const ir_node *node, int pos) { + TEMPLATE_attr_t *attr = get_TEMPLATE_attr(node); + return attr->in_req[pos]; +} + +/** + * Returns the result register requirement at position pos of an TEMPLATE node. + */ +const TEMPLATE_register_req_t *get_TEMPLATE_out_req(const ir_node *node, int pos) { + TEMPLATE_attr_t *attr = get_TEMPLATE_attr(node); + return attr->out_req[pos]; +} + +/** + * Sets the OUT register requirements at position pos. + */ +void set_TEMPLATE_req_out(ir_node *node, const TEMPLATE_register_req_t *req, int pos) { + TEMPLATE_attr_t *attr = get_TEMPLATE_attr(node); + attr->out_req[pos] = req; +} + +/** + * Sets the IN register requirements at position pos. + */ +void set_TEMPLATE_req_in(ir_node *node, const TEMPLATE_register_req_t *req, int pos) { + TEMPLATE_attr_t *attr = get_TEMPLATE_attr(node); + attr->in_req[pos] = req; +} + +/** + * Returns the register flag of an TEMPLATE node. + */ +arch_irn_flags_t get_TEMPLATE_flags(const ir_node *node) { + TEMPLATE_attr_t *attr = get_TEMPLATE_attr(node); + return attr->flags; +} + +/** + * Sets the register flag of an TEMPLATE node. + */ +void set_TEMPLATE_flags(const ir_node *node, arch_irn_flags_t flags) { + TEMPLATE_attr_t *attr = get_TEMPLATE_attr(node); + attr->flags = flags; +} + +/** + * Returns the result register slots of an TEMPLATE node. + */ +const arch_register_t **get_TEMPLATE_slots(const ir_node *node) { + TEMPLATE_attr_t *attr = get_TEMPLATE_attr(node); + return attr->slots; +} + +/** + * Returns the name of the OUT register at position pos. + */ +const char *get_TEMPLATE_out_reg_name(const ir_node *node, int pos) { + TEMPLATE_attr_t *attr = get_TEMPLATE_attr(node); + + assert(is_TEMPLATE_irn(node) && "Not an TEMPLATE node."); + assert(pos < attr->n_res && "Invalid OUT position."); + assert(attr->slots[pos] && "No register assigned"); + + return arch_register_get_name(attr->slots[pos]); +} + +/** + * Returns the index of the OUT register at position pos within its register class. + */ +int get_TEMPLATE_out_regnr(const ir_node *node, int pos) { + TEMPLATE_attr_t *attr = get_TEMPLATE_attr(node); + + assert(is_TEMPLATE_irn(node) && "Not an TEMPLATE node."); + assert(pos < attr->n_res && "Invalid OUT position."); + assert(attr->slots[pos] && "No register assigned"); + + return arch_register_get_index(attr->slots[pos]); +} + +/** + * Returns the OUT register at position pos. + */ +const arch_register_t *get_TEMPLATE_out_reg(const ir_node *node, int pos) { + TEMPLATE_attr_t *attr = get_TEMPLATE_attr(node); + + assert(is_TEMPLATE_irn(node) && "Not an TEMPLATE node."); + assert(pos < attr->n_res && "Invalid OUT position."); + assert(attr->slots[pos] && "No register assigned"); + + return attr->slots[pos]; +} + +/** + * Sets the number of results. + */ +void set_TEMPLATE_n_res(ir_node *node, int n_res) { + TEMPLATE_attr_t *attr = get_TEMPLATE_attr(node); + attr->n_res = n_res; +} + +/** + * Returns the number of results. + */ +int get_TEMPLATE_n_res(const ir_node *node) { + TEMPLATE_attr_t *attr = get_TEMPLATE_attr(node); + return attr->n_res; +} + + + +/*************************************************************************************** + * _ _ _ + * | | | | | | + * _ __ ___ __| | ___ ___ ___ _ __ ___| |_ _ __ _ _ ___| |_ ___ _ __ ___ + * | '_ \ / _ \ / _` |/ _ \ / __/ _ \| '_ \/ __| __| '__| | | |/ __| __/ _ \| '__/ __| + * | | | | (_) | (_| | __/ | (_| (_) | | | \__ \ |_| | | |_| | (__| || (_) | | \__ \ + * |_| |_|\___/ \__,_|\___| \___\___/|_| |_|___/\__|_| \__,_|\___|\__\___/|_| |___/ + * + ***************************************************************************************/ + +/* Include the generated constructor functions */ +#include "gen_TEMPLATE_new_nodes.c.inl" diff --git a/ir/be/TEMPLATE/TEMPLATE_new_nodes.h b/ir/be/TEMPLATE/TEMPLATE_new_nodes.h new file mode 100644 index 000000000..48d0b6d38 --- /dev/null +++ b/ir/be/TEMPLATE/TEMPLATE_new_nodes.h @@ -0,0 +1,101 @@ +#ifndef _TEMPLATE_NEW_NODES_H_ +#define _TEMPLATE_NEW_NODES_H_ + +/** + * Function prototypes for the assembler ir node constructors. + * $Id$ + */ + +#include "TEMPLATE_nodes_attr.h" + +/*************************************************************************************************** + * _ _ _ __ _ _ _ _ + * | | | | | | / / | | | | | | | | + * __ _| |_| |_ _ __ ___ ___| |_ / /_ _ ___| |_ _ __ ___ ___| |_| |__ ___ __| |___ + * / _` | __| __| '__| / __|/ _ \ __| / / _` |/ _ \ __| | '_ ` _ \ / _ \ __| '_ \ / _ \ / _` / __| + * | (_| | |_| |_| | \__ \ __/ |_ / / (_| | __/ |_ | | | | | | __/ |_| | | | (_) | (_| \__ \ + * \__,_|\__|\__|_| |___/\___|\__/_/ \__, |\___|\__| |_| |_| |_|\___|\__|_| |_|\___/ \__,_|___/ + * __/ | + * |___/ + ***************************************************************************************************/ + +/** + * Returns the attributes of an TEMPLATE node. + */ +TEMPLATE_attr *get_TEMPLATE_attr(const ir_node *node); + +/** + * Returns the argument register requirements of an TEMPLATE node. + */ +const TEMPLATE_register_req_t **get_TEMPLATE_in_req_all(const ir_node *node); + +/** + * Returns the result register requirements of an TEMPLATE node. + */ +const TEMPLATE_register_req_t **get_TEMPLATE_out_req_all(const ir_node *node); + +/** + * Returns the argument register requirements of an TEMPLATE node. + */ +const TEMPLATE_register_req_t *get_TEMPLATE_in_req(const ir_node *node, int pos); + +/** + * Returns the result register requirements of an TEMPLATE node. + */ +const TEMPLATE_register_req_t *get_TEMPLATE_out_req(const ir_node *node, int pos); + +/** + * Sets the OUT register requirements at position pos. + */ +void set_TEMPLATE_req_out(ir_node *node, const TEMPLATE_register_req_t *req, int pos); + +/** + * Sets the IN register requirements at position pos. + */ +void set_TEMPLATE_req_in(ir_node *node, const TEMPLATE_register_req_t *req, int pos); + +/** + * Returns the register flag of an TEMPLATE node. + */ +arch_irn_flags_t get_TEMPLATE_flags(const ir_node *node); + +/** + * Sets the register flag of an TEMPLATE node. + */ +void set_TEMPLATE_flags(const ir_node *node, arch_irn_flags_t flags); + +/** + * Returns the result register slots of an TEMPLATE node. + */ +const arch_register_t **get_TEMPLATE_slots(const ir_node *node); + +/** + * Returns the name of the OUT register at position pos. + */ +const char *get_TEMPLATE_out_reg_name(const ir_node *node, int pos); + +/** + * Returns the index of the OUT register at position pos within its register class. + */ +int get_TEMPLATE_out_regnr(const ir_node *node, int pos); + +/** + * Returns the OUT register at position pos. + */ +const arch_register_t *get_TEMPLATE_out_reg(const ir_node *node, int pos); + +/** + * Sets the number of results. + */ +void set_TEMPLATE_n_res(ir_node *node, int n_res); + +/** + * Returns the number of results. + */ +int get_TEMPLATE_n_res(const ir_node *node); + + +/* Include the generated headers */ +#include "gen_TEMPLATE_new_nodes.h" + +#endif /* _TEMPLATE_NEW_NODES_H_ */ diff --git a/ir/be/TEMPLATE/TEMPLATE_nodes_attr.h b/ir/be/TEMPLATE/TEMPLATE_nodes_attr.h new file mode 100644 index 000000000..156ef65e0 --- /dev/null +++ b/ir/be/TEMPLATE/TEMPLATE_nodes_attr.h @@ -0,0 +1,22 @@ +#ifndef _TEMPLATE_NODES_ATTR_H_ +#define _TEMPLATE_NODES_ATTR_H_ + +#include "../bearch.h" + +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 */ +} TEMPLATE_register_req_t; + + +typedef struct _TEMPLATE_attr_t { + arch_irn_flags_t flags; /**<< indicating if spillable, rematerializeable ... etc. */ + int n_res; /**<< number of results for this node */ + + const TEMPLATE_register_req_t **in_req; /**<< register requirements for arguments */ + const TEMPLATE_register_req_t **out_req; /**<< register requirements for results */ + + const arch_register_t **slots; /**<< register slots for assigned registers */ +} TEMPLATE_attr_t; + +#endif /* _TEMPLATE_NODES_ATTR_H_ */ diff --git a/ir/be/TEMPLATE/bearch_TEMPLATE.c b/ir/be/TEMPLATE/bearch_TEMPLATE.c new file mode 100644 index 000000000..8ca6d38a8 --- /dev/null +++ b/ir/be/TEMPLATE/bearch_TEMPLATE.c @@ -0,0 +1,496 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "pseudo_irg.h" +#include "irgwalk.h" +#include "irprog.h" +#include "irprintf.h" +#include "ircons.h" +#include "irgmod.h" + +#include "bitset.h" +#include "debug.h" + +#include "../bearch.h" /* the general register allocator interface */ +#include "../benode_t.h" +#include "../belower.h" +#include "../besched_t.h" +#include "bearch_TEMPLATE_t.h" + +#include "TEMPLATE_new_nodes.h" /* TEMPLATE nodes interface */ +#include "gen_TEMPLATE_regalloc_if.h" /* the generated interface (register type and class defenitions) */ +#include "TEMPLATE_gen_decls.h" /* interface declaration emitter */ +#include "TEMPLATE_transform.h" +#include "TEMPLATE_emitter.h" +#include "TEMPLATE_map_regs.h" + +#define DEBUG_MODULE "firm.be.TEMPLATE.isa" + +/* TODO: ugly, but we need it to get access to the registers assigned to Phi nodes */ +static set *cur_reg_set = NULL; + +/************************************************** + * _ _ _ __ + * | | | (_)/ _| + * _ __ ___ __ _ __ _| | | ___ ___ _| |_ + * | '__/ _ \/ _` | / _` | | |/ _ \ / __| | | _| + * | | | __/ (_| | | (_| | | | (_) | (__ | | | + * |_| \___|\__, | \__,_|_|_|\___/ \___| |_|_| + * __/ | + * |___/ + **************************************************/ + +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 a TEMPLATE node. + * If the node returns a tuple (mode_T) then the proj's + * will be asked for this information. + */ +static const arch_register_req_t *TEMPLATE_get_irn_reg_req(const void *self, arch_register_req_t *req, const ir_node *irn, int pos) { + const TEMPLATE_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)) { + /* in case of a proj, we need to get the correct OUT slot */ + /* of the node corresponding to the proj number */ + if (pos == -1) { + node_pos = TEMPLATE_translate_proj_pos(irn); + } + else { + node_pos = pos; + } + + irn = my_skip_proj(irn); + + DB((mod, LEVEL_1, "skipping Proj, going to %+F at pos %d ... ", irn, node_pos)); + } + + /* get requirements for our own nodes */ + if (is_TEMPLATE_irn(irn)) { + if (pos >= 0) { + irn_req = get_TEMPLATE_in_req(irn, pos); + } + else { + irn_req = get_TEMPLATE_out_req(irn, node_pos); + } + + DB((mod, LEVEL_1, "returning reqs for %+F at pos %d\n", irn, pos)); + + 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); + } + } + /* get requirements for FIRM nodes */ + else { + /* treat Phi like Const with default requirements */ + if (is_Phi(irn)) { + DB((mod, LEVEL_1, "returning standard reqs for %+F\n", irn)); + + if (mode_is_float(mode)) { + memcpy(req, &(TEMPLATE_default_req_TEMPLATE_floating_point.req), sizeof(*req)); + } + else if (mode_is_int(mode) || mode_is_reference(mode)) { + memcpy(req, &(TEMPLATE_default_req_TEMPLATE_general_purpose.req), 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_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; + } + } + + return req; +} + +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)) { + pos = TEMPLATE_translate_proj_pos(irn); + irn = my_skip_proj(irn); + } + + if (is_TEMPLATE_irn(irn)) { + const arch_register_t **slots; + + slots = get_TEMPLATE_slots(irn); + slots[pos] = reg; + } + else { + /* here we set the registers for the Phi nodes */ + TEMPLATE_set_firm_reg(irn, reg, cur_reg_set); + } +} + +static const arch_register_t *TEMPLATE_get_irn_reg(const void *self, const ir_node *irn) { + int pos = 0; + const arch_register_t *reg = NULL; + + else if (is_Proj(irn)) { + pos = TEMPLATE_translate_proj_pos(irn); + irn = my_skip_proj(irn); + } + + if (is_TEMPLATE_irn(irn)) { + const arch_register_t **slots; + slots = get_TEMPLATE_slots(irn); + reg = slots[pos]; + } + else { + reg = TEMPLATE_get_firm_reg(irn, cur_reg_set); + } + + return reg; +} + +static arch_irn_class_t TEMPLATE_classify(const void *self, const ir_node *irn) { + irn = my_skip_proj(irn); + + if (is_cfop(irn)) { + return arch_irn_class_branch; + } + else if (is_TEMPLATE_irn(irn)) { + return arch_irn_class_normal; + } + + return 0; +} + +static arch_irn_flags_t TEMPLATE_get_flags(const void *self, const ir_node *irn) { + irn = my_skip_proj(irn); + + if (is_TEMPLATE_irn(irn)) { + return get_TEMPLATE_flags(irn); + } + else if (is_Unknown(irn)) { + return arch_irn_flags_ignore; + } + + return 0; +} + +/* fill register allocator interface */ + +static const arch_irn_ops_if_t TEMPLATE_irn_ops_if = { + TEMPLATE_get_irn_reg_req, + TEMPLATE_set_irn_reg, + TEMPLATE_get_irn_reg, + TEMPLATE_classify, + TEMPLATE_get_flags +}; + +TEMPLATE_irn_ops_t TEMPLATE_irn_ops = { + &TEMPLATE_irn_ops_if, + NULL +}; + + + +/************************************************** + * _ _ __ + * | | (_)/ _| + * ___ ___ __| | ___ __ _ ___ _ __ _| |_ + * / __/ _ \ / _` |/ _ \/ _` |/ _ \ '_ \ | | _| + * | (_| (_) | (_| | __/ (_| | __/ | | | | | | + * \___\___/ \__,_|\___|\__, |\___|_| |_| |_|_| + * __/ | + * |___/ + **************************************************/ + +/** + * Transforms the standard firm graph into + * a TEMLPATE firm graph + */ +static void TEMPLATE_prepare_graph(void *self) { + TEMPLATE_code_gen_t *cg = self; + + if (! is_pseudo_ir_graph(cg->irg)) { + irg_walk_blkwise_graph(cg->irg, TEMPLATE_place_consts, TEMPLATE_transform_node, cg); + } +} + + + +/** + * Fix offsets and stacksize + */ +static void TEMPLATE_finish_irg(ir_graph *irg, TEMPLATE_code_gen_t *cg) { + /* TODO */ +} + + +static void TEMPLATE_before_sched(void *self) { +} + +static void TEMPLATE_before_ra(void *self) { +} + + +/** + * Creates a Store for a Spill + */ +static ir_node *TEMPLATE_lower_spill(void *self, ir_node *spill) { + TEMPLATE_code_gen_t *cg = self; + dbg_info *dbg = get_irn_dbg_info(spill); + ir_node *block = get_nodes_block(spill); + ir_node *ptr = get_irg_frame(cg->irg); + ir_node *val = be_get_Spill_context(spill); + ir_node *mem = new_rd_NoMem(cg->irg); + ir_mode *mode = get_irn_mode(spill); + ir_node *res; + entity *ent = be_get_spill_entity(spill); + unsigned offs = get_entity_offset_bytes(ent); + + DB((cg->mod, LEVEL_1, "lower_spill: got offset %d for %+F\n", offs, ent)); + + /* TODO: create Store */ + + return res; +} + +/** + * Create a Load for a Spill + */ +static ir_node *TEMPLATE_lower_reload(void *self, ir_node *reload) { + TEMPLATE_code_gen_t *cg = self; + dbg_info *dbg = get_irn_dbg_info(reload); + ir_node *block = get_nodes_block(reload); + ir_node *ptr = get_irg_frame(cg->irg); + ir_mode *mode = get_irn_mode(reload); + ir_node *pred = get_irn_n(reload, 0); + tarval *tv; + ir_node *res; + + /* TODO: create Load */ + + return res; +} + +/** + * Returns the Stackregister + */ +static const arch_register_t *TEMPLATE_get_stack_register(void *self) { + /* TODO */ +} + +/** + * Emits the code, closes the output file and frees + * the code generator interface. + */ +static void TEMPLATE_codegen(void *self) { + TEMPLATE_code_gen_t *cg = self; + ir_graph *irg = cg->irg; + FILE *out = cg->out; + + if (cg->emit_decls) { + TEMPLATE_gen_decls(cg->out); + cg->emit_decls = 0; + } + + TEMPLATE_finish_irg(irg, cg); + dump_ir_block_graph_sched(irg, "-TEMPLATE-finished"); + TEMPLATE_gen_routine(out, irg, cg); + + cur_reg_set = NULL; + + /* de-allocate code generator */ + del_set(cg->reg_set); + free(self); +} + +static void *TEMPLATE_cg_init(FILE *F, ir_graph *irg, const arch_env_t *arch_env); + +static const arch_code_generator_if_t TEMPLATE_code_gen_if = { + TEMPLATE_cg_init, + TEMPLATE_prepare_graph, + TEMPLATE_before_sched, /* before scheduling hook */ + TEMPLATE_before_ra, /* before register allocation hook */ + TEMPLATE_lower_spill, + TEMPLATE_lower_reload, + TEMPLATE_get_stack_register, + TEMPLATE_codegen /* emit && 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; + 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; + + isa->num_codegens++; + + if (isa->num_codegens > 1) + cg->emit_decls = 0; + else + cg->emit_decls = 1; + + cur_reg_set = cg->reg_set; + + TEMPLATE_irn_ops.cg = cg; + + return (arch_code_generator_t *)cg; +} + + + +/***************************************************************** + * ____ _ _ _____ _____ + * | _ \ | | | | |_ _|/ ____| /\ + * | |_) | __ _ ___| | _____ _ __ __| | | | | (___ / \ + * | _ < / _` |/ __| |/ / _ \ '_ \ / _` | | | \___ \ / /\ \ + * | |_) | (_| | (__| < __/ | | | (_| | _| |_ ____) / ____ \ + * |____/ \__,_|\___|_|\_\___|_| |_|\__,_| |_____|_____/_/ \_\ + * + *****************************************************************/ + +/** + * 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; + + if(inited) + return NULL; + + inited = 1; + isa->num_codegens = 0; + + TEMPLATE_register_init(isa); + TEMPLATE_create_opcodes(); + + return isa; +} + + + +/** + * Closes the output file and frees the ISA structure. + */ +static void TEMPLATE_done(void *self) { + free(self); +} + + + +static int TEMPLATE_get_n_reg_class(const void *self) { + return N_CLASSES; +} + +static const arch_register_class_t *TEMPLATE_get_reg_class(const void *self, int i) { + assert(i >= 0 && i < N_CLASSES && "Invalid TEMPLATE register class requested."); + return &TEMPLATE_reg_classes[i]; +} + +static const void *TEMPLATE_get_irn_ops(const arch_irn_handler_t *self, const ir_node *irn) { + return &TEMPLATE_irn_ops; +} + +const arch_irn_handler_t TEMPLATE_irn_handler = { + TEMPLATE_get_irn_ops +}; + +const arch_irn_handler_t *TEMPLATE_get_irn_handler(const void *self) { + return &TEMPLATE_irn_handler; +} + +int TEMPLATE_to_appear_in_schedule(void *block_env, const ir_node *irn) { + return is_TEMPLATE_irn(irn); +} + +/** + * Initializes the code generator interface. + */ +static const arch_code_generator_if_t *TEMPLATE_get_code_generator_if(void *self) { + return &TEMPLATE_code_gen_if; +} + +list_sched_selector_t TEMPLATE_sched_selector; + +/** + * Returns the reg_pressure scheduler with to_appear_in_schedule() overloaded + */ +static const list_sched_selector_t *TEMPLATE_get_list_sched_selector(const void *self) { + memcpy(&TEMPLATE_sched_selector, trivial_selector, sizeof(list_sched_selector_t)); + TEMPLATE_sched_selector.to_appear_in_schedule = TEMPLATE_to_appear_in_schedule; + return &TEMPLATE_sched_selector; +} + +#ifdef WITH_LIBCORE +static void TEMPLATE_register_options(lc_opt_entry_t *ent) +{ +} +#endif /* WITH_LIBCORE */ + +const arch_isa_if_t TEMPLATE_isa_if = { +#ifdef WITH_LIBCORE + TEMPLATE_register_options, +#endif + TEMPLATE_init, + TEMPLATE_done, + TEMPLATE_get_n_reg_class, + TEMPLATE_get_reg_class, + TEMPLATE_get_irn_handler, + TEMPLATE_get_code_generator_if, + TEMPLATE_get_list_sched_selector, +}; diff --git a/ir/be/TEMPLATE/bearch_TEMPLATE.h b/ir/be/TEMPLATE/bearch_TEMPLATE.h new file mode 100644 index 000000000..4e9194bbe --- /dev/null +++ b/ir/be/TEMPLATE/bearch_TEMPLATE.h @@ -0,0 +1,8 @@ +#ifndef _BEARCH_TEMPLATE_H_ +#define _BEARCH_TEMPLATE_H_ + +#include "../bearch.h" + +extern const arch_isa_if_t TEMPLATE_isa_if; + +#endif /* _BEARCH_TEMPLATE_H_ */ diff --git a/ir/be/TEMPLATE/bearch_TEMPLATE_t.h b/ir/be/TEMPLATE/bearch_TEMPLATE_t.h new file mode 100644 index 000000000..cde5333b8 --- /dev/null +++ b/ir/be/TEMPLATE/bearch_TEMPLATE_t.h @@ -0,0 +1,34 @@ +#ifndef _BEARCH_TEMPLATE_T_H_ +#define _BEARCH_TEMPLATE_T_H_ + +#include "debug.h" +#include "bearch_TEMPLATE.h" +#include "TEMPLATE_nodes_attr.h" + + +typedef struct _TEMPLATE_code_gen_t { + const arch_code_generator_if_t *impl; /* implementation */ + ir_graph *irg; /* current irg */ + FILE *out; /* output file */ + const arch_env_t *arch_env; /* the arch env */ + 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 */ +} TEMPLATE_code_gen_t; + + +typedef struct _TEMPLATE_isa_t { + const arch_isa_if_t *impl; + 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_irn_ops_t; + + +#endif /* _BEARCH_TEMPLATE_T_H_ */ -- 2.20.1