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); \
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 (ARRAY_LEN(sparc_opcodes))
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 = ARRAY_LEN(argv); \
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 	void (*ErrJump)(void);
515 	unsigned int data[0];
516 } vm_data_t;
517 
518 #ifdef offsetof
519 # define VM_Data_Offset(field)		offsetof(vm_data_t, field)
520 #else
521 # define OFFSET(structName, field) \
522 	((void *)&(((structName *)NULL)->field) - NULL)
523 # define VM_Data_Offset(field)		OFFSET(vm_data_t, field)
524 #endif
525 
526 struct src_insn {
527 	unsigned char		op;
528 	unsigned int		i_count;
529 
530 	union {
531 		unsigned int	i;
532 		signed int	si;
533 		signed short	ss[2];
534 		unsigned short	us[2];
535 		unsigned char	b;
536 	} arg;
537 
538 	unsigned char		dst_reg_flags;
539 	unsigned char		src1_reg_flags;
540 	unsigned char		src2_reg_flags;
541 #define REG_FLAGS_FLOAT		0x1
542 
543 	struct src_insn		*next;
544 };
545 
546 struct dst_insn;
547 struct jump_insn {
548 	enum sparc_iname	jump_iname;
549 	int			jump_dest_insn;
550 	struct dst_insn		*parent;
551 	struct jump_insn	*next;
552 };
553 
554 struct dst_insn {
555 	struct dst_insn		*next;
556 
557 	unsigned int		count;
558 	unsigned int		i_count;
559 
560 	struct jump_insn	*jump;
561 	unsigned int		length;
562 	unsigned int		code[0];
563 };
564 
565 #define HUNK_SIZE		29
566 struct data_hunk {
567 	struct data_hunk *next;
568 	int count;
569 	unsigned int data[HUNK_SIZE];
570 };
571 
572 struct func_info {
573 	struct src_insn		*first;
574 	struct src_insn		*last;
575 	int			has_call;
576 	int			need_float_tmp;
577 
578 	struct src_insn		*cached_const;
579 
580 	int			stack_space;
581 	int			gpr_pos;
582 #define rFIRST(fp)		((fp)->gpr_pos - 1)
583 #define rSECOND(fp)		((fp)->gpr_pos - 2)
584 #define POP_GPR(fp)		((fp)->gpr_pos--)
585 #define PUSH_GPR(fp)		((fp)->gpr_pos++)
586 
587 	int			fpr_pos;
588 #define fFIRST(fp)		((fp)->fpr_pos - 1)
589 #define fSECOND(fp)		((fp)->fpr_pos - 2)
590 #define POP_FPR(fp)		((fp)->fpr_pos--)
591 #define PUSH_FPR(fp)		((fp)->fpr_pos++)
592 
593 #define INSN_BUF_SIZE		50
594 	unsigned int		insn_buf[INSN_BUF_SIZE];
595 	int			insn_index;
596 
597 	int			saved_icount;
598 	int			force_emit;
599 
600 	struct jump_insn	*jump_first;
601 	struct jump_insn	*jump_last;
602 
603 	struct dst_insn		*dst_first;
604 	struct dst_insn		*dst_last;
605 	int			dst_count;
606 
607 	struct dst_insn		**dst_by_i_count;
608 
609 	struct data_hunk	*data_first;
610 	int			data_num;
611 };
612 
613 #define THUNK_ICOUNT		-1
614 
sparc_push_data(struct func_info * const fp,unsigned int val)615 static unsigned int sparc_push_data(struct func_info * const fp, unsigned int val)
616 {
617 	struct data_hunk *last, *dp = fp->data_first;
618 	int off = 0;
619 
620 	last = NULL;
621 	while (dp) {
622 		int i;
623 
624 		for (i = 0; i < dp->count; i++) {
625 			if (dp->data[i] == val) {
626 				off += i;
627 				return VM_Data_Offset(data[off]);
628 			}
629 		}
630 		off += dp->count;
631 		last = dp;
632 		dp = dp->next;
633 	}
634 
635 	dp = last;
636 	if (!dp || dp->count >= HUNK_SIZE) {
637 		struct data_hunk *new = Z_Malloc(sizeof(*new));
638 		if (!dp)
639 			fp->data_first = new;
640 		else
641 			dp->next = new;
642 		dp = new;
643 		dp->count = 0;
644 		dp->next = NULL;
645 	}
646 	dp->data[dp->count++] = val;
647 	fp->data_num = off + 1;
648 	return VM_Data_Offset(data[off]);
649 }
650 
dst_insn_insert_tail(struct func_info * const fp,struct dst_insn * dp)651 static void dst_insn_insert_tail(struct func_info * const fp,
652 				 struct dst_insn *dp)
653 {
654 	if (!fp->dst_first) {
655 		fp->dst_first = fp->dst_last = dp;
656 	} else {
657 		fp->dst_last->next = dp;
658 		fp->dst_last = dp;
659 	}
660 }
661 
jump_insn_insert_tail(struct func_info * const fp,struct jump_insn * jp)662 static void jump_insn_insert_tail(struct func_info * const fp,
663 				  struct jump_insn *jp)
664 {
665 	if (!fp->jump_first) {
666 		fp->jump_first = fp->jump_last = jp;
667 	} else {
668 		fp->jump_last->next = jp;
669 		fp->jump_last = jp;
670 	}
671 }
672 
dst_new(struct func_info * const fp,unsigned int length,struct jump_insn * jp,int insns_size)673 static struct dst_insn *dst_new(struct func_info * const fp, unsigned int length,
674 				struct jump_insn *jp, int insns_size)
675 {
676 	struct dst_insn *dp = Z_Malloc(sizeof(struct dst_insn) + insns_size);
677 
678 	dp->length = length;
679 	dp->jump = jp;
680 	dp->count = fp->dst_count++;
681 	dp->i_count = fp->saved_icount;
682 	dp->next = NULL;
683 	if (fp->saved_icount != THUNK_ICOUNT)
684 		fp->dst_by_i_count[fp->saved_icount] = dp;
685 
686 	return dp;
687 }
688 
dst_insn_append(struct func_info * const fp)689 static void dst_insn_append(struct func_info * const fp)
690 {
691 	int insns_size = (sizeof(unsigned int) * fp->insn_index);
692 	struct dst_insn *dp;
693 
694 	dp = dst_new(fp, fp->insn_index, NULL, insns_size);
695 	if (insns_size)
696 		memcpy(&dp->code[0], fp->insn_buf, insns_size);
697 	dst_insn_insert_tail(fp, dp);
698 
699 	fp->insn_index = 0;
700 }
701 
ErrJump(void)702 static void ErrJump(void)
703 {
704 	Com_Error(ERR_DROP, "program tried to execute code outside VM");
705 	exit(1);
706 }
707 
jump_insn_append(vm_t * vm,struct func_info * const fp,enum sparc_iname iname,int dest)708 static void jump_insn_append(vm_t *vm, struct func_info * const fp, enum sparc_iname iname, int dest)
709 {
710 	struct jump_insn *jp = Z_Malloc(sizeof(*jp));
711 	struct dst_insn *dp;
712 
713 	if (dest < 0 || dest >= vm->instructionCount)
714 		ErrJump();
715 
716 	dp = dst_new(fp, 2, jp, 0);
717 
718 	jp->jump_iname = iname;
719 	jp->jump_dest_insn = dest;
720 	jp->parent = dp;
721 	jp->next = NULL;
722 
723 	jump_insn_insert_tail(fp, jp);
724 	dst_insn_insert_tail(fp, dp);
725 }
726 
start_emit(struct func_info * const fp,int i_count)727 static void start_emit(struct func_info * const fp, int i_count)
728 {
729 	fp->saved_icount = i_count;
730 	fp->insn_index = 0;
731 	fp->force_emit = 0;
732 }
733 
__do_emit_one(struct func_info * const fp,unsigned int insn)734 static void __do_emit_one(struct func_info * const fp, unsigned int insn)
735 {
736 	fp->insn_buf[fp->insn_index++] = insn;
737 }
738 
739 #define in(inst, args...) __do_emit_one(fp,  IN(inst, args))
740 
end_emit(struct func_info * const fp)741 static void end_emit(struct func_info * const fp)
742 {
743 	if (fp->insn_index || fp->force_emit)
744 		dst_insn_append(fp);
745 }
746 
emit_jump(vm_t * vm,struct func_info * const fp,enum sparc_iname iname,int dest)747 static void emit_jump(vm_t *vm, struct func_info * const fp, enum sparc_iname iname, int dest)
748 {
749 	end_emit(fp);
750 	jump_insn_append(vm, fp, iname, dest);
751 }
752 
analyze_function(struct func_info * const fp)753 static void analyze_function(struct func_info * const fp)
754 {
755 	struct src_insn *value_provider[20] = { NULL };
756 	struct src_insn *sp = fp->first;
757 	int opstack_depth = 0;
758 
759 	while ((sp = sp->next) != NULL) {
760 		unsigned char opi, op = sp->op;
761 
762 		opi = vm_opInfo[op];
763 		if (opi & opArgIF) {
764 			struct src_insn *vp = value_provider[--opstack_depth];
765 			unsigned char vpopi = vm_opInfo[vp->op];
766 
767 			if ((opi & opArgI) && (vpopi & opRetI)) {
768 				/* src1 and dst are integers */
769 			} else if ((opi & opArgF) && (vpopi & opRetF)) {
770 				/* src1 and dst are floats */
771 				vp->dst_reg_flags |= REG_FLAGS_FLOAT;
772 				sp->src1_reg_flags = REG_FLAGS_FLOAT;
773 			} else {
774 				/* illegal combination */
775 				DIE("unrecognized instruction combination");
776 			}
777 		}
778 		if (opi & opArg2IF) {
779 			struct src_insn *vp = value_provider[--opstack_depth];
780 			unsigned char vpopi = vm_opInfo[vp->op];
781 
782 			if ((opi & opArg2I) && (vpopi & opRetI)) {
783 				/* src2 and dst are integers */
784 			} else if ( (opi & opArg2F) && (vpopi & opRetF) ) {
785 				/* src2 and dst are floats */
786 				vp->dst_reg_flags |= REG_FLAGS_FLOAT;
787 				sp->src2_reg_flags = REG_FLAGS_FLOAT;
788 			} else {
789 				/* illegal combination */
790 				DIE("unrecognized instruction combination");
791 			}
792 		}
793 		if (opi & opRetIF) {
794 			value_provider[opstack_depth] = sp;
795 			opstack_depth++;
796 		}
797 	}
798 }
799 
asmcall(int call,int pstack)800 static int asmcall(int call, int pstack)
801 {
802 	vm_t *savedVM = currentVM;
803 	int i, ret;
804 
805 	currentVM->programStack = pstack - 4;
806 	if (sizeof(intptr_t) == sizeof(int)) {
807 		intptr_t *argPosition = (intptr_t *)((byte *)currentVM->dataBase + pstack + 4);
808 		argPosition[0] = -1 - call;
809 		ret = currentVM->systemCall(argPosition);
810 	} else {
811 		intptr_t args[MAX_VMSYSCALL_ARGS];
812 
813 		args[0] = -1 - call;
814 		int *argPosition = (int *)((byte *)currentVM->dataBase + pstack + 4);
815 		for( i = 1; i < ARRAY_LEN(args); i++ )
816 			args[i] = argPosition[i];
817 
818 		ret = currentVM->systemCall(args);
819 	}
820 
821 	currentVM = savedVM;
822 
823 	return ret;
824 }
825 
blockcopy(unsigned int dest,unsigned int src,unsigned int count)826 static void blockcopy(unsigned int dest, unsigned int src, unsigned int count)
827 {
828 	unsigned int dataMask = currentVM->dataMask;
829 
830 	if ((dest & dataMask) != dest ||
831 	    (src & dataMask) != src ||
832 	    ((dest+count) & dataMask) != dest + count ||
833 	    ((src+count) & dataMask) != src + count) {
834 		DIE("OP_BLOCK_COPY out of range!");
835 	}
836 
837 	memcpy(currentVM->dataBase+dest, currentVM->dataBase+src, count);
838 }
839 
do_emit_const(struct func_info * const fp,struct src_insn * sp)840 static void do_emit_const(struct func_info * const fp, struct src_insn *sp)
841 {
842 	start_emit(fp, sp->i_count);
843 	if (sp->dst_reg_flags & REG_FLAGS_FLOAT) {
844 		in(LDFI, rVMDATA, sparc_push_data(fp, sp->arg.i), fFIRST(fp));
845 	} else {
846 		if ((sp->arg.i & ~0x3ff) == 0) {
847 			in(ORI, G0, sp->arg.i & 0x3ff, rFIRST(fp));
848 		} else if ((sp->arg.i & 0x3ff) == 0) {
849 			in(SETHI, sp->arg.i >> 10, rFIRST(fp));
850 		} else {
851 			in(SETHI, sp->arg.i >> 10, rFIRST(fp));
852 			in(ORI, rFIRST(fp), sp->arg.i & 0x3ff, rFIRST(fp));
853 		}
854 	}
855 	end_emit(fp);
856 }
857 
858 #define MAYBE_EMIT_CONST(fp)	\
859 do {	if ((fp)->cached_const) {	       \
860 		int saved_i_count = (fp)->saved_icount; \
861 		do_emit_const(fp, (fp)->cached_const); \
862 		(fp)->saved_icount = saved_i_count; \
863 	} \
864 } while (0)
865 
866 #define EMIT_FALSE_CONST(fp)					\
867 do {	int saved_i_count = (fp)->saved_icount;			\
868 	(fp)->saved_icount = (fp)->cached_const->i_count;	\
869 	dst_insn_append(fp);					\
870 	(fp)->saved_icount = saved_i_count;			\
871 } while (0)
872 
compile_one_insn(vm_t * vm,struct func_info * const fp,struct src_insn * sp)873 static void compile_one_insn(vm_t *vm, struct func_info * const fp, struct src_insn *sp)
874 {
875 	start_emit(fp, sp->i_count);
876 
877 	switch (sp->op) {
878 	default:
879 		Com_Printf("VM: Unhandled opcode 0x%02x[%s]\n",
880 			   sp->op,
881 			   opnames[sp->op] ? opnames[sp->op] : "UNKNOWN");
882 		DIE("Unsupported opcode");
883 		break;
884 
885 	case OP_ENTER: {
886 		int stack = SL(64, 128);
887 
888 		if (fp->need_float_tmp)
889 			stack += 16;
890 
891 		in(SAVEI, O6, -stack, O6);
892 		if (!SIMM13_P(sp->arg.si)) {
893 			in(SETHI, sp->arg.i >> 10, rTMP);
894 			in(ORI, rTMP, sp->arg.i & 0x3ff, rTMP);
895 			in(SUB, rPSTACK, rTMP, rPSTACK);
896 		} else
897 			in(SUBI, rPSTACK, sp->arg.si, rPSTACK);
898 		break;
899 	}
900 	case OP_LEAVE:
901 		if (fp->cached_const && SIMM13_P(fp->cached_const->arg.si)) {
902 			EMIT_FALSE_CONST(fp);
903 			if (fp->cached_const->src1_reg_flags & REG_FLAGS_FLOAT)
904 				DIE("constant float in OP_LEAVE");
905 
906 			if (!SIMM13_P(sp->arg.si)) {
907 				in(SETHI, sp->arg.i >> 10, rTMP);
908 				in(ORI, rTMP, sp->arg.i & 0x3ff, rTMP);
909 				in(ADD, rPSTACK, rTMP, rPSTACK);
910 			} else
911 				in(ADDI, rPSTACK, sp->arg.si, rPSTACK);
912 			in(JMPLI, I7, 8, G0);
913 			in(RESTOREI, G0, fp->cached_const->arg.si, O0);
914 			POP_GPR(fp);
915 		} else {
916 			MAYBE_EMIT_CONST(fp);
917 			if (!SIMM13_P(sp->arg.si)) {
918 				in(SETHI, sp->arg.i >> 10, rTMP);
919 				in(ORI, rTMP, sp->arg.i & 0x3ff, rTMP);
920 				in(ADD, rPSTACK, rTMP, rPSTACK);
921 			} else
922 				in(ADDI, rPSTACK, sp->arg.si, rPSTACK);
923 			if (sp->src1_reg_flags & REG_FLAGS_FLOAT) {
924 				in(STFI, O6, SL(64, 128), fFIRST(fp));
925 				in(LDUWI, O6, SL(64, 128), O0);
926 				in(JMPLI, I7, 8, G0);
927 				in(RESTORE, O0, G0, O0);
928 				POP_FPR(fp);
929 			} else {
930 				in(JMPLI, I7, 8, G0);
931 				in(RESTORE, rFIRST(fp), G0, O0);
932 				POP_GPR(fp);
933 			}
934 		}
935 		assert(fp->gpr_pos == L0);
936 		assert(fp->fpr_pos == F0);
937 		break;
938 	case OP_JUMP:
939 		if (fp->cached_const) {
940 			EMIT_FALSE_CONST(fp);
941 			emit_jump(vm, fp, BA, fp->cached_const->arg.i);
942 		} else {
943 			MAYBE_EMIT_CONST(fp);
944 			in(SETHI, vm->instructionCount >> 10, rTMP);
945 			in(ORI, rTMP, vm->instructionCount & 0x3ff, rTMP);
946 			in(SUBCC, rTMP, rFIRST(fp), G0);
947 			in(BLEU, +4*5);
948 			in(LDLI, rVMDATA, VM_Data_Offset(ErrJump), rTMP);
949 
950 			in(SLLI, rFIRST(fp), 2, rFIRST(fp));
951 			in(LDLI, rVMDATA, VM_Data_Offset(iPointers), rTMP);
952 			in(LDL, rTMP, rFIRST(fp), rTMP);
953 			in(JMPL, rTMP, G0, G0);
954 			in(NOP);
955 		}
956 		POP_GPR(fp);
957 		break;
958 	case OP_CALL:
959 		if (fp->cached_const) {
960 			EMIT_FALSE_CONST(fp);
961 			if (fp->cached_const->arg.si >= 0) {
962 				emit_jump(vm, fp, CALL, fp->cached_const->arg.i);
963 			} else {
964 				in(LDLI, rVMDATA, VM_Data_Offset(CallThunk), rTMP);
965 				in(LDLI, rVMDATA, VM_Data_Offset(AsmCall), O3);
966 				in(ORI, G0, fp->cached_const->arg.si, O0);
967 				in(JMPL, rTMP, G0, O7);
968 				in(OR, G0, rPSTACK, O1);
969 			}
970 			in(OR, G0, O0, rFIRST(fp));
971 		} else {
972 			MAYBE_EMIT_CONST(fp);
973 			in(SUBCCI, rFIRST(fp), 0, G0);
974 			in(BL, +4*7);
975 			in(NOP);
976 
977 			/* normal call */
978 			in(SETHI, vm->instructionCount >> 10, rTMP);
979 			in(ORI, rTMP, vm->instructionCount & 0x3ff, rTMP);
980 			in(SUBCC, rTMP, rFIRST(fp), G0);
981 			in(BLEU, +4*9);
982 			in(LDLI, rVMDATA, VM_Data_Offset(ErrJump), rTMP);
983 			in(LDLI, rVMDATA, VM_Data_Offset(iPointers), O5);
984 			in(SLLI, rFIRST(fp), 2, rFIRST(fp));
985 			in(LDL, O5, rFIRST(fp), rTMP);
986 			in(BA, +4*4);
987 			in(NOP);
988 
989 			/* syscall */
990 			in(LDLI, rVMDATA, VM_Data_Offset(CallThunk), rTMP);
991 			in(LDLI, rVMDATA, VM_Data_Offset(AsmCall), O3);
992 
993 			in(OR, G0, rFIRST(fp), O0);
994 			in(JMPL, rTMP, G0, O7);
995 			in(OR, G0, rPSTACK, O1);
996 
997 			/* return value */
998 			in(OR, G0, O0, rFIRST(fp));
999 		}
1000 		break;
1001 	case OP_BLOCK_COPY:
1002 		MAYBE_EMIT_CONST(fp);
1003 		in(LDLI, rVMDATA, VM_Data_Offset(CallThunk), rTMP);
1004 		in(LDLI, rVMDATA, VM_Data_Offset(BlockCopy), O3);
1005 		in(OR, G0, rSECOND(fp), O0);
1006 		in(OR, G0, rFIRST(fp), O1);
1007 		if ((sp->arg.i & ~0x3ff) == 0) {
1008 			in(ORI, G0, sp->arg.i & 0x3ff, O2);
1009 		} else if ((sp->arg.i & 0x3ff) == 0) {
1010 			in(SETHI, sp->arg.i >> 10, O2);
1011 		} else {
1012 			in(SETHI, sp->arg.i >> 10, O2);
1013 			in(ORI, O2, sp->arg.i & 0x3ff, O2);
1014 		}
1015 		in(JMPL, rTMP, G0, O7);
1016 		in(NOP);
1017 		POP_GPR(fp);
1018 		POP_GPR(fp);
1019 		break;
1020 
1021 	case OP_PUSH:
1022 		MAYBE_EMIT_CONST(fp);
1023 		if (sp->dst_reg_flags & REG_FLAGS_FLOAT)
1024 			PUSH_FPR(fp);
1025 		else
1026 			PUSH_GPR(fp);
1027 		fp->force_emit = 1;
1028 		break;
1029 	case OP_POP:
1030 		MAYBE_EMIT_CONST(fp);
1031 		if (sp->src1_reg_flags & REG_FLAGS_FLOAT)
1032 			POP_FPR(fp);
1033 		else
1034 			POP_GPR(fp);
1035 		fp->force_emit = 1;
1036 		break;
1037 	case OP_ARG:
1038 		MAYBE_EMIT_CONST(fp);
1039 		in(ADDI, rPSTACK, sp->arg.b, rTMP);
1040 		if (sp->src1_reg_flags & REG_FLAGS_FLOAT) {
1041 			in(STF, rDATABASE, rTMP, fFIRST(fp));
1042 			POP_FPR(fp);
1043 		} else {
1044 			in(STW, rDATABASE, rTMP, rFIRST(fp));
1045 			POP_GPR(fp);
1046 		}
1047 		break;
1048 	case OP_IGNORE:
1049 		MAYBE_EMIT_CONST(fp);
1050 		in(NOP);
1051 		break;
1052 	case OP_BREAK:
1053 		MAYBE_EMIT_CONST(fp);
1054 		in(TA, 0x5);
1055 		break;
1056 	case OP_LOCAL:
1057 		MAYBE_EMIT_CONST(fp);
1058 		PUSH_GPR(fp);
1059 		if (!SIMM13_P(sp->arg.i)) {
1060 			in(SETHI, sp->arg.i >> 10, rTMP);
1061 			in(ORI, rTMP, sp->arg.i & 0x3ff, rTMP);
1062 			in(ADD, rPSTACK, rTMP, rFIRST(fp));
1063 		} else
1064 			in(ADDI, rPSTACK, sp->arg.i, rFIRST(fp));
1065 		break;
1066 	case OP_CONST:
1067 		MAYBE_EMIT_CONST(fp);
1068 		break;
1069 	case OP_LOAD4:
1070 		MAYBE_EMIT_CONST(fp);
1071 		in(AND, rFIRST(fp), rDATAMASK, rFIRST(fp));
1072 		if (sp->dst_reg_flags & REG_FLAGS_FLOAT) {
1073 			PUSH_FPR(fp);
1074 			in(LDF, rFIRST(fp), rDATABASE, fFIRST(fp));
1075 			POP_GPR(fp);
1076 		} else {
1077 			in(LDUW, rFIRST(fp), rDATABASE, rFIRST(fp));
1078 		}
1079 		break;
1080 	case OP_LOAD2:
1081 		MAYBE_EMIT_CONST(fp);
1082 		in(AND, rFIRST(fp), rDATAMASK, rFIRST(fp));
1083 		in(LDUH, rFIRST(fp), rDATABASE, rFIRST(fp));
1084 		break;
1085 	case OP_LOAD1:
1086 		MAYBE_EMIT_CONST(fp);
1087 		in(AND, rFIRST(fp), rDATAMASK, rFIRST(fp));
1088 		in(LDUB, rFIRST(fp), rDATABASE, rFIRST(fp));
1089 		break;
1090 	case OP_STORE4:
1091 		MAYBE_EMIT_CONST(fp);
1092 		if (sp->src1_reg_flags & REG_FLAGS_FLOAT) {
1093 			in(AND, rFIRST(fp), rDATAMASK, rFIRST(fp));
1094 			in(STF, rFIRST(fp), rDATABASE, fFIRST(fp));
1095 			POP_FPR(fp);
1096 		} else {
1097 			in(AND, rSECOND(fp), rDATAMASK, rSECOND(fp));
1098 			in(STW, rSECOND(fp), rDATABASE, rFIRST(fp));
1099 			POP_GPR(fp);
1100 		}
1101 		POP_GPR(fp);
1102 		break;
1103 	case OP_STORE2:
1104 		MAYBE_EMIT_CONST(fp);
1105 		in(AND, rSECOND(fp), rDATAMASK, rSECOND(fp));
1106 		in(STH, rSECOND(fp), rDATABASE, rFIRST(fp));
1107 		POP_GPR(fp);
1108 		POP_GPR(fp);
1109 		break;
1110 	case OP_STORE1:
1111 		MAYBE_EMIT_CONST(fp);
1112 		in(AND, rSECOND(fp), rDATAMASK, rSECOND(fp));
1113 		in(STB, rSECOND(fp), rDATABASE, rFIRST(fp));
1114 		POP_GPR(fp);
1115 		POP_GPR(fp);
1116 		break;
1117 	case OP_EQ:
1118 	case OP_NE:
1119 	case OP_LTI:
1120 	case OP_GEI:
1121 	case OP_GTI:
1122 	case OP_LEI:
1123 	case OP_LTU:
1124 	case OP_GEU:
1125 	case OP_GTU:
1126 	case OP_LEU: {
1127 		enum sparc_iname iname = BA;
1128 
1129 		if (fp->cached_const && SIMM13_P(fp->cached_const->arg.si)) {
1130 			EMIT_FALSE_CONST(fp);
1131 			in(SUBCCI, rSECOND(fp), fp->cached_const->arg.si, G0);
1132 		} else {
1133 			MAYBE_EMIT_CONST(fp);
1134 			in(SUBCC, rSECOND(fp), rFIRST(fp), G0);
1135 		}
1136 		switch(sp->op) {
1137 		case OP_EQ: iname = BE; break;
1138 		case OP_NE: iname = BNE; break;
1139 		case OP_LTI: iname = BL; break;
1140 		case OP_GEI: iname = BGE; break;
1141 		case OP_GTI: iname = BG; break;
1142 		case OP_LEI: iname = BLE; break;
1143 		case OP_LTU: iname = BCS; break;
1144 		case OP_GEU: iname = BCC; break;
1145 		case OP_GTU: iname = BGU; break;
1146 		case OP_LEU: iname = BLEU; break;
1147 		}
1148 		emit_jump(vm, fp, iname, sp->arg.i);
1149 		POP_GPR(fp);
1150 		POP_GPR(fp);
1151 		break;
1152 	}
1153 
1154 	case OP_SEX8:
1155 		MAYBE_EMIT_CONST(fp);
1156 		in(SLLI, rFIRST(fp), 24, rFIRST(fp));
1157 		in(SRAI, rFIRST(fp), 24, rFIRST(fp));
1158 		break;
1159 	case OP_SEX16:
1160 		MAYBE_EMIT_CONST(fp);
1161 		in(SLLI, rFIRST(fp), 16, rFIRST(fp));
1162 		in(SRAI, rFIRST(fp), 16, rFIRST(fp));
1163 		break;
1164 	case OP_NEGI:
1165 		MAYBE_EMIT_CONST(fp);
1166 		in(SUB, G0, rFIRST(fp), rFIRST(fp));
1167 		break;
1168 	case OP_ADD:
1169 		if (fp->cached_const && SIMM13_P(fp->cached_const->arg.si)) {
1170 			EMIT_FALSE_CONST(fp);
1171 			in(ADDI, rSECOND(fp), fp->cached_const->arg.si, rSECOND(fp));
1172 		} else {
1173 			MAYBE_EMIT_CONST(fp);
1174 			in(ADD, rSECOND(fp), rFIRST(fp), rSECOND(fp));
1175 		}
1176 		POP_GPR(fp);
1177 		break;
1178 	case OP_SUB:
1179 		if (fp->cached_const && SIMM13_P(fp->cached_const->arg.si)) {
1180 			EMIT_FALSE_CONST(fp);
1181 			in(SUBI, rSECOND(fp), fp->cached_const->arg.si, rSECOND(fp));
1182 		} else {
1183 			MAYBE_EMIT_CONST(fp);
1184 			in(SUB, rSECOND(fp), rFIRST(fp), rSECOND(fp));
1185 		}
1186 		POP_GPR(fp);
1187 		break;
1188 	case OP_DIVI:
1189 		MAYBE_EMIT_CONST(fp);
1190 		in(SRAI, rSECOND(fp), 31, rTMP);
1191 		in(WRI, rTMP, 0, Y_REG);
1192 		in(SDIV, rSECOND(fp), rFIRST(fp), rSECOND(fp));
1193 		POP_GPR(fp);
1194 		break;
1195 	case OP_DIVU:
1196 		MAYBE_EMIT_CONST(fp);
1197 		in(WRI, G0, 0, Y_REG);
1198 		in(UDIV, rSECOND(fp), rFIRST(fp), rSECOND(fp));
1199 		POP_GPR(fp);
1200 		break;
1201 	case OP_MODI:
1202 		MAYBE_EMIT_CONST(fp);
1203 		in(SRAI, rSECOND(fp), 31, rTMP);
1204 		in(WRI, rTMP, 0, Y_REG);
1205 		in(SDIV, rSECOND(fp), rFIRST(fp), rTMP);
1206 		in(SMUL, rTMP, rFIRST(fp), rTMP);
1207 		in(SUB, rSECOND(fp), rTMP, rSECOND(fp));
1208 		POP_GPR(fp);
1209 		break;
1210 	case OP_MODU:
1211 		MAYBE_EMIT_CONST(fp);
1212 		in(WRI, G0, 0, Y_REG);
1213 		in(UDIV, rSECOND(fp), rFIRST(fp), rTMP);
1214 		in(SMUL, rTMP, rFIRST(fp), rTMP);
1215 		in(SUB, rSECOND(fp), rTMP, rSECOND(fp));
1216 		POP_GPR(fp);
1217 		break;
1218 	case OP_MULI:
1219 		MAYBE_EMIT_CONST(fp);
1220 		in(SMUL, rSECOND(fp), rFIRST(fp), rSECOND(fp));
1221 		POP_GPR(fp);
1222 		break;
1223 	case OP_MULU:
1224 		MAYBE_EMIT_CONST(fp);
1225 		in(UMUL, rSECOND(fp), rFIRST(fp), rSECOND(fp));
1226 		POP_GPR(fp);
1227 		break;
1228 	case OP_BAND:
1229 		MAYBE_EMIT_CONST(fp);
1230 		in(AND, rSECOND(fp), rFIRST(fp), rSECOND(fp));
1231 		POP_GPR(fp);
1232 		break;
1233 	case OP_BOR:
1234 		MAYBE_EMIT_CONST(fp);
1235 		in(OR, rSECOND(fp), rFIRST(fp), rSECOND(fp));
1236 		POP_GPR(fp);
1237 		break;
1238 	case OP_BXOR:
1239 		MAYBE_EMIT_CONST(fp);
1240 		in(XOR, rSECOND(fp), rFIRST(fp), rSECOND(fp));
1241 		POP_GPR(fp);
1242 		break;
1243 	case OP_BCOM:
1244 		MAYBE_EMIT_CONST(fp);
1245 		in(XNOR, rFIRST(fp), G0, rFIRST(fp));
1246 		break;
1247 	case OP_LSH:
1248 		if (fp->cached_const) {
1249 			EMIT_FALSE_CONST(fp);
1250 			in(SLLI, rSECOND(fp), fp->cached_const->arg.si, rSECOND(fp));
1251 		} else {
1252 			MAYBE_EMIT_CONST(fp);
1253 			in(SLL, rSECOND(fp), rFIRST(fp), rSECOND(fp));
1254 		}
1255 		POP_GPR(fp);
1256 		break;
1257 	case OP_RSHI:
1258 		if (fp->cached_const) {
1259 			EMIT_FALSE_CONST(fp);
1260 			in(SRAI, rSECOND(fp), fp->cached_const->arg.si, rSECOND(fp));
1261 		} else {
1262 			MAYBE_EMIT_CONST(fp);
1263 			in(SRA, rSECOND(fp), rFIRST(fp), rSECOND(fp));
1264 		}
1265 		POP_GPR(fp);
1266 		break;
1267 	case OP_RSHU:
1268 		if (fp->cached_const) {
1269 			EMIT_FALSE_CONST(fp);
1270 			in(SRLI, rSECOND(fp), fp->cached_const->arg.si, rSECOND(fp));
1271 		} else {
1272 			MAYBE_EMIT_CONST(fp);
1273 			in(SRL, rSECOND(fp), rFIRST(fp), rSECOND(fp));
1274 		}
1275 		POP_GPR(fp);
1276 		break;
1277 
1278 	case OP_NEGF:
1279 		MAYBE_EMIT_CONST(fp);
1280 		in(FNEG, fFIRST(fp), fFIRST(fp));
1281 		break;
1282 	case OP_ADDF:
1283 		MAYBE_EMIT_CONST(fp);
1284 		in(FADD, fSECOND(fp), fFIRST(fp), fSECOND(fp));
1285 		POP_FPR(fp);
1286 		break;
1287 	case OP_SUBF:
1288 		MAYBE_EMIT_CONST(fp);
1289 		in(FSUB, fSECOND(fp), fFIRST(fp), fSECOND(fp));
1290 		POP_FPR(fp);
1291 		break;
1292 	case OP_DIVF:
1293 		MAYBE_EMIT_CONST(fp);
1294 		in(FDIV, fSECOND(fp), fFIRST(fp), fSECOND(fp));
1295 		POP_FPR(fp);
1296 		break;
1297 	case OP_MULF:
1298 		MAYBE_EMIT_CONST(fp);
1299 		in(FMUL, fSECOND(fp), fFIRST(fp), fSECOND(fp));
1300 		POP_FPR(fp);
1301 		break;
1302 
1303 	case OP_EQF:
1304 	case OP_NEF:
1305 	case OP_LTF:
1306 	case OP_GEF:
1307 	case OP_GTF:
1308 	case OP_LEF: {
1309 		enum sparc_iname iname = FBE;
1310 
1311 		MAYBE_EMIT_CONST(fp);
1312 		in(FCMP, fSECOND(fp), fFIRST(fp));
1313 		switch(sp->op) {
1314 		case OP_EQF: iname = FBE; break;
1315 		case OP_NEF: iname = FBNE; break;
1316 		case OP_LTF: iname = FBL; break;
1317 		case OP_GEF: iname = FBGE; break;
1318 		case OP_GTF: iname = FBG; break;
1319 		case OP_LEF: iname = FBLE; break;
1320 		}
1321 		emit_jump(vm, fp, iname, sp->arg.i);
1322 		POP_FPR(fp);
1323 		POP_FPR(fp);
1324 		break;
1325 	}
1326 	case OP_CVIF:
1327 		MAYBE_EMIT_CONST(fp);
1328 		PUSH_FPR(fp);
1329 		in(STWI, O6, SL(64, 128), rFIRST(fp));
1330 		in(LDFI, O6, SL(64, 128), fFIRST(fp));
1331 		in(FITOS, fFIRST(fp), fFIRST(fp));
1332 		POP_GPR(fp);
1333 		break;
1334 	case OP_CVFI:
1335 		MAYBE_EMIT_CONST(fp);
1336 		PUSH_GPR(fp);
1337 		in(FSTOI, fFIRST(fp), fFIRST(fp));
1338 		in(STFI, O6, SL(64, 128), fFIRST(fp));
1339 		in(LDUWI, O6, SL(64, 128), rFIRST(fp));
1340 		POP_FPR(fp);
1341 		break;
1342 	}
1343 	if (sp->op != OP_CONST) {
1344 		fp->cached_const = NULL;
1345 		end_emit(fp);
1346 	} else {
1347 		fp->cached_const = sp;
1348 		if (sp->dst_reg_flags & REG_FLAGS_FLOAT) {
1349 			PUSH_FPR(fp);
1350 		} else {
1351 			PUSH_GPR(fp);
1352 		}
1353 	}
1354 	end_emit(fp);
1355 }
1356 
free_source_insns(struct func_info * const fp)1357 static void free_source_insns(struct func_info * const fp)
1358 {
1359 	struct src_insn *sp = fp->first->next;
1360 
1361 	while (sp) {
1362 		struct src_insn *next = sp->next;
1363 		Z_Free(sp);
1364 		sp = next;
1365 	}
1366 }
1367 
compile_function(vm_t * vm,struct func_info * const fp)1368 static void compile_function(vm_t *vm, struct func_info * const fp)
1369 {
1370 	struct src_insn *sp;
1371 
1372 	analyze_function(fp);
1373 
1374 	fp->gpr_pos = L0;
1375 	fp->fpr_pos = F0;
1376 	fp->insn_index = 0;
1377 
1378 	fp->stack_space = SL(64, 128);
1379 	fp->cached_const = NULL;
1380 
1381 	sp = fp->first;
1382 	while ((sp = sp->next) != NULL)
1383 		compile_one_insn(vm, fp, sp);
1384 
1385 	free_source_insns(fp);
1386 }
1387 
1388 /* We have two thunks for sparc.  The first is for the entry into
1389  * the VM, where setup the fixed global registers.  The second is
1390  * for calling out to C code from the VM, where we need to preserve
1391  * those fixed globals across the call.
1392  */
emit_vm_thunk(struct func_info * const fp)1393 static void emit_vm_thunk(struct func_info * const fp)
1394 {
1395 	/* int vm_thunk(void *vmdata, int programstack, void *database, int datamask) */
1396 	start_emit(fp, THUNK_ICOUNT);
1397 
1398 	in(OR, G0, O0, rVMDATA);
1399 	in(OR, G0, O1, rPSTACK);
1400 	in(OR, G0, O2, rDATABASE);
1401 	in(BA, +4*17);
1402 	in(OR, G0, O3, rDATAMASK);
1403 
1404 	/* int call_thunk(int arg0, int arg1, int arg2, int (*func)(int int int)) */
1405 #define CALL_THUNK_INSN_OFFSET		5
1406 	in(SAVEI, O6, -SL(64, 128), O6);
1407 
1408 	in(OR, G0, rVMDATA, L0);
1409 	in(OR, G0, rPSTACK, L1);
1410 	in(OR, G0, rDATABASE, L2);
1411 	in(OR, G0, rDATAMASK, L3);
1412 
1413 	in(OR, G0, I0, O0);
1414 	in(OR, G0, I1, O1);
1415 	in(JMPL, I3, G0, O7);
1416 	in(OR, G0, I2, O2);
1417 
1418 	in(OR, G0, L0, rVMDATA);
1419 	in(OR, G0, L1, rPSTACK);
1420 	in(OR, G0, L2, rDATABASE);
1421 	in(OR, G0, L3, rDATAMASK);
1422 
1423 	in(JMPLI, I7, 8, G0);
1424 	in(RESTORE, O0, G0, O0);
1425 
1426 	end_emit(fp);
1427 }
1428 
sparc_compute_code(vm_t * vm,struct func_info * const fp)1429 static void sparc_compute_code(vm_t *vm, struct func_info * const fp)
1430 {
1431 	struct dst_insn *dp = fp->dst_first;
1432 	unsigned int *code_now, *code_begin;
1433 	unsigned char *data_and_code;
1434 	unsigned int code_length;
1435 	int code_insns = 0, off;
1436 	struct data_hunk *dhp;
1437 	struct jump_insn *jp;
1438 	vm_data_t *data;
1439 
1440 	while (dp) {
1441 		code_insns += dp->length;
1442 		dp = dp->next;
1443 	}
1444 
1445 	code_length = (sizeof(vm_data_t) +
1446 		       (fp->data_num * sizeof(unsigned int)) +
1447 		       (code_insns * sizeof(unsigned int)));
1448 
1449 	data_and_code = mmap(NULL, code_length, PROT_READ | PROT_WRITE,
1450 			     MAP_SHARED | MAP_ANONYMOUS, -1, 0);
1451 	if (data_and_code == MAP_FAILED)
1452 		DIE("Not enough memory");
1453 
1454 	code_now = code_begin = (unsigned int *)
1455 		(data_and_code + VM_Data_Offset(data[fp->data_num]));
1456 
1457 	dp = fp->dst_first;
1458 	while (dp) {
1459 		int i_count = dp->i_count;
1460 
1461 		if (i_count != THUNK_ICOUNT) {
1462 			if (!fp->dst_by_i_count[i_count])
1463 				fp->dst_by_i_count[i_count] = (void *) code_now;
1464 		}
1465 		if (!dp->jump) {
1466 			memcpy(code_now, &dp->code[0], dp->length * sizeof(unsigned int));
1467 			code_now += dp->length;
1468 		} else {
1469 			int i;
1470 
1471 			dp->jump->parent = (void *) code_now;
1472 
1473 			for (i = 0; i < dp->length; i++)
1474 				code_now[i] = SPARC_NOP;
1475 			code_now += dp->length;
1476 		}
1477 
1478 		dp = dp->next;
1479 	}
1480 
1481 	jp = fp->jump_first;
1482 	while (jp) {
1483 		unsigned int *from = (void *) jp->parent;
1484 		unsigned int *to = (void *) fp->dst_by_i_count[jp->jump_dest_insn];
1485 		signed int disp = (to - from);
1486 
1487 		*from = IN(jp->jump_iname, disp << 2);
1488 
1489 		jp = jp->next;
1490 	}
1491 
1492 	vm->codeBase = data_and_code;
1493 	vm->codeLength = code_length;
1494 
1495 	data = (vm_data_t *) data_and_code;
1496 	data->CallThunk = code_begin + CALL_THUNK_INSN_OFFSET;
1497 	data->AsmCall = asmcall;
1498 	data->BlockCopy = blockcopy;
1499 	data->iPointers = (unsigned int *) vm->instructionPointers;
1500 	data->dataLength = VM_Data_Offset(data[fp->data_num]);
1501 	data->codeLength = (code_now - code_begin) * sizeof(unsigned int);
1502 	data->ErrJump = ErrJump;
1503 
1504 #if 0
1505 	{
1506 		unsigned int *insn = code_begin;
1507 		int i;
1508 
1509 		Com_Printf("INSN DUMP\n");
1510 		for (i = 0; i < data->codeLength / 4; i+= 8) {
1511 			Com_Printf("\t.word\t0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
1512 				   insn[i + 0], insn[i + 1],
1513 				   insn[i + 2], insn[i + 3],
1514 				   insn[i + 4], insn[i + 5],
1515 				   insn[i + 6], insn[i + 7]);
1516 		}
1517 	}
1518 #endif
1519 
1520 	dhp = fp->data_first;
1521 	off = 0;
1522 	while (dhp) {
1523 		struct data_hunk *next = dhp->next;
1524 		int i;
1525 
1526 		for (i = 0; i < dhp->count; i++)
1527 			data->data[off + i] = dhp->data[i];
1528 
1529 		off += dhp->count;
1530 
1531 		Z_Free(dhp);
1532 
1533 		dhp = next;
1534 	}
1535 	fp->data_first = NULL;
1536 	fp->data_num = 0;
1537 
1538 	dp = fp->dst_first;
1539 	while (dp) {
1540 		struct dst_insn *next = dp->next;
1541 		if (dp->jump)
1542 			Z_Free(dp->jump);
1543 		Z_Free(dp);
1544 		dp = next;
1545 	}
1546 	fp->dst_first = fp->dst_last = NULL;
1547 }
1548 
VM_Compile(vm_t * vm,vmHeader_t * header)1549 void VM_Compile(vm_t *vm, vmHeader_t *header)
1550 {
1551 	struct func_info fi;
1552 	unsigned char *code;
1553 	int i_count, pc, i;
1554 
1555 	memset(&fi, 0, sizeof(fi));
1556 
1557 	fi.first = Z_Malloc(sizeof(struct src_insn));
1558 	fi.first->next = NULL;
1559 
1560 #ifdef __arch64__
1561 	Z_Free(vm->instructionPointers);
1562 	vm->instructionPointers = Z_Malloc(header->instructionCount *
1563 					   sizeof(void *));
1564 #endif
1565 
1566 	fi.dst_by_i_count = (struct dst_insn **) vm->instructionPointers;
1567 	memset(fi.dst_by_i_count, 0, header->instructionCount * sizeof(void *));
1568 
1569 	vm->compiled = qfalse;
1570 
1571 	emit_vm_thunk(&fi);
1572 
1573 	code = (unsigned char *) header + header->codeOffset;
1574 	pc = 0;
1575 
1576 	for (i_count = 0; i_count < header->instructionCount; i_count++) {
1577 		unsigned char opi, op = code[pc++];
1578 		struct src_insn *sp;
1579 
1580 		if (op == OP_CALL || op == OP_BLOCK_COPY)
1581 			fi.has_call = 1;
1582 		opi = vm_opInfo[op];
1583 		if (op == OP_CVIF || op == OP_CVFI ||
1584 		    (op == OP_LEAVE && (opi & opArgF)))
1585 			fi.need_float_tmp = 1;
1586 
1587 		if (op == OP_ENTER) {
1588 			if (fi.first->next)
1589 				compile_function(vm, &fi);
1590 			fi.first->next = NULL;
1591 			fi.last = fi.first;
1592 			fi.has_call = fi.need_float_tmp = 0;
1593 		}
1594 
1595 		sp = Z_Malloc(sizeof(*sp));
1596 		sp->op = op;
1597 		sp->i_count = i_count;
1598 		sp->arg.i = 0;
1599 		sp->next = NULL;
1600 
1601 		if (vm_opInfo[op] & opImm4) {
1602 			union {
1603 				unsigned char b[4];
1604 				unsigned int i;
1605 			} c = { { code[ pc + 3 ], code[ pc + 2 ],
1606 				  code[ pc + 1 ], code[ pc + 0 ] }, };
1607 
1608 			sp->arg.i = c.i;
1609 			pc += 4;
1610 		} else if (vm_opInfo[op] & opImm1) {
1611 			sp->arg.b = code[pc++];
1612 		}
1613 
1614 		fi.last->next = sp;
1615 		fi.last = sp;
1616 	}
1617 	compile_function(vm, &fi);
1618 
1619 	Z_Free(fi.first);
1620 
1621 	memset(fi.dst_by_i_count, 0, header->instructionCount * sizeof(void *));
1622 	sparc_compute_code(vm, &fi);
1623 
1624 	for (i = 0; i < header->instructionCount; i++) {
1625 		if (!fi.dst_by_i_count[i]) {
1626 			Com_Printf(S_COLOR_RED "Pointer %d not initialized !\n", i);
1627 			DIE("sparc JIT bug");
1628 		}
1629 	}
1630 
1631 	if (mprotect(vm->codeBase, vm->codeLength, PROT_READ|PROT_EXEC)) {
1632 		VM_Destroy_Compiled(vm);
1633 		DIE("mprotect failed");
1634 	}
1635 
1636 	vm->destroy = VM_Destroy_Compiled;
1637 	vm->compiled = qtrue;
1638 }
1639 
VM_CallCompiled(vm_t * vm,int * args)1640 int VM_CallCompiled(vm_t *vm, int *args)
1641 {
1642 	vm_data_t *vm_dataAndCode = (void *) vm->codeBase;
1643 	int programStack = vm->programStack;
1644 	int stackOnEntry = programStack;
1645 	byte *image = vm->dataBase;
1646 	int *argPointer;
1647 	int retVal;
1648 
1649 	currentVM = vm;
1650 
1651 	vm->currentlyInterpreting = qtrue;
1652 
1653 	programStack -= ( 8 + 4 * MAX_VMMAIN_ARGS );
1654 	argPointer = (int *)&image[ programStack + 8 ];
1655 	memcpy( argPointer, args, 4 * MAX_VMMAIN_ARGS );
1656 	argPointer[-1] = 0;
1657 	argPointer[-2] = -1;
1658 
1659 	/* call generated code */
1660 	{
1661 		int (*entry)(void *, int, void *, int);
1662 		entry = (void *)(vm->codeBase + vm_dataAndCode->dataLength);
1663 		retVal = entry(vm->codeBase, programStack, vm->dataBase, vm->dataMask);
1664 	}
1665 
1666 	vm->programStack = stackOnEntry;
1667 	vm->currentlyInterpreting = qfalse;
1668 
1669 	return retVal;
1670 }
1671