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