git subrepo pull --force deps/lightrec
[pcsx_rearmed.git] / deps / lightrec / regcache.c
CommitLineData
98fa08a5 1// SPDX-License-Identifier: LGPL-2.1-or-later
d16005f8 2/*
98fa08a5 3 * Copyright (C) 2014-2021 Paul Cercueil <paul@crapouillou.net>
d16005f8
PC
4 */
5
6#include "debug.h"
7#include "memmanager.h"
98fa08a5 8#include "lightning-wrapper.h"
d16005f8
PC
9#include "regcache.h"
10
d16005f8
PC
11#include <stdbool.h>
12#include <stddef.h>
13
0e720fb1 14#define REG_PC (offsetof(struct lightrec_state, curr_pc) / sizeof(u32))
9259d748 15
ba3814c1
PC
16enum reg_priority {
17 REG_IS_TEMP,
18 REG_IS_TEMP_VALUE,
19 REG_IS_ZERO,
20 REG_IS_LOADED,
21 REG_IS_DIRTY,
22
23 REG_NB_PRIORITIES,
24};
25
d16005f8 26struct native_register {
ba3814c1 27 bool used, output, extend, extended,
98fa08a5 28 zero_extend, zero_extended, locked;
9259d748 29 s16 emulated_register;
ba3814c1
PC
30 intptr_t value;
31 enum reg_priority prio;
d16005f8
PC
32};
33
34struct regcache {
35 struct lightrec_state *state;
36 struct native_register lightrec_regs[NUM_REGS + NUM_TEMPS];
37};
38
39static const char * mips_regs[] = {
40 "zero",
41 "at",
42 "v0", "v1",
43 "a0", "a1", "a2", "a3",
44 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
45 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
46 "t8", "t9",
47 "k0", "k1",
48 "gp", "sp", "fp", "ra",
49 "lo", "hi",
50};
51
cb72ea13
PC
52/* Forward declaration(s) */
53static void clean_reg(jit_state_t *_jit,
54 struct native_register *nreg, u8 jit_reg, bool clean);
55
d16005f8
PC
56const char * lightrec_reg_name(u8 reg)
57{
58 return mips_regs[reg];
59}
60
98fa08a5
PC
61static inline bool lightrec_reg_is_zero(u8 jit_reg)
62{
63#if defined(__mips__) || defined(__alpha__) || defined(__riscv)
64 if (jit_reg == _ZERO)
65 return true;
66#endif
67 return false;
68}
69
9259d748 70static inline s8 lightrec_get_hardwired_reg(u16 reg)
98fa08a5
PC
71{
72#if defined(__mips__) || defined(__alpha__) || defined(__riscv)
73 if (reg == 0)
74 return _ZERO;
75#endif
76 return -1;
77}
78
d16005f8
PC
79static inline u8 lightrec_reg_number(const struct regcache *cache,
80 const struct native_register *nreg)
81{
82 return (u8) (((uintptr_t) nreg - (uintptr_t) cache->lightrec_regs)
83 / sizeof(*nreg));
84}
85
86static inline u8 lightrec_reg_to_lightning(const struct regcache *cache,
87 const struct native_register *nreg)
88{
89 u8 offset = lightrec_reg_number(cache, nreg);
ba3814c1
PC
90
91 if (offset < NUM_REGS)
92 return JIT_V(FIRST_REG + offset);
93 else
94 return JIT_R(FIRST_TEMP + offset - NUM_REGS);
d16005f8
PC
95}
96
97static inline struct native_register * lightning_reg_to_lightrec(
98 struct regcache *cache, u8 reg)
99{
100 if ((JIT_V0 > JIT_R0 && reg >= JIT_V0) ||
101 (JIT_V0 < JIT_R0 && reg < JIT_R0)) {
102 if (JIT_V1 > JIT_V0)
ba3814c1 103 return &cache->lightrec_regs[reg - JIT_V(FIRST_REG)];
d16005f8 104 else
ba3814c1 105 return &cache->lightrec_regs[JIT_V(FIRST_REG) - reg];
d16005f8
PC
106 } else {
107 if (JIT_R1 > JIT_R0)
ba3814c1 108 return &cache->lightrec_regs[NUM_REGS + reg - JIT_R(FIRST_TEMP)];
d16005f8 109 else
ba3814c1 110 return &cache->lightrec_regs[NUM_REGS + JIT_R(FIRST_TEMP) - reg];
d16005f8
PC
111 }
112}
113
98fa08a5
PC
114u8 lightrec_get_reg_in_flags(struct regcache *cache, u8 jit_reg)
115{
116 struct native_register *reg;
117 u8 flags = 0;
118
119 if (lightrec_reg_is_zero(jit_reg))
120 return REG_EXT | REG_ZEXT;
121
122 reg = lightning_reg_to_lightrec(cache, jit_reg);
123 if (reg->extended)
124 flags |= REG_EXT;
125 if (reg->zero_extended)
126 flags |= REG_ZEXT;
127
128 return flags;
129}
130
131void lightrec_set_reg_out_flags(struct regcache *cache, u8 jit_reg, u8 flags)
132{
133 struct native_register *reg;
134
135 if (!lightrec_reg_is_zero(jit_reg)) {
136 reg = lightning_reg_to_lightrec(cache, jit_reg);
137 reg->extend = flags & REG_EXT;
138 reg->zero_extend = flags & REG_ZEXT;
139 }
140}
141
d16005f8
PC
142static struct native_register * alloc_temp(struct regcache *cache)
143{
ba3814c1
PC
144 struct native_register *elm, *nreg = NULL;
145 enum reg_priority best = REG_NB_PRIORITIES;
d16005f8
PC
146 unsigned int i;
147
148 /* We search the register list in reverse order. As temporaries are
149 * meant to be used only in the emitter functions, they can be mapped to
150 * caller-saved registers, as they won't have to be saved back to
151 * memory. */
152 for (i = ARRAY_SIZE(cache->lightrec_regs); i; i--) {
ba3814c1 153 elm = &cache->lightrec_regs[i - 1];
d16005f8 154
9259d748 155 if (!elm->used && !elm->locked && elm->prio < best) {
ba3814c1
PC
156 nreg = elm;
157 best = elm->prio;
158
159 if (best == REG_IS_TEMP)
160 break;
161 }
d16005f8
PC
162 }
163
ba3814c1 164 return nreg;
d16005f8
PC
165}
166
167static struct native_register * find_mapped_reg(struct regcache *cache,
9259d748 168 u16 reg, bool out)
d16005f8
PC
169{
170 unsigned int i;
171
172 for (i = 0; i < ARRAY_SIZE(cache->lightrec_regs); i++) {
173 struct native_register *nreg = &cache->lightrec_regs[i];
ba3814c1
PC
174 if ((nreg->prio >= REG_IS_ZERO) &&
175 nreg->emulated_register == reg &&
176 (!out || !nreg->locked))
d16005f8
PC
177 return nreg;
178 }
179
180 return NULL;
181}
182
183static struct native_register * alloc_in_out(struct regcache *cache,
9259d748 184 u16 reg, bool out)
d16005f8 185{
ba3814c1
PC
186 struct native_register *elm, *nreg = NULL;
187 enum reg_priority best = REG_NB_PRIORITIES;
d16005f8
PC
188 unsigned int i;
189
190 /* Try to find if the register is already mapped somewhere */
191 nreg = find_mapped_reg(cache, reg, out);
192 if (nreg)
193 return nreg;
194
ba3814c1 195 nreg = NULL;
d16005f8 196
d16005f8 197 for (i = 0; i < ARRAY_SIZE(cache->lightrec_regs); i++) {
ba3814c1 198 elm = &cache->lightrec_regs[i];
d16005f8 199
9259d748 200 if (!elm->used && !elm->locked && elm->prio < best) {
ba3814c1
PC
201 nreg = elm;
202 best = elm->prio;
203
204 if (best == REG_IS_TEMP)
205 break;
206 }
d16005f8
PC
207 }
208
ba3814c1 209 return nreg;
d16005f8
PC
210}
211
212static void lightrec_discard_nreg(struct native_register *nreg)
213{
214 nreg->extended = false;
98fa08a5 215 nreg->zero_extended = false;
d16005f8 216 nreg->output = false;
d16005f8
PC
217 nreg->used = false;
218 nreg->locked = false;
219 nreg->emulated_register = -1;
ba3814c1 220 nreg->prio = 0;
d16005f8
PC
221}
222
223static void lightrec_unload_nreg(struct regcache *cache, jit_state_t *_jit,
224 struct native_register *nreg, u8 jit_reg)
225{
cb72ea13 226 clean_reg(_jit, nreg, jit_reg, false);
d16005f8
PC
227 lightrec_discard_nreg(nreg);
228}
229
230void lightrec_unload_reg(struct regcache *cache, jit_state_t *_jit, u8 jit_reg)
231{
98fa08a5
PC
232 if (lightrec_reg_is_zero(jit_reg))
233 return;
234
d16005f8
PC
235 lightrec_unload_nreg(cache, _jit,
236 lightning_reg_to_lightrec(cache, jit_reg), jit_reg);
237}
238
d16005f8
PC
239u8 lightrec_alloc_reg(struct regcache *cache, jit_state_t *_jit, u8 jit_reg)
240{
98fa08a5 241 struct native_register *reg;
d16005f8 242
98fa08a5
PC
243 if (lightrec_reg_is_zero(jit_reg))
244 return jit_reg;
245
246 reg = lightning_reg_to_lightrec(cache, jit_reg);
d16005f8
PC
247 lightrec_unload_nreg(cache, _jit, reg, jit_reg);
248
249 reg->used = true;
ba3814c1 250 reg->prio = REG_IS_LOADED;
d16005f8
PC
251 return jit_reg;
252}
253
254u8 lightrec_alloc_reg_temp(struct regcache *cache, jit_state_t *_jit)
255{
256 u8 jit_reg;
257 struct native_register *nreg = alloc_temp(cache);
258 if (!nreg) {
259 /* No free register, no dirty register to free. */
260 pr_err("No more registers! Abandon ship!\n");
261 return 0;
262 }
263
264 jit_reg = lightrec_reg_to_lightning(cache, nreg);
265 lightrec_unload_nreg(cache, _jit, nreg, jit_reg);
266
ba3814c1 267 nreg->prio = REG_IS_TEMP;
d16005f8
PC
268 nreg->used = true;
269 return jit_reg;
270}
271
ba3814c1
PC
272s8 lightrec_get_reg_with_value(struct regcache *cache, intptr_t value)
273{
274 struct native_register *nreg;
275 unsigned int i;
276
277 for (i = 0; i < ARRAY_SIZE(cache->lightrec_regs); i++) {
278 nreg = &cache->lightrec_regs[i];
279
280 if (nreg->prio == REG_IS_TEMP_VALUE && nreg->value == value) {
281 nreg->used = true;
282 return lightrec_reg_to_lightning(cache, nreg);
283 }
284 }
285
286 return -1;
287}
288
289void lightrec_temp_set_value(struct regcache *cache, u8 jit_reg, intptr_t value)
290{
291 struct native_register *nreg;
292
293 nreg = lightning_reg_to_lightrec(cache, jit_reg);
294
295 nreg->prio = REG_IS_TEMP_VALUE;
296 nreg->value = value;
297}
298
684432ad
PC
299u8 lightrec_alloc_reg_temp_with_value(struct regcache *cache,
300 jit_state_t *_jit, intptr_t value)
301{
302 s8 reg;
303
304 reg = lightrec_get_reg_with_value(cache, value);
305 if (reg < 0) {
306 reg = lightrec_alloc_reg_temp(cache, _jit);
307 jit_movi((u8)reg, value);
308 lightrec_temp_set_value(cache, (u8)reg, value);
309 }
310
311 return (u8)reg;
312}
313
98fa08a5 314u8 lightrec_alloc_reg_out(struct regcache *cache, jit_state_t *_jit,
9259d748 315 u16 reg, u8 flags)
d16005f8 316{
98fa08a5 317 struct native_register *nreg;
d16005f8 318 u8 jit_reg;
98fa08a5
PC
319 s8 hw_reg;
320
321 hw_reg = lightrec_get_hardwired_reg(reg);
322 if (hw_reg >= 0)
323 return (u8) hw_reg;
324
325 nreg = alloc_in_out(cache, reg, true);
d16005f8
PC
326 if (!nreg) {
327 /* No free register, no dirty register to free. */
328 pr_err("No more registers! Abandon ship!\n");
329 return 0;
330 }
331
332 jit_reg = lightrec_reg_to_lightning(cache, nreg);
333
334 /* If we get a dirty register that doesn't correspond to the one
335 * we're requesting, store back the old value */
336 if (nreg->emulated_register != reg)
337 lightrec_unload_nreg(cache, _jit, nreg, jit_reg);
338
d16005f8
PC
339 nreg->used = true;
340 nreg->output = true;
341 nreg->emulated_register = reg;
98fa08a5
PC
342 nreg->extend = flags & REG_EXT;
343 nreg->zero_extend = flags & REG_ZEXT;
ba3814c1 344 nreg->prio = reg ? REG_IS_LOADED : REG_IS_ZERO;
d16005f8
PC
345 return jit_reg;
346}
347
98fa08a5 348u8 lightrec_alloc_reg_in(struct regcache *cache, jit_state_t *_jit,
9259d748 349 u16 reg, u8 flags)
d16005f8 350{
98fa08a5 351 struct native_register *nreg;
d16005f8
PC
352 u8 jit_reg;
353 bool reg_changed;
98fa08a5
PC
354 s8 hw_reg;
355
356 hw_reg = lightrec_get_hardwired_reg(reg);
357 if (hw_reg >= 0)
358 return (u8) hw_reg;
359
360 nreg = alloc_in_out(cache, reg, false);
d16005f8
PC
361 if (!nreg) {
362 /* No free register, no dirty register to free. */
363 pr_err("No more registers! Abandon ship!\n");
364 return 0;
365 }
366
367 jit_reg = lightrec_reg_to_lightning(cache, nreg);
368
369 /* If we get a dirty register that doesn't correspond to the one
370 * we're requesting, store back the old value */
371 reg_changed = nreg->emulated_register != reg;
372 if (reg_changed)
373 lightrec_unload_nreg(cache, _jit, nreg, jit_reg);
374
ba3814c1 375 if (nreg->prio < REG_IS_LOADED && reg != 0) {
8afce295 376 s16 offset = lightrec_offset(regs.gpr) + (reg << 2);
d16005f8 377
98fa08a5
PC
378 nreg->zero_extended = flags & REG_ZEXT;
379 nreg->extended = !nreg->zero_extended;
380
d16005f8 381 /* Load previous value from register cache */
98fa08a5
PC
382 if (nreg->zero_extended)
383 jit_ldxi_ui(jit_reg, LIGHTREC_REG_STATE, offset);
384 else
385 jit_ldxi_i(jit_reg, LIGHTREC_REG_STATE, offset);
386
ba3814c1 387 nreg->prio = REG_IS_LOADED;
d16005f8
PC
388 }
389
390 /* Clear register r0 before use */
ba3814c1 391 if (reg == 0 && nreg->prio != REG_IS_ZERO) {
d16005f8
PC
392 jit_movi(jit_reg, 0);
393 nreg->extended = true;
98fa08a5 394 nreg->zero_extended = true;
ba3814c1 395 nreg->prio = REG_IS_ZERO;
d16005f8
PC
396 }
397
398 nreg->used = true;
399 nreg->output = false;
400 nreg->emulated_register = reg;
d16005f8 401
98fa08a5
PC
402 if ((flags & REG_EXT) && !nreg->extended &&
403 (!nreg->zero_extended || !(flags & REG_ZEXT))) {
d16005f8 404 nreg->extended = true;
98fa08a5 405 nreg->zero_extended = false;
d16005f8 406 jit_extr_i(jit_reg, jit_reg);
98fa08a5
PC
407 } else if (!(flags & REG_EXT) && (flags & REG_ZEXT) &&
408 !nreg->zero_extended) {
409 nreg->zero_extended = true;
410 nreg->extended = false;
411 jit_extr_ui(jit_reg, jit_reg);
d16005f8 412 }
d16005f8
PC
413
414 return jit_reg;
415}
416
684432ad
PC
417void lightrec_remap_reg(struct regcache *cache, jit_state_t *_jit,
418 u8 jit_reg, u16 reg_out, bool discard)
419{
420 struct native_register *nreg;
421
422 lightrec_discard_reg_if_loaded(cache, reg_out);
423
424 nreg = lightning_reg_to_lightrec(cache, jit_reg);
425 clean_reg(_jit, nreg, jit_reg, !discard);
426
427 nreg->output = true;
428 nreg->emulated_register = reg_out;
429 nreg->extend = nreg->extended;
430 nreg->zero_extend = nreg->zero_extended;
431}
432
9259d748 433static bool reg_pc_is_mapped(struct regcache *cache)
d16005f8 434{
9259d748
PC
435 struct native_register *nreg = lightning_reg_to_lightrec(cache, JIT_V0);
436
437 return nreg->prio == REG_IS_LOADED && nreg->emulated_register == REG_PC;
438}
439
440void lightrec_load_imm(struct regcache *cache,
441 jit_state_t *_jit, u8 jit_reg, u32 pc, u32 imm)
442{
443 s32 delta = imm - pc;
444
445 if (!reg_pc_is_mapped(cache) || !can_sign_extend(delta, 16))
446 jit_movi(jit_reg, imm);
447 else if (jit_reg != JIT_V0 || delta)
448 jit_addi(jit_reg, JIT_V0, delta);
449}
450
451void lightrec_load_next_pc_imm(struct regcache *cache,
452 jit_state_t *_jit, u32 pc, u32 imm)
453{
454 struct native_register *nreg = lightning_reg_to_lightrec(cache, JIT_V0);
0e720fb1
PC
455 u8 reg = JIT_V0;
456
457 if (lightrec_store_next_pc())
458 reg = lightrec_alloc_reg_temp(cache, _jit);
9259d748
PC
459
460 if (reg_pc_is_mapped(cache)) {
461 /* JIT_V0 contains next PC - so we can overwrite it */
0e720fb1 462 lightrec_load_imm(cache, _jit, reg, pc, imm);
9259d748
PC
463 } else {
464 /* JIT_V0 contains something else - invalidate it */
0e720fb1
PC
465 if (reg == JIT_V0)
466 lightrec_unload_reg(cache, _jit, JIT_V0);
9259d748 467
0e720fb1 468 jit_movi(reg, imm);
9259d748
PC
469 }
470
0e720fb1 471 if (lightrec_store_next_pc()) {
8afce295 472 jit_stxi_i(lightrec_offset(next_pc), LIGHTREC_REG_STATE, reg);
0e720fb1
PC
473 lightrec_free_reg(cache, reg);
474 } else {
475 nreg->prio = REG_IS_LOADED;
476 nreg->emulated_register = -1;
477 nreg->locked = true;
478 }
9259d748
PC
479}
480
481void lightrec_load_next_pc(struct regcache *cache, jit_state_t *_jit, u8 reg)
482{
483 struct native_register *nreg_v0, *nreg;
d16005f8 484 u16 offset;
9259d748
PC
485 u8 jit_reg;
486
0e720fb1
PC
487 if (lightrec_store_next_pc()) {
488 jit_reg = lightrec_alloc_reg_in(cache, _jit, reg, 0);
8afce295 489 offset = lightrec_offset(next_pc);
0e720fb1
PC
490 jit_stxi_i(offset, LIGHTREC_REG_STATE, jit_reg);
491 lightrec_free_reg(cache, jit_reg);
492
493 return;
494 }
495
9259d748
PC
496 /* Invalidate JIT_V0 if it is not mapped to 'reg' */
497 nreg_v0 = lightning_reg_to_lightrec(cache, JIT_V0);
498 if (nreg_v0->prio >= REG_IS_LOADED && nreg_v0->emulated_register != reg)
499 lightrec_unload_nreg(cache, _jit, nreg_v0, JIT_V0);
d16005f8
PC
500
501 nreg = find_mapped_reg(cache, reg, false);
9259d748
PC
502 if (!nreg) {
503 /* Not mapped - load the value from the register cache */
d16005f8 504
8afce295 505 offset = lightrec_offset(regs.gpr) + (reg << 2);
9259d748 506 jit_ldxi_ui(JIT_V0, LIGHTREC_REG_STATE, offset);
d16005f8 507
9259d748
PC
508 nreg_v0->prio = REG_IS_LOADED;
509 nreg_v0->emulated_register = reg;
d16005f8 510
9259d748
PC
511 } else if (nreg == nreg_v0) {
512 /* The target register 'reg' is mapped to JIT_V0 */
d16005f8 513
9259d748
PC
514 if (!nreg->zero_extended)
515 jit_extr_ui(JIT_V0, JIT_V0);
516
517 } else {
518 /* The target register 'reg' is mapped elsewhere. In that case,
519 * move the register's value to JIT_V0 and re-map it in the
520 * register cache. We can then safely discard the original
521 * mapped register (even if it was dirty). */
522
523 jit_reg = lightrec_reg_to_lightning(cache, nreg);
524 if (nreg->zero_extended)
525 jit_movr(JIT_V0, jit_reg);
526 else
527 jit_extr_ui(JIT_V0, jit_reg);
528
529 *nreg_v0 = *nreg;
530 lightrec_discard_nreg(nreg);
531 }
532
0e720fb1 533 if (lightrec_store_next_pc()) {
8afce295 534 jit_stxi_i(lightrec_offset(next_pc),
0e720fb1
PC
535 LIGHTREC_REG_STATE, JIT_V0);
536 } else {
537 lightrec_clean_reg(cache, _jit, JIT_V0);
9259d748 538
0e720fb1
PC
539 nreg_v0->zero_extended = true;
540 nreg_v0->locked = true;
541 }
d16005f8
PC
542}
543
544static void free_reg(struct native_register *nreg)
545{
546 /* Set output registers as dirty */
547 if (nreg->used && nreg->output && nreg->emulated_register > 0)
ba3814c1 548 nreg->prio = REG_IS_DIRTY;
98fa08a5 549 if (nreg->output) {
d16005f8 550 nreg->extended = nreg->extend;
98fa08a5
PC
551 nreg->zero_extended = nreg->zero_extend;
552 }
d16005f8
PC
553 nreg->used = false;
554}
555
556void lightrec_free_reg(struct regcache *cache, u8 jit_reg)
557{
98fa08a5
PC
558 if (!lightrec_reg_is_zero(jit_reg))
559 free_reg(lightning_reg_to_lightrec(cache, jit_reg));
d16005f8
PC
560}
561
562void lightrec_free_regs(struct regcache *cache)
563{
564 unsigned int i;
565
566 for (i = 0; i < ARRAY_SIZE(cache->lightrec_regs); i++)
567 free_reg(&cache->lightrec_regs[i]);
568}
569
570static void clean_reg(jit_state_t *_jit,
571 struct native_register *nreg, u8 jit_reg, bool clean)
572{
cb72ea13 573 /* If we get a dirty register, store back the old value */
ba3814c1 574 if (nreg->prio == REG_IS_DIRTY) {
8afce295 575 s16 offset = lightrec_offset(regs.gpr)
d16005f8
PC
576 + (nreg->emulated_register << 2);
577
578 jit_stxi_i(offset, LIGHTREC_REG_STATE, jit_reg);
ba3814c1
PC
579
580 if (clean) {
581 if (nreg->emulated_register == 0)
582 nreg->prio = REG_IS_ZERO;
583 else
584 nreg->prio = REG_IS_LOADED;
585 }
d16005f8
PC
586 }
587}
588
589static void clean_regs(struct regcache *cache, jit_state_t *_jit, bool clean)
590{
591 unsigned int i;
592
ba3814c1
PC
593 for (i = 0; i < NUM_REGS; i++) {
594 clean_reg(_jit, &cache->lightrec_regs[i],
595 JIT_V(FIRST_REG + i), clean);
596 }
d16005f8
PC
597 for (i = 0; i < NUM_TEMPS; i++) {
598 clean_reg(_jit, &cache->lightrec_regs[i + NUM_REGS],
ba3814c1 599 JIT_R(FIRST_TEMP + i), clean);
d16005f8
PC
600 }
601}
602
603void lightrec_storeback_regs(struct regcache *cache, jit_state_t *_jit)
604{
605 clean_regs(cache, _jit, false);
606}
607
608void lightrec_clean_regs(struct regcache *cache, jit_state_t *_jit)
609{
610 clean_regs(cache, _jit, true);
611}
612
ba3814c1
PC
613bool lightrec_has_dirty_regs(struct regcache *cache)
614{
615 unsigned int i;
616
617 for (i = 0; i < NUM_REGS + NUM_TEMPS; i++)
618 if (cache->lightrec_regs[i].prio == REG_IS_DIRTY)
619 return true;
620
621 return false;
622}
623
d16005f8
PC
624void lightrec_clean_reg(struct regcache *cache, jit_state_t *_jit, u8 jit_reg)
625{
98fa08a5
PC
626 struct native_register *reg;
627
628 if (!lightrec_reg_is_zero(jit_reg)) {
629 reg = lightning_reg_to_lightrec(cache, jit_reg);
630 clean_reg(_jit, reg, jit_reg, true);
631 }
d16005f8
PC
632}
633
cb72ea13
PC
634bool lightrec_reg_is_loaded(struct regcache *cache, u16 reg)
635{
636 return !!find_mapped_reg(cache, reg, false);
637}
638
d16005f8 639void lightrec_clean_reg_if_loaded(struct regcache *cache, jit_state_t *_jit,
9259d748 640 u16 reg, bool unload)
d16005f8
PC
641{
642 struct native_register *nreg;
643 u8 jit_reg;
644
645 nreg = find_mapped_reg(cache, reg, false);
646 if (nreg) {
647 jit_reg = lightrec_reg_to_lightning(cache, nreg);
648
649 if (unload)
650 lightrec_unload_nreg(cache, _jit, nreg, jit_reg);
651 else
652 clean_reg(_jit, nreg, jit_reg, true);
653 }
654}
655
9259d748 656void lightrec_discard_reg_if_loaded(struct regcache *cache, u16 reg)
03535202
PC
657{
658 struct native_register *nreg;
659
660 nreg = find_mapped_reg(cache, reg, false);
661 if (nreg)
662 lightrec_discard_nreg(nreg);
663}
664
d16005f8
PC
665struct native_register * lightrec_regcache_enter_branch(struct regcache *cache)
666{
667 struct native_register *backup;
668
669 backup = lightrec_malloc(cache->state, MEM_FOR_LIGHTREC,
670 sizeof(cache->lightrec_regs));
671 memcpy(backup, &cache->lightrec_regs, sizeof(cache->lightrec_regs));
672
673 return backup;
674}
675
676void lightrec_regcache_leave_branch(struct regcache *cache,
677 struct native_register *regs)
678{
679 memcpy(&cache->lightrec_regs, regs, sizeof(cache->lightrec_regs));
680 lightrec_free(cache->state, MEM_FOR_LIGHTREC,
681 sizeof(cache->lightrec_regs), regs);
682}
683
684void lightrec_regcache_reset(struct regcache *cache)
685{
686 memset(&cache->lightrec_regs, 0, sizeof(cache->lightrec_regs));
687}
688
0e720fb1 689void lightrec_preload_pc(struct regcache *cache, jit_state_t *_jit)
9259d748
PC
690{
691 struct native_register *nreg;
692
693 /* The block's PC is loaded in JIT_V0 at the start of the block */
694 nreg = lightning_reg_to_lightrec(cache, JIT_V0);
695 nreg->emulated_register = REG_PC;
696 nreg->prio = REG_IS_LOADED;
697 nreg->zero_extended = true;
0e720fb1
PC
698
699 jit_live(JIT_V0);
9259d748
PC
700}
701
d16005f8
PC
702struct regcache * lightrec_regcache_init(struct lightrec_state *state)
703{
704 struct regcache *cache;
705
706 cache = lightrec_calloc(state, MEM_FOR_LIGHTREC, sizeof(*cache));
707 if (!cache)
708 return NULL;
709
710 cache->state = state;
711
712 return cache;
713}
714
715void lightrec_free_regcache(struct regcache *cache)
716{
717 return lightrec_free(cache->state, MEM_FOR_LIGHTREC,
718 sizeof(*cache), cache);
719}
720
721void lightrec_regcache_mark_live(struct regcache *cache, jit_state_t *_jit)
722{
723 struct native_register *nreg;
724 unsigned int i;
725
726#ifdef _WIN32
727 /* FIXME: GNU Lightning on Windows seems to use our mapped registers as
728 * temporaries. Until the actual bug is found and fixed, unconditionally
729 * mark our registers as live here. */
730 for (i = 0; i < NUM_REGS; i++) {
731 nreg = &cache->lightrec_regs[i];
732
ba3814c1
PC
733 if (nreg->used || nreg->prio > REG_IS_TEMP)
734 jit_live(JIT_V(FIRST_REG + i));
d16005f8
PC
735 }
736#endif
737
738 for (i = 0; i < NUM_TEMPS; i++) {
739 nreg = &cache->lightrec_regs[NUM_REGS + i];
740
ba3814c1
PC
741 if (nreg->used || nreg->prio > REG_IS_TEMP)
742 jit_live(JIT_R(FIRST_TEMP + i));
d16005f8 743 }
ba3814c1
PC
744
745 jit_live(LIGHTREC_REG_STATE);
746 jit_live(LIGHTREC_REG_CYCLE);
d16005f8 747}