diff options
-rw-r--r-- | src/lj_asm_arm64.h | 64 | ||||
-rw-r--r-- | src/lj_emit_arm64.h | 18 | ||||
-rw-r--r-- | src/lj_target_arm64.h | 7 |
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 | ||
246 | static Reg ra_allock(ASMState *as, intptr_t k, RegSet allow); | 246 | static 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 | ||
327 | static void emit_tnb(ASMState *as, A64Ins ai, Reg r, uint32_t bit, MCode *target) | 327 | static 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 | ||
336 | static void emit_cnb(ASMState *as, A64Ins ai, Reg r, MCode *target) | 336 | static 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 | |||
148 | typedef enum A64Ins { | 151 | typedef enum A64Ins { |
149 | A64I_S = 0x20000000, | 152 | A64I_S = 0x20000000, |
150 | A64I_X = 0x80000000, | 153 | A64I_X = 0x80000000, |