* PURPOSE.
*/
-/* The main mips backend driver file. */
-/* $Id$ */
+/**
+ * @file
+ * @brief The main mips backend driver file.
+ * @author Matthias Braun, Mehdi
+ * @version $Id$
+ */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "bitset.h"
#include "debug.h"
-#include "../bearch_t.h" /* the general register allocator interface */
+#include "../bearch_t.h"
#include "../benode_t.h"
#include "../belower.h"
#include "../besched_t.h"
#include "../beabi.h"
#include "../bemachine.h"
#include "../bemodule.h"
+#include "../beemitter.h"
+#include "../begnuas.h"
+#include "../begnuas.h"
#include "bearch_mips_t.h"
-#include "mips_new_nodes.h" /* mips nodes interface */
-#include "gen_mips_regalloc_if.h" /* the generated interface (register type and class defenitions) */
-#include "mips_gen_decls.h" /* interface declaration emitter */
+#include "mips_new_nodes.h"
+#include "gen_mips_regalloc_if.h"
#include "mips_transform.h"
#include "mips_emitter.h"
#include "mips_map_regs.h"
* the code generator interface.
*/
static void mips_emit_and_done(void *self) {
- mips_code_gen_t *cg = self;
- ir_graph *irg = cg->irg;
- FILE *out = cg->isa->out;
-
- mips_register_emitters();
-
- if (cg->emit_decls) {
- mips_gen_decls(out);
- cg->emit_decls = 0;
- }
+ mips_code_gen_t *cg = self;
+ ir_graph *irg = cg->irg;
- mips_gen_routine(out, irg, cg);
+ mips_gen_routine(cg, irg);
cur_reg_set = NULL;
*/
static void *mips_cg_init(be_irg_t *birg) {
const arch_env_t *arch_env = be_get_birg_arch_env(birg);
- mips_isa_t *isa = (mips_isa_t *) arch_env->isa;
- mips_code_gen_t *cg = xmalloc(sizeof(*cg));
+ mips_isa_t *isa = (mips_isa_t *) arch_env->isa;
+ mips_code_gen_t *cg = xmalloc(sizeof(*cg));
cg->impl = &mips_code_gen_if;
cg->irg = be_get_birg_irg(birg);
cg->bl_list = NULL;
FIRM_DBG_REGISTER(cg->mod, "firm.be.mips.cg");
- isa->num_codegens++;
-
- if (isa->num_codegens > 1)
- cg->emit_decls = 0;
- else
- cg->emit_decls = 1;
-
cur_reg_set = cg->reg_set;
mips_irn_ops.cg = cg;
*****************************************************************/
static mips_isa_t mips_isa_template = {
- &mips_isa_if,
- &mips_gp_regs[REG_SP],
- &mips_gp_regs[REG_FP],
- -1, // stack direction
- 0, // num codegens?!? TODO what is this?
- NULL
+ {
+ &mips_isa_if,
+ &mips_gp_regs[REG_SP],
+ &mips_gp_regs[REG_FP],
+ -1, /* stack direction */
+ NULL, /* main environment */
+ },
+ { NULL, }, /* emitter environment */
};
/**
if(inited)
return NULL;
+ inited = 1;
- isa = xcalloc(1, sizeof(*isa));
- memcpy(isa, &mips_isa_template, sizeof(*isa));
+ isa = xcalloc(1, sizeof(isa[0]));
+ memcpy(isa, &mips_isa_template, sizeof(isa[0]));
- isa->out = file_handle;
+ be_emit_init_env(&isa->emit, file_handle);
mips_register_init(isa);
mips_create_opcodes();
mips_init_opcode_transforms();
- inited = 1;
+ /* we mark referenced global entities, so we can only emit those which
+ * are actually referenced. (Note: you mustn't use the type visited flag
+ * elsewhere in the backend)
+ */
+ inc_master_type_visited();
return isa;
}
* Closes the output file and frees the ISA structure.
*/
static void mips_done(void *self) {
- free(self);
+ mips_isa_t *isa = self;
+
+ be_gas_emit_decls(&isa->emit, isa->arch_isa.main_env, 1);
+
+ be_emit_destroy_env(&isa->emit);
+ free(isa);
}
static int mips_get_n_reg_class(const void *self) {
typedef struct {
be_abi_call_flags_bits_t flags;
- const mips_isa_t *isa;
+ const arch_isa_t *isa;
const arch_env_t *arch_env;
ir_graph *irg;
// do special handling to support debuggers
{
mips_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 = (const mips_isa_t*) arch_env->isa;
- env->debug = 1;
+ env->flags = fl.bits;
+ env->irg = irg;
+ env->arch_env = arch_env;
+ env->isa = arch_env->isa;
+ env->debug = 1;
return env;
}
static void mips_abi_dont_save_regs(void *self, pset *s)
{
mips_abi_env_t *env = self;
+
if(env->flags.try_omit_fp)
- pset_insert_ptr(s, env->isa->fp);
+ pset_insert_ptr(s, env->isa->bp);
}
static const arch_register_t *mips_abi_prologue(void *self, ir_node** mem, pmap *reg_map)
* PURPOSE.
*/
-#ifndef _BEARCH_MIPS_H_
-#define _BEARCH_MIPS_H_
+/**
+ * @file
+ * @brief declarations for the mips backend
+ * @author Matthias Braun, Mehdi
+ * @version $Id$
+ */
+#ifndef FIRM_BE_MIPS_BEARCH_MIPS_H
+#define FIRM_BE_MIPS_BEARCH_MIPS_H
#include "../bearch_t.h"
-typedef struct _mips_code_gen_t mips_code_gen_t;
+typedef struct mips_code_gen_t mips_code_gen_t;
extern const arch_isa_if_t mips_isa_if;
/** get a block schedule number */
int mips_get_block_sched_nr(ir_node *block);
-#endif /* _BEARCH_MIPS_H_ */
+#endif
* PURPOSE.
*/
-#ifndef _BEARCH_mips_T_H_
-#define _BEARCH_mips_T_H_
+/**
+ * @file
+ * @brief datastructures and declarations for the mips backend
+ * @author Matthias Braun, Mehdi
+ * @version $Id$
+ */
+#ifndef FIRM_BE_MIPS_BEARCH_MIPS_T_H
+#define FIRM_BE_MIPS_BEARCH_MIPS_T_H
#include "debug.h"
#include "irgopt.h"
#include "bearch_mips.h"
#include "mips_nodes_attr.h"
#include "../be.h"
+#include "../beemitter.h"
#include "set.h"
-typedef struct _mips_isa_t mips_isa_t;
+typedef struct mips_isa_t mips_isa_t;
+typedef struct mips_irn_ops_t mips_irn_ops_t;
+typedef struct mips_transform_env_t mips_transform_env_t;
-struct _mips_code_gen_t {
+struct mips_code_gen_t {
const arch_code_generator_if_t *impl; /**< implementation */
ir_graph *irg; /**< current irg */
const arch_env_t *arch_env; /**< the arch env */
DEBUG_ONLY(firm_dbg_module_t *mod;) /**< debugging module */
};
-struct _mips_isa_t {
- const arch_isa_if_t *impl;
- const arch_register_t *sp; /**< The stack pointer register. */
- const arch_register_t *fp; /**< The base pointer register. */
- const int stack_dir; /**< -1 for decreasing, 1 for increasing. */
- int num_codegens;
- FILE *out; /**< output file */
+struct mips_isa_t {
+ arch_isa_t arch_isa; /**< must be derived from arch_isa_t */
+
+ be_emit_env_t emit;
};
-typedef struct _mips_irn_ops_t {
+struct mips_irn_ops_t {
const arch_irn_ops_if_t *impl;
- mips_code_gen_t *cg;
-} mips_irn_ops_t;
+ mips_code_gen_t *cg;
+};
-/* this is a struct to minimize the number of parameters
- for transformation walker */
-typedef struct _mips_transform_env_t {
+/**
+ * this is a struct to minimize the number of parameters
+ * for transformation walker
+ */
+struct mips_transform_env_t {
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_mode *mode; /**< The mode of the irn */
mips_code_gen_t *cg; /**< The code generator */
DEBUG_ONLY(firm_dbg_module_t *mod;) /**< The firm debugger */
-} mips_transform_env_t;
+};
ir_node *mips_new_NoReg(mips_code_gen_t *cg);
-#endif /* _BEARCH_mips_T_H_ */
+#endif
* PURPOSE.
*/
-/* mips emitter */
-/* $Id$ */
+/**
+ * @file
+ * @brief implementation of mips assembly emitter
+ * @author Matthias Braun, Mehdi
+ * @version $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 "irargs_t.h"
#include "irprog_t.h"
#include "irouts.h"
+#include "tv.h"
#include "error.h"
#include "../besched.h"
#include "../benode_t.h"
#include "../beutil.h"
+#include "../begnuas.h"
#include "mips_emitter.h"
#include "gen_mips_emitter.h"
#include "mips_new_nodes.h"
#include "mips_map_regs.h"
+DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
+
#define SNPRINTF_BUF_LEN 128
-static const arch_env_t *arch_env = NULL;
+/**
+ * Returns the register at in position pos.
+ */
+static const arch_register_t *get_in_reg(const arch_env_t *arch_env,
+ const ir_node *node, int pos)
+{
+ ir_node *op;
+ const arch_register_t *reg = NULL;
+
+ assert(get_irn_arity(node) > pos && "Invalid IN position");
+ /* The out register of the operator at position pos is the
+ in register we need. */
+ op = get_irn_n(node, pos);
+
+ reg = arch_get_irn_register(arch_env, op);
+
+ assert(reg && "no in register found");
+ return reg;
+}
+
+/**
+ * Returns the register at out position pos.
+ */
+static const arch_register_t *get_out_reg(const arch_env_t *arch_env,
+ const ir_node *node, int pos)
+{
+ ir_node *proj;
+ const arch_register_t *reg = NULL;
+
+ /* 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(node) != mode_T) {
+ reg = arch_get_irn_register(arch_env, node);
+ } else if (is_mips_irn(node)) {
+ reg = get_mips_out_reg(node, pos);
+ } else {
+ const ir_edge_t *edge;
+
+ foreach_out_edge(node, 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;
+}
/*************************************************************
* _ _ __ _ _
* |_| |_|
*************************************************************/
+void mips_emit_source_register(mips_emit_env_t *env, const ir_node *node,
+ int pos)
+{
+ const arch_register_t *reg = get_in_reg(env->arch_env, node, pos);
+ be_emit_string(env->emit, arch_register_get_name(reg));
+}
+
+void mips_emit_dest_register(mips_emit_env_t *env, const ir_node *node,
+ int pos)
+{
+ const arch_register_t *reg = get_out_reg(env->arch_env, node, pos);
+ be_emit_string(env->emit, arch_register_get_name(reg));
+}
+
+#if 0
static const char *get_symconst_str(ir_node *node)
{
ident *id;
return buf;
}
+#endif
-/**
- * Returns node's offset as string.
- */
-static const char *node_offset_to_str(ir_node *n)
-{
- return "";
-}
-
-/* We always pass the ir_node which is a pointer. */
-static int mips_get_arg_type(const lc_arg_occ_t *occ) {
- return lc_arg_type_ptr;
-}
-
-
-/**
- * Returns the register at in position pos.
- */
-static const arch_register_t *get_in_reg(ir_node *irn, int pos)
-{
- ir_node *op;
- const arch_register_t *reg = NULL;
-
- assert(get_irn_arity(irn) > pos && "Invalid IN position");
-
- /* The out register of the operator at position pos is the
- in register we need. */
- op = get_irn_n(irn, pos);
-
- reg = arch_get_irn_register(arch_env, op);
-
- assert(reg && "no in register found");
- return reg;
-}
-
-/**
- * Returns the register at out position pos.
- */
-static const arch_register_t *get_out_reg(ir_node *irn, int pos)
-{
- ir_node *proj;
- const arch_register_t *reg = NULL;
-
- /* 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_mips_irn(irn)) {
- reg = get_mips_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_mips_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_mips_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 mips_get_reg_name(lc_appendable_t *app,
- const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
-{
- const char *buf;
- int res;
- ir_node *X = arg->v_ptr;
- int nr = occ->width - 1;
-
- if (!X)
- return lc_arg_append(app, occ, "(null)", 6);
-
- if (occ->conversion == 'S') {
- buf = get_mips_reg_name(X, nr, 1);
- }
- else { /* 'D' */
- buf = get_mips_reg_name(X, nr, 0);
- }
-
- res = lc_appendable_chadd(app, '$');
- res += lc_appendable_snadd(app, buf, strlen(buf));
- return res;
-}
-
-/**
- * Returns the tarval or offset of an mips node as a string.
- */
-static int mips_const_to_str(lc_appendable_t *app,
- const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
-{
- const char *buf;
- ir_node *X = arg->v_ptr;
-
- if (!X)
- return lc_arg_append(app, occ, "(null)", 6);
-
- if (occ->conversion == 'C') {
- buf = node_const_to_str(X);
- }
- else { /* 'O' */
- buf = node_offset_to_str(X);
- }
-
- return lc_arg_append(app, occ, buf, strlen(buf));
-}
-
-/**
- * Determines the SSE suffix depending on the mode.
- */
-static int mips_get_mode_suffix(lc_appendable_t *app,
- const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
-{
- ir_node *X = arg->v_ptr;
-
- if (!X)
- return lc_arg_append(app, occ, "(null)", 6);
-
- if (get_mode_size_bits(get_irn_mode(X)) == 32)
- return lc_appendable_chadd(app, 's');
- else
- return lc_appendable_chadd(app, 'd');
-}
-
-/**
- * Return the mips printf arg environment.
- * We use the firm environment with some additional handlers.
- */
-const lc_arg_env_t *mips_get_arg_env(void)
+void mips_emit_immediate(mips_emit_env_t *env, const ir_node *node)
{
- static lc_arg_env_t *env = NULL;
-
- static const lc_arg_handler_t mips_reg_handler = { mips_get_arg_type, mips_get_reg_name };
- static const lc_arg_handler_t mips_const_handler = { mips_get_arg_type, mips_const_to_str };
- static const lc_arg_handler_t mips_mode_handler = { mips_get_arg_type, mips_get_mode_suffix };
-
- if(env == NULL) {
- /* extend the firm printer */
- env = firm_get_arg_env();
- //lc_arg_new_env();
-
- lc_arg_register(env, "mips:sreg", 'S', &mips_reg_handler);
- lc_arg_register(env, "mips:dreg", 'D', &mips_reg_handler);
- lc_arg_register(env, "mips:cnst", 'C', &mips_const_handler);
- lc_arg_register(env, "mips:offs", 'O', &mips_const_handler);
- lc_arg_register(env, "mips:mode", 'M', &mips_mode_handler);
- }
+ const mips_attr_t *attr = get_mips_attr(node);
- return env;
+ be_emit_char(env->emit, '$');
+ tarval *tv = attr->tv;
+ be_emit_tarval(env->emit, tv);
}
/*
* 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
+char *get_unique_label(char *buf, size_t buflen, const char *prefix)
{
static unsigned long id = 0;
snprintf(buf, buflen, "%s%lu", prefix, ++id);
/* ABI Handling */
/************************************************************************/
-static void mips_emit_IncSP(const ir_node *node, mips_emit_env_t *env)
+static
+void mips_emit_IncSP(mips_emit_env_t *env, const ir_node *node)
{
- FILE *F = env->out;
int offset = be_get_IncSP_offset(node);
if(offset == 0) {
- fprintf(F, "\t\t\t\t # omitted IncSP with 0\n");
+ be_emit_cstring(env->emit, "\t/* omitted IncSP with 0 */");
+ be_emit_finish_line_gas(env->emit, node);
return;
}
}
if(offset > 0) {
- fprintf(F, "\tsubu $sp, $sp, %d\n", offset);
+ be_emit_irprintf(env->emit, "\tsubu $sp, $sp, %d", offset);
} else {
- fprintf(F, "\taddu $sp, $sp, %d\n", -offset);
+ be_emit_irprintf(env->emit, "\taddu $sp, $sp, %d", -offset);
}
+ be_emit_finish_line_gas(env->emit, node);
}
-static void mips_emit_Copy(const ir_node *node, mips_emit_env_t *env)
+static void mips_emit_Copy(mips_emit_env_t *env, const ir_node *node)
{
- FILE *F = env->out;
-
- lc_efprintf(mips_get_arg_env(), F, "\tmove %1D, %1S\t\t\t# copy\n", node, node);
+ be_emit_cstring(env->emit, "\tmove ");
+ mips_emit_dest_register(env, node, 0);
+ be_emit_cstring(env->emit, ", ");
+ mips_emit_source_register(env, node, 0);
+ be_emit_finish_line_gas(env->emit, node);
}
-static void mips_emit_Return(const ir_node* node, mips_emit_env_t *env)
+static void mips_emit_Return(mips_emit_env_t *env, const ir_node* node)
{
- FILE *F = env->out;
- fprintf(F, "\tj $ra\t\t\t\t# return\n");
+ be_emit_cstring(env->emit, "\tj $ra");
+ be_emit_finish_line_gas(env->emit, node);
}
-static void mips_emit_nops(FILE* F, int n)
+static __attribute__((unused))
+void mips_emit_nops(mips_emit_env_t *env, int n)
{
int i;
for(i = 0; i < n; ++i) {
- fprintf(F, "\tnop\n");
+ be_emit_cstring(env->emit, "\tnop\n");
+ be_emit_write_line(env->emit);
}
}
static void mips_emit_Perm(const ir_node *node, mips_emit_env_t *env)
{
- FILE *F = env->out;
-
assert(get_irn_arity(node) == 2);
- lc_efprintf(mips_get_arg_env(), F, "\txor %1S, %1S, %2S\t\t\t# perm\n", node, node, node);
- mips_emit_nops(F, 3);
- lc_efprintf(mips_get_arg_env(), F, "\txor %2S, %2S, %1S\n", node, node, node);
- mips_emit_nops(F, 3);
- lc_efprintf(mips_get_arg_env(), F, "\txor %1S, %1S, %2S\n", node, node, node);
- mips_emit_nops(F, 3);
+ be_emit_cstring(env->emit, "\txor ");
+ mips_emit_source_register(env, node, 0);
+ be_emit_cstring(env->emit, ", ");
+ mips_emit_source_register(env, node, 0);
+ be_emit_cstring(env->emit, ", ");
+ mips_emit_source_register(env, node, 1);
+ be_emit_finish_line_gas(env->emit, node);
+
+ /* mips_emit_nops(env, 3); */
+
+ be_emit_cstring(env->emit, "\txor ");
+ mips_emit_source_register(env, node, 1);
+ be_emit_cstring(env->emit, ", ");
+ mips_emit_source_register(env, node, 1);
+ be_emit_cstring(env->emit, ", ");
+ mips_emit_source_register(env, node, 0);
+ be_emit_finish_line_gas(env->emit, node);
+
+ /* mips_emit_nops(env, 3); */
+
+ be_emit_cstring(env->emit, "\txor ");
+ mips_emit_source_register(env, node, 0);
+ be_emit_cstring(env->emit, ", ");
+ mips_emit_source_register(env, node, 0);
+ be_emit_cstring(env->emit, ", ");
+ mips_emit_source_register(env, node, 1);
+ be_emit_finish_line_gas(env->emit, node);
+
+ /* mips_emit_nops(env, 3); */
}
-static void mips_emit_Spill(const ir_node* node, mips_emit_env_t *env)
+
+static void mips_emit_Spill(mips_emit_env_t *env, const ir_node *node)
{
+#if 0
FILE *F = env->out;
ir_entity *ent = be_get_frame_entity(node);
lc_efprintf(mips_get_arg_env(), F, "\tsw %1S, %d($fp)\n", node, get_entity_offset(ent));
+#endif
+ /* TODO lower spills and don't emit them... */
}
-static void mips_emit_Reload(const ir_node* node, mips_emit_env_t *env)
+static void mips_emit_Reload(mips_emit_env_t *env, const ir_node *node)
{
+#if 0
FILE *F = env->out;
ir_entity *ent = be_get_frame_entity(node);
lc_efprintf(mips_get_arg_env(), F, "\tlw %1D, %d($fp)\n", node, get_entity_offset(ent));
+#endif
+ /* TODO lower reloads instead of emitting them... */
}
/************************************************************************/
/* Calls */
/************************************************************************/
-static void mips_emit_Call(ir_node *node, mips_emit_env_t *env)
+static void mips_emit_Call(mips_emit_env_t *env, const ir_node *node)
{
- FILE *F = env->out;
- const arch_register_t *callee_reg;
+ be_emit_cstring(env->emit, "\tjal ");
// call to imediate value (label)
ir_entity *callee = be_Call_get_entity(node);
if(callee != NULL) {
- fprintf(F, "\tjal %s\n", get_entity_name(callee));
- return;
+ be_emit_ident(env->emit, get_entity_ident(callee));
+ } else {
+ mips_emit_source_register(env, node, be_pos_Call_ptr);
}
-
- // call to function pointer
- callee_reg = get_in_reg(node, be_pos_Call_ptr);
- assert(callee_reg != NULL);
-
- fprintf(F, "\tjal %s\n", arch_register_get_name(callee_reg));
+ be_emit_finish_line_gas(env->emit, node);
}
/************************************************************************
return buf;
}
-static void mips_emit_Jump(ir_node *node, mips_emit_env_t *env)
+static
+void mips_emit_block_label(mips_emit_env_t *env, const ir_node *block)
{
- FILE *F = env->out;
- const ir_node *block = get_irn_link(node);
+ be_emit_irprintf(env->emit, "BLOCK_%ld", get_irn_node_nr(block));
+}
+static void mips_emit_Jump(mips_emit_env_t *env, const ir_node *node)
+{
+ const ir_node *block = get_irn_link(node);
assert(is_Block(block));
- fprintf(F, "\tb %s\n", mips_get_block_label(block));
+ be_emit_cstring(env->emit, "\tb ");
+ mips_emit_block_label(env, block);
+ be_emit_finish_line_gas(env->emit, node);
}
ir_node *mips_get_jump_block(const ir_node* node, int projn)
return NULL;
}
+void mips_emit_jump_target_proj(mips_emit_env_t *env, const ir_node *node, int projn)
+{
+ ir_node *jumpblock = mips_get_jump_block(node, projn);
+ assert(jumpblock != NULL);
+
+ mips_emit_block_label(env, jumpblock);
+}
+
+void mips_emit_jump_target(mips_emit_env_t *env, const ir_node *node)
+{
+ ir_node *jumpblock = get_irn_link(node);
+ assert(jumpblock != NULL);
+
+ mips_emit_block_label(env, jumpblock);
+}
+
/************************************************************************
* ____ _ _ _ _ *
* / ___|_ _(_) |_ ___| |__ | |_ _ _ __ ___ _ __ *
* Emits code for a SwitchJmp (creates a jump table if
* possible otherwise a cmp-jmp cascade). Stolen from ia32
*/
-void emit_mips_jump_table(const ir_node *irn, FILE* F) {
+void emit_mips_jump_table(mips_emit_env_t *env, const ir_node *irn) {
int lastval, i, i2, pn;
jmp_tbl_t tbl;
ir_node *proj;
/* sort the branches by their number */
qsort(tbl.branches, tbl.num_branches, sizeof(tbl.branches[0]), mips_cmp_branch_t);
- fprintf(F, "%s:\n", mips_get_jumptbl_label(irn));
+ be_emit_string(env->emit, mips_get_jumptbl_label(irn));
+ be_emit_cstring(env->emit, ":\n");
+ be_emit_write_line(env->emit);
lastval = tbl.min_value;
for(i = 0; i < tbl.num_branches; ++i) {
const branch_t *branch = &tbl.branches[i];
int value = branch->value;
for(i2 = lastval + 1; i2 < value; ++i2) {
- fprintf(F, "\t.word %s\n", get_id_str(attr->symconst_id));
+ be_emit_cstring(env->emit, "\t.word ");
+ be_emit_ident(env->emit, attr->symconst_id);
+ be_emit_char(env->emit, '\n');
+ be_emit_write_line(env->emit);
}
- fprintf(F, "\t.word %s\n", mips_get_block_label(branch->target));
+ be_emit_cstring(env->emit, "\t.word ");
+ mips_emit_block_label(env, branch->target);
+ be_emit_char(env->emit, '\n');
+ be_emit_write_line(env->emit);
+
lastval = branch->value;
}
free(tbl.branches);
}
-static void dump_jump_tables(ir_node* node, void *env)
+static
+void dump_jump_tables(ir_node* node, void *data)
{
- FILE* F = (FILE*) env;
+ mips_emit_env_t *env = data;
// emit jump tables
if(is_mips_SwitchJump(node)) {
- fprintf(F, ".data\n");
- emit_mips_jump_table(node, F);
- fprintf(F, ".text\n");
+ be_emit_cstring(env->emit, ".data\n");
+ be_emit_write_line(env->emit);
+
+ emit_mips_jump_table(env, node);
+
+ be_emit_cstring(env->emit, ".text\n");
+ be_emit_write_line(env->emit);
}
}
op_Cond->ops.generic = (op_func) mips_emit_this_shouldnt_happen;
}
-typedef void (*emit_func) (const ir_node *, mips_emit_env_t *);
+typedef void (*emit_func) (mips_emit_env_t *, const ir_node *);
/**
* Emits assembly for a single node
*/
-static void mips_emit_node(ir_node *irn, mips_emit_env_t* env)
+static void mips_emit_node(mips_emit_env_t *env, const ir_node *node)
{
- mips_emit_env_t *emit_env = env;
- FILE *F = emit_env->out;
- ir_op *op = get_irn_op(irn);
- DEBUG_ONLY(firm_dbg_module_t *mod = emit_env->mod;)
-
- DBG((mod, LEVEL_1, "emitting code for %+F\n", irn));
+ ir_op *op = get_irn_op(node);
if (op->ops.generic) {
emit_func emit = (emit_func) op->ops.generic;
- (*emit) (irn, env);
-
-#if 0
- if(emit != (emit_func) mips_emit_nothing)
- mips_emit_nops(F, 5);
-#endif
+ (*emit) (env, node);
} else {
- ir_fprintf(F, "\t\t\t\t\t# %+F\n", irn);
+ be_emit_cstring(env->emit, "\t/* TODO */");
+ be_emit_finish_line_gas(env->emit, node);
}
}
* Walks over the nodes in a block connected by scheduling edges
* and emits code for each node.
*/
-void mips_gen_block(ir_node *block, void *env)
+void mips_gen_block(mips_emit_env_t *env, ir_node *block)
{
- FILE *F = ((mips_emit_env_t *)env)->out;
- ir_node *irn;
+ ir_node *node;
if (! is_Block(block))
return;
- fprintf(F, "%s:\n", mips_get_block_label(block));
- sched_foreach(block, irn) {
- mips_emit_node(irn, env);
+ mips_emit_block_label(env, block);
+ be_emit_cstring(env->emit, ":\n");
+ be_emit_write_line(env->emit);
+
+ sched_foreach(block, node) {
+ mips_emit_node(env, node);
}
- fprintf(F, "\n");
+
+ be_emit_char(env->emit, '\n');
+ be_emit_write_line(env->emit);
}
/**
* Emits code for function start.
*/
-void mips_emit_start(FILE *F, ir_graph *irg)
+void mips_emit_func_prolog(mips_emit_env_t *env, ir_graph *irg)
{
- const char *irg_name = get_entity_name(get_irg_entity(irg));
+ ident *irg_ident = get_entity_ident(get_irg_entity(irg));
+ be_emit_env_t *eenv = env->emit;
// dump jump tables
- irg_walk_graph(irg, NULL, dump_jump_tables, F);
+ irg_walk_graph(irg, NULL, dump_jump_tables, env);
+
+ be_emit_write_line(eenv);
+ be_gas_emit_switch_section(eenv, GAS_SECTION_TEXT);
+
+ be_emit_cstring(eenv, "\t.balign\t4\n");
+
+ be_emit_cstring(eenv, "\t.global\t")
+ be_emit_ident(eenv, irg_ident);
+ be_emit_char(eenv, '\n');
- fprintf(F, "\n\n");
- fprintf(F, "\t.balign\t4\n");
- fprintf(F, "\t.global\t%s\n", irg_name);
- fprintf(F, "\t.set\tnomips16\n");
- fprintf(F, "\t.ent\t%s\n", irg_name);
- fprintf(F, "%s:\n", irg_name);
- fprintf(F, "\t.frame\t$fp, 24, $ra\n");
- fprintf(F, "\t.mask\t0xc0000000, -4\n");
- fprintf(F, "\t.fmask\t0x00000000, 0\n");
+ be_emit_cstring(eenv, "\t.set\tnomips16\n");
+
+ be_emit_cstring(eenv, "\t.ent\t");
+ be_emit_ident(eenv, irg_ident);
+ be_emit_char(eenv, '\n');
+
+ be_emit_ident(eenv, irg_ident);
+ be_emit_cstring(eenv, ":\n");
+
+ be_emit_cstring(eenv, "\t.frame\t$fp, 24, $ra\n");
+ be_emit_cstring(eenv, "\t.mask\t0xc0000000, -4\n");
+ be_emit_cstring(eenv, "\t.fmask\t0x00000000, 0\n");
+
+ be_emit_write_line(eenv);
}
/**
* Emits code for function end
*/
-void mips_emit_end(FILE *F, ir_graph *irg)
+void mips_emit_func_epilog(mips_emit_env_t *env, ir_graph *irg)
{
- const char *irg_name = get_entity_name(get_irg_entity(irg));
- fprintf(F, "\t.end\t%s\n", irg_name);
+ ident *irg_ident = get_entity_ident(get_irg_entity(irg));
+
+ be_emit_cstring(env->emit, "\t.end\t");
+ be_emit_ident(env->emit, irg_ident);
+ be_emit_char(env->emit, '\n');
+ be_emit_write_line(env->emit);
}
/**
* Sets labels for control flow nodes (jump target)
- * TODO: Jump optimization
*/
void mips_gen_labels(ir_node *block, void *env)
{
/**
* Main driver
*/
-void mips_gen_routine(FILE *F, ir_graph *irg, const mips_code_gen_t *cg)
+void mips_gen_routine(mips_code_gen_t *cg, ir_graph *irg)
{
- mips_emit_env_t emit_env;
+ mips_emit_env_t env;
int i, n;
- emit_env.out = F;
- emit_env.arch_env = cg->arch_env;
- emit_env.cg = cg;
- FIRM_DBG_REGISTER(emit_env.mod, "firm.be.mips.emit");
+ env.isa = (mips_isa_t*) cg->arch_env->isa;
+ env.emit = &env.isa->emit;
+ env.arch_env = cg->arch_env;
+ env.cg = cg;
- /* set the global arch_env (needed by print hooks) */
- arch_env = cg->arch_env;
+ mips_register_emitters();
- irg_block_walk_graph(irg, mips_gen_labels, NULL, &emit_env);
- mips_emit_start(F, irg);
-// irg_walk_blkwise_graph(irg, NULL, mips_gen_block, &emit_env);
+ irg_block_walk_graph(irg, mips_gen_labels, NULL, &env);
+
+ mips_emit_func_prolog(&env, irg);
dump_ir_block_graph_sched(irg, "-kaputtelist");
for (i = 0, n = mips_get_sched_n_blocks(cg); i < n; ++i) {
ir_node *block = mips_get_sched_block(cg, i);
- mips_gen_block(block, &emit_env);
+ mips_gen_block(&env, block);
}
- mips_emit_end(F, irg);
+ mips_emit_func_epilog(&env, irg);
+}
+
+void mips_init_emitter(void)
+{
+ FIRM_DBG_REGISTER(dbg, "firm.be.mips.emitter");
}
* PURPOSE.
*/
-#ifndef _mips_EMITTER_H_
-#define _mips_EMITTER_H_
+/**
+ * @file
+ * @brief declarations for the mips assembler emitter
+ * @author Matthias Braun, Mehdi
+ * @version $Id$
+ */
+#ifndef FIRM_BE_MIPS_MIPS_EMITTER_H
+#define FIRM_BE_MIPS_MIPS_EMITTER_H
-#include "irargs_t.h" // this also inlucdes <libcore/lc_print.h>
#include "irnode.h"
-#include "debug.h"
-#include "../bearch_t.h"
+#include "../bearch.h"
+#include "../beemitter.h"
#include "bearch_mips_t.h"
-typedef struct _mips_emit_env_t {
- FILE *out;
- const arch_env_t *arch_env;
+typedef struct mips_emit_env_t mips_emit_env_t;
+
+struct mips_emit_env_t {
+ be_emit_env_t *emit;
+ const arch_env_t *arch_env;
const mips_code_gen_t *cg;
- DEBUG_ONLY(firm_dbg_module_t *mod;)
-} mips_emit_env_t;
+ mips_isa_t *isa;
+};
-const lc_arg_env_t *mips_get_arg_env(void);
+void mips_emit_source_register(mips_emit_env_t *env, const ir_node *node, int pos);
+void mips_emit_dest_register(mips_emit_env_t *env, const ir_node *node, int pos);
+void mips_emit_immediate(mips_emit_env_t *env, const ir_node *node);
+void mips_emit_jump_target(mips_emit_env_t *env, const ir_node *node);
+void mips_emit_jump_target_proj(mips_emit_env_t *env, const ir_node *node,
+ int pn);
void equalize_dest_src(FILE *F, ir_node *n);
int get_mips_reg_nr(ir_node *irn, int posi, int in_out);
const char *get_mips_in_reg_name(ir_node *irn, int pos);
-void mips_gen_routine(FILE *F, ir_graph *irg, const mips_code_gen_t *cg);
void mips_register_emitters(void);
ir_node *mips_get_jump_block(const ir_node* node, int projn);
/** returns the label for the jumptable */
const char* mips_get_jumptbl_label(const ir_node* switchjmp);
-#endif /* _mips_EMITTER_H_ */
+void mips_gen_routine(mips_code_gen_t *cg, ir_graph *irg);
+
+#endif
+++ /dev/null
-/*
- * Copyright (C) 1995-2007 University of Karlsruhe. All right reserved.
- *
- * This file is part of libFirm.
- *
- * This file may be distributed and/or modified under the terms of the
- * GNU General Public License version 2 as published by the Free Software
- * Foundation and appearing in the file LICENSE.GPL included in the
- * packaging of this file.
- *
- * Licensees holding valid libFirm Professional Edition licenses may use
- * this file in accordance with the libFirm Commercial License.
- * Agreement provided with the Software.
- *
- * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
- * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE.
- */
-
-/**
- * Dumps global variables and constants as mips assembler.
- * @date 14.02.2006
- * @version $Id$
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <assert.h>
-
-#include "xmalloc.h"
-#include "obst.h"
-
-#include "tv.h"
-#include "irnode.h"
-#include "entity.h"
-#include "irprog.h"
-
-#include "mips_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 mips_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 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_ofs_ent:
- obstack_printf(obst, "%d", get_entity_offset(get_SymConst_entity(init)));
- break;
-
- case symconst_type_size:
- obstack_printf(obst, "%d", get_type_size_bytes(get_SymConst_type(init)));
- break;
-
- case symconst_type_align:
- obstack_printf(obst, "%d", get_type_alignment_bytes(get_SymConst_type(init)));
- break;
-
- case symconst_enum_const:
- tv = get_enumeration_value(get_SymConst_enum(init));
- dump_arith_tarval(obst, tv, bytes);
- 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.half\t");
- break;
-
- case 4:
- obstack_printf(obst, "\t.word\t");
- 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(ir_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, ir_entity *ent)
-{
- int i, n;
-
- obstack_printf(obst, "\t.asciiz \"");
- 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, ir_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)) {
- ir_variability variability = get_entity_variability(ent);
- ir_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);
- }
-
- align = get_type_alignment_bytes(ty);
- mips_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) {
- ir_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.space\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.space\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++) {
- ir_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++) {
- ir_entity *step = get_compound_graph_path_node(path, j);
- ir_type *step_type = get_entity_type(step);
- int ent_ofs = get_entity_offset(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 mips_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 mips_gen_decls(FILE *out) {
- struct obstack rodata, data, comm;
- int size;
- char *cp;
-
- obstack_init(&rodata);
- obstack_init(&data);
- obstack_init(&comm);
-
- mips_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.data\n");
- fwrite(cp, 1, size, out);
- }
-
- size = obstack_object_size(&comm);
- cp = obstack_finish(&comm);
- if (size > 0) {
- fprintf(out, "\t.data\n");
- fwrite(cp, 1, size, out);
- }
-
- obstack_free(&rodata, NULL);
- obstack_free(&data, NULL);
- obstack_free(&comm, NULL);
-}
+++ /dev/null
-/*
- * Copyright (C) 1995-2007 University of Karlsruhe. All right reserved.
- *
- * This file is part of libFirm.
- *
- * This file may be distributed and/or modified under the terms of the
- * GNU General Public License version 2 as published by the Free Software
- * Foundation and appearing in the file LICENSE.GPL included in the
- * packaging of this file.
- *
- * Licensees holding valid libFirm Professional Edition licenses may use
- * this file in accordance with the libFirm Commercial License.
- * Agreement provided with the Software.
- *
- * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
- * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE.
- */
-
-#ifndef _MIPS_GEN_DECLS_H_
-#define _MIPS_GEN_DECLS_H_
-
-/**
- * Generate all entities.
- */
-void mips_gen_decls(FILE *out);
-
-#endif /* _MIPS_GEN_DECLS_H_ */
*/
/**
- * Register mapping for firm nodes. Stolen from bearch_firm :)
- * $Id$
+ * @file
+ * @brief Register mapping for firm nodes. Stolen from bearch_firm :)
+ * @author Matthias Braun, Mehdi
+ * @version $Id$
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
* PURPOSE.
*/
-#ifndef _mips_MAP_REGS_H_
-#define _mips_MAP_REGS_H_
+/**
+ * @file
+ * @brief mips register allocation interface
+ * @author Matthias Braun, Mehdi
+ * @version $Id$
+ */
+#ifndef FIRM_BE_MIPS_MIPS_MAP_REGS_H
+#define FIRM_BE_MIPS_MIPS_MAP_REGS_H
#include "irnode.h"
#include "set.h"
long mips_translate_proj_pos(const ir_node *proj);
-#endif /* _mips_MAP_REGS_H_ */
+#endif
*/
/**
- * This file implements the creation of the achitecture specific firm opcodes
- * and the coresponding node constructors for the mips assembler irg.
- * $Id$
+ * @file
+ * @brief This file implements the creation of the achitecture specific firm
+ * opcodes and the coresponding node constructors for the mips
+ * assembler irg.
+ * @author Matthias Braun, Mehdi
+ * @version $Id$
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
* PURPOSE.
*/
-#ifndef _mips_NEW_NODES_H_
-#define _mips_NEW_NODES_H_
-
/**
- * Function prototypes for the assembler ir node constructors.
- * $Id$
+ * @file
+ * @brief Function prototypes for the assembler ir node constructors.
+ * @author Matthias Braun, Mehdi
+ * @version $Id$
*/
+#ifndef FIRM_BE_MIPS_MIPS_NEW_NODES_H
+#define FIRM_BE_MIPS_MIPS_NEW_NODES_H
#include "mips_nodes_attr.h"
/* Include the generated headers */
#include "gen_mips_new_nodes.h"
-#endif /* _mips_NEW_NODES_H_ */
+#endif
* PURPOSE.
*/
-#ifndef _MIPS_NODES_ATTR_H_
-#define _MIPS_NODES_ATTR_H_
+/**
+ * @file
+ * @brief declaration of attributes for mips nodes
+ * @author Matthias Braun
+ * @version $Id$
+ */
+#ifndef FIRM_BE_MIPS_MIPS_NODES_ATTR_H
+#define FIRM_BE_MIPS_MIPS_NODES_ATTR_H
#include "../bearch_t.h"
#include "irmode_t.h"
const arch_register_t *slots[1]; /**< register slots for assigned registers */
} mips_attr_t;
-#endif /* _mips_NODES_ATTR_H_ */
+#endif
* PURPOSE.
*/
-/* Mips implementation of list scheduler selector */
-/* $Id$ */
+/**
+ * @file
+ * @brief Mips implementation of list scheduler selector
+ * @author Matthias Braun, Mehdi
+ * @version $Id$
+ */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
# the cpu architecture (ia32, ia64, mips, sparc, ppc, ...)
$arch = "mips";
-
-# this strings mark the beginning and the end of a comment in emit
-$comment_string = "#";
-$comment_string_end = "";
+$new_emit_syntax = 1;
# The node description is done as a perl hash initializer with the
# following structure:
],
); # %reg_classes
+%emit_templates = (
+ S1 => "${arch}_emit_source_register(env, node, 0);",
+ S2 => "${arch}_emit_source_register(env, node, 1);",
+ S3 => "${arch}_emit_source_register(env, node, 2);",
+ D1 => "${arch}_emit_dest_register(env, node, 0);",
+ D2 => "${arch}_emit_dest_register(env, node, 1);",
+ D3 => "${arch}_emit_dest_register(env, node, 2);",
+ C => "${arch}_emit_immediate(env, node);",
+ JumpTarget => "${arch}_emit_jump_target(env, node);",
+ JumpTarget1 => "${arch}_emit_jump_target_proj(env, node, 1);",
+);
+
+
#--------------------------------------------------#
# _ #
# (_) #
sl => {
reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] },
emit => '
- if (mode_is_signed(get_irn_mode(n))) {
-2. sal %D1, %S1, %S2
+ if (mode_is_signed(get_irn_mode(node))) {
+ . sal %D1, %S1, %S2
} else {
-2. sll %D1, %S1, %S2
+ . sll %D1, %S1, %S2
}
',
mode => "mode_Iu",
sli => {
reg_req => { in => [ "gp" ], out => [ "gp" ] },
emit => '
- if (mode_is_signed(get_irn_mode(n))) {
-2. sal %D1, %S1, %C
+ if (mode_is_signed(get_irn_mode(node))) {
+ . sal %D1, %S1, %C
} else {
-2. sll %D1, %S1, %C
+ . sll %D1, %S1, %C
}
',
mode => "mode_Iu",
sr => {
reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] },
emit => '
- if (mode_is_signed(get_irn_mode(n))) {
-2. sra %D1, %S1, %S2
+ if (mode_is_signed(get_irn_mode(node))) {
+ . sra %D1, %S1, %S2
} else {
-2. srl %D1, %S1, %S2
+ . srl %D1, %S1, %S2
}
',
mode => "mode_Iu",
sri => {
reg_req => { in => [ "gp" ], out => [ "gp" ] },
emit => '
- if (mode_is_signed(get_irn_mode(n))) {
-2. sra %D1, %S1, %C
+ if (mode_is_signed(get_irn_mode(node))) {
+ . sra %D1, %S1, %C
} else {
-2. srl %D1, %S1, %C
+ . srl %D1, %S1, %C
}
',
mode => "mode_Iu"
slt => {
reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] },
emit => '
- if (mode_is_signed(get_irn_mode(n))) {
-2. slt %D1, %S1, %S2
+ if (mode_is_signed(get_irn_mode(node))) {
+ . slt %D1, %S1, %S2
}
else {
-2. sltu %D1, %S1, %S2
+ . sltu %D1, %S1, %S2
}
',
mode => "mode_Iu",
slti => {
reg_req => { in => [ "gp" ], out => [ "gp" ] },
emit => '
- if (mode_is_signed(get_irn_mode(n))) {
-2. slti %D1, %S1, %C
+ if (mode_is_signed(get_irn_mode(node))) {
+ . slti %D1, %S1, %C
}
else {
-2. sltiu %D1, %S1, %C
+ . sltiu %D1, %S1, %C
}
',
cmp_attr => 'return attr_a->tv != attr_b->tv;',
op_flags => "X|Y",
# TxT -> TxX
reg_req => { in => [ "gp", "gp" ], out => [ "in_r0", "none" ] },
- emit => '
- ir_node *jumpblock = mips_get_jump_block(n, 1);
- assert(jumpblock != NULL);
-
- (void) cmd_buf;
- (void) cmnt_buf;
- lc_efprintf(arg_env, F, "\tbeq %1S, %2S, BLOCK_%d\n", n, n, get_irn_node_nr(jumpblock));
-'
+ emit => '. beq %S1, %S2, %JumpTarget1'
},
bne => {
op_flags => "X|Y",
# TxT -> TxX
reg_req => { in => [ "gp", "gp" ], out => [ "in_r0", "none" ] },
- emit => '
- ir_node *jumpblock = mips_get_jump_block(n, 1);
- assert(jumpblock != NULL);
-
- (void) cmd_buf;
- (void) cmnt_buf;
- lc_efprintf(arg_env, F, "\tbne %1S, %2S, BLOCK_%d\n", n, n, get_irn_node_nr(jumpblock));
-'
+ emit => '. bne %S1, %S2, %JumpTarget1'
},
bgtz => {
op_flags => "X|Y",
# TxT -> TxX
reg_req => { in => [ "gp" ], out => [ "in_r0", "none" ] },
- emit => '
- ir_node *jumpblock = mips_get_jump_block(n, 1);
- assert(jumpblock != NULL);
-
- (void) cmd_buf;
- (void) cmnt_buf;
- lc_efprintf(arg_env, F, "\tbgtz %1S, BLOCK_%d\n", n, get_irn_node_nr(jumpblock));
-'
+ emit => '. bgtz %S1, %JumpTarget1'
},
blez => {
op_flags => "X|Y",
# TxT -> TxX
reg_req => { in => [ "gp" ], out => [ "in_r0", "none" ] },
- emit => '
- ir_node *jumpblock = mips_get_jump_block(n, 1);
- assert(jumpblock != NULL);
-
- (void) cmd_buf;
- (void) cmnt_buf;
- lc_efprintf(arg_env, F, "\tblez %1S, BLOCK_%d\n", n, get_irn_node_nr(jumpblock));
-'
+ emit => '. blez %S1, %JumpTarget1'
},
j => {
op_flags => "X",
# -> X
reg_req => { in => [ ], out => [ "none" ] },
- emit => '
- ir_node *jumpblock = get_irn_link(n);
- assert(jumpblock != NULL);
-
- (void) cmd_buf;
- (void) cmnt_buf;
- lc_efprintf(arg_env, F, "\tb BLOCK_%d\t\t\t# mips_b\n", get_irn_node_nr(jumpblock));
-'
+ emit => '. b %JumpTarget'
},
fallthrough => {
op_flags => "X",
# -> X
reg_req => { in => [ ], out => [ "none" ] },
- emit => '. # fallthrough'
+ emit => '. /* fallthrough to %JumpTarget */'
},
SwitchJump => {
load_r => {
reg_req => { in => [ "none", "gp" ], out => [ "none", "none", "gp" ] },
emit => '
- mips_attr_t* attr = get_mips_attr(n);
+ mips_attr_t* attr = get_mips_attr(node);
ir_mode *mode;
mode = attr->modes.load_store_mode;
switch (get_mode_size_bits(mode)) {
case 8:
if (mode_is_signed(mode)) {
-3. lb %D3, %C(%S2)
+ . lb %D3, %C(%S2)
} else {
-3. lbu %D3, %C(%S2)
+ . lbu %D3, %C(%S2)
}
break;
case 16:
if (mode_is_signed(mode)) {
-3. lh %D3, %C(%S2)
+ . lh %D3, %C(%S2)
} else {
-3. lhu %D3, %C(%S2)
+ . lhu %D3, %C(%S2)
}
break;
case 32:
-2. lw %D3, %C(%S2)
+ . lw %D3, %C(%S2)
break;
default:
assert(! "Only 8, 16 and 32 bit loads supported");
store_r => {
reg_req => { in => [ "none", "gp", "gp" ], out => [ "none", "none" ] },
emit => '
- mips_attr_t* attr = get_mips_attr(n);
+ mips_attr_t* attr = get_mips_attr(node);
ir_mode* mode;
mode = attr->modes.load_store_mode;
switch (get_mode_size_bits(mode)) {
case 8:
if (mode_is_signed(mode))
-2. sb %S3, %C(%S2)
+ . sb %S3, %C(%S2)
break;
case 16:
if (mode_is_signed(mode))
-2. sh %S3, %C(%S2)
+ . sh %S3, %C(%S2)
break;
case 32:
-2. sw %S3, %C(%S2)
+ . sw %S3, %C(%S2)
break;
default:
assert(! "Only 8, 16 and 32 bit stores supported");
store_i => {
reg_req => { in => [ "none", "none", "gp" ], out => [ "none", "none" ] },
emit => '
- mips_attr_t* attr = get_mips_attr(n);
+ mips_attr_t* attr = get_mips_attr(node);
ir_mode *mode;
mode = attr->modes.load_store_mode;
switch (get_mode_size_bits(mode)) {
case 8:
-2. sb %S3, %C
+ . sb %S3, %C
break;
case 16:
-2. sh %S3, %C
+ . sh %S3, %C
break;
case 32:
-2. sw %S3, %C
+ . sw %S3, %C
break;
default:
assert(! "Only 8, 16 and 32 bit stores supported");
* PURPOSE.
*/
-/* The codegenrator (transform FIRM into mips FIRM */
-/* $Id$ */
-
+/**
+ * @file
+ * @brief The codegenrator (transform FIRM into mips FIRM
+ * @author Matthias Braun, Mehdi
+ * @version $Id$
+ */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
* PURPOSE.
*/
-#ifndef _MIPS_TRANSFORM_H_
-#define _MIPS_TRANSFORM_H_
+/**
+ * @file
+ * @brief declarations for code transform (code selection)
+ * @author Matthias Braun, Mehdi
+ * @version $Id$
+ */
+#ifndef FIRM_BE_MIPS_MIPS_TRANSFORM_H
+#define FIRM_BE_MIPS_MIPS_TRANSFORM_H
/**
* Create Firm assembler for a copyB node.
void mips_transform_node(ir_node *node, void *env);
void mips_after_ra_walker(ir_node *node, void *env);
-#endif /* _MIPS_TRANSFORM_H_ */
+#endif
* PURPOSE.
*/
-#ifndef _MIPS_UTIL_H_
-#define _MIPS_UTIL_H_
+/**
+ * @file
+ * @brief utility macros for mips backend
+ * @author Matthias Braun, Mehdi
+ * @version $Id$
+ */
+#ifndef FIRM_BE_MIPS_MIPS_UTIL_H
+#define FIRM_BE_MIPS_MIPS_UTIL_H
#define ASSERT_NO_FLOAT(mode) { assert( (!mode_is_float(mode)) && "floating point not supported (yet)"); }
-#endif /* _MIPS_UTIL_H_ */
+#endif