--- /dev/null
+/* 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:
+ */
--- /dev/null
+/* 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 <asm/fpu.h>
+
+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:
+ */
--- /dev/null
+/* 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:
+ */