First version of mips target
authorGuillaume Emont <guijemont@igalia.com>
Fri, 5 Oct 2012 14:03:32 +0000 (16:03 +0200)
committerGuillaume Emont <guijemont@igalia.com>
Fri, 28 Dec 2012 10:43:28 +0000 (11:43 +0100)
Only generates asm code, and only support loadl, storel and addl for now.

configure.ac
orc/Makefile.am
orc/orc.c
orc/orcinternal.h
orc/orcmips.c [new file with mode: 0644]
orc/orcmips.h [new file with mode: 0644]
orc/orcprogram-mips.c [new file with mode: 0644]
orc/orcrules-mips.c [new file with mode: 0644]

index c7eb1990df7de7af6abea4847ceb297566199c35..071d914355cb46e77df730a05a01c08b4752e871 100644 (file)
@@ -119,7 +119,7 @@ AC_SUBST(PTHREAD_CFLAGS)
 AC_SUBST(PTHREAD_LIBS)
 
 AC_ARG_ENABLE(backend,
-  AC_HELP_STRING([--enable-backend],[sse,mmx,neon,arm,all (default all)]),
+  AC_HELP_STRING([--enable-backend],[sse,mmx,neon,arm,mips,all (default all)]),
     [], [enable_backend=all])
 case "${enable_backend}" in
   sse)
@@ -146,6 +146,10 @@ case "${enable_backend}" in
     ENABLE_BACKEND_C64X=yes
     AC_DEFINE(ENABLE_BACKEND_C64X, 1, [Enable c64x backend])
     ;;
+  mips)
+    ENABLE_BACKEND_MIPS=yes
+    AC_DEFINE(ENABLE_BACKEND_MIPS, 1, [Enable MIPS backend])
+    ;;
   all|auto)
     ENABLE_BACKEND_SSE=yes
     AC_DEFINE(ENABLE_BACKEND_SSE, 1, [Enable SSE backend])
@@ -159,6 +163,8 @@ case "${enable_backend}" in
     AC_DEFINE(ENABLE_BACKEND_ARM, 1, [Enable Arm backend])
     ENABLE_BACKEND_C64X=yes
     AC_DEFINE(ENABLE_BACKEND_C64X, 1, [Enable c64x backend])
+    ENABLE_BACKEND_MIPS=yes
+    AC_DEFINE(ENABLE_BACKEND_MIPS, 1, [Enable MIPS backend])
     ;;
 esac
 AM_CONDITIONAL(ENABLE_BACKEND_SSE, test "x$ENABLE_BACKEND_SSE" = "xyes")
@@ -167,6 +173,7 @@ AM_CONDITIONAL(ENABLE_BACKEND_ALTIVEC, test "x$ENABLE_BACKEND_ALTIVEC" = "xyes")
 AM_CONDITIONAL(ENABLE_BACKEND_NEON, test "x$ENABLE_BACKEND_NEON" = "xyes")
 AM_CONDITIONAL(ENABLE_BACKEND_ARM, test "x$ENABLE_BACKEND_ARM" = "xyes")
 AM_CONDITIONAL(ENABLE_BACKEND_C64X, test "x$ENABLE_BACKEND_C64X" = "xyes")
+AM_CONDITIONAL(ENABLE_BACKEND_MIPS, test "x$ENABLE_BACKEND_MIPS" = "xyes")
 
 
 AC_DEFINE(ORC_EXPORTS, 1, [Defined for compiling internal code])
index 1b6d879c59c9db2694af28e5f00793f511971cfa..f31d1834e8b6d8699227262db9c49728ab606002 100644 (file)
@@ -58,6 +58,9 @@ endif
 if ENABLE_BACKEND_C64X
 liborc_@ORC_MAJORMINOR@_la_SOURCES += orcprogram-c64x-c.c
 endif
