--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <limits.h>
+
+#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);
+}
--- /dev/null
+#ifndef _TEMPLATE_EMITTER_H_
+#define _TEMPLATE_EMITTER_H_
+
+#include "irargs_t.h" // this also inlucdes <libcore/lc_print.h>
+#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_ */
--- /dev/null
+/**
+ * Dumps global variables and constants as TEMPLATE assembler.
+ * @author Christian Wuerdig
+ * @date 14.02.2006
+ * @version $Id$
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "xmalloc.h"
+#include <obstack.h>
+
+#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);
+}
--- /dev/null
+#ifndef _TEMPLATE_GEN_DECLS_H_
+#define _TEMPLATE_GEN_DECLS_H_
+
+/**
+ * Generate all entities.
+ */
+void TEMPLATE_gen_decls(FILE *out);
+
+#endif /* _TEMPLATE_GEN_DECLS_H_ */
--- /dev/null
+/**
+ * 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 <stdlib.h>
+
+#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"
--- /dev/null
+#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_ */
--- /dev/null
+#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_ */
--- /dev/null
+#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,
+};
--- /dev/null
+#ifndef _BEARCH_TEMPLATE_H_
+#define _BEARCH_TEMPLATE_H_
+
+#include "../bearch.h"
+
+extern const arch_isa_if_t TEMPLATE_isa_if;
+
+#endif /* _BEARCH_TEMPLATE_H_ */
--- /dev/null
+#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_ */