#include "pcnt.h"
#include "arm_features.h"
-#define unused __attribute__((unused))
-
void do_memhandler_pre();
void do_memhandler_post();
// should only happen when jumping to an already compiled block (see add_jump_out)
// a workaround would be to do a trampoline jump via a stub at the end of the block
assert(-1048576 <= offset && offset < 1048576);
- *ptr=(*ptr&0xFF00000F)|(((offset>>2)&0x7ffff)<<5);
+ *ptr=(*ptr&0xFF00001F)|(((offset>>2)&0x7ffff)<<5);
}
else if((*ptr&0x9f000000)==0x10000000) { // adr
// generated by do_miniht_insert
}
}
+static void emit_movimm64(uint64_t imm, u_int rt)
+{
+ u_int shift, op, imm16, insns = 0;
+ for (shift = 0; shift < 4; shift++) {
+ imm16 = (imm >> shift * 16) & 0xffff;
+ if (!imm16)
+ continue;
+ op = insns ? 0xf2800000 : 0xd2800000;
+ assem_debug("mov%c %s,#%#x", insns ? 'k' : 'z', regname64[rt], imm16);
+ if (shift)
+ assem_debug(",lsl #%u", shift * 16);
+ assem_debug("\n");
+ output_w32(op | (shift << 21) | imm16_rd(imm16, rt));
+ insns++;
+ }
+ if (!insns) {
+ assem_debug("movz %s,#0\n", regname64[rt]);
+ output_w32(0xd2800000 | imm16_rd(0, rt));
+ }
+}
+
static void emit_readword(void *addr, u_int rt)
{
uintptr_t offset = (u_char *)addr - (u_char *)&dynarec_local;
static void emit_addimm(u_int rs, uintptr_t imm, u_int rt)
{
+ if (imm == 0) {
+ emit_mov(rs, rt);
+ return;
+ }
emit_addimm_s(0, 0, rs, imm, rt);
}
output_w32(0x34000000 | is64 | isnz | imm19_rt(offset, r));
}
-static unused void emit_cbz(const void *a, u_int r)
+static void *emit_cbz(u_int r, const void *a)
{
+ void *ret = out;
emit_cb(0, 0, a, r);
+ return ret;
}
static void emit_jmpreg(u_int r)
}
// special case for checking invalid_code
-static void emit_cmpmem_indexedsr12_reg(u_int rbase, u_int r, u_int imm)
+static void emit_ldrb_indexedsr12_reg(u_int rbase, u_int r, u_int rt)
{
- host_tempreg_acquire();
- emit_shrimm(r, 12, HOST_TEMPREG);
- assem_debug("ldrb %s,[%s,%s,uxtw]\n",regname[HOST_TEMPREG],regname64[rbase],regname[HOST_TEMPREG]);
- output_w32(0x38604800 | rm_rn_rd(HOST_TEMPREG, rbase, HOST_TEMPREG));
- emit_cmpimm(HOST_TEMPREG, imm);
- host_tempreg_release();
+ emit_shrimm(r, 12, rt);
+ assem_debug("ldrb %s,[%s,%s,uxtw]\n",regname[rt],regname64[rbase],regname[rt]);
+ output_w32(0x38604800 | rm_rn_rd(rt, rbase, rt));
}
// special for loadlr_assemble, rs2 is destroyed
}
// just move the whole thing. At least on Linux all addresses
// seem to be 48bit, so 3 insns - not great not terrible
- assem_debug("movz %s,#%#lx\n", regname64[rt], rt_val & 0xffff);
- output_w32(0xd2800000 | imm16_rd(rt_val & 0xffff, rt));
- assem_debug("movk %s,#%#lx,lsl #16\n", regname64[rt], (rt_val >> 16) & 0xffff);
- output_w32(0xf2a00000 | imm16_rd((rt_val >> 16) & 0xffff, rt));
- assem_debug("movk %s,#%#lx,lsl #32\n", regname64[rt], (rt_val >> 32) & 0xffff);
- output_w32(0xf2c00000 | imm16_rd((rt_val >> 32) & 0xffff, rt));
- if (rt_val >> 48) {
- assem_debug("movk %s,#%#lx,lsl #48\n", regname64[rt], (rt_val >> 48) & 0xffff);
- output_w32(0xf2e00000 | imm16_rd((rt_val >> 48) & 0xffff, rt));
- }
+ emit_movimm64(rt_val, rt);
}
// trashes x2
emit_addimm(cc<0?2:cc,adj,2);
if(is_dynamic) {
uintptr_t l1 = ((uintptr_t *)mem_rtab)[addr>>12] << 1;
- emit_adrp((void *)l1, 1);
- emit_addimm64(1, l1 & 0xfff, 1);
+ intptr_t offset = (l1 & ~0xfffl) - ((intptr_t)out & ~0xfffl);
+ if (-4294967296l <= offset && offset < 4294967296l) {
+ emit_adrp((void *)l1, 1);
+ emit_addimm64(1, l1 & 0xfff, 1);
+ }
+ else
+ emit_movimm64(l1, 1);
}
else
emit_far_call(do_memhandler_pre);