Merge pull request #836 from pcercuei/update-lightrec-20240611
[pcsx_rearmed.git] / deps / lightrec / regcache.c
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 /*
3  * Copyright (C) 2014-2021 Paul Cercueil <paul@crapouillou.net>
4  */
5
6 #include "debug.h"
7 #include "memmanager.h"
8 #include "lightning-wrapper.h"
9 #include "regcache.h"
10
11 #include <stdbool.h>
12 #include <stddef.h>
13
14 #define REG_PC (offsetof(struct lightrec_state, curr_pc) / sizeof(u32))
15
16 enum 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
26 struct native_register {
27         bool used, output, extend, extended,
28              zero_extend, zero_extended, locked;
29         s16 emulated_register;
30         intptr_t value;
31         enum reg_priority prio;
32 };
33
34 struct regcache {
35         struct lightrec_state *state;
36         struct native_register lightrec_regs[NUM_REGS + NUM_TEMPS];
37 };
38
39 static 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
52 /* Forward declaration(s) */
53 static void clean_reg(jit_state_t *_jit,
54                       struct native_register *nreg, u8 jit_reg, bool clean);
55
56 const char * lightrec_reg_name(u8 reg)
57 {
58         return mips_regs[reg];
59 }
60
61 static 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
70 static inline s8 lightrec_get_hardwired_reg(u16 reg)
71 {
72 #if defined(__mips__) || defined(__alpha__) || defined(__riscv)
73         if (reg == 0)
74                 return _ZERO;
75 #endif
76         return -1;
77 }
78
79 static 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
86 static 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);
90
91         if (offset < NUM_REGS)
92                 return JIT_V(FIRST_REG + offset);
93         else
94                 return JIT_R(FIRST_TEMP + offset - NUM_REGS);
95 }
96
97 static 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)
103                         return &cache->lightrec_regs[reg - JIT_V(FIRST_REG)];
104                 else
105                         return &cache->lightrec_regs[JIT_V(FIRST_REG) - reg];
106         } else {
107                 if (JIT_R1 > JIT_R0)
108                         return &cache->lightrec_regs[NUM_REGS + reg - JIT_R(FIRST_TEMP)];
109                 else
110                         return &cache->lightrec_regs[NUM_REGS + JIT_R(FIRST_TEMP) - reg];
111         }
112 }
113
114 u8 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
131 void 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
142 static struct native_register * alloc_temp(struct regcache *cache)
143 {
144         struct native_register *elm, *nreg = NULL;
145         enum reg_priority best = REG_NB_PRIORITIES;
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--) {
153                 elm = &cache->lightrec_regs[i - 1];
154
155                 if (!elm->used && !elm->locked && elm->prio < best) {
156                         nreg = elm;
157                         best = elm->prio;
158
159                         if (best == REG_IS_TEMP)
160                                 break;
161                 }
162         }
163
164         return nreg;
165 }
166
167 static struct native_register * find_mapped_reg(struct regcache *cache,
168                                                 u16 reg, bool out)
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];
174                 if ((nreg->prio >= REG_IS_ZERO) &&
175                     nreg->emulated_register == reg &&
176                     (!out || !nreg->locked))
177                         return nreg;
178         }
179
180         return NULL;
181 }
182
183 static struct native_register * alloc_in_out(struct regcache *cache,
184                                              u16 reg, bool out)
185 {
186         struct native_register *elm, *nreg = NULL;
187         enum reg_priority best = REG_NB_PRIORITIES;
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
195         nreg = NULL;
196
197         for (i = 0; i < ARRAY_SIZE(cache->lightrec_regs); i++) {
198                 elm = &cache->lightrec_regs[i];
199
200                 if (!elm->used && !elm->locked && elm->prio < best) {
201                         nreg = elm;
202                         best = elm->prio;
203
204                         if (best == REG_IS_TEMP)
205                                 break;
206                 }
207         }
208
209         return nreg;
210 }
211
212 static void lightrec_discard_nreg(struct native_register *nreg)
213 {
214         nreg->extended = false;
215         nreg->zero_extended = false;
216         nreg->output = false;
217         nreg->used = false;
218         nreg->locked = false;
219         nreg->emulated_register = -1;
220         nreg->prio = 0;
221 }
222
223 static void lightrec_unload_nreg(struct regcache *cache, jit_state_t *_jit,
224                 struct native_register *nreg, u8 jit_reg)
225 {
226         clean_reg(_jit, nreg, jit_reg, false);
227         lightrec_discard_nreg(nreg);
228 }
229
230 void lightrec_unload_reg(struct regcache *cache, jit_state_t *_jit, u8 jit_reg)
231 {
232         if (lightrec_reg_is_zero(jit_reg))
233                 return;
234
235         lightrec_unload_nreg(cache, _jit,
236                         lightning_reg_to_lightrec(cache, jit_reg), jit_reg);
237 }
238
239 u8 lightrec_alloc_reg(struct regcache *cache, jit_state_t *_jit, u8 jit_reg)
240 {
241         struct native_register *reg;
242
243         if (lightrec_reg_is_zero(jit_reg))
244                 return jit_reg;
245
246         reg = lightning_reg_to_lightrec(cache, jit_reg);
247         lightrec_unload_nreg(cache, _jit, reg, jit_reg);
248
249         reg->used = true;
250         reg->prio = REG_IS_LOADED;
251         return jit_reg;
252 }
253
254 u8 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
267         nreg->prio = REG_IS_TEMP;
268         nreg->used = true;
269         return jit_reg;
270 }
271
272 s8 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
289 void 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
299 u8 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
314 u8 lightrec_alloc_reg_out(struct regcache *cache, jit_state_t *_jit,
315                           u16 reg, u8 flags)
316 {
317         struct native_register *nreg;
318         u8 jit_reg;
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);
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
339         nreg->used = true;
340         nreg->output = true;
341         nreg->emulated_register = reg;
342         nreg->extend = flags & REG_EXT;
343         nreg->zero_extend = flags & REG_ZEXT;
344         nreg->prio = reg ? REG_IS_LOADED : REG_IS_ZERO;
345         return jit_reg;
346 }
347
348 u8 lightrec_alloc_reg_in(struct regcache *cache, jit_state_t *_jit,
349                          u16 reg, u8 flags)
350 {
351         struct native_register *nreg;
352         u8 jit_reg;
353         bool reg_changed;
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);
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
375         if (nreg->prio < REG_IS_LOADED && reg != 0) {
376                 s16 offset = lightrec_offset(regs.gpr) + (reg << 2);
377
378                 nreg->zero_extended = flags & REG_ZEXT;
379                 nreg->extended = !nreg->zero_extended;
380
381                 /* Load previous value from register cache */
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
387                 nreg->prio = REG_IS_LOADED;
388         }
389
390         /* Clear register r0 before use */
391         if (reg == 0 && nreg->prio != REG_IS_ZERO) {
392                 jit_movi(jit_reg, 0);
393                 nreg->extended = true;
394                 nreg->zero_extended = true;
395                 nreg->prio = REG_IS_ZERO;
396         }
397
398         nreg->used = true;
399         nreg->output = false;
400         nreg->emulated_register = reg;
401
402         if ((flags & REG_EXT) && !nreg->extended &&
403             (!nreg->zero_extended || !(flags & REG_ZEXT))) {
404                 nreg->extended = true;
405                 nreg->zero_extended = false;
406                 jit_extr_i(jit_reg, jit_reg);
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);
412         }
413
414         return jit_reg;
415 }
416
417 void 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
433 static bool reg_pc_is_mapped(struct regcache *cache)
434 {
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
440 void 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
451 void 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);
455         u8 reg = JIT_V0;
456
457         if (lightrec_store_next_pc())
458                 reg = lightrec_alloc_reg_temp(cache, _jit);
459
460         if (reg_pc_is_mapped(cache)) {
461                 /* JIT_V0 contains next PC - so we can overwrite it */
462                 lightrec_load_imm(cache, _jit, reg, pc, imm);
463         } else {
464                 /* JIT_V0 contains something else - invalidate it */
465                 if (reg == JIT_V0)
466                       lightrec_unload_reg(cache, _jit, JIT_V0);
467
468                 jit_movi(reg, imm);
469         }
470
471         if (lightrec_store_next_pc()) {
472                 jit_stxi_i(lightrec_offset(next_pc), LIGHTREC_REG_STATE, reg);
473                 lightrec_free_reg(cache, reg);
474         } else {
475                 nreg->prio = REG_IS_LOADED;
476                 nreg->emulated_register = -1;
477                 nreg->locked = true;
478         }
479 }
480
481 void lightrec_load_next_pc(struct regcache *cache, jit_state_t *_jit, u8 reg)
482 {
483         struct native_register *nreg_v0, *nreg;
484         u16 offset;
485         u8 jit_reg;
486
487         if (lightrec_store_next_pc()) {
488                 jit_reg = lightrec_alloc_reg_in(cache, _jit, reg, 0);
489                 offset = lightrec_offset(next_pc);
490                 jit_stxi_i(offset, LIGHTREC_REG_STATE, jit_reg);
491                 lightrec_free_reg(cache, jit_reg);
492
493                 return;
494         }
495
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);
500
501         nreg = find_mapped_reg(cache, reg, false);
502         if (!nreg) {
503                 /* Not mapped - load the value from the register cache */
504
505                 offset = lightrec_offset(regs.gpr) + (reg << 2);
506                 jit_ldxi_ui(JIT_V0, LIGHTREC_REG_STATE, offset);
507
508                 nreg_v0->prio = REG_IS_LOADED;
509                 nreg_v0->emulated_register = reg;
510
511         } else if (nreg == nreg_v0) {
512                 /* The target register 'reg' is mapped to JIT_V0 */
513
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
533         if (lightrec_store_next_pc()) {
534                 jit_stxi_i(lightrec_offset(next_pc),
535                            LIGHTREC_REG_STATE, JIT_V0);
536         } else {
537                 lightrec_clean_reg(cache, _jit, JIT_V0);
538
539                 nreg_v0->zero_extended = true;
540                 nreg_v0->locked = true;
541         }
542 }
543
544 static void free_reg(struct native_register *nreg)
545 {
546         /* Set output registers as dirty */
547         if (nreg->used && nreg->output && nreg->emulated_register > 0)
548                 nreg->prio = REG_IS_DIRTY;
549         if (nreg->output) {
550                 nreg->extended = nreg->extend;
551                 nreg->zero_extended = nreg->zero_extend;
552         }
553         nreg->used = false;
554 }
555
556 void lightrec_free_reg(struct regcache *cache, u8 jit_reg)
557 {
558         if (!lightrec_reg_is_zero(jit_reg))
559                 free_reg(lightning_reg_to_lightrec(cache, jit_reg));
560 }
561
562 void 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
570 static void clean_reg(jit_state_t *_jit,
571                 struct native_register *nreg, u8 jit_reg, bool clean)
572 {
573         /* If we get a dirty register, store back the old value */
574         if (nreg->prio == REG_IS_DIRTY) {
575                 s16 offset = lightrec_offset(regs.gpr)
576                         + (nreg->emulated_register << 2);
577
578                 jit_stxi_i(offset, LIGHTREC_REG_STATE, jit_reg);
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                 }
586         }
587 }
588
589 static void clean_regs(struct regcache *cache, jit_state_t *_jit, bool clean)
590 {
591         unsigned int i;
592
593         for (i = 0; i < NUM_REGS; i++) {
594                 clean_reg(_jit, &cache->lightrec_regs[i],
595                           JIT_V(FIRST_REG + i), clean);
596         }
597         for (i = 0; i < NUM_TEMPS; i++) {
598                 clean_reg(_jit, &cache->lightrec_regs[i + NUM_REGS],
599                                 JIT_R(FIRST_TEMP + i), clean);
600         }
601 }
602
603 void lightrec_storeback_regs(struct regcache *cache, jit_state_t *_jit)
604 {
605         clean_regs(cache, _jit, false);
606 }
607
608 void lightrec_clean_regs(struct regcache *cache, jit_state_t *_jit)
609 {
610         clean_regs(cache, _jit, true);
611 }
612
613 bool 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
624 void lightrec_clean_reg(struct regcache *cache, jit_state_t *_jit, u8 jit_reg)
625 {
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         }
632 }
633
634 bool lightrec_reg_is_loaded(struct regcache *cache, u16 reg)
635 {
636         return !!find_mapped_reg(cache, reg, false);
637 }
638
639 void lightrec_clean_reg_if_loaded(struct regcache *cache, jit_state_t *_jit,
640                                   u16 reg, bool unload)
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
656 void lightrec_discard_reg_if_loaded(struct regcache *cache, u16 reg)
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
665 struct 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
676 void 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
684 void lightrec_regcache_reset(struct regcache *cache)
685 {
686         memset(&cache->lightrec_regs, 0, sizeof(cache->lightrec_regs));
687 }
688
689 void lightrec_preload_pc(struct regcache *cache, jit_state_t *_jit)
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;
698
699         jit_live(JIT_V0);
700 }
701
702 struct 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
715 void lightrec_free_regcache(struct regcache *cache)
716 {
717         return lightrec_free(cache->state, MEM_FOR_LIGHTREC,
718                              sizeof(*cache), cache);
719 }
720
721 void 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
733                 if (nreg->used || nreg->prio > REG_IS_TEMP)
734                         jit_live(JIT_V(FIRST_REG + i));
735         }
736 #endif
737
738         for (i = 0; i < NUM_TEMPS; i++) {
739                 nreg = &cache->lightrec_regs[NUM_REGS + i];
740
741                 if (nreg->used || nreg->prio > REG_IS_TEMP)
742                         jit_live(JIT_R(FIRST_TEMP + i));
743         }
744
745         jit_live(LIGHTREC_REG_STATE);
746         jit_live(LIGHTREC_REG_CYCLE);
747 }