/[pearpc]/src/cpu/cpu_jitc_x86/jitc.cc
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /src/cpu/cpu_jitc_x86/jitc.cc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (hide annotations)
Wed Sep 5 17:11:21 2007 UTC (16 years, 7 months ago) by dpavlin
File size: 15840 byte(s)
import upstream CVS
1 dpavlin 1 /*
2     * PearPC
3     * jitc.cc
4     *
5     * Copyright (C) 2004 Sebastian Biallas (sb@biallas.net)
6     *
7     * This program is free software; you can redistribute it and/or modify
8     * it under the terms of the GNU General Public License version 2 as
9     * published by the Free Software Foundation.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19     */
20    
21     #include <cstdlib>
22     #include <cstring>
23    
24     #include "system/sys.h"
25     #include "tools/snprintf.h"
26    
27     #include "jitc.h"
28     #include "jitc_debug.h"
29     #include "jitc_asm.h"
30    
31     #include "ppc_dec.h"
32     #include "ppc_mmu.h"
33     #include "ppc_tools.h"
34    
35     JITC gJITC;
36    
37     static TranslationCacheFragment *jitcAllocFragment();
38    
39     /*
40     * Intern
41     * Called whenever a new fragment is needed
42     * returns true if a new fragment was really necessary
43     */
44     static bool FASTCALL jitcEmitNextFragment()
45     {
46     // save old
47     TranslationCacheFragment *tcf_old = gJITC.currentPage->tcf_current;
48     NativeAddress tcp_old = gJITC.currentPage->tcp;
49     // alloc new
50     gJITC.currentPage->tcf_current = jitcAllocFragment();
51     gJITC.currentPage->tcf_current->prev = tcf_old;
52     if (((uint)(gJITC.currentPage->tcf_current->base - gJITC.currentPage->tcp)) < 20) {
53     // next Fragment directly follows
54     gJITC.currentPage->bytesLeft += FRAGMENT_SIZE;
55     return false;
56     } else {
57     gJITC.currentPage->tcp = gJITC.currentPage->tcf_current->base;
58     gJITC.currentPage->bytesLeft = FRAGMENT_SIZE;
59     // hardcoded JMP from old to new fragment
60     // FIXME: use 0xeb if possible
61     tcp_old[0] = 0xe9;
62     *((uint32 *)&tcp_old[1]) = gJITC.currentPage->tcp - (tcp_old+5);
63     return true;
64     }
65     }
66    
67     /*
68     * emit one byte of native code
69     */
70     void FASTCALL jitcEmit1(byte b)
71     {
72     jitcDebugLogEmit(&b, 1);
73     /*
74     * We always have to leave at least 5 bytes in the fragment
75     * to issue a final JMP
76     */
77     if (gJITC.currentPage->bytesLeft <= 5) {
78     jitcEmitNextFragment();
79     }
80     *(gJITC.currentPage->tcp++) = b;
81     gJITC.currentPage->bytesLeft--;
82     }
83    
84     /*
85     * emit native code
86     */
87     void FASTCALL jitcEmit(byte *instr, int size)
88     {
89     jitcDebugLogEmit(instr, size);
90     if ((gJITC.currentPage->bytesLeft - size) < 5) {
91     jitcEmitNextFragment();
92     }
93     memcpy(gJITC.currentPage->tcp, instr, size);
94     gJITC.currentPage->tcp += size;
95     gJITC.currentPage->bytesLeft -= size;
96     }
97    
98     /*
99     * Assures that the next instruction will be
100     * emitted in the current fragment
101     */
102     bool FASTCALL jitcEmitAssure(int size)
103     {
104     if ((gJITC.currentPage->bytesLeft - size) < 5) {
105     jitcEmitNextFragment();
106     return false;
107     }
108     return true;
109     }
110    
111     void FASTCALL jitcEmitAlign(int align)
112     {
113     do {
114     int missalign = ((uint)gJITC.currentPage->tcp) % align;
115     if (missalign) {
116     int bytes = align - missalign;
117     if ((gJITC.currentPage->bytesLeft - bytes) < 5) {
118     if (jitcEmitNextFragment()) continue;
119     }
120     gJITC.currentPage->tcp += bytes;
121     gJITC.currentPage->bytesLeft -= bytes;
122     }
123     } while (false);
124     }
125     /*
126     * Intern.
127     * Maps ClientPage to base address
128     */
129     static void inline jitcMapClientPage(uint32 baseaddr, ClientPage *cp)
130     {
131     gJITC.clientPages[baseaddr >> 12] = cp;
132     cp->baseaddress = baseaddr;
133     }
134    
135     /*
136     * Intern.
137     * Unmaps ClientPage at base address
138     */
139     static void inline jitcUnmapClientPage(uint32 baseaddr)
140     {
141     gJITC.clientPages[baseaddr >> 12] = NULL;
142     }
143    
144     /*
145     * Intern.
146     * Unmaps ClientPage
147     */
148     static void inline jitcUnmapClientPage(ClientPage *cp)
149     {
150     jitcUnmapClientPage(cp->baseaddress);
151     }
152    
153     /*
154     * Moves client page to the end of the LRU list
155     * page *must* be in LRU list before
156     */
157     extern "C" FASTCALL ClientPage *jitcTouchClientPage(ClientPage *cp)
158     {
159     if (cp->moreRU) {
160     // there's a page which is used more recently
161     if (cp->lessRU) {
162     // we've got at least 3 pages and
163     // cp is neither LRU nor MRU
164     cp->moreRU->lessRU = cp->lessRU;
165     cp->lessRU->moreRU = cp->moreRU;
166     } else {
167     // page is LRU
168     gJITC.LRUpage = cp->moreRU;
169     gJITC.LRUpage->lessRU = NULL;
170     }
171     cp->moreRU = NULL;
172     cp->lessRU = gJITC.MRUpage;
173     gJITC.MRUpage->moreRU = cp;
174     gJITC.MRUpage = cp;
175     }
176     return cp;
177     }
178    
179     /*
180     * Puts fragments into the freeFragmentsList
181     */
182     //#include <valgrind/valgrind.h>
183     void FASTCALL jitcDestroyFragments(TranslationCacheFragment *tcf)
184     {
185     while (tcf) {
186     // VALGRIND_DISCARD_TRANSLATIONS(tcf->base, FRAGMENT_SIZE);
187     // FIXME: this could be done in O(1) with an additional
188     // variable in ClientPage
189     TranslationCacheFragment *next = tcf->prev;
190     tcf->prev = gJITC.freeFragmentsList;
191     gJITC.freeFragmentsList = tcf;
192     tcf = next;
193     }
194     }
195    
196     /*
197     * Unmaps ClientPage and destroys fragments
198     */
199     static void FASTCALL jitcDestroyClientPage(ClientPage *cp)
200     {
201     // assert(cp->tcf_current)
202     jitcDestroyFragments(cp->tcf_current);
203     memset(cp->entrypoints, 0, sizeof cp->entrypoints);
204     cp->tcf_current = NULL;
205     jitcUnmapClientPage(cp);
206     }
207    
208     /*
209     * Moves client page into the freeClientPages list
210     * (and out of the LRU list)
211     * page *must* be in LRU list before
212     */
213     static void FASTCALL jitcFreeClientPage(ClientPage *cp)
214     {
215     // assert(gJITC.LRUpage)
216     // assert(gJITC.MRUpage)
217    
218     // delete page from LRU list
219     if (!cp->lessRU) {
220     // cp is LRU
221     if (!cp->moreRU) {
222     // cp is also MRU
223     gJITC.LRUpage = gJITC.MRUpage = NULL;
224     } else {
225     // assert(cp->moreRU)
226     gJITC.LRUpage = cp->moreRU;
227     gJITC.LRUpage->lessRU = NULL;
228     }
229     } else {
230     if (!cp->moreRU) {
231     // cp is MRU
232     // assert(cp->LRUprev)
233     gJITC.MRUpage = cp->lessRU;
234     gJITC.MRUpage->moreRU = NULL;
235     } else {
236     cp->moreRU->lessRU = cp->lessRU;
237     cp->lessRU->moreRU = cp->moreRU;
238     }
239     }
240     // and move it into the freeClientPages list
241     cp->moreRU = gJITC.freeClientPages;
242     gJITC.freeClientPages = cp;
243     }
244    
245     /*
246     * Destroys and frees ClientPage
247     */
248     extern "C" void FASTCALL jitcDestroyAndFreeClientPage(ClientPage *cp)
249     {
250     gJITC.destroy_write++;
251     jitcDestroyClientPage(cp);
252     jitcFreeClientPage(cp);
253     }
254    
255     /*
256     * Destroys and touches ClientPage
257     */
258     static void FASTCALL jitcDestroyAndTouchClientPage(ClientPage *cp)
259     {
260     gJITC.destroy_oopages++;
261     jitcDestroyClientPage(cp);
262     jitcTouchClientPage(cp);
263     }
264    
265     /*
266     * Removes and returns fragment from top of freeFragmentsList
267     */
268     static TranslationCacheFragment *jitcGetFragment()
269     {
270     TranslationCacheFragment *tcf = gJITC.freeFragmentsList;
271     gJITC.freeFragmentsList = tcf->prev;
272     tcf->prev = NULL;
273     return tcf;
274     }
275    
276     /*
277     * Returns free fragment
278     * May destroy a page to make new free fragments
279     */
280     static TranslationCacheFragment *jitcAllocFragment()
281     {
282     if (!gJITC.freeFragmentsList) {
283     /*
284     * There are no free fragments
285     * -> must free a ClientPage
286     */
287     gJITC.destroy_write--; // destroy and free will increase this
288     gJITC.destroy_ootc++;
289     jitcDestroyAndFreeClientPage(gJITC.LRUpage);
290     }
291     return jitcGetFragment();
292     }
293    
294     /*
295     * Moves page from freeClientPages at the end of the LRU list if there's
296     * a free page or destroys the LRU page and touches it
297     */
298     extern "C" ClientPage FASTCALL *jitcCreateClientPage(uint32 baseaddr)
299     {
300     ClientPage *cp;
301     if (gJITC.freeClientPages) {
302     // get page
303     cp = gJITC.freeClientPages;
304     gJITC.freeClientPages = gJITC.freeClientPages->moreRU;
305     // and move to the end of LRU list
306     if (gJITC.MRUpage) {
307     gJITC.MRUpage->moreRU = cp;
308     cp->lessRU = gJITC.MRUpage;
309     gJITC.MRUpage = cp;
310     } else {
311     cp->lessRU = NULL;
312     gJITC.LRUpage = gJITC.MRUpage = cp;
313     }
314     cp->moreRU = NULL;
315     } else {
316     cp = gJITC.LRUpage;
317     jitcDestroyAndTouchClientPage(cp);
318     // destroy some more
319     if (gJITC.LRUpage) jitcDestroyAndTouchClientPage(gJITC.LRUpage);
320     if (gJITC.LRUpage) jitcDestroyAndTouchClientPage(gJITC.LRUpage);
321     if (gJITC.LRUpage) jitcDestroyAndTouchClientPage(gJITC.LRUpage);
322     if (gJITC.LRUpage) jitcDestroyAndTouchClientPage(gJITC.LRUpage);
323     }
324     jitcMapClientPage(baseaddr, cp);
325     return cp;
326     }
327    
328     /*
329     * Returns the ClientPage which maps to baseaddr or
330     * creates a new page that maps to baseaddr
331     */
332     ClientPage FASTCALL *jitcGetOrCreateClientPage(uint32 baseaddr)
333     {
334     ClientPage *cp = gJITC.clientPages[baseaddr >> 12];
335     if (cp) {
336     return cp;
337     } else {
338     return jitcCreateClientPage(baseaddr);
339     }
340     }
341    
342     static inline void jitcCreateEntrypoint(ClientPage *cp, uint32 ofs)
343     {
344     cp->entrypoints[ofs >> 2] = cp->tcp;
345     }
346    
347     static inline NativeAddress jitcGetEntrypoint(ClientPage *cp, uint32 ofs)
348     {
349     return cp->entrypoints[ofs >> 2];
350     }
351    
352     extern uint64 gJITCCompileTicks;
353     extern uint64 gJITCRunTicks;
354     extern uint64 gJITCRunTicksStart;
355    
356     extern "C" NativeAddress FASTCALL jitcNewEntrypoint(ClientPage *cp, uint32 baseaddr, uint32 ofs)
357     {
358     /*
359     gJITCRunTicks += jitcDebugGetTicks() - gJITCRunTicksStart;
360     uint64 jitcCompileStartTicks = jitcDebugGetTicks();
361     */
362     jitcDebugLogAdd("=== jitcNewEntrypoint: %08x Beginning jitc ===\n", baseaddr+ofs);
363     gJITC.currentPage = cp;
364    
365     jitcEmitAlign(gJITC.hostCPUCaps.loop_align);
366    
367     NativeAddress entry = cp->tcp;
368     jitcCreateEntrypoint(cp, ofs);
369    
370     byte *physpage;
371     ppc_direct_physical_memory_handle(baseaddr, physpage);
372    
373     gJITC.pc = ofs;
374     jitcInvalidateAll();
375     gJITC.checkedPriviledge = false;
376     gJITC.checkedFloat = false;
377     gJITC.checkedVector = false;
378    
379     // now we've setup gJITC and can start the real compilation
380    
381     while (1) {
382     gJITC.current_opc = ppc_word_from_BE(*(uint32 *)(&physpage[ofs]));
383     jitcDebugLogNewInstruction();
384     JITCFlow flow = ppc_gen_opc();
385     if (flow == flowContinue) {
386     /* nothing to do */
387     } else if (flow == flowEndBlock) {
388     jitcClobberAll();
389    
390     gJITC.checkedPriviledge = false;
391     gJITC.checkedFloat = false;
392     gJITC.checkedVector = false;
393     if (ofs+4 < 4096) {
394     jitcCreateEntrypoint(cp, ofs+4);
395     }
396     } else {
397     /* flowEndBlockUnreachable */
398     break;
399     }
400     ofs += 4;
401     if (ofs == 4096) {
402     /*
403     * End of page.
404     * We must use jump to the next page via
405     * ppc_new_pc_asm
406     */
407     jitcClobberAll();
408     asmALURegImm(X86_MOV, EAX, 4096);
409     asmJMP((NativeAddress)ppc_new_pc_rel_asm);
410     break;
411     }
412     gJITC.pc += 4;
413     }
414     /*
415     gJITCRunTicksStart = jitcDebugGetTicks();
416     gJITCCompileTicks += jitcDebugGetTicks() - jitcCompileStartTicks;
417     */
418     return entry;
419     }
420    
421     extern "C" NativeAddress FASTCALL jitcStartTranslation(ClientPage *cp, uint32 baseaddr, uint32 ofs)
422     {
423     cp->tcf_current = jitcAllocFragment();
424     cp->tcp = cp->tcf_current->base;
425     cp->bytesLeft = FRAGMENT_SIZE;
426    
427     return jitcNewEntrypoint(cp, baseaddr, ofs);
428     }
429    
430     /*
431     * Called whenever the client PC changes (to a new BB)
432     * Note that entry is a physical address
433     */
434     extern "C" NativeAddress FASTCALL jitcNewPC(uint32 entry)
435     {
436     if (entry > gMemorySize) {
437     ht_printf("entry not physical: %08x\n", entry);
438     exit(-1);
439     }
440     uint32 baseaddr = entry & 0xfffff000;
441     ClientPage *cp = jitcGetOrCreateClientPage(baseaddr);
442     jitcTouchClientPage(cp);
443     if (!cp->tcf_current) {
444     return jitcStartTranslation(cp, baseaddr, entry & 0xfff);
445     } else {
446     NativeAddress ofs = jitcGetEntrypoint(cp, entry & 0xfff);
447     if (ofs) {
448     return ofs;
449     } else {
450     return jitcNewEntrypoint(cp, baseaddr, entry & 0xfff);
451     }
452     }
453     }
454    
455     extern "C" void FASTCALL jitc_error_msr_unsupported_bits(uint32 a)
456     {
457     ht_printf("JITC msr Error: %08x\n", a);
458     exit(1);
459     }
460    
461     extern "C" void FASTCALL jitc_error(const char *error)
462     {
463     ht_printf("JITC Error: %s\n", error);
464     exit(1);
465     }
466    
467     extern "C" void FASTCALL jitc_error_program(uint32 a, uint32 b)
468     {
469     if (a != 0x00020000) { // Filter out trap exceptions, no need to report them
470     ht_printf("JITC Warning: program exception: %08x %08x\n", a, b);
471     }
472     }
473    
474     extern uint8 jitcFlagsMapping[257];
475     extern uint8 jitcFlagsMapping2[256];
476     extern uint8 jitcFlagsMappingCMP_U[257];
477     extern uint8 jitcFlagsMappingCMP_L[257];
478    
479     bool jitc_init(int maxClientPages, uint32 tcSize)
480     {
481     memset(&gJITC, 0, sizeof gJITC);
482    
483     x86GetCaps(gJITC.hostCPUCaps);
484    
485     gJITC.translationCache = (byte*)sys_alloc_read_write_execute(tcSize);
486     if (!gJITC.translationCache) return false;
487     int maxPages = gMemorySize / 4096;
488     gJITC.clientPages = (ClientPage **)malloc(maxPages * sizeof (ClientPage *));
489     memset(gJITC.clientPages, 0, maxPages * sizeof (ClientPage *));
490    
491     // allocate fragments
492     TranslationCacheFragment *tcf = (TranslationCacheFragment *)malloc(sizeof (TranslationCacheFragment));
493     gJITC.freeFragmentsList = tcf;
494     tcf->base = gJITC.translationCache;
495     for (uint32 addr=FRAGMENT_SIZE; addr < tcSize; addr += FRAGMENT_SIZE) {
496     tcf->prev = (TranslationCacheFragment *)malloc(sizeof (TranslationCacheFragment));
497     tcf = tcf->prev;
498     tcf->base = gJITC.translationCache + addr;
499     }
500     tcf->prev = NULL;
501    
502     // allocate client pages
503     ClientPage *cp = (ClientPage *)malloc(sizeof (ClientPage));
504     memset(cp->entrypoints, 0, sizeof cp->entrypoints);
505     cp->tcf_current = NULL; // not translated yet
506     cp->lessRU = NULL;
507     gJITC.LRUpage = NULL;
508     gJITC.freeClientPages = cp;
509     for (int i=1; i < maxClientPages; i++) {
510     cp->moreRU = (ClientPage *)malloc(sizeof (ClientPage));
511     cp->moreRU->lessRU = cp;
512     cp = cp->moreRU;
513    
514     memset(cp->entrypoints, 0, sizeof cp->entrypoints);
515     cp->tcf_current = NULL; // not translated yet
516     }
517     cp->moreRU = NULL;
518     gJITC.MRUpage = NULL;
519    
520     // initialize native registers
521     NativeRegType *nr = (NativeRegType *)malloc(sizeof (NativeRegType));
522     nr->reg = EAX;
523     nr->lessRU = NULL;
524     gJITC.LRUreg = nr;
525     gJITC.nativeRegsList[EAX] = nr;
526     for (NativeReg reg = ECX; reg <= EDI; reg=(NativeReg)(reg+1)) {
527     if (reg != ESP) {
528     nr->moreRU = (NativeRegType *)malloc(sizeof (NativeRegType));
529     nr->moreRU->lessRU = nr;
530     nr = nr->moreRU;
531     nr->reg = reg;
532     gJITC.nativeRegsList[reg] = nr;
533     }
534     }
535     nr->moreRU = NULL;
536     gJITC.MRUreg = nr;
537    
538     for (int i=1; i<9; i++) {
539     gJITC.floatRegPerm[i] = i;
540     gJITC.floatRegPermInverse[i] = i;
541     }
542    
543     jitcFlagsMapping[0] = 1<<6; // GT
544     jitcFlagsMapping[1] = 1<<7; // LT
545     jitcFlagsMapping[1<<8] = 1<<5; // EQ
546     jitcFlagsMappingCMP_U[0] = 1<<5; // EQ
547     jitcFlagsMappingCMP_U[1] = 1<<6; // GT
548     jitcFlagsMappingCMP_U[1<<8] = 1<<7; // LT
549     jitcFlagsMappingCMP_L[0] = 1<<1; // EQ
550     jitcFlagsMappingCMP_L[1] = 1<<2; // GT
551     jitcFlagsMappingCMP_L[1<<8] = 1<<3; // LT
552     for (int i=0; i<256; i++) {
553     switch (i & 0xc0) {
554     case 0x00: // neither zero nor sign
555     jitcFlagsMapping2[i] = 1<<6; // GT
556     break;
557     case 0x40: // zero flag
558     jitcFlagsMapping2[i] = 1<<5; // EQ
559     break;
560     case 0x80: // sign flag
561     jitcFlagsMapping2[i] = 1<<7; // LT
562     break;
563     case 0xc0: // impossible
564     jitcFlagsMapping2[i] = 0;
565     break;
566     }
567     }
568    
569     for (int i=XMM0; i<=XMM_SENTINEL; i++) {
570     gJITC.LRUvregs[i] = (NativeVectorReg)(i-1);
571     gJITC.MRUvregs[i] = (NativeVectorReg)(i+1);
572     }
573    
574     gJITC.LRUvregs[XMM0] = XMM_SENTINEL;
575     gJITC.MRUvregs[XMM_SENTINEL] = XMM0;
576    
577     gJITC.nativeVectorReg = VECTREG_NO;
578    
579     /*
580     * Note that REG_NO=-1 and PPC_REG_NO=0 so this works
581     * by accident.
582     */
583     memset(gJITC.clientReg, REG_NO, sizeof gJITC.clientReg);
584     memset(gJITC.nativeReg, PPC_REG_NO, sizeof gJITC.nativeReg);
585     memset(gJITC.nativeRegState, rsUnused, sizeof gJITC.nativeRegState);
586    
587     memset(gJITC.n2cVectorReg, PPC_REG_NO, sizeof gJITC.n2cVectorReg);
588     memset(gJITC.c2nVectorReg, VECTREG_NO, sizeof gJITC.c2nVectorReg);
589     memset(gJITC.nativeVectorRegState, rsUnused, sizeof gJITC.nativeVectorRegState);
590    
591     /*
592     * This -1 register is to be read-only, and only used when
593     * needed, and must ALWAYS stay this way!
594     *
595     * It's absolutely fundamental to doing NOT's with SSE
596     */
597     memset(&gCPU.vr[JITC_VECTOR_NEG1], 0xff, sizeof gCPU.vr[0]);
598    
599     memset(gJITC.tlb_code_eff, 0xff, sizeof gJITC.tlb_code_eff);
600     memset(gJITC.tlb_data_read_eff, 0xff, sizeof gJITC.tlb_data_read_eff);
601     memset(gJITC.tlb_data_write_eff, 0xff, sizeof gJITC.tlb_data_write_eff);
602     gJITC.tlb_code_hits = 0;
603     gJITC.tlb_data_read_hits = 0;
604     gJITC.tlb_data_write_hits = 0;
605     gJITC.tlb_code_misses = 0;
606     gJITC.tlb_data_read_misses = 0;
607     gJITC.tlb_data_write_misses = 0;
608     return true;
609     }
610    
611     void jitc_done()
612     {
613     if (gJITC.translationCache) sys_free_read_write_execute(gJITC.translationCache);
614     }

  ViewVC Help
Powered by ViewVC 1.1.26