+static void do_invstub(int n)
+{
+ literal_pool(20);
+ assem_debug("do_invstub\n");
+ u_int reglist = stubs[n].a;
+ u_int addrr = stubs[n].b;
+ int ofs_start = stubs[n].c;
+ int ofs_end = stubs[n].d;
+ int len = ofs_end - ofs_start;
+ u_int rightr = 0;
+
+ set_jump_target(stubs[n].addr, out);
+ save_regs(reglist);
+ if (addrr != 0 || ofs_start != 0)
+ emit_addimm(addrr, ofs_start, 0);
+ emit_readword(&inv_code_start, 2);
+ emit_readword(&inv_code_end, 3);
+ if (len != 0)
+ emit_addimm(0, len + 4, (rightr = 1));
+ emit_cmp(0, 2);
+ emit_cmpcs(3, rightr);
+ void *jaddr = out;
+ emit_jc(0);
+ void *func = (len != 0)
+ ? (void *)ndrc_write_invalidate_many
+ : (void *)ndrc_write_invalidate_one;
+ emit_far_call(func);
+ set_jump_target(jaddr, out);
+ restore_regs(reglist);
+ emit_jmp(stubs[n].retaddr);
+}
+
+static void do_store_smc_check(int i, const struct regstat *i_regs, u_int reglist, int addr)
+{
+ if (HACK_ENABLED(NDHACK_NO_SMC_CHECK))
+ return;
+ // this can't be used any more since we started to check exact
+ // block boundaries in invalidate_range()
+ //if (i_regs->waswritten & (1<<dops[i].rs1))
+ // return;
+ // (naively) assume nobody will run code from stack
+ if (dops[i].rs1 == 29)
+ return;
+
+ int j, imm_maxdiff = 32, imm_min = cinfo[i].imm, imm_max = cinfo[i].imm, count = 1;
+ if (i < slen - 1 && dops[i+1].is_store && dops[i+1].rs1 == dops[i].rs1
+ && abs(cinfo[i+1].imm - cinfo[i].imm) <= imm_maxdiff)
+ return;
+ for (j = i - 1; j >= 0; j--) {
+ if (!dops[j].is_store || dops[j].rs1 != dops[i].rs1
+ || abs(cinfo[j].imm - cinfo[j+1].imm) > imm_maxdiff)
+ break;
+ count++;
+ if (imm_min > cinfo[j].imm)
+ imm_min = cinfo[j].imm;
+ if (imm_max < cinfo[j].imm)
+ imm_max = cinfo[j].imm;
+ }
+#if defined(HOST_IMM8)
+ int ir = get_reg(i_regs->regmap, INVCP);
+ assert(ir >= 0);
+ host_tempreg_acquire();
+ emit_ldrb_indexedsr12_reg(ir, addr, HOST_TEMPREG);
+#else
+ emit_cmpmem_indexedsr12_imm(invalid_code, addr, 1);
+ #error not handled
+#endif
+#ifdef INVALIDATE_USE_COND_CALL
+ if (count == 1) {
+ emit_cmpimm(HOST_TEMPREG, 1);
+ emit_callne(invalidate_addr_reg[addr]);
+ host_tempreg_release();
+ return;
+ }
+#endif
+ void *jaddr = emit_cbz(HOST_TEMPREG, 0);
+ host_tempreg_release();
+ imm_min -= cinfo[i].imm;
+ imm_max -= cinfo[i].imm;
+ add_stub(INVCODE_STUB, jaddr, out, reglist|(1<<HOST_CCREG),
+ addr, imm_min, imm_max, 0);
+}
+