+if ENABLE_BACKEND_MIPS
+liborc_@ORC_MAJORMINOR@_la_SOURCES += orcmips.c orcprogram-mips.c orcrules-mips.c
+endif
 
 if HAVE_I386
 liborc_@ORC_MAJORMINOR@_la_SOURCES += orccpu-x86.c
index 49f350f96d7e2b312ee425c2efeb29e1c096e8d3..55ac93437dc0c95565d96524ab4e3a36c3b5214b 100644 (file)
--- a/orc/orc.c
+++ b/orc/orc.c
@@ -60,6 +60,9 @@ orc_init (void)
 #ifdef ENABLE_BACKEND_NEON
       orc_neon_init();
 #endif
+#ifdef ENABLE_BACKEND_MIPS
+      orc_mips_init();
+#endif
 
       inited = TRUE;
     }
index 2eb390f66c0b886a354b023f4a21f1ee819aed0c..a60838bba5384082477190d70fa9f507c31b0d13 100644 (file)
@@ -17,6 +17,7 @@ void orc_c_init (void);
 void orc_neon_init (void);
 void orc_c64x_init (void);
 void orc_c64x_c_init (void);
+void orc_mips_init (void);
 
 extern int _orc_data_cache_size_level1;
 extern int _orc_data_cache_size_level2;
