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