1 /*
2 ===========================================================================
3 Copyright (C) 2009 David S. Miller <davem@davemloft.net>
4 
5 This file is part of Quake III Arena source code.
6 
7 Quake III Arena source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
11 
12 Quake III Arena source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Quake III Arena source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 ===========================================================================
21 */
22 
23 /* This code is based almost entirely upon the vm_powerpc.c code by
24  * Przemyslaw Iskra.  All I did was make it work on Sparc :-) -DaveM
25  */
26 
27 #include <sys/types.h>
28 #include <sys/mman.h>
29 #include <sys/time.h>
30 #include <time.h>
31 #include <stddef.h>
32 
33 #include "vm_local.h"
34 #include "vm_sparc.h"
35 
36 /* exit() won't be called but use it because it is marked with noreturn */
37 #define DIE( reason ) \
38 	do { \
39 		Com_Error(ERR_DROP, "vm_sparc compiler error: " reason "\n"); \
40 		exit(1); \
41 	} while(0)
42 
43 /* Select Length - first value on 32 bits, second on 64 */
44 #ifdef __arch64__
45 #define SL(a, b) (b)
46 #else
47 #define SL(a, b) (a)
48 #endif
49 
50 #define rTMP		G1
51 #define rVMDATA		G2
52 #define rPSTACK		G3
53 #define rDATABASE	G4
54 #define rDATAMASK	G5
55 
56 struct sparc_opcode {
57 	const char	*name;
58 	unsigned int	opcode;
59 	unsigned int	mask;
60 	unsigned char	args[4];
61 #define ARG_NONE	0
62 #define ARG_RS1		1
63 #define ARG_RS2		2
64 #define ARG_RD		3
65 #define ARG_SIMM13	4
66 #define ARG_DISP30	5
67 #define ARG_IMM22	6
68 #define ARG_DISP22	7
69 #define ARG_SWTRAP	8
70 };
71 
72 #define ARG_RS1_RS2_RD		{ ARG_RS1, ARG_RS2, ARG_RD }
73 #define ARG_RS1_SIMM13_RD	{ ARG_RS1, ARG_SIMM13, ARG_RD }
74 #define ARG_RS1_RS2		{ ARG_RS1, ARG_RS2 }
75 #define ARG_RS2_RD		{ ARG_RS2, ARG_RD }
76 
77 #define OP_MASK		0xc0000000
78 #define OP2_MASK	0x01c00000
79 #define OP3_MASK	0x01f80000
80 #define OPF_MASK	0x00003fe0
81 
82 #define IMM		0x00002000
83 
84 #define FMT1(op)		((op) << 30), OP_MASK
85 #define FMT2(op,op2)		((op) << 30)|((op2)<<22), (OP_MASK | OP2_MASK)
86 #define FMT3(op,op3)		((op) << 30)|((op3)<<19), (OP_MASK | OP3_MASK | IMM)
87 #define FMT3I(op,op3)		((op) << 30)|((op3)<<19)|IMM, (OP_MASK | OP3_MASK | IMM)
88 #define FMT3F(op,op3,opf)	((op) << 30)|((op3)<<19)|((opf)<<5), \
89 				(OP_MASK | OP3_MASK | OPF_MASK)
90 
91 #define BICC(A,COND)		FMT2(0,((A<<7)|(COND<<3)|0x2))
92 #define BFCC(A,COND)		FMT2(0,((A<<7)|(COND<<3)|0x6))
93 #define TICC(COND)		FMT3I(0,((COND<<6)|0x3a))
94 
95 enum sparc_iname {
96 	CALL, NOP, SETHI,
97 
98 	BA, BN, BNE, BE, BG, BLE, BGE, BL, BGU, BLEU, BCC, BCS,
99 	BPOS, BNEG, BVC, BVS,
100 
101 	ADDI, ADD,
102 	ANDI, AND,
103 	ORI, OR,
104 	XORI, XOR,
105 	SUBI, SUB,
106 	ANDNI, ANDN,
107 	ORNI, ORN,
108 	XNORI, XNOR,
109 
110 	UMULI, UMUL,
111 	SMULI, SMUL,
112 	UDIVI, UDIV,
113 	SDIVI, SDIV,
114 
115 	SUBCCI, SUBCC,
116 
117 	SLLI, SLL,
118 	SRLI, SRL,
119 	SRAI, SRA,
120 
121 	WRI, WR,
122 
123 	SAVEI, SAVE,
124 	RESTOREI, RESTORE,
125 
126 	TA,
127 
128 	JMPLI, JMPL,
129 
130 	LDXI, LDX,
131 	LDUWI, LDUW,
132 	LDUHI, LDUH,
133 	LDUBI, LDUB,
134 
135 	STXI, STX,
136 	STWI, STW,
137 	STHI, STH,
138 	STBI, STB,
139 
140 	LDFI, LDF,
141 	STFI, STF,
142 
143 	FADD, FSUB, FCMP, FSTOI, FITOS, FNEG, FDIV, FMUL,
144 	FBE, FBNE, FBL, FBGE, FBG, FBLE,
145 };
146 
147 #define LDLI	SL(LDUWI, LDXI)
148 #define LDL	SL(LDUW, LDX)
149 #define STLI	SL(STWI, STXI)
150 #define STL	SL(STW, STX)
151 
152 #define SPARC_NOP	0x01000000
153 
154 static const struct sparc_opcode sparc_opcodes[] = {
155 	{ "call",	FMT1(1), { ARG_DISP30 }, },
156 	{ "nop",	SPARC_NOP, 0xffffffff, { ARG_NONE }, }, /* sethi %hi(0), %g0 */
157 	{ "sethi",	FMT2(0,4), { ARG_IMM22, ARG_RD }, },
158 	{ "ba",		BICC(0,8), { ARG_DISP22 }, },
159 	{ "bn",		BICC(0,0), { ARG_DISP22 }, },
160 	{ "bne",	BICC(0,9), { ARG_DISP22 }, },
161 	{ "be",		BICC(0,1), { ARG_DISP22 }, },
162 	{ "bg",		BICC(0,10), { ARG_DISP22 }, },
163 	{ "ble",	BICC(0,2), { ARG_DISP22 }, },
164 	{ "bge",	BICC(0,11), { ARG_DISP22 }, },
165 	{ "bl",		BICC(0,3), { ARG_DISP22 }, },
166 	{ "bgu",	BICC(0,12), { ARG_DISP22 }, },
167 	{ "bleu",	BICC(0,4), { ARG_DISP22 }, },
168 	{ "bcc",	BICC(0,13), { ARG_DISP22 }, },
169 	{ "bcs",	BICC(0,5), { ARG_DISP22 }, },
170 	{ "bpos",	BICC(0,14), { ARG_DISP22 }, },
171 	{ "bneg",	BICC(0,6), { ARG_DISP22 }, },
172 	{ "bvc",	BICC(0,15), { ARG_DISP22 }, },
173 	{ "bvs",	BICC(0,7), { ARG_DISP22 }, },
174 
175 	{ "add",	FMT3I(2, 0x00), ARG_RS1_SIMM13_RD, },
176 	{ "add",	FMT3 (2, 0x00), ARG_RS1_RS2_RD,    },
177 	{ "and",	FMT3I(2, 0x01), ARG_RS1_SIMM13_RD, },
178 	{ "and",	FMT3 (2, 0x01), ARG_RS1_RS2_RD,    },
179 	{ "or",		FMT3I(2, 0x02), ARG_RS1_SIMM13_RD, },
180 	{ "or",		FMT3 (2, 0x02), ARG_RS1_RS2_RD,    },
181 	{ "xor",	FMT3I(2, 0x03), ARG_RS1_SIMM13_RD, },
182 	{ "xor",	FMT3 (2, 0x03), ARG_RS1_RS2_RD,    },
183 	{ "sub",	FMT3I(2, 0x04), ARG_RS1_SIMM13_RD, },
184 	{ "sub",	FMT3 (2, 0x04), ARG_RS1_RS2_RD,    },
185 	{ "andn",	FMT3I(2, 0x05), ARG_RS1_SIMM13_RD, },
186 	{ "andn",	FMT3 (2, 0x05), ARG_RS1_RS2_RD,    },
187 	{ "orn",	FMT3I(2, 0x06), ARG_RS1_SIMM13_RD, },
188 	{ "orn",	FMT3 (2, 0x06), ARG_RS1_RS2_RD,    },
189 	{ "xnor",	FMT3I(2, 0x07), ARG_RS1_SIMM13_RD, },
190 	{ "xnor",	FMT3 (2, 0x07), ARG_RS1_RS2_RD,    },
191 
192 	{ "umul",	FMT3I(2, 0x0a), ARG_RS1_SIMM13_RD, },
193 	{ "umul",	FMT3 (2, 0x0a), ARG_RS1_RS2_RD,    },
194 	{ "smul",	FMT3I(2, 0x0b), ARG_RS1_SIMM13_RD, },
195 	{ "smul",	FMT3 (2, 0x0b), ARG_RS1_RS2_RD,    },
196 	{ "udiv",	FMT3I(2, 0x0e), ARG_RS1_SIMM13_RD, },
197 	{ "udiv",	FMT3 (2, 0x0e), ARG_RS1_RS2_RD,    },
198 	{ "sdiv",	FMT3I(2, 0x0f), ARG_RS1_SIMM13_RD, },
199 	{ "sdiv",	FMT3 (2, 0x0f), ARG_RS1_RS2_RD,    },
200 
201 	{ "subcc",	FMT3I(2, 0x14), ARG_RS1_SIMM13_RD, },
202 	{ "subcc",	FMT3 (2, 0x14), ARG_RS1_RS2_RD,    },
203 
204 	{ "sll",	FMT3I(2, 0x25), ARG_RS1_SIMM13_RD, },
205 	{ "sll",	FMT3 (2, 0x25), ARG_RS1_RS2_RD,    },
206 	{ "srl",	FMT3I(2, 0x26), ARG_RS1_SIMM13_RD, },
207 	{ "srl",	FMT3 (2, 0x26), ARG_RS1_RS2_RD,    },
208 	{ "sra",	FMT3I(2, 0x27), ARG_RS1_SIMM13_RD, },
209 	{ "sra",	FMT3 (2, 0x27), ARG_RS1_RS2_RD,    },
210 
211 	{ "wr",		FMT3I(2, 0x30), ARG_RS1_SIMM13_RD, },
212 	{ "wr",		FMT3 (2, 0x30), ARG_RS1_SIMM13_RD, },
213 
214 	{ "save",	FMT3I(2,0x3c), ARG_RS1_SIMM13_RD, },
215 	{ "save",	FMT3 (2,0x3c), ARG_RS1_RS2_RD,    },
216 	{ "restore",	FMT3I(2,0x3d), ARG_RS1_SIMM13_RD, },
217 	{ "restore",	FMT3 (2,0x3d), ARG_RS1_RS2_RD,    },
218 	{ "ta",		TICC(8), { ARG_SWTRAP, ARG_NONE }, },
219 	{ "jmpl",	FMT3I(2,0x38), ARG_RS1_SIMM13_RD, },
220 	{ "jmpl",	FMT3 (2,0x38), ARG_RS1_RS2_RD,    },
221 
222 	{ "ldx",	FMT3I(3,0x0b), ARG_RS1_SIMM13_RD, },
223 	{ "ldx",	FMT3 (3,0x0b), ARG_RS1_RS2_RD,    },
224 	{ "lduw",	FMT3I(3,0x00), ARG_RS1_SIMM13_RD, },
225 	{ "lduw",	FMT3 (3,0x00), ARG_RS1_RS2_RD,    },
226 	{ "lduh",	FMT3I(3,0x02), ARG_RS1_SIMM13_RD, },
227 	{ "lduh",	FMT3 (3,0x02), ARG_RS1_RS2_RD,    },
228 	{ "ldub",	FMT3I(3,0x01), ARG_RS1_SIMM13_RD, },
229 	{ "ldub",	FMT3 (3,0x01), ARG_RS1_RS2_RD,    },
230 
231 	{ "stx",	FMT3I(3,0x0e), ARG_RS1_SIMM13_RD, },
232 	{ "stx",	FMT3 (3,0x0e), ARG_RS1_RS2_RD,    },
233 	{ "stw",	FMT3I(3,0x04), ARG_RS1_SIMM13_RD, },
234 	{ "stw",	FMT3 (3,0x04), ARG_RS1_RS2_RD,    },
235 	{ "sth",	FMT3I(3,0x06), ARG_RS1_SIMM13_RD, },
236 	{ "sth",	FMT3 (3,0x06), ARG_RS1_RS2_RD,    },
237 	{ "stb",	FMT3I(3,0x05), ARG_RS1_SIMM13_RD, },
238 	{ "stb",	FMT3 (3,0x05), ARG_RS1_RS2_RD,    },
239 
240 	{ "ldf",	FMT3I(3,0x20), ARG_RS1_SIMM13_RD, },
241 	{ "ldf",	FMT3 (3,0x20), ARG_RS1_RS2_RD,    },
242 	{ "stf",	FMT3I(3,0x24), ARG_RS1_SIMM13_RD, },
243 	{ "stf",	FMT3 (3,0x24), ARG_RS1_RS2_RD, },
244 
245 	{ "fadd",	FMT3F(2,0x34,0x041), ARG_RS1_RS2_RD, },
246 	{ "fsub",	FMT3F(2,0x34,0x045), ARG_RS1_RS2_RD, },
247 	{ "fcmp",	FMT3F(2,0x35,0x051), ARG_RS1_RS2, },
248 	{ "fstoi",	FMT3F(2,0x34,0x0d1), ARG_RS2_RD, },
249 	{ "fitos",	FMT3F(2,0x34,0x0c4), ARG_RS2_RD, },
250 
251 	{ "fneg",	FMT3F(2,0x34,0x005), ARG_RS2_RD, },
252 	{ "fdiv",	FMT3F(2,0x34,0x04d), ARG_RS1_RS2_RD, },
253 	{ "fmul",	FMT3F(2,0x34,0x049), ARG_RS1_RS2_RD, },
254 
255 	{ "fbe",	BFCC(0,9), { ARG_DISP22 }, },
256 	{ "fbne",	BFCC(0,1), { ARG_DISP22 }, },
257 	{ "fbl",	BFCC(0,4), { ARG_DISP22 }, },
258 	{ "fbge",	BFCC(0,11), { ARG_DISP22 }, },
259 	{ "fbg",	BFCC(0,6), { ARG_DISP22 }, },
260 	{ "fble",	BFCC(0,13), { ARG_DISP22 }, },
261 };
262 #define SPARC_NUM_OPCODES (sizeof(sparc_opcodes) / sizeof(sparc_opcodes[0]))
263 
264 #define RS1(X)			(((X) & 0x1f) << 14)
265 #define RS2(X)			(((X) & 0x1f) << 0)
266 #define RD(X)			(((X) & 0x1f) << 25)
267 #define SIMM13(X)		(((X) & 0x1fff) << 0)
268 #define IMM22(X)		(((X) & 0x3fffff) << 0)
269 #define DISP30(X)		((((X) >> 2) & 0x3fffffff) << 0)
270 #define DISP22(X)		((((X) >> 2) & 0x3fffff) << 0)
271 #define SWTRAP(X)		(((X) & 0x7f) << 0)
272 
273 #define SIMM13_P(X)		((unsigned int) (X) + 0x1000 < 0x2000)
274 
vimm(unsigned int val,int bits,int shift,int sgned,int arg_index)275 static void vimm(unsigned int val, int bits, int shift, int sgned, int arg_index)
276 {
277 	unsigned int orig_val = val;
278 	int orig_bits = bits;
279 
280 	if (sgned) {
281 		int x = (int) val;
282 		if (x < 0)
283 			x = -x;
284 		val = (unsigned int) x;
285 		bits--;
286 	}
287 	if (val & ~((1U << bits) - 1U)) {
288 		Com_Printf("VM ERROR: immediate value 0x%08x out of %d bit range\n",
289 			   orig_val, orig_bits);
290 		DIE("sparc VM bug");
291 	}
292 }
293 
sparc_assemble(enum sparc_iname iname,const int argc,const int * argv)294 static unsigned int sparc_assemble(enum sparc_iname iname, const int argc, const int *argv)
295 {
296 	const struct sparc_opcode *op = &sparc_opcodes[iname];
297 	unsigned int insn = op->opcode;
298 	int i, flt, rd_flt;
299 
300 	flt = (op->name[0] == 'f');
301 	rd_flt = flt || (op->name[2] == 'f');
302 
303 	for (i = 0; op->args[i] != ARG_NONE; i++) {
304 		int val = argv[i];
305 
306 		switch (op->args[i]) {
307 		case ARG_RS1: insn |= RS1(val); break;
308 		case ARG_RS2: insn |= RS2(val); break;
309 		case ARG_RD:  insn |= RD(val); break;
310 		case ARG_SIMM13: insn |= SIMM13(val); vimm(val,13,0,1,i); break;
311 		case ARG_DISP30: insn |= DISP30(val); vimm(val,30,0,1,i); break;
312 		case ARG_IMM22: insn |= IMM22(val); vimm(val,22,0,0,i); break;
313 		case ARG_DISP22: insn |= DISP22(val); vimm(val,22,0,1,i); break;
314 		case ARG_SWTRAP: insn |= SWTRAP(val); vimm(val,7,0,0,i); break;
315 		}
316 	}
317 
318 	return insn;
319 }
320 
321 #define IN(inst, args...) \
322 ({	const int argv[] = { args }; \
323 	const int argc = sizeof(argv) / sizeof(argv[0]); \
324 	sparc_assemble(inst, argc, argv); \
325 })
326 
327 #if 0
328 static void pgreg(int reg_num, int arg_index, int flt)
329 {
330 	if (!flt) {
331 		const char *fmt[] = { "%g", "%o", "%l", "%i" };
332 
333 		Com_Printf("%s%s%d",
334 			   (arg_index ? ", " : ""),
335 			   fmt[reg_num >> 3], reg_num & 7);
336 	} else
337 		Com_Printf("%s%%f%d", (arg_index ? ", " : ""), reg_num);
338 }
339 
340 static void pimm(unsigned int val, int bits, int shift, int sgned, int arg_index)
341 
342 {
343 	val >>= shift;
344 	val &= ((1 << bits) - 1);
345 	if (sgned) {
346 		int sval = val << (32 - bits);
347 		sval >>= (32 - bits);
348 		Com_Printf("%s%d",
349 			   (arg_index ? ", " : ""), sval);
350 	} else
351 		Com_Printf("%s0x%08x",
352 			   (arg_index ? ", " : ""), val);
353 }
354 
355 static void sparc_disassemble(unsigned int insn)
356 {
357 	int op_idx;
358 
359 	for (op_idx = 0; op_idx < SPARC_NUM_OPCODES; op_idx++) {
360 		const struct sparc_opcode *op = &sparc_opcodes[op_idx];
361 		int i, flt, rd_flt;
362 
363 		if ((insn & op->mask) != op->opcode)
364 			continue;
365 
366 		flt = (op->name[0] == 'f');
367 		rd_flt = flt || (op->name[2] == 'f');
368 
369 		Com_Printf("ASM: %7s\t", op->name);
370 		for (i = 0; op->args[i] != ARG_NONE; i++) {
371 			switch (op->args[i]) {
372 			case ARG_RS1: pgreg((insn >> 14) & 0x1f, i, flt); break;
373 			case ARG_RS2: pgreg((insn >> 0) & 0x1f, i, flt); break;
374 			case ARG_RD:  pgreg((insn >> 25) & 0x1f, i, rd_flt); break;
375 			case ARG_SIMM13: pimm(insn, 13, 0, 1, i); break;
376 			case ARG_DISP30: pimm(insn, 30, 0, 0, i); break;
377 			case ARG_IMM22: pimm(insn, 22, 0, 0, i); break;
378 			case ARG_DISP22: pimm(insn, 22, 0, 0, i); break;
379 			case ARG_SWTRAP: pimm(insn, 7, 0, 0, i); break;
380 			}
381 		}
382 		Com_Printf("\n");
383 		return;
384 	}
385 }
386 #endif
387 
388 /*
389  * opcode information table:
390  * - length of immediate value
391  * - returned register type
392  * - required register(s) type
393  */
394 #define opImm0	0x0000 /* no immediate */
395 #define opImm1	0x0001 /* 1 byte immadiate value after opcode */
396 #define opImm4	0x0002 /* 4 bytes immediate value after opcode */
397 
398 #define opRet0	0x0000 /* returns nothing */
399 #define opRetI	0x0004 /* returns integer */
400 #define opRetF	0x0008 /* returns float */
401 #define opRetIF	(opRetI | opRetF) /* returns integer or float */
402 
403 #define opArg0	0x0000 /* requires nothing */
404 #define opArgI	0x0010 /* requires integer(s) */
405 #define opArgF	0x0020 /* requires float(s) */
406 #define opArgIF	(opArgI | opArgF) /* requires integer or float */
407 
408 #define opArg2I	0x0040 /* requires second argument, integer */
409 #define opArg2F	0x0080 /* requires second argument, float */
410 #define opArg2IF (opArg2I | opArg2F) /* requires second argument, integer or float */
411 
412 static const unsigned char vm_opInfo[256] =
413 {
414 	[OP_UNDEF]	= opImm0,
415 	[OP_IGNORE]	= opImm0,
416 	[OP_BREAK]	= opImm0,
417 	[OP_ENTER]	= opImm4,
418 			/* OP_LEAVE has to accept floats, they will be converted to ints */
419 	[OP_LEAVE]	= opImm4 | opRet0 | opArgIF,
420 			/* only STORE4 and POP use values from OP_CALL,
421 			 * no need to convert floats back */
422 	[OP_CALL]	= opImm0 | opRetI | opArgI,
423 	[OP_PUSH]	= opImm0 | opRetIF,
424 	[OP_POP]	= opImm0 | opRet0 | opArgIF,
425 	[OP_CONST]	= opImm4 | opRetIF,
426 	[OP_LOCAL]	= opImm4 | opRetI,
427 	[OP_JUMP]	= opImm0 | opRet0 | opArgI,
428 
429 	[OP_EQ]		= opImm4 | opRet0 | opArgI | opArg2I,
430 	[OP_NE]		= opImm4 | opRet0 | opArgI | opArg2I,
431 	[OP_LTI]	= opImm4 | opRet0 | opArgI | opArg2I,
432 	[OP_LEI]	= opImm4 | opRet0 | opArgI | opArg2I,
433 	[OP_GTI]	= opImm4 | opRet0 | opArgI | opArg2I,
434 	[OP_GEI]	= opImm4 | opRet0 | opArgI | opArg2I,
435 	[OP_LTU]	= opImm4 | opRet0 | opArgI | opArg2I,
436 	[OP_LEU]	= opImm4 | opRet0 | opArgI | opArg2I,
437 	[OP_GTU]	= opImm4 | opRet0 | opArgI | opArg2I,
438 	[OP_GEU]	= opImm4 | opRet0 | opArgI | opArg2I,
439 	[OP_EQF]	= opImm4 | opRet0 | opArgF | opArg2F,
440 	[OP_NEF]	= opImm4 | opRet0 | opArgF | opArg2F,
441 	[OP_LTF]	= opImm4 | opRet0 | opArgF | opArg2F,
442 	[OP_LEF]	= opImm4 | opRet0 | opArgF | opArg2F,
443 	[OP_GTF]	= opImm4 | opRet0 | opArgF | opArg2F,
444 	[OP_GEF]	= opImm4 | opRet0 | opArgF | opArg2F,
445 
446 	[OP_LOAD1]	= opImm0 | opRetI | opArgI,
447 	[OP_LOAD2]	= opImm0 | opRetI | opArgI,
448 	[OP_LOAD4]	= opImm0 | opRetIF| opArgI,
449 	[OP_STORE1]	= opImm0 | opRet0 | opArgI | opArg2I,
450 	[OP_STORE2]	= opImm0 | opRet0 | opArgI | opArg2I,
451 	[OP_STORE4]	= opImm0 | opRet0 | opArgIF| opArg2I,
452 	[OP_ARG]	= opImm1 | opRet0 | opArgIF,
453 	[OP_BLOCK_COPY]	= opImm4 | opRet0 | opArgI | opArg2I,
454 
455 	[OP_SEX8]	= opImm0 | opRetI | opArgI,
456 	[OP_SEX16]	= opImm0 | opRetI | opArgI,
457 	[OP_NEGI]	= opImm0 | opRetI | opArgI,
458 	[OP_ADD]	= opImm0 | opRetI | opArgI | opArg2I,
459 	[OP_SUB]	= opImm0 | opRetI | opArgI | opArg2I,
460 	[OP_DIVI]	= opImm0 | opRetI | opArgI | opArg2I,
461 	[OP_DIVU]	= opImm0 | opRetI | opArgI | opArg2I,
462 	[OP_MODI]	= opImm0 | opRetI | opArgI | opArg2I,
463 	[OP_MODU]	= opImm0 | opRetI | opArgI | opArg2I,
464 	[OP_MULI]	= opImm0 | opRetI | opArgI | opArg2I,
465 	[OP_MULU]	= opImm0 | opRetI | opArgI | opArg2I,
466 	[OP_BAND]	= opImm0 | opRetI | opArgI | opArg2I,
467 	[OP_BOR]	= opImm0 | opRetI | opArgI | opArg2I,
468 	[OP_BXOR]	= opImm0 | opRetI | opArgI | opArg2I,
469 	[OP_BCOM]	= opImm0 | opRetI | opArgI,
470 	[OP_LSH]	= opImm0 | opRetI | opArgI | opArg2I,
471 	[OP_RSHI]	= opImm0 | opRetI | opArgI | opArg2I,
472 	[OP_RSHU]	= opImm0 | opRetI | opArgI | opArg2I,
473 	[OP_NEGF]	= opImm0 | opRetF | opArgF,
474 	[OP_ADDF]	= opImm0 | opRetF | opArgF | opArg2F,
475 	[OP_SUBF]	= opImm0 | opRetF | opArgF | opArg2F,
476 	[OP_DIVF]	= opImm0 | opRetF | opArgF | opArg2F,
477 	[OP_MULF]	= opImm0 | opRetF | opArgF | opArg2F,
478 	[OP_CVIF]	= opImm0 | opRetF | opArgI,
479 	[OP_CVFI]	= opImm0 | opRetI | opArgF,
480 };
481 
482 static const char *opnames[256] = {
483 	"OP_UNDEF", "OP_IGNORE", "OP_BREAK", "OP_ENTER", "OP_LEAVE", "OP_CALL",
484 	"OP_PUSH", "OP_POP", "OP_CONST", "OP_LOCAL", "OP_JUMP",
485 	"OP_EQ", "OP_NE", "OP_LTI", "OP_LEI", "OP_GTI", "OP_GEI",
486 	"OP_LTU", "OP_LEU", "OP_GTU", "OP_GEU", "OP_EQF", "OP_NEF",
487 	"OP_LTF", "OP_LEF", "OP_GTF", "OP_GEF",
488 	"OP_LOAD1", "OP_LOAD2", "OP_LOAD4", "OP_STORE1", "OP_STORE2",
489 	"OP_STORE4", "OP_ARG", "OP_BLOCK_COPY",
490 	"OP_SEX8", "OP_SEX16",
491 	"OP_NEGI", "OP_ADD", "OP_SUB", "OP_DIVI", "OP_DIVU",
492 	"OP_MODI", "OP_MODU", "OP_MULI", "OP_MULU", "OP_BAND",
493 	"OP_BOR", "OP_BXOR", "OP_BCOM", "OP_LSH", "OP_RSHI", "OP_RSHU",
494 	"OP_NEGF", "OP_ADDF", "OP_SUBF", "OP_DIVF", "OP_MULF",
495 	"OP_CVIF", "OP_CVFI",
496 };
497 
VM_Destroy_Compiled(vm_t * vm)498 static void VM_Destroy_Compiled(vm_t *vm)
499 {
500 	if (vm->codeBase) {
501 		if (munmap(vm->codeBase, vm->codeLength))
502 			Com_Printf(S_COLOR_RED "Memory unmap failed, possible memory leak\n");
503 	}
504 	vm->codeBase = NULL;
505 }
506 
507 typedef struct VM_Data {
508 	unsigned int dataLength;
509 	unsigned int codeLength;
510 	unsigned int *CallThunk;
511 	int (*AsmCall)(int, int);
512 	void (*BlockCopy)(unsigned int, unsigned int, unsigned int);
513 	unsigned int *iPointers;
514 	unsigned int data[0];
515 } vm_data_t;
516 
517 #ifdef offsetof
518 # define VM_Data_Offset(field)		offsetof(vm_data_t, field)
519 #else
520 # define OFFSET(structName, field) \
521 	((void *)&(((structName *)NULL)->field) - NULL)
522 # define VM_Data_Offset(field)		OFFSET(vm_data_t, field)
523 #endif
524 
525 struct src_insn {
526 	unsigned char		op;
527 	unsigned int		i_count;
528 
529 	union {
530 		unsigned int	i;
531 		signed int	si;
532 		signed short	ss[2];
533 		unsigned short	us[2];
534 		unsigned char	b;
535 	} arg;
536 
537 	unsigned char		dst_reg_flags;
538 	unsigned char		src1_reg_flags;
539 	unsigned char		src2_reg_flags;
540 #define REG_FLAGS_FLOAT		0x1
541 
542 	struct src_insn		*next;
543 };
544 
545 struct dst_insn;
546 struct jump_insn {
547 	enum sparc_iname	jump_iname;
548 	int			jump_dest_insn;
549 	struct dst_insn		*parent;
550 	struct jump_insn	*next;
551 };
552 
553 struct dst_insn {
554 	struct dst_insn		*next;
555 
556 	unsigned int		count;
557 	unsigned int		i_count;
558 
559 	struct jump_insn	*jump;
560 	unsigned int		length;
561 	unsigned int		code[0];
562 };
563 
564 #define HUNK_SIZE		29
565 struct data_hunk {
566 	struct data_hunk *next;
567 	int count;
568 	unsigned int data[HUNK_SIZE];
569 };
570 
571 struct func_info {
572 	struct src_insn		*first;
573 	struct src_insn		*last;
574 	int			has_call;
575 	int			need_float_tmp;
576 
577 	struct src_insn		*cached_const;
578 
579 	int			stack_space;
580 	int			gpr_pos;
581 #define rFIRST(fp)		((fp)->gpr_pos - 1)
582 #define rSECOND(fp)		((fp)->gpr_pos - 2)
583 #define POP_GPR(fp)		((fp)->gpr_pos--)
584 #define PUSH_GPR(fp)		((fp)->gpr_pos++)
585 
586 	int			fpr_pos;
587 #define fFIRST(fp)		((fp)->fpr_pos - 1)
588 #define fSECOND(fp)		((fp)->fpr_pos - 2)
589 #define POP_FPR(fp)		((fp)->fpr_pos--)
590 #define PUSH_FPR(fp)		((fp)->fpr_pos++)
591 
592 #define INSN_BUF_SIZE		50
593 	unsigned int		insn_buf[INSN_BUF_SIZE];
594 	int			insn_index;
595 
596 	int			saved_icount;
597 	int			force_emit;
598 
599 	struct jump_insn	*jump_first;
600 	struct jump_insn	*jump_last;
601 
602 	struct dst_insn		*dst_first;
603 	struct dst_insn		*dst_last;
604 	int			dst_count;
605 
606 	struct dst_insn		**dst_by_i_count;
607 
608 	struct data_hunk	*data_first;
609 	int			data_num;
610 };
611 
612 #define THUNK_ICOUNT		-1
613 
sparc_push_data(struct func_info * const fp,unsigned int val)614 static unsigned int sparc_push_data(struct func_info * const fp, unsigned int val)
615 {
616 	struct data_hunk *last, *dp = fp->data_first;
617 	int off = 0;
618 
619 	last = NULL;
620 	while (dp) {
621 		int i;
622 
623 		for (i = 0; i < dp->count; i++) {
624 			if (dp->data[i] == val) {
625 				off += i;
626 				return VM_Data_Offset(data[off]);
627 			}
628 		}
629 		off += dp->count;
630 		last = dp;
631 		dp = dp->next;
632 	}
633 
634 	dp = last;
635 	if (!dp || dp->count >= HUNK_SIZE) {
636 		struct data_hunk *new = Z_Malloc(sizeof(*new));
637 		if (!dp)
638 			fp->data_first = new;
639 		else
640 			dp->next = new;
641 		dp = new;
642 		dp->count = 0;
643 		dp->next = NULL;
644 	}
645 	dp->data[dp->count++] = val;
646 	fp->data_num = off + 1;
647 	return VM_Data_Offset(data[off]);
648 }
649 
dst_insn_insert_tail(struct func_info * const fp,struct dst_insn * dp)650 static void dst_insn_insert_tail(struct func_info * const fp,
651 				 struct dst_insn *dp)
652 {
653 	if (!fp->dst_first) {
654 		fp->dst_first = fp->dst_last = dp;
655 	} else {
656 		fp->dst_last->next = dp;
657 		fp->dst_last = dp;
658 	}
659 }
660 
jump_insn_insert_tail(struct func_info * const fp,struct jump_insn * jp)661 static void jump_insn_insert_tail(struct func_info * const fp,
662 				  struct jump_insn *jp)
663 {
664 	if (!fp->jump_first) {
665 		fp->jump_first = fp->jump_last = jp;
666 	} else {
667 		fp->jump_last->next = jp;
668 		fp->jump_last = jp;
669 	}
670 }
671 
dst_new(struct func_info * const fp,unsigned int length,struct jump_insn * jp,int insns_size)672 static struct dst_insn *dst_new(struct func_info * const fp, unsigned int length,
673 				struct jump_insn *jp, int insns_size)
674 {
675 	struct dst_insn *dp = Z_Malloc(sizeof(struct dst_insn) + insns_size);
676 
677 	dp->length = length;
678 	dp->jump = jp;
679 	dp->count = fp->dst_count++;
680 	dp->i_count = fp->saved_icount;
681 	dp->next = NULL;
682 	if (fp->saved_icount != THUNK_ICOUNT)
683 		fp->dst_by_i_count[fp->saved_icount] = dp;
684 
685 	return dp;
686 }
687 
dst_insn_append(struct func_info * const fp)688 static void dst_insn_append(struct func_info * const fp)
689 {
690 	int insns_size = (sizeof(unsigned int) * fp->insn_index);
691 	struct dst_insn *dp;
692 
693 	dp = dst_new(fp, fp->insn_index, NULL, insns_size);
694 	if (insns_size)
695 		memcpy(&dp->code[0], fp->insn_buf, insns_size);
696 	dst_insn_insert_tail(fp, dp);
697 
698 	fp->insn_index = 0;
699 }
700 
jump_insn_append(struct func_info * const fp,enum sparc_iname iname,int dest)701 static void jump_insn_append(struct func_info * const fp, enum sparc_iname iname, int dest)
702 {
703 	struct jump_insn *jp = Z_Malloc(sizeof(*jp));
704 	struct dst_insn *dp;
705 
706 	dp = dst_new(fp, 2, jp, 0);
707 
708 	jp->jump_iname = iname;
709 	jp->jump_dest_insn = dest;
710 	jp->parent = dp;
711 	jp->next = NULL;
712 
713 	jump_insn_insert_tail(fp, jp);
714 	dst_insn_insert_tail(fp, dp);
715 }
716 
start_emit(struct func_info * const fp,int i_count)717 static void start_emit(struct func_info * const fp, int i_count)
718 {
719 	fp->saved_icount = i_count;
720 	fp->insn_index = 0;
721 	fp->force_emit = 0;
722 }
723 
__do_emit_one(struct func_info * const fp,unsigned int insn)724 static void __do_emit_one(struct func_info * const fp, unsigned int insn)
725 {
726 	fp->insn_buf[fp->insn_index++] = insn;
727 }
728 
729 #define in(inst, args...) __do_emit_one(fp,  IN(inst, args))
730 
end_emit(struct func_info * const fp)731 static void end_emit(struct func_info * const fp)
732 {
733 	if (fp->insn_index || fp->force_emit)
734 		dst_insn_append(fp);
735 }
736 
emit_jump(struct func_info * const fp,enum sparc_iname iname,int dest)737 static void emit_jump(struct func_info * const fp, enum sparc_iname iname, int dest)
738 {
739 	end_emit(fp);
740 	jump_insn_append(fp, iname, dest);
741 }
742 
analyze_function(struct func_info * const fp)743 static void analyze_function(struct func_info * const fp)
744 {
745 	struct src_insn *value_provider[20] = { NULL };
746 	struct src_insn *sp = fp->first;
747 	int opstack_depth = 0;
748 
749 	while ((sp = sp->next) != NULL) {
750 		unsigned char opi, op = sp->op;
751 
752 		opi = vm_opInfo[op];
753 		if (opi & opArgIF) {
754 			struct src_insn *vp = value_provider[--opstack_depth];
755 			unsigned char vpopi = vm_opInfo[vp->op];
756 
757 			if ((opi & opArgI) && (vpopi & opRetI)) {
758 				/* src1 and dst are integers */
759 			} else if ((opi & opArgF) && (vpopi & opRetF)) {
760 				/* src1 and dst are floats */
761 				vp->dst_reg_flags |= REG_FLAGS_FLOAT;
762 				sp->src1_reg_flags = REG_FLAGS_FLOAT;
763 			} else {
764 				/* illegal combination */
765 				DIE("unrecognized instruction combination");
766 			}
767 		}
768 		if (opi & opArg2IF) {
769 			struct src_insn *vp = value_provider[--opstack_depth];
770 			unsigned char vpopi = vm_opInfo[vp->op];
771 
772 			if ((opi & opArg2I) && (vpopi & opRetI)) {
773 				/* src2 and dst are integers */
774 			} else if ( (opi & opArg2F) && (vpopi & opRetF) ) {
775 				/* src2 and dst are floats */
776 				vp->dst_reg_flags |= REG_FLAGS_FLOAT;
777 				sp->src2_reg_flags = REG_FLAGS_FLOAT;
778 			} else {
779 				/* illegal combination */
780 				DIE("unrecognized instruction combination");
781 			}
782 		}
783 		if (opi & opRetIF) {
784 			value_provider[opstack_depth] = sp;
785 			opstack_depth++;
786 		}
787 	}
788 }
789 
asmcall(int call,int pstack)790 static int asmcall(int call, int pstack)
791 {
792 	vm_t *savedVM = currentVM;
793 	int i, ret;
794 
795 	currentVM->programStack = pstack - 4;
796 	if (sizeof(intptr_t) == sizeof(int)) {
797 		intptr_t *argPosition = (intptr_t *)((byte *)currentVM->dataBase + pstack + 4);
798 		argPosition[0] = -1 - call;
799 		ret = currentVM->systemCall(argPosition);
800 	} else {
801 		intptr_t args[11];
802 
803 		args[0] = -1 - call;
804 		int *argPosition = (int *)((byte *)currentVM->dataBase + pstack + 4);
805 		for( i = 1; i < 11; i++ )
806 			args[i] = argPosition[i];
807 
808 		ret = currentVM->systemCall(args);
809 	}
810 
811 	currentVM = savedVM;
812 
813 	return ret;
814 }
815 
blockcopy(unsigned int dest,unsigned int src,unsigned int count)816 static void blockcopy(unsigned int dest, unsigned int src, unsigned int count)
817 {
818 	unsigned int dataMask = currentVM->dataMask;
819 
820 	if ((dest & dataMask) != dest ||
821 	    (src & dataMask) != src ||
822 	    ((dest+count) & dataMask) != dest + count ||
823 	    ((src+count) & dataMask) != src + count) {
824 		DIE("OP_BLOCK_COPY out of range!");
825 	}
826 
827 	memcpy(currentVM->dataBase+dest, currentVM->dataBase+src, count);
828 }
829 
do_emit_const(struct func_info * const fp,struct src_insn * sp)830 static void do_emit_const(struct func_info * const fp, struct src_insn *sp)
831 {
832 	start_emit(fp, sp->i_count);
833 	if (sp->dst_reg_flags & REG_FLAGS_FLOAT) {
834 		in(LDFI, rVMDATA, sparc_push_data(fp, sp->arg.i), fFIRST(fp));
835 	} else {
836 		if ((sp->arg.i & ~0x3ff) == 0) {
837 			in(ORI, G0, sp->arg.i & 0x3ff, rFIRST(fp));
838 		} else if ((sp->arg.i & 0x3ff) == 0) {
839 			in(SETHI, sp->arg.i >> 10, rFIRST(fp));
840 		} else {
841 			in(SETHI, sp->arg.i >> 10, rFIRST(fp));
842 			in(ORI, rFIRST(fp), sp->arg.i & 0x3ff, rFIRST(fp));
843 		}
844 	}
845 	end_emit(fp);
846 }
847 
848 #define MAYBE_EMIT_CONST(fp)	\
849 do {	if ((fp)->cached_const) {	       \
850 		int saved_i_count = (fp)->saved_icount; \
851 		do_emit_const(fp, (fp)->cached_const); \
852 		(fp)->saved_icount = saved_i_count; \
853 	} \
854 } while (0)
855 
856 #define EMIT_FALSE_CONST(fp)					\
857 do {	int saved_i_count = (fp)->saved_icount;			\
858 	(fp)->saved_icount = (fp)->cached_const->i_count;	\
859 	dst_insn_append(fp);					\
860 	(fp)->saved_icount = saved_i_count;			\
861 } while (0)
862 
compile_one_insn(struct func_info * const fp,struct src_insn * sp)863 static void compile_one_insn(struct func_info * const fp, struct src_insn *sp)
864 {
865 	start_emit(fp, sp->i_count);
866 
867 	switch (sp->op) {
868 	default:
869 		Com_Printf("VM: Unhandled opcode 0x%02x[%s]\n",
870 			   sp->op,
871 			   opnames[sp->op] ? opnames[sp->op] : "UNKNOWN");
872 		DIE("Unsupported opcode");
873 		break;
874 
875 	case OP_ENTER: {
876 		int stack = SL(64, 128);
877 
878 		if (fp->need_float_tmp)
879 			stack += 16;
880 
881 		in(SAVEI, O6, -stack, O6);
882 		if (!SIMM13_P(sp->arg.si)) {
883 			in(SETHI, sp->arg.i >> 10, rTMP);
884 			in(ORI, rTMP, sp->arg.i & 0x3ff, rTMP);
885 			in(SUB, rPSTACK, rTMP, rPSTACK);
886 		} else
887 			in(SUBI, rPSTACK, sp->arg.si, rPSTACK);
888 		break;
889 	}
890 	case OP_LEAVE:
891 		if (fp->cached_const && SIMM13_P(fp->cached_const->arg.si)) {
892 			EMIT_FALSE_CONST(fp);
893 			if (fp->cached_const->src1_reg_flags & REG_FLAGS_FLOAT)
894 				DIE("constant float in OP_LEAVE");
895 
896 			if (!SIMM13_P(sp->arg.si)) {
897 				in(SETHI, sp->arg.i >> 10, rTMP);
898 				in(ORI, rTMP, sp->arg.i & 0x3ff, rTMP);
899 				in(ADD, rPSTACK, rTMP, rPSTACK);
900 			} else
901 				in(ADDI, rPSTACK, sp->arg.si, rPSTACK);
902 			in(JMPLI, I7, 8, G0);
903 			in(RESTOREI, G0, fp->cached_const->arg.si, O0);
904 			POP_GPR(fp);
905 		} else {
906 			MAYBE_EMIT_CONST(fp);
907 			if (!SIMM13_P(sp->arg.si)) {
908 				in(SETHI, sp->arg.i >> 10, rTMP);
909 				in(ORI, rTMP, sp->arg.i & 0x3ff, rTMP);
910 				in(ADD, rPSTACK, rTMP, rPSTACK);
911 			} else
912 				in(ADDI, rPSTACK, sp->arg.si, rPSTACK);
913 			if (sp->src1_reg_flags & REG_FLAGS_FLOAT) {
914 				in(STFI, O6, SL(64, 128), fFIRST(fp));
915 				in(LDUWI, O6, SL(64, 128), O0);
916 				in(JMPLI, I7, 8, G0);
917 				in(RESTORE, O0, G0, O0);
918 				POP_FPR(fp);
919 			} else {
920 				in(JMPLI, I7, 8, G0);
921 				in(RESTORE, rFIRST(fp), G0, O0);
922 				POP_GPR(fp);
923 			}
924 		}
925 		assert(fp->gpr_pos == L0);
926 		assert(fp->fpr_pos == F0);
927 		break;
928 	case OP_JUMP:
929 		if (fp->cached_const) {
930 			EMIT_FALSE_CONST(fp);
931 			emit_jump(fp, BA, fp->cached_const->arg.i);
932 		} else {
933 			MAYBE_EMIT_CONST(fp);
934 			in(LDLI, rVMDATA, VM_Data_Offset(iPointers), rTMP);
935 			in(SLLI, rFIRST(fp), 2, rFIRST(fp));
936 			in(LDL, rTMP, rFIRST(fp), rTMP);
937 			in(JMPL, rTMP, G0, G0);
938 			in(NOP);
939 		}
940 		POP_GPR(fp);
941 		break;
942 	case OP_CALL:
943 		if (fp->cached_const) {
944 			EMIT_FALSE_CONST(fp);
945 			if (fp->cached_const->arg.si >= 0) {
946 				emit_jump(fp, CALL, fp->cached_const->arg.i);
947 			} else {
948 				in(LDLI, rVMDATA, VM_Data_Offset(CallThunk), rTMP);
949 				in(LDLI, rVMDATA, VM_Data_Offset(AsmCall), O3);
950 				in(ORI, G0, fp->cached_const->arg.si, O0);
951 				in(JMPL, rTMP, G0, O7);
952 				in(OR, G0, rPSTACK, O1);
953 			}
954 			in(OR, G0, O0, rFIRST(fp));
955 		} else {
956 			MAYBE_EMIT_CONST(fp);
957 			in(SUBCCI, rFIRST(fp), 0, G0);
958 			in(BL, +4*7);
959 			in(NOP);
960 
961 			/* normal call */
962 			in(LDLI, rVMDATA, VM_Data_Offset(iPointers), O5);
963 			in(SLLI, rFIRST(fp), 2, rFIRST(fp));
964 			in(LDL, O5, rFIRST(fp), rTMP);
965 			in(BA, +4*4);
966 			in(NOP);
967 
968 			/* syscall */
969 			in(LDLI, rVMDATA, VM_Data_Offset(CallThunk), rTMP);
970 			in(LDLI, rVMDATA, VM_Data_Offset(AsmCall), O3);
971 
972 			in(OR, G0, rFIRST(fp), O0);
973 			in(JMPL, rTMP, G0, O7);
974 			in(OR, G0, rPSTACK, O1);
975 
976 			/* return value */
977 			in(OR, G0, O0, rFIRST(fp));
978 		}
979 		break;
980 	case OP_BLOCK_COPY:
981 		MAYBE_EMIT_CONST(fp);
982 		in(LDLI, rVMDATA, VM_Data_Offset(CallThunk), rTMP);
983 		in(LDLI, rVMDATA, VM_Data_Offset(BlockCopy), O3);
984 		in(OR, G0, rSECOND(fp), O0);
985 		in(OR, G0, rFIRST(fp), O1);
986 		if ((sp->arg.i & ~0x3ff) == 0) {
987 			in(ORI, G0, sp->arg.i & 0x3ff, O2);
988 		} else if ((sp->arg.i & 0x3ff) == 0) {
989 			in(SETHI, sp->arg.i >> 10, O2);
990 		} else {
991 			in(SETHI, sp->arg.i >> 10, O2);
992 			in(ORI, O2, sp->arg.i & 0x3ff, O2);
993 		}
994 		in(JMPL, rTMP, G0, O7);
995 		in(NOP);
996 		POP_GPR(fp);
997 		POP_GPR(fp);
998 		break;
999 
1000 	case OP_PUSH:
1001 		MAYBE_EMIT_CONST(fp);
1002 		if (sp->dst_reg_flags & REG_FLAGS_FLOAT)
1003 			PUSH_FPR(fp);
1004 		else
1005 			PUSH_GPR(fp);
1006 		fp->force_emit = 1;
1007 		break;
1008 	case OP_POP:
1009 		MAYBE_EMIT_CONST(fp);
1010 		if (sp->src1_reg_flags & REG_FLAGS_FLOAT)
1011 			POP_FPR(fp);
1012 		else
1013 			POP_GPR(fp);
1014 		fp->force_emit = 1;
1015 		break;
1016 	case OP_ARG:
1017 		MAYBE_EMIT_CONST(fp);
1018 		in(ADDI, rPSTACK, sp->arg.b, rTMP);
1019 		if (sp->src1_reg_flags & REG_FLAGS_FLOAT) {
1020 			in(STF, rDATABASE, rTMP, fFIRST(fp));
1021 			POP_FPR(fp);
1022 		} else {
1023 			in(STW, rDATABASE, rTMP, rFIRST(fp));
1024 			POP_GPR(fp);
1025 		}
1026 		break;
1027 	case OP_IGNORE:
1028 		MAYBE_EMIT_CONST(fp);
1029 		in(NOP);
1030 		break;
1031 	case OP_BREAK:
1032 		MAYBE_EMIT_CONST(fp);
1033 		in(TA, 0x5);
1034 		break;
1035 	case OP_LOCAL:
1036 		MAYBE_EMIT_CONST(fp);
1037 		PUSH_GPR(fp);
1038 		if (!SIMM13_P(sp->arg.i)) {
1039 			in(SETHI, sp->arg.i >> 10, rTMP);
1040 			in(ORI, rTMP, sp->arg.i & 0x3ff, rTMP);
1041 			in(ADD, rPSTACK, rTMP, rFIRST(fp));
1042 		} else
1043 			in(ADDI, rPSTACK, sp->arg.i, rFIRST(fp));
1044 		break;
1045 	case OP_CONST:
1046 		MAYBE_EMIT_CONST(fp);
1047 		break;
1048 	case OP_LOAD4:
1049 		MAYBE_EMIT_CONST(fp);
1050 		in(AND, rFIRST(fp), rDATAMASK, rFIRST(fp));
1051 		if (sp->dst_reg_flags & REG_FLAGS_FLOAT) {
1052 			PUSH_FPR(fp);
1053 			in(LDF, rFIRST(fp), rDATABASE, fFIRST(fp));
1054 			POP_GPR(fp);
1055 		} else {
1056 			in(LDUW, rFIRST(fp), rDATABASE, rFIRST(fp));
1057 		}
1058 		break;
1059 	case OP_LOAD2:
1060 		MAYBE_EMIT_CONST(fp);
1061 		in(AND, rFIRST(fp), rDATAMASK, rFIRST(fp));
1062 		in(LDUH, rFIRST(fp), rDATABASE, rFIRST(fp));
1063 		break;
1064 	case OP_LOAD1:
1065 		MAYBE_EMIT_CONST(fp);
1066 		in(AND, rFIRST(fp), rDATAMASK, rFIRST(fp));
1067 		in(LDUB, rFIRST(fp), rDATABASE, rFIRST(fp));
1068 		break;
1069 	case OP_STORE4:
1070 		MAYBE_EMIT_CONST(fp);
1071 		if (sp->src1_reg_flags & REG_FLAGS_FLOAT) {
1072 			in(AND, rFIRST(fp), rDATAMASK, rFIRST(fp));
1073 			in(STF, rFIRST(fp), rDATABASE, fFIRST(fp));
1074 			POP_FPR(fp);
1075 		} else {
1076 			in(AND, rSECOND(fp), rDATAMASK, rSECOND(fp));
1077 			in(STW, rSECOND(fp), rDATABASE, rFIRST(fp));
1078 			POP_GPR(fp);
1079 		}
1080 		POP_GPR(fp);
1081 		break;
1082 	case OP_STORE2:
1083 		MAYBE_EMIT_CONST(fp);
1084 		in(AND, rSECOND(fp), rDATAMASK, rSECOND(fp));
1085 		in(STH, rSECOND(fp), rDATABASE, rFIRST(fp));
1086 		POP_GPR(fp);
1087 		POP_GPR(fp);
1088 		break;
1089 	case OP_STORE1:
1090 		MAYBE_EMIT_CONST(fp);
1091 		in(AND, rSECOND(fp), rDATAMASK, rSECOND(fp));
1092 		in(STB, rSECOND(fp), rDATABASE, rFIRST(fp));
1093 		POP_GPR(fp);
1094 		POP_GPR(fp);
1095 		break;
1096 	case OP_EQ:
1097 	case OP_NE:
1098 	case OP_LTI:
1099 	case OP_GEI:
1100 	case OP_GTI:
1101 	case OP_LEI:
1102 	case OP_LTU:
1103 	case OP_GEU:
1104 	case OP_GTU:
1105 	case OP_LEU: {
1106 		enum sparc_iname iname = BA;
1107 
1108 		if (fp->cached_const && SIMM13_P(fp->cached_const->arg.si)) {
1109 			EMIT_FALSE_CONST(fp);
1110 			in(SUBCCI, rSECOND(fp), fp->cached_const->arg.si, G0);
1111 		} else {
1112 			MAYBE_EMIT_CONST(fp);
1113 			in(SUBCC, rSECOND(fp), rFIRST(fp), G0);
1114 		}
1115 		switch(sp->op) {
1116 		case OP_EQ: iname = BE; break;
1117 		case OP_NE: iname = BNE; break;
1118 		case OP_LTI: iname = BL; break;
1119 		case OP_GEI: iname = BGE; break;
1120 		case OP_GTI: iname = BG; break;
1121 		case OP_LEI: iname = BLE; break;
1122 		case OP_LTU: iname = BCS; break;
1123 		case OP_GEU: iname = BCC; break;
1124 		case OP_GTU: iname = BGU; break;
1125 		case OP_LEU: iname = BLEU; break;
1126 		}
1127 		emit_jump(fp, iname, sp->arg.i);
1128 		POP_GPR(fp);
1129 		POP_GPR(fp);
1130 		break;
1131 	}
1132 
1133 	case OP_SEX8:
1134 		MAYBE_EMIT_CONST(fp);
1135 		in(SLLI, rFIRST(fp), 24, rFIRST(fp));
1136 		in(SRAI, rFIRST(fp), 24, rFIRST(fp));
1137 		break;
1138 	case OP_SEX16:
1139 		MAYBE_EMIT_CONST(fp);
1140 		in(SLLI, rFIRST(fp), 16, rFIRST(fp));
1141 		in(SRAI, rFIRST(fp), 16, rFIRST(fp));
1142 		break;
1143 	case OP_NEGI:
1144 		MAYBE_EMIT_CONST(fp);
1145 		in(SUB, G0, rFIRST(fp), rFIRST(fp));
1146 		break;
1147 	case OP_ADD:
1148 		if (fp->cached_const && SIMM13_P(fp->cached_const->arg.si)) {
1149 			EMIT_FALSE_CONST(fp);
1150 			in(ADDI, rSECOND(fp), fp->cached_const->arg.si, rSECOND(fp));
1151 		} else {
1152 			MAYBE_EMIT_CONST(fp);
1153 			in(ADD, rSECOND(fp), rFIRST(fp), rSECOND(fp));
1154 		}
1155 		POP_GPR(fp);
1156 		break;
1157 	case OP_SUB:
1158 		if (fp->cached_const && SIMM13_P(fp->cached_const->arg.si)) {
1159 			EMIT_FALSE_CONST(fp);
1160 			in(SUBI, rSECOND(fp), fp->cached_const->arg.si, rSECOND(fp));
1161 		} else {
1162 			MAYBE_EMIT_CONST(fp);
1163 			in(SUB, rSECOND(fp), rFIRST(fp), rSECOND(fp));
1164 		}
1165 		POP_GPR(fp);
1166 		break;
1167 	case OP_DIVI:
1168 		MAYBE_EMIT_CONST(fp);
1169 		in(SRAI, rSECOND(fp), 31, rTMP);
1170 		in(WRI, rTMP, 0, Y_REG);
1171 		in(SDIV, rSECOND(fp), rFIRST(fp), rSECOND(fp));
1172 		POP_GPR(fp);
1173 		break;
1174 	case OP_DIVU:
1175 		MAYBE_EMIT_CONST(fp);
1176 		in(WRI, G0, 0, Y_REG);
1177 		in(UDIV, rSECOND(fp), rFIRST(fp), rSECOND(fp));
1178 		POP_GPR(fp);
1179 		break;
1180 	case OP_MODI:
1181 		MAYBE_EMIT_CONST(fp);
1182 		in(SRAI, rSECOND(fp), 31, rTMP);
1183 		in(WRI, rTMP, 0, Y_REG);
1184 		in(SDIV, rSECOND(fp), rFIRST(fp), rTMP);
1185 		in(SMUL, rTMP, rFIRST(fp), rTMP);
1186 		in(SUB, rSECOND(fp), rTMP, rSECOND(fp));
1187 		POP_GPR(fp);
1188 		break;
1189 	case OP_MODU:
1190 		MAYBE_EMIT_CONST(fp);
1191 		in(WRI, G0, 0, Y_REG);
1192 		in(UDIV, rSECOND(fp), rFIRST(fp), rTMP);
1193 		in(SMUL, rTMP, rFIRST(fp), rTMP);
1194 		in(SUB, rSECOND(fp), rTMP, rSECOND(fp));
1195 		POP_GPR(fp);
1196 		break;
1197 	case OP_MULI:
1198 		MAYBE_EMIT_CONST(fp);
1199 		in(SMUL, rSECOND(fp), rFIRST(fp), rSECOND(fp));
1200 		POP_GPR(fp);
1201 		break;
1202 	case OP_MULU:
1203 		MAYBE_EMIT_CONST(fp);
1204 		in(UMUL, rSECOND(fp), rFIRST(fp), rSECOND(fp));
1205 		POP_GPR(fp);
1206 		break;
1207 	case OP_BAND:
1208 		MAYBE_EMIT_CONST(fp);
1209 		in(AND, rSECOND(fp), rFIRST(fp), rSECOND(fp));
1210 		POP_GPR(fp);
1211 		break;
1212 	case OP_BOR:
1213 		MAYBE_EMIT_CONST(fp);
1214 		in(OR, rSECOND(fp), rFIRST(fp), rSECOND(fp));
1215 		POP_GPR(fp);
1216 		break;
1217 	case OP_BXOR:
1218 		MAYBE_EMIT_CONST(fp);
1219 		in(XOR, rSECOND(fp), rFIRST(fp), rSECOND(fp));
1220 		POP_GPR(fp);
1221 		break;
1222 	case OP_BCOM:
1223 		MAYBE_EMIT_CONST(fp);
1224 		in(XNOR, rFIRST(fp), G0, rFIRST(fp));
1225 		break;
1226 	case OP_LSH:
1227 		if (fp->cached_const) {
1228 			EMIT_FALSE_CONST(fp);
1229 			in(SLLI, rSECOND(fp), fp->cached_const->arg.si, rSECOND(fp));
1230 		} else {
1231 			MAYBE_EMIT_CONST(fp);
1232 			in(SLL, rSECOND(fp), rFIRST(fp), rSECOND(fp));
1233 		}
1234 		POP_GPR(fp);
1235 		break;
1236 	case OP_RSHI:
1237 		if (fp->cached_const) {
1238 			EMIT_FALSE_CONST(fp);
1239 			in(SRAI, rSECOND(fp), fp->cached_const->arg.si, rSECOND(fp));
1240 		} else {
1241 			MAYBE_EMIT_CONST(fp);
1242 			in(SRA, rSECOND(fp), rFIRST(fp), rSECOND(fp));
1243 		}
1244 		POP_GPR(fp);
1245 		break;
1246 	case OP_RSHU:
1247 		if (fp->cached_const) {
1248 			EMIT_FALSE_CONST(fp);
1249 			in(SRLI, rSECOND(fp), fp->cached_const->arg.si, rSECOND(fp));
1250 		} else {
1251 			MAYBE_EMIT_CONST(fp);
1252 			in(SRL, rSECOND(fp), rFIRST(fp), rSECOND(fp));
1253 		}
1254 		POP_GPR(fp);
1255 		break;
1256 
1257 	case OP_NEGF:
1258 		MAYBE_EMIT_CONST(fp);
1259 		in(FNEG, fFIRST(fp), fFIRST(fp));
1260 		break;
1261 	case OP_ADDF:
1262 		MAYBE_EMIT_CONST(fp);
1263 		in(FADD, fSECOND(fp), fFIRST(fp), fSECOND(fp));
1264 		POP_FPR(fp);
1265 		break;
1266 	case OP_SUBF:
1267 		MAYBE_EMIT_CONST(fp);
1268 		in(FSUB, fSECOND(fp), fFIRST(fp), fSECOND(fp));
1269 		POP_FPR(fp);
1270 		break;
1271 	case OP_DIVF:
1272 		MAYBE_EMIT_CONST(fp);
1273 		in(FDIV, fSECOND(fp), fFIRST(fp), fSECOND(fp));
1274 		POP_FPR(fp);
1275 		break;
1276 	case OP_MULF:
1277 		MAYBE_EMIT_CONST(fp);
1278 		in(FMUL, fSECOND(fp), fFIRST(fp), fSECOND(fp));
1279 		POP_FPR(fp);
1280 		break;
1281 
1282 	case OP_EQF:
1283 	case OP_NEF:
1284 	case OP_LTF:
1285 	case OP_GEF:
1286 	case OP_GTF:
1287 	case OP_LEF: {
1288 		enum sparc_iname iname = FBE;
1289 
1290 		MAYBE_EMIT_CONST(fp);
1291 		in(FCMP, fSECOND(fp), fFIRST(fp));
1292 		switch(sp->op) {
1293 		case OP_EQF: iname = FBE; break;
1294 		case OP_NEF: iname = FBNE; break;
1295 		case OP_LTF: iname = FBL; break;
1296 		case OP_GEF: iname = FBGE; break;
1297 		case OP_GTF: iname = FBG; break;
1298 		case OP_LEF: iname = FBLE; break;
1299 		}
1300 		emit_jump(fp, iname, sp->arg.i);
1301 		POP_FPR(fp);
1302 		POP_FPR(fp);
1303 		break;
1304 	}
1305 	case OP_CVIF:
1306 		MAYBE_EMIT_CONST(fp);
1307 		PUSH_FPR(fp);
1308 		in(STWI, O6, SL(64, 128), rFIRST(fp));
1309 		in(LDFI, O6, SL(64, 128), fFIRST(fp));
1310 		in(FITOS, fFIRST(fp), fFIRST(fp));
1311 		POP_GPR(fp);
1312 		break;
1313 	case OP_CVFI:
1314 		MAYBE_EMIT_CONST(fp);
1315 		PUSH_GPR(fp);
1316 		in(FSTOI, fFIRST(fp), fFIRST(fp));
1317 		in(STFI, O6, SL(64, 128), fFIRST(fp));
1318 		in(LDUWI, O6, SL(64, 128), rFIRST(fp));
1319 		POP_FPR(fp);
1320 		break;
1321 	}
1322 	if (sp->op != OP_CONST) {
1323 		fp->cached_const = NULL;
1324 		end_emit(fp);
1325 	} else {
1326 		fp->cached_const = sp;
1327 		if (sp->dst_reg_flags & REG_FLAGS_FLOAT) {
1328 			PUSH_FPR(fp);
1329 		} else {
1330 			PUSH_GPR(fp);
1331 		}
1332 	}
1333 	end_emit(fp);
1334 }
1335 
free_source_insns(struct func_info * const fp)1336 static void free_source_insns(struct func_info * const fp)
1337 {
1338 	struct src_insn *sp = fp->first->next;
1339 
1340 	while (sp) {
1341 		struct src_insn *next = sp->next;
1342 		Z_Free(sp);
1343 		sp = next;
1344 	}
1345 }
1346 
compile_function(struct func_info * const fp)1347 static void compile_function(struct func_info * const fp)
1348 {
1349 	struct src_insn *sp;
1350 
1351 	analyze_function(fp);
1352 
1353 	fp->gpr_pos = L0;
1354 	fp->fpr_pos = F0;
1355 	fp->insn_index = 0;
1356 
1357 	fp->stack_space = SL(64, 128);
1358 	fp->cached_const = NULL;
1359 
1360 	sp = fp->first;
1361 	while ((sp = sp->next) != NULL)
1362 		compile_one_insn(fp, sp);
1363 
1364 	free_source_insns(fp);
1365 }
1366 
1367 /* We have two thunks for sparc.  The first is for the entry into
1368  * the VM, where setup the fixed global registers.  The second is
1369  * for calling out to C code from the VM, where we need to preserve
1370  * those fixed globals across the call.
1371  */
emit_vm_thunk(struct func_info * const fp)1372 static void emit_vm_thunk(struct func_info * const fp)
1373 {
1374 	/* int vm_thunk(void *vmdata, int programstack, void *database, int datamask) */
1375 	start_emit(fp, THUNK_ICOUNT);
1376 
1377 	in(OR, G0, O0, rVMDATA);
1378 	in(OR, G0, O1, rPSTACK);
1379 	in(OR, G0, O2, rDATABASE);
1380 	in(BA, +4*17);
1381 	in(OR, G0, O3, rDATAMASK);
1382 
1383 	/* int call_thunk(int arg0, int arg1, int arg2, int (*func)(int int int)) */
1384 #define CALL_THUNK_INSN_OFFSET		5
1385 	in(SAVEI, O6, -SL(64, 128), O6);
1386 
1387 	in(OR, G0, rVMDATA, L0);
1388 	in(OR, G0, rPSTACK, L1);
1389 	in(OR, G0, rDATABASE, L2);
1390 	in(OR, G0, rDATAMASK, L3);
1391 
1392 	in(OR, G0, I0, O0);
1393 	in(OR, G0, I1, O1);
1394 	in(JMPL, I3, G0, O7);
1395 	in(OR, G0, I2, O2);
1396 
1397 	in(OR, G0, L0, rVMDATA);
1398 	in(OR, G0, L1, rPSTACK);
1399 	in(OR, G0, L2, rDATABASE);
1400 	in(OR, G0, L3, rDATAMASK);
1401 
1402 	in(JMPLI, I7, 8, G0);
1403 	in(RESTORE, O0, G0, O0);
1404 
1405 	end_emit(fp);
1406 }
1407 
sparc_compute_code(vm_t * vm,struct func_info * const fp)1408 static void sparc_compute_code(vm_t *vm, struct func_info * const fp)
1409 {
1410 	struct dst_insn *dp = fp->dst_first;
1411 	unsigned int *code_now, *code_begin;
1412 	unsigned char *data_and_code;
1413 	unsigned int code_length;
1414 	int code_insns = 0, off;
1415 	struct data_hunk *dhp;
1416 	struct jump_insn *jp;
1417 	vm_data_t *data;
1418 
1419 	while (dp) {
1420 		code_insns += dp->length;
1421 		dp = dp->next;
1422 	}
1423 
1424 	code_length = (sizeof(vm_data_t) +
1425 		       (fp->data_num * sizeof(unsigned int)) +
1426 		       (code_insns * sizeof(unsigned int)));
1427 
1428 	data_and_code = mmap(NULL, code_length, PROT_READ | PROT_WRITE,
1429 			     MAP_SHARED | MAP_ANONYMOUS, -1, 0);
1430 	if (!data_and_code)
1431 		DIE("Not enough memory");
1432 
1433 	code_now = code_begin = (unsigned int *)
1434 		(data_and_code + VM_Data_Offset(data[fp->data_num]));
1435 
1436 	dp = fp->dst_first;
1437 	while (dp) {
1438 		int i_count = dp->i_count;
1439 
1440 		if (i_count != THUNK_ICOUNT) {
1441 			if (!fp->dst_by_i_count[i_count])
1442 				fp->dst_by_i_count[i_count] = (void *) code_now;
1443 		}
1444 		if (!dp->jump) {
1445 			memcpy(code_now, &dp->code[0], dp->length * sizeof(unsigned int));
1446 			code_now += dp->length;
1447 		} else {
1448 			int i;
1449 
1450 			dp->jump->parent = (void *) code_now;
1451 
1452 			for (i = 0; i < dp->length; i++)
1453 				code_now[i] = SPARC_NOP;
1454 			code_now += dp->length;
1455 		}
1456 
1457 		dp = dp->next;
1458 	}
1459 
1460 	jp = fp->jump_first;
1461 	while (jp) {
1462 		unsigned int *from = (void *) jp->parent;
1463 		unsigned int *to = (void *) fp->dst_by_i_count[jp->jump_dest_insn];
1464 		signed int disp = (to - from);
1465 
1466 		*from = IN(jp->jump_iname, disp << 2);
1467 
1468 		jp = jp->next;
1469 	}
1470 
1471 	vm->codeBase = data_and_code;
1472 	vm->codeLength = code_length;
1473 
1474 	data = (vm_data_t *) data_and_code;
1475 	data->CallThunk = code_begin + CALL_THUNK_INSN_OFFSET;
1476 	data->AsmCall = asmcall;
1477 	data->BlockCopy = blockcopy;
1478 	data->iPointers = (unsigned int *) vm->instructionPointers;
1479 	data->dataLength = VM_Data_Offset(data[fp->data_num]);
1480 	data->codeLength = (code_now - code_begin) * sizeof(unsigned int);
1481 
1482 #if 0
1483 	{
1484 		unsigned int *insn = code_begin;
1485 		int i;
1486 
1487 		Com_Printf("INSN DUMP\n");
1488 		for (i = 0; i < data->codeLength / 4; i+= 8) {
1489 			Com_Printf("\t.word\t0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
1490 				   insn[i + 0], insn[i + 1],
1491 				   insn[i + 2], insn[i + 3],
1492 				   insn[i + 4], insn[i + 5],
1493 				   insn[i + 6], insn[i + 7]);
1494 		}
1495 	}
1496 #endif
1497 
1498 	dhp = fp->data_first;
1499 	off = 0;
1500 	while (dhp) {
1501 		struct data_hunk *next = dhp->next;
1502 		int i;
1503 
1504 		for (i = 0; i < dhp->count; i++)
1505 			data->data[off + i] = dhp->data[i];
1506 
1507 		off += dhp->count;
1508 
1509 		Z_Free(dhp);
1510 
1511 		dhp = next;
1512 	}
1513 	fp->data_first = NULL;
1514 	fp->data_num = 0;
1515 
1516 	dp = fp->dst_first;
1517 	while (dp) {
1518 		struct dst_insn *next = dp->next;
1519 		if (dp->jump)
1520 			Z_Free(dp->jump);
1521 		Z_Free(dp);
1522 		dp = next;
1523 	}
1524 	fp->dst_first = fp->dst_last = NULL;
1525 }
1526 
VM_Compile(vm_t * vm,vmHeader_t * header)1527 void VM_Compile(vm_t *vm, vmHeader_t *header)
1528 {
1529 	struct func_info fi;
1530 	unsigned char *code;
1531 	int i_count, pc, i;
1532 
1533 	memset(&fi, 0, sizeof(fi));
1534 
1535 	fi.first = Z_Malloc(sizeof(struct src_insn));
1536 	fi.first->next = NULL;
1537 
1538 #ifdef __arch64__
1539 	Z_Free(vm->instructionPointers);
1540 	vm->instructionPointers = Z_Malloc(header->instructionCount *
1541 					   sizeof(void *));
1542 #endif
1543 
1544 	fi.dst_by_i_count = (struct dst_insn **) vm->instructionPointers;
1545 	memset(fi.dst_by_i_count, 0, header->instructionCount * sizeof(void *));
1546 
1547 	vm->compiled = qfalse;
1548 
1549 	emit_vm_thunk(&fi);
1550 
1551 	code = (unsigned char *) header + header->codeOffset;
1552 	pc = 0;
1553 
1554 	for (i_count = 0; i_count < header->instructionCount; i_count++) {
1555 		unsigned char opi, op = code[pc++];
1556 		struct src_insn *sp;
1557 
1558 		if (op == OP_CALL || op == OP_BLOCK_COPY)
1559 			fi.has_call = 1;
1560 		opi = vm_opInfo[op];
1561 		if (op == OP_CVIF || op == OP_CVFI ||
1562 		    (op == OP_LEAVE && (opi & opArgF)))
1563 			fi.need_float_tmp = 1;
1564 
1565 		if (op == OP_ENTER) {
1566 			if (fi.first->next)
1567 				compile_function(&fi);
1568 			fi.first->next = NULL;
1569 			fi.last = fi.first;
1570 			fi.has_call = fi.need_float_tmp = 0;
1571 		}
1572 
1573 		sp = Z_Malloc(sizeof(*sp));
1574 		sp->op = op;
1575 		sp->i_count = i_count;
1576 		sp->arg.i = 0;
1577 		sp->next = NULL;
1578 
1579 		if (vm_opInfo[op] & opImm4) {
1580 			union {
1581 				unsigned char b[4];
1582 				unsigned int i;
1583 			} c = { { code[ pc + 3 ], code[ pc + 2 ],
1584 				  code[ pc + 1 ], code[ pc + 0 ] }, };
1585 
1586 			sp->arg.i = c.i;
1587 			pc += 4;
1588 		} else if (vm_opInfo[op] & opImm1) {
1589 			sp->arg.b = code[pc++];
1590 		}
1591 
1592 		fi.last->next = sp;
1593 		fi.last = sp;
1594 	}
1595 	compile_function(&fi);
1596 
1597 	Z_Free(fi.first);
1598 
1599 	memset(fi.dst_by_i_count, 0, header->instructionCount * sizeof(void *));
1600 	sparc_compute_code(vm, &fi);
1601 
1602 	for (i = 0; i < header->instructionCount; i++) {
1603 		if (!fi.dst_by_i_count[i]) {
1604 			Com_Printf(S_COLOR_RED "Pointer %d not initialized !\n", i);
1605 			DIE("sparc JIT bug");
1606 		}
1607 	}
1608 
1609 	if (mprotect(vm->codeBase, vm->codeLength, PROT_READ|PROT_EXEC)) {
1610 		VM_Destroy_Compiled(vm);
1611 		DIE("mprotect failed");
1612 	}
1613 
1614 	vm->destroy = VM_Destroy_Compiled;
1615 	vm->compiled = qtrue;
1616 }
1617 
VM_CallCompiled(vm_t * vm,int * args)1618 int VM_CallCompiled(vm_t *vm, int *args)
1619 {
1620 	vm_data_t *vm_dataAndCode = (void *) vm->codeBase;
1621 	int programStack = vm->programStack;
1622 	int stackOnEntry = programStack;
1623 	byte *image = vm->dataBase;
1624 	int *argPointer;
1625 	int retVal;
1626 
1627 	currentVM = vm;
1628 
1629 	vm->currentlyInterpreting = qtrue;
1630 
1631 	programStack -= 48;
1632 	argPointer = (int *)&image[ programStack + 8 ];
1633 	memcpy( argPointer, args, 4 * 9 );
1634 	argPointer[-1] = 0;
1635 	argPointer[-2] = -1;
1636 
1637 	/* call generated code */
1638 	{
1639 		int (*entry)(void *, int, void *, int);
1640 		entry = (void *)(vm->codeBase + vm_dataAndCode->dataLength);
1641 		retVal = entry(vm->codeBase, programStack, vm->dataBase, vm->dataMask);
1642 	}
1643 
1644 	vm->programStack = stackOnEntry;
1645 	vm->currentlyInterpreting = qfalse;
1646 
1647 	return retVal;
1648 }
1649