From a7cf3a91f851a50971adcbbc2c2444677b5cb8de Mon Sep 17 00:00:00 2001 From: cacao Date: Fri, 13 Nov 1998 09:12:34 +0000 Subject: [PATCH] first part of mips port --- mips/calling.doc | 165 +++ mips/disass.c | 504 +++++++ mips/ngen.c | 3604 ++++++++++++++++++++++++++++++++++++++++++++++ mips/ngen.h | 390 +++++ 4 files changed, 4663 insertions(+) create mode 100644 mips/calling.doc create mode 100644 mips/disass.c create mode 100644 mips/ngen.c create mode 100644 mips/ngen.h diff --git a/mips/calling.doc b/mips/calling.doc new file mode 100644 index 000000000..95d3ce390 --- /dev/null +++ b/mips/calling.doc @@ -0,0 +1,165 @@ +/* calling.doc ***************************************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + A short description of MIPS calling conventions and register usage. + + Authors: Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1998/11/05 + +*******************************************************************************/ + +Short documentation of the Java calling conventions for the MIPS. + +-------------------------------------------------------------------------------- + + +Die Aufrufskonventionen halten sich weitgehende an die Konventionen +f"ur normale C-Funktionen, allerdings mit einigen zus"atzlichen +Registerbelegungen: + +R28 ..... enth"alt bei einem Methodenaufruf auf jeden Fall den Zeiger + auf die zugeh"orige 'methodinfo'-Struktur, die gegebenenfalls an + den JIT-Compiler weitergegeben werden muss. + + Wenn von Java-Methoden aus direkt C-Funktionen aufgerufen werden, + (f"ur die nat"urlich auch keine 'methodinfo'-Struktur existiert), + dann hat dieses Register keinen definierten Wert (Alle von der + JavaVM verwendeten Funktionen, z. B. 'builtin_new', etc. werden + so aufgerufen) + +Die restlichen Register folgen den normalen Konventionen, aber ich gebe +hier noch einmal eine kurze "Ubersicht: + + +integer registers: + +R0 ........ always contains zero + +R1 ........ code generator temporary register (destroyed by called method) + +R2 ........ method result value for types INT, LONG and ADDRESS + +R3 ........ code generator temporary register (destroyed by called method) + +R4 -R11 ... argument registers 0 - 7 (contain the first six method arguments + of type INT, LONG and ADDRESS. Argument registers are destroyed + by called method) + +R12-R15 ... temporary registers (destroyed by called method) + +R16-R23 ... saved registers (left unchanged by called method) + +R24 ....... pointer to 'methodinfo' structure. This register has to be set + correctly, because it is needed in the case the jit is invoked. + Also used as code generator temporary register. It is destroyed + by called method) + +R25 (pv) .. procedure vector, points to the first instruction of the called + method. This vector is used for addressing the entries in the + data segment. The ov of the caller is recomputed from the ra. + Therefore it is necessary that a return is always done using ra. + +R26-R27 ... reserved register (reserved for kernel) + +R28 ....... saved registers (left unchanged by called method) + +R29 (sp) .. stack pointer. The stack grows from high to low. + +R30 ....... saved register (left unchanged by called method) + +R31 (ra) .. return address (left unchanged by called method) + + +floating point registers: + +F0 ........ method result value for types FLOAT and DOUBLE + +F1-F3 ..... code generator temporary register (destroyed by called method) + +F4 -F11 ... temporary register (destroyed by called method) + +F12-F19 ... argument registers 0 - 7 (contain the first 8 method arguments + of type FLOAT and DOUBLE. Argument registers are destroyed + by called method) + +F20-F23 ... temporary registers (destroyed by called method) + +F24 ....... saved register (left unchanged by called method) + +F25 ....... temporary register (destroyed by called method) + +F26 ....... saved register (left unchanged by called method) + +F27 ....... temporary register (destroyed by called method) + +F28 ....... saved register (left unchanged by called method) + +F29 ....... temporary register (destroyed by called method) + +F30 ....... saved register (left unchanged by called method) + +F31 ....... temporary register (destroyed by called method) + + +PARAMETER"UBERGABE AM STACK: + +Bei mehr als sechs Parametern reicht der Platz in den Registern nicht mehr +aus, daf"ur werden alle Parameter ab dem Siebenten am Stack "ubergeben, +und zwar nach folgendem Muster: + + + | ..... | + -------------------------------------------------- + | Parameter 9 ( 64 bit, egal bei welchem Typ) | + -------------------------------------------------- + | Parameter 8 ( 64 bit, egal bei welchem Typ | + -------------------------------------------------- + R30 (sp) ---> | Parameter 7 ( 64 bit, egal bei welchem Typ) | + -------------------------------------------------- + +Der Stackpointer zeigt dabei auf die Untergrenze des Parameterbereichs. + + + + + +VOLLST"ANDIGES LAYOUT EINES STACKFRAMES: + +Jede Methode muss (wenn es keine Leaf-Methode ist, auf jeden Fall) gewisse +Registerinhalte am Stack sichern. +Eventuell werden auch noch lokale Werte, die nicht mehr in Registern +Platz finden, ebenfalls am Stack aufbewahrt, und die Parameter"ubergabe +bei mehr als 6 Parametern ben"otigt ebenfalls Platz am Stack. + +Ein vollst"andiger Stackframe hat also dieses Aussehen (jeder Eintrag +im Stackframe ist unabh"angig vom Typ auf jedem Fall 64 bit lang, die +Gr"ossenangaben der Bereiche sind in solchen Einheiten von 64 Bit +angegeben): + + --------------------------------------------- + | parameter n (passed from caller) | + --------------------------------------------- + | parameter n-1 | + --------------------------------------------- + | ... | + --------------------------------------------- + | parameter 7 | +old SP ---> ============================================= --- parentargs_base + | saved RA | + --------------------------------------------- savedregs_num + | others saved registers | + ============================================= --- maxmemuse + 1 + | optional monitor_exit argument | + ============================================= --- maxmemuse + | area for spilled registers | + ============================================= + | .... | + --------------------------------------------- + | parameter 8 | + --------------------------------------------- + | parameter 7 (passed to called method) | +new SP ---> ============================================= diff --git a/mips/disass.c b/mips/disass.c new file mode 100644 index 000000000..88e6b1d12 --- /dev/null +++ b/mips/disass.c @@ -0,0 +1,504 @@ +/* disass.c ******************************************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + A very primitive disassembler for MIPS machine code for easy debugging. + + Authors: Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1998/11/12 + +*******************************************************************************/ + +/* The disassembler uses four tables for decoding the instructions. The first + table (ops) is used to classify the instructions based on the op code and + contains the instruction names for instructions which don't used the + function codes. This table is indexed by the op code (6 bit, 64 entries). + The other tables are either indexed by the function code or some special + format and branch codes. +*/ + +#define ITYPE_UNDEF 0 /* undefined instructions (illegal opcode) */ +#define ITYPE_JMP 1 /* jump instructions */ +#define ITYPE_IMM 2 /* immediate instructions */ +#define ITYPE_MEM 3 /* memory instructions */ +#define ITYPE_BRA 4 /* branch instructions */ +#define ITYPE_RIMM 5 /* special/branch instructions */ +#define ITYPE_OP 6 /* integer instructions */ +#define ITYPE_TRAP 7 /* trap instructions */ +#define ITYPE_DIVMUL 8 /* integer divide/multiply instructions */ +#define ITYPE_MTOJR 9 /* move to and jump register instructions */ +#define ITYPE_MFROM 10 /* move from instructions */ +#define ITYPE_SYS 11 /* operating system instructions */ +#define ITYPE_FOP 12 /* floating point instructions */ +#define ITYPE_FOP2 13 /* 2 operand floating point instructions */ +#define ITYPE_FCMP 14 /* floating point compare instructions */ + + +/* instruction decode table for 6 bit op codes */ + +static struct {char *name; int itype;} ops[] = { + + /* 0x00 */ {"SPECIAL ", ITYPE_OP}, + /* 0x01 */ {"REGIMM ", ITYPE_RIMM}, + /* 0x02 */ {"J ", ITYPE_JMP}, + /* 0x03 */ {"JAL ", ITYPE_JMP}, + /* 0x04 */ {"BEQ ", ITYPE_BRA}, + /* 0x05 */ {"BNE ", ITYPE_BRA}, + /* 0x06 */ {"BLEZ ", ITYPE_BRA}, + /* 0x07 */ {"BGTZ ", ITYPE_BRA}, + + /* 0x08 */ {"ADDI ", ITYPE_IMM}, + /* 0x09 */ {"ADDIU ", ITYPE_IMM}, + /* 0x0a */ {"SLTI ", ITYPE_IMM}, + /* 0x0b */ {"SLTIU ", ITYPE_IMM}, + /* 0x0c */ {"ANDI ", ITYPE_IMM}, + /* 0x0d */ {"ORI ", ITYPE_IMM}, + /* 0x0e */ {"XORI ", ITYPE_IMM}, + /* 0x0f */ {"LUI ", ITYPE_IMM}, + + /* 0x10 */ {"COP0 ", ITYPE_OP}, + /* 0x11 */ {"COP1 ", ITYPE_FOP}, + /* 0x12 */ {"COP2 ", ITYPE_OP}, + /* 0x13 */ {"", ITYPE_UNDEF}, + /* 0x14 */ {"BEQL ", ITYPE_BRA}, + /* 0x15 */ {"BNEL ", ITYPE_BRA}, + /* 0x16 */ {"BLEZL ", ITYPE_BRA}, + /* 0x17 */ {"BGTZL ", ITYPE_BRA}, + + /* 0x18 */ {"DADDI ", ITYPE_IMM}, + /* 0x19 */ {"DADDIU ", ITYPE_IMM}, + /* 0x1a */ {"LDL ", ITYPE_MEM}, + /* 0x1b */ {"LDR ", ITYPE_MEM}, + /* 0x1c */ {"", ITYPE_UNDEF}, + /* 0x1d */ {"", ITYPE_UNDEF}, + /* 0x1e */ {"", ITYPE_UNDEF}, + /* 0x1f */ {"", ITYPE_UNDEF}, + + /* 0x20 */ {"LB ", ITYPE_MEM}, + /* 0x21 */ {"LH ", ITYPE_MEM}, + /* 0x22 */ {"LWL ", ITYPE_MEM}, + /* 0x23 */ {"LW ", ITYPE_MEM}, + /* 0x24 */ {"LBU ", ITYPE_MEM}, + /* 0x25 */ {"LHU ", ITYPE_MEM}, + /* 0x26 */ {"LWR ", ITYPE_MEM}, + /* 0x27 */ {"LWU ", ITYPE_MEM}, + + /* 0x28 */ {"SB ", ITYPE_MEM}, + /* 0x29 */ {"SH ", ITYPE_MEM}, + /* 0x2a */ {"SWL ", ITYPE_MEM}, + /* 0x2b */ {"SW ", ITYPE_MEM}, + /* 0x2c */ {"SDL ", ITYPE_MEM}, + /* 0x2d */ {"SDR ", ITYPE_MEM}, + /* 0x2e */ {"SWR ", ITYPE_MEM}, + /* 0x2f */ {"CACHE ", ITYPE_MEM}, + + /* 0x30 */ {"LL ", ITYPE_MEM}, + /* 0x31 */ {"LWC1 ", ITYPE_MEM}, + /* 0x32 */ {"LWC2 ", ITYPE_MEM}, + /* 0x33 */ {"", ITYPE_UNDEF}, + /* 0x34 */ {"LLD ", ITYPE_MEM}, + /* 0x35 */ {"LDC1 ", ITYPE_MEM}, + /* 0x36 */ {"LDC2 ", ITYPE_MEM}, + /* 0x37 */ {"LD ", ITYPE_MEM}, + + /* 0x38 */ {"SC ", ITYPE_MEM}, + /* 0x39 */ {"SWC1 ", ITYPE_MEM}, + /* 0x3a */ {"SWC2 ", ITYPE_MEM}, + /* 0x3b */ {"", ITYPE_UNDEF}, + /* 0x3c */ {"SLD ", ITYPE_MEM}, + /* 0x3d */ {"SDC1 ", ITYPE_MEM}, + /* 0x3e */ {"SDC2 ", ITYPE_MEM}, + /* 0x3f */ {"SD ", ITYPE_MEM} +}; + + +/* instruction decode table for 6 bit special function codes */ + +static struct {char *name; int ftype;} regops[] = { + + /* 0x00 */ {"SLL ", ITYPE_IMM}, + /* 0x01 */ {"" , ITYPE_UNDEF}, + /* 0x02 */ {"SRL ", ITYPE_IMM}, + /* 0x03 */ {"SRA ", ITYPE_IMM}, + /* 0x04 */ {"SLLV ", ITYPE_OP}, + /* 0x05 */ {"" , ITYPE_UNDEF}, + /* 0x06 */ {"SRLV ", ITYPE_OP}, + /* 0x07 */ {"SRAV ", ITYPE_OP}, + + /* 0x08 */ {"JR ", ITYPE_MTOJR}, + /* 0x09 */ {"JALR ", ITYPE_JMP}, + /* 0x0a */ {"" , ITYPE_UNDEF}, + /* 0x0b */ {"" , ITYPE_UNDEF}, + /* 0x0c */ {"SYSCALL ", ITYPE_SYS}, + /* 0x0d */ {"BREAK ", ITYPE_SYS}, + /* 0x0e */ {"" , ITYPE_UNDEF}, + /* 0x0f */ {"SYNC ", ITYPE_SYS}, + + /* 0x10 */ {"MFHI ", ITYPE_MFROM}, + /* 0x11 */ {"MTHI ", ITYPE_MTOJR}, + /* 0x12 */ {"MFLO ", ITYPE_MFROM}, + /* 0x13 */ {"MTLO ", ITYPE_MTOJR}, + /* 0x14 */ {"DSLLV ", ITYPE_OP}, + /* 0x15 */ {"" , ITYPE_UNDEF}, + /* 0x16 */ {"DSLRV ", ITYPE_OP}, + /* 0x17 */ {"DSRAV ", ITYPE_OP}, + + /* 0x18 */ {"MULT ",ITYPE_DIVMUL}, + /* 0x19 */ {"MULTU ",ITYPE_DIVMUL}, + /* 0x1a */ {"DIV ",ITYPE_DIVMUL}, + /* 0x1b */ {"DIVU ",ITYPE_DIVMUL}, + /* 0x1c */ {"DMULT ",ITYPE_DIVMUL}, + /* 0x1d */ {"DMULTU ",ITYPE_DIVMUL}, + /* 0x1e */ {"DDIV ",ITYPE_DIVMUL}, + /* 0x1f */ {"DDIVU ",ITYPE_DIVMUL}, + + /* 0x20 */ {"ADD ", ITYPE_OP}, + /* 0x21 */ {"ADDU ", ITYPE_OP}, + /* 0x22 */ {"SUB ", ITYPE_OP}, + /* 0x23 */ {"SUBU ", ITYPE_OP}, + /* 0x24 */ {"AND ", ITYPE_OP}, + /* 0x25 */ {"OR ", ITYPE_OP}, + /* 0x26 */ {"XOR ", ITYPE_OP}, + /* 0x27 */ {"NOR ", ITYPE_OP}, + + /* 0x28 */ {"" , ITYPE_UNDEF}, + /* 0x29 */ {"" , ITYPE_UNDEF}, + /* 0x2a */ {"SLT ", ITYPE_OP}, + /* 0x2b */ {"SLTU ", ITYPE_OP}, + /* 0x2c */ {"DADD ", ITYPE_OP}, + /* 0x2d */ {"DADDU ", ITYPE_OP}, + /* 0x2e */ {"DSUB ", ITYPE_OP}, + /* 0x2f */ {"DSUBU ", ITYPE_OP}, + + /* 0x30 */ {"TGE ", ITYPE_TRAP}, + /* 0x31 */ {"TGEU ", ITYPE_TRAP}, + /* 0x32 */ {"TLT ", ITYPE_TRAP}, + /* 0x33 */ {"TLTU ", ITYPE_TRAP}, + /* 0x34 */ {"TEQ ", ITYPE_TRAP}, + /* 0x35 */ {"" , ITYPE_UNDEF}, + /* 0x36 */ {"TNE ", ITYPE_TRAP}, + /* 0x37 */ {"" , ITYPE_UNDEF}, + + /* 0x38 */ {"DSLL ", ITYPE_IMM}, + /* 0x39 */ {"" , ITYPE_UNDEF}, + /* 0x3a */ {"DSLR ", ITYPE_IMM}, + /* 0x3b */ {"DSRA ", ITYPE_IMM}, + /* 0x3c */ {"DSLL32 ", ITYPE_IMM}, + /* 0x3d */ {"" , ITYPE_UNDEF}, + /* 0x3e */ {"DSLR32 ", ITYPE_IMM}, + /* 0x3f */ {"DSRA32 ", ITYPE_IMM} +}; + + +/* instruction decode table for 5 bit reg immediate function codes */ + +static struct {char *name; int ftype;} regimms[] = { + + /* 0x00 */ {"BLTZ ", ITYPE_BRA}, + /* 0x01 */ {"BGEZ ", ITYPE_BRA}, + /* 0x02 */ {"BLTZL ", ITYPE_BRA}, + /* 0x03 */ {"BGEZL ", ITYPE_BRA}, + /* 0x04 */ {"", ITYPE_UNDEF}, + /* 0x05 */ {"", ITYPE_UNDEF}, + /* 0x06 */ {"", ITYPE_UNDEF}, + /* 0x07 */ {"", ITYPE_UNDEF}, + + /* 0x08 */ {"TGEI ", ITYPE_IMM}, + /* 0x09 */ {"DGEIU ", ITYPE_IMM}, + /* 0x0a */ {"TLTI ", ITYPE_IMM}, + /* 0x0b */ {"TLTIU ", ITYPE_IMM}, + /* 0x0c */ {"TEQI ", ITYPE_IMM}, + /* 0x0d */ {"" , ITYPE_UNDEF}, + /* 0x0e */ {"TNEI ", ITYPE_IMM}, + /* 0x0f */ {"" , ITYPE_UNDEF}, + + /* 0x10 */ {"BLTZAL ", ITYPE_BRA}, + /* 0x11 */ {"BGEZAL ", ITYPE_BRA}, + /* 0x12 */ {"BLTZALL", ITYPE_BRA}, + /* 0x13 */ {"BGEZALL", ITYPE_BRA}, + /* 0x14 */ {"", ITYPE_UNDEF}, + /* 0x15 */ {"", ITYPE_UNDEF}, + /* 0x16 */ {"", ITYPE_UNDEF}, + /* 0x17 */ {"", ITYPE_UNDEF}, + + /* 0x18 */ {"", ITYPE_UNDEF}, + /* 0x19 */ {"", ITYPE_UNDEF}, + /* 0x1a */ {"", ITYPE_UNDEF}, + /* 0x1b */ {"", ITYPE_UNDEF}, + /* 0x1c */ {"", ITYPE_UNDEF}, + /* 0x1d */ {"", ITYPE_UNDEF}, + /* 0x1e */ {"", ITYPE_UNDEF}, + /* 0x1f */ {"", ITYPE_UNDEF} +}; + + +/* instruction decode table for 6 bit floating point op codes */ + +static struct {char *name; char *fill; int ftype;} fops[] = { + + /* 0x00 */ {"ADD", " ", ITYPE_FOP}, + /* 0x01 */ {"SUB", " ", ITYPE_FOP}, + /* 0x02 */ {"MUL", " ", ITYPE_FOP}, + /* 0x03 */ {"DIV", " ", ITYPE_FOP}, + /* 0x04 */ {"SQRT", " ", ITYPE_FOP}, + /* 0x05 */ {"ABS", " ", ITYPE_FOP2}, + /* 0x06 */ {"MOV", " ", ITYPE_FOP2}, + /* 0x07 */ {"NEG", " ", ITYPE_FOP2}, + + /* 0x08 */ {"ROUNDL", "", ITYPE_FOP2}, + /* 0x09 */ {"TRUNCL", "", ITYPE_FOP2}, + /* 0x0a */ {"CEILL", " ", ITYPE_FOP2}, + /* 0x0b */ {"FLOORL", "", ITYPE_FOP2}, + /* 0x0c */ {"ROUND", " ", ITYPE_FOP2}, + /* 0x0d */ {"TRUNC", " ", ITYPE_FOP2}, + /* 0x0e */ {"CEIL", " ", ITYPE_FOP2}, + /* 0x0f */ {"FLOOR", " ", ITYPE_FOP2}, + + /* 0x10 */ {"", "", ITYPE_UNDEF}, + /* 0x11 */ {"", "", ITYPE_UNDEF}, + /* 0x12 */ {"", "", ITYPE_UNDEF}, + /* 0x13 */ {"", "", ITYPE_UNDEF}, + /* 0x14 */ {"", "", ITYPE_UNDEF}, + /* 0x15 */ {"", "", ITYPE_UNDEF}, + /* 0x16 */ {"", "", ITYPE_UNDEF}, + /* 0x17 */ {"", "", ITYPE_UNDEF}, + + /* 0x18 */ {"", "", ITYPE_UNDEF}, + /* 0x19 */ {"RECIP", " ", ITYPE_FOP2}, + /* 0x1a */ {"RSQRT", " ", ITYPE_FOP2}, + /* 0x1b */ {"", "", ITYPE_UNDEF}, + /* 0x1c */ {"", "", ITYPE_UNDEF}, + /* 0x1d */ {"", "", ITYPE_UNDEF}, + /* 0x1e */ {"", "", ITYPE_UNDEF}, + /* 0x1f */ {"", "", ITYPE_UNDEF}, + + /* 0x20 */ {"CVTS", " ", ITYPE_FOP2}, + /* 0x21 */ {"CVTD", " ", ITYPE_FOP2}, + /* 0x22 */ {"CVTX", " ", ITYPE_FOP2}, + /* 0x23 */ {"CVTQ", " ", ITYPE_FOP2}, + /* 0x24 */ {"CVTW", " ", ITYPE_FOP2}, + /* 0x25 */ {"CVTL", " ", ITYPE_FOP2}, + /* 0x26 */ {"", "", ITYPE_UNDEF}, + /* 0x27 */ {"", "", ITYPE_UNDEF}, + + /* 0x28 */ {"", "", ITYPE_UNDEF}, + /* 0x29 */ {"", "", ITYPE_UNDEF}, + /* 0x2a */ {"", "", ITYPE_UNDEF}, + /* 0x2b */ {"", "", ITYPE_UNDEF}, + /* 0x2c */ {"", "", ITYPE_UNDEF}, + /* 0x2d */ {"", "", ITYPE_UNDEF}, + /* 0x2e */ {"", "", ITYPE_UNDEF}, + /* 0x2f */ {"", "", ITYPE_UNDEF}, + + /* 0x30 */ {"C.F", " ", ITYPE_FCMP}, + /* 0x31 */ {"C.UN", " ", ITYPE_FCMP}, + /* 0x32 */ {"C.EQ", " ", ITYPE_FCMP}, + /* 0x33 */ {"C.UEQ", " ", ITYPE_FCMP}, + /* 0x34 */ {"C.OLT", " ", ITYPE_FCMP}, + /* 0x35 */ {"C.ULT", " ", ITYPE_FCMP}, + /* 0x36 */ {"C.OLE", " ", ITYPE_FCMP}, + /* 0x37 */ {"C.ULE", " ", ITYPE_FCMP}, + + /* 0x38 */ {"C.SF", " ", ITYPE_FCMP}, + /* 0x39 */ {"C.NGLE", "", ITYPE_FCMP}, + /* 0x3a */ {"C.SEQ", " ", ITYPE_FCMP}, + /* 0x3b */ {"C.NGL", " ", ITYPE_FCMP}, + /* 0x3c */ {"C.LT", " ", ITYPE_FCMP}, + /* 0x3d */ {"C.NGE", " ", ITYPE_FCMP}, + /* 0x3e */ {"C.LE", " ", ITYPE_FCMP}, + /* 0x3f */ {"C.NGT", " ", ITYPE_FCMP} +}; + + +/* format decode table for 3 bit floating point format codes */ + +static char *fmt[] = { + /* 0x00 */ ".S", + /* 0x01 */ ".D", + /* 0x02 */ ".X", + /* 0x03 */ ".Q", + /* 0x04 */ ".W", + /* 0x05 */ ".L", + /* 0x06 */ ".?", + /* 0x07 */ ".?" +}; + + +/* format decode table for 2 bit floating point branch codes */ + +static char *fbra[] = { + /* 0x00 */ "BC1F ", + /* 0x01 */ "BC1T ", + /* 0x02 */ "BC1FL ", + /* 0x03 */ "BC1TL " +}; + + +/* function disassinstr ******************************************************** + + outputs a disassembler listing of one machine code instruction on 'stdout' + c: instructions machine code + pos: instructions address relative to method start + +*******************************************************************************/ + +static void disassinstr(int c, int pos) +{ + int op; /* 6 bit op code */ + int opfun; /* 6 bit function code */ + int rs, rt, rd; /* 5 bit integer register specifiers */ + int fs, ft, fd; /* 5 bit floating point register specifiers */ + int shift; /* 5 bit unsigned shift amount */ + + op = (c >> 26) & 0x3f; /* 6 bit op code */ + opfun = (c >> 0) & 0x3f; /* 6 bit function code */ + rs = (c >> 21) & 0x1f; /* 5 bit source register specifier */ + rt = (c >> 16) & 0x1f; /* 5 bit source/destination register specifier*/ + rd = (c >> 11) & 0x1f; /* 5 bit destination register specifier */ + shift = (c >> 6) & 0x1f; /* 5 bit unsigned shift amount */ + + printf ("%6x: %#8x ", pos, c); + + switch (ops[op].itype) { + case ITYPE_JMP: /* 26 bit unsigned jump offset */ + printf ("%s %#7x\n", ops[op].name, (c & 0x3ffffff) << 2); + break; + + case ITYPE_IMM: /* 16 bit signed immediate value */ + printf ("%s $%d,$%d,%d\n", ops[op].name, rt, rs, (c << 16) >> 16); + break; + + case ITYPE_MEM: /* 16 bit signed memory offset */ + printf ("%s $%d,%d($%d)\n", ops[op].name, rt, (c << 16) >> 16, rs); + break; + + case ITYPE_BRA: /* 16 bit signed branch offset */ + printf("%s $%d,$%d,%x\n", ops[op].name, rs, rt, + pos + 4 + ((c << 16) >> 14)); + break; + + case ITYPE_RIMM: + if (regimms[rt].ftype == ITYPE_IMM) + printf("%s $%d,#%d\n", regimms[rt].name, rs, (c << 16) >> 16); + else if (regimms[rt].ftype == ITYPE_BRA) + printf("%s $%d,%x\n", regimms[rt].name, rs, + pos + 4 + ((c << 16) >> 14)); + else + printf("REGIMM %#2x,$%d,%d\n", rt, rs, (c << 16) >> 16); + break; + + case ITYPE_OP: + if (opfun == 0x25 && rs == rt) { + if (rs == 0 && rd == 0) + printf("NOP\n"); + else if (rs == 0) + printf("CLR $%d\n", rd); + else + printf("MOV $%d,$%d\n", rs, rd); + return; + } + switch (regops[opfun].ftype) { + case ITYPE_OP: + printf("%s $%d,$%d,$%d\n", regops[opfun].name, rd, rs, rt); + break; + case ITYPE_IMM: /* immediate instruction */ + printf("%s $%d,$%d,#%d\n", + regops[opfun].name, rd, rt, shift); + break; + case ITYPE_TRAP: + printf("%s $%d,$%d,#%d\n", + regops[opfun].name, rs, rt, (c << 16) >> 22); + break; + case ITYPE_DIVMUL: /* div/mul instruction */ + printf("%s $%d,$%d\n", regops[opfun].name, rs, rt); + break; + case ITYPE_JMP: + printf("%s $%d,$%d\n", regops[opfun].name, rd, rs); + break; + case ITYPE_MTOJR: + printf("%s $%d\n", regops[opfun].name, rs); + break; + case ITYPE_MFROM: + printf("%s $%d\n", regops[opfun].name, rd); + break; + case ITYPE_SYS: + printf("%s\n", regops[opfun].name); + default: + printf("SPECIAL (%#2x) $%d,$%d,$%d\n", opfun, rd, rs, rt); + } + break; + case ITYPE_FOP: + fs = (c >> 11) & 0x1f; /* 5 bit source register */ + ft = (c >> 16) & 0x1f; /* 5 bit source/destination register */ + fd = (c >> 6) & 0x1f; /* 5 bit destination register */ + + if (rs == 8) { /* floating point branch */ + printf("%s %x\n", fbra[ft&3], pos + 4 + ((c << 16) >> 14)); + break; + } + + if (rs == 1) { /* double move from */ + printf("MFC1 $%d,$f%d\n", rt, fs); + break; + } + + if (rs == 5) { /* double move to */ + printf("MTC1 ,$%d,$f%d\n", rt, fs); + break; + } + + rs = rs & 7; /* truncate to 3 bit format specifier */ + + if (fops[opfun].ftype == ITYPE_FOP) + printf("%s%s%s $%d,$%d,$%d\n", fops[opfun].name, fmt[rs], + fops[opfun].fill, fd, fs, ft); + else if (fops[opfun].ftype == ITYPE_FOP2) + printf("%s%s%s $%d,$%d\n", fops[opfun].name, fmt[rs], + fops[opfun].fill, fd, fs); + else if (fops[opfun].ftype == ITYPE_FOP2) + printf("%s%s%s $%d,$%d\n", fops[opfun].name, fmt[rs], + fops[opfun].fill, fs, ft); + else + printf("COP1 (%#2x) $%d,$%d,$%d\n", opfun, fd, fs, ft); + + break; + + default: + printf("UNDEF %#2x(%#2x) $%d,$%d,$%d\n", op, opfun, rd, rs, rt); + } +} + + +/* function disassemble ******************************************************** + + outputs a disassembler listing of some machine code on 'stdout' + code: pointer to first instruction + len: code size (number of instructions * 4) + +*******************************************************************************/ + +static void disassemble(int *code, int len) +{ + int p; + + printf (" --- disassembler listing ---\n"); + for (p = 0; p < len; p += 4, code++) + disassinstr(*code, p); +} + + +/* + * These are local overrides for various environment variables in Emacs. + * Please do not remove this and leave it at the end of the file, where + * Emacs will automagically detect them. + * --------------------------------------------------------------------- + * Local variables: + * mode: c + * indent-tabs-mode: t + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff --git a/mips/ngen.c b/mips/ngen.c new file mode 100644 index 000000000..ea2f50d04 --- /dev/null +++ b/mips/ngen.c @@ -0,0 +1,3604 @@ +/* mips/ngen.c ***************************************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Contains the codegenerator for an MIPS (R4000 or higher) processor. + This module generates MIPS machine code for a sequence of intermediate + code commands (ICMDs). + + Authors: Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1998/11/118 + +*******************************************************************************/ + + + +/* ***************************************************************************** + +Datatypes and Register Allocations: +----------------------------------- + +On 64-bit-machines (like the MIPS) all operands are stored in the +registers in a 64-bit form, even when the correspondig JavaVM operands +only need 32 bits. This is done by a canonical representation: + +32-bit integers are allways stored as sign-extended 64-bit values (this +approach is directly supported by the MIPS architecture and is very easy +to implement). + +32-bit-floats are stored in a 64-bit double precision register by simply +expanding the exponent and mantissa with zeroes. (also supported by the +architecture) + + +Stackframes: + +The calling conventions and the layout of the stack is explained in detail +in the documention file: calling.doc + +*******************************************************************************/ + + +/* additional functions and macros to generate code ***************************/ + +#define BlockPtrOfPC(pc) block+block_index[pc] + +#ifdef STATISTICS +#define COUNT_SPILLS count_spills++ +#else +#define COUNT_SPILLS +#endif + + +/* gen_nullptr_check(objreg) */ + +#ifdef SOFTNULLPTRCHECK +#define gen_nullptr_check(objreg) \ + if (checknull) {\ + M_BEQZ((objreg), 0);\ + mcode_addxnullrefs(mcodeptr);\ + } +#else +#define gen_nullptr_check(objreg) +#endif + + +/* MCODECHECK(icnt) */ + +#define MCODECHECK(icnt) \ + if((mcodeptr+(icnt))>mcodeend)mcodeptr=mcode_increase((u1*)mcodeptr) + +/* M_INTMOVE: + generates an integer-move from register a to b. + if a and b are the same int-register, no code will be generated. +*/ + +#define M_INTMOVE(a,b) if(a!=b){M_MOV(a,b);} + + +/* M_FLTMOVE: + generates a floating-point-move from register a to b. + if a and b are the same float-register, no code will be generated +*/ + +#define M_FLTMOVE(a,b) if(a!=b){M_FMOV(a,b);} + + +/* var_to_reg_xxx: + this function generates code to fetch data from a pseudo-register + into a real register. + If the pseudo-register has actually been assigned to a real + register, no code will be emitted, since following operations + can use this register directly. + + v: pseudoregister to be fetched from + tempregnum: temporary register to be used if v is actually spilled to ram + + return: the register number, where the operand can be found after + fetching (this wil be either tempregnum or the register + number allready given to v) +*/ + +#define var_to_reg_int(regnr,v,tempnr) { \ + if ((v)->flags & INMEMORY) \ + {COUNT_SPILLS;M_LLD(tempnr,REG_SP,8*(v)->regoff);regnr=tempnr;} \ + else regnr=(v)->regoff; \ +} + + +#define var_to_reg_flt(regnr,v,tempnr) { \ + if ((v)->flags & INMEMORY) \ + {COUNT_SPILLS;M_DLD(tempnr,REG_SP,8*(v)->regoff);regnr=tempnr;} \ + else regnr=(v)->regoff; \ +} + + +/* reg_of_var: + This function determines a register, to which the result of an operation + should go, when it is ultimatively intended to store the result in + pseudoregister v. + If v is assigned to an actual register, this register will be returned. + Otherwise (when v is spilled) this function returns tempregnum. + If not already done, regoff and flags are set in the stack location. +*/ + +static int reg_of_var(stackptr v, int tempregnum) +{ + varinfo *var; + + switch (v->varkind) { + case TEMPVAR: + if (!(v->flags & INMEMORY)) + return(v->regoff); + break; + case STACKVAR: + var = &(interfaces[v->varnum][v->type]); + v->regoff = var->regoff; + if (!(var->flags & INMEMORY)) + return(var->regoff); + break; + case LOCALVAR: + var = &(locals[v->varnum][v->type]); + v->regoff = var->regoff; + if (!(var->flags & INMEMORY)) + return(var->regoff); + break; + case ARGVAR: + v->regoff = v->varnum; + if (IS_FLT_DBL_TYPE(v->type)) { + if (v->varnum < fltreg_argnum) { + v->regoff = argfltregs[v->varnum]; + return(argfltregs[v->varnum]); + } + } + else + if (v->varnum < intreg_argnum) { + v->regoff = argintregs[v->varnum]; + return(argintregs[v->varnum]); + } + v->regoff -= intreg_argnum; + break; + } + v->flags |= INMEMORY; + return tempregnum; +} + + +/* store_reg_to_var_xxx: + This function generates the code to store the result of an operation + back into a spilled pseudo-variable. + If the pseudo-variable has not been spilled in the first place, this + function will generate nothing. + + v ............ Pseudovariable + tempregnum ... Number of the temporary registers as returned by + reg_of_var. +*/ + +#define store_reg_to_var_int(sptr, tempregnum) { \ + if ((sptr)->flags & INMEMORY) { \ + COUNT_SPILLS; \ + M_LST(tempregnum, REG_SP, 8 * (sptr)->regoff); \ + } \ + } + +#define store_reg_to_var_flt(sptr, tempregnum) { \ + if ((sptr)->flags & INMEMORY) { \ + COUNT_SPILLS; \ + M_DST(tempregnum, REG_SP, 8 * (sptr)->regoff); \ + } \ + } + + +/* NullPointerException handlers and exception handling initialisation */ + +typedef struct sigctx_struct { + + long sc_onstack; /* sigstack state to restore */ + long sc_mask; /* signal mask to restore */ + long sc_pc; /* pc at time of signal */ + long sc_ps; /* psl to retore */ + long sc_regs[32]; /* processor regs 0 to 31 */ + long sc_ownedfp; /* fp has been used */ + long sc_fpregs[32]; /* fp regs 0 to 31 */ + unsigned long sc_fpcr; /* floating point control register */ + unsigned long sc_fp_control; /* software fpcr */ + /* rest is unused */ + unsigned long sc_reserved1, sc_reserved2; + unsigned long sc_ssize; + char *sc_sbase; + unsigned long sc_traparg_a0; + unsigned long sc_traparg_a1; + unsigned long sc_traparg_a2; + unsigned long sc_fp_trap_pc; + unsigned long sc_fp_trigger_sum; + unsigned long sc_fp_trigger_inst; + unsigned long sc_retcode[2]; +} sigctx_struct; + + +/* asm_signal_exception passes exception pointer and the signal context + structure (contains the saved registers) to the assembler handler which + restores registers and walks through the Java exception tables. +*/ + +void asm_signal_exception(void *xptr, void *sigctx); + + +/* NullPointerException signal handler for hardware null pointer check */ + +void catch_NullPointerException(int sig, int code, sigctx_struct *sigctx) +{ + sigset_t nsig; + int instr; + long faultaddr; + + /* Reset signal handler - necessary for SysV, does no harm for BSD */ + + instr = *((int*)(sigctx->sc_pc)); + faultaddr = sigctx->sc_regs[(instr >> 16) & 0x1f]; + + if (faultaddr == 0) { + signal(sig, (void*) catch_NullPointerException); /* reinstall handler */ + sigemptyset(&nsig); + sigaddset(&nsig, sig); + sigprocmask(SIG_UNBLOCK, &nsig, NULL); /* unblock signal */ + asm_signal_exception(proto_java_lang_NullPointerException, sigctx); + } + else { + faultaddr += (long) ((instr << 16) >> 16); + fprintf(stderr, "faulting address: 0x%16lx\n", faultaddr); + panic("Stack overflow"); + } +} + + +#ifdef __osf__ + +void init_exceptions(void) +{ + +#else /* Linux */ + +/* Linux on Digital Alpha needs an initialisation of the ieee floating point + control for IEEE compliant arithmetic (option -mieee of GCC). Under + Digital Unix this is done automatically. +*/ + +#include + +extern unsigned long ieee_get_fp_control(); +extern void ieee_set_fp_control(unsigned long fp_control); + +void init_exceptions(void) +{ +/* initialize floating point control */ + +ieee_set_fp_control(ieee_get_fp_control() + & ~IEEE_TRAP_ENABLE_INV + & ~IEEE_TRAP_ENABLE_DZE +/* & ~IEEE_TRAP_ENABLE_UNF we dont want underflow */ + & ~IEEE_TRAP_ENABLE_OVF); +#endif + + /* install signal handlers we need to convert to exceptions */ + + if (!checknull) { + +#if defined(SIGSEGV) + signal(SIGSEGV, (void*) catch_NullPointerException); +#endif + +#if defined(SIGBUS) + signal(SIGBUS, (void*) catch_NullPointerException); +#endif + } +} + + +/* function gen_mcode ********************************************************** + + generates machine code + +*******************************************************************************/ + +#define MethodPointer -8 +#define FrameSize -12 +#define IsSync -16 +#define IsLeaf -20 +#define IntSave -24 +#define FltSave -28 +#define ExTableSize -32 +#define ExTableStart -32 + +#define ExEntrySize -32 +#define ExStartPC -8 +#define ExEndPC -16 +#define ExHandlerPC -24 +#define ExCatchType -32 + +static void gen_mcode() +{ + int len, s1, s2, s3, d, bbs; + s4 a; + s4 *mcodeptr; + stackptr src; + varinfo *var; + basicblock *bptr; + instruction *iptr; + + { + int p, pa, t, l, r; + + savedregs_num = (isleafmethod) ? 0 : 1; /* space to save the RA */ + + /* space to save used callee saved registers */ + + savedregs_num += (savintregcnt - maxsavintreguse); + savedregs_num += (savfltregcnt - maxsavfltreguse); + + parentargs_base = maxmemuse + savedregs_num; + +#ifdef USE_THREADS /* space to save argument of monitor_enter */ + + if (checksync && (method->flags & ACC_SYNCHRONIZED)) + parentargs_base++; + +#endif + + /* create method header */ + + (void) dseg_addaddress(method); /* MethodPointer */ + (void) dseg_adds4(parentargs_base * 8); /* FrameSize */ + +#ifdef USE_THREADS + + /* IsSync contains the offset relative to the stack pointer for the + argument of monitor_exit used in the exception handler. Since the + offset could be zero and give a wrong meaning of the flag it is + offset by one. + */ + + if (checksync && (method->flags & ACC_SYNCHRONIZED)) + (void) dseg_adds4((maxmemuse + 1) * 8); /* IsSync */ + else + +#endif + + (void) dseg_adds4(0); /* IsSync */ + + (void) dseg_adds4(isleafmethod); /* IsLeaf */ + (void) dseg_adds4(savintregcnt - maxsavintreguse); /* IntSave */ + (void) dseg_adds4(savfltregcnt - maxsavfltreguse); /* FltSave */ + (void) dseg_adds4(exceptiontablelength); /* ExTableSize */ + + /* create exception table */ + + for (len = 0; len < exceptiontablelength; len++) { + dseg_addtarget(BlockPtrOfPC(extable[len].startpc)); + dseg_addtarget(BlockPtrOfPC(extable[len].endpc)); + dseg_addtarget(BlockPtrOfPC(extable[len].handlerpc)); + (void) dseg_addaddress(extable[len].catchtype); + } + + /* initialize mcode variables */ + + mcodeptr = (s4*) mcodebase; + mcodeend = (s4*) (mcodebase + mcodesize); + MCODECHECK(128 + mparamcount); + + /* create stack frame (if necessary) */ + + if (parentargs_base) + {M_LDA (REG_SP, REG_SP, -parentargs_base * 8);} + + /* save return address and used callee saved registers */ + + p = parentargs_base; + if (!isleafmethod) + {p--; M_AST (REG_RA, REG_SP, 8*p);} + for (r = savintregcnt - 1; r >= maxsavintreguse; r--) + {p--; M_LST (savintregs[r], REG_SP, 8 * p);} + for (r = savfltregcnt - 1; r >= maxsavfltreguse; r--) + {p--; M_DST (savfltregs[r], REG_SP, 8 * p);} + + /* save monitorenter argument */ + +#ifdef USE_THREADS + if (checksync && (method->flags & ACC_SYNCHRONIZED)) { + if (method->flags & ACC_STATIC) { + p = dseg_addaddress (class); + M_ALD(REG_ITMP1, REG_PV, p); + M_AST(REG_ITMP1, REG_SP, 8 * maxmemuse); + } + else { + M_AST (argintregs[0], REG_SP, 8 * maxmemuse); + } + } +#endif + + /* copy argument registers to stack and call trace function with pointer + to arguments on stack. ToDo: save floating point registers !!!!!!!!! + */ + + if (runverbose && isleafmethod) { + M_LDA (REG_SP, REG_SP, -(14*8)); + M_AST(REG_RA, REG_SP, 1*8); + + M_LST(argintregs[0], REG_SP, 2*8); + M_LST(argintregs[1], REG_SP, 3*8); + M_LST(argintregs[2], REG_SP, 4*8); + M_LST(argintregs[3], REG_SP, 5*8); + M_LST(argintregs[4], REG_SP, 6*8); + M_LST(argintregs[5], REG_SP, 7*8); + + M_DST(argfltregs[0], REG_SP, 8*8); + M_DST(argfltregs[1], REG_SP, 9*8); + M_DST(argfltregs[2], REG_SP, 10*8); + M_DST(argfltregs[3], REG_SP, 11*8); + M_DST(argfltregs[4], REG_SP, 12*8); + M_DST(argfltregs[5], REG_SP, 13*8); + + p = dseg_addaddress (method); + M_ALD(REG_ITMP1, REG_PV, p); + M_AST(REG_ITMP1, REG_SP, 0); + p = dseg_addaddress ((void*) (builtin_trace_args)); + M_ALD(REG_PV, REG_PV, p); + M_JSR(REG_RA, REG_PV); + M_LDA(REG_PV, REG_RA, -(int)((u1*) mcodeptr - mcodebase)); + M_ALD(REG_RA, REG_SP, 1*8); + + M_LLD(argintregs[0], REG_SP, 2*8); + M_LLD(argintregs[1], REG_SP, 3*8); + M_LLD(argintregs[2], REG_SP, 4*8); + M_LLD(argintregs[3], REG_SP, 5*8); + M_LLD(argintregs[4], REG_SP, 6*8); + M_LLD(argintregs[5], REG_SP, 7*8); + + M_DLD(argfltregs[0], REG_SP, 8*8); + M_DLD(argfltregs[1], REG_SP, 9*8); + M_DLD(argfltregs[2], REG_SP, 10*8); + M_DLD(argfltregs[3], REG_SP, 11*8); + M_DLD(argfltregs[4], REG_SP, 12*8); + M_DLD(argfltregs[5], REG_SP, 13*8); + + M_LDA (REG_SP, REG_SP, 14*8); + } + + /* take arguments out of register or stack frame */ + + for (p = 0, l = 0; p < mparamcount; p++) { + t = mparamtypes[p]; + var = &(locals[l][t]); + l++; + if (IS_2_WORD_TYPE(t)) /* increment local counter for 2 word types */ + l++; + if (var->type < 0) + continue; + r = var->regoff; + if (IS_INT_LNG_TYPE(t)) { /* integer args */ + if (p < INT_ARG_CNT) { /* register arguments */ + if (!(var->flags & INMEMORY)) /* reg arg -> register */ + {M_INTMOVE (argintregs[p], r);} + else /* reg arg -> spilled */ + M_LST (argintregs[p], REG_SP, 8 * r); + } + else { /* stack arguments */ + pa = p - INT_ARG_CNT; + if (!(var->flags & INMEMORY)) /* stack arg -> register */ + M_LLD (r, REG_SP, 8 * (parentargs_base + pa)); + else { /* stack arg -> spilled */ + M_LLD (REG_ITMP1, REG_SP, 8 * (parentargs_base + pa)); + M_LST (REG_ITMP1, REG_SP, 8 * r); + } + } + } + else { /* floating args */ + if (p < FLT_ARG_CNT) { /* register arguments */ + if (!(var->flags & INMEMORY)) /* reg arg -> register */ + {M_FLTMOVE (argfltregs[p], r);} + else /* reg arg -> spilled */ + M_DST (argfltregs[p], REG_SP, 8 * r); + } + else { /* stack arguments */ + pa = p - FLT_ARG_CNT; + if (!(var->flags & INMEMORY)) /* stack-arg -> register */ + M_DLD (r, REG_SP, 8 * (parentargs_base + pa) ); + else { /* stack-arg -> spilled */ + M_DLD (REG_FTMP1, REG_SP, 8 * (parentargs_base + pa)); + M_DST (REG_FTMP1, REG_SP, 8 * r); + } + } + } + } /* end for */ + + /* call trace function */ + + if (runverbose && !isleafmethod) { + M_LDA (REG_SP, REG_SP, -8); + p = dseg_addaddress (method); + M_ALD(REG_ITMP1, REG_PV, p); + M_AST(REG_ITMP1, REG_SP, 0); + p = dseg_addaddress ((void*) (builtin_trace_args)); + M_ALD(REG_PV, REG_PV, p); + M_JSR(REG_RA, REG_PV); + M_LDA(REG_PV, REG_RA, -(int)((u1*) mcodeptr - mcodebase)); + M_LDA(REG_SP, REG_SP, 8); + } + + /* call monitorenter function */ + +#ifdef USE_THREADS + if (checksync && (method->flags & ACC_SYNCHRONIZED)) { + p = dseg_addaddress ((void*) (builtin_monitorenter)); + M_ALD(REG_PV, REG_PV, p); + M_ALD(argintregs[0], REG_SP, 8 * maxmemuse); + M_JSR(REG_RA, REG_PV); + M_LDA(REG_PV, REG_RA, -(int)((u1*) mcodeptr - mcodebase)); + } +#endif + } + + /* end of header generation */ + + /* walk through all basic blocks */ + + for (bbs = block_count, bptr = block; --bbs >= 0; bptr++) { + bptr -> mpc = (int)((u1*) mcodeptr - mcodebase); + + if (bptr->flags >= BBREACHED) { + + /* branch resolving */ + + { + branchref *brefs; + for (brefs = bptr->branchrefs; brefs != NULL; brefs = brefs->next) { + gen_resolvebranch((u1*) mcodebase + brefs->branchpos, + brefs->branchpos, bptr->mpc); + } + } + + /* copy interface registers to their destination */ + + src = bptr->instack; + len = bptr->indepth; + MCODECHECK(64+len); + while (src != NULL) { + len--; + if ((len == 0) && (bptr->type != BBTYPE_STD)) { + d = reg_of_var(src, REG_ITMP1); + M_INTMOVE(REG_ITMP1, d); + store_reg_to_var_int(src, d); + } + else { + d = reg_of_var(src, REG_IFTMP); + if ((src->varkind != STACKVAR)) { + s2 = src->type; + if (IS_FLT_DBL_TYPE(s2)) { + if (!(interfaces[len][s2].flags & INMEMORY)) { + s1 = interfaces[len][s2].regoff; + M_FLTMOVE(s1,d); + } + else { + M_DLD(d, REG_SP, 8 * interfaces[len][s2].regoff); + } + store_reg_to_var_flt(src, d); + } + else { + if (!(interfaces[len][s2].flags & INMEMORY)) { + s1 = interfaces[len][s2].regoff; + M_INTMOVE(s1,d); + } + else { + M_LLD(d, REG_SP, 8 * interfaces[len][s2].regoff); + } + store_reg_to_var_int(src, d); + } + } + } + src = src->prev; + } + + /* walk through all instructions */ + + src = bptr->instack; + len = bptr->icount; + for (iptr = bptr->iinstr; + len > 0; + src = iptr->dst, len--, iptr++) { + + MCODECHECK(64); /* an instruction usually needs < 64 words */ + switch (iptr->opc) { + + case ICMD_NOP: /* ... ==> ... */ + break; + + case ICMD_NULLCHECKPOP: /* ..., objectref ==> ... */ + + var_to_reg_int(s1, src, REG_ITMP1); + M_BEQZ(s1, 0); + mcode_addxnullrefs(mcodeptr); + break; + + /* constant operations ************************************************/ + +#define ICONST(r,c) if(((c)>=-32768)&&((c)<= 32767)){M_LDA(r,REG_ZERO,c);} \ + else{a=dseg_adds4(c);M_ILD(r,REG_PV,a);} + +#define LCONST(r,c) if(((c)>=-32768)&&((c)<= 32767)){M_LDA(r,REG_ZERO,c);} \ + else{a=dseg_adds8(c);M_LLD(r,REG_PV,a);} + + case ICMD_ICONST: /* ... ==> ..., constant */ + /* op1 = 0, val.i = constant */ + + d = reg_of_var(iptr->dst, REG_ITMP1); + ICONST(d, iptr->val.i); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_LCONST: /* ... ==> ..., constant */ + /* op1 = 0, val.l = constant */ + + d = reg_of_var(iptr->dst, REG_ITMP1); + LCONST(d, iptr->val.l); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_FCONST: /* ... ==> ..., constant */ + /* op1 = 0, val.f = constant */ + + d = reg_of_var (iptr->dst, REG_FTMP1); + a = dseg_addfloat (iptr->val.f); + M_FLD(d, REG_PV, a); + store_reg_to_var_flt (iptr->dst, d); + break; + + case ICMD_DCONST: /* ... ==> ..., constant */ + /* op1 = 0, val.d = constant */ + + d = reg_of_var (iptr->dst, REG_FTMP1); + a = dseg_adddouble (iptr->val.d); + M_DLD(d, REG_PV, a); + store_reg_to_var_flt (iptr->dst, d); + break; + + case ICMD_ACONST: /* ... ==> ..., constant */ + /* op1 = 0, val.a = constant */ + + d = reg_of_var(iptr->dst, REG_ITMP1); + if (iptr->val.a) { + a = dseg_addaddress (iptr->val.a); + M_ALD(d, REG_PV, a); + } + else { + M_INTMOVE(REG_ZERO, d); + } + store_reg_to_var_int(iptr->dst, d); + break; + + + /* load/store operations **********************************************/ + + case ICMD_ILOAD: /* ... ==> ..., content of local variable */ + case ICMD_LLOAD: /* op1 = local variable */ + case ICMD_ALOAD: + + d = reg_of_var(iptr->dst, REG_ITMP1); + if ((iptr->dst->varkind == LOCALVAR) && + (iptr->dst->varnum == iptr->op1)) + break; + var = &(locals[iptr->op1][iptr->opc - ICMD_ILOAD]); + if (var->flags & INMEMORY) + M_LLD(d, REG_SP, 8 * var->regoff); + else + {M_INTMOVE(var->regoff,d);} + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_FLOAD: /* ... ==> ..., content of local variable */ + case ICMD_DLOAD: /* op1 = local variable */ + + d = reg_of_var(iptr->dst, REG_FTMP1); + if ((iptr->dst->varkind == LOCALVAR) && + (iptr->dst->varnum == iptr->op1)) + break; + var = &(locals[iptr->op1][iptr->opc - ICMD_ILOAD]); + if (var->flags & INMEMORY) + M_DLD(d, REG_SP, 8 * var->regoff); + else + {M_FLTMOVE(var->regoff,d);} + store_reg_to_var_flt(iptr->dst, d); + break; + + + case ICMD_ISTORE: /* ..., value ==> ... */ + case ICMD_LSTORE: /* op1 = local variable */ + case ICMD_ASTORE: + + if ((src->varkind == LOCALVAR) && + (src->varnum == iptr->op1)) + break; + var = &(locals[iptr->op1][iptr->opc - ICMD_ISTORE]); + if (var->flags & INMEMORY) { + var_to_reg_int(s1, src, REG_ITMP1); + M_LST(s1, REG_SP, 8 * var->regoff); + } + else { + var_to_reg_int(s1, src, var->regoff); + M_INTMOVE(s1, var->regoff); + } + break; + + case ICMD_FSTORE: /* ..., value ==> ... */ + case ICMD_DSTORE: /* op1 = local variable */ + + if ((src->varkind == LOCALVAR) && + (src->varnum == iptr->op1)) + break; + var = &(locals[iptr->op1][iptr->opc - ICMD_ISTORE]); + if (var->flags & INMEMORY) { + var_to_reg_flt(s1, src, REG_FTMP1); + M_DST(s1, REG_SP, 8 * var->regoff); + } + else { + var_to_reg_flt(s1, src, var->regoff); + M_FLTMOVE(s1, var->regoff); + } + break; + + + /* pop/dup/swap operations ********************************************/ + + /* attention: double and longs are only one entry in CACAO ICMDs */ + + case ICMD_POP: /* ..., value ==> ... */ + case ICMD_POP2: /* ..., value, value ==> ... */ + break; + +#define M_COPY(from,to) \ + d = reg_of_var(to, REG_IFTMP); \ + if ((from->regoff != to->regoff) || \ + ((from->flags ^ to->flags) & INMEMORY)) { \ + if (IS_FLT_DBL_TYPE(from->type)) { \ + var_to_reg_flt(s1, from, d); \ + M_FLTMOVE(s1,d); \ + store_reg_to_var_flt(to, d); \ + }\ + else { \ + var_to_reg_int(s1, from, d); \ + M_INTMOVE(s1,d); \ + store_reg_to_var_int(to, d); \ + }\ + } + + case ICMD_DUP: /* ..., a ==> ..., a, a */ + M_COPY(src, iptr->dst); + break; + + case ICMD_DUP_X1: /* ..., a, b ==> ..., b, a, b */ + + M_COPY(src, iptr->dst->prev->prev); + + case ICMD_DUP2: /* ..., a, b ==> ..., a, b, a, b */ + + M_COPY(src, iptr->dst); + M_COPY(src->prev, iptr->dst->prev); + break; + + case ICMD_DUP2_X1: /* ..., a, b, c ==> ..., b, c, a, b, c */ + + M_COPY(src->prev, iptr->dst->prev->prev->prev); + + case ICMD_DUP_X2: /* ..., a, b, c ==> ..., c, a, b, c */ + + M_COPY(src, iptr->dst); + M_COPY(src->prev, iptr->dst->prev); + M_COPY(src->prev->prev, iptr->dst->prev->prev); + M_COPY(src, iptr->dst->prev->prev->prev); + break; + + case ICMD_DUP2_X2: /* ..., a, b, c, d ==> ..., c, d, a, b, c, d */ + + M_COPY(src, iptr->dst); + M_COPY(src->prev, iptr->dst->prev); + M_COPY(src->prev->prev, iptr->dst->prev->prev); + M_COPY(src->prev->prev->prev, iptr->dst->prev->prev->prev); + M_COPY(src, iptr->dst->prev->prev->prev->prev); + M_COPY(src->prev, iptr->dst->prev->prev->prev->prev->prev); + break; + + case ICMD_SWAP: /* ..., a, b ==> ..., b, a */ + + M_COPY(src, iptr->dst->prev); + M_COPY(src->prev, iptr->dst); + break; + + + /* integer operations *************************************************/ + + case ICMD_INEG: /* ..., value ==> ..., - value */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_ISUB(REG_ZERO, s1, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_LNEG: /* ..., value ==> ..., - value */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_LSUB(REG_ZERO, s1, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_I2L: /* ..., value ==> ..., value */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_INTMOVE(s1, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_L2I: /* ..., value ==> ..., value */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_IADD(s1, REG_ZERO, d ); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_INT2BYTE: /* ..., value ==> ..., value */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if (has_ext_instr_set) { + M_BSEXT(s1, d); + } + else { + M_SLL_IMM(s1, 56, d); + M_SRA_IMM( d, 56, d); + } + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_INT2CHAR: /* ..., value ==> ..., value */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_CZEXT(s1, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_INT2SHORT: /* ..., value ==> ..., value */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if (has_ext_instr_set) { + M_SSEXT(s1, d); + } + else { + M_SLL_IMM(s1, 48, d); + M_SRA_IMM( d, 48, d); + } + store_reg_to_var_int(iptr->dst, d); + break; + + + case ICMD_IADD: /* ..., val1, val2 ==> ..., val1 + val2 */ + + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_IADD(s1, s2, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_IADDCONST: /* ..., value ==> ..., value + constant */ + /* val.i = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if ((iptr->val.i >= 0) && (iptr->val.i <= 255)) { + M_IADD_IMM(s1, iptr->val.i, d); + } + else { + ICONST(REG_ITMP2, iptr->val.i); + M_IADD(s1, REG_ITMP2, d); + } + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_LADD: /* ..., val1, val2 ==> ..., val1 + val2 */ + + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_LADD(s1, s2, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_LADDCONST: /* ..., value ==> ..., value + constant */ + /* val.l = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if ((iptr->val.l >= 0) && (iptr->val.l <= 255)) { + M_LADD_IMM(s1, iptr->val.l, d); + } + else { + LCONST(REG_ITMP2, iptr->val.l); + M_LADD(s1, REG_ITMP2, d); + } + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_ISUB: /* ..., val1, val2 ==> ..., val1 - val2 */ + + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_ISUB(s1, s2, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_ISUBCONST: /* ..., value ==> ..., value + constant */ + /* val.i = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if ((iptr->val.i >= 0) && (iptr->val.i <= 255)) { + M_ISUB_IMM(s1, iptr->val.i, d); + } + else { + ICONST(REG_ITMP2, iptr->val.i); + M_ISUB(s1, REG_ITMP2, d); + } + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_LSUB: /* ..., val1, val2 ==> ..., val1 - val2 */ + + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_LSUB(s1, s2, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_LSUBCONST: /* ..., value ==> ..., value - constant */ + /* val.l = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if ((iptr->val.l >= 0) && (iptr->val.l <= 255)) { + M_LSUB_IMM(s1, iptr->val.l, d); + } + else { + LCONST(REG_ITMP2, iptr->val.l); + M_LSUB(s1, REG_ITMP2, d); + } + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_IMUL: /* ..., val1, val2 ==> ..., val1 * val2 */ + + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_IMUL(s1, s2, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_IMULCONST: /* ..., value ==> ..., value * constant */ + /* val.i = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if ((iptr->val.i >= 0) && (iptr->val.i <= 255)) { + M_IMUL_IMM(s1, iptr->val.i, d); + } + else { + ICONST(REG_ITMP2, iptr->val.i); + M_IMUL(s1, REG_ITMP2, d); + } + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_LMUL: /* ..., val1, val2 ==> ..., val1 * val2 */ + + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_LMUL (s1, s2, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_LMULCONST: /* ..., value ==> ..., value * constant */ + /* val.l = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if ((iptr->val.l >= 0) && (iptr->val.l <= 255)) { + M_LMUL_IMM(s1, iptr->val.l, d); + } + else { + LCONST(REG_ITMP2, iptr->val.l); + M_LMUL(s1, REG_ITMP2, d); + } + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_IDIVPOW2: /* ..., value ==> ..., value << constant */ + case ICMD_LDIVPOW2: /* val.i = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if (iptr->val.i <= 15) { + M_LDA(REG_ITMP2, s1, (1 << iptr->val.i) -1); + M_CMOVGE(s1, s1, REG_ITMP2); + } + else { + M_SRA_IMM(s1, 63, REG_ITMP2); + M_SRL_IMM(REG_ITMP2, 64 - iptr->val.i, REG_ITMP2); + M_LADD(s1, REG_ITMP2, REG_ITMP2); + } + M_SRA_IMM(REG_ITMP2, iptr->val.i, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_ISHL: /* ..., val1, val2 ==> ..., val1 << val2 */ + + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_AND_IMM(s2, 0x1f, REG_ITMP3); + M_SLL(s1, REG_ITMP3, d); + M_IADD(d, REG_ZERO, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_ISHLCONST: /* ..., value ==> ..., value << constant */ + /* val.i = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_SLL_IMM(s1, iptr->val.i & 0x1f, d); + M_IADD(d, REG_ZERO, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_ISHR: /* ..., val1, val2 ==> ..., val1 >> val2 */ + + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_AND_IMM(s2, 0x1f, REG_ITMP3); + M_SRA(s1, REG_ITMP3, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_ISHRCONST: /* ..., value ==> ..., value >> constant */ + /* val.i = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_SRA_IMM(s1, iptr->val.i & 0x1f, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_IUSHR: /* ..., val1, val2 ==> ..., val1 >>> val2 */ + + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_AND_IMM(s2, 0x1f, REG_ITMP2); + M_IZEXT(s1, d); + M_SRL(d, REG_ITMP2, d); + M_IADD(d, REG_ZERO, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_IUSHRCONST: /* ..., value ==> ..., value >>> constant */ + /* val.i = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_IZEXT(s1, d); + M_SRL_IMM(d, iptr->val.i & 0x1f, d); + M_IADD(d, REG_ZERO, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_LSHL: /* ..., val1, val2 ==> ..., val1 << val2 */ + + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_SLL(s1, s2, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_LSHLCONST: /* ..., value ==> ..., value << constant */ + /* val.l = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_SLL_IMM(s1, iptr->val.l & 0x3f, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_LSHR: /* ..., val1, val2 ==> ..., val1 >> val2 */ + + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_SRA(s1, s2, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_LSHRCONST: /* ..., value ==> ..., value >> constant */ + /* val.l = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_SRA_IMM(s1, iptr->val.l & 0x3f, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_LUSHR: /* ..., val1, val2 ==> ..., val1 >>> val2 */ + + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_SRL(s1, s2, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_LUSHRCONST: /* ..., value ==> ..., value >>> constant */ + /* val.l = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_SRL_IMM(s1, iptr->val.l & 0x3f, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_IAND: /* ..., val1, val2 ==> ..., val1 & val2 */ + case ICMD_LAND: + + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_AND(s1, s2, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_IANDCONST: /* ..., value ==> ..., value & constant */ + /* val.i = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if ((iptr->val.i >= 0) && (iptr->val.i <= 255)) { + M_AND_IMM(s1, iptr->val.i, d); + } + else if (iptr->val.i == 0xffff) { + M_CZEXT(s1, d); + } + else if (iptr->val.i == 0xffffff) { + M_ZAPNOT_IMM(s1, 0x07, d); + } + else { + ICONST(REG_ITMP2, iptr->val.i); + M_AND(s1, REG_ITMP2, d); + } + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_IREMPOW2: /* ..., value ==> ..., value % constant */ + /* val.i = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if (s1 == d) { + M_MOV(s1, REG_ITMP1); + s1 = REG_ITMP1; + } + if ((iptr->val.i >= 0) && (iptr->val.i <= 255)) { + M_AND_IMM(s1, iptr->val.i, d); + M_BGEZ(s1, 3); + M_ISUB(REG_ZERO, s1, d); + M_AND_IMM(d, iptr->val.i, d); + } + else if (iptr->val.i == 0xffff) { + M_CZEXT(s1, d); + M_BGEZ(s1, 3); + M_ISUB(REG_ZERO, s1, d); + M_CZEXT(d, d); + } + else if (iptr->val.i == 0xffffff) { + M_ZAPNOT_IMM(s1, 0x07, d); + M_BGEZ(s1, 3); + M_ISUB(REG_ZERO, s1, d); + M_ZAPNOT_IMM(d, 0x07, d); + } + else { + ICONST(REG_ITMP2, iptr->val.i); + M_AND(s1, REG_ITMP2, d); + M_BGEZ(s1, 3); + M_ISUB(REG_ZERO, s1, d); + M_AND(d, REG_ITMP2, d); + } + M_ISUB(REG_ZERO, d, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_IREM0X10001: /* ..., value ==> ..., value % 0x100001 */ + +/* b = value & 0xffff; + a = value >> 16; + a = ((b - a) & 0xffff) + (b < a); +*/ + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if (s1 == d) { + M_MOV(s1, REG_ITMP3); + s1 = REG_ITMP3; + } + M_BLTZ(s1, 7); + M_CZEXT(s1, REG_ITMP2); + M_SRA_IMM(s1, 16, d); + M_CMPLT(REG_ITMP2, d, REG_ITMP1); + M_ISUB(REG_ITMP2, d, d); + M_CZEXT(d, d); + M_IADD(d, REG_ITMP1, d); + M_BR(11 + (s1 == REG_ITMP1)); + M_ISUB(REG_ZERO, s1, REG_ITMP1); + M_CZEXT(REG_ITMP1, REG_ITMP2); + M_SRA_IMM(REG_ITMP1, 16, d); + M_CMPLT(REG_ITMP2, d, REG_ITMP1); + M_ISUB(REG_ITMP2, d, d); + M_CZEXT(d, d); + M_IADD(d, REG_ITMP1, d); + M_ISUB(REG_ZERO, d, d); + if (s1 == REG_ITMP1) { + var_to_reg_int(s1, src, REG_ITMP1); + } + M_SLL_IMM(s1, 33, REG_ITMP2); + M_CMPEQ(REG_ITMP2, REG_ZERO, REG_ITMP2); + M_ISUB(d, REG_ITMP2, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_LANDCONST: /* ..., value ==> ..., value & constant */ + /* val.l = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if ((iptr->val.l >= 0) && (iptr->val.l <= 255)) { + M_AND_IMM(s1, iptr->val.l, d); + } + else if (iptr->val.l == 0xffffL) { + M_CZEXT(s1, d); + } + else if (iptr->val.l == 0xffffffL) { + M_ZAPNOT_IMM(s1, 0x07, d); + } + else if (iptr->val.l == 0xffffffffL) { + M_IZEXT(s1, d); + } + else if (iptr->val.l == 0xffffffffffL) { + M_ZAPNOT_IMM(s1, 0x1f, d); + } + else if (iptr->val.l == 0xffffffffffffL) { + M_ZAPNOT_IMM(s1, 0x3f, d); + } + else if (iptr->val.l == 0xffffffffffffffL) { + M_ZAPNOT_IMM(s1, 0x7f, d); + } + else { + LCONST(REG_ITMP2, iptr->val.l); + M_AND(s1, REG_ITMP2, d); + } + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_LREMPOW2: /* ..., value ==> ..., value % constant */ + /* val.l = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if (s1 == d) { + M_MOV(s1, REG_ITMP1); + s1 = REG_ITMP1; + } + if ((iptr->val.l >= 0) && (iptr->val.l <= 255)) { + M_AND_IMM(s1, iptr->val.l, d); + M_BGEZ(s1, 3); + M_LSUB(REG_ZERO, s1, d); + M_AND_IMM(d, iptr->val.l, d); + } + else if (iptr->val.l == 0xffffL) { + M_CZEXT(s1, d); + M_BGEZ(s1, 3); + M_LSUB(REG_ZERO, s1, d); + M_CZEXT(d, d); + } + else if (iptr->val.l == 0xffffffL) { + M_ZAPNOT_IMM(s1, 0x07, d); + M_BGEZ(s1, 3); + M_LSUB(REG_ZERO, s1, d); + M_ZAPNOT_IMM(d, 0x07, d); + } + else if (iptr->val.l == 0xffffffffL) { + M_IZEXT(s1, d); + M_BGEZ(s1, 3); + M_LSUB(REG_ZERO, s1, d); + M_IZEXT(d, d); + } + else if (iptr->val.l == 0xffffffffffL) { + M_ZAPNOT_IMM(s1, 0x1f, d); + M_BGEZ(s1, 3); + M_LSUB(REG_ZERO, s1, d); + M_ZAPNOT_IMM(d, 0x1f, d); + } + else if (iptr->val.l == 0xffffffffffffL) { + M_ZAPNOT_IMM(s1, 0x3f, d); + M_BGEZ(s1, 3); + M_LSUB(REG_ZERO, s1, d); + M_ZAPNOT_IMM(d, 0x3f, d); + } + else if (iptr->val.l == 0xffffffffffffffL) { + M_ZAPNOT_IMM(s1, 0x7f, d); + M_BGEZ(s1, 3); + M_LSUB(REG_ZERO, s1, d); + M_ZAPNOT_IMM(d, 0x7f, d); + } + else { + LCONST(REG_ITMP2, iptr->val.l); + M_AND(s1, REG_ITMP2, d); + M_BGEZ(s1, 3); + M_LSUB(REG_ZERO, s1, d); + M_AND(d, REG_ITMP2, d); + } + M_LSUB(REG_ZERO, d, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_LREM0X10001:/* ..., value ==> ..., value % 0x10001 */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if (s1 == d) { + M_MOV(s1, REG_ITMP3); + s1 = REG_ITMP3; + } + M_CZEXT(s1, REG_ITMP2); + M_SRA_IMM(s1, 16, d); + M_CMPLT(REG_ITMP2, d, REG_ITMP1); + M_LSUB(REG_ITMP2, d, d); + M_CZEXT(d, d); + M_LADD(d, REG_ITMP1, d); + M_LDA(REG_ITMP2, REG_ZERO, -1); + M_SRL_IMM(REG_ITMP2, 33, REG_ITMP2); + if (s1 == REG_ITMP1) { + var_to_reg_int(s1, src, REG_ITMP1); + } + M_CMPULT(s1, REG_ITMP2, REG_ITMP2); + M_BNEZ(REG_ITMP2, 11); + M_LDA(d, REG_ZERO, -257); + M_ZAPNOT_IMM(d, 0xcd, d); + M_LSUB(REG_ZERO, s1, REG_ITMP2); + M_CMOVGE(s1, s1, REG_ITMP2); + M_UMULH(REG_ITMP2, d, REG_ITMP2); + M_SRL_IMM(REG_ITMP2, 16, REG_ITMP2); + M_LSUB(REG_ZERO, REG_ITMP2, d); + M_CMOVGE(s1, REG_ITMP2, d); + M_SLL_IMM(d, 16, REG_ITMP2); + M_LADD(d, REG_ITMP2, d); + M_LSUB(s1, d, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_IOR: /* ..., val1, val2 ==> ..., val1 | val2 */ + case ICMD_LOR: + + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_OR( s1,s2, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_IORCONST: /* ..., value ==> ..., value | constant */ + /* val.i = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if ((iptr->val.i >= 0) && (iptr->val.i <= 255)) { + M_OR_IMM(s1, iptr->val.i, d); + } + else { + ICONST(REG_ITMP2, iptr->val.i); + M_OR(s1, REG_ITMP2, d); + } + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_LORCONST: /* ..., value ==> ..., value | constant */ + /* val.l = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if ((iptr->val.l >= 0) && (iptr->val.l <= 255)) { + M_OR_IMM(s1, iptr->val.l, d); + } + else { + LCONST(REG_ITMP2, iptr->val.l); + M_OR(s1, REG_ITMP2, d); + } + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_IXOR: /* ..., val1, val2 ==> ..., val1 ^ val2 */ + case ICMD_LXOR: + + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_XOR(s1, s2, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_IXORCONST: /* ..., value ==> ..., value ^ constant */ + /* val.i = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if ((iptr->val.i >= 0) && (iptr->val.i <= 255)) { + M_XOR_IMM(s1, iptr->val.i, d); + } + else { + ICONST(REG_ITMP2, iptr->val.i); + M_XOR(s1, REG_ITMP2, d); + } + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_LXORCONST: /* ..., value ==> ..., value ^ constant */ + /* val.l = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if ((iptr->val.l >= 0) && (iptr->val.l <= 255)) { + M_XOR_IMM(s1, iptr->val.l, d); + } + else { + LCONST(REG_ITMP2, iptr->val.l); + M_XOR(s1, REG_ITMP2, d); + } + store_reg_to_var_int(iptr->dst, d); + break; + + + case ICMD_LCMP: /* ..., val1, val2 ==> ..., val1 cmp val2 */ + + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_CMPLT(s1, s2, REG_ITMP3); + M_CMPLT(s2, s1, REG_ITMP1); + M_LSUB (REG_ITMP1, REG_ITMP3, d); + store_reg_to_var_int(iptr->dst, d); + break; + + + case ICMD_IINC: /* ..., value ==> ..., value + constant */ + /* op1 = variable, val.i = constant */ + + var = &(locals[iptr->op1][TYPE_INT]); + if (var->flags & INMEMORY) { + s1 = REG_ITMP1; + M_LLD(s1, REG_SP, 8 * var->regoff); + } + else + s1 = var->regoff; + if ((iptr->val.i >= 0) && (iptr->val.i <= 255)) { + M_IADD_IMM(s1, iptr->val.i, s1); + } + else if ((iptr->val.i > -256) && (iptr->val.i < 0)) { + M_ISUB_IMM(s1, (-iptr->val.i), s1); + } + else { + M_LDA (s1, s1, iptr->val.i); + M_IADD(s1, REG_ZERO, s1); + } + if (var->flags & INMEMORY) + M_LST(s1, REG_SP, 8 * var->regoff); + break; + + + /* floating operations ************************************************/ + + case ICMD_FNEG: /* ..., value ==> ..., - value */ + + var_to_reg_flt(s1, src, REG_FTMP1); + d = reg_of_var(iptr->dst, REG_FTMP3); + M_FNEG(s1, d); + store_reg_to_var_flt(iptr->dst, d); + break; + + case ICMD_DNEG: /* ..., value ==> ..., - value */ + + var_to_reg_flt(s1, src, REG_FTMP1); + d = reg_of_var(iptr->dst, REG_FTMP3); + M_DNEG(s1, d); + store_reg_to_var_flt(iptr->dst, d); + break; + + case ICMD_FADD: /* ..., val1, val2 ==> ..., val1 + val2 */ + + var_to_reg_flt(s1, src->prev, REG_FTMP1); + var_to_reg_flt(s2, src, REG_FTMP2); + d = reg_of_var(iptr->dst, REG_FTMP3); + M_FADD(s1, s2, d); + store_reg_to_var_flt(iptr->dst, d); + break; + + case ICMD_DADD: /* ..., val1, val2 ==> ..., val1 + val2 */ + + var_to_reg_flt(s1, src->prev, REG_FTMP1); + var_to_reg_flt(s2, src, REG_FTMP2); + d = reg_of_var(iptr->dst, REG_FTMP3); + M_DADD(s1, s2, d); + store_reg_to_var_flt(iptr->dst, d); + break; + + case ICMD_FSUB: /* ..., val1, val2 ==> ..., val1 - val2 */ + + var_to_reg_flt(s1, src->prev, REG_FTMP1); + var_to_reg_flt(s2, src, REG_FTMP2); + d = reg_of_var(iptr->dst, REG_FTMP3); + M_FSUB(s1, s2, d); + store_reg_to_var_flt(iptr->dst, d); + break; + + case ICMD_DSUB: /* ..., val1, val2 ==> ..., val1 - val2 */ + + var_to_reg_flt(s1, src->prev, REG_FTMP1); + var_to_reg_flt(s2, src, REG_FTMP2); + d = reg_of_var(iptr->dst, REG_FTMP3); + M_DSUB(s1, s2, d); + store_reg_to_var_flt(iptr->dst, d); + break; + + case ICMD_FMUL: /* ..., val1, val2 ==> ..., val1 * val2 */ + + var_to_reg_flt(s1, src->prev, REG_FTMP1); + var_to_reg_flt(s2, src, REG_FTMP2); + d = reg_of_var(iptr->dst, REG_FTMP3); + M_FMUL(s1, s2, d); + store_reg_to_var_flt(iptr->dst, d); + break; + + case ICMD_DMUL: /* ..., val1, val2 ==> ..., val1 *** val2 */ + + var_to_reg_flt(s1, src->prev, REG_FTMP1); + var_to_reg_flt(s2, src, REG_FTMP2); + d = reg_of_var(iptr->dst, REG_FTMP3); + M_DMUL(s1, s2, d); + store_reg_to_var_flt(iptr->dst, d); + break; + + case ICMD_FDIV: /* ..., val1, val2 ==> ..., val1 / val2 */ + + var_to_reg_flt(s1, src->prev, REG_FTMP1); + var_to_reg_flt(s2, src, REG_FTMP2); + d = reg_of_var(iptr->dst, REG_FTMP3); + M_FDIV(s1, s2, d); + store_reg_to_var_flt(iptr->dst, d); + break; + + case ICMD_DDIV: /* ..., val1, val2 ==> ..., val1 / val2 */ + + var_to_reg_flt(s1, src->prev, REG_FTMP1); + var_to_reg_flt(s2, src, REG_FTMP2); + d = reg_of_var(iptr->dst, REG_FTMP3); + M_DDIV(s1, s2, d); + store_reg_to_var_flt(iptr->dst, d); + break; + + case ICMD_FREM: /* ..., val1, val2 ==> ..., val1 % val2 */ + + var_to_reg_flt(s1, src->prev, REG_FTMP1); + var_to_reg_flt(s2, src, REG_FTMP2); + d = reg_of_var(iptr->dst, REG_FTMP3); + M_FDIV(s1,s2, REG_FTMP3); + M_FLOORFL(REG_FTMP3, REG_FTMP3); + M_CVTLF(REG_FTMP3, REG_FTMP3); + M_FMUL(REG_FTMP3, s2, REG_FTMP3); + M_FSUB(s1, REG_FTMP3, d); + store_reg_to_var_flt(iptr->dst, d); + break; + + case ICMD_DREM: /* ..., val1, val2 ==> ..., val1 % val2 */ + + var_to_reg_flt(s1, src->prev, REG_FTMP1); + var_to_reg_flt(s2, src, REG_FTMP2); + d = reg_of_var(iptr->dst, REG_FTMP3); + M_DDIV(s1,s2, REG_FTMP3); + M_FLOORDL(REG_FTMP3, REG_FTMP3); + M_CVTLD(REG_FTMP3, REG_FTMP3); + M_DMUL(REG_FTMP3, s2, REG_FTMP3); + M_DSUB(s1, REG_FTMP3, d); + store_reg_to_var_flt(iptr->dst, d); + break; + + case ICMD_I2F: /* ..., value ==> ..., (float) value */ + case ICMD_L2F: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_FTMP3); + M_MOVLD(s1, d); + M_CVTLF(d, d); + store_reg_to_var_flt(iptr->dst, d); + break; + + case ICMD_I2D: /* ..., value ==> ..., (double) value */ + case ICMD_L2D: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_FTMP3); + M_MOVLD(s1, d); + M_CVTLD(d, d); + store_reg_to_var_flt(iptr->dst, d); + break; + + case ICMD_F2I: /* ..., (float) value ==> ..., (int) value */ + + var_to_reg_flt(s1, src, REG_FTMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_CVTFI(s1, REG_FTMP1); + M_MOVDL(REG_FTMP1, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_D2I: /* ..., (double) value ==> ..., (int) value */ + + var_to_reg_flt(s1, src, REG_FTMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_CVTDI(s1, REG_FTMP1); + M_MOVDL(REG_FTMP1, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_F2L: /* ..., (float) value ==> ..., (long) value */ + + var_to_reg_flt(s1, src, REG_FTMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_CVTFL(s1, REG_FTMP1); + M_MOVDL(REG_FTMP1, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_D2L: /* ..., (double) value ==> ..., (long) value */ + + var_to_reg_flt(s1, src, REG_FTMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_CVTDL(s1, REG_FTMP1); + M_MOVDL(REG_FTMP1, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_F2D: /* ..., value ==> ..., (double) value */ + + var_to_reg_flt(s1, src, REG_FTMP1); + d = reg_of_var(iptr->dst, REG_FTMP3); + M_CVTFD(s1, d); + store_reg_to_var_flt(iptr->dst, d); + break; + + case ICMD_D2F: /* ..., value ==> ..., (double) value */ + + var_to_reg_flt(s1, src, REG_FTMP1); + d = reg_of_var(iptr->dst, REG_FTMP3); + M_CVTDF(s1, d); + store_reg_to_var_flt(iptr->dst, d); + break; + + case ICMD_FCMPL: /* ..., val1, val2 ==> ..., val1 fcmpl val2 */ + + var_to_reg_flt(s1, src->prev, REG_FTMP1); + var_to_reg_flt(s2, src, REG_FTMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_FCMPUEQF(s1, s2); + M_FBF(2); /* jump over next instructions */ + M_LSUB_IMM(REG_ZERO, 1, d); + M_CLR(d); + M_FCMPULTF(s2, s1); + M_FBF(2); /* jump over next instruction */ + M_NOP; + M_LADD_IMM(REG_ZERO, 1, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_DCMPL: /* ..., val1, val2 ==> ..., val1 fcmpl val2 */ + + var_to_reg_flt(s1, src->prev, REG_FTMP1); + var_to_reg_flt(s2, src, REG_FTMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_FCMPUEQD(s1, s2); + M_FBF(2); /* jump over next instructions */ + M_LSUB_IMM(REG_ZERO, 1, d); + M_CLR(d); + M_FCMPULTD(s2, s1); + M_FBF(2); /* jump over next instruction */ + M_NOP; + M_LADD_IMM(REG_ZERO, 1, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_FCMPG: /* ..., val1, val2 ==> ..., val1 fcmpg val2 */ + + var_to_reg_flt(s1, src->prev, REG_FTMP1); + var_to_reg_flt(s2, src, REG_FTMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_FCMPUEQF(s1, s2); + M_FBF(2); /* jump over next instruction */ + M_LADD_IMM(REG_ZERO, 1, d); + M_CLR(d); + M_FCMPULTF(s1, s2); + M_FBF(2); /* jump over next instruction */ + M_NOP; + M_LSUB_IMM(REG_ZERO, 1, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_DCMPG: /* ..., val1, val2 ==> ..., val1 fcmpg val2 */ + + var_to_reg_flt(s1, src->prev, REG_FTMP1); + var_to_reg_flt(s2, src, REG_FTMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + M_FCMPUEQD(s1, s2); + M_FBF(2); /* jump over next instruction */ + M_LADD_IMM(REG_ZERO, 1, d); + M_CLR(d); + M_FCMPULTD(s1, s2); + M_FBF(2); /* jump over next instruction */ + M_NOP; + M_LSUB_IMM(REG_ZERO, 1, d); + store_reg_to_var_int(iptr->dst, d); + break; + + + /* memory operations **************************************************/ + +#define gen_bound_check \ + if (checkbounds) {\ + M_ILD(REG_ITMP3, s1, OFFSET(java_arrayheader, size));\ + M_CMPULT(s2, REG_ITMP3, REG_ITMP3);\ + M_BEQZ(REG_ITMP3, 0);\ + mcode_addxboundrefs(mcodeptr);\ + } + + case ICMD_ARRAYLENGTH: /* ..., arrayref ==> ..., length */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + gen_nullptr_check(s1); + M_ILD(d, s1, OFFSET(java_arrayheader, size)); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_AALOAD: /* ..., arrayref, index ==> ..., value */ + + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + gen_nullptr_check(s1); + gen_bound_check; + M_SAADDQ(s2, s1, REG_ITMP1); + M_ALD( d, REG_ITMP1, OFFSET(java_objectarray, data[0])); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_LALOAD: /* ..., arrayref, index ==> ..., value */ + + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + gen_nullptr_check(s1); + gen_bound_check; + M_S8ADDQ(s2, s1, REG_ITMP1); + M_LLD(d, REG_ITMP1, OFFSET(java_longarray, data[0])); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_IALOAD: /* ..., arrayref, index ==> ..., value */ + + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + gen_nullptr_check(s1); + gen_bound_check; + M_S4ADDQ(s2, s1, REG_ITMP1); + M_ILD(d, REG_ITMP1, OFFSET(java_intarray, data[0])); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_FALOAD: /* ..., arrayref, index ==> ..., value */ + + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_FTMP3); + gen_nullptr_check(s1); + gen_bound_check; + M_S4ADDQ(s2, s1, REG_ITMP1); + M_FLD(d, REG_ITMP1, OFFSET(java_floatarray, data[0])); + store_reg_to_var_flt(iptr->dst, d); + break; + + case ICMD_DALOAD: /* ..., arrayref, index ==> ..., value */ + + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_FTMP3); + gen_nullptr_check(s1); + gen_bound_check; + M_S8ADDQ(s2, s1, REG_ITMP1); + M_DLD(d, REG_ITMP1, OFFSET(java_doublearray, data[0])); + store_reg_to_var_flt(iptr->dst, d); + break; + + case ICMD_CALOAD: /* ..., arrayref, index ==> ..., value */ + + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + gen_nullptr_check(s1); + gen_bound_check; + if (has_ext_instr_set) { + M_LADD(s2, s1, REG_ITMP1); + M_LADD(s2, REG_ITMP1, REG_ITMP1); + M_SLDU(d, REG_ITMP1, OFFSET(java_chararray, data[0])); + } + else { + M_LADD (s2, s1, REG_ITMP1); + M_LADD (s2, REG_ITMP1, REG_ITMP1); + M_LLD_U(REG_ITMP2, REG_ITMP1, OFFSET(java_chararray, data[0])); + M_LDA (REG_ITMP1, REG_ITMP1, OFFSET(java_chararray, data[0])); + M_EXTWL(REG_ITMP2, REG_ITMP1, d); + } + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_SALOAD: /* ..., arrayref, index ==> ..., value */ + + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + gen_nullptr_check(s1); + gen_bound_check; + if (has_ext_instr_set) { + M_LADD(s2, s1, REG_ITMP1); + M_LADD(s2, REG_ITMP1, REG_ITMP1); + M_SLDU( d, REG_ITMP1, OFFSET (java_shortarray, data[0])); + M_SSEXT(d, d); + } + else { + M_LADD(s2, s1, REG_ITMP1); + M_LADD(s2, REG_ITMP1, REG_ITMP1); + M_LLD_U(REG_ITMP2, REG_ITMP1, OFFSET(java_shortarray, data[0])); + M_LDA(REG_ITMP1, REG_ITMP1, OFFSET(java_shortarray, data[0])+2); + M_EXTQH(REG_ITMP2, REG_ITMP1, d); + M_SRA_IMM(d, 48, d); + } + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_BALOAD: /* ..., arrayref, index ==> ..., value */ + + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + d = reg_of_var(iptr->dst, REG_ITMP3); + gen_nullptr_check(s1); + gen_bound_check; + if (has_ext_instr_set) { + M_LADD (s2, s1, REG_ITMP1); + M_BLDU (d, REG_ITMP1, OFFSET (java_shortarray, data[0])); + M_BSEXT (d, d); + } + else { + M_LADD(s2, s1, REG_ITMP1); + M_LLD_U(REG_ITMP2, REG_ITMP1, OFFSET(java_bytearray, data[0])); + M_LDA(REG_ITMP1, REG_ITMP1, OFFSET(java_bytearray, data[0])+1); + M_EXTQH(REG_ITMP2, REG_ITMP1, d); + M_SRA_IMM(d, 56, d); + } + store_reg_to_var_int(iptr->dst, d); + break; + + + case ICMD_AASTORE: /* ..., arrayref, index, value ==> ... */ + + var_to_reg_int(s1, src->prev->prev, REG_ITMP1); + var_to_reg_int(s2, src->prev, REG_ITMP2); + gen_nullptr_check(s1); + gen_bound_check; + var_to_reg_int(s3, src, REG_ITMP3); + M_SAADDQ(s2, s1, REG_ITMP1); + M_AST (s3, REG_ITMP1, OFFSET(java_objectarray, data[0])); + break; + + case ICMD_LASTORE: /* ..., arrayref, index, value ==> ... */ + + var_to_reg_int(s1, src->prev->prev, REG_ITMP1); + var_to_reg_int(s2, src->prev, REG_ITMP2); + gen_nullptr_check(s1); + gen_bound_check; + var_to_reg_int(s3, src, REG_ITMP3); + M_S8ADDQ(s2, s1, REG_ITMP1); + M_LST (s3, REG_ITMP1, OFFSET(java_longarray, data[0])); + break; + + case ICMD_IASTORE: /* ..., arrayref, index, value ==> ... */ + + var_to_reg_int(s1, src->prev->prev, REG_ITMP1); + var_to_reg_int(s2, src->prev, REG_ITMP2); + gen_nullptr_check(s1); + gen_bound_check; + var_to_reg_int(s3, src, REG_ITMP3); + M_S4ADDQ(s2, s1, REG_ITMP1); + M_IST (s3, REG_ITMP1, OFFSET(java_intarray, data[0])); + break; + + case ICMD_FASTORE: /* ..., arrayref, index, value ==> ... */ + + var_to_reg_int(s1, src->prev->prev, REG_ITMP1); + var_to_reg_int(s2, src->prev, REG_ITMP2); + gen_nullptr_check(s1); + gen_bound_check; + var_to_reg_flt(s3, src, REG_FTMP3); + M_S4ADDQ(s2, s1, REG_ITMP1); + M_FST (s3, REG_ITMP1, OFFSET(java_floatarray, data[0])); + break; + + case ICMD_DASTORE: /* ..., arrayref, index, value ==> ... */ + + var_to_reg_int(s1, src->prev->prev, REG_ITMP1); + var_to_reg_int(s2, src->prev, REG_ITMP2); + gen_nullptr_check(s1); + gen_bound_check; + var_to_reg_flt(s3, src, REG_FTMP3); + M_S8ADDQ(s2, s1, REG_ITMP1); + M_DST (s3, REG_ITMP1, OFFSET(java_doublearray, data[0])); + break; + + case ICMD_CASTORE: /* ..., arrayref, index, value ==> ... */ + + var_to_reg_int(s1, src->prev->prev, REG_ITMP1); + var_to_reg_int(s2, src->prev, REG_ITMP2); + gen_nullptr_check(s1); + gen_bound_check; + var_to_reg_int(s3, src, REG_ITMP3); + if (has_ext_instr_set) { + M_LADD(s2, s1, REG_ITMP1); + M_LADD(s2, REG_ITMP1, REG_ITMP1); + M_SST (s3, REG_ITMP1, OFFSET(java_chararray, data[0])); + } + else { + M_LADD (s2, s1, REG_ITMP1); + M_LADD (s2, REG_ITMP1, REG_ITMP1); + M_LLD_U(REG_ITMP2, REG_ITMP1, OFFSET(java_chararray, data[0])); + M_LDA (REG_ITMP1, REG_ITMP1, OFFSET(java_chararray, data[0])); + M_INSWL(s3, REG_ITMP1, REG_ITMP3); + M_MSKWL(REG_ITMP2, REG_ITMP1, REG_ITMP2); + M_OR (REG_ITMP2, REG_ITMP3, REG_ITMP2); + M_LST_U(REG_ITMP2, REG_ITMP1, 0); + } + break; + + case ICMD_SASTORE: /* ..., arrayref, index, value ==> ... */ + + var_to_reg_int(s1, src->prev->prev, REG_ITMP1); + var_to_reg_int(s2, src->prev, REG_ITMP2); + gen_nullptr_check(s1); + gen_bound_check; + var_to_reg_int(s3, src, REG_ITMP3); + if (has_ext_instr_set) { + M_LADD(s2, s1, REG_ITMP1); + M_LADD(s2, REG_ITMP1, REG_ITMP1); + M_SST (s3, REG_ITMP1, OFFSET(java_shortarray, data[0])); + } + else { + M_LADD (s2, s1, REG_ITMP1); + M_LADD (s2, REG_ITMP1, REG_ITMP1); + M_LLD_U(REG_ITMP2, REG_ITMP1, OFFSET(java_shortarray, data[0])); + M_LDA (REG_ITMP1, REG_ITMP1, OFFSET(java_shortarray, data[0])); + M_INSWL(s3, REG_ITMP1, REG_ITMP3); + M_MSKWL(REG_ITMP2, REG_ITMP1, REG_ITMP2); + M_OR (REG_ITMP2, REG_ITMP3, REG_ITMP2); + M_LST_U(REG_ITMP2, REG_ITMP1, 0); + } + break; + + case ICMD_BASTORE: /* ..., arrayref, index, value ==> ... */ + + var_to_reg_int(s1, src->prev->prev, REG_ITMP1); + var_to_reg_int(s2, src->prev, REG_ITMP2); + gen_nullptr_check(s1); + gen_bound_check; + var_to_reg_int(s3, src, REG_ITMP3); + if (has_ext_instr_set) { + M_LADD(s2, s1, REG_ITMP1); + M_BST (s3, REG_ITMP1, OFFSET(java_bytearray, data[0])); + } + else { + M_LADD (s2, s1, REG_ITMP1); + M_LLD_U(REG_ITMP2, REG_ITMP1, OFFSET(java_bytearray, data[0])); + M_LDA (REG_ITMP1, REG_ITMP1, OFFSET(java_bytearray, data[0])); + M_INSBL(s3, REG_ITMP1, REG_ITMP3); + M_MSKBL(REG_ITMP2, REG_ITMP1, REG_ITMP2); + M_OR (REG_ITMP2, REG_ITMP3, REG_ITMP2); + M_LST_U(REG_ITMP2, REG_ITMP1, 0); + } + break; + + + case ICMD_PUTSTATIC: /* ..., value ==> ... */ + /* op1 = type, val.a = field address */ + + a = dseg_addaddress (&(((fieldinfo *)(iptr->val.a))->value)); + M_ALD(REG_ITMP1, REG_PV, a); + switch (iptr->op1) { + case TYPE_INT: + var_to_reg_int(s2, src, REG_ITMP2); + M_IST(s2, REG_ITMP1, 0); + break; + case TYPE_LNG: + var_to_reg_int(s2, src, REG_ITMP2); + M_LST(s2, REG_ITMP1, 0); + break; + case TYPE_ADR: + var_to_reg_int(s2, src, REG_ITMP2); + M_AST(s2, REG_ITMP1, 0); + break; + case TYPE_FLT: + var_to_reg_flt(s2, src, REG_FTMP2); + M_FST(s2, REG_ITMP1, 0); + break; + case TYPE_DBL: + var_to_reg_flt(s2, src, REG_FTMP2); + M_DST(s2, REG_ITMP1, 0); + break; + default: panic ("internal error"); + } + break; + + case ICMD_GETSTATIC: /* ... ==> ..., value */ + /* op1 = type, val.a = field address */ + + a = dseg_addaddress (&(((fieldinfo *)(iptr->val.a))->value)); + M_ALD(REG_ITMP1, REG_PV, a); + switch (iptr->op1) { + case TYPE_INT: + d = reg_of_var(iptr->dst, REG_ITMP3); + M_ILD(d, REG_ITMP1, 0); + store_reg_to_var_int(iptr->dst, d); + break; + case TYPE_LNG: + d = reg_of_var(iptr->dst, REG_ITMP3); + M_LLD(d, REG_ITMP1, 0); + store_reg_to_var_int(iptr->dst, d); + break; + case TYPE_ADR: + d = reg_of_var(iptr->dst, REG_ITMP3); + M_ALD(d, REG_ITMP1, 0); + store_reg_to_var_int(iptr->dst, d); + break; + case TYPE_FLT: + d = reg_of_var(iptr->dst, REG_FTMP1); + M_FLD(d, REG_ITMP1, 0); + store_reg_to_var_flt(iptr->dst, d); + break; + case TYPE_DBL: + d = reg_of_var(iptr->dst, REG_FTMP1); + M_DLD(d, REG_ITMP1, 0); + store_reg_to_var_flt(iptr->dst, d); + break; + default: panic ("internal error"); + } + break; + + + case ICMD_PUTFIELD: /* ..., value ==> ... */ + /* op1 = type, val.i = field offset */ + + a = ((fieldinfo *)(iptr->val.a))->offset; + switch (iptr->op1) { + case TYPE_INT: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + gen_nullptr_check(s1); + M_IST(s2, s1, a); + break; + case TYPE_LNG: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + gen_nullptr_check(s1); + M_LST(s2, s1, a); + break; + case TYPE_ADR: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + gen_nullptr_check(s1); + M_AST(s2, s1, a); + break; + case TYPE_FLT: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_flt(s2, src, REG_FTMP2); + gen_nullptr_check(s1); + M_FST(s2, s1, a); + break; + case TYPE_DBL: + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_flt(s2, src, REG_FTMP2); + gen_nullptr_check(s1); + M_DST(s2, s1, a); + break; + default: panic ("internal error"); + } + break; + + case ICMD_GETFIELD: /* ... ==> ..., value */ + /* op1 = type, val.i = field offset */ + + a = ((fieldinfo *)(iptr->val.a))->offset; + switch (iptr->op1) { + case TYPE_INT: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + gen_nullptr_check(s1); + M_ILD(d, s1, a); + store_reg_to_var_int(iptr->dst, d); + break; + case TYPE_LNG: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + gen_nullptr_check(s1); + M_LLD(d, s1, a); + store_reg_to_var_int(iptr->dst, d); + break; + case TYPE_ADR: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + gen_nullptr_check(s1); + M_ALD(d, s1, a); + store_reg_to_var_int(iptr->dst, d); + break; + case TYPE_FLT: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_FTMP1); + gen_nullptr_check(s1); + M_FLD(d, s1, a); + store_reg_to_var_flt(iptr->dst, d); + break; + case TYPE_DBL: + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_FTMP1); + gen_nullptr_check(s1); + M_DLD(d, s1, a); + store_reg_to_var_flt(iptr->dst, d); + break; + default: panic ("internal error"); + } + break; + + + /* branch operations **************************************************/ + +#define ALIGNCODENOP {if((int)((long)mcodeptr&7)){M_NOP;}} + + case ICMD_ATHROW: /* ..., objectref ==> ... (, objectref) */ + + var_to_reg_int(s1, src, REG_ITMP1); + M_INTMOVE(s1, REG_ITMP1_XPTR); + a = dseg_addaddress(asm_handle_exception); + M_ALD(REG_ITMP2, REG_PV, a); + M_JSR(REG_ITMP2_XPC, REG_ITMP2); + ALIGNCODENOP; + break; + + case ICMD_GOTO: /* ... ==> ... */ + /* op1 = target JavaVM pc */ + M_BR(0); + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + ALIGNCODENOP; + break; + + case ICMD_JSR: /* ... ==> ... */ + /* op1 = target JavaVM pc */ + + M_BSR(REG_ITMP1, 0); + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + + case ICMD_RET: /* ... ==> ... */ + /* op1 = local variable */ + + var = &(locals[iptr->op1][TYPE_ADR]); + if (var->flags & INMEMORY) { + M_ALD(REG_ITMP1, REG_SP, 8 * var->regoff); + M_RET(REG_ITMP1); + } + else + M_RET(var->regoff); + ALIGNCODENOP; + break; + + case ICMD_IFNULL: /* ..., value ==> ... */ + /* op1 = target JavaVM pc */ + + var_to_reg_int(s1, src, REG_ITMP1); + M_BEQZ(s1, 0); + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + + case ICMD_IFNONNULL: /* ..., value ==> ... */ + /* op1 = target JavaVM pc */ + + var_to_reg_int(s1, src, REG_ITMP1); + M_BNEZ(s1, 0); + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + + case ICMD_IFEQ: /* ..., value ==> ... */ + /* op1 = target JavaVM pc, val.i = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + if (iptr->val.i == 0) { + M_BEQZ(s1, 0); + } + else { + if ((iptr->val.i > 0) && (iptr->val.i <= 255)) { + M_CMPEQ_IMM(s1, iptr->val.i, REG_ITMP1); + } + else { + ICONST(REG_ITMP2, iptr->val.i); + M_CMPEQ(s1, REG_ITMP2, REG_ITMP1); + } + M_BNEZ(REG_ITMP1, 0); + } + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + + case ICMD_IFLT: /* ..., value ==> ... */ + /* op1 = target JavaVM pc, val.i = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + if (iptr->val.i == 0) { + M_BLTZ(s1, 0); + } + else { + if ((iptr->val.i > 0) && (iptr->val.i <= 255)) { + M_CMPLT_IMM(s1, iptr->val.i, REG_ITMP1); + } + else { + ICONST(REG_ITMP2, iptr->val.i); + M_CMPLT(s1, REG_ITMP2, REG_ITMP1); + } + M_BNEZ(REG_ITMP1, 0); + } + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + + case ICMD_IFLE: /* ..., value ==> ... */ + /* op1 = target JavaVM pc, val.i = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + if (iptr->val.i == 0) { + M_BLEZ(s1, 0); + } + else { + if ((iptr->val.i > 0) && (iptr->val.i <= 255)) { + M_CMPLE_IMM(s1, iptr->val.i, REG_ITMP1); + } + else { + ICONST(REG_ITMP2, iptr->val.i); + M_CMPLE(s1, REG_ITMP2, REG_ITMP1); + } + M_BNEZ(REG_ITMP1, 0); + } + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + + case ICMD_IFNE: /* ..., value ==> ... */ + /* op1 = target JavaVM pc, val.i = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + if (iptr->val.i == 0) { + M_BNEZ(s1, 0); + } + else { + if ((iptr->val.i > 0) && (iptr->val.i <= 255)) { + M_CMPEQ_IMM(s1, iptr->val.i, REG_ITMP1); + } + else { + ICONST(REG_ITMP2, iptr->val.i); + M_CMPEQ(s1, REG_ITMP2, REG_ITMP1); + } + M_BEQZ(REG_ITMP1, 0); + } + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + + case ICMD_IFGT: /* ..., value ==> ... */ + /* op1 = target JavaVM pc, val.i = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + if (iptr->val.i == 0) { + M_BGTZ(s1, 0); + } + else { + if ((iptr->val.i > 0) && (iptr->val.i <= 255)) { + M_CMPLE_IMM(s1, iptr->val.i, REG_ITMP1); + } + else { + ICONST(REG_ITMP2, iptr->val.i); + M_CMPLE(s1, REG_ITMP2, REG_ITMP1); + } + M_BEQZ(REG_ITMP1, 0); + } + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + + case ICMD_IFGE: /* ..., value ==> ... */ + /* op1 = target JavaVM pc, val.i = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + if (iptr->val.i == 0) { + M_BGEZ(s1, 0); + } + else { + if ((iptr->val.i > 0) && (iptr->val.i <= 255)) { + M_CMPLT_IMM(s1, iptr->val.i, REG_ITMP1); + } + else { + ICONST(REG_ITMP2, iptr->val.i); + M_CMPLT(s1, REG_ITMP2, REG_ITMP1); + } + M_BEQZ(REG_ITMP1, 0); + } + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + + case ICMD_IF_LEQ: /* ..., value ==> ... */ + /* op1 = target JavaVM pc, val.l = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + if (iptr->val.l == 0) { + M_BEQZ(s1, 0); + } + else { + if ((iptr->val.l > 0) && (iptr->val.l <= 255)) { + M_CMPEQ_IMM(s1, iptr->val.l, REG_ITMP1); + } + else { + LCONST(REG_ITMP2, iptr->val.l); + M_CMPEQ(s1, REG_ITMP2, REG_ITMP1); + } + M_BNEZ(REG_ITMP1, 0); + } + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + + case ICMD_IF_LLT: /* ..., value ==> ... */ + /* op1 = target JavaVM pc, val.l = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + if (iptr->val.l == 0) { + M_BLTZ(s1, 0); + } + else { + if ((iptr->val.l > 0) && (iptr->val.l <= 255)) { + M_CMPLT_IMM(s1, iptr->val.l, REG_ITMP1); + } + else { + LCONST(REG_ITMP2, iptr->val.l); + M_CMPLT(s1, REG_ITMP2, REG_ITMP1); + } + M_BNEZ(REG_ITMP1, 0); + } + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + + case ICMD_IF_LLE: /* ..., value ==> ... */ + /* op1 = target JavaVM pc, val.l = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + if (iptr->val.l == 0) { + M_BLEZ(s1, 0); + } + else { + if ((iptr->val.l > 0) && (iptr->val.l <= 255)) { + M_CMPLE_IMM(s1, iptr->val.l, REG_ITMP1); + } + else { + LCONST(REG_ITMP2, iptr->val.l); + M_CMPLE(s1, REG_ITMP2, REG_ITMP1); + } + M_BNEZ(REG_ITMP1, 0); + } + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + + case ICMD_IF_LNE: /* ..., value ==> ... */ + /* op1 = target JavaVM pc, val.l = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + if (iptr->val.l == 0) { + M_BNEZ(s1, 0); + } + else { + if ((iptr->val.l > 0) && (iptr->val.l <= 255)) { + M_CMPEQ_IMM(s1, iptr->val.l, REG_ITMP1); + } + else { + LCONST(REG_ITMP2, iptr->val.l); + M_CMPEQ(s1, REG_ITMP2, REG_ITMP1); + } + M_BEQZ(REG_ITMP1, 0); + } + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + + case ICMD_IF_LGT: /* ..., value ==> ... */ + /* op1 = target JavaVM pc, val.l = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + if (iptr->val.l == 0) { + M_BGTZ(s1, 0); + } + else { + if ((iptr->val.l > 0) && (iptr->val.l <= 255)) { + M_CMPLE_IMM(s1, iptr->val.l, REG_ITMP1); + } + else { + LCONST(REG_ITMP2, iptr->val.l); + M_CMPLE(s1, REG_ITMP2, REG_ITMP1); + } + M_BEQZ(REG_ITMP1, 0); + } + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + + case ICMD_IF_LGE: /* ..., value ==> ... */ + /* op1 = target JavaVM pc, val.l = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + if (iptr->val.l == 0) { + M_BGEZ(s1, 0); + } + else { + if ((iptr->val.l > 0) && (iptr->val.l <= 255)) { + M_CMPLT_IMM(s1, iptr->val.l, REG_ITMP1); + } + else { + LCONST(REG_ITMP2, iptr->val.l); + M_CMPLT(s1, REG_ITMP2, REG_ITMP1); + } + M_BEQZ(REG_ITMP1, 0); + } + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + + case ICMD_IF_ICMPEQ: /* ..., value, value ==> ... */ + case ICMD_IF_LCMPEQ: /* op1 = target JavaVM pc */ + case ICMD_IF_ACMPEQ: + + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + M_CMPEQ(s1, s2, REG_ITMP1); + M_BNEZ(REG_ITMP1, 0); + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + + case ICMD_IF_ICMPNE: /* ..., value, value ==> ... */ + case ICMD_IF_LCMPNE: /* op1 = target JavaVM pc */ + case ICMD_IF_ACMPNE: + + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + M_CMPEQ(s1, s2, REG_ITMP1); + M_BEQZ(REG_ITMP1, 0); + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + + case ICMD_IF_ICMPLT: /* ..., value, value ==> ... */ + case ICMD_IF_LCMPLT: /* op1 = target JavaVM pc */ + + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + M_CMPLT(s1, s2, REG_ITMP1); + M_BNEZ(REG_ITMP1, 0); + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + + case ICMD_IF_ICMPGT: /* ..., value, value ==> ... */ + case ICMD_IF_LCMPGT: /* op1 = target JavaVM pc */ + + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + M_CMPLE(s1, s2, REG_ITMP1); + M_BEQZ(REG_ITMP1, 0); + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + + case ICMD_IF_ICMPLE: /* ..., value, value ==> ... */ + case ICMD_IF_LCMPLE: /* op1 = target JavaVM pc */ + + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + M_CMPLE(s1, s2, REG_ITMP1); + M_BNEZ(REG_ITMP1, 0); + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + + case ICMD_IF_ICMPGE: /* ..., value, value ==> ... */ + case ICMD_IF_LCMPGE: /* op1 = target JavaVM pc */ + + var_to_reg_int(s1, src->prev, REG_ITMP1); + var_to_reg_int(s2, src, REG_ITMP2); + M_CMPLT(s1, s2, REG_ITMP1); + M_BEQZ(REG_ITMP1, 0); + mcode_addreference(BlockPtrOfPC(iptr->op1), mcodeptr); + break; + + /* (value xx 0) ? IFxx_ICONST : ELSE_ICONST */ + + case ICMD_ELSE_ICONST: /* handled by IFxx_ICONST */ + break; + + case ICMD_IFEQ_ICONST: /* ..., value ==> ..., constant */ + /* val.i = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + a = iptr->val.i; + if (iptr[1].opc == ICMD_ELSE_ICONST) { + if ((a == 1) && (iptr[1].val.i == 0)) { + M_CMPEQ(s1, REG_ZERO, d); + store_reg_to_var_int(iptr->dst, d); + break; + } + if ((a == 0) && (iptr[1].val.i == 1)) { + M_CMPEQ(s1, REG_ZERO, d); + M_XOR_IMM(d, 1, d); + store_reg_to_var_int(iptr->dst, d); + break; + } + if (s1 == d) { + M_MOV(s1, REG_ITMP1); + s1 = REG_ITMP1; + } + ICONST(d, iptr[1].val.i); + } + if ((a >= 0) && (a <= 255)) { + M_CMOVEQ_IMM(s1, a, d); + } + else { + ICONST(REG_ITMP2, a); + M_CMOVEQ(s1, REG_ITMP2, d); + } + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_IFNE_ICONST: /* ..., value ==> ..., constant */ + /* val.i = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + a = iptr->val.i; + if (iptr[1].opc == ICMD_ELSE_ICONST) { + if ((a == 0) && (iptr[1].val.i == 1)) { + M_CMPEQ(s1, REG_ZERO, d); + store_reg_to_var_int(iptr->dst, d); + break; + } + if ((a == 1) && (iptr[1].val.i == 0)) { + M_CMPEQ(s1, REG_ZERO, d); + M_XOR_IMM(d, 1, d); + store_reg_to_var_int(iptr->dst, d); + break; + } + if (s1 == d) { + M_MOV(s1, REG_ITMP1); + s1 = REG_ITMP1; + } + ICONST(d, iptr[1].val.i); + } + if ((a >= 0) && (a <= 255)) { + M_CMOVNE_IMM(s1, a, d); + } + else { + ICONST(REG_ITMP2, a); + M_CMOVNE(s1, REG_ITMP2, d); + } + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_IFLT_ICONST: /* ..., value ==> ..., constant */ + /* val.i = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + a = iptr->val.i; + if ((iptr[1].opc == ICMD_ELSE_ICONST)) { + if ((a == 1) && (iptr[1].val.i == 0)) { + M_CMPLT(s1, REG_ZERO, d); + store_reg_to_var_int(iptr->dst, d); + break; + } + if ((a == 0) && (iptr[1].val.i == 1)) { + M_CMPLE(REG_ZERO, s1, d); + store_reg_to_var_int(iptr->dst, d); + break; + } + if (s1 == d) { + M_MOV(s1, REG_ITMP1); + s1 = REG_ITMP1; + } + ICONST(d, iptr[1].val.i); + } + if ((a >= 0) && (a <= 255)) { + M_CMOVLT_IMM(s1, a, d); + } + else { + ICONST(REG_ITMP2, a); + M_CMOVLT(s1, REG_ITMP2, d); + } + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_IFGE_ICONST: /* ..., value ==> ..., constant */ + /* val.i = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + a = iptr->val.i; + if ((iptr[1].opc == ICMD_ELSE_ICONST)) { + if ((a == 1) && (iptr[1].val.i == 0)) { + M_CMPLE(REG_ZERO, s1, d); + store_reg_to_var_int(iptr->dst, d); + break; + } + if ((a == 0) && (iptr[1].val.i == 1)) { + M_CMPLT(s1, REG_ZERO, d); + store_reg_to_var_int(iptr->dst, d); + break; + } + if (s1 == d) { + M_MOV(s1, REG_ITMP1); + s1 = REG_ITMP1; + } + ICONST(d, iptr[1].val.i); + } + if ((a >= 0) && (a <= 255)) { + M_CMOVGE_IMM(s1, a, d); + } + else { + ICONST(REG_ITMP2, a); + M_CMOVGE(s1, REG_ITMP2, d); + } + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_IFGT_ICONST: /* ..., value ==> ..., constant */ + /* val.i = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + a = iptr->val.i; + if ((iptr[1].opc == ICMD_ELSE_ICONST)) { + if ((a == 1) && (iptr[1].val.i == 0)) { + M_CMPLT(REG_ZERO, s1, d); + store_reg_to_var_int(iptr->dst, d); + break; + } + if ((a == 0) && (iptr[1].val.i == 1)) { + M_CMPLE(s1, REG_ZERO, d); + store_reg_to_var_int(iptr->dst, d); + break; + } + if (s1 == d) { + M_MOV(s1, REG_ITMP1); + s1 = REG_ITMP1; + } + ICONST(d, iptr[1].val.i); + } + if ((a >= 0) && (a <= 255)) { + M_CMOVGT_IMM(s1, a, d); + } + else { + ICONST(REG_ITMP2, a); + M_CMOVGT(s1, REG_ITMP2, d); + } + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_IFLE_ICONST: /* ..., value ==> ..., constant */ + /* val.i = constant */ + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + a = iptr->val.i; + if ((iptr[1].opc == ICMD_ELSE_ICONST)) { + if ((a == 1) && (iptr[1].val.i == 0)) { + M_CMPLE(s1, REG_ZERO, d); + store_reg_to_var_int(iptr->dst, d); + break; + } + if ((a == 0) && (iptr[1].val.i == 1)) { + M_CMPLT(REG_ZERO, s1, d); + store_reg_to_var_int(iptr->dst, d); + break; + } + if (s1 == d) { + M_MOV(s1, REG_ITMP1); + s1 = REG_ITMP1; + } + ICONST(d, iptr[1].val.i); + } + if ((a >= 0) && (a <= 255)) { + M_CMOVLE_IMM(s1, a, d); + } + else { + ICONST(REG_ITMP2, a); + M_CMOVLE(s1, REG_ITMP2, d); + } + store_reg_to_var_int(iptr->dst, d); + break; + + + case ICMD_IRETURN: /* ..., retvalue ==> ... */ + case ICMD_LRETURN: + case ICMD_ARETURN: + +#ifdef USE_THREADS + if (checksync && (method->flags & ACC_SYNCHRONIZED)) { + a = dseg_addaddress ((void*) (builtin_monitorexit)); + M_ALD(REG_PV, REG_PV, a); + M_ALD(argintregs[0], REG_SP, 8 * maxmemuse); + M_JSR(REG_RA, REG_PV); + M_LDA(REG_PV, REG_RA, -(int)((u1*) mcodeptr - mcodebase)); + } +#endif + var_to_reg_int(s1, src, REG_RESULT); + M_INTMOVE(s1, REG_RESULT); + goto nowperformreturn; + + case ICMD_FRETURN: /* ..., retvalue ==> ... */ + case ICMD_DRETURN: + +#ifdef USE_THREADS + if (checksync && (method->flags & ACC_SYNCHRONIZED)) { + a = dseg_addaddress ((void*) (builtin_monitorexit)); + M_ALD(REG_PV, REG_PV, a); + M_ALD(argintregs[0], REG_SP, 8 * maxmemuse); + M_JSR(REG_RA, REG_PV); + M_LDA(REG_PV, REG_RA, -(int)((u1*) mcodeptr - mcodebase)); + } +#endif + var_to_reg_flt(s1, src, REG_FRESULT); + M_FLTMOVE(s1, REG_FRESULT); + goto nowperformreturn; + + case ICMD_RETURN: /* ... ==> ... */ + +#ifdef USE_THREADS + if (checksync && (method->flags & ACC_SYNCHRONIZED)) { + a = dseg_addaddress ((void*) (builtin_monitorexit)); + M_ALD(REG_PV, REG_PV, a); + M_ALD(argintregs[0], REG_SP, 8 * maxmemuse); + M_JSR(REG_RA, REG_PV); + M_LDA(REG_PV, REG_RA, -(int)((u1*) mcodeptr - mcodebase)); + } +#endif + +nowperformreturn: + { + int r, p; + + p = parentargs_base; + + /* restore return address */ + + if (!isleafmethod) + {p--; M_LLD (REG_RA, REG_SP, 8 * p);} + + /* restore saved registers */ + + for (r = savintregcnt - 1; r >= maxsavintreguse; r--) + {p--; M_LLD(savintregs[r], REG_SP, 8 * p);} + for (r = savfltregcnt - 1; r >= maxsavfltreguse; r--) + {p--; M_DLD(savfltregs[r], REG_SP, 8 * p);} + + /* deallocate stack */ + + if (parentargs_base) + {M_LDA(REG_SP, REG_SP, parentargs_base*8);} + + /* call trace function */ + + if (runverbose) { + M_LDA (REG_SP, REG_SP, -24); + M_AST(REG_RA, REG_SP, 0); + M_LST(REG_RESULT, REG_SP, 8); + M_DST(REG_FRESULT, REG_SP,16); + a = dseg_addaddress (method); + M_ALD(argintregs[0], REG_PV, a); + M_MOV(REG_RESULT, argintregs[1]); + M_FLTMOVE(REG_FRESULT, argfltregs[2]); + a = dseg_addaddress ((void*) (builtin_displaymethodstop)); + M_ALD(REG_PV, REG_PV, a); + M_JSR (REG_RA, REG_PV); + s1 = (int)((u1*) mcodeptr - mcodebase); + if (s1<=32768) M_LDA (REG_PV, REG_RA, -s1); + else { + s4 ml=-s1, mh=0; + while (ml<-32768) { ml+=65536; mh--; } + M_LDA (REG_PV, REG_RA, ml ); + M_LDAH (REG_PV, REG_PV, mh ); + } + M_DLD(REG_FRESULT, REG_SP,16); + M_LLD(REG_RESULT, REG_SP, 8); + M_ALD(REG_RA, REG_SP, 0); + M_LDA (REG_SP, REG_SP, 24); + } + + M_RET(REG_RA); + ALIGNCODENOP; + } + break; + + + case ICMD_TABLESWITCH: /* ..., index ==> ... */ + { + s4 i, l, *s4ptr; + + s4ptr = iptr->val.a; + l = s4ptr[1]; /* low */ + i = s4ptr[2]; /* high */ + + var_to_reg_int(s1, src, REG_ITMP1); + if (l == 0) + {M_INTMOVE(s1, REG_ITMP1);} + else + M_LDA(REG_ITMP1, s1, -l); + i = i - l + 1; + + /* range check */ + + if (i <= 256) + M_CMPULE_IMM(REG_ITMP1, i - 1, REG_ITMP2); + else { + M_LDA(REG_ITMP2, REG_ZERO, i - 1); + M_CMPULE(REG_ITMP1, REG_ITMP2, REG_ITMP2); + } + M_BEQZ(REG_ITMP2, 0); + mcode_addreference(BlockPtrOfPC(s4ptr[0]), mcodeptr); + + /* build jump table top down and use address of lowest entry */ + + s4ptr += 3 + i; + while (--i >= 0) { + dseg_addtarget(BlockPtrOfPC(*--s4ptr)); + } + } + + /* length of dataseg after last dseg_addtarget is used by load */ + + M_SAADDQ(REG_ITMP1, REG_PV, REG_ITMP2); + M_ALD(REG_ITMP2, REG_ITMP2, -dseglen); + M_JMP(REG_ITMP2); + ALIGNCODENOP; + break; + + + case ICMD_LOOKUPSWITCH: /* ..., key ==> ... */ + { + s4 i, l, val, *s4ptr; + + s4ptr = iptr->val.a; + l = s4ptr[0]; /* default */ + i = s4ptr[1]; /* count */ + + MCODECHECK((i<<2)+8); + var_to_reg_int(s1, src, REG_ITMP1); + while (--i >= 0) { + s4ptr += 2; + val = s4ptr[0]; + if ((val >= 0) && (val <= 255)) { + M_CMPEQ_IMM(s1, val, REG_ITMP2); + } + else { + if ((val >= -32768) && (val <= 32767)) { + M_LDA(REG_ITMP2, REG_ZERO, val); + } + else { + a = dseg_adds4 (val); + M_ILD(REG_ITMP2, REG_PV, a); + } + M_CMPEQ(s1, REG_ITMP2, REG_ITMP2); + } + M_BNEZ(REG_ITMP2, 0); + mcode_addreference(BlockPtrOfPC(s4ptr[1]), mcodeptr); + } + + M_BR(0); + mcode_addreference(BlockPtrOfPC(l), mcodeptr); + ALIGNCODENOP; + break; + } + + + case ICMD_BUILTIN3: /* ..., arg1, arg2, arg3 ==> ... */ + /* op1 = return type, val.a = function pointer*/ + s3 = 3; + goto gen_method; + + case ICMD_BUILTIN2: /* ..., arg1, arg2 ==> ... */ + /* op1 = return type, val.a = function pointer*/ + s3 = 2; + goto gen_method; + + case ICMD_BUILTIN1: /* ..., arg1 ==> ... */ + /* op1 = return type, val.a = function pointer*/ + s3 = 1; + goto gen_method; + + case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ... */ + /* op1 = arg count, val.a = method pointer */ + + case ICMD_INVOKESPECIAL:/* ..., objectref, [arg1, [arg2 ...]] ==> ... */ + /* op1 = arg count, val.a = method pointer */ + + case ICMD_INVOKEVIRTUAL:/* ..., objectref, [arg1, [arg2 ...]] ==> ... */ + /* op1 = arg count, val.a = method pointer */ + + case ICMD_INVOKEINTERFACE:/*.., objectref, [arg1, [arg2 ...]] ==> ... */ + /* op1 = arg count, val.a = method pointer */ + + s3 = iptr->op1; + +gen_method: { + methodinfo *m; + classinfo *ci; + + MCODECHECK((s3 << 1) + 64); + + /* copy arguments to registers or stack location */ + + for (; --s3 >= 0; src = src->prev) { + if (src->varkind == ARGVAR) + continue; + if (IS_INT_LNG_TYPE(src->type)) { + if (s3 < INT_ARG_CNT) { + s1 = argintregs[s3]; + var_to_reg_int(d, src, s1); + M_INTMOVE(d, s1); + } + else { + var_to_reg_int(d, src, REG_ITMP1); + M_LST(d, REG_SP, 8 * (s3 - INT_ARG_CNT)); + } + } + else + if (s3 < FLT_ARG_CNT) { + s1 = argfltregs[s3]; + var_to_reg_flt(d, src, s1); + M_FLTMOVE(d, s1); + } + else { + var_to_reg_flt(d, src, REG_FTMP1); + M_DST(d, REG_SP, 8 * (s3 - FLT_ARG_CNT)); + } + } /* end of for */ + + m = iptr->val.a; + switch (iptr->opc) { + case ICMD_BUILTIN3: + case ICMD_BUILTIN2: + case ICMD_BUILTIN1: + a = dseg_addaddress ((void*) (m)); + + M_ALD(REG_PV, REG_PV, a); /* Pointer to built-in-function */ + d = iptr->op1; + goto makeactualcall; + + case ICMD_INVOKESTATIC: + case ICMD_INVOKESPECIAL: + a = dseg_addaddress (m->stubroutine); + + M_ALD(REG_PV, REG_PV, a ); /* method pointer in r27 */ + + d = m->returntype; + goto makeactualcall; + + case ICMD_INVOKEVIRTUAL: + + gen_nullptr_check(argintregs[0]); + M_ALD(REG_METHODPTR, argintregs[0], + OFFSET(java_objectheader, vftbl)); + M_ALD(REG_PV, REG_METHODPTR, OFFSET(vftbl, table[0]) + + sizeof(methodptr) * m->vftblindex); + + d = m->returntype; + goto makeactualcall; + + case ICMD_INVOKEINTERFACE: + ci = m->class; + + gen_nullptr_check(argintregs[0]); + M_ALD(REG_METHODPTR, argintregs[0], + OFFSET(java_objectheader, vftbl)); + M_ALD(REG_METHODPTR, REG_METHODPTR, + OFFSET(vftbl, interfacetable[0]) - + sizeof(methodptr*) * ci->index); + M_ALD(REG_PV, REG_METHODPTR, + sizeof(methodptr) * (m - ci->methods)); + + d = m->returntype; + goto makeactualcall; + + default: + d = 0; + sprintf (logtext, "Unkown ICMD-Command: %d", iptr->opc); + error (); + } + +makeactualcall: + + M_JSR (REG_RA, REG_PV); + + /* recompute pv */ + + s1 = (int)((u1*) mcodeptr - mcodebase); + if (s1<=32768) M_LDA (REG_PV, REG_RA, -s1); + else { + s4 ml=-s1, mh=0; + while (ml<-32768) { ml+=65536; mh--; } + M_LDA (REG_PV, REG_RA, ml ); + M_LDAH (REG_PV, REG_PV, mh ); + } + + /* d contains return type */ + + if (d != TYPE_VOID) { + if (IS_INT_LNG_TYPE(iptr->dst->type)) { + s1 = reg_of_var(iptr->dst, REG_RESULT); + M_INTMOVE(REG_RESULT, s1); + store_reg_to_var_int(iptr->dst, s1); + } + else { + s1 = reg_of_var(iptr->dst, REG_FRESULT); + M_FLTMOVE(REG_FRESULT, s1); + store_reg_to_var_flt(iptr->dst, s1); + } + } + } + break; + + + case ICMD_INSTANCEOF: /* ..., objectref ==> ..., intresult */ + + /* op1: 0 == array, 1 == class */ + /* val.a: (classinfo*) superclass */ + +/* superclass is an interface: + * + * return (sub != NULL) && + * (sub->vftbl->interfacetablelength > super->index) && + * (sub->vftbl->interfacetable[-super->index] != NULL); + * + * superclass is a class: + * + * return ((sub != NULL) && (0 + * <= (sub->vftbl->baseval - super->vftbl->baseval) <= + * super->vftbl->diffvall)); + */ + + { + classinfo *super = (classinfo*) iptr->val.a; + + var_to_reg_int(s1, src, REG_ITMP1); + d = reg_of_var(iptr->dst, REG_ITMP3); + if (s1 == d) { + M_MOV(s1, REG_ITMP1); + s1 = REG_ITMP1; + } + M_CLR(d); + if (iptr->op1) { /* class/interface */ + if (super->flags & ACC_INTERFACE) { /* interface */ + M_BEQZ(s1, 6); + M_ALD(REG_ITMP1, s1, OFFSET(java_objectheader, vftbl)); + M_ILD(REG_ITMP2, REG_ITMP1, OFFSET(vftbl, interfacetablelength)); + M_LDA(REG_ITMP2, REG_ITMP2, - super->index); + M_BLEZ(REG_ITMP2, 2); + M_ALD(REG_ITMP1, REG_ITMP1, + OFFSET(vftbl, interfacetable[0]) - + super->index * sizeof(methodptr*)); + M_CMPULT(REG_ZERO, REG_ITMP1, d); /* REG_ITMP1 != 0 */ + } + else { /* class */ + s2 = super->vftbl->diffval; + M_BEQZ(s1, 4 + (s2 > 255)); + M_ALD(REG_ITMP1, s1, OFFSET(java_objectheader, vftbl)); + M_ILD(REG_ITMP1, REG_ITMP1, OFFSET(vftbl, baseval)); + M_LDA(REG_ITMP1, REG_ITMP1, - super->vftbl->baseval); + if (s2 <= 255) + M_CMPULE_IMM(REG_ITMP1, s2, d); + else { + M_LDA(REG_ITMP2, REG_ZERO, s2); + M_CMPULE(REG_ITMP1, REG_ITMP2, d); + } + } + } + else + panic ("internal error: no inlined array instanceof"); + } + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_CHECKCAST: /* ..., objectref ==> ..., objectref */ + + /* op1: 0 == array, 1 == class */ + /* val.a: (classinfo*) superclass */ + +/* superclass is an interface: + * + * OK if ((sub == NULL) || + * (sub->vftbl->interfacetablelength > super->index) && + * (sub->vftbl->interfacetable[-super->index] != NULL)); + * + * superclass is a class: + * + * OK if ((sub == NULL) || (0 + * <= (sub->vftbl->baseval - super->vftbl->baseval) <= + * super->vftbl->diffvall)); + */ + + { + classinfo *super = (classinfo*) iptr->val.a; + + d = reg_of_var(iptr->dst, REG_ITMP3); + var_to_reg_int(s1, src, d); + if (iptr->op1) { /* class/interface */ + if (super->flags & ACC_INTERFACE) { /* interface */ + M_BEQZ(s1, 6); + M_ALD(REG_ITMP1, s1, OFFSET(java_objectheader, vftbl)); + M_ILD(REG_ITMP2, REG_ITMP1, OFFSET(vftbl, interfacetablelength)); + M_LDA(REG_ITMP2, REG_ITMP2, - super->index); + M_BLEZ(REG_ITMP2, 0); + mcode_addxcastrefs(mcodeptr); + M_ALD(REG_ITMP2, REG_ITMP1, + OFFSET(vftbl, interfacetable[0]) - + super->index * sizeof(methodptr*)); + M_BEQZ(REG_ITMP2, 0); + mcode_addxcastrefs(mcodeptr); + } + else { /* class */ + s2 = super->vftbl->diffval; + M_BEQZ(s1, 4 + (s2 != 0) + (s2 > 255)); + M_ALD(REG_ITMP1, s1, OFFSET(java_objectheader, vftbl)); + M_ILD(REG_ITMP1, REG_ITMP1, OFFSET(vftbl, baseval)); + M_LDA(REG_ITMP1, REG_ITMP1, - super->vftbl->baseval); + if (s2 == 0) { + M_BNEZ(REG_ITMP1, 0); + } + else if (s2 <= 255) { + M_CMPULE_IMM(REG_ITMP1, s2, REG_ITMP2); + M_BEQZ(REG_ITMP2, 0); + } + else { + M_LDA(REG_ITMP2, REG_ZERO, s2); + M_CMPULE(REG_ITMP1, REG_ITMP2, REG_ITMP2); + M_BEQZ(REG_ITMP2, 0); + } + mcode_addxcastrefs(mcodeptr); + } + } + else + panic ("internal error: no inlined array checkcast"); + } + M_INTMOVE(s1, d); + store_reg_to_var_int(iptr->dst, d); + break; + + case ICMD_CHECKASIZE: /* ..., size ==> ..., size */ + + var_to_reg_int(s1, src, REG_ITMP1); + M_BLTZ(s1, 0); + mcode_addxcheckarefs(mcodeptr); + break; + + case ICMD_MULTIANEWARRAY:/* ..., cnt1, [cnt2, ...] ==> ..., arrayref */ + /* op1 = dimension, val.a = array descriptor */ + + /* check for negative sizes and copy sizes to stack if necessary */ + + MCODECHECK((iptr->op1 << 1) + 64); + + for (s1 = iptr->op1; --s1 >= 0; src = src->prev) { + var_to_reg_int(s2, src, REG_ITMP1); + M_BLTZ(s2, 0); + mcode_addxcheckarefs(mcodeptr); + + /* copy sizes to stack (argument numbers >= INT_ARG_CNT) */ + + if (src->varkind != ARGVAR) { + M_LST(s2, REG_SP, 8 * (s1 + INT_ARG_CNT)); + } + } + + /* a0 = dimension count */ + + M_LDA(argintregs[0], REG_ZERO, iptr->op1); + + /* a1 = arraydescriptor */ + + a = dseg_addaddress(iptr->val.a); + M_ALD(argintregs[1], REG_PV, a); + + /* a2 = pointer to dimensions = stack pointer */ + + M_INTMOVE(REG_SP, argintregs[2]); + + a = dseg_addaddress((void*) (builtin_nmultianewarray)); + M_ALD(REG_PV, REG_PV, a); + M_JSR(REG_RA, REG_PV); + s1 = (int)((u1*) mcodeptr - mcodebase); + if (s1 <= 32768) + M_LDA (REG_PV, REG_RA, -s1); + else { + s4 ml = -s1, mh = 0; + while (ml < -32768) {ml += 65536; mh--;} + M_LDA(REG_PV, REG_RA, ml); + M_LDAH(REG_PV, REG_PV, mh); + } + s1 = reg_of_var(iptr->dst, REG_RESULT); + M_INTMOVE(REG_RESULT, s1); + store_reg_to_var_int(iptr->dst, s1); + break; + + + default: sprintf (logtext, "Unknown pseudo command: %d", iptr->opc); + error(); + } /* switch */ + } /* for instruction */ + + /* copy values to interface registers */ + + src = bptr->outstack; + len = bptr->outdepth; + MCODECHECK(64+len); + while (src) { + len--; + if ((src->varkind != STACKVAR)) { + s2 = src->type; + if (IS_FLT_DBL_TYPE(s2)) { + var_to_reg_flt(s1, src, REG_FTMP1); + if (!(interfaces[len][s2].flags & INMEMORY)) { + M_FLTMOVE(s1,interfaces[len][s2].regoff); + } + else { + M_DST(s1, REG_SP, 8 * interfaces[len][s2].regoff); + } + } + else { + var_to_reg_int(s1, src, REG_ITMP1); + if (!(interfaces[len][s2].flags & INMEMORY)) { + M_INTMOVE(s1,interfaces[len][s2].regoff); + } + else { + M_LST(s1, REG_SP, 8 * interfaces[len][s2].regoff); + } + } + } + src = src->prev; + } + } /* if (bptr -> flags >= BBREACHED) */ + } /* for basic block */ + + bptr -> mpc = (int)((u1*) mcodeptr - mcodebase); + + { + /* generate bound check stubs */ + + s4 *xcodeptr = NULL; + + for (; xboundrefs != NULL; xboundrefs = xboundrefs->next) { + if ((exceptiontablelength == 0) && (xcodeptr != NULL)) { + gen_resolvebranch((u1*) mcodebase + xboundrefs->branchpos, + xboundrefs->branchpos, (u1*) xcodeptr - (u1*) mcodebase - 4); + continue; + } + + gen_resolvebranch((u1*) mcodebase + xboundrefs->branchpos, + xboundrefs->branchpos, (u1*) mcodeptr - mcodebase); + + MCODECHECK(8); + + M_LDA(REG_ITMP2_XPC, REG_PV, xboundrefs->branchpos); + + if (xcodeptr != NULL) { + M_BR((xcodeptr-mcodeptr)-1); + } + else { + xcodeptr = mcodeptr; + + a = dseg_addaddress(proto_java_lang_ArrayIndexOutOfBoundsException); + M_ALD(REG_ITMP1_XPTR, REG_PV, a); + + a = dseg_addaddress(asm_handle_exception); + M_ALD(REG_ITMP3, REG_PV, a); + + M_JMP(REG_ITMP3); + } + } + + /* generate negative array size check stubs */ + + xcodeptr = NULL; + + for (; xcheckarefs != NULL; xcheckarefs = xcheckarefs->next) { + if ((exceptiontablelength == 0) && (xcodeptr != NULL)) { + gen_resolvebranch((u1*) mcodebase + xcheckarefs->branchpos, + xcheckarefs->branchpos, (u1*) xcodeptr - (u1*) mcodebase - 4); + continue; + } + + gen_resolvebranch((u1*) mcodebase + xcheckarefs->branchpos, + xcheckarefs->branchpos, (u1*) mcodeptr - mcodebase); + + MCODECHECK(8); + + M_LDA(REG_ITMP2_XPC, REG_PV, xcheckarefs->branchpos); + + if (xcodeptr != NULL) { + M_BR((xcodeptr-mcodeptr)-1); + } + else { + xcodeptr = mcodeptr; + + a = dseg_addaddress(proto_java_lang_NegativeArraySizeException); + M_ALD(REG_ITMP1_XPTR, REG_PV, a); + + a = dseg_addaddress(asm_handle_exception); + M_ALD(REG_ITMP3, REG_PV, a); + + M_JMP(REG_ITMP3); + } + } + + /* generate cast check stubs */ + + xcodeptr = NULL; + + for (; xcastrefs != NULL; xcastrefs = xcastrefs->next) { + if ((exceptiontablelength == 0) && (xcodeptr != NULL)) { + gen_resolvebranch((u1*) mcodebase + xcastrefs->branchpos, + xcastrefs->branchpos, (u1*) xcodeptr - (u1*) mcodebase - 4); + continue; + } + + gen_resolvebranch((u1*) mcodebase + xcastrefs->branchpos, + xcastrefs->branchpos, (u1*) mcodeptr - mcodebase); + + MCODECHECK(8); + + M_LDA(REG_ITMP2_XPC, REG_PV, xcastrefs->branchpos); + + if (xcodeptr != NULL) { + M_BR((xcodeptr-mcodeptr)-1); + } + else { + xcodeptr = mcodeptr; + + a = dseg_addaddress(proto_java_lang_ClassCastException); + M_ALD(REG_ITMP1_XPTR, REG_PV, a); + + a = dseg_addaddress(asm_handle_exception); + M_ALD(REG_ITMP3, REG_PV, a); + + M_JMP(REG_ITMP3); + } + } + + +#ifdef SOFTNULLPTRCHECK + + /* generate null pointer check stubs */ + + xcodeptr = NULL; + + for (; xnullrefs != NULL; xnullrefs = xnullrefs->next) { + if ((exceptiontablelength == 0) && (xcodeptr != NULL)) { + gen_resolvebranch((u1*) mcodebase + xnullrefs->branchpos, + xnullrefs->branchpos, (u1*) xcodeptr - (u1*) mcodebase - 4); + continue; + } + + gen_resolvebranch((u1*) mcodebase + xnullrefs->branchpos, + xnullrefs->branchpos, (u1*) mcodeptr - mcodebase); + + MCODECHECK(8); + + M_LDA(REG_ITMP2_XPC, REG_PV, xnullrefs->branchpos - 4); + + if (xcodeptr != NULL) { + M_BR((xcodeptr-mcodeptr)-1); + } + else { + xcodeptr = mcodeptr; + + a = dseg_addaddress(proto_java_lang_NullPointerException); + M_ALD(REG_ITMP1_XPTR, REG_PV, a); + + a = dseg_addaddress(asm_handle_exception); + M_ALD(REG_ITMP3, REG_PV, a); + + M_JMP(REG_ITMP3); + } + } + +#endif + } + + mcode_finish((int)((u1*) mcodeptr - mcodebase)); +} + + +/* redefinition of code generation macros (compiling into array) **************/ + +/* +These macros are newly defined to allow code generation into an array. +This is necessary, because the original M_.. macros generate code by +calling 'mcode_adds4' that uses an additional data structure to +receive the code. + +For a faster (but less flexible) version to generate code, these +macros directly use the (s4* p) - pointer to put the code directly +in a locally defined array. +This makes sense only for the stub-generation-routines below. +*/ + +#undef M_OP3 +#define M_OP3(op,fu,a,b,c,const) \ + *(p++) = ( (((s4)(op))<<26)|((a)<<21)|((b)<<(16-3*(const)))| \ + ((const)<<12)|((fu)<<5)|((c)) ) +#undef M_FOP3 +#define M_FOP3(op,fu,a,b,c) \ + *(p++) = ( (((s4)(op))<<26)|((a)<<21)|((b)<<16)|((fu)<<5)|(c) ) +#undef M_BRA +#define M_BRA(op,a,disp) \ + *(p++) = ( (((s4)(op))<<26)|((a)<<21)|((disp)&0x1fffff) ) +#undef M_MEM +#define M_MEM(op,a,b,disp) \ + *(p++) = ( (((s4)(op))<<26)|((a)<<21)|((b)<<16)|((disp)&0xffff) ) + + +/* function createcompilerstub ************************************************* + + creates a stub routine which calls the compiler + +*******************************************************************************/ + +#define COMPSTUBSIZE 3 + +u1 *createcompilerstub (methodinfo *m) +{ + u8 *s = CNEW (u8, COMPSTUBSIZE); /* memory to hold the stub */ + s4 *p = (s4*) s; /* code generation pointer */ + + /* code for the stub */ + M_ALD (REG_PV, REG_PV, 16); /* load pointer to the compiler */ + M_JSR (0, REG_PV); /* jump to the compiler, return address + in reg 0 is used as method pointer */ + s[1] = (u8) m; /* literals to be adressed */ + s[2] = (u8) asm_call_jit_compiler; /* jump directly via PV from above */ + +#ifdef STATISTICS + count_cstub_len += COMPSTUBSIZE * 8; +#endif + + return (u1*) s; +} + + +/* function removecompilerstub ************************************************* + + deletes a compilerstub from memory (simply by freeing it) + +*******************************************************************************/ + +void removecompilerstub (u1 *stub) +{ + CFREE (stub, COMPSTUBSIZE * 8); +} + + +/* function: createnativestub ************************************************** + + creates a stub routine which calls a native method + +*******************************************************************************/ + +#define NATIVESTUBSIZE 11 + +u1 *createnativestub (functionptr f, methodinfo *m) +{ + u8 *s = CNEW (u8, NATIVESTUBSIZE); /* memory to hold the stub */ + s4 *p = (s4*) s; /* code generation pointer */ + + M_LDA (REG_SP, REG_SP, -8); /* build up stackframe */ + M_AST (REG_RA, REG_SP, 0); /* store return address */ + + M_ALD (REG_PV, REG_PV, 8*8); /* load adress of native method */ + M_JSR (REG_RA, REG_PV); /* call native method */ + + M_LDA (REG_PV, REG_RA, -4*4); /* recompute pv from ra */ + M_ALD (REG_ITMP3, REG_PV, 9*8); /* get address of exceptionptr */ + + M_ALD (REG_RA, REG_SP, 0); /* load return address */ + M_ALD (REG_ITMP1, REG_ITMP3, 0); /* load exception into reg. itmp1 */ + + M_LDA (REG_SP, REG_SP, 8); /* remove stackframe */ + M_BNEZ (REG_ITMP1, 1); /* if no exception then return */ + + M_RET (REG_RA); /* return to caller */ + + M_AST (REG_ZERO, REG_ITMP3, 0); /* store NULL into exceptionptr */ + M_LDA (REG_ITMP2, REG_RA, -4); /* move fault address into reg. itmp2 */ + + M_ALD (REG_ITMP3, REG_PV,10*8); /* load asm exception handler address */ + M_JMP (REG_ITMP3); /* jump to asm exception handler */ + + + s[8] = (u8) f; /* address of native method */ + s[9] = (u8) (&exceptionptr); /* address of exceptionptr */ + s[10]= (u8) (asm_handle_nat_exception); /* addr of asm exception handler */ + +#ifdef STATISTICS + count_nstub_len += NATIVESTUBSIZE * 8; +#endif + + return (u1*) s; +} + + +/* function: removenativestub ************************************************** + + removes a previously created native-stub from memory + +*******************************************************************************/ + +void removenativestub (u1 *stub) +{ + CFREE (stub, NATIVESTUBSIZE * 8); +} + + +/* + * These are local overrides for various environment variables in Emacs. + * Please do not remove this and leave it at the end of the file, where + * Emacs will automagically detect them. + * --------------------------------------------------------------------- + * Local variables: + * mode: c + * indent-tabs-mode: t + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff --git a/mips/ngen.h b/mips/ngen.h new file mode 100644 index 000000000..9f525be53 --- /dev/null +++ b/mips/ngen.h @@ -0,0 +1,390 @@ +/* mips/ngen.h ***************************************************************** + + Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + + See file COPYRIGHT for information on usage and disclaimer of warranties + + Contains the machine dependent code generator definitions and macros for an + Alpha processor. + + Authors: Andreas Krall EMAIL: cacao@complang.tuwien.ac.at + + Last Change: 1998/11/12 + +*******************************************************************************/ + +/* see also file calling.doc for explanation of calling conventions */ + +/* preallocated registers *****************************************************/ + +/* integer registers */ + +#define REG_ZERO 0 /* allways zero */ + +#define REG_RESULT 2 /* to deliver method results */ + +#define REG_ITMP1 1 /* temporary register */ +#define REG_ITMP2 3 /* temporary register and method pointer */ +#define REG_ITMP3 24 /* temporary register */ + +#define REG_RA 31 /* return address */ +#define REG_SP 29 /* stack pointer */ + +#define REG_PV 25 /* procedure vector, must be provided by caller */ +#define REG_METHODPTR 24 /* pointer to the place from where the procedure */ + /* vector has been fetched */ +#define REG_ITMP1_XPTR 1 /* exception pointer = temporary register 1 */ +#define REG_ITMP2_XPC 3 /* exception pc = temporary register 2 */ + +/* floating point registers */ + +#define REG_FRESULT 0 /* to deliver floating point method results */ +#define REG_FTMP1 1 /* temporary floating point register */ +#define REG_FTMP2 2 /* temporary floating point register */ +#define REG_FTMP3 3 /* temporary floating point register */ + +#define REG_IFTMP 1 /* temporary integer and floating point register */ + +/* register descripton - array ************************************************/ + +/* #define REG_RES 0 reserved register for OS or code generator */ +/* #define REG_RET 1 return value register */ +/* #define REG_EXC 2 exception value register (only old jit) */ +/* #define REG_SAV 3 (callee) saved register */ +/* #define REG_TMP 4 scratch temporary register (caller saved) */ +/* #define REG_ARG 5 argument register (caller saved) */ + +/* #define REG_END -1 last entry in tables */ + +int nregdescint[] = { + REG_RES, REG_RES, REG_RET, REG_RES, REG_ARG, REG_ARG, REG_ARG, REG_ARG, + REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_TMP, REG_TMP, REG_TMP, REG_TMP, + REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, + REG_RES, REG_RES, REG_RES, REG_RES, REG_SAV, REG_RES, REG_SAV, REG_RES, + REG_END }; + +#define INT_SAV_CNT 10 /* number of int callee saved registers */ +#define INT_ARG_CNT 8 /* number of int argument registers */ + +/* for use of reserved registers, see comment above */ + +int nregdescfloat[] = { + REG_RET, REG_RES, REG_RES, REG_RES, REG_TMP, REG_TMP, REG_TMP, REG_TMP, + REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_ARG, REG_ARG, REG_ARG, REG_ARG, + REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_TMP, REG_TMP, REG_TMP, REG_TMP, + REG_SAV, REG_TMP, REG_SAV, REG_TMP, REG_SAV, REG_TMP, REG_SAV, REG_TMP, + REG_END }; + +#define FLT_SAV_CNT 4 /* number of flt callee saved registers */ +#define FLT_ARG_CNT 8 /* number of flt argument registers */ + +/* for use of reserved registers, see comment above */ + + +/* parameter allocation mode */ + +int nreg_parammode = PARAMMODE_NUMBERED; + + /* parameter-registers will be allocated by assigning the + 1. parameter: int/float-reg a0 + 2. parameter: int/float-reg a1 + 3. parameter: int/float-reg a2 .... + */ + + +/* stackframe-infos ***********************************************************/ + +int parentargs_base; /* offset in stackframe for the parameter from the caller*/ + +/* -> see file 'calling.doc' */ + + +/* macros to create code ******************************************************/ + +/* code generation macros operands: + op ..... opcode + fu ..... function-number + rs ..... register number source 1 + rt ..... register number or constant integer source 2 + rd ..... register number destination + imm .... immediate/offset + sa ..... shift amount +*/ + + +#define M_ITYPE(op, rs, rt, imm)\ + *(mcodeptr++) = (((op)<<26)|((rs)<<21)|((rt)<<16)|((off)&0xffff)) + +#define M_JTYPE(op, imm)\ + *(mcodeptr++) = (((op)<<26)|((off)&0x3ffffff)) + +#define M_RTYPE(op, rs, rt, rd, sa, fu)\ + *(mcodeptr++) = (((op)<<26)|((rs)<<21)|((rt)<<16)|((rd)<<11)|((sa)<<6)|(fu) + +#define M_FP2(fu, fmt, fs, fd) M_RTYPE(0x11, fmt, 0, fs, fd, fu) +#define M_FP3(fu, fmt, fs, ft, fd) M_RTYPE(0x11, fmt, ft, fs, fd, fu) + +#define FMT_F 16 +#define FMT_D 17 +#define FMT_I 20 +#define FMT_L 21 + +/* macros for all used commands (see a MIPS-manual for description) ***********/ + +/* load/store macros use the form OPERATION(source/dest, base, offset) */ + +#define M_BLDS(a,b,disp) M_ITYPE(0x20,b,a,disp) /* 8 load */ +#define M_BLDU(a,b,disp) M_ITYPE(0x24,b,a,disp) /* 8 load */ +#define M_SLDS(a,b,disp) M_ITYPE(0x21,b,a,disp) /* 16 load */ +#define M_SLDU(a,b,disp) M_ITYPE(0x25,b,a,disp) /* 16 load */ +#define M_ILD(a,b,disp) M_ITYPE(0x23,b,a,disp) /* 32 load */ +#define M_LLD(a,b,disp) M_ITYPE(0x37,b,a,disp) /* 64 load */ +#define M_BST(a,b,disp) M_ITYPE(0x28,b,a,disp) /* 8 store */ +#define M_SST(a,b,disp) M_ITYPE(0x29,b,a,disp) /* 16 store */ +#define M_IST(a,b,disp) M_ITYPE(0x2b,b,a,disp) /* 32 store */ +#define M_LST(a,b,disp) M_ITYPE(0x3f,b,a,disp) /* 64 store */ + +#define M_FLD(a,b,disp) M_ITYPE(0x31,b,a,disp) /* load flt */ +#define M_DLD(a,b,disp) M_ITYPE(0x35,b,a,disp) /* load dbl */ +#define M_FST(a,b,disp) M_ITYPE(0x39,b,a,disp) /* store flt */ +#define M_DST(a,b,disp) M_ITYPE(0x3d,b,a,disp) /* store dbl */ + +/* + * Load Address pseudo instruction: + * -n32 addressing mode -> 32 bit addrs, -64 addressing mode -> 64 bit addrs + */ +#if POINTERSIZE==8 +#define POINTERSHIFT 3 +#define M_ALD(a,b,disp) M_LLD(a,b,disp) +#define M_AST(a,b,disp) M_LST(a,b,disp) +#else +#define POINTERSHIFT 2 +#define M_ALD(a,b,disp) M_ILD(a,b,disp) +#define M_AST(a,b,disp) M_IST(a,b,disp) +#endif + +#define M_BEQ(a,b,disp) M_ITYPE(0x04,a,b,disp) /* br a == b */ +#define M_BNE(a,b,disp) M_ITYPE(0x05,a,b,disp) /* br a != b */ +#define M_BEQZ(a,disp) M_ITYPE(0x04,a,0,disp) /* br a == 0 */ +#define M_BLTZ(a,disp) M_ITYPE(0x01,a,0,disp) /* br a < 0 */ +#define M_BLEZ(a,disp) M_ITYPE(0x06,a,0,disp) /* br a <= 0 */ +#define M_BNEZ(a,disp) M_ITYPE(0x05,a,0,disp) /* br a != 0 */ +#define M_BGEZ(a,disp) M_ITYPE(0x01,a,1,disp) /* br a >= 0 */ +#define M_BGTZ(a,disp) M_ITYPE(0x07,a,0,disp) /* br a > 0 */ + +#define M_BEQL(a,b,disp) M_ITYPE(0x14,a,b,disp) /* br a == b */ +#define M_BNEL(a,b,disp) M_ITYPE(0x15,a,b,disp) /* br a != b */ +#define M_BEQZL(a,disp) M_ITYPE(0x14,a,0,disp) /* br a == 0 */ +#define M_BLTZL(a,disp) M_ITYPE(0x01,a,2,disp) /* br a < 0 */ +#define M_BLEZL(a,disp) M_ITYPE(0x16,a,0,disp) /* br a <= 0 */ +#define M_BNEZL(a,disp) M_ITYPE(0x15,a,0,disp) /* br a != 0 */ +#define M_BGEZL(a,disp) M_ITYPE(0x01,a,3,disp) /* br a >= 0 */ +#define M_BGTZL(a,disp) M_ITYPE(0x17,a,0,disp) /* br a > 0 */ + +#define M_BR(disp) M_ITYPE(0x04,0,0,disp) /* branch */ + +#define M_JMP(a) M_RTYPE(0,a,0,0,0,0x08) /* jump */ +#define M_JSR(r,a) M_RTYPE(0,a,0,r,0,0x09) /* call */ +#define M_RET(a) M_RTYPE(0,a,0,0,0,0x08) /* return */ + +#define M_TGE(a,b,code) M_RTYPE(0,a,b,0,code&3ff,0x30) /* trp a >= b */ +#define M_TGEU(a,b,code) M_RTYPE(0,a,b,0,code&3ff,0x31) /* trp a >= b */ +#define M_TLT(a,b,code) M_RTYPE(0,a,b,0,code&3ff,0x32) /* trp a < b */ +#define M_TLTU(a,b,code) M_RTYPE(0,a,b,0,code&3ff,0x33) /* trp a < b */ +#define M_TEQ(a,b,code) M_RTYPE(0,a,b,0,code&3ff,0x34) /* trp a == b */ +#define M_TNE(a,b,code) M_RTYPE(0,a,b,0,code&3ff,0x36) /* trp a != b */ +#define M_TLE(a,b,code) M_RTYPE(0,b,a,0,code&3ff,0x30) /* trp a <= b */ +#define M_TLEU(a,b,code) M_RTYPE(0,b,a,0,code&3ff,0x31) /* trp a <= b */ +#define M_TGT(a,b,code) M_RTYPE(0,b,a,0,code&3ff,0x32) /* trp a > b */ +#define M_TGTU(a,b,code) M_RTYPE(0,b,a,0,code&3ff,0x33) /* trp a > b */ + +#define M_TGE_IMM(a,b) M_ITYPE(1,a,0x08,b) /* trp a >= b */ +#define M_TGEU_IMM(a,b) M_ITYPE(1,a,0x09,b) /* trp a >= b */ +#define M_TLT_IMM(a,b) M_ITYPE(1,a,0x0a,b) /* trp a < b */ +#define M_TLTU_IMM(a,b) M_ITYPE(1,a,0x0b,b) /* trp a < b */ +#define M_TEQ_IMM(a,b) M_ITYPE(1,a,0x0c,b) /* trp a == b */ +#define M_TNE_IMM(a,b) M_ITYPE(1,a,0x0e,b) /* trp a != b */ +#if 0 +#define M_TGT_IMM(a,b) M_ITYPE(1,a,0x08,b+1) /* trp a > b */ +#define M_TGTU_IMM(a,b) M_ITYPE(1,a,0x09,b+1) /* trp a > b */ +#define M_TLE_IMM(a,b) M_ITYPE(1,a,0x0a,b+1) /* trp a <= b */ +#define M_TLEU_IMM(a,b) M_ITYPE(1,a,0x0b,b+1) /* trp a <= b */ +#endif + +/* arithmetic macros use the form OPERATION(source, source/immediate, dest) */ + +#define M_IADD(a,b,c) M_RTYPE(0,a,b,c,0,0x21) /* 32 add */ +#define M_LADD(a,b,c) M_RTYPE(0,a,b,c,0,0x2d) /* 64 add */ +#define M_ISUB(a,b,c) M_RTYPE(0,a,b,c,0,0x23) /* 32 sub */ +#define M_LSUB(a,b,c) M_RTYPE(0,a,b,c,0,0x2f) /* 64 sub */ +#define M_IMUL(a,b) M_ITYPE(0,a,b,0x18) /* 32 mul */ +#define M_LMUL(a,b) M_ITYPE(0,a,b,0x1c) /* 64 mul */ +#define M_IDIV(a,b) M_ITYPE(0,a,b,0x1b) /* 32 div */ +#define M_LDIV(a,b) M_ITYPE(0,a,b,0x1e) /* 64 div */ + +#define M_MFLO(a) M_RTYPE(0,0,0,a,0,0x12) /* quotient */ +#define M_MFHI(a) M_RTYPE(0,0,0,a,0,0x10) /* remainder */ + +#define M_IADD_IMM(a,b,c) M_ITYPE(0x08,a,c,b) /* 32 add */ +#define M_LADD_IMM(a,b,c) M_ITYPE(0x18,a,c,b) /* 64 add */ +#define M_ISUB_IMM(a,b,c) M_ITYPE(0x08,a,c,-(b)) /* 32 sub */ +#define M_LSUB_IMM(a,b,c) M_ITYPE(0x18,a,c,-(b)) /* 64 sub */ + +#define M_LDA(a,b,disp) M_LADD_IMM(b,disp,a) /* a = b+disp */ + +#define M_CMPLT(a,b,c) M_RTYPE(0,a,b,c,0,0x2a) /* c = a < b */ +#define M_CMPGT(a,b,c) M_RTYPE(0,b,a,c,0,0x2a) /* c = a > b */ + +#define M_CMPULT(a,b,c) M_RTYPE(0,a,b,c,0,0x2b) /* c = a < b */ +#define M_CMPUGT(a,b,c) M_RTYPE(0,b,a,c,0,0x2b) /* c = a > b */ + +#define M_CMPLT_IMM(a,b,c) M_ITYPE(0x0a,a,c,b) /* c = a < b */ +#define M_CMPULT_IMM(a,b,c) M_ITYPE(0x0b,a,c,b) /* c = a < b */ + +#define M_AND(a,b,c) M_RTYPE(0,a,b,c,0,0x24) /* c = a & b */ +#define M_OR( a,b,c) M_RTYPE(0,a,b,c,0,0x25) /* c = a | b */ +#define M_XOR(a,b,c) M_RTYPE(0,a,b,c,0,0x26) /* c = a ^ b */ + +#define M_AND_IMM(a,b,c) M_ITYPE(0x0c,a,c,b) /* c = a & b */ +#define M_OR_IMM( a,b,c) M_ITYPE(0x0d,a,c,b) /* c = a | b */ +#define M_XOR_IMM(a,b,c) M_ITYPE(0x0e,a,c,b) /* c = a ^ b */ + +#define M_MOV(a,c) M_OR(a,a,c) /* c = a */ +#define M_CLR(c) M_OR(0,0,c) /* c = 0 */ +#define M_NOP M_OR(0,0,0) /* ; */ + +#define M_ISLL(a,b,c) M_RTYPE(0,b,a,c,0,0x04) /* c = a << b */ +#define M_ISRL(a,b,c) M_RTYPE(0,b,a,c,0,0x06) /* c = a >>>b */ +#define M_ISRA(a,b,c) M_RTYPE(0,b,a,c,0,0x07) /* c = a >> b */ +#define M_LSLL(a,b,c) M_RTYPE(0,b,a,c,0,0x14) /* c = a << b */ +#define M_LSRL(a,b,c) M_RTYPE(0,b,a,c,0,0x16) /* c = a >>>b */ +#define M_LSRA(a,b,c) M_RTYPE(0,b,a,c,0,0x17) /* c = a >> b */ + +#define M_ISLL_IMM(a,b,c) M_RTYPE(0,0,a,c,b&1f,0x00) /* c = a << b */ +#define M_ISRL_IMM(a,b,c) M_RTYPE(0,0,a,c,b&1f,0x02) /* c = a >>>b */ +#define M_ISRA_IMM(a,b,c) M_RTYPE(0,0,a,c,b&1f,0x03) /* c = a >> b */ +#define M_LSLL_IMM(a,b,c) M_RTYPE(0,0,a,c,b&1f,0x38+4*(b&x020)) /* c = a << b */ +#define M_LSRL_IMM(a,b,c) M_RTYPE(0,0,a,c,b&1f,0x3a+4*(b&x020)) /* c = a >>>b */ +#define M_LSRA_IMM(a,b,c) M_RTYPE(0,0,a,c,b&1f,0x3b+4*(b&x020)) /* c = a >> b */ + +/* floating point macros use the form OPERATION(source, source, dest) */ + +#define M_FADD(a,b,c) M_FP3(0x00,FMT_F,a,b,c) /* flt add */ +#define M_DADD(a,b,c) M_FP3(0x00,FMT_D,a,b,c) /* dbl add */ +#define M_FSUB(a,b,c) M_FP3(0x01,FMT_F,a,b,c) /* flt sub */ +#define M_DSUB(a,b,c) M_FP3(0x01,FMT_D,a,b,c) /* dbl sub */ +#define M_FMUL(a,b,c) M_FP3(0x02,FMT_F,a,b,c) /* flt mul */ +#define M_DMUL(a,b,c) M_FP3(0x02,FMT_D,a,b,c) /* dbl mul */ +#define M_FDIV(a,b,c) M_FP3(0x03,FMT_F,a,b,c) /* flt div */ +#define M_DDIV(a,b,c) M_FP3(0x03,FMT_D,a,b,c) /* dbl div */ + +#define M_FSQRT(a,c) M_FP2(0x04,FMT_F,a,c) /* flt sqrt */ +#define M_DSQRT(a,c) M_FP2(0x04,FMT_D,a,c) /* dbl sqrt */ +#define M_FABS(a,c) M_FP2(0x05,FMT_F,a,c) /* flt abs */ +#define M_DABS(a,c) M_FP2(0x05,FMT_D,a,c) /* dbl abs */ +#define M_FMOV(a,c) M_FP2(0x06,FMT_F,a,c) /* flt mov */ +#define M_DMOV(a,c) M_FP2(0x06,FMT_D,a,c) /* dbl mov */ +#define M_FNEG(a,c) M_FP2(0x07,FMT_F,a,c) /* flt neg */ +#define M_DNEG(a,c) M_FP2(0x07,FMT_D,a,c) /* dbl neg */ + +#define M_ROUNDFI(a,c) M_FP2(0x0c,FMT_F,a,c) /* flt roundi */ +#define M_ROUNDDI(a,c) M_FP2(0x0c,FMT_D,a,c) /* dbl roundi */ +#define M_TRUNCFI(a,c) M_FP2(0x0d,FMT_F,a,c) /* flt trunci */ +#define M_TRUNCDI(a,c) M_FP2(0x0d,FMT_D,a,c) /* dbl trunci */ +#define M_CEILFI(a,c) M_FP2(0x0e,FMT_F,a,c) /* flt ceili */ +#define M_CEILDI(a,c) M_FP2(0x0e,FMT_D,a,c) /* dbl ceili */ +#define M_FLOORFI(a,c) M_FP2(0x0f,FMT_F,a,c) /* flt trunci */ +#define M_FLOORDI(a,c) M_FP2(0x0f,FMT_D,a,c) /* dbl trunci */ + +#define M_ROUNDFL(a,c) M_FP2(0x08,FMT_F,a,c) /* flt roundl */ +#define M_ROUNDDL(a,c) M_FP2(0x08,FMT_D,a,c) /* dbl roundl */ +#define M_TRUNCFL(a,c) M_FP2(0x09,FMT_F,a,c) /* flt truncl */ +#define M_TRUNCDL(a,c) M_FP2(0x09,FMT_D,a,c) /* dbl truncl */ +#define M_CEILFL(a,c) M_FP2(0x0a,FMT_F,a,c) /* flt ceill */ +#define M_CEILDL(a,c) M_FP2(0x0a,FMT_D,a,c) /* dbl ceill */ +#define M_FLOORFL(a,c) M_FP2(0x0b,FMT_F,a,c) /* flt truncl */ +#define M_FLOORDL(a,c) M_FP2(0x0b,FMT_D,a,c) /* dbl truncl */ + +#define M_CVTDF(b,c) M_FP2(0x20,FMT_D,a,c) /* dbl2flt */ +#define M_CVTIF(b,c) M_FP2(0x20,FMT_I,a,c) /* int2flt */ +#define M_CVTLF(b,c) M_FP2(0x20,FMT_L,a,c) /* long2flt */ +#define M_CVTFD(b,c) M_FP2(0x21,FMT_F,a,c) /* flt2dbl */ +#define M_CVTID(b,c) M_FP2(0x21,FMT_I,a,c) /* int2dbl */ +#define M_CVTLD(b,c) M_FP2(0x21,FMT_L,a,c) /* long2dbl */ +#define M_CVTFI(b,c) M_FP2(0x24,FMT_F,a,c) /* flt2int */ +#define M_CVTDI(b,c) M_FP2(0x24,FMT_D,a,c) /* dbl2int */ +#define M_CVTFL(b,c) M_FP2(0x25,FMT_F,a,c) /* flt2long */ +#define M_CVTDL(b,c) M_FP2(0x25,FMT_D,a,c) /* dbl2long */ + +#define M_MOVDL(d,l) M_FP3(0,1,l,d,0) /* l = d */ +#define M_MOVLD(l,d) M_FP3(0,5,l,d,0) /* d = l */ + +#define M_FCMPFF(a,b) M_FP3(0x30,FMT_F,a,b,0) /* c = a == b */ +#define M_FCMPFD(a,b) M_FP3(0x30,FMT_D,a,b,0) /* c = a == b */ +#define M_FCMPUNF(a,b) M_FP3(0x30,FMT_F,a,b,0) /* c = a == b */ +#define M_FCMPUND(a,b) M_FP3(0x30,FMT_D,a,b,0) /* c = a == b */ +#define M_FCMPEQF(a,b) M_FP3(0x30,FMT_F,a,b,0) /* c = a == b */ +#define M_FCMPEQD(a,b) M_FP3(0x30,FMT_D,a,b,0) /* c = a == b */ +#define M_FCMPUEQF(a,b) M_FP3(0x30,FMT_F,a,b,0) /* c = a == b */ +#define M_FCMPUEQD(a,b) M_FP3(0x30,FMT_D,a,b,0) /* c = a == b */ +#define M_FCMPOLTF(a,b) M_FP3(0x30,FMT_F,a,b,0) /* c = a < b */ +#define M_FCMPOLTD(a,b) M_FP3(0x30,FMT_D,a,b,0) /* c = a < b */ +#define M_FCMPULTF(a,b) M_FP3(0x30,FMT_F,a,b,0) /* c = a < b */ +#define M_FCMPULTD(a,b) M_FP3(0x30,FMT_D,a,b,0) /* c = a < b */ +#define M_FCMPOLEF(a,b) M_FP3(0x30,FMT_F,a,b,0) /* c = a <= b */ +#define M_FCMPOLED(a,b) M_FP3(0x30,FMT_D,a,b,0) /* c = a <= b */ +#define M_FCMPULEF(a,b) M_FP3(0x30,FMT_F,a,b,0) /* c = a <= b */ +#define M_FCMPULE(a,b) M_FP3(0x30,FMT_D,a,b,0) /* c = a <= b */ + +#define M_FBF(disp) M_ITYPE(0x11,8,0,disp) /* br false */ +#define M_FBT(disp) M_ITYPE(0x11,8,1,disp) /* br true */ +#define M_FBFL(disp) M_ITYPE(0x11,8,2,disp) /* br false */ +#define M_FBTL(disp) M_ITYPE(0x11,8,3,disp) /* br true */ + +/* macros for special commands (see an Alpha-manual for description) **********/ + +#if 0 +#define M_CMOVEQ(a,b,c) M_OP3 (0x11,0x24, a,b,c,0) /* a==0 ? c=b */ +#define M_CMOVNE(a,b,c) M_OP3 (0x11,0x26, a,b,c,0) /* a!=0 ? c=b */ +#define M_CMOVLT(a,b,c) M_OP3 (0x11,0x44, a,b,c,0) /* a< 0 ? c=b */ +#define M_CMOVGE(a,b,c) M_OP3 (0x11,0x46, a,b,c,0) /* a>=0 ? c=b */ +#define M_CMOVLE(a,b,c) M_OP3 (0x11,0x64, a,b,c,0) /* a<=0 ? c=b */ +#define M_CMOVGT(a,b,c) M_OP3 (0x11,0x66, a,b,c,0) /* a> 0 ? c=b */ + +#define M_CMOVEQ_IMM(a,b,c) M_OP3 (0x11,0x24, a,b,c,1) /* a==0 ? c=b */ +#define M_CMOVNE_IMM(a,b,c) M_OP3 (0x11,0x26, a,b,c,1) /* a!=0 ? c=b */ +#define M_CMOVLT_IMM(a,b,c) M_OP3 (0x11,0x44, a,b,c,1) /* a< 0 ? c=b */ +#define M_CMOVGE_IMM(a,b,c) M_OP3 (0x11,0x46, a,b,c,1) /* a>=0 ? c=b */ +#define M_CMOVLE_IMM(a,b,c) M_OP3 (0x11,0x64, a,b,c,1) /* a<=0 ? c=b */ +#define M_CMOVGT_IMM(a,b,c) M_OP3 (0x11,0x66, a,b,c,1) /* a> 0 ? c=b */ +#endif + +/* function gen_resolvebranch ************************************************** + + backpatches a branch instruction; MIPS branch instructions are very + regular, so it is only necessary to overwrite some fixed bits in the + instruction. + + parameters: ip ... pointer to instruction after branch (void*) + so ... offset of instruction after branch (s4) + to ... offset of branch target (s4) + +*******************************************************************************/ + +#define gen_resolvebranch(ip,so,to) ((s4*)(ip))[-1]|=((s4)(to)-(so))>>2&0xffff + +#define SOFTNULLPTRCHECK /* soft null pointer check supportet as option */ + + +/* + * These are local overrides for various environment variables in Emacs. + * Please do not remove this and leave it at the end of the file, where + * Emacs will automagically detect them. + * --------------------------------------------------------------------- + * Local variables: + * mode: c + * indent-tabs-mode: t + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ -- 2.25.1