|
|
1.1 root 1:
2: #define writemem_special writemem
3: #define readmem_special readmem
4:
5: #define USE_MATCHSTATE 0
6: #include "sysconfig.h"
7: #include "sysdeps.h"
8:
9: #if defined(JIT)
10:
11: #include "options.h"
12: #include "events.h"
13: #include "include/memory.h"
14: #include "newcpu.h"
15: #include "comptbl.h"
16: #include "compemu.h"
17:
18:
19: #define NATMEM_OFFSETX (uae_u32)NATMEM_OFFSET
20:
21: // %%% BRIAN KING WAS HERE %%%
22: extern bool canbang;
23: #include <sys/mman.h>
24: void jit_abort(const TCHAR*,...);
25: compop_func *compfunctbl[65536];
26: compop_func *nfcompfunctbl[65536];
27: #ifdef NOFLAGS_SUPPORT
28: compop_func *nfcpufunctbl[65536];
29: #endif
30: uae_u8* comp_pc_p;
31:
32: uae_u8* start_pc_p;
33: uae_u32 start_pc;
34: uae_u32 current_block_pc_p;
35: uae_u32 current_block_start_target;
36: uae_u32 needed_flags;
37: static uae_u32 next_pc_p;
38: static uae_u32 taken_pc_p;
39: static int branch_cc;
40: int segvcount=0;
41: int soft_flush_count=0;
42: int hard_flush_count=0;
43: int compile_count=0;
44: int checksum_count=0;
45: static uae_u8* current_compile_p=NULL;
46: static uae_u8* max_compile_start;
47: uae_u8* compiled_code=NULL;
48: static uae_s32 reg_alloc_run;
49:
50: static int lazy_flush = 1; // Flag: lazy translation cache invalidation
51: static int avoid_fpu = 1; // Flag: compile FPU instructions ?
52: static int have_cmov = 0; // target has CMOV instructions ?
53: static int have_rat_stall = 1; // target has partial register stalls ?
54: const int tune_alignment = 1; // Tune code alignments for running CPU ?
55: const int tune_nop_fillers = 1; // Tune no-op fillers for architecture
56:
57: static int setzflg_uses_bsf = 0; // setzflg virtual instruction can use native BSF instruction correctly?
58: static int align_loops = 32; // Align the start of loops
59: static int align_jumps = 32; // Align the start of jumps
60:
61: void* pushall_call_handler=NULL;
62: static void* popall_do_nothing=NULL;
63: static void* popall_exec_nostats=NULL;
64: static void* popall_execute_normal=NULL;
65: static void* popall_cache_miss=NULL;
66: static void* popall_recompile_block=NULL;
67: static void* popall_check_checksum=NULL;
68:
69: extern uae_u32 oink;
70: extern unsigned long foink3;
71: extern unsigned long foink;
72:
73: /* The 68k only ever executes from even addresses. So right now, we
74: waste half the entries in this array
75: UPDATE: We now use those entries to store the start of the linked
76: lists that we maintain for each hash result. */
77: static cacheline cache_tags[TAGSIZE];
78: static int letit=0;
79: static blockinfo* hold_bi[MAX_HOLD_BI];
80: static blockinfo* active;
81: static blockinfo* dormant;
82:
83: op_properties prop[65536];
84:
85: #ifdef NOFLAGS_SUPPORT
86: /* 68040 */
87: extern const struct comptbl op_smalltbl_0_nf[];
88: #endif
89: extern const struct comptbl op_smalltbl_0_comp_nf[];
90: extern const struct comptbl op_smalltbl_0_comp_ff[];
91: #ifdef NOFLAGS_SUPPORT
92: /* 68020 + 68881 */
93: extern const struct cputbl op_smalltbl_1_nf[];
94: /* 68020 */
95: extern const struct cputbl op_smalltbl_2_nf[];
96: /* 68010 */
97: extern const struct cputbl op_smalltbl_3_nf[];
98: /* 68000 */
99: extern const struct cputbl op_smalltbl_4_nf[];
100: /* 68000 slow but compatible. */
101: extern const struct cputbl op_smalltbl_5_nf[];
102: #endif
103:
104: static void flush_icache_hard(uae_u32 ptr, int n);
105:
106:
107:
108: static bigstate live;
109: static smallstate empty_ss;
110: static smallstate default_ss;
111: static int optlev;
112:
113: static int writereg(int r, int size);
114: static void unlock(int r);
115: static void setlock(int r);
116: static int readreg_specific(int r, int size, int spec);
117: static int writereg_specific(int r, int size, int spec);
118: static void prepare_for_call_1(void);
119: static void prepare_for_call_2(void);
120: static void align_target(uae_u32 a);
121:
122: static uae_s32 nextused[VREGS];
123:
124: static uae_u8 *popallspace;
125:
126: uae_u32 m68k_pc_offset;
127:
128: /* Some arithmetic operations can be optimized away if the operands
129: are known to be constant. But that's only a good idea when the
130: side effects they would have on the flags are not important. This
131: variable indicates whether we need the side effects or not
132: */
133: uae_u32 needflags=0;
134:
135: /* Flag handling is complicated.
136:
137: x86 instructions create flags, which quite often are exactly what we
138: want. So at times, the "68k" flags are actually in the x86 flags.
139:
140: Then again, sometimes we do x86 instructions that clobber the x86
141: flags, but don't represent a corresponding m68k instruction. In that
142: case, we have to save them.
143:
144: We used to save them to the stack, but now store them back directly
145: into the regflags.cznv of the traditional emulation. Thus some odd
146: names.
147:
148: So flags can be in either of two places (used to be three; boy were
149: things complicated back then!); And either place can contain either
150: valid flags or invalid trash (and on the stack, there was also the
151: option of "nothing at all", now gone). A couple of variables keep
152: track of the respective states.
153:
154: To make things worse, we might or might not be interested in the flags.
155: by default, we are, but a call to dont_care_flags can change that
156: until the next call to live_flags. If we are not, pretty much whatever
157: is in the register and/or the native flags is seen as valid.
158: */
159:
160:
161: STATIC_INLINE blockinfo* get_blockinfo(uae_u32 cl)
162: {
163: return cache_tags[cl+1].bi;
164: }
165:
166: STATIC_INLINE blockinfo* get_blockinfo_addr(void* addr)
167: {
168: blockinfo* bi=get_blockinfo(cacheline(addr));
169:
170: while (bi) {
171: if (bi->pc_p==addr)
172: return bi;
173: bi=bi->next_same_cl;
174: }
175: return NULL;
176: }
177:
178:
179: /*******************************************************************
180: * All sorts of list related functions for all of the lists *
181: *******************************************************************/
182:
183: STATIC_INLINE void remove_from_cl_list(blockinfo* bi)
184: {
185: uae_u32 cl=cacheline(bi->pc_p);
186:
187: if (bi->prev_same_cl_p)
188: *(bi->prev_same_cl_p)=bi->next_same_cl;
189: if (bi->next_same_cl)
190: bi->next_same_cl->prev_same_cl_p=bi->prev_same_cl_p;
191: if (cache_tags[cl+1].bi)
192: cache_tags[cl].handler=cache_tags[cl+1].bi->handler_to_use;
193: else
194: cache_tags[cl].handler=(cpuop_func*)popall_execute_normal;
195: }
196:
197: STATIC_INLINE void remove_from_list(blockinfo* bi)
198: {
199: if (bi->prev_p)
200: *(bi->prev_p)=bi->next;
201: if (bi->next)
202: bi->next->prev_p=bi->prev_p;
203: }
204:
205: STATIC_INLINE void remove_from_lists(blockinfo* bi)
206: {
207: remove_from_list(bi);
208: remove_from_cl_list(bi);
209: }
210:
211: STATIC_INLINE void add_to_cl_list(blockinfo* bi)
212: {
213: uae_u32 cl=cacheline(bi->pc_p);
214:
215: if (cache_tags[cl+1].bi)
216: cache_tags[cl+1].bi->prev_same_cl_p=&(bi->next_same_cl);
217: bi->next_same_cl=cache_tags[cl+1].bi;
218:
219: cache_tags[cl+1].bi=bi;
220: bi->prev_same_cl_p=&(cache_tags[cl+1].bi);
221:
222: cache_tags[cl].handler=bi->handler_to_use;
223: }
224:
225: STATIC_INLINE void raise_in_cl_list(blockinfo* bi)
226: {
227: remove_from_cl_list(bi);
228: add_to_cl_list(bi);
229: }
230:
231: STATIC_INLINE void add_to_active(blockinfo* bi)
232: {
233: if (active)
234: active->prev_p=&(bi->next);
235: bi->next=active;
236:
237: active=bi;
238: bi->prev_p=&active;
239: }
240:
241: STATIC_INLINE void add_to_dormant(blockinfo* bi)
242: {
243: if (dormant)
244: dormant->prev_p=&(bi->next);
245: bi->next=dormant;
246:
247: dormant=bi;
248: bi->prev_p=&dormant;
249: }
250:
251: STATIC_INLINE void remove_dep(dependency* d)
252: {
253: if (d->prev_p)
254: *(d->prev_p)=d->next;
255: if (d->next)
256: d->next->prev_p=d->prev_p;
257: d->prev_p=NULL;
258: d->next=NULL;
259: }
260:
261: /* This block's code is about to be thrown away, so it no longer
262: depends on anything else */
263: STATIC_INLINE void remove_deps(blockinfo* bi)
264: {
265: remove_dep(&(bi->dep[0]));
266: remove_dep(&(bi->dep[1]));
267: }
268:
269: STATIC_INLINE void adjust_jmpdep(dependency* d, void* a)
270: {
271: *(d->jmp_off)=(uae_u32)a-((uae_u32)d->jmp_off+4);
272: }
273:
274: /********************************************************************
275: * Soft flush handling support functions *
276: ********************************************************************/
277:
278: STATIC_INLINE void set_dhtu(blockinfo* bi, void* dh)
279: {
280: //write_log (L"JIT: bi is %p\n",bi);
281: if (dh!=bi->direct_handler_to_use) {
282: dependency* x=bi->deplist;
283: //write_log (L"JIT: bi->deplist=%p\n",bi->deplist);
284: while (x) {
285: //write_log (L"JIT: x is %p\n",x);
286: //write_log (L"JIT: x->next is %p\n",x->next);
287: //write_log (L"JIT: x->prev_p is %p\n",x->prev_p);
288:
289: if (x->jmp_off) {
290: adjust_jmpdep(x,dh);
291: }
292: x=x->next;
293: }
294: bi->direct_handler_to_use=(cpuop_func*)dh;
295: }
296: }
297:
298: STATIC_INLINE void invalidate_block(blockinfo* bi)
299: {
300: int i;
301:
302: bi->optlevel=0;
303: bi->count=currprefs.optcount[0]-1;
304: bi->handler=NULL;
305: bi->handler_to_use=(cpuop_func*)popall_execute_normal;
306: bi->direct_handler=NULL;
307: set_dhtu(bi,bi->direct_pen);
308: bi->needed_flags=0xff;
309:
310: for (i=0;i<2;i++) {
311: bi->dep[i].jmp_off=NULL;
312: bi->dep[i].target=NULL;
313: }
314: remove_deps(bi);
315: }
316:
317: STATIC_INLINE void create_jmpdep(blockinfo* bi, int i, uae_u32* jmpaddr, uae_u32 target)
318: {
319: blockinfo* tbi=get_blockinfo_addr((void*)target);
320:
321: Dif(!tbi) {
322: jit_abort (L"JIT: Could not create jmpdep!\n");
323: }
324: bi->dep[i].jmp_off=jmpaddr;
325: bi->dep[i].target=tbi;
326: bi->dep[i].next=tbi->deplist;
327: if (bi->dep[i].next)
328: bi->dep[i].next->prev_p=&(bi->dep[i].next);
329: bi->dep[i].prev_p=&(tbi->deplist);
330: tbi->deplist=&(bi->dep[i]);
331: }
332:
333: STATIC_INLINE void big_to_small_state(bigstate* b, smallstate* s)
334: {
335: int i;
336: int count=0;
337:
338: for (i=0;i<N_REGS;i++) {
339: s->nat[i].validsize=0;
340: s->nat[i].dirtysize=0;
341: if (b->nat[i].nholds) {
342: int index=b->nat[i].nholds-1;
343: int r=b->nat[i].holds[index];
344: s->nat[i].holds=r;
345: s->nat[i].validsize=b->state[r].validsize;
346: s->nat[i].dirtysize=b->state[r].dirtysize;
347: count++;
348: }
349: }
350: write_log (L"JIT: count=%d\n",count);
351: for (i=0;i<N_REGS;i++) { // FIXME --- don't do dirty yet
352: s->nat[i].dirtysize=0;
353: }
354: }
355:
356: STATIC_INLINE void attached_state(blockinfo* bi)
357: {
358: bi->havestate=1;
359: if (bi->direct_handler_to_use==bi->direct_handler)
360: set_dhtu(bi,bi->direct_pen);
361: bi->direct_handler=bi->direct_pen;
362: bi->status=BI_TARGETTED;
363: }
364:
365: STATIC_INLINE blockinfo* get_blockinfo_addr_new(void* addr, int setstate)
366: {
367: blockinfo* bi=get_blockinfo_addr(addr);
368: int i;
369:
370: #if USE_OPTIMIZER
371: if (reg_alloc_run)
372: return NULL;
373: #endif
374: if (!bi) {
375: for (i=0;i<MAX_HOLD_BI && !bi;i++) {
376: if (hold_bi[i]) {
377: uae_u32 cl=cacheline(addr);
378:
379: bi=hold_bi[i];
380: hold_bi[i]=NULL;
381: bi->pc_p=(uae_u8*)addr;
382: invalidate_block(bi);
383: add_to_active(bi);
384: add_to_cl_list(bi);
385:
386: }
387: }
388: }
389: if (!bi) {
390: jit_abort (L"JIT: Looking for blockinfo, can't find free one\n");
391: }
392:
393: #if USE_MATCHSTATE
394: if (setstate &&
395: !bi->havestate) {
396: big_to_small_state(&live,&(bi->env));
397: attached_state(bi);
398: }
399: #endif
400: return bi;
401: }
402:
403: static void prepare_block(blockinfo* bi);
404:
405: STATIC_INLINE void alloc_blockinfos(void)
406: {
407: int i;
408: blockinfo* bi;
409:
410: for (i=0;i<MAX_HOLD_BI;i++) {
411: if (hold_bi[i])
412: return;
413: bi=hold_bi[i]=(blockinfo*)current_compile_p;
414: current_compile_p+=sizeof(blockinfo);
415:
416: prepare_block(bi);
417: }
418: }
419:
420: /********************************************************************
421: * Preferences handling. This is just a convenient place to put it *
422: ********************************************************************/
423: extern bool have_done_picasso;
424:
425: bool check_prefs_changed_comp (void)
426: {
427: bool changed = 0;
428: static int cachesize_prev, comptrust_prev;
429: static bool canbang_prev;
430:
431: if (currprefs.comptrustbyte != changed_prefs.comptrustbyte ||
432: currprefs.comptrustword != changed_prefs.comptrustword ||
433: currprefs.comptrustlong != changed_prefs.comptrustlong ||
434: currprefs.comptrustnaddr!= changed_prefs.comptrustnaddr ||
435: currprefs.compnf != changed_prefs.compnf ||
436: currprefs.comp_hardflush != changed_prefs.comp_hardflush ||
437: currprefs.comp_constjump != changed_prefs.comp_constjump ||
438: currprefs.comp_oldsegv != changed_prefs.comp_oldsegv ||
439: currprefs.compfpu != changed_prefs.compfpu ||
440: currprefs.fpu_strict != changed_prefs.fpu_strict)
441: changed = 1;
442:
443: currprefs.comptrustbyte = changed_prefs.comptrustbyte;
444: currprefs.comptrustword = changed_prefs.comptrustword;
445: currprefs.comptrustlong = changed_prefs.comptrustlong;
446: currprefs.comptrustnaddr= changed_prefs.comptrustnaddr;
447: currprefs.compnf = changed_prefs.compnf;
448: currprefs.comp_hardflush = changed_prefs.comp_hardflush;
449: currprefs.comp_constjump = changed_prefs.comp_constjump;
450: currprefs.comp_oldsegv = changed_prefs.comp_oldsegv;
451: currprefs.compfpu = changed_prefs.compfpu;
452: currprefs.fpu_strict = changed_prefs.fpu_strict;
453:
454: if (currprefs.cachesize != changed_prefs.cachesize) {
455: if (currprefs.cachesize && !changed_prefs.cachesize) {
456: cachesize_prev = currprefs.cachesize;
457: comptrust_prev = currprefs.comptrustbyte;
458: canbang_prev = canbang;
459: } else if (!currprefs.cachesize && changed_prefs.cachesize == cachesize_prev) {
460: changed_prefs.comptrustbyte = currprefs.comptrustbyte = comptrust_prev;
461: changed_prefs.comptrustword = currprefs.comptrustword = comptrust_prev;
462: changed_prefs.comptrustlong = currprefs.comptrustlong = comptrust_prev;
463: changed_prefs.comptrustnaddr = currprefs.comptrustnaddr = comptrust_prev;
464: }
465: currprefs.cachesize = changed_prefs.cachesize;
466: alloc_cache();
467: changed = 1;
468: }
469: if (!candirect)
470: canbang = 0;
471:
472: // Turn off illegal-mem logging when using JIT...
473: if(currprefs.cachesize)
474: currprefs.illegal_mem = changed_prefs.illegal_mem;// = 0;
475:
476: currprefs.comp_midopt = changed_prefs.comp_midopt;
477: currprefs.comp_lowopt = changed_prefs.comp_lowopt;
478:
479: if ((!canbang || !currprefs.cachesize) && currprefs.comptrustbyte != 1) {
480: // Set all of these to indirect when canbang == 0
481: // Basically, set the compforcesettings option...
482: currprefs.comptrustbyte = 1;
483: currprefs.comptrustword = 1;
484: currprefs.comptrustlong = 1;
485: currprefs.comptrustnaddr= 1;
486:
487: changed_prefs.comptrustbyte = 1;
488: changed_prefs.comptrustword = 1;
489: changed_prefs.comptrustlong = 1;
490: changed_prefs.comptrustnaddr= 1;
491:
492: changed = 1;
493:
494: if (currprefs.cachesize)
495: write_log (L"JIT: Reverting to \"indirect\" access, because canbang is zero!\n");
496: }
497:
498: if (changed)
499: write_log (L"JIT: cache=%d. b=%d w=%d l=%d fpu=%d nf=%d const=%d hard=%d\n",
500: currprefs.cachesize,
501: currprefs.comptrustbyte, currprefs.comptrustword, currprefs.comptrustlong,
502: currprefs.compfpu, currprefs.compnf, currprefs.comp_constjump, currprefs.comp_hardflush);
503:
504: #if 0
505: if (!currprefs.compforcesettings) {
506: int stop=0;
507: if (currprefs.comptrustbyte!=0 && currprefs.comptrustbyte!=3)
508: stop = 1, write_log (L"JIT: comptrustbyte is not 'direct' or 'afterpic'\n");
509: if (currprefs.comptrustword!=0 && currprefs.comptrustword!=3)
510: stop = 1, write_log (L"JIT: comptrustword is not 'direct' or 'afterpic'\n");
511: if (currprefs.comptrustlong!=0 && currprefs.comptrustlong!=3)
512: stop = 1, write_log (L"JIT: comptrustlong is not 'direct' or 'afterpic'\n");
513: if (currprefs.comptrustnaddr!=0 && currprefs.comptrustnaddr!=3)
514: stop = 1, write_log (L"JIT: comptrustnaddr is not 'direct' or 'afterpic'\n");
515: if (currprefs.compnf!=1)
516: stop = 1, write_log (L"JIT: compnf is not 'yes'\n");
517: if (currprefs.cachesize<1024)
518: stop = 1, write_log (L"JIT: cachesize is less than 1024\n");
519: if (currprefs.comp_hardflush)
520: stop = 1, write_log (L"JIT: comp_flushmode is 'hard'\n");
521: if (!canbang)
522: stop = 1, write_log (L"JIT: Cannot use most direct memory access,\n"
523: " and unable to recover from failed guess!\n");
524: if (stop) {
525: gui_message("JIT: Configuration problems were detected!\n"
526: "JIT: These will adversely affect performance, and should\n"
527: "JIT: not be used. For more info, please see README.JIT-tuning\n"
528: "JIT: in the UAE documentation directory. You can force\n"
529: "JIT: your settings to be used by setting\n"
530: "JIT: 'compforcesettings=yes'\n"
531: "JIT: in your config file\n");
532: exit(1);
533: }
534: }
535: #endif
536: return changed;
537: }
538:
539: /********************************************************************
540: * Get the optimizer stuff *
541: ********************************************************************/
542:
543: //#include "compemu_optimizer.c"
544: #include "compemu_optimizer_x86.cpp"
545:
546: /********************************************************************
547: * Functions to emit data into memory, and other general support *
548: ********************************************************************/
549:
550: static uae_u8* target;
551:
552: static void emit_init(void)
553: {
554: }
555:
556: STATIC_INLINE void emit_byte(uae_u8 x)
557: {
558: *target++=x;
559: }
560:
561: STATIC_INLINE void emit_word(uae_u16 x)
562: {
563: *((uae_u16*)target)=x;
564: target+=2;
565: }
566:
567: STATIC_INLINE void emit_long(uae_u32 x)
568: {
569: *((uae_u32*)target)=x;
570: target+=4;
571: }
572:
573: STATIC_INLINE uae_u32 reverse32(uae_u32 oldv)
574: {
575: return ((oldv>>24)&0xff) | ((oldv>>8)&0xff00) |
576: ((oldv<<8)&0xff0000) | ((oldv<<24)&0xff000000);
577: }
578:
579:
580: void set_target(uae_u8* t)
581: {
582: lopt_emit_all();
583: target=t;
584: }
585:
586: STATIC_INLINE uae_u8* get_target_noopt(void)
587: {
588: return target;
589: }
590:
591: STATIC_INLINE uae_u8* get_target(void)
592: {
593: lopt_emit_all();
594: return get_target_noopt();
595: }
596:
597:
598: /********************************************************************
599: * Getting the information about the target CPU *
600: ********************************************************************/
601:
602: #include "compemu_raw_x86.cpp"
603:
604:
605: /********************************************************************
606: * Flags status handling. EMIT TIME! *
607: ********************************************************************/
608:
609: static void bt_l_ri_noclobber(R4 r, IMM i);
610:
611: static void make_flags_live_internal(void)
612: {
613: if (live.flags_in_flags==VALID)
614: return;
615: Dif (live.flags_on_stack==TRASH) {
616: jit_abort (L"JIT: Want flags, got something on stack, but it is TRASH\n");
617: }
618: if (live.flags_on_stack==VALID) {
619: int tmp;
620: tmp=readreg_specific(FLAGTMP,4,FLAG_NREG2);
621: raw_reg_to_flags(tmp);
622: unlock(tmp);
623:
624: live.flags_in_flags=VALID;
625: return;
626: }
627: jit_abort (L"JIT: Huh? live.flags_in_flags=%d, live.flags_on_stack=%d, but need to make live\n",
628: live.flags_in_flags,live.flags_on_stack);
629: }
630:
631: static void flags_to_stack(void)
632: {
633: if (live.flags_on_stack==VALID)
634: return;
635: if (!live.flags_are_important) {
636: live.flags_on_stack=VALID;
637: return;
638: }
639: Dif (live.flags_in_flags!=VALID)
640: jit_abort (L"flags_to_stack != VALID");
641: else {
642: int tmp;
643: tmp=writereg_specific(FLAGTMP,4,FLAG_NREG1);
644: raw_flags_to_reg(tmp);
645: unlock(tmp);
646: }
647: live.flags_on_stack=VALID;
648: }
649:
650: STATIC_INLINE void clobber_flags(void)
651: {
652: if (live.flags_in_flags==VALID && live.flags_on_stack!=VALID)
653: flags_to_stack();
654: live.flags_in_flags=TRASH;
655: }
656:
657: /* Prepare for leaving the compiled stuff */
658: STATIC_INLINE void flush_flags(void)
659: {
660: flags_to_stack();
661: return;
662: }
663:
664: int touchcnt;
665:
666: /********************************************************************
667: * register allocation per block logging *
668: ********************************************************************/
669:
670: static uae_s8 vstate[VREGS];
671: static uae_s8 nstate[N_REGS];
672:
673: #define L_UNKNOWN -127
674: #define L_UNAVAIL -1
675: #define L_NEEDED -2
676: #define L_UNNEEDED -3
677:
678: STATIC_INLINE void log_startblock(void)
679: {
680: int i;
681: for (i=0;i<VREGS;i++)
682: vstate[i]=L_UNKNOWN;
683: for (i=0;i<N_REGS;i++)
684: nstate[i]=L_UNKNOWN;
685: }
686:
687: STATIC_INLINE void log_isused(int n)
688: {
689: if (nstate[n]==L_UNKNOWN)
690: nstate[n]=L_UNAVAIL;
691: }
692:
693: STATIC_INLINE void log_isreg(int n, int r)
694: {
695: if (nstate[n]==L_UNKNOWN)
696: nstate[n]=r;
697: if (vstate[r]==L_UNKNOWN)
698: vstate[r]=L_NEEDED;
699: }
700:
701: STATIC_INLINE void log_clobberreg(int r)
702: {
703: if (vstate[r]==L_UNKNOWN)
704: vstate[r]=L_UNNEEDED;
705: }
706:
707: /* This ends all possibility of clever register allocation */
708:
709: STATIC_INLINE void log_flush(void)
710: {
711: int i;
712: for (i=0;i<VREGS;i++)
713: if (vstate[i]==L_UNKNOWN)
714: vstate[i]=L_NEEDED;
715: for (i=0;i<N_REGS;i++)
716: if (nstate[i]==L_UNKNOWN)
717: nstate[i]=L_UNAVAIL;
718: }
719:
720: STATIC_INLINE void log_dump(void)
721: {
722: int i;
723:
724: return;
725:
726: write_log (L"----------------------\n");
727: for (i=0;i<N_REGS;i++) {
728: switch(nstate[i]) {
729: case L_UNKNOWN: write_log (L"Nat %d : UNKNOWN\n",i); break;
730: case L_UNAVAIL: write_log (L"Nat %d : UNAVAIL\n",i); break;
731: default: write_log (L"Nat %d : %d\n",i,nstate[i]); break;
732: }
733: }
734: for (i=0;i<VREGS;i++) {
735: if (vstate[i]==L_UNNEEDED)
736: write_log (L"Virt %d: UNNEEDED\n",i);
737: }
738: }
739:
740: /********************************************************************
741: * register status handling. EMIT TIME! *
742: ********************************************************************/
743:
744: STATIC_INLINE void set_status(int r, int status)
745: {
746: if (status==ISCONST)
747: log_clobberreg(r);
748: live.state[r].status=status;
749: }
750:
751:
752: STATIC_INLINE int isinreg(int r)
753: {
754: return live.state[r].status==CLEAN || live.state[r].status==DIRTY;
755: }
756:
757: STATIC_INLINE void adjust_nreg(int r, uae_u32 val)
758: {
759: if (!val)
760: return;
761: raw_lea_l_brr(r,r,val);
762: }
763:
764: static void tomem(int r)
765: {
766: int rr=live.state[r].realreg;
767:
768: if (isinreg(r)) {
769: if (live.state[r].val &&
770: live.nat[rr].nholds==1 &&
771: !live.nat[rr].locked) {
772: // write_log (L"JIT: RemovingA offset %x from reg %d (%d) at %p\n",
773: // live.state[r].val,r,rr,target);
774: adjust_nreg(rr,live.state[r].val);
775: live.state[r].val=0;
776: live.state[r].dirtysize=4;
777: set_status(r,DIRTY);
778: }
779: }
780:
781: if (live.state[r].status==DIRTY) {
782: switch (live.state[r].dirtysize) {
783: case 1: raw_mov_b_mr((uae_u32)live.state[r].mem,rr); break;
784: case 2: raw_mov_w_mr((uae_u32)live.state[r].mem,rr); break;
785: case 4: raw_mov_l_mr((uae_u32)live.state[r].mem,rr); break;
786: default: abort();
787: }
788: set_status(r,CLEAN);
789: live.state[r].dirtysize=0;
790: }
791: }
792:
793: STATIC_INLINE int isconst(int r)
794: {
795: return live.state[r].status==ISCONST;
796: }
797:
798: int is_const(int r)
799: {
800: return isconst(r);
801: }
802:
803: STATIC_INLINE void writeback_const(int r)
804: {
805: if (!isconst(r))
806: return;
807: Dif (live.state[r].needflush==NF_HANDLER) {
808: jit_abort (L"JIT: Trying to write back constant NF_HANDLER!\n");
809: }
810:
811: raw_mov_l_mi((uae_u32)live.state[r].mem,live.state[r].val);
812: live.state[r].val=0;
813: set_status(r,INMEM);
814: }
815:
816: STATIC_INLINE void tomem_c(int r)
817: {
818: if (isconst(r)) {
819: writeback_const(r);
820: }
821: else
822: tomem(r);
823: }
824:
825: static void evict(int r)
826: {
827: int rr;
828:
829: if (!isinreg(r))
830: return;
831: tomem(r);
832: rr=live.state[r].realreg;
833:
834: Dif (live.nat[rr].locked &&
835: live.nat[rr].nholds==1) {
836: jit_abort (L"JIT: register %d in nreg %d is locked!\n",r,live.state[r].realreg);
837: }
838:
839: live.nat[rr].nholds--;
840: if (live.nat[rr].nholds!=live.state[r].realind) { /* Was not last */
841: int topreg=live.nat[rr].holds[live.nat[rr].nholds];
842: int thisind=live.state[r].realind;
843: live.nat[rr].holds[thisind]=topreg;
844: live.state[topreg].realind=thisind;
845: }
846: live.state[r].realreg=-1;
847: set_status(r,INMEM);
848: }
849:
850: STATIC_INLINE void free_nreg(int r)
851: {
852: int i=live.nat[r].nholds;
853:
854: while (i) {
855: int vr;
856:
857: --i;
858: vr=live.nat[r].holds[i];
859: evict(vr);
860: }
861: Dif (live.nat[r].nholds!=0) {
862: jit_abort (L"JIT: Failed to free nreg %d, nholds is %d\n",r,live.nat[r].nholds);
863: }
864: }
865:
866: /* Use with care! */
867: STATIC_INLINE void isclean(int r)
868: {
869: if (!isinreg(r))
870: return;
871: live.state[r].validsize=4;
872: live.state[r].dirtysize=0;
873: live.state[r].val=0;
874: set_status(r,CLEAN);
875: }
876:
877: STATIC_INLINE void disassociate(int r)
878: {
879: isclean(r);
880: evict(r);
881: }
882:
883: STATIC_INLINE void set_const(int r, uae_u32 val)
884: {
885: disassociate(r);
886: live.state[r].val=val;
887: set_status(r,ISCONST);
888: }
889:
890: STATIC_INLINE uae_u32 get_offset(int r)
891: {
892: return live.state[r].val;
893: }
894:
895: static int alloc_reg_hinted(int r, int size, int willclobber, int hint)
896: {
897: int bestreg;
898: uae_s32 when;
899: int i;
900: uae_s32 badness=0; /* to shut up gcc */
901: bestreg=-1;
902: when=2000000000;
903:
904: for (i=N_REGS;i--;) {
905: badness=live.nat[i].touched;
906: if (live.nat[i].nholds==0)
907: badness=0;
908: if (i==hint)
909: badness-=200000000;
910: if (!live.nat[i].locked && badness<when) {
911: if ((size==1 && live.nat[i].canbyte) ||
912: (size==2 && live.nat[i].canword) ||
913: (size==4)) {
914: bestreg=i;
915: when=badness;
916: if (live.nat[i].nholds==0 && hint<0)
917: break;
918: if (i==hint)
919: break;
920: }
921: }
922: }
923: Dif (bestreg==-1)
924: jit_abort (L"alloc_reg_hinted bestreg=-1");
925:
926: if (live.nat[bestreg].nholds>0) {
927: free_nreg(bestreg);
928: }
929: if (isinreg(r)) {
930: int rr=live.state[r].realreg;
931: /* This will happen if we read a partially dirty register at a
932: bigger size */
933: Dif (willclobber || live.state[r].validsize>=size)
934: jit_abort (L"willclobber || live.state[r].validsize>=size");
935: Dif (live.nat[rr].nholds!=1)
936: jit_abort (L"live.nat[rr].nholds!=1");
937: if (size==4 && live.state[r].validsize==2) {
938: log_isused(bestreg);
939: raw_mov_l_rm(bestreg,(uae_u32)live.state[r].mem);
940: raw_bswap_32(bestreg);
941: raw_zero_extend_16_rr(rr,rr);
942: raw_zero_extend_16_rr(bestreg,bestreg);
943: raw_bswap_32(bestreg);
944: raw_lea_l_rr_indexed(rr,rr,bestreg);
945: live.state[r].validsize=4;
946: live.nat[rr].touched=touchcnt++;
947: return rr;
948: }
949: if (live.state[r].validsize==1) {
950: /* Nothing yet */
951: }
952: evict(r);
953: }
954:
955: if (!willclobber) {
956: if (live.state[r].status!=UNDEF) {
957: if (isconst(r)) {
958: raw_mov_l_ri(bestreg,live.state[r].val);
959: live.state[r].val=0;
960: live.state[r].dirtysize=4;
961: set_status(r,DIRTY);
962: log_isused(bestreg);
963: }
964: else {
965: if (r==FLAGTMP)
966: raw_load_flagreg(bestreg,r);
967: else if (r==FLAGX)
968: raw_load_flagx(bestreg,r);
969: else {
970: raw_mov_l_rm(bestreg,(uae_u32)live.state[r].mem);
971: }
972: live.state[r].dirtysize=0;
973: set_status(r,CLEAN);
974: log_isreg(bestreg,r);
975: }
976: }
977: else {
978: live.state[r].val=0;
979: live.state[r].dirtysize=0;
980: set_status(r,CLEAN);
981: log_isused(bestreg);
982: }
983: live.state[r].validsize=4;
984: }
985: else { /* this is the easiest way, but not optimal. FIXME! */
986: /* Now it's trickier, but hopefully still OK */
987: if (!isconst(r) || size==4) {
988: live.state[r].validsize=size;
989: live.state[r].dirtysize=size;
990: live.state[r].val=0;
991: set_status(r,DIRTY);
992: if (size==4)
993: log_isused(bestreg);
994: else
995: log_isreg(bestreg,r);
996: }
997: else {
998: if (live.state[r].status!=UNDEF)
999: raw_mov_l_ri(bestreg,live.state[r].val);
1000: live.state[r].val=0;
1001: live.state[r].validsize=4;
1002: live.state[r].dirtysize=4;
1003: set_status(r,DIRTY);
1004: log_isused(bestreg);
1005: }
1006: }
1007: live.state[r].realreg=bestreg;
1008: live.state[r].realind=live.nat[bestreg].nholds;
1009: live.nat[bestreg].touched=touchcnt++;
1010: live.nat[bestreg].holds[live.nat[bestreg].nholds]=r;
1011: live.nat[bestreg].nholds++;
1012:
1013: return bestreg;
1014: }
1015:
1016: static int alloc_reg(int r, int size, int willclobber)
1017: {
1018: return alloc_reg_hinted(r,size,willclobber,-1);
1019: }
1020:
1021: static void unlock(int r)
1022: {
1023: Dif (!live.nat[r].locked)
1024: jit_abort (L"unlock %d not locked", r);
1025: live.nat[r].locked--;
1026: }
1027:
1028: static void setlock(int r)
1029: {
1030: live.nat[r].locked++;
1031: }
1032:
1033:
1034: static void mov_nregs(int d, int s)
1035: {
1036: int ns=live.nat[s].nholds;
1037: int nd=live.nat[d].nholds;
1038: int i;
1039:
1040: if (s==d)
1041: return;
1042:
1043: if (nd>0)
1044: free_nreg(d);
1045:
1046: raw_mov_l_rr(d,s);
1047: log_isused(d);
1048:
1049: for (i=0;i<live.nat[s].nholds;i++) {
1050: int vs=live.nat[s].holds[i];
1051:
1052: live.state[vs].realreg=d;
1053: live.state[vs].realind=i;
1054: live.nat[d].holds[i]=vs;
1055: }
1056: live.nat[d].nholds=live.nat[s].nholds;
1057:
1058: live.nat[s].nholds=0;
1059: }
1060:
1061:
1062: STATIC_INLINE void make_exclusive(int r, int size, int spec)
1063: {
1064: reg_status oldstate;
1065: int rr=live.state[r].realreg;
1066: int nr;
1067: int nind;
1068: int ndirt=0;
1069: int i;
1070:
1071: if (!isinreg(r))
1072: return;
1073: if (live.nat[rr].nholds==1)
1074: return;
1075: for (i=0;i<live.nat[rr].nholds;i++) {
1076: int vr=live.nat[rr].holds[i];
1077: if (vr!=r &&
1078: (live.state[vr].status==DIRTY || live.state[vr].val))
1079: ndirt++;
1080: }
1081: if (!ndirt && size<live.state[r].validsize && !live.nat[rr].locked) {
1082: /* Everything else is clean, so let's keep this register */
1083: for (i=0;i<live.nat[rr].nholds;i++) {
1084: int vr=live.nat[rr].holds[i];
1085: if (vr!=r) {
1086: evict(vr);
1087: i--; /* Try that index again! */
1088: }
1089: }
1090: Dif (live.nat[rr].nholds!=1) {
1091: jit_abort (L"JIT: natreg %d holds %d vregs, %d not exclusive\n",
1092: rr,live.nat[rr].nholds,r);
1093: }
1094: return;
1095: }
1096:
1097: /* We have to split the register */
1098: oldstate=live.state[r];
1099:
1100: setlock(rr); /* Make sure this doesn't go away */
1101: /* Forget about r being in the register rr */
1102: disassociate(r);
1103: /* Get a new register, that we will clobber completely */
1104: if (oldstate.status==DIRTY) {
1105: /* If dirtysize is <4, we need a register that can handle the
1106: eventual smaller memory store! Thanks to Quake68k for exposing
1107: this detail ;-) */
1108: nr=alloc_reg_hinted(r,oldstate.dirtysize,1,spec);
1109: }
1110: else {
1111: nr=alloc_reg_hinted(r,4,1,spec);
1112: }
1113: nind=live.state[r].realind;
1114: live.state[r]=oldstate; /* Keep all the old state info */
1115: live.state[r].realreg=nr;
1116: live.state[r].realind=nind;
1117:
1118: if (size<live.state[r].validsize) {
1119: if (live.state[r].val) {
1120: /* Might as well compensate for the offset now */
1121: raw_lea_l_brr(nr,rr,oldstate.val);
1122: live.state[r].val=0;
1123: live.state[r].dirtysize=4;
1124: set_status(r,DIRTY);
1125: }
1126: else
1127: raw_mov_l_rr(nr,rr); /* Make another copy */
1128: }
1129: unlock(rr);
1130: }
1131:
1132: STATIC_INLINE void add_offset(int r, uae_u32 off)
1133: {
1134: live.state[r].val+=off;
1135: }
1136:
1137: STATIC_INLINE void remove_offset(int r, int spec)
1138: {
1139: int rr;
1140:
1141: if (isconst(r))
1142: return;
1143: if (live.state[r].val==0)
1144: return;
1145: if (isinreg(r) && live.state[r].validsize<4)
1146: evict(r);
1147:
1148: if (!isinreg(r))
1149: alloc_reg_hinted(r,4,0,spec);
1150:
1151: Dif (live.state[r].validsize!=4) {
1152: jit_abort (L"JIT: Validsize=%d in remove_offset\n",live.state[r].validsize);
1153: }
1154: make_exclusive(r,0,-1);
1155: /* make_exclusive might have done the job already */
1156: if (live.state[r].val==0)
1157: return;
1158:
1159: rr=live.state[r].realreg;
1160:
1161: if (live.nat[rr].nholds==1) {
1162: //write_log (L"JIT: RemovingB offset %x from reg %d (%d) at %p\n",
1163: // live.state[r].val,r,rr,target);
1164: adjust_nreg(rr,live.state[r].val);
1165: live.state[r].dirtysize=4;
1166: live.state[r].val=0;
1167: set_status(r,DIRTY);
1168: return;
1169: }
1170: jit_abort (L"JIT: Failed in remove_offset\n");
1171: }
1172:
1173: STATIC_INLINE void remove_all_offsets(void)
1174: {
1175: int i;
1176:
1177: for (i=0;i<VREGS;i++)
1178: remove_offset(i,-1);
1179: }
1180:
1181: STATIC_INLINE int readreg_general(int r, int size, int spec, int can_offset)
1182: {
1183: int n;
1184: int answer=-1;
1185:
1186: if (live.state[r].status==UNDEF) {
1187: write_log (L"JIT: WARNING: Unexpected read of undefined register %d\n",r);
1188: }
1189: if (!can_offset)
1190: remove_offset(r,spec);
1191:
1192: if (isinreg(r) && live.state[r].validsize>=size) {
1193: n=live.state[r].realreg;
1194: switch(size) {
1195: case 1:
1196: if (live.nat[n].canbyte || spec>=0) {
1197: answer=n;
1198: }
1199: break;
1200: case 2:
1201: if (live.nat[n].canword || spec>=0) {
1202: answer=n;
1203: }
1204: break;
1205: case 4:
1206: answer=n;
1207: break;
1208: default: abort();
1209: }
1210: if (answer<0)
1211: evict(r);
1212: }
1213: /* either the value was in memory to start with, or it was evicted and
1214: is in memory now */
1215: if (answer<0) {
1216: answer=alloc_reg_hinted(r,spec>=0?4:size,0,spec);
1217: }
1218:
1219: if (spec>=0 && spec!=answer) {
1220: /* Too bad */
1221: mov_nregs(spec,answer);
1222: answer=spec;
1223: }
1224: live.nat[answer].locked++;
1225: live.nat[answer].touched=touchcnt++;
1226: return answer;
1227: }
1228:
1229:
1230:
1231: static int readreg(int r, int size)
1232: {
1233: return readreg_general(r,size,-1,0);
1234: }
1235:
1236: static int readreg_specific(int r, int size, int spec)
1237: {
1238: return readreg_general(r,size,spec,0);
1239: }
1240:
1241: static int readreg_offset(int r, int size)
1242: {
1243: return readreg_general(r,size,-1,1);
1244: }
1245:
1246:
1247: STATIC_INLINE int writereg_general(int r, int size, int spec)
1248: {
1249: int n;
1250: int answer=-1;
1251:
1252: if (size<4) {
1253: remove_offset(r,spec);
1254: }
1255:
1256: make_exclusive(r,size,spec);
1257: if (isinreg(r)) {
1258: int nvsize=size>live.state[r].validsize?size:live.state[r].validsize;
1259: int ndsize=size>live.state[r].dirtysize?size:live.state[r].dirtysize;
1260: n=live.state[r].realreg;
1261:
1262: Dif (live.nat[n].nholds!=1)
1263: jit_abort (L"live.nat[%d].nholds!=1", n);
1264: switch(size) {
1265: case 1:
1266: if (live.nat[n].canbyte || spec>=0) {
1267: live.state[r].dirtysize=ndsize;
1268: live.state[r].validsize=nvsize;
1269: answer=n;
1270: }
1271: break;
1272: case 2:
1273: if (live.nat[n].canword || spec>=0) {
1274: live.state[r].dirtysize=ndsize;
1275: live.state[r].validsize=nvsize;
1276: answer=n;
1277: }
1278: break;
1279: case 4:
1280: live.state[r].dirtysize=ndsize;
1281: live.state[r].validsize=nvsize;
1282: answer=n;
1283: break;
1284: default: abort();
1285: }
1286: if (answer<0)
1287: evict(r);
1288: }
1289: /* either the value was in memory to start with, or it was evicted and
1290: is in memory now */
1291: if (answer<0) {
1292: answer=alloc_reg_hinted(r,size,1,spec);
1293: }
1294: if (spec>=0 && spec!=answer) {
1295: mov_nregs(spec,answer);
1296: answer=spec;
1297: }
1298: if (live.state[r].status==UNDEF)
1299: live.state[r].validsize=4;
1300: live.state[r].dirtysize=size>live.state[r].dirtysize?size:live.state[r].dirtysize;
1301: live.state[r].validsize=size>live.state[r].validsize?size:live.state[r].validsize;
1302:
1303: live.nat[answer].locked++;
1304: live.nat[answer].touched=touchcnt++;
1305: if (size==4) {
1306: live.state[r].val=0;
1307: }
1308: else {
1309: Dif (live.state[r].val) {
1310: jit_abort (L"JIT: Problem with val\n");
1311: }
1312: }
1313: set_status(r,DIRTY);
1314: return answer;
1315: }
1316:
1317: static int writereg(int r, int size)
1318: {
1319: return writereg_general(r,size,-1);
1320: }
1321:
1322: static int writereg_specific(int r, int size, int spec)
1323: {
1324: return writereg_general(r,size,spec);
1325: }
1326:
1327: STATIC_INLINE int rmw_general(int r, int wsize, int rsize, int spec)
1328: {
1329: int n;
1330: int answer=-1;
1331:
1332: if (live.state[r].status==UNDEF) {
1333: write_log (L"JIT: WARNING: Unexpected read of undefined register %d\n",r);
1334: }
1335: remove_offset(r,spec);
1336: make_exclusive(r,0,spec);
1337:
1338: Dif (wsize<rsize) {
1339: jit_abort (L"JIT: Cannot handle wsize<rsize in rmw_general()\n");
1340: }
1341: if (isinreg(r) && live.state[r].validsize>=rsize) {
1342: n=live.state[r].realreg;
1343: Dif (live.nat[n].nholds!=1)
1344: jit_abort (L"live.nat[n].nholds!=1", n);
1345:
1346: switch(rsize) {
1347: case 1:
1348: if (live.nat[n].canbyte || spec>=0) {
1349: answer=n;
1350: }
1351: break;
1352: case 2:
1353: if (live.nat[n].canword || spec>=0) {
1354: answer=n;
1355: }
1356: break;
1357: case 4:
1358: answer=n;
1359: break;
1360: default: abort();
1361: }
1362: if (answer<0)
1363: evict(r);
1364: }
1365: /* either the value was in memory to start with, or it was evicted and
1366: is in memory now */
1367: if (answer<0) {
1368: answer=alloc_reg_hinted(r,spec>=0?4:rsize,0,spec);
1369: }
1370:
1371: if (spec>=0 && spec!=answer) {
1372: /* Too bad */
1373: mov_nregs(spec,answer);
1374: answer=spec;
1375: }
1376: if (wsize>live.state[r].dirtysize)
1377: live.state[r].dirtysize=wsize;
1378: if (wsize>live.state[r].validsize)
1379: live.state[r].validsize=wsize;
1380: set_status(r,DIRTY);
1381:
1382: live.nat[answer].locked++;
1383: live.nat[answer].touched=touchcnt++;
1384:
1385: Dif (live.state[r].val) {
1386: jit_abort (L"JIT: Problem with val(rmw)\n");
1387: }
1388: return answer;
1389: }
1390:
1391: static int rmw(int r, int wsize, int rsize)
1392: {
1393: return rmw_general(r,wsize,rsize,-1);
1394: }
1395:
1396: static int rmw_specific(int r, int wsize, int rsize, int spec)
1397: {
1398: return rmw_general(r,wsize,rsize,spec);
1399: }
1400:
1401:
1402: /* needed for restoring the carry flag on non-P6 cores */
1403: static void bt_l_ri_noclobber(R4 r, IMM i)
1404: {
1405: int size=4;
1406: if (i<16)
1407: size=2;
1408: r=readreg(r,size);
1409: raw_bt_l_ri(r,i);
1410: unlock(r);
1411: }
1412:
1413: /********************************************************************
1414: * FPU register status handling. EMIT TIME! *
1415: ********************************************************************/
1416:
1417: static void f_tomem(int r)
1418: {
1419: if (live.fate[r].status==DIRTY) {
1420: #if USE_LONG_DOUBLE
1421: raw_fmov_ext_mr((uae_u32)live.fate[r].mem,live.fate[r].realreg);
1422: #else
1423: raw_fmov_mr((uae_u32)live.fate[r].mem,live.fate[r].realreg);
1424: #endif
1425: live.fate[r].status=CLEAN;
1426: }
1427: }
1428:
1429: static void f_tomem_drop(int r)
1430: {
1431: if (live.fate[r].status==DIRTY) {
1432: #if USE_LONG_DOUBLE
1433: raw_fmov_ext_mr_drop((uae_u32)live.fate[r].mem,live.fate[r].realreg);
1434: #else
1435: raw_fmov_mr_drop((uae_u32)live.fate[r].mem,live.fate[r].realreg);
1436: #endif
1437: live.fate[r].status=INMEM;
1438: }
1439: }
1440:
1441:
1442: STATIC_INLINE int f_isinreg(int r)
1443: {
1444: return live.fate[r].status==CLEAN || live.fate[r].status==DIRTY;
1445: }
1446:
1447: static void f_evict(int r)
1448: {
1449: int rr;
1450:
1451: if (!f_isinreg(r))
1452: return;
1453: rr=live.fate[r].realreg;
1454: if (live.fat[rr].nholds==1)
1455: f_tomem_drop(r);
1456: else
1457: f_tomem(r);
1458:
1459: Dif (live.fat[rr].locked &&
1460: live.fat[rr].nholds==1) {
1461: jit_abort (L"JIT: FPU register %d in nreg %d is locked!\n",r,live.fate[r].realreg);
1462: }
1463:
1464: live.fat[rr].nholds--;
1465: if (live.fat[rr].nholds!=live.fate[r].realind) { /* Was not last */
1466: int topreg=live.fat[rr].holds[live.fat[rr].nholds];
1467: int thisind=live.fate[r].realind;
1468: live.fat[rr].holds[thisind]=topreg;
1469: live.fate[topreg].realind=thisind;
1470: }
1471: live.fate[r].status=INMEM;
1472: live.fate[r].realreg=-1;
1473: }
1474:
1475: STATIC_INLINE void f_free_nreg(int r)
1476: {
1477: int i=live.fat[r].nholds;
1478:
1479: while (i) {
1480: int vr;
1481:
1482: --i;
1483: vr=live.fat[r].holds[i];
1484: f_evict(vr);
1485: }
1486: Dif (live.fat[r].nholds!=0) {
1487: jit_abort (L"JIT: Failed to free nreg %d, nholds is %d\n",r,live.fat[r].nholds);
1488: }
1489: }
1490:
1491:
1492: /* Use with care! */
1493: STATIC_INLINE void f_isclean(int r)
1494: {
1495: if (!f_isinreg(r))
1496: return;
1497: live.fate[r].status=CLEAN;
1498: }
1499:
1500: STATIC_INLINE void f_disassociate(int r)
1501: {
1502: f_isclean(r);
1503: f_evict(r);
1504: }
1505:
1506:
1507:
1508: static int f_alloc_reg(int r, int willclobber)
1509: {
1510: int bestreg;
1511: uae_s32 when;
1512: int i;
1513: uae_s32 badness;
1514: bestreg=-1;
1515: when=2000000000;
1516: for (i=N_FREGS;i--;) {
1517: badness=live.fat[i].touched;
1518: if (live.fat[i].nholds==0)
1519: badness=0;
1520:
1521: if (!live.fat[i].locked && badness<when) {
1522: bestreg=i;
1523: when=badness;
1524: if (live.fat[i].nholds==0)
1525: break;
1526: }
1527: }
1528: Dif (bestreg==-1)
1529: abort();
1530:
1531: if (live.fat[bestreg].nholds>0) {
1532: f_free_nreg(bestreg);
1533: }
1534: if (f_isinreg(r)) {
1535: f_evict(r);
1536: }
1537:
1538: if (!willclobber) {
1539: if (live.fate[r].status!=UNDEF) {
1540: #if USE_LONG_DOUBLE
1541: raw_fmov_ext_rm(bestreg,(uae_u32)live.fate[r].mem);
1542: #else
1543: raw_fmov_rm(bestreg,(uae_u32)live.fate[r].mem);
1544: #endif
1545: }
1546: live.fate[r].status=CLEAN;
1547: }
1548: else {
1549: live.fate[r].status=DIRTY;
1550: }
1551: live.fate[r].realreg=bestreg;
1552: live.fate[r].realind=live.fat[bestreg].nholds;
1553: live.fat[bestreg].touched=touchcnt++;
1554: live.fat[bestreg].holds[live.fat[bestreg].nholds]=r;
1555: live.fat[bestreg].nholds++;
1556:
1557: return bestreg;
1558: }
1559:
1560: static void f_unlock(int r)
1561: {
1562: Dif (!live.fat[r].locked)
1563: jit_abort (L"unlock %d", r);
1564: live.fat[r].locked--;
1565: }
1566:
1567: static void f_setlock(int r)
1568: {
1569: live.fat[r].locked++;
1570: }
1571:
1572: STATIC_INLINE int f_readreg(int r)
1573: {
1574: int n;
1575: int answer=-1;
1576:
1577: if (f_isinreg(r)) {
1578: n=live.fate[r].realreg;
1579: answer=n;
1580: }
1581: /* either the value was in memory to start with, or it was evicted and
1582: is in memory now */
1583: if (answer<0)
1584: answer=f_alloc_reg(r,0);
1585:
1586: live.fat[answer].locked++;
1587: live.fat[answer].touched=touchcnt++;
1588: return answer;
1589: }
1590:
1591: STATIC_INLINE void f_make_exclusive(int r, int clobber)
1592: {
1593: freg_status oldstate;
1594: int rr=live.fate[r].realreg;
1595: int nr;
1596: int nind;
1597: int ndirt=0;
1598: int i;
1599:
1600: if (!f_isinreg(r))
1601: return;
1602: if (live.fat[rr].nholds==1)
1603: return;
1604: for (i=0;i<live.fat[rr].nholds;i++) {
1605: int vr=live.fat[rr].holds[i];
1606: if (vr!=r && live.fate[vr].status==DIRTY)
1607: ndirt++;
1608: }
1609: if (!ndirt && !live.fat[rr].locked) {
1610: /* Everything else is clean, so let's keep this register */
1611: for (i=0;i<live.fat[rr].nholds;i++) {
1612: int vr=live.fat[rr].holds[i];
1613: if (vr!=r) {
1614: f_evict(vr);
1615: i--; /* Try that index again! */
1616: }
1617: }
1618: Dif (live.fat[rr].nholds!=1) {
1619: write_log (L"JIT: realreg %d holds %d (",rr,live.fat[rr].nholds);
1620: for (i=0;i<live.fat[rr].nholds;i++) {
1621: write_log (L"JIT: %d(%d,%d)",live.fat[rr].holds[i],
1622: live.fate[live.fat[rr].holds[i]].realreg,
1623: live.fate[live.fat[rr].holds[i]].realind);
1624: }
1625: write_log (L"\n");
1626: jit_abort (L"x");
1627: }
1628: return;
1629: }
1630:
1631: /* We have to split the register */
1632: oldstate=live.fate[r];
1633:
1634: f_setlock(rr); /* Make sure this doesn't go away */
1635: /* Forget about r being in the register rr */
1636: f_disassociate(r);
1637: /* Get a new register, that we will clobber completely */
1638: nr=f_alloc_reg(r,1);
1639: nind=live.fate[r].realind;
1640: if (!clobber)
1641: raw_fmov_rr(nr,rr); /* Make another copy */
1642: live.fate[r]=oldstate; /* Keep all the old state info */
1643: live.fate[r].realreg=nr;
1644: live.fate[r].realind=nind;
1645: f_unlock(rr);
1646: }
1647:
1648:
1649: STATIC_INLINE int f_writereg(int r)
1650: {
1651: int n;
1652: int answer=-1;
1653:
1654: f_make_exclusive(r,1);
1655: if (f_isinreg(r)) {
1656: n=live.fate[r].realreg;
1657: answer=n;
1658: }
1659: if (answer<0) {
1660: answer=f_alloc_reg(r,1);
1661: }
1662: live.fate[r].status=DIRTY;
1663: live.fat[answer].locked++;
1664: live.fat[answer].touched=touchcnt++;
1665: return answer;
1666: }
1667:
1668: static int f_rmw(int r)
1669: {
1670: int n;
1671:
1672: f_make_exclusive(r,0);
1673: if (f_isinreg(r)) {
1674: n=live.fate[r].realreg;
1675: }
1676: else
1677: n=f_alloc_reg(r,0);
1678: live.fate[r].status=DIRTY;
1679: live.fat[n].locked++;
1680: live.fat[n].touched=touchcnt++;
1681: return n;
1682: }
1683:
1684: static void fflags_into_flags_internal(uae_u32 tmp)
1685: {
1686: int r;
1687:
1688: clobber_flags();
1689: r=f_readreg(FP_RESULT);
1690: raw_fflags_into_flags(r);
1691: f_unlock(r);
1692: }
1693:
1694:
1695:
1696:
1697: /********************************************************************
1698: * CPU functions exposed to gencomp. Both CREATE and EMIT time *
1699: ********************************************************************/
1700:
1701: /*
1702: * RULES FOR HANDLING REGISTERS:
1703: *
1704: * * In the function headers, order the parameters
1705: * - 1st registers written to
1706: * - 2nd read/modify/write registers
1707: * - 3rd registers read from
1708: * * Before calling raw_*, you must call readreg, writereg or rmw for
1709: * each register
1710: * * The order for this is
1711: * - 1st call remove_offset for all registers written to with size<4
1712: * - 2nd call readreg for all registers read without offset
1713: * - 3rd call rmw for all rmw registers
1714: * - 4th call readreg_offset for all registers that can handle offsets
1715: * - 5th call get_offset for all the registers from the previous step
1716: * - 6th call writereg for all written-to registers
1717: * - 7th call raw_*
1718: * - 8th unlock all registers that were locked
1719: */
1720:
1721: MIDFUNC(0,live_flags,(void))
1722: {
1723: live.flags_on_stack=TRASH;
1724: live.flags_in_flags=VALID;
1725: live.flags_are_important=1;
1726: }
1727: MENDFUNC(0,live_flags,(void))
1728:
1729: MIDFUNC(0,dont_care_flags,(void))
1730: {
1731: live.flags_are_important=0;
1732: }
1733: MENDFUNC(0,dont_care_flags,(void))
1734:
1735:
1736: /*
1737: * Copy m68k C flag into m68k X flag
1738: *
1739: * FIXME: This needs to be moved into the machdep
1740: * part of the source because it depends on what bit
1741: * is used to hold X.
1742: */
1743: MIDFUNC(0,duplicate_carry,(void))
1744: {
1745: evict(FLAGX);
1746: make_flags_live_internal();
1747: COMPCALL(setcc_m)((uae_u32)live.state[FLAGX].mem + 1,2);
1748: }
1749: MENDFUNC(0,duplicate_carry,(void))
1750:
1751: /*
1752: * Set host C flag from m68k X flag.
1753: *
1754: * FIXME: This needs to be moved into the machdep
1755: * part of the source because it depends on what bit
1756: * is used to hold X.
1757: */
1758: MIDFUNC(0,restore_carry,(void))
1759: {
1760: if (!have_rat_stall) { /* Not a P6 core, i.e. no partial stalls */
1761: bt_l_ri_noclobber(FLAGX, 8);
1762: }
1763: else { /* Avoid the stall the above creates.
1764: This is slow on non-P6, though.
1765: */
1766: COMPCALL(rol_w_ri(FLAGX, 8));
1767: isclean(FLAGX);
1768: /* Why is the above faster than the below? */
1769: //raw_rol_b_mi((uae_u32)live.state[FLAGX].mem,8);
1770: }
1771: }
1772: MENDFUNC(0,restore_carry,(void))
1773:
1774: MIDFUNC(0,start_needflags,(void))
1775: {
1776: needflags=1;
1777: }
1778: MENDFUNC(0,start_needflags,(void))
1779:
1780: MIDFUNC(0,end_needflags,(void))
1781: {
1782: needflags=0;
1783: }
1784: MENDFUNC(0,end_needflags,(void))
1785:
1786: MIDFUNC(0,make_flags_live,(void))
1787: {
1788: make_flags_live_internal();
1789: }
1790: MENDFUNC(0,make_flags_live,(void))
1791:
1792: MIDFUNC(1,fflags_into_flags,(W2 tmp))
1793: {
1794: clobber_flags();
1795: fflags_into_flags_internal(tmp);
1796: }
1797: MENDFUNC(1,fflags_into_flags,(W2 tmp))
1798:
1799:
1800: MIDFUNC(2,bt_l_ri,(R4 r, IMM i)) /* This is defined as only affecting C */
1801: {
1802: int size=4;
1803: if (i<16)
1804: size=2;
1805: CLOBBER_BT;
1806: r=readreg(r,size);
1807: raw_bt_l_ri(r,i);
1808: unlock(r);
1809: }
1810: MENDFUNC(2,bt_l_ri,(R4 r, IMM i)) /* This is defined as only affecting C */
1811:
1812: MIDFUNC(2,bt_l_rr,(R4 r, R4 b)) /* This is defined as only affecting C */
1813: {
1814: CLOBBER_BT;
1815: r=readreg(r,4);
1816: b=readreg(b,4);
1817: raw_bt_l_rr(r,b);
1818: unlock(r);
1819: unlock(b);
1820: }
1821: MENDFUNC(2,bt_l_rr,(R4 r, R4 b)) /* This is defined as only affecting C */
1822:
1823: MIDFUNC(2,btc_l_ri,(RW4 r, IMM i))
1824: {
1825: int size=4;
1826: if (i<16)
1827: size=2;
1828: CLOBBER_BT;
1829: r=rmw(r,size,size);
1830: raw_btc_l_ri(r,i);
1831: unlock(r);
1832: }
1833: MENDFUNC(2,btc_l_ri,(RW4 r, IMM i))
1834:
1835: MIDFUNC(2,btc_l_rr,(RW4 r, R4 b))
1836: {
1837: CLOBBER_BT;
1838: b=readreg(b,4);
1839: r=rmw(r,4,4);
1840: raw_btc_l_rr(r,b);
1841: unlock(r);
1842: unlock(b);
1843: }
1844: MENDFUNC(2,btc_l_rr,(RW4 r, R4 b))
1845:
1846:
1847: MIDFUNC(2,btr_l_ri,(RW4 r, IMM i))
1848: {
1849: int size=4;
1850: if (i<16)
1851: size=2;
1852: CLOBBER_BT;
1853: r=rmw(r,size,size);
1854: raw_btr_l_ri(r,i);
1855: unlock(r);
1856: }
1857: MENDFUNC(2,btr_l_ri,(RW4 r, IMM i))
1858:
1859: MIDFUNC(2,btr_l_rr,(RW4 r, R4 b))
1860: {
1861: CLOBBER_BT;
1862: b=readreg(b,4);
1863: r=rmw(r,4,4);
1864: raw_btr_l_rr(r,b);
1865: unlock(r);
1866: unlock(b);
1867: }
1868: MENDFUNC(2,btr_l_rr,(RW4 r, R4 b))
1869:
1870:
1871: MIDFUNC(2,bts_l_ri,(RW4 r, IMM i))
1872: {
1873: int size=4;
1874: if (i<16)
1875: size=2;
1876: CLOBBER_BT;
1877: r=rmw(r,size,size);
1878: raw_bts_l_ri(r,i);
1879: unlock(r);
1880: }
1881: MENDFUNC(2,bts_l_ri,(RW4 r, IMM i))
1882:
1883: MIDFUNC(2,bts_l_rr,(RW4 r, R4 b))
1884: {
1885: CLOBBER_BT;
1886: b=readreg(b,4);
1887: r=rmw(r,4,4);
1888: raw_bts_l_rr(r,b);
1889: unlock(r);
1890: unlock(b);
1891: }
1892: MENDFUNC(2,bts_l_rr,(RW4 r, R4 b))
1893:
1894: MIDFUNC(2,mov_l_rm,(W4 d, IMM s))
1895: {
1896: CLOBBER_MOV;
1897: d=writereg(d,4);
1898: raw_mov_l_rm(d,s);
1899: unlock(d);
1900: }
1901: MENDFUNC(2,mov_l_rm,(W4 d, IMM s))
1902:
1903:
1904: MIDFUNC(1,call_r,(R4 r)) /* Clobbering is implicit */
1905: {
1906: r=readreg(r,4);
1907: raw_call_r(r);
1908: unlock(r);
1909: }
1910: MENDFUNC(1,call_r,(R4 r)) /* Clobbering is implicit */
1911:
1912: MIDFUNC(2,sub_l_mi,(IMM d, IMM s))
1913: {
1914: CLOBBER_SUB;
1915: raw_sub_l_mi(d,s) ;
1916: }
1917: MENDFUNC(2,sub_l_mi,(IMM d, IMM s))
1918:
1919: MIDFUNC(2,mov_l_mi,(IMM d, IMM s))
1920: {
1921: CLOBBER_MOV;
1922: raw_mov_l_mi(d,s) ;
1923: }
1924: MENDFUNC(2,mov_l_mi,(IMM d, IMM s))
1925:
1926: MIDFUNC(2,mov_w_mi,(IMM d, IMM s))
1927: {
1928: CLOBBER_MOV;
1929: raw_mov_w_mi(d,s) ;
1930: }
1931: MENDFUNC(2,mov_w_mi,(IMM d, IMM s))
1932:
1933: MIDFUNC(2,mov_b_mi,(IMM d, IMM s))
1934: {
1935: CLOBBER_MOV;
1936: raw_mov_b_mi(d,s) ;
1937: }
1938: MENDFUNC(2,mov_b_mi,(IMM d, IMM s))
1939:
1940: MIDFUNC(2,rol_b_ri,(RW1 r, IMM i))
1941: {
1942: if (!i && !needflags)
1943: return;
1944: CLOBBER_ROL;
1945: r=rmw(r,1,1);
1946: raw_rol_b_ri(r,i);
1947: unlock(r);
1948: }
1949: MENDFUNC(2,rol_b_ri,(RW1 r, IMM i))
1950:
1951: MIDFUNC(2,rol_w_ri,(RW2 r, IMM i))
1952: {
1953: if (!i && !needflags)
1954: return;
1955: CLOBBER_ROL;
1956: r=rmw(r,2,2);
1957: raw_rol_w_ri(r,i);
1958: unlock(r);
1959: }
1960: MENDFUNC(2,rol_w_ri,(RW2 r, IMM i))
1961:
1962: MIDFUNC(2,rol_l_ri,(RW4 r, IMM i))
1963: {
1964: if (!i && !needflags)
1965: return;
1966: CLOBBER_ROL;
1967: r=rmw(r,4,4);
1968: raw_rol_l_ri(r,i);
1969: unlock(r);
1970: }
1971: MENDFUNC(2,rol_l_ri,(RW4 r, IMM i))
1972:
1973: MIDFUNC(2,rol_l_rr,(RW4 d, R1 r))
1974: {
1975: if (isconst(r)) {
1976: COMPCALL(rol_l_ri)(d,(uae_u8)live.state[r].val);
1977: return;
1978: }
1979: CLOBBER_ROL;
1980: r=readreg_specific(r,1,SHIFTCOUNT_NREG);
1981: d=rmw(d,4,4);
1982: Dif (r!=1) {
1983: jit_abort (L"JIT: Illegal register %d in raw_rol_b\n",r);
1984: }
1985: raw_rol_l_rr(d,r) ;
1986: unlock(r);
1987: unlock(d);
1988: }
1989: MENDFUNC(2,rol_l_rr,(RW4 d, R1 r))
1990:
1991: MIDFUNC(2,rol_w_rr,(RW2 d, R1 r))
1992: { /* Can only do this with r==1, i.e. cl */
1993:
1994: if (isconst(r)) {
1995: COMPCALL(rol_w_ri)(d,(uae_u8)live.state[r].val);
1996: return;
1997: }
1998: CLOBBER_ROL;
1999: r=readreg_specific(r,1,SHIFTCOUNT_NREG);
2000: d=rmw(d,2,2);
2001: Dif (r!=1) {
2002: jit_abort (L"JIT: Illegal register %d in raw_rol_b\n",r);
2003: }
2004: raw_rol_w_rr(d,r) ;
2005: unlock(r);
2006: unlock(d);
2007: }
2008: MENDFUNC(2,rol_w_rr,(RW2 d, R1 r))
2009:
2010: MIDFUNC(2,rol_b_rr,(RW1 d, R1 r))
2011: { /* Can only do this with r==1, i.e. cl */
2012:
2013: if (isconst(r)) {
2014: COMPCALL(rol_b_ri)(d,(uae_u8)live.state[r].val);
2015: return;
2016: }
2017:
2018: CLOBBER_ROL;
2019: r=readreg_specific(r,1,SHIFTCOUNT_NREG);
2020: d=rmw(d,1,1);
2021: Dif (r!=1) {
2022: jit_abort (L"JIT: Illegal register %d in raw_rol_b\n",r);
2023: }
2024: raw_rol_b_rr(d,r) ;
2025: unlock(r);
2026: unlock(d);
2027: }
2028: MENDFUNC(2,rol_b_rr,(RW1 d, R1 r))
2029:
2030:
2031: MIDFUNC(2,shll_l_rr,(RW4 d, R1 r))
2032: {
2033: if (isconst(r)) {
2034: COMPCALL(shll_l_ri)(d,(uae_u8)live.state[r].val);
2035: return;
2036: }
2037: CLOBBER_SHLL;
2038: r=readreg_specific(r,1,SHIFTCOUNT_NREG);
2039: d=rmw(d,4,4);
2040: Dif (r!=1) {
2041: jit_abort (L"JIT: Illegal register %d in raw_rol_b\n",r);
2042: }
2043: raw_shll_l_rr(d,r) ;
2044: unlock(r);
2045: unlock(d);
2046: }
2047: MENDFUNC(2,shll_l_rr,(RW4 d, R1 r))
2048:
2049: MIDFUNC(2,shll_w_rr,(RW2 d, R1 r))
2050: { /* Can only do this with r==1, i.e. cl */
2051:
2052: if (isconst(r)) {
2053: COMPCALL(shll_w_ri)(d,(uae_u8)live.state[r].val);
2054: return;
2055: }
2056: CLOBBER_SHLL;
2057: r=readreg_specific(r,1,SHIFTCOUNT_NREG);
2058: d=rmw(d,2,2);
2059: Dif (r!=1) {
2060: jit_abort (L"JIT: Illegal register %d in raw_shll_b\n",r);
2061: }
2062: raw_shll_w_rr(d,r) ;
2063: unlock(r);
2064: unlock(d);
2065: }
2066: MENDFUNC(2,shll_w_rr,(RW2 d, R1 r))
2067:
2068: MIDFUNC(2,shll_b_rr,(RW1 d, R1 r))
2069: { /* Can only do this with r==1, i.e. cl */
2070:
2071: if (isconst(r)) {
2072: COMPCALL(shll_b_ri)(d,(uae_u8)live.state[r].val);
2073: return;
2074: }
2075:
2076: CLOBBER_SHLL;
2077: r=readreg_specific(r,1,SHIFTCOUNT_NREG);
2078: d=rmw(d,1,1);
2079: Dif (r!=1) {
2080: jit_abort (L"JIT: Illegal register %d in raw_shll_b\n",r);
2081: }
2082: raw_shll_b_rr(d,r) ;
2083: unlock(r);
2084: unlock(d);
2085: }
2086: MENDFUNC(2,shll_b_rr,(RW1 d, R1 r))
2087:
2088:
2089: MIDFUNC(2,ror_b_ri,(R1 r, IMM i))
2090: {
2091: if (!i && !needflags)
2092: return;
2093: CLOBBER_ROR;
2094: r=rmw(r,1,1);
2095: raw_ror_b_ri(r,i);
2096: unlock(r);
2097: }
2098: MENDFUNC(2,ror_b_ri,(R1 r, IMM i))
2099:
2100: MIDFUNC(2,ror_w_ri,(R2 r, IMM i))
2101: {
2102: if (!i && !needflags)
2103: return;
2104: CLOBBER_ROR;
2105: r=rmw(r,2,2);
2106: raw_ror_w_ri(r,i);
2107: unlock(r);
2108: }
2109: MENDFUNC(2,ror_w_ri,(R2 r, IMM i))
2110:
2111: MIDFUNC(2,ror_l_ri,(R4 r, IMM i))
2112: {
2113: if (!i && !needflags)
2114: return;
2115: CLOBBER_ROR;
2116: r=rmw(r,4,4);
2117: raw_ror_l_ri(r,i);
2118: unlock(r);
2119: }
2120: MENDFUNC(2,ror_l_ri,(R4 r, IMM i))
2121:
2122: MIDFUNC(2,ror_l_rr,(R4 d, R1 r))
2123: {
2124: if (isconst(r)) {
2125: COMPCALL(ror_l_ri)(d,(uae_u8)live.state[r].val);
2126: return;
2127: }
2128: CLOBBER_ROR;
2129: r=readreg_specific(r,1,SHIFTCOUNT_NREG);
2130: d=rmw(d,4,4);
2131: raw_ror_l_rr(d,r) ;
2132: unlock(r);
2133: unlock(d);
2134: }
2135: MENDFUNC(2,ror_l_rr,(R4 d, R1 r))
2136:
2137: MIDFUNC(2,ror_w_rr,(R2 d, R1 r))
2138: {
2139: if (isconst(r)) {
2140: COMPCALL(ror_w_ri)(d,(uae_u8)live.state[r].val);
2141: return;
2142: }
2143: CLOBBER_ROR;
2144: r=readreg_specific(r,1,SHIFTCOUNT_NREG);
2145: d=rmw(d,2,2);
2146: raw_ror_w_rr(d,r) ;
2147: unlock(r);
2148: unlock(d);
2149: }
2150: MENDFUNC(2,ror_w_rr,(R2 d, R1 r))
2151:
2152: MIDFUNC(2,ror_b_rr,(R1 d, R1 r))
2153: {
2154: if (isconst(r)) {
2155: COMPCALL(ror_b_ri)(d,(uae_u8)live.state[r].val);
2156: return;
2157: }
2158:
2159: CLOBBER_ROR;
2160: r=readreg_specific(r,1,SHIFTCOUNT_NREG);
2161: d=rmw(d,1,1);
2162: raw_ror_b_rr(d,r) ;
2163: unlock(r);
2164: unlock(d);
2165: }
2166: MENDFUNC(2,ror_b_rr,(R1 d, R1 r))
2167:
2168: MIDFUNC(2,shrl_l_rr,(RW4 d, R1 r))
2169: {
2170: if (isconst(r)) {
2171: COMPCALL(shrl_l_ri)(d,(uae_u8)live.state[r].val);
2172: return;
2173: }
2174: CLOBBER_SHRL;
2175: r=readreg_specific(r,1,SHIFTCOUNT_NREG);
2176: d=rmw(d,4,4);
2177: Dif (r!=1) {
2178: jit_abort (L"JIT: Illegal register %d in raw_rol_b\n",r);
2179: }
2180: raw_shrl_l_rr(d,r) ;
2181: unlock(r);
2182: unlock(d);
2183: }
2184: MENDFUNC(2,shrl_l_rr,(RW4 d, R1 r))
2185:
2186: MIDFUNC(2,shrl_w_rr,(RW2 d, R1 r))
2187: { /* Can only do this with r==1, i.e. cl */
2188:
2189: if (isconst(r)) {
2190: COMPCALL(shrl_w_ri)(d,(uae_u8)live.state[r].val);
2191: return;
2192: }
2193: CLOBBER_SHRL;
2194: r=readreg_specific(r,1,SHIFTCOUNT_NREG);
2195: d=rmw(d,2,2);
2196: Dif (r!=1) {
2197: jit_abort (L"JIT: Illegal register %d in raw_shrl_b\n",r);
2198: }
2199: raw_shrl_w_rr(d,r) ;
2200: unlock(r);
2201: unlock(d);
2202: }
2203: MENDFUNC(2,shrl_w_rr,(RW2 d, R1 r))
2204:
2205: MIDFUNC(2,shrl_b_rr,(RW1 d, R1 r))
2206: { /* Can only do this with r==1, i.e. cl */
2207:
2208: if (isconst(r)) {
2209: COMPCALL(shrl_b_ri)(d,(uae_u8)live.state[r].val);
2210: return;
2211: }
2212:
2213: CLOBBER_SHRL;
2214: r=readreg_specific(r,1,SHIFTCOUNT_NREG);
2215: d=rmw(d,1,1);
2216: Dif (r!=1) {
2217: jit_abort (L"JIT: Illegal register %d in raw_shrl_b\n",r);
2218: }
2219: raw_shrl_b_rr(d,r) ;
2220: unlock(r);
2221: unlock(d);
2222: }
2223: MENDFUNC(2,shrl_b_rr,(RW1 d, R1 r))
2224:
2225: MIDFUNC(2,shll_l_ri,(RW4 r, IMM i))
2226: {
2227: if (!i && !needflags)
2228: return;
2229: if (isconst(r) && !needflags) {
2230: live.state[r].val<<=i;
2231: return;
2232: }
2233: CLOBBER_SHLL;
2234: r=rmw(r,4,4);
2235: raw_shll_l_ri(r,i);
2236: unlock(r);
2237: }
2238: MENDFUNC(2,shll_l_ri,(RW4 r, IMM i))
2239:
2240: MIDFUNC(2,shll_w_ri,(RW2 r, IMM i))
2241: {
2242: if (!i && !needflags)
2243: return;
2244: CLOBBER_SHLL;
2245: r=rmw(r,2,2);
2246: raw_shll_w_ri(r,i);
2247: unlock(r);
2248: }
2249: MENDFUNC(2,shll_w_ri,(RW2 r, IMM i))
2250:
2251: MIDFUNC(2,shll_b_ri,(RW1 r, IMM i))
2252: {
2253: if (!i && !needflags)
2254: return;
2255: CLOBBER_SHLL;
2256: r=rmw(r,1,1);
2257: raw_shll_b_ri(r,i);
2258: unlock(r);
2259: }
2260: MENDFUNC(2,shll_b_ri,(RW1 r, IMM i))
2261:
2262: MIDFUNC(2,shrl_l_ri,(RW4 r, IMM i))
2263: {
2264: if (!i && !needflags)
2265: return;
2266: if (isconst(r) && !needflags) {
2267: live.state[r].val>>=i;
2268: return;
2269: }
2270: CLOBBER_SHRL;
2271: r=rmw(r,4,4);
2272: raw_shrl_l_ri(r,i);
2273: unlock(r);
2274: }
2275: MENDFUNC(2,shrl_l_ri,(RW4 r, IMM i))
2276:
2277: MIDFUNC(2,shrl_w_ri,(RW2 r, IMM i))
2278: {
2279: if (!i && !needflags)
2280: return;
2281: CLOBBER_SHRL;
2282: r=rmw(r,2,2);
2283: raw_shrl_w_ri(r,i);
2284: unlock(r);
2285: }
2286: MENDFUNC(2,shrl_w_ri,(RW2 r, IMM i))
2287:
2288: MIDFUNC(2,shrl_b_ri,(RW1 r, IMM i))
2289: {
2290: if (!i && !needflags)
2291: return;
2292: CLOBBER_SHRL;
2293: r=rmw(r,1,1);
2294: raw_shrl_b_ri(r,i);
2295: unlock(r);
2296: }
2297: MENDFUNC(2,shrl_b_ri,(RW1 r, IMM i))
2298:
2299: MIDFUNC(2,shra_l_ri,(RW4 r, IMM i))
2300: {
2301: if (!i && !needflags)
2302: return;
2303: CLOBBER_SHRA;
2304: r=rmw(r,4,4);
2305: raw_shra_l_ri(r,i);
2306: unlock(r);
2307: }
2308: MENDFUNC(2,shra_l_ri,(RW4 r, IMM i))
2309:
2310: MIDFUNC(2,shra_w_ri,(RW2 r, IMM i))
2311: {
2312: if (!i && !needflags)
2313: return;
2314: CLOBBER_SHRA;
2315: r=rmw(r,2,2);
2316: raw_shra_w_ri(r,i);
2317: unlock(r);
2318: }
2319: MENDFUNC(2,shra_w_ri,(RW2 r, IMM i))
2320:
2321: MIDFUNC(2,shra_b_ri,(RW1 r, IMM i))
2322: {
2323: if (!i && !needflags)
2324: return;
2325: CLOBBER_SHRA;
2326: r=rmw(r,1,1);
2327: raw_shra_b_ri(r,i);
2328: unlock(r);
2329: }
2330: MENDFUNC(2,shra_b_ri,(RW1 r, IMM i))
2331:
2332: MIDFUNC(2,shra_l_rr,(RW4 d, R1 r))
2333: {
2334: if (isconst(r)) {
2335: COMPCALL(shra_l_ri)(d,(uae_u8)live.state[r].val);
2336: return;
2337: }
2338: CLOBBER_SHRA;
2339: r=readreg_specific(r,1,SHIFTCOUNT_NREG);
2340: d=rmw(d,4,4);
2341: Dif (r!=1) {
2342: jit_abort (L"JIT: Illegal register %d in raw_rol_b\n",r);
2343: }
2344: raw_shra_l_rr(d,r) ;
2345: unlock(r);
2346: unlock(d);
2347: }
2348: MENDFUNC(2,shra_l_rr,(RW4 d, R1 r))
2349:
2350: MIDFUNC(2,shra_w_rr,(RW2 d, R1 r))
2351: { /* Can only do this with r==1, i.e. cl */
2352:
2353: if (isconst(r)) {
2354: COMPCALL(shra_w_ri)(d,(uae_u8)live.state[r].val);
2355: return;
2356: }
2357: CLOBBER_SHRA;
2358: r=readreg_specific(r,1,SHIFTCOUNT_NREG);
2359: d=rmw(d,2,2);
2360: Dif (r!=1) {
2361: jit_abort (L"JIT: Illegal register %d in raw_shra_b\n",r);
2362: }
2363: raw_shra_w_rr(d,r) ;
2364: unlock(r);
2365: unlock(d);
2366: }
2367: MENDFUNC(2,shra_w_rr,(RW2 d, R1 r))
2368:
2369: MIDFUNC(2,shra_b_rr,(RW1 d, R1 r))
2370: { /* Can only do this with r==1, i.e. cl */
2371:
2372: if (isconst(r)) {
2373: COMPCALL(shra_b_ri)(d,(uae_u8)live.state[r].val);
2374: return;
2375: }
2376:
2377: CLOBBER_SHRA;
2378: r=readreg_specific(r,1,SHIFTCOUNT_NREG);
2379: d=rmw(d,1,1);
2380: Dif (r!=1) {
2381: jit_abort (L"JIT: Illegal register %d in raw_shra_b\n",r);
2382: }
2383: raw_shra_b_rr(d,r) ;
2384: unlock(r);
2385: unlock(d);
2386: }
2387: MENDFUNC(2,shra_b_rr,(RW1 d, R1 r))
2388:
2389: MIDFUNC(2,setcc,(W1 d, IMM cc))
2390: {
2391: CLOBBER_SETCC;
2392: d=writereg(d,1);
2393: raw_setcc(d,cc);
2394: unlock(d);
2395: }
2396: MENDFUNC(2,setcc,(W1 d, IMM cc))
2397:
2398: MIDFUNC(2,setcc_m,(IMM d, IMM cc))
2399: {
2400: CLOBBER_SETCC;
2401: raw_setcc_m(d,cc);
2402: }
2403: MENDFUNC(2,setcc_m,(IMM d, IMM cc))
2404:
2405: MIDFUNC(3,cmov_b_rr,(RW1 d, R1 s, IMM cc))
2406: {
2407: if (d==s)
2408: return;
2409: CLOBBER_CMOV;
2410: s=readreg(s,1);
2411: d=rmw(d,1,1);
2412: raw_cmov_b_rr(d,s,cc);
2413: unlock(s);
2414: unlock(d);
2415: }
2416: MENDFUNC(3,cmov_b_rr,(RW1 d, R1 s, IMM cc))
2417:
2418: MIDFUNC(3,cmov_w_rr,(RW2 d, R2 s, IMM cc))
2419: {
2420: if (d==s)
2421: return;
2422: CLOBBER_CMOV;
2423: s=readreg(s,2);
2424: d=rmw(d,2,2);
2425: raw_cmov_w_rr(d,s,cc);
2426: unlock(s);
2427: unlock(d);
2428: }
2429: MENDFUNC(3,cmov_w_rr,(RW2 d, R2 s, IMM cc))
2430:
2431: MIDFUNC(3,cmov_l_rr,(RW4 d, R4 s, IMM cc))
2432: {
2433: if (d==s)
2434: return;
2435: CLOBBER_CMOV;
2436: s=readreg(s,4);
2437: d=rmw(d,4,4);
2438: raw_cmov_l_rr(d,s,cc);
2439: unlock(s);
2440: unlock(d);
2441: }
2442: MENDFUNC(3,cmov_l_rr,(RW4 d, R4 s, IMM cc))
2443:
2444: MIDFUNC(1,setzflg_l,(RW4 r))
2445: {
2446: if (setzflg_uses_bsf) {
2447: CLOBBER_BSF;
2448: r=rmw(r,4,4);
2449: raw_bsf_l_rr(r,r);
2450: unlock(r);
2451: }
2452: else {
2453: Dif (live.flags_in_flags!=VALID) {
2454: jit_abort (L"JIT: setzflg() wanted flags in native flags, they are %d\n",
2455: live.flags_in_flags);
2456: }
2457: r=readreg(r,4);
2458: {
2459: int f=writereg(S11,4);
2460: int t=writereg(S12,4);
2461: raw_flags_set_zero(f,r,t);
2462: unlock(f);
2463: unlock(r);
2464: unlock(t);
2465: }
2466: }
2467: }
2468: MENDFUNC(1,setzflg_l,(RW4 r))
2469:
2470: MIDFUNC(3,cmov_l_rm,(RW4 d, IMM s, IMM cc))
2471: {
2472: CLOBBER_CMOV;
2473: d=rmw(d,4,4);
2474: raw_cmov_l_rm(d,s,cc);
2475: unlock(d);
2476: }
2477: MENDFUNC(3,cmov_l_rm,(RW4 d, IMM s, IMM cc))
2478:
2479: MIDFUNC(2,bsf_l_rr,(W4 d, R4 s))
2480: {
2481: CLOBBER_BSF;
2482: s=readreg(s,4);
2483: d=writereg(d,4);
2484: raw_bsf_l_rr(d,s);
2485: unlock(s);
2486: unlock(d);
2487: }
2488: MENDFUNC(2,bsf_l_rr,(W4 d, R4 s))
2489:
2490: MIDFUNC(2,imul_32_32,(RW4 d, R4 s))
2491: {
2492: CLOBBER_MUL;
2493: s=readreg(s,4);
2494: d=rmw(d,4,4);
2495: raw_imul_32_32(d,s);
2496: unlock(s);
2497: unlock(d);
2498: }
2499: MENDFUNC(2,imul_32_32,(RW4 d, R4 s))
2500:
2501: MIDFUNC(2,imul_64_32,(RW4 d, RW4 s))
2502: {
2503: CLOBBER_MUL;
2504: s=rmw_specific(s,4,4,MUL_NREG2);
2505: d=rmw_specific(d,4,4,MUL_NREG1);
2506: raw_imul_64_32(d,s);
2507: unlock(s);
2508: unlock(d);
2509: }
2510: MENDFUNC(2,imul_64_32,(RW4 d, RW4 s))
2511:
2512: MIDFUNC(2,mul_64_32,(RW4 d, RW4 s))
2513: {
2514: CLOBBER_MUL;
2515: s=rmw_specific(s,4,4,MUL_NREG2);
2516: d=rmw_specific(d,4,4,MUL_NREG1);
2517: raw_mul_64_32(d,s);
2518: unlock(s);
2519: unlock(d);
2520: }
2521: MENDFUNC(2,mul_64_32,(RW4 d, RW4 s))
2522:
2523: MIDFUNC(2,sign_extend_16_rr,(W4 d, R2 s))
2524: {
2525: int isrmw;
2526:
2527: if (isconst(s)) {
2528: set_const(d,(uae_s32)(uae_s16)live.state[s].val);
2529: return;
2530: }
2531:
2532: CLOBBER_SE16;
2533: isrmw=(s==d);
2534: if (!isrmw) {
2535: s=readreg(s,2);
2536: d=writereg(d,4);
2537: }
2538: else { /* If we try to lock this twice, with different sizes, we
2539: are int trouble! */
2540: s=d=rmw(s,4,2);
2541: }
2542: raw_sign_extend_16_rr(d,s);
2543: if (!isrmw) {
2544: unlock(d);
2545: unlock(s);
2546: }
2547: else {
2548: unlock(s);
2549: }
2550: }
2551: MENDFUNC(2,sign_extend_16_rr,(W4 d, R2 s))
2552:
2553: MIDFUNC(2,sign_extend_8_rr,(W4 d, R1 s))
2554: {
2555: int isrmw;
2556:
2557: if (isconst(s)) {
2558: set_const(d,(uae_s32)(uae_s8)live.state[s].val);
2559: return;
2560: }
2561:
2562: isrmw=(s==d);
2563: CLOBBER_SE8;
2564: if (!isrmw) {
2565: s=readreg(s,1);
2566: d=writereg(d,4);
2567: }
2568: else { /* If we try to lock this twice, with different sizes, we
2569: are int trouble! */
2570: s=d=rmw(s,4,1);
2571: }
2572:
2573: raw_sign_extend_8_rr(d,s);
2574:
2575: if (!isrmw) {
2576: unlock(d);
2577: unlock(s);
2578: }
2579: else {
2580: unlock(s);
2581: }
2582: }
2583: MENDFUNC(2,sign_extend_8_rr,(W4 d, R1 s))
2584:
2585: MIDFUNC(2,zero_extend_16_rr,(W4 d, R2 s))
2586: {
2587: int isrmw;
2588:
2589: if (isconst(s)) {
2590: set_const(d,(uae_u32)(uae_u16)live.state[s].val);
2591: return;
2592: }
2593:
2594: isrmw=(s==d);
2595: CLOBBER_ZE16;
2596: if (!isrmw) {
2597: s=readreg(s,2);
2598: d=writereg(d,4);
2599: }
2600: else { /* If we try to lock this twice, with different sizes, we
2601: are int trouble! */
2602: s=d=rmw(s,4,2);
2603: }
2604: raw_zero_extend_16_rr(d,s);
2605: if (!isrmw) {
2606: unlock(d);
2607: unlock(s);
2608: }
2609: else {
2610: unlock(s);
2611: }
2612: }
2613: MENDFUNC(2,zero_extend_16_rr,(W4 d, R2 s))
2614:
2615: MIDFUNC(2,zero_extend_8_rr,(W4 d, R1 s))
2616: {
2617: int isrmw;
2618: if (isconst(s)) {
2619: set_const(d,(uae_u32)(uae_u8)live.state[s].val);
2620: return;
2621: }
2622:
2623: isrmw=(s==d);
2624: CLOBBER_ZE8;
2625: if (!isrmw) {
2626: s=readreg(s,1);
2627: d=writereg(d,4);
2628: }
2629: else { /* If we try to lock this twice, with different sizes, we
2630: are int trouble! */
2631: s=d=rmw(s,4,1);
2632: }
2633:
2634: raw_zero_extend_8_rr(d,s);
2635:
2636: if (!isrmw) {
2637: unlock(d);
2638: unlock(s);
2639: }
2640: else {
2641: unlock(s);
2642: }
2643: }
2644: MENDFUNC(2,zero_extend_8_rr,(W4 d, R1 s))
2645:
2646: MIDFUNC(2,mov_b_rr,(W1 d, R1 s))
2647: {
2648: if (d==s)
2649: return;
2650: if (isconst(s)) {
2651: COMPCALL(mov_b_ri)(d,(uae_u8)live.state[s].val);
2652: return;
2653: }
2654:
2655: CLOBBER_MOV;
2656: s=readreg(s,1);
2657: d=writereg(d,1);
2658: raw_mov_b_rr(d,s);
2659: unlock(d);
2660: unlock(s);
2661: }
2662: MENDFUNC(2,mov_b_rr,(W1 d, R1 s))
2663:
2664: MIDFUNC(2,mov_w_rr,(W2 d, R2 s))
2665: {
2666: if (d==s)
2667: return;
2668: if (isconst(s)) {
2669: COMPCALL(mov_w_ri)(d,(uae_u16)live.state[s].val);
2670: return;
2671: }
2672:
2673: CLOBBER_MOV;
2674: s=readreg(s,2);
2675: d=writereg(d,2);
2676: raw_mov_w_rr(d,s);
2677: unlock(d);
2678: unlock(s);
2679: }
2680: MENDFUNC(2,mov_w_rr,(W2 d, R2 s))
2681:
2682: MIDFUNC(3,mov_l_rrm_indexed,(W4 d,R4 baser, R4 index))
2683: {
2684: CLOBBER_MOV;
2685: baser=readreg(baser,4);
2686: index=readreg(index,4);
2687: d=writereg(d,4);
2688:
2689: raw_mov_l_rrm_indexed(d,baser,index);
2690: unlock(d);
2691: unlock(baser);
2692: unlock(index);
2693: }
2694: MENDFUNC(3,mov_l_rrm_indexed,(W4 d,R4 baser, R4 index))
2695:
2696: MIDFUNC(3,mov_w_rrm_indexed,(W2 d, R4 baser, R4 index))
2697: {
2698: CLOBBER_MOV;
2699: baser=readreg(baser,4);
2700: index=readreg(index,4);
2701: d=writereg(d,2);
2702:
2703: raw_mov_w_rrm_indexed(d,baser,index);
2704: unlock(d);
2705: unlock(baser);
2706: unlock(index);
2707: }
2708: MENDFUNC(3,mov_w_rrm_indexed,(W2 d, R4 baser, R4 index))
2709:
2710: MIDFUNC(3,mov_b_rrm_indexed,(W1 d, R4 baser, R4 index))
2711: {
2712: CLOBBER_MOV;
2713: baser=readreg(baser,4);
2714: index=readreg(index,4);
2715: d=writereg(d,1);
2716:
2717: raw_mov_b_rrm_indexed(d,baser,index);
2718:
2719: unlock(d);
2720: unlock(baser);
2721: unlock(index);
2722: }
2723: MENDFUNC(3,mov_b_rrm_indexed,(W1 d, R4 baser, R4 index))
2724:
2725: MIDFUNC(3,mov_l_mrr_indexed,(R4 baser, R4 index, R4 s))
2726: {
2727: CLOBBER_MOV;
2728: baser=readreg(baser,4);
2729: index=readreg(index,4);
2730: s=readreg(s,4);
2731:
2732: Dif (baser==s || index==s)
2733: jit_abort (L"mov_l_mrr_indexed");
2734:
2735: raw_mov_l_mrr_indexed(baser,index,s);
2736: unlock(s);
2737: unlock(baser);
2738: unlock(index);
2739: }
2740: MENDFUNC(3,mov_l_mrr_indexed,(R4 baser, R4 index, R4 s))
2741:
2742: MIDFUNC(3,mov_w_mrr_indexed,(R4 baser, R4 index, R2 s))
2743: {
2744: CLOBBER_MOV;
2745: baser=readreg(baser,4);
2746: index=readreg(index,4);
2747: s=readreg(s,2);
2748:
2749: raw_mov_w_mrr_indexed(baser,index,s);
2750: unlock(s);
2751: unlock(baser);
2752: unlock(index);
2753: }
2754: MENDFUNC(3,mov_w_mrr_indexed,(R4 baser, R4 index, R2 s))
2755:
2756: MIDFUNC(3,mov_b_mrr_indexed,(R4 baser, R4 index, R1 s))
2757: {
2758: CLOBBER_MOV;
2759: s=readreg(s,1);
2760: baser=readreg(baser,4);
2761: index=readreg(index,4);
2762:
2763: raw_mov_b_mrr_indexed(baser,index,s);
2764: unlock(s);
2765: unlock(baser);
2766: unlock(index);
2767: }
2768: MENDFUNC(3,mov_b_mrr_indexed,(R4 baser, R4 index, R1 s))
2769:
2770: /* Read a long from base+4*index */
2771: MIDFUNC(3,mov_l_rm_indexed,(W4 d, IMM base, R4 index))
2772: {
2773: int indexreg=index;
2774:
2775: if (isconst(index)) {
2776: COMPCALL(mov_l_rm)(d,base+4*live.state[index].val);
2777: return;
2778: }
2779:
2780: CLOBBER_MOV;
2781: index=readreg_offset(index,4);
2782: base+=get_offset(indexreg)*4;
2783: d=writereg(d,4);
2784:
2785: raw_mov_l_rm_indexed(d,base,index);
2786: unlock(index);
2787: unlock(d);
2788: }
2789: MENDFUNC(3,mov_l_rm_indexed,(W4 d, IMM base, R4 index))
2790:
2791: /* read the long at the address contained in s+offset and store in d */
2792: MIDFUNC(3,mov_l_rR,(W4 d, R4 s, IMM offset))
2793: {
2794: if (isconst(s)) {
2795: COMPCALL(mov_l_rm)(d,live.state[s].val+offset);
2796: return;
2797: }
2798: CLOBBER_MOV;
2799: s=readreg(s,4);
2800: d=writereg(d,4);
2801:
2802: raw_mov_l_rR(d,s,offset);
2803: unlock(d);
2804: unlock(s);
2805: }
2806: MENDFUNC(3,mov_l_rR,(W4 d, R4 s, IMM offset))
2807:
2808: /* read the word at the address contained in s+offset and store in d */
2809: MIDFUNC(3,mov_w_rR,(W2 d, R4 s, IMM offset))
2810: {
2811: if (isconst(s)) {
2812: COMPCALL(mov_w_rm)(d,live.state[s].val+offset);
2813: return;
2814: }
2815: CLOBBER_MOV;
2816: s=readreg(s,4);
2817: d=writereg(d,2);
2818:
2819: raw_mov_w_rR(d,s,offset);
2820: unlock(d);
2821: unlock(s);
2822: }
2823: MENDFUNC(3,mov_w_rR,(W2 d, R4 s, IMM offset))
2824:
2825: /* read the word at the address contained in s+offset and store in d */
2826: MIDFUNC(3,mov_b_rR,(W1 d, R4 s, IMM offset))
2827: {
2828: if (isconst(s)) {
2829: COMPCALL(mov_b_rm)(d,live.state[s].val+offset);
2830: return;
2831: }
2832: CLOBBER_MOV;
2833: s=readreg(s,4);
2834: d=writereg(d,1);
2835:
2836: raw_mov_b_rR(d,s,offset);
2837: unlock(d);
2838: unlock(s);
2839: }
2840: MENDFUNC(3,mov_b_rR,(W1 d, R4 s, IMM offset))
2841:
2842: /* read the long at the address contained in s+offset and store in d */
2843: MIDFUNC(3,mov_l_brR,(W4 d, R4 s, IMM offset))
2844: {
2845: int sreg=s;
2846: if (isconst(s)) {
2847: COMPCALL(mov_l_rm)(d,live.state[s].val+offset);
2848: return;
2849: }
2850: CLOBBER_MOV;
2851: s=readreg_offset(s,4);
2852: offset+=get_offset(sreg);
2853: d=writereg(d,4);
2854:
2855: raw_mov_l_brR(d,s,offset);
2856: unlock(d);
2857: unlock(s);
2858: }
2859: MENDFUNC(3,mov_l_brR,(W4 d, R4 s, IMM offset))
2860:
2861: /* read the word at the address contained in s+offset and store in d */
2862: MIDFUNC(3,mov_w_brR,(W2 d, R4 s, IMM offset))
2863: {
2864: int sreg=s;
2865: if (isconst(s)) {
2866: COMPCALL(mov_w_rm)(d,live.state[s].val+offset);
2867: return;
2868: }
2869: CLOBBER_MOV;
2870: remove_offset(d,-1);
2871: s=readreg_offset(s,4);
2872: offset+=get_offset(sreg);
2873: d=writereg(d,2);
2874:
2875: raw_mov_w_brR(d,s,offset);
2876: unlock(d);
2877: unlock(s);
2878: }
2879: MENDFUNC(3,mov_w_brR,(W2 d, R4 s, IMM offset))
2880:
2881: /* read the word at the address contained in s+offset and store in d */
2882: MIDFUNC(3,mov_b_brR,(W1 d, R4 s, IMM offset))
2883: {
2884: int sreg=s;
2885: if (isconst(s)) {
2886: COMPCALL(mov_b_rm)(d,live.state[s].val+offset);
2887: return;
2888: }
2889: CLOBBER_MOV;
2890: remove_offset(d,-1);
2891: s=readreg_offset(s,4);
2892: offset+=get_offset(sreg);
2893: d=writereg(d,1);
2894:
2895: raw_mov_b_brR(d,s,offset);
2896: unlock(d);
2897: unlock(s);
2898: }
2899: MENDFUNC(3,mov_b_brR,(W1 d, R4 s, IMM offset))
2900:
2901: MIDFUNC(3,mov_l_Ri,(R4 d, IMM i, IMM offset))
2902: {
2903: int dreg=d;
2904: if (isconst(d)) {
2905: COMPCALL(mov_l_mi)(live.state[d].val+offset,i);
2906: return;
2907: }
2908:
2909: CLOBBER_MOV;
2910: d=readreg_offset(d,4);
2911: offset+=get_offset(dreg);
2912: raw_mov_l_Ri(d,i,offset);
2913: unlock(d);
2914: }
2915: MENDFUNC(3,mov_l_Ri,(R4 d, IMM i, IMM offset))
2916:
2917: MIDFUNC(3,mov_w_Ri,(R4 d, IMM i, IMM offset))
2918: {
2919: int dreg=d;
2920: if (isconst(d)) {
2921: COMPCALL(mov_w_mi)(live.state[d].val+offset,i);
2922: return;
2923: }
2924:
2925: CLOBBER_MOV;
2926: d=readreg_offset(d,4);
2927: offset+=get_offset(dreg);
2928: raw_mov_w_Ri(d,i,offset);
2929: unlock(d);
2930: }
2931: MENDFUNC(3,mov_w_Ri,(R4 d, IMM i, IMM offset))
2932:
2933: MIDFUNC(3,mov_b_Ri,(R4 d, IMM i, IMM offset))
2934: {
2935: int dreg=d;
2936: if (isconst(d)) {
2937: COMPCALL(mov_b_mi)(live.state[d].val+offset,i);
2938: return;
2939: }
2940:
2941: CLOBBER_MOV;
2942: d=readreg_offset(d,4);
2943: offset+=get_offset(dreg);
2944: raw_mov_b_Ri(d,i,offset);
2945: unlock(d);
2946: }
2947: MENDFUNC(3,mov_b_Ri,(R4 d, IMM i, IMM offset))
2948:
2949: /* Warning! OFFSET is byte sized only! */
2950: MIDFUNC(3,mov_l_Rr,(R4 d, R4 s, IMM offset))
2951: {
2952: if (isconst(d)) {
2953: COMPCALL(mov_l_mr)(live.state[d].val+offset,s);
2954: return;
2955: }
2956: if (isconst(s)) {
2957: COMPCALL(mov_l_Ri)(d,live.state[s].val,offset);
2958: return;
2959: }
2960:
2961: CLOBBER_MOV;
2962: s=readreg(s,4);
2963: d=readreg(d,4);
2964:
2965: raw_mov_l_Rr(d,s,offset);
2966: unlock(d);
2967: unlock(s);
2968: }
2969: MENDFUNC(3,mov_l_Rr,(R4 d, R4 s, IMM offset))
2970:
2971: MIDFUNC(3,mov_w_Rr,(R4 d, R2 s, IMM offset))
2972: {
2973: if (isconst(d)) {
2974: COMPCALL(mov_w_mr)(live.state[d].val+offset,s);
2975: return;
2976: }
2977: if (isconst(s)) {
2978: COMPCALL(mov_w_Ri)(d,(uae_u16)live.state[s].val,offset);
2979: return;
2980: }
2981:
2982: CLOBBER_MOV;
2983: s=readreg(s,2);
2984: d=readreg(d,4);
2985: raw_mov_w_Rr(d,s,offset);
2986: unlock(d);
2987: unlock(s);
2988: }
2989: MENDFUNC(3,mov_w_Rr,(R4 d, R2 s, IMM offset))
2990:
2991: MIDFUNC(3,mov_b_Rr,(R4 d, R1 s, IMM offset))
2992: {
2993: if (isconst(d)) {
2994: COMPCALL(mov_b_mr)(live.state[d].val+offset,s);
2995: return;
2996: }
2997: if (isconst(s)) {
2998: COMPCALL(mov_b_Ri)(d,(uae_u8)live.state[s].val,offset);
2999: return;
3000: }
3001:
3002: CLOBBER_MOV;
3003: s=readreg(s,1);
3004: d=readreg(d,4);
3005: raw_mov_b_Rr(d,s,offset);
3006: unlock(d);
3007: unlock(s);
3008: }
3009: MENDFUNC(3,mov_b_Rr,(R4 d, R1 s, IMM offset))
3010:
3011: MIDFUNC(3,lea_l_brr,(W4 d, R4 s, IMM offset))
3012: {
3013: if (isconst(s)) {
3014: COMPCALL(mov_l_ri)(d,live.state[s].val+offset);
3015: return;
3016: }
3017: #if USE_OFFSET
3018: if (d==s) {
3019: add_offset(d,offset);
3020: return;
3021: }
3022: #endif
3023: CLOBBER_LEA;
3024: s=readreg(s,4);
3025: d=writereg(d,4);
3026: raw_lea_l_brr(d,s,offset);
3027: unlock(d);
3028: unlock(s);
3029: }
3030: MENDFUNC(3,lea_l_brr,(W4 d, R4 s, IMM offset))
3031:
3032: MIDFUNC(5,lea_l_brr_indexed,(W4 d, R4 s, R4 index, IMM factor, IMM offset))
3033: {
3034: CLOBBER_LEA;
3035: s=readreg(s,4);
3036: index=readreg(index,4);
3037: d=writereg(d,4);
3038:
3039: raw_lea_l_brr_indexed(d,s,index,factor,offset);
3040: unlock(d);
3041: unlock(index);
3042: unlock(s);
3043: }
3044: MENDFUNC(5,lea_l_brr_indexed,(W4 d, R4 s, R4 index, IMM factor, IMM offset))
3045:
3046: /* write d to the long at the address contained in s+offset */
3047: MIDFUNC(3,mov_l_bRr,(R4 d, R4 s, IMM offset))
3048: {
3049: int dreg=d;
3050: if (isconst(d)) {
3051: COMPCALL(mov_l_mr)(live.state[d].val+offset,s);
3052: return;
3053: }
3054:
3055: CLOBBER_MOV;
3056: s=readreg(s,4);
3057: d=readreg_offset(d,4);
3058: offset+=get_offset(dreg);
3059:
3060: raw_mov_l_bRr(d,s,offset);
3061: unlock(d);
3062: unlock(s);
3063: }
3064: MENDFUNC(3,mov_l_bRr,(R4 d, R4 s, IMM offset))
3065:
3066: /* write the word at the address contained in s+offset and store in d */
3067: MIDFUNC(3,mov_w_bRr,(R4 d, R2 s, IMM offset))
3068: {
3069: int dreg=d;
3070:
3071: if (isconst(d)) {
3072: COMPCALL(mov_w_mr)(live.state[d].val+offset,s);
3073: return;
3074: }
3075:
3076: CLOBBER_MOV;
3077: s=readreg(s,2);
3078: d=readreg_offset(d,4);
3079: offset+=get_offset(dreg);
3080: raw_mov_w_bRr(d,s,offset);
3081: unlock(d);
3082: unlock(s);
3083: }
3084: MENDFUNC(3,mov_w_bRr,(R4 d, R2 s, IMM offset))
3085:
3086: MIDFUNC(3,mov_b_bRr,(R4 d, R1 s, IMM offset))
3087: {
3088: int dreg=d;
3089: if (isconst(d)) {
3090: COMPCALL(mov_b_mr)(live.state[d].val+offset,s);
3091: return;
3092: }
3093:
3094: CLOBBER_MOV;
3095: s=readreg(s,1);
3096: d=readreg_offset(d,4);
3097: offset+=get_offset(dreg);
3098: raw_mov_b_bRr(d,s,offset);
3099: unlock(d);
3100: unlock(s);
3101: }
3102: MENDFUNC(3,mov_b_bRr,(R4 d, R1 s, IMM offset))
3103:
3104: MIDFUNC(1,gen_bswap_32,(RW4 r))
3105: {
3106: int reg=r;
3107:
3108: if (isconst(r)) {
3109: uae_u32 oldv=live.state[r].val;
3110: live.state[r].val=reverse32(oldv);
3111: return;
3112: }
3113:
3114: CLOBBER_SW32;
3115: r=rmw(r,4,4);
3116: raw_bswap_32(r);
3117: unlock(r);
3118: }
3119: MENDFUNC(1,gen_bswap_32,(RW4 r))
3120:
3121: MIDFUNC(1,gen_bswap_16,(RW2 r))
3122: {
3123: if (isconst(r)) {
3124: uae_u32 oldv=live.state[r].val;
3125: live.state[r].val=((oldv>>8)&0xff) | ((oldv<<8)&0xff00) |
3126: (oldv&0xffff0000);
3127: return;
3128: }
3129:
3130: CLOBBER_SW16;
3131: r=rmw(r,2,2);
3132:
3133: raw_bswap_16(r);
3134: unlock(r);
3135: }
3136: MENDFUNC(1,gen_bswap_16,(RW2 r))
3137:
3138:
3139:
3140: MIDFUNC(2,mov_l_rr,(W4 d, R4 s))
3141: {
3142: int olds;
3143:
3144: if (d==s) { /* How pointless! */
3145: return;
3146: }
3147: if (isconst(s)) {
3148: COMPCALL(mov_l_ri)(d,live.state[s].val);
3149: return;
3150: }
3151: #if USE_ALIAS
3152: olds=s;
3153: disassociate(d);
3154: s=readreg_offset(s,4);
3155: live.state[d].realreg=s;
3156: live.state[d].realind=live.nat[s].nholds;
3157: live.state[d].val=live.state[olds].val;
3158: live.state[d].validsize=4;
3159: live.state[d].dirtysize=4;
3160: set_status(d,DIRTY);
3161:
3162: live.nat[s].holds[live.nat[s].nholds]=d;
3163: live.nat[s].nholds++;
3164: log_clobberreg(d);
3165:
3166: /* write_log (L"JIT: Added %d to nreg %d(%d), now holds %d regs\n",
3167: d,s,live.state[d].realind,live.nat[s].nholds); */
3168: unlock(s);
3169: #else
3170: CLOBBER_MOV;
3171: s=readreg(s,4);
3172: d=writereg(d,4);
3173:
3174: raw_mov_l_rr(d,s);
3175: unlock(d);
3176: unlock(s);
3177: #endif
3178: }
3179: MENDFUNC(2,mov_l_rr,(W4 d, R4 s))
3180:
3181: MIDFUNC(2,mov_l_mr,(IMM d, R4 s))
3182: {
3183: if (isconst(s)) {
3184: COMPCALL(mov_l_mi)(d,live.state[s].val);
3185: return;
3186: }
3187: CLOBBER_MOV;
3188: s=readreg(s,4);
3189:
3190: raw_mov_l_mr(d,s);
3191: unlock(s);
3192: }
3193: MENDFUNC(2,mov_l_mr,(IMM d, R4 s))
3194:
3195:
3196: MIDFUNC(2,mov_w_mr,(IMM d, R2 s))
3197: {
3198: if (isconst(s)) {
3199: COMPCALL(mov_w_mi)(d,(uae_u16)live.state[s].val);
3200: return;
3201: }
3202: CLOBBER_MOV;
3203: s=readreg(s,2);
3204:
3205: raw_mov_w_mr(d,s);
3206: unlock(s);
3207: }
3208: MENDFUNC(2,mov_w_mr,(IMM d, R2 s))
3209:
3210: MIDFUNC(2,mov_w_rm,(W2 d, IMM s))
3211: {
3212: CLOBBER_MOV;
3213: d=writereg(d,2);
3214:
3215: raw_mov_w_rm(d,s);
3216: unlock(d);
3217: }
3218: MENDFUNC(2,mov_w_rm,(W2 d, IMM s))
3219:
3220: MIDFUNC(2,mov_b_mr,(IMM d, R1 s))
3221: {
3222: if (isconst(s)) {
3223: COMPCALL(mov_b_mi)(d,(uae_u8)live.state[s].val);
3224: return;
3225: }
3226:
3227: CLOBBER_MOV;
3228: s=readreg(s,1);
3229:
3230: raw_mov_b_mr(d,s);
3231: unlock(s);
3232: }
3233: MENDFUNC(2,mov_b_mr,(IMM d, R1 s))
3234:
3235: MIDFUNC(2,mov_b_rm,(W1 d, IMM s))
3236: {
3237: CLOBBER_MOV;
3238: d=writereg(d,1);
3239:
3240: raw_mov_b_rm(d,s);
3241: unlock(d);
3242: }
3243: MENDFUNC(2,mov_b_rm,(W1 d, IMM s))
3244:
3245: MIDFUNC(2,mov_l_ri,(W4 d, IMM s))
3246: {
3247: set_const(d,s);
3248: return;
3249: }
3250: MENDFUNC(2,mov_l_ri,(W4 d, IMM s))
3251:
3252: MIDFUNC(2,mov_w_ri,(W2 d, IMM s))
3253: {
3254: CLOBBER_MOV;
3255: d=writereg(d,2);
3256:
3257: raw_mov_w_ri(d,s);
3258: unlock(d);
3259: }
3260: MENDFUNC(2,mov_w_ri,(W2 d, IMM s))
3261:
3262: MIDFUNC(2,mov_b_ri,(W1 d, IMM s))
3263: {
3264: CLOBBER_MOV;
3265: d=writereg(d,1);
3266:
3267: raw_mov_b_ri(d,s);
3268: unlock(d);
3269: }
3270: MENDFUNC(2,mov_b_ri,(W1 d, IMM s))
3271:
3272:
3273: MIDFUNC(2,add_l_mi,(IMM d, IMM s))
3274: {
3275: CLOBBER_ADD;
3276: raw_add_l_mi(d,s) ;
3277: }
3278: MENDFUNC(2,add_l_mi,(IMM d, IMM s))
3279:
3280: MIDFUNC(2,add_w_mi,(IMM d, IMM s))
3281: {
3282: CLOBBER_ADD;
3283: raw_add_w_mi(d,s) ;
3284: }
3285: MENDFUNC(2,add_w_mi,(IMM d, IMM s))
3286:
3287: MIDFUNC(2,add_b_mi,(IMM d, IMM s))
3288: {
3289: CLOBBER_ADD;
3290: raw_add_b_mi(d,s) ;
3291: }
3292: MENDFUNC(2,add_b_mi,(IMM d, IMM s))
3293:
3294:
3295: MIDFUNC(2,test_l_ri,(R4 d, IMM i))
3296: {
3297: CLOBBER_TEST;
3298: d=readreg(d,4);
3299:
3300: raw_test_l_ri(d,i);
3301: unlock(d);
3302: }
3303: MENDFUNC(2,test_l_ri,(R4 d, IMM i))
3304:
3305: MIDFUNC(2,test_l_rr,(R4 d, R4 s))
3306: {
3307: CLOBBER_TEST;
3308: d=readreg(d,4);
3309: s=readreg(s,4);
3310:
3311: raw_test_l_rr(d,s);;
3312: unlock(d);
3313: unlock(s);
3314: }
3315: MENDFUNC(2,test_l_rr,(R4 d, R4 s))
3316:
3317: MIDFUNC(2,test_w_rr,(R2 d, R2 s))
3318: {
3319: CLOBBER_TEST;
3320: d=readreg(d,2);
3321: s=readreg(s,2);
3322:
3323: raw_test_w_rr(d,s);
3324: unlock(d);
3325: unlock(s);
3326: }
3327: MENDFUNC(2,test_w_rr,(R2 d, R2 s))
3328:
3329: MIDFUNC(2,test_b_rr,(R1 d, R1 s))
3330: {
3331: CLOBBER_TEST;
3332: d=readreg(d,1);
3333: s=readreg(s,1);
3334:
3335: raw_test_b_rr(d,s);
3336: unlock(d);
3337: unlock(s);
3338: }
3339: MENDFUNC(2,test_b_rr,(R1 d, R1 s))
3340:
3341: MIDFUNC(2,and_l_ri,(RW4 d, IMM i))
3342: {
3343: if (isconst (d) && ! needflags) {
3344: live.state[d].val &= i;
3345: return;
3346: }
3347:
3348: CLOBBER_AND;
3349: d=rmw(d,4,4);
3350:
3351: raw_and_l_ri(d,i);
3352: unlock(d);
3353: }
3354: MENDFUNC(2,and_l_ri,(RW4 d, IMM i))
3355:
3356: MIDFUNC(2,and_l,(RW4 d, R4 s))
3357: {
3358: CLOBBER_AND;
3359: s=readreg(s,4);
3360: d=rmw(d,4,4);
3361:
3362: raw_and_l(d,s);
3363: unlock(d);
3364: unlock(s);
3365: }
3366: MENDFUNC(2,and_l,(RW4 d, R4 s))
3367:
3368: MIDFUNC(2,and_w,(RW2 d, R2 s))
3369: {
3370: CLOBBER_AND;
3371: s=readreg(s,2);
3372: d=rmw(d,2,2);
3373:
3374: raw_and_w(d,s);
3375: unlock(d);
3376: unlock(s);
3377: }
3378: MENDFUNC(2,and_w,(RW2 d, R2 s))
3379:
3380: MIDFUNC(2,and_b,(RW1 d, R1 s))
3381: {
3382: CLOBBER_AND;
3383: s=readreg(s,1);
3384: d=rmw(d,1,1);
3385:
3386: raw_and_b(d,s);
3387: unlock(d);
3388: unlock(s);
3389: }
3390: MENDFUNC(2,and_b,(RW1 d, R1 s))
3391:
3392: MIDFUNC(2,or_l_ri,(RW4 d, IMM i))
3393: {
3394: if (isconst(d) && !needflags) {
3395: live.state[d].val|=i;
3396: return;
3397: }
3398: CLOBBER_OR;
3399: d=rmw(d,4,4);
3400:
3401: raw_or_l_ri(d,i);
3402: unlock(d);
3403: }
3404: MENDFUNC(2,or_l_ri,(RW4 d, IMM i))
3405:
3406: MIDFUNC(2,or_l,(RW4 d, R4 s))
3407: {
3408: if (isconst(d) && isconst(s) && !needflags) {
3409: live.state[d].val|=live.state[s].val;
3410: return;
3411: }
3412: CLOBBER_OR;
3413: s=readreg(s,4);
3414: d=rmw(d,4,4);
3415:
3416: raw_or_l(d,s);
3417: unlock(d);
3418: unlock(s);
3419: }
3420: MENDFUNC(2,or_l,(RW4 d, R4 s))
3421:
3422: MIDFUNC(2,or_w,(RW2 d, R2 s))
3423: {
3424: CLOBBER_OR;
3425: s=readreg(s,2);
3426: d=rmw(d,2,2);
3427:
3428: raw_or_w(d,s);
3429: unlock(d);
3430: unlock(s);
3431: }
3432: MENDFUNC(2,or_w,(RW2 d, R2 s))
3433:
3434: MIDFUNC(2,or_b,(RW1 d, R1 s))
3435: {
3436: CLOBBER_OR;
3437: s=readreg(s,1);
3438: d=rmw(d,1,1);
3439:
3440: raw_or_b(d,s);
3441: unlock(d);
3442: unlock(s);
3443: }
3444: MENDFUNC(2,or_b,(RW1 d, R1 s))
3445:
3446: MIDFUNC(2,adc_l,(RW4 d, R4 s))
3447: {
3448: CLOBBER_ADC;
3449: s=readreg(s,4);
3450: d=rmw(d,4,4);
3451:
3452: raw_adc_l(d,s);
3453:
3454: unlock(d);
3455: unlock(s);
3456: }
3457: MENDFUNC(2,adc_l,(RW4 d, R4 s))
3458:
3459: MIDFUNC(2,adc_w,(RW2 d, R2 s))
3460: {
3461: CLOBBER_ADC;
3462: s=readreg(s,2);
3463: d=rmw(d,2,2);
3464:
3465: raw_adc_w(d,s);
3466: unlock(d);
3467: unlock(s);
3468: }
3469: MENDFUNC(2,adc_w,(RW2 d, R2 s))
3470:
3471: MIDFUNC(2,adc_b,(RW1 d, R1 s))
3472: {
3473: CLOBBER_ADC;
3474: s=readreg(s,1);
3475: d=rmw(d,1,1);
3476:
3477: raw_adc_b(d,s);
3478: unlock(d);
3479: unlock(s);
3480: }
3481: MENDFUNC(2,adc_b,(RW1 d, R1 s))
3482:
3483: MIDFUNC(2,add_l,(RW4 d, R4 s))
3484: {
3485: if (isconst(s)) {
3486: COMPCALL(add_l_ri)(d,live.state[s].val);
3487: return;
3488: }
3489:
3490: CLOBBER_ADD;
3491: s=readreg(s,4);
3492: d=rmw(d,4,4);
3493:
3494: raw_add_l(d,s);
3495:
3496: unlock(d);
3497: unlock(s);
3498: }
3499: MENDFUNC(2,add_l,(RW4 d, R4 s))
3500:
3501: MIDFUNC(2,add_w,(RW2 d, R2 s))
3502: {
3503: if (isconst(s)) {
3504: COMPCALL(add_w_ri)(d,(uae_u16)live.state[s].val);
3505: return;
3506: }
3507:
3508: CLOBBER_ADD;
3509: s=readreg(s,2);
3510: d=rmw(d,2,2);
3511:
3512: raw_add_w(d,s);
3513: unlock(d);
3514: unlock(s);
3515: }
3516: MENDFUNC(2,add_w,(RW2 d, R2 s))
3517:
3518: MIDFUNC(2,add_b,(RW1 d, R1 s))
3519: {
3520: if (isconst(s)) {
3521: COMPCALL(add_b_ri)(d,(uae_u8)live.state[s].val);
3522: return;
3523: }
3524:
3525: CLOBBER_ADD;
3526: s=readreg(s,1);
3527: d=rmw(d,1,1);
3528:
3529: raw_add_b(d,s);
3530: unlock(d);
3531: unlock(s);
3532: }
3533: MENDFUNC(2,add_b,(RW1 d, R1 s))
3534:
3535: MIDFUNC(2,sub_l_ri,(RW4 d, IMM i))
3536: {
3537: if (!i && !needflags)
3538: return;
3539: if (isconst(d) && !needflags) {
3540: live.state[d].val-=i;
3541: return;
3542: }
3543: #if USE_OFFSET
3544: if (!needflags) {
3545: add_offset(d,-(signed)i);
3546: return;
3547: }
3548: #endif
3549:
3550: CLOBBER_SUB;
3551: d=rmw(d,4,4);
3552:
3553: raw_sub_l_ri(d,i);
3554: unlock(d);
3555: }
3556: MENDFUNC(2,sub_l_ri,(RW4 d, IMM i))
3557:
3558: MIDFUNC(2,sub_w_ri,(RW2 d, IMM i))
3559: {
3560: if (!i && !needflags)
3561: return;
3562:
3563: CLOBBER_SUB;
3564: d=rmw(d,2,2);
3565:
3566: raw_sub_w_ri(d,i);
3567: unlock(d);
3568: }
3569: MENDFUNC(2,sub_w_ri,(RW2 d, IMM i))
3570:
3571: MIDFUNC(2,sub_b_ri,(RW1 d, IMM i))
3572: {
3573: if (!i && !needflags)
3574: return;
3575:
3576: CLOBBER_SUB;
3577: d=rmw(d,1,1);
3578:
3579: raw_sub_b_ri(d,i);
3580:
3581: unlock(d);
3582: }
3583: MENDFUNC(2,sub_b_ri,(RW1 d, IMM i))
3584:
3585: MIDFUNC(2,add_l_ri,(RW4 d, IMM i))
3586: {
3587: if (!i && !needflags)
3588: return;
3589: if (isconst(d) && !needflags) {
3590: live.state[d].val+=i;
3591: return;
3592: }
3593: #if USE_OFFSET
3594: if (!needflags) {
3595: add_offset(d,i);
3596: return;
3597: }
3598: #endif
3599: CLOBBER_ADD;
3600: d=rmw(d,4,4);
3601: raw_add_l_ri(d,i);
3602: unlock(d);
3603: }
3604: MENDFUNC(2,add_l_ri,(RW4 d, IMM i))
3605:
3606: MIDFUNC(2,add_w_ri,(RW2 d, IMM i))
3607: {
3608: if (!i && !needflags)
3609: return;
3610:
3611: CLOBBER_ADD;
3612: d=rmw(d,2,2);
3613:
3614: raw_add_w_ri(d,i);
3615: unlock(d);
3616: }
3617: MENDFUNC(2,add_w_ri,(RW2 d, IMM i))
3618:
3619: MIDFUNC(2,add_b_ri,(RW1 d, IMM i))
3620: {
3621: if (!i && !needflags)
3622: return;
3623:
3624: CLOBBER_ADD;
3625: d=rmw(d,1,1);
3626:
3627: raw_add_b_ri(d,i);
3628:
3629: unlock(d);
3630: }
3631: MENDFUNC(2,add_b_ri,(RW1 d, IMM i))
3632:
3633: MIDFUNC(2,sbb_l,(RW4 d, R4 s))
3634: {
3635: CLOBBER_SBB;
3636: s=readreg(s,4);
3637: d=rmw(d,4,4);
3638:
3639: raw_sbb_l(d,s);
3640: unlock(d);
3641: unlock(s);
3642: }
3643: MENDFUNC(2,sbb_l,(RW4 d, R4 s))
3644:
3645: MIDFUNC(2,sbb_w,(RW2 d, R2 s))
3646: {
3647: CLOBBER_SBB;
3648: s=readreg(s,2);
3649: d=rmw(d,2,2);
3650:
3651: raw_sbb_w(d,s);
3652: unlock(d);
3653: unlock(s);
3654: }
3655: MENDFUNC(2,sbb_w,(RW2 d, R2 s))
3656:
3657: MIDFUNC(2,sbb_b,(RW1 d, R1 s))
3658: {
3659: CLOBBER_SBB;
3660: s=readreg(s,1);
3661: d=rmw(d,1,1);
3662:
3663: raw_sbb_b(d,s);
3664: unlock(d);
3665: unlock(s);
3666: }
3667: MENDFUNC(2,sbb_b,(RW1 d, R1 s))
3668:
3669: MIDFUNC(2,sub_l,(RW4 d, R4 s))
3670: {
3671: if (isconst(s)) {
3672: COMPCALL(sub_l_ri)(d,live.state[s].val);
3673: return;
3674: }
3675:
3676: CLOBBER_SUB;
3677: s=readreg(s,4);
3678: d=rmw(d,4,4);
3679:
3680: raw_sub_l(d,s);
3681: unlock(d);
3682: unlock(s);
3683: }
3684: MENDFUNC(2,sub_l,(RW4 d, R4 s))
3685:
3686: MIDFUNC(2,sub_w,(RW2 d, R2 s))
3687: {
3688: if (isconst(s)) {
3689: COMPCALL(sub_w_ri)(d,(uae_u16)live.state[s].val);
3690: return;
3691: }
3692:
3693: CLOBBER_SUB;
3694: s=readreg(s,2);
3695: d=rmw(d,2,2);
3696:
3697: raw_sub_w(d,s);
3698: unlock(d);
3699: unlock(s);
3700: }
3701: MENDFUNC(2,sub_w,(RW2 d, R2 s))
3702:
3703: MIDFUNC(2,sub_b,(RW1 d, R1 s))
3704: {
3705: if (isconst(s)) {
3706: COMPCALL(sub_b_ri)(d,(uae_u8)live.state[s].val);
3707: return;
3708: }
3709:
3710: CLOBBER_SUB;
3711: s=readreg(s,1);
3712: d=rmw(d,1,1);
3713:
3714: raw_sub_b(d,s);
3715: unlock(d);
3716: unlock(s);
3717: }
3718: MENDFUNC(2,sub_b,(RW1 d, R1 s))
3719:
3720: MIDFUNC(2,cmp_l,(R4 d, R4 s))
3721: {
3722: CLOBBER_CMP;
3723: s=readreg(s,4);
3724: d=readreg(d,4);
3725:
3726: raw_cmp_l(d,s);
3727: unlock(d);
3728: unlock(s);
3729: }
3730: MENDFUNC(2,cmp_l,(R4 d, R4 s))
3731:
3732: MIDFUNC(2,cmp_l_ri,(R4 r, IMM i))
3733: {
3734: CLOBBER_CMP;
3735: r=readreg(r,4);
3736:
3737: raw_cmp_l_ri(r,i);
3738: unlock(r);
3739: }
3740: MENDFUNC(2,cmp_l_ri,(R4 r, IMM i))
3741:
3742: MIDFUNC(2,cmp_w,(R2 d, R2 s))
3743: {
3744: CLOBBER_CMP;
3745: s=readreg(s,2);
3746: d=readreg(d,2);
3747:
3748: raw_cmp_w(d,s);
3749: unlock(d);
3750: unlock(s);
3751: }
3752: MENDFUNC(2,cmp_w,(R2 d, R2 s))
3753:
3754: MIDFUNC(2,cmp_b,(R1 d, R1 s))
3755: {
3756: CLOBBER_CMP;
3757: s=readreg(s,1);
3758: d=readreg(d,1);
3759:
3760: raw_cmp_b(d,s);
3761: unlock(d);
3762: unlock(s);
3763: }
3764: MENDFUNC(2,cmp_b,(R1 d, R1 s))
3765:
3766:
3767: MIDFUNC(2,xor_l,(RW4 d, R4 s))
3768: {
3769: CLOBBER_XOR;
3770: s=readreg(s,4);
3771: d=rmw(d,4,4);
3772:
3773: raw_xor_l(d,s);
3774: unlock(d);
3775: unlock(s);
3776: }
3777: MENDFUNC(2,xor_l,(RW4 d, R4 s))
3778:
3779: MIDFUNC(2,xor_w,(RW2 d, R2 s))
3780: {
3781: CLOBBER_XOR;
3782: s=readreg(s,2);
3783: d=rmw(d,2,2);
3784:
3785: raw_xor_w(d,s);
3786: unlock(d);
3787: unlock(s);
3788: }
3789: MENDFUNC(2,xor_w,(RW2 d, R2 s))
3790:
3791: MIDFUNC(2,xor_b,(RW1 d, R1 s))
3792: {
3793: CLOBBER_XOR;
3794: s=readreg(s,1);
3795: d=rmw(d,1,1);
3796:
3797: raw_xor_b(d,s);
3798: unlock(d);
3799: unlock(s);
3800: }
3801: MENDFUNC(2,xor_b,(RW1 d, R1 s))
3802:
3803: MIDFUNC(5,call_r_11,(W4 out1, R4 r, R4 in1, IMM osize, IMM isize))
3804: {
3805: clobber_flags();
3806: remove_all_offsets();
3807: if (osize==4) {
3808: if (out1!=in1 && out1!=r) {
3809: COMPCALL(forget_about)(out1);
3810: }
3811: }
3812: else {
3813: tomem_c(out1);
3814: }
3815:
3816: in1=readreg_specific(in1,isize,REG_PAR1);
3817: r=readreg(r,4);
3818: prepare_for_call_1(); /* This should ensure that there won't be
3819: any need for swapping nregs in prepare_for_call_2
3820: */
3821: #if USE_NORMAL_CALLING_CONVENTION
3822: raw_push_l_r(in1);
3823: #endif
3824: unlock(in1);
3825: unlock(r);
3826:
3827: prepare_for_call_2();
3828: raw_call_r(r);
3829:
3830: #if USE_NORMAL_CALLING_CONVENTION
3831: raw_inc_sp(4);
3832: #endif
3833:
3834:
3835: live.nat[REG_RESULT].holds[0]=out1;
3836: live.nat[REG_RESULT].nholds=1;
3837: live.nat[REG_RESULT].touched=touchcnt++;
3838:
3839: live.state[out1].realreg=REG_RESULT;
3840: live.state[out1].realind=0;
3841: live.state[out1].val=0;
3842: live.state[out1].validsize=osize;
3843: live.state[out1].dirtysize=osize;
3844: set_status(out1,DIRTY);
3845: }
3846: MENDFUNC(5,call_r_11,(W4 out1, R4 r, R4 in1, IMM osize, IMM isize))
3847:
3848: MIDFUNC(5,call_r_02,(R4 r, R4 in1, R4 in2, IMM isize1, IMM isize2))
3849: {
3850: clobber_flags();
3851: remove_all_offsets();
3852: in1=readreg_specific(in1,isize1,REG_PAR1);
3853: in2=readreg_specific(in2,isize2,REG_PAR2);
3854: r=readreg(r,4);
3855: prepare_for_call_1(); /* This should ensure that there won't be
3856: any need for swapping nregs in prepare_for_call_2
3857: */
3858: #if USE_NORMAL_CALLING_CONVENTION
3859: raw_push_l_r(in2);
3860: raw_push_l_r(in1);
3861: #endif
3862: unlock(r);
3863: unlock(in1);
3864: unlock(in2);
3865: prepare_for_call_2();
3866: raw_call_r(r);
3867: #if USE_NORMAL_CALLING_CONVENTION
3868: raw_inc_sp(8);
3869: #endif
3870: }
3871: MENDFUNC(5,call_r_02,(R4 r, R4 in1, R4 in2, IMM isize1, IMM isize2))
3872:
3873: MIDFUNC(1,forget_about,(W4 r))
3874: {
3875: if (isinreg(r))
3876: disassociate(r);
3877: live.state[r].val=0;
3878: set_status(r,UNDEF);
3879: }
3880: MENDFUNC(1,forget_about,(W4 r))
3881:
3882: MIDFUNC(0,nop,(void))
3883: {
3884: raw_nop();
3885: }
3886: MENDFUNC(0,nop,(void))
3887:
3888: MIDFUNC(1,f_forget_about,(FW r))
3889: {
3890: if (f_isinreg(r))
3891: f_disassociate(r);
3892: live.fate[r].status=UNDEF;
3893: }
3894: MENDFUNC(1,f_forget_about,(FW r))
3895:
3896: MIDFUNC(1,fmov_pi,(FW r))
3897: {
3898: r=f_writereg(r);
3899: raw_fmov_pi(r);
3900: f_unlock(r);
3901: }
3902: MENDFUNC(1,fmov_pi,(FW r))
3903:
3904: MIDFUNC(1,fmov_log10_2,(FW r))
3905: {
3906: r=f_writereg(r);
3907: raw_fmov_log10_2(r);
3908: f_unlock(r);
3909: }
3910: MENDFUNC(1,fmov_log10_2,(FW r))
3911:
3912: MIDFUNC(1,fmov_log2_e,(FW r))
3913: {
3914: r=f_writereg(r);
3915: raw_fmov_log2_e(r);
3916: f_unlock(r);
3917: }
3918: MENDFUNC(1,fmov_log2_e,(FW r))
3919:
3920: MIDFUNC(1,fmov_loge_2,(FW r))
3921: {
3922: r=f_writereg(r);
3923: raw_fmov_loge_2(r);
3924: f_unlock(r);
3925: }
3926: MENDFUNC(1,fmov_loge_2,(FW r))
3927:
3928: MIDFUNC(1,fmov_1,(FW r))
3929: {
3930: r=f_writereg(r);
3931: raw_fmov_1(r);
3932: f_unlock(r);
3933: }
3934: MENDFUNC(1,fmov_1,(FW r))
3935:
3936: MIDFUNC(1,fmov_0,(FW r))
3937: {
3938: r=f_writereg(r);
3939: raw_fmov_0(r);
3940: f_unlock(r);
3941: }
3942: MENDFUNC(1,fmov_0,(FW r))
3943:
3944: MIDFUNC(2,fmov_rm,(FW r, MEMR m))
3945: {
3946: r=f_writereg(r);
3947: raw_fmov_rm(r,m);
3948: f_unlock(r);
3949: }
3950: MENDFUNC(2,fmov_rm,(FW r, MEMR m))
3951:
3952: MIDFUNC(2,fmovi_rm,(FW r, MEMR m))
3953: {
3954: r=f_writereg(r);
3955: raw_fmovi_rm(r,m);
3956: f_unlock(r);
3957: }
3958: MENDFUNC(2,fmovi_rm,(FW r, MEMR m))
3959:
3960: MIDFUNC(3,fmovi_mrb,(MEMW m, FR r, double *bounds))
3961: {
3962: r=f_readreg(r);
3963: raw_fmovi_mrb(m,r,bounds);
3964: f_unlock(r);
3965: }
3966: MENDFUNC(3,fmovi_mrb,(MEMW m, FR r, double *bounds))
3967:
3968: MIDFUNC(2,fmovs_rm,(FW r, MEMR m))
3969: {
3970: r=f_writereg(r);
3971: raw_fmovs_rm(r,m);
3972: f_unlock(r);
3973: }
3974: MENDFUNC(2,fmovs_rm,(FW r, MEMR m))
3975:
3976: MIDFUNC(2,fmovs_mr,(MEMW m, FR r))
3977: {
3978: r=f_readreg(r);
3979: raw_fmovs_mr(m,r);
3980: f_unlock(r);
3981: }
3982: MENDFUNC(2,fmovs_mr,(MEMW m, FR r))
3983:
3984: MIDFUNC(1,fcuts_r,(FRW r))
3985: {
3986: r=f_rmw(r);
3987: raw_fcuts_r(r);
3988: f_unlock(r);
3989: }
3990: MENDFUNC(1,fcuts_r,(FRW r))
3991:
3992: MIDFUNC(1,fcut_r,(FRW r))
3993: {
3994: r=f_rmw(r);
3995: raw_fcut_r(r);
3996: f_unlock(r);
3997: }
3998: MENDFUNC(1,fcut_r,(FRW r))
3999:
4000: MIDFUNC(2,fmovl_ri,(FW r, IMMS i))
4001: {
4002: r=f_writereg(r);
4003: raw_fmovl_ri(r,i);
4004: f_unlock(r);
4005: }
4006: MENDFUNC(2,fmovl_ri,(FW r, IMMS i))
4007:
4008: MIDFUNC(2,fmovs_ri,(FW r, IMM i))
4009: {
4010: r=f_writereg(r);
4011: raw_fmovs_ri(r,i);
4012: f_unlock(r);
4013: }
4014: MENDFUNC(2,fmovs_ri,(FW r, IMM i))
4015:
4016: MIDFUNC(3,fmov_ri,(FW r, IMM i1, IMM i2))
4017: {
4018: r=f_writereg(r);
4019: raw_fmov_ri(r,i1,i2);
4020: f_unlock(r);
4021: }
4022: MENDFUNC(3,fmov_ri,(FW r, IMM i1, IMM i2))
4023:
4024: MIDFUNC(4,fmov_ext_ri,(FW r, IMM i1, IMM i2, IMM i3))
4025: {
4026: r=f_writereg(r);
4027: raw_fmov_ext_ri(r,i1,i2,i3);
4028: f_unlock(r);
4029: }
4030: MENDFUNC(4,fmov_ext_ri,(FW r, IMM i1, IMM i2, IMM i3))
4031:
4032: MIDFUNC(2,fmov_ext_mr,(MEMW m, FR r))
4033: {
4034: r=f_readreg(r);
4035: raw_fmov_ext_mr(m,r);
4036: f_unlock(r);
4037: }
4038: MENDFUNC(2,fmov_ext_mr,(MEMW m, FR r))
4039:
4040: MIDFUNC(2,fmov_mr,(MEMW m, FR r))
4041: {
4042: r=f_readreg(r);
4043: raw_fmov_mr(m,r);
4044: f_unlock(r);
4045: }
4046: MENDFUNC(2,fmov_mr,(MEMW m, FR r))
4047:
4048: MIDFUNC(2,fmov_ext_rm,(FW r, MEMR m))
4049: {
4050: r=f_writereg(r);
4051: raw_fmov_ext_rm(r,m);
4052: f_unlock(r);
4053: }
4054: MENDFUNC(2,fmov_ext_rm,(FW r, MEMR m))
4055:
4056: MIDFUNC(2,fmov_rr,(FW d, FR s))
4057: {
4058: if (d==s) { /* How pointless! */
4059: return;
4060: }
4061: #if USE_F_ALIAS
4062: f_disassociate(d);
4063: s=f_readreg(s);
4064: live.fate[d].realreg=s;
4065: live.fate[d].realind=live.fat[s].nholds;
4066: live.fate[d].status=DIRTY;
4067: live.fat[s].holds[live.fat[s].nholds]=d;
4068: live.fat[s].nholds++;
4069: f_unlock(s);
4070: #else
4071: s=f_readreg(s);
4072: d=f_writereg(d);
4073: raw_fmov_rr(d,s);
4074: f_unlock(s);
4075: f_unlock(d);
4076: #endif
4077: }
4078: MENDFUNC(2,fmov_rr,(FW d, FR s))
4079:
4080: MIDFUNC(2,fldcw_m_indexed,(R4 index, IMM base))
4081: {
4082: index=readreg(index,4);
4083:
4084: raw_fldcw_m_indexed(index,base);
4085: unlock(index);
4086: }
4087: MENDFUNC(2,fldcw_m_indexed,(R4 index, IMM base))
4088:
4089: MIDFUNC(1,ftst_r,(FR r))
4090: {
4091: r=f_readreg(r);
4092: raw_ftst_r(r);
4093: f_unlock(r);
4094: }
4095: MENDFUNC(1,ftst_r,(FR r))
4096:
4097: MIDFUNC(0,dont_care_fflags,(void))
4098: {
4099: f_disassociate(FP_RESULT);
4100: }
4101: MENDFUNC(0,dont_care_fflags,(void))
4102:
4103: MIDFUNC(2,fsqrt_rr,(FW d, FR s))
4104: {
4105: s=f_readreg(s);
4106: d=f_writereg(d);
4107: raw_fsqrt_rr(d,s);
4108: f_unlock(s);
4109: f_unlock(d);
4110: }
4111: MENDFUNC(2,fsqrt_rr,(FW d, FR s))
4112:
4113: MIDFUNC(2,fabs_rr,(FW d, FR s))
4114: {
4115: s=f_readreg(s);
4116: d=f_writereg(d);
4117: raw_fabs_rr(d,s);
4118: f_unlock(s);
4119: f_unlock(d);
4120: }
4121: MENDFUNC(2,fabs_rr,(FW d, FR s))
4122:
4123: MIDFUNC(2,frndint_rr,(FW d, FR s))
4124: {
4125: s=f_readreg(s);
4126: d=f_writereg(d);
4127: raw_frndint_rr(d,s);
4128: f_unlock(s);
4129: f_unlock(d);
4130: }
4131: MENDFUNC(2,frndint_rr,(FW d, FR s))
4132:
4133: MIDFUNC(2,fgetexp_rr,(FW d, FR s))
4134: {
4135: s=f_readreg(s);
4136: d=f_writereg(d);
4137: raw_fgetexp_rr(d,s);
4138: f_unlock(s);
4139: f_unlock(d);
4140: }
4141: MENDFUNC(2,fgetexp_rr,(FW d, FR s))
4142:
4143: MIDFUNC(2,fgetman_rr,(FW d, FR s))
4144: {
4145: s=f_readreg(s);
4146: d=f_writereg(d);
4147: raw_fgetman_rr(d,s);
4148: f_unlock(s);
4149: f_unlock(d);
4150: }
4151: MENDFUNC(2,fgetman_rr,(FW d, FR s))
4152:
4153: MIDFUNC(2,fsin_rr,(FW d, FR s))
4154: {
4155: s=f_readreg(s);
4156: d=f_writereg(d);
4157: raw_fsin_rr(d,s);
4158: f_unlock(s);
4159: f_unlock(d);
4160: }
4161: MENDFUNC(2,fsin_rr,(FW d, FR s))
4162:
4163: MIDFUNC(2,fcos_rr,(FW d, FR s))
4164: {
4165: s=f_readreg(s);
4166: d=f_writereg(d);
4167: raw_fcos_rr(d,s);
4168: f_unlock(s);
4169: f_unlock(d);
4170: }
4171: MENDFUNC(2,fcos_rr,(FW d, FR s))
4172:
4173: MIDFUNC(2,ftan_rr,(FW d, FR s))
4174: {
4175: s=f_readreg(s);
4176: d=f_writereg(d);
4177: raw_ftan_rr(d,s);
4178: f_unlock(s);
4179: f_unlock(d);
4180: }
4181: MENDFUNC(2,ftan_rr,(FW d, FR s))
4182:
4183: MIDFUNC(3,fsincos_rr,(FW d, FW c, FR s))
4184: {
4185: s=f_readreg(s); /* s for source */
4186: d=f_writereg(d); /* d for sine */
4187: c=f_writereg(c); /* c for cosine */
4188: raw_fsincos_rr(d,c,s);
4189: f_unlock(s);
4190: f_unlock(d);
4191: f_unlock(c);
4192: }
4193: MENDFUNC(3,fsincos_rr,(FW d, FW c, FR s))
4194:
4195: MIDFUNC(2,fscale_rr,(FRW d, FR s))
4196: {
4197: s=f_readreg(s);
4198: d=f_rmw(d);
4199: raw_fscale_rr(d,s);
4200: f_unlock(s);
4201: f_unlock(d);
4202: }
4203: MENDFUNC(2,fscale_rr,(FRW d, FR s))
4204:
4205: MIDFUNC(2,ftwotox_rr,(FW d, FR s))
4206: {
4207: s=f_readreg(s);
4208: d=f_writereg(d);
4209: raw_ftwotox_rr(d,s);
4210: f_unlock(s);
4211: f_unlock(d);
4212: }
4213: MENDFUNC(2,ftwotox_rr,(FW d, FR s))
4214:
4215: MIDFUNC(2,fetox_rr,(FW d, FR s))
4216: {
4217: s=f_readreg(s);
4218: d=f_writereg(d);
4219: raw_fetox_rr(d,s);
4220: f_unlock(s);
4221: f_unlock(d);
4222: }
4223: MENDFUNC(2,fetox_rr,(FW d, FR s))
4224:
4225: MIDFUNC(2,fetoxM1_rr,(FW d, FR s))
4226: {
4227: s=f_readreg(s);
4228: d=f_writereg(d);
4229: raw_fetoxM1_rr(d,s);
4230: f_unlock(s);
4231: f_unlock(d);
4232: }
4233: MENDFUNC(2,fetoxM1_rr,(FW d, FR s))
4234:
4235: MIDFUNC(2,ftentox_rr,(FW d, FR s))
4236: {
4237: s=f_readreg(s);
4238: d=f_writereg(d);
4239: raw_ftentox_rr(d,s);
4240: f_unlock(s);
4241: f_unlock(d);
4242: }
4243: MENDFUNC(2,ftentox_rr,(FW d, FR s))
4244:
4245: MIDFUNC(2,flog2_rr,(FW d, FR s))
4246: {
4247: s=f_readreg(s);
4248: d=f_writereg(d);
4249: raw_flog2_rr(d,s);
4250: f_unlock(s);
4251: f_unlock(d);
4252: }
4253: MENDFUNC(2,flog2_rr,(FW d, FR s))
4254:
4255: MIDFUNC(2,flogN_rr,(FW d, FR s))
4256: {
4257: s=f_readreg(s);
4258: d=f_writereg(d);
4259: raw_flogN_rr(d,s);
4260: f_unlock(s);
4261: f_unlock(d);
4262: }
4263: MENDFUNC(2,flogN_rr,(FW d, FR s))
4264:
4265: MIDFUNC(2,flogNP1_rr,(FW d, FR s))
4266: {
4267: s=f_readreg(s);
4268: d=f_writereg(d);
4269: raw_flogNP1_rr(d,s);
4270: f_unlock(s);
4271: f_unlock(d);
4272: }
4273: MENDFUNC(2,flogNP1_rr,(FW d, FR s))
4274:
4275: MIDFUNC(2,flog10_rr,(FW d, FR s))
4276: {
4277: s=f_readreg(s);
4278: d=f_writereg(d);
4279: raw_flog10_rr(d,s);
4280: f_unlock(s);
4281: f_unlock(d);
4282: }
4283: MENDFUNC(2,flog10_rr,(FW d, FR s))
4284:
4285: MIDFUNC(2,fasin_rr,(FW d, FR s))
4286: {
4287: s=f_readreg(s);
4288: d=f_writereg(d);
4289: raw_fasin_rr(d,s);
4290: f_unlock(s);
4291: f_unlock(d);
4292: }
4293: MENDFUNC(2,fasin_rr,(FW d, FR s))
4294:
4295: MIDFUNC(2,facos_rr,(FW d, FR s))
4296: {
4297: s=f_readreg(s);
4298: d=f_writereg(d);
4299: raw_facos_rr(d,s);
4300: f_unlock(s);
4301: f_unlock(d);
4302: }
4303: MENDFUNC(2,facos_rr,(FW d, FR s))
4304:
4305: MIDFUNC(2,fatan_rr,(FW d, FR s))
4306: {
4307: s=f_readreg(s);
4308: d=f_writereg(d);
4309: raw_fatan_rr(d,s);
4310: f_unlock(s);
4311: f_unlock(d);
4312: }
4313: MENDFUNC(2,fatan_rr,(FW d, FR s))
4314:
4315: MIDFUNC(2,fatanh_rr,(FW d, FR s))
4316: {
4317: s=f_readreg(s);
4318: d=f_writereg(d);
4319: raw_fatanh_rr(d,s);
4320: f_unlock(s);
4321: f_unlock(d);
4322: }
4323: MENDFUNC(2,fatanh_rr,(FW d, FR s))
4324:
4325: MIDFUNC(2,fsinh_rr,(FW d, FR s))
4326: {
4327: s=f_readreg(s);
4328: d=f_writereg(d);
4329: raw_fsinh_rr(d,s);
4330: f_unlock(s);
4331: f_unlock(d);
4332: }
4333: MENDFUNC(2,fsinh_rr,(FW d, FR s))
4334:
4335: MIDFUNC(2,fcosh_rr,(FW d, FR s))
4336: {
4337: s=f_readreg(s);
4338: d=f_writereg(d);
4339: raw_fcosh_rr(d,s);
4340: f_unlock(s);
4341: f_unlock(d);
4342: }
4343: MENDFUNC(2,fcosh_rr,(FW d, FR s))
4344:
4345: MIDFUNC(2,ftanh_rr,(FW d, FR s))
4346: {
4347: s=f_readreg(s);
4348: d=f_writereg(d);
4349: raw_ftanh_rr(d,s);
4350: f_unlock(s);
4351: f_unlock(d);
4352: }
4353: MENDFUNC(2,ftanh_rr,(FW d, FR s))
4354:
4355: MIDFUNC(2,fneg_rr,(FW d, FR s))
4356: {
4357: s=f_readreg(s);
4358: d=f_writereg(d);
4359: raw_fneg_rr(d,s);
4360: f_unlock(s);
4361: f_unlock(d);
4362: }
4363: MENDFUNC(2,fneg_rr,(FW d, FR s))
4364:
4365: MIDFUNC(2,fadd_rr,(FRW d, FR s))
4366: {
4367: s=f_readreg(s);
4368: d=f_rmw(d);
4369: raw_fadd_rr(d,s);
4370: f_unlock(s);
4371: f_unlock(d);
4372: }
4373: MENDFUNC(2,fadd_rr,(FRW d, FR s))
4374:
4375: MIDFUNC(2,fsub_rr,(FRW d, FR s))
4376: {
4377: s=f_readreg(s);
4378: d=f_rmw(d);
4379: raw_fsub_rr(d,s);
4380: f_unlock(s);
4381: f_unlock(d);
4382: }
4383: MENDFUNC(2,fsub_rr,(FRW d, FR s))
4384:
4385: MIDFUNC(2,fcmp_rr,(FR d, FR s))
4386: {
4387: d=f_readreg(d);
4388: s=f_readreg(s);
4389: raw_fcmp_rr(d,s);
4390: f_unlock(s);
4391: f_unlock(d);
4392: }
4393: MENDFUNC(2,fcmp_rr,(FR d, FR s))
4394:
4395: MIDFUNC(2,fdiv_rr,(FRW d, FR s))
4396: {
4397: s=f_readreg(s);
4398: d=f_rmw(d);
4399: raw_fdiv_rr(d,s);
4400: f_unlock(s);
4401: f_unlock(d);
4402: }
4403: MENDFUNC(2,fdiv_rr,(FRW d, FR s))
4404:
4405: MIDFUNC(2,frem_rr,(FRW d, FR s))
4406: {
4407: s=f_readreg(s);
4408: d=f_rmw(d);
4409: raw_frem_rr(d,s);
4410: f_unlock(s);
4411: f_unlock(d);
4412: }
4413: MENDFUNC(2,frem_rr,(FRW d, FR s))
4414:
4415: MIDFUNC(2,frem1_rr,(FRW d, FR s))
4416: {
4417: s=f_readreg(s);
4418: d=f_rmw(d);
4419: raw_frem1_rr(d,s);
4420: f_unlock(s);
4421: f_unlock(d);
4422: }
4423: MENDFUNC(2,frem1_rr,(FRW d, FR s))
4424:
4425: MIDFUNC(2,fmul_rr,(FRW d, FR s))
4426: {
4427: s=f_readreg(s);
4428: d=f_rmw(d);
4429: raw_fmul_rr(d,s);
4430: f_unlock(s);
4431: f_unlock(d);
4432: }
4433: MENDFUNC(2,fmul_rr,(FRW d, FR s))
4434:
4435: /********************************************************************
4436: * Support functions exposed to gencomp. CREATE time *
4437: ********************************************************************/
4438:
4439: int kill_rodent(int r)
4440: {
4441: return KILLTHERAT &&
4442: have_rat_stall &&
4443: (live.state[r].status==INMEM ||
4444: live.state[r].status==CLEAN ||
4445: live.state[r].status==ISCONST ||
4446: live.state[r].dirtysize==4);
4447: }
4448:
4449: uae_u32 get_const(int r)
4450: {
4451: #if USE_OPTIMIZER
4452: if (!reg_alloc_run)
4453: #endif
4454: Dif (!isconst(r)) {
4455: jit_abort (L"JIT: Register %d should be constant, but isn't\n",r);
4456: }
4457: return live.state[r].val;
4458: }
4459:
4460: void sync_m68k_pc(void)
4461: {
4462: if (m68k_pc_offset) {
4463: add_l_ri(PC_P,m68k_pc_offset);
4464: comp_pc_p+=m68k_pc_offset;
4465: m68k_pc_offset=0;
4466: }
4467: }
4468:
4469: /********************************************************************
4470: * Support functions exposed to newcpu *
4471: ********************************************************************/
4472:
4473: uae_u32 scratch[VREGS];
4474: fptype fscratch[VFREGS];
4475:
4476: void init_comp(void)
4477: {
4478: int i;
4479: uae_u8* cb=can_byte;
4480: uae_u8* cw=can_word;
4481: uae_u8* au=always_used;
4482:
4483: for (i=0;i<VREGS;i++) {
4484: live.state[i].realreg=-1;
4485: live.state[i].needflush=NF_SCRATCH;
4486: live.state[i].val=0;
4487: set_status(i,UNDEF);
4488: }
4489:
4490: for (i=0;i<VFREGS;i++) {
4491: live.fate[i].status=UNDEF;
4492: live.fate[i].realreg=-1;
4493: live.fate[i].needflush=NF_SCRATCH;
4494: }
4495:
4496: for (i=0;i<VREGS;i++) {
4497: if (i<16) { /* First 16 registers map to 68k registers */
4498: live.state[i].mem=((uae_u32*)®s)+i;
4499: live.state[i].needflush=NF_TOMEM;
4500: set_status(i,INMEM);
4501: }
4502: else
4503: live.state[i].mem=scratch+i;
4504: }
4505: live.state[PC_P].mem=(uae_u32*)&(regs.pc_p);
4506: live.state[PC_P].needflush=NF_TOMEM;
4507: set_const(PC_P,(uae_u32)comp_pc_p);
4508:
4509: live.state[FLAGX].mem=&(regflags.x);
4510: live.state[FLAGX].needflush=NF_TOMEM;
4511: set_status(FLAGX,INMEM);
4512:
4513: live.state[FLAGTMP].mem=&(regflags.cznv);
4514: live.state[FLAGTMP].needflush=NF_TOMEM;
4515: set_status(FLAGTMP,INMEM);
4516:
4517: live.state[NEXT_HANDLER].needflush=NF_HANDLER;
4518: set_status(NEXT_HANDLER,UNDEF);
4519:
4520: for (i=0;i<VFREGS;i++) {
4521: if (i<8) { /* First 8 registers map to 68k FPU registers */
4522: live.fate[i].mem=(uae_u32*)(((fptype*)regs.fp)+i);
4523: live.fate[i].needflush=NF_TOMEM;
4524: live.fate[i].status=INMEM;
4525: }
4526: else if (i==FP_RESULT) {
4527: live.fate[i].mem=(uae_u32*)(®s.fp_result);
4528: live.fate[i].needflush=NF_TOMEM;
4529: live.fate[i].status=INMEM;
4530: }
4531: else
4532: live.fate[i].mem=(uae_u32*)(fscratch+i);
4533: }
4534:
4535: for (i=0;i<N_REGS;i++) {
4536: live.nat[i].touched=0;
4537: live.nat[i].nholds=0;
4538: live.nat[i].locked=0;
4539: if (*cb==i) {
4540: live.nat[i].canbyte=1; cb++;
4541: } else live.nat[i].canbyte=0;
4542: if (*cw==i) {
4543: live.nat[i].canword=1; cw++;
4544: } else live.nat[i].canword=0;
4545: if (*au==i) {
4546: live.nat[i].locked=1; au++;
4547: }
4548: }
4549:
4550: for (i=0;i<N_FREGS;i++) {
4551: live.fat[i].touched=0;
4552: live.fat[i].nholds=0;
4553: live.fat[i].locked=0;
4554: }
4555:
4556: touchcnt=1;
4557: m68k_pc_offset=0;
4558: live.flags_in_flags=TRASH;
4559: live.flags_on_stack=VALID;
4560: live.flags_are_important=1;
4561:
4562: raw_fp_init();
4563: }
4564:
4565: static void vinton(int i, uae_s8* vton, int depth)
4566: {
4567: int n;
4568: int rr;
4569:
4570: Dif (vton[i]==-1) {
4571: jit_abort (L"JIT: Asked to load register %d, but nowhere to go\n",i);
4572: }
4573: n=vton[i];
4574: Dif (live.nat[n].nholds>1)
4575: jit_abort (L"vinton");
4576: if (live.nat[n].nholds && depth<N_REGS) {
4577: vinton(live.nat[n].holds[0],vton,depth+1);
4578: }
4579: if (!isinreg(i))
4580: return; /* Oops --- got rid of that one in the recursive calls */
4581: rr=live.state[i].realreg;
4582: if (rr!=n)
4583: mov_nregs(n,rr);
4584: }
4585:
4586: #if USE_MATCHSTATE
4587: /* This is going to be, amongst other things, a more elaborate version of
4588: flush() */
4589: STATIC_INLINE void match_states(smallstate* s)
4590: {
4591: uae_s8 vton[VREGS];
4592: uae_s8 ndone[N_REGS];
4593: int i;
4594: int again=0;
4595:
4596: for (i=0;i<VREGS;i++)
4597: vton[i]=-1;
4598:
4599: for (i=0;i<N_REGS;i++)
4600: if (s->nat[i].validsize)
4601: vton[s->nat[i].holds]=i;
4602:
4603: flush_flags(); /* low level */
4604: sync_m68k_pc(); /* mid level */
4605:
4606: /* We don't do FREGS yet, so this is raw flush() code */
4607: for (i=0;i<VFREGS;i++) {
4608: if (live.fate[i].needflush==NF_SCRATCH ||
4609: live.fate[i].status==CLEAN) {
4610: f_disassociate(i);
4611: }
4612: }
4613: for (i=0;i<VFREGS;i++) {
4614: if (live.fate[i].needflush==NF_TOMEM &&
4615: live.fate[i].status==DIRTY) {
4616: f_evict(i);
4617: }
4618: }
4619: raw_fp_cleanup_drop();
4620:
4621: /* Now comes the fun part. First, we need to remove all offsets */
4622: for (i=0;i<VREGS;i++)
4623: if (!isconst(i) && live.state[i].val)
4624: remove_offset(i,-1);
4625:
4626: /* Next, we evict everything that does not end up in registers,
4627: write back overly dirty registers, and write back constants */
4628: for (i=0;i<VREGS;i++) {
4629: switch (live.state[i].status) {
4630: case ISCONST:
4631: if (i!=PC_P)
4632: writeback_const(i);
4633: break;
4634: case DIRTY:
4635: if (vton[i]==-1) {
4636: evict(i);
4637: break;
4638: }
4639: if (live.state[i].dirtysize>s->nat[vton[i]].dirtysize)
4640: tomem(i);
4641: /* Fall-through! */
4642: case CLEAN:
4643: if (vton[i]==-1 ||
4644: live.state[i].validsize<s->nat[vton[i]].validsize)
4645: evict(i);
4646: else
4647: make_exclusive(i,0,-1);
4648: break;
4649: case INMEM:
4650: break;
4651: case UNDEF:
4652: break;
4653: default:
4654: write_log (L"JIT: Weird status: %d\n",live.state[i].status);
4655: abort();
4656: }
4657: }
4658:
4659: /* Quick consistency check */
4660: for (i=0;i<VREGS;i++) {
4661: if (isinreg(i)) {
4662: int n=live.state[i].realreg;
4663:
4664: if (live.nat[n].nholds!=1) {
4665: write_log (L"JIT: Register %d isn't alone in nreg %d\n",
4666: i,n);
4667: abort();
4668: }
4669: if (vton[i]==-1) {
4670: write_log (L"JIT: Register %d is still in register, shouldn't be\n",
4671: i);
4672: abort();
4673: }
4674: }
4675: }
4676:
4677: /* Now we need to shuffle things around so the VREGs are in the
4678: right N_REGs. */
4679: for (i=0;i<VREGS;i++) {
4680: if (isinreg(i) && vton[i]!=live.state[i].realreg)
4681: vinton(i,vton,0);
4682: }
4683:
4684: /* And now we may need to load some registers from memory */
4685: for (i=0;i<VREGS;i++) {
4686: int n=vton[i];
4687: if (n==-1) {
4688: Dif (isinreg(i)) {
4689: write_log (L"JIT: Register %d unexpectedly in nreg %d\n",
4690: i,live.state[i].realreg);
4691: abort();
4692: }
4693: }
4694: else {
4695: switch(live.state[i].status) {
4696: case CLEAN:
4697: case DIRTY:
4698: Dif (n!=live.state[i].realreg)
4699: abort();
4700: break;
4701: case INMEM:
4702: Dif (live.nat[n].nholds) {
4703: write_log (L"JIT: natreg %d holds %d vregs, should be empty\n",
4704: n,live.nat[n].nholds);
4705: }
4706: raw_mov_l_rm(n,(uae_u32)live.state[i].mem);
4707: live.state[i].validsize=4;
4708: live.state[i].dirtysize=0;
4709: live.state[i].realreg=n;
4710: live.state[i].realind=0;
4711: live.state[i].val=0;
4712: live.state[i].is_swapped=0;
4713: live.nat[n].nholds=1;
4714: live.nat[n].holds[0]=i;
4715:
4716: set_status(i,CLEAN);
4717: break;
4718: case ISCONST:
4719: if (i!=PC_P) {
4720: write_log (L"JIT: Got constant in matchstate for reg %d. Bad!\n",i);
4721: abort();
4722: }
4723: break;
4724: case UNDEF:
4725: break;
4726: }
4727: }
4728: }
4729:
4730: /* One last consistency check, and adjusting the states in live
4731: to those in s */
4732: for (i=0;i<VREGS;i++) {
4733: int n=vton[i];
4734: switch(live.state[i].status) {
4735: case INMEM:
4736: if (n!=-1)
4737: abort();
4738: break;
4739: case ISCONST:
4740: if (i!=PC_P)
4741: abort();
4742: break;
4743: case CLEAN:
4744: case DIRTY:
4745: if (n==-1)
4746: abort();
4747: if (live.state[i].dirtysize>s->nat[n].dirtysize)
4748: abort;
4749: if (live.state[i].validsize<s->nat[n].validsize)
4750: abort;
4751: live.state[i].dirtysize=s->nat[n].dirtysize;
4752: live.state[i].validsize=s->nat[n].validsize;
4753: if (live.state[i].dirtysize)
4754: set_status(i,DIRTY);
4755: break;
4756: case UNDEF:
4757: break;
4758: }
4759: if (n!=-1)
4760: live.nat[n].touched=touchcnt++;
4761: }
4762: }
4763: #else
4764: STATIC_INLINE void match_states(smallstate* s)
4765: {
4766: flush(1);
4767: }
4768: #endif
4769:
4770: /* Only do this if you really mean it! The next call should be to init!*/
4771: void flush(int save_regs)
4772: {
4773: int i;
4774:
4775: log_flush();
4776: flush_flags(); /* low level */
4777: sync_m68k_pc(); /* mid level */
4778:
4779: if (save_regs) {
4780: for (i=0;i<VFREGS;i++) {
4781: if (live.fate[i].needflush==NF_SCRATCH ||
4782: live.fate[i].status==CLEAN) {
4783: f_disassociate(i);
4784: }
4785: }
4786: for (i=0;i<VREGS;i++) {
4787: if (live.state[i].needflush==NF_TOMEM) {
4788: switch(live.state[i].status) {
4789: case INMEM:
4790: if (live.state[i].val) {
4791: raw_add_l_mi((uae_u32)live.state[i].mem,live.state[i].val);
4792: live.state[i].val=0;
4793: }
4794: break;
4795: case CLEAN:
4796: case DIRTY:
4797: remove_offset(i,-1); tomem(i); break;
4798: case ISCONST:
4799: if (i!=PC_P)
4800: writeback_const(i);
4801: break;
4802: default: break;
4803: }
4804: Dif (live.state[i].val && i!=PC_P) {
4805: write_log (L"JIT: Register %d still has val %x\n",
4806: i,live.state[i].val);
4807: }
4808: }
4809: }
4810: for (i=0;i<VFREGS;i++) {
4811: if (live.fate[i].needflush==NF_TOMEM &&
4812: live.fate[i].status==DIRTY) {
4813: f_evict(i);
4814: }
4815: }
4816: raw_fp_cleanup_drop();
4817: }
4818: if (needflags) {
4819: write_log (L"JIT: Warning! flush with needflags=1!\n");
4820: }
4821:
4822: lopt_emit_all();
4823: }
4824:
4825: static void flush_keepflags(void)
4826: {
4827: int i;
4828:
4829: for (i=0;i<VFREGS;i++) {
4830: if (live.fate[i].needflush==NF_SCRATCH ||
4831: live.fate[i].status==CLEAN) {
4832: f_disassociate(i);
4833: }
4834: }
4835: for (i=0;i<VREGS;i++) {
4836: if (live.state[i].needflush==NF_TOMEM) {
4837: switch(live.state[i].status) {
4838: case INMEM:
4839: /* Can't adjust the offset here --- that needs "add" */
4840: break;
4841: case CLEAN:
4842: case DIRTY:
4843: remove_offset(i,-1); tomem(i); break;
4844: case ISCONST:
4845: if (i!=PC_P)
4846: writeback_const(i);
4847: break;
4848: default: break;
4849: }
4850: }
4851: }
4852: for (i=0;i<VFREGS;i++) {
4853: if (live.fate[i].needflush==NF_TOMEM &&
4854: live.fate[i].status==DIRTY) {
4855: f_evict(i);
4856: }
4857: }
4858: raw_fp_cleanup_drop();
4859: lopt_emit_all();
4860: }
4861:
4862: void freescratch(void)
4863: {
4864: int i;
4865: for (i=0;i<N_REGS;i++)
4866: if (live.nat[i].locked && i!=4)
4867: write_log (L"JIT: Warning! %d is locked\n",i);
4868:
4869: for (i=0;i<VREGS;i++)
4870: if (live.state[i].needflush==NF_SCRATCH) {
4871: forget_about(i);
4872: }
4873:
4874: for (i=0;i<VFREGS;i++)
4875: if (live.fate[i].needflush==NF_SCRATCH) {
4876: f_forget_about(i);
4877: }
4878: }
4879:
4880: /********************************************************************
4881: * Support functions, internal *
4882: ********************************************************************/
4883:
4884:
4885: static void align_target(uae_u32 a)
4886: {
4887: lopt_emit_all();
4888: /* Fill with NOPs --- makes debugging with gdb easier */
4889: while ((uae_u32)target&(a-1))
4890: *target++=0x90;
4891: }
4892:
4893: extern uae_u8* kickmemory;
4894: STATIC_INLINE int isinrom(uae_u32 addr)
4895: {
4896: return (addr>=(uae_u32)kickmemory &&
4897: addr<(uae_u32)kickmemory+8*65536);
4898: }
4899:
4900: static void flush_all(void)
4901: {
4902: int i;
4903:
4904: log_flush();
4905: for (i=0;i<VREGS;i++)
4906: if (live.state[i].status==DIRTY) {
4907: if (!call_saved[live.state[i].realreg]) {
4908: tomem(i);
4909: }
4910: }
4911: for (i=0;i<VFREGS;i++)
4912: if (f_isinreg(i))
4913: f_evict(i);
4914: raw_fp_cleanup_drop();
4915: }
4916:
4917: /* Make sure all registers that will get clobbered by a call are
4918: save and sound in memory */
4919: static void prepare_for_call_1(void)
4920: {
4921: flush_all(); /* If there are registers that don't get clobbered,
4922: * we should be a bit more selective here */
4923: }
4924:
4925: /* We will call a C routine in a moment. That will clobber all registers,
4926: so we need to disassociate everything */
4927: static void prepare_for_call_2(void)
4928: {
4929: int i;
4930: for (i=0;i<N_REGS;i++)
4931: if (!call_saved[i] && live.nat[i].nholds>0)
4932: free_nreg(i);
4933:
4934: for (i=0;i<N_FREGS;i++)
4935: if (live.fat[i].nholds>0)
4936: f_free_nreg(i);
4937:
4938: live.flags_in_flags=TRASH; /* Note: We assume we already rescued the
4939: flags at the very start of the call_r
4940: functions! */
4941: }
4942:
4943:
4944: /********************************************************************
4945: * Memory access and related functions, CREATE time *
4946: ********************************************************************/
4947:
4948: void register_branch(uae_u32 not_taken, uae_u32 taken, uae_u8 cond)
4949: {
4950: next_pc_p=not_taken;
4951: taken_pc_p=taken;
4952: branch_cc=cond;
4953: }
4954:
4955: static uae_u32 get_handler_address(uae_u32 addr)
4956: {
4957: uae_u32 cl=cacheline(addr);
4958: blockinfo* bi=get_blockinfo_addr_new((void*)addr,0);
4959:
4960: #if USE_OPTIMIZER
4961: if (!bi && reg_alloc_run)
4962: return 0;
4963: #endif
4964: return (uae_u32)&(bi->direct_handler_to_use);
4965: }
4966:
4967: static uae_u32 get_handler(uae_u32 addr)
4968: {
4969: uae_u32 cl=cacheline(addr);
4970: blockinfo* bi=get_blockinfo_addr_new((void*)addr,0);
4971:
4972: #if USE_OPTIMIZER
4973: if (!bi && reg_alloc_run)
4974: return 0;
4975: #endif
4976: return (uae_u32)bi->direct_handler_to_use;
4977: }
4978:
4979: static void load_handler(int reg, uae_u32 addr)
4980: {
4981: mov_l_rm(reg,get_handler_address(addr));
4982: }
4983:
4984: /* This version assumes that it is writing *real* memory, and *will* fail
4985: * if that assumption is wrong! No branches, no second chances, just
4986: * straight go-for-it attitude */
4987:
4988: static void writemem_real(int address, int source, int offset, int size, int tmp, int clobber)
4989: {
4990: int f=tmp;
4991:
4992: #ifdef NATMEM_OFFSET
4993: if (canbang) { /* Woohoo! go directly at the memory! */
4994: if (clobber)
4995: f=source;
4996: switch(size) {
4997: case 1: mov_b_bRr(address,source,NATMEM_OFFSETX); break;
4998: case 2: mov_w_rr(f,source); gen_bswap_16(f); mov_w_bRr(address,f,NATMEM_OFFSETX); break;
4999: case 4: mov_l_rr(f,source); gen_bswap_32(f); mov_l_bRr(address,f,NATMEM_OFFSETX); break;
5000: }
5001: forget_about(tmp);
5002: forget_about(f);
5003: return;
5004: }
5005: #endif
5006:
5007: mov_l_rr(f,address);
5008: shrl_l_ri(f,16); /* The index into the baseaddr table */
5009: mov_l_rm_indexed(f,(uae_u32)(baseaddr),f);
5010:
5011: if (address==source) { /* IBrowse does this! */
5012: if (size > 1) {
5013: add_l(f,address); /* f now holds the final address */
5014: switch (size) {
5015: case 2: gen_bswap_16(source); mov_w_Rr(f,source,0);
5016: gen_bswap_16(source); return;
5017: case 4: gen_bswap_32(source); mov_l_Rr(f,source,0);
5018: gen_bswap_32(source); return;
5019: }
5020: }
5021: }
5022: switch (size) { /* f now holds the offset */
5023: case 1: mov_b_mrr_indexed(address,f,source); break;
5024: case 2: gen_bswap_16(source); mov_w_mrr_indexed(address,f,source);
5025: gen_bswap_16(source); break; /* base, index, source */
5026: case 4: gen_bswap_32(source); mov_l_mrr_indexed(address,f,source);
5027: gen_bswap_32(source); break;
5028: }
5029: }
5030:
5031: STATIC_INLINE void writemem(int address, int source, int offset, int size, int tmp)
5032: {
5033: int f=tmp;
5034:
5035: mov_l_rr(f,address);
5036: shrl_l_ri(f,16); /* The index into the mem bank table */
5037: mov_l_rm_indexed(f,(uae_u32)mem_banks,f);
5038: /* Now f holds a pointer to the actual membank */
5039: mov_l_rR(f,f,offset);
5040: /* Now f holds the address of the b/w/lput function */
5041: call_r_02(f,address,source,4,size);
5042: forget_about(tmp);
5043: }
5044:
5045: void writebyte(int address, int source, int tmp)
5046: {
5047: int distrust;
5048: switch (currprefs.comptrustbyte) {
5049: case 0: distrust=0; break;
5050: case 1: distrust=1; break;
5051: case 2: distrust=((start_pc&0xF80000)==0xF80000); break;
5052: case 3: distrust=!have_done_picasso; break;
5053: default: abort();
5054: }
5055:
5056: if ((special_mem&S_WRITE) || distrust)
5057: writemem_special(address,source,20,1,tmp);
5058: else
5059: writemem_real(address,source,20,1,tmp,0);
5060: }
5061:
5062: STATIC_INLINE void writeword_general(int address, int source, int tmp,
5063: int clobber)
5064: {
5065: int distrust;
5066: switch (currprefs.comptrustword) {
5067: case 0: distrust=0; break;
5068: case 1: distrust=1; break;
5069: case 2: distrust=((start_pc&0xF80000)==0xF80000); break;
5070: case 3: distrust=!have_done_picasso; break;
5071: default: abort();
5072: }
5073:
5074: if ((special_mem&S_WRITE) || distrust)
5075: writemem_special(address,source,16,2,tmp);
5076: else
5077: writemem_real(address,source,16,2,tmp,clobber);
5078: }
5079:
5080: void writeword_clobber(int address, int source, int tmp)
5081: {
5082: writeword_general(address,source,tmp,1);
5083: }
5084:
5085: void writeword(int address, int source, int tmp)
5086: {
5087: writeword_general(address,source,tmp,0);
5088: }
5089:
5090: STATIC_INLINE void writelong_general(int address, int source, int tmp,
5091: int clobber)
5092: {
5093: int distrust;
5094: switch (currprefs.comptrustlong) {
5095: case 0: distrust=0; break;
5096: case 1: distrust=1; break;
5097: case 2: distrust=((start_pc&0xF80000)==0xF80000); break;
5098: case 3: distrust=!have_done_picasso; break;
5099: default: abort();
5100: }
5101:
5102: if ((special_mem&S_WRITE) || distrust)
5103: writemem_special(address,source,12,4,tmp);
5104: else
5105: writemem_real(address,source,12,4,tmp,clobber);
5106: }
5107:
5108: void writelong_clobber(int address, int source, int tmp)
5109: {
5110: writelong_general(address,source,tmp,1);
5111: }
5112:
5113: void writelong(int address, int source, int tmp)
5114: {
5115: writelong_general(address,source,tmp,0);
5116: }
5117:
5118:
5119:
5120: /* This version assumes that it is reading *real* memory, and *will* fail
5121: * if that assumption is wrong! No branches, no second chances, just
5122: * straight go-for-it attitude */
5123:
5124: static void readmem_real(int address, int dest, int offset, int size, int tmp)
5125: {
5126: int f=tmp;
5127:
5128: if (size==4 && address!=dest)
5129: f=dest;
5130:
5131: #ifdef NATMEM_OFFSET
5132: if (canbang) { /* Woohoo! go directly at the memory! */
5133: switch(size) {
5134: case 1: mov_b_brR(dest,address,NATMEM_OFFSETX); break;
5135: case 2: mov_w_brR(dest,address,NATMEM_OFFSETX); gen_bswap_16(dest); break;
5136: case 4: mov_l_brR(dest,address,NATMEM_OFFSETX); gen_bswap_32(dest); break;
5137: }
5138: forget_about(tmp);
5139: return;
5140: }
5141: #endif
5142:
5143: mov_l_rr(f,address);
5144: shrl_l_ri(f,16); /* The index into the baseaddr table */
5145: mov_l_rm_indexed(f,(uae_u32)baseaddr,f);
5146: /* f now holds the offset */
5147:
5148: switch(size) {
5149: case 1: mov_b_rrm_indexed(dest,address,f); break;
5150: case 2: mov_w_rrm_indexed(dest,address,f); gen_bswap_16(dest); break;
5151: case 4: mov_l_rrm_indexed(dest,address,f); gen_bswap_32(dest); break;
5152: }
5153: forget_about(tmp);
5154: }
5155:
5156:
5157:
5158: STATIC_INLINE void readmem(int address, int dest, int offset, int size, int tmp)
5159: {
5160: int f=tmp;
5161:
5162: mov_l_rr(f,address);
5163: shrl_l_ri(f,16); /* The index into the mem bank table */
5164: mov_l_rm_indexed(f,(uae_u32)mem_banks,f);
5165: /* Now f holds a pointer to the actual membank */
5166: mov_l_rR(f,f,offset);
5167: /* Now f holds the address of the b/w/lget function */
5168: call_r_11(dest,f,address,size,4);
5169: forget_about(tmp);
5170: }
5171:
5172: void readbyte(int address, int dest, int tmp)
5173: {
5174: int distrust;
5175: switch (currprefs.comptrustbyte) {
5176: case 0: distrust=0; break;
5177: case 1: distrust=1; break;
5178: case 2: distrust=((start_pc&0xF80000)==0xF80000); break;
5179: case 3: distrust=!have_done_picasso; break;
5180: default: abort();
5181: }
5182:
5183: if ((special_mem&S_READ) || distrust)
5184: readmem_special(address,dest,8,1,tmp);
5185: else
5186: readmem_real(address,dest,8,1,tmp);
5187: }
5188:
5189: void readword(int address, int dest, int tmp)
5190: {
5191: int distrust;
5192: switch (currprefs.comptrustword) {
5193: case 0: distrust=0; break;
5194: case 1: distrust=1; break;
5195: case 2: distrust=((start_pc&0xF80000)==0xF80000); break;
5196: case 3: distrust=!have_done_picasso; break;
5197: default: abort();
5198: }
5199:
5200: if ((special_mem&S_READ) || distrust)
5201: readmem_special(address,dest,4,2,tmp);
5202: else
5203: readmem_real(address,dest,4,2,tmp);
5204: }
5205:
5206: void readlong(int address, int dest, int tmp)
5207: {
5208: int distrust;
5209: switch (currprefs.comptrustlong) {
5210: case 0: distrust=0; break;
5211: case 1: distrust=1; break;
5212: case 2: distrust=((start_pc&0xF80000)==0xF80000); break;
5213: case 3: distrust=!have_done_picasso; break;
5214: default: abort();
5215: }
5216:
5217: if ((special_mem&S_READ) || distrust)
5218: readmem_special(address,dest,0,4,tmp);
5219: else
5220: readmem_real(address,dest,0,4,tmp);
5221: }
5222:
5223:
5224:
5225: /* This one might appear a bit odd... */
5226: STATIC_INLINE void get_n_addr_old(int address, int dest, int tmp)
5227: {
5228: readmem(address,dest,24,4,tmp);
5229: }
5230:
5231: STATIC_INLINE void get_n_addr_real(int address, int dest, int tmp)
5232: {
5233: int f=tmp;
5234: if (address!=dest)
5235: f=dest;
5236:
5237: #ifdef NATMEM_OFFSET
5238: if (canbang) {
5239: lea_l_brr(dest,address,NATMEM_OFFSETX);
5240: forget_about(tmp);
5241: return;
5242: }
5243: #endif
5244: mov_l_rr(f,address);
5245: mov_l_rr(dest,address); // gb-- nop if dest==address
5246: shrl_l_ri(f,16);
5247: mov_l_rm_indexed(f,(uae_u32)baseaddr,f);
5248: add_l(dest,f);
5249: forget_about(tmp);
5250: }
5251:
5252: void get_n_addr(int address, int dest, int tmp)
5253: {
5254: int distrust;
5255: switch (currprefs.comptrustnaddr) {
5256: case 0: distrust=0; break;
5257: case 1: distrust=1; break;
5258: case 2: distrust=((start_pc&0xF80000)==0xF80000); break;
5259: case 3: distrust=!have_done_picasso; break;
5260: default: abort();
5261: }
5262:
5263: if (special_mem || distrust)
5264: get_n_addr_old(address,dest,tmp);
5265: else
5266: get_n_addr_real(address,dest,tmp);
5267: }
5268:
5269: void get_n_addr_jmp(int address, int dest, int tmp)
5270: {
5271: #if 0 /* For this, we need to get the same address as the rest of UAE
5272: would --- otherwise we end up translating everything twice */
5273: get_n_addr(address,dest,tmp);
5274: #else
5275: int f=tmp;
5276: if (address!=dest)
5277: f=dest;
5278: mov_l_rr(f,address);
5279: shrl_l_ri(f,16); /* The index into the baseaddr bank table */
5280: mov_l_rm_indexed(dest,(uae_u32)baseaddr,f);
5281: add_l(dest,address);
5282: and_l_ri (dest, ~1);
5283: forget_about(tmp);
5284: #endif
5285: }
5286:
5287: /* base, target and tmp are registers, but dp is the actual opcode extension word */
5288: void calc_disp_ea_020(int base, uae_u32 dp, int target, int tmp)
5289: {
5290: int reg = (dp >> 12) & 15;
5291: int regd_shift=(dp >> 9) & 3;
5292:
5293: if (dp & 0x100) {
5294: int ignorebase=(dp&0x80);
5295: int ignorereg=(dp&0x40);
5296: int addbase=0;
5297: int outer=0;
5298:
5299: if ((dp & 0x30) == 0x20) addbase = (uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
5300: if ((dp & 0x30) == 0x30) addbase = comp_get_ilong((m68k_pc_offset+=4)-4);
5301:
5302: if ((dp & 0x3) == 0x2) outer = (uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
5303: if ((dp & 0x3) == 0x3) outer = comp_get_ilong((m68k_pc_offset+=4)-4);
5304:
5305: if ((dp & 0x4) == 0) { /* add regd *before* the get_long */
5306: if (!ignorereg) {
5307: if ((dp & 0x800) == 0)
5308: sign_extend_16_rr(target,reg);
5309: else
5310: mov_l_rr(target,reg);
5311: shll_l_ri(target,regd_shift);
5312: }
5313: else
5314: mov_l_ri(target,0);
5315:
5316: /* target is now regd */
5317: if (!ignorebase)
5318: add_l(target,base);
5319: add_l_ri(target,addbase);
5320: if (dp&0x03) readlong(target,target,tmp);
5321: } else { /* do the getlong first, then add regd */
5322: if (!ignorebase) {
5323: mov_l_rr(target,base);
5324: add_l_ri(target,addbase);
5325: }
5326: else
5327: mov_l_ri(target,addbase);
5328: if (dp&0x03) readlong(target,target,tmp);
5329:
5330: if (!ignorereg) {
5331: if ((dp & 0x800) == 0)
5332: sign_extend_16_rr(tmp,reg);
5333: else
5334: mov_l_rr(tmp,reg);
5335: shll_l_ri(tmp,regd_shift);
5336: /* tmp is now regd */
5337: add_l(target,tmp);
5338: }
5339: }
5340: add_l_ri(target,outer);
5341: }
5342: else { /* 68000 version */
5343: if ((dp & 0x800) == 0) { /* Sign extend */
5344: sign_extend_16_rr(target,reg);
5345: lea_l_brr_indexed(target,base,target,regd_shift,(uae_s32)(uae_s8)dp);
5346: }
5347: else {
5348: lea_l_brr_indexed(target,base,reg,regd_shift,(uae_s32)(uae_s8)dp);
5349: }
5350: }
5351: forget_about(tmp);
5352: }
5353:
5354: STATIC_INLINE unsigned int cft_map (unsigned int f)
5355: {
5356: return ((f >> 8) & 255) | ((f & 255) << 8);
5357: }
5358:
5359: void set_cache_state(int enabled)
5360: {
5361: if (enabled!=letit)
5362: flush_icache_hard(0, 3);
5363: letit=enabled;
5364: }
5365:
5366: int get_cache_state(void)
5367: {
5368: return letit;
5369: }
5370:
5371: uae_u32 get_jitted_size(void)
5372: {
5373: if (compiled_code)
5374: return current_compile_p-compiled_code;
5375: return 0;
5376: }
5377:
5378: void alloc_cache(void)
5379: {
5380: if (compiled_code) {
5381: flush_icache_hard(0, 3);
5382: cache_free(compiled_code);
5383: }
5384: if (veccode == NULL)
5385: veccode = cache_alloc (256);
5386: if (popallspace == NULL)
5387: popallspace = cache_alloc (1024);
5388: compiled_code = NULL;
5389: if (currprefs.cachesize == 0)
5390: return;
5391:
5392: while (!compiled_code && currprefs.cachesize) {
5393: compiled_code=cache_alloc(currprefs.cachesize*1024);
5394: if (!compiled_code)
5395: currprefs.cachesize/=2;
5396: }
5397: if (compiled_code) {
5398: max_compile_start=compiled_code+currprefs.cachesize*1024-BYTES_PER_INST;
5399: current_compile_p=compiled_code;
5400: }
5401: }
5402:
5403: static void calc_checksum(blockinfo* bi, uae_u32* c1, uae_u32* c2)
5404: {
5405: uae_u32 k1=0;
5406: uae_u32 k2=0;
5407: uae_s32 len=bi->len;
5408: uae_u32 tmp=bi->min_pcp;
5409: uae_u32* pos;
5410:
5411: len+=(tmp&3);
5412: tmp&=(~3);
5413: pos=(uae_u32*)tmp;
5414:
5415: if (len<0 || len>MAX_CHECKSUM_LEN) {
5416: *c1=0;
5417: *c2=0;
5418: }
5419: else {
5420: while (len>0) {
5421: k1+=*pos;
5422: k2^=*pos;
5423: pos++;
5424: len-=4;
5425: }
5426: *c1=k1;
5427: *c2=k2;
5428: }
5429: }
5430:
5431: static void show_checksum(blockinfo* bi)
5432: {
5433: uae_u32 k1=0;
5434: uae_u32 k2=0;
5435: uae_s32 len=bi->len;
5436: uae_u32 tmp=(uae_u32)bi->pc_p;
5437: uae_u32* pos;
5438:
5439: len+=(tmp&3);
5440: tmp&=(~3);
5441: pos=(uae_u32*)tmp;
5442:
5443: if (len<0 || len>MAX_CHECKSUM_LEN) {
5444: return;
5445: }
5446: else {
5447: while (len>0) {
5448: write_log (L"%08x ",*pos);
5449: pos++;
5450: len-=4;
5451: }
5452: write_log (L" bla\n");
5453: }
5454: }
5455:
5456:
5457: int check_for_cache_miss(void)
5458: {
5459: blockinfo* bi=get_blockinfo_addr(regs.pc_p);
5460:
5461: if (bi) {
5462: int cl=cacheline(regs.pc_p);
5463: if (bi!=cache_tags[cl+1].bi) {
5464: raise_in_cl_list(bi);
5465: return 1;
5466: }
5467: }
5468: return 0;
5469: }
5470:
5471:
5472: static void recompile_block(void)
5473: {
5474: /* An existing block's countdown code has expired. We need to make
5475: sure that execute_normal doesn't refuse to recompile due to a
5476: perceived cache miss... */
5477: blockinfo* bi=get_blockinfo_addr(regs.pc_p);
5478:
5479: Dif (!bi)
5480: jit_abort (L"recompile_block");
5481: raise_in_cl_list(bi);
5482: execute_normal();
5483: return;
5484: }
5485:
5486: static void cache_miss(void)
5487: {
5488: blockinfo* bi=get_blockinfo_addr(regs.pc_p);
5489: uae_u32 cl=cacheline(regs.pc_p);
5490: blockinfo* bi2=get_blockinfo(cl);
5491:
5492: if (!bi) {
5493: execute_normal(); /* Compile this block now */
5494: return;
5495: }
5496: Dif (!bi2 || bi==bi2) {
5497: jit_abort (L"Unexplained cache miss %p %p\n",bi,bi2);
5498: }
5499: raise_in_cl_list(bi);
5500: return;
5501: }
5502:
5503: static void check_checksum(void)
5504: {
5505: blockinfo* bi=get_blockinfo_addr(regs.pc_p);
5506: uae_u32 cl=cacheline(regs.pc_p);
5507: blockinfo* bi2=get_blockinfo(cl);
5508:
5509: uae_u32 c1,c2;
5510:
5511: checksum_count++;
5512: /* These are not the droids you are looking for... */
5513: if (!bi) {
5514: /* Whoever is the primary target is in a dormant state, but
5515: calling it was accidental, and we should just compile this
5516: new block */
5517: execute_normal();
5518: return;
5519: }
5520: if (bi!=bi2) {
5521: /* The block was hit accidentally, but it does exist. Cache miss */
5522: cache_miss();
5523: return;
5524: }
5525:
5526: if (bi->c1 || bi->c2)
5527: calc_checksum(bi,&c1,&c2);
5528: else {
5529: c1=c2=1; /* Make sure it doesn't match */
5530: }
5531: if (c1==bi->c1 && c2==bi->c2) {
5532: /* This block is still OK. So we reactivate. Of course, that
5533: means we have to move it into the needs-to-be-flushed list */
5534: bi->handler_to_use=bi->handler;
5535: set_dhtu(bi,bi->direct_handler);
5536:
5537: /* write_log (L"JIT: reactivate %p/%p (%x %x/%x %x)\n",bi,bi->pc_p,
5538: c1,c2,bi->c1,bi->c2);*/
5539: remove_from_list(bi);
5540: add_to_active(bi);
5541: raise_in_cl_list(bi);
5542: }
5543: else {
5544: /* This block actually changed. We need to invalidate it,
5545: and set it up to be recompiled */
5546: /* write_log (L"JIT: discard %p/%p (%x %x/%x %x)\n",bi,bi->pc_p,
5547: c1,c2,bi->c1,bi->c2); */
5548: invalidate_block(bi);
5549: raise_in_cl_list(bi);
5550: execute_normal();
5551: }
5552: }
5553:
5554:
5555: STATIC_INLINE void create_popalls(void)
5556: {
5557: int i,r;
5558:
5559: current_compile_p=popallspace;
5560: set_target(current_compile_p);
5561: #if USE_PUSH_POP
5562: /* If we can't use gcc inline assembly, we need to pop some
5563: registers before jumping back to the various get-out routines.
5564: This generates the code for it.
5565: */
5566: popall_do_nothing=current_compile_p;
5567: for (i=0;i<N_REGS;i++) {
5568: if (need_to_preserve[i])
5569: raw_pop_l_r(i);
5570: }
5571: raw_jmp((uae_u32)do_nothing);
5572: align_target(32);
5573:
5574: popall_execute_normal=get_target();
5575: for (i=0;i<N_REGS;i++) {
5576: if (need_to_preserve[i])
5577: raw_pop_l_r(i);
5578: }
5579: raw_jmp((uae_u32)execute_normal);
5580: align_target(32);
5581:
5582: popall_cache_miss=get_target();
5583: for (i=0;i<N_REGS;i++) {
5584: if (need_to_preserve[i])
5585: raw_pop_l_r(i);
5586: }
5587: raw_jmp((uae_u32)cache_miss);
5588: align_target(32);
5589:
5590: popall_recompile_block=get_target();
5591: for (i=0;i<N_REGS;i++) {
5592: if (need_to_preserve[i])
5593: raw_pop_l_r(i);
5594: }
5595: raw_jmp((uae_u32)recompile_block);
5596: align_target(32);
5597:
5598: popall_exec_nostats=get_target();
5599: for (i=0;i<N_REGS;i++) {
5600: if (need_to_preserve[i])
5601: raw_pop_l_r(i);
5602: }
5603: raw_jmp((uae_u32)exec_nostats);
5604: align_target(32);
5605:
5606: popall_check_checksum=get_target();
5607: for (i=0;i<N_REGS;i++) {
5608: if (need_to_preserve[i])
5609: raw_pop_l_r(i);
5610: }
5611: raw_jmp((uae_u32)check_checksum);
5612: align_target(32);
5613:
5614: current_compile_p=get_target();
5615: #else
5616: popall_exec_nostats=exec_nostats;
5617: popall_execute_normal=execute_normal;
5618: popall_cache_miss=cache_miss;
5619: popall_recompile_block=recompile_block;
5620: popall_do_nothing=do_nothing;
5621: popall_check_checksum=check_checksum;
5622: #endif
5623:
5624: /* And now, the code to do the matching pushes and then jump
5625: into a handler routine */
5626: pushall_call_handler=get_target();
5627: #if USE_PUSH_POP
5628: for (i=N_REGS;i--;) {
5629: if (need_to_preserve[i])
5630: raw_push_l_r(i);
5631: }
5632: #endif
5633: r=REG_PC_TMP;
5634: raw_mov_l_rm(r,(uae_u32)®s.pc_p);
5635: raw_and_l_ri(r,TAGMASK);
5636: raw_jmp_m_indexed((uae_u32)cache_tags,r,4);
5637: }
5638:
5639: STATIC_INLINE void reset_lists(void)
5640: {
5641: int i;
5642:
5643: for (i=0;i<MAX_HOLD_BI;i++)
5644: hold_bi[i]=NULL;
5645: active=NULL;
5646: dormant=NULL;
5647: }
5648:
5649: static void prepare_block(blockinfo* bi)
5650: {
5651: int i;
5652:
5653: set_target(current_compile_p);
5654: align_target(32);
5655: bi->direct_pen=(cpuop_func*)get_target();
5656: raw_mov_l_rm(0,(uae_u32)&(bi->pc_p));
5657: raw_mov_l_mr((uae_u32)®s.pc_p,0);
5658: raw_jmp((uae_u32)popall_execute_normal);
5659:
5660: align_target(32);
5661: bi->direct_pcc=(cpuop_func*)get_target();
5662: raw_mov_l_rm(0,(uae_u32)&(bi->pc_p));
5663: raw_mov_l_mr((uae_u32)®s.pc_p,0);
5664: raw_jmp((uae_u32)popall_check_checksum);
5665:
5666: align_target(32);
5667: current_compile_p=get_target();
5668:
5669: bi->deplist=NULL;
5670: for (i=0;i<2;i++) {
5671: bi->dep[i].prev_p=NULL;
5672: bi->dep[i].next=NULL;
5673: }
5674: bi->env=default_ss;
5675: bi->status=BI_NEW;
5676: bi->havestate=0;
5677: //bi->env=empty_ss;
5678: }
5679:
5680: void compemu_reset(void)
5681: {
5682: set_cache_state(0);
5683: }
5684:
5685: void build_comp(void)
5686: {
5687: int i;
5688: int jumpcount=0;
5689: unsigned long opcode;
5690: const struct comptbl* tbl=op_smalltbl_0_comp_ff;
5691: const struct comptbl* nftbl=op_smalltbl_0_comp_nf;
5692: int count;
5693: #ifdef NOFLAGS_SUPPORT
5694: struct comptbl *nfctbl = (currprefs.cpu_level >= 5 ? op_smalltbl_0_nf
5695: : currprefs.cpu_level == 4 ? op_smalltbl_1_nf
5696: : (currprefs.cpu_level == 2 || currprefs.cpu_level == 3) ? op_smalltbl_2_nf
5697: : currprefs.cpu_level == 1 ? op_smalltbl_3_nf
5698: : ! currprefs.cpu_compatible ? op_smalltbl_4_nf
5699: : op_smalltbl_5_nf);
5700: #endif
5701: raw_init_cpu();
5702: #ifdef NATMEM_OFFSET
5703: write_log (L"JIT: Setting signal handler\n");
5704: #ifndef _WIN32
5705: signal(SIGSEGV,vec);
5706: #endif
5707: #endif
5708: write_log (L"JIT: Building Compiler function table\n");
5709: for (opcode = 0; opcode < 65536; opcode++) {
5710: #ifdef NOFLAGS_SUPPORT
5711: nfcpufunctbl[opcode] = op_illg;
5712: #endif
5713: compfunctbl[opcode] = NULL;
5714: nfcompfunctbl[opcode] = NULL;
5715: prop[opcode].use_flags = 0x1f;
5716: prop[opcode].set_flags = 0x1f;
5717: prop[opcode].is_jump=1;
5718: }
5719:
5720: for (i = 0; tbl[i].opcode < 65536; i++) {
5721: int isjmp=(tbl[i].specific&1);
5722: int isaddx=(tbl[i].specific&8);
5723: int iscjmp=(tbl[i].specific&16);
5724:
5725: prop[tbl[i].opcode].is_jump=isjmp;
5726: prop[tbl[i].opcode].is_const_jump=iscjmp;
5727: prop[tbl[i].opcode].is_addx=isaddx;
5728: compfunctbl[tbl[i].opcode] = tbl[i].handler;
5729: }
5730: for (i = 0; nftbl[i].opcode < 65536; i++) {
5731: nfcompfunctbl[nftbl[i].opcode] = nftbl[i].handler;
5732: #ifdef NOFLAGS_SUPPORT
5733: nfcpufunctbl[nftbl[i].opcode] = nfctbl[i].handler;
5734: #endif
5735: }
5736:
5737: #ifdef NOFLAGS_SUPPORT
5738: for (i = 0; nfctbl[i].handler; i++) {
5739: nfcpufunctbl[nfctbl[i].opcode] = nfctbl[i].handler;
5740: }
5741: #endif
5742:
5743: for (opcode = 0; opcode < 65536; opcode++) {
5744: compop_func *f;
5745: compop_func *nff;
5746: #ifdef NOFLAGS_SUPPORT
5747: compop_func *nfcf;
5748: #endif
5749: int isjmp,isaddx,iscjmp;
5750: int lvl;
5751:
5752: lvl = (currprefs.cpu_model - 68000) / 10;
5753: if (lvl > 4)
5754: lvl--;
5755: if (table68k[opcode].mnemo == i_ILLG || table68k[opcode].clev > lvl)
5756: continue;
5757:
5758: if (table68k[opcode].handler != -1) {
5759: f = compfunctbl[table68k[opcode].handler];
5760: nff = nfcompfunctbl[table68k[opcode].handler];
5761: #ifdef NOFLAGS_SUPPORT
5762: nfcf = nfcpufunctbl[table68k[opcode].handler];
5763: #endif
5764: isjmp=prop[table68k[opcode].handler].is_jump;
5765: iscjmp=prop[table68k[opcode].handler].is_const_jump;
5766: isaddx=prop[table68k[opcode].handler].is_addx;
5767: prop[opcode].is_jump=isjmp;
5768: prop[opcode].is_const_jump=iscjmp;
5769: prop[opcode].is_addx=isaddx;
5770: compfunctbl[opcode] = f;
5771: nfcompfunctbl[opcode] = nff;
5772: #ifdef NOFLAGS_SUPPORT
5773: Dif (nfcf == op_illg)
5774: abort();
5775: nfcpufunctbl[opcode] = nfcf;
5776: #endif
5777: }
5778: prop[opcode].set_flags =table68k[opcode].flagdead;
5779: prop[opcode].use_flags =table68k[opcode].flaglive;
5780: /* Unconditional jumps don't evaluate condition codes, so they
5781: don't actually use any flags themselves */
5782: if (prop[opcode].is_const_jump)
5783: prop[opcode].use_flags=0;
5784: }
5785: #ifdef NOFLAGS_SUPPORT
5786: for (i = 0; nfctbl[i].handler != NULL; i++) {
5787: if (nfctbl[i].specific)
5788: nfcpufunctbl[tbl[i].opcode] = nfctbl[i].handler;
5789: }
5790: #endif
5791:
5792: count=0;
5793: for (opcode = 0; opcode < 65536; opcode++) {
5794: if (compfunctbl[opcode])
5795: count++;
5796: }
5797: write_log (L"JIT: Supposedly %d compileable opcodes!\n",count);
5798:
5799: /* Initialise state */
5800: alloc_cache();
5801: create_popalls();
5802: reset_lists();
5803:
5804: for (i=0;i<TAGSIZE;i+=2) {
5805: cache_tags[i].handler=(cpuop_func*)popall_execute_normal;
5806: cache_tags[i+1].bi=NULL;
5807: }
5808: compemu_reset();
5809:
5810: for (i=0;i<N_REGS;i++) {
5811: empty_ss.nat[i].holds=-1;
5812: empty_ss.nat[i].validsize=0;
5813: empty_ss.nat[i].dirtysize=0;
5814: }
5815: default_ss=empty_ss;
5816: #if 0
5817: default_ss.nat[6].holds=11;
5818: default_ss.nat[6].validsize=4;
5819: default_ss.nat[5].holds=12;
5820: default_ss.nat[5].validsize=4;
5821: #endif
5822: }
5823:
5824:
5825: static void flush_icache_hard(uae_u32 ptr, int n)
5826: {
5827: blockinfo* bi;
5828:
5829: hard_flush_count++;
5830: #if 0
5831: write_log (L"JIT: Flush Icache_hard(%d/%x/%p), %u instruction bytes\n",
5832: n,regs.pc,regs.pc_p,current_compile_p-compiled_code);
5833: #endif
5834: bi=active;
5835: while(bi) {
5836: cache_tags[cacheline(bi->pc_p)].handler=(cpuop_func*)popall_execute_normal;
5837: cache_tags[cacheline(bi->pc_p)+1].bi=NULL;
5838: bi=bi->next;
5839: }
5840: bi=dormant;
5841: while(bi) {
5842: cache_tags[cacheline(bi->pc_p)].handler=(cpuop_func*)popall_execute_normal;
5843: cache_tags[cacheline(bi->pc_p)+1].bi=NULL;
5844: bi=bi->next;
5845: }
5846:
5847: reset_lists();
5848: if (!compiled_code)
5849: return;
5850: current_compile_p=compiled_code;
5851: set_special(0); /* To get out of compiled code */
5852: }
5853:
5854:
5855: /* "Soft flushing" --- instead of actually throwing everything away,
5856: we simply mark everything as "needs to be checked".
5857: */
5858:
5859: void flush_icache(uaecptr ptr, int n)
5860: {
5861: blockinfo* bi;
5862: blockinfo* bi2;
5863:
5864: if (currprefs.comp_hardflush) {
5865: flush_icache_hard(ptr, n);
5866: return;
5867: }
5868: soft_flush_count++;
5869: if (!active)
5870: return;
5871:
5872: bi=active;
5873: while (bi) {
5874: uae_u32 cl=cacheline(bi->pc_p);
5875: if (!bi->handler) {
5876: /* invalidated block */
5877: if (bi==cache_tags[cl+1].bi)
5878: cache_tags[cl].handler=(cpuop_func*)popall_execute_normal;
5879: bi->handler_to_use=(cpuop_func*)popall_execute_normal;
5880: set_dhtu(bi,bi->direct_pen);
5881: } else {
5882: if (bi==cache_tags[cl+1].bi)
5883: cache_tags[cl].handler=(cpuop_func*)popall_check_checksum;
5884: bi->handler_to_use=(cpuop_func*)popall_check_checksum;
5885: set_dhtu(bi,bi->direct_pcc);
5886: }
5887: bi2=bi;
5888: bi=bi->next;
5889: }
5890: /* bi2 is now the last entry in the active list */
5891: bi2->next=dormant;
5892: if (dormant)
5893: dormant->prev_p=&(bi2->next);
5894:
5895: dormant=active;
5896: active->prev_p=&dormant;
5897: active=NULL;
5898: }
5899:
5900:
5901: static void catastrophe(void)
5902: {
5903: jit_abort (L"catastprophe");
5904: }
5905:
5906: int failure;
5907:
5908:
5909: void compile_block(cpu_history* pc_hist, int blocklen, int totcycles)
5910: {
5911: if (letit && compiled_code && currprefs.cpu_model>=68020) {
5912:
5913: /* OK, here we need to 'compile' a block */
5914: int i;
5915: int r;
5916: int was_comp=0;
5917: uae_u8 liveflags[MAXRUN+1];
5918: uae_u32 max_pcp=(uae_u32)pc_hist[0].location;
5919: uae_u32 min_pcp=max_pcp;
5920: uae_u32 cl=cacheline(pc_hist[0].location);
5921: void* specflags=(void*)®s.spcflags;
5922: blockinfo* bi=NULL;
5923: blockinfo* bi2;
5924: int extra_len=0;
5925:
5926: compile_count++;
5927: if (current_compile_p>=max_compile_start)
5928: flush_icache_hard(0, 3);
5929:
5930: alloc_blockinfos();
5931:
5932: bi=get_blockinfo_addr_new(pc_hist[0].location,0);
5933: bi2=get_blockinfo(cl);
5934:
5935: optlev=bi->optlevel;
5936: if (bi->handler) {
5937: Dif (bi!=bi2) {
5938: /* I don't think it can happen anymore. Shouldn't, in
5939: any case. So let's make sure... */
5940: jit_abort (L"JIT: WOOOWOO count=%d, ol=%d %p %p\n",
5941: bi->count,bi->optlevel,bi->handler_to_use,
5942: cache_tags[cl].handler);
5943: }
5944:
5945: Dif (bi->count!=-1 && bi->status!=BI_TARGETTED) {
5946: /* What the heck? We are not supposed to be here! */
5947: jit_abort (L"BI_TARGETTED");
5948: }
5949: }
5950: if (bi->count==-1) {
5951: optlev++;
5952: while (!currprefs.optcount[optlev])
5953: optlev++;
5954: bi->count=currprefs.optcount[optlev]-1;
5955: }
5956: current_block_pc_p=(uae_u32)pc_hist[0].location;
5957:
5958: remove_deps(bi); /* We are about to create new code */
5959: bi->optlevel=optlev;
5960: bi->pc_p=(uae_u8*)pc_hist[0].location;
5961:
5962: liveflags[blocklen]=0x1f; /* All flags needed afterwards */
5963: i=blocklen;
5964: while (i--) {
5965: uae_u16* currpcp=pc_hist[i].location;
5966: int op=cft_map(*currpcp);
5967:
5968: if ((uae_u32)currpcp<min_pcp)
5969: min_pcp=(uae_u32)currpcp;
5970: if ((uae_u32)currpcp>max_pcp)
5971: max_pcp=(uae_u32)currpcp;
5972:
5973: if (currprefs.compnf) {
5974: liveflags[i]=((liveflags[i+1]&
5975: (~prop[op].set_flags))|
5976: prop[op].use_flags);
5977: if (prop[op].is_addx && (liveflags[i+1]&FLAG_Z)==0)
5978: liveflags[i]&= ~FLAG_Z;
5979: }
5980: else {
5981: liveflags[i]=0x1f;
5982: }
5983: }
5984:
5985: bi->needed_flags=liveflags[0];
5986:
5987: /* This is the non-direct handler */
5988: align_target(32);
5989: set_target(get_target()+1);
5990: align_target(16);
5991: /* Now aligned at n*32+16 */
5992:
5993: bi->handler=
5994: bi->handler_to_use=(cpuop_func*)get_target();
5995: raw_cmp_l_mi((uae_u32)®s.pc_p,(uae_u32)pc_hist[0].location);
5996: raw_jnz((uae_u32)popall_cache_miss);
5997: /* This was 16 bytes on the x86, so now aligned on (n+1)*32 */
5998:
5999: was_comp=0;
6000:
6001: #if USE_MATCHSTATE
6002: comp_pc_p=(uae_u8*)pc_hist[0].location;
6003: init_comp();
6004: match_states(&(bi->env));
6005: was_comp=1;
6006: #endif
6007:
6008: bi->direct_handler=(cpuop_func*)get_target();
6009: set_dhtu(bi,bi->direct_handler);
6010: current_block_start_target=(uae_u32)get_target();
6011:
6012: if (bi->count>=0) { /* Need to generate countdown code */
6013: raw_mov_l_mi((uae_u32)®s.pc_p,(uae_u32)pc_hist[0].location);
6014: raw_sub_l_mi((uae_u32)&(bi->count),1);
6015: raw_jl((uae_u32)popall_recompile_block);
6016: }
6017: if (optlev==0) { /* No need to actually translate */
6018: /* Execute normally without keeping stats */
6019: raw_mov_l_mi((uae_u32)®s.pc_p,(uae_u32)pc_hist[0].location);
6020: raw_jmp((uae_u32)popall_exec_nostats);
6021: }
6022: else {
6023: reg_alloc_run=0;
6024: next_pc_p=0;
6025: taken_pc_p=0;
6026: branch_cc=0;
6027:
6028: log_startblock();
6029: for (i=0;i<blocklen &&
6030: get_target_noopt()<max_compile_start;i++) {
6031: cpuop_func **cputbl;
6032: compop_func **comptbl;
6033: uae_u16 opcode;
6034:
6035: opcode=cft_map((uae_u16)*pc_hist[i].location);
6036: special_mem=pc_hist[i].specmem;
6037: needed_flags=(liveflags[i+1] & prop[opcode].set_flags);
6038: if (!needed_flags && currprefs.compnf) {
6039: #ifdef NOFLAGS_SUPPORT
6040: cputbl=nfcpufunctbl;
6041: #else
6042: cputbl=cpufunctbl;
6043: #endif
6044: comptbl=nfcompfunctbl;
6045: }
6046: else {
6047: cputbl=cpufunctbl;
6048: comptbl=compfunctbl;
6049: }
6050:
6051: if (comptbl[opcode] && optlev>1) {
6052: failure=0;
6053: if (!was_comp) {
6054: comp_pc_p=(uae_u8*)pc_hist[i].location;
6055: init_comp();
6056: }
6057: was_comp++;
6058:
6059: comptbl[opcode](opcode);
6060: freescratch();
6061: if (!(liveflags[i+1] & FLAG_CZNV)) {
6062: /* We can forget about flags */
6063: dont_care_flags();
6064: }
6065: #if INDIVIDUAL_INST
6066: flush(1);
6067: nop();
6068: flush(1);
6069: was_comp=0;
6070: #endif
6071: }
6072: else
6073: failure=1;
6074: if (failure) {
6075: if (was_comp) {
6076: flush(1);
6077: was_comp=0;
6078: }
6079: raw_mov_l_ri(REG_PAR1,(uae_u32)opcode);
6080: raw_mov_l_ri(REG_PAR2,(uae_u32)®s);
6081: #if USE_NORMAL_CALLING_CONVENTION
6082: raw_push_l_r(REG_PAR2);
6083: raw_push_l_r(REG_PAR1);
6084: #endif
6085: raw_mov_l_mi((uae_u32)®s.pc_p,
6086: (uae_u32)pc_hist[i].location);
6087: raw_call((uae_u32)cputbl[opcode]);
6088: //raw_add_l_mi((uae_u32)&oink,1); // FIXME
6089: #if USE_NORMAL_CALLING_CONVENTION
6090: raw_inc_sp(8);
6091: #endif
6092: /*if (needed_flags)
6093: raw_mov_l_mi((uae_u32)&foink3,(uae_u32)opcode+65536);
6094: else
6095: raw_mov_l_mi((uae_u32)&foink3,(uae_u32)opcode);
6096: */
6097:
6098: if (i<blocklen-1) {
6099: uae_s8* branchadd;
6100:
6101: raw_mov_l_rm(0,(uae_u32)specflags);
6102: raw_test_l_rr(0,0);
6103: raw_jz_b_oponly();
6104: branchadd=(uae_s8*)get_target();
6105: emit_byte(0);
6106: raw_sub_l_mi((uae_u32)&countdown,scaled_cycles(totcycles));
6107: raw_jmp((uae_u32)popall_do_nothing);
6108: *branchadd=(uae_u32)get_target()-(uae_u32)branchadd-1;
6109: }
6110: }
6111: }
6112: #if 0 /* This isn't completely kosher yet; It really needs to be
6113: be integrated into a general inter-block-dependency scheme */
6114: if (next_pc_p && taken_pc_p &&
6115: was_comp && taken_pc_p==current_block_pc_p) {
6116: blockinfo* bi1=get_blockinfo_addr_new((void*)next_pc_p,0);
6117: blockinfo* bi2=get_blockinfo_addr_new((void*)taken_pc_p,0);
6118: uae_u8 x=bi1->needed_flags;
6119:
6120: if (x==0xff || 1) { /* To be on the safe side */
6121: uae_u16* next=(uae_u16*)next_pc_p;
6122: uae_u16 op=cft_map(*next);
6123:
6124: x=0x1f;
6125: x&=(~prop[op].set_flags);
6126: x|=prop[op].use_flags;
6127: }
6128:
6129: x|=bi2->needed_flags;
6130: if (!(x & FLAG_CZNV)) {
6131: /* We can forget about flags */
6132: dont_care_flags();
6133: extra_len+=2; /* The next instruction now is part of this
6134: block */
6135: }
6136:
6137: }
6138: #endif
6139:
6140: if (next_pc_p) { /* A branch was registered */
6141: uae_u32 t1=next_pc_p;
6142: uae_u32 t2=taken_pc_p;
6143: int cc=branch_cc;
6144:
6145: uae_u32* branchadd;
6146: uae_u32* tba;
6147: bigstate tmp;
6148: blockinfo* tbi;
6149:
6150: if (taken_pc_p<next_pc_p) {
6151: /* backward branch. Optimize for the "taken" case ---
6152: which means the raw_jcc should fall through when
6153: the 68k branch is taken. */
6154: t1=taken_pc_p;
6155: t2=next_pc_p;
6156: cc=branch_cc^1;
6157: }
6158:
6159: #if !USE_MATCHSTATE
6160: flush_keepflags();
6161: #endif
6162: tmp=live; /* ouch! This is big... */
6163: raw_jcc_l_oponly(cc);
6164: branchadd=(uae_u32*)get_target();
6165: emit_long(0);
6166: /* predicted outcome */
6167: tbi=get_blockinfo_addr_new((void*)t1,1);
6168: match_states(&(tbi->env));
6169: //flush(1); /* Can only get here if was_comp==1 */
6170: raw_sub_l_mi((uae_u32)&countdown,scaled_cycles(totcycles));
6171: raw_jcc_l_oponly(9);
6172: tba=(uae_u32*)get_target();
6173: emit_long(get_handler(t1)-((uae_u32)tba+4));
6174: raw_mov_l_mi((uae_u32)®s.pc_p,t1);
6175: raw_jmp((uae_u32)popall_do_nothing);
6176: create_jmpdep(bi,0,tba,t1);
6177:
6178: align_target(16);
6179: /* not-predicted outcome */
6180: *branchadd=(uae_u32)get_target()-((uae_u32)branchadd+4);
6181: live=tmp; /* Ouch again */
6182: tbi=get_blockinfo_addr_new((void*)t2,1);
6183: match_states(&(tbi->env));
6184:
6185: //flush(1); /* Can only get here if was_comp==1 */
6186: raw_sub_l_mi((uae_u32)&countdown,scaled_cycles(totcycles));
6187: raw_jcc_l_oponly(9);
6188: tba=(uae_u32*)get_target();
6189: emit_long(get_handler(t2)-((uae_u32)tba+4));
6190: raw_mov_l_mi((uae_u32)®s.pc_p,t2);
6191: raw_jmp((uae_u32)popall_do_nothing);
6192: create_jmpdep(bi,1,tba,t2);
6193: }
6194: else
6195: {
6196: if (was_comp) {
6197: flush(1);
6198: }
6199:
6200: /* Let's find out where next_handler is... */
6201: if (was_comp && isinreg(PC_P)) {
6202: int r2;
6203:
6204: r=live.state[PC_P].realreg;
6205:
6206: if (r==0)
6207: r2=1;
6208: else
6209: r2=0;
6210:
6211: raw_and_l_ri(r,TAGMASK);
6212: raw_mov_l_ri(r2,(uae_u32)popall_do_nothing);
6213: raw_sub_l_mi((uae_u32)&countdown,scaled_cycles(totcycles));
6214: raw_cmov_l_rm_indexed(r2,(uae_u32)cache_tags,r,9);
6215: raw_jmp_r(r2);
6216: }
6217: else if (was_comp && isconst(PC_P)) {
6218: uae_u32 v=live.state[PC_P].val;
6219: uae_u32* tba;
6220: blockinfo* tbi;
6221:
6222: tbi=get_blockinfo_addr_new((void*)v,1);
6223: match_states(&(tbi->env));
6224:
6225: raw_sub_l_mi((uae_u32)&countdown,scaled_cycles(totcycles));
6226: raw_jcc_l_oponly(9);
6227: tba=(uae_u32*)get_target();
6228: emit_long(get_handler(v)-((uae_u32)tba+4));
6229: raw_mov_l_mi((uae_u32)®s.pc_p,v);
6230: raw_jmp((uae_u32)popall_do_nothing);
6231: create_jmpdep(bi,0,tba,v);
6232: }
6233: else {
6234: int r2;
6235:
6236: r=REG_PC_TMP;
6237: raw_mov_l_rm(r,(uae_u32)®s.pc_p);
6238: if (r==0)
6239: r2=1;
6240: else
6241: r2=0;
6242:
6243: raw_and_l_ri(r,TAGMASK);
6244: raw_mov_l_ri(r2,(uae_u32)popall_do_nothing);
6245: raw_sub_l_mi((uae_u32)&countdown,scaled_cycles(totcycles));
6246: raw_cmov_l_rm_indexed(r2,(uae_u32)cache_tags,r,9);
6247: raw_jmp_r(r2);
6248: }
6249: }
6250: }
6251:
6252: if (next_pc_p+extra_len>=max_pcp &&
6253: next_pc_p+extra_len<max_pcp+LONGEST_68K_INST)
6254: max_pcp=next_pc_p+extra_len; /* extra_len covers flags magic */
6255: else
6256: max_pcp+=LONGEST_68K_INST;
6257: bi->len=max_pcp-min_pcp;
6258: bi->min_pcp=min_pcp;
6259:
6260: remove_from_list(bi);
6261: if (isinrom(min_pcp) && isinrom(max_pcp))
6262: add_to_dormant(bi); /* No need to checksum it on cache flush.
6263: Please don't start changing ROMs in
6264: flight! */
6265: else {
6266: calc_checksum(bi,&(bi->c1),&(bi->c2));
6267: add_to_active(bi);
6268: }
6269:
6270: log_dump();
6271: align_target(32);
6272: current_compile_p=get_target();
6273:
6274: raise_in_cl_list(bi);
6275: bi->nexthandler=current_compile_p;
6276:
6277: /* We will flush soon, anyway, so let's do it now */
6278: if (current_compile_p>=max_compile_start)
6279: flush_icache_hard(0, 3);
6280:
6281: do_extra_cycles(totcycles); /* for the compilation time */
6282: }
6283: }
6284:
6285: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.