libretro: improve retro_memory_map
[pcsx_rearmed.git] / deps / lightrec / constprop.c
CommitLineData
9259d748
PC
1// SPDX-License-Identifier: LGPL-2.1-or-later
2/*
3 * Copyright (C) 2022 Paul Cercueil <paul@crapouillou.net>
4 */
5
6#include "constprop.h"
7#include "disassembler.h"
8#include "lightrec-private.h"
9
10#include <stdbool.h>
11#include <string.h>
12
13static u32 get_min_value(const struct constprop_data *d)
14{
15 /* Min value: all sign bits to 1, all unknown bits but MSB to 0 */
16 return (d->value & d->known) | d->sign | (~d->known & BIT(31));
17}
18
19static u32 get_max_value(const struct constprop_data *d)
20{
21 /* Max value: all sign bits to 0, all unknown bits to 1 */
22 return ((d->value & d->known) | ~d->known) & ~d->sign;
23}
24
25static u32 lightrec_same_sign(const struct constprop_data *d1,
26 const struct constprop_data *d2)
27{
28 u32 min1, min2, max1, max2, a, b, c, d;
29
30 min1 = get_min_value(d1);
31 max1 = get_max_value(d1);
32 min2 = get_min_value(d2);
33 max2 = get_max_value(d2);
34
35 a = min1 + min2;
36 b = min1 + max2;
37 c = max1 + min2;
38 d = max1 + max2;
39
40 return ((a & b & c & d) | (~a & ~b & ~c & ~d)) & BIT(31);
41}
42
43static u32 lightrec_get_sign_mask(const struct constprop_data *d)
44{
45 u32 imm;
46
47 if (d->sign)
48 return d->sign;
49
50 imm = (d->value & BIT(31)) ? d->value : ~d->value;
51 imm = ~(imm & d->known);
52 if (imm)
53 imm = 32 - clz32(imm);
54
55 return imm < 32 ? GENMASK(31, imm) : 0;
56}
57
58static void lightrec_propagate_addi(u32 rs, u32 rd,
59 const struct constprop_data *d,
60 struct constprop_data *v)
61{
3107c849 62 u32 end, bit, sum, min, max, mask, imm, value;
9259d748
PC
63 struct constprop_data result = {
64 .value = v[rd].value,
65 .known = v[rd].known,
66 .sign = v[rd].sign,
67 };
68 bool carry = false;
69
70 /* clear unknown bits to ease processing */
71 v[rs].value &= v[rs].known;
72 value = d->value & d->known;
73
74 mask = ~(lightrec_get_sign_mask(d) & lightrec_get_sign_mask(&v[rs]));
75 end = mask ? 32 - clz32(mask) : 0;
76
77 for (bit = 0; bit < 32; bit++) {
78 if (v[rs].known & d->known & BIT(bit)) {
79 /* the bits are known - compute the resulting bit and
80 * the carry */
81 sum = ((u32)carry << bit) + (v[rs].value & BIT(bit))
82 + (value & BIT(bit));
83
84 if (sum & BIT(bit))
85 result.value |= BIT(bit);
86 else
87 result.value &= ~BIT(bit);
88
89 result.known |= BIT(bit);
90 result.sign &= ~BIT(bit);
91 carry = sum & BIT(bit + 1);
92 continue;
93 }
94
95 if (bit >= end) {
96 /* We're past the last significant bits of the values
97 * (extra sign bits excepted).
98 * The destination register will be sign-extended
99 * starting from here (if no carry) or from the next
100 * bit (if carry).
101 * If the source registers are not sign-extended and we
102 * have no carry, the algorithm is done here. */
103
104 if ((v[rs].sign | d->sign) & BIT(bit)) {
105 mask = GENMASK(31, bit);
106
107 if (lightrec_same_sign(&v[rs], d)) {
108 /* Theorical minimum and maximum values
109 * have the same sign; therefore the
110 * sign bits are known. */
111 min = get_min_value(&v[rs])
112 + get_min_value(d);
3107c849
PC
113 max = get_max_value(&v[rs])
114 + get_max_value(d);
115
116 /* The sum may have less sign bits */
117 if ((s32)min < 0)
118 mask &= min & max;
119 else
120 mask &= ~(min | mask);
121
9259d748
PC
122 result.value = (min & mask)
123 | (result.value & ~mask);
124 result.known |= mask << carry;
125 result.sign = 0;
126 } else {
127 /* min/max have different signs. */
128 result.sign = mask << 1;
129 result.known &= ~mask;
130 }
131 break;
132 } else if (!carry) {
133 /* Past end bit, no carry; we're done here. */
134 break;
135 }
136 }
137
138 result.known &= ~BIT(bit);
139 result.sign &= ~BIT(bit);
140
141 /* Found an unknown bit in one of the registers.
142 * If the carry and the bit in the other register are both zero,
143 * we can continue the algorithm. */
144 if (!carry && (((d->known & ~value)
145 | (v[rs].known & ~v[rs].value)) & BIT(bit)))
146 continue;
147
148 /* We have an unknown bit in one of the source registers, and we
149 * may generate a carry: there's nothing to do. Everything from
150 * this bit till the next known 0 bit or sign bit will be marked
151 * as unknown. The algorithm can then restart at the following
152 * bit. */
153
154 imm = (v[rs].known & d->known & ~v[rs].value & ~value)
155 | v[rs].sign | d->sign;
156
157 imm &= GENMASK(31, bit);
158 imm = imm ? ctz32(imm) : 31;
159 mask = GENMASK(imm, bit);
160 result.known &= ~mask;
161 result.sign &= ~mask;
162
163 bit = imm;
164 carry = false;
165 }
166
167 v[rd] = result;
168}
169
170static void lightrec_propagate_sub(u32 rs, u32 rt, u32 rd,
171 struct constprop_data *v)
172{
173 struct constprop_data d = {
174 .value = ~v[rt].value,
175 .known = v[rt].known,
176 .sign = v[rt].sign,
177 };
178 u32 imm, mask, bit;
179
180 /* Negate the known Rt value, then propagate as a regular ADD. */
181
182 for (bit = 0; bit < 32; bit++) {
183 if (!(d.known & BIT(bit))) {
184 /* Unknown bit - mark bits unknown up to the next known 0 */
185
186 imm = (d.known & ~d.value) | d.sign;
187 imm &= GENMASK(31, bit);
188 imm = imm ? ctz32(imm) : 31;
189 mask = GENMASK(imm, bit);
190 d.known &= ~mask;
191 d.sign &= ~mask;
192 break;
193 }
194
195 if (!(d.value & BIT(bit))) {
196 /* Bit is 0: we can set our carry, and the algorithm is done. */
197 d.value |= BIT(bit);
198 break;
199 }
200
201 /* Bit is 1 - set to 0 and continue algorithm */
202 d.value &= ~BIT(bit);
203 }
204
205 lightrec_propagate_addi(rs, rd, &d, v);
206}
207
208static void lightrec_propagate_slt(u32 rs, u32 rd, bool is_signed,
209 const struct constprop_data *d,
210 struct constprop_data *v)
211{
212 unsigned int bit;
213
214 if (is_signed && (v[rs].known & d->known
215 & (v[rs].value ^ d->value) & BIT(31))) {
216 /* If doing a signed comparison and the two bits 31 are known
217 * to be opposite, we can deduce the value. */
218 v[rd].value = v[rs].value >> 31;
219 v[rd].known = 0xffffffff;
220 v[rd].sign = 0;
221 return;
222 }
223
224 for (bit = 32; bit > 0; bit--) {
225 if (!(v[rs].known & d->known & BIT(bit - 1))) {
226 /* One bit is unknown and we cannot figure out which
227 * value is smaller. We still know that the upper 31
228 * bits are zero. */
229 v[rd].value = 0;
230 v[rd].known = 0xfffffffe;
231 v[rd].sign = 0;
232 break;
233 }
234
235 /* The two bits are equal - continue to the next bit. */
236 if (~(v[rs].value ^ d->value) & BIT(bit - 1))
237 continue;
238
239 /* The two bits aren't equal; we can therefore deduce which
240 * value is smaller. */
241 v[rd].value = !(v[rs].value & BIT(bit - 1));
242 v[rd].known = 0xffffffff;
243 v[rd].sign = 0;
244 break;
245 }
246
247 if (bit == 0) {
248 /* rs == rt and all bits are known */
249 v[rd].value = 0;
250 v[rd].known = 0xffffffff;
251 v[rd].sign = 0;
252 }
253}
254
cb72ea13 255void lightrec_consts_propagate(const struct block *block,
9259d748
PC
256 unsigned int idx,
257 struct constprop_data *v)
258{
cb72ea13 259 const struct opcode *list = block->opcode_list;
9259d748 260 union code c;
cb72ea13 261 u32 imm, flags;
9259d748
PC
262
263 if (idx == 0)
264 return;
265
266 /* Register $zero is always, well, zero */
267 v[0].value = 0;
268 v[0].sign = 0;
269 v[0].known = 0xffffffff;
270
271 if (op_flag_sync(list[idx].flags)) {
272 memset(&v[1], 0, sizeof(*v) * 31);
273 return;
274 }
275
cb72ea13
PC
276 flags = list[idx - 1].flags;
277
278 if (idx > 1 && !op_flag_sync(flags)) {
279 if (op_flag_no_ds(flags))
280 c = list[idx - 1].c;
281 else
282 c = list[idx - 2].c;
9259d748
PC
283
284 switch (c.i.op) {
285 case OP_BNE:
286 /* After a BNE $zero + delay slot, we know that the
287 * branch wasn't taken, and therefore the other register
288 * is zero. */
289 if (c.i.rs == 0) {
290 v[c.i.rt].value = 0;
291 v[c.i.rt].sign = 0;
292 v[c.i.rt].known = 0xffffffff;
293 } else if (c.i.rt == 0) {
294 v[c.i.rs].value = 0;
295 v[c.i.rs].sign = 0;
296 v[c.i.rs].known = 0xffffffff;
297 }
298 break;
299 case OP_BLEZ:
300 v[c.i.rs].value &= ~BIT(31);
301 v[c.i.rs].known |= BIT(31);
302 fallthrough;
303 case OP_BEQ:
304 /* TODO: handle non-zero? */
305 break;
306 case OP_REGIMM:
307 switch (c.r.rt) {
308 case OP_REGIMM_BLTZ:
309 case OP_REGIMM_BLTZAL:
310 v[c.i.rs].value &= ~BIT(31);
311 v[c.i.rs].known |= BIT(31);
312 break;
313 case OP_REGIMM_BGEZ:
314 case OP_REGIMM_BGEZAL:
315 v[c.i.rs].value |= BIT(31);
316 v[c.i.rs].known |= BIT(31);
317 /* TODO: handle non-zero? */
318 break;
319 }
320 break;
321 default:
322 break;
323 }
324 }
325
326 c = list[idx - 1].c;
327
328 switch (c.i.op) {
329 case OP_SPECIAL:
330 switch (c.r.op) {
331 case OP_SPECIAL_SLL:
332 v[c.r.rd].value = v[c.r.rt].value << c.r.imm;
333 v[c.r.rd].known = (v[c.r.rt].known << c.r.imm)
334 | (BIT(c.r.imm) - 1);
335 v[c.r.rd].sign = v[c.r.rt].sign << c.r.imm;
336 break;
337
338 case OP_SPECIAL_SRL:
339 v[c.r.rd].value = v[c.r.rt].value >> c.r.imm;
340 v[c.r.rd].known = (v[c.r.rt].known >> c.r.imm)
684432ad 341 | ((BIT(c.r.imm) - 1) << (32 - c.r.imm));
9259d748
PC
342 v[c.r.rd].sign = c.r.imm ? 0 : v[c.r.rt].sign;
343 break;
344
345 case OP_SPECIAL_SRA:
346 v[c.r.rd].value = (s32)v[c.r.rt].value >> c.r.imm;
878e6cda
PC
347 v[c.r.rd].sign = (s32)(v[c.r.rt].sign
348 | (~v[c.r.rt].known & 0x80000000)) >> c.r.imm;
9259d748 349 v[c.r.rd].known = (s32)v[c.r.rt].known >> c.r.imm;
9259d748
PC
350 break;
351
352 case OP_SPECIAL_SLLV:
353 if ((v[c.r.rs].known & 0x1f) == 0x1f) {
354 imm = v[c.r.rs].value & 0x1f;
355 v[c.r.rd].value = v[c.r.rt].value << imm;
356 v[c.r.rd].known = (v[c.r.rt].known << imm)
357 | (BIT(imm) - 1);
358 v[c.r.rd].sign = v[c.r.rt].sign << imm;
359 } else {
360 v[c.r.rd].known = 0;
361 v[c.r.rd].sign = 0;
362 }
363 break;
364
365 case OP_SPECIAL_SRLV:
366 if ((v[c.r.rs].known & 0x1f) == 0x1f) {
367 imm = v[c.r.rs].value & 0x1f;
368 v[c.r.rd].value = v[c.r.rt].value >> imm;
369 v[c.r.rd].known = (v[c.r.rt].known >> imm)
684432ad 370 | ((BIT(imm) - 1) << (32 - imm));
9259d748
PC
371 if (imm)
372 v[c.r.rd].sign = 0;
373 } else {
374 v[c.r.rd].known = 0;
375 v[c.r.rd].sign = 0;
376 }
377 break;
378
379 case OP_SPECIAL_SRAV:
380 if ((v[c.r.rs].known & 0x1f) == 0x1f) {
381 imm = v[c.r.rs].value & 0x1f;
382 v[c.r.rd].value = (s32)v[c.r.rt].value >> imm;
878e6cda
PC
383 v[c.r.rd].sign = (s32)(v[c.r.rt].sign
384 | (~v[c.r.rt].known & 0x80000000)) >> imm;
9259d748 385 v[c.r.rd].known = (s32)v[c.r.rt].known >> imm;
9259d748
PC
386 } else {
387 v[c.r.rd].known = 0;
388 v[c.r.rd].sign = 0;
389 }
390 break;
391
392 case OP_SPECIAL_ADD:
393 case OP_SPECIAL_ADDU:
394 if (is_known_zero(v, c.r.rs))
395 v[c.r.rd] = v[c.r.rt];
396 else if (is_known_zero(v, c.r.rt))
397 v[c.r.rd] = v[c.r.rs];
398 else
399 lightrec_propagate_addi(c.r.rs, c.r.rd, &v[c.r.rt], v);
400 break;
401
402 case OP_SPECIAL_SUB:
403 case OP_SPECIAL_SUBU:
404 if (c.r.rs == c.r.rt) {
405 v[c.r.rd].value = 0;
406 v[c.r.rd].known = 0xffffffff;
407 v[c.r.rd].sign = 0;
408 } else {
409 lightrec_propagate_sub(c.r.rs, c.r.rt, c.r.rd, v);
410 }
411 break;
412
413 case OP_SPECIAL_AND:
414 v[c.r.rd].known = (v[c.r.rt].known & v[c.r.rs].known)
415 | (~v[c.r.rt].value & v[c.r.rt].known)
416 | (~v[c.r.rs].value & v[c.r.rs].known);
417 v[c.r.rd].value = v[c.r.rt].value & v[c.r.rs].value & v[c.r.rd].known;
418 v[c.r.rd].sign = v[c.r.rt].sign & v[c.r.rs].sign;
419 break;
420
421 case OP_SPECIAL_OR:
422 v[c.r.rd].known = (v[c.r.rt].known & v[c.r.rs].known)
423 | (v[c.r.rt].value & v[c.r.rt].known)
424 | (v[c.r.rs].value & v[c.r.rs].known);
425 v[c.r.rd].value = (v[c.r.rt].value | v[c.r.rs].value) & v[c.r.rd].known;
426 v[c.r.rd].sign = v[c.r.rt].sign & v[c.r.rs].sign;
427 break;
428
429 case OP_SPECIAL_XOR:
430 v[c.r.rd].value = v[c.r.rt].value ^ v[c.r.rs].value;
431 v[c.r.rd].known = v[c.r.rt].known & v[c.r.rs].known;
432 v[c.r.rd].sign = v[c.r.rt].sign & v[c.r.rs].sign;
433 break;
434
435 case OP_SPECIAL_NOR:
436 v[c.r.rd].known = (v[c.r.rt].known & v[c.r.rs].known)
437 | (v[c.r.rt].value & v[c.r.rt].known)
438 | (v[c.r.rs].value & v[c.r.rs].known);
439 v[c.r.rd].value = ~(v[c.r.rt].value | v[c.r.rs].value) & v[c.r.rd].known;
440 v[c.r.rd].sign = v[c.r.rt].sign & v[c.r.rs].sign;
441 break;
442
443 case OP_SPECIAL_SLT:
444 case OP_SPECIAL_SLTU:
445 lightrec_propagate_slt(c.r.rs, c.r.rd,
446 c.r.op == OP_SPECIAL_SLT,
447 &v[c.r.rt], v);
448 break;
449
450 case OP_SPECIAL_MULT:
451 case OP_SPECIAL_MULTU:
452 case OP_SPECIAL_DIV:
453 case OP_SPECIAL_DIVU:
454 if (OPT_FLAG_MULT_DIV && c.r.rd) {
455 v[c.r.rd].known = 0;
456 v[c.r.rd].sign = 0;
457 }
458 if (OPT_FLAG_MULT_DIV && c.r.imm) {
459 v[c.r.imm].known = 0;
460 v[c.r.imm].sign = 0;
461 }
462 break;
463
464 case OP_SPECIAL_MFLO:
465 case OP_SPECIAL_MFHI:
466 v[c.r.rd].known = 0;
467 v[c.r.rd].sign = 0;
468 break;
cb72ea13
PC
469
470 case OP_SPECIAL_JALR:
471 v[c.r.rd].known = 0xffffffff;
472 v[c.r.rd].sign = 0;
684432ad 473 v[c.r.rd].value = block->pc + ((idx + 2) << 2);
cb72ea13
PC
474 break;
475
9259d748
PC
476 default:
477 break;
478 }
479 break;
480
481 case OP_META_MULT2:
482 case OP_META_MULTU2:
483 if (OPT_FLAG_MULT_DIV && c.r.rd) {
484 if (c.r.op < 32) {
485 v[c.r.rd].value = v[c.r.rs].value << c.r.op;
486 v[c.r.rd].known = (v[c.r.rs].known << c.r.op)
487 | (BIT(c.r.op) - 1);
488 v[c.r.rd].sign = v[c.r.rs].sign << c.r.op;
489 } else {
490 v[c.r.rd].value = 0;
491 v[c.r.rd].known = 0xffffffff;
492 v[c.r.rd].sign = 0;
493 }
494 }
495
496 if (OPT_FLAG_MULT_DIV && c.r.imm) {
497 if (c.r.op >= 32) {
684432ad
PC
498 v[c.r.imm].value = v[c.r.rs].value << (c.r.op - 32);
499 v[c.r.imm].known = (v[c.r.rs].known << (c.r.op - 32))
9259d748 500 | (BIT(c.r.op - 32) - 1);
684432ad 501 v[c.r.imm].sign = v[c.r.rs].sign << (c.r.op - 32);
9259d748 502 } else if (c.i.op == OP_META_MULT2) {
684432ad
PC
503 v[c.r.imm].value = (s32)v[c.r.rs].value >> (32 - c.r.op);
504 v[c.r.imm].known = (s32)v[c.r.rs].known >> (32 - c.r.op);
505 v[c.r.imm].sign = (s32)v[c.r.rs].sign >> (32 - c.r.op);
9259d748 506 } else {
684432ad
PC
507 v[c.r.imm].value = v[c.r.rs].value >> (32 - c.r.op);
508 v[c.r.imm].known = v[c.r.rs].known >> (32 - c.r.op);
509 v[c.r.imm].sign = v[c.r.rs].sign >> (32 - c.r.op);
9259d748
PC
510 }
511 }
512 break;
513
514 case OP_REGIMM:
515 break;
516
517 case OP_ADDI:
518 case OP_ADDIU:
519 if (c.i.imm) {
520 struct constprop_data d = {
521 .value = (s32)(s16)c.i.imm,
522 .known = 0xffffffff,
523 .sign = 0,
524 };
525
526 lightrec_propagate_addi(c.i.rs, c.i.rt, &d, v);
527 } else {
528 /* immediate is zero - that's just a register copy. */
529 v[c.i.rt] = v[c.i.rs];
530 }
531 break;
532
533 case OP_SLTI:
534 case OP_SLTIU:
535 {
536 struct constprop_data d = {
537 .value = (s32)(s16)c.i.imm,
538 .known = 0xffffffff,
539 .sign = 0,
540 };
541
542 lightrec_propagate_slt(c.i.rs, c.i.rt,
543 c.i.op == OP_SLTI, &d, v);
544 }
545 break;
546
547 case OP_ANDI:
548 v[c.i.rt].value = v[c.i.rs].value & c.i.imm;
549 v[c.i.rt].known = v[c.i.rs].known | ~c.i.imm;
550 v[c.i.rt].sign = 0;
551 break;
552
553 case OP_ORI:
554 v[c.i.rt].value = v[c.i.rs].value | c.i.imm;
555 v[c.i.rt].known = v[c.i.rs].known | c.i.imm;
556 v[c.i.rt].sign = (v[c.i.rs].sign & 0xffff) ? 0xffff0000 : v[c.i.rs].sign;
557 break;
558
559 case OP_XORI:
560 v[c.i.rt].value = v[c.i.rs].value ^ c.i.imm;
561 v[c.i.rt].known = v[c.i.rs].known;
562 v[c.i.rt].sign = (v[c.i.rs].sign & 0xffff) ? 0xffff0000 : v[c.i.rs].sign;
563 break;
564
565 case OP_LUI:
566 v[c.i.rt].value = c.i.imm << 16;
567 v[c.i.rt].known = 0xffffffff;
568 v[c.i.rt].sign = 0;
569 break;
570
571 case OP_CP0:
572 switch (c.r.rs) {
573 case OP_CP0_MFC0:
574 case OP_CP0_CFC0:
575 v[c.r.rt].known = 0;
576 v[c.r.rt].sign = 0;
577 break;
578 default:
579 break;
580 }
581 break;
582
583 case OP_CP2:
584 if (c.r.op == OP_CP2_BASIC) {
585 switch (c.r.rs) {
586 case OP_CP2_BASIC_MFC2:
587 switch (c.r.rd) {
588 case 1:
589 case 3:
590 case 5:
591 case 8:
592 case 9:
593 case 10:
594 case 11:
595 /* Signed 16-bit */
596 v[c.r.rt].known = 0;
597 v[c.r.rt].sign = 0xffff8000;
598 break;
599 case 7:
600 case 16:
601 case 17:
602 case 18:
603 case 19:
604 /* Unsigned 16-bit */
605 v[c.r.rt].value = 0;
606 v[c.r.rt].known = 0xffff0000;
607 v[c.r.rt].sign = 0;
608 break;
609 default:
610 /* 32-bit */
611 v[c.r.rt].known = 0;
612 v[c.r.rt].sign = 0;
613 break;
614 }
615 break;
616 case OP_CP2_BASIC_CFC2:
617 switch (c.r.rd) {
618 case 4:
619 case 12:
620 case 20:
621 case 26:
622 case 27:
623 case 29:
624 case 30:
625 /* Signed 16-bit */
626 v[c.r.rt].known = 0;
627 v[c.r.rt].sign = 0xffff8000;
628 break;
629 default:
630 /* 32-bit */
631 v[c.r.rt].known = 0;
632 v[c.r.rt].sign = 0;
633 break;
634 }
635 break;
636 }
637 }
638 break;
639 case OP_LB:
640 v[c.i.rt].known = 0;
641 v[c.i.rt].sign = 0xffffff80;
642 break;
643 case OP_LH:
644 v[c.i.rt].known = 0;
645 v[c.i.rt].sign = 0xffff8000;
646 break;
647 case OP_LBU:
648 v[c.i.rt].value = 0;
649 v[c.i.rt].known = 0xffffff00;
650 v[c.i.rt].sign = 0;
651 break;
652 case OP_LHU:
653 v[c.i.rt].value = 0;
654 v[c.i.rt].known = 0xffff0000;
655 v[c.i.rt].sign = 0;
656 break;
657 case OP_LWL:
658 case OP_LWR:
659 /* LWL/LWR don't write the full register if the address is
660 * unaligned, so we only need to know the low 2 bits */
661 if (v[c.i.rs].known & 0x3) {
662 imm = (v[c.i.rs].value & 0x3) * 8;
663
664 if (c.i.op == OP_LWL) {
665 imm = BIT(24 - imm) - 1;
666 v[c.i.rt].sign &= ~imm;
667 } else {
668 imm = imm ? GENMASK(31, 32 - imm) : 0;
669 v[c.i.rt].sign = 0;
670 }
cb72ea13 671 v[c.i.rt].known &= imm;
9259d748
PC
672 break;
673 }
674 fallthrough;
675 case OP_LW:
5459088b 676 case OP_META_LWU:
9259d748
PC
677 v[c.i.rt].known = 0;
678 v[c.i.rt].sign = 0;
679 break;
cb72ea13
PC
680 case OP_META:
681 switch (c.m.op) {
682 case OP_META_MOV:
683 v[c.m.rd] = v[c.m.rs];
684 break;
9259d748 685
cb72ea13
PC
686 case OP_META_EXTC:
687 v[c.m.rd].value = (s32)(s8)v[c.m.rs].value;
688 if (v[c.m.rs].known & BIT(7)) {
689 v[c.m.rd].known = v[c.m.rs].known | 0xffffff00;
690 v[c.m.rd].sign = 0;
691 } else {
692 v[c.m.rd].known = v[c.m.rs].known & 0x7f;
693 v[c.m.rd].sign = 0xffffff80;
694 }
695 break;
696
697 case OP_META_EXTS:
698 v[c.m.rd].value = (s32)(s16)v[c.m.rs].value;
699 if (v[c.m.rs].known & BIT(15)) {
700 v[c.m.rd].known = v[c.m.rs].known | 0xffff0000;
701 v[c.m.rd].sign = 0;
702 } else {
703 v[c.m.rd].known = v[c.m.rs].known & 0x7fff;
704 v[c.m.rd].sign = 0xffff8000;
705 }
706 break;
707
708 case OP_META_COM:
709 v[c.m.rd].known = v[c.m.rs].known;
710 v[c.m.rd].value = ~v[c.m.rs].value;
711 v[c.m.rd].sign = v[c.m.rs].sign;
712 break;
713 default:
714 break;
9259d748
PC
715 }
716 break;
cb72ea13
PC
717 case OP_JAL:
718 v[31].known = 0xffffffff;
719 v[31].sign = 0;
684432ad 720 v[31].value = block->pc + ((idx + 2) << 2);
cb72ea13 721 break;
9259d748
PC
722
723 default:
724 break;
725 }
726
727 /* Reset register 0 which may have been used as a target */
728 v[0].value = 0;
729 v[0].sign = 0;
730 v[0].known = 0xffffffff;
731}
732
733enum psx_map
734lightrec_get_constprop_map(const struct lightrec_state *state,
735 const struct constprop_data *v, u8 reg, s16 imm)
736{
737 const struct lightrec_mem_map *map;
738 unsigned int i;
739 u32 min, max;
740
741 min = get_min_value(&v[reg]) + imm;
742 max = get_max_value(&v[reg]) + imm;
743
744 /* Handle the case where max + imm overflows */
745 if ((min & 0xe0000000) != (max & 0xe0000000))
746 return PSX_MAP_UNKNOWN;
747
8afce295 748 pr_debug("Min: "X32_FMT" max: "X32_FMT" Known: "X32_FMT" Sign: "X32_FMT"\n",
9259d748
PC
749 min, max, v[reg].known, v[reg].sign);
750
751 min = kunseg(min);
752 max = kunseg(max);
753
754 for (i = 0; i < state->nb_maps; i++) {
755 map = &state->maps[i];
756
757 if (min >= map->pc && min < map->pc + map->length
758 && max >= map->pc && max < map->pc + map->length)
759 return (enum psx_map) i;
760 }
761
762 return PSX_MAP_UNKNOWN;
763}