aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lj_asm_arm64.h64
-rw-r--r--src/lj_emit_arm64.h18
-rw-r--r--src/lj_target_arm64.h7
3 files changed, 51 insertions, 38 deletions
diff --git a/src/lj_asm_arm64.h b/src/lj_asm_arm64.h
index cbb186d3..baafa21a 100644
--- a/src/lj_asm_arm64.h
+++ b/src/lj_asm_arm64.h
@@ -56,11 +56,11 @@ static void asm_exitstub_setup(ASMState *as, ExitNo nexits)
56 asm_mclimit(as); 56 asm_mclimit(as);
57 /* 1: str lr,[sp]; bl ->vm_exit_handler; movz w0,traceno; bl <1; bl <1; ... */ 57 /* 1: str lr,[sp]; bl ->vm_exit_handler; movz w0,traceno; bl <1; bl <1; ... */
58 for (i = nexits-1; (int32_t)i >= 0; i--) 58 for (i = nexits-1; (int32_t)i >= 0; i--)
59 *--mxp = A64I_LE(A64I_BL|((-3-i)&0x03ffffffu)); 59 *--mxp = A64I_LE(A64I_BL | A64F_S26(-3-i));
60 *--mxp = A64I_LE(A64I_MOVZw|A64F_U16(as->T->traceno)); 60 *--mxp = A64I_LE(A64I_MOVZw | A64F_U16(as->T->traceno));
61 mxp--; 61 mxp--;
62 *mxp = A64I_LE(A64I_BL|(((MCode *)(void *)lj_vm_exit_handler-mxp)&0x03ffffffu)); 62 *mxp = A64I_LE(A64I_BL | A64F_S26(((MCode *)(void *)lj_vm_exit_handler-mxp)));
63 *--mxp = A64I_LE(A64I_STRx|A64F_D(RID_LR)|A64F_N(RID_SP)); 63 *--mxp = A64I_LE(A64I_STRx | A64F_D(RID_LR) | A64F_N(RID_SP));
64 as->mctop = mxp; 64 as->mctop = mxp;
65} 65}
66 66
@@ -77,7 +77,7 @@ static void asm_guardcc(ASMState *as, A64CC cc)
77 MCode *p = as->mcp; 77 MCode *p = as->mcp;
78 if (LJ_UNLIKELY(p == as->invmcp)) { 78 if (LJ_UNLIKELY(p == as->invmcp)) {
79 as->loopinv = 1; 79 as->loopinv = 1;
80 *p = A64I_B | ((target-p) & 0x03ffffffu); 80 *p = A64I_B | A64F_S26(target-p);
81 emit_cond_branch(as, cc^1, p-1); 81 emit_cond_branch(as, cc^1, p-1);
82 return; 82 return;
83 } 83 }
@@ -91,7 +91,7 @@ static void asm_guardtnb(ASMState *as, A64Ins ai, Reg r, uint32_t bit)
91 MCode *p = as->mcp; 91 MCode *p = as->mcp;
92 if (LJ_UNLIKELY(p == as->invmcp)) { 92 if (LJ_UNLIKELY(p == as->invmcp)) {
93 as->loopinv = 1; 93 as->loopinv = 1;
94 *p = A64I_B | ((target-p) & 0x03ffffffu); 94 *p = A64I_B | A64F_S26(target-p);
95 emit_tnb(as, ai^0x01000000u, r, bit, p-1); 95 emit_tnb(as, ai^0x01000000u, r, bit, p-1);
96 return; 96 return;
97 } 97 }
@@ -105,7 +105,7 @@ static void asm_guardcnb(ASMState *as, A64Ins ai, Reg r)
105 MCode *p = as->mcp; 105 MCode *p = as->mcp;
106 if (LJ_UNLIKELY(p == as->invmcp)) { 106 if (LJ_UNLIKELY(p == as->invmcp)) {
107 as->loopinv = 1; 107 as->loopinv = 1;
108 *p = A64I_B | ((target-p) & 0x03ffffffu); 108 *p = A64I_B | A64F_S26(target-p);
109 emit_cnb(as, ai^0x01000000u, r, p-1); 109 emit_cnb(as, ai^0x01000000u, r, p-1);
110 return; 110 return;
111 } 111 }
@@ -1850,7 +1850,7 @@ static void asm_loop_fixup(ASMState *as)
1850 p[-2] |= ((uint32_t)delta & mask) << 5; 1850 p[-2] |= ((uint32_t)delta & mask) << 5;
1851 } else { 1851 } else {
1852 ptrdiff_t delta = target - (p - 1); 1852 ptrdiff_t delta = target - (p - 1);
1853 p[-1] = A64I_B | ((uint32_t)(delta) & 0x03ffffffu); 1853 p[-1] = A64I_B | A64F_S26(delta);
1854 } 1854 }
1855} 1855}
1856 1856
@@ -1919,7 +1919,7 @@ static void asm_tail_fixup(ASMState *as, TraceNo lnk)
1919 } 1919 }
1920 /* Patch exit branch. */ 1920 /* Patch exit branch. */
1921 target = lnk ? traceref(as->J, lnk)->mcode : (MCode *)lj_vm_exit_interp; 1921 target = lnk ? traceref(as->J, lnk)->mcode : (MCode *)lj_vm_exit_interp;
1922 p[-1] = A64I_B | (((target-p)+1)&0x03ffffffu); 1922 p[-1] = A64I_B | A64F_S26((target-p)+1);
1923} 1923}
1924 1924
1925/* Prepare tail of code. */ 1925/* Prepare tail of code. */
@@ -1982,40 +1982,50 @@ void lj_asm_patchexit(jit_State *J, GCtrace *T, ExitNo exitno, MCode *target)
1982{ 1982{
1983 MCode *p = T->mcode; 1983 MCode *p = T->mcode;
1984 MCode *pe = (MCode *)((char *)p + T->szmcode); 1984 MCode *pe = (MCode *)((char *)p + T->szmcode);
1985 MCode *cstart = NULL, *cend = p; 1985 MCode *cstart = NULL;
1986 MCode *mcarea = lj_mcode_patch(J, p, 0); 1986 MCode *mcarea = lj_mcode_patch(J, p, 0);
1987 MCode *px = exitstub_trace_addr(T, exitno); 1987 MCode *px = exitstub_trace_addr(T, exitno);
1988 /* Note: this assumes a trace exit is only ever patched once. */
1988 for (; p < pe; p++) { 1989 for (; p < pe; p++) {
1989 /* Look for exitstub branch, replace with branch to target. */ 1990 /* Look for exitstub branch, replace with branch to target. */
1991 ptrdiff_t delta = target - p;
1990 MCode ins = A64I_LE(*p); 1992 MCode ins = A64I_LE(*p);
1991 if ((ins & 0xff000000u) == 0x54000000u && 1993 if ((ins & 0xff000000u) == 0x54000000u &&
1992 ((ins ^ ((px-p)<<5)) & 0x00ffffe0u) == 0) { 1994 ((ins ^ ((px-p)<<5)) & 0x00ffffe0u) == 0) {
1993 /* Patch bcc exitstub. */ 1995 /* Patch bcc, if within range. */
1994 *p = A64I_LE((ins & 0xff00001fu) | (((target-p)<<5) & 0x00ffffe0u)); 1996 if (A64F_S_OK(delta, 19)) {
1995 cend = p+1; 1997 *p = A64I_LE((ins & 0xff00001fu) | A64F_S19(delta));
1996 if (!cstart) cstart = p; 1998 if (!cstart) cstart = p;
1999 }
1997 } else if ((ins & 0xfc000000u) == 0x14000000u && 2000 } else if ((ins & 0xfc000000u) == 0x14000000u &&
1998 ((ins ^ (px-p)) & 0x03ffffffu) == 0) { 2001 ((ins ^ (px-p)) & 0x03ffffffu) == 0) {
1999 /* Patch b exitstub. */ 2002 /* Patch b. */
2000 *p = A64I_LE((ins & 0xfc000000u) | ((target-p) & 0x03ffffffu)); 2003 lua_assert(A64F_S_OK(delta, 26));
2001 cend = p+1; 2004 *p = A64I_LE((ins & 0xfc000000u) | A64F_S26(delta));
2002 if (!cstart) cstart = p; 2005 if (!cstart) cstart = p;
2003 } else if ((ins & 0x7e000000u) == 0x34000000u && 2006 } else if ((ins & 0x7e000000u) == 0x34000000u &&
2004 ((ins ^ ((px-p)<<5)) & 0x00ffffe0u) == 0) { 2007 ((ins ^ ((px-p)<<5)) & 0x00ffffe0u) == 0) {
2005 /* Patch cbz/cbnz exitstub. */ 2008 /* Patch cbz/cbnz, if within range. */
2006 *p = A64I_LE((ins & 0xff00001f) | (((target-p)<<5) & 0x00ffffe0u)); 2009 if (A64F_S_OK(delta, 19)) {
2007 cend = p+1; 2010 *p = A64I_LE((ins & 0xff00001fu) | A64F_S19(delta));
2008 if (!cstart) cstart = p; 2011 if (!cstart) cstart = p;
2012 }
2009 } else if ((ins & 0x7e000000u) == 0x36000000u && 2013 } else if ((ins & 0x7e000000u) == 0x36000000u &&
2010 ((ins ^ ((px-p)<<5)) & 0x0007ffe0u) == 0) { 2014 ((ins ^ ((px-p)<<5)) & 0x0007ffe0u) == 0) {
2011 /* Patch tbz/tbnz exitstub. */ 2015 /* Patch tbz/tbnz, if within range. */
2012 *p = A64I_LE((ins & 0xfff8001fu) | (((target-p)<<5) & 0x0007ffe0u)); 2016 if (A64F_S_OK(delta, 14)) {
2013 cend = p+1; 2017 *p = A64I_LE((ins & 0xfff8001fu) | A64F_S14(delta));
2014 if (!cstart) cstart = p; 2018 if (!cstart) cstart = p;
2019 }
2015 } 2020 }
2016 } 2021 }
2017 lua_assert(cstart != NULL); 2022 { /* Always patch long-range branch in exit stub itself. */
2018 lj_mcode_sync(cstart, cend); 2023 ptrdiff_t delta = target - px;
2024 lua_assert(A64F_S_OK(delta, 26));
2025 *px = A64I_B | A64F_S26(delta);
2026 if (!cstart) cstart = px;
2027 }
2028 lj_mcode_sync(cstart, px+1);
2019 lj_mcode_patch(J, mcarea, 1); 2029 lj_mcode_patch(J, mcarea, 1);
2020} 2030}
2021 2031
diff --git a/src/lj_emit_arm64.h b/src/lj_emit_arm64.h
index 6da4c7d4..1001b1d8 100644
--- a/src/lj_emit_arm64.h
+++ b/src/lj_emit_arm64.h
@@ -241,7 +241,7 @@ static void emit_loadk(ASMState *as, Reg rd, uint64_t u64, int is64)
241#define mcpofs(as, k) \ 241#define mcpofs(as, k) \
242 ((intptr_t)((uintptr_t)(k) - (uintptr_t)(as->mcp - 1))) 242 ((intptr_t)((uintptr_t)(k) - (uintptr_t)(as->mcp - 1)))
243#define checkmcpofs(as, k) \ 243#define checkmcpofs(as, k) \
244 ((((mcpofs(as, k)>>2) + 0x00040000) >> 19) == 0) 244 (A64F_S_OK(mcpofs(as, k)>>2, 19))
245 245
246static Reg ra_allock(ASMState *as, intptr_t k, RegSet allow); 246static Reg ra_allock(ASMState *as, intptr_t k, RegSet allow);
247 247
@@ -312,7 +312,7 @@ static void emit_cond_branch(ASMState *as, A64CC cond, MCode *target)
312{ 312{
313 MCode *p = --as->mcp; 313 MCode *p = --as->mcp;
314 ptrdiff_t delta = target - p; 314 ptrdiff_t delta = target - p;
315 lua_assert(((delta + 0x40000) >> 19) == 0); 315 lua_assert(A64F_S_OK(delta, 19));
316 *p = A64I_BCC | A64F_S19(delta) | cond; 316 *p = A64I_BCC | A64F_S19(delta) | cond;
317} 317}
318 318
@@ -320,24 +320,24 @@ static void emit_branch(ASMState *as, A64Ins ai, MCode *target)
320{ 320{
321 MCode *p = --as->mcp; 321 MCode *p = --as->mcp;
322 ptrdiff_t delta = target - p; 322 ptrdiff_t delta = target - p;
323 lua_assert(((delta + 0x02000000) >> 26) == 0); 323 lua_assert(A64F_S_OK(delta, 26));
324 *p = ai | ((uint32_t)delta & 0x03ffffffu); 324 *p = ai | A64F_S26(delta);
325} 325}
326 326
327static void emit_tnb(ASMState *as, A64Ins ai, Reg r, uint32_t bit, MCode *target) 327static void emit_tnb(ASMState *as, A64Ins ai, Reg r, uint32_t bit, MCode *target)
328{ 328{
329 MCode *p = --as->mcp; 329 MCode *p = --as->mcp;
330 ptrdiff_t delta = target - p; 330 ptrdiff_t delta = target - p;
331 lua_assert(bit < 63 && ((delta + 0x2000) >> 14) == 0); 331 lua_assert(bit < 63 && A64F_S_OK(delta, 14));
332 if (bit > 31) ai |= A64I_X; 332 if (bit > 31) ai |= A64I_X;
333 *p = ai | A64F_BIT(bit & 31) | A64F_S14((uint32_t)delta & 0x3fffu) | r; 333 *p = ai | A64F_BIT(bit & 31) | A64F_S14(delta) | r;
334} 334}
335 335
336static void emit_cnb(ASMState *as, A64Ins ai, Reg r, MCode *target) 336static void emit_cnb(ASMState *as, A64Ins ai, Reg r, MCode *target)
337{ 337{
338 MCode *p = --as->mcp; 338 MCode *p = --as->mcp;
339 ptrdiff_t delta = target - p; 339 ptrdiff_t delta = target - p;
340 lua_assert(((delta + 0x40000) >> 19) == 0); 340 lua_assert(A64F_S_OK(delta, 19));
341 *p = ai | A64F_S19(delta) | r; 341 *p = ai | A64F_S19(delta) | r;
342} 342}
343 343
@@ -347,8 +347,8 @@ static void emit_call(ASMState *as, void *target)
347{ 347{
348 MCode *p = --as->mcp; 348 MCode *p = --as->mcp;
349 ptrdiff_t delta = (char *)target - (char *)p; 349 ptrdiff_t delta = (char *)target - (char *)p;
350 if ((((delta>>2) + 0x02000000) >> 26) == 0) { 350 if (A64F_S_OK(delta>>2, 26)) {
351 *p = A64I_BL | ((uint32_t)(delta>>2) & 0x03ffffffu); 351 *p = A64I_BL | A64F_S26(delta>>2);
352 } else { /* Target out of range: need indirect call. But don't use R0-R7. */ 352 } else { /* Target out of range: need indirect call. But don't use R0-R7. */
353 Reg r = ra_allock(as, i64ptr(target), 353 Reg r = ra_allock(as, i64ptr(target),
354 RSET_RANGE(RID_X8, RID_MAX_GPR)-RSET_FIXED); 354 RSET_RANGE(RID_X8, RID_MAX_GPR)-RSET_FIXED);
diff --git a/src/lj_target_arm64.h b/src/lj_target_arm64.h
index 520023ae..a207a2ba 100644
--- a/src/lj_target_arm64.h
+++ b/src/lj_target_arm64.h
@@ -132,9 +132,9 @@ static LJ_AINLINE uint32_t *exitstub_trace_addr_(uint32_t *p, uint32_t exitno)
132#define A64F_IMMR(x) ((x) << 16) 132#define A64F_IMMR(x) ((x) << 16)
133#define A64F_U16(x) ((x) << 5) 133#define A64F_U16(x) ((x) << 5)
134#define A64F_U12(x) ((x) << 10) 134#define A64F_U12(x) ((x) << 10)
135#define A64F_S26(x) (x) 135#define A64F_S26(x) (((uint32_t)(x) & 0x03ffffffu))
136#define A64F_S19(x) (((uint32_t)(x) & 0x7ffffu) << 5) 136#define A64F_S19(x) (((uint32_t)(x) & 0x7ffffu) << 5)
137#define A64F_S14(x) ((x) << 5) 137#define A64F_S14(x) (((uint32_t)(x) & 0x3fffu) << 5)
138#define A64F_S9(x) ((x) << 12) 138#define A64F_S9(x) ((x) << 12)
139#define A64F_BIT(x) ((x) << 19) 139#define A64F_BIT(x) ((x) << 19)
140#define A64F_SH(sh, x) (((sh) << 22) | ((x) << 10)) 140#define A64F_SH(sh, x) (((sh) << 22) | ((x) << 10))
@@ -145,6 +145,9 @@ static LJ_AINLINE uint32_t *exitstub_trace_addr_(uint32_t *p, uint32_t exitno)
145#define A64F_LSL16(x) (((x) / 16) << 21) 145#define A64F_LSL16(x) (((x) / 16) << 21)
146#define A64F_BSH(sh) ((sh) << 10) 146#define A64F_BSH(sh) ((sh) << 10)
147 147
148/* Check for valid field range. */
149#define A64F_S_OK(x, b) ((((x) + (1 << (b-1))) >> (b)) == 0)
150
148typedef enum A64Ins { 151typedef enum A64Ins {
149 A64I_S = 0x20000000, 152 A64I_S = 0x20000000,
150 A64I_X = 0x80000000, 153 A64I_X = 0x80000000,