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