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