aboutsummaryrefslogtreecommitdiff
path: root/src/lj_emit_mips.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/lj_emit_mips.h')
-rw-r--r--src/lj_emit_mips.h153
1 files changed, 125 insertions, 28 deletions
diff --git a/src/lj_emit_mips.h b/src/lj_emit_mips.h
index f3dcd1dd..bdabcf16 100644
--- a/src/lj_emit_mips.h
+++ b/src/lj_emit_mips.h
@@ -3,6 +3,30 @@
3** Copyright (C) 2005-2020 Mike Pall. See Copyright Notice in luajit.h 3** Copyright (C) 2005-2020 Mike Pall. See Copyright Notice in luajit.h
4*/ 4*/
5 5
6#if LJ_64
7static intptr_t get_k64val(IRIns *ir)
8{
9 if (ir->o == IR_KINT64) {
10 return (intptr_t)ir_kint64(ir)->u64;
11 } else if (ir->o == IR_KGC) {
12 return (intptr_t)ir_kgc(ir);
13 } else if (ir->o == IR_KPTR || ir->o == IR_KKPTR) {
14 return (intptr_t)ir_kptr(ir);
15 } else if (LJ_SOFTFP && ir->o == IR_KNUM) {
16 return (intptr_t)ir_knum(ir)->u64;
17 } else {
18 lua_assert(ir->o == IR_KINT || ir->o == IR_KNULL);
19 return ir->i; /* Sign-extended. */
20 }
21}
22#endif
23
24#if LJ_64
25#define get_kval(ir) get_k64val(ir)
26#else
27#define get_kval(ir) ((ir)->i)
28#endif
29
6/* -- Emit basic instructions --------------------------------------------- */ 30/* -- Emit basic instructions --------------------------------------------- */
7 31
8static void emit_dst(ASMState *as, MIPSIns mi, Reg rd, Reg rs, Reg rt) 32static void emit_dst(ASMState *as, MIPSIns mi, Reg rd, Reg rs, Reg rt)
@@ -35,7 +59,7 @@ static void emit_fgh(ASMState *as, MIPSIns mi, Reg rf, Reg rg, Reg rh)
35 59
36static void emit_rotr(ASMState *as, Reg dest, Reg src, Reg tmp, uint32_t shift) 60static void emit_rotr(ASMState *as, Reg dest, Reg src, Reg tmp, uint32_t shift)
37{ 61{
38 if ((as->flags & JIT_F_MIPS32R2)) { 62 if (LJ_64 || (as->flags & JIT_F_MIPSXXR2)) {
39 emit_dta(as, MIPSI_ROTR, dest, src, shift); 63 emit_dta(as, MIPSI_ROTR, dest, src, shift);
40 } else { 64 } else {
41 emit_dst(as, MIPSI_OR, dest, dest, tmp); 65 emit_dst(as, MIPSI_OR, dest, dest, tmp);
@@ -44,13 +68,21 @@ static void emit_rotr(ASMState *as, Reg dest, Reg src, Reg tmp, uint32_t shift)
44 } 68 }
45} 69}
46 70
71#if LJ_64
72static void emit_tsml(ASMState *as, MIPSIns mi, Reg rt, Reg rs, uint32_t msb,
73 uint32_t lsb)
74{
75 *--as->mcp = mi | MIPSF_T(rt) | MIPSF_S(rs) | MIPSF_M(msb) | MIPSF_L(lsb);
76}
77#endif
78
47/* -- Emit loads/stores --------------------------------------------------- */ 79/* -- Emit loads/stores --------------------------------------------------- */
48 80
49/* Prefer rematerialization of BASE/L from global_State over spills. */ 81/* Prefer rematerialization of BASE/L from global_State over spills. */
50#define emit_canremat(ref) ((ref) <= REF_BASE) 82#define emit_canremat(ref) ((ref) <= REF_BASE)
51 83
52/* Try to find a one step delta relative to another constant. */ 84/* Try to find a one step delta relative to another constant. */
53static int emit_kdelta1(ASMState *as, Reg t, int32_t i) 85static int emit_kdelta1(ASMState *as, Reg t, intptr_t i)
54{ 86{
55 RegSet work = ~as->freeset & RSET_GPR; 87 RegSet work = ~as->freeset & RSET_GPR;
56 while (work) { 88 while (work) {
@@ -58,9 +90,10 @@ static int emit_kdelta1(ASMState *as, Reg t, int32_t i)
58 IRRef ref = regcost_ref(as->cost[r]); 90 IRRef ref = regcost_ref(as->cost[r]);
59 lua_assert(r != t); 91 lua_assert(r != t);
60 if (ref < ASMREF_L) { 92 if (ref < ASMREF_L) {
61 int32_t delta = i - (ra_iskref(ref) ? ra_krefk(as, ref) : IR(ref)->i); 93 intptr_t delta = (intptr_t)((uintptr_t)i -
94 (uintptr_t)(ra_iskref(ref) ? ra_krefk(as, ref) : get_kval(IR(ref))));
62 if (checki16(delta)) { 95 if (checki16(delta)) {
63 emit_tsi(as, MIPSI_ADDIU, t, r, delta); 96 emit_tsi(as, MIPSI_AADDIU, t, r, delta);
64 return 1; 97 return 1;
65 } 98 }
66 } 99 }
@@ -76,8 +109,8 @@ static void emit_loadi(ASMState *as, Reg r, int32_t i)
76 emit_ti(as, MIPSI_LI, r, i); 109 emit_ti(as, MIPSI_LI, r, i);
77 } else { 110 } else {
78 if ((i & 0xffff)) { 111 if ((i & 0xffff)) {
79 int32_t jgl = i32ptr(J2G(as->J)); 112 intptr_t jgl = (intptr_t)(void *)J2G(as->J);
80 if ((uint32_t)(i-jgl) < 65536) { 113 if ((uintptr_t)(i-jgl) < 65536) {
81 emit_tsi(as, MIPSI_ADDIU, r, RID_JGL, i-jgl-32768); 114 emit_tsi(as, MIPSI_ADDIU, r, RID_JGL, i-jgl-32768);
82 return; 115 return;
83 } else if (emit_kdelta1(as, r, i)) { 116 } else if (emit_kdelta1(as, r, i)) {
@@ -92,16 +125,49 @@ static void emit_loadi(ASMState *as, Reg r, int32_t i)
92 } 125 }
93} 126}
94 127
128#if LJ_64
129/* Load a 64 bit constant into a GPR. */
130static void emit_loadu64(ASMState *as, Reg r, uint64_t u64)
131{
132 if (checki32((int64_t)u64)) {
133 emit_loadi(as, r, (int32_t)u64);
134 } else {
135 uint64_t delta = u64 - (uint64_t)(void *)J2G(as->J);
136 if (delta < 65536) {
137 emit_tsi(as, MIPSI_DADDIU, r, RID_JGL, (int32_t)(delta-32768));
138 } else if (emit_kdelta1(as, r, (intptr_t)u64)) {
139 return;
140 } else {
141 /* TODO MIPSR6: Use DAHI & DATI. Caveat: sign-extension. */
142 if ((u64 & 0xffff)) {
143 emit_tsi(as, MIPSI_ORI, r, r, u64 & 0xffff);
144 }
145 if (((u64 >> 16) & 0xffff)) {
146 emit_dta(as, MIPSI_DSLL, r, r, 16);
147 emit_tsi(as, MIPSI_ORI, r, r, (u64 >> 16) & 0xffff);
148 emit_dta(as, MIPSI_DSLL, r, r, 16);
149 } else {
150 emit_dta(as, MIPSI_DSLL32, r, r, 0);
151 }
152 emit_loadi(as, r, (int32_t)(u64 >> 32));
153 }
154 /* TODO: There are probably more optimization opportunities. */
155 }
156}
157
158#define emit_loada(as, r, addr) emit_loadu64(as, (r), u64ptr((addr)))
159#else
95#define emit_loada(as, r, addr) emit_loadi(as, (r), i32ptr((addr))) 160#define emit_loada(as, r, addr) emit_loadi(as, (r), i32ptr((addr)))
161#endif
96 162
97static Reg ra_allock(ASMState *as, int32_t k, RegSet allow); 163static Reg ra_allock(ASMState *as, intptr_t k, RegSet allow);
98static void ra_allockreg(ASMState *as, int32_t k, Reg r); 164static void ra_allockreg(ASMState *as, intptr_t k, Reg r);
99 165
100/* Get/set from constant pointer. */ 166/* Get/set from constant pointer. */
101static void emit_lsptr(ASMState *as, MIPSIns mi, Reg r, void *p, RegSet allow) 167static void emit_lsptr(ASMState *as, MIPSIns mi, Reg r, void *p, RegSet allow)
102{ 168{
103 int32_t jgl = i32ptr(J2G(as->J)); 169 intptr_t jgl = (intptr_t)(J2G(as->J));
104 int32_t i = i32ptr(p); 170 intptr_t i = (intptr_t)(p);
105 Reg base; 171 Reg base;
106 if ((uint32_t)(i-jgl) < 65536) { 172 if ((uint32_t)(i-jgl) < 65536) {
107 i = i-jgl-32768; 173 i = i-jgl-32768;
@@ -112,8 +178,24 @@ static void emit_lsptr(ASMState *as, MIPSIns mi, Reg r, void *p, RegSet allow)
112 emit_tsi(as, mi, r, base, i); 178 emit_tsi(as, mi, r, base, i);
113} 179}
114 180
115#define emit_loadn(as, r, tv) \ 181#if LJ_64
116 emit_lsptr(as, MIPSI_LDC1, ((r) & 31), (void *)(tv), RSET_GPR) 182static void emit_loadk64(ASMState *as, Reg r, IRIns *ir)
183{
184 const uint64_t *k = &ir_k64(ir)->u64;
185 Reg r64 = r;
186 if (rset_test(RSET_FPR, r)) {
187 r64 = RID_TMP;
188 emit_tg(as, MIPSI_DMTC1, r64, r);
189 }
190 if ((uint32_t)((intptr_t)k-(intptr_t)J2G(as->J)) < 65536)
191 emit_lsptr(as, MIPSI_LD, r64, (void *)k, 0);
192 else
193 emit_loadu64(as, r64, *k);
194}
195#else
196#define emit_loadk64(as, r, ir) \
197 emit_lsptr(as, MIPSI_LDC1, ((r) & 31), (void *)&ir_knum((ir))->u64, RSET_GPR)
198#endif
117 199
118/* Get/set global_State fields. */ 200/* Get/set global_State fields. */
119static void emit_lsglptr(ASMState *as, MIPSIns mi, Reg r, int32_t ofs) 201static void emit_lsglptr(ASMState *as, MIPSIns mi, Reg r, int32_t ofs)
@@ -122,9 +204,9 @@ static void emit_lsglptr(ASMState *as, MIPSIns mi, Reg r, int32_t ofs)
122} 204}
123 205
124#define emit_getgl(as, r, field) \ 206#define emit_getgl(as, r, field) \
125 emit_lsglptr(as, MIPSI_LW, (r), (int32_t)offsetof(global_State, field)) 207 emit_lsglptr(as, MIPSI_AL, (r), (int32_t)offsetof(global_State, field))
126#define emit_setgl(as, r, field) \ 208#define emit_setgl(as, r, field) \
127 emit_lsglptr(as, MIPSI_SW, (r), (int32_t)offsetof(global_State, field)) 209 emit_lsglptr(as, MIPSI_AS, (r), (int32_t)offsetof(global_State, field))
128 210
129/* Trace number is determined from per-trace exit stubs. */ 211/* Trace number is determined from per-trace exit stubs. */
130#define emit_setvmstate(as, i) UNUSED(i) 212#define emit_setvmstate(as, i) UNUSED(i)
@@ -152,16 +234,31 @@ static void emit_jmp(ASMState *as, MCode *target)
152 emit_branch(as, MIPSI_B, RID_ZERO, RID_ZERO, (target)); 234 emit_branch(as, MIPSI_B, RID_ZERO, RID_ZERO, (target));
153} 235}
154 236
155static void emit_call(ASMState *as, void *target) 237static void emit_call(ASMState *as, void *target, int needcfa)
156{ 238{
157 MCode *p = as->mcp; 239 MCode *p = as->mcp;
158 *--p = MIPSI_NOP; 240#if LJ_TARGET_MIPSR6
159 if ((((uintptr_t)target ^ (uintptr_t)p) >> 28) == 0) 241 ptrdiff_t delta = (char *)target - (char *)p;
242 if ((((delta>>2) + 0x02000000) >> 26) == 0) { /* Try compact call first. */
243 *--p = MIPSI_BALC | (((uintptr_t)delta >>2) & 0x03ffffffu);
244 as->mcp = p;
245 return;
246 }
247#endif
248 *--p = MIPSI_NOP; /* Delay slot. */
249 if ((((uintptr_t)target ^ (uintptr_t)p) >> 28) == 0) {
250#if !LJ_TARGET_MIPSR6
251 *--p = (((uintptr_t)target & 1) ? MIPSI_JALX : MIPSI_JAL) |
252 (((uintptr_t)target >>2) & 0x03ffffffu);
253#else
160 *--p = MIPSI_JAL | (((uintptr_t)target >>2) & 0x03ffffffu); 254 *--p = MIPSI_JAL | (((uintptr_t)target >>2) & 0x03ffffffu);
161 else /* Target out of range: need indirect call. */ 255#endif
256 } else { /* Target out of range: need indirect call. */
162 *--p = MIPSI_JALR | MIPSF_S(RID_CFUNCADDR); 257 *--p = MIPSI_JALR | MIPSF_S(RID_CFUNCADDR);
258 needcfa = 1;
259 }
163 as->mcp = p; 260 as->mcp = p;
164 ra_allockreg(as, i32ptr(target), RID_CFUNCADDR); 261 if (needcfa) ra_allockreg(as, (intptr_t)target, RID_CFUNCADDR);
165} 262}
166 263
167/* -- Emit generic operations --------------------------------------------- */ 264/* -- Emit generic operations --------------------------------------------- */
@@ -178,24 +275,24 @@ static void emit_movrr(ASMState *as, IRIns *ir, Reg dst, Reg src)
178 emit_fg(as, irt_isnum(ir->t) ? MIPSI_MOV_D : MIPSI_MOV_S, dst, src); 275 emit_fg(as, irt_isnum(ir->t) ? MIPSI_MOV_D : MIPSI_MOV_S, dst, src);
179} 276}
180 277
181/* Generic load of register from stack slot. */ 278/* Generic load of register with base and (small) offset address. */
182static void emit_spload(ASMState *as, IRIns *ir, Reg r, int32_t ofs) 279static void emit_loadofs(ASMState *as, IRIns *ir, Reg r, Reg base, int32_t ofs)
183{ 280{
184 if (r < RID_MAX_GPR) 281 if (r < RID_MAX_GPR)
185 emit_tsi(as, MIPSI_LW, r, RID_SP, ofs); 282 emit_tsi(as, irt_is64(ir->t) ? MIPSI_LD : MIPSI_LW, r, base, ofs);
186 else 283 else
187 emit_tsi(as, irt_isnum(ir->t) ? MIPSI_LDC1 : MIPSI_LWC1, 284 emit_tsi(as, irt_isnum(ir->t) ? MIPSI_LDC1 : MIPSI_LWC1,
188 (r & 31), RID_SP, ofs); 285 (r & 31), base, ofs);
189} 286}
190 287
191/* Generic store of register to stack slot. */ 288/* Generic store of register with base and (small) offset address. */
192static void emit_spstore(ASMState *as, IRIns *ir, Reg r, int32_t ofs) 289static void emit_storeofs(ASMState *as, IRIns *ir, Reg r, Reg base, int32_t ofs)
193{ 290{
194 if (r < RID_MAX_GPR) 291 if (r < RID_MAX_GPR)
195 emit_tsi(as, MIPSI_SW, r, RID_SP, ofs); 292 emit_tsi(as, irt_is64(ir->t) ? MIPSI_SD : MIPSI_SW, r, base, ofs);
196 else 293 else
197 emit_tsi(as, irt_isnum(ir->t) ? MIPSI_SDC1 : MIPSI_SWC1, 294 emit_tsi(as, irt_isnum(ir->t) ? MIPSI_SDC1 : MIPSI_SWC1,
198 (r&31), RID_SP, ofs); 295 (r&31), base, ofs);
199} 296}
200 297
201/* Add offset to pointer. */ 298/* Add offset to pointer. */
@@ -203,7 +300,7 @@ static void emit_addptr(ASMState *as, Reg r, int32_t ofs)
203{ 300{
204 if (ofs) { 301 if (ofs) {
205 lua_assert(checki16(ofs)); 302 lua_assert(checki16(ofs));
206 emit_tsi(as, MIPSI_ADDIU, r, r, ofs); 303 emit_tsi(as, MIPSI_AADDIU, r, r, ofs);
207 } 304 }
208} 305}
209 306