powerpc: Pre-load long constants & invariants
authorDoug Nazar <nazard@nazar.ca>
Sun, 25 Aug 2019 19:50:15 +0000 (15:50 -0400)
committerSebastian Dröge <slomo@coaxion.net>
Sun, 8 Sep 2019 07:58:54 +0000 (07:58 +0000)
PowerPC doesn't have an easy way to load a long constant into a
vector register so we emit the value into the code and then load it.

This moves those values to after the epilogue and then loads them
before starting the outer loop.

orc/orcconstant.h
orc/orcpowerpc.c
orc/orcpowerpc.h
orc/orcprogram-altivec.c

index 28fb4ec..4c2e7df 100644 (file)
@@ -29,6 +29,7 @@ struct _OrcConstant {
   unsigned int full_value[4];
   int use_count;
   int is_long;
+  int label;
 };
 
 
index 9758cb0..ad6cccd 100644 (file)
@@ -441,11 +441,22 @@ orc_powerpc_flush_cache (OrcCode *code)
 #endif
 }
 
-static void
+void
+powerpc_emit_load_address (OrcCompiler* compiler, int regd, int rega, int imm)
+{
+  if (compiler->is_64bit) {
+    powerpc_emit_ld (compiler, regd, rega, imm);
+  } else {
+    powerpc_emit_lwz (compiler, regd, rega, imm);
+  }
+}
+
+void
 powerpc_load_constant (OrcCompiler *p, int i, int reg)
 {
   int j;
   int value = p->constants[i].value;
+  int greg = p->gp_tmpreg;
 
   switch (p->constants[i].type) {
     case ORC_CONST_ZERO:
@@ -492,6 +503,7 @@ powerpc_load_constant (OrcCompiler *p, int i, int reg)
       value &= 0xff;
       value |= (value<<8);
       value |= (value<<16);
+      value |= (value<<24);
       for(j=0;j<4;j++){
         p->constants[i].full_value[j] = value;
       }
@@ -512,31 +524,39 @@ powerpc_load_constant (OrcCompiler *p, int i, int reg)
       break;
   }
 
-  powerpc_load_long_constant (p, reg,
-    p->constants[i].full_value[0],
-    p->constants[i].full_value[1],
-    p->constants[i].full_value[2],
-    p->constants[i].full_value[3]);
-}
+  p->constants[i].is_long = TRUE;
+  if (p->constants[i].label == 0) {
+    p->constants[i].label = orc_compiler_label_new(p);
+  }
 
