--- /dev/null
+/* arm emitter */
+/* $Id$ */
+
+#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 "irprog_t.h"
+#include "irargs_t.h"
+
+#include "../besched.h"
+
+#include "arm_emitter.h"
+#include "gen_arm_emitter.h"
+#include "arm_nodes_attr.h"
+#include "arm_new_nodes.h"
+#include "arm_map_regs.h"
+#include "gen_arm_regalloc_if.h"
+
+#include "../benode_t.h"
+
+#define SNPRINTF_BUF_LEN 128
+
+static const arch_env_t *arch_env = NULL;
+
+
+/*************************************************************
+ * _ _ __ _ _
+ * (_) | | / _| | | | |
+ * _ __ _ __ _ _ __ | |_| |_ | |__ ___| |_ __ ___ _ __
+ * | '_ \| '__| | '_ \| __| _| | '_ \ / _ \ | '_ \ / _ \ '__|
+ * | |_) | | | | | | | |_| | | | | | __/ | |_) | __/ |
+ * | .__/|_| |_|_| |_|\__|_| |_| |_|\___|_| .__/ \___|_|
+ * | | | |
+ * |_| |_|
+ *************************************************************/
+
+int is_immediate_node(ir_node *irn) {
+ if (is_arm_Add_i(irn) || is_arm_Sub_i(irn))
+ return 1;
+ if (is_arm_Shr_i(irn) || is_arm_Shr_i(irn) || is_arm_Shl_i(irn))
+ return 1;
+ if (is_arm_And_i(irn) || is_arm_Or_i(irn) || is_arm_Eor_i(irn))
+ return 1;
+ if (is_arm_Or_Shl_i(irn))
+ return 1;
+ return 0;
+}
+
+/**
+ * Return a const or symconst as string.
+ */
+static const char *node_const_to_str(ir_node *n) {
+ char buffer[SNPRINTF_BUF_LEN];
+ ir_mode *mode = get_irn_mode(n);
+
+ if ( is_immediate_node(n) ) {
+ tarval *tv = get_arm_value(n);
+ long longvalue = get_tarval_long(get_arm_value(n));
+ char *str;
+ assert(longvalue < 0x1000 && "constant doesn't fit in shifter_operand");
+ snprintf(buffer, SNPRINTF_BUF_LEN - 1, "#%ld << %ld", longvalue & 0xff, (longvalue >> 8) << 1 );
+ str = xmalloc(strlen(buffer) * sizeof(char));
+ strcpy(str, buffer);
+ return str;
+ }
+ if ( is_arm_Const(n) || is_arm_Const_Neg(n) ) {
+ tarval *tv = get_arm_value(n);
+ if ( mode_is_int(get_tarval_mode(tv)) ) {
+ long longvalue = get_tarval_long(get_arm_value(n));
+ char *str;
+ assert(longvalue < 0x1000 && "constant doesn't fit in shifter_operand");
+ snprintf(buffer, SNPRINTF_BUF_LEN - 1, "#%ld << %ld", longvalue & 0xff, (longvalue >> 8) << 1 );
+ str = xmalloc(strlen(buffer) * sizeof(char));
+ strcpy(str, buffer);
+ return str;
+ } else {
+ return "found something else in arm_const";
+ }
+ } else if ( is_arm_SymConst(n) ) {
+ return get_arm_symconst_label(n);
+ } else {
+ assert( 0 && "das ist gar keine Konstante");
+ return NULL;
+ }
+
+}
+
+/**
+ * Returns node's offset as string.
+ */
+static char *node_offset_to_str(ir_node *n) {
+ char buffer[SNPRINTF_BUF_LEN];
+ char *result;
+ int offset = 0;
+ ir_op *irn_op = get_irn_op(n);
+ if (irn_op == op_be_StackParam) {
+ entity *ent = be_get_frame_entity(n);
+ offset = get_entity_offset_bytes(ent);
+ } else if (irn_op==op_be_Reload || irn_op==op_be_Spill) {
+ entity * ent = be_get_spill_entity(n);
+ offset = get_entity_offset_bytes(ent);
+ } else if (irn_op==op_be_IncSP) {
+ int offs = be_get_IncSP_offset(n);
+ be_stack_dir_t dir = be_get_IncSP_direction(n);
+ offset = (dir == be_stack_dir_expand) ? -offs : offs;
+ } else {
+ return "node_offset_to_str will fuer diesen Knotentyp noch implementiert werden";
+ }
+ snprintf(buffer, SNPRINTF_BUF_LEN, "%d", offset);
+ result = xmalloc(sizeof(char)*(strlen(buffer) + 1));
+ strcpy(result, buffer);
+ return result;
+}
+
+/* We always pass the ir_node which is a pointer. */
+static int arm_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(const 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);
+
+ /* ONLY TEMPORARY WORK-AROUND */
+// if (!reg) {
+// printf("FIXME\n");
+// reg = &arm_general_purpose_regs[REG_MURX];
+// }
+
+ assert(reg && "no in register found");
+ return reg;
+}
+
+/**
+ * Returns the register at out position pos.
+ */
+static const arch_register_t *get_out_reg(const 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_arm_irn(irn)) {
+ reg = get_arm_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_arm_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_arm_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 arm_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_appendable_snadd(app, "(null)", 6);
+
+ if (occ->conversion == 'S') {
+ buf = get_arm_reg_name(X, nr, 1);
+ }
+ else { /* 'D' */
+ buf = get_arm_reg_name(X, nr, 0);
+ }
+
+ lc_appendable_chadd(app, '%');
+ return lc_appendable_snadd(app, buf, strlen(buf));
+}
+
+/**
+ * Returns the tarval or offset of an arm node as a string.
+ */
+static int arm_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_appendable_snadd(app, "(null)", 6);
+
+ if (occ->conversion == 'C') {
+ buf = node_const_to_str(X);
+ }
+ else { /* 'O' */
+ buf = node_offset_to_str(X);
+ }
+
+ return lc_appendable_snadd(app, buf, strlen(buf));
+}
+
+/**
+ * Determines the SSE suffix depending on the mode.
+ */
+static int arm_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_appendable_snadd(app, "(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 arm printf arg environment.
+ * We use the firm environment with some additional handlers.
+ */
+const lc_arg_env_t *arm_get_arg_env(void) {
+ static lc_arg_env_t *env = NULL;
+
+ static const lc_arg_handler_t arm_reg_handler = { arm_get_arg_type, arm_get_reg_name };
+ static const lc_arg_handler_t arm_const_handler = { arm_get_arg_type, arm_const_to_str };
+ static const lc_arg_handler_t arm_mode_handler = { arm_get_arg_type, arm_get_mode_suffix };
+
+ if(env == NULL) {
+ /* extend the firm printer */
+ env = firm_get_arg_env();
+ //lc_arg_new_env();
+
+ lc_arg_register(env, "arm:sreg", 'S', &arm_reg_handler);
+ lc_arg_register(env, "arm:dreg", 'D', &arm_reg_handler);
+ lc_arg_register(env, "arm:cnst", 'C', &arm_const_handler);
+ lc_arg_register(env, "arm:offs", 'O', &arm_const_handler);
+ lc_arg_register(env, "arm:mode", 'M', &arm_mode_handler);
+ }
+
+ return env;
+}
+
+/**
+ * Formated print of commands and comments.
+ */
+static void arm_fprintf_format(FILE *F, char *cmd_buf, char *cmnt_buf, ir_node *irn) {
+ lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
+}
+
+/*
+ * Add a number to a prefix. This number will not be used a second time.
+ */
+static char *get_unique_label(char *buf, size_t buflen, const char *prefix) {
+ static unsigned long id = 0;
+ snprintf(buf, buflen, "%s%lu", prefix, ++id);
+ return buf;
+}
+
+
+/**
+ * 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;
+}
+
+/************************************************************************/
+/* emit_arm */
+/************************************************************************/
+
+static void emit_arm_SymConst(ir_node *irn, void *env) {
+ arm_emit_env_t *emit_env = env;
+ FILE *out = emit_env->out;
+ char buffer1[SNPRINTF_BUF_LEN];
+ char *skip_label = get_unique_label(buffer1, SNPRINTF_BUF_LEN, ".L");
+ char buffer2[SNPRINTF_BUF_LEN];
+ char *indi_label = get_unique_label(buffer2, SNPRINTF_BUF_LEN, ".L");
+ fprintf( out, "\tB %s\t\t\t\t\t/* start of indirect SymConst */\n", skip_label );
+ fprintf( out, "\t.align 2\n" );
+ fprintf( out, "%s:\n", indi_label );
+ lc_efprintf(arm_get_arg_env(), out, "\t.word\t%C\n", irn);
+ fprintf( out, "\t.align 2\n" );
+ fprintf( out, "%s:\n", skip_label );
+ lc_efprintf(arm_get_arg_env(), out, "\tLDR %1D, %s\t\t\t/* end of indirect SymConst */\n", irn, indi_label);
+}
+
+static void emit_arm_CondJmp(ir_node *irn, void *env) {
+ arm_emit_env_t *emit_env = env;
+ FILE *out = emit_env->out;
+ const ir_edge_t *edge;
+ ir_node *true_block = NULL;
+ ir_node *false_block = NULL;
+ ir_node *op1 = get_irn_n(irn, 0);
+ ir_mode *opmode = get_irn_mode(op1);
+ char *suffix;
+ int proj_num = get_arm_proj_num(irn);
+ char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
+
+
+ foreach_out_edge(irn, edge) {
+ ir_node* proj = get_edge_src_irn(edge);
+ long nr = get_Proj_proj(proj);
+ ir_node *block = get_irn_link(proj);
+ if ( nr == pn_Cond_true) {
+ true_block = block;
+ } else if (nr == pn_Cond_false) {
+ false_block = block;
+ } else {
+ assert(0 && "tertium non datur! (CondJmp)");
+ }
+ }
+
+ if (proj_num == pn_Cmp_False) {
+ fprintf(out, "\tB BLOCK_%d\t\t\t/* false case */\n", get_irn_node_nr(false_block));
+ } else if (proj_num == pn_Cmp_True) {
+ fprintf(out, "\tB BLOCK_%d\t\t\t/* true case */\n", get_irn_node_nr(true_block));
+ } else {
+ if (mode_is_float(opmode)) {
+ suffix = "ICHWILLIMPLEMENTIERTWERDEN";
+
+ lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "FCMP %1S, %2S", irn, irn);
+ lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* Compare(%1S, %2S) -> FCPSR */", irn, irn );
+ arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
+
+ lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "FMSTAT", irn, irn);
+ lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* FCSPR -> CPSR */");
+ arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
+
+ lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "B%s BLOCK_%d", suffix, get_irn_node_nr(true_block));
+ lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* true case */");
+ arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
+
+ lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "B BLOCK_%d", get_irn_node_nr(false_block));
+ lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* false case */");
+ arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
+ } else {
+ switch(proj_num) {
+ case pn_Cmp_Eq: suffix = "EQ"; break;
+ case pn_Cmp_Lt: suffix = "LT"; break;
+ case pn_Cmp_Le: suffix = "LE"; break;
+ case pn_Cmp_Gt: suffix = "GT"; break;
+ case pn_Cmp_Ge: suffix = "GE"; break;
+ case pn_Cmp_Lg: suffix = "NE"; break;
+ case pn_Cmp_Leg: suffix = "AL"; break;
+ default: assert(0 && "komische Dinge geschehen");
+ }
+
+ lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "CMP %1S, %2S", irn, irn);
+ lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* Compare(%1S, %2S) -> CPSR */", irn, irn );
+ arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
+
+ lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "B%s BLOCK_%d", suffix, get_irn_node_nr(true_block));
+ lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* true case */");
+ arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
+
+ lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "B BLOCK_%d", get_irn_node_nr(false_block));
+ lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* false case */");
+ arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
+ }
+ }
+}
+
+static void emit_arm_CopyB(ir_node *irn, void *env) {
+ arm_emit_env_t *emit_env = env;
+ FILE *out = emit_env->out;
+ char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
+ unsigned int size = get_tarval_long(get_arm_value(irn));
+ const lc_arg_env_t *arg_env = arm_get_arg_env();
+
+ lc_esnprintf(arg_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* MemCopy (%2S)->(%1S) [%d bytes], Use %3S, %4S, %5S and %%r12 */", irn, irn, size, irn, irn, irn);
+
+ assert ( size > 0 && "CopyB needs size > 0" );
+ if (size & 3)
+ size += 4;
+ size >>= 2;
+ switch(size & 3) {
+ case 0:
+ break;
+ case 1:
+ lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "LDR %%r12, [%2S, #0]!", irn);
+ arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
+ lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "STR %%r12, [%1S, #0]!", irn);
+ arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
+ break;
+ case 2:
+ lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "LDMIA %2S!, {%%r12, %3S}", irn, irn);
+ arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
+ lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "STMIA %1S!, {%%r12, %3S}", irn, irn);
+ arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
+ break;
+ case 3:
+ lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "LDMIA %2S!, {%%r12, %3S, %4S}", irn, irn, irn);
+ arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
+ lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "STMIA %1S!, {%%r12, %3S, %4S}", irn, irn, irn);
+ arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
+ break;
+ }
+ size >>= 2;
+ while (size) {
+ lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "LDMIA %2S!, {%%r12, %3S, %4S, %5S}", irn, irn, irn, irn);
+ arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
+ lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "STMIA %1S!, {%%r12, %3S, %4S, %5S}", irn, irn, irn, irn);
+ arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
+ --size;
+ }
+}
+
+static void emit_arm_SwitchJmp(ir_node *irn, void *env) {
+ char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
+ const ir_edge_t *edge;
+ ir_node *proj;
+ arm_emit_env_t *emit_env = env;
+ FILE *out = emit_env->out;
+ int i;
+ ir_node **projs;
+ int n_projs;
+ int block_nr;
+ int default_block_num;
+
+ block_nr = get_irn_node_nr(irn);
+ n_projs = get_arm_n_projs(irn);
+
+ projs = xcalloc(n_projs , sizeof(ir_node*));
+
+ foreach_out_edge(irn, edge) {
+ proj = get_edge_src_irn(edge);
+ assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");
+
+ if (get_Proj_proj(proj) == get_arm_default_proj_num(irn))
+ default_block_num = get_irn_node_nr(get_irn_link(proj));
+
+ projs[get_Proj_proj(proj)] = proj;
+ }
+
+ // CMP %1S, n_projs - 1
+ // BHI default
+
+
+
+ lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "CMP %1S, #%u", irn, n_projs - 1);
+ lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "", irn);
+ lc_efprintf(arm_get_arg_env(), out, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
+
+ lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "BHI BLOCK_%d", default_block_num);
+ lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "", irn);
+ lc_efprintf(arm_get_arg_env(), out, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
+
+
+ lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "LDR %%r12, TABLE_%d_START", block_nr);
+ lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "", irn);
+ lc_efprintf(arm_get_arg_env(), out, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
+
+ lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "ADD %%r12, %%r12, %1S, LSL #2", irn);
+ lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "", irn);
+ lc_efprintf(arm_get_arg_env(), out, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
+
+ lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "LDR %%r15, [%%r12, #0]");
+ lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "", irn);
+ lc_efprintf(arm_get_arg_env(), out, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
+
+ // LDR %r12, .TABLE_X_START
+ // ADD %r12, %r12, [%1S, LSL #2]
+ // LDR %r15, %r12
+
+ fprintf(out, "TABLE_%d_START:\n\t.word\tTABLE_%d\n", block_nr, block_nr);
+ fprintf(out, "\t.align 2\n");
+ fprintf(out, "TABLE_%d:\n", block_nr);
+
+
+ for ( i=0; i<n_projs; i++) {
+ ir_node *block;
+ proj = projs[i];
+ if ( proj ) {
+ block = get_irn_link(proj);
+ } else {
+ block = get_irn_link(projs[get_arm_default_proj_num(irn)]);
+ }
+ fprintf(out, "\t.word\tBLOCK_%d\n",get_irn_node_nr(block));
+ }
+ fprintf(out, "\t.align 2\n");
+
+ xfree(projs);
+}
+
+/************************************************************************/
+/* emit_be */
+/************************************************************************/
+
+static void emit_be_Call(ir_node *irn, void *env) {
+ arm_emit_env_t *emit_env = env;
+ FILE *out = emit_env->out;
+ entity *target_entity = be_Call_get_entity(irn);
+ const char *target_name = get_entity_name(target_entity);
+ fprintf(out, "\tBL %s\t\t\t\t/* Call */\n", target_name);
+}
+
+static void emit_be_IncSP(const ir_node *irn, arm_emit_env_t *emit_env) {
+ FILE *F = emit_env->out;
+ unsigned offs = be_get_IncSP_offset(irn);
+ if (offs) {
+ char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
+ lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "ADD %1D, %1S, #%O", irn, irn, irn );
+ lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* IncSP(%O) */", irn);
+ lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
+ } else {
+ char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
+ lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "");
+ lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* omitted IncSP(%O) */", irn);
+ lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
+ }
+}
+
+// void emit_be_AddSP(const ir_node *irn, arm_emit_env_t *emit_env) {
+// FILE *F = emit_env->out;
+// char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
+// lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "ADD %1D, %1S, %2S", irn, irn, irn );
+// lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* AddSP(%2S) */", irn);
+// lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
+// }
+
+static void emit_be_Copy(const ir_node *irn, arm_emit_env_t *emit_env) {
+ FILE *F = emit_env->out;
+ ir_mode *mode = get_irn_mode(irn);
+ assert( (mode != mode_E) && "IEEE Extended FP not supported");
+
+ if (get_in_reg(irn, 0) == get_out_reg(irn, 0)) {
+ char cmd_buf[256], cmnt_buf[256];
+ lc_esnprintf(arm_get_arg_env(), cmd_buf, 256, "");
+ lc_esnprintf(arm_get_arg_env(), cmnt_buf, 256, "/* omitted Copy: %1S -> %1D */", irn, irn);
+ lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
+ return;
+ }
+
+ if (mode == mode_F) {
+ char cmd_buf[256], cmnt_buf[256];
+ lc_esnprintf(arm_get_arg_env(), cmd_buf, 256, "FCPYS %1D, %1S", irn, irn);
+ lc_esnprintf(arm_get_arg_env(), cmnt_buf, 256, "/* Copy: %1S -> %1D */", irn, irn);
+ lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
+ } else if (mode == mode_D) {
+ char cmd_buf[256], cmnt_buf[256];
+ lc_esnprintf(arm_get_arg_env(), cmd_buf, 256, "FCPYD %1D, %1S", irn, irn);
+ lc_esnprintf(arm_get_arg_env(), cmnt_buf, 256, "/* Copy: %1S -> %1D */", irn, irn);
+ lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
+ } else if (mode_is_numP(mode)) {
+ char cmd_buf[256], cmnt_buf[256];
+ lc_esnprintf(arm_get_arg_env(), cmd_buf, 256, "MOV %1D, %1S", irn, irn);
+ lc_esnprintf(arm_get_arg_env(), cmnt_buf, 256, "/* Copy: %1S -> %1D */", irn, irn);
+ lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
+ } else {
+ assert(0 && "move not supported for this mode");
+ }
+// emit_arm_Copy(irn, emit_env);
+}
+
+static void emit_be_Spill(const ir_node *irn, arm_emit_env_t *emit_env) {
+ FILE *F = emit_env->out;
+ ir_mode *mode = get_irn_mode(irn);
+ assert( (mode != mode_E) && "IEEE Extended FP not supported");
+ if (mode_is_dataM(mode)) {
+ char cmd_buf[256], cmnt_buf[256];
+ lc_esnprintf(arm_get_arg_env(), cmd_buf, 256, "STR %2S, [%1S, #%O]", irn, irn, irn );
+ lc_esnprintf(arm_get_arg_env(), cmnt_buf, 256, "/* Spill(%2S) -> (%1S) */", irn, irn);
+ lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
+ } else {
+ assert(0 && "spill not supported for this mode");
+ }
+}
+
+static void emit_be_Reload(const ir_node* irn, arm_emit_env_t *emit_env) {
+ FILE *F = emit_env->out;
+ ir_mode *mode = get_irn_mode(irn);
+ assert( (mode != mode_E) && "IEEE Extended FP not supported");
+ if (mode_is_dataM(mode)) {
+ char cmd_buf[256], cmnt_buf[256];
+ lc_esnprintf(arm_get_arg_env(), cmd_buf, 256, "LDR %1D, [%1S, #%O]", irn, irn, irn );
+ lc_esnprintf(arm_get_arg_env(), cmnt_buf, 256, "/* Reload(%1S) -> (%1D) */", irn, irn);
+ lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
+ } else {
+ assert(0 && "reload not supported for this mode");
+ }
+}
+
+static void emit_be_Perm(const ir_node* irn, arm_emit_env_t *emit_env) {
+ FILE *F = emit_env->out;
+ ir_mode *mode = get_irn_mode(irn);
+ assert( (mode != mode_E) && "IEEE Extended FP not supported");
+ lc_efprintf(arm_get_arg_env(), F, "\tEOR %1S, %1S, %2S\t\t\t/* begin Perm(%1S, %2S) */\n", irn, irn, irn, irn, irn);
+ lc_efprintf(arm_get_arg_env(), F, "\tEOR %2S, %1S, %2S\n", irn, irn, irn);
+ lc_efprintf(arm_get_arg_env(), F, "\tEOR %1S, %1S, %2S\t\t\t/* end Perm(%1S, %2S) */\n", irn, irn, irn, irn, irn);
+}
+
+static void emit_be_StackParam(const ir_node *irn, arm_emit_env_t *emit_env) {
+ FILE *F = emit_env->out;
+ ir_mode *mode = get_irn_mode(irn);
+ char cmd_buf[256], cmnt_buf[256];
+ assert( (mode != mode_E) && "IEEE Extended FP not supported");
+
+ lc_esnprintf(arm_get_arg_env(), cmd_buf, 256, "LDR %1D, [%1S, #%O]", irn, irn, irn );
+ lc_esnprintf(arm_get_arg_env(), cmnt_buf, 256, "/* StackParam: (%1S + %O) -> %1D */",irn , irn, irn, get_irn_n(irn, 0));
+ lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
+}
+
+/************************************************************************/
+/* emit */
+/************************************************************************/
+
+static void emit_Jmp(ir_node *irn, void *env) {
+ arm_emit_env_t *emit_env = env;
+ FILE *out = emit_env->out;
+ const ir_edge_t *edge = get_irn_out_edge_first(irn);
+ ir_node *target_block = get_edge_src_irn(edge);
+ fprintf(out, "\tB BLOCK_%d\t\t\t/* unconditional Jump */\n", get_irn_node_nr(target_block));
+}
+
+static void emit_Proj(ir_node *irn, void *env) {
+
+}
+
+
+
+/***********************************************************************************
+ * _ __ _
+ * (_) / _| | |
+ * _ __ ___ __ _ _ _ __ | |_ _ __ __ _ _ __ ___ _____ _____ _ __| | __
+ * | '_ ` _ \ / _` | | '_ \ | _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /
+ * | | | | | | (_| | | | | | | | | | | (_| | | | | | | __/\ V V / (_) | | | <
+ * |_| |_| |_|\__,_|_|_| |_| |_| |_| \__,_|_| |_| |_|\___| \_/\_/ \___/|_| |_|\_\
+ *
+ ***********************************************************************************/
+
+/**
+ * Enters the emitter functions for handled nodes into the generic
+ * pointer of an opcode.
+ */
+static void arm_register_emitters(void) {
+
+#define ARM_EMIT(a) op_arm_##a->ops.generic = (op_func)emit_arm_##a
+#define EMIT(a) op_##a->ops.generic = (op_func)emit_##a
+#define BE_EMIT(a) op_be_##a->ops.generic = (op_func)emit_be_##a
+
+ /* first clear the generic function pointer for all ops */
+ clear_irp_opcodes_generic_func();
+
+ /* register all emitter functions defined in spec */
+ arm_register_spec_emitters();
+
+ /* other emitter functions */
+ ARM_EMIT(CondJmp);
+// ARM_EMIT(SwitchJmp);
+ ARM_EMIT(CopyB);
+// ARM_EMIT(CopyB_i);
+// ARM_EMIT(Const);
+ ARM_EMIT(SymConst);
+ ARM_EMIT(SwitchJmp);
+
+ /* benode emitter */
+ BE_EMIT(Call);
+ BE_EMIT(IncSP);
+// BE_EMIT(AddSP);
+ BE_EMIT(Copy);
+ BE_EMIT(Spill);
+ BE_EMIT(Reload);
+ BE_EMIT(Perm);
+ BE_EMIT(StackParam);
+
+ /* firm emitter */
+ EMIT(Jmp);
+
+
+ /* noisy stuff */
+#ifdef SILENCER
+ EMIT(Proj);
+#endif
+
+#undef ARM_EMIT
+#undef BE_EMIT
+#undef EMIT
+}
+
+/**
+ * Emits code for a node.
+ */
+static void arm_emit_node(const ir_node *irn, void *env) {
+ arm_emit_env_t *emit_env = env;
+ firm_dbg_module_t *mod = emit_env->mod;
+ FILE *F = emit_env->out;
+ ir_op *op = get_irn_op(irn);
+
+ DBG((mod, LEVEL_1, "emitting code for %+F\n", irn));
+
+ if (op->ops.generic) {
+ void (*emit)(const ir_node *, void *) = (void (*)(const ir_node *, void *))op->ops.generic;
+ (*emit)(irn, env);
+ }
+ else {
+ 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 arm_gen_block(ir_node *block, void *env) {
+ ir_node *irn;
+
+ if (! is_Block(block))
+ return;
+
+ fprintf(((arm_emit_env_t *)env)->out, "BLOCK_%ld:\n", get_irn_node_nr(block));
+ sched_foreach(block, irn) {
+ arm_emit_node(irn, env);
+ }
+}
+
+
+/**
+ * Emits code for function start.
+ */
+void arm_emit_start(FILE *F, ir_graph *irg) {
+ const char *irg_name = get_entity_name(get_irg_entity(irg));
+ fprintf(F, "\t.text\n");
+ fprintf(F, "\t.align 2\n");
+ fprintf(F, "\t.global %s\n", irg_name);
+ fprintf(F, "%s:\n", irg_name);
+}
+
+/**
+ * Emits code for function end
+ */
+void arm_emit_end(FILE *F, ir_graph *irg) {
+ const char *irg_name = get_entity_name(get_irg_entity(irg));
+}
+
+/**
+ * Sets labels for control flow nodes (jump target)
+ * TODO: Jump optimization
+ */
+void arm_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 arm_gen_routine(FILE *F, ir_graph *irg, const arm_code_gen_t *cg) {
+ arm_emit_env_t emit_env;
+
+ emit_env.mod = firm_dbg_register("firm.be.arm.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;
+
+ arm_register_emitters();
+
+ arm_emit_start(F, irg);
+ irg_block_walk_graph(irg, arm_gen_labels, NULL, &emit_env);
+ irg_walk_blkwise_graph(irg, NULL, arm_gen_block, &emit_env);
+ arm_emit_end(F, irg);
+}
--- /dev/null
+#ifndef _arm_EMITTER_H_
+#define _arm_EMITTER_H_
+
+#include "irargs_t.h" // this also inlucdes <libcore/lc_print.h>
+#include "irnode.h"
+#include "debug.h"
+
+#include "../bearch.h"
+
+#include "bearch_arm_t.h"
+
+typedef struct _arm_emit_env_t {
+ firm_dbg_module_t *mod;
+ FILE *out;
+ const arch_env_t *arch_env;
+ const arm_code_gen_t *cg;
+} arm_emit_env_t;
+
+const lc_arg_env_t *arm_get_arg_env(void);
+
+void equalize_dest_src(FILE *F, ir_node *n);
+
+int get_arm_reg_nr(ir_node *irn, int posi, int in_out);
+const char *get_arm_in_reg_name(ir_node *irn, int pos);
+
+void arm_gen_routine(FILE *F, ir_graph *irg, const arm_code_gen_t *cg);
+
+#endif /* _arm_EMITTER_H_ */
--- /dev/null
+/**
+ * Dumps global variables and constants as arm assembler.
+ * @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 "arm_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 arm_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 arm_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);
+ arm_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 arm_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 arm_gen_decls(FILE *out) {
+ struct obstack rodata, data, comm;
+ int size;
+ char *cp;
+
+ obstack_init(&rodata);
+ obstack_init(&data);
+ obstack_init(&comm);
+
+ arm_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 _ARM_GEN_DECLS_H_
+#define _ARM_GEN_DECLS_H_
+
+/**
+ * Generate all entities.
+ */
+void arm_gen_decls(FILE *out);
+
+#endif /* _ARM_GEN_DECLS_H_ */
--- /dev/null
+/**
+ * Register mapping for firm nodes. Stolen from bearch_firm :)
+ * $Id$
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+
+#include "arm_map_regs.h"
+#include "arm_new_nodes.h"
+
+#include "gen_arm_regalloc_if.h"
+
+
+static const arch_register_t *gpreg_param_reg_std[] = {
+ &arm_general_purpose_regs[REG_R0],
+ &arm_general_purpose_regs[REG_R1],
+ &arm_general_purpose_regs[REG_R2],
+ &arm_general_purpose_regs[REG_R3],
+};
+
+const arch_register_t *arm_get_RegParam_reg(int n) {
+ assert(n < 4 && n >=0 && "register param > 3 angefordert");
+ return gpreg_param_reg_std[n];
+}
+
+/* Mapping to store registers in firm nodes */
+
+struct arm_irn_reg_assoc {
+ const ir_node *irn;
+ const arch_register_t *reg;
+};
+
+int arm_cmp_irn_reg_assoc(const void *a, const void *b, size_t len) {
+ const struct arm_irn_reg_assoc *x = a;
+ const struct arm_irn_reg_assoc *y = b;
+
+ return x->irn != y->irn;
+}
+
+static struct arm_irn_reg_assoc *get_irn_reg_assoc(const ir_node *irn, set *reg_set) {
+ struct arm_irn_reg_assoc templ;
+ unsigned int hash;
+
+ templ.irn = irn;
+ templ.reg = NULL;
+ hash = HASH_PTR(irn);
+
+ return set_insert(reg_set, &templ, sizeof(templ), hash);
+}
+
+void arm_set_firm_reg(ir_node *irn, const arch_register_t *reg, set *reg_set) {
+ struct arm_irn_reg_assoc *assoc = get_irn_reg_assoc(irn, reg_set);
+ assoc->reg = reg;
+}
+
+const arch_register_t *arm_get_firm_reg(const ir_node *irn, set *reg_set) {
+ struct arm_irn_reg_assoc *assoc = get_irn_reg_assoc(irn, reg_set);
+ return assoc->reg;
+}
+
+
+
+/**
+ * Translates the projnum into a "real" argument position for register
+ * requirements dependend on the predecessor.
+ */
+long arm_translate_proj_pos(const ir_node *proj) {
+ ir_node *pred = get_Proj_pred(proj);
+ long nr = get_Proj_proj(proj);
+
+ if (is_arm_Load(pred) || is_arm_fLoadd(pred) || is_arm_fLoads(pred)) {
+ if (nr == pn_Load_res)
+ return 0;
+ assert(0 && "unsupported Proj(Load) number");
+ }
+ else if (is_arm_Store(pred) || is_arm_fStores(pred) || is_arm_fStored(pred)) {
+ return 0;
+ }
+ else if (is_arm_fDiv(pred)) {
+ if (nr == pn_Quot_res)
+ return 0;
+ else
+ assert(0 && "there should be no more Projs for a fDiv");
+ }
+
+// assert(0 && "unsupported Proj(X)");
+ return nr;
+}
--- /dev/null
+#ifndef _arm_MAP_REGS_H_
+#define _arm_MAP_REGS_H_
+
+#include "irnode.h"
+#include "set.h"
+
+#include "../bearch.h"
+#include "arm_nodes_attr.h"
+
+const arch_register_t *arm_get_RegParam_reg(int n);
+
+int arm_cmp_irn_reg_assoc(const void *a, const void *b, size_t len);
+void arm_set_firm_reg(ir_node *irn, const arch_register_t *reg, set *reg_set);
+const arch_register_t *arm_get_firm_reg(const ir_node *irn, set *reg_set);
+
+long arm_translate_proj_pos(const ir_node *proj);
+
+#endif /* _arm_MAP_REGS_H_ */
--- /dev/null
+/**
+ * This file implements the creation of the achitecture specific firm opcodes
+ * and the coresponding node constructors for the arm assembler irg.
+ * $Id$
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef _WIN32
+#include <malloc.h>
+#else
+#include <alloca.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 "irprintf.h"
+
+#include "../bearch.h"
+
+#include "arm_nodes_attr.h"
+#include "arm_new_nodes.h"
+#include "gen_arm_regalloc_if.h"
+
+#include "../beabi.h"
+#include "bearch_arm_t.h"
+
+
+/***********************************************************************************
+ * _ _ _ __
+ * | | (_) | | / _|
+ * __| |_ _ _ __ ___ _ __ ___ _ __ _ _ __ | |_ ___ _ __| |_ __ _ ___ ___
+ * / _` | | | | '_ ` _ \| '_ \ / _ \ '__| | | '_ \| __/ _ \ '__| _/ _` |/ __/ _ \
+ * | (_| | |_| | | | | | | |_) | __/ | | | | | | || __/ | | || (_| | (_| __/
+ * \__,_|\__,_|_| |_| |_| .__/ \___|_| |_|_| |_|\__\___|_| |_| \__,_|\___\___|
+ * | |
+ * |_|
+ ***********************************************************************************/
+
+/**
+ * Returns a string containing the names of all registers within the limited bitset
+ */
+static char *get_limited_regs(const arch_register_req_t *req, char *buf, int max) {
+ bitset_t *bs = bitset_alloca(req->cls->n_regs);
+ char *p = buf;
+ int size = 0;
+ int i, cnt;
+
+ req->limited(NULL, bs);
+
+ for (i = 0; i < req->cls->n_regs; i++) {
+ if (bitset_is_set(bs, i)) {
+ cnt = snprintf(p, max - size, " %s", req->cls->regs[i].name);
+ if (cnt < 0) {
+ fprintf(stderr, "dumper problem, exiting\n");
+ exit(1);
+ }
+
+ p += cnt;
+ size += cnt;
+
+ if (size >= max)
+ break;
+ }
+ }
+
+ return buf;
+}
+
+/**
+ * Dumps the register requirements for either in or out.
+ */
+static void dump_reg_req(FILE *F, ir_node *n, const arm_register_req_t **reqs, int inout) {
+ char *dir = inout ? "out" : "in";
+ int max = inout ? get_arm_n_res(n) : get_irn_arity(n);
+ char *buf = alloca(1024);
+ int i;
+
+ memset(buf, 0, 1024);
+
+ if (reqs) {
+ for (i = 0; i < max; i++) {
+ fprintf(F, "%sreq #%d =", dir, i);
+
+ if (reqs[i]->req.type == arch_register_req_type_none) {
+ fprintf(F, " n/a");
+ }
+
+ if (reqs[i]->req.type & arch_register_req_type_normal) {
+ fprintf(F, " %s", reqs[i]->req.cls->name);
+ }
+
+ if (reqs[i]->req.type & arch_register_req_type_limited) {
+ fprintf(F, " %s", get_limited_regs(&reqs[i]->req, buf, 1024));
+ }
+
+ if (reqs[i]->req.type & arch_register_req_type_should_be_same) {
+ ir_fprintf(F, " same as %+F", get_irn_n(n, reqs[i]->same_pos));
+ }
+
+ if (reqs[i]->req.type & arch_register_req_type_should_be_different) {
+ ir_fprintf(F, " different from %+F", get_irn_n(n, reqs[i]->different_pos));
+ }
+
+ fprintf(F, "\n");
+ }
+
+ fprintf(F, "\n");
+ }
+ else {
+ fprintf(F, "%sreq = N/A\n", dir);
+ }
+}
+
+
+/**
+ * Dumper interface for dumping arm 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_arm(ir_node *n, FILE *F, dump_reason_t reason) {
+ ir_mode *mode = NULL;
+ int bad = 0;
+ int i;
+ arm_attr_t *attr;
+ const arm_register_req_t **reqs;
+ const arch_register_t **slots;
+
+ switch (reason) {
+ case dump_node_opcode_txt:
+ fprintf(F, "%s", get_irn_opname(n));
+ break;
+
+ case dump_node_mode_txt:
+ mode = get_irn_mode(n);
+
+ if (mode) {
+ fprintf(F, "[%s]", get_mode_name(mode));
+ }
+ else {
+ fprintf(F, "[?NOMODE?]");
+ }
+ break;
+
+ case dump_node_nodeattr_txt:
+
+ /* TODO: dump some attributes which should show up */
+ /* in node name in dump (e.g. consts or the like) */
+
+ break;
+
+ case dump_node_info_txt:
+ attr = get_arm_attr(n);
+ fprintf(F, "=== arm attr begin ===\n");
+
+ /* dump IN requirements */
+ if (get_irn_arity(n) > 0) {
+ reqs = get_arm_in_req_all(n);
+ dump_reg_req(F, n, reqs, 0);
+ }
+
+ /* dump OUT requirements */
+ if (attr->n_res > 0) {
+ reqs = get_arm_out_req_all(n);
+ dump_reg_req(F, n, reqs, 1);
+ }
+
+ /* dump assigned registers */
+ slots = get_arm_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);
+ }
+ }
+ }
+ fprintf(F, "\n");
+
+ /* dump n_res */
+ fprintf(F, "n_res = %d\n", get_arm_n_res(n));
+
+ /* dump flags */
+ fprintf(F, "flags =");
+ if (attr->flags == arch_irn_flags_none) {
+ fprintf(F, " none");
+ }
+ else {
+ if (attr->flags & arch_irn_flags_dont_spill) {
+ fprintf(F, " unspillable");
+ }
+ if (attr->flags & arch_irn_flags_rematerializable) {
+ fprintf(F, " remat");
+ }
+ if (attr->flags & arch_irn_flags_ignore) {
+ fprintf(F, " ignore");
+ }
+ }
+ fprintf(F, " (%d)\n", attr->flags);
+
+ if (get_arm_value(n)) {
+ if (is_arm_CopyB(n)) {
+ fprintf(F, "size = %u\n", get_tarval_long(get_arm_value(n)));
+ } else {
+ if (mode_is_float(get_irn_mode(n))) {
+ fprintf(F, "float value = (%lf)\n", get_tarval_double(get_arm_value(n)));
+ } else if (mode_is_int(get_irn_mode(n))) {
+ long v = get_tarval_long(get_arm_value(n));
+ fprintf(F, "long value = %ld (0x%08lx)\n", v, v);
+ } else if (mode_is_reference(get_irn_mode(n))) {
+ fprintf(F, "pointer\n");
+ } else {
+ assert(0 && "unbehandelter Typ im const-Knoten");
+ }
+ }
+ }
+ if (get_arm_proj_num(n) >= 0) {
+ fprintf(F, "proj_num = (%d)\n", get_arm_proj_num(n));
+ }
+ /* TODO: dump all additional attributes */
+
+ fprintf(F, "=== arm attr end ===\n");
+ /* end of: case dump_node_info_txt */
+ 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 :-(
+ */
+arm_attr_t *get_arm_attr(const ir_node *node) {
+ assert(is_arm_irn(node) && "need arm node to get attributes");
+ return (arm_attr_t *)get_irn_generic_attr((ir_node *)node);
+}
+
+/**
+ * Returns the argument register requirements of a arm node.
+ */
+const arm_register_req_t **get_arm_in_req_all(const ir_node *node) {
+ arm_attr_t *attr = get_arm_attr(node);
+ return attr->in_req;
+}
+
+/**
+ * Returns the result register requirements of an arm node.
+ */
+const arm_register_req_t **get_arm_out_req_all(const ir_node *node) {
+ arm_attr_t *attr = get_arm_attr(node);
+ return attr->out_req;
+}
+
+/**
+ * Returns the argument register requirement at position pos of an arm node.
+ */
+const arm_register_req_t *get_arm_in_req(const ir_node *node, int pos) {
+ arm_attr_t *attr = get_arm_attr(node);
+ return attr->in_req[pos];
+}
+
+/**
+ * Returns the result register requirement at position pos of an arm node.
+ */
+const arm_register_req_t *get_arm_out_req(const ir_node *node, int pos) {
+ arm_attr_t *attr = get_arm_attr(node);
+ return attr->out_req[pos];
+}
+
+/**
+ * Sets the OUT register requirements at position pos.
+ */
+void set_arm_req_out(ir_node *node, const arm_register_req_t *req, int pos) {
+ arm_attr_t *attr = get_arm_attr(node);
+ attr->out_req[pos] = req;
+}
+
+/**
+ * Sets the complete OUT requirements of node.
+ */
+void set_arm_req_out_all(ir_node *node, const arm_register_req_t **reqs) {
+ arm_attr_t *attr = get_arm_attr(node);
+ attr->out_req = reqs;
+}
+
+/**
+ * Sets the IN register requirements at position pos.
+ */
+void set_arm_req_in(ir_node *node, const arm_register_req_t *req, int pos) {
+ arm_attr_t *attr = get_arm_attr(node);
+ attr->in_req[pos] = req;
+}
+
+/**
+ * Returns the register flag of an arm node.
+ */
+arch_irn_flags_t get_arm_flags(const ir_node *node) {
+ arm_attr_t *attr = get_arm_attr(node);
+ return attr->flags;
+}
+
+/**
+ * Sets the register flag of an arm node.
+ */
+void set_arm_flags(const ir_node *node, arch_irn_flags_t flags) {
+ arm_attr_t *attr = get_arm_attr(node);
+ attr->flags = flags;
+}
+
+/**
+ * Returns the result register slots of an arm node.
+ */
+const arch_register_t **get_arm_slots(const ir_node *node) {
+ arm_attr_t *attr = get_arm_attr(node);
+ return attr->slots;
+}
+
+/**
+ * Returns the name of the OUT register at position pos.
+ */
+const char *get_arm_out_reg_name(const ir_node *node, int pos) {
+ arm_attr_t *attr = get_arm_attr(node);
+
+ assert(is_arm_irn(node) && "Not an arm 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_arm_out_regnr(const ir_node *node, int pos) {
+ arm_attr_t *attr = get_arm_attr(node);
+
+ assert(is_arm_irn(node) && "Not an arm 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_arm_out_reg(const ir_node *node, int pos) {
+ arm_attr_t *attr = get_arm_attr(node);
+
+ assert(is_arm_irn(node) && "Not an arm 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_arm_n_res(ir_node *node, int n_res) {
+ arm_attr_t *attr = get_arm_attr(node);
+ attr->n_res = n_res;
+}
+
+/**
+ * Returns the number of results.
+ */
+int get_arm_n_res(const ir_node *node) {
+ arm_attr_t *attr = get_arm_attr(node);
+ return attr->n_res;
+}
+/**
+ * Returns the tarvalue
+ */
+tarval *get_arm_value(const ir_node *node) {
+ arm_attr_t *attr = get_arm_attr(node);
+ return attr->value;
+}
+
+/**
+ * Sets the tarvalue
+ */
+void set_arm_value(ir_node *node, tarval *tv) {
+ arm_attr_t *attr = get_arm_attr(node);
+ attr->value = tv;
+}
+
+/**
+ * Returns the proj num
+ */
+int get_arm_proj_num(const ir_node *node) {
+ arm_attr_t *attr = get_arm_attr(node);
+ return attr->proj_num;
+}
+
+/**
+ * Sets the proj num
+ */
+void set_arm_proj_num(ir_node *node, int proj_num) {
+ arm_attr_t *attr = get_arm_attr(node);
+ attr->proj_num = proj_num;
+}
+
+/**
+ * Returns the SymConst label
+ */
+const char *get_arm_symconst_label(ir_node *node) {
+ arm_attr_t *attr = get_arm_attr(node);
+ return attr->symconst_label;
+}
+
+/**
+ * Sets the SymConst label
+ */
+void set_arm_symconst_label(ir_node *node, const char *symconst_label) {
+ arm_attr_t *attr = get_arm_attr(node);
+ attr->symconst_label = symconst_label;
+}
+
+
+/**
+ * Returns the number of projs.
+ */
+int get_arm_n_projs(ir_node *node) {
+ arm_attr_t *attr = get_arm_attr(node);
+ return attr->n_projs;
+}
+
+/**
+ * Sets the number of projs.
+ */
+void set_arm_n_projs(ir_node *node, int n_projs) {
+ arm_attr_t *attr = get_arm_attr(node);
+ attr->n_projs = n_projs;
+}
+
+/**
+ * Returns the default_proj_num.
+ */
+long get_arm_default_proj_num(ir_node *node) {
+ arm_attr_t *attr = get_arm_attr(node);
+ return attr->default_proj_num;
+}
+
+/**
+ * Sets the default_proj_num.
+ */
+void set_arm_default_proj_num(ir_node *node, long default_proj_num) {
+ arm_attr_t *attr = get_arm_attr(node);
+ attr->default_proj_num = default_proj_num;
+}
+
+
+
+void init_arm_attributes(ir_node *node, int flags, const arm_register_req_t ** in_reqs,
+ const arm_register_req_t ** out_reqs, int n_res) {
+ arm_attr_t *attr = get_arm_attr(node);
+ attr->in_req = in_reqs;
+ attr->out_req = out_reqs;
+ attr->n_res = n_res;
+ attr->flags = flags;
+ attr->slots = xcalloc(n_res, sizeof(attr->slots[0]));
+ attr->value = NULL;
+ attr->proj_num = -42;
+ attr->symconst_label = NULL;
+ attr->n_projs = 0;
+ attr->default_proj_num = 0;
+}
+
+static int arm_comp_condJmp(arm_attr_t *attr_a, arm_attr_t *attr_b) {
+ return 1;
+}
+
+ir_node *arm_new_NoReg_gp(arm_code_gen_t *cg) {
+ return be_abi_get_callee_save_irn(cg->birg->abi, &arm_general_purpose_regs[REG_RXX]);
+}
+
+ir_node *arm_new_NoReg_fp(arm_code_gen_t *cg) {
+ return be_abi_get_callee_save_irn(cg->birg->abi, &arm_floating_point_regs[REG_FXX]);
+}
+
+
+
+
+/***************************************************************************************
+ * _ _ _
+ * | | | | | |
+ * _ __ ___ __| | ___ ___ ___ _ __ ___| |_ _ __ _ _ ___| |_ ___ _ __ ___
+ * | '_ \ / _ \ / _` |/ _ \ / __/ _ \| '_ \/ __| __| '__| | | |/ __| __/ _ \| '__/ __|
+ * | | | | (_) | (_| | __/ | (_| (_) | | | \__ \ |_| | | |_| | (__| || (_) | | \__ \
+ * |_| |_|\___/ \__,_|\___| \___\___/|_| |_|___/\__|_| \__,_|\___|\__\___/|_| |___/
+ *
+ ***************************************************************************************/
+
+/* limit the possible registers for sp in arm_StoreStackM4Inc */
+static void limit_reg_arm_StoreStackM4Inc_sp(void *_unused, bitset_t *bs) {
+ bs = bitset_clear_all(bs); /* disallow all register (positive constraints given) */
+ bitset_set(bs, 14); /* allow r13 */
+ bitset_clear(bs, 13); /* disallow ignore reg r12 */
+ bitset_clear(bs, 14); /* disallow ignore reg r13 */
+ bitset_clear(bs, 15); /* disallow ignore reg r15 */
+ bitset_clear(bs, 16); /* disallow ignore reg rxx */
+ bitset_clear(bs, 17); /* disallow ignore reg MURX */
+}
+
+static const arm_register_req_t _arm_req_sp = {
+ {
+ arch_register_req_type_limited,
+ &arm_reg_classes[CLASS_arm_general_purpose],
+ limit_reg_arm_StoreStackM4Inc_sp,
+ NULL, /* limit environment */
+ NULL, /* same node */
+ NULL /* different node */
+ },
+ 0,
+ 0
+};
+
+/* construct Store: Store(ptr, val, mem) = ST ptr,val */
+ir_node *new_r_arm_StoreStackMInc(ir_graph *irg, ir_node *block, ir_node *mem, ir_node *sp,
+ int n_regs, ir_node **regs, ir_mode *mode) {
+ ir_node *res;
+ ir_node *in[16];
+ int flags = 0;
+ static const arm_register_req_t *_in_req_arm_StoreStackM4Inc[] =
+ {
+ &arm_default_req_none,
+ &_arm_req_sp,
+ &arm_default_req_arm_general_purpose,
+ &arm_default_req_arm_general_purpose,
+ &arm_default_req_arm_general_purpose,
+ &arm_default_req_arm_general_purpose,
+ &arm_default_req_arm_general_purpose,
+ &arm_default_req_arm_general_purpose,
+ &arm_default_req_arm_general_purpose,
+ &arm_default_req_arm_general_purpose,
+ &arm_default_req_arm_general_purpose,
+ &arm_default_req_arm_general_purpose,
+ &arm_default_req_arm_general_purpose,
+ &arm_default_req_arm_general_purpose,
+ &arm_default_req_arm_general_purpose,
+ &arm_default_req_arm_general_purpose,
+ };
+
+ assert(n_regs <= 15);
+
+ in[0] = mem;
+ in[1] = sp;
+ memcpy(&in[2], regs, n_regs * sizeof(in[0]));
+ res = new_ir_node(NULL, irg, block, op_arm_StoreStackM4Inc, mode, 2 + n_regs, in);
+ flags |= arch_irn_flags_rematerializable; /* op can be easily recalculated */
+
+ /* init node attributes */
+ init_arm_attributes(res, flags, _in_req_arm_StoreStackM4Inc, NULL, 0);
+
+ res = optimize_node(res);
+ irn_vrfy_irg(res, irg);
+
+ return res;
+}
+
+/**
+ * Register additional opcodes here.
+ */
+static void arm_register_additional_opcodes(int cur_opcode) {
+}
+
+
+/* Include the generated constructor functions */
+#include "gen_arm_new_nodes.c.inl"
--- /dev/null
+#ifndef _arm_NEW_NODES_H_
+#define _arm_NEW_NODES_H_
+
+/**
+ * Function prototypes for the assembler ir node constructors.
+ * $Id$
+ */
+
+#include "arm_nodes_attr.h"
+#include "bearch_arm_t.h"
+
+/***************************************************************************************************
+ * _ _ _ __ _ _ _ _
+ * | | | | | | / / | | | | | | | |
+ * __ _| |_| |_ _ __ ___ ___| |_ / /_ _ ___| |_ _ __ ___ ___| |_| |__ ___ __| |___
+ * / _` | __| __| '__| / __|/ _ \ __| / / _` |/ _ \ __| | '_ ` _ \ / _ \ __| '_ \ / _ \ / _` / __|
+ * | (_| | |_| |_| | \__ \ __/ |_ / / (_| | __/ |_ | | | | | | __/ |_| | | | (_) | (_| \__ \
+ * \__,_|\__|\__|_| |___/\___|\__/_/ \__, |\___|\__| |_| |_| |_|\___|\__|_| |_|\___/ \__,_|___/
+ * __/ |
+ * |___/
+ ***************************************************************************************************/
+
+/**
+ * Returns the attributes of an arm node.
+ */
+arm_attr_t *get_arm_attr(const ir_node *node);
+
+/**
+ * Returns the argument register requirements of an arm node.
+ */
+const arm_register_req_t **get_arm_in_req_all(const ir_node *node);
+
+/**
+ * Returns the result register requirements of an arm node.
+ */
+const arm_register_req_t **get_arm_out_req_all(const ir_node *node);
+
+/**
+ * Returns the argument register requirements of an arm node.
+ */
+const arm_register_req_t *get_arm_in_req(const ir_node *node, int pos);
+
+/**
+ * Returns the result register requirements of an arm node.
+ */
+const arm_register_req_t *get_arm_out_req(const ir_node *node, int pos);
+
+/**
+ * Sets the OUT register requirements at position pos.
+ */
+void set_arm_req_out(ir_node *node, const arm_register_req_t *req, int pos);
+
+/**
+ * Sets the complete OUT requirements of node.
+ */
+void set_arm_req_out_all(ir_node *node, const arm_register_req_t **reqs);
+
+/**
+ * Sets the IN register requirements at position pos.
+ */
+void set_arm_req_in(ir_node *node, const arm_register_req_t *req, int pos);
+
+/**
+ * Returns the register flag of an arm node.
+ */
+arch_irn_flags_t get_arm_flags(const ir_node *node);
+
+/**
+ * Sets the register flag of an arm node.
+ */
+void set_arm_flags(const ir_node *node, arch_irn_flags_t flags);
+
+/**
+ * Returns the result register slots of an arm node.
+ */
+const arch_register_t **get_arm_slots(const ir_node *node);
+
+/**
+ * Returns the name of the OUT register at position pos.
+ */
+const char *get_arm_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_arm_out_regnr(const ir_node *node, int pos);
+
+/**
+ * Returns the OUT register at position pos.
+ */
+const arch_register_t *get_arm_out_reg(const ir_node *node, int pos);
+
+/**
+ * Sets the number of results.
+ */
+void set_arm_n_res(ir_node *node, int n_res);
+
+/**
+ * Returns the number of results.
+ */
+int get_arm_n_res(const ir_node *node);
+
+void init_arm_attributes(ir_node *node, int flags, const arm_register_req_t ** in_reqs,
+ const arm_register_req_t ** out_reqs, int n_res);
+
+ir_node *arm_new_NoReg_gp(arm_code_gen_t *cg);
+ir_node *arm_new_NoReg_fp(arm_code_gen_t *cg);
+
+/**
+ * Returns the tarval
+ */
+tarval *get_arm_value(const ir_node *node);
+
+/**
+ * Sets the tarval
+ */
+void set_arm_value(ir_node *node, tarval *tv);
+
+/**
+ * Returns the proj num
+ */
+int get_arm_proj_num(const ir_node *node);
+
+/**
+ * Sets the proj num
+ */
+void set_arm_proj_num(ir_node *node, int proj_num);
+
+const char *get_arm_symconst_label(ir_node *node);
+void set_arm_symconst_label(ir_node *node, const char *symconst_label);
+
+ir_node *new_r_arm_StoreStackMInc(ir_graph *irg, ir_node *block, ir_node *mem, ir_node *sp,
+ int n_regs, ir_node **regs, ir_mode *mode);
+
+/**
+ * Returns the number of projs.
+ */
+int get_arm_n_projs(ir_node *node);
+
+/**
+ * Sets the number of projs.
+ */
+void set_arm_n_projs(ir_node *node, int n_projs);
+
+/**
+ * Returns the default_proj_num.
+ */
+long get_arm_default_proj_num(ir_node *node);
+
+/**
+ * Sets the default_proj_num.
+ */
+void set_arm_default_proj_num(ir_node *node, long default_proj_num);
+
+
+/* Include the generated headers */
+#include "gen_arm_new_nodes.h"
+
+#endif /* _arm_NEW_NODES_H_ */
--- /dev/null
+#ifndef _ARM_NODES_ATTR_H_
+#define _ARM_NODES_ATTR_H_
+
+#include "../bearch.h"
+#include "../../common/firm_types.h"
+
+
+typedef struct _arm_register_req_t {
+ const arch_register_req_t req;
+ int same_pos; /**<< in case of "should be same" we need to remember the pos to get the irn */
+ int different_pos; /**<< in case of "should be different" we need to remember the pos to get the irn */
+} arm_register_req_t;
+
+
+typedef struct _arm_attr_t {
+ arch_irn_flags_t flags; /**<< indicating if spillable, rematerializeable ... etc. */
+ int n_res; /**<< number of results for this node */
+
+ const arm_register_req_t **in_req; /**<< register requirements for arguments */
+ const arm_register_req_t **out_req; /**<< register requirements for results */
+
+ const arch_register_t **slots; /**<< register slots for assigned registers */
+
+ tarval *value;
+ const char *symconst_label;
+ int proj_num;
+ int n_projs;
+ long default_proj_num;
+} arm_attr_t;
+
+#endif /* _ARM_NODES_ATTR_H_ */
--- /dev/null
+# Creation: 2006/02/13
+# $Id$
+# This is a template specification for the Firm-Backend
+
+# the cpu architecture (ia32, ia64, mips, sparc, ppc, ...)
+
+$arch = "arm";
+
+# $comment_string = 'WIRHABENKEINEKOMMENTARE';
+$comment_string = '/*';
+
+# the number of additional opcodes you want to register
+$additional_opcodes = 0;
+
+# The node description is done as a perl hash initializer with the
+# following structure:
+#
+# %nodes = (
+#
+# <op-name> => {
+# "op_flags" => "N|L|C|X|I|F|Y|H|c|K",
+# "irn_flags" => "R|N|I"
+# "arity" => "0|1|2|3 ... |variable|dynamic|any",
+# "state" => "floats|pinned|mem_pinned|exc_pinned",
+# "args" => [
+# { "type" => "type 1", "name" => "name 1" },
+# { "type" => "type 2", "name" => "name 2" },
+# ...
+# ],
+# "comment" => "any comment for constructor",
+# "reg_req" => { "in" => [ "reg_class|register" ], "out" => [ "reg_class|register|in_rX" ] },
+# "cmp_attr" => "c source code for comparing node attributes",
+# "emit" => "emit code with templates",
+# "rd_constructor" => "c source code which constructs an ir_node"
+# },
+#
+# ... # (all nodes you need to describe)
+#
+# ); # close the %nodes initializer
+
+# op_flags: flags for the operation, OPTIONAL (default is "N")
+# the op_flags correspond to the firm irop_flags:
+# N irop_flag_none
+# L irop_flag_labeled
+# C irop_flag_commutative
+# X irop_flag_cfopcode
+# I irop_flag_ip_cfopcode
+# F irop_flag_fragile
+# Y irop_flag_forking
+# H irop_flag_highlevel
+# c irop_flag_constlike
+# K irop_flag_keep
+#
+# irn_flags: special node flags, OPTIONAL (default is 0)
+# following irn_flags are supported:
+# R rematerializeable
+# N not spillable
+# I ignore for register allocation
+#
+# state: state of the operation, OPTIONAL (default is "floats")
+#
+# arity: arity of the operation, MUST NOT BE OMITTED
+#
+# args: the OPTIONAL arguments of the node constructor (debug, irg and block
+# are always the first 3 arguments and are always autmatically
+# created)
+# If this key is missing the following arguments will be created:
+# for i = 1 .. arity: ir_node *op_i
+# ir_mode *mode
+#
+# comment: OPTIONAL comment for the node constructor
+#
+# rd_constructor: for every operation there will be a
+# new_rd_<arch>_<op-name> function with the arguments from above
+# which creates the ir_node corresponding to the defined operation
+# you can either put the complete source code of this function here
+#
+# This key is OPTIONAL. If omitted, the following constructor will
+# be created:
+# if (!op_<arch>_<op-name>) assert(0);
+# for i = 1 to arity
+# set in[i] = op_i
+# done
+# res = new_ir_node(db, irg, block, op_<arch>_<op-name>, mode, arity, in)
+# return res
+#
+# NOTE: rd_constructor and args are only optional if and only if arity is 0,1,2 or 3
+
+# register types:
+# 0 - no special type
+# 1 - caller save (register must be saved by the caller of a function)
+# 2 - callee save (register must be saved by the called function)
+# 4 - ignore (do not assign this register)
+# NOTE: Last entry of each class is the largest Firm-Mode a register can hold
+%reg_classes = (
+ "general_purpose" => [
+ { "name" => "r0", "type" => 1 },
+ { "name" => "r1", "type" => 1 },
+ { "name" => "r2", "type" => 1 },
+ { "name" => "r3", "type" => 1 },
+ { "name" => "r4", "type" => 2 },
+ { "name" => "r5", "type" => 2 },
+ { "name" => "r6", "type" => 2 },
+ { "name" => "r7", "type" => 2 },
+ { "name" => "r8", "type" => 2 },
+ { "name" => "r9", "type" => 2 },
+ { "name" => "r10", "type" => 2 },
+ { "name" => "r11", "type" => 2 },
+ { "name" => "r12", "type" => 6 }, # reserved for linker
+ { "name" => "r13", "type" => 6 }, # this is our stack pointer
+ { "name" => "r14", "type" => 3 }, # this is our return address
+ { "name" => "r15", "type" => 6 }, # this is our program counter
+ { "name" => "rxx", "type" => 6 }, # dummy register for no_mem
+ { "name" => "MURX", "type" => 6 }, # this is our workaround-register
+ { "mode" => "mode_P" }
+ ],
+ "floating_point" => [
+ { "name" => "f0", "type" => 1 },
+ { "name" => "f1", "type" => 1 },
+ { "name" => "f2", "type" => 1 },
+ { "name" => "f3", "type" => 1 },
+ { "name" => "f4", "type" => 2 },
+ { "name" => "f5", "type" => 2 },
+ { "name" => "f6", "type" => 2 },
+ { "name" => "f7", "type" => 2 },
+ { "name" => "fxx", "type" => 6 }, # dummy register for no_mem
+ { "mode" => "mode_D" }
+ ]
+); # %reg_classes
+
+#--------------------------------------------------#
+# _ #
+# (_) #
+# _ __ _____ __ _ _ __ ___ _ __ ___ #
+# | '_ \ / _ \ \ /\ / / | | '__| / _ \| '_ \/ __| #
+# | | | | __/\ V V / | | | | (_) | |_) \__ \ #
+# |_| |_|\___| \_/\_/ |_|_| \___/| .__/|___/ #
+# | | #
+# |_| #
+#--------------------------------------------------#
+
+%nodes = (
+
+#-----------------------------------------------------------------#
+# _ _ _ #
+# (_) | | | | #
+# _ _ __ | |_ ___ __ _ ___ _ __ _ __ ___ __| | ___ ___ #
+# | | '_ \| __/ _ \/ _` |/ _ \ '__| | '_ \ / _ \ / _` |/ _ \/ __| #
+# | | | | | || __/ (_| | __/ | | | | | (_) | (_| | __/\__ \ #
+# |_|_| |_|\__\___|\__, |\___|_| |_| |_|\___/ \__,_|\___||___/ #
+# __/ | #
+# |___/ #
+#-----------------------------------------------------------------#
+
+# commutative operations
+
+"Add" => {
+ "op_flags" => "C",
+ "irn_flags" => "R",
+ "comment" => "construct Add: Add(a, b) = Add(b, a) = a + b",
+ "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+ "emit" => '. ADD %D1, %S1, %S2\t\t\t/* Add(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+"Add_i" => {
+ "irn_flags" => "R",
+ "comment" => "construct Add: Add(a, const) = Add(const, a) = a + const",
+ "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+ "emit" => '. ADD %D1, %S1, %C\t\t\t/* Add(%C, %S1) -> %D1, (%A1, const) */',
+ "cmp_attr" =>
+' if (attr_a->value == NULL || attr_b->value == NULL)
+ return 1;
+
+ return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
+'
+},
+
+"Mul" => {
+ #"op_flags" => "C",
+ "irn_flags" => "R",
+ "comment" => "construct Mul: Mul(a, b) = Mul(b, a) = a * b",
+ "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "!in_r1" ] },
+ "emit" =>'. MUL %D1, %S1, %S2\t\t\t/* Mul(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+"And" => {
+ "op_flags" => "C",
+ "irn_flags" => "R",
+ "comment" => "construct And: And(a, b) = And(b, a) = a AND b",
+ "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+ "emit" => '. AND %D1, %S1, %S2\t\t/* And(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+"And_i" => {
+ "irn_flags" => "R",
+ "comment" => "construct And: And(a, const) = And(const, a) = a AND const",
+ "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+ "emit" => '. AND %D1, %S1, %C\t\t\t/* And(%C, %S1) -> %D1, (%A1, const) */',
+ "cmp_attr" =>
+' if (attr_a->value == NULL || attr_b->value == NULL)
+ return 1;
+
+ return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
+'
+},
+
+"Or" => {
+ "op_flags" => "C",
+ "irn_flags" => "R",
+ "comment" => "construct Or: Or(a, b) = Or(b, a) = a OR b",
+ "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+ "emit" => '. ORR %D1, %S1, %S2\t\t/* Or(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+"Or_i" => {
+ "irn_flags" => "R",
+ "comment" => "construct Or: Or(a, const) = Or(const, a) = a OR const",
+ "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+ "emit" => '. ORR %D1, %S1, %C\t\t\t/* Or(%C, %S1) -> %D1, (%A1, const) */',
+ "cmp_attr" =>
+' if (attr_a->value == NULL || attr_b->value == NULL)
+ return 1;
+
+ return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
+'
+},
+
+"Or_Shl_i" => {
+ "irn_flags" => "R",
+ "comment" => "construct Or with immediate shifter operand",
+ "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+ "emit" => '. ORR %D1, %S1, %S2 LSL %C\t\t\t/* Or_Shl_i(%S1, %S2 << %C) -> %D1, (%A1, const) */',
+ "cmp_attr" =>
+' if (attr_a->value == NULL || attr_b->value == NULL)
+ return 1;
+
+ return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
+'
+},
+
+"Eor" => {
+ "op_flags" => "C",
+ "irn_flags" => "R",
+ "comment" => "construct Eor: Eor(a, b) = Eor(b, a) = a EOR b",
+ "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+ "emit" => '. EOR %D1, %S1, %S2\t\t\t/* Xor(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+"Eor_i" => {
+ "irn_flags" => "R",
+ "comment" => "construct Eor: Eor(a, const) = Eor(const, a) = a EOR const",
+ "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+ "emit" => '. EOR %D1, %S1, %C\t\t\t/* Xor(%C, %S1) -> %D1, (%A1, const) */',
+ "cmp_attr" =>
+' if (attr_a->value == NULL || attr_b->value == NULL)
+ return 1;
+
+ return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
+'
+},
+
+# not commutative operations
+
+"Sub" => {
+ "irn_flags" => "R",
+ "comment" => "construct Sub: Sub(a, b) = a - b",
+ "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+ "emit" => '. SUB %D1, %S1, %S2\t\t\t/* Sub(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+"Sub_i" => {
+ "irn_flags" => "R",
+ "comment" => "construct Sub: Sub(a, const) = a - const",
+ "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+ "emit" => '. SUB %D1, %S1, %C\t\t\t/* Sub(%S1, %C) -> %D1, (%A1, const) */',
+ "cmp_attr" =>
+' if (attr_a->value == NULL || attr_b->value == NULL)
+ return 1;
+
+ return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
+'
+},
+
+"Shl" => {
+ "irn_flags" => "R",
+ "comment" => "construct Shl: Shl(a, b) = a << b",
+ "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+ "emit" => '. MOV %D1, %S1, LSL %S2\t/* Shl(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+"Shl_i" => {
+ "irn_flags" => "R",
+ "comment" => "construct Shl: Shl(a, const) = a << const",
+ "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+ "emit" => '. MOV %D1, %S1, LSL %C\t\t\t/* Shl(%S1, %C) -> %D1, (%A1, const) */',
+ "cmp_attr" =>
+' if (attr_a->value == NULL || attr_b->value == NULL)
+ return 1;
+
+ return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
+'
+},
+
+"Shr" => {
+ "irn_flags" => "R",
+ "comment" => "construct Shr: Shr(a, b) = a >> b",
+ "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "in_r1" ] },
+ "emit" => '. MOV %D1, %S1, LSR %S2\t\t\t/* Shr(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+"Shr_i" => {
+ "irn_flags" => "R",
+ "comment" => "construct Shr: Shr(a, const) = a >> const",
+ "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+ "emit" => '. MOV %D1, %S1, LSR %C\t\t\t/* Shr(%S1, %C) -> %D1, (%A1, const) */',
+ "cmp_attr" =>
+' if (attr_a->value == NULL || attr_b->value == NULL)
+ return 1;
+
+ return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
+'
+},
+
+"Shrs" => {
+ "irn_flags" => "R",
+ "comment" => "construct Shrs: Shrs(a, b) = a >> b",
+ "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "in_r1" ] },
+ "emit" => '. MOV %D1, %S1, ASR %S2\t\t\t\t\t/* Shrs(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+"Shrs_i" => {
+ "irn_flags" => "R",
+ "comment" => "construct Shrs: Shrs(a, const) = a >> const",
+ "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+ "emit" => '. MOV %D1, %S1, ASR %C\t\t\t/* Shrs(%S1, %C) -> %D1, (%A1, const) */',
+ "cmp_attr" =>
+' if (attr_a->value == NULL || attr_b->value == NULL)
+ return 1;
+
+ return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
+'
+},
+
+#"Div" => {
+# "irn_flags" => "R",
+# "comment" => "construct Div: Div(a, b) = a / b",
+# "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+# "emit" =>'. div %S1, %S2, %D1\t\t\t/* div(%S1, %S2) -> %D1, (%A1, %A2) */'
+#},
+#
+#"Div_i" => {
+# "irn_flags" => "R",
+# "comment" => "construct Div: Div(a, const) = a / const",
+# "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+# "emit" => '. div %S1, %C, %D1\t\t\t/* signed div(%C, %S1) -> %D1, (%A1, const) */'
+#},
+#
+#"Mod" => {
+# "irn_flags" => "R",
+# "comment" => "construct Mod: Mod(a, b) = a % b",
+# "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+# "emit" =>'. mod %S1, %S2, %D1\t\t\t/* mod(%S1, %S2) -> %D1, (%A1, %A2) */'
+#},
+#
+#"Mod_i" => {
+# "irn_flags" => "R",
+# "comment" => "construct mod: Mod(a, const) = a % const",
+# "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+# "emit" => '. mod %S1, %C, %D1\t\t\t/* mod(%C, %S1) -> %D1, (%A1, const) */'
+#},
+#
+#"DivMod" => {
+# "irn_flags" => "R",
+# "comment" => "construct DivMod: DivMod(a, b) = a / b",
+# "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+# "emit" =>'. div %S1, %S2, %D1\t\t\t/* div(%S1, %S2) -> %D1, (%A1, %A2) */'
+#},
+#
+#"Div_i" => {
+# "irn_flags" => "R",
+# "comment" => "construct DivMod: DivMod(a, const) = a / const",
+# "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+# "emit" => '. div %S1, %C, %D1\t\t\t/* signed div(%C, %S1) -> %D1, (%A1, const) */'
+#},
+
+#"RotR" => {
+# "irn_flags" => "R",
+# "comment" => "construct RotR: RotR(a, b) = a ROTR b",
+# "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+# "emit" => '. MOV %D1, %S1, ROR %S2\t\t\t/* RotR(%S1, %S2) -> %D1, (%A1, %A2) */'
+## "emit" => '. ror %S1, %S2, %D1\t\t\t/* RotR(%S1, %S2) -> %D1, (%A1, %A2) */'
+#},
+
+#"RotL" => {
+# "irn_flags" => "R",
+# "comment" => "construct RotL: RotL(a, b) = a ROTL b",
+# "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+# "emit" => '. rol %S1, %S2, %D1\t\t\t/* RotL(%S1, %S2) -> %D1, (%A1, %A2) */'
+#},
+
+#"RotL_i" => {
+# "irn_flags" => "R",
+# "comment" => "construct RotL: RotL(a, const) = a ROTL const",
+# "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+# "emit" => '. rol %S1, %C, %D1\t\t\t/* RotL(%S1, %C) -> %D1, (%A1, const) */'
+#},
+
+"Minus" => {
+ "irn_flags" => "R",
+ "comment" => "construct Minus: Minus(a) = -a",
+ "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+ "emit" => '. RSB %D1, %S1, #0\t\t\t/* Neg(%S1) -> %D1, (%A1) */'
+},
+
+#"Inc" => {
+# "irn_flags" => "R",
+# "comment" => "construct Increment: Inc(a) = a++",
+# "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+# "emit" => '. inc %S1, %D1\t\t\t/* Inc(%S1) -> %D1, (%A1) */'
+#},
+#
+#"Dec" => {
+# "irn_flags" => "R",
+# "comment" => "construct Decrement: Dec(a) = a--",
+# "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+# "emit" => '. dec %S1, %D1\t\t\t/* Dec(%S1) -> %D1, (%A1) */'
+#},
+
+"Not" => {
+ "arity" => 1,
+# "remat" => 1,
+ "irn_flags" => "R",
+ "comment" => "construct Not: Not(a) = !a",
+ "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+ "emit" => '. MVN %D1, %S1\t\t\t/* Not(%S1) -> %D1, (%A1) */'
+},
+
+"Abs" => {
+ "irn_flags" => "R",
+ "comment" => "construct Abs: Abs(a) = |a|",
+ "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+ "emit" =>
+'. MOVS %S1, %S1, #0\t\t\t/* set condition flag */\n
+. RSBMI %D1, %S1, #0\t\t\t/* Neg(%S1) -> %D1, (%A1) */'
+},
+
+# other operations
+
+"EmptyReg" => {
+ "op_flags" => "c",
+ "irn_flags" => "R",
+ "comment" => "just to get an emptz register for calculations",
+ "reg_req" => { "out" => [ "general_purpose" ] },
+ "emit" => '. /* %D1 now available for calculations */',
+ "cmp_attr" => 'return 1;'
+},
+
+"Copy" => {
+ "comment" => "implements a register copy",
+ "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+},
+
+"CopyB" => {
+ "op_flags" => "F|H",
+ "state" => "pinned",
+ "comment" => "implements a memcopy: CopyB(dst, src, size, mem) == memcpy(dst, src, size)",
+ "reg_req" => { "in" => [ "!r13", "!r13", "general_purpose", "general_purpose", "general_purpose", "none" ], "out" => [ "none" ] },
+},
+
+"Const" => {
+ "irn_flags" => "R",
+ "comment" => "represents an integer constant",
+ "reg_req" => { "out" => [ "general_purpose" ] },
+ "emit" => '. MOV %D1, %C \t\t\t/* Mov Const into register */',
+ "cmp_attr" =>
+' if (attr_a->value == NULL || attr_b->value == NULL)
+ return 1;
+
+ return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
+'
+},
+
+"Const_Neg" => {
+ "irn_flags" => "R",
+ "comment" => "represents a negated integer constant",
+ "reg_req" => { "out" => [ "general_purpose" ] },
+ "emit" => '. MVN %D1, %C \t\t\t/* Mov negated Const into register */',
+ "cmp_attr" =>
+' if (attr_a->value == NULL || attr_b->value == NULL)
+ return 1;
+
+ return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
+'
+},
+
+"SymConst" => {
+ "op_flags" => "c",
+ "irn_flags" => "R",
+ "comment" => "represents a symbolic constant",
+ "reg_req" => { "out" => [ "general_purpose" ] },
+# "emit" => '. LDR %D1, %C\t\t\t/* Mov Const into register */',
+ "cmp_attr" =>
+' if (attr_a->value == NULL || attr_b->value == NULL)
+ return 1;
+
+ return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
+'
+},
+
+"CondJmp" => {
+ "op_flags" => "L|X|Y",
+ "comment" => "construct conditional jump: CMP A, B && JMPxx LABEL",
+ "cmp_attr" => " return arm_comp_condJmp(attr_a, attr_b);\n",
+ "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "none", "none"] },
+},
+
+"SwitchJmp" => {
+ "op_flags" => "L|X|Y",
+ "comment" => "construct switch",
+ "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "none" ] },
+ "cmp_attr" => " return 0;\n",
+},
+
+# Load / Store
+
+"Load" => {
+ "op_flags" => "L|F",
+ "irn_flags" => "R",
+ "state" => "exc_pinned",
+ "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg",
+ "reg_req" => { "in" => [ "general_purpose", "none" ], "out" => [ "general_purpose" ] },
+ "emit" => '. LDR %D1, [%S1, #0]\t\t\t/* Load((%S1)) -> %D1, (%A1) */'
+# "emit" => '. LDR %D1, %S1, %O\t\t\t/* Load((%S1)) -> %D1, (%A1) */'
+},
+
+"Loadb" => {
+ "op_flags" => "L|F",
+ "irn_flags" => "R",
+ "state" => "exc_pinned",
+ "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg",
+ "reg_req" => { "in" => [ "general_purpose", "none" ], "out" => [ "general_purpose" ] },
+ "emit" => '. LDRB %D1, [%S1, #0]\t\t\t/* Load((%S1)) -> %D1, (%A1) */'
+# "emit" => '. LDRB %D1, %S1, %O\t\t\t/* Load((%S1)) -> %D1, (%A1) */'
+},
+
+"Loadbs" => {
+ "op_flags" => "L|F",
+ "irn_flags" => "R",
+ "state" => "exc_pinned",
+ "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg",
+ "reg_req" => { "in" => [ "general_purpose", "none" ], "out" => [ "general_purpose" ] },
+ "emit" => '. LDRSB %D1, [%S1, #0]\t\t\t/* Load((%S1)) -> %D1, (%A1) */'
+# "emit" => '. LDRSB %D1, %S1, %O\t\t\t/* Load((%S1)) -> %D1, (%A1) */'
+},
+
+"Loadh" => {
+ "op_flags" => "L|F",
+ "irn_flags" => "R",
+ "state" => "exc_pinned",
+ "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg",
+ "reg_req" => { "in" => [ "general_purpose", "none" ], "out" => [ "general_purpose" ] },
+ "emit" => '. LDRH %D1, [%S1, #0]\t\t\t/* Load((%S1)) -> %D1, (%A1) */'
+# "emit" => '. LDRH %D1, %S1, %O\t\t\t/* Load((%S1)) -> %D1, (%A1) */'
+},
+
+"Loadhs" => {
+ "op_flags" => "L|F",
+ "irn_flags" => "R",
+ "state" => "exc_pinned",
+ "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg",
+ "reg_req" => { "in" => [ "general_purpose", "none" ], "out" => [ "general_purpose" ] },
+ "emit" => '. LDRSH %D1, [%S1, #0]\t\t\t/* Load((%S1)) -> %D1, (%A1) */'
+# "emit" => '. LDRSH %D1, %S1, %O\t\t\t/* Load((%S1)) -> %D1, (%A1) */'
+},
+
+"Storeb" => {
+ "op_flags" => "L|F",
+ "irn_flags" => "R",
+ "state" => "exc_pinned",
+ "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val",
+ "reg_req" => { "in" => [ "general_purpose", "general_purpose", "none" ] },
+ "emit" => '. STRB %S2, [%S1, #0]\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
+# "emit" => '. movl %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
+},
+
+"Storebs" => {
+ "op_flags" => "L|F",
+ "irn_flags" => "R",
+ "state" => "exc_pinned",
+ "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val",
+ "reg_req" => { "in" => [ "general_purpose", "general_purpose", "none" ] },
+ "emit" => '. STRSB %S2, [%S1, #0]\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
+# "emit" => '. movl %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
+},
+
+"Storeh" => {
+ "op_flags" => "L|F",
+ "irn_flags" => "R",
+ "state" => "exc_pinned",
+ "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val",
+ "reg_req" => { "in" => [ "general_purpose", "general_purpose", "none" ] },
+ "emit" => '. STRH %S2, [%S1, #0]\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
+# "emit" => '. movl %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
+},
+
+"Storehs" => {
+ "op_flags" => "L|F",
+ "irn_flags" => "R",
+ "state" => "exc_pinned",
+ "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val",
+ "reg_req" => { "in" => [ "general_purpose", "general_purpose", "none" ] },
+ "emit" => '. STRSH%S2, [%S1, #0]\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
+# "emit" => '. movl %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
+},
+
+"Store" => {
+ "op_flags" => "L|F",
+ "irn_flags" => "R",
+ "state" => "exc_pinned",
+ "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val",
+ "reg_req" => { "in" => [ "general_purpose", "general_purpose", "none" ] },
+ "emit" => '. STR %S2, [%S1, #0]\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
+# "emit" => '. movl %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
+},
+
+"StoreStackM4Inc" => {
+ "op_flags" => "L|F",
+ "irn_flags" => "R",
+ "state" => "exc_pinned",
+ "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val",
+ "reg_req" => { "in" => [ "r13", "general_purpose", "general_purpose", "general_purpose", "general_purpose", "none" ], "out" => [ "general_purpose", "none" ] },
+ "emit" => '. STMFD %S1!, {%S2, %S3, %S4, %S5}\t\t\t/* Store multiple on Stack*/'
+},
+
+"LoadStackM3" => {
+ "op_flags" => "L|F",
+ "irn_flags" => "R",
+ "state" => "exc_pinned",
+ "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg",
+ "reg_req" => { "in" => [ "r13", "none" ], "out" => [ "general_purpose", "general_purpose", "general_purpose", "none" ] },
+ "emit" => '. LDMFD %S1, {%D1, %D2, %D3}\t\t\t/* Load multiple from Stack */'
+},
+
+
+
+
+
+
+
+
+#--------------------------------------------------------#
+# __ _ _ _ #
+# / _| | | | | | #
+# | |_| | ___ __ _| |_ _ __ ___ __| | ___ ___ #
+# | _| |/ _ \ / _` | __| | '_ \ / _ \ / _` |/ _ \/ __| #
+# | | | | (_) | (_| | |_ | | | | (_) | (_| | __/\__ \ #
+# |_| |_|\___/ \__,_|\__| |_| |_|\___/ \__,_|\___||___/ #
+#--------------------------------------------------------#
+
+# commutative operations
+
+"fAddd" => {
+ "op_flags" => "C",
+ "irn_flags" => "R",
+ "comment" => "construct DP FP Add: Add(a, b) = Add(b, a) = a + b",
+ "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
+ "emit" => '. FADDD %D1, %S1, %S2\t\t\t/* FP Add(%S1, %S2) -> %D1 */'
+},
+
+"fAdds" => {
+ "op_flags" => "C",
+ "irn_flags" => "R",
+ "comment" => "construct SP FP Add: Add(a, b) = Add(b, a) = a + b",
+ "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
+ "emit" => '. FADDS %D1, %S1, %S2\t\t\t/* FP Add(%S1, %S2) -> %D1 */'
+},
+
+"fMuls" => {
+ "op_flags" => "C",
+ "comment" => "construct FP Mul: Mul(a, b) = Mul(b, a) = a * b",
+ "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
+ "emit" =>'. FMULS %D1, %S1, %S2\t\t\t/* FP Mul(%S1, %S2) -> %D1 */'
+},
+
+"fMuld" => {
+ "op_flags" => "C",
+ "comment" => "construct FP Mul: Mul(a, b) = Mul(b, a) = a * b",
+ "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
+ "emit" =>'. FMULD %D1, %S1, %S2\t\t\t/* FP Mul(%S1, %S2) -> %D1 */'
+},
+
+"fDivs" => {
+ "comment" => "construct FP Div: Div(a, b) = a / b",
+ "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
+ "emit" =>'. FDIVS %D1, %S1, %S2\t\t\t/* FP Div(%S1, %S2) -> %D1 */'
+},
+
+"fDivd" => {
+ "comment" => "construct FP Div: Div(a, b) = a / b",
+ "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
+ "emit" =>'. FDIVD %D1, %S1, %S2\t\t\t/* FP Div(%S1, %S2) -> %D1 */'
+},
+
+"fDiv" => {
+ "comment" => "construct FP Div: Div(a, b) = a / b",
+ "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
+ "emit" =>'. FDIV %D1, %S1, %S2\t\t\t/* FP Div(%S1, %S2) -> %D1 */'
+},
+
+"fMax" => {
+ "op_flags" => "C",
+ "irn_flags" => "R",
+ "comment" => "construct FP Max: Max(a, b) = Max(b, a) = a > b ? a : b",
+ "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
+ "emit" =>'. fmax %S1, %S2, %D1\t\t\t/* FP Max(%S1, %S2) -> %D1 */'
+},
+
+"fMin" => {
+ "op_flags" => "C",
+ "irn_flags" => "R",
+ "comment" => "construct FP Min: Min(a, b) = Min(b, a) = a < b ? a : b",
+ "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
+ "emit" =>'. fmin %S1, %S2, %D1\t\t\t/* FP Min(%S1, %S2) -> %D1 */'
+},
+
+# not commutative operations
+
+"fSubs" => {
+ "irn_flags" => "R",
+ "comment" => "construct FP Sub: Sub(a, b) = a - b",
+ "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
+ "emit" => '. FSUBS %D1, %S1, %S2\t\t\t/* FP Sub(%S1, %S2) -> %D1 */'
+},
+
+"fSubd" => {
+ "irn_flags" => "R",
+ "comment" => "construct FP Sub: Sub(a, b) = a - b",
+ "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
+ "emit" => '. FSUBD %D1, %S1, %S2\t\t\t/* FP Sub(%S1, %S2) -> %D1 */'
+},
+
+"fMinus" => {
+ "irn_flags" => "R",
+ "comment" => "construct FP Minus: Minus(a) = -a",
+ "reg_req" => { "in" => [ "floating_point" ], "out" => [ "floating_point" ] },
+ "emit" => '. fneg %S1, %D1\t\t\t/* FP Minus(%S1) -> %D1 */'
+},
+
+"fAbss" => {
+ "irn_flags" => "R",
+ "comment" => "construct FP Absolute value: fAbss(a) = |a|",
+ "reg_req" => { "in" => [ "floating_point" ], "out" => [ "floating_point" ] },
+ "emit" => '. FABSS %D1, %S1\t\t\t/* FP Abss(%S1) -> %D1 */'
+},
+
+"fAbsd" => {
+ "irn_flags" => "R",
+ "comment" => "construct FP Absolute value: fAbsd(a) = |a|",
+ "reg_req" => { "in" => [ "floating_point" ], "out" => [ "floating_point" ] },
+ "emit" => '. FABSD %D1, %S1\t\t\t/* FP Absd(%S1) -> %D1 */'
+},
+
+# other operations
+
+"fConst" => {
+ "op_flags" => "c",
+ "irn_flags" => "R",
+ "comment" => "represents a FP constant",
+ "reg_req" => { "out" => [ "floating_point" ] },
+ "emit" => '. FMOV %D1, %C\t\t\t/* Mov fConst into register */',
+ "cmp_attr" =>
+' if (attr_a->value == NULL || attr_b->value == NULL)
+ return 1;
+
+ return get_tarval_double(attr_a->value) != get_tarval_double(attr_b->value);'
+},
+
+"fConvD2S" => {
+ "irn_flags" => "R",
+ "comment" => "convert double to single",
+ "reg_req" => { "in" => [ "floating_point" ], "out" => [ "floating_point" ] },
+ "emit" => '. FCVTSD %D1, %S1\t\t\t/* Convert double to single */',
+},
+
+"fConvS2D" => {
+ "irn_flags" => "R",
+ "comment" => "convert single to double",
+ "reg_req" => { "in" => [ "floating_point" ], "out" => [ "floating_point" ] },
+ "emit" => '. FCVTDS %D1, %S1\t\t\t/* Convert single to double */',
+},
+
+
+# Load / Store
+
+"fLoads" => {
+ "op_flags" => "L|F",
+ "irn_flags" => "R",
+ "state" => "exc_pinned",
+ "comment" => "construct FP Load: Load(ptr, mem) = LD ptr",
+ "reg_req" => { "in" => [ "general_purpose", "none" ], "out" => [ "floating_point" ] },
+ "emit" => '. FLDS %D1, %S1\t\t\t/* Load((%S1)) -> %D1 */'
+# "emit" => '. fmov %O(%S1), %D1\t\t\t/* Load((%S1)) -> %D1 */'
+},
+
+"fLoadd" => {
+ "op_flags" => "L|F",
+ "irn_flags" => "R",
+ "state" => "exc_pinned",
+ "comment" => "construct FP Load: Load(ptr, mem) = LD ptr",
+ "reg_req" => { "in" => [ "general_purpose", "none" ], "out" => [ "floating_point" ] },
+ "emit" => '. FLDD %D1, %S1\t\t\t/* Load((%S1)) -> %D1 */'
+# "emit" => '. fmov %O(%S1), %D1\t\t\t/* Load((%S1)) -> %D1 */'
+},
+
+"fStores" => {
+ "op_flags" => "L|F",
+ "irn_flags" => "R",
+ "state" => "exc_pinned",
+ "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val",
+ "reg_req" => { "in" => [ "general_purpose", "floating_point", "none" ] },
+ "emit" => '. FSTS %S2, %S1\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
+},
+
+"fStored" => {
+ "op_flags" => "L|F",
+ "irn_flags" => "R",
+ "state" => "exc_pinned",
+ "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val",
+ "reg_req" => { "in" => [ "general_purpose", "floating_point", "none" ] },
+ "emit" => '. FSTD %S2, %S1\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
+},
+
+); # end of %nodes
--- /dev/null
+/* The codegenrator (transform FIRM into arm FIRM */
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "irnode_t.h"
+#include "irgraph_t.h"
+#include "irmode_t.h"
+#include "irgmod.h"
+#include "iredges.h"
+#include "irvrfy.h"
+#include "ircons.h"
+#include "dbginfo.h"
+#include "iropt_t.h"
+#include "debug.h"
+
+#include "../benode_t.h"
+#include "bearch_arm_t.h"
+
+#include "arm_nodes_attr.h"
+#include "../arch/archop.h" /* we need this for Min and Max nodes */
+#include "arm_transform.h"
+#include "arm_new_nodes.h"
+#include "arm_map_regs.h"
+
+#include "gen_arm_regalloc_if.h"
+
+#include <limits.h>
+
+extern ir_op *get_op_Mulh(void);
+
+
+
+/****************************************************************************************************
+ * _ _ __ _ _
+ * | | | | / _| | | (_)
+ * _ __ ___ __| | ___ | |_ _ __ __ _ _ __ ___| |_ ___ _ __ _ __ ___ __ _| |_ _ ___ _ __
+ * | '_ \ / _ \ / _` |/ _ \ | __| '__/ _` | '_ \/ __| _/ _ \| '__| '_ ` _ \ / _` | __| |/ _ \| '_ \
+ * | | | | (_) | (_| | __/ | |_| | | (_| | | | \__ \ || (_) | | | | | | | | (_| | |_| | (_) | | | |
+ * |_| |_|\___/ \__,_|\___| \__|_| \__,_|_| |_|___/_| \___/|_| |_| |_| |_|\__,_|\__|_|\___/|_| |_|
+ *
+ ****************************************************************************************************/
+
+
+
+
+
+typedef struct vals_ {
+ int ops;
+ unsigned char values[4];
+ unsigned char shifts[4];
+} vals;
+
+static vals construct_vals() {
+ vals result = {0, {0, 0, 0, 0}, {0, 0, 0, 0}};
+ return result;
+}
+
+static vals gen_vals_from_word(unsigned int value)
+{
+ vals result = construct_vals();
+ int cur_offset = 0;
+ while (value != 0) {
+ if ((value & 3) == 0) {
+ cur_offset += 2;
+ value >>= 2;
+ } else {
+ result.values[result.ops] = value & 0xff;
+ result.shifts[result.ops] = cur_offset;
+ ++result.ops;
+ value >>= 8;
+ cur_offset += 8;
+ }
+ }
+ return result;
+}
+
+static ir_node *create_const_node(arm_transform_env_t *env, int value) {
+ ir_node *result = new_rd_arm_Const(env->dbg, env->irg, env->block, env->mode);
+ get_arm_attr(result)->value = new_tarval_from_long(value, env->mode);
+ return result;
+}
+
+#define NEW_BINOP_NODE(opname, env, op1, op2) new_rd_arm_##opname(env->dbg, env->irg, env->block, op1, op2, env->mode)
+
+unsigned int create_shifter_operand(unsigned int shift, unsigned int immediate) {
+ return immediate | ((shift>>1)<<8);
+}
+
+static ir_node *create_const_graph_value(arm_transform_env_t *env, unsigned int value) {
+ ir_node *result;
+ int negate = 0;
+
+ if (value < 0x100 || ~value < 0x100 ) {
+ if ( ~value < 0x100 ) {
+ negate = 1;
+ value = ~value;
+ }
+ result = create_const_node(env, value);
+ } else {
+ vals v;
+ vals v1 = gen_vals_from_word(value);
+ vals v2 = gen_vals_from_word(~value);
+ int cnt = 0;
+ if (v2.ops == 1) {
+ result = new_rd_arm_Const_Neg(env->dbg, env->irg, env->block, env->mode);
+ set_arm_value(result, new_tarval_from_long(create_shifter_operand(v2.shifts[0], v2.values[0]), mode_Iu));
+ } else {
+ if ( v2.ops < v1.ops ) {
+ negate = 1;
+ v = v2;
+ } else {
+ v = v1;
+ }
+ if (v.shifts[cnt] == 0) {
+ result = create_const_node(env, v.values[cnt]);
+ } else {
+ result = create_const_node(env, create_shifter_operand(v.shifts[cnt], v.values[cnt]));
+ }
+ ++cnt;
+ while(cnt < v.ops) {
+ ir_node *const_node = create_const_node(env, v.values[cnt]);
+ ir_node *orr_i_node = new_rd_arm_Or_i(env->dbg, env->irg, env->block, result, env->mode);
+ set_arm_value(orr_i_node, new_tarval_from_long(create_shifter_operand(v.shifts[cnt], v.values[cnt]), mode_Iu));
+ result = orr_i_node;
+ ++cnt;
+ }
+ }
+ }
+ if ( negate ) {
+ result = new_rd_arm_Not(env->dbg, env->irg, env->block, result, env->mode);
+ }
+ return result;
+}
+
+// static ir_node *create_const_graph_value(arm_transform_env_t *env, unsigned int value) {
+// ir_node *irn = env->irn;
+// ir_node *result;
+// int negate = 0;
+//
+// if ( ~value < 0x100 ) {
+// negate = 1;
+// value = ~value;
+// }
+//
+// if (value < 0x100) {
+// return create_const_node(env, value);
+// } else {
+// vals v = gen_vals_from_word(value);
+// int cnt = 0;
+// ir_node *mov_val = create_const_node(env, v.values[cnt]);
+// if (v.shifts[cnt] != 0) {
+// ir_node *shift_node = new_rd_arm_Shl_i(env->dbg, env->irg, env->block, mov_val, env->mode);
+// set_arm_value(shift_node, new_tarval_from_long(v.shifts[cnt], mode_Iu));
+// result = shift_node;
+// } else {
+// result = mov_val;
+// }
+// ++cnt;
+// while(cnt < v.ops) {
+// ir_node *const_node = create_const_node(env, v.values[cnt]);
+// ir_node *orr_i_node = new_rd_arm_Or_i(env->dbg, env->irg, env->block, result, env->mode);
+// unsigned shift = v.shifts[cnt];
+// unsigned immediate = v.values[cnt];
+// unsigned immediate_with_shift = immediate | ((shift>>1)<<8);
+// set_arm_value(orr_i_node, new_tarval_from_long(immediate_with_shift, mode_Iu));
+// result = orr_i_node;
+// ++cnt;
+// }
+// return result;
+// }
+// }
+
+static ir_node *create_const_graph(arm_transform_env_t *env) {
+ int value = get_tarval_long(get_Const_tarval(env->irn));
+ return create_const_graph_value(env, value);
+}
+
+
+
+static ir_node *gen_Const(arm_transform_env_t *env) {
+ ir_node *result;
+ assert(env->mode != mode_E && "IEEE Extended FP not supported");
+ if (env->mode == mode_F) {
+ result = new_rd_arm_fConst(env->dbg, env->irg, env->block, env->mode);
+ get_arm_attr(result)->value = get_Const_tarval(env->irn);
+ } else if (env->mode == mode_D) {
+ result = new_rd_arm_fConst(env->dbg, env->irg, env->block, env->mode);
+ get_arm_attr(result)->value = get_Const_tarval(env->irn);
+ } else if (env->mode == mode_P) {
+ return env->irn;
+ } else {
+ result = create_const_graph(env);
+ }
+ return result;
+}
+
+static ir_node *gen_mask(arm_transform_env_t *env, ir_node *op, int result_bits) {
+ unsigned mask_bits = (1 << result_bits) - 1;
+ ir_node *mask_node = create_const_graph_value(env, mask_bits);
+ return new_rd_arm_And(env->dbg, env->irg, env->block, op, mask_node, get_irn_mode(env->irn));
+}
+
+static ir_node *gen_sign_extension(arm_transform_env_t *env, ir_node *op, int result_bits) {
+ int shift_width = 32 - result_bits;
+ ir_node *shift_const_node = create_const_graph_value(env, shift_width);
+ ir_node *lshift_node = new_rd_arm_Shl(env->dbg, env->irg, env->block, op, shift_const_node, get_irn_mode(op));
+ ir_node *rshift_node = new_rd_arm_Shrs(env->dbg, env->irg, env->block, lshift_node, shift_const_node, get_irn_mode(env->irn));
+ return rshift_node;
+}
+
+static ir_node *gen_Conv(arm_transform_env_t *env, ir_node *op) {
+ ir_mode *in_mode = get_irn_mode(op);
+ ir_mode *out_mode = env->mode;
+
+ assert( in_mode != mode_E && "");
+ assert( in_mode != mode_Ls && "");
+ assert( in_mode != mode_Lu && "");
+ assert( out_mode != mode_E && "");
+ assert( out_mode != mode_Ls && "");
+ assert( out_mode != mode_Lu && "");
+
+ if (in_mode == out_mode)
+ return op;
+
+ if ((mode_is_int(in_mode) || mode_is_reference(in_mode))
+ && (mode_is_reference(out_mode) || mode_is_int(out_mode))) {
+ int in_bits = get_mode_size_bits(in_mode);
+ int out_bits = get_mode_size_bits(out_mode);
+ int in_sign = get_mode_sign(in_mode);
+ int out_sign = get_mode_sign(out_mode);
+
+ // 32 -> 32
+ // NOPpen
+ if (in_bits == out_bits && in_bits == 32)
+ return op;
+
+ // 16 -> 16
+ // unsigned -> unsigned
+ // NOP
+ // unsigned -> signed
+ // sign extension (31:16)=(15)
+ // signed -> unsigned
+ // maskieren (31:16)=0
+ // signed -> signed
+ // NOP
+ if (in_bits == out_bits && out_bits < 32) {
+ if (in_sign && !out_sign) {
+ return gen_mask(env, op, out_bits);
+ } else {
+ return gen_sign_extension(env, op, out_bits);
+ }
+ }
+
+ // 16 -> 32
+ // unsigned -> unsigned
+ // NOP
+ // unsigned -> signed
+ // NOP
+ // signed -> unsigned
+ // sign extension (31:16)=(15)
+ // signed -> signed
+ // sign extension (31:16)=(15)
+ if (in_bits < out_bits) {
+ if (in_sign) {
+ return gen_sign_extension(env, op, out_bits);
+ } else {
+ return op;
+ }
+ }
+
+ // 32 -> 16
+ // unsigned -> unsigned
+ // maskieren (31:16)=0
+ // unsigned -> signed
+ // maskieren (31:16)=0
+ // signed -> unsigned
+ // maskieren (31:16)=0
+ // signed -> signed
+ // sign extension (erledigt auch maskieren) (31:16)=(15)
+ if (in_bits > out_bits) {
+ if (in_sign && out_sign) {
+ return gen_sign_extension(env, op, out_bits);
+ } else {
+ return gen_mask(env, op, out_bits);
+ }
+ }
+ assert(0 && "recheck integer conversion logic!");
+ return env->irn;
+ } else if (in_mode == mode_D && out_mode == mode_F) {
+ return new_rd_arm_fConvD2S(env->dbg, env->irg, env->block, op, env->mode);
+ } else if (in_mode == mode_F && out_mode == mode_D) {
+ return new_rd_arm_fConvS2D(env->dbg, env->irg, env->block, op, env->mode);
+ } else if (mode_is_int(in_mode) && mode_is_float(out_mode)) {
+ return env->irn; /* TODO: implement int->float conversion*/
+ } else if (mode_is_float(in_mode) && mode_is_int(out_mode)) {
+ return env->irn; /* TODO: implement float->int conversion*/
+ } else {
+ assert(0 && "not implemented conversion");
+ return env->irn;
+ }
+}
+
+
+/**
+ * Creates an arm Add.
+ *
+ * @param env The transformation environment
+ * @param op1 first operator
+ * @param op2 second operator
+ * @return the created arm Add node
+ */
+static ir_node *gen_Add(arm_transform_env_t *env, ir_node *op1, ir_node *op2) {
+ ir_node *result = NULL;
+ assert(!mode_is_float(env->mode) || (get_irn_mode(op1)->sort == get_irn_mode(op2)->sort));
+ assert(env->mode != mode_E && "IEEE Extended FP not supported");
+
+ if (env->mode == mode_F) {
+ result = new_rd_arm_fAdds(env->dbg, env->irg, env->block, op1, op2, env->mode);
+ } else if (env->mode == mode_D) {
+ result = new_rd_arm_fAddd(env->dbg, env->irg, env->block, op1, op2, env->mode);
+ } else if (mode_is_numP(env->mode)) {
+ if (is_arm_Const(op1)) {
+ result = new_rd_arm_Add_i(env->dbg, env->irg, env->block, op2, env->mode);
+ set_arm_value(result, get_arm_value(op1));
+ } else if (is_arm_Const(op2)) {
+ result = new_rd_arm_Add_i(env->dbg, env->irg, env->block, op1, env->mode);
+ set_arm_value(result, get_arm_value(op2));
+ } else {
+ result = new_rd_arm_Add(env->dbg, env->irg, env->block, op1, op2, env->mode);
+ }
+ } else {
+ assert(0 && "unknown mode for add");
+ }
+ return result;
+}
+
+
+
+/**
+ * Creates an arm Mul.
+ *
+ * @param dbg firm node dbg
+ * @param block the block the new node should belong to
+ * @param op1 first operator
+ * @param op2 second operator
+ * @param mode node mode
+ * @return the created arm Mul node
+ */
+static ir_node *gen_Mul(arm_transform_env_t *env, ir_node *op1, ir_node *op2) {
+ assert(!mode_is_float(env->mode) || (get_irn_mode(op1)->sort == get_irn_mode(op2)->sort));
+ assert(env->mode != mode_E && "IEEE Extended FP not supported");
+
+ if (env->mode == mode_F) {
+ return new_rd_arm_fMuls(env->dbg, env->irg, env->block, op1, op2, env->mode);
+ }
+ if (env->mode == mode_D) {
+ return new_rd_arm_fMuld(env->dbg, env->irg, env->block, op1, op2, env->mode);
+ }
+ return new_rd_arm_Mul(env->dbg, env->irg, env->block, op1, op2, env->mode);
+}
+
+
+/**
+ * Creates an arm floating Div.
+ *
+ * @param dbg firm node dbg
+ * @param block the block the new node should belong to
+ * @param op1 first operator
+ * @param op2 second operator
+ * @param mode node mode
+ * @return the created arm fDiv node
+ */
+static ir_node *gen_Quot(arm_transform_env_t *env, ir_node *op1, ir_node *op2) {
+ // assert(mode_is_float(env->mode) && "only floating point supported");
+ assert(get_irn_mode(op1)->sort == get_irn_mode(op2)->sort);
+ assert(mode_is_float(get_irn_mode(op1)));
+ assert(get_irn_mode(op1) != mode_E && "IEEE Extended FP not supported");
+
+ if (get_irn_mode(op1) == mode_F) {
+ return new_rd_arm_fDivs(env->dbg, env->irg, env->block, op1, op2, env->mode);
+ }
+ return new_rd_arm_fDivd(env->dbg, env->irg, env->block, op1, op2, env->mode);
+}
+
+
+/**
+ * Creates an arm And.
+ *
+ * @param dbg firm node dbg
+ * @param block the block the new node should belong to
+ * @param op1 first operator
+ * @param op2 second operator
+ * @param mode node mode
+ * @return the created arm And node
+ */
+static ir_node *gen_And(arm_transform_env_t *env, ir_node *op1, ir_node *op2) {
+ ir_node *result;
+ if (is_arm_Const(op1)) {
+ result = new_rd_arm_And_i(env->dbg, env->irg, env->block, op2, env->mode);
+ set_arm_value(result, get_arm_value(op1));
+ } else if (is_arm_Const(op2)) {
+ result = new_rd_arm_And_i(env->dbg, env->irg, env->block, op1, env->mode);
+ set_arm_value(result, get_arm_value(op2));
+ } else {
+ result = new_rd_arm_And(env->dbg, env->irg, env->block, op1, op2, env->mode);
+ }
+ return result;
+}
+
+
+
+/**
+ * Creates an arm Or.
+ *
+ * @param dbg firm node dbg
+ * @param block the block the new node should belong to
+ * @param op1 first operator
+ * @param op2 second operator
+ * @param mode node mode
+ * @return the created arm Or node
+ */
+static ir_node *gen_Or(arm_transform_env_t *env, ir_node *op1, ir_node *op2) {
+ ir_node *result;
+ if (is_arm_Const(op1)) {
+ result = new_rd_arm_Or_i(env->dbg, env->irg, env->block, op2, env->mode);
+ set_arm_value(result, get_arm_value(op1));
+ } else if (is_arm_Const(op2)) {
+ result = new_rd_arm_Or_i(env->dbg, env->irg, env->block, op1, env->mode);
+ set_arm_value(result, get_arm_value(op2));
+ } else {
+ result = new_rd_arm_Or(env->dbg, env->irg, env->block, op1, op2, env->mode);
+ }
+ return result;
+}
+
+
+
+/**
+ * Creates an arm Eor.
+ *
+ * @param dbg firm node dbg
+ * @param block the block the new node should belong to
+ * @param op1 first operator
+ * @param op2 second operator
+ * @param mode node mode
+ * @return the created arm Eor node
+ */
+static ir_node *gen_Eor(arm_transform_env_t *env, ir_node *op1, ir_node *op2) {
+ ir_node *result;
+ if (is_arm_Const(op1)) {
+ result = new_rd_arm_Eor_i(env->dbg, env->irg, env->block, op2, env->mode);
+ set_arm_value(result, get_arm_value(op1));
+ } else if (is_arm_Const(op2)) {
+ result = new_rd_arm_Eor_i(env->dbg, env->irg, env->block, op1, env->mode);
+ set_arm_value(result, get_arm_value(op2));
+ } else {
+ result = new_rd_arm_Eor(env->dbg, env->irg, env->block, op1, op2, env->mode);
+ }
+ return result;
+}
+
+
+
+/**
+ * Creates an arm Sub.
+ *
+ * @param dbg firm node dbg
+ * @param block the block the new node should belong to
+ * @param op1 first operator
+ * @param op2 second operator
+ * @param mode node mode
+ * @return the created arm Sub node
+ */
+static ir_node *gen_Sub(arm_transform_env_t *env, ir_node *op1, ir_node *op2) {
+ ir_node *result = NULL;
+ assert(!mode_is_float(env->mode) || (get_irn_mode(op1)->sort == get_irn_mode(op2)->sort));
+ assert(env->mode != mode_E && "IEEE Extended FP not supported");
+
+ if (env->mode == mode_F) {
+ result = new_rd_arm_fSubs(env->dbg, env->irg, env->block, op1, op2, env->mode);
+ } else if (env->mode == mode_D) {
+ result = new_rd_arm_fSubd(env->dbg, env->irg, env->block, op1, op2, env->mode);
+ } else if (mode_is_numP(env->mode)) {
+ if (is_arm_Const(op2)) {
+ result = new_rd_arm_Sub_i(env->dbg, env->irg, env->block, op1, env->mode);
+ set_arm_value(result, get_arm_value(op2));
+ } else {
+ result = new_rd_arm_Sub(env->dbg, env->irg, env->block, op1, op2, env->mode);
+ }
+ } else {
+ assert(0 && "unknown mode for sub");
+ }
+ return result;
+}
+
+/**
+ * Creates an arm Shl.
+ *
+ * @param dbg firm node dbg
+ * @param block the block the new node should belong to
+ * @param op1 first operator
+ * @param op2 second operator
+ * @param mode node mode
+ * @return the created arm Shl node
+ */
+static ir_node *gen_Shl(arm_transform_env_t *env, ir_node *op1, ir_node *op2) {
+ ir_node *result;
+ if (is_arm_Const(op2)) {
+ result = new_rd_arm_Shl_i(env->dbg, env->irg, env->block, op1, env->mode);
+ set_arm_value(result, get_arm_value(op2));
+ } else {
+ result = new_rd_arm_Shl(env->dbg, env->irg, env->block, op1, op2, env->mode);
+ }
+ return result;
+}
+
+
+
+/**
+ * Creates an arm Shr.
+ *
+ * @param dbg firm node dbg
+ * @param block the block the new node should belong to
+ * @param op1 first operator
+ * @param op2 second operator
+ * @param mode node mode
+ * @return the created arm Shr node
+ */
+static ir_node *gen_Shr(arm_transform_env_t *env, ir_node *op1, ir_node *op2) {
+ ir_node *result;
+ if (is_arm_Const(op2)) {
+ result = new_rd_arm_Shr_i(env->dbg, env->irg, env->block, op1, env->mode);
+ set_arm_value(result, get_arm_value(op2));
+ } else {
+ result = new_rd_arm_Shr(env->dbg, env->irg, env->block, op1, op2, env->mode);
+ }
+ return result;
+}
+
+/**
+ * Creates an arm Shrs.
+ *
+ * @param dbg firm node dbg
+ * @param block the block the new node should belong to
+ * @param op1 first operator
+ * @param op2 second operator
+ * @param mode node mode
+ * @return the created arm Shrs node
+ */
+static ir_node *gen_Shrs(arm_transform_env_t *env, ir_node *op1, ir_node *op2) {
+ ir_node *result;
+ if (is_arm_Const(op2)) {
+ result = new_rd_arm_Shrs_i(env->dbg, env->irg, env->block, op1, env->mode);
+ set_arm_value(result, get_arm_value(op2));
+ } else {
+ result = new_rd_arm_Shrs(env->dbg, env->irg, env->block, op1, op2, env->mode);
+ }
+ return result;
+}
+
+/**
+ * Transforms a Not node.
+ *
+ * @param mod the debug module
+ * @param block the block the new node should belong to
+ * @param node the ir Not node
+ * @param op operator
+ * @param mode node mode
+ * @return the created arm Not node
+ */
+static ir_node *gen_Not(arm_transform_env_t *env, ir_node *op) {
+ return new_rd_arm_Not(env->dbg, env->irg, env->block, op, env->mode);
+}
+
+
+static ir_node *gen_Abs(arm_transform_env_t *env, ir_node *op) {
+ assert(env->mode != mode_E && "IEEE Extended FP not supported");
+
+ if (env->mode == mode_F) {
+ return new_rd_arm_fAbss(env->dbg, env->irg, env->block, op, env->mode);
+ }
+ if (env->mode == mode_D) {
+ return new_rd_arm_fAbsd(env->dbg, env->irg, env->block, op, env->mode);
+ }
+
+ return new_rd_arm_Abs(env->dbg, env->irg, env->block, op, env->mode);
+}
+
+
+/**
+ * Transforms a Minus node.
+ *
+ * @param mod the debug module
+ * @param block the block the new node should belong to
+ * @param node the ir Minus node
+ * @param op operator
+ * @param mode node mode
+ * @return the created arm Minus node
+ */
+static ir_node *gen_Minus(arm_transform_env_t *env, ir_node *op) {
+ if (mode_is_float(env->mode)) {
+ return new_rd_arm_fMinus(env->dbg, env->irg, env->block, op, env->mode);
+ }
+ return new_rd_arm_Minus(env->dbg, env->irg, env->block, op, env->mode);
+}
+
+
+/**
+ * Transforms a Load.
+ *
+ * @param mod the debug module
+ * @param block the block the new node should belong to
+ * @param node the ir Load node
+ * @param mode node mode
+ * @return the created arm Load node
+ */
+static ir_node *gen_Load(arm_transform_env_t *env) {
+ ir_node *node = env->irn;
+ ir_mode *mode = get_Load_mode(node);
+
+// const ir_edge_t *edge;
+//
+// foreach_out_edge(node, edge) {
+// ir_node* proj = get_edge_src_irn(edge);
+// long nr = get_Proj_proj(proj);
+// if ( nr == pn_Load_res )
+// mode = proj->mode;
+// }
+// besser: get_Load_mode() verwenden!
+
+ assert(mode!=NULL && "irgendwie hat das load kein proj fuers result");
+ if (mode==mode_F) {
+ return new_rd_arm_fLoads(env->dbg, env->irg, env->block, get_Load_ptr(node), get_Load_mem(node), env->mode);
+ }
+ if (mode==mode_D) {
+ return new_rd_arm_fLoadd(env->dbg, env->irg, env->block, get_Load_ptr(node), get_Load_mem(node), env->mode);
+ }
+ if (mode == mode_Bu) {
+ return new_rd_arm_Loadb(env->dbg, env->irg, env->block, get_Load_ptr(node), get_Load_mem(node), env->mode);
+ }
+ if (mode == mode_Bs) {
+ return new_rd_arm_Loadbs(env->dbg, env->irg, env->block, get_Load_ptr(node), get_Load_mem(node), env->mode);
+ }
+ if (mode == mode_Hu) {
+ return new_rd_arm_Loadh(env->dbg, env->irg, env->block, get_Load_ptr(node), get_Load_mem(node), env->mode);
+ }
+ if (mode == mode_Hs) {
+ return new_rd_arm_Loadhs(env->dbg, env->irg, env->block, get_Load_ptr(node), get_Load_mem(node), env->mode);
+ }
+ if (mode_is_reference(mode)) {
+ return new_rd_arm_Load(env->dbg, env->irg, env->block, get_Load_ptr(node), get_Load_mem(node), env->mode);
+ }
+ return new_rd_arm_Load(env->dbg, env->irg, env->block, get_Load_ptr(node), get_Load_mem(node), env->mode);
+}
+
+
+
+/**
+ * Transforms a Store.
+ *
+ * @param mod the debug module
+ * @param block the block the new node should belong to
+ * @param node the ir Store node
+ * @param mode node mode
+ * @return the created arm Store node
+ */
+static ir_node *gen_Store(arm_transform_env_t *env) {
+ ir_node *node = env->irn;
+ ir_mode *mode = get_irn_mode(get_Store_value(node));
+ assert(env->mode != mode_E && "IEEE Extended FP not supported");
+
+ if (mode == mode_F) {
+ return new_rd_arm_fStores(env->dbg, env->irg, env->block, get_Store_ptr(node), get_Store_value(node), get_Store_mem(node), env->mode);
+ }
+ if (mode == mode_D) {
+ return new_rd_arm_fStored(env->dbg, env->irg, env->block, get_Store_ptr(node), get_Store_value(node), get_Store_mem(node), env->mode);
+ }
+ if (mode == mode_Bu) {
+ return new_rd_arm_Storeb(env->dbg, env->irg, env->block, get_Store_ptr(node), get_Store_value(node), get_Store_mem(node), env->mode);
+ }
+ if (mode == mode_Bs) {
+ return new_rd_arm_Storebs(env->dbg, env->irg, env->block, get_Store_ptr(node), get_Store_value(node), get_Store_mem(node), env->mode);
+ }
+ if (mode == mode_Hu) {
+ return new_rd_arm_Storeh(env->dbg, env->irg, env->block, get_Store_ptr(node), get_Store_value(node), get_Store_mem(node), env->mode);
+ }
+ if (mode == mode_Hs) {
+ return new_rd_arm_Storehs(env->dbg, env->irg, env->block, get_Store_ptr(node), get_Store_value(node), get_Store_mem(node), env->mode);
+ }
+ return new_rd_arm_Store(env->dbg, env->irg, env->block, get_Store_ptr(node), get_Store_value(node), get_Store_mem(node), env->mode);
+}
+
+
+static ir_node *gen_Cond(arm_transform_env_t *env) {
+ ir_node *result = NULL;
+ ir_node *selector = get_Cond_selector(env->irn);
+ ir_node *irn = env->irn;
+ if ( get_irn_mode(selector) == mode_b ) {
+ //CondJmp
+ ir_node *proj_node = get_Cond_selector(irn);
+ ir_mode *proj_mode = get_irn_mode(proj_node);
+ ir_node *cmp_node = get_Proj_pred(proj_node);
+ ir_node *op1 = get_Cmp_left(cmp_node);
+ ir_node *op2 = get_Cmp_right(cmp_node);
+ result = new_rd_arm_CondJmp(env->dbg, env->irg, env->block, op1, op2, mode_T);
+ set_arm_proj_num(result, get_Proj_proj(proj_node));
+ } else {
+ //SwitchJmp
+ ir_node *op = get_irn_n(env->irn, 0);
+ ir_node *const_graph;
+ ir_node *sub;
+ ir_node *const_node;
+
+ ir_node *proj;
+ const ir_edge_t *edge;
+ int min = INT_MAX;
+ int max = INT_MIN;
+ int translation;
+ int norm_max;
+ int norm_min;
+ int pn;
+ arm_transform_env_t const_env;
+ int n_projs;
+ ir_node **projs;
+
+ foreach_out_edge(irn, edge) {
+ proj = get_edge_src_irn(edge);
+ assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");
+
+ pn = get_Proj_proj(proj);
+
+ min = pn<min ? pn : min;
+ max = pn>max ? pn : max;
+ }
+ translation = min;
+ norm_max = max - translation;
+ norm_min = min - translation;
+
+ n_projs = norm_max + 1;
+ projs = xcalloc(n_projs , sizeof(ir_node*));
+
+
+ foreach_out_edge(irn, edge) {
+ proj = get_edge_src_irn(edge);
+ assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");
+
+ pn = get_Proj_proj(proj) - translation;
+ set_Proj_proj(proj, pn);
+ }
+
+
+ const_node = new_rd_Const(env->dbg, env->irg, env->block, mode_Iu, new_tarval_from_long(translation, mode_Iu));
+ const_env = *env;
+ const_env.mode = mode_Is;
+ const_env.irn = const_node;
+ const_graph = gen_Const(&const_env);
+ sub = new_rd_arm_Sub(env->dbg, env->irg, env->block, op, const_graph, get_irn_mode(op));
+ result = new_rd_arm_SwitchJmp(env->dbg, env->irg, env->block, sub, mode_T);
+ set_arm_n_projs(result, n_projs);
+ set_arm_default_proj_num(result, get_Cond_defaultProj(irn)-translation);
+ }
+ return result;
+}
+
+/**
+ * Returns the name of a SymConst.
+ * @param symc the SymConst
+ * @return name of the SymConst
+ */
+const char *get_sc_name(ir_node *symc) {
+ if (get_irn_opcode(symc) != iro_SymConst)
+ return "NONE";
+
+ switch (get_SymConst_kind(symc)) {
+ case symconst_addr_name:
+ return get_id_str(get_SymConst_name(symc));
+
+ case symconst_addr_ent:
+ return get_entity_ld_name(get_SymConst_entity(symc));
+
+ default:
+ assert(0 && "Unsupported SymConst");
+ }
+
+ return NULL;
+}
+
+static ir_node *gen_SymConst(arm_transform_env_t *env) {
+ ir_node *result;
+ const char *str = get_sc_name(env->irn);
+ result = new_rd_arm_SymConst(env->dbg, env->irg, env->block, env->mode);
+ set_arm_symconst_label(result, str);
+ return result;
+}
+
+
+
+
+
+/**
+ * Transforms a CopyB node.
+ *
+ * @param env The transformation environment
+ * @return The transformed node.
+ */
+static ir_node *gen_CopyB(arm_transform_env_t *env) {
+ ir_node *res = NULL;
+ dbg_info *dbg = env->dbg;
+ ir_graph *irg = env->irg;
+ ir_mode *mode = env->mode;
+ ir_node *block = env->block;
+ ir_node *node = env->irn;
+ ir_node *src = get_CopyB_src(node);
+ ir_node *dst = get_CopyB_dst(node);
+ ir_node *mem = get_CopyB_mem(node);
+ int size = get_type_size_bytes(get_CopyB_type(node));
+ ir_node *src_copy;
+ ir_node *dst_copy;
+
+ arm_transform_env_t const_env;
+ const_env.block = block;
+ const_env.dbg = dbg;
+ const_env.irg = irg;
+ const_env.irn = node;
+ const_env.mod = env->mod;
+ const_env.mode = mode_Iu;
+
+ src_copy = be_new_Copy(&arm_reg_classes[CLASS_arm_general_purpose], irg, block, src);
+ dst_copy = be_new_Copy(&arm_reg_classes[CLASS_arm_general_purpose], irg, block, dst);
+
+ res = new_rd_arm_CopyB( dbg, irg, block, dst_copy, src_copy, new_rd_arm_EmptyReg(dbg, irg, block, mode_Iu), new_rd_arm_EmptyReg(dbg, irg, block, mode_Iu), new_rd_arm_EmptyReg(dbg, irg, block, mode_Iu), mem, mode);
+ set_arm_value(res, new_tarval_from_long(size, mode_Iu));
+
+ return res;
+}
+
+
+
+
+
+// /************************************************************************/
+// /* be transforms */
+// /************************************************************************/
+//
+// static ir_node *gen_be_Copy(arm_transform_env_t *env, ir_node *op) {
+// return new_rd_arm_Copy(env->dbg, env->irg, env->block, op, env->mode);
+// }
+
+/*********************************************************
+ * _ _ _
+ * (_) | | (_)
+ * _ __ ___ __ _ _ _ __ __| |_ __ ___ _____ _ __
+ * | '_ ` _ \ / _` | | '_ \ / _` | '__| \ \ / / _ \ '__|
+ * | | | | | | (_| | | | | | | (_| | | | |\ V / __/ |
+ * |_| |_| |_|\__,_|_|_| |_| \__,_|_| |_| \_/ \___|_|
+ *
+ *********************************************************/
+
+/************************************************************************/
+/* move constants out of startblock */
+/************************************************************************/
+void arm_move_consts(ir_node *node, void *env) {
+ arm_code_gen_t *cgenv = (arm_code_gen_t *)env;
+ int i;
+ if (is_Block(node))
+ return;
+ if (is_Phi(node)) {
+ for (i=0; i<get_irn_arity(node); i++) {
+ ir_node *pred = get_irn_n(node,i);
+ opcode pred_code = get_irn_opcode(pred);
+ if (pred_code == iro_Const) {
+ ir_node *const_graph;
+ arm_transform_env_t tenv;
+ tenv.block = get_nodes_block(get_irn_n(get_nodes_block(node),i));
+ tenv.dbg = get_irn_dbg_info(pred);
+ tenv.irg = current_ir_graph;
+ tenv.irn = pred;
+ tenv.mod = cgenv->mod;
+ tenv.mode = get_irn_mode(pred);
+ const_graph = create_const_graph(&tenv);
+ set_irn_n(node, i, const_graph);
+ } else if (pred_code == iro_SymConst) {
+ const char *str = get_sc_name(pred);
+ ir_node *symconst_node;
+ symconst_node = new_rd_arm_SymConst(get_irn_dbg_info(pred),
+ current_ir_graph, get_nodes_block(get_irn_n(get_nodes_block(node),i)), get_irn_mode(pred));
+ set_arm_symconst_label(symconst_node, str);
+ set_irn_n(node, i, symconst_node);
+ }
+ }
+ return;
+ }
+ for (i=0; i<get_irn_arity(node); i++) {
+ ir_node *pred = get_irn_n(node,i);
+ opcode pred_code = get_irn_opcode(pred);
+ if (pred_code == iro_Const) {
+ ir_node *const_graph;
+ arm_transform_env_t tenv;
+ tenv.block = get_nodes_block(node);
+ tenv.dbg = get_irn_dbg_info(pred);
+ tenv.irg = current_ir_graph;
+ tenv.irn = pred;
+ tenv.mod = cgenv->mod;
+ tenv.mode = get_irn_mode(pred);
+ const_graph = create_const_graph(&tenv);
+ set_irn_n(node, i, const_graph);
+ } else if (pred_code == iro_SymConst) {
+ const char *str = get_sc_name(pred);
+ ir_node *symconst_node;
+ symconst_node = new_rd_arm_SymConst(get_irn_dbg_info(pred),
+ current_ir_graph, get_nodes_block(node), get_irn_mode(pred));
+ set_arm_symconst_label(symconst_node, str);
+ set_irn_n(node, i, symconst_node);
+ }
+ }
+}
+
+
+/************************************************************************/
+/* move symbolic constants out of startblock */
+/************************************************************************/
+void arm_move_symconsts(ir_node *node, void *env) {
+ arm_code_gen_t *cgenv = (arm_code_gen_t *)env;
+ int i;
+ if (is_Block(node))
+ return;
+ for (i=0; i<get_irn_arity(node); i++) {
+ ir_node *pred = get_irn_n(node,i);
+ opcode pred_code = get_irn_opcode(pred);
+ if (pred_code == iro_SymConst) {
+ const char *str = get_sc_name(pred);
+ ir_node *symconst_node;
+ symconst_node = new_rd_arm_SymConst(get_irn_dbg_info(pred),
+ current_ir_graph, get_nodes_block(node), get_irn_mode(pred));
+ set_arm_symconst_label(symconst_node, str);
+ set_irn_n(node, i, symconst_node);
+ }
+ }
+}
+
+
+/**
+ * Transforms the given firm node (and maybe some other related nodes)
+ * into one or more assembler nodes.
+ *
+ * @param node the firm node
+ * @param env the debug module
+ */
+void arm_transform_node(ir_node *node, void *env) {
+ arm_code_gen_t *cgenv = (arm_code_gen_t *)env;
+ opcode code = get_irn_opcode(node);
+ ir_node *asm_node = NULL;
+ arm_transform_env_t tenv;
+
+ if (is_Block(node))
+ return;
+
+ tenv.block = get_nodes_block(node);
+ tenv.dbg = get_irn_dbg_info(node);
+ tenv.irg = current_ir_graph;
+ tenv.irn = node;
+ tenv.mod = cgenv->mod;
+ tenv.mode = get_irn_mode(node);
+
+#define UNOP(a) case iro_##a: asm_node = gen_##a(&tenv, get_##a##_op(node)); break
+#define BINOP(a) case iro_##a: asm_node = gen_##a(&tenv, get_##a##_left(node), get_##a##_right(node)); break
+#define GEN(a) case iro_##a: asm_node = gen_##a(&tenv); break
+#define IGN(a) case iro_##a: break
+#define BAD(a) case iro_##a: goto bad
+
+ DBG((tenv.mod, LEVEL_1, "check %+F ... ", node));
+
+ switch (code) {
+ BINOP(Add); // done
+ BINOP(Mul); // done
+ BINOP(Quot); // done
+ BINOP(And); // done
+ BINOP(Or); // done
+ BINOP(Eor); // done
+
+ BINOP(Sub); // done
+ BINOP(Shl); // done
+ BINOP(Shr); // done
+ BINOP(Shrs); // done
+
+ UNOP(Minus); // done
+ UNOP(Not); // done
+ UNOP(Abs); // done
+
+ GEN(CopyB); // done
+ GEN(Const); // TODO: floating point consts
+ UNOP(Conv); // TODO: floating point conversions
+
+ GEN(Load); // done
+ GEN(Store); // done
+
+ GEN(SymConst);
+ GEN(Cond); // integer done
+
+ /* TODO: implement these nodes */
+
+ IGN(Div); // intrinsic lowering
+ IGN(Mod); // intrinsic lowering
+ IGN(DivMod); // TODO: implement DivMod
+
+ IGN(Mux);
+ IGN(Unknown);
+ IGN(Cmp); // done, implemented in cond
+
+ /* You probably don't need to handle the following nodes */
+
+ IGN(Call);
+ IGN(Proj);
+ IGN(Alloc);
+
+ IGN(Block);
+ IGN(Start);
+ IGN(End);
+ IGN(NoMem);
+ IGN(Phi);
+ IGN(IJmp);
+ IGN(Jmp); // emitter done
+ IGN(Break);
+ IGN(Sync);
+
+ BAD(Raise);
+ BAD(Sel);
+ BAD(InstOf);
+ BAD(Cast);
+ BAD(Free);
+ BAD(Tuple);
+ BAD(Id);
+ BAD(Bad);
+ BAD(Confirm);
+ BAD(Filter);
+ BAD(CallBegin);
+ BAD(EndReg);
+ BAD(EndExcept);
+
+ default:
+ if (get_irn_op(node) == get_op_Max() ||
+ get_irn_op(node) == get_op_Min() ||
+ get_irn_op(node) == get_op_Mulh())
+ {
+ /* TODO: implement */
+ /* ignore for now */
+ }
+ break;
+bad:
+ fprintf(stderr, "Not implemented: %s\n", get_irn_opname(node));
+ assert(0);
+ }
+
+ if (asm_node) {
+ exchange(node, asm_node);
+ DB((tenv.mod, LEVEL_1, "created node %+F[%p]\n", asm_node, asm_node));
+ }
+ else {
+ DB((tenv.mod, LEVEL_1, "ignored\n"));
+ }
+}
--- /dev/null
+#ifndef _ARM_TRANSFORM_H_
+#define _ARM_TRANSFORM_H_
+
+void arm_move_consts(ir_node *node, void *env);
+void arm_move_symconsts(ir_node *node, void *env);
+void arm_transform_node(ir_node *node, void *env);
+
+#endif /* _ARM_TRANSFORM_H_ */
--- /dev/null
+/* The main arm backend driver file. */
+/* $Id$ */
+
+#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 "lower_intrinsics.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 "../be.h"
+#include "../beabi.h"
+
+#include "bearch_arm_t.h"
+
+#include "arm_new_nodes.h" /* arm nodes interface */
+#include "gen_arm_regalloc_if.h" /* the generated interface (register type and class defenitions) */
+#include "arm_gen_decls.h" /* interface declaration emitter */
+#include "arm_transform.h"
+#include "arm_emitter.h"
+#include "arm_map_regs.h"
+
+#define DEBUG_MODULE "firm.be.arm.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 arm 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 *arm_get_irn_reg_req(const void *self, arch_register_req_t *req, const ir_node *irn, int pos) {
+ const arm_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 (is_Block(irn) || mode == mode_X || mode == mode_M) {
+ DBG((mod, LEVEL_1, "ignoring mode_T, mode_M node %+F\n", irn));
+ return NULL;
+ }
+
+ if (mode == mode_T && pos < 0) {
+ DBG((mod, LEVEL_1, "ignoring request for OUT requirements at %+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 = arm_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_arm_irn(irn)) {
+ if (pos >= 0) {
+ irn_req = get_arm_in_req(irn, pos);
+ }
+ else {
+ irn_req = get_arm_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)) {
+ assert(irn_req->same_pos >= 0 && "should be same constraint for in -> out NYI");
+ req->other_same = get_irn_n(irn, irn_req->same_pos);
+ }
+
+ if (arch_register_req_is(&(irn_req->req), should_be_different)) {
+ assert(irn_req->different_pos >= 0 && "should be different constraint for in -> out NYI");
+ req->other_different = get_irn_n(irn, irn_req->different_pos);
+ }
+ }
+ /* get requirements for FIRM nodes */
+ 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, &(arm_default_req_arm_floating_point.req), sizeof(*req));
+ }
+ else if (mode_is_int(mode) || mode_is_reference(mode)) {
+ memcpy(req, &(arm_default_req_arm_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 {
+ DB((mod, LEVEL_1, "returning NULL for %+F (node not supported)\n", irn));
+ req = NULL;
+ }
+ }
+
+ return req;
+}
+
+static void arm_set_irn_reg(const void *self, ir_node *irn, const arch_register_t *reg) {
+ int pos = 0;
+
+ if (is_Proj(irn)) {
+
+ if (get_irn_mode(irn) == mode_X) {
+ return;
+ }
+
+ pos = arm_translate_proj_pos(irn);
+ irn = my_skip_proj(irn);
+ }
+
+ if (is_arm_irn(irn)) {
+ const arch_register_t **slots;
+
+ slots = get_arm_slots(irn);
+ slots[pos] = reg;
+ }
+ else {
+ /* here we set the registers for the Phi nodes */
+ arm_set_firm_reg(irn, reg, cur_reg_set);
+ }
+}
+
+static const arch_register_t *arm_get_irn_reg(const void *self, const ir_node *irn) {
+ int pos = 0;
+ const arch_register_t *reg = NULL;
+
+ if (is_Proj(irn)) {
+
+ if (get_irn_mode(irn) == mode_X) {
+ return NULL;
+ }
+
+ pos = arm_translate_proj_pos(irn);
+ irn = my_skip_proj(irn);
+ }
+
+ if (is_arm_irn(irn)) {
+ const arch_register_t **slots;
+ slots = get_arm_slots(irn);
+ reg = slots[pos];
+ }
+ else {
+ reg = arm_get_firm_reg(irn, cur_reg_set);
+ }
+
+ return reg;
+}
+
+static arch_irn_class_t arm_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_arm_irn(irn)) {
+ return arch_irn_class_normal;
+ }
+
+ return 0;
+}
+
+static arch_irn_flags_t arm_get_flags(const void *self, const ir_node *irn) {
+ irn = my_skip_proj(irn);
+
+ if (is_arm_irn(irn)) {
+ return get_arm_flags(irn);
+ }
+ else if (is_Unknown(irn)) {
+ return arch_irn_flags_ignore;
+ }
+
+ return 0;
+}
+
+static entity *arm_get_frame_entity(const void *self, const ir_node *irn) {
+ /* TODO: return the entity assigned to the frame */
+ return NULL;
+}
+
+/**
+ * This function is called by the generic backend to correct offsets for
+ * nodes accessing the stack.
+ */
+static void arm_set_stack_bias(const void *self, ir_node *irn, int bias) {
+ /* TODO: correct offset if irn accesses the stack */
+}
+
+/* fill register allocator interface */
+
+static const arch_irn_ops_if_t arm_irn_ops_if = {
+ arm_get_irn_reg_req,
+ arm_set_irn_reg,
+ arm_get_irn_reg,
+ arm_classify,
+ arm_get_flags,
+ arm_get_frame_entity,
+ arm_set_stack_bias
+};
+
+arm_irn_ops_t arm_irn_ops = {
+ &arm_irn_ops_if,
+ NULL
+};
+
+
+
+/**************************************************
+ * _ _ __
+ * | | (_)/ _|
+ * ___ ___ __| | ___ __ _ ___ _ __ _| |_
+ * / __/ _ \ / _` |/ _ \/ _` |/ _ \ '_ \ | | _|
+ * | (_| (_) | (_| | __/ (_| | __/ | | | | | |
+ * \___\___/ \__,_|\___|\__, |\___|_| |_| |_|_|
+ * __/ |
+ * |___/
+ **************************************************/
+
+/**
+ * Transforms the standard firm graph into
+ * a ARM firm graph
+ */
+static void arm_prepare_graph(void *self) {
+ arm_code_gen_t *cg = self;
+
+ irg_walk_blkwise_graph(cg->irg, arm_move_consts, arm_transform_node, cg);
+}
+
+
+
+/**
+ * Called immediately before emit phase.
+ */
+static void arm_finish_irg(ir_graph *irg, arm_code_gen_t *cg) {
+ /* TODO: - fix offsets for nodes accessing stack
+ - ...
+ */
+}
+
+
+/**
+ * These are some hooks which must be filled but are probably not needed.
+ */
+static void arm_before_sched(void *self) {
+ /* Some stuff you need to do after scheduling but before register allocation */
+}
+
+static void arm_before_ra(void *self) {
+ /* Some stuff you need to do immediately after register allocation */
+}
+
+
+/**
+ * Emits the code, closes the output file and frees
+ * the code generator interface.
+ */
+static void arm_emit_and_done(void *self) {
+ arm_code_gen_t *cg = self;
+ ir_graph *irg = cg->irg;
+ FILE *out = cg->out;
+
+ if (cg->emit_decls) {
+ arm_gen_decls(cg->out);
+ cg->emit_decls = 0;
+ }
+
+ arm_finish_irg(irg, cg);
+ dump_ir_block_graph_sched(irg, "-arm-finished");
+ arm_gen_routine(out, irg, cg);
+
+ cur_reg_set = NULL;
+
+ /* de-allocate code generator */
+ del_set(cg->reg_set);
+ free(self);
+}
+
+enum convert_which { low, high };
+
+/**
+ * Move an floating point value to a integer register.
+ * Place the move operation into block bl.
+ */
+static ir_node *convert_to_int(ir_node *bl, ir_node *arg, enum convert_which which) {
+ return NULL;
+}
+
+/**
+ * Convert the arguments of a call to support the
+ * ARM calling convention of general purpose AND floating
+ * point arguments
+ */
+static void handle_calls(ir_node *call, void *env)
+{
+ arm_code_gen_t *cg = env;
+ int i, j, n, size, idx, flag, n_param, n_res;
+ ir_type *mtp, *new_mtd, *new_tp[5];
+ ir_node *new_in[5], **in;
+ ir_node *bl;
+
+ if (! is_Call(call))
+ return;
+
+ /* check, if we need conversions */
+ n = get_Call_n_params(call);
+ mtp = get_Call_type(call);
+ assert(get_method_n_params(mtp) == n);
+
+ /* it's always enough to handle the first 4 parameters */
+ if (n > 4)
+ n = 4;
+ flag = size = idx = 0;
+ bl = get_nodes_block(call);
+ for (i = 0; i < n; ++i) {
+ ir_type *param_tp = get_method_param_type(mtp, i);
+
+ if (is_compound_type(param_tp)) {
+ /* an aggregate parameter: bad case */
+ assert(0);
+ }
+ else {
+ /* a primitive parameter */
+ ir_mode *mode = get_type_mode(param_tp);
+
+ if (mode_is_float(mode)) {
+ if (get_mode_size_bits(mode) > 32) {
+ size += 2 * 4;
+ new_tp[idx] = cg->int_tp;
+ new_in[idx] = convert_to_int(bl, get_Call_param(call, i), low);
+ ++idx;
+ new_tp[idx] = cg->int_tp;
+ new_in[idx] = convert_to_int(bl, get_Call_param(call, i), high);
+ ++idx;
+ }
+ else {
+ size += 4;
+ new_tp[idx] = cg->int_tp;
+ new_in[idx] = convert_to_int(bl, get_Call_param(call, i), low);
+ ++idx;
+ }
+ flag = 1;
+ }
+ else {
+ size += 4;
+ new_tp[idx] = param_tp;
+ new_in[idx] = get_Call_param(call, i);
+ ++idx;
+ }
+ }
+
+ if (size >= 16)
+ break;
+ }
+
+ /* if flag is NOT set, no need to translate the method type */
+ if (! flag)
+ return;
+
+ /* construct a new method type */
+ n = i;
+ n_param = get_method_n_params(mtp) - n + idx;
+ n_res = get_method_n_ress(mtp);
+ new_mtd = new_d_type_method(get_type_ident(mtp), n_param, n_res, get_type_dbg_info(mtp));
+
+ for (i = 0; i < idx; ++i)
+ set_method_param_type(new_mtd, i, new_tp[i]);
+ for (i = n, j = idx; i < get_method_n_params(mtp); ++i)
+ set_method_param_type(new_mtd, j++, get_method_param_type(mtp, i));
+ for (i = 0; i < n_res; ++i)
+ set_method_res_type(new_mtd, i, get_method_res_type(mtp, i));
+
+ set_method_calling_convention(new_mtd, get_method_calling_convention(mtp));
+ set_method_first_variadic_param_index(new_mtd, get_method_first_variadic_param_index(mtp));
+
+ if (is_lowered_type(mtp)) {
+ mtp = get_associated_type(mtp);
+ }
+ set_lowered_type(mtp, new_mtd);
+
+ set_Call_type(call, new_mtd);
+
+ /* calculate new in array of the Call */
+ NEW_ARR_A(ir_node *, in, n_param + 2);
+ for (i = 0; i < idx; ++i)
+ in[2 + i] = new_in[i];
+ for (i = n, j = idx; i < get_method_n_params(mtp); ++i)
+ in[2 + j++] = get_Call_param(call, i);
+
+ in[0] = get_Call_mem(call);
+ in[1] = get_Call_ptr(call);
+
+ /* finally, change the call inputs */
+ set_irn_in(call, n_param + 2, in);
+}
+
+/**
+ * Handle graph transformations before the abi converter does it's work
+ */
+static void arm_before_abi(void *self) {
+ arm_code_gen_t *cg = self;
+
+ irg_walk_graph(cg->irg, NULL, handle_calls, cg);
+}
+
+static void *arm_cg_init(FILE *F, const be_irg_t *birg);
+
+static const arch_code_generator_if_t arm_code_gen_if = {
+ arm_cg_init,
+ arm_before_abi, /* before abi introduce */
+ arm_prepare_graph,
+ arm_before_sched, /* before scheduling hook */
+ arm_before_ra, /* before register allocation hook */
+ NULL, /* after register allocation */
+ arm_emit_and_done,
+};
+
+/**
+ * Initializes the code generator.
+ */
+static void *arm_cg_init(FILE *F, const be_irg_t *birg) {
+ static ir_type *int_tp = NULL;
+ arm_isa_t *isa = (arm_isa_t *)birg->main_env->arch_env->isa;
+ arm_code_gen_t *cg;
+
+ if (! int_tp) {
+ /* create an integer type with machine size */
+ int_tp = new_type_primitive(new_id_from_chars("int", 3), mode_Is);
+ }
+
+ cg = xmalloc(sizeof(*cg));
+ cg->impl = &arm_code_gen_if;
+ cg->irg = birg->irg;
+ cg->reg_set = new_set(arm_cmp_irn_reg_assoc, 1024);
+ cg->mod = firm_dbg_register("firm.be.arm.cg");
+ cg->out = F;
+ cg->arch_env = birg->main_env->arch_env;
+ cg->birg = birg;
+ cg->int_tp = int_tp;
+
+ isa->num_codegens++;
+
+ if (isa->num_codegens > 1)
+ cg->emit_decls = 0;
+ else
+ cg->emit_decls = 1;
+
+ cur_reg_set = cg->reg_set;
+
+ arm_irn_ops.cg = cg;
+
+ return (arch_code_generator_t *)cg;
+}
+
+
+/**
+ * Maps all intrinsic calls that the backend support
+ * and map all instructions the backend did not support
+ * to runtime calls.
+ */
+void arm_global_init(void) {
+ ir_type *tp, *int_tp, *uint_tp;
+ i_record records[8];
+ int n_records = 0;
+
+#define ID(x) new_id_from_chars(x, sizeof(x)-1)
+
+ int_tp = new_type_primitive(ID("int"), mode_Is);
+ uint_tp = new_type_primitive(ID("uint"), mode_Iu);
+
+ {
+ runtime_rt rt_Div;
+ i_instr_record *map_Div = &records[n_records++].i_instr;
+
+ tp = new_type_method(ID("rt_iDiv"), 2, 1);
+ set_method_param_type(tp, 0, int_tp);
+ set_method_param_type(tp, 1, int_tp);
+ set_method_res_type(tp, 0, int_tp);
+
+ rt_Div.ent = new_entity(get_glob_type(), ID("__divsi3"), tp);
+ rt_Div.mode = mode_T;
+ rt_Div.mem_proj_nr = pn_Div_M;
+ rt_Div.exc_proj_nr = pn_Div_X_except;
+ rt_Div.exc_mem_proj_nr = pn_Div_M;
+ rt_Div.res_proj_nr = pn_Div_res;
+
+ set_entity_visibility(rt_Div.ent, visibility_external_allocated);
+
+ map_Div->kind = INTRINSIC_INSTR;
+ map_Div->op = op_Div;
+ map_Div->i_mapper = i_mapper_RuntimeCall;
+ map_Div->ctx = &rt_Div;
+ }
+ {
+ runtime_rt rt_Div;
+ i_instr_record *map_Div = &records[n_records++].i_instr;
+
+ tp = new_type_method(ID("rt_uDiv"), 2, 1);
+ set_method_param_type(tp, 0, uint_tp);
+ set_method_param_type(tp, 1, uint_tp);
+ set_method_res_type(tp, 0, uint_tp);
+
+ rt_Div.ent = new_entity(get_glob_type(), ID("__udivsi3"), tp);
+ rt_Div.mode = mode_T;
+ rt_Div.mem_proj_nr = pn_Div_M;
+ rt_Div.exc_proj_nr = pn_Div_X_except;
+ rt_Div.exc_mem_proj_nr = pn_Div_M;
+ rt_Div.res_proj_nr = pn_Div_res;
+
+ set_entity_visibility(rt_Div.ent, visibility_external_allocated);
+
+ map_Div->kind = INTRINSIC_INSTR;
+ map_Div->op = op_Div;
+ map_Div->i_mapper = i_mapper_RuntimeCall;
+ map_Div->ctx = &rt_Div;
+ }
+ {
+ runtime_rt rt_Mod;
+ i_instr_record *map_Mod = &records[n_records++].i_instr;
+
+ tp = new_type_method(ID("rt_iMod"), 2, 1);
+ set_method_param_type(tp, 0, int_tp);
+ set_method_param_type(tp, 1, int_tp);
+ set_method_res_type(tp, 0, int_tp);
+
+ rt_Mod.ent = new_entity(get_glob_type(), ID("__modsi3"), tp);
+ rt_Mod.mode = mode_T;
+ rt_Mod.mem_proj_nr = pn_Mod_M;
+ rt_Mod.exc_proj_nr = pn_Mod_X_except;
+ rt_Mod.exc_mem_proj_nr = pn_Mod_M;
+ rt_Mod.res_proj_nr = pn_Mod_res;
+
+ set_entity_visibility(rt_Mod.ent, visibility_external_allocated);
+
+ map_Mod->kind = INTRINSIC_INSTR;
+ map_Mod->op = op_Mod;
+ map_Mod->i_mapper = i_mapper_RuntimeCall;
+ map_Mod->ctx = &rt_Mod;
+ }
+ {
+ runtime_rt rt_Mod;
+ i_instr_record *map_Mod = &records[n_records++].i_instr;
+
+ tp = new_type_method(ID("rt_uMod"), 2, 1);
+ set_method_param_type(tp, 0, uint_tp);
+ set_method_param_type(tp, 1, uint_tp);
+ set_method_res_type(tp, 0, uint_tp);
+
+ rt_Mod.ent = new_entity(get_glob_type(), ID("__umodsi3"), tp);
+ rt_Mod.mode = mode_T;
+ rt_Mod.mem_proj_nr = pn_Mod_M;
+ rt_Mod.exc_proj_nr = pn_Mod_X_except;
+ rt_Mod.exc_mem_proj_nr = pn_Mod_M;
+ rt_Mod.res_proj_nr = pn_Mod_res;
+
+ set_entity_visibility(rt_Mod.ent, visibility_external_allocated);
+
+ map_Mod->kind = INTRINSIC_INSTR;
+ map_Mod->op = op_Mod;
+ map_Mod->i_mapper = i_mapper_RuntimeCall;
+ map_Mod->ctx = &rt_Mod;
+ }
+
+ if (n_records > 0)
+ lower_intrinsics(records, n_records);
+}
+
+/*****************************************************************
+ * ____ _ _ _____ _____
+ * | _ \ | | | | |_ _|/ ____| /\
+ * | |_) | __ _ ___| | _____ _ __ __| | | | | (___ / \
+ * | _ < / _` |/ __| |/ / _ \ '_ \ / _` | | | \___ \ / /\ \
+ * | |_) | (_| | (__| < __/ | | | (_| | _| |_ ____) / ____ \
+ * |____/ \__,_|\___|_|\_\___|_| |_|\__,_| |_____|_____/_/ \_\
+ *
+ *****************************************************************/
+
+static arm_isa_t arm_isa_template = {
+ &arm_isa_if, /* isa interface */
+ &arm_general_purpose_regs[REG_R13], /* stack pointer */
+ &arm_general_purpose_regs[REG_R11], /* base pointer */
+ -1, /* stack direction */
+ 0 /* number of codegenerator objects */
+};
+
+/**
+ * Initializes the backend ISA and opens the output file.
+ */
+static void *arm_init(void) {
+ static int inited = 0;
+ arm_isa_t *isa;
+
+ if(inited)
+ return NULL;
+
+ isa = xcalloc(1, sizeof(*isa));
+ memcpy(isa, &arm_isa_template, sizeof(*isa));
+
+ arm_register_init(isa);
+ arm_create_opcodes();
+
+ inited = 1;
+
+ return isa;
+}
+
+
+
+/**
+ * Closes the output file and frees the ISA structure.
+ */
+static void arm_done(void *self) {
+ free(self);
+}
+
+
+
+static int arm_get_n_reg_class(const void *self) {
+ return N_CLASSES;
+}
+
+static const arch_register_class_t *arm_get_reg_class(const void *self, int i) {
+ assert(i >= 0 && i < N_CLASSES && "Invalid arm register class requested.");
+ return &arm_reg_classes[i];
+}
+
+
+
+/**
+ * Get the register class which shall be used to store a value of a given mode.
+ * @param self The this pointer.
+ * @param mode The mode in question.
+ * @return A register class which can hold values of the given mode.
+ */
+const arch_register_class_t *arm_get_reg_class_for_mode(const void *self, const ir_mode *mode) {
+ if (mode_is_float(mode))
+ return &arm_reg_classes[CLASS_arm_floating_point];
+ else
+ return &arm_reg_classes[CLASS_arm_general_purpose];
+}
+
+
+
+/**
+ * Produces the type which sits between the stack args and the locals on the stack.
+ * it will contain the return address and space to store the old base pointer.
+ * @return The Firm type modelling the ABI between type.
+ */
+static ir_type *arm_get_between_type(void *self) {
+ static ir_type *between_type = NULL;
+ static entity *old_bp_ent = NULL;
+
+ if(!between_type) {
+ entity *ret_addr_ent;
+ ir_type *ret_addr_type = new_type_primitive(new_id_from_str("return_addr"), mode_P);
+ ir_type *old_bp_type = new_type_primitive(new_id_from_str("bp"), mode_P);
+
+ between_type = new_type_class(new_id_from_str("arm_between_type"));
+ old_bp_ent = new_entity(between_type, new_id_from_str("old_bp"), old_bp_type);
+ ret_addr_ent = new_entity(between_type, new_id_from_str("old_bp"), ret_addr_type);
+
+ set_entity_offset_bytes(old_bp_ent, 0);
+ set_entity_offset_bytes(ret_addr_ent, get_type_size_bytes(old_bp_type));
+ set_type_size_bytes(between_type, get_type_size_bytes(old_bp_type) + get_type_size_bytes(ret_addr_type));
+ }
+
+ return between_type;
+}
+
+
+
+
+
+
+
+
+typedef struct {
+ be_abi_call_flags_bits_t flags;
+ const arch_env_t *arch_env;
+ const arch_isa_t *isa;
+ ir_graph *irg;
+} arm_abi_env_t;
+
+static void *arm_abi_init(const be_abi_call_t *call, const arch_env_t *arch_env, ir_graph *irg)
+{
+ arm_abi_env_t *env = xmalloc(sizeof(env[0]));
+ be_abi_call_flags_t fl = be_abi_call_get_flags(call);
+ env->flags = fl.bits;
+ env->irg = irg;
+ env->arch_env = arch_env;
+ env->isa = arch_env->isa;
+ return env;
+}
+
+static void arm_abi_dont_save_regs(void *self, pset *s)
+{
+ arm_abi_env_t *env = self;
+ if(env->flags.try_omit_fp)
+ pset_insert_ptr(s, env->isa->bp);
+}
+
+
+
+/**
+ * Build the ARM prolog
+ */
+static const arch_register_t *arm_abi_prologue(void *self, ir_node **mem, pmap *reg_map) {
+ ir_node *keep, *store;
+ arm_abi_env_t *env = self;
+ ir_graph *irg = env->irg;
+ ir_node *block = get_irg_start_block(irg);
+// ir_node *regs[16];
+// int n_regs = 0;
+ arch_register_class_t *gp = &arm_reg_classes[CLASS_arm_general_purpose];
+ static const arm_register_req_t *fp_req[] = {
+ &arm_default_req_arm_general_purpose_r11
+ };
+
+ ir_node *fp = be_abi_reg_map_get(reg_map, env->isa->bp);
+ ir_node *ip = be_abi_reg_map_get(reg_map, &arm_general_purpose_regs[REG_R12]);
+ ir_node *sp = be_abi_reg_map_get(reg_map, env->isa->sp);
+ ir_node *lr = be_abi_reg_map_get(reg_map, &arm_general_purpose_regs[REG_R14]);
+ ir_node *pc = be_abi_reg_map_get(reg_map, &arm_general_purpose_regs[REG_R15]);
+// ir_node *r0 = be_abi_reg_map_get(reg_map, &arm_general_purpose_regs[REG_R0]);
+// ir_node *r1 = be_abi_reg_map_get(reg_map, &arm_general_purpose_regs[REG_R1]);
+// ir_node *r2 = be_abi_reg_map_get(reg_map, &arm_general_purpose_regs[REG_R2]);
+// ir_node *r3 = be_abi_reg_map_get(reg_map, &arm_general_purpose_regs[REG_R3]);
+
+ if(env->flags.try_omit_fp)
+ return env->isa->sp;
+
+ ip = be_new_Copy(gp, irg, block, sp );
+ arch_set_irn_register(env->arch_env, ip, &arm_general_purpose_regs[REG_R12]);
+ be_set_constr_single_reg(ip, BE_OUT_POS(0), &arm_general_purpose_regs[REG_R12] );
+
+// if (r0) regs[n_regs++] = r0;
+// if (r1) regs[n_regs++] = r1;
+// if (r2) regs[n_regs++] = r2;
+// if (r3) regs[n_regs++] = r3;
+// sp = new_r_arm_StoreStackMInc(irg, block, *mem, sp, n_regs, regs, get_irn_mode(sp));
+// set_arm_req_out(sp, &arm_default_req_arm_general_purpose_r13, 0);
+// arch_set_irn_register(env->arch_env, sp, env->isa->sp);
+ store = new_rd_arm_StoreStackM4Inc(NULL, irg, block, sp, fp, ip, lr, pc, *mem, mode_T);
+ set_arm_req_out(store, &arm_default_req_arm_general_purpose_r13, 0);
+// arch_set_irn_register(env->arch_env, store, env->isa->sp);
+
+ sp = new_r_Proj(irg, block, store, env->isa->sp->reg_class->mode, 0);
+ arch_set_irn_register(env->arch_env, sp, env->isa->sp);
+ *mem = new_r_Proj(irg, block, store, mode_M, 1);
+
+ keep = be_new_CopyKeep_single(gp, irg, block, ip, sp, get_irn_mode(ip));
+ be_node_set_reg_class(keep, 1, gp);
+ arch_set_irn_register(env->arch_env, keep, &arm_general_purpose_regs[REG_R12]);
+ be_set_constr_single_reg(keep, BE_OUT_POS(0), &arm_general_purpose_regs[REG_R12] );
+
+ fp = new_rd_arm_Sub_i(NULL, irg, block, keep, get_irn_mode(fp) );
+ set_arm_value(fp, new_tarval_from_long(4, mode_Iu));
+ set_arm_req_out_all(fp, fp_req);
+ //set_arm_req_out(fp, &arm_default_req_arm_general_purpose_r11, 0);
+ arch_set_irn_register(env->arch_env, fp, env->isa->bp);
+
+// be_abi_reg_map_set(reg_map, &arm_general_purpose_regs[REG_R0], r0);
+// be_abi_reg_map_set(reg_map, &arm_general_purpose_regs[REG_R1], r1);
+// be_abi_reg_map_set(reg_map, &arm_general_purpose_regs[REG_R2], r2);
+// be_abi_reg_map_set(reg_map, &arm_general_purpose_regs[REG_R3], r3);
+ be_abi_reg_map_set(reg_map, env->isa->bp, fp);
+ be_abi_reg_map_set(reg_map, &arm_general_purpose_regs[REG_R12], keep);
+ be_abi_reg_map_set(reg_map, env->isa->sp, sp);
+ be_abi_reg_map_set(reg_map, &arm_general_purpose_regs[REG_R14], lr);
+ be_abi_reg_map_set(reg_map, &arm_general_purpose_regs[REG_R15], pc);
+
+ return env->isa->bp;
+}
+
+static void arm_abi_epilogue(void *self, ir_node *bl, ir_node **mem, pmap *reg_map) {
+ arm_abi_env_t *env = self;
+ ir_node *curr_sp = be_abi_reg_map_get(reg_map, env->isa->sp);
+ ir_node *curr_bp = be_abi_reg_map_get(reg_map, env->isa->bp);
+ ir_node *curr_pc = be_abi_reg_map_get(reg_map, &arm_general_purpose_regs[REG_R15]);
+ ir_node *curr_lr = be_abi_reg_map_get(reg_map, &arm_general_purpose_regs[REG_R14]);
+ static const arm_register_req_t *sub12_req[] = {
+ &arm_default_req_arm_general_purpose_r13
+ };
+
+// TODO: Activate Omit fp in epilogue
+ if(env->flags.try_omit_fp) {
+ curr_sp = be_new_IncSP(env->isa->sp, env->irg, bl, curr_sp, *mem, BE_STACK_FRAME_SIZE, be_stack_dir_shrink);
+
+ curr_lr = be_new_CopyKeep_single(&arm_reg_classes[CLASS_arm_general_purpose], env->irg, bl, curr_lr, curr_sp, get_irn_mode(curr_lr));
+ be_node_set_reg_class(curr_lr, 1, &arm_reg_classes[CLASS_arm_general_purpose]);
+ arch_set_irn_register(env->arch_env, curr_lr, &arm_general_purpose_regs[REG_R14]);
+ be_set_constr_single_reg(curr_lr, BE_OUT_POS(0), &arm_general_purpose_regs[REG_R14] );
+
+ curr_pc = be_new_Copy(&arm_reg_classes[CLASS_arm_general_purpose], env->irg, bl, curr_lr );
+ arch_set_irn_register(env->arch_env, curr_pc, &arm_general_purpose_regs[REG_R15]);
+ be_set_constr_single_reg(curr_pc, BE_OUT_POS(0), &arm_general_purpose_regs[REG_R15] );
+ } else {
+ ir_node *sub12_node;
+ ir_node *load_node;
+ sub12_node = new_rd_arm_Sub_i(NULL, env->irg, bl, curr_bp, mode_Iu );
+ set_arm_value(sub12_node, new_tarval_from_long(12,mode_Iu));
+ set_arm_req_out_all(sub12_node, sub12_req);
+ arch_set_irn_register(env->arch_env, sub12_node, env->isa->sp);
+ load_node = new_rd_arm_LoadStackM3( NULL, env->irg, bl, sub12_node, *mem, mode_T );
+ set_arm_req_out(load_node, &arm_default_req_arm_general_purpose_r11, 0);
+ set_arm_req_out(load_node, &arm_default_req_arm_general_purpose_r13, 1);
+ set_arm_req_out(load_node, &arm_default_req_arm_general_purpose_r15, 2);
+ curr_bp = new_r_Proj(env->irg, bl, load_node, env->isa->bp->reg_class->mode, 0);
+ curr_sp = new_r_Proj(env->irg, bl, load_node, env->isa->sp->reg_class->mode, 1);
+ curr_pc = new_r_Proj(env->irg, bl, load_node, mode_Iu, 2);
+ *mem = new_r_Proj(env->irg, bl, load_node, mode_M, 3);
+ arch_set_irn_register(env->arch_env, curr_bp, env->isa->bp);
+ arch_set_irn_register(env->arch_env, curr_sp, env->isa->sp);
+ arch_set_irn_register(env->arch_env, curr_pc, &arm_general_purpose_regs[REG_R15]);
+ }
+ be_abi_reg_map_set(reg_map, env->isa->sp, curr_sp);
+ be_abi_reg_map_set(reg_map, env->isa->bp, curr_bp);
+ be_abi_reg_map_set(reg_map, &arm_general_purpose_regs[REG_R14], curr_lr);
+ be_abi_reg_map_set(reg_map, &arm_general_purpose_regs[REG_R15], curr_pc);
+}
+
+static const be_abi_callbacks_t arm_abi_callbacks = {
+ arm_abi_init,
+ free,
+ arm_get_between_type,
+ arm_abi_dont_save_regs,
+ arm_abi_prologue,
+ arm_abi_epilogue,
+};
+
+
+/**
+ * Get the ABI restrictions for procedure calls.
+ * @param self The this pointer.
+ * @param method_type The type of the method (procedure) in question.
+ * @param abi The abi object to be modified
+ */
+void arm_get_call_abi(const void *self, ir_type *method_type, be_abi_call_t *abi) {
+ ir_type *tp;
+ ir_mode *mode;
+ int i;
+ int n = get_method_n_params(method_type);
+// const arch_register_t *reg;
+ be_abi_call_flags_t flags = {
+ 0, /* store from left to right */
+ 0, /* store arguments sequential */
+ 1, /* try to omit the frame pointer */
+ 1, /* the function can use any register as frame pointer */
+ 1 /* a call can take the callee's address as an immediate */
+ };
+
+ /* set stack parameter passing style */
+ be_abi_call_set_flags(abi, flags, &arm_abi_callbacks);
+
+ for (i = 0; i < n; i++) {
+ /* reg = get reg for param i; */
+ /* be_abi_call_param_reg(abi, i, reg); */
+ if (i < 4)
+
+ be_abi_call_param_reg(abi, i, arm_get_RegParam_reg(i));
+ else
+ be_abi_call_param_stack(abi, i, 4, 0, 0);
+ }
+
+ /* default: return value is in R0 resp. F0 */
+ assert(get_method_n_ress(method_type) < 2);
+ if (get_method_n_ress(method_type) > 0) {
+ tp = get_method_res_type(method_type, 0);
+ mode = get_type_mode(tp);
+
+ be_abi_call_res_reg(abi, 0,
+ mode_is_float(mode) ? &arm_floating_point_regs[REG_F0] : &arm_general_purpose_regs[REG_R0]);
+ }
+}
+
+static const void *arm_get_irn_ops(const arch_irn_handler_t *self, const ir_node *irn) {
+ return &arm_irn_ops;
+}
+
+const arch_irn_handler_t arm_irn_handler = {
+ arm_get_irn_ops
+};
+
+const arch_irn_handler_t *arm_get_irn_handler(const void *self) {
+ return &arm_irn_handler;
+}
+
+int arm_to_appear_in_schedule(void *block_env, const ir_node *irn) {
+ return is_arm_irn(irn);
+}
+
+/**
+ * Initializes the code generator interface.
+ */
+static const arch_code_generator_if_t *arm_get_code_generator_if(void *self) {
+ return &arm_code_gen_if;
+}
+
+list_sched_selector_t arm_sched_selector;
+
+/**
+ * Returns the reg_pressure scheduler with to_appear_in_schedule() over\loaded
+ */
+static const list_sched_selector_t *arm_get_list_sched_selector(const void *self) {
+ memcpy(&arm_sched_selector, reg_pressure_selector, sizeof(list_sched_selector_t));
+ arm_sched_selector.to_appear_in_schedule = arm_to_appear_in_schedule;
+ return &arm_sched_selector;
+}
+
+#ifdef WITH_LIBCORE
+static void arm_register_options(lc_opt_entry_t *ent)
+{
+}
+#endif /* WITH_LIBCORE */
+
+const arch_isa_if_t arm_isa_if = {
+#ifdef WITH_LIBCORE
+ arm_register_options,
+#endif
+ arm_init,
+ arm_done,
+ arm_get_n_reg_class,
+ arm_get_reg_class,
+ arm_get_reg_class_for_mode,
+ arm_get_call_abi,
+ arm_get_irn_handler,
+ arm_get_code_generator_if,
+ arm_get_list_sched_selector,
+};
--- /dev/null
+#ifndef _BEARCH_ARM_H_
+#define _BEARCH_ARM_H_
+
+#include "../bearch.h"
+
+extern const arch_isa_if_t arm_isa_if;
+void arm_global_init(void);
+
+
+#endif /* _BEARCH_ARM_H_ */
--- /dev/null
+#ifndef _BEARCH_ARM_T_H_
+#define _BEARCH_ARM_T_H_
+
+#include "debug.h"
+#include "bearch_arm.h"
+#include "arm_nodes_attr.h"
+#include "../be.h"
+#include "set.h"
+#include <stdio.h>
+
+typedef struct _arm_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 */
+ const be_irg_t *birg; /**< The be-irg (contains additional information about the irg) */
+ ir_type *int_tp; /**< the int type, needed for Call conversion */
+} arm_code_gen_t;
+
+
+typedef struct _arm_isa_t {
+ const arch_isa_if_t *impl;
+ const arch_register_t *sp; /**< The stack pointer register. */
+ const arch_register_t *bp; /**< The base pointer register. */
+ const int stack_dir; /**< -1 for decreasing, 1 for increasing. */
+ int num_codegens;
+} arm_isa_t;
+
+
+typedef struct _arm_irn_ops_t {
+ const arch_irn_ops_if_t *impl;
+ arm_code_gen_t *cg;
+} arm_irn_ops_t;
+
+
+/* this is a struct to minimize the number of parameters
+ for transformation walker */
+typedef struct _arm_transform_env_t {
+ firm_dbg_module_t *mod; /**< The firm debugger */
+ dbg_info *dbg; /**< The node debug info */
+ ir_graph *irg; /**< The irg, the node should be created in */
+ ir_node *block; /**< The block, the node should belong to */
+ ir_node *irn; /**< The irn, to be transformed */
+ ir_mode *mode; /**< The mode of the irn */
+// arm_code_gen_t *cg; /**< The code generator */
+} arm_transform_env_t;
+
+
+#endif /* _BEARCH_ARM_T_H_ */