q3rally/engine/code/qcommon/vm_sparc.c

1671 lines
43 KiB
C
Raw Normal View History

2011-02-18 14:31:32 +00:00
/*
===========================================================================
Copyright (C) 2009 David S. Miller <davem@davemloft.net>
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
/* This code is based almost entirely upon the vm_powerpc.c code by
* Przemyslaw Iskra. All I did was make it work on Sparc :-) -DaveM
*/
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <time.h>
#include <stddef.h>
#include "vm_local.h"
#include "vm_sparc.h"
/* exit() won't be called but use it because it is marked with noreturn */
#define DIE( reason ) \
do { \
Com_Error(ERR_DROP, "vm_sparc compiler error: " reason); \
2011-02-18 14:31:32 +00:00
exit(1); \
} while(0)
/* Select Length - first value on 32 bits, second on 64 */
#ifdef __arch64__
#define SL(a, b) (b)
#else
#define SL(a, b) (a)
#endif
#define rTMP G1
#define rVMDATA G2
#define rPSTACK G3
#define rDATABASE G4
#define rDATAMASK G5
struct sparc_opcode {
const char *name;
unsigned int opcode;
unsigned int mask;
unsigned char args[4];
#define ARG_NONE 0
#define ARG_RS1 1
#define ARG_RS2 2
#define ARG_RD 3
#define ARG_SIMM13 4
#define ARG_DISP30 5
#define ARG_IMM22 6
#define ARG_DISP22 7
#define ARG_SWTRAP 8
};
#define ARG_RS1_RS2_RD { ARG_RS1, ARG_RS2, ARG_RD }
#define ARG_RS1_SIMM13_RD { ARG_RS1, ARG_SIMM13, ARG_RD }
#define ARG_RS1_RS2 { ARG_RS1, ARG_RS2 }
#define ARG_RS2_RD { ARG_RS2, ARG_RD }
#define OP_MASK 0xc0000000
#define OP2_MASK 0x01c00000
#define OP3_MASK 0x01f80000
#define OPF_MASK 0x00003fe0
#define IMM 0x00002000
#define FMT1(op) ((op) << 30), OP_MASK
#define FMT2(op,op2) ((op) << 30)|((op2)<<22), (OP_MASK | OP2_MASK)
#define FMT3(op,op3) ((op) << 30)|((op3)<<19), (OP_MASK | OP3_MASK | IMM)
#define FMT3I(op,op3) ((op) << 30)|((op3)<<19)|IMM, (OP_MASK | OP3_MASK | IMM)
#define FMT3F(op,op3,opf) ((op) << 30)|((op3)<<19)|((opf)<<5), \
(OP_MASK | OP3_MASK | OPF_MASK)
#define BICC(A,COND) FMT2(0,((A<<7)|(COND<<3)|0x2))
#define BFCC(A,COND) FMT2(0,((A<<7)|(COND<<3)|0x6))
#define TICC(COND) FMT3I(0,((COND<<6)|0x3a))
enum sparc_iname {
CALL, NOP, SETHI,
BA, BN, BNE, BE, BG, BLE, BGE, BL, BGU, BLEU, BCC, BCS,
BPOS, BNEG, BVC, BVS,
ADDI, ADD,
ANDI, AND,
ORI, OR,
XORI, XOR,
SUBI, SUB,
ANDNI, ANDN,
ORNI, ORN,
XNORI, XNOR,
UMULI, UMUL,
SMULI, SMUL,
UDIVI, UDIV,
SDIVI, SDIV,
SUBCCI, SUBCC,
SLLI, SLL,
SRLI, SRL,
SRAI, SRA,
WRI, WR,
SAVEI, SAVE,
RESTOREI, RESTORE,
TA,
JMPLI, JMPL,
LDXI, LDX,
LDUWI, LDUW,
LDUHI, LDUH,
LDUBI, LDUB,
STXI, STX,
STWI, STW,
STHI, STH,
STBI, STB,
LDFI, LDF,
STFI, STF,
FADD, FSUB, FCMP, FSTOI, FITOS, FNEG, FDIV, FMUL,
FBE, FBNE, FBL, FBGE, FBG, FBLE,
};
#define LDLI SL(LDUWI, LDXI)
#define LDL SL(LDUW, LDX)
#define STLI SL(STWI, STXI)
#define STL SL(STW, STX)
#define SPARC_NOP 0x01000000
static const struct sparc_opcode sparc_opcodes[] = {
{ "call", FMT1(1), { ARG_DISP30 }, },
{ "nop", SPARC_NOP, 0xffffffff, { ARG_NONE }, }, /* sethi %hi(0), %g0 */
{ "sethi", FMT2(0,4), { ARG_IMM22, ARG_RD }, },
{ "ba", BICC(0,8), { ARG_DISP22 }, },
{ "bn", BICC(0,0), { ARG_DISP22 }, },
{ "bne", BICC(0,9), { ARG_DISP22 }, },
{ "be", BICC(0,1), { ARG_DISP22 }, },
{ "bg", BICC(0,10), { ARG_DISP22 }, },
{ "ble", BICC(0,2), { ARG_DISP22 }, },
{ "bge", BICC(0,11), { ARG_DISP22 }, },
{ "bl", BICC(0,3), { ARG_DISP22 }, },
{ "bgu", BICC(0,12), { ARG_DISP22 }, },
{ "bleu", BICC(0,4), { ARG_DISP22 }, },
{ "bcc", BICC(0,13), { ARG_DISP22 }, },
{ "bcs", BICC(0,5), { ARG_DISP22 }, },
{ "bpos", BICC(0,14), { ARG_DISP22 }, },
{ "bneg", BICC(0,6), { ARG_DISP22 }, },
{ "bvc", BICC(0,15), { ARG_DISP22 }, },
{ "bvs", BICC(0,7), { ARG_DISP22 }, },
{ "add", FMT3I(2, 0x00), ARG_RS1_SIMM13_RD, },
{ "add", FMT3 (2, 0x00), ARG_RS1_RS2_RD, },
{ "and", FMT3I(2, 0x01), ARG_RS1_SIMM13_RD, },
{ "and", FMT3 (2, 0x01), ARG_RS1_RS2_RD, },
{ "or", FMT3I(2, 0x02), ARG_RS1_SIMM13_RD, },
{ "or", FMT3 (2, 0x02), ARG_RS1_RS2_RD, },
{ "xor", FMT3I(2, 0x03), ARG_RS1_SIMM13_RD, },
{ "xor", FMT3 (2, 0x03), ARG_RS1_RS2_RD, },
{ "sub", FMT3I(2, 0x04), ARG_RS1_SIMM13_RD, },
{ "sub", FMT3 (2, 0x04), ARG_RS1_RS2_RD, },
{ "andn", FMT3I(2, 0x05), ARG_RS1_SIMM13_RD, },
{ "andn", FMT3 (2, 0x05), ARG_RS1_RS2_RD, },
{ "orn", FMT3I(2, 0x06), ARG_RS1_SIMM13_RD, },
{ "orn", FMT3 (2, 0x06), ARG_RS1_RS2_RD, },
{ "xnor", FMT3I(2, 0x07), ARG_RS1_SIMM13_RD, },
{ "xnor", FMT3 (2, 0x07), ARG_RS1_RS2_RD, },
{ "umul", FMT3I(2, 0x0a), ARG_RS1_SIMM13_RD, },
{ "umul", FMT3 (2, 0x0a), ARG_RS1_RS2_RD, },
{ "smul", FMT3I(2, 0x0b), ARG_RS1_SIMM13_RD, },
{ "smul", FMT3 (2, 0x0b), ARG_RS1_RS2_RD, },
{ "udiv", FMT3I(2, 0x0e), ARG_RS1_SIMM13_RD, },
{ "udiv", FMT3 (2, 0x0e), ARG_RS1_RS2_RD, },
{ "sdiv", FMT3I(2, 0x0f), ARG_RS1_SIMM13_RD, },
{ "sdiv", FMT3 (2, 0x0f), ARG_RS1_RS2_RD, },
{ "subcc", FMT3I(2, 0x14), ARG_RS1_SIMM13_RD, },
{ "subcc", FMT3 (2, 0x14), ARG_RS1_RS2_RD, },
{ "sll", FMT3I(2, 0x25), ARG_RS1_SIMM13_RD, },
{ "sll", FMT3 (2, 0x25), ARG_RS1_RS2_RD, },
{ "srl", FMT3I(2, 0x26), ARG_RS1_SIMM13_RD, },
{ "srl", FMT3 (2, 0x26), ARG_RS1_RS2_RD, },
{ "sra", FMT3I(2, 0x27), ARG_RS1_SIMM13_RD, },
{ "sra", FMT3 (2, 0x27), ARG_RS1_RS2_RD, },
{ "wr", FMT3I(2, 0x30), ARG_RS1_SIMM13_RD, },
{ "wr", FMT3 (2, 0x30), ARG_RS1_SIMM13_RD, },
{ "save", FMT3I(2,0x3c), ARG_RS1_SIMM13_RD, },
{ "save", FMT3 (2,0x3c), ARG_RS1_RS2_RD, },
{ "restore", FMT3I(2,0x3d), ARG_RS1_SIMM13_RD, },
{ "restore", FMT3 (2,0x3d), ARG_RS1_RS2_RD, },
{ "ta", TICC(8), { ARG_SWTRAP, ARG_NONE }, },
{ "jmpl", FMT3I(2,0x38), ARG_RS1_SIMM13_RD, },
{ "jmpl", FMT3 (2,0x38), ARG_RS1_RS2_RD, },
{ "ldx", FMT3I(3,0x0b), ARG_RS1_SIMM13_RD, },
{ "ldx", FMT3 (3,0x0b), ARG_RS1_RS2_RD, },
{ "lduw", FMT3I(3,0x00), ARG_RS1_SIMM13_RD, },
{ "lduw", FMT3 (3,0x00), ARG_RS1_RS2_RD, },
{ "lduh", FMT3I(3,0x02), ARG_RS1_SIMM13_RD, },
{ "lduh", FMT3 (3,0x02), ARG_RS1_RS2_RD, },
{ "ldub", FMT3I(3,0x01), ARG_RS1_SIMM13_RD, },
{ "ldub", FMT3 (3,0x01), ARG_RS1_RS2_RD, },
{ "stx", FMT3I(3,0x0e), ARG_RS1_SIMM13_RD, },
{ "stx", FMT3 (3,0x0e), ARG_RS1_RS2_RD, },
{ "stw", FMT3I(3,0x04), ARG_RS1_SIMM13_RD, },
{ "stw", FMT3 (3,0x04), ARG_RS1_RS2_RD, },
{ "sth", FMT3I(3,0x06), ARG_RS1_SIMM13_RD, },
{ "sth", FMT3 (3,0x06), ARG_RS1_RS2_RD, },
{ "stb", FMT3I(3,0x05), ARG_RS1_SIMM13_RD, },
{ "stb", FMT3 (3,0x05), ARG_RS1_RS2_RD, },
{ "ldf", FMT3I(3,0x20), ARG_RS1_SIMM13_RD, },
{ "ldf", FMT3 (3,0x20), ARG_RS1_RS2_RD, },
{ "stf", FMT3I(3,0x24), ARG_RS1_SIMM13_RD, },
{ "stf", FMT3 (3,0x24), ARG_RS1_RS2_RD, },
{ "fadd", FMT3F(2,0x34,0x041), ARG_RS1_RS2_RD, },
{ "fsub", FMT3F(2,0x34,0x045), ARG_RS1_RS2_RD, },
{ "fcmp", FMT3F(2,0x35,0x051), ARG_RS1_RS2, },
{ "fstoi", FMT3F(2,0x34,0x0d1), ARG_RS2_RD, },
{ "fitos", FMT3F(2,0x34,0x0c4), ARG_RS2_RD, },
{ "fneg", FMT3F(2,0x34,0x005), ARG_RS2_RD, },
{ "fdiv", FMT3F(2,0x34,0x04d), ARG_RS1_RS2_RD, },
{ "fmul", FMT3F(2,0x34,0x049), ARG_RS1_RS2_RD, },
{ "fbe", BFCC(0,9), { ARG_DISP22 }, },
{ "fbne", BFCC(0,1), { ARG_DISP22 }, },
{ "fbl", BFCC(0,4), { ARG_DISP22 }, },
{ "fbge", BFCC(0,11), { ARG_DISP22 }, },
{ "fbg", BFCC(0,6), { ARG_DISP22 }, },
{ "fble", BFCC(0,13), { ARG_DISP22 }, },
};
#define SPARC_NUM_OPCODES (ARRAY_LEN(sparc_opcodes))
2011-02-18 14:31:32 +00:00
#define RS1(X) (((X) & 0x1f) << 14)
#define RS2(X) (((X) & 0x1f) << 0)
#define RD(X) (((X) & 0x1f) << 25)
#define SIMM13(X) (((X) & 0x1fff) << 0)
#define IMM22(X) (((X) & 0x3fffff) << 0)
#define DISP30(X) ((((X) >> 2) & 0x3fffffff) << 0)
#define DISP22(X) ((((X) >> 2) & 0x3fffff) << 0)
#define SWTRAP(X) (((X) & 0x7f) << 0)
#define SIMM13_P(X) ((unsigned int) (X) + 0x1000 < 0x2000)
static void vimm(unsigned int val, int bits, int shift, int sgned, int arg_index)
{
unsigned int orig_val = val;
int orig_bits = bits;
if (sgned) {
int x = (int) val;
if (x < 0)
x = -x;
val = (unsigned int) x;
bits--;
}
if (val & ~((1U << bits) - 1U)) {
Com_Printf("VM ERROR: immediate value 0x%08x out of %d bit range\n",
orig_val, orig_bits);
DIE("sparc VM bug");
}
}
static unsigned int sparc_assemble(enum sparc_iname iname, const int argc, const int *argv)
{
const struct sparc_opcode *op = &sparc_opcodes[iname];
unsigned int insn = op->opcode;
int i, flt, rd_flt;
flt = (op->name[0] == 'f');
rd_flt = flt || (op->name[2] == 'f');
for (i = 0; op->args[i] != ARG_NONE; i++) {
int val = argv[i];
switch (op->args[i]) {
case ARG_RS1: insn |= RS1(val); break;
case ARG_RS2: insn |= RS2(val); break;
case ARG_RD: insn |= RD(val); break;
case ARG_SIMM13: insn |= SIMM13(val); vimm(val,13,0,1,i); break;
case ARG_DISP30: insn |= DISP30(val); vimm(val,30,0,1,i); break;
case ARG_IMM22: insn |= IMM22(val); vimm(val,22,0,0,i); break;
case ARG_DISP22: insn |= DISP22(val); vimm(val,22,0,1,i); break;
case ARG_SWTRAP: insn |= SWTRAP(val); vimm(val,7,0,0,i); break;
}
}
return insn;
}
#define IN(inst, args...) \
({ const int argv[] = { args }; \
const int argc = ARRAY_LEN(argv); \
2011-02-18 14:31:32 +00:00
sparc_assemble(inst, argc, argv); \
})
#if 0
static void pgreg(int reg_num, int arg_index, int flt)
{
if (!flt) {
const char *fmt[] = { "%g", "%o", "%l", "%i" };
Com_Printf("%s%s%d",
(arg_index ? ", " : ""),
fmt[reg_num >> 3], reg_num & 7);
} else
Com_Printf("%s%%f%d", (arg_index ? ", " : ""), reg_num);
}
static void pimm(unsigned int val, int bits, int shift, int sgned, int arg_index)
{
val >>= shift;
val &= ((1 << bits) - 1);
if (sgned) {
int sval = val << (32 - bits);
sval >>= (32 - bits);
Com_Printf("%s%d",
(arg_index ? ", " : ""), sval);
} else
Com_Printf("%s0x%08x",
(arg_index ? ", " : ""), val);
}
static void sparc_disassemble(unsigned int insn)
{
int op_idx;
for (op_idx = 0; op_idx < SPARC_NUM_OPCODES; op_idx++) {
const struct sparc_opcode *op = &sparc_opcodes[op_idx];
int i, flt, rd_flt;
if ((insn & op->mask) != op->opcode)
continue;
flt = (op->name[0] == 'f');
rd_flt = flt || (op->name[2] == 'f');
Com_Printf("ASM: %7s\t", op->name);
for (i = 0; op->args[i] != ARG_NONE; i++) {
switch (op->args[i]) {
case ARG_RS1: pgreg((insn >> 14) & 0x1f, i, flt); break;
case ARG_RS2: pgreg((insn >> 0) & 0x1f, i, flt); break;
case ARG_RD: pgreg((insn >> 25) & 0x1f, i, rd_flt); break;
case ARG_SIMM13: pimm(insn, 13, 0, 1, i); break;
case ARG_DISP30: pimm(insn, 30, 0, 0, i); break;
case ARG_IMM22: pimm(insn, 22, 0, 0, i); break;
case ARG_DISP22: pimm(insn, 22, 0, 0, i); break;
case ARG_SWTRAP: pimm(insn, 7, 0, 0, i); break;
}
}
Com_Printf("\n");
return;
}
}
#endif
/*
* opcode information table:
* - length of immediate value
* - returned register type
* - required register(s) type
*/
#define opImm0 0x0000 /* no immediate */
#define opImm1 0x0001 /* 1 byte immadiate value after opcode */
#define opImm4 0x0002 /* 4 bytes immediate value after opcode */
#define opRet0 0x0000 /* returns nothing */
#define opRetI 0x0004 /* returns integer */
#define opRetF 0x0008 /* returns float */
#define opRetIF (opRetI | opRetF) /* returns integer or float */
#define opArg0 0x0000 /* requires nothing */
#define opArgI 0x0010 /* requires integer(s) */
#define opArgF 0x0020 /* requires float(s) */
#define opArgIF (opArgI | opArgF) /* requires integer or float */
#define opArg2I 0x0040 /* requires second argument, integer */
#define opArg2F 0x0080 /* requires second argument, float */
#define opArg2IF (opArg2I | opArg2F) /* requires second argument, integer or float */
static const unsigned char vm_opInfo[256] =
{
[OP_UNDEF] = opImm0,
[OP_IGNORE] = opImm0,
[OP_BREAK] = opImm0,
[OP_ENTER] = opImm4,
/* OP_LEAVE has to accept floats, they will be converted to ints */
[OP_LEAVE] = opImm4 | opRet0 | opArgIF,
/* only STORE4 and POP use values from OP_CALL,
* no need to convert floats back */
[OP_CALL] = opImm0 | opRetI | opArgI,
[OP_PUSH] = opImm0 | opRetIF,
[OP_POP] = opImm0 | opRet0 | opArgIF,
[OP_CONST] = opImm4 | opRetIF,
[OP_LOCAL] = opImm4 | opRetI,
[OP_JUMP] = opImm0 | opRet0 | opArgI,
[OP_EQ] = opImm4 | opRet0 | opArgI | opArg2I,
[OP_NE] = opImm4 | opRet0 | opArgI | opArg2I,
[OP_LTI] = opImm4 | opRet0 | opArgI | opArg2I,
[OP_LEI] = opImm4 | opRet0 | opArgI | opArg2I,
[OP_GTI] = opImm4 | opRet0 | opArgI | opArg2I,
[OP_GEI] = opImm4 | opRet0 | opArgI | opArg2I,
[OP_LTU] = opImm4 | opRet0 | opArgI | opArg2I,
[OP_LEU] = opImm4 | opRet0 | opArgI | opArg2I,
[OP_GTU] = opImm4 | opRet0 | opArgI | opArg2I,
[OP_GEU] = opImm4 | opRet0 | opArgI | opArg2I,
[OP_EQF] = opImm4 | opRet0 | opArgF | opArg2F,
[OP_NEF] = opImm4 | opRet0 | opArgF | opArg2F,
[OP_LTF] = opImm4 | opRet0 | opArgF | opArg2F,
[OP_LEF] = opImm4 | opRet0 | opArgF | opArg2F,
[OP_GTF] = opImm4 | opRet0 | opArgF | opArg2F,
[OP_GEF] = opImm4 | opRet0 | opArgF | opArg2F,
[OP_LOAD1] = opImm0 | opRetI | opArgI,
[OP_LOAD2] = opImm0 | opRetI | opArgI,
[OP_LOAD4] = opImm0 | opRetIF| opArgI,
[OP_STORE1] = opImm0 | opRet0 | opArgI | opArg2I,
[OP_STORE2] = opImm0 | opRet0 | opArgI | opArg2I,
[OP_STORE4] = opImm0 | opRet0 | opArgIF| opArg2I,
[OP_ARG] = opImm1 | opRet0 | opArgIF,
[OP_BLOCK_COPY] = opImm4 | opRet0 | opArgI | opArg2I,
[OP_SEX8] = opImm0 | opRetI | opArgI,
[OP_SEX16] = opImm0 | opRetI | opArgI,
[OP_NEGI] = opImm0 | opRetI | opArgI,
[OP_ADD] = opImm0 | opRetI | opArgI | opArg2I,
[OP_SUB] = opImm0 | opRetI | opArgI | opArg2I,
[OP_DIVI] = opImm0 | opRetI | opArgI | opArg2I,
[OP_DIVU] = opImm0 | opRetI | opArgI | opArg2I,
[OP_MODI] = opImm0 | opRetI | opArgI | opArg2I,
[OP_MODU] = opImm0 | opRetI | opArgI | opArg2I,
[OP_MULI] = opImm0 | opRetI | opArgI | opArg2I,
[OP_MULU] = opImm0 | opRetI | opArgI | opArg2I,
[OP_BAND] = opImm0 | opRetI | opArgI | opArg2I,
[OP_BOR] = opImm0 | opRetI | opArgI | opArg2I,
[OP_BXOR] = opImm0 | opRetI | opArgI | opArg2I,
[OP_BCOM] = opImm0 | opRetI | opArgI,
[OP_LSH] = opImm0 | opRetI | opArgI | opArg2I,
[OP_RSHI] = opImm0 | opRetI | opArgI | opArg2I,
[OP_RSHU] = opImm0 | opRetI | opArgI | opArg2I,
[OP_NEGF] = opImm0 | opRetF | opArgF,
[OP_ADDF] = opImm0 | opRetF | opArgF | opArg2F,
[OP_SUBF] = opImm0 | opRetF | opArgF | opArg2F,
[OP_DIVF] = opImm0 | opRetF | opArgF | opArg2F,
[OP_MULF] = opImm0 | opRetF | opArgF | opArg2F,
[OP_CVIF] = opImm0 | opRetF | opArgI,
[OP_CVFI] = opImm0 | opRetI | opArgF,
};
static const char *opnames[256] = {
"OP_UNDEF", "OP_IGNORE", "OP_BREAK", "OP_ENTER", "OP_LEAVE", "OP_CALL",
"OP_PUSH", "OP_POP", "OP_CONST", "OP_LOCAL", "OP_JUMP",
"OP_EQ", "OP_NE", "OP_LTI", "OP_LEI", "OP_GTI", "OP_GEI",
"OP_LTU", "OP_LEU", "OP_GTU", "OP_GEU", "OP_EQF", "OP_NEF",
"OP_LTF", "OP_LEF", "OP_GTF", "OP_GEF",
"OP_LOAD1", "OP_LOAD2", "OP_LOAD4", "OP_STORE1", "OP_STORE2",
"OP_STORE4", "OP_ARG", "OP_BLOCK_COPY",
"OP_SEX8", "OP_SEX16",
"OP_NEGI", "OP_ADD", "OP_SUB", "OP_DIVI", "OP_DIVU",
"OP_MODI", "OP_MODU", "OP_MULI", "OP_MULU", "OP_BAND",
"OP_BOR", "OP_BXOR", "OP_BCOM", "OP_LSH", "OP_RSHI", "OP_RSHU",
"OP_NEGF", "OP_ADDF", "OP_SUBF", "OP_DIVF", "OP_MULF",
"OP_CVIF", "OP_CVFI",
};
static void VM_Destroy_Compiled(vm_t *vm)
{
if (vm->codeBase) {
if (munmap(vm->codeBase, vm->codeLength))
Com_Printf(S_COLOR_RED "Memory unmap failed, possible memory leak\n");
}
vm->codeBase = NULL;
}
typedef struct VM_Data {
unsigned int dataLength;
unsigned int codeLength;
unsigned int *CallThunk;
int (*AsmCall)(int, int);
void (*BlockCopy)(unsigned int, unsigned int, unsigned int);
unsigned int *iPointers;
void (*ErrJump)(void);
2011-02-18 14:31:32 +00:00
unsigned int data[0];
} vm_data_t;
#ifdef offsetof
# define VM_Data_Offset(field) offsetof(vm_data_t, field)
#else
# define OFFSET(structName, field) \
((void *)&(((structName *)NULL)->field) - NULL)
# define VM_Data_Offset(field) OFFSET(vm_data_t, field)
#endif
struct src_insn {
unsigned char op;
unsigned int i_count;
union {
unsigned int i;
signed int si;
signed short ss[2];
unsigned short us[2];
unsigned char b;
} arg;
unsigned char dst_reg_flags;
unsigned char src1_reg_flags;
unsigned char src2_reg_flags;
#define REG_FLAGS_FLOAT 0x1
struct src_insn *next;
};
struct dst_insn;
struct jump_insn {
enum sparc_iname jump_iname;
int jump_dest_insn;
struct dst_insn *parent;
struct jump_insn *next;
};
struct dst_insn {
struct dst_insn *next;
unsigned int count;
unsigned int i_count;
struct jump_insn *jump;
unsigned int length;
unsigned int code[0];
};
#define HUNK_SIZE 29
struct data_hunk {
struct data_hunk *next;
int count;
unsigned int data[HUNK_SIZE];
};
struct func_info {
struct src_insn *first;
struct src_insn *last;
int has_call;
int need_float_tmp;
struct src_insn *cached_const;
int stack_space;
int gpr_pos;
#define rFIRST(fp) ((fp)->gpr_pos - 1)
#define rSECOND(fp) ((fp)->gpr_pos - 2)
#define POP_GPR(fp) ((fp)->gpr_pos--)
#define PUSH_GPR(fp) ((fp)->gpr_pos++)
int fpr_pos;
#define fFIRST(fp) ((fp)->fpr_pos - 1)
#define fSECOND(fp) ((fp)->fpr_pos - 2)
#define POP_FPR(fp) ((fp)->fpr_pos--)
#define PUSH_FPR(fp) ((fp)->fpr_pos++)
#define INSN_BUF_SIZE 50
unsigned int insn_buf[INSN_BUF_SIZE];
int insn_index;
int saved_icount;
int force_emit;
struct jump_insn *jump_first;
struct jump_insn *jump_last;
struct dst_insn *dst_first;
struct dst_insn *dst_last;
int dst_count;
struct dst_insn **dst_by_i_count;
struct data_hunk *data_first;
int data_num;
};
#define THUNK_ICOUNT -1
static unsigned int sparc_push_data(struct func_info * const fp, unsigned int val)
{
struct data_hunk *last, *dp = fp->data_first;
int off = 0;
last = NULL;
while (dp) {
int i;
for (i = 0; i < dp->count; i++) {
if (dp->data[i] == val) {
off += i;
return VM_Data_Offset(data[off]);
}
}
off += dp->count;
last = dp;
dp = dp->next;
}
dp = last;
if (!dp || dp->count >= HUNK_SIZE) {
struct data_hunk *new = Z_Malloc(sizeof(*new));
if (!dp)
fp->data_first = new;
else
dp->next = new;
dp = new;
dp->count = 0;
dp->next = NULL;
}
dp->data[dp->count++] = val;
fp->data_num = off + 1;
return VM_Data_Offset(data[off]);
}
static void dst_insn_insert_tail(struct func_info * const fp,
struct dst_insn *dp)
{
if (!fp->dst_first) {
fp->dst_first = fp->dst_last = dp;
} else {
fp->dst_last->next = dp;
fp->dst_last = dp;
}
}
static void jump_insn_insert_tail(struct func_info * const fp,
struct jump_insn *jp)
{
if (!fp->jump_first) {
fp->jump_first = fp->jump_last = jp;
} else {
fp->jump_last->next = jp;
fp->jump_last = jp;
}
}
static struct dst_insn *dst_new(struct func_info * const fp, unsigned int length,
struct jump_insn *jp, int insns_size)
{
struct dst_insn *dp = Z_Malloc(sizeof(struct dst_insn) + insns_size);
dp->length = length;
dp->jump = jp;
dp->count = fp->dst_count++;
dp->i_count = fp->saved_icount;
dp->next = NULL;
if (fp->saved_icount != THUNK_ICOUNT)
fp->dst_by_i_count[fp->saved_icount] = dp;
return dp;
}
static void dst_insn_append(struct func_info * const fp)
{
int insns_size = (sizeof(unsigned int) * fp->insn_index);
struct dst_insn *dp;
dp = dst_new(fp, fp->insn_index, NULL, insns_size);
if (insns_size)
memcpy(&dp->code[0], fp->insn_buf, insns_size);
dst_insn_insert_tail(fp, dp);
fp->insn_index = 0;
}
static void ErrJump(void)
{
Com_Error(ERR_DROP, "program tried to execute code outside VM");
exit(1);
}
static void jump_insn_append(vm_t *vm, struct func_info * const fp, enum sparc_iname iname, int dest)
2011-02-18 14:31:32 +00:00
{
struct jump_insn *jp = Z_Malloc(sizeof(*jp));
struct dst_insn *dp;
if (dest < 0 || dest >= vm->instructionCount)
ErrJump();
2011-02-18 14:31:32 +00:00
dp = dst_new(fp, 2, jp, 0);
jp->jump_iname = iname;
jp->jump_dest_insn = dest;
jp->parent = dp;
jp->next = NULL;
jump_insn_insert_tail(fp, jp);
dst_insn_insert_tail(fp, dp);
}
static void start_emit(struct func_info * const fp, int i_count)
{
fp->saved_icount = i_count;
fp->insn_index = 0;
fp->force_emit = 0;
}
static void __do_emit_one(struct func_info * const fp, unsigned int insn)
{
fp->insn_buf[fp->insn_index++] = insn;
}
#define in(inst, args...) __do_emit_one(fp, IN(inst, args))
static void end_emit(struct func_info * const fp)
{
if (fp->insn_index || fp->force_emit)
dst_insn_append(fp);
}
static void emit_jump(vm_t *vm, struct func_info * const fp, enum sparc_iname iname, int dest)
2011-02-18 14:31:32 +00:00
{
end_emit(fp);
jump_insn_append(vm, fp, iname, dest);
2011-02-18 14:31:32 +00:00
}
static void analyze_function(struct func_info * const fp)
{
struct src_insn *value_provider[20] = { NULL };
struct src_insn *sp = fp->first;
int opstack_depth = 0;
while ((sp = sp->next) != NULL) {
unsigned char opi, op = sp->op;
opi = vm_opInfo[op];
if (opi & opArgIF) {
struct src_insn *vp = value_provider[--opstack_depth];
unsigned char vpopi = vm_opInfo[vp->op];
if ((opi & opArgI) && (vpopi & opRetI)) {
/* src1 and dst are integers */
} else if ((opi & opArgF) && (vpopi & opRetF)) {
/* src1 and dst are floats */
vp->dst_reg_flags |= REG_FLAGS_FLOAT;
sp->src1_reg_flags = REG_FLAGS_FLOAT;
} else {
/* illegal combination */
DIE("unrecognized instruction combination");
}
}
if (opi & opArg2IF) {
struct src_insn *vp = value_provider[--opstack_depth];
unsigned char vpopi = vm_opInfo[vp->op];
if ((opi & opArg2I) && (vpopi & opRetI)) {
/* src2 and dst are integers */
} else if ( (opi & opArg2F) && (vpopi & opRetF) ) {
/* src2 and dst are floats */
vp->dst_reg_flags |= REG_FLAGS_FLOAT;
sp->src2_reg_flags = REG_FLAGS_FLOAT;
} else {
/* illegal combination */
DIE("unrecognized instruction combination");
}
}
if (opi & opRetIF) {
value_provider[opstack_depth] = sp;
opstack_depth++;
}
}
}
static int asmcall(int call, int pstack)
{
vm_t *savedVM = currentVM;
int i, ret;
currentVM->programStack = pstack - 4;
if (sizeof(intptr_t) == sizeof(int)) {
intptr_t *argPosition = (intptr_t *)((byte *)currentVM->dataBase + pstack + 4);
argPosition[0] = -1 - call;
ret = currentVM->systemCall(argPosition);
} else {
ioquake3 resync to revision 2398 from 2369. This is the last ioquake3 revision before ioquake3 changed from subversion to git at the beginning of 2013. #5808 - Include and use .glsl in source (rend2) #5812 - Use refdef's coordinates when drawing to screen shadow fbo, and separate depth texture and screen texture coordinates in glsl shaders. Include Rend2 renderer in MacOSX bundle Include OpenGL1 and Rend2 renderers in MacOSX UB Include Rend2 renderer in NSIS installer. Include OpenGL1 and Rend2 renderers in Loki Setup Installer. Have NSIS uninstaller delete rend2. Split light sample into direct and ambient parts when using deluxemaps or per-vertex light vectors. Fixes #5813. Fix writting voip data in demos (broke in r2102). Fix server ignoring client move commands if voip data is included. Allow changing cl_voip without restarting. Fix assert failing in CL_ParseVoip() while flipping cl_voip off and on. Only declare var_SampleToView in lightall shader when it is actually used. Fix a couple files not ending with a newline. Fix clients being able to reset their player state and respawn using donedl. Fix passing arg9 (qvm only), arg10, and arg11 to vmMain for native libs and non-i386 compiled or interpated qvms. (Currently they aren't use in vmMain in game, cgame, or ui.) Fix passing args[11] to args[15] from vm to engine on ppc64 and sparc64. Some of the args are used by game bot prediction syscalls. May have been causing bugs. Note: This was fixed for x86_64 in r2163. Fix reconnect command to work after leaving server. (#5794) Fix dedicated server crashing when using MSG_ReadDelta*, though it only happens if someone modifies the engine. (#5449) Makefile fixes for OpenBSD by Jonathan Gray. (#5728) Save all arguments from connect for reconnect command. Remove unnecessary localhost check from reconnect command. Support r_srgb even without hardware support. Also tweak default autoexposure/tonemap settings to look good on both r_srgb 0 and 1. Changed the MacOS-X build system to make UB's containing i386 and x86_64 arches and made make-macosx.sh not build UB's but only standard binaries Fix spectator client being switched from follow to free after map_restart if following a client with a higher client number. Fix client unlinking issue caused by ent->s.number being set to followed client's ps->clientNum after map_restart. Reported by Ensiform. Changes from Ensiform: - In G_AddBot, try to allocate clientNum before doing anything else. - In G_AddBot, don't set SVF_BOT and inuse. It's done in ClientConnect, plus inuse causes ClientDisconnect to be run for no reason. - In G_AddBot, only set skill in bot useinfo once. - Avoid using cl->ps.clientNum to check if cl is a bot. Fix bot skill format so it doesn't always have a space at the beginning of it. More fixes to the macosx buildsystem. This removes the SDL Framework and makes use of a SDL library that is position independant. This also brings back PPC builds into the UB and also as a standa alone build choice. Have make-macosx.sh require the user to specify which architecture she/he wants to build for and suggest building UB's if the user is unaware of what architectures are Lets list all the valid options.
2017-07-09 21:21:12 +00:00
intptr_t args[MAX_VMSYSCALL_ARGS];
2011-02-18 14:31:32 +00:00
args[0] = -1 - call;
int *argPosition = (int *)((byte *)currentVM->dataBase + pstack + 4);
ioquake3 resync to revision 2398 from 2369. This is the last ioquake3 revision before ioquake3 changed from subversion to git at the beginning of 2013. #5808 - Include and use .glsl in source (rend2) #5812 - Use refdef's coordinates when drawing to screen shadow fbo, and separate depth texture and screen texture coordinates in glsl shaders. Include Rend2 renderer in MacOSX bundle Include OpenGL1 and Rend2 renderers in MacOSX UB Include Rend2 renderer in NSIS installer. Include OpenGL1 and Rend2 renderers in Loki Setup Installer. Have NSIS uninstaller delete rend2. Split light sample into direct and ambient parts when using deluxemaps or per-vertex light vectors. Fixes #5813. Fix writting voip data in demos (broke in r2102). Fix server ignoring client move commands if voip data is included. Allow changing cl_voip without restarting. Fix assert failing in CL_ParseVoip() while flipping cl_voip off and on. Only declare var_SampleToView in lightall shader when it is actually used. Fix a couple files not ending with a newline. Fix clients being able to reset their player state and respawn using donedl. Fix passing arg9 (qvm only), arg10, and arg11 to vmMain for native libs and non-i386 compiled or interpated qvms. (Currently they aren't use in vmMain in game, cgame, or ui.) Fix passing args[11] to args[15] from vm to engine on ppc64 and sparc64. Some of the args are used by game bot prediction syscalls. May have been causing bugs. Note: This was fixed for x86_64 in r2163. Fix reconnect command to work after leaving server. (#5794) Fix dedicated server crashing when using MSG_ReadDelta*, though it only happens if someone modifies the engine. (#5449) Makefile fixes for OpenBSD by Jonathan Gray. (#5728) Save all arguments from connect for reconnect command. Remove unnecessary localhost check from reconnect command. Support r_srgb even without hardware support. Also tweak default autoexposure/tonemap settings to look good on both r_srgb 0 and 1. Changed the MacOS-X build system to make UB's containing i386 and x86_64 arches and made make-macosx.sh not build UB's but only standard binaries Fix spectator client being switched from follow to free after map_restart if following a client with a higher client number. Fix client unlinking issue caused by ent->s.number being set to followed client's ps->clientNum after map_restart. Reported by Ensiform. Changes from Ensiform: - In G_AddBot, try to allocate clientNum before doing anything else. - In G_AddBot, don't set SVF_BOT and inuse. It's done in ClientConnect, plus inuse causes ClientDisconnect to be run for no reason. - In G_AddBot, only set skill in bot useinfo once. - Avoid using cl->ps.clientNum to check if cl is a bot. Fix bot skill format so it doesn't always have a space at the beginning of it. More fixes to the macosx buildsystem. This removes the SDL Framework and makes use of a SDL library that is position independant. This also brings back PPC builds into the UB and also as a standa alone build choice. Have make-macosx.sh require the user to specify which architecture she/he wants to build for and suggest building UB's if the user is unaware of what architectures are Lets list all the valid options.
2017-07-09 21:21:12 +00:00
for( i = 1; i < ARRAY_LEN(args); i++ )
2011-02-18 14:31:32 +00:00
args[i] = argPosition[i];
ret = currentVM->systemCall(args);
}
currentVM = savedVM;
return ret;
}
static void blockcopy(unsigned int dest, unsigned int src, unsigned int count)
{
unsigned int dataMask = currentVM->dataMask;
if ((dest & dataMask) != dest ||
(src & dataMask) != src ||
((dest+count) & dataMask) != dest + count ||
((src+count) & dataMask) != src + count) {
DIE("OP_BLOCK_COPY out of range!");
}
memcpy(currentVM->dataBase+dest, currentVM->dataBase+src, count);
}
static void do_emit_const(struct func_info * const fp, struct src_insn *sp)
{
start_emit(fp, sp->i_count);
if (sp->dst_reg_flags & REG_FLAGS_FLOAT) {
in(LDFI, rVMDATA, sparc_push_data(fp, sp->arg.i), fFIRST(fp));
} else {
if ((sp->arg.i & ~0x3ff) == 0) {
in(ORI, G0, sp->arg.i & 0x3ff, rFIRST(fp));
} else if ((sp->arg.i & 0x3ff) == 0) {
in(SETHI, sp->arg.i >> 10, rFIRST(fp));
} else {
in(SETHI, sp->arg.i >> 10, rFIRST(fp));
in(ORI, rFIRST(fp), sp->arg.i & 0x3ff, rFIRST(fp));
}
}
end_emit(fp);
}
#define MAYBE_EMIT_CONST(fp) \
do { if ((fp)->cached_const) { \
int saved_i_count = (fp)->saved_icount; \
do_emit_const(fp, (fp)->cached_const); \
(fp)->saved_icount = saved_i_count; \
} \
} while (0)
#define EMIT_FALSE_CONST(fp) \
do { int saved_i_count = (fp)->saved_icount; \
(fp)->saved_icount = (fp)->cached_const->i_count; \
dst_insn_append(fp); \
(fp)->saved_icount = saved_i_count; \
} while (0)
static void compile_one_insn(vm_t *vm, struct func_info * const fp, struct src_insn *sp)
2011-02-18 14:31:32 +00:00
{
start_emit(fp, sp->i_count);
switch (sp->op) {
default:
Com_Printf("VM: Unhandled opcode 0x%02x[%s]\n",
sp->op,
opnames[sp->op] ? opnames[sp->op] : "UNKNOWN");
DIE("Unsupported opcode");
break;
case OP_ENTER: {
int stack = SL(64, 128);
if (fp->need_float_tmp)
stack += 16;
in(SAVEI, O6, -stack, O6);
if (!SIMM13_P(sp->arg.si)) {
in(SETHI, sp->arg.i >> 10, rTMP);
in(ORI, rTMP, sp->arg.i & 0x3ff, rTMP);
in(SUB, rPSTACK, rTMP, rPSTACK);
} else
in(SUBI, rPSTACK, sp->arg.si, rPSTACK);
break;
}
case OP_LEAVE:
if (fp->cached_const && SIMM13_P(fp->cached_const->arg.si)) {
EMIT_FALSE_CONST(fp);
if (fp->cached_const->src1_reg_flags & REG_FLAGS_FLOAT)
DIE("constant float in OP_LEAVE");
if (!SIMM13_P(sp->arg.si)) {
in(SETHI, sp->arg.i >> 10, rTMP);
in(ORI, rTMP, sp->arg.i & 0x3ff, rTMP);
in(ADD, rPSTACK, rTMP, rPSTACK);
} else
in(ADDI, rPSTACK, sp->arg.si, rPSTACK);
in(JMPLI, I7, 8, G0);
in(RESTOREI, G0, fp->cached_const->arg.si, O0);
POP_GPR(fp);
} else {
MAYBE_EMIT_CONST(fp);
if (!SIMM13_P(sp->arg.si)) {
in(SETHI, sp->arg.i >> 10, rTMP);
in(ORI, rTMP, sp->arg.i & 0x3ff, rTMP);
in(ADD, rPSTACK, rTMP, rPSTACK);
} else
in(ADDI, rPSTACK, sp->arg.si, rPSTACK);
if (sp->src1_reg_flags & REG_FLAGS_FLOAT) {
in(STFI, O6, SL(64, 128), fFIRST(fp));
in(LDUWI, O6, SL(64, 128), O0);
in(JMPLI, I7, 8, G0);
in(RESTORE, O0, G0, O0);
POP_FPR(fp);
} else {
in(JMPLI, I7, 8, G0);
in(RESTORE, rFIRST(fp), G0, O0);
POP_GPR(fp);
}
}
assert(fp->gpr_pos == L0);
assert(fp->fpr_pos == F0);
break;
case OP_JUMP:
if (fp->cached_const) {
EMIT_FALSE_CONST(fp);
emit_jump(vm, fp, BA, fp->cached_const->arg.i);
2011-02-18 14:31:32 +00:00
} else {
MAYBE_EMIT_CONST(fp);
in(SETHI, vm->instructionCount >> 10, rTMP);
in(ORI, rTMP, vm->instructionCount & 0x3ff, rTMP);
in(SUBCC, rTMP, rFIRST(fp), G0);
in(BLEU, +4*5);
in(LDLI, rVMDATA, VM_Data_Offset(ErrJump), rTMP);
2011-02-18 14:31:32 +00:00
in(SLLI, rFIRST(fp), 2, rFIRST(fp));
in(LDLI, rVMDATA, VM_Data_Offset(iPointers), rTMP);
2011-02-18 14:31:32 +00:00
in(LDL, rTMP, rFIRST(fp), rTMP);
in(JMPL, rTMP, G0, G0);
in(NOP);
}
POP_GPR(fp);
break;
case OP_CALL:
if (fp->cached_const) {
EMIT_FALSE_CONST(fp);
if (fp->cached_const->arg.si >= 0) {
emit_jump(vm, fp, CALL, fp->cached_const->arg.i);
2011-02-18 14:31:32 +00:00
} else {
in(LDLI, rVMDATA, VM_Data_Offset(CallThunk), rTMP);
in(LDLI, rVMDATA, VM_Data_Offset(AsmCall), O3);
in(ORI, G0, fp->cached_const->arg.si, O0);
in(JMPL, rTMP, G0, O7);
in(OR, G0, rPSTACK, O1);
}
in(OR, G0, O0, rFIRST(fp));
} else {
MAYBE_EMIT_CONST(fp);
in(SUBCCI, rFIRST(fp), 0, G0);
in(BL, +4*7);
in(NOP);
/* normal call */
in(SETHI, vm->instructionCount >> 10, rTMP);
in(ORI, rTMP, vm->instructionCount & 0x3ff, rTMP);
in(SUBCC, rTMP, rFIRST(fp), G0);
in(BLEU, +4*9);
in(LDLI, rVMDATA, VM_Data_Offset(ErrJump), rTMP);
2011-02-18 14:31:32 +00:00
in(LDLI, rVMDATA, VM_Data_Offset(iPointers), O5);
in(SLLI, rFIRST(fp), 2, rFIRST(fp));
in(LDL, O5, rFIRST(fp), rTMP);
in(BA, +4*4);
in(NOP);
/* syscall */
in(LDLI, rVMDATA, VM_Data_Offset(CallThunk), rTMP);
in(LDLI, rVMDATA, VM_Data_Offset(AsmCall), O3);
in(OR, G0, rFIRST(fp), O0);
in(JMPL, rTMP, G0, O7);
in(OR, G0, rPSTACK, O1);
/* return value */
in(OR, G0, O0, rFIRST(fp));
}
break;
case OP_BLOCK_COPY:
MAYBE_EMIT_CONST(fp);
in(LDLI, rVMDATA, VM_Data_Offset(CallThunk), rTMP);
in(LDLI, rVMDATA, VM_Data_Offset(BlockCopy), O3);
in(OR, G0, rSECOND(fp), O0);
in(OR, G0, rFIRST(fp), O1);
if ((sp->arg.i & ~0x3ff) == 0) {
in(ORI, G0, sp->arg.i & 0x3ff, O2);
} else if ((sp->arg.i & 0x3ff) == 0) {
in(SETHI, sp->arg.i >> 10, O2);
} else {
in(SETHI, sp->arg.i >> 10, O2);
in(ORI, O2, sp->arg.i & 0x3ff, O2);
}
in(JMPL, rTMP, G0, O7);
in(NOP);
POP_GPR(fp);
POP_GPR(fp);
break;
case OP_PUSH:
MAYBE_EMIT_CONST(fp);
if (sp->dst_reg_flags & REG_FLAGS_FLOAT)
PUSH_FPR(fp);
else
PUSH_GPR(fp);
fp->force_emit = 1;
break;
case OP_POP:
MAYBE_EMIT_CONST(fp);
if (sp->src1_reg_flags & REG_FLAGS_FLOAT)
POP_FPR(fp);
else
POP_GPR(fp);
fp->force_emit = 1;
break;
case OP_ARG:
MAYBE_EMIT_CONST(fp);
in(ADDI, rPSTACK, sp->arg.b, rTMP);
if (sp->src1_reg_flags & REG_FLAGS_FLOAT) {
in(STF, rDATABASE, rTMP, fFIRST(fp));
POP_FPR(fp);
} else {
in(STW, rDATABASE, rTMP, rFIRST(fp));
POP_GPR(fp);
}
break;
case OP_IGNORE:
MAYBE_EMIT_CONST(fp);
in(NOP);
break;
case OP_BREAK:
MAYBE_EMIT_CONST(fp);
in(TA, 0x5);
break;
case OP_LOCAL:
MAYBE_EMIT_CONST(fp);
PUSH_GPR(fp);
if (!SIMM13_P(sp->arg.i)) {
in(SETHI, sp->arg.i >> 10, rTMP);
in(ORI, rTMP, sp->arg.i & 0x3ff, rTMP);
in(ADD, rPSTACK, rTMP, rFIRST(fp));
} else
in(ADDI, rPSTACK, sp->arg.i, rFIRST(fp));
break;
case OP_CONST:
MAYBE_EMIT_CONST(fp);
break;
case OP_LOAD4:
MAYBE_EMIT_CONST(fp);
in(AND, rFIRST(fp), rDATAMASK, rFIRST(fp));
if (sp->dst_reg_flags & REG_FLAGS_FLOAT) {
PUSH_FPR(fp);
in(LDF, rFIRST(fp), rDATABASE, fFIRST(fp));
POP_GPR(fp);
} else {
in(LDUW, rFIRST(fp), rDATABASE, rFIRST(fp));
}
break;
case OP_LOAD2:
MAYBE_EMIT_CONST(fp);
in(AND, rFIRST(fp), rDATAMASK, rFIRST(fp));
in(LDUH, rFIRST(fp), rDATABASE, rFIRST(fp));
break;
case OP_LOAD1:
MAYBE_EMIT_CONST(fp);
in(AND, rFIRST(fp), rDATAMASK, rFIRST(fp));
in(LDUB, rFIRST(fp), rDATABASE, rFIRST(fp));
break;
case OP_STORE4:
MAYBE_EMIT_CONST(fp);
if (sp->src1_reg_flags & REG_FLAGS_FLOAT) {
in(AND, rFIRST(fp), rDATAMASK, rFIRST(fp));
in(STF, rFIRST(fp), rDATABASE, fFIRST(fp));
POP_FPR(fp);
} else {
in(AND, rSECOND(fp), rDATAMASK, rSECOND(fp));
in(STW, rSECOND(fp), rDATABASE, rFIRST(fp));
POP_GPR(fp);
}
POP_GPR(fp);
break;
case OP_STORE2:
MAYBE_EMIT_CONST(fp);
in(AND, rSECOND(fp), rDATAMASK, rSECOND(fp));
in(STH, rSECOND(fp), rDATABASE, rFIRST(fp));
POP_GPR(fp);
POP_GPR(fp);
break;
case OP_STORE1:
MAYBE_EMIT_CONST(fp);
in(AND, rSECOND(fp), rDATAMASK, rSECOND(fp));
in(STB, rSECOND(fp), rDATABASE, rFIRST(fp));
POP_GPR(fp);
POP_GPR(fp);
break;
case OP_EQ:
case OP_NE:
case OP_LTI:
case OP_GEI:
case OP_GTI:
case OP_LEI:
case OP_LTU:
case OP_GEU:
case OP_GTU:
case OP_LEU: {
enum sparc_iname iname = BA;
if (fp->cached_const && SIMM13_P(fp->cached_const->arg.si)) {
EMIT_FALSE_CONST(fp);
in(SUBCCI, rSECOND(fp), fp->cached_const->arg.si, G0);
} else {
MAYBE_EMIT_CONST(fp);
in(SUBCC, rSECOND(fp), rFIRST(fp), G0);
}
switch(sp->op) {
case OP_EQ: iname = BE; break;
case OP_NE: iname = BNE; break;
case OP_LTI: iname = BL; break;
case OP_GEI: iname = BGE; break;
case OP_GTI: iname = BG; break;
case OP_LEI: iname = BLE; break;
case OP_LTU: iname = BCS; break;
case OP_GEU: iname = BCC; break;
case OP_GTU: iname = BGU; break;
case OP_LEU: iname = BLEU; break;
}
emit_jump(vm, fp, iname, sp->arg.i);
2011-02-18 14:31:32 +00:00
POP_GPR(fp);
POP_GPR(fp);
break;
}
case OP_SEX8:
MAYBE_EMIT_CONST(fp);
in(SLLI, rFIRST(fp), 24, rFIRST(fp));
in(SRAI, rFIRST(fp), 24, rFIRST(fp));
break;
case OP_SEX16:
MAYBE_EMIT_CONST(fp);
in(SLLI, rFIRST(fp), 16, rFIRST(fp));
in(SRAI, rFIRST(fp), 16, rFIRST(fp));
break;
case OP_NEGI:
MAYBE_EMIT_CONST(fp);
in(SUB, G0, rFIRST(fp), rFIRST(fp));
break;
case OP_ADD:
if (fp->cached_const && SIMM13_P(fp->cached_const->arg.si)) {
EMIT_FALSE_CONST(fp);
in(ADDI, rSECOND(fp), fp->cached_const->arg.si, rSECOND(fp));
} else {
MAYBE_EMIT_CONST(fp);
in(ADD, rSECOND(fp), rFIRST(fp), rSECOND(fp));
}
POP_GPR(fp);
break;
case OP_SUB:
if (fp->cached_const && SIMM13_P(fp->cached_const->arg.si)) {
EMIT_FALSE_CONST(fp);
in(SUBI, rSECOND(fp), fp->cached_const->arg.si, rSECOND(fp));
} else {
MAYBE_EMIT_CONST(fp);
in(SUB, rSECOND(fp), rFIRST(fp), rSECOND(fp));
}
POP_GPR(fp);
break;
case OP_DIVI:
MAYBE_EMIT_CONST(fp);
in(SRAI, rSECOND(fp), 31, rTMP);
in(WRI, rTMP, 0, Y_REG);
in(SDIV, rSECOND(fp), rFIRST(fp), rSECOND(fp));
POP_GPR(fp);
break;
case OP_DIVU:
MAYBE_EMIT_CONST(fp);
in(WRI, G0, 0, Y_REG);
in(UDIV, rSECOND(fp), rFIRST(fp), rSECOND(fp));
POP_GPR(fp);
break;
case OP_MODI:
MAYBE_EMIT_CONST(fp);
in(SRAI, rSECOND(fp), 31, rTMP);
in(WRI, rTMP, 0, Y_REG);
in(SDIV, rSECOND(fp), rFIRST(fp), rTMP);
in(SMUL, rTMP, rFIRST(fp), rTMP);
in(SUB, rSECOND(fp), rTMP, rSECOND(fp));
POP_GPR(fp);
break;
case OP_MODU:
MAYBE_EMIT_CONST(fp);
in(WRI, G0, 0, Y_REG);
in(UDIV, rSECOND(fp), rFIRST(fp), rTMP);
in(SMUL, rTMP, rFIRST(fp), rTMP);
in(SUB, rSECOND(fp), rTMP, rSECOND(fp));
POP_GPR(fp);
break;
case OP_MULI:
MAYBE_EMIT_CONST(fp);
in(SMUL, rSECOND(fp), rFIRST(fp), rSECOND(fp));
POP_GPR(fp);
break;
case OP_MULU:
MAYBE_EMIT_CONST(fp);
in(UMUL, rSECOND(fp), rFIRST(fp), rSECOND(fp));
POP_GPR(fp);
break;
case OP_BAND:
MAYBE_EMIT_CONST(fp);
in(AND, rSECOND(fp), rFIRST(fp), rSECOND(fp));
POP_GPR(fp);
break;
case OP_BOR:
MAYBE_EMIT_CONST(fp);
in(OR, rSECOND(fp), rFIRST(fp), rSECOND(fp));
POP_GPR(fp);
break;
case OP_BXOR:
MAYBE_EMIT_CONST(fp);
in(XOR, rSECOND(fp), rFIRST(fp), rSECOND(fp));
POP_GPR(fp);
break;
case OP_BCOM:
MAYBE_EMIT_CONST(fp);
in(XNOR, rFIRST(fp), G0, rFIRST(fp));
break;
case OP_LSH:
if (fp->cached_const) {
EMIT_FALSE_CONST(fp);
in(SLLI, rSECOND(fp), fp->cached_const->arg.si, rSECOND(fp));
} else {
MAYBE_EMIT_CONST(fp);
in(SLL, rSECOND(fp), rFIRST(fp), rSECOND(fp));
}
POP_GPR(fp);
break;
case OP_RSHI:
if (fp->cached_const) {
EMIT_FALSE_CONST(fp);
in(SRAI, rSECOND(fp), fp->cached_const->arg.si, rSECOND(fp));
} else {
MAYBE_EMIT_CONST(fp);
in(SRA, rSECOND(fp), rFIRST(fp), rSECOND(fp));
}
POP_GPR(fp);
break;
case OP_RSHU:
if (fp->cached_const) {
EMIT_FALSE_CONST(fp);
in(SRLI, rSECOND(fp), fp->cached_const->arg.si, rSECOND(fp));
} else {
MAYBE_EMIT_CONST(fp);
in(SRL, rSECOND(fp), rFIRST(fp), rSECOND(fp));
}
POP_GPR(fp);
break;
case OP_NEGF:
MAYBE_EMIT_CONST(fp);
in(FNEG, fFIRST(fp), fFIRST(fp));
break;
case OP_ADDF:
MAYBE_EMIT_CONST(fp);
in(FADD, fSECOND(fp), fFIRST(fp), fSECOND(fp));
POP_FPR(fp);
break;
case OP_SUBF:
MAYBE_EMIT_CONST(fp);
in(FSUB, fSECOND(fp), fFIRST(fp), fSECOND(fp));
POP_FPR(fp);
break;
case OP_DIVF:
MAYBE_EMIT_CONST(fp);
in(FDIV, fSECOND(fp), fFIRST(fp), fSECOND(fp));
POP_FPR(fp);
break;
case OP_MULF:
MAYBE_EMIT_CONST(fp);
in(FMUL, fSECOND(fp), fFIRST(fp), fSECOND(fp));
POP_FPR(fp);
break;
case OP_EQF:
case OP_NEF:
case OP_LTF:
case OP_GEF:
case OP_GTF:
case OP_LEF: {
enum sparc_iname iname = FBE;
MAYBE_EMIT_CONST(fp);
in(FCMP, fSECOND(fp), fFIRST(fp));
switch(sp->op) {
case OP_EQF: iname = FBE; break;
case OP_NEF: iname = FBNE; break;
case OP_LTF: iname = FBL; break;
case OP_GEF: iname = FBGE; break;
case OP_GTF: iname = FBG; break;
case OP_LEF: iname = FBLE; break;
}
emit_jump(vm, fp, iname, sp->arg.i);
2011-02-18 14:31:32 +00:00
POP_FPR(fp);
POP_FPR(fp);
break;
}
case OP_CVIF:
MAYBE_EMIT_CONST(fp);
PUSH_FPR(fp);
in(STWI, O6, SL(64, 128), rFIRST(fp));
in(LDFI, O6, SL(64, 128), fFIRST(fp));
in(FITOS, fFIRST(fp), fFIRST(fp));
POP_GPR(fp);
break;
case OP_CVFI:
MAYBE_EMIT_CONST(fp);
PUSH_GPR(fp);
in(FSTOI, fFIRST(fp), fFIRST(fp));
in(STFI, O6, SL(64, 128), fFIRST(fp));
in(LDUWI, O6, SL(64, 128), rFIRST(fp));
POP_FPR(fp);
break;
}
if (sp->op != OP_CONST) {
fp->cached_const = NULL;
end_emit(fp);
} else {
fp->cached_const = sp;
if (sp->dst_reg_flags & REG_FLAGS_FLOAT) {
PUSH_FPR(fp);
} else {
PUSH_GPR(fp);
}
}
end_emit(fp);
}
static void free_source_insns(struct func_info * const fp)
{
struct src_insn *sp = fp->first->next;
while (sp) {
struct src_insn *next = sp->next;
Z_Free(sp);
sp = next;
}
}
static void compile_function(vm_t *vm, struct func_info * const fp)
2011-02-18 14:31:32 +00:00
{
struct src_insn *sp;
analyze_function(fp);
fp->gpr_pos = L0;
fp->fpr_pos = F0;
fp->insn_index = 0;
fp->stack_space = SL(64, 128);
fp->cached_const = NULL;
sp = fp->first;
while ((sp = sp->next) != NULL)
compile_one_insn(vm, fp, sp);
2011-02-18 14:31:32 +00:00
free_source_insns(fp);
}
/* We have two thunks for sparc. The first is for the entry into
* the VM, where setup the fixed global registers. The second is
* for calling out to C code from the VM, where we need to preserve
* those fixed globals across the call.
*/
static void emit_vm_thunk(struct func_info * const fp)
{
/* int vm_thunk(void *vmdata, int programstack, void *database, int datamask) */
start_emit(fp, THUNK_ICOUNT);
in(OR, G0, O0, rVMDATA);
in(OR, G0, O1, rPSTACK);
in(OR, G0, O2, rDATABASE);
in(BA, +4*17);
in(OR, G0, O3, rDATAMASK);
/* int call_thunk(int arg0, int arg1, int arg2, int (*func)(int int int)) */
#define CALL_THUNK_INSN_OFFSET 5
in(SAVEI, O6, -SL(64, 128), O6);
in(OR, G0, rVMDATA, L0);
in(OR, G0, rPSTACK, L1);
in(OR, G0, rDATABASE, L2);
in(OR, G0, rDATAMASK, L3);
in(OR, G0, I0, O0);
in(OR, G0, I1, O1);
in(JMPL, I3, G0, O7);
in(OR, G0, I2, O2);
in(OR, G0, L0, rVMDATA);
in(OR, G0, L1, rPSTACK);
in(OR, G0, L2, rDATABASE);
in(OR, G0, L3, rDATAMASK);
in(JMPLI, I7, 8, G0);
in(RESTORE, O0, G0, O0);
end_emit(fp);
}
static void sparc_compute_code(vm_t *vm, struct func_info * const fp)
{
struct dst_insn *dp = fp->dst_first;
unsigned int *code_now, *code_begin;
unsigned char *data_and_code;
unsigned int code_length;
int code_insns = 0, off;
struct data_hunk *dhp;
struct jump_insn *jp;
vm_data_t *data;
while (dp) {
code_insns += dp->length;
dp = dp->next;
}
code_length = (sizeof(vm_data_t) +
(fp->data_num * sizeof(unsigned int)) +
(code_insns * sizeof(unsigned int)));
data_and_code = mmap(NULL, code_length, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (data_and_code == MAP_FAILED)
2011-02-18 14:31:32 +00:00
DIE("Not enough memory");
code_now = code_begin = (unsigned int *)
(data_and_code + VM_Data_Offset(data[fp->data_num]));
dp = fp->dst_first;
while (dp) {
int i_count = dp->i_count;
if (i_count != THUNK_ICOUNT) {
if (!fp->dst_by_i_count[i_count])
fp->dst_by_i_count[i_count] = (void *) code_now;
}
if (!dp->jump) {
memcpy(code_now, &dp->code[0], dp->length * sizeof(unsigned int));
code_now += dp->length;
} else {
int i;
dp->jump->parent = (void *) code_now;
for (i = 0; i < dp->length; i++)
code_now[i] = SPARC_NOP;
code_now += dp->length;
}
dp = dp->next;
}
jp = fp->jump_first;
while (jp) {
unsigned int *from = (void *) jp->parent;
unsigned int *to = (void *) fp->dst_by_i_count[jp->jump_dest_insn];
signed int disp = (to - from);
*from = IN(jp->jump_iname, disp << 2);
jp = jp->next;
}
vm->codeBase = data_and_code;
vm->codeLength = code_length;
data = (vm_data_t *) data_and_code;
data->CallThunk = code_begin + CALL_THUNK_INSN_OFFSET;
data->AsmCall = asmcall;
data->BlockCopy = blockcopy;
data->iPointers = (unsigned int *) vm->instructionPointers;
data->dataLength = VM_Data_Offset(data[fp->data_num]);
data->codeLength = (code_now - code_begin) * sizeof(unsigned int);
data->ErrJump = ErrJump;
2011-02-18 14:31:32 +00:00
#if 0
{
unsigned int *insn = code_begin;
int i;
Com_Printf("INSN DUMP\n");
for (i = 0; i < data->codeLength / 4; i+= 8) {
Com_Printf("\t.word\t0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
insn[i + 0], insn[i + 1],
insn[i + 2], insn[i + 3],
insn[i + 4], insn[i + 5],
insn[i + 6], insn[i + 7]);
}
}
#endif
dhp = fp->data_first;
off = 0;
while (dhp) {
struct data_hunk *next = dhp->next;
int i;
for (i = 0; i < dhp->count; i++)
data->data[off + i] = dhp->data[i];
off += dhp->count;
Z_Free(dhp);
dhp = next;
}
fp->data_first = NULL;
fp->data_num = 0;
dp = fp->dst_first;
while (dp) {
struct dst_insn *next = dp->next;
if (dp->jump)
Z_Free(dp->jump);
Z_Free(dp);
dp = next;
}
fp->dst_first = fp->dst_last = NULL;
}
void VM_Compile(vm_t *vm, vmHeader_t *header)
{
struct func_info fi;
unsigned char *code;
int i_count, pc, i;
memset(&fi, 0, sizeof(fi));
fi.first = Z_Malloc(sizeof(struct src_insn));
fi.first->next = NULL;
#ifdef __arch64__
Z_Free(vm->instructionPointers);
vm->instructionPointers = Z_Malloc(header->instructionCount *
sizeof(void *));
#endif
fi.dst_by_i_count = (struct dst_insn **) vm->instructionPointers;
memset(fi.dst_by_i_count, 0, header->instructionCount * sizeof(void *));
vm->compiled = qfalse;
emit_vm_thunk(&fi);
code = (unsigned char *) header + header->codeOffset;
pc = 0;
for (i_count = 0; i_count < header->instructionCount; i_count++) {
unsigned char opi, op = code[pc++];
struct src_insn *sp;
if (op == OP_CALL || op == OP_BLOCK_COPY)
fi.has_call = 1;
opi = vm_opInfo[op];
if (op == OP_CVIF || op == OP_CVFI ||
(op == OP_LEAVE && (opi & opArgF)))
fi.need_float_tmp = 1;
if (op == OP_ENTER) {
if (fi.first->next)
compile_function(vm, &fi);
2011-02-18 14:31:32 +00:00
fi.first->next = NULL;
fi.last = fi.first;
fi.has_call = fi.need_float_tmp = 0;
}
sp = Z_Malloc(sizeof(*sp));
sp->op = op;
sp->i_count = i_count;
sp->arg.i = 0;
sp->next = NULL;
if (vm_opInfo[op] & opImm4) {
union {
unsigned char b[4];
unsigned int i;
} c = { { code[ pc + 3 ], code[ pc + 2 ],
code[ pc + 1 ], code[ pc + 0 ] }, };
sp->arg.i = c.i;
pc += 4;
} else if (vm_opInfo[op] & opImm1) {
sp->arg.b = code[pc++];
}
fi.last->next = sp;
fi.last = sp;
}
compile_function(vm, &fi);
2011-02-18 14:31:32 +00:00
Z_Free(fi.first);
memset(fi.dst_by_i_count, 0, header->instructionCount * sizeof(void *));
sparc_compute_code(vm, &fi);
for (i = 0; i < header->instructionCount; i++) {
if (!fi.dst_by_i_count[i]) {
Com_Printf(S_COLOR_RED "Pointer %d not initialized !\n", i);
DIE("sparc JIT bug");
}
}
if (mprotect(vm->codeBase, vm->codeLength, PROT_READ|PROT_EXEC)) {
VM_Destroy_Compiled(vm);
DIE("mprotect failed");
}
vm->destroy = VM_Destroy_Compiled;
vm->compiled = qtrue;
}
int VM_CallCompiled(vm_t *vm, int *args)
{
vm_data_t *vm_dataAndCode = (void *) vm->codeBase;
int programStack = vm->programStack;
int stackOnEntry = programStack;
byte *image = vm->dataBase;
int *argPointer;
int retVal;
currentVM = vm;
vm->currentlyInterpreting = qtrue;
ioquake3 resync to revision 2398 from 2369. This is the last ioquake3 revision before ioquake3 changed from subversion to git at the beginning of 2013. #5808 - Include and use .glsl in source (rend2) #5812 - Use refdef's coordinates when drawing to screen shadow fbo, and separate depth texture and screen texture coordinates in glsl shaders. Include Rend2 renderer in MacOSX bundle Include OpenGL1 and Rend2 renderers in MacOSX UB Include Rend2 renderer in NSIS installer. Include OpenGL1 and Rend2 renderers in Loki Setup Installer. Have NSIS uninstaller delete rend2. Split light sample into direct and ambient parts when using deluxemaps or per-vertex light vectors. Fixes #5813. Fix writting voip data in demos (broke in r2102). Fix server ignoring client move commands if voip data is included. Allow changing cl_voip without restarting. Fix assert failing in CL_ParseVoip() while flipping cl_voip off and on. Only declare var_SampleToView in lightall shader when it is actually used. Fix a couple files not ending with a newline. Fix clients being able to reset their player state and respawn using donedl. Fix passing arg9 (qvm only), arg10, and arg11 to vmMain for native libs and non-i386 compiled or interpated qvms. (Currently they aren't use in vmMain in game, cgame, or ui.) Fix passing args[11] to args[15] from vm to engine on ppc64 and sparc64. Some of the args are used by game bot prediction syscalls. May have been causing bugs. Note: This was fixed for x86_64 in r2163. Fix reconnect command to work after leaving server. (#5794) Fix dedicated server crashing when using MSG_ReadDelta*, though it only happens if someone modifies the engine. (#5449) Makefile fixes for OpenBSD by Jonathan Gray. (#5728) Save all arguments from connect for reconnect command. Remove unnecessary localhost check from reconnect command. Support r_srgb even without hardware support. Also tweak default autoexposure/tonemap settings to look good on both r_srgb 0 and 1. Changed the MacOS-X build system to make UB's containing i386 and x86_64 arches and made make-macosx.sh not build UB's but only standard binaries Fix spectator client being switched from follow to free after map_restart if following a client with a higher client number. Fix client unlinking issue caused by ent->s.number being set to followed client's ps->clientNum after map_restart. Reported by Ensiform. Changes from Ensiform: - In G_AddBot, try to allocate clientNum before doing anything else. - In G_AddBot, don't set SVF_BOT and inuse. It's done in ClientConnect, plus inuse causes ClientDisconnect to be run for no reason. - In G_AddBot, only set skill in bot useinfo once. - Avoid using cl->ps.clientNum to check if cl is a bot. Fix bot skill format so it doesn't always have a space at the beginning of it. More fixes to the macosx buildsystem. This removes the SDL Framework and makes use of a SDL library that is position independant. This also brings back PPC builds into the UB and also as a standa alone build choice. Have make-macosx.sh require the user to specify which architecture she/he wants to build for and suggest building UB's if the user is unaware of what architectures are Lets list all the valid options.
2017-07-09 21:21:12 +00:00
programStack -= ( 8 + 4 * MAX_VMMAIN_ARGS );
2011-02-18 14:31:32 +00:00
argPointer = (int *)&image[ programStack + 8 ];
ioquake3 resync to revision 2398 from 2369. This is the last ioquake3 revision before ioquake3 changed from subversion to git at the beginning of 2013. #5808 - Include and use .glsl in source (rend2) #5812 - Use refdef's coordinates when drawing to screen shadow fbo, and separate depth texture and screen texture coordinates in glsl shaders. Include Rend2 renderer in MacOSX bundle Include OpenGL1 and Rend2 renderers in MacOSX UB Include Rend2 renderer in NSIS installer. Include OpenGL1 and Rend2 renderers in Loki Setup Installer. Have NSIS uninstaller delete rend2. Split light sample into direct and ambient parts when using deluxemaps or per-vertex light vectors. Fixes #5813. Fix writting voip data in demos (broke in r2102). Fix server ignoring client move commands if voip data is included. Allow changing cl_voip without restarting. Fix assert failing in CL_ParseVoip() while flipping cl_voip off and on. Only declare var_SampleToView in lightall shader when it is actually used. Fix a couple files not ending with a newline. Fix clients being able to reset their player state and respawn using donedl. Fix passing arg9 (qvm only), arg10, and arg11 to vmMain for native libs and non-i386 compiled or interpated qvms. (Currently they aren't use in vmMain in game, cgame, or ui.) Fix passing args[11] to args[15] from vm to engine on ppc64 and sparc64. Some of the args are used by game bot prediction syscalls. May have been causing bugs. Note: This was fixed for x86_64 in r2163. Fix reconnect command to work after leaving server. (#5794) Fix dedicated server crashing when using MSG_ReadDelta*, though it only happens if someone modifies the engine. (#5449) Makefile fixes for OpenBSD by Jonathan Gray. (#5728) Save all arguments from connect for reconnect command. Remove unnecessary localhost check from reconnect command. Support r_srgb even without hardware support. Also tweak default autoexposure/tonemap settings to look good on both r_srgb 0 and 1. Changed the MacOS-X build system to make UB's containing i386 and x86_64 arches and made make-macosx.sh not build UB's but only standard binaries Fix spectator client being switched from follow to free after map_restart if following a client with a higher client number. Fix client unlinking issue caused by ent->s.number being set to followed client's ps->clientNum after map_restart. Reported by Ensiform. Changes from Ensiform: - In G_AddBot, try to allocate clientNum before doing anything else. - In G_AddBot, don't set SVF_BOT and inuse. It's done in ClientConnect, plus inuse causes ClientDisconnect to be run for no reason. - In G_AddBot, only set skill in bot useinfo once. - Avoid using cl->ps.clientNum to check if cl is a bot. Fix bot skill format so it doesn't always have a space at the beginning of it. More fixes to the macosx buildsystem. This removes the SDL Framework and makes use of a SDL library that is position independant. This also brings back PPC builds into the UB and also as a standa alone build choice. Have make-macosx.sh require the user to specify which architecture she/he wants to build for and suggest building UB's if the user is unaware of what architectures are Lets list all the valid options.
2017-07-09 21:21:12 +00:00
memcpy( argPointer, args, 4 * MAX_VMMAIN_ARGS );
2011-02-18 14:31:32 +00:00
argPointer[-1] = 0;
argPointer[-2] = -1;
/* call generated code */
{
int (*entry)(void *, int, void *, int);
entry = (void *)(vm->codeBase + vm_dataAndCode->dataLength);
retVal = entry(vm->codeBase, programStack, vm->dataBase, vm->dataMask);
}
vm->programStack = stackOnEntry;
vm->currentlyInterpreting = qfalse;
return retVal;
}