1 /*
2 #FILENAME#
3
4 #DESCRIPTION#
5
6 Copyright (C) 2001 #AUTHOR#
7
8 Author: #AUTHOR#
9 Date: #DATE#
10
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License
13 as published by the Free Software Foundation; either version 2
14 of the License, or (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19
20 See the GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to:
24
25 Free Software Foundation, Inc.
26 59 Temple Place - Suite 330
27 Boston, MA 02111-1307, USA
28
29 */
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #ifdef HAVE_STRING_H
35 # include "string.h"
36 #endif
37 #ifdef HAVE_STRINGS_H
38 # include "strings.h"
39 #endif
40
41 #include "QF/cvar.h"
42 #include "QF/hash.h"
43 #include "QF/pr_comp.h"
44 #include "QF/progs.h"
45 #include "QF/sys.h"
46
47 hashtab_t *opcode_table;
48
49 VISIBLE int pr_type_size[ev_type_count] = {
50 1, // ev_void
51 1, // ev_string
52 1, // ev_float
53 3, // ev_vector
54 1, // ev_entity
55 1, // ev_field
56 1, // ev_func
57 1, // ev_pointer
58 4, // ev_quat
59 1, // ev_integer
60 1, // ev_uinteger
61 0, // ev_short value in opcode
62 };
63
64 VISIBLE const char *pr_type_name[ev_type_count] = {
65 "void",
66 "string",
67 "float",
68 "vector",
69 "entity",
70 "field",
71 "function",
72 "pointer",
73 "quaternion",
74 "integer",
75 "uinteger",
76 "short",
77 "invalid",
78 };
79
80 // default format is "%Ga, %Gb, %gc"
81 // V global_string, contents, void
82 // G global_string, contents
83 // g global_string, no contents
84 // s as short
85 // O address + short
86 // P function parameter
87 // F function (must come before any P)
88 // R return value
89 // E entity + field (%Eab)
90 //
91 // a operand a
92 // b operand b
93 // c operand c
94 // x place holder for P (padding)
95 // 0-7 parameter index (for P)
96 VISIBLE opcode_t pr_opcodes[] = {
97 {"<DONE>", "done", OP_DONE, false, // OP_DONE is actually the same as
98 ev_entity, ev_field, ev_void, // OP_RETURN, the types are bogus
99 PROG_ID_VERSION,
100 "%Va",
101 },
102
103 {"*", "mul.f", OP_MUL_F, false,
104 ev_float, ev_float, ev_float,
105 PROG_ID_VERSION,
106 },
107 {"*", "mul.v", OP_MUL_V, false,
108 ev_vector, ev_vector, ev_float,
109 PROG_ID_VERSION,
110 },
111 {"*", "mul.fv", OP_MUL_FV, false,
112 ev_float, ev_vector, ev_vector,
113 PROG_ID_VERSION,
114 },
115 {"*", "mul.vf", OP_MUL_VF, false,
116 ev_vector, ev_float, ev_vector,
117 PROG_ID_VERSION,
118 },
119 {"*", "mul.q", OP_MUL_Q, false,
120 ev_quat, ev_quat, ev_quat,
121 PROG_VERSION,
122 },
123 {"*", "mul.fq", OP_MUL_FQ, false,
124 ev_float, ev_quat, ev_quat,
125 PROG_VERSION,
126 },
127 {"*", "mul.qf", OP_MUL_QF, false,
128 ev_quat, ev_float, ev_quat,
129 PROG_VERSION,
130 },
131 {"*", "mul.qv", OP_MUL_QV, false,
132 ev_quat, ev_vector, ev_vector,
133 PROG_VERSION,
134 },
135
136 {"~", "conj.q", OP_CONJ_Q, false,
137 ev_quat, ev_invalid, ev_quat,
138 PROG_VERSION,
139 "%Ga, %gc",
140 },
141
142 {"/", "div.f", OP_DIV_F, false,
143 ev_float, ev_float, ev_float,
144 PROG_ID_VERSION,
145 },
146
147 {"+", "add.f", OP_ADD_F, false,
148 ev_float, ev_float, ev_float,
149 PROG_ID_VERSION,
150 },
151 {"+", "add.v", OP_ADD_V, false,
152 ev_vector, ev_vector, ev_vector,
153 PROG_ID_VERSION,
154 },
155 {"+", "add.q", OP_ADD_Q, false,
156 ev_quat, ev_quat, ev_quat,
157 PROG_VERSION,
158 },
159 {"+", "add.s", OP_ADD_S, false,
160 ev_string, ev_string, ev_string,
161 PROG_VERSION,
162 },
163
164 {"-", "sub.f", OP_SUB_F, false,
165 ev_float, ev_float, ev_float,
166 PROG_ID_VERSION,
167 },
168 {"-", "sub.v", OP_SUB_V, false,
169 ev_vector, ev_vector, ev_vector,
170 PROG_ID_VERSION,
171 },
172 {"-", "sub.q", OP_SUB_Q, false,
173 ev_quat, ev_quat, ev_quat,
174 PROG_VERSION,
175 },
176
177 {"==", "eq.f", OP_EQ_F, false,
178 ev_float, ev_float, ev_integer,
179 PROG_ID_VERSION,
180 },
181 {"==", "eq.v", OP_EQ_V, false,
182 ev_vector, ev_vector, ev_integer,
183 PROG_ID_VERSION,
184 },
185 {"==", "eq.q", OP_EQ_Q, false,
186 ev_quat, ev_quat, ev_integer,
187 PROG_VERSION,
188 },
189 {"==", "eq.s", OP_EQ_S, false,
190 ev_string, ev_string, ev_integer,
191 PROG_ID_VERSION,
192 },
193 {"==", "eq.e", OP_EQ_E, false,
194 ev_entity, ev_entity, ev_integer,
195 PROG_ID_VERSION,
196 },
197 {"==", "eq.fn", OP_EQ_FN, false,
198 ev_func, ev_func, ev_integer,
199 PROG_ID_VERSION,
200 },
201
202 {"!=", "ne.f", OP_NE_F, false,
203 ev_float, ev_float, ev_integer,
204 PROG_ID_VERSION,
205 },
206 {"!=", "ne.v", OP_NE_V, false,
207 ev_vector, ev_vector, ev_integer,
208 PROG_ID_VERSION,
209 },
210 {"!=", "ne.q", OP_NE_Q, false,
211 ev_quat, ev_quat, ev_integer,
212 PROG_VERSION,
213 },
214 {"!=", "ne.s", OP_NE_S, false,
215 ev_string, ev_string, ev_integer,
216 PROG_ID_VERSION,
217 },
218 {"!=", "ne.e", OP_NE_E, false,
219 ev_entity, ev_entity, ev_integer,
220 PROG_ID_VERSION,
221 },
222 {"!=", "ne.fn", OP_NE_FN, false,
223 ev_func, ev_func, ev_integer,
224 PROG_ID_VERSION,
225 },
226
227 {"<=", "le.f", OP_LE_F, false,
228 ev_float, ev_float, ev_integer,
229 PROG_ID_VERSION,
230 },
231 {">=", "ge.f", OP_GE_F, false,
232 ev_float, ev_float, ev_integer,
233 PROG_ID_VERSION,
234 },
235 {"<=", "le.s", OP_LE_S, false,
236 ev_string, ev_string, ev_integer,
237 PROG_VERSION,
238 },
239 {">=", "ge.s", OP_GE_S, false,
240 ev_string, ev_string, ev_integer,
241 PROG_VERSION,
242 },
243 {"<", "lt.f", OP_LT_F, false,
244 ev_float, ev_float, ev_integer,
245 PROG_ID_VERSION,
246 },
247 {">", "gt.f", OP_GT_F, false,
248 ev_float, ev_float, ev_integer,
249 PROG_ID_VERSION,
250 },
251 {"<", "lt.s", OP_LT_S, false,
252 ev_string, ev_string, ev_integer,
253 PROG_VERSION,
254 },
255 {">", "gt.s", OP_GT_S, false,
256 ev_string, ev_string, ev_integer,
257 PROG_VERSION,
258 },
259
260 {".", "load.f", OP_LOAD_F, false,
261 ev_entity, ev_field, ev_float,
262 PROG_ID_VERSION,
263 "%Ga.%Gb(%Ec), %gc",//FIXME %E more flexible?
264 },
265 {".", "load.v", OP_LOAD_V, false,
266 ev_entity, ev_field, ev_vector,
267 PROG_ID_VERSION,
268 "%Ga.%Gb(%Ec), %gc",
269 },
270 {".", "load.q", OP_LOAD_Q, false,
271 ev_entity, ev_field, ev_quat,
272 PROG_VERSION,
273 "%Ga.%Gb(%Ec), %gc",
274 },
275 {".", "load.s", OP_LOAD_S, false,
276 ev_entity, ev_field, ev_string,
277 PROG_ID_VERSION,
278 "%Ga.%Gb(%Ec), %gc",
279 },
280 {".", "load.ent", OP_LOAD_ENT, false,
281 ev_entity, ev_field, ev_entity,
282 PROG_ID_VERSION,
283 "%Ga.%Gb(%Ec), %gc",
284 },
285 {".", "load.fld", OP_LOAD_FLD, false,
286 ev_entity, ev_field, ev_field,
287 PROG_ID_VERSION,
288 "%Ga.%Gb(%Ec), %gc",
289 },
290 {".", "load.fn", OP_LOAD_FN, false,
291 ev_entity, ev_field, ev_func,
292 PROG_ID_VERSION,
293 "%Ga.%Gb(%Ec), %gc",
294 },
295 {".", "load.i", OP_LOAD_I, false,
296 ev_entity, ev_field, ev_integer,
297 PROG_VERSION,
298 "%Ga.%Gb(%Ec), %gc",
299 },
300 {".", "load.p", OP_LOAD_P, false,
301 ev_entity, ev_field, ev_pointer,
302 PROG_VERSION,
303 "%Ga.%Gb(%Ec), %gc",
304 },
305
306 {".", "loadb.f", OP_LOADB_F, false,
307 ev_pointer, ev_integer, ev_float,
308 PROG_VERSION,
309 "*(%Ga + %Gb), %gc",
310 },
311 {".", "loadb.v", OP_LOADB_V, false,
312 ev_pointer, ev_integer, ev_vector,
313 PROG_VERSION,
314 "*(%Ga + %Gb), %gc",
315 },
316 {".", "loadb.q", OP_LOADB_Q, false,
317 ev_pointer, ev_integer, ev_quat,
318 PROG_VERSION,
319 "*(%Ga + %Gb), %gc",
320 },
321 {".", "loadb.s", OP_LOADB_S, false,
322 ev_pointer, ev_integer, ev_string,
323 PROG_VERSION,
324 "*(%Ga + %Gb), %gc",
325 },
326 {".", "loadb.ent", OP_LOADB_ENT, false,
327 ev_pointer, ev_integer, ev_entity,
328 PROG_VERSION,
329 "*(%Ga + %Gb), %gc",
330 },
331 {".", "loadb.fld", OP_LOADB_FLD, false,
332 ev_pointer, ev_integer, ev_field,
333 PROG_VERSION,
334 "*(%Ga + %Gb), %gc",
335 },
336 {".", "loadb.fn", OP_LOADB_FN, false,
337 ev_pointer, ev_integer, ev_func,
338 PROG_VERSION,
339 "*(%Ga + %Gb), %gc",
340 },
341 {".", "loadb.i", OP_LOADB_I, false,
342 ev_pointer, ev_integer, ev_integer,
343 PROG_VERSION,
344 "*(%Ga + %Gb), %gc",
345 },
346 {".", "loadb.p", OP_LOADB_P, false,
347 ev_pointer, ev_integer, ev_pointer,
348 PROG_VERSION,
349 "*(%Ga + %Gb), %gc",
350 },
351
352 {".", "loadbi.f", OP_LOADBI_F, false,
353 ev_pointer, ev_short, ev_float,
354 PROG_VERSION,
355 "*(%Ga + %sb), %gc",
356 },
357 {".", "loadbi.v", OP_LOADBI_V, false,
358 ev_pointer, ev_short, ev_vector,
359 PROG_VERSION,
360 "*(%Ga + %sb), %gc",
361 },
362 {".", "loadbi.q", OP_LOADBI_Q, false,
363 ev_pointer, ev_short, ev_quat,
364 PROG_VERSION,
365 "*(%Ga + %sb), %gc",
366 },
367 {".", "loadbi.s", OP_LOADBI_S, false,
368 ev_pointer, ev_short, ev_string,
369 PROG_VERSION,
370 "*(%Ga + %sb), %gc",
371 },
372 {".", "loadbi.ent", OP_LOADBI_ENT, false,
373 ev_pointer, ev_short, ev_entity,
374 PROG_VERSION,
375 "*(%Ga + %sb), %gc",
376 },
377 {".", "loadbi.fld", OP_LOADBI_FLD, false,
378 ev_pointer, ev_short, ev_field,
379 PROG_VERSION,
380 "*(%Ga + %sb), %gc",
381 },
382 {".", "loadbi.fn", OP_LOADBI_FN, false,
383 ev_pointer, ev_short, ev_func,
384 PROG_VERSION,
385 "*(%Ga + %sb), %gc",
386 },
387 {".", "loadbi.i", OP_LOADBI_I, false,
388 ev_pointer, ev_short, ev_integer,
389 PROG_VERSION,
390 "*(%Ga + %sb), %gc",
391 },
392 {".", "loadbi.p", OP_LOADBI_P, false,
393 ev_pointer, ev_short, ev_pointer,
394 PROG_VERSION,
395 "*(%Ga + %sb), %gc",
396 },
397
398 {"&", "address", OP_ADDRESS, false,
399 ev_entity, ev_field, ev_pointer,
400 PROG_ID_VERSION,
401 "%Ga.%Gb(%Ec), %gc",
402 },
403
404 {"&", "address", OP_ADDRESS_VOID, false,
405 ev_void, ev_invalid, ev_pointer,
406 PROG_VERSION,
407 "%Ga, %gc",
408 },
409 {"&", "address.f", OP_ADDRESS_F, false,
410 ev_float, ev_invalid, ev_pointer,
411 PROG_VERSION,
412 "%Ga, %gc",
413 },
414 {"&", "address.v", OP_ADDRESS_V, false,
415 ev_vector, ev_invalid, ev_pointer,
416 PROG_VERSION,
417 "%Ga, %gc",
418 },
419 {"&", "address.q", OP_ADDRESS_Q, false,
420 ev_quat, ev_invalid, ev_pointer,
421 PROG_VERSION,
422 "%Ga, %gc",
423 },
424 {"&", "address.s", OP_ADDRESS_S, false,
425 ev_string, ev_invalid, ev_pointer,
426 PROG_VERSION,
427 "%Ga, %gc",
428 },
429 {"&", "address.ent", OP_ADDRESS_ENT, false,
430 ev_entity, ev_invalid, ev_pointer,
431 PROG_VERSION,
432 "%Ga, %gc",
433 },
434 {"&", "address.fld", OP_ADDRESS_FLD, false,
435 ev_field, ev_invalid, ev_pointer,
436 PROG_VERSION,
437 "%Ga, %gc",
438 },
439 {"&", "address.fn", OP_ADDRESS_FN, false,
440 ev_func, ev_invalid, ev_pointer,
441 PROG_VERSION,
442 "%Ga, %gc",
443 },
444 {"&", "address.i", OP_ADDRESS_I, false,
445 ev_integer, ev_invalid, ev_pointer,
446 PROG_VERSION,
447 "%Ga, %gc",
448 },
449 {"&", "address.p", OP_ADDRESS_P, false,
450 ev_pointer, ev_invalid, ev_pointer,
451 PROG_VERSION,
452 "%Ga, %gc",
453 },
454
455 {"&", "lea", OP_LEA, false,
456 ev_pointer, ev_integer, ev_pointer,
457 PROG_VERSION,
458 "%Ga, %Gb, %gc",
459 },
460 {"&", "leai", OP_LEAI, false,
461 ev_pointer, ev_short, ev_pointer,
462 PROG_VERSION,
463 "%Ga, %sb, %gc",
464 },
465
466 {"<CONV>", "conv.if", OP_CONV_IF, false,
467 ev_integer, ev_invalid, ev_float,
468 PROG_VERSION,
469 "%Ga, %gc",
470 },
471 {"<CONV>", "conv.fi", OP_CONV_FI, false,
472 ev_float, ev_invalid, ev_integer,
473 PROG_VERSION,
474 "%Ga, %gc",
475 },
476
477 {"=", "store.f", OP_STORE_F, true,
478 ev_float, ev_float, ev_invalid,
479 PROG_ID_VERSION,
480 "%Ga, %gb",
481 },
482 {"=", "store.v", OP_STORE_V, true,
483 ev_vector, ev_vector, ev_invalid,
484 PROG_ID_VERSION,
485 "%Ga, %gb",
486 },
487 {"=", "store.q", OP_STORE_Q, true,
488 ev_quat, ev_quat, ev_invalid,
489 PROG_VERSION,
490 "%Ga, %gb",
491 },
492 {"=", "store.s", OP_STORE_S, true,
493 ev_string, ev_string, ev_invalid,
494 PROG_ID_VERSION,
495 "%Ga, %gb",
496 },
497 {"=", "store.ent", OP_STORE_ENT, true,
498 ev_entity, ev_entity, ev_invalid,
499 PROG_ID_VERSION,
500 "%Ga, %gb",
501 },
502 {"=", "store.fld", OP_STORE_FLD, true,
503 ev_field, ev_field, ev_invalid,
504 PROG_ID_VERSION,
505 "%Ga, %gb",
506 },
507 {"=", "store.fn", OP_STORE_FN, true,
508 ev_func, ev_func, ev_invalid,
509 PROG_ID_VERSION,
510 "%Ga, %gb",
511 },
512 {"=", "store.i", OP_STORE_I, true,
513 ev_integer, ev_integer, ev_invalid,
514 PROG_VERSION,
515 "%Ga, %gb",
516 },
517 {"=", "store.p", OP_STORE_P, true,
518 ev_pointer, ev_pointer, ev_invalid,
519 PROG_VERSION,
520 "%Ga, %gb",
521 },
522
523 {".=", "storep.f", OP_STOREP_F, true,
524 ev_float, ev_pointer, ev_invalid,
525 PROG_ID_VERSION,
526 "%Ga, *%Gb",
527 },
528 {".=", "storep.v", OP_STOREP_V, true,
529 ev_vector, ev_pointer, ev_invalid,
530 PROG_ID_VERSION,
531 "%Ga, *%Gb",
532 },
533 {".=", "storep.q", OP_STOREP_Q, true,
534 ev_quat, ev_pointer, ev_invalid,
535 PROG_VERSION,
536 "%Ga, *%Gb",
537 },
538 {".=", "storep.s", OP_STOREP_S, true,
539 ev_string, ev_pointer, ev_invalid,
540 PROG_ID_VERSION,
541 "%Ga, *%Gb",
542 },
543 {".=", "storep.ent", OP_STOREP_ENT, true,
544 ev_entity, ev_pointer, ev_invalid,
545 PROG_ID_VERSION,
546 "%Ga, *%Gb",
547 },
548 {".=", "storep.fld", OP_STOREP_FLD, true,
549 ev_field, ev_pointer, ev_invalid,
550 PROG_ID_VERSION,
551 "%Ga, *%Gb",
552 },
553 {".=", "storep.fn", OP_STOREP_FN, true,
554 ev_func, ev_pointer, ev_invalid,
555 PROG_ID_VERSION,
556 "%Ga, *%Gb",
557 },
558 {".=", "storep.i", OP_STOREP_I, true,
559 ev_integer, ev_pointer, ev_invalid,
560 PROG_VERSION,
561 "%Ga, *%Gb",
562 },
563 {".=", "storep.p", OP_STOREP_P, true,
564 ev_pointer, ev_pointer, ev_invalid,
565 PROG_VERSION,
566 "%Ga, *%Gb",
567 },
568
569 {".=", "storeb.f", OP_STOREB_F, true,
570 ev_float, ev_pointer, ev_integer,
571 PROG_VERSION,
572 "%Ga, *(%Gb + %Gc)",
573 },
574 {".=", "storeb.v", OP_STOREB_V, true,
575 ev_vector, ev_pointer, ev_integer,
576 PROG_VERSION,
577 "%Ga, *(%Gb + %Gc)",
578 },
579 {".=", "storeb.q", OP_STOREB_Q, true,
580 ev_quat, ev_pointer, ev_integer,
581 PROG_VERSION,
582 "%Ga, *(%Gb + %Gc)",
583 },
584 {".=", "storeb.s", OP_STOREB_S, true,
585 ev_string, ev_pointer, ev_integer,
586 PROG_VERSION,
587 "%Ga, *(%Gb + %Gc)",
588 },
589 {".=", "storeb.ent", OP_STOREB_ENT, true,
590 ev_entity, ev_pointer, ev_integer,
591 PROG_VERSION,
592 "%Ga, *(%Gb + %Gc)",
593 },
594 {".=", "storeb.fld", OP_STOREB_FLD, true,
595 ev_field, ev_pointer, ev_integer,
596 PROG_VERSION,
597 "%Ga, *(%Gb + %Gc)",
598 },
599 {".=", "storeb.fn", OP_STOREB_FN, true,
600 ev_func, ev_pointer, ev_integer,
601 PROG_VERSION,
602 "%Ga, *(%Gb + %Gc)",
603 },
604 {".=", "storeb.i", OP_STOREB_I, true,
605 ev_integer, ev_pointer, ev_integer,
606 PROG_VERSION,
607 "%Ga, *(%Gb + %Gc)",
608 },
609 {".=", "storeb.p", OP_STOREB_P, true,
610 ev_pointer, ev_pointer, ev_integer,
611 PROG_VERSION,
612 "%Ga, *(%Gb + %Gc)",
613 },
614
615 {".=", "storebi.f", OP_STOREBI_F, true,
616 ev_float, ev_pointer, ev_short,
617 PROG_VERSION,
618 "%Ga, *(%Gb + %sc)",
619 },
620 {".=", "storebi.v", OP_STOREBI_V, true,
621 ev_vector, ev_pointer, ev_short,
622 PROG_VERSION,
623 "%Ga, *(%Gb + %sc)",
624 },
625 {".=", "storebi.q", OP_STOREBI_Q, true,
626 ev_quat, ev_pointer, ev_short,
627 PROG_VERSION,
628 "%Ga, *(%Gb + %sc)",
629 },
630 {".=", "storebi.s", OP_STOREBI_S, true,
631 ev_string, ev_pointer, ev_short,
632 PROG_VERSION,
633 "%Ga, *(%Gb + %sc)",
634 },
635 {".=", "storebi.ent", OP_STOREBI_ENT, true,
636 ev_entity, ev_pointer, ev_short,
637 PROG_VERSION,
638 "%Ga, *(%Gb + %sc)",
639 },
640 {".=", "storebi.fld", OP_STOREBI_FLD, true,
641 ev_field, ev_pointer, ev_short,
642 PROG_VERSION,
643 "%Ga, *(%Gb + %sc)",
644 },
645 {".=", "storebi.fn", OP_STOREBI_FN, true,
646 ev_func, ev_pointer, ev_short,
647 PROG_VERSION,
648 "%Ga, *(%Gb + %sc)",
649 },
650 {".=", "storebi.i", OP_STOREBI_I, true,
651 ev_integer, ev_pointer, ev_short,
652 PROG_VERSION,
653 "%Ga, *(%Gb + %sc)",
654 },
655 {".=", "storebi.p", OP_STOREBI_P, true,
656 ev_pointer, ev_pointer, ev_short,
657 PROG_VERSION,
658 "%Ga, *(%Gb + %sc)",
659 },
660
661 {"<RETURN>", "return", OP_RETURN, false,
662 ev_void, ev_invalid, ev_invalid,
663 PROG_ID_VERSION,
664 "%Ra",
665 },
666
667 {"<RETURN_V>", "return", OP_RETURN_V, false,
668 ev_invalid, ev_invalid, ev_invalid,
669 PROG_VERSION,
670 "",
671 },
672
673 {"!", "not.f", OP_NOT_F, false,
674 ev_float, ev_invalid, ev_integer,
675 PROG_ID_VERSION,
676 "%Ga, %gc",
677 },
678 {"!", "not.v", OP_NOT_V, false,
679 ev_vector, ev_invalid, ev_integer,
680 PROG_ID_VERSION,
681 "%Ga, %gc",
682 },
683 {"!", "not.q", OP_NOT_Q, false,
684 ev_quat, ev_invalid, ev_integer,
685 PROG_VERSION,
686 "%Ga, %gc",
687 },
688 {"!", "not.s", OP_NOT_S, false,
689 ev_string, ev_invalid, ev_integer,
690 PROG_ID_VERSION,
691 "%Ga, %gc",
692 },
693 {"!", "not.ent", OP_NOT_ENT, false,
694 ev_entity, ev_invalid, ev_integer,
695 PROG_ID_VERSION,
696 "%Ga, %gc",
697 },
698 {"!", "not.fn", OP_NOT_FN, false,
699 ev_func, ev_invalid, ev_integer,
700 PROG_ID_VERSION,
701 "%Ga, %gc",
702 },
703 {"!", "not.p", OP_NOT_P, false,
704 ev_pointer, ev_invalid, ev_integer,
705 PROG_VERSION,
706 "%Ga, %gc",
707 },
708
709 {"<IF>", "if", OP_IF, false,
710 ev_integer, ev_short, ev_invalid,
711 PROG_ID_VERSION,
712 "%Ga branch %sb (%Ob)",
713 },
714 {"<IFNOT>", "ifnot", OP_IFNOT, false,
715 ev_integer, ev_short, ev_invalid,
716 PROG_ID_VERSION,
717 "%Ga branch %sb (%Ob)",
718 },
719 {"<IFBE>", "ifbe", OP_IFBE, true,
720 ev_integer, ev_short, ev_invalid,
721 PROG_VERSION,
722 "%Ga branch %sb (%Ob)",
723 },
724 {"<IFB>", "ifb", OP_IFB, true,
725 ev_integer, ev_short, ev_invalid,
726 PROG_VERSION,
727 "%Ga branch %sb (%Ob)",
728 },
729 {"<IFAE>", "ifae", OP_IFAE, true,
730 ev_integer, ev_short, ev_invalid,
731 PROG_VERSION,
732 "%Ga branch %sb (%Ob)",
733 },
734 {"<IFA>", "ifa", OP_IFA, true,
735 ev_integer, ev_short, ev_invalid,
736 PROG_VERSION,
737 "%Ga branch %sb (%Ob)",
738 },
739
740 // calls returns REG_RETURN
741 {"<CALL0>", "call0", OP_CALL0, false,
742 ev_func, ev_invalid, ev_invalid,
743 PROG_ID_VERSION,
744 "%Fa ()",
745 },
746 {"<CALL1>", "call1", OP_CALL1, false,
747 ev_func, ev_invalid, ev_invalid,
748 PROG_ID_VERSION,
749 "%Fa (%P0x)",
750 },
751 {"<CALL2>", "call2", OP_CALL2, false,
752 ev_func, ev_invalid, ev_invalid,
753 PROG_ID_VERSION,
754 "%Fa (%P0x, %P1x)",
755 },
756 {"<CALL3>", "call3", OP_CALL3, false,
757 ev_func, ev_invalid, ev_invalid,
758 PROG_ID_VERSION,
759 "%Fa (%P0x, %P1x, %P2x)",
760 },
761 {"<CALL4>", "call4", OP_CALL4, false,
762 ev_func, ev_invalid, ev_invalid,
763 PROG_ID_VERSION,
764 "%Fa (%P0x, %P1x, %P2x, %P3x)",
765 },
766 {"<CALL5>", "call5", OP_CALL5, false,
767 ev_func, ev_invalid, ev_invalid,
768 PROG_ID_VERSION,
769 "%Fa (%P0x, %P1x, %P2x, %P3x, %P4x)",
770 },
771 {"<CALL6>", "call6", OP_CALL6, false,
772 ev_func, ev_invalid, ev_invalid,
773 PROG_ID_VERSION,
774 "%Fa (%P0x, %P1x, %P2x, %P3x, %P4x, %P5x)",
775 },
776 {"<CALL7>", "call7", OP_CALL7, false,
777 ev_func, ev_invalid, ev_invalid,
778 PROG_ID_VERSION,
779 "%Fa (%P0x, %P1x, %P2x, %P3x, %P4x, %P5x, %P6x)",
780 },
781 {"<CALL8>", "call8", OP_CALL8, false,
782 ev_func, ev_invalid, ev_invalid,
783 PROG_ID_VERSION,
784 "%Fa (%P0x, %P1x, %P2x, %P3x, %P4x, %P5x, %P6x, %P7x)",
785 },
786 {"<RCALL1>", "rcall1", OP_RCALL1, false,
787 ev_func, ev_void, ev_invalid,
788 PROG_VERSION,
789 "%Fa (%P0b)",
790 },
791 {"<RCALL2>", "rcall2", OP_RCALL2, false,
792 ev_func, ev_void, ev_void,
793 PROG_VERSION,
794 "%Fa (%P0b, %P1c)",
795 },
796 {"<RCALL3>", "rcall3", OP_RCALL3, false,
797 ev_func, ev_void, ev_void,
798 PROG_VERSION,
799 "%Fa (%P0b, %P1c, %P2x)",
800 },
801 {"<RCALL4>", "rcall4", OP_RCALL4, false,
802 ev_func, ev_void, ev_void,
803 PROG_VERSION,
804 "%Fa (%P0b, %P1c, %P2x, %P3x)",
805 },
806 {"<RCALL5>", "rcall5", OP_RCALL5, false,
807 ev_func, ev_void, ev_void,
808 PROG_VERSION,
809 "%Fa (%P0b, %P1c, %P2x, %P3x, %P4x)",
810 },
811 {"<RCALL6>", "rcall6", OP_RCALL6, false,
812 ev_func, ev_void, ev_void,
813 PROG_VERSION,
814 "%Fa (%P0b, %P1c, %P2x, %P3x, %P4x, %P5x)",
815 },
816 {"<RCALL7>", "rcall7", OP_RCALL7, false,
817 ev_func, ev_void, ev_void,
818 PROG_VERSION,
819 "%Fa (%P0b, %P1c, %P2x, %P3x, %P4x, %P5x, %P6x)",
820 },
821 {"<RCALL8>", "rcall8", OP_RCALL8, false,
822 ev_func, ev_void, ev_void,
823 PROG_VERSION,
824 "%Fa (%P0b, %P1c, %P2x, %P3x, %P4x, %P5x, %P6x, %P7x)",
825 },
826
827 {"<STATE>", "state", OP_STATE, false,
828 ev_float, ev_func, ev_invalid,
829 PROG_ID_VERSION,
830 "%Ga, %Gb",
831 },
832
833 {"<STATE>", "state.f", OP_STATE_F, false,
834 ev_float, ev_func, ev_float,
835 PROG_VERSION,
836 "%Ga, %Gb, %Gc",
837 },
838
839 {"<GOTO>", "goto", OP_GOTO, false,
840 ev_short, ev_invalid, ev_invalid,
841 PROG_ID_VERSION,
842 "branch %sa (%Oa)",
843 },
844 {"<JUMP>", "jump", OP_JUMP, false,
845 ev_integer, ev_invalid, ev_invalid,
846 PROG_VERSION,
847 "%Ga",
848 },
849 {"<JUMPB>", "jumpb", OP_JUMPB, false,
850 ev_void, ev_integer, ev_invalid,
851 PROG_VERSION,
852 "%Ga[%Gb]",
853 },
854
855 {"&&", "and.f", OP_AND, false,
856 ev_float, ev_float, ev_integer,
857 PROG_ID_VERSION,
858 },
859 {"||", "or.f", OP_OR, false,
860 ev_float, ev_float, ev_integer,
861 PROG_ID_VERSION,
862 },
863
864 {"<<", "shl.f", OP_SHL_F, false,
865 ev_float, ev_float, ev_float,
866 PROG_VERSION,
867 },
868 {">>", "shr.f", OP_SHR_F, false,
869 ev_float, ev_float, ev_float,
870 PROG_VERSION,
871 },
872 {"<<", "shl.i", OP_SHL_I, false,
873 ev_integer, ev_integer, ev_integer,
874 PROG_VERSION,
875 },
876 {">>", "shr.i", OP_SHR_I, false,
877 ev_integer, ev_integer, ev_integer,
878 PROG_VERSION,
879 },
880 {">>", "shr.u", OP_SHR_U, false,
881 ev_uinteger, ev_integer, ev_uinteger,
882 PROG_VERSION,
883 },
884
885 {"&", "bitand", OP_BITAND, false,
886 ev_float, ev_float, ev_float,
887 PROG_ID_VERSION,
888 },
889 {"|", "bitor", OP_BITOR, false,
890 ev_float, ev_float, ev_float,
891 PROG_ID_VERSION,
892 },
893
894 {"+", "add.i", OP_ADD_I, false,
895 ev_integer, ev_integer, ev_integer,
896 PROG_VERSION,
897 },
898 {"-", "sub.i", OP_SUB_I, false,
899 ev_integer, ev_integer, ev_integer,
900 PROG_VERSION,
901 },
902 {"*", "mul.i", OP_MUL_I, false,
903 ev_integer, ev_integer, ev_integer,
904 PROG_VERSION,
905 },
906 {"/", "div.i", OP_DIV_I, false,
907 ev_integer, ev_integer, ev_integer,
908 PROG_VERSION,
909 },
910 {"%", "mod.i", OP_MOD_I, false,
911 ev_integer, ev_integer, ev_integer,
912 PROG_VERSION,
913 },
914 {"&", "bitand.i", OP_BITAND_I, false,
915 ev_integer, ev_integer, ev_integer,
916 PROG_VERSION,
917 },
918 {"|", "bitor.i", OP_BITOR_I, false,
919 ev_integer, ev_integer, ev_integer,
920 PROG_VERSION,
921 },
922
923 {"%", "mod.f", OP_MOD_F, false,
924 ev_float, ev_float, ev_float,
925 PROG_VERSION,
926 },
927
928 {">=", "ge.i", OP_GE_I, false,
929 ev_integer, ev_integer, ev_integer,
930 PROG_VERSION,
931 },
932 {"<=", "le.i", OP_LE_I, false,
933 ev_integer, ev_integer, ev_integer,
934 PROG_VERSION,
935 },
936 {">", "gt.i", OP_GT_I, false,
937 ev_integer, ev_integer, ev_integer,
938 PROG_VERSION,
939 },
940 {"<", "lt.i", OP_LT_I, false,
941 ev_integer, ev_integer, ev_integer,
942 PROG_VERSION,
943 },
944
945 {"&&", "and.i", OP_AND_I, false,
946 ev_integer, ev_integer, ev_integer,
947 PROG_VERSION,
948 },
949 {"||", "or.i", OP_OR_I, false,
950 ev_integer, ev_integer, ev_integer,
951 PROG_VERSION,
952 },
953 {"!", "not.i", OP_NOT_I, false,
954 ev_integer, ev_invalid, ev_integer,
955 PROG_VERSION,
956 "%Ga, %gc",
957 },
958 {"==", "eq.i", OP_EQ_I, false,
959 ev_integer, ev_integer, ev_integer,
960 PROG_VERSION,
961 },
962 {"!=", "ne.i", OP_NE_I, false,
963 ev_integer, ev_integer, ev_integer,
964 PROG_VERSION,
965 },
966
967 {">=", "ge.u", OP_GE_U, false,
968 ev_uinteger, ev_uinteger, ev_integer,
969 PROG_VERSION,
970 },
971 {"<=", "le.u", OP_LE_U, false,
972 ev_uinteger, ev_uinteger, ev_integer,
973 PROG_VERSION,
974 },
975 {">", "gt.u", OP_GT_U, false,
976 ev_uinteger, ev_uinteger, ev_integer,
977 PROG_VERSION,
978 },
979 {"<", "lt.u", OP_LT_U, false,
980 ev_uinteger, ev_uinteger, ev_integer,
981 PROG_VERSION,
982 },
983
984 {"^", "bitxor.f", OP_BITXOR_F, false,
985 ev_float, ev_float, ev_float,
986 PROG_VERSION,
987 },
988 {"~", "bitnot.f", OP_BITNOT_F, false,
989 ev_float, ev_invalid, ev_float,
990 PROG_VERSION,
991 "%Ga, %gc",
992 },
993 {"^", "bitxor.i", OP_BITXOR_I, false,
994 ev_integer, ev_integer, ev_integer,
995 PROG_VERSION,
996 },
997 {"~", "bitnot.i", OP_BITNOT_I, false,
998 ev_integer, ev_invalid, ev_integer,
999 PROG_VERSION,
1000 "%Ga, %gc",
1001 },
1002
1003 {">=", "ge.p", OP_GE_P, false,
1004 ev_pointer, ev_pointer, ev_integer,
1005 PROG_VERSION,
1006 },
1007 {"<=", "le.p", OP_LE_P, false,
1008 ev_pointer, ev_pointer, ev_integer,
1009 PROG_VERSION,
1010 },
1011 {">", "gt.p", OP_GT_P, false,
1012 ev_pointer, ev_pointer, ev_integer,
1013 PROG_VERSION,
1014 },
1015 {"<", "lt.p", OP_LT_P, false,
1016 ev_pointer, ev_pointer, ev_integer,
1017 PROG_VERSION,
1018 },
1019 {"==", "eq.p", OP_EQ_P, false,
1020 ev_pointer, ev_pointer, ev_integer,
1021 PROG_VERSION,
1022 },
1023 {"!=", "ne.p", OP_NE_P, false,
1024 ev_pointer, ev_pointer, ev_integer,
1025 PROG_VERSION,
1026 },
1027
1028 {"<MOVE>", "movei", OP_MOVEI, true,
1029 ev_void, ev_short, ev_void,
1030 PROG_VERSION,
1031 "%Ga, %sb, %gc",
1032 },
1033 {"<MOVEP>", "movep", OP_MOVEP, true,
1034 ev_pointer, ev_integer, ev_pointer,
1035 PROG_VERSION,
1036 "%Ga, %Gb, %Gc",
1037 },
1038 {"<MOVEP>", "movepi", OP_MOVEPI, true,
1039 ev_pointer, ev_short, ev_pointer,
1040 PROG_VERSION,
1041 "%Ga, %Gb, %Gc",
1042 },
1043
1044 // end of table
1045 {0},
1046 };
1047
1048
1049 static uintptr_t
opcode_get_hash(const void * op,void * unused)1050 opcode_get_hash (const void *op, void *unused)
1051 {
1052 return ((opcode_t *)op)->opcode;
1053 }
1054
1055 static int
opcode_compare(const void * _opa,const void * _opb,void * unused)1056 opcode_compare (const void *_opa, const void *_opb, void *unused)
1057 {
1058 opcode_t *opa = (opcode_t *)_opa;
1059 opcode_t *opb = (opcode_t *)_opb;
1060
1061 return opa->opcode == opb->opcode;
1062 }
1063
1064 opcode_t *
PR_Opcode(pr_short_t opcode)1065 PR_Opcode (pr_short_t opcode)
1066 {
1067 opcode_t op;
1068
1069 op.opcode = opcode;
1070 return Hash_FindElement (opcode_table, &op);
1071 }
1072
1073 VISIBLE void
PR_Opcode_Init(void)1074 PR_Opcode_Init (void)
1075 {
1076 opcode_t *op;
1077
1078 opcode_table = Hash_NewTable (1021, 0, 0, 0);
1079 Hash_SetHashCompare (opcode_table, opcode_get_hash, opcode_compare);
1080
1081 for (op = pr_opcodes; op->name; op++) {
1082 Hash_AddElement (opcode_table, op);
1083 }
1084 }
1085
1086 static inline void
check_branch(progs_t * pr,dstatement_t * st,opcode_t * op,short offset)1087 check_branch (progs_t *pr, dstatement_t *st, opcode_t *op, short offset)
1088 {
1089 pr_int_t address = st - pr->pr_statements;
1090
1091 address += offset;
1092 if (address < 0 || (pr_uint_t) address >= pr->progs->numstatements)
1093 PR_Error (pr, "PR_Check_Opcodes: invalid branch (statement %ld: %s)",
1094 (long)(st - pr->pr_statements), op->opname);
1095 }
1096
1097 static int
is_vector_parameter_store(progs_t * pr,dstatement_t * st,unsigned short operand)1098 is_vector_parameter_store (progs_t *pr, dstatement_t *st,
1099 unsigned short operand)
1100 {
1101 int i;
1102
1103 if (st->op != OP_STORE_V)
1104 return 0;
1105 if (operand != st->a)
1106 return 0;
1107 for (i = 0; i < MAX_PARMS; i++)
1108 if (st->b == pr->pr_params[i] - pr->pr_globals)
1109 return 1;
1110 return 0;
1111 }
1112
1113 #define ISDENORM(x) ((x) && !((x) & 0x7f800000))
1114
1115 static inline void
check_global(progs_t * pr,dstatement_t * st,opcode_t * op,etype_t type,unsigned short operand,int check_denorm)1116 check_global (progs_t *pr, dstatement_t *st, opcode_t *op, etype_t type,
1117 unsigned short operand, int check_denorm)
1118 {
1119 const char *msg;
1120 ddef_t *def;
1121
1122 switch (type) {
1123 case ev_short:
1124 break;
1125 case ev_invalid:
1126 if (operand) {
1127 msg = "non-zero global index in invalid operand";
1128 goto error;
1129 }
1130 break;
1131 default:
1132 if (operand + (unsigned) pr_type_size[type]
1133 > pr->progs->numglobals) {
1134 if (operand >= pr->progs->numglobals
1135 || !is_vector_parameter_store (pr, st, operand)) {
1136 msg = "out of bounds global index";
1137 goto error;
1138 }
1139 }
1140 if (type != ev_float || !check_denorm)
1141 break;
1142 if (!ISDENORM (G_INT (pr, operand))
1143 || G_UINT(pr, operand) == 0x80000000)
1144 break;
1145 if ((def = PR_GlobalAtOfs (pr, operand))
1146 && (def->type & ~DEF_SAVEGLOBAL) != ev_float) {
1147 // FTEqcc uses store.f parameters of most types :/
1148 break;
1149 }
1150 if (!pr->denorm_found) {
1151 pr->denorm_found = 1;
1152 if (pr_boundscheck->int_val) {
1153 Sys_Printf ("DENORMAL floats detected, these progs might "
1154 "not work. Good luck.\n");
1155 return;
1156 }
1157 msg = "DENORMAL float detected. These progs are probably "
1158 "using qccx arrays and integers. If just simple arrays "
1159 "are being used, then they should work, but if "
1160 "internal.qc is used, they most definitely will NOT. To"
1161 "allow these progs to be used, set pr_boundscheck to 1.";
1162 goto error;
1163 }
1164 break;
1165 }
1166 return;
1167 error:
1168 PR_PrintStatement (pr, st, 0);
1169 PR_Error (pr, "PR_Check_Opcodes: %s (statement %ld: %s)", msg,
1170 (long)(st - pr->pr_statements), op->opname);
1171 }
1172
1173 static void
check_global_size(progs_t * pr,dstatement_t * st,opcode_t * op,unsigned short size,unsigned short operand)1174 check_global_size (progs_t *pr, dstatement_t *st, opcode_t *op,
1175 unsigned short size, unsigned short operand)
1176 {
1177 const char *msg;
1178 if (operand + size > pr->progs->numglobals) {
1179 msg = "out of bounds global index";
1180 goto error;
1181 }
1182 return;
1183 error:
1184 PR_PrintStatement (pr, st, 0);
1185 PR_Error (pr, "PR_Check_Opcodes: %s (statement %ld: %s)", msg,
1186 (long)(st - pr->pr_statements), op->opname);
1187 }
1188
1189 int
PR_Check_Opcodes(progs_t * pr)1190 PR_Check_Opcodes (progs_t *pr)
1191 {
1192 opcode_t *op;
1193 dstatement_t *st;
1194 int state_ok = 0;
1195 pr_uint_t i;
1196
1197 if (pr->globals.time && pr->globals.self && pr->fields.nextthink != -1
1198 && pr->fields.think != -1 && pr->fields.frame != -1)
1199 state_ok = 1;
1200
1201 //FIXME need to decide if I really want to always do static bounds checking
1202 // the only problem is that it slows progs load a little, but it's the only
1203 // way to check for qccx' evil
1204 if (0 && !pr_boundscheck->int_val) {
1205 for (i = 0, st = pr->pr_statements; i < pr->progs->numstatements;
1206 st++, i++) {
1207 op = PR_Opcode (st->op);
1208 if (!op) {
1209 PR_Error (pr, "PR_Check_Opcodes: unknown opcode %d at "
1210 "statement %ld", st->op,
1211 (long)(st - pr->pr_statements));
1212 }
1213 if ((st->op == OP_STATE || st->op == OP_STATE_F) && !state_ok) {
1214 PR_Error (pr, "PR_Check_Opcodes: %s used with missing fields "
1215 "or globals", op->opname);
1216 }
1217 }
1218 } else {
1219 for (i = 0, st = pr->pr_statements; i < pr->progs->numstatements;
1220 st++, i++) {
1221 op = PR_Opcode (st->op);
1222 if (!op) {
1223 PR_Error (pr, "PR_Check_Opcodes: unknown opcode %d at "
1224 "statement %ld", st->op,
1225 (long)(st - pr->pr_statements));
1226 }
1227 switch (st->op) {
1228 case OP_IF:
1229 case OP_IFNOT:
1230 check_global (pr, st, op, op->type_a, st->a, 1);
1231 check_branch (pr, st, op, st->b);
1232 break;
1233 case OP_GOTO:
1234 check_branch (pr, st, op, st->a);
1235 break;
1236 case OP_DONE:
1237 case OP_RETURN:
1238 check_global (pr, st, op, ev_integer, st->a, 1);
1239 check_global (pr, st, op, ev_void, st->b, 0);
1240 check_global (pr, st, op, ev_void, st->c, 0);
1241 break;
1242 case OP_RCALL1:
1243 check_global (pr, st, op, ev_void, st->c, 1);
1244 case OP_RCALL2:
1245 case OP_RCALL3:
1246 case OP_RCALL4:
1247 case OP_RCALL5:
1248 case OP_RCALL6:
1249 case OP_RCALL7:
1250 case OP_RCALL8:
1251 if (st->op > OP_RCALL1)
1252 check_global (pr, st, op, ev_integer, st->c, 1);
1253 check_global (pr, st, op, ev_integer, st->b, 1);
1254 check_global (pr, st, op, ev_func, st->a, 1);
1255 break;
1256 case OP_STATE:
1257 case OP_STATE_F:
1258 if (!state_ok) {
1259 PR_Error (pr, "PR_Check_Opcodes: %s used with missing "
1260 "fields or globals", op->opname);
1261 }
1262 check_global (pr, st, op, op->type_a, st->a, 1);
1263 check_global (pr, st, op, op->type_b, st->b, 1);
1264 check_global (pr, st, op, op->type_c, st->c, 1);
1265 break;
1266 case OP_MOVEI:
1267 check_global_size (pr, st, op, st->b, st->a);
1268 check_global_size (pr, st, op, st->b, st->c);
1269 break;
1270 default:
1271 check_global (pr, st, op, op->type_a, st->a, 1);
1272 check_global (pr, st, op, op->type_b, st->b,
1273 op->opcode != OP_STORE_F);
1274 check_global (pr, st, op, op->type_c, st->c, 0);
1275 break;
1276 }
1277 }
1278 }
1279 return 1;
1280 }
1281