+ unload_rs = OPT_EARLY_UNLOAD
+ && LIGHTREC_FLAGS_GET_RS(op->flags) == LIGHTREC_REG_UNLOAD;
+ discard_rs = OPT_EARLY_UNLOAD
+ && LIGHTREC_FLAGS_GET_RS(op->flags) == LIGHTREC_REG_DISCARD;
+
+ if ((unload_rs || discard_rs) && c.m.rs) {
+ /* If the source register is going to be unloaded or discarded,
+ * then we can simply mark its host register as now pointing to
+ * the destination register. */
+ pr_debug("Remap %s to %s at offset 0x%x\n",
+ lightrec_reg_name(c.m.rs), lightrec_reg_name(c.m.rd),
+ offset << 2);
+ rs = lightrec_alloc_reg_in(reg_cache, _jit, c.m.rs, 0);
+ lightrec_remap_reg(reg_cache, _jit, rs, c.m.rd, discard_rs);
+ lightrec_free_reg(reg_cache, rs);
+ return;
+ }
+
+ unload_rd = OPT_EARLY_UNLOAD
+ && LIGHTREC_FLAGS_GET_RD(op->flags) == LIGHTREC_REG_UNLOAD;
+
+ if (c.m.rs && !lightrec_reg_is_loaded(reg_cache, c.m.rs)) {
+ /* The source register is not yet loaded - we can load its value
+ * from the register cache directly into the target register. */
+ rd = lightrec_alloc_reg_out(reg_cache, _jit, c.m.rd, REG_EXT);
+
+ jit_ldxi_i(rd, LIGHTREC_REG_STATE,
+ offsetof(struct lightrec_state, regs.gpr) + (c.m.rs << 2));
+
+ lightrec_free_reg(reg_cache, rd);
+ } else if (unload_rd) {
+ /* If the destination register will be unloaded right after the
+ * MOV meta-opcode, we don't actually need to write any host
+ * register - we can just store the source register directly to
+ * the register cache, at the offset corresponding to the
+ * destination register. */
+ lightrec_discard_reg_if_loaded(reg_cache, c.m.rd);
+
+ rs = lightrec_alloc_reg_in(reg_cache, _jit, c.m.rs, 0);
+
+ jit_stxi_i(offsetof(struct lightrec_state, regs.gpr)
+ + (c.m.rd << 2), LIGHTREC_REG_STATE, rs);