-void
-powerpc_load_long_constant (OrcCompiler *p, int reg, orc_uint32 a,
-    orc_uint32 b, orc_uint32 c, orc_uint32 d)
-{
-  int label_skip, label_data;
-  int greg = p->gp_tmpreg;
+  powerpc_emit_load_address (p, greg, POWERPC_R3,
+      (int)ORC_STRUCT_OFFSET(OrcExecutor, arrays[ORC_VAR_A2]));
+  powerpc_emit_load_address (p, greg, greg,
+      (int)ORC_STRUCT_OFFSET(OrcCode, exec));
 
-  label_skip = orc_compiler_label_new (p);
-  label_data = orc_compiler_label_new (p);
+  powerpc_add_fixup (p, 1, p->codeptr, p->constants[i].label);
+  {
+    unsigned int insn;
 
-  powerpc_emit_b (p, label_skip);
+    ORC_ASM_CODE(p,"  addi %s, %s, %db - %s\n",
+        powerpc_get_regname(greg),
+        powerpc_get_regname(greg), p->constants[i].label, p->program->name);
+    insn = (14<<26) | (powerpc_regnum (greg)<<21) | (powerpc_regnum (greg)<<16);
+    insn |= 0;
 
-  while ((p->codeptr - p->code) & 0xf) {
-    ORC_ASM_CODE(p,"  .long 0x00000000\n");
-    powerpc_emit (p, 0x00000000);
+    powerpc_emit (p, insn);
   }
 
-  powerpc_emit_label (p, label_data);
+  ORC_ASM_CODE(p,"  lvx %s, 0, %s\n",
+      powerpc_get_regname(reg),
+      powerpc_get_regname(greg));
+  powerpc_emit_X (p, 0x7c0000ce, reg, 0, greg);
+}
+
+static void
+powerpc_emit_long_value(OrcCompiler* p, orc_uint32 a, orc_uint32 b,
+    orc_uint32 c, orc_uint32 d)
+{
   if (IS_POWERPC_BE(p)) {
     ORC_ASM_CODE(p,"  .long 0x%08x\n", a);
     powerpc_emit (p, a);
@@ -556,44 +576,44 @@ powerpc_load_long_constant (OrcCompiler *p, int reg, orc_uint32 a,
     ORC_ASM_CODE(p,"  .long 0x%08x\n", a);
     powerpc_emit (p, a);
   }
+}
 
-  powerpc_emit_label (p, label_skip);
-  if (p->is_64bit) {
-    powerpc_emit_ld (p,
-        greg,
-        POWERPC_R3,
-        (int)ORC_STRUCT_OFFSET(OrcExecutor, arrays[ORC_VAR_A2]));
-    powerpc_emit_ld (p,
-        greg, greg,
-        (int)ORC_STRUCT_OFFSET(OrcCode, exec));
-  } else {
-    powerpc_emit_lwz (p,
-        greg,
-        POWERPC_R3,
-        (int)ORC_STRUCT_OFFSET(OrcExecutor, arrays[ORC_VAR_A2]));
-    powerpc_emit_lwz (p,
-        greg, greg,
-        (int)ORC_STRUCT_OFFSET(OrcCode, exec));
-  }
-
-  powerpc_add_fixup (p, 1, p->codeptr, label_data);
-  {
-    unsigned int insn;
-
-    ORC_ASM_CODE(p,"  addi %s, %s, %db - %s\n",
-        powerpc_get_regname(greg),
-        powerpc_get_regname(greg), label_data, p->program->name);
-    insn = (14<<26) | (powerpc_regnum (greg)<<21) | (powerpc_regnum (greg)<<16);
-    insn |= 0;
-
-    powerpc_emit (p, insn);
+void
+powerpc_emit_full_constants(OrcCompiler* p)
+{
+  int i;
+  int aligned = FALSE;
+
+  for (i = 0; i < p->n_constants; i++) {
+    if (p->constants[i].is_long == TRUE && p->constants[i].label) {
+      if (!aligned) {
+        while ((p->codeptr - p->code) & 0xf) {
+          ORC_ASM_CODE(p, "  .long 0x00000000\n");
+          powerpc_emit(p, 0x00000000);
+        }
+        aligned = TRUE;
+      }
+      powerpc_emit_label(p, p->constants[i].label);
+      powerpc_emit_long_value(p,
+          p->constants[i].full_value[0], p->constants[i].full_value[1],
+          p->constants[i].full_value[2], p->constants[i].full_value[3]);
+    }
   }
+}
 
-  ORC_ASM_CODE(p,"  lvx %s, 0, %s\n",
-      powerpc_get_regname(reg),
-      powerpc_get_regname(greg));
-  powerpc_emit_X (p, 0x7c0000ce, reg, 0, greg);
+void
+powerpc_load_long_constant (OrcCompiler *p, int reg, orc_uint32 value0,
+    orc_uint32 value1, orc_uint32 value2, orc_uint32 value3)
+{
+  int i = p->n_constants++;
+  p->constants[i].type = ORC_CONST_FULL;
+  p->constants[i].full_value[0] = value0;
+  p->constants[i].full_value[1] = value1;
+  p->constants[i].full_value[2] = value2;
+  p->constants[i].full_value[3] = value3;
+  p->constants[i].alloc_reg = -1;
 
+  powerpc_load_constant (p, i, reg);
 }
 
 int
@@ -605,7 +625,7 @@ powerpc_get_constant (OrcCompiler *p, int type, int value)
   for(i=0;i<p->n_constants;i++){
     if (p->constants[i].type == type &&
         p->constants[i].value == value) {
-      if (p->constants[i].alloc_reg != 0) {
+      if (p->constants[i].alloc_reg > 0) {
         return p->constants[i].alloc_reg;
       }
       break;
@@ -631,15 +651,16 @@ powerpc_get_constant_full (OrcCompiler *p, int value0, int value1,
   int i;
 
   for(i=0;i<p->n_constants;i++){
-#if 0
-    if (p->constants[i].type == type &&
-        p->constants[i].value == value) {
-      if (p->constants[i].alloc_reg != 0) {
+    if (p->constants[i].type == ORC_CONST_FULL &&
+        p->constants[i].full_value[0] == value0 &&
+        p->constants[i].full_value[1] == value1 &&
+        p->constants[i].full_value[2] == value2 &&
+        p->constants[i].full_value[3] == value3) {
+      if (p->constants[i].alloc_reg > 0) {
         return p->constants[i].alloc_reg;
       }
       break;
     }
-#endif
   }
   if (i == p->n_constants) {
     p->n_constants++;
index 8f25341..134af6c 100644 (file)
@@ -136,6 +136,9 @@ void powerpc_emit_VX_4 (OrcCompiler *p, const char *name, unsigned int insn, int
 int  powerpc_get_constant (OrcCompiler *p, int type, int value);
 int  powerpc_get_constant_full (OrcCompiler *p, int value0, int value1, int value2, int value3);
 void powerpc_load_long_constant (OrcCompiler *p, int reg, orc_uint32 a, orc_uint32 b, orc_uint32 c, orc_uint32 d);
+void powerpc_emit_full_constants (OrcCompiler* p);
+void powerpc_emit_load_address (OrcCompiler* compiler, int regd, int rega, int imm);
+void powerpc_load_constant (OrcCompiler* p, int i, int reg);
 
 /* instructions */
 #define powerpc_emit_vand(p,a,b,c)         powerpc_emit_VX_2 (p, "vand", 0x10000404, a, b, c)
index c3ab64d..fb3e0a5 100644 (file)
@@ -143,6 +143,47 @@ orc_compiler_powerpc_init (OrcCompiler *compiler)
 }
 
 static void
+powerpc_load_constants_outer (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:
+        break;
+      case ORC_VAR_TYPE_PARAM:
+        break;
+      case ORC_VAR_TYPE_SRC:
+      case ORC_VAR_TYPE_DEST:
+        break;
+      case ORC_VAR_TYPE_ACCUMULATOR:
+        powerpc_emit_vxor(compiler, compiler->vars[i].alloc,
+            compiler->vars[i].alloc, compiler->vars[i].alloc);
+        break;
+      case ORC_VAR_TYPE_TEMP:
+        break;
+      default:
+        orc_compiler_error(compiler,"bad vartype");
+        break;
+    }
+  }
+
+  orc_compiler_emit_invariants (compiler);
+
+  for(i=0;i<compiler->n_constants;i++) {
+    if (compiler->constants[i].is_long &&
+        !compiler->constants[i].alloc_reg) {
+      compiler->constants[i].alloc_reg =
+          orc_compiler_get_constant_reg (compiler);
+      if (compiler->constants[i].alloc_reg > 0) {
+        powerpc_load_constant (compiler, i,
+            compiler->constants[i].alloc_reg);
+      }
+    }
+  }
+}
+
+static void
 powerpc_load_inner_constants (OrcCompiler *compiler)
 {
   int i;
@@ -153,17 +194,10 @@ powerpc_load_inner_constants (OrcCompiler *compiler)
       case ORC_VAR_TYPE_SRC:
       case ORC_VAR_TYPE_DEST:
         if (compiler->vars[i].ptr_register) {
-          if (compiler->is_64bit) {
-            powerpc_emit_ld (compiler,
-                compiler->vars[i].ptr_register,
-                POWERPC_R3,
-                (int)ORC_STRUCT_OFFSET(OrcExecutor, arrays[i]));
-          } else {
-            powerpc_emit_lwz (compiler,
-                compiler->vars[i].ptr_register,
-                POWERPC_R3,
-                (int)ORC_STRUCT_OFFSET(OrcExecutor, arrays[i]));
-          }
+          powerpc_emit_load_address (compiler,
+              compiler->vars[i].ptr_register,
+              POWERPC_R3,
+              (int)ORC_STRUCT_OFFSET(OrcExecutor, arrays[i]));
         } else {
           /* FIXME */
           ORC_ASM_CODE(compiler,"ERROR");
@@ -176,14 +210,65 @@ powerpc_load_inner_constants (OrcCompiler *compiler)
 }
 
 static void
-orc_compiler_powerpc_assemble (OrcCompiler *compiler)
+orc_powerpc_emit_loop (OrcCompiler* compiler, int update)
 {
   int j;
   int k;
   OrcInstruction *insn;
   OrcStaticOpcode *opcode;
-  /* OrcVariable *args[10]; */
   OrcRule *rule;
+
+  for(j=0;j<compiler->n_insns;j++){
+    insn = compiler->insns + j;
+    opcode = insn->opcode;
+
+    compiler->insn_index = j;
+
+    if (insn->flags & ORC_INSN_FLAG_INVARIANT) continue;
+
+    ORC_ASM_CODE(compiler,"# %d: %s\n", j, insn->opcode->name);
+
+    compiler->min_temp_reg = ORC_VEC_REG_BASE;
+
+    compiler->insn_shift = compiler->loop_shift;
+    if (insn->flags & ORC_INSTRUCTION_FLAG_X2) {
+      compiler->insn_shift += 1;
+    }
+    if (insn->flags & ORC_INSTRUCTION_FLAG_X4) {
+      compiler->insn_shift += 2;
+    }
+
+    rule = insn->rule;
+    if (rule && rule->emit) {
+      rule->emit (compiler, rule->emit_user, insn);
+    } else {
+      orc_compiler_error (compiler, "no code generation rule for %s",
+          opcode->name);
+    }
+  }
+
+  if (update) {
+    for(k=0;k<ORC_N_COMPILER_VARIABLES;k++){
+      if (compiler->vars[k].name == NULL) continue;
+      if (compiler->vars[k].vartype == ORC_VAR_TYPE_SRC ||
+          compiler->vars[k].vartype == ORC_VAR_TYPE_DEST) {
+        if (compiler->vars[k].ptr_register) {
+          powerpc_emit_addi (compiler,
+              compiler->vars[k].ptr_register,
+              compiler->vars[k].ptr_register,
+              compiler->vars[k].size << compiler->loop_shift);
+        } else {
+            ORC_ASM_CODE(compiler,"ERROR\n");
+        }
+      }
+    }
+  }
+}
+
+static void
+orc_compiler_powerpc_assemble (OrcCompiler *compiler)
+{
+  int k;
   int label_outer_loop_start;
   int label_loop_start;
   int label_leave;
@@ -193,6 +278,27 @@ orc_compiler_powerpc_assemble (OrcCompiler *compiler)
   label_loop_start = orc_compiler_label_new (compiler);
   label_leave = orc_compiler_label_new (compiler);
 
+  {
+    int i;
+
+    orc_powerpc_emit_loop (compiler, 0);
+
+    compiler->codeptr = compiler->code;
+    free (compiler->asm_code);
+    compiler->asm_code = NULL;
+    compiler->asm_code_len = 0;
+    memset (compiler->labels, 0, sizeof (compiler->labels));
+    memset (compiler->labels_int, 0, sizeof (compiler->labels_int));
+    compiler->n_fixups = 0;
+    compiler->n_output_insns = 0;
+
+    for(i=0;i<compiler->n_constants;i++) {
+      compiler->constants[i].label = 0;
+    }
+  }
+
+  if (compiler->error) return;
+
   powerpc_emit_prologue (compiler);
 
   if (orc_program_has_float (compiler)) {
@@ -208,6 +314,8 @@ orc_compiler_powerpc_assemble (OrcCompiler *compiler)
     powerpc_emit_VX_b(compiler, "mtvscr", 0x10000644, tmp);
   }
 
+  powerpc_load_constants_outer (compiler);
+
   if (compiler->program->is_2d) {
     powerpc_emit_lwz (compiler, POWERPC_R0, POWERPC_R3,
         (int)ORC_STRUCT_OFFSET(OrcExecutorAlt, m));
@@ -218,18 +326,8 @@ orc_compiler_powerpc_assemble (OrcCompiler *compiler)
         (int)ORC_STRUCT_OFFSET(OrcExecutorAlt, m_index));
   }
 
-  /* powerpc_load_constants (compiler); */
   powerpc_load_inner_constants (compiler);
 
-  for(k=0;k<4;k++){
-    OrcVariable *var = &compiler->vars[ORC_VAR_A1 + k];
-
-    if (compiler->vars[ORC_VAR_A1 + k].name == NULL) continue;
-
-      /* powerpc_emit_VX_2(p, "vxor", 0x100004c4, reg, reg, reg); */
-    powerpc_emit_vxor (compiler, var->alloc, var->alloc, var->alloc);
-  }
-
   powerpc_emit_label (compiler, label_outer_loop_start);
 
   powerpc_emit_lwz (compiler, POWERPC_R0, POWERPC_R3,
@@ -244,85 +342,7 @@ orc_compiler_powerpc_assemble (OrcCompiler *compiler)
 
   powerpc_emit_label (compiler, label_loop_start);
 
-  for(j=0;j<compiler->n_insns;j++){
-    insn = compiler->insns + j;
-    opcode = insn->opcode;
-
-    compiler->insn_index = j;
-
-    ORC_ASM_CODE(compiler,"# %d: %s\n", j, insn->opcode->name);
-
-#if 0
-    /* set up args */
-    for(k=0;k<opcode->n_src + opcode->n_dest;k++){
-      args[k] = compiler->vars + insn->args[k];
-      ORC_ASM_CODE(compiler," %d", args[k]->alloc);
-      if (args[k]->is_chained) {
-        ORC_ASM_CODE(compiler," (chained)");
-      }
-    }
-    ORC_ASM_CODE(compiler,"\n");
-#endif
-
-    for(k=0;k<ORC_STATIC_OPCODE_N_SRC;k++){
-      OrcVariable *var = compiler->vars + insn->src_args[k];
-
-      if (opcode->src_size[k] == 0) continue;
-
-      switch (var->vartype) {
-        case ORC_VAR_TYPE_SRC:
-        case ORC_VAR_TYPE_DEST:
-          /* powerpc_emit_load_src (compiler, var); */
-          break;
-        case ORC_VAR_TYPE_CONST:
-          break;
-        case ORC_VAR_TYPE_TEMP:
-          break;
-        default:
-          break;
-      }
-    }
-
-    compiler->min_temp_reg = ORC_VEC_REG_BASE;
-
-    rule = insn->rule;
-    if (rule) {
-      rule->emit (compiler, rule->emit_user, insn);
-    } else {
-      ORC_ASM_CODE(compiler,"No rule for: %s\n", opcode->name);
-    }
-
-    for(k=0;k<ORC_STATIC_OPCODE_N_DEST;k++){
-      OrcVariable *var = compiler->vars + insn->dest_args[k];
-
-      if (opcode->dest_size[k] == 0) continue;
-
-      switch (var->vartype) {
-        case ORC_VAR_TYPE_DEST:
-          /* powerpc_emit_store_dest (compiler, var); */
-          break;
-        case ORC_VAR_TYPE_TEMP:
-          break;
-        default:
-          break;
-      }
-    }
-  }
-
-  for(k=0;k<ORC_N_COMPILER_VARIABLES;k++){
-    if (compiler->vars[k].name == NULL) continue;
-    if (compiler->vars[k].vartype == ORC_VAR_TYPE_SRC ||
-        compiler->vars[k].vartype == ORC_VAR_TYPE_DEST) {
-      if (compiler->vars[k].ptr_register) {
-        powerpc_emit_addi (compiler,
-            compiler->vars[k].ptr_register,
-            compiler->vars[k].ptr_register,
-            compiler->vars[k].size << compiler->loop_shift);
-      } else {
-        ORC_ASM_CODE(compiler,"ERROR\n");
-      }
-    }
-  }
+  orc_powerpc_emit_loop (compiler, 1);
 
   powerpc_emit_bne (compiler, label_loop_start);
 
@@ -340,17 +360,10 @@ orc_compiler_powerpc_assemble (OrcCompiler *compiler)
       if (compiler->vars[k].vartype == ORC_VAR_TYPE_SRC ||
           compiler->vars[k].vartype == ORC_VAR_TYPE_DEST) {
         if (compiler->vars[k].ptr_register) {
-          if (compiler->is_64bit) {
-            powerpc_emit_ld (compiler,
-                compiler->vars[k].ptr_register,
-                POWERPC_R3,
-                (int)ORC_STRUCT_OFFSET(OrcExecutor, arrays[k]));
-          } else {
-            powerpc_emit_lwz (compiler,
-                compiler->vars[k].ptr_register,
-                POWERPC_R3,
-                (int)ORC_STRUCT_OFFSET(OrcExecutor, arrays[k]));
-          }
+          powerpc_emit_load_address (compiler,
+              compiler->vars[k].ptr_register,
+              POWERPC_R3,
+              (int)ORC_STRUCT_OFFSET(OrcExecutor, arrays[k]));
           powerpc_emit_lwz (compiler,
               POWERPC_R0,
               POWERPC_R3,
@@ -437,6 +450,8 @@ orc_compiler_powerpc_assemble (OrcCompiler *compiler)
   }
   powerpc_emit_epilogue (compiler);
 
+  powerpc_emit_full_constants (compiler);
+
   powerpc_do_fixups (compiler);
 }