diff --git a/orc/orcmips.c b/orc/orcmips.c
new file mode 100644 (file)
index 0000000..488a7a8
--- /dev/null
@@ -0,0 +1,95 @@
+#include <orc/orcmips.h>
+#include <orc/orcdebug.h>
+
+const char *
+orc_mips_reg_name (int reg)
+{
+  static const char *regs[] = {
+    "$0", "$at",
+    "$v0", "$v1",
+    "$a0", "$a1", "$a2", "$a3",
+    "$t0", "$t1", "$t2", "$t3","$t4", "$t5", "$t6", "$t7",
+    "$s0", "$s1", "$s2", "$s3","$s4", "$s5", "$s6", "$s7",
+    "$t8", "$t9",
+    "$k0", "$k1",
+    "$gp", "$sp", "$fp", "$ra"
+  };
+
+  if (reg < ORC_GP_REG_BASE || reg > ORC_GP_REG_BASE + 32)
+    return "ERROR";
+
+  return regs[reg-32];
+}
+
+void
+orc_mips_emit_label (OrcCompiler *compiler, unsigned int label)
+{
+  ORC_ASSERT (label < ORC_N_LABELS);
+  ORC_ASM_CODE(compiler,".L%d:\n", label);
+  //compiler->labels[label] = compiler->codeptr;
+}
+
+void
+orc_mips_emit_nop (OrcCompiler *compiler)
+{
+  ORC_ASM_CODE(compiler,"  nop\n");
+}
+
+void
+orc_mips_emit_sw (OrcCompiler *compiler, OrcMipsRegister reg,
+                  OrcMipsRegister base, unsigned int offset)
+{
+  ORC_ASM_CODE (compiler, "  sw      %s, %d(%s)\n",
+                orc_mips_reg_name (reg),
+                offset, orc_mips_reg_name (base));
+}
+
+void
+orc_mips_emit_lw (OrcCompiler *compiler, OrcMipsRegister dest,
+                  OrcMipsRegister base, unsigned int offset)
+{
+  ORC_ASM_CODE (compiler, "  lw      %s, %d(%s)\n",
+                orc_mips_reg_name (dest),
+                offset, orc_mips_reg_name (base));
+}
+
+void
+orc_mips_emit_jr (OrcCompiler *compiler, OrcMipsRegister address_reg)
+{
+  ORC_ASM_CODE (compiler, "  jr      %s\n", orc_mips_reg_name (address_reg));
+}
+
+void
+orc_mips_emit_blez (OrcCompiler *compiler,
+                    OrcMipsRegister reg, unsigned int label)
+{
+  ORC_ASM_CODE (compiler, "  blez    %s, .L%d\n",
+                orc_mips_reg_name (reg), label);
+}
+
+void
+orc_mips_emit_bnez (OrcCompiler *compiler,
+                    OrcMipsRegister reg, unsigned int label)
+{
+  ORC_ASM_CODE (compiler, "  bnez    %s, .L%d\n",
+                orc_mips_reg_name (reg), label);
+}
+
+void
+orc_mips_emit_addiu (OrcCompiler *compiler,
+                     OrcMipsRegister dest, OrcMipsRegister source, int value)
+{
+  ORC_ASM_CODE (compiler, "  addiu   %s, %s, %d\n",
+                orc_mips_reg_name (dest),
+                orc_mips_reg_name (source), value);
+}
+void
+orc_mips_emit_add (OrcCompiler *compiler,
+                   OrcMipsRegister dest,
+                   OrcMipsRegister source1, OrcMipsRegister source2)
+{
+  ORC_ASM_CODE (compiler, "  add     %s, %s, %s\n",
+                orc_mips_reg_name (dest),
+                orc_mips_reg_name (source1),
+                orc_mips_reg_name (source2));
+}
diff --git a/orc/orcmips.h b/orc/orcmips.h
new file mode 100644 (file)
index 0000000..c8e36e7
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef _ORC_MIPS_H_
+#define _ORC_MIPS_H_
+
+#include <orc/orcutils.h>
+#include <orc/orcprogram.h>
+
+ORC_BEGIN_DECLS
+
+#ifdef ORC_ENABLE_UNSTABLE_API
+
+typedef enum {
+  ORC_MIPS_ZERO = ORC_GP_REG_BASE+0,
+  ORC_MIPS_AT,
+  ORC_MIPS_V0,
+  ORC_MIPS_V1,
+  ORC_MIPS_A0,
+  ORC_MIPS_A1,
+  ORC_MIPS_A2,
+  ORC_MIPS_A3,
+  ORC_MIPS_T0,
+  ORC_MIPS_T1,
+  ORC_MIPS_T2,
+  ORC_MIPS_T3,
+  ORC_MIPS_T4,
+  ORC_MIPS_T5,
+  ORC_MIPS_T6,
+  ORC_MIPS_T7,
+  ORC_MIPS_S0,
+  ORC_MIPS_S1,
+  ORC_MIPS_S2,
+  ORC_MIPS_S3,
+  ORC_MIPS_S4,
+  ORC_MIPS_S5,
+  ORC_MIPS_S6,
+  ORC_MIPS_S7,
+  ORC_MIPS_T8,
+  ORC_MIPS_T9,
+  ORC_MIPS_K0,
+  ORC_MIPS_K1,
+  ORC_MIPS_GP,
+  ORC_MIPS_SP,
+  ORC_MIPS_FP,
+  ORC_MIPS_RA
+} OrcMipsRegister;
+
+void orc_mips_emit_label (OrcCompiler *compiler, unsigned int label);
+
+void orc_mips_emit_nop (OrcCompiler *compiler);
+
+void orc_mips_emit_sw (OrcCompiler *compiler, OrcMipsRegister reg,
+                       OrcMipsRegister base, unsigned int offset);
+
+void orc_mips_emit_lw (OrcCompiler *compiler, OrcMipsRegister dest,
+                       OrcMipsRegister base, unsigned int offset);
+
+void orc_mips_emit_jr (OrcCompiler *compiler, OrcMipsRegister address_reg);
+void orc_mips_emit_blez (OrcCompiler *compiler, OrcMipsRegister reg, unsigned int label);
+void orc_mips_emit_bnez (OrcCompiler *compiler, OrcMipsRegister reg, unsigned int label);
+
+void orc_mips_emit_addiu (OrcCompiler *compiler, OrcMipsRegister dest, OrcMipsRegister source, int value);
+void orc_mips_emit_add (OrcCompiler *compiler, OrcMipsRegister dest, OrcMipsRegister source1, OrcMipsRegister source2);
+
+
+#endif /* ORC_ENABLE_UNSTABLE_API */
+
+ORC_END_DECLS
+
+#endif /* _ORC_MIPS_H_ */
diff --git a/orc/orcprogram-mips.c b/orc/orcprogram-mips.c
new file mode 100644 (file)
index 0000000..53511eb
--- /dev/null
@@ -0,0 +1,244 @@
+#include <orc/orcmips.h>
+#include <orc/orcdebug.h>
+#include <stdlib.h>
+
+unsigned int orc_compiler_orc_mips_get_default_flags (void);
+
+void orc_compiler_orc_mips_init (OrcCompiler *compiler);
+
+void orc_compiler_orc_mips_assemble (OrcCompiler *compiler);
+
+const char * orc_compiler_orc_mips_get_asm_preamble (void);
+
+/* in orcrules-mips.c */
+void orc_compiler_orc_mips_register_rules (OrcTarget *target);
+
+static OrcTarget orc_mips_target = {
+  "mips",
+#ifdef HAVE_MIPS
+  TRUE,
+#else
+  FALSE,
+#endif
+  ORC_GP_REG_BASE,
+  orc_compiler_orc_mips_get_default_flags,
+  orc_compiler_orc_mips_init,
+  orc_compiler_orc_mips_assemble,
+  { { 0 } },
+  0,
+  orc_compiler_orc_mips_get_asm_preamble,
+};
+
+void
+orc_mips_init (void)
+{
+  orc_target_register (&orc_mips_target);
+
+  orc_compiler_orc_mips_register_rules (&orc_mips_target);
+}
+
+unsigned int
+orc_compiler_orc_mips_get_default_flags (void)
+{
+  return 0;
+}
+
+void
+orc_compiler_orc_mips_init (OrcCompiler *compiler)
+{
+  int i;
+
+  for (i=ORC_GP_REG_BASE; i<ORC_GP_REG_BASE+32; i++)
+    compiler->valid_regs[i] = 1;
+
+  compiler->valid_regs[ORC_MIPS_ZERO] = 0; /* always 0 */
+  compiler->valid_regs[ORC_MIPS_AT] = 0; /* we shouldn't touch that (assembler
+                                            temporary) */
+  compiler->exec_reg = ORC_MIPS_A0;
+  compiler->valid_regs[ORC_MIPS_A0] = 0; /* first (and in our case only)
+                                            function argument */
+  compiler->valid_regs[ORC_MIPS_T0] = 0; /* We get the arg size here */
+  compiler->valid_regs[ORC_MIPS_K0] = 0; /* for kernel/interupts */
+  compiler->valid_regs[ORC_MIPS_K1] = 0; /* for kernel/interupts */
+  compiler->valid_regs[ORC_MIPS_GP] = 0; /* global pointer */
+  compiler->valid_regs[ORC_MIPS_SP] = 0; /* stack pointer */
+  compiler->valid_regs[ORC_MIPS_FP] = 0; /* frame pointer */
+  compiler->valid_regs[ORC_MIPS_RA] = 0; /* return address */
+
+  for (i=0;i<ORC_N_REGS;i++){
+    compiler->alloc_regs[i] = 0;
+    compiler->used_regs[i] = 0;
+    compiler->save_regs[i] = 0;
+  }
+
+  compiler->save_regs[ORC_MIPS_V0] = 1;
+  compiler->save_regs[ORC_MIPS_V1] = 1;
+  compiler->save_regs[ORC_MIPS_A1] = 1;
+  compiler->save_regs[ORC_MIPS_A2] = 1;
+  compiler->save_regs[ORC_MIPS_A3] = 1;
+  for (i=ORC_MIPS_S0; i<= ORC_MIPS_S7; i++)
+    compiler->save_regs[i] = 1;
+
+  /* what's compiler->gp_tmpreg? and ->tmpreg? */
+}
+
+const char *
+orc_compiler_orc_mips_get_asm_preamble (void)
+{
+  return "\n"
+      "/* begin Orc MIPS target preamble */\n"
+      ".abicalls\n" /* not exactly sure what this is, but linker complains
+                       without it  */
+      "/* end Orc MIPS target preamble */\n\n";
+}
+
+int
+orc_mips_emit_prologue (OrcCompiler *compiler)
+{
+  int i, stack_size = 0;
+
+  orc_compiler_append_code(compiler,".globl %s\n", compiler->program->name);
+  orc_compiler_append_code(compiler,"%s:\n", compiler->program->name);
+
+  /* push registers we need to save */
+  for(i=0; i<32; i++)
+    if (compiler->used_regs[ORC_GP_REG_BASE + i] &&
+        compiler->save_regs[ORC_GP_REG_BASE + i])
+      stack_size += 4;
+
+  if (stack_size) {
+    unsigned int stack_increment = 0;
+
+    orc_mips_emit_addiu (compiler, ORC_MIPS_SP, ORC_MIPS_SP, -stack_size);
+
+    for(i=0; i<32; i++){
+      if (compiler->used_regs[ORC_GP_REG_BASE + i] &&
+          compiler->save_regs[ORC_GP_REG_BASE + i]) {
+        orc_mips_emit_sw (compiler, ORC_GP_REG_BASE+i,
+                          ORC_MIPS_SP, stack_increment);
+            stack_increment +=4;
+      }
+    }
+  }
+
+  return stack_size;
+}
+
+void orc_mips_emit_epilogue (OrcCompiler *compiler, int stack_size)
+{
+  int i;
+
+  /* pop saved registers */
+  if (stack_size) {
+    unsigned int stack_increment = 0;
+    for(i=0; i<32; i++){
+      if (compiler->used_regs[ORC_GP_REG_BASE + i] &&
+          compiler->save_regs[ORC_GP_REG_BASE + i]) {
+        orc_mips_emit_lw (compiler, ORC_GP_REG_BASE+i,
+                          ORC_MIPS_SP, stack_increment);
+            stack_increment +=4;
+      }
+    }
+    orc_mips_emit_addiu (compiler, ORC_MIPS_SP, ORC_MIPS_SP, stack_size);
+  }
+
+  orc_mips_emit_jr (compiler, ORC_MIPS_RA);
+  orc_mips_emit_nop (compiler);
+}
+
+void
+orc_mips_load_constants_inner (OrcCompiler *compiler)
+{
+  int i;
+  for(i=0;i<ORC_N_COMPILER_VARIABLES;i++){
+    if (compiler->vars[i].name == NULL) continue;
+    switch (compiler->vars[i].vartype) {
+      case ORC_VAR_TYPE_CONST:
+      case ORC_VAR_TYPE_PARAM:
+        break;
+      case ORC_VAR_TYPE_SRC:
+      case ORC_VAR_TYPE_DEST:
+        orc_mips_emit_lw (compiler,
+            compiler->vars[i].ptr_register,
+            compiler->exec_reg, ORC_STRUCT_OFFSET(OrcExecutor, arrays[i]));
+        break;
+      default:
+        break;
+    }
+  }
+}
+
+void
+orc_mips_emit_loop (OrcCompiler *compiler)
+{
+  int i, j;
+  OrcInstruction *insn;
+  OrcStaticOpcode *opcode;
+  OrcRule *rule;
+
+  for (i=0; i<compiler->n_insns; i++) {
+    insn = compiler->insns + i;
+    opcode = insn->opcode;
+    if (insn->flags & ORC_INSN_FLAG_INVARIANT) continue;
+
+    orc_compiler_append_code(compiler,"/* %d: %s */\n", i, insn->opcode->name);
+
+    rule = insn->rule;
+    if (rule && rule->emit) {
+      rule->emit (compiler, rule->emit_user, insn);
+    } else {
+      orc_compiler_append_code (compiler, "No rule for %s\n", opcode->name);
+    }
+  }
+
+  for (j=0; j<ORC_N_COMPILER_VARIABLES; j++) {
+    if (compiler->vars[j].name == NULL) continue;
+    if (compiler->vars[j].vartype == ORC_VAR_TYPE_SRC ||
+        compiler->vars[j].vartype == ORC_VAR_TYPE_DEST) {
+      if (compiler->vars[j].ptr_register) {
+        orc_mips_emit_addiu (compiler,
+            compiler->vars[j].ptr_register,
+            compiler->vars[j].ptr_register,
+            compiler->vars[j].size << compiler->loop_shift);
+      }
+    }
+  }
+}
+
+void
+orc_compiler_orc_mips_assemble (OrcCompiler *compiler)
+{
+  int stack_size;
+
+  stack_size = orc_mips_emit_prologue (compiler);
+
+  /* FIXME: load constants and params */
+#if 0
+  for (i=0; i<ORC_N_COMPILER_VARIABLES; i++) {
+    if (compiler->vars[i].name == NULL)
+      ORC_PROGRAM_ERROR (compiler, "unimplemented");
+  }
+#endif
+
+  /* FIXME */
+  if (compiler->program->is_2d)
+    ORC_PROGRAM_ERROR (compiler, "unimplemented");
+
+  orc_mips_emit_lw (compiler, ORC_MIPS_T0, compiler->exec_reg,
+                    (int)ORC_STRUCT_OFFSET(OrcExecutor, n));
+  orc_mips_emit_blez (compiler, ORC_MIPS_T0, 2);
+  orc_mips_emit_nop (compiler);
+  orc_mips_load_constants_inner (compiler);
+
+  orc_mips_emit_label (compiler, 1);
+  orc_mips_emit_loop (compiler);
+
+  orc_mips_emit_addiu (compiler, ORC_MIPS_T0, ORC_MIPS_T0, -1);
+  orc_mips_emit_bnez (compiler, ORC_MIPS_T0, 1);
+  orc_mips_emit_nop (compiler);
+
+  orc_mips_emit_label (compiler, 2);
+
+  orc_mips_emit_epilogue (compiler, stack_size);
+}
+
diff --git a/orc/orcrules-mips.c b/orc/orcrules-mips.c
new file mode 100644 (file)
index 0000000..8bc47de
--- /dev/null
@@ -0,0 +1,42 @@
+#include <orc/orcmips.h>
+#include <stdlib.h>
+
+void
+mips_rule_loadl (OrcCompiler *compiler, void *user, OrcInstruction *insn)
+{
+  int src = compiler->vars[insn->src_args[0]].ptr_register;
+  int dest = compiler->vars[insn->dest_args[0]].alloc;
+
+  orc_mips_emit_lw (compiler, dest, src, 0);
+}
+
+void
+mips_rule_storel (OrcCompiler *compiler, void *user, OrcInstruction *insn)
+{
+  int src = compiler->vars[insn->src_args[0]].alloc;
+  int dest = compiler->vars[insn->dest_args[0]].ptr_register;
+
+  orc_mips_emit_sw (compiler, src, dest, 0);
+}
+
+void
+mips_rule_addl (OrcCompiler *compiler, void *user, OrcInstruction *insn)
+{
+  int src1 = ORC_SRC_ARG (compiler, insn, 0);
+  int src2 = ORC_SRC_ARG (compiler, insn, 1);
+  int dest = ORC_DEST_ARG (compiler, insn, 0);
+
+  orc_mips_emit_add (compiler, dest, src1, src2);
+}
+
+void
+orc_compiler_orc_mips_register_rules (OrcTarget *target)
+{
+  OrcRuleSet *rule_set;
+
+  rule_set = orc_rule_set_new (orc_opcode_set_get("sys"), target, 0);
+
+  orc_rule_register (rule_set, "loadl", mips_rule_loadl, NULL);
+  orc_rule_register (rule_set, "storel", mips_rule_storel, NULL);
+  orc_rule_register (rule_set, "addl", mips_rule_addl, NULL);
+}