uses the generic pointer in ir_op to register the emitters
[libfirm] / ir / be / ia32 / ia32_emitter.c
index 650e0c1..c138bd4 100644 (file)
@@ -12,6 +12,7 @@
 #include "irprintf.h"
 #include "irop_t.h"
 #include "irargs_t.h"
+#include "irprog_t.h"
 
 #include "../besched.h"
 
 # define obstack_chunk_free free
 #endif
 
+extern int obstack_printf(struct obstack *obst, char *fmt, ...);
+
 #define SNPRINTF_BUF_LEN 128
 
 static const arch_env_t *arch_env = NULL;
 
+/**
+ * Emits registers and/or address mode of a binary operation.
+ */
 char *ia32_emit_binop(const ir_node *n) {
        static char *buf = NULL;
 
@@ -65,6 +71,9 @@ char *ia32_emit_binop(const ir_node *n) {
        return buf;
 }
 
+/**
+ * Emits registers and/or address mode of a unary operation.
+ */
 char *ia32_emit_unop(const ir_node *n) {
        static char *buf = NULL;
 
@@ -89,6 +98,9 @@ char *ia32_emit_unop(const ir_node *n) {
        return buf;
 }
 
+/**
+ * Emits adressmode.
+ */
 char *ia32_emit_am(const ir_node *n) {
        ia32_am_flavour_t am_flav    = get_ia32_am_flavour(n);
        int               had_output = 0;
@@ -121,7 +133,7 @@ char *ia32_emit_am(const ir_node *n) {
                lc_eoprintf(ia32_get_arg_env(), obst, "%2S", n);
 
                if (am_flav & ia32_S) {
-                       obstack_printf(obst, "*%d", get_ia32_am_scale(n));
+                       obstack_printf(obst, "*%d", 1 << get_ia32_am_scale(n));
                }
 
                had_output = 1;
@@ -229,13 +241,18 @@ int get_ia32_reg_nr(ir_node *irn, int pos, int in_out) {
        return arch_register_get_index(reg);
 }
 
+enum io_direction {
+  IN_REG,
+  OUT_REG
+};
+
 /**
  * Returns the name of the in register at position pos.
  */
-const char *get_ia32_reg_name(ir_node *irn, int pos, int in_out) {
+static const char *get_ia32_reg_name(ir_node *irn, int pos, enum io_direction in_out) {
        const arch_register_t *reg;
 
-       if (in_out == 1) {
+       if (in_out == IN_REG) {
                reg = get_in_reg(irn, pos);
        }
        else {
@@ -258,12 +275,7 @@ static int ia32_get_reg_name(lc_appendable_t *app,
        if (!X)
                return lc_arg_append(app, occ, "(null)", 6);
 
-       if (occ->conversion == 'S') {
-               buf = get_ia32_reg_name(X, nr, 1);
-       }
-       else { /* 'D' */
-               buf = get_ia32_reg_name(X, nr, 0);
-       }
+  buf = get_ia32_reg_name(X, nr, occ->conversion == 'S' ? IN_REG : OUT_REG);
 
        lc_appendable_chadd(app, '%');
        return lc_arg_append(app, occ, buf, strlen(buf));
@@ -762,77 +774,106 @@ void emit_ia32_Call(ir_node *irn, emit_env_t *emit_env) {
  ***********************************************************************************/
 
 /**
- * Emits code for a node.
+ * Enters the emitter functions for handled nodes into the generic
+ * pointer of an opcode.
  */
-void ia32_emit_node(ir_node *irn, void *env) {
-       emit_env_t *emit_env   = env;
-       firm_dbg_module_t *mod = emit_env->mod;
-       FILE              *F   = emit_env->out;
+void ia32_register_emitters(void) {
+  int i;
 
-       DBG((mod, LEVEL_1, "emitting code for %+F\n", irn));
+#define BEGIN()      if (0)
+#define IA32_EMIT(a) else if (op_ia32_##a == op) op->ops.generic = (op_func)emit_ia32_##a
+#define EMIT(a)      else if (op_##a == op)      op->ops.generic = (op_func)emit_##a
+#define END()        else op->ops.generic = (op_func)NULL
+
+  for (i = get_irp_n_opcodes() - 1; i >= 0; --i) {
+    ir_op *op = get_irp_opcode(i);
+
+    BEGIN();
+         /* generated int emitter functions */
+         IA32_EMIT(Const);
+
+         IA32_EMIT(Add);
+         IA32_EMIT(Sub);
+         IA32_EMIT(Minus);
+         IA32_EMIT(Inc);
+         IA32_EMIT(Dec);
 
-#define IA32_EMIT(a) if (is_ia32_##a(irn))               { emit_ia32_##a(irn, emit_env); return; }
-#define EMIT(a)      if (get_irn_opcode(irn) == iro_##a) { emit_##a(irn, emit_env); return; }
+         IA32_EMIT(Max);
+         IA32_EMIT(Min);
+         IA32_EMIT(CMov);
 
-       /* generated int emitter functions */
-       IA32_EMIT(Const);
+         IA32_EMIT(And);
+         IA32_EMIT(Or);
+         IA32_EMIT(Eor);
+         IA32_EMIT(Not);
 
-       IA32_EMIT(Add);
-       IA32_EMIT(Sub);
-       IA32_EMIT(Minus);
-       IA32_EMIT(Inc);
-       IA32_EMIT(Dec);
+         IA32_EMIT(Shl);
+         IA32_EMIT(Shr);
+         IA32_EMIT(Shrs);
+         IA32_EMIT(RotL);
+         IA32_EMIT(RotR);
 
-       IA32_EMIT(Max);
-       IA32_EMIT(Min);
-       IA32_EMIT(CMov);
+         IA32_EMIT(Lea);
 
-       IA32_EMIT(And);
-       IA32_EMIT(Or);
-       IA32_EMIT(Eor);
-       IA32_EMIT(Not);
+         IA32_EMIT(Mul);
 
-       IA32_EMIT(Shl);
-       IA32_EMIT(Shr);
-       IA32_EMIT(Shrs);
-       IA32_EMIT(RotL);
-       IA32_EMIT(RotR);
+         IA32_EMIT(Cdq);
+         IA32_EMIT(DivMod);
 
-       IA32_EMIT(Lea);
+         IA32_EMIT(Store);
+         IA32_EMIT(Load);
 
-       IA32_EMIT(Mul);
+         IA32_EMIT(CopyB);
+         IA32_EMIT(CopyB_i);
 
-       IA32_EMIT(Cdq);
-       IA32_EMIT(DivMod);
+         /* generated floating point emitter */
+         IA32_EMIT(fConst);
 
-       IA32_EMIT(Store);
-       IA32_EMIT(Load);
+         IA32_EMIT(fAdd);
+         IA32_EMIT(fSub);
 
-       IA32_EMIT(CopyB);
-       IA32_EMIT(CopyB_i);
+         IA32_EMIT(fMul);
+         IA32_EMIT(fDiv);
 
-       /* generated floating point emitter */
-       IA32_EMIT(fConst);
+         IA32_EMIT(fMin);
+         IA32_EMIT(fMax);
 
-       IA32_EMIT(fAdd);
-       IA32_EMIT(fSub);
+         IA32_EMIT(fLoad);
+         IA32_EMIT(fStore);
 
-       IA32_EMIT(fMul);
-       IA32_EMIT(fDiv);
+         /* other emitter functions */
+         IA32_EMIT(CondJmp);
+         IA32_EMIT(SwitchJmp);
+         IA32_EMIT(Call);
 
-       IA32_EMIT(fMin);
-       IA32_EMIT(fMax);
+         EMIT(Jmp);
+         EMIT(Proj);
 
-       IA32_EMIT(fLoad);
-       IA32_EMIT(fStore);
+    END();
+  }
 
-       /* other emitter functions */
-       IA32_EMIT(CondJmp);
-       IA32_EMIT(SwitchJmp);
-       IA32_EMIT(Call);
+#undef BEGIN
+#undef IA32_EMIT
+#undef EMIT
+#undef END
+
+}
+
+/**
+ * Emits code for a node.
+ */
+static void ia32_emit_node(ir_node *irn, void *env) {
+       emit_env_t *emit_env   = env;
+       firm_dbg_module_t *mod = emit_env->mod;
+       FILE              *F   = emit_env->out;
+  ir_op             *op = get_irn_op(irn);
+
+       DBG((mod, LEVEL_1, "emitting code for %+F\n", irn));
 
-       EMIT(Jmp);
-       EMIT(Proj);
+  if (op->ops.generic) {
+    void (*emit)(ir_node *, void *) = (void (*)(ir_node *, void *))op->ops.generic;
+    (*emit)(irn, env);
+  }
 
        ir_fprintf(F, "\t\t\t\t\t/* %+F */\n", irn);
 }
@@ -841,7 +882,7 @@ void ia32_emit_node(ir_node *irn, void *env) {
  * Walks over the nodes in a block connected by scheduling edges
  * and emits code for each node.
  */
-void ia32_gen_block(ir_node *block, void *env) {
+static void ia32_gen_block(ir_node *block, void *env) {
        ir_node *irn;
 
        if (! is_Block(block))
@@ -891,7 +932,7 @@ void ia32_gen_labels(ir_node *block, void *env) {
 }
 
 /**
- * Main driver
+ * Main driver. Emits the code for one routine.
  */
 void ia32_gen_routine(FILE *F, ir_graph *irg, const ia32_code_gen_t *cg) {
        emit_env_t emit_env;