diff options
Diffstat (limited to 'src/lj_emit_mips.h')
-rw-r--r-- | src/lj_emit_mips.h | 153 |
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 | ||
7 | static 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 | ||
8 | static void emit_dst(ASMState *as, MIPSIns mi, Reg rd, Reg rs, Reg rt) | 32 | static 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 | ||
36 | static void emit_rotr(ASMState *as, Reg dest, Reg src, Reg tmp, uint32_t shift) | 60 | static 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 | ||
72 | static 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. */ |
53 | static int emit_kdelta1(ASMState *as, Reg t, int32_t i) | 85 | static 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. */ | ||
130 | static 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 | ||
97 | static Reg ra_allock(ASMState *as, int32_t k, RegSet allow); | 163 | static Reg ra_allock(ASMState *as, intptr_t k, RegSet allow); |
98 | static void ra_allockreg(ASMState *as, int32_t k, Reg r); | 164 | static void ra_allockreg(ASMState *as, intptr_t k, Reg r); |
99 | 165 | ||
100 | /* Get/set from constant pointer. */ | 166 | /* Get/set from constant pointer. */ |
101 | static void emit_lsptr(ASMState *as, MIPSIns mi, Reg r, void *p, RegSet allow) | 167 | static 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) | 182 | static 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. */ |
119 | static void emit_lsglptr(ASMState *as, MIPSIns mi, Reg r, int32_t ofs) | 201 | static 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 | ||
155 | static void emit_call(ASMState *as, void *target) | 237 | static 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. */ |
182 | static void emit_spload(ASMState *as, IRIns *ir, Reg r, int32_t ofs) | 279 | static 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. */ |
192 | static void emit_spstore(ASMState *as, IRIns *ir, Reg r, int32_t ofs) | 289 | static 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 | ||