Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

vm_ppc_new.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 // vm_ppc.c
00023 // ppc dynamic compiler
00024 
00025 #include "vm_local.h"
00026 
00027 #pragma opt_pointer_analysis off
00028 
00029 #define DEBUG_VM 0
00030 
00031 #if DEBUG_VM
00032 static char *opnames[256] = {
00033     "OP_UNDEF", 
00034 
00035     "OP_IGNORE", 
00036 
00037     "OP_BREAK",
00038 
00039     "OP_ENTER",
00040     "OP_LEAVE",
00041     "OP_CALL",
00042     "OP_PUSH",
00043     "OP_POP",
00044 
00045     "OP_CONST",
00046 
00047     "OP_LOCAL",
00048 
00049     "OP_JUMP",
00050 
00051     //-------------------
00052 
00053     "OP_EQ",
00054     "OP_NE",
00055 
00056     "OP_LTI",
00057     "OP_LEI",
00058     "OP_GTI",
00059     "OP_GEI",
00060 
00061     "OP_LTU",
00062     "OP_LEU",
00063     "OP_GTU",
00064     "OP_GEU",
00065 
00066     "OP_EQF",
00067     "OP_NEF",
00068 
00069     "OP_LTF",
00070     "OP_LEF",
00071     "OP_GTF",
00072     "OP_GEF",
00073 
00074     //-------------------
00075 
00076     "OP_LOAD1",
00077     "OP_LOAD2",
00078     "OP_LOAD4",
00079     "OP_STORE1",
00080     "OP_STORE2",
00081     "OP_STORE4",
00082     "OP_ARG",
00083 
00084     "OP_BLOCK_COPY",
00085 
00086     //-------------------
00087 
00088     "OP_SEX8",
00089     "OP_SEX16",
00090 
00091     "OP_NEGI",
00092     "OP_ADD",
00093     "OP_SUB",
00094     "OP_DIVI",
00095     "OP_DIVU",
00096     "OP_MODI",
00097     "OP_MODU",
00098     "OP_MULI",
00099     "OP_MULU",
00100 
00101     "OP_BAND",
00102     "OP_BOR",
00103     "OP_BXOR",
00104     "OP_BCOM",
00105 
00106     "OP_LSH",
00107     "OP_RSHI",
00108     "OP_RSHU",
00109 
00110     "OP_NEGF",
00111     "OP_ADDF",
00112     "OP_SUBF",
00113     "OP_DIVF",
00114     "OP_MULF",
00115 
00116     "OP_CVIF",
00117     "OP_CVFI"
00118 };
00119 #endif
00120 
00121 typedef enum {
00122     R_REAL_STACK = 1,
00123     // registers 3-11 are the parameter passing registers
00124     
00125     // state
00126     R_STACK = 3,            // local
00127     R_OPSTACK,              // global
00128 
00129     // constants    
00130     R_MEMBASE,          // global
00131     R_MEMMASK,
00132     R_ASMCALL,          // global
00133     R_INSTRUCTIONS,     // global
00134     R_NUM_INSTRUCTIONS, // global
00135     R_CVM,              // currentVM
00136     
00137     // temps
00138     R_TOP = 11,
00139     R_SECOND = 12,
00140     R_EA = 2                // effective address calculation
00141      
00142 } regNums_t;
00143 
00144 #define RG_REAL_STACK       r1
00145 #define RG_STACK            r3
00146 #define RG_OPSTACK          r4
00147 #define RG_MEMBASE          r5
00148 #define RG_MEMMASK          r6
00149 #define RG_ASMCALL          r7
00150 #define RG_INSTRUCTIONS     r8
00151 #define RG_NUM_INSTRUCTIONS r9
00152 #define RG_CVM              r10
00153 #define RG_TOP              r12
00154 #define RG_SECOND           r13
00155 #define RG_EA               r14
00156 
00157 // The deepest value I saw in the Quake3 games was 9.
00158 #define OP_STACK_MAX_DEPTH  12
00159 
00160 // These are all volatile and thus must be saved
00161 // upon entry to the VM code.
00162 static int opStackIntRegisters[OP_STACK_MAX_DEPTH] =
00163 {
00164     16, 17, 18, 19,
00165     20, 21, 22, 23,
00166     24, 25, 26, 27
00167 };
00168 
00169 static unsigned int *opStackLoadInstructionAddr[OP_STACK_MAX_DEPTH];
00170 
00171 // We use different registers for the floating point
00172 // operand stack (these are volatile in the PPC ABI)
00173 static int opStackFloatRegisters[OP_STACK_MAX_DEPTH] =
00174 {
00175     0, 1, 2, 3,
00176     4, 5, 6, 7,
00177     8, 9, 10, 11
00178 };
00179 
00180 static int opStackRegType[OP_STACK_MAX_DEPTH] =
00181 {
00182     0, 0, 0, 0,
00183     0, 0, 0, 0,
00184     0, 0, 0, 0
00185 };
00186 
00187 // this doesn't have the low order bits set for instructions i'm not using...
00188 typedef enum {
00189     PPC_TDI     = 0x08000000,
00190     PPC_TWI     = 0x0c000000,
00191     PPC_MULLI   = 0x1c000000,
00192     PPC_SUBFIC  = 0x20000000,
00193     PPC_CMPI    = 0x28000000,
00194     PPC_CMPLI   = 0x2c000000,
00195     PPC_ADDIC   = 0x30000000,
00196     PPC_ADDIC_  = 0x34000000,
00197     PPC_ADDI    = 0x38000000,
00198     PPC_ADDIS   = 0x3c000000,
00199     PPC_BC      = 0x40000000,
00200     PPC_SC      = 0x44000000,
00201     PPC_B       = 0x48000000,
00202 
00203     PPC_MCRF    = 0x4c000000,
00204     PPC_BCLR    = 0x4c000020,
00205     PPC_RFID    = 0x4c000000,
00206     PPC_CRNOR   = 0x4c000000,
00207     PPC_RFI     = 0x4c000000,
00208     PPC_CRANDC  = 0x4c000000,
00209     PPC_ISYNC   = 0x4c000000,
00210     PPC_CRXOR   = 0x4c000000,
00211     PPC_CRNAND  = 0x4c000000,
00212     PPC_CREQV   = 0x4c000000,
00213     PPC_CRORC   = 0x4c000000,
00214     PPC_CROR    = 0x4c000000,
00215 //------------
00216     PPC_BCCTR   = 0x4c000420,
00217     PPC_RLWIMI  = 0x50000000,
00218     PPC_RLWINM  = 0x54000000,
00219     PPC_RLWNM   = 0x5c000000,
00220     PPC_ORI     = 0x60000000,
00221     PPC_ORIS    = 0x64000000,
00222     PPC_XORI    = 0x68000000,
00223     PPC_XORIS   = 0x6c000000,
00224     PPC_ANDI_   = 0x70000000,
00225     PPC_ANDIS_  = 0x74000000,
00226     PPC_RLDICL  = 0x78000000,
00227     PPC_RLDICR  = 0x78000000,
00228     PPC_RLDIC   = 0x78000000,
00229     PPC_RLDIMI  = 0x78000000,
00230     PPC_RLDCL   = 0x78000000,
00231     PPC_RLDCR   = 0x78000000,
00232     PPC_CMP     = 0x7c000000,
00233     PPC_TW      = 0x7c000000,
00234     PPC_SUBFC   = 0x7c000010,
00235     PPC_MULHDU  = 0x7c000000,
00236     PPC_ADDC    = 0x7c000014,
00237     PPC_MULHWU  = 0x7c000000,
00238     PPC_MFCR    = 0x7c000000,
00239     PPC_LWAR    = 0x7c000000,
00240     PPC_LDX     = 0x7c000000,
00241     PPC_LWZX    = 0x7c00002e,
00242     PPC_SLW     = 0x7c000030,
00243     PPC_CNTLZW  = 0x7c000000,
00244     PPC_SLD     = 0x7c000000,
00245     PPC_AND     = 0x7c000038,
00246     PPC_CMPL    = 0x7c000040,
00247     PPC_SUBF    = 0x7c000050,
00248     PPC_LDUX    = 0x7c000000,
00249 //------------
00250     PPC_DCBST   = 0x7c000000,
00251     PPC_LWZUX   = 0x7c00006c,
00252     PPC_CNTLZD  = 0x7c000000,
00253     PPC_ANDC    = 0x7c000000,
00254     PPC_TD      = 0x7c000000,
00255     PPC_MULHD   = 0x7c000000,
00256     PPC_MULHW   = 0x7c000000,
00257     PPC_MTSRD   = 0x7c000000,
00258     PPC_MFMSR   = 0x7c000000,
00259     PPC_LDARX   = 0x7c000000,
00260     PPC_DCBF    = 0x7c000000,
00261     PPC_LBZX    = 0x7c0000ae,
00262     PPC_NEG     = 0x7c000000,
00263     PPC_MTSRDIN = 0x7c000000,
00264     PPC_LBZUX   = 0x7c000000,
00265     PPC_NOR     = 0x7c0000f8,
00266     PPC_SUBFE   = 0x7c000000,
00267     PPC_ADDE    = 0x7c000000,
00268     PPC_MTCRF   = 0x7c000000,
00269     PPC_MTMSR   = 0x7c000000,
00270     PPC_STDX    = 0x7c000000,
00271     PPC_STWCX_  = 0x7c000000,
00272     PPC_STWX    = 0x7c00012e,
00273     PPC_MTMSRD  = 0x7c000000,
00274     PPC_STDUX   = 0x7c000000,
00275     PPC_STWUX   = 0x7c00016e,
00276     PPC_SUBFZE  = 0x7c000000,
00277     PPC_ADDZE   = 0x7c000000,
00278     PPC_MTSR    = 0x7c000000,
00279     PPC_STDCX_  = 0x7c000000,
00280     PPC_STBX    = 0x7c0001ae,
00281     PPC_SUBFME  = 0x7c000000,
00282     PPC_MULLD   = 0x7c000000,
00283 //------------
00284     PPC_ADDME   = 0x7c000000,
00285     PPC_MULLW   = 0x7c0001d6,
00286     PPC_MTSRIN  = 0x7c000000,
00287     PPC_DCBTST  = 0x7c000000,
00288     PPC_STBUX   = 0x7c000000,
00289     PPC_ADD     = 0x7c000214,
00290     PPC_DCBT    = 0x7c000000,
00291     PPC_LHZX    = 0x7c00022e,
00292     PPC_EQV     = 0x7c000000,
00293     PPC_TLBIE   = 0x7c000000,
00294     PPC_ECIWX   = 0x7c000000,
00295     PPC_LHZUX   = 0x7c000000,
00296     PPC_XOR     = 0x7c000278,
00297     PPC_MFSPR   = 0x7c0002a6,
00298     PPC_LWAX    = 0x7c000000,
00299     PPC_LHAX    = 0x7c000000,
00300     PPC_TLBIA   = 0x7c000000,
00301     PPC_MFTB    = 0x7c000000,
00302     PPC_LWAUX   = 0x7c000000,
00303     PPC_LHAUX   = 0x7c000000,
00304     PPC_STHX    = 0x7c00032e,
00305     PPC_ORC     = 0x7c000338,
00306     PPC_SRADI   = 0x7c000000,
00307     PPC_SLBIE   = 0x7c000000,
00308     PPC_ECOWX   = 0x7c000000,
00309     PPC_STHUX   = 0x7c000000,
00310     PPC_OR      = 0x7c000378,
00311     PPC_DIVDU   = 0x7c000000,
00312     PPC_DIVWU   = 0x7c000396,
00313     PPC_MTSPR   = 0x7c0003a6,
00314     PPC_DCBI    = 0x7c000000,
00315     PPC_NAND    = 0x7c000000,
00316     PPC_DIVD    = 0x7c000000,
00317 //------------
00318     PPC_DIVW    = 0x7c0003d6,
00319     PPC_SLBIA   = 0x7c000000,
00320     PPC_MCRXR   = 0x7c000000,
00321     PPC_LSWX    = 0x7c000000,
00322     PPC_LWBRX   = 0x7c000000,
00323     PPC_LFSX    = 0x7c00042e,
00324     PPC_SRW     = 0x7c000430,
00325     PPC_SRD     = 0x7c000000,
00326     PPC_TLBSYNC = 0x7c000000,
00327     PPC_LFSUX   = 0x7c000000,
00328     PPC_MFSR    = 0x7c000000,
00329     PPC_LSWI    = 0x7c000000,
00330     PPC_SYNC    = 0x7c000000,
00331     PPC_LFDX    = 0x7c000000,
00332     PPC_LFDUX   = 0x7c000000,
00333     PPC_MFSRIN  = 0x7c000000,
00334     PPC_STSWX   = 0x7c000000,
00335     PPC_STWBRX  = 0x7c000000,
00336     PPC_STFSX   = 0x7c00052e,
00337     PPC_STFSUX  = 0x7c000000,
00338     PPC_STSWI   = 0x7c000000,
00339     PPC_STFDX   = 0x7c000000,
00340     PPC_DCBA    = 0x7c000000,
00341     PPC_STFDUX  = 0x7c000000,
00342     PPC_LHBRX   = 0x7c000000,
00343     PPC_SRAW    = 0x7c000630,
00344     PPC_SRAD    = 0x7c000000,
00345     PPC_SRAWI   = 0x7c000000,
00346     PPC_EIEIO   = 0x7c000000,
00347     PPC_STHBRX  = 0x7c000000,
00348     PPC_EXTSH   = 0x7c000734,
00349     PPC_EXTSB   = 0x7c000774,
00350     PPC_ICBI    = 0x7c000000,
00351 //------------
00352     PPC_STFIWX  = 0x7c0007ae,
00353     PPC_EXTSW   = 0x7c000000,
00354     PPC_DCBZ    = 0x7c000000,
00355     PPC_LWZ     = 0x80000000,
00356     PPC_LWZU    = 0x84000000,
00357     PPC_LBZ     = 0x88000000,
00358     PPC_LBZU    = 0x8c000000,
00359     PPC_STW     = 0x90000000,
00360     PPC_STWU    = 0x94000000,
00361     PPC_STB     = 0x98000000,
00362     PPC_STBU    = 0x9c000000,
00363     PPC_LHZ     = 0xa0000000,
00364     PPC_LHZU    = 0xa4000000,
00365     PPC_LHA     = 0xa8000000,
00366     PPC_LHAU    = 0xac000000,
00367     PPC_STH     = 0xb0000000,
00368     PPC_STHU    = 0xb4000000,
00369     PPC_LMW     = 0xb8000000,
00370     PPC_STMW    = 0xbc000000,
00371     PPC_LFS     = 0xc0000000,
00372     PPC_LFSU    = 0xc4000000,
00373     PPC_LFD     = 0xc8000000,
00374     PPC_LFDU    = 0xcc000000,
00375     PPC_STFS    = 0xd0000000,
00376     PPC_STFSU   = 0xd4000000,
00377     PPC_STFD    = 0xd8000000,
00378     PPC_STFDU   = 0xdc000000,
00379     PPC_LD      = 0xe8000000,
00380     PPC_LDU     = 0xe8000001,
00381     PPC_LWA     = 0xe8000002,
00382     PPC_FDIVS   = 0xec000024,
00383     PPC_FSUBS   = 0xec000028,
00384     PPC_FADDS   = 0xec00002a,
00385 //------------
00386     PPC_FSQRTS  = 0xec000000,
00387     PPC_FRES    = 0xec000000,
00388     PPC_FMULS   = 0xec000032,
00389     PPC_FMSUBS  = 0xec000000,
00390     PPC_FMADDS  = 0xec000000,
00391     PPC_FNMSUBS = 0xec000000,
00392     PPC_FNMADDS = 0xec000000,
00393     PPC_STD     = 0xf8000000,
00394     PPC_STDU    = 0xf8000001,
00395     PPC_FCMPU   = 0xfc000000,
00396     PPC_FRSP    = 0xfc000018,
00397     PPC_FCTIW   = 0xfc000000,
00398     PPC_FCTIWZ  = 0xfc00001e,
00399     PPC_FDIV    = 0xfc000000,
00400     PPC_FSUB    = 0xfc000028,
00401     PPC_FADD    = 0xfc000000,
00402     PPC_FSQRT   = 0xfc000000,
00403     PPC_FSEL    = 0xfc000000,
00404     PPC_FMUL    = 0xfc000000,
00405     PPC_FRSQRTE = 0xfc000000,
00406     PPC_FMSUB   = 0xfc000000,
00407     PPC_FMADD   = 0xfc000000,
00408     PPC_FNMSUB  = 0xfc000000,
00409     PPC_FNMADD  = 0xfc000000,
00410     PPC_FCMPO   = 0xfc000000,
00411     PPC_MTFSB1  = 0xfc000000,
00412     PPC_FNEG    = 0xfc000050,
00413     PPC_MCRFS   = 0xfc000000,
00414     PPC_MTFSB0  = 0xfc000000,
00415     PPC_FMR     = 0xfc000000,
00416     PPC_MTFSFI  = 0xfc000000,
00417     PPC_FNABS   = 0xfc000000,
00418     PPC_FABS    = 0xfc000000,
00419 //------------
00420     PPC_MFFS    = 0xfc000000,
00421     PPC_MTFSF   = 0xfc000000,
00422     PPC_FCTID   = 0xfc000000,
00423     PPC_FCTIDZ  = 0xfc000000,
00424     PPC_FCFID   = 0xfc000000
00425     
00426 } ppcOpcodes_t;
00427 
00428 
00429 // the newly generated code
00430 static  unsigned    *buf;
00431 static  int     compiledOfs;    // in dwords
00432 static int pass;
00433 
00434 // fromt the original bytecode
00435 static  byte    *code;
00436 static  int     pc;
00437 
00438 void AsmCall( void );
00439 
00440 double  itofConvert[2];
00441 
00442 static int  Constant4( void ) {
00443     int     v;
00444 
00445     v = code[pc] | (code[pc+1]<<8) | (code[pc+2]<<16) | (code[pc+3]<<24);
00446     pc += 4;
00447     return v;
00448 }
00449 
00450 static int  Constant1( void ) {
00451     int     v;
00452 
00453     v = code[pc];
00454     pc += 1;
00455     return v;
00456 }
00457 
00458 static void Emit4( char *opname, int i ) {
00459     #if DEBUG_VM
00460     if(pass == 1)
00461         printf("\t\t\t%p %s\t%08lx\n",&buf[compiledOfs],opname,i&0x3ffffff);
00462     #endif
00463     buf[ compiledOfs ] = i;
00464     compiledOfs++;
00465 }
00466 
00467 static void Inst( char *opname, int opcode, int destReg, int aReg, int bReg ) {
00468     unsigned        r;
00469 
00470     #if DEBUG_VM
00471     if(pass == 1)
00472         printf("\t\t\t%p %s\tr%d,r%d,r%d\n",&buf[compiledOfs],opname,destReg,aReg,bReg);
00473     #endif
00474     r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) ;
00475     buf[ compiledOfs ] = r;
00476     compiledOfs++;
00477 }
00478 
00479 static void Inst4( char *opname, int opcode, int destReg, int aReg, int bReg, int cReg ) {
00480     unsigned        r;
00481 
00482     #if DEBUG_VM
00483     if(pass == 1)
00484         printf("\t\t\t%p %s\tr%d,r%d,r%d,r%d\n",&buf[compiledOfs],opname,destReg,aReg,bReg,cReg);
00485     #endif
00486     r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) | ( cReg << 6 );
00487     buf[ compiledOfs ] = r;
00488     compiledOfs++;
00489 }
00490 
00491 static void InstImm( char *opname, int opcode, int destReg, int aReg, int immediate ) {
00492     unsigned        r;
00493     
00494     if ( immediate > 32767 || immediate < -32768 ) {
00495         Com_Error( ERR_FATAL, "VM_Compile: immediate value %i out of range, opcode %x,%d,%d", immediate, opcode, destReg, aReg );
00496     }
00497     #if DEBUG_VM
00498     if(pass == 1)
00499         printf("\t\t\t%p %s\tr%d,r%d,0x%x\n",&buf[compiledOfs],opname,destReg,aReg,immediate);
00500     #endif
00501     r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( immediate & 0xffff );
00502     buf[ compiledOfs ] = r;
00503     compiledOfs++;
00504 }
00505 
00506 static void InstImmU( char *opname, int opcode, int destReg, int aReg, int immediate ) {
00507     unsigned        r;
00508     
00509     if ( immediate > 0xffff || immediate < 0 ) {
00510         Com_Error( ERR_FATAL, "VM_Compile: immediate value %i out of range", immediate );
00511     }
00512     #if DEBUG_VM
00513     if(pass == 1)
00514         printf("\t\t\t%p %s\tr%d,r%d,0x%x\n",&buf[compiledOfs],opname,destReg,aReg,immediate);
00515     #endif
00516     r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( immediate & 0xffff );
00517     buf[ compiledOfs ] = r;
00518     compiledOfs++;
00519 }
00520 
00521 static int pop0, pop1, oc0, oc1;
00522 static vm_t *tvm;
00523 static int instruction;
00524 static byte *jused;
00525 
00526 static void ltop() {
00527 //    if (rtopped == qfalse) {
00528 //  InstImm( PPC_LWZ, R_TOP, R_OPSTACK, 0 );        // get value from opstack
00529 //    }
00530 }
00531 
00532 static void ltopandsecond() {
00533 #if 0
00534     if (pass>=0 && buf[compiledOfs-1] == (PPC_STWU |  R_TOP<<21 | R_OPSTACK<<16 | 4 ) && jused[instruction]==0 ) {
00535     compiledOfs--;
00536     if (!pass) {
00537         tvm->instructionPointers[instruction] = compiledOfs * 4;
00538     }
00539     InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 ); // get value from opstack
00540     InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 );
00541     } else if (pass>=0 && buf[compiledOfs-1] == (PPC_STW |  R_TOP<<21 | R_OPSTACK<<16 | 0 )  && jused[instruction]==0 ) {
00542     compiledOfs--;
00543     if (!pass) {
00544         tvm->instructionPointers[instruction] = compiledOfs * 4;
00545     }
00546     InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, -4 );    // get value from opstack
00547     InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 );
00548     } else {
00549     ltop();     // get value from opstack
00550     InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, -4 );    // get value from opstack
00551     InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 );
00552     }
00553     rtopped = qfalse;
00554 #endif
00555 }
00556 
00557 static void spillOpStack(int depth)
00558 {
00559     // Store out each register on the operand stack to it's correct location.
00560     int i;
00561     
00562     for(i = 0; i < depth; i++)
00563     {
00564         assert(opStackRegType[i]);
00565         assert(opStackRegType[i] == 1);
00566         switch(opStackRegType[i])
00567         {
00568             case 1: // Integer register
00569                 InstImm( "stw", PPC_STW, opStackIntRegisters[i], R_OPSTACK, i*4+4);
00570                 break;
00571             case 2: // Float register
00572                 InstImm( "stfs", PPC_STFS, opStackFloatRegisters[i], R_OPSTACK, i*4+4);
00573                 break;
00574         }
00575         opStackRegType[i] = 0;
00576     }
00577 }
00578 
00579 static void loadOpStack(int depth)
00580 {
00581     // Back off operand stack pointer and reload all operands.
00582 //  InstImm( "addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, -(depth)*4 );
00583 
00584     int i;
00585     
00586     for(i = 0; i < depth; i++)
00587     {
00588         assert(opStackRegType[i] == 0);
00589         // For now we're stuck reloading everything as an integer.
00590         opStackLoadInstructionAddr[i] = &buf[compiledOfs];
00591         InstImm( "lwz", PPC_LWZ, opStackIntRegisters[i], R_OPSTACK, i*4+4);
00592         opStackRegType[i] = 1;
00593     }   
00594 }
00595 
00596 static void makeInteger(int depth)
00597 {
00598     // This should really never be necessary...
00599     assert(opStackRegType[depth] == 1);
00600     //assert(opStackRegType[depth] == 2);
00601     if(opStackRegType[depth] == 2)
00602     {
00603         unsigned instruction;
00604         assert(opStackLoadInstructionAddr[depth]);
00605         
00606         printf("patching float load at %p to int load\n",opStackLoadInstructionAddr[depth]);
00607         // Repatch load instruction to use LFS instead of LWZ
00608         instruction = *opStackLoadInstructionAddr[depth];
00609         instruction &= ~PPC_LFSX;
00610         instruction |=  PPC_LWZX;
00611         *opStackLoadInstructionAddr[depth] = instruction;
00612         opStackLoadInstructionAddr[depth] = 0;
00613         opStackRegType[depth] = 1;
00614         #if 0
00615         InstImm( "stfs", PPC_STFS, opStackFloatRegisters[depth], R_OPSTACK, depth*4+4);
00616         // For XXX make sure we force enough NOPs to get the load into
00617         // another dispatch group to avoid pipeline flush.
00618         Inst( "ori", PPC_ORI,  0, 0, 0 );
00619         Inst( "ori", PPC_ORI,  0, 0, 0 );
00620         Inst( "ori", PPC_ORI,  0, 0, 0 );
00621         Inst( "ori", PPC_ORI,  0, 0, 0 );
00622         InstImm( "lwz", PPC_LWZ, opStackIntRegisters[depth], R_OPSTACK, depth*4+4);
00623         opStackRegType[depth] = 1;
00624         #endif
00625     }
00626 }
00627 
00628 static void makeFloat(int depth)
00629 {
00630     //assert(opStackRegType[depth] == 1);
00631     if(opStackRegType[depth] == 1)
00632     {
00633         unsigned instruction;
00634         unsigned destReg, aReg, bReg, imm;
00635         
00636         if(opStackLoadInstructionAddr[depth])
00637         {
00638             // Repatch load instruction to use LFS instead of LWZ
00639             instruction = *opStackLoadInstructionAddr[depth];
00640             // Figure out if it's LWZ or LWZX
00641             if((instruction & 0xfc000000) == PPC_LWZ)
00642             {
00643                 //printf("patching LWZ at %p to LFS at depth %ld\n",opStackLoadInstructionAddr[depth],depth);
00644                 //printf("old instruction: %08lx\n",instruction);
00645                 // Extract registers
00646                 destReg = (instruction >> 21) & 31;
00647                 aReg    = (instruction >> 16) & 31;
00648                 imm     = instruction & 0xffff;
00649                 
00650                 // Calculate correct FP register to use.
00651                 // THIS ASSUMES REGISTER USAGE FOR THE STACK IS n, n+1, n+2, etc!
00652                 //printf("old dest: %ld\n",destReg);
00653                 destReg = (destReg - opStackIntRegisters[0]) + opStackFloatRegisters[0];
00654                 instruction = PPC_LFS | ( destReg << 21 ) | ( aReg << 16 ) | imm ;          
00655                 //printf("new dest: %ld\n",destReg);
00656                 //printf("new instruction: %08lx\n",instruction);
00657             }
00658             else
00659             {
00660                 //printf("patching LWZX at %p to LFSX at depth %ld\n",opStackLoadInstructionAddr[depth],depth);
00661                 //printf("old instruction: %08lx\n",instruction);
00662                 // Extract registers
00663                 destReg = (instruction >> 21) & 31;
00664                 aReg    = (instruction >> 16) & 31;
00665                 bReg    = (instruction >> 11) & 31;
00666                 // Calculate correct FP register to use.
00667                 // THIS ASSUMES REGISTER USAGE FOR THE STACK IS n, n+1, n+2, etc!
00668                 //printf("old dest: %ld\n",destReg);
00669                 destReg = (destReg - opStackIntRegisters[0]) + opStackFloatRegisters[0];
00670                 instruction = PPC_LFSX | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) ;          
00671                 //printf("new dest: %ld\n",destReg);
00672                 //printf("new instruction: %08lx\n",instruction);
00673             }
00674             *opStackLoadInstructionAddr[depth] = instruction;
00675             opStackLoadInstructionAddr[depth] = 0;
00676         }
00677         else
00678         {   
00679             //printf("doing float constant load at %p for depth %ld\n",&buf[compiledOfs],depth);
00680             // It was likely loaded as a constant so we have to save/load it.  A more
00681             // interesting implementation might be to generate code to do a "PC relative"
00682             // load from the VM code region.
00683             InstImm( "stw", PPC_STW, opStackIntRegisters[depth], R_OPSTACK, depth*4+4);
00684             // For XXX make sure we force enough NOPs to get the load into
00685             // another dispatch group to avoid pipeline flush.
00686             Inst( "ori", PPC_ORI,  0, 0, 0 );
00687             Inst( "ori", PPC_ORI,  0, 0, 0 );
00688             Inst( "ori", PPC_ORI,  0, 0, 0 );
00689             Inst( "ori", PPC_ORI,  0, 0, 0 );
00690             InstImm( "lfs", PPC_LFS, opStackFloatRegisters[depth], R_OPSTACK, depth*4+4);
00691         }
00692         opStackRegType[depth] = 2;
00693     }
00694 }
00695 
00696 // TJW: Unused
00697 #if 0
00698 static void fltop() {
00699     if (rtopped == qfalse) {
00700     InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 );        // get value from opstack
00701     }
00702 }
00703 #endif
00704 
00705 #if 0
00706 static void fltopandsecond() {
00707     InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 );        // get value from opstack
00708     InstImm( PPC_LFS, R_SECOND, R_OPSTACK, -4 );    // get value from opstack
00709     InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 );
00710     rtopped = qfalse;
00711     return;
00712 }
00713 #endif
00714 
00715 #define assertInteger(depth)    assert(opStackRegType[depth] == 1)
00716 
00717 /*
00718 =================
00719 VM_Compile
00720 =================
00721 */
00722 void VM_Compile( vm_t *vm, vmHeader_t *header ) {
00723     int     op;
00724     int     maxLength;
00725     int     v;
00726     int     i;
00727         int     opStackDepth;
00728     
00729     int     mainFunction;
00730     
00731     // set up the into-to-float variables
00732     ((int *)itofConvert)[0] = 0x43300000;
00733     ((int *)itofConvert)[1] = 0x80000000;
00734     ((int *)itofConvert)[2] = 0x43300000;
00735 
00736     // allocate a very large temp buffer, we will shrink it later
00737     maxLength = header->codeLength * 8;
00738     buf = Z_Malloc( maxLength );
00739     jused = Z_Malloc(header->instructionCount + 2);
00740     Com_Memset(jused, 0, header->instructionCount+2);
00741     
00742     // compile everything twice, so the second pass will have valid instruction
00743     // pointers for branches
00744     for ( pass = -1 ; pass < 2 ; pass++ ) {
00745 
00746         // translate all instructions
00747         pc = 0;
00748     mainFunction = 0;
00749     opStackDepth = 0;
00750     
00751     pop0 = 343545;
00752     pop1 = 2443545;
00753     oc0 = -2343535;
00754     oc1 = 24353454;
00755     tvm = vm;
00756         code = (byte *)header + header->codeOffset;
00757         compiledOfs = 0;
00758 #ifndef __GNUC__
00759         // metrowerks seems to require this header in front of functions
00760         Emit4( (int)(buf+2) );
00761         Emit4( 0 );
00762 #endif
00763 
00764     for ( instruction = 0 ; instruction < header->instructionCount ; instruction++ ) {
00765             if ( compiledOfs*4 > maxLength - 16 ) {
00766                 Com_Error( ERR_DROP, "VM_Compile: maxLength exceeded" );
00767             }
00768 
00769             op = code[ pc ];
00770             if ( !pass ) {
00771                 vm->instructionPointers[ instruction ] = compiledOfs * 4;
00772             }
00773             pc++;
00774             switch ( op ) {
00775             case 0:
00776                 break;
00777             case OP_BREAK:
00778         #if DEBUG_VM
00779         if(pass == 1)
00780             printf("%08lx BREAK\n",instruction);
00781         #endif
00782                 InstImmU( "addi", PPC_ADDI, R_TOP, 0, 0 );
00783                 InstImm( "lwz", PPC_LWZ, R_TOP, R_TOP, 0 );         // *(int *)0 to crash to debugger
00784                 break;
00785             case OP_ENTER:
00786         opStackDepth = 0;
00787         v = Constant4();
00788         #if DEBUG_VM
00789         if(pass == 1)
00790             printf("%08x ENTER\t%04x\n",instruction,v);
00791         #endif
00792         opStackRegType[opStackDepth] = 0;
00793         mainFunction++;
00794         if(mainFunction == 1)
00795         {
00796             // Main VM entry point is the first thing we compile, so save off operand stack
00797             // registers here.  This avoids issues with trying to trick the native compiler
00798             // into doing it, and properly matches the PowerPC ABI
00799             InstImm( "addi", PPC_ADDI, R_REAL_STACK, R_REAL_STACK, -OP_STACK_MAX_DEPTH*4 ); // sub R_STACK, R_STACK, imm
00800             for(i = 0; i < OP_STACK_MAX_DEPTH; i++)
00801                 InstImm( "stw", PPC_STW, opStackIntRegisters[i], R_REAL_STACK, i*4);
00802         }
00803                 InstImm( "addi", PPC_ADDI, R_STACK, R_STACK, -v );  // sub R_STACK, R_STACK, imm
00804                 break;
00805             case OP_CONST:
00806                 v = Constant4();
00807         #if DEBUG_VM
00808         if(pass == 1)
00809             printf("%08x CONST\t%08x\n",instruction,v);
00810         #endif
00811         opStackLoadInstructionAddr[opStackDepth] = 0;
00812                 if ( v < 32768 && v >= -32768 ) {
00813                     InstImmU( "addi", PPC_ADDI, opStackIntRegisters[opStackDepth], 0, v & 0xffff );
00814                 } else {
00815                     InstImmU( "addis", PPC_ADDIS, opStackIntRegisters[opStackDepth], 0, (v >> 16)&0xffff );
00816                     if ( v & 0xffff ) {
00817                         InstImmU( "ori", PPC_ORI, opStackIntRegisters[opStackDepth], opStackIntRegisters[opStackDepth], v & 0xffff );
00818                     }
00819                 }
00820         opStackRegType[opStackDepth] = 1;
00821         opStackDepth += 1;
00822         if (code[pc] == OP_JUMP) {
00823             jused[v] = 1;
00824         }
00825         break;
00826             case OP_LOCAL:
00827         oc1 = Constant4();
00828         #if DEBUG_VM
00829         if(pass == 1)
00830             printf("%08x LOCAL\t%08x\n",instruction,oc1);
00831         #endif
00832         if (code[pc] == OP_LOAD4 || code[pc] == OP_LOAD2 || code[pc] == OP_LOAD1) {
00833             oc1 &= vm->dataMask;
00834         }
00835                 InstImm( "addi", PPC_ADDI, opStackIntRegisters[opStackDepth], R_STACK, oc1 );
00836         opStackRegType[opStackDepth] = 1;
00837         opStackLoadInstructionAddr[opStackDepth] = 0;
00838         opStackDepth += 1;
00839                 break;
00840             case OP_ARG:
00841         v = Constant1();
00842         #if DEBUG_VM
00843         if(pass == 1)
00844             printf("%08x ARG \t%08x\n",instruction,v);
00845         #endif
00846                 InstImm( "addi", PPC_ADDI, R_EA, R_STACK, v );  // location to put it
00847         if(opStackRegType[opStackDepth-1] == 1)
00848             Inst( "stwx", PPC_STWX, opStackIntRegisters[opStackDepth-1], R_EA, R_MEMBASE );
00849         else
00850             Inst( "stfsx", PPC_STFSX, opStackFloatRegisters[opStackDepth-1], R_EA, R_MEMBASE );
00851         opStackRegType[opStackDepth-1] = 0;
00852         opStackLoadInstructionAddr[opStackDepth-1] = 0;
00853         opStackDepth -= 1;
00854         
00855                 break;
00856             case OP_CALL:
00857         #if DEBUG_VM
00858         if(pass == 1)
00859             printf("%08x CALL\n",instruction);
00860         #endif
00861         assertInteger(opStackDepth-1);
00862         assert(opStackDepth > 0);
00863                 Inst( "mflr", PPC_MFSPR, R_SECOND, 8, 0 );          // move from link register
00864                 InstImm( "stwu", PPC_STWU, R_SECOND, R_REAL_STACK, -16 );   // save off the old return address
00865 
00866         // Spill operand stack registers.
00867         spillOpStack(opStackDepth);
00868         
00869         // We need to leave R_OPSTACK pointing to the top entry on the stack, which is the call address.
00870         // It will be consumed (and R4 decremented) by the AsmCall code.
00871         InstImm( "addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, opStackDepth*4);
00872 
00873                 Inst( "mtctr", PPC_MTSPR, R_ASMCALL, 9, 0 );            // move to count register
00874                 Inst( "bctrl", PPC_BCCTR | 1, 20, 0, 0 );           // jump and link to the count register
00875 
00876         // R4 now points to the top of the operand stack, which has the return value in it.  We want to
00877         // back off the pointer to point to the base of our local operand stack and then reload the stack.
00878         
00879         InstImm("addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, -opStackDepth*4);
00880         
00881         // Reload operand stack.
00882         loadOpStack(opStackDepth);
00883 
00884                 InstImm( "lwz", PPC_LWZ, R_SECOND, R_REAL_STACK, 0 );       // fetch the old return address
00885                 InstImm( "addi", PPC_ADDI, R_REAL_STACK, R_REAL_STACK, 16 );
00886                 Inst( "mtlr", PPC_MTSPR, R_SECOND, 8, 0 );          // move to link register
00887                 break;
00888             case OP_PUSH:
00889         #if DEBUG_VM
00890         if(pass == 1)
00891             printf("%08x PUSH\n",instruction);
00892         #endif
00893         opStackRegType[opStackDepth] = 1;   // Garbage int value.
00894         opStackDepth += 1;
00895                 break;
00896             case OP_POP:
00897         #if DEBUG_VM
00898         if(pass == 1)
00899             printf("%08x POP\n",instruction);
00900         #endif
00901         opStackDepth -= 1;
00902         opStackRegType[opStackDepth] = 0;   // ??
00903         opStackLoadInstructionAddr[opStackDepth-1] = 0;
00904                 break;
00905             case OP_LEAVE:
00906         #if DEBUG_VM
00907         if(pass == 1)
00908             printf("%08x LEAVE\n",instruction);
00909         #endif
00910         assert(opStackDepth == 1);
00911         assert(opStackRegType[0] != 0);
00912         // Save return value onto top of op stack.  We also have to increment R_OPSTACK
00913         switch(opStackRegType[0])
00914         {
00915             case 1: // Integer register
00916                 InstImm( "stw", PPC_STWU, opStackIntRegisters[0], R_OPSTACK, 4);
00917                 break;
00918             case 2: // Float register
00919                 InstImm( "stfs", PPC_STFSU, opStackFloatRegisters[0], R_OPSTACK, 4);
00920                 break;
00921         }
00922                 InstImm( "addi", PPC_ADDI, R_STACK, R_STACK, Constant4() ); // add R_STACK, R_STACK, imm
00923         if(mainFunction == 1)
00924         {
00925             for(i = 0; i < OP_STACK_MAX_DEPTH; i++)
00926                 InstImm( "lwz", PPC_LWZ,  opStackIntRegisters[i], R_REAL_STACK, i*4);
00927             InstImm( "addi", PPC_ADDI, R_REAL_STACK, R_REAL_STACK, OP_STACK_MAX_DEPTH*4 );  
00928         }
00929         opStackDepth--;
00930         opStackRegType[opStackDepth] = 0;
00931         opStackLoadInstructionAddr[opStackDepth] = 0;
00932                 Inst( "blr", PPC_BCLR, 20, 0, 0 );                          // branch unconditionally to link register
00933                 break;
00934             case OP_LOAD4:
00935         #if DEBUG_VM
00936         if(pass == 1)
00937             printf("%08x LOAD4\n",instruction);
00938         #endif
00939         // We should try to figure out whether to use LWZX or LFSX based
00940         // on some kind of code analysis after subsequent passes.  I think what
00941         // we could do is store the compiled load instruction address along with
00942         // the register type.  When we hit the first mismatched operator, we go back
00943         // and patch the load.  Since LCC's operand stack should be at 0 depth by the
00944         // time we hit a branch, this should work fairly well.  FIXME FIXME FIXME.
00945         assertInteger(opStackDepth-1);
00946         opStackLoadInstructionAddr[opStackDepth-1] = &buf[ compiledOfs ];
00947                 Inst( "lwzx", PPC_LWZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE );// load from memory base
00948         opStackRegType[opStackDepth-1] = 1;
00949                 break;
00950             case OP_LOAD2:
00951         #if DEBUG_VM
00952         if(pass == 1)
00953             printf("%08x LOAD2\n",instruction);
00954         #endif
00955         assertInteger(opStackDepth-1);
00956         opStackLoadInstructionAddr[opStackDepth-1] = 0;
00957                 Inst( "lhzx", PPC_LHZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE );// load from memory base
00958         opStackRegType[opStackDepth-1] = 1;
00959                 break;
00960             case OP_LOAD1:
00961         #if DEBUG_VM
00962         if(pass == 1)
00963             printf("%08x LOAD1\n",instruction);
00964         #endif
00965         assertInteger(opStackDepth-1);
00966         opStackLoadInstructionAddr[opStackDepth-1] = 0;
00967                 Inst( "lbzx", PPC_LBZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE );// load from memory base
00968         opStackRegType[opStackDepth-1] = 1;
00969                 break;
00970             case OP_STORE4:
00971         #if DEBUG_VM
00972         if(pass == 1)
00973             printf("%08x STORE4\n",instruction);
00974         #endif
00975         assertInteger(opStackDepth-2);
00976         if(opStackRegType[opStackDepth-1] == 1)
00977             Inst( "stwx", PPC_STWX, opStackIntRegisters[opStackDepth-1], 
00978                     opStackIntRegisters[opStackDepth-2], R_MEMBASE );       // store from memory base
00979         else
00980             Inst( "stfsx", PPC_STFSX, opStackFloatRegisters[opStackDepth-1], 
00981                     opStackIntRegisters[opStackDepth-2], R_MEMBASE );       // store from memory base
00982         opStackRegType[opStackDepth-1] = 0;
00983         opStackRegType[opStackDepth-2] = 0;
00984         opStackLoadInstructionAddr[opStackDepth-1] = 0;
00985         opStackLoadInstructionAddr[opStackDepth-2] = 0;
00986         opStackDepth -= 2;
00987                 break;
00988             case OP_STORE2:
00989         #if DEBUG_VM
00990         if(pass == 1)
00991             printf("%08x STORE2\n",instruction);
00992         #endif
00993         assertInteger(opStackDepth-1);
00994         assertInteger(opStackDepth-2);
00995                 Inst( "sthx", PPC_STHX, opStackIntRegisters[opStackDepth-1],
00996                 opStackIntRegisters[opStackDepth-2], R_MEMBASE );       // store from memory base
00997         opStackRegType[opStackDepth-1] = 0;
00998         opStackRegType[opStackDepth-2] = 0;
00999         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01000         opStackLoadInstructionAddr[opStackDepth-2] = 0;
01001         opStackDepth -= 2;
01002                 break;
01003             case OP_STORE1:
01004         #if DEBUG_VM
01005         if(pass == 1)
01006             printf("%08x STORE1\n",instruction);
01007         #endif
01008         assertInteger(opStackDepth-1);
01009         assertInteger(opStackDepth-2);
01010                 Inst( "stbx", PPC_STBX, opStackIntRegisters[opStackDepth-1],
01011                 opStackIntRegisters[opStackDepth-2], R_MEMBASE );       // store from memory base
01012         opStackRegType[opStackDepth-1] = 0;
01013         opStackRegType[opStackDepth-2] = 0;
01014         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01015         opStackLoadInstructionAddr[opStackDepth-2] = 0;
01016         opStackDepth -= 2;
01017                 break;
01018 
01019             case OP_EQ:
01020         #if DEBUG_VM
01021         if(pass == 1)
01022             printf("%08x EQ\n",instruction);
01023         #endif
01024         assertInteger(opStackDepth-1);
01025         assertInteger(opStackDepth-2);
01026                 Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01027         opStackRegType[opStackDepth-1] = 0;
01028         opStackRegType[opStackDepth-2] = 0;
01029         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01030         opStackLoadInstructionAddr[opStackDepth-2] = 0;
01031         opStackDepth -= 2;
01032                 i = Constant4();
01033                 jused[i] = 1;
01034                 InstImm( "bc", PPC_BC, 4, 2, 8 );
01035                 if ( pass==1 ) {
01036                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];                    
01037                 } else {
01038                     v = 0;             
01039                 }
01040                 Emit4("b", PPC_B | (v&0x3ffffff) );
01041                 break;
01042             case OP_NE:
01043         #if DEBUG_VM
01044         if(pass == 1)
01045             printf("%08x NE\n",instruction);
01046         #endif
01047         assertInteger(opStackDepth-1);
01048         assertInteger(opStackDepth-2);
01049                 Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01050         opStackRegType[opStackDepth-1] = 0;
01051         opStackRegType[opStackDepth-2] = 0;
01052         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01053         opStackLoadInstructionAddr[opStackDepth-2] = 0;
01054         opStackDepth -= 2;
01055                 i = Constant4();
01056                 jused[i] = 1;
01057                 InstImm( "bc", PPC_BC, 12, 2, 8 );
01058                 if ( pass==1 ) {
01059                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];                    
01060                 } else {
01061                     v = 0;
01062                 }
01063                 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
01064 //                InstImm( "bc", PPC_BC, 4, 2, v );
01065 
01066                 break;
01067             case OP_LTI:
01068         #if DEBUG_VM
01069         if(pass == 1)
01070         printf("%08x LTI\n",instruction);
01071         #endif
01072         assertInteger(opStackDepth-1);
01073         assertInteger(opStackDepth-2);
01074                 Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01075         opStackRegType[opStackDepth-1] = 0;
01076         opStackRegType[opStackDepth-2] = 0;
01077         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01078         opStackLoadInstructionAddr[opStackDepth-2] = 0;
01079         opStackDepth -= 2;
01080                 i = Constant4();
01081                 jused[i] = 1;
01082                 InstImm( "bc", PPC_BC, 4, 0, 8 );
01083                 if ( pass==1 ) {
01084                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
01085                 } else {
01086                     v = 0;
01087                 }
01088                 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
01089 //                InstImm( "bc", PPC_BC, 12, 0, v );
01090                 break;
01091             case OP_LEI:
01092         #if DEBUG_VM
01093         if(pass == 1)
01094         printf("%08x LEI\n",instruction);
01095         #endif
01096         assertInteger(opStackDepth-1);
01097         assertInteger(opStackDepth-2);
01098                 Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01099         opStackRegType[opStackDepth-1] = 0;
01100         opStackRegType[opStackDepth-2] = 0;
01101         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01102         opStackLoadInstructionAddr[opStackDepth-2] = 0;
01103         opStackDepth -= 2;
01104                 i = Constant4();
01105                 jused[i] = 1;
01106                 InstImm( "bc", PPC_BC, 12, 1, 8 );
01107                 if ( pass==1 ) {
01108                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
01109                 } else {
01110                     v = 0;
01111                 }
01112                 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
01113 //                InstImm( "bc", PPC_BC, 4, 1, v );
01114                 break;
01115             case OP_GTI:
01116         #if DEBUG_VM
01117         if(pass == 1)
01118         printf("%08x GTI\n",instruction);
01119         #endif
01120         assertInteger(opStackDepth-1);
01121         assertInteger(opStackDepth-2);
01122                 Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01123         opStackRegType[opStackDepth-1] = 0;
01124         opStackRegType[opStackDepth-2] = 0;
01125         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01126         opStackLoadInstructionAddr[opStackDepth-2] = 0;
01127         opStackDepth -= 2;
01128                 i = Constant4();
01129                 jused[i] = 1;
01130                 InstImm( "bc", PPC_BC, 4, 1, 8 );
01131                 if ( pass==1 ) {
01132                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
01133                 } else {
01134                     v = 0;
01135                 }
01136                 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
01137 //                InstImm( "bc", PPC_BC, 12, 1, v );
01138                 break;
01139             case OP_GEI:
01140         #if DEBUG_VM
01141         if(pass == 1)
01142         printf("%08x GEI\n",instruction);
01143         #endif
01144         assertInteger(opStackDepth-1);
01145         assertInteger(opStackDepth-2);
01146                 Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01147         opStackRegType[opStackDepth-1] = 0;
01148         opStackRegType[opStackDepth-2] = 0;
01149         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01150         opStackLoadInstructionAddr[opStackDepth-2] = 0;
01151         opStackDepth -= 2;
01152                 i = Constant4();
01153                 jused[i] = 1;
01154                 InstImm( "bc", PPC_BC, 12, 0, 8 );
01155                 if ( pass==1 ) {
01156                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
01157                 } else {
01158                     v = 0;
01159                 }
01160                 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
01161 //                InstImm( "bc", PPC_BC, 4, 0, v );
01162                 break;
01163             case OP_LTU:
01164         #if DEBUG_VM
01165         if(pass == 1)
01166         printf("%08x LTU\n",instruction);
01167         #endif
01168         assertInteger(opStackDepth-1);
01169         assertInteger(opStackDepth-2);
01170                 Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01171         opStackRegType[opStackDepth-1] = 0;
01172         opStackRegType[opStackDepth-2] = 0;
01173         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01174         opStackLoadInstructionAddr[opStackDepth-2] = 0;
01175         opStackDepth -= 2;
01176                 i = Constant4();
01177         jused[i] = 1;
01178                 InstImm( "bc", PPC_BC, 4, 0, 8 );
01179                 if ( pass==1 ) {
01180                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
01181                 } else {
01182                     v = 0;
01183                 }
01184                 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
01185 //                InstImm( "bc", PPC_BC, 12, 0, v );
01186                 break;
01187             case OP_LEU:
01188         #if DEBUG_VM
01189         if(pass == 1)
01190         printf("%08x LEU\n",instruction);
01191         #endif
01192         assertInteger(opStackDepth-1);
01193         assertInteger(opStackDepth-2);
01194                 Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] );
01195         opStackRegType[opStackDepth-1] = 0;
01196         opStackRegType[opStackDepth-2] = 0;
01197         opStackLoadInstructionAddr[opStackDepth-1] = 0;
01198         opStackLoadInstructionAddr[opStackDepth-2] = 0;
01199         opStackDepth -= 2;
01200                 i = Constant4();
01201         jused[i] = 1;
01202                 InstImm( "bc", PPC_BC, 12, 1, 8 );
01203                 if ( pass==1 ) {
01204                     v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs];
01205                 } else {
01206                     v = 0;
01207                 }
01208                 Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) );
01209 //                InstImm( "bc", PPC_BC, 4, 1, v );
01210                 break;
01211             case OP_GTU:
01212         #if DEBUG_VM
01213         if(pass == 1)
01214         printf(