+// register cache / constant propagation stuff
+typedef enum {
+ RC_GR_READ,
+ RC_GR_WRITE,
+ RC_GR_RMW,
+} rc_gr_mode;
+
+static int rcache_get_reg_(sh2_reg_e r, rc_gr_mode mode, int do_locking);
+
+// guest regs with constants
+static u32 dr_gcregs[24];
+// a mask of constant/dirty regs
+static u32 dr_gcregs_mask;
+static u32 dr_gcregs_dirty;
+
+#if PROPAGATE_CONSTANTS
+static void gconst_new(sh2_reg_e r, u32 val)
+{
+ int i;
+
+ dr_gcregs_mask |= 1 << r;
+ dr_gcregs_dirty |= 1 << r;
+ dr_gcregs[r] = val;
+
+ // throw away old r that we might have cached
+ for (i = ARRAY_SIZE(reg_temp) - 1; i >= 0; i--) {
+ if ((reg_temp[i].type == HR_CACHED) &&
+ reg_temp[i].greg == r) {
+ reg_temp[i].type = HR_FREE;
+ reg_temp[i].flags = 0;
+ }
+ }
+}
+#endif
+
+static int gconst_get(sh2_reg_e r, u32 *val)
+{
+ if (dr_gcregs_mask & (1 << r)) {
+ *val = dr_gcregs[r];
+ return 1;
+ }
+ return 0;
+}
+
+static int gconst_check(sh2_reg_e r)
+{
+ if ((dr_gcregs_mask | dr_gcregs_dirty) & (1 << r))
+ return 1;
+ return 0;
+}
+
+// update hr if dirty, else do nothing
+static int gconst_try_read(int hr, sh2_reg_e r)
+{
+ if (dr_gcregs_dirty & (1 << r)) {
+ emith_move_r_imm(hr, dr_gcregs[r]);
+ dr_gcregs_dirty &= ~(1 << r);
+ return 1;
+ }
+ return 0;
+}
+
+static void gconst_check_evict(sh2_reg_e r)
+{
+ if (dr_gcregs_mask & (1 << r))
+ // no longer cached in reg, make dirty again
+ dr_gcregs_dirty |= 1 << r;
+}
+
+static void gconst_kill(sh2_reg_e r)
+{
+ dr_gcregs_mask &= ~(1 << r);
+ dr_gcregs_dirty &= ~(1 << r);
+}
+
+static void gconst_clean(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dr_gcregs); i++)
+ if (dr_gcregs_dirty & (1 << i)) {
+ // using RC_GR_READ here: it will call gconst_try_read,
+ // cache the reg and mark it dirty.
+ rcache_get_reg_(i, RC_GR_READ, 0);
+ }
+}
+
+static void gconst_invalidate(void)
+{
+ dr_gcregs_mask = dr_gcregs_dirty = 0;
+